diff options
405 files changed, 9763 insertions, 32314 deletions
@@ -43,6 +43,12 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 13.x IS SLOW: sysctls have been removed. If you felt the need to set any of them to a non-default value, please tell asomers@FreeBSD.org why. +20190620: + Entropy collection and the /dev/random device are no longer optional + components. The "device random" option has been removed. + Implementations of distilling algorithms can still be made loadable + with "options RANDOM_LOADABLE" (e.g., random_fortuna.ko). + 20190612: Clang, llvm, lld, lldb, compiler-rt, libc++, libunwind and openmp have been upgraded to 8.0.1. Please see the 20141231 entry below for diff --git a/contrib/elftoolchain/elfcopy/sections.c b/contrib/elftoolchain/elfcopy/sections.c index 93dbf4422863..2bd094d2bfbe 100644 --- a/contrib/elftoolchain/elfcopy/sections.c +++ b/contrib/elftoolchain/elfcopy/sections.c @@ -1398,7 +1398,23 @@ update_shdr(struct elfcopy *ecp, int update_link) void init_shstrtab(struct elfcopy *ecp) { + Elf_Scn *shstrtab; + GElf_Shdr shdr; struct section *s; + size_t indx, sizehint; + + if (elf_getshstrndx(ecp->ein, &indx) != 0) { + shstrtab = elf_getscn(ecp->ein, indx); + if (shstrtab == NULL) + errx(EXIT_FAILURE, "elf_getscn failed: %s", + elf_errmsg(-1)); + if (gelf_getshdr(shstrtab, &shdr) != &shdr) + errx(EXIT_FAILURE, "gelf_getshdr failed: %s", + elf_errmsg(-1)); + sizehint = shdr.sh_size; + } else { + sizehint = 0; + } if ((ecp->shstrtab = calloc(1, sizeof(*ecp->shstrtab))) == NULL) err(EXIT_FAILURE, "calloc failed"); @@ -1410,7 +1426,7 @@ init_shstrtab(struct elfcopy *ecp) s->loadable = 0; s->type = SHT_STRTAB; s->vma = 0; - s->strtab = elftc_string_table_create(0); + s->strtab = elftc_string_table_create(sizehint); add_to_shstrtab(ecp, ""); add_to_shstrtab(ecp, ".symtab"); diff --git a/contrib/elftoolchain/libdwarf/libdwarf_attr.c b/contrib/elftoolchain/libdwarf/libdwarf_attr.c index dfbbc484c352..ea05374d051c 100644 --- a/contrib/elftoolchain/libdwarf/libdwarf_attr.c +++ b/contrib/elftoolchain/libdwarf/libdwarf_attr.c @@ -100,7 +100,6 @@ _dwarf_attr_init(Dwarf_Debug dbg, Dwarf_Section *ds, uint64_t *offsetp, uint64_t form, int indirect, Dwarf_Error *error) { struct _Dwarf_Attribute atref; - Dwarf_Section *str; int ret; ret = DW_DLE_NONE; @@ -183,9 +182,7 @@ _dwarf_attr_init(Dwarf_Debug dbg, Dwarf_Section *ds, uint64_t *offsetp, break; case DW_FORM_strp: atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, dwarf_size); - str = _dwarf_find_section(dbg, ".debug_str"); - assert(str != NULL); - atref.u[1].s = (char *) str->ds_data + atref.u[0].u64; + atref.u[1].s = _dwarf_strtab_get_table(dbg) + atref.u[0].u64; break; case DW_FORM_ref_sig8: atref.u[0].u64 = 8; diff --git a/contrib/elftoolchain/libelftc/elftc_string_table.c b/contrib/elftoolchain/libelftc/elftc_string_table.c index c0da15eed794..37fcc36d407b 100644 --- a/contrib/elftoolchain/libelftc/elftc_string_table.c +++ b/contrib/elftoolchain/libelftc/elftc_string_table.c @@ -44,7 +44,7 @@ ELFTC_VCSID("$Id: elftc_string_table.c 2869 2013-01-06 13:29:18Z jkoshy $"); #define ELFTC_STRING_TABLE_POOL_SIZE_INCREMENT (4*1024) struct _Elftc_String_Table_Entry { - int ste_idx; + ssize_t ste_idx; SLIST_ENTRY(_Elftc_String_Table_Entry) ste_next; }; @@ -64,9 +64,9 @@ struct _Elftc_String_Table_Entry { } while (0) struct _Elftc_String_Table { - unsigned int st_len; /* length and flags */ + size_t st_len; /* length and flags */ int st_nbuckets; - int st_string_pool_size; + size_t st_string_pool_size; char *st_string_pool; SLIST_HEAD(_Elftc_String_Table_Bucket, _Elftc_String_Table_Entry) st_buckets[]; @@ -86,7 +86,7 @@ elftc_string_table_find_hash_entry(Elftc_String_Table *st, const char *string, *rhashindex = hashindex; SLIST_FOREACH(ste, &st->st_buckets[hashindex], ste_next) { - s = st->st_string_pool + abs(ste->ste_idx); + s = st->st_string_pool + labs(ste->ste_idx); assert(s > st->st_string_pool && s < st->st_string_pool + st->st_string_pool_size); @@ -102,7 +102,7 @@ static int elftc_string_table_add_to_pool(Elftc_String_Table *st, const char *string) { char *newpool; - int len, newsize, stlen; + size_t len, newsize, stlen; len = strlen(string) + 1; /* length, including the trailing NUL */ stlen = ELFTC_STRING_TABLE_LENGTH(st); @@ -119,17 +119,17 @@ elftc_string_table_add_to_pool(Elftc_String_Table *st, const char *string) st->st_string_pool_size = newsize; } - strcpy(st->st_string_pool + stlen, string); + memcpy(st->st_string_pool + stlen, string, len); ELFTC_STRING_TABLE_UPDATE_LENGTH(st, stlen + len); return (stlen); } Elftc_String_Table * -elftc_string_table_create(int sizehint) +elftc_string_table_create(size_t sizehint) { - int n, nbuckets, tablesize; struct _Elftc_String_Table *st; + int n, nbuckets, tablesize; if (sizehint < ELFTC_STRING_TABLE_DEFAULT_SIZE) sizehint = ELFTC_STRING_TABLE_DEFAULT_SIZE; @@ -173,13 +173,13 @@ elftc_string_table_destroy(Elftc_String_Table *st) } Elftc_String_Table * -elftc_string_table_from_section(Elf_Scn *scn, int sizehint) +elftc_string_table_from_section(Elf_Scn *scn, size_t sizehint) { - int len; Elf_Data *d; GElf_Shdr sh; const char *s, *end; Elftc_String_Table *st; + size_t len; /* Verify the type of the section passed in. */ if (gelf_getshdr(scn, &sh) == NULL || @@ -235,7 +235,8 @@ elftc_string_table_image(Elftc_String_Table *st, size_t *size) char *r, *s, *end; struct _Elftc_String_Table_Entry *ste; struct _Elftc_String_Table_Bucket *head; - int copied, hashindex, offset, length, newsize; + size_t copied, offset, length, newsize; + int hashindex; /* * For the common case of a string table has not seen @@ -303,8 +304,9 @@ elftc_string_table_image(Elftc_String_Table *st, size_t *size) size_t elftc_string_table_insert(Elftc_String_Table *st, const char *string) { - int hashindex, idx; struct _Elftc_String_Table_Entry *ste; + ssize_t idx; + int hashindex; hashindex = 0; @@ -326,7 +328,7 @@ elftc_string_table_insert(Elftc_String_Table *st, const char *string) idx = ste->ste_idx; if (idx < 0) /* Undelete. */ - ste->ste_idx = idx = (- idx); + ste->ste_idx = idx = -idx; return (idx); } @@ -334,8 +336,9 @@ elftc_string_table_insert(Elftc_String_Table *st, const char *string) size_t elftc_string_table_lookup(Elftc_String_Table *st, const char *string) { - int hashindex, idx; struct _Elftc_String_Table_Entry *ste; + ssize_t idx; + int hashindex; ste = elftc_string_table_find_hash_entry(st, string, &hashindex); @@ -350,17 +353,17 @@ elftc_string_table_lookup(Elftc_String_Table *st, const char *string) int elftc_string_table_remove(Elftc_String_Table *st, const char *string) { - int idx; struct _Elftc_String_Table_Entry *ste; + ssize_t idx; ste = elftc_string_table_find_hash_entry(st, string, NULL); if (ste == NULL || (idx = ste->ste_idx) < 0) return (ELFTC_FAILURE); - assert(idx > 0 && idx < (int) ELFTC_STRING_TABLE_LENGTH(st)); + assert(idx > 0 && (size_t)idx < ELFTC_STRING_TABLE_LENGTH(st)); - ste->ste_idx = (- idx); + ste->ste_idx = -idx; ELFTC_STRING_TABLE_SET_COMPACTION_FLAG(st); diff --git a/contrib/elftoolchain/libelftc/elftc_string_table_create.3 b/contrib/elftoolchain/libelftc/elftc_string_table_create.3 index 36c7290d9f46..c3cf864af29c 100644 --- a/contrib/elftoolchain/libelftc/elftc_string_table_create.3 +++ b/contrib/elftoolchain/libelftc/elftc_string_table_create.3 @@ -24,7 +24,7 @@ .\" .\" $Id: elftc_string_table_create.3 3645 2018-10-15 20:17:14Z jkoshy $ .\" -.Dd January 5, 2013 +.Dd June 19, 2019 .Dt ELFTC_STRING_TABLE_CREATE 3 .Os .Sh NAME @@ -40,11 +40,11 @@ .Sh SYNOPSIS .In libelftc.h .Ft "Elftc_String_Table *" -.Fn elftc_string_table_create "int sizehint" -.Ft int +.Fn elftc_string_table_create "size_t sizehint" +.Ft void .Fn elftc_string_table_destroy "Elftc_String_Table *table" .Ft "Elftc_String_Table *" -.Fn elftc_string_table_from_section "Elf_Scn *scn" "int sizehint" +.Fn elftc_string_table_from_section "Elf_Scn *scn" "size_t sizehint" .Ft "const char *" .Fo elftc_string_table_image .Fa "Elftc_String_Table *table" diff --git a/contrib/elftoolchain/libelftc/libelftc.h b/contrib/elftoolchain/libelftc/libelftc.h index a235097e6910..a404dfe34e9c 100644 --- a/contrib/elftoolchain/libelftc/libelftc.h +++ b/contrib/elftoolchain/libelftc/libelftc.h @@ -77,10 +77,10 @@ int elftc_demangle(const char *_mangledname, char *_buffer, size_t _bufsize, unsigned int _flags); const char *elftc_reloc_type_str(unsigned int mach, unsigned int type); int elftc_set_timestamps(const char *_filename, struct stat *_sb); -Elftc_String_Table *elftc_string_table_create(int _hint); +Elftc_String_Table *elftc_string_table_create(size_t _sizehint); void elftc_string_table_destroy(Elftc_String_Table *_table); Elftc_String_Table *elftc_string_table_from_section(Elf_Scn *_scn, - int _hint); + size_t _sizehint); const char *elftc_string_table_image(Elftc_String_Table *_table, size_t *_sz); size_t elftc_string_table_insert(Elftc_String_Table *_table, diff --git a/contrib/gcc/config/rs6000/tramp.asm b/contrib/gcc/config/rs6000/tramp.asm index 013cac363b68..fe05401e039c 100644 --- a/contrib/gcc/config/rs6000/tramp.asm +++ b/contrib/gcc/config/rs6000/tramp.asm @@ -38,6 +38,7 @@ .file "tramp.asm" .section ".text" #include "ppc-asm.h" + #include "auto-host.h" #ifndef __powerpc64__ .type trampoline_initial,@object @@ -105,7 +106,7 @@ FUNC_START(__trampoline_setup) blr .Labort: -#if defined SHARED && defined HAVE_AS_REL16 +#if (defined(__PIC__) || defined(__pic__)) && defined HAVE_AS_REL16 bcl 20,31,1f 1: mflr r30 addis r30,r30,_GLOBAL_OFFSET_TABLE_-1b@ha diff --git a/contrib/ipfilter/man/ipmon.8 b/contrib/ipfilter/man/ipmon.8 index 126f4a7b15ee..aa20e5b3a49d 100644 --- a/contrib/ipfilter/man/ipmon.8 +++ b/contrib/ipfilter/man/ipmon.8 @@ -27,7 +27,7 @@ ipmon \- monitors /dev/ipl for logged packets .LP \fBipmon\fP opens \fB/dev/ipl\fP for reading and awaits data to be saved from the packet filter. The binary data read from the device is reprinted in -human readable for, however, IP#'s are not mapped back to hostnames, nor are +human readable form, however, IP#'s are not mapped back to hostnames, nor are ports mapped back to service names. The output goes to standard output by default or a filename, if given on the command line. Should the \fB\-s\fP option be used, output is instead sent to \fBsyslogd(8)\fP. Messages sent diff --git a/contrib/ipfilter/tools/ipmon.c b/contrib/ipfilter/tools/ipmon.c index 4e4d9cc28f9e..d7ad1a228378 100644 --- a/contrib/ipfilter/tools/ipmon.c +++ b/contrib/ipfilter/tools/ipmon.c @@ -1438,7 +1438,10 @@ printipflog: static void usage(prog) char *prog; { - fprintf(stderr, "%s: [-NFhstvxX] [-f <logfile>]\n", prog); + fprintf(stderr, "Usage: %s [ -abDFhnpstvxX ] [ -B <binary-logfile> ] [ -C <config-file> ]\n" + "\t[ -f <device> ] [ -L <facility> ] [ -N <device> ]\n" + "\t[ -o [NSI] ] [ -O [NSI] ] [ -P <pidfile> ] [ -S <device> ]\n" + "\t[ <filename> ]\n", prog); exit(1); } diff --git a/contrib/llvm/lib/Target/PowerPC/PPCSubtarget.cpp b/contrib/llvm/lib/Target/PowerPC/PPCSubtarget.cpp index 1fdf74549dec..57244ddff552 100644 --- a/contrib/llvm/lib/Target/PowerPC/PPCSubtarget.cpp +++ b/contrib/llvm/lib/Target/PowerPC/PPCSubtarget.cpp @@ -138,7 +138,8 @@ void PPCSubtarget::initSubtargetFeatures(StringRef CPU, StringRef FS) { if (isDarwin()) HasLazyResolverStubs = true; - if (TargetTriple.isOSNetBSD() || TargetTriple.isOSOpenBSD()) + if ((TargetTriple.isOSFreeBSD() && TargetTriple.getOSMajorVersion() >= 13) + || TargetTriple.isOSNetBSD() || TargetTriple.isOSOpenBSD()) SecurePlt = true; if (HasSPE && IsPPC64) diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/PPC.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/PPC.cpp index 791f1206cf25..a85ff8d30a2e 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/PPC.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/PPC.cpp @@ -116,7 +116,8 @@ ppc::ReadGOTPtrMode ppc::getPPCReadGOTPtrMode(const Driver &D, const llvm::Tripl const ArgList &Args) { if (Args.getLastArg(options::OPT_msecure_plt)) return ppc::ReadGOTPtrMode::SecurePlt; - if (Triple.isOSOpenBSD()) + if ((Triple.isOSFreeBSD() && Triple.getOSMajorVersion() >= 13) || + Triple.isOSOpenBSD()) return ppc::ReadGOTPtrMode::SecurePlt; else return ppc::ReadGOTPtrMode::Bss; diff --git a/etc/mtree/BSD.include.dist b/etc/mtree/BSD.include.dist index b0e305558f1a..b774449a17bf 100644 --- a/etc/mtree/BSD.include.dist +++ b/etc/mtree/BSD.include.dist @@ -138,8 +138,6 @@ mpilib .. .. - nand - .. nvme .. ofw @@ -184,8 +182,6 @@ .. msdosfs .. - nandfs - .. nfs .. nullfs diff --git a/gnu/usr.bin/cc/cc_tools/Makefile.hdrs b/gnu/usr.bin/cc/cc_tools/Makefile.hdrs index f2576f7fdf0a..dc5bcb7a2d94 100644 --- a/gnu/usr.bin/cc/cc_tools/Makefile.hdrs +++ b/gnu/usr.bin/cc/cc_tools/Makefile.hdrs @@ -21,6 +21,9 @@ TARGET_INC+= ${GCC_CPU}/${GCC_CPU}.h TARGET_INC+= ${GCC_CPU}/unix.h TARGET_INC+= ${GCC_CPU}/att.h .endif +.if ${TARGET_CPUARCH} == "powerpc" +TARGET_INC+= ${GCC_CPU}/secureplt.h +.endif TARGET_INC+= dbxelf.h TARGET_INC+= elfos-undef.h TARGET_INC+= elfos.h diff --git a/include/Makefile b/include/Makefile index bd0ddc10b492..8893eba97ea9 100644 --- a/include/Makefile +++ b/include/Makefile @@ -48,7 +48,7 @@ LSUBDIRS= cam/ata cam/mmc cam/nvme cam/scsi \ dev/ic dev/iicbus dev/io dev/mfi dev/mmc dev/nvme \ dev/ofw dev/pbio dev/pci ${_dev_powermac_nvram} dev/ppbus dev/pwm \ dev/smbus dev/speaker dev/tcp_log dev/veriexec dev/vkbd dev/wi \ - fs/devfs fs/fdescfs fs/msdosfs fs/nandfs fs/nfs fs/nullfs \ + fs/devfs fs/fdescfs fs/msdosfs fs/nfs fs/nullfs \ fs/procfs fs/smbfs fs/udf fs/unionfs \ geom/cache geom/concat geom/eli geom/gate geom/journal geom/label \ geom/mirror geom/mountver geom/multipath geom/nop \ @@ -158,7 +158,7 @@ copies: .PHONY .META done; \ fi .endfor -.for i in ${LDIRS} ${LSUBDIRS:Ndev/agp:Ndev/acpica:Ndev/bktr:Ndev/evdev:Ndev/hyperv:Ndev/nand:Ndev/pci:Ndev/veriexec} ${LSUBSUBDIRS} +.for i in ${LDIRS} ${LSUBDIRS:Ndev/agp:Ndev/acpica:Ndev/bktr:Ndev/evdev:Ndev/hyperv:Ndev/pci:Ndev/veriexec} ${LSUBSUBDIRS} cd ${SRCTOP}/sys; \ ${INSTALL} -C ${TAG_ARGS} -o ${BINOWN} -g ${BINGRP} -m 444 $i/*.h \ ${SDESTDIR}${INCLUDEDIR}/$i @@ -174,13 +174,6 @@ copies: .PHONY .META cd ${SRCTOP}/sys/dev/bktr; \ ${INSTALL} -C ${TAG_ARGS} -o ${BINOWN} -g ${BINGRP} -m 444 ioctl_*.h \ ${SDESTDIR}${INCLUDEDIR}/dev/bktr -.if ${MK_NAND} != "no" - cd ${SRCTOP}/sys/dev/nand; \ - ${INSTALL} -C ${TAG_ARGS} -o ${BINOWN} -g ${BINGRP} -m 444 nandsim.h \ - ${SDESTDIR}${INCLUDEDIR}/dev/nand; \ - ${INSTALL} -C ${TAG_ARGS} -o ${BINOWN} -g ${BINGRP} -m 444 nand_dev.h \ - ${SDESTDIR}${INCLUDEDIR}/dev/nand -.endif cd ${SRCTOP}/sys/dev/evdev; \ ${INSTALL} -C -o ${BINOWN} -g ${BINGRP} -m 444 input.h \ ${SDESTDIR}${INCLUDEDIR}/dev/evdev; \ @@ -268,7 +261,7 @@ symlinks: .PHONY .META ${INSTALL_SYMLINK} ${TAG_ARGS} ../../../sys/$i/$$h ${SDESTDIR}${INCLUDEDIR}/$i; \ done .endfor -.for i in ${LSUBDIRS:Ndev/agp:Ndev/acpica:Ndev/bktr:Ndev/evdev:Ndev/hyperv:Ndev/nand:Ndev/pci:Ndev/veriexec} +.for i in ${LSUBDIRS:Ndev/agp:Ndev/acpica:Ndev/bktr:Ndev/evdev:Ndev/hyperv:Ndev/pci:Ndev/veriexec} cd ${SRCTOP}/sys/$i; \ for h in *.h; do \ ${INSTALL_SYMLINK} ${TAG_ARGS} ../../../../sys/$i/$$h ${SDESTDIR}${INCLUDEDIR}/$i; \ @@ -289,13 +282,6 @@ symlinks: .PHONY .META ${INSTALL_SYMLINK} ${TAG_ARGS} ../../../../sys/dev/bktr/$$h \ ${SDESTDIR}${INCLUDEDIR}/dev/bktr; \ done -.if ${MK_NAND} != "no" - cd ${SRCTOP}/sys/dev/nand; \ - for h in nandsim.h nand_dev.h; do \ - ${INSTALL_SYMLINK} ${TAG_ARGS} ../../../../sys/dev/nand/$$h \ - ${SDESTDIR}${INCLUDEDIR}/dev/nand; \ - done -.endif cd ${SRCTOP}/sys/dev/evdev; \ for h in input.h input-event-codes.h uinput.h; do \ ln -fs ../../../../sys/dev/evdev/$$h \ diff --git a/lib/Makefile b/lib/Makefile index f5e89b0712c4..33f31f7f7ed6 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -174,7 +174,6 @@ SUBDIR.${MK_GOOGLETEST}+= googletest SUBDIR.${MK_LIBTHR}+= libthr SUBDIR.${MK_LLVM_LIBUNWIND}+= libgcc_eh SUBDIR.${MK_LLVM_LIBUNWIND}+= libgcc_s -SUBDIR.${MK_NAND}+= libnandfs SUBDIR.${MK_NETGRAPH}+= libnetgraph SUBDIR.${MK_NIS}+= libypclnt diff --git a/lib/libbe/be_access.c b/lib/libbe/be_access.c index d3e415bdbd42..9c267bd2f9a6 100644 --- a/lib/libbe/be_access.c +++ b/lib/libbe/be_access.c @@ -89,25 +89,31 @@ be_mount_iter(zfs_handle_t *zfs_hdl, void *data) return (0); } - if (zfs_prop_get_int(zfs_hdl, ZFS_PROP_CANMOUNT) == ZFS_CANMOUNT_OFF) - return (0); + /* + * canmount and mountpoint are both ignored for the BE dataset, because + * the rest of the system (kernel and loader) will effectively do the + * same. + */ + if (info->depth == 0) { + snprintf(tmp, BE_MAXPATHLEN, "%s", info->mountpoint); + } else { + if (zfs_prop_get_int(zfs_hdl, ZFS_PROP_CANMOUNT) == + ZFS_CANMOUNT_OFF) + return (0); - if (zfs_prop_get(zfs_hdl, ZFS_PROP_MOUNTPOINT, zfs_mnt, BE_MAXPATHLEN, - NULL, NULL, 0, 1)) - return (1); + if (zfs_prop_get(zfs_hdl, ZFS_PROP_MOUNTPOINT, zfs_mnt, + BE_MAXPATHLEN, NULL, NULL, 0, 1)) + return (1); - if (strcmp("none", zfs_mnt) == 0) { /* - * mountpoint=none; we'll mount it at info->mountpoint assuming - * we're at the root. If we're not at the root, we're likely - * at some intermediate dataset (e.g. zroot/var) that will have - * children that may need to be mounted. + * We've encountered mountpoint=none at some intermediate + * dataset (e.g. zroot/var) that will have children that may + * need to be mounted. Skip mounting it, but iterate through + * the children. */ - if (info->depth > 0) + if (strcmp("none", zfs_mnt) == 0) goto skipmount; - snprintf(tmp, BE_MAXPATHLEN, "%s", info->mountpoint); - } else { mountpoint = be_mountpoint_augmented(info->lbh, zfs_mnt); snprintf(tmp, BE_MAXPATHLEN, "%s%s", info->mountpoint, mountpoint); diff --git a/lib/libc/gen/Symbol.map b/lib/libc/gen/Symbol.map index 9c6b969ea8d3..703cfe796a38 100644 --- a/lib/libc/gen/Symbol.map +++ b/lib/libc/gen/Symbol.map @@ -338,6 +338,7 @@ FBSD_1.2 { getutxid; getutxline; getutxuser; + pthread_getthreadid_np; pututxline; sem_close; sem_destroy; diff --git a/lib/libc/gen/_pthread_stubs.c b/lib/libc/gen/_pthread_stubs.c index 89325a39b48a..870cbf2152ee 100644 --- a/lib/libc/gen/_pthread_stubs.c +++ b/lib/libc/gen/_pthread_stubs.c @@ -130,6 +130,7 @@ pthread_func_entry_t __thr_jtable[PJT_MAX] = { {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_MUTEX_CONSISTENT */ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_MUTEXATTR_GETROBUST */ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_MUTEXATTR_SETROBUST */ + {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_GETTHREADID_NP */ }; /* @@ -248,6 +249,7 @@ STUB_FUNC1(pthread_rwlock_trywrlock, PJT_RWLOCK_TRYWRLOCK, int, void *) STUB_FUNC1(pthread_rwlock_unlock, PJT_RWLOCK_UNLOCK, int, void *) STUB_FUNC1(pthread_rwlock_wrlock, PJT_RWLOCK_WRLOCK, int, void *) STUB_FUNC(pthread_self, PJT_SELF, pthread_t) +STUB_FUNC(pthread_getthreadid_np, PJT_GETTHREADID_NP, int) STUB_FUNC2(pthread_setspecific, PJT_SETSPECIFIC, int, pthread_key_t, void *) STUB_FUNC3(pthread_sigmask, PJT_SIGMASK, int, int, void *, void *) STUB_FUNC3(pthread_atfork, PJT_ATFORK, int, void *, void *, void*) diff --git a/lib/libc/gen/libc_dlopen.c b/lib/libc/gen/libc_dlopen.c index fe28d56f8cb0..5c386b649456 100644 --- a/lib/libc/gen/libc_dlopen.c +++ b/lib/libc/gen/libc_dlopen.c @@ -48,8 +48,8 @@ libc_dlopen(const char *path, int mode) if (__libc_restricted_mode) { _rtld_error("Service unavailable -- libc in restricted mode"); return (NULL); - } else - return (dlopen(path, mode)); + } + return (dlopen(path, mode)); } void @@ -57,6 +57,5 @@ __FreeBSD_libc_enter_restricted_mode(void) { __libc_restricted_mode = 1; - return; } diff --git a/lib/libc/gen/opendir.c b/lib/libc/gen/opendir.c index f264dd956a4c..98354e028dc4 100644 --- a/lib/libc/gen/opendir.c +++ b/lib/libc/gen/opendir.c @@ -99,8 +99,8 @@ static int opendir_compar(const void *p1, const void *p2) { - return (strcmp((*(const struct dirent **)p1)->d_name, - (*(const struct dirent **)p2)->d_name)); + return (strcmp((*(const struct dirent * const *)p1)->d_name, + (*(const struct dirent * const *)p2)->d_name)); } /* diff --git a/lib/libc/gen/telldir.c b/lib/libc/gen/telldir.c index 12309cf93266..d801345fc24c 100644 --- a/lib/libc/gen/telldir.c +++ b/lib/libc/gen/telldir.c @@ -63,8 +63,8 @@ telldir(DIR *dirp) * 2) Otherwise, see if it's already been recorded in the linked list * 3) Otherwise, malloc a new one */ - if (dirp->dd_seek < (1ul << DD_SEEK_BITS) && - dirp->dd_loc < (1ul << DD_LOC_BITS)) { + if (dirp->dd_seek < (off_t)(1l << DD_SEEK_BITS) && + dirp->dd_loc < (1l << DD_LOC_BITS)) { ddloc.s.is_packed = 1; ddloc.s.loc = dirp->dd_loc; ddloc.s.seek = dirp->dd_seek; diff --git a/lib/libc/include/libc_private.h b/lib/libc/include/libc_private.h index 116764b399b9..529ae6b17c41 100644 --- a/lib/libc/include/libc_private.h +++ b/lib/libc/include/libc_private.h @@ -176,6 +176,7 @@ typedef enum { PJT_MUTEX_CONSISTENT, PJT_MUTEXATTR_GETROBUST, PJT_MUTEXATTR_SETROBUST, + PJT_GETTHREADID_NP, PJT_MAX } pjt_index_t; diff --git a/lib/libc/powerpc/SYS.h b/lib/libc/powerpc/SYS.h index 63a5ec47c4b4..e9b6d3226c97 100644 --- a/lib/libc/powerpc/SYS.h +++ b/lib/libc/powerpc/SYS.h @@ -44,7 +44,7 @@ #define SYSCALL(name) \ .text; \ .align 2; \ -2: b PIC_PLT(CNAME(HIDENAME(cerror))); \ +2: b CNAME(HIDENAME(cerror)); \ ENTRY(__sys_##name); \ WEAK_REFERENCE(__sys_##name, name); \ WEAK_REFERENCE(__sys_##name, _##name); \ @@ -58,15 +58,14 @@ ENTRY(__sys_##name); \ WEAK_REFERENCE(__sys_##name, _##name); \ _SYSCALL(name); \ bnslr; \ - b PIC_PLT(CNAME(HIDENAME(cerror))) + b CNAME(HIDENAME(cerror)) #define RSYSCALL(name) \ .text; \ .align 2; \ -2: b PIC_PLT(CNAME(HIDENAME(cerror))); \ ENTRY(__sys_##name); \ WEAK_REFERENCE(__sys_##name, name); \ WEAK_REFERENCE(__sys_##name, _##name); \ _SYSCALL(name); \ bnslr; \ - b PIC_PLT(CNAME(HIDENAME(cerror))) + b CNAME(HIDENAME(cerror)) diff --git a/lib/libc/powerpc/gen/_ctx_start.S b/lib/libc/powerpc/gen/_ctx_start.S index 4b9fc1d53ae0..70b4a9d91c8c 100644 --- a/lib/libc/powerpc/gen/_ctx_start.S +++ b/lib/libc/powerpc/gen/_ctx_start.S @@ -35,11 +35,18 @@ mtlr %r14 blrl /* branch to start function */ mr %r3,%r15 /* pass pointer to ucontext as argument */ - bl PIC_PLT(CNAME(_ctx_done)) /* branch to ctxt completion func */ + bl CNAME(_ctx_done) /* branch to ctxt completion func */ + /* * we should never return from the * above branch. */ + /* Don't bother saving off %r30, we're already in a bad state. */ + bcl 20,31,1f +1: mflr %r30 + mr %r3,%r30 # save for _DYNAMIC + addis %r30,%r30,_GLOBAL_OFFSET_TABLE_-1b@ha + addi %r30,%r30,_GLOBAL_OFFSET_TABLE_-1b@l bl PIC_PLT(CNAME(abort)) /* abort */ END(_cts_start) diff --git a/lib/libc/powerpc/sys/cerror.S b/lib/libc/powerpc/sys/cerror.S index 7667cb8361d3..c2bc994b9c33 100644 --- a/lib/libc/powerpc/sys/cerror.S +++ b/lib/libc/powerpc/sys/cerror.S @@ -40,16 +40,27 @@ __FBSDID("$FreeBSD$"); */ HIDENAME(cerror): mflr %r0 - stwu %r1,-16(%r1) /* allocate new stack frame */ - stw %r0,20(%r1) /* and save lr, r31 */ - stw %r31,8(%r1) + stwu %r1,-20(%r1) /* allocate new stack frame */ + stw %r0,24(%r1) /* and save lr, r31 */ + stw %r31,12(%r1) +#ifdef __PIC__ + stw %r30,8(%r1) + bcl 20,31,1f +1: + mflr %r30 + addis %r30,%r30,_GLOBAL_OFFSET_TABLE_-1b@ha + addi %r30,%r30,_GLOBAL_OFFSET_TABLE_-1b@l +#endif mr %r31,%r3 /* stash errval in callee-saved register */ bl PIC_PLT(CNAME(__error)) stw %r31,0(%r3) /* store errval into &errno */ - lwz %r0,20(%r1) - lwz %r31,8(%r1) + lwz %r0,24(%r1) + lwz %r31,12(%r1) +#ifdef __PIC__ + lwz %r30,8(%r1) +#endif mtlr %r0 - la %r1,16(%r1) + la %r1,20(%r1) li %r3,-1 li %r4,-1 blr /* return to callers caller */ diff --git a/lib/libc/stdlib/realpath.c b/lib/libc/stdlib/realpath.c index 9b0ba94473cb..99dc388c4db6 100644 --- a/lib/libc/stdlib/realpath.c +++ b/lib/libc/stdlib/realpath.c @@ -91,7 +91,7 @@ realpath1(const char *path, char *resolved) */ p = strchr(left, '/'); - next_token_len = p != NULL ? p - left : left_len; + next_token_len = p != NULL ? (size_t)(p - left) : left_len; memcpy(next_token, left, next_token_len); next_token[next_token_len] = '\0'; @@ -146,7 +146,7 @@ realpath1(const char *path, char *resolved) return (NULL); } slen = readlink(resolved, symlink, sizeof(symlink)); - if (slen <= 0 || slen >= sizeof(symlink)) { + if (slen <= 0 || slen >= (ssize_t)sizeof(symlink)) { if (slen < 0) ; /* keep errno from readlink(2) call */ else if (slen == 0) @@ -173,7 +173,7 @@ realpath1(const char *path, char *resolved) */ if (p != NULL) { if (symlink[slen - 1] != '/') { - if (slen + 1 >= sizeof(symlink)) { + if (slen + 1 >= (ssize_t)sizeof(symlink)) { errno = ENAMETOOLONG; return (NULL); } diff --git a/lib/libc/sys/mmap.2 b/lib/libc/sys/mmap.2 index 607a0a636352..8a3c7c45f139 100644 --- a/lib/libc/sys/mmap.2 +++ b/lib/libc/sys/mmap.2 @@ -28,7 +28,7 @@ .\" @(#)mmap.2 8.4 (Berkeley) 5/11/95 .\" $FreeBSD$ .\" -.Dd June 22, 2017 +.Dd June 20, 2019 .Dt MMAP 2 .Os .Sh NAME @@ -113,6 +113,22 @@ Pages may be written. Pages may be executed. .El .Pp +In addition to these protection flags, +.Fx +provides the ability to set the maximum protection of a region allocated by +.Nm +and later altered by +.Xr mprotect 2 . +This is accomplished by +.Em or Ns 'ing +one or more +.Dv PROT_ +values wrapped in the +.Dv PROT_MAX() +macro into the +.Fa prot +argument. +.Pp The .Fa flags argument specifies the type of the mapped object, mapping options and @@ -416,6 +432,11 @@ An invalid value was passed in the .Fa prot argument. .It Bq Er EINVAL +The +.Fa prot +argument contains permissions which are not a subset of the specified +maximum permissions. +.It Bq Er EINVAL An undefined option was set in the .Fa flags argument. @@ -521,3 +542,16 @@ was specified and insufficient memory was available. .Xr munmap 2 , .Xr getpagesize 3 , .Xr getpagesizes 3 +.Sh HISTORY +The +.Nm +system call was first documented in +.Bx 4.2 +and implemented in +.Bx 4.4 . +.\" XXX: lots of missing history of FreeBSD additions. +.Pp +The +.Dv PROT_MAX +functionality was introduced in +.Fx 13 . diff --git a/lib/libc/sys/mprotect.2 b/lib/libc/sys/mprotect.2 index 3be81c6582a3..2c165f093861 100644 --- a/lib/libc/sys/mprotect.2 +++ b/lib/libc/sys/mprotect.2 @@ -28,7 +28,7 @@ .\" @(#)mprotect.2 8.1 (Berkeley) 6/9/93 .\" $FreeBSD$ .\" -.Dd August 3, 2016 +.Dd June 20, 2019 .Dt MPROTECT 2 .Os .Sh NAME @@ -65,6 +65,22 @@ The pages can be written. .It Dv PROT_EXEC The pages can be executed. .El +.Pp +In addition to these protection flags, +.Fx +provides the ability to set the maximum protection of a region +(which prevents +.Nm +from upgrading the permissions). +This is accomplished by +.Em or Ns 'ing +one or more +.Dv PROT_ +values wrapped in the +.Dv PROT_MAX() +macro into the +.Fa prot +argument. .Sh RETURN VALUES .Rv -std mprotect .Sh ERRORS @@ -78,6 +94,15 @@ The virtual address range specified by the and .Fa len arguments is not valid. +.It Bq Er EINVAL +The +.Fa prot +argument contains unhandled bits. +.It Bq Er EINVAL +The +.Fa prot +argument contains permissions which are not a subset of the specified +maximum permissions. .It Bq Er EACCES The calling process was not allowed to change the protection to the value specified by @@ -93,5 +118,12 @@ argument. .Sh HISTORY The .Fn mprotect -system call first appeared in +system call was first documented in +.Bx 4.2 +and first appeared in .Bx 4.4 . +.Pp +The +.Dv PROT_MAX +functionality was introduced in +.Fx 13 . diff --git a/lib/libjail/jail.c b/lib/libjail/jail.c index ad05f5273f2c..6a35cdc6dde5 100644 --- a/lib/libjail/jail.c +++ b/lib/libjail/jail.c @@ -30,7 +30,6 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> -#include <sys/types.h> #include <sys/jail.h> #include <sys/linker.h> #include <sys/socket.h> diff --git a/lib/libnandfs/Makefile b/lib/libnandfs/Makefile deleted file mode 100644 index e900c3c6eab4..000000000000 --- a/lib/libnandfs/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# $FreeBSD$ - -PACKAGE=lib${LIB} -LIB= nandfs -SRCS+= nandfs.c -INCS= libnandfs.h - -CFLAGS += -I${.CURDIR} - -.include <bsd.lib.mk> diff --git a/lib/libnandfs/Makefile.depend b/lib/libnandfs/Makefile.depend deleted file mode 100644 index 6cfaab1c3644..000000000000 --- a/lib/libnandfs/Makefile.depend +++ /dev/null @@ -1,17 +0,0 @@ -# $FreeBSD$ -# Autogenerated - do NOT edit! - -DIRDEPS = \ - gnu/lib/csu \ - include \ - include/xlocale \ - lib/${CSU_DIR} \ - lib/libc \ - lib/libcompiler_rt \ - - -.include <dirdeps.mk> - -.if ${DEP_RELDIR} == ${_DEP_RELDIR} -# local dependencies - needed for -jN in clean tree -.endif diff --git a/lib/libnandfs/libnandfs.h b/lib/libnandfs/libnandfs.h deleted file mode 100644 index 53cd04946d0e..000000000000 --- a/lib/libnandfs/libnandfs.h +++ /dev/null @@ -1,67 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _LIBNANDFS_NANDFS_H -#define _LIBNANDFS_NANDFS_H - -struct nandfs { - struct nandfs_fsdata n_fsdata; - struct nandfs_super_block n_sb; - char n_ioc[MNAMELEN]; - char n_dev[MNAMELEN]; - int n_iocfd; - int n_devfd; - int n_flags; - char n_errmsg[120]; -}; - -int nandfs_iserror(struct nandfs *); -const char *nandfs_errmsg(struct nandfs *); - -void nandfs_init(struct nandfs *, const char *); -void nandfs_destroy(struct nandfs *); - -const char *nandfs_dev(struct nandfs *); - -int nandfs_open(struct nandfs *); -void nandfs_close(struct nandfs *); - -int nandfs_get_cpstat(struct nandfs *, struct nandfs_cpstat *); - -ssize_t nandfs_get_cp(struct nandfs *, uint64_t, - struct nandfs_cpinfo *, size_t); - -ssize_t nandfs_get_snap(struct nandfs *, uint64_t, - struct nandfs_cpinfo *, size_t); - -int nandfs_make_snap(struct nandfs *, uint64_t *); -int nandfs_delete_snap(struct nandfs *, uint64_t); - -#endif /* _LIBNANDFS_NANDFS_H */ diff --git a/lib/libnandfs/nandfs.c b/lib/libnandfs/nandfs.c deleted file mode 100644 index f1dd771ae8fd..000000000000 --- a/lib/libnandfs/nandfs.c +++ /dev/null @@ -1,249 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf. - * 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 <assert.h> -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <fcntl.h> -#include <errno.h> -#include <sys/ioctl.h> -#include <sys/stat.h> -#include <sys/param.h> -#include <sys/stdint.h> -#include <sys/ucred.h> -#include <sys/disk.h> -#include <sys/mount.h> - -#include <fs/nandfs/nandfs_fs.h> -#include <libnandfs.h> - -#define NANDFS_IS_VALID 0x1 -#define NANDFS_IS_OPENED 0x2 -#define NANDFS_IS_OPENED_DEV 0x4 -#define NANDFS_IS_ERROR 0x8 - -#define DEBUG -#undef DEBUG -#ifdef DEBUG -#define NANDFS_DEBUG(fmt, args...) do { \ - printf("libnandfs:" fmt "\n", ##args); } while (0) -#else -#define NANDFS_DEBUG(fmt, args...) -#endif - -#define NANDFS_ASSERT_VALID(fs) assert((fs)->n_flags & NANDFS_IS_VALID) -#define NANDFS_ASSERT_VALID_DEV(fs) \ - assert(((fs)->n_flags & (NANDFS_IS_VALID | NANDFS_IS_OPENED_DEV)) == \ - (NANDFS_IS_VALID | NANDFS_IS_OPENED_DEV)) - -int -nandfs_iserror(struct nandfs *fs) -{ - - NANDFS_ASSERT_VALID(fs); - - return (fs->n_flags & NANDFS_IS_ERROR); -} - -const char * -nandfs_errmsg(struct nandfs *fs) -{ - - NANDFS_ASSERT_VALID(fs); - - assert(nandfs_iserror(fs)); - assert(fs->n_errmsg); - return (fs->n_errmsg); -} - -static void -nandfs_seterr(struct nandfs *fs, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - vsnprintf(fs->n_errmsg, sizeof(fs->n_errmsg), fmt, ap); - va_end(ap); - fs->n_flags |= NANDFS_IS_ERROR; -} - -const char * -nandfs_dev(struct nandfs *fs) -{ - - NANDFS_ASSERT_VALID(fs); - return (fs->n_dev); -} - -void -nandfs_init(struct nandfs *fs, const char *dir) -{ - - snprintf(fs->n_ioc, sizeof(fs->n_ioc), "%s/%s", dir, "."); - fs->n_iocfd = -1; - fs->n_flags = NANDFS_IS_VALID; -} - -void -nandfs_destroy(struct nandfs *fs) -{ - - assert(fs->n_iocfd == -1); - fs->n_flags &= - ~(NANDFS_IS_ERROR | NANDFS_IS_VALID); - assert(fs->n_flags == 0); -} - -int -nandfs_open(struct nandfs *fs) -{ - struct nandfs_fsinfo fsinfo; - - fs->n_flags |= NANDFS_IS_OPENED; - - fs->n_iocfd = open(fs->n_ioc, O_RDONLY, S_IRUSR | S_IWUSR | S_IRGRP | - S_IWGRP | S_IROTH | S_IWOTH); - if (fs->n_iocfd == -1) { - nandfs_seterr(fs, "couldn't open %s: %s", fs->n_ioc, - strerror(errno)); - return (-1); - } - - if (ioctl(fs->n_iocfd, NANDFS_IOCTL_GET_FSINFO, &fsinfo) == -1) { - nandfs_seterr(fs, "couldn't fetch fsinfo: %s", - strerror(errno)); - return (-1); - } - - memcpy(&fs->n_fsdata, &fsinfo.fs_fsdata, sizeof(fs->n_fsdata)); - memcpy(&fs->n_sb, &fsinfo.fs_super, sizeof(fs->n_sb)); - snprintf(fs->n_dev, sizeof(fs->n_dev), "%s", fsinfo.fs_dev); - - return (0); -} - -void -nandfs_close(struct nandfs *fs) -{ - - NANDFS_ASSERT_VALID(fs); - assert(fs->n_flags & NANDFS_IS_OPENED); - - close(fs->n_iocfd); - fs->n_iocfd = -1; - fs->n_flags &= ~NANDFS_IS_OPENED; -} - -int -nandfs_get_cpstat(struct nandfs *fs, struct nandfs_cpstat *cpstat) -{ - - NANDFS_ASSERT_VALID(fs); - - if (ioctl(fs->n_iocfd, NANDFS_IOCTL_GET_CPSTAT, cpstat) == -1) { - nandfs_seterr(fs, "ioctl NANDFS_IOCTL_GET_CPSTAT: %s", - strerror(errno)); - return (-1); - } - - return (0); -} - -static ssize_t -nandfs_get_cpinfo(struct nandfs *fs, uint64_t cno, int mode, - struct nandfs_cpinfo *cpinfo, size_t nci) -{ - struct nandfs_argv args; - - NANDFS_ASSERT_VALID(fs); - - args.nv_base = (u_long)cpinfo; - args.nv_nmembs = nci; - args.nv_index = cno; - args.nv_flags = mode; - - if (ioctl(fs->n_iocfd, NANDFS_IOCTL_GET_CPINFO, &args) == -1) { - nandfs_seterr(fs, "ioctl NANDFS_IOCTL_GET_CPINFO: %s", - strerror(errno)); - return (-1); - } - - return (args.nv_nmembs); -} - -ssize_t -nandfs_get_cp(struct nandfs *fs, uint64_t cno, struct nandfs_cpinfo *cpinfo, - size_t nci) -{ - - return (nandfs_get_cpinfo(fs, cno, NANDFS_CHECKPOINT, cpinfo, nci)); -} - -ssize_t -nandfs_get_snap(struct nandfs *fs, uint64_t cno, struct nandfs_cpinfo *cpinfo, - size_t nci) -{ - - return (nandfs_get_cpinfo(fs, cno, NANDFS_SNAPSHOT, cpinfo, nci)); -} - -int -nandfs_make_snap(struct nandfs *fs, uint64_t *cno) -{ - - NANDFS_ASSERT_VALID(fs); - - if (ioctl(fs->n_iocfd, NANDFS_IOCTL_MAKE_SNAP, cno) == -1) { - nandfs_seterr(fs, "ioctl NANDFS_IOCTL_MAKE_SNAP: %s", - strerror(errno)); - return (-1); - } - - return (0); -} - -int -nandfs_delete_snap(struct nandfs *fs, uint64_t cno) -{ - - NANDFS_ASSERT_VALID(fs); - - if (ioctl(fs->n_iocfd, NANDFS_IOCTL_DELETE_SNAP, &cno) == -1) { - nandfs_seterr(fs, "ioctl NANDFS_IOCTL_DELETE_SNAP: %s", - strerror(errno)); - return (-1); - } - - return (0); -} diff --git a/lib/libsecureboot/h/libsecureboot.h b/lib/libsecureboot/h/libsecureboot.h index 81984fde5f3e..d7d72e880744 100644 --- a/lib/libsecureboot/h/libsecureboot.h +++ b/lib/libsecureboot/h/libsecureboot.h @@ -42,6 +42,7 @@ #include <bearssl.h> +unsigned char * read_fd(int, size_t); #ifndef NEED_BRSSL_H unsigned char * read_file(const char *, size_t *); #endif @@ -51,8 +52,12 @@ extern int DebugVe; #define DEBUG_PRINTF(n, x) if (DebugVe >= n) printf x int ve_trust_init(void); +size_t ve_trust_anchors_add_buf(unsigned char *, size_t); +size_t ve_trust_anchors_revoke(unsigned char *, size_t); int ve_trust_add(const char *); void ve_debug_set(int); +void ve_anchor_verbose_set(int); +int ve_anchor_verbose_get(void); void ve_utc_set(time_t utc); char *ve_error_get(void); int ve_error_set(const char *, ...) __printflike(1,2); diff --git a/lib/libsecureboot/libsecureboot-priv.h b/lib/libsecureboot/libsecureboot-priv.h index c6a90d2c7404..bdf0c5c0c9bb 100644 --- a/lib/libsecureboot/libsecureboot-priv.h +++ b/lib/libsecureboot/libsecureboot-priv.h @@ -56,6 +56,8 @@ int is_verified(struct stat *stp); void add_verify_status(struct stat *stp, int status); int openpgp_trust_init(void); +int openpgp_trust_add_buf(unsigned char *, size_t); +int openpgp_trust_revoke(const char *); int openpgp_self_tests(void); int efi_secure_boot_enabled(void); diff --git a/lib/libsecureboot/local.trust.mk b/lib/libsecureboot/local.trust.mk index 4ba4c862e929..b28e5ee2d1ef 100644 --- a/lib/libsecureboot/local.trust.mk +++ b/lib/libsecureboot/local.trust.mk @@ -33,6 +33,10 @@ VE_SIGNATURE_EXT_LIST+= \ sig .endif +# add OpenPGP support - possibly dormant +VE_SIGNATURE_LIST+= OPENPGP +VE_SIGNATURE_EXT_LIST+= asc + SIGNER ?= ${SB_TOOLS_PATH:U/volume/buildtools/bin}/sign.py .if exists(${SIGNER}) @@ -42,7 +46,12 @@ SIGN_ECDSA= ${PYTHON} ${SIGNER} -u ${SIGN_HOST}:${ECDSA_PORT} -h sha256 RSA2_PORT:= ${163%y:L:gmtime} SIGN_RSA2= ${PYTHON} ${SIGNER} -u ${SIGN_HOST}:${RSA2_PORT} -h sha256 +# deal with quirk of our .esig format +XCFLAGS.vets+= -DVE_ECDSA_HASH_AGAIN + .if !empty(OPENPGP_SIGN_URL) +XCFLAGS.opgp_key+= -DHAVE_TA_ASC_H + VE_SIGNATURE_LIST+= OPENPGP VE_SIGNATURE_EXT_LIST+= asc diff --git a/lib/libsecureboot/openpgp/opgp_key.c b/lib/libsecureboot/openpgp/opgp_key.c index dc0d8fa2934d..c108cd2fa328 100644 --- a/lib/libsecureboot/openpgp/opgp_key.c +++ b/lib/libsecureboot/openpgp/opgp_key.c @@ -209,13 +209,54 @@ openpgp_trust_add(OpenPGP_key *key) LIST_INIT(&trust_list); } - if (key) { - DEBUG_PRINTF(2, ("openpgp_trust_add(%s)\n", key->id)); + if (key && openpgp_trust_get(key->id) == NULL) { + if (ve_anchor_verbose_get()) + printf("openpgp_trust_add(%s)\n", key->id); LIST_INSERT_HEAD(&trust_list, key, entries); } } /** + * @brief add trust anchor from buf + */ +int +openpgp_trust_add_buf(unsigned char *buf, size_t nbytes) +{ + OpenPGP_key *key; + + if ((key = load_key_buf(buf, nbytes))) { + openpgp_trust_add(key); + } + return (key != NULL); +} + + +/** + * @brief if keyID is in our list clobber it + * + * @return true if keyID removed + */ +int +openpgp_trust_revoke(const char *keyID) +{ + OpenPGP_key *key, *tkey; + + openpgp_trust_add(NULL); /* initialize if needed */ + + LIST_FOREACH(key, &trust_list, entries) { + if (strcmp(key->id, keyID) == 0) { + tkey = key; + LIST_REMOVE(tkey, entries); + printf("openpgp_trust_revoke(%s)\n", key->id); + memset(key, 0, sizeof(OpenPGP_key)); + free(key); + return (1); + } + } + return (0); +} + +/** * @brief if keyID is in our list return the key * * @return key or NULL @@ -251,7 +292,9 @@ load_key_file(const char *kfile) return (key); } +#ifdef HAVE_TA_ASC_H #include <ta_asc.h> +#endif #ifndef _STANDALONE /* we can lookup keyID in filesystem */ @@ -330,8 +373,8 @@ openpgp_trust_init(void) } } } - } #endif + } return (once); } diff --git a/lib/libsecureboot/readfile.c b/lib/libsecureboot/readfile.c index f632922143ce..ff9f9f6f6d60 100644 --- a/lib/libsecureboot/readfile.c +++ b/lib/libsecureboot/readfile.c @@ -28,21 +28,13 @@ __FBSDID("$FreeBSD$"); #include <libsecureboot.h> unsigned char * -read_file(const char *path, size_t *len) +read_fd(int fd, size_t len) { - int fd, m, n, x; - struct stat st; + int m, n, x; unsigned char *buf; - if (len) - *len = 0; - if ((fd = open(path, O_RDONLY)) < 0) - return (NULL); - fstat(fd, &st); - if (len) - *len = st.st_size; - buf = malloc(st.st_size + 1); - for (x = 0, m = st.st_size; m > 0; ) { + buf = malloc(len + 1); + for (x = 0, m = len; m > 0; ) { n = read(fd, &buf[x], m); if (n < 0) break; @@ -51,11 +43,30 @@ read_file(const char *path, size_t *len) x += n; } } - close(fd); if (m == 0) { - buf[st.st_size] = '\0'; + buf[len] = '\0'; return (buf); } free(buf); return (NULL); } + +unsigned char * +read_file(const char *path, size_t *len) +{ + struct stat st; + unsigned char *ucp; + int fd; + + if (len) + *len = 0; + if ((fd = open(path, O_RDONLY)) < 0) + return (NULL); + fstat(fd, &st); + ucp = read_fd(fd, st.st_size); + close(fd); + if (len != NULL && ucp != NULL) + *len = st.st_size; + return (ucp); +} + diff --git a/lib/libsecureboot/verify_file.c b/lib/libsecureboot/verify_file.c index e8b00451133f..bb092dda2ed2 100644 --- a/lib/libsecureboot/verify_file.c +++ b/lib/libsecureboot/verify_file.c @@ -246,7 +246,9 @@ severity_guess(const char *filename) } static void -verify_tweak(char *tweak, int *accept_no_fp, int *verbose, int *verifying) +verify_tweak(int fd, off_t off, struct stat *stp, + char *tweak, int *accept_no_fp, + int *verbose, int *verifying) { if (strcmp(tweak, "off") == 0) { *verifying = 0; @@ -268,6 +270,25 @@ verify_tweak(char *tweak, int *accept_no_fp, int *verbose, int *verifying) *verbose = 1; } else if (strcmp(tweak, "quiet") == 0) { *verbose = 0; + } else if (strncmp(tweak, "trust", 5) == 0) { + /* content is trust anchor to add or revoke */ + unsigned char *ucp; + size_t num; + + if (off > 0) + lseek(fd, 0, SEEK_SET); + ucp = read_fd(fd, stp->st_size); + if (ucp == NULL) + return; + if (strstr(tweak, "revoke")) { + num = ve_trust_anchors_revoke(ucp, stp->st_size); + DEBUG_PRINTF(3, ("revoked %d trust anchors\n", + (int) num)); + } else { + num = ve_trust_anchors_add_buf(ucp, stp->st_size); + DEBUG_PRINTF(3, ("added %d trust anchors\n", + (int) num)); + } } } @@ -317,8 +338,10 @@ verify_file(int fd, const char *filename, off_t off, int severity) rc = verifying ? VE_NOT_CHECKED : VE_NOT_VERIFYING; ve_status_set(0, rc); ve_status_state = VE_STATUS_NONE; - if (verifying) + if (verifying) { ve_self_tests(); + ve_anchor_verbose_set(1); + } } if (!verifying) return (0); @@ -367,7 +390,7 @@ verify_file(int fd, const char *filename, off_t off, int severity) cp++; if (strncmp(cp, "loader.ve.", 10) == 0) { cp += 10; - verify_tweak(cp, + verify_tweak(fd, off, &st, cp, &accept_no_fp, &verbose, &verifying); } diff --git a/lib/libsecureboot/vets.c b/lib/libsecureboot/vets.c index 73e3db7722d5..87fb190577eb 100644 --- a/lib/libsecureboot/vets.c +++ b/lib/libsecureboot/vets.c @@ -55,6 +55,20 @@ static anchor_list trust_anchors = VEC_INIT; static anchor_list forbidden_anchors = VEC_INIT; static digest_list forbidden_digests = VEC_INIT; +static int anchor_verbose = 0; + +void +ve_anchor_verbose_set(int n) +{ + anchor_verbose = n; +} + +int +ve_anchor_verbose_get(void) +{ + return (anchor_verbose); +} + void ve_debug_set(int n) { @@ -116,6 +130,47 @@ free_cert_contents(br_x509_certificate *xc) xfree(xc->data); } +/* + * a bit of a dance to get commonName from a certificate + */ +static char * +x509_cn_get(br_x509_certificate *xc, char *buf, size_t len) +{ + br_x509_minimal_context mc; + br_name_element cn; + unsigned char cn_oid[4]; + int err; + + if (buf == NULL) + return (buf); + /* + * We want the commonName field + * the OID we want is 2,5,4,3 - but DER encoded + */ + cn_oid[0] = 3; + cn_oid[1] = 0x55; + cn_oid[2] = 4; + cn_oid[3] = 3; + cn.oid = cn_oid; + cn.buf = buf; + cn.len = len; + cn.buf[0] = '\0'; + + br_x509_minimal_init(&mc, &br_sha256_vtable, NULL, 0); + br_x509_minimal_set_name_elements(&mc, &cn, 1); + /* the below actually does the work - updates cn.status */ + mc.vtable->start_chain(&mc.vtable, NULL); + mc.vtable->start_cert(&mc.vtable, xc->data_len); + mc.vtable->append(&mc.vtable, xc->data, xc->data_len); + mc.vtable->end_cert(&mc.vtable); + /* we don' actually care about cert status - just its name */ + err = mc.vtable->end_chain(&mc.vtable); + + if (!cn.status) + buf = NULL; + return (buf); +} + /* ASN parsing related defines */ #define ASN1_PRIMITIVE_TAG 0x1F #define ASN1_INF_LENGTH 0x80 @@ -184,7 +239,8 @@ ve_forbidden_digest_add(hash_data *digest, size_t num) } static size_t -ve_anchors_add(br_x509_certificate *xcs, size_t num, anchor_list *anchors) +ve_anchors_add(br_x509_certificate *xcs, size_t num, anchor_list *anchors, + char *anchors_name) { br_x509_trust_anchor ta; size_t u; @@ -194,6 +250,15 @@ ve_anchors_add(br_x509_certificate *xcs, size_t num, anchor_list *anchors) break; } VEC_ADD(*anchors, ta); + if (anchor_verbose && anchors_name) { + char buf[64]; + char *cp; + + cp = x509_cn_get(&xcs[u], buf, sizeof(buf)); + if (cp) { + printf("x509_anchor(%s) %s\n", cp, anchors_name); + } + } } return (u); } @@ -205,13 +270,68 @@ ve_anchors_add(br_x509_certificate *xcs, size_t num, anchor_list *anchors) size_t ve_trust_anchors_add(br_x509_certificate *xcs, size_t num) { - return (ve_anchors_add(xcs, num, &trust_anchors)); + return (ve_anchors_add(xcs, num, &trust_anchors, "trusted")); } size_t ve_forbidden_anchors_add(br_x509_certificate *xcs, size_t num) { - return (ve_anchors_add(xcs, num, &forbidden_anchors)); + return (ve_anchors_add(xcs, num, &forbidden_anchors, "forbidden")); +} + + +/** + * @brief add trust anchors in buf + * + * Assume buf contains x509 certificates, but if not and + * we support OpenPGP try adding as that. + * + * @return number of anchors added + */ +size_t +ve_trust_anchors_add_buf(unsigned char *buf, size_t len) +{ + br_x509_certificate *xcs; + size_t num; + + num = 0; + xcs = parse_certificates(buf, len, &num); + if (xcs != NULL) { + num = ve_trust_anchors_add(xcs, num); +#ifdef VE_OPENPGP_SUPPORT + } else { + num = openpgp_trust_add_buf(buf, len); +#endif + } + return (num); +} + +/** + * @brief revoke trust anchors in buf + * + * Assume buf contains x509 certificates, but if not and + * we support OpenPGP try revoking keyId + * + * @return number of anchors revoked + */ +size_t +ve_trust_anchors_revoke(unsigned char *buf, size_t len) +{ + br_x509_certificate *xcs; + size_t num; + + num = 0; + xcs = parse_certificates(buf, len, &num); + if (xcs != NULL) { + num = ve_forbidden_anchors_add(xcs, num); +#ifdef VE_OPENPGP_SUPPORT + } else { + if (buf[len - 1] == '\n') + buf[len - 1] = '\0'; + num = openpgp_trust_revoke((char *)buf); +#endif + } + return (num); } /** @@ -221,11 +341,7 @@ ve_forbidden_anchors_add(br_x509_certificate *xcs, size_t num) int ve_trust_init(void) { -#ifdef TRUST_ANCHOR_STR - br_x509_certificate *xcs; -#endif static int once = -1; - size_t num; if (once >= 0) return (once); @@ -240,10 +356,8 @@ ve_trust_init(void) #endif #ifdef TRUST_ANCHOR_STR - xcs = parse_certificates(__DECONST(unsigned char *, TRUST_ANCHOR_STR), - sizeof(TRUST_ANCHOR_STR), &num); - if (xcs != NULL) - num = ve_trust_anchors_add(xcs, num); + ve_trust_anchors_add_buf(__DECONST(unsigned char *, TRUST_ANCHOR_STR), + sizeof(TRUST_ANCHOR_STR)); #endif once = (int) VEC_LEN(trust_anchors); #ifdef VE_OPENPGP_SUPPORT @@ -552,6 +666,7 @@ verify_ec(br_x509_pkey *pk, const char *file, const char *sigfile) br_sha256_init(&ctx); br_sha256_update(&ctx, fcp, flen); br_sha256_out(&ctx, rhbuf); +#ifdef VE_ECDSA_HASH_AGAIN hex = hexdigest(hexbuf, sizeof(hexbuf), rhbuf, br_sha256_SIZE); /* now hash that */ if (hex) { @@ -559,6 +674,7 @@ verify_ec(br_x509_pkey *pk, const char *file, const char *sigfile) br_sha256_update(&ctx, hex, strlen(hex)); br_sha256_out(&ctx, rhbuf); } +#endif ec = br_ec_get_default(); vrfy = br_ecdsa_vrfy_asn1_get_default(); if (!vrfy(ec, rhbuf, br_sha256_SIZE, &pk->key.ec, po->data, diff --git a/lib/libthr/thread/thr_init.c b/lib/libthr/thread/thr_init.c index 1568529e8c51..7b043a38b1f2 100644 --- a/lib/libthr/thread/thr_init.c +++ b/lib/libthr/thread/thr_init.c @@ -272,6 +272,7 @@ static pthread_func_t jmp_table[][2] = { {DUAL_ENTRY(_pthread_mutex_consistent)},/* PJT_MUTEX_CONSISTENT */ {DUAL_ENTRY(_pthread_mutexattr_getrobust)},/* PJT_MUTEXATTR_GETROBUST */ {DUAL_ENTRY(_pthread_mutexattr_setrobust)},/* PJT_MUTEXATTR_SETROBUST */ + {DUAL_ENTRY(_pthread_getthreadid_np)}, /* PJT_GETTHREADID_NP */ }; static int init_once = 0; diff --git a/lib/libusb/libusb10.h b/lib/libusb/libusb10.h index c3deb562c6d4..5caa56666c32 100644 --- a/lib/libusb/libusb10.h +++ b/lib/libusb/libusb10.h @@ -89,6 +89,8 @@ struct libusb_hotplug_callback_handle_struct { void *user_data; }; +TAILQ_HEAD(libusb_device_head, libusb_device); + struct libusb_context { int debug; int debug_fixed; @@ -106,7 +108,7 @@ struct libusb_context { TAILQ_HEAD(, libusb_super_pollfd) pollfds; TAILQ_HEAD(, libusb_super_transfer) tr_done; TAILQ_HEAD(, libusb_hotplug_callback_handle_struct) hotplug_cbh; - TAILQ_HEAD(, libusb_device) hotplug_devs; + struct libusb_device_head hotplug_devs; struct libusb_super_pollfd ctx_poll; diff --git a/lib/libusb/libusb10_hotplug.c b/lib/libusb/libusb10_hotplug.c index 162cf2bbb5af..96e3bf9a12ca 100644 --- a/lib/libusb/libusb10_hotplug.c +++ b/lib/libusb/libusb10_hotplug.c @@ -1,6 +1,6 @@ /* $FreeBSD$ */ /*- - * Copyright (c) 2016 Hans Petter Selasky. All rights reserved. + * Copyright (c) 2016-2019 Hans Petter Selasky. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -85,20 +85,35 @@ libusb_hotplug_filter(libusb_context *ctx, libusb_hotplug_callback_handle pcbh, return (pcbh->fn(ctx, dev, event, pcbh->user_data)); } +static int +libusb_hotplug_enumerate(libusb_context *ctx, struct libusb_device_head *phead) +{ + libusb_device **ppdev; + ssize_t count; + ssize_t x; + + count = libusb_get_device_list(ctx, &ppdev); + if (count < 0) + return (-1); + + for (x = 0; x != count; x++) + TAILQ_INSERT_TAIL(phead, ppdev[x], hotplug_entry); + + libusb_free_device_list(ppdev, 0); + return (0); +} + static void * libusb_hotplug_scan(void *arg) { - TAILQ_HEAD(, libusb_device) hotplug_devs; + struct libusb_device_head hotplug_devs; libusb_hotplug_callback_handle acbh; libusb_hotplug_callback_handle bcbh; libusb_context *ctx = arg; - libusb_device **ppdev; libusb_device *temp; libusb_device *adev; libusb_device *bdev; unsigned do_loop = 1; - ssize_t count; - ssize_t x; while (do_loop) { usleep(4000000); @@ -108,14 +123,8 @@ libusb_hotplug_scan(void *arg) TAILQ_INIT(&hotplug_devs); if (ctx->hotplug_handler != NO_THREAD) { - count = libusb_get_device_list(ctx, &ppdev); - if (count < 0) + if (libusb_hotplug_enumerate(ctx, &hotplug_devs) < 0) continue; - for (x = 0; x != count; x++) { - TAILQ_INSERT_TAIL(&hotplug_devs, ppdev[x], - hotplug_entry); - } - libusb_free_device_list(ppdev, 0); } else { do_loop = 0; } @@ -191,6 +200,8 @@ int libusb_hotplug_register_callback(libusb_context *ctx, HOTPLUG_LOCK(ctx); if (ctx->hotplug_handler == NO_THREAD) { + libusb_hotplug_enumerate(ctx, &ctx->hotplug_devs); + if (pthread_create(&ctx->hotplug_handler, NULL, &libusb_hotplug_scan, ctx) != 0) ctx->hotplug_handler = NO_THREAD; diff --git a/libexec/rc/rc.d/motd b/libexec/rc/rc.d/motd index acb376723e80..2c06187c1d2a 100755 --- a/libexec/rc/rc.d/motd +++ b/libexec/rc/rc.d/motd @@ -37,11 +37,15 @@ motd_start() uname -v | sed -e 's,^\([^#]*\) #\(.* [1-2][0-9][0-9][0-9]\).*/\([^\]*\) $,\1 (\3) #\2,' > ${T} awk '{if (NR == 1) {if ($1 == "FreeBSD") {next} else {print "\n"$0}} else {print}}' < /etc/motd >> ${T} - cmp -s $T /etc/motd || { - cp $T /etc/motd + if ! cmp -s $T /etc/motd; then + mv -f $T /etc/.motd.tmp + fsync /etc/.motd.tmp + mv -f /etc/.motd.tmp /etc/motd chmod ${PERMS} /etc/motd - } - rm -f $T + fsync /etc + else + rm -f $T + fi check_startmsgs && echo '.' } diff --git a/libexec/rtld-elf/debug.h b/libexec/rtld-elf/debug.h index 1ad0323b42f9..4dcefbabdb45 100644 --- a/libexec/rtld-elf/debug.h +++ b/libexec/rtld-elf/debug.h @@ -37,7 +37,7 @@ #include <sys/cdefs.h> #include <string.h> -#include <unistd.h> +#include "rtld_printf.h" void debug_printf(const char *, ...) __printflike(1, 2); extern int debug; @@ -57,7 +57,7 @@ extern int debug; #define assert(cond) ((cond) ? (void) 0 : \ (msg(_MYNAME ": assert failed: " __FILE__ ":" \ __XSTRING(__LINE__) "\n"), abort())) -#define msg(s) write(STDOUT_FILENO, s, strlen(s)) +#define msg(s) rtld_putstr(s) #define trace() msg(_MYNAME ": " __XSTRING(__LINE__) "\n") diff --git a/libexec/rtld-elf/powerpc/reloc.c b/libexec/rtld-elf/powerpc/reloc.c index 382417ca3490..c923c7326079 100644 --- a/libexec/rtld-elf/powerpc/reloc.c +++ b/libexec/rtld-elf/powerpc/reloc.c @@ -57,6 +57,8 @@ #define JMPTAB_BASE(N) (18 + N*2 + ((N > PLT_EXTENDED_BEGIN) ? \ (N - PLT_EXTENDED_BEGIN)*2 : 0)) +void _rtld_bind_secureplt_start(void); + /* * Process the R_PPC_COPY relocations */ @@ -361,6 +363,11 @@ reloc_plt_object(Obj_Entry *obj, const Elf_Rela *rela) if (reloff < 0) return (-1); + if (obj->gotptr != NULL) { + *where += (Elf_Addr)obj->relocbase; + return (0); + } + pltlongresolve = obj->pltgot + 5; pltresolve = pltlongresolve + 5; @@ -425,7 +432,7 @@ reloc_plt(Obj_Entry *obj, int flags __unused, RtldLockState *lockstate __unused) * Sync the icache for the byte range represented by the * trampoline routines and call slots. */ - if (obj->pltgot != NULL) + if (obj->pltgot != NULL && obj->gotptr == NULL) __syncicache(obj->pltgot, JMPTAB_BASE(N)*4); return (0); @@ -501,6 +508,14 @@ reloc_jmpslot(Elf_Addr *wherep, Elf_Addr target, */ offset = target - (Elf_Addr)wherep; + if (obj->gotptr != NULL) { + assert(wherep >= (Elf_Word *)obj->pltgot); + assert(wherep < + (Elf_Word *)obj->pltgot + obj->pltrelasize); + *wherep = target; + goto out; + } + if (abs((int)offset) < 32*1024*1024) { /* inside 32MB? */ /* b value # branch directly */ *wherep = 0x48000000 | (offset & 0x03fffffc); @@ -579,6 +594,16 @@ init_pltgot(Obj_Entry *obj) return; } + /* Handle Secure-PLT first, if applicable. */ + if (obj->gotptr != NULL) { + obj->gotptr[1] = (Elf_Addr)_rtld_bind_secureplt_start; + obj->gotptr[2] = (Elf_Addr)obj; + dbg("obj %s secure-plt gotptr=%p start=%p obj=%p", + obj->path, obj->gotptr, + (void *)obj->gotptr[1], (void *)obj->gotptr[2]); + return; + } + /* * From the SVR4 PPC ABI: * diff --git a/libexec/rtld-elf/powerpc/rtld_start.S b/libexec/rtld-elf/powerpc/rtld_start.S index 28ec19bad110..5a2cd7bd2652 100644 --- a/libexec/rtld-elf/powerpc/rtld_start.S +++ b/libexec/rtld-elf/powerpc/rtld_start.S @@ -52,35 +52,22 @@ _ENTRY(.rtld_start) * - use link-time constants to determine offset to the * _DYNAMIC section and the GOT. Add these to the PC to * convert to absolute addresses. - * - sync icache to allow execution of the SVR4 ABI-specified - * blrl instruction preceding the GOT - * - Use this instruction to determine the GOT absolute address * - read GOT[0], which is the SVR4 ABI-specified link-time * value of _DYNAMIC. Subtract this value from the absolute * value to determine the load address * - call reloc_non_plt_self() to fix up ld-elf.so's relocations */ - bl 1f - .long _DYNAMIC-. - .long _GLOBAL_OFFSET_TABLE_-. /* branch lr + 4 */ -1: - mflr %r3 /* PC value at .long */ - lwz %r4,4(%r3) - add %r4,%r4,%r3 /* &_GLOBAL_OFFSET_TABLE-4, blrl insn. */ - dcbst %r0,%r4 /* sync i-cache with d-cache */ - sync - icbi %r0,%r4 - isync - - lwz %r4,0(%r3) /* offset to _DYNAMIC */ - add %r3,%r4,%r3 /* r3 = &_DYNAMIC, absolute value */ - - bl _GLOBAL_OFFSET_TABLE_@local-4 - mflr %r4 /* &_GLOBAL_OFFSET_TABLE_, absolute value */ - lwz %r4,0(%r4) /* linker &_DYNAMIC, from got[0] */ - subf %r4,%r4,%r3 /* subtract to calculate relocbase */ - - bl reloc_non_plt_self@plt /* reloc_non_plt_self(&_DYNAMIC,base) */ + bcl 20,31,1f +1: mflr %r30 + mr %r3,%r30 # save for _DYNAMIC + addis %r30,%r30,_GLOBAL_OFFSET_TABLE_-1b@ha + addi %r30,%r30,_GLOBAL_OFFSET_TABLE_-1b@l + addis %r3,%r3,_DYNAMIC-1b@ha # get _DYNAMIC actual address + addi %r3,%r3,_DYNAMIC-1b@l + lwz %r28,0(%r30) # get base-relative &_DYNAMIC + sub %r28,%r3,%r28 # r28 = relocbase + mr %r4,%r28 # r4 = relocbase + bl reloc_non_plt_self /* reloc_non_plt_self(&_DYNAMIC,base) */ /* * The _rtld() function likes to see a stack layout containing @@ -95,7 +82,7 @@ _ENTRY(.rtld_start) addi %r4,%r1,8 /* &exit_proc on stack */ addi %r5,%r1,12 /* &obj_main on stack */ - bl _rtld@plt /* &_start = _rtld(sp, &exit_proc, &obj_main)*/ + bl _rtld /* &_start = _rtld(sp, &exit_proc, &obj_main)*/ mtlr %r3 /* @@ -115,6 +102,29 @@ _ENTRY(.rtld_start) sc /* + * _rtld_bind_secureplt_start() + * + * Call into the MI binder (Secure-PLT stub). + * secure-plt expects %r11 to be the offset to the rela entry. + * bss-plt expects %r11 to be index of the rela entry. + * So for bss-plt, we multiply the index by 12 to get the offset. + */ +_ENTRY(_rtld_bind_secureplt_start) + stwu %r1,-160(%r1) # stack space for 29 regs + r0/lr/cr + stw %r0,20(%r1) # save r0 + + /* + * Instead of division which is costly we will use multiplicative + * inverse. a / n = ((a * inv(n)) >> 32) + * where inv(n) = (0x100000000 + n - 1) / n + */ + mr %r0,%r11 + lis %r11,0x15555556@h # load multiplicative inverse of 12 + ori %r11,%r11,0x15555556@l + mulhwu %r11,%r11,%r0 # get high half of multiplication + b 1f + +/* * _rtld_bind_start() * * Call into the MI binder. This routine is reached via the PLT call cell, @@ -129,6 +139,7 @@ _ENTRY(.rtld_start) _ENTRY(_rtld_bind_start) stwu %r1,-160(%r1) # stack space for 29 regs + r0/lr/cr stw %r0,20(%r1) # save r0 +1: mflr %r0 stw %r0,16(%r1) # save lr mfcr %r0 @@ -137,7 +148,7 @@ _ENTRY(_rtld_bind_start) mr %r3,%r12 # obj mulli %r4,%r11,12 # rela index * sizeof(Elf_Rela) - bl _rtld_bind@PLT # target addr = _rtld_bind(obj, reloff) + bl _rtld_bind # target addr = _rtld_bind(obj, reloff) mtctr %r3 # move absolute target addr into ctr lmw %r3,24(%r1) # restore r3-r31 diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c index 7cdd5c58c5dc..ece58e138235 100644 --- a/libexec/rtld-elf/rtld.c +++ b/libexec/rtld-elf/rtld.c @@ -1286,10 +1286,16 @@ digest_dynamic1(Obj_Entry *obj, int early, const Elf_Dyn **dyn_rpath, #endif +#ifdef __powerpc__ #ifdef __powerpc64__ case DT_PPC64_GLINK: obj->glink = (Elf_Addr)(obj->relocbase + dynp->d_un.d_ptr); break; +#else + case DT_PPC_GOT: + obj->gotptr = (Elf_Addr *)(obj->relocbase + dynp->d_un.d_ptr); + break; +#endif #endif case DT_FLAGS_1: diff --git a/libexec/rtld-elf/rtld.h b/libexec/rtld-elf/rtld.h index d7ef9d56b8d0..fc9f10255811 100644 --- a/libexec/rtld-elf/rtld.h +++ b/libexec/rtld-elf/rtld.h @@ -190,8 +190,12 @@ typedef struct Struct_Obj_Entry { Elf_Word gotsym; /* First dynamic symbol in GOT */ Elf_Addr *mips_pltgot; /* Second PLT GOT */ #endif +#ifdef __powerpc__ #ifdef __powerpc64__ Elf_Addr glink; /* GLINK PLT call stub section */ +#else + Elf_Addr *gotptr; /* GOT pointer (secure-plt only) */ +#endif #endif const Elf_Verneed *verneed; /* Required versions. */ diff --git a/libexec/rtld-elf/rtld_printf.h b/libexec/rtld-elf/rtld_printf.h index 5cfcc6d062f1..3d3a0480ecce 100644 --- a/libexec/rtld-elf/rtld_printf.h +++ b/libexec/rtld-elf/rtld_printf.h @@ -31,6 +31,7 @@ #define RTLD_PRINTF_H 1 #include <sys/cdefs.h> +#include <stdarg.h> #include <unistd.h> int rtld_snprintf(char *buf, size_t bufsize, const char *fmt, ...) diff --git a/release/Makefile.mirrors b/release/Makefile.mirrors index 44589d698c3c..6857ff0eafb1 100644 --- a/release/Makefile.mirrors +++ b/release/Makefile.mirrors @@ -19,6 +19,7 @@ FTPDIR?= ${RELEASEDIR}/ftp-stage .if exists(${RELEASEDIR}) STAGE_TARGETS?= iso-images-stage .endif +SRCBRANCH!= ${SVN_CMD} info --show-item relative-url ${WORLDDIR} .if (defined(EMBEDDED_TARGET) && !empty(EMBEDDED_TARGET)) || (defined(EMBEDDEDBUILD) && !empty(EMBEDDEDBUILD)) . if ${TARGET:Marm*} != "" || ${EMBEDDED_TARGET:Marm*} != "" @@ -185,6 +186,9 @@ iso-images-stage: .if exists(${RELEASEDIR}/ftp) mkdir -p ${FTP_DIR} cp -p ${RELEASEDIR}/ftp/*.txz ${RELEASEDIR}/ftp/MANIFEST ${FTP_DIR} + echo ${BUILDDATE} > ${FTP_DIR}/BUILDDATE + echo ${SRCBRANCH} > ${FTP_DIR}/SRCBRANCH + echo r${SVNREVISION} > ${FTP_DIR}/REVISION cd ${TLD}/${TARGET} && \ ln -s ${TARGET_ARCH}/${REVISION}-${BRANCH} \ ${REVISION}-${BRANCH} diff --git a/release/picobsd/bridge/PICOBSD b/release/picobsd/bridge/PICOBSD index bc1185d61c64..c06091dcb888 100644 --- a/release/picobsd/bridge/PICOBSD +++ b/release/picobsd/bridge/PICOBSD @@ -50,7 +50,6 @@ device if_bridge # qemu, so we set HZ explicitly. options HZ=1000 -device random # used by ssh device pci # Floppy drives diff --git a/release/picobsd/build/picobsd b/release/picobsd/build/picobsd index 807f9acd7242..2d057ed81c5c 100755 --- a/release/picobsd/build/picobsd +++ b/release/picobsd/build/picobsd @@ -437,7 +437,7 @@ populate_floppy_fs() { # OK ${MY_TREE}/floppy.tree.${SITE} ; do if [ -d ${FLOPPY_TREE} ] ; then (cd ${FLOPPY_TREE} ; tar -cf - \ - --exclude .svn ${excl} . ) | \ + --exclude .git --exclude .svn ${excl} . ) | \ (cd ${dst} ; tar x${o_tarv}f - ) log "Copied from ${FLOPPY_TREE}" fi @@ -698,7 +698,7 @@ populate_mfs_tree() { for MFS_TREE in ${PICO_TREE}/mfs_tree ${MY_TREE}/mfs_tree ; do if [ -d ${MFS_TREE} ] ; then log "Copy ${MFS_TREE} ..." - (cd ${MFS_TREE} ; tar -cf - --exclude .svn . ) | \ + (cd ${MFS_TREE} ; tar -cf - --exclude .git --exclude .svn . ) | \ (cd ${dst} ; tar x${o_tarv}f - ) fi done diff --git a/release/picobsd/qemu/PICOBSD b/release/picobsd/qemu/PICOBSD index 16b175385b0a..f3a9f9ccaf28 100644 --- a/release/picobsd/qemu/PICOBSD +++ b/release/picobsd/qemu/PICOBSD @@ -56,7 +56,6 @@ device if_bridge # qemu, so we set HZ explicitly. options HZ=1000 -device random # used by ssh device pci # Floppy drives diff --git a/sbin/Makefile b/sbin/Makefile index 78c581e357a1..72da4c5bb058 100644 --- a/sbin/Makefile +++ b/sbin/Makefile @@ -79,8 +79,6 @@ SUBDIR.${MK_IPFILTER}+= ipf SUBDIR.${MK_IPFW}+= ipfw SUBDIR.${MK_IPFW}+= natd SUBDIR.${MK_ISCSI}+= iscontrol -SUBDIR.${MK_NAND}+= nandfs -SUBDIR.${MK_NAND}+= newfs_nandfs SUBDIR.${MK_NVME}+= nvmecontrol SUBDIR.${MK_OPENSSL}+= decryptcore SUBDIR.${MK_PF}+= pfctl diff --git a/sbin/bectl/bectl.c b/sbin/bectl/bectl.c index 366fa048a893..5119759deb97 100644 --- a/sbin/bectl/bectl.c +++ b/sbin/bectl/bectl.c @@ -184,7 +184,8 @@ bectl_cmd_activate(int argc, char *argv[]) static int bectl_cmd_create(int argc, char *argv[]) { - char *atpos, *bootenv, *snapname, *source; + char snapshot[BE_MAXPATHLEN]; + char *atpos, *bootenv, *snapname; int err, opt; bool recursive; @@ -214,6 +215,8 @@ bectl_cmd_create(int argc, char *argv[]) } bootenv = *argv; + + err = BE_ERR_SUCCESS; if ((atpos = strchr(bootenv, '@')) != NULL) { /* * This is the "create a snapshot variant". No new boot @@ -221,24 +224,22 @@ bectl_cmd_create(int argc, char *argv[]) */ *atpos++ = '\0'; err = be_snapshot(be, bootenv, atpos, recursive, NULL); - } else if (snapname != NULL) { - if (strchr(snapname, '@') != NULL) - err = be_create_from_existing_snap(be, bootenv, - snapname); - else - err = be_create_from_existing(be, bootenv, snapname); } else { - if ((snapname = strchr(bootenv, '@')) != NULL) { - *(snapname++) = '\0'; - if ((err = be_snapshot(be, be_active_path(be), - snapname, true, NULL)) != BE_ERR_SUCCESS) - fprintf(stderr, "failed to create snapshot\n"); - asprintf(&source, "%s@%s", be_active_path(be), snapname); - err = be_create_from_existing_snap(be, bootenv, - source); - return (err); - } else - err = be_create(be, bootenv); + if (snapname == NULL) + /* Create from currently booted BE */ + err = be_snapshot(be, be_active_path(be), NULL, + recursive, snapshot); + else if (strchr(snapname, '@') != NULL) + /* Create from given snapshot */ + strlcpy(snapshot, snapname, sizeof(snapshot)); + else + /* Create from given BE */ + err = be_snapshot(be, snapname, NULL, recursive, + snapshot); + + if (err == BE_ERR_SUCCESS) + err = be_create_depth(be, bootenv, snapshot, + recursive == true ? -1 : 0); } switch (err) { diff --git a/sbin/bectl/tests/bectl_test.sh b/sbin/bectl/tests/bectl_test.sh index 6d268c00b178..e551e501b790 100755 --- a/sbin/bectl/tests/bectl_test.sh +++ b/sbin/bectl/tests/bectl_test.sh @@ -99,11 +99,35 @@ bectl_create_body() mount=${cwd}/mnt bectl_create_setup ${zpool} ${disk} ${mount} + + # Create a child dataset that will be used to test creation + # of recursive and non-recursive boot environments. + atf_check zfs create -o mountpoint=/usr -o canmount=noauto \ + ${zpool}/ROOT/default/usr + # Test standard creation, creation of a snapshot, and creation from a # snapshot. atf_check bectl -r ${zpool}/ROOT create -e default default2 atf_check bectl -r ${zpool}/ROOT create default2@test_snap atf_check bectl -r ${zpool}/ROOT create -e default2@test_snap default3 + + # Test standard creation, creation of a snapshot, and creation from a + # snapshot for recursive boot environments. + atf_check bectl -r ${zpool}/ROOT create -r -e default recursive + atf_check bectl -r ${zpool}/ROOT create -r recursive@test_snap + atf_check bectl -r ${zpool}/ROOT create -r -e recursive@test_snap recursive-snap + + # Test that non-recursive boot environments have no child datasets. + atf_check -e not-empty -s not-exit:0 \ + zfs list "${zpool}/ROOT/default2/usr" + atf_check -e not-empty -s not-exit:0 \ + zfs list "${zpool}/ROOT/default3/usr" + + # Test that recursive boot environments have child datasets. + atf_check -o not-empty \ + zfs list "${zpool}/ROOT/recursive/usr" + atf_check -o not-empty \ + zfs list "${zpool}/ROOT/recursive-snap/usr" } bectl_create_cleanup() { diff --git a/sbin/camcontrol/camcontrol.c b/sbin/camcontrol/camcontrol.c index 0784fab75a0e..99d59e59d86c 100644 --- a/sbin/camcontrol/camcontrol.c +++ b/sbin/camcontrol/camcontrol.c @@ -2326,9 +2326,11 @@ ata_do_identify(struct cam_device *device, int retry_count, int timeout, } } + ident_buf = (struct ata_params *)ptr; + ata_param_fixup(ident_buf); + error = 1; for (i = 0; i < sizeof(struct ata_params) / 2; i++) { - ptr[i] = le16toh(ptr[i]); if (ptr[i] != 0) error = 0; } @@ -2346,26 +2348,6 @@ ata_do_identify(struct cam_device *device, int retry_count, int timeout, return (error); } - ident_buf = (struct ata_params *)ptr; - if (strncmp(ident_buf->model, "FX", 2) && - strncmp(ident_buf->model, "NEC", 3) && - strncmp(ident_buf->model, "Pioneer", 7) && - strncmp(ident_buf->model, "SHARP", 5)) { - ata_bswap(ident_buf->model, sizeof(ident_buf->model)); - ata_bswap(ident_buf->revision, sizeof(ident_buf->revision)); - ata_bswap(ident_buf->serial, sizeof(ident_buf->serial)); - ata_bswap(ident_buf->media_serial, sizeof(ident_buf->media_serial)); - } - ata_btrim(ident_buf->model, sizeof(ident_buf->model)); - ata_bpack(ident_buf->model, ident_buf->model, sizeof(ident_buf->model)); - ata_btrim(ident_buf->revision, sizeof(ident_buf->revision)); - ata_bpack(ident_buf->revision, ident_buf->revision, sizeof(ident_buf->revision)); - ata_btrim(ident_buf->serial, sizeof(ident_buf->serial)); - ata_bpack(ident_buf->serial, ident_buf->serial, sizeof(ident_buf->serial)); - ata_btrim(ident_buf->media_serial, sizeof(ident_buf->media_serial)); - ata_bpack(ident_buf->media_serial, ident_buf->media_serial, - sizeof(ident_buf->media_serial)); - *ident_bufp = ident_buf; return (0); diff --git a/sbin/dhclient/options.c b/sbin/dhclient/options.c index 3b05e3ff1889..dc4cceab8418 100644 --- a/sbin/dhclient/options.c +++ b/sbin/dhclient/options.c @@ -896,6 +896,5 @@ do_packet(struct interface_info *interface, struct dhcp_packet *packet, /* Free the data associated with the options. */ for (i = 0; i < 256; i++) - if (tp.options[i].len && tp.options[i].data) - free(tp.options[i].data); + free(tp.options[i].data); } diff --git a/sbin/dhclient/packet.c b/sbin/dhclient/packet.c index 2328d577386d..21726aaaeb84 100644 --- a/sbin/dhclient/packet.c +++ b/sbin/dhclient/packet.c @@ -183,7 +183,7 @@ decode_udp_ip_header(unsigned char *buf, int bufix, struct sockaddr_in *from, ip_packets_seen++; if (wrapsum(checksum(buf + bufix, ip_len, 0)) != 0) { ip_packets_bad_checksum++; - if (ip_packets_seen > 4 && + if (ip_packets_seen > 4 && ip_packets_bad_checksum != 0 && (ip_packets_seen / ip_packets_bad_checksum) < 2) { note("%d bad IP checksums seen in %d packets", ip_packets_bad_checksum, ip_packets_seen); @@ -235,7 +235,7 @@ decode_udp_ip_header(unsigned char *buf, int bufix, struct sockaddr_in *from, udp_packets_seen++; if (usum && usum != sum) { udp_packets_bad_checksum++; - if (udp_packets_seen > 4 && + if (udp_packets_seen > 4 && udp_packets_bad_checksum != 0 && (udp_packets_seen / udp_packets_bad_checksum) < 2) { note("%d bad udp checksums in %d packets", udp_packets_bad_checksum, udp_packets_seen); diff --git a/sbin/ipf/ipmon/Makefile b/sbin/ipf/ipmon/Makefile index 5d76a05ae44a..8227811db2ad 100644 --- a/sbin/ipf/ipmon/Makefile +++ b/sbin/ipf/ipmon/Makefile @@ -3,7 +3,8 @@ PACKAGE= ipf PROG= ipmon SRCS= ${GENHDRS} ipmon.c ipmon_y.c ipmon_l.c -MAN= ipmon.8 +MAN= ipmon.5 ipmon.8 +MLINKS= ipmon.5 ipmon.conf.5 CFLAGS+= -DLOGFAC=LOG_LOCAL0 -I. diff --git a/sbin/ipfw/ipfw.8 b/sbin/ipfw/ipfw.8 index fcba4a4b03f2..bcc8017a571b 100644 --- a/sbin/ipfw/ipfw.8 +++ b/sbin/ipfw/ipfw.8 @@ -1,7 +1,7 @@ .\" .\" $FreeBSD$ .\" -.Dd May 24, 2019 +.Dd June 21, 2019 .Dt IPFW 8 .Os .Sh NAME @@ -1989,6 +1989,12 @@ a non-zero offset. See the .Cm frag option for details on matching fragmented packets. +.It Cm tcpmss Ar tcpmss-list +Matches TCP packets whose MSS (maximum segment size) value is set to +.Ar tcpmss-list , +which is either a single value or a list of values or ranges +specified in the same way as +.Ar ports . .It Cm tcpseq Ar seq TCP packets only. Match if the TCP header sequence number field is set to diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c index 3e73fa3b8736..c2d89fcbf72f 100644 --- a/sbin/ipfw/ipfw2.c +++ b/sbin/ipfw/ipfw2.c @@ -338,6 +338,7 @@ static struct _s_x rule_options[] = { { "tcpdatalen", TOK_TCPDATALEN }, { "tcpflags", TOK_TCPFLAGS }, { "tcpflgs", TOK_TCPFLAGS }, + { "tcpmss", TOK_TCPMSS }, { "tcpoptions", TOK_TCPOPTS }, { "tcpopts", TOK_TCPOPTS }, { "tcpseq", TOK_TCPSEQ }, @@ -881,6 +882,7 @@ static struct _s_x _port_name[] = { {"ipttl", O_IPTTL}, {"mac-type", O_MAC_TYPE}, {"tcpdatalen", O_TCPDATALEN}, + {"tcpmss", O_TCPMSS}, {"tcpwin", O_TCPWIN}, {"tagged", O_TAGGED}, {NULL, 0} @@ -1588,6 +1590,7 @@ print_instruction(struct buf_pr *bp, const struct format_opts *fo, case O_IPTTL: case O_IPLEN: case O_TCPDATALEN: + case O_TCPMSS: case O_TCPWIN: if (F_LEN(cmd) == 1) { switch (cmd->opcode) { @@ -1603,6 +1606,9 @@ print_instruction(struct buf_pr *bp, const struct format_opts *fo, case O_TCPDATALEN: s = "tcpdatalen"; break; + case O_TCPMSS: + s = "tcpmss"; + break; case O_TCPWIN: s = "tcpwin"; break; @@ -2217,6 +2223,8 @@ show_static_rule(struct cmdline_opts *co, struct format_opts *fo, } print_proto(bp, fo, &state); + if (co->do_compact != 0 && (rule->flags & IPFW_RULE_NOOPT)) + goto justopts; /* Print source */ bprintf(bp, " from"); @@ -4389,6 +4397,8 @@ chkarg: } OR_BLOCK(get_proto); + first_cmd = cmd; /* update pointer to use in compact form */ + /* * "from", mandatory */ @@ -4460,6 +4470,8 @@ chkarg: cmd = next_cmd(cmd, &cblen); } } + if (first_cmd == cmd) + rule->flags |= IPFW_RULE_NOOPT; read_options: prev = NULL; @@ -4709,14 +4721,18 @@ read_options: av++; break; + case TOK_TCPMSS: case TOK_TCPWIN: - NEED1("tcpwin requires length"); + NEED1("tcpmss/tcpwin requires size"); if (strpbrk(*av, "-,")) { - if (!add_ports(cmd, *av, 0, O_TCPWIN, cblen)) - errx(EX_DATAERR, "invalid tcpwin len %s", *av); + if (add_ports(cmd, *av, 0, + i == TOK_TCPWIN ? O_TCPWIN : O_TCPMSS, + cblen) == NULL) + errx(EX_DATAERR, "invalid %s size %s", + s, *av); } else - fill_cmd(cmd, O_TCPWIN, 0, - strtoul(*av, NULL, 0)); + fill_cmd(cmd, i == TOK_TCPWIN ? O_TCPWIN : + O_TCPMSS, 0, strtoul(*av, NULL, 0)); av++; break; diff --git a/sbin/ipfw/ipfw2.h b/sbin/ipfw/ipfw2.h index e6c209d65bab..215416eecc8a 100644 --- a/sbin/ipfw/ipfw2.h +++ b/sbin/ipfw/ipfw2.h @@ -151,6 +151,7 @@ enum tokens { TOK_TCPOPTS, TOK_TCPSEQ, TOK_TCPACK, + TOK_TCPMSS, TOK_TCPWIN, TOK_ICMPTYPES, TOK_MAC, diff --git a/sbin/nandfs/Makefile b/sbin/nandfs/Makefile deleted file mode 100644 index 40af5775c510..000000000000 --- a/sbin/nandfs/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# $FreeBSD$ - -PACKAGE=nandfs -PROG= nandfs -SRCS= nandfs.c lssnap.c mksnap.c rmsnap.c -MAN= nandfs.8 - -LIBADD= nandfs - -.include <bsd.prog.mk> diff --git a/sbin/nandfs/Makefile.depend b/sbin/nandfs/Makefile.depend deleted file mode 100644 index 1269878d50ef..000000000000 --- a/sbin/nandfs/Makefile.depend +++ /dev/null @@ -1,18 +0,0 @@ -# $FreeBSD$ -# Autogenerated - do NOT edit! - -DIRDEPS = \ - gnu/lib/csu \ - include \ - include/xlocale \ - lib/${CSU_DIR} \ - lib/libc \ - lib/libcompiler_rt \ - lib/libnandfs \ - - -.include <dirdeps.mk> - -.if ${DEP_RELDIR} == ${_DEP_RELDIR} -# local dependencies - needed for -jN in clean tree -.endif diff --git a/sbin/nandfs/lssnap.c b/sbin/nandfs/lssnap.c deleted file mode 100644 index cb240fb1da84..000000000000 --- a/sbin/nandfs/lssnap.c +++ /dev/null @@ -1,114 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2012 The FreeBSD Foundation - * All rights reserved. - * - * This software was developed by Semihalf under sponsorship - * from the FreeBSD Foundation. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); -#include <sys/types.h> - -#include <stdio.h> -#include <stdlib.h> -#include <sysexits.h> -#include <time.h> - -#include <fs/nandfs/nandfs_fs.h> -#include <libnandfs.h> - -#include "nandfs.h" - -#define NCPINFO 512 - -static void -lssnap_usage(void) -{ - - fprintf(stderr, "usage:\n"); - fprintf(stderr, "\tlssnap node\n"); -} - -static void -print_cpinfo(struct nandfs_cpinfo *cpinfo) -{ - struct tm tm; - time_t t; - char timebuf[128]; - - t = (time_t)cpinfo->nci_create; - localtime_r(&t, &tm); - strftime(timebuf, sizeof(timebuf), "%F %T", &tm); - - printf("%20llu %s\n", (unsigned long long)cpinfo->nci_cno, timebuf); -} - -int -nandfs_lssnap(int argc, char **argv) -{ - struct nandfs_cpinfo *cpinfos; - struct nandfs fs; - uint64_t next; - int error, nsnap, i; - - if (argc != 1) { - lssnap_usage(); - return (EX_USAGE); - } - - cpinfos = malloc(sizeof(*cpinfos) * NCPINFO); - if (cpinfos == NULL) { - fprintf(stderr, "cannot allocate memory\n"); - return (-1); - } - - nandfs_init(&fs, argv[0]); - error = nandfs_open(&fs); - if (error == -1) { - fprintf(stderr, "nandfs_open: %s\n", nandfs_errmsg(&fs)); - goto out; - } - - for (next = 1; next != 0; next = cpinfos[nsnap - 1].nci_next) { - nsnap = nandfs_get_snap(&fs, next, cpinfos, NCPINFO); - if (nsnap < 1) - break; - - for (i = 0; i < nsnap; i++) - print_cpinfo(&cpinfos[i]); - } - - if (nsnap == -1) - fprintf(stderr, "nandfs_get_snap: %s\n", nandfs_errmsg(&fs)); - -out: - nandfs_close(&fs); - nandfs_destroy(&fs); - free(cpinfos); - return (error); -} diff --git a/sbin/nandfs/mksnap.c b/sbin/nandfs/mksnap.c deleted file mode 100644 index f75eda3834a9..000000000000 --- a/sbin/nandfs/mksnap.c +++ /dev/null @@ -1,82 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2012 The FreeBSD Foundation - * All rights reserved. - * - * This software was developed by Semihalf under sponsorship - * from the FreeBSD Foundation. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); -#include <sys/types.h> - -#include <stdio.h> -#include <sysexits.h> - -#include <fs/nandfs/nandfs_fs.h> -#include <libnandfs.h> - -#include "nandfs.h" - -static void -mksnap_usage(void) -{ - - fprintf(stderr, "usage:\n"); - fprintf(stderr, "\tmksnap node\n"); -} - -int -nandfs_mksnap(int argc, char **argv) -{ - struct nandfs fs; - uint64_t cpno; - int error; - - if (argc != 1) { - mksnap_usage(); - return (EX_USAGE); - } - - nandfs_init(&fs, argv[0]); - error = nandfs_open(&fs); - if (error == -1) { - fprintf(stderr, "nandfs_open: %s\n", nandfs_errmsg(&fs)); - goto out; - } - - error = nandfs_make_snap(&fs, &cpno); - if (error == -1) - fprintf(stderr, "nandfs_make_snap: %s\n", nandfs_errmsg(&fs)); - else - printf("%jd\n", cpno); - -out: - nandfs_close(&fs); - nandfs_destroy(&fs); - return (error); -} diff --git a/sbin/nandfs/nandfs.8 b/sbin/nandfs/nandfs.8 deleted file mode 100644 index 9995905d3c68..000000000000 --- a/sbin/nandfs/nandfs.8 +++ /dev/null @@ -1,79 +0,0 @@ -.\" -.\" Copyright (c) 2012 The FreeBSD Foundation -.\" All rights reserved. -.\" -.\" This software was developed by Semihalf under sponsorship -.\" from the FreeBSD Foundation. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" -.\" $FreeBSD$ -.\" -.Dd September 10, 2016 -.Dt NANDFS 8 -.Os -.Sh NAME -.Nm nandfs -.Nd manage mounted NAND FS -.Sh SYNOPSIS -.Nm -.Cm lssnap -.Ar node -.Nm -.Cm mksnap -.Ar node -.Nm -.Cm rmsnap -.Ar snapshot node -.Sh DESCRIPTION -The -.Nm -utility allows the management of snapshots on a mounted NAND FS. -.Sh EXAMPLES -Create a snapshot of filesystem mounted on -.Em /nand . -.Bd -literal -offset 2n -.Li # Ic nandfs mksnap /nand -1 -.Ed -.Pp -List snapshots of filesystem mounted on -.Em /nand . -.Bd -literal -offset 2n -.Li # Ic nandfs lssnap /nand -1 2012-02-28 18:49:45 ss 138 2 -.Ed -.Pp -Remove snapshot 1 of filesystem mounted on -.Em /nand . -.Bd -literal -offset 2n -.Li # Ic nandfs rmsnap 1 /nand -.Ed -.Sh HISTORY -The -.Nm -utility appeared in -.Fx 10.0 . -.Sh AUTHORS -This utility and manual page were written by -.An Mateusz Guzik . diff --git a/sbin/nandfs/nandfs.c b/sbin/nandfs/nandfs.c deleted file mode 100644 index b319b58bc5c1..000000000000 --- a/sbin/nandfs/nandfs.c +++ /dev/null @@ -1,76 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2012 The FreeBSD Foundation - * All rights reserved. - * - * This software was developed by Semihalf under sponsorship - * from the FreeBSD Foundation. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <err.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sysexits.h> - -#include "nandfs.h" - -static void -usage(void) -{ - - fprintf(stderr, "usage: nandfs [lssnap | mksnap | rmsnap <snap>] " - "node\n"); - exit(1); -} - -int -main(int argc, char **argv) -{ - int error = 0; - char *cmd; - - if (argc < 2) - usage(); - - cmd = argv[1]; - argc -= 2; - argv += 2; - - if (strcmp(cmd, "lssnap") == 0) - error = nandfs_lssnap(argc, argv); - else if (strcmp(cmd, "mksnap") == 0) - error = nandfs_mksnap(argc, argv); - else if (strcmp(cmd, "rmsnap") == 0) - error = nandfs_rmsnap(argc, argv); - else - usage(); - - return (error); -} diff --git a/sbin/nandfs/nandfs.h b/sbin/nandfs/nandfs.h deleted file mode 100644 index 993d9338e904..000000000000 --- a/sbin/nandfs/nandfs.h +++ /dev/null @@ -1,42 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2012 The FreeBSD Foundation - * All rights reserved. - * - * This software was developed by Semihalf under sponsorship - * from the FreeBSD Foundation. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef NANDFS_H -#define NANDFS_H - -int nandfs_lssnap(int, char **); -int nandfs_mksnap(int, char **); -int nandfs_rmsnap(int, char **); - -#endif /* !NANDFS_H */ diff --git a/sbin/nandfs/rmsnap.c b/sbin/nandfs/rmsnap.c deleted file mode 100644 index c07439d694ef..000000000000 --- a/sbin/nandfs/rmsnap.c +++ /dev/null @@ -1,89 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2012 The FreeBSD Foundation - * All rights reserved. - * - * This software was developed by Semihalf under sponsorship - * from the FreeBSD Foundation. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); -#include <sys/types.h> - -#include <stdio.h> -#include <stdlib.h> -#include <limits.h> -#include <sysexits.h> - -#include <fs/nandfs/nandfs_fs.h> -#include <libnandfs.h> - -#include "nandfs.h" - -static void -rmsnap_usage(void) -{ - - fprintf(stderr, "usage:\n"); - fprintf(stderr, "\trmsnap snap node\n"); -} - -int -nandfs_rmsnap(int argc, char **argv) -{ - struct nandfs fs; - uint64_t cpno; - int error; - - if (argc != 2) { - rmsnap_usage(); - return (EX_USAGE); - } - - cpno = strtoll(argv[0], (char **)NULL, 10); - if (cpno == 0) { - fprintf(stderr, "%s must be a number greater than 0\n", - argv[0]); - return (EX_USAGE); - } - - nandfs_init(&fs, argv[1]); - error = nandfs_open(&fs); - if (error == -1) { - fprintf(stderr, "nandfs_open: %s\n", nandfs_errmsg(&fs)); - goto out; - } - - error = nandfs_delete_snap(&fs, cpno); - if (error == -1) - fprintf(stderr, "nandfs_delete_snap: %s\n", nandfs_errmsg(&fs)); - -out: - nandfs_close(&fs); - nandfs_destroy(&fs); - return (error); -} diff --git a/sbin/newfs_nandfs/Makefile b/sbin/newfs_nandfs/Makefile deleted file mode 100644 index 9b1b3009c400..000000000000 --- a/sbin/newfs_nandfs/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# $FreeBSD$ - -PACKAGE=nandfs -PROG= newfs_nandfs -MAN= newfs_nandfs.8 - -LIBADD= geom - -.include <bsd.prog.mk> diff --git a/sbin/newfs_nandfs/Makefile.depend b/sbin/newfs_nandfs/Makefile.depend deleted file mode 100644 index 0220673c9076..000000000000 --- a/sbin/newfs_nandfs/Makefile.depend +++ /dev/null @@ -1,20 +0,0 @@ -# $FreeBSD$ -# Autogenerated - do NOT edit! - -DIRDEPS = \ - gnu/lib/csu \ - include \ - include/xlocale \ - lib/${CSU_DIR} \ - lib/libc \ - lib/libcompiler_rt \ - lib/libexpat \ - lib/libgeom \ - lib/libsbuf \ - - -.include <dirdeps.mk> - -.if ${DEP_RELDIR} == ${_DEP_RELDIR} -# local dependencies - needed for -jN in clean tree -.endif diff --git a/sbin/newfs_nandfs/newfs_nandfs.8 b/sbin/newfs_nandfs/newfs_nandfs.8 deleted file mode 100644 index fe3216394109..000000000000 --- a/sbin/newfs_nandfs/newfs_nandfs.8 +++ /dev/null @@ -1,74 +0,0 @@ -.\" -.\" Copyright (c) 2010 Semihalf -.\" 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 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 October 1, 2013 -.Dt NEWFS_NANDFS 8 -.Os -.Sh NAME -.Nm newfs_nandfs -.Nd construct a new NAND FS file system -.Sh SYNOPSIS -.Nm -.Op Fl b Ar blocsize -.Op Fl B Ar blocks-per-segment -.Op Fl L Ar label -.Op Fl m Ar reserved-segment-percent -.Ar device -.Sh DESCRIPTION -The -.Nm -utility creates a NAND FS file system on device. -.Pp -The options are as follow: -.Bl -tag -width indent -.It Fl b Ar blocksize -Size of block (1024 if not specified). -.It Fl B Ar blocks_per_segment -Number of blocks per segment (2048 if not specified). -.It Fl L Ar label -Volume label (up to 16 characters). -.It Fl m Ar reserved_block_percent -Percentage of reserved blocks (5 if not specified). -.El -.Sh EXIT STATUS -Exit status is 0 on success and 1 on error. -.Sh EXAMPLES -Create a file system, using default parameters, on -.Pa /dev/ada0s1 : -.Bd -literal -offset indent -newfs_nandfs /dev/ada0s1 -.Ed -.Sh SEE ALSO -.Xr gpart 8 , -.Xr newfs 8 -.Sh HISTORY -The -.Nm -utility first appeared in -.Fx 10.0 . -.Sh AUTHORS -.An Grzegorz Bernacki diff --git a/sbin/newfs_nandfs/newfs_nandfs.c b/sbin/newfs_nandfs/newfs_nandfs.c deleted file mode 100644 index e432cc6e6420..000000000000 --- a/sbin/newfs_nandfs/newfs_nandfs.c +++ /dev/null @@ -1,1183 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/fdcio.h> -#include <sys/disk.h> -#include <sys/disklabel.h> -#include <sys/mount.h> -#include <sys/stat.h> -#include <sys/time.h> -#include <sys/endian.h> -#include <sys/stddef.h> -#include <sys/uuid.h> -#include <sys/dirent.h> -#include <sys/stat.h> - -#include <ctype.h> -#include <err.h> -#include <errno.h> -#include <fcntl.h> -#include <inttypes.h> -#include <libgeom.h> -#include <paths.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#include <unistd.h> - -#include <fs/nandfs/nandfs_fs.h> -#include <dev/nand/nand_dev.h> - -#define DEBUG -#undef DEBUG -#ifdef DEBUG -#define debug(fmt, args...) do { \ - printf("nandfs:" fmt "\n", ##args); } while (0) -#else -#define debug(fmt, args...) -#endif - -#define NANDFS_FIRST_BLOCK nandfs_first_block() -#define NANDFS_FIRST_CNO 1 -#define NANDFS_BLOCK_BAD 1 -#define NANDFS_BLOCK_GOOD 0 - -struct file_info { - uint64_t ino; - const char *name; - uint32_t mode; - uint64_t size; - uint8_t nblocks; - uint32_t *blocks; - struct nandfs_inode *inode; -}; - -static struct file_info user_files[] = { - { NANDFS_ROOT_INO, NULL, S_IFDIR | 0755, 0, 1, NULL, NULL }, -}; - -static struct file_info ifile = - { NANDFS_IFILE_INO, NULL, 0, 0, -1, NULL, NULL }; -static struct file_info sufile = - { NANDFS_SUFILE_INO, NULL, 0, 0, -1, NULL, NULL }; -static struct file_info cpfile = - { NANDFS_CPFILE_INO, NULL, 0, 0, -1, NULL, NULL }; -static struct file_info datfile = - { NANDFS_DAT_INO, NULL, 0, 0, -1, NULL, NULL }; - -struct nandfs_block { - LIST_ENTRY(nandfs_block) block_link; - uint32_t number; - uint64_t offset; - void *data; -}; - -static LIST_HEAD(, nandfs_block) block_head = - LIST_HEAD_INITIALIZER(&block_head); - -/* Storage geometry */ -static off_t mediasize; -static ssize_t sectorsize; -static uint64_t nsegments; -static uint64_t erasesize; -static uint64_t segsize; - -static struct nandfs_fsdata fsdata; -static struct nandfs_super_block super_block; - -static int is_nand; - -/* Nandfs parameters */ -static size_t blocksize = NANDFS_DEF_BLOCKSIZE; -static long blocks_per_segment; -static long rsv_segment_percent = 5; -static time_t nandfs_time; -static uint32_t bad_segments_count = 0; -static uint32_t *bad_segments = NULL; -static uint8_t fsdata_blocks_state[NANDFS_NFSAREAS]; - -static u_char *volumelabel = NULL; - -static struct nandfs_super_root *sr; - -static uint32_t nuserfiles; -static uint32_t seg_nblocks; -static uint32_t seg_endblock; - -#define SIZE_TO_BLOCK(size) howmany(size, blocksize) - -static uint32_t -nandfs_first_block(void) -{ - uint32_t i, first_free, start_bad_segments = 0; - - for (i = 0; i < bad_segments_count; i++) { - if (i == bad_segments[i]) - start_bad_segments++; - else - break; - } - - first_free = SIZE_TO_BLOCK(NANDFS_DATA_OFFSET_BYTES(erasesize) + - (start_bad_segments * segsize)); - - if (first_free < (uint32_t)blocks_per_segment) - return (blocks_per_segment); - else - return (first_free); -} - -static void -usage(void) -{ - - fprintf(stderr, - "usage: newfs_nandfs [ -options ] device\n" - "where the options are:\n" - "\t-b block-size\n" - "\t-B blocks-per-segment\n" - "\t-L volume label\n" - "\t-m reserved-segments-percentage\n"); - exit(1); -} - -static int -nandfs_log2(unsigned n) -{ - unsigned count; - - /* - * N.B. this function will return 0 if supplied 0. - */ - for (count = 0; n/2; count++) - n /= 2; - return count; -} - -/* from NetBSD's src/sys/net/if_ethersubr.c */ -static uint32_t -crc32_le(uint32_t crc, const uint8_t *buf, size_t len) -{ - static const uint32_t crctab[] = { - 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, - 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, - 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, - 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c - }; - size_t i; - - crc = crc ^ ~0U; - - for (i = 0; i < len; i++) { - crc ^= buf[i]; - crc = (crc >> 4) ^ crctab[crc & 0xf]; - crc = (crc >> 4) ^ crctab[crc & 0xf]; - } - - return (crc ^ ~0U); -} - -static void * -get_block(uint32_t block_nr, uint64_t offset) -{ - struct nandfs_block *block, *new_block; - - LIST_FOREACH(block, &block_head, block_link) { - if (block->number == block_nr) - return block->data; - } - - debug("allocating block %x\n", block_nr); - - new_block = malloc(sizeof(*block)); - if (!new_block) - err(1, "cannot allocate block"); - - new_block->number = block_nr; - new_block->offset = offset; - new_block->data = malloc(blocksize); - if (!new_block->data) - err(1, "cannot allocate block data"); - - memset(new_block->data, 0, blocksize); - - LIST_INSERT_HEAD(&block_head, new_block, block_link); - - return (new_block->data); -} - -static int -nandfs_seg_usage_blk_offset(uint64_t seg, uint64_t *blk, uint64_t *offset) -{ - uint64_t off; - uint16_t seg_size; - - seg_size = sizeof(struct nandfs_segment_usage); - - off = roundup(sizeof(struct nandfs_sufile_header), seg_size); - off += (seg * seg_size); - - *blk = off / blocksize; - *offset = (off % blocksize) / seg_size; - return (0); -} - -static uint32_t -segment_size(void) -{ - u_int size; - - size = sizeof(struct nandfs_segment_summary ); - size += seg_nblocks * sizeof(struct nandfs_binfo_v); - - if (size > blocksize) - err(1, "segsum info bigger that blocksize"); - - return (size); -} - - -static void -prepare_blockgrouped_file(uint32_t block) -{ - struct nandfs_block_group_desc *desc; - uint32_t i, entries; - - desc = (struct nandfs_block_group_desc *)get_block(block, 0); - entries = blocksize / sizeof(struct nandfs_block_group_desc); - for (i = 0; i < entries; i++) - desc[i].bg_nfrees = blocksize * 8; -} - -static void -alloc_blockgrouped_file(uint32_t block, uint32_t entry) -{ - struct nandfs_block_group_desc *desc; - uint32_t desc_nr; - uint32_t *bitmap; - - desc = (struct nandfs_block_group_desc *)get_block(block, 0); - bitmap = (uint32_t *)get_block(block + 1, 1); - - bitmap += (entry >> 5); - if (*bitmap & (1 << (entry % 32))) { - printf("nandfs: blockgrouped entry %d already allocated\n", - entry); - } - *bitmap |= (1 << (entry % 32)); - - desc_nr = entry / (blocksize * 8); - desc[desc_nr].bg_nfrees--; -} - - -static uint64_t -count_su_blocks(void) -{ - uint64_t maxblk, blk, offset, i; - - maxblk = blk = 0; - - for (i = 0; i < bad_segments_count; i++) { - nandfs_seg_usage_blk_offset(bad_segments[i], &blk, &offset); - debug("bad segment at block:%jx off: %jx", blk, offset); - if (blk > maxblk) - maxblk = blk; - } - - debug("bad segment needs %#jx", blk); - if (blk >= NANDFS_NDADDR) { - printf("nandfs: file too big (%jd > %d)\n", blk, NANDFS_NDADDR); - exit(2); - } - - sufile.size = (blk + 1) * blocksize; - return (blk + 1); -} - -static void -count_seg_blocks(void) -{ - uint32_t i; - - for (i = 0; i < nuserfiles; i++) - if (user_files[i].nblocks) { - seg_nblocks += user_files[i].nblocks; - user_files[i].blocks = malloc(user_files[i].nblocks * sizeof(uint32_t)); - } - - ifile.nblocks = 2 + - SIZE_TO_BLOCK(sizeof(struct nandfs_inode) * (NANDFS_USER_INO + 1)); - ifile.blocks = malloc(ifile.nblocks * sizeof(uint32_t)); - seg_nblocks += ifile.nblocks; - - cpfile.nblocks = - SIZE_TO_BLOCK((NANDFS_CPFILE_FIRST_CHECKPOINT_OFFSET + 1) * - sizeof(struct nandfs_checkpoint)); - cpfile.blocks = malloc(cpfile.nblocks * sizeof(uint32_t)); - seg_nblocks += cpfile.nblocks; - - if (!bad_segments) { - sufile.nblocks = - SIZE_TO_BLOCK((NANDFS_SUFILE_FIRST_SEGMENT_USAGE_OFFSET + 1) * - sizeof(struct nandfs_segment_usage)); - } else { - debug("bad blocks found: extra space for sufile"); - sufile.nblocks = count_su_blocks(); - } - - sufile.blocks = malloc(sufile.nblocks * sizeof(uint32_t)); - seg_nblocks += sufile.nblocks; - - datfile.nblocks = 2 + - SIZE_TO_BLOCK((seg_nblocks) * sizeof(struct nandfs_dat_entry)); - datfile.blocks = malloc(datfile.nblocks * sizeof(uint32_t)); - seg_nblocks += datfile.nblocks; -} - -static void -assign_file_blocks(uint64_t start_block) -{ - uint32_t i, j; - - for (i = 0; i < nuserfiles; i++) - for (j = 0; j < user_files[i].nblocks; j++) { - debug("user file %d at block %d at %#jx", - i, j, (uintmax_t)start_block); - user_files[i].blocks[j] = start_block++; - } - - for (j = 0; j < ifile.nblocks; j++) { - debug("ifile block %d at %#jx", j, (uintmax_t)start_block); - ifile.blocks[j] = start_block++; - } - - for (j = 0; j < cpfile.nblocks; j++) { - debug("cpfile block %d at %#jx", j, (uintmax_t)start_block); - cpfile.blocks[j] = start_block++; - } - - for (j = 0; j < sufile.nblocks; j++) { - debug("sufile block %d at %#jx", j, (uintmax_t)start_block); - sufile.blocks[j] = start_block++; - } - - for (j = 0; j < datfile.nblocks; j++) { - debug("datfile block %d at %#jx", j, (uintmax_t)start_block); - datfile.blocks[j] = start_block++; - } - - /* add one for superroot */ - debug("sr at block %#jx", (uintmax_t)start_block); - sr = (struct nandfs_super_root *)get_block(start_block++, 0); - seg_endblock = start_block; -} - -static void -save_datfile(void) -{ - - prepare_blockgrouped_file(datfile.blocks[0]); -} - -static uint64_t -update_datfile(uint64_t block) -{ - struct nandfs_dat_entry *dat; - static uint64_t vblock = 0; - uint64_t allocated, i, off; - - if (vblock == 0) { - alloc_blockgrouped_file(datfile.blocks[0], vblock); - vblock++; - } - allocated = vblock; - i = vblock / (blocksize / sizeof(*dat)); - off = vblock % (blocksize / sizeof(*dat)); - vblock++; - - dat = (struct nandfs_dat_entry *)get_block(datfile.blocks[2 + i], 2 + i); - - alloc_blockgrouped_file(datfile.blocks[0], allocated); - dat[off].de_blocknr = block; - dat[off].de_start = NANDFS_FIRST_CNO; - dat[off].de_end = UINTMAX_MAX; - - return (allocated); -} - -static union nandfs_binfo * -update_block_info(union nandfs_binfo *binfo, struct file_info *file) -{ - nandfs_daddr_t vblock; - uint32_t i; - - for (i = 0; i < file->nblocks; i++) { - debug("%s: blk %x", __func__, i); - if (file->ino != NANDFS_DAT_INO) { - vblock = update_datfile(file->blocks[i]); - binfo->bi_v.bi_vblocknr = vblock; - binfo->bi_v.bi_blkoff = i; - binfo->bi_v.bi_ino = file->ino; - file->inode->i_db[i] = vblock; - } else { - binfo->bi_dat.bi_blkoff = i; - binfo->bi_dat.bi_ino = file->ino; - file->inode->i_db[i] = datfile.blocks[i]; - } - binfo++; - } - - return (binfo); -} - -static void -save_segsum(struct nandfs_segment_summary *ss) -{ - union nandfs_binfo *binfo; - struct nandfs_block *block; - uint32_t sum_bytes, i; - uint8_t crc_data, crc_skip; - - sum_bytes = segment_size(); - ss->ss_magic = NANDFS_SEGSUM_MAGIC; - ss->ss_bytes = sizeof(struct nandfs_segment_summary); - ss->ss_flags = NANDFS_SS_LOGBGN | NANDFS_SS_LOGEND | NANDFS_SS_SR; - ss->ss_seq = 1; - ss->ss_create = nandfs_time; - - ss->ss_next = nandfs_first_block() + blocks_per_segment; - /* nblocks = segment blocks + segsum block + superroot */ - ss->ss_nblocks = seg_nblocks + 2; - ss->ss_nbinfos = seg_nblocks; - ss->ss_sumbytes = sum_bytes; - - crc_skip = sizeof(ss->ss_datasum) + sizeof(ss->ss_sumsum); - ss->ss_sumsum = crc32_le(0, (uint8_t *)ss + crc_skip, - sum_bytes - crc_skip); - crc_data = 0; - - binfo = (union nandfs_binfo *)(ss + 1); - for (i = 0; i < nuserfiles; i++) { - if (user_files[i].nblocks) - binfo = update_block_info(binfo, &user_files[i]); - } - - binfo = update_block_info(binfo, &ifile); - binfo = update_block_info(binfo, &cpfile); - binfo = update_block_info(binfo, &sufile); - update_block_info(binfo, &datfile); - - /* save superroot crc */ - crc_skip = sizeof(sr->sr_sum); - sr->sr_sum = crc32_le(0, (uint8_t *)sr + crc_skip, - NANDFS_SR_BYTES - crc_skip); - - /* segment checksup */ - crc_skip = sizeof(ss->ss_datasum); - LIST_FOREACH(block, &block_head, block_link) { - if (block->number < NANDFS_FIRST_BLOCK) - continue; - if (block->number == NANDFS_FIRST_BLOCK) - crc_data = crc32_le(0, - (uint8_t *)block->data + crc_skip, - blocksize - crc_skip); - else - crc_data = crc32_le(crc_data, (uint8_t *)block->data, - blocksize); - } - ss->ss_datasum = crc_data; -} - -static void -create_fsdata(void) -{ - struct uuid tmp; - - memset(&fsdata, 0, sizeof(struct nandfs_fsdata)); - - fsdata.f_magic = NANDFS_FSDATA_MAGIC; - fsdata.f_nsegments = nsegments; - fsdata.f_erasesize = erasesize; - fsdata.f_first_data_block = NANDFS_FIRST_BLOCK; - fsdata.f_blocks_per_segment = blocks_per_segment; - fsdata.f_r_segments_percentage = rsv_segment_percent; - fsdata.f_rev_level = NANDFS_CURRENT_REV; - fsdata.f_sbbytes = NANDFS_SB_BYTES; - fsdata.f_bytes = NANDFS_FSDATA_CRC_BYTES; - fsdata.f_ctime = nandfs_time; - fsdata.f_log_block_size = nandfs_log2(blocksize) - 10; - fsdata.f_errors = 1; - fsdata.f_inode_size = sizeof(struct nandfs_inode); - fsdata.f_dat_entry_size = sizeof(struct nandfs_dat_entry); - fsdata.f_checkpoint_size = sizeof(struct nandfs_checkpoint); - fsdata.f_segment_usage_size = sizeof(struct nandfs_segment_usage); - - uuidgen(&tmp, 1); - fsdata.f_uuid = tmp; - - if (volumelabel) - memcpy(fsdata.f_volume_name, volumelabel, 16); - - fsdata.f_sum = crc32_le(0, (const uint8_t *)&fsdata, - NANDFS_FSDATA_CRC_BYTES); -} - -static void -save_fsdata(void *data) -{ - - memcpy(data, &fsdata, sizeof(fsdata)); -} - -static void -create_super_block(void) -{ - - memset(&super_block, 0, sizeof(struct nandfs_super_block)); - - super_block.s_magic = NANDFS_SUPER_MAGIC; - super_block.s_last_cno = NANDFS_FIRST_CNO; - super_block.s_last_pseg = NANDFS_FIRST_BLOCK; - super_block.s_last_seq = 1; - super_block.s_free_blocks_count = - (nsegments - bad_segments_count) * blocks_per_segment; - super_block.s_mtime = 0; - super_block.s_wtime = nandfs_time; - super_block.s_state = NANDFS_VALID_FS; - - super_block.s_sum = crc32_le(0, (const uint8_t *)&super_block, - NANDFS_SB_BYTES); -} - -static void -save_super_block(void *data) -{ - - memcpy(data, &super_block, sizeof(super_block)); -} - -static void -save_super_root(void) -{ - - sr->sr_bytes = NANDFS_SR_BYTES; - sr->sr_flags = 0; - sr->sr_nongc_ctime = nandfs_time; - datfile.inode = &sr->sr_dat; - cpfile.inode = &sr->sr_cpfile; - sufile.inode = &sr->sr_sufile; -} - -static struct nandfs_dir_entry * -add_de(void *block, struct nandfs_dir_entry *de, uint64_t ino, - const char *name, uint8_t type) -{ - uint16_t reclen; - - /* modify last de */ - de->rec_len = NANDFS_DIR_REC_LEN(de->name_len); - de = (void *)((uint8_t *)de + de->rec_len); - - reclen = blocksize - ((uintptr_t)de - (uintptr_t)block); - if (reclen < NANDFS_DIR_REC_LEN(strlen(name))) { - printf("nandfs: too many dir entries for one block\n"); - return (NULL); - } - - de->inode = ino; - de->rec_len = reclen; - de->name_len = strlen(name); - de->file_type = type; - memset(de->name, 0, - (strlen(name) + NANDFS_DIR_PAD - 1) & ~NANDFS_DIR_ROUND); - memcpy(de->name, name, strlen(name)); - - return (de); -} - -static struct nandfs_dir_entry * -make_dir(void *block, uint64_t ino, uint64_t parent_ino) -{ - struct nandfs_dir_entry *de = (struct nandfs_dir_entry *)block; - - /* create '..' entry */ - de->inode = parent_ino; - de->rec_len = NANDFS_DIR_REC_LEN(2); - de->name_len = 2; - de->file_type = DT_DIR; - memset(de->name, 0, NANDFS_DIR_NAME_LEN(2)); - memcpy(de->name, "..", 2); - - /* create '.' entry */ - de = (void *)((uint8_t *)block + NANDFS_DIR_REC_LEN(2)); - de->inode = ino; - de->rec_len = blocksize - NANDFS_DIR_REC_LEN(2); - de->name_len = 1; - de->file_type = DT_DIR; - memset(de->name, 0, NANDFS_DIR_NAME_LEN(1)); - memcpy(de->name, ".", 1); - - return (de); -} - -static void -save_root_dir(void) -{ - struct file_info *root = &user_files[0]; - struct nandfs_dir_entry *de; - uint32_t i; - void *block; - - block = get_block(root->blocks[0], 0); - - de = make_dir(block, root->ino, root->ino); - for (i = 1; i < nuserfiles; i++) - de = add_de(block, de, user_files[i].ino, user_files[i].name, - IFTODT(user_files[i].mode)); - - root->size = ((uintptr_t)de - (uintptr_t)block) + - NANDFS_DIR_REC_LEN(de->name_len); -} - -static void -save_sufile(void) -{ - struct nandfs_sufile_header *header; - struct nandfs_segment_usage *su; - uint64_t blk, i, off; - void *block; - int start; - - /* - * At the beginning just zero-out everything - */ - for (i = 0; i < sufile.nblocks; i++) - get_block(sufile.blocks[i], 0); - - start = 0; - - block = get_block(sufile.blocks[start], 0); - header = (struct nandfs_sufile_header *)block; - header->sh_ncleansegs = nsegments - bad_segments_count - 1; - header->sh_ndirtysegs = 1; - header->sh_last_alloc = 1; - - su = (struct nandfs_segment_usage *)header; - off = NANDFS_SUFILE_FIRST_SEGMENT_USAGE_OFFSET; - /* Allocate data segment */ - su[off].su_lastmod = nandfs_time; - /* nblocks = segment blocks + segsum block + superroot */ - su[off].su_nblocks = seg_nblocks + 2; - su[off].su_flags = NANDFS_SEGMENT_USAGE_DIRTY; - off++; - /* Allocate next segment */ - su[off].su_lastmod = nandfs_time; - su[off].su_nblocks = 0; - su[off].su_flags = NANDFS_SEGMENT_USAGE_DIRTY; - for (i = 0; i < bad_segments_count; i++) { - nandfs_seg_usage_blk_offset(bad_segments[i], &blk, &off); - debug("storing bad_segments[%jd]=%x at %jx off %jx\n", i, - bad_segments[i], blk, off); - block = get_block(sufile.blocks[blk], - off * sizeof(struct nandfs_segment_usage *)); - su = (struct nandfs_segment_usage *)block; - su[off].su_lastmod = nandfs_time; - su[off].su_nblocks = 0; - su[off].su_flags = NANDFS_SEGMENT_USAGE_ERROR; - } -} - -static void -save_cpfile(void) -{ - struct nandfs_cpfile_header *header; - struct nandfs_checkpoint *cp, *initial_cp; - int i, entries = blocksize / sizeof(struct nandfs_checkpoint); - uint64_t cno; - - header = (struct nandfs_cpfile_header *)get_block(cpfile.blocks[0], 0); - header->ch_ncheckpoints = 1; - header->ch_nsnapshots = 0; - - cp = (struct nandfs_checkpoint *)header; - - /* fill first checkpoint data*/ - initial_cp = &cp[NANDFS_CPFILE_FIRST_CHECKPOINT_OFFSET]; - initial_cp->cp_flags = 0; - initial_cp->cp_checkpoints_count = 0; - initial_cp->cp_cno = NANDFS_FIRST_CNO; - initial_cp->cp_create = nandfs_time; - initial_cp->cp_nblk_inc = seg_endblock - 1; - initial_cp->cp_blocks_count = seg_nblocks; - memset(&initial_cp->cp_snapshot_list, 0, - sizeof(struct nandfs_snapshot_list)); - - ifile.inode = &initial_cp->cp_ifile_inode; - - /* mark rest of cp as invalid */ - cno = NANDFS_FIRST_CNO + 1; - i = NANDFS_CPFILE_FIRST_CHECKPOINT_OFFSET + 1; - for (; i < entries; i++) { - cp[i].cp_cno = cno++; - cp[i].cp_flags = NANDFS_CHECKPOINT_INVALID; - } -} - -static void -init_inode(struct nandfs_inode *inode, struct file_info *file) -{ - - inode->i_blocks = file->nblocks; - inode->i_ctime = nandfs_time; - inode->i_mtime = nandfs_time; - inode->i_mode = file->mode & 0xffff; - inode->i_links_count = 1; - - if (file->size > 0) - inode->i_size = file->size; - else - inode->i_size = 0; - - if (file->ino == NANDFS_USER_INO) - inode->i_flags = SF_NOUNLINK|UF_NOUNLINK; - else - inode->i_flags = 0; -} - -static void -save_ifile(void) -{ - struct nandfs_inode *inode; - struct file_info *file; - uint64_t ino, blk, off; - uint32_t i; - - prepare_blockgrouped_file(ifile.blocks[0]); - for (i = 0; i <= NANDFS_USER_INO; i++) - alloc_blockgrouped_file(ifile.blocks[0], i); - - for (i = 0; i < nuserfiles; i++) { - file = &user_files[i]; - ino = file->ino; - blk = ino / (blocksize / sizeof(*inode)); - off = ino % (blocksize / sizeof(*inode)); - inode = - (struct nandfs_inode *)get_block(ifile.blocks[2 + blk], 2 + blk); - file->inode = &inode[off]; - init_inode(file->inode, file); - } - - init_inode(ifile.inode, &ifile); - init_inode(cpfile.inode, &cpfile); - init_inode(sufile.inode, &sufile); - init_inode(datfile.inode, &datfile); -} - -static int -create_fs(void) -{ - uint64_t start_block; - uint32_t segsum_size; - char *data; - int i; - - nuserfiles = nitems(user_files); - - /* Count and assign blocks */ - count_seg_blocks(); - segsum_size = segment_size(); - start_block = NANDFS_FIRST_BLOCK + SIZE_TO_BLOCK(segsum_size); - assign_file_blocks(start_block); - - /* Create super root structure */ - save_super_root(); - - /* Create root directory */ - save_root_dir(); - - /* Fill in file contents */ - save_sufile(); - save_cpfile(); - save_ifile(); - save_datfile(); - - /* Save fsdata and superblocks */ - create_fsdata(); - create_super_block(); - - for (i = 0; i < NANDFS_NFSAREAS; i++) { - if (fsdata_blocks_state[i] != NANDFS_BLOCK_GOOD) - continue; - - data = get_block((i * erasesize)/blocksize, 0); - save_fsdata(data); - - data = get_block((i * erasesize + NANDFS_SBLOCK_OFFSET_BYTES) / - blocksize, 0); - if (blocksize > NANDFS_SBLOCK_OFFSET_BYTES) - data += NANDFS_SBLOCK_OFFSET_BYTES; - save_super_block(data); - memset(data + sizeof(struct nandfs_super_block), 0xff, - (blocksize - sizeof(struct nandfs_super_block) - - NANDFS_SBLOCK_OFFSET_BYTES)); - } - - /* Save segment summary and CRCs */ - save_segsum(get_block(NANDFS_FIRST_BLOCK, 0)); - - return (0); -} - -static void -write_fs(int fda) -{ - struct nandfs_block *block; - char *data; - u_int ret; - - /* Overwrite next block with ff if not nand device */ - if (!is_nand) { - data = get_block(seg_endblock, 0); - memset(data, 0xff, blocksize); - } - - LIST_FOREACH(block, &block_head, block_link) { - lseek(fda, block->number * blocksize, SEEK_SET); - ret = write(fda, block->data, blocksize); - if (ret != blocksize) - err(1, "cannot write filesystem data"); - } -} - -static void -check_parameters(void) -{ - int i; - - /* check blocksize */ - if ((blocksize < NANDFS_MIN_BLOCKSIZE) || (blocksize > MAXBSIZE) || - ((blocksize - 1) & blocksize)) { - errx(1, "Bad blocksize (%zu). Must be in range [%u-%u] " - "and a power of two.", blocksize, NANDFS_MIN_BLOCKSIZE, - MAXBSIZE); - } - - /* check blocks per segments */ - if ((blocks_per_segment < NANDFS_SEG_MIN_BLOCKS) || - ((blocksize - 1) & blocksize)) - errx(1, "Bad blocks per segment (%lu). Must be greater than " - "%u and a power of two.", blocks_per_segment, - NANDFS_SEG_MIN_BLOCKS); - - /* check reserved segment percentage */ - if ((rsv_segment_percent < 1) || (rsv_segment_percent > 99)) - errx(1, "Bad reserved segment percentage. " - "Must in range 1..99."); - - /* check volume label */ - i = 0; - if (volumelabel) { - while (isalnum(volumelabel[++i])) - ; - - if (volumelabel[i] != '\0') { - errx(1, "bad volume label. " - "Valid characters are alphanumerics."); - } - - if (strlen(volumelabel) >= 16) - errx(1, "Bad volume label. Length is longer than %d.", - 16); - } - - nandfs_time = time(NULL); -} - -static void -print_parameters(void) -{ - - printf("filesystem parameters:\n"); - printf("blocksize: %#zx sectorsize: %#zx\n", blocksize, sectorsize); - printf("erasesize: %#jx mediasize: %#jx\n", erasesize, mediasize); - printf("segment size: %#jx blocks per segment: %#x\n", segsize, - (uint32_t)blocks_per_segment); -} - -/* - * Exit with error if file system is mounted. - */ -static void -check_mounted(const char *fname, mode_t mode) -{ - struct statfs *mp; - const char *s1, *s2; - size_t len; - int n, r; - - if (!(n = getmntinfo(&mp, MNT_NOWAIT))) - err(1, "getmntinfo"); - - len = strlen(_PATH_DEV); - s1 = fname; - if (!strncmp(s1, _PATH_DEV, len)) - s1 += len; - - r = S_ISCHR(mode) && s1 != fname && *s1 == 'r'; - - for (; n--; mp++) { - s2 = mp->f_mntfromname; - - if (!strncmp(s2, _PATH_DEV, len)) - s2 += len; - if ((r && s2 != mp->f_mntfromname && !strcmp(s1 + 1, s2)) || - !strcmp(s1, s2)) - errx(1, "%s is mounted on %s", fname, mp->f_mntonname); - } -} - -static void -calculate_geometry(int fd) -{ - struct chip_param_io chip_params; - char ident[DISK_IDENT_SIZE]; - char medianame[MAXPATHLEN]; - - /* Check storage type */ - g_get_ident(fd, ident, DISK_IDENT_SIZE); - g_get_name(ident, medianame, MAXPATHLEN); - debug("device name: %s", medianame); - - is_nand = (strstr(medianame, "gnand") != NULL); - debug("is_nand = %d", is_nand); - - sectorsize = g_sectorsize(fd); - debug("sectorsize: %#zx", sectorsize); - - /* Get storage size */ - mediasize = g_mediasize(fd); - debug("mediasize: %#jx", mediasize); - - /* Get storage erase unit size */ - if (!is_nand) - erasesize = NANDFS_DEF_ERASESIZE; - else if (ioctl(fd, NAND_IO_GET_CHIP_PARAM, &chip_params) != -1) - erasesize = chip_params.page_size * chip_params.pages_per_block; - else - errx(1, "Cannot ioctl(NAND_IO_GET_CHIP_PARAM)"); - - debug("erasesize: %#jx", (uintmax_t)erasesize); - - if (blocks_per_segment == 0) { - if (erasesize >= NANDFS_MIN_SEGSIZE) - blocks_per_segment = erasesize / blocksize; - else - blocks_per_segment = NANDFS_MIN_SEGSIZE / blocksize; - } - - /* Calculate number of segments */ - segsize = blocksize * blocks_per_segment; - nsegments = ((mediasize - NANDFS_NFSAREAS * erasesize) / segsize) - 2; - debug("segsize: %#jx", segsize); - debug("nsegments: %#jx", nsegments); -} - -static void -erase_device(int fd) -{ - int rest, failed; - uint64_t i, nblocks; - off_t offset; - - failed = 0; - for (i = 0; i < NANDFS_NFSAREAS; i++) { - debug("Deleting %jx\n", i * erasesize); - if (g_delete(fd, i * erasesize, erasesize)) { - printf("cannot delete %jx\n", i * erasesize); - fsdata_blocks_state[i] = NANDFS_BLOCK_BAD; - failed++; - } else - fsdata_blocks_state[i] = NANDFS_BLOCK_GOOD; - } - - if (failed == NANDFS_NFSAREAS) { - printf("%d first blocks not usable. Unable to create " - "filesystem.\n", failed); - exit(1); - } - - for (i = 0; i < nsegments; i++) { - offset = NANDFS_NFSAREAS * erasesize + i * segsize; - if (g_delete(fd, offset, segsize)) { - printf("cannot delete segment %jx (offset %jd)\n", - i, offset); - bad_segments_count++; - bad_segments = realloc(bad_segments, - bad_segments_count * sizeof(uint32_t)); - bad_segments[bad_segments_count - 1] = i; - } - } - - if (bad_segments_count == nsegments) { - printf("no valid segments\n"); - exit(1); - } - - /* Delete remaining blocks at the end of device */ - rest = mediasize % segsize; - nblocks = rest / erasesize; - for (i = 0; i < nblocks; i++) { - offset = (segsize * nsegments) + (i * erasesize); - if (g_delete(fd, offset, erasesize)) { - printf("cannot delete space after last segment " - "- probably a bad block\n"); - } - } -} - -static void -erase_initial(int fd) -{ - char buf[512]; - u_int i; - - memset(buf, 0xff, sizeof(buf)); - - lseek(fd, 0, SEEK_SET); - for (i = 0; i < NANDFS_NFSAREAS * erasesize; i += sizeof(buf)) - write(fd, buf, sizeof(buf)); -} - -static void -create_nandfs(int fd) -{ - - create_fs(); - - write_fs(fd); -} - -static void -print_summary(void) -{ - - printf("filesystem was created successfully\n"); - printf("total segments: %#jx valid segments: %#jx\n", nsegments, - nsegments - bad_segments_count); - printf("total space: %ju MB free: %ju MB\n", - (nsegments * - blocks_per_segment * blocksize) / (1024 * 1024), - ((nsegments - bad_segments_count) * - blocks_per_segment * blocksize) / (1024 * 1024)); -} - -int -main(int argc, char *argv[]) -{ - struct stat sb; - char buf[MAXPATHLEN]; - const char opts[] = "b:B:L:m:"; - const char *fname; - int ch, fd; - - while ((ch = getopt(argc, argv, opts)) != -1) { - switch (ch) { - case 'b': - blocksize = strtol(optarg, (char **)NULL, 10); - if (blocksize == 0) - usage(); - break; - case 'B': - blocks_per_segment = strtol(optarg, (char **)NULL, 10); - if (blocks_per_segment == 0) - usage(); - break; - case 'L': - volumelabel = optarg; - break; - case 'm': - rsv_segment_percent = strtol(optarg, (char **)NULL, 10); - if (rsv_segment_percent == 0) - usage(); - break; - default: - usage(); - } - } - - argc -= optind; - argv += optind; - if (argc < 1 || argc > 2) - usage(); - - /* construct proper device path */ - fname = *argv++; - if (!strchr(fname, '/')) { - snprintf(buf, sizeof(buf), "%s%s", _PATH_DEV, fname); - if (!(fname = strdup(buf))) - err(1, NULL); - } - - fd = g_open(fname, 1); - if (fd == -1) - err(1, "Cannot open %s", fname); - - if (fstat(fd, &sb) == -1) - err(1, "Cannot stat %s", fname); - if (!S_ISCHR(sb.st_mode)) - warnx("%s is not a character device", fname); - - check_mounted(fname, sb.st_mode); - - calculate_geometry(fd); - - check_parameters(); - - print_parameters(); - - if (is_nand) - erase_device(fd); - else - erase_initial(fd); - - create_nandfs(fd); - - print_summary(); - - g_close(fd); - - return (0); -} - - diff --git a/sbin/swapon/swapon.8 b/sbin/swapon/swapon.8 index 058f681ce5ce..f69dd484a93b 100644 --- a/sbin/swapon/swapon.8 +++ b/sbin/swapon/swapon.8 @@ -28,7 +28,7 @@ .\" @(#)swapon.8 8.1 (Berkeley) 6/5/93 .\" $FreeBSD$ .\" -.Dd October 21, 2016 +.Dd June 21, 2019 .Dt SWAPON 8 .Os .Sh NAME @@ -38,7 +38,7 @@ .Nm swapon .Oo Fl F Ar fstab .Oc -.Fl aLq | Ar +.Fl aLq | E Ar .Nm swapoff .Oo Fl F Ar fstab .Oc @@ -86,6 +86,11 @@ If the option is used, informational messages will not be written to standard output when a swap device is added. +The +.Fl E +option causes each of following devices to receive a +.Dv BIO_DELETE +command to mark all blocks as unused. .Pp The .Nm swapoff diff --git a/sbin/swapon/swapon.c b/sbin/swapon/swapon.c index 83201535b4ab..e6c8b7eb215d 100644 --- a/sbin/swapon/swapon.c +++ b/sbin/swapon/swapon.c @@ -44,7 +44,7 @@ static char sccsid[] = "@(#)swapon.c 8.1 (Berkeley) 6/5/93"; __FBSDID("$FreeBSD$"); #include <sys/param.h> -#include <sys/types.h> +#include <sys/disk.h> #include <sys/mdioctl.h> #include <sys/stat.h> #include <sys/sysctl.h> @@ -77,7 +77,7 @@ static int run_cmd(int *, const char *, ...) __printflike(2, 3); static enum { SWAPON, SWAPOFF, SWAPCTL } orig_prog, which_prog = SWAPCTL; -static int qflag; +static int Eflag, qflag; int main(int argc, char **argv) @@ -100,7 +100,7 @@ main(int argc, char **argv) doall = 0; etc_fstab = NULL; - while ((ch = getopt(argc, argv, "AadghklLmqsUF:")) != -1) { + while ((ch = getopt(argc, argv, "AadEghklLmqsUF:")) != -1) { switch(ch) { case 'A': if (which_prog == SWAPCTL) { @@ -121,6 +121,12 @@ main(int argc, char **argv) else usage(); break; + case 'E': + if (which_prog == SWAPON) + Eflag = 2; + else + usage(); + break; case 'g': hflag = 'G'; break; @@ -182,8 +188,10 @@ main(int argc, char **argv) strstr(fsp->fs_mntops, "late") == NULL && late != 0) continue; + Eflag |= (strstr(fsp->fs_mntops, "trimonce") != NULL); swfile = swap_on_off(fsp->fs_spec, 1, fsp->fs_mntops); + Eflag &= ~1; if (swfile == NULL) { ret = 1; continue; @@ -378,12 +386,22 @@ swap_on_geli_args(const char *mntops) return (NULL); } } else if (strcmp(token, "notrim") == 0) { + if (Eflag) { + warn("Options \"notrim\" and " + "\"trimonce\" conflict"); + free(ops); + return (NULL); + } Tflag = " -T "; } else if (strcmp(token, "late") == 0) { /* ignore known option */ } else if (strcmp(token, "noauto") == 0) { /* ignore known option */ - } else if (strcmp(token, "sw") != 0) { + } else if (strcmp(token, "sw") == 0) { + /* ignore known option */ + } else if (strcmp(token, "trimonce") == 0) { + /* ignore known option */ + } else { warnx("Invalid option: %s", token); free(ops); return (NULL); @@ -721,14 +739,42 @@ run_cmd(int *ofd, const char *cmdline, ...) return (WEXITSTATUS(status)); } +static void +swap_trim(const char *name) +{ + struct stat sb; + off_t ioarg[2], sz; + int fd; + + fd = open(name, O_WRONLY); + if (fd < 0) + errx(1, "Cannot open %s", name); + if (fstat(fd, &sb) < 0) + errx(1, "Cannot stat %s", name); + if (S_ISREG(sb.st_mode)) + sz = sb.st_size; + else if (S_ISCHR(sb.st_mode)) { + if (ioctl(fd, DIOCGMEDIASIZE, &sz) != 0) + err(1, "ioctl(DIOCGMEDIASIZE)"); + } else + errx(1, "%s has an invalid file type", name); + ioarg[0] = 0; + ioarg[1] = sz; + if (ioctl(fd, DIOCGDELETE, ioarg) != 0) + warn("ioctl(DIOCGDELETE)"); + close(fd); +} + static const char * swap_on_off_sfile(const char *name, int doingall) { int error; - if (which_prog == SWAPON) + if (which_prog == SWAPON) { + if (Eflag) + swap_trim(name); error = swapon(name); - else /* SWAPOFF */ + } else /* SWAPOFF */ error = swapoff(name); if (error == -1) { @@ -759,6 +805,8 @@ usage(void) fprintf(stderr, "usage: %s ", getprogname()); switch(orig_prog) { case SWAPON: + fprintf(stderr, "[-F fstab] -aLq | [-E] file ...\n"); + break; case SWAPOFF: fprintf(stderr, "[-F fstab] -aLq | file ...\n"); break; diff --git a/share/examples/etc/make.conf b/share/examples/etc/make.conf index 8a9fa90ac12a..f9463c334631 100644 --- a/share/examples/etc/make.conf +++ b/share/examples/etc/make.conf @@ -49,6 +49,12 @@ # icelake-client, cannonlake, knm, skylake-avx512, knl, # goldmont, skylake, broadwell, haswell, ivybridge, # sandybridge, westmere, nehalem, silvermont, bonnell +# ARM architecture: armv5, armv5te, armv6, armv6t2, arm1176jzf-s, armv7, +# armv7-a, armv7ve, generic-armv7-a, cortex-a5, +# cortex-a7, cortex-a8, cortex-a9, cortex-a12, +# cortex-a15, cortex-a17 +# ARM64 architechture: cortex-a53, cortex-a57, cortex-a72, +# exynos-m1 # # (?= allows to buildworld for a different CPUTYPE.) # diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile index a810d9153349..13c3069b8172 100644 --- a/share/man/man4/Makefile +++ b/share/man/man4/Makefile @@ -303,8 +303,6 @@ MAN= aac.4 \ mx25l.4 \ mxge.4 \ my.4 \ - nand.4 \ - nandsim.4 \ ${_ndis.4} \ net80211.4 \ netdump.4 \ diff --git a/share/man/man4/gpio.4 b/share/man/man4/gpio.4 index 0e2c8cdb1423..da95c39f8e98 100644 --- a/share/man/man4/gpio.4 +++ b/share/man/man4/gpio.4 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd November 5, 2013 +.Dd June 27, 2019 .Dt GPIO 4 .Os .Sh NAME @@ -103,12 +103,50 @@ passed to the kernel, being either statically compiled in, or by a variety of ways where the boot loader (or Open Firmware enabled system) passes the DTS blob to the kernel at boot. .Pp +On a +.Xr device.hints 5 +based system these hints can be used to configure drivers for devices +attached to +.Nm +pins: +.Bl -tag -width ".Va hint.driver.unit.pin_list" +.It Va hint.driver.unit.at +The +.Nm gpiobus +where the device is attached. +For example, +.Qq gpiobus0 . +.Ar driver +and +.Ar unit +are the driver name and the unit number for the device driver. +.It Va hint.driver.unit.pins +This is a bitmask of the pins on the +.Nm gpiobus +that are connected to the device. +The pins will be allocated to the specified driver instance. +Only pins with numbers from 0 to 31 can be specified using this hint. +.It Va hint.driver.unit.pin_list +This is a list of pin numbers of pins on the +.Nm gpiobus +that are connected to the device. +The pins will be allocated to the specified driver instance. +This is a more user friendly alternative to the +.Ar pins +hint. +Additionally, this hint allows specifying pin numbers greater than 31. +The numbers can be decimal or hexadecimal with 0x prefix. +Any non-digit character can be used as a separator. +For example, it can be a comma, a slash or a space. +The separator can be followed by any number of space characters. +.El +.Pp The following .Xr device.hints 5 are only provided by the .Cd ar71xx_gpio driver: -.Bl -tag -width ".Va hint.gpioiic.%d.atXXX" +.Bl -tag -width ".Va hint.gpio.function_clear" .It Va hint.gpio.%d.pinmask This is a bitmask of pins on the GPIO board that we would like to expose for use to the host operating system. @@ -133,6 +171,7 @@ of some device in a system. .Xr gpioiic 4 , .Xr gpioled 4 , .Xr iicbus 4 , +.Xr device.hints 5 , .Xr gpioctl 8 .Sh HISTORY The diff --git a/share/man/man4/nand.4 b/share/man/man4/nand.4 deleted file mode 100644 index 5c868a1151e6..000000000000 --- a/share/man/man4/nand.4 +++ /dev/null @@ -1,145 +0,0 @@ -.\" -.\" Copyright (c) 2012 The FreeBSD Foundation -.\" All rights reserved. -.\" -.\" This documentation was written by Semihalf under sponsorship from -.\" the FreeBSD Foundation. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" -.\" $FreeBSD$ -.\" -.Dd March 8, 2012 -.Dt NAND 4 -.Os -.Sh NAME -.Nm nand -.Nd NAND Flash framework -.Sh SYNOPSIS -.Cd "device nand" -.Sh DESCRIPTION -The -.Fx -.Nm -framework consists of a set of interfaces that aim to provide an extensible, -object oriented environment for NAND controllers and NAND Flash memory chips -from various hardware vendors, and to allow for uniform and flexible -management of the NAND devices. -It comprises of the following major components: -.Bl -bullet -.It -NAND Flash controller (NFC) interface. -.Pp -Defines methods which allow to send commands as well as send/receive data -between the controller and a NAND chip. -Back-end drivers for specific NAND -controllers plug into this interface and implement low-level routines for a -given NAND controller. -.Pp -This layer implements basic functionality of a NAND Flash controller. -It allows to send command and address to chip, drive CS (chip select line), -as well as read/write to the selected NAND chip. -This layer is independent of -NAND chip devices actually connected to the controller. -.It -NAND chip interface. -.Pp -Provides basic operations like read page, program page, erase block. -Currently three generic classes of drivers are available, which provide -support for the following chips: -.Bl -bullet -.It -large page -.It -small page -.It -ONFI-compliant -.El -.Pp -This layer implements basic operations to be performed on a NAND chip, like -read, program, erase, get status etc. -Since these operations use specific -commands (depending on the vendor), each chip has potentially its own -implementation of the commands set. -.Pp -The framework is extensible so it is also possible to create a custom command -set for a non standard chip support. -.It -NANDbus. -.Pp -This layer is responsible for enumerating NAND chips in the system and -establishing the hierarchy between chips and their supervising controllers. -.Pp -Its main purpose is detecting type of NAND chips connected to a given chip -select (CS line). -It also allows manages locking access to the NAND -controller. -NANDbus passes requests from an active chip to the chip controller. -.It -NAND character / GEOM device. -.Pp -For each NAND chip found in a system a character and GEOM devices are created -which allows to read / write directly to a device, as well as perform other -specific operations (like via ioctl). -.Pp -There are two GEOM devices created for each NAND chip: -.Bl -bullet -.It -raw device -.It -normal device -.El -.Pp -Raw device allows to bypass ECC checking when reading/writing to it, while -normal device always uses ECC algorithm to validate the read data. -.Pp -NAND character devices will be created for each NAND chip detected while -probing the NAND controller. -.El -.Sh SEE ALSO -.Xr libnandfs 3 , -.Xr gnand 4 , -.Xr nandsim 4 , -.Xr nandfs 5 , -.Xr makefs 8 , -.Xr mount_nandfs 8 , -.Xr nandfs 8 , -.Xr nandsim 8 , -.Xr nandtool 8 , -.Xr newfs_nandfs 8 , -.Xr umount_nandfs 8 -.Sh STANDARDS -Open NAND Flash Interface Working Group -.Pq Vt ONFI . -.Sh HISTORY -The -.Nm -framework support first appeared in -.Fx 10.0 . -.Sh AUTHORS -.An -nosplit -The -.Nm -framework was designed and developed by -.An Grzegorz Bernacki . -This manual page was written by -.An Rafal Jaworowski . diff --git a/share/man/man4/nandsim.4 b/share/man/man4/nandsim.4 deleted file mode 100644 index bf8d624eeb8a..000000000000 --- a/share/man/man4/nandsim.4 +++ /dev/null @@ -1,93 +0,0 @@ -.\" -.\" Copyright (c) 2012 The FreeBSD Foundation -.\" All rights reserved. -.\" -.\" This documentation was written by Semihalf under sponsorship from -.\" the FreeBSD Foundation. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" -.\" $FreeBSD$ -.\" -.Dd March 8, 2012 -.Dt NANDSIM 4 -.Os -.Sh NAME -.Nm nandsim -.Nd NAND Flash simulator driver -.Sh SYNOPSIS -.Cd "device nand" -.Cd "device nandsim" -.Cd "options ALQ" -.Sh DESCRIPTION -The -.Nm -is part of the -.Fx -NAND framework -.Xr nand 4 -and can be characterized with the following highlights: -.Bl -bullet -.It -plugs into the -.Xr nand 4 -framework APIs as if it were a hardware controller (hanging on the nexus bus) -with real NAND chips connected to it -.It -physically part of the kernel code (either statically linked into the kernel -image or built as a module) -.It -controlled with a user space program -.Xr nandsim 8 -.El -.Pp -From the user perspective, the -.Nm -allows for imitating ONFI-compliant NAND Flash devices as if they were -attached to the system via a virtual controller. -.Pp -Some -.Nm -features rely on the ability to log contents to a file, which is achieved -through the -.Xr alq 9 -facility. -.Sh SEE ALSO -.Xr nand 4 , -.Xr nandsim.conf 5 , -.Xr nandsim 8 -.Sh STANDARDS -Open NAND Flash Interface Working Group -.Pq Vt ONFI . -.Sh HISTORY -The -.Nm -support first appeared in -.Fx 10.0 . -.Sh AUTHORS -.An -nosplit -The -.Nm -kernel driver was developed by -.An Grzegorz Bernacki . -This manual page was written by -.An Rafal Jaworowski . diff --git a/share/man/man4/owc.4 b/share/man/man4/owc.4 index 43d6cb776ae4..06c4e909ac96 100644 --- a/share/man/man4/owc.4 +++ b/share/man/man4/owc.4 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd July 20, 2015 +.Dd June 26, 2019 .Dt OWC 4 .Os .Sh NAME @@ -69,6 +69,24 @@ For more details about the .Va gpios property, please consult .Pa /usr/src/sys/dts/bindings-gpio.txt . +.Pp +On a +.Xr device.hints 5 +based system these values are required for the +.Nm : +.Bl -tag -width ".Va hint.owc.%d.atXXX" +.It Va hint.owc.%d.at +The +.Nm gpiobus +you are attaching to. +.It Va hint.owc.%d.pins +This is a bitmask that defines a pin on the +.Nm gpiobus +that is to be used for the 1-Wire bus. +For instance, to configure pin 10, use the bitmask of 0x400. +Please note that this mask should have only one bit set +(any other bits - i.e., pins - will be ignored). +.El .Sh SEE ALSO .Xr gpiobus 4 , .Xr ow 4 , diff --git a/share/man/man4/random.4 b/share/man/man4/random.4 index 0ccad03aeda4..3b3f9b2330e3 100644 --- a/share/man/man4/random.4 +++ b/share/man/man4/random.4 @@ -30,7 +30,6 @@ .Nm random .Nd the entropy device .Sh SYNOPSIS -.Cd "device random" .Cd "options RANDOM_LOADABLE" .Cd "options RANDOM_ENABLE_ETHER" .Cd "options RANDOM_ENABLE_UMA" diff --git a/share/man/man5/Makefile b/share/man/man5/Makefile index b5ec870f75ff..119869128acb 100644 --- a/share/man/man5/Makefile +++ b/share/man/man5/Makefile @@ -101,10 +101,6 @@ MAN+= freebsd-update.conf.5 MAN+= hesiod.conf.5 .endif -.if ${MK_NAND} != "no" -MAN+= nandfs.5 -.endif - .if ${MK_PF} != "no" MAN+= pf.conf.5 \ pf.os.5 diff --git a/share/man/man5/fstab.5 b/share/man/man5/fstab.5 index 062ab601851f..f4e9ce2b653e 100644 --- a/share/man/man5/fstab.5 +++ b/share/man/man5/fstab.5 @@ -216,6 +216,12 @@ then the special file is made available as a piece of swap space by the .Xr swapon 8 command at the end of the system reboot procedure. +For swap devices, the keyword +.Dq trimonce +triggers the delivery of a +.Dv BIO_DELETE +command to the device to mark +all blocks as unused. For vnode-backed swap spaces, .Dq file is supported in the diff --git a/share/man/man5/nandfs.5 b/share/man/man5/nandfs.5 deleted file mode 100644 index 7e895993674d..000000000000 --- a/share/man/man5/nandfs.5 +++ /dev/null @@ -1,132 +0,0 @@ -.\" -.\" Copyright (c) 2010 Semihalf -.\" 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 Nov 11, 2010 -.Dt NANDFS 5 -.Os -.Sh NAME -.Nm nandfs -.Nd NAND Flash file system -.Sh SYNOPSIS -To compile support for the -.Nm , -place the following in your kernel configuration file: -.Bd -ragged -offset indent -.Cd "options NANDFS" -.Ed -.Pp -Even though the NAND FS can be used with any storage media, it has been -optimized and designed towards NAND Flash devices, so typically the following -driver is used: -.Bd -ragged -offset indent -.Cd "device nand" -.Ed -.Sh DESCRIPTION -The -.Nm -driver enables -.Fx -with support for NAND-oriented file system. -.Pp -It is a log-structured style file system with the following major features and -characteristics: -.Bl -bullet -.It -Hard links, symbolic links support -.It -Block journaling -.It -Copy-On-Write -.It -Snapshots (continuous, taken automatically, simultaneously mountable) -.It -Quick crash recovery at mount time -.It -64-bit data structures; supports many files, large files and volumes -.It -POSIX file permissions -.It -Checksum / ECC -.El -.Sh EXAMPLES -The most common usage is mounting the file system: -.Pp -.Dl "mount -t nandfs /dev/<gnandN> /mnt" -.Pp -or: -.Dl "mount_nandfs /dev/<gnandN> /mnt" -.Pp -where -.Ar gnandN -is the GEOM device representing a Flash partition (slice) containing the -.Nm -structure, and -.Pa /mnt -is a mount point. -.Pp -It is possible to define an entry in -.Pa /etc/fstab -for the -.Nm : -.Bd -literal -/dev/gnand0 /flash nandfs rw 0 0 -.Ed -.Pp -This will mount a -.Nm -partition at the specified mount point during system boot. -.Sh SEE ALSO -.Xr gnand 4 , -.Xr nand 4 , -.Xr mount_nandfs 8 , -.Xr nandfs 8 , -.Xr nandsim 8 , -.Xr nandtool 8 , -.Xr umount_nandfs 8 -.Sh HISTORY -The NAND FS concepts are based on NILFS principles and initial implementation -was derived from early read-only NILFS NetBSD code. -Since then the NAND FS -code diverged significantly and is by no means compatible with NILFS. -.Pp -The NAND Flash file system first appeared in -.Fx 10.0 . -.Sh AUTHORS -.An -nosplit -The NAND FS was written by -.An Grzegorz Bernacki -with the help of -.An Mateusz Guzik , -based on the NetBSD code created by -.An Reinoud Zandijk . -Additional help and support by -.An Lukasz Plachno , -.An Jan Sieka -and -.An Lukasz Wojcik . -This manual page was written by -.An Rafal Jaworowski . diff --git a/share/man/man9/Makefile b/share/man/man9/Makefile index 682eb2a39502..a4fb56b891b9 100644 --- a/share/man/man9/Makefile +++ b/share/man/man9/Makefile @@ -270,7 +270,6 @@ MAN= accept_filter.9 \ proc_rwmem.9 \ pseudofs.9 \ psignal.9 \ - pwm.9 \ pwmbus.9 \ random.9 \ random_harvest.9 \ @@ -1670,6 +1669,7 @@ MLINKS+=proc_rwmem.9 proc_readmem.9 \ MLINKS+=psignal.9 gsignal.9 \ psignal.9 pgsignal.9 \ psignal.9 tdsignal.9 +MLINKS+=pwmbus.9 pwm.9 MLINKS+=random.9 arc4rand.9 \ random.9 arc4random.9 \ random.9 is_random_seeded.9 \ diff --git a/share/man/man9/VOP_REVOKE.9 b/share/man/man9/VOP_REVOKE.9 index 3557ce1109e8..610fdb7142aa 100644 --- a/share/man/man9/VOP_REVOKE.9 +++ b/share/man/man9/VOP_REVOKE.9 @@ -34,7 +34,7 @@ .\" .\" $FreeBSD$ .\" -.Dd February 5, 2002 +.Dd June 20, 2019 .Dt VOP_REVOKE 9 .Os .Sh NAME @@ -61,7 +61,7 @@ to signify that all access will be revoked; any other value is invalid. .Sh LOCKS The .Fa vp -must be unlocked on entry, and will remain unlocked upon return. +must be exclusively locked on entry, and will remain locked upon return. .Sh SEE ALSO .Xr make_dev_alias 9 , .Xr vnode 9 diff --git a/share/man/man9/iflibdi.9 b/share/man/man9/iflibdi.9 index 84340d502080..c37832ede6af 100644 --- a/share/man/man9/iflibdi.9 +++ b/share/man/man9/iflibdi.9 @@ -1,5 +1,5 @@ .\" $FreeBSD$ -.Dd May 24, 2017 +.Dd May 21, 2019 .Dt IFLIBDI 9 .Os .Sh NAME @@ -194,10 +194,10 @@ Allocate and initialize the \fIif_ctx_t\fP structure. Setup and initialize the MSI or MSI/X interrupt queues if necessary. Allocate memory for queues and qset structure setup. -.It Fn iflib_device_irq_alloc +.It Fn iflib_irq_alloc Allocate an interrupt resource for a given rid value with an associated filter and handler function. -.It Fn iflib_device_irq_alloc_generic +.It Fn iflib_irq_alloc_generic Performs the same function as iflib_device_irq_alloc along with the additional functionality of adding a taskgroup. The data fields and callback function are determined by the type of interrupt, diff --git a/share/man/man9/pwm.9 b/share/man/man9/pwm.9 deleted file mode 100644 index f7564a4eeca3..000000000000 --- a/share/man/man9/pwm.9 +++ /dev/null @@ -1,93 +0,0 @@ -.\" Copyright (c) 2018 Emmanuel Vadot <manu@freebsd.org> -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``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 DEVELOPERS 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 January 12, 2019 -.Dt PWM 9 -.Os -.Sh NAME -.Nm pwm , -.Nm PWM_GET_BUS , -.Nm PWM_CHANNEL_CONFIG , -.Nm PWM_CHANNEL_GET_CONFIG , -.Nm PWM_CHANNEL_SET_FLAGS , -.Nm PWM_CHANNEL_GET_FLAGS , -.Nm PWM_CHANNEL_ENABLE , -.Nm PWM_CHANNEL_IS_ENABLED , -.Nm PWM_CHANNEL_MAX -.Nd PWM methods -.Sh SYNOPSIS -.Cd "device pwm" -.In "pwm_if.h" -.Ft device_t -.Fn PWM_GET_BUS "device_t dev" -.Ft int -.Fn PWM_CHANNEL_CONFIG "device_t dev" "int channel" "uint64_t period" "uint64_t duty" -.Ft int -.Fn PWM_CHANNEL_GET_CONFIG "device_t dev" "int channel" "uint64_t *period" "uint64_t *duty" -.Ft int -.Fn PWM_CHANNEL_SET_FLAGS "device_t dev" "int channel" "uint32_t flags" -.Ft int -.Fn PWM_CHANNEL_GET_FLAGS "device_t dev" "int channel" "uint32_t *flags" -.Ft int -.Fn PWM_CHANNEL_ENABLE "device_t dev" "int channel" "bool enable" -.Ft int -.Fn PWM_CHANNEL_IS_ENABLED "device_t dev" "int channel" "bool *enabled" -.Ft int -.Fn PWM_CHANNEL_MAX "device_t dev" "int channel" "int *nchannel" -.Sh DESCRIPTION -The PWM (Pulse-Width Modulation) interface allows the device driver to register to a global -bus so other devices in the kernel can use them in a generic way. -.Sh INTERFACE -.Bl -tag -width indent -.It Fn PWM_GET_BUS "device_t dev" -Return the bus device. -.It Fn PWM_CHANNEL_CONFIG "device_t dev" "int channel" "uint64_t period" "uint64_t duty" -Configure the period and duty (in nanoseconds) in the PWM controller for the specified channel. -Returns 0 on success or -.Er EINVAL -if the values are not supported by the controller or -.Er EBUSY -is the PWM controller is in use and does not support changing the value on the fly. -.It Fn PWM_CHANNEL_GET_CONFIG "device_t dev" "int channel" "uint64_t *period" "uint64_t *duty" -Get the current configuration of the period and duty for the specified channel. -.It Fn PWM_CHANNEL_SET_FLAGS "device_t dev" "int channel" "uint32_t flags" -Set the flags of the channel (like inverted polarity). -.It Fn PWM_CHANNEL_GET_FLAGS "device_t dev" "int channel" "uint32_t *flags" -Get the current flags for the channel. -.It Fn PWM_CHANNEL_ENABLE "device_t dev" "int channel" "bool enable" -Enable the PWM channel. -.It Fn PWM_CHANNEL_ISENABLED "device_t dev" "int channel" "bool *enable" -Test if the PWM channel is enabled. -.It Fn PWM_CHANNEL_MAX "device_t dev" "int channel" "int *nchannel" -Get the maximum number of channels supported by the controller. -.El -.Sh HISTORY -The -.Nm pwm -interface first appeared in -.Fx 13.0 . -The -.Nm pwm -interface and manual page was written by -.An Emmanuel Vadot Aq Mt manu@FreeBSD.org . diff --git a/share/man/man9/pwmbus.9 b/share/man/man9/pwmbus.9 index ba987eaf77a5..5b0915c10812 100644 --- a/share/man/man9/pwmbus.9 +++ b/share/man/man9/pwmbus.9 @@ -22,70 +22,85 @@ .\" .\" $FreeBSD$ .\" -.Dd November 12, 2018 +.Dd June 21, 2019 .Dt PWMBUS 9 .Os .Sh NAME .Nm pwmbus , -.Nm pwmbus_attach_bus , -.Nm PWMBUS_GET_BUS , .Nm PWMBUS_CHANNEL_CONFIG , +.Nm PWMBUS_CHANNEL_COUNT , +.Nm PWMBUS_CHANNEL_ENABLE , .Nm PWMBUS_CHANNEL_GET_CONFIG , -.Nm PWMBUS_CHANNEL_SET_FLAGS , .Nm PWMBUS_CHANNEL_GET_FLAGS , -.Nm PWMBUS_CHANNEL_ENABLE , .Nm PWMBUS_CHANNEL_IS_ENABLED , -.Nm PWMBUS_CHANNEL_MAX +.Nm PWMBUS_CHANNEL_SET_FLAGS , +.Nm PWMBUS_GET_BUS .Nd PWMBUS methods .Sh SYNOPSIS .Cd "device pwm" .In "pwmbus_if.h" -.Ft device_t -.Fn pwmbus_attach_bus "device_t dev" .Ft int .Fn PWMBUS_CHANNEL_CONFIG "device_t bus" "int channel" "uint64_t period" "uint64_t duty" .Ft int -.Fn PWMBUS_CHANNEL_GET_CONFIG "device_t bus" "int channel" "uint64_t *period" "uint64_t *duty" +.Fn PWMBUS_CHANNEL_COUNT "device_t bus" "int channel" "int *nchannel" .Ft int -.Fn PWMBUS_CHANNEL_SET_FLAGS "device_t bus" "int channel" "uint32_t flags" +.Fn PWMBUS_CHANNEL_ENABLE "device_t bus" "int channel" "bool enable" .Ft int -.Fn PWMBUS_CHANNEL_GET_FLAGS "device_t bus" "int channel" "uint32_t *flags" +.Fn PWMBUS_CHANNEL_GET_CONFIG "device_t bus" "int channel" "uint64_t *period" "uint64_t *duty" .Ft int -.Fn PWMBUS_CHANNEL_ENABLE "device_t bus" "int channel" "bool enable" +.Fn PWMBUS_CHANNEL_GET_FLAGS "device_t bus" "int channel" "uint32_t *flags" .Ft int .Fn PWMBUS_CHANNEL_IS_ENABLED "device_t bus" "int channel" "bool *enabled" .Ft int -.Fn PWMBUS_CHANNEL_MAX "device_t bus" "int channel" "int *nchannel" +.Fn PWMBUS_CHANNEL_SET_FLAGS "device_t bus" "int channel" "uint32_t flags" .Sh DESCRIPTION -The PWMBUS (Pulse-Width Modulation) interface allows the device driver to register to a global -bus so other devices in the kernel can use them in a generic way +The PWMBUS (Pulse-Width Modulation) interface allows a device driver to +register to a global bus so other devices in the kernel can use them in a +generic way. +.Pp +For all +.Nm +methods, the +.Va period +argument is the duration in nanoseconds of one complete on-off cycle, and the +.Va duty +argument is the duration in nanoseconds of the on portion of that cycle. +.Pp +Some PWM hardware is organized as a single controller with multiple channels. +Channel numbers count up from zero. +When multiple channels are present, they sometimes share a common clock or +other resources. +In such cases, changing the period or duty cycle of any one channel may affect +other channels within the hardware which share the same resources. +Consult the documentation for the underlying PWM hardware device driver for +details on channels that share resources. .Sh INTERFACE .Bl -tag -width indent -.It Fn pwmbus_attach_bus "device_t dev" -Attach the -.Nm pwmbus -to the device driver .It Fn PWMBUS_CHANNEL_CONFIG "device_t bus" "int channel" "uint64_t period" "uint64_t duty" -Configure the period and duty (in nanoseconds) in the PWM controller on the bus for the specified channel. +Configure the period and duty (in nanoseconds) in the PWM controller on the bus +for the specified channel. Returns 0 on success or .Er EINVAL -is the values are not supported by the controller or +if the values are not supported by the controller or .Er EBUSY -is the PWMBUS controller is in use and doesn't support changing the value on the fly. +if the PWMBUS controller is in use and does not support changing the value on +the fly. +.It Fn PWMBUS_CHANNEL_COUNT "device_t bus" "int *nchannel" +Get the number of channels supported by the controller. +.It Fn PWMBUS_CHANNEL_ENABLE "device_t bus" "int channel" "bool enable" +Enable the PWM channel. .It Fn PWMBUS_CHANNEL_GET_CONFIG "device_t bus" "int channel" "uint64_t *period" "uint64_t *duty" Get the current configuration of the period and duty for the specified channel. -.It Fn PWMBUS_CHANNEL_SET_FLAGS "device_t bus" "int channel" "uint32_t flags" -Set the flags of the channel (like inverted polarity), if the driver or controller -doesn't support this a default method is used. .It Fn PWMBUS_CHANNEL_GET_FLAGS "device_t bus" "int channel" "uint32_t *flags" -Get the current flags for the channel, if the driver or controller -doesn't support this, a default method is used. -.It Fn PWMBUS_CHANNEL_ENABLE "device_t bus" "int channel" "bool enable" -Enable the PWM channel. -.It Fn PWMBUS_CHANNEL_ISENABLED "device_t bus" "int channel" "bool *enable" -Test if the PWM channel is enabled. -.It PWMBUS_CHANNEL_MAX "device_t bus" "int channel" "int *nchannel" -Get the maximum number of channel supported by the controller. +Get the current flags for the channel. +If the driver or controller +does not support this, a default method returns a flags value of zero. +.It Fn PWMBUS_CHANNEL_IS_ENABLED "device_t bus" "int channel" "bool *enable" +Test whether the PWM channel is enabled. +.It Fn PWMBUS_CHANNEL_SET_FLAGS "device_t bus" "int channel" "uint32_t flags" +Set the flags of the channel (such as inverted polarity). +If the driver or controller does not support this a do-nothing default method +is used. .El .Sh HISTORY The diff --git a/share/man/man9/vm_map_protect.9 b/share/man/man9/vm_map_protect.9 index c4b5a738abe7..5e58074ebda7 100644 --- a/share/man/man9/vm_map_protect.9 +++ b/share/man/man9/vm_map_protect.9 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd July 19, 2003 +.Dd June 20, 2019 .Dt VM_MAP_PROTECT 9 .Os .Sh NAME @@ -51,6 +51,11 @@ within the map .Fa map to .Fa new_prot . +The value specified by +.Fa new_prot +may not include any protection bits that are not set in +.Va max_protection +on every entry within the range. .Pp If .Fa set_max @@ -59,7 +64,12 @@ is TRUE, is treated as the new .Va max_protection setting for each underlying entry. -Otherwise, only the +Protection bits not included +.Fa new_prot +will be cleared from existing entries. +If +.Fa set_max +is FALSE only the .Va protection field is affected. .Pp @@ -86,6 +96,11 @@ would exceed for an entry within the range, .Dv KERN_PROTECTION_FAILURE is returned. +If a copy-on-write mapping is transitioned from read-only to +read-write, and too little swap space is available for backing the +copied pages, +.Dv KERN_RESOURCE_SHORTAGE +is returned. .Sh SEE ALSO .Xr vm_map 9 .Sh AUTHORS diff --git a/share/misc/bsd-family-tree b/share/misc/bsd-family-tree index 81741ca34446..6f386cbc0b08 100644 --- a/share/misc/bsd-family-tree +++ b/share/misc/bsd-family-tree @@ -135,7 +135,7 @@ FreeBSD 4.0 | | | | | NetBSD 1.4.2 | | | FreeBSD 3.5.1 | | | | | | | | | | | | | | | *---FreeBSD 4.1 | | | | | | | - | | | | (?) | | | | + | | | | | | | | | | FreeBSD 4.1.1 | | / | | | | | | | | / | | | | | FreeBSD 4.2 Darwin/ | NetBSD 1.4.3 | | @@ -399,6 +399,8 @@ FreeBSD 5.2 | | | | | | | NetBSD | | | | | 8.1 | DragonFly 5.6 | | | | | + | | | | DragonFly 5.6.1 + | | | | | FreeBSD 13 -current | NetBSD -current OpenBSD -current DragonFly -current | | | | | v v v v v @@ -783,6 +785,7 @@ DragonFly 5.4.1 2018-12-24 [DFB] OpenBSD 6.5 2019-05-01 [OBD] NetBSD 8.1 2019-06-04 [NBD] DragonFly 5.6 2019-06-17 [DFB] +DragonFly 5.6.1 2019-06-19 [DFB] Bibliography ------------------------ diff --git a/share/mk/bsd.cpu.mk b/share/mk/bsd.cpu.mk index acf1f5922593..c16ab5a85bf6 100644 --- a/share/mk/bsd.cpu.mk +++ b/share/mk/bsd.cpu.mk @@ -369,6 +369,10 @@ CFLAGS += -mfloat-abi=softfp .endif .endif +.if ${MACHINE_ARCH} == "powerpc" || ${MACHINE_ARCH} == "powerpcspe" +LDFLAGS+= -Wl,--secure-plt +.endif + .if ${MACHINE_ARCH} == "powerpcspe" CFLAGS += -mcpu=8548 -Wa,-me500 -mspe=yes -mabi=spe -mfloat-gprs=double .endif diff --git a/share/mk/bsd.libnames.mk b/share/mk/bsd.libnames.mk index b2675fce7cf3..1bea2ff10786 100644 --- a/share/mk/bsd.libnames.mk +++ b/share/mk/bsd.libnames.mk @@ -104,7 +104,6 @@ LIBMLX4?= ${LIBDESTDIR}${LIBDIR_BASE}/libmlx4.a LIBMLX5?= ${LIBDESTDIR}${LIBDIR_BASE}/libmlx5.a LIBMP?= ${LIBDESTDIR}${LIBDIR_BASE}/libmp.a LIBMT?= ${LIBDESTDIR}${LIBDIR_BASE}/libmt.a -LIBNANDFS?= ${LIBDESTDIR}${LIBDIR_BASE}/libnandfs.a LIBNCURSES?= ${LIBDESTDIR}${LIBDIR_BASE}/libncurses.a LIBNCURSESW?= ${LIBDESTDIR}${LIBDIR_BASE}/libncursesw.a LIBNETGRAPH?= ${LIBDESTDIR}${LIBDIR_BASE}/libnetgraph.a diff --git a/share/mk/src.libnames.mk b/share/mk/src.libnames.mk index d08a8653de3a..fcb03aaaedcd 100644 --- a/share/mk/src.libnames.mk +++ b/share/mk/src.libnames.mk @@ -135,7 +135,6 @@ _LIBRARIES= \ memstat \ mp \ mt \ - nandfs \ ncurses \ ncursesw \ netgraph \ diff --git a/share/mk/src.opts.mk b/share/mk/src.opts.mk index 96e3c94a948f..03d089b8246b 100644 --- a/share/mk/src.opts.mk +++ b/share/mk/src.opts.mk @@ -206,7 +206,6 @@ __DEFAULT_NO_OPTIONS = \ LOADER_FORCE_LE \ LOADER_VERBOSE \ LOADER_VERIEXEC_PASS_MANIFEST \ - NAND \ OFED_EXTRA \ OPENLDAP \ RPCBIND_WARMSTART_SUPPORT \ diff --git a/stand/arm/uboot/conf.c b/stand/arm/uboot/conf.c index 777a7b20340c..077541220f92 100644 --- a/stand/arm/uboot/conf.c +++ b/stand/arm/uboot/conf.c @@ -59,9 +59,6 @@ struct fs_ops *file_system[] = { #if defined(LOADER_EXT2FS_SUPPORT) &ext2fs_fsops, #endif -#if defined(LOADER_NANDFS_SUPPORT) - &nandfs_fsops, -#endif #if defined(LOADER_NFS_SUPPORT) &nfs_fsops, #endif diff --git a/stand/arm/uboot/version b/stand/arm/uboot/version index 486c4125cc0d..ec46b388b281 100644 --- a/stand/arm/uboot/version +++ b/stand/arm/uboot/version @@ -3,6 +3,7 @@ $FreeBSD$ NOTE ANY CHANGES YOU MAKE TO THE BOOTBLOCKS HERE. The format of this file is important. Make sure the current version number is on line 6. +1.3: Remove NAND FS support. 1.2: Extended with NAND FS support. 1.1: Flattened Device Tree blob support. 1.0: Added storage support. Booting from HDD, USB, etc. is now possible. diff --git a/stand/common/part.c b/stand/common/part.c index ec9697c6a10b..8eb4c065b473 100644 --- a/stand/common/part.c +++ b/stand/common/part.c @@ -57,7 +57,6 @@ static const uuid_t gpt_uuid_freebsd_ufs = GPT_ENT_TYPE_FREEBSD_UFS; static const uuid_t gpt_uuid_efi = GPT_ENT_TYPE_EFI; static const uuid_t gpt_uuid_freebsd = GPT_ENT_TYPE_FREEBSD; static const uuid_t gpt_uuid_freebsd_boot = GPT_ENT_TYPE_FREEBSD_BOOT; -static const uuid_t gpt_uuid_freebsd_nandfs = GPT_ENT_TYPE_FREEBSD_NANDFS; static const uuid_t gpt_uuid_freebsd_swap = GPT_ENT_TYPE_FREEBSD_SWAP; static const uuid_t gpt_uuid_freebsd_zfs = GPT_ENT_TYPE_FREEBSD_ZFS; static const uuid_t gpt_uuid_freebsd_vinum = GPT_ENT_TYPE_FREEBSD_VINUM; @@ -91,7 +90,6 @@ static struct parttypes { { PART_EFI, "EFI" }, { PART_FREEBSD, "FreeBSD" }, { PART_FREEBSD_BOOT, "FreeBSD boot" }, - { PART_FREEBSD_NANDFS, "FreeBSD nandfs" }, { PART_FREEBSD_UFS, "FreeBSD UFS" }, { PART_FREEBSD_ZFS, "FreeBSD ZFS" }, { PART_FREEBSD_SWAP, "FreeBSD swap" }, @@ -141,8 +139,6 @@ gpt_parttype(uuid_t type) return (PART_FREEBSD_SWAP); else if (uuid_equal(&type, &gpt_uuid_freebsd_vinum, NULL)) return (PART_FREEBSD_VINUM); - else if (uuid_equal(&type, &gpt_uuid_freebsd_nandfs, NULL)) - return (PART_FREEBSD_NANDFS); else if (uuid_equal(&type, &gpt_uuid_freebsd, NULL)) return (PART_FREEBSD); return (PART_UNKNOWN); @@ -445,8 +441,6 @@ bsd_parttype(uint8_t type) { switch (type) { - case FS_NANDFS: - return (PART_FREEBSD_NANDFS); case FS_SWAP: return (PART_FREEBSD_SWAP); case FS_BSDFFS: @@ -527,8 +521,6 @@ vtoc8_parttype(uint16_t type) { switch (type) { - case VTOC_TAG_FREEBSD_NANDFS: - return (PART_FREEBSD_NANDFS); case VTOC_TAG_FREEBSD_SWAP: return (PART_FREEBSD_SWAP); case VTOC_TAG_FREEBSD_UFS: diff --git a/stand/common/part.h b/stand/common/part.h index 3eac476b6d66..490db6746c38 100644 --- a/stand/common/part.h +++ b/stand/common/part.h @@ -45,7 +45,6 @@ enum partition_type { PART_EFI, PART_FREEBSD, PART_FREEBSD_BOOT, - PART_FREEBSD_NANDFS, PART_FREEBSD_UFS, PART_FREEBSD_ZFS, PART_FREEBSD_SWAP, diff --git a/stand/common/paths.h b/stand/common/paths.h index 9ed45e646a3e..b32313770129 100644 --- a/stand/common/paths.h +++ b/stand/common/paths.h @@ -29,11 +29,14 @@ #ifndef _PATHS_H_ #define _PATHS_H_ +#include <sys/boot.h> /* To get kernel path */ + #define PATH_DOTCONFIG "/boot.config" #define PATH_CONFIG "/boot/config" #define PATH_LOADER "/boot/loader" #define PATH_LOADER_EFI "/boot/loader.efi" #define PATH_LOADER_ZFS "/boot/zfsloader" -#define PATH_KERNEL "/boot/kernel/kernel" +#define PATH_LOADER_CONF "/boot/loader.conf" +#define PATH_DEFAULTS_LOADER_CONF "/boot/defaults/loader.conf" #endif /* _PATHS_H_ */ diff --git a/stand/efi/include/Protocol/Http.h b/stand/efi/include/Protocol/Http.h new file mode 100644 index 000000000000..54f49ab5e35c --- /dev/null +++ b/stand/efi/include/Protocol/Http.h @@ -0,0 +1,523 @@ +/* $FreeBSD$ */ +/** @file + This file defines the EFI HTTP Protocol interface. It is split into + the following two main sections: + HTTP Service Binding Protocol (HTTPSB) + HTTP Protocol (HTTP) + + Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR> + (C) Copyright 2015-2017 Hewlett Packard Enterprise Development LP<BR> + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + @par Revision Reference: + This Protocol is introduced in UEFI Specification 2.5 + +**/ + +#ifndef __EFI_HTTP_PROTOCOL_H__ +#define __EFI_HTTP_PROTOCOL_H__ + +#define EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID \ + { \ + 0xbdc8e6af, 0xd9bc, 0x4379, {0xa7, 0x2a, 0xe0, 0xc4, 0xe7, 0x5d, 0xae, 0x1c } \ + } + +#define EFI_HTTP_PROTOCOL_GUID \ + { \ + 0x7a59b29b, 0x910b, 0x4171, {0x82, 0x42, 0xa8, 0x5a, 0x0d, 0xf2, 0x5b, 0x5b } \ + } + +typedef struct _EFI_HTTP_PROTOCOL EFI_HTTP_PROTOCOL; + +/// +/// EFI_HTTP_VERSION +/// +typedef enum { + HttpVersion10, + HttpVersion11, + HttpVersionUnsupported +} EFI_HTTP_VERSION; + +/// +/// EFI_HTTP_METHOD +/// +typedef enum { + HttpMethodGet, + HttpMethodPost, + HttpMethodPatch, + HttpMethodOptions, + HttpMethodConnect, + HttpMethodHead, + HttpMethodPut, + HttpMethodDelete, + HttpMethodTrace, + HttpMethodMax +} EFI_HTTP_METHOD; + +/// +/// EFI_HTTP_STATUS_CODE +/// +typedef enum { + HTTP_STATUS_UNSUPPORTED_STATUS = 0, + HTTP_STATUS_100_CONTINUE, + HTTP_STATUS_101_SWITCHING_PROTOCOLS, + HTTP_STATUS_200_OK, + HTTP_STATUS_201_CREATED, + HTTP_STATUS_202_ACCEPTED, + HTTP_STATUS_203_NON_AUTHORITATIVE_INFORMATION, + HTTP_STATUS_204_NO_CONTENT, + HTTP_STATUS_205_RESET_CONTENT, + HTTP_STATUS_206_PARTIAL_CONTENT, + HTTP_STATUS_300_MULTIPLE_CHOICES, + HTTP_STATUS_301_MOVED_PERMANENTLY, + HTTP_STATUS_302_FOUND, + HTTP_STATUS_303_SEE_OTHER, + HTTP_STATUS_304_NOT_MODIFIED, + HTTP_STATUS_305_USE_PROXY, + HTTP_STATUS_307_TEMPORARY_REDIRECT, + HTTP_STATUS_400_BAD_REQUEST, + HTTP_STATUS_401_UNAUTHORIZED, + HTTP_STATUS_402_PAYMENT_REQUIRED, + HTTP_STATUS_403_FORBIDDEN, + HTTP_STATUS_404_NOT_FOUND, + HTTP_STATUS_405_METHOD_NOT_ALLOWED, + HTTP_STATUS_406_NOT_ACCEPTABLE, + HTTP_STATUS_407_PROXY_AUTHENTICATION_REQUIRED, + HTTP_STATUS_408_REQUEST_TIME_OUT, + HTTP_STATUS_409_CONFLICT, + HTTP_STATUS_410_GONE, + HTTP_STATUS_411_LENGTH_REQUIRED, + HTTP_STATUS_412_PRECONDITION_FAILED, + HTTP_STATUS_413_REQUEST_ENTITY_TOO_LARGE, + HTTP_STATUS_414_REQUEST_URI_TOO_LARGE, + HTTP_STATUS_415_UNSUPPORTED_MEDIA_TYPE, + HTTP_STATUS_416_REQUESTED_RANGE_NOT_SATISFIED, + HTTP_STATUS_417_EXPECTATION_FAILED, + HTTP_STATUS_500_INTERNAL_SERVER_ERROR, + HTTP_STATUS_501_NOT_IMPLEMENTED, + HTTP_STATUS_502_BAD_GATEWAY, + HTTP_STATUS_503_SERVICE_UNAVAILABLE, + HTTP_STATUS_504_GATEWAY_TIME_OUT, + HTTP_STATUS_505_HTTP_VERSION_NOT_SUPPORTED, + HTTP_STATUS_308_PERMANENT_REDIRECT +} EFI_HTTP_STATUS_CODE; + +/// +/// EFI_HTTPv4_ACCESS_POINT +/// +typedef struct { + /// + /// Set to TRUE to instruct the EFI HTTP instance to use the default address + /// information in every TCP connection made by this instance. In addition, when set + /// to TRUE, LocalAddress and LocalSubnet are ignored. + /// + BOOLEAN UseDefaultAddress; + /// + /// If UseDefaultAddress is set to FALSE, this defines the local IP address to be + /// used in every TCP connection opened by this instance. + /// + EFI_IPv4_ADDRESS LocalAddress; + /// + /// If UseDefaultAddress is set to FALSE, this defines the local subnet to be used + /// in every TCP connection opened by this instance. + /// + EFI_IPv4_ADDRESS LocalSubnet; + /// + /// This defines the local port to be used in + /// every TCP connection opened by this instance. + /// + UINT16 LocalPort; +} EFI_HTTPv4_ACCESS_POINT; + +/// +/// EFI_HTTPv6_ACCESS_POINT +/// +typedef struct { + /// + /// Local IP address to be used in every TCP connection opened by this instance. + /// + EFI_IPv6_ADDRESS LocalAddress; + /// + /// Local port to be used in every TCP connection opened by this instance. + /// + UINT16 LocalPort; +} EFI_HTTPv6_ACCESS_POINT; + +/// +/// EFI_HTTP_CONFIG_DATA_ACCESS_POINT +/// + + +typedef struct { + /// + /// HTTP version that this instance will support. + /// + EFI_HTTP_VERSION HttpVersion; + /// + /// Time out (in milliseconds) when blocking for requests. + /// + UINT32 TimeOutMillisec; + /// + /// Defines behavior of EFI DNS and TCP protocols consumed by this instance. If + /// FALSE, this instance will use EFI_DNS4_PROTOCOL and EFI_TCP4_PROTOCOL. If TRUE, + /// this instance will use EFI_DNS6_PROTOCOL and EFI_TCP6_PROTOCOL. + /// + BOOLEAN LocalAddressIsIPv6; + + union { + /// + /// When LocalAddressIsIPv6 is FALSE, this points to the local address, subnet, and + /// port used by the underlying TCP protocol. + /// + EFI_HTTPv4_ACCESS_POINT *IPv4Node; + /// + /// When LocalAddressIsIPv6 is TRUE, this points to the local IPv6 address and port + /// used by the underlying TCP protocol. + /// + EFI_HTTPv6_ACCESS_POINT *IPv6Node; + } AccessPoint; +} EFI_HTTP_CONFIG_DATA; + +/// +/// EFI_HTTP_REQUEST_DATA +/// +typedef struct { + /// + /// The HTTP method (e.g. GET, POST) for this HTTP Request. + /// + EFI_HTTP_METHOD Method; + /// + /// The URI of a remote host. From the information in this field, the HTTP instance + /// will be able to determine whether to use HTTP or HTTPS and will also be able to + /// determine the port number to use. If no port number is specified, port 80 (HTTP) + /// is assumed. See RFC 3986 for more details on URI syntax. + /// + CHAR16 *Url; +} EFI_HTTP_REQUEST_DATA; + +/// +/// EFI_HTTP_RESPONSE_DATA +/// +typedef struct { + /// + /// Response status code returned by the remote host. + /// + EFI_HTTP_STATUS_CODE StatusCode; +} EFI_HTTP_RESPONSE_DATA; + +/// +/// EFI_HTTP_HEADER +/// +typedef struct { + /// + /// Null terminated string which describes a field name. See RFC 2616 Section 14 for + /// detailed information about field names. + /// + CHAR8 *FieldName; + /// + /// Null terminated string which describes the corresponding field value. See RFC 2616 + /// Section 14 for detailed information about field values. + /// + CHAR8 *FieldValue; +} EFI_HTTP_HEADER; + +/// +/// EFI_HTTP_MESSAGE +/// +typedef struct { + /// + /// HTTP message data. + /// + union { + /// + /// When the token is used to send a HTTP request, Request is a pointer to storage that + /// contains such data as URL and HTTP method. + /// + EFI_HTTP_REQUEST_DATA *Request; + /// + /// When used to await a response, Response points to storage containing HTTP response + /// status code. + /// + EFI_HTTP_RESPONSE_DATA *Response; + } Data; + /// + /// Number of HTTP header structures in Headers list. On request, this count is + /// provided by the caller. On response, this count is provided by the HTTP driver. + /// + UINTN HeaderCount; + /// + /// Array containing list of HTTP headers. On request, this array is populated by the + /// caller. On response, this array is allocated and populated by the HTTP driver. It + /// is the responsibility of the caller to free this memory on both request and + /// response. + /// + EFI_HTTP_HEADER *Headers; + /// + /// Length in bytes of the HTTP body. This can be zero depending on the HttpMethod type. + /// + UINTN BodyLength; + /// + /// Body associated with the HTTP request or response. This can be NULL depending on + /// the HttpMethod type. + /// + VOID *Body; +} EFI_HTTP_MESSAGE; + + +/// +/// EFI_HTTP_TOKEN +/// +typedef struct { + /// + /// This Event will be signaled after the Status field is updated by the EFI HTTP + /// Protocol driver. The type of Event must be EFI_NOTIFY_SIGNAL. The Task Priority + /// Level (TPL) of Event must be lower than or equal to TPL_CALLBACK. + /// + EFI_EVENT Event; + /// + /// Status will be set to one of the following value if the HTTP request is + /// successfully sent or if an unexpected error occurs: + /// EFI_SUCCESS: The HTTP request was successfully sent to the remote host. + /// EFI_HTTP_ERROR: The response message was successfully received but contains a + /// HTTP error. The response status code is returned in token. + /// EFI_ABORTED: The HTTP request was cancelled by the caller and removed from + /// the transmit queue. + /// EFI_TIMEOUT: The HTTP request timed out before reaching the remote host. + /// EFI_DEVICE_ERROR: An unexpected system or network error occurred. + /// + EFI_STATUS Status; + /// + /// Pointer to storage containing HTTP message data. + /// + EFI_HTTP_MESSAGE *Message; +} EFI_HTTP_TOKEN; + +/** + Returns the operational parameters for the current HTTP child instance. + + The GetModeData() function is used to read the current mode data (operational + parameters) for this HTTP protocol instance. + + @param[in] This Pointer to EFI_HTTP_PROTOCOL instance. + @param[out] HttpConfigData Point to buffer for operational parameters of this + HTTP instance. It is the responsibility of the caller + to allocate the memory for HttpConfigData and + HttpConfigData->AccessPoint.IPv6Node/IPv4Node. In fact, + it is recommended to allocate sufficient memory to record + IPv6Node since it is big enough for all possibilities. + + @retval EFI_SUCCESS Operation succeeded. + @retval EFI_INVALID_PARAMETER This is NULL. + HttpConfigData is NULL. + HttpConfigData->AccessPoint.IPv4Node or + HttpConfigData->AccessPoint.IPv6Node is NULL. + @retval EFI_NOT_STARTED This EFI HTTP Protocol instance has not been started. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_HTTP_GET_MODE_DATA)( + IN EFI_HTTP_PROTOCOL *This, + OUT EFI_HTTP_CONFIG_DATA *HttpConfigData + ); + +/** + Initialize or brutally reset the operational parameters for this EFI HTTP instance. + + The Configure() function does the following: + When HttpConfigData is not NULL Initialize this EFI HTTP instance by configuring + timeout, local address, port, etc. + When HttpConfigData is NULL, reset this EFI HTTP instance by closing all active + connections with remote hosts, canceling all asynchronous tokens, and flush request + and response buffers without informing the appropriate hosts. + + No other EFI HTTP function can be executed by this instance until the Configure() + function is executed and returns successfully. + + @param[in] This Pointer to EFI_HTTP_PROTOCOL instance. + @param[in] HttpConfigData Pointer to the configure data to configure the instance. + + @retval EFI_SUCCESS Operation succeeded. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + This is NULL. + HttpConfigData->LocalAddressIsIPv6 is FALSE and + HttpConfigData->AccessPoint.IPv4Node is NULL. + HttpConfigData->LocalAddressIsIPv6 is TRUE and + HttpConfigData->AccessPoint.IPv6Node is NULL. + @retval EFI_ALREADY_STARTED Reinitialize this HTTP instance without calling + Configure() with NULL to reset it. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + @retval EFI_OUT_OF_RESOURCES Could not allocate enough system resources when + executing Configure(). + @retval EFI_UNSUPPORTED One or more options in ConfigData are not supported + in the implementation. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_HTTP_CONFIGURE)( + IN EFI_HTTP_PROTOCOL *This, + IN EFI_HTTP_CONFIG_DATA *HttpConfigData OPTIONAL + ); + +/** + The Request() function queues an HTTP request to this HTTP instance, + similar to Transmit() function in the EFI TCP driver. When the HTTP request is sent + successfully, or if there is an error, Status in token will be updated and Event will + be signaled. + + @param[in] This Pointer to EFI_HTTP_PROTOCOL instance. + @param[in] Token Pointer to storage containing HTTP request token. + + @retval EFI_SUCCESS Outgoing data was processed. + @retval EFI_NOT_STARTED This EFI HTTP Protocol instance has not been started. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + @retval EFI_TIMEOUT Data was dropped out of the transmit or receive queue. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + This is NULL. + Token is NULL. + Token->Message is NULL. + Token->Message->Body is not NULL, + Token->Message->BodyLength is non-zero, and + Token->Message->Data is NULL, but a previous call to + Request()has not been completed successfully. + @retval EFI_OUT_OF_RESOURCES Could not allocate enough system resources. + @retval EFI_UNSUPPORTED The HTTP method is not supported in current implementation. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_HTTP_REQUEST) ( + IN EFI_HTTP_PROTOCOL *This, + IN EFI_HTTP_TOKEN *Token + ); + +/** + Abort an asynchronous HTTP request or response token. + + The Cancel() function aborts a pending HTTP request or response transaction. If + Token is not NULL and the token is in transmit or receive queues when it is being + cancelled, its Token->Status will be set to EFI_ABORTED and then Token->Event will + be signaled. If the token is not in one of the queues, which usually means that the + asynchronous operation has completed, EFI_NOT_FOUND is returned. If Token is NULL, + all asynchronous tokens issued by Request() or Response() will be aborted. + + @param[in] This Pointer to EFI_HTTP_PROTOCOL instance. + @param[in] Token Point to storage containing HTTP request or response + token. + + @retval EFI_SUCCESS Request and Response queues are successfully flushed. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_NOT_STARTED This instance hasn't been configured. + @retval EFI_NOT_FOUND The asynchronous request or response token is not + found. + @retval EFI_UNSUPPORTED The implementation does not support this function. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_HTTP_CANCEL)( + IN EFI_HTTP_PROTOCOL *This, + IN EFI_HTTP_TOKEN *Token + ); + +/** + The Response() function queues an HTTP response to this HTTP instance, similar to + Receive() function in the EFI TCP driver. When the HTTP Response is received successfully, + or if there is an error, Status in token will be updated and Event will be signaled. + + The HTTP driver will queue a receive token to the underlying TCP instance. When data + is received in the underlying TCP instance, the data will be parsed and Token will + be populated with the response data. If the data received from the remote host + contains an incomplete or invalid HTTP header, the HTTP driver will continue waiting + (asynchronously) for more data to be sent from the remote host before signaling + Event in Token. + + It is the responsibility of the caller to allocate a buffer for Body and specify the + size in BodyLength. If the remote host provides a response that contains a content + body, up to BodyLength bytes will be copied from the receive buffer into Body and + BodyLength will be updated with the amount of bytes received and copied to Body. This + allows the client to download a large file in chunks instead of into one contiguous + block of memory. Similar to HTTP request, if Body is not NULL and BodyLength is + non-zero and all other fields are NULL or 0, the HTTP driver will queue a receive + token to underlying TCP instance. If data arrives in the receive buffer, up to + BodyLength bytes of data will be copied to Body. The HTTP driver will then update + BodyLength with the amount of bytes received and copied to Body. + + If the HTTP driver does not have an open underlying TCP connection with the host + specified in the response URL, Request() will return EFI_ACCESS_DENIED. This is + consistent with RFC 2616 recommendation that HTTP clients should attempt to maintain + an open TCP connection between client and host. + + @param[in] This Pointer to EFI_HTTP_PROTOCOL instance. + @param[in] Token Pointer to storage containing HTTP response token. + + @retval EFI_SUCCESS Allocation succeeded. + @retval EFI_NOT_STARTED This EFI HTTP Protocol instance has not been + initialized. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + This is NULL. + Token is NULL. + Token->Message->Headers is NULL. + Token->Message is NULL. + Token->Message->Body is not NULL, + Token->Message->BodyLength is non-zero, and + Token->Message->Data is NULL, but a previous call to + Response() has not been completed successfully. + @retval EFI_OUT_OF_RESOURCES Could not allocate enough system resources. + @retval EFI_ACCESS_DENIED An open TCP connection is not present with the host + specified by response URL. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_HTTP_RESPONSE) ( + IN EFI_HTTP_PROTOCOL *This, + IN EFI_HTTP_TOKEN *Token + ); + +/** + The Poll() function can be used by network drivers and applications to increase the + rate that data packets are moved between the communication devices and the transmit + and receive queues. + + In some systems, the periodic timer event in the managed network driver may not poll + the underlying communications device fast enough to transmit and/or receive all data + packets without missing incoming packets or dropping outgoing packets. Drivers and + applications that are experiencing packet loss should try calling the Poll() function + more often. + + @param[in] This Pointer to EFI_HTTP_PROTOCOL instance. + + @retval EFI_SUCCESS Incoming or outgoing data was processed.. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_NOT_READY No incoming or outgoing data is processed. + @retval EFI_NOT_STARTED This EFI HTTP Protocol instance has not been started. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_HTTP_POLL) ( + IN EFI_HTTP_PROTOCOL *This + ); + +/// +/// The EFI HTTP protocol is designed to be used by EFI drivers and applications to +/// create and transmit HTTP Requests, as well as handle HTTP responses that are +/// returned by a remote host. This EFI protocol uses and relies on an underlying EFI +/// TCP protocol. +/// +struct _EFI_HTTP_PROTOCOL { + EFI_HTTP_GET_MODE_DATA GetModeData; + EFI_HTTP_CONFIGURE Configure; + EFI_HTTP_REQUEST Request; + EFI_HTTP_CANCEL Cancel; + EFI_HTTP_RESPONSE Response; + EFI_HTTP_POLL Poll; +}; + +extern EFI_GUID gEfiHttpServiceBindingProtocolGuid; +extern EFI_GUID gEfiHttpProtocolGuid; + +#endif diff --git a/stand/efi/include/Protocol/Ip4Config2.h b/stand/efi/include/Protocol/Ip4Config2.h new file mode 100644 index 000000000000..47241d7ad7d4 --- /dev/null +++ b/stand/efi/include/Protocol/Ip4Config2.h @@ -0,0 +1,324 @@ +/* $FreeBSD$ */ +/** @file + This file provides a definition of the EFI IPv4 Configuration II + Protocol. + +Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR> +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at<BR> +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +@par Revision Reference: +This Protocol is introduced in UEFI Specification 2.5 + +**/ +#ifndef __EFI_IP4CONFIG2_PROTOCOL_H__ +#define __EFI_IP4CONFIG2_PROTOCOL_H__ + +/* #include <Protocol/Ip4.h> */ + +#define EFI_IP4_CONFIG2_PROTOCOL_GUID \ + { \ + 0x5b446ed1, 0xe30b, 0x4faa, {0x87, 0x1a, 0x36, 0x54, 0xec, 0xa3, 0x60, 0x80 } \ + } + +typedef struct _EFI_IP4_CONFIG2_PROTOCOL EFI_IP4_CONFIG2_PROTOCOL; + + +/// +/// EFI_IP4_CONFIG2_DATA_TYPE +/// +typedef enum { + /// + /// The interface information of the communication device this EFI + /// IPv4 Configuration II Protocol instance manages. This type of + /// data is read only. The corresponding Data is of type + /// EFI_IP4_CONFIG2_INTERFACE_INFO. + /// + Ip4Config2DataTypeInterfaceInfo, + /// + /// The general configuration policy for the EFI IPv4 network stack + /// running on the communication device this EFI IPv4 + /// Configuration II Protocol instance manages. The policy will + /// affect other configuration settings. The corresponding Data is of + /// type EFI_IP4_CONFIG2_POLICY. + /// + Ip4Config2DataTypePolicy, + /// + /// The station addresses set manually for the EFI IPv4 network + /// stack. It is only configurable when the policy is + /// Ip4Config2PolicyStatic. The corresponding Data is of + /// type EFI_IP4_CONFIG2_MANUAL_ADDRESS. When DataSize + /// is 0 and Data is NULL, the existing configuration is cleared + /// from the EFI IPv4 Configuration II Protocol instance. + /// + Ip4Config2DataTypeManualAddress, + /// + /// The gateway addresses set manually for the EFI IPv4 network + /// stack running on the communication device this EFI IPv4 + /// Configuration II Protocol manages. It is not configurable when + /// the policy is Ip4Config2PolicyDhcp. The gateway + /// addresses must be unicast IPv4 addresses. The corresponding + /// Data is a pointer to an array of EFI_IPv4_ADDRESS instances. + /// When DataSize is 0 and Data is NULL, the existing configuration + /// is cleared from the EFI IPv4 Configuration II Protocol instance. + /// + Ip4Config2DataTypeGateway, + /// + /// The DNS server list for the EFI IPv4 network stack running on + /// the communication device this EFI IPv4 Configuration II + /// Protocol manages. It is not configurable when the policy is + /// Ip4Config2PolicyDhcp. The DNS server addresses must be + /// unicast IPv4 addresses. The corresponding Data is a pointer to + /// an array of EFI_IPv4_ADDRESS instances. When DataSize + /// is 0 and Data is NULL, the existing configuration is cleared + /// from the EFI IPv4 Configuration II Protocol instance. + /// + Ip4Config2DataTypeDnsServer, + Ip4Config2DataTypeMaximum +} EFI_IP4_CONFIG2_DATA_TYPE; + +/// +/// EFI_IP4_CONFIG2_INTERFACE_INFO related definitions +/// +#define EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE 32 + +/// +/// EFI_IP4_CONFIG2_INTERFACE_INFO +/// +typedef struct { + /// + /// The name of the interface. It is a NULL-terminated Unicode string. + /// + CHAR16 Name[EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE]; + /// + /// The interface type of the network interface. See RFC 1700, + /// section "Number Hardware Type". + /// + UINT8 IfType; + /// + /// The size, in bytes, of the network interface's hardware address. + /// + UINT32 HwAddressSize; + /// + /// The hardware address for the network interface. + /// + EFI_MAC_ADDRESS HwAddress; + /// + /// The station IPv4 address of this EFI IPv4 network stack. + /// + EFI_IPv4_ADDRESS StationAddress; + /// + /// The subnet address mask that is associated with the station address. + /// + EFI_IPv4_ADDRESS SubnetMask; + /// + /// Size of the following RouteTable, in bytes. May be zero. + /// + UINT32 RouteTableSize; + /// + /// The route table of the IPv4 network stack runs on this interface. + /// Set to NULL if RouteTableSize is zero. Type EFI_IP4_ROUTE_TABLE is defined in + /// EFI_IP4_PROTOCOL.GetModeData(). + /// + EFI_IP4_ROUTE_TABLE *RouteTable OPTIONAL; +} EFI_IP4_CONFIG2_INTERFACE_INFO; + +/// +/// EFI_IP4_CONFIG2_POLICY +/// +typedef enum { + /// + /// Under this policy, the Ip4Config2DataTypeManualAddress, + /// Ip4Config2DataTypeGateway and Ip4Config2DataTypeDnsServer configuration + /// data are required to be set manually. The EFI IPv4 Protocol will get all + /// required configuration such as IPv4 address, subnet mask and + /// gateway settings from the EFI IPv4 Configuration II protocol. + /// + Ip4Config2PolicyStatic, + /// + /// Under this policy, the Ip4Config2DataTypeManualAddress, + /// Ip4Config2DataTypeGateway and Ip4Config2DataTypeDnsServer configuration data are + /// not allowed to set via SetData(). All of these configurations are retrieved from DHCP + /// server or other auto-configuration mechanism. + /// + Ip4Config2PolicyDhcp, + Ip4Config2PolicyMax +} EFI_IP4_CONFIG2_POLICY; + +/// +/// EFI_IP4_CONFIG2_MANUAL_ADDRESS +/// +typedef struct { + /// + /// The IPv4 unicast address. + /// + EFI_IPv4_ADDRESS Address; + /// + /// The subnet mask. + /// + EFI_IPv4_ADDRESS SubnetMask; +} EFI_IP4_CONFIG2_MANUAL_ADDRESS; + +/** + Set the configuration for the EFI IPv4 network stack running on the communication device this EFI + IPv4 Configuration II Protocol instance manages. + + This function is used to set the configuration data of type DataType for the EFI IPv4 network stack + running on the communication device this EFI IPv4 Configuration II Protocol instance manages. + The successfully configured data is valid after system reset or power-off. + The DataSize is used to calculate the count of structure instances in the Data for some + DataType that multiple structure instances are allowed. + This function is always non-blocking. When setting some typeof configuration data, an + asynchronous process is invoked to check the correctness of the data, such as doing address conflict + detection on the manually set local IPv4 address. EFI_NOT_READY is returned immediately to + indicate that such an asynchronous process is invoked and the process is not finished yet. The caller + willing to get the result of the asynchronous process is required to call RegisterDataNotify() + to register an event on the specified configuration data. Once the event is signaled, the caller can call + GetData()to get back the configuration data in order to know the result. For other types of + configuration data that do not require an asynchronous configuration process, the result of the + operation is immediately returned. + + @param[in] This Pointer to the EFI_IP4_CONFIG2_PROTOCOL instance. + @param[in] DataType The type of data to set. + @param[in] DataSize Size of the buffer pointed to by Data in bytes. + @param[in] Data The data buffer to set. The type ofthe data buffer is associated + with the DataType. + + @retval EFI_SUCCESS The specified configuration data for the EFI IPv4 network stack is set + successfully. + @retval EFI_INVALID_PARAMETER One or more of the following are TRUE: + This is NULL. + One or more fields in Data and DataSize do not match the + requirement of the data type indicated by DataType. + @retval EFI_WRITE_PROTECTED The specified configuration data is read-only or the specified configuration + data can not be set under the current policy. + @retval EFI_ACCESS_DENIED Another set operation on the specified configuration data is already in process. + @retval EFI_NOT_READY An asynchronous process is invoked to set the specified configuration data and + the process is not finished yet. + @retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type indicated by DataType. + @retval EFI_UNSUPPORTED This DataType is not supported. + @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. + @retval EFI_DEVICE_ERROR An unexpected system error or network error occurred. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IP4_CONFIG2_SET_DATA) ( + IN EFI_IP4_CONFIG2_PROTOCOL *This, + IN EFI_IP4_CONFIG2_DATA_TYPE DataType, + IN UINTN DataSize, + IN VOID *Data + ); + +/** + Get the configuration data for the EFI IPv4 network stack running on the communication device this + EFI IPv4 Configuration II Protocol instance manages. + + This function returns the configuration data of type DataType for the EFI IPv4 network stack + running on the communication device this EFI IPv4 Configuration II Protocol instance manages. + The caller is responsible for allocating the buffer usedto return the specified configuration data and + the required size will be returned to the caller if the size of the buffer is too small. + EFI_NOT_READY is returned if the specified configuration data is not ready due to an already in + progress asynchronous configuration process. The caller can call RegisterDataNotify() to + register an event on the specified configuration data. Once the asynchronous configuration process is + finished, the event will be signaled and a subsequent GetData() call will return the specified + configuration data. + + @param[in] This Pointer to the EFI_IP4_CONFIG2_PROTOCOL instance. + @param[in] DataType The type of data to get. + @param[out] DataSize On input, in bytes, the size of Data. On output, in bytes, the size + of buffer required to store the specified configuration data. + @param[in] Data The data buffer in which the configuration data is returned. The + type of the data buffer is associated with the DataType. Ignored + if DataSize is 0. + + @retval EFI_SUCCESS The specified configuration data is got successfully. + @retval EFI_INVALID_PARAMETER One or more of the followings are TRUE: + This is NULL. + DataSize is NULL. + Data is NULL if *DataSizeis not zero. + @retval EFI_BUFFER_TOO_SMALL The size of Data is too small for the specified configuration data + and the required size is returned in DataSize. + @retval EFI_NOT_READY The specified configuration data is not ready due to an already in + progress asynchronous configuration process. + @retval EFI_NOT_FOUND The specified configuration data is not found. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IP4_CONFIG2_GET_DATA) ( + IN EFI_IP4_CONFIG2_PROTOCOL *This, + IN EFI_IP4_CONFIG2_DATA_TYPE DataType, + IN OUT UINTN *DataSize, + IN VOID *Data OPTIONAL + ); + +/** + Register an event that is to be signaled whenever a configuration process on the specified + configuration data is done. + + This function registers an event that is to be signaled whenever a configuration process on the + specified configuration data is done. An event can be registered for different DataType + simultaneously and the caller is responsible for determining which type of configuration data causes + the signaling of the event in such case. + + @param[in] This Pointer to the EFI_IP4_CONFIG2_PROTOCOL instance. + @param[in] DataType The type of data to unregister the event for. + @param[in] Event The event to register. + + @retval EFI_SUCCESS The notification event for the specified configuration data is + registered. + @retval EFI_INVALID_PARAMETER This is NULL or Event is NULL. + @retval EFI_UNSUPPORTED The configuration data type specified by DataType is not supported. + @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. + @retval EFI_ACCESS_DENIED The Event is already registered for the DataType. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IP4_CONFIG2_REGISTER_NOTIFY) ( + IN EFI_IP4_CONFIG2_PROTOCOL *This, + IN EFI_IP4_CONFIG2_DATA_TYPE DataType, + IN EFI_EVENT Event + ); + +/** + Remove a previously registered event for the specified configuration data. + + This function removes a previously registeredevent for the specified configuration data. + + @param[in] This Pointer to the EFI_IP4_CONFIG2_PROTOCOL instance. + @param[in] DataType The type of data to remove the previously registered event for. + @param[in] Event The event to unregister. + + @retval EFI_SUCCESS The event registered for the specified configuration data is removed. + @retval EFI_INVALID_PARAMETER This is NULL or Event is NULL. + @retval EFI_NOT_FOUND The Eventhas not been registered for the specified DataType. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IP4_CONFIG2_UNREGISTER_NOTIFY) ( + IN EFI_IP4_CONFIG2_PROTOCOL *This, + IN EFI_IP4_CONFIG2_DATA_TYPE DataType, + IN EFI_EVENT Event + ); + +/// +/// The EFI_IP4_CONFIG2_PROTOCOL is designed to be the central repository for the common +/// configurations and the administrator configurable settings for the EFI IPv4 network stack. +/// An EFI IPv4 Configuration II Protocol instance will be installed on each communication device that +/// the EFI IPv4 network stack runs on. +/// +struct _EFI_IP4_CONFIG2_PROTOCOL { + EFI_IP4_CONFIG2_SET_DATA SetData; + EFI_IP4_CONFIG2_GET_DATA GetData; + EFI_IP4_CONFIG2_REGISTER_NOTIFY RegisterDataNotify; + EFI_IP4_CONFIG2_UNREGISTER_NOTIFY UnregisterDataNotify; +}; + +extern EFI_GUID gEfiIp4Config2ProtocolGuid; + +#endif + diff --git a/stand/efi/include/Protocol/ServiceBinding.h b/stand/efi/include/Protocol/ServiceBinding.h new file mode 100644 index 000000000000..39602b086e5b --- /dev/null +++ b/stand/efi/include/Protocol/ServiceBinding.h @@ -0,0 +1,95 @@ +/* $FreeBSD$ */ +/** @file + UEFI Service Binding Protocol is defined in UEFI specification. + + The file defines the generic Service Binding Protocol functions. + It provides services that are required to create and destroy child + handles that support a given set of protocols. + + Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR> + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __EFI_SERVICE_BINDING_H__ +#define __EFI_SERVICE_BINDING_H__ + +/// +/// Forward reference for pure ANSI compatibility +/// +typedef struct _EFI_SERVICE_BINDING_PROTOCOL EFI_SERVICE_BINDING_PROTOCOL; + +/** + Creates a child handle and installs a protocol. + + The CreateChild() function installs a protocol on ChildHandle. + If ChildHandle is a pointer to NULL, then a new handle is created and returned in ChildHandle. + If ChildHandle is not a pointer to NULL, then the protocol installs on the existing ChildHandle. + + @param This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance. + @param ChildHandle Pointer to the handle of the child to create. If it is NULL, + then a new handle is created. If it is a pointer to an existing UEFI handle, + then the protocol is added to the existing UEFI handle. + + @retval EFI_SUCCES The protocol was added to ChildHandle. + @retval EFI_INVALID_PARAMETER ChildHandle is NULL. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available to create + the child + @retval other The child handle was not created + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SERVICE_BINDING_CREATE_CHILD)( + IN EFI_SERVICE_BINDING_PROTOCOL *This, + IN OUT EFI_HANDLE *ChildHandle + ); + +/** + Destroys a child handle with a protocol installed on it. + + The DestroyChild() function does the opposite of CreateChild(). It removes a protocol + that was installed by CreateChild() from ChildHandle. If the removed protocol is the + last protocol on ChildHandle, then ChildHandle is destroyed. + + @param This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance. + @param ChildHandle Handle of the child to destroy + + @retval EFI_SUCCES The protocol was removed from ChildHandle. + @retval EFI_UNSUPPORTED ChildHandle does not support the protocol that is being removed. + @retval EFI_INVALID_PARAMETER Child handle is NULL. + @retval EFI_ACCESS_DENIED The protocol could not be removed from the ChildHandle + because its services are being used. + @retval other The child handle was not destroyed + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SERVICE_BINDING_DESTROY_CHILD)( + IN EFI_SERVICE_BINDING_PROTOCOL *This, + IN EFI_HANDLE ChildHandle + ); + +/// +/// The EFI_SERVICE_BINDING_PROTOCOL provides member functions to create and destroy +/// child handles. A driver is responsible for adding protocols to the child handle +/// in CreateChild() and removing protocols in DestroyChild(). It is also required +/// that the CreateChild() function opens the parent protocol BY_CHILD_CONTROLLER +/// to establish the parent-child relationship, and closes the protocol in DestroyChild(). +/// The pseudo code for CreateChild() and DestroyChild() is provided to specify the +/// required behavior, not to specify the required implementation. Each consumer of +/// a software protocol is responsible for calling CreateChild() when it requires the +/// protocol and calling DestroyChild() when it is finished with that protocol. +/// +struct _EFI_SERVICE_BINDING_PROTOCOL { + EFI_SERVICE_BINDING_CREATE_CHILD CreateChild; + EFI_SERVICE_BINDING_DESTROY_CHILD DestroyChild; +}; + +#endif diff --git a/stand/efi/include/efidevp.h b/stand/efi/include/efidevp.h index 6f320260952e..70e506efa50b 100644 --- a/stand/efi/include/efidevp.h +++ b/stand/efi/include/efidevp.h @@ -232,6 +232,8 @@ typedef struct _IPv4_DEVICE_PATH { UINT16 RemotePort; UINT16 Protocol; BOOLEAN StaticIpAddress; + EFI_IPv4_ADDRESS GatewayIpAddress; + EFI_IPv4_ADDRESS SubnetMask; } IPv4_DEVICE_PATH; #define MSG_IPv6_DP 0x0d @@ -294,6 +296,26 @@ typedef struct _SATA_DEVICE_PATH { UINT16 Lun; } SATA_DEVICE_PATH; + +/* DNS Device Path SubType */ +#define MSG_DNS_DP 0x1F +typedef struct { + EFI_DEVICE_PATH Header; + /* Indicates the DNS server address is IPv4 or IPv6 address. */ + UINT8 IsIPv6; + /* Instance of the DNS server address. */ + /* XXX: actually EFI_IP_ADDRESS */ + EFI_IPv4_ADDRESS DnsServerIp[]; +} DNS_DEVICE_PATH; + +/* Uniform Resource Identifiers (URI) Device Path SubType */ +#define MSG_URI_DP 0x18 +typedef struct { + EFI_DEVICE_PATH Header; + /* Instance of the URI pursuant to RFC 3986. */ + CHAR8 Uri[]; +} URI_DEVICE_PATH; + #define MEDIA_DEVICE_PATH 0x04 #define MEDIA_HARDDRIVE_DP 0x01 diff --git a/stand/efi/include/efilib.h b/stand/efi/include/efilib.h index 91fa294965a3..6ca41d848384 100644 --- a/stand/efi/include/efilib.h +++ b/stand/efi/include/efilib.h @@ -42,6 +42,7 @@ extern EFI_RUNTIME_SERVICES *RS; extern struct devsw efipart_fddev; extern struct devsw efipart_cddev; extern struct devsw efipart_hddev; +extern struct devsw efihttp_dev; extern struct devsw efinet_dev; extern struct netif_driver efinetif; diff --git a/stand/efi/libefi/Makefile b/stand/efi/libefi/Makefile index 9b0330815900..7ca1a1f92fd7 100644 --- a/stand/efi/libefi/Makefile +++ b/stand/efi/libefi/Makefile @@ -12,6 +12,7 @@ SRCS= delay.c \ efi_driver_utils.c \ efichar.c \ efienv.c \ + efihttp.c \ efinet.c \ efipart.c \ efizfs.c \ diff --git a/stand/efi/libefi/efihttp.c b/stand/efi/libefi/efihttp.c new file mode 100644 index 000000000000..abe2e28821ea --- /dev/null +++ b/stand/efi/libefi/efihttp.c @@ -0,0 +1,776 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2019 Intel Corporation + * + * 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 AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/types.h> + +#include <netinet/in.h> +#include <netinet/in_systm.h> + +#include <stand.h> +#include <net.h> + +#include <efi.h> +#include <efilib.h> +#include <efiprot.h> +#include <Protocol/Http.h> +#include <Protocol/Ip4Config2.h> +#include <Protocol/ServiceBinding.h> + +/* Poll timeout in milliseconds */ +static const int EFIHTTP_POLL_TIMEOUT = 300000; + +static EFI_GUID http_guid = EFI_HTTP_PROTOCOL_GUID; +static EFI_GUID httpsb_guid = EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID; +static EFI_GUID ip4config2_guid = EFI_IP4_CONFIG2_PROTOCOL_GUID; + +static bool efihttp_init_done = false; + +static int efihttp_dev_init(void); +static int efihttp_dev_strategy(void *devdata, int rw, daddr_t blk, size_t size, + char *buf, size_t *rsize); +static int efihttp_dev_open(struct open_file *f, ...); +static int efihttp_dev_close(struct open_file *f); + +static int efihttp_fs_open(const char *path, struct open_file *f); +static int efihttp_fs_close(struct open_file *f); +static int efihttp_fs_read(struct open_file *f, void *buf, size_t size, + size_t *resid); +static int efihttp_fs_write(struct open_file *f, const void *buf, size_t size, + size_t *resid); +static off_t efihttp_fs_seek(struct open_file *f, off_t offset, int where); +static int efihttp_fs_stat(struct open_file *f, struct stat *sb); +static int efihttp_fs_readdir(struct open_file *f, struct dirent *d); + +struct open_efihttp { + EFI_HTTP_PROTOCOL *http; + EFI_HANDLE http_handle; + EFI_HANDLE dev_handle; + char *uri_base; +}; + +struct file_efihttp { + ssize_t size; + off_t offset; + char *path; + bool is_dir; +}; + +struct devsw efihttp_dev = { + .dv_name = "http", + .dv_type = DEVT_NET, + .dv_init = efihttp_dev_init, + .dv_strategy = efihttp_dev_strategy, + .dv_open = efihttp_dev_open, + .dv_close = efihttp_dev_close, + .dv_ioctl = noioctl, + .dv_print = NULL, + .dv_cleanup = NULL, +}; + +struct fs_ops efihttp_fsops = { + .fs_name = "efihttp", + .fo_open = efihttp_fs_open, + .fo_close = efihttp_fs_close, + .fo_read = efihttp_fs_read, + .fo_write = efihttp_fs_write, + .fo_seek = efihttp_fs_seek, + .fo_stat = efihttp_fs_stat, + .fo_readdir = efihttp_fs_readdir, +}; + +static void EFIAPI +notify(EFI_EVENT event, void *context) +{ + bool *b; + + b = (bool *)context; + *b = true; +} + +static int +setup_ipv4_config2(EFI_HANDLE handle, MAC_ADDR_DEVICE_PATH *mac, + IPv4_DEVICE_PATH *ipv4, DNS_DEVICE_PATH *dns) +{ + EFI_IP4_CONFIG2_PROTOCOL *ip4config2; + EFI_STATUS status; + + status = BS->OpenProtocol(handle, &ip4config2_guid, + (void **)&ip4config2, IH, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + if (ipv4) { + setenv("boot.netif.hwaddr", + ether_sprintf((u_char *)mac->MacAddress.Addr), 1); + setenv("boot.netif.ip", + inet_ntoa(*(struct in_addr *)ipv4->LocalIpAddress.Addr), 1); + setenv("boot.netif.netmask", + intoa(*(n_long *)ipv4->SubnetMask.Addr), 1); + setenv("boot.netif.gateway", + inet_ntoa(*(struct in_addr *)ipv4->GatewayIpAddress.Addr), + 1); + status = ip4config2->SetData(ip4config2, + Ip4Config2DataTypePolicy, sizeof(EFI_IP4_CONFIG2_POLICY), + &(EFI_IP4_CONFIG2_POLICY) { Ip4Config2PolicyStatic }); + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + + status = ip4config2->SetData(ip4config2, + Ip4Config2DataTypeManualAddress, + sizeof(EFI_IP4_CONFIG2_MANUAL_ADDRESS), + &(EFI_IP4_CONFIG2_MANUAL_ADDRESS) { + .Address = ipv4->LocalIpAddress, + .SubnetMask = ipv4->SubnetMask }); + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + + if (ipv4->GatewayIpAddress.Addr[0] != 0) { + status = ip4config2->SetData(ip4config2, + Ip4Config2DataTypeGateway, sizeof(EFI_IPv4_ADDRESS), + &ipv4->GatewayIpAddress); + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + } + + if (dns) { + status = ip4config2->SetData(ip4config2, + Ip4Config2DataTypeDnsServer, + sizeof(EFI_IPv4_ADDRESS), &dns->DnsServerIp); + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + } + } else { + status = ip4config2->SetData(ip4config2, + Ip4Config2DataTypePolicy, sizeof(EFI_IP4_CONFIG2_POLICY), + &(EFI_IP4_CONFIG2_POLICY) { Ip4Config2PolicyDhcp }); + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + } + + return (0); +} + +static int +efihttp_dev_init(void) +{ + EFI_DEVICE_PATH *imgpath, *devpath; + URI_DEVICE_PATH *uri; + EFI_HANDLE handle; + EFI_STATUS status; + int err; + bool found_http; + + imgpath = efi_lookup_image_devpath(IH); + if (imgpath == NULL) + return (ENXIO); + devpath = imgpath; + found_http = false; + for (; !IsDevicePathEnd(devpath); + devpath = NextDevicePathNode(devpath)) { + if (DevicePathType(devpath) != MESSAGING_DEVICE_PATH || + DevicePathSubType(devpath) != MSG_URI_DP) + continue; + uri = (URI_DEVICE_PATH *)devpath; + if (strncmp("http", uri->Uri, 4) == 0) + found_http = true; + } + if (!found_http) + return (ENXIO); + + status = BS->LocateDevicePath(&httpsb_guid, &imgpath, &handle); + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + + err = efi_register_handles(&efihttp_dev, &handle, NULL, 1); + if (!err) + efihttp_init_done = true; + + return (err); +} + +static int +efihttp_dev_strategy(void *devdata, int rw, daddr_t blk, size_t size, char *buf, + size_t *rsize) +{ + return (EIO); +} + +static int +efihttp_dev_open(struct open_file *f, ...) +{ + EFI_HTTP_CONFIG_DATA config; + EFI_HTTPv4_ACCESS_POINT config_access; + DNS_DEVICE_PATH *dns; + EFI_DEVICE_PATH *devpath, *imgpath; + EFI_SERVICE_BINDING_PROTOCOL *sb; + IPv4_DEVICE_PATH *ipv4; + MAC_ADDR_DEVICE_PATH *mac; + URI_DEVICE_PATH *uri; + struct devdesc *dev; + struct open_efihttp *oh; + char *c; + EFI_HANDLE handle; + EFI_STATUS status; + int err, len; + + if (!efihttp_init_done) + return (ENXIO); + + imgpath = efi_lookup_image_devpath(IH); + if (imgpath == NULL) + return (ENXIO); + devpath = imgpath; + status = BS->LocateDevicePath(&httpsb_guid, &devpath, &handle); + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + ipv4 = NULL; + dns = NULL; + uri = NULL; + for (; !IsDevicePathEnd(imgpath); + imgpath = NextDevicePathNode(imgpath)) { + if (DevicePathType(imgpath) != MESSAGING_DEVICE_PATH) + continue; + switch (DevicePathSubType(imgpath)) { + case MSG_MAC_ADDR_DP: + mac = (MAC_ADDR_DEVICE_PATH *)imgpath; + break; + case MSG_IPv4_DP: + ipv4 = (IPv4_DEVICE_PATH *)imgpath; + break; + case MSG_DNS_DP: + dns = (DNS_DEVICE_PATH *)imgpath; + break; + case MSG_URI_DP: + uri = (URI_DEVICE_PATH *)imgpath; + break; + default: + break; + } + } + + if (uri == NULL) + return (ENXIO); + + err = setup_ipv4_config2(handle, mac, ipv4, dns); + if (err) + return (err); + + oh = calloc(1, sizeof(struct open_efihttp)); + if (!oh) + return (ENOMEM); + oh->dev_handle = handle; + dev = (struct devdesc *)f->f_devdata; + dev->d_opendata = oh; + + status = BS->OpenProtocol(handle, &httpsb_guid, (void **)&sb, IH, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR(status)) { + err = efi_status_to_errno(status); + goto end; + } + + status = sb->CreateChild(sb, &oh->http_handle); + if (EFI_ERROR(status)) { + err = efi_status_to_errno(status); + goto end; + } + + status = BS->OpenProtocol(oh->http_handle, &http_guid, + (void **)&oh->http, IH, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR(status)) { + sb->DestroyChild(sb, oh->http_handle); + err = efi_status_to_errno(status); + goto end; + } + + config.HttpVersion = HttpVersion11; + config.TimeOutMillisec = 0; + config.LocalAddressIsIPv6 = FALSE; + config.AccessPoint.IPv4Node = &config_access; + config_access.UseDefaultAddress = TRUE; + config_access.LocalPort = 0; + status = oh->http->Configure(oh->http, &config); + if (EFI_ERROR(status)) { + sb->DestroyChild(sb, oh->http_handle); + err = efi_status_to_errno(status); + goto end; + } + + /* + * Here we make attempt to construct a "base" URI by stripping + * the last two path components from the loaded URI under the + * assumption that it is something like: + * + * http://127.0.0.1/foo/boot/loader.efi + * + * hoping to arriving at: + * + * http://127.0.0.1/foo/ + */ + len = DevicePathNodeLength(&uri->Header) - sizeof(URI_DEVICE_PATH); + oh->uri_base = malloc(len + 1); + if (oh->uri_base == NULL) { + err = ENOMEM; + goto end; + } + strncpy(oh->uri_base, uri->Uri, len); + oh->uri_base[len] = '\0'; + c = strrchr(oh->uri_base, '/'); + if (c != NULL) + *c = '\0'; + c = strrchr(oh->uri_base, '/'); + if (c != NULL && *(c + 1) != '\0') + *(c + 1) = '\0'; + + err = 0; +end: + if (err != 0) { + free(dev->d_opendata); + dev->d_opendata = NULL; + } + return (err); +} + +static int +efihttp_dev_close(struct open_file *f) +{ + EFI_SERVICE_BINDING_PROTOCOL *sb; + struct devdesc *dev; + struct open_efihttp *oh; + EFI_STATUS status; + + dev = (struct devdesc *)f->f_devdata; + oh = (struct open_efihttp *)dev->d_opendata; + status = BS->OpenProtocol(oh->dev_handle, &httpsb_guid, (void **)&sb, + IH, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + sb->DestroyChild(sb, oh->http_handle); + free(oh->uri_base); + free(oh); + dev->d_opendata = NULL; + return (0); +} + +static int +_efihttp_fs_open(const char *path, struct open_file *f) +{ + EFI_HTTP_CONFIG_DATA config; + EFI_HTTPv4_ACCESS_POINT config_access; + EFI_HTTP_TOKEN token; + EFI_HTTP_MESSAGE message; + EFI_HTTP_REQUEST_DATA request; + EFI_HTTP_RESPONSE_DATA response; + EFI_HTTP_HEADER headers[3]; + char *host, *hostp; + char *c; + struct devdesc *dev; + struct open_efihttp *oh; + struct file_efihttp *fh; + EFI_STATUS status; + int i; + int polltime; + bool done; + + dev = (struct devdesc *)f->f_devdata; + oh = (struct open_efihttp *)dev->d_opendata; + fh = calloc(1, sizeof(struct file_efihttp)); + if (fh == NULL) + return (ENOMEM); + f->f_fsdata = fh; + fh->path = strdup(path); + + /* + * Reset the HTTP state. + * + * EDK II's persistent HTTP connection handling is graceless, + * assuming that all connections are persistent regardless of + * any Connection: header or HTTP version reported by the + * server, and failing to send requests when a more sane + * implementation would seem to be just reestablishing the + * closed connection. + * + * In the hopes of having some robustness, we indicate to the + * server that we will close the connection by using a + * Connection: close header. And then here we manually + * unconfigure and reconfigure the http instance to force the + * connection closed. + */ + memset(&config, 0, sizeof(config)); + memset(&config_access, 0, sizeof(config_access)); + config.AccessPoint.IPv4Node = &config_access; + status = oh->http->GetModeData(oh->http, &config); + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + status = oh->http->Configure(oh->http, NULL); + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + status = oh->http->Configure(oh->http, &config); + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + + /* Send the read request */ + done = false; + status = BS->CreateEvent(EVT_NOTIFY_SIGNAL, TPL_CALLBACK, notify, + &done, &token.Event); + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + + /* extract the host portion of the URL */ + host = strdup(oh->uri_base); + if (host == NULL) + return (ENOMEM); + hostp = host; + /* Remove the protocol scheme */ + c = strchr(host, '/'); + if (c != NULL && *(c + 1) == '/') + hostp = (c + 2); + + /* Remove any path information */ + c = strchr(hostp, '/'); + if (c != NULL) + *c = '\0'; + + token.Status = EFI_NOT_READY; + token.Message = &message; + message.Data.Request = &request; + message.HeaderCount = 3; + message.Headers = headers; + message.BodyLength = 0; + message.Body = NULL; + request.Method = HttpMethodGet; + request.Url = calloc(strlen(oh->uri_base) + strlen(path) + 1, 2); + headers[0].FieldName = "Host"; + headers[0].FieldValue = hostp; + headers[1].FieldName = "Connection"; + headers[1].FieldValue = "close"; + headers[2].FieldName = "Accept"; + headers[2].FieldValue = "*/*"; + cpy8to16(oh->uri_base, request.Url, strlen(oh->uri_base)); + cpy8to16(path, request.Url + strlen(oh->uri_base), strlen(path)); + status = oh->http->Request(oh->http, &token); + free(request.Url); + free(host); + if (EFI_ERROR(status)) { + BS->CloseEvent(token.Event); + return (efi_status_to_errno(status)); + } + + polltime = 0; + while (!done && polltime < EFIHTTP_POLL_TIMEOUT) { + status = oh->http->Poll(oh->http); + if (EFI_ERROR(status)) + break; + + if (!done) { + delay(100 * 1000); + polltime += 100; + } + } + BS->CloseEvent(token.Event); + if (EFI_ERROR(token.Status)) + return (efi_status_to_errno(token.Status)); + + /* Wait for the read response */ + done = false; + status = BS->CreateEvent(EVT_NOTIFY_SIGNAL, TPL_CALLBACK, notify, + &done, &token.Event); + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + token.Status = EFI_NOT_READY; + token.Message = &message; + message.Data.Response = &response; + message.HeaderCount = 0; + message.Headers = NULL; + message.BodyLength = 0; + message.Body = NULL; + response.StatusCode = HTTP_STATUS_UNSUPPORTED_STATUS; + status = oh->http->Response(oh->http, &token); + if (EFI_ERROR(status)) { + BS->CloseEvent(token.Event); + return (efi_status_to_errno(status)); + } + + polltime = 0; + while (!done && polltime < EFIHTTP_POLL_TIMEOUT) { + status = oh->http->Poll(oh->http); + if (EFI_ERROR(status)) + break; + + if (!done) { + delay(100 * 1000); + polltime += 100; + } + } + BS->CloseEvent(token.Event); + if (EFI_ERROR(token.Status)) { + BS->FreePool(message.Headers); + return (efi_status_to_errno(token.Status)); + } + if (response.StatusCode != HTTP_STATUS_200_OK) { + BS->FreePool(message.Headers); + return (EIO); + } + fh->size = 0; + fh->is_dir = false; + for (i = 0; i < message.HeaderCount; i++) { + if (strcasecmp(message.Headers[i].FieldName, + "Content-Length") == 0) + fh->size = strtoul(message.Headers[i].FieldValue, NULL, + 10); + else if (strcasecmp(message.Headers[i].FieldName, + "Content-type") == 0) { + if (strncmp(message.Headers[i].FieldValue, "text/html", + 9) == 0) + fh->is_dir = true; + } + } + + return (0); +} + +static int +efihttp_fs_open(const char *path, struct open_file *f) +{ + char *path_slash; + int err; + + if (!efihttp_init_done) + return (ENXIO); + /* + * If any path fails to open, try with a trailing slash in + * case it's a directory. + */ + err = _efihttp_fs_open(path, f); + if (err != 0) { + path_slash = malloc(strlen(path) + 2); + if (path_slash == NULL) + return (ENOMEM); + strcpy(path_slash, path); + strcat(path_slash, "/"); + err = _efihttp_fs_open(path_slash, f); + free(path_slash); + } + return (err); +} + +static int +efihttp_fs_close(struct open_file *f) +{ + return (0); +} + +static int +_efihttp_fs_read(struct open_file *f, void *buf, size_t size, size_t *resid) +{ + EFI_HTTP_TOKEN token; + EFI_HTTP_MESSAGE message; + EFI_STATUS status; + struct devdesc *dev; + struct open_efihttp *oh; + struct file_efihttp *fh; + bool done; + int polltime; + + fh = (struct file_efihttp *)f->f_fsdata; + + if (fh->size > 0 && fh->offset >= fh->size) { + if (resid != NULL) + *resid = size; + + return 0; + } + + dev = (struct devdesc *)f->f_devdata; + oh = (struct open_efihttp *)dev->d_opendata; + done = false; + status = BS->CreateEvent(EVT_NOTIFY_SIGNAL, TPL_CALLBACK, notify, + &done, &token.Event); + if (EFI_ERROR(status)) { + return (efi_status_to_errno(status)); + } + token.Status = EFI_NOT_READY; + token.Message = &message; + message.Data.Request = NULL; + message.HeaderCount = 0; + message.Headers = NULL; + message.BodyLength = size; + message.Body = buf; + status = oh->http->Response(oh->http, &token); + if (status == EFI_CONNECTION_FIN) { + if (resid) + *resid = size; + return (0); + } else if (EFI_ERROR(status)) { + BS->CloseEvent(token.Event); + return (efi_status_to_errno(status)); + } + polltime = 0; + while (!done && polltime < EFIHTTP_POLL_TIMEOUT) { + status = oh->http->Poll(oh->http); + if (EFI_ERROR(status)) + break; + + if (!done) { + delay(100 * 1000); + polltime += 100; + } + } + BS->CloseEvent(token.Event); + if (token.Status == EFI_CONNECTION_FIN) { + if (resid) + *resid = size; + return (0); + } else if (EFI_ERROR(token.Status)) + return (efi_status_to_errno(token.Status)); + if (resid) + *resid = size - message.BodyLength; + fh->offset += message.BodyLength; + return (0); +} + +static int +efihttp_fs_read(struct open_file *f, void *buf, size_t size, size_t *resid) +{ + size_t res; + int err; + + while (size > 0) { + err = _efihttp_fs_read(f, buf, size, &res); + if (err != 0 || res == size) + goto end; + buf += (size - res); + size = res; + } +end: + if (resid) + *resid = size; + return (err); +} + +static int +efihttp_fs_write(struct open_file *f, const void *buf, size_t size, size_t *resid) +{ + return (EIO); +} + +static off_t +efihttp_fs_seek(struct open_file *f, off_t offset, int where) +{ + struct file_efihttp *fh; + char *path; + void *buf; + size_t res, res2; + int err; + + fh = (struct file_efihttp *)f->f_fsdata; + if (where == SEEK_SET && fh->offset == offset) + return (0); + if (where == SEEK_SET && fh->offset < offset) { + buf = malloc(1500); + res = offset - fh->offset; + while (res > 0) { + err = _efihttp_fs_read(f, buf, min(1500, res), &res2); + if (err != 0) { + free(buf); + return (err); + } + res -= min(1500, res) - res2; + } + free(buf); + return (0); + } else if (where == SEEK_SET) { + path = fh->path; + fh->path = NULL; + efihttp_fs_close(f); + err = efihttp_fs_open(path, f); + free(path); + if (err != 0) + return (err); + return efihttp_fs_seek(f, offset, where); + } + return (EIO); +} + +static int +efihttp_fs_stat(struct open_file *f, struct stat *sb) +{ + struct file_efihttp *fh; + + fh = (struct file_efihttp *)f->f_fsdata; + memset(sb, 0, sizeof(*sb)); + sb->st_nlink = 1; + sb->st_mode = 0777 | (fh->is_dir ? S_IFDIR : S_IFREG); + sb->st_size = fh->size; + return (0); +} + +static int +efihttp_fs_readdir(struct open_file *f, struct dirent *d) +{ + static char *dirbuf = NULL, *db2, *cursor; + static int dirbuf_len = 0; + char *end; + struct file_efihttp *fh; + + fh = (struct file_efihttp *)f->f_fsdata; + if (dirbuf_len < fh->size) { + db2 = realloc(dirbuf, fh->size); + if (db2 == NULL) { + free(dirbuf); + return (ENOMEM); + } else + dirbuf = db2; + + dirbuf_len = fh->size; + } + + if (fh->offset != fh->size) { + efihttp_fs_seek(f, 0, SEEK_SET); + efihttp_fs_read(f, dirbuf, dirbuf_len, NULL); + cursor = dirbuf; + } + + cursor = strstr(cursor, "<a href=\""); + if (cursor == NULL) + return (ENOENT); + cursor += 9; + end = strchr(cursor, '"'); + if (*(end - 1) == '/') { + end--; + d->d_type = DT_DIR; + } else + d->d_type = DT_REG; + memcpy(d->d_name, cursor, end - cursor); + d->d_name[end - cursor] = '\0'; + + return (0); +} diff --git a/stand/efi/loader/conf.c b/stand/efi/loader/conf.c index 2e4d35f88a6c..d08ded39b4f2 100644 --- a/stand/efi/loader/conf.c +++ b/stand/efi/loader/conf.c @@ -39,6 +39,7 @@ struct devsw *devsw[] = { &efipart_fddev, &efipart_cddev, &efipart_hddev, + &efihttp_dev, /* ordering with efinet_dev matters */ &efinet_dev, &vdisk_dev, #ifdef EFI_ZFS_BOOT @@ -54,6 +55,7 @@ struct fs_ops *file_system[] = { &dosfs_fsops, &ufs_fsops, &cd9660_fsops, + &efihttp_fsops, &tftp_fsops, &nfs_fsops, &gzipfs_fsops, diff --git a/stand/efi/loader/copy.c b/stand/efi/loader/copy.c index a19b048c9beb..e134c22c091e 100644 --- a/stand/efi/loader/copy.c +++ b/stand/efi/loader/copy.c @@ -176,8 +176,12 @@ out: #endif /* __i386__ || __amd64__ */ #ifndef EFI_STAGING_SIZE +#if defined(__amd64__) +#define EFI_STAGING_SIZE 100 +#else #define EFI_STAGING_SIZE 64 #endif +#endif EFI_PHYSICAL_ADDRESS staging, staging_end; int stage_offset_set = 0; diff --git a/stand/efi/loader/main.c b/stand/efi/loader/main.c index 8b3ba741178c..60d8c1442518 100644 --- a/stand/efi/loader/main.c +++ b/stand/efi/loader/main.c @@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/reboot.h> #include <sys/boot.h> +#include <paths.h> #include <stdint.h> #include <string.h> #include <setjmp.h> @@ -237,8 +238,8 @@ sanity_check_currdev(void) { struct stat st; - return (stat("/boot/defaults/loader.conf", &st) == 0 || - stat("/boot/kernel/kernel", &st) == 0); + return (stat(PATH_DEFAULTS_LOADER_CONF, &st) == 0 || + stat(PATH_KERNEL, &st) == 0); } #ifdef EFI_ZFS_BOOT diff --git a/stand/i386/loader/conf.c b/stand/i386/loader/conf.c index 02f1160cd1a4..c70a53d4191a 100644 --- a/stand/i386/loader/conf.c +++ b/stand/i386/loader/conf.c @@ -84,9 +84,6 @@ struct fs_ops *file_system[] = { #if defined(LOADER_CD9660_SUPPORT) &cd9660_fsops, #endif -#if defined(LOADER_NANDFS_SUPPORT) - &nandfs_fsops, -#endif #ifdef LOADER_NFS_SUPPORT &nfs_fsops, #endif diff --git a/stand/libsa/Makefile b/stand/libsa/Makefile index b09b23c79d93..72a9775298d0 100644 --- a/stand/libsa/Makefile +++ b/stand/libsa/Makefile @@ -145,9 +145,6 @@ SRCS+= ufs.c nfs.c cd9660.c tftp.c gzipfs.c bzipfs.c SRCS+= dosfs.c ext2fs.c SRCS+= splitfs.c SRCS+= pkgfs.c -.if ${MK_NAND} != "no" -SRCS+= nandfs.c -.endif # kernel ufs support .PATH: ${SRCTOP}/sys/ufs/ffs diff --git a/stand/libsa/nandfs.c b/stand/libsa/nandfs.c deleted file mode 100644 index b3e72243e995..000000000000 --- a/stand/libsa/nandfs.c +++ /dev/null @@ -1,1061 +0,0 @@ -/*- - * Copyright (c) 2010-2012 Semihalf. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/queue.h> -#include <sys/stdint.h> -#include <ufs/ufs/dinode.h> -#include <fs/nandfs/nandfs_fs.h> -#include "stand.h" -#include "string.h" -#include "zlib.h" - -#define DEBUG -#undef DEBUG -#ifdef DEBUG -#define NANDFS_DEBUG(fmt, args...) do { \ - printf("NANDFS_DEBUG:" fmt "\n", ##args); } while (0) -#else -#define NANDFS_DEBUG(fmt, args...) -#endif - -struct nandfs_mdt { - uint32_t entries_per_block; - uint32_t entries_per_group; - uint32_t blocks_per_group; - uint32_t groups_per_desc_block; /* desc is super group */ - uint32_t blocks_per_desc_block; /* desc is super group */ -}; - -struct bmap_buf { - LIST_ENTRY(bmap_buf) list; - nandfs_daddr_t blknr; - uint64_t *map; -}; - -struct nandfs_node { - struct nandfs_inode *inode; - LIST_HEAD(, bmap_buf) bmap_bufs; -}; -struct nandfs { - int nf_blocksize; - int nf_sectorsize; - int nf_cpno; - - struct open_file *nf_file; - struct nandfs_node *nf_opened_node; - u_int nf_offset; - uint8_t *nf_buf; - int64_t nf_buf_blknr; - - struct nandfs_fsdata *nf_fsdata; - struct nandfs_super_block *nf_sb; - struct nandfs_segment_summary nf_segsum; - struct nandfs_checkpoint nf_checkpoint; - struct nandfs_super_root nf_sroot; - struct nandfs_node nf_ifile; - struct nandfs_node nf_datfile; - struct nandfs_node nf_cpfile; - struct nandfs_mdt nf_datfile_mdt; - struct nandfs_mdt nf_ifile_mdt; - - int nf_nindir[NANDFS_NIADDR]; -}; - -static int nandfs_open(const char *, struct open_file *); -static int nandfs_close(struct open_file *); -static int nandfs_read(struct open_file *, void *, size_t, size_t *); -static off_t nandfs_seek(struct open_file *, off_t, int); -static int nandfs_stat(struct open_file *, struct stat *); -static int nandfs_readdir(struct open_file *, struct dirent *); - -static int nandfs_buf_read(struct nandfs *, void **, size_t *); -static struct nandfs_node *nandfs_lookup_path(struct nandfs *, const char *); -static int nandfs_read_inode(struct nandfs *, struct nandfs_node *, - nandfs_lbn_t, u_int, void *, int); -static int nandfs_read_blk(struct nandfs *, nandfs_daddr_t, void *, int); -static int nandfs_bmap_lookup(struct nandfs *, struct nandfs_node *, - nandfs_lbn_t, nandfs_daddr_t *, int); -static int nandfs_get_checkpoint(struct nandfs *, uint64_t, - struct nandfs_checkpoint *); -static nandfs_daddr_t nandfs_vtop(struct nandfs *, nandfs_daddr_t); -static void nandfs_calc_mdt_consts(int, struct nandfs_mdt *, int); -static void nandfs_mdt_trans(struct nandfs_mdt *, uint64_t, - nandfs_daddr_t *, uint32_t *); -static int ioread(struct open_file *, off_t, void *, u_int); -static int nandfs_probe_sectorsize(struct open_file *); - -struct fs_ops nandfs_fsops = { - "nandfs", - nandfs_open, - nandfs_close, - nandfs_read, - null_write, - nandfs_seek, - nandfs_stat, - nandfs_readdir -}; - -#define NINDIR(fs) ((fs)->nf_blocksize / sizeof(nandfs_daddr_t)) - -/* from NetBSD's src/sys/net/if_ethersubr.c */ -static uint32_t -nandfs_crc32(uint32_t crc, const uint8_t *buf, size_t len) -{ - static const uint32_t crctab[] = { - 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, - 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, - 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, - 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c - }; - size_t i; - - crc = crc ^ ~0U; - for (i = 0; i < len; i++) { - crc ^= buf[i]; - crc = (crc >> 4) ^ crctab[crc & 0xf]; - crc = (crc >> 4) ^ crctab[crc & 0xf]; - } - return (crc ^ ~0U); -} - -static int -nandfs_check_fsdata_crc(struct nandfs_fsdata *fsdata) -{ - uint32_t fsdata_crc, comp_crc; - - if (fsdata->f_magic != NANDFS_FSDATA_MAGIC) - return (0); - - /* Preserve crc */ - fsdata_crc = fsdata->f_sum; - - /* Calculate */ - fsdata->f_sum = (0); - comp_crc = nandfs_crc32(0, (uint8_t *)fsdata, fsdata->f_bytes); - - /* Restore */ - fsdata->f_sum = fsdata_crc; - - /* Check CRC */ - return (fsdata_crc == comp_crc); -} - -static int -nandfs_check_superblock_crc(struct nandfs_fsdata *fsdata, - struct nandfs_super_block *super) -{ - uint32_t super_crc, comp_crc; - - /* Check super block magic */ - if (super->s_magic != NANDFS_SUPER_MAGIC) - return (0); - - /* Preserve CRC */ - super_crc = super->s_sum; - - /* Calculate */ - super->s_sum = (0); - comp_crc = nandfs_crc32(0, (uint8_t *)super, fsdata->f_sbbytes); - - /* Restore */ - super->s_sum = super_crc; - - /* Check CRC */ - return (super_crc == comp_crc); -} - -static int -nandfs_find_super_block(struct nandfs *fs, struct open_file *f) -{ - struct nandfs_super_block *sb; - int i, j, n, s; - int sectors_to_read, error; - - sb = malloc(fs->nf_sectorsize); - if (sb == NULL) - return (ENOMEM); - - memset(fs->nf_sb, 0, sizeof(*fs->nf_sb)); - - sectors_to_read = (NANDFS_NFSAREAS * fs->nf_fsdata->f_erasesize) / - fs->nf_sectorsize; - for (i = 0; i < sectors_to_read; i++) { - NANDFS_DEBUG("reading i %d offset %d\n", i, - i * fs->nf_sectorsize); - error = ioread(f, i * fs->nf_sectorsize, (char *)sb, - fs->nf_sectorsize); - if (error) { - NANDFS_DEBUG("error %d\n", error); - continue; - } - n = fs->nf_sectorsize / sizeof(struct nandfs_super_block); - s = 0; - if ((i * fs->nf_sectorsize) % fs->nf_fsdata->f_erasesize == 0) { - if (fs->nf_sectorsize == sizeof(struct nandfs_fsdata)) - continue; - else { - s += (sizeof(struct nandfs_fsdata) / - sizeof(struct nandfs_super_block)); - } - } - - for (j = s; j < n; j++) { - if (!nandfs_check_superblock_crc(fs->nf_fsdata, &sb[j])) - continue; - NANDFS_DEBUG("magic %x wtime %jd, lastcp 0x%jx\n", - sb[j].s_magic, sb[j].s_wtime, sb[j].s_last_cno); - if (sb[j].s_last_cno > fs->nf_sb->s_last_cno) - memcpy(fs->nf_sb, &sb[j], sizeof(*fs->nf_sb)); - } - } - - free(sb); - - return (fs->nf_sb->s_magic != 0 ? 0 : EINVAL); -} - -static int -nandfs_find_fsdata(struct nandfs *fs, struct open_file *f) -{ - int offset, error, i; - - NANDFS_DEBUG("starting\n"); - - offset = 0; - for (i = 0; i < 64 * NANDFS_NFSAREAS; i++) { - error = ioread(f, offset, (char *)fs->nf_fsdata, - sizeof(struct nandfs_fsdata)); - if (error) - return (error); - if (fs->nf_fsdata->f_magic == NANDFS_FSDATA_MAGIC) { - NANDFS_DEBUG("found at %x, volume %s\n", offset, - fs->nf_fsdata->f_volume_name); - if (nandfs_check_fsdata_crc(fs->nf_fsdata)) - break; - } - offset += fs->nf_sectorsize; - } - - return (error); -} - -static int -nandfs_read_structures(struct nandfs *fs, struct open_file *f) -{ - int error; - - error = nandfs_find_fsdata(fs, f); - if (error) - return (error); - - error = nandfs_find_super_block(fs, f); - - if (error == 0) - NANDFS_DEBUG("selected sb with w_time %jd last_pseg %jx\n", - fs->nf_sb->s_wtime, fs->nf_sb->s_last_pseg); - - return (error); -} - -static int -nandfs_mount(struct nandfs *fs, struct open_file *f) -{ - int err = 0, level; - uint64_t last_pseg; - - fs->nf_fsdata = malloc(sizeof(struct nandfs_fsdata)); - fs->nf_sb = malloc(sizeof(struct nandfs_super_block)); - - err = nandfs_read_structures(fs, f); - if (err) { - free(fs->nf_fsdata); - free(fs->nf_sb); - return (err); - } - - fs->nf_blocksize = 1 << (fs->nf_fsdata->f_log_block_size + 10); - - NANDFS_DEBUG("using superblock with wtime %jd\n", fs->nf_sb->s_wtime); - - fs->nf_cpno = fs->nf_sb->s_last_cno; - last_pseg = fs->nf_sb->s_last_pseg; - - /* - * Calculate indirect block levels. - */ - nandfs_daddr_t mult; - - mult = 1; - for (level = 0; level < NANDFS_NIADDR; level++) { - mult *= NINDIR(fs); - fs->nf_nindir[level] = mult; - } - - nandfs_calc_mdt_consts(fs->nf_blocksize, &fs->nf_datfile_mdt, - fs->nf_fsdata->f_dat_entry_size); - - nandfs_calc_mdt_consts(fs->nf_blocksize, &fs->nf_ifile_mdt, - fs->nf_fsdata->f_inode_size); - - err = ioread(f, last_pseg * fs->nf_blocksize, &fs->nf_segsum, - sizeof(struct nandfs_segment_summary)); - if (err) { - free(fs->nf_sb); - free(fs->nf_fsdata); - return (err); - } - - err = ioread(f, (last_pseg + fs->nf_segsum.ss_nblocks - 1) * - fs->nf_blocksize, &fs->nf_sroot, sizeof(struct nandfs_super_root)); - if (err) { - free(fs->nf_sb); - free(fs->nf_fsdata); - return (err); - } - - fs->nf_datfile.inode = &fs->nf_sroot.sr_dat; - LIST_INIT(&fs->nf_datfile.bmap_bufs); - fs->nf_cpfile.inode = &fs->nf_sroot.sr_cpfile; - LIST_INIT(&fs->nf_cpfile.bmap_bufs); - - err = nandfs_get_checkpoint(fs, fs->nf_cpno, &fs->nf_checkpoint); - if (err) { - free(fs->nf_sb); - free(fs->nf_fsdata); - return (err); - } - - NANDFS_DEBUG("checkpoint cp_cno=%lld\n", fs->nf_checkpoint.cp_cno); - NANDFS_DEBUG("checkpoint cp_inodes_count=%lld\n", - fs->nf_checkpoint.cp_inodes_count); - NANDFS_DEBUG("checkpoint cp_ifile_inode.i_blocks=%lld\n", - fs->nf_checkpoint.cp_ifile_inode.i_blocks); - - fs->nf_ifile.inode = &fs->nf_checkpoint.cp_ifile_inode; - LIST_INIT(&fs->nf_ifile.bmap_bufs); - return (0); -} - -#define NINDIR(fs) ((fs)->nf_blocksize / sizeof(nandfs_daddr_t)) - -static int -nandfs_open(const char *path, struct open_file *f) -{ - struct nandfs *fs; - struct nandfs_node *node; - int err, bsize, level; - - NANDFS_DEBUG("nandfs_open('%s', %p)\n", path, f); - - fs = malloc(sizeof(struct nandfs)); - f->f_fsdata = fs; - fs->nf_file = f; - - bsize = nandfs_probe_sectorsize(f); - if (bsize < 0) { - printf("Cannot probe medium sector size\n"); - return (EINVAL); - } - - fs->nf_sectorsize = bsize; - - /* - * Calculate indirect block levels. - */ - nandfs_daddr_t mult; - - mult = 1; - for (level = 0; level < NANDFS_NIADDR; level++) { - mult *= NINDIR(fs); - fs->nf_nindir[level] = mult; - } - - NANDFS_DEBUG("fs %p nf_sectorsize=%x\n", fs, fs->nf_sectorsize); - - err = nandfs_mount(fs, f); - if (err) { - NANDFS_DEBUG("Cannot mount nandfs: %s\n", strerror(err)); - return (err); - } - - node = nandfs_lookup_path(fs, path); - if (node == NULL) - return (EINVAL); - - fs->nf_offset = 0; - fs->nf_buf = NULL; - fs->nf_buf_blknr = -1; - fs->nf_opened_node = node; - LIST_INIT(&fs->nf_opened_node->bmap_bufs); - return (0); -} - -static void -nandfs_free_node(struct nandfs_node *node) -{ - struct bmap_buf *bmap, *tmp; - - free(node->inode); - LIST_FOREACH_SAFE(bmap, &node->bmap_bufs, list, tmp) { - LIST_REMOVE(bmap, list); - free(bmap->map); - free(bmap); - } - free(node); -} - -static int -nandfs_close(struct open_file *f) -{ - struct nandfs *fs = f->f_fsdata; - - NANDFS_DEBUG("nandfs_close(%p)\n", f); - - if (fs->nf_buf != NULL) - free(fs->nf_buf); - - nandfs_free_node(fs->nf_opened_node); - free(fs->nf_sb); - free(fs); - return (0); -} - -static int -nandfs_read(struct open_file *f, void *addr, size_t size, size_t *resid) -{ - struct nandfs *fs = (struct nandfs *)f->f_fsdata; - size_t csize, buf_size; - void *buf; - int error = 0; - - NANDFS_DEBUG("nandfs_read(file=%p, addr=%p, size=%d)\n", f, addr, size); - - while (size != 0) { - if (fs->nf_offset >= fs->nf_opened_node->inode->i_size) - break; - - error = nandfs_buf_read(fs, &buf, &buf_size); - if (error) - break; - - csize = size; - if (csize > buf_size) - csize = buf_size; - - bcopy(buf, addr, csize); - - fs->nf_offset += csize; - addr = (char *)addr + csize; - size -= csize; - } - - if (resid) - *resid = size; - return (error); -} - -static off_t -nandfs_seek(struct open_file *f, off_t offset, int where) -{ - struct nandfs *fs = f->f_fsdata; - off_t off; - u_int size; - - NANDFS_DEBUG("nandfs_seek(file=%p, offset=%lld, where=%d)\n", f, - offset, where); - - size = fs->nf_opened_node->inode->i_size; - - switch (where) { - case SEEK_SET: - off = 0; - break; - case SEEK_CUR: - off = fs->nf_offset; - break; - case SEEK_END: - off = size; - break; - default: - errno = EINVAL; - return (-1); - } - - off += offset; - if (off < 0 || off > size) { - errno = EINVAL; - return(-1); - } - - fs->nf_offset = (u_int)off; - - return (off); -} - -static int -nandfs_stat(struct open_file *f, struct stat *sb) -{ - struct nandfs *fs = f->f_fsdata; - - NANDFS_DEBUG("nandfs_stat(file=%p, stat=%p)\n", f, sb); - - sb->st_size = fs->nf_opened_node->inode->i_size; - sb->st_mode = fs->nf_opened_node->inode->i_mode; - sb->st_uid = fs->nf_opened_node->inode->i_uid; - sb->st_gid = fs->nf_opened_node->inode->i_gid; - return (0); -} - -static int -nandfs_readdir(struct open_file *f, struct dirent *d) -{ - struct nandfs *fs = f->f_fsdata; - struct nandfs_dir_entry *dirent; - void *buf; - size_t buf_size; - - NANDFS_DEBUG("nandfs_readdir(file=%p, dirent=%p)\n", f, d); - - if (fs->nf_offset >= fs->nf_opened_node->inode->i_size) { - NANDFS_DEBUG("nandfs_readdir(file=%p, dirent=%p) ENOENT\n", - f, d); - return (ENOENT); - } - - if (nandfs_buf_read(fs, &buf, &buf_size)) { - NANDFS_DEBUG("nandfs_readdir(file=%p, dirent=%p)" - "buf_read failed\n", f, d); - return (EIO); - } - - NANDFS_DEBUG("nandfs_readdir(file=%p, dirent=%p) moving forward\n", - f, d); - - dirent = (struct nandfs_dir_entry *)buf; - fs->nf_offset += dirent->rec_len; - strncpy(d->d_name, dirent->name, dirent->name_len); - d->d_name[dirent->name_len] = '\0'; - d->d_type = dirent->file_type; - return (0); -} - -static int -nandfs_buf_read(struct nandfs *fs, void **buf_p, size_t *size_p) -{ - nandfs_daddr_t blknr, blkoff; - - blknr = fs->nf_offset / fs->nf_blocksize; - blkoff = fs->nf_offset % fs->nf_blocksize; - - if (blknr != fs->nf_buf_blknr) { - if (fs->nf_buf == NULL) - fs->nf_buf = malloc(fs->nf_blocksize); - - if (nandfs_read_inode(fs, fs->nf_opened_node, blknr, 1, - fs->nf_buf, 0)) - return (EIO); - - fs->nf_buf_blknr = blknr; - } - - *buf_p = fs->nf_buf + blkoff; - *size_p = fs->nf_blocksize - blkoff; - - NANDFS_DEBUG("nandfs_buf_read buf_p=%p size_p=%d\n", *buf_p, *size_p); - - if (*size_p > fs->nf_opened_node->inode->i_size - fs->nf_offset) - *size_p = fs->nf_opened_node->inode->i_size - fs->nf_offset; - - return (0); -} - -static struct nandfs_node * -nandfs_lookup_node(struct nandfs *fs, uint64_t ino) -{ - uint64_t blocknr; - int entrynr; - struct nandfs_inode *buffer; - struct nandfs_node *node; - struct nandfs_inode *inode; - - NANDFS_DEBUG("nandfs_lookup_node ino=%lld\n", ino); - - if (ino == 0) { - printf("nandfs_lookup_node: invalid inode requested\n"); - return (NULL); - } - - buffer = malloc(fs->nf_blocksize); - inode = malloc(sizeof(struct nandfs_inode)); - node = malloc(sizeof(struct nandfs_node)); - - nandfs_mdt_trans(&fs->nf_ifile_mdt, ino, &blocknr, &entrynr); - - if (nandfs_read_inode(fs, &fs->nf_ifile, blocknr, 1, buffer, 0)) - return (NULL); - - memcpy(inode, &buffer[entrynr], sizeof(struct nandfs_inode)); - node->inode = inode; - free(buffer); - return (node); -} - -static struct nandfs_node * -nandfs_lookup_path(struct nandfs *fs, const char *path) -{ - struct nandfs_node *node; - struct nandfs_dir_entry *dirent; - char *namebuf; - uint64_t i, done, pinode, inode; - int nlinks = 0, counter, len, link_len, nameidx; - uint8_t *buffer, *orig; - char *strp, *lpath; - - buffer = malloc(fs->nf_blocksize); - orig = buffer; - - namebuf = malloc(2 * MAXPATHLEN + 2); - strncpy(namebuf, path, MAXPATHLEN); - namebuf[MAXPATHLEN] = '\0'; - done = nameidx = 0; - lpath = namebuf; - - /* Get the root inode */ - node = nandfs_lookup_node(fs, NANDFS_ROOT_INO); - inode = NANDFS_ROOT_INO; - - while ((strp = strsep(&lpath, "/")) != NULL) { - if (*strp == '\0') - continue; - if ((node->inode->i_mode & IFMT) != IFDIR) { - nandfs_free_node(node); - node = NULL; - goto out; - } - - len = strlen(strp); - NANDFS_DEBUG("%s: looking for %s\n", __func__, strp); - for (i = 0; i < node->inode->i_blocks; i++) { - if (nandfs_read_inode(fs, node, i, 1, orig, 0)) { - node = NULL; - goto out; - } - - buffer = orig; - done = counter = 0; - while (1) { - dirent = - (struct nandfs_dir_entry *)(void *)buffer; - NANDFS_DEBUG("%s: dirent.name = %s\n", - __func__, dirent->name); - NANDFS_DEBUG("%s: dirent.rec_len = %d\n", - __func__, dirent->rec_len); - NANDFS_DEBUG("%s: dirent.inode = %lld\n", - __func__, dirent->inode); - if (len == dirent->name_len && - (strncmp(strp, dirent->name, len) == 0) && - dirent->inode != 0) { - nandfs_free_node(node); - node = nandfs_lookup_node(fs, - dirent->inode); - pinode = inode; - inode = dirent->inode; - done = 1; - break; - } - - counter += dirent->rec_len; - buffer += dirent->rec_len; - - if (counter == fs->nf_blocksize) - break; - } - - if (done) - break; - } - - if (!done) { - node = NULL; - goto out; - } - - NANDFS_DEBUG("%s: %.*s has mode %o\n", __func__, - dirent->name_len, dirent->name, node->inode->i_mode); - - if ((node->inode->i_mode & IFMT) == IFLNK) { - NANDFS_DEBUG("%s: %.*s is symlink\n", - __func__, dirent->name_len, dirent->name); - link_len = node->inode->i_size; - - if (++nlinks > MAXSYMLINKS) { - nandfs_free_node(node); - node = NULL; - goto out; - } - - if (nandfs_read_inode(fs, node, 0, 1, orig, 0)) { - nandfs_free_node(node); - node = NULL; - goto out; - } - - NANDFS_DEBUG("%s: symlink is %.*s\n", - __func__, link_len, (char *)orig); - - nameidx = (nameidx == 0) ? MAXPATHLEN + 1 : 0; - bcopy((char *)orig, namebuf + nameidx, - (unsigned)link_len); - if (lpath != NULL) { - namebuf[nameidx + link_len++] = '/'; - strncpy(namebuf + nameidx + link_len, lpath, - MAXPATHLEN - link_len); - namebuf[nameidx + MAXPATHLEN] = '\0'; - } else - namebuf[nameidx + link_len] = '\0'; - - NANDFS_DEBUG("%s: strp=%s, lpath=%s, namebuf0=%s, " - "namebuf1=%s, idx=%d\n", __func__, strp, lpath, - namebuf + 0, namebuf + MAXPATHLEN + 1, nameidx); - - lpath = namebuf + nameidx; - - nandfs_free_node(node); - - /* - * If absolute pathname, restart at root. Otherwise - * continue with out parent inode. - */ - inode = (orig[0] == '/') ? NANDFS_ROOT_INO : pinode; - node = nandfs_lookup_node(fs, inode); - } - } - -out: - free(namebuf); - free(orig); - return (node); -} - -static int -nandfs_read_inode(struct nandfs *fs, struct nandfs_node *node, - nandfs_daddr_t blknr, u_int nblks, void *buf, int raw) -{ - uint64_t *pblks; - uint64_t *vblks; - u_int i; - int error; - - pblks = malloc(nblks * sizeof(uint64_t)); - vblks = malloc(nblks * sizeof(uint64_t)); - - NANDFS_DEBUG("nandfs_read_inode fs=%p node=%p blknr=%lld nblks=%d\n", - fs, node, blknr, nblks); - for (i = 0; i < nblks; i++) { - error = nandfs_bmap_lookup(fs, node, blknr + i, &vblks[i], raw); - if (error) { - free(pblks); - free(vblks); - return (error); - } - if (raw == 0) - pblks[i] = nandfs_vtop(fs, vblks[i]); - else - pblks[i] = vblks[i]; - } - - for (i = 0; i < nblks; i++) { - if (ioread(fs->nf_file, pblks[i] * fs->nf_blocksize, buf, - fs->nf_blocksize)) { - free(pblks); - free(vblks); - return (EIO); - } - - buf = (void *)((uintptr_t)buf + fs->nf_blocksize); - } - - free(pblks); - free(vblks); - return (0); -} - -static int -nandfs_read_blk(struct nandfs *fs, nandfs_daddr_t blknr, void *buf, int phys) -{ - uint64_t pblknr; - - pblknr = (phys ? blknr : nandfs_vtop(fs, blknr)); - - return (ioread(fs->nf_file, pblknr * fs->nf_blocksize, buf, - fs->nf_blocksize)); -} - -static int -nandfs_get_checkpoint(struct nandfs *fs, uint64_t cpno, - struct nandfs_checkpoint *cp) -{ - uint64_t blocknr; - int blockoff, cp_per_block, dlen; - uint8_t *buf; - - NANDFS_DEBUG("nandfs_get_checkpoint(fs=%p cpno=%lld)\n", fs, cpno); - - buf = malloc(fs->nf_blocksize); - - cpno += NANDFS_CPFILE_FIRST_CHECKPOINT_OFFSET - 1; - dlen = fs->nf_fsdata->f_checkpoint_size; - cp_per_block = fs->nf_blocksize / dlen; - blocknr = cpno / cp_per_block; - blockoff = (cpno % cp_per_block) * dlen; - - if (nandfs_read_inode(fs, &fs->nf_cpfile, blocknr, 1, buf, 0)) { - free(buf); - return (EINVAL); - } - - memcpy(cp, buf + blockoff, sizeof(struct nandfs_checkpoint)); - free(buf); - - return (0); -} - -static uint64_t * -nandfs_get_map(struct nandfs *fs, struct nandfs_node *node, nandfs_daddr_t blknr, - int phys) -{ - struct bmap_buf *bmap; - uint64_t *map; - - LIST_FOREACH(bmap, &node->bmap_bufs, list) { - if (bmap->blknr == blknr) - return (bmap->map); - } - - map = malloc(fs->nf_blocksize); - if (nandfs_read_blk(fs, blknr, map, phys)) { - free(map); - return (NULL); - } - - bmap = malloc(sizeof(struct bmap_buf)); - bmap->blknr = blknr; - bmap->map = map; - - LIST_INSERT_HEAD(&node->bmap_bufs, bmap, list); - - NANDFS_DEBUG("%s:(node=%p, map=%p)\n", __func__, node, map); - return (map); -} - -static int -nandfs_bmap_lookup(struct nandfs *fs, struct nandfs_node *node, - nandfs_lbn_t lblknr, nandfs_daddr_t *vblknr, int phys) -{ - struct nandfs_inode *ino; - nandfs_daddr_t ind_block_num; - uint64_t *map; - int idx; - int level; - - ino = node->inode; - - if (lblknr < NANDFS_NDADDR) { - *vblknr = ino->i_db[lblknr]; - return (0); - } - - lblknr -= NANDFS_NDADDR; - - /* - * nindir[0] = NINDIR - * nindir[1] = NINDIR**2 - * nindir[2] = NINDIR**3 - * etc - */ - for (level = 0; level < NANDFS_NIADDR; level++) { - NANDFS_DEBUG("lblknr=%jx fs->nf_nindir[%d]=%d\n", lblknr, level, fs->nf_nindir[level]); - if (lblknr < fs->nf_nindir[level]) - break; - lblknr -= fs->nf_nindir[level]; - } - - if (level == NANDFS_NIADDR) { - /* Block number too high */ - NANDFS_DEBUG("lblknr %jx too high\n", lblknr); - return (EFBIG); - } - - ind_block_num = ino->i_ib[level]; - - for (; level >= 0; level--) { - if (ind_block_num == 0) { - *vblknr = 0; /* missing */ - return (0); - } - - twiddle(1); - NANDFS_DEBUG("calling get_map with %jx\n", ind_block_num); - map = nandfs_get_map(fs, node, ind_block_num, phys); - if (map == NULL) - return (EIO); - - if (level > 0) { - idx = lblknr / fs->nf_nindir[level - 1]; - lblknr %= fs->nf_nindir[level - 1]; - } else - idx = lblknr; - - ind_block_num = ((nandfs_daddr_t *)map)[idx]; - } - - *vblknr = ind_block_num; - - return (0); -} - -static nandfs_daddr_t -nandfs_vtop(struct nandfs *fs, nandfs_daddr_t vblocknr) -{ - nandfs_lbn_t blocknr; - nandfs_daddr_t pblocknr; - int entrynr; - struct nandfs_dat_entry *dat; - - dat = malloc(fs->nf_blocksize); - nandfs_mdt_trans(&fs->nf_datfile_mdt, vblocknr, &blocknr, &entrynr); - - if (nandfs_read_inode(fs, &fs->nf_datfile, blocknr, 1, dat, 1)) { - free(dat); - return (0); - } - - NANDFS_DEBUG("nandfs_vtop entrynr=%d vblocknr=%lld pblocknr=%lld\n", - entrynr, vblocknr, dat[entrynr].de_blocknr); - - pblocknr = dat[entrynr].de_blocknr; - free(dat); - return (pblocknr); -} - -static void -nandfs_calc_mdt_consts(int blocksize, struct nandfs_mdt *mdt, int entry_size) -{ - - mdt->entries_per_group = blocksize * 8; /* bits in sector */ - mdt->entries_per_block = blocksize / entry_size; - mdt->blocks_per_group = - (mdt->entries_per_group -1) / mdt->entries_per_block + 1 + 1; - mdt->groups_per_desc_block = - blocksize / sizeof(struct nandfs_block_group_desc); - mdt->blocks_per_desc_block = - mdt->groups_per_desc_block * mdt->blocks_per_group + 1; -} - -static void -nandfs_mdt_trans(struct nandfs_mdt *mdt, uint64_t index, - nandfs_daddr_t *blocknr, uint32_t *entry_in_block) -{ - nandfs_daddr_t blknr; - uint64_t group, group_offset, blocknr_in_group; - uint64_t desc_block, desc_offset; - - /* Calculate our offset in the file */ - group = index / mdt->entries_per_group; - group_offset = index % mdt->entries_per_group; - desc_block = group / mdt->groups_per_desc_block; - desc_offset = group % mdt->groups_per_desc_block; - blocknr_in_group = group_offset / mdt->entries_per_block; - - /* To descgroup offset */ - blknr = 1 + desc_block * mdt->blocks_per_desc_block; - - /* To group offset */ - blknr += desc_offset * mdt->blocks_per_group; - - /* To actual file block */ - blknr += 1 + blocknr_in_group; - - *blocknr = blknr; - *entry_in_block = group_offset % mdt->entries_per_block; -} - -static int -ioread(struct open_file *f, off_t pos, void *buf, u_int length) -{ - void *buffer; - int err; - int bsize = ((struct nandfs *)f->f_fsdata)->nf_sectorsize; - u_int off, nsec; - - off = pos % bsize; - pos /= bsize; - nsec = howmany(length, bsize); - - NANDFS_DEBUG("pos=%lld length=%d off=%d nsec=%d\n", pos, length, - off, nsec); - - buffer = malloc(nsec * bsize); - - err = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, pos, - nsec * bsize, buffer, NULL); - - memcpy(buf, (void *)((uintptr_t)buffer + off), length); - free(buffer); - - return (err); -} - -static int -nandfs_probe_sectorsize(struct open_file *f) -{ - void *buffer; - int i, err; - - buffer = malloc(16 * 1024); - - NANDFS_DEBUG("probing for sector size: "); - - for (i = 512; i < (16 * 1024); i <<= 1) { - NANDFS_DEBUG("%d ", i); - err = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 0, i, - buffer, NULL); - - if (err == 0) { - NANDFS_DEBUG("found"); - free(buffer); - return (i); - } - } - - free(buffer); - NANDFS_DEBUG("not found\n"); - return (-1); -} diff --git a/stand/libsa/stand.h b/stand/libsa/stand.h index 5e44e31ff2d9..3d0cb4ff0c50 100644 --- a/stand/libsa/stand.h +++ b/stand/libsa/stand.h @@ -119,13 +119,13 @@ extern struct fs_ops ufs_fsops; extern struct fs_ops tftp_fsops; extern struct fs_ops nfs_fsops; extern struct fs_ops cd9660_fsops; -extern struct fs_ops nandfs_fsops; extern struct fs_ops gzipfs_fsops; extern struct fs_ops bzipfs_fsops; extern struct fs_ops dosfs_fsops; extern struct fs_ops ext2fs_fsops; extern struct fs_ops splitfs_fsops; extern struct fs_ops pkgfs_fsops; +extern struct fs_ops efihttp_fsops; /* where values for lseek(2) */ #define SEEK_SET 0 /* set file offset to offset */ diff --git a/stand/loader.mk b/stand/loader.mk index bd24f33bc6b1..a7fbd6c12dd9 100644 --- a/stand/loader.mk +++ b/stand/loader.mk @@ -99,9 +99,6 @@ CFLAGS+= -DLOADER_EXT2FS_SUPPORT .if ${LOADER_MSDOS_SUPPORT:Uno} == "yes" CFLAGS+= -DLOADER_MSDOS_SUPPORT .endif -.if ${LOADER_NANDFS_SUPPORT:U${MK_NAND}} == "yes" -CFLAGS+= -DLOADER_NANDFS_SUPPORT -.endif .if ${LOADER_UFS_SUPPORT:Uyes} == "yes" CFLAGS+= -DLOADER_UFS_SUPPORT .endif diff --git a/stand/mips/uboot/conf.c b/stand/mips/uboot/conf.c index f711a8cec5f2..922f7680b616 100644 --- a/stand/mips/uboot/conf.c +++ b/stand/mips/uboot/conf.c @@ -62,9 +62,6 @@ struct fs_ops *file_system[] = { #if defined(LOADER_EXT2FS_SUPPORT) &ext2fs_fsops, #endif -#if defined(LOADER_NANDFS_SUPPORT) - &nandfs_fsops, -#endif #if defined(LOADER_NFS_SUPPORT) &nfs_fsops, #endif diff --git a/stand/mips/uboot/version b/stand/mips/uboot/version index 486c4125cc0d..ec46b388b281 100644 --- a/stand/mips/uboot/version +++ b/stand/mips/uboot/version @@ -3,6 +3,7 @@ $FreeBSD$ NOTE ANY CHANGES YOU MAKE TO THE BOOTBLOCKS HERE. The format of this file is important. Make sure the current version number is on line 6. +1.3: Remove NAND FS support. 1.2: Extended with NAND FS support. 1.1: Flattened Device Tree blob support. 1.0: Added storage support. Booting from HDD, USB, etc. is now possible. diff --git a/sys/amd64/amd64/pmap.c b/sys/amd64/amd64/pmap.c index d7a35b5c9cfc..a0a2eb0baa6b 100644 --- a/sys/amd64/amd64/pmap.c +++ b/sys/amd64/amd64/pmap.c @@ -484,6 +484,9 @@ static struct pmap_invl_gen pmap_invl_gen_head = { .next = NULL, }; static u_long pmap_invl_gen = 1; +static int pmap_invl_waiters; +static struct callout pmap_invl_callout; +static bool pmap_invl_callout_inited; #define PMAP_ASSERT_NOT_IN_DI() \ KASSERT(pmap_not_in_di(), ("DI already started")) @@ -538,6 +541,34 @@ pmap_thread_init_invl_gen_l(struct thread *td) invl_gen->gen = 0; } +static void +pmap_delayed_invl_wait_block(u_long *m_gen, u_long *invl_gen) +{ + struct turnstile *ts; + + ts = turnstile_trywait(&invl_gen_ts); + if (*m_gen > atomic_load_long(invl_gen)) + turnstile_wait(ts, NULL, TS_SHARED_QUEUE); + else + turnstile_cancel(ts); +} + +static void +pmap_delayed_invl_finish_unblock(u_long new_gen) +{ + struct turnstile *ts; + + turnstile_chain_lock(&invl_gen_ts); + ts = turnstile_lookup(&invl_gen_ts); + if (new_gen != 0) + pmap_invl_gen = new_gen; + if (ts != NULL) { + turnstile_broadcast(ts, TS_SHARED_QUEUE); + turnstile_unpend(ts); + } + turnstile_chain_unlock(&invl_gen_ts); +} + /* * Start a new Delayed Invalidation (DI) block of code, executed by * the current thread. Within a DI block, the current thread may @@ -582,24 +613,15 @@ static void pmap_delayed_invl_finish_l(void) { struct pmap_invl_gen *invl_gen, *next; - struct turnstile *ts; invl_gen = &curthread->td_md.md_invl_gen; KASSERT(invl_gen->gen != 0, ("missed invl_start")); mtx_lock(&invl_gen_mtx); next = LIST_NEXT(invl_gen, link); - if (next == NULL) { - turnstile_chain_lock(&invl_gen_ts); - ts = turnstile_lookup(&invl_gen_ts); - pmap_invl_gen = invl_gen->gen; - if (ts != NULL) { - turnstile_broadcast(ts, TS_SHARED_QUEUE); - turnstile_unpend(ts); - } - turnstile_chain_unlock(&invl_gen_ts); - } else { + if (next == NULL) + pmap_delayed_invl_finish_unblock(invl_gen->gen); + else next->gen = invl_gen->gen; - } LIST_REMOVE(invl_gen, link); mtx_unlock(&invl_gen_mtx); invl_gen->gen = 0; @@ -856,6 +878,8 @@ again: goto again; } critical_exit(); + if (atomic_load_int(&pmap_invl_waiters) > 0) + pmap_delayed_invl_finish_unblock(0); if (invl_gen->saved_pri != 0) { thread_lock(td); sched_prio(td, invl_gen->saved_pri); @@ -888,6 +912,9 @@ DB_SHOW_COMMAND(di_queue, pmap_di_queue) static long invl_wait; SYSCTL_LONG(_vm_pmap, OID_AUTO, invl_wait, CTLFLAG_RD, &invl_wait, 0, "Number of times DI invalidation blocked pmap_remove_all/write"); +static long invl_wait_slow; +SYSCTL_LONG(_vm_pmap, OID_AUTO, invl_wait_slow, CTLFLAG_RD, &invl_wait_slow, 0, + "Number of slow invalidation waits for lockless DI"); #endif static u_long * @@ -897,6 +924,27 @@ pmap_delayed_invl_genp(vm_page_t m) return (&pv_invl_gen[pa_index(VM_PAGE_TO_PHYS(m)) % NPV_LIST_LOCKS]); } +static void +pmap_delayed_invl_callout_func(void *arg __unused) +{ + + if (atomic_load_int(&pmap_invl_waiters) == 0) + return; + pmap_delayed_invl_finish_unblock(0); +} + +static void +pmap_delayed_invl_callout_init(void *arg __unused) +{ + + if (pmap_di_locked()) + return; + callout_init(&pmap_invl_callout, 1); + pmap_invl_callout_inited = true; +} +SYSINIT(pmap_di_callout, SI_SUB_CPU + 1, SI_ORDER_ANY, + pmap_delayed_invl_callout_init, NULL); + /* * Ensure that all currently executing DI blocks, that need to flush * TLB for the given page m, actually flushed the TLB at the time the @@ -914,7 +962,6 @@ pmap_delayed_invl_genp(vm_page_t m) static void pmap_delayed_invl_wait_l(vm_page_t m) { - struct turnstile *ts; u_long *m_gen; #ifdef PV_STATS bool accounted = false; @@ -928,11 +975,7 @@ pmap_delayed_invl_wait_l(vm_page_t m) accounted = true; } #endif - ts = turnstile_trywait(&invl_gen_ts); - if (*m_gen > pmap_invl_gen) - turnstile_wait(ts, NULL, TS_SHARED_QUEUE); - else - turnstile_cancel(ts); + pmap_delayed_invl_wait_block(m_gen, &pmap_invl_gen); } } @@ -940,19 +983,53 @@ static void pmap_delayed_invl_wait_u(vm_page_t m) { u_long *m_gen; -#ifdef PV_STATS - bool accounted = false; -#endif + struct lock_delay_arg lda; + bool fast; + fast = true; m_gen = pmap_delayed_invl_genp(m); + lock_delay_arg_init(&lda, &di_delay); while (*m_gen > atomic_load_long(&pmap_invl_gen_head.gen)) { -#ifdef PV_STATS - if (!accounted) { - atomic_add_long(&invl_wait, 1); - accounted = true; + if (fast || !pmap_invl_callout_inited) { + PV_STAT(atomic_add_long(&invl_wait, 1)); + lock_delay(&lda); + fast = false; + } else { + /* + * The page's invalidation generation number + * is still below the current thread's number. + * Prepare to block so that we do not waste + * CPU cycles or worse, suffer livelock. + * + * Since it is impossible to block without + * racing with pmap_delayed_invl_finish_u(), + * prepare for the race by incrementing + * pmap_invl_waiters and arming a 1-tick + * callout which will unblock us if we lose + * the race. + */ + atomic_add_int(&pmap_invl_waiters, 1); + + /* + * Re-check the current thread's invalidation + * generation after incrementing + * pmap_invl_waiters, so that there is no race + * with pmap_delayed_invl_finish_u() setting + * the page generation and checking + * pmap_invl_waiters. The only race allowed + * is for a missed unblock, which is handled + * by the callout. + */ + if (*m_gen > + atomic_load_long(&pmap_invl_gen_head.gen)) { + callout_reset(&pmap_invl_callout, 1, + pmap_delayed_invl_callout_func, NULL); + PV_STAT(atomic_add_long(&invl_wait_slow, 1)); + pmap_delayed_invl_wait_block(m_gen, + &pmap_invl_gen_head.gen); + } + atomic_add_int(&pmap_invl_waiters, -1); } -#endif - kern_yield(PRI_USER); } } @@ -4921,6 +4998,7 @@ pmap_remove(pmap_t pmap, vm_offset_t sva, vm_offset_t eva) pmap_delayed_invl_start(); PMAP_LOCK(pmap); + pmap_pkru_on_remove(pmap, sva, eva); /* * special handling of removing one page. a very @@ -5014,7 +5092,6 @@ pmap_remove(pmap_t pmap, vm_offset_t sva, vm_offset_t eva) out: if (anyvalid) pmap_invalidate_all(pmap); - pmap_pkru_on_remove(pmap, sva, eva); PMAP_UNLOCK(pmap); pmap_delayed_invl_finish(); vm_page_free_pages_toq(&free, true); diff --git a/sys/amd64/conf/GENERIC b/sys/amd64/conf/GENERIC index 520f64734bb9..f04b60f3ca66 100644 --- a/sys/amd64/conf/GENERIC +++ b/sys/amd64/conf/GENERIC @@ -309,7 +309,6 @@ device wpi # Intel 3945ABG wireless NICs. # Pseudo devices. device crypto # core crypto support device loop # Network loopback -device random # Entropy device device padlock_rng # VIA Padlock RNG device rdrand_rng # Intel Bull Mountain RNG device ether # Ethernet support diff --git a/sys/amd64/conf/MINIMAL b/sys/amd64/conf/MINIMAL index 481a7ce96e44..211e00e7de46 100644 --- a/sys/amd64/conf/MINIMAL +++ b/sys/amd64/conf/MINIMAL @@ -10,7 +10,7 @@ # some features (ACL, GJOURNAL) that GENERIC includes. # o acpi as a module has been reported flakey and not well tested, so # is included in the kernel. -# o random is included due to uncertaty... +# o (non-loaded) random is included due to uncertainty... # o Many networking things are included # # For now, please run changes to these list past imp@freebsd.org @@ -131,7 +131,6 @@ device agp # support several AGP chipsets # Pseudo devices. device loop # Network loopback -device random # Entropy device device padlock_rng # VIA Padlock RNG device rdrand_rng # Intel Bull Mountain RNG device ether # Ethernet support diff --git a/sys/amd64/sgx/sgx.c b/sys/amd64/sgx/sgx.c index d47d4a3596a5..3d45b60de3ef 100644 --- a/sys/amd64/sgx/sgx.c +++ b/sys/amd64/sgx/sgx.c @@ -358,7 +358,7 @@ sgx_page_remove(struct sgx_softc *sc, vm_page_t p) uint64_t offs; vm_page_lock(p); - vm_page_remove(p); + (void)vm_page_remove(p); vm_page_unlock(p); dprintf("%s: p->pidx %ld\n", __func__, p->pindex); diff --git a/sys/amd64/vmm/vmm_instruction_emul.c b/sys/amd64/vmm/vmm_instruction_emul.c index 230da1881ef0..f3afa23d8281 100644 --- a/sys/amd64/vmm/vmm_instruction_emul.c +++ b/sys/amd64/vmm/vmm_instruction_emul.c @@ -78,6 +78,7 @@ enum { VIE_OP_TYPE_BITTEST, VIE_OP_TYPE_TWOB_GRP15, VIE_OP_TYPE_ADD, + VIE_OP_TYPE_TEST, VIE_OP_TYPE_LAST }; @@ -221,6 +222,12 @@ static const struct vie_op one_byte_opcodes[256] = { .op_byte = 0x8F, .op_type = VIE_OP_TYPE_POP, }, + [0xF7] = { + /* XXX Group 3 extended opcode - not just TEST */ + .op_byte = 0xF7, + .op_type = VIE_OP_TYPE_TEST, + .op_flags = VIE_OP_F_IMM, + }, [0xFF] = { /* XXX Group 5 extended opcode - not just PUSH */ .op_byte = 0xFF, @@ -450,6 +457,41 @@ getaddflags(int opsize, uint64_t x, uint64_t y) return (getaddflags64(x, y)); } +/* + * Return the status flags that would result from doing (x & y). + */ +#define GETANDFLAGS(sz) \ +static u_long \ +getandflags##sz(uint##sz##_t x, uint##sz##_t y) \ +{ \ + u_long rflags; \ + \ + __asm __volatile("and %2,%1; pushfq; popq %0" : \ + "=r" (rflags), "+r" (x) : "m" (y)); \ + return (rflags); \ +} struct __hack + +GETANDFLAGS(8); +GETANDFLAGS(16); +GETANDFLAGS(32); +GETANDFLAGS(64); + +static u_long +getandflags(int opsize, uint64_t x, uint64_t y) +{ + KASSERT(opsize == 1 || opsize == 2 || opsize == 4 || opsize == 8, + ("getandflags: invalid operand size %d", opsize)); + + if (opsize == 1) + return (getandflags8(x, y)); + else if (opsize == 2) + return (getandflags16(x, y)); + else if (opsize == 4) + return (getandflags32(x, y)); + else + return (getandflags64(x, y)); +} + static int emulate_mov(void *vm, int vcpuid, uint64_t gpa, struct vie *vie, mem_region_read_t memread, mem_region_write_t memwrite, void *arg) @@ -1219,6 +1261,55 @@ emulate_cmp(void *vm, int vcpuid, uint64_t gpa, struct vie *vie, } static int +emulate_test(void *vm, int vcpuid, uint64_t gpa, struct vie *vie, + mem_region_read_t memread, mem_region_write_t memwrite, void *arg) +{ + int error, size; + uint64_t op1, rflags, rflags2; + + size = vie->opsize; + error = EINVAL; + + switch (vie->op.op_byte) { + case 0xF7: + /* + * F7 /0 test r/m16, imm16 + * F7 /0 test r/m32, imm32 + * REX.W + F7 /0 test r/m64, imm32 sign-extended to 64 + * + * Test mem (ModRM:r/m) with immediate and set status + * flags according to the results. The comparison is + * performed by anding the immediate from the first + * operand and then setting the status flags. + */ + if ((vie->reg & 7) != 0) + return (EINVAL); + + error = memread(vm, vcpuid, gpa, &op1, size, arg); + if (error) + return (error); + + rflags2 = getandflags(size, op1, vie->immediate); + break; + default: + return (EINVAL); + } + error = vie_read_register(vm, vcpuid, VM_REG_GUEST_RFLAGS, &rflags); + if (error) + return (error); + + /* + * OF and CF are cleared; the SF, ZF and PF flags are set according + * to the result; AF is undefined. + */ + rflags &= ~RFLAGS_STATUS_BITS; + rflags |= rflags2 & (PSL_PF | PSL_Z | PSL_N); + + error = vie_update_register(vm, vcpuid, VM_REG_GUEST_RFLAGS, rflags, 8); + return (error); +} + +static int emulate_add(void *vm, int vcpuid, uint64_t gpa, struct vie *vie, mem_region_read_t memread, mem_region_write_t memwrite, void *arg) { @@ -1643,6 +1734,10 @@ vmm_emulate_instruction(void *vm, int vcpuid, uint64_t gpa, struct vie *vie, error = emulate_add(vm, vcpuid, gpa, vie, memread, memwrite, memarg); break; + case VIE_OP_TYPE_TEST: + error = emulate_test(vm, vcpuid, gpa, vie, + memread, memwrite, memarg); + break; default: error = EINVAL; break; diff --git a/sys/arm/allwinner/files.allwinner b/sys/arm/allwinner/files.allwinner index 73367b391c3a..dd801c016d49 100644 --- a/sys/arm/allwinner/files.allwinner +++ b/sys/arm/allwinner/files.allwinner @@ -28,7 +28,6 @@ dev/usb/controller/generic_ohci.c optional ohci dev/usb/controller/generic_usb_if.m optional ohci arm/allwinner/aw_sid.c optional aw_sid arm/allwinner/aw_thermal.c optional aw_thermal -dev/iicbus/sy8106a.c optional sy8106a arm/allwinner/aw_cir.c optional aw_cir evdev arm/allwinner/aw_reset.c standard diff --git a/sys/arm/conf/ALPINE b/sys/arm/conf/ALPINE index 6b35f120aefb..76689b5805c9 100644 --- a/sys/arm/conf/ALPINE +++ b/sys/arm/conf/ALPINE @@ -41,7 +41,6 @@ device al_udma # Universal DMA # Pseudo devices device loop -device random device pty device md device gpio diff --git a/sys/arm/conf/ARMADA38X b/sys/arm/conf/ARMADA38X index 29ea724172be..b82c18d79c52 100644 --- a/sys/arm/conf/ARMADA38X +++ b/sys/arm/conf/ARMADA38X @@ -25,7 +25,6 @@ options SMP options VM_KMEM_SIZE_MAX=0x9CCD000 # Pseudo devices -device random device pty device loop device md diff --git a/sys/arm/conf/ARMADAXP b/sys/arm/conf/ARMADAXP index 5e891e51fba7..7f73d69ece7a 100644 --- a/sys/arm/conf/ARMADAXP +++ b/sys/arm/conf/ARMADAXP @@ -46,7 +46,6 @@ options NO_FFS_SNAPSHOT options NO_SWAPPING # Pseudo devices -device random device pty device loop device md diff --git a/sys/arm/conf/DB-78XXX b/sys/arm/conf/DB-78XXX index aa474bcc43a1..44df77cf45f1 100644 --- a/sys/arm/conf/DB-78XXX +++ b/sys/arm/conf/DB-78XXX @@ -20,7 +20,6 @@ options GEOM_PART_BSD # BSD partition scheme options GEOM_PART_MBR # MBR partition scheme options TMPFS # Efficient memory filesystem options FFS # Berkeley Fast Filesystem -options NANDFS # NAND Filesystem options NFSCL # Network Filesystem Client options NFSLOCKD # Network Lock Manager options NFS_ROOT # NFS usable as /, requires NFSCL @@ -45,7 +44,6 @@ device pci # Pseudo devices device loop device md -device random # Serial ports device uart @@ -75,9 +73,6 @@ device ds133x # SATA device mvs -# NAND -device nand - # GPIO device gpio diff --git a/sys/arm/conf/DB-88F5XXX b/sys/arm/conf/DB-88F5XXX index 0199e8663336..a13a7002332d 100644 --- a/sys/arm/conf/DB-88F5XXX +++ b/sys/arm/conf/DB-88F5XXX @@ -44,7 +44,6 @@ device pci # Pseudo devices device md device loop -device random # Serial ports device uart diff --git a/sys/arm/conf/DB-88F6XXX b/sys/arm/conf/DB-88F6XXX index fa2810c97122..66a385ddbe40 100644 --- a/sys/arm/conf/DB-88F6XXX +++ b/sys/arm/conf/DB-88F6XXX @@ -17,7 +17,6 @@ options INET # InterNETworking options INET6 # IPv6 communications protocols options TCP_HHOOK # hhook(9) framework for TCP options FFS # Berkeley Fast Filesystem -options NANDFS # NAND Filesystem options NFSCL # Network Filesystem Client options NFSLOCKD # Network Lock Manager options NFS_ROOT # NFS usable as /, requires NFSCL @@ -46,7 +45,6 @@ device pci # Pseudo devices device loop device md -device random # Serial ports device uart @@ -79,9 +77,6 @@ device twsi # SATA device mvs -# NAND -device nand - # GPIO device gpio diff --git a/sys/arm/conf/DOCKSTAR b/sys/arm/conf/DOCKSTAR index 5684d29ef87b..6f26d4290801 100644 --- a/sys/arm/conf/DOCKSTAR +++ b/sys/arm/conf/DOCKSTAR @@ -68,7 +68,6 @@ device gif # IPv6 and IPv4 tunneling device loop # Network loopback device md # Memory/malloc disk device pty # BSD-style compatibility pseudo ttys -device random # Entropy device device tuntap # Packet tunnel. device ether # Required for all ethernet devices device vlan # 802.1Q VLAN support diff --git a/sys/arm/conf/DREAMPLUG-1001 b/sys/arm/conf/DREAMPLUG-1001 index 5d6928470e5d..18b2dee86fac 100644 --- a/sys/arm/conf/DREAMPLUG-1001 +++ b/sys/arm/conf/DREAMPLUG-1001 @@ -71,7 +71,6 @@ device gif # IPv6 and IPv4 tunneling device loop # Network loopback device md # Memory/malloc disk device pty # BSD-style compatibility pseudo ttys -device random # Entropy device device tuntap # Packet tunnel. device ether # Required for all ethernet devices device vlan # 802.1Q VLAN support @@ -158,14 +157,6 @@ options ALTQ_PRIQ # Priority Queueing options ALTQ_NOPCC # Required if the TSC is unusable #options ALTQ_DEBUG -# To use this configuration with the (rare) model 1001N (nand flash), -# create a kernel config file that looks like this: -# -# include DREAMPLUG-1001 -# nomakeoptions FDT_DTS_FILE -# makeoptions FDT_DTS_FILE=dreamplug-1001N.dts -# device nand - # Flattened Device Tree options FDT # Configure using FDT/DTB data options FDT_DTB_STATIC diff --git a/sys/arm/conf/EFIKA_MX b/sys/arm/conf/EFIKA_MX index 248060b6cf04..be5f5f35570d 100644 --- a/sys/arm/conf/EFIKA_MX +++ b/sys/arm/conf/EFIKA_MX @@ -57,7 +57,6 @@ device bpf # Berkeley packet filter # Pseudo devices. device loop # Network loopback -device random # Entropy device device ether # Ethernet support #device vlan # 802.1Q VLAN support #device tuntap # Packet tunnel. diff --git a/sys/arm/conf/GENERIC b/sys/arm/conf/GENERIC index d32baa63a667..34be5898c7eb 100644 --- a/sys/arm/conf/GENERIC +++ b/sys/arm/conf/GENERIC @@ -121,7 +121,6 @@ device pl011 device pty device snp device md # Memory "disks" -device random # Entropy device device firmware # firmware assist module device pl310 # PL310 L2 cache controller device psci @@ -175,6 +174,9 @@ device ti_spi # ADC support device ti_adc +# PWM +device pwm + # Watchdog support # If we don't enable the watchdog driver, the BealeBone could potentially # reboot automatically because the boot loader might have enabled the diff --git a/sys/arm/conf/IMX53 b/sys/arm/conf/IMX53 index 7b7d67bbca9c..be18afda6094 100644 --- a/sys/arm/conf/IMX53 +++ b/sys/arm/conf/IMX53 @@ -44,7 +44,6 @@ device bpf # Berkeley packet filter # Pseudo devices. device loop # Network loopback -device random # Entropy device device ether # Ethernet support #device vlan # 802.1Q VLAN support #device tuntap # Packet tunnel. diff --git a/sys/arm/conf/IMX6 b/sys/arm/conf/IMX6 index 3baf9f06f039..4dbebdfccd1f 100644 --- a/sys/arm/conf/IMX6 +++ b/sys/arm/conf/IMX6 @@ -49,7 +49,6 @@ device mpcore_timer # Pseudo devices. device loop # Network loopback -device random # Entropy device device vlan # 802.1Q VLAN support device tuntap # Packet tunnel. device md # Memory "disks" diff --git a/sys/arm/conf/NOTES b/sys/arm/conf/NOTES index 559146b58014..518cf4050ad9 100644 --- a/sys/arm/conf/NOTES +++ b/sys/arm/conf/NOTES @@ -1,44 +1,22 @@ # $FreeBSD$ -machine arm - -cpu CPU_ARM9E - -files "../mv/files.mv" -files "../mv/discovery/files.db78xxx" -files "../mv/kirkwood/files.kirkwood" -files "../mv/orion/files.db88f5xxx" -files "../mv/orion/files.ts7800" - -makeoptions CONF_CFLAGS+="-march=armv5te" -makeoptions LDFLAGS="-zmuldefs" -makeoptions KERNPHYSADDR=0x00000000 - options FDT -options SOC_MV_DISCOVERY -options SOC_MV_KIRKWOOD -options SOC_MV_ORION - -options ARM_MANY_BOARD -device nand - -# IIC -device twsi - -nooptions SMP -nooptions MAXCPU +# Undo options from sys/conf/NOTES that we do not want... nooptions COMPAT_FREEBSD4 nooptions COMPAT_FREEBSD5 nooptions COMPAT_FREEBSD6 nooptions COMPAT_FREEBSD7 nooptions COMPAT_FREEBSD9 -nooption PPC_PROBE_CHIPSET +nooptions PPC_PROBE_CHIPSET +nooptions MAXCPU # value is set in machine/param.h + +# Devices in sys/conf/NOTES for which no such hardware exists on arm, +# or the drivers don't compile... nodevice fdc nodevice sym -nodevice ukbd nodevice sc nodevice blank_saver @@ -58,28 +36,9 @@ nodevice cxgbe nodevice cxgbev nodevice snd_cmi -# -# Enable the kernel DTrace hooks which are required to load the DTrace -# kernel modules. -# -options KDTRACE_HOOKS - -# DTrace core -# NOTE: introduces CDDL-licensed components into the kernel -#device dtrace - -# DTrace modules -#device dtrace_profile -#device dtrace_sdt -#device dtrace_fbt -#device dtrace_systrace -#device dtrace_prototype -#device dtnfscl -#device dtmalloc - -# Alternatively include all the DTrace modules -#device dtraceall - -# These aren't known to work on arm and/or don't compile nodevice mpr nodevice mps + +# Add devices which are specific to various arm platforms... + +device twsi # i2c controller on Marvel and Allwinner diff --git a/sys/arm/conf/NOTES.armv5 b/sys/arm/conf/NOTES.armv5 new file mode 100644 index 000000000000..1e8825980448 --- /dev/null +++ b/sys/arm/conf/NOTES.armv5 @@ -0,0 +1,33 @@ +# armv5-specific changes for doing a LINT build. +# +# The contents of sys/conf/NOTES, sys/arm/conf/NOTES, and this file are +# concatenated (in that order) to create the LINT-V5 kernel config file. +# +# $FreeBSD$ + +#NO_UNIVERSE + +machine arm arm +cpu CPU_ARM9E + +files "../mv/files.mv" +files "../mv/discovery/files.db78xxx" +files "../mv/kirkwood/files.kirkwood" +files "../mv/orion/files.db88f5xxx" +files "../mv/orion/files.ts7800" + +makeoptions CONF_CFLAGS+="-march=armv5te" +makeoptions LDFLAGS="-zmuldefs" +makeoptions KERNPHYSADDR=0x00000000 + +# Undo options from sys/conf/NOTES that we do not want... + +nooptions SMP # All armv5 are single-core + +# Add options for armv5 that are not in sys/conf/NOTES... + +options ARM_MANY_BOARD + +options SOC_MV_DISCOVERY +options SOC_MV_KIRKWOOD +options SOC_MV_ORION diff --git a/sys/arm/conf/NOTES.armv7 b/sys/arm/conf/NOTES.armv7 new file mode 100644 index 000000000000..e8a19034b001 --- /dev/null +++ b/sys/arm/conf/NOTES.armv7 @@ -0,0 +1,64 @@ +# armv7-specific changes for doing a LINT build. +# +# The contents of sys/conf/NOTES, sys/arm/conf/NOTES, and this file are +# concatenated (in that order) to create the LINT-V7 kernel config file. +# +# $FreeBSD$ + + +#NO_UNIVERSE + +machine arm armv7 +cpu CPU_CORTEXA +cpu CPU_MV_PJ4B +makeoptions CONF_CFLAGS+="-march=armv7a" + +# Add options for armv7 that are not in sys/conf/NOTES... + +options ARM_L2_PIPT # Only L2 PIPT is supported +options FREEBSD_BOOT_LOADER # Process metadata passed from loader(8) +options INTRNG # Include INTRNG framework +options LINUX_BOOT_ABI # Process metadata passed from U-Boot +options PLATFORM # Include platform_if support +options SMP # Most v7 SoCs are multicore +options VFP # Enable floating point hardware support + +# NOTE: dtrace introduces CDDL-licensed components into the kernel +device dtrace # dtrace core +device dtraceall # include all dtrace modules +options KDTRACE_HOOKS + +# Add misc devices which are specific to various arm platforms... + +device generic_timer # ARM Generic Timer +device gic # Interrupt controller +device gpio # gpio interface and bus +device mpcore_timer # ARM MPCore Timer +device pl310 # PL310 L2 cache controller +device pmu # PMU support (for CCNT). + +# Add EXT_RESOURCES pseudo devices... + +options EXT_RESOURCES +device clk +device phy +device hwreset +device nvmem +device regulator +device syscon + +# Build SOC-specific modules... + +makeoptions MODULES_EXTRA+="allwinner" +makeoptions MODULES_EXTRA+="arm_ti" +makeoptions MODULES_EXTRA+="imx" + +# Build dtb files... + +makeoptions MODULES_EXTRA+="dtb/allwinner" +makeoptions MODULES_EXTRA+="dtb/am335x" +makeoptions MODULES_EXTRA+="dtb/imx6" +makeoptions MODULES_EXTRA+="dtb/nvidia" +makeoptions MODULES_EXTRA+="dtb/omap4" +makeoptions MODULES_EXTRA+="dtb/rpi" +makeoptions MODULES_EXTRA+="dtb/zynq" diff --git a/sys/arm/conf/RPI-B b/sys/arm/conf/RPI-B index e1f132105c20..e456d33742b8 100644 --- a/sys/arm/conf/RPI-B +++ b/sys/arm/conf/RPI-B @@ -65,7 +65,6 @@ device iicbus device bcm2835_bsc device md -device random # Entropy device # USB support device usb diff --git a/sys/arm/conf/RT1310 b/sys/arm/conf/RT1310 index 3ade997821be..08fde3516ac1 100644 --- a/sys/arm/conf/RT1310 +++ b/sys/arm/conf/RT1310 @@ -51,7 +51,6 @@ options WITNESS_SKIPSPIN # Don't run witness on spinlocks for speed device loop device md device pty -device random # Serial ports device uart diff --git a/sys/arm/conf/SHEEVAPLUG b/sys/arm/conf/SHEEVAPLUG index ff60f82bcf60..d7d161956ce4 100644 --- a/sys/arm/conf/SHEEVAPLUG +++ b/sys/arm/conf/SHEEVAPLUG @@ -19,7 +19,6 @@ options INET # InterNETworking options INET6 # IPv6 communications protocols options TCP_HHOOK # hhook(9) framework for TCP options FFS # Berkeley Fast Filesystem -options NANDFS # NAND Filesystem options NFSCL # Network Filesystem Client options NFSLOCKD # Network Lock Manager options NFS_ROOT # NFS usable as /, requires NFSCL @@ -46,7 +45,6 @@ options BOOTP_WIRED_TO=mge0 # Pseudo devices device loop -device random # Serial ports device uart @@ -73,9 +71,6 @@ device scbus device pass device da -# NAND -device nand - # GPIO device gpio diff --git a/sys/arm/conf/SOCFPGA b/sys/arm/conf/SOCFPGA index b740ef1b84c9..cd78e17e08a4 100644 --- a/sys/arm/conf/SOCFPGA +++ b/sys/arm/conf/SOCFPGA @@ -58,7 +58,6 @@ device dwmmc # Pseudo devices device loop -device random device pty device md device gpio diff --git a/sys/arm/conf/TEGRA124 b/sys/arm/conf/TEGRA124 index a830519d909e..c44939b67301 100644 --- a/sys/arm/conf/TEGRA124 +++ b/sys/arm/conf/TEGRA124 @@ -43,7 +43,6 @@ device regulator # Pseudo devices. device loop # Network loopback -device random # Entropy device device vlan # 802.1Q VLAN support #device tuntap # Packet tunnel. device md # Memory "disks" diff --git a/sys/arm/conf/TS7800 b/sys/arm/conf/TS7800 index 17b237af46dd..15e9a77342d5 100644 --- a/sys/arm/conf/TS7800 +++ b/sys/arm/conf/TS7800 @@ -45,7 +45,6 @@ device pci # Pseudo devices device md device loop -device random # Serial ports device uart diff --git a/sys/arm/conf/VERSATILEPB b/sys/arm/conf/VERSATILEPB index 8c3e76cc2e87..3312f6d4f9e8 100644 --- a/sys/arm/conf/VERSATILEPB +++ b/sys/arm/conf/VERSATILEPB @@ -66,7 +66,6 @@ options SC_DFLT_FONT # compile font in makeoptions SC_DFLT_FONT=cp437 device md -device random # Entropy device options PLATFORM diff --git a/sys/arm/conf/VYBRID b/sys/arm/conf/VYBRID index 4ff18320df1a..b114c6e3e923 100644 --- a/sys/arm/conf/VYBRID +++ b/sys/arm/conf/VYBRID @@ -26,7 +26,6 @@ makeoptions WERROR="-Werror" options SCHED_4BSD # 4BSD scheduler options PLATFORM # Platform based SoC -#options NANDFS # NAND Filesystem #options SMP # Enable multiple cores # NFS root from boopt/dhcp @@ -37,7 +36,6 @@ options PLATFORM # Platform based SoC #options BOOTP_WIRED_TO=ffec0 #options ROOTDEVNAME=\"nfs:10.5.0.1:/tftpboot/cosmic\" -#options ROOTDEVNAME=\"nandfs:/dev/gnand0s.root\" options ROOTDEVNAME=\"ufs:/dev/da0\" options MUTEX_NOINLINE @@ -59,7 +57,6 @@ device sdhci # generic sdhci # Pseudo devices device loop -device random device pty device md device gpio @@ -81,8 +78,6 @@ device pass #device atadisk #device mvs -device nand - # Serial ports device uart diff --git a/sys/arm/conf/ZEDBOARD b/sys/arm/conf/ZEDBOARD index 274d96642d6b..187d636c2e49 100644 --- a/sys/arm/conf/ZEDBOARD +++ b/sys/arm/conf/ZEDBOARD @@ -48,7 +48,6 @@ device pl310 # PL310 L2 cache controller device mpcore_timer device loop -device random device ether device cgem # Zynq-7000 gig ethernet device device mii diff --git a/sys/arm/freescale/vybrid/vf_nfc.c b/sys/arm/freescale/vybrid/vf_nfc.c deleted file mode 100644 index cdefa2564864..000000000000 --- a/sys/arm/freescale/vybrid/vf_nfc.c +++ /dev/null @@ -1,528 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2013 Ruslan Bukin <br@bsdpad.com> - * 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. - */ - -/* - * Vybrid Family NAND Flash Controller (NFC) - * Chapter 31, Vybrid Reference Manual, Rev. 5, 07/2013 - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/proc.h> -#include <sys/bus.h> -#include <sys/conf.h> -#include <sys/kernel.h> -#include <sys/module.h> -#include <sys/malloc.h> -#include <sys/rman.h> -#include <sys/lock.h> -#include <sys/mutex.h> -#include <sys/time.h> - -#include <dev/ofw/ofw_bus.h> -#include <dev/ofw/ofw_bus_subr.h> -#include <dev/nand/nand.h> -#include <dev/nand/nandbus.h> - -#include <machine/bus.h> - -#include "nfc_if.h" - -#include <arm/freescale/vybrid/vf_common.h> - -enum addr_type { - ADDR_NONE, - ADDR_ID, - ADDR_ROW, - ADDR_ROWCOL -}; - -struct fsl_nfc_fcm { - uint32_t addr_bits; - enum addr_type addr_type; - uint32_t col_addr_bits; - uint32_t row_addr_bits; - u_int read_ptr; - u_int addr_ptr; - u_int command; - u_int code; -}; - -struct vf_nand_softc { - struct nand_softc nand_dev; - bus_space_handle_t bsh; - bus_space_tag_t bst; - struct resource *res[2]; - struct fsl_nfc_fcm fcm; -}; - -static struct resource_spec nfc_spec[] = { - { SYS_RES_MEMORY, 0, RF_ACTIVE }, - { SYS_RES_IRQ, 0, RF_ACTIVE }, - { -1, 0 } -}; - -static int vf_nand_attach(device_t); -static int vf_nand_probe(device_t); -static int vf_nand_send_command(device_t, uint8_t); -static int vf_nand_send_address(device_t, uint8_t); -static int vf_nand_start_command(device_t); -static uint8_t vf_nand_read_byte(device_t); -static void vf_nand_read_buf(device_t, void *, uint32_t); -static void vf_nand_write_buf(device_t, void *, uint32_t); -static int vf_nand_select_cs(device_t, uint8_t); -static int vf_nand_read_rnb(device_t); - -#define CMD_READ_PAGE 0x7EE0 -#define CMD_PROG_PAGE 0x7FC0 -#define CMD_PROG_PAGE_DMA 0xFFC8 -#define CMD_ERASE 0x4EC0 -#define CMD_READ_ID 0x4804 -#define CMD_READ_STATUS 0x4068 -#define CMD_RESET 0x4040 -#define CMD_RANDOM_IN 0x7140 -#define CMD_RANDOM_OUT 0x70E0 - -#define CMD_BYTE2_PROG_PAGE 0x10 -#define CMD_BYTE2_PAGE_READ 0x30 -#define CMD_BYTE2_ERASE 0xD0 - -#define NFC_CMD1 0x3F00 /* Flash command 1 */ -#define NFC_CMD2 0x3F04 /* Flash command 2 */ -#define NFC_CAR 0x3F08 /* Column address */ -#define NFC_RAR 0x3F0C /* Row address */ -#define NFC_RPT 0x3F10 /* Flash command repeat */ -#define NFC_RAI 0x3F14 /* Row address increment */ -#define NFC_SR1 0x3F18 /* Flash status 1 */ -#define NFC_SR2 0x3F1C /* Flash status 2 */ -#define NFC_DMA_CH1 0x3F20 /* DMA channel 1 address */ -#define NFC_DMACFG 0x3F24 /* DMA configuration */ -#define NFC_SWAP 0x3F28 /* Cach swap */ -#define NFC_SECSZ 0x3F2C /* Sector size */ -#define NFC_CFG 0x3F30 /* Flash configuration */ -#define NFC_DMA_CH2 0x3F34 /* DMA channel 2 address */ -#define NFC_ISR 0x3F38 /* Interrupt status */ - -#define ECCMODE_SHIFT 17 -#define AIAD_SHIFT 5 -#define AIBN_SHIFT 4 -#define PAGECOUNT_SHIFT 0 -#define BITWIDTH_SHIFT 7 -#define BITWIDTH8 0 -#define BITWIDTH16 1 -#define PAGECOUNT_MASK 0xf - -#define CMD2_BYTE1_SHIFT 24 -#define CMD2_CODE_SHIFT 8 -#define CMD2_BUFNO_SHIFT 1 -#define CMD2_START_SHIFT 0 - -static device_method_t vf_nand_methods[] = { - DEVMETHOD(device_probe, vf_nand_probe), - DEVMETHOD(device_attach, vf_nand_attach), - DEVMETHOD(nfc_start_command, vf_nand_start_command), - DEVMETHOD(nfc_send_command, vf_nand_send_command), - DEVMETHOD(nfc_send_address, vf_nand_send_address), - DEVMETHOD(nfc_read_byte, vf_nand_read_byte), - DEVMETHOD(nfc_read_buf, vf_nand_read_buf), - DEVMETHOD(nfc_write_buf, vf_nand_write_buf), - DEVMETHOD(nfc_select_cs, vf_nand_select_cs), - DEVMETHOD(nfc_read_rnb, vf_nand_read_rnb), - { 0, 0 }, -}; - -static driver_t vf_nand_driver = { - "nand", - vf_nand_methods, - sizeof(struct vf_nand_softc), -}; - -static devclass_t vf_nand_devclass; -DRIVER_MODULE(vf_nand, simplebus, vf_nand_driver, vf_nand_devclass, 0, 0); - -static int -vf_nand_probe(device_t dev) -{ - - if (!ofw_bus_status_okay(dev)) - return (ENXIO); - - if (!ofw_bus_is_compatible(dev, "fsl,mvf600-nand")) - return (ENXIO); - - device_set_desc(dev, "Vybrid Family NAND controller"); - return (BUS_PROBE_DEFAULT); -} - -static int -vf_nand_attach(device_t dev) -{ - struct vf_nand_softc *sc; - int err; - int reg; - - sc = device_get_softc(dev); - if (bus_alloc_resources(dev, nfc_spec, sc->res)) { - device_printf(dev, "could not allocate resources!\n"); - return (ENXIO); - } - - sc->bst = rman_get_bustag(sc->res[0]); - sc->bsh = rman_get_bushandle(sc->res[0]); - - /* Size in bytes of one elementary transfer unit */ - WRITE4(sc, NFC_SECSZ, 2048); - - /* Flash mode width */ - reg = READ4(sc, NFC_CFG); - reg |= (BITWIDTH16 << BITWIDTH_SHIFT); - - /* No correction, ECC bypass */ - reg &= ~(0x7 << ECCMODE_SHIFT); - - /* Disable Auto-incrementing of flash row address */ - reg &= ~(0x1 << AIAD_SHIFT); - - /* Disable Auto-incrementing of buffer numbers */ - reg &= ~(0x1 << AIBN_SHIFT); - - /* - * Number of virtual pages (in one physical flash page) - * to be programmed or read, etc. - */ - reg &= ~(PAGECOUNT_MASK); - reg |= (1 << PAGECOUNT_SHIFT); - WRITE4(sc, NFC_CFG, reg); - - nand_init(&sc->nand_dev, dev, NAND_ECC_NONE, 0, 0, NULL, NULL); - err = nandbus_create(dev); - return (err); -} - -static int -vf_nand_start_command(device_t dev) -{ - struct vf_nand_softc *sc; - struct fsl_nfc_fcm *fcm; - int reg; - - sc = device_get_softc(dev); - fcm = &sc->fcm; - - nand_debug(NDBG_DRV,"vf_nand: start command %x", fcm->command); - - /* CMD2 */ - reg = READ4(sc, NFC_CMD2); - reg &= ~(0xff << CMD2_BYTE1_SHIFT); - reg |= (fcm->command << CMD2_BYTE1_SHIFT); - WRITE4(sc, NFC_CMD2, reg); - - /* CMD1 */ - if ((fcm->command == NAND_CMD_READ) || - (fcm->command == NAND_CMD_PROG) || - (fcm->command == NAND_CMD_ERASE)) { - reg = READ4(sc, NFC_CMD1); - reg &= ~(0xff << 24); - - if (fcm->command == NAND_CMD_READ) - reg |= (CMD_BYTE2_PAGE_READ << 24); - else if (fcm->command == NAND_CMD_PROG) - reg |= (CMD_BYTE2_PROG_PAGE << 24); - else if (fcm->command == NAND_CMD_ERASE) - reg |= (CMD_BYTE2_ERASE << 24); - - WRITE4(sc, NFC_CMD1, reg); - } - - /* We work with 1st buffer */ - reg = READ4(sc, NFC_CMD2); - reg &= ~(0xf << CMD2_BUFNO_SHIFT); - reg |= (0 << CMD2_BUFNO_SHIFT); - WRITE4(sc, NFC_CMD2, reg); - - /* Cmd CODE */ - reg = READ4(sc, NFC_CMD2); - reg &= ~(0xffff << CMD2_CODE_SHIFT); - reg |= (fcm->code << CMD2_CODE_SHIFT); - WRITE4(sc, NFC_CMD2, reg); - - /* Col */ - if (fcm->addr_type == ADDR_ROWCOL) { - reg = READ4(sc, NFC_CAR); - reg &= ~(0xffff); - reg |= fcm->col_addr_bits; - nand_debug(NDBG_DRV,"setting CAR to 0x%08x\n", reg); - WRITE4(sc, NFC_CAR, reg); - } - - /* Row */ - reg = READ4(sc, NFC_RAR); - reg &= ~(0xffffff); - if (fcm->addr_type == ADDR_ID) - reg |= fcm->addr_bits; - else - reg |= fcm->row_addr_bits; - WRITE4(sc, NFC_RAR, reg); - - /* Start */ - reg = READ4(sc, NFC_CMD2); - reg |= (1 << CMD2_START_SHIFT); - WRITE4(sc, NFC_CMD2, reg); - - /* Wait command completion */ - while (READ4(sc, NFC_CMD2) & (1 << CMD2_START_SHIFT)) - ; - - return (0); -} - -static int -vf_nand_send_command(device_t dev, uint8_t command) -{ - struct vf_nand_softc *sc; - struct fsl_nfc_fcm *fcm; - - nand_debug(NDBG_DRV,"vf_nand: send command %x", command); - - sc = device_get_softc(dev); - fcm = &sc->fcm; - - if ((command == NAND_CMD_READ_END) || - (command == NAND_CMD_PROG_END) || - (command == NAND_CMD_ERASE_END)) { - return (0); - } - - fcm->command = command; - - fcm->code = 0; - fcm->read_ptr = 0; - fcm->addr_type = 0; - fcm->addr_bits = 0; - - fcm->addr_ptr = 0; - fcm->col_addr_bits = 0; - fcm->row_addr_bits = 0; - - switch (command) { - case NAND_CMD_READ: - fcm->code = CMD_READ_PAGE; - fcm->addr_type = ADDR_ROWCOL; - break; - case NAND_CMD_PROG: - fcm->code = CMD_PROG_PAGE; - fcm->addr_type = ADDR_ROWCOL; - break; - case NAND_CMD_PROG_END: - break; - case NAND_CMD_ERASE_END: - break; - case NAND_CMD_RESET: - fcm->code = CMD_RESET; - break; - case NAND_CMD_READ_ID: - fcm->code = CMD_READ_ID; - fcm->addr_type = ADDR_ID; - break; - case NAND_CMD_READ_PARAMETER: - fcm->code = CMD_READ_PAGE; - fcm->addr_type = ADDR_ID; - break; - case NAND_CMD_STATUS: - fcm->code = CMD_READ_STATUS; - break; - case NAND_CMD_ERASE: - fcm->code = CMD_ERASE; - fcm->addr_type = ADDR_ROW; - break; - default: - nand_debug(NDBG_DRV, "unknown command %d\n", command); - return (1); - } - - return (0); -} - -static int -vf_nand_send_address(device_t dev, uint8_t addr) -{ - struct vf_nand_softc *sc; - struct fsl_nfc_fcm *fcm; - - nand_debug(NDBG_DRV,"vf_nand: send address %x", addr); - sc = device_get_softc(dev); - fcm = &sc->fcm; - - nand_debug(NDBG_DRV, "setting addr #%d to 0x%02x\n", fcm->addr_ptr, addr); - - if (fcm->addr_type == ADDR_ID) { - fcm->addr_bits = addr; - } else if (fcm->addr_type == ADDR_ROWCOL) { - - if (fcm->addr_ptr < 2) - fcm->col_addr_bits |= (addr << (fcm->addr_ptr * 8)); - else - fcm->row_addr_bits |= (addr << ((fcm->addr_ptr - 2) * 8)); - - } else if (fcm->addr_type == ADDR_ROW) - fcm->row_addr_bits |= (addr << (fcm->addr_ptr * 8)); - - fcm->addr_ptr += 1; - - return (0); -} - -static uint8_t -vf_nand_read_byte(device_t dev) -{ - struct vf_nand_softc *sc; - struct fsl_nfc_fcm *fcm; - uint8_t data; - int sr1, sr2; - int b; - - sc = device_get_softc(dev); - fcm = &sc->fcm; - - sr1 = READ4(sc, NFC_SR1); - sr2 = READ4(sc, NFC_SR2); - - data = 0; - if (fcm->addr_type == ADDR_ID) { - b = 32 - ((fcm->read_ptr + 1) * 8); - data = (sr1 >> b) & 0xff; - fcm->read_ptr++; - } else if (fcm->command == NAND_CMD_STATUS) { - data = sr2 & 0xff; - } - - nand_debug(NDBG_DRV,"vf_nand: read %x", data); - return (data); -} - -static void -vf_nand_read_buf(device_t dev, void* buf, uint32_t len) -{ - struct vf_nand_softc *sc; - struct fsl_nfc_fcm *fcm; - uint16_t *tmp; - uint8_t *b; - int i; - - b = (uint8_t*)buf; - sc = device_get_softc(dev); - fcm = &sc->fcm; - - nand_debug(NDBG_DRV, "vf_nand: read_buf len %d", len); - - if (fcm->command == NAND_CMD_READ_PARAMETER) { - tmp = malloc(len, M_DEVBUF, M_NOWAIT); - bus_read_region_2(sc->res[0], 0x0, tmp, len); - - for (i = 0; i < len; i += 2) { - b[i] = tmp[i+1]; - b[i+1] = tmp[i]; - } - - free(tmp, M_DEVBUF); - -#ifdef NAND_DEBUG - for (i = 0; i < len; i++) { - if (!(i % 16)) - printf("%s", i == 0 ? "vf_nand:\n" : "\n"); - printf(" %x", b[i]); - if (i == len - 1) - printf("\n"); - } -#endif - - } else { - - for (i = 0; i < len; i++) { - b[i] = READ1(sc, i); - -#ifdef NAND_DEBUG - if (!(i % 16)) - printf("%s", i == 0 ? "vf_nand:\n" : "\n"); - printf(" %x", b[i]); - if (i == len - 1) - printf("\n"); -#endif - } - - } -} - -static void -vf_nand_write_buf(device_t dev, void* buf, uint32_t len) -{ - struct vf_nand_softc *sc; - struct fsl_nfc_fcm *fcm; - uint8_t *b; - int i; - - b = (uint8_t*)buf; - sc = device_get_softc(dev); - fcm = &sc->fcm; - - nand_debug(NDBG_DRV,"vf_nand: write_buf len %d", len); - - for (i = 0; i < len; i++) { - WRITE1(sc, i, b[i]); - -#ifdef NAND_DEBUG - if (!(i % 16)) - printf("%s", i == 0 ? "vf_nand:\n" : "\n"); - printf(" %x", b[i]); - if (i == len - 1) - printf("\n"); -#endif - - } -} - -static int -vf_nand_select_cs(device_t dev, uint8_t cs) -{ - - if (cs > 0) - return (ENODEV); - - return (0); -} - -static int -vf_nand_read_rnb(device_t dev) -{ - - /* no-op */ - return (0); /* ready */ -} diff --git a/sys/arm/mv/files.arm7 b/sys/arm/mv/files.arm7 index d27357480cae..a6138042bc80 100644 --- a/sys/arm/mv/files.arm7 +++ b/sys/arm/mv/files.arm7 @@ -29,7 +29,6 @@ dev/iicbus/twsi/mv_twsi.c optional twsi dev/mge/if_mge.c optional mge dev/neta/if_mvneta_fdt.c optional neta fdt dev/neta/if_mvneta.c optional neta mdio mii -dev/nand/nfc_mv.c optional nand dev/mvs/mvs_soc.c optional mvs dev/uart/uart_dev_ns8250.c optional uart dev/uart/uart_dev_snps.c optional uart diff --git a/sys/arm/mv/files.mv b/sys/arm/mv/files.mv index ee027f059441..1dc45105450c 100644 --- a/sys/arm/mv/files.mv +++ b/sys/arm/mv/files.mv @@ -26,7 +26,6 @@ dev/iicbus/twsi/mv_twsi.c optional twsi dev/mge/if_mge.c optional mge dev/neta/if_mvneta_fdt.c optional neta fdt dev/neta/if_mvneta.c optional neta mdio mii -dev/nand/nfc_mv.c optional nand dev/mvs/mvs_soc.c optional mvs dev/uart/uart_dev_ns8250.c optional uart dev/uart/uart_dev_snps.c optional uart diff --git a/sys/arm/ti/am335x/am335x_ehrpwm.c b/sys/arm/ti/am335x/am335x_ehrpwm.c index 53cb3bb78249..cbb947038ba9 100644 --- a/sys/arm/ti/am335x/am335x_ehrpwm.c +++ b/sys/arm/ti/am335x/am335x_ehrpwm.c @@ -45,21 +45,43 @@ __FBSDID("$FreeBSD$"); #include <dev/ofw/ofw_bus.h> #include <dev/ofw/ofw_bus_subr.h> +#include "pwmbus_if.h" + #include "am335x_pwm.h" +/******************************************************************************* + * Enhanced resolution PWM driver. Many of the advanced featues of the hardware + * are not supported by this driver. What is implemented here is simple + * variable-duty-cycle PWM output. + * + * Note that this driver was historically configured using a set of sysctl + * variables/procs, and later gained support for the PWM(9) API. The sysctl + * code is still present to support existing apps, but that interface is + * considered deprecated. + * + * An important caveat is that the original sysctl interface and the new PWM API + * cannot both be used at once. If both interfaces are used to change + * configuration, it's quite likely you won't get the expected results. Also, + * reading the sysctl values after configuring via PWM will not return the right + * results. + ******************************************************************************/ + /* In ticks */ #define DEFAULT_PWM_PERIOD 1000 #define PWM_CLOCK 100000000UL +#define NS_PER_SEC 1000000000 + #define PWM_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) #define PWM_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) +#define PWM_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_mtx, MA_OWNED) #define PWM_LOCK_INIT(_sc) mtx_init(&(_sc)->sc_mtx, \ device_get_nameunit(_sc->sc_dev), "am335x_ehrpwm softc", MTX_DEF) #define PWM_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_mtx) -#define EPWM_READ2(_sc, reg) bus_read_2((_sc)->sc_mem_res, reg); +#define EPWM_READ2(_sc, reg) bus_read_2((_sc)->sc_mem_res, reg) #define EPWM_WRITE2(_sc, reg, value) \ - bus_write_2((_sc)->sc_mem_res, reg, value); + bus_write_2((_sc)->sc_mem_res, reg, value) #define EPWM_TBCTL 0x00 #define TBCTL_FREERUN (2 << 14) @@ -119,6 +141,11 @@ __FBSDID("$FreeBSD$"); #define AQCTL_ZRO_TOGGLE (3 << 0) #define EPWM_AQSFRC 0x1a #define EPWM_AQCSFRC 0x1c +#define AQCSFRC_OFF 0 +#define AQCSFRC_LO 1 +#define AQCSFRC_HI 2 +#define AQCSFRC_MASK 3 +#define AQCSFRC(chan, hilo) ((hilo) << (2 * chan)) /* Trip-Zone module */ #define EPWM_TZCTL 0x28 @@ -135,12 +162,21 @@ static device_detach_t am335x_ehrpwm_detach; static int am335x_ehrpwm_clkdiv[8] = { 1, 2, 4, 8, 16, 32, 64, 128 }; +struct ehrpwm_channel { + u_int duty; /* on duration, in ns */ + bool enabled; /* channel enabled? */ + bool inverted; /* signal inverted? */ +}; +#define NUM_CHANNELS 2 + struct am335x_ehrpwm_softc { device_t sc_dev; + device_t sc_busdev; struct mtx sc_mtx; struct resource *sc_mem_res; int sc_mem_rid; - /* sysctl for configuration */ + + /* Things used for configuration via sysctl [deprecated]. */ int sc_pwm_clkdiv; int sc_pwm_freq; struct sysctl_oid *sc_clkdiv_oid; @@ -151,23 +187,130 @@ struct am335x_ehrpwm_softc { uint32_t sc_pwm_period; uint32_t sc_pwm_dutyA; uint32_t sc_pwm_dutyB; -}; - -static device_method_t am335x_ehrpwm_methods[] = { - DEVMETHOD(device_probe, am335x_ehrpwm_probe), - DEVMETHOD(device_attach, am335x_ehrpwm_attach), - DEVMETHOD(device_detach, am335x_ehrpwm_detach), - DEVMETHOD_END + /* Things used for configuration via pwm(9) api. */ + u_int sc_clkfreq; /* frequency in Hz */ + u_int sc_clktick; /* duration in ns */ + u_int sc_period; /* duration in ns */ + struct ehrpwm_channel sc_channels[NUM_CHANNELS]; }; -static driver_t am335x_ehrpwm_driver = { - "am335x_ehrpwm", - am335x_ehrpwm_methods, - sizeof(struct am335x_ehrpwm_softc), +static struct ofw_compat_data compat_data[] = { + {"ti,am33xx-ehrpwm", true}, + {NULL, false}, }; +SIMPLEBUS_PNP_INFO(compat_data); -static devclass_t am335x_ehrpwm_devclass; +static void +am335x_ehrpwm_cfg_duty(struct am335x_ehrpwm_softc *sc, u_int chan, u_int duty) +{ + u_int tbcmp; + + if (duty == 0) + tbcmp = 0; + else + tbcmp = max(1, duty / sc->sc_clktick); + + sc->sc_channels[chan].duty = tbcmp * sc->sc_clktick; + + PWM_LOCK_ASSERT(sc); + EPWM_WRITE2(sc, (chan == 0) ? EPWM_CMPA : EPWM_CMPB, tbcmp); +} + +static void +am335x_ehrpwm_cfg_enable(struct am335x_ehrpwm_softc *sc, u_int chan, bool enable) +{ + uint16_t regval; + + sc->sc_channels[chan].enabled = enable; + + /* + * Turn off any existing software-force of the channel, then force + * it in the right direction (high or low) if it's not being enabled. + */ + PWM_LOCK_ASSERT(sc); + regval = EPWM_READ2(sc, EPWM_AQCSFRC); + regval &= ~AQCSFRC(chan, AQCSFRC_MASK); + if (!sc->sc_channels[chan].enabled) { + if (sc->sc_channels[chan].inverted) + regval |= AQCSFRC(chan, AQCSFRC_HI); + else + regval |= AQCSFRC(chan, AQCSFRC_LO); + } + EPWM_WRITE2(sc, EPWM_AQCSFRC, regval); +} + +static bool +am335x_ehrpwm_cfg_period(struct am335x_ehrpwm_softc *sc, u_int period) +{ + uint16_t regval; + u_int clkdiv, hspclkdiv, pwmclk, pwmtick, tbprd; + + /* Can't do a period shorter than 2 clock ticks. */ + if (period < 2 * NS_PER_SEC / PWM_CLOCK) { + sc->sc_clkfreq = 0; + sc->sc_clktick = 0; + sc->sc_period = 0; + return (false); + } + + /* + * Figure out how much we have to divide down the base 100MHz clock so + * that we can express the requested period as a 16-bit tick count. + */ + tbprd = 0; + for (clkdiv = 0; clkdiv < 8; ++clkdiv) { + const u_int cd = 1 << clkdiv; + for (hspclkdiv = 0; hspclkdiv < 8; ++hspclkdiv) { + const u_int cdhs = max(1, hspclkdiv * 2); + pwmclk = PWM_CLOCK / (cd * cdhs); + pwmtick = NS_PER_SEC / pwmclk; + if (period / pwmtick < 65536) { + tbprd = period / pwmtick; + break; + } + } + if (tbprd != 0) + break; + } + + /* Handle requested period too long for available clock divisors. */ + if (tbprd == 0) + return (false); + + /* + * If anything has changed from the current settings, reprogram the + * clock divisors and period register. + */ + if (sc->sc_clkfreq != pwmclk || sc->sc_clktick != pwmtick || + sc->sc_period != tbprd * pwmtick) { + + sc->sc_clkfreq = pwmclk; + sc->sc_clktick = pwmtick; + sc->sc_period = tbprd * pwmtick; + + PWM_LOCK_ASSERT(sc); + regval = EPWM_READ2(sc, EPWM_TBCTL); + regval &= ~(TBCTL_CLKDIV_MASK | TBCTL_HSPCLKDIV_MASK); + regval |= TBCTL_CLKDIV(clkdiv) | TBCTL_HSPCLKDIV(hspclkdiv); + EPWM_WRITE2(sc, EPWM_TBCTL, regval); + EPWM_WRITE2(sc, EPWM_TBPRD, tbprd - 1); +#if 0 + device_printf(sc->sc_dev, "clkdiv %u hspclkdiv %u tbprd %u " + "clkfreq %u Hz clktick %u ns period got %u requested %u\n", + clkdiv, hspclkdiv, tbprd - 1, + sc->sc_clkfreq, sc->sc_clktick, sc->sc_period, period); +#endif + /* + * If the period changed, that invalidates the current CMP + * registers (duty values), just zero them out. + */ + am335x_ehrpwm_cfg_duty(sc, 0, 0); + am335x_ehrpwm_cfg_duty(sc, 1, 0); + } + + return (true); +} static void am335x_ehrpwm_freq(struct am335x_ehrpwm_softc *sc) @@ -331,13 +474,89 @@ am335x_ehrpwm_sysctl_period(SYSCTL_HANDLER_ARGS) } static int +am335x_ehrpwm_channel_count(device_t dev, u_int *nchannel) +{ + + *nchannel = NUM_CHANNELS; + + return (0); +} + +static int +am335x_ehrpwm_channel_config(device_t dev, u_int channel, u_int period, u_int duty) +{ + struct am335x_ehrpwm_softc *sc; + bool status; + + if (channel >= NUM_CHANNELS) + return (EINVAL); + + sc = device_get_softc(dev); + + PWM_LOCK(sc); + status = am335x_ehrpwm_cfg_period(sc, period); + if (status) + am335x_ehrpwm_cfg_duty(sc, channel, duty); + PWM_UNLOCK(sc); + + return (status ? 0 : EINVAL); +} + +static int +am335x_ehrpwm_channel_get_config(device_t dev, u_int channel, + u_int *period, u_int *duty) +{ + struct am335x_ehrpwm_softc *sc; + + if (channel >= NUM_CHANNELS) + return (EINVAL); + + sc = device_get_softc(dev); + *period = sc->sc_period; + *duty = sc->sc_channels[channel].duty; + return (0); +} + +static int +am335x_ehrpwm_channel_enable(device_t dev, u_int channel, bool enable) +{ + struct am335x_ehrpwm_softc *sc; + + if (channel >= NUM_CHANNELS) + return (EINVAL); + + sc = device_get_softc(dev); + + PWM_LOCK(sc); + am335x_ehrpwm_cfg_enable(sc, channel, enable); + PWM_UNLOCK(sc); + + return (0); +} + +static int +am335x_ehrpwm_channel_is_enabled(device_t dev, u_int channel, bool *enabled) +{ + struct am335x_ehrpwm_softc *sc; + + if (channel >= NUM_CHANNELS) + return (EINVAL); + + sc = device_get_softc(dev); + + *enabled = sc->sc_channels[channel].enabled; + + return (0); +} + +static int am335x_ehrpwm_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); - if (!ofw_bus_is_compatible(dev, "ti,am33xx-ehrpwm")) + if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) return (ENXIO); device_set_desc(dev, "AM335x EHRPWM"); @@ -365,7 +584,7 @@ am335x_ehrpwm_attach(device_t dev) goto fail; } - /* Init backlight interface */ + /* Init sysctl interface */ ctx = device_get_sysctl_ctx(sc->sc_dev); tree = device_get_sysctl_tree(sc->sc_dev); @@ -414,7 +633,13 @@ am335x_ehrpwm_attach(device_t dev) EPWM_WRITE2(sc, EPWM_TZCTL, 0xf); reg = EPWM_READ2(sc, EPWM_TZFLG); - return (0); + if ((sc->sc_busdev = device_add_child(dev, "pwmbus", -1)) == NULL) { + device_printf(dev, "Cannot add child pwmbus\n"); + // This driver can still do things even without the bus child. + } + + bus_generic_probe(dev); + return (bus_generic_attach(dev)); fail: PWM_LOCK_DESTROY(sc); if (sc->sc_mem_res) @@ -428,13 +653,22 @@ static int am335x_ehrpwm_detach(device_t dev) { struct am335x_ehrpwm_softc *sc; + int error; sc = device_get_softc(dev); + if ((error = bus_generic_detach(sc->sc_dev)) != 0) + return (error); + PWM_LOCK(sc); + + if (sc->sc_busdev != NULL) + device_delete_child(dev, sc->sc_busdev); + if (sc->sc_mem_res) bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_mem_rid, sc->sc_mem_res); + PWM_UNLOCK(sc); PWM_LOCK_DESTROY(sc); @@ -442,6 +676,44 @@ am335x_ehrpwm_detach(device_t dev) return (0); } +static phandle_t +am335x_ehrpwm_get_node(device_t bus, device_t dev) +{ + + /* + * Share our controller node with our pwmbus child; it instantiates + * devices by walking the children contained within our node. + */ + return ofw_bus_get_node(bus); +} + +static device_method_t am335x_ehrpwm_methods[] = { + DEVMETHOD(device_probe, am335x_ehrpwm_probe), + DEVMETHOD(device_attach, am335x_ehrpwm_attach), + DEVMETHOD(device_detach, am335x_ehrpwm_detach), + + /* ofw_bus_if */ + DEVMETHOD(ofw_bus_get_node, am335x_ehrpwm_get_node), + + /* pwm interface */ + DEVMETHOD(pwmbus_channel_count, am335x_ehrpwm_channel_count), + DEVMETHOD(pwmbus_channel_config, am335x_ehrpwm_channel_config), + DEVMETHOD(pwmbus_channel_get_config, am335x_ehrpwm_channel_get_config), + DEVMETHOD(pwmbus_channel_enable, am335x_ehrpwm_channel_enable), + DEVMETHOD(pwmbus_channel_is_enabled, am335x_ehrpwm_channel_is_enabled), + + DEVMETHOD_END +}; + +static driver_t am335x_ehrpwm_driver = { + "pwm", + am335x_ehrpwm_methods, + sizeof(struct am335x_ehrpwm_softc), +}; + +static devclass_t am335x_ehrpwm_devclass; + DRIVER_MODULE(am335x_ehrpwm, am335x_pwmss, am335x_ehrpwm_driver, am335x_ehrpwm_devclass, 0, 0); MODULE_VERSION(am335x_ehrpwm, 1); MODULE_DEPEND(am335x_ehrpwm, am335x_pwmss, 1, 1, 1); +MODULE_DEPEND(am335x_ehrpwm, pwmbus, 1, 1, 1); diff --git a/sys/arm64/acpica/acpi_iort.c b/sys/arm64/acpica/acpi_iort.c index edd87474c9c9..10a501254bc6 100644 --- a/sys/arm64/acpica/acpi_iort.c +++ b/sys/arm64/acpica/acpi_iort.c @@ -370,19 +370,44 @@ srat_resolve_its_pxm(ACPI_SUBTABLE_HEADER *entry, void *arg) ACPI_SRAT_GIC_ITS_AFFINITY *gicits; struct iort_node *its_node; struct iort_its_entry *its_entry; - int i, matches; + int *map_counts; + int i, matches, dom; if (entry->Type != ACPI_SRAT_TYPE_GIC_ITS_AFFINITY) return; matches = 0; + map_counts = arg; gicits = (ACPI_SRAT_GIC_ITS_AFFINITY *)entry; + dom = acpi_map_pxm_to_vm_domainid(gicits->ProximityDomain); + + /* + * Catch firmware and config errors. map_counts keeps a + * count of ProximityDomain values mapping to a domain ID + */ +#if MAXMEMDOM > 1 + if (dom == -1) + printf("Firmware Error: Proximity Domain %d could not be" + " mapped for GIC ITS ID %d!\n", + gicits->ProximityDomain, gicits->ItsId); +#endif + /* use dom + 1 as index to handle the case where dom == -1 */ + i = ++map_counts[dom + 1]; + if (i > 1) { +#ifdef NUMA + if (dom != -1) + printf("ERROR: Multiple Proximity Domains map to the" + " same NUMA domain %d!\n", dom); +#else + printf("WARNING: multiple Proximity Domains in SRAT but NUMA" + " NOT enabled!\n"); +#endif + } TAILQ_FOREACH(its_node, &its_groups, next) { its_entry = its_node->entries.its; for (i = 0; i < its_node->nentries; i++, its_entry++) { if (its_entry->its_id == gicits->ItsId) { - its_entry->pxm = acpi_map_pxm_to_vm_domainid( - gicits->ProximityDomain); + its_entry->pxm = dom; matches++; } } @@ -401,6 +426,7 @@ iort_post_process_its(void) ACPI_TABLE_MADT *madt; ACPI_TABLE_SRAT *srat; vm_paddr_t madt_pa, srat_pa; + int map_counts[MAXMEMDOM + 1] = { 0 }; /* Check ITS block in MADT */ madt_pa = acpi_find_table(ACPI_SIG_MADT); @@ -417,7 +443,7 @@ iort_post_process_its(void) srat = acpi_map_table(srat_pa, ACPI_SIG_SRAT); KASSERT(srat != NULL, ("can't map SRAT!")); acpi_walk_subtables(srat + 1, (char *)srat + srat->Header.Length, - srat_resolve_its_pxm, NULL); + srat_resolve_its_pxm, map_counts); acpi_unmap_table(srat); } return (0); diff --git a/sys/arm64/arm64/freebsd32_machdep.c b/sys/arm64/arm64/freebsd32_machdep.c index aeac4605f2f5..2e25fe062b19 100644 --- a/sys/arm64/arm64/freebsd32_machdep.c +++ b/sys/arm64/arm64/freebsd32_machdep.c @@ -122,6 +122,7 @@ static void get_fpcontext32(struct thread *td, mcontext32_vfp_t *mcp) { struct pcb *curpcb; + int i; critical_enter(); curpcb = curthread->td_pcb; @@ -137,8 +138,8 @@ get_fpcontext32(struct thread *td, mcontext32_vfp_t *mcp) ("Called get_fpcontext while the kernel is using the VFP")); KASSERT((curpcb->pcb_fpflags & ~PCB_FP_USERMASK) == 0, ("Non-userspace FPU flags set in get_fpcontext")); - memcpy(mcp->mcv_reg, curpcb->pcb_fpustate.vfp_regs, - sizeof(mcp->mcv_reg)); + for (i = 0; i < 32; i++) + mcp->mcv_reg[i] = (uint64_t)curpcb->pcb_fpustate.vfp_regs[i]; mcp->mcv_fpscr = VFP_FPSCR_FROM_SRCR(curpcb->pcb_fpustate.vfp_fpcr, curpcb->pcb_fpustate.vfp_fpsr); } @@ -149,13 +150,14 @@ static void set_fpcontext32(struct thread *td, mcontext32_vfp_t *mcp) { struct pcb *pcb; + int i; critical_enter(); pcb = td->td_pcb; if (td == curthread) vfp_discard(td); - memcpy(pcb->pcb_fpustate.vfp_regs, mcp->mcv_reg, - sizeof(pcb->pcb_fpustate.vfp_regs)); + for (i = 0; i < 32; i++) + pcb->pcb_fpustate.vfp_regs[i] = mcp->mcv_reg[i]; pcb->pcb_fpustate.vfp_fpsr = VFP_FPSR_FROM_FPSCR(mcp->mcv_fpscr); pcb->pcb_fpustate.vfp_fpcr = VFP_FPSR_FROM_FPSCR(mcp->mcv_fpscr); critical_exit(); diff --git a/sys/arm64/arm64/gic_v3.c b/sys/arm64/arm64/gic_v3.c index af08ee992bb6..a83ef576e30e 100644 --- a/sys/arm64/arm64/gic_v3.c +++ b/sys/arm64/arm64/gic_v3.c @@ -390,10 +390,6 @@ gic_v3_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) case GICV3_IVAR_NIRQS: *result = (NIRQ - sc->gic_nirqs) / sc->gic_nchildren; return (0); - case GICV3_IVAR_REDIST_VADDR: - *result = (uintptr_t)rman_get_virtual( - &sc->gic_redists.pcpu[PCPU_GET(cpuid)]->res); - return (0); case GICV3_IVAR_REDIST: *result = (uintptr_t)sc->gic_redists.pcpu[PCPU_GET(cpuid)]; return (0); diff --git a/sys/arm64/arm64/gic_v3_var.h b/sys/arm64/arm64/gic_v3_var.h index 27dec4d72190..1257484a5e57 100644 --- a/sys/arm64/arm64/gic_v3_var.h +++ b/sys/arm64/arm64/gic_v3_var.h @@ -94,11 +94,10 @@ MALLOC_DECLARE(M_GIC_V3); /* ivars */ #define GICV3_IVAR_NIRQS 1000 -#define GICV3_IVAR_REDIST_VADDR 1001 +/* 1001 was GICV3_IVAR_REDIST_VADDR */ #define GICV3_IVAR_REDIST 1002 __BUS_ACCESSOR(gicv3, nirqs, GICV3, NIRQS, u_int); -__BUS_ACCESSOR(gicv3, redist_vaddr, GICV3, REDIST_VADDR, void *); __BUS_ACCESSOR(gicv3, redist, GICV3, REDIST, void *); /* Device methods */ diff --git a/sys/arm64/arm64/gicv3_its.c b/sys/arm64/arm64/gicv3_its.c index f347a36c12cc..2701a7e8df0a 100644 --- a/sys/arm64/arm64/gicv3_its.c +++ b/sys/arm64/arm64/gicv3_its.c @@ -747,9 +747,7 @@ gicv3_its_attach(device_t dev) if (domain < MAXMEMDOM) CPU_COPY(&cpuset_domain[domain], &sc->sc_cpus); } else { - /* XXX : cannot handle more than one ITS per cpu */ - if (device_get_unit(dev) == 0) - CPU_COPY(&all_cpus, &sc->sc_cpus); + CPU_COPY(&all_cpus, &sc->sc_cpus); } /* Allocate the command circular buffer */ diff --git a/sys/arm64/arm64/machdep.c b/sys/arm64/arm64/machdep.c index b8ecfc08e676..4356add12aa0 100644 --- a/sys/arm64/arm64/machdep.c +++ b/sys/arm64/arm64/machdep.c @@ -194,6 +194,16 @@ fill_regs(struct thread *td, struct reg *regs) memcpy(regs->x, frame->tf_x, sizeof(regs->x)); +#ifdef COMPAT_FREEBSD32 + /* + * We may be called here for a 32bits process, if we're using a + * 64bits debugger. If so, put PC and SPSR where it expects it. + */ + if (SV_PROC_FLAG(td->td_proc, SV_ILP32)) { + regs->x[15] = frame->tf_elr; + regs->x[16] = frame->tf_spsr; + } +#endif return (0); } @@ -211,6 +221,17 @@ set_regs(struct thread *td, struct reg *regs) memcpy(frame->tf_x, regs->x, sizeof(frame->tf_x)); +#ifdef COMPAT_FREEBSD32 + if (SV_PROC_FLAG(td->td_proc, SV_ILP32)) { + /* + * We may be called for a 32bits process if we're using + * a 64bits debugger. If so, get PC and SPSR from where + * it put it. + */ + frame->tf_elr = regs->x[15]; + frame->tf_spsr = regs->x[16] & PSR_FLAGS; + } +#endif return (0); } @@ -283,8 +304,9 @@ fill_regs32(struct thread *td, struct reg32 *regs) tf = td->td_frame; for (i = 0; i < 13; i++) regs->r[i] = tf->tf_x[i]; - regs->r_sp = tf->tf_sp; - regs->r_lr = tf->tf_lr; + /* For arm32, SP is r13 and LR is r14 */ + regs->r_sp = tf->tf_x[13]; + regs->r_lr = tf->tf_x[14]; regs->r_pc = tf->tf_elr; regs->r_cpsr = tf->tf_spsr; @@ -300,8 +322,9 @@ set_regs32(struct thread *td, struct reg32 *regs) tf = td->td_frame; for (i = 0; i < 13; i++) tf->tf_x[i] = regs->r[i]; - tf->tf_sp = regs->r_sp; - tf->tf_lr = regs->r_lr; + /* For arm 32, SP is r13 an LR is r14 */ + tf->tf_x[13] = regs->r_sp; + tf->tf_x[14] = regs->r_lr; tf->tf_elr = regs->r_pc; tf->tf_spsr = regs->r_cpsr; diff --git a/sys/arm64/arm64/pmap.c b/sys/arm64/arm64/pmap.c index df34873025dd..bf74bb55f038 100644 --- a/sys/arm64/arm64/pmap.c +++ b/sys/arm64/arm64/pmap.c @@ -2510,6 +2510,82 @@ pmap_remove_l3(pmap_t pmap, pt_entry_t *l3, vm_offset_t va, } /* + * Remove the specified range of addresses from the L3 page table that is + * identified by the given L2 entry. + */ +static void +pmap_remove_l3_range(pmap_t pmap, pd_entry_t l2e, vm_offset_t sva, + vm_offset_t eva, struct spglist *free, struct rwlock **lockp) +{ + struct md_page *pvh; + struct rwlock *new_lock; + pt_entry_t *l3, old_l3; + vm_offset_t va; + vm_page_t m; + + PMAP_LOCK_ASSERT(pmap, MA_OWNED); + KASSERT(rounddown2(sva, L2_SIZE) + L2_SIZE == roundup2(eva, L2_SIZE), + ("pmap_remove_l3_range: range crosses an L3 page table boundary")); + va = eva; + for (l3 = pmap_l2_to_l3(&l2e, sva); sva != eva; l3++, sva += L3_SIZE) { + if (!pmap_l3_valid(pmap_load(l3))) { + if (va != eva) { + pmap_invalidate_range(pmap, va, sva); + va = eva; + } + continue; + } + old_l3 = pmap_load_clear(l3); + if ((old_l3 & ATTR_SW_WIRED) != 0) + pmap->pm_stats.wired_count--; + pmap_resident_count_dec(pmap, 1); + if ((old_l3 & ATTR_SW_MANAGED) != 0) { + m = PHYS_TO_VM_PAGE(old_l3 & ~ATTR_MASK); + if (pmap_page_dirty(old_l3)) + vm_page_dirty(m); + if ((old_l3 & ATTR_AF) != 0) + vm_page_aflag_set(m, PGA_REFERENCED); + new_lock = PHYS_TO_PV_LIST_LOCK(VM_PAGE_TO_PHYS(m)); + if (new_lock != *lockp) { + if (*lockp != NULL) { + /* + * Pending TLB invalidations must be + * performed before the PV list lock is + * released. Otherwise, a concurrent + * pmap_remove_all() on a physical page + * could return while a stale TLB entry + * still provides access to that page. + */ + if (va != eva) { + pmap_invalidate_range(pmap, va, + sva); + va = eva; + } + rw_wunlock(*lockp); + } + *lockp = new_lock; + rw_wlock(*lockp); + } + pmap_pvh_free(&m->md, pmap, sva); + if (TAILQ_EMPTY(&m->md.pv_list) && + (m->flags & PG_FICTITIOUS) == 0) { + pvh = pa_to_pvh(VM_PAGE_TO_PHYS(m)); + if (TAILQ_EMPTY(&pvh->pv_list)) + vm_page_aflag_clear(m, PGA_WRITEABLE); + } + } + if (va == eva) + va = sva; + if (pmap_unuse_pt(pmap, sva, l2e, free)) { + sva += L3_SIZE; + break; + } + } + if (va != eva) + pmap_invalidate_range(pmap, va, sva); +} + +/* * Remove the given range of addresses from the specified map. * * It is assumed that the start and end are properly @@ -2519,9 +2595,9 @@ void pmap_remove(pmap_t pmap, vm_offset_t sva, vm_offset_t eva) { struct rwlock *lock; - vm_offset_t va, va_next; + vm_offset_t va_next; pd_entry_t *l0, *l1, *l2; - pt_entry_t l3_paddr, *l3; + pt_entry_t l3_paddr; struct spglist free; /* @@ -2594,28 +2670,8 @@ pmap_remove(pmap_t pmap, vm_offset_t sva, vm_offset_t eva) if (va_next > eva) va_next = eva; - va = va_next; - for (l3 = pmap_l2_to_l3(l2, sva); sva != va_next; l3++, - sva += L3_SIZE) { - if (l3 == NULL) - panic("l3 == NULL"); - if (pmap_load(l3) == 0) { - if (va != va_next) { - pmap_invalidate_range(pmap, va, sva); - va = va_next; - } - continue; - } - if (va == va_next) - va = sva; - if (pmap_remove_l3(pmap, l3, sva, l3_paddr, &free, - &lock)) { - sva += L3_SIZE; - break; - } - } - if (va != va_next) - pmap_invalidate_range(pmap, va, sva); + pmap_remove_l3_range(pmap, l3_paddr, sva, va_next, &free, + &lock); } if (lock != NULL) rw_wunlock(lock); @@ -3352,7 +3408,7 @@ validate: __func__, pmap, va, new_l3); } } else { - /* New mappig */ + /* New mapping */ pmap_load_store(l3, new_l3); dsb(ishst); } @@ -3419,8 +3475,7 @@ pmap_enter_l2(pmap_t pmap, vm_offset_t va, pd_entry_t new_l2, u_int flags, vm_page_t m, struct rwlock **lockp) { struct spglist free; - pd_entry_t *l2, *l3, old_l2; - vm_offset_t sva; + pd_entry_t *l2, old_l2; vm_page_t l2pg, mt; PMAP_LOCK_ASSERT(pmap, MA_OWNED); @@ -3449,13 +3504,8 @@ pmap_enter_l2(pmap_t pmap, vm_offset_t va, pd_entry_t new_l2, u_int flags, (void)pmap_remove_l2(pmap, l2, va, pmap_load(pmap_l1(pmap, va)), &free, lockp); else - for (sva = va; sva < va + L2_SIZE; sva += PAGE_SIZE) { - l3 = pmap_l2_to_l3(l2, sva); - if (pmap_l3_valid(pmap_load(l3)) && - pmap_remove_l3(pmap, l3, sva, old_l2, &free, - lockp) != 0) - break; - } + pmap_remove_l3_range(pmap, old_l2, va, va + L2_SIZE, + &free, lockp); vm_page_free_pages_toq(&free, true); if (va >= VM_MAXUSER_ADDRESS) { /* @@ -3656,6 +3706,9 @@ pmap_enter_quick_locked(pmap_t pmap, vm_offset_t va, vm_page_t m, l3 = pmap_l2_to_l3(pde, va); } + /* + * Abort if a mapping already exists. + */ if (pmap_load(l3) != 0) { if (mpte != NULL) { mpte->wire_count--; @@ -3705,7 +3758,15 @@ pmap_enter_quick_locked(pmap_t pmap, vm_offset_t va, vm_page_t m, cpu_icache_sync_range(PHYS_TO_DMAP(pa), PAGE_SIZE); pmap_load_store(l3, l3_val); + + /* + * XXX In principle, because this L3 entry was invalid, we should not + * need to perform a TLB invalidation here. However, in practice, + * when simply performing a "dsb ishst" here, processes are being + * terminated due to bus errors and segmentation violations. + */ pmap_invalidate_page(pmap, va); + return (mpte); } diff --git a/sys/arm64/conf/GENERIC b/sys/arm64/conf/GENERIC index 8e3f04fe1db1..2adee9db99d4 100644 --- a/sys/arm64/conf/GENERIC +++ b/sys/arm64/conf/GENERIC @@ -293,7 +293,6 @@ device aw_cir # Pseudo devices. device crypto # core crypto support device loop # Network loopback -device random # Entropy device device ether # Ethernet support device vlan # 802.1Q VLAN support device tuntap # Packet tunnel. diff --git a/sys/cam/ata/ata_all.c b/sys/cam/ata/ata_all.c index 76d65ae5e405..9a4cdbed071b 100644 --- a/sys/cam/ata/ata_all.c +++ b/sys/cam/ata/ata_all.c @@ -1238,3 +1238,28 @@ ata_zac_mgmt_in(struct ccb_ataio *ataio, uint32_t retries, ataio->aux = auxiliary; } } + +void +ata_param_fixup(struct ata_params *ident_buf) +{ + int16_t *ptr; + + for (ptr = (int16_t *)ident_buf; + ptr < (int16_t *)ident_buf + sizeof(struct ata_params)/2; ptr++) { + *ptr = le16toh(*ptr); + } + if (strncmp(ident_buf->model, "FX", 2) && + strncmp(ident_buf->model, "NEC", 3) && + strncmp(ident_buf->model, "Pioneer", 7) && + strncmp(ident_buf->model, "SHARP", 5)) { + ata_bswap(ident_buf->model, sizeof(ident_buf->model)); + ata_bswap(ident_buf->revision, sizeof(ident_buf->revision)); + ata_bswap(ident_buf->serial, sizeof(ident_buf->serial)); + } + ata_btrim(ident_buf->model, sizeof(ident_buf->model)); + ata_bpack(ident_buf->model, ident_buf->model, sizeof(ident_buf->model)); + ata_btrim(ident_buf->revision, sizeof(ident_buf->revision)); + ata_bpack(ident_buf->revision, ident_buf->revision, sizeof(ident_buf->revision)); + ata_btrim(ident_buf->serial, sizeof(ident_buf->serial)); + ata_bpack(ident_buf->serial, ident_buf->serial, sizeof(ident_buf->serial)); +} diff --git a/sys/cam/ata/ata_all.h b/sys/cam/ata/ata_all.h index 087d6820f980..ca635253511c 100644 --- a/sys/cam/ata/ata_all.h +++ b/sys/cam/ata/ata_all.h @@ -135,6 +135,7 @@ void ata_read_log(struct ccb_ataio *ataio, uint32_t retries, uint16_t block_count, uint32_t protocol, uint8_t *data_ptr, uint32_t dxfer_len, uint32_t timeout); +void ata_param_fixup(struct ata_params *ident_buf); void ata_bswap(int8_t *buf, int len); void ata_btrim(int8_t *buf, int len); void ata_bpack(int8_t *src, int8_t *dst, int len); diff --git a/sys/cam/ata/ata_xpt.c b/sys/cam/ata/ata_xpt.c index 94dc435b099b..017db8854b08 100644 --- a/sys/cam/ata/ata_xpt.c +++ b/sys/cam/ata/ata_xpt.c @@ -893,14 +893,13 @@ noerror: case PROBE_IDENTIFY: { struct ccb_pathinq cpi; - int16_t *ptr; int veto = 0; + /* + * Convert to host byte order, and fix the strings. + */ ident_buf = &softc->ident_data; - for (ptr = (int16_t *)ident_buf; - ptr < (int16_t *)ident_buf + sizeof(struct ata_params)/2; ptr++) { - *ptr = le16toh(*ptr); - } + ata_param_fixup(ident_buf); /* * Allow others to veto this ATA disk attachment. This @@ -912,20 +911,6 @@ noerror: goto device_fail; } - if (strncmp(ident_buf->model, "FX", 2) && - strncmp(ident_buf->model, "NEC", 3) && - strncmp(ident_buf->model, "Pioneer", 7) && - strncmp(ident_buf->model, "SHARP", 5)) { - ata_bswap(ident_buf->model, sizeof(ident_buf->model)); - ata_bswap(ident_buf->revision, sizeof(ident_buf->revision)); - ata_bswap(ident_buf->serial, sizeof(ident_buf->serial)); - } - ata_btrim(ident_buf->model, sizeof(ident_buf->model)); - ata_bpack(ident_buf->model, ident_buf->model, sizeof(ident_buf->model)); - ata_btrim(ident_buf->revision, sizeof(ident_buf->revision)); - ata_bpack(ident_buf->revision, ident_buf->revision, sizeof(ident_buf->revision)); - ata_btrim(ident_buf->serial, sizeof(ident_buf->serial)); - ata_bpack(ident_buf->serial, ident_buf->serial, sizeof(ident_buf->serial)); /* Device may need spin-up before IDENTIFY become valid. */ if ((ident_buf->specconf == 0x37c8 || ident_buf->specconf == 0x738c) && diff --git a/sys/cam/cam_xpt.c b/sys/cam/cam_xpt.c index 2217ecc6d2ff..4736c7212a2c 100644 --- a/sys/cam/cam_xpt.c +++ b/sys/cam/cam_xpt.c @@ -1244,6 +1244,7 @@ xpt_getattr(char *buf, size_t len, const char *attr, struct cam_path *path) { int ret = -1, l, o; struct ccb_dev_advinfo cdai; + struct scsi_vpd_device_id *did; struct scsi_vpd_id_descriptor *idd; xpt_path_assert(path, MA_OWNED); @@ -1253,6 +1254,7 @@ xpt_getattr(char *buf, size_t len, const char *attr, struct cam_path *path) cdai.ccb_h.func_code = XPT_DEV_ADVINFO; cdai.flags = CDAI_FLAG_NONE; cdai.bufsiz = len; + cdai.buf = buf; if (!strcmp(attr, "GEOM::ident")) cdai.buftype = CDAI_TYPE_SERIAL_NUM; @@ -1262,44 +1264,49 @@ xpt_getattr(char *buf, size_t len, const char *attr, struct cam_path *path) strcmp(attr, "GEOM::lunname") == 0) { cdai.buftype = CDAI_TYPE_SCSI_DEVID; cdai.bufsiz = CAM_SCSI_DEVID_MAXLEN; + cdai.buf = malloc(cdai.bufsiz, M_CAMXPT, M_NOWAIT); + if (cdai.buf == NULL) { + ret = ENOMEM; + goto out; + } } else goto out; - cdai.buf = malloc(cdai.bufsiz, M_CAMXPT, M_NOWAIT|M_ZERO); - if (cdai.buf == NULL) { - ret = ENOMEM; - goto out; - } xpt_action((union ccb *)&cdai); /* can only be synchronous */ if ((cdai.ccb_h.status & CAM_DEV_QFRZN) != 0) cam_release_devq(cdai.ccb_h.path, 0, 0, 0, FALSE); if (cdai.provsiz == 0) goto out; - if (cdai.buftype == CDAI_TYPE_SCSI_DEVID) { + switch(cdai.buftype) { + case CDAI_TYPE_SCSI_DEVID: + did = (struct scsi_vpd_device_id *)cdai.buf; if (strcmp(attr, "GEOM::lunid") == 0) { - idd = scsi_get_devid((struct scsi_vpd_device_id *)cdai.buf, - cdai.provsiz, scsi_devid_is_lun_naa); + idd = scsi_get_devid(did, cdai.provsiz, + scsi_devid_is_lun_naa); if (idd == NULL) - idd = scsi_get_devid((struct scsi_vpd_device_id *)cdai.buf, - cdai.provsiz, scsi_devid_is_lun_eui64); + idd = scsi_get_devid(did, cdai.provsiz, + scsi_devid_is_lun_eui64); if (idd == NULL) - idd = scsi_get_devid((struct scsi_vpd_device_id *)cdai.buf, - cdai.provsiz, scsi_devid_is_lun_uuid); + idd = scsi_get_devid(did, cdai.provsiz, + scsi_devid_is_lun_uuid); if (idd == NULL) - idd = scsi_get_devid((struct scsi_vpd_device_id *)cdai.buf, - cdai.provsiz, scsi_devid_is_lun_md5); + idd = scsi_get_devid(did, cdai.provsiz, + scsi_devid_is_lun_md5); } else idd = NULL; + if (idd == NULL) - idd = scsi_get_devid((struct scsi_vpd_device_id *)cdai.buf, - cdai.provsiz, scsi_devid_is_lun_t10); + idd = scsi_get_devid(did, cdai.provsiz, + scsi_devid_is_lun_t10); if (idd == NULL) - idd = scsi_get_devid((struct scsi_vpd_device_id *)cdai.buf, - cdai.provsiz, scsi_devid_is_lun_name); + idd = scsi_get_devid(did, cdai.provsiz, + scsi_devid_is_lun_name); if (idd == NULL) - goto out; + break; + ret = 0; - if ((idd->proto_codeset & SVPD_ID_CODESET_MASK) == SVPD_ID_CODESET_ASCII) { + if ((idd->proto_codeset & SVPD_ID_CODESET_MASK) == + SVPD_ID_CODESET_ASCII) { if (idd->length < len) { for (l = 0; l < idd->length; l++) buf[l] = idd->identifier[l] ? @@ -1307,40 +1314,50 @@ xpt_getattr(char *buf, size_t len, const char *attr, struct cam_path *path) buf[l] = 0; } else ret = EFAULT; - } else if ((idd->proto_codeset & SVPD_ID_CODESET_MASK) == SVPD_ID_CODESET_UTF8) { + break; + } + if ((idd->proto_codeset & SVPD_ID_CODESET_MASK) == + SVPD_ID_CODESET_UTF8) { l = strnlen(idd->identifier, idd->length); if (l < len) { bcopy(idd->identifier, buf, l); buf[l] = 0; } else ret = EFAULT; - } else if ((idd->id_type & SVPD_ID_TYPE_MASK) == SVPD_ID_TYPE_UUID - && idd->identifier[0] == 0x10) { - if ((idd->length - 2) * 2 + 4 < len) { - for (l = 2, o = 0; l < idd->length; l++) { - if (l == 6 || l == 8 || l == 10 || l == 12) - o += sprintf(buf + o, "-"); - o += sprintf(buf + o, "%02x", - idd->identifier[l]); - } - } else - ret = EFAULT; - } else { - if (idd->length * 2 < len) { - for (l = 0; l < idd->length; l++) - sprintf(buf + l * 2, "%02x", - idd->identifier[l]); - } else + break; + } + if ((idd->id_type & SVPD_ID_TYPE_MASK) == + SVPD_ID_TYPE_UUID && idd->identifier[0] == 0x10) { + if ((idd->length - 2) * 2 + 4 >= len) { ret = EFAULT; + break; + } + for (l = 2, o = 0; l < idd->length; l++) { + if (l == 6 || l == 8 || l == 10 || l == 12) + o += sprintf(buf + o, "-"); + o += sprintf(buf + o, "%02x", + idd->identifier[l]); + } + break; } - } else { - ret = 0; - if (strlcpy(buf, cdai.buf, len) >= len) + if (idd->length * 2 < len) { + for (l = 0; l < idd->length; l++) + sprintf(buf + l * 2, "%02x", + idd->identifier[l]); + } else + ret = EFAULT; + break; + default: + if (cdai.provsiz < len) { + cdai.buf[cdai.provsiz] = 0; + ret = 0; + } else ret = EFAULT; + break; } out: - if (cdai.buf != NULL) + if ((char *)cdai.buf != buf) free(cdai.buf, M_CAMXPT); return ret; } diff --git a/sys/cam/ctl/ctl_error.c b/sys/cam/ctl/ctl_error.c index 17e9e3a51d80..dae4deb9e5e7 100644 --- a/sys/cam/ctl/ctl_error.c +++ b/sys/cam/ctl/ctl_error.c @@ -81,6 +81,12 @@ ctl_set_sense_data_va(struct scsi_sense_data *sense_data, u_int *sense_len, */ if (sense_format == SSD_TYPE_NONE) { /* + * SPC-3 and up require some UAs to be returned as fixed. + */ + if (asc == 0x29 || (asc == 0x2A && ascq == 0x01)) + sense_format = SSD_TYPE_FIXED; + else + /* * If the format isn't specified, we only return descriptor * sense if the LUN exists and descriptor sense is turned * on for that LUN. diff --git a/sys/cam/scsi/scsi_all.c b/sys/cam/scsi/scsi_all.c index 1d92c4d8e915..5ab37e3f6416 100644 --- a/sys/cam/scsi/scsi_all.c +++ b/sys/cam/scsi/scsi_all.c @@ -5574,6 +5574,7 @@ scsi_devid_is_naa_ieee_reg(uint8_t *bufp) { struct scsi_vpd_id_descriptor *descr; struct scsi_vpd_id_naa_basic *naa; + int n; descr = (struct scsi_vpd_id_descriptor *)bufp; naa = (struct scsi_vpd_id_naa_basic *)descr->identifier; @@ -5581,7 +5582,8 @@ scsi_devid_is_naa_ieee_reg(uint8_t *bufp) return 0; if (descr->length < sizeof(struct scsi_vpd_id_naa_ieee_reg)) return 0; - if ((naa->naa >> SVPD_ID_NAA_NAA_SHIFT) != SVPD_ID_NAA_IEEE_REG) + n = naa->naa >> SVPD_ID_NAA_NAA_SHIFT; + if (n != SVPD_ID_NAA_LOCAL_REG && n != SVPD_ID_NAA_IEEE_REG) return 0; return 1; } diff --git a/sys/cam/scsi/scsi_da.c b/sys/cam/scsi/scsi_da.c index a89c40e19a7b..f2f60d35b2e2 100644 --- a/sys/cam/scsi/scsi_da.c +++ b/sys/cam/scsi/scsi_da.c @@ -64,6 +64,9 @@ __FBSDID("$FreeBSD$"); #include <cam/cam_ccb.h> #include <cam/cam_periph.h> #include <cam/cam_xpt_periph.h> +#ifdef _KERNEL +#include <cam/cam_xpt_internal.h> +#endif /* _KERNEL */ #include <cam/cam_sim.h> #include <cam/cam_iosched.h> @@ -3613,15 +3616,7 @@ out: break; } - ata_params = (struct ata_params*) - malloc(sizeof(*ata_params), M_SCSIDA,M_NOWAIT|M_ZERO); - - if (ata_params == NULL) { - xpt_print(periph->path, "Couldn't malloc ata_params " - "data\n"); - /* da_free_periph??? */ - break; - } + ata_params = &periph->path->device->ident_data; scsi_ata_identify(&start_ccb->csio, /*retries*/da_retry_count, @@ -5192,7 +5187,7 @@ dadone_probeata(struct cam_periph *periph, union ccb *done_ccb) struct da_softc *softc; u_int32_t priority; int continue_probe; - int error, i; + int error; int16_t *ptr; CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("dadone_probeata\n")); @@ -5210,8 +5205,7 @@ dadone_probeata(struct cam_periph *periph, union ccb *done_ccb) if ((csio->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { uint16_t old_rate; - for (i = 0; i < sizeof(*ata_params) / 2; i++) - ptr[i] = le16toh(ptr[i]); + ata_param_fixup(ata_params); if (ata_params->support_dsm & ATA_SUPPORT_DSM_TRIM && (softc->quirks & DA_Q_NO_UNMAP) == 0) { dadeleteflag(softc, DA_DELETE_ATA_TRIM, 1); @@ -5295,7 +5289,6 @@ dadone_probeata(struct cam_periph *periph, union ccb *done_ccb) } } - free(ata_params, M_SCSIDA); if ((softc->zone_mode == DA_ZONE_HOST_AWARE) || (softc->zone_mode == DA_ZONE_HOST_MANAGED)) { /* diff --git a/sys/cam/scsi/scsi_enc.c b/sys/cam/scsi/scsi_enc.c index 363f27db5f78..ec190232fff9 100644 --- a/sys/cam/scsi/scsi_enc.c +++ b/sys/cam/scsi/scsi_enc.c @@ -81,6 +81,17 @@ static enctyp enc_type(struct ccb_getdev *); SYSCTL_NODE(_kern_cam, OID_AUTO, enc, CTLFLAG_RD, 0, "CAM Enclosure Services driver"); +#if defined(DEBUG) || defined(ENC_DEBUG) +int enc_verbose = 1; +#else +int enc_verbose = 0; +#endif +SYSCTL_INT(_kern_cam_enc, OID_AUTO, verbose, CTLFLAG_RWTUN, + &enc_verbose, 0, "Enable verbose logging"); + +const char *elm_type_names[] = ELM_TYPE_NAMES; +CTASSERT(nitems(elm_type_names) - 1 == ELMTYP_LAST); + static struct periph_driver encdriver = { enc_init, "ses", TAILQ_HEAD_INITIALIZER(encdriver.units), /* generation */ 0 @@ -232,11 +243,17 @@ enc_async(void *callback_arg, uint32_t code, struct cam_path *path, void *arg) struct enc_softc *softc; softc = (struct enc_softc *)periph->softc; - if (xpt_path_path_id(periph->path) != path_id - || softc == NULL - || (softc->enc_flags & ENC_FLAG_INITIALIZED) - == 0 - || softc->enc_vec.device_found == NULL) + + /* Check this SEP is ready. */ + if (softc == NULL || (softc->enc_flags & + ENC_FLAG_INITIALIZED) == 0 || + softc->enc_vec.device_found == NULL) + continue; + + /* Check this SEP may manage this device. */ + if (xpt_path_path_id(periph->path) != path_id && + (softc->enc_type != ENC_SEMB_SES || + cgd->protocol != PROTO_ATA)) continue; softc->enc_vec.device_found(softc); @@ -432,7 +449,7 @@ enc_ioctl(struct cdev *dev, u_long cmd, caddr_t arg_addr, int flag, encioc_element_t kelm; kelm.elm_idx = i; kelm.elm_subenc_id = cache->elm_map[i].subenclosure; - kelm.elm_type = cache->elm_map[i].enctype; + kelm.elm_type = cache->elm_map[i].elm_type; error = copyout(&kelm, &uelm[i], sizeof(kelm)); if (error) break; @@ -684,14 +701,8 @@ enc_type(struct ccb_getdev *cgd) buflen = min(sizeof(cgd->inq_data), SID_ADDITIONAL_LENGTH(&cgd->inq_data)); - if ((iqd[0] & 0x1f) == T_ENCLOSURE) { - if ((iqd[2] & 0x7) > 2) { - return (ENC_SES); - } else { - return (ENC_SES_SCSI2); - } - return (ENC_NONE); - } + if ((iqd[0] & 0x1f) == T_ENCLOSURE) + return (ENC_SES); #ifdef SES_ENABLE_PASSTHROUGH if ((iqd[6] & 0x40) && (iqd[2] & 0x7) >= 2) { @@ -928,7 +939,6 @@ enc_ctor(struct cam_periph *periph, void *arg) switch (enc->enc_type) { case ENC_SES: - case ENC_SES_SCSI2: case ENC_SES_PASSTHROUGH: case ENC_SEMB_SES: err = ses_softc_init(enc); @@ -1017,17 +1027,14 @@ enc_ctor(struct cam_periph *periph, void *arg) case ENC_NONE: tname = "No ENC device"; break; - case ENC_SES_SCSI2: - tname = "SCSI-2 ENC Device"; - break; case ENC_SES: - tname = "SCSI-3 ENC Device"; + tname = "SES Device"; break; case ENC_SES_PASSTHROUGH: - tname = "ENC Passthrough Device"; + tname = "SES Passthrough Device"; break; case ENC_SAFT: - tname = "SAF-TE Compliant Device"; + tname = "SAF-TE Device"; break; case ENC_SEMB_SES: tname = "SEMB SES Device"; diff --git a/sys/cam/scsi/scsi_enc.h b/sys/cam/scsi/scsi_enc.h index fc7e3bd3f1c6..f9abe099e337 100644 --- a/sys/cam/scsi/scsi_enc.h +++ b/sys/cam/scsi/scsi_enc.h @@ -120,10 +120,42 @@ typedef enum { ELMTYP_SCSI_INI = 0x15, ELMTYP_SUBENC = 0x16, ELMTYP_ARRAY_DEV = 0x17, - ELMTYP_SAS_EXP = 0x18, /* SAS expander */ - ELMTYP_SAS_CONN = 0x19 /* SAS connector */ + ELMTYP_SAS_EXP = 0x18, /* SAS Expander */ + ELMTYP_SAS_CONN = 0x19, /* SAS Connector */ + ELMTYP_LAST = ELMTYP_SAS_CONN } elm_type_t; +#define ELM_TYPE_NAMES { \ + "Unspecified", \ + "Device Slot", \ + "Power Supply", \ + "Cooling", \ + "Temperature Sensors", \ + "Door", \ + "Audible alarm", \ + "Enclosure Services Controller Electronics", \ + "SCC Controller Electronics", \ + "Nonvolatile Cache", \ + "Invalid Operation Reason", \ + "Uninterruptible Power Supply", \ + "Display", \ + "Key Pad Entry", \ + "Enclosure", \ + "SCSI Port/Transceiver", \ + "Language", \ + "Communication Port", \ + "Voltage Sensor", \ + "Current Sensor", \ + "SCSI Target Port", \ + "SCSI Initiator Port", \ + "Simple Subenclosure", \ + "Array Device Slot", \ + "SAS Expander", \ + "SAS Connector" \ +} + +extern const char *elm_type_names[]; + typedef struct encioc_element { /* Element Index */ unsigned int elm_idx; diff --git a/sys/cam/scsi/scsi_enc_internal.h b/sys/cam/scsi/scsi_enc_internal.h index 0d4bdffda4f9..293da3ee7386 100644 --- a/sys/cam/scsi/scsi_enc_internal.h +++ b/sys/cam/scsi/scsi_enc_internal.h @@ -36,17 +36,15 @@ #ifndef __SCSI_ENC_INTERNAL_H__ #define __SCSI_ENC_INTERNAL_H__ +#include <sys/sysctl.h> + typedef struct enc_element { - uint32_t - enctype : 8, /* enclosure type */ - subenclosure : 8, /* subenclosure id */ - svalid : 1, /* enclosure information valid */ - overall_status_elem: 1,/* - * This object represents generic - * status about all objects of this - * type. - */ - priv : 14; /* private data, per object */ + uint8_t elm_idx; /* index of element */ + uint8_t elm_type; /* element type */ + uint8_t subenclosure; /* subenclosure id */ + uint8_t type_elm_idx; /* index of element within type */ + uint8_t svalid; /* enclosure information valid */ + uint16_t priv; /* private data, per object */ uint8_t encstat[4]; /* state && stats */ uint8_t *physical_path; /* Device physical path data. */ u_int physical_path_len; /* Length of device path data. */ @@ -55,10 +53,8 @@ typedef struct enc_element { typedef enum { ENC_NONE, - ENC_SES_SCSI2, ENC_SES, ENC_SES_PASSTHROUGH, - ENC_SEN, ENC_SAFT, ENC_SEMB_SES, ENC_SEMB_SAFT @@ -206,6 +202,9 @@ enc_softc_init_t ses_softc_init; /* SAF-TE interface */ enc_softc_init_t safte_softc_init; +SYSCTL_DECL(_kern_cam_enc); +extern int enc_verbose; + /* Helper macros */ MALLOC_DECLARE(M_SCSIENC); #define ENC_CFLAGS CAM_RETRY_SELTO @@ -218,7 +217,7 @@ MALLOC_DECLARE(M_SCSIENC); #else #define ENC_DLOG if (0) enc_log #endif -#define ENC_VLOG if (bootverbose) enc_log +#define ENC_VLOG if (enc_verbose) enc_log #define ENC_MALLOC(amt) malloc(amt, M_SCSIENC, M_NOWAIT) #define ENC_MALLOCZ(amt) malloc(amt, M_SCSIENC, M_ZERO|M_NOWAIT) /* Cast away const avoiding GCC warnings. */ diff --git a/sys/cam/scsi/scsi_enc_safte.c b/sys/cam/scsi/scsi_enc_safte.c index 8afcc323991a..94219cde7a89 100644 --- a/sys/cam/scsi/scsi_enc_safte.c +++ b/sys/cam/scsi/scsi_enc_safte.c @@ -227,7 +227,6 @@ static char *safte_2little = "Too Little Data Returned (%d) at line %d\n"; } int emulate_array_devices = 1; -SYSCTL_DECL(_kern_cam_enc); SYSCTL_INT(_kern_cam_enc, OID_AUTO, emulate_array_devices, CTLFLAG_RWTUN, &emulate_array_devices, 0, "Emulate Array Devices for SAF-TE"); @@ -302,21 +301,21 @@ safte_process_config(enc_softc_t *enc, struct enc_fsm_state *state, * in later fetches of status. */ for (i = 0; i < cfg->Nfans; i++) - enc->enc_cache.elm_map[r++].enctype = ELMTYP_FAN; + enc->enc_cache.elm_map[r++].elm_type = ELMTYP_FAN; cfg->pwroff = (uint8_t) r; for (i = 0; i < cfg->Npwr; i++) - enc->enc_cache.elm_map[r++].enctype = ELMTYP_POWER; + enc->enc_cache.elm_map[r++].elm_type = ELMTYP_POWER; for (i = 0; i < cfg->DoorLock; i++) - enc->enc_cache.elm_map[r++].enctype = ELMTYP_DOORLOCK; + enc->enc_cache.elm_map[r++].elm_type = ELMTYP_DOORLOCK; if (cfg->Nspkrs > 0) - enc->enc_cache.elm_map[r++].enctype = ELMTYP_ALARM; + enc->enc_cache.elm_map[r++].elm_type = ELMTYP_ALARM; for (i = 0; i < cfg->Ntherm; i++) - enc->enc_cache.elm_map[r++].enctype = ELMTYP_THERM; + enc->enc_cache.elm_map[r++].elm_type = ELMTYP_THERM; for (i = 0; i <= cfg->Ntstats; i++) - enc->enc_cache.elm_map[r++].enctype = ELMTYP_THERM; + enc->enc_cache.elm_map[r++].elm_type = ELMTYP_THERM; cfg->slotoff = (uint8_t) r; for (i = 0; i < cfg->Nslots; i++) - enc->enc_cache.elm_map[r++].enctype = + enc->enc_cache.elm_map[r++].elm_type = emulate_array_devices ? ELMTYP_ARRAY_DEV : ELMTYP_DEVICE; @@ -506,7 +505,7 @@ safte_process_status(enc_softc_t *enc, struct enc_fsm_state *state, */ for (i = 0; i < cfg->Nslots; i++) { SAFT_BAIL(r, xfer_len); - if (cache->elm_map[cfg->slotoff + i].enctype == ELMTYP_DEVICE) + if (cache->elm_map[cfg->slotoff + i].elm_type == ELMTYP_DEVICE) cache->elm_map[cfg->slotoff + i].encstat[1] = buf[r]; r++; } @@ -679,7 +678,7 @@ safte_process_slotstatus(enc_softc_t *enc, struct enc_fsm_state *state, oid = cfg->slotoff; for (r = i = 0; i < cfg->Nslots; i++, r += 4) { SAFT_BAIL(r+3, xfer_len); - if (cache->elm_map[oid].enctype == ELMTYP_ARRAY_DEV) + if (cache->elm_map[oid].elm_type == ELMTYP_ARRAY_DEV) cache->elm_map[oid].encstat[1] = 0; cache->elm_map[oid].encstat[2] &= SESCTL_RQSID; cache->elm_map[oid].encstat[3] = 0; @@ -706,7 +705,7 @@ safte_process_slotstatus(enc_softc_t *enc, struct enc_fsm_state *state, cache->elm_map[oid].encstat[3] |= SESCTL_RQSFLT; if (buf[r+0] & 0x40) cache->elm_map[oid].encstat[0] |= SESCTL_PRDFAIL; - if (cache->elm_map[oid].enctype == ELMTYP_ARRAY_DEV) { + if (cache->elm_map[oid].elm_type == ELMTYP_ARRAY_DEV) { if (buf[r+0] & 0x01) cache->elm_map[oid].encstat[1] |= 0x80; if (buf[r+0] & 0x04) @@ -772,7 +771,7 @@ safte_fill_control_request(enc_softc_t *enc, struct enc_fsm_state *state, } else { ep = &enc->enc_cache.elm_map[idx]; - switch (ep->enctype) { + switch (ep->elm_type) { case ELMTYP_DEVICE: case ELMTYP_ARRAY_DEV: switch (cfg->current_request_stage) { @@ -782,7 +781,7 @@ safte_fill_control_request(enc_softc_t *enc, struct enc_fsm_state *state, ep->priv |= 0x40; if (req->elm_stat[3] & SESCTL_RQSFLT) ep->priv |= 0x02; - if (ep->enctype == ELMTYP_ARRAY_DEV) { + if (ep->elm_type == ELMTYP_ARRAY_DEV) { if (req->elm_stat[1] & 0x01) ep->priv |= 0x200; if (req->elm_stat[1] & 0x02) @@ -971,7 +970,7 @@ safte_process_control_request(enc_softc_t *enc, struct enc_fsm_state *state, if (idx == SES_SETSTATUS_ENC_IDX) type = -1; else - type = enc->enc_cache.elm_map[idx].enctype; + type = enc->enc_cache.elm_map[idx].elm_type; if (type == ELMTYP_DEVICE || type == ELMTYP_ARRAY_DEV) enc_update_request(enc, SAFTE_UPDATE_READSLOTSTATUS); else diff --git a/sys/cam/scsi/scsi_enc_ses.c b/sys/cam/scsi/scsi_enc_ses.c index 5e9d2dc94d2d..e5a18d5d9a45 100644 --- a/sys/cam/scsi/scsi_enc_ses.c +++ b/sys/cam/scsi/scsi_enc_ses.c @@ -102,6 +102,7 @@ typedef struct ses_addl_status { union { union ses_fcobj_hdr *fc; union ses_elm_sas_hdr *sas; + struct ses_elm_ata_hdr *ata; } proto_hdr; union ses_addl_data proto_data; /* array sizes stored in header */ } ses_add_status_t; @@ -444,6 +445,7 @@ ses_iter_next(struct ses_iterator *iter) iter->type_element_index = ITERATOR_INDEX_END; iter->global_element_index = ITERATOR_INDEX_END; iter->individual_element_index = ITERATOR_INDEX_END; + iter->saved_individual_element_index = ITERATOR_INDEX_END; return (NULL); } @@ -468,17 +470,12 @@ ses_iter_next(struct ses_iterator *iter) */ iter->type_index++; iter->type_element_index = 0; - iter->saved_individual_element_index - = iter->individual_element_index; iter->individual_element_index = ITERATOR_INDEX_INVALID; } if (iter->type_element_index > 0) { - if (iter->type_element_index == 1) { - iter->individual_element_index - = iter->saved_individual_element_index; - } - iter->individual_element_index++; + iter->individual_element_index = + ++iter->saved_individual_element_index; } return (&iter->cache->elm_map[iter->global_element_index]); @@ -829,14 +826,6 @@ ses_devids_iter(enc_softc_t *enc, enc_element_t *elm, elmpriv = elm->elm_private; addl = &(elmpriv->addl); - /* - * Don't assume this object has additional status information, or - * that it is a SAS device, or that it is a device slot device. - */ - if (addl->hdr == NULL || addl->proto_hdr.sas == NULL - || addl->proto_data.sasdev_phys == NULL) - return; - devid_record_size = SVPD_DEVICE_ID_DESC_HDR_LEN + sizeof(struct scsi_vpd_id_naa_ieee_reg); for (i = 0; i < addl->proto_hdr.sas->base_hdr.num_phys; i++) { @@ -954,11 +943,40 @@ static void ses_paths_iter(enc_softc_t *enc, enc_element_t *elm, ses_path_callback_t *callback, void *callback_arg) { - ses_path_iter_args_t args; + ses_element_t *elmpriv; + struct ses_addl_status *addl; + + elmpriv = elm->elm_private; + addl = &(elmpriv->addl); + + if (addl->hdr == NULL) + return; - args.callback = callback; - args.callback_arg = callback_arg; - ses_devids_iter(enc, elm, ses_path_iter_devid_callback, &args); + if (addl->proto_hdr.sas != NULL && + addl->proto_data.sasdev_phys != NULL) { + ses_path_iter_args_t args; + + args.callback = callback; + args.callback_arg = callback_arg; + ses_devids_iter(enc, elm, ses_path_iter_devid_callback, &args); + } else if (addl->proto_hdr.ata != NULL) { + struct cam_path *path; + struct ccb_getdev cgd; + + if (xpt_create_path(&path, /*periph*/NULL, + scsi_4btoul(addl->proto_hdr.ata->bus), + scsi_4btoul(addl->proto_hdr.ata->target), 0) + != CAM_REQ_CMP) + return; + + xpt_setup_ccb(&cgd.ccb_h, path, CAM_PRIORITY_NORMAL); + cgd.ccb_h.func_code = XPT_GDEV_TYPE; + xpt_action((union ccb *)&cgd); + if (cgd.ccb_h.status == CAM_REQ_CMP) + callback(enc, elm, path, callback_arg); + + xpt_free_path(path); + } } /** @@ -1063,6 +1081,10 @@ ses_set_physpath(enc_softc_t *enc, enc_element_t *elm, ret = EIO; devid = NULL; + elmpriv = elm->elm_private; + if (elmpriv->addl.hdr == NULL) + goto out; + /* * Assemble the components of the physical path starting with * the device ID of the enclosure itself. @@ -1095,7 +1117,6 @@ ses_set_physpath(enc_softc_t *enc, enc_element_t *elm, scsi_8btou64(idd->identifier), iter->type_index, iter->type_element_index); /* Append the element descriptor if one exists */ - elmpriv = elm->elm_private; if (elmpriv->descr != NULL && elmpriv->descr_len > 0) { sbuf_cat(&sb, "/elmdesc@"); for (i = 0, c = elmpriv->descr; i < elmpriv->descr_len; @@ -1461,9 +1482,10 @@ ses_process_config(enc_softc_t *enc, struct enc_fsm_state *state, iter.global_element_index, iter.type_index, nelm, iter.type_element_index); thdr = ses_cache->ses_types[iter.type_index].hdr; + element->elm_idx = iter.global_element_index; + element->elm_type = thdr->etype_elm_type; element->subenclosure = thdr->etype_subenc; - element->enctype = thdr->etype_elm_type; - element->overall_status_elem = iter.type_element_index == 0; + element->type_elm_idx = iter.type_element_index; element->elm_private = malloc(sizeof(ses_element_t), M_SCSIENC, M_WAITOK|M_ZERO); ENC_DLOG(enc, "%s: creating elmpriv %d(%d,%d) subenc %d " @@ -1667,6 +1689,8 @@ static int ses_get_elm_addlstatus_fc(enc_softc_t *, enc_cache_t *, uint8_t *, int); static int ses_get_elm_addlstatus_sas(enc_softc_t *, enc_cache_t *, uint8_t *, int, int, int, int); +static int ses_get_elm_addlstatus_ata(enc_softc_t *, enc_cache_t *, uint8_t *, + int, int, int, int); /** * \brief Parse the additional status element data for each object. @@ -1685,7 +1709,6 @@ ses_process_elm_addlstatus(enc_softc_t *enc, struct enc_fsm_state *state, struct ses_iterator iter, titer; int eip; int err; - int ignore_index = 0; int length; int offset; enc_cache_t *enc_cache; @@ -1756,7 +1779,7 @@ ses_process_elm_addlstatus(enc_softc_t *enc, struct enc_fsm_state *state, elm_hdr = (struct ses_elm_addlstatus_base_hdr *)&buf[offset]; eip = ses_elm_addlstatus_eip(elm_hdr); - if (eip && !ignore_index) { + if (eip) { struct ses_elm_addlstatus_eip_hdr *eip_hdr; int expected_index, index; ses_elem_index_type_t index_type; @@ -1769,17 +1792,44 @@ ses_process_elm_addlstatus(enc_softc_t *enc, struct enc_fsm_state *state, index_type = SES_ELEM_INDEX_INDIVIDUAL; expected_index = iter.individual_element_index; } + if (eip_hdr->element_index < expected_index) { + ENC_VLOG(enc, "%s: provided %selement index " + "%d is lower then expected %d\n", + __func__, (eip_hdr->byte2 & + SES_ADDL_EIP_EIIOE) ? "global " : "", + eip_hdr->element_index, expected_index); + goto badindex; + } titer = iter; telement = ses_iter_seek_to(&titer, eip_hdr->element_index, index_type); - if (telement != NULL && - (ses_typehasaddlstatus(enc, titer.type_index) != - TYPE_ADDLSTATUS_NONE || - titer.type_index > ELMTYP_SAS_CONN)) { + if (telement == NULL) { + ENC_VLOG(enc, "%s: provided %selement index " + "%d does not exist\n", __func__, + (eip_hdr->byte2 & SES_ADDL_EIP_EIIOE) ? + "global " : "", eip_hdr->element_index); + goto badindex; + } + if (ses_typehasaddlstatus(enc, titer.type_index) == + TYPE_ADDLSTATUS_NONE) { + ENC_VLOG(enc, "%s: provided %selement index " + "%d can't have additional status\n", + __func__, + (eip_hdr->byte2 & SES_ADDL_EIP_EIIOE) ? + "global " : "", eip_hdr->element_index); +badindex: + /* + * If we expected mandatory element, we may + * guess it was just a wrong index and we may + * use the status. If element was optional, + * then we have no idea where status belongs. + */ + if (status_type == TYPE_ADDLSTATUS_OPTIONAL) + break; + } else { iter = titer; element = telement; - } else - ignore_index = 1; + } if (eip_hdr->byte2 & SES_ADDL_EIP_EIIOE) index = iter.global_element_index; @@ -1796,40 +1846,46 @@ ses_process_elm_addlstatus(enc_softc_t *enc, struct enc_fsm_state *state, } } elmpriv = element->elm_private; - elmpriv->addl.hdr = elm_hdr; ENC_DLOG(enc, "%s: global element index=%d, type index=%d " "type element index=%d, offset=0x%x, " "byte0=0x%x, length=0x%x\n", __func__, iter.global_element_index, iter.type_index, - iter.type_element_index, offset, elmpriv->addl.hdr->byte0, - elmpriv->addl.hdr->length); + iter.type_element_index, offset, elm_hdr->byte0, + elm_hdr->length); /* Skip to after the length field */ offset += sizeof(struct ses_elm_addlstatus_base_hdr); /* Make sure the descriptor is within bounds */ - if ((offset + elmpriv->addl.hdr->length) > length) { + if ((offset + elm_hdr->length) > length) { ENC_VLOG(enc, "Element %d Beyond End " "of Additional Element Status Descriptors\n", iter.global_element_index); break; } + /* Skip elements marked as invalid. */ + if (ses_elm_addlstatus_invalid(elm_hdr)) { + offset += elm_hdr->length; + continue; + } + elmpriv->addl.hdr = elm_hdr; + /* Advance to the protocol data, skipping eip bytes if needed */ offset += (eip * SES_EIP_HDR_EXTRA_LEN); - proto_info_len = elmpriv->addl.hdr->length + proto_info_len = elm_hdr->length - (eip * SES_EIP_HDR_EXTRA_LEN); /* Errors in this block are ignored as they are non-fatal */ - switch(ses_elm_addlstatus_proto(elmpriv->addl.hdr)) { + switch(ses_elm_addlstatus_proto(elm_hdr)) { case SPSP_PROTO_FC: - if (elmpriv->addl.hdr->length == 0) + if (elm_hdr->length == 0) break; ses_get_elm_addlstatus_fc(enc, enc_cache, &buf[offset], proto_info_len); break; case SPSP_PROTO_SAS: - if (elmpriv->addl.hdr->length <= 2) + if (elm_hdr->length <= 2) break; ses_get_elm_addlstatus_sas(enc, enc_cache, &buf[offset], @@ -1837,10 +1893,17 @@ ses_process_elm_addlstatus(enc_softc_t *enc, struct enc_fsm_state *state, eip, iter.type_index, iter.global_element_index); break; + case SPSP_PROTO_ATA: + ses_get_elm_addlstatus_ata(enc, enc_cache, + &buf[offset], + proto_info_len, + eip, iter.type_index, + iter.global_element_index); + break; default: ENC_VLOG(enc, "Element %d: Unknown Additional Element " "Protocol 0x%x\n", iter.global_element_index, - ses_elm_addlstatus_proto(elmpriv->addl.hdr)); + ses_elm_addlstatus_proto(elm_hdr)); break; } @@ -2165,18 +2228,16 @@ ses_get_elm_addlstatus_fc(enc_softc_t *enc, enc_cache_t *enc_cache, } #define SES_PRINT_PORTS(p, type) do { \ - sbuf_printf(sbp, " %s(", type); \ - if (((p) & SES_SASOBJ_DEV_PHY_PROTOMASK) == 0) \ - sbuf_printf(sbp, " None"); \ - else { \ + if (((p) & SES_SASOBJ_DEV_PHY_PROTOMASK) != 0) { \ + sbuf_printf(sbp, " %s (", type); \ if ((p) & SES_SASOBJ_DEV_PHY_SMP) \ sbuf_printf(sbp, " SMP"); \ if ((p) & SES_SASOBJ_DEV_PHY_STP) \ sbuf_printf(sbp, " STP"); \ if ((p) & SES_SASOBJ_DEV_PHY_SSP) \ sbuf_printf(sbp, " SSP"); \ + sbuf_printf(sbp, " )"); \ } \ - sbuf_printf(sbp, " )"); \ } while(0) /** @@ -2186,11 +2247,10 @@ ses_get_elm_addlstatus_fc(enc_softc_t *enc, enc_cache_t *enc_cache, * \param sesname SES device name associated with the object. * \param sbp Sbuf to print to. * \param obj The object to print the data for. - * \param periph_name Peripheral string associated with the object. */ static void ses_print_addl_data_sas_type0(char *sesname, struct sbuf *sbp, - enc_element_t *obj, char *periph_name) + enc_element_t *obj) { int i; ses_element_t *elmpriv; @@ -2199,16 +2259,12 @@ ses_print_addl_data_sas_type0(char *sesname, struct sbuf *sbp, elmpriv = obj->elm_private; addl = &(elmpriv->addl); - if (addl->proto_hdr.sas == NULL) - return; - sbuf_printf(sbp, "%s: %s: SAS Device Slot Element:", - sesname, periph_name); - sbuf_printf(sbp, " %d Phys", addl->proto_hdr.sas->base_hdr.num_phys); + sbuf_printf(sbp, ", SAS Slot: %d%s phys", + addl->proto_hdr.sas->base_hdr.num_phys, + ses_elm_sas_type0_not_all_phys(addl->proto_hdr.sas) ? "+" : ""); if (ses_elm_addlstatus_eip(addl->hdr)) - sbuf_printf(sbp, " at Slot %d", + sbuf_printf(sbp, " at slot %d", addl->proto_hdr.sas->type0_eip.dev_slot_num); - if (ses_elm_sas_type0_not_all_phys(addl->proto_hdr.sas)) - sbuf_printf(sbp, ", Not All Phys"); sbuf_printf(sbp, "\n"); if (addl->proto_data.sasdev_phys == NULL) return; @@ -2219,9 +2275,8 @@ ses_print_addl_data_sas_type0(char *sesname, struct sbuf *sbp, /* Spec says all other fields are specific values */ sbuf_printf(sbp, " SATA device\n"); else { - sbuf_printf(sbp, " SAS device type %d id %d\n", + sbuf_printf(sbp, " SAS device type %d phy %d", ses_elm_sas_dev_phy_dev_type(phy), phy->phy_id); - sbuf_printf(sbp, "%s: phy %d: protocols:", sesname, i); SES_PRINT_PORTS(phy->initiator_ports, "Initiator"); SES_PRINT_PORTS(phy->target_ports, "Target"); sbuf_printf(sbp, "\n"); @@ -2235,32 +2290,16 @@ ses_print_addl_data_sas_type0(char *sesname, struct sbuf *sbp, #undef SES_PRINT_PORTS /** - * \brief Report whether a given enclosure object is an expander. - * - * \param enc SES softc associated with object. - * \param obj Enclosure object to report for. - * - * \return 1 if true, 0 otherwise. - */ -static int -ses_obj_is_expander(enc_softc_t *enc, enc_element_t *obj) -{ - return (obj->enctype == ELMTYP_SAS_EXP); -} - -/** * \brief Print the additional element status data for this object, for SAS * type 1 objects. See SES2 r20 Sections 6.1.13.3.3 and 6.1.13.3.4. * - * \param enc SES enclosure, needed for type identification. * \param sesname SES device name associated with the object. * \param sbp Sbuf to print to. * \param obj The object to print the data for. - * \param periph_name Peripheral string associated with the object. */ static void -ses_print_addl_data_sas_type1(enc_softc_t *enc, char *sesname, - struct sbuf *sbp, enc_element_t *obj, char *periph_name) +ses_print_addl_data_sas_type1(char *sesname, struct sbuf *sbp, + enc_element_t *obj) { int i, num_phys; ses_element_t *elmpriv; @@ -2270,12 +2309,10 @@ ses_print_addl_data_sas_type1(enc_softc_t *enc, char *sesname, elmpriv = obj->elm_private; addl = &(elmpriv->addl); - if (addl->proto_hdr.sas == NULL) - return; - sbuf_printf(sbp, "%s: %s: SAS ", sesname, periph_name); - if (ses_obj_is_expander(enc, obj)) { + sbuf_printf(sbp, ", SAS "); + if (obj->elm_type == ELMTYP_SAS_EXP) { num_phys = addl->proto_hdr.sas->base_hdr.num_phys; - sbuf_printf(sbp, "Expander: %d Phys", num_phys); + sbuf_printf(sbp, "Expander: %d phys", num_phys); if (addl->proto_data.sasexp_phys == NULL) return; for (i = 0;i < num_phys;i++) { @@ -2286,7 +2323,7 @@ ses_print_addl_data_sas_type1(enc_softc_t *enc, char *sesname, } } else { num_phys = addl->proto_hdr.sas->base_hdr.num_phys; - sbuf_printf(sbp, "Port: %d Phys", num_phys); + sbuf_printf(sbp, "Port: %d phys", num_phys); if (addl->proto_data.sasport_phys == NULL) return; for (i = 0;i < num_phys;i++) { @@ -2302,6 +2339,24 @@ ses_print_addl_data_sas_type1(enc_softc_t *enc, char *sesname, } /** + * \brief Print the additional element status data for this object, for + * ATA objects. + * + * \param sbp Sbuf to print to. + * \param obj The object to print the data for. + */ +static void +ses_print_addl_data_ata(struct sbuf *sbp, enc_element_t *obj) +{ + ses_element_t *elmpriv = obj->elm_private; + struct ses_addl_status *addl = &elmpriv->addl; + struct ses_elm_ata_hdr *ata = addl->proto_hdr.ata; + + sbuf_printf(sbp, ", SATA Slot: scbus%d target %d\n", + scsi_4btoul(ata->bus), scsi_4btoul(ata->target)); +} + +/** * \brief Print the additional element status data for this object. * * \param enc SES softc associated with the object. @@ -2332,27 +2387,45 @@ ses_print_addl_data(enc_softc_t *enc, enc_element_t *obj) sbuf_printf(&sesname, "%s%d", enc->periph->periph_name, enc->periph->unit_number); sbuf_finish(&sesname); + sbuf_printf(&out, "%s: %s in ", sbuf_data(&sesname), sbuf_data(&name)); if (elmpriv->descr != NULL) - sbuf_printf(&out, "%s: %s: Element descriptor: '%s'\n", - sbuf_data(&sesname), sbuf_data(&name), elmpriv->descr); + sbuf_printf(&out, "'%s'", elmpriv->descr); + else { + if (obj->elm_type <= ELMTYP_LAST) + sbuf_cat(&out, elm_type_names[obj->elm_type]); + else + sbuf_printf(&out, "<Type 0x%02x>", obj->elm_type); + sbuf_printf(&out, " %d", obj->type_elm_idx); + if (obj->subenclosure != 0) + sbuf_printf(&out, " of subenc %d", obj->subenclosure); + } switch(ses_elm_addlstatus_proto(addl->hdr)) { + case SPSP_PROTO_FC: + goto noaddl; /* stubbed for now */ case SPSP_PROTO_SAS: + if (addl->proto_hdr.sas == NULL) + goto noaddl; switch(ses_elm_sas_descr_type(addl->proto_hdr.sas)) { case SES_SASOBJ_TYPE_SLOT: ses_print_addl_data_sas_type0(sbuf_data(&sesname), - &out, obj, sbuf_data(&name)); + &out, obj); break; case SES_SASOBJ_TYPE_OTHER: - ses_print_addl_data_sas_type1(enc, sbuf_data(&sesname), - &out, obj, sbuf_data(&name)); + ses_print_addl_data_sas_type1(sbuf_data(&sesname), + &out, obj); break; default: - break; + goto noaddl; } break; - case SPSP_PROTO_FC: /* stubbed for now */ + case SPSP_PROTO_ATA: + if (addl->proto_hdr.ata == NULL) + goto noaddl; + ses_print_addl_data_ata(&out, obj); break; default: +noaddl: + sbuf_cat(&out, "\n"); break; } sbuf_finish(&out); @@ -2457,7 +2530,7 @@ ses_get_elm_addlstatus_sas_type1(enc_softc_t *enc, enc_cache_t *enc_cache, goto out; /* Process expanders differently from other type1 cases */ - if (ses_obj_is_expander(enc, obj)) { + if (obj->elm_type == ELMTYP_SAS_EXP) { offset += sizeof(struct ses_elm_sas_type1_expander_hdr); physz = addl->proto_hdr.sas->base_hdr.num_phys * sizeof(struct ses_elm_sas_expander_phy); @@ -2565,6 +2638,53 @@ out: return (err); } +/** + * \brief Update the softc with the additional element status data for this + * object, for ATA objects. + * + * \param enc SES softc to be updated. + * \param buf The additional element status response buffer. + * \param bufsiz Size of the response buffer. + * \param eip The EIP bit value. + * \param tidx Type index for this object. + * \param nobj Number of objects attached to the SES softc. + * + * \return 0 on success, errno otherwise. + */ +static int +ses_get_elm_addlstatus_ata(enc_softc_t *enc, enc_cache_t *enc_cache, + uint8_t *buf, int bufsiz, int eip, int tidx, + int nobj) +{ + int err; + ses_cache_t *ses_cache; + + if (bufsiz < sizeof(struct ses_elm_ata_hdr)) { + err = EIO; + goto out; + } + + ses_cache = enc_cache->private; + switch(ses_cache->ses_types[tidx].hdr->etype_elm_type) { + case ELMTYP_DEVICE: + case ELMTYP_ARRAY_DEV: + break; + default: + ENC_VLOG(enc, "Element %d has Additional Status, " + "invalid for SES element type 0x%x\n", nobj, + ses_cache->ses_types[tidx].hdr->etype_elm_type); + err = ENODEV; + goto out; + } + + ((ses_element_t *)enc_cache->elm_map[nobj].elm_private) + ->addl.proto_hdr.ata = (struct ses_elm_ata_hdr *)buf; + err = 0; + +out: + return (err); +} + static void ses_softc_invalidate(enc_softc_t *enc) { diff --git a/sys/cam/scsi/scsi_ses.h b/sys/cam/scsi/scsi_ses.h index 779b3a97a00d..b9c69cbcfe30 100644 --- a/sys/cam/scsi/scsi_ses.h +++ b/sys/cam/scsi/scsi_ses.h @@ -2181,15 +2181,27 @@ struct ses_status_page_hdr { #define SESCTL_DISABLE 0x20 #define SESCTL_RSTSWAP 0x10 - -/* Control bits, Device Elements, byte 2 */ -#define SESCTL_DRVLCK 0x40 /* "DO NOT REMOVE" */ +/* Control bits, Array Device Slot Elements, byte 1 */ +#define SESCTL_RQSOK 0x80 /* RQST OK */ +#define SESCTL_RQSRSV 0x40 /* RQST RSVD DEVICE */ +#define SESCTL_RQSSPR 0x20 /* RQST HOT SPARE */ +#define SESCTL_RQSCCH 0x10 /* RQST CONS CHECK */ +#define SESCTL_RQSCRA 0x08 /* RQST IN CRIT ARRAY */ +#define SESCTL_RQSFAA 0x04 /* RQST IN FAILED ARRAY */ +#define SESCTL_RQSRR 0x02 /* RQST REBUI/REMAP */ +#define SESCTL_RQSRRA 0x01 /* RQST R/R ABORT */ +/* Control bits, [Array] Device Slot Elements, byte 2 */ +#define SESCTL_RQSACT 0x80 /* RQST ACTIVE */ +#define SESCTL_DRVLCK 0x40 /* DO NOT REMOVE */ +#define SESCTL_RQSMSN 0x10 /* RQST MISSING */ #define SESCTL_RQSINS 0x08 /* RQST INSERT */ #define SESCTL_RQSRMV 0x04 /* RQST REMOVE */ #define SESCTL_RQSID 0x02 /* RQST IDENT */ -/* Control bits, Device Elements, byte 3 */ +/* Control bits, [Array] Device Slot Elements, byte 3 */ #define SESCTL_RQSFLT 0x20 /* RQST FAULT */ #define SESCTL_DEVOFF 0x10 /* DEVICE OFF */ +#define SESCTL_ENBYPA 0x08 /* ENABLE BYP A */ +#define SESCTL_ENBYPB 0x04 /* ENABLE BYP B */ /* Control bits, Generic, byte 3 */ #define SESCTL_RQSTFAIL 0x40 @@ -2399,6 +2411,17 @@ union ses_elm_sas_hdr { int ses_elm_sas_type0_not_all_phys(union ses_elm_sas_hdr *); int ses_elm_sas_descr_type(union ses_elm_sas_hdr *); +/* + * This structure for SPSP_PROTO_ATA is not defined by SES specs, + * but purely my own design to make AHCI EM interoperate with SES. + * Since no other software I know can talk to SEMB, and we do not + * expose this this outside, it should be safe to do what we want. + */ +struct ses_elm_ata_hdr { + uint8_t bus[4]; + uint8_t target[4]; +}; + struct ses_elm_addlstatus_base_hdr { uint8_t byte0; /* diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_objset.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_objset.c index 2e36e0e5eec1..71d9cd7b6f17 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_objset.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_objset.c @@ -1334,6 +1334,8 @@ dmu_objset_sync(objset_t *os, zio_t *pio, dmu_tx_t *tx) zio_t *zio; list_t *list; dbuf_dirty_record_t *dr; + int num_sublists; + multilist_t *ml; blkptr_t *blkptr_copy = kmem_alloc(sizeof (*os->os_rootbp), KM_SLEEP); *blkptr_copy = *os->os_rootbp; @@ -1402,10 +1404,13 @@ dmu_objset_sync(objset_t *os, zio_t *pio, dmu_tx_t *tx) } } - for (int i = 0; - i < multilist_get_num_sublists(os->os_dirty_dnodes[txgoff]); i++) { + ml = os->os_dirty_dnodes[txgoff]; + num_sublists = multilist_get_num_sublists(ml); + for (int i = 0; i < num_sublists; i++) { + if (multilist_sublist_is_empty_idx(ml, i)) + continue; sync_dnodes_arg_t *sda = kmem_alloc(sizeof (*sda), KM_SLEEP); - sda->sda_list = os->os_dirty_dnodes[txgoff]; + sda->sda_list = ml; sda->sda_sublist_idx = i; sda->sda_tx = tx; (void) taskq_dispatch(dmu_objset_pool(os)->dp_sync_taskq, @@ -1619,6 +1624,8 @@ userquota_updates_task(void *arg) void dmu_objset_do_userquota_updates(objset_t *os, dmu_tx_t *tx) { + int num_sublists; + if (!dmu_objset_userused_enabled(os)) return; @@ -1632,8 +1639,10 @@ dmu_objset_do_userquota_updates(objset_t *os, dmu_tx_t *tx) DMU_OT_USERGROUP_USED, DMU_OT_NONE, 0, tx)); } - for (int i = 0; - i < multilist_get_num_sublists(os->os_synced_dnodes); i++) { + num_sublists = multilist_get_num_sublists(os->os_synced_dnodes); + for (int i = 0; i < num_sublists; i++) { + if (multilist_sublist_is_empty_idx(os->os_synced_dnodes, i)) + continue; userquota_updates_arg_t *uua = kmem_alloc(sizeof (*uua), KM_SLEEP); uua->uua_os = os; diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/multilist.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/multilist.c index b61d1358c8a8..f517454d3d6d 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/multilist.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/multilist.c @@ -360,6 +360,28 @@ multilist_sublist_remove(multilist_sublist_t *mls, void *obj) list_remove(&mls->mls_list, obj); } +int +multilist_sublist_is_empty(multilist_sublist_t *mls) +{ + ASSERT(MUTEX_HELD(&mls->mls_lock)); + return (list_is_empty(&mls->mls_list)); +} + +int +multilist_sublist_is_empty_idx(multilist_t *ml, unsigned int sublist_idx) +{ + multilist_sublist_t *mls; + int empty; + + ASSERT3U(sublist_idx, <, ml->ml_num_sublists); + mls = &ml->ml_sublists[sublist_idx]; + ASSERT(!MUTEX_HELD(&mls->mls_lock)); + mutex_enter(&mls->mls_lock); + empty = list_is_empty(&mls->mls_list); + mutex_exit(&mls->mls_lock); + return (empty); +} + void * multilist_sublist_head(multilist_sublist_t *mls) { diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/multilist.h b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/multilist.h index 7f386fb7c3be..a3b44e60eb97 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/multilist.h +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/multilist.h @@ -89,6 +89,8 @@ void multilist_sublist_insert_head(multilist_sublist_t *, void *); void multilist_sublist_insert_tail(multilist_sublist_t *, void *); void multilist_sublist_move_forward(multilist_sublist_t *mls, void *obj); void multilist_sublist_remove(multilist_sublist_t *, void *); +int multilist_sublist_is_empty(multilist_sublist_t *); +int multilist_sublist_is_empty_idx(multilist_t *, unsigned int); void *multilist_sublist_head(multilist_sublist_t *); void *multilist_sublist_tail(multilist_sublist_t *); diff --git a/sys/compat/linuxkpi/common/include/asm/atomic-long.h b/sys/compat/linuxkpi/common/include/asm/atomic-long.h index d7f839f2541f..108d7f4f7b3a 100644 --- a/sys/compat/linuxkpi/common/include/asm/atomic-long.h +++ b/sys/compat/linuxkpi/common/include/asm/atomic-long.h @@ -42,6 +42,7 @@ typedef struct { } atomic_long_t; #define atomic_long_add(i, v) atomic_long_add_return((i), (v)) +#define atomic_long_sub(i, v) atomic_long_add_return(-(i), (v)) #define atomic_long_inc_return(v) atomic_long_add_return(1, (v)) #define atomic_long_inc_not_zero(v) atomic_long_add_unless((v), 1, 0) diff --git a/sys/compat/linuxkpi/common/include/linux/rculist.h b/sys/compat/linuxkpi/common/include/linux/rculist.h index e4823de7a3bf..0a4ad499c380 100644 --- a/sys/compat/linuxkpi/common/include/linux/rculist.h +++ b/sys/compat/linuxkpi/common/include/linux/rculist.h @@ -33,6 +33,25 @@ #include <linux/list.h> #include <linux/rcupdate.h> +#define list_entry_rcu(ptr, type, member) \ + container_of(READ_ONCE(ptr), type, member) + +#define list_next_rcu(head) (*((struct list_head **)(&(head)->next))) + +#define list_for_each_entry_rcu(pos, head, member) \ + for (pos = list_entry_rcu((head)->next, typeof(*(pos)), member); \ + &(pos)->member != (head); \ + pos = list_entry_rcu((pos)->member.next, typeof(*(pos)), member)) + +static inline void +list_add_rcu(struct list_head *new, struct list_head *prev) +{ + new->next = prev->next; + new->prev = prev; + rcu_assign_pointer(list_next_rcu(prev), new); + prev->prev = new; +} + #define hlist_first_rcu(head) (*((struct hlist_node **)(&(head)->first))) #define hlist_next_rcu(node) (*((struct hlist_node **)(&(node)->next))) #define hlist_pprev_rcu(node) (*((struct hlist_node **)((node)->pprev))) @@ -47,8 +66,12 @@ hlist_add_behind_rcu(struct hlist_node *n, struct hlist_node *prev) n->next->pprev = &n->next; } -#define hlist_for_each_entry_rcu(pos, head, member) \ - hlist_for_each_entry(pos, head, member) +#define hlist_for_each_entry_rcu(pos, head, member) \ + for (pos = hlist_entry_safe (rcu_dereference_raw(hlist_first_rcu(head)),\ + typeof(*(pos)), member); \ + (pos); \ + pos = hlist_entry_safe(rcu_dereference_raw(hlist_next_rcu( \ + &(pos)->member)), typeof(*(pos)), member)) static inline void hlist_del_rcu(struct hlist_node *n) diff --git a/sys/conf/NOTES b/sys/conf/NOTES index 30ae142ba29b..dfa5ff68d802 100644 --- a/sys/conf/NOTES +++ b/sys/conf/NOTES @@ -1170,9 +1170,6 @@ options NFS_DEBUG # Enable NFS Debugging # options EXT2FS -# Cryptographically secure random number generator; /dev/random -device random - # The system memory devices; /dev/mem, /dev/kmem device mem @@ -2424,14 +2421,19 @@ device iicoc # OpenCores I2C controller support # I2C peripheral devices # +device ad7418 # Analog Devices temp and voltage sensor device ds1307 # Dallas DS1307 RTC and compatible device ds13rtc # All Dallas/Maxim ds13xx chips device ds1672 # Dallas DS1672 RTC device ds3231 # Dallas DS3231 RTC + temperature device icee # AT24Cxxx and compatible EEPROMs +device isl12xx # Intersil ISL12xx RTC device lm75 # LM75 compatible temperature sensor device nxprtc # NXP RTCs: PCA/PFC212x PCA/PCF85xx +device rtc8583 # Epson RTC-8583 device s35390a # Seiko Instruments S-35390A RTC +device sy8106a # Silergy Corp. SY8106A buck regulator +device syr827 # Silergy Corp. DC/DC regulator # Parallel-Port Bus # @@ -2479,6 +2481,22 @@ device pps device lpbb device pcfclock +# General Purpose I/O pins +device gpio # gpio interfaces and bus support +device gpiobacklight # sysctl control of gpio-based backlight +device gpioiic # i2c via gpio bitbang +device gpiokeys # kbd(4) glue for gpio-based key input +device gpioled # led(4) gpio glue +device gpiopower # event handler for gpio-based powerdown +device gpiopps # Pulse per second input from gpio pin +device gpioregulator # extres/regulator glue for gpio pin +device gpiospi # SPI via gpio bitbang +device gpioths # 1-wire temp/humidity sensor on gpio pin + +# Pulse width modulation +device pwmbus # pwm interface and bus support +device pwmc # userland control access to pwm outputs + # # Etherswitch framework and drivers # diff --git a/sys/conf/files b/sys/conf/files index dd67e0ec7a68..c62a9e285e47 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -686,14 +686,14 @@ crypto/des/des_ecb.c optional crypto | ipsec | ipsec_support | netsmb crypto/des/des_setkey.c optional crypto | ipsec | ipsec_support | netsmb crypto/rc4/rc4.c optional netgraph_mppc_encryption | kgssapi crypto/rijndael/rijndael-alg-fst.c optional crypto | ekcd | geom_bde | \ - ipsec | ipsec_support | random !random_loadable | wlan_ccmp -crypto/rijndael/rijndael-api-fst.c optional ekcd | geom_bde | random !random_loadable + ipsec | ipsec_support | !random_loadable | wlan_ccmp +crypto/rijndael/rijndael-api-fst.c optional ekcd | geom_bde | !random_loadable crypto/rijndael/rijndael-api.c optional crypto | ipsec | ipsec_support | \ wlan_ccmp crypto/sha1.c optional carp | crypto | ether | ipsec | \ ipsec_support | netgraph_mppc_encryption | sctp crypto/sha2/sha256c.c optional crypto | ekcd | geom_bde | ipsec | \ - ipsec_support | random !random_loadable | sctp | zfs + ipsec_support | !random_loadable | sctp | zfs crypto/sha2/sha512c.c optional crypto | geom_bde | ipsec | \ ipsec_support | zfs crypto/skein/skein.c optional crypto | zfs @@ -1708,7 +1708,7 @@ dev/fdt/fdt_clock_if.m optional fdt fdt_clock dev/fdt/fdt_common.c optional fdt dev/fdt/fdt_pinctrl.c optional fdt fdt_pinctrl dev/fdt/fdt_pinctrl_if.m optional fdt fdt_pinctrl -dev/fdt/fdt_slicer.c optional fdt cfi | fdt nand | fdt mx25l | fdt n25q | fdt at45d +dev/fdt/fdt_slicer.c optional fdt cfi | fdt mx25l | fdt n25q | fdt at45d dev/fdt/fdt_static_dtb.S optional fdt fdt_dtb_static \ dependency "${FDT_DTS_FILE:T:R}.dtb" dev/fdt/simplebus.c optional fdt @@ -1751,7 +1751,7 @@ dev/gpio/gpiospi.c optional gpiospi dev/gpio/gpioths.c optional gpioths dev/gpio/gpio_if.m optional gpio dev/gpio/gpiobus_if.m optional gpio -dev/gpio/gpiopps.c optional gpiopps +dev/gpio/gpiopps.c optional gpiopps fdt dev/gpio/ofw_gpiobus.c optional fdt gpio dev/hifn/hifn7751.c optional hifn dev/hme/if_hme.c optional hme @@ -1775,7 +1775,7 @@ dev/iicbus/ds13rtc.c optional ds13rtc | ds133x | ds1374 dev/iicbus/ds1672.c optional ds1672 dev/iicbus/ds3231.c optional ds3231 dev/iicbus/rtc8583.c optional rtc8583 -dev/iicbus/syr827.c optional ext_resources syr827 +dev/iicbus/syr827.c optional syr827 ext_resources fdt dev/iicbus/icee.c optional icee dev/iicbus/if_ic.c optional ic dev/iicbus/iic.c optional iic @@ -1792,7 +1792,9 @@ dev/iicbus/isl12xx.c optional isl12xx dev/iicbus/lm75.c optional lm75 dev/iicbus/nxprtc.c optional nxprtc | pcf8563 dev/iicbus/ofw_iicbus.c optional fdt iicbus +dev/iicbus/rtc8583.c optional rtc8583 dev/iicbus/s35390a.c optional s35390a +dev/iicbus/sy8106a.c optional sy8106a ext_resources fdt dev/iir/iir.c optional iir dev/iir/iir_ctrl.c optional iir dev/iir/iir_pci.c optional iir pci @@ -2455,21 +2457,6 @@ dev/mxge/mxge_ethp_z8e.c optional mxge pci dev/mxge/mxge_rss_eth_z8e.c optional mxge pci dev/mxge/mxge_rss_ethp_z8e.c optional mxge pci dev/my/if_my.c optional my -dev/nand/nand.c optional nand -dev/nand/nand_bbt.c optional nand -dev/nand/nand_cdev.c optional nand -dev/nand/nand_generic.c optional nand -dev/nand/nand_geom.c optional nand -dev/nand/nand_id.c optional nand -dev/nand/nandbus.c optional nand -dev/nand/nandbus_if.m optional nand -dev/nand/nand_if.m optional nand -dev/nand/nandsim.c optional nandsim nand -dev/nand/nandsim_chip.c optional nandsim nand -dev/nand/nandsim_ctrl.c optional nandsim nand -dev/nand/nandsim_log.c optional nandsim nand -dev/nand/nandsim_swap.c optional nandsim nand -dev/nand/nfc_if.m optional nand dev/netmap/if_ptnet.c optional netmap inet dev/netmap/netmap.c optional netmap dev/netmap/netmap_bdg.c optional netmap @@ -2766,11 +2753,11 @@ rt2860.fw optional rt2860fw | ralfw \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "rt2860.fw" -dev/random/random_infra.c optional random -dev/random/random_harvestq.c optional random -dev/random/randomdev.c optional random !random_loadable -dev/random/fortuna.c optional random !random_loadable -dev/random/hash.c optional random !random_loadable +dev/random/random_infra.c standard +dev/random/random_harvestq.c standard +dev/random/randomdev.c optional !random_loadable +dev/random/fortuna.c optional !random_loadable +dev/random/hash.c optional !random_loadable dev/rc/rc.c optional rc dev/rccgpio/rccgpio.c optional rccgpio gpio dev/re/if_re.c optional re @@ -3497,20 +3484,6 @@ fs/msdosfs/msdosfs_iconv.c optional msdosfs_iconv fs/msdosfs/msdosfs_lookup.c optional msdosfs fs/msdosfs/msdosfs_vfsops.c optional msdosfs fs/msdosfs/msdosfs_vnops.c optional msdosfs -fs/nandfs/bmap.c optional nandfs -fs/nandfs/nandfs_alloc.c optional nandfs -fs/nandfs/nandfs_bmap.c optional nandfs -fs/nandfs/nandfs_buffer.c optional nandfs -fs/nandfs/nandfs_cleaner.c optional nandfs -fs/nandfs/nandfs_cpfile.c optional nandfs -fs/nandfs/nandfs_dat.c optional nandfs -fs/nandfs/nandfs_dir.c optional nandfs -fs/nandfs/nandfs_ifile.c optional nandfs -fs/nandfs/nandfs_segment.c optional nandfs -fs/nandfs/nandfs_subr.c optional nandfs -fs/nandfs/nandfs_sufile.c optional nandfs -fs/nandfs/nandfs_vfsops.c optional nandfs -fs/nandfs/nandfs_vnops.c optional nandfs fs/nfs/nfs_commonkrpc.c optional nfscl | nfsd fs/nfs/nfs_commonsubs.c optional nfscl | nfsd fs/nfs/nfs_commonport.c optional nfscl | nfsd @@ -3598,7 +3571,7 @@ geom/geom_disk.c standard geom/geom_dump.c standard geom/geom_event.c standard geom/geom_fox.c optional geom_fox -geom/geom_flashmap.c optional fdt cfi | fdt nand | fdt mx25l | mmcsd | fdt n25q | fdt at45d +geom/geom_flashmap.c optional fdt cfi | fdt mx25l | mmcsd | fdt n25q | fdt at45d geom/geom_io.c standard geom/geom_kern.c standard geom/geom_map.c optional geom_map diff --git a/sys/conf/files.amd64 b/sys/conf/files.amd64 index 1d399122c50c..81cd730a5c34 100644 --- a/sys/conf/files.amd64 +++ b/sys/conf/files.amd64 @@ -389,6 +389,9 @@ dev/qlxgbe/ql_isr.c optional qlxgbe pci dev/qlxgbe/ql_misc.c optional qlxgbe pci dev/qlxgbe/ql_os.c optional qlxgbe pci dev/qlxgbe/ql_reset.c optional qlxgbe pci +dev/qlxgbe/ql_fw.c optional qlxgbe pci +dev/qlxgbe/ql_boot.c optional qlxgbe pci +dev/qlxgbe/ql_minidump.c optional qlxgbe pci dev/qlnx/qlnxe/ecore_cxt.c optional qlnxe pci \ compile-with "${LINUXKPI_C}" dev/qlnx/qlnxe/ecore_dbg_fw_funcs.c optional qlnxe pci \ diff --git a/sys/conf/files.arm b/sys/conf/files.arm index 6134b20e1177..8d890144b277 100644 --- a/sys/conf/files.arm +++ b/sys/conf/files.arm @@ -166,6 +166,12 @@ cloudabi32_vdso_blob.o optional compat_cloudabi32 \ clean "cloudabi32_vdso_blob.o" # +# +ukbdmap.h optional ukbd_dflt_keymap \ + compile-with "kbdcontrol -P ${S:S/sys$/share/}/vt/keymaps -P ${S:S/sys$/share/}/syscons/keymaps -L ${UKBD_DFLT_KEYMAP} | sed -e 's/^static keymap_t.* = /static keymap_t key_map = /' -e 's/^static accentmap_t.* = /static accentmap_t accent_map = /' > ukbdmap.h" \ + no-obj no-implicit-rule before-depend \ + clean "ukbdmap.h" + # Annapurna support arm/annapurna/alpine/alpine_ccu.c optional al_ccu fdt arm/annapurna/alpine/alpine_nb_service.c optional al_nb_service fdt diff --git a/sys/conf/files.arm64 b/sys/conf/files.arm64 index f8d9beba599d..b8c023425293 100644 --- a/sys/conf/files.arm64 +++ b/sys/conf/files.arm64 @@ -87,7 +87,7 @@ arm/broadcom/bcm2835/bcm2835_ft5406.c optional evdev bcm2835_ft5406 soc_brcm_bc arm/broadcom/bcm2835/bcm2835_gpio.c optional gpio soc_brcm_bcm2837 fdt arm/broadcom/bcm2835/bcm2835_intr.c optional soc_brcm_bcm2837 fdt arm/broadcom/bcm2835/bcm2835_mbox.c optional soc_brcm_bcm2837 fdt -arm/broadcom/bcm2835/bcm2835_rng.c optional random !random_loadable soc_brcm_bcm2837 fdt +arm/broadcom/bcm2835/bcm2835_rng.c optional !random_loadable soc_brcm_bcm2837 fdt arm/broadcom/bcm2835/bcm2835_sdhci.c optional sdhci soc_brcm_bcm2837 fdt arm/broadcom/bcm2835/bcm2835_sdhost.c optional sdhci soc_brcm_bcm2837 fdt arm/broadcom/bcm2835/bcm2835_spi.c optional bcm2835_spi soc_brcm_bcm2837 fdt diff --git a/sys/conf/files.powerpc b/sys/conf/files.powerpc index cbda69a0d7cf..5383595b1411 100644 --- a/sys/conf/files.powerpc +++ b/sys/conf/files.powerpc @@ -43,8 +43,6 @@ dev/iicbus/max6690.c optional max6690 powermac dev/iicbus/ofw_iicbus.c optional iicbus aim dev/ipmi/ipmi.c optional ipmi dev/ipmi/ipmi_opal.c optional powernv ipmi -dev/nand/nfc_fsl.c optional nand mpc85xx -dev/nand/nfc_rb.c optional nand mpc85xx # Most ofw stuff below is brought in by conf/files for options FDT, but # we always want it, even on non-FDT platforms. dev/fdt/simplebus.c standard @@ -62,7 +60,7 @@ dev/ofw/ofw_standard.c optional aim powerpc dev/ofw/ofw_subr.c standard dev/powermac_nvram/powermac_nvram.c optional powermac_nvram powermac dev/quicc/quicc_bfe_fdt.c optional quicc mpc85xx -dev/random/darn.c optional powerpc64 random !random_loadable +dev/random/darn.c optional powerpc64 !random_loadable dev/scc/scc_bfe_macio.c optional scc powermac dev/sdhci/fsl_sdhci.c optional mpc85xx sdhci dev/sec/sec.c optional sec mpc85xx diff --git a/sys/conf/kern.opts.mk b/sys/conf/kern.opts.mk index 33aa0bcba989..58f125efbd06 100644 --- a/sys/conf/kern.opts.mk +++ b/sys/conf/kern.opts.mk @@ -52,7 +52,6 @@ __DEFAULT_YES_OPTIONS = \ __DEFAULT_NO_OPTIONS = \ EXTRA_TCP_STACKS \ KERNEL_RETPOLINE \ - NAND \ OFED \ RATELIMIT diff --git a/sys/conf/makeLINT.mk b/sys/conf/makeLINT.mk index 52dddf5a97d7..d3a414c14ff6 100644 --- a/sys/conf/makeLINT.mk +++ b/sys/conf/makeLINT.mk @@ -47,6 +47,11 @@ LINT: ${NOTES} ${MAKELINT_SED} echo "nodevice txp" >> ${.TARGET}-NOIP echo "nodevice netmap" >> ${.TARGET}-NOIP .endif +.if ${TARGET} == "arm" + cat ${.TARGET} ${.CURDIR}/NOTES.armv5 > ${.TARGET}-V5 + cat ${.TARGET} ${.CURDIR}/NOTES.armv7 > ${.TARGET}-V7 + rm ${.TARGET} +.endif .if ${TARGET} == "mips" echo "machine ${TARGET} ${TARGET_ARCH}" >> ${.TARGET} .endif diff --git a/sys/conf/options b/sys/conf/options index df394936b9d4..c4c3bb7eed67 100644 --- a/sys/conf/options +++ b/sys/conf/options @@ -256,7 +256,6 @@ FDESCFS opt_dontuse.h FFS opt_dontuse.h FUSEFS opt_dontuse.h MSDOSFS opt_dontuse.h -NANDFS opt_dontuse.h NULLFS opt_dontuse.h PROCFS opt_dontuse.h PSEUDOFS opt_dontuse.h @@ -734,7 +733,6 @@ DEV_PCI opt_pci.h DEV_PF opt_pf.h DEV_PFLOG opt_pf.h DEV_PFSYNC opt_pf.h -DEV_RANDOM opt_global.h DEV_SPLASH opt_splash.h DEV_VLAN opt_vlan.h @@ -863,6 +861,12 @@ AH_INTERRUPT_DEBUGGING opt_ah.h # XXX do not use this for AR9130 AH_AR5416_INTERRUPT_MITIGATION opt_ah.h +# options for the Altera mSGDMA driver (altera_msgdma) +ALTERA_MSGDMA_DESC_STD opt_altera_msgdma.h +ALTERA_MSGDMA_DESC_EXT opt_altera_msgdma.h +ALTERA_MSGDMA_DESC_PF_STD opt_altera_msgdma.h +ALTERA_MSGDMA_DESC_PF_EXT opt_altera_msgdma.h + # options for the Broadcom BCM43xx driver (bwi) BWI_DEBUG opt_bwi.h BWI_DEBUG_VERBOSE opt_bwi.h diff --git a/sys/contrib/ipfilter/netinet/fil.c b/sys/contrib/ipfilter/netinet/fil.c index a0d008dbd2d7..1d142165c341 100644 --- a/sys/contrib/ipfilter/netinet/fil.c +++ b/sys/contrib/ipfilter/netinet/fil.c @@ -1723,29 +1723,31 @@ ipf_pr_ipv4hdr(fin) * calculate the byte offset that it represents. */ off &= IP_MF|IP_OFFMASK; + if (off == 1 && p == IPPROTO_TCP) { + fin->fin_flx |= FI_SHORT; /* RFC 3128 */ + DT1(ipf_fi_tcp_frag_off_1, fr_info_t *, fin); + } if (off != 0) { int morefrag = off & IP_MF; fi->fi_flx |= FI_FRAG; off &= IP_OFFMASK; - if (off != 0) { - fin->fin_flx |= FI_FRAGBODY; - off <<= 3; - if ((off + fin->fin_dlen > 65535) || - (fin->fin_dlen == 0) || - ((morefrag != 0) && ((fin->fin_dlen & 7) != 0))) { - /* - * The length of the packet, starting at its - * offset cannot exceed 65535 (0xffff) as the - * length of an IP packet is only 16 bits. - * - * Any fragment that isn't the last fragment - * must have a length greater than 0 and it - * must be an even multiple of 8. - */ - fi->fi_flx |= FI_BAD; - DT1(ipf_fi_bad_fragbody_gt_65535, fr_info_t *, fin); - } + fin->fin_flx |= FI_FRAGBODY; + off <<= 3; + if ((off + fin->fin_dlen > 65535) || + (fin->fin_dlen == 0) || + ((morefrag != 0) && ((fin->fin_dlen & 7) != 0))) { + /* + * The length of the packet, starting at its + * offset cannot exceed 65535 (0xffff) as the + * length of an IP packet is only 16 bits. + * + * Any fragment that isn't the last fragment + * must have a length greater than 0 and it + * must be an even multiple of 8. + */ + fi->fi_flx |= FI_BAD; + DT1(ipf_fi_bad_fragbody_gt_65535, fr_info_t *, fin); } } fin->fin_off = off; @@ -7472,10 +7474,6 @@ ipf_resolvedest(softc, base, fdp, v) } fdp->fd_ptr = ifp; - if ((ifp != NULL) && (ifp != (void *)-1)) { - fdp->fd_local = ipf_deliverlocal(softc, v, ifp, &fdp->fd_ip6); - } - return errval; } diff --git a/sys/contrib/ipfilter/netinet/ip_compat.h b/sys/contrib/ipfilter/netinet/ip_compat.h index 777495b39aed..75f4d7c116ce 100644 --- a/sys/contrib/ipfilter/netinet/ip_compat.h +++ b/sys/contrib/ipfilter/netinet/ip_compat.h @@ -829,190 +829,9 @@ typedef struct tcpiphdr tcpiphdr_t; #undef IPOPT_AH #define IPOPT_AH 256+IPPROTO_AH -#ifndef TCPOPT_EOL -# define TCPOPT_EOL 0 -#endif -#ifndef TCPOPT_NOP -# define TCPOPT_NOP 1 -#endif -#ifndef TCPOPT_MAXSEG -# define TCPOPT_MAXSEG 2 -#endif -#ifndef TCPOLEN_MAXSEG -# define TCPOLEN_MAXSEG 4 -#endif -#ifndef TCPOPT_WINDOW -# define TCPOPT_WINDOW 3 -#endif -#ifndef TCPOLEN_WINDOW -# define TCPOLEN_WINDOW 3 -#endif -#ifndef TCPOPT_SACK_PERMITTED -# define TCPOPT_SACK_PERMITTED 4 -#endif -#ifndef TCPOLEN_SACK_PERMITTED -# define TCPOLEN_SACK_PERMITTED 2 -#endif -#ifndef TCPOPT_SACK -# define TCPOPT_SACK 5 -#endif -#ifndef TCPOPT_TIMESTAMP -# define TCPOPT_TIMESTAMP 8 -#endif +# define ICMP_UNREACH_ADMIN_PROHIBIT ICMP_UNREACH_FILTER_PROHIB +# define ICMP_UNREACH_FILTER ICMP_UNREACH_FILTER_PROHIB -#ifndef ICMP_MINLEN -# define ICMP_MINLEN 8 -#endif -#ifndef ICMP_ECHOREPLY -# define ICMP_ECHOREPLY 0 -#endif -#ifndef ICMP_UNREACH -# define ICMP_UNREACH 3 -#endif -#ifndef ICMP_UNREACH_NET -# define ICMP_UNREACH_NET 0 -#endif -#ifndef ICMP_UNREACH_HOST -# define ICMP_UNREACH_HOST 1 -#endif -#ifndef ICMP_UNREACH_PROTOCOL -# define ICMP_UNREACH_PROTOCOL 2 -#endif -#ifndef ICMP_UNREACH_PORT -# define ICMP_UNREACH_PORT 3 -#endif -#ifndef ICMP_UNREACH_NEEDFRAG -# define ICMP_UNREACH_NEEDFRAG 4 -#endif -#ifndef ICMP_UNREACH_SRCFAIL -# define ICMP_UNREACH_SRCFAIL 5 -#endif -#ifndef ICMP_UNREACH_NET_UNKNOWN -# define ICMP_UNREACH_NET_UNKNOWN 6 -#endif -#ifndef ICMP_UNREACH_HOST_UNKNOWN -# define ICMP_UNREACH_HOST_UNKNOWN 7 -#endif -#ifndef ICMP_UNREACH_ISOLATED -# define ICMP_UNREACH_ISOLATED 8 -#endif -#ifndef ICMP_UNREACH_NET_PROHIB -# define ICMP_UNREACH_NET_PROHIB 9 -#endif -#ifndef ICMP_UNREACH_HOST_PROHIB -# define ICMP_UNREACH_HOST_PROHIB 10 -#endif -#ifndef ICMP_UNREACH_TOSNET -# define ICMP_UNREACH_TOSNET 11 -#endif -#ifndef ICMP_UNREACH_TOSHOST -# define ICMP_UNREACH_TOSHOST 12 -#endif -#ifndef ICMP_UNREACH_ADMIN_PROHIBIT -# define ICMP_UNREACH_ADMIN_PROHIBIT 13 -#endif -#ifndef ICMP_UNREACH_FILTER -# define ICMP_UNREACH_FILTER 13 -#endif -#ifndef ICMP_UNREACH_HOST_PRECEDENCE -# define ICMP_UNREACH_HOST_PRECEDENCE 14 -#endif -#ifndef ICMP_UNREACH_PRECEDENCE_CUTOFF -# define ICMP_UNREACH_PRECEDENCE_CUTOFF 15 -#endif -#ifndef ICMP_SOURCEQUENCH -# define ICMP_SOURCEQUENCH 4 -#endif -#ifndef ICMP_REDIRECT_NET -# define ICMP_REDIRECT_NET 0 -#endif -#ifndef ICMP_REDIRECT_HOST -# define ICMP_REDIRECT_HOST 1 -#endif -#ifndef ICMP_REDIRECT_TOSNET -# define ICMP_REDIRECT_TOSNET 2 -#endif -#ifndef ICMP_REDIRECT_TOSHOST -# define ICMP_REDIRECT_TOSHOST 3 -#endif -#ifndef ICMP_ALTHOSTADDR -# define ICMP_ALTHOSTADDR 6 -#endif -#ifndef ICMP_TIMXCEED -# define ICMP_TIMXCEED 11 -#endif -#ifndef ICMP_TIMXCEED_INTRANS -# define ICMP_TIMXCEED_INTRANS 0 -#endif -#ifndef ICMP_TIMXCEED_REASS -# define ICMP_TIMXCEED_REASS 1 -#endif -#ifndef ICMP_PARAMPROB -# define ICMP_PARAMPROB 12 -#endif -#ifndef ICMP_PARAMPROB_ERRATPTR -# define ICMP_PARAMPROB_ERRATPTR 0 -#endif -#ifndef ICMP_PARAMPROB_OPTABSENT -# define ICMP_PARAMPROB_OPTABSENT 1 -#endif -#ifndef ICMP_PARAMPROB_LENGTH -# define ICMP_PARAMPROB_LENGTH 2 -#endif -#ifndef ICMP_TSTAMP -# define ICMP_TSTAMP 13 -#endif -#ifndef ICMP_TSTAMPREPLY -# define ICMP_TSTAMPREPLY 14 -#endif -#ifndef ICMP_IREQ -# define ICMP_IREQ 15 -#endif -#ifndef ICMP_IREQREPLY -# define ICMP_IREQREPLY 16 -#endif -#ifndef ICMP_MASKREQ -# define ICMP_MASKREQ 17 -#endif -#ifndef ICMP_MASKREPLY -# define ICMP_MASKREPLY 18 -#endif -#ifndef ICMP_TRACEROUTE -# define ICMP_TRACEROUTE 30 -#endif -#ifndef ICMP_DATACONVERR -# define ICMP_DATACONVERR 31 -#endif -#ifndef ICMP_MOBILE_REDIRECT -# define ICMP_MOBILE_REDIRECT 32 -#endif -#ifndef ICMP_IPV6_WHEREAREYOU -# define ICMP_IPV6_WHEREAREYOU 33 -#endif -#ifndef ICMP_IPV6_IAMHERE -# define ICMP_IPV6_IAMHERE 34 -#endif -#ifndef ICMP_MOBILE_REGREQUEST -# define ICMP_MOBILE_REGREQUEST 35 -#endif -#ifndef ICMP_MOBILE_REGREPLY -# define ICMP_MOBILE_REGREPLY 36 -#endif -#ifndef ICMP_SKIP -# define ICMP_SKIP 39 -#endif -#ifndef ICMP_PHOTURIS -# define ICMP_PHOTURIS 40 -#endif -#ifndef ICMP_PHOTURIS_UNKNOWN_INDEX -# define ICMP_PHOTURIS_UNKNOWN_INDEX 1 -#endif -#ifndef ICMP_PHOTURIS_AUTH_FAILED -# define ICMP_PHOTURIS_AUTH_FAILED 2 -#endif -#ifndef ICMP_PHOTURIS_DECRYPT_FAILED -# define ICMP_PHOTURIS_DECRYPT_FAILED 3 -#endif #ifndef IPVERSION # define IPVERSION 4 #endif diff --git a/sys/contrib/ipfilter/netinet/ip_fil.h b/sys/contrib/ipfilter/netinet/ip_fil.h index f3185c6458d7..032cf0dea853 100644 --- a/sys/contrib/ipfilter/netinet/ip_fil.h +++ b/sys/contrib/ipfilter/netinet/ip_fil.h @@ -560,7 +560,6 @@ typedef struct frdest { addrfamily_t fd_addr; fr_dtypes_t fd_type; int fd_name; - int fd_local; } frdest_t; #define fd_ip6 fd_addr.adf_addr diff --git a/sys/ddb/db_ps.c b/sys/ddb/db_ps.c index 72bf0edd9161..82e50e0ca85d 100644 --- a/sys/ddb/db_ps.c +++ b/sys/ddb/db_ps.c @@ -481,7 +481,7 @@ DB_SHOW_COMMAND(proc, db_show_proc) dump_args(p); db_printf("\n"); } - db_printf(" repear: %p reapsubtree: %d\n", + db_printf(" reaper: %p reapsubtree: %d\n", p->p_reaper, p->p_reapsubtree); db_printf(" sigparent: %d\n", p->p_sigparent); db_printf(" vmspace: %p\n", p->p_vmspace); diff --git a/sys/dev/ahci/ahci.c b/sys/dev/ahci/ahci.c index 4a17fb535498..435661107e95 100644 --- a/sys/dev/ahci/ahci.c +++ b/sys/dev/ahci/ahci.c @@ -186,6 +186,7 @@ ahci_attach(device_t dev) ctlr->ccc = 0; resource_int_value(device_get_name(dev), device_get_unit(dev), "ccc", &ctlr->ccc); + mtx_init(&ctlr->ch_mtx, "AHCI channels lock", NULL, MTX_DEF); /* Setup our own memory management for channels. */ ctlr->sc_iomem.rm_start = rman_get_start(ctlr->r_mem); @@ -379,6 +380,7 @@ ahci_detach(device_t dev) /* Free memory. */ rman_fini(&ctlr->sc_iomem); ahci_free_mem(dev); + mtx_destroy(&ctlr->ch_mtx); return (0); } @@ -666,6 +668,50 @@ ahci_get_dma_tag(device_t dev, device_t child) return (ctlr->dma_tag); } +void +ahci_attached(device_t dev, struct ahci_channel *ch) +{ + struct ahci_controller *ctlr = device_get_softc(dev); + + mtx_lock(&ctlr->ch_mtx); + ctlr->ch[ch->unit] = ch; + mtx_unlock(&ctlr->ch_mtx); +} + +void +ahci_detached(device_t dev, struct ahci_channel *ch) +{ + struct ahci_controller *ctlr = device_get_softc(dev); + + mtx_lock(&ctlr->ch_mtx); + mtx_lock(&ch->mtx); + ctlr->ch[ch->unit] = NULL; + mtx_unlock(&ch->mtx); + mtx_unlock(&ctlr->ch_mtx); +} + +struct ahci_channel * +ahci_getch(device_t dev, int n) +{ + struct ahci_controller *ctlr = device_get_softc(dev); + struct ahci_channel *ch; + + KASSERT(n >= 0 && n < AHCI_MAX_PORTS, ("Bad channel number %d", n)); + mtx_lock(&ctlr->ch_mtx); + ch = ctlr->ch[n]; + if (ch != NULL) + mtx_lock(&ch->mtx); + mtx_unlock(&ctlr->ch_mtx); + return (ch); +} + +void +ahci_putch(struct ahci_channel *ch) +{ + + mtx_unlock(&ch->mtx); +} + static int ahci_ch_probe(device_t dev) { @@ -824,6 +870,7 @@ ahci_ch_attach(device_t dev) ahci_ch_pm, ch); } mtx_unlock(&ch->mtx); + ahci_attached(device_get_parent(dev), ch); ctx = device_get_sysctl_ctx(dev); tree = device_get_sysctl_tree(dev); SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "disable_phy", @@ -849,6 +896,7 @@ ahci_ch_detach(device_t dev) { struct ahci_channel *ch = device_get_softc(dev); + ahci_detached(device_get_parent(dev), ch); mtx_lock(&ch->mtx); xpt_async(AC_LOST_DEVICE, ch->path, NULL); /* Forget about reset. */ diff --git a/sys/dev/ahci/ahci.h b/sys/dev/ahci/ahci.h index fc53d346f17f..27b3970dadfc 100644 --- a/sys/dev/ahci/ahci.h +++ b/sys/dev/ahci/ahci.h @@ -524,6 +524,8 @@ struct ahci_controller { } interrupt[AHCI_MAX_PORTS]; void (*ch_start)(struct ahci_channel *); int dma_coherent; /* DMA is cache-coherent */ + struct mtx ch_mtx; /* Lock for attached channels */ + struct ahci_channel *ch[AHCI_MAX_PORTS]; /* Attached channels */ }; enum ahci_err_type { @@ -654,5 +656,11 @@ int ahci_ctlr_reset(device_t dev); int ahci_ctlr_setup(device_t dev); void ahci_free_mem(device_t dev); +/* Functions to allow AHCI EM to access other channels. */ +void ahci_attached(device_t dev, struct ahci_channel *ch); +void ahci_detached(device_t dev, struct ahci_channel *ch); +struct ahci_channel * ahci_getch(device_t dev, int n); +void ahci_putch(struct ahci_channel *ch); + extern devclass_t ahci_devclass; diff --git a/sys/dev/ahci/ahciem.c b/sys/dev/ahci/ahciem.c index 9bb4d9717763..a6f22fac5639 100644 --- a/sys/dev/ahci/ahciem.c +++ b/sys/dev/ahci/ahciem.c @@ -294,14 +294,14 @@ ahci_em_setleds(device_t dev, int c) enc = device_get_softc(dev); val = 0; - if (enc->status[c][2] & 0x80) /* Activity */ + if (enc->status[c][2] & SESCTL_RQSACT) /* Activity */ val |= (1 << 0); - if (enc->status[c][2] & SESCTL_RQSID) /* Identification */ + if (enc->status[c][1] & SESCTL_RQSRR) /* Rebuild */ + val |= (1 << 6) | (1 << 3); + else if (enc->status[c][2] & SESCTL_RQSID) /* Identification */ val |= (1 << 3); else if (enc->status[c][3] & SESCTL_RQSFLT) /* Fault */ val |= (1 << 6); - else if (enc->status[c][1] & 0x02) /* Rebuild */ - val |= (1 << 6) | (1 << 3); timeout = 10000; while (ATA_INL(enc->r_memc, 0) & (AHCI_EM_TM | AHCI_EM_RST) && @@ -366,9 +366,12 @@ static void ahci_em_emulate_ses_on_led(device_t dev, union ccb *ccb) { struct ahci_enclosure *enc; + struct ahci_channel *ch; struct ses_status_page *page; struct ses_status_array_dev_slot *ads, *ads0; struct ses_elm_desc_hdr *elmd; + struct ses_elm_addlstatus_eip_hdr *elma; + struct ses_elm_ata_hdr *elmb; uint8_t *buf; int i; @@ -391,7 +394,7 @@ ahci_em_emulate_ses_on_led(device_t dev, union ccb *ccb) strncpy(&buf[3], device_get_nameunit(dev), 7); strncpy(&buf[10], "AHCI ", SID_VENDOR_SIZE); strncpy(&buf[18], "SGPIO Enclosure ", SID_PRODUCT_SIZE); - strncpy(&buf[34], "1.00", SID_REVISION_SIZE); + strncpy(&buf[34], "2.00", SID_REVISION_SIZE); strncpy(&buf[39], "0001", 4); strncpy(&buf[43], "S-E-S ", 6); strncpy(&buf[49], "2.00", 4); @@ -403,14 +406,15 @@ ahci_em_emulate_ses_on_led(device_t dev, union ccb *ccb) page = (struct ses_status_page *)buf; if (ccb->ataio.cmd.lba_low == 0x02 && ccb->ataio.cmd.features == 0x00 && - ccb->ataio.cmd.sector_count >= 2) { + ccb->ataio.cmd.sector_count >= 3) { bzero(buf, ccb->ataio.dxfer_len); page->hdr.page_code = 0; - scsi_ulto2b(4, page->hdr.length); - buf[4] = 0; - buf[5] = 1; - buf[6] = 2; - buf[7] = 7; + scsi_ulto2b(5, page->hdr.length); + buf[4] = 0x00; + buf[5] = 0x01; + buf[6] = 0x02; + buf[7] = 0x07; + buf[8] = 0x0a; ccb->ccb_h.status = CAM_REQ_CMP; goto out; } @@ -418,26 +422,30 @@ ahci_em_emulate_ses_on_led(device_t dev, union ccb *ccb) /* SEMB RECEIVE DIAGNOSTIC RESULT (1) */ if (ccb->ataio.cmd.lba_low == 0x02 && ccb->ataio.cmd.features == 0x01 && - ccb->ataio.cmd.sector_count >= 13) { + ccb->ataio.cmd.sector_count >= 16) { struct ses_enc_desc *ed; struct ses_elm_type_desc *td; bzero(buf, ccb->ataio.dxfer_len); page->hdr.page_code = 0x01; - scsi_ulto2b(4 + 4 + 36 + 4, page->hdr.length); + scsi_ulto2b(4 + sizeof(*ed) + sizeof(*td) + 11, + page->hdr.length); ed = (struct ses_enc_desc *)&buf[8]; ed->byte0 = 0x11; ed->subenc_id = 0; ed->num_types = 1; ed->length = 36; + ed->logical_id[0] = 0x30; /* NAA Locally Assigned. */ + strncpy(&ed->logical_id[1], device_get_nameunit(dev), 7); strncpy(ed->vendor_id, "AHCI ", SID_VENDOR_SIZE); strncpy(ed->product_id, "SGPIO Enclosure ", SID_PRODUCT_SIZE); - strncpy(ed->product_rev, " ", SID_REVISION_SIZE); + strncpy(ed->product_rev, "2.00", SID_REVISION_SIZE); td = (struct ses_elm_type_desc *)ses_enc_desc_next(ed); td->etype_elm_type = 0x17; td->etype_maxelt = enc->channels; td->etype_subenc = 0; - td->etype_txt_len = 0; + td->etype_txt_len = 11; + snprintf((char *)(td + 1), 12, "Drive Slots"); ccb->ccb_h.status = CAM_REQ_CMP; goto out; } @@ -453,10 +461,22 @@ ahci_em_emulate_ses_on_led(device_t dev, union ccb *ccb) for (i = 0; i < enc->channels; i++) { ads = &page->elements[i + 1].array_dev_slot; memcpy(ads, enc->status[i], 4); - ads->common.bytes[0] |= - (enc->ichannels & (1 << i)) ? - SES_OBJSTAT_UNKNOWN : - SES_OBJSTAT_NOTINSTALLED; + ch = ahci_getch(device_get_parent(dev), i); + if (ch == NULL) { + ads->common.bytes[0] |= SES_OBJSTAT_UNKNOWN; + continue; + } + if (ch->pm_present) + ads->common.bytes[0] |= SES_OBJSTAT_UNKNOWN; + else if (ch->devices) + ads->common.bytes[0] |= SES_OBJSTAT_OK; + else if (ch->disablephy) + ads->common.bytes[0] |= SES_OBJSTAT_NOTAVAIL; + else + ads->common.bytes[0] |= SES_OBJSTAT_NOTINSTALLED; + if (ch->disablephy) + ads->common.bytes[3] |= SESCTL_DEVOFF; + ahci_putch(ch); } ccb->ccb_h.status = CAM_REQ_CMP; goto out; @@ -471,21 +491,21 @@ ahci_em_emulate_ses_on_led(device_t dev, union ccb *ccb) ads = &page->elements[i + 1].array_dev_slot; if (ads->common.bytes[0] & SESCTL_CSEL) { enc->status[i][0] = 0; - enc->status[i][1] = - ads->bytes[0] & 0x02; - enc->status[i][2] = - ads->bytes[1] & (0x80 | SESCTL_RQSID); - enc->status[i][3] = - ads->bytes[2] & SESCTL_RQSFLT; + enc->status[i][1] = ads->bytes[0] & + SESCTL_RQSRR; + enc->status[i][2] = ads->bytes[1] & + (SESCTL_RQSACT | SESCTL_RQSID); + enc->status[i][3] = ads->bytes[2] & + SESCTL_RQSFLT; ahci_em_setleds(dev, i); } else if (ads0->common.bytes[0] & SESCTL_CSEL) { enc->status[i][0] = 0; - enc->status[i][1] = - ads0->bytes[0] & 0x02; - enc->status[i][2] = - ads0->bytes[1] & (0x80 | SESCTL_RQSID); - enc->status[i][3] = - ads0->bytes[2] & SESCTL_RQSFLT; + enc->status[i][1] = ads0->bytes[0] & + SESCTL_RQSRR; + enc->status[i][2] = ads0->bytes[1] & + (SESCTL_RQSACT | SESCTL_RQSID); + enc->status[i][3] = ads0->bytes[2] & + SESCTL_RQSFLT; ahci_em_setleds(dev, i); } } @@ -496,15 +516,48 @@ ahci_em_emulate_ses_on_led(device_t dev, union ccb *ccb) /* SEMB RECEIVE DIAGNOSTIC RESULT (7) */ if (ccb->ataio.cmd.lba_low == 0x02 && ccb->ataio.cmd.features == 0x07 && - ccb->ataio.cmd.sector_count >= (3 + 3 * enc->channels)) { + ccb->ataio.cmd.sector_count >= (6 + 3 * enc->channels)) { bzero(buf, ccb->ataio.dxfer_len); page->hdr.page_code = 0x07; - scsi_ulto2b(4 + 4 + 12 * enc->channels, + scsi_ulto2b(4 + 15 + 11 * enc->channels, page->hdr.length); + elmd = (struct ses_elm_desc_hdr *)&buf[8]; + scsi_ulto2b(11, elmd->length); + snprintf((char *)(elmd + 1), 12, "Drive Slots"); + for (i = 0; i < enc->channels; i++) { + elmd = (struct ses_elm_desc_hdr *)&buf[8 + 15 + 11 * i]; + scsi_ulto2b(7, elmd->length); + snprintf((char *)(elmd + 1), 8, "Slot %02d", i); + } + ccb->ccb_h.status = CAM_REQ_CMP; + goto out; + } + + /* SEMB RECEIVE DIAGNOSTIC RESULT (a) */ + if (ccb->ataio.cmd.lba_low == 0x02 && + ccb->ataio.cmd.features == 0x0a && + ccb->ataio.cmd.sector_count >= (2 + 3 * enc->channels)) { + bzero(buf, ccb->ataio.dxfer_len); + page->hdr.page_code = 0x0a; + scsi_ulto2b(4 + (sizeof(*elma) + sizeof(*elmb)) * enc->channels, page->hdr.length); for (i = 0; i < enc->channels; i++) { - elmd = (struct ses_elm_desc_hdr *)&buf[8 + 4 + 12 * i]; - scsi_ulto2b(8, elmd->length); - snprintf((char *)(elmd + 1), 9, "SLOT %03d", i); + elma = (struct ses_elm_addlstatus_eip_hdr *)&buf[ + 8 + (sizeof(*elma) + sizeof(*elmb)) * i]; + elma->base.byte0 = 0x10 | SPSP_PROTO_ATA; + elma->base.length = 2 + sizeof(*elmb); + elma->byte2 = 0x01; + elma->element_index = 1 + i; + ch = ahci_getch(device_get_parent(dev), i); + if (ch == NULL) { + elma->base.byte0 |= 0x80; + continue; + } + if (ch->devices == 0 || ch->pm_present) + elma->base.byte0 |= 0x80; + elmb = (struct ses_elm_ata_hdr *)(elma + 1); + scsi_ulto4b(cam_sim_path(ch->sim), elmb->bus); + scsi_ulto4b(0, elmb->target); + ahci_putch(ch); } ccb->ccb_h.status = CAM_REQ_CMP; goto out; diff --git a/sys/dev/altera/msgdma/msgdma.c b/sys/dev/altera/msgdma/msgdma.c index c60c7ccfe352..9acb313f91f5 100644 --- a/sys/dev/altera/msgdma/msgdma.c +++ b/sys/dev/altera/msgdma/msgdma.c @@ -60,6 +60,7 @@ __FBSDID("$FreeBSD$"); #include <dev/xdma/xdma.h> #include "xdma_if.h" +#include "opt_altera_msgdma.h" #include <dev/altera/msgdma/msgdma.h> @@ -470,8 +471,8 @@ msgdma_channel_submit_sg(device_t dev, struct xdma_channel *xchan, struct msgdma_channel *chan; struct msgdma_desc *desc; struct msgdma_softc *sc; - uint32_t src_addr_lo; - uint32_t dst_addr_lo; + bus_addr_t src_addr_lo; + bus_addr_t dst_addr_lo; uint32_t len; uint32_t tmp; int i; @@ -481,14 +482,18 @@ msgdma_channel_submit_sg(device_t dev, struct xdma_channel *xchan, chan = (struct msgdma_channel *)xchan->chan; for (i = 0; i < sg_n; i++) { - src_addr_lo = (uint32_t)sg[i].src_addr; - dst_addr_lo = (uint32_t)sg[i].dst_addr; + src_addr_lo = sg[i].src_addr; + dst_addr_lo = sg[i].dst_addr; len = (uint32_t)sg[i].len; dprintf("%s: src %x dst %x len %d\n", __func__, src_addr_lo, dst_addr_lo, len); desc = chan->descs[chan->idx_head]; +#if defined(ALTERA_MSGDMA_DESC_EXT) || defined(ALTERA_MSGDMA_DESC_PF_EXT) + desc->read_hi = htole32(src_addr_lo >> 32); + desc->write_hi = htole32(dst_addr_lo >> 32); +#endif desc->read_lo = htole32(src_addr_lo); desc->write_lo = htole32(dst_addr_lo); desc->length = htole32(len); diff --git a/sys/dev/altera/msgdma/msgdma.h b/sys/dev/altera/msgdma/msgdma.h index e10a233902a2..498fb93d86bf 100644 --- a/sys/dev/altera/msgdma/msgdma.h +++ b/sys/dev/altera/msgdma/msgdma.h @@ -30,6 +30,8 @@ * $FreeBSD$ */ +#include "opt_altera_msgdma.h" + /* Altera mSGDMA registers. */ #define DMA_STATUS 0x00 #define STATUS_RESETTING (1 << 6) @@ -75,15 +77,36 @@ #define WRITE4_DESC(_sc, _reg, _val) \ bus_space_write_4(_sc->bst_d, _sc->bsh_d, _reg, htole32(_val)) -/* Prefetcher-disabled descriptor format. */ -struct msgdma_desc_nonpf { - uint32_t src_addr; - uint32_t dst_addr; +#if defined(ALTERA_MSGDMA_DESC_STD) + +/* Standard descriptor format with prefetcher disabled. */ +struct msgdma_desc { + uint32_t read_lo; + uint32_t write_lo; uint32_t length; uint32_t control; }; -/* Prefetcher-enabled descriptor format. */ +#elif defined(ALTERA_MSGDMA_DESC_EXT) + +/* Extended descriptor format with prefetcher disabled. */ +struct msgdma_desc { + uint32_t read_lo; + uint32_t write_lo; + uint32_t length; + uint8_t write_burst; + uint8_t read_burst; + uint16_t seq_num; + uint16_t write_stride; + uint16_t read_stride; + uint32_t read_hi; + uint32_t write_hi; + uint32_t control; +}; + +#elif defined(ALTERA_MSGDMA_DESC_PF_STD) + +/* Standard descriptor format with prefetcher enabled. */ struct msgdma_desc { uint32_t read_lo; uint32_t write_lo; @@ -94,3 +117,34 @@ struct msgdma_desc { uint32_t reserved; uint32_t control; }; + +#elif defined(ALTERA_MSGDMA_DESC_PF_EXT) + +/* Extended descriptor format with prefetcher enabled. */ +struct msgdma_desc { + uint32_t read_lo; + uint32_t write_lo; + uint32_t length; + uint32_t next; + uint32_t transferred; + uint32_t status; + uint32_t reserved; + uint8_t write_burst; + uint8_t read_burst; + uint16_t seq_num; + uint16_t write_stride; + uint16_t read_stride; + uint32_t read_hi; + uint32_t write_hi; + uint32_t next_hi; + uint32_t reserved1; + uint32_t reserved2; + uint32_t reserved3; + uint32_t control; +}; + +#else + +#error "mSGDMA descriptor format (kernel option) is not set." + +#endif diff --git a/sys/dev/cxgbe/tom/t4_cpl_io.c b/sys/dev/cxgbe/tom/t4_cpl_io.c index 27ef745c764c..fd4f376d8676 100644 --- a/sys/dev/cxgbe/tom/t4_cpl_io.c +++ b/sys/dev/cxgbe/tom/t4_cpl_io.c @@ -74,7 +74,7 @@ __FBSDID("$FreeBSD$"); #include "tom/t4_tom.h" static void t4_aiotx_cancel(struct kaiocb *job); -static void t4_aiotx_queue_toep(struct toepcb *toep); +static void t4_aiotx_queue_toep(struct socket *so, struct toepcb *toep); static size_t aiotx_mbuf_pgoff(struct mbuf *m) @@ -785,7 +785,7 @@ t4_push_frames(struct adapter *sc, struct toepcb *toep, int drop) if (sowwakeup) { if (!TAILQ_EMPTY( &toep->aiotx_jobq)) - t4_aiotx_queue_toep( + t4_aiotx_queue_toep(so, toep); sowwakeup_locked(so); } else @@ -829,7 +829,7 @@ t4_push_frames(struct adapter *sc, struct toepcb *toep, int drop) } if (sowwakeup) { if (!TAILQ_EMPTY(&toep->aiotx_jobq)) - t4_aiotx_queue_toep(toep); + t4_aiotx_queue_toep(so, toep); sowwakeup_locked(so); } else SOCKBUF_UNLOCK(sb); @@ -1821,7 +1821,7 @@ do_fw4_ack(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m) tls_ofld->sb_off -= plen; } if (!TAILQ_EMPTY(&toep->aiotx_jobq)) - t4_aiotx_queue_toep(toep); + t4_aiotx_queue_toep(so, toep); sowwakeup_locked(so); /* unlocks so_snd */ } SOCKBUF_UNLOCK_ASSERT(sb); @@ -2195,10 +2195,10 @@ static void t4_aiotx_task(void *context, int pending) { struct toepcb *toep = context; - struct inpcb *inp = toep->inp; - struct socket *so = inp->inp_socket; + struct socket *so; struct kaiocb *job; + so = toep->aiotx_so; CURVNET_SET(toep->vnet); SOCKBUF_LOCK(&so->so_snd); while (!TAILQ_EMPTY(&toep->aiotx_jobq) && sowriteable(so)) { @@ -2209,15 +2209,17 @@ t4_aiotx_task(void *context, int pending) t4_aiotx_process_job(toep, so, job); } - toep->aiotx_task_active = false; + toep->aiotx_so = NULL; SOCKBUF_UNLOCK(&so->so_snd); CURVNET_RESTORE(); free_toepcb(toep); + SOCK_LOCK(so); + sorele(so); } static void -t4_aiotx_queue_toep(struct toepcb *toep) +t4_aiotx_queue_toep(struct socket *so, struct toepcb *toep) { SOCKBUF_LOCK_ASSERT(&toep->inp->inp_socket->so_snd); @@ -2225,9 +2227,10 @@ t4_aiotx_queue_toep(struct toepcb *toep) CTR3(KTR_CXGBE, "%s: queueing aiotx task for tid %d, active = %s", __func__, toep->tid, toep->aiotx_task_active ? "true" : "false"); #endif - if (toep->aiotx_task_active) + if (toep->aiotx_so != NULL) return; - toep->aiotx_task_active = true; + soref(so); + toep->aiotx_so = so; hold_toepcb(toep); soaio_enqueue(&toep->aiotx_task); } @@ -2284,7 +2287,7 @@ t4_aio_queue_aiotx(struct socket *so, struct kaiocb *job) panic("new job was cancelled"); TAILQ_INSERT_TAIL(&toep->aiotx_jobq, job, list); if (sowriteable(so)) - t4_aiotx_queue_toep(toep); + t4_aiotx_queue_toep(so, toep); SOCKBUF_UNLOCK(&so->so_snd); return (0); } diff --git a/sys/dev/cxgbe/tom/t4_ddp.c b/sys/dev/cxgbe/tom/t4_ddp.c index 47062e634bbf..f3f03e0faa2c 100644 --- a/sys/dev/cxgbe/tom/t4_ddp.c +++ b/sys/dev/cxgbe/tom/t4_ddp.c @@ -220,7 +220,7 @@ release_ddp_resources(struct toepcb *toep) int i; DDP_LOCK(toep); - toep->flags |= DDP_DEAD; + toep->ddp.flags |= DDP_DEAD; for (i = 0; i < nitems(toep->ddp.db); i++) { free_ddp_buffer(toep->td, &toep->ddp.db[i]); } diff --git a/sys/dev/cxgbe/tom/t4_tom.h b/sys/dev/cxgbe/tom/t4_tom.h index db9e50cd39e1..d4ff4490abad 100644 --- a/sys/dev/cxgbe/tom/t4_tom.h +++ b/sys/dev/cxgbe/tom/t4_tom.h @@ -194,7 +194,7 @@ struct toepcb { TAILQ_HEAD(, kaiocb) aiotx_jobq; struct task aiotx_task; - bool aiotx_task_active; + struct socket *aiotx_so; /* Tx software descriptor */ uint8_t txsd_total; diff --git a/sys/dev/drm2/ttm/ttm_bo_vm.c b/sys/dev/drm2/ttm/ttm_bo_vm.c index 6f7184857ce6..43d027fc5cd9 100644 --- a/sys/dev/drm2/ttm/ttm_bo_vm.c +++ b/sys/dev/drm2/ttm/ttm_bo_vm.c @@ -115,7 +115,7 @@ ttm_bo_vm_fault(vm_object_t vm_obj, vm_ooffset_t offset, vm_object_pip_add(vm_obj, 1); if (*mres != NULL) { vm_page_lock(*mres); - vm_page_remove(*mres); + (void)vm_page_remove(*mres); vm_page_unlock(*mres); } retry: diff --git a/sys/dev/gpio/gpiobus.c b/sys/dev/gpio/gpiobus.c index 133b72185d7f..64fadb382a02 100644 --- a/sys/dev/gpio/gpiobus.c +++ b/sys/dev/gpio/gpiobus.c @@ -255,13 +255,6 @@ gpiobus_alloc_ivars(struct gpiobus_ivar *devi) M_NOWAIT | M_ZERO); if (devi->pins == NULL) return (ENOMEM); - devi->flags = malloc(sizeof(uint32_t) * devi->npins, M_DEVBUF, - M_NOWAIT | M_ZERO); - if (devi->flags == NULL) { - free(devi->pins, M_DEVBUF); - return (ENOMEM); - } - return (0); } @@ -269,14 +262,11 @@ void gpiobus_free_ivars(struct gpiobus_ivar *devi) { - if (devi->flags) { - free(devi->flags, M_DEVBUF); - devi->flags = NULL; - } if (devi->pins) { free(devi->pins, M_DEVBUF); devi->pins = NULL; } + devi->npins = 0; } int @@ -326,6 +316,34 @@ gpiobus_release_pin(device_t bus, uint32_t pin) } static int +gpiobus_acquire_child_pins(device_t dev, device_t child) +{ + struct gpiobus_ivar *devi = GPIOBUS_IVAR(child); + int i; + + for (i = 0; i < devi->npins; i++) { + /* Reserve the GPIO pin. */ + if (gpiobus_acquire_pin(dev, devi->pins[i]) != 0) { + device_printf(child, "cannot acquire pin %d\n", + devi->pins[i]); + while (--i >= 0) { + (void)gpiobus_release_pin(dev, + devi->pins[i]); + } + gpiobus_free_ivars(devi); + return (EBUSY); + } + } + for (i = 0; i < devi->npins; i++) { + /* Use the child name as pin name. */ + GPIOBUS_PIN_SETNAME(dev, devi->pins[i], + device_get_nameunit(child)); + + } + return (0); +} + +static int gpiobus_parse_pins(struct gpiobus_softc *sc, device_t child, int mask) { struct gpiobus_ivar *devi = GPIOBUS_IVAR(child); @@ -349,17 +367,66 @@ gpiobus_parse_pins(struct gpiobus_softc *sc, device_t child, int mask) for (i = 0; i < 32; i++) { if ((mask & (1 << i)) == 0) continue; - /* Reserve the GPIO pin. */ - if (gpiobus_acquire_pin(sc->sc_busdev, i) != 0) { - gpiobus_free_ivars(devi); - return (EINVAL); - } devi->pins[npins++] = i; - /* Use the child name as pin name. */ - GPIOBUS_PIN_SETNAME(sc->sc_busdev, i, - device_get_nameunit(child)); } + if (gpiobus_acquire_child_pins(sc->sc_busdev, child) != 0) + return (EINVAL); + return (0); +} + +static int +gpiobus_parse_pin_list(struct gpiobus_softc *sc, device_t child, + const char *pins) +{ + struct gpiobus_ivar *devi = GPIOBUS_IVAR(child); + const char *p; + char *endp; + unsigned long pin; + int i, npins; + + npins = 0; + p = pins; + for (;;) { + pin = strtoul(p, &endp, 0); + if (endp == p) + break; + npins++; + if (*endp == '\0') + break; + p = endp + 1; + } + + if (*endp != '\0') { + device_printf(child, "garbage in the pin list: %s\n", endp); + return (EINVAL); + } + if (npins == 0) { + device_printf(child, "empty pin list\n"); + return (EINVAL); + } + + devi->npins = npins; + if (gpiobus_alloc_ivars(devi) != 0) { + device_printf(child, "cannot allocate device ivars\n"); + return (EINVAL); + } + + i = 0; + p = pins; + for (;;) { + pin = strtoul(p, &endp, 0); + + devi->pins[i] = pin; + + if (*endp == '\0') + break; + i++; + p = endp + 1; + } + + if (gpiobus_acquire_child_pins(sc->sc_busdev, child) != 0) + return (EINVAL); return (0); } @@ -539,15 +606,26 @@ gpiobus_hinted_child(device_t bus, const char *dname, int dunit) struct gpiobus_softc *sc = GPIOBUS_SOFTC(bus); struct gpiobus_ivar *devi; device_t child; - int irq, pins; + const char *pins; + int irq, pinmask; child = BUS_ADD_CHILD(bus, 0, dname, dunit); devi = GPIOBUS_IVAR(child); - resource_int_value(dname, dunit, "pins", &pins); - if (gpiobus_parse_pins(sc, child, pins)) { - resource_list_free(&devi->rl); - free(devi, M_DEVBUF); - device_delete_child(bus, child); + if (resource_int_value(dname, dunit, "pins", &pinmask) == 0) { + if (gpiobus_parse_pins(sc, child, pinmask)) { + resource_list_free(&devi->rl); + free(devi, M_DEVBUF); + device_delete_child(bus, child); + return; + } + } + else if (resource_string_value(dname, dunit, "pin_list", &pins) == 0) { + if (gpiobus_parse_pin_list(sc, child, pins)) { + resource_list_free(&devi->rl); + free(devi, M_DEVBUF); + device_delete_child(bus, child); + return; + } } if (resource_int_value(dname, dunit, "irq", &irq) == 0) { if (bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1) != 0) @@ -574,6 +652,61 @@ gpiobus_set_resource(device_t dev, device_t child, int type, int rid, return (0); } +static int +gpiobus_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) +{ + struct gpiobus_ivar *devi; + + devi = GPIOBUS_IVAR(child); + switch (which) { + case GPIOBUS_IVAR_NPINS: + *result = devi->npins; + break; + case GPIOBUS_IVAR_PINS: + /* Children do not ever need to directly examine this. */ + return (ENOTSUP); + default: + return (ENOENT); + } + + return (0); +} + +static int +gpiobus_write_ivar(device_t dev, device_t child, int which, uintptr_t value) +{ + struct gpiobus_ivar *devi; + const uint32_t *ptr; + int i; + + devi = GPIOBUS_IVAR(child); + switch (which) { + case GPIOBUS_IVAR_NPINS: + /* GPIO ivars are set once. */ + if (devi->npins != 0) { + return (EBUSY); + } + devi->npins = value; + if (gpiobus_alloc_ivars(devi) != 0) { + device_printf(child, "cannot allocate device ivars\n"); + devi->npins = 0; + return (ENOMEM); + } + break; + case GPIOBUS_IVAR_PINS: + ptr = (const uint32_t *)value; + for (i = 0; i < devi->npins; i++) + devi->pins[i] = ptr[i]; + if (gpiobus_acquire_child_pins(dev, child) != 0) + return (EBUSY); + break; + default: + return (ENOENT); + } + + return (0); +} + static struct resource * gpiobus_alloc_resource(device_t bus, device_t child, int type, int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) @@ -833,6 +966,8 @@ static device_method_t gpiobus_methods[] = { DEVMETHOD(bus_child_pnpinfo_str, gpiobus_child_pnpinfo_str), DEVMETHOD(bus_child_location_str, gpiobus_child_location_str), DEVMETHOD(bus_hinted_child, gpiobus_hinted_child), + DEVMETHOD(bus_read_ivar, gpiobus_read_ivar), + DEVMETHOD(bus_write_ivar, gpiobus_write_ivar), /* GPIO protocol */ DEVMETHOD(gpiobus_acquire_bus, gpiobus_acquire_bus), diff --git a/sys/dev/gpio/gpiobusvar.h b/sys/dev/gpio/gpiobusvar.h index 5aa363a23daf..08f0ccf904d0 100644 --- a/sys/dev/gpio/gpiobusvar.h +++ b/sys/dev/gpio/gpiobusvar.h @@ -107,10 +107,22 @@ struct gpiobus_ivar { struct resource_list rl; /* isr resource list */ uint32_t npins; /* pins total */ - uint32_t *flags; /* pins flags */ uint32_t *pins; /* pins map */ }; +enum gpiobus_ivars { + GPIOBUS_IVAR_NPINS = 10500, + GPIOBUS_IVAR_PINS, +}; + +#define GPIOBUS_ACCESSOR(var, ivar, type) \ + __BUS_ACCESSOR(gpiobus, var, GPIOBUS, ivar, type) + +GPIOBUS_ACCESSOR(npins, NPINS, uint32_t) +GPIOBUS_ACCESSOR(pins, PINS, const uint32_t *) + +#undef GPIOBUS_ACCESSOR + #ifdef FDT struct ofw_gpiobus_devinfo { struct gpiobus_ivar opd_dinfo; diff --git a/sys/dev/gpio/ofw_gpiobus.c b/sys/dev/gpio/ofw_gpiobus.c index 698701c8769d..3c48c62feed3 100644 --- a/sys/dev/gpio/ofw_gpiobus.c +++ b/sys/dev/gpio/ofw_gpiobus.c @@ -321,10 +321,8 @@ ofw_gpiobus_setup_devinfo(device_t bus, device_t child, phandle_t node) ofw_gpiobus_destroy_devinfo(bus, dinfo); return (NULL); } - for (i = 0; i < devi->npins; i++) { - devi->flags[i] = pins[i].flags; + for (i = 0; i < devi->npins; i++) devi->pins[i] = pins[i].pin; - } free(pins, M_DEVBUF); /* Parse the interrupt resources. */ if (ofw_bus_intr_to_rl(bus, node, &dinfo->opd_dinfo.rl, NULL) != 0) { diff --git a/sys/dev/iicbus/ad7418.c b/sys/dev/iicbus/ad7418.c index 457b3626c8ef..034597768790 100644 --- a/sys/dev/iicbus/ad7418.c +++ b/sys/dev/iicbus/ad7418.c @@ -35,18 +35,9 @@ __FBSDID("$FreeBSD$"); #include <sys/lock.h> #include <sys/module.h> #include <sys/bus.h> -#include <sys/resource.h> -#include <sys/rman.h> #include <sys/sysctl.h> #include <sys/sx.h> -#include <machine/bus.h> -#include <machine/cpu.h> -#include <machine/cpufunc.h> -#include <machine/frame.h> -#include <machine/resource.h> -#include <machine/intr.h> - #include <dev/iicbus/iiconf.h> #include "iicbus_if.h" diff --git a/sys/dev/nand/nand.c b/sys/dev/nand/nand.c deleted file mode 100644 index 6997ef7f8a0d..000000000000 --- a/sys/dev/nand/nand.c +++ /dev/null @@ -1,826 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/socket.h> -#include <sys/malloc.h> -#include <sys/module.h> -#include <sys/bus.h> -#include <sys/lock.h> -#include <sys/mutex.h> -#include <sys/callout.h> -#include <sys/sysctl.h> - -#include <dev/nand/nand.h> -#include <dev/nand/nandbus.h> -#include <dev/nand/nand_ecc_pos.h> -#include "nfc_if.h" -#include "nand_if.h" -#include "nandbus_if.h" -#include <machine/stdarg.h> - -#define NAND_RESET_DELAY 1000 /* tRST */ -#define NAND_ERASE_DELAY 3000 /* tBERS */ -#define NAND_PROG_DELAY 700 /* tPROG */ -#define NAND_READ_DELAY 50 /* tR */ - -#define BIT0(x) ((x) & 0x1) -#define BIT1(x) (BIT0(x >> 1)) -#define BIT2(x) (BIT0(x >> 2)) -#define BIT3(x) (BIT0(x >> 3)) -#define BIT4(x) (BIT0(x >> 4)) -#define BIT5(x) (BIT0(x >> 5)) -#define BIT6(x) (BIT0(x >> 6)) -#define BIT7(x) (BIT0(x >> 7)) - -#define SOFTECC_SIZE 256 -#define SOFTECC_BYTES 3 - -int nand_debug_flag = 0; -SYSCTL_INT(_debug, OID_AUTO, nand_debug, CTLFLAG_RWTUN, &nand_debug_flag, 0, - "NAND subsystem debug flag"); - -MALLOC_DEFINE(M_NAND, "NAND", "NAND dynamic data"); - -static void calculate_ecc(const uint8_t *, uint8_t *); -static int correct_ecc(uint8_t *, uint8_t *, uint8_t *); - -void -nand_debug(int level, const char *fmt, ...) -{ - va_list ap; - - if (!(nand_debug_flag & level)) - return; - va_start(ap, fmt); - vprintf(fmt, ap); - va_end(ap); - printf("\n"); -} - -void -nand_init(struct nand_softc *nand, device_t dev, int ecc_mode, - int ecc_bytes, int ecc_size, uint16_t *eccposition, char *cdev_name) -{ - - nand->ecc.eccmode = ecc_mode; - nand->chip_cdev_name = cdev_name; - - if (ecc_mode == NAND_ECC_SOFT) { - nand->ecc.eccbytes = SOFTECC_BYTES; - nand->ecc.eccsize = SOFTECC_SIZE; - } else if (ecc_mode != NAND_ECC_NONE) { - nand->ecc.eccbytes = ecc_bytes; - nand->ecc.eccsize = ecc_size; - if (eccposition) - nand->ecc.eccpositions = eccposition; - } -} - -void -nand_onfi_set_params(struct nand_chip *chip, struct onfi_chip_params *params) -{ - struct chip_geom *cg; - - cg = &chip->chip_geom; - - init_chip_geom(cg, params->luns, params->blocks_per_lun, - params->pages_per_block, params->bytes_per_page, - params->spare_bytes_per_page); - chip->t_bers = params->t_bers; - chip->t_prog = params->t_prog; - chip->t_r = params->t_r; - chip->t_ccs = params->t_ccs; - - if (params->features & ONFI_FEAT_16BIT) - chip->flags |= NAND_16_BIT; -} - -void -nand_set_params(struct nand_chip *chip, struct nand_params *params) -{ - struct chip_geom *cg; - uint32_t blocks_per_chip; - - cg = &chip->chip_geom; - blocks_per_chip = (params->chip_size << 20) / - (params->page_size * params->pages_per_block); - - init_chip_geom(cg, 1, blocks_per_chip, - params->pages_per_block, params->page_size, - params->oob_size); - - chip->t_bers = NAND_ERASE_DELAY; - chip->t_prog = NAND_PROG_DELAY; - chip->t_r = NAND_READ_DELAY; - chip->t_ccs = 0; - - if (params->flags & NAND_16_BIT) - chip->flags |= NAND_16_BIT; -} - -int -nand_init_stat(struct nand_chip *chip) -{ - struct block_stat *blk_stat; - struct page_stat *pg_stat; - struct chip_geom *cg; - uint32_t blks, pgs; - - cg = &chip->chip_geom; - blks = cg->blks_per_lun * cg->luns; - blk_stat = malloc(sizeof(struct block_stat) * blks, M_NAND, - M_WAITOK | M_ZERO); - if (!blk_stat) - return (ENOMEM); - - pgs = blks * cg->pgs_per_blk; - pg_stat = malloc(sizeof(struct page_stat) * pgs, M_NAND, - M_WAITOK | M_ZERO); - if (!pg_stat) { - free(blk_stat, M_NAND); - return (ENOMEM); - } - - chip->blk_stat = blk_stat; - chip->pg_stat = pg_stat; - - return (0); -} - -void -nand_destroy_stat(struct nand_chip *chip) -{ - - free(chip->pg_stat, M_NAND); - free(chip->blk_stat, M_NAND); -} - -int -init_chip_geom(struct chip_geom *cg, uint32_t luns, uint32_t blks_per_lun, - uint32_t pgs_per_blk, uint32_t pg_size, uint32_t oob_size) -{ - int shift; - - if (!cg) - return (-1); - - cg->luns = luns; - cg->blks_per_lun = blks_per_lun; - cg->blks_per_chip = blks_per_lun * luns; - cg->pgs_per_blk = pgs_per_blk; - - cg->page_size = pg_size; - cg->oob_size = oob_size; - cg->block_size = cg->page_size * cg->pgs_per_blk; - cg->chip_size = cg->block_size * cg->blks_per_chip; - - shift = fls(cg->pgs_per_blk - 1); - cg->pg_mask = (1 << shift) - 1; - cg->blk_shift = shift; - - if (cg->blks_per_lun > 0) { - shift = fls(cg->blks_per_lun - 1); - cg->blk_mask = ((1 << shift) - 1) << cg->blk_shift; - } else { - shift = 0; - cg->blk_mask = 0; - } - - cg->lun_shift = shift + cg->blk_shift; - shift = fls(cg->luns - 1); - cg->lun_mask = ((1 << shift) - 1) << cg->lun_shift; - - nand_debug(NDBG_NAND, "Masks: lun 0x%x blk 0x%x page 0x%x\n" - "Shifts: lun %d blk %d", - cg->lun_mask, cg->blk_mask, cg->pg_mask, - cg->lun_shift, cg->blk_shift); - - return (0); -} - -int -nand_row_to_blkpg(struct chip_geom *cg, uint32_t row, uint32_t *lun, - uint32_t *blk, uint32_t *pg) -{ - - if (!cg || !lun || !blk || !pg) - return (-1); - - if (row & ~(cg->lun_mask | cg->blk_mask | cg->pg_mask)) { - nand_debug(NDBG_NAND,"Address out of bounds\n"); - return (-1); - } - - *lun = (row & cg->lun_mask) >> cg->lun_shift; - *blk = (row & cg->blk_mask) >> cg->blk_shift; - *pg = (row & cg->pg_mask); - - nand_debug(NDBG_NAND,"address %x-%x-%x\n", *lun, *blk, *pg); - - return (0); -} - -int page_to_row(struct chip_geom *cg, uint32_t page, uint32_t *row) -{ - uint32_t lun, block, pg_in_blk; - - if (!cg || !row) - return (-1); - - block = page / cg->pgs_per_blk; - pg_in_blk = page % cg->pgs_per_blk; - - lun = block / cg->blks_per_lun; - block = block % cg->blks_per_lun; - - *row = (lun << cg->lun_shift) & cg->lun_mask; - *row |= ((block << cg->blk_shift) & cg->blk_mask); - *row |= (pg_in_blk & cg->pg_mask); - - return (0); -} - -int -nand_check_page_boundary(struct nand_chip *chip, uint32_t page) -{ - struct chip_geom* cg; - - cg = &chip->chip_geom; - if (page >= (cg->pgs_per_blk * cg->blks_per_lun * cg->luns)) { - nand_debug(NDBG_GEN,"%s: page number too big %#x\n", - __func__, page); - return (1); - } - - return (0); -} - -void -nand_get_chip_param(struct nand_chip *chip, struct chip_param_io *param) -{ - struct chip_geom *cg; - - cg = &chip->chip_geom; - param->page_size = cg->page_size; - param->oob_size = cg->oob_size; - - param->blocks = cg->blks_per_lun * cg->luns; - param->pages_per_block = cg->pgs_per_blk; -} - -static uint16_t * -default_software_ecc_positions(struct nand_chip *chip) -{ - /* If positions have been set already, use them. */ - if (chip->nand->ecc.eccpositions) - return (chip->nand->ecc.eccpositions); - - /* - * XXX Note that the following logic isn't really sufficient, especially - * in the ONFI case where the number of ECC bytes can be dictated by - * values in the parameters page, and that could lead to needing more - * byte positions than exist within the tables of software-ecc defaults. - */ - if (chip->chip_geom.oob_size >= 128) - return (default_software_ecc_positions_128); - if (chip->chip_geom.oob_size >= 64) - return (default_software_ecc_positions_64); - else if (chip->chip_geom.oob_size >= 16) - return (default_software_ecc_positions_16); - - return (NULL); -} - -static void -calculate_ecc(const uint8_t *buf, uint8_t *ecc) -{ - uint8_t p8, byte; - int i; - - memset(ecc, 0, 3); - - for (i = 0; i < 256; i++) { - byte = buf[i]; - ecc[0] ^= (BIT0(byte) ^ BIT2(byte) ^ BIT4(byte) ^ - BIT6(byte)) << 2; - ecc[0] ^= (BIT1(byte) ^ BIT3(byte) ^ BIT5(byte) ^ - BIT7(byte)) << 3; - ecc[0] ^= (BIT0(byte) ^ BIT1(byte) ^ BIT4(byte) ^ - BIT5(byte)) << 4; - ecc[0] ^= (BIT2(byte) ^ BIT3(byte) ^ BIT6(byte) ^ - BIT7(byte)) << 5; - ecc[0] ^= (BIT0(byte) ^ BIT1(byte) ^ BIT2(byte) ^ - BIT3(byte)) << 6; - ecc[0] ^= (BIT4(byte) ^ BIT5(byte) ^ BIT6(byte) ^ - BIT7(byte)) << 7; - - p8 = BIT0(byte) ^ BIT1(byte) ^ BIT2(byte) ^ - BIT3(byte) ^ BIT4(byte) ^ BIT5(byte) ^ BIT6(byte) ^ - BIT7(byte); - - if (p8) { - ecc[2] ^= (0x1 << BIT0(i)); - ecc[2] ^= (0x4 << BIT1(i)); - ecc[2] ^= (0x10 << BIT2(i)); - ecc[2] ^= (0x40 << BIT3(i)); - - ecc[1] ^= (0x1 << BIT4(i)); - ecc[1] ^= (0x4 << BIT5(i)); - ecc[1] ^= (0x10 << BIT6(i)); - ecc[1] ^= (0x40 << BIT7(i)); - } - } - ecc[0] = ~ecc[0]; - ecc[1] = ~ecc[1]; - ecc[2] = ~ecc[2]; - ecc[0] |= 3; -} - -static int -correct_ecc(uint8_t *buf, uint8_t *calc_ecc, uint8_t *read_ecc) -{ - uint8_t ecc0, ecc1, ecc2, onesnum, bit, byte; - uint16_t addr = 0; - - ecc0 = calc_ecc[0] ^ read_ecc[0]; - ecc1 = calc_ecc[1] ^ read_ecc[1]; - ecc2 = calc_ecc[2] ^ read_ecc[2]; - - if (!ecc0 && !ecc1 && !ecc2) - return (ECC_OK); - - addr = BIT3(ecc0) | (BIT5(ecc0) << 1) | (BIT7(ecc0) << 2); - addr |= (BIT1(ecc2) << 3) | (BIT3(ecc2) << 4) | - (BIT5(ecc2) << 5) | (BIT7(ecc2) << 6); - addr |= (BIT1(ecc1) << 7) | (BIT3(ecc1) << 8) | - (BIT5(ecc1) << 9) | (BIT7(ecc1) << 10); - - onesnum = 0; - while (ecc0 || ecc1 || ecc2) { - if (ecc0 & 1) - onesnum++; - if (ecc1 & 1) - onesnum++; - if (ecc2 & 1) - onesnum++; - - ecc0 >>= 1; - ecc1 >>= 1; - ecc2 >>= 1; - } - - if (onesnum == 11) { - /* Correctable error */ - bit = addr & 7; - byte = addr >> 3; - buf[byte] ^= (1 << bit); - return (ECC_CORRECTABLE); - } else if (onesnum == 1) { - /* ECC error */ - return (ECC_ERROR_ECC); - } else { - /* Uncorrectable error */ - return (ECC_UNCORRECTABLE); - } - - return (0); -} - -int -nand_softecc_get(device_t dev, uint8_t *buf, int pagesize, uint8_t *ecc) -{ - int steps = pagesize / SOFTECC_SIZE; - int i = 0, j = 0; - - for (; i < (steps * SOFTECC_BYTES); - i += SOFTECC_BYTES, j += SOFTECC_SIZE) { - calculate_ecc(&buf[j], &ecc[i]); - } - - return (0); -} - -int -nand_softecc_correct(device_t dev, uint8_t *buf, int pagesize, - uint8_t *readecc, uint8_t *calcecc) -{ - int steps = pagesize / SOFTECC_SIZE; - int i = 0, j = 0, ret = 0; - - for (i = 0; i < (steps * SOFTECC_BYTES); - i += SOFTECC_BYTES, j += SOFTECC_SIZE) { - ret += correct_ecc(&buf[j], &calcecc[i], &readecc[i]); - if (ret < 0) - return (ret); - } - - return (ret); -} - -static int -offset_to_page(struct chip_geom *cg, uint32_t offset) -{ - - return (offset / cg->page_size); -} - -int -nand_read_pages(struct nand_chip *chip, uint32_t offset, void *buf, - uint32_t len) -{ - struct chip_geom *cg; - struct nand_ecc_data *eccd; - struct page_stat *pg_stat; - device_t nandbus; - void *oob = NULL; - uint8_t *ptr; - uint16_t *eccpos = NULL; - uint32_t page, num, steps = 0; - int i, retval = 0, needwrite; - - nand_debug(NDBG_NAND,"%p read page %x[%x]", chip, offset, len); - cg = &chip->chip_geom; - eccd = &chip->nand->ecc; - page = offset_to_page(cg, offset); - num = len / cg->page_size; - - if (eccd->eccmode != NAND_ECC_NONE) { - steps = cg->page_size / eccd->eccsize; - eccpos = default_software_ecc_positions(chip); - oob = malloc(cg->oob_size, M_NAND, M_WAITOK); - } - - nandbus = device_get_parent(chip->dev); - NANDBUS_LOCK(nandbus); - NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num); - - ptr = (uint8_t *)buf; - while (num--) { - pg_stat = &(chip->pg_stat[page]); - - if (NAND_READ_PAGE(chip->dev, page, ptr, cg->page_size, 0)) { - retval = ENXIO; - break; - } - - if (eccd->eccmode != NAND_ECC_NONE) { - if (NAND_GET_ECC(chip->dev, ptr, eccd->ecccalculated, - &needwrite)) { - retval = ENXIO; - break; - } - nand_debug(NDBG_ECC,"%s: ECC calculated:", - __func__); - if (nand_debug_flag & NDBG_ECC) - for (i = 0; i < (eccd->eccbytes * steps); i++) - printf("%x ", eccd->ecccalculated[i]); - - nand_debug(NDBG_ECC,"\n"); - - if (NAND_READ_OOB(chip->dev, page, oob, cg->oob_size, - 0)) { - retval = ENXIO; - break; - } - for (i = 0; i < (eccd->eccbytes * steps); i++) - eccd->eccread[i] = ((uint8_t *)oob)[eccpos[i]]; - - nand_debug(NDBG_ECC,"%s: ECC read:", __func__); - if (nand_debug_flag & NDBG_ECC) - for (i = 0; i < (eccd->eccbytes * steps); i++) - printf("%x ", eccd->eccread[i]); - nand_debug(NDBG_ECC,"\n"); - - retval = NAND_CORRECT_ECC(chip->dev, ptr, eccd->eccread, - eccd->ecccalculated); - - nand_debug(NDBG_ECC, "NAND_CORRECT_ECC() returned %d", - retval); - - if (retval == 0) - pg_stat->ecc_stat.ecc_succeded++; - else if (retval > 0) { - pg_stat->ecc_stat.ecc_corrected += retval; - retval = ECC_CORRECTABLE; - } else { - pg_stat->ecc_stat.ecc_failed++; - break; - } - } - - pg_stat->page_read++; - page++; - ptr += cg->page_size; - } - - NANDBUS_UNLOCK(nandbus); - - if (oob) - free(oob, M_NAND); - - return (retval); -} - -int -nand_read_pages_raw(struct nand_chip *chip, uint32_t offset, void *buf, - uint32_t len) -{ - struct chip_geom *cg; - device_t nandbus; - uint8_t *ptr; - uint32_t page, num, end, begin = 0, begin_off; - int retval = 0; - - cg = &chip->chip_geom; - page = offset_to_page(cg, offset); - begin_off = offset - page * cg->page_size; - if (begin_off) { - begin = cg->page_size - begin_off; - len -= begin; - } - num = len / cg->page_size; - end = len % cg->page_size; - - nandbus = device_get_parent(chip->dev); - NANDBUS_LOCK(nandbus); - NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num); - - ptr = (uint8_t *)buf; - if (begin_off) { - if (NAND_READ_PAGE(chip->dev, page, ptr, begin, begin_off)) { - NANDBUS_UNLOCK(nandbus); - return (ENXIO); - } - - page++; - ptr += begin; - } - - while (num--) { - if (NAND_READ_PAGE(chip->dev, page, ptr, cg->page_size, 0)) { - NANDBUS_UNLOCK(nandbus); - return (ENXIO); - } - - page++; - ptr += cg->page_size; - } - - if (end) - if (NAND_READ_PAGE(chip->dev, page, ptr, end, 0)) { - NANDBUS_UNLOCK(nandbus); - return (ENXIO); - } - - NANDBUS_UNLOCK(nandbus); - - return (retval); -} - - -int -nand_prog_pages(struct nand_chip *chip, uint32_t offset, uint8_t *buf, - uint32_t len) -{ - struct chip_geom *cg; - struct page_stat *pg_stat; - struct nand_ecc_data *eccd; - device_t nandbus; - uint32_t page, num; - uint8_t *oob = NULL; - uint16_t *eccpos = NULL; - int steps = 0, i, needwrite, err = 0; - - nand_debug(NDBG_NAND,"%p prog page %x[%x]", chip, offset, len); - - eccd = &chip->nand->ecc; - cg = &chip->chip_geom; - page = offset_to_page(cg, offset); - num = len / cg->page_size; - - if (eccd->eccmode != NAND_ECC_NONE) { - steps = cg->page_size / eccd->eccsize; - oob = malloc(cg->oob_size, M_NAND, M_WAITOK); - eccpos = default_software_ecc_positions(chip); - } - - nandbus = device_get_parent(chip->dev); - NANDBUS_LOCK(nandbus); - NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num); - - while (num--) { - if (NAND_PROGRAM_PAGE(chip->dev, page, buf, cg->page_size, 0)) { - err = ENXIO; - break; - } - - if (eccd->eccmode != NAND_ECC_NONE) { - if (NAND_GET_ECC(chip->dev, buf, &eccd->ecccalculated, - &needwrite)) { - err = ENXIO; - break; - } - nand_debug(NDBG_ECC,"ECC calculated:"); - if (nand_debug_flag & NDBG_ECC) - for (i = 0; i < (eccd->eccbytes * steps); i++) - printf("%x ", eccd->ecccalculated[i]); - - nand_debug(NDBG_ECC,"\n"); - - if (needwrite) { - if (NAND_READ_OOB(chip->dev, page, oob, cg->oob_size, - 0)) { - err = ENXIO; - break; - } - - for (i = 0; i < (eccd->eccbytes * steps); i++) - oob[eccpos[i]] = eccd->ecccalculated[i]; - - if (NAND_PROGRAM_OOB(chip->dev, page, oob, - cg->oob_size, 0)) { - err = ENXIO; - break; - } - } - } - - pg_stat = &(chip->pg_stat[page]); - pg_stat->page_written++; - - page++; - buf += cg->page_size; - } - - NANDBUS_UNLOCK(nandbus); - - if (oob) - free(oob, M_NAND); - - return (err); -} - -int -nand_prog_pages_raw(struct nand_chip *chip, uint32_t offset, void *buf, - uint32_t len) -{ - struct chip_geom *cg; - device_t nandbus; - uint8_t *ptr; - uint32_t page, num, end, begin = 0, begin_off; - int retval = 0; - - cg = &chip->chip_geom; - page = offset_to_page(cg, offset); - begin_off = offset - page * cg->page_size; - if (begin_off) { - begin = cg->page_size - begin_off; - len -= begin; - } - num = len / cg->page_size; - end = len % cg->page_size; - - nandbus = device_get_parent(chip->dev); - NANDBUS_LOCK(nandbus); - NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num); - - ptr = (uint8_t *)buf; - if (begin_off) { - if (NAND_PROGRAM_PAGE(chip->dev, page, ptr, begin, begin_off)) { - NANDBUS_UNLOCK(nandbus); - return (ENXIO); - } - - page++; - ptr += begin; - } - - while (num--) { - if (NAND_PROGRAM_PAGE(chip->dev, page, ptr, cg->page_size, 0)) { - NANDBUS_UNLOCK(nandbus); - return (ENXIO); - } - - page++; - ptr += cg->page_size; - } - - if (end) - retval = NAND_PROGRAM_PAGE(chip->dev, page, ptr, end, 0); - - NANDBUS_UNLOCK(nandbus); - - return (retval); -} - -int -nand_read_oob(struct nand_chip *chip, uint32_t page, void *buf, - uint32_t len) -{ - device_t nandbus; - int retval = 0; - - nandbus = device_get_parent(chip->dev); - NANDBUS_LOCK(nandbus); - NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num); - - retval = NAND_READ_OOB(chip->dev, page, buf, len, 0); - - NANDBUS_UNLOCK(nandbus); - - return (retval); -} - - -int -nand_prog_oob(struct nand_chip *chip, uint32_t page, void *buf, - uint32_t len) -{ - device_t nandbus; - int retval = 0; - - nandbus = device_get_parent(chip->dev); - NANDBUS_LOCK(nandbus); - NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num); - - retval = NAND_PROGRAM_OOB(chip->dev, page, buf, len, 0); - - NANDBUS_UNLOCK(nandbus); - - return (retval); -} - -int -nand_erase_blocks(struct nand_chip *chip, off_t offset, size_t len) -{ - device_t nandbus; - struct chip_geom *cg; - uint32_t block, num_blocks; - int err = 0; - - cg = &chip->chip_geom; - if ((offset % cg->block_size) || (len % cg->block_size)) - return (EINVAL); - - block = offset / cg->block_size; - num_blocks = len / cg->block_size; - nand_debug(NDBG_NAND,"%p erase blocks %d[%d]", chip, block, num_blocks); - - nandbus = device_get_parent(chip->dev); - NANDBUS_LOCK(nandbus); - NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num); - - while (num_blocks--) { - if (!nand_check_bad_block(chip, block)) { - if (NAND_ERASE_BLOCK(chip->dev, block)) { - nand_debug(NDBG_NAND,"%p erase blocks %d error", - chip, block); - nand_mark_bad_block(chip, block); - err = ENXIO; - } - } else - err = ENXIO; - - block++; - } - - NANDBUS_UNLOCK(nandbus); - - if (err) - nand_update_bbt(chip); - - return (err); -} - -MODULE_VERSION(nand, 1); diff --git a/sys/dev/nand/nand.h b/sys/dev/nand/nand.h deleted file mode 100644 index 06902601b8d0..000000000000 --- a/sys/dev/nand/nand.h +++ /dev/null @@ -1,415 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _DEV_NAND_H_ -#define _DEV_NAND_H_ - -#include <sys/bus.h> -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/lock.h> -#include <sys/sx.h> -#include <sys/taskqueue.h> -#include <sys/queue.h> -#include <sys/bio.h> -#include <sys/lock.h> -#include <sys/mutex.h> -#include <sys/malloc.h> - -#include <dev/nand/nand_dev.h> - -MALLOC_DECLARE(M_NAND); - -/* Read commands */ -#define NAND_CMD_READ 0x00 -#define NAND_CMD_CHNG_READ_COL 0x05 -#define NAND_CMD_READ_END 0x30 -#define NAND_CMD_READ_CACHE 0x31 -#define NAND_CMD_READ_CPBK 0x35 -#define NAND_CMD_READ_CACHE_END 0x3F -#define NAND_CMD_CHNG_READ_COL_END 0xE0 - -/* Erase commands */ -#define NAND_CMD_ERASE 0x60 -#define NAND_CMD_ERASE_END 0xD0 -#define NAND_CMD_ERASE_INTLV 0xD1 - -/* Program commands */ -#define NAND_CMD_PROG 0x80 -#define NAND_CMD_CHNG_WRITE_COL 0x85 -#define NAND_CMD_PROG_END 0x10 -#define NAND_CMD_PROG_INTLV 0x11 -#define NAND_CMD_PROG_CACHE 0x15 - -/* Misc commands */ -#define NAND_CMD_STATUS 0x70 -#define NAND_CMD_STATUS_ENH 0x78 -#define NAND_CMD_READ_ID 0x90 -#define NAND_CMD_READ_PARAMETER 0xec -#define NAND_CMD_READ_UNIQUE_ID 0xed -#define NAND_CMD_GET_FEATURE 0xee -#define NAND_CMD_SET_FEATURE 0xef - -/* Reset commands */ -#define NAND_CMD_SYNCH_RESET 0xfc -#define NAND_CMD_RESET 0xff - -/* Small page flash commands */ -#define NAND_CMD_SMALLA 0x00 -#define NAND_CMD_SMALLB 0x01 -#define NAND_CMD_SMALLOOB 0x50 - -#define NAND_STATUS_FAIL 0x1 -#define NAND_STATUS_FAILC 0x2 -#define NAND_STATUS_ARDY 0x20 -#define NAND_STATUS_RDY 0x40 -#define NAND_STATUS_WP 0x80 - -#define NAND_LP_OOB_COLUMN_START 0x800 -#define NAND_LP_OOBSZ 0x40 -#define NAND_SP_OOB_COLUMN_START 0x200 -#define NAND_SP_OOBSZ 0x10 - -#define PAGE_PARAM_LENGTH 0x100 -#define PAGE_PARAMETER_DEF 0x0 -#define PAGE_PARAMETER_RED_1 0x100 -#define PAGE_PARAMETER_RED_2 0x200 - -#define ONFI_SIG_ADDR 0x20 - -#define NAND_MAX_CHIPS 0x4 -#define NAND_MAX_OOBSZ 512 -#define NAND_MAX_PAGESZ 16384 - -#define NAND_SMALL_PAGE_SIZE 0x200 - -#define NAND_16_BIT 0x00000001 - -#define NAND_ECC_NONE 0x0 -#define NAND_ECC_SOFT 0x1 -#define NAND_ECC_FULLHW 0x2 -#define NAND_ECC_PARTHW 0x4 -#define NAND_ECC_MODE_MASK 0x7 - -#define ECC_OK 0 -#define ECC_CORRECTABLE 1 -#define ECC_ERROR_ECC (-1) -#define ECC_UNCORRECTABLE (-2) - -#define NAND_MAN_SAMSUNG 0xec -#define NAND_MAN_HYNIX 0xad -#define NAND_MAN_STMICRO 0x20 -#define NAND_MAN_MICRON 0x2c - -struct nand_id { - uint8_t man_id; - uint8_t dev_id; -}; - -struct nand_params { - struct nand_id id; - char *name; - uint32_t chip_size; - uint32_t page_size; - uint32_t oob_size; - uint32_t pages_per_block; - uint32_t flags; -}; - -/* nand debug levels */ -#define NDBG_NAND 0x01 -#define NDBG_CDEV 0x02 -#define NDBG_GEN 0x04 -#define NDBG_GEOM 0x08 -#define NDBG_BUS 0x10 -#define NDBG_SIM 0x20 -#define NDBG_CTRL 0x40 -#define NDBG_DRV 0x80 -#define NDBG_ECC 0x100 - -/* nand_debug_function */ -void nand_debug(int level, const char *fmt, ...); -extern int nand_debug_flag; - -/* ONFI features bit*/ -#define ONFI_FEAT_16BIT 0x01 -#define ONFI_FEAT_MULT_LUN 0x02 -#define ONFI_FEAT_INTLV_OPS 0x04 -#define ONFI_FEAT_CPBK_RESTRICT 0x08 -#define ONFI_FEAT_SRC_SYNCH 0x10 - -/* ONFI optional commands bits */ -#define ONFI_OPTCOM_PROG_CACHE 0x01 -#define ONFI_OPTCOM_READ_CACHE 0x02 -#define ONFI_OPTCOM_GETSET_FEAT 0x04 -#define ONFI_OPTCOM_STATUS_ENH 0x08 -#define ONFI_OPTCOM_COPYBACK 0x10 -#define ONFI_OPTCOM_UNIQUE_ID 0x20 - - -/* Layout of parameter page is defined in ONFI */ -struct onfi_params { - char signature[4]; - uint16_t rev; - uint16_t features; - uint16_t optional_commands; - uint8_t primary_advanced_command; - uint8_t res1; - uint16_t extended_parameter_page_length; - uint8_t parameter_page_count; - uint8_t res2[17]; - char manufacturer_name[12]; - char device_model[20]; - uint8_t manufacturer_id; - uint8_t manufacture_date_yy; - uint8_t manufacture_date_ww; - uint8_t res3[13]; - uint32_t bytes_per_page; - uint16_t spare_bytes_per_page; - uint32_t bytes_per_partial_page; - uint16_t spare_bytes_per_partial_page; - uint32_t pages_per_block; - uint32_t blocks_per_lun; - uint8_t luns; - uint8_t address_cycles; - uint8_t bits_per_cell; - uint16_t max_bad_block_per_lun; - uint16_t block_endurance; - uint8_t guaranteed_valid_blocks; - uint16_t valid_block_endurance; - uint8_t programs_per_page; - uint8_t partial_prog_attr; - uint8_t bits_of_ecc; - uint8_t interleaved_addr_bits; - uint8_t interleaved_oper_attr; - uint8_t eznand_support; - uint8_t res4[12]; - uint8_t pin_capacitance; - uint16_t asynch_timing_mode_support; - uint16_t asynch_prog_cache_timing_mode_support; - uint16_t t_prog; /* us, max page program time */ - uint16_t t_bers; /* us, max block erase time */ - uint16_t t_r; /* us, max page read time */ - uint16_t t_ccs; /* ns, min change column setup time */ - uint16_t source_synch_timing_mode_support; - uint8_t source_synch_feat; - uint16_t clk_input_capacitance; - uint16_t io_capacitance; - uint16_t input_capacitance; - uint8_t input_capacitance_max; - uint8_t driver_strength_support; - uint16_t t_r_interleaved; - uint16_t t_adl; - uint16_t t_r_eznand; - uint8_t nv_ddr2_features; - uint8_t nv_ddr2_warmup_cycles; - uint8_t res5[4]; - uint16_t vendor_rev; - uint8_t vendor_spec[88]; - uint16_t crc; -}__attribute__((packed)); -CTASSERT(sizeof(struct onfi_params) == 256); - -struct onfi_chip_params { - uint32_t blocks_per_lun; - uint32_t pages_per_block; - uint32_t bytes_per_page; - uint32_t spare_bytes_per_page; - uint16_t t_bers; - uint16_t t_prog; - uint16_t t_r; - uint16_t t_ccs; - uint16_t features; - uint8_t address_cycles; - uint8_t luns; -}; - -struct nand_ecc_data { - int eccsize; /* Number of data bytes per ECC step */ - int eccmode; - int eccbytes; /* Number of ECC bytes per step */ - - uint16_t *eccpositions; /* Positions of ecc bytes */ - uint8_t ecccalculated[NAND_MAX_OOBSZ]; - uint8_t eccread[NAND_MAX_OOBSZ]; -}; - -struct ecc_stat { - uint32_t ecc_succeded; - uint32_t ecc_corrected; - uint32_t ecc_failed; -}; - -struct page_stat { - struct ecc_stat ecc_stat; - uint32_t page_read; - uint32_t page_raw_read; - uint32_t page_written; - uint32_t page_raw_written; -}; - -struct block_stat { - uint32_t block_erased; -}; - -struct chip_geom { - uint32_t chip_size; - uint32_t block_size; - uint32_t page_size; - uint32_t oob_size; - - uint32_t luns; - uint32_t blks_per_lun; - uint32_t blks_per_chip; - uint32_t pgs_per_blk; - - uint32_t pg_mask; - uint32_t blk_mask; - uint32_t lun_mask; - uint8_t blk_shift; - uint8_t lun_shift; -}; - -struct nand_chip { - device_t dev; - struct nand_id id; - struct chip_geom chip_geom; - - uint16_t t_prog; /* us, max page program time */ - uint16_t t_bers; /* us, max block erase time */ - uint16_t t_r; /* us, max page read time */ - uint16_t t_ccs; /* ns, min change column setup time */ - uint8_t num; - uint8_t flags; - - struct page_stat *pg_stat; - struct block_stat *blk_stat; - struct nand_softc *nand; - struct nand_bbt *bbt; - struct nand_ops *ops; - struct cdev *cdev; - - struct disk *ndisk; - struct disk *rdisk; - struct bio_queue_head bioq; /* bio queue */ - struct mtx qlock; /* bioq lock */ - struct taskqueue *tq; /* private task queue for i/o request */ - struct task iotask; /* i/o processing */ - -}; - -struct nand_softc { - uint8_t flags; - - char *chip_cdev_name; - struct nand_ecc_data ecc; -}; - -/* NAND ops */ -int nand_erase_blocks(struct nand_chip *chip, off_t offset, size_t len); -int nand_prog_pages(struct nand_chip *chip, uint32_t offset, uint8_t *buf, - uint32_t len); -int nand_read_pages(struct nand_chip *chip, uint32_t offset, void *buf, - uint32_t len); -int nand_read_pages_raw(struct nand_chip *chip, uint32_t offset, void *buf, - uint32_t len); -int nand_prog_pages_raw(struct nand_chip *chip, uint32_t offset, void *buf, - uint32_t len); -int nand_read_oob(struct nand_chip *chip, uint32_t page, void *buf, - uint32_t len); -int nand_prog_oob(struct nand_chip *chip, uint32_t page, void *buf, - uint32_t len); - -int nand_select_cs(device_t dev, uint8_t cs); - -int nand_read_parameter(struct nand_softc *nand, struct onfi_params *param); -int nand_synch_reset(struct nand_softc *nand); -int nand_chng_read_col(device_t dev, uint32_t col, void *buf, size_t len); -int nand_chng_write_col(device_t dev, uint32_t col, void *buf, size_t len); -int nand_get_feature(device_t dev, uint8_t feat, void* buf); -int nand_set_feature(device_t dev, uint8_t feat, void* buf); - - -int nand_erase_block_intlv(device_t dev, uint32_t block); -int nand_copyback_read(device_t dev, uint32_t page, uint32_t col, - void *buf, size_t len); -int nand_copyback_prog(device_t dev, uint32_t page, uint32_t col, - void *buf, size_t len); -int nand_copyback_prog_intlv(device_t dev, uint32_t page); -int nand_prog_cache(device_t dev, uint32_t page, uint32_t col, - void *buf, size_t len, uint8_t end); -int nand_prog_intlv(device_t dev, uint32_t page, uint32_t col, - void *buf, size_t len); -int nand_read_cache(device_t dev, uint32_t page, uint32_t col, - void *buf, size_t len, uint8_t end); - -int nand_write_ecc(struct nand_softc *nand, uint32_t page, uint8_t *data); -int nand_read_ecc(struct nand_softc *nand, uint32_t page, uint8_t *data); - -int nand_softecc_get(device_t dev, uint8_t *buf, int pagesize, uint8_t *ecc); -int nand_softecc_correct(device_t dev, uint8_t *buf, int pagesize, - uint8_t *readecc, uint8_t *calcecc); - -/* Chip initialization */ -void nand_init(struct nand_softc *nand, device_t dev, int ecc_mode, - int ecc_bytes, int ecc_size, uint16_t* eccposition, char* cdev_name); -void nand_detach(struct nand_softc *nand); -struct nand_params *nand_get_params(struct nand_id *id); - -void nand_onfi_set_params(struct nand_chip *chip, struct onfi_chip_params *params); -void nand_set_params(struct nand_chip *chip, struct nand_params *params); -int nand_init_stat(struct nand_chip *chip); -void nand_destroy_stat(struct nand_chip *chip); - -/* BBT */ -int nand_init_bbt(struct nand_chip *chip); -void nand_destroy_bbt(struct nand_chip *chip); -int nand_update_bbt(struct nand_chip *chip); -int nand_mark_bad_block(struct nand_chip* chip, uint32_t block_num); -int nand_check_bad_block(struct nand_chip* chip, uint32_t block_num); - -/* cdev creation/removal */ -int nand_make_dev(struct nand_chip* chip); -void nand_destroy_dev(struct nand_chip *chip); - -int create_geom_disk(struct nand_chip* chip); -int create_geom_raw_disk(struct nand_chip *chip); -void destroy_geom_disk(struct nand_chip *chip); -void destroy_geom_raw_disk(struct nand_chip *chip); - -int init_chip_geom(struct chip_geom* cg, uint32_t luns, uint32_t blks_per_lun, - uint32_t pgs_per_blk, uint32_t pg_size, uint32_t oob_size); -int nand_row_to_blkpg(struct chip_geom *cg, uint32_t row, uint32_t *lun, - uint32_t *blk, uint32_t *pg); -int page_to_row(struct chip_geom *cg, uint32_t page, uint32_t *row); -int nand_check_page_boundary(struct nand_chip *chip, uint32_t page); -void nand_get_chip_param(struct nand_chip *chip, struct chip_param_io *param); - -#endif /* _DEV_NAND_H_ */ diff --git a/sys/dev/nand/nand_bbt.c b/sys/dev/nand/nand_bbt.c deleted file mode 100644 index d99ed67523a2..000000000000 --- a/sys/dev/nand/nand_bbt.c +++ /dev/null @@ -1,275 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2009-2012 Semihalf - * 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/cdefs.h> - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/socket.h> -#include <sys/malloc.h> -#include <sys/bus.h> - -#include <dev/nand/nand.h> - -#include "nand_if.h" - -#define BBT_PRIMARY_PATTERN 0x01020304 -#define BBT_SECONDARY_PATTERN 0x05060708 - -enum bbt_place { - BBT_NONE, - BBT_PRIMARY, - BBT_SECONDARY -}; - -struct nand_bbt { - struct nand_chip *chip; - uint32_t primary_map; - uint32_t secondary_map; - enum bbt_place active; - struct bbt_header *hdr; - uint32_t tab_len; - uint32_t *table; -}; - -struct bbt_header { - uint32_t pattern; - int32_t seq_nr; -}; - -static int nand_bbt_save(struct nand_bbt *); -static int nand_bbt_load_hdr(struct nand_bbt *, struct bbt_header *, int8_t); -static int nand_bbt_load_table(struct nand_bbt *); -static int nand_bbt_prescan(struct nand_bbt *); - -int -nand_init_bbt(struct nand_chip *chip) -{ - struct chip_geom *cg; - struct nand_bbt *bbt; - int err; - - cg = &chip->chip_geom; - - bbt = malloc(sizeof(struct nand_bbt), M_NAND, M_ZERO | M_WAITOK); - if (!bbt) { - device_printf(chip->dev, - "Cannot allocate memory for bad block struct"); - return (ENOMEM); - } - - bbt->chip = chip; - bbt->active = BBT_NONE; - bbt->primary_map = cg->chip_size - cg->block_size; - bbt->secondary_map = cg->chip_size - 2 * cg->block_size; - bbt->tab_len = cg->blks_per_chip * sizeof(uint32_t); - bbt->hdr = malloc(sizeof(struct bbt_header) + bbt->tab_len, M_NAND, - M_WAITOK); - if (!bbt->hdr) { - device_printf(chip->dev, "Cannot allocate %d bytes for BB " - "Table", bbt->tab_len); - free(bbt, M_NAND); - return (ENOMEM); - } - bbt->hdr->seq_nr = 0; - bbt->table = (uint32_t *)((uint8_t *)bbt->hdr + - sizeof(struct bbt_header)); - - err = nand_bbt_load_table(bbt); - if (err) { - free(bbt->table, M_NAND); - free(bbt, M_NAND); - return (err); - } - - chip->bbt = bbt; - if (bbt->active == BBT_NONE) { - bbt->active = BBT_PRIMARY; - memset(bbt->table, 0xff, bbt->tab_len); - nand_bbt_prescan(bbt); - nand_bbt_save(bbt); - } else - device_printf(chip->dev, "Found BBT table for chip\n"); - - return (0); -} - -void -nand_destroy_bbt(struct nand_chip *chip) -{ - - if (chip->bbt) { - nand_bbt_save(chip->bbt); - - free(chip->bbt->hdr, M_NAND); - free(chip->bbt, M_NAND); - chip->bbt = NULL; - } -} - -int -nand_update_bbt(struct nand_chip *chip) -{ - - nand_bbt_save(chip->bbt); - - return (0); -} - -static int -nand_bbt_save(struct nand_bbt *bbt) -{ - enum bbt_place next; - uint32_t addr; - int32_t err; - - if (bbt->active == BBT_PRIMARY) { - addr = bbt->secondary_map; - bbt->hdr->pattern = BBT_SECONDARY_PATTERN; - next = BBT_SECONDARY; - } else { - addr = bbt->primary_map; - bbt->hdr->pattern = BBT_PRIMARY_PATTERN; - next = BBT_PRIMARY; - } - - err = nand_erase_blocks(bbt->chip, addr, - bbt->chip->chip_geom.block_size); - if (err) - return (err); - - bbt->hdr->seq_nr++; - - err = nand_prog_pages_raw(bbt->chip, addr, bbt->hdr, - bbt->tab_len + sizeof(struct bbt_header)); - if (err) - return (err); - - bbt->active = next; - return (0); -} - -static int -nand_bbt_load_hdr(struct nand_bbt *bbt, struct bbt_header *hdr, int8_t primary) -{ - uint32_t addr; - - if (primary) - addr = bbt->primary_map; - else - addr = bbt->secondary_map; - - return (nand_read_pages_raw(bbt->chip, addr, hdr, - sizeof(struct bbt_header))); -} - -static int -nand_bbt_load_table(struct nand_bbt *bbt) -{ - struct bbt_header hdr1, hdr2; - uint32_t address = 0; - int err = 0; - - bzero(&hdr1, sizeof(hdr1)); - bzero(&hdr2, sizeof(hdr2)); - - nand_bbt_load_hdr(bbt, &hdr1, 1); - if (hdr1.pattern == BBT_PRIMARY_PATTERN) { - bbt->active = BBT_PRIMARY; - address = bbt->primary_map; - } else - bzero(&hdr1, sizeof(hdr1)); - - - nand_bbt_load_hdr(bbt, &hdr2, 0); - if ((hdr2.pattern == BBT_SECONDARY_PATTERN) && - (hdr2.seq_nr > hdr1.seq_nr)) { - bbt->active = BBT_SECONDARY; - address = bbt->secondary_map; - } else - bzero(&hdr2, sizeof(hdr2)); - - if (bbt->active != BBT_NONE) - err = nand_read_pages_raw(bbt->chip, address, bbt->hdr, - bbt->tab_len + sizeof(struct bbt_header)); - - return (err); -} - -static int -nand_bbt_prescan(struct nand_bbt *bbt) -{ - int32_t i; - uint8_t bad; - bool printed_hash = 0; - - device_printf(bbt->chip->dev, "No BBT found. Prescan chip...\n"); - for (i = 0; i < bbt->chip->chip_geom.blks_per_chip; i++) { - if (NAND_IS_BLK_BAD(bbt->chip->dev, i, &bad)) - return (ENXIO); - - if (bad) { - device_printf(bbt->chip->dev, "Bad block(%d)\n", i); - bbt->table[i] = 0x0FFFFFFF; - } - if (!(i % 100)) { - printf("#"); - printed_hash = 1; - } - } - - if (printed_hash) - printf("\n"); - - return (0); -} - -int -nand_check_bad_block(struct nand_chip *chip, uint32_t block_number) -{ - - if (!chip || !chip->bbt) - return (0); - - if ((chip->bbt->table[block_number] & 0xF0000000) == 0) - return (1); - - return (0); -} - -int -nand_mark_bad_block(struct nand_chip *chip, uint32_t block_number) -{ - - chip->bbt->table[block_number] = 0x0FFFFFFF; - - return (0); -} diff --git a/sys/dev/nand/nand_cdev.c b/sys/dev/nand/nand_cdev.c deleted file mode 100644 index 53c62dbc2913..000000000000 --- a/sys/dev/nand/nand_cdev.c +++ /dev/null @@ -1,454 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/conf.h> -#include <sys/bus.h> -#include <sys/malloc.h> -#include <sys/uio.h> -#include <sys/bio.h> - -#include <dev/nand/nand.h> -#include <dev/nand/nandbus.h> -#include <dev/nand/nand_dev.h> -#include "nand_if.h" -#include "nandbus_if.h" - -static int nand_page_stat(struct nand_chip *, struct page_stat_io *); -static int nand_block_stat(struct nand_chip *, struct block_stat_io *); - -static d_ioctl_t nand_ioctl; -static d_open_t nand_open; -static d_strategy_t nand_strategy; - -static struct cdevsw nand_cdevsw = { - .d_version = D_VERSION, - .d_name = "nand", - .d_open = nand_open, - .d_read = physread, - .d_write = physwrite, - .d_ioctl = nand_ioctl, - .d_strategy = nand_strategy, -}; - -static int -offset_to_page(struct chip_geom *cg, uint32_t offset) -{ - - return (offset / cg->page_size); -} - -static int -offset_to_page_off(struct chip_geom *cg, uint32_t offset) -{ - - return (offset % cg->page_size); -} - -int -nand_make_dev(struct nand_chip *chip) -{ - struct nandbus_ivar *ivar; - device_t parent, nandbus; - int parent_unit, unit; - char *name; - - ivar = device_get_ivars(chip->dev); - nandbus = device_get_parent(chip->dev); - - if (ivar->chip_cdev_name) { - name = ivar->chip_cdev_name; - - /* - * If we got distinct name for chip device we can enumarete it - * based on contoller number. - */ - parent = device_get_parent(nandbus); - } else { - name = "nand"; - parent = nandbus; - } - - parent_unit = device_get_unit(parent); - unit = parent_unit * 4 + chip->num; - chip->cdev = make_dev(&nand_cdevsw, unit, UID_ROOT, GID_WHEEL, - 0666, "%s%d.%d", name, parent_unit, chip->num); - - if (chip->cdev == NULL) - return (ENXIO); - - if (bootverbose) - device_printf(chip->dev, "Created cdev %s%d.%d for chip " - "[0x%0x, 0x%0x]\n", name, parent_unit, chip->num, - ivar->man_id, ivar->dev_id); - - chip->cdev->si_drv1 = chip; - - return (0); -} - -void -nand_destroy_dev(struct nand_chip *chip) -{ - - if (chip->cdev) - destroy_dev(chip->cdev); -} - -static int -nand_open(struct cdev *dev, int oflags, int devtype, struct thread *td) -{ - - return (0); -} - -static int -nand_read(struct nand_chip *chip, uint32_t offset, void *buf, uint32_t len) -{ - struct chip_geom *cg; - device_t nandbus; - int start_page, count, off, err = 0; - uint8_t *ptr, *tmp; - - nand_debug(NDBG_CDEV, "Read from chip%d [%p] at %d\n", chip->num, - chip, offset); - - nandbus = device_get_parent(chip->dev); - NANDBUS_LOCK(nandbus); - NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num); - - cg = &chip->chip_geom; - start_page = offset_to_page(cg, offset); - off = offset_to_page_off(cg, offset); - count = (len > cg->page_size - off) ? cg->page_size - off : len; - - ptr = (uint8_t *)buf; - while (len > 0) { - if (len < cg->page_size) { - tmp = malloc(cg->page_size, M_NAND, M_WAITOK); - if (!tmp) { - err = ENOMEM; - break; - } - err = NAND_READ_PAGE(chip->dev, start_page, - tmp, cg->page_size, 0); - if (err) { - free(tmp, M_NAND); - break; - } - bcopy(tmp + off, ptr, count); - free(tmp, M_NAND); - } else { - err = NAND_READ_PAGE(chip->dev, start_page, - ptr, cg->page_size, 0); - if (err) - break; - } - - len -= count; - start_page++; - ptr += count; - count = (len > cg->page_size) ? cg->page_size : len; - off = 0; - } - - NANDBUS_UNLOCK(nandbus); - return (err); -} - -static int -nand_write(struct nand_chip *chip, uint32_t offset, void* buf, uint32_t len) -{ - struct chip_geom *cg; - device_t nandbus; - int off, start_page, err = 0; - uint8_t *ptr; - - nand_debug(NDBG_CDEV, "Write to chip %d [%p] at %d\n", chip->num, - chip, offset); - - nandbus = device_get_parent(chip->dev); - NANDBUS_LOCK(nandbus); - NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num); - - cg = &chip->chip_geom; - start_page = offset_to_page(cg, offset); - off = offset_to_page_off(cg, offset); - - if (off != 0 || (len % cg->page_size) != 0) { - printf("Not aligned write start [0x%08x] size [0x%08x]\n", - off, len); - NANDBUS_UNLOCK(nandbus); - return (EINVAL); - } - - ptr = (uint8_t *)buf; - while (len > 0) { - err = NAND_PROGRAM_PAGE(chip->dev, start_page, ptr, - cg->page_size, 0); - if (err) - break; - - len -= cg->page_size; - start_page++; - ptr += cg->page_size; - } - - NANDBUS_UNLOCK(nandbus); - return (err); -} - -static void -nand_strategy(struct bio *bp) -{ - struct nand_chip *chip; - struct cdev *dev; - int err = 0; - - dev = bp->bio_dev; - chip = dev->si_drv1; - - nand_debug(NDBG_CDEV, "Strategy %s on chip %d [%p]\n", - bp->bio_cmd == BIO_READ ? "READ" : "WRITE", - chip->num, chip); - - if (bp->bio_cmd == BIO_READ) { - err = nand_read(chip, - bp->bio_offset & 0xffffffff, - bp->bio_data, bp->bio_bcount); - } else { - err = nand_write(chip, - bp->bio_offset & 0xffffffff, - bp->bio_data, bp->bio_bcount); - } - - if (err == 0) - bp->bio_resid = 0; - else { - bp->bio_error = EIO; - bp->bio_flags |= BIO_ERROR; - bp->bio_resid = bp->bio_bcount; - } - - biodone(bp); -} - -static int -nand_oob_access(struct nand_chip *chip, uint32_t page, uint32_t offset, - uint32_t len, uint8_t *data, uint8_t write) -{ - struct chip_geom *cg; - uint8_t *buf = NULL; - int ret = 0; - - cg = &chip->chip_geom; - - buf = malloc(cg->oob_size, M_NAND, M_WAITOK); - if (!buf) - return (ENOMEM); - - memset(buf, 0xff, cg->oob_size); - - if (!write) { - ret = nand_read_oob(chip, page, buf, cg->oob_size); - copyout(buf, data, len); - } else { - copyin(data, buf, len); - ret = nand_prog_oob(chip, page, buf, cg->oob_size); - } - - free(buf, M_NAND); - - return (ret); -} - -static int -nand_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, - struct thread *td) -{ - struct nand_chip *chip; - struct chip_geom *cg; - struct nand_oob_rw *oob_rw = NULL; - struct nand_raw_rw *raw_rw = NULL; - device_t nandbus; - size_t bufsize = 0, len = 0; - size_t raw_size; - off_t off; - uint8_t *buf = NULL; - int ret = 0; - uint8_t status; - - chip = (struct nand_chip *)dev->si_drv1; - cg = &chip->chip_geom; - nandbus = device_get_parent(chip->dev); - - if ((cmd == NAND_IO_RAW_READ) || (cmd == NAND_IO_RAW_PROG)) { - raw_rw = (struct nand_raw_rw *)data; - raw_size = cg->pgs_per_blk * (cg->page_size + cg->oob_size); - - /* Check if len is not bigger than chip size */ - if (raw_rw->len > raw_size) - return (EFBIG); - - /* - * Do not ask for too much memory, in case of large transfers - * read/write in 16-pages chunks - */ - bufsize = 16 * (cg->page_size + cg->oob_size); - if (raw_rw->len < bufsize) - bufsize = raw_rw->len; - - buf = malloc(bufsize, M_NAND, M_WAITOK); - len = raw_rw->len; - off = 0; - } - switch(cmd) { - case NAND_IO_ERASE: - ret = nand_erase_blocks(chip, ((off_t *)data)[0], - ((off_t *)data)[1]); - break; - - case NAND_IO_OOB_READ: - oob_rw = (struct nand_oob_rw *)data; - ret = nand_oob_access(chip, oob_rw->page, 0, - oob_rw->len, oob_rw->data, 0); - break; - - case NAND_IO_OOB_PROG: - oob_rw = (struct nand_oob_rw *)data; - ret = nand_oob_access(chip, oob_rw->page, 0, - oob_rw->len, oob_rw->data, 1); - break; - - case NAND_IO_GET_STATUS: - NANDBUS_LOCK(nandbus); - ret = NANDBUS_GET_STATUS(nandbus, &status); - if (ret == 0) - *(uint8_t *)data = status; - NANDBUS_UNLOCK(nandbus); - break; - - case NAND_IO_RAW_PROG: - while (len > 0) { - if (len < bufsize) - bufsize = len; - ret = copyin(raw_rw->data + off, buf, bufsize); - if (ret) - break; - ret = nand_prog_pages_raw(chip, raw_rw->off + off, buf, - bufsize); - if (ret) - break; - len -= bufsize; - off += bufsize; - } - break; - - case NAND_IO_RAW_READ: - while (len > 0) { - if (len < bufsize) - bufsize = len; - - ret = nand_read_pages_raw(chip, raw_rw->off + off, buf, - bufsize); - if (ret) - break; - - ret = copyout(buf, raw_rw->data + off, bufsize); - if (ret) - break; - len -= bufsize; - off += bufsize; - } - break; - - case NAND_IO_PAGE_STAT: - ret = nand_page_stat(chip, (struct page_stat_io *)data); - break; - - case NAND_IO_BLOCK_STAT: - ret = nand_block_stat(chip, (struct block_stat_io *)data); - break; - - case NAND_IO_GET_CHIP_PARAM: - nand_get_chip_param(chip, (struct chip_param_io *)data); - break; - - default: - printf("Unknown nand_ioctl request \n"); - ret = EIO; - } - - if (buf) - free(buf, M_NAND); - - return (ret); -} - -static int -nand_page_stat(struct nand_chip *chip, struct page_stat_io *page_stat) -{ - struct chip_geom *cg; - struct page_stat *stat; - int num_pages; - - cg = &chip->chip_geom; - num_pages = cg->pgs_per_blk * cg->blks_per_lun * cg->luns; - if (page_stat->page_num >= num_pages) - return (EINVAL); - - stat = &chip->pg_stat[page_stat->page_num]; - page_stat->page_read = stat->page_read; - page_stat->page_written = stat->page_written; - page_stat->page_raw_read = stat->page_raw_read; - page_stat->page_raw_written = stat->page_raw_written; - page_stat->ecc_succeded = stat->ecc_stat.ecc_succeded; - page_stat->ecc_corrected = stat->ecc_stat.ecc_corrected; - page_stat->ecc_failed = stat->ecc_stat.ecc_failed; - - return (0); -} - -static int -nand_block_stat(struct nand_chip *chip, struct block_stat_io *block_stat) -{ - struct chip_geom *cg; - uint32_t block_num = block_stat->block_num; - - cg = &chip->chip_geom; - if (block_num >= cg->blks_per_lun * cg->luns) - return (EINVAL); - - block_stat->block_erased = chip->blk_stat[block_num].block_erased; - - return (0); -} diff --git a/sys/dev/nand/nand_dev.h b/sys/dev/nand/nand_dev.h deleted file mode 100644 index bd00c4d4b3b4..000000000000 --- a/sys/dev/nand/nand_dev.h +++ /dev/null @@ -1,92 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _DEV_NAND_CDEV_H_ -#define _DEV_NAND_CDEV_H_ - -#include <sys/ioccom.h> -#include <sys/param.h> - -struct nand_raw_rw { - off_t off; - off_t len; - uint8_t *data; -}; - -struct nand_oob_rw { - uint32_t page; - off_t len; - uint8_t *data; -}; - -#define NAND_IOCTL_GROUP 'N' -#define NAND_IO_ERASE _IOWR(NAND_IOCTL_GROUP, 0x0, off_t[2]) - -#define NAND_IO_OOB_READ _IOWR(NAND_IOCTL_GROUP, 0x1, struct nand_oob_rw) - -#define NAND_IO_OOB_PROG _IOWR(NAND_IOCTL_GROUP, 0x2, struct nand_oob_rw) - -#define NAND_IO_RAW_READ _IOWR(NAND_IOCTL_GROUP, 0x3, struct nand_raw_rw) - -#define NAND_IO_RAW_PROG _IOWR(NAND_IOCTL_GROUP, 0x4, struct nand_raw_rw) - -#define NAND_IO_GET_STATUS _IOWR(NAND_IOCTL_GROUP, 0x5, uint8_t) - -struct page_stat_io { - uint32_t page_num; - uint32_t page_read; - uint32_t page_written; - uint32_t page_raw_read; - uint32_t page_raw_written; - uint32_t ecc_succeded; - uint32_t ecc_corrected; - uint32_t ecc_failed; -}; -#define NAND_IO_PAGE_STAT _IOWR(NAND_IOCTL_GROUP, 0x6, \ - struct page_stat_io) - -struct block_stat_io { - uint32_t block_num; - uint32_t block_erased; -}; -#define NAND_IO_BLOCK_STAT _IOWR(NAND_IOCTL_GROUP, 0x7, \ - struct block_stat_io) - -struct chip_param_io { - uint32_t page_size; - uint32_t oob_size; - - uint32_t blocks; - uint32_t pages_per_block; -}; -#define NAND_IO_GET_CHIP_PARAM _IOWR(NAND_IOCTL_GROUP, 0x8, \ - struct chip_param_io) - -#endif /* _DEV_NAND_CDEV_H_ */ diff --git a/sys/dev/nand/nand_ecc_pos.h b/sys/dev/nand/nand_ecc_pos.h deleted file mode 100644 index 835f45e6c083..000000000000 --- a/sys/dev/nand/nand_ecc_pos.h +++ /dev/null @@ -1,58 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _DEV_NAND_ECC_POS_H_ -#define _DEV_NAND_ECC_POS_H_ - -static uint16_t default_software_ecc_positions_16[] = {2, 0, 1, 7, 4, 6}; - -static uint16_t default_software_ecc_positions_64[] = { - - 42, 40, 41, 45, 43, 44, 48, 46, - 47, 51, 49, 50, 54, 52, 53, 57, - 55, 56, 60, 58, 59, 63, 61, 62 -}; - -static uint16_t default_software_ecc_positions_128[] = { - 8, 9, 10, 11, 12, 13, - 18, 19, 20, 21, 22, 23, - 28, 29, 30, 31, 32, 33, - 38, 39, 40, 41, 42, 43, - 48, 49, 50, 51, 52, 53, - 58, 59, 60, 61, 62, 63, - 68, 69, 70, 71, 72, 73, - 78, 79, 80, 81, 82, 83, - 88, 89, 90, 91, 92, 93, - 98, 99, 100, 101, 102, 103, - 108, 109, 110, 111, 112, 113, - 118, 119, 120, 121, 122, 123, -}; -#endif /* _DEV_NAND_ECC_POS_H_ */ - diff --git a/sys/dev/nand/nand_generic.c b/sys/dev/nand/nand_generic.c deleted file mode 100644 index cc6ef9bd57b0..000000000000 --- a/sys/dev/nand/nand_generic.c +++ /dev/null @@ -1,1366 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * 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. - */ - -/* Generic NAND driver */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/proc.h> -#include <sys/bus.h> -#include <sys/conf.h> -#include <sys/endian.h> -#include <sys/kernel.h> -#include <sys/module.h> -#include <sys/rman.h> -#include <sys/lock.h> -#include <sys/mutex.h> -#include <sys/time.h> -#include <sys/malloc.h> - -#include <dev/nand/nand.h> -#include <dev/nand/nandbus.h> -#include "nfc_if.h" -#include "nand_if.h" -#include "nandbus_if.h" - - -static int onfi_nand_probe(device_t dev); -static int large_nand_probe(device_t dev); -static int small_nand_probe(device_t dev); -static int generic_nand_attach(device_t dev); -static int generic_nand_detach(device_t dev); - -static int generic_erase_block(device_t, uint32_t); -static int generic_erase_block_intlv(device_t, uint32_t); -static int generic_read_page (device_t, uint32_t, void *, uint32_t, uint32_t); -static int generic_read_oob(device_t, uint32_t, void *, uint32_t, uint32_t); -static int generic_program_page(device_t, uint32_t, void *, uint32_t, uint32_t); -static int generic_program_page_intlv(device_t, uint32_t, void *, uint32_t, - uint32_t); -static int generic_program_oob(device_t, uint32_t, void *, uint32_t, uint32_t); -static int generic_is_blk_bad(device_t, uint32_t, uint8_t *); -static int generic_get_ecc(device_t, void *, void *, int *); -static int generic_correct_ecc(device_t, void *, void *, void *); - -static int small_read_page(device_t, uint32_t, void *, uint32_t, uint32_t); -static int small_read_oob(device_t, uint32_t, void *, uint32_t, uint32_t); -static int small_program_page(device_t, uint32_t, void *, uint32_t, uint32_t); -static int small_program_oob(device_t, uint32_t, void *, uint32_t, uint32_t); - -static int onfi_is_blk_bad(device_t, uint32_t, uint8_t *); -static int onfi_read_parameter(struct nand_chip *, struct onfi_chip_params *); - -static int nand_send_address(device_t, int32_t, int32_t, int8_t); - -static device_method_t onand_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, onfi_nand_probe), - DEVMETHOD(device_attach, generic_nand_attach), - DEVMETHOD(device_detach, generic_nand_detach), - - DEVMETHOD(nand_read_page, generic_read_page), - DEVMETHOD(nand_program_page, generic_program_page), - DEVMETHOD(nand_program_page_intlv, generic_program_page_intlv), - DEVMETHOD(nand_read_oob, generic_read_oob), - DEVMETHOD(nand_program_oob, generic_program_oob), - DEVMETHOD(nand_erase_block, generic_erase_block), - DEVMETHOD(nand_erase_block_intlv, generic_erase_block_intlv), - - DEVMETHOD(nand_is_blk_bad, onfi_is_blk_bad), - DEVMETHOD(nand_get_ecc, generic_get_ecc), - DEVMETHOD(nand_correct_ecc, generic_correct_ecc), - { 0, 0 } -}; - -static device_method_t lnand_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, large_nand_probe), - DEVMETHOD(device_attach, generic_nand_attach), - DEVMETHOD(device_detach, generic_nand_detach), - - DEVMETHOD(nand_read_page, generic_read_page), - DEVMETHOD(nand_program_page, generic_program_page), - DEVMETHOD(nand_read_oob, generic_read_oob), - DEVMETHOD(nand_program_oob, generic_program_oob), - DEVMETHOD(nand_erase_block, generic_erase_block), - - DEVMETHOD(nand_is_blk_bad, generic_is_blk_bad), - DEVMETHOD(nand_get_ecc, generic_get_ecc), - DEVMETHOD(nand_correct_ecc, generic_correct_ecc), - { 0, 0 } -}; - -static device_method_t snand_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, small_nand_probe), - DEVMETHOD(device_attach, generic_nand_attach), - DEVMETHOD(device_detach, generic_nand_detach), - - DEVMETHOD(nand_read_page, small_read_page), - DEVMETHOD(nand_program_page, small_program_page), - DEVMETHOD(nand_read_oob, small_read_oob), - DEVMETHOD(nand_program_oob, small_program_oob), - DEVMETHOD(nand_erase_block, generic_erase_block), - - DEVMETHOD(nand_is_blk_bad, generic_is_blk_bad), - DEVMETHOD(nand_get_ecc, generic_get_ecc), - DEVMETHOD(nand_correct_ecc, generic_correct_ecc), - { 0, 0 } -}; - -devclass_t onand_devclass; -devclass_t lnand_devclass; -devclass_t snand_devclass; - -driver_t onand_driver = { - "onand", - onand_methods, - sizeof(struct nand_chip) -}; - -driver_t lnand_driver = { - "lnand", - lnand_methods, - sizeof(struct nand_chip) -}; - -driver_t snand_driver = { - "snand", - snand_methods, - sizeof(struct nand_chip) -}; - -DRIVER_MODULE(onand, nandbus, onand_driver, onand_devclass, 0, 0); -DRIVER_MODULE(lnand, nandbus, lnand_driver, lnand_devclass, 0, 0); -DRIVER_MODULE(snand, nandbus, snand_driver, snand_devclass, 0, 0); - -static int -onfi_nand_probe(device_t dev) -{ - struct nandbus_ivar *ivar; - - ivar = device_get_ivars(dev); - if (ivar && ivar->is_onfi) { - device_set_desc(dev, "ONFI compliant NAND"); - return (BUS_PROBE_DEFAULT); - } - - return (ENODEV); -} - -static int -large_nand_probe(device_t dev) -{ - struct nandbus_ivar *ivar; - - ivar = device_get_ivars(dev); - if (ivar && !ivar->is_onfi && ivar->params->page_size >= 512) { - device_set_desc(dev, ivar->params->name); - return (BUS_PROBE_DEFAULT); - } - - return (ENODEV); -} - -static int -small_nand_probe(device_t dev) -{ - struct nandbus_ivar *ivar; - - ivar = device_get_ivars(dev); - if (ivar && !ivar->is_onfi && ivar->params->page_size == 512) { - device_set_desc(dev, ivar->params->name); - return (BUS_PROBE_DEFAULT); - } - - return (ENODEV); -} - -static int -generic_nand_attach(device_t dev) -{ - struct nand_chip *chip; - struct nandbus_ivar *ivar; - struct onfi_chip_params *onfi_chip_params; - device_t nandbus, nfc; - int err; - - chip = device_get_softc(dev); - chip->dev = dev; - - ivar = device_get_ivars(dev); - chip->id.man_id = ivar->man_id; - chip->id.dev_id = ivar->dev_id; - chip->num = ivar->cs; - - /* TODO remove when HW ECC supported */ - nandbus = device_get_parent(dev); - nfc = device_get_parent(nandbus); - - chip->nand = device_get_softc(nfc); - - if (ivar->is_onfi) { - onfi_chip_params = malloc(sizeof(struct onfi_chip_params), - M_NAND, M_WAITOK | M_ZERO); - - if (onfi_read_parameter(chip, onfi_chip_params)) { - nand_debug(NDBG_GEN,"Could not read parameter page!\n"); - free(onfi_chip_params, M_NAND); - return (ENXIO); - } - - nand_onfi_set_params(chip, onfi_chip_params); - /* Set proper column and row cycles */ - ivar->cols = (onfi_chip_params->address_cycles >> 4) & 0xf; - ivar->rows = onfi_chip_params->address_cycles & 0xf; - free(onfi_chip_params, M_NAND); - - } else { - nand_set_params(chip, ivar->params); - } - - err = nand_init_stat(chip); - if (err) { - generic_nand_detach(dev); - return (err); - } - - err = nand_init_bbt(chip); - if (err) { - generic_nand_detach(dev); - return (err); - } - - err = nand_make_dev(chip); - if (err) { - generic_nand_detach(dev); - return (err); - } - - err = create_geom_disk(chip); - if (err) { - generic_nand_detach(dev); - return (err); - } - - return (0); -} - -static int -generic_nand_detach(device_t dev) -{ - struct nand_chip *chip; - - chip = device_get_softc(dev); - - nand_destroy_bbt(chip); - destroy_geom_disk(chip); - nand_destroy_dev(chip); - nand_destroy_stat(chip); - - return (0); -} - -static int -can_write(device_t nandbus) -{ - uint8_t status; - - if (NANDBUS_WAIT_READY(nandbus, &status)) - return (0); - - if (!(status & NAND_STATUS_WP)) { - nand_debug(NDBG_GEN,"Chip is write-protected"); - return (0); - } - - return (1); -} - -static int -check_fail(device_t nandbus) -{ - uint8_t status; - - NANDBUS_WAIT_READY(nandbus, &status); - if (status & NAND_STATUS_FAIL) { - nand_debug(NDBG_GEN,"Status failed %x", status); - return (ENXIO); - } - - return (0); -} - -static uint16_t -onfi_crc(const void *buf, size_t buflen) -{ - int i, j; - uint16_t crc; - const uint8_t *bufptr; - - bufptr = buf; - crc = 0x4f4e; - for (j = 0; j < buflen; j++) { - crc ^= *bufptr++ << 8; - for (i = 0; i < 8; i++) - if (crc & 0x8000) - crc = (crc << 1) ^ 0x8005; - else - crc <<= 1; - } - return crc; -} - -static int -onfi_read_parameter(struct nand_chip *chip, struct onfi_chip_params *chip_params) -{ - device_t nandbus; - struct onfi_params params; - int found, sigcount, trycopy; - - nand_debug(NDBG_GEN,"read parameter"); - - nandbus = device_get_parent(chip->dev); - - NANDBUS_SELECT_CS(nandbus, chip->num); - - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_READ_PARAMETER)) - return (ENXIO); - - if (nand_send_address(chip->dev, -1, -1, PAGE_PARAMETER_DEF)) - return (ENXIO); - - if (NANDBUS_START_COMMAND(nandbus)) - return (ENXIO); - - /* - * XXX Bogus DELAY, we really need a nandbus_wait_ready() here, but it's - * not accessible from here (static to nandbus). - */ - DELAY(1000); - - /* - * The ONFI spec mandates a minimum of three copies of the parameter - * data, so loop up to 3 times trying to find good data. Each copy is - * validated by a signature of "ONFI" and a crc. There is a very strange - * rule that the signature is valid if any 2 of the 4 bytes are correct. - */ - for (found= 0, trycopy = 0; !found && trycopy < 3; trycopy++) { - NANDBUS_READ_BUFFER(nandbus, ¶ms, sizeof(struct onfi_params)); - sigcount = params.signature[0] == 'O'; - sigcount += params.signature[1] == 'N'; - sigcount += params.signature[2] == 'F'; - sigcount += params.signature[3] == 'I'; - if (sigcount < 2) - continue; - if (onfi_crc(¶ms, 254) != params.crc) - continue; - found = 1; - } - if (!found) - return (ENXIO); - - chip_params->luns = params.luns; - chip_params->blocks_per_lun = le32dec(¶ms.blocks_per_lun); - chip_params->pages_per_block = le32dec(¶ms.pages_per_block); - chip_params->bytes_per_page = le32dec(¶ms.bytes_per_page); - chip_params->spare_bytes_per_page = le16dec(¶ms.spare_bytes_per_page); - chip_params->t_bers = le16dec(¶ms.t_bers); - chip_params->t_prog = le16dec(¶ms.t_prog); - chip_params->t_r = le16dec(¶ms.t_r); - chip_params->t_ccs = le16dec(¶ms.t_ccs); - chip_params->features = le16dec(¶ms.features); - chip_params->address_cycles = params.address_cycles; - - return (0); -} - -static int -send_read_page(device_t nand, uint8_t start_command, uint8_t end_command, - uint32_t row, uint32_t column) -{ - device_t nandbus = device_get_parent(nand); - - if (NANDBUS_SEND_COMMAND(nandbus, start_command)) - return (ENXIO); - - if (nand_send_address(nand, row, column, -1)) - return (ENXIO); - - if (NANDBUS_SEND_COMMAND(nandbus, end_command)) - return (ENXIO); - - if (NANDBUS_START_COMMAND(nandbus)) - return (ENXIO); - - return (0); -} - -static int -generic_read_page(device_t nand, uint32_t page, void *buf, uint32_t len, - uint32_t offset) -{ - struct nand_chip *chip; - struct page_stat *pg_stat; - device_t nandbus; - uint32_t row; - - nand_debug(NDBG_GEN,"%p raw read page %x[%x] at %x", nand, page, len, offset); - chip = device_get_softc(nand); - nandbus = device_get_parent(nand); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - - if (send_read_page(nand, NAND_CMD_READ, NAND_CMD_READ_END, row, - offset)) - return (ENXIO); - - DELAY(chip->t_r); - - NANDBUS_READ_BUFFER(nandbus, buf, len); - - if (check_fail(nandbus)) - return (ENXIO); - - pg_stat = &(chip->pg_stat[page]); - pg_stat->page_raw_read++; - - return (0); -} - -static int -generic_read_oob(device_t nand, uint32_t page, void* buf, uint32_t len, - uint32_t offset) -{ - struct nand_chip *chip; - device_t nandbus; - uint32_t row; - - nand_debug(NDBG_GEN,"%p raw read oob %x[%x] at %x", nand, page, len, offset); - chip = device_get_softc(nand); - nandbus = device_get_parent(nand); - - if (nand_check_page_boundary(chip, page)) { - nand_debug(NDBG_GEN,"page boundary check failed: %08x\n", page); - return (ENXIO); - } - - page_to_row(&chip->chip_geom, page, &row); - - offset += chip->chip_geom.page_size; - - if (send_read_page(nand, NAND_CMD_READ, NAND_CMD_READ_END, row, - offset)) - return (ENXIO); - - DELAY(chip->t_r); - - NANDBUS_READ_BUFFER(nandbus, buf, len); - - if (check_fail(nandbus)) - return (ENXIO); - - return (0); -} - -static int -send_start_program_page(device_t nand, uint32_t row, uint32_t column) -{ - device_t nandbus = device_get_parent(nand); - - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_PROG)) - return (ENXIO); - - if (nand_send_address(nand, row, column, -1)) - return (ENXIO); - - return (0); -} - -static int -send_end_program_page(device_t nandbus, uint8_t end_command) -{ - - if (NANDBUS_SEND_COMMAND(nandbus, end_command)) - return (ENXIO); - - if (NANDBUS_START_COMMAND(nandbus)) - return (ENXIO); - - return (0); -} - -static int -generic_program_page(device_t nand, uint32_t page, void *buf, uint32_t len, - uint32_t offset) -{ - struct nand_chip *chip; - struct page_stat *pg_stat; - device_t nandbus; - uint32_t row; - - nand_debug(NDBG_GEN,"%p raw prog page %x[%x] at %x", nand, page, len, - offset); - chip = device_get_softc(nand); - nandbus = device_get_parent(nand); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - - if (!can_write(nandbus)) - return (ENXIO); - - if (send_start_program_page(nand, row, offset)) - return (ENXIO); - - NANDBUS_WRITE_BUFFER(nandbus, buf, len); - - if (send_end_program_page(nandbus, NAND_CMD_PROG_END)) - return (ENXIO); - - DELAY(chip->t_prog); - - if (check_fail(nandbus)) - return (ENXIO); - - pg_stat = &(chip->pg_stat[page]); - pg_stat->page_raw_written++; - - return (0); -} - -static int -generic_program_page_intlv(device_t nand, uint32_t page, void *buf, - uint32_t len, uint32_t offset) -{ - struct nand_chip *chip; - struct page_stat *pg_stat; - device_t nandbus; - uint32_t row; - - nand_debug(NDBG_GEN,"%p raw prog page %x[%x] at %x", nand, page, len, offset); - chip = device_get_softc(nand); - nandbus = device_get_parent(nand); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - - if (!can_write(nandbus)) - return (ENXIO); - - if (send_start_program_page(nand, row, offset)) - return (ENXIO); - - NANDBUS_WRITE_BUFFER(nandbus, buf, len); - - if (send_end_program_page(nandbus, NAND_CMD_PROG_INTLV)) - return (ENXIO); - - DELAY(chip->t_prog); - - if (check_fail(nandbus)) - return (ENXIO); - - pg_stat = &(chip->pg_stat[page]); - pg_stat->page_raw_written++; - - return (0); -} - -static int -generic_program_oob(device_t nand, uint32_t page, void* buf, uint32_t len, - uint32_t offset) -{ - struct nand_chip *chip; - device_t nandbus; - uint32_t row; - - nand_debug(NDBG_GEN,"%p raw prog oob %x[%x] at %x", nand, page, len, - offset); - chip = device_get_softc(nand); - nandbus = device_get_parent(nand); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - offset += chip->chip_geom.page_size; - - if (!can_write(nandbus)) - return (ENXIO); - - if (send_start_program_page(nand, row, offset)) - return (ENXIO); - - NANDBUS_WRITE_BUFFER(nandbus, buf, len); - - if (send_end_program_page(nandbus, NAND_CMD_PROG_END)) - return (ENXIO); - - DELAY(chip->t_prog); - - if (check_fail(nandbus)) - return (ENXIO); - - return (0); -} - -static int -send_erase_block(device_t nand, uint32_t row, uint8_t second_command) -{ - device_t nandbus = device_get_parent(nand); - - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_ERASE)) - return (ENXIO); - - if (nand_send_address(nand, row, -1, -1)) - return (ENXIO); - - if (NANDBUS_SEND_COMMAND(nandbus, second_command)) - return (ENXIO); - - if (NANDBUS_START_COMMAND(nandbus)) - return (ENXIO); - - return (0); -} - -static int -generic_erase_block(device_t nand, uint32_t block) -{ - struct block_stat *blk_stat; - struct nand_chip *chip; - device_t nandbus; - int row; - - nand_debug(NDBG_GEN,"%p erase block %x", nand, block); - nandbus = device_get_parent(nand); - chip = device_get_softc(nand); - - if (block >= (chip->chip_geom.blks_per_lun * chip->chip_geom.luns)) - return (ENXIO); - - row = (block << chip->chip_geom.blk_shift) & - chip->chip_geom.blk_mask; - - nand_debug(NDBG_GEN,"%p erase block row %x", nand, row); - - if (!can_write(nandbus)) - return (ENXIO); - - send_erase_block(nand, row, NAND_CMD_ERASE_END); - - DELAY(chip->t_bers); - - if (check_fail(nandbus)) - return (ENXIO); - - blk_stat = &(chip->blk_stat[block]); - blk_stat->block_erased++; - - return (0); -} - -static int -generic_erase_block_intlv(device_t nand, uint32_t block) -{ - struct block_stat *blk_stat; - struct nand_chip *chip; - device_t nandbus; - int row; - - nand_debug(NDBG_GEN,"%p erase block %x", nand, block); - nandbus = device_get_parent(nand); - chip = device_get_softc(nand); - - if (block >= (chip->chip_geom.blks_per_lun * chip->chip_geom.luns)) - return (ENXIO); - - row = (block << chip->chip_geom.blk_shift) & - chip->chip_geom.blk_mask; - - if (!can_write(nandbus)) - return (ENXIO); - - send_erase_block(nand, row, NAND_CMD_ERASE_INTLV); - - DELAY(chip->t_bers); - - if (check_fail(nandbus)) - return (ENXIO); - - blk_stat = &(chip->blk_stat[block]); - blk_stat->block_erased++; - - return (0); - -} - -static int -onfi_is_blk_bad(device_t device, uint32_t block_number, uint8_t *bad) -{ - struct nand_chip *chip; - int page_number, i, j, err; - uint8_t *oob; - - chip = device_get_softc(device); - - oob = malloc(chip->chip_geom.oob_size, M_NAND, M_WAITOK); - - page_number = block_number * chip->chip_geom.pgs_per_blk; - *bad = 0; - /* Check OOB of first and last page */ - for (i = 0; i < 2; i++, page_number+= chip->chip_geom.pgs_per_blk - 1) { - err = generic_read_oob(device, page_number, oob, - chip->chip_geom.oob_size, 0); - if (err) { - device_printf(device, "%s: cannot allocate oob\n", - __func__); - free(oob, M_NAND); - return (ENOMEM); - } - - for (j = 0; j < chip->chip_geom.oob_size; j++) { - if (!oob[j]) { - *bad = 1; - free(oob, M_NAND); - return (0); - } - } - } - - free(oob, M_NAND); - - return (0); -} - -static int -send_small_read_page(device_t nand, uint8_t start_command, - uint32_t row, uint32_t column) -{ - device_t nandbus = device_get_parent(nand); - - if (NANDBUS_SEND_COMMAND(nandbus, start_command)) - return (ENXIO); - - if (nand_send_address(nand, row, column, -1)) - return (ENXIO); - - if (NANDBUS_START_COMMAND(nandbus)) - return (ENXIO); - - return (0); -} - - -static int -small_read_page(device_t nand, uint32_t page, void *buf, uint32_t len, - uint32_t offset) -{ - struct nand_chip *chip; - struct page_stat *pg_stat; - device_t nandbus; - uint32_t row; - - nand_debug(NDBG_GEN,"%p small read page %x[%x] at %x", nand, page, len, offset); - chip = device_get_softc(nand); - nandbus = device_get_parent(nand); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - - if (offset < 256) { - if (send_small_read_page(nand, NAND_CMD_SMALLA, row, offset)) - return (ENXIO); - } else { - offset -= 256; - if (send_small_read_page(nandbus, NAND_CMD_SMALLB, row, offset)) - return (ENXIO); - } - - DELAY(chip->t_r); - - NANDBUS_READ_BUFFER(nandbus, buf, len); - - if (check_fail(nandbus)) - return (ENXIO); - - pg_stat = &(chip->pg_stat[page]); - pg_stat->page_raw_read++; - - return (0); -} - -static int -small_read_oob(device_t nand, uint32_t page, void *buf, uint32_t len, - uint32_t offset) -{ - struct nand_chip *chip; - struct page_stat *pg_stat; - device_t nandbus; - uint32_t row; - - nand_debug(NDBG_GEN,"%p small read oob %x[%x] at %x", nand, page, len, offset); - chip = device_get_softc(nand); - nandbus = device_get_parent(nand); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - - if (send_small_read_page(nand, NAND_CMD_SMALLOOB, row, 0)) - return (ENXIO); - - DELAY(chip->t_r); - - NANDBUS_READ_BUFFER(nandbus, buf, len); - - if (check_fail(nandbus)) - return (ENXIO); - - pg_stat = &(chip->pg_stat[page]); - pg_stat->page_raw_read++; - - return (0); -} - -static int -small_program_page(device_t nand, uint32_t page, void* buf, uint32_t len, - uint32_t offset) -{ - struct nand_chip *chip; - device_t nandbus; - uint32_t row; - - nand_debug(NDBG_GEN,"%p small prog page %x[%x] at %x", nand, page, len, offset); - chip = device_get_softc(nand); - nandbus = device_get_parent(nand); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - - if (!can_write(nandbus)) - return (ENXIO); - - if (offset < 256) { - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_SMALLA)) - return (ENXIO); - } else { - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_SMALLB)) - return (ENXIO); - } - - if (send_start_program_page(nand, row, offset)) - return (ENXIO); - - NANDBUS_WRITE_BUFFER(nandbus, buf, len); - - if (send_end_program_page(nandbus, NAND_CMD_PROG_END)) - return (ENXIO); - - DELAY(chip->t_prog); - - if (check_fail(nandbus)) - return (ENXIO); - - return (0); -} - -static int -small_program_oob(device_t nand, uint32_t page, void* buf, uint32_t len, - uint32_t offset) -{ - struct nand_chip *chip; - device_t nandbus; - uint32_t row; - - nand_debug(NDBG_GEN,"%p small prog oob %x[%x] at %x", nand, page, len, offset); - chip = device_get_softc(nand); - nandbus = device_get_parent(nand); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - - if (!can_write(nandbus)) - return (ENXIO); - - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_SMALLOOB)) - return (ENXIO); - - if (send_start_program_page(nand, row, offset)) - return (ENXIO); - - NANDBUS_WRITE_BUFFER(nandbus, buf, len); - - if (send_end_program_page(nandbus, NAND_CMD_PROG_END)) - return (ENXIO); - - DELAY(chip->t_prog); - - if (check_fail(nandbus)) - return (ENXIO); - - return (0); -} - -int -nand_send_address(device_t nand, int32_t row, int32_t col, int8_t id) -{ - struct nandbus_ivar *ivar; - device_t nandbus; - uint8_t addr; - int err = 0; - int i; - - nandbus = device_get_parent(nand); - ivar = device_get_ivars(nand); - - if (id != -1) { - nand_debug(NDBG_GEN,"send_address: send id %02x", id); - err = NANDBUS_SEND_ADDRESS(nandbus, id); - } - - if (!err && col != -1) { - for (i = 0; i < ivar->cols; i++, col >>= 8) { - addr = (uint8_t)(col & 0xff); - nand_debug(NDBG_GEN,"send_address: send address column " - "%02x", addr); - err = NANDBUS_SEND_ADDRESS(nandbus, addr); - if (err) - break; - } - } - - if (!err && row != -1) { - for (i = 0; i < ivar->rows; i++, row >>= 8) { - addr = (uint8_t)(row & 0xff); - nand_debug(NDBG_GEN,"send_address: send address row " - "%02x", addr); - err = NANDBUS_SEND_ADDRESS(nandbus, addr); - if (err) - break; - } - } - - return (err); -} - -static int -generic_is_blk_bad(device_t dev, uint32_t block, uint8_t *bad) -{ - struct nand_chip *chip; - int page_number, err, i; - uint8_t *oob; - - chip = device_get_softc(dev); - - oob = malloc(chip->chip_geom.oob_size, M_NAND, M_WAITOK); - - page_number = block * chip->chip_geom.pgs_per_blk; - *bad = 0; - - /* Check OOB of first and second page */ - for (i = 0; i < 2; i++) { - err = NAND_READ_OOB(dev, page_number + i, oob, - chip->chip_geom.oob_size, 0); - if (err) { - device_printf(dev, "%s: cannot allocate OOB\n", - __func__); - free(oob, M_NAND); - return (ENOMEM); - } - - if (!oob[0]) { - *bad = 1; - free(oob, M_NAND); - return (0); - } - } - - free(oob, M_NAND); - - return (0); -} - -static int -generic_get_ecc(device_t dev, void *buf, void *ecc, int *needwrite) -{ - struct nand_chip *chip = device_get_softc(dev); - struct chip_geom *cg = &chip->chip_geom; - - return (NANDBUS_GET_ECC(device_get_parent(dev), buf, cg->page_size, - ecc, needwrite)); -} - -static int -generic_correct_ecc(device_t dev, void *buf, void *readecc, void *calcecc) -{ - struct nand_chip *chip = device_get_softc(dev); - struct chip_geom *cg = &chip->chip_geom; - - return (NANDBUS_CORRECT_ECC(device_get_parent(dev), buf, - cg->page_size, readecc, calcecc)); -} - - -#if 0 -int -nand_chng_read_col(device_t nand, uint32_t col, void *buf, size_t len) -{ - struct nand_chip *chip; - device_t nandbus; - - chip = device_get_softc(nand); - nandbus = device_get_parent(nand); - - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_CHNG_READ_COL)) - return (ENXIO); - - if (NANDBUS_SEND_ADDRESS(nandbus, -1, col, -1)) - return (ENXIO); - - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_CHNG_READ_COL_END)) - return (ENXIO); - - if (NANDBUS_START_COMMAND(nandbus)) - return (ENXIO); - - if (buf != NULL && len > 0) - NANDBUS_READ_BUFFER(nandbus, buf, len); - - return (0); -} - -int -nand_chng_write_col(device_t dev, uint32_t col, void *buf, - size_t len) -{ - struct nand_chip *chip; - device_t nandbus; - - chip = device_get_softc(dev); - nandbus = device_get_parent(dev); - - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_CHNG_WRITE_COL)) - return (ENXIO); - - if (NANDBUS_SEND_ADDRESS(nandbus, -1, col, -1)) - return (ENXIO); - - if (buf != NULL && len > 0) - NANDBUS_WRITE_BUFFER(nandbus, buf, len); - - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_CHNG_READ_COL_END)) - return (ENXIO); - - if (NANDBUS_START_COMMAND(nandbus)) - return (ENXIO); - - return (0); -} - -int -nand_copyback_read(device_t dev, uint32_t page, uint32_t col, - void *buf, size_t len) -{ - struct nand_chip *chip; - struct page_stat *pg_stat; - device_t nandbus; - uint32_t row; - - nand_debug(NDBG_GEN," raw read page %x[%x] at %x", page, col, len); - chip = device_get_softc(dev); - nandbus = device_get_parent(dev); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - - if (send_read_page(nand, NAND_CMD_READ, NAND_CMD_READ_CPBK, row, 0)) - return (ENXIO); - - DELAY(chip->t_r); - if (check_fail(nandbus)) - return (ENXIO); - - if (buf != NULL && len > 0) - NANDBUS_READ_BUFFER(nandbus, buf, len); - - pg_stat = &(chip->pg_stat[page]); - pg_stat->page_raw_read++; - - return (0); -} - -int -nand_copyback_prog(device_t dev, uint32_t page, uint32_t col, - void *buf, size_t len) -{ - struct nand_chip *chip; - struct page_stat *pg_stat; - device_t nandbus; - uint32_t row; - - nand_debug(NDBG_GEN,"copyback prog page %x[%x]", page, len); - chip = device_get_softc(dev); - nandbus = device_get_parent(dev); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - - if (!can_write(nandbus)) - return (ENXIO); - - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_CHNG_WRITE_COL)) - return (ENXIO); - - if (NANDBUS_SEND_ADDRESS(nandbus, row, col, -1)) - return (ENXIO); - - if (buf != NULL && len > 0) - NANDBUS_WRITE_BUFFER(nandbus, buf, len); - - if (send_end_program_page(nandbus, NAND_CMD_PROG_END)) - return (ENXIO); - - DELAY(chip->t_prog); - - if (check_fail(nandbus)) - return (ENXIO); - - pg_stat = &(chip->pg_stat[page]); - pg_stat->page_raw_written++; - - return (0); -} - -int -nand_copyback_prog_intlv(device_t dev, uint32_t page) -{ - struct nand_chip *chip; - struct page_stat *pg_stat; - device_t nandbus; - uint32_t row; - - nand_debug(NDBG_GEN,"cache prog page %x", page); - chip = device_get_softc(dev); - nandbus = device_get_parent(dev); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - - if (!can_write(nandbus)) - return (ENXIO); - - if (send_start_program_page(nand, row, 0)) - return (ENXIO); - - if (send_end_program_page(nandbus, NAND_CMD_PROG_INTLV)) - return (ENXIO); - - DELAY(chip->t_prog); - - if (check_fail(nandbus)) - return (ENXIO); - - pg_stat = &(chip->pg_stat[page]); - pg_stat->page_raw_written++; - - return (0); -} - -int -nand_prog_cache(device_t dev, uint32_t page, uint32_t col, - void *buf, size_t len, uint8_t end) -{ - struct nand_chip *chip; - struct page_stat *pg_stat; - device_t nandbus; - uint32_t row; - uint8_t command; - - nand_debug(NDBG_GEN,"cache prog page %x[%x]", page, len); - chip = device_get_softc(dev); - nandbus = device_get_parent(dev); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - - if (!can_write(nandbus)) - return (ENXIO); - - if (send_start_program_page(dev, row, 0)) - return (ENXIO); - - NANDBUS_WRITE_BUFFER(nandbus, buf, len); - - if (end) - command = NAND_CMD_PROG_END; - else - command = NAND_CMD_PROG_CACHE; - - if (send_end_program_page(nandbus, command)) - return (ENXIO); - - DELAY(chip->t_prog); - - if (check_fail(nandbus)) - return (ENXIO); - - pg_stat = &(chip->pg_stat[page]); - pg_stat->page_raw_written++; - - return (0); -} - -int -nand_read_cache(device_t dev, uint32_t page, uint32_t col, - void *buf, size_t len, uint8_t end) -{ - struct nand_chip *chip; - struct page_stat *pg_stat; - device_t nandbus; - uint32_t row; - uint8_t command; - - nand_debug(NDBG_GEN,"cache read page %x[%x] ", page, len); - chip = device_get_softc(dev); - nandbus = device_get_parent(dev); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - - if (page != -1) { - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_READ)) - return (ENXIO); - - if (NANDBUS_SEND_ADDRESS(nandbus, row, col, -1)) - return (ENXIO); - } - - if (end) - command = NAND_CMD_READ_CACHE_END; - else - command = NAND_CMD_READ_CACHE; - - if (NANDBUS_SEND_COMMAND(nandbus, command)) - return (ENXIO); - - if (NANDBUS_START_COMMAND(nandbus)) - return (ENXIO); - - DELAY(chip->t_r); - if (check_fail(nandbus)) - return (ENXIO); - - if (buf != NULL && len > 0) - NANDBUS_READ_BUFFER(nandbus, buf, len); - - pg_stat = &(chip->pg_stat[page]); - pg_stat->page_raw_read++; - - return (0); -} - -int -nand_get_feature(device_t dev, uint8_t feat, void *buf) -{ - struct nand_chip *chip; - device_t nandbus; - - nand_debug(NDBG_GEN,"nand get feature"); - - chip = device_get_softc(dev); - nandbus = device_get_parent(dev); - - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_GET_FEATURE)) - return (ENXIO); - - if (NANDBUS_SEND_ADDRESS(nandbus, -1, -1, feat)) - return (ENXIO); - - if (NANDBUS_START_COMMAND(nandbus)) - return (ENXIO); - - DELAY(chip->t_r); - NANDBUS_READ_BUFFER(nandbus, buf, 4); - - return (0); -} - -int -nand_set_feature(device_t dev, uint8_t feat, void *buf) -{ - struct nand_chip *chip; - device_t nandbus; - - nand_debug(NDBG_GEN,"nand set feature"); - - chip = device_get_softc(dev); - nandbus = device_get_parent(dev); - - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_SET_FEATURE)) - return (ENXIO); - - if (NANDBUS_SEND_ADDRESS(nandbus, -1, -1, feat)) - return (ENXIO); - - NANDBUS_WRITE_BUFFER(nandbus, buf, 4); - - if (NANDBUS_START_COMMAND(nandbus)) - return (ENXIO); - - return (0); -} -#endif diff --git a/sys/dev/nand/nand_geom.c b/sys/dev/nand/nand_geom.c deleted file mode 100644 index b814ffc4e0a9..000000000000 --- a/sys/dev/nand/nand_geom.c +++ /dev/null @@ -1,467 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/conf.h> -#include <sys/bus.h> -#include <sys/malloc.h> -#include <sys/uio.h> -#include <sys/bio.h> -#include <geom/geom.h> -#include <geom/geom_disk.h> - -#include <dev/nand/nand.h> -#include <dev/nand/nandbus.h> -#include <dev/nand/nand_dev.h> -#include "nand_if.h" -#include "nandbus_if.h" - -#define BIO_NAND_STD ((void *)1) -#define BIO_NAND_RAW ((void *)2) - -static disk_ioctl_t nand_ioctl; -static disk_getattr_t nand_getattr; -static disk_strategy_t nand_strategy; -static disk_strategy_t nand_strategy_raw; - -static int -nand_read(struct nand_chip *chip, uint32_t offset, void *buf, uint32_t len) -{ - - nand_debug(NDBG_GEOM, "Read from chip %d [%p] at %d", chip->num, chip, - offset); - - return (nand_read_pages(chip, offset, buf, len)); -} - -static int -nand_write(struct nand_chip *chip, uint32_t offset, void* buf, uint32_t len) -{ - - nand_debug(NDBG_GEOM, "Write to chip %d [%p] at %d", chip->num, chip, - offset); - - return (nand_prog_pages(chip, offset, buf, len)); -} - -static int -nand_read_raw(struct nand_chip *chip, uint32_t offset, void *buf, uint32_t len) -{ - nand_debug(NDBG_GEOM, "Raw read from chip %d [%p] at %d", chip->num, - chip, offset); - - return (nand_read_pages_raw(chip, offset, buf, len)); -} - -static int -nand_write_raw(struct nand_chip *chip, uint32_t offset, void *buf, uint32_t len) -{ - - nand_debug(NDBG_GEOM, "Raw write to chip %d [%p] at %d", chip->num, - chip, offset); - - return (nand_prog_pages_raw(chip, offset, buf, len)); -} - -static void -nand_strategy(struct bio *bp) -{ - struct nand_chip *chip; - - chip = (struct nand_chip *)bp->bio_disk->d_drv1; - - bp->bio_driver1 = BIO_NAND_STD; - - nand_debug(NDBG_GEOM, "Strategy %s on chip %d [%p]", - bp->bio_cmd == BIO_READ ? "READ" : - (bp->bio_cmd == BIO_WRITE ? "WRITE" : - (bp->bio_cmd == BIO_DELETE ? "DELETE" : "UNKNOWN")), - chip->num, chip); - - mtx_lock(&chip->qlock); - bioq_insert_tail(&chip->bioq, bp); - mtx_unlock(&chip->qlock); - taskqueue_enqueue(chip->tq, &chip->iotask); -} - -static void -nand_strategy_raw(struct bio *bp) -{ - struct nand_chip *chip; - - chip = (struct nand_chip *)bp->bio_disk->d_drv1; - - /* Inform taskqueue that it's a raw access */ - bp->bio_driver1 = BIO_NAND_RAW; - - nand_debug(NDBG_GEOM, "Strategy %s on chip %d [%p]", - bp->bio_cmd == BIO_READ ? "READ" : - (bp->bio_cmd == BIO_WRITE ? "WRITE" : - (bp->bio_cmd == BIO_DELETE ? "DELETE" : "UNKNOWN")), - chip->num, chip); - - mtx_lock(&chip->qlock); - bioq_insert_tail(&chip->bioq, bp); - mtx_unlock(&chip->qlock); - taskqueue_enqueue(chip->tq, &chip->iotask); -} - -static int -nand_oob_access(struct nand_chip *chip, uint32_t page, uint32_t offset, - uint32_t len, uint8_t *data, uint8_t write) -{ - struct chip_geom *cg; - int ret = 0; - - cg = &chip->chip_geom; - - if (!write) - ret = nand_read_oob(chip, page, data, cg->oob_size); - else - ret = nand_prog_oob(chip, page, data, cg->oob_size); - - return (ret); -} - -static int -nand_getattr(struct bio *bp) -{ - struct nand_chip *chip; - struct chip_geom *cg; - device_t dev; - int val; - - if (bp->bio_disk == NULL || bp->bio_disk->d_drv1 == NULL) - return (ENXIO); - - chip = (struct nand_chip *)bp->bio_disk->d_drv1; - cg = &(chip->chip_geom); - - dev = device_get_parent(chip->dev); - dev = device_get_parent(dev); - - if (strcmp(bp->bio_attribute, "NAND::device") == 0) { - if (bp->bio_length != sizeof(dev)) - return (EFAULT); - bcopy(&dev, bp->bio_data, sizeof(dev)); - } else { - if (strcmp(bp->bio_attribute, "NAND::oobsize") == 0) - val = cg->oob_size; - else if (strcmp(bp->bio_attribute, "NAND::pagesize") == 0) - val = cg->page_size; - else if (strcmp(bp->bio_attribute, "NAND::blocksize") == 0) - val = cg->block_size; - else - return (-1); - if (bp->bio_length != sizeof(val)) - return (EFAULT); - bcopy(&val, bp->bio_data, sizeof(val)); - } - bp->bio_completed = bp->bio_length; - return (0); -} - -static int -nand_ioctl(struct disk *ndisk, u_long cmd, void *data, int fflag, - struct thread *td) -{ - struct nand_chip *chip; - struct chip_geom *cg; - struct nand_oob_rw *oob_rw = NULL; - struct nand_raw_rw *raw_rw = NULL; - device_t nandbus; - size_t bufsize = 0, len = 0; - size_t raw_size; - off_t off; - uint8_t *buf = NULL; - int ret = 0; - uint8_t status; - - chip = (struct nand_chip *)ndisk->d_drv1; - cg = &chip->chip_geom; - nandbus = device_get_parent(chip->dev); - - if ((cmd == NAND_IO_RAW_READ) || (cmd == NAND_IO_RAW_PROG)) { - raw_rw = (struct nand_raw_rw *)data; - raw_size = cg->pgs_per_blk * (cg->page_size + cg->oob_size); - - /* Check if len is not bigger than chip size */ - if (raw_rw->len > raw_size) - return (EFBIG); - - /* - * Do not ask for too much memory, in case of large transfers - * read/write in 16-pages chunks - */ - bufsize = 16 * (cg->page_size + cg->oob_size); - if (raw_rw->len < bufsize) - bufsize = raw_rw->len; - - buf = malloc(bufsize, M_NAND, M_WAITOK); - len = raw_rw->len; - off = 0; - } - - switch (cmd) { - case NAND_IO_ERASE: - ret = nand_erase_blocks(chip, ((off_t *)data)[0], - ((off_t *)data)[1]); - break; - - case NAND_IO_OOB_READ: - oob_rw = (struct nand_oob_rw *)data; - ret = nand_oob_access(chip, oob_rw->page, 0, - oob_rw->len, oob_rw->data, 0); - break; - - case NAND_IO_OOB_PROG: - oob_rw = (struct nand_oob_rw *)data; - ret = nand_oob_access(chip, oob_rw->page, 0, - oob_rw->len, oob_rw->data, 1); - break; - - case NAND_IO_GET_STATUS: - NANDBUS_LOCK(nandbus); - ret = NANDBUS_GET_STATUS(nandbus, &status); - if (ret == 0) - *(uint8_t *)data = status; - NANDBUS_UNLOCK(nandbus); - break; - - case NAND_IO_RAW_PROG: - while (len > 0) { - if (len < bufsize) - bufsize = len; - - ret = copyin(raw_rw->data + off, buf, bufsize); - if (ret) - break; - ret = nand_prog_pages_raw(chip, raw_rw->off + off, buf, - bufsize); - if (ret) - break; - len -= bufsize; - off += bufsize; - } - break; - - case NAND_IO_RAW_READ: - while (len > 0) { - if (len < bufsize) - bufsize = len; - - ret = nand_read_pages_raw(chip, raw_rw->off + off, buf, - bufsize); - if (ret) - break; - - ret = copyout(buf, raw_rw->data + off, bufsize); - if (ret) - break; - len -= bufsize; - off += bufsize; - } - break; - - case NAND_IO_GET_CHIP_PARAM: - nand_get_chip_param(chip, (struct chip_param_io *)data); - break; - - default: - printf("Unknown nand_ioctl request \n"); - ret = EIO; - } - - if (buf) - free(buf, M_NAND); - - return (ret); -} - -static void -nand_io_proc(void *arg, int pending) -{ - struct nand_chip *chip = arg; - struct bio *bp; - int err = 0; - - for (;;) { - mtx_lock(&chip->qlock); - bp = bioq_takefirst(&chip->bioq); - mtx_unlock(&chip->qlock); - if (bp == NULL) - break; - - if (bp->bio_driver1 == BIO_NAND_STD) { - if (bp->bio_cmd == BIO_READ) { - err = nand_read(chip, - bp->bio_offset & 0xffffffff, - bp->bio_data, bp->bio_bcount); - } else if (bp->bio_cmd == BIO_WRITE) { - err = nand_write(chip, - bp->bio_offset & 0xffffffff, - bp->bio_data, bp->bio_bcount); - } - } else if (bp->bio_driver1 == BIO_NAND_RAW) { - if (bp->bio_cmd == BIO_READ) { - err = nand_read_raw(chip, - bp->bio_offset & 0xffffffff, - bp->bio_data, bp->bio_bcount); - } else if (bp->bio_cmd == BIO_WRITE) { - err = nand_write_raw(chip, - bp->bio_offset & 0xffffffff, - bp->bio_data, bp->bio_bcount); - } - } else - panic("Unknown access type in bio->bio_driver1\n"); - - if (bp->bio_cmd == BIO_DELETE) { - nand_debug(NDBG_GEOM, "Delete on chip%d offset %lld " - "length %ld\n", chip->num, bp->bio_offset, - bp->bio_bcount); - err = nand_erase_blocks(chip, - bp->bio_offset & 0xffffffff, - bp->bio_bcount); - } - - if (err == 0 || err == ECC_CORRECTABLE) - bp->bio_resid = 0; - else { - nand_debug(NDBG_GEOM,"nand_[read|write|erase_blocks] " - "error: %d\n", err); - - bp->bio_error = EIO; - bp->bio_flags |= BIO_ERROR; - bp->bio_resid = bp->bio_bcount; - } - biodone(bp); - } -} - -int -create_geom_disk(struct nand_chip *chip) -{ - struct disk *ndisk, *rdisk; - - /* Create the disk device */ - ndisk = disk_alloc(); - ndisk->d_strategy = nand_strategy; - ndisk->d_ioctl = nand_ioctl; - ndisk->d_getattr = nand_getattr; - ndisk->d_name = "gnand"; - ndisk->d_drv1 = chip; - ndisk->d_maxsize = chip->chip_geom.block_size; - ndisk->d_sectorsize = chip->chip_geom.page_size; - ndisk->d_mediasize = chip->chip_geom.chip_size; - ndisk->d_unit = chip->num + - 10 * device_get_unit(device_get_parent(chip->dev)); - - /* - * When using BBT, make two last blocks of device unavailable - * to user (because those are used to store BBT table). - */ - if (chip->bbt != NULL) - ndisk->d_mediasize -= (2 * chip->chip_geom.block_size); - - ndisk->d_flags = DISKFLAG_CANDELETE; - - snprintf(ndisk->d_ident, sizeof(ndisk->d_ident), - "nand: Man:0x%02x Dev:0x%02x", chip->id.man_id, chip->id.dev_id); - ndisk->d_rotation_rate = DISK_RR_NON_ROTATING; - - disk_create(ndisk, DISK_VERSION); - - /* Create the RAW disk device */ - rdisk = disk_alloc(); - rdisk->d_strategy = nand_strategy_raw; - rdisk->d_ioctl = nand_ioctl; - rdisk->d_getattr = nand_getattr; - rdisk->d_name = "gnand.raw"; - rdisk->d_drv1 = chip; - rdisk->d_maxsize = chip->chip_geom.block_size; - rdisk->d_sectorsize = chip->chip_geom.page_size; - rdisk->d_mediasize = chip->chip_geom.chip_size; - rdisk->d_unit = chip->num + - 10 * device_get_unit(device_get_parent(chip->dev)); - - rdisk->d_flags = DISKFLAG_CANDELETE; - - snprintf(rdisk->d_ident, sizeof(rdisk->d_ident), - "nand_raw: Man:0x%02x Dev:0x%02x", chip->id.man_id, - chip->id.dev_id); - rdisk->d_rotation_rate = DISK_RR_NON_ROTATING; - - disk_create(rdisk, DISK_VERSION); - - chip->ndisk = ndisk; - chip->rdisk = rdisk; - - mtx_init(&chip->qlock, "NAND I/O lock", NULL, MTX_DEF); - bioq_init(&chip->bioq); - - TASK_INIT(&chip->iotask, 0, nand_io_proc, chip); - chip->tq = taskqueue_create("nand_taskq", M_WAITOK, - taskqueue_thread_enqueue, &chip->tq); - taskqueue_start_threads(&chip->tq, 1, PI_DISK, "nand taskq"); - - if (bootverbose) - device_printf(chip->dev, "Created gnand%d for chip [0x%0x, " - "0x%0x]\n", ndisk->d_unit, chip->id.man_id, - chip->id.dev_id); - - return (0); -} - -void -destroy_geom_disk(struct nand_chip *chip) -{ - struct bio *bp; - - taskqueue_free(chip->tq); - disk_destroy(chip->ndisk); - disk_destroy(chip->rdisk); - - mtx_lock(&chip->qlock); - for (;;) { - bp = bioq_takefirst(&chip->bioq); - if (bp == NULL) - break; - bp->bio_error = EIO; - bp->bio_flags |= BIO_ERROR; - bp->bio_resid = bp->bio_bcount; - - biodone(bp); - } - mtx_unlock(&chip->qlock); - - mtx_destroy(&chip->qlock); -} diff --git a/sys/dev/nand/nand_id.c b/sys/dev/nand/nand_id.c deleted file mode 100644 index 7259c951bfc9..000000000000 --- a/sys/dev/nand/nand_id.c +++ /dev/null @@ -1,70 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> - -#include <dev/nand/nand.h> - -struct nand_params nand_ids[] = { - { { NAND_MAN_SAMSUNG, 0x75 }, "Samsung K9F5608U0B NAND 32MiB 8-bit", - 0x20, 0x200, 0x10, 0x20, 0 }, - { { NAND_MAN_SAMSUNG, 0xf1 }, "Samsung K9F1G08U0A NAND 128MiB 3,3V 8-bit", - 0x80, 0x800, 0x40, 0x40, 0 }, - { { NAND_MAN_SAMSUNG, 0xda }, "Samsung K9F2G08U0A NAND 256MiB 3,3V 8-bit", - 0x100, 0x800, 0x40, 0x40, 0 }, - { { NAND_MAN_SAMSUNG, 0xdc }, "Samsung NAND 512MiB 3,3V 8-bit", - 0x200, 0x800, 0x40, 0x40, 0 }, - { { NAND_MAN_SAMSUNG, 0xd3 }, "Samsung NAND 1GiB 3,3V 8-bit", - 0x400, 0x800, 0x40, 0x40, 0 }, - { { NAND_MAN_HYNIX, 0x76 }, "Hynix NAND 64MiB 3,3V 8-bit", - 0x40, 0x200, 0x10, 0x20, 0 }, - { { NAND_MAN_HYNIX, 0xdc }, "Hynix NAND 512MiB 3,3V 8-bit", - 0x200, 0x800, 0x40, 0x40, 0 }, - { { NAND_MAN_HYNIX, 0x79 }, "Hynix NAND 128MB 3,3V 8-bit", - 0x80, 0x200, 0x10, 0x20, 0 }, - { { NAND_MAN_STMICRO, 0xf1 }, "STMicro 128MB 3,3V 8-bit", - 0x80, 2048, 64, 0x40, 0 }, - { { NAND_MAN_MICRON, 0xcc }, "Micron NAND 512MiB 3,3V 16-bit", - 0x200, 2048, 64, 0x40, 0 }, -}; - -struct nand_params *nand_get_params(struct nand_id *id) -{ - int i; - - for (i = 0; i < nitems(nand_ids); i++) - if (nand_ids[i].id.man_id == id->man_id && - nand_ids[i].id.dev_id == id->dev_id) - return (&nand_ids[i]); - - return (NULL); -} diff --git a/sys/dev/nand/nand_if.m b/sys/dev/nand/nand_if.m deleted file mode 100644 index 49c8879b6890..000000000000 --- a/sys/dev/nand/nand_if.m +++ /dev/null @@ -1,168 +0,0 @@ -#- -# Copyright (C) 2009-2012 Semihalf -# 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$ - -# NAND chip interface description -# - -#include <sys/bus.h> -#include <dev/nand/nand.h> - -INTERFACE nand; - -CODE { - static int nand_method_not_supported(device_t dev) - { - return (ENOENT); - } -}; - -# Read NAND page -# -# Return values: -# 0: Success -# -METHOD int read_page { - device_t dev; - uint32_t page; - void* buf; - uint32_t len; - uint32_t offset; -}; - -# Program NAND page -# -# Return values: -# 0: Success -# -METHOD int program_page { - device_t dev; - uint32_t page; - void* buf; - uint32_t len; - uint32_t offset; -}; - -# Program NAND page interleaved -# -# Return values: -# 0: Success -# -METHOD int program_page_intlv { - device_t dev; - uint32_t page; - void* buf; - uint32_t len; - uint32_t offset; -} DEFAULT nand_method_not_supported; - -# Read NAND oob -# -# Return values: -# 0: Success -# -METHOD int read_oob { - device_t dev; - uint32_t page; - void* buf; - uint32_t len; - uint32_t offset; -}; - -# Program NAND oob -# -# Return values: -# 0: Success -# -METHOD int program_oob { - device_t dev; - uint32_t page; - void* buf; - uint32_t len; - uint32_t offset; -}; - -# Erase NAND block -# -# Return values: -# 0: Success -# -METHOD int erase_block { - device_t dev; - uint32_t block; -}; - -# Erase NAND block interleaved -# -# Return values: -# 0: Success -# -METHOD int erase_block_intlv { - device_t dev; - uint32_t block; -} DEFAULT nand_method_not_supported; - -# NAND get status -# -# Return values: -# 0: Success -# -METHOD int get_status { - device_t dev; - uint8_t *status; -}; - -# NAND check if block is bad -# -# Return values: -# 0: Success -# -METHOD int is_blk_bad { - device_t dev; - uint32_t block_number; - uint8_t *bad; -}; - -# NAND get ECC -# -# -METHOD int get_ecc { - device_t dev; - void *buf; - void *ecc; - int *needwrite; -}; - -# NAND correct ECC -# -# -METHOD int correct_ecc { - device_t dev; - void *buf; - void *readecc; - void *calcecc; -}; - diff --git a/sys/dev/nand/nandbus.c b/sys/dev/nand/nandbus.c deleted file mode 100644 index 003c1797af64..000000000000 --- a/sys/dev/nand/nandbus.c +++ /dev/null @@ -1,542 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/socket.h> -#include <sys/malloc.h> -#include <sys/module.h> -#include <sys/bus.h> -#include <sys/proc.h> -#include <sys/lock.h> -#include <sys/mutex.h> -#include <sys/condvar.h> - -#include <dev/nand/nand.h> -#include <dev/nand/nandbus.h> -#include "nand_if.h" -#include "nandbus_if.h" -#include "nfc_if.h" - -#define NAND_NCS 4 - -static int nandbus_probe(device_t dev); -static int nandbus_attach(device_t dev); -static int nandbus_detach(device_t dev); - -static int nandbus_child_location_str(device_t, device_t, char *, size_t); -static int nandbus_child_pnpinfo_str(device_t, device_t, char *, size_t); - -static int nandbus_get_status(device_t, uint8_t *); -static void nandbus_read_buffer(device_t, void *, uint32_t); -static int nandbus_select_cs(device_t, uint8_t); -static int nandbus_send_command(device_t, uint8_t); -static int nandbus_send_address(device_t, uint8_t); -static int nandbus_start_command(device_t); -static int nandbus_wait_ready(device_t, uint8_t *); -static void nandbus_write_buffer(device_t, void *, uint32_t); -static int nandbus_get_ecc(device_t, void *, uint32_t, void *, int *); -static int nandbus_correct_ecc(device_t, void *, int, void *, void *); -static void nandbus_lock(device_t); -static void nandbus_unlock(device_t); - -static int nand_readid(device_t, uint8_t *, uint8_t *); -static int nand_probe_onfi(device_t, uint8_t *); -static int nand_reset(device_t); - -struct nandbus_softc { - device_t dev; - struct cv nandbus_cv; - struct mtx nandbus_mtx; - uint8_t busy; -}; - -static device_method_t nandbus_methods[] = { - /* device interface */ - DEVMETHOD(device_probe, nandbus_probe), - DEVMETHOD(device_attach, nandbus_attach), - DEVMETHOD(device_detach, nandbus_detach), - DEVMETHOD(device_shutdown, bus_generic_shutdown), - - /* bus interface */ - DEVMETHOD(bus_print_child, bus_generic_print_child), - DEVMETHOD(bus_driver_added, bus_generic_driver_added), - DEVMETHOD(bus_child_pnpinfo_str, nandbus_child_pnpinfo_str), - DEVMETHOD(bus_child_location_str, nandbus_child_location_str), - - /* nandbus interface */ - DEVMETHOD(nandbus_get_status, nandbus_get_status), - DEVMETHOD(nandbus_read_buffer, nandbus_read_buffer), - DEVMETHOD(nandbus_select_cs, nandbus_select_cs), - DEVMETHOD(nandbus_send_command, nandbus_send_command), - DEVMETHOD(nandbus_send_address, nandbus_send_address), - DEVMETHOD(nandbus_start_command,nandbus_start_command), - DEVMETHOD(nandbus_wait_ready, nandbus_wait_ready), - DEVMETHOD(nandbus_write_buffer, nandbus_write_buffer), - DEVMETHOD(nandbus_get_ecc, nandbus_get_ecc), - DEVMETHOD(nandbus_correct_ecc, nandbus_correct_ecc), - DEVMETHOD(nandbus_lock, nandbus_lock), - DEVMETHOD(nandbus_unlock, nandbus_unlock), - { 0, 0 } -}; - -devclass_t nandbus_devclass; - -driver_t nandbus_driver = { - "nandbus", - nandbus_methods, - sizeof(struct nandbus_softc) -}; - -DRIVER_MODULE(nandbus, nand, nandbus_driver, nandbus_devclass, 0, 0); - -int -nandbus_create(device_t nfc) -{ - device_t child; - - child = device_add_child(nfc, "nandbus", -1); - if (!child) - return (ENODEV); - - bus_generic_attach(nfc); - - return(0); -} - -void -nandbus_destroy(device_t nfc) -{ - device_t *children; - int nchildren, i; - - mtx_lock(&Giant); - /* Detach & delete all children */ - if (!device_get_children(nfc, &children, &nchildren)) { - for (i = 0; i < nchildren; i++) - device_delete_child(nfc, children[i]); - - free(children, M_TEMP); - } - mtx_unlock(&Giant); -} - -static int -nandbus_probe(device_t dev) -{ - - device_set_desc(dev, "NAND bus"); - - return (0); -} - -static int -nandbus_attach(device_t dev) -{ - device_t child, nfc; - struct nand_id chip_id; - struct nandbus_softc *sc; - struct nandbus_ivar *ivar; - struct nand_softc *nfc_sc; - struct nand_params *chip_params; - uint8_t cs, onfi; - - sc = device_get_softc(dev); - sc->dev = dev; - - nfc = device_get_parent(dev); - nfc_sc = device_get_softc(nfc); - - mtx_init(&sc->nandbus_mtx, "nandbus lock", NULL, MTX_DEF); - cv_init(&sc->nandbus_cv, "nandbus cv"); - - /* Check each possible CS for existing nand devices */ - for (cs = 0; cs < NAND_NCS; cs++) { - nand_debug(NDBG_BUS,"probe chip select %x", cs); - - /* Select & reset chip */ - if (nandbus_select_cs(dev, cs)) - break; - - if (nand_reset(dev)) - continue; - - /* Read manufacturer and device id */ - if (nand_readid(dev, &chip_id.man_id, &chip_id.dev_id)) - continue; - - if (chip_id.man_id == 0xff) - continue; - - /* - * First try to get info from the table. If that fails, see if - * the chip can provide ONFI info. We check the table first to - * allow table entries to override info from chips that are - * known to provide bad ONFI data. - */ - onfi = 0; - chip_params = nand_get_params(&chip_id); - if (chip_params == NULL) { - nand_probe_onfi(dev, &onfi); - } - - /* - * At this point it appears there is a chip at this chipselect, - * so if we can't work with it, whine about it. - */ - if (chip_params == NULL && onfi == 0) { - if (bootverbose || (nand_debug_flag & NDBG_BUS)) - printf("Chip params not found, chipsel: %d " - "(manuf: 0x%0x, chipid: 0x%0x, onfi: %d)\n", - cs, chip_id.man_id, chip_id.dev_id, onfi); - continue; - } - - ivar = malloc(sizeof(struct nandbus_ivar), - M_NAND, M_WAITOK); - - if (onfi == 1) { - ivar->cs = cs; - ivar->cols = 0; - ivar->rows = 0; - ivar->params = NULL; - ivar->man_id = chip_id.man_id; - ivar->dev_id = chip_id.dev_id; - ivar->is_onfi = onfi; - ivar->chip_cdev_name = nfc_sc->chip_cdev_name; - - child = device_add_child(dev, NULL, -1); - device_set_ivars(child, ivar); - continue; - } - - ivar->cs = cs; - ivar->cols = 1; - ivar->rows = 2; - ivar->params = chip_params; - ivar->man_id = chip_id.man_id; - ivar->dev_id = chip_id.dev_id; - ivar->is_onfi = onfi; - ivar->chip_cdev_name = nfc_sc->chip_cdev_name; - - /* - * Check what type of device we have. - * devices bigger than 32MiB have on more row (3) - */ - if (chip_params->chip_size > 32) - ivar->rows++; - /* Large page devices have one more col (2) */ - if (chip_params->chip_size >= 128 && - chip_params->page_size > 512) - ivar->cols++; - - child = device_add_child(dev, NULL, -1); - device_set_ivars(child, ivar); - } - - bus_generic_attach(dev); - return (0); -} - -static int -nandbus_detach(device_t dev) -{ - struct nandbus_softc *sc; - - sc = device_get_softc(dev); - - bus_generic_detach(dev); - - mtx_destroy(&sc->nandbus_mtx); - cv_destroy(&sc->nandbus_cv); - - return (0); -} - -static int -nandbus_child_location_str(device_t bus, device_t child, char *buf, - size_t buflen) -{ - struct nandbus_ivar *ivar = device_get_ivars(child); - - snprintf(buf, buflen, "at cs#%d", ivar->cs); - return (0); -} - -static int -nandbus_child_pnpinfo_str(device_t bus, device_t child, char *buf, - size_t buflen) -{ - // XXX man id, model id ???? - *buf = '\0'; - return (0); -} - -static int -nand_readid(device_t bus, uint8_t *man_id, uint8_t *dev_id) -{ - device_t nfc; - - if (!bus || !man_id || !dev_id) - return (EINVAL); - - nand_debug(NDBG_BUS,"read id"); - - nfc = device_get_parent(bus); - - if (NFC_SEND_COMMAND(nfc, NAND_CMD_READ_ID)) { - nand_debug(NDBG_BUS,"Error : could not send READ ID command"); - return (ENXIO); - } - - if (NFC_SEND_ADDRESS(nfc, 0)) { - nand_debug(NDBG_BUS,"Error : could not sent address to chip"); - return (ENXIO); - } - - if (NFC_START_COMMAND(nfc) != 0) { - nand_debug(NDBG_BUS,"Error : could not start command"); - return (ENXIO); - } - - DELAY(25); - - *man_id = NFC_READ_BYTE(nfc); - *dev_id = NFC_READ_BYTE(nfc); - - nand_debug(NDBG_BUS,"manufacturer id: %x chip id: %x", *man_id, - *dev_id); - - return (0); -} - -static int -nand_probe_onfi(device_t bus, uint8_t *onfi_compliant) -{ - device_t nfc; - char onfi_id[] = {'O', 'N', 'F', 'I', '\0'}; - int i; - - nand_debug(NDBG_BUS,"probing ONFI"); - - nfc = device_get_parent(bus); - - if (NFC_SEND_COMMAND(nfc, NAND_CMD_READ_ID)) { - nand_debug(NDBG_BUS,"Error : could not sent READ ID command"); - return (ENXIO); - } - - if (NFC_SEND_ADDRESS(nfc, ONFI_SIG_ADDR)) { - nand_debug(NDBG_BUS,"Error : could not sent address to chip"); - return (ENXIO); - } - - if (NFC_START_COMMAND(nfc) != 0) { - nand_debug(NDBG_BUS,"Error : could not start command"); - return (ENXIO); - } - for (i = 0; onfi_id[i] != '\0'; i++) - if (NFC_READ_BYTE(nfc) != onfi_id[i]) { - nand_debug(NDBG_BUS,"ONFI non-compliant"); - *onfi_compliant = 0; - return (0); - } - - nand_debug(NDBG_BUS,"ONFI compliant"); - *onfi_compliant = 1; - - return (0); -} - -static int -nand_reset(device_t bus) -{ - device_t nfc; - nand_debug(NDBG_BUS,"resetting..."); - - nfc = device_get_parent(bus); - - if (NFC_SEND_COMMAND(nfc, NAND_CMD_RESET) != 0) { - nand_debug(NDBG_BUS,"Error : could not sent RESET command"); - return (ENXIO); - } - - if (NFC_START_COMMAND(nfc) != 0) { - nand_debug(NDBG_BUS,"Error : could not start RESET command"); - return (ENXIO); - } - - DELAY(1000); - - return (0); -} - -void -nandbus_lock(device_t dev) -{ - struct nandbus_softc *sc; - - sc = device_get_softc(dev); - - mtx_lock(&sc->nandbus_mtx); - if (sc->busy) - cv_wait(&sc->nandbus_cv, &sc->nandbus_mtx); - sc->busy = 1; - mtx_unlock(&sc->nandbus_mtx); -} - -void -nandbus_unlock(device_t dev) -{ - struct nandbus_softc *sc; - - sc = device_get_softc(dev); - - mtx_lock(&sc->nandbus_mtx); - sc->busy = 0; - cv_signal(&sc->nandbus_cv); - mtx_unlock(&sc->nandbus_mtx); -} - -int -nandbus_select_cs(device_t dev, uint8_t cs) -{ - - return (NFC_SELECT_CS(device_get_parent(dev), cs)); -} - -int -nandbus_send_command(device_t dev, uint8_t command) -{ - int err; - - if ((err = NFC_SEND_COMMAND(device_get_parent(dev), command))) - nand_debug(NDBG_BUS,"Err: Could not send command %x, err %x", - command, err); - - return (err); -} - -int -nandbus_send_address(device_t dev, uint8_t address) -{ - int err; - - if ((err = NFC_SEND_ADDRESS(device_get_parent(dev), address))) - nand_debug(NDBG_BUS,"Err: Could not send address %x, err %x", - address, err); - - return (err); -} - -int -nandbus_start_command(device_t dev) -{ - int err; - - if ((err = NFC_START_COMMAND(device_get_parent(dev)))) - nand_debug(NDBG_BUS,"Err: Could not start command, err %x", - err); - - return (err); -} - -void -nandbus_read_buffer(device_t dev, void *buf, uint32_t len) -{ - - NFC_READ_BUF(device_get_parent(dev), buf, len); -} - -void -nandbus_write_buffer(device_t dev, void *buf, uint32_t len) -{ - - NFC_WRITE_BUF(device_get_parent(dev), buf, len); -} - -int -nandbus_get_status(device_t dev, uint8_t *status) -{ - int err; - - if ((err = NANDBUS_SEND_COMMAND(dev, NAND_CMD_STATUS))) - return (err); - if ((err = NANDBUS_START_COMMAND(dev))) - return (err); - - *status = NFC_READ_BYTE(device_get_parent(dev)); - - return (0); -} - -int -nandbus_wait_ready(device_t dev, uint8_t *status) -{ - struct timeval tv, tv2; - - tv2.tv_sec = 0; - tv2.tv_usec = 50 * 5000; /* 250ms */ - - getmicrotime(&tv); - timevaladd(&tv, &tv2); - - do { - if (NANDBUS_GET_STATUS(dev, status)) - return (ENXIO); - - if (*status & NAND_STATUS_RDY) - return (0); - - getmicrotime(&tv2); - } while (timevalcmp(&tv2, &tv, <=)); - - return (EBUSY); -} - -int -nandbus_get_ecc(device_t dev, void *buf, uint32_t pagesize, void *ecc, - int *needwrite) -{ - - return (NFC_GET_ECC(device_get_parent(dev), buf, pagesize, ecc, needwrite)); -} - -int -nandbus_correct_ecc(device_t dev, void *buf, int pagesize, void *readecc, - void *calcecc) -{ - - return (NFC_CORRECT_ECC(device_get_parent(dev), buf, pagesize, - readecc, calcecc)); -} - diff --git a/sys/dev/nand/nandbus.h b/sys/dev/nand/nandbus.h deleted file mode 100644 index 6dd4cbf26daa..000000000000 --- a/sys/dev/nand/nandbus.h +++ /dev/null @@ -1,51 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _NANDBUS_H_ -#define _NANDBUS_H_ - -struct nandbus_ivar { - uint8_t cs; - uint8_t cols; - uint8_t rows; - uint8_t man_id; - uint8_t dev_id; - uint8_t is_onfi; - char *chip_cdev_name; - struct nand_params *params; -}; - -extern devclass_t nandbus_devclass; -extern driver_t nandbus_driver; - -int nandbus_create(device_t nfc); -void nandbus_destroy(device_t nfc); - -#endif /* _NANDBUS_H_ */ diff --git a/sys/dev/nand/nandbus_if.m b/sys/dev/nand/nandbus_if.m deleted file mode 100644 index e914e18de661..000000000000 --- a/sys/dev/nand/nandbus_if.m +++ /dev/null @@ -1,100 +0,0 @@ -#- -# Copyright (C) 2009-2012 Semihalf -# 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$ - -# NAND bus interface description -# - -#include <sys/bus.h> -#include <dev/nand/nand.h> - -INTERFACE nandbus; - -METHOD int get_status { - device_t dev; - uint8_t * status; -}; - -METHOD void read_buffer { - device_t dev; - void * buf; - uint32_t len; -}; - -METHOD int select_cs { - device_t dev; - uint8_t cs; -}; - -METHOD int send_command { - device_t dev; - uint8_t command; -}; - -METHOD int send_address { - device_t dev; - uint8_t address; -}; - -METHOD int start_command { - device_t dev; -}; - -METHOD int wait_ready { - device_t dev; - uint8_t * status; -} - -METHOD void write_buffer { - device_t dev; - void * buf; - uint32_t len; -}; - -METHOD int get_ecc { - device_t dev; - void * buf; - uint32_t pagesize; - void * ecc; - int * needwrite; -}; - -METHOD int correct_ecc { - device_t dev; - void * buf; - int pagesize; - void * readecc; - void * calcecc; -}; - -METHOD void lock { - device_t dev; -}; - -METHOD void unlock { - device_t dev; -}; - diff --git a/sys/dev/nand/nandsim.c b/sys/dev/nand/nandsim.c deleted file mode 100644 index 4639a15700a2..000000000000 --- a/sys/dev/nand/nandsim.c +++ /dev/null @@ -1,670 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * 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. - */ - -/* Simulated NAND controller driver */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/proc.h> -#include <sys/bus.h> -#include <sys/conf.h> -#include <sys/kernel.h> -#include <sys/module.h> -#include <sys/malloc.h> - -#include <dev/nand/nand.h> -#include <dev/nand/nandsim.h> -#include <dev/nand/nandsim_chip.h> -#include <dev/nand/nandsim_log.h> -#include <dev/nand/nandsim_swap.h> - -struct sim_param sim; -struct sim_ctrl_conf ctrls[MAX_SIM_DEV]; - -static struct cdev *nandsim_dev; -static d_ioctl_t nandsim_ioctl; - -static void nandsim_init_sim_param(struct sim_param *); -static int nandsim_create_ctrl(struct sim_ctrl *); -static int nandsim_destroy_ctrl(int); -static int nandsim_ctrl_status(struct sim_ctrl *); -static int nandsim_create_chip(struct sim_chip *); -static int nandsim_destroy_chip(struct sim_ctrl_chip *); -static int nandsim_chip_status(struct sim_chip *); -static int nandsim_start_ctrl(int); -static int nandsim_stop_ctrl(int); -static int nandsim_inject_error(struct sim_error *); -static int nandsim_get_block_state(struct sim_block_state *); -static int nandsim_set_block_state(struct sim_block_state *); -static int nandsim_modify(struct sim_mod *); -static int nandsim_dump(struct sim_dump *); -static int nandsim_restore(struct sim_dump *); -static int nandsim_freeze(struct sim_ctrl_chip *); -static void nandsim_print_log(struct sim_log *); -static struct nandsim_chip *get_nandsim_chip(uint8_t, uint8_t); - -static struct cdevsw nandsim_cdevsw = { - .d_version = D_VERSION, - .d_flags = D_NEEDGIANT, - .d_ioctl = nandsim_ioctl, - .d_name = "nandsim", -}; - -int -nandsim_ioctl(struct cdev *dev, u_long cmd, caddr_t data, - int flags, struct thread *td) -{ - int ret = 0; - - switch (cmd) { - case NANDSIM_SIM_PARAM: - nandsim_init_sim_param((struct sim_param *)data); - break; - case NANDSIM_CREATE_CTRL: - ret = nandsim_create_ctrl((struct sim_ctrl *)data); - break; - case NANDSIM_DESTROY_CTRL: - ret = nandsim_destroy_ctrl(*(int *)data); - break; - case NANDSIM_STATUS_CTRL: - ret = nandsim_ctrl_status((struct sim_ctrl *)data); - break; - case NANDSIM_CREATE_CHIP: - ret = nandsim_create_chip((struct sim_chip *)data); - break; - case NANDSIM_DESTROY_CHIP: - ret = nandsim_destroy_chip((struct sim_ctrl_chip *)data); - break; - case NANDSIM_STATUS_CHIP: - ret = nandsim_chip_status((struct sim_chip *)data); - break; - case NANDSIM_MODIFY: - ret = nandsim_modify((struct sim_mod *)data); - break; - case NANDSIM_START_CTRL: - ret = nandsim_start_ctrl(*(int *)data); - break; - case NANDSIM_STOP_CTRL: - ret = nandsim_stop_ctrl(*(int *)data); - break; - case NANDSIM_INJECT_ERROR: - ret = nandsim_inject_error((struct sim_error *)data); - break; - case NANDSIM_SET_BLOCK_STATE: - ret = nandsim_set_block_state((struct sim_block_state *)data); - break; - case NANDSIM_GET_BLOCK_STATE: - ret = nandsim_get_block_state((struct sim_block_state *)data); - break; - case NANDSIM_PRINT_LOG: - nandsim_print_log((struct sim_log *)data); - break; - case NANDSIM_DUMP: - ret = nandsim_dump((struct sim_dump *)data); - break; - case NANDSIM_RESTORE: - ret = nandsim_restore((struct sim_dump *)data); - break; - case NANDSIM_FREEZE: - ret = nandsim_freeze((struct sim_ctrl_chip *)data); - break; - default: - ret = EINVAL; - break; - } - - return (ret); -} - -static void -nandsim_init_sim_param(struct sim_param *param) -{ - - if (!param) - return; - - nand_debug(NDBG_SIM,"log level:%d output %d", param->log_level, - param->log_output); - nandsim_log_level = param->log_level; - nandsim_log_output = param->log_output; -} - -static int -nandsim_create_ctrl(struct sim_ctrl *ctrl) -{ - struct sim_ctrl_conf *sim_ctrl; - - nand_debug(NDBG_SIM,"create controller num:%d cs:%d",ctrl->num, - ctrl->num_cs); - - if (ctrl->num >= MAX_SIM_DEV) { - return (EINVAL); - } - - sim_ctrl = &ctrls[ctrl->num]; - if(sim_ctrl->created) - return (EEXIST); - - sim_ctrl->num = ctrl->num; - sim_ctrl->num_cs = ctrl->num_cs; - sim_ctrl->ecc = ctrl->ecc; - memcpy(sim_ctrl->ecc_layout, ctrl->ecc_layout, - MAX_ECC_BYTES * sizeof(ctrl->ecc_layout[0])); - strlcpy(sim_ctrl->filename, ctrl->filename, - FILENAME_SIZE); - sim_ctrl->created = 1; - - return (0); -} - -static int -nandsim_destroy_ctrl(int ctrl_num) -{ - - nand_debug(NDBG_SIM,"destroy controller num:%d", ctrl_num); - - if (ctrl_num >= MAX_SIM_DEV) { - return (EINVAL); - } - - if (!ctrls[ctrl_num].created) { - return (ENODEV); - } - - if (ctrls[ctrl_num].running) { - return (EBUSY); - } - - memset(&ctrls[ctrl_num], 0, sizeof(ctrls[ctrl_num])); - - return (0); -} - -static int -nandsim_ctrl_status(struct sim_ctrl *ctrl) -{ - - nand_debug(NDBG_SIM,"status controller num:%d cs:%d",ctrl->num, - ctrl->num_cs); - - if (ctrl->num >= MAX_SIM_DEV) { - return (EINVAL); - } - - ctrl->num_cs = ctrls[ctrl->num].num_cs; - ctrl->ecc = ctrls[ctrl->num].ecc; - memcpy(ctrl->ecc_layout, ctrls[ctrl->num].ecc_layout, - MAX_ECC_BYTES * sizeof(ctrl->ecc_layout[0])); - strlcpy(ctrl->filename, ctrls[ctrl->num].filename, - FILENAME_SIZE); - ctrl->running = ctrls[ctrl->num].running; - ctrl->created = ctrls[ctrl->num].created; - - return (0); -} - -static int -nandsim_create_chip(struct sim_chip *chip) -{ - struct sim_chip *sim_chip; - - nand_debug(NDBG_SIM,"create chip num:%d at ctrl:%d", chip->num, - chip->ctrl_num); - - if (chip->ctrl_num >= MAX_SIM_DEV || - chip->num >= MAX_CTRL_CS) { - return (EINVAL); - } - - if (ctrls[chip->ctrl_num].chips[chip->num]) { - return (EEXIST); - } - - sim_chip = malloc(sizeof(*sim_chip), M_NANDSIM, - M_WAITOK); - if (sim_chip == NULL) { - return (ENOMEM); - } - - memcpy(sim_chip, chip, sizeof(*sim_chip)); - ctrls[chip->ctrl_num].chips[chip->num] = sim_chip; - sim_chip->created = 1; - - return (0); -} - -static int -nandsim_destroy_chip(struct sim_ctrl_chip *chip) -{ - struct sim_ctrl_conf *ctrl_conf; - - nand_debug(NDBG_SIM,"destroy chip num:%d at ctrl:%d", chip->chip_num, - chip->ctrl_num); - - if (chip->ctrl_num >= MAX_SIM_DEV || - chip->chip_num >= MAX_CTRL_CS) - return (EINVAL); - - ctrl_conf = &ctrls[chip->ctrl_num]; - - if (!ctrl_conf->created || !ctrl_conf->chips[chip->chip_num]) - return (ENODEV); - - if (ctrl_conf->running) - return (EBUSY); - - free(ctrl_conf->chips[chip->chip_num], M_NANDSIM); - ctrl_conf->chips[chip->chip_num] = NULL; - - return (0); -} - -static int -nandsim_chip_status(struct sim_chip *chip) -{ - struct sim_ctrl_conf *ctrl_conf; - - nand_debug(NDBG_SIM,"status for chip num:%d at ctrl:%d", chip->num, - chip->ctrl_num); - - if (chip->ctrl_num >= MAX_SIM_DEV && - chip->num >= MAX_CTRL_CS) - return (EINVAL); - - ctrl_conf = &ctrls[chip->ctrl_num]; - if (!ctrl_conf->chips[chip->num]) - chip->created = 0; - else - memcpy(chip, ctrl_conf->chips[chip->num], sizeof(*chip)); - - return (0); -} - -static int -nandsim_start_ctrl(int num) -{ - device_t nexus, ndev; - devclass_t nexus_devclass; - int ret = 0; - - nand_debug(NDBG_SIM,"start ctlr num:%d", num); - - if (num >= MAX_SIM_DEV) - return (EINVAL); - - if (!ctrls[num].created) - return (ENODEV); - - if (ctrls[num].running) - return (EBUSY); - - /* We will add our device as a child of the nexus0 device */ - if (!(nexus_devclass = devclass_find("nexus")) || - !(nexus = devclass_get_device(nexus_devclass, 0))) - return (EFAULT); - - /* - * Create a newbus device representing this frontend instance - * - * XXX powerpc nexus doesn't implement bus_add_child, so child - * must be added by device_add_child(). - */ -#if defined(__powerpc__) - ndev = device_add_child(nexus, "nandsim", num); -#else - ndev = BUS_ADD_CHILD(nexus, 0, "nandsim", num); -#endif - if (!ndev) - return (EFAULT); - - mtx_lock(&Giant); - ret = device_probe_and_attach(ndev); - mtx_unlock(&Giant); - - if (ret == 0) { - ctrls[num].sim_ctrl_dev = ndev; - ctrls[num].running = 1; - } - - return (ret); -} - -static int -nandsim_stop_ctrl(int num) -{ - device_t nexus; - devclass_t nexus_devclass; - int ret = 0; - - nand_debug(NDBG_SIM,"stop controller num:%d", num); - - if (num >= MAX_SIM_DEV) { - return (EINVAL); - } - - if (!ctrls[num].created || !ctrls[num].running) { - return (ENODEV); - } - - /* We will add our device as a child of the nexus0 device */ - if (!(nexus_devclass = devclass_find("nexus")) || - !(nexus = devclass_get_device(nexus_devclass, 0))) { - return (ENODEV); - } - - mtx_lock(&Giant); - if (ctrls[num].sim_ctrl_dev) { - ret = device_delete_child(nexus, ctrls[num].sim_ctrl_dev); - ctrls[num].sim_ctrl_dev = NULL; - } - mtx_unlock(&Giant); - - ctrls[num].running = 0; - - return (ret); -} - -static struct nandsim_chip * -get_nandsim_chip(uint8_t ctrl_num, uint8_t chip_num) -{ - struct nandsim_softc *sc; - - if (!ctrls[ctrl_num].sim_ctrl_dev) - return (NULL); - - sc = device_get_softc(ctrls[ctrl_num].sim_ctrl_dev); - return (sc->chips[chip_num]); -} - -static void -nandsim_print_log(struct sim_log *sim_log) -{ - struct nandsim_softc *sc; - int len1, len2; - - if (!ctrls[sim_log->ctrl_num].sim_ctrl_dev) - return; - - sc = device_get_softc(ctrls[sim_log->ctrl_num].sim_ctrl_dev); - if (sc->log_buff) { - len1 = strlen(&sc->log_buff[sc->log_idx + 1]); - if (len1 >= sim_log->len) - len1 = sim_log->len; - copyout(&sc->log_buff[sc->log_idx + 1], sim_log->log, len1); - len2 = strlen(sc->log_buff); - if (len2 >= (sim_log->len - len1)) - len2 = (sim_log->len - len1); - copyout(sc->log_buff, &sim_log->log[len1], len2); - sim_log->len = len1 + len2; - } -} - -static int -nandsim_inject_error(struct sim_error *error) -{ - struct nandsim_chip *chip; - struct block_space *bs; - struct onfi_params *param; - int page, page_size, block, offset; - - nand_debug(NDBG_SIM,"inject error for chip %d at ctrl %d\n", - error->chip_num, error->ctrl_num); - - if (error->ctrl_num >= MAX_SIM_DEV || - error->chip_num >= MAX_CTRL_CS) - return (EINVAL); - - if (!ctrls[error->ctrl_num].created || !ctrls[error->ctrl_num].running) - return (ENODEV); - - chip = get_nandsim_chip(error->ctrl_num, error->chip_num); - param = &chip->params; - page_size = param->bytes_per_page + param->spare_bytes_per_page; - block = error->page_num / param->pages_per_block; - page = error->page_num % param->pages_per_block; - - bs = get_bs(chip->swap, block, 1); - if (!bs) - return (EINVAL); - - offset = (page * page_size) + error->column; - memset(&bs->blk_ptr[offset], error->pattern, error->len); - - return (0); -} - -static int -nandsim_set_block_state(struct sim_block_state *bs) -{ - struct onfi_params *params; - struct nandsim_chip *chip; - int blocks; - - nand_debug(NDBG_SIM,"set block state for %d:%d block %d\n", - bs->chip_num, bs->ctrl_num, bs->block_num); - - if (bs->ctrl_num >= MAX_SIM_DEV || - bs->chip_num >= MAX_CTRL_CS) - return (EINVAL); - - chip = get_nandsim_chip(bs->ctrl_num, bs->chip_num); - params = &chip->params; - blocks = params->luns * params->blocks_per_lun; - - if (bs->block_num > blocks) - return (EINVAL); - - chip->blk_state[bs->block_num].is_bad = bs->state; - - if (bs->wearout >= 0) - chip->blk_state[bs->block_num].wear_lev = bs->wearout; - - return (0); -} - -static int -nandsim_get_block_state(struct sim_block_state *bs) -{ - struct onfi_params *params; - struct nandsim_chip *chip; - int blocks; - - if (bs->ctrl_num >= MAX_SIM_DEV || - bs->chip_num >= MAX_CTRL_CS) - return (EINVAL); - - nand_debug(NDBG_SIM,"get block state for %d:%d block %d\n", - bs->chip_num, bs->ctrl_num, bs->block_num); - - chip = get_nandsim_chip(bs->ctrl_num, bs->chip_num); - params = &chip->params; - blocks = params->luns * params->blocks_per_lun; - - if (bs->block_num > blocks) - return (EINVAL); - - bs->state = chip->blk_state[bs->block_num].is_bad; - bs->wearout = chip->blk_state[bs->block_num].wear_lev; - - return (0); -} - -static int -nandsim_dump(struct sim_dump *dump) -{ - struct nandsim_chip *chip; - struct block_space *bs; - int blk_size; - - nand_debug(NDBG_SIM,"dump chip %d %d\n", dump->ctrl_num, dump->chip_num); - - if (dump->ctrl_num >= MAX_SIM_DEV || - dump->chip_num >= MAX_CTRL_CS) - return (EINVAL); - - chip = get_nandsim_chip(dump->ctrl_num, dump->chip_num); - blk_size = chip->cg.block_size + - (chip->cg.oob_size * chip->cg.pgs_per_blk); - - bs = get_bs(chip->swap, dump->block_num, 0); - if (!bs) - return (EINVAL); - - if (dump->len > blk_size) - dump->len = blk_size; - - copyout(bs->blk_ptr, dump->data, dump->len); - - return (0); -} - -static int -nandsim_restore(struct sim_dump *dump) -{ - struct nandsim_chip *chip; - struct block_space *bs; - int blk_size; - - nand_debug(NDBG_SIM,"restore chip %d %d\n", dump->ctrl_num, - dump->chip_num); - - if (dump->ctrl_num >= MAX_SIM_DEV || - dump->chip_num >= MAX_CTRL_CS) - return (EINVAL); - - chip = get_nandsim_chip(dump->ctrl_num, dump->chip_num); - blk_size = chip->cg.block_size + - (chip->cg.oob_size * chip->cg.pgs_per_blk); - - bs = get_bs(chip->swap, dump->block_num, 1); - if (!bs) - return (EINVAL); - - if (dump->len > blk_size) - dump->len = blk_size; - - - copyin(dump->data, bs->blk_ptr, dump->len); - - return (0); -} - -static int -nandsim_freeze(struct sim_ctrl_chip *ctrl_chip) -{ - struct nandsim_chip *chip; - - if (ctrl_chip->ctrl_num >= MAX_SIM_DEV || - ctrl_chip->chip_num >= MAX_CTRL_CS) - return (EINVAL); - - chip = get_nandsim_chip(ctrl_chip->ctrl_num, ctrl_chip->chip_num); - nandsim_chip_freeze(chip); - - return (0); -} - -static int -nandsim_modify(struct sim_mod *mod) -{ - struct sim_chip *sim_conf = NULL; - struct nandsim_chip *sim_chip = NULL; - - nand_debug(NDBG_SIM,"modify ctlr %d chip %d", mod->ctrl_num, - mod->chip_num); - - if (mod->field != SIM_MOD_LOG_LEVEL) { - if (mod->ctrl_num >= MAX_SIM_DEV || - mod->chip_num >= MAX_CTRL_CS) - return (EINVAL); - - sim_conf = ctrls[mod->ctrl_num].chips[mod->chip_num]; - sim_chip = get_nandsim_chip(mod->ctrl_num, mod->chip_num); - } - - switch (mod->field) { - case SIM_MOD_LOG_LEVEL: - nandsim_log_level = mod->new_value; - break; - case SIM_MOD_ERASE_TIME: - sim_conf->erase_time = sim_chip->erase_delay = mod->new_value; - break; - case SIM_MOD_PROG_TIME: - sim_conf->prog_time = sim_chip->prog_delay = mod->new_value; - break; - case SIM_MOD_READ_TIME: - sim_conf->read_time = sim_chip->read_delay = mod->new_value; - break; - case SIM_MOD_ERROR_RATIO: - sim_conf->error_ratio = mod->new_value; - sim_chip->error_ratio = mod->new_value; - break; - default: - break; - } - - return (0); -} -static int -nandsim_modevent(module_t mod __unused, int type, void *data __unused) -{ - struct sim_ctrl_chip chip_ctrl; - int i, j; - - switch (type) { - case MOD_LOAD: - nandsim_dev = make_dev(&nandsim_cdevsw, 0, - UID_ROOT, GID_WHEEL, 0600, "nandsim.ioctl"); - break; - case MOD_UNLOAD: - for (i = 0; i < MAX_SIM_DEV; i++) { - nandsim_stop_ctrl(i); - chip_ctrl.ctrl_num = i; - for (j = 0; j < MAX_CTRL_CS; j++) { - chip_ctrl.chip_num = j; - nandsim_destroy_chip(&chip_ctrl); - } - nandsim_destroy_ctrl(i); - } - destroy_dev(nandsim_dev); - break; - case MOD_SHUTDOWN: - break; - default: - return (EOPNOTSUPP); - } - return (0); -} - -DEV_MODULE(nandsim, nandsim_modevent, NULL); -MODULE_VERSION(nandsim, 1); -MODULE_DEPEND(nandsim, nand, 1, 1, 1); -MODULE_DEPEND(nandsim, alq, 1, 1, 1); diff --git a/sys/dev/nand/nandsim.h b/sys/dev/nand/nandsim.h deleted file mode 100644 index d4b225113bfd..000000000000 --- a/sys/dev/nand/nandsim.h +++ /dev/null @@ -1,177 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _NANDSIM_H_ -#define _NANDSIM_H_ - -#include <sys/ioccom.h> -#include <sys/types.h> - -#define MAX_SIM_DEV 4 -#define MAX_CTRL_CS 4 -#define MAX_ECC_BYTES 512 -#define MAX_BAD_BLOCKS 512 -#define DEV_MODEL_STR_SIZE 21 -#define MAN_STR_SIZE 13 -#define FILENAME_SIZE 20 - -#define MAX_CHIPS (MAX_SIM_DEV*MAX_CTRL_CS) - -#define NANDSIM_OUTPUT_NONE 0x0 -#define NANDSIM_OUTPUT_CONSOLE 0x1 -#define NANDSIM_OUTPUT_RAM 0x2 -#define NANDSIM_OUTPUT_FILE 0x3 - -struct sim_ctrl_chip { - uint8_t ctrl_num; - uint8_t chip_num; -}; - -#define NANDSIM_BASE 'A' - -struct sim_param { - uint8_t log_level; - uint8_t log_output; -}; - -#define NANDSIM_SIM_PARAM _IOW(NANDSIM_BASE, 1, struct sim_param) - -struct sim_ctrl { - uint8_t running; - uint8_t created; - uint8_t num; - uint8_t num_cs; - uint8_t ecc; - char filename[FILENAME_SIZE]; - uint16_t ecc_layout[MAX_ECC_BYTES]; -}; -#define NANDSIM_CREATE_CTRL _IOW(NANDSIM_BASE, 2, struct sim_ctrl) -#define NANDSIM_DESTROY_CTRL _IOW(NANDSIM_BASE, 3, int) - -struct sim_chip { - uint8_t num; - uint8_t ctrl_num; - uint8_t created; - uint8_t device_id; - uint8_t manufact_id; - char device_model[DEV_MODEL_STR_SIZE]; - char manufacturer[MAN_STR_SIZE]; - uint8_t col_addr_cycles; - uint8_t row_addr_cycles; - uint8_t features; - uint8_t width; - uint32_t page_size; - uint32_t oob_size; - uint32_t pgs_per_blk; - uint32_t blks_per_lun; - uint32_t luns; - - uint32_t prog_time; - uint32_t erase_time; - uint32_t read_time; - uint32_t ccs_time; - - uint32_t error_ratio; - uint32_t wear_level; - uint32_t bad_block_map[MAX_BAD_BLOCKS]; - uint8_t is_wp; -}; - -#define NANDSIM_CREATE_CHIP _IOW(NANDSIM_BASE, 3, struct sim_chip) - -struct sim_chip_destroy { - uint8_t ctrl_num; - uint8_t chip_num; -}; -#define NANDSIM_DESTROY_CHIP _IOW(NANDSIM_BASE, 4, struct sim_chip_destroy) - -#define NANDSIM_START_CTRL _IOW(NANDSIM_BASE, 5, int) -#define NANDSIM_STOP_CTRL _IOW(NANDSIM_BASE, 6, int) -#define NANDSIM_RESTART_CTRL _IOW(NANDSIM_BASE, 7, int) - -#define NANDSIM_STATUS_CTRL _IOWR(NANDSIM_BASE, 8, struct sim_ctrl) -#define NANDSIM_STATUS_CHIP _IOWR(NANDSIM_BASE, 9, struct sim_chip) - -struct sim_mod { - uint8_t chip_num; - uint8_t ctrl_num; - uint32_t field; - uint32_t new_value; -}; -#define SIM_MOD_LOG_LEVEL 0 -#define SIM_MOD_ERASE_TIME 1 -#define SIM_MOD_PROG_TIME 2 -#define SIM_MOD_READ_TIME 3 -#define SIM_MOD_CCS_TIME 4 -#define SIM_MOD_ERROR_RATIO 5 - -#define NANDSIM_MODIFY _IOW(NANDSIM_BASE, 10, struct sim_mod) -#define NANDSIM_FREEZE _IOW(NANDSIM_BASE, 11, struct sim_ctrl_chip) - -struct sim_error { - uint8_t ctrl_num; - uint8_t chip_num; - uint32_t page_num; - uint32_t column; - uint32_t len; - uint32_t pattern; -}; -#define NANDSIM_INJECT_ERROR _IOW(NANDSIM_BASE, 20, struct sim_error) - -#define NANDSIM_GOOD_BLOCK 0 -#define NANDSIM_BAD_BLOCK 1 -struct sim_block_state { - uint8_t ctrl_num; - uint8_t chip_num; - uint32_t block_num; - int wearout; - uint8_t state; -}; -#define NANDSIM_SET_BLOCK_STATE _IOW(NANDSIM_BASE, 21, struct sim_block_state) -#define NANDSIM_GET_BLOCK_STATE _IOWR(NANDSIM_BASE, 22, struct sim_block_state) - -struct sim_log { - uint8_t ctrl_num; - char* log; - size_t len; -}; -#define NANDSIM_PRINT_LOG _IOWR(NANDSIM_BASE, 23, struct sim_log) - -struct sim_dump { - uint8_t ctrl_num; - uint8_t chip_num; - uint32_t block_num; - uint32_t len; - void* data; -}; -#define NANDSIM_DUMP _IOWR(NANDSIM_BASE, 24, struct sim_dump) -#define NANDSIM_RESTORE _IOWR(NANDSIM_BASE, 25, struct sim_dump) - -#endif /* _NANDSIM_H_ */ diff --git a/sys/dev/nand/nandsim_chip.c b/sys/dev/nand/nandsim_chip.c deleted file mode 100644 index b7ab83b9d208..000000000000 --- a/sys/dev/nand/nandsim_chip.c +++ /dev/null @@ -1,898 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/types.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/lock.h> -#include <sys/malloc.h> -#include <sys/module.h> -#include <sys/mutex.h> -#include <sys/proc.h> -#include <sys/sched.h> -#include <sys/kthread.h> -#include <sys/unistd.h> - -#include <dev/nand/nand.h> -#include <dev/nand/nandsim_chip.h> -#include <dev/nand/nandsim_log.h> -#include <dev/nand/nandsim_swap.h> - -MALLOC_DEFINE(M_NANDSIM, "NANDsim", "NANDsim dynamic data"); - -#define NANDSIM_CHIP_LOCK(chip) mtx_lock(&(chip)->ns_lock) -#define NANDSIM_CHIP_UNLOCK(chip) mtx_unlock(&(chip)->ns_lock) - -static nandsim_evh_t erase_evh; -static nandsim_evh_t idle_evh; -static nandsim_evh_t poweron_evh; -static nandsim_evh_t reset_evh; -static nandsim_evh_t read_evh; -static nandsim_evh_t readid_evh; -static nandsim_evh_t readparam_evh; -static nandsim_evh_t write_evh; - -static void nandsim_loop(void *); -static void nandsim_undefined(struct nandsim_chip *, uint8_t); -static void nandsim_bad_address(struct nandsim_chip *, uint8_t *); -static void nandsim_ignore_address(struct nandsim_chip *, uint8_t); -static void nandsim_sm_error(struct nandsim_chip *); -static void nandsim_start_handler(struct nandsim_chip *, nandsim_evh_t); - -static void nandsim_callout_eh(void *); -static int nandsim_delay(struct nandsim_chip *, int); - -static int nandsim_bbm_init(struct nandsim_chip *, uint32_t, uint32_t *); -static int nandsim_blk_state_init(struct nandsim_chip *, uint32_t, uint32_t); -static void nandsim_blk_state_destroy(struct nandsim_chip *); -static int nandchip_is_block_valid(struct nandsim_chip *, int); - -static void nandchip_set_status(struct nandsim_chip *, uint8_t); -static void nandchip_clear_status(struct nandsim_chip *, uint8_t); - -struct proc *nandsim_proc; - -struct nandsim_chip * -nandsim_chip_init(struct nandsim_softc* sc, uint8_t chip_num, - struct sim_chip *sim_chip) -{ - struct nandsim_chip *chip; - struct onfi_params *chip_param; - char swapfile[20]; - uint32_t size; - int error; - - chip = malloc(sizeof(*chip), M_NANDSIM, M_WAITOK | M_ZERO); - - mtx_init(&chip->ns_lock, "nandsim lock", NULL, MTX_DEF); - callout_init(&chip->ns_callout, 1); - STAILQ_INIT(&chip->nandsim_events); - - chip->chip_num = chip_num; - chip->ctrl_num = sim_chip->ctrl_num; - chip->sc = sc; - - if (!sim_chip->is_wp) - nandchip_set_status(chip, NAND_STATUS_WP); - - chip_param = &chip->params; - - chip->id.dev_id = sim_chip->device_id; - chip->id.man_id = sim_chip->manufact_id; - - chip->error_ratio = sim_chip->error_ratio; - chip->wear_level = sim_chip->wear_level; - chip->prog_delay = sim_chip->prog_time; - chip->erase_delay = sim_chip->erase_time; - chip->read_delay = sim_chip->read_time; - - chip_param->t_prog = sim_chip->prog_time; - chip_param->t_bers = sim_chip->erase_time; - chip_param->t_r = sim_chip->read_time; - bcopy("onfi", &chip_param->signature, 4); - - chip_param->manufacturer_id = sim_chip->manufact_id; - strncpy(chip_param->manufacturer_name, sim_chip->manufacturer, 12); - chip_param->manufacturer_name[11] = 0; - strncpy(chip_param->device_model, sim_chip->device_model, 20); - chip_param->device_model[19] = 0; - - chip_param->bytes_per_page = sim_chip->page_size; - chip_param->spare_bytes_per_page = sim_chip->oob_size; - chip_param->pages_per_block = sim_chip->pgs_per_blk; - chip_param->blocks_per_lun = sim_chip->blks_per_lun; - chip_param->luns = sim_chip->luns; - - init_chip_geom(&chip->cg, chip_param->luns, chip_param->blocks_per_lun, - chip_param->pages_per_block, chip_param->bytes_per_page, - chip_param->spare_bytes_per_page); - - chip_param->address_cycles = sim_chip->row_addr_cycles | - (sim_chip->col_addr_cycles << 4); - chip_param->features = sim_chip->features; - if (sim_chip->width == 16) - chip_param->features |= ONFI_FEAT_16BIT; - - size = chip_param->blocks_per_lun * chip_param->luns; - - error = nandsim_blk_state_init(chip, size, sim_chip->wear_level); - if (error) { - mtx_destroy(&chip->ns_lock); - free(chip, M_NANDSIM); - return (NULL); - } - - error = nandsim_bbm_init(chip, size, sim_chip->bad_block_map); - if (error) { - mtx_destroy(&chip->ns_lock); - nandsim_blk_state_destroy(chip); - free(chip, M_NANDSIM); - return (NULL); - } - - nandsim_start_handler(chip, poweron_evh); - - nand_debug(NDBG_SIM,"Create thread for chip%d [%8p]", chip->chip_num, - chip); - /* Create chip thread */ - error = kproc_kthread_add(nandsim_loop, chip, &nandsim_proc, - &chip->nandsim_td, RFSTOPPED | RFHIGHPID, - 0, "nandsim", "chip"); - if (error) { - mtx_destroy(&chip->ns_lock); - nandsim_blk_state_destroy(chip); - free(chip, M_NANDSIM); - return (NULL); - } - - thread_lock(chip->nandsim_td); - sched_class(chip->nandsim_td, PRI_REALTIME); - sched_add(chip->nandsim_td, SRQ_BORING); - thread_unlock(chip->nandsim_td); - - size = (chip_param->bytes_per_page + - chip_param->spare_bytes_per_page) * - chip_param->pages_per_block; - - sprintf(swapfile, "chip%d%d.swp", chip->ctrl_num, chip->chip_num); - chip->swap = nandsim_swap_init(swapfile, chip_param->blocks_per_lun * - chip_param->luns, size); - if (!chip->swap) - nandsim_chip_destroy(chip); - - /* Wait for new thread to enter main loop */ - tsleep(chip->nandsim_td, PWAIT, "ns_chip", 1 * hz); - - return (chip); -} - -static int -nandsim_blk_state_init(struct nandsim_chip *chip, uint32_t size, - uint32_t wear_lev) -{ - int i; - - if (!chip || size == 0) - return (-1); - - chip->blk_state = malloc(size * sizeof(struct nandsim_block_state), - M_NANDSIM, M_WAITOK | M_ZERO); - - for (i = 0; i < size; i++) { - if (wear_lev) - chip->blk_state[i].wear_lev = wear_lev; - else - chip->blk_state[i].wear_lev = -1; - } - - return (0); -} - -static void -nandsim_blk_state_destroy(struct nandsim_chip *chip) -{ - - if (chip && chip->blk_state) - free(chip->blk_state, M_NANDSIM); -} - -static int -nandsim_bbm_init(struct nandsim_chip *chip, uint32_t size, - uint32_t *sim_bbm) -{ - uint32_t index; - int i; - - if ((chip == NULL) || (size == 0)) - return (-1); - - if (chip->blk_state == NULL) - return (-1); - - if (sim_bbm == NULL) - return (0); - - for (i = 0; i < MAX_BAD_BLOCKS; i++) { - index = sim_bbm[i]; - - if (index == 0xffffffff) - break; - else if (index > size) - return (-1); - else - chip->blk_state[index].is_bad = 1; - } - - return (0); -} - -void -nandsim_chip_destroy(struct nandsim_chip *chip) -{ - struct nandsim_ev *ev; - - ev = create_event(chip, NANDSIM_EV_EXIT, 0); - if (ev) - send_event(ev); -} - -void -nandsim_chip_freeze(struct nandsim_chip *chip) -{ - - chip->flags |= NANDSIM_CHIP_FROZEN; -} - -static void -nandsim_loop(void *arg) -{ - struct nandsim_chip *chip = (struct nandsim_chip *)arg; - struct nandsim_ev *ev; - - nand_debug(NDBG_SIM,"Start main loop for chip%d [%8p]", chip->chip_num, - chip); - for(;;) { - NANDSIM_CHIP_LOCK(chip); - if (!(chip->flags & NANDSIM_CHIP_ACTIVE)) { - chip->flags |= NANDSIM_CHIP_ACTIVE; - wakeup(chip->nandsim_td); - } - - if (STAILQ_EMPTY(&chip->nandsim_events)) { - nand_debug(NDBG_SIM,"Chip%d [%8p] going sleep", - chip->chip_num, chip); - msleep(chip, &chip->ns_lock, PRIBIO, "nandev", 0); - } - - ev = STAILQ_FIRST(&chip->nandsim_events); - STAILQ_REMOVE_HEAD(&chip->nandsim_events, links); - NANDSIM_CHIP_UNLOCK(chip); - if (ev->type == NANDSIM_EV_EXIT) { - NANDSIM_CHIP_LOCK(chip); - destroy_event(ev); - wakeup(ev); - while (!STAILQ_EMPTY(&chip->nandsim_events)) { - ev = STAILQ_FIRST(&chip->nandsim_events); - STAILQ_REMOVE_HEAD(&chip->nandsim_events, - links); - destroy_event(ev); - wakeup(ev); - } - NANDSIM_CHIP_UNLOCK(chip); - nandsim_log(chip, NANDSIM_LOG_SM, "destroyed\n"); - mtx_destroy(&chip->ns_lock); - nandsim_blk_state_destroy(chip); - nandsim_swap_destroy(chip->swap); - free(chip, M_NANDSIM); - nandsim_proc = NULL; - - kthread_exit(); - } - - if (!(chip->flags & NANDSIM_CHIP_FROZEN)) { - nand_debug(NDBG_SIM,"Chip [%x] get event [%x]", - chip->chip_num, ev->type); - chip->ev_handler(chip, ev->type, ev->data); - } - - wakeup(ev); - destroy_event(ev); - } - -} - -struct nandsim_ev * -create_event(struct nandsim_chip *chip, uint8_t type, uint8_t data_size) -{ - struct nandsim_ev *ev; - - ev = malloc(sizeof(*ev), M_NANDSIM, M_NOWAIT | M_ZERO); - if (!ev) { - nand_debug(NDBG_SIM,"Cannot create event"); - return (NULL); - } - - if (data_size > 0) - ev->data = malloc(sizeof(*ev), M_NANDSIM, M_NOWAIT | M_ZERO); - ev->type = type; - ev->chip = chip; - - return (ev); -} - -void -destroy_event(struct nandsim_ev *ev) -{ - - if (ev->data) - free(ev->data, M_NANDSIM); - free(ev, M_NANDSIM); -} - -int -send_event(struct nandsim_ev *ev) -{ - struct nandsim_chip *chip = ev->chip; - - if (!(chip->flags & NANDSIM_CHIP_FROZEN)) { - nand_debug(NDBG_SIM,"Chip%d [%p] send event %x", - chip->chip_num, chip, ev->type); - - NANDSIM_CHIP_LOCK(chip); - STAILQ_INSERT_TAIL(&chip->nandsim_events, ev, links); - NANDSIM_CHIP_UNLOCK(chip); - - wakeup(chip); - if ((ev->type != NANDSIM_EV_TIMEOUT) && chip->nandsim_td && - (curthread != chip->nandsim_td)) - tsleep(ev, PWAIT, "ns_ev", 5 * hz); - } - - return (0); -} - -static void -nandsim_callout_eh(void *arg) -{ - struct nandsim_ev *ev = (struct nandsim_ev *)arg; - - send_event(ev); -} - -static int -nandsim_delay(struct nandsim_chip *chip, int timeout) -{ - struct nandsim_ev *ev; - struct timeval delay; - int tm; - - nand_debug(NDBG_SIM,"Chip[%d] Set delay: %d", chip->chip_num, timeout); - - ev = create_event(chip, NANDSIM_EV_TIMEOUT, 0); - if (!ev) - return (-1); - - chip->sm_state = NANDSIM_STATE_TIMEOUT; - tm = (timeout/10000) * (hz / 100); - if (callout_reset(&chip->ns_callout, tm, nandsim_callout_eh, ev)) - return (-1); - - delay.tv_sec = chip->read_delay / 1000000; - delay.tv_usec = chip->read_delay % 1000000; - timevaladd(&chip->delay_tv, &delay); - - return (0); -} - -static void -nandsim_start_handler(struct nandsim_chip *chip, nandsim_evh_t evh) -{ - struct nandsim_ev *ev; - - chip->ev_handler = evh; - - nand_debug(NDBG_SIM,"Start handler %p for chip%d [%p]", evh, - chip->chip_num, chip); - ev = create_event(chip, NANDSIM_EV_START, 0); - if (!ev) - nandsim_sm_error(chip); - - send_event(ev); -} - -static void -nandchip_set_data(struct nandsim_chip *chip, uint8_t *data, uint32_t len, - uint32_t idx) -{ - - nand_debug(NDBG_SIM,"Chip [%x] data %p [%x] at %x", chip->chip_num, - data, len, idx); - chip->data.data_ptr = data; - chip->data.size = len; - chip->data.index = idx; -} - -static int -nandchip_chip_space(struct nandsim_chip *chip, int32_t row, int32_t column, - size_t size, uint8_t writing) -{ - struct block_space *blk_space; - uint32_t lun, block, page, offset, block_size; - int err; - - block_size = chip->cg.block_size + - (chip->cg.oob_size * chip->cg.pgs_per_blk); - - err = nand_row_to_blkpg(&chip->cg, row, &lun, &block, &page); - if (err) { - nand_debug(NDBG_SIM,"cannot get address\n"); - return (-1); - } - - if (!nandchip_is_block_valid(chip, block)) { - nandchip_set_data(chip, NULL, 0, 0); - return (-1); - } - - blk_space = get_bs(chip->swap, block, writing); - if (!blk_space) { - nandchip_set_data(chip, NULL, 0, 0); - return (-1); - } - - if (size > block_size) - size = block_size; - - if (size == block_size) { - offset = 0; - column = 0; - } else - offset = page * (chip->cg.page_size + chip->cg.oob_size); - - nandchip_set_data(chip, &blk_space->blk_ptr[offset], size, column); - - return (0); -} - -static int -nandchip_get_addr_byte(struct nandsim_chip *chip, void *data, uint32_t *value) -{ - int ncycles = 0; - uint8_t byte; - uint8_t *buffer; - - buffer = (uint8_t *)value; - byte = *((uint8_t *)data); - - KASSERT((chip->sm_state == NANDSIM_STATE_WAIT_ADDR_ROW || - chip->sm_state == NANDSIM_STATE_WAIT_ADDR_COL), - ("unexpected state")); - - if (chip->sm_state == NANDSIM_STATE_WAIT_ADDR_ROW) { - ncycles = chip->params.address_cycles & 0xf; - buffer[chip->sm_addr_cycle++] = byte; - } else if (chip->sm_state == NANDSIM_STATE_WAIT_ADDR_COL) { - ncycles = (chip->params.address_cycles >> 4) & 0xf; - buffer[chip->sm_addr_cycle++] = byte; - } - - nand_debug(NDBG_SIM, "Chip [%x] read addr byte: %02x (%d of %d)\n", - chip->chip_num, byte, chip->sm_addr_cycle, ncycles); - - if (chip->sm_addr_cycle == ncycles) { - chip->sm_addr_cycle = 0; - return (0); - } - - return (1); -} - -static int -nandchip_is_block_valid(struct nandsim_chip *chip, int block_num) -{ - - if (!chip || !chip->blk_state) - return (0); - - if (chip->blk_state[block_num].wear_lev == 0 || - chip->blk_state[block_num].is_bad) - return (0); - - return (1); -} - -static void -nandchip_set_status(struct nandsim_chip *chip, uint8_t flags) -{ - - chip->chip_status |= flags; -} - -static void -nandchip_clear_status(struct nandsim_chip *chip, uint8_t flags) -{ - - chip->chip_status &= ~flags; -} - -uint8_t -nandchip_get_status(struct nandsim_chip *chip) -{ - return (chip->chip_status); -} - -void -nandsim_chip_timeout(struct nandsim_chip *chip) -{ - struct timeval tv; - - getmicrotime(&tv); - - if (chip->sm_state == NANDSIM_STATE_TIMEOUT && - timevalcmp(&tv, &chip->delay_tv, >=)) { - nandchip_set_status(chip, NAND_STATUS_RDY); - } -} -void -poweron_evh(struct nandsim_chip *chip, uint32_t type, void *data) -{ - uint8_t cmd; - - if (type == NANDSIM_EV_START) - chip->sm_state = NANDSIM_STATE_IDLE; - else if (type == NANDSIM_EV_CMD) { - cmd = *(uint8_t *)data; - switch(cmd) { - case NAND_CMD_RESET: - nandsim_log(chip, NANDSIM_LOG_SM, "in RESET state\n"); - nandsim_start_handler(chip, reset_evh); - break; - default: - nandsim_undefined(chip, type); - break; - } - } else - nandsim_undefined(chip, type); -} - -void -idle_evh(struct nandsim_chip *chip, uint32_t type, void *data) -{ - uint8_t cmd; - - if (type == NANDSIM_EV_START) { - nandsim_log(chip, NANDSIM_LOG_SM, "in IDLE state\n"); - chip->sm_state = NANDSIM_STATE_WAIT_CMD; - } else if (type == NANDSIM_EV_CMD) { - nandchip_clear_status(chip, NAND_STATUS_FAIL); - getmicrotime(&chip->delay_tv); - cmd = *(uint8_t *)data; - switch(cmd) { - case NAND_CMD_READ_ID: - nandsim_start_handler(chip, readid_evh); - break; - case NAND_CMD_READ_PARAMETER: - nandsim_start_handler(chip, readparam_evh); - break; - case NAND_CMD_READ: - nandsim_start_handler(chip, read_evh); - break; - case NAND_CMD_PROG: - nandsim_start_handler(chip, write_evh); - break; - case NAND_CMD_ERASE: - nandsim_start_handler(chip, erase_evh); - break; - default: - nandsim_undefined(chip, type); - break; - } - } else - nandsim_undefined(chip, type); -} - -void -readid_evh(struct nandsim_chip *chip, uint32_t type, void *data) -{ - struct onfi_params *params; - uint8_t addr; - - params = &chip->params; - - if (type == NANDSIM_EV_START) { - nandsim_log(chip, NANDSIM_LOG_SM, "in READID state\n"); - chip->sm_state = NANDSIM_STATE_WAIT_ADDR_BYTE; - } else if (type == NANDSIM_EV_ADDR) { - - addr = *((uint8_t *)data); - - if (addr == 0x0) - nandchip_set_data(chip, (uint8_t *)&chip->id, 2, 0); - else if (addr == ONFI_SIG_ADDR) - nandchip_set_data(chip, (uint8_t *)¶ms->signature, - 4, 0); - else - nandsim_bad_address(chip, &addr); - - nandsim_start_handler(chip, idle_evh); - } else - nandsim_undefined(chip, type); -} - -void -readparam_evh(struct nandsim_chip *chip, uint32_t type, void *data) -{ - struct onfi_params *params; - uint8_t addr; - - params = &chip->params; - - if (type == NANDSIM_EV_START) { - nandsim_log(chip, NANDSIM_LOG_SM, "in READPARAM state\n"); - chip->sm_state = NANDSIM_STATE_WAIT_ADDR_BYTE; - } else if (type == NANDSIM_EV_ADDR) { - addr = *((uint8_t *)data); - - if (addr == 0) { - nandchip_set_data(chip, (uint8_t *)params, - sizeof(*params), 0); - } else - nandsim_bad_address(chip, &addr); - - nandsim_start_handler(chip, idle_evh); - } else - nandsim_undefined(chip, type); -} - -void -read_evh(struct nandsim_chip *chip, uint32_t type, void *data) -{ - static uint32_t column = 0, row = 0; - uint32_t size; - uint8_t cmd; - - size = chip->cg.page_size + chip->cg.oob_size; - - switch (type) { - case NANDSIM_EV_START: - nandsim_log(chip, NANDSIM_LOG_SM, "in READ state\n"); - chip->sm_state = NANDSIM_STATE_WAIT_ADDR_COL; - break; - case NANDSIM_EV_ADDR: - if (chip->sm_state == NANDSIM_STATE_WAIT_ADDR_COL) { - if (nandchip_get_addr_byte(chip, data, &column)) - break; - - chip->sm_state = NANDSIM_STATE_WAIT_ADDR_ROW; - } else if (chip->sm_state == NANDSIM_STATE_WAIT_ADDR_ROW) { - if (nandchip_get_addr_byte(chip, data, &row)) - break; - - chip->sm_state = NANDSIM_STATE_WAIT_CMD; - } else - nandsim_ignore_address(chip, *((uint8_t *)data)); - break; - case NANDSIM_EV_CMD: - cmd = *(uint8_t *)data; - if (chip->sm_state == NANDSIM_STATE_WAIT_CMD && - cmd == NAND_CMD_READ_END) { - if (chip->read_delay != 0 && - nandsim_delay(chip, chip->read_delay) == 0) - nandchip_clear_status(chip, NAND_STATUS_RDY); - else { - nandchip_chip_space(chip, row, column, size, 0); - nandchip_set_status(chip, NAND_STATUS_RDY); - nandsim_start_handler(chip, idle_evh); - } - } else - nandsim_undefined(chip, type); - break; - case NANDSIM_EV_TIMEOUT: - if (chip->sm_state == NANDSIM_STATE_TIMEOUT) { - nandchip_chip_space(chip, row, column, size, 0); - nandchip_set_status(chip, NAND_STATUS_RDY); - nandsim_start_handler(chip, idle_evh); - } else - nandsim_undefined(chip, type); - break; - } -} -void -write_evh(struct nandsim_chip *chip, uint32_t type, void *data) -{ - static uint32_t column, row; - uint32_t size; - uint8_t cmd; - int err; - - size = chip->cg.page_size + chip->cg.oob_size; - - switch(type) { - case NANDSIM_EV_START: - nandsim_log(chip, NANDSIM_LOG_SM, "in WRITE state\n"); - chip->sm_state = NANDSIM_STATE_WAIT_ADDR_COL; - break; - case NANDSIM_EV_ADDR: - if (chip->sm_state == NANDSIM_STATE_WAIT_ADDR_COL) { - if (nandchip_get_addr_byte(chip, data, &column)) - break; - - chip->sm_state = NANDSIM_STATE_WAIT_ADDR_ROW; - } else if (chip->sm_state == NANDSIM_STATE_WAIT_ADDR_ROW) { - if (nandchip_get_addr_byte(chip, data, &row)) - break; - - err = nandchip_chip_space(chip, row, column, size, 1); - if (err == -1) - nandchip_set_status(chip, NAND_STATUS_FAIL); - - chip->sm_state = NANDSIM_STATE_WAIT_CMD; - } else - nandsim_ignore_address(chip, *((uint8_t *)data)); - break; - case NANDSIM_EV_CMD: - cmd = *(uint8_t *)data; - if (chip->sm_state == NANDSIM_STATE_WAIT_CMD && - cmd == NAND_CMD_PROG_END) { - if (chip->prog_delay != 0 && - nandsim_delay(chip, chip->prog_delay) == 0) - nandchip_clear_status(chip, NAND_STATUS_RDY); - else { - nandchip_set_status(chip, NAND_STATUS_RDY); - nandsim_start_handler(chip, idle_evh); - } - } else - nandsim_undefined(chip, type); - break; - case NANDSIM_EV_TIMEOUT: - if (chip->sm_state == NANDSIM_STATE_TIMEOUT) { - nandsim_start_handler(chip, idle_evh); - nandchip_set_status(chip, NAND_STATUS_RDY); - } else - nandsim_undefined(chip, type); - break; - } -} - -void -erase_evh(struct nandsim_chip *chip, uint32_t type, void *data) -{ - static uint32_t row, block_size; - uint32_t lun, block, page; - int err; - uint8_t cmd; - - block_size = chip->cg.block_size + - (chip->cg.oob_size * chip->cg.pgs_per_blk); - - switch (type) { - case NANDSIM_EV_START: - nandsim_log(chip, NANDSIM_LOG_SM, "in ERASE state\n"); - chip->sm_state = NANDSIM_STATE_WAIT_ADDR_ROW; - break; - case NANDSIM_EV_CMD: - cmd = *(uint8_t *)data; - if (chip->sm_state == NANDSIM_STATE_WAIT_CMD && - cmd == NAND_CMD_ERASE_END) { - if (chip->data.data_ptr != NULL && - chip->data.size == block_size) - memset(chip->data.data_ptr, 0xff, block_size); - else - nand_debug(NDBG_SIM,"Bad block erase data\n"); - - err = nand_row_to_blkpg(&chip->cg, row, &lun, - &block, &page); - if (!err) { - if (chip->blk_state[block].wear_lev > 0) - chip->blk_state[block].wear_lev--; - } - - if (chip->erase_delay != 0 && - nandsim_delay(chip, chip->erase_delay) == 0) - nandchip_clear_status(chip, NAND_STATUS_RDY); - else { - nandchip_set_status(chip, NAND_STATUS_RDY); - nandsim_start_handler(chip, idle_evh); - } - } else - nandsim_undefined(chip, type); - break; - case NANDSIM_EV_ADDR: - if (chip->sm_state == NANDSIM_STATE_WAIT_ADDR_ROW) { - if (nandchip_get_addr_byte(chip, data, &row)) - break; - - err = nandchip_chip_space(chip, row, 0, block_size, 1); - if (err == -1) { - nandchip_set_status(chip, NAND_STATUS_FAIL); - } - chip->sm_state = NANDSIM_STATE_WAIT_CMD; - } else - nandsim_ignore_address(chip, *((uint8_t *)data)); - break; - case NANDSIM_EV_TIMEOUT: - if (chip->sm_state == NANDSIM_STATE_TIMEOUT) { - nandchip_set_status(chip, NAND_STATUS_RDY); - nandsim_start_handler(chip, idle_evh); - } else - nandsim_undefined(chip, type); - break; - } -} - -void -reset_evh(struct nandsim_chip *chip, uint32_t type, void *data) -{ - - if (type == NANDSIM_EV_START) { - nandsim_log(chip, NANDSIM_LOG_SM, "in RESET state\n"); - chip->sm_state = NANDSIM_STATE_TIMEOUT; - nandchip_set_data(chip, NULL, 0, 0); - DELAY(500); - nandsim_start_handler(chip, idle_evh); - } else - nandsim_undefined(chip, type); -} - -static void -nandsim_undefined(struct nandsim_chip *chip, uint8_t type) -{ - - nandsim_log(chip, NANDSIM_LOG_ERR, - "ERR: Chip received ev %x in state %x\n", - type, chip->sm_state); - nandsim_start_handler(chip, idle_evh); -} - -static void -nandsim_bad_address(struct nandsim_chip *chip, uint8_t *addr) -{ - - nandsim_log(chip, NANDSIM_LOG_ERR, - "ERR: Chip received out of range address" - "%02x%02x - %02x%02x%02x\n", addr[0], addr[1], addr[2], - addr[3], addr[4]); -} - -static void -nandsim_ignore_address(struct nandsim_chip *chip, uint8_t byte) -{ - nandsim_log(chip, NANDSIM_LOG_SM, "ignored address byte: %d\n", byte); -} - -static void -nandsim_sm_error(struct nandsim_chip *chip) -{ - - nandsim_log(chip, NANDSIM_LOG_ERR, "ERR: State machine error." - "Restart required.\n"); -} diff --git a/sys/dev/nand/nandsim_chip.h b/sys/dev/nand/nandsim_chip.h deleted file mode 100644 index 86ced5ea2bf2..000000000000 --- a/sys/dev/nand/nandsim_chip.h +++ /dev/null @@ -1,161 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _NANDSIM_CHIP_H -#define _NANDSIM_CHIP_H - -#include <sys/malloc.h> -#include <sys/callout.h> -#include <dev/nand/nand.h> -#include <dev/nand/nandsim.h> -#include <dev/nand/nandsim_swap.h> - -MALLOC_DECLARE(M_NANDSIM); - -#define MAX_CS_NUM 4 -struct nandsim_chip; - -typedef void nandsim_evh_t(struct nandsim_chip *chip, uint32_t ev, void *data); - -enum addr_type { - ADDR_NONE, - ADDR_ID, - ADDR_ROW, - ADDR_ROWCOL -}; - -struct nandsim_softc { - struct nand_softc nand_dev; - device_t dev; - - struct nandsim_chip *chips[MAX_CS_NUM]; - struct nandsim_chip *active_chip; - - uint8_t address_cycle; - enum addr_type address_type; - int log_idx; - char *log_buff; - struct alq *alq; -}; - -struct nandsim_ev { - STAILQ_ENTRY(nandsim_ev) links; - struct nandsim_chip *chip; - uint8_t type; - void *data; -}; - -struct nandsim_data { - uint8_t *data_ptr; - uint32_t index; - uint32_t size; -}; - -struct nandsim_block_state { - int32_t wear_lev; - uint8_t is_bad; -}; - -#define NANDSIM_CHIP_ACTIVE 0x1 -#define NANDSIM_CHIP_FROZEN 0x2 -#define NANDSIM_CHIP_GET_STATUS 0x4 - -struct nandsim_chip { - struct nandsim_softc *sc; - struct thread *nandsim_td; - - STAILQ_HEAD(, nandsim_ev) nandsim_events; - nandsim_evh_t *ev_handler; - struct mtx ns_lock; - struct callout ns_callout; - - struct chip_geom cg; - struct nand_id id; - struct onfi_params params; - struct nandsim_data data; - struct nandsim_block_state *blk_state; - - struct chip_swap *swap; - - uint32_t error_ratio; - uint32_t wear_level; - uint32_t sm_state; - uint32_t sm_addr_cycle; - - uint32_t erase_delay; - uint32_t prog_delay; - uint32_t read_delay; - struct timeval delay_tv; - - uint8_t flags; - uint8_t chip_status; - uint8_t ctrl_num; - uint8_t chip_num; -}; - -struct sim_ctrl_conf { - uint8_t num; - uint8_t num_cs; - uint8_t ecc; - uint8_t running; - uint8_t created; - device_t sim_ctrl_dev; - struct sim_chip *chips[MAX_CTRL_CS]; - uint16_t ecc_layout[MAX_ECC_BYTES]; - char filename[FILENAME_SIZE]; -}; - -#define NANDSIM_STATE_IDLE 0x0 -#define NANDSIM_STATE_WAIT_ADDR_BYTE 0x1 -#define NANDSIM_STATE_WAIT_CMD 0x2 -#define NANDSIM_STATE_TIMEOUT 0x3 -#define NANDSIM_STATE_WAIT_ADDR_ROW 0x4 -#define NANDSIM_STATE_WAIT_ADDR_COL 0x5 - -#define NANDSIM_EV_START 0x1 -#define NANDSIM_EV_CMD 0x2 -#define NANDSIM_EV_ADDR 0x3 -#define NANDSIM_EV_TIMEOUT 0x4 -#define NANDSIM_EV_EXIT 0xff - -struct nandsim_chip *nandsim_chip_init(struct nandsim_softc *, - uint8_t, struct sim_chip *); -void nandsim_chip_destroy(struct nandsim_chip *); -void nandsim_chip_freeze(struct nandsim_chip *); -void nandsim_chip_timeout(struct nandsim_chip *); -int nandsim_chip_check_bad_block(struct nandsim_chip *, int); - -uint8_t nandchip_get_status(struct nandsim_chip *); - -void destroy_event(struct nandsim_ev *); -int send_event(struct nandsim_ev *); -struct nandsim_ev *create_event(struct nandsim_chip *, uint8_t, uint8_t); - -#endif /* _NANDSIM_CHIP_H */ diff --git a/sys/dev/nand/nandsim_ctrl.c b/sys/dev/nand/nandsim_ctrl.c deleted file mode 100644 index bc203902fe7e..000000000000 --- a/sys/dev/nand/nandsim_ctrl.c +++ /dev/null @@ -1,398 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * 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. - */ - -/* Simulated NAND controller driver */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/proc.h> -#include <sys/bus.h> -#include <sys/conf.h> -#include <sys/kernel.h> -#include <sys/module.h> -#include <sys/rman.h> -#include <sys/lock.h> -#include <sys/mutex.h> -#include <sys/time.h> - -#include <dev/nand/nand.h> -#include <dev/nand/nandbus.h> -#include <dev/nand/nandsim.h> -#include <dev/nand/nandsim_log.h> -#include <dev/nand/nandsim_chip.h> -#include "nfc_if.h" - -#define ADDRESS_SIZE 5 - -extern struct sim_ctrl_conf ctrls[MAX_SIM_DEV]; - -static void byte_corrupt(struct nandsim_chip *, uint8_t *); - -static int nandsim_attach(device_t); -static int nandsim_detach(device_t); -static int nandsim_probe(device_t); - -static uint8_t nandsim_read_byte(device_t); -static uint16_t nandsim_read_word(device_t); -static int nandsim_select_cs(device_t, uint8_t); -static void nandsim_write_byte(device_t, uint8_t); -static void nandsim_write_word(device_t, uint16_t); -static void nandsim_read_buf(device_t, void *, uint32_t); -static void nandsim_write_buf(device_t, void *, uint32_t); -static int nandsim_send_command(device_t, uint8_t); -static int nandsim_send_address(device_t, uint8_t); - -static device_method_t nandsim_methods[] = { - DEVMETHOD(device_probe, nandsim_probe), - DEVMETHOD(device_attach, nandsim_attach), - DEVMETHOD(device_detach, nandsim_detach), - - DEVMETHOD(nfc_select_cs, nandsim_select_cs), - DEVMETHOD(nfc_send_command, nandsim_send_command), - DEVMETHOD(nfc_send_address, nandsim_send_address), - DEVMETHOD(nfc_read_byte, nandsim_read_byte), - DEVMETHOD(nfc_read_word, nandsim_read_word), - DEVMETHOD(nfc_write_byte, nandsim_write_byte), - DEVMETHOD(nfc_read_buf, nandsim_read_buf), - DEVMETHOD(nfc_write_buf, nandsim_write_buf), - - { 0, 0 }, -}; - -static driver_t nandsim_driver = { - "nandsim", - nandsim_methods, - sizeof(struct nandsim_softc), -}; - -static devclass_t nandsim_devclass; -DRIVER_MODULE(nandsim, nexus, nandsim_driver, nandsim_devclass, 0, 0); -DRIVER_MODULE(nandbus, nandsim, nandbus_driver, nandbus_devclass, 0, 0); - -static int -nandsim_probe(device_t dev) -{ - - device_set_desc(dev, "NAND controller simulator"); - return (BUS_PROBE_DEFAULT); -} - -static int -nandsim_attach(device_t dev) -{ - struct nandsim_softc *sc; - struct sim_ctrl_conf *params; - struct sim_chip *chip; - uint16_t *eccpos; - int i, err; - - sc = device_get_softc(dev); - params = &ctrls[device_get_unit(dev)]; - - if (strlen(params->filename) == 0) - snprintf(params->filename, FILENAME_SIZE, "ctrl%d.log", - params->num); - - nandsim_log_init(sc, params->filename); - for (i = 0; i < params->num_cs; i++) { - chip = params->chips[i]; - if (chip && chip->device_id != 0) { - sc->chips[i] = nandsim_chip_init(sc, i, chip); - if (chip->features & ONFI_FEAT_16BIT) - sc->nand_dev.flags |= NAND_16_BIT; - } - } - - if (params->ecc_layout[0] != 0xffff) - eccpos = params->ecc_layout; - else - eccpos = NULL; - - nand_init(&sc->nand_dev, dev, params->ecc, 0, 0, eccpos, "nandsim"); - - err = nandbus_create(dev); - - return (err); -} - -static int -nandsim_detach(device_t dev) -{ - struct nandsim_softc *sc; - struct sim_ctrl_conf *params; - int i; - - sc = device_get_softc(dev); - params = &ctrls[device_get_unit(dev)]; - - for (i = 0; i < params->num_cs; i++) - if (sc->chips[i] != NULL) - nandsim_chip_destroy(sc->chips[i]); - - nandsim_log_close(sc); - - return (0); -} - -static int -nandsim_select_cs(device_t dev, uint8_t cs) -{ - struct nandsim_softc *sc; - - sc = device_get_softc(dev); - - if (cs >= MAX_CS_NUM) - return (EINVAL); - - sc->active_chip = sc->chips[cs]; - - if (sc->active_chip) - nandsim_log(sc->active_chip, NANDSIM_LOG_EV, - "Select cs %d\n", cs); - - return (0); -} - -static int -nandsim_send_command(device_t dev, uint8_t command) -{ - struct nandsim_softc *sc; - struct nandsim_chip *chip; - struct nandsim_ev *ev; - - sc = device_get_softc(dev); - chip = sc->active_chip; - - if (chip == NULL) - return (0); - - nandsim_log(chip, NANDSIM_LOG_EV, "Send command %x\n", command); - - switch (command) { - case NAND_CMD_READ_ID: - case NAND_CMD_READ_PARAMETER: - sc->address_type = ADDR_ID; - break; - case NAND_CMD_ERASE: - sc->address_type = ADDR_ROW; - break; - case NAND_CMD_READ: - case NAND_CMD_PROG: - sc->address_type = ADDR_ROWCOL; - break; - default: - sc->address_type = ADDR_NONE; - break; - } - - if (command == NAND_CMD_STATUS) - chip->flags |= NANDSIM_CHIP_GET_STATUS; - else { - ev = create_event(chip, NANDSIM_EV_CMD, 1); - *(uint8_t *)ev->data = command; - send_event(ev); - } - - return (0); -} - -static int -nandsim_send_address(device_t dev, uint8_t addr) -{ - struct nandsim_ev *ev; - struct nandsim_softc *sc; - struct nandsim_chip *chip; - - sc = device_get_softc(dev); - chip = sc->active_chip; - - if (chip == NULL) - return (0); - - KASSERT((sc->address_type != ADDR_NONE), ("unexpected address")); - nandsim_log(chip, NANDSIM_LOG_EV, "Send addr %x\n", addr); - - ev = create_event(chip, NANDSIM_EV_ADDR, 1); - - *((uint8_t *)(ev->data)) = addr; - - send_event(ev); - return (0); -} - -static uint8_t -nandsim_read_byte(device_t dev) -{ - struct nandsim_softc *sc; - struct nandsim_chip *chip; - uint8_t ret = 0xff; - - sc = device_get_softc(dev); - chip = sc->active_chip; - - if (chip && !(chip->flags & NANDSIM_CHIP_FROZEN)) { - if (chip->flags & NANDSIM_CHIP_GET_STATUS) { - nandsim_chip_timeout(chip); - ret = nandchip_get_status(chip); - chip->flags &= ~NANDSIM_CHIP_GET_STATUS; - } else if (chip->data.index < chip->data.size) { - ret = chip->data.data_ptr[chip->data.index++]; - byte_corrupt(chip, &ret); - } - nandsim_log(chip, NANDSIM_LOG_DATA, "read %02x\n", ret); - } - - return (ret); -} - -static uint16_t -nandsim_read_word(device_t dev) -{ - struct nandsim_softc *sc; - struct nandsim_chip *chip; - uint16_t *data_ptr; - uint16_t ret = 0xffff; - uint8_t *byte_ret = (uint8_t *)&ret; - - sc = device_get_softc(dev); - chip = sc->active_chip; - - if (chip && !(chip->flags & NANDSIM_CHIP_FROZEN)) { - if (chip->data.index < chip->data.size - 1) { - data_ptr = - (uint16_t *)&(chip->data.data_ptr[chip->data.index]); - ret = *data_ptr; - chip->data.index += 2; - byte_corrupt(chip, byte_ret); - byte_corrupt(chip, byte_ret + 1); - } - nandsim_log(chip, NANDSIM_LOG_DATA, "read %04x\n", ret); - } - - return (ret); -} - -static void -nandsim_write_byte(device_t dev, uint8_t byte) -{ - struct nandsim_softc *sc; - struct nandsim_chip *chip; - - sc = device_get_softc(dev); - chip = sc->active_chip; - - if (chip && !(chip->flags & NANDSIM_CHIP_FROZEN) && - (chip->data.index < chip->data.size)) { - byte_corrupt(chip, &byte); - chip->data.data_ptr[chip->data.index] &= byte; - chip->data.index++; - nandsim_log(chip, NANDSIM_LOG_DATA, "write %02x\n", byte); - } -} - -static void -nandsim_write_word(device_t dev, uint16_t word) -{ - struct nandsim_softc *sc; - struct nandsim_chip *chip; - uint16_t *data_ptr; - uint8_t *byte_ptr = (uint8_t *)&word; - - sc = device_get_softc(dev); - chip = sc->active_chip; - - if (chip && !(chip->flags & NANDSIM_CHIP_FROZEN)) { - if ((chip->data.index + 1) < chip->data.size) { - byte_corrupt(chip, byte_ptr); - byte_corrupt(chip, byte_ptr + 1); - data_ptr = - (uint16_t *)&(chip->data.data_ptr[chip->data.index]); - *data_ptr &= word; - chip->data.index += 2; - } - - nandsim_log(chip, NANDSIM_LOG_DATA, "write %04x\n", word); - } -} - -static void -nandsim_read_buf(device_t dev, void *buf, uint32_t len) -{ - struct nandsim_softc *sc; - uint16_t *buf16 = (uint16_t *)buf; - uint8_t *buf8 = (uint8_t *)buf; - int i; - - sc = device_get_softc(dev); - - if (sc->nand_dev.flags & NAND_16_BIT) { - for (i = 0; i < len / 2; i++) - buf16[i] = nandsim_read_word(dev); - } else { - for (i = 0; i < len; i++) - buf8[i] = nandsim_read_byte(dev); - } -} - -static void -nandsim_write_buf(device_t dev, void *buf, uint32_t len) -{ - struct nandsim_softc *sc; - uint16_t *buf16 = (uint16_t *)buf; - uint8_t *buf8 = (uint8_t *)buf; - int i; - - sc = device_get_softc(dev); - - if (sc->nand_dev.flags & NAND_16_BIT) { - for (i = 0; i < len / 2; i++) - nandsim_write_word(dev, buf16[i]); - } else { - for (i = 0; i < len; i++) - nandsim_write_byte(dev, buf8[i]); - } -} - -static void -byte_corrupt(struct nandsim_chip *chip, uint8_t *byte) -{ - uint32_t rand; - uint8_t bit; - - rand = random(); - if ((rand % 1000000) < chip->error_ratio) { - bit = rand % 8; - if (*byte & (1 << bit)) - *byte &= ~(1 << bit); - else - *byte |= (1 << bit); - } -} diff --git a/sys/dev/nand/nandsim_log.c b/sys/dev/nand/nandsim_log.c deleted file mode 100644 index 0bd316ace4e2..000000000000 --- a/sys/dev/nand/nandsim_log.c +++ /dev/null @@ -1,188 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/module.h> -#include <sys/malloc.h> -#include <sys/proc.h> -#include <sys/alq.h> -#include <sys/time.h> - -#include <machine/stdarg.h> - -#include <dev/nand/nandsim_log.h> - -int nandsim_log_level; -int nandsim_log_output; -int log_size = NANDSIM_RAM_LOG_SIZE; - -static int nandsim_entry_size = NANDSIM_ENTRY_SIZE; -static int nandsim_entry_count = NANDSIM_ENTRY_COUNT; -static int str_index = 0; -static char string[NANDSIM_ENTRY_SIZE + 1] = {0}; - -int -nandsim_log_init(struct nandsim_softc *sc, char *filename) -{ - int error = 0; - - if (nandsim_log_output == NANDSIM_OUTPUT_FILE) { - error = alq_open(&sc->alq, filename, - curthread->td_ucred, 0644, - nandsim_entry_size, nandsim_entry_count); - } else if (nandsim_log_output == NANDSIM_OUTPUT_RAM) { - sc->log_buff = malloc(log_size, M_NANDSIM, M_WAITOK | M_ZERO); - if (!sc->log_buff) - error = ENOMEM; - } - - return (error); -} - -void -nandsim_log_close(struct nandsim_softc *sc) -{ - - if (nandsim_log_output == NANDSIM_OUTPUT_FILE) { - memset(&string[str_index], 0, NANDSIM_ENTRY_SIZE - str_index); - alq_write(sc->alq, (void *) string, ALQ_NOWAIT); - str_index = 0; - string[0] = '\0'; - alq_close(sc->alq); - } else if (nandsim_log_output == NANDSIM_OUTPUT_RAM) { - free(sc->log_buff, M_NANDSIM); - sc->log_buff = NULL; - } -} - -void -nandsim_log(struct nandsim_chip *chip, int level, const char *fmt, ...) -{ - char hdr[TIME_STR_SIZE]; - char tmp[NANDSIM_ENTRY_SIZE]; - struct nandsim_softc *sc; - struct timeval currtime; - va_list ap; - int hdr_len, len, rest; - - if (nandsim_log_output == NANDSIM_OUTPUT_NONE) - return; - - if (chip == NULL) - return; - - sc = chip->sc; - if (!sc->alq && nandsim_log_output == NANDSIM_OUTPUT_FILE) - return; - - if (level <= nandsim_log_level) { - microtime(&currtime); - hdr_len = sprintf(hdr, "%08jd.%08li [chip:%d, ctrl:%d]: ", - (intmax_t)currtime.tv_sec, currtime.tv_usec, - chip->chip_num, chip->ctrl_num); - - switch(nandsim_log_output) { - case NANDSIM_OUTPUT_CONSOLE: - printf("%s", hdr); - va_start(ap, fmt); - vprintf(fmt, ap); - va_end(ap); - break; - case NANDSIM_OUTPUT_RAM: - va_start(ap, fmt); - len = vsnprintf(tmp, NANDSIM_ENTRY_SIZE - 1, fmt, ap); - tmp[NANDSIM_ENTRY_SIZE - 1] = 0; - va_end(ap); - - rest = log_size - sc->log_idx - 1; - if (rest >= hdr_len) { - bcopy(hdr, &sc->log_buff[sc->log_idx], - hdr_len); - sc->log_idx += hdr_len; - sc->log_buff[sc->log_idx] = 0; - } else { - bcopy(hdr, &sc->log_buff[sc->log_idx], rest); - bcopy(&hdr[rest], sc->log_buff, - hdr_len - rest); - sc->log_idx = hdr_len - rest; - sc->log_buff[sc->log_idx] = 0; - } - - rest = log_size - sc->log_idx - 1; - if (rest >= len) { - bcopy(tmp, &sc->log_buff[sc->log_idx], len); - sc->log_idx += len; - sc->log_buff[sc->log_idx] = 0; - } else { - bcopy(tmp, &sc->log_buff[sc->log_idx], rest); - bcopy(&tmp[rest], sc->log_buff, len - rest); - sc->log_idx = len - rest; - sc->log_buff[sc->log_idx] = 0; - } - - break; - - case NANDSIM_OUTPUT_FILE: - va_start(ap, fmt); - len = vsnprintf(tmp, NANDSIM_ENTRY_SIZE - 1, fmt, ap); - tmp[NANDSIM_ENTRY_SIZE - 1] = 0; - va_end(ap); - - rest = NANDSIM_ENTRY_SIZE - str_index; - if (rest >= hdr_len) { - strcat(string, hdr); - str_index += hdr_len; - } else { - strlcat(string, hdr, NANDSIM_ENTRY_SIZE + 1); - alq_write(sc->alq, (void *) string, - ALQ_NOWAIT); - strcpy(string, &hdr[rest]); - str_index = hdr_len - rest; - } - rest = NANDSIM_ENTRY_SIZE - str_index; - if (rest >= len) { - strcat(string, tmp); - str_index += len; - } else { - strlcat(string, tmp, NANDSIM_ENTRY_SIZE + 1); - alq_write(sc->alq, (void *) string, - ALQ_NOWAIT); - strcpy(string, &tmp[rest]); - str_index = len - rest; - } - break; - default: - break; - } - } -} diff --git a/sys/dev/nand/nandsim_log.h b/sys/dev/nand/nandsim_log.h deleted file mode 100644 index 5e5a055a4053..000000000000 --- a/sys/dev/nand/nandsim_log.h +++ /dev/null @@ -1,54 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _NANDSIM_LOG_H -#define _NANDSIM_LOG_H - -#include <dev/nand/nandsim_chip.h> - -#define NANDSIM_ENTRY_SIZE 128 -#define NANDSIM_ENTRY_COUNT 1024 -#define NANDSIM_RAM_LOG_SIZE 16384 -#define TIME_STR_SIZE 40 - -#define NANDSIM_LOG_ERR 1 -#define NANDSIM_LOG_SM 5 -#define NANDSIM_LOG_EV 10 -#define NANDSIM_LOG_DATA 15 - -extern int nandsim_log_level; -extern int nandsim_log_output; - -int nandsim_log_init(struct nandsim_softc *, char *); -void nandsim_log_close(struct nandsim_softc *); -void nandsim_log(struct nandsim_chip *, int, const char *, ...); - -#endif /* _NANDSIM_LOG_H */ - diff --git a/sys/dev/nand/nandsim_swap.c b/sys/dev/nand/nandsim_swap.c deleted file mode 100644 index 78e14e9557bd..000000000000 --- a/sys/dev/nand/nandsim_swap.c +++ /dev/null @@ -1,383 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/types.h> -#include <sys/systm.h> -#include <sys/malloc.h> -#include <sys/queue.h> -#include <sys/fcntl.h> -#include <sys/proc.h> -#include <sys/namei.h> -#include <sys/lock.h> -#include <sys/vnode.h> -#include <sys/mount.h> - -#include <dev/nand/nandsim_chip.h> -#include <dev/nand/nandsim_swap.h> - -static int init_block_state(struct chip_swap *); -static void destroy_block_state(struct chip_swap *); - -static int create_buffers(struct chip_swap *); -static void destroy_buffers(struct chip_swap *); - -static int swap_file_open(struct chip_swap *, const char *); -static void swap_file_close(struct chip_swap *); -static int swap_file_write(struct chip_swap *, struct block_state *); -static int swap_file_read(struct chip_swap *, struct block_state *); - -#define CHIP_SWAP_CMODE 0600 -#define CHIP_SWAP_BLOCKSPACES 2 - -static int -init_block_state(struct chip_swap *swap) -{ - struct block_state *blk_state; - int i; - - if (swap == NULL) - return (-1); - - blk_state = malloc(swap->nof_blks * sizeof(struct block_state), - M_NANDSIM, M_WAITOK | M_ZERO); - - for (i = 0; i < swap->nof_blks; i++) - blk_state[i].offset = 0xffffffff; - - swap->blk_state = blk_state; - - return (0); -} - -static void -destroy_block_state(struct chip_swap *swap) -{ - - if (swap == NULL) - return; - - if (swap->blk_state != NULL) - free(swap->blk_state, M_NANDSIM); -} - -static int -create_buffers(struct chip_swap *swap) -{ - struct block_space *block_space; - void *block; - int i; - - for (i = 0; i < CHIP_SWAP_BLOCKSPACES; i++) { - block_space = malloc(sizeof(*block_space), M_NANDSIM, M_WAITOK); - block = malloc(swap->blk_size, M_NANDSIM, M_WAITOK); - block_space->blk_ptr = block; - SLIST_INSERT_HEAD(&swap->free_bs, block_space, free_link); - nand_debug(NDBG_SIM,"created blk_space %p[%p]\n", block_space, - block); - } - - if (i == 0) - return (-1); - - return (0); -} - -static void -destroy_buffers(struct chip_swap *swap) -{ - struct block_space *blk_space; - - if (swap == NULL) - return; - - blk_space = SLIST_FIRST(&swap->free_bs); - while (blk_space) { - SLIST_REMOVE_HEAD(&swap->free_bs, free_link); - nand_debug(NDBG_SIM,"destroyed blk_space %p[%p]\n", - blk_space, blk_space->blk_ptr); - free(blk_space->blk_ptr, M_NANDSIM); - free(blk_space, M_NANDSIM); - blk_space = SLIST_FIRST(&swap->free_bs); - } - - blk_space = STAILQ_FIRST(&swap->used_bs); - while (blk_space) { - STAILQ_REMOVE_HEAD(&swap->used_bs, used_link); - nand_debug(NDBG_SIM,"destroyed blk_space %p[%p]\n", - blk_space, blk_space->blk_ptr); - free(blk_space->blk_ptr, M_NANDSIM); - free(blk_space, M_NANDSIM); - blk_space = STAILQ_FIRST(&swap->used_bs); - } -} - -static int -swap_file_open(struct chip_swap *swap, const char *swap_file) -{ - struct nameidata nd; - int flags, error; - - NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, swap_file, - curthread); - - flags = FWRITE | FREAD | O_NOFOLLOW | O_CREAT | O_TRUNC; - - error = vn_open(&nd, &flags, CHIP_SWAP_CMODE, NULL); - if (error) { - nand_debug(NDBG_SIM,"Cannot create swap file %s", swap_file); - NDFREE(&nd, NDF_ONLY_PNBUF); - return (error); - } - - swap->swap_cred = crhold(curthread->td_ucred); - NDFREE(&nd, NDF_ONLY_PNBUF); - - /* We just unlock so we hold a reference */ - VOP_UNLOCK(nd.ni_vp, 0); - - swap->swap_vp = nd.ni_vp; - - return (0); -} - -static void -swap_file_close(struct chip_swap *swap) -{ - - if (swap == NULL) - return; - - if (swap->swap_vp == NULL) - return; - - vn_close(swap->swap_vp, FWRITE, swap->swap_cred, curthread); - crfree(swap->swap_cred); -} - -static int -swap_file_write(struct chip_swap *swap, struct block_state *blk_state) -{ - struct block_space *blk_space; - struct thread *td; - struct mount *mp; - struct vnode *vp; - struct uio auio; - struct iovec aiov; - - if (swap == NULL || blk_state == NULL) - return (-1); - - blk_space = blk_state->blk_sp; - if (blk_state->offset == -1) { - blk_state->offset = swap->swap_offset; - swap->swap_offset += swap->blk_size; - } - - nand_debug(NDBG_SIM,"saving %p[%p] at %x\n", - blk_space, blk_space->blk_ptr, blk_state->offset); - - bzero(&aiov, sizeof(aiov)); - bzero(&auio, sizeof(auio)); - - aiov.iov_base = blk_space->blk_ptr; - aiov.iov_len = swap->blk_size; - td = curthread; - vp = swap->swap_vp; - - auio.uio_iov = &aiov; - auio.uio_offset = blk_state->offset; - auio.uio_segflg = UIO_SYSSPACE; - auio.uio_rw = UIO_WRITE; - auio.uio_iovcnt = 1; - auio.uio_resid = swap->blk_size; - auio.uio_td = td; - - vn_start_write(vp, &mp, V_WAIT); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); - VOP_WRITE(vp, &auio, IO_UNIT, swap->swap_cred); - VOP_UNLOCK(vp, 0); - vn_finished_write(mp); - - return (0); -} - -static int -swap_file_read(struct chip_swap *swap, struct block_state *blk_state) -{ - struct block_space *blk_space; - struct thread *td; - struct vnode *vp; - struct uio auio; - struct iovec aiov; - - if (swap == NULL || blk_state == NULL) - return (-1); - - blk_space = blk_state->blk_sp; - - nand_debug(NDBG_SIM,"restore %p[%p] at %x\n", - blk_space, blk_space->blk_ptr, blk_state->offset); - - bzero(&aiov, sizeof(aiov)); - bzero(&auio, sizeof(auio)); - - aiov.iov_base = blk_space->blk_ptr; - aiov.iov_len = swap->blk_size; - td = curthread; - vp = swap->swap_vp; - - auio.uio_iov = &aiov; - auio.uio_offset = blk_state->offset; - auio.uio_segflg = UIO_SYSSPACE; - auio.uio_rw = UIO_READ; - auio.uio_iovcnt = 1; - auio.uio_resid = swap->blk_size; - auio.uio_td = td; - - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); - VOP_READ(vp, &auio, 0, swap->swap_cred); - VOP_UNLOCK(vp, 0); - - return (0); -} - -struct chip_swap * -nandsim_swap_init(const char *swap_file, uint32_t nof_blks, uint32_t blk_size) -{ - struct chip_swap *swap; - int err = 0; - - if ((swap_file == NULL) || (nof_blks == 0) || (blk_size == 0)) - return (NULL); - - swap = malloc(sizeof(*swap), M_NANDSIM, M_WAITOK | M_ZERO); - - SLIST_INIT(&swap->free_bs); - STAILQ_INIT(&swap->used_bs); - swap->blk_size = blk_size; - swap->nof_blks = nof_blks; - - err = init_block_state(swap); - if (err) { - nandsim_swap_destroy(swap); - return (NULL); - } - - err = create_buffers(swap); - if (err) { - nandsim_swap_destroy(swap); - return (NULL); - } - - err = swap_file_open(swap, swap_file); - if (err) { - nandsim_swap_destroy(swap); - return (NULL); - } - - return (swap); -} - -void -nandsim_swap_destroy(struct chip_swap *swap) -{ - - if (swap == NULL) - return; - - destroy_block_state(swap); - destroy_buffers(swap); - swap_file_close(swap); - free(swap, M_NANDSIM); -} - -struct block_space * -get_bs(struct chip_swap *swap, uint32_t block, uint8_t writing) -{ - struct block_state *blk_state, *old_blk_state = NULL; - struct block_space *blk_space; - - if (swap == NULL || (block >= swap->nof_blks)) - return (NULL); - - blk_state = &swap->blk_state[block]; - nand_debug(NDBG_SIM,"blk_state %x\n", blk_state->status); - - if (blk_state->status & BLOCK_ALLOCATED) { - blk_space = blk_state->blk_sp; - } else { - blk_space = SLIST_FIRST(&swap->free_bs); - if (blk_space) { - SLIST_REMOVE_HEAD(&swap->free_bs, free_link); - STAILQ_INSERT_TAIL(&swap->used_bs, blk_space, - used_link); - } else { - blk_space = STAILQ_FIRST(&swap->used_bs); - old_blk_state = blk_space->blk_state; - STAILQ_REMOVE_HEAD(&swap->used_bs, used_link); - STAILQ_INSERT_TAIL(&swap->used_bs, blk_space, - used_link); - if (old_blk_state->status & BLOCK_DIRTY) { - swap_file_write(swap, old_blk_state); - old_blk_state->status &= ~BLOCK_DIRTY; - old_blk_state->status |= BLOCK_SWAPPED; - } - } - } - - if (blk_space == NULL) - return (NULL); - - if (old_blk_state != NULL) { - old_blk_state->status &= ~BLOCK_ALLOCATED; - old_blk_state->blk_sp = NULL; - } - - blk_state->blk_sp = blk_space; - blk_space->blk_state = blk_state; - - if (!(blk_state->status & BLOCK_ALLOCATED)) { - if (blk_state->status & BLOCK_SWAPPED) - swap_file_read(swap, blk_state); - else - memset(blk_space->blk_ptr, 0xff, swap->blk_size); - blk_state->status |= BLOCK_ALLOCATED; - } - - if (writing) - blk_state->status |= BLOCK_DIRTY; - - nand_debug(NDBG_SIM,"get_bs returned %p[%p] state %x\n", blk_space, - blk_space->blk_ptr, blk_state->status); - - return (blk_space); -} diff --git a/sys/dev/nand/nandsim_swap.h b/sys/dev/nand/nandsim_swap.h deleted file mode 100644 index c9eb0be63a9c..000000000000 --- a/sys/dev/nand/nandsim_swap.h +++ /dev/null @@ -1,66 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _NANDSIM_SWAP_CHIP_H_ -#define _NANDSIM_SWAP_CHIP_H_ - -struct block_space { - SLIST_ENTRY(block_space) free_link; - STAILQ_ENTRY(block_space) used_link; - struct block_state *blk_state; - uint8_t *blk_ptr; -}; - -#define BLOCK_ALLOCATED 0x1 -#define BLOCK_SWAPPED 0x2 -#define BLOCK_DIRTY 0x4 - -struct block_state { - struct block_space *blk_sp; - uint32_t offset; - uint8_t status; -}; - -struct chip_swap { - struct block_state *blk_state; - SLIST_HEAD(,block_space) free_bs; - STAILQ_HEAD(,block_space) used_bs; - struct ucred *swap_cred; - struct vnode *swap_vp; - uint32_t swap_offset; - uint32_t blk_size; - uint32_t nof_blks; -}; - -struct chip_swap *nandsim_swap_init(const char *, uint32_t, uint32_t); -void nandsim_swap_destroy(struct chip_swap *); -struct block_space *get_bs(struct chip_swap *, uint32_t, uint8_t); - -#endif /* _NANDSIM_SWAP_CHIP_H_ */ diff --git a/sys/dev/nand/nfc_fsl.c b/sys/dev/nand/nfc_fsl.c deleted file mode 100644 index 992cfeb784fe..000000000000 --- a/sys/dev/nand/nfc_fsl.c +++ /dev/null @@ -1,717 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2012 Juniper Networks, Inc. - * Copyright (C) 2009-2012 Semihalf - * 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. - */ -/* - * TODO : - * - * -- test support for small pages - * -- support for reading ONFI parameters - * -- support for cached and interleaving commands - * -- proper setting of AL bits in FMR - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/proc.h> -#include <sys/bus.h> -#include <sys/conf.h> -#include <sys/kernel.h> -#include <sys/module.h> -#include <sys/malloc.h> -#include <sys/rman.h> -#include <sys/sysctl.h> -#include <sys/time.h> -#include <sys/kdb.h> - -#include <machine/bus.h> - -#include <dev/ofw/ofw_bus.h> -#include <dev/ofw/ofw_bus_subr.h> - -#include <powerpc/mpc85xx/lbc.h> - -#include <dev/nand/nand.h> -#include <dev/nand/nandbus.h> - -#include "nfc_fsl.h" - -#include "nfc_if.h" - -#define LBC_READ(regname) lbc_read_reg(dev, (LBC85XX_ ## regname)) -#define LBC_WRITE(regname, val) lbc_write_reg(dev, (LBC85XX_ ## regname), val) - -enum addr_type { - ADDR_NONE, - ADDR_ID, - ADDR_ROW, - ADDR_ROWCOL -}; - -struct fsl_nfc_fcm { - /* Read-only after initialization */ - uint32_t reg_fmr; - - /* To be preserved across "start_command" */ - u_int buf_ofs; - u_int read_ptr; - u_int status:1; - - /* Command state -- cleared by "start_command" */ - uint32_t fcm_startzero; - uint32_t reg_fcr; - uint32_t reg_fir; - uint32_t reg_mdr; - uint32_t reg_fbcr; - uint32_t reg_fbar; - uint32_t reg_fpar; - u_int cmdnr; - u_int opnr; - u_int pg_ofs; - enum addr_type addr_type; - u_int addr_bytes; - u_int row_addr; - u_int column_addr; - u_int data_fir:8; - uint32_t fcm_endzero; -}; - -struct fsl_nand_softc { - struct nand_softc nand_dev; - device_t dev; - struct resource *res; - int rid; /* Resourceid */ - struct lbc_devinfo *dinfo; - struct fsl_nfc_fcm fcm; - uint8_t col_cycles; - uint8_t row_cycles; - uint16_t pgsz; /* Page size */ -}; - -static int fsl_nand_attach(device_t dev); -static int fsl_nand_probe(device_t dev); -static int fsl_nand_detach(device_t dev); - -static int fsl_nfc_select_cs(device_t dev, uint8_t cs); -static int fsl_nfc_read_rnb(device_t dev); -static int fsl_nfc_send_command(device_t dev, uint8_t command); -static int fsl_nfc_send_address(device_t dev, uint8_t address); -static uint8_t fsl_nfc_read_byte(device_t dev); -static int fsl_nfc_start_command(device_t dev); -static void fsl_nfc_read_buf(device_t dev, void *buf, uint32_t len); -static void fsl_nfc_write_buf(device_t dev, void *buf, uint32_t len); - -static device_method_t fsl_nand_methods[] = { - DEVMETHOD(device_probe, fsl_nand_probe), - DEVMETHOD(device_attach, fsl_nand_attach), - DEVMETHOD(device_detach, fsl_nand_detach), - - DEVMETHOD(nfc_select_cs, fsl_nfc_select_cs), - DEVMETHOD(nfc_read_rnb, fsl_nfc_read_rnb), - DEVMETHOD(nfc_start_command, fsl_nfc_start_command), - DEVMETHOD(nfc_send_command, fsl_nfc_send_command), - DEVMETHOD(nfc_send_address, fsl_nfc_send_address), - DEVMETHOD(nfc_read_byte, fsl_nfc_read_byte), - DEVMETHOD(nfc_read_buf, fsl_nfc_read_buf), - DEVMETHOD(nfc_write_buf, fsl_nfc_write_buf), - { 0, 0 }, -}; - -static driver_t fsl_nand_driver = { - "nand", - fsl_nand_methods, - sizeof(struct fsl_nand_softc), -}; - -static devclass_t fsl_nand_devclass; - -DRIVER_MODULE(fsl_nand, lbc, fsl_nand_driver, fsl_nand_devclass, - 0, 0); - -static int fsl_nand_build_address(device_t dev, uint32_t page, uint32_t column); -static int fsl_nand_chip_preprobe(device_t dev, struct nand_id *id); - -#ifdef NAND_DEBUG_TIMING -static device_t fcm_devs[8]; -#endif - -#define CMD_SHIFT(cmd_num) (24 - ((cmd_num) * 8)) -#define OP_SHIFT(op_num) (28 - ((op_num) * 4)) - -#define FSL_LARGE_PAGE_SIZE (2112) -#define FSL_SMALL_PAGE_SIZE (528) - -static void -fsl_nand_init_regs(struct fsl_nand_softc *sc) -{ - uint32_t or_v, br_v; - device_t dev; - - dev = sc->dev; - - sc->fcm.reg_fmr = (15 << FMR_CWTO_SHIFT); - - /* - * Setup 4 row cycles and hope that chip ignores superfluous address - * bytes. - */ - sc->fcm.reg_fmr |= (2 << FMR_AL_SHIFT); - - /* Reprogram BR(x) */ - br_v = lbc_read_reg(dev, LBC85XX_BR(sc->dinfo->di_bank)); - br_v &= 0xffff8000; - br_v |= 1 << 11; /* 8-bit port size */ - br_v |= 0 << 9; /* No ECC checking and generation */ - br_v |= 1 << 5; /* FCM machine */ - br_v |= 1; /* Valid */ - lbc_write_reg(dev, LBC85XX_BR(sc->dinfo->di_bank), br_v); - - /* Reprogram OR(x) */ - or_v = lbc_read_reg(dev, LBC85XX_OR(sc->dinfo->di_bank)); - or_v &= 0xfffffc00; - or_v |= 0x03AE; /* Default POR timing */ - lbc_write_reg(dev, LBC85XX_OR(sc->dinfo->di_bank), or_v); - - if (or_v & OR_FCM_PAGESIZE) { - sc->pgsz = FSL_LARGE_PAGE_SIZE; - sc->col_cycles = 2; - nand_debug(NDBG_DRV, "%s: large page NAND device at #%d", - device_get_nameunit(dev), sc->dinfo->di_bank); - } else { - sc->pgsz = FSL_SMALL_PAGE_SIZE; - sc->col_cycles = 1; - nand_debug(NDBG_DRV, "%s: small page NAND device at #%d", - device_get_nameunit(dev), sc->dinfo->di_bank); - } -} - -static int -fsl_nand_probe(device_t dev) -{ - - if (!ofw_bus_is_compatible(dev, "fsl,elbc-fcm-nand")) - return (ENXIO); - - device_set_desc(dev, "Freescale localbus FCM Controller"); - return (BUS_PROBE_DEFAULT); -} - -static int -fsl_nand_attach(device_t dev) -{ - struct fsl_nand_softc *sc; - struct nand_id id; - struct nand_params *param; - uint32_t num_pages; - - sc = device_get_softc(dev); - sc->dev = dev; - sc->dinfo = device_get_ivars(dev); - - sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->rid, - RF_ACTIVE); - if (sc->res == NULL) { - device_printf(dev, "could not allocate resources!\n"); - return (ENXIO); - } - - bzero(&sc->fcm, sizeof(sc->fcm)); - - /* Init register and check if HW ECC turned on */ - fsl_nand_init_regs(sc); - - /* Chip is probed, so determine number of row address cycles */ - fsl_nand_chip_preprobe(dev, &id); - param = nand_get_params(&id); - if (param != NULL) { - num_pages = (param->chip_size << 20) / param->page_size; - while(num_pages) { - sc->row_cycles++; - num_pages >>= 8; - } - - sc->fcm.reg_fmr &= ~(FMR_AL); - sc->fcm.reg_fmr |= (sc->row_cycles - 2) << FMR_AL_SHIFT; - } - - nand_init(&sc->nand_dev, dev, NAND_ECC_SOFT, 0, 0, NULL, NULL); - -#ifdef NAND_DEBUG_TIMING - fcm_devs[sc->dinfo->di_bank] = dev; -#endif - - return (nandbus_create(dev)); -} - -static int -fsl_nand_detach(device_t dev) -{ - struct fsl_nand_softc *sc; - - sc = device_get_softc(dev); - - if (sc->res != NULL) - bus_release_resource(dev, SYS_RES_MEMORY, sc->rid, sc->res); - - return (0); -} - -static int -fsl_nfc_select_cs(device_t dev, uint8_t cs) -{ - - // device_printf(dev, "%s(cs=%u)\n", __func__, cs); - return ((cs > 0) ? EINVAL : 0); -} - -static int -fsl_nfc_read_rnb(device_t dev) -{ - - // device_printf(dev, "%s()\n", __func__); - return (0); -} - -static int -fsl_nfc_send_command(device_t dev, uint8_t command) -{ - struct fsl_nand_softc *sc; - struct fsl_nfc_fcm *fcm; - uint8_t fir_op; - - // device_printf(dev, "%s(command=%u)\n", __func__, command); - - sc = device_get_softc(dev); - fcm = &sc->fcm; - - if (command == NAND_CMD_PROG_END) { - fcm->reg_fir |= (FIR_OP_WB << OP_SHIFT(fcm->opnr)); - fcm->opnr++; - } - fcm->reg_fcr |= command << CMD_SHIFT(fcm->cmdnr); - fir_op = (fcm->cmdnr == 0) ? FIR_OP_CW0 : FIR_OP_CM(fcm->cmdnr); - fcm->cmdnr++; - - fcm->reg_fir |= (fir_op << OP_SHIFT(fcm->opnr)); - fcm->opnr++; - - switch (command) { - case NAND_CMD_READ_ID: - fcm->data_fir = FIR_OP_RBW; - fcm->addr_type = ADDR_ID; - break; - case NAND_CMD_SMALLOOB: - fcm->pg_ofs += 256; - /*FALLTHROUGH*/ - case NAND_CMD_SMALLB: - fcm->pg_ofs += 256; - /*FALLTHROUGH*/ - case NAND_CMD_READ: /* NAND_CMD_SMALLA */ - fcm->data_fir = FIR_OP_RBW; - fcm->addr_type = ADDR_ROWCOL; - break; - case NAND_CMD_STATUS: - fcm->data_fir = FIR_OP_RS; - fcm->status = 1; - break; - case NAND_CMD_ERASE: - fcm->addr_type = ADDR_ROW; - break; - case NAND_CMD_PROG: - fcm->addr_type = ADDR_ROWCOL; - break; - } - return (0); -} - -static int -fsl_nfc_send_address(device_t dev, uint8_t addr) -{ - struct fsl_nand_softc *sc; - struct fsl_nfc_fcm *fcm; - uint32_t addr_bits; - - // device_printf(dev, "%s(address=%u)\n", __func__, addr); - - sc = device_get_softc(dev); - fcm = &sc->fcm; - - KASSERT(fcm->addr_type != ADDR_NONE, - ("controller doesn't expect address cycle")); - - addr_bits = addr; - - if (fcm->addr_type == ADDR_ID) { - fcm->reg_fir |= (FIR_OP_UA << OP_SHIFT(fcm->opnr)); - fcm->opnr++; - - fcm->reg_fbcr = 5; - fcm->reg_fbar = 0; - fcm->reg_fpar = 0; - fcm->reg_mdr = addr_bits; - fcm->buf_ofs = 0; - fcm->read_ptr = 0; - return (0); - } - - if (fcm->addr_type == ADDR_ROW) { - addr_bits <<= fcm->addr_bytes * 8; - fcm->row_addr |= addr_bits; - fcm->addr_bytes++; - if (fcm->addr_bytes < sc->row_cycles) - return (0); - } else { - if (fcm->addr_bytes < sc->col_cycles) { - addr_bits <<= fcm->addr_bytes * 8; - fcm->column_addr |= addr_bits; - } else { - addr_bits <<= (fcm->addr_bytes - sc->col_cycles) * 8; - fcm->row_addr |= addr_bits; - } - fcm->addr_bytes++; - if (fcm->addr_bytes < (sc->row_cycles + sc->col_cycles)) - return (0); - } - - return (fsl_nand_build_address(dev, fcm->row_addr, fcm->column_addr)); -} - -static int -fsl_nand_build_address(device_t dev, uint32_t row, uint32_t column) -{ - struct fsl_nand_softc *sc; - struct fsl_nfc_fcm *fcm; - uint32_t byte_count = 0; - uint32_t block_address = 0; - uint32_t page_address = 0; - - sc = device_get_softc(dev); - fcm = &sc->fcm; - - fcm->read_ptr = 0; - fcm->buf_ofs = 0; - - if (fcm->addr_type == ADDR_ROWCOL) { - fcm->reg_fir |= (FIR_OP_CA << OP_SHIFT(fcm->opnr)); - fcm->opnr++; - - column += fcm->pg_ofs; - fcm->pg_ofs = 0; - - page_address |= column; - - if (column != 0) { - byte_count = sc->pgsz - column; - fcm->read_ptr = column; - } - } - - fcm->reg_fir |= (FIR_OP_PA << OP_SHIFT(fcm->opnr)); - fcm->opnr++; - - if (sc->pgsz == FSL_LARGE_PAGE_SIZE) { - block_address = row >> 6; - page_address |= ((row << FPAR_LP_PI_SHIFT) & FPAR_LP_PI); - fcm->buf_ofs = (row & 1) * 4096; - } else { - block_address = row >> 5; - page_address |= ((row << FPAR_SP_PI_SHIFT) & FPAR_SP_PI); - fcm->buf_ofs = (row & 7) * 1024; - } - - fcm->reg_fbcr = byte_count; - fcm->reg_fbar = block_address; - fcm->reg_fpar = page_address; - return (0); -} - -static int -fsl_nfc_start_command(device_t dev) -{ - struct fsl_nand_softc *sc; - struct fsl_nfc_fcm *fcm; - uint32_t fmr, ltesr_v; - int error, timeout; - - // device_printf(dev, "%s()\n", __func__); - - sc = device_get_softc(dev); - fcm = &sc->fcm; - - fmr = fcm->reg_fmr | FMR_OP; - - if (fcm->data_fir) - fcm->reg_fir |= (fcm->data_fir << OP_SHIFT(fcm->opnr)); - - LBC_WRITE(FIR, fcm->reg_fir); - LBC_WRITE(FCR, fcm->reg_fcr); - - LBC_WRITE(FMR, fmr); - - LBC_WRITE(FBCR, fcm->reg_fbcr); - LBC_WRITE(FBAR, fcm->reg_fbar); - LBC_WRITE(FPAR, fcm->reg_fpar); - - if (fcm->addr_type == ADDR_ID) - LBC_WRITE(MDR, fcm->reg_mdr); - - nand_debug(NDBG_DRV, "BEFORE:\nFMR=%#x, FIR=%#x, FCR=%#x", fmr, - fcm->reg_fir, fcm->reg_fcr); - nand_debug(NDBG_DRV, "MDR=%#x, FBAR=%#x, FPAR=%#x, FBCR=%#x", - LBC_READ(MDR), fcm->reg_fbar, fcm->reg_fpar, fcm->reg_fbcr); - - LBC_WRITE(LSOR, sc->dinfo->di_bank); - - timeout = (cold) ? FSL_FCM_WAIT_TIMEOUT : ~0; - error = 0; - ltesr_v = LBC_READ(LTESR); - while (!error && (ltesr_v & LTESR_CC) == 0) { - if (cold) { - DELAY(1000); - timeout--; - if (timeout < 0) - error = EWOULDBLOCK; - } else - error = tsleep(device_get_parent(sc->dev), PRIBIO, - "nfcfsl", hz); - ltesr_v = LBC_READ(LTESR); - } - if (error) - nand_debug(NDBG_DRV, "Command complete wait timeout\n"); - - nand_debug(NDBG_DRV, "AFTER:\nLTESR=%#x, LTEDR=%#x, LTEIR=%#x," - " LTEATR=%#x, LTEAR=%#x, LTECCR=%#x", ltesr_v, - LBC_READ(LTEDR), LBC_READ(LTEIR), LBC_READ(LTEATR), - LBC_READ(LTEAR), LBC_READ(LTECCR)); - - bzero(&fcm->fcm_startzero, - __rangeof(struct fsl_nfc_fcm, fcm_startzero, fcm_endzero)); - - if (fcm->status) - sc->fcm.reg_mdr = LBC_READ(MDR); - - /* Even if timeout occurred, we should perform steps below */ - LBC_WRITE(LTESR, ltesr_v); - LBC_WRITE(LTEATR, 0); - - return (error); -} - -static uint8_t -fsl_nfc_read_byte(device_t dev) -{ - struct fsl_nand_softc *sc = device_get_softc(dev); - uint32_t offset; - - // device_printf(dev, "%s()\n", __func__); - - /* - * LBC controller allows us to read status into a MDR instead of FCM - * buffer. If last operation requested before read_byte() was STATUS, - * then return MDR instead of reading a single byte from a buffer. - */ - if (sc->fcm.status) { - sc->fcm.status = 0; - return (sc->fcm.reg_mdr); - } - - KASSERT(sc->fcm.read_ptr < sc->pgsz, - ("Attempt to read beyond buffer %x %x", sc->fcm.read_ptr, - sc->pgsz)); - - offset = sc->fcm.buf_ofs + sc->fcm.read_ptr; - sc->fcm.read_ptr++; - return (bus_read_1(sc->res, offset)); -} - -static void -fsl_nfc_read_buf(device_t dev, void *buf, uint32_t len) -{ - struct fsl_nand_softc *sc = device_get_softc(dev); - uint32_t offset; - int bytesleft = 0; - - // device_printf(dev, "%s(buf=%p, len=%u)\n", __func__, buf, len); - - nand_debug(NDBG_DRV, "REQUEST OF 0x%0x B (BIB=0x%0x, NTR=0x%0x)", - len, sc->pgsz, sc->fcm.read_ptr); - - bytesleft = MIN((unsigned int)len, sc->pgsz - sc->fcm.read_ptr); - - offset = sc->fcm.buf_ofs + sc->fcm.read_ptr; - bus_read_region_1(sc->res, offset, buf, bytesleft); - sc->fcm.read_ptr += bytesleft; -} - -static void -fsl_nfc_write_buf(device_t dev, void *buf, uint32_t len) -{ - struct fsl_nand_softc *sc = device_get_softc(dev); - uint32_t offset; - int bytesleft = 0; - - // device_printf(dev, "%s(buf=%p, len=%u)\n", __func__, buf, len); - - KASSERT(len <= sc->pgsz - sc->fcm.read_ptr, - ("Attempt to write beyond buffer")); - - bytesleft = MIN((unsigned int)len, sc->pgsz - sc->fcm.read_ptr); - - nand_debug(NDBG_DRV, "REQUEST TO WRITE 0x%0x (BIB=0x%0x, NTR=0x%0x)", - bytesleft, sc->pgsz, sc->fcm.read_ptr); - - offset = sc->fcm.buf_ofs + sc->fcm.read_ptr; - bus_write_region_1(sc->res, offset, buf, bytesleft); - sc->fcm.read_ptr += bytesleft; -} - -static int -fsl_nand_chip_preprobe(device_t dev, struct nand_id *id) -{ - - if (fsl_nfc_send_command(dev, NAND_CMD_RESET) != 0) - return (ENXIO); - - if (fsl_nfc_start_command(dev) != 0) - return (ENXIO); - - DELAY(1000); - - if (fsl_nfc_send_command(dev, NAND_CMD_READ_ID)) - return (ENXIO); - - if (fsl_nfc_send_address(dev, 0)) - return (ENXIO); - - if (fsl_nfc_start_command(dev) != 0) - return (ENXIO); - - DELAY(25); - - id->man_id = fsl_nfc_read_byte(dev); - id->dev_id = fsl_nfc_read_byte(dev); - - nand_debug(NDBG_DRV, "manufacturer id: %x chip id: %x", - id->man_id, id->dev_id); - - return (0); -} - -#ifdef NAND_DEBUG_TIMING - -static SYSCTL_NODE(_debug, OID_AUTO, fcm, CTLFLAG_RD, 0, "FCM timing"); - -static u_int csct = 1; /* 22: Chip select to command time (trlx). */ -SYSCTL_UINT(_debug_fcm, OID_AUTO, csct, CTLFLAG_RW, &csct, 1, - "Chip select to command time: determines how far in advance -LCSn is " - "asserted prior to any bus activity during a NAND Flash access handled " - "by the FCM. This helps meet chip-select setup times for slow memories."); - -static u_int cst = 1; /* 23: Command setup time (trlx). */ -SYSCTL_UINT(_debug_fcm, OID_AUTO, cst, CTLFLAG_RW, &cst, 1, - "Command setup time: determines the delay of -LFWE assertion relative to " - "the command, address, or data change when the external memory access " - "is handled by the FCM."); - -static u_int cht = 1; /* 24: Command hold time (trlx). */ -SYSCTL_UINT(_debug_fcm, OID_AUTO, cht, CTLFLAG_RW, &cht, 1, - "Command hold time: determines the -LFWE negation prior to the command, " - "address, or data change when the external memory access is handled by " - "the FCM."); - -static u_int scy = 2; /* 25-27: Cycle length in bus clocks */ -SYSCTL_UINT(_debug_fcm, OID_AUTO, scy, CTLFLAG_RW, &scy, 2, - "Cycle length in bus clocks: see RM"); - -static u_int rst = 1; /* 28: Read setup time (trlx). */ -SYSCTL_UINT(_debug_fcm, OID_AUTO, rst, CTLFLAG_RW, &rst, 1, - "Read setup time: determines the delay of -LFRE assertion relative to " - "sampling of read data when the external memory access is handled by " - "the FCM."); - -static u_int trlx = 1; /* 29: Timing relaxed. */ -SYSCTL_UINT(_debug_fcm, OID_AUTO, trlx, CTLFLAG_RW, &trlx, 1, - "Timing relaxed: modifies the settings of timing parameters for slow " - "memories. See RM"); - -static u_int ehtr = 1; /* 30: Extended hold time on read accesses. */ -SYSCTL_UINT(_debug_fcm, OID_AUTO, ehtr, CTLFLAG_RW, &ehtr, 1, - "Extended hold time on read accesses: indicates with TRLX how many " - "cycles are inserted between a read access from the current bank and " - "the next access."); - -static u_int -fsl_nand_get_timing(void) -{ - u_int timing; - - timing = ((csct & 1) << 9) | ((cst & 1) << 8) | ((cht & 1) << 7) | - ((scy & 7) << 4) | ((rst & 1) << 3) | ((trlx & 1) << 2) | - ((ehtr & 1) << 1); - - printf("nfc_fsl: timing = %u\n", timing); - return (timing); -} - -static int -fsl_sysctl_program(SYSCTL_HANDLER_ARGS) -{ - struct fsl_nand_softc *sc; - int error, i; - device_t dev; - uint32_t or_v; - - error = sysctl_wire_old_buffer(req, sizeof(int)); - if (error == 0) { - i = 0; - error = sysctl_handle_int(oidp, &i, 0, req); - } - if (error != 0 || req->newptr == NULL) - return (error); - - for (i = 0; i < 8; i++) { - dev = fcm_devs[i]; - if (dev == NULL) - continue; - sc = device_get_softc(dev); - - /* Reprogram OR(x) */ - or_v = lbc_read_reg(dev, LBC85XX_OR(sc->dinfo->di_bank)); - or_v &= 0xfffffc00; - or_v |= fsl_nand_get_timing(); - lbc_write_reg(dev, LBC85XX_OR(sc->dinfo->di_bank), or_v); - } - return (0); -} - -SYSCTL_PROC(_debug_fcm, OID_AUTO, program, CTLTYPE_INT | CTLFLAG_RW, NULL, 0, - fsl_sysctl_program, "I", "write to program FCM with current values"); - -#endif /* NAND_DEBUG_TIMING */ diff --git a/sys/dev/nand/nfc_fsl.h b/sys/dev/nand/nfc_fsl.h deleted file mode 100644 index 5410da558171..000000000000 --- a/sys/dev/nand/nfc_fsl.h +++ /dev/null @@ -1,99 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2012 Juniper Networks, Inc. - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _NAND_NFC_FSL_H_ -#define _NAND_NFC_FSL_H_ - -/* LBC BR/OR Registers layout definitions */ -#define BR_V 0x00000001 -#define BR_V_SHIFT 0 -#define BR_MSEL 0x000000E0 -#define BR_MSEL_SHIFT 5 -#define BR_DECC_CHECK_MODE 0x00000600 -#define BR_DECC_CHECK_GEN 0x00000400 - -#define OR_FCM_PAGESIZE 0x00000400 - -/* Options definitions */ -#define NAND_OPT_ECC_MODE_HW 1 -#define NAND_OPT_ECC_MODE_SOFT (1 << 1) - -/* FMR - Flash Mode Register */ -#define FMR_CWTO 0xF000 -#define FMR_CWTO_SHIFT 12 -#define FMR_BOOT 0x0800 -#define FMR_ECCM 0x0100 -#define FMR_AL 0x0030 -#define FMR_AL_SHIFT 4 -#define FMR_OP 0x0003 -#define FMR_OP_SHIFT 0 - -#define FIR_OP_NOP 0x0 /* No operation and end of sequence */ -#define FIR_OP_CA 0x1 /* Issue current column address */ -#define FIR_OP_PA 0x2 /* Issue current block+page address */ -#define FIR_OP_UA 0x3 /* Issue user defined address */ -#define FIR_OP_CM(x) (4 + (x)) /* Issue command from FCR[CMD(x)] */ -#define FIR_OP_WB 0x8 /* Write FBCR bytes from FCM buffer */ -#define FIR_OP_WS 0x9 /* Write 1 or 2 bytes from MDR[AS] */ -#define FIR_OP_RB 0xA /* Read FBCR bytes to FCM buffer */ -#define FIR_OP_RS 0xB /* Read 1 or 2 bytes to MDR[AS] */ -#define FIR_OP_CW0 0xC /* Wait then issue FCR[CMD0] */ -#define FIR_OP_CW1 0xD /* Wait then issue FCR[CMD1] */ -#define FIR_OP_RBW 0xE /* Wait then read FBCR bytes */ -#define FIR_OP_RSW 0xF /* Wait then read 1 or 2 bytes */ - -/* LTESR - Transfer Error Status Register */ -#define LTESR_BM 0x80000000 -#define LTESR_FCT 0x40000000 -#define LTESR_PAR 0x20000000 -#define LTESR_WP 0x04000000 -#define LTESR_ATMW 0x00800000 -#define LTESR_ATMR 0x00400000 -#define LTESR_CS 0x00080000 -#define LTESR_CC 0x00000001 - -#define LTESR_NAND_MASK (LTESR_FCT | LTESR_CC | LTESR_CS) - -/* FPAR - Flash Page Address Register */ -#define FPAR_SP_PI 0x00007C00 -#define FPAR_SP_PI_SHIFT 10 -#define FPAR_SP_MS 0x00000200 -#define FPAR_SP_CI 0x000001FF -#define FPAR_SP_CI_SHIFT 0 -#define FPAR_LP_PI 0x0003F000 -#define FPAR_LP_PI_SHIFT 12 -#define FPAR_LP_MS 0x00000800 -#define FPAR_LP_CI 0x000007FF -#define FPAR_LP_CI_SHIFT 0 - -#define FSL_FCM_WAIT_TIMEOUT 10 - -#endif /* _NAND_NFC_FSL_H_ */ diff --git a/sys/dev/nand/nfc_if.m b/sys/dev/nand/nfc_if.m deleted file mode 100644 index a4e1099220ac..000000000000 --- a/sys/dev/nand/nfc_if.m +++ /dev/null @@ -1,165 +0,0 @@ -#- -# Copyright (C) 2009-2012 Semihalf -# 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$ - -# NAND controller interface description -# - -#include <sys/bus.h> -#include <dev/nand/nand.h> - -INTERFACE nfc; - -CODE { - static int nfc_default_method(device_t dev) - { - return (0); - } - - static int nfc_softecc_get(device_t dev, void *buf, int pagesize, - void *ecc, int *needwrite) - { - *needwrite = 1; - return (nand_softecc_get(dev, buf, pagesize, ecc)); - } - - static int nfc_softecc_correct(device_t dev, void *buf, int pagesize, - void *readecc, void *calcecc) - { - return (nand_softecc_correct(dev, buf, pagesize, readecc, - calcecc)); - } -}; - -# Send command to a NAND chip -# -# Return values: -# 0: Success -# -METHOD int send_command { - device_t dev; - uint8_t command; -}; - -# Send address to a NAND chip -# -# Return values: -# 0: Success -# -METHOD int send_address { - device_t dev; - uint8_t address; -}; - -# Read byte -# -# Return values: -# byte read -# -METHOD uint8_t read_byte { - device_t dev; -}; - -# Write byte -# -METHOD void write_byte { - device_t dev; - uint8_t byte; -}; - -# Read word -# -# Return values: -# word read -# -METHOD uint16_t read_word { - device_t dev; -}; - -# Write word -# -METHOD void write_word { - device_t dev; - uint16_t word; -}; - -# Read buf -# -METHOD void read_buf { - device_t dev; - void *buf; - uint32_t len; -}; - -# Write buf -# -METHOD void write_buf { - device_t dev; - void *buf; - uint32_t len; -}; - -# Select CS -# -METHOD int select_cs { - device_t dev; - uint8_t cs; -}; - -# Read ready/busy signal -# -METHOD int read_rnb { - device_t dev; -}; - -# Start command -# -# Return values: -# 0: Success -# -METHOD int start_command { - device_t dev; -} DEFAULT nfc_default_method; - -# Generate ECC or get it from H/W -# -METHOD int get_ecc { - device_t dev; - void *buf; - int pagesize; - void *ecc; - int *needwrite; -} DEFAULT nfc_softecc_get; - -# Correct ECC -# -METHOD int correct_ecc { - device_t dev; - void *buf; - int pagesize; - void *readecc; - void *calcecc; -} DEFAULT nfc_softecc_correct; diff --git a/sys/dev/nand/nfc_mv.c b/sys/dev/nand/nfc_mv.c deleted file mode 100644 index 0d78d34d9912..000000000000 --- a/sys/dev/nand/nfc_mv.c +++ /dev/null @@ -1,238 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * 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. - */ - -/* Integrated NAND controller driver */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/proc.h> -#include <sys/bus.h> -#include <sys/conf.h> -#include <sys/kernel.h> -#include <sys/module.h> -#include <sys/malloc.h> -#include <sys/rman.h> -#include <sys/lock.h> -#include <sys/mutex.h> -#include <sys/time.h> - -#include <machine/bus.h> -#include <machine/fdt.h> -#include <arm/mv/mvvar.h> -#include <arm/mv/mvwin.h> - -#include <dev/ofw/ofw_bus.h> -#include <dev/ofw/ofw_bus_subr.h> - -#include <dev/nand/nand.h> -#include <dev/nand/nandbus.h> -#include "nfc_if.h" - -#define MV_NAND_DATA (0x00) -#define MV_NAND_COMMAND (0x01) -#define MV_NAND_ADDRESS (0x02) - -struct mv_nand_softc { - struct nand_softc nand_dev; - bus_space_handle_t sc_handle; - bus_space_tag_t sc_tag; - struct resource *res; - int rid; -}; - -static int mv_nand_attach(device_t); -static int mv_nand_probe(device_t); -static int mv_nand_send_command(device_t, uint8_t); -static int mv_nand_send_address(device_t, uint8_t); -static uint8_t mv_nand_read_byte(device_t); -static void mv_nand_read_buf(device_t, void *, uint32_t); -static void mv_nand_write_buf(device_t, void *, uint32_t); -static int mv_nand_select_cs(device_t, uint8_t); -static int mv_nand_read_rnb(device_t); - -static device_method_t mv_nand_methods[] = { - DEVMETHOD(device_probe, mv_nand_probe), - DEVMETHOD(device_attach, mv_nand_attach), - - DEVMETHOD(nfc_send_command, mv_nand_send_command), - DEVMETHOD(nfc_send_address, mv_nand_send_address), - DEVMETHOD(nfc_read_byte, mv_nand_read_byte), - DEVMETHOD(nfc_read_buf, mv_nand_read_buf), - DEVMETHOD(nfc_write_buf, mv_nand_write_buf), - DEVMETHOD(nfc_select_cs, mv_nand_select_cs), - DEVMETHOD(nfc_read_rnb, mv_nand_read_rnb), - - { 0, 0 }, -}; - -static driver_t mv_nand_driver = { - "nand", - mv_nand_methods, - sizeof(struct mv_nand_softc), -}; - -static devclass_t mv_nand_devclass; -DRIVER_MODULE(mv_nand, localbus, mv_nand_driver, mv_nand_devclass, 0, 0); - -static int -mv_nand_probe(device_t dev) -{ - - if (!ofw_bus_is_compatible(dev, "mrvl,nfc")) - return (ENXIO); - - device_set_desc(dev, "Marvell NAND controller"); - return (BUS_PROBE_DEFAULT); -} - -static int -mv_nand_attach(device_t dev) -{ - struct mv_nand_softc *sc; - int err; - - sc = device_get_softc(dev); - sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->rid, - RF_ACTIVE); - if (sc->res == NULL) { - device_printf(dev, "could not allocate resources!\n"); - return (ENXIO); - } - - sc->sc_tag = rman_get_bustag(sc->res); - sc->sc_handle = rman_get_bushandle(sc->res); - - nand_init(&sc->nand_dev, dev, NAND_ECC_SOFT, 0, 0, NULL, NULL); - - err = nandbus_create(dev); - - return (err); -} - -static int -mv_nand_send_command(device_t dev, uint8_t command) -{ - struct mv_nand_softc *sc; - - nand_debug(NDBG_DRV,"mv_nand: send command %x", command); - - sc = device_get_softc(dev); - bus_space_write_1(sc->sc_tag, sc->sc_handle, MV_NAND_COMMAND, command); - return (0); -} - -static int -mv_nand_send_address(device_t dev, uint8_t addr) -{ - struct mv_nand_softc *sc; - - nand_debug(NDBG_DRV,"mv_nand: send address %x", addr); - - sc = device_get_softc(dev); - bus_space_write_1(sc->sc_tag, sc->sc_handle, MV_NAND_ADDRESS, addr); - return (0); -} - -static uint8_t -mv_nand_read_byte(device_t dev) -{ - struct mv_nand_softc *sc; - uint8_t data; - - sc = device_get_softc(dev); - data = bus_space_read_1(sc->sc_tag, sc->sc_handle, MV_NAND_DATA); - - nand_debug(NDBG_DRV,"mv_nand: read %x", data); - - return (data); -} - -static void -mv_nand_read_buf(device_t dev, void* buf, uint32_t len) -{ - struct mv_nand_softc *sc; - int i; - uint8_t *b = (uint8_t*)buf; - - sc = device_get_softc(dev); - - for (i = 0; i < len; i++) { - b[i] = bus_space_read_1(sc->sc_tag, sc->sc_handle, - MV_NAND_DATA); -#ifdef NAND_DEBUG - if (!(i % 16)) - printf("%s", i == 0 ? "mv_nand:\n" : "\n"); - printf(" %x", b[i]); - if (i == len - 1) - printf("\n"); -#endif - } -} - -static void -mv_nand_write_buf(device_t dev, void* buf, uint32_t len) -{ - struct mv_nand_softc *sc; - int i; - uint8_t *b = (uint8_t*)buf; - - sc = device_get_softc(dev); - - for (i = 0; i < len; i++) { -#ifdef NAND_DEBUG - if (!(i % 16)) - printf("%s", i == 0 ? "mv_nand:\n" : "\n"); - printf(" %x", b[i]); - if (i == len - 1) - printf("\n"); -#endif - bus_space_write_1(sc->sc_tag, sc->sc_handle, MV_NAND_DATA, - b[i]); - } -} - -static int -mv_nand_select_cs(device_t dev, uint8_t cs) -{ - - if (cs > 0) - return (ENODEV); - - return (0); -} - -static int -mv_nand_read_rnb(device_t dev) -{ - - /* no-op */ - return (0); /* ready */ -} diff --git a/sys/dev/nand/nfc_rb.c b/sys/dev/nand/nfc_rb.c deleted file mode 100644 index 1102b3abb9c4..000000000000 --- a/sys/dev/nand/nfc_rb.c +++ /dev/null @@ -1,321 +0,0 @@ -/*- - * Copyright (C) 2015 Justin Hibbits - * 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. - */ - -/* RouterBoard 600/800 NAND controller driver. */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/bus.h> -#include <sys/kernel.h> -#include <sys/module.h> -#include <sys/malloc.h> -#include <sys/rman.h> -#include <sys/slicer.h> - -#include <geom/geom_disk.h> - -#include <machine/bus.h> - -#include <dev/ofw/ofw_bus.h> -#include <dev/ofw/ofw_bus_subr.h> - -#include <dev/nand/nand.h> -#include <dev/nand/nandbus.h> - -#include <powerpc/mpc85xx/mpc85xx.h> - -#include "nfc_if.h" -#include "gpio_if.h" - -#define RB_NAND_DATA (0x00) - -struct rb_nand_softc { - struct nand_softc nand_dev; - struct resource *sc_mem; - int rid; - device_t sc_gpio; - uint32_t sc_rdy_pin; - uint32_t sc_nce_pin; - uint32_t sc_cle_pin; - uint32_t sc_ale_pin; -}; - -static int rb_nand_attach(device_t); -static int rb_nand_probe(device_t); -static int rb_nand_send_command(device_t, uint8_t); -static int rb_nand_send_address(device_t, uint8_t); -static uint8_t rb_nand_read_byte(device_t); -static void rb_nand_read_buf(device_t, void *, uint32_t); -static void rb_nand_write_buf(device_t, void *, uint32_t); -static int rb_nand_select_cs(device_t, uint8_t); -static int rb_nand_read_rnb(device_t); - -static device_method_t rb_nand_methods[] = { - DEVMETHOD(device_probe, rb_nand_probe), - DEVMETHOD(device_attach, rb_nand_attach), - - DEVMETHOD(nfc_send_command, rb_nand_send_command), - DEVMETHOD(nfc_send_address, rb_nand_send_address), - DEVMETHOD(nfc_read_byte, rb_nand_read_byte), - DEVMETHOD(nfc_read_buf, rb_nand_read_buf), - DEVMETHOD(nfc_write_buf, rb_nand_write_buf), - DEVMETHOD(nfc_select_cs, rb_nand_select_cs), - DEVMETHOD(nfc_read_rnb, rb_nand_read_rnb), - - { 0, 0 }, -}; - -static driver_t rb_nand_driver = { - "nand", - rb_nand_methods, - sizeof(struct rb_nand_softc), -}; - -static devclass_t rb_nand_devclass; -DRIVER_MODULE(rb_nand, ofwbus, rb_nand_driver, rb_nand_devclass, 0, 0); - -#if 0 -static const struct nand_ecc_data rb_ecc = { - .eccsize = 6, - .eccmode = NAND_ECC_SOFT, - .eccbytes = 6, - .eccpositions = { 8, 9, 10, 13, 14, 15 }, -}; -#endif - -/* Slicer operates on the NAND controller, so we have to find the chip. */ -static int -rb_nand_slicer(device_t dev, const char *provider __unused, - struct flash_slice *slices, int *nslices) -{ - struct nand_chip *chip; - device_t *children; - int n; - - if (device_get_children(dev, &children, &n) != 0) { - panic("Slicer called on controller with no child!"); - } - dev = children[0]; - free(children, M_TEMP); - - if (device_get_children(dev, &children, &n) != 0) { - panic("Slicer called on controller with nandbus but no child!"); - } - dev = children[0]; - free(children, M_TEMP); - - chip = device_get_softc(dev); - *nslices = 2; - slices[0].base = 0; - slices[0].size = 4 * 1024 * 1024; - slices[0].label = "boot"; - - slices[1].base = 4 * 1024 * 1024; - slices[1].size = chip->ndisk->d_mediasize - slices[0].size; - slices[1].label = "rootfs"; - - return (0); -} - -static int -rb_nand_probe(device_t dev) -{ - const char *device_type; - - device_type = ofw_bus_get_type(dev); - - if (!device_type || strcmp(device_type, "rb,nand")) - return (ENXIO); - - device_set_desc(dev, "RouterBoard 333/600/800 NAND controller"); - return (BUS_PROBE_DEFAULT); -} - -static int -rb_nand_attach(device_t dev) -{ - struct rb_nand_softc *sc; - phandle_t node; - uint32_t ale[2],cle[2],nce[2],rdy[2]; - u_long size,start; - int err; - - sc = device_get_softc(dev); - node = ofw_bus_get_node(dev); - - if (OF_getprop(node, "ale", ale, sizeof(ale)) <= 0) { - return (ENXIO); - } - if (OF_getprop(node, "cle", cle, sizeof(cle)) <= 0) { - return (ENXIO); - } - if (OF_getprop(node, "nce", nce, sizeof(nce)) <= 0) { - return (ENXIO); - } - if (OF_getprop(node, "rdy", rdy, sizeof(rdy)) <= 0) { - return (ENXIO); - } - - if (ale[0] != cle[0] || ale[0] != nce[0] || ale[0] != rdy[0]) { - device_printf(dev, "GPIO handles for signals must match.\n"); - return (ENXIO); - } - sc->sc_ale_pin = ale[1]; - sc->sc_cle_pin = cle[1]; - sc->sc_nce_pin = nce[1]; - sc->sc_rdy_pin = rdy[1]; - - sc->sc_gpio = OF_device_from_xref(ale[0]); - if (sc->sc_gpio == NULL) { - device_printf(dev, "No GPIO resource found!\n"); - return (ENXIO); - } - - sc->sc_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->rid, - RF_ACTIVE); - if (sc->sc_mem == NULL) { - device_printf(dev, "could not allocate resources!\n"); - return (ENXIO); - } - - start = rman_get_start(sc->sc_mem); - size = rman_get_size(sc->sc_mem); - if (law_enable(OCP85XX_TGTIF_LBC, start, size) != 0) { - bus_release_resource(dev, SYS_RES_MEMORY, sc->rid, sc->sc_mem); - device_printf(dev, "could not allocate local address window.\n"); - return (ENXIO); - } - - flash_register_slicer(rb_nand_slicer, FLASH_SLICES_TYPE_NAND, TRUE); - - nand_init(&sc->nand_dev, dev, NAND_ECC_SOFT, 0, 0, NULL, NULL); - - err = nandbus_create(dev); - - return (err); -} - -static int -rb_nand_send_command(device_t dev, uint8_t command) -{ - struct rb_nand_softc *sc; - - nand_debug(NDBG_DRV,"rb_nand: send command %x", command); - - sc = device_get_softc(dev); - GPIO_PIN_SET(sc->sc_gpio, sc->sc_cle_pin, 1); - GPIO_PIN_SET(sc->sc_gpio, sc->sc_ale_pin, 0); - GPIO_PIN_SET(sc->sc_gpio, sc->sc_nce_pin, 0); - bus_write_1(sc->sc_mem, RB_NAND_DATA, command); - GPIO_PIN_SET(sc->sc_gpio, sc->sc_cle_pin, 0); - return (0); -} - -static int -rb_nand_send_address(device_t dev, uint8_t addr) -{ - struct rb_nand_softc *sc; - - nand_debug(NDBG_DRV,"rb_nand: send address %x", addr); - - sc = device_get_softc(dev); - GPIO_PIN_SET(sc->sc_gpio, sc->sc_cle_pin, 0); - GPIO_PIN_SET(sc->sc_gpio, sc->sc_ale_pin, 1); - GPIO_PIN_SET(sc->sc_gpio, sc->sc_nce_pin, 0); - bus_write_1(sc->sc_mem, RB_NAND_DATA, addr); - GPIO_PIN_SET(sc->sc_gpio, sc->sc_ale_pin, 0); - return (0); -} - -static uint8_t -rb_nand_read_byte(device_t dev) -{ - struct rb_nand_softc *sc; - uint8_t data; - - sc = device_get_softc(dev); - data = bus_read_1(sc->sc_mem, RB_NAND_DATA); - - nand_debug(NDBG_DRV,"rb_nand: read %x", data); - - return (data); -} - -static void -rb_nand_read_buf(device_t dev, void* buf, uint32_t len) -{ - struct rb_nand_softc *sc; - - sc = device_get_softc(dev); - - bus_read_region_1(sc->sc_mem, RB_NAND_DATA, buf, len); -} - -static void -rb_nand_write_buf(device_t dev, void* buf, uint32_t len) -{ - struct rb_nand_softc *sc; - int i; - uint8_t *b = (uint8_t*)buf; - - sc = device_get_softc(dev); - - for (i = 0; i < len; i++) { -#ifdef NAND_DEBUG - if (!(i % 16)) - printf("%s", i == 0 ? "rb_nand:\n" : "\n"); - printf(" %x", b[i]); - if (i == len - 1) - printf("\n"); -#endif - bus_write_1(sc->sc_mem, RB_NAND_DATA, b[i]); - } -} - -static int -rb_nand_select_cs(device_t dev, uint8_t cs) -{ - - if (cs > 0) - return (ENODEV); - - return (0); -} - -static int -rb_nand_read_rnb(device_t dev) -{ - struct rb_nand_softc *sc; - uint32_t rdy_bit; - - sc = device_get_softc(dev); - GPIO_PIN_GET(sc->sc_gpio, sc->sc_rdy_pin, &rdy_bit); - - return (rdy_bit); /* ready */ -} diff --git a/sys/dev/ow/owc_gpiobus.c b/sys/dev/ow/owc_gpiobus.c index f03d01432b03..24a18789bea8 100644 --- a/sys/dev/ow/owc_gpiobus.c +++ b/sys/dev/ow/owc_gpiobus.c @@ -416,5 +416,7 @@ static driver_t owc_gpiobus_driver = { sizeof(struct owc_gpiobus_softc), }; -DRIVER_MODULE(owc_gpiobus_fdt, gpiobus, owc_gpiobus_driver, owc_gpiobus_devclass, 0, 0); -MODULE_DEPEND(owc_gpiobus_fdt, ow, 1, 1, 1); +DRIVER_MODULE(owc_gpiobus, gpiobus, owc_gpiobus_driver, owc_gpiobus_devclass, 0, 0); +MODULE_DEPEND(owc_gpiobus, ow, 1, 1, 1); +MODULE_DEPEND(owc_gpiobus, gpiobus, 1, 1, 1); +MODULE_VERSION(owc_gpiobus, 1); diff --git a/sys/dev/usb/usb_hub_acpi.c b/sys/dev/usb/usb_hub_acpi.c index 5dd9f06ebaa4..b536a3d282e9 100644 --- a/sys/dev/usb/usb_hub_acpi.c +++ b/sys/dev/usb/usb_hub_acpi.c @@ -243,13 +243,14 @@ acpi_uhub_parse_pld(device_t dev, unsigned int port, ACPI_HANDLE ah) } ACPI_STATUS -acpi_uhub_find_rh(device_t dev, ACPI_HANDLE * ah){ +acpi_uhub_find_rh(device_t dev, ACPI_HANDLE * ah) +{ device_t grand; ACPI_HANDLE gah; + *ah = NULL; grand = device_get_parent(device_get_parent(dev)); if ((gah = acpi_get_handle(grand)) == NULL) { - *ah = NULL; return AE_ERROR; } return AcpiWalkNamespace(ACPI_TYPE_DEVICE, gah, 1, @@ -257,7 +258,8 @@ acpi_uhub_find_rh(device_t dev, ACPI_HANDLE * ah){ } ACPI_STATUS -acpi_usb_hub_port_probe_cb(ACPI_HANDLE ah, UINT32 lv, void *ctx, void **rv){ +acpi_usb_hub_port_probe_cb(ACPI_HANDLE ah, UINT32 lv, void *ctx, void **rv) +{ ACPI_DEVICE_INFO *devinfo; device_t dev = ctx; struct acpi_uhub_softc *sc = device_get_softc(dev); @@ -281,7 +283,8 @@ acpi_usb_hub_port_probe_cb(ACPI_HANDLE ah, UINT32 lv, void *ctx, void **rv){ } ACPI_STATUS -acpi_usb_hub_port_probe(device_t dev, ACPI_HANDLE ah){ +acpi_usb_hub_port_probe(device_t dev, ACPI_HANDLE ah) +{ return AcpiWalkNamespace(ACPI_TYPE_DEVICE, ah, 1, acpi_usb_hub_port_probe_cb, @@ -293,6 +296,9 @@ acpi_uhub_root_probe(device_t dev) ACPI_HANDLE ah; ACPI_STATUS status; + if(acpi_disabled("usb")) { + return ENXIO; + } status = acpi_uhub_find_rh(dev, &ah); if (ACPI_SUCCESS(status) && ah != NULL @@ -308,7 +314,7 @@ acpi_uhub_probe(device_t dev) { ACPI_HANDLE ah = acpi_get_handle(dev); - if (ah && (uhub_probe(dev) <= 0)) { + if (!acpi_disabled("usb") && ah && (uhub_probe(dev) <= 0)) { /*success prior than non - acpi hub*/ return (BUS_PROBE_DEFAULT + 1); } @@ -335,7 +341,6 @@ acpi_uhub_root_attach(device_t dev) sc->nports = uh->nports; sc->porthandle = malloc(sizeof(ACPI_HANDLE) * uh->nports, M_USBDEV, M_WAITOK | M_ZERO); - acpi_uhub_find_rh(dev, &devhandle); acpi_usb_hub_port_probe(dev, devhandle); return 0; diff --git a/sys/dev/virtio/scsi/virtio_scsi.c b/sys/dev/virtio/scsi/virtio_scsi.c index ec98178d5697..6f2dfbcac5a4 100644 --- a/sys/dev/virtio/scsi/virtio_scsi.c +++ b/sys/dev/virtio/scsi/virtio_scsi.c @@ -81,6 +81,7 @@ static void vtscsi_read_config(struct vtscsi_softc *, struct virtio_scsi_config *); static int vtscsi_maximum_segments(struct vtscsi_softc *, int); static int vtscsi_alloc_virtqueues(struct vtscsi_softc *); +static void vtscsi_check_sizes(struct vtscsi_softc *); static void vtscsi_write_device_config(struct vtscsi_softc *); static int vtscsi_reinit(struct vtscsi_softc *); @@ -311,6 +312,8 @@ vtscsi_attach(device_t dev) goto fail; } + vtscsi_check_sizes(sc); + error = vtscsi_init_event_vq(sc); if (error) { device_printf(dev, "cannot populate the eventvq\n"); @@ -478,6 +481,26 @@ vtscsi_alloc_virtqueues(struct vtscsi_softc *sc) } static void +vtscsi_check_sizes(struct vtscsi_softc *sc) +{ + int rqsize; + + if ((sc->vtscsi_flags & VTSCSI_FLAG_INDIRECT) == 0) { + /* + * Ensure the assertions in virtqueue_enqueue(), + * even if the hypervisor reports a bad seg_max. + */ + rqsize = virtqueue_size(sc->vtscsi_request_vq); + if (sc->vtscsi_max_nsegs > rqsize) { + device_printf(sc->vtscsi_dev, + "clamping seg_max (%d %d)\n", sc->vtscsi_max_nsegs, + rqsize); + sc->vtscsi_max_nsegs = rqsize; + } + } +} + +static void vtscsi_write_device_config(struct vtscsi_softc *sc) { diff --git a/sys/fs/cuse/cuse.c b/sys/fs/cuse/cuse.c index 578bf3eda74f..765fe308af7b 100644 --- a/sys/fs/cuse/cuse.c +++ b/sys/fs/cuse/cuse.c @@ -671,8 +671,6 @@ cuse_server_unref(struct cuse_server *pcs) TAILQ_REMOVE(&cuse_server_head, pcs, entry); - cuse_free_unit_by_id_locked(pcs, -1); - while ((pcsd = TAILQ_FIRST(&pcs->hdev)) != NULL) { TAILQ_REMOVE(&pcs->hdev, pcsd, entry); cuse_unlock(); @@ -680,6 +678,8 @@ cuse_server_unref(struct cuse_server *pcs) cuse_lock(); } + cuse_free_unit_by_id_locked(pcs, -1); + while ((mem = TAILQ_FIRST(&pcs->hmem)) != NULL) { TAILQ_REMOVE(&pcs->hmem, mem, entry); cuse_unlock(); @@ -699,12 +699,38 @@ cuse_server_unref(struct cuse_server *pcs) free(pcs, M_CUSE); } +static int +cuse_server_do_close(struct cuse_server *pcs) +{ + int retval; + + cuse_lock(); + cuse_server_is_closing(pcs); + /* final client wakeup, if any */ + cuse_server_wakeup_all_client_locked(pcs); + + knlist_clear(&pcs->selinfo.si_note, 1); + + retval = pcs->refs; + cuse_unlock(); + + return (retval); +} + static void cuse_server_free(void *arg) { struct cuse_server *pcs = arg; - /* drop refcount */ + /* + * The final server unref should be done by the server thread + * to prevent deadlock in the client cdevpriv destructor, + * which cannot destroy itself. + */ + while (cuse_server_do_close(pcs) != 1) + pause("W", hz); + + /* drop final refcount */ cuse_server_unref(pcs); } @@ -746,21 +772,10 @@ static int cuse_server_close(struct cdev *dev, int fflag, int devtype, struct thread *td) { struct cuse_server *pcs; - int error; - error = cuse_server_get(&pcs); - if (error != 0) - goto done; + if (cuse_server_get(&pcs) == 0) + cuse_server_do_close(pcs); - cuse_lock(); - cuse_server_is_closing(pcs); - /* final client wakeup, if any */ - cuse_server_wakeup_all_client_locked(pcs); - - knlist_clear(&pcs->selinfo.si_note, 1); - cuse_unlock(); - -done: return (0); } diff --git a/sys/fs/fifofs/fifo_vnops.c b/sys/fs/fifofs/fifo_vnops.c index 96dd05a18323..b4fefbde79a6 100644 --- a/sys/fs/fifofs/fifo_vnops.c +++ b/sys/fs/fifofs/fifo_vnops.c @@ -174,7 +174,7 @@ fifo_open(ap) if (fip->fi_writers > 0) wakeup(&fip->fi_writers); } - fp->f_seqcount = fpipe->pipe_wgen - fip->fi_writers; + fp->f_pipegen = fpipe->pipe_wgen - fip->fi_writers; } if (ap->a_mode & FWRITE) { if ((ap->a_mode & O_NONBLOCK) && fip->fi_readers == 0) { diff --git a/sys/fs/nandfs/bmap.c b/sys/fs/nandfs/bmap.c deleted file mode 100644 index 5721cf0157bc..000000000000 --- a/sys/fs/nandfs/bmap.c +++ /dev/null @@ -1,625 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/namei.h> -#include <sys/kernel.h> -#include <sys/stat.h> -#include <sys/buf.h> -#include <sys/bio.h> -#include <sys/proc.h> -#include <sys/mount.h> -#include <sys/vnode.h> -#include <sys/signalvar.h> -#include <sys/malloc.h> -#include <sys/dirent.h> -#include <sys/lockf.h> -#include <sys/ktr.h> -#include <sys/kdb.h> - -#include <vm/vm.h> -#include <vm/vm_extern.h> -#include <vm/vm_object.h> -#include <vm/vnode_pager.h> - -#include <machine/_inttypes.h> - -#include <vm/vm.h> -#include <vm/vm_extern.h> -#include <vm/vm_object.h> -#include <vm/vnode_pager.h> - -#include "nandfs_mount.h" -#include "nandfs.h" -#include "nandfs_subr.h" -#include "bmap.h" - -static int bmap_getlbns(struct nandfs_node *, nandfs_lbn_t, - struct nandfs_indir *, int *); - -int -bmap_lookup(struct nandfs_node *node, nandfs_lbn_t lblk, nandfs_daddr_t *vblk) -{ - struct nandfs_inode *ip; - struct nandfs_indir a[NANDFS_NIADDR + 1], *ap; - nandfs_daddr_t daddr; - struct buf *bp; - int error; - int num, *nump; - - DPRINTF(BMAP, ("%s: node %p lblk %jx enter\n", __func__, node, lblk)); - ip = &node->nn_inode; - - ap = a; - nump = # - - error = bmap_getlbns(node, lblk, ap, nump); - if (error) - return (error); - - if (num == 0) { - *vblk = ip->i_db[lblk]; - return (0); - } - - DPRINTF(BMAP, ("%s: node %p lblk=%jx trying ip->i_ib[%x]\n", __func__, - node, lblk, ap->in_off)); - daddr = ip->i_ib[ap->in_off]; - for (bp = NULL, ++ap; --num; ap++) { - if (daddr == 0) { - DPRINTF(BMAP, ("%s: node %p lblk=%jx returning with " - "vblk 0\n", __func__, node, lblk)); - *vblk = 0; - return (0); - } - if (ap->in_lbn == lblk) { - DPRINTF(BMAP, ("%s: node %p lblk=%jx ap->in_lbn=%jx " - "returning address of indirect block (%jx)\n", - __func__, node, lblk, ap->in_lbn, daddr)); - *vblk = daddr; - return (0); - } - - DPRINTF(BMAP, ("%s: node %p lblk=%jx reading block " - "ap->in_lbn=%jx\n", __func__, node, lblk, ap->in_lbn)); - - error = nandfs_bread_meta(node, ap->in_lbn, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - - daddr = ((nandfs_daddr_t *)bp->b_data)[ap->in_off]; - brelse(bp); - } - - DPRINTF(BMAP, ("%s: node %p lblk=%jx returning with %jx\n", __func__, - node, lblk, daddr)); - *vblk = daddr; - - return (0); -} - -int -bmap_dirty_meta(struct nandfs_node *node, nandfs_lbn_t lblk, int force) -{ - struct nandfs_indir a[NANDFS_NIADDR+1], *ap; -#ifdef DEBUG - nandfs_daddr_t daddr; -#endif - struct buf *bp; - int error; - int num, *nump; - - DPRINTF(BMAP, ("%s: node %p lblk=%jx\n", __func__, node, lblk)); - - ap = a; - nump = # - - error = bmap_getlbns(node, lblk, ap, nump); - if (error) - return (error); - - /* - * Direct block, nothing to do - */ - if (num == 0) - return (0); - - DPRINTF(BMAP, ("%s: node %p reading blocks\n", __func__, node)); - - for (bp = NULL, ++ap; --num; ap++) { - error = nandfs_bread_meta(node, ap->in_lbn, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - -#ifdef DEBUG - daddr = ((nandfs_daddr_t *)bp->b_data)[ap->in_off]; - MPASS(daddr != 0 || node->nn_ino == 3); -#endif - - error = nandfs_dirty_buf_meta(bp, force); - if (error) - return (error); - } - - return (0); -} - -int -bmap_insert_block(struct nandfs_node *node, nandfs_lbn_t lblk, - nandfs_daddr_t vblk) -{ - struct nandfs_inode *ip; - struct nandfs_indir a[NANDFS_NIADDR+1], *ap; - struct buf *bp; - nandfs_daddr_t daddr; - int error; - int num, *nump, i; - - DPRINTF(BMAP, ("%s: node %p lblk=%jx vblk=%jx\n", __func__, node, lblk, - vblk)); - - ip = &node->nn_inode; - - ap = a; - nump = # - - error = bmap_getlbns(node, lblk, ap, nump); - if (error) - return (error); - - DPRINTF(BMAP, ("%s: node %p lblk=%jx vblk=%jx got num=%d\n", __func__, - node, lblk, vblk, num)); - - if (num == 0) { - DPRINTF(BMAP, ("%s: node %p lblk=%jx direct block\n", __func__, - node, lblk)); - ip->i_db[lblk] = vblk; - return (0); - } - - DPRINTF(BMAP, ("%s: node %p lblk=%jx indirect block level %d\n", - __func__, node, lblk, ap->in_off)); - - if (num == 1) { - DPRINTF(BMAP, ("%s: node %p lblk=%jx indirect block: inserting " - "%jx as vblk for indirect block %d\n", __func__, node, - lblk, vblk, ap->in_off)); - ip->i_ib[ap->in_off] = vblk; - return (0); - } - - bp = NULL; - daddr = ip->i_ib[a[0].in_off]; - for (i = 1; i < num; i++) { - if (bp) - brelse(bp); - if (daddr == 0) { - DPRINTF(BMAP, ("%s: node %p lblk=%jx vblk=%jx create " - "block %jx %d\n", __func__, node, lblk, vblk, - a[i].in_lbn, a[i].in_off)); - error = nandfs_bcreate_meta(node, a[i].in_lbn, NOCRED, - 0, &bp); - if (error) - return (error); - } else { - DPRINTF(BMAP, ("%s: node %p lblk=%jx vblk=%jx read " - "block %jx %d\n", __func__, node, daddr, vblk, - a[i].in_lbn, a[i].in_off)); - error = nandfs_bread_meta(node, a[i].in_lbn, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - } - daddr = ((nandfs_daddr_t *)bp->b_data)[a[i].in_off]; - } - i--; - - DPRINTF(BMAP, - ("%s: bmap node %p lblk=%jx vblk=%jx inserting vblk level %d at " - "offset %d at %jx\n", __func__, node, lblk, vblk, i, a[i].in_off, - daddr)); - - if (!bp) { - nandfs_error("%s: cannot find indirect block\n", __func__); - return (-1); - } - ((nandfs_daddr_t *)bp->b_data)[a[i].in_off] = vblk; - - error = nandfs_dirty_buf_meta(bp, 0); - if (error) { - nandfs_warning("%s: dirty failed buf: %p\n", __func__, bp); - return (error); - } - DPRINTF(BMAP, ("%s: exiting node %p lblk=%jx vblk=%jx\n", __func__, - node, lblk, vblk)); - - return (error); -} - -CTASSERT(NANDFS_NIADDR <= 3); -#define SINGLE 0 /* index of single indirect block */ -#define DOUBLE 1 /* index of double indirect block */ -#define TRIPLE 2 /* index of triple indirect block */ - -static __inline nandfs_lbn_t -lbn_offset(struct nandfs_device *fsdev, int level) -{ - nandfs_lbn_t res; - - for (res = 1; level > 0; level--) - res *= MNINDIR(fsdev); - return (res); -} - -static nandfs_lbn_t -blocks_inside(struct nandfs_device *fsdev, int level, struct nandfs_indir *nip) -{ - nandfs_lbn_t blocks; - - for (blocks = 1; level >= SINGLE; level--, nip++) { - MPASS(nip->in_off >= 0 && nip->in_off < MNINDIR(fsdev)); - blocks += nip->in_off * lbn_offset(fsdev, level); - } - - return (blocks); -} - -static int -bmap_truncate_indirect(struct nandfs_node *node, int level, nandfs_lbn_t *left, - int *cleaned, struct nandfs_indir *ap, struct nandfs_indir *fp, - nandfs_daddr_t *copy) -{ - struct buf *bp; - nandfs_lbn_t i, lbn, nlbn, factor, tosub; - struct nandfs_device *fsdev; - int error, lcleaned, modified; - - DPRINTF(BMAP, ("%s: node %p level %d left %jx\n", __func__, - node, level, *left)); - - fsdev = node->nn_nandfsdev; - - MPASS(ap->in_off >= 0 && ap->in_off < MNINDIR(fsdev)); - - factor = lbn_offset(fsdev, level); - lbn = ap->in_lbn; - - error = nandfs_bread_meta(node, lbn, NOCRED, 0, &bp); - if (error) { - if (bp != NULL) - brelse(bp); - return (error); - } - - bcopy(bp->b_data, copy, fsdev->nd_blocksize); - bqrelse(bp); - - modified = 0; - - i = ap->in_off; - - if (ap != fp) - ap++; - for (nlbn = lbn + 1 - i * factor; i >= 0 && *left > 0; i--, - nlbn += factor) { - lcleaned = 0; - - DPRINTF(BMAP, - ("%s: node %p i=%jx nlbn=%jx left=%jx ap=%p vblk %jx\n", - __func__, node, i, nlbn, *left, ap, copy[i])); - - if (copy[i] == 0) { - tosub = blocks_inside(fsdev, level - 1, ap); - if (tosub > *left) - tosub = 0; - - *left -= tosub; - } else { - if (level > SINGLE) { - if (ap == fp) - ap->in_lbn = nlbn; - - error = bmap_truncate_indirect(node, level - 1, - left, &lcleaned, ap, fp, - copy + MNINDIR(fsdev)); - if (error) - return (error); - } else { - error = nandfs_bdestroy(node, copy[i]); - if (error) - return (error); - lcleaned = 1; - *left -= 1; - } - } - - if (lcleaned) { - if (level > SINGLE) { - error = nandfs_vblock_end(fsdev, copy[i]); - if (error) - return (error); - } - copy[i] = 0; - modified++; - } - - ap = fp; - } - - if (i == -1) - *cleaned = 1; - - error = nandfs_bread_meta(node, lbn, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - if (modified) - bcopy(copy, bp->b_data, fsdev->nd_blocksize); - - /* Force success even if we can't dirty the buffer metadata when freeing space */ - nandfs_dirty_buf_meta(bp, 1); - - return (0); -} - -int -bmap_truncate_mapping(struct nandfs_node *node, nandfs_lbn_t lastblk, - nandfs_lbn_t todo) -{ - struct nandfs_inode *ip; - struct nandfs_indir a[NANDFS_NIADDR + 1], f[NANDFS_NIADDR], *ap; - nandfs_daddr_t indir_lbn[NANDFS_NIADDR]; - nandfs_daddr_t *copy; - int error, level; - nandfs_lbn_t left, tosub; - struct nandfs_device *fsdev; - int cleaned, i; - int num, *nump; - - DPRINTF(BMAP, ("%s: node %p lastblk %jx truncating by %jx\n", __func__, - node, lastblk, todo)); - - ip = &node->nn_inode; - fsdev = node->nn_nandfsdev; - - ap = a; - nump = # - - error = bmap_getlbns(node, lastblk, ap, nump); - if (error) - return (error); - - indir_lbn[SINGLE] = -NANDFS_NDADDR; - indir_lbn[DOUBLE] = indir_lbn[SINGLE] - MNINDIR(fsdev) - 1; - indir_lbn[TRIPLE] = indir_lbn[DOUBLE] - MNINDIR(fsdev) - * MNINDIR(fsdev) - 1; - - for (i = 0; i < NANDFS_NIADDR; i++) { - f[i].in_off = MNINDIR(fsdev) - 1; - f[i].in_lbn = 0xdeadbeef; - } - - left = todo; - -#ifdef DEBUG - a[num].in_off = -1; -#endif - - ap++; - num -= 2; - - if (num < 0) - goto direct; - - copy = malloc(MNINDIR(fsdev) * sizeof(nandfs_daddr_t) * (num + 1), - M_NANDFSTEMP, M_WAITOK); - - for (level = num; level >= SINGLE && left > 0; level--) { - cleaned = 0; - - if (ip->i_ib[level] == 0) { - tosub = blocks_inside(fsdev, level, ap); - if (tosub > left) - left = 0; - else - left -= tosub; - } else { - if (ap == f) - ap->in_lbn = indir_lbn[level]; - error = bmap_truncate_indirect(node, level, &left, - &cleaned, ap, f, copy); - if (error) { - free(copy, M_NANDFSTEMP); - nandfs_error("%s: error %d when truncate " - "at level %d\n", __func__, error, level); - return (error); - } - } - - if (cleaned) { - nandfs_vblock_end(fsdev, ip->i_ib[level]); - ip->i_ib[level] = 0; - } - - ap = f; - } - - free(copy, M_NANDFSTEMP); - -direct: - if (num < 0) - i = lastblk; - else - i = NANDFS_NDADDR - 1; - - for (; i >= 0 && left > 0; i--) { - if (ip->i_db[i] != 0) { - error = nandfs_bdestroy(node, ip->i_db[i]); - if (error) { - nandfs_error("%s: cannot destroy " - "block %jx, error %d\n", __func__, - (uintmax_t)ip->i_db[i], error); - return (error); - } - ip->i_db[i] = 0; - } - - left--; - } - - KASSERT(left == 0, - ("truncated wrong number of blocks (%jd should be 0)", left)); - - return (error); -} - -nandfs_lbn_t -get_maxfilesize(struct nandfs_device *fsdev) -{ - struct nandfs_indir f[NANDFS_NIADDR]; - nandfs_lbn_t max; - int i; - - max = NANDFS_NDADDR; - - for (i = 0; i < NANDFS_NIADDR; i++) { - f[i].in_off = MNINDIR(fsdev) - 1; - max += blocks_inside(fsdev, i, f); - } - - max *= fsdev->nd_blocksize; - - return (max); -} - -/* - * This is ufs_getlbns with minor modifications. - */ -/* - * Create an array of logical block number/offset pairs which represent the - * path of indirect blocks required to access a data block. The first "pair" - * contains the logical block number of the appropriate single, double or - * triple indirect block and the offset into the inode indirect block array. - * Note, the logical block number of the inode single/double/triple indirect - * block appears twice in the array, once with the offset into the i_ib and - * once with the offset into the page itself. - */ -static int -bmap_getlbns(struct nandfs_node *node, nandfs_lbn_t bn, struct nandfs_indir *ap, int *nump) -{ - nandfs_daddr_t blockcnt; - nandfs_lbn_t metalbn, realbn; - struct nandfs_device *fsdev; - int i, numlevels, off; - - fsdev = node->nn_nandfsdev; - - DPRINTF(BMAP, ("%s: node %p bn=%jx mnindir=%zd enter\n", __func__, - node, bn, MNINDIR(fsdev))); - - if (nump) - *nump = 0; - numlevels = 0; - realbn = bn; - - if (bn < 0) - bn = -bn; - - /* The first NANDFS_NDADDR blocks are direct blocks. */ - if (bn < NANDFS_NDADDR) - return (0); - - /* - * Determine the number of levels of indirection. After this loop - * is done, blockcnt indicates the number of data blocks possible - * at the previous level of indirection, and NANDFS_NIADDR - i is the - * number of levels of indirection needed to locate the requested block. - */ - for (blockcnt = 1, i = NANDFS_NIADDR, bn -= NANDFS_NDADDR;; i--, bn -= blockcnt) { - DPRINTF(BMAP, ("%s: blockcnt=%jd i=%d bn=%jd\n", __func__, - blockcnt, i, bn)); - if (i == 0) - return (EFBIG); - blockcnt *= MNINDIR(fsdev); - if (bn < blockcnt) - break; - } - - /* Calculate the address of the first meta-block. */ - if (realbn >= 0) - metalbn = -(realbn - bn + NANDFS_NIADDR - i); - else - metalbn = -(-realbn - bn + NANDFS_NIADDR - i); - - /* - * At each iteration, off is the offset into the bap array which is - * an array of disk addresses at the current level of indirection. - * The logical block number and the offset in that block are stored - * into the argument array. - */ - ap->in_lbn = metalbn; - ap->in_off = off = NANDFS_NIADDR - i; - - DPRINTF(BMAP, ("%s: initial: ap->in_lbn=%jx ap->in_off=%d\n", __func__, - metalbn, off)); - - ap++; - for (++numlevels; i <= NANDFS_NIADDR; i++) { - /* If searching for a meta-data block, quit when found. */ - if (metalbn == realbn) - break; - - blockcnt /= MNINDIR(fsdev); - off = (bn / blockcnt) % MNINDIR(fsdev); - - ++numlevels; - ap->in_lbn = metalbn; - ap->in_off = off; - - DPRINTF(BMAP, ("%s: in_lbn=%jx in_off=%d\n", __func__, - ap->in_lbn, ap->in_off)); - ++ap; - - metalbn -= -1 + off * blockcnt; - } - if (nump) - *nump = numlevels; - - DPRINTF(BMAP, ("%s: numlevels=%d\n", __func__, numlevels)); - - return (0); -} diff --git a/sys/fs/nandfs/bmap.h b/sys/fs/nandfs/bmap.h deleted file mode 100644 index a4784f7a88f9..000000000000 --- a/sys/fs/nandfs/bmap.h +++ /dev/null @@ -1,42 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _BMAP_H -#define _BMAP_H - -#include "nandfs_fs.h" - -int bmap_lookup(struct nandfs_node *, nandfs_lbn_t, nandfs_daddr_t *); -int bmap_insert_block(struct nandfs_node *, nandfs_lbn_t, nandfs_daddr_t); -int bmap_truncate_mapping(struct nandfs_node *, nandfs_lbn_t, nandfs_lbn_t); -int bmap_dirty_meta(struct nandfs_node *, nandfs_lbn_t, int); - -nandfs_lbn_t get_maxfilesize(struct nandfs_device *); - -#endif /* _BMAP_H */ diff --git a/sys/fs/nandfs/nandfs.h b/sys/fs/nandfs/nandfs.h deleted file mode 100644 index 9a9b28a1bc0b..000000000000 --- a/sys/fs/nandfs/nandfs.h +++ /dev/null @@ -1,312 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf - * Copyright (c) 2008, 2009 Reinoud Zandijk - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * From: NetBSD: nilfs.h,v 1.1 2009/07/18 16:31:42 reinoud - * - * $FreeBSD$ - */ - -#ifndef _FS_NANDFS_NANDFS_H_ -#define _FS_NANDFS_NANDFS_H_ - -#include <sys/param.h> -#include <sys/proc.h> -#include <sys/condvar.h> -#include <sys/lock.h> -#include <sys/mutex.h> - -#include <sys/queue.h> -#include <sys/uio.h> -#include <sys/mutex.h> - -#include <sys/disk.h> -#include <sys/kthread.h> -#include "nandfs_fs.h" - -MALLOC_DECLARE(M_NANDFSTEMP); - -/* Debug categories */ -#define NANDFS_DEBUG_VOLUMES 0x000001 -#define NANDFS_DEBUG_BLOCK 0x000004 -#define NANDFS_DEBUG_LOCKING 0x000008 -#define NANDFS_DEBUG_NODE 0x000010 -#define NANDFS_DEBUG_LOOKUP 0x000020 -#define NANDFS_DEBUG_READDIR 0x000040 -#define NANDFS_DEBUG_TRANSLATE 0x000080 -#define NANDFS_DEBUG_STRATEGY 0x000100 -#define NANDFS_DEBUG_READ 0x000200 -#define NANDFS_DEBUG_WRITE 0x000400 -#define NANDFS_DEBUG_IFILE 0x000800 -#define NANDFS_DEBUG_ATTR 0x001000 -#define NANDFS_DEBUG_EXTATTR 0x002000 -#define NANDFS_DEBUG_ALLOC 0x004000 -#define NANDFS_DEBUG_CPFILE 0x008000 -#define NANDFS_DEBUG_DIRHASH 0x010000 -#define NANDFS_DEBUG_NOTIMPL 0x020000 -#define NANDFS_DEBUG_SHEDULE 0x040000 -#define NANDFS_DEBUG_SEG 0x080000 -#define NANDFS_DEBUG_SYNC 0x100000 -#define NANDFS_DEBUG_PARANOIA 0x200000 -#define NANDFS_DEBUG_VNCALL 0x400000 -#define NANDFS_DEBUG_BUF 0x1000000 -#define NANDFS_DEBUG_BMAP 0x2000000 -#define NANDFS_DEBUG_DAT 0x4000000 -#define NANDFS_DEBUG_GENERIC 0x8000000 -#define NANDFS_DEBUG_CLEAN 0x10000000 - -extern int nandfs_verbose; - -#define DPRINTF(name, arg) { \ - if (nandfs_verbose & NANDFS_DEBUG_##name) {\ - printf arg;\ - };\ - } -#define DPRINTFIF(name, cond, arg) { \ - if (nandfs_verbose & NANDFS_DEBUG_##name) { \ - if (cond) printf arg;\ - };\ - } - -#define VFSTONANDFS(mp) ((struct nandfsmount *)((mp)->mnt_data)) -#define VTON(vp) ((struct nandfs_node *)(vp)->v_data) -#define NTOV(xp) ((xp)->nn_vnode) - -int nandfs_init(struct vfsconf *); -int nandfs_uninit(struct vfsconf *); - -extern struct vop_vector nandfs_vnodeops; -extern struct vop_vector nandfs_system_vnodeops; - -struct nandfs_node; - -/* Structure and derivatives */ -struct nandfs_mdt { - uint32_t entries_per_block; - uint32_t entries_per_group; - uint32_t blocks_per_group; - uint32_t groups_per_desc_block; /* desc is super group */ - uint32_t blocks_per_desc_block; /* desc is super group */ -}; - -struct nandfs_segment { - LIST_ENTRY(nandfs_segment) seg_link; - - struct nandfs_device *fsdev; - - TAILQ_HEAD(, buf) segsum; - TAILQ_HEAD(, buf) data; - - uint64_t seg_num; - uint64_t seg_next; - uint64_t start_block; - uint32_t num_blocks; - - uint32_t nblocks; - uint32_t nbinfos; - uint32_t segsum_blocks; - uint32_t segsum_bytes; - uint32_t bytes_left; - char *current_off; -}; - -struct nandfs_seginfo { - LIST_HEAD( ,nandfs_segment) seg_list; - struct nandfs_segment *curseg; - struct nandfs_device *fsdev; - uint32_t blocks; - uint8_t reiterate; -}; - -#define NANDFS_FSSTOR_FAILED 1 -struct nandfs_fsarea { - int offset; - int flags; - int last_used; -}; - -extern int nandfs_cleaner_enable; -extern int nandfs_cleaner_interval; -extern int nandfs_cleaner_segments; - -struct nandfs_device { - struct vnode *nd_devvp; - struct g_consumer *nd_gconsumer; - - struct thread *nd_syncer; - struct thread *nd_cleaner; - int nd_syncer_exit; - int nd_cleaner_exit; - - struct nandfs_fsarea nd_fsarea[NANDFS_NFSAREAS]; - int nd_last_fsarea; - - STAILQ_HEAD(nandfs_mnts, nandfsmount) nd_mounts; - SLIST_ENTRY(nandfs_device) nd_next_device; - - /* FS structures */ - struct nandfs_fsdata nd_fsdata; - struct nandfs_super_block nd_super; - struct nandfs_segment_summary nd_last_segsum; - struct nandfs_super_root nd_super_root; - struct nandfs_node *nd_dat_node; - struct nandfs_node *nd_cp_node; - struct nandfs_node *nd_su_node; - struct nandfs_node *nd_gc_node; - - struct nandfs_mdt nd_dat_mdt; - struct nandfs_mdt nd_ifile_mdt; - - struct timespec nd_ts; - - /* Synchronization */ - struct mtx nd_mutex; - struct mtx nd_sync_mtx; - struct cv nd_sync_cv; - struct mtx nd_clean_mtx; - struct cv nd_clean_cv; - struct lock nd_seg_const; - - struct nandfs_seginfo *nd_seginfo; - - /* FS geometry */ - uint64_t nd_devsize; - uint64_t nd_maxfilesize; - uint32_t nd_blocksize; - uint32_t nd_erasesize; - - uint32_t nd_devblocksize; - - uint32_t nd_segs_reserved; - - /* Segment usage */ - uint64_t nd_clean_segs; - uint64_t *nd_free_base; - uint64_t nd_free_count; - uint64_t nd_dirty_bufs; - - /* Running values */ - uint64_t nd_seg_sequence; - uint64_t nd_seg_num; - uint64_t nd_next_seg_num; - uint64_t nd_last_pseg; - uint64_t nd_last_cno; - uint64_t nd_last_ino; - uint64_t nd_fakevblk; - - int nd_mount_state; - int nd_refcnt; - int nd_syncing; - int nd_cleaning; -}; - -extern SLIST_HEAD(_nandfs_devices, nandfs_device) nandfs_devices; - -#define NANDFS_FORCE_SYNCER 0x1 -#define NANDFS_UMOUNT 0x2 - -#define SYNCER_UMOUNT 0x0 -#define SYNCER_VFS_SYNC 0x1 -#define SYNCER_BDFLUSH 0x2 -#define SYNCER_FFORCE 0x3 -#define SYNCER_FSYNC 0x4 -#define SYNCER_ROUPD 0x5 - -static __inline int -nandfs_writelockflags(struct nandfs_device *fsdev, int flags) -{ - int error = 0; - - if (lockstatus(&fsdev->nd_seg_const) != LK_EXCLUSIVE) - error = lockmgr(&fsdev->nd_seg_const, flags | LK_SHARED, NULL); - - return (error); -} - -static __inline void -nandfs_writeunlock(struct nandfs_device *fsdev) -{ - - if (lockstatus(&fsdev->nd_seg_const) != LK_EXCLUSIVE) - lockmgr(&(fsdev)->nd_seg_const, LK_RELEASE, NULL); -} - -#define NANDFS_WRITELOCKFLAGS(fsdev, flags) nandfs_writelockflags(fsdev, flags) - -#define NANDFS_WRITELOCK(fsdev) NANDFS_WRITELOCKFLAGS(fsdev, 0) - -#define NANDFS_WRITEUNLOCK(fsdev) nandfs_writeunlock(fsdev) - -#define NANDFS_WRITEASSERT(fsdev) lockmgr_assert(&(fsdev)->nd_seg_const, KA_LOCKED) - -/* Specific mountpoint; head or a checkpoint/snapshot */ -struct nandfsmount { - STAILQ_ENTRY(nandfsmount) nm_next_mount; - - struct mount *nm_vfs_mountp; - struct nandfs_device *nm_nandfsdev; - struct nandfs_args nm_mount_args; - struct nandfs_node *nm_ifile_node; - - uint8_t nm_flags; - int8_t nm_ronly; -}; - -struct nandfs_node { - struct vnode *nn_vnode; - struct nandfsmount *nn_nmp; - struct nandfs_device *nn_nandfsdev; - struct lockf *nn_lockf; - - uint64_t nn_ino; - struct nandfs_inode nn_inode; - - uint64_t nn_diroff; - uint32_t nn_flags; -}; - -#define IN_ACCESS 0x0001 /* Inode access time update request */ -#define IN_CHANGE 0x0002 /* Inode change time update request */ -#define IN_UPDATE 0x0004 /* Inode was written to; update mtime*/ -#define IN_MODIFIED 0x0008 /* node has been modified */ -#define IN_RENAME 0x0010 /* node is being renamed. */ - -/* File permissions. */ -#define IEXEC 0000100 /* Executable. */ -#define IWRITE 0000200 /* Writeable. */ -#define IREAD 0000400 /* Readable. */ -#define ISVTX 0001000 /* Sticky bit. */ -#define ISGID 0002000 /* Set-gid. */ -#define ISUID 0004000 /* Set-uid. */ - -#define PRINT_NODE_FLAGS \ - "\10\1IN_ACCESS\2IN_CHANGE\3IN_UPDATE\4IN_MODIFIED\5IN_RENAME" - -#define NANDFS_GATHER(x) ((x)->b_flags |= B_FS_FLAG1) -#define NANDFS_UNGATHER(x) ((x)->b_flags &= ~B_FS_FLAG1) -#define NANDFS_ISGATHERED(x) ((x)->b_flags & B_FS_FLAG1) - -#endif /* !_FS_NANDFS_NANDFS_H_ */ diff --git a/sys/fs/nandfs/nandfs_alloc.c b/sys/fs/nandfs/nandfs_alloc.c deleted file mode 100644 index afff174d130d..000000000000 --- a/sys/fs/nandfs/nandfs_alloc.c +++ /dev/null @@ -1,366 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/conf.h> -#include <sys/kernel.h> -#include <sys/lock.h> -#include <sys/malloc.h> -#include <sys/mount.h> -#include <sys/mutex.h> -#include <sys/namei.h> -#include <sys/sysctl.h> -#include <sys/vnode.h> -#include <sys/buf.h> -#include <sys/bio.h> - -#include <vm/vm.h> -#include <vm/vm_param.h> -#include <vm/vm_kern.h> -#include <vm/vm_page.h> - -#include <fs/nandfs/nandfs_mount.h> -#include <fs/nandfs/nandfs.h> -#include <fs/nandfs/nandfs_subr.h> - -static void -nandfs_get_desc_block_nr(struct nandfs_mdt *mdt, uint64_t desc, - uint64_t *desc_block) -{ - - *desc_block = desc * mdt->blocks_per_desc_block; -} - -static void -nandfs_get_group_block_nr(struct nandfs_mdt *mdt, uint64_t group, - uint64_t *group_block) -{ - uint64_t desc, group_off; - - desc = group / mdt->groups_per_desc_block; - group_off = group % mdt->groups_per_desc_block; - *group_block = desc * mdt->blocks_per_desc_block + - 1 + group_off * mdt->blocks_per_group; -} - -static void -init_desc_block(struct nandfs_mdt *mdt, uint8_t *block_data) -{ - struct nandfs_block_group_desc *desc; - uint32_t i; - - desc = (struct nandfs_block_group_desc *) block_data; - for (i = 0; i < mdt->groups_per_desc_block; i++) - desc[i].bg_nfrees = mdt->entries_per_group; -} - -int -nandfs_find_free_entry(struct nandfs_mdt *mdt, struct nandfs_node *node, - struct nandfs_alloc_request *req) -{ - nandfs_daddr_t desc, group, maxgroup, maxdesc, pos = 0; - nandfs_daddr_t start_group, start_desc; - nandfs_daddr_t desc_block, group_block; - nandfs_daddr_t file_blocks; - struct nandfs_block_group_desc *descriptors; - struct buf *bp, *bp2; - uint32_t *mask, i, mcount, msize; - int error; - - file_blocks = node->nn_inode.i_blocks; - maxgroup = 0x100000000ull / mdt->entries_per_group; - maxdesc = maxgroup / mdt->groups_per_desc_block; - start_group = req->entrynum / mdt->entries_per_group; - start_desc = start_group / mdt->groups_per_desc_block; - - bp = bp2 = NULL; -restart: - for (desc = start_desc; desc < maxdesc; desc++) { - nandfs_get_desc_block_nr(mdt, desc, &desc_block); - - if (bp) - brelse(bp); - if (desc_block < file_blocks) { - error = nandfs_bread(node, desc_block, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - } else { - error = nandfs_bcreate(node, desc_block, NOCRED, 0, - &bp); - if (error) - return (error); - file_blocks++; - init_desc_block(mdt, bp->b_data); - } - - descriptors = (struct nandfs_block_group_desc *) bp->b_data; - for (group = start_group; group < mdt->groups_per_desc_block; - group++) { - if (descriptors[group].bg_nfrees > 0) { - nandfs_get_group_block_nr(mdt, group, - &group_block); - - if (bp2) - brelse(bp2); - if (group_block < file_blocks) { - error = nandfs_bread(node, group_block, - NOCRED, 0, &bp2); - if (error) { - brelse(bp); - return (error); - } - } else { - error = nandfs_bcreate(node, - group_block, NOCRED, 0, &bp2); - if (error) - return (error); - file_blocks++; - } - mask = (uint32_t *)bp2->b_data; - msize = (sizeof(uint32_t) * __CHAR_BIT); - mcount = mdt->entries_per_group / msize; - for (i = 0; i < mcount; i++) { - if (mask[i] == UINT32_MAX) - continue; - - pos = ffs(~mask[i]) - 1; - pos += (msize * i); - pos += (group * mdt->entries_per_group); - pos += desc * group * - mdt->groups_per_desc_block * - mdt->entries_per_group; - goto found; - } - } - } - start_group = 0; - } - - if (start_desc != 0) { - maxdesc = start_desc; - start_desc = 0; - req->entrynum = 0; - goto restart; - } - - return (ENOENT); - -found: - req->entrynum = pos; - req->bp_desc = bp; - req->bp_bitmap = bp2; - DPRINTF(ALLOC, ("%s: desc: %p bitmap: %p entry: %#jx\n", - __func__, req->bp_desc, req->bp_bitmap, (uintmax_t)pos)); - - return (0); -} - -int -nandfs_find_entry(struct nandfs_mdt* mdt, struct nandfs_node *nnode, - struct nandfs_alloc_request *req) -{ - uint64_t dblock, bblock, eblock; - uint32_t offset; - int error; - - nandfs_mdt_trans_blk(mdt, req->entrynum, &dblock, &bblock, &eblock, - &offset); - - error = nandfs_bread(nnode, dblock, NOCRED, 0, &req->bp_desc); - if (error) { - brelse(req->bp_desc); - return (error); - } - - error = nandfs_bread(nnode, bblock, NOCRED, 0, &req->bp_bitmap); - if (error) { - brelse(req->bp_desc); - brelse(req->bp_bitmap); - return (error); - } - - error = nandfs_bread(nnode, eblock, NOCRED, 0, &req->bp_entry); - if (error) { - brelse(req->bp_desc); - brelse(req->bp_bitmap); - brelse(req->bp_entry); - return (error); - } - - DPRINTF(ALLOC, - ("%s: desc_buf: %p bitmap_buf %p entry_buf %p offset %x\n", - __func__, req->bp_desc, req->bp_bitmap, req->bp_entry, offset)); - - return (0); -} - -static __inline void -nandfs_calc_idx_entry(struct nandfs_mdt* mdt, uint32_t entrynum, - uint64_t *group, uint64_t *bitmap_idx, uint64_t *bitmap_off) -{ - - /* Find group_desc index */ - entrynum = entrynum % - (mdt->entries_per_group * mdt->groups_per_desc_block); - *group = entrynum / mdt->entries_per_group; - /* Find bitmap index and bit offset */ - entrynum = entrynum % mdt->entries_per_group; - *bitmap_idx = entrynum / (sizeof(uint32_t) * __CHAR_BIT); - *bitmap_off = entrynum % (sizeof(uint32_t) * __CHAR_BIT); -} - -int -nandfs_free_entry(struct nandfs_mdt* mdt, struct nandfs_alloc_request *req) -{ - struct nandfs_block_group_desc *descriptors; - uint64_t bitmap_idx, bitmap_off; - uint64_t group; - uint32_t *mask, maskrw; - - nandfs_calc_idx_entry(mdt, req->entrynum, &group, &bitmap_idx, - &bitmap_off); - - DPRINTF(ALLOC, ("nandfs_free_entry: req->entrynum=%jx bitmap_idx=%jx" - " bitmap_off=%jx group=%jx\n", (uintmax_t)req->entrynum, - (uintmax_t)bitmap_idx, (uintmax_t)bitmap_off, (uintmax_t)group)); - - /* Update counter of free entries for group */ - descriptors = (struct nandfs_block_group_desc *) req->bp_desc->b_data; - descriptors[group].bg_nfrees++; - - /* Set bit to indicate that entry is taken */ - mask = (uint32_t *)req->bp_bitmap->b_data; - maskrw = mask[bitmap_idx]; - KASSERT(maskrw & (1 << bitmap_off), ("freeing unallocated vblock")); - maskrw &= ~(1 << bitmap_off); - mask[bitmap_idx] = maskrw; - - /* Make descriptor, bitmap and entry buffer dirty */ - if (nandfs_dirty_buf(req->bp_desc, 0) == 0) { - nandfs_dirty_buf(req->bp_bitmap, 1); - nandfs_dirty_buf(req->bp_entry, 1); - } else { - brelse(req->bp_bitmap); - brelse(req->bp_entry); - return (-1); - } - - return (0); -} - -int -nandfs_alloc_entry(struct nandfs_mdt* mdt, struct nandfs_alloc_request *req) -{ - struct nandfs_block_group_desc *descriptors; - uint64_t bitmap_idx, bitmap_off; - uint64_t group; - uint32_t *mask, maskrw; - - nandfs_calc_idx_entry(mdt, req->entrynum, &group, &bitmap_idx, - &bitmap_off); - - DPRINTF(ALLOC, ("nandfs_alloc_entry: req->entrynum=%jx bitmap_idx=%jx" - " bitmap_off=%jx group=%jx\n", (uintmax_t)req->entrynum, - (uintmax_t)bitmap_idx, (uintmax_t)bitmap_off, (uintmax_t)group)); - - /* Update counter of free entries for group */ - descriptors = (struct nandfs_block_group_desc *) req->bp_desc->b_data; - descriptors[group].bg_nfrees--; - - /* Clear bit to indicate that entry is free */ - mask = (uint32_t *)req->bp_bitmap->b_data; - maskrw = mask[bitmap_idx]; - maskrw |= 1 << bitmap_off; - mask[bitmap_idx] = maskrw; - - /* Make descriptor, bitmap and entry buffer dirty */ - if (nandfs_dirty_buf(req->bp_desc, 0) == 0) { - nandfs_dirty_buf(req->bp_bitmap, 1); - nandfs_dirty_buf(req->bp_entry, 1); - } else { - brelse(req->bp_bitmap); - brelse(req->bp_entry); - return (-1); - } - - return (0); -} - -void -nandfs_abort_entry(struct nandfs_alloc_request *req) -{ - - brelse(req->bp_desc); - brelse(req->bp_bitmap); - brelse(req->bp_entry); -} - -int -nandfs_get_entry_block(struct nandfs_mdt *mdt, struct nandfs_node *node, - struct nandfs_alloc_request *req, uint32_t *entry, int create) -{ - struct buf *bp; - nandfs_lbn_t blocknr; - int error; - - /* Find buffer number for given entry */ - nandfs_mdt_trans(mdt, req->entrynum, &blocknr, entry); - DPRINTF(ALLOC, ("%s: ino %#jx entrynum:%#jx block:%#jx entry:%x\n", - __func__, (uintmax_t)node->nn_ino, (uintmax_t)req->entrynum, - (uintmax_t)blocknr, *entry)); - - /* Read entry block or create if 'create' parameter is not zero */ - bp = NULL; - - if (blocknr < node->nn_inode.i_blocks) - error = nandfs_bread(node, blocknr, NOCRED, 0, &bp); - else if (create) - error = nandfs_bcreate(node, blocknr, NOCRED, 0, &bp); - else - error = E2BIG; - - if (error) { - DPRINTF(ALLOC, ("%s: ino %#jx block %#jx entry %x error %d\n", - __func__, (uintmax_t)node->nn_ino, (uintmax_t)blocknr, - *entry, error)); - if (bp) - brelse(bp); - return (error); - } - - MPASS(nandfs_vblk_get(bp) != 0 || node->nn_ino == NANDFS_DAT_INO); - - req->bp_entry = bp; - return (0); -} diff --git a/sys/fs/nandfs/nandfs_bmap.c b/sys/fs/nandfs/nandfs_bmap.c deleted file mode 100644 index 6a1c2b0775d5..000000000000 --- a/sys/fs/nandfs/nandfs_bmap.c +++ /dev/null @@ -1,232 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf - * Copyright (c) 2008, 2009 Reinoud Zandijk - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * From: NetBSD: nilfs_subr.c,v 1.4 2009/07/29 17:06:57 reinoud - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/namei.h> -#include <sys/kernel.h> -#include <sys/stat.h> -#include <sys/buf.h> -#include <sys/bio.h> -#include <sys/proc.h> -#include <sys/mount.h> -#include <sys/vnode.h> -#include <sys/signalvar.h> -#include <sys/malloc.h> -#include <sys/dirent.h> -#include <sys/lockf.h> -#include <sys/ktr.h> - -#include <vm/vm.h> -#include <vm/vm_extern.h> -#include <vm/vm_object.h> -#include <vm/vnode_pager.h> - -#include <machine/_inttypes.h> - -#include <vm/vm.h> -#include <vm/vm_extern.h> -#include <vm/vm_object.h> -#include <vm/vnode_pager.h> - -#include "nandfs_mount.h" -#include "nandfs.h" -#include "nandfs_subr.h" -#include "bmap.h" - -nandfs_lbn_t -nandfs_get_maxfilesize(struct nandfs_device *fsdev) -{ - - return (get_maxfilesize(fsdev)); -} - -int -nandfs_bmap_lookup(struct nandfs_node *node, nandfs_lbn_t lblk, - nandfs_daddr_t *vblk) -{ - int error = 0; - - if (node->nn_ino == NANDFS_GC_INO && lblk >= 0) - *vblk = lblk; - else - error = bmap_lookup(node, lblk, vblk); - - DPRINTF(TRANSLATE, ("%s: error %d ino %#jx lblocknr %#jx -> %#jx\n", - __func__, error, (uintmax_t)node->nn_ino, (uintmax_t)lblk, - (uintmax_t)*vblk)); - - if (error) - nandfs_error("%s: returned %d", __func__, error); - - return (error); -} - -int -nandfs_bmap_insert_block(struct nandfs_node *node, nandfs_lbn_t lblk, - struct buf *bp) -{ - struct nandfs_device *fsdev; - nandfs_daddr_t vblk; - int error; - - fsdev = node->nn_nandfsdev; - - vblk = 0; - if (node->nn_ino != NANDFS_DAT_INO) { - error = nandfs_vblock_alloc(fsdev, &vblk); - if (error) - return (error); - } - - nandfs_buf_set(bp, NANDFS_VBLK_ASSIGNED); - nandfs_vblk_set(bp, vblk); - - error = bmap_insert_block(node, lblk, vblk); - if (error) { - nandfs_vblock_free(fsdev, vblk); - return (error); - } - - return (0); -} - -int -nandfs_bmap_dirty_blocks(struct nandfs_node *node, struct buf *bp, int force) -{ - int error; - - error = bmap_dirty_meta(node, bp->b_lblkno, force); - if (error) - nandfs_error("%s: cannot dirty buffer %p\n", - __func__, bp); - - return (error); -} - -static int -nandfs_bmap_update_mapping(struct nandfs_node *node, nandfs_lbn_t lblk, - nandfs_daddr_t blknr) -{ - int error; - - DPRINTF(BMAP, - ("%s: node: %p ino: %#jx lblk: %#jx vblk: %#jx\n", - __func__, node, (uintmax_t)node->nn_ino, (uintmax_t)lblk, - (uintmax_t)blknr)); - - error = bmap_insert_block(node, lblk, blknr); - - return (error); -} - -int -nandfs_bmap_update_block(struct nandfs_node *node, struct buf *bp, - nandfs_lbn_t blknr) -{ - nandfs_lbn_t lblk; - int error; - - lblk = bp->b_lblkno; - nandfs_vblk_set(bp, blknr); - - DPRINTF(BMAP, ("%s: node: %p ino: %#jx bp: %p lblk: %#jx blk: %#jx\n", - __func__, node, (uintmax_t)node->nn_ino, bp, - (uintmax_t)lblk, (uintmax_t)blknr)); - - error = nandfs_bmap_update_mapping(node, lblk, blknr); - if (error) { - nandfs_error("%s: cannot update lblk:%jx to blk:%jx for " - "node:%p, error:%d\n", __func__, (uintmax_t)lblk, - (uintmax_t)blknr, node, error); - return (error); - } - - return (error); -} - -int -nandfs_bmap_update_dat(struct nandfs_node *node, nandfs_daddr_t oldblk, - struct buf *bp) -{ - struct nandfs_device *fsdev; - nandfs_daddr_t vblk = 0; - int error; - - if (node->nn_ino == NANDFS_DAT_INO) - return (0); - - if (nandfs_buf_check(bp, NANDFS_VBLK_ASSIGNED)) { - nandfs_buf_clear(bp, NANDFS_VBLK_ASSIGNED); - return (0); - } - - fsdev = node->nn_nandfsdev; - - /* First alloc new virtual block.... */ - error = nandfs_vblock_alloc(fsdev, &vblk); - if (error) - return (error); - - error = nandfs_bmap_update_block(node, bp, vblk); - if (error) - return (error); - - /* Then we can end up with old one */ - nandfs_vblock_end(fsdev, oldblk); - - DPRINTF(BMAP, - ("%s: ino %#jx block %#jx: update vblk %#jx to %#jx\n", - __func__, (uintmax_t)node->nn_ino, (uintmax_t)bp->b_lblkno, - (uintmax_t)oldblk, (uintmax_t)vblk)); - return (error); -} - -int -nandfs_bmap_truncate_mapping(struct nandfs_node *node, nandfs_lbn_t oblk, - nandfs_lbn_t nblk) -{ - nandfs_lbn_t todo; - int error; - - todo = oblk - nblk; - - DPRINTF(BMAP, ("%s: node %p oblk %jx nblk %jx truncate by %jx\n", - __func__, node, oblk, nblk, todo)); - - error = bmap_truncate_mapping(node, oblk, todo); - if (error) - return (error); - - return (error); -} diff --git a/sys/fs/nandfs/nandfs_buffer.c b/sys/fs/nandfs/nandfs_buffer.c deleted file mode 100644 index 57089718554f..000000000000 --- a/sys/fs/nandfs/nandfs_buffer.c +++ /dev/null @@ -1,85 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/conf.h> -#include <sys/kernel.h> -#include <sys/lock.h> -#include <sys/malloc.h> -#include <sys/mount.h> -#include <sys/mutex.h> -#include <sys/buf.h> -#include <sys/namei.h> -#include <sys/vnode.h> -#include <sys/bio.h> - -#include <fs/nandfs/nandfs_mount.h> -#include <fs/nandfs/nandfs.h> -#include <fs/nandfs/nandfs_subr.h> - -struct buf * -nandfs_geteblk(int size, int flags) -{ - struct buf *bp; - - /* - * XXX - * Right now we can call geteblk with GB_NOWAIT_BD flag, which means - * it can return NULL. But we cannot afford to get NULL, hence this panic. - */ - bp = geteblk(size, flags); - if (bp == NULL) - panic("geteblk returned NULL"); - - return (bp); -} - -void -nandfs_dirty_bufs_increment(struct nandfs_device *fsdev) -{ - - mtx_lock(&fsdev->nd_mutex); - KASSERT(fsdev->nd_dirty_bufs >= 0, ("negative nd_dirty_bufs")); - fsdev->nd_dirty_bufs++; - mtx_unlock(&fsdev->nd_mutex); -} - -void -nandfs_dirty_bufs_decrement(struct nandfs_device *fsdev) -{ - - mtx_lock(&fsdev->nd_mutex); - KASSERT(fsdev->nd_dirty_bufs > 0, - ("decrementing not-positive nd_dirty_bufs")); - fsdev->nd_dirty_bufs--; - mtx_unlock(&fsdev->nd_mutex); -} diff --git a/sys/fs/nandfs/nandfs_cleaner.c b/sys/fs/nandfs/nandfs_cleaner.c deleted file mode 100644 index 3241c8701bfc..000000000000 --- a/sys/fs/nandfs/nandfs_cleaner.c +++ /dev/null @@ -1,622 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/conf.h> -#include <sys/kernel.h> -#include <sys/lock.h> -#include <sys/malloc.h> -#include <sys/mount.h> -#include <sys/mutex.h> -#include <sys/buf.h> -#include <sys/namei.h> -#include <sys/vnode.h> -#include <sys/bio.h> - -#include <fs/nandfs/nandfs_mount.h> -#include <fs/nandfs/nandfs.h> -#include <fs/nandfs/nandfs_subr.h> - -#define NANDFS_CLEANER_KILL 1 - -static void nandfs_cleaner(struct nandfs_device *); -static int nandfs_cleaner_clean_segments(struct nandfs_device *, - struct nandfs_vinfo *, uint32_t, struct nandfs_period *, uint32_t, - struct nandfs_bdesc *, uint32_t, uint64_t *, uint32_t); - -static int -nandfs_process_bdesc(struct nandfs_device *nffsdev, struct nandfs_bdesc *bd, - uint64_t nmembs); - -static void -nandfs_wakeup_wait_cleaner(struct nandfs_device *fsdev, int reason) -{ - - mtx_lock(&fsdev->nd_clean_mtx); - if (reason == NANDFS_CLEANER_KILL) - fsdev->nd_cleaner_exit = 1; - if (fsdev->nd_cleaning == 0) { - fsdev->nd_cleaning = 1; - wakeup(&fsdev->nd_cleaning); - } - cv_wait(&fsdev->nd_clean_cv, &fsdev->nd_clean_mtx); - mtx_unlock(&fsdev->nd_clean_mtx); -} - -int -nandfs_start_cleaner(struct nandfs_device *fsdev) -{ - int error; - - MPASS(fsdev->nd_cleaner == NULL); - - fsdev->nd_cleaner_exit = 0; - - error = kthread_add((void(*)(void *))nandfs_cleaner, fsdev, NULL, - &fsdev->nd_cleaner, 0, 0, "nandfs_cleaner"); - if (error) - printf("nandfs: could not start cleaner: %d\n", error); - - return (error); -} - -int -nandfs_stop_cleaner(struct nandfs_device *fsdev) -{ - - MPASS(fsdev->nd_cleaner != NULL); - nandfs_wakeup_wait_cleaner(fsdev, NANDFS_CLEANER_KILL); - fsdev->nd_cleaner = NULL; - - DPRINTF(CLEAN, ("cleaner stopped\n")); - return (0); -} - -static int -nandfs_cleaner_finished(struct nandfs_device *fsdev) -{ - int exit; - - mtx_lock(&fsdev->nd_clean_mtx); - fsdev->nd_cleaning = 0; - if (!fsdev->nd_cleaner_exit) { - DPRINTF(CLEAN, ("%s: sleep\n", __func__)); - msleep(&fsdev->nd_cleaning, &fsdev->nd_clean_mtx, PRIBIO, "-", - hz * nandfs_cleaner_interval); - } - exit = fsdev->nd_cleaner_exit; - cv_broadcast(&fsdev->nd_clean_cv); - mtx_unlock(&fsdev->nd_clean_mtx); - if (exit) { - DPRINTF(CLEAN, ("%s: no longer active\n", __func__)); - return (1); - } - - return (0); -} - -static void -print_suinfo(struct nandfs_suinfo *suinfo, int nsegs) -{ - int i; - - for (i = 0; i < nsegs; i++) { - DPRINTF(CLEAN, ("%jx %jd %c%c%c %10u\n", - suinfo[i].nsi_num, suinfo[i].nsi_lastmod, - (suinfo[i].nsi_flags & - (NANDFS_SEGMENT_USAGE_ACTIVE) ? 'a' : '-'), - (suinfo[i].nsi_flags & - (NANDFS_SEGMENT_USAGE_DIRTY) ? 'd' : '-'), - (suinfo[i].nsi_flags & - (NANDFS_SEGMENT_USAGE_ERROR) ? 'e' : '-'), - suinfo[i].nsi_blocks)); - } -} - -static int -nandfs_cleaner_vblock_is_alive(struct nandfs_device *fsdev, - struct nandfs_vinfo *vinfo, struct nandfs_cpinfo *cp, uint32_t ncps) -{ - int64_t idx, min, max; - - if (vinfo->nvi_end >= fsdev->nd_last_cno) - return (1); - - if (ncps == 0) - return (0); - - if (vinfo->nvi_end < cp[0].nci_cno || - vinfo->nvi_start > cp[ncps - 1].nci_cno) - return (0); - - idx = min = 0; - max = ncps - 1; - while (min <= max) { - idx = (min + max) / 2; - if (vinfo->nvi_start == cp[idx].nci_cno) - return (1); - if (vinfo->nvi_start < cp[idx].nci_cno) - max = idx - 1; - else - min = idx + 1; - } - - return (vinfo->nvi_end >= cp[idx].nci_cno); -} - -static void -nandfs_cleaner_vinfo_mark_alive(struct nandfs_device *fsdev, - struct nandfs_vinfo *vinfo, uint32_t nmembs, struct nandfs_cpinfo *cp, - uint32_t ncps) -{ - uint32_t i; - - for (i = 0; i < nmembs; i++) - vinfo[i].nvi_alive = - nandfs_cleaner_vblock_is_alive(fsdev, &vinfo[i], cp, ncps); -} - -static int -nandfs_cleaner_bdesc_is_alive(struct nandfs_device *fsdev, - struct nandfs_bdesc *bdesc) -{ - int alive; - - alive = bdesc->bd_oblocknr == bdesc->bd_blocknr; - if (!alive) - MPASS(abs(bdesc->bd_oblocknr - bdesc->bd_blocknr) > 2); - - return (alive); -} - -static void -nandfs_cleaner_bdesc_mark_alive(struct nandfs_device *fsdev, - struct nandfs_bdesc *bdesc, uint32_t nmembs) -{ - uint32_t i; - - for (i = 0; i < nmembs; i++) - bdesc[i].bd_alive = nandfs_cleaner_bdesc_is_alive(fsdev, - &bdesc[i]); -} - -static void -nandfs_cleaner_iterate_psegment(struct nandfs_device *fsdev, - struct nandfs_segment_summary *segsum, union nandfs_binfo *binfo, - nandfs_daddr_t blk, struct nandfs_vinfo **vipp, struct nandfs_bdesc **bdpp) -{ - int i; - - DPRINTF(CLEAN, ("%s nbinfos %x\n", __func__, segsum->ss_nbinfos)); - for (i = 0; i < segsum->ss_nbinfos; i++) { - if (binfo[i].bi_v.bi_ino == NANDFS_DAT_INO) { - (*bdpp)->bd_oblocknr = blk + segsum->ss_nblocks - - segsum->ss_nbinfos + i; - /* - * XXX Hack - */ - if (segsum->ss_flags & NANDFS_SS_SR) - (*bdpp)->bd_oblocknr--; - (*bdpp)->bd_level = binfo[i].bi_dat.bi_level; - (*bdpp)->bd_offset = binfo[i].bi_dat.bi_blkoff; - (*bdpp)++; - } else { - (*vipp)->nvi_ino = binfo[i].bi_v.bi_ino; - (*vipp)->nvi_vblocknr = binfo[i].bi_v.bi_vblocknr; - (*vipp)++; - } - } -} - -static int -nandfs_cleaner_iterate_segment(struct nandfs_device *fsdev, uint64_t segno, - struct nandfs_vinfo **vipp, struct nandfs_bdesc **bdpp, int *select) -{ - struct nandfs_segment_summary *segsum; - union nandfs_binfo *binfo; - struct buf *bp; - uint32_t nblocks; - nandfs_daddr_t curr, start, end; - int error = 0; - - nandfs_get_segment_range(fsdev, segno, &start, &end); - - DPRINTF(CLEAN, ("%s: segno %jx start %jx end %jx\n", __func__, segno, - start, end)); - - *select = 0; - - for (curr = start; curr < end; curr += nblocks) { - error = nandfs_dev_bread(fsdev, curr, NOCRED, 0, &bp); - if (error) { - brelse(bp); - nandfs_error("%s: couldn't load segment summary of %jx: %d\n", - __func__, segno, error); - return (error); - } - - segsum = (struct nandfs_segment_summary *)bp->b_data; - binfo = (union nandfs_binfo *)(bp->b_data + segsum->ss_bytes); - - if (!nandfs_segsum_valid(segsum)) { - brelse(bp); - nandfs_error("nandfs: invalid summary of segment %jx\n", segno); - return (error); - } - - DPRINTF(CLEAN, ("%s: %jx magic %x bytes %x nblocks %x nbinfos " - "%x\n", __func__, segno, segsum->ss_magic, segsum->ss_bytes, - segsum->ss_nblocks, segsum->ss_nbinfos)); - - nandfs_cleaner_iterate_psegment(fsdev, segsum, binfo, curr, - vipp, bdpp); - nblocks = segsum->ss_nblocks; - brelse(bp); - } - - if (error == 0) - *select = 1; - - return (error); -} - -static int -nandfs_cleaner_choose_segment(struct nandfs_device *fsdev, uint64_t **segpp, - uint64_t nsegs, uint64_t *rseg) -{ - struct nandfs_suinfo *suinfo; - uint64_t i, ssegs; - int error; - - suinfo = malloc(sizeof(*suinfo) * nsegs, M_NANDFSTEMP, - M_ZERO | M_WAITOK); - - if (*rseg >= fsdev->nd_fsdata.f_nsegments) - *rseg = 0; - -retry: - error = nandfs_get_segment_info_filter(fsdev, suinfo, nsegs, *rseg, - &ssegs, NANDFS_SEGMENT_USAGE_DIRTY, - NANDFS_SEGMENT_USAGE_ACTIVE | NANDFS_SEGMENT_USAGE_ERROR | - NANDFS_SEGMENT_USAGE_GC); - if (error) { - nandfs_error("%s:%d", __FILE__, __LINE__); - goto out; - } - if (ssegs == 0 && *rseg != 0) { - *rseg = 0; - goto retry; - } - if (ssegs > 0) { - print_suinfo(suinfo, ssegs); - - for (i = 0; i < ssegs; i++) { - (**segpp) = suinfo[i].nsi_num; - (*segpp)++; - } - *rseg = suinfo[i - 1].nsi_num + 1; - } - -out: - free(suinfo, M_NANDFSTEMP); - return (error); -} - -static int -nandfs_cleaner_body(struct nandfs_device *fsdev, uint64_t *rseg) -{ - struct nandfs_vinfo *vinfo, *vip, *vipi; - struct nandfs_bdesc *bdesc, *bdp, *bdpi; - struct nandfs_cpstat cpstat; - struct nandfs_cpinfo *cpinfo = NULL; - uint64_t *segnums, *segp; - int select, selected; - int error = 0; - int nsegs; - int i; - - nsegs = nandfs_cleaner_segments; - - vip = vinfo = malloc(sizeof(*vinfo) * - fsdev->nd_fsdata.f_blocks_per_segment * nsegs, M_NANDFSTEMP, - M_ZERO | M_WAITOK); - bdp = bdesc = malloc(sizeof(*bdesc) * - fsdev->nd_fsdata.f_blocks_per_segment * nsegs, M_NANDFSTEMP, - M_ZERO | M_WAITOK); - segp = segnums = malloc(sizeof(*segnums) * nsegs, M_NANDFSTEMP, - M_WAITOK); - - error = nandfs_cleaner_choose_segment(fsdev, &segp, nsegs, rseg); - if (error) { - nandfs_error("%s:%d", __FILE__, __LINE__); - goto out; - } - - if (segnums == segp) - goto out; - - selected = 0; - for (i = 0; i < segp - segnums; i++) { - error = nandfs_cleaner_iterate_segment(fsdev, segnums[i], &vip, - &bdp, &select); - if (error) { - /* - * XXX deselect (see below)? - */ - goto out; - } - if (!select) - segnums[i] = NANDFS_NOSEGMENT; - else { - error = nandfs_markgc_segment(fsdev, segnums[i]); - if (error) { - nandfs_error("%s:%d\n", __FILE__, __LINE__); - goto out; - } - selected++; - } - } - - if (selected == 0) { - MPASS(vinfo == vip); - MPASS(bdesc == bdp); - goto out; - } - - error = nandfs_get_cpstat(fsdev->nd_cp_node, &cpstat); - if (error) { - nandfs_error("%s:%d\n", __FILE__, __LINE__); - goto out; - } - - if (cpstat.ncp_nss != 0) { - cpinfo = malloc(sizeof(struct nandfs_cpinfo) * cpstat.ncp_nss, - M_NANDFSTEMP, M_WAITOK); - error = nandfs_get_cpinfo(fsdev->nd_cp_node, 1, NANDFS_SNAPSHOT, - cpinfo, cpstat.ncp_nss, NULL); - if (error) { - nandfs_error("%s:%d\n", __FILE__, __LINE__); - goto out_locked; - } - } - - NANDFS_WRITELOCK(fsdev); - DPRINTF(CLEAN, ("%s: got lock\n", __func__)); - - error = nandfs_get_dat_vinfo(fsdev, vinfo, vip - vinfo); - if (error) { - nandfs_error("%s:%d\n", __FILE__, __LINE__); - goto out_locked; - } - - nandfs_cleaner_vinfo_mark_alive(fsdev, vinfo, vip - vinfo, cpinfo, - cpstat.ncp_nss); - - error = nandfs_get_dat_bdescs(fsdev, bdesc, bdp - bdesc); - if (error) { - nandfs_error("%s:%d\n", __FILE__, __LINE__); - goto out_locked; - } - - nandfs_cleaner_bdesc_mark_alive(fsdev, bdesc, bdp - bdesc); - - DPRINTF(CLEAN, ("got:\n")); - for (vipi = vinfo; vipi < vip; vipi++) { - DPRINTF(CLEAN, ("v ino %jx vblocknr %jx start %jx end %jx " - "alive %d\n", vipi->nvi_ino, vipi->nvi_vblocknr, - vipi->nvi_start, vipi->nvi_end, vipi->nvi_alive)); - } - for (bdpi = bdesc; bdpi < bdp; bdpi++) { - DPRINTF(CLEAN, ("b oblocknr %jx blocknr %jx offset %jx " - "alive %d\n", bdpi->bd_oblocknr, bdpi->bd_blocknr, - bdpi->bd_offset, bdpi->bd_alive)); - } - DPRINTF(CLEAN, ("end list\n")); - - error = nandfs_cleaner_clean_segments(fsdev, vinfo, vip - vinfo, NULL, - 0, bdesc, bdp - bdesc, segnums, segp - segnums); - if (error) - nandfs_error("%s:%d\n", __FILE__, __LINE__); - -out_locked: - NANDFS_WRITEUNLOCK(fsdev); -out: - free(cpinfo, M_NANDFSTEMP); - free(segnums, M_NANDFSTEMP); - free(bdesc, M_NANDFSTEMP); - free(vinfo, M_NANDFSTEMP); - - return (error); -} - -static void -nandfs_cleaner(struct nandfs_device *fsdev) -{ - uint64_t checked_seg = 0; - int error; - - while (!nandfs_cleaner_finished(fsdev)) { - if (!nandfs_cleaner_enable || rebooting) - continue; - - DPRINTF(CLEAN, ("%s: run started\n", __func__)); - - fsdev->nd_cleaning = 1; - - error = nandfs_cleaner_body(fsdev, &checked_seg); - - DPRINTF(CLEAN, ("%s: run finished error %d\n", __func__, - error)); - } - - DPRINTF(CLEAN, ("%s: exiting\n", __func__)); - kthread_exit(); -} - -static int -nandfs_cleaner_clean_segments(struct nandfs_device *nffsdev, - struct nandfs_vinfo *vinfo, uint32_t nvinfo, - struct nandfs_period *pd, uint32_t npd, - struct nandfs_bdesc *bdesc, uint32_t nbdesc, - uint64_t *segments, uint32_t nsegs) -{ - struct nandfs_node *gc; - struct buf *bp; - uint32_t i; - int error = 0; - - gc = nffsdev->nd_gc_node; - - DPRINTF(CLEAN, ("%s: enter\n", __func__)); - - VOP_LOCK(NTOV(gc), LK_EXCLUSIVE); - for (i = 0; i < nvinfo; i++) { - if (!vinfo[i].nvi_alive) - continue; - DPRINTF(CLEAN, ("%s: read vblknr:%#jx blk:%#jx\n", - __func__, (uintmax_t)vinfo[i].nvi_vblocknr, - (uintmax_t)vinfo[i].nvi_blocknr)); - error = nandfs_bread(nffsdev->nd_gc_node, vinfo[i].nvi_blocknr, - NULL, 0, &bp); - if (error) { - nandfs_error("%s:%d", __FILE__, __LINE__); - VOP_UNLOCK(NTOV(gc), 0); - goto out; - } - nandfs_vblk_set(bp, vinfo[i].nvi_vblocknr); - nandfs_buf_set(bp, NANDFS_VBLK_ASSIGNED); - nandfs_dirty_buf(bp, 1); - } - VOP_UNLOCK(NTOV(gc), 0); - - /* Delete checkpoints */ - for (i = 0; i < npd; i++) { - DPRINTF(CLEAN, ("delete checkpoint: %jx\n", - (uintmax_t)pd[i].p_start)); - error = nandfs_delete_cp(nffsdev->nd_cp_node, pd[i].p_start, - pd[i].p_end); - if (error) { - nandfs_error("%s:%d", __FILE__, __LINE__); - goto out; - } - } - - /* Update vblocks */ - for (i = 0; i < nvinfo; i++) { - if (vinfo[i].nvi_alive) - continue; - DPRINTF(CLEAN, ("freeing vblknr: %jx\n", vinfo[i].nvi_vblocknr)); - error = nandfs_vblock_free(nffsdev, vinfo[i].nvi_vblocknr); - if (error) { - nandfs_error("%s:%d", __FILE__, __LINE__); - goto out; - } - } - - error = nandfs_process_bdesc(nffsdev, bdesc, nbdesc); - if (error) { - nandfs_error("%s:%d", __FILE__, __LINE__); - goto out; - } - - /* Add segments to clean */ - if (nffsdev->nd_free_count) { - nffsdev->nd_free_base = realloc(nffsdev->nd_free_base, - (nffsdev->nd_free_count + nsegs) * sizeof(uint64_t), - M_NANDFSTEMP, M_WAITOK | M_ZERO); - memcpy(&nffsdev->nd_free_base[nffsdev->nd_free_count], segments, - nsegs * sizeof(uint64_t)); - nffsdev->nd_free_count += nsegs; - } else { - nffsdev->nd_free_base = malloc(nsegs * sizeof(uint64_t), - M_NANDFSTEMP, M_WAITOK|M_ZERO); - memcpy(nffsdev->nd_free_base, segments, - nsegs * sizeof(uint64_t)); - nffsdev->nd_free_count = nsegs; - } - -out: - - DPRINTF(CLEAN, ("%s: exit error %d\n", __func__, error)); - - return (error); -} - -static int -nandfs_process_bdesc(struct nandfs_device *nffsdev, struct nandfs_bdesc *bd, - uint64_t nmembs) -{ - struct nandfs_node *dat_node; - struct buf *bp; - uint64_t i; - int error; - - dat_node = nffsdev->nd_dat_node; - - VOP_LOCK(NTOV(dat_node), LK_EXCLUSIVE); - - for (i = 0; i < nmembs; i++) { - if (!bd[i].bd_alive) - continue; - DPRINTF(CLEAN, ("%s: idx %jx offset %jx\n", - __func__, i, bd[i].bd_offset)); - if (bd[i].bd_level) { - error = nandfs_bread_meta(dat_node, bd[i].bd_offset, - NULL, 0, &bp); - if (error) { - nandfs_error("%s: cannot read dat node " - "level:%d\n", __func__, bd[i].bd_level); - brelse(bp); - VOP_UNLOCK(NTOV(dat_node), 0); - return (error); - } - nandfs_dirty_buf_meta(bp, 1); - nandfs_bmap_dirty_blocks(VTON(bp->b_vp), bp, 1); - } else { - error = nandfs_bread(dat_node, bd[i].bd_offset, NULL, - 0, &bp); - if (error) { - nandfs_error("%s: cannot read dat node\n", - __func__); - brelse(bp); - VOP_UNLOCK(NTOV(dat_node), 0); - return (error); - } - nandfs_dirty_buf(bp, 1); - } - DPRINTF(CLEAN, ("%s: bp: %p\n", __func__, bp)); - } - - VOP_UNLOCK(NTOV(dat_node), 0); - - return (0); -} diff --git a/sys/fs/nandfs/nandfs_cpfile.c b/sys/fs/nandfs/nandfs_cpfile.c deleted file mode 100644 index 8c9a695879e4..000000000000 --- a/sys/fs/nandfs/nandfs_cpfile.c +++ /dev/null @@ -1,778 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/conf.h> -#include <sys/kernel.h> -#include <sys/lock.h> -#include <sys/malloc.h> -#include <sys/mount.h> -#include <sys/mutex.h> -#include <sys/namei.h> -#include <sys/sysctl.h> -#include <sys/vnode.h> -#include <sys/buf.h> -#include <sys/bio.h> - -#include <vm/vm.h> -#include <vm/vm_param.h> -#include <vm/vm_kern.h> -#include <vm/vm_page.h> - -#include "nandfs_mount.h" -#include "nandfs.h" -#include "nandfs_subr.h" - - -static int -nandfs_checkpoint_size(struct nandfs_device *fsdev) -{ - - return (fsdev->nd_fsdata.f_checkpoint_size); -} - -static int -nandfs_checkpoint_blk_offset(struct nandfs_device *fsdev, uint64_t cn, - uint64_t *blk, uint64_t *offset) -{ - uint64_t off; - uint16_t cp_size, cp_per_blk; - - KASSERT((cn), ("checkpoing cannot be zero")); - - cp_size = fsdev->nd_fsdata.f_checkpoint_size; - cp_per_blk = fsdev->nd_blocksize / cp_size; - off = roundup(sizeof(struct nandfs_cpfile_header), cp_size) / cp_size; - off += (cn - 1); - - *blk = off / cp_per_blk; - *offset = (off % cp_per_blk) * cp_size; - - return (0); -} - -static int -nandfs_checkpoint_blk_remaining(struct nandfs_device *fsdev, uint64_t cn, - uint64_t blk, uint64_t offset) -{ - uint16_t cp_size, cp_remaining; - - cp_size = fsdev->nd_fsdata.f_checkpoint_size; - cp_remaining = (fsdev->nd_blocksize - offset) / cp_size; - - return (cp_remaining); -} - -int -nandfs_get_checkpoint(struct nandfs_device *fsdev, struct nandfs_node *cp_node, - uint64_t cn) -{ - struct buf *bp; - uint64_t blk, offset; - int error; - - if (cn != fsdev->nd_last_cno && cn != (fsdev->nd_last_cno + 1)) { - return (-1); - } - - error = nandfs_bread(cp_node, 0, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (-1); - } - - error = nandfs_dirty_buf(bp, 0); - if (error) - return (-1); - - - nandfs_checkpoint_blk_offset(fsdev, cn, &blk, &offset); - - if (blk != 0) { - if (blk < cp_node->nn_inode.i_blocks) - error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp); - else - error = nandfs_bcreate(cp_node, blk, NOCRED, 0, &bp); - if (error) { - if (bp) - brelse(bp); - return (-1); - } - - nandfs_dirty_buf(bp, 1); - } - - DPRINTF(CPFILE, ("%s: cn:%#jx entry block:%#jx offset:%#jx\n", - __func__, (uintmax_t)cn, (uintmax_t)blk, (uintmax_t)offset)); - - return (0); -} - -int -nandfs_set_checkpoint(struct nandfs_device *fsdev, struct nandfs_node *cp_node, - uint64_t cn, struct nandfs_inode *ifile_inode, uint64_t nblocks) -{ - struct nandfs_cpfile_header *cnh; - struct nandfs_checkpoint *cnp; - struct buf *bp; - uint64_t blk, offset; - int error; - - if (cn != fsdev->nd_last_cno && cn != (fsdev->nd_last_cno + 1)) { - nandfs_error("%s: trying to set invalid chekpoint %jx - %jx\n", - __func__, cn, fsdev->nd_last_cno); - return (-1); - } - - error = nandfs_bread(cp_node, 0, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return error; - } - - cnh = (struct nandfs_cpfile_header *) bp->b_data; - cnh->ch_ncheckpoints++; - - nandfs_checkpoint_blk_offset(fsdev, cn, &blk, &offset); - - if(blk != 0) { - brelse(bp); - error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return error; - } - } - - cnp = (struct nandfs_checkpoint *)((uint8_t *)bp->b_data + offset); - cnp->cp_flags = 0; - cnp->cp_checkpoints_count = 1; - memset(&cnp->cp_snapshot_list, 0, sizeof(struct nandfs_snapshot_list)); - cnp->cp_cno = cn; - cnp->cp_create = fsdev->nd_ts.tv_sec; - cnp->cp_nblk_inc = nblocks; - cnp->cp_blocks_count = 0; - memcpy (&cnp->cp_ifile_inode, ifile_inode, sizeof(cnp->cp_ifile_inode)); - - DPRINTF(CPFILE, ("%s: cn:%#jx ctime:%#jx nblk:%#jx\n", - __func__, (uintmax_t)cn, (uintmax_t)cnp->cp_create, - (uintmax_t)nblocks)); - - brelse(bp); - return (0); -} - -static int -nandfs_cp_mounted(struct nandfs_device *nandfsdev, uint64_t cno) -{ - struct nandfsmount *nmp; - int mounted = 0; - - mtx_lock(&nandfsdev->nd_mutex); - /* No double-mounting of the same checkpoint */ - STAILQ_FOREACH(nmp, &nandfsdev->nd_mounts, nm_next_mount) { - if (nmp->nm_mount_args.cpno == cno) { - mounted = 1; - break; - } - } - mtx_unlock(&nandfsdev->nd_mutex); - - return (mounted); -} - -static int -nandfs_cp_set_snapshot(struct nandfs_node *cp_node, uint64_t cno) -{ - struct nandfs_device *fsdev; - struct nandfs_cpfile_header *cnh; - struct nandfs_checkpoint *cnp; - struct nandfs_snapshot_list *list; - struct buf *bp; - uint64_t blk, prev_blk, offset; - uint64_t curr, prev; - int error; - - fsdev = cp_node->nn_nandfsdev; - - /* Get snapshot data */ - nandfs_checkpoint_blk_offset(fsdev, cno, &blk, &offset); - error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - cnp = (struct nandfs_checkpoint *)(bp->b_data + offset); - if (cnp->cp_flags & NANDFS_CHECKPOINT_INVALID) { - brelse(bp); - return (ENOENT); - } - if ((cnp->cp_flags & NANDFS_CHECKPOINT_SNAPSHOT)) { - brelse(bp); - return (EINVAL); - } - - brelse(bp); - /* Get list from header */ - error = nandfs_bread(cp_node, 0, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - - cnh = (struct nandfs_cpfile_header *) bp->b_data; - list = &cnh->ch_snapshot_list; - prev = list->ssl_prev; - brelse(bp); - prev_blk = ~(0); - curr = 0; - while (prev > cno) { - curr = prev; - nandfs_checkpoint_blk_offset(fsdev, prev, &prev_blk, &offset); - error = nandfs_bread(cp_node, prev_blk, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - cnp = (struct nandfs_checkpoint *)(bp->b_data + offset); - list = &cnp->cp_snapshot_list; - prev = list->ssl_prev; - brelse(bp); - } - - if (curr == 0) { - nandfs_bread(cp_node, 0, NOCRED, 0, &bp); - cnh = (struct nandfs_cpfile_header *) bp->b_data; - list = &cnh->ch_snapshot_list; - } else { - nandfs_checkpoint_blk_offset(fsdev, curr, &blk, &offset); - error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - cnp = (struct nandfs_checkpoint *)(bp->b_data + offset); - list = &cnp->cp_snapshot_list; - } - - list->ssl_prev = cno; - error = nandfs_dirty_buf(bp, 0); - if (error) - return (error); - - - /* Update snapshot for cno */ - nandfs_checkpoint_blk_offset(fsdev, cno, &blk, &offset); - error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - cnp = (struct nandfs_checkpoint *)(bp->b_data + offset); - list = &cnp->cp_snapshot_list; - list->ssl_prev = prev; - list->ssl_next = curr; - cnp->cp_flags |= NANDFS_CHECKPOINT_SNAPSHOT; - nandfs_dirty_buf(bp, 1); - - if (prev == 0) { - nandfs_bread(cp_node, 0, NOCRED, 0, &bp); - cnh = (struct nandfs_cpfile_header *) bp->b_data; - list = &cnh->ch_snapshot_list; - } else { - /* Update snapshot list for prev */ - nandfs_checkpoint_blk_offset(fsdev, prev, &blk, &offset); - error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - cnp = (struct nandfs_checkpoint *)(bp->b_data + offset); - list = &cnp->cp_snapshot_list; - } - list->ssl_next = cno; - nandfs_dirty_buf(bp, 1); - - /* Update header */ - error = nandfs_bread(cp_node, 0, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - cnh = (struct nandfs_cpfile_header *) bp->b_data; - cnh->ch_nsnapshots++; - nandfs_dirty_buf(bp, 1); - - return (0); -} - -static int -nandfs_cp_clr_snapshot(struct nandfs_node *cp_node, uint64_t cno) -{ - struct nandfs_device *fsdev; - struct nandfs_cpfile_header *cnh; - struct nandfs_checkpoint *cnp; - struct nandfs_snapshot_list *list; - struct buf *bp; - uint64_t blk, offset, snapshot_cnt; - uint64_t next, prev; - int error; - - fsdev = cp_node->nn_nandfsdev; - - /* Get snapshot data */ - nandfs_checkpoint_blk_offset(fsdev, cno, &blk, &offset); - error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - cnp = (struct nandfs_checkpoint *)(bp->b_data + offset); - if (cnp->cp_flags & NANDFS_CHECKPOINT_INVALID) { - brelse(bp); - return (ENOENT); - } - if (!(cnp->cp_flags & NANDFS_CHECKPOINT_SNAPSHOT)) { - brelse(bp); - return (EINVAL); - } - - list = &cnp->cp_snapshot_list; - next = list->ssl_next; - prev = list->ssl_prev; - brelse(bp); - - /* Get previous snapshot */ - if (prev != 0) { - nandfs_checkpoint_blk_offset(fsdev, prev, &blk, &offset); - error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - cnp = (struct nandfs_checkpoint *)(bp->b_data + offset); - list = &cnp->cp_snapshot_list; - } else { - nandfs_bread(cp_node, 0, NOCRED, 0, &bp); - cnh = (struct nandfs_cpfile_header *) bp->b_data; - list = &cnh->ch_snapshot_list; - } - - list->ssl_next = next; - error = nandfs_dirty_buf(bp, 0); - if (error) - return (error); - - /* Get next snapshot */ - if (next != 0) { - nandfs_checkpoint_blk_offset(fsdev, next, &blk, &offset); - error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - cnp = (struct nandfs_checkpoint *)(bp->b_data + offset); - list = &cnp->cp_snapshot_list; - } else { - nandfs_bread(cp_node, 0, NOCRED, 0, &bp); - cnh = (struct nandfs_cpfile_header *) bp->b_data; - list = &cnh->ch_snapshot_list; - } - list->ssl_prev = prev; - nandfs_dirty_buf(bp, 1); - - /* Update snapshot list for cno */ - nandfs_checkpoint_blk_offset(fsdev, cno, &blk, &offset); - error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - cnp = (struct nandfs_checkpoint *)(bp->b_data + offset); - list = &cnp->cp_snapshot_list; - list->ssl_prev = 0; - list->ssl_next = 0; - cnp->cp_flags &= !NANDFS_CHECKPOINT_SNAPSHOT; - nandfs_dirty_buf(bp, 1); - - /* Update header */ - error = nandfs_bread(cp_node, 0, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - cnh = (struct nandfs_cpfile_header *) bp->b_data; - snapshot_cnt = cnh->ch_nsnapshots; - snapshot_cnt--; - cnh->ch_nsnapshots = snapshot_cnt; - nandfs_dirty_buf(bp, 1); - - return (0); -} - -int -nandfs_chng_cpmode(struct nandfs_node *node, struct nandfs_cpmode *ncpm) -{ - struct nandfs_device *fsdev; - uint64_t cno = ncpm->ncpm_cno; - int mode = ncpm->ncpm_mode; - int ret; - - fsdev = node->nn_nandfsdev; - VOP_LOCK(NTOV(node), LK_EXCLUSIVE); - switch (mode) { - case NANDFS_CHECKPOINT: - if (nandfs_cp_mounted(fsdev, cno)) { - ret = EBUSY; - } else - ret = nandfs_cp_clr_snapshot(node, cno); - break; - case NANDFS_SNAPSHOT: - ret = nandfs_cp_set_snapshot(node, cno); - break; - default: - ret = EINVAL; - break; - } - VOP_UNLOCK(NTOV(node), 0); - - return (ret); -} - -static void -nandfs_cpinfo_fill(struct nandfs_checkpoint *cnp, struct nandfs_cpinfo *nci) -{ - - nci->nci_flags = cnp->cp_flags; - nci->nci_pad = 0; - nci->nci_cno = cnp->cp_cno; - nci->nci_create = cnp->cp_create; - nci->nci_nblk_inc = cnp->cp_nblk_inc; - nci->nci_blocks_count = cnp->cp_blocks_count; - nci->nci_next = cnp->cp_snapshot_list.ssl_next; - DPRINTF(CPFILE, ("%s: cn:%#jx ctime:%#jx\n", - __func__, (uintmax_t)cnp->cp_cno, - (uintmax_t)cnp->cp_create)); -} - -static int -nandfs_get_cpinfo_cp(struct nandfs_node *node, uint64_t cno, - struct nandfs_cpinfo *nci, uint32_t mnmembs, uint32_t *nmembs) -{ - struct nandfs_device *fsdev; - struct buf *bp; - uint64_t blk, offset, last_cno, i; - uint16_t remaining; - int error; -#ifdef INVARIANTS - uint64_t testblk, testoffset; -#endif - - if (cno == 0) { - return (ENOENT); - } - - if (mnmembs < 1) { - return (EINVAL); - } - - fsdev = node->nn_nandfsdev; - last_cno = fsdev->nd_last_cno; - DPRINTF(CPFILE, ("%s: cno:%#jx mnmembs: %#jx last:%#jx\n", __func__, - (uintmax_t)cno, (uintmax_t)mnmembs, - (uintmax_t)fsdev->nd_last_cno)); - - /* - * do { - * get block - * read checkpoints until we hit last checkpoint, end of block or - * requested number - * } while (last read checkpoint <= last checkpoint on fs && - * read checkpoints < request number); - */ - *nmembs = i = 0; - do { - nandfs_checkpoint_blk_offset(fsdev, cno, &blk, &offset); - remaining = nandfs_checkpoint_blk_remaining(fsdev, cno, - blk, offset); - error = nandfs_bread(node, blk, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - - while (cno <= last_cno && i < mnmembs && remaining) { -#ifdef INVARIANTS - nandfs_checkpoint_blk_offset(fsdev, cno, &testblk, - &testoffset); - KASSERT(testblk == blk, ("testblk != blk")); - KASSERT(testoffset == offset, ("testoffset != offset")); -#endif - DPRINTF(CPFILE, ("%s: cno %#jx\n", __func__, - (uintmax_t)cno)); - - nandfs_cpinfo_fill((struct nandfs_checkpoint *) - (bp->b_data + offset), nci); - offset += nandfs_checkpoint_size(fsdev); - i++; - nci++; - cno++; - (*nmembs)++; - remaining--; - } - brelse(bp); - } while (cno <= last_cno && i < mnmembs); - - return (0); -} - -static int -nandfs_get_cpinfo_sp(struct nandfs_node *node, uint64_t cno, - struct nandfs_cpinfo *nci, uint32_t mnmembs, uint32_t *nmembs) -{ - struct nandfs_checkpoint *cnp; - struct nandfs_cpfile_header *cnh; - struct nandfs_device *fsdev; - struct buf *bp = NULL; - uint64_t curr = 0; - uint64_t blk, offset, curr_cno; - uint32_t flag; - int i, error; - - if (cno == 0 || cno == ~(0)) - return (ENOENT); - - fsdev = node->nn_nandfsdev; - curr_cno = cno; - - if (nmembs) - *nmembs = 0; - if (curr_cno == 1) { - /* Get list from header */ - error = nandfs_bread(node, 0, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - cnh = (struct nandfs_cpfile_header *) bp->b_data; - curr_cno = cnh->ch_snapshot_list.ssl_next; - brelse(bp); - bp = NULL; - - /* No snapshots */ - if (curr_cno == 0) - return (0); - } - - for (i = 0; i < mnmembs; i++, nci++) { - nandfs_checkpoint_blk_offset(fsdev, curr_cno, &blk, &offset); - if (i == 0 || curr != blk) { - if (bp) - brelse(bp); - error = nandfs_bread(node, blk, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (ENOENT); - } - curr = blk; - } - cnp = (struct nandfs_checkpoint *)(bp->b_data + offset); - flag = cnp->cp_flags; - if (!(flag & NANDFS_CHECKPOINT_SNAPSHOT) || - (flag & NANDFS_CHECKPOINT_INVALID)) - break; - - nci->nci_flags = flag; - nci->nci_pad = 0; - nci->nci_cno = cnp->cp_cno; - nci->nci_create = cnp->cp_create; - nci->nci_nblk_inc = cnp->cp_nblk_inc; - nci->nci_blocks_count = cnp->cp_blocks_count; - nci->nci_next = cnp->cp_snapshot_list.ssl_next; - if (nmembs) - (*nmembs)++; - - curr_cno = nci->nci_next; - if (!curr_cno) - break; - } - - brelse(bp); - - return (0); -} - -int -nandfs_get_cpinfo(struct nandfs_node *node, uint64_t cno, uint16_t flags, - struct nandfs_cpinfo *nci, uint32_t nmembs, uint32_t *nnmembs) -{ - int error; - - VOP_LOCK(NTOV(node), LK_EXCLUSIVE); - switch (flags) { - case NANDFS_CHECKPOINT: - error = nandfs_get_cpinfo_cp(node, cno, nci, nmembs, nnmembs); - break; - case NANDFS_SNAPSHOT: - error = nandfs_get_cpinfo_sp(node, cno, nci, nmembs, nnmembs); - break; - default: - error = EINVAL; - break; - } - VOP_UNLOCK(NTOV(node), 0); - - return (error); -} - -int -nandfs_get_cpinfo_ioctl(struct nandfs_node *node, struct nandfs_argv *nargv) -{ - struct nandfs_cpinfo *nci; - uint64_t cno = nargv->nv_index; - void *buf = (void *)((uintptr_t)nargv->nv_base); - uint16_t flags = nargv->nv_flags; - uint32_t nmembs = 0; - int error; - - if (nargv->nv_nmembs > NANDFS_CPINFO_MAX) - return (EINVAL); - - nci = malloc(sizeof(struct nandfs_cpinfo) * nargv->nv_nmembs, - M_NANDFSTEMP, M_WAITOK | M_ZERO); - - error = nandfs_get_cpinfo(node, cno, flags, nci, nargv->nv_nmembs, &nmembs); - - if (error == 0) { - nargv->nv_nmembs = nmembs; - error = copyout(nci, buf, - sizeof(struct nandfs_cpinfo) * nmembs); - } - - free(nci, M_NANDFSTEMP); - return (error); -} - -int -nandfs_delete_cp(struct nandfs_node *node, uint64_t start, uint64_t end) -{ - struct nandfs_checkpoint *cnp; - struct nandfs_device *fsdev; - struct buf *bp; - uint64_t cno = start, blk, offset; - int error; - - DPRINTF(CPFILE, ("%s: delete cno %jx-%jx\n", __func__, start, end)); - VOP_LOCK(NTOV(node), LK_EXCLUSIVE); - fsdev = node->nn_nandfsdev; - for (cno = start; cno <= end; cno++) { - if (!cno) - continue; - - nandfs_checkpoint_blk_offset(fsdev, cno, &blk, &offset); - error = nandfs_bread(node, blk, NOCRED, 0, &bp); - if (error) { - VOP_UNLOCK(NTOV(node), 0); - brelse(bp); - return (error); - } - - cnp = (struct nandfs_checkpoint *)(bp->b_data + offset); - if (cnp->cp_flags & NANDFS_CHECKPOINT_SNAPSHOT) { - brelse(bp); - VOP_UNLOCK(NTOV(node), 0); - return (0); - } - - cnp->cp_flags |= NANDFS_CHECKPOINT_INVALID; - - error = nandfs_dirty_buf(bp, 0); - if (error) - return (error); - } - VOP_UNLOCK(NTOV(node), 0); - - return (0); -} - -int -nandfs_make_snap(struct nandfs_device *fsdev, uint64_t *cno) -{ - struct nandfs_cpmode cpm; - int error; - - *cno = cpm.ncpm_cno = fsdev->nd_last_cno; - cpm.ncpm_mode = NANDFS_SNAPSHOT; - error = nandfs_chng_cpmode(fsdev->nd_cp_node, &cpm); - return (error); -} - -int -nandfs_delete_snap(struct nandfs_device *fsdev, uint64_t cno) -{ - struct nandfs_cpmode cpm; - int error; - - cpm.ncpm_cno = cno; - cpm.ncpm_mode = NANDFS_CHECKPOINT; - error = nandfs_chng_cpmode(fsdev->nd_cp_node, &cpm); - return (error); -} - -int nandfs_get_cpstat(struct nandfs_node *cp_node, struct nandfs_cpstat *ncp) -{ - struct nandfs_device *fsdev; - struct nandfs_cpfile_header *cnh; - struct buf *bp; - int error; - - VOP_LOCK(NTOV(cp_node), LK_EXCLUSIVE); - fsdev = cp_node->nn_nandfsdev; - - /* Get header */ - error = nandfs_bread(cp_node, 0, NOCRED, 0, &bp); - if (error) { - brelse(bp); - VOP_UNLOCK(NTOV(cp_node), 0); - return (error); - } - cnh = (struct nandfs_cpfile_header *) bp->b_data; - ncp->ncp_cno = fsdev->nd_last_cno; - ncp->ncp_ncps = cnh->ch_ncheckpoints; - ncp->ncp_nss = cnh->ch_nsnapshots; - DPRINTF(CPFILE, ("%s: cno:%#jx ncps:%#jx nss:%#jx\n", - __func__, ncp->ncp_cno, ncp->ncp_ncps, ncp->ncp_nss)); - brelse(bp); - VOP_UNLOCK(NTOV(cp_node), 0); - - return (0); -} diff --git a/sys/fs/nandfs/nandfs_dat.c b/sys/fs/nandfs/nandfs_dat.c deleted file mode 100644 index e81a117589f8..000000000000 --- a/sys/fs/nandfs/nandfs_dat.c +++ /dev/null @@ -1,346 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/conf.h> -#include <sys/kernel.h> -#include <sys/lock.h> -#include <sys/malloc.h> -#include <sys/mount.h> -#include <sys/mutex.h> -#include <sys/namei.h> -#include <sys/sysctl.h> -#include <sys/vnode.h> -#include <sys/buf.h> -#include <sys/bio.h> - -#include <vm/vm.h> -#include <vm/vm_param.h> -#include <vm/vm_kern.h> -#include <vm/vm_page.h> - -#include <fs/nandfs/nandfs_mount.h> -#include <fs/nandfs/nandfs.h> -#include <fs/nandfs/nandfs_subr.h> - -int -nandfs_vblock_alloc(struct nandfs_device *nandfsdev, nandfs_daddr_t *vblock) -{ - struct nandfs_node *dat; - struct nandfs_mdt *mdt; - struct nandfs_alloc_request req; - struct nandfs_dat_entry *dat_entry; - uint64_t start; - uint32_t entry; - int locked, error; - - dat = nandfsdev->nd_dat_node; - mdt = &nandfsdev->nd_dat_mdt; - start = nandfsdev->nd_last_cno + 1; - - locked = NANDFS_VOP_ISLOCKED(NTOV(dat)); - if (!locked) - VOP_LOCK(NTOV(dat), LK_EXCLUSIVE); - req.entrynum = 0; - - /* Alloc vblock number */ - error = nandfs_find_free_entry(mdt, dat, &req); - if (error) { - nandfs_error("%s: cannot find free vblk entry\n", - __func__); - if (!locked) - VOP_UNLOCK(NTOV(dat), 0); - return (error); - } - - /* Read/create buffer */ - error = nandfs_get_entry_block(mdt, dat, &req, &entry, 1); - if (error) { - nandfs_error("%s: cannot get free vblk entry\n", - __func__); - nandfs_abort_entry(&req); - if (!locked) - VOP_UNLOCK(NTOV(dat), 0); - return (error); - } - - /* Fill out vblock data */ - dat_entry = (struct nandfs_dat_entry *) req.bp_entry->b_data; - dat_entry[entry].de_start = start; - dat_entry[entry].de_end = UINTMAX_MAX; - dat_entry[entry].de_blocknr = 0; - - /* Commit allocation */ - error = nandfs_alloc_entry(mdt, &req); - if (error) { - nandfs_error("%s: cannot get free vblk entry\n", - __func__); - if (!locked) - VOP_UNLOCK(NTOV(dat), 0); - return (error); - } - - /* Return allocated vblock */ - *vblock = req.entrynum; - DPRINTF(DAT, ("%s: allocated vblock %#jx\n", - __func__, (uintmax_t)*vblock)); - - if (!locked) - VOP_UNLOCK(NTOV(dat), 0); - return (error); -} - -int -nandfs_vblock_assign(struct nandfs_device *nandfsdev, nandfs_daddr_t vblock, - nandfs_lbn_t block) -{ - struct nandfs_node *dat; - struct nandfs_mdt *mdt; - struct nandfs_alloc_request req; - struct nandfs_dat_entry *dat_entry; - uint32_t entry; - int locked, error; - - dat = nandfsdev->nd_dat_node; - mdt = &nandfsdev->nd_dat_mdt; - - locked = NANDFS_VOP_ISLOCKED(NTOV(dat)); - if (!locked) - VOP_LOCK(NTOV(dat), LK_EXCLUSIVE); - req.entrynum = vblock; - - error = nandfs_get_entry_block(mdt, dat, &req, &entry, 0); - if (!error) { - dat_entry = (struct nandfs_dat_entry *) req.bp_entry->b_data; - dat_entry[entry].de_blocknr = block; - - DPRINTF(DAT, ("%s: assing vblock %jx->%jx\n", - __func__, (uintmax_t)vblock, (uintmax_t)block)); - - /* - * It is mostly called from syncer() so - * we want to force making buf dirty - */ - error = nandfs_dirty_buf(req.bp_entry, 1); - } - - if (!locked) - VOP_UNLOCK(NTOV(dat), 0); - - return (error); -} - -int -nandfs_vblock_end(struct nandfs_device *nandfsdev, nandfs_daddr_t vblock) -{ - struct nandfs_node *dat; - struct nandfs_mdt *mdt; - struct nandfs_alloc_request req; - struct nandfs_dat_entry *dat_entry; - uint64_t end; - uint32_t entry; - int locked, error; - - dat = nandfsdev->nd_dat_node; - mdt = &nandfsdev->nd_dat_mdt; - end = nandfsdev->nd_last_cno; - - locked = NANDFS_VOP_ISLOCKED(NTOV(dat)); - if (!locked) - VOP_LOCK(NTOV(dat), LK_EXCLUSIVE); - req.entrynum = vblock; - - error = nandfs_get_entry_block(mdt, dat, &req, &entry, 0); - if (!error) { - dat_entry = (struct nandfs_dat_entry *) req.bp_entry->b_data; - dat_entry[entry].de_end = end; - DPRINTF(DAT, ("%s: end vblock %#jx at checkpoint %#jx\n", - __func__, (uintmax_t)vblock, (uintmax_t)end)); - - /* - * It is mostly called from syncer() so - * we want to force making buf dirty - */ - error = nandfs_dirty_buf(req.bp_entry, 1); - } - - if (!locked) - VOP_UNLOCK(NTOV(dat), 0); - - return (error); -} - -int -nandfs_vblock_free(struct nandfs_device *nandfsdev, nandfs_daddr_t vblock) -{ - struct nandfs_node *dat; - struct nandfs_mdt *mdt; - struct nandfs_alloc_request req; - int error; - - dat = nandfsdev->nd_dat_node; - mdt = &nandfsdev->nd_dat_mdt; - - VOP_LOCK(NTOV(dat), LK_EXCLUSIVE); - req.entrynum = vblock; - - error = nandfs_find_entry(mdt, dat, &req); - if (!error) { - DPRINTF(DAT, ("%s: vblk %#jx\n", __func__, (uintmax_t)vblock)); - nandfs_free_entry(mdt, &req); - } - - VOP_UNLOCK(NTOV(dat), 0); - return (error); -} - -int -nandfs_get_dat_vinfo_ioctl(struct nandfs_device *nandfsdev, struct nandfs_argv *nargv) -{ - struct nandfs_vinfo *vinfo; - size_t size; - int error; - - if (nargv->nv_nmembs > NANDFS_VINFO_MAX) - return (EINVAL); - - size = sizeof(struct nandfs_vinfo) * nargv->nv_nmembs; - vinfo = malloc(size, M_NANDFSTEMP, M_WAITOK|M_ZERO); - - error = copyin((void *)(uintptr_t)nargv->nv_base, vinfo, size); - if (error) { - free(vinfo, M_NANDFSTEMP); - return (error); - } - - error = nandfs_get_dat_vinfo(nandfsdev, vinfo, nargv->nv_nmembs); - if (error == 0) - error = copyout(vinfo, (void *)(uintptr_t)nargv->nv_base, size); - free(vinfo, M_NANDFSTEMP); - return (error); -} - -int -nandfs_get_dat_vinfo(struct nandfs_device *nandfsdev, struct nandfs_vinfo *vinfo, - uint32_t nmembs) -{ - struct nandfs_node *dat; - struct nandfs_mdt *mdt; - struct nandfs_alloc_request req; - struct nandfs_dat_entry *dat_entry; - uint32_t i, idx; - int error = 0; - - dat = nandfsdev->nd_dat_node; - mdt = &nandfsdev->nd_dat_mdt; - - DPRINTF(DAT, ("%s: nmembs %#x\n", __func__, nmembs)); - - VOP_LOCK(NTOV(dat), LK_EXCLUSIVE); - - for (i = 0; i < nmembs; i++) { - req.entrynum = vinfo[i].nvi_vblocknr; - - error = nandfs_get_entry_block(mdt, dat,&req, &idx, 0); - if (error) - break; - - dat_entry = ((struct nandfs_dat_entry *) req.bp_entry->b_data); - vinfo[i].nvi_start = dat_entry[idx].de_start; - vinfo[i].nvi_end = dat_entry[idx].de_end; - vinfo[i].nvi_blocknr = dat_entry[idx].de_blocknr; - - DPRINTF(DAT, ("%s: vinfo: %jx[%jx-%jx]->%jx\n", - __func__, vinfo[i].nvi_vblocknr, vinfo[i].nvi_start, - vinfo[i].nvi_end, vinfo[i].nvi_blocknr)); - - brelse(req.bp_entry); - } - - VOP_UNLOCK(NTOV(dat), 0); - return (error); -} - -int -nandfs_get_dat_bdescs_ioctl(struct nandfs_device *nffsdev, - struct nandfs_argv *nargv) -{ - struct nandfs_bdesc *bd; - size_t size; - int error; - - size = nargv->nv_nmembs * sizeof(struct nandfs_bdesc); - bd = malloc(size, M_NANDFSTEMP, M_WAITOK); - error = copyin((void *)(uintptr_t)nargv->nv_base, bd, size); - if (error) { - free(bd, M_NANDFSTEMP); - return (error); - } - - error = nandfs_get_dat_bdescs(nffsdev, bd, nargv->nv_nmembs); - - if (error == 0) - error = copyout(bd, (void *)(uintptr_t)nargv->nv_base, size); - - free(bd, M_NANDFSTEMP); - return (error); -} - -int -nandfs_get_dat_bdescs(struct nandfs_device *nffsdev, struct nandfs_bdesc *bd, - uint32_t nmembs) -{ - struct nandfs_node *dat_node; - uint64_t map; - uint32_t i; - int error = 0; - - dat_node = nffsdev->nd_dat_node; - - VOP_LOCK(NTOV(dat_node), LK_EXCLUSIVE); - - for (i = 0; i < nmembs; i++) { - DPRINTF(CLEAN, - ("%s: bd ino:%#jx oblk:%#jx blocknr:%#jx off:%#jx\n", - __func__, (uintmax_t)bd[i].bd_ino, - (uintmax_t)bd[i].bd_oblocknr, (uintmax_t)bd[i].bd_blocknr, - (uintmax_t)bd[i].bd_offset)); - - error = nandfs_bmap_lookup(dat_node, bd[i].bd_offset, &map); - if (error) - break; - bd[i].bd_blocknr = map; - } - - VOP_UNLOCK(NTOV(dat_node), 0); - return (error); -} diff --git a/sys/fs/nandfs/nandfs_dir.c b/sys/fs/nandfs/nandfs_dir.c deleted file mode 100644 index 404edecfaa08..000000000000 --- a/sys/fs/nandfs/nandfs_dir.c +++ /dev/null @@ -1,316 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf - * Copyright (c) 2008, 2009 Reinoud Zandijk - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * From: NetBSD: nilfs_subr.c,v 1.4 2009/07/29 17:06:57 reinoud - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/namei.h> -#include <sys/kernel.h> -#include <sys/stat.h> -#include <sys/buf.h> -#include <sys/bio.h> -#include <sys/proc.h> -#include <sys/mount.h> -#include <sys/vnode.h> -#include <sys/signalvar.h> -#include <sys/malloc.h> -#include <sys/dirent.h> -#include <sys/lockf.h> - -#include <vm/vm.h> -#include <vm/vm_extern.h> - -#include "nandfs_mount.h" -#include "nandfs.h" -#include "nandfs_subr.h" - -int -nandfs_add_dirent(struct vnode *dvp, uint64_t ino, char *nameptr, long namelen, - uint8_t type) -{ - struct nandfs_node *dir_node = VTON(dvp); - struct nandfs_dir_entry *dirent, *pdirent; - uint32_t blocksize = dir_node->nn_nandfsdev->nd_blocksize; - uint64_t filesize = dir_node->nn_inode.i_size; - uint64_t inode_blks = dir_node->nn_inode.i_blocks; - uint32_t off, rest; - uint8_t *pos; - struct buf *bp; - int error; - - pdirent = NULL; - bp = NULL; - if (inode_blks) { - error = nandfs_bread(dir_node, inode_blks - 1, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - - pos = bp->b_data; - off = 0; - while (off < blocksize) { - pdirent = (struct nandfs_dir_entry *) (pos + off); - if (!pdirent->rec_len) { - pdirent = NULL; - break; - } - off += pdirent->rec_len; - } - - if (pdirent) - rest = pdirent->rec_len - - NANDFS_DIR_REC_LEN(pdirent->name_len); - else - rest = blocksize; - - if (rest < NANDFS_DIR_REC_LEN(namelen)) { - /* Do not update pdirent as new block is created */ - pdirent = NULL; - brelse(bp); - /* Set to NULL to create new */ - bp = NULL; - filesize += rest; - } - } - - /* If no bp found create new */ - if (!bp) { - error = nandfs_bcreate(dir_node, inode_blks, NOCRED, 0, &bp); - if (error) - return (error); - off = 0; - pos = bp->b_data; - } - - /* Modify pdirent if exists */ - if (pdirent) { - DPRINTF(LOOKUP, ("modify pdirent %p\n", pdirent)); - /* modify last de */ - off -= pdirent->rec_len; - pdirent->rec_len = - NANDFS_DIR_REC_LEN(pdirent->name_len); - off += pdirent->rec_len; - } - - /* Create new dirent */ - dirent = (struct nandfs_dir_entry *) (pos + off); - dirent->rec_len = blocksize - off; - dirent->inode = ino; - dirent->name_len = namelen; - memset(dirent->name, 0, NANDFS_DIR_NAME_LEN(namelen)); - memcpy(dirent->name, nameptr, namelen); - dirent->file_type = type; - - filesize += NANDFS_DIR_REC_LEN(dirent->name_len); - - DPRINTF(LOOKUP, ("create dir_entry '%.*s' at %p with size %x " - "new filesize: %jx\n", - (int)namelen, dirent->name, dirent, dirent->rec_len, - (uintmax_t)filesize)); - - error = nandfs_dirty_buf(bp, 0); - if (error) - return (error); - - dir_node->nn_inode.i_size = filesize; - dir_node->nn_flags |= IN_CHANGE | IN_UPDATE; - vnode_pager_setsize(dvp, filesize); - - return (0); -} - -int -nandfs_remove_dirent(struct vnode *dvp, struct nandfs_node *node, - struct componentname *cnp) -{ - struct nandfs_node *dir_node; - struct nandfs_dir_entry *dirent, *pdirent; - struct buf *bp; - uint64_t filesize, blocknr, ino, offset; - uint32_t blocksize, limit, off; - uint16_t newsize; - uint8_t *pos; - int error, found; - - dir_node = VTON(dvp); - filesize = dir_node->nn_inode.i_size; - if (!filesize) - return (0); - - if (node) { - offset = node->nn_diroff; - ino = node->nn_ino; - } else { - offset = dir_node->nn_diroff; - ino = NANDFS_WHT_INO; - } - - dirent = pdirent = NULL; - blocksize = dir_node->nn_nandfsdev->nd_blocksize; - blocknr = offset / blocksize; - - DPRINTF(LOOKUP, ("rm direntry dvp %p node %p ino %#jx at off %#jx\n", - dvp, node, (uintmax_t)ino, (uintmax_t)offset)); - - error = nandfs_bread(dir_node, blocknr, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - - pos = bp->b_data; - off = 0; - found = 0; - limit = offset % blocksize; - pdirent = (struct nandfs_dir_entry *) bp->b_data; - while (off <= limit) { - dirent = (struct nandfs_dir_entry *) (pos + off); - - if ((off == limit) && - (dirent->inode == ino)) { - found = 1; - break; - } - if (dirent->inode != 0) - pdirent = dirent; - off += dirent->rec_len; - } - - if (!found) { - nandfs_error("cannot find entry to remove"); - brelse(bp); - return (error); - } - DPRINTF(LOOKUP, - ("rm dirent ino %#jx at %#x with size %#x\n", - (uintmax_t)dirent->inode, off, dirent->rec_len)); - - newsize = (uintptr_t)dirent - (uintptr_t)pdirent; - newsize += dirent->rec_len; - pdirent->rec_len = newsize; - dirent->inode = 0; - error = nandfs_dirty_buf(bp, 0); - if (error) - return (error); - - dir_node->nn_flags |= IN_CHANGE | IN_UPDATE; - /* If last one modify filesize */ - if ((offset + NANDFS_DIR_REC_LEN(dirent->name_len)) == filesize) { - filesize = blocknr * blocksize + - ((uintptr_t)pdirent - (uintptr_t)pos) + - NANDFS_DIR_REC_LEN(pdirent->name_len); - dir_node->nn_inode.i_size = filesize; - } - - return (0); -} - -int -nandfs_update_parent_dir(struct vnode *dvp, uint64_t newparent) -{ - struct nandfs_dir_entry *dirent; - struct nandfs_node *dir_node; - struct buf *bp; - int error; - - dir_node = VTON(dvp); - error = nandfs_bread(dir_node, 0, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - dirent = (struct nandfs_dir_entry *)bp->b_data; - dirent->inode = newparent; - error = nandfs_dirty_buf(bp, 0); - if (error) - return (error); - - return (0); -} - -int -nandfs_update_dirent(struct vnode *dvp, struct nandfs_node *fnode, - struct nandfs_node *tnode) -{ - struct nandfs_node *dir_node; - struct nandfs_dir_entry *dirent; - struct buf *bp; - uint64_t file_size, blocknr; - uint32_t blocksize, off; - uint8_t *pos; - int error; - - dir_node = VTON(dvp); - file_size = dir_node->nn_inode.i_size; - if (!file_size) - return (0); - - DPRINTF(LOOKUP, - ("chg direntry dvp %p ino %#jx to in %#jx at off %#jx\n", - dvp, (uintmax_t)tnode->nn_ino, (uintmax_t)fnode->nn_ino, - (uintmax_t)tnode->nn_diroff)); - - blocksize = dir_node->nn_nandfsdev->nd_blocksize; - blocknr = tnode->nn_diroff / blocksize; - off = tnode->nn_diroff % blocksize; - error = nandfs_bread(dir_node, blocknr, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - - pos = bp->b_data; - dirent = (struct nandfs_dir_entry *) (pos + off); - KASSERT((dirent->inode == tnode->nn_ino), - ("direntry mismatch")); - - dirent->inode = fnode->nn_ino; - error = nandfs_dirty_buf(bp, 0); - if (error) - return (error); - - return (0); -} - -int -nandfs_init_dir(struct vnode *dvp, uint64_t ino, uint64_t parent_ino) -{ - - if (nandfs_add_dirent(dvp, parent_ino, "..", 2, DT_DIR) || - nandfs_add_dirent(dvp, ino, ".", 1, DT_DIR)) { - nandfs_error("%s: cannot initialize dir ino:%jd(pino:%jd)\n", - __func__, ino, parent_ino); - return (-1); - } - return (0); -} diff --git a/sys/fs/nandfs/nandfs_fs.h b/sys/fs/nandfs/nandfs_fs.h deleted file mode 100644 index 9cb440ebcb90..000000000000 --- a/sys/fs/nandfs/nandfs_fs.h +++ /dev/null @@ -1,567 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf - * Copyright (c) 2008, 2009 Reinoud Zandijk - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Original definitions written by Koji Sato <koji@osrg.net> - * and Ryusuke Konishi <ryusuke@osrg.net> - * From: NetBSD: nandfs_fs.h,v 1.1 2009/07/18 16:31:42 reinoud - * - * $FreeBSD$ - */ - -#ifndef _NANDFS_FS_H -#define _NANDFS_FS_H - -#include <sys/uuid.h> - -#define MNINDIR(fsdev) ((fsdev)->nd_blocksize / sizeof(nandfs_daddr_t)) - -/* - * Inode structure. There are a few dedicated inode numbers that are - * defined here first. - */ -#define NANDFS_WHT_INO 1 /* Whiteout ino */ -#define NANDFS_ROOT_INO 2 /* Root file inode */ -#define NANDFS_DAT_INO 3 /* DAT file */ -#define NANDFS_CPFILE_INO 4 /* checkpoint file */ -#define NANDFS_SUFILE_INO 5 /* segment usage file */ -#define NANDFS_IFILE_INO 6 /* ifile */ -#define NANDFS_GC_INO 7 /* Cleanerd node */ -#define NANDFS_ATIME_INO 8 /* Atime file (reserved) */ -#define NANDFS_XATTR_INO 9 /* Xattribute file (reserved) */ -#define NANDFS_SKETCH_INO 10 /* Sketch file (obsolete) */ -#define NANDFS_USER_INO 11 /* First user's file inode number */ - -#define NANDFS_SYS_NODE(ino) \ - (((ino) >= NANDFS_DAT_INO) && ((ino) <= NANDFS_GC_INO)) - -#define NANDFS_NDADDR 12 /* Direct addresses in inode. */ -#define NANDFS_NIADDR 3 /* Indirect addresses in inode. */ - -typedef int64_t nandfs_daddr_t; -typedef int64_t nandfs_lbn_t; - -struct nandfs_inode { - uint64_t i_blocks; /* 0: size in device blocks */ - uint64_t i_size; /* 8: size in bytes */ - uint64_t i_ctime; /* 16: creation time in seconds */ - uint64_t i_mtime; /* 24: modification time in seconds part*/ - uint32_t i_ctime_nsec; /* 32: creation time nanoseconds part */ - uint32_t i_mtime_nsec; /* 36: modification time in nanoseconds */ - uint32_t i_uid; /* 40: user id */ - uint32_t i_gid; /* 44: group id */ - uint16_t i_mode; /* 48: file mode */ - uint16_t i_links_count; /* 50: number of references to the inode*/ - uint32_t i_flags; /* 52: NANDFS_*_FL flags */ - nandfs_daddr_t i_special; /* 56: special */ - nandfs_daddr_t i_db[NANDFS_NDADDR]; /* 64: Direct disk blocks. */ - nandfs_daddr_t i_ib[NANDFS_NIADDR]; /* 160: Indirect disk blocks. */ - uint64_t i_xattr; /* 184: reserved for extended attributes*/ - uint32_t i_generation; /* 192: file generation for NFS */ - uint32_t i_pad[15]; /* 196: make it 64 bits aligned */ -}; - -#ifdef _KERNEL -CTASSERT(sizeof(struct nandfs_inode) == 256); -#endif - -/* - * Each checkpoint/snapshot has a super root. - * - * The super root holds the inodes of the three system files: `dat', `cp' and - * 'su' files. All other FS state is defined by those. - * - * It is CRC checksum'ed and time stamped. - */ - -struct nandfs_super_root { - uint32_t sr_sum; /* check-sum */ - uint16_t sr_bytes; /* byte count of this structure */ - uint16_t sr_flags; /* reserved for flags */ - uint64_t sr_nongc_ctime; /* timestamp, not for cleaner(?) */ - struct nandfs_inode sr_dat; /* DAT, virt->phys translation inode */ - struct nandfs_inode sr_cpfile; /* CP, checkpoints inode */ - struct nandfs_inode sr_sufile; /* SU, segment usage inode */ -}; - -#define NANDFS_SR_MDT_OFFSET(inode_size, i) \ - ((uint32_t)&((struct nandfs_super_root *)0)->sr_dat + \ - (inode_size) * (i)) - -#define NANDFS_SR_DAT_OFFSET(inode_size) NANDFS_SR_MDT_OFFSET(inode_size, 0) -#define NANDFS_SR_CPFILE_OFFSET(inode_size) NANDFS_SR_MDT_OFFSET(inode_size, 1) -#define NANDFS_SR_SUFILE_OFFSET(inode_size) NANDFS_SR_MDT_OFFSET(inode_size, 2) -#define NANDFS_SR_BYTES (sizeof(struct nandfs_super_root)) - -/* - * The superblock describes the basic structure and mount history. It also - * records some sizes of structures found on the disc for sanity checks. - * - * The superblock is stored at two places: NANDFS_SB_OFFSET_BYTES and - * NANDFS_SB2_OFFSET_BYTES. - */ - -/* File system states stored on media in superblock's sbp->s_state */ -#define NANDFS_VALID_FS 0x0001 /* cleanly unmounted and all is ok */ -#define NANDFS_ERROR_FS 0x0002 /* there were errors detected, fsck */ -#define NANDFS_RESIZE_FS 0x0004 /* resize required, XXX unknown flag*/ -#define NANDFS_MOUNT_STATE_BITS "\20\1VALID_FS\2ERROR_FS\3RESIZE_FS" - -/* - * Brief description of control structures: - * - * NANDFS_NFSAREAS first blocks contain fsdata and some amount of super blocks. - * Simple round-robin policy is used in order to choose which block will - * contain new super block. - * - * Simple case with 2 blocks: - * 1: fsdata sblock1 [sblock3 [sblock5 ..]] - * 2: fsdata sblock2 [sblock4 [sblock6 ..]] - */ -struct nandfs_fsdata { - uint16_t f_magic; - uint16_t f_bytes; - - uint32_t f_sum; /* checksum of fsdata */ - uint32_t f_rev_level; /* major disk format revision */ - - uint64_t f_ctime; /* creation time (execution time - of newfs) */ - /* Block size represented as: blocksize = 1 << (f_log_block_size + 10) */ - uint32_t f_log_block_size; - - uint16_t f_inode_size; /* size of an inode */ - uint16_t f_dat_entry_size; /* size of a dat entry */ - uint16_t f_checkpoint_size; /* size of a checkpoint */ - uint16_t f_segment_usage_size; /* size of a segment usage */ - - uint16_t f_sbbytes; /* byte count of CRC calculation - for super blocks. s_reserved - is excluded! */ - - uint16_t f_errors; /* behaviour on detecting errors */ - - uint32_t f_erasesize; - uint64_t f_nsegments; /* number of segm. in filesystem */ - nandfs_daddr_t f_first_data_block; /* 1st seg disk block number */ - uint32_t f_blocks_per_segment; /* number of blocks per segment */ - uint32_t f_r_segments_percentage; /* reserved segments percentage */ - - struct uuid f_uuid; /* 128-bit uuid for volume */ - char f_volume_name[16]; /* volume name */ - uint32_t f_pad[104]; -} __packed; - -#ifdef _KERNEL -CTASSERT(sizeof(struct nandfs_fsdata) == 512); -#endif - -struct nandfs_super_block { - uint16_t s_magic; /* magic value for identification */ - - uint32_t s_sum; /* check sum of super block */ - - uint64_t s_last_cno; /* last checkpoint number */ - uint64_t s_last_pseg; /* addr part. segm. written last */ - uint64_t s_last_seq; /* seq.number of seg written last */ - uint64_t s_free_blocks_count; /* free blocks count */ - - uint64_t s_mtime; /* mount time */ - uint64_t s_wtime; /* write time */ - uint16_t s_state; /* file system state */ - - char s_last_mounted[64]; /* directory where last mounted */ - - uint32_t s_c_interval; /* commit interval of segment */ - uint32_t s_c_block_max; /* threshold of data amount for - the segment construction */ - uint32_t s_reserved[32]; /* padding to end of the block */ -} __packed; - -#ifdef _KERNEL -CTASSERT(sizeof(struct nandfs_super_block) == 256); -#endif - -#define NANDFS_FSDATA_MAGIC 0xf8da -#define NANDFS_SUPER_MAGIC 0x8008 - -#define NANDFS_NFSAREAS 4 -#define NANDFS_DATA_OFFSET_BYTES(esize) (NANDFS_NFSAREAS * (esize)) - -#define NANDFS_SBLOCK_OFFSET_BYTES (sizeof(struct nandfs_fsdata)) - -#define NANDFS_DEF_BLOCKSIZE 4096 -#define NANDFS_MIN_BLOCKSIZE 512 - -#define NANDFS_DEF_ERASESIZE (2 << 16) - -#define NANDFS_MIN_SEGSIZE NANDFS_DEF_ERASESIZE - -#define NANDFS_CURRENT_REV 9 /* current major revision */ - -#define NANDFS_FSDATA_CRC_BYTES offsetof(struct nandfs_fsdata, f_pad) -/* Bytes count of super_block for CRC-calculation */ -#define NANDFS_SB_BYTES offsetof(struct nandfs_super_block, s_reserved) - -/* Maximal count of links to a file */ -#define NANDFS_LINK_MAX 32000 - -/* - * Structure of a directory entry. - * - * Note that they can't span blocks; the rec_len fills out. - */ - -#define NANDFS_NAME_LEN 255 -struct nandfs_dir_entry { - uint64_t inode; /* inode number */ - uint16_t rec_len; /* directory entry length */ - uint8_t name_len; /* name length */ - uint8_t file_type; - char name[NANDFS_NAME_LEN]; /* file name */ - char pad; -}; - -/* - * NANDFS_DIR_PAD defines the directory entries boundaries - * - * NOTE: It must be a multiple of 8 - */ -#define NANDFS_DIR_PAD 8 -#define NANDFS_DIR_ROUND (NANDFS_DIR_PAD - 1) -#define NANDFS_DIR_NAME_OFFSET (offsetof(struct nandfs_dir_entry, name)) -#define NANDFS_DIR_REC_LEN(name_len) \ - (((name_len) + NANDFS_DIR_NAME_OFFSET + NANDFS_DIR_ROUND) \ - & ~NANDFS_DIR_ROUND) -#define NANDFS_DIR_NAME_LEN(name_len) \ - (NANDFS_DIR_REC_LEN(name_len) - NANDFS_DIR_NAME_OFFSET) - -/* - * NiLFS/NANDFS devides the disc into fixed length segments. Each segment is - * filled with one or more partial segments of variable lengths. - * - * Each partial segment has a segment summary header followed by updates of - * files and optionally a super root. - */ - -/* - * Virtual to physical block translation information. For data blocks it maps - * logical block number bi_blkoff to virtual block nr bi_vblocknr. For non - * datablocks it is the virtual block number assigned to an indirect block - * and has no bi_blkoff. The physical block number is the next - * available data block in the partial segment after all the binfo's. - */ -struct nandfs_binfo_v { - uint64_t bi_ino; /* file's inode */ - uint64_t bi_vblocknr; /* assigned virtual block number */ - uint64_t bi_blkoff; /* for file's logical block number */ -}; - -/* - * DAT allocation. For data blocks just the logical block number that maps on - * the next available data block in the partial segment after the binfo's. - */ -struct nandfs_binfo_dat { - uint64_t bi_ino; - uint64_t bi_blkoff; /* DAT file's logical block number */ - uint8_t bi_level; /* whether this is meta block */ - uint8_t bi_pad[7]; -}; - -#ifdef _KERNEL -CTASSERT(sizeof(struct nandfs_binfo_v) == sizeof(struct nandfs_binfo_dat)); -#endif - -/* Convenience union for both types of binfo's */ -union nandfs_binfo { - struct nandfs_binfo_v bi_v; - struct nandfs_binfo_dat bi_dat; -}; - -/* Indirect buffers path */ -struct nandfs_indir { - nandfs_daddr_t in_lbn; - int in_off; -}; - -/* The (partial) segment summary */ -struct nandfs_segment_summary { - uint32_t ss_datasum; /* CRC of complete data block */ - uint32_t ss_sumsum; /* CRC of segment summary only */ - uint32_t ss_magic; /* magic to identify segment summary */ - uint16_t ss_bytes; /* size of segment summary structure */ - uint16_t ss_flags; /* NANDFS_SS_* flags */ - uint64_t ss_seq; /* sequence number of this segm. sum */ - uint64_t ss_create; /* creation timestamp in seconds */ - uint64_t ss_next; /* blocknumber of next segment */ - uint32_t ss_nblocks; /* number of blocks used by summary */ - uint32_t ss_nbinfos; /* number of binfo structures */ - uint32_t ss_sumbytes; /* total size of segment summary */ - uint32_t ss_pad; - /* stream of binfo structures */ -}; - -#define NANDFS_SEGSUM_MAGIC 0x8e680011 /* segment summary magic number */ - -/* Segment summary flags */ -#define NANDFS_SS_LOGBGN 0x0001 /* begins a logical segment */ -#define NANDFS_SS_LOGEND 0x0002 /* ends a logical segment */ -#define NANDFS_SS_SR 0x0004 /* has super root */ -#define NANDFS_SS_SYNDT 0x0008 /* includes data only updates */ -#define NANDFS_SS_GC 0x0010 /* segment written for cleaner operation */ -#define NANDFS_SS_FLAG_BITS "\20\1LOGBGN\2LOGEND\3SR\4SYNDT\5GC" - -/* Segment summary constrains */ -#define NANDFS_SEG_MIN_BLOCKS 16 /* minimum number of blocks in a - full segment */ -#define NANDFS_PSEG_MIN_BLOCKS 2 /* minimum number of blocks in a - partial segment */ -#define NANDFS_MIN_NRSVSEGS 8 /* minimum number of reserved - segments */ - -/* - * Structure of DAT/inode file. - * - * A DAT file is divided into groups. The maximum number of groups is the - * number of block group descriptors that fit into one block; this descriptor - * only gives the number of free entries in the associated group. - * - * Each group has a block sized bitmap indicating if an entry is taken or - * empty. Each bit stands for a DAT entry. - * - * The inode file has exactly the same format only the entries are inode - * entries. - */ - -struct nandfs_block_group_desc { - uint32_t bg_nfrees; /* num. free entries in block group */ -}; - -/* DAT entry in a super root's DAT file */ -struct nandfs_dat_entry { - uint64_t de_blocknr; /* block number */ - uint64_t de_start; /* valid from checkpoint */ - uint64_t de_end; /* valid till checkpoint */ - uint64_t de_rsv; /* reserved for future use */ -}; - -/* - * Structure of CP file. - * - * A snapshot is just a checkpoint only it's protected against removal by the - * cleaner. The snapshots are kept on a double linked list of checkpoints. - */ -struct nandfs_snapshot_list { - uint64_t ssl_next; /* checkpoint nr. forward */ - uint64_t ssl_prev; /* checkpoint nr. back */ -}; - -/* Checkpoint entry structure */ -struct nandfs_checkpoint { - uint32_t cp_flags; /* NANDFS_CHECKPOINT_* flags */ - uint32_t cp_checkpoints_count; /* ZERO, not used anymore? */ - struct nandfs_snapshot_list cp_snapshot_list; /* list of snapshots */ - uint64_t cp_cno; /* checkpoint number */ - uint64_t cp_create; /* creation timestamp */ - uint64_t cp_nblk_inc; /* number of blocks incremented */ - uint64_t cp_blocks_count; /* reserved (might be deleted) */ - struct nandfs_inode cp_ifile_inode; /* inode file inode */ -}; - -/* Checkpoint flags */ -#define NANDFS_CHECKPOINT_SNAPSHOT 1 -#define NANDFS_CHECKPOINT_INVALID 2 -#define NANDFS_CHECKPOINT_SKETCH 4 -#define NANDFS_CHECKPOINT_MINOR 8 -#define NANDFS_CHECKPOINT_BITS "\20\1SNAPSHOT\2INVALID\3SKETCH\4MINOR" - -/* Header of the checkpoint file */ -struct nandfs_cpfile_header { - uint64_t ch_ncheckpoints; /* number of checkpoints */ - uint64_t ch_nsnapshots; /* number of snapshots */ - struct nandfs_snapshot_list ch_snapshot_list; /* snapshot list */ -}; - -#define NANDFS_CPFILE_FIRST_CHECKPOINT_OFFSET \ - ((sizeof(struct nandfs_cpfile_header) + \ - sizeof(struct nandfs_checkpoint) - 1) / \ - sizeof(struct nandfs_checkpoint)) - - -#define NANDFS_NOSEGMENT 0xffffffff - -/* - * Structure of SU file. - * - * The segment usage file sums up how each of the segments are used. They are - * indexed by their segment number. - */ - -/* Segment usage entry */ -struct nandfs_segment_usage { - uint64_t su_lastmod; /* last modified timestamp */ - uint32_t su_nblocks; /* number of blocks in segment */ - uint32_t su_flags; /* NANDFS_SEGMENT_USAGE_* flags */ -}; - -/* Segment usage flag */ -#define NANDFS_SEGMENT_USAGE_ACTIVE 1 -#define NANDFS_SEGMENT_USAGE_DIRTY 2 -#define NANDFS_SEGMENT_USAGE_ERROR 4 -#define NANDFS_SEGMENT_USAGE_GC 8 -#define NANDFS_SEGMENT_USAGE_BITS "\20\1ACTIVE\2DIRTY\3ERROR" - -/* Header of the segment usage file */ -struct nandfs_sufile_header { - uint64_t sh_ncleansegs; /* number of segments marked clean */ - uint64_t sh_ndirtysegs; /* number of segments marked dirty */ - uint64_t sh_last_alloc; /* last allocated segment number */ -}; - -#define NANDFS_SUFILE_FIRST_SEGMENT_USAGE_OFFSET \ - ((sizeof(struct nandfs_sufile_header) + \ - sizeof(struct nandfs_segment_usage) - 1) / \ - sizeof(struct nandfs_segment_usage)) - -struct nandfs_seg_stat { - uint64_t nss_nsegs; - uint64_t nss_ncleansegs; - uint64_t nss_ndirtysegs; - uint64_t nss_ctime; - uint64_t nss_nongc_ctime; - uint64_t nss_prot_seq; -}; - -enum { - NANDFS_CHECKPOINT, - NANDFS_SNAPSHOT -}; - -#define NANDFS_CPINFO_MAX 512 - -struct nandfs_cpinfo { - uint32_t nci_flags; - uint32_t nci_pad; - uint64_t nci_cno; - uint64_t nci_create; - uint64_t nci_nblk_inc; - uint64_t nci_blocks_count; - uint64_t nci_next; -}; - -#define NANDFS_SEGMENTS_MAX 512 - -struct nandfs_suinfo { - uint64_t nsi_num; - uint64_t nsi_lastmod; - uint32_t nsi_blocks; - uint32_t nsi_flags; -}; - -#define NANDFS_VINFO_MAX 512 - -struct nandfs_vinfo { - uint64_t nvi_ino; - uint64_t nvi_vblocknr; - uint64_t nvi_start; - uint64_t nvi_end; - uint64_t nvi_blocknr; - int nvi_alive; -}; - -struct nandfs_cpmode { - uint64_t ncpm_cno; - uint32_t ncpm_mode; - uint32_t ncpm_pad; -}; - -struct nandfs_argv { - uint64_t nv_base; - uint32_t nv_nmembs; - uint16_t nv_size; - uint16_t nv_flags; - uint64_t nv_index; -}; - -struct nandfs_cpstat { - uint64_t ncp_cno; - uint64_t ncp_ncps; - uint64_t ncp_nss; -}; - -struct nandfs_period { - uint64_t p_start; - uint64_t p_end; -}; - -struct nandfs_vdesc { - uint64_t vd_ino; - uint64_t vd_cno; - uint64_t vd_vblocknr; - struct nandfs_period vd_period; - uint64_t vd_blocknr; - uint64_t vd_offset; - uint32_t vd_flags; - uint32_t vd_pad; -}; - -struct nandfs_bdesc { - uint64_t bd_ino; - uint64_t bd_oblocknr; - uint64_t bd_blocknr; - uint64_t bd_offset; - uint32_t bd_level; - uint32_t bd_alive; -}; - -#ifndef _KERNEL -#ifndef MNAMELEN -#define MNAMELEN 1024 -#endif -#endif - -struct nandfs_fsinfo { - struct nandfs_fsdata fs_fsdata; - struct nandfs_super_block fs_super; - char fs_dev[MNAMELEN]; -}; - -#define NANDFS_MAX_MOUNTS 65535 - -#define NANDFS_IOCTL_GET_SUSTAT _IOR('N', 100, struct nandfs_seg_stat) -#define NANDFS_IOCTL_CHANGE_CPMODE _IOWR('N', 101, struct nandfs_cpmode) -#define NANDFS_IOCTL_GET_CPINFO _IOWR('N', 102, struct nandfs_argv) -#define NANDFS_IOCTL_DELETE_CP _IOWR('N', 103, uint64_t[2]) -#define NANDFS_IOCTL_GET_CPSTAT _IOR('N', 104, struct nandfs_cpstat) -#define NANDFS_IOCTL_GET_SUINFO _IOWR('N', 105, struct nandfs_argv) -#define NANDFS_IOCTL_GET_VINFO _IOWR('N', 106, struct nandfs_argv) -#define NANDFS_IOCTL_GET_BDESCS _IOWR('N', 107, struct nandfs_argv) -#define NANDFS_IOCTL_GET_FSINFO _IOR('N', 108, struct nandfs_fsinfo) -#define NANDFS_IOCTL_MAKE_SNAP _IOWR('N', 109, uint64_t) -#define NANDFS_IOCTL_DELETE_SNAP _IOWR('N', 110, uint64_t) -#define NANDFS_IOCTL_SYNC _IOWR('N', 111, uint64_t) - -#endif /* _NANDFS_FS_H */ diff --git a/sys/fs/nandfs/nandfs_ifile.c b/sys/fs/nandfs/nandfs_ifile.c deleted file mode 100644 index 2c10bbac1ffe..000000000000 --- a/sys/fs/nandfs/nandfs_ifile.c +++ /dev/null @@ -1,215 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/conf.h> -#include <sys/kernel.h> -#include <sys/lock.h> -#include <sys/malloc.h> -#include <sys/mount.h> -#include <sys/mutex.h> -#include <sys/namei.h> -#include <sys/sysctl.h> -#include <sys/vnode.h> -#include <sys/buf.h> -#include <sys/bio.h> - -#include <vm/vm.h> -#include <vm/vm_param.h> -#include <vm/vm_kern.h> -#include <vm/vm_page.h> - -#include <fs/nandfs/nandfs_mount.h> -#include <fs/nandfs/nandfs.h> -#include <fs/nandfs/nandfs_subr.h> - -int -nandfs_node_create(struct nandfsmount *nmp, struct nandfs_node **node, - uint16_t mode) -{ - struct nandfs_alloc_request req; - struct nandfs_device *nandfsdev; - struct nandfs_mdt *mdt; - struct nandfs_node *ifile; - struct nandfs_inode *inode; - struct vnode *vp; - uint32_t entry; - int error = 0; - - nandfsdev = nmp->nm_nandfsdev; - mdt = &nandfsdev->nd_ifile_mdt; - ifile = nmp->nm_ifile_node; - vp = NTOV(ifile); - - VOP_LOCK(vp, LK_EXCLUSIVE); - /* Allocate new inode in ifile */ - req.entrynum = nandfsdev->nd_last_ino + 1; - error = nandfs_find_free_entry(mdt, ifile, &req); - if (error) { - VOP_UNLOCK(vp, 0); - return (error); - } - - error = nandfs_get_entry_block(mdt, ifile, &req, &entry, 1); - if (error) { - VOP_UNLOCK(vp, 0); - return (error); - } - - /* Inode initialization */ - inode = ((struct nandfs_inode *) req.bp_entry->b_data) + entry; - nandfs_inode_init(inode, mode); - - error = nandfs_alloc_entry(mdt, &req); - if (error) { - VOP_UNLOCK(vp, 0); - return (error); - } - - VOP_UNLOCK(vp, 0); - - nandfsdev->nd_last_ino = req.entrynum; - error = nandfs_get_node(nmp, req.entrynum, node); - DPRINTF(IFILE, ("%s: node: %p ino: %#jx\n", - __func__, node, (uintmax_t)((*node)->nn_ino))); - - return (error); -} - -int -nandfs_node_destroy(struct nandfs_node *node) -{ - struct nandfs_alloc_request req; - struct nandfsmount *nmp; - struct nandfs_mdt *mdt; - struct nandfs_node *ifile; - struct vnode *vp; - int error = 0; - - nmp = node->nn_nmp; - req.entrynum = node->nn_ino; - mdt = &nmp->nm_nandfsdev->nd_ifile_mdt; - ifile = nmp->nm_ifile_node; - vp = NTOV(ifile); - - DPRINTF(IFILE, ("%s: destroy node: %p ino: %#jx\n", - __func__, node, (uintmax_t)node->nn_ino)); - VOP_LOCK(vp, LK_EXCLUSIVE); - - error = nandfs_find_entry(mdt, ifile, &req); - if (error) { - nandfs_error("%s: finding entry error:%d node %p(%jx)", - __func__, error, node, node->nn_ino); - VOP_UNLOCK(vp, 0); - return (error); - } - - nandfs_inode_destroy(&node->nn_inode); - - error = nandfs_free_entry(mdt, &req); - if (error) { - nandfs_error("%s: freing entry error:%d node %p(%jx)", - __func__, error, node, node->nn_ino); - VOP_UNLOCK(vp, 0); - return (error); - } - - VOP_UNLOCK(vp, 0); - DPRINTF(IFILE, ("%s: freed node %p ino %#jx\n", - __func__, node, (uintmax_t)node->nn_ino)); - return (error); -} - -int -nandfs_node_update(struct nandfs_node *node) -{ - struct nandfs_alloc_request req; - struct nandfsmount *nmp; - struct nandfs_mdt *mdt; - struct nandfs_node *ifile; - struct nandfs_inode *inode; - uint32_t index; - int error = 0; - - nmp = node->nn_nmp; - ifile = nmp->nm_ifile_node; - ASSERT_VOP_LOCKED(NTOV(ifile), __func__); - - req.entrynum = node->nn_ino; - mdt = &nmp->nm_nandfsdev->nd_ifile_mdt; - - DPRINTF(IFILE, ("%s: node:%p ino:%#jx\n", - __func__, &node->nn_inode, (uintmax_t)node->nn_ino)); - - error = nandfs_get_entry_block(mdt, ifile, &req, &index, 0); - if (error) { - printf("nandfs_get_entry_block returned with ERROR=%d\n", - error); - return (error); - } - - inode = ((struct nandfs_inode *) req.bp_entry->b_data) + index; - memcpy(inode, &node->nn_inode, sizeof(*inode)); - error = nandfs_dirty_buf(req.bp_entry, 0); - - return (error); -} - -int -nandfs_get_node_entry(struct nandfsmount *nmp, struct nandfs_inode **inode, - uint64_t ino, struct buf **bp) -{ - struct nandfs_alloc_request req; - struct nandfs_mdt *mdt; - struct nandfs_node *ifile; - struct vnode *vp; - uint32_t index; - int error = 0; - - req.entrynum = ino; - mdt = &nmp->nm_nandfsdev->nd_ifile_mdt; - ifile = nmp->nm_ifile_node; - vp = NTOV(ifile); - - VOP_LOCK(vp, LK_EXCLUSIVE); - error = nandfs_get_entry_block(mdt, ifile, &req, &index, 0); - if (error) { - VOP_UNLOCK(vp, 0); - return (error); - } - - *inode = ((struct nandfs_inode *) req.bp_entry->b_data) + index; - *bp = req.bp_entry; - VOP_UNLOCK(vp, 0); - return (0); -} - diff --git a/sys/fs/nandfs/nandfs_mount.h b/sys/fs/nandfs/nandfs_mount.h deleted file mode 100644 index cc6e30eb0bbd..000000000000 --- a/sys/fs/nandfs/nandfs_mount.h +++ /dev/null @@ -1,52 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-4-Clause - * - * Copyright (c) 2008, 2009 Reinoud Zandijk - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed for the - * NetBSD Project. See http://www.NetBSD.org/ for - * information about NetBSD. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * From: NetBSD: nilfs_mount.h,v 1.1 2009/07/18 16:31:42 reinoud - * - * $FreeBSD$ - */ - -#ifndef _FS_NANDFS_NANDFS_MOUNT_H_ -#define _FS_NANDFS_NANDFS_MOUNT_H_ - -/* - * Arguments to mount NANDFS filingsystem. - */ - -struct nandfs_args { - char *fspec; /* mount specifier */ - int64_t cpno; /* checkpoint number */ -}; - -#endif /* !_FS_NANDFS_NANDFS_MOUNT_H_ */ - diff --git a/sys/fs/nandfs/nandfs_segment.c b/sys/fs/nandfs/nandfs_segment.c deleted file mode 100644 index 36efc89af409..000000000000 --- a/sys/fs/nandfs/nandfs_segment.c +++ /dev/null @@ -1,1314 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf. - * 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 "opt_ddb.h" - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/conf.h> -#include <sys/gsb_crc32.h> -#include <sys/kernel.h> -#include <sys/lock.h> -#include <sys/malloc.h> -#include <sys/mount.h> -#include <sys/mutex.h> -#include <sys/namei.h> -#include <sys/rwlock.h> -#include <sys/sysctl.h> -#include <sys/vnode.h> -#include <sys/buf.h> -#include <sys/bio.h> -#include <sys/libkern.h> - -#include <ddb/ddb.h> - -#include <vm/vm.h> -#include <vm/vm_param.h> -#include <vm/vm_kern.h> -#include <vm/vm_page.h> - -#include <geom/geom.h> -#include <geom/geom_vfs.h> - -#include <fs/nandfs/nandfs_mount.h> -#include <fs/nandfs/nandfs.h> -#include <fs/nandfs/nandfs_subr.h> - -static int -nandfs_new_segment(struct nandfs_device *fsdev) -{ - int error = 0; - uint64_t new; - - error = nandfs_alloc_segment(fsdev, &new); - if (!error) { - fsdev->nd_seg_num = fsdev->nd_next_seg_num; - fsdev->nd_next_seg_num = new; - } - DPRINTF(SYNC, ("%s: new segment %jx next %jx error %d\n", - __func__, (uintmax_t)fsdev->nd_seg_num, (uintmax_t)new, error)); - if (error) - nandfs_error("%s: cannot create segment error %d\n", - __func__, error); - - return (error); -} - -static int -create_segment(struct nandfs_seginfo *seginfo) -{ - struct nandfs_segment *seg; - struct nandfs_device *fsdev; - struct nandfs_segment *prev; - struct buf *bp; - uint64_t start_block, curr; - uint32_t blks_per_seg, nblocks; - int error; - - fsdev = seginfo->fsdev; - prev = seginfo->curseg; - blks_per_seg = fsdev->nd_fsdata.f_blocks_per_segment; - nblocks = fsdev->nd_last_segsum.ss_nblocks; - - if (!prev) { - vfs_timestamp(&fsdev->nd_ts); - /* Touch current segment */ - error = nandfs_touch_segment(fsdev, fsdev->nd_seg_num); - if (error) { - nandfs_error("%s: cannot preallocate segment %jx\n", - __func__, fsdev->nd_seg_num); - return (error); - } - error = nandfs_touch_segment(fsdev, 0); - if (error) { - nandfs_error("%s: cannot dirty block with segment 0\n", - __func__); - return (error); - } - start_block = fsdev->nd_last_pseg + (uint64_t)nblocks; - /* - * XXX Hack - */ - if (blks_per_seg - (start_block % blks_per_seg) - 1 == 0) - start_block++; - curr = nandfs_get_segnum_of_block(fsdev, start_block); - /* Allocate new segment if last one is full */ - if (fsdev->nd_seg_num != curr) { - error = nandfs_new_segment(fsdev); - if (error) { - nandfs_error("%s: cannot create new segment\n", - __func__); - return (error); - } - /* - * XXX Hack - */ - nandfs_get_segment_range(fsdev, fsdev->nd_seg_num, &start_block, NULL); - } - } else { - nandfs_get_segment_range(fsdev, fsdev->nd_next_seg_num, - &start_block, NULL); - - /* Touch current segment and allocate and touch new one */ - error = nandfs_new_segment(fsdev); - if (error) { - nandfs_error("%s: cannot create next segment\n", - __func__); - return (error); - } - - /* Reiterate in case new buf is dirty */ - seginfo->reiterate = 1; - } - - /* Allocate and initialize nandfs_segment structure */ - seg = malloc(sizeof(*seg), M_DEVBUF, M_WAITOK|M_ZERO); - TAILQ_INIT(&seg->segsum); - TAILQ_INIT(&seg->data); - seg->fsdev = fsdev; - seg->start_block = start_block; - seg->num_blocks = blks_per_seg - (start_block % blks_per_seg) - 1; - seg->seg_num = fsdev->nd_seg_num; - seg->seg_next = fsdev->nd_next_seg_num; - seg->segsum_blocks = 1; - seg->bytes_left = fsdev->nd_blocksize - - sizeof(struct nandfs_segment_summary); - seg->segsum_bytes = sizeof(struct nandfs_segment_summary); - - /* Allocate buffer for segment summary */ - bp = getblk(fsdev->nd_devvp, nandfs_block_to_dblock(fsdev, - seg->start_block), fsdev->nd_blocksize, 0, 0, 0); - bzero(bp->b_data, seginfo->fsdev->nd_blocksize); - bp->b_bufobj = &seginfo->fsdev->nd_devvp->v_bufobj; - bp->b_flags |= B_MANAGED; - - /* Add buffer to segment */ - TAILQ_INSERT_TAIL(&seg->segsum, bp, b_cluster.cluster_entry); - seg->current_off = bp->b_data + sizeof(struct nandfs_segment_summary); - - DPRINTF(SYNC, ("%s: seg %p : initial settings: start %#jx size :%#x\n", - __func__, seg, (uintmax_t)seg->start_block, seg->num_blocks)); - DPRINTF(SYNC, ("%s: seg->seg_num %#jx cno %#jx next %#jx\n", __func__, - (uintmax_t)seg->seg_num, (uintmax_t)(fsdev->nd_last_cno + 1), - (uintmax_t)seg->seg_next)); - - if (!prev) - LIST_INSERT_HEAD(&seginfo->seg_list, seg, seg_link); - else - LIST_INSERT_AFTER(prev, seg, seg_link); - - seginfo->curseg = seg; - - return (0); -} - -static int -delete_segment(struct nandfs_seginfo *seginfo) -{ - struct nandfs_segment *seg, *tseg; - struct buf *bp, *tbp; - - LIST_FOREACH_SAFE(seg, &seginfo->seg_list, seg_link, tseg) { - TAILQ_FOREACH_SAFE(bp, &seg->segsum, b_cluster.cluster_entry, - tbp) { - TAILQ_REMOVE(&seg->segsum, bp, b_cluster.cluster_entry); - bp->b_flags &= ~B_MANAGED; - brelse(bp); - } - - LIST_REMOVE(seg, seg_link); - free(seg, M_DEVBUF); - } - - return (0); -} - -static int -create_seginfo(struct nandfs_device *fsdev, struct nandfs_seginfo **seginfo) -{ - struct nandfs_seginfo *info; - - info = malloc(sizeof(*info), M_DEVBUF, M_WAITOK); - - LIST_INIT(&info->seg_list); - info->fsdev = fsdev; - info->curseg = NULL; - info->blocks = 0; - *seginfo = info; - fsdev->nd_seginfo = info; - return (0); -} - -static int -delete_seginfo(struct nandfs_seginfo *seginfo) -{ - struct nandfs_device *nffsdev; - - nffsdev = seginfo->fsdev; - delete_segment(seginfo); - nffsdev->nd_seginfo = NULL; - free(seginfo, M_DEVBUF); - - return (0); -} - -static int -nandfs_create_superroot_block(struct nandfs_seginfo *seginfo, - struct buf **newbp) -{ - struct buf *bp; - int error; - - bp = nandfs_geteblk(seginfo->fsdev->nd_blocksize, GB_NOWAIT_BD); - - bzero(bp->b_data, seginfo->fsdev->nd_blocksize); - bp->b_bufobj = &seginfo->fsdev->nd_devvp->v_bufobj; - bp->b_flags |= B_MANAGED; - - if (!(seginfo->curseg) || !seginfo->curseg->num_blocks) { - error = create_segment(seginfo); - if (error) { - brelse(bp); - nandfs_error("%s: no segment for superroot\n", - __func__); - return (error); - } - } - - TAILQ_INSERT_TAIL(&seginfo->curseg->data, bp, b_cluster.cluster_entry); - - seginfo->curseg->nblocks++; - seginfo->curseg->num_blocks--; - seginfo->blocks++; - - *newbp = bp; - return (0); -} - -static int -nandfs_add_superroot(struct nandfs_seginfo *seginfo) -{ - struct nandfs_device *fsdev; - struct nandfs_super_root *sr; - struct buf *bp = NULL; - uint64_t crc_skip; - uint32_t crc_calc; - int error; - - fsdev = seginfo->fsdev; - - error = nandfs_create_superroot_block(seginfo, &bp); - if (error) { - nandfs_error("%s: cannot add superroot\n", __func__); - return (error); - } - - sr = (struct nandfs_super_root *)bp->b_data; - /* Save superroot CRC */ - sr->sr_bytes = NANDFS_SR_BYTES; - sr->sr_flags = 0; - sr->sr_nongc_ctime = 0; - - memcpy(&sr->sr_dat, &fsdev->nd_dat_node->nn_inode, - sizeof(struct nandfs_inode)); - memcpy(&sr->sr_cpfile, &fsdev->nd_cp_node->nn_inode, - sizeof(struct nandfs_inode)); - memcpy(&sr->sr_sufile, &fsdev->nd_su_node->nn_inode, - sizeof(struct nandfs_inode)); - - crc_skip = sizeof(sr->sr_sum); - crc_calc = crc32((uint8_t *)sr + crc_skip, NANDFS_SR_BYTES - crc_skip); - - sr->sr_sum = crc_calc; - - bp->b_flags |= B_MANAGED; - bp->b_bufobj = &seginfo->fsdev->nd_devvp->v_bufobj; - - bp->b_flags &= ~B_INVAL; - nandfs_dirty_bufs_increment(fsdev); - DPRINTF(SYNC, ("%s: bp:%p\n", __func__, bp)); - - return (0); -} - -static int -nandfs_add_segsum_block(struct nandfs_seginfo *seginfo, struct buf **newbp) -{ - struct nandfs_device *fsdev; - nandfs_daddr_t blk; - struct buf *bp; - int error; - - if (!(seginfo->curseg) || seginfo->curseg->num_blocks <= 1) { - error = create_segment(seginfo); - if (error) { - nandfs_error("%s: error:%d when creating segment\n", - __func__, error); - return (error); - } - *newbp = TAILQ_FIRST(&seginfo->curseg->segsum); - return (0); - } - - fsdev = seginfo->fsdev; - blk = nandfs_block_to_dblock(fsdev, seginfo->curseg->start_block + - seginfo->curseg->segsum_blocks); - - bp = getblk(fsdev->nd_devvp, blk, fsdev->nd_blocksize, 0, 0, 0); - - bzero(bp->b_data, seginfo->fsdev->nd_blocksize); - bp->b_bufobj = &seginfo->fsdev->nd_devvp->v_bufobj; - bp->b_flags |= B_MANAGED; - - TAILQ_INSERT_TAIL(&seginfo->curseg->segsum, bp, - b_cluster.cluster_entry); - seginfo->curseg->num_blocks--; - - seginfo->curseg->segsum_blocks++; - seginfo->curseg->bytes_left = seginfo->fsdev->nd_blocksize; - seginfo->curseg->current_off = bp->b_data; - seginfo->blocks++; - - *newbp = bp; - - DPRINTF(SYNC, ("%s: bp %p\n", __func__, bp)); - - return (0); -} - -static int -nandfs_add_blocks(struct nandfs_seginfo *seginfo, struct nandfs_node *node, - struct buf *bp) -{ - union nandfs_binfo *binfo; - struct buf *seg_bp; - int error; - - if (!(seginfo->curseg) || !seginfo->curseg->num_blocks) { - error = create_segment(seginfo); - if (error) { - nandfs_error("%s: error:%d when creating segment\n", - __func__, error); - return (error); - } - } - - if (seginfo->curseg->bytes_left < sizeof(union nandfs_binfo)) { - error = nandfs_add_segsum_block(seginfo, &seg_bp); - if (error) { - nandfs_error("%s: error:%d when adding segsum\n", - __func__, error); - return (error); - } - } - binfo = (union nandfs_binfo *)seginfo->curseg->current_off; - - if (node->nn_ino != NANDFS_DAT_INO) { - binfo->bi_v.bi_blkoff = bp->b_lblkno; - binfo->bi_v.bi_ino = node->nn_ino; - } else { - binfo->bi_dat.bi_blkoff = bp->b_lblkno; - binfo->bi_dat.bi_ino = node->nn_ino; - if (NANDFS_IS_INDIRECT(bp)) - binfo->bi_dat.bi_level = 1; - else - binfo->bi_dat.bi_level = 0; - } - binfo++; - - seginfo->curseg->bytes_left -= sizeof(union nandfs_binfo); - seginfo->curseg->segsum_bytes += sizeof(union nandfs_binfo); - seginfo->curseg->current_off = (char *)binfo; - - TAILQ_INSERT_TAIL(&seginfo->curseg->data, bp, b_cluster.cluster_entry); - - seginfo->curseg->nbinfos++; - seginfo->curseg->nblocks++; - seginfo->curseg->num_blocks--; - seginfo->blocks++; - - DPRINTF(SYNC, ("%s: bp (%p) number %x (left %x)\n", - __func__, bp, seginfo->curseg->nblocks, - seginfo->curseg->num_blocks)); - return (0); -} - -static int -nandfs_iterate_dirty_buf(struct vnode *vp, struct nandfs_seginfo *seginfo, - uint8_t hold) -{ - struct buf *bp, *tbd; - struct bufobj *bo; - struct nandfs_node *node; - int error; - - node = VTON(vp); - bo = &vp->v_bufobj; - - ASSERT_VOP_ELOCKED(vp, __func__); - - /* Iterate dirty data bufs */ - TAILQ_FOREACH_SAFE(bp, &bo->bo_dirty.bv_hd, b_bobufs, tbd) { - DPRINTF(SYNC, ("%s: vp (%p): bp (%p) with lblkno %jx ino %jx " - "add buf\n", __func__, vp, bp, bp->b_lblkno, node->nn_ino)); - - if (!(NANDFS_ISGATHERED(bp))) { - error = nandfs_bmap_update_dat(node, - nandfs_vblk_get(bp), bp); - if (error) - return (error); - NANDFS_GATHER(bp); - nandfs_add_blocks(seginfo, node, bp); - } - } - - return (0); -} - -static int -nandfs_iterate_system_vnode(struct nandfs_node *node, - struct nandfs_seginfo *seginfo) -{ - struct vnode *vp; - int nblocks; - uint8_t hold = 0; - - if (node->nn_ino != NANDFS_IFILE_INO) - hold = 1; - - vp = NTOV(node); - - nblocks = vp->v_bufobj.bo_dirty.bv_cnt; - DPRINTF(SYNC, ("%s: vp (%p): nblocks %x ino %jx\n", - __func__, vp, nblocks, node->nn_ino)); - - if (nblocks) - nandfs_iterate_dirty_buf(vp, seginfo, hold); - - return (0); -} - -static int -nandfs_iterate_dirty_vnodes(struct mount *mp, struct nandfs_seginfo *seginfo) -{ - struct nandfs_node *nandfs_node; - struct vnode *vp, *mvp; - struct thread *td; - struct bufobj *bo; - int error, update; - - td = curthread; - - MNT_VNODE_FOREACH_ACTIVE(vp, mp, mvp) { - update = 0; - - if (mp->mnt_syncer == vp || VOP_ISLOCKED(vp)) { - VI_UNLOCK(vp); - continue; - } - if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK | LK_NOWAIT, td) != 0) - continue; - - nandfs_node = VTON(vp); - if (nandfs_node->nn_flags & IN_MODIFIED) { - nandfs_node->nn_flags &= ~(IN_MODIFIED); - update = 1; - } - - bo = &vp->v_bufobj; - BO_LOCK(bo); - if (vp->v_bufobj.bo_dirty.bv_cnt) { - error = nandfs_iterate_dirty_buf(vp, seginfo, 0); - if (error) { - nandfs_error("%s: cannot iterate vnode:%p " - "err:%d\n", __func__, vp, error); - vput(vp); - BO_UNLOCK(bo); - return (error); - } - update = 1; - } else - vput(vp); - BO_UNLOCK(bo); - - if (update) - nandfs_node_update(nandfs_node); - } - - return (0); -} - -static int -nandfs_update_phys_block(struct nandfs_device *fsdev, struct buf *bp, - uint64_t phys_blknr, union nandfs_binfo *binfo) -{ - struct nandfs_node *node, *dat; - struct vnode *vp; - uint64_t new_blknr; - int error; - - vp = bp->b_vp; - node = VTON(vp); - new_blknr = nandfs_vblk_get(bp); - dat = fsdev->nd_dat_node; - - DPRINTF(BMAP, ("%s: ino %#jx lblk %#jx: vblk %#jx -> %#jx\n", - __func__, (uintmax_t)node->nn_ino, (uintmax_t)bp->b_lblkno, - (uintmax_t)new_blknr, (uintmax_t)phys_blknr)); - - if (node->nn_ino != NANDFS_DAT_INO) { - KASSERT((new_blknr != 0), ("vblk for bp %p is 0", bp)); - - nandfs_vblock_assign(fsdev, new_blknr, phys_blknr); - binfo->bi_v.bi_vblocknr = new_blknr; - binfo->bi_v.bi_blkoff = bp->b_lblkno; - binfo->bi_v.bi_ino = node->nn_ino; - } else { - VOP_LOCK(NTOV(dat), LK_EXCLUSIVE); - error = nandfs_bmap_update_block(node, bp, phys_blknr); - if (error) { - nandfs_error("%s: error updating block:%jx for bp:%p\n", - __func__, (uintmax_t)phys_blknr, bp); - VOP_UNLOCK(NTOV(dat), 0); - return (error); - } - VOP_UNLOCK(NTOV(dat), 0); - binfo->bi_dat.bi_blkoff = bp->b_lblkno; - binfo->bi_dat.bi_ino = node->nn_ino; - if (NANDFS_IS_INDIRECT(bp)) - binfo->bi_dat.bi_level = 1; - else - binfo->bi_dat.bi_level = 0; - } - - return (0); -} - -#define NBINFO(off) ((off) + sizeof(union nandfs_binfo)) -static int -nandfs_segment_assign_pblk(struct nandfs_segment *nfsseg) -{ - struct nandfs_device *fsdev; - union nandfs_binfo *binfo; - struct buf *bp, *seg_bp; - uint64_t blocknr; - uint32_t curr_off, blocksize; - int error; - - fsdev = nfsseg->fsdev; - blocksize = fsdev->nd_blocksize; - - blocknr = nfsseg->start_block + nfsseg->segsum_blocks; - seg_bp = TAILQ_FIRST(&nfsseg->segsum); - DPRINTF(SYNC, ("%s: seg:%p segsum bp:%p data:%p\n", - __func__, nfsseg, seg_bp, seg_bp->b_data)); - - binfo = (union nandfs_binfo *)(seg_bp->b_data + - sizeof(struct nandfs_segment_summary)); - curr_off = sizeof(struct nandfs_segment_summary); - - TAILQ_FOREACH(bp, &nfsseg->data, b_cluster.cluster_entry) { - KASSERT((bp->b_vp), ("bp %p has not vp", bp)); - - DPRINTF(BMAP, ("\n\n%s: assign buf %p for ino %#jx next %p\n", - __func__, bp, (uintmax_t)VTON(bp->b_vp)->nn_ino, - TAILQ_NEXT(bp, b_cluster.cluster_entry))); - - if (NBINFO(curr_off) > blocksize) { - seg_bp = TAILQ_NEXT(seg_bp, b_cluster.cluster_entry); - binfo = (union nandfs_binfo *)seg_bp->b_data; - curr_off = 0; - DPRINTF(SYNC, ("%s: next segsum %p data %p\n", - __func__, seg_bp, seg_bp->b_data)); - } - - error = nandfs_update_phys_block(fsdev, bp, blocknr, binfo); - if (error) { - nandfs_error("%s: err:%d when updatinng phys block:%jx" - " for bp:%p and binfo:%p\n", __func__, error, - (uintmax_t)blocknr, bp, binfo); - return (error); - } - binfo++; - curr_off = NBINFO(curr_off); - - blocknr++; - } - - return (0); -} - -static int -nandfs_seginfo_assign_pblk(struct nandfs_seginfo *seginfo) -{ - struct nandfs_segment *nfsseg; - int error = 0; - - LIST_FOREACH(nfsseg, &seginfo->seg_list, seg_link) { - error = nandfs_segment_assign_pblk(nfsseg); - if (error) - break; - } - - return (error); -} - -static struct nandfs_segment_summary * -nandfs_fill_segsum(struct nandfs_segment *seg, int has_sr) -{ - struct nandfs_segment_summary *ss; - struct nandfs_device *fsdev; - struct buf *bp; - uint32_t rest, segsum_size, blocksize, crc_calc; - uint16_t flags; - uint8_t *crc_area, crc_skip; - - DPRINTF(SYNC, ("%s: seg %#jx nblocks %#x sumbytes %#x\n", - __func__, (uintmax_t) seg->seg_num, - seg->nblocks + seg->segsum_blocks, - seg->segsum_bytes)); - - fsdev = seg->fsdev; - - flags = NANDFS_SS_LOGBGN | NANDFS_SS_LOGEND; - if (has_sr) - flags |= NANDFS_SS_SR; - - bp = TAILQ_FIRST(&seg->segsum); - ss = (struct nandfs_segment_summary *) bp->b_data; - ss->ss_magic = NANDFS_SEGSUM_MAGIC; - ss->ss_bytes = sizeof(struct nandfs_segment_summary); - ss->ss_flags = flags; - ss->ss_seq = ++(fsdev->nd_seg_sequence); - ss->ss_create = fsdev->nd_ts.tv_sec; - nandfs_get_segment_range(fsdev, seg->seg_next, &ss->ss_next, NULL); - ss->ss_nblocks = seg->nblocks + seg->segsum_blocks; - ss->ss_nbinfos = seg->nbinfos; - ss->ss_sumbytes = seg->segsum_bytes; - - crc_skip = sizeof(ss->ss_datasum) + sizeof(ss->ss_sumsum); - blocksize = seg->fsdev->nd_blocksize; - - segsum_size = seg->segsum_bytes - crc_skip; - rest = min(seg->segsum_bytes, blocksize) - crc_skip; - crc_area = (uint8_t *)ss + crc_skip; - crc_calc = ~0U; - while (segsum_size > 0) { - crc_calc = crc32_raw(crc_area, rest, crc_calc); - segsum_size -= rest; - if (!segsum_size) - break; - bp = TAILQ_NEXT(bp, b_cluster.cluster_entry); - crc_area = (uint8_t *)bp->b_data; - rest = segsum_size <= blocksize ? segsum_size : blocksize; - } - ss->ss_sumsum = crc_calc ^ ~0U; - - return (ss); - -} - -static int -nandfs_save_buf(struct buf *bp, uint64_t blocknr, struct nandfs_device *fsdev) -{ - struct bufobj *bo; - int error; - - bo = &fsdev->nd_devvp->v_bufobj; - - bp->b_blkno = nandfs_block_to_dblock(fsdev, blocknr); - bp->b_iooffset = dbtob(bp->b_blkno); - - KASSERT(bp->b_bufobj != NULL, ("no bufobj for %p", bp)); - if (bp->b_bufobj != bo) { - BO_LOCK(bp->b_bufobj); - BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, - BO_LOCKPTR(bp->b_bufobj)); - KASSERT(BUF_ISLOCKED(bp), ("Problem with locking buffer")); - } - - DPRINTF(SYNC, ("%s: buf: %p offset %#jx blk %#jx size %#x\n", - __func__, bp, (uintmax_t)bp->b_offset, (uintmax_t)blocknr, - fsdev->nd_blocksize)); - - NANDFS_UNGATHER(bp); - nandfs_buf_clear(bp, 0xffffffff); - bp->b_flags &= ~(B_ASYNC|B_INVAL|B_MANAGED); - error = bwrite(bp); - if (error) { - nandfs_error("%s: error:%d when writing buffer:%p\n", - __func__, error, bp); - return (error); - } - return (error); -} - -static void -nandfs_clean_buf(struct nandfs_device *fsdev, struct buf *bp) -{ - - DPRINTF(SYNC, ("%s: buf: %p\n", __func__, bp)); - - NANDFS_UNGATHER(bp); - nandfs_buf_clear(bp, 0xffffffff); - bp->b_flags &= ~(B_ASYNC|B_INVAL|B_MANAGED); - nandfs_undirty_buf_fsdev(fsdev, bp); -} - -static void -nandfs_clean_segblocks(struct nandfs_segment *seg, uint8_t unlock) -{ - struct nandfs_device *fsdev = seg->fsdev; - struct nandfs_segment *next_seg; - struct buf *bp, *tbp, *next_bp; - struct vnode *vp, *next_vp; - - VOP_LOCK(fsdev->nd_devvp, LK_EXCLUSIVE); - TAILQ_FOREACH_SAFE(bp, &seg->segsum, b_cluster.cluster_entry, tbp) { - TAILQ_REMOVE(&seg->segsum, bp, b_cluster.cluster_entry); - nandfs_clean_buf(fsdev, bp); - } - - TAILQ_FOREACH_SAFE(bp, &seg->data, b_cluster.cluster_entry, tbp) { - TAILQ_REMOVE(&seg->data, bp, b_cluster.cluster_entry); - - /* - * If bp is not super-root and vnode is not currently - * locked lock it. - */ - vp = bp->b_vp; - next_vp = NULL; - next_bp = TAILQ_NEXT(bp, b_cluster.cluster_entry); - if (!next_bp) { - next_seg = LIST_NEXT(seg, seg_link); - if (next_seg) - next_bp = TAILQ_FIRST(&next_seg->data); - } - - if (next_bp) - next_vp = next_bp->b_vp; - - nandfs_clean_buf(fsdev, bp); - - if (unlock && vp != NULL && next_vp != vp && - !NANDFS_SYS_NODE(VTON(vp)->nn_ino)) - vput(vp); - - nandfs_dirty_bufs_decrement(fsdev); - } - - VOP_UNLOCK(fsdev->nd_devvp, 0); -} - -static int -nandfs_save_segblocks(struct nandfs_segment *seg, uint8_t unlock) -{ - struct nandfs_device *fsdev = seg->fsdev; - struct nandfs_segment *next_seg; - struct buf *bp, *tbp, *next_bp; - struct vnode *vp, *next_vp; - uint64_t blocknr; - uint32_t i = 0; - int error = 0; - - VOP_LOCK(fsdev->nd_devvp, LK_EXCLUSIVE); - TAILQ_FOREACH_SAFE(bp, &seg->segsum, b_cluster.cluster_entry, tbp) { - TAILQ_REMOVE(&seg->segsum, bp, b_cluster.cluster_entry); - blocknr = seg->start_block + i; - error = nandfs_save_buf(bp, blocknr, fsdev); - if (error) { - nandfs_error("%s: error saving buf: %p blocknr:%jx\n", - __func__, bp, (uintmax_t)blocknr); - goto out; - } - i++; - } - - i = 0; - TAILQ_FOREACH_SAFE(bp, &seg->data, b_cluster.cluster_entry, tbp) { - TAILQ_REMOVE(&seg->data, bp, b_cluster.cluster_entry); - - blocknr = seg->start_block + seg->segsum_blocks + i; - /* - * If bp is not super-root and vnode is not currently - * locked lock it. - */ - vp = bp->b_vp; - next_vp = NULL; - next_bp = TAILQ_NEXT(bp, b_cluster.cluster_entry); - if (!next_bp) { - next_seg = LIST_NEXT(seg, seg_link); - if (next_seg) - next_bp = TAILQ_FIRST(&next_seg->data); - } - - if (next_bp) - next_vp = next_bp->b_vp; - - error = nandfs_save_buf(bp, blocknr, fsdev); - if (error) { - nandfs_error("%s: error saving buf: %p blknr: %jx\n", - __func__, bp, (uintmax_t)blocknr); - if (unlock && vp != NULL && next_vp != vp && - !NANDFS_SYS_NODE(VTON(vp)->nn_ino)) - vput(vp); - goto out; - } - - if (unlock && vp != NULL && next_vp != vp && - !NANDFS_SYS_NODE(VTON(vp)->nn_ino)) - vput(vp); - - i++; - nandfs_dirty_bufs_decrement(fsdev); - } -out: - if (error) { - nandfs_clean_segblocks(seg, unlock); - VOP_UNLOCK(fsdev->nd_devvp, 0); - return (error); - } - - VOP_UNLOCK(fsdev->nd_devvp, 0); - return (error); -} - - -static void -clean_seginfo(struct nandfs_seginfo *seginfo, uint8_t unlock) -{ - struct nandfs_segment *seg; - - DPRINTF(SYNC, ("%s: seginfo %p\n", __func__, seginfo)); - - LIST_FOREACH(seg, &seginfo->seg_list, seg_link) { - nandfs_clean_segblocks(seg, unlock); - } -} - -static int -save_seginfo(struct nandfs_seginfo *seginfo, uint8_t unlock) -{ - struct nandfs_segment *seg; - struct nandfs_device *fsdev; - struct nandfs_segment_summary *ss; - int error = 0; - - fsdev = seginfo->fsdev; - - DPRINTF(SYNC, ("%s: seginfo %p\n", __func__, seginfo)); - - LIST_FOREACH(seg, &seginfo->seg_list, seg_link) { - if (LIST_NEXT(seg, seg_link)) { - nandfs_fill_segsum(seg, 0); - error = nandfs_save_segblocks(seg, unlock); - if (error) { - nandfs_error("%s: error:%d saving seg:%p\n", - __func__, error, seg); - goto out; - } - } else { - ss = nandfs_fill_segsum(seg, 1); - fsdev->nd_last_segsum = *ss; - error = nandfs_save_segblocks(seg, unlock); - if (error) { - nandfs_error("%s: error:%d saving seg:%p\n", - __func__, error, seg); - goto out; - } - fsdev->nd_last_cno++; - fsdev->nd_last_pseg = seg->start_block; - } - } -out: - if (error) - clean_seginfo(seginfo, unlock); - return (error); -} - -static void -nandfs_invalidate_bufs(struct nandfs_device *fsdev, uint64_t segno) -{ - uint64_t start, end; - struct buf *bp, *tbd; - struct bufobj *bo; - - nandfs_get_segment_range(fsdev, segno, &start, &end); - - bo = &NTOV(fsdev->nd_gc_node)->v_bufobj; - - BO_LOCK(bo); -restart_locked_gc: - TAILQ_FOREACH_SAFE(bp, &bo->bo_clean.bv_hd, b_bobufs, tbd) { - if (!(bp->b_lblkno >= start && bp->b_lblkno <= end)) - continue; - - if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL)) - goto restart_locked_gc; - - bremfree(bp); - bp->b_flags |= (B_INVAL | B_RELBUF); - bp->b_flags &= ~(B_ASYNC | B_MANAGED); - BO_UNLOCK(bo); - brelse(bp); - BO_LOCK(bo); - } - BO_UNLOCK(bo); -} - -/* Process segments marks to free by cleaner */ -static void -nandfs_process_segments(struct nandfs_device *fsdev) -{ - uint64_t saved_segment; - int i; - - if (fsdev->nd_free_base) { - saved_segment = nandfs_get_segnum_of_block(fsdev, - fsdev->nd_super.s_last_pseg); - for (i = 0; i < fsdev->nd_free_count; i++) { - if (fsdev->nd_free_base[i] == NANDFS_NOSEGMENT) - continue; - /* Update superblock if clearing segment point by it */ - if (fsdev->nd_free_base[i] == saved_segment) { - nandfs_write_superblock(fsdev); - saved_segment = nandfs_get_segnum_of_block( - fsdev, fsdev->nd_super.s_last_pseg); - } - nandfs_invalidate_bufs(fsdev, fsdev->nd_free_base[i]); - nandfs_clear_segment(fsdev, fsdev->nd_free_base[i]); - } - - free(fsdev->nd_free_base, M_NANDFSTEMP); - fsdev->nd_free_base = NULL; - fsdev->nd_free_count = 0; - } -} - -/* Collect and write dirty buffers */ -int -nandfs_sync_file(struct vnode *vp) -{ - struct nandfs_device *fsdev; - struct nandfs_node *nandfs_node; - struct nandfsmount *nmp; - struct nandfs_node *dat, *su, *ifile, *cp; - struct nandfs_seginfo *seginfo = NULL; - struct nandfs_segment *seg; - int update, error; - int cno_changed; - - ASSERT_VOP_LOCKED(vp, __func__); - DPRINTF(SYNC, ("%s: START\n", __func__)); - - error = 0; - nmp = VFSTONANDFS(vp->v_mount); - fsdev = nmp->nm_nandfsdev; - - dat = fsdev->nd_dat_node; - su = fsdev->nd_su_node; - cp = fsdev->nd_cp_node; - ifile = nmp->nm_ifile_node; - - NANDFS_WRITEASSERT(fsdev); - if (lockmgr(&fsdev->nd_seg_const, LK_UPGRADE, NULL) != 0) { - DPRINTF(SYNC, ("%s: lost shared lock\n", __func__)); - if (lockmgr(&fsdev->nd_seg_const, LK_EXCLUSIVE, NULL) != 0) - panic("couldn't lock exclusive"); - } - DPRINTF(SYNC, ("%s: got lock\n", __func__)); - - VOP_LOCK(NTOV(su), LK_EXCLUSIVE); - create_seginfo(fsdev, &seginfo); - - update = 0; - - nandfs_node = VTON(vp); - if (nandfs_node->nn_flags & IN_MODIFIED) { - nandfs_node->nn_flags &= ~(IN_MODIFIED); - update = 1; - } - - if (vp->v_bufobj.bo_dirty.bv_cnt) { - error = nandfs_iterate_dirty_buf(vp, seginfo, 0); - if (error) { - clean_seginfo(seginfo, 0); - delete_seginfo(seginfo); - VOP_UNLOCK(NTOV(su), 0); - lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL); - nandfs_error("%s: err:%d iterating dirty bufs vp:%p", - __func__, error, vp); - return (error); - } - update = 1; - } - - if (update) { - VOP_LOCK(NTOV(ifile), LK_EXCLUSIVE); - error = nandfs_node_update(nandfs_node); - if (error) { - clean_seginfo(seginfo, 0); - delete_seginfo(seginfo); - VOP_UNLOCK(NTOV(ifile), 0); - VOP_UNLOCK(NTOV(su), 0); - lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL); - nandfs_error("%s: err:%d updating vp:%p", - __func__, error, vp); - return (error); - } - VOP_UNLOCK(NTOV(ifile), 0); - } - - cno_changed = 0; - if (seginfo->blocks) { - VOP_LOCK(NTOV(cp), LK_EXCLUSIVE); - cno_changed = 1; - /* Create new checkpoint */ - error = nandfs_get_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1); - if (error) { - clean_seginfo(seginfo, 0); - delete_seginfo(seginfo); - VOP_UNLOCK(NTOV(cp), 0); - VOP_UNLOCK(NTOV(su), 0); - lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL); - nandfs_error("%s: err:%d getting cp:%jx", - __func__, error, fsdev->nd_last_cno + 1); - return (error); - } - - /* Reiterate all blocks and assign physical block number */ - nandfs_seginfo_assign_pblk(seginfo); - - /* Fill checkpoint data */ - error = nandfs_set_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1, - &ifile->nn_inode, seginfo->blocks); - if (error) { - clean_seginfo(seginfo, 0); - delete_seginfo(seginfo); - VOP_UNLOCK(NTOV(cp), 0); - VOP_UNLOCK(NTOV(su), 0); - lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL); - nandfs_error("%s: err:%d setting cp:%jx", - __func__, error, fsdev->nd_last_cno + 1); - return (error); - } - - VOP_UNLOCK(NTOV(cp), 0); - LIST_FOREACH(seg, &seginfo->seg_list, seg_link) - nandfs_update_segment(fsdev, seg->seg_num, - seg->nblocks + seg->segsum_blocks); - - VOP_LOCK(NTOV(dat), LK_EXCLUSIVE); - error = save_seginfo(seginfo, 0); - if (error) { - clean_seginfo(seginfo, 0); - delete_seginfo(seginfo); - VOP_UNLOCK(NTOV(dat), 0); - VOP_UNLOCK(NTOV(su), 0); - lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL); - nandfs_error("%s: err:%d updating seg", - __func__, error); - return (error); - } - VOP_UNLOCK(NTOV(dat), 0); - } - - VOP_UNLOCK(NTOV(su), 0); - - delete_seginfo(seginfo); - lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL); - - if (cno_changed && !error) { - if (nandfs_cps_between_sblocks != 0 && - fsdev->nd_last_cno % nandfs_cps_between_sblocks == 0) - nandfs_write_superblock(fsdev); - } - - ASSERT_VOP_LOCKED(vp, __func__); - DPRINTF(SYNC, ("%s: END error %d\n", __func__, error)); - return (error); -} - -int -nandfs_segment_constructor(struct nandfsmount *nmp, int flags) -{ - struct nandfs_device *fsdev; - struct nandfs_seginfo *seginfo = NULL; - struct nandfs_segment *seg; - struct nandfs_node *dat, *su, *ifile, *cp, *gc; - int cno_changed, error; - - DPRINTF(SYNC, ("%s: START\n", __func__)); - fsdev = nmp->nm_nandfsdev; - - lockmgr(&fsdev->nd_seg_const, LK_EXCLUSIVE, NULL); - DPRINTF(SYNC, ("%s: git lock\n", __func__)); -again: - create_seginfo(fsdev, &seginfo); - - dat = fsdev->nd_dat_node; - su = fsdev->nd_su_node; - cp = fsdev->nd_cp_node; - gc = fsdev->nd_gc_node; - ifile = nmp->nm_ifile_node; - - VOP_LOCK(NTOV(su), LK_EXCLUSIVE); - VOP_LOCK(NTOV(ifile), LK_EXCLUSIVE); - VOP_LOCK(NTOV(gc), LK_EXCLUSIVE); - VOP_LOCK(NTOV(cp), LK_EXCLUSIVE); - - nandfs_iterate_system_vnode(gc, seginfo); - nandfs_iterate_dirty_vnodes(nmp->nm_vfs_mountp, seginfo); - nandfs_iterate_system_vnode(ifile, seginfo); - nandfs_iterate_system_vnode(su, seginfo); - - cno_changed = 0; - if (seginfo->blocks || flags) { - cno_changed = 1; - /* Create new checkpoint */ - error = nandfs_get_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1); - if (error) { - clean_seginfo(seginfo, 0); - delete_seginfo(seginfo); - goto error_locks; - } - - /* Collect blocks from system files */ - nandfs_iterate_system_vnode(cp, seginfo); - nandfs_iterate_system_vnode(su, seginfo); - VOP_LOCK(NTOV(dat), LK_EXCLUSIVE); - nandfs_iterate_system_vnode(dat, seginfo); - VOP_UNLOCK(NTOV(dat), 0); -reiterate: - seginfo->reiterate = 0; - nandfs_iterate_system_vnode(su, seginfo); - VOP_LOCK(NTOV(dat), LK_EXCLUSIVE); - nandfs_iterate_system_vnode(dat, seginfo); - VOP_UNLOCK(NTOV(dat), 0); - if (seginfo->reiterate) - goto reiterate; - if (!(seginfo->curseg) || !seginfo->curseg->num_blocks) { - error = create_segment(seginfo); - if (error) { - clean_seginfo(seginfo, 0); - delete_seginfo(seginfo); - goto error_locks; - } - goto reiterate; - } - - /* Reiterate all blocks and assign physical block number */ - nandfs_seginfo_assign_pblk(seginfo); - - /* Fill superroot */ - error = nandfs_add_superroot(seginfo); - if (error) { - clean_seginfo(seginfo, 0); - delete_seginfo(seginfo); - goto error_locks; - } - KASSERT(!(seginfo->reiterate), ("reiteration after superroot")); - - /* Fill checkpoint data */ - nandfs_set_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1, - &ifile->nn_inode, seginfo->blocks); - - LIST_FOREACH(seg, &seginfo->seg_list, seg_link) - nandfs_update_segment(fsdev, seg->seg_num, - seg->nblocks + seg->segsum_blocks); - - VOP_LOCK(NTOV(dat), LK_EXCLUSIVE); - error = save_seginfo(seginfo, 1); - if (error) { - clean_seginfo(seginfo, 1); - delete_seginfo(seginfo); - goto error_dat; - } - VOP_UNLOCK(NTOV(dat), 0); - } - - VOP_UNLOCK(NTOV(cp), 0); - VOP_UNLOCK(NTOV(gc), 0); - VOP_UNLOCK(NTOV(ifile), 0); - - nandfs_process_segments(fsdev); - - VOP_UNLOCK(NTOV(su), 0); - - delete_seginfo(seginfo); - - /* - * XXX: a hack, will go away soon - */ - if ((NTOV(dat)->v_bufobj.bo_dirty.bv_cnt != 0 || - NTOV(cp)->v_bufobj.bo_dirty.bv_cnt != 0 || - NTOV(gc)->v_bufobj.bo_dirty.bv_cnt != 0 || - NTOV(ifile)->v_bufobj.bo_dirty.bv_cnt != 0 || - NTOV(su)->v_bufobj.bo_dirty.bv_cnt != 0) && - (flags & NANDFS_UMOUNT)) { - DPRINTF(SYNC, ("%s: RERUN\n", __func__)); - goto again; - } - - MPASS(fsdev->nd_free_base == NULL); - - lockmgr(&fsdev->nd_seg_const, LK_RELEASE, NULL); - - if (cno_changed) { - if ((nandfs_cps_between_sblocks != 0 && - fsdev->nd_last_cno % nandfs_cps_between_sblocks == 0) || - flags & NANDFS_UMOUNT) - nandfs_write_superblock(fsdev); - } - - DPRINTF(SYNC, ("%s: END\n", __func__)); - return (0); -error_dat: - VOP_UNLOCK(NTOV(dat), 0); -error_locks: - VOP_UNLOCK(NTOV(cp), 0); - VOP_UNLOCK(NTOV(gc), 0); - VOP_UNLOCK(NTOV(ifile), 0); - VOP_UNLOCK(NTOV(su), 0); - lockmgr(&fsdev->nd_seg_const, LK_RELEASE, NULL); - - return (error); -} - -#ifdef DDB -/* - * Show details about the given NANDFS mount point. - */ -DB_SHOW_COMMAND(nandfs, db_show_nandfs) -{ - struct mount *mp; - struct nandfs_device *nffsdev; - struct nandfs_segment *seg; - struct nandfsmount *nmp; - struct buf *bp; - struct vnode *vp; - - if (!have_addr) { - db_printf("\nUsage: show nandfs <mount_addr>\n"); - return; - } - - mp = (struct mount *)addr; - db_printf("%p %s on %s (%s)\n", mp, mp->mnt_stat.f_mntfromname, - mp->mnt_stat.f_mntonname, mp->mnt_stat.f_fstypename); - - - nmp = (struct nandfsmount *)(mp->mnt_data); - nffsdev = nmp->nm_nandfsdev; - db_printf("dev vnode:%p\n", nffsdev->nd_devvp); - db_printf("blocksize:%jx last cno:%jx last pseg:%jx seg num:%jx\n", - (uintmax_t)nffsdev->nd_blocksize, (uintmax_t)nffsdev->nd_last_cno, - (uintmax_t)nffsdev->nd_last_pseg, (uintmax_t)nffsdev->nd_seg_num); - db_printf("system nodes: dat:%p cp:%p su:%p ifile:%p gc:%p\n", - nffsdev->nd_dat_node, nffsdev->nd_cp_node, nffsdev->nd_su_node, - nmp->nm_ifile_node, nffsdev->nd_gc_node); - - if (nffsdev->nd_seginfo != NULL) { - LIST_FOREACH(seg, &nffsdev->nd_seginfo->seg_list, seg_link) { - db_printf("seg: %p\n", seg); - TAILQ_FOREACH(bp, &seg->segsum, - b_cluster.cluster_entry) - db_printf("segbp %p\n", bp); - TAILQ_FOREACH(bp, &seg->data, - b_cluster.cluster_entry) { - vp = bp->b_vp; - db_printf("bp:%p bp->b_vp:%p ino:%jx\n", bp, vp, - (uintmax_t)(vp ? VTON(vp)->nn_ino : 0)); - } - } - } -} -#endif diff --git a/sys/fs/nandfs/nandfs_subr.c b/sys/fs/nandfs/nandfs_subr.c deleted file mode 100644 index 0a3f65a50543..000000000000 --- a/sys/fs/nandfs/nandfs_subr.c +++ /dev/null @@ -1,1091 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf - * Copyright (c) 2008, 2009 Reinoud Zandijk - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * From: NetBSD: nilfs_subr.c,v 1.4 2009/07/29 17:06:57 reinoud - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/gsb_crc32.h> -#include <sys/namei.h> -#include <sys/resourcevar.h> -#include <sys/kernel.h> -#include <sys/file.h> -#include <sys/stat.h> -#include <sys/buf.h> -#include <sys/bio.h> -#include <sys/proc.h> -#include <sys/mount.h> -#include <sys/vnode.h> -#include <sys/signalvar.h> -#include <sys/malloc.h> -#include <sys/dirent.h> -#include <sys/lockf.h> -#include <sys/libkern.h> - -#include <geom/geom.h> -#include <geom/geom_vfs.h> - -#include <vm/vm.h> -#include <vm/vm_extern.h> - -#include <machine/_inttypes.h> -#include "nandfs_mount.h" -#include "nandfs.h" -#include "nandfs_subr.h" - -MALLOC_DEFINE(M_NANDFSMNT, "nandfs_mount", "NANDFS mount"); -MALLOC_DEFINE(M_NANDFSTEMP, "nandfs_tmt", "NANDFS tmp"); - -uma_zone_t nandfs_node_zone; - -void nandfs_bdflush(struct bufobj *bo, struct buf *bp); -int nandfs_bufsync(struct bufobj *bo, int waitfor); - -struct buf_ops buf_ops_nandfs = { - .bop_name = "buf_ops_nandfs", - .bop_write = bufwrite, - .bop_strategy = bufstrategy, - .bop_sync = nandfs_bufsync, - .bop_bdflush = nandfs_bdflush, -}; - -int -nandfs_bufsync(struct bufobj *bo, int waitfor) -{ - struct vnode *vp; - int error = 0; - - vp = bo2vnode(bo); - - ASSERT_VOP_LOCKED(vp, __func__); - error = nandfs_sync_file(vp); - if (error) - nandfs_warning("%s: cannot flush buffers err:%d\n", - __func__, error); - - return (error); -} - -void -nandfs_bdflush(bo, bp) - struct bufobj *bo; - struct buf *bp; -{ - struct vnode *vp; - int error; - - if (bo->bo_dirty.bv_cnt <= ((dirtybufthresh * 8) / 10)) - return; - - vp = bp->b_vp; - if (NANDFS_SYS_NODE(VTON(vp)->nn_ino)) - return; - - if (NANDFS_IS_INDIRECT(bp)) - return; - - error = nandfs_sync_file(vp); - if (error) - nandfs_warning("%s: cannot flush buffers err:%d\n", - __func__, error); -} - -int -nandfs_init(struct vfsconf *vfsp) -{ - - nandfs_node_zone = uma_zcreate("nandfs node zone", - sizeof(struct nandfs_node), NULL, NULL, NULL, NULL, 0, 0); - - return (0); -} - -int -nandfs_uninit(struct vfsconf *vfsp) -{ - - uma_zdestroy(nandfs_node_zone); - return (0); -} - -/* Basic calculators */ -uint64_t -nandfs_get_segnum_of_block(struct nandfs_device *nandfsdev, - nandfs_daddr_t blocknr) -{ - uint64_t segnum, blks_per_seg; - - MPASS(blocknr >= nandfsdev->nd_fsdata.f_first_data_block); - - blks_per_seg = nandfsdev->nd_fsdata.f_blocks_per_segment; - - segnum = blocknr / blks_per_seg; - segnum -= nandfsdev->nd_fsdata.f_first_data_block / blks_per_seg; - - DPRINTF(SYNC, ("%s: returning blocknr %jx -> segnum %jx\n", __func__, - blocknr, segnum)); - - return (segnum); -} - -void -nandfs_get_segment_range(struct nandfs_device *nandfsdev, uint64_t segnum, - uint64_t *seg_start, uint64_t *seg_end) -{ - uint64_t blks_per_seg; - - blks_per_seg = nandfsdev->nd_fsdata.f_blocks_per_segment; - *seg_start = nandfsdev->nd_fsdata.f_first_data_block + - blks_per_seg * segnum; - if (seg_end != NULL) - *seg_end = *seg_start + blks_per_seg -1; -} - -void nandfs_calc_mdt_consts(struct nandfs_device *nandfsdev, - struct nandfs_mdt *mdt, int entry_size) -{ - uint32_t blocksize = nandfsdev->nd_blocksize; - - mdt->entries_per_group = blocksize * 8; - mdt->entries_per_block = blocksize / entry_size; - - mdt->blocks_per_group = - (mdt->entries_per_group -1) / mdt->entries_per_block + 1 + 1; - mdt->groups_per_desc_block = - blocksize / sizeof(struct nandfs_block_group_desc); - mdt->blocks_per_desc_block = - mdt->groups_per_desc_block * mdt->blocks_per_group + 1; -} - -int -nandfs_dev_bread(struct nandfs_device *nandfsdev, nandfs_lbn_t blocknr, - struct ucred *cred, int flags, struct buf **bpp) -{ - int blk2dev = nandfsdev->nd_blocksize / DEV_BSIZE; - int error; - - DPRINTF(BLOCK, ("%s: read from block %jx vp %p\n", __func__, - blocknr * blk2dev, nandfsdev->nd_devvp)); - error = bread(nandfsdev->nd_devvp, blocknr * blk2dev, - nandfsdev->nd_blocksize, NOCRED, bpp); - if (error) - nandfs_error("%s: cannot read from device - blk:%jx\n", - __func__, blocknr); - return (error); -} - -/* Read on a node */ -int -nandfs_bread(struct nandfs_node *node, nandfs_lbn_t blocknr, - struct ucred *cred, int flags, struct buf **bpp) -{ - nandfs_daddr_t vblk; - int error; - - DPRINTF(BLOCK, ("%s: vp:%p lbn:%#jx\n", __func__, NTOV(node), - blocknr)); - - error = bread(NTOV(node), blocknr, node->nn_nandfsdev->nd_blocksize, - cred, bpp); - - KASSERT(error == 0, ("%s: vp:%p lbn:%#jx err:%d\n", __func__, - NTOV(node), blocknr, error)); - - if (!nandfs_vblk_get(*bpp) && - ((*bpp)->b_flags & B_CACHE) && node->nn_ino != NANDFS_DAT_INO) { - nandfs_bmap_lookup(node, blocknr, &vblk); - nandfs_vblk_set(*bpp, vblk); - } - return (error); -} - -int -nandfs_bread_meta(struct nandfs_node *node, nandfs_lbn_t blocknr, - struct ucred *cred, int flags, struct buf **bpp) -{ - nandfs_daddr_t vblk; - int error; - - DPRINTF(BLOCK, ("%s: vp:%p lbn:%#jx\n", __func__, NTOV(node), - blocknr)); - - error = bread(NTOV(node), blocknr, node->nn_nandfsdev->nd_blocksize, - cred, bpp); - - KASSERT(error == 0, ("%s: vp:%p lbn:%#jx err:%d\n", __func__, - NTOV(node), blocknr, error)); - - if (!nandfs_vblk_get(*bpp) && - ((*bpp)->b_flags & B_CACHE) && node->nn_ino != NANDFS_DAT_INO) { - nandfs_bmap_lookup(node, blocknr, &vblk); - nandfs_vblk_set(*bpp, vblk); - } - - return (error); -} - -int -nandfs_bdestroy(struct nandfs_node *node, nandfs_daddr_t vblk) -{ - int error; - - if (!NANDFS_SYS_NODE(node->nn_ino)) - NANDFS_WRITEASSERT(node->nn_nandfsdev); - - error = nandfs_vblock_end(node->nn_nandfsdev, vblk); - if (error) { - nandfs_error("%s: ending vblk: %jx failed\n", - __func__, (uintmax_t)vblk); - return (error); - } - node->nn_inode.i_blocks--; - - return (0); -} - -int -nandfs_bcreate(struct nandfs_node *node, nandfs_lbn_t blocknr, - struct ucred *cred, int flags, struct buf **bpp) -{ - int error; - - ASSERT_VOP_LOCKED(NTOV(node), __func__); - if (!NANDFS_SYS_NODE(node->nn_ino)) - NANDFS_WRITEASSERT(node->nn_nandfsdev); - - DPRINTF(BLOCK, ("%s: vp:%p lbn:%#jx\n", __func__, NTOV(node), - blocknr)); - - *bpp = getblk(NTOV(node), blocknr, node->nn_nandfsdev->nd_blocksize, - 0, 0, 0); - - KASSERT((*bpp), ("%s: vp:%p lbn:%#jx\n", __func__, - NTOV(node), blocknr)); - - if (*bpp) { - vfs_bio_clrbuf(*bpp); - (*bpp)->b_blkno = ~(0); /* To avoid VOP_BMAP in bdwrite */ - error = nandfs_bmap_insert_block(node, blocknr, *bpp); - if (error) { - nandfs_warning("%s: failed bmap insert node:%p" - " blk:%jx\n", __func__, node, blocknr); - brelse(*bpp); - return (error); - } - node->nn_inode.i_blocks++; - - return (0); - } - - return (-1); -} - -int -nandfs_bcreate_meta(struct nandfs_node *node, nandfs_lbn_t blocknr, - struct ucred *cred, int flags, struct buf **bpp) -{ - struct nandfs_device *fsdev; - nandfs_daddr_t vblk; - int error; - - ASSERT_VOP_LOCKED(NTOV(node), __func__); - NANDFS_WRITEASSERT(node->nn_nandfsdev); - - DPRINTF(BLOCK, ("%s: vp:%p lbn:%#jx\n", __func__, NTOV(node), - blocknr)); - - fsdev = node->nn_nandfsdev; - - *bpp = getblk(NTOV(node), blocknr, node->nn_nandfsdev->nd_blocksize, - 0, 0, 0); - - KASSERT((*bpp), ("%s: vp:%p lbn:%#jx\n", __func__, - NTOV(node), blocknr)); - - memset((*bpp)->b_data, 0, fsdev->nd_blocksize); - - vfs_bio_clrbuf(*bpp); - (*bpp)->b_blkno = ~(0); /* To avoid VOP_BMAP in bdwrite */ - - nandfs_buf_set(*bpp, NANDFS_VBLK_ASSIGNED); - - if (node->nn_ino != NANDFS_DAT_INO) { - error = nandfs_vblock_alloc(fsdev, &vblk); - if (error) { - nandfs_buf_clear(*bpp, NANDFS_VBLK_ASSIGNED); - brelse(*bpp); - return (error); - } - } else - vblk = fsdev->nd_fakevblk++; - - nandfs_vblk_set(*bpp, vblk); - - nandfs_bmap_insert_block(node, blocknr, *bpp); - return (0); -} - -/* Translate index to a file block number and an entry */ -void -nandfs_mdt_trans(struct nandfs_mdt *mdt, uint64_t index, - nandfs_lbn_t *blocknr, uint32_t *entry_in_block) -{ - uint64_t blknr; - uint64_t group, group_offset, blocknr_in_group; - uint64_t desc_block, desc_offset; - - /* Calculate our offset in the file */ - group = index / mdt->entries_per_group; - group_offset = index % mdt->entries_per_group; - desc_block = group / mdt->groups_per_desc_block; - desc_offset = group % mdt->groups_per_desc_block; - blocknr_in_group = group_offset / mdt->entries_per_block; - - /* To descgroup offset */ - blknr = 1 + desc_block * mdt->blocks_per_desc_block; - - /* To group offset */ - blknr += desc_offset * mdt->blocks_per_group; - - /* To actual file block */ - blknr += 1 + blocknr_in_group; - - *blocknr = blknr; - *entry_in_block = group_offset % mdt->entries_per_block; -} - -void -nandfs_mdt_trans_blk(struct nandfs_mdt *mdt, uint64_t index, - uint64_t *desc, uint64_t *bitmap, nandfs_lbn_t *blocknr, - uint32_t *entry_in_block) -{ - uint64_t blknr; - uint64_t group, group_offset, blocknr_in_group; - uint64_t desc_block, desc_offset; - - /* Calculate our offset in the file */ - group = index / mdt->entries_per_group; - group_offset = index % mdt->entries_per_group; - desc_block = group / mdt->groups_per_desc_block; - desc_offset = group % mdt->groups_per_desc_block; - blocknr_in_group = group_offset / mdt->entries_per_block; - - /* To descgroup offset */ - *desc = desc_block * mdt->blocks_per_desc_block; - blknr = 1 + desc_block * mdt->blocks_per_desc_block; - - /* To group offset */ - blknr += desc_offset * mdt->blocks_per_group; - *bitmap = blknr; - - /* To actual file block */ - blknr += 1 + blocknr_in_group; - - *blocknr = blknr; - *entry_in_block = group_offset % mdt->entries_per_block; - - DPRINTF(ALLOC, - ("%s: desc_buf: %jx bitmap_buf: %jx entry_buf: %jx entry: %x\n", - __func__, (uintmax_t)*desc, (uintmax_t)*bitmap, - (uintmax_t)*blocknr, *entry_in_block)); -} - -int -nandfs_vtop(struct nandfs_node *node, nandfs_daddr_t vblocknr, - nandfs_daddr_t *pblocknr) -{ - struct nandfs_node *dat_node; - struct nandfs_dat_entry *entry; - struct buf *bp; - nandfs_lbn_t ldatblknr; - uint32_t entry_in_block; - int locked, error; - - if (node->nn_ino == NANDFS_DAT_INO || node->nn_ino == NANDFS_GC_INO) { - *pblocknr = vblocknr; - return (0); - } - - /* only translate valid vblocknrs */ - if (vblocknr == 0) - return (0); - - dat_node = node->nn_nandfsdev->nd_dat_node; - nandfs_mdt_trans(&node->nn_nandfsdev->nd_dat_mdt, vblocknr, &ldatblknr, - &entry_in_block); - - locked = NANDFS_VOP_ISLOCKED(NTOV(dat_node)); - if (!locked) - VOP_LOCK(NTOV(dat_node), LK_SHARED); - error = nandfs_bread(dat_node, ldatblknr, NOCRED, 0, &bp); - if (error) { - DPRINTF(TRANSLATE, ("vtop: can't read in DAT block %#jx!\n", - (uintmax_t)ldatblknr)); - brelse(bp); - VOP_UNLOCK(NTOV(dat_node), 0); - return (error); - } - - /* Get our translation */ - entry = ((struct nandfs_dat_entry *) bp->b_data) + entry_in_block; - DPRINTF(TRANSLATE, ("\tentry %p data %p entry_in_block %x\n", - entry, bp->b_data, entry_in_block)) - DPRINTF(TRANSLATE, ("\tvblk %#jx -> %#jx for cp [%#jx-%#jx]\n", - (uintmax_t)vblocknr, (uintmax_t)entry->de_blocknr, - (uintmax_t)entry->de_start, (uintmax_t)entry->de_end)); - - *pblocknr = entry->de_blocknr; - brelse(bp); - if (!locked) - VOP_UNLOCK(NTOV(dat_node), 0); - - MPASS(*pblocknr >= node->nn_nandfsdev->nd_fsdata.f_first_data_block || - *pblocknr == 0); - - return (0); -} - -int -nandfs_segsum_valid(struct nandfs_segment_summary *segsum) -{ - - return (segsum->ss_magic == NANDFS_SEGSUM_MAGIC); -} - -int -nandfs_load_segsum(struct nandfs_device *fsdev, nandfs_daddr_t blocknr, - struct nandfs_segment_summary *segsum) -{ - struct buf *bp; - int error; - - DPRINTF(VOLUMES, ("nandfs: try segsum at block %jx\n", - (uintmax_t)blocknr)); - - error = nandfs_dev_bread(fsdev, blocknr, NOCRED, 0, &bp); - if (error) - return (error); - - memcpy(segsum, bp->b_data, sizeof(struct nandfs_segment_summary)); - brelse(bp); - - if (!nandfs_segsum_valid(segsum)) { - DPRINTF(VOLUMES, ("%s: bad magic pseg:%jx\n", __func__, - blocknr)); - return (EINVAL); - } - - return (error); -} - -static int -nandfs_load_super_root(struct nandfs_device *nandfsdev, - struct nandfs_segment_summary *segsum, uint64_t pseg) -{ - struct nandfs_super_root super_root; - struct buf *bp; - uint64_t blocknr; - uint32_t super_root_crc, comp_crc; - int off, error; - - /* Check if there is a superroot */ - if ((segsum->ss_flags & NANDFS_SS_SR) == 0) { - DPRINTF(VOLUMES, ("%s: no super root in pseg:%jx\n", __func__, - pseg)); - return (ENOENT); - } - - /* Get our super root, located at the end of the pseg */ - blocknr = pseg + segsum->ss_nblocks - 1; - DPRINTF(VOLUMES, ("%s: try at %#jx\n", __func__, (uintmax_t)blocknr)); - - error = nandfs_dev_bread(nandfsdev, blocknr, NOCRED, 0, &bp); - if (error) - return (error); - - memcpy(&super_root, bp->b_data, sizeof(struct nandfs_super_root)); - brelse(bp); - - /* Check super root CRC */ - super_root_crc = super_root.sr_sum; - off = sizeof(super_root.sr_sum); - comp_crc = crc32((uint8_t *)&super_root + off, - NANDFS_SR_BYTES - off); - - if (super_root_crc != comp_crc) { - DPRINTF(VOLUMES, ("%s: invalid crc:%#x [expect:%#x]\n", - __func__, super_root_crc, comp_crc)); - return (EINVAL); - } - - nandfsdev->nd_super_root = super_root; - DPRINTF(VOLUMES, ("%s: got valid superroot\n", __func__)); - - return (0); -} - -/* - * Search for the last super root recorded. - */ -int -nandfs_search_super_root(struct nandfs_device *nandfsdev) -{ - struct nandfs_super_block *super; - struct nandfs_segment_summary segsum; - uint64_t seg_start, seg_end, cno, seq, create, pseg; - uint64_t segnum; - int error, found; - - error = found = 0; - - /* Search for last super root */ - pseg = nandfsdev->nd_super.s_last_pseg; - segnum = nandfs_get_segnum_of_block(nandfsdev, pseg); - - cno = nandfsdev->nd_super.s_last_cno; - create = seq = 0; - DPRINTF(VOLUMES, ("%s: start in pseg %#jx\n", __func__, - (uintmax_t)pseg)); - - for (;;) { - error = nandfs_load_segsum(nandfsdev, pseg, &segsum); - if (error) - break; - - if (segsum.ss_seq < seq || segsum.ss_create < create) - break; - - /* Try to load super root */ - if (segsum.ss_flags & NANDFS_SS_SR) { - error = nandfs_load_super_root(nandfsdev, &segsum, pseg); - if (error) - break; /* confused */ - found = 1; - - super = &nandfsdev->nd_super; - nandfsdev->nd_last_segsum = segsum; - super->s_last_pseg = pseg; - super->s_last_cno = cno++; - super->s_last_seq = segsum.ss_seq; - super->s_state = NANDFS_VALID_FS; - seq = segsum.ss_seq; - create = segsum.ss_create; - } else { - seq = segsum.ss_seq; - create = segsum.ss_create; - } - - /* Calculate next partial segment location */ - pseg += segsum.ss_nblocks; - DPRINTF(VOLUMES, ("%s: next partial seg is %jx\n", __func__, - (uintmax_t)pseg)); - - /* Did we reach the end of the segment? if so, go to the next */ - nandfs_get_segment_range(nandfsdev, segnum, &seg_start, - &seg_end); - if (pseg >= seg_end) { - pseg = segsum.ss_next; - DPRINTF(VOLUMES, - (" partial seg oor next is %jx[%jx - %jx]\n", - (uintmax_t)pseg, (uintmax_t)seg_start, - (uintmax_t)seg_end)); - } - segnum = nandfs_get_segnum_of_block(nandfsdev, pseg); - } - - if (error && !found) - return (error); - - return (0); -} - -int -nandfs_get_node_raw(struct nandfs_device *nandfsdev, struct nandfsmount *nmp, - uint64_t ino, struct nandfs_inode *inode, struct nandfs_node **nodep) -{ - struct nandfs_node *node; - struct vnode *nvp; - struct mount *mp; - int error; - - *nodep = NULL; - - /* Associate with mountpoint if present */ - if (nmp) { - mp = nmp->nm_vfs_mountp; - error = getnewvnode("nandfs", mp, &nandfs_vnodeops, &nvp); - if (error) - return (error); - } else { - mp = NULL; - error = getnewvnode("snandfs", mp, &nandfs_system_vnodeops, - &nvp); - if (error) - return (error); - } - - if (mp) - NANDFS_WRITELOCK(nandfsdev); - - DPRINTF(IFILE, ("%s: ino: %#jx -> vp: %p\n", - __func__, (uintmax_t)ino, nvp)); - /* Lock node */ - lockmgr(nvp->v_vnlock, LK_EXCLUSIVE, NULL); - - if (mp) { - error = insmntque(nvp, mp); - if (error != 0) { - *nodep = NULL; - return (error); - } - } - - node = uma_zalloc(nandfs_node_zone, M_WAITOK | M_ZERO); - - /* Crosslink */ - node->nn_vnode = nvp; - nvp->v_bufobj.bo_ops = &buf_ops_nandfs; - node->nn_nmp = nmp; - node->nn_nandfsdev = nandfsdev; - nvp->v_data = node; - - /* Initiase NANDFS node */ - node->nn_ino = ino; - if (inode != NULL) - node->nn_inode = *inode; - - nandfs_vinit(nvp, ino); - - /* Return node */ - *nodep = node; - DPRINTF(IFILE, ("%s: ino:%#jx vp:%p node:%p\n", - __func__, (uintmax_t)ino, nvp, *nodep)); - - return (0); -} - -int -nandfs_get_node(struct nandfsmount *nmp, uint64_t ino, - struct nandfs_node **nodep) -{ - struct nandfs_device *nandfsdev; - struct nandfs_inode inode, *entry; - struct vnode *nvp, *vpp; - struct thread *td; - struct buf *bp; - uint64_t ivblocknr; - uint32_t entry_in_block; - int error; - - /* Look up node in hash table */ - td = curthread; - *nodep = NULL; - - if ((ino < NANDFS_ATIME_INO) && (ino != NANDFS_ROOT_INO)) { - printf("nandfs_get_node: system ino %"PRIu64" not in mount " - "point!\n", ino); - return (ENOENT); - } - - error = vfs_hash_get(nmp->nm_vfs_mountp, ino, LK_EXCLUSIVE, td, &nvp, - NULL, NULL); - if (error) - return (error); - - if (nvp != NULL) { - *nodep = (struct nandfs_node *)nvp->v_data; - return (0); - } - - /* Look up inode structure in mountpoints ifile */ - nandfsdev = nmp->nm_nandfsdev; - nandfs_mdt_trans(&nandfsdev->nd_ifile_mdt, ino, &ivblocknr, - &entry_in_block); - - VOP_LOCK(NTOV(nmp->nm_ifile_node), LK_SHARED); - error = nandfs_bread(nmp->nm_ifile_node, ivblocknr, NOCRED, 0, &bp); - if (error) { - brelse(bp); - VOP_UNLOCK(NTOV(nmp->nm_ifile_node), 0); - return (ENOENT); - } - - /* Get inode entry */ - entry = (struct nandfs_inode *) bp->b_data + entry_in_block; - memcpy(&inode, entry, sizeof(struct nandfs_inode)); - brelse(bp); - VOP_UNLOCK(NTOV(nmp->nm_ifile_node), 0); - - /* Get node */ - error = nandfs_get_node_raw(nmp->nm_nandfsdev, nmp, ino, &inode, nodep); - if (error) { - *nodep = NULL; - return (error); - } - - nvp = (*nodep)->nn_vnode; - error = vfs_hash_insert(nvp, ino, 0, td, &vpp, NULL, NULL); - if (error) { - *nodep = NULL; - return (error); - } - - return (error); -} - -void -nandfs_dispose_node(struct nandfs_node **nodep) -{ - struct nandfs_node *node; - struct vnode *vp; - - /* Protect against rogue values */ - node = *nodep; - if (!node) { - return; - } - DPRINTF(NODE, ("nandfs_dispose_node: %p\n", *nodep)); - - vp = NTOV(node); - vp->v_data = NULL; - - /* Free our associated memory */ - uma_zfree(nandfs_node_zone, node); - - *nodep = NULL; -} - -int -nandfs_lookup_name_in_dir(struct vnode *dvp, const char *name, int namelen, - uint64_t *ino, int *found, uint64_t *off) -{ - struct nandfs_node *dir_node = VTON(dvp); - struct nandfs_dir_entry *ndirent; - struct buf *bp; - uint64_t file_size, diroffset, blkoff; - uint64_t blocknr; - uint32_t blocksize = dir_node->nn_nandfsdev->nd_blocksize; - uint8_t *pos, name_len; - int error; - - *found = 0; - - DPRINTF(VNCALL, ("%s: %s file\n", __func__, name)); - if (dvp->v_type != VDIR) { - return (ENOTDIR); - } - - /* Get directory filesize */ - file_size = dir_node->nn_inode.i_size; - - /* Walk the directory */ - diroffset = 0; - blocknr = 0; - blkoff = 0; - error = nandfs_bread(dir_node, blocknr, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (EIO); - } - - while (diroffset < file_size) { - if (blkoff >= blocksize) { - blkoff = 0; blocknr++; - brelse(bp); - error = nandfs_bread(dir_node, blocknr, NOCRED, 0, - &bp); - if (error) { - brelse(bp); - return (EIO); - } - } - - /* Read in one dirent */ - pos = (uint8_t *) bp->b_data + blkoff; - ndirent = (struct nandfs_dir_entry *) pos; - name_len = ndirent->name_len; - - if ((name_len == namelen) && - (strncmp(name, ndirent->name, name_len) == 0) && - (ndirent->inode != 0)) { - *ino = ndirent->inode; - *off = diroffset; - DPRINTF(LOOKUP, ("found `%.*s` with ino %"PRIx64"\n", - name_len, ndirent->name, *ino)); - *found = 1; - break; - } - - /* Advance */ - diroffset += ndirent->rec_len; - blkoff += ndirent->rec_len; - } - brelse(bp); - - return (error); -} - -int -nandfs_get_fsinfo(struct nandfsmount *nmp, struct nandfs_fsinfo *fsinfo) -{ - struct nandfs_device *fsdev; - - fsdev = nmp->nm_nandfsdev; - - memcpy(&fsinfo->fs_fsdata, &fsdev->nd_fsdata, sizeof(fsdev->nd_fsdata)); - memcpy(&fsinfo->fs_super, &fsdev->nd_super, sizeof(fsdev->nd_super)); - snprintf(fsinfo->fs_dev, sizeof(fsinfo->fs_dev), - "%s", nmp->nm_vfs_mountp->mnt_stat.f_mntfromname); - - return (0); -} - -void -nandfs_inode_init(struct nandfs_inode *inode, uint16_t mode) -{ - struct timespec ts; - - vfs_timestamp(&ts); - - inode->i_blocks = 0; - inode->i_size = 0; - inode->i_ctime = ts.tv_sec; - inode->i_ctime_nsec = ts.tv_nsec; - inode->i_mtime = ts.tv_sec; - inode->i_mtime_nsec = ts.tv_nsec; - inode->i_mode = mode; - inode->i_links_count = 1; - if (S_ISDIR(mode)) - inode->i_links_count = 2; - inode->i_flags = 0; - - inode->i_special = 0; - memset(inode->i_db, 0, sizeof(inode->i_db)); - memset(inode->i_ib, 0, sizeof(inode->i_ib)); -} - -void -nandfs_inode_destroy(struct nandfs_inode *inode) -{ - - MPASS(inode->i_blocks == 0); - bzero(inode, sizeof(*inode)); -} - -int -nandfs_fs_full(struct nandfs_device *nffsdev) -{ - uint64_t space, bps; - - bps = nffsdev->nd_fsdata.f_blocks_per_segment; - space = (nffsdev->nd_clean_segs - 1) * bps; - - DPRINTF(BUF, ("%s: bufs:%jx space:%jx\n", __func__, - (uintmax_t)nffsdev->nd_dirty_bufs, (uintmax_t)space)); - - if (nffsdev->nd_dirty_bufs + (nffsdev->nd_segs_reserved * bps) >= space) - return (1); - - return (0); -} - -static int -_nandfs_dirty_buf(struct buf *bp, int dirty_meta, int force) -{ - struct nandfs_device *nffsdev; - struct nandfs_node *node; - uint64_t ino, bps; - - if (NANDFS_ISGATHERED(bp)) { - bqrelse(bp); - return (0); - } - if ((bp->b_flags & (B_MANAGED | B_DELWRI)) == (B_MANAGED | B_DELWRI)) { - bqrelse(bp); - return (0); - } - - node = VTON(bp->b_vp); - nffsdev = node->nn_nandfsdev; - DPRINTF(BUF, ("%s: buf:%p\n", __func__, bp)); - ino = node->nn_ino; - - if (nandfs_fs_full(nffsdev) && !NANDFS_SYS_NODE(ino) && !force) { - brelse(bp); - return (ENOSPC); - } - - bp->b_flags |= B_MANAGED; - bdwrite(bp); - - nandfs_dirty_bufs_increment(nffsdev); - - KASSERT((bp->b_vp), ("vp missing for bp")); - KASSERT((nandfs_vblk_get(bp) || ino == NANDFS_DAT_INO), - ("bp vblk is 0")); - - /* - * To maintain consistency of FS we need to force making - * meta buffers dirty, even if free space is low. - */ - if (dirty_meta && ino != NANDFS_GC_INO) - nandfs_bmap_dirty_blocks(VTON(bp->b_vp), bp, 1); - - bps = nffsdev->nd_fsdata.f_blocks_per_segment; - - if (nffsdev->nd_dirty_bufs >= (bps * nandfs_max_dirty_segs)) { - mtx_lock(&nffsdev->nd_sync_mtx); - if (nffsdev->nd_syncing == 0) { - DPRINTF(SYNC, ("%s: wakeup gc\n", __func__)); - nffsdev->nd_syncing = 1; - wakeup(&nffsdev->nd_syncing); - } - mtx_unlock(&nffsdev->nd_sync_mtx); - } - - return (0); -} - -int -nandfs_dirty_buf(struct buf *bp, int force) -{ - - return (_nandfs_dirty_buf(bp, 1, force)); -} - -int -nandfs_dirty_buf_meta(struct buf *bp, int force) -{ - - return (_nandfs_dirty_buf(bp, 0, force)); -} - -void -nandfs_undirty_buf_fsdev(struct nandfs_device *nffsdev, struct buf *bp) -{ - - BUF_ASSERT_HELD(bp); - - if (bp->b_flags & B_DELWRI) { - bp->b_flags &= ~(B_DELWRI|B_MANAGED); - nandfs_dirty_bufs_decrement(nffsdev); - } - /* - * Since it is now being written, we can clear its deferred write flag. - */ - bp->b_flags &= ~B_DEFERRED; - - brelse(bp); -} - -void -nandfs_undirty_buf(struct buf *bp) -{ - struct nandfs_node *node; - - node = VTON(bp->b_vp); - - nandfs_undirty_buf_fsdev(node->nn_nandfsdev, bp); -} - -void -nandfs_vblk_set(struct buf *bp, nandfs_daddr_t blocknr) -{ - - nandfs_daddr_t *vblk = (nandfs_daddr_t *)(&bp->b_fsprivate1); - *vblk = blocknr; -} - -nandfs_daddr_t -nandfs_vblk_get(struct buf *bp) -{ - - nandfs_daddr_t *vblk = (nandfs_daddr_t *)(&bp->b_fsprivate1); - return (*vblk); -} - -void -nandfs_buf_set(struct buf *bp, uint32_t bits) -{ - uintptr_t flags; - - flags = (uintptr_t)bp->b_fsprivate3; - flags |= (uintptr_t)bits; - bp->b_fsprivate3 = (void *)flags; -} - -void -nandfs_buf_clear(struct buf *bp, uint32_t bits) -{ - uintptr_t flags; - - flags = (uintptr_t)bp->b_fsprivate3; - flags &= ~(uintptr_t)bits; - bp->b_fsprivate3 = (void *)flags; -} - -int -nandfs_buf_check(struct buf *bp, uint32_t bits) -{ - uintptr_t flags; - - flags = (uintptr_t)bp->b_fsprivate3; - if (flags & bits) - return (1); - return (0); -} - -int -nandfs_erase(struct nandfs_device *fsdev, off_t offset, size_t size) -{ - DPRINTF(BLOCK, ("%s: performing erase at offset %jx size %zx\n", - __func__, offset, size)); - - MPASS(size % fsdev->nd_erasesize == 0); - - return (g_delete_data(fsdev->nd_gconsumer, offset, size)); -} - -int -nandfs_vop_islocked(struct vnode *vp) -{ - int islocked; - - islocked = VOP_ISLOCKED(vp); - return (islocked == LK_EXCLUSIVE || islocked == LK_SHARED); -} - -nandfs_daddr_t -nandfs_block_to_dblock(struct nandfs_device *fsdev, nandfs_lbn_t block) -{ - - return (btodb(block * fsdev->nd_blocksize)); -} diff --git a/sys/fs/nandfs/nandfs_subr.h b/sys/fs/nandfs/nandfs_subr.h deleted file mode 100644 index 36c2c9dc2ff2..000000000000 --- a/sys/fs/nandfs/nandfs_subr.h +++ /dev/null @@ -1,240 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf - * Copyright (c) 2008, 2009 Reinoud Zandijk - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * From: NetBSD: nilfs_subr.h,v 1.1 2009/07/18 16:31:42 reinoud - * - * $FreeBSD$ - */ - -#ifndef _FS_NANDFS_NANDFS_SUBR_H_ -#define _FS_NANDFS_NANDFS_SUBR_H_ - -struct nandfs_mdt; - -struct nandfs_alloc_request -{ - uint64_t entrynum; - struct buf *bp_desc; - struct buf *bp_bitmap; - struct buf *bp_entry; -}; - -/* Segment creation */ -void nandfs_wakeup_wait_sync(struct nandfs_device *, int); -int nandfs_segment_constructor(struct nandfsmount *, int); -int nandfs_sync_file(struct vnode *); - -/* Basic calculators */ -uint64_t nandfs_get_segnum_of_block(struct nandfs_device *, nandfs_daddr_t); -void nandfs_get_segment_range(struct nandfs_device *, uint64_t, uint64_t *, - uint64_t *); -void nandfs_calc_mdt_consts(struct nandfs_device *, struct nandfs_mdt *, int); - -/* Log reading / volume helpers */ -int nandfs_search_super_root(struct nandfs_device *); - -/* Reading */ -int nandfs_dev_bread(struct nandfs_device *, nandfs_daddr_t, struct ucred *, - int, struct buf **); -int nandfs_bread(struct nandfs_node *, nandfs_lbn_t, struct ucred *, int, - struct buf **); -int nandfs_bread_meta(struct nandfs_node *, nandfs_lbn_t, struct ucred *, int, - struct buf **); -int nandfs_bdestroy(struct nandfs_node *, nandfs_daddr_t); -int nandfs_bcreate(struct nandfs_node *, nandfs_lbn_t, struct ucred *, int, - struct buf **); -int nandfs_bcreate_meta(struct nandfs_node *, nandfs_lbn_t, struct ucred *, - int, struct buf **); -int nandfs_bread_create(struct nandfs_node *, nandfs_lbn_t, struct ucred *, - int, struct buf **); - -/* vtop operations */ -int nandfs_vtop(struct nandfs_node *, nandfs_daddr_t, nandfs_daddr_t *); - -/* Node action implementators */ -int nandfs_vinit(struct vnode *, uint64_t); -int nandfs_get_node(struct nandfsmount *, uint64_t, struct nandfs_node **); -int nandfs_get_node_raw(struct nandfs_device *, struct nandfsmount *, uint64_t, - struct nandfs_inode *, struct nandfs_node **); -void nandfs_dispose_node(struct nandfs_node **); - -void nandfs_itimes(struct vnode *); -int nandfs_lookup_name_in_dir(struct vnode *, const char *, int, uint64_t *, - int *, uint64_t *); -int nandfs_create_node(struct vnode *, struct vnode **, struct vattr *, - struct componentname *); -void nandfs_delete_node(struct nandfs_node *); - -int nandfs_chsize(struct vnode *, u_quad_t, struct ucred *); -int nandfs_dir_detach(struct nandfsmount *, struct nandfs_node *, - struct nandfs_node *, struct componentname *); -int nandfs_dir_attach(struct nandfsmount *, struct nandfs_node *, - struct nandfs_node *, struct vattr *, struct componentname *); - -int nandfs_dirty_buf(struct buf *, int); -int nandfs_dirty_buf_meta(struct buf *, int); -int nandfs_fs_full(struct nandfs_device *); -void nandfs_undirty_buf_fsdev(struct nandfs_device *, struct buf *); -void nandfs_undirty_buf(struct buf *); - -void nandfs_clear_buf(struct buf *); -void nandfs_buf_set(struct buf *, uint32_t); -void nandfs_buf_clear(struct buf *, uint32_t); -int nandfs_buf_check(struct buf *, uint32_t); - -int nandfs_find_free_entry(struct nandfs_mdt *, struct nandfs_node *, - struct nandfs_alloc_request *); -int nandfs_find_entry(struct nandfs_mdt *, struct nandfs_node *, - struct nandfs_alloc_request *); -int nandfs_alloc_entry(struct nandfs_mdt *, struct nandfs_alloc_request *); -void nandfs_abort_entry(struct nandfs_alloc_request *); -int nandfs_free_entry(struct nandfs_mdt *, struct nandfs_alloc_request *); -int nandfs_get_entry_block(struct nandfs_mdt *, struct nandfs_node *, - struct nandfs_alloc_request *, uint32_t *, int); - -/* Inode management. */ -int nandfs_node_create(struct nandfsmount *, struct nandfs_node **, uint16_t); -int nandfs_node_destroy(struct nandfs_node *); -int nandfs_node_update(struct nandfs_node *); -int nandfs_get_node_entry(struct nandfsmount *, struct nandfs_inode **, - uint64_t, struct buf **); -void nandfs_mdt_trans_blk(struct nandfs_mdt *, uint64_t, uint64_t *, - uint64_t *, nandfs_lbn_t *, uint32_t *); - -/* vblock management */ -void nandfs_mdt_trans(struct nandfs_mdt *, uint64_t, nandfs_lbn_t *, uint32_t *); -int nandfs_vblock_alloc(struct nandfs_device *, nandfs_daddr_t *); -int nandfs_vblock_end(struct nandfs_device *, nandfs_daddr_t); -int nandfs_vblock_assign(struct nandfs_device *, nandfs_daddr_t, - nandfs_lbn_t); -int nandfs_vblock_free(struct nandfs_device *, nandfs_daddr_t); - -/* Checkpoint management */ -int nandfs_get_checkpoint(struct nandfs_device *, struct nandfs_node *, - uint64_t); -int nandfs_set_checkpoint(struct nandfs_device *, struct nandfs_node *, - uint64_t, struct nandfs_inode *, uint64_t); - -/* Segment management */ -int nandfs_alloc_segment(struct nandfs_device *, uint64_t *); -int nandfs_update_segment(struct nandfs_device *, uint64_t, uint32_t); -int nandfs_free_segment(struct nandfs_device *, uint64_t); -int nandfs_clear_segment(struct nandfs_device *, uint64_t); -int nandfs_touch_segment(struct nandfs_device *, uint64_t); -int nandfs_markgc_segment(struct nandfs_device *, uint64_t); - -int nandfs_bmap_insert_block(struct nandfs_node *, nandfs_lbn_t, struct buf *); -int nandfs_bmap_update_block(struct nandfs_node *, struct buf *, nandfs_lbn_t); -int nandfs_bmap_update_dat(struct nandfs_node *, nandfs_daddr_t, struct buf *); -int nandfs_bmap_dirty_blocks(struct nandfs_node *, struct buf *, int); -int nandfs_bmap_truncate_mapping(struct nandfs_node *, nandfs_lbn_t, - nandfs_lbn_t); -int nandfs_bmap_lookup(struct nandfs_node *, nandfs_lbn_t, nandfs_daddr_t *); - -/* dirent */ -int nandfs_add_dirent(struct vnode *, uint64_t, char *, long, uint8_t); -int nandfs_remove_dirent(struct vnode *, struct nandfs_node *, - struct componentname *); -int nandfs_update_dirent(struct vnode *, struct nandfs_node *, - struct nandfs_node *); -int nandfs_init_dir(struct vnode *, uint64_t, uint64_t); -int nandfs_update_parent_dir(struct vnode *, uint64_t); - -void nandfs_vblk_set(struct buf *, nandfs_daddr_t); -nandfs_daddr_t nandfs_vblk_get(struct buf *); - -void nandfs_inode_init(struct nandfs_inode *, uint16_t); -void nandfs_inode_destroy(struct nandfs_inode *); - -/* ioctl */ -int nandfs_get_seg_stat(struct nandfs_device *, struct nandfs_seg_stat *); -int nandfs_chng_cpmode(struct nandfs_node *, struct nandfs_cpmode *); -int nandfs_get_cpinfo_ioctl(struct nandfs_node *, struct nandfs_argv *); -int nandfs_delete_cp(struct nandfs_node *, uint64_t start, uint64_t); -int nandfs_make_snap(struct nandfs_device *, uint64_t *); -int nandfs_delete_snap(struct nandfs_device *, uint64_t); -int nandfs_get_cpstat(struct nandfs_node *, struct nandfs_cpstat *); -int nandfs_get_segment_info_ioctl(struct nandfs_device *, struct nandfs_argv *); -int nandfs_get_dat_vinfo_ioctl(struct nandfs_device *, struct nandfs_argv *); -int nandfs_get_dat_bdescs_ioctl(struct nandfs_device *, struct nandfs_argv *); -int nandfs_get_fsinfo(struct nandfsmount *, struct nandfs_fsinfo *); - -int nandfs_get_cpinfo(struct nandfs_node *, uint64_t, uint16_t, - struct nandfs_cpinfo *, uint32_t, uint32_t *); - -nandfs_lbn_t nandfs_get_maxfilesize(struct nandfs_device *); - -int nandfs_write_superblock(struct nandfs_device *); - -extern int nandfs_sync_interval; -extern int nandfs_max_dirty_segs; -extern int nandfs_cps_between_sblocks; - -struct buf *nandfs_geteblk(int, int); - -void nandfs_dirty_bufs_increment(struct nandfs_device *); -void nandfs_dirty_bufs_decrement(struct nandfs_device *); - -int nandfs_start_cleaner(struct nandfs_device *); -int nandfs_stop_cleaner(struct nandfs_device *); - -int nandfs_segsum_valid(struct nandfs_segment_summary *); -int nandfs_load_segsum(struct nandfs_device *, nandfs_daddr_t, - struct nandfs_segment_summary *); -int nandfs_get_segment_info(struct nandfs_device *, struct nandfs_suinfo *, - uint32_t, uint64_t); -int nandfs_get_segment_info_filter(struct nandfs_device *, - struct nandfs_suinfo *, uint32_t, uint64_t, uint64_t *, uint32_t, uint32_t); -int nandfs_get_dat_vinfo(struct nandfs_device *, struct nandfs_vinfo *, - uint32_t); -int nandfs_get_dat_bdescs(struct nandfs_device *, struct nandfs_bdesc *, - uint32_t); - -#define NANDFS_VBLK_ASSIGNED 1 - -#define NANDFS_IS_INDIRECT(bp) ((bp)->b_lblkno < 0) - -int nandfs_erase(struct nandfs_device *, off_t, size_t); - -#define NANDFS_VOP_ISLOCKED(vp) nandfs_vop_islocked((vp)) -int nandfs_vop_islocked(struct vnode *vp); - -nandfs_daddr_t nandfs_block_to_dblock(struct nandfs_device *, nandfs_lbn_t); - -#define DEBUG_MODE -#if defined(DEBUG_MODE) -#define nandfs_error panic -#define nandfs_warning printf -#elif defined(TEST_MODE) -#define nandfs_error printf -#define nandfs_warning printf -#else -#define nandfs_error(...) -#define nandfs_warning(...) -#endif - -#endif /* !_FS_NANDFS_NANDFS_SUBR_H_ */ diff --git a/sys/fs/nandfs/nandfs_sufile.c b/sys/fs/nandfs/nandfs_sufile.c deleted file mode 100644 index 5276008de096..000000000000 --- a/sys/fs/nandfs/nandfs_sufile.c +++ /dev/null @@ -1,571 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/conf.h> -#include <sys/kernel.h> -#include <sys/lock.h> -#include <sys/malloc.h> -#include <sys/mount.h> -#include <sys/mutex.h> -#include <sys/namei.h> -#include <sys/sysctl.h> -#include <sys/vnode.h> -#include <sys/buf.h> -#include <sys/bio.h> - -#include <vm/vm.h> -#include <vm/vm_param.h> -#include <vm/vm_kern.h> -#include <vm/vm_page.h> - -#include <geom/geom.h> -#include <geom/geom_vfs.h> - -#include <fs/nandfs/nandfs_mount.h> -#include <fs/nandfs/nandfs.h> -#include <fs/nandfs/nandfs_subr.h> - -#define SU_USAGE_OFF(bp, offset) \ - ((struct nandfs_segment_usage *)((bp)->b_data + offset)) - -static int -nandfs_seg_usage_blk_offset(struct nandfs_device *fsdev, uint64_t seg, - uint64_t *blk, uint64_t *offset) -{ - uint64_t off; - uint16_t seg_size; - - seg_size = fsdev->nd_fsdata.f_segment_usage_size; - - off = roundup(sizeof(struct nandfs_sufile_header), seg_size); - off += (seg * seg_size); - - *blk = off / fsdev->nd_blocksize; - *offset = off % fsdev->nd_blocksize; - return (0); -} - -/* Alloc new segment */ -int -nandfs_alloc_segment(struct nandfs_device *fsdev, uint64_t *seg) -{ - struct nandfs_node *su_node; - struct nandfs_sufile_header *su_header; - struct nandfs_segment_usage *su_usage; - struct buf *bp_header, *bp; - uint64_t blk, vblk, offset, i, rest, nsegments; - uint16_t seg_size; - int error, found; - - seg_size = fsdev->nd_fsdata.f_segment_usage_size; - nsegments = fsdev->nd_fsdata.f_nsegments; - - su_node = fsdev->nd_su_node; - ASSERT_VOP_LOCKED(NTOV(su_node), __func__); - - /* Read header buffer */ - error = nandfs_bread(su_node, 0, NOCRED, 0, &bp_header); - if (error) { - brelse(bp_header); - return (error); - } - - su_header = (struct nandfs_sufile_header *)bp_header->b_data; - - /* Get last allocated segment */ - i = su_header->sh_last_alloc + 1; - - found = 0; - bp = NULL; - while (!found) { - nandfs_seg_usage_blk_offset(fsdev, i, &blk, &offset); - if(blk != 0) { - error = nandfs_bmap_lookup(su_node, blk, &vblk); - if (error) { - nandfs_error("%s: cannot find vblk for blk " - "blk:%jx\n", __func__, blk); - return (error); - } - if (vblk) - error = nandfs_bread(su_node, blk, NOCRED, 0, - &bp); - else - error = nandfs_bcreate(su_node, blk, NOCRED, 0, - &bp); - if (error) { - nandfs_error("%s: cannot create/read " - "vblk:%jx\n", __func__, vblk); - if (bp) - brelse(bp); - return (error); - } - - su_usage = SU_USAGE_OFF(bp, offset); - } else { - su_usage = SU_USAGE_OFF(bp_header, offset); - bp = bp_header; - } - - rest = (fsdev->nd_blocksize - offset) / seg_size; - /* Go through all su usage in block */ - while (rest) { - /* When last check start from beginning */ - if (i == nsegments) - break; - - if (!su_usage->su_flags) { - su_usage->su_flags = 1; - found = 1; - break; - } - su_usage++; - i++; - - /* If all checked return error */ - if (i == su_header->sh_last_alloc) { - DPRINTF(SEG, ("%s: cannot allocate segment \n", - __func__)); - brelse(bp_header); - if (blk != 0) - brelse(bp); - return (1); - } - rest--; - } - if (!found) { - /* Otherwise read another block */ - if (blk != 0) - brelse(bp); - if (i == nsegments) { - blk = 0; - i = 0; - } else - blk++; - offset = 0; - } - } - - if (found) { - *seg = i; - su_header->sh_last_alloc = i; - su_header->sh_ncleansegs--; - su_header->sh_ndirtysegs++; - - fsdev->nd_super.s_free_blocks_count = su_header->sh_ncleansegs * - fsdev->nd_fsdata.f_blocks_per_segment; - fsdev->nd_clean_segs--; - - /* - * It is mostly called from syncer() so we want to force - * making buf dirty. - */ - error = nandfs_dirty_buf(bp_header, 1); - if (error) { - if (bp && bp != bp_header) - brelse(bp); - return (error); - } - if (bp && bp != bp_header) - nandfs_dirty_buf(bp, 1); - - DPRINTF(SEG, ("%s: seg:%#jx\n", __func__, (uintmax_t)i)); - - return (0); - } - - DPRINTF(SEG, ("%s: failed\n", __func__)); - - return (1); -} - -/* - * Make buffer dirty, it will be updated soon but first it need to be - * gathered by syncer. - */ -int -nandfs_touch_segment(struct nandfs_device *fsdev, uint64_t seg) -{ - struct nandfs_node *su_node; - struct buf *bp; - uint64_t blk, offset; - int error; - - su_node = fsdev->nd_su_node; - ASSERT_VOP_LOCKED(NTOV(su_node), __func__); - - nandfs_seg_usage_blk_offset(fsdev, seg, &blk, &offset); - - error = nandfs_bread(su_node, blk, NOCRED, 0, &bp); - if (error) { - brelse(bp); - nandfs_error("%s: cannot preallocate new segment\n", __func__); - return (error); - } else - nandfs_dirty_buf(bp, 1); - - DPRINTF(SEG, ("%s: seg:%#jx\n", __func__, (uintmax_t)seg)); - return (error); -} - -/* Update block count of segment */ -int -nandfs_update_segment(struct nandfs_device *fsdev, uint64_t seg, uint32_t nblks) -{ - struct nandfs_node *su_node; - struct nandfs_segment_usage *su_usage; - struct buf *bp; - uint64_t blk, offset; - int error; - - su_node = fsdev->nd_su_node; - ASSERT_VOP_LOCKED(NTOV(su_node), __func__); - - nandfs_seg_usage_blk_offset(fsdev, seg, &blk, &offset); - - error = nandfs_bread(su_node, blk, NOCRED, 0, &bp); - if (error) { - nandfs_error("%s: read block:%jx to update\n", - __func__, blk); - brelse(bp); - return (error); - } - - su_usage = SU_USAGE_OFF(bp, offset); - su_usage->su_lastmod = fsdev->nd_ts.tv_sec; - su_usage->su_flags = NANDFS_SEGMENT_USAGE_DIRTY; - su_usage->su_nblocks += nblks; - - DPRINTF(SEG, ("%s: seg:%#jx inc:%#x cur:%#x\n", __func__, - (uintmax_t)seg, nblks, su_usage->su_nblocks)); - - nandfs_dirty_buf(bp, 1); - - return (0); -} - -/* Make segment free */ -int -nandfs_free_segment(struct nandfs_device *fsdev, uint64_t seg) -{ - struct nandfs_node *su_node; - struct nandfs_sufile_header *su_header; - struct nandfs_segment_usage *su_usage; - struct buf *bp_header, *bp; - uint64_t blk, offset; - int error; - - su_node = fsdev->nd_su_node; - ASSERT_VOP_LOCKED(NTOV(su_node), __func__); - - /* Read su header */ - error = nandfs_bread(su_node, 0, NOCRED, 0, &bp_header); - if (error) { - brelse(bp_header); - return (error); - } - - su_header = (struct nandfs_sufile_header *)bp_header->b_data; - nandfs_seg_usage_blk_offset(fsdev, seg, &blk, &offset); - - /* Read su usage block if other than su header block */ - if (blk != 0) { - error = nandfs_bread(su_node, blk, NOCRED, 0, &bp); - if (error) { - brelse(bp); - brelse(bp_header); - return (error); - } - } else - bp = bp_header; - - /* Reset su usage data */ - su_usage = SU_USAGE_OFF(bp, offset); - su_usage->su_lastmod = fsdev->nd_ts.tv_sec; - su_usage->su_nblocks = 0; - su_usage->su_flags = 0; - - /* Update clean/dirty counter in header */ - su_header->sh_ncleansegs++; - su_header->sh_ndirtysegs--; - - /* - * Make buffers dirty, called by cleaner - * so force dirty even if no much space left - * on device - */ - nandfs_dirty_buf(bp_header, 1); - if (bp != bp_header) - nandfs_dirty_buf(bp, 1); - - /* Update free block count */ - fsdev->nd_super.s_free_blocks_count = su_header->sh_ncleansegs * - fsdev->nd_fsdata.f_blocks_per_segment; - fsdev->nd_clean_segs++; - - DPRINTF(SEG, ("%s: seg:%#jx\n", __func__, (uintmax_t)seg)); - - return (0); -} - -static int -nandfs_bad_segment(struct nandfs_device *fsdev, uint64_t seg) -{ - struct nandfs_node *su_node; - struct nandfs_segment_usage *su_usage; - struct buf *bp; - uint64_t blk, offset; - int error; - - su_node = fsdev->nd_su_node; - ASSERT_VOP_LOCKED(NTOV(su_node), __func__); - - nandfs_seg_usage_blk_offset(fsdev, seg, &blk, &offset); - - error = nandfs_bread(su_node, blk, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - - su_usage = SU_USAGE_OFF(bp, offset); - su_usage->su_lastmod = fsdev->nd_ts.tv_sec; - su_usage->su_flags = NANDFS_SEGMENT_USAGE_ERROR; - - DPRINTF(SEG, ("%s: seg:%#jx\n", __func__, (uintmax_t)seg)); - - nandfs_dirty_buf(bp, 1); - - return (0); -} - -int -nandfs_markgc_segment(struct nandfs_device *fsdev, uint64_t seg) -{ - struct nandfs_node *su_node; - struct nandfs_segment_usage *su_usage; - struct buf *bp; - uint64_t blk, offset; - int error; - - su_node = fsdev->nd_su_node; - - VOP_LOCK(NTOV(su_node), LK_EXCLUSIVE); - - nandfs_seg_usage_blk_offset(fsdev, seg, &blk, &offset); - - error = nandfs_bread(su_node, blk, NOCRED, 0, &bp); - if (error) { - brelse(bp); - VOP_UNLOCK(NTOV(su_node), 0); - return (error); - } - - su_usage = SU_USAGE_OFF(bp, offset); - MPASS((su_usage->su_flags & NANDFS_SEGMENT_USAGE_GC) == 0); - su_usage->su_flags |= NANDFS_SEGMENT_USAGE_GC; - - brelse(bp); - VOP_UNLOCK(NTOV(su_node), 0); - - DPRINTF(SEG, ("%s: seg:%#jx\n", __func__, (uintmax_t)seg)); - - return (0); -} - -int -nandfs_clear_segment(struct nandfs_device *fsdev, uint64_t seg) -{ - uint64_t offset, segsize; - uint32_t bps, bsize; - int error = 0; - - bps = fsdev->nd_fsdata.f_blocks_per_segment; - bsize = fsdev->nd_blocksize; - segsize = bsize * bps; - nandfs_get_segment_range(fsdev, seg, &offset, NULL); - offset *= bsize; - - DPRINTF(SEG, ("%s: seg:%#jx\n", __func__, (uintmax_t)seg)); - - /* Erase it and mark it bad when fail */ - if (nandfs_erase(fsdev, offset, segsize)) - error = nandfs_bad_segment(fsdev, seg); - - if (error) - return (error); - - /* Mark it free */ - error = nandfs_free_segment(fsdev, seg); - - return (error); -} - -int -nandfs_get_seg_stat(struct nandfs_device *nandfsdev, - struct nandfs_seg_stat *nss) -{ - struct nandfs_sufile_header *suhdr; - struct nandfs_node *su_node; - struct buf *bp; - int err; - - su_node = nandfsdev->nd_su_node; - - NANDFS_WRITELOCK(nandfsdev); - VOP_LOCK(NTOV(su_node), LK_SHARED); - err = nandfs_bread(nandfsdev->nd_su_node, 0, NOCRED, 0, &bp); - if (err) { - brelse(bp); - VOP_UNLOCK(NTOV(su_node), 0); - NANDFS_WRITEUNLOCK(nandfsdev); - return (-1); - } - - suhdr = (struct nandfs_sufile_header *)bp->b_data; - nss->nss_nsegs = nandfsdev->nd_fsdata.f_nsegments; - nss->nss_ncleansegs = suhdr->sh_ncleansegs; - nss->nss_ndirtysegs = suhdr->sh_ndirtysegs; - nss->nss_ctime = 0; - nss->nss_nongc_ctime = nandfsdev->nd_ts.tv_sec; - nss->nss_prot_seq = nandfsdev->nd_seg_sequence; - - brelse(bp); - VOP_UNLOCK(NTOV(su_node), 0); - - NANDFS_WRITEUNLOCK(nandfsdev); - - return (0); -} - -int -nandfs_get_segment_info_ioctl(struct nandfs_device *fsdev, - struct nandfs_argv *nargv) -{ - struct nandfs_suinfo *nsi; - int error; - - if (nargv->nv_nmembs > NANDFS_SEGMENTS_MAX) - return (EINVAL); - - nsi = malloc(sizeof(struct nandfs_suinfo) * nargv->nv_nmembs, - M_NANDFSTEMP, M_WAITOK | M_ZERO); - - error = nandfs_get_segment_info(fsdev, nsi, nargv->nv_nmembs, - nargv->nv_index); - - if (error == 0) - error = copyout(nsi, (void *)(uintptr_t)nargv->nv_base, - sizeof(struct nandfs_suinfo) * nargv->nv_nmembs); - - free(nsi, M_NANDFSTEMP); - return (error); -} - -int -nandfs_get_segment_info(struct nandfs_device *fsdev, struct nandfs_suinfo *nsi, - uint32_t nmembs, uint64_t segment) -{ - - return (nandfs_get_segment_info_filter(fsdev, nsi, nmembs, segment, - NULL, 0, 0)); -} - -int -nandfs_get_segment_info_filter(struct nandfs_device *fsdev, - struct nandfs_suinfo *nsi, uint32_t nmembs, uint64_t segment, - uint64_t *nsegs, uint32_t filter, uint32_t nfilter) -{ - struct nandfs_segment_usage *su; - struct nandfs_node *su_node; - struct buf *bp; - uint64_t curr, blocknr, blockoff, i; - uint32_t flags; - int err = 0; - - curr = ~(0); - - lockmgr(&fsdev->nd_seg_const, LK_EXCLUSIVE, NULL); - su_node = fsdev->nd_su_node; - - VOP_LOCK(NTOV(su_node), LK_SHARED); - - bp = NULL; - if (nsegs != NULL) - *nsegs = 0; - for (i = 0; i < nmembs; segment++) { - if (segment == fsdev->nd_fsdata.f_nsegments) - break; - - nandfs_seg_usage_blk_offset(fsdev, segment, &blocknr, - &blockoff); - - if (i == 0 || curr != blocknr) { - if (bp != NULL) - brelse(bp); - err = nandfs_bread(su_node, blocknr, NOCRED, - 0, &bp); - if (err) { - goto out; - } - curr = blocknr; - } - - su = SU_USAGE_OFF(bp, blockoff); - flags = su->su_flags; - if (segment == fsdev->nd_seg_num || - segment == fsdev->nd_next_seg_num) - flags |= NANDFS_SEGMENT_USAGE_ACTIVE; - - if (nfilter != 0 && (flags & nfilter) != 0) - continue; - if (filter != 0 && (flags & filter) == 0) - continue; - - nsi->nsi_num = segment; - nsi->nsi_lastmod = su->su_lastmod; - nsi->nsi_blocks = su->su_nblocks; - nsi->nsi_flags = flags; - nsi++; - i++; - if (nsegs != NULL) - (*nsegs)++; - } - -out: - if (bp != NULL) - brelse(bp); - VOP_UNLOCK(NTOV(su_node), 0); - lockmgr(&fsdev->nd_seg_const, LK_RELEASE, NULL); - - return (err); -} diff --git a/sys/fs/nandfs/nandfs_vfsops.c b/sys/fs/nandfs/nandfs_vfsops.c deleted file mode 100644 index f703044728ef..000000000000 --- a/sys/fs/nandfs/nandfs_vfsops.c +++ /dev/null @@ -1,1601 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf - * Copyright (c) 2008, 2009 Reinoud Zandijk - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * From: NetBSD: nilfs_vfsops.c,v 1.1 2009/07/18 16:31:42 reinoud Exp - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/fcntl.h> -#include <sys/gsb_crc32.h> -#include <sys/kernel.h> -#include <sys/lock.h> -#include <sys/malloc.h> -#include <sys/mount.h> -#include <sys/namei.h> -#include <sys/proc.h> -#include <sys/priv.h> -#include <sys/vnode.h> -#include <sys/buf.h> -#include <sys/sysctl.h> -#include <sys/libkern.h> - -#include <geom/geom.h> -#include <geom/geom_vfs.h> - -#include <machine/_inttypes.h> - -#include <fs/nandfs/nandfs_mount.h> -#include <fs/nandfs/nandfs.h> -#include <fs/nandfs/nandfs_subr.h> - -static MALLOC_DEFINE(M_NANDFSMNT, "nandfs_mount", "NANDFS mount structure"); - -#define NANDFS_SET_SYSTEMFILE(vp) { \ - (vp)->v_vflag |= VV_SYSTEM; \ - vref(vp); \ - vput(vp); } - -#define NANDFS_UNSET_SYSTEMFILE(vp) { \ - VOP_LOCK(vp, LK_EXCLUSIVE); \ - MPASS(vp->v_bufobj.bo_dirty.bv_cnt == 0); \ - (vp)->v_vflag &= ~VV_SYSTEM; \ - vgone(vp); \ - vput(vp); } - -/* Globals */ -struct _nandfs_devices nandfs_devices; - -/* Parameters */ -int nandfs_verbose = 0; - -static void -nandfs_tunable_init(void *arg) -{ - - TUNABLE_INT_FETCH("vfs.nandfs.verbose", &nandfs_verbose); -} -SYSINIT(nandfs_tunables, SI_SUB_VFS, SI_ORDER_ANY, nandfs_tunable_init, NULL); - -static SYSCTL_NODE(_vfs, OID_AUTO, nandfs, CTLFLAG_RD, 0, "NAND filesystem"); -static SYSCTL_NODE(_vfs_nandfs, OID_AUTO, mount, CTLFLAG_RD, 0, - "NANDFS mountpoints"); -SYSCTL_INT(_vfs_nandfs, OID_AUTO, verbose, CTLFLAG_RW, &nandfs_verbose, 0, ""); - -#define NANDFS_CONSTR_INTERVAL 5 -int nandfs_sync_interval = NANDFS_CONSTR_INTERVAL; /* sync every 5 seconds */ -SYSCTL_UINT(_vfs_nandfs, OID_AUTO, sync_interval, CTLFLAG_RW, - &nandfs_sync_interval, 0, ""); - -#define NANDFS_MAX_DIRTY_SEGS 5 -int nandfs_max_dirty_segs = NANDFS_MAX_DIRTY_SEGS; /* sync when 5 dirty seg */ -SYSCTL_UINT(_vfs_nandfs, OID_AUTO, max_dirty_segs, CTLFLAG_RW, - &nandfs_max_dirty_segs, 0, ""); - -#define NANDFS_CPS_BETWEEN_SBLOCKS 5 -int nandfs_cps_between_sblocks = NANDFS_CPS_BETWEEN_SBLOCKS; /* write superblock every 5 checkpoints */ -SYSCTL_UINT(_vfs_nandfs, OID_AUTO, cps_between_sblocks, CTLFLAG_RW, - &nandfs_cps_between_sblocks, 0, ""); - -#define NANDFS_CLEANER_ENABLE 1 -int nandfs_cleaner_enable = NANDFS_CLEANER_ENABLE; -SYSCTL_UINT(_vfs_nandfs, OID_AUTO, cleaner_enable, CTLFLAG_RW, - &nandfs_cleaner_enable, 0, ""); - -#define NANDFS_CLEANER_INTERVAL 5 -int nandfs_cleaner_interval = NANDFS_CLEANER_INTERVAL; -SYSCTL_UINT(_vfs_nandfs, OID_AUTO, cleaner_interval, CTLFLAG_RW, - &nandfs_cleaner_interval, 0, ""); - -#define NANDFS_CLEANER_SEGMENTS 5 -int nandfs_cleaner_segments = NANDFS_CLEANER_SEGMENTS; -SYSCTL_UINT(_vfs_nandfs, OID_AUTO, cleaner_segments, CTLFLAG_RW, - &nandfs_cleaner_segments, 0, ""); - -static int nandfs_mountfs(struct vnode *devvp, struct mount *mp); -static vfs_mount_t nandfs_mount; -static vfs_root_t nandfs_root; -static vfs_statfs_t nandfs_statfs; -static vfs_unmount_t nandfs_unmount; -static vfs_vget_t nandfs_vget; -static vfs_sync_t nandfs_sync; -static const char *nandfs_opts[] = { - "snap", "from", "noatime", NULL -}; - -/* System nodes */ -static int -nandfs_create_system_nodes(struct nandfs_device *nandfsdev) -{ - int error; - - error = nandfs_get_node_raw(nandfsdev, NULL, NANDFS_DAT_INO, - &nandfsdev->nd_super_root.sr_dat, &nandfsdev->nd_dat_node); - if (error) - goto errorout; - - error = nandfs_get_node_raw(nandfsdev, NULL, NANDFS_CPFILE_INO, - &nandfsdev->nd_super_root.sr_cpfile, &nandfsdev->nd_cp_node); - if (error) - goto errorout; - - error = nandfs_get_node_raw(nandfsdev, NULL, NANDFS_SUFILE_INO, - &nandfsdev->nd_super_root.sr_sufile, &nandfsdev->nd_su_node); - if (error) - goto errorout; - - error = nandfs_get_node_raw(nandfsdev, NULL, NANDFS_GC_INO, - NULL, &nandfsdev->nd_gc_node); - if (error) - goto errorout; - - NANDFS_SET_SYSTEMFILE(NTOV(nandfsdev->nd_dat_node)); - NANDFS_SET_SYSTEMFILE(NTOV(nandfsdev->nd_cp_node)); - NANDFS_SET_SYSTEMFILE(NTOV(nandfsdev->nd_su_node)); - NANDFS_SET_SYSTEMFILE(NTOV(nandfsdev->nd_gc_node)); - - DPRINTF(VOLUMES, ("System vnodes: dat: %p cp: %p su: %p\n", - NTOV(nandfsdev->nd_dat_node), NTOV(nandfsdev->nd_cp_node), - NTOV(nandfsdev->nd_su_node))); - return (0); - -errorout: - nandfs_dispose_node(&nandfsdev->nd_gc_node); - nandfs_dispose_node(&nandfsdev->nd_dat_node); - nandfs_dispose_node(&nandfsdev->nd_cp_node); - nandfs_dispose_node(&nandfsdev->nd_su_node); - - return (error); -} - -static void -nandfs_release_system_nodes(struct nandfs_device *nandfsdev) -{ - - if (!nandfsdev) - return; - if (nandfsdev->nd_refcnt > 0) - return; - - if (nandfsdev->nd_gc_node) - NANDFS_UNSET_SYSTEMFILE(NTOV(nandfsdev->nd_gc_node)); - if (nandfsdev->nd_dat_node) - NANDFS_UNSET_SYSTEMFILE(NTOV(nandfsdev->nd_dat_node)); - if (nandfsdev->nd_cp_node) - NANDFS_UNSET_SYSTEMFILE(NTOV(nandfsdev->nd_cp_node)); - if (nandfsdev->nd_su_node) - NANDFS_UNSET_SYSTEMFILE(NTOV(nandfsdev->nd_su_node)); -} - -static int -nandfs_check_fsdata_crc(struct nandfs_fsdata *fsdata) -{ - uint32_t fsdata_crc, comp_crc; - - if (fsdata->f_magic != NANDFS_FSDATA_MAGIC) - return (0); - - /* Preserve CRC */ - fsdata_crc = fsdata->f_sum; - - /* Calculate */ - fsdata->f_sum = (0); - comp_crc = crc32((uint8_t *)fsdata, fsdata->f_bytes); - - /* Restore */ - fsdata->f_sum = fsdata_crc; - - /* Check CRC */ - return (fsdata_crc == comp_crc); -} - -static int -nandfs_check_superblock_crc(struct nandfs_fsdata *fsdata, - struct nandfs_super_block *super) -{ - uint32_t super_crc, comp_crc; - - /* Check super block magic */ - if (super->s_magic != NANDFS_SUPER_MAGIC) - return (0); - - /* Preserve CRC */ - super_crc = super->s_sum; - - /* Calculate */ - super->s_sum = (0); - comp_crc = crc32((uint8_t *)super, fsdata->f_sbbytes); - - /* Restore */ - super->s_sum = super_crc; - - /* Check CRC */ - return (super_crc == comp_crc); -} - -static void -nandfs_calc_superblock_crc(struct nandfs_fsdata *fsdata, - struct nandfs_super_block *super) -{ - uint32_t comp_crc; - - /* Calculate */ - super->s_sum = 0; - comp_crc = crc32((uint8_t *)super, fsdata->f_sbbytes); - - /* Restore */ - super->s_sum = comp_crc; -} - -static int -nandfs_is_empty(u_char *area, int size) -{ - int i; - - for (i = 0; i < size; i++) - if (area[i] != 0xff) - return (0); - - return (1); -} - -static __inline int -nandfs_sblocks_in_esize(struct nandfs_device *fsdev) -{ - - return ((fsdev->nd_erasesize - NANDFS_SBLOCK_OFFSET_BYTES) / - sizeof(struct nandfs_super_block)); -} - -static __inline int -nandfs_max_sblocks(struct nandfs_device *fsdev) -{ - - return (NANDFS_NFSAREAS * nandfs_sblocks_in_esize(fsdev)); -} - -static __inline int -nandfs_sblocks_in_block(struct nandfs_device *fsdev) -{ - - return (fsdev->nd_devblocksize / sizeof(struct nandfs_super_block)); -} - -#if 0 -static __inline int -nandfs_sblocks_in_first_block(struct nandfs_device *fsdev) -{ - int n; - - n = nandfs_sblocks_in_block(fsdev) - - NANDFS_SBLOCK_OFFSET_BYTES / sizeof(struct nandfs_super_block); - if (n < 0) - n = 0; - - return (n); -} -#endif - -static int -nandfs_write_superblock_at(struct nandfs_device *fsdev, - struct nandfs_fsarea *fstp) -{ - struct nandfs_super_block *super, *supert; - struct buf *bp; - int sb_per_sector, sbs_in_fsd, read_block; - int index, pos, error; - off_t offset; - - DPRINTF(SYNC, ("%s: last_used %d nandfs_sblocks_in_esize %d\n", - __func__, fstp->last_used, nandfs_sblocks_in_esize(fsdev))); - if (fstp->last_used == nandfs_sblocks_in_esize(fsdev) - 1) - index = 0; - else - index = fstp->last_used + 1; - - super = &fsdev->nd_super; - supert = NULL; - - sb_per_sector = nandfs_sblocks_in_block(fsdev); - sbs_in_fsd = sizeof(struct nandfs_fsdata) / - sizeof(struct nandfs_super_block); - index += sbs_in_fsd; - offset = fstp->offset; - - DPRINTF(SYNC, ("%s: offset %#jx s_last_pseg %#jx s_last_cno %#jx " - "s_last_seq %#jx wtime %jd index %d\n", __func__, offset, - super->s_last_pseg, super->s_last_cno, super->s_last_seq, - super->s_wtime, index)); - - read_block = btodb(offset + rounddown(index, sb_per_sector) * - sizeof(struct nandfs_super_block)); - - DPRINTF(SYNC, ("%s: read_block %#x\n", __func__, read_block)); - - if (index == sbs_in_fsd) { - error = nandfs_erase(fsdev, offset, fsdev->nd_erasesize); - if (error) - return (error); - - error = bread(fsdev->nd_devvp, btodb(offset), - fsdev->nd_devblocksize, NOCRED, &bp); - if (error) { - printf("NANDFS: couldn't read initial data: %d\n", - error); - brelse(bp); - return (error); - } - memcpy(bp->b_data, &fsdev->nd_fsdata, sizeof(fsdev->nd_fsdata)); - /* - * 0xff-out the rest. This bp could be cached, so potentially - * b_data contains stale super blocks. - * - * We don't mind cached bp since most of the time we just add - * super blocks to already 0xff-out b_data and don't need to - * perform actual read. - */ - if (fsdev->nd_devblocksize > sizeof(fsdev->nd_fsdata)) - memset(bp->b_data + sizeof(fsdev->nd_fsdata), 0xff, - fsdev->nd_devblocksize - sizeof(fsdev->nd_fsdata)); - error = bwrite(bp); - if (error) { - printf("NANDFS: cannot rewrite initial data at %jx\n", - offset); - return (error); - } - } - - error = bread(fsdev->nd_devvp, read_block, fsdev->nd_devblocksize, - NOCRED, &bp); - if (error) { - brelse(bp); - return (error); - } - - supert = (struct nandfs_super_block *)(bp->b_data); - pos = index % sb_per_sector; - - DPRINTF(SYNC, ("%s: storing at %d\n", __func__, pos)); - memcpy(&supert[pos], super, sizeof(struct nandfs_super_block)); - - /* - * See comment above in code that performs erase. - */ - if (pos == 0) - memset(&supert[1], 0xff, - (sb_per_sector - 1) * sizeof(struct nandfs_super_block)); - - error = bwrite(bp); - if (error) { - printf("NANDFS: cannot update superblock at %jx\n", offset); - return (error); - } - - DPRINTF(SYNC, ("%s: fstp->last_used %d -> %d\n", __func__, - fstp->last_used, index - sbs_in_fsd)); - fstp->last_used = index - sbs_in_fsd; - - return (0); -} - -int -nandfs_write_superblock(struct nandfs_device *fsdev) -{ - struct nandfs_super_block *super; - struct timespec ts; - int error; - int i, j; - - vfs_timestamp(&ts); - - super = &fsdev->nd_super; - - super->s_last_pseg = fsdev->nd_last_pseg; - super->s_last_cno = fsdev->nd_last_cno; - super->s_last_seq = fsdev->nd_seg_sequence; - super->s_wtime = ts.tv_sec; - - nandfs_calc_superblock_crc(&fsdev->nd_fsdata, super); - - error = 0; - for (i = 0, j = fsdev->nd_last_fsarea; i < NANDFS_NFSAREAS; - i++, j = (j + 1 % NANDFS_NFSAREAS)) { - if (fsdev->nd_fsarea[j].flags & NANDFS_FSSTOR_FAILED) { - DPRINTF(SYNC, ("%s: skipping %d\n", __func__, j)); - continue; - } - error = nandfs_write_superblock_at(fsdev, &fsdev->nd_fsarea[j]); - if (error) { - printf("NANDFS: writing superblock at offset %d failed:" - "%d\n", j * fsdev->nd_erasesize, error); - fsdev->nd_fsarea[j].flags |= NANDFS_FSSTOR_FAILED; - } else - break; - } - - if (i == NANDFS_NFSAREAS) { - printf("NANDFS: superblock was not written\n"); - /* - * TODO: switch to read-only? - */ - return (error); - } else - fsdev->nd_last_fsarea = (j + 1) % NANDFS_NFSAREAS; - - return (0); -} - -static int -nandfs_select_fsdata(struct nandfs_device *fsdev, - struct nandfs_fsdata *fsdatat, struct nandfs_fsdata **fsdata, int nfsds) -{ - int i; - - *fsdata = NULL; - for (i = 0; i < nfsds; i++) { - DPRINTF(VOLUMES, ("%s: i %d f_magic %x f_crc %x\n", __func__, - i, fsdatat[i].f_magic, fsdatat[i].f_sum)); - if (!nandfs_check_fsdata_crc(&fsdatat[i])) - continue; - *fsdata = &fsdatat[i]; - break; - } - - return (*fsdata != NULL ? 0 : EINVAL); -} - -static int -nandfs_select_sb(struct nandfs_device *fsdev, - struct nandfs_super_block *supert, struct nandfs_super_block **super, - int nsbs) -{ - int i; - - *super = NULL; - for (i = 0; i < nsbs; i++) { - if (!nandfs_check_superblock_crc(&fsdev->nd_fsdata, &supert[i])) - continue; - DPRINTF(SYNC, ("%s: i %d s_last_cno %jx s_magic %x " - "s_wtime %jd\n", __func__, i, supert[i].s_last_cno, - supert[i].s_magic, supert[i].s_wtime)); - if (*super == NULL || supert[i].s_last_cno > - (*super)->s_last_cno) - *super = &supert[i]; - } - - return (*super != NULL ? 0 : EINVAL); -} - -static int -nandfs_read_structures_at(struct nandfs_device *fsdev, - struct nandfs_fsarea *fstp, struct nandfs_fsdata *fsdata, - struct nandfs_super_block *super) -{ - struct nandfs_super_block *tsuper, *tsuperd; - struct buf *bp; - int error, read_size; - int i; - int offset; - - offset = fstp->offset; - - if (fsdev->nd_erasesize > MAXBSIZE) - read_size = MAXBSIZE; - else - read_size = fsdev->nd_erasesize; - - error = bread(fsdev->nd_devvp, btodb(offset), read_size, NOCRED, &bp); - if (error) { - printf("couldn't read: %d\n", error); - brelse(bp); - fstp->flags |= NANDFS_FSSTOR_FAILED; - return (error); - } - - tsuper = super; - - memcpy(fsdata, bp->b_data, sizeof(struct nandfs_fsdata)); - memcpy(tsuper, (bp->b_data + sizeof(struct nandfs_fsdata)), - read_size - sizeof(struct nandfs_fsdata)); - brelse(bp); - - tsuper += (read_size - sizeof(struct nandfs_fsdata)) / - sizeof(struct nandfs_super_block); - - for (i = 1; i < fsdev->nd_erasesize / read_size; i++) { - error = bread(fsdev->nd_devvp, btodb(offset + i * read_size), - read_size, NOCRED, &bp); - if (error) { - printf("couldn't read: %d\n", error); - brelse(bp); - fstp->flags |= NANDFS_FSSTOR_FAILED; - return (error); - } - memcpy(tsuper, bp->b_data, read_size); - tsuper += read_size / sizeof(struct nandfs_super_block); - brelse(bp); - } - - tsuper -= 1; - fstp->last_used = nandfs_sblocks_in_esize(fsdev) - 1; - for (tsuperd = super - 1; (tsuper != tsuperd); tsuper -= 1) { - if (nandfs_is_empty((u_char *)tsuper, sizeof(*tsuper))) - fstp->last_used--; - else - break; - } - - DPRINTF(VOLUMES, ("%s: last_used %d\n", __func__, fstp->last_used)); - - return (0); -} - -static int -nandfs_read_structures(struct nandfs_device *fsdev) -{ - struct nandfs_fsdata *fsdata, *fsdatat; - struct nandfs_super_block *sblocks, *ssblock; - u_int nsbs, nfsds, i; - int error = 0; - int nrsbs; - - nfsds = NANDFS_NFSAREAS; - nsbs = nandfs_max_sblocks(fsdev); - - fsdatat = malloc(sizeof(struct nandfs_fsdata) * nfsds, M_NANDFSTEMP, - M_WAITOK | M_ZERO); - sblocks = malloc(sizeof(struct nandfs_super_block) * nsbs, M_NANDFSTEMP, - M_WAITOK | M_ZERO); - - nrsbs = 0; - for (i = 0; i < NANDFS_NFSAREAS; i++) { - fsdev->nd_fsarea[i].offset = i * fsdev->nd_erasesize; - error = nandfs_read_structures_at(fsdev, &fsdev->nd_fsarea[i], - &fsdatat[i], sblocks + nrsbs); - if (error) - continue; - nrsbs += (fsdev->nd_fsarea[i].last_used + 1); - if (fsdev->nd_fsarea[fsdev->nd_last_fsarea].last_used > - fsdev->nd_fsarea[i].last_used) - fsdev->nd_last_fsarea = i; - } - - if (nrsbs == 0) { - printf("nandfs: no valid superblocks found\n"); - error = EINVAL; - goto out; - } - - error = nandfs_select_fsdata(fsdev, fsdatat, &fsdata, nfsds); - if (error) - goto out; - memcpy(&fsdev->nd_fsdata, fsdata, sizeof(struct nandfs_fsdata)); - - error = nandfs_select_sb(fsdev, sblocks, &ssblock, nsbs); - if (error) - goto out; - - memcpy(&fsdev->nd_super, ssblock, sizeof(struct nandfs_super_block)); -out: - free(fsdatat, M_NANDFSTEMP); - free(sblocks, M_NANDFSTEMP); - - if (error == 0) - DPRINTF(VOLUMES, ("%s: selected sb with w_time %jd " - "last_pseg %#jx\n", __func__, fsdev->nd_super.s_wtime, - fsdev->nd_super.s_last_pseg)); - - return (error); -} - -static void -nandfs_unmount_base(struct nandfs_device *nandfsdev) -{ - int error; - - if (!nandfsdev) - return; - - /* Remove all our information */ - error = vinvalbuf(nandfsdev->nd_devvp, V_SAVE, 0, 0); - if (error) { - /* - * Flushing buffers failed when fs was umounting, can't do - * much now, just printf error and continue with umount. - */ - nandfs_error("%s(): error:%d when umounting FS\n", - __func__, error); - } - - /* Release the device's system nodes */ - nandfs_release_system_nodes(nandfsdev); -} - -static void -nandfs_get_ncleanseg(struct nandfs_device *nandfsdev) -{ - struct nandfs_seg_stat nss; - - nandfs_get_seg_stat(nandfsdev, &nss); - nandfsdev->nd_clean_segs = nss.nss_ncleansegs; - DPRINTF(VOLUMES, ("nandfs_mount: clean segs: %jx\n", - (uintmax_t)nandfsdev->nd_clean_segs)); -} - - -static int -nandfs_mount_base(struct nandfs_device *nandfsdev, struct mount *mp, - struct nandfs_args *args) -{ - uint32_t log_blocksize; - int error; - - /* Flush out any old buffers remaining from a previous use. */ - if ((error = vinvalbuf(nandfsdev->nd_devvp, V_SAVE, 0, 0))) - return (error); - - error = nandfs_read_structures(nandfsdev); - if (error) { - printf("nandfs: could not get valid filesystem structures\n"); - return (error); - } - - if (nandfsdev->nd_fsdata.f_rev_level != NANDFS_CURRENT_REV) { - printf("nandfs: unsupported file system revision: %d " - "(supported is %d).\n", nandfsdev->nd_fsdata.f_rev_level, - NANDFS_CURRENT_REV); - return (EINVAL); - } - - if (nandfsdev->nd_fsdata.f_erasesize != nandfsdev->nd_erasesize) { - printf("nandfs: erasesize mismatch (device %#x, fs %#x)\n", - nandfsdev->nd_erasesize, nandfsdev->nd_fsdata.f_erasesize); - return (EINVAL); - } - - /* Get our blocksize */ - log_blocksize = nandfsdev->nd_fsdata.f_log_block_size; - nandfsdev->nd_blocksize = (uint64_t) 1 << (log_blocksize + 10); - DPRINTF(VOLUMES, ("%s: blocksize:%x\n", __func__, - nandfsdev->nd_blocksize)); - - DPRINTF(VOLUMES, ("%s: accepted super block with cp %#jx\n", __func__, - (uintmax_t)nandfsdev->nd_super.s_last_cno)); - - /* Calculate dat structure parameters */ - nandfs_calc_mdt_consts(nandfsdev, &nandfsdev->nd_dat_mdt, - nandfsdev->nd_fsdata.f_dat_entry_size); - nandfs_calc_mdt_consts(nandfsdev, &nandfsdev->nd_ifile_mdt, - nandfsdev->nd_fsdata.f_inode_size); - - /* Search for the super root and roll forward when needed */ - if (nandfs_search_super_root(nandfsdev)) { - printf("Cannot find valid SuperRoot\n"); - return (EINVAL); - } - - nandfsdev->nd_mount_state = nandfsdev->nd_super.s_state; - if (nandfsdev->nd_mount_state != NANDFS_VALID_FS) { - printf("FS is seriously damaged, needs repairing\n"); - printf("aborting mount\n"); - return (EINVAL); - } - - /* - * FS should be ok now. The superblock and the last segsum could be - * updated from the repair so extract running values again. - */ - nandfsdev->nd_last_pseg = nandfsdev->nd_super.s_last_pseg; - nandfsdev->nd_seg_sequence = nandfsdev->nd_super.s_last_seq; - nandfsdev->nd_seg_num = nandfs_get_segnum_of_block(nandfsdev, - nandfsdev->nd_last_pseg); - nandfsdev->nd_next_seg_num = nandfs_get_segnum_of_block(nandfsdev, - nandfsdev->nd_last_segsum.ss_next); - nandfsdev->nd_ts.tv_sec = nandfsdev->nd_last_segsum.ss_create; - nandfsdev->nd_last_cno = nandfsdev->nd_super.s_last_cno; - nandfsdev->nd_fakevblk = 1; - /* - * FIXME: bogus calculation. Should use actual number of usable segments - * instead of total amount. - */ - nandfsdev->nd_segs_reserved = - nandfsdev->nd_fsdata.f_nsegments * - nandfsdev->nd_fsdata.f_r_segments_percentage / 100; - nandfsdev->nd_last_ino = NANDFS_USER_INO; - DPRINTF(VOLUMES, ("%s: last_pseg %#jx last_cno %#jx last_seq %#jx\n" - "fsdev: last_seg: seq %#jx num %#jx, next_seg_num %#jx " - "segs_reserved %#jx\n", - __func__, (uintmax_t)nandfsdev->nd_last_pseg, - (uintmax_t)nandfsdev->nd_last_cno, - (uintmax_t)nandfsdev->nd_seg_sequence, - (uintmax_t)nandfsdev->nd_seg_sequence, - (uintmax_t)nandfsdev->nd_seg_num, - (uintmax_t)nandfsdev->nd_next_seg_num, - (uintmax_t)nandfsdev->nd_segs_reserved)); - - DPRINTF(VOLUMES, ("nandfs_mount: accepted super root\n")); - - /* Create system vnodes for DAT, CP and SEGSUM */ - error = nandfs_create_system_nodes(nandfsdev); - if (error) - nandfs_unmount_base(nandfsdev); - - nandfs_get_ncleanseg(nandfsdev); - - return (error); -} - -static void -nandfs_unmount_device(struct nandfs_device *nandfsdev) -{ - - /* Is there anything? */ - if (nandfsdev == NULL) - return; - - /* Remove the device only if we're the last reference */ - nandfsdev->nd_refcnt--; - if (nandfsdev->nd_refcnt >= 1) - return; - - MPASS(nandfsdev->nd_syncer == NULL); - MPASS(nandfsdev->nd_cleaner == NULL); - MPASS(nandfsdev->nd_free_base == NULL); - - /* Unmount our base */ - nandfs_unmount_base(nandfsdev); - - /* Remove from our device list */ - SLIST_REMOVE(&nandfs_devices, nandfsdev, nandfs_device, nd_next_device); - - DROP_GIANT(); - g_topology_lock(); - g_vfs_close(nandfsdev->nd_gconsumer); - g_topology_unlock(); - PICKUP_GIANT(); - - DPRINTF(VOLUMES, ("closing device\n")); - - /* Clear our mount reference and release device node */ - vrele(nandfsdev->nd_devvp); - - dev_rel(nandfsdev->nd_devvp->v_rdev); - - /* Free our device info */ - cv_destroy(&nandfsdev->nd_sync_cv); - mtx_destroy(&nandfsdev->nd_sync_mtx); - cv_destroy(&nandfsdev->nd_clean_cv); - mtx_destroy(&nandfsdev->nd_clean_mtx); - mtx_destroy(&nandfsdev->nd_mutex); - lockdestroy(&nandfsdev->nd_seg_const); - free(nandfsdev, M_NANDFSMNT); -} - -static int -nandfs_check_mounts(struct nandfs_device *nandfsdev, struct mount *mp, - struct nandfs_args *args) -{ - struct nandfsmount *nmp; - uint64_t last_cno; - - /* no double-mounting of the same checkpoint */ - STAILQ_FOREACH(nmp, &nandfsdev->nd_mounts, nm_next_mount) { - if (nmp->nm_mount_args.cpno == args->cpno) - return (EBUSY); - } - - /* Allow readonly mounts without questioning here */ - if (mp->mnt_flag & MNT_RDONLY) - return (0); - - /* Read/write mount */ - STAILQ_FOREACH(nmp, &nandfsdev->nd_mounts, nm_next_mount) { - /* Only one RW mount on this device! */ - if ((nmp->nm_vfs_mountp->mnt_flag & MNT_RDONLY)==0) - return (EROFS); - /* RDONLY on last mountpoint is device busy */ - last_cno = nmp->nm_nandfsdev->nd_super.s_last_cno; - if (nmp->nm_mount_args.cpno == last_cno) - return (EBUSY); - } - - /* OK for now */ - return (0); -} - -static int -nandfs_mount_device(struct vnode *devvp, struct mount *mp, - struct nandfs_args *args, struct nandfs_device **nandfsdev_p) -{ - struct nandfs_device *nandfsdev; - struct g_provider *pp; - struct g_consumer *cp; - struct cdev *dev; - uint32_t erasesize; - int error, size; - int ronly; - - DPRINTF(VOLUMES, ("Mounting NANDFS device\n")); - - ronly = (mp->mnt_flag & MNT_RDONLY) != 0; - - /* Look up device in our nandfs_mountpoints */ - *nandfsdev_p = NULL; - SLIST_FOREACH(nandfsdev, &nandfs_devices, nd_next_device) - if (nandfsdev->nd_devvp == devvp) - break; - - if (nandfsdev) { - DPRINTF(VOLUMES, ("device already mounted\n")); - error = nandfs_check_mounts(nandfsdev, mp, args); - if (error) - return error; - nandfsdev->nd_refcnt++; - *nandfsdev_p = nandfsdev; - - if (!ronly) { - DROP_GIANT(); - g_topology_lock(); - error = g_access(nandfsdev->nd_gconsumer, 0, 1, 0); - g_topology_unlock(); - PICKUP_GIANT(); - } - return (error); - } - - vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); - dev = devvp->v_rdev; - dev_ref(dev); - DROP_GIANT(); - g_topology_lock(); - error = g_vfs_open(devvp, &cp, "nandfs", ronly ? 0 : 1); - pp = g_dev_getprovider(dev); - g_topology_unlock(); - PICKUP_GIANT(); - VOP_UNLOCK(devvp, 0); - if (error) { - dev_rel(dev); - return (error); - } - - nandfsdev = malloc(sizeof(struct nandfs_device), M_NANDFSMNT, M_WAITOK | M_ZERO); - - /* Initialise */ - nandfsdev->nd_refcnt = 1; - nandfsdev->nd_devvp = devvp; - nandfsdev->nd_syncing = 0; - nandfsdev->nd_cleaning = 0; - nandfsdev->nd_gconsumer = cp; - cv_init(&nandfsdev->nd_sync_cv, "nandfssync"); - mtx_init(&nandfsdev->nd_sync_mtx, "nffssyncmtx", NULL, MTX_DEF); - cv_init(&nandfsdev->nd_clean_cv, "nandfsclean"); - mtx_init(&nandfsdev->nd_clean_mtx, "nffscleanmtx", NULL, MTX_DEF); - mtx_init(&nandfsdev->nd_mutex, "nandfsdev lock", NULL, MTX_DEF); - lockinit(&nandfsdev->nd_seg_const, PVFS, "nffssegcon", VLKTIMEOUT, - LK_CANRECURSE); - STAILQ_INIT(&nandfsdev->nd_mounts); - - nandfsdev->nd_devsize = pp->mediasize; - nandfsdev->nd_devblocksize = pp->sectorsize; - - size = sizeof(erasesize); - error = g_io_getattr("NAND::blocksize", nandfsdev->nd_gconsumer, &size, - &erasesize); - if (error) { - DPRINTF(VOLUMES, ("couldn't get erasesize: %d\n", error)); - - if (error == ENOIOCTL || error == EOPNOTSUPP) { - /* - * We conclude that this is not NAND storage - */ - erasesize = NANDFS_DEF_ERASESIZE; - } else { - DROP_GIANT(); - g_topology_lock(); - g_vfs_close(nandfsdev->nd_gconsumer); - g_topology_unlock(); - PICKUP_GIANT(); - dev_rel(dev); - free(nandfsdev, M_NANDFSMNT); - return (error); - } - } - nandfsdev->nd_erasesize = erasesize; - - DPRINTF(VOLUMES, ("%s: erasesize %x\n", __func__, - nandfsdev->nd_erasesize)); - - /* Register nandfs_device in list */ - SLIST_INSERT_HEAD(&nandfs_devices, nandfsdev, nd_next_device); - - error = nandfs_mount_base(nandfsdev, mp, args); - if (error) { - /* Remove all our information */ - nandfs_unmount_device(nandfsdev); - return (EINVAL); - } - - nandfsdev->nd_maxfilesize = nandfs_get_maxfilesize(nandfsdev); - - *nandfsdev_p = nandfsdev; - DPRINTF(VOLUMES, ("NANDFS device mounted ok\n")); - - return (0); -} - -static int -nandfs_mount_checkpoint(struct nandfsmount *nmp) -{ - struct nandfs_cpfile_header *cphdr; - struct nandfs_checkpoint *cp; - struct nandfs_inode ifile_inode; - struct nandfs_node *cp_node; - struct buf *bp; - uint64_t ncp, nsn, cpno, fcpno, blocknr, last_cno; - uint32_t off, dlen; - int cp_per_block, error; - - cpno = nmp->nm_mount_args.cpno; - if (cpno == 0) - cpno = nmp->nm_nandfsdev->nd_super.s_last_cno; - - DPRINTF(VOLUMES, ("%s: trying to mount checkpoint number %"PRIu64"\n", - __func__, cpno)); - - cp_node = nmp->nm_nandfsdev->nd_cp_node; - - VOP_LOCK(NTOV(cp_node), LK_SHARED); - /* Get cpfile header from 1st block of cp file */ - error = nandfs_bread(cp_node, 0, NOCRED, 0, &bp); - if (error) { - brelse(bp); - VOP_UNLOCK(NTOV(cp_node), 0); - return (error); - } - - cphdr = (struct nandfs_cpfile_header *) bp->b_data; - ncp = cphdr->ch_ncheckpoints; - nsn = cphdr->ch_nsnapshots; - - brelse(bp); - - DPRINTF(VOLUMES, ("mount_nandfs: checkpoint header read in\n")); - DPRINTF(VOLUMES, ("\tNumber of checkpoints %"PRIu64"\n", ncp)); - DPRINTF(VOLUMES, ("\tNumber of snapshots %"PRIu64"\n", nsn)); - - /* Read in our specified checkpoint */ - dlen = nmp->nm_nandfsdev->nd_fsdata.f_checkpoint_size; - cp_per_block = nmp->nm_nandfsdev->nd_blocksize / dlen; - - fcpno = cpno + NANDFS_CPFILE_FIRST_CHECKPOINT_OFFSET - 1; - blocknr = fcpno / cp_per_block; - off = (fcpno % cp_per_block) * dlen; - error = nandfs_bread(cp_node, blocknr, NOCRED, 0, &bp); - if (error) { - brelse(bp); - VOP_UNLOCK(NTOV(cp_node), 0); - printf("mount_nandfs: couldn't read cp block %"PRIu64"\n", - fcpno); - return (EINVAL); - } - - /* Needs to be a valid checkpoint */ - cp = (struct nandfs_checkpoint *) ((uint8_t *) bp->b_data + off); - if (cp->cp_flags & NANDFS_CHECKPOINT_INVALID) { - printf("mount_nandfs: checkpoint marked invalid\n"); - brelse(bp); - VOP_UNLOCK(NTOV(cp_node), 0); - return (EINVAL); - } - - /* Is this really the checkpoint we want? */ - if (cp->cp_cno != cpno) { - printf("mount_nandfs: checkpoint file corrupt? " - "expected cpno %"PRIu64", found cpno %"PRIu64"\n", - cpno, cp->cp_cno); - brelse(bp); - VOP_UNLOCK(NTOV(cp_node), 0); - return (EINVAL); - } - - /* Check if it's a snapshot ! */ - last_cno = nmp->nm_nandfsdev->nd_super.s_last_cno; - if (cpno != last_cno) { - /* Only allow snapshots if not mounting on the last cp */ - if ((cp->cp_flags & NANDFS_CHECKPOINT_SNAPSHOT) == 0) { - printf( "mount_nandfs: checkpoint %"PRIu64" is not a " - "snapshot\n", cpno); - brelse(bp); - VOP_UNLOCK(NTOV(cp_node), 0); - return (EINVAL); - } - } - - ifile_inode = cp->cp_ifile_inode; - brelse(bp); - - /* Get ifile inode */ - error = nandfs_get_node_raw(nmp->nm_nandfsdev, NULL, NANDFS_IFILE_INO, - &ifile_inode, &nmp->nm_ifile_node); - if (error) { - printf("mount_nandfs: can't read ifile node\n"); - VOP_UNLOCK(NTOV(cp_node), 0); - return (EINVAL); - } - - NANDFS_SET_SYSTEMFILE(NTOV(nmp->nm_ifile_node)); - VOP_UNLOCK(NTOV(cp_node), 0); - /* Get root node? */ - - return (0); -} - -static void -free_nandfs_mountinfo(struct mount *mp) -{ - struct nandfsmount *nmp = VFSTONANDFS(mp); - - if (nmp == NULL) - return; - - free(nmp, M_NANDFSMNT); -} - -void -nandfs_wakeup_wait_sync(struct nandfs_device *nffsdev, int reason) -{ - char *reasons[] = { - "umount", - "vfssync", - "bdflush", - "fforce", - "fsync", - "ro_upd" - }; - - DPRINTF(SYNC, ("%s: %s\n", __func__, reasons[reason])); - mtx_lock(&nffsdev->nd_sync_mtx); - if (nffsdev->nd_syncing) - cv_wait(&nffsdev->nd_sync_cv, &nffsdev->nd_sync_mtx); - if (reason == SYNCER_UMOUNT) - nffsdev->nd_syncer_exit = 1; - nffsdev->nd_syncing = 1; - wakeup(&nffsdev->nd_syncing); - cv_wait(&nffsdev->nd_sync_cv, &nffsdev->nd_sync_mtx); - - mtx_unlock(&nffsdev->nd_sync_mtx); -} - -static void -nandfs_gc_finished(struct nandfs_device *nffsdev, int exit) -{ - int error; - - mtx_lock(&nffsdev->nd_sync_mtx); - nffsdev->nd_syncing = 0; - DPRINTF(SYNC, ("%s: cleaner finish\n", __func__)); - cv_broadcast(&nffsdev->nd_sync_cv); - mtx_unlock(&nffsdev->nd_sync_mtx); - if (!exit) { - error = tsleep(&nffsdev->nd_syncing, PRIBIO, "-", - hz * nandfs_sync_interval); - DPRINTF(SYNC, ("%s: cleaner waked up: %d\n", - __func__, error)); - } -} - -static void -nandfs_syncer(struct nandfsmount *nmp) -{ - struct nandfs_device *nffsdev; - struct mount *mp; - int flags, error; - - mp = nmp->nm_vfs_mountp; - nffsdev = nmp->nm_nandfsdev; - tsleep(&nffsdev->nd_syncing, PRIBIO, "-", hz * nandfs_sync_interval); - - while (!nffsdev->nd_syncer_exit) { - DPRINTF(SYNC, ("%s: syncer run\n", __func__)); - nffsdev->nd_syncing = 1; - - flags = (nmp->nm_flags & (NANDFS_FORCE_SYNCER | NANDFS_UMOUNT)); - - error = nandfs_segment_constructor(nmp, flags); - if (error) - nandfs_error("%s: error:%d when creating segments\n", - __func__, error); - - nmp->nm_flags &= ~flags; - - nandfs_gc_finished(nffsdev, 0); - } - - MPASS(nffsdev->nd_cleaner == NULL); - error = nandfs_segment_constructor(nmp, - NANDFS_FORCE_SYNCER | NANDFS_UMOUNT); - if (error) - nandfs_error("%s: error:%d when creating segments\n", - __func__, error); - nandfs_gc_finished(nffsdev, 1); - nffsdev->nd_syncer = NULL; - MPASS(nffsdev->nd_free_base == NULL); - - DPRINTF(SYNC, ("%s: exiting\n", __func__)); - kthread_exit(); -} - -static int -start_syncer(struct nandfsmount *nmp) -{ - int error; - - MPASS(nmp->nm_nandfsdev->nd_syncer == NULL); - - DPRINTF(SYNC, ("%s: start syncer\n", __func__)); - - nmp->nm_nandfsdev->nd_syncer_exit = 0; - - error = kthread_add((void(*)(void *))nandfs_syncer, nmp, NULL, - &nmp->nm_nandfsdev->nd_syncer, 0, 0, "nandfs_syncer"); - - if (error) - printf("nandfs: could not start syncer: %d\n", error); - - return (error); -} - -static int -stop_syncer(struct nandfsmount *nmp) -{ - - MPASS(nmp->nm_nandfsdev->nd_syncer != NULL); - - nandfs_wakeup_wait_sync(nmp->nm_nandfsdev, SYNCER_UMOUNT); - - DPRINTF(SYNC, ("%s: stop syncer\n", __func__)); - return (0); -} - -/* - * Mount null layer - */ -static int -nandfs_mount(struct mount *mp) -{ - struct nandfsmount *nmp; - struct vnode *devvp; - struct nameidata nd; - struct vfsoptlist *opts; - struct thread *td; - char *from; - int error = 0, flags; - - DPRINTF(VOLUMES, ("%s: mp = %p\n", __func__, (void *)mp)); - - td = curthread; - opts = mp->mnt_optnew; - - if (vfs_filteropt(opts, nandfs_opts)) - return (EINVAL); - - /* - * Update is a no-op - */ - if (mp->mnt_flag & MNT_UPDATE) { - nmp = VFSTONANDFS(mp); - if (vfs_flagopt(mp->mnt_optnew, "export", NULL, 0)) { - return (error); - } - if (!(nmp->nm_ronly) && vfs_flagopt(opts, "ro", NULL, 0)) { - vn_start_write(NULL, &mp, V_WAIT); - error = VFS_SYNC(mp, MNT_WAIT); - if (error) - return (error); - vn_finished_write(mp); - - flags = WRITECLOSE; - if (mp->mnt_flag & MNT_FORCE) - flags |= FORCECLOSE; - - nandfs_wakeup_wait_sync(nmp->nm_nandfsdev, - SYNCER_ROUPD); - error = vflush(mp, 0, flags, td); - if (error) - return (error); - - nandfs_stop_cleaner(nmp->nm_nandfsdev); - stop_syncer(nmp); - DROP_GIANT(); - g_topology_lock(); - g_access(nmp->nm_nandfsdev->nd_gconsumer, 0, -1, 0); - g_topology_unlock(); - PICKUP_GIANT(); - MNT_ILOCK(mp); - mp->mnt_flag |= MNT_RDONLY; - MNT_IUNLOCK(mp); - nmp->nm_ronly = 1; - - } else if ((nmp->nm_ronly) && - !vfs_flagopt(opts, "ro", NULL, 0)) { - /* - * Don't allow read-write snapshots. - */ - if (nmp->nm_mount_args.cpno != 0) - return (EROFS); - /* - * If upgrade to read-write by non-root, then verify - * that user has necessary permissions on the device. - */ - devvp = nmp->nm_nandfsdev->nd_devvp; - vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); - error = VOP_ACCESS(devvp, VREAD | VWRITE, - td->td_ucred, td); - if (error) { - error = priv_check(td, PRIV_VFS_MOUNT_PERM); - if (error) { - VOP_UNLOCK(devvp, 0); - return (error); - } - } - - VOP_UNLOCK(devvp, 0); - DROP_GIANT(); - g_topology_lock(); - error = g_access(nmp->nm_nandfsdev->nd_gconsumer, 0, 1, - 0); - g_topology_unlock(); - PICKUP_GIANT(); - if (error) - return (error); - - MNT_ILOCK(mp); - mp->mnt_flag &= ~MNT_RDONLY; - MNT_IUNLOCK(mp); - error = start_syncer(nmp); - if (error == 0) - error = nandfs_start_cleaner(nmp->nm_nandfsdev); - if (error) { - DROP_GIANT(); - g_topology_lock(); - g_access(nmp->nm_nandfsdev->nd_gconsumer, 0, -1, - 0); - g_topology_unlock(); - PICKUP_GIANT(); - return (error); - } - - nmp->nm_ronly = 0; - } - return (0); - } - - from = vfs_getopts(opts, "from", &error); - if (error) - return (error); - - /* - * Find device node - */ - NDINIT(&nd, LOOKUP, FOLLOW|LOCKLEAF, UIO_SYSSPACE, from, curthread); - error = namei(&nd); - if (error) - return (error); - NDFREE(&nd, NDF_ONLY_PNBUF); - - devvp = nd.ni_vp; - - if (!vn_isdisk(devvp, &error)) { - vput(devvp); - return (error); - } - - /* Check the access rights on the mount device */ - error = VOP_ACCESS(devvp, VREAD, curthread->td_ucred, curthread); - if (error) - error = priv_check(curthread, PRIV_VFS_MOUNT_PERM); - if (error) { - vput(devvp); - return (error); - } - - vfs_getnewfsid(mp); - - error = nandfs_mountfs(devvp, mp); - if (error) - return (error); - vfs_mountedfrom(mp, from); - - return (0); -} - -static int -nandfs_mountfs(struct vnode *devvp, struct mount *mp) -{ - struct nandfsmount *nmp = NULL; - struct nandfs_args *args = NULL; - struct nandfs_device *nandfsdev; - char *from; - int error, ronly; - char *cpno; - - ronly = (mp->mnt_flag & MNT_RDONLY) != 0; - - if (devvp->v_rdev->si_iosize_max != 0) - mp->mnt_iosize_max = devvp->v_rdev->si_iosize_max; - VOP_UNLOCK(devvp, 0); - - if (mp->mnt_iosize_max > MAXPHYS) - mp->mnt_iosize_max = MAXPHYS; - - from = vfs_getopts(mp->mnt_optnew, "from", &error); - if (error) - goto error; - - error = vfs_getopt(mp->mnt_optnew, "snap", (void **)&cpno, NULL); - if (error == ENOENT) - cpno = NULL; - else if (error) - goto error; - - args = (struct nandfs_args *)malloc(sizeof(struct nandfs_args), - M_NANDFSMNT, M_WAITOK | M_ZERO); - - if (cpno != NULL) - args->cpno = strtoul(cpno, (char **)NULL, 10); - else - args->cpno = 0; - args->fspec = from; - - if (args->cpno != 0 && !ronly) { - error = EROFS; - goto error; - } - - printf("WARNING: NANDFS is considered to be a highly experimental " - "feature in FreeBSD.\n"); - - error = nandfs_mount_device(devvp, mp, args, &nandfsdev); - if (error) - goto error; - - nmp = (struct nandfsmount *) malloc(sizeof(struct nandfsmount), - M_NANDFSMNT, M_WAITOK | M_ZERO); - - mp->mnt_data = nmp; - nmp->nm_vfs_mountp = mp; - nmp->nm_ronly = ronly; - MNT_ILOCK(mp); - mp->mnt_flag |= MNT_LOCAL; - mp->mnt_kern_flag |= MNTK_USES_BCACHE; - MNT_IUNLOCK(mp); - nmp->nm_nandfsdev = nandfsdev; - /* Add our mountpoint */ - STAILQ_INSERT_TAIL(&nandfsdev->nd_mounts, nmp, nm_next_mount); - - if (args->cpno > nandfsdev->nd_last_cno) { - printf("WARNING: supplied checkpoint number (%jd) is greater " - "than last known checkpoint on filesystem (%jd). Mounting" - " checkpoint %jd\n", (uintmax_t)args->cpno, - (uintmax_t)nandfsdev->nd_last_cno, - (uintmax_t)nandfsdev->nd_last_cno); - args->cpno = nandfsdev->nd_last_cno; - } - - /* Setting up other parameters */ - nmp->nm_mount_args = *args; - free(args, M_NANDFSMNT); - error = nandfs_mount_checkpoint(nmp); - if (error) { - nandfs_unmount(mp, MNT_FORCE); - goto unmounted; - } - - if (!ronly) { - error = start_syncer(nmp); - if (error == 0) - error = nandfs_start_cleaner(nmp->nm_nandfsdev); - if (error) - nandfs_unmount(mp, MNT_FORCE); - } - - return (0); - -error: - if (args != NULL) - free(args, M_NANDFSMNT); - - if (nmp != NULL) { - free(nmp, M_NANDFSMNT); - mp->mnt_data = NULL; - } -unmounted: - return (error); -} - -static int -nandfs_unmount(struct mount *mp, int mntflags) -{ - struct nandfs_device *nandfsdev; - struct nandfsmount *nmp; - int error; - int flags = 0; - - DPRINTF(VOLUMES, ("%s: mp = %p\n", __func__, (void *)mp)); - - if (mntflags & MNT_FORCE) - flags |= FORCECLOSE; - - nmp = mp->mnt_data; - nandfsdev = nmp->nm_nandfsdev; - - error = vflush(mp, 0, flags | SKIPSYSTEM, curthread); - if (error) - return (error); - - if (!(nmp->nm_ronly)) { - nandfs_stop_cleaner(nandfsdev); - stop_syncer(nmp); - } - - if (nmp->nm_ifile_node) - NANDFS_UNSET_SYSTEMFILE(NTOV(nmp->nm_ifile_node)); - - /* Remove our mount point */ - STAILQ_REMOVE(&nandfsdev->nd_mounts, nmp, nandfsmount, nm_next_mount); - - /* Unmount the device itself when we're the last one */ - nandfs_unmount_device(nandfsdev); - - free_nandfs_mountinfo(mp); - - /* - * Finally, throw away the null_mount structure - */ - mp->mnt_data = 0; - MNT_ILOCK(mp); - mp->mnt_flag &= ~MNT_LOCAL; - MNT_IUNLOCK(mp); - - return (0); -} - -static int -nandfs_statfs(struct mount *mp, struct statfs *sbp) -{ - struct nandfsmount *nmp; - struct nandfs_device *nandfsdev; - struct nandfs_fsdata *fsdata; - struct nandfs_super_block *sb; - struct nandfs_block_group_desc *groups; - struct nandfs_node *ifile; - struct nandfs_mdt *mdt; - struct buf *bp; - int i, error; - uint32_t entries_per_group; - uint64_t files = 0; - - nmp = mp->mnt_data; - nandfsdev = nmp->nm_nandfsdev; - fsdata = &nandfsdev->nd_fsdata; - sb = &nandfsdev->nd_super; - ifile = nmp->nm_ifile_node; - mdt = &nandfsdev->nd_ifile_mdt; - entries_per_group = mdt->entries_per_group; - - VOP_LOCK(NTOV(ifile), LK_SHARED); - error = nandfs_bread(ifile, 0, NOCRED, 0, &bp); - if (error) { - brelse(bp); - VOP_UNLOCK(NTOV(ifile), 0); - return (error); - } - - groups = (struct nandfs_block_group_desc *)bp->b_data; - - for (i = 0; i < mdt->groups_per_desc_block; i++) - files += (entries_per_group - groups[i].bg_nfrees); - - brelse(bp); - VOP_UNLOCK(NTOV(ifile), 0); - - sbp->f_bsize = nandfsdev->nd_blocksize; - sbp->f_iosize = sbp->f_bsize; - sbp->f_blocks = fsdata->f_blocks_per_segment * fsdata->f_nsegments; - sbp->f_bfree = sb->s_free_blocks_count; - sbp->f_bavail = sbp->f_bfree; - sbp->f_files = files; - sbp->f_ffree = 0; - return (0); -} - -static int -nandfs_root(struct mount *mp, int flags, struct vnode **vpp) -{ - struct nandfsmount *nmp = VFSTONANDFS(mp); - struct nandfs_node *node; - int error; - - error = nandfs_get_node(nmp, NANDFS_ROOT_INO, &node); - if (error) - return (error); - - KASSERT(NTOV(node)->v_vflag & VV_ROOT, - ("root_vp->v_vflag & VV_ROOT")); - - *vpp = NTOV(node); - - return (error); -} - -static int -nandfs_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) -{ - struct nandfsmount *nmp = VFSTONANDFS(mp); - struct nandfs_node *node; - int error; - - error = nandfs_get_node(nmp, ino, &node); - if (node) - *vpp = NTOV(node); - - return (error); -} - -static int -nandfs_sync(struct mount *mp, int waitfor) -{ - struct nandfsmount *nmp = VFSTONANDFS(mp); - - DPRINTF(SYNC, ("%s: mp %p waitfor %d\n", __func__, mp, waitfor)); - - /* - * XXX: A hack to be removed soon - */ - if (waitfor == MNT_LAZY) - return (0); - if (waitfor == MNT_SUSPEND) - return (0); - nandfs_wakeup_wait_sync(nmp->nm_nandfsdev, SYNCER_VFS_SYNC); - return (0); -} - -static struct vfsops nandfs_vfsops = { - .vfs_init = nandfs_init, - .vfs_mount = nandfs_mount, - .vfs_root = nandfs_root, - .vfs_statfs = nandfs_statfs, - .vfs_uninit = nandfs_uninit, - .vfs_unmount = nandfs_unmount, - .vfs_vget = nandfs_vget, - .vfs_sync = nandfs_sync, -}; - -VFS_SET(nandfs_vfsops, nandfs, VFCF_LOOPBACK); diff --git a/sys/fs/nandfs/nandfs_vnops.c b/sys/fs/nandfs/nandfs_vnops.c deleted file mode 100644 index 5027d6adbbc1..000000000000 --- a/sys/fs/nandfs/nandfs_vnops.c +++ /dev/null @@ -1,2454 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf - * Copyright (c) 2008, 2009 Reinoud Zandijk - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * From: NetBSD: nilfs_vnops.c,v 1.2 2009/08/26 03:40:48 elad - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/conf.h> -#include <sys/kernel.h> -#include <sys/lock.h> -#include <sys/lockf.h> -#include <sys/malloc.h> -#include <sys/mount.h> -#include <sys/mutex.h> -#include <sys/namei.h> -#include <sys/sysctl.h> -#include <sys/unistd.h> -#include <sys/vnode.h> -#include <sys/buf.h> -#include <sys/bio.h> -#include <sys/fcntl.h> -#include <sys/dirent.h> -#include <sys/rwlock.h> -#include <sys/stat.h> -#include <sys/priv.h> - -#include <vm/vm.h> -#include <vm/vm_extern.h> -#include <vm/vm_object.h> -#include <vm/vnode_pager.h> - -#include <machine/_inttypes.h> - -#include <fs/nandfs/nandfs_mount.h> -#include <fs/nandfs/nandfs.h> -#include <fs/nandfs/nandfs_subr.h> - -extern uma_zone_t nandfs_node_zone; -static void nandfs_read_filebuf(struct nandfs_node *, struct buf *); -static void nandfs_itimes_locked(struct vnode *); -static int nandfs_truncate(struct vnode *, uint64_t); - -static vop_pathconf_t nandfs_pathconf; - -#define UPDATE_CLOSE 0 -#define UPDATE_WAIT 0 - -static int -nandfs_inactive(struct vop_inactive_args *ap) -{ - struct vnode *vp = ap->a_vp; - struct nandfs_node *node = VTON(vp); - int error = 0; - - DPRINTF(VNCALL, ("%s: vp:%p node:%p\n", __func__, vp, node)); - - if (node == NULL) { - DPRINTF(NODE, ("%s: inactive NULL node\n", __func__)); - return (0); - } - - if (node->nn_inode.i_mode != 0 && !(node->nn_inode.i_links_count)) { - nandfs_truncate(vp, 0); - error = nandfs_node_destroy(node); - if (error) - nandfs_error("%s: destroy node: %p\n", __func__, node); - node->nn_flags = 0; - vrecycle(vp); - } - - return (error); -} - -static int -nandfs_reclaim(struct vop_reclaim_args *ap) -{ - struct vnode *vp = ap->a_vp; - struct nandfs_node *nandfs_node = VTON(vp); - struct nandfs_device *fsdev = nandfs_node->nn_nandfsdev; - uint64_t ino = nandfs_node->nn_ino; - - DPRINTF(VNCALL, ("%s: vp:%p node:%p\n", __func__, vp, nandfs_node)); - - /* Invalidate all entries to a particular vnode. */ - cache_purge(vp); - - /* Destroy the vm object and flush associated pages. */ - vnode_destroy_vobject(vp); - - /* Remove from vfs hash if not system vnode */ - if (!NANDFS_SYS_NODE(nandfs_node->nn_ino)) - vfs_hash_remove(vp); - - /* Dispose all node knowledge */ - nandfs_dispose_node(&nandfs_node); - - if (!NANDFS_SYS_NODE(ino)) - NANDFS_WRITEUNLOCK(fsdev); - - return (0); -} - -static int -nandfs_read(struct vop_read_args *ap) -{ - struct vnode *vp = ap->a_vp; - struct nandfs_node *node = VTON(vp); - struct nandfs_device *nandfsdev = node->nn_nandfsdev; - struct uio *uio = ap->a_uio; - struct buf *bp; - uint64_t size; - uint32_t blocksize; - off_t bytesinfile; - ssize_t toread, off; - daddr_t lbn; - ssize_t resid; - int error = 0; - - if (uio->uio_resid == 0) - return (0); - - size = node->nn_inode.i_size; - if (uio->uio_offset >= size) - return (0); - - blocksize = nandfsdev->nd_blocksize; - bytesinfile = size - uio->uio_offset; - - resid = omin(uio->uio_resid, bytesinfile); - - while (resid) { - lbn = uio->uio_offset / blocksize; - off = uio->uio_offset & (blocksize - 1); - - toread = omin(resid, blocksize - off); - - DPRINTF(READ, ("nandfs_read bn: 0x%jx toread: 0x%zx (0x%x)\n", - (uintmax_t)lbn, toread, blocksize)); - - error = nandfs_bread(node, lbn, NOCRED, 0, &bp); - if (error) { - brelse(bp); - break; - } - - error = uiomove(bp->b_data + off, toread, uio); - if (error) { - brelse(bp); - break; - } - - brelse(bp); - resid -= toread; - } - - return (error); -} - -static int -nandfs_write(struct vop_write_args *ap) -{ - struct nandfs_device *fsdev; - struct nandfs_node *node; - struct vnode *vp; - struct uio *uio; - struct buf *bp; - uint64_t file_size, vblk; - uint32_t blocksize; - ssize_t towrite, off; - daddr_t lbn; - ssize_t resid; - int error, ioflag, modified; - - vp = ap->a_vp; - uio = ap->a_uio; - ioflag = ap->a_ioflag; - node = VTON(vp); - fsdev = node->nn_nandfsdev; - - if (nandfs_fs_full(fsdev)) - return (ENOSPC); - - DPRINTF(WRITE, ("nandfs_write called %#zx at %#jx\n", - uio->uio_resid, (uintmax_t)uio->uio_offset)); - - if (uio->uio_offset < 0) - return (EINVAL); - if (uio->uio_resid == 0) - return (0); - - blocksize = fsdev->nd_blocksize; - file_size = node->nn_inode.i_size; - - switch (vp->v_type) { - case VREG: - if (ioflag & IO_APPEND) - uio->uio_offset = file_size; - break; - case VDIR: - return (EISDIR); - case VLNK: - break; - default: - panic("%s: bad file type vp: %p", __func__, vp); - } - - /* If explicitly asked to append, uio_offset can be wrong? */ - if (ioflag & IO_APPEND) - uio->uio_offset = file_size; - - resid = uio->uio_resid; - modified = error = 0; - - while (uio->uio_resid) { - lbn = uio->uio_offset / blocksize; - off = uio->uio_offset & (blocksize - 1); - - towrite = omin(uio->uio_resid, blocksize - off); - - DPRINTF(WRITE, ("%s: lbn: 0x%jd toread: 0x%zx (0x%x)\n", - __func__, (uintmax_t)lbn, towrite, blocksize)); - - error = nandfs_bmap_lookup(node, lbn, &vblk); - if (error) - break; - - DPRINTF(WRITE, ("%s: lbn: 0x%jd toread: 0x%zx (0x%x) " - "vblk=%jx\n", __func__, (uintmax_t)lbn, towrite, blocksize, - vblk)); - - if (vblk != 0) - error = nandfs_bread(node, lbn, NOCRED, 0, &bp); - else - error = nandfs_bcreate(node, lbn, NOCRED, 0, &bp); - - DPRINTF(WRITE, ("%s: vp %p bread bp %p lbn %#jx\n", __func__, - vp, bp, (uintmax_t)lbn)); - if (error) { - if (bp) - brelse(bp); - break; - } - - error = uiomove((char *)bp->b_data + off, (int)towrite, uio); - if (error) - break; - - error = nandfs_dirty_buf(bp, 0); - if (error) - break; - - modified++; - } - - /* XXX proper handling when only part of file was properly written */ - if (modified) { - if (resid > uio->uio_resid && ap->a_cred && - ap->a_cred->cr_uid != 0) - node->nn_inode.i_mode &= ~(ISUID | ISGID); - - if (file_size < uio->uio_offset + uio->uio_resid) { - node->nn_inode.i_size = uio->uio_offset + - uio->uio_resid; - node->nn_flags |= IN_CHANGE | IN_UPDATE; - vnode_pager_setsize(vp, uio->uio_offset + - uio->uio_resid); - nandfs_itimes(vp); - } - } - - DPRINTF(WRITE, ("%s: return:%d\n", __func__, error)); - - return (error); -} - -static int -nandfs_lookup(struct vop_cachedlookup_args *ap) -{ - struct vnode *dvp, **vpp; - struct componentname *cnp; - struct ucred *cred; - struct thread *td; - struct nandfs_node *dir_node, *node; - struct nandfsmount *nmp; - uint64_t ino, off; - const char *name; - int namelen, nameiop, islastcn, mounted_ro; - int error, found; - - DPRINTF(VNCALL, ("%s\n", __func__)); - - dvp = ap->a_dvp; - vpp = ap->a_vpp; - *vpp = NULL; - - cnp = ap->a_cnp; - cred = cnp->cn_cred; - td = cnp->cn_thread; - - dir_node = VTON(dvp); - nmp = dir_node->nn_nmp; - - /* Simplify/clarification flags */ - nameiop = cnp->cn_nameiop; - islastcn = cnp->cn_flags & ISLASTCN; - mounted_ro = dvp->v_mount->mnt_flag & MNT_RDONLY; - - /* - * If requesting a modify on the last path element on a read-only - * filingsystem, reject lookup; - */ - if (islastcn && mounted_ro && (nameiop == DELETE || nameiop == RENAME)) - return (EROFS); - - if (dir_node->nn_inode.i_links_count == 0) - return (ENOENT); - - /* - * Obviously, the file is not (anymore) in the namecache, we have to - * search for it. There are three basic cases: '.', '..' and others. - * - * Following the guidelines of VOP_LOOKUP manpage and tmpfs. - */ - error = 0; - if ((cnp->cn_namelen == 1) && (cnp->cn_nameptr[0] == '.')) { - DPRINTF(LOOKUP, ("\tlookup '.'\n")); - /* Special case 1 '.' */ - VREF(dvp); - *vpp = dvp; - /* Done */ - } else if (cnp->cn_flags & ISDOTDOT) { - /* Special case 2 '..' */ - DPRINTF(LOOKUP, ("\tlookup '..'\n")); - - /* Get our node */ - name = ".."; - namelen = 2; - error = nandfs_lookup_name_in_dir(dvp, name, namelen, &ino, - &found, &off); - if (error) - goto out; - if (!found) - error = ENOENT; - - /* First unlock parent */ - VOP_UNLOCK(dvp, 0); - - if (error == 0) { - DPRINTF(LOOKUP, ("\tfound '..'\n")); - /* Try to create/reuse the node */ - error = nandfs_get_node(nmp, ino, &node); - - if (!error) { - DPRINTF(LOOKUP, - ("\tnode retrieved/created OK\n")); - *vpp = NTOV(node); - } - } - - /* Try to relock parent */ - vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); - } else { - DPRINTF(LOOKUP, ("\tlookup file\n")); - /* All other files */ - /* Look up filename in the directory returning its inode */ - name = cnp->cn_nameptr; - namelen = cnp->cn_namelen; - error = nandfs_lookup_name_in_dir(dvp, name, namelen, - &ino, &found, &off); - if (error) - goto out; - if (!found) { - DPRINTF(LOOKUP, ("\tNOT found\n")); - /* - * UGH, didn't find name. If we're creating or - * renaming on the last name this is OK and we ought - * to return EJUSTRETURN if its allowed to be created. - */ - error = ENOENT; - if ((nameiop == CREATE || nameiop == RENAME) && - islastcn) { - error = VOP_ACCESS(dvp, VWRITE, cred, td); - if (!error) { - /* keep the component name */ - cnp->cn_flags |= SAVENAME; - error = EJUSTRETURN; - } - } - /* Done */ - } else { - if (ino == NANDFS_WHT_INO) - cnp->cn_flags |= ISWHITEOUT; - - if ((cnp->cn_flags & ISWHITEOUT) && - (nameiop == LOOKUP)) - return (ENOENT); - - if ((nameiop == DELETE) && islastcn) { - if ((cnp->cn_flags & ISWHITEOUT) && - (cnp->cn_flags & DOWHITEOUT)) { - cnp->cn_flags |= SAVENAME; - dir_node->nn_diroff = off; - return (EJUSTRETURN); - } - - error = VOP_ACCESS(dvp, VWRITE, cred, - cnp->cn_thread); - if (error) - return (error); - - /* Try to create/reuse the node */ - error = nandfs_get_node(nmp, ino, &node); - if (!error) { - *vpp = NTOV(node); - node->nn_diroff = off; - } - - if ((dir_node->nn_inode.i_mode & ISVTX) && - cred->cr_uid != 0 && - cred->cr_uid != dir_node->nn_inode.i_uid && - node->nn_inode.i_uid != cred->cr_uid) { - vput(*vpp); - *vpp = NULL; - return (EPERM); - } - } else if ((nameiop == RENAME) && islastcn) { - error = VOP_ACCESS(dvp, VWRITE, cred, - cnp->cn_thread); - if (error) - return (error); - - /* Try to create/reuse the node */ - error = nandfs_get_node(nmp, ino, &node); - if (!error) { - *vpp = NTOV(node); - node->nn_diroff = off; - } - } else { - /* Try to create/reuse the node */ - error = nandfs_get_node(nmp, ino, &node); - if (!error) { - *vpp = NTOV(node); - node->nn_diroff = off; - } - } - } - } - -out: - /* - * Store result in the cache if requested. If we are creating a file, - * the file might not be found and thus putting it into the namecache - * might be seen as negative caching. - */ - if ((cnp->cn_flags & MAKEENTRY) != 0) - cache_enter(dvp, *vpp, cnp); - - return (error); - -} - -static int -nandfs_getattr(struct vop_getattr_args *ap) -{ - struct vnode *vp = ap->a_vp; - struct vattr *vap = ap->a_vap; - struct nandfs_node *node = VTON(vp); - struct nandfs_inode *inode = &node->nn_inode; - - DPRINTF(VNCALL, ("%s: vp: %p\n", __func__, vp)); - nandfs_itimes(vp); - - /* Basic info */ - VATTR_NULL(vap); - vap->va_atime.tv_sec = inode->i_mtime; - vap->va_atime.tv_nsec = inode->i_mtime_nsec; - vap->va_mtime.tv_sec = inode->i_mtime; - vap->va_mtime.tv_nsec = inode->i_mtime_nsec; - vap->va_ctime.tv_sec = inode->i_ctime; - vap->va_ctime.tv_nsec = inode->i_ctime_nsec; - vap->va_type = IFTOVT(inode->i_mode); - vap->va_mode = inode->i_mode & ~S_IFMT; - vap->va_nlink = inode->i_links_count; - vap->va_uid = inode->i_uid; - vap->va_gid = inode->i_gid; - vap->va_rdev = inode->i_special; - vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; - vap->va_fileid = node->nn_ino; - vap->va_size = inode->i_size; - vap->va_blocksize = node->nn_nandfsdev->nd_blocksize; - vap->va_gen = 0; - vap->va_flags = inode->i_flags; - vap->va_bytes = inode->i_blocks * vap->va_blocksize; - vap->va_filerev = 0; - vap->va_vaflags = 0; - - return (0); -} - -static int -nandfs_vtruncbuf(struct vnode *vp, uint64_t nblks) -{ - struct nandfs_device *nffsdev; - struct bufobj *bo; - struct buf *bp, *nbp; - - bo = &vp->v_bufobj; - nffsdev = VTON(vp)->nn_nandfsdev; - - ASSERT_VOP_LOCKED(vp, "nandfs_truncate"); -restart: - BO_LOCK(bo); -restart_locked: - TAILQ_FOREACH_SAFE(bp, &bo->bo_clean.bv_hd, b_bobufs, nbp) { - if (bp->b_lblkno < nblks) - continue; - if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL)) - goto restart_locked; - - bremfree(bp); - bp->b_flags |= (B_INVAL | B_RELBUF); - bp->b_flags &= ~(B_ASYNC | B_MANAGED); - BO_UNLOCK(bo); - brelse(bp); - BO_LOCK(bo); - } - - TAILQ_FOREACH_SAFE(bp, &bo->bo_dirty.bv_hd, b_bobufs, nbp) { - if (bp->b_lblkno < nblks) - continue; - if (BUF_LOCK(bp, - LK_EXCLUSIVE | LK_SLEEPFAIL | LK_INTERLOCK, - BO_LOCKPTR(bo)) == ENOLCK) - goto restart; - bp->b_flags |= (B_INVAL | B_RELBUF); - bp->b_flags &= ~(B_ASYNC | B_MANAGED); - brelse(bp); - nandfs_dirty_bufs_decrement(nffsdev); - BO_LOCK(bo); - } - - BO_UNLOCK(bo); - - return (0); -} - -static int -nandfs_truncate(struct vnode *vp, uint64_t newsize) -{ - struct nandfs_device *nffsdev; - struct nandfs_node *node; - struct nandfs_inode *inode; - struct buf *bp = NULL; - uint64_t oblks, nblks, vblk, size, rest; - int error; - - node = VTON(vp); - nffsdev = node->nn_nandfsdev; - inode = &node->nn_inode; - - /* Calculate end of file */ - size = inode->i_size; - - if (newsize == size) { - node->nn_flags |= IN_CHANGE | IN_UPDATE; - nandfs_itimes(vp); - return (0); - } - - if (newsize > size) { - inode->i_size = newsize; - vnode_pager_setsize(vp, newsize); - node->nn_flags |= IN_CHANGE | IN_UPDATE; - nandfs_itimes(vp); - return (0); - } - - nblks = howmany(newsize, nffsdev->nd_blocksize); - oblks = howmany(size, nffsdev->nd_blocksize); - rest = newsize % nffsdev->nd_blocksize; - - if (rest) { - error = nandfs_bmap_lookup(node, nblks - 1, &vblk); - if (error) - return (error); - - if (vblk != 0) - error = nandfs_bread(node, nblks - 1, NOCRED, 0, &bp); - else - error = nandfs_bcreate(node, nblks - 1, NOCRED, 0, &bp); - - if (error) { - if (bp) - brelse(bp); - return (error); - } - - bzero((char *)bp->b_data + rest, - (u_int)(nffsdev->nd_blocksize - rest)); - error = nandfs_dirty_buf(bp, 0); - if (error) - return (error); - } - - DPRINTF(VNCALL, ("%s: vp %p oblks %jx nblks %jx\n", __func__, vp, oblks, - nblks)); - - error = nandfs_bmap_truncate_mapping(node, oblks - 1, nblks - 1); - if (error) { - if (bp) - nandfs_undirty_buf(bp); - return (error); - } - - error = nandfs_vtruncbuf(vp, nblks); - if (error) { - if (bp) - nandfs_undirty_buf(bp); - return (error); - } - - inode->i_size = newsize; - vnode_pager_setsize(vp, newsize); - node->nn_flags |= IN_CHANGE | IN_UPDATE; - nandfs_itimes(vp); - - return (error); -} - -static void -nandfs_itimes_locked(struct vnode *vp) -{ - struct nandfs_node *node; - struct nandfs_inode *inode; - struct timespec ts; - - ASSERT_VI_LOCKED(vp, __func__); - - node = VTON(vp); - inode = &node->nn_inode; - - if ((node->nn_flags & (IN_ACCESS | IN_CHANGE | IN_UPDATE)) == 0) - return; - - if (((vp->v_mount->mnt_kern_flag & - (MNTK_SUSPENDED | MNTK_SUSPEND)) == 0) || - (node->nn_flags & (IN_CHANGE | IN_UPDATE))) - node->nn_flags |= IN_MODIFIED; - - vfs_timestamp(&ts); - if (node->nn_flags & IN_UPDATE) { - inode->i_mtime = ts.tv_sec; - inode->i_mtime_nsec = ts.tv_nsec; - } - if (node->nn_flags & IN_CHANGE) { - inode->i_ctime = ts.tv_sec; - inode->i_ctime_nsec = ts.tv_nsec; - } - - node->nn_flags &= ~(IN_ACCESS | IN_CHANGE | IN_UPDATE); -} - -void -nandfs_itimes(struct vnode *vp) -{ - - VI_LOCK(vp); - nandfs_itimes_locked(vp); - VI_UNLOCK(vp); -} - -static int -nandfs_chmod(struct vnode *vp, int mode, struct ucred *cred, struct thread *td) -{ - struct nandfs_node *node = VTON(vp); - struct nandfs_inode *inode = &node->nn_inode; - uint16_t nmode; - int error = 0; - - DPRINTF(VNCALL, ("%s: vp %p, mode %x, cred %p, td %p\n", __func__, vp, - mode, cred, td)); - /* - * To modify the permissions on a file, must possess VADMIN - * for that file. - */ - if ((error = VOP_ACCESS(vp, VADMIN, cred, td))) - return (error); - - /* - * Privileged processes may set the sticky bit on non-directories, - * as well as set the setgid bit on a file with a group that the - * process is not a member of. Both of these are allowed in - * jail(8). - */ - if (vp->v_type != VDIR && (mode & S_ISTXT)) { - if (priv_check_cred(cred, PRIV_VFS_STICKYFILE)) - return (EFTYPE); - } - if (!groupmember(inode->i_gid, cred) && (mode & ISGID)) { - error = priv_check_cred(cred, PRIV_VFS_SETGID); - if (error) - return (error); - } - - /* - * Deny setting setuid if we are not the file owner. - */ - if ((mode & ISUID) && inode->i_uid != cred->cr_uid) { - error = priv_check_cred(cred, PRIV_VFS_ADMIN); - if (error) - return (error); - } - - nmode = inode->i_mode; - nmode &= ~ALLPERMS; - nmode |= (mode & ALLPERMS); - inode->i_mode = nmode; - node->nn_flags |= IN_CHANGE; - - DPRINTF(VNCALL, ("%s: to mode %x\n", __func__, nmode)); - - return (error); -} - -static int -nandfs_chown(struct vnode *vp, uid_t uid, gid_t gid, struct ucred *cred, - struct thread *td) -{ - struct nandfs_node *node = VTON(vp); - struct nandfs_inode *inode = &node->nn_inode; - uid_t ouid; - gid_t ogid; - int error = 0; - - if (uid == (uid_t)VNOVAL) - uid = inode->i_uid; - if (gid == (gid_t)VNOVAL) - gid = inode->i_gid; - /* - * To modify the ownership of a file, must possess VADMIN for that - * file. - */ - if ((error = VOP_ACCESSX(vp, VWRITE_OWNER, cred, td))) - return (error); - /* - * To change the owner of a file, or change the group of a file to a - * group of which we are not a member, the caller must have - * privilege. - */ - if (((uid != inode->i_uid && uid != cred->cr_uid) || - (gid != inode->i_gid && !groupmember(gid, cred))) && - (error = priv_check_cred(cred, PRIV_VFS_CHOWN))) - return (error); - ogid = inode->i_gid; - ouid = inode->i_uid; - - inode->i_gid = gid; - inode->i_uid = uid; - - node->nn_flags |= IN_CHANGE; - if ((inode->i_mode & (ISUID | ISGID)) && - (ouid != uid || ogid != gid)) { - if (priv_check_cred(cred, PRIV_VFS_RETAINSUGID)) - inode->i_mode &= ~(ISUID | ISGID); - } - DPRINTF(VNCALL, ("%s: vp %p, cred %p, td %p - ret OK\n", __func__, vp, - cred, td)); - return (0); -} - -static int -nandfs_setattr(struct vop_setattr_args *ap) -{ - struct vnode *vp = ap->a_vp; - struct nandfs_node *node = VTON(vp); - struct nandfs_inode *inode = &node->nn_inode; - struct vattr *vap = ap->a_vap; - struct ucred *cred = ap->a_cred; - struct thread *td = curthread; - uint32_t flags; - int error = 0; - - if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) || - (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) || - (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) || - (vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) { - DPRINTF(VNCALL, ("%s: unsettable attribute\n", __func__)); - return (EINVAL); - } - - if (vap->va_flags != VNOVAL) { - DPRINTF(VNCALL, ("%s: vp:%p td:%p flags:%lx\n", __func__, vp, - td, vap->va_flags)); - - if (vp->v_mount->mnt_flag & MNT_RDONLY) - return (EROFS); - /* - * Callers may only modify the file flags on objects they - * have VADMIN rights for. - */ - if ((error = VOP_ACCESS(vp, VADMIN, cred, td))) - return (error); - /* - * Unprivileged processes are not permitted to unset system - * flags, or modify flags if any system flags are set. - * Privileged non-jail processes may not modify system flags - * if securelevel > 0 and any existing system flags are set. - * Privileged jail processes behave like privileged non-jail - * processes if the PR_ALLOW_CHFLAGS permission bit is set; - * otherwise, they behave like unprivileged processes. - */ - - flags = inode->i_flags; - if (!priv_check_cred(cred, PRIV_VFS_SYSFLAGS)) { - if (flags & (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND)) { - error = securelevel_gt(cred, 0); - if (error) - return (error); - } - /* Snapshot flag cannot be set or cleared */ - if (((vap->va_flags & SF_SNAPSHOT) != 0 && - (flags & SF_SNAPSHOT) == 0) || - ((vap->va_flags & SF_SNAPSHOT) == 0 && - (flags & SF_SNAPSHOT) != 0)) - return (EPERM); - - inode->i_flags = vap->va_flags; - } else { - if (flags & (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND) || - (vap->va_flags & UF_SETTABLE) != vap->va_flags) - return (EPERM); - - flags &= SF_SETTABLE; - flags |= (vap->va_flags & UF_SETTABLE); - inode->i_flags = flags; - } - node->nn_flags |= IN_CHANGE; - if (vap->va_flags & (IMMUTABLE | APPEND)) - return (0); - } - if (inode->i_flags & (IMMUTABLE | APPEND)) - return (EPERM); - - if (vap->va_size != (u_quad_t)VNOVAL) { - DPRINTF(VNCALL, ("%s: vp:%p td:%p size:%jx\n", __func__, vp, td, - (uintmax_t)vap->va_size)); - - switch (vp->v_type) { - case VDIR: - return (EISDIR); - case VLNK: - case VREG: - if (vp->v_mount->mnt_flag & MNT_RDONLY) - return (EROFS); - if ((inode->i_flags & SF_SNAPSHOT) != 0) - return (EPERM); - break; - default: - return (0); - } - - if (vap->va_size > node->nn_nandfsdev->nd_maxfilesize) - return (EFBIG); - - KASSERT((vp->v_type == VREG), ("Set size %d", vp->v_type)); - nandfs_truncate(vp, vap->va_size); - node->nn_flags |= IN_CHANGE; - - return (0); - } - - if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) { - if (vp->v_mount->mnt_flag & MNT_RDONLY) - return (EROFS); - DPRINTF(VNCALL, ("%s: vp:%p td:%p uid/gid %x/%x\n", __func__, - vp, td, vap->va_uid, vap->va_gid)); - error = nandfs_chown(vp, vap->va_uid, vap->va_gid, cred, td); - if (error) - return (error); - } - - if (vap->va_mode != (mode_t)VNOVAL) { - if (vp->v_mount->mnt_flag & MNT_RDONLY) - return (EROFS); - DPRINTF(VNCALL, ("%s: vp:%p td:%p mode %x\n", __func__, vp, td, - vap->va_mode)); - - error = nandfs_chmod(vp, (int)vap->va_mode, cred, td); - if (error) - return (error); - } - if (vap->va_atime.tv_sec != VNOVAL || - vap->va_mtime.tv_sec != VNOVAL || - vap->va_birthtime.tv_sec != VNOVAL) { - DPRINTF(VNCALL, ("%s: vp:%p td:%p time a/m/b %jx/%jx/%jx\n", - __func__, vp, td, (uintmax_t)vap->va_atime.tv_sec, - (uintmax_t)vap->va_mtime.tv_sec, - (uintmax_t)vap->va_birthtime.tv_sec)); - - if (vap->va_atime.tv_sec != VNOVAL) - node->nn_flags |= IN_ACCESS; - if (vap->va_mtime.tv_sec != VNOVAL) - node->nn_flags |= IN_CHANGE | IN_UPDATE; - if (vap->va_birthtime.tv_sec != VNOVAL) - node->nn_flags |= IN_MODIFIED; - nandfs_itimes(vp); - return (0); - } - - return (0); -} - -static int -nandfs_open(struct vop_open_args *ap) -{ - struct nandfs_node *node = VTON(ap->a_vp); - uint64_t filesize; - - DPRINTF(VNCALL, ("nandfs_open called ap->a_mode %x\n", ap->a_mode)); - - if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK) - return (EOPNOTSUPP); - - if ((node->nn_inode.i_flags & APPEND) && - (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE) - return (EPERM); - - filesize = node->nn_inode.i_size; - vnode_create_vobject(ap->a_vp, filesize, ap->a_td); - - return (0); -} - -static int -nandfs_close(struct vop_close_args *ap) -{ - struct vnode *vp = ap->a_vp; - struct nandfs_node *node = VTON(vp); - - DPRINTF(VNCALL, ("%s: vp %p node %p\n", __func__, vp, node)); - - mtx_lock(&vp->v_interlock); - if (vp->v_usecount > 1) - nandfs_itimes_locked(vp); - mtx_unlock(&vp->v_interlock); - - return (0); -} - -static int -nandfs_check_possible(struct vnode *vp, struct vattr *vap, mode_t mode) -{ - - /* Check if we are allowed to write */ - switch (vap->va_type) { - case VDIR: - case VLNK: - case VREG: - /* - * Normal nodes: check if we're on a read-only mounted - * filingsystem and bomb out if we're trying to write. - */ - if ((mode & VMODIFY_PERMS) && (vp->v_mount->mnt_flag & MNT_RDONLY)) - return (EROFS); - break; - case VBLK: - case VCHR: - case VSOCK: - case VFIFO: - /* - * Special nodes: even on read-only mounted filingsystems - * these are allowed to be written to if permissions allow. - */ - break; - default: - /* No idea what this is */ - return (EINVAL); - } - - /* No one may write immutable files */ - if ((mode & VWRITE) && (VTON(vp)->nn_inode.i_flags & IMMUTABLE)) - return (EPERM); - - return (0); -} - -static int -nandfs_check_permitted(struct vnode *vp, struct vattr *vap, mode_t mode, - struct ucred *cred) -{ - - return (vaccess(vp->v_type, vap->va_mode, vap->va_uid, vap->va_gid, mode, - cred, NULL)); -} - -static int -nandfs_advlock(struct vop_advlock_args *ap) -{ - struct nandfs_node *nvp; - quad_t size; - - nvp = VTON(ap->a_vp); - size = nvp->nn_inode.i_size; - return (lf_advlock(ap, &(nvp->nn_lockf), size)); -} - -static int -nandfs_access(struct vop_access_args *ap) -{ - struct vnode *vp = ap->a_vp; - accmode_t accmode = ap->a_accmode; - struct ucred *cred = ap->a_cred; - struct vattr vap; - int error; - - DPRINTF(VNCALL, ("%s: vp:%p mode: %x\n", __func__, vp, accmode)); - - error = VOP_GETATTR(vp, &vap, NULL); - if (error) - return (error); - - error = nandfs_check_possible(vp, &vap, accmode); - if (error) - return (error); - - error = nandfs_check_permitted(vp, &vap, accmode, cred); - - return (error); -} - -static int -nandfs_print(struct vop_print_args *ap) -{ - struct vnode *vp = ap->a_vp; - struct nandfs_node *nvp = VTON(vp); - - printf("\tvp=%p, nandfs_node=%p\n", vp, nvp); - printf("nandfs inode %#jx\n", (uintmax_t)nvp->nn_ino); - printf("flags = 0x%b\n", (u_int)nvp->nn_flags, PRINT_NODE_FLAGS); - - return (0); -} - -static void -nandfs_read_filebuf(struct nandfs_node *node, struct buf *bp) -{ - struct nandfs_device *nandfsdev = node->nn_nandfsdev; - struct buf *nbp; - nandfs_daddr_t vblk, pblk; - nandfs_lbn_t from; - uint32_t blocksize; - int error = 0; - int blk2dev = nandfsdev->nd_blocksize / DEV_BSIZE; - - /* - * Translate all the block sectors into a series of buffers to read - * asynchronously from the nandfs device. Note that this lookup may - * induce readin's too. - */ - - blocksize = nandfsdev->nd_blocksize; - if (bp->b_bcount / blocksize != 1) - panic("invalid b_count in bp %p\n", bp); - - from = bp->b_blkno; - - DPRINTF(READ, ("\tread in from inode %#jx blkno %#jx" - " count %#lx\n", (uintmax_t)node->nn_ino, from, - bp->b_bcount)); - - /* Get virtual block numbers for the vnode's buffer span */ - error = nandfs_bmap_lookup(node, from, &vblk); - if (error) { - bp->b_error = EINVAL; - bp->b_ioflags |= BIO_ERROR; - bufdone(bp); - return; - } - - /* Translate virtual block numbers to physical block numbers */ - error = nandfs_vtop(node, vblk, &pblk); - if (error) { - bp->b_error = EINVAL; - bp->b_ioflags |= BIO_ERROR; - bufdone(bp); - return; - } - - /* Issue translated blocks */ - bp->b_resid = bp->b_bcount; - - /* Note virtual block 0 marks not mapped */ - if (vblk == 0) { - vfs_bio_clrbuf(bp); - bufdone(bp); - return; - } - - nbp = bp; - nbp->b_blkno = pblk * blk2dev; - bp->b_iooffset = dbtob(nbp->b_blkno); - MPASS(bp->b_iooffset >= 0); - BO_STRATEGY(&nandfsdev->nd_devvp->v_bufobj, nbp); - nandfs_vblk_set(bp, vblk); - DPRINTF(READ, ("read_filebuf : ino %#jx blk %#jx -> " - "%#jx -> %#jx [bp %p]\n", (uintmax_t)node->nn_ino, - (uintmax_t)(from), (uintmax_t)vblk, - (uintmax_t)pblk, nbp)); -} - -static void -nandfs_write_filebuf(struct nandfs_node *node, struct buf *bp) -{ - struct nandfs_device *nandfsdev = node->nn_nandfsdev; - - bp->b_iooffset = dbtob(bp->b_blkno); - MPASS(bp->b_iooffset >= 0); - BO_STRATEGY(&nandfsdev->nd_devvp->v_bufobj, bp); -} - -static int -nandfs_strategy(struct vop_strategy_args *ap) -{ - struct vnode *vp = ap->a_vp; - struct buf *bp = ap->a_bp; - struct nandfs_node *node = VTON(vp); - - - /* check if we ought to be here */ - KASSERT((vp->v_type != VBLK && vp->v_type != VCHR), - ("nandfs_strategy on type %d", vp->v_type)); - - /* Translate if needed and pass on */ - if (bp->b_iocmd == BIO_READ) { - nandfs_read_filebuf(node, bp); - return (0); - } - - /* Send to segment collector */ - nandfs_write_filebuf(node, bp); - return (0); -} - -static int -nandfs_readdir(struct vop_readdir_args *ap) -{ - struct uio *uio = ap->a_uio; - struct vnode *vp = ap->a_vp; - struct nandfs_node *node = VTON(vp); - struct nandfs_dir_entry *ndirent; - struct dirent dirent; - struct buf *bp; - uint64_t file_size, diroffset, transoffset, blkoff; - uint64_t blocknr; - uint32_t blocksize = node->nn_nandfsdev->nd_blocksize; - uint8_t *pos, name_len; - int error; - - DPRINTF(READDIR, ("nandfs_readdir called\n")); - - if (vp->v_type != VDIR) - return (ENOTDIR); - - file_size = node->nn_inode.i_size; - DPRINTF(READDIR, ("nandfs_readdir filesize %jd resid %zd\n", - (uintmax_t)file_size, uio->uio_resid )); - - /* We are called just as long as we keep on pushing data in */ - error = 0; - if ((uio->uio_offset < file_size) && - (uio->uio_resid >= sizeof(struct dirent))) { - diroffset = uio->uio_offset; - transoffset = diroffset; - - blocknr = diroffset / blocksize; - blkoff = diroffset % blocksize; - error = nandfs_bread(node, blocknr, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (EIO); - } - while (diroffset < file_size) { - DPRINTF(READDIR, ("readdir : offset = %"PRIu64"\n", - diroffset)); - if (blkoff >= blocksize) { - blkoff = 0; blocknr++; - brelse(bp); - error = nandfs_bread(node, blocknr, NOCRED, 0, - &bp); - if (error) { - brelse(bp); - return (EIO); - } - } - - /* Read in one dirent */ - pos = (uint8_t *)bp->b_data + blkoff; - ndirent = (struct nandfs_dir_entry *)pos; - - name_len = ndirent->name_len; - memset(&dirent, 0, sizeof(dirent)); - dirent.d_fileno = ndirent->inode; - if (dirent.d_fileno) { - dirent.d_type = ndirent->file_type; - dirent.d_namlen = name_len; - strncpy(dirent.d_name, ndirent->name, name_len); - dirent.d_reclen = GENERIC_DIRSIZ(&dirent); - /* NOTE: d_off is the offset of the *next* entry. */ - dirent.d_off = diroffset + ndirent->rec_len; - dirent_terminate(&dirent); - DPRINTF(READDIR, ("copying `%*.*s`\n", name_len, - name_len, dirent.d_name)); - } - - /* - * If there isn't enough space in the uio to return a - * whole dirent, break off read - */ - if (uio->uio_resid < GENERIC_DIRSIZ(&dirent)) - break; - - /* Transfer */ - if (dirent.d_fileno) - uiomove(&dirent, dirent.d_reclen, uio); - - /* Advance */ - diroffset += ndirent->rec_len; - blkoff += ndirent->rec_len; - - /* Remember the last entry we transferred */ - transoffset = diroffset; - } - brelse(bp); - - /* Pass on last transferred offset */ - uio->uio_offset = transoffset; - } - - if (ap->a_eofflag) - *ap->a_eofflag = (uio->uio_offset >= file_size); - - return (error); -} - -static int -nandfs_dirempty(struct vnode *dvp, uint64_t parentino, struct ucred *cred) -{ - struct nandfs_node *dnode = VTON(dvp); - struct nandfs_dir_entry *dirent; - uint64_t file_size = dnode->nn_inode.i_size; - uint64_t blockcount = dnode->nn_inode.i_blocks; - uint64_t blocknr; - uint32_t blocksize = dnode->nn_nandfsdev->nd_blocksize; - uint32_t limit; - uint32_t off; - uint8_t *pos; - struct buf *bp; - int error; - - DPRINTF(LOOKUP, ("%s: dvp %p parentino %#jx cred %p\n", __func__, dvp, - (uintmax_t)parentino, cred)); - - KASSERT((file_size != 0), ("nandfs_dirempty for NULL dir %p", dvp)); - - blocknr = 0; - while (blocknr < blockcount) { - error = nandfs_bread(dnode, blocknr, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (0); - } - - pos = (uint8_t *)bp->b_data; - off = 0; - - if (blocknr == (blockcount - 1)) - limit = file_size % blocksize; - else - limit = blocksize; - - while (off < limit) { - dirent = (struct nandfs_dir_entry *)(pos + off); - off += dirent->rec_len; - - if (dirent->inode == 0) - continue; - - switch (dirent->name_len) { - case 0: - break; - case 1: - if (dirent->name[0] != '.') - goto notempty; - - KASSERT(dirent->inode == dnode->nn_ino, - (".'s inode does not match dir")); - break; - case 2: - if (dirent->name[0] != '.' && - dirent->name[1] != '.') - goto notempty; - - KASSERT(dirent->inode == parentino, - ("..'s inode does not match parent")); - break; - default: - goto notempty; - } - } - - brelse(bp); - blocknr++; - } - - return (1); -notempty: - brelse(bp); - return (0); -} - -static int -nandfs_link(struct vop_link_args *ap) -{ - struct vnode *tdvp = ap->a_tdvp; - struct vnode *vp = ap->a_vp; - struct componentname *cnp = ap->a_cnp; - struct nandfs_node *node = VTON(vp); - struct nandfs_inode *inode = &node->nn_inode; - int error; - - if (inode->i_links_count >= NANDFS_LINK_MAX) - return (EMLINK); - - if (inode->i_flags & (IMMUTABLE | APPEND)) - return (EPERM); - - /* Update link count */ - inode->i_links_count++; - - /* Add dir entry */ - error = nandfs_add_dirent(tdvp, node->nn_ino, cnp->cn_nameptr, - cnp->cn_namelen, IFTODT(inode->i_mode)); - if (error) { - inode->i_links_count--; - } - - node->nn_flags |= IN_CHANGE; - nandfs_itimes(vp); - DPRINTF(VNCALL, ("%s: tdvp %p vp %p cnp %p\n", - __func__, tdvp, vp, cnp)); - - return (0); -} - -static int -nandfs_create(struct vop_create_args *ap) -{ - struct vnode *dvp = ap->a_dvp; - struct vnode **vpp = ap->a_vpp; - struct componentname *cnp = ap->a_cnp; - uint16_t mode = MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode); - struct nandfs_node *dir_node = VTON(dvp); - struct nandfsmount *nmp = dir_node->nn_nmp; - struct nandfs_node *node; - int error; - - DPRINTF(VNCALL, ("%s: dvp %p\n", __func__, dvp)); - - if (nandfs_fs_full(dir_node->nn_nandfsdev)) - return (ENOSPC); - - /* Create new vnode/inode */ - error = nandfs_node_create(nmp, &node, mode); - if (error) - return (error); - node->nn_inode.i_gid = dir_node->nn_inode.i_gid; - node->nn_inode.i_uid = cnp->cn_cred->cr_uid; - - /* Add new dir entry */ - error = nandfs_add_dirent(dvp, node->nn_ino, cnp->cn_nameptr, - cnp->cn_namelen, IFTODT(mode)); - if (error) { - if (nandfs_node_destroy(node)) { - nandfs_error("%s: error destroying node %p\n", - __func__, node); - } - return (error); - } - *vpp = NTOV(node); - if ((cnp->cn_flags & MAKEENTRY) != 0) - cache_enter(dvp, *vpp, cnp); - - DPRINTF(VNCALL, ("created file vp %p nandnode %p ino %jx\n", *vpp, node, - (uintmax_t)node->nn_ino)); - return (0); -} - -static int -nandfs_remove(struct vop_remove_args *ap) -{ - struct vnode *vp = ap->a_vp; - struct vnode *dvp = ap->a_dvp; - struct nandfs_node *node = VTON(vp); - struct nandfs_node *dnode = VTON(dvp); - struct componentname *cnp = ap->a_cnp; - - DPRINTF(VNCALL, ("%s: dvp %p vp %p nandnode %p ino %#jx link %d\n", - __func__, dvp, vp, node, (uintmax_t)node->nn_ino, - node->nn_inode.i_links_count)); - - if (vp->v_type == VDIR) - return (EISDIR); - - /* Files marked as immutable or append-only cannot be deleted. */ - if ((node->nn_inode.i_flags & (IMMUTABLE | APPEND | NOUNLINK)) || - (dnode->nn_inode.i_flags & APPEND)) - return (EPERM); - - nandfs_remove_dirent(dvp, node, cnp); - node->nn_inode.i_links_count--; - node->nn_flags |= IN_CHANGE; - - return (0); -} - -/* - * Check if source directory is in the path of the target directory. - * Target is supplied locked, source is unlocked. - * The target is always vput before returning. - */ -static int -nandfs_checkpath(struct nandfs_node *src, struct nandfs_node *dest, - struct ucred *cred) -{ - struct vnode *vp; - int error, rootino; - struct nandfs_dir_entry dirent; - - vp = NTOV(dest); - if (src->nn_ino == dest->nn_ino) { - error = EEXIST; - goto out; - } - rootino = NANDFS_ROOT_INO; - error = 0; - if (dest->nn_ino == rootino) - goto out; - - for (;;) { - if (vp->v_type != VDIR) { - error = ENOTDIR; - break; - } - - error = vn_rdwr(UIO_READ, vp, (caddr_t)&dirent, - NANDFS_DIR_REC_LEN(2), (off_t)0, UIO_SYSSPACE, - IO_NODELOCKED | IO_NOMACCHECK, cred, NOCRED, - NULL, NULL); - if (error != 0) - break; - if (dirent.name_len != 2 || - dirent.name[0] != '.' || - dirent.name[1] != '.') { - error = ENOTDIR; - break; - } - if (dirent.inode == src->nn_ino) { - error = EINVAL; - break; - } - if (dirent.inode == rootino) - break; - vput(vp); - if ((error = VFS_VGET(vp->v_mount, dirent.inode, - LK_EXCLUSIVE, &vp)) != 0) { - vp = NULL; - break; - } - } - -out: - if (error == ENOTDIR) - printf("checkpath: .. not a directory\n"); - if (vp != NULL) - vput(vp); - return (error); -} - -static int -nandfs_rename(struct vop_rename_args *ap) -{ - struct vnode *tvp = ap->a_tvp; - struct vnode *tdvp = ap->a_tdvp; - struct vnode *fvp = ap->a_fvp; - struct vnode *fdvp = ap->a_fdvp; - struct componentname *tcnp = ap->a_tcnp; - struct componentname *fcnp = ap->a_fcnp; - int doingdirectory = 0, oldparent = 0, newparent = 0; - int error = 0; - - struct nandfs_node *fdnode, *fnode, *fnode1; - struct nandfs_node *tdnode = VTON(tdvp); - struct nandfs_node *tnode; - - uint32_t tdflags, fflags, fdflags; - uint16_t mode; - - DPRINTF(VNCALL, ("%s: fdvp:%p fvp:%p tdvp:%p tdp:%p\n", __func__, fdvp, - fvp, tdvp, tvp)); - - /* - * Check for cross-device rename. - */ - if ((fvp->v_mount != tdvp->v_mount) || - (tvp && (fvp->v_mount != tvp->v_mount))) { - error = EXDEV; -abortit: - if (tdvp == tvp) - vrele(tdvp); - else - vput(tdvp); - if (tvp) - vput(tvp); - vrele(fdvp); - vrele(fvp); - return (error); - } - - tdflags = tdnode->nn_inode.i_flags; - if (tvp && - ((VTON(tvp)->nn_inode.i_flags & (NOUNLINK | IMMUTABLE | APPEND)) || - (tdflags & APPEND))) { - error = EPERM; - goto abortit; - } - - /* - * Renaming a file to itself has no effect. The upper layers should - * not call us in that case. Temporarily just warn if they do. - */ - if (fvp == tvp) { - printf("nandfs_rename: fvp == tvp (can't happen)\n"); - error = 0; - goto abortit; - } - - if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0) - goto abortit; - - fdnode = VTON(fdvp); - fnode = VTON(fvp); - - if (fnode->nn_inode.i_links_count >= NANDFS_LINK_MAX) { - VOP_UNLOCK(fvp, 0); - error = EMLINK; - goto abortit; - } - - fflags = fnode->nn_inode.i_flags; - fdflags = fdnode->nn_inode.i_flags; - - if ((fflags & (NOUNLINK | IMMUTABLE | APPEND)) || - (fdflags & APPEND)) { - VOP_UNLOCK(fvp, 0); - error = EPERM; - goto abortit; - } - - mode = fnode->nn_inode.i_mode; - if ((mode & S_IFMT) == S_IFDIR) { - /* - * Avoid ".", "..", and aliases of "." for obvious reasons. - */ - - if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') || - (fdvp == fvp) || - ((fcnp->cn_flags | tcnp->cn_flags) & ISDOTDOT) || - (fnode->nn_flags & IN_RENAME)) { - VOP_UNLOCK(fvp, 0); - error = EINVAL; - goto abortit; - } - fnode->nn_flags |= IN_RENAME; - doingdirectory = 1; - DPRINTF(VNCALL, ("%s: doingdirectory dvp %p\n", __func__, - tdvp)); - oldparent = fdnode->nn_ino; - } - - vrele(fdvp); - - tnode = NULL; - if (tvp) - tnode = VTON(tvp); - - /* - * Bump link count on fvp while we are moving stuff around. If we - * crash before completing the work, the link count may be wrong - * but correctable. - */ - fnode->nn_inode.i_links_count++; - - /* Check for in path moving XXX */ - error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_thread); - VOP_UNLOCK(fvp, 0); - if (oldparent != tdnode->nn_ino) - newparent = tdnode->nn_ino; - if (doingdirectory && newparent) { - if (error) /* write access check above */ - goto bad; - if (tnode != NULL) - vput(tvp); - - error = nandfs_checkpath(fnode, tdnode, tcnp->cn_cred); - if (error) - goto out; - - VREF(tdvp); - error = relookup(tdvp, &tvp, tcnp); - if (error) - goto out; - vrele(tdvp); - tdnode = VTON(tdvp); - tnode = NULL; - if (tvp) - tnode = VTON(tvp); - } - - /* - * If the target doesn't exist, link the target to the source and - * unlink the source. Otherwise, rewrite the target directory to - * reference the source and remove the original entry. - */ - - if (tvp == NULL) { - /* - * Account for ".." in new directory. - */ - if (doingdirectory && fdvp != tdvp) - tdnode->nn_inode.i_links_count++; - - DPRINTF(VNCALL, ("%s: new entry in dvp:%p\n", __func__, tdvp)); - /* - * Add name in new directory. - */ - error = nandfs_add_dirent(tdvp, fnode->nn_ino, tcnp->cn_nameptr, - tcnp->cn_namelen, IFTODT(fnode->nn_inode.i_mode)); - if (error) { - if (doingdirectory && fdvp != tdvp) - tdnode->nn_inode.i_links_count--; - goto bad; - } - - vput(tdvp); - } else { - /* - * If the parent directory is "sticky", then the user must - * own the parent directory, or the destination of the rename, - * otherwise the destination may not be changed (except by - * root). This implements append-only directories. - */ - if ((tdnode->nn_inode.i_mode & S_ISTXT) && - tcnp->cn_cred->cr_uid != 0 && - tcnp->cn_cred->cr_uid != tdnode->nn_inode.i_uid && - tnode->nn_inode.i_uid != tcnp->cn_cred->cr_uid) { - error = EPERM; - goto bad; - } - /* - * Target must be empty if a directory and have no links - * to it. Also, ensure source and target are compatible - * (both directories, or both not directories). - */ - mode = tnode->nn_inode.i_mode; - if ((mode & S_IFMT) == S_IFDIR) { - if (!nandfs_dirempty(tvp, tdnode->nn_ino, - tcnp->cn_cred)) { - error = ENOTEMPTY; - goto bad; - } - if (!doingdirectory) { - error = ENOTDIR; - goto bad; - } - /* - * Update name cache since directory is going away. - */ - cache_purge(tdvp); - } else if (doingdirectory) { - error = EISDIR; - goto bad; - } - - DPRINTF(VNCALL, ("%s: update entry dvp:%p\n", __func__, tdvp)); - /* - * Change name tcnp in tdvp to point at fvp. - */ - error = nandfs_update_dirent(tdvp, fnode, tnode); - if (error) - goto bad; - - if (doingdirectory && !newparent) - tdnode->nn_inode.i_links_count--; - - vput(tdvp); - - tnode->nn_inode.i_links_count--; - vput(tvp); - tnode = NULL; - } - - /* - * Unlink the source. - */ - fcnp->cn_flags &= ~MODMASK; - fcnp->cn_flags |= LOCKPARENT | LOCKLEAF; - VREF(fdvp); - error = relookup(fdvp, &fvp, fcnp); - if (error == 0) - vrele(fdvp); - if (fvp != NULL) { - fnode1 = VTON(fvp); - fdnode = VTON(fdvp); - } else { - /* - * From name has disappeared. - */ - if (doingdirectory) - panic("nandfs_rename: lost dir entry"); - vrele(ap->a_fvp); - return (0); - } - - DPRINTF(VNCALL, ("%s: unlink source fnode:%p\n", __func__, fnode)); - - /* - * Ensure that the directory entry still exists and has not - * changed while the new name has been entered. If the source is - * a file then the entry may have been unlinked or renamed. In - * either case there is no further work to be done. If the source - * is a directory then it cannot have been rmdir'ed; its link - * count of three would cause a rmdir to fail with ENOTEMPTY. - * The IN_RENAME flag ensures that it cannot be moved by another - * rename. - */ - if (fnode != fnode1) { - if (doingdirectory) - panic("nandfs: lost dir entry"); - } else { - /* - * If the source is a directory with a - * new parent, the link count of the old - * parent directory must be decremented - * and ".." set to point to the new parent. - */ - if (doingdirectory && newparent) { - DPRINTF(VNCALL, ("%s: new parent %#jx -> %#jx\n", - __func__, (uintmax_t) oldparent, - (uintmax_t) newparent)); - error = nandfs_update_parent_dir(fvp, newparent); - if (!error) { - fdnode->nn_inode.i_links_count--; - fdnode->nn_flags |= IN_CHANGE; - } - } - error = nandfs_remove_dirent(fdvp, fnode, fcnp); - if (!error) { - fnode->nn_inode.i_links_count--; - fnode->nn_flags |= IN_CHANGE; - } - fnode->nn_flags &= ~IN_RENAME; - } - if (fdnode) - vput(fdvp); - if (fnode) - vput(fvp); - vrele(ap->a_fvp); - return (error); - -bad: - DPRINTF(VNCALL, ("%s: error:%d\n", __func__, error)); - if (tnode) - vput(NTOV(tnode)); - vput(NTOV(tdnode)); -out: - if (doingdirectory) - fnode->nn_flags &= ~IN_RENAME; - if (vn_lock(fvp, LK_EXCLUSIVE) == 0) { - fnode->nn_inode.i_links_count--; - fnode->nn_flags |= IN_CHANGE; - fnode->nn_flags &= ~IN_RENAME; - vput(fvp); - } else - vrele(fvp); - return (error); -} - -static int -nandfs_mkdir(struct vop_mkdir_args *ap) -{ - struct vnode *dvp = ap->a_dvp; - struct vnode **vpp = ap->a_vpp; - struct componentname *cnp = ap->a_cnp; - struct nandfs_node *dir_node = VTON(dvp); - struct nandfs_inode *dir_inode = &dir_node->nn_inode; - struct nandfs_node *node; - struct nandfsmount *nmp = dir_node->nn_nmp; - uint16_t mode = MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode); - int error; - - DPRINTF(VNCALL, ("%s: dvp %p\n", __func__, dvp)); - - if (nandfs_fs_full(dir_node->nn_nandfsdev)) - return (ENOSPC); - - if (dir_inode->i_links_count >= NANDFS_LINK_MAX) - return (EMLINK); - - error = nandfs_node_create(nmp, &node, mode); - if (error) - return (error); - - node->nn_inode.i_gid = dir_node->nn_inode.i_gid; - node->nn_inode.i_uid = cnp->cn_cred->cr_uid; - - *vpp = NTOV(node); - - error = nandfs_add_dirent(dvp, node->nn_ino, cnp->cn_nameptr, - cnp->cn_namelen, IFTODT(mode)); - if (error) { - vput(*vpp); - return (error); - } - - dir_node->nn_inode.i_links_count++; - dir_node->nn_flags |= IN_CHANGE; - - error = nandfs_init_dir(NTOV(node), node->nn_ino, dir_node->nn_ino); - if (error) { - vput(NTOV(node)); - return (error); - } - - DPRINTF(VNCALL, ("created dir vp %p nandnode %p ino %jx\n", *vpp, node, - (uintmax_t)node->nn_ino)); - return (0); -} - -static int -nandfs_mknod(struct vop_mknod_args *ap) -{ - struct vnode *dvp = ap->a_dvp; - struct vnode **vpp = ap->a_vpp; - struct vattr *vap = ap->a_vap; - uint16_t mode = MAKEIMODE(vap->va_type, vap->va_mode); - struct componentname *cnp = ap->a_cnp; - struct nandfs_node *dir_node = VTON(dvp); - struct nandfsmount *nmp = dir_node->nn_nmp; - struct nandfs_node *node; - int error; - - if (nandfs_fs_full(dir_node->nn_nandfsdev)) - return (ENOSPC); - - error = nandfs_node_create(nmp, &node, mode); - if (error) - return (error); - node->nn_inode.i_gid = dir_node->nn_inode.i_gid; - node->nn_inode.i_uid = cnp->cn_cred->cr_uid; - if (vap->va_rdev != VNOVAL) - node->nn_inode.i_special = vap->va_rdev; - - *vpp = NTOV(node); - - if (nandfs_add_dirent(dvp, node->nn_ino, cnp->cn_nameptr, - cnp->cn_namelen, IFTODT(mode))) { - vput(*vpp); - return (ENOTDIR); - } - - node->nn_flags |= IN_ACCESS | IN_CHANGE | IN_UPDATE; - - return (0); -} - -static int -nandfs_symlink(struct vop_symlink_args *ap) -{ - struct vnode **vpp = ap->a_vpp; - struct vnode *dvp = ap->a_dvp; - uint16_t mode = MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode); - struct componentname *cnp = ap->a_cnp; - struct nandfs_node *dir_node = VTON(dvp); - struct nandfsmount *nmp = dir_node->nn_nmp; - struct nandfs_node *node; - int len, error; - - if (nandfs_fs_full(dir_node->nn_nandfsdev)) - return (ENOSPC); - - error = nandfs_node_create(nmp, &node, S_IFLNK | mode); - if (error) - return (error); - node->nn_inode.i_gid = dir_node->nn_inode.i_gid; - node->nn_inode.i_uid = cnp->cn_cred->cr_uid; - - *vpp = NTOV(node); - - if (nandfs_add_dirent(dvp, node->nn_ino, cnp->cn_nameptr, - cnp->cn_namelen, IFTODT(mode))) { - vput(*vpp); - return (ENOTDIR); - } - - - len = strlen(ap->a_target); - error = vn_rdwr(UIO_WRITE, *vpp, __DECONST(void *, ap->a_target), - len, (off_t)0, UIO_SYSSPACE, IO_NODELOCKED | IO_NOMACCHECK, - cnp->cn_cred, NOCRED, NULL, NULL); - if (error) - vput(*vpp); - - return (error); -} - -static int -nandfs_readlink(struct vop_readlink_args *ap) -{ - struct vnode *vp = ap->a_vp; - - return (VOP_READ(vp, ap->a_uio, 0, ap->a_cred)); -} - -static int -nandfs_rmdir(struct vop_rmdir_args *ap) -{ - struct vnode *vp = ap->a_vp; - struct vnode *dvp = ap->a_dvp; - struct componentname *cnp = ap->a_cnp; - struct nandfs_node *node, *dnode; - uint32_t dflag, flag; - int error = 0; - - node = VTON(vp); - dnode = VTON(dvp); - - /* Files marked as immutable or append-only cannot be deleted. */ - if ((node->nn_inode.i_flags & (IMMUTABLE | APPEND | NOUNLINK)) || - (dnode->nn_inode.i_flags & APPEND)) - return (EPERM); - - DPRINTF(VNCALL, ("%s: dvp %p vp %p nandnode %p ino %#jx\n", __func__, - dvp, vp, node, (uintmax_t)node->nn_ino)); - - if (node->nn_inode.i_links_count < 2) - return (EINVAL); - - if (!nandfs_dirempty(vp, dnode->nn_ino, cnp->cn_cred)) - return (ENOTEMPTY); - - /* Files marked as immutable or append-only cannot be deleted. */ - dflag = dnode->nn_inode.i_flags; - flag = node->nn_inode.i_flags; - if ((dflag & APPEND) || - (flag & (NOUNLINK | IMMUTABLE | APPEND))) { - return (EPERM); - } - - if (vp->v_mountedhere != 0) - return (EINVAL); - - nandfs_remove_dirent(dvp, node, cnp); - dnode->nn_inode.i_links_count -= 1; - dnode->nn_flags |= IN_CHANGE; - - cache_purge(dvp); - - error = nandfs_truncate(vp, (uint64_t)0); - if (error) - return (error); - - node->nn_inode.i_links_count -= 2; - node->nn_flags |= IN_CHANGE; - - cache_purge(vp); - - return (error); -} - -static int -nandfs_fsync(struct vop_fsync_args *ap) -{ - struct vnode *vp = ap->a_vp; - struct nandfs_node *node = VTON(vp); - int locked; - - DPRINTF(VNCALL, ("%s: vp %p nandnode %p ino %#jx\n", __func__, vp, - node, (uintmax_t)node->nn_ino)); - - /* - * Start syncing vnode only if inode was modified or - * there are some dirty buffers - */ - if (VTON(vp)->nn_flags & IN_MODIFIED || - vp->v_bufobj.bo_dirty.bv_cnt) { - locked = VOP_ISLOCKED(vp); - VOP_UNLOCK(vp, 0); - nandfs_wakeup_wait_sync(node->nn_nandfsdev, SYNCER_FSYNC); - VOP_LOCK(vp, locked | LK_RETRY); - } - - return (0); -} - -static int -nandfs_bmap(struct vop_bmap_args *ap) -{ - struct vnode *vp = ap->a_vp; - struct nandfs_node *nnode = VTON(vp); - struct nandfs_device *nandfsdev = nnode->nn_nandfsdev; - nandfs_daddr_t l2vmap, v2pmap; - int error; - int blk2dev = nandfsdev->nd_blocksize / DEV_BSIZE; - - DPRINTF(VNCALL, ("%s: vp %p nandnode %p ino %#jx\n", __func__, vp, - nnode, (uintmax_t)nnode->nn_ino)); - - if (ap->a_bop != NULL) - *ap->a_bop = &nandfsdev->nd_devvp->v_bufobj; - if (ap->a_bnp == NULL) - return (0); - if (ap->a_runp != NULL) - *ap->a_runp = 0; - if (ap->a_runb != NULL) - *ap->a_runb = 0; - - /* - * Translate all the block sectors into a series of buffers to read - * asynchronously from the nandfs device. Note that this lookup may - * induce readin's too. - */ - - /* Get virtual block numbers for the vnode's buffer span */ - error = nandfs_bmap_lookup(nnode, ap->a_bn, &l2vmap); - if (error) - return (-1); - - /* Translate virtual block numbers to physical block numbers */ - error = nandfs_vtop(nnode, l2vmap, &v2pmap); - if (error) - return (-1); - - /* Note virtual block 0 marks not mapped */ - if (l2vmap == 0) - *ap->a_bnp = -1; - else - *ap->a_bnp = v2pmap * blk2dev; /* in DEV_BSIZE */ - - DPRINTF(VNCALL, ("%s: vp %p nandnode %p ino %#jx lblk %jx -> blk %jx\n", - __func__, vp, nnode, (uintmax_t)nnode->nn_ino, (uintmax_t)ap->a_bn, - (uintmax_t)*ap->a_bnp )); - - return (0); -} - -static void -nandfs_force_syncer(struct nandfsmount *nmp) -{ - - nmp->nm_flags |= NANDFS_FORCE_SYNCER; - nandfs_wakeup_wait_sync(nmp->nm_nandfsdev, SYNCER_FFORCE); -} - -static int -nandfs_ioctl(struct vop_ioctl_args *ap) -{ - struct vnode *vp = ap->a_vp; - u_long command = ap->a_command; - caddr_t data = ap->a_data; - struct nandfs_node *node = VTON(vp); - struct nandfs_device *nandfsdev = node->nn_nandfsdev; - struct nandfsmount *nmp = node->nn_nmp; - uint64_t *tab, *cno; - struct nandfs_seg_stat *nss; - struct nandfs_cpmode *ncpm; - struct nandfs_argv *nargv; - struct nandfs_cpstat *ncp; - int error; - - DPRINTF(VNCALL, ("%s: %x\n", __func__, (uint32_t)command)); - - error = priv_check(ap->a_td, PRIV_VFS_MOUNT); - if (error) - return (error); - - if (nmp->nm_ronly) { - switch (command) { - case NANDFS_IOCTL_GET_FSINFO: - case NANDFS_IOCTL_GET_SUSTAT: - case NANDFS_IOCTL_GET_CPINFO: - case NANDFS_IOCTL_GET_CPSTAT: - case NANDFS_IOCTL_GET_SUINFO: - case NANDFS_IOCTL_GET_VINFO: - case NANDFS_IOCTL_GET_BDESCS: - break; - default: - return (EROFS); - } - } - - switch (command) { - case NANDFS_IOCTL_GET_FSINFO: - error = nandfs_get_fsinfo(nmp, (struct nandfs_fsinfo *)data); - break; - case NANDFS_IOCTL_GET_SUSTAT: - nss = (struct nandfs_seg_stat *)data; - error = nandfs_get_seg_stat(nandfsdev, nss); - break; - case NANDFS_IOCTL_CHANGE_CPMODE: - ncpm = (struct nandfs_cpmode *)data; - error = nandfs_chng_cpmode(nandfsdev->nd_cp_node, ncpm); - nandfs_force_syncer(nmp); - break; - case NANDFS_IOCTL_GET_CPINFO: - nargv = (struct nandfs_argv *)data; - error = nandfs_get_cpinfo_ioctl(nandfsdev->nd_cp_node, nargv); - break; - case NANDFS_IOCTL_DELETE_CP: - tab = (uint64_t *)data; - error = nandfs_delete_cp(nandfsdev->nd_cp_node, tab[0], tab[1]); - nandfs_force_syncer(nmp); - break; - case NANDFS_IOCTL_GET_CPSTAT: - ncp = (struct nandfs_cpstat *)data; - error = nandfs_get_cpstat(nandfsdev->nd_cp_node, ncp); - break; - case NANDFS_IOCTL_GET_SUINFO: - nargv = (struct nandfs_argv *)data; - error = nandfs_get_segment_info_ioctl(nandfsdev, nargv); - break; - case NANDFS_IOCTL_GET_VINFO: - nargv = (struct nandfs_argv *)data; - error = nandfs_get_dat_vinfo_ioctl(nandfsdev, nargv); - break; - case NANDFS_IOCTL_GET_BDESCS: - nargv = (struct nandfs_argv *)data; - error = nandfs_get_dat_bdescs_ioctl(nandfsdev, nargv); - break; - case NANDFS_IOCTL_SYNC: - cno = (uint64_t *)data; - nandfs_force_syncer(nmp); - *cno = nandfsdev->nd_last_cno; - error = 0; - break; - case NANDFS_IOCTL_MAKE_SNAP: - cno = (uint64_t *)data; - error = nandfs_make_snap(nandfsdev, cno); - nandfs_force_syncer(nmp); - break; - case NANDFS_IOCTL_DELETE_SNAP: - cno = (uint64_t *)data; - error = nandfs_delete_snap(nandfsdev, *cno); - nandfs_force_syncer(nmp); - break; - default: - error = ENOTTY; - break; - } - - return (error); -} - -/* - * Whiteout vnode call - */ -static int -nandfs_whiteout(struct vop_whiteout_args *ap) -{ - struct vnode *dvp = ap->a_dvp; - struct componentname *cnp = ap->a_cnp; - int error = 0; - - switch (ap->a_flags) { - case LOOKUP: - return (0); - case CREATE: - /* Create a new directory whiteout */ -#ifdef INVARIANTS - if ((cnp->cn_flags & SAVENAME) == 0) - panic("nandfs_whiteout: missing name"); -#endif - error = nandfs_add_dirent(dvp, NANDFS_WHT_INO, cnp->cn_nameptr, - cnp->cn_namelen, DT_WHT); - break; - - case DELETE: - /* Remove an existing directory whiteout */ - cnp->cn_flags &= ~DOWHITEOUT; - error = nandfs_remove_dirent(dvp, NULL, cnp); - break; - default: - panic("nandf_whiteout: unknown op: %d", ap->a_flags); - } - - return (error); -} - -static int -nandfs_pathconf(struct vop_pathconf_args *ap) -{ - int error; - - error = 0; - switch (ap->a_name) { - case _PC_LINK_MAX: - *ap->a_retval = NANDFS_LINK_MAX; - break; - case _PC_NAME_MAX: - *ap->a_retval = NANDFS_NAME_LEN; - break; - case _PC_PIPE_BUF: - if (ap->a_vp->v_type == VDIR || ap->a_vp->v_type == VFIFO) - *ap->a_retval = PIPE_BUF; - else - error = EINVAL; - break; - case _PC_CHOWN_RESTRICTED: - *ap->a_retval = 1; - break; - case _PC_NO_TRUNC: - *ap->a_retval = 1; - break; - case _PC_ALLOC_SIZE_MIN: - *ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_bsize; - break; - case _PC_FILESIZEBITS: - *ap->a_retval = 64; - break; - case _PC_REC_INCR_XFER_SIZE: - *ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_iosize; - break; - case _PC_REC_MAX_XFER_SIZE: - *ap->a_retval = -1; /* means ``unlimited'' */ - break; - case _PC_REC_MIN_XFER_SIZE: - *ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_iosize; - break; - default: - error = vop_stdpathconf(ap); - break; - } - return (error); -} - -static int -nandfs_vnlock1(struct vop_lock1_args *ap) -{ - struct vnode *vp = ap->a_vp; - struct nandfs_node *node = VTON(vp); - int error, vi_locked; - - /* - * XXX can vnode go away while we are sleeping? - */ - vi_locked = mtx_owned(&vp->v_interlock); - if (vi_locked) - VI_UNLOCK(vp); - error = NANDFS_WRITELOCKFLAGS(node->nn_nandfsdev, - ap->a_flags & LK_NOWAIT); - if (vi_locked && !error) - VI_LOCK(vp); - if (error) - return (error); - - error = vop_stdlock(ap); - if (error) { - NANDFS_WRITEUNLOCK(node->nn_nandfsdev); - return (error); - } - - return (0); -} - -static int -nandfs_vnunlock(struct vop_unlock_args *ap) -{ - struct vnode *vp = ap->a_vp; - struct nandfs_node *node = VTON(vp); - int error; - - error = vop_stdunlock(ap); - if (error) - return (error); - - NANDFS_WRITEUNLOCK(node->nn_nandfsdev); - - return (0); -} - -/* - * Global vfs data structures - */ -struct vop_vector nandfs_vnodeops = { - .vop_default = &default_vnodeops, - .vop_access = nandfs_access, - .vop_advlock = nandfs_advlock, - .vop_bmap = nandfs_bmap, - .vop_close = nandfs_close, - .vop_create = nandfs_create, - .vop_fsync = nandfs_fsync, - .vop_getattr = nandfs_getattr, - .vop_inactive = nandfs_inactive, - .vop_cachedlookup = nandfs_lookup, - .vop_ioctl = nandfs_ioctl, - .vop_link = nandfs_link, - .vop_lookup = vfs_cache_lookup, - .vop_mkdir = nandfs_mkdir, - .vop_mknod = nandfs_mknod, - .vop_open = nandfs_open, - .vop_pathconf = nandfs_pathconf, - .vop_print = nandfs_print, - .vop_read = nandfs_read, - .vop_readdir = nandfs_readdir, - .vop_readlink = nandfs_readlink, - .vop_reclaim = nandfs_reclaim, - .vop_remove = nandfs_remove, - .vop_rename = nandfs_rename, - .vop_rmdir = nandfs_rmdir, - .vop_whiteout = nandfs_whiteout, - .vop_write = nandfs_write, - .vop_setattr = nandfs_setattr, - .vop_strategy = nandfs_strategy, - .vop_symlink = nandfs_symlink, - .vop_lock1 = nandfs_vnlock1, - .vop_unlock = nandfs_vnunlock, -}; - -struct vop_vector nandfs_system_vnodeops = { - .vop_default = &default_vnodeops, - .vop_close = nandfs_close, - .vop_inactive = nandfs_inactive, - .vop_reclaim = nandfs_reclaim, - .vop_strategy = nandfs_strategy, - .vop_fsync = nandfs_fsync, - .vop_bmap = nandfs_bmap, - .vop_access = VOP_PANIC, - .vop_advlock = VOP_PANIC, - .vop_create = VOP_PANIC, - .vop_getattr = VOP_PANIC, - .vop_cachedlookup = VOP_PANIC, - .vop_ioctl = VOP_PANIC, - .vop_link = VOP_PANIC, - .vop_lookup = VOP_PANIC, - .vop_mkdir = VOP_PANIC, - .vop_mknod = VOP_PANIC, - .vop_open = VOP_PANIC, - .vop_pathconf = VOP_PANIC, - .vop_print = VOP_PANIC, - .vop_read = VOP_PANIC, - .vop_readdir = VOP_PANIC, - .vop_readlink = VOP_PANIC, - .vop_remove = VOP_PANIC, - .vop_rename = VOP_PANIC, - .vop_rmdir = VOP_PANIC, - .vop_whiteout = VOP_PANIC, - .vop_write = VOP_PANIC, - .vop_setattr = VOP_PANIC, - .vop_symlink = VOP_PANIC, -}; - -static int -nandfsfifo_close(struct vop_close_args *ap) -{ - struct vnode *vp = ap->a_vp; - struct nandfs_node *node = VTON(vp); - - DPRINTF(VNCALL, ("%s: vp %p node %p\n", __func__, vp, node)); - - mtx_lock(&vp->v_interlock); - if (vp->v_usecount > 1) - nandfs_itimes_locked(vp); - mtx_unlock(&vp->v_interlock); - - return (fifo_specops.vop_close(ap)); -} - -struct vop_vector nandfs_fifoops = { - .vop_default = &fifo_specops, - .vop_fsync = VOP_PANIC, - .vop_access = nandfs_access, - .vop_close = nandfsfifo_close, - .vop_getattr = nandfs_getattr, - .vop_inactive = nandfs_inactive, - .vop_pathconf = nandfs_pathconf, - .vop_print = nandfs_print, - .vop_read = VOP_PANIC, - .vop_reclaim = nandfs_reclaim, - .vop_setattr = nandfs_setattr, - .vop_write = VOP_PANIC, - .vop_lock1 = nandfs_vnlock1, - .vop_unlock = nandfs_vnunlock, -}; - -int -nandfs_vinit(struct vnode *vp, uint64_t ino) -{ - struct nandfs_node *node; - - ASSERT_VOP_LOCKED(vp, __func__); - - node = VTON(vp); - - /* Check if we're fetching the root */ - if (ino == NANDFS_ROOT_INO) - vp->v_vflag |= VV_ROOT; - - if (ino != NANDFS_GC_INO) - vp->v_type = IFTOVT(node->nn_inode.i_mode); - else - vp->v_type = VREG; - - if (vp->v_type == VFIFO) - vp->v_op = &nandfs_fifoops; - - return (0); -} diff --git a/sys/fs/smbfs/smbfs_io.c b/sys/fs/smbfs/smbfs_io.c index 4edba5c761e7..fa6a14024213 100644 --- a/sys/fs/smbfs/smbfs_io.c +++ b/sys/fs/smbfs/smbfs_io.c @@ -375,9 +375,6 @@ smbfs_doio(struct vnode *vp, struct buf *bp, struct ucred *cr, struct thread *td */ if (error == EINTR || (!error && (bp->b_flags & B_NEEDCOMMIT))) { - int s; - - s = splbio(); bp->b_flags &= ~(B_INVAL|B_NOCACHE); if ((bp->b_flags & B_ASYNC) == 0) bp->b_flags |= B_EINTR; @@ -387,7 +384,6 @@ smbfs_doio(struct vnode *vp, struct buf *bp, struct ucred *cr, struct thread *td } if ((bp->b_flags & B_ASYNC) == 0) bp->b_flags |= B_EINTR; - splx(s); } else { if (error) { bp->b_ioflags |= BIO_ERROR; diff --git a/sys/geom/geom_flashmap.c b/sys/geom/geom_flashmap.c index ac7344a34bb6..71007a4f7936 100644 --- a/sys/geom/geom_flashmap.c +++ b/sys/geom/geom_flashmap.c @@ -43,8 +43,6 @@ __FBSDID("$FreeBSD$"); #include <geom/geom_flashmap.h> #include <geom/geom_slice.h> -#include <dev/nand/nand_dev.h> - struct g_flashmap_slice { off_t sl_start; off_t sl_end; @@ -65,7 +63,6 @@ static struct { { "MMC::device", NULL } }; -static g_ioctl_t g_flashmap_ioctl; static g_taste_t g_flashmap_taste; static int g_flashmap_load(device_t dev, struct g_provider *pp, @@ -127,26 +124,6 @@ g_flashmap_modify(struct g_flashmap *gfp, struct g_geom *gp, return (0); } -static int -g_flashmap_ioctl(struct g_provider *pp, u_long cmd, void *data, int fflag, - struct thread *td) -{ - struct g_consumer *cp; - struct g_geom *gp; - - if (cmd != NAND_IO_GET_CHIP_PARAM) - return (ENOIOCTL); - - cp = LIST_FIRST(&pp->geom->consumer); - if (cp == NULL) - return (ENOIOCTL); - gp = cp->provider->geom; - if (gp->ioctl == NULL) - return (ENOIOCTL); - - return (gp->ioctl(cp->provider, cmd, data, fflag, td)); -} - static struct g_geom * g_flashmap_taste(struct g_class *mp, struct g_provider *pp, int flags) { @@ -245,7 +222,6 @@ static struct g_class g_flashmap_class = { .name = FLASHMAP_CLASS_NAME, .version = G_VERSION, .taste = g_flashmap_taste, - .ioctl = g_flashmap_ioctl, }; DECLARE_GEOM_CLASS(g_flashmap_class, g_flashmap); diff --git a/sys/i386/conf/GENERIC b/sys/i386/conf/GENERIC index dab73ee51da6..ddeabf5952c8 100644 --- a/sys/i386/conf/GENERIC +++ b/sys/i386/conf/GENERIC @@ -292,7 +292,6 @@ device wpi # Intel 3945ABG wireless NICs. # Pseudo devices. device crypto # core crypto support device loop # Network loopback -device random # Entropy device device padlock_rng # VIA Padlock RNG device rdrand_rng # Intel Bull Mountain RNG device ether # Ethernet support diff --git a/sys/i386/conf/MINIMAL b/sys/i386/conf/MINIMAL index 0b0bd23f40b4..0f1d268d013e 100644 --- a/sys/i386/conf/MINIMAL +++ b/sys/i386/conf/MINIMAL @@ -10,7 +10,7 @@ # some features (ACL, GJOURNAL) that GENERIC includes. # o acpi as a module has been reported flakey and not well tested, so # is included in the kernel. -# o random is included due to uncertaty... +# o (non-loaded) random is included due to uncertainty... # o Many networking things are included # # For now, please run changes to these list past imp@freebsd.org @@ -132,7 +132,6 @@ device agp # support several AGP chipsets # Pseudo devices. device loop # Network loopback -device random # Entropy device device padlock_rng # VIA Padlock RNG device rdrand_rng # Intel Bull Mountain RNG device ether # Ethernet support diff --git a/sys/kern/Make.tags.inc b/sys/kern/Make.tags.inc index 50aed68dbf40..cdefa98a32f6 100644 --- a/sys/kern/Make.tags.inc +++ b/sys/kern/Make.tags.inc @@ -28,7 +28,6 @@ COMM= ${SYS}/sys/vnode.h \ ${SYS}/fs/fifofs/*.[ch] \ ${SYS}/fs/fuse/*.[ch] \ ${SYS}/fs/msdosfs/*.[ch] \ - ${SYS}/fs/nandfs/*.[ch] \ ${SYS}/fs/nfs/*.[ch] \ ${SYS}/fs/nfsclient/*.[ch] \ ${SYS}/fs/nfsserver/*.[ch] \ @@ -82,7 +81,6 @@ COMMDIR2= ${SYS}/dev/alc \ ${SYS}/fs/fifofs \ ${SYS}/fs/fuse \ ${SYS}/fs/msdosfs \ - ${SYS}/fs/nandfs \ ${SYS}/fs/nfs \ ${SYS}/fs/nfsclient \ ${SYS}/fs/nfsserver \ diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index 4d09eea37d56..4bc1a1546820 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -780,7 +780,9 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) } if (arg >= 0) { bsize = fp->f_vnode->v_mount->mnt_stat.f_iosize; - fp->f_seqcount = (arg + bsize - 1) / bsize; + arg = MIN(arg, INT_MAX - bsize + 1); + fp->f_seqcount = MIN(IO_SEQMAX, + (arg + bsize - 1) / bsize); atomic_set_int(&fp->f_flag, FRDAHEAD); } else { atomic_clear_int(&fp->f_flag, FRDAHEAD); diff --git a/sys/kern/kern_mib.c b/sys/kern/kern_mib.c index a92f6488c39f..54cdff148247 100644 --- a/sys/kern/kern_mib.c +++ b/sys/kern/kern_mib.c @@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$"); #include "opt_config.h" #include <sys/param.h> +#include <sys/boot.h> #include <sys/jail.h> #include <sys/kernel.h> #include <sys/limits.h> @@ -136,7 +137,7 @@ SYSCTL_INT(_kern, KERN_SAVED_IDS, saved_ids, CTLFLAG_RD|CTLFLAG_CAPRD, SYSCTL_NULL_INT_PTR, 0, "Whether saved set-group/user ID is available"); #endif -char kernelname[MAXPATHLEN] = "/boot/kernel/kernel"; /* XXX bloat */ +char kernelname[MAXPATHLEN] = PATH_KERNEL; /* XXX bloat */ SYSCTL_STRING(_kern, KERN_BOOTFILE, bootfile, CTLFLAG_RW | CTLFLAG_MPSAFE, kernelname, sizeof kernelname, "Name of kernel file booted"); diff --git a/sys/kern/kern_rangelock.c b/sys/kern/kern_rangelock.c index 35bd6e864d37..b434ac4b4c1c 100644 --- a/sys/kern/kern_rangelock.c +++ b/sys/kern/kern_rangelock.c @@ -141,15 +141,33 @@ out: static void rangelock_unlock_locked(struct rangelock *lock, struct rl_q_entry *entry, - struct mtx *ilk) + struct mtx *ilk, bool do_calc_block) { MPASS(lock != NULL && entry != NULL && ilk != NULL); mtx_assert(ilk, MA_OWNED); - KASSERT(entry != lock->rl_currdep, ("stuck currdep")); + + if (!do_calc_block) { + /* + * This is the case where rangelock_enqueue() has been called + * with trylock == true and just inserted this entry in the + * queue. + * If rl_currdep is this entry, rl_currdep needs to + * be set to the next entry in the rl_waiters list. + * However, since this entry is the last entry in the + * list, the next entry is NULL. + */ + if (lock->rl_currdep == entry) { + KASSERT(TAILQ_NEXT(lock->rl_currdep, rl_q_link) == NULL, + ("rangelock_enqueue: next entry not NULL")); + lock->rl_currdep = NULL; + } + } else + KASSERT(entry != lock->rl_currdep, ("stuck currdep")); TAILQ_REMOVE(&lock->rl_waiters, entry, rl_q_link); - rangelock_calc_block(lock); + if (do_calc_block) + rangelock_calc_block(lock); mtx_unlock(ilk); if (curthread->td_rlqe == NULL) curthread->td_rlqe = entry; @@ -164,7 +182,7 @@ rangelock_unlock(struct rangelock *lock, void *cookie, struct mtx *ilk) MPASS(lock != NULL && cookie != NULL && ilk != NULL); mtx_lock(ilk); - rangelock_unlock_locked(lock, cookie, ilk); + rangelock_unlock_locked(lock, cookie, ilk, true); } /* @@ -185,7 +203,7 @@ rangelock_unlock_range(struct rangelock *lock, void *cookie, off_t start, mtx_lock(ilk); if (entry->rl_q_end == end) { - rangelock_unlock_locked(lock, cookie, ilk); + rangelock_unlock_locked(lock, cookie, ilk, true); return (NULL); } entry->rl_q_end = end; @@ -196,11 +214,11 @@ rangelock_unlock_range(struct rangelock *lock, void *cookie, off_t start, /* * Add the lock request to the queue of the pending requests for - * rangelock. Sleep until the request can be granted. + * rangelock. Sleep until the request can be granted unless trylock == true. */ static void * rangelock_enqueue(struct rangelock *lock, off_t start, off_t end, int mode, - struct mtx *ilk) + struct mtx *ilk, bool trylock) { struct rl_q_entry *entry; struct thread *td; @@ -226,11 +244,28 @@ rangelock_enqueue(struct rangelock *lock, off_t start, off_t end, int mode, */ TAILQ_INSERT_TAIL(&lock->rl_waiters, entry, rl_q_link); + /* + * If rl_currdep == NULL, there is no entry waiting for a conflicting + * range to be resolved, so set rl_currdep to this entry. If there is + * no conflicting entry for this entry, rl_currdep will be set back to + * NULL by rangelock_calc_block(). + */ if (lock->rl_currdep == NULL) lock->rl_currdep = entry; rangelock_calc_block(lock); - while (!(entry->rl_q_flags & RL_LOCK_GRANTED)) + while (!(entry->rl_q_flags & RL_LOCK_GRANTED)) { + if (trylock) { + /* + * For this case, the range is not actually locked + * yet, but removal from the list requires the same + * steps, except for not doing a rangelock_calc_block() + * call, since rangelock_calc_block() was called above. + */ + rangelock_unlock_locked(lock, entry, ilk, false); + return (NULL); + } msleep(entry, ilk, 0, "range", 0); + } mtx_unlock(ilk); return (entry); } @@ -239,12 +274,28 @@ void * rangelock_rlock(struct rangelock *lock, off_t start, off_t end, struct mtx *ilk) { - return (rangelock_enqueue(lock, start, end, RL_LOCK_READ, ilk)); + return (rangelock_enqueue(lock, start, end, RL_LOCK_READ, ilk, false)); +} + +void * +rangelock_tryrlock(struct rangelock *lock, off_t start, off_t end, + struct mtx *ilk) +{ + + return (rangelock_enqueue(lock, start, end, RL_LOCK_READ, ilk, true)); } void * rangelock_wlock(struct rangelock *lock, off_t start, off_t end, struct mtx *ilk) { - return (rangelock_enqueue(lock, start, end, RL_LOCK_WRITE, ilk)); + return (rangelock_enqueue(lock, start, end, RL_LOCK_WRITE, ilk, false)); +} + +void * +rangelock_trywlock(struct rangelock *lock, off_t start, off_t end, + struct mtx *ilk) +{ + + return (rangelock_enqueue(lock, start, end, RL_LOCK_WRITE, ilk, true)); } diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index 044865a489a6..8a1ee1e53cbe 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -3415,10 +3415,16 @@ corefile_open_last(struct thread *td, char *name, int indexpos, } if (oldvp != NULL) { - if (nextvp == NULL) - nextvp = oldvp; - else + if (nextvp == NULL) { + if ((td->td_proc->p_flag & P_SUGID) != 0) { + error = EFAULT; + vnode_close_locked(td, oldvp); + } else { + nextvp = oldvp; + } + } else { vnode_close_locked(td, oldvp); + } } if (error != 0) { if (nextvp != NULL) @@ -3538,6 +3544,8 @@ corefile_open(const char *comm, uid_t uid, pid_t pid, struct thread *td, oflags = VN_OPEN_NOAUDIT | VN_OPEN_NAMECACHE | (capmode_coredump ? VN_OPEN_NOCAPCHECK : 0); flags = O_CREAT | FWRITE | O_NOFOLLOW; + if ((td->td_proc->p_flag & P_SUGID) != 0) + flags |= O_EXCL; NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, name, td); error = vn_open_cred(&nd, &flags, cmode, oflags, td->td_ucred, @@ -3614,10 +3622,11 @@ coredump(struct thread *td) /* * Don't dump to non-regular files or files with links. - * Do not dump into system files. + * Do not dump into system files. Effective user must own the corefile. */ if (vp->v_type != VREG || VOP_GETATTR(vp, &vattr, cred) != 0 || - vattr.va_nlink != 1 || (vp->v_vflag & VV_SYSTEM) != 0) { + vattr.va_nlink != 1 || (vp->v_vflag & VV_SYSTEM) != 0 || + vattr.va_uid != cred->cr_uid) { VOP_UNLOCK(vp, 0); error = EFAULT; goto out; diff --git a/sys/kern/sys_pipe.c b/sys/kern/sys_pipe.c index eafb902601d7..3c04e8607a71 100644 --- a/sys/kern/sys_pipe.c +++ b/sys/kern/sys_pipe.c @@ -1414,7 +1414,7 @@ pipe_poll(struct file *fp, int events, struct ucred *active_cred, levents = events & (POLLIN | POLLINIGNEOF | POLLPRI | POLLRDNORM | POLLRDBAND); if (rpipe->pipe_state & PIPE_NAMED && fp->f_flag & FREAD && levents && - fp->f_seqcount == rpipe->pipe_wgen) + fp->f_pipegen == rpipe->pipe_wgen) events |= POLLINIGNEOF; if ((events & POLLINIGNEOF) == 0) { diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c index e38f8c06bbb3..05be168e8a84 100644 --- a/sys/kern/uipc_socket.c +++ b/sys/kern/uipc_socket.c @@ -1044,7 +1044,7 @@ sofree(struct socket *so) * * We used to do a lot of socket buffer and socket locking here, as * well as invoke sorflush() and perform wakeups. The direct call to - * dom_dispose() and sbrelease_internal() are an inlining of what was + * dom_dispose() and sbdestroy() are an inlining of what was * necessary from sorflush(). * * Notice that the socket buffer and kqueue state are torn down diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c index 7871e536b56e..aba141c26249 100644 --- a/sys/kern/vfs_vnops.c +++ b/sys/kern/vfs_vnops.c @@ -499,9 +499,8 @@ sequential_heuristic(struct uio *uio, struct file *fp) * closely related to the best I/O size for real disks than * to any block size used by software. */ - fp->f_seqcount += howmany(uio->uio_resid, 16384); - if (fp->f_seqcount > IO_SEQMAX) - fp->f_seqcount = IO_SEQMAX; + fp->f_seqcount += lmin(IO_SEQMAX, + howmany(uio->uio_resid, 16384)); return (fp->f_seqcount << IO_SEQSHIFT); } diff --git a/sys/mips/conf/BCM b/sys/mips/conf/BCM index 5c2753279a23..27d93766c354 100644 --- a/sys/mips/conf/BCM +++ b/sys/mips/conf/BCM @@ -82,7 +82,6 @@ device uart #Base device loop device ether -device random device md #Performance diff --git a/sys/mips/conf/BERI_DE4_BASE b/sys/mips/conf/BERI_DE4_BASE index 0985d60e60d1..7719009ccf5a 100644 --- a/sys/mips/conf/BERI_DE4_BASE +++ b/sys/mips/conf/BERI_DE4_BASE @@ -44,6 +44,7 @@ options DEVICE_POLLING # # DMA support # +options ALTERA_MSGDMA_DESC_PF_STD device xdma device altera_softdma device altera_msgdma diff --git a/sys/mips/conf/DIR-825B1 b/sys/mips/conf/DIR-825B1 index 80a1d17c0ac0..8b43cf1b22ca 100644 --- a/sys/mips/conf/DIR-825B1 +++ b/sys/mips/conf/DIR-825B1 @@ -21,7 +21,6 @@ hints "DIR-825B1.hints" # Since the kernel image must fit inside 1024KiB, we have to build almost # everything as modules. -# nodevice random nodevice gpio nodevice gpioled nodevice gif diff --git a/sys/mips/conf/ERL b/sys/mips/conf/ERL index f12f6228bd95..a0e79450c871 100644 --- a/sys/mips/conf/ERL +++ b/sys/mips/conf/ERL @@ -149,7 +149,6 @@ device wlan_amrr # AMRR transmit rate control algorithm # Pseudo devices. device loop # Network loopback -device random # Entropy device device ether # Ethernet support device vlan # 802.1Q VLAN support device tuntap # Packet tunnel. diff --git a/sys/mips/conf/JZ4780 b/sys/mips/conf/JZ4780 index a3716cbe4873..459f908857a6 100644 --- a/sys/mips/conf/JZ4780 +++ b/sys/mips/conf/JZ4780 @@ -68,7 +68,6 @@ device miibus device bpf device md device uart -device random device fdt_pinctrl diff --git a/sys/mips/conf/OCTEON1 b/sys/mips/conf/OCTEON1 index 6c536f0d6ed4..256b66eff71f 100644 --- a/sys/mips/conf/OCTEON1 +++ b/sys/mips/conf/OCTEON1 @@ -184,7 +184,6 @@ device ral # Ralink Technology RT2500 wireless NICs. # Pseudo devices. device loop # Network loopback -device random # Entropy device device ether # Ethernet support device vlan # 802.1Q VLAN support device tuntap # Packet tunnel. diff --git a/sys/mips/conf/PB92 b/sys/mips/conf/PB92 index 4d3e890d0f96..64a0e6db120b 100644 --- a/sys/mips/conf/PB92 +++ b/sys/mips/conf/PB92 @@ -133,5 +133,4 @@ device loop device ether #device md #device bpf -device random #device if_bridge diff --git a/sys/mips/conf/PICOSTATION_M2HP b/sys/mips/conf/PICOSTATION_M2HP index e331f7764d2d..38e3d69c0509 100644 --- a/sys/mips/conf/PICOSTATION_M2HP +++ b/sys/mips/conf/PICOSTATION_M2HP @@ -68,6 +68,3 @@ device arswitch # Enable GPIO device gpio device gpioled - -# RNG -device random diff --git a/sys/mips/conf/WZR-300HP b/sys/mips/conf/WZR-300HP index 217e444f1b89..dd767888a1e9 100644 --- a/sys/mips/conf/WZR-300HP +++ b/sys/mips/conf/WZR-300HP @@ -49,4 +49,4 @@ device hwpmc # load these via modules, shrink kernel nodevice if_bridge nodevice bridgestp -nodevice random +options RANDOM_LOADABLE diff --git a/sys/mips/conf/WZR-HPAG300H b/sys/mips/conf/WZR-HPAG300H index b46f9de3eb8d..3337af682f2c 100644 --- a/sys/mips/conf/WZR-HPAG300H +++ b/sys/mips/conf/WZR-HPAG300H @@ -49,4 +49,4 @@ device hwpmc # load these via modules, shrink kernel nodevice if_bridge nodevice bridgestp -nodevice random +options RANDOM_LOADABLE diff --git a/sys/mips/conf/X1000 b/sys/mips/conf/X1000 index 907ea814de8f..8f10337218a5 100644 --- a/sys/mips/conf/X1000 +++ b/sys/mips/conf/X1000 @@ -63,7 +63,6 @@ device miibus device bpf device md device uart -device random device fdt_pinctrl diff --git a/sys/mips/conf/std.AR5312 b/sys/mips/conf/std.AR5312 index a3b055bfb743..56a45cb4c869 100644 --- a/sys/mips/conf/std.AR5312 +++ b/sys/mips/conf/std.AR5312 @@ -72,7 +72,6 @@ device loop device ether device md device bpf -device random options ARGE_DEBUG # Enable if_arge debugging for now diff --git a/sys/mips/conf/std.AR5315 b/sys/mips/conf/std.AR5315 index c9f85f6c0813..74a888c32f85 100644 --- a/sys/mips/conf/std.AR5315 +++ b/sys/mips/conf/std.AR5315 @@ -72,7 +72,6 @@ device loop device ether device md device bpf -device random options ARGE_DEBUG # Enable if_arge debugging for now diff --git a/sys/mips/conf/std.AR_MIPS_BASE b/sys/mips/conf/std.AR_MIPS_BASE index 37544a9b6660..ab0947a391ea 100644 --- a/sys/mips/conf/std.AR_MIPS_BASE +++ b/sys/mips/conf/std.AR_MIPS_BASE @@ -25,9 +25,6 @@ makeoptions MODULES_OVERRIDE+="gpio ar71xx if_gif if_vlan if_gre if_tuntap" makeoptions MODULES_OVERRIDE+="if_bridge bridgestp usb" makeoptions MODULES_OVERRIDE+="alq" -# Random - required during early boot! -device random - # net80211 options IEEE80211_DEBUG options IEEE80211_SUPPORT_MESH diff --git a/sys/mips/conf/std.BERI b/sys/mips/conf/std.BERI index 903af51875af..07f907b760df 100644 --- a/sys/mips/conf/std.BERI +++ b/sys/mips/conf/std.BERI @@ -61,5 +61,4 @@ device ether device geom_map device loop device md -device random device snp diff --git a/sys/mips/conf/std.MALTA b/sys/mips/conf/std.MALTA index 4c1965650fba..26940db1b92f 100644 --- a/sys/mips/conf/std.MALTA +++ b/sys/mips/conf/std.MALTA @@ -55,4 +55,3 @@ device miibus device bpf device md device uart -device random diff --git a/sys/mips/conf/std.XLP b/sys/mips/conf/std.XLP index 5330c19b3657..cbc13746fd06 100644 --- a/sys/mips/conf/std.XLP +++ b/sys/mips/conf/std.XLP @@ -66,7 +66,6 @@ makeoptions FDT_DTS_FILE=xlp-basic.dts # Pseudo device loop -device random device md device bpf diff --git a/sys/mips/mediatek/std.mediatek b/sys/mips/mediatek/std.mediatek index 7806da8f099a..d8c351aab36f 100644 --- a/sys/mips/mediatek/std.mediatek +++ b/sys/mips/mediatek/std.mediatek @@ -74,9 +74,6 @@ device fdt_pinctrl # UART support device uart -# random support -device random - # loop device support device loop diff --git a/sys/mips/mediatek/std.rt2880 b/sys/mips/mediatek/std.rt2880 index 8040585e9cb9..397a0bc322da 100644 --- a/sys/mips/mediatek/std.rt2880 +++ b/sys/mips/mediatek/std.rt2880 @@ -73,9 +73,6 @@ device fdt_pinctrl # UART support device uart -# random support -device random - # loop device support device loop diff --git a/sys/modules/Makefile b/sys/modules/Makefile index a9a5c5ed98ef..876a13f19ea9 100644 --- a/sys/modules/Makefile +++ b/sys/modules/Makefile @@ -255,8 +255,6 @@ SUBDIR= \ ${_mwlfw} \ mxge \ my \ - ${_nandfs} \ - ${_nandsim} \ ${_nctgpio} \ ${_ndis} \ ${_netgraph} \ @@ -489,11 +487,6 @@ _mlx5ib= mlx5ib .endif .endif -.if ${MK_NAND} != "no" || defined(ALL_MODULES) -_nandfs= nandfs -_nandsim= nandsim -.endif - .if ${MK_NETGRAPH} != "no" || defined(ALL_MODULES) _netgraph= netgraph .endif diff --git a/sys/modules/nand/Makefile b/sys/modules/nand/Makefile deleted file mode 100644 index c9d9962e897f..000000000000 --- a/sys/modules/nand/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# $FreeBSD$ - -.PATH: ${SRCTOP}/sys/dev/nand - -KMOD = nand -SRCS= nand.c nand_bbt.c nand_cdev.c nand_generic.c nand_geom.c \ - nand_id.c nandbus.c nandbus_if.c nand_if.c nfc_if.c \ - nand_if.h device_if.h bus_if.h nfc_if.h nandbus_if.h - -.include <bsd.kmod.mk> diff --git a/sys/modules/nandfs/Makefile b/sys/modules/nandfs/Makefile deleted file mode 100644 index f13858c57c7b..000000000000 --- a/sys/modules/nandfs/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# $FreeBSD$ - -.PATH: ${SRCTOP}/sys/fs/nandfs - -KMOD= nandfs -SRCS= vnode_if.h opt_ddb.h \ - bmap.c nandfs_bmap.c nandfs_dir.c nandfs_subr.c nandfs_vfsops.c \ - nandfs_vnops.c nandfs_alloc.c nandfs_cpfile.c nandfs_dat.c \ - nandfs_ifile.c nandfs_segment.c nandfs_sufile.c nandfs_buffer.c \ - nandfs_cleaner.c - -.include <bsd.kmod.mk> diff --git a/sys/modules/nandsim/Makefile b/sys/modules/nandsim/Makefile deleted file mode 100644 index 4f0aeca9eb4b..000000000000 --- a/sys/modules/nandsim/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# $FreeBSD$ - -.PATH: ${SRCTOP}/sys/dev/nand - -KMOD= nandsim -SRCS= nandsim.c nandsim_chip.c nandsim_swap.c nandsim_ctrl.c nandsim_log.c\ - bus_if.h device_if.h vnode_if.h nfc_if.h nand_if.h - -.include <bsd.kmod.mk> diff --git a/sys/net/if_vxlan.c b/sys/net/if_vxlan.c index 81065bcec431..5e35baae2dbc 100644 --- a/sys/net/if_vxlan.c +++ b/sys/net/if_vxlan.c @@ -1134,7 +1134,7 @@ vxlan_socket_mc_join_group(struct vxlan_socket *vso, * If we really need to, we can of course look in the INP's * membership list: * sotoinpcb(vso->vxlso_sock)->inp_moptions-> - * imo_membership[]->inm_ifp + * imo_head[]->imf_inm->inm_ifp * similarly to imo_match_group(). */ source->in4.sin_addr = local->in4.sin_addr; diff --git a/sys/net/iflib.c b/sys/net/iflib.c index d932e9373be0..e33c2bec61e2 100644 --- a/sys/net/iflib.c +++ b/sys/net/iflib.c @@ -3580,10 +3580,10 @@ iflib_txq_drain(struct ifmp_ring *r, uint32_t cidx, uint32_t pidx) iflib_txq_t txq = r->cookie; if_ctx_t ctx = txq->ift_ctx; if_t ifp = ctx->ifc_ifp; - struct mbuf **mp, *m; - int i, count, consumed, pkt_sent, bytes_sent, mcast_sent, avail; - int reclaimed, err, in_use_prev, desc_used; - bool do_prefetch, ring, rang; + struct mbuf *m, **mp; + int avail, bytes_sent, consumed, count, err, i, in_use_prev; + int mcast_sent, pkt_sent, reclaimed, txq_avail; + bool do_prefetch, rang, ring; if (__predict_false(!(if_getdrvflags(ifp) & IFF_DRV_RUNNING) || !LINK_ACTIVE(ctx))) { @@ -3621,16 +3621,15 @@ iflib_txq_drain(struct ifmp_ring *r, uint32_t cidx, uint32_t pidx) avail, ctx->ifc_flags, TXQ_AVAIL(txq)); #endif do_prefetch = (ctx->ifc_flags & IFC_PREFETCH); - avail = TXQ_AVAIL(txq); + txq_avail = TXQ_AVAIL(txq); err = 0; - for (desc_used = i = 0; i < count && avail > MAX_TX_DESC(ctx) + 2; i++) { + for (i = 0; i < count && txq_avail > MAX_TX_DESC(ctx) + 2; i++) { int rem = do_prefetch ? count - i : 0; mp = _ring_peek_one(r, cidx, i, rem); MPASS(mp != NULL && *mp != NULL); if (__predict_false(*mp == (struct mbuf *)txq)) { consumed++; - reclaimed++; continue; } in_use_prev = txq->ift_in_use; @@ -3649,10 +3648,9 @@ iflib_txq_drain(struct ifmp_ring *r, uint32_t cidx, uint32_t pidx) DBG_COUNTER_INC(tx_sent); bytes_sent += m->m_pkthdr.len; mcast_sent += !!(m->m_flags & M_MCAST); - avail = TXQ_AVAIL(txq); + txq_avail = TXQ_AVAIL(txq); txq->ift_db_pending += (txq->ift_in_use - in_use_prev); - desc_used += (txq->ift_in_use - in_use_prev); ETHER_BPF_MTAP(ifp, m); if (__predict_false(!(ifp->if_drv_flags & IFF_DRV_RUNNING))) break; @@ -6155,9 +6153,6 @@ iflib_tx_credits_update(if_ctx_t ctx, iflib_txq_t txq) int credits_pre = txq->ift_cidx_processed; #endif - if (ctx->isc_txd_credits_update == NULL) - return (0); - bus_dmamap_sync(txq->ift_ifdi->idi_tag, txq->ift_ifdi->idi_map, BUS_DMASYNC_POSTREAD); if ((credits = ctx->isc_txd_credits_update(ctx->ifc_softc, txq->ift_id, true)) == 0) diff --git a/sys/net/vnet.h b/sys/net/vnet.h index b4168750e026..a8c9887ed506 100644 --- a/sys/net/vnet.h +++ b/sys/net/vnet.h @@ -273,7 +273,8 @@ extern struct sx vnet_sxlock; /* struct _hack is to stop this from being used with static data */ #define VNET_DEFINE(t, n) \ struct _hack; t VNET_NAME(n) __section(VNET_SETNAME) __used -#if defined(KLD_MODULE) && (defined(__aarch64__) || defined(__riscv)) +#if defined(KLD_MODULE) && (defined(__aarch64__) || defined(__riscv) \ + || defined(__powerpc64__)) /* * As with DPCPU_DEFINE_STATIC we are unable to mark this data as static * in modules on some architectures. diff --git a/sys/netinet/in.h b/sys/netinet/in.h index 148d51eff36a..cfa168f99be6 100644 --- a/sys/netinet/in.h +++ b/sys/netinet/in.h @@ -505,13 +505,9 @@ __END_DECLS #define IP_DEFAULT_MULTICAST_LOOP 1 /* normally hear sends if a member */ /* - * The imo_membership vector for each socket is now dynamically allocated at - * run-time, bounded by USHRT_MAX, and is reallocated when needed, sized - * according to a power-of-two increment. + * Limit for IPv4 multicast memberships */ -#define IP_MIN_MEMBERSHIPS 31 #define IP_MAX_MEMBERSHIPS 4095 -#define IP_MAX_SOURCE_FILTER 1024 /* XXX to be unused */ /* * Default resource limits for IPv4 multicast source filtering. diff --git a/sys/netinet/in_mcast.c b/sys/netinet/in_mcast.c index 2980c1a463ca..ac5c6a03ab54 100644 --- a/sys/netinet/in_mcast.c +++ b/sys/netinet/in_mcast.c @@ -94,7 +94,9 @@ static MALLOC_DEFINE(M_IPMSOURCE, "ip_msource", /* * Locking: - * - Lock order is: Giant, INP_WLOCK, IN_MULTI_LIST_LOCK, IGMP_LOCK, IF_ADDR_LOCK. + * + * - Lock order is: Giant, IN_MULTI_LOCK, INP_WLOCK, + * IN_MULTI_LIST_LOCK, IGMP_LOCK, IF_ADDR_LOCK. * - The IF_ADDR_LOCK is implicitly taken by inm_lookup() earlier, however * it can be taken by code in net/if.c also. * - ip_moptions and in_mfilter are covered by the INP_WLOCK. @@ -144,12 +146,11 @@ static int imf_prune(struct in_mfilter *, const struct sockaddr_in *); static void imf_purge(struct in_mfilter *); static void imf_rollback(struct in_mfilter *); static void imf_reap(struct in_mfilter *); -static int imo_grow(struct ip_moptions *); -static size_t imo_match_group(const struct ip_moptions *, +static struct in_mfilter * + imo_match_group(const struct ip_moptions *, const struct ifnet *, const struct sockaddr *); static struct in_msource * - imo_match_source(const struct ip_moptions *, const size_t, - const struct sockaddr *); + imo_match_source(struct in_mfilter *, const struct sockaddr *); static void ims_merge(struct ip_msource *ims, const struct in_msource *lims, const int rollback); static int in_getmulti(struct ifnet *, const struct in_addr *, @@ -333,6 +334,26 @@ imf_init(struct in_mfilter *imf, const int st0, const int st1) imf->imf_st[1] = st1; } +struct in_mfilter * +ip_mfilter_alloc(const int mflags, const int st0, const int st1) +{ + struct in_mfilter *imf; + + imf = malloc(sizeof(*imf), M_INMFILTER, mflags); + if (imf != NULL) + imf_init(imf, st0, st1); + + return (imf); +} + +void +ip_mfilter_free(struct in_mfilter *imf) +{ + + imf_purge(imf); + free(imf, M_INMFILTER); +} + /* * Function for looking up an in_multi record for an IPv4 multicast address * on a given interface. ifp must be valid. If no record found, return NULL. @@ -379,89 +400,30 @@ inm_lookup(struct ifnet *ifp, const struct in_addr ina) } /* - * Resize the ip_moptions vector to the next power-of-two minus 1. - * May be called with locks held; do not sleep. - */ -static int -imo_grow(struct ip_moptions *imo) -{ - struct in_multi **nmships; - struct in_multi **omships; - struct in_mfilter *nmfilters; - struct in_mfilter *omfilters; - size_t idx; - size_t newmax; - size_t oldmax; - - nmships = NULL; - nmfilters = NULL; - omships = imo->imo_membership; - omfilters = imo->imo_mfilters; - oldmax = imo->imo_max_memberships; - newmax = ((oldmax + 1) * 2) - 1; - - if (newmax <= IP_MAX_MEMBERSHIPS) { - nmships = (struct in_multi **)realloc(omships, - sizeof(struct in_multi *) * newmax, M_IPMOPTS, M_NOWAIT); - nmfilters = (struct in_mfilter *)realloc(omfilters, - sizeof(struct in_mfilter) * newmax, M_INMFILTER, M_NOWAIT); - if (nmships != NULL && nmfilters != NULL) { - /* Initialize newly allocated source filter heads. */ - for (idx = oldmax; idx < newmax; idx++) { - imf_init(&nmfilters[idx], MCAST_UNDEFINED, - MCAST_EXCLUDE); - } - imo->imo_max_memberships = newmax; - imo->imo_membership = nmships; - imo->imo_mfilters = nmfilters; - } - } - - if (nmships == NULL || nmfilters == NULL) { - if (nmships != NULL) - free(nmships, M_IPMOPTS); - if (nmfilters != NULL) - free(nmfilters, M_INMFILTER); - return (ETOOMANYREFS); - } - - return (0); -} - -/* * Find an IPv4 multicast group entry for this ip_moptions instance * which matches the specified group, and optionally an interface. * Return its index into the array, or -1 if not found. */ -static size_t +static struct in_mfilter * imo_match_group(const struct ip_moptions *imo, const struct ifnet *ifp, const struct sockaddr *group) { const struct sockaddr_in *gsin; - struct in_multi **pinm; - int idx; - int nmships; + struct in_mfilter *imf; + struct in_multi *inm; gsin = (const struct sockaddr_in *)group; - /* The imo_membership array may be lazy allocated. */ - if (imo->imo_membership == NULL || imo->imo_num_memberships == 0) - return (-1); - - nmships = imo->imo_num_memberships; - pinm = &imo->imo_membership[0]; - for (idx = 0; idx < nmships; idx++, pinm++) { - if (*pinm == NULL) + IP_MFILTER_FOREACH(imf, &imo->imo_head) { + inm = imf->imf_inm; + if (inm == NULL) continue; - if ((ifp == NULL || ((*pinm)->inm_ifp == ifp)) && - in_hosteq((*pinm)->inm_addr, gsin->sin_addr)) { + if ((ifp == NULL || (inm->inm_ifp == ifp)) && + in_hosteq(inm->inm_addr, gsin->sin_addr)) { break; } } - if (idx >= nmships) - idx = -1; - - return (idx); + return (imf); } /* @@ -472,22 +434,13 @@ imo_match_group(const struct ip_moptions *imo, const struct ifnet *ifp, * it exists, which may not be the desired behaviour. */ static struct in_msource * -imo_match_source(const struct ip_moptions *imo, const size_t gidx, - const struct sockaddr *src) +imo_match_source(struct in_mfilter *imf, const struct sockaddr *src) { struct ip_msource find; - struct in_mfilter *imf; struct ip_msource *ims; const sockunion_t *psa; KASSERT(src->sa_family == AF_INET, ("%s: !AF_INET", __func__)); - KASSERT(gidx != -1 && gidx < imo->imo_num_memberships, - ("%s: invalid index %d\n", __func__, (int)gidx)); - - /* The imo_mfilters array may be lazy allocated. */ - if (imo->imo_mfilters == NULL) - return (NULL); - imf = &imo->imo_mfilters[gidx]; /* Source trees are keyed in host byte order. */ psa = (const sockunion_t *)src; @@ -507,14 +460,14 @@ int imo_multi_filter(const struct ip_moptions *imo, const struct ifnet *ifp, const struct sockaddr *group, const struct sockaddr *src) { - size_t gidx; + struct in_mfilter *imf; struct in_msource *ims; int mode; KASSERT(ifp != NULL, ("%s: null ifp", __func__)); - gidx = imo_match_group(imo, ifp, group); - if (gidx == -1) + imf = imo_match_group(imo, ifp, group); + if (imf == NULL) return (MCAST_NOTGMEMBER); /* @@ -526,8 +479,8 @@ imo_multi_filter(const struct ip_moptions *imo, const struct ifnet *ifp, * NOTE: We are comparing group state here at IGMP t1 (now) * with socket-layer t0 (since last downcall). */ - mode = imo->imo_mfilters[gidx].imf_st[1]; - ims = imo_match_source(imo, gidx, src); + mode = imf->imf_st[1]; + ims = imo_match_source(imf, src); if ((ims == NULL && mode == MCAST_INCLUDE) || (ims != NULL && ims->imsl_st[0] != mode)) @@ -1452,7 +1405,6 @@ inp_block_unblock_source(struct inpcb *inp, struct sockopt *sopt) struct ip_moptions *imo; struct in_msource *ims; struct in_multi *inm; - size_t idx; uint16_t fmode; int error, doblock; @@ -1531,20 +1483,18 @@ inp_block_unblock_source(struct inpcb *inp, struct sockopt *sopt) if (!IN_MULTICAST(ntohl(gsa->sin.sin_addr.s_addr))) return (EINVAL); + IN_MULTI_LOCK(); + /* * Check if we are actually a member of this group. */ imo = inp_findmoptions(inp); - idx = imo_match_group(imo, ifp, &gsa->sa); - if (idx == -1 || imo->imo_mfilters == NULL) { + imf = imo_match_group(imo, ifp, &gsa->sa); + if (imf == NULL) { error = EADDRNOTAVAIL; goto out_inp_locked; } - - KASSERT(imo->imo_mfilters != NULL, - ("%s: imo_mfilters not allocated", __func__)); - imf = &imo->imo_mfilters[idx]; - inm = imo->imo_membership[idx]; + inm = imf->imf_inm; /* * Attempting to use the delta-based API on an @@ -1562,7 +1512,7 @@ inp_block_unblock_source(struct inpcb *inp, struct sockopt *sopt) * Asked to unblock, but nothing to unblock. * If adding a new block entry, allocate it. */ - ims = imo_match_source(imo, idx, &ssa->sa); + ims = imo_match_source(imf, &ssa->sa); if ((ims != NULL && doblock) || (ims == NULL && !doblock)) { CTR3(KTR_IGMPV3, "%s: source 0x%08x %spresent", __func__, ntohl(ssa->sin.sin_addr.s_addr), doblock ? "" : "not "); @@ -1593,14 +1543,13 @@ inp_block_unblock_source(struct inpcb *inp, struct sockopt *sopt) /* * Begin state merge transaction at IGMP layer. */ - IN_MULTI_LOCK(); CTR1(KTR_IGMPV3, "%s: merge inm state", __func__); IN_MULTI_LIST_LOCK(); error = inm_merge(inm, imf); if (error) { CTR1(KTR_IGMPV3, "%s: failed to merge inm state", __func__); IN_MULTI_LIST_UNLOCK(); - goto out_in_multi_locked; + goto out_imf_rollback; } CTR1(KTR_IGMPV3, "%s: doing igmp downcall", __func__); @@ -1609,9 +1558,6 @@ inp_block_unblock_source(struct inpcb *inp, struct sockopt *sopt) if (error) CTR1(KTR_IGMPV3, "%s: failed igmp downcall", __func__); -out_in_multi_locked: - - IN_MULTI_UNLOCK(); out_imf_rollback: if (error) imf_rollback(imf); @@ -1622,6 +1568,7 @@ out_imf_rollback: out_inp_locked: INP_WUNLOCK(inp); + IN_MULTI_UNLOCK(); return (error); } @@ -1636,9 +1583,6 @@ static struct ip_moptions * inp_findmoptions(struct inpcb *inp) { struct ip_moptions *imo; - struct in_multi **immp; - struct in_mfilter *imfp; - size_t idx; INP_WLOCK(inp); if (inp->inp_moptions != NULL) @@ -1647,29 +1591,16 @@ inp_findmoptions(struct inpcb *inp) INP_WUNLOCK(inp); imo = malloc(sizeof(*imo), M_IPMOPTS, M_WAITOK); - immp = malloc(sizeof(*immp) * IP_MIN_MEMBERSHIPS, M_IPMOPTS, - M_WAITOK | M_ZERO); - imfp = malloc(sizeof(struct in_mfilter) * IP_MIN_MEMBERSHIPS, - M_INMFILTER, M_WAITOK); imo->imo_multicast_ifp = NULL; imo->imo_multicast_addr.s_addr = INADDR_ANY; imo->imo_multicast_vif = -1; imo->imo_multicast_ttl = IP_DEFAULT_MULTICAST_TTL; imo->imo_multicast_loop = in_mcast_loop; - imo->imo_num_memberships = 0; - imo->imo_max_memberships = IP_MIN_MEMBERSHIPS; - imo->imo_membership = immp; - - /* Initialize per-group source filters. */ - for (idx = 0; idx < IP_MIN_MEMBERSHIPS; idx++) - imf_init(&imfp[idx], MCAST_UNDEFINED, MCAST_EXCLUDE); - imo->imo_mfilters = imfp; + STAILQ_INIT(&imo->imo_head); INP_WLOCK(inp); if (inp->inp_moptions != NULL) { - free(imfp, M_INMFILTER); - free(immp, M_IPMOPTS); free(imo, M_IPMOPTS); return (inp->inp_moptions); } @@ -1680,32 +1611,25 @@ inp_findmoptions(struct inpcb *inp) static void inp_gcmoptions(struct ip_moptions *imo) { - struct in_mfilter *imf; + struct in_mfilter *imf; struct in_multi *inm; struct ifnet *ifp; - size_t idx, nmships; - - nmships = imo->imo_num_memberships; - for (idx = 0; idx < nmships; ++idx) { - imf = imo->imo_mfilters ? &imo->imo_mfilters[idx] : NULL; - if (imf) - imf_leave(imf); - inm = imo->imo_membership[idx]; - ifp = inm->inm_ifp; - if (ifp != NULL) { - CURVNET_SET(ifp->if_vnet); - (void)in_leavegroup(inm, imf); - CURVNET_RESTORE(); - } else { - (void)in_leavegroup(inm, imf); + + while ((imf = ip_mfilter_first(&imo->imo_head)) != NULL) { + ip_mfilter_remove(&imo->imo_head, imf); + + imf_leave(imf); + if ((inm = imf->imf_inm) != NULL) { + if ((ifp = inm->inm_ifp) != NULL) { + CURVNET_SET(ifp->if_vnet); + (void)in_leavegroup(inm, imf); + CURVNET_RESTORE(); + } else { + (void)in_leavegroup(inm, imf); + } } - if (imf) - imf_purge(imf); + ip_mfilter_free(imf); } - - if (imo->imo_mfilters) - free(imo->imo_mfilters, M_INMFILTER); - free(imo->imo_membership, M_IPMOPTS); free(imo, M_IPMOPTS); } @@ -1741,7 +1665,7 @@ inp_get_source_filters(struct inpcb *inp, struct sockopt *sopt) struct sockaddr_storage *ptss; struct sockaddr_storage *tss; int error; - size_t idx, nsrcs, ncsrcs; + size_t nsrcs, ncsrcs; INP_WLOCK_ASSERT(inp); @@ -1768,12 +1692,11 @@ inp_get_source_filters(struct inpcb *inp, struct sockopt *sopt) * Lookup group on the socket. */ gsa = (sockunion_t *)&msfr.msfr_group; - idx = imo_match_group(imo, ifp, &gsa->sa); - if (idx == -1 || imo->imo_mfilters == NULL) { + imf = imo_match_group(imo, ifp, &gsa->sa); + if (imf == NULL) { INP_WUNLOCK(inp); return (EADDRNOTAVAIL); } - imf = &imo->imo_mfilters[idx]; /* * Ignore memberships which are in limbo. @@ -2033,14 +1956,11 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt) struct ip_moptions *imo; struct in_multi *inm; struct in_msource *lims; - size_t idx; int error, is_new; ifp = NULL; - imf = NULL; lims = NULL; error = 0; - is_new = 0; memset(&gsr, 0, sizeof(struct group_source_req)); gsa = (sockunion_t *)&gsr.gsr_group; @@ -2148,13 +2068,25 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt) if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) return (EADDRNOTAVAIL); + IN_MULTI_LOCK(); + + /* + * Find the membership in the membership list. + */ imo = inp_findmoptions(inp); - idx = imo_match_group(imo, ifp, &gsa->sa); - if (idx == -1) { + imf = imo_match_group(imo, ifp, &gsa->sa); + if (imf == NULL) { is_new = 1; + inm = NULL; + + if (ip_mfilter_count(&imo->imo_head) >= IP_MAX_MEMBERSHIPS) { + error = ENOMEM; + goto out_inp_locked; + } } else { - inm = imo->imo_membership[idx]; - imf = &imo->imo_mfilters[idx]; + is_new = 0; + inm = imf->imf_inm; + if (ssa->ss.ss_family != AF_UNSPEC) { /* * MCAST_JOIN_SOURCE_GROUP on an exclusive membership @@ -2181,7 +2113,7 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt) * full-state SSM API with the delta-based API, * which is discouraged in the relevant RFCs. */ - lims = imo_match_source(imo, idx, &ssa->sa); + lims = imo_match_source(imf, &ssa->sa); if (lims != NULL /*&& lims->imsl_st[1] == MCAST_INCLUDE*/) { error = EADDRNOTAVAIL; @@ -2214,27 +2146,6 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt) */ INP_WLOCK_ASSERT(inp); - if (is_new) { - if (imo->imo_num_memberships == imo->imo_max_memberships) { - error = imo_grow(imo); - if (error) - goto out_inp_locked; - } - /* - * Allocate the new slot upfront so we can deal with - * grafting the new source filter in same code path - * as for join-source on existing membership. - */ - idx = imo->imo_num_memberships; - imo->imo_membership[idx] = NULL; - imo->imo_num_memberships++; - KASSERT(imo->imo_mfilters != NULL, - ("%s: imf_mfilters vector was not allocated", __func__)); - imf = &imo->imo_mfilters[idx]; - KASSERT(RB_EMPTY(&imf->imf_sources), - ("%s: imf_sources not empty", __func__)); - } - /* * Graft new source into filter list for this inpcb's * membership of the group. The in_multi may not have @@ -2250,7 +2161,11 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt) /* Membership starts in IN mode */ if (is_new) { CTR1(KTR_IGMPV3, "%s: new join w/source", __func__); - imf_init(imf, MCAST_UNDEFINED, MCAST_INCLUDE); + imf = ip_mfilter_alloc(M_NOWAIT, MCAST_UNDEFINED, MCAST_INCLUDE); + if (imf == NULL) { + error = ENOMEM; + goto out_inp_locked; + } } else { CTR2(KTR_IGMPV3, "%s: %s source", __func__, "allow"); } @@ -2259,34 +2174,41 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt) CTR1(KTR_IGMPV3, "%s: merge imf state failed", __func__); error = ENOMEM; - goto out_imo_free; + goto out_inp_locked; } } else { /* No address specified; Membership starts in EX mode */ if (is_new) { CTR1(KTR_IGMPV3, "%s: new join w/o source", __func__); - imf_init(imf, MCAST_UNDEFINED, MCAST_EXCLUDE); + imf = ip_mfilter_alloc(M_NOWAIT, MCAST_UNDEFINED, MCAST_EXCLUDE); + if (imf == NULL) { + error = ENOMEM; + goto out_inp_locked; + } } } /* * Begin state merge transaction at IGMP layer. */ - in_pcbref(inp); - INP_WUNLOCK(inp); - IN_MULTI_LOCK(); - if (is_new) { + in_pcbref(inp); + INP_WUNLOCK(inp); + error = in_joingroup_locked(ifp, &gsa->sin.sin_addr, imf, - &inm); + &imf->imf_inm); + + INP_WLOCK(inp); + if (in_pcbrele_wlocked(inp)) { + error = ENXIO; + goto out_inp_unlocked; + } if (error) { CTR1(KTR_IGMPV3, "%s: in_joingroup_locked failed", __func__); - IN_MULTI_LIST_UNLOCK(); - goto out_imo_free; + goto out_inp_locked; } - inm_acquire(inm); - imo->imo_membership[idx] = inm; + inm_acquire(imf->imf_inm); } else { CTR1(KTR_IGMPV3, "%s: merge inm state", __func__); IN_MULTI_LIST_LOCK(); @@ -2295,7 +2217,9 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt) CTR1(KTR_IGMPV3, "%s: failed to merge inm state", __func__); IN_MULTI_LIST_UNLOCK(); - goto out_in_multi_locked; + imf_rollback(imf); + imf_reap(imf); + goto out_inp_locked; } CTR1(KTR_IGMPV3, "%s: doing igmp downcall", __func__); error = igmp_change_state(inm); @@ -2303,40 +2227,30 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt) if (error) { CTR1(KTR_IGMPV3, "%s: failed igmp downcall", __func__); - goto out_in_multi_locked; + imf_rollback(imf); + imf_reap(imf); + goto out_inp_locked; } } + if (is_new) + ip_mfilter_insert(&imo->imo_head, imf); -out_in_multi_locked: + imf_commit(imf); + imf = NULL; +out_inp_locked: + INP_WUNLOCK(inp); +out_inp_unlocked: IN_MULTI_UNLOCK(); - INP_WLOCK(inp); - if (in_pcbrele_wlocked(inp)) - return (ENXIO); - if (error) { - imf_rollback(imf); - if (is_new) - imf_purge(imf); - else - imf_reap(imf); - } else { - imf_commit(imf); - } -out_imo_free: - if (error && is_new) { - inm = imo->imo_membership[idx]; - if (inm != NULL) { + if (is_new && imf) { + if (imf->imf_inm != NULL) { IN_MULTI_LIST_LOCK(); - inm_release_deferred(inm); + inm_release_deferred(imf->imf_inm); IN_MULTI_LIST_UNLOCK(); } - imo->imo_membership[idx] = NULL; - --imo->imo_num_memberships; + ip_mfilter_free(imf); } - -out_inp_locked: - INP_WUNLOCK(inp); return (error); } @@ -2355,12 +2269,12 @@ inp_leave_group(struct inpcb *inp, struct sockopt *sopt) struct ip_moptions *imo; struct in_msource *ims; struct in_multi *inm; - size_t idx; - int error, is_final; + int error; + bool is_final; ifp = NULL; error = 0; - is_final = 1; + is_final = true; memset(&gsr, 0, sizeof(struct group_source_req)); gsa = (sockunion_t *)&gsr.gsr_group; @@ -2460,20 +2374,21 @@ inp_leave_group(struct inpcb *inp, struct sockopt *sopt) if (!IN_MULTICAST(ntohl(gsa->sin.sin_addr.s_addr))) return (EINVAL); + IN_MULTI_LOCK(); + /* - * Find the membership in the membership array. + * Find the membership in the membership list. */ imo = inp_findmoptions(inp); - idx = imo_match_group(imo, ifp, &gsa->sa); - if (idx == -1) { + imf = imo_match_group(imo, ifp, &gsa->sa); + if (imf == NULL) { error = EADDRNOTAVAIL; goto out_inp_locked; } - inm = imo->imo_membership[idx]; - imf = &imo->imo_mfilters[idx]; + inm = imf->imf_inm; if (ssa->ss.ss_family != AF_UNSPEC) - is_final = 0; + is_final = false; /* * Begin state merge transaction at socket layer. @@ -2485,13 +2400,14 @@ inp_leave_group(struct inpcb *inp, struct sockopt *sopt) * MCAST_LEAVE_SOURCE_GROUP is only valid for inclusive memberships. */ if (is_final) { + ip_mfilter_remove(&imo->imo_head, imf); imf_leave(imf); } else { if (imf->imf_st[0] == MCAST_EXCLUDE) { error = EADDRNOTAVAIL; goto out_inp_locked; } - ims = imo_match_source(imo, idx, &ssa->sa); + ims = imo_match_source(imf, &ssa->sa); if (ims == NULL) { CTR3(KTR_IGMPV3, "%s: source 0x%08x %spresent", __func__, ntohl(ssa->sin.sin_addr.s_addr), "not "); @@ -2510,17 +2426,7 @@ inp_leave_group(struct inpcb *inp, struct sockopt *sopt) /* * Begin state merge transaction at IGMP layer. */ - in_pcbref(inp); - INP_WUNLOCK(inp); - IN_MULTI_LOCK(); - - if (is_final) { - /* - * Give up the multicast address record to which - * the membership points. - */ - (void)in_leavegroup_locked(inm, imf); - } else { + if (!is_final) { CTR1(KTR_IGMPV3, "%s: merge inm state", __func__); IN_MULTI_LIST_LOCK(); error = inm_merge(inm, imf); @@ -2528,7 +2434,9 @@ inp_leave_group(struct inpcb *inp, struct sockopt *sopt) CTR1(KTR_IGMPV3, "%s: failed to merge inm state", __func__); IN_MULTI_LIST_UNLOCK(); - goto out_in_multi_locked; + imf_rollback(imf); + imf_reap(imf); + goto out_inp_locked; } CTR1(KTR_IGMPV3, "%s: doing igmp downcall", __func__); @@ -2537,38 +2445,27 @@ inp_leave_group(struct inpcb *inp, struct sockopt *sopt) if (error) { CTR1(KTR_IGMPV3, "%s: failed igmp downcall", __func__); + imf_rollback(imf); + imf_reap(imf); + goto out_inp_locked; } } - -out_in_multi_locked: - - IN_MULTI_UNLOCK(); - INP_WLOCK(inp); - if (in_pcbrele_wlocked(inp)) - return (ENXIO); - - if (error) - imf_rollback(imf); - else - imf_commit(imf); - + imf_commit(imf); imf_reap(imf); - if (is_final) { - /* Remove the gap in the membership and filter array. */ - KASSERT(RB_EMPTY(&imf->imf_sources), - ("%s: imf_sources not empty", __func__)); - for (++idx; idx < imo->imo_num_memberships; ++idx) { - imo->imo_membership[idx - 1] = imo->imo_membership[idx]; - imo->imo_mfilters[idx - 1] = imo->imo_mfilters[idx]; - } - imf_init(&imo->imo_mfilters[idx - 1], MCAST_UNDEFINED, - MCAST_EXCLUDE); - imo->imo_num_memberships--; - } - out_inp_locked: INP_WUNLOCK(inp); + + if (is_final && imf) { + /* + * Give up the multicast address record to which + * the membership points. + */ + (void) in_leavegroup_locked(imf->imf_inm, imf); + ip_mfilter_free(imf); + } + + IN_MULTI_UNLOCK(); return (error); } @@ -2658,7 +2555,6 @@ inp_set_source_filters(struct inpcb *inp, struct sockopt *sopt) struct in_mfilter *imf; struct ip_moptions *imo; struct in_multi *inm; - size_t idx; int error; error = sooptcopyin(sopt, &msfr, sizeof(struct __msfilterreq), @@ -2690,18 +2586,19 @@ inp_set_source_filters(struct inpcb *inp, struct sockopt *sopt) if (ifp == NULL) return (EADDRNOTAVAIL); + IN_MULTI_LOCK(); + /* * Take the INP write lock. * Check if this socket is a member of this group. */ imo = inp_findmoptions(inp); - idx = imo_match_group(imo, ifp, &gsa->sa); - if (idx == -1 || imo->imo_mfilters == NULL) { + imf = imo_match_group(imo, ifp, &gsa->sa); + if (imf == NULL) { error = EADDRNOTAVAIL; goto out_inp_locked; } - inm = imo->imo_membership[idx]; - imf = &imo->imo_mfilters[idx]; + inm = imf->imf_inm; /* * Begin state merge transaction at socket layer. @@ -2778,7 +2675,6 @@ inp_set_source_filters(struct inpcb *inp, struct sockopt *sopt) goto out_imf_rollback; INP_WLOCK_ASSERT(inp); - IN_MULTI_LOCK(); /* * Begin state merge transaction at IGMP layer. @@ -2789,7 +2685,7 @@ inp_set_source_filters(struct inpcb *inp, struct sockopt *sopt) if (error) { CTR1(KTR_IGMPV3, "%s: failed to merge inm state", __func__); IN_MULTI_LIST_UNLOCK(); - goto out_in_multi_locked; + goto out_imf_rollback; } CTR1(KTR_IGMPV3, "%s: doing igmp downcall", __func__); @@ -2798,10 +2694,6 @@ inp_set_source_filters(struct inpcb *inp, struct sockopt *sopt) if (error) CTR1(KTR_IGMPV3, "%s: failed igmp downcall", __func__); -out_in_multi_locked: - - IN_MULTI_UNLOCK(); - out_imf_rollback: if (error) imf_rollback(imf); @@ -2812,6 +2704,7 @@ out_imf_rollback: out_inp_locked: INP_WUNLOCK(inp); + IN_MULTI_UNLOCK(); return (error); } diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c index 17fa34895595..b68475afa655 100644 --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -86,6 +86,9 @@ __FBSDID("$FreeBSD$"); #if defined(INET) || defined(INET6) #include <netinet/in.h> #include <netinet/in_pcb.h> +#ifdef INET +#include <netinet/in_var.h> +#endif #include <netinet/ip_var.h> #include <netinet/tcp_var.h> #ifdef TCPHPTS @@ -93,16 +96,13 @@ __FBSDID("$FreeBSD$"); #endif #include <netinet/udp.h> #include <netinet/udp_var.h> -#endif -#ifdef INET -#include <netinet/in_var.h> -#endif #ifdef INET6 #include <netinet/ip6.h> #include <netinet6/in6_pcb.h> #include <netinet6/in6_var.h> #include <netinet6/ip6_var.h> #endif /* INET6 */ +#endif #include <netipsec/ipsec_support.h> @@ -1779,8 +1779,9 @@ void in_pcbpurgeif0(struct inpcbinfo *pcbinfo, struct ifnet *ifp) { struct inpcb *inp; + struct in_multi *inm; + struct in_mfilter *imf; struct ip_moptions *imo; - int i, gap; INP_INFO_WLOCK(pcbinfo); CK_LIST_FOREACH(inp, pcbinfo->ipi_listhead, inp_list) { @@ -1801,17 +1802,18 @@ in_pcbpurgeif0(struct inpcbinfo *pcbinfo, struct ifnet *ifp) * * XXX This can all be deferred to an epoch_call */ - for (i = 0, gap = 0; i < imo->imo_num_memberships; - i++) { - if (imo->imo_membership[i]->inm_ifp == ifp) { - IN_MULTI_LOCK_ASSERT(); - in_leavegroup_locked(imo->imo_membership[i], NULL); - gap++; - } else if (gap != 0) - imo->imo_membership[i - gap] = - imo->imo_membership[i]; +restart: + IP_MFILTER_FOREACH(imf, &imo->imo_head) { + if ((inm = imf->imf_inm) == NULL) + continue; + if (inm->inm_ifp != ifp) + continue; + ip_mfilter_remove(&imo->imo_head, imf); + IN_MULTI_LOCK_ASSERT(); + in_leavegroup_locked(inm, NULL); + ip_mfilter_free(imf); + goto restart; } - imo->imo_num_memberships -= gap; } INP_WUNLOCK(inp); } diff --git a/sys/netinet/in_var.h b/sys/netinet/in_var.h index 5b7a464bd3e8..50112481f236 100644 --- a/sys/netinet/in_var.h +++ b/sys/netinet/in_var.h @@ -232,9 +232,61 @@ struct in_mfilter { struct ip_msource_tree imf_sources; /* source list for (S,G) */ u_long imf_nsrc; /* # of source entries */ uint8_t imf_st[2]; /* state before/at commit */ + struct in_multi *imf_inm; /* associated multicast address */ + STAILQ_ENTRY(in_mfilter) imf_entry; /* list entry */ }; /* + * Helper types and functions for IPv4 multicast filters. + */ +STAILQ_HEAD(ip_mfilter_head, in_mfilter); + +struct in_mfilter *ip_mfilter_alloc(int mflags, int st0, int st1); +void ip_mfilter_free(struct in_mfilter *); + +static inline void +ip_mfilter_init(struct ip_mfilter_head *head) +{ + + STAILQ_INIT(head); +} + +static inline struct in_mfilter * +ip_mfilter_first(const struct ip_mfilter_head *head) +{ + + return (STAILQ_FIRST(head)); +} + +static inline void +ip_mfilter_insert(struct ip_mfilter_head *head, struct in_mfilter *imf) +{ + + STAILQ_INSERT_TAIL(head, imf, imf_entry); +} + +static inline void +ip_mfilter_remove(struct ip_mfilter_head *head, struct in_mfilter *imf) +{ + + STAILQ_REMOVE(head, imf, in_mfilter, imf_entry); +} + +#define IP_MFILTER_FOREACH(imf, head) \ + STAILQ_FOREACH(imf, head, imf_entry) + +static inline size_t +ip_mfilter_count(struct ip_mfilter_head *head) +{ + struct in_mfilter *imf; + size_t num = 0; + + STAILQ_FOREACH(imf, head, imf_entry) + num++; + return (num); +} + +/* * IPv4 group descriptor. * * For every entry on an ifnet's if_multiaddrs list which represents diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c index 9c24fb9fdd67..819a0f9c75e6 100644 --- a/sys/netinet/ip_carp.c +++ b/sys/netinet/ip_carp.c @@ -1371,25 +1371,24 @@ carp_multicast_setup(struct carp_if *cif, sa_family_t sa) case AF_INET: { struct ip_moptions *imo = &cif->cif_imo; + struct in_mfilter *imf; struct in_addr addr; - if (imo->imo_membership) + if (ip_mfilter_first(&imo->imo_head) != NULL) return (0); - imo->imo_membership = (struct in_multi **)malloc( - (sizeof(struct in_multi *) * IP_MIN_MEMBERSHIPS), M_CARP, - M_WAITOK); - imo->imo_mfilters = NULL; - imo->imo_max_memberships = IP_MIN_MEMBERSHIPS; + imf = ip_mfilter_alloc(M_WAITOK, 0, 0); + ip_mfilter_init(&imo->imo_head); imo->imo_multicast_vif = -1; addr.s_addr = htonl(INADDR_CARP_GROUP); if ((error = in_joingroup(ifp, &addr, NULL, - &imo->imo_membership[0])) != 0) { - free(imo->imo_membership, M_CARP); + &imf->imf_inm)) != 0) { + ip_mfilter_free(imf); break; } - imo->imo_num_memberships++; + + ip_mfilter_insert(&imo->imo_head, imf); imo->imo_multicast_ifp = ifp; imo->imo_multicast_ttl = CARP_DFLTTL; imo->imo_multicast_loop = 0; @@ -1400,17 +1399,16 @@ carp_multicast_setup(struct carp_if *cif, sa_family_t sa) case AF_INET6: { struct ip6_moptions *im6o = &cif->cif_im6o; + struct in6_mfilter *im6f[2]; struct in6_addr in6; - struct in6_multi *in6m; - if (im6o->im6o_membership) + if (ip6_mfilter_first(&im6o->im6o_head)) return (0); - im6o->im6o_membership = (struct in6_multi **)malloc( - (sizeof(struct in6_multi *) * IPV6_MIN_MEMBERSHIPS), M_CARP, - M_ZERO | M_WAITOK); - im6o->im6o_mfilters = NULL; - im6o->im6o_max_memberships = IPV6_MIN_MEMBERSHIPS; + im6f[0] = ip6_mfilter_alloc(M_WAITOK, 0, 0); + im6f[1] = ip6_mfilter_alloc(M_WAITOK, 0, 0); + + ip6_mfilter_init(&im6o->im6o_head); im6o->im6o_multicast_hlim = CARP_DFLTTL; im6o->im6o_multicast_ifp = ifp; @@ -1419,17 +1417,15 @@ carp_multicast_setup(struct carp_if *cif, sa_family_t sa) in6.s6_addr16[0] = htons(0xff02); in6.s6_addr8[15] = 0x12; if ((error = in6_setscope(&in6, ifp, NULL)) != 0) { - free(im6o->im6o_membership, M_CARP); + ip6_mfilter_free(im6f[0]); + ip6_mfilter_free(im6f[1]); break; } - in6m = NULL; - if ((error = in6_joingroup(ifp, &in6, NULL, &in6m, 0)) != 0) { - free(im6o->im6o_membership, M_CARP); + if ((error = in6_joingroup(ifp, &in6, NULL, &im6f[0]->im6f_in6m, 0)) != 0) { + ip6_mfilter_free(im6f[0]); + ip6_mfilter_free(im6f[1]); break; } - in6m_acquire(in6m); - im6o->im6o_membership[0] = in6m; - im6o->im6o_num_memberships++; /* Join solicited multicast address. */ bzero(&in6, sizeof(in6)); @@ -1438,20 +1434,21 @@ carp_multicast_setup(struct carp_if *cif, sa_family_t sa) in6.s6_addr32[2] = htonl(1); in6.s6_addr32[3] = 0; in6.s6_addr8[12] = 0xff; + if ((error = in6_setscope(&in6, ifp, NULL)) != 0) { - in6_leavegroup(im6o->im6o_membership[0], NULL); - free(im6o->im6o_membership, M_CARP); + ip6_mfilter_free(im6f[0]); + ip6_mfilter_free(im6f[1]); break; } - in6m = NULL; - if ((error = in6_joingroup(ifp, &in6, NULL, &in6m, 0)) != 0) { - in6_leavegroup(im6o->im6o_membership[0], NULL); - free(im6o->im6o_membership, M_CARP); + + if ((error = in6_joingroup(ifp, &in6, NULL, &im6f[1]->im6f_in6m, 0)) != 0) { + in6_leavegroup(im6f[0]->im6f_in6m, NULL); + ip6_mfilter_free(im6f[0]); + ip6_mfilter_free(im6f[1]); break; } - in6m_acquire(in6m); - im6o->im6o_membership[1] = in6m; - im6o->im6o_num_memberships++; + ip6_mfilter_insert(&im6o->im6o_head, im6f[0]); + ip6_mfilter_insert(&im6o->im6o_head, im6f[1]); break; } #endif @@ -1466,35 +1463,38 @@ carp_multicast_setup(struct carp_if *cif, sa_family_t sa) static void carp_multicast_cleanup(struct carp_if *cif, sa_family_t sa) { - +#ifdef INET + struct ip_moptions *imo = &cif->cif_imo; + struct in_mfilter *imf; +#endif +#ifdef INET6 + struct ip6_moptions *im6o = &cif->cif_im6o; + struct in6_mfilter *im6f; +#endif sx_assert(&carp_sx, SA_XLOCKED); switch (sa) { #ifdef INET case AF_INET: - if (cif->cif_naddrs == 0) { - struct ip_moptions *imo = &cif->cif_imo; - - in_leavegroup(imo->imo_membership[0], NULL); - KASSERT(imo->imo_mfilters == NULL, - ("%s: imo_mfilters != NULL", __func__)); - free(imo->imo_membership, M_CARP); - imo->imo_membership = NULL; + if (cif->cif_naddrs != 0) + break; + while ((imf = ip_mfilter_first(&imo->imo_head)) != NULL) { + ip_mfilter_remove(&imo->imo_head, imf); + in_leavegroup(imf->imf_inm, NULL); + ip_mfilter_free(imf); } break; #endif #ifdef INET6 case AF_INET6: - if (cif->cif_naddrs6 == 0) { - struct ip6_moptions *im6o = &cif->cif_im6o; - - in6_leavegroup(im6o->im6o_membership[0], NULL); - in6_leavegroup(im6o->im6o_membership[1], NULL); - KASSERT(im6o->im6o_mfilters == NULL, - ("%s: im6o_mfilters != NULL", __func__)); - free(im6o->im6o_membership, M_CARP); - im6o->im6o_membership = NULL; + if (cif->cif_naddrs6 != 0) + break; + + while ((im6f = ip6_mfilter_first(&im6o->im6o_head)) != NULL) { + ip6_mfilter_remove(&im6o->im6o_head, im6f); + in6_leavegroup(im6f->im6f_in6m, NULL); + ip6_mfilter_free(im6f); } break; #endif diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h index de0cc29db1d2..7a01c82ba58b 100644 --- a/sys/netinet/ip_fw.h +++ b/sys/netinet/ip_fw.h @@ -293,6 +293,7 @@ enum ipfw_opcodes { /* arguments (4 byte each) */ O_EXTERNAL_DATA, /* variable length data */ O_SKIP_ACTION, /* none */ + O_TCPMSS, /* arg1=MSS value */ O_LAST_OPCODE /* not an opcode! */ }; diff --git a/sys/netinet/ip_mroute.c b/sys/netinet/ip_mroute.c index 0439d353575d..14ebb6ef1007 100644 --- a/sys/netinet/ip_mroute.c +++ b/sys/netinet/ip_mroute.c @@ -1680,7 +1680,6 @@ static void send_packet(struct vif *vifp, struct mbuf *m) { struct ip_moptions imo; - struct in_multi *imm[2]; int error __unused; VIF_LOCK_ASSERT(); @@ -1689,9 +1688,7 @@ send_packet(struct vif *vifp, struct mbuf *m) imo.imo_multicast_ttl = mtod(m, struct ip *)->ip_ttl - 1; imo.imo_multicast_loop = 1; imo.imo_multicast_vif = -1; - imo.imo_num_memberships = 0; - imo.imo_max_memberships = 2; - imo.imo_membership = &imm[0]; + STAILQ_INIT(&imo.imo_head); /* * Re-entrancy should not be a problem here, because diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c index 99b8c3662be5..2a7eb7f56286 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -109,20 +109,24 @@ extern int in_mcast_loop; extern struct protosw inetsw[]; static inline int -ip_output_pfil(struct mbuf **mp, struct ifnet *ifp, struct inpcb *inp, - struct sockaddr_in *dst, int *fibnum, int *error) +ip_output_pfil(struct mbuf **mp, struct ifnet *ifp, int flags, + struct inpcb *inp, struct sockaddr_in *dst, int *fibnum, int *error) { struct m_tag *fwd_tag = NULL; struct mbuf *m; struct in_addr odst; struct ip *ip; + int pflags = PFIL_OUT; + + if (flags & IP_FORWARDING) + pflags |= PFIL_FWD; m = *mp; ip = mtod(m, struct ip *); /* Run through list of hooks for output packets. */ odst.s_addr = ip->ip_dst.s_addr; - switch (pfil_run_hooks(V_inet_pfil_head, mp, ifp, PFIL_OUT, inp)) { + switch (pfil_run_hooks(V_inet_pfil_head, mp, ifp, pflags, inp)) { case PFIL_DROPPED: *error = EPERM; /* FALLTHROUGH */ @@ -653,7 +657,8 @@ sendit: /* Jump over all PFIL processing if hooks are not active. */ if (PFIL_HOOKED_OUT(V_inet_pfil_head)) { - switch (ip_output_pfil(&m, ifp, inp, dst, &fibnum, &error)) { + switch (ip_output_pfil(&m, ifp, flags, inp, dst, &fibnum, + &error)) { case 1: /* Finished */ goto done; diff --git a/sys/netinet/ip_var.h b/sys/netinet/ip_var.h index 38602efb3f4e..7580a7b45212 100644 --- a/sys/netinet/ip_var.h +++ b/sys/netinet/ip_var.h @@ -82,6 +82,7 @@ struct ipoption { char ipopt_list[MAX_IPOPTLEN]; /* options proper */ }; +#if defined(_NETINET_IN_VAR_H_) && defined(_KERNEL) /* * Structure attached to inpcb.ip_moptions and * passed to ip_output when IP multicast options are in use. @@ -93,12 +94,11 @@ struct ip_moptions { u_long imo_multicast_vif; /* vif num outgoing multicasts */ u_char imo_multicast_ttl; /* TTL for outgoing multicasts */ u_char imo_multicast_loop; /* 1 => hear sends if a member */ - u_short imo_num_memberships; /* no. memberships this socket */ - u_short imo_max_memberships; /* max memberships this socket */ - struct in_multi **imo_membership; /* group memberships */ - struct in_mfilter *imo_mfilters; /* source filters */ - struct epoch_context imo_epoch_ctx; + struct ip_mfilter_head imo_head; /* group membership list */ }; +#else +struct ip_moptions; +#endif struct ipstat { uint64_t ips_total; /* total packets received */ diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c index 4ac87cb0d470..8f767305f97d 100644 --- a/sys/netinet/tcp_subr.c +++ b/sys/netinet/tcp_subr.c @@ -798,8 +798,12 @@ register_tcp_functions_as_names(struct tcp_function_block *blk, int wait, } } + if (blk->tfb_flags & TCP_FUNC_BEING_REMOVED) { + *num_names = 0; + return (EINVAL); + } + refcount_init(&blk->tfb_refcnt, 0); - blk->tfb_flags = 0; blk->tfb_id = atomic_fetchadd_int(&next_tcp_stack_id, 1); for (i = 0; i < *num_names; i++) { n = malloc(sizeof(struct tcp_function), M_TCPFUNCTIONS, wait); diff --git a/sys/netinet6/in6.h b/sys/netinet6/in6.h index 37d6ad40289e..56ab11460af2 100644 --- a/sys/netinet6/in6.h +++ b/sys/netinet6/in6.h @@ -523,11 +523,8 @@ struct route_in6 { #define IPV6_DEFAULT_MULTICAST_LOOP 1 /* normally hear sends if a member */ /* - * The im6o_membership vector for each socket is now dynamically allocated at - * run-time, bounded by USHRT_MAX, and is reallocated when needed, sized - * according to a power-of-two increment. + * Limit for IPv6 multicast memberships */ -#define IPV6_MIN_MEMBERSHIPS 31 #define IPV6_MAX_MEMBERSHIPS 4095 /* diff --git a/sys/netinet6/in6_ifattach.c b/sys/netinet6/in6_ifattach.c index a1a707449bf2..7ce680f2f91a 100644 --- a/sys/netinet6/in6_ifattach.c +++ b/sys/netinet6/in6_ifattach.c @@ -774,9 +774,11 @@ _in6_ifdetach(struct ifnet *ifp, int purgeulp) in6_purgeaddr(ifa); } if (purgeulp) { + IN6_MULTI_LOCK(); in6_pcbpurgeif0(&V_udbinfo, ifp); in6_pcbpurgeif0(&V_ulitecbinfo, ifp); in6_pcbpurgeif0(&V_ripcbinfo, ifp); + IN6_MULTI_UNLOCK(); } /* leave from all multicast groups joined */ in6_purgemaddrs(ifp); diff --git a/sys/netinet6/in6_mcast.c b/sys/netinet6/in6_mcast.c index 5557a7c76564..f68b0a84d17d 100644 --- a/sys/netinet6/in6_mcast.c +++ b/sys/netinet6/in6_mcast.c @@ -102,7 +102,8 @@ RB_GENERATE(ip6_msource_tree, ip6_msource, im6s_link, ip6_msource_cmp); /* * Locking: - * - Lock order is: Giant, INP_WLOCK, IN6_MULTI_LOCK, MLD_LOCK, IF_ADDR_LOCK. + * - Lock order is: Giant, IN6_MULTI_LOCK, INP_WLOCK, + * IN6_MULTI_LIST_LOCK, MLD_LOCK, IF_ADDR_LOCK. * - The IF_ADDR_LOCK is implicitly taken by in6m_lookup() earlier, however * it can be taken by code in net/if.c also. * - ip6_moptions and in6_mfilter are covered by the INP_WLOCK. @@ -134,12 +135,11 @@ static int im6f_prune(struct in6_mfilter *, const struct sockaddr_in6 *); static void im6f_purge(struct in6_mfilter *); static void im6f_rollback(struct in6_mfilter *); static void im6f_reap(struct in6_mfilter *); -static int im6o_grow(struct ip6_moptions *); -static size_t im6o_match_group(const struct ip6_moptions *, +static struct in6_mfilter * + im6o_match_group(const struct ip6_moptions *, const struct ifnet *, const struct sockaddr *); static struct in6_msource * - im6o_match_source(const struct ip6_moptions *, const size_t, - const struct sockaddr *); + im6o_match_source(struct in6_mfilter *, const struct sockaddr *); static void im6s_merge(struct ip6_msource *ims, const struct in6_msource *lims, const int rollback); static int in6_getmulti(struct ifnet *, const struct in6_addr *, @@ -228,55 +228,25 @@ im6f_init(struct in6_mfilter *imf, const int st0, const int st1) imf->im6f_st[1] = st1; } -/* - * Resize the ip6_moptions vector to the next power-of-two minus 1. - * May be called with locks held; do not sleep. - */ -static int -im6o_grow(struct ip6_moptions *imo) +struct in6_mfilter * +ip6_mfilter_alloc(const int mflags, const int st0, const int st1) { - struct in6_multi **nmships; - struct in6_multi **omships; - struct in6_mfilter *nmfilters; - struct in6_mfilter *omfilters; - size_t idx; - size_t newmax; - size_t oldmax; - - nmships = NULL; - nmfilters = NULL; - omships = imo->im6o_membership; - omfilters = imo->im6o_mfilters; - oldmax = imo->im6o_max_memberships; - newmax = ((oldmax + 1) * 2) - 1; - - if (newmax <= IPV6_MAX_MEMBERSHIPS) { - nmships = (struct in6_multi **)realloc(omships, - sizeof(struct in6_multi *) * newmax, M_IP6MOPTS, M_NOWAIT); - nmfilters = (struct in6_mfilter *)realloc(omfilters, - sizeof(struct in6_mfilter) * newmax, M_IN6MFILTER, - M_NOWAIT); - if (nmships != NULL && nmfilters != NULL) { - /* Initialize newly allocated source filter heads. */ - for (idx = oldmax; idx < newmax; idx++) { - im6f_init(&nmfilters[idx], MCAST_UNDEFINED, - MCAST_EXCLUDE); - } - imo->im6o_max_memberships = newmax; - imo->im6o_membership = nmships; - imo->im6o_mfilters = nmfilters; - } - } + struct in6_mfilter *imf; - if (nmships == NULL || nmfilters == NULL) { - if (nmships != NULL) - free(nmships, M_IP6MOPTS); - if (nmfilters != NULL) - free(nmfilters, M_IN6MFILTER); - return (ETOOMANYREFS); - } + imf = malloc(sizeof(*imf), M_IN6MFILTER, mflags); - return (0); + if (imf != NULL) + im6f_init(imf, st0, st1); + + return (imf); +} + +void +ip6_mfilter_free(struct in6_mfilter *imf) +{ + + im6f_purge(imf); + free(imf, M_IN6MFILTER); } /* @@ -284,36 +254,27 @@ im6o_grow(struct ip6_moptions *imo) * which matches the specified group, and optionally an interface. * Return its index into the array, or -1 if not found. */ -static size_t +static struct in6_mfilter * im6o_match_group(const struct ip6_moptions *imo, const struct ifnet *ifp, const struct sockaddr *group) { const struct sockaddr_in6 *gsin6; - struct in6_multi **pinm; - int idx; - int nmships; + struct in6_mfilter *imf; + struct in6_multi *inm; - gsin6 = (const struct sockaddr_in6 *)group; + gsin6 = (const struct sockaddr_in6 *)group; - /* The im6o_membership array may be lazy allocated. */ - if (imo->im6o_membership == NULL || imo->im6o_num_memberships == 0) - return (-1); - - nmships = imo->im6o_num_memberships; - pinm = &imo->im6o_membership[0]; - for (idx = 0; idx < nmships; idx++, pinm++) { - if (*pinm == NULL) + IP6_MFILTER_FOREACH(imf, &imo->im6o_head) { + inm = imf->im6f_in6m; + if (inm == NULL) continue; - if ((ifp == NULL || ((*pinm)->in6m_ifp == ifp)) && - IN6_ARE_ADDR_EQUAL(&(*pinm)->in6m_addr, + if ((ifp == NULL || (inm->in6m_ifp == ifp)) && + IN6_ARE_ADDR_EQUAL(&inm->in6m_addr, &gsin6->sin6_addr)) { break; } } - if (idx >= nmships) - idx = -1; - - return (idx); + return (imf); } /* @@ -328,22 +289,13 @@ im6o_match_group(const struct ip6_moptions *imo, const struct ifnet *ifp, * it exists, which may not be the desired behaviour. */ static struct in6_msource * -im6o_match_source(const struct ip6_moptions *imo, const size_t gidx, - const struct sockaddr *src) +im6o_match_source(struct in6_mfilter *imf, const struct sockaddr *src) { struct ip6_msource find; - struct in6_mfilter *imf; struct ip6_msource *ims; const sockunion_t *psa; KASSERT(src->sa_family == AF_INET6, ("%s: !AF_INET6", __func__)); - KASSERT(gidx != -1 && gidx < imo->im6o_num_memberships, - ("%s: invalid index %d\n", __func__, (int)gidx)); - - /* The im6o_mfilters array may be lazy allocated. */ - if (imo->im6o_mfilters == NULL) - return (NULL); - imf = &imo->im6o_mfilters[gidx]; psa = (const sockunion_t *)src; find.im6s_addr = psa->sin6.sin6_addr; @@ -363,14 +315,14 @@ int im6o_mc_filter(const struct ip6_moptions *imo, const struct ifnet *ifp, const struct sockaddr *group, const struct sockaddr *src) { - size_t gidx; + struct in6_mfilter *imf; struct in6_msource *ims; int mode; KASSERT(ifp != NULL, ("%s: null ifp", __func__)); - gidx = im6o_match_group(imo, ifp, group); - if (gidx == -1) + imf = im6o_match_group(imo, ifp, group); + if (imf == NULL) return (MCAST_NOTGMEMBER); /* @@ -382,8 +334,8 @@ im6o_mc_filter(const struct ip6_moptions *imo, const struct ifnet *ifp, * NOTE: We are comparing group state here at MLD t1 (now) * with socket-layer t0 (since last downcall). */ - mode = imo->im6o_mfilters[gidx].im6f_st[1]; - ims = im6o_match_source(imo, gidx, src); + mode = imf->im6f_st[1]; + ims = im6o_match_source(imf, src); if ((ims == NULL && mode == MCAST_INCLUDE) || (ims != NULL && ims->im6sl_st[0] != mode)) @@ -1447,7 +1399,6 @@ in6p_block_unblock_source(struct inpcb *inp, struct sockopt *sopt) struct ip6_moptions *imo; struct in6_msource *ims; struct in6_multi *inm; - size_t idx; uint16_t fmode; int error, doblock; #ifdef KTR @@ -1504,16 +1455,12 @@ in6p_block_unblock_source(struct inpcb *inp, struct sockopt *sopt) * Check if we are actually a member of this group. */ imo = in6p_findmoptions(inp); - idx = im6o_match_group(imo, ifp, &gsa->sa); - if (idx == -1 || imo->im6o_mfilters == NULL) { + imf = im6o_match_group(imo, ifp, &gsa->sa); + if (imf == NULL) { error = EADDRNOTAVAIL; goto out_in6p_locked; } - - KASSERT(imo->im6o_mfilters != NULL, - ("%s: im6o_mfilters not allocated", __func__)); - imf = &imo->im6o_mfilters[idx]; - inm = imo->im6o_membership[idx]; + inm = imf->im6f_in6m; /* * Attempting to use the delta-based API on an @@ -1531,7 +1478,7 @@ in6p_block_unblock_source(struct inpcb *inp, struct sockopt *sopt) * Asked to unblock, but nothing to unblock. * If adding a new block entry, allocate it. */ - ims = im6o_match_source(imo, idx, &ssa->sa); + ims = im6o_match_source(imf, &ssa->sa); if ((ims != NULL && doblock) || (ims == NULL && !doblock)) { CTR3(KTR_MLD, "%s: source %s %spresent", __func__, ip6_sprintf(ip6tbuf, &ssa->sin6.sin6_addr), @@ -1601,9 +1548,6 @@ static struct ip6_moptions * in6p_findmoptions(struct inpcb *inp) { struct ip6_moptions *imo; - struct in6_multi **immp; - struct in6_mfilter *imfp; - size_t idx; INP_WLOCK(inp); if (inp->in6p_moptions != NULL) @@ -1612,27 +1556,14 @@ in6p_findmoptions(struct inpcb *inp) INP_WUNLOCK(inp); imo = malloc(sizeof(*imo), M_IP6MOPTS, M_WAITOK); - immp = malloc(sizeof(*immp) * IPV6_MIN_MEMBERSHIPS, M_IP6MOPTS, - M_WAITOK | M_ZERO); - imfp = malloc(sizeof(struct in6_mfilter) * IPV6_MIN_MEMBERSHIPS, - M_IN6MFILTER, M_WAITOK); imo->im6o_multicast_ifp = NULL; imo->im6o_multicast_hlim = V_ip6_defmcasthlim; imo->im6o_multicast_loop = in6_mcast_loop; - imo->im6o_num_memberships = 0; - imo->im6o_max_memberships = IPV6_MIN_MEMBERSHIPS; - imo->im6o_membership = immp; - - /* Initialize per-group source filters. */ - for (idx = 0; idx < IPV6_MIN_MEMBERSHIPS; idx++) - im6f_init(&imfp[idx], MCAST_UNDEFINED, MCAST_EXCLUDE); - imo->im6o_mfilters = imfp; + STAILQ_INIT(&imo->im6o_head); INP_WLOCK(inp); if (inp->in6p_moptions != NULL) { - free(imfp, M_IN6MFILTER); - free(immp, M_IP6MOPTS); free(imo, M_IP6MOPTS); return (inp->in6p_moptions); } @@ -1652,33 +1583,26 @@ in6p_findmoptions(struct inpcb *inp) static void inp_gcmoptions(struct ip6_moptions *imo) { - struct in6_mfilter *imf; + struct in6_mfilter *imf; struct in6_multi *inm; struct ifnet *ifp; - size_t idx, nmships; - - nmships = imo->im6o_num_memberships; - for (idx = 0; idx < nmships; ++idx) { - imf = imo->im6o_mfilters ? &imo->im6o_mfilters[idx] : NULL; - if (imf) - im6f_leave(imf); - inm = imo->im6o_membership[idx]; - ifp = inm->in6m_ifp; - if (ifp != NULL) { - CURVNET_SET(ifp->if_vnet); - (void)in6_leavegroup(inm, imf); - CURVNET_RESTORE(); - } else { - (void)in6_leavegroup(inm, imf); - } - if (imf) - im6f_purge(imf); - } - if (imo->im6o_mfilters) - free(imo->im6o_mfilters, M_IN6MFILTER); - free(imo->im6o_membership, M_IP6MOPTS); - free(imo, M_IP6MOPTS); + while ((imf = ip6_mfilter_first(&imo->im6o_head)) != NULL) { + ip6_mfilter_remove(&imo->im6o_head, imf); + + im6f_leave(imf); + if ((inm = imf->im6f_in6m) != NULL) { + if ((ifp = inm->in6m_ifp) != NULL) { + CURVNET_SET(ifp->if_vnet); + (void)in6_leavegroup(inm, imf); + CURVNET_RESTORE(); + } else { + (void)in6_leavegroup(inm, imf); + } + } + ip6_mfilter_free(imf); + } + free(imo, M_IP6MOPTS); } void @@ -1707,7 +1631,7 @@ in6p_get_source_filters(struct inpcb *inp, struct sockopt *sopt) struct sockaddr_storage *ptss; struct sockaddr_storage *tss; int error; - size_t idx, nsrcs, ncsrcs; + size_t nsrcs, ncsrcs; INP_WLOCK_ASSERT(inp); @@ -1741,12 +1665,11 @@ in6p_get_source_filters(struct inpcb *inp, struct sockopt *sopt) /* * Lookup group on the socket. */ - idx = im6o_match_group(imo, ifp, &gsa->sa); - if (idx == -1 || imo->im6o_mfilters == NULL) { + imf = im6o_match_group(imo, ifp, &gsa->sa); + if (imf == NULL) { INP_WUNLOCK(inp); return (EADDRNOTAVAIL); } - imf = &imo->im6o_mfilters[idx]; /* * Ignore memberships which are in limbo. @@ -1943,15 +1866,12 @@ in6p_join_group(struct inpcb *inp, struct sockopt *sopt) struct ip6_moptions *imo; struct in6_multi *inm; struct in6_msource *lims; - size_t idx; int error, is_new; SLIST_INIT(&inmh); ifp = NULL; - imf = NULL; lims = NULL; error = 0; - is_new = 0; memset(&gsr, 0, sizeof(struct group_source_req)); gsa = (sockunion_t *)&gsr.gsr_group; @@ -2052,13 +1972,25 @@ in6p_join_group(struct inpcb *inp, struct sockopt *sopt) */ (void)in6_setscope(&gsa->sin6.sin6_addr, ifp, NULL); + IN6_MULTI_LOCK(); + + /* + * Find the membership in the membership list. + */ imo = in6p_findmoptions(inp); - idx = im6o_match_group(imo, ifp, &gsa->sa); - if (idx == -1) { + imf = im6o_match_group(imo, ifp, &gsa->sa); + if (imf == NULL) { is_new = 1; + inm = NULL; + + if (ip6_mfilter_count(&imo->im6o_head) >= IPV6_MAX_MEMBERSHIPS) { + error = ENOMEM; + goto out_in6p_locked; + } } else { - inm = imo->im6o_membership[idx]; - imf = &imo->im6o_mfilters[idx]; + is_new = 0; + inm = imf->im6f_in6m; + if (ssa->ss.ss_family != AF_UNSPEC) { /* * MCAST_JOIN_SOURCE_GROUP on an exclusive membership @@ -2085,7 +2017,7 @@ in6p_join_group(struct inpcb *inp, struct sockopt *sopt) * full-state SSM API with the delta-based API, * which is discouraged in the relevant RFCs. */ - lims = im6o_match_source(imo, idx, &ssa->sa); + lims = im6o_match_source(imf, &ssa->sa); if (lims != NULL /*&& lims->im6sl_st[1] == MCAST_INCLUDE*/) { error = EADDRNOTAVAIL; @@ -2113,27 +2045,6 @@ in6p_join_group(struct inpcb *inp, struct sockopt *sopt) */ INP_WLOCK_ASSERT(inp); - if (is_new) { - if (imo->im6o_num_memberships == imo->im6o_max_memberships) { - error = im6o_grow(imo); - if (error) - goto out_in6p_locked; - } - /* - * Allocate the new slot upfront so we can deal with - * grafting the new source filter in same code path - * as for join-source on existing membership. - */ - idx = imo->im6o_num_memberships; - imo->im6o_membership[idx] = NULL; - imo->im6o_num_memberships++; - KASSERT(imo->im6o_mfilters != NULL, - ("%s: im6f_mfilters vector was not allocated", __func__)); - imf = &imo->im6o_mfilters[idx]; - KASSERT(RB_EMPTY(&imf->im6f_sources), - ("%s: im6f_sources not empty", __func__)); - } - /* * Graft new source into filter list for this inpcb's * membership of the group. The in6_multi may not have @@ -2149,7 +2060,11 @@ in6p_join_group(struct inpcb *inp, struct sockopt *sopt) /* Membership starts in IN mode */ if (is_new) { CTR1(KTR_MLD, "%s: new join w/source", __func__); - im6f_init(imf, MCAST_UNDEFINED, MCAST_INCLUDE); + imf = ip6_mfilter_alloc(M_NOWAIT, MCAST_UNDEFINED, MCAST_INCLUDE); + if (imf == NULL) { + error = ENOMEM; + goto out_in6p_locked; + } } else { CTR2(KTR_MLD, "%s: %s source", __func__, "allow"); } @@ -2158,81 +2073,88 @@ in6p_join_group(struct inpcb *inp, struct sockopt *sopt) CTR1(KTR_MLD, "%s: merge imf state failed", __func__); error = ENOMEM; - goto out_im6o_free; + goto out_in6p_locked; } } else { /* No address specified; Membership starts in EX mode */ if (is_new) { CTR1(KTR_MLD, "%s: new join w/o source", __func__); - im6f_init(imf, MCAST_UNDEFINED, MCAST_EXCLUDE); + imf = ip6_mfilter_alloc(M_NOWAIT, MCAST_UNDEFINED, MCAST_EXCLUDE); + if (imf == NULL) { + error = ENOMEM; + goto out_in6p_locked; + } } } /* * Begin state merge transaction at MLD layer. */ - in_pcbref(inp); - INP_WUNLOCK(inp); - IN6_MULTI_LOCK(); - if (is_new) { + in_pcbref(inp); + INP_WUNLOCK(inp); + error = in6_joingroup_locked(ifp, &gsa->sin6.sin6_addr, imf, - &inm, 0); + &imf->im6f_in6m, 0); + + INP_WLOCK(inp); + if (in_pcbrele_wlocked(inp)) { + error = ENXIO; + goto out_in6p_unlocked; + } if (error) { - IN6_MULTI_UNLOCK(); - goto out_im6o_free; + goto out_in6p_locked; } /* * NOTE: Refcount from in6_joingroup_locked() * is protecting membership. */ - imo->im6o_membership[idx] = inm; } else { CTR1(KTR_MLD, "%s: merge inm state", __func__); IN6_MULTI_LIST_LOCK(); error = in6m_merge(inm, imf); - if (error) + if (error) { CTR1(KTR_MLD, "%s: failed to merge inm state", __func__); - else { - CTR1(KTR_MLD, "%s: doing mld downcall", __func__); - error = mld_change_state(inm, 0); - if (error) - CTR1(KTR_MLD, "%s: failed mld downcall", - __func__); + IN6_MULTI_LIST_UNLOCK(); + im6f_rollback(imf); + im6f_reap(imf); + goto out_in6p_locked; } + CTR1(KTR_MLD, "%s: doing mld downcall", __func__); + error = mld_change_state(inm, 0); IN6_MULTI_LIST_UNLOCK(); - } - IN6_MULTI_UNLOCK(); - INP_WLOCK(inp); - if (in_pcbrele_wlocked(inp)) - return (ENXIO); - if (error) { - im6f_rollback(imf); - if (is_new) - im6f_purge(imf); - else + if (error) { + CTR1(KTR_MLD, "%s: failed mld downcall", + __func__); + im6f_rollback(imf); im6f_reap(imf); - } else { - im6f_commit(imf); - } - -out_im6o_free: - if (error && is_new) { - inm = imo->im6o_membership[idx]; - if (inm != NULL) { - IN6_MULTI_LIST_LOCK(); - in6m_rele_locked(&inmh, inm); - IN6_MULTI_LIST_UNLOCK(); + goto out_in6p_locked; } - imo->im6o_membership[idx] = NULL; - --imo->im6o_num_memberships; } + if (is_new) + ip6_mfilter_insert(&imo->im6o_head, imf); + + im6f_commit(imf); + imf = NULL; + out_in6p_locked: INP_WUNLOCK(inp); - in6m_release_list_deferred(&inmh); +out_in6p_unlocked: + IN6_MULTI_UNLOCK(); + + if (is_new && imf) { + if (imf->im6f_in6m != NULL) { + struct in6_multi_head inmh; + + SLIST_INIT(&inmh); + SLIST_INSERT_HEAD(&inmh, imf->im6f_in6m, in6m_defer); + in6m_release_list_deferred(&inmh); + } + ip6_mfilter_free(imf); + } return (error); } @@ -2251,8 +2173,8 @@ in6p_leave_group(struct inpcb *inp, struct sockopt *sopt) struct in6_msource *ims; struct in6_multi *inm; uint32_t ifindex; - size_t idx; - int error, is_final; + int error; + bool is_final; #ifdef KTR char ip6tbuf[INET6_ADDRSTRLEN]; #endif @@ -2260,7 +2182,7 @@ in6p_leave_group(struct inpcb *inp, struct sockopt *sopt) ifp = NULL; ifindex = 0; error = 0; - is_final = 1; + is_final = true; memset(&gsr, 0, sizeof(struct group_source_req)); gsa = (sockunion_t *)&gsr.gsr_group; @@ -2378,20 +2300,21 @@ in6p_leave_group(struct inpcb *inp, struct sockopt *sopt) CTR2(KTR_MLD, "%s: ifp = %p", __func__, ifp); KASSERT(ifp != NULL, ("%s: ifp did not resolve", __func__)); + IN6_MULTI_LOCK(); + /* - * Find the membership in the membership array. + * Find the membership in the membership list. */ imo = in6p_findmoptions(inp); - idx = im6o_match_group(imo, ifp, &gsa->sa); - if (idx == -1) { + imf = im6o_match_group(imo, ifp, &gsa->sa); + if (imf == NULL) { error = EADDRNOTAVAIL; goto out_in6p_locked; } - inm = imo->im6o_membership[idx]; - imf = &imo->im6o_mfilters[idx]; + inm = imf->im6f_in6m; if (ssa->ss.ss_family != AF_UNSPEC) - is_final = 0; + is_final = false; /* * Begin state merge transaction at socket layer. @@ -2403,13 +2326,14 @@ in6p_leave_group(struct inpcb *inp, struct sockopt *sopt) * MCAST_LEAVE_SOURCE_GROUP is only valid for inclusive memberships. */ if (is_final) { + ip6_mfilter_remove(&imo->im6o_head, imf); im6f_leave(imf); } else { if (imf->im6f_st[0] == MCAST_EXCLUDE) { error = EADDRNOTAVAIL; goto out_in6p_locked; } - ims = im6o_match_source(imo, idx, &ssa->sa); + ims = im6o_match_source(imf, &ssa->sa); if (ims == NULL) { CTR3(KTR_MLD, "%s: source %p %spresent", __func__, ip6_sprintf(ip6tbuf, &ssa->sin6.sin6_addr), @@ -2429,60 +2353,47 @@ in6p_leave_group(struct inpcb *inp, struct sockopt *sopt) /* * Begin state merge transaction at MLD layer. */ - in_pcbref(inp); - INP_WUNLOCK(inp); - IN6_MULTI_LOCK(); - - if (is_final) { - /* - * Give up the multicast address record to which - * the membership points. - */ - (void)in6_leavegroup_locked(inm, imf); - } else { + if (!is_final) { CTR1(KTR_MLD, "%s: merge inm state", __func__); IN6_MULTI_LIST_LOCK(); error = in6m_merge(inm, imf); - if (error) + if (error) { CTR1(KTR_MLD, "%s: failed to merge inm state", __func__); - else { - CTR1(KTR_MLD, "%s: doing mld downcall", __func__); - error = mld_change_state(inm, 0); - if (error) - CTR1(KTR_MLD, "%s: failed mld downcall", - __func__); + IN6_MULTI_LIST_UNLOCK(); + im6f_rollback(imf); + im6f_reap(imf); + goto out_in6p_locked; } + + CTR1(KTR_MLD, "%s: doing mld downcall", __func__); + error = mld_change_state(inm, 0); IN6_MULTI_LIST_UNLOCK(); + if (error) { + CTR1(KTR_MLD, "%s: failed mld downcall", + __func__); + im6f_rollback(imf); + im6f_reap(imf); + goto out_in6p_locked; + } } - IN6_MULTI_UNLOCK(); - INP_WLOCK(inp); - if (in_pcbrele_wlocked(inp)) - return (ENXIO); - - if (error) - im6f_rollback(imf); - else - im6f_commit(imf); - + im6f_commit(imf); im6f_reap(imf); - if (is_final) { - /* Remove the gap in the membership array. */ - KASSERT(RB_EMPTY(&imf->im6f_sources), - ("%s: im6f_sources not empty", __func__)); - for (++idx; idx < imo->im6o_num_memberships; ++idx) { - imo->im6o_membership[idx - 1] = imo->im6o_membership[idx]; - imo->im6o_mfilters[idx - 1] = imo->im6o_mfilters[idx]; - } - im6f_init(&imo->im6o_mfilters[idx - 1], MCAST_UNDEFINED, - MCAST_EXCLUDE); - imo->im6o_num_memberships--; - } - out_in6p_locked: INP_WUNLOCK(inp); + + if (is_final && imf) { + /* + * Give up the multicast address record to which + * the membership points. + */ + (void)in6_leavegroup_locked(inm, imf); + ip6_mfilter_free(imf); + } + + IN6_MULTI_UNLOCK(); return (error); } @@ -2540,7 +2451,6 @@ in6p_set_source_filters(struct inpcb *inp, struct sockopt *sopt) struct in6_mfilter *imf; struct ip6_moptions *imo; struct in6_multi *inm; - size_t idx; int error; error = sooptcopyin(sopt, &msfr, sizeof(struct __msfilterreq), @@ -2577,13 +2487,12 @@ in6p_set_source_filters(struct inpcb *inp, struct sockopt *sopt) * Check if this socket is a member of this group. */ imo = in6p_findmoptions(inp); - idx = im6o_match_group(imo, ifp, &gsa->sa); - if (idx == -1 || imo->im6o_mfilters == NULL) { + imf = im6o_match_group(imo, ifp, &gsa->sa); + if (imf == NULL) { error = EADDRNOTAVAIL; goto out_in6p_locked; } - inm = imo->im6o_membership[idx]; - imf = &imo->im6o_mfilters[idx]; + inm = imf->im6f_in6m; /* * Begin state merge transaction at socket layer. diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c index c27464b1e3e7..abad883dc623 100644 --- a/sys/netinet6/in6_pcb.c +++ b/sys/netinet6/in6_pcb.c @@ -802,8 +802,9 @@ void in6_pcbpurgeif0(struct inpcbinfo *pcbinfo, struct ifnet *ifp) { struct inpcb *in6p; + struct in6_multi *inm; + struct in6_mfilter *imf; struct ip6_moptions *im6o; - int i, gap; INP_INFO_WLOCK(pcbinfo); CK_LIST_FOREACH(in6p, pcbinfo->ipi_listhead, inp_list) { @@ -824,18 +825,18 @@ in6_pcbpurgeif0(struct inpcbinfo *pcbinfo, struct ifnet *ifp) * Drop multicast group membership if we joined * through the interface being detached. */ - gap = 0; - for (i = 0; i < im6o->im6o_num_memberships; i++) { - if (im6o->im6o_membership[i]->in6m_ifp == - ifp) { - in6_leavegroup(im6o->im6o_membership[i], NULL); - gap++; - } else if (gap != 0) { - im6o->im6o_membership[i - gap] = - im6o->im6o_membership[i]; - } +restart: + IP6_MFILTER_FOREACH(imf, &im6o->im6o_head) { + if ((inm = imf->im6f_in6m) == NULL) + continue; + if (inm->in6m_ifp != ifp) + continue; + ip6_mfilter_remove(&im6o->im6o_head, imf); + IN6_MULTI_LOCK_ASSERT(); + in6_leavegroup_locked(inm, NULL); + ip6_mfilter_free(imf); + goto restart; } - im6o->im6o_num_memberships -= gap; } INP_WUNLOCK(in6p); } diff --git a/sys/netinet6/in6_var.h b/sys/netinet6/in6_var.h index 3e965c2d4b32..3e535310b29e 100644 --- a/sys/netinet6/in6_var.h +++ b/sys/netinet6/in6_var.h @@ -602,9 +602,61 @@ struct in6_mfilter { struct ip6_msource_tree im6f_sources; /* source list for (S,G) */ u_long im6f_nsrc; /* # of source entries */ uint8_t im6f_st[2]; /* state before/at commit */ + struct in6_multi *im6f_in6m; /* associated multicast address */ + STAILQ_ENTRY(in6_mfilter) im6f_entry; /* list entry */ }; /* + * Helper types and functions for IPv4 multicast filters. + */ +STAILQ_HEAD(ip6_mfilter_head, in6_mfilter); + +struct in6_mfilter *ip6_mfilter_alloc(int mflags, int st0, int st1); +void ip6_mfilter_free(struct in6_mfilter *); + +static inline void +ip6_mfilter_init(struct ip6_mfilter_head *head) +{ + + STAILQ_INIT(head); +} + +static inline struct in6_mfilter * +ip6_mfilter_first(const struct ip6_mfilter_head *head) +{ + + return (STAILQ_FIRST(head)); +} + +static inline void +ip6_mfilter_insert(struct ip6_mfilter_head *head, struct in6_mfilter *imf) +{ + + STAILQ_INSERT_TAIL(head, imf, im6f_entry); +} + +static inline void +ip6_mfilter_remove(struct ip6_mfilter_head *head, struct in6_mfilter *imf) +{ + + STAILQ_REMOVE(head, imf, in6_mfilter, im6f_entry); +} + +#define IP6_MFILTER_FOREACH(imf, head) \ + STAILQ_FOREACH(imf, head, im6f_entry) + +static inline size_t +ip6_mfilter_count(struct ip6_mfilter_head *head) +{ + struct in6_mfilter *imf; + size_t num = 0; + + STAILQ_FOREACH(imf, head, im6f_entry) + num++; + return (num); +} + +/* * Legacy KAME IPv6 multicast membership descriptor. */ struct in6_multi_mship { diff --git a/sys/netinet6/ip6_var.h b/sys/netinet6/ip6_var.h index 40f502abcd08..45ee4425fb74 100644 --- a/sys/netinet6/ip6_var.h +++ b/sys/netinet6/ip6_var.h @@ -110,6 +110,7 @@ struct ip6_direct_ctx { uint32_t ip6dc_off; /* offset to next header */ }; +#if defined(_NETINET6_IN6_VAR_H_) && defined(_KERNEL) /* * Structure attached to inpcb.in6p_moptions and * passed to ip6_output when IPv6 multicast options are in use. @@ -119,13 +120,11 @@ struct ip6_moptions { struct ifnet *im6o_multicast_ifp; /* ifp for outgoing multicasts */ u_char im6o_multicast_hlim; /* hoplimit for outgoing multicasts */ u_char im6o_multicast_loop; /* 1 >= hear sends if a member */ - u_short im6o_num_memberships; /* no. memberships this socket */ - u_short im6o_max_memberships; /* max memberships this socket */ - struct in6_multi **im6o_membership; /* group memberships */ - struct in6_mfilter *im6o_mfilters; /* source filters */ - struct epoch_context imo6_epoch_ctx; + struct ip6_mfilter_head im6o_head; /* group membership list */ }; - +#else +struct ip6_moptions; +#endif /* * Control options for outgoing packets */ diff --git a/sys/netipsec/key.c b/sys/netipsec/key.c index d54427410b92..82a84a412538 100644 --- a/sys/netipsec/key.c +++ b/sys/netipsec/key.c @@ -7164,7 +7164,7 @@ key_register(struct socket *so, struct mbuf *m, const struct sadb_msghdr *mhp) return key_senderror(so, m, ENOBUFS); MGETHDR(n, M_NOWAIT, MT_DATA); - if (len > MHLEN) { + if (n != NULL && len > MHLEN) { if (!(MCLGET(n, M_NOWAIT))) { m_freem(n); n = NULL; diff --git a/sys/netpfil/ipfw/ip_fw2.c b/sys/netpfil/ipfw/ip_fw2.c index a4a3830132eb..535be037b6cc 100644 --- a/sys/netpfil/ipfw/ip_fw2.c +++ b/sys/netpfil/ipfw/ip_fw2.c @@ -331,10 +331,10 @@ ipopts_match(struct ip *ip, ipfw_insn *cmd) } static int -tcpopts_match(struct tcphdr *tcp, ipfw_insn *cmd) +tcpopts_parse(struct tcphdr *tcp, uint16_t *mss) { - int optlen, bits = 0; u_char *cp = (u_char *)(tcp + 1); + int optlen, bits = 0; int x = (tcp->th_off << 2) - sizeof(struct tcphdr); for (; x > 0; x -= optlen, cp += optlen) { @@ -350,12 +350,13 @@ tcpopts_match(struct tcphdr *tcp, ipfw_insn *cmd) } switch (opt) { - default: break; case TCPOPT_MAXSEG: bits |= IP_FW_TCPOPT_MSS; + if (mss != NULL) + *mss = be16dec(cp + 2); break; case TCPOPT_WINDOW: @@ -370,10 +371,16 @@ tcpopts_match(struct tcphdr *tcp, ipfw_insn *cmd) case TCPOPT_TIMESTAMP: bits |= IP_FW_TCPOPT_TS; break; - } } - return (flags_match(cmd, bits)); + return (bits); +} + +static int +tcpopts_match(struct tcphdr *tcp, ipfw_insn *cmd) +{ + + return (flags_match(cmd, tcpopts_parse(tcp, NULL))); } static int @@ -1712,6 +1719,11 @@ do { \ default: break; } + } else { + if (offset == 1 && proto == IPPROTO_TCP) { + /* RFC 3128 */ + goto pullup_failed; + } } UPDATE_POINTERS(); @@ -2316,6 +2328,31 @@ do { \ TCP(ulp)->th_ack); break; + case O_TCPMSS: + if (proto == IPPROTO_TCP && + (args->f_id._flags & TH_SYN) != 0 && + ulp != NULL) { + uint16_t mss, *p; + int i; + + PULLUP_LEN(hlen, ulp, + (TCP(ulp)->th_off << 2)); + if ((tcpopts_parse(TCP(ulp), &mss) & + IP_FW_TCPOPT_MSS) == 0) + break; + if (cmdlen == 1) { + match = (cmd->arg1 == mss); + break; + } + /* Otherwise we have ranges. */ + p = ((ipfw_insn_u16 *)cmd)->ports; + i = cmdlen - 1; + for (; !match && i > 0; i--, p += 2) + match = (mss >= p[0] && + mss <= p[1]); + } + break; + case O_TCPWIN: if (proto == IPPROTO_TCP && offset == 0) { uint16_t x; @@ -3332,6 +3369,7 @@ vnet_ipfw_init(const void *unused) /* fill and insert the default rule */ rule = ipfw_alloc_rule(chain, sizeof(struct ip_fw)); + rule->flags |= IPFW_RULE_NOOPT; rule->cmd_len = 1; rule->cmd[0].len = 1; rule->cmd[0].opcode = default_to_accept ? O_ACCEPT : O_DENY; diff --git a/sys/netpfil/ipfw/ip_fw_sockopt.c b/sys/netpfil/ipfw/ip_fw_sockopt.c index a83e75447633..297b01ca7d3d 100644 --- a/sys/netpfil/ipfw/ip_fw_sockopt.c +++ b/sys/netpfil/ipfw/ip_fw_sockopt.c @@ -1176,7 +1176,9 @@ move_objects(struct ip_fw_chain *ch, ipfw_range_tlv *rt) } } return (c); -}/* +} + +/* * Changes set of given rule rannge @rt * with each other. * @@ -1907,6 +1909,7 @@ check_ipfw_rule_body(ipfw_insn *cmd, int cmd_len, struct rule_check_info *ci) case O_IPTTL: case O_IPLEN: case O_TCPDATALEN: + case O_TCPMSS: case O_TCPWIN: case O_TAGGED: if (cmdlen < 1 || cmdlen > 31) diff --git a/sys/netpfil/pf/if_pfsync.c b/sys/netpfil/pf/if_pfsync.c index 45b1e090f95c..0566593b7616 100644 --- a/sys/netpfil/pf/if_pfsync.c +++ b/sys/netpfil/pf/if_pfsync.c @@ -264,7 +264,7 @@ static void pfsync_push(struct pfsync_bucket *); static void pfsync_push_all(struct pfsync_softc *); static void pfsyncintr(void *); static int pfsync_multicast_setup(struct pfsync_softc *, struct ifnet *, - void *); + struct in_mfilter *imf); static void pfsync_multicast_cleanup(struct pfsync_softc *); static void pfsync_pointers_init(void); static void pfsync_pointers_uninit(void); @@ -430,8 +430,7 @@ pfsync_clone_destroy(struct ifnet *ifp) pfsync_drop(sc); if_free(ifp); - if (sc->sc_imo.imo_membership) - pfsync_multicast_cleanup(sc); + pfsync_multicast_cleanup(sc); mtx_destroy(&sc->sc_mtx); mtx_destroy(&sc->sc_bulk_mtx); @@ -1373,10 +1372,9 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data) case SIOCSETPFSYNC: { - struct ip_moptions *imo = &sc->sc_imo; + struct in_mfilter *imf = NULL; struct ifnet *sifp; struct ip *ip; - void *mship = NULL; if ((error = priv_check(curthread, PRIV_NETINET_PF)) != 0) return (error); @@ -1396,8 +1394,7 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data) pfsyncr.pfsyncr_syncpeer.s_addr == 0 || pfsyncr.pfsyncr_syncpeer.s_addr == htonl(INADDR_PFSYNC_GROUP))) - mship = malloc((sizeof(struct in_multi *) * - IP_MIN_MEMBERSHIPS), M_PFSYNC, M_WAITOK | M_ZERO); + imf = ip_mfilter_alloc(M_WAITOK, 0, 0); PFSYNC_LOCK(sc); if (pfsyncr.pfsyncr_syncpeer.s_addr == 0) @@ -1419,8 +1416,7 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data) if (sc->sc_sync_if) if_rele(sc->sc_sync_if); sc->sc_sync_if = NULL; - if (imo->imo_membership) - pfsync_multicast_cleanup(sc); + pfsync_multicast_cleanup(sc); PFSYNC_UNLOCK(sc); break; } @@ -1436,14 +1432,13 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data) PFSYNC_BUCKET_UNLOCK(&sc->sc_buckets[c]); } - if (imo->imo_membership) - pfsync_multicast_cleanup(sc); + pfsync_multicast_cleanup(sc); if (sc->sc_sync_peer.s_addr == htonl(INADDR_PFSYNC_GROUP)) { - error = pfsync_multicast_setup(sc, sifp, mship); + error = pfsync_multicast_setup(sc, sifp, imf); if (error) { if_rele(sifp); - free(mship, M_PFSYNC); + ip_mfilter_free(imf); PFSYNC_UNLOCK(sc); return (error); } @@ -2353,7 +2348,8 @@ pfsyncintr(void *arg) } static int -pfsync_multicast_setup(struct pfsync_softc *sc, struct ifnet *ifp, void *mship) +pfsync_multicast_setup(struct pfsync_softc *sc, struct ifnet *ifp, + struct in_mfilter *imf) { struct ip_moptions *imo = &sc->sc_imo; int error; @@ -2361,16 +2357,14 @@ pfsync_multicast_setup(struct pfsync_softc *sc, struct ifnet *ifp, void *mship) if (!(ifp->if_flags & IFF_MULTICAST)) return (EADDRNOTAVAIL); - imo->imo_membership = (struct in_multi **)mship; - imo->imo_max_memberships = IP_MIN_MEMBERSHIPS; imo->imo_multicast_vif = -1; if ((error = in_joingroup(ifp, &sc->sc_sync_peer, NULL, - &imo->imo_membership[0])) != 0) { - imo->imo_membership = NULL; + &imf->imf_inm)) != 0) return (error); - } - imo->imo_num_memberships++; + + ip_mfilter_init(&imo->imo_head); + ip_mfilter_insert(&imo->imo_head, imf); imo->imo_multicast_ifp = ifp; imo->imo_multicast_ttl = PFSYNC_DFLTTL; imo->imo_multicast_loop = 0; @@ -2382,10 +2376,13 @@ static void pfsync_multicast_cleanup(struct pfsync_softc *sc) { struct ip_moptions *imo = &sc->sc_imo; + struct in_mfilter *imf; - in_leavegroup(imo->imo_membership[0], NULL); - free(imo->imo_membership, M_PFSYNC); - imo->imo_membership = NULL; + while ((imf = ip_mfilter_first(&imo->imo_head)) != NULL) { + ip_mfilter_remove(&imo->imo_head, imf); + in_leavegroup(imf->imf_inm, NULL); + ip_mfilter_free(imf); + } imo->imo_multicast_ifp = NULL; } @@ -2404,7 +2401,7 @@ pfsync_detach_ifnet(struct ifnet *ifp) * is going away. We do need to ensure we don't try to do * cleanup later. */ - sc->sc_imo.imo_membership = NULL; + ip_mfilter_init(&sc->sc_imo.imo_head); sc->sc_imo.imo_multicast_ifp = NULL; sc->sc_sync_if = NULL; } diff --git a/sys/powerpc/conf/GENERIC b/sys/powerpc/conf/GENERIC index dc19d7a85598..78d83c9ba12d 100644 --- a/sys/powerpc/conf/GENERIC +++ b/sys/powerpc/conf/GENERIC @@ -162,7 +162,6 @@ device fxp # Intel EtherExpress PRO/100B (82557, 82558) # Pseudo devices. device crypto # core crypto support device loop # Network loopback -device random # Entropy device device ether # Ethernet support device vlan # 802.1Q VLAN support device tuntap # Packet tunnel. diff --git a/sys/powerpc/conf/GENERIC64 b/sys/powerpc/conf/GENERIC64 index dc3d54e371c9..409062047b24 100644 --- a/sys/powerpc/conf/GENERIC64 +++ b/sys/powerpc/conf/GENERIC64 @@ -183,7 +183,6 @@ device rl # RealTek 8129/8139 # Pseudo devices. device crypto # core crypto support device loop # Network loopback -device random # Entropy device device ether # Ethernet support device vlan # 802.1Q VLAN support device tuntap # Packet tunnel. diff --git a/sys/powerpc/conf/MPC85XX b/sys/powerpc/conf/MPC85XX index 3eeba5f54ec4..7962bdc22db0 100644 --- a/sys/powerpc/conf/MPC85XX +++ b/sys/powerpc/conf/MPC85XX @@ -93,7 +93,6 @@ device mmcsd device pass device pci device quicc -device random #device rl device scbus device scc diff --git a/sys/powerpc/conf/MPC85XXSPE b/sys/powerpc/conf/MPC85XXSPE index 1d649c1b36b9..2cea302361a3 100644 --- a/sys/powerpc/conf/MPC85XXSPE +++ b/sys/powerpc/conf/MPC85XXSPE @@ -94,7 +94,6 @@ device mmcsd device pass device pci device quicc -device random #device rl device scbus device scc diff --git a/sys/powerpc/conf/QORIQ64 b/sys/powerpc/conf/QORIQ64 index eecc0eb8e06b..1661829a6d25 100644 --- a/sys/powerpc/conf/QORIQ64 +++ b/sys/powerpc/conf/QORIQ64 @@ -99,7 +99,6 @@ device mmc device mmcsd device pass device pci -device random #device rl device scbus device scc diff --git a/sys/powerpc/conf/dpaa/DPAA b/sys/powerpc/conf/dpaa/DPAA index 2cbc908ec120..4aa24c188acc 100644 --- a/sys/powerpc/conf/dpaa/DPAA +++ b/sys/powerpc/conf/dpaa/DPAA @@ -96,7 +96,6 @@ device pci # Pseudo devices device ether # Ethernet support device loop # Network loopback -device random # Entropy device device bpf # Berkeley packet filter device md # Memory "disks" diff --git a/sys/powerpc/include/trap.h b/sys/powerpc/include/trap.h index 5017a7535d29..56b789c248ef 100644 --- a/sys/powerpc/include/trap.h +++ b/sys/powerpc/include/trap.h @@ -130,7 +130,7 @@ /* Macros to extract register information */ #define EXC_ALI_RST(dsisr) ((dsisr >> 5) & 0x1f) /* source or target */ #define EXC_ALI_RA(dsisr) (dsisr & 0x1f) -#define EXC_ALI_SPE_REG(instr) ((instr >> 21) & 0x1f) +#define EXC_ALI_INST_RST(instr) ((instr >> 21) & 0x1f) /* * SRR1 bits for program exception traps. These identify what caused diff --git a/sys/powerpc/powerpc/machdep.c b/sys/powerpc/powerpc/machdep.c index 6fb874e31d9c..0bd6a11197ab 100644 --- a/sys/powerpc/powerpc/machdep.c +++ b/sys/powerpc/powerpc/machdep.c @@ -595,3 +595,16 @@ bzero(void *buf, size_t len) len--; } } + +/* __stack_chk_fail_local() is called in secure-plt (32-bit). */ +#if !defined(__powerpc64__) +extern void __stack_chk_fail(void); +void __stack_chk_fail_local(void); + +void +__stack_chk_fail_local(void) +{ + + __stack_chk_fail(); +} +#endif diff --git a/sys/powerpc/powerpc/trap.c b/sys/powerpc/powerpc/trap.c index 0200c7bbd142..3cc04fbc75ad 100644 --- a/sys/powerpc/powerpc/trap.c +++ b/sys/powerpc/powerpc/trap.c @@ -788,7 +788,7 @@ static int fix_unaligned(struct thread *td, struct trapframe *frame) { struct thread *fputhread; -#ifdef __SPE__ +#ifdef BOOKE uint32_t inst; #endif int indicator, reg; @@ -799,7 +799,7 @@ fix_unaligned(struct thread *td, struct trapframe *frame) if (indicator & ESR_SPE) { if (copyin((void *)frame->srr0, &inst, sizeof(inst)) != 0) return (-1); - reg = EXC_ALI_SPE_REG(inst); + reg = EXC_ALI_INST_RST(inst); fpr = (double *)td->td_pcb->pcb_vec.vr[reg]; fputhread = PCPU_GET(vecthread); @@ -829,12 +829,22 @@ fix_unaligned(struct thread *td, struct trapframe *frame) return (0); } #else +#ifdef BOOKE + indicator = (frame->cpu.booke.esr & ESR_ST) ? EXC_ALI_STFD : EXC_ALI_LFD; +#else indicator = EXC_ALI_OPCODE_INDICATOR(frame->cpu.aim.dsisr); +#endif switch (indicator) { case EXC_ALI_LFD: case EXC_ALI_STFD: +#ifdef BOOKE + if (copyin((void *)frame->srr0, &inst, sizeof(inst)) != 0) + return (-1); + reg = EXC_ALI_INST_RST(inst); +#else reg = EXC_ALI_RST(frame->cpu.aim.dsisr); +#endif fpr = &td->td_pcb->pcb_fpu.fpr[reg].fpr; fputhread = PCPU_GET(fputhread); diff --git a/sys/riscv/conf/GENERIC b/sys/riscv/conf/GENERIC index 559e9166daa9..5b647977879f 100644 --- a/sys/riscv/conf/GENERIC +++ b/sys/riscv/conf/GENERIC @@ -137,7 +137,6 @@ options ZSTDIO # zstd-compressed kernel and user dumps # Pseudo devices. device crypto # core crypto support device loop # Network loopback -device random # Entropy device device ether # Ethernet support device vlan # 802.1Q VLAN support device tuntap # Packet tunnel. diff --git a/sys/sparc64/conf/GENERIC b/sys/sparc64/conf/GENERIC index 285adadf332c..75fe3f842577 100644 --- a/sys/sparc64/conf/GENERIC +++ b/sys/sparc64/conf/GENERIC @@ -224,7 +224,6 @@ device ath_rate_sample # SampleRate tx rate control for ath # Pseudo devices. device crypto # core crypto support device loop # Network loopback -device random # Entropy device device ether # Ethernet support device vlan # 802.1Q VLAN support device tuntap # Packet tunnel. diff --git a/sys/sys/_types.h b/sys/sys/_types.h index 22a37c53389a..020ba025ea98 100644 --- a/sys/sys/_types.h +++ b/sys/sys/_types.h @@ -68,6 +68,7 @@ typedef unsigned int __useconds_t; /* microseconds (unsigned) */ typedef int __cpuwhich_t; /* which parameter for cpuset. */ typedef int __cpulevel_t; /* level parameter for cpuset. */ typedef int __cpusetid_t; /* cpuset identifier. */ +typedef __int64_t __daddr_t; /* bwrite(3), FIOBMAP2, etc */ /* * Unusual type definitions. diff --git a/sys/sys/boot.h b/sys/sys/boot.h index 68b9e1e0daf3..7874d9663736 100644 --- a/sys/sys/boot.h +++ b/sys/sys/boot.h @@ -32,6 +32,8 @@ #ifndef _SYS_BOOT_H_ #define _SYS_BOOT_H_ +#define PATH_KERNEL "/boot/kernel/kernel" + int boot_env_to_howto(void); void boot_howto_to_env(int howto); int boot_parse_arg(char *v); diff --git a/sys/sys/file.h b/sys/sys/file.h index 82af5e6b1bbe..942380c1647f 100644 --- a/sys/sys/file.h +++ b/sys/sys/file.h @@ -179,7 +179,10 @@ struct file { /* * DTYPE_VNODE specific fields. */ - int f_seqcount; /* (a) Count of sequential accesses. */ + union { + int16_t f_seqcount; /* (a) Count of sequential accesses. */ + int f_pipegen; + }; off_t f_nextoff; /* next expected read/write offset. */ union { struct cdev_privdata *fvn_cdevpriv; diff --git a/sys/sys/filio.h b/sys/sys/filio.h index e85db9cff4d1..c5cf3d4432e9 100644 --- a/sys/sys/filio.h +++ b/sys/sys/filio.h @@ -40,7 +40,7 @@ #ifndef _SYS_FILIO_H_ #define _SYS_FILIO_H_ -#include <sys/types.h> +#include <sys/_types.h> #include <sys/ioccom.h> /* Generic file-descriptor ioctl's. */ @@ -64,12 +64,12 @@ struct fiodgname_arg { #define FIOSEEKDATA _IOWR('f', 97, off_t) /* SEEK_DATA */ #define FIOSEEKHOLE _IOWR('f', 98, off_t) /* SEEK_HOLE */ struct fiobmap2_arg { - int64_t bn; - int runp; - int runb; + __daddr_t bn; + int runp; + int runb; }; -/* Get the file's bmap info for the logical block bn */ -#define FIOBMAP2 _IOWR('f', 99, struct fiobmap2_arg) +/* Get the file's bmap info for the logical block bn. */ +#define FIOBMAP2 _IOWR('f', 99, struct fiobmap2_arg) #ifdef _KERNEL #ifdef COMPAT_FREEBSD32 diff --git a/sys/sys/mman.h b/sys/sys/mman.h index b2fad0e47579..1b1b4bcc2cb9 100644 --- a/sys/sys/mman.h +++ b/sys/sys/mman.h @@ -55,6 +55,14 @@ #define PROT_READ 0x01 /* pages can be read */ #define PROT_WRITE 0x02 /* pages can be written */ #define PROT_EXEC 0x04 /* pages can be executed */ +#if __BSD_VISIBLE +#define _PROT_ALL (PROT_READ | PROT_WRITE | PROT_EXEC) +#define PROT_EXTRACT(prot) ((prot) & _PROT_ALL) + +#define _PROT_MAX_SHIFT 16 +#define PROT_MAX(prot) ((prot) << _PROT_MAX_SHIFT) +#define PROT_MAX_EXTRACT(prot) (((prot) >> _PROT_MAX_SHIFT) & _PROT_ALL) +#endif /* * Flags contain sharing type and options. diff --git a/sys/sys/param.h b/sys/sys/param.h index 2534537558c5..9a68762388f2 100644 --- a/sys/sys/param.h +++ b/sys/sys/param.h @@ -60,7 +60,7 @@ * in the range 5 to 9. */ #undef __FreeBSD_version -#define __FreeBSD_version 1300032 /* Master, propagated to newvers */ +#define __FreeBSD_version 1300034 /* Master, propagated to newvers */ /* * __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD, diff --git a/sys/sys/pcpu.h b/sys/sys/pcpu.h index 38785cd26c94..3672d6070deb 100644 --- a/sys/sys/pcpu.h +++ b/sys/sys/pcpu.h @@ -85,7 +85,8 @@ extern uintptr_t dpcpu_off[]; /* struct _hack is to stop this from being used with the static keyword. */ #define DPCPU_DEFINE(t, n) \ struct _hack; t DPCPU_NAME(n) __section(DPCPU_SETNAME) __used -#if defined(KLD_MODULE) && (defined(__aarch64__) || defined(__riscv)) +#if defined(KLD_MODULE) && (defined(__aarch64__) || defined(__riscv) \ + || defined(__powerpc64__)) /* * On some architectures the compiler will use PC-relative load to * find the address of DPCPU data with the static keyword. We then diff --git a/sys/sys/pmckern.h b/sys/sys/pmckern.h index e892d658a1ca..5b337f8d76df 100644 --- a/sys/sys/pmckern.h +++ b/sys/sys/pmckern.h @@ -226,7 +226,7 @@ do { \ */ #define PMC_CALL_HOOK_UNLOCKED(t, cmd, arg) \ do { \ - if (pmc_hook != NULL) \ + if (pmc_hook != NULL) \ (pmc_hook)((t), (cmd), (arg)); \ } while (0) diff --git a/sys/sys/random.h b/sys/sys/random.h index aa8c5f02c32e..8bcbe470cfc1 100644 --- a/sys/sys/random.h +++ b/sys/sys/random.h @@ -37,26 +37,9 @@ struct uio; -#if defined(DEV_RANDOM) void read_random(void *, u_int); int read_random_uio(struct uio *, bool); bool is_random_seeded(void); -#else -static __inline int -read_random_uio(void *a __unused, u_int b __unused) -{ - return (0); -} -static __inline void -read_random(void *a __unused, u_int b __unused) -{ -} -static __inline bool -is_random_seeded(void) -{ - return (false); -} -#endif /* * Note: if you add or remove members of random_entropy_source, remember to @@ -101,7 +84,6 @@ _Static_assert(ENTROPYSOURCE <= 32, #define RANDOM_LEGACY_BOOT_ENTROPY_MODULE "/boot/entropy" #define RANDOM_CACHED_BOOT_ENTROPY_MODULE "boot_entropy_cache" -#if defined(DEV_RANDOM) extern u_int hc_source_mask; void random_harvest_queue_(const void *, u_int, enum random_entropy_source); void random_harvest_fast_(const void *, u_int); @@ -133,13 +115,6 @@ random_harvest_direct(const void *entropy, u_int size, enum random_entropy_sourc void random_harvest_register_source(enum random_entropy_source); void random_harvest_deregister_source(enum random_entropy_source); -#else -#define random_harvest_queue(a, b, c) do {} while (0) -#define random_harvest_fast(a, b, c) do {} while (0) -#define random_harvest_direct(a, b, c) do {} while (0) -#define random_harvest_register_source(a) do {} while (0) -#define random_harvest_deregister_source(a) do {} while (0) -#endif #if defined(RANDOM_ENABLE_UMA) #define random_harvest_fast_uma(a, b, c) random_harvest_fast(a, b, c) diff --git a/sys/sys/rangelock.h b/sys/sys/rangelock.h index 732bd9406d48..9a8a107aed8f 100644 --- a/sys/sys/rangelock.h +++ b/sys/sys/rangelock.h @@ -75,8 +75,12 @@ void *rangelock_unlock_range(struct rangelock *lock, void *cookie, off_t start, off_t end, struct mtx *ilk); void *rangelock_rlock(struct rangelock *lock, off_t start, off_t end, struct mtx *ilk); +void *rangelock_tryrlock(struct rangelock *lock, off_t start, off_t end, + struct mtx *ilk); void *rangelock_wlock(struct rangelock *lock, off_t start, off_t end, struct mtx *ilk); +void *rangelock_trywlock(struct rangelock *lock, off_t start, off_t end, + struct mtx *ilk); void rlqentry_free(struct rl_q_entry *rlqe); #endif /* _KERNEL */ diff --git a/sys/sys/types.h b/sys/sys/types.h index 39d8d63262e8..c3ece22e58b8 100644 --- a/sys/sys/types.h +++ b/sys/sys/types.h @@ -101,7 +101,7 @@ typedef __clockid_t clockid_t; #endif typedef __critical_t critical_t; /* Critical section value */ -typedef __int64_t daddr_t; /* disk address */ +typedef __daddr_t daddr_t; /* disk address */ #ifndef _DEV_T_DECLARED typedef __dev_t dev_t; /* device number or struct cdev */ diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h index 50eae14026af..9c0dc25f3f83 100644 --- a/sys/sys/vnode.h +++ b/sys/sys/vnode.h @@ -722,8 +722,12 @@ int vn_io_fault_pgmove(vm_page_t ma[], vm_offset_t offset, int xfersize, VI_MTX(vp)) #define vn_rangelock_rlock(vp, start, end) \ rangelock_rlock(&(vp)->v_rl, (start), (end), VI_MTX(vp)) +#define vn_rangelock_tryrlock(vp, start, end) \ + rangelock_tryrlock(&(vp)->v_rl, (start), (end), VI_MTX(vp)) #define vn_rangelock_wlock(vp, start, end) \ rangelock_wlock(&(vp)->v_rl, (start), (end), VI_MTX(vp)) +#define vn_rangelock_trywlock(vp, start, end) \ + rangelock_trywlock(&(vp)->v_rl, (start), (end), VI_MTX(vp)) int vfs_cache_lookup(struct vop_lookup_args *ap); void vfs_timestamp(struct timespec *); diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c index 3a4a20b8565c..8d43e5528e18 100644 --- a/sys/ufs/ffs/ffs_softdep.c +++ b/sys/ufs/ffs/ffs_softdep.c @@ -2110,7 +2110,6 @@ pagedep_find(pagedephd, ino, lbn, pagedeppp) * Look up a pagedep. Return 1 if found, 0 otherwise. * If not found, allocate if DEPALLOC flag is passed. * Found or allocated entry is returned in pagedeppp. - * This routine must be called with splbio interrupts blocked. */ static int pagedep_lookup(mp, bp, ino, lbn, flags, pagedeppp) @@ -2202,7 +2201,6 @@ inodedep_find(inodedephd, inum, inodedeppp) * Look up an inodedep. Return 1 if found, 0 if not found. * If not found, allocate if DEPALLOC flag is passed. * Found or allocated entry is returned in inodedeppp. - * This routine must be called with splbio interrupts blocked. */ static int inodedep_lookup(mp, inum, flags, inodedeppp) @@ -5478,7 +5476,6 @@ jnewblk_merge(new, old, wkhd) /* * Replace an old allocdirect dependency with a newer one. - * This routine must be called with splbio interrupts blocked. */ static void allocdirect_merge(adphead, newadp, oldadp) @@ -7534,7 +7531,6 @@ free_newblk(newblk) /* * Free a newdirblk. Clear the NEWBLOCK flag on its associated pagedep. - * This routine must be called with splbio interrupts blocked. */ static void free_newdirblk(newdirblk) @@ -7665,7 +7661,6 @@ softdep_freefile(pvp, ino, mode) /* * Check to see if an inode has never been written to disk. If * so free the inodedep and return success, otherwise return failure. - * This routine must be called with splbio interrupts blocked. * * If we still have a bitmap dependency, then the inode has never * been written to disk. Drop the dependency as it is no longer @@ -8897,8 +8892,7 @@ cancel_diradd(dap, dirrem, jremref, dotremref, dotdotremref) } /* - * Free a diradd dependency structure. This routine must be called - * with splbio interrupts blocked. + * Free a diradd dependency structure. */ static void free_diradd(dap, wkhd) @@ -11195,9 +11189,7 @@ softdep_disk_write_complete(bp) } /* - * Called from within softdep_disk_write_complete above. Note that - * this routine is always called from interrupt level with further - * splbio interrupts blocked. + * Called from within softdep_disk_write_complete above. */ static void handle_allocdirect_partdone(adp, wkhd) @@ -11209,6 +11201,7 @@ handle_allocdirect_partdone(adp, wkhd) struct inodedep *inodedep; long bsize; + LOCK_OWNED(VFSTOUFS(adp->ad_block.nb_list.wk_mp)); if ((adp->ad_state & ALLCOMPLETE) != ALLCOMPLETE) return; /* @@ -11818,7 +11811,6 @@ handle_written_indirdep(indirdep, bp, bpp, flags) /* * Process a diradd entry after its dependent inode has been written. - * This routine must be called with splbio interrupts blocked. */ static void diradd_inode_written(dap, inodedep) @@ -11826,6 +11818,7 @@ diradd_inode_written(dap, inodedep) struct inodedep *inodedep; { + LOCK_OWNED(VFSTOUFS(dap->da_list.wk_mp)); dap->da_state |= COMPLETE; complete_diradd(dap); WORKLIST_INSERT(&inodedep->id_pendinghd, &dap->da_list); @@ -12386,8 +12379,7 @@ retry: /* * Merge the a new inode dependency list (such as id_newinoupdt) into an - * old inode dependency list (such as id_inoupdt). This routine must be - * called with splbio interrupts blocked. + * old inode dependency list (such as id_inoupdt). */ static void merge_inode_lists(newlisthead, oldlisthead) @@ -12397,6 +12389,8 @@ merge_inode_lists(newlisthead, oldlisthead) struct allocdirect *listadp, *newadp; newadp = TAILQ_FIRST(newlisthead); + if (newadp != NULL) + LOCK_OWNED(VFSTOUFS(newadp->ad_block.nb_list.wk_mp)); for (listadp = TAILQ_FIRST(oldlisthead); listadp && newadp;) { if (listadp->ad_offset < newadp->ad_offset) { listadp = TAILQ_NEXT(listadp, ad_next); @@ -12891,7 +12885,6 @@ out: /* * Flush the dependencies associated with an inodedep. - * Called with splbio blocked. */ static int flush_inodedep_deps(vp, mp, ino) @@ -12956,7 +12949,6 @@ restart: /* * Flush an inode dependency list. - * Called with splbio blocked. */ static int flush_deplist(listhead, waitfor, errorp) @@ -13098,7 +13090,6 @@ flush_newblk_dep(vp, mp, lbn) /* * Eliminate a pagedep dependency by flushing out all its diradd dependencies. - * Called with splbio blocked. */ static int flush_pagedep_deps(pvp, mp, diraddhdp) diff --git a/sys/vm/device_pager.c b/sys/vm/device_pager.c index c27d60869def..7dce4778f951 100644 --- a/sys/vm/device_pager.c +++ b/sys/vm/device_pager.c @@ -236,7 +236,7 @@ cdev_pager_free_page(vm_object_t object, vm_page_t m) KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("unmanaged %p", m)); pmap_remove_all(m); vm_page_lock(m); - vm_page_remove(m); + (void)vm_page_remove(m); vm_page_unlock(m); } else if (object->type == OBJT_DEVICE) dev_pager_free_page(object, m); diff --git a/sys/vm/vm_fault.c b/sys/vm/vm_fault.c index 4268db264d52..ae0103595ae7 100644 --- a/sys/vm/vm_fault.c +++ b/sys/vm/vm_fault.c @@ -1144,7 +1144,7 @@ readrest: fs.object == fs.first_object->backing_object) { vm_page_lock(fs.m); vm_page_dequeue(fs.m); - vm_page_remove(fs.m); + (void)vm_page_remove(fs.m); vm_page_unlock(fs.m); vm_page_lock(fs.first_m); vm_page_replace_checked(fs.m, fs.first_object, diff --git a/sys/vm/vm_map.c b/sys/vm/vm_map.c index 912031702070..38afe6308cc8 100644 --- a/sys/vm/vm_map.c +++ b/sys/vm/vm_map.c @@ -2472,11 +2472,8 @@ again: VM_MAP_RANGE_CHECK(map, start, end); - if (vm_map_lookup_entry(map, start, &entry)) { - vm_map_clip_start(map, entry, start); - } else { + if (!vm_map_lookup_entry(map, start, &entry)) entry = entry->next; - } /* * Make a first pass to check for protection violations. @@ -2515,6 +2512,7 @@ again: * now will do cow due to allowed write (e.g. debugger sets * breakpoint on text segment) */ + vm_map_clip_start(map, entry, start); for (current = entry; current->start < end; current = current->next) { vm_map_clip_end(map, current, end); diff --git a/sys/vm/vm_mmap.c b/sys/vm/vm_mmap.c index cd483527af71..24864889060c 100644 --- a/sys/vm/vm_mmap.c +++ b/sys/vm/vm_mmap.c @@ -103,6 +103,9 @@ SYSCTL_INT(_vm, OID_AUTO, old_mlock, CTLFLAG_RWTUN, &old_mlock, 0, static int mincore_mapped = 1; SYSCTL_INT(_vm, OID_AUTO, mincore_mapped, CTLFLAG_RWTUN, &mincore_mapped, 0, "mincore reports mappings, not residency"); +static int imply_prot_max = 0; +SYSCTL_INT(_vm, OID_AUTO, imply_prot_max, CTLFLAG_RWTUN, &imply_prot_max, 0, + "Imply maximum page permissions in mmap() when none are specified"); #ifdef MAP_32BIT #define MAP_32BIT_MAX_ADDR ((vm_offset_t)1 << 31) @@ -187,9 +190,25 @@ kern_mmap(struct thread *td, uintptr_t addr0, size_t len, int prot, int flags, vm_offset_t addr; vm_size_t pageoff, size; vm_prot_t cap_maxprot; - int align, error; + int align, error, max_prot; cap_rights_t rights; + if ((prot & ~(_PROT_ALL | PROT_MAX(_PROT_ALL))) != 0) + return (EINVAL); + max_prot = PROT_MAX_EXTRACT(prot); + prot = PROT_EXTRACT(prot); + if (max_prot != 0 && (max_prot & prot) != prot) + return (EINVAL); + /* + * Always honor PROT_MAX if set. If not, default to all + * permissions unless we're implying maximum permissions. + * + * XXX: should be tunable per process and ABI. + */ + if (max_prot == 0) + max_prot = (imply_prot_max && prot != PROT_NONE) ? + prot : _PROT_ALL; + vms = td->td_proc->p_vmspace; fp = NULL; AUDIT_ARG_FD(fd); @@ -335,7 +354,7 @@ kern_mmap(struct thread *td, uintptr_t addr0, size_t len, int prot, int flags, * This relies on VM_PROT_* matching PROT_*. */ error = vm_mmap_object(&vms->vm_map, &addr, size, prot, - VM_PROT_ALL, flags, NULL, pos, FALSE, td); + max_prot, flags, NULL, pos, FALSE, td); } else { /* * Mapping file, get fp for validation and don't let the @@ -363,7 +382,7 @@ kern_mmap(struct thread *td, uintptr_t addr0, size_t len, int prot, int flags, /* This relies on VM_PROT_* matching PROT_*. */ error = fo_mmap(fp, &vms->vm_map, &addr, size, prot, - cap_maxprot, flags, pos, td); + max_prot & cap_maxprot, flags, pos, td); } if (error == 0) @@ -594,9 +613,13 @@ kern_mprotect(struct thread *td, uintptr_t addr0, size_t size, int prot) { vm_offset_t addr; vm_size_t pageoff; + int vm_error, max_prot; addr = addr0; - prot = (prot & VM_PROT_ALL); + if ((prot & ~(_PROT_ALL | PROT_MAX(_PROT_ALL))) != 0) + return (EINVAL); + max_prot = PROT_MAX_EXTRACT(prot); + prot = PROT_EXTRACT(prot); pageoff = (addr & PAGE_MASK); addr -= pageoff; size += pageoff; @@ -610,8 +633,18 @@ kern_mprotect(struct thread *td, uintptr_t addr0, size_t size, int prot) if (addr + size < addr) return (EINVAL); - switch (vm_map_protect(&td->td_proc->p_vmspace->vm_map, addr, - addr + size, prot, FALSE)) { + vm_error = KERN_SUCCESS; + if (max_prot != 0) { + if ((max_prot & prot) != prot) + return (EINVAL); + vm_error = vm_map_protect(&td->td_proc->p_vmspace->vm_map, + addr, addr + size, max_prot, TRUE); + } + if (vm_error == KERN_SUCCESS) + vm_error = vm_map_protect(&td->td_proc->p_vmspace->vm_map, + addr, addr + size, prot, FALSE); + + switch (vm_error) { case KERN_SUCCESS: return (0); case KERN_PROTECTION_FAILURE: diff --git a/sys/vm/vm_object.c b/sys/vm/vm_object.c index 9fd90f04b6d9..7c3575e646cf 100644 --- a/sys/vm/vm_object.c +++ b/sys/vm/vm_object.c @@ -1595,10 +1595,8 @@ vm_object_collapse_scan(vm_object_t object, int op) vm_page_lock(p); KASSERT(!pmap_page_is_mapped(p), ("freeing mapped page %p", p)); - if (!vm_page_wired(p)) + if (vm_page_remove(p)) vm_page_free(p); - else - vm_page_remove(p); vm_page_unlock(p); continue; } @@ -1639,10 +1637,8 @@ vm_object_collapse_scan(vm_object_t object, int op) vm_page_lock(p); KASSERT(!pmap_page_is_mapped(p), ("freeing mapped page %p", p)); - if (!vm_page_wired(p)) + if (vm_page_remove(p)) vm_page_free(p); - else - vm_page_remove(p); vm_page_unlock(p); continue; } diff --git a/sys/vm/vm_page.c b/sys/vm/vm_page.c index a90961ce57b5..e43817b812a0 100644 --- a/sys/vm/vm_page.c +++ b/sys/vm/vm_page.c @@ -1458,20 +1458,21 @@ vm_page_insert_radixdone(vm_page_t m, vm_object_t object, vm_page_t mpred) * vm_page_remove: * * Removes the specified page from its containing object, but does not - * invalidate any backing storage. + * invalidate any backing storage. Return true if the page may be safely + * freed and false otherwise. * * The object must be locked. The page must be locked if it is managed. */ -void +bool vm_page_remove(vm_page_t m) { vm_object_t object; vm_page_t mrem; + object = m->object; + if ((m->oflags & VPO_UNMANAGED) == 0) vm_page_assert_locked(m); - if ((object = m->object) == NULL) - return; VM_OBJECT_ASSERT_WLOCKED(object); if (vm_page_xbusied(m)) vm_page_xunbusy_maybelocked(m); @@ -1495,6 +1496,7 @@ vm_page_remove(vm_page_t m) vdrop(object->handle); m->object = NULL; + return (!vm_page_wired(m)); } /* @@ -1665,7 +1667,7 @@ vm_page_rename(vm_page_t m, vm_object_t new_object, vm_pindex_t new_pindex) */ m->pindex = opidx; vm_page_lock(m); - vm_page_remove(m); + (void)vm_page_remove(m); /* Return back to the new pindex to complete vm_page_insert(). */ m->pindex = new_pindex; @@ -3436,7 +3438,8 @@ vm_page_free_prep(vm_page_t m) if (vm_page_sbusied(m)) panic("vm_page_free_prep: freeing busy page %p", m); - vm_page_remove(m); + if (m->object != NULL) + (void)vm_page_remove(m); /* * If fictitious remove object association and diff --git a/sys/vm/vm_page.h b/sys/vm/vm_page.h index d1938d2a1bd8..57f9f6e9081c 100644 --- a/sys/vm/vm_page.h +++ b/sys/vm/vm_page.h @@ -561,7 +561,7 @@ bool vm_page_reclaim_contig(int req, u_long npages, vm_paddr_t low, bool vm_page_reclaim_contig_domain(int domain, int req, u_long npages, vm_paddr_t low, vm_paddr_t high, u_long alignment, vm_paddr_t boundary); void vm_page_reference(vm_page_t m); -void vm_page_remove (vm_page_t); +bool vm_page_remove(vm_page_t); int vm_page_rename (vm_page_t, vm_object_t, vm_pindex_t); vm_page_t vm_page_replace(vm_page_t mnew, vm_object_t object, vm_pindex_t pindex); diff --git a/targets/pseudo/userland/Makefile.depend b/targets/pseudo/userland/Makefile.depend index 934d7be54ed7..469d34993b46 100644 --- a/targets/pseudo/userland/Makefile.depend +++ b/targets/pseudo/userland/Makefile.depend @@ -772,15 +772,6 @@ DIRDEPS+= \ DIRDEPS+= usr.sbin/efidp .endif -.if ${MK_NAND} != "no" -DIRDEPS+= \ - sbin/nandfs \ - sbin/newfs_nandfs \ - usr.sbin/nandsim \ - usr.sbin/nandtool \ - -.endif - DIRDEPS.amd64= \ sbin/bsdlabel \ sbin/fdisk \ diff --git a/targets/pseudo/userland/lib/Makefile.depend b/targets/pseudo/userland/lib/Makefile.depend index 2139d18204ca..6e2e549278a7 100644 --- a/targets/pseudo/userland/lib/Makefile.depend +++ b/targets/pseudo/userland/lib/Makefile.depend @@ -215,10 +215,6 @@ DIRDEPS+= \ DIRDEPS+= stand/libsa32 .endif -.if ${MK_NAND} != "no" -DIRDEPS+= lib/libnandfs -.endif - .if ${MK_CASPER} != "no" DIRDEPS+= \ lib/libcasper/libcasper \ diff --git a/tests/sys/netinet/socket_afinet.c b/tests/sys/netinet/socket_afinet.c index d45f70165519..47744d69b587 100644 --- a/tests/sys/netinet/socket_afinet.c +++ b/tests/sys/netinet/socket_afinet.c @@ -51,6 +51,8 @@ ATF_TC_BODY(socket_afinet_bind_zero, tc) int sd, rc; struct sockaddr_in sin; + atf_tc_skip("doesn't work when mac_portacl(4) loaded (bug238781)"); + sd = socket(PF_INET, SOCK_DGRAM, 0); ATF_CHECK(sd >= 0); diff --git a/tools/build/mk/OptionalObsoleteFiles.inc b/tools/build/mk/OptionalObsoleteFiles.inc index 58592329e11d..c8a2235b5bc0 100644 --- a/tools/build/mk/OptionalObsoleteFiles.inc +++ b/tools/build/mk/OptionalObsoleteFiles.inc @@ -3350,6 +3350,8 @@ OLD_FILES+=usr/share/man/man5/ipf.5.gz OLD_FILES+=usr/share/man/man5/ipf.conf.5.gz OLD_FILES+=usr/share/man/man5/ipf6.conf.5.gz OLD_FILES+=usr/share/man/man5/ipfilter.5.gz +OLD_FILES+=usr/share/man/man8/ipmon.5.gz +OLD_FILES+=usr/share/man/man5/ipmon.conf.5.gz OLD_FILES+=usr/share/man/man5/ipnat.5.gz OLD_FILES+=usr/share/man/man5/ipnat.conf.5.gz OLD_FILES+=usr/share/man/man5/ippool.5.gz diff --git a/tools/tools/nanobsd/defaults.sh b/tools/tools/nanobsd/defaults.sh index 0002373be658..86acab65f67d 100755 --- a/tools/tools/nanobsd/defaults.sh +++ b/tools/tools/nanobsd/defaults.sh @@ -778,8 +778,9 @@ cust_pkgng ( ) ( # Mount packages into chroot mkdir -p ${NANO_WORLDDIR}/_.p mount -t nullfs -o noatime -o ro ${NANO_PACKAGE_DIR} ${NANO_WORLDDIR}/_.p + mount -t devfs devfs ${NANO_WORLDDIR}/dev - trap "umount ${NANO_WORLDDIR}/_.p ; rm -rf ${NANO_WORLDDIR}/_.p" 1 2 15 EXIT + trap "umount ${NANO_WORLDDIR}/dev; umount ${NANO_WORLDDIR}/_.p ; rm -rf ${NANO_WORLDDIR}/_.p" 1 2 15 EXIT # Install pkg-* package CR "${PKGCMD} add /_.p/${_NANO_PKG_PACKAGE}" @@ -804,6 +805,7 @@ cust_pkgng ( ) ( CR0 "${PKGCMD} info" trap - 1 2 15 EXIT + umount ${NANO_WORLDDIR}/dev umount ${NANO_WORLDDIR}/_.p rm -rf ${NANO_WORLDDIR}/_.p ) diff --git a/tools/tools/nanobsd/pcengines/ALIX_DSK b/tools/tools/nanobsd/pcengines/ALIX_DSK index 96ae724d736b..e11f7de4f2f4 100644 --- a/tools/tools/nanobsd/pcengines/ALIX_DSK +++ b/tools/tools/nanobsd/pcengines/ALIX_DSK @@ -65,7 +65,6 @@ device ath_hal device ath_rate_sample device wi device loop -device random device ether device tun device pty diff --git a/tools/tools/tinybsd/conf/bridge/TINYBSD b/tools/tools/tinybsd/conf/bridge/TINYBSD index 0788aea40e44..5d99ad95700d 100644 --- a/tools/tools/tinybsd/conf/bridge/TINYBSD +++ b/tools/tools/tinybsd/conf/bridge/TINYBSD @@ -130,7 +130,6 @@ device wi # WaveLAN/Intersil/Symbol 802.11 wireless NICs. # Pseudo devices. device loop # Network loopback -device random # Entropy device device ether # Ethernet support device pty # Pseudo-ttys (telnet etc) device md # Memory "disks" diff --git a/tools/tools/tinybsd/conf/default/TINYBSD b/tools/tools/tinybsd/conf/default/TINYBSD index 6052764b3f81..841a19e8ee49 100644 --- a/tools/tools/tinybsd/conf/default/TINYBSD +++ b/tools/tools/tinybsd/conf/default/TINYBSD @@ -140,7 +140,6 @@ device wi # WaveLAN/Intersil/Symbol 802.11 wireless NICs. # Pseudo devices. device loop # Network loopback -device random # Entropy device device ether # Ethernet support device ppp # Kernel PPP device tun # Packet tunnel. diff --git a/tools/tools/tinybsd/conf/firewall/TINYBSD b/tools/tools/tinybsd/conf/firewall/TINYBSD index f410c139e371..994280346bbd 100644 --- a/tools/tools/tinybsd/conf/firewall/TINYBSD +++ b/tools/tools/tinybsd/conf/firewall/TINYBSD @@ -129,7 +129,6 @@ device wlan # 802.11 support # Pseudo devices. device loop # Network loopback -device random # Entropy device device ether # Ethernet support device pty # Pseudo-ttys (telnet etc) device md # Memory "disks" diff --git a/tools/tools/tinybsd/conf/minimal/TINYBSD b/tools/tools/tinybsd/conf/minimal/TINYBSD index 2cd1f9af9ae6..74e3c0506bcf 100644 --- a/tools/tools/tinybsd/conf/minimal/TINYBSD +++ b/tools/tools/tinybsd/conf/minimal/TINYBSD @@ -65,7 +65,6 @@ device pmtimer # Pseudo devices. device loop # Network loopback -device random # Entropy device device ether # Ethernet support device pty # Pseudo-ttys (telnet etc) device md # Memory "disks" diff --git a/tools/tools/tinybsd/conf/vpn/TINYBSD b/tools/tools/tinybsd/conf/vpn/TINYBSD index 956c13b00413..4fd064ef8fc7 100644 --- a/tools/tools/tinybsd/conf/vpn/TINYBSD +++ b/tools/tools/tinybsd/conf/vpn/TINYBSD @@ -130,7 +130,6 @@ device xe # Xircom pccard Ethernet # Pseudo devices. device loop # Network loopback -device random # Entropy device device ether # Ethernet support device ppp # Kernel PPP device tun # Packet tunnel. diff --git a/tools/tools/tinybsd/conf/wireless/TINYBSD b/tools/tools/tinybsd/conf/wireless/TINYBSD index aa7ddceb7895..afcd47ca4462 100644 --- a/tools/tools/tinybsd/conf/wireless/TINYBSD +++ b/tools/tools/tinybsd/conf/wireless/TINYBSD @@ -136,7 +136,6 @@ device wi # WaveLAN/Intersil/Symbol 802.11 wireless NICs. # Pseudo devices. device loop # Network loopback -device random # Entropy device device ether # Ethernet support device pty # Pseudo-ttys (telnet etc) device md # Memory "disks" diff --git a/tools/tools/tinybsd/conf/wrap/TINYBSD b/tools/tools/tinybsd/conf/wrap/TINYBSD index c3ce7954b278..2ef7c6742cbd 100644 --- a/tools/tools/tinybsd/conf/wrap/TINYBSD +++ b/tools/tools/tinybsd/conf/wrap/TINYBSD @@ -102,7 +102,6 @@ device ath_rate_sample # Pseudo devices. device loop # Network loopback -device random # Entropy device device ether # Ethernet support device ppp # Kernel PPP device tun # Packet tunnel. diff --git a/usr.bin/calendar/calendars/hr_HR.ISO8859-2/calendar.praznici b/usr.bin/calendar/calendars/hr_HR.ISO8859-2/calendar.praznici index 60ae5e30bd2f..491ec6a4f3f3 100644 --- a/usr.bin/calendar/calendars/hr_HR.ISO8859-2/calendar.praznici +++ b/usr.bin/calendar/calendars/hr_HR.ISO8859-2/calendar.praznici @@ -10,31 +10,31 @@ LANG=hr_HR.ISO8859-2 /* dr¾avni praznici */ -01/01 Nova godina -05/01 Praznik rada -05/30 Tjelovo -06/22 Dan antifa¹istièke borbe -06/25 Dan dr¾avnosti -08/05 Dan domovinske zahvalnosti -10/08 Dan neovisnosti - -/* katolièki blagdani */ -01/06 Sveta tri kralja -Easter-2 Veliki petak +01/01 Nova godina +01/06 Bogojavljenje ili Sveta tri kralja Easter Uskrs Easter+1 Uskrsni ponedjeljak -Easter+49 Duhovi -Easter+50 Duhovni ponedjeljak -Easter+39 Uza¹a¹æe +05/01 Praznik rada +Easter+60 Tijelovo +06/22 Dan antifa¹istièke borbe +06/25 Dan dr¾avnosti +08/05 Dan pobjede i domovinske zahvalnosti i Dan hrvatskih branitelja 08/15 Velika Gospa +10/08 Dan neovisnosti 11/01 Svi sveti 12/25 Bo¾iæ -12/26 Stjepandan +12/26 Sveti Stjepan + +/* katolièki blagdani */ +Easter-2 Veliki petak +Easter+39 Uza¹a¹æe +Easter+49 Duhovi +Easter+50 Duhovni ponedjeljak /* godi¹nja doba */ 03/21* Poèetak proljeæa 06/21* Poèetak ljeta -09/21* Poèetak jesena +09/23* Poèetak jeseni 12/21* Poèetak zime /* ljetno vrijeme */ diff --git a/usr.bin/top/display.c b/usr.bin/top/display.c index 539ddb4d536e..00534fd7f411 100644 --- a/usr.bin/top/display.c +++ b/usr.bin/top/display.c @@ -675,6 +675,9 @@ i_swap(int *stats) { swap_buffer = setup_buffer(swap_buffer, 0); + if (swap_names == NULL) + return; + fputs("\nSwap: ", stdout); lastline++; @@ -690,6 +693,9 @@ u_swap(int *stats) new = setup_buffer(new, 0); + if (swap_names == NULL) + return; + /* format the new line */ summary_format(new, stats, swap_names); line_update(swap_buffer, new, x_swap, y_swap); diff --git a/usr.bin/top/machine.c b/usr.bin/top/machine.c index 563efc624e24..dd2b7a110419 100644 --- a/usr.bin/top/machine.c +++ b/usr.bin/top/machine.c @@ -150,6 +150,7 @@ static const char *swapnames[] = { }; static int swap_stats[nitems(swapnames)]; +static int has_swap; /* these are for keeping track of the proc array */ @@ -248,12 +249,12 @@ update_layout(void) y_mem = 3; y_arc = 4; y_carc = 5; - y_swap = 4 + arc_enabled + carc_enabled; - y_idlecursor = 5 + arc_enabled + carc_enabled; - y_message = 5 + arc_enabled + carc_enabled; - y_header = 6 + arc_enabled + carc_enabled; - y_procs = 7 + arc_enabled + carc_enabled; - Header_lines = 7 + arc_enabled + carc_enabled; + y_swap = 3 + arc_enabled + carc_enabled + has_swap; + y_idlecursor = 4 + arc_enabled + carc_enabled + has_swap; + y_message = 4 + arc_enabled + carc_enabled + has_swap; + y_header = 5 + arc_enabled + carc_enabled + has_swap; + y_procs = 6 + arc_enabled + carc_enabled + has_swap; + Header_lines = 6 + arc_enabled + carc_enabled + has_swap; if (pcpu_stats) { y_mem += ncpus - 1; @@ -273,7 +274,7 @@ machine_init(struct statics *statics) { int i, j, empty, pagesize; uint64_t arc_size; - int carc_en; + int carc_en, nswapdev; size_t size; size = sizeof(smpmode); @@ -298,6 +299,11 @@ machine_init(struct statics *statics) if (kd == NULL) return (-1); + size = sizeof(nswapdev); + if (sysctlbyname("vm.nswapdev", &nswapdev, &size, NULL, + 0) == 0 && nswapdev != 0) + has_swap = 1; + GETSYSCTL("kern.ccpu", ccpu); /* this is used in calculating WCPU -- calculate it ahead of time */ @@ -332,7 +338,10 @@ machine_init(struct statics *statics) statics->carc_names = carcnames; else statics->carc_names = NULL; - statics->swap_names = swapnames; + if (has_swap) + statics->swap_names = swapnames; + else + statics->swap_names = NULL; statics->order_names = ordernames; /* Allocate state for per-CPU stats. */ diff --git a/usr.bin/uname/uname.1 b/usr.bin/uname/uname.1 index 2a5a03f5162f..a3ccc893c1a9 100644 --- a/usr.bin/uname/uname.1 +++ b/usr.bin/uname/uname.1 @@ -28,7 +28,7 @@ .\" @(#)uname.1 8.3 (Berkeley) 4/8/94 .\" $FreeBSD$ .\" -.Dd May 31, 2017 +.Dd June 27, 2019 .Dt UNAME 1 .Os .Sh NAME @@ -36,7 +36,7 @@ .Nd display information about the system .Sh SYNOPSIS .Nm -.Op Fl aiKmnoprsUv +.Op Fl abiKmnoprsUv .Sh DESCRIPTION The .Nm @@ -53,6 +53,8 @@ Behave as though the options and .Fl v were specified. +.It Fl b +Write the kernel's linker-generated build-id to standard output. .It Fl i Write the kernel ident to standard output. .It Fl K @@ -152,3 +154,7 @@ and .Fl U extension flags appeared in .Fx 10.0 . +The +.Fl b +extension flag appeared in +.Fx 13.0 . diff --git a/usr.bin/uname/uname.c b/usr.bin/uname/uname.c index c3bf57303b3c..e97b9c3cb744 100644 --- a/usr.bin/uname/uname.c +++ b/usr.bin/uname/uname.c @@ -67,9 +67,10 @@ static const char sccsid[] = "@(#)uname.c 8.2 (Berkeley) 5/4/95"; #define IFLAG 0x40 #define UFLAG 0x80 #define KFLAG 0x100 +#define BFLAG 0x200 typedef void (*get_t)(void); -static get_t get_ident, get_platform, get_hostname, get_arch, +static get_t get_buildid, get_ident, get_platform, get_hostname, get_arch, get_release, get_sysname, get_kernvers, get_uservers, get_version; static void native_ident(void); @@ -81,11 +82,13 @@ static void native_sysname(void); static void native_version(void); static void native_kernvers(void); static void native_uservers(void); +static void native_buildid(void); static void print_uname(u_int); static void setup_get(void); static void usage(void); -static char *ident, *platform, *hostname, *arch, *release, *sysname, *version, *kernvers, *uservers; +static char *buildid, *ident, *platform, *hostname, *arch, *release, *sysname, + *version, *kernvers, *uservers; static int space; int @@ -97,11 +100,14 @@ main(int argc, char *argv[]) setup_get(); flags = 0; - while ((ch = getopt(argc, argv, "aiKmnoprsUv")) != -1) + while ((ch = getopt(argc, argv, "abiKmnoprsUv")) != -1) switch(ch) { case 'a': flags |= (MFLAG | NFLAG | RFLAG | SFLAG | VFLAG); break; + case 'b': + flags |= BFLAG; + break; case 'i': flags |= IFLAG; break; @@ -169,6 +175,7 @@ setup_get(void) CHECK_ENV("i", ident); CHECK_ENV("K", kernvers); CHECK_ENV("U", uservers); + CHECK_ENV("b", buildid); } #define PRINT_FLAG(flags,flag,var) \ @@ -194,6 +201,7 @@ print_uname(u_int flags) PRINT_FLAG(flags, IFLAG, ident); PRINT_FLAG(flags, KFLAG, kernvers); PRINT_FLAG(flags, UFLAG, uservers); + PRINT_FLAG(flags, BFLAG, buildid); printf("\n"); } @@ -261,6 +269,9 @@ NATIVE_SYSCTL2_GET(arch, CTL_HW, HW_MACHINE_ARCH) { NATIVE_SYSCTLNAME_GET(ident, "kern.ident") { } NATIVE_SET; +NATIVE_SYSCTLNAME_GET(buildid, "kern.build_id") { +} NATIVE_SET; + static void native_uservers(void) { @@ -282,6 +293,6 @@ native_kernvers(void) static void usage(void) { - fprintf(stderr, "usage: uname [-aiKmnoprsUv]\n"); + fprintf(stderr, "usage: uname [-abiKmnoprsUv]\n"); exit(1); } diff --git a/usr.bin/vtfontcvt/vtfontcvt.c b/usr.bin/vtfontcvt/vtfontcvt.c index 70ec7cf31812..e34308d5d365 100644 --- a/usr.bin/vtfontcvt/vtfontcvt.c +++ b/usr.bin/vtfontcvt/vtfontcvt.c @@ -335,9 +335,11 @@ parse_bdf(FILE *fp, unsigned int map_idx) break; } } - } else if (strncmp(ln, "FONTBOUNDINGBOX ", 16) == 0 && - sscanf(ln + 16, "%d %d %d %d", &fbbw, &fbbh, &fbbox, - &fbboy) == 4) { + } else if (strncmp(ln, "FONTBOUNDINGBOX ", 16) == 0) { + if (sscanf(ln + 16, "%d %d %d %d", &fbbw, &fbbh, &fbbox, + &fbboy) != 4) + errx(1, "invalid FONTBOUNDINGBOX at line %u", + linenum); set_width(fbbw); set_height(fbbh); break; @@ -353,8 +355,9 @@ parse_bdf(FILE *fp, unsigned int map_idx) linenum++; ln[length - 1] = '\0'; - if (strncmp(ln, "DWIDTH ", 7) == 0 && - sscanf(ln + 7, "%d %d", &dwidth, &dwy) == 2) { + if (strncmp(ln, "DWIDTH ", 7) == 0) { + if (sscanf(ln + 7, "%d %d", &dwidth, &dwy) != 2) + errx(1, "invalid DWIDTH at line %u", linenum); if (dwy != 0 || (dwidth != fbbw && dwidth * 2 != fbbw)) errx(1, "bitmap with unsupported DWIDTH %d %d at line %u", dwidth, dwy, linenum); diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile index d52364bac84e..508573b23bc1 100644 --- a/usr.sbin/Makefile +++ b/usr.sbin/Makefile @@ -166,8 +166,6 @@ SUBDIR.${MK_NS_CACHING}+= nscd SUBDIR.${MK_LPR}+= lpr SUBDIR.${MK_MAN_UTILS}+= manctl SUBDIR.${MK_MLX5TOOL}+= mlx5tool -SUBDIR.${MK_NAND}+= nandsim -SUBDIR.${MK_NAND}+= nandtool SUBDIR.${MK_NETGRAPH}+= flowctl SUBDIR.${MK_NETGRAPH}+= ngctl SUBDIR.${MK_NETGRAPH}+= nghook diff --git a/usr.sbin/bhyve/Makefile b/usr.sbin/bhyve/Makefile index 85fdf11928b1..e203a57c18a3 100644 --- a/usr.sbin/bhyve/Makefile +++ b/usr.sbin/bhyve/Makefile @@ -16,6 +16,7 @@ BHYVE_SYSDIR?=${SRCTOP} SRCS= \ atkbdc.c \ acpi.c \ + audio.c \ bhyvegc.c \ bhyverun.c \ block_if.c \ @@ -27,6 +28,7 @@ SRCS= \ dbgport.c \ fwctl.c \ gdb.c \ + hda_codec.c \ inout.c \ ioapic.c \ mem.c \ @@ -36,6 +38,7 @@ SRCS= \ pci_ahci.c \ pci_e82545.c \ pci_emul.c \ + pci_hda.c \ pci_fbuf.c \ pci_hostbridge.c \ pci_irq.c \ diff --git a/usr.sbin/bhyve/audio.c b/usr.sbin/bhyve/audio.c new file mode 100644 index 000000000000..dda575813332 --- /dev/null +++ b/usr.sbin/bhyve/audio.c @@ -0,0 +1,284 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2016 Alex Teaca <iateaca@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 ``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$"); + +#ifndef WITHOUT_CAPSICUM +#include <sys/capsicum.h> +#include <capsicum_helpers.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <unistd.h> +#include <assert.h> +#include <errno.h> +#include <err.h> +#include <sysexits.h> + +#include "audio.h" +#include "pci_hda.h" + +/* + * Audio Player internal data structures + */ + +struct audio { + int fd; + uint8_t dir; + uint8_t inited; + char dev_name[64]; +}; + +/* + * Audio Player module function definitions + */ + +/* + * audio_init - initialize an instance of audio player + * @dev_name - the backend sound device used to play / capture + * @dir - dir = 1 for write mode, dir = 0 for read mode + */ +struct audio * +audio_init(const char *dev_name, uint8_t dir) +{ + struct audio *aud = NULL; +#ifndef WITHOUT_CAPSICUM + cap_rights_t rights; + cap_ioctl_t cmds[] = { + SNDCTL_DSP_RESET, SNDCTL_DSP_SETFMT, SNDCTL_DSP_CHANNELS, + SNDCTL_DSP_SPEED, +#ifdef DEBUG_HDA + SNDCTL_DSP_GETOSPACE, SNDCTL_DSP_GETISPACE, +#endif + }; +#endif + + assert(dev_name); + + aud = calloc(1, sizeof(*aud)); + if (!aud) + return NULL; + + if (strlen(dev_name) < sizeof(aud->dev_name)) + memcpy(aud->dev_name, dev_name, strlen(dev_name) + 1); + else { + DPRINTF("dev_name too big\n"); + free(aud); + return NULL; + } + + aud->dir = dir; + + aud->fd = open(aud->dev_name, aud->dir ? O_WRONLY : O_RDONLY, 0); + if (aud->fd == -1) { + DPRINTF("Failed to open dev: %s, errno: %d\n", + aud->dev_name, errno); + return (NULL); + } + +#ifndef WITHOUT_CAPSICUM + cap_rights_init(&rights, CAP_IOCTL, CAP_READ, CAP_WRITE); + if (caph_rights_limit(aud->fd, &rights) == -1) + errx(EX_OSERR, "Unable to apply rights for sandbox"); + if (caph_ioctls_limit(aud->fd, cmds, nitems(cmds)) == -1) + errx(EX_OSERR, "Unable to limit ioctl rights for sandbox"); +#endif + + return aud; +} + +/* + * audio_set_params - reset the sound device and set the audio params + * @aud - the audio player to be configured + * @params - the audio parameters to be set + */ +int +audio_set_params(struct audio *aud, struct audio_params *params) +{ + int audio_fd; + int format, channels, rate; + int err; +#if DEBUG_HDA == 1 + audio_buf_info info; +#endif + + assert(aud); + assert(params); + + if ((audio_fd = aud->fd) < 0) { + DPRINTF("Incorrect audio device descriptor for %s\n", + aud->dev_name); + return (-1); + } + + /* Reset the device if it was previously opened */ + if (aud->inited) { + err = ioctl(audio_fd, SNDCTL_DSP_RESET, NULL); + if (err == -1) { + DPRINTF("Failed to reset fd: %d, errno: %d\n", + aud->fd, errno); + return (-1); + } + } else + aud->inited = 1; + + /* Set the Format (Bits per Sample) */ + format = params->format; + err = ioctl(audio_fd, SNDCTL_DSP_SETFMT, &format); + if (err == -1) { + DPRINTF("Fail to set fmt: 0x%x errno: %d\n", + params->format, errno); + return -1; + } + + /* The device does not support the requested audio format */ + if (format != params->format) { + DPRINTF("Mismatch format: 0x%x params->format: 0x%x\n", + format, params->format); + return -1; + } + + /* Set the Number of Channels */ + channels = params->channels; + err = ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &channels); + if (err == -1) { + DPRINTF("Fail to set channels: %d errno: %d\n", + params->channels, errno); + return -1; + } + + /* The device does not support the requested no. of channels */ + if (channels != params->channels) { + DPRINTF("Mismatch channels: %d params->channels: %d\n", + channels, params->channels); + return -1; + } + + /* Set the Sample Rate / Speed */ + rate = params->rate; + err = ioctl(audio_fd, SNDCTL_DSP_SPEED, &rate); + if (err == -1) { + DPRINTF("Fail to set speed: %d errno: %d\n", + params->rate, errno); + return -1; + } + + /* The device does not support the requested rate / speed */ + if (rate != params->rate) { + DPRINTF("Mismatch rate: %d params->rate: %d\n", + rate, params->rate); + return -1; + } + +#if DEBUG_HDA == 1 + err = ioctl(audio_fd, aud->dir ? SNDCTL_DSP_GETOSPACE : + SNDCTL_DSP_GETISPACE, &info); + if (err == -1) { + DPRINTF("Fail to get audio buf info errno: %d\n", errno); + return -1; + } + DPRINTF("fragstotal: 0x%x fragsize: 0x%x\n", + info.fragstotal, info.fragsize); +#endif + return 0; +} + +/* + * audio_playback - plays samples to the sound device using blocking operations + * @aud - the audio player used to play the samples + * @buf - the buffer containing the samples + * @count - the number of bytes in buffer + */ +int +audio_playback(struct audio *aud, const void *buf, size_t count) +{ + int audio_fd = -1; + ssize_t len = 0, total = 0; + + assert(aud); + assert(aud->dir); + assert(buf); + + audio_fd = aud->fd; + assert(audio_fd != -1); + + total = 0; + while (total < count) { + len = write(audio_fd, buf + total, count - total); + if (len == -1) { + DPRINTF("Fail to write to fd: %d, errno: %d\n", + audio_fd, errno); + return -1; + } + + total += len; + } + + return 0; +} + +/* + * audio_record - records samples from the sound device using + * blocking operations. + * @aud - the audio player used to capture the samples + * @buf - the buffer to receive the samples + * @count - the number of bytes to capture in buffer + * Returns -1 on error and 0 on success + */ +int +audio_record(struct audio *aud, void *buf, size_t count) +{ + int audio_fd = -1; + ssize_t len = 0, total = 0; + + assert(aud); + assert(!aud->dir); + assert(buf); + + audio_fd = aud->fd; + assert(audio_fd != -1); + + total = 0; + while (total < count) { + len = read(audio_fd, buf + total, count - total); + if (len == -1) { + DPRINTF("Fail to write to fd: %d, errno: %d\n", + audio_fd, errno); + return -1; + } + + total += len; + } + + return 0; +} diff --git a/usr.sbin/bhyve/audio.h b/usr.sbin/bhyve/audio.h new file mode 100644 index 000000000000..2b559a43e5df --- /dev/null +++ b/usr.sbin/bhyve/audio.h @@ -0,0 +1,88 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2016 Alex Teaca <iateaca@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 ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _AUDIO_EMUL_H_ +#define _AUDIO_EMUL_H_ + +#include <sys/types.h> +#include <sys/soundcard.h> + +/* + * Audio Player data structures + */ + +struct audio; + +struct audio_params { + int channels; + int format; + int rate; +}; + +/* + * Audio Player API + */ + +/* + * audio_init - initialize an instance of audio player + * @dev_name - the backend sound device used to play / capture + * @dir - dir = 1 for write mode, dir = 0 for read mode + * Returns NULL on error and the address of the audio player instance + */ +struct audio *audio_init(const char *dev_name, uint8_t dir); + +/* + * audio_set_params - reset the sound device and set the audio params + * @aud - the audio player to be configured + * @params - the audio parameters to be set + * Returns -1 on error and 0 on success + */ +int audio_set_params(struct audio *aud, struct audio_params *params); + +/* + * audio_playback - plays samples to the sound device using blocking operations + * @aud - the audio player used to play the samples + * @buf - the buffer containing the samples + * @count - the number of bytes in buffer + * Returns -1 on error and 0 on success + */ +int audio_playback(struct audio *aud, const void *buf, size_t count); + +/* + * audio_record - records samples from the sound device using blocking + * operations. + * @aud - the audio player used to capture the samples + * @buf - the buffer to receive the samples + * @count - the number of bytes to capture in buffer + * Returns -1 on error and 0 on success + */ +int audio_record(struct audio *aud, void *buf, size_t count); + +#endif /* _AUDIO_EMUL_H_ */ diff --git a/usr.sbin/bhyve/bhyve.8 b/usr.sbin/bhyve/bhyve.8 index 2f2236e8ce38..3ab9e4e67dde 100644 --- a/usr.sbin/bhyve/bhyve.8 +++ b/usr.sbin/bhyve/bhyve.8 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd December 11, 2018 +.Dd June 24, 2019 .Dt BHYVE 8 .Os .Sh NAME @@ -248,6 +248,8 @@ Raw framebuffer device attached to VNC server. eXtensible Host Controller Interface (xHCI) USB controller. .It Li nvme NVM Express (NVMe) controller. +.It Li hda +High Definition Audio Controller. .El .It Op Ar conf This optional parameter describes the backend for device emulations. @@ -475,6 +477,16 @@ Sector size (defaults to blockif sector size). .It Li ser Serial number with maximum 20 characters. .El +.Pp +HD Audio devices: +.Bl -tag -width 10n +.It Li play +Playback device, typically +.Ar /dev/dsp0 . +.It Li rec +Recording device, typically +.Ar /dev/dsp0 . +.El .El .It Fl S Wire guest memory. diff --git a/usr.sbin/bhyve/hda_codec.c b/usr.sbin/bhyve/hda_codec.c new file mode 100644 index 000000000000..82f5fb1eed92 --- /dev/null +++ b/usr.sbin/bhyve/hda_codec.c @@ -0,0 +1,952 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2016 Alex Teaca <iateaca@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 ``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 <pthread.h> +#include <pthread_np.h> +#include <unistd.h> + +#include "pci_hda.h" +#include "audio.h" + +/* + * HDA Codec defines + */ +#define INTEL_VENDORID 0x8086 + +#define HDA_CODEC_SUBSYSTEM_ID ((INTEL_VENDORID << 16) | 0x01) +#define HDA_CODEC_ROOT_NID 0x00 +#define HDA_CODEC_FG_NID 0x01 +#define HDA_CODEC_AUDIO_OUTPUT_NID 0x02 +#define HDA_CODEC_PIN_OUTPUT_NID 0x03 +#define HDA_CODEC_AUDIO_INPUT_NID 0x04 +#define HDA_CODEC_PIN_INPUT_NID 0x05 + +#define HDA_CODEC_STREAMS_COUNT 0x02 +#define HDA_CODEC_STREAM_OUTPUT 0x00 +#define HDA_CODEC_STREAM_INPUT 0x01 + +#define HDA_CODEC_PARAMS_COUNT 0x14 +#define HDA_CODEC_CONN_LIST_COUNT 0x01 +#define HDA_CODEC_RESPONSE_EX_UNSOL 0x10 +#define HDA_CODEC_RESPONSE_EX_SOL 0x00 +#define HDA_CODEC_AMP_NUMSTEPS 0x4a + +#define HDA_CODEC_SUPP_STREAM_FORMATS_PCM \ + (1 << HDA_PARAM_SUPP_STREAM_FORMATS_PCM_SHIFT) + +#define HDA_CODEC_FMT_BASE_MASK (0x01 << 14) + +#define HDA_CODEC_FMT_MULT_MASK (0x07 << 11) +#define HDA_CODEC_FMT_MULT_2 (0x01 << 11) +#define HDA_CODEC_FMT_MULT_3 (0x02 << 11) +#define HDA_CODEC_FMT_MULT_4 (0x03 << 11) + +#define HDA_CODEC_FMT_DIV_MASK 0x07 +#define HDA_CODEC_FMT_DIV_SHIFT 8 + +#define HDA_CODEC_FMT_BITS_MASK (0x07 << 4) +#define HDA_CODEC_FMT_BITS_8 (0x00 << 4) +#define HDA_CODEC_FMT_BITS_16 (0x01 << 4) +#define HDA_CODEC_FMT_BITS_24 (0x03 << 4) +#define HDA_CODEC_FMT_BITS_32 (0x04 << 4) + +#define HDA_CODEC_FMT_CHAN_MASK (0x0f << 0) + +#define HDA_CODEC_AUDIO_WCAP_OUTPUT \ + (0x00 << HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_SHIFT) +#define HDA_CODEC_AUDIO_WCAP_INPUT \ + (0x01 << HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_SHIFT) +#define HDA_CODEC_AUDIO_WCAP_PIN \ + (0x04 << HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_SHIFT) +#define HDA_CODEC_AUDIO_WCAP_CONN_LIST \ + (1 << HDA_PARAM_AUDIO_WIDGET_CAP_CONN_LIST_SHIFT) +#define HDA_CODEC_AUDIO_WCAP_FORMAT_OVR \ + (1 << HDA_PARAM_AUDIO_WIDGET_CAP_FORMAT_OVR_SHIFT) +#define HDA_CODEC_AUDIO_WCAP_AMP_OVR \ + (1 << HDA_PARAM_AUDIO_WIDGET_CAP_AMP_OVR_SHIFT) +#define HDA_CODEC_AUDIO_WCAP_OUT_AMP \ + (1 << HDA_PARAM_AUDIO_WIDGET_CAP_OUT_AMP_SHIFT) +#define HDA_CODEC_AUDIO_WCAP_IN_AMP \ + (1 << HDA_PARAM_AUDIO_WIDGET_CAP_IN_AMP_SHIFT) +#define HDA_CODEC_AUDIO_WCAP_STEREO \ + (1 << HDA_PARAM_AUDIO_WIDGET_CAP_STEREO_SHIFT) + +#define HDA_CODEC_PIN_CAP_OUTPUT \ + (1 << HDA_PARAM_PIN_CAP_OUTPUT_CAP_SHIFT) +#define HDA_CODEC_PIN_CAP_INPUT \ + (1 << HDA_PARAM_PIN_CAP_INPUT_CAP_SHIFT) +#define HDA_CODEC_PIN_CAP_PRESENCE_DETECT \ + (1 << HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP_SHIFT) + +#define HDA_CODEC_OUTPUT_AMP_CAP_MUTE_CAP \ + (1 << HDA_PARAM_OUTPUT_AMP_CAP_MUTE_CAP_SHIFT) +#define HDA_CODEC_OUTPUT_AMP_CAP_STEPSIZE \ + (0x03 << HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE_SHIFT) +#define HDA_CODEC_OUTPUT_AMP_CAP_NUMSTEPS \ + (HDA_CODEC_AMP_NUMSTEPS << HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS_SHIFT) +#define HDA_CODEC_OUTPUT_AMP_CAP_OFFSET \ + (HDA_CODEC_AMP_NUMSTEPS << HDA_PARAM_OUTPUT_AMP_CAP_OFFSET_SHIFT) + +#define HDA_CODEC_SET_AMP_GAIN_MUTE_MUTE 0x80 +#define HDA_CODEC_SET_AMP_GAIN_MUTE_GAIN_MASK 0x7f + +#define HDA_CODEC_PIN_SENSE_PRESENCE_PLUGGED (1 << 31) +#define HDA_CODEC_PIN_WIDGET_CTRL_OUT_ENABLE \ + (1 << HDA_CMD_GET_PIN_WIDGET_CTRL_OUT_ENABLE_SHIFT) +#define HDA_CODEC_PIN_WIDGET_CTRL_IN_ENABLE \ + (1 << HDA_CMD_GET_PIN_WIDGET_CTRL_IN_ENABLE_SHIFT) + +#define HDA_CONFIG_DEFAULTCONF_COLOR_BLACK \ + (0x01 << HDA_CONFIG_DEFAULTCONF_COLOR_SHIFT) +#define HDA_CONFIG_DEFAULTCONF_COLOR_RED \ + (0x05 << HDA_CONFIG_DEFAULTCONF_COLOR_SHIFT) + +#define HDA_CODEC_BUF_SIZE HDA_FIFO_SIZE + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + + +/* + * HDA Audio Context data structures + */ + +typedef void (*transfer_func_t)(void *arg); +typedef int (*setup_func_t)(void *arg); + +struct hda_audio_ctxt { + char name[64]; + uint8_t run; + uint8_t started; + void *priv; + pthread_t tid; + pthread_mutex_t mtx; + pthread_cond_t cond; + setup_func_t do_setup; + transfer_func_t do_transfer; +}; + +/* + * HDA Audio Context module function declarations + */ + +static void *hda_audio_ctxt_thr(void *arg); +static int hda_audio_ctxt_init(struct hda_audio_ctxt *actx, const char *tname, + transfer_func_t do_transfer, setup_func_t do_setup, void *priv); +static int hda_audio_ctxt_start(struct hda_audio_ctxt *actx); +static int hda_audio_ctxt_stop(struct hda_audio_ctxt *actx); + +/* + * HDA Codec data structures + */ + +struct hda_codec_softc; + +typedef uint32_t (*verb_func_t)(struct hda_codec_softc *sc, uint16_t verb, + uint16_t payload); + +struct hda_codec_stream { + uint8_t buf[HDA_CODEC_BUF_SIZE]; + uint8_t channel; + uint16_t fmt; + uint8_t stream; + + uint8_t left_gain; + uint8_t right_gain; + uint8_t left_mute; + uint8_t right_mute; + + struct audio *aud; + struct hda_audio_ctxt actx; +}; + +struct hda_codec_softc { + uint32_t no_nodes; + uint32_t subsystem_id; + const uint32_t (*get_parameters)[HDA_CODEC_PARAMS_COUNT]; + const uint8_t (*conn_list)[HDA_CODEC_CONN_LIST_COUNT]; + const uint32_t *conf_default; + const uint8_t *pin_ctrl_default; + const verb_func_t *verb_handlers; + + struct hda_codec_inst *hci; + struct hda_codec_stream streams[HDA_CODEC_STREAMS_COUNT]; +}; + +/* + * HDA Codec module function declarations + */ +static int hda_codec_init(struct hda_codec_inst *hci, const char *play, + const char *rec, const char *opts); +static int hda_codec_reset(struct hda_codec_inst *hci); +static int hda_codec_command(struct hda_codec_inst *hci, uint32_t cmd_data); +static int hda_codec_notify(struct hda_codec_inst *hci, uint8_t run, + uint8_t stream, uint8_t dir); + +static int hda_codec_parse_format(uint16_t fmt, struct audio_params *params); + +static uint32_t hda_codec_audio_output_nid(struct hda_codec_softc *sc, + uint16_t verb, uint16_t payload); +static void hda_codec_audio_output_do_transfer(void *arg); +static int hda_codec_audio_output_do_setup(void *arg); +static uint32_t hda_codec_audio_input_nid(struct hda_codec_softc *sc, + uint16_t verb, uint16_t payload); +static void hda_codec_audio_input_do_transfer(void *arg); +static int hda_codec_audio_input_do_setup(void *arg); + +static uint32_t hda_codec_audio_inout_nid(struct hda_codec_stream *st, + uint16_t verb, uint16_t payload); + +/* + * HDA Codec global data + */ + +#define HDA_CODEC_ROOT_DESC \ + [HDA_CODEC_ROOT_NID] = { \ + [HDA_PARAM_VENDOR_ID] = INTEL_VENDORID, \ + [HDA_PARAM_REVISION_ID] = 0xffff, \ + /* 1 Subnode, StartNid = 1 */ \ + [HDA_PARAM_SUB_NODE_COUNT] = 0x00010001, \ + }, \ + +#define HDA_CODEC_FG_COMMON_DESC \ + [HDA_PARAM_FCT_GRP_TYPE] = HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO,\ + /* B8 - B32, 8.0 - 192.0kHz */ \ + [HDA_PARAM_SUPP_PCM_SIZE_RATE] = (0x1f << 16) | 0x7ff, \ + [HDA_PARAM_SUPP_STREAM_FORMATS] = HDA_CODEC_SUPP_STREAM_FORMATS_PCM,\ + [HDA_PARAM_INPUT_AMP_CAP] = 0x00, /* None */ \ + [HDA_PARAM_OUTPUT_AMP_CAP] = 0x00, /* None */ \ + [HDA_PARAM_GPIO_COUNT] = 0x00, \ + +#define HDA_CODEC_FG_OUTPUT_DESC \ + [HDA_CODEC_FG_NID] = { \ + /* 2 Subnodes, StartNid = 2 */ \ + [HDA_PARAM_SUB_NODE_COUNT] = 0x00020002, \ + HDA_CODEC_FG_COMMON_DESC \ + }, \ + +#define HDA_CODEC_FG_INPUT_DESC \ + [HDA_CODEC_FG_NID] = { \ + /* 2 Subnodes, StartNid = 4 */ \ + [HDA_PARAM_SUB_NODE_COUNT] = 0x00040002, \ + HDA_CODEC_FG_COMMON_DESC \ + }, \ + +#define HDA_CODEC_FG_DUPLEX_DESC \ + [HDA_CODEC_FG_NID] = { \ + /* 4 Subnodes, StartNid = 2 */ \ + [HDA_PARAM_SUB_NODE_COUNT] = 0x00020004, \ + HDA_CODEC_FG_COMMON_DESC \ + }, \ + +#define HDA_CODEC_OUTPUT_DESC \ + [HDA_CODEC_AUDIO_OUTPUT_NID] = { \ + [HDA_PARAM_AUDIO_WIDGET_CAP] = \ + HDA_CODEC_AUDIO_WCAP_OUTPUT | \ + HDA_CODEC_AUDIO_WCAP_FORMAT_OVR | \ + HDA_CODEC_AUDIO_WCAP_AMP_OVR | \ + HDA_CODEC_AUDIO_WCAP_OUT_AMP | \ + HDA_CODEC_AUDIO_WCAP_STEREO, \ + /* B16, 16.0 - 192.0kHz */ \ + [HDA_PARAM_SUPP_PCM_SIZE_RATE] = (0x02 << 16) | 0x7fc, \ + [HDA_PARAM_SUPP_STREAM_FORMATS] = \ + HDA_CODEC_SUPP_STREAM_FORMATS_PCM, \ + [HDA_PARAM_INPUT_AMP_CAP] = 0x00, /* None */ \ + [HDA_PARAM_CONN_LIST_LENGTH] = 0x00, \ + [HDA_PARAM_OUTPUT_AMP_CAP] = \ + HDA_CODEC_OUTPUT_AMP_CAP_MUTE_CAP | \ + HDA_CODEC_OUTPUT_AMP_CAP_STEPSIZE | \ + HDA_CODEC_OUTPUT_AMP_CAP_NUMSTEPS | \ + HDA_CODEC_OUTPUT_AMP_CAP_OFFSET, \ + }, \ + [HDA_CODEC_PIN_OUTPUT_NID] = { \ + [HDA_PARAM_AUDIO_WIDGET_CAP] = \ + HDA_CODEC_AUDIO_WCAP_PIN | \ + HDA_CODEC_AUDIO_WCAP_CONN_LIST | \ + HDA_CODEC_AUDIO_WCAP_STEREO, \ + [HDA_PARAM_PIN_CAP] = HDA_CODEC_PIN_CAP_OUTPUT | \ + HDA_CODEC_PIN_CAP_PRESENCE_DETECT,\ + [HDA_PARAM_INPUT_AMP_CAP] = 0x00, /* None */ \ + [HDA_PARAM_CONN_LIST_LENGTH] = 0x01, \ + [HDA_PARAM_OUTPUT_AMP_CAP] = 0x00, /* None */ \ + }, \ + +#define HDA_CODEC_INPUT_DESC \ + [HDA_CODEC_AUDIO_INPUT_NID] = { \ + [HDA_PARAM_AUDIO_WIDGET_CAP] = \ + HDA_CODEC_AUDIO_WCAP_INPUT | \ + HDA_CODEC_AUDIO_WCAP_CONN_LIST | \ + HDA_CODEC_AUDIO_WCAP_FORMAT_OVR | \ + HDA_CODEC_AUDIO_WCAP_AMP_OVR | \ + HDA_CODEC_AUDIO_WCAP_IN_AMP | \ + HDA_CODEC_AUDIO_WCAP_STEREO, \ + /* B16, 16.0 - 192.0kHz */ \ + [HDA_PARAM_SUPP_PCM_SIZE_RATE] = (0x02 << 16) | 0x7fc, \ + [HDA_PARAM_SUPP_STREAM_FORMATS] = \ + HDA_CODEC_SUPP_STREAM_FORMATS_PCM, \ + [HDA_PARAM_OUTPUT_AMP_CAP] = 0x00, /* None */ \ + [HDA_PARAM_CONN_LIST_LENGTH] = 0x01, \ + [HDA_PARAM_INPUT_AMP_CAP] = \ + HDA_CODEC_OUTPUT_AMP_CAP_MUTE_CAP | \ + HDA_CODEC_OUTPUT_AMP_CAP_STEPSIZE | \ + HDA_CODEC_OUTPUT_AMP_CAP_NUMSTEPS | \ + HDA_CODEC_OUTPUT_AMP_CAP_OFFSET, \ + }, \ + [HDA_CODEC_PIN_INPUT_NID] = { \ + [HDA_PARAM_AUDIO_WIDGET_CAP] = \ + HDA_CODEC_AUDIO_WCAP_PIN | \ + HDA_CODEC_AUDIO_WCAP_STEREO, \ + [HDA_PARAM_PIN_CAP] = HDA_CODEC_PIN_CAP_INPUT | \ + HDA_CODEC_PIN_CAP_PRESENCE_DETECT, \ + [HDA_PARAM_INPUT_AMP_CAP] = 0x00, /* None */ \ + [HDA_PARAM_OUTPUT_AMP_CAP] = 0x00, /* None */ \ + }, \ + +static const uint32_t +hda_codec_output_parameters[][HDA_CODEC_PARAMS_COUNT] = { + HDA_CODEC_ROOT_DESC + HDA_CODEC_FG_OUTPUT_DESC + HDA_CODEC_OUTPUT_DESC +}; + +static const uint32_t +hda_codec_input_parameters[][HDA_CODEC_PARAMS_COUNT] = { + HDA_CODEC_ROOT_DESC + HDA_CODEC_FG_INPUT_DESC + HDA_CODEC_INPUT_DESC +}; + +static const uint32_t +hda_codec_duplex_parameters[][HDA_CODEC_PARAMS_COUNT] = { + HDA_CODEC_ROOT_DESC + HDA_CODEC_FG_DUPLEX_DESC + HDA_CODEC_OUTPUT_DESC + HDA_CODEC_INPUT_DESC +}; + +#define HDA_CODEC_NODES_COUNT (ARRAY_SIZE(hda_codec_duplex_parameters)) + +static const uint8_t +hda_codec_conn_list[HDA_CODEC_NODES_COUNT][HDA_CODEC_CONN_LIST_COUNT] = { + [HDA_CODEC_PIN_OUTPUT_NID] = {HDA_CODEC_AUDIO_OUTPUT_NID}, + [HDA_CODEC_AUDIO_INPUT_NID] = {HDA_CODEC_PIN_INPUT_NID}, +}; + +static const uint32_t +hda_codec_conf_default[HDA_CODEC_NODES_COUNT] = { + [HDA_CODEC_PIN_OUTPUT_NID] = \ + HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK | + HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_OUT | + HDA_CONFIG_DEFAULTCONF_COLOR_BLACK | + (0x01 << HDA_CONFIG_DEFAULTCONF_ASSOCIATION_SHIFT), + [HDA_CODEC_PIN_INPUT_NID] = HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK | + HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN | + HDA_CONFIG_DEFAULTCONF_COLOR_RED | + (0x02 << HDA_CONFIG_DEFAULTCONF_ASSOCIATION_SHIFT), +}; + +static const uint8_t +hda_codec_pin_ctrl_default[HDA_CODEC_NODES_COUNT] = { + [HDA_CODEC_PIN_OUTPUT_NID] = HDA_CODEC_PIN_WIDGET_CTRL_OUT_ENABLE, + [HDA_CODEC_PIN_INPUT_NID] = HDA_CODEC_PIN_WIDGET_CTRL_IN_ENABLE, +}; + +static const +verb_func_t hda_codec_verb_handlers[HDA_CODEC_NODES_COUNT] = { + [HDA_CODEC_AUDIO_OUTPUT_NID] = hda_codec_audio_output_nid, + [HDA_CODEC_AUDIO_INPUT_NID] = hda_codec_audio_input_nid, +}; + +/* + * HDA Codec module function definitions + */ + +static int +hda_codec_init(struct hda_codec_inst *hci, const char *play, + const char *rec, const char *opts) +{ + struct hda_codec_softc *sc = NULL; + struct hda_codec_stream *st = NULL; + int err; + + if (!(play || rec)) + return (-1); + + DPRINTF("cad: 0x%x opts: %s\n", hci->cad, opts); + + sc = calloc(1, sizeof(*sc)); + if (!sc) + return (-1); + + if (play && rec) + sc->get_parameters = hda_codec_duplex_parameters; + else { + if (play) + sc->get_parameters = hda_codec_output_parameters; + else + sc->get_parameters = hda_codec_input_parameters; + } + sc->subsystem_id = HDA_CODEC_SUBSYSTEM_ID; + sc->no_nodes = HDA_CODEC_NODES_COUNT; + sc->conn_list = hda_codec_conn_list; + sc->conf_default = hda_codec_conf_default; + sc->pin_ctrl_default = hda_codec_pin_ctrl_default; + sc->verb_handlers = hda_codec_verb_handlers; + DPRINTF("HDA Codec nodes: %d\n", sc->no_nodes); + + /* + * Initialize the Audio Output stream + */ + if (play) { + st = &sc->streams[HDA_CODEC_STREAM_OUTPUT]; + + err = hda_audio_ctxt_init(&st->actx, "hda-audio-output", + hda_codec_audio_output_do_transfer, + hda_codec_audio_output_do_setup, sc); + assert(!err); + + st->aud = audio_init(play, 1); + if (!st->aud) { + DPRINTF("Fail to init the output audio player\n"); + return (-1); + } + } + + /* + * Initialize the Audio Input stream + */ + if (rec) { + st = &sc->streams[HDA_CODEC_STREAM_INPUT]; + + err = hda_audio_ctxt_init(&st->actx, "hda-audio-input", + hda_codec_audio_input_do_transfer, + hda_codec_audio_input_do_setup, sc); + assert(!err); + + st->aud = audio_init(rec, 0); + if (!st->aud) { + DPRINTF("Fail to init the input audio player\n"); + return (-1); + } + } + + sc->hci = hci; + hci->priv = sc; + + return (0); +} + +static int +hda_codec_reset(struct hda_codec_inst *hci) +{ + struct hda_ops *hops = NULL; + struct hda_codec_softc *sc = NULL; + struct hda_codec_stream *st = NULL; + int i; + + assert(hci); + + hops = hci->hops; + assert(hops); + + sc = (struct hda_codec_softc *)hci->priv; + assert(sc); + + for (i = 0; i < HDA_CODEC_STREAMS_COUNT; i++) { + st = &sc->streams[i]; + st->left_gain = HDA_CODEC_AMP_NUMSTEPS; + st->right_gain = HDA_CODEC_AMP_NUMSTEPS; + st->left_mute = HDA_CODEC_SET_AMP_GAIN_MUTE_MUTE; + st->right_mute = HDA_CODEC_SET_AMP_GAIN_MUTE_MUTE; + } + + DPRINTF("cad: 0x%x\n", hci->cad); + + if (!hops->signal) { + DPRINTF("The controller ops does not implement \ + the signal function\n"); + return (-1); + } + + return (hops->signal(hci)); +} + +static int +hda_codec_command(struct hda_codec_inst *hci, uint32_t cmd_data) +{ + struct hda_codec_softc *sc = NULL; + struct hda_ops *hops = NULL; + uint8_t cad = 0, nid = 0; + uint16_t verb = 0, payload = 0; + uint32_t res = 0; + + /* 4 bits */ + cad = (cmd_data >> HDA_CMD_CAD_SHIFT) & 0x0f; + /* 8 bits */ + nid = (cmd_data >> HDA_CMD_NID_SHIFT) & 0xff; + + if ((cmd_data & 0x70000) == 0x70000) { + /* 12 bits */ + verb = (cmd_data >> HDA_CMD_VERB_12BIT_SHIFT) & 0x0fff; + /* 8 bits */ + payload = cmd_data & 0xff; + } else { + /* 4 bits */ + verb = (cmd_data >> HDA_CMD_VERB_4BIT_SHIFT) & 0x0f; + /* 16 bits */ + payload = cmd_data & 0xffff; + } + + assert(cad == hci->cad); + assert(hci); + + hops = hci->hops; + assert(hops); + + sc = (struct hda_codec_softc *)hci->priv; + assert(sc); + + assert(nid < sc->no_nodes); + + if (!hops->response) { + DPRINTF("The controller ops does not implement \ + the response function\n"); + return (-1); + } + + switch (verb) { + case HDA_CMD_VERB_GET_PARAMETER: + res = sc->get_parameters[nid][payload]; + break; + case HDA_CMD_VERB_GET_CONN_LIST_ENTRY: + res = sc->conn_list[nid][0]; + break; + case HDA_CMD_VERB_GET_PIN_WIDGET_CTRL: + res = sc->pin_ctrl_default[nid]; + break; + case HDA_CMD_VERB_GET_PIN_SENSE: + res = HDA_CODEC_PIN_SENSE_PRESENCE_PLUGGED; + break; + case HDA_CMD_VERB_GET_CONFIGURATION_DEFAULT: + res = sc->conf_default[nid]; + break; + case HDA_CMD_VERB_GET_SUBSYSTEM_ID: + res = sc->subsystem_id; + break; + default: + assert(sc->verb_handlers); + if (sc->verb_handlers[nid]) + res = sc->verb_handlers[nid](sc, verb, payload); + else + DPRINTF("Unknown VERB: 0x%x\n", verb); + break; + } + + DPRINTF("cad: 0x%x nid: 0x%x verb: 0x%x payload: 0x%x response: 0x%x\n", + cad, nid, verb, payload, res); + + return (hops->response(hci, res, HDA_CODEC_RESPONSE_EX_SOL)); +} + +static int +hda_codec_notify(struct hda_codec_inst *hci, uint8_t run, + uint8_t stream, uint8_t dir) +{ + struct hda_codec_softc *sc = NULL; + struct hda_codec_stream *st = NULL; + struct hda_audio_ctxt *actx = NULL; + int i; + int err; + + assert(hci); + assert(stream); + + sc = (struct hda_codec_softc *)hci->priv; + assert(sc); + + i = dir ? HDA_CODEC_STREAM_OUTPUT : HDA_CODEC_STREAM_INPUT; + st = &sc->streams[i]; + + DPRINTF("run: %d, stream: 0x%x, st->stream: 0x%x dir: %d\n", + run, stream, st->stream, dir); + + if (stream != st->stream) { + DPRINTF("Stream not found\n"); + return (0); + } + + actx = &st->actx; + + if (run) + err = hda_audio_ctxt_start(actx); + else + err = hda_audio_ctxt_stop(actx); + + return (err); +} + +static int +hda_codec_parse_format(uint16_t fmt, struct audio_params *params) +{ + uint8_t div = 0; + + assert(params); + + /* Compute the Sample Rate */ + params->rate = (fmt & HDA_CODEC_FMT_BASE_MASK) ? 44100 : 48000; + + switch (fmt & HDA_CODEC_FMT_MULT_MASK) { + case HDA_CODEC_FMT_MULT_2: + params->rate *= 2; + break; + case HDA_CODEC_FMT_MULT_3: + params->rate *= 3; + break; + case HDA_CODEC_FMT_MULT_4: + params->rate *= 4; + break; + } + + div = (fmt >> HDA_CODEC_FMT_DIV_SHIFT) & HDA_CODEC_FMT_DIV_MASK; + params->rate /= (div + 1); + + /* Compute the Bits per Sample */ + switch (fmt & HDA_CODEC_FMT_BITS_MASK) { + case HDA_CODEC_FMT_BITS_8: + params->format = AFMT_U8; + break; + case HDA_CODEC_FMT_BITS_16: + params->format = AFMT_S16_LE; + break; + case HDA_CODEC_FMT_BITS_24: + params->format = AFMT_S24_LE; + break; + case HDA_CODEC_FMT_BITS_32: + params->format = AFMT_S32_LE; + break; + default: + DPRINTF("Unknown format bits: 0x%x\n", + fmt & HDA_CODEC_FMT_BITS_MASK); + return (-1); + } + + /* Compute the Number of Channels */ + params->channels = (fmt & HDA_CODEC_FMT_CHAN_MASK) + 1; + + return (0); +} + +static uint32_t +hda_codec_audio_output_nid(struct hda_codec_softc *sc, uint16_t verb, + uint16_t payload) +{ + struct hda_codec_stream *st = &sc->streams[HDA_CODEC_STREAM_OUTPUT]; + int res; + + res = hda_codec_audio_inout_nid(st, verb, payload); + + return (res); +} + +static void +hda_codec_audio_output_do_transfer(void *arg) +{ + struct hda_codec_softc *sc = (struct hda_codec_softc *)arg; + struct hda_codec_inst *hci = NULL; + struct hda_ops *hops = NULL; + struct hda_codec_stream *st = NULL; + struct audio *aud = NULL; + int err; + + hci = sc->hci; + assert(hci); + + hops = hci->hops; + assert(hops); + + st = &sc->streams[HDA_CODEC_STREAM_OUTPUT]; + aud = st->aud; + + err = hops->transfer(hci, st->stream, 1, st->buf, sizeof(st->buf)); + if (err) + return; + + err = audio_playback(aud, st->buf, sizeof(st->buf)); + assert(!err); +} + +static int +hda_codec_audio_output_do_setup(void *arg) +{ + struct hda_codec_softc *sc = (struct hda_codec_softc *)arg; + struct hda_codec_stream *st = NULL; + struct audio *aud = NULL; + struct audio_params params; + int err; + + st = &sc->streams[HDA_CODEC_STREAM_OUTPUT]; + aud = st->aud; + + err = hda_codec_parse_format(st->fmt, ¶ms); + if (err) + return (-1); + + DPRINTF("rate: %d, channels: %d, format: 0x%x\n", + params.rate, params.channels, params.format); + + return (audio_set_params(aud, ¶ms)); +} + +static uint32_t +hda_codec_audio_input_nid(struct hda_codec_softc *sc, uint16_t verb, + uint16_t payload) +{ + struct hda_codec_stream *st = &sc->streams[HDA_CODEC_STREAM_INPUT]; + int res; + + res = hda_codec_audio_inout_nid(st, verb, payload); + + return (res); +} + +static void +hda_codec_audio_input_do_transfer(void *arg) +{ + struct hda_codec_softc *sc = (struct hda_codec_softc *)arg; + struct hda_codec_inst *hci = NULL; + struct hda_ops *hops = NULL; + struct hda_codec_stream *st = NULL; + struct audio *aud = NULL; + int err; + + hci = sc->hci; + assert(hci); + + hops = hci->hops; + assert(hops); + + st = &sc->streams[HDA_CODEC_STREAM_INPUT]; + aud = st->aud; + + err = audio_record(aud, st->buf, sizeof(st->buf)); + assert(!err); + + hops->transfer(hci, st->stream, 0, st->buf, sizeof(st->buf)); +} + +static int +hda_codec_audio_input_do_setup(void *arg) +{ + struct hda_codec_softc *sc = (struct hda_codec_softc *)arg; + struct hda_codec_stream *st = NULL; + struct audio *aud = NULL; + struct audio_params params; + int err; + + st = &sc->streams[HDA_CODEC_STREAM_INPUT]; + aud = st->aud; + + err = hda_codec_parse_format(st->fmt, ¶ms); + if (err) + return (-1); + + DPRINTF("rate: %d, channels: %d, format: 0x%x\n", + params.rate, params.channels, params.format); + + return (audio_set_params(aud, ¶ms)); +} + +static uint32_t +hda_codec_audio_inout_nid(struct hda_codec_stream *st, uint16_t verb, + uint16_t payload) +{ + uint32_t res = 0; + uint8_t mute = 0; + uint8_t gain = 0; + + DPRINTF("%s verb: 0x%x, payload, 0x%x\n", st->actx.name, verb, payload); + + switch (verb) { + case HDA_CMD_VERB_GET_CONV_FMT: + res = st->fmt; + break; + case HDA_CMD_VERB_SET_CONV_FMT: + st->fmt = payload; + break; + case HDA_CMD_VERB_GET_AMP_GAIN_MUTE: + if (payload & HDA_CMD_GET_AMP_GAIN_MUTE_LEFT) { + res = st->left_gain | st->left_mute; + DPRINTF("GET_AMP_GAIN_MUTE_LEFT: 0x%x\n", res); + } else { + res = st->right_gain | st->right_mute; + DPRINTF("GET_AMP_GAIN_MUTE_RIGHT: 0x%x\n", res); + } + break; + case HDA_CMD_VERB_SET_AMP_GAIN_MUTE: + mute = payload & HDA_CODEC_SET_AMP_GAIN_MUTE_MUTE; + gain = payload & HDA_CODEC_SET_AMP_GAIN_MUTE_GAIN_MASK; + + if (payload & HDA_CMD_SET_AMP_GAIN_MUTE_LEFT) { + st->left_mute = mute; + st->left_gain = gain; + DPRINTF("SET_AMP_GAIN_MUTE_LEFT: \ + mute: 0x%x gain: 0x%x\n", mute, gain); + } + + if (payload & HDA_CMD_SET_AMP_GAIN_MUTE_RIGHT) { + st->right_mute = mute; + st->right_gain = gain; + DPRINTF("SET_AMP_GAIN_MUTE_RIGHT: \ + mute: 0x%x gain: 0x%x\n", mute, gain); + } + break; + case HDA_CMD_VERB_GET_CONV_STREAM_CHAN: + res = (st->stream << 4) | st->channel; + break; + case HDA_CMD_VERB_SET_CONV_STREAM_CHAN: + st->channel = payload & 0x0f; + st->stream = (payload >> 4) & 0x0f; + DPRINTF("st->channel: 0x%x st->stream: 0x%x\n", + st->channel, st->stream); + if (!st->stream) + hda_audio_ctxt_stop(&st->actx); + break; + default: + DPRINTF("Unknown VERB: 0x%x\n", verb); + break; + } + + return (res); +} + +struct hda_codec_class hda_codec = { + .name = "hda_codec", + .init = hda_codec_init, + .reset = hda_codec_reset, + .command = hda_codec_command, + .notify = hda_codec_notify, +}; + +HDA_EMUL_SET(hda_codec); + + +/* + * HDA Audio Context module function definitions + */ + +static void * +hda_audio_ctxt_thr(void *arg) +{ + struct hda_audio_ctxt *actx = arg; + + DPRINTF("Start Thread: %s\n", actx->name); + + pthread_mutex_lock(&actx->mtx); + while (1) { + while (!actx->run) + pthread_cond_wait(&actx->cond, &actx->mtx); + + actx->do_transfer(actx->priv); + } + pthread_mutex_unlock(&actx->mtx); + + pthread_exit(NULL); + return (NULL); +} + +static int +hda_audio_ctxt_init(struct hda_audio_ctxt *actx, const char *tname, + transfer_func_t do_transfer, setup_func_t do_setup, void *priv) +{ + int err; + + assert(actx); + assert(tname); + assert(do_transfer); + assert(do_setup); + assert(priv); + + memset(actx, 0, sizeof(*actx)); + + actx->run = 0; + actx->do_transfer = do_transfer; + actx->do_setup = do_setup; + actx->priv = priv; + if (strlen(tname) < sizeof(actx->name)) + memcpy(actx->name, tname, strlen(tname) + 1); + else + strcpy(actx->name, "unknown"); + + err = pthread_mutex_init(&actx->mtx, NULL); + assert(!err); + + err = pthread_cond_init(&actx->cond, NULL); + assert(!err); + + err = pthread_create(&actx->tid, NULL, hda_audio_ctxt_thr, actx); + assert(!err); + + pthread_set_name_np(actx->tid, tname); + + actx->started = 1; + + return (0); +} + +static int +hda_audio_ctxt_start(struct hda_audio_ctxt *actx) +{ + int err = 0; + + assert(actx); + assert(actx->started); + + /* The stream is supposed to be stopped */ + if (actx->run) + return (-1); + + pthread_mutex_lock(&actx->mtx); + err = (* actx->do_setup)(actx->priv); + if (!err) { + actx->run = 1; + pthread_cond_signal(&actx->cond); + } + pthread_mutex_unlock(&actx->mtx); + + return (err); +} + +static int +hda_audio_ctxt_stop(struct hda_audio_ctxt *actx) +{ + actx->run = 0; + return (0); +} diff --git a/usr.sbin/bhyve/hda_reg.h b/usr.sbin/bhyve/hda_reg.h new file mode 100644 index 000000000000..b3034bf9f417 --- /dev/null +++ b/usr.sbin/bhyve/hda_reg.h @@ -0,0 +1,1369 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2006 Stephane E. Potvin <sepotvin@videotron.ca> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _HDA_REG_H_ +#define _HDA_REG_H_ + +/**************************************************************************** + * HDA Device Verbs + ****************************************************************************/ + +/* HDA Command */ +#define HDA_CMD_VERB_MASK 0x000fffff +#define HDA_CMD_VERB_SHIFT 0 +#define HDA_CMD_NID_MASK 0x0ff00000 +#define HDA_CMD_NID_SHIFT 20 +#define HDA_CMD_CAD_MASK 0xf0000000 +#define HDA_CMD_CAD_SHIFT 28 + +#define HDA_CMD_VERB_4BIT_SHIFT 16 +#define HDA_CMD_VERB_12BIT_SHIFT 8 + +#define HDA_CMD_VERB_4BIT(verb, payload) \ + (((verb) << HDA_CMD_VERB_4BIT_SHIFT) | (payload)) +#define HDA_CMD_4BIT(cad, nid, verb, payload) \ + (((cad) << HDA_CMD_CAD_SHIFT) | \ + ((nid) << HDA_CMD_NID_SHIFT) | \ + (HDA_CMD_VERB_4BIT((verb), (payload)))) + +#define HDA_CMD_VERB_12BIT(verb, payload) \ + (((verb) << HDA_CMD_VERB_12BIT_SHIFT) | (payload)) +#define HDA_CMD_12BIT(cad, nid, verb, payload) \ + (((cad) << HDA_CMD_CAD_SHIFT) | \ + ((nid) << HDA_CMD_NID_SHIFT) | \ + (HDA_CMD_VERB_12BIT((verb), (payload)))) + +/* Get Parameter */ +#define HDA_CMD_VERB_GET_PARAMETER 0xf00 + +#define HDA_CMD_GET_PARAMETER(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_PARAMETER, (payload))) + +/* Connection Select Control */ +#define HDA_CMD_VERB_GET_CONN_SELECT_CONTROL 0xf01 +#define HDA_CMD_VERB_SET_CONN_SELECT_CONTROL 0x701 + +#define HDA_CMD_GET_CONN_SELECT_CONTROL(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_CONN_SELECT_CONTROL, 0x0)) +#define HDA_CMD_SET_CONNECTION_SELECT_CONTROL(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_CONN_SELECT_CONTROL, (payload))) + +/* Connection List Entry */ +#define HDA_CMD_VERB_GET_CONN_LIST_ENTRY 0xf02 + +#define HDA_CMD_GET_CONN_LIST_ENTRY(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_CONN_LIST_ENTRY, (payload))) + +#define HDA_CMD_GET_CONN_LIST_ENTRY_SIZE_SHORT 1 +#define HDA_CMD_GET_CONN_LIST_ENTRY_SIZE_LONG 2 + +/* Processing State */ +#define HDA_CMD_VERB_GET_PROCESSING_STATE 0xf03 +#define HDA_CMD_VERB_SET_PROCESSING_STATE 0x703 + +#define HDA_CMD_GET_PROCESSING_STATE(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_PROCESSING_STATE, 0x0)) +#define HDA_CMD_SET_PROCESSING_STATE(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_PROCESSING_STATE, (payload))) + +#define HDA_CMD_GET_PROCESSING_STATE_STATE_OFF 0x00 +#define HDA_CMD_GET_PROCESSING_STATE_STATE_ON 0x01 +#define HDA_CMD_GET_PROCESSING_STATE_STATE_BENIGN 0x02 + +/* Coefficient Index */ +#define HDA_CMD_VERB_GET_COEFF_INDEX 0xd +#define HDA_CMD_VERB_SET_COEFF_INDEX 0x5 + +#define HDA_CMD_GET_COEFF_INDEX(cad, nid) \ + (HDA_CMD_4BIT((cad), (nid), \ + HDA_CMD_VERB_GET_COEFF_INDEX, 0x0)) +#define HDA_CMD_SET_COEFF_INDEX(cad, nid, payload) \ + (HDA_CMD_4BIT((cad), (nid), \ + HDA_CMD_VERB_SET_COEFF_INDEX, (payload))) + +/* Processing Coefficient */ +#define HDA_CMD_VERB_GET_PROCESSING_COEFF 0xc +#define HDA_CMD_VERB_SET_PROCESSING_COEFF 0x4 + +#define HDA_CMD_GET_PROCESSING_COEFF(cad, nid) \ + (HDA_CMD_4BIT((cad), (nid), \ + HDA_CMD_VERB_GET_PROCESSING_COEFF, 0x0)) +#define HDA_CMD_SET_PROCESSING_COEFF(cad, nid, payload) \ + (HDA_CMD_4BIT((cad), (nid), \ + HDA_CMD_VERB_SET_PROCESSING_COEFF, (payload))) + +/* Amplifier Gain/Mute */ +#define HDA_CMD_VERB_GET_AMP_GAIN_MUTE 0xb +#define HDA_CMD_VERB_SET_AMP_GAIN_MUTE 0x3 + +#define HDA_CMD_GET_AMP_GAIN_MUTE(cad, nid, payload) \ + (HDA_CMD_4BIT((cad), (nid), \ + HDA_CMD_VERB_GET_AMP_GAIN_MUTE, (payload))) +#define HDA_CMD_SET_AMP_GAIN_MUTE(cad, nid, payload) \ + (HDA_CMD_4BIT((cad), (nid), \ + HDA_CMD_VERB_SET_AMP_GAIN_MUTE, (payload))) + +#define HDA_CMD_GET_AMP_GAIN_MUTE_INPUT 0x0000 +#define HDA_CMD_GET_AMP_GAIN_MUTE_OUTPUT 0x8000 +#define HDA_CMD_GET_AMP_GAIN_MUTE_RIGHT 0x0000 +#define HDA_CMD_GET_AMP_GAIN_MUTE_LEFT 0x2000 + +#define HDA_CMD_GET_AMP_GAIN_MUTE_MUTE_MASK 0x00000008 +#define HDA_CMD_GET_AMP_GAIN_MUTE_MUTE_SHIFT 7 +#define HDA_CMD_GET_AMP_GAIN_MUTE_GAIN_MASK 0x00000007 +#define HDA_CMD_GET_AMP_GAIN_MUTE_GAIN_SHIFT 0 + +#define HDA_CMD_GET_AMP_GAIN_MUTE_MUTE(rsp) \ + (((rsp) & HDA_CMD_GET_AMP_GAIN_MUTE_MUTE_MASK) >> \ + HDA_CMD_GET_AMP_GAIN_MUTE_MUTE_SHIFT) +#define HDA_CMD_GET_AMP_GAIN_MUTE_GAIN(rsp) \ + (((rsp) & HDA_CMD_GET_AMP_GAIN_MUTE_GAIN_MASK) >> \ + HDA_CMD_GET_AMP_GAIN_MUTE_GAIN_SHIFT) + +#define HDA_CMD_SET_AMP_GAIN_MUTE_OUTPUT 0x8000 +#define HDA_CMD_SET_AMP_GAIN_MUTE_INPUT 0x4000 +#define HDA_CMD_SET_AMP_GAIN_MUTE_LEFT 0x2000 +#define HDA_CMD_SET_AMP_GAIN_MUTE_RIGHT 0x1000 +#define HDA_CMD_SET_AMP_GAIN_MUTE_INDEX_MASK 0x0f00 +#define HDA_CMD_SET_AMP_GAIN_MUTE_INDEX_SHIFT 8 +#define HDA_CMD_SET_AMP_GAIN_MUTE_MUTE 0x0080 +#define HDA_CMD_SET_AMP_GAIN_MUTE_GAIN_MASK 0x0007 +#define HDA_CMD_SET_AMP_GAIN_MUTE_GAIN_SHIFT 0 + +#define HDA_CMD_SET_AMP_GAIN_MUTE_INDEX(index) \ + (((index) << HDA_CMD_SET_AMP_GAIN_MUTE_INDEX_SHIFT) & \ + HDA_CMD_SET_AMP_GAIN_MUTE_INDEX_MASK) +#define HDA_CMD_SET_AMP_GAIN_MUTE_GAIN(index) \ + (((index) << HDA_CMD_SET_AMP_GAIN_MUTE_GAIN_SHIFT) & \ + HDA_CMD_SET_AMP_GAIN_MUTE_GAIN_MASK) + +/* Converter format */ +#define HDA_CMD_VERB_GET_CONV_FMT 0xa +#define HDA_CMD_VERB_SET_CONV_FMT 0x2 + +#define HDA_CMD_GET_CONV_FMT(cad, nid) \ + (HDA_CMD_4BIT((cad), (nid), \ + HDA_CMD_VERB_GET_CONV_FMT, 0x0)) +#define HDA_CMD_SET_CONV_FMT(cad, nid, payload) \ + (HDA_CMD_4BIT((cad), (nid), \ + HDA_CMD_VERB_SET_CONV_FMT, (payload))) + +/* Digital Converter Control */ +#define HDA_CMD_VERB_GET_DIGITAL_CONV_FMT1 0xf0d +#define HDA_CMD_VERB_GET_DIGITAL_CONV_FMT2 0xf0e +#define HDA_CMD_VERB_SET_DIGITAL_CONV_FMT1 0x70d +#define HDA_CMD_VERB_SET_DIGITAL_CONV_FMT2 0x70e + +#define HDA_CMD_GET_DIGITAL_CONV_FMT(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_DIGITAL_CONV_FMT1, 0x0)) +#define HDA_CMD_SET_DIGITAL_CONV_FMT1(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_DIGITAL_CONV_FMT1, (payload))) +#define HDA_CMD_SET_DIGITAL_CONV_FMT2(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_DIGITAL_CONV_FMT2, (payload))) + +#define HDA_CMD_GET_DIGITAL_CONV_FMT_CC_MASK 0x7f00 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_CC_SHIFT 8 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_L_MASK 0x0080 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_L_SHIFT 7 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_PRO_MASK 0x0040 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_PRO_SHIFT 6 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_NAUDIO_MASK 0x0020 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_NAUDIO_SHIFT 5 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_COPY_MASK 0x0010 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_COPY_SHIFT 4 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_PRE_MASK 0x0008 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_PRE_SHIFT 3 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_VCFG_MASK 0x0004 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_VCFG_SHIFT 2 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_V_MASK 0x0002 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_V_SHIFT 1 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_DIGEN_MASK 0x0001 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_DIGEN_SHIFT 0 + +#define HDA_CMD_GET_DIGITAL_CONV_FMT_CC(rsp) \ + (((rsp) & HDA_CMD_GET_DIGITAL_CONV_FMT_CC_MASK) >> \ + HDA_CMD_GET_DIGITAL_CONV_FMT_CC_SHIFT) +#define HDA_CMD_GET_DIGITAL_CONV_FMT_L(rsp) \ + (((rsp) & HDA_CMD_GET_DIGITAL_CONV_FMT_L_MASK) >> \ + HDA_CMD_GET_DIGITAL_CONV_FMT_L_SHIFT) +#define HDA_CMD_GET_DIGITAL_CONV_FMT_PRO(rsp) \ + (((rsp) & HDA_CMD_GET_DIGITAL_CONV_FMT_PRO_MASK) >> \ + HDA_CMD_GET_DIGITAL_CONV_FMT_PRO_SHIFT) +#define HDA_CMD_GET_DIGITAL_CONV_FMT_NAUDIO(rsp) \ + (((rsp) & HDA_CMD_GET_DIGITAL_CONV_FMT_NAUDIO_MASK) >> \ + HDA_CMD_GET_DIGITAL_CONV_FMT_NAUDIO_SHIFT) +#define HDA_CMD_GET_DIGITAL_CONV_FMT_COPY(rsp) \ + (((rsp) & HDA_CMD_GET_DIGITAL_CONV_FMT_COPY_MASK) >> \ + HDA_CMD_GET_DIGITAL_CONV_FMT_COPY_SHIFT) +#define HDA_CMD_GET_DIGITAL_CONV_FMT_PRE(rsp) \ + (((rsp) & HDA_CMD_GET_DIGITAL_CONV_FMT_PRE_MASK) >> \ + HDA_CMD_GET_DIGITAL_CONV_FMT_PRE_SHIFT) +#define HDA_CMD_GET_DIGITAL_CONV_FMT_VCFG(rsp) \ + (((rsp) & HDA_CMD_GET_DIGITAL_CONV_FMT_VCFG_MASK) >> \ + HDA_CMD_GET_DIGITAL_CONV_FMT_VCFG_SHIFT) +#define HDA_CMD_GET_DIGITAL_CONV_FMT_V(rsp) \ + (((rsp) & HDA_CMD_GET_DIGITAL_CONV_FMT_V_MASK) >> \ + HDA_CMD_GET_DIGITAL_CONV_FMT_V_SHIFT) +#define HDA_CMD_GET_DIGITAL_CONV_FMT_DIGEN(rsp) \ + (((rsp) & HDA_CMD_GET_DIGITAL_CONV_FMT_DIGEN_MASK) >> \ + HDA_CMD_GET_DIGITAL_CONV_FMT_DIGEN_SHIFT) + +#define HDA_CMD_SET_DIGITAL_CONV_FMT1_L 0x80 +#define HDA_CMD_SET_DIGITAL_CONV_FMT1_PRO 0x40 +#define HDA_CMD_SET_DIGITAL_CONV_FMT1_NAUDIO 0x20 +#define HDA_CMD_SET_DIGITAL_CONV_FMT1_COPY 0x10 +#define HDA_CMD_SET_DIGITAL_CONV_FMT1_PRE 0x08 +#define HDA_CMD_SET_DIGITAL_CONV_FMT1_VCFG 0x04 +#define HDA_CMD_SET_DIGITAL_CONV_FMT1_V 0x02 +#define HDA_CMD_SET_DIGITAL_CONV_FMT1_DIGEN 0x01 + +/* Power State */ +#define HDA_CMD_VERB_GET_POWER_STATE 0xf05 +#define HDA_CMD_VERB_SET_POWER_STATE 0x705 + +#define HDA_CMD_GET_POWER_STATE(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_POWER_STATE, 0x0)) +#define HDA_CMD_SET_POWER_STATE(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_POWER_STATE, (payload))) + +#define HDA_CMD_POWER_STATE_D0 0x00 +#define HDA_CMD_POWER_STATE_D1 0x01 +#define HDA_CMD_POWER_STATE_D2 0x02 +#define HDA_CMD_POWER_STATE_D3 0x03 + +#define HDA_CMD_POWER_STATE_ACT_MASK 0x000000f0 +#define HDA_CMD_POWER_STATE_ACT_SHIFT 4 +#define HDA_CMD_POWER_STATE_SET_MASK 0x0000000f +#define HDA_CMD_POWER_STATE_SET_SHIFT 0 + +#define HDA_CMD_GET_POWER_STATE_ACT(rsp) \ + (((rsp) & HDA_CMD_POWER_STATE_ACT_MASK) >> \ + HDA_CMD_POWER_STATE_ACT_SHIFT) +#define HDA_CMD_GET_POWER_STATE_SET(rsp) \ + (((rsp) & HDA_CMD_POWER_STATE_SET_MASK) >> \ + HDA_CMD_POWER_STATE_SET_SHIFT) + +#define HDA_CMD_SET_POWER_STATE_ACT(ps) \ + (((ps) << HDA_CMD_POWER_STATE_ACT_SHIFT) & \ + HDA_CMD_POWER_STATE_ACT_MASK) +#define HDA_CMD_SET_POWER_STATE_SET(ps) \ + (((ps) << HDA_CMD_POWER_STATE_SET_SHIFT) & \ + HDA_CMD_POWER_STATE_ACT_MASK) + +/* Converter Stream, Channel */ +#define HDA_CMD_VERB_GET_CONV_STREAM_CHAN 0xf06 +#define HDA_CMD_VERB_SET_CONV_STREAM_CHAN 0x706 + +#define HDA_CMD_GET_CONV_STREAM_CHAN(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_CONV_STREAM_CHAN, 0x0)) +#define HDA_CMD_SET_CONV_STREAM_CHAN(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_CONV_STREAM_CHAN, (payload))) + +#define HDA_CMD_CONV_STREAM_CHAN_STREAM_MASK 0x000000f0 +#define HDA_CMD_CONV_STREAM_CHAN_STREAM_SHIFT 4 +#define HDA_CMD_CONV_STREAM_CHAN_CHAN_MASK 0x0000000f +#define HDA_CMD_CONV_STREAM_CHAN_CHAN_SHIFT 0 + +#define HDA_CMD_GET_CONV_STREAM_CHAN_STREAM(rsp) \ + (((rsp) & HDA_CMD_CONV_STREAM_CHAN_STREAM_MASK) >> \ + HDA_CMD_CONV_STREAM_CHAN_STREAM_SHIFT) +#define HDA_CMD_GET_CONV_STREAM_CHAN_CHAN(rsp) \ + (((rsp) & HDA_CMD_CONV_STREAM_CHAN_CHAN_MASK) >> \ + HDA_CMD_CONV_STREAM_CHAN_CHAN_SHIFT) + +#define HDA_CMD_SET_CONV_STREAM_CHAN_STREAM(param) \ + (((param) << HDA_CMD_CONV_STREAM_CHAN_STREAM_SHIFT) & \ + HDA_CMD_CONV_STREAM_CHAN_STREAM_MASK) +#define HDA_CMD_SET_CONV_STREAM_CHAN_CHAN(param) \ + (((param) << HDA_CMD_CONV_STREAM_CHAN_CHAN_SHIFT) & \ + HDA_CMD_CONV_STREAM_CHAN_CHAN_MASK) + +/* Input Converter SDI Select */ +#define HDA_CMD_VERB_GET_INPUT_CONVERTER_SDI_SELECT 0xf04 +#define HDA_CMD_VERB_SET_INPUT_CONVERTER_SDI_SELECT 0x704 + +#define HDA_CMD_GET_INPUT_CONVERTER_SDI_SELECT(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_INPUT_CONVERTER_SDI_SELECT, 0x0)) +#define HDA_CMD_SET_INPUT_CONVERTER_SDI_SELECT(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_INPUT_CONVERTER_SDI_SELECT, (payload))) + +/* Pin Widget Control */ +#define HDA_CMD_VERB_GET_PIN_WIDGET_CTRL 0xf07 +#define HDA_CMD_VERB_SET_PIN_WIDGET_CTRL 0x707 + +#define HDA_CMD_GET_PIN_WIDGET_CTRL(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_PIN_WIDGET_CTRL, 0x0)) +#define HDA_CMD_SET_PIN_WIDGET_CTRL(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_PIN_WIDGET_CTRL, (payload))) + +#define HDA_CMD_GET_PIN_WIDGET_CTRL_HPHN_ENABLE_MASK 0x00000080 +#define HDA_CMD_GET_PIN_WIDGET_CTRL_HPHN_ENABLE_SHIFT 7 +#define HDA_CMD_GET_PIN_WIDGET_CTRL_OUT_ENABLE_MASK 0x00000040 +#define HDA_CMD_GET_PIN_WIDGET_CTRL_OUT_ENABLE_SHIFT 6 +#define HDA_CMD_GET_PIN_WIDGET_CTRL_IN_ENABLE_MASK 0x00000020 +#define HDA_CMD_GET_PIN_WIDGET_CTRL_IN_ENABLE_SHIFT 5 +#define HDA_CMD_GET_PIN_WIDGET_CTRL_VREF_ENABLE_MASK 0x00000007 +#define HDA_CMD_GET_PIN_WIDGET_CTRL_VREF_ENABLE_SHIFT 0 + +#define HDA_CMD_GET_PIN_WIDGET_CTRL_HPHN_ENABLE(rsp) \ + (((rsp) & HDA_CMD_GET_PIN_WIDGET_CTRL_HPHN_ENABLE_MASK) >> \ + HDA_CMD_GET_PIN_WIDGET_CTRL_HPHN_ENABLE_SHIFT) +#define HDA_CMD_GET_PIN_WIDGET_CTRL_OUT_ENABLE(rsp) \ + (((rsp) & HDA_CMD_GET_PIN_WIDGET_CTRL_OUT_ENABLE_MASK) >> \ + HDA_GET_CMD_PIN_WIDGET_CTRL_OUT_ENABLE_SHIFT) +#define HDA_CMD_GET_PIN_WIDGET_CTRL_IN_ENABLE(rsp) \ + (((rsp) & HDA_CMD_GET_PIN_WIDGET_CTRL_IN_ENABLE_MASK) >> \ + HDA_CMD_GET_PIN_WIDGET_CTRL_IN_ENABLE_SHIFT) +#define HDA_CMD_GET_PIN_WIDGET_CTRL_VREF_ENABLE(rsp) \ + (((rsp) & HDA_CMD_GET_PIN_WIDGET_CTRL_VREF_ENABLE_MASK) >> \ + HDA_CMD_GET_PIN_WIDGET_CTRL_VREF_ENABLE_SHIFT) + +#define HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE 0x80 +#define HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE 0x40 +#define HDA_CMD_SET_PIN_WIDGET_CTRL_IN_ENABLE 0x20 +#define HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE_MASK 0x07 +#define HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE_SHIFT 0 + +#define HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE(param) \ + (((param) << HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE_SHIFT) & \ + HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE_MASK) + +#define HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_HIZ 0 +#define HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_50 1 +#define HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_GROUND 2 +#define HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_80 4 +#define HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_100 5 + +/* Unsolicited Response */ +#define HDA_CMD_VERB_GET_UNSOLICITED_RESPONSE 0xf08 +#define HDA_CMD_VERB_SET_UNSOLICITED_RESPONSE 0x708 + +#define HDA_CMD_GET_UNSOLICITED_RESPONSE(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_UNSOLICITED_RESPONSE, 0x0)) +#define HDA_CMD_SET_UNSOLICITED_RESPONSE(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_UNSOLICITED_RESPONSE, (payload))) + +#define HDA_CMD_GET_UNSOLICITED_RESPONSE_ENABLE_MASK 0x00000080 +#define HDA_CMD_GET_UNSOLICITED_RESPONSE_ENABLE_SHIFT 7 +#define HDA_CMD_GET_UNSOLICITED_RESPONSE_TAG_MASK 0x0000001f +#define HDA_CMD_GET_UNSOLICITED_RESPONSE_TAG_SHIFT 0 + +#define HDA_CMD_GET_UNSOLICITED_RESPONSE_ENABLE(rsp) \ + (((rsp) & HDA_CMD_GET_UNSOLICITED_RESPONSE_ENABLE_MASK) >> \ + HDA_CMD_GET_UNSOLICITED_RESPONSE_ENABLE_SHIFT) +#define HDA_CMD_GET_UNSOLICITED_RESPONSE_TAG(rsp) \ + (((rsp) & HDA_CMD_GET_UNSOLICITED_RESPONSE_TAG_MASK) >> \ + HDA_CMD_GET_UNSOLICITED_RESPONSE_TAG_SHIFT) + +#define HDA_CMD_SET_UNSOLICITED_RESPONSE_ENABLE 0x80 +#define HDA_CMD_SET_UNSOLICITED_RESPONSE_TAG_MASK 0x3f +#define HDA_CMD_SET_UNSOLICITED_RESPONSE_TAG_SHIFT 0 + +#define HDA_CMD_SET_UNSOLICITED_RESPONSE_TAG(param) \ + (((param) << HDA_CMD_SET_UNSOLICITED_RESPONSE_TAG_SHIFT) & \ + HDA_CMD_SET_UNSOLICITED_RESPONSE_TAG_MASK) + +/* Pin Sense */ +#define HDA_CMD_VERB_GET_PIN_SENSE 0xf09 +#define HDA_CMD_VERB_SET_PIN_SENSE 0x709 + +#define HDA_CMD_GET_PIN_SENSE(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_PIN_SENSE, 0x0)) +#define HDA_CMD_SET_PIN_SENSE(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_PIN_SENSE, (payload))) + +#define HDA_CMD_GET_PIN_SENSE_PRESENCE_DETECT 0x80000000 +#define HDA_CMD_GET_PIN_SENSE_ELD_VALID 0x40000000 +#define HDA_CMD_GET_PIN_SENSE_IMP_SENSE_MASK 0x7fffffff +#define HDA_CMD_GET_PIN_SENSE_IMP_SENSE_SHIFT 0 + +#define HDA_CMD_GET_PIN_SENSE_IMP_SENSE(rsp) \ + (((rsp) & HDA_CMD_GET_PIN_SENSE_IMP_SENSE_MASK) >> \ + HDA_CMD_GET_PIN_SENSE_IMP_SENSE_SHIFT) + +#define HDA_CMD_GET_PIN_SENSE_IMP_SENSE_INVALID 0x7fffffff + +#define HDA_CMD_SET_PIN_SENSE_LEFT_CHANNEL 0x00 +#define HDA_CMD_SET_PIN_SENSE_RIGHT_CHANNEL 0x01 + +/* EAPD/BTL Enable */ +#define HDA_CMD_VERB_GET_EAPD_BTL_ENABLE 0xf0c +#define HDA_CMD_VERB_SET_EAPD_BTL_ENABLE 0x70c + +#define HDA_CMD_GET_EAPD_BTL_ENABLE(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_EAPD_BTL_ENABLE, 0x0)) +#define HDA_CMD_SET_EAPD_BTL_ENABLE(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_EAPD_BTL_ENABLE, (payload))) + +#define HDA_CMD_GET_EAPD_BTL_ENABLE_LR_SWAP_MASK 0x00000004 +#define HDA_CMD_GET_EAPD_BTL_ENABLE_LR_SWAP_SHIFT 2 +#define HDA_CMD_GET_EAPD_BTL_ENABLE_EAPD_MASK 0x00000002 +#define HDA_CMD_GET_EAPD_BTL_ENABLE_EAPD_SHIFT 1 +#define HDA_CMD_GET_EAPD_BTL_ENABLE_BTL_MASK 0x00000001 +#define HDA_CMD_GET_EAPD_BTL_ENABLE_BTL_SHIFT 0 + +#define HDA_CMD_GET_EAPD_BTL_ENABLE_LR_SWAP(rsp) \ + (((rsp) & HDA_CMD_GET_EAPD_BTL_ENABLE_LR_SWAP_MASK) >> \ + HDA_CMD_GET_EAPD_BTL_ENABLE_LR_SWAP_SHIFT) +#define HDA_CMD_GET_EAPD_BTL_ENABLE_EAPD(rsp) \ + (((rsp) & HDA_CMD_GET_EAPD_BTL_ENABLE_EAPD_MASK) >> \ + HDA_CMD_GET_EAPD_BTL_ENABLE_EAPD_SHIFT) +#define HDA_CMD_GET_EAPD_BTL_ENABLE_BTL(rsp) \ + (((rsp) & HDA_CMD_GET_EAPD_BTL_ENABLE_BTL_MASK) >> \ + HDA_CMD_GET_EAPD_BTL_ENABLE_BTL_SHIFT) + +#define HDA_CMD_SET_EAPD_BTL_ENABLE_LR_SWAP 0x04 +#define HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD 0x02 +#define HDA_CMD_SET_EAPD_BTL_ENABLE_BTL 0x01 + +/* GPI Data */ +#define HDA_CMD_VERB_GET_GPI_DATA 0xf10 +#define HDA_CMD_VERB_SET_GPI_DATA 0x710 + +#define HDA_CMD_GET_GPI_DATA(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_GPI_DATA, 0x0)) +#define HDA_CMD_SET_GPI_DATA(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_GPI_DATA, (payload))) + +/* GPI Wake Enable Mask */ +#define HDA_CMD_VERB_GET_GPI_WAKE_ENABLE_MASK 0xf11 +#define HDA_CMD_VERB_SET_GPI_WAKE_ENABLE_MASK 0x711 + +#define HDA_CMD_GET_GPI_WAKE_ENABLE_MASK(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_GPI_WAKE_ENABLE_MASK, 0x0)) +#define HDA_CMD_SET_GPI_WAKE_ENABLE_MASK(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_GPI_WAKE_ENABLE_MASK, (payload))) + +/* GPI Unsolicited Enable Mask */ +#define HDA_CMD_VERB_GET_GPI_UNSOLICITED_ENABLE_MASK 0xf12 +#define HDA_CMD_VERB_SET_GPI_UNSOLICITED_ENABLE_MASK 0x712 + +#define HDA_CMD_GET_GPI_UNSOLICITED_ENABLE_MASK(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_GPI_UNSOLICITED_ENABLE_MASK, 0x0)) +#define HDA_CMD_SET_GPI_UNSOLICITED_ENABLE_MASK(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_GPI_UNSOLICITED_ENABLE_MASK, (payload))) + +/* GPI Sticky Mask */ +#define HDA_CMD_VERB_GET_GPI_STICKY_MASK 0xf13 +#define HDA_CMD_VERB_SET_GPI_STICKY_MASK 0x713 + +#define HDA_CMD_GET_GPI_STICKY_MASK(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_GPI_STICKY_MASK, 0x0)) +#define HDA_CMD_SET_GPI_STICKY_MASK(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_GPI_STICKY_MASK, (payload))) + +/* GPO Data */ +#define HDA_CMD_VERB_GET_GPO_DATA 0xf14 +#define HDA_CMD_VERB_SET_GPO_DATA 0x714 + +#define HDA_CMD_GET_GPO_DATA(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_GPO_DATA, 0x0)) +#define HDA_CMD_SET_GPO_DATA(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_GPO_DATA, (payload))) + +/* GPIO Data */ +#define HDA_CMD_VERB_GET_GPIO_DATA 0xf15 +#define HDA_CMD_VERB_SET_GPIO_DATA 0x715 + +#define HDA_CMD_GET_GPIO_DATA(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_GPIO_DATA, 0x0)) +#define HDA_CMD_SET_GPIO_DATA(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_GPIO_DATA, (payload))) + +/* GPIO Enable Mask */ +#define HDA_CMD_VERB_GET_GPIO_ENABLE_MASK 0xf16 +#define HDA_CMD_VERB_SET_GPIO_ENABLE_MASK 0x716 + +#define HDA_CMD_GET_GPIO_ENABLE_MASK(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_GPIO_ENABLE_MASK, 0x0)) +#define HDA_CMD_SET_GPIO_ENABLE_MASK(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_GPIO_ENABLE_MASK, (payload))) + +/* GPIO Direction */ +#define HDA_CMD_VERB_GET_GPIO_DIRECTION 0xf17 +#define HDA_CMD_VERB_SET_GPIO_DIRECTION 0x717 + +#define HDA_CMD_GET_GPIO_DIRECTION(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_GPIO_DIRECTION, 0x0)) +#define HDA_CMD_SET_GPIO_DIRECTION(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_GPIO_DIRECTION, (payload))) + +/* GPIO Wake Enable Mask */ +#define HDA_CMD_VERB_GET_GPIO_WAKE_ENABLE_MASK 0xf18 +#define HDA_CMD_VERB_SET_GPIO_WAKE_ENABLE_MASK 0x718 + +#define HDA_CMD_GET_GPIO_WAKE_ENABLE_MASK(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_GPIO_WAKE_ENABLE_MASK, 0x0)) +#define HDA_CMD_SET_GPIO_WAKE_ENABLE_MASK(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_GPIO_WAKE_ENABLE_MASK, (payload))) + +/* GPIO Unsolicited Enable Mask */ +#define HDA_CMD_VERB_GET_GPIO_UNSOLICITED_ENABLE_MASK 0xf19 +#define HDA_CMD_VERB_SET_GPIO_UNSOLICITED_ENABLE_MASK 0x719 + +#define HDA_CMD_GET_GPIO_UNSOLICITED_ENABLE_MASK(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_GPIO_UNSOLICITED_ENABLE_MASK, 0x0)) +#define HDA_CMD_SET_GPIO_UNSOLICITED_ENABLE_MASK(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_GPIO_UNSOLICITED_ENABLE_MASK, (payload))) + +/* GPIO_STICKY_MASK */ +#define HDA_CMD_VERB_GET_GPIO_STICKY_MASK 0xf1a +#define HDA_CMD_VERB_SET_GPIO_STICKY_MASK 0x71a + +#define HDA_CMD_GET_GPIO_STICKY_MASK(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_GPIO_STICKY_MASK, 0x0)) +#define HDA_CMD_SET_GPIO_STICKY_MASK(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_GPIO_STICKY_MASK, (payload))) + +/* Beep Generation */ +#define HDA_CMD_VERB_GET_BEEP_GENERATION 0xf0a +#define HDA_CMD_VERB_SET_BEEP_GENERATION 0x70a + +#define HDA_CMD_GET_BEEP_GENERATION(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_BEEP_GENERATION, 0x0)) +#define HDA_CMD_SET_BEEP_GENERATION(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_BEEP_GENERATION, (payload))) + +/* Volume Knob */ +#define HDA_CMD_VERB_GET_VOLUME_KNOB 0xf0f +#define HDA_CMD_VERB_SET_VOLUME_KNOB 0x70f + +#define HDA_CMD_GET_VOLUME_KNOB(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_VOLUME_KNOB, 0x0)) +#define HDA_CMD_SET_VOLUME_KNOB(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_VOLUME_KNOB, (payload))) + +/* Subsystem ID */ +#define HDA_CMD_VERB_GET_SUBSYSTEM_ID 0xf20 +#define HDA_CMD_VERB_SET_SUSBYSTEM_ID1 0x720 +#define HDA_CMD_VERB_SET_SUBSYSTEM_ID2 0x721 +#define HDA_CMD_VERB_SET_SUBSYSTEM_ID3 0x722 +#define HDA_CMD_VERB_SET_SUBSYSTEM_ID4 0x723 + +#define HDA_CMD_GET_SUBSYSTEM_ID(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_SUBSYSTEM_ID, 0x0)) +#define HDA_CMD_SET_SUBSYSTEM_ID1(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_SUSBYSTEM_ID1, (payload))) +#define HDA_CMD_SET_SUBSYSTEM_ID2(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_SUSBYSTEM_ID2, (payload))) +#define HDA_CMD_SET_SUBSYSTEM_ID3(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_SUSBYSTEM_ID3, (payload))) +#define HDA_CMD_SET_SUBSYSTEM_ID4(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_SUSBYSTEM_ID4, (payload))) + +/* Configuration Default */ +#define HDA_CMD_VERB_GET_CONFIGURATION_DEFAULT 0xf1c +#define HDA_CMD_VERB_SET_CONFIGURATION_DEFAULT1 0x71c +#define HDA_CMD_VERB_SET_CONFIGURATION_DEFAULT2 0x71d +#define HDA_CMD_VERB_SET_CONFIGURATION_DEFAULT3 0x71e +#define HDA_CMD_VERB_SET_CONFIGURATION_DEFAULT4 0x71f + +#define HDA_CMD_GET_CONFIGURATION_DEFAULT(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_CONFIGURATION_DEFAULT, 0x0)) +#define HDA_CMD_SET_CONFIGURATION_DEFAULT1(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_CONFIGURATION_DEFAULT1, (payload))) +#define HDA_CMD_SET_CONFIGURATION_DEFAULT2(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_CONFIGURATION_DEFAULT2, (payload))) +#define HDA_CMD_SET_CONFIGURATION_DEFAULT3(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_CONFIGURATION_DEFAULT3, (payload))) +#define HDA_CMD_SET_CONFIGURATION_DEFAULT4(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_CONFIGURATION_DEFAULT4, (payload))) + +/* Stripe Control */ +#define HDA_CMD_VERB_GET_STRIPE_CONTROL 0xf24 +#define HDA_CMD_VERB_SET_STRIPE_CONTROL 0x724 + +#define HDA_CMD_GET_STRIPE_CONTROL(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_STRIPE_CONTROL, 0x0)) +#define HDA_CMD_SET_STRIPE_CONTROL(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_STRIPE_CONTROL, (payload))) + +/* Channel Count Control */ +#define HDA_CMD_VERB_GET_CONV_CHAN_COUNT 0xf2d +#define HDA_CMD_VERB_SET_CONV_CHAN_COUNT 0x72d + +#define HDA_CMD_GET_CONV_CHAN_COUNT(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_CONV_CHAN_COUNT, 0x0)) +#define HDA_CMD_SET_CONV_CHAN_COUNT(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_CONV_CHAN_COUNT, (payload))) + +#define HDA_CMD_VERB_GET_HDMI_DIP_SIZE 0xf2e + +#define HDA_CMD_GET_HDMI_DIP_SIZE(cad, nid, arg) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_HDMI_DIP_SIZE, (arg))) + +#define HDA_CMD_VERB_GET_HDMI_ELDD 0xf2f + +#define HDA_CMD_GET_HDMI_ELDD(cad, nid, off) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_HDMI_ELDD, (off))) + +#define HDA_CMD_VERB_GET_HDMI_DIP_INDEX 0xf30 +#define HDA_CMD_VERB_SET_HDMI_DIP_INDEX 0x730 + +#define HDA_CMD_GET_HDMI_DIP_INDEX(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_HDMI_DIP_INDEX, 0x0)) +#define HDA_CMD_SET_HDMI_DIP_INDEX(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_HDMI_DIP_INDEX, (payload))) + +#define HDA_CMD_VERB_GET_HDMI_DIP_DATA 0xf31 +#define HDA_CMD_VERB_SET_HDMI_DIP_DATA 0x731 + +#define HDA_CMD_GET_HDMI_DIP_DATA(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_HDMI_DIP_DATA, 0x0)) +#define HDA_CMD_SET_HDMI_DIP_DATA(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_HDMI_DIP_DATA, (payload))) + +#define HDA_CMD_VERB_GET_HDMI_DIP_XMIT 0xf32 +#define HDA_CMD_VERB_SET_HDMI_DIP_XMIT 0x732 + +#define HDA_CMD_GET_HDMI_DIP_XMIT(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_HDMI_DIP_XMIT, 0x0)) +#define HDA_CMD_SET_HDMI_DIP_XMIT(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_HDMI_DIP_XMIT, (payload))) + +#define HDA_CMD_VERB_GET_HDMI_CP_CTRL 0xf33 +#define HDA_CMD_VERB_SET_HDMI_CP_CTRL 0x733 + +#define HDA_CMD_VERB_GET_HDMI_CHAN_SLOT 0xf34 +#define HDA_CMD_VERB_SET_HDMI_CHAN_SLOT 0x734 + +#define HDA_CMD_GET_HDMI_CHAN_SLOT(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_HDMI_CHAN_SLOT, 0x0)) +#define HDA_CMD_SET_HDMI_CHAN_SLOT(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_HDMI_CHAN_SLOT, (payload))) + +#define HDA_HDMI_CODING_TYPE_REF_STREAM_HEADER 0 +#define HDA_HDMI_CODING_TYPE_LPCM 1 +#define HDA_HDMI_CODING_TYPE_AC3 2 +#define HDA_HDMI_CODING_TYPE_MPEG1 3 +#define HDA_HDMI_CODING_TYPE_MP3 4 +#define HDA_HDMI_CODING_TYPE_MPEG2 5 +#define HDA_HDMI_CODING_TYPE_AACLC 6 +#define HDA_HDMI_CODING_TYPE_DTS 7 +#define HDA_HDMI_CODING_TYPE_ATRAC 8 +#define HDA_HDMI_CODING_TYPE_SACD 9 +#define HDA_HDMI_CODING_TYPE_EAC3 10 +#define HDA_HDMI_CODING_TYPE_DTS_HD 11 +#define HDA_HDMI_CODING_TYPE_MLP 12 +#define HDA_HDMI_CODING_TYPE_DST 13 +#define HDA_HDMI_CODING_TYPE_WMAPRO 14 +#define HDA_HDMI_CODING_TYPE_REF_CTX 15 + +/* Function Reset */ +#define HDA_CMD_VERB_FUNCTION_RESET 0x7ff + +#define HDA_CMD_FUNCTION_RESET(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_FUNCTION_RESET, 0x0)) + + +/**************************************************************************** + * HDA Device Parameters + ****************************************************************************/ + +/* Vendor ID */ +#define HDA_PARAM_VENDOR_ID 0x00 + +#define HDA_PARAM_VENDOR_ID_VENDOR_ID_MASK 0xffff0000 +#define HDA_PARAM_VENDOR_ID_VENDOR_ID_SHIFT 16 +#define HDA_PARAM_VENDOR_ID_DEVICE_ID_MASK 0x0000ffff +#define HDA_PARAM_VENDOR_ID_DEVICE_ID_SHIFT 0 + +#define HDA_PARAM_VENDOR_ID_VENDOR_ID(param) \ + (((param) & HDA_PARAM_VENDOR_ID_VENDOR_ID_MASK) >> \ + HDA_PARAM_VENDOR_ID_VENDOR_ID_SHIFT) +#define HDA_PARAM_VENDOR_ID_DEVICE_ID(param) \ + (((param) & HDA_PARAM_VENDOR_ID_DEVICE_ID_MASK) >> \ + HDA_PARAM_VENDOR_ID_DEVICE_ID_SHIFT) + +/* Revision ID */ +#define HDA_PARAM_REVISION_ID 0x02 + +#define HDA_PARAM_REVISION_ID_MAJREV_MASK 0x00f00000 +#define HDA_PARAM_REVISION_ID_MAJREV_SHIFT 20 +#define HDA_PARAM_REVISION_ID_MINREV_MASK 0x000f0000 +#define HDA_PARAM_REVISION_ID_MINREV_SHIFT 16 +#define HDA_PARAM_REVISION_ID_REVISION_ID_MASK 0x0000ff00 +#define HDA_PARAM_REVISION_ID_REVISION_ID_SHIFT 8 +#define HDA_PARAM_REVISION_ID_STEPPING_ID_MASK 0x000000ff +#define HDA_PARAM_REVISION_ID_STEPPING_ID_SHIFT 0 + +#define HDA_PARAM_REVISION_ID_MAJREV(param) \ + (((param) & HDA_PARAM_REVISION_ID_MAJREV_MASK) >> \ + HDA_PARAM_REVISION_ID_MAJREV_SHIFT) +#define HDA_PARAM_REVISION_ID_MINREV(param) \ + (((param) & HDA_PARAM_REVISION_ID_MINREV_MASK) >> \ + HDA_PARAM_REVISION_ID_MINREV_SHIFT) +#define HDA_PARAM_REVISION_ID_REVISION_ID(param) \ + (((param) & HDA_PARAM_REVISION_ID_REVISION_ID_MASK) >> \ + HDA_PARAM_REVISION_ID_REVISION_ID_SHIFT) +#define HDA_PARAM_REVISION_ID_STEPPING_ID(param) \ + (((param) & HDA_PARAM_REVISION_ID_STEPPING_ID_MASK) >> \ + HDA_PARAM_REVISION_ID_STEPPING_ID_SHIFT) + +/* Subordinate Node Cound */ +#define HDA_PARAM_SUB_NODE_COUNT 0x04 + +#define HDA_PARAM_SUB_NODE_COUNT_START_MASK 0x00ff0000 +#define HDA_PARAM_SUB_NODE_COUNT_START_SHIFT 16 +#define HDA_PARAM_SUB_NODE_COUNT_TOTAL_MASK 0x000000ff +#define HDA_PARAM_SUB_NODE_COUNT_TOTAL_SHIFT 0 + +#define HDA_PARAM_SUB_NODE_COUNT_START(param) \ + (((param) & HDA_PARAM_SUB_NODE_COUNT_START_MASK) >> \ + HDA_PARAM_SUB_NODE_COUNT_START_SHIFT) +#define HDA_PARAM_SUB_NODE_COUNT_TOTAL(param) \ + (((param) & HDA_PARAM_SUB_NODE_COUNT_TOTAL_MASK) >> \ + HDA_PARAM_SUB_NODE_COUNT_TOTAL_SHIFT) + +/* Function Group Type */ +#define HDA_PARAM_FCT_GRP_TYPE 0x05 + +#define HDA_PARAM_FCT_GRP_TYPE_UNSOL_MASK 0x00000100 +#define HDA_PARAM_FCT_GRP_TYPE_UNSOL_SHIFT 8 +#define HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_MASK 0x000000ff +#define HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_SHIFT 0 + +#define HDA_PARAM_FCT_GRP_TYPE_UNSOL(param) \ + (((param) & HDA_PARAM_FCT_GRP_TYPE_UNSOL_MASK) >> \ + HDA_PARAM_FCT_GROUP_TYPE_UNSOL_SHIFT) +#define HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE(param) \ + (((param) & HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_MASK) >> \ + HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_SHIFT) + +#define HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO 0x01 +#define HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_MODEM 0x02 + +/* Audio Function Group Capabilities */ +#define HDA_PARAM_AUDIO_FCT_GRP_CAP 0x08 + +#define HDA_PARAM_AUDIO_FCT_GRP_CAP_BEEP_GEN_MASK 0x00010000 +#define HDA_PARAM_AUDIO_FCT_GRP_CAP_BEEP_GEN_SHIFT 16 +#define HDA_PARAM_AUDIO_FCT_GRP_CAP_INPUT_DELAY_MASK 0x00000f00 +#define HDA_PARAM_AUDIO_FCT_GRP_CAP_INPUT_DELAY_SHIFT 8 +#define HDA_PARAM_AUDIO_FCT_GRP_CAP_OUTPUT_DELAY_MASK 0x0000000f +#define HDA_PARAM_AUDIO_FCT_GRP_CAP_OUTPUT_DELAY_SHIFT 0 + +#define HDA_PARAM_AUDIO_FCT_GRP_CAP_BEEP_GEN(param) \ + (((param) & HDA_PARAM_AUDIO_FCT_GRP_CAP_BEEP_GEN_MASK) >> \ + HDA_PARAM_AUDIO_FCT_GRP_CAP_BEEP_GEN_SHIFT) +#define HDA_PARAM_AUDIO_FCT_GRP_CAP_INPUT_DELAY(param) \ + (((param) & HDA_PARAM_AUDIO_FCT_GRP_CAP_INPUT_DELAY_MASK) >> \ + HDA_PARAM_AUDIO_FCT_GRP_CAP_INPUT_DELAY_SHIFT) +#define HDA_PARAM_AUDIO_FCT_GRP_CAP_OUTPUT_DELAY(param) \ + (((param) & HDA_PARAM_AUDIO_FCT_GRP_CAP_OUTPUT_DELAY_MASK) >> \ + HDA_PARAM_AUDIO_FCT_GRP_CAP_OUTPUT_DELAY_SHIFT) + +/* Audio Widget Capabilities */ +#define HDA_PARAM_AUDIO_WIDGET_CAP 0x09 + +#define HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_MASK 0x00f00000 +#define HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_SHIFT 20 +#define HDA_PARAM_AUDIO_WIDGET_CAP_DELAY_MASK 0x000f0000 +#define HDA_PARAM_AUDIO_WIDGET_CAP_DELAY_SHIFT 16 +#define HDA_PARAM_AUDIO_WIDGET_CAP_CC_EXT_MASK 0x0000e000 +#define HDA_PARAM_AUDIO_WIDGET_CAP_CC_EXT_SHIFT 13 +#define HDA_PARAM_AUDIO_WIDGET_CAP_CP_MASK 0x00001000 +#define HDA_PARAM_AUDIO_WIDGET_CAP_CP_SHIFT 12 +#define HDA_PARAM_AUDIO_WIDGET_CAP_LR_SWAP_MASK 0x00000800 +#define HDA_PARAM_AUDIO_WIDGET_CAP_LR_SWAP_SHIFT 11 +#define HDA_PARAM_AUDIO_WIDGET_CAP_POWER_CTRL_MASK 0x00000400 +#define HDA_PARAM_AUDIO_WIDGET_CAP_POWER_CTRL_SHIFT 10 +#define HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL_MASK 0x00000200 +#define HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL_SHIFT 9 +#define HDA_PARAM_AUDIO_WIDGET_CAP_CONN_LIST_MASK 0x00000100 +#define HDA_PARAM_AUDIO_WIDGET_CAP_CONN_LIST_SHIFT 8 +#define HDA_PARAM_AUDIO_WIDGET_CAP_UNSOL_CAP_MASK 0x00000080 +#define HDA_PARAM_AUDIO_WIDGET_CAP_UNSOL_CAP_SHIFT 7 +#define HDA_PARAM_AUDIO_WIDGET_CAP_PROC_WIDGET_MASK 0x00000040 +#define HDA_PARAM_AUDIO_WIDGET_CAP_PROC_WIDGET_SHIFT 6 +#define HDA_PARAM_AUDIO_WIDGET_CAP_STRIPE_MASK 0x00000020 +#define HDA_PARAM_AUDIO_WIDGET_CAP_STRIPE_SHIFT 5 +#define HDA_PARAM_AUDIO_WIDGET_CAP_FORMAT_OVR_MASK 0x00000010 +#define HDA_PARAM_AUDIO_WIDGET_CAP_FORMAT_OVR_SHIFT 4 +#define HDA_PARAM_AUDIO_WIDGET_CAP_AMP_OVR_MASK 0x00000008 +#define HDA_PARAM_AUDIO_WIDGET_CAP_AMP_OVR_SHIFT 3 +#define HDA_PARAM_AUDIO_WIDGET_CAP_OUT_AMP_MASK 0x00000004 +#define HDA_PARAM_AUDIO_WIDGET_CAP_OUT_AMP_SHIFT 2 +#define HDA_PARAM_AUDIO_WIDGET_CAP_IN_AMP_MASK 0x00000002 +#define HDA_PARAM_AUDIO_WIDGET_CAP_IN_AMP_SHIFT 1 +#define HDA_PARAM_AUDIO_WIDGET_CAP_STEREO_MASK 0x00000001 +#define HDA_PARAM_AUDIO_WIDGET_CAP_STEREO_SHIFT 0 + +#define HDA_PARAM_AUDIO_WIDGET_CAP_TYPE(param) \ + (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_MASK) >> \ + HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_SHIFT) +#define HDA_PARAM_AUDIO_WIDGET_CAP_DELAY(param) \ + (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_DELAY_MASK) >> \ + HDA_PARAM_AUDIO_WIDGET_CAP_DELAY_SHIFT) +#define HDA_PARAM_AUDIO_WIDGET_CAP_CC(param) \ + ((((param) & HDA_PARAM_AUDIO_WIDGET_CAP_CC_EXT_MASK) >> \ + (HDA_PARAM_AUDIO_WIDGET_CAP_CC_EXT_SHIFT - 1)) | \ + (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_STEREO_MASK) >> \ + HDA_PARAM_AUDIO_WIDGET_CAP_STEREO_SHIFT)) +#define HDA_PARAM_AUDIO_WIDGET_CAP_CP(param) \ + (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_CP_MASK) >> \ + HDA_PARAM_AUDIO_WIDGET_CAP_CP_SHIFT) +#define HDA_PARAM_AUDIO_WIDGET_CAP_LR_SWAP(param) \ + (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_LR_SWAP_MASK) >> \ + HDA_PARAM_AUDIO_WIDGET_CAP_LR_SWAP_SHIFT) +#define HDA_PARAM_AUDIO_WIDGET_CAP_POWER_CTRL(param) \ + (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_POWER_CTRL_MASK) >> \ + HDA_PARAM_AUDIO_WIDGET_CAP_POWER_CTRL_SHIFT) +#define HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(param) \ + (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL_MASK) >> \ + HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL_SHIFT) +#define HDA_PARAM_AUDIO_WIDGET_CAP_CONN_LIST(param) \ + (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_CONN_LIST_MASK) >> \ + HDA_PARAM_AUDIO_WIDGET_CAP_CONN_LIST_SHIFT) +#define HDA_PARAM_AUDIO_WIDGET_CAP_UNSOL_CAP(param) \ + (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_UNSOL_CAP_MASK) >> \ + HDA_PARAM_AUDIO_WIDGET_CAP_UNSOL_CAP_SHIFT) +#define HDA_PARAM_AUDIO_WIDGET_CAP_PROC_WIDGET(param) \ + (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_PROC_WIDGET_MASK) >> \ + HDA_PARAM_AUDIO_WIDGET_CAP_PROC_WIDGET_SHIFT) +#define HDA_PARAM_AUDIO_WIDGET_CAP_STRIPE(param) \ + (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_STRIPE_MASK) >> \ + HDA_PARAM_AUDIO_WIDGET_CAP_STRIPE_SHIFT) +#define HDA_PARAM_AUDIO_WIDGET_CAP_FORMAT_OVR(param) \ + (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_FORMAT_OVR_MASK) >> \ + HDA_PARAM_AUDIO_WIDGET_CAP_FORMAT_OVR_SHIFT) +#define HDA_PARAM_AUDIO_WIDGET_CAP_AMP_OVR(param) \ + (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_AMP_OVR_MASK) >> \ + HDA_PARAM_AUDIO_WIDGET_CAP_AMP_OVR_SHIFT) +#define HDA_PARAM_AUDIO_WIDGET_CAP_OUT_AMP(param) \ + (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_OUT_AMP_MASK) >> \ + HDA_PARAM_AUDIO_WIDGET_CAP_OUT_AMP_SHIFT) +#define HDA_PARAM_AUDIO_WIDGET_CAP_IN_AMP(param) \ + (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_IN_AMP_MASK) >> \ + HDA_PARAM_AUDIO_WIDGET_CAP_IN_AMP_SHIFT) +#define HDA_PARAM_AUDIO_WIDGET_CAP_STEREO(param) \ + (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_STEREO_MASK) >> \ + HDA_PARAM_AUDIO_WIDGET_CAP_STEREO_SHIFT) + +#define HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT 0x0 +#define HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT 0x1 +#define HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER 0x2 +#define HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR 0x3 +#define HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX 0x4 +#define HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_POWER_WIDGET 0x5 +#define HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_VOLUME_WIDGET 0x6 +#define HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET 0x7 +#define HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_VENDOR_WIDGET 0xf + +/* Supported PCM Size, Rates */ + +#define HDA_PARAM_SUPP_PCM_SIZE_RATE 0x0a + +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_32BIT_MASK 0x00100000 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_32BIT_SHIFT 20 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_24BIT_MASK 0x00080000 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_24BIT_SHIFT 19 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_20BIT_MASK 0x00040000 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_20BIT_SHIFT 18 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_16BIT_MASK 0x00020000 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_16BIT_SHIFT 17 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_8BIT_MASK 0x00010000 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_8BIT_SHIFT 16 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_8KHZ_MASK 0x00000001 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_8KHZ_SHIFT 0 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_11KHZ_MASK 0x00000002 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_11KHZ_SHIFT 1 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_16KHZ_MASK 0x00000004 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_16KHZ_SHIFT 2 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_22KHZ_MASK 0x00000008 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_22KHZ_SHIFT 3 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_32KHZ_MASK 0x00000010 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_32KHZ_SHIFT 4 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_44KHZ_MASK 0x00000020 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_44KHZ_SHIFT 5 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_48KHZ_MASK 0x00000040 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_48KHZ_SHIFT 6 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_88KHZ_MASK 0x00000080 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_88KHZ_SHIFT 7 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_96KHZ_MASK 0x00000100 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_96KHZ_SHIFT 8 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_176KHZ_MASK 0x00000200 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_176KHZ_SHIFT 9 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_192KHZ_MASK 0x00000400 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_192KHZ_SHIFT 10 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_384KHZ_MASK 0x00000800 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_384KHZ_SHIFT 11 + +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_32BIT(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_32BIT_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_32BIT_SHIFT) +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_24BIT(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_24BIT_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_24BIT_SHIFT) +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_20BIT(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_20BIT_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_20BIT_SHIFT) +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_16BIT(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_16BIT_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_16BIT_SHIFT) +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_8BIT(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_8BIT_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_8BIT_SHIFT) +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_8KHZ(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_8KHZ_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_8KHZ_SHIFT) +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_11KHZ(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_11KHZ_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_11KHZ_SHIFT) +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_16KHZ(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_16KHZ_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_16KHZ_SHIFT) +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_22KHZ(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_22KHZ_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_22KHZ_SHIFT) +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_32KHZ(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_32KHZ_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_32KHZ_SHIFT) +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_44KHZ(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_44KHZ_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_44KHZ_SHIFT) +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_48KHZ(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_48KHZ_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_48KHZ_SHIFT) +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_88KHZ(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_88KHZ_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_88KHZ_SHIFT) +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_96KHZ(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_96KHZ_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_96KHZ_SHIFT) +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_176KHZ(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_176KHZ_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_176KHZ_SHIFT) +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_192KHZ(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_192KHZ_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_192KHZ_SHIFT) +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_384KHZ(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_384KHZ_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_384KHZ_SHIFT) + +/* Supported Stream Formats */ +#define HDA_PARAM_SUPP_STREAM_FORMATS 0x0b + +#define HDA_PARAM_SUPP_STREAM_FORMATS_AC3_MASK 0x00000004 +#define HDA_PARAM_SUPP_STREAM_FORMATS_AC3_SHIFT 2 +#define HDA_PARAM_SUPP_STREAM_FORMATS_FLOAT32_MASK 0x00000002 +#define HDA_PARAM_SUPP_STREAM_FORMATS_FLOAT32_SHIFT 1 +#define HDA_PARAM_SUPP_STREAM_FORMATS_PCM_MASK 0x00000001 +#define HDA_PARAM_SUPP_STREAM_FORMATS_PCM_SHIFT 0 + +#define HDA_PARAM_SUPP_STREAM_FORMATS_AC3(param) \ + (((param) & HDA_PARAM_SUPP_STREAM_FORMATS_AC3_MASK) >> \ + HDA_PARAM_SUPP_STREAM_FORMATS_AC3_SHIFT) +#define HDA_PARAM_SUPP_STREAM_FORMATS_FLOAT32(param) \ + (((param) & HDA_PARAM_SUPP_STREAM_FORMATS_FLOAT32_MASK) >> \ + HDA_PARAM_SUPP_STREAM_FORMATS_FLOAT32_SHIFT) +#define HDA_PARAM_SUPP_STREAM_FORMATS_PCM(param) \ + (((param) & HDA_PARAM_SUPP_STREAM_FORMATS_PCM_MASK) >> \ + HDA_PARAM_SUPP_STREAM_FORMATS_PCM_SHIFT) + +/* Pin Capabilities */ +#define HDA_PARAM_PIN_CAP 0x0c + +#define HDA_PARAM_PIN_CAP_HBR_MASK 0x08000000 +#define HDA_PARAM_PIN_CAP_HBR_SHIFT 27 +#define HDA_PARAM_PIN_CAP_DP_MASK 0x01000000 +#define HDA_PARAM_PIN_CAP_DP_SHIFT 24 +#define HDA_PARAM_PIN_CAP_EAPD_CAP_MASK 0x00010000 +#define HDA_PARAM_PIN_CAP_EAPD_CAP_SHIFT 16 +#define HDA_PARAM_PIN_CAP_VREF_CTRL_MASK 0x0000ff00 +#define HDA_PARAM_PIN_CAP_VREF_CTRL_SHIFT 8 +#define HDA_PARAM_PIN_CAP_VREF_CTRL_100_MASK 0x00002000 +#define HDA_PARAM_PIN_CAP_VREF_CTRL_100_SHIFT 13 +#define HDA_PARAM_PIN_CAP_VREF_CTRL_80_MASK 0x00001000 +#define HDA_PARAM_PIN_CAP_VREF_CTRL_80_SHIFT 12 +#define HDA_PARAM_PIN_CAP_VREF_CTRL_GROUND_MASK 0x00000400 +#define HDA_PARAM_PIN_CAP_VREF_CTRL_GROUND_SHIFT 10 +#define HDA_PARAM_PIN_CAP_VREF_CTRL_50_MASK 0x00000200 +#define HDA_PARAM_PIN_CAP_VREF_CTRL_50_SHIFT 9 +#define HDA_PARAM_PIN_CAP_VREF_CTRL_HIZ_MASK 0x00000100 +#define HDA_PARAM_PIN_CAP_VREF_CTRL_HIZ_SHIFT 8 +#define HDA_PARAM_PIN_CAP_HDMI_MASK 0x00000080 +#define HDA_PARAM_PIN_CAP_HDMI_SHIFT 7 +#define HDA_PARAM_PIN_CAP_BALANCED_IO_PINS_MASK 0x00000040 +#define HDA_PARAM_PIN_CAP_BALANCED_IO_PINS_SHIFT 6 +#define HDA_PARAM_PIN_CAP_INPUT_CAP_MASK 0x00000020 +#define HDA_PARAM_PIN_CAP_INPUT_CAP_SHIFT 5 +#define HDA_PARAM_PIN_CAP_OUTPUT_CAP_MASK 0x00000010 +#define HDA_PARAM_PIN_CAP_OUTPUT_CAP_SHIFT 4 +#define HDA_PARAM_PIN_CAP_HEADPHONE_CAP_MASK 0x00000008 +#define HDA_PARAM_PIN_CAP_HEADPHONE_CAP_SHIFT 3 +#define HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP_MASK 0x00000004 +#define HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP_SHIFT 2 +#define HDA_PARAM_PIN_CAP_TRIGGER_REQD_MASK 0x00000002 +#define HDA_PARAM_PIN_CAP_TRIGGER_REQD_SHIFT 1 +#define HDA_PARAM_PIN_CAP_IMP_SENSE_CAP_MASK 0x00000001 +#define HDA_PARAM_PIN_CAP_IMP_SENSE_CAP_SHIFT 0 + +#define HDA_PARAM_PIN_CAP_HBR(param) \ + (((param) & HDA_PARAM_PIN_CAP_HBR_MASK) >> \ + HDA_PARAM_PIN_CAP_HBR_SHIFT) +#define HDA_PARAM_PIN_CAP_DP(param) \ + (((param) & HDA_PARAM_PIN_CAP_DP_MASK) >> \ + HDA_PARAM_PIN_CAP_DP_SHIFT) +#define HDA_PARAM_PIN_CAP_EAPD_CAP(param) \ + (((param) & HDA_PARAM_PIN_CAP_EAPD_CAP_MASK) >> \ + HDA_PARAM_PIN_CAP_EAPD_CAP_SHIFT) +#define HDA_PARAM_PIN_CAP_VREF_CTRL(param) \ + (((param) & HDA_PARAM_PIN_CAP_VREF_CTRL_MASK) >> \ + HDA_PARAM_PIN_CAP_VREF_CTRL_SHIFT) +#define HDA_PARAM_PIN_CAP_VREF_CTRL_100(param) \ + (((param) & HDA_PARAM_PIN_CAP_VREF_CTRL_100_MASK) >> \ + HDA_PARAM_PIN_CAP_VREF_CTRL_100_SHIFT) +#define HDA_PARAM_PIN_CAP_VREF_CTRL_80(param) \ + (((param) & HDA_PARAM_PIN_CAP_VREF_CTRL_80_MASK) >> \ + HDA_PARAM_PIN_CAP_VREF_CTRL_80_SHIFT) +#define HDA_PARAM_PIN_CAP_VREF_CTRL_GROUND(param) \ + (((param) & HDA_PARAM_PIN_CAP_VREF_CTRL_GROUND_MASK) >> \ + HDA_PARAM_PIN_CAP_VREF_CTRL_GROUND_SHIFT) +#define HDA_PARAM_PIN_CAP_VREF_CTRL_50(param) \ + (((param) & HDA_PARAM_PIN_CAP_VREF_CTRL_50_MASK) >> \ + HDA_PARAM_PIN_CAP_VREF_CTRL_50_SHIFT) +#define HDA_PARAM_PIN_CAP_VREF_CTRL_HIZ(param) \ + (((param) & HDA_PARAM_PIN_CAP_VREF_CTRL_HIZ_MASK) >> \ + HDA_PARAM_PIN_CAP_VREF_CTRL_HIZ_SHIFT) +#define HDA_PARAM_PIN_CAP_HDMI(param) \ + (((param) & HDA_PARAM_PIN_CAP_HDMI_MASK) >> \ + HDA_PARAM_PIN_CAP_HDMI_SHIFT) +#define HDA_PARAM_PIN_CAP_BALANCED_IO_PINS(param) \ + (((param) & HDA_PARAM_PIN_CAP_BALANCED_IO_PINS_MASK) >> \ + HDA_PARAM_PIN_CAP_BALANCED_IO_PINS_SHIFT) +#define HDA_PARAM_PIN_CAP_INPUT_CAP(param) \ + (((param) & HDA_PARAM_PIN_CAP_INPUT_CAP_MASK) >> \ + HDA_PARAM_PIN_CAP_INPUT_CAP_SHIFT) +#define HDA_PARAM_PIN_CAP_OUTPUT_CAP(param) \ + (((param) & HDA_PARAM_PIN_CAP_OUTPUT_CAP_MASK) >> \ + HDA_PARAM_PIN_CAP_OUTPUT_CAP_SHIFT) +#define HDA_PARAM_PIN_CAP_HEADPHONE_CAP(param) \ + (((param) & HDA_PARAM_PIN_CAP_HEADPHONE_CAP_MASK) >> \ + HDA_PARAM_PIN_CAP_HEADPHONE_CAP_SHIFT) +#define HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP(param) \ + (((param) & HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP_MASK) >> \ + HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP_SHIFT) +#define HDA_PARAM_PIN_CAP_TRIGGER_REQD(param) \ + (((param) & HDA_PARAM_PIN_CAP_TRIGGER_REQD_MASK) >> \ + HDA_PARAM_PIN_CAP_TRIGGER_REQD_SHIFT) +#define HDA_PARAM_PIN_CAP_IMP_SENSE_CAP(param) \ + (((param) & HDA_PARAM_PIN_CAP_IMP_SENSE_CAP_MASK) >> \ + HDA_PARAM_PIN_CAP_IMP_SENSE_CAP_SHIFT) + +/* Input Amplifier Capabilities */ +#define HDA_PARAM_INPUT_AMP_CAP 0x0d + +#define HDA_PARAM_INPUT_AMP_CAP_MUTE_CAP_MASK 0x80000000 +#define HDA_PARAM_INPUT_AMP_CAP_MUTE_CAP_SHIFT 31 +#define HDA_PARAM_INPUT_AMP_CAP_STEPSIZE_MASK 0x007f0000 +#define HDA_PARAM_INPUT_AMP_CAP_STEPSIZE_SHIFT 16 +#define HDA_PARAM_INPUT_AMP_CAP_NUMSTEPS_MASK 0x00007f00 +#define HDA_PARAM_INPUT_AMP_CAP_NUMSTEPS_SHIFT 8 +#define HDA_PARAM_INPUT_AMP_CAP_OFFSET_MASK 0x0000007f +#define HDA_PARAM_INPUT_AMP_CAP_OFFSET_SHIFT 0 + +#define HDA_PARAM_INPUT_AMP_CAP_MUTE_CAP(param) \ + (((param) & HDA_PARAM_INPUT_AMP_CAP_MUTE_CAP_MASK) >> \ + HDA_PARAM_INPUT_AMP_CAP_MUTE_CAP_SHIFT) +#define HDA_PARAM_INPUT_AMP_CAP_STEPSIZE(param) \ + (((param) & HDA_PARAM_INPUT_AMP_CAP_STEPSIZE_MASK) >> \ + HDA_PARAM_INPUT_AMP_CAP_STEPSIZE_SHIFT) +#define HDA_PARAM_INPUT_AMP_CAP_NUMSTEPS(param) \ + (((param) & HDA_PARAM_INPUT_AMP_CAP_NUMSTEPS_MASK) >> \ + HDA_PARAM_INPUT_AMP_CAP_NUMSTEPS_SHIFT) +#define HDA_PARAM_INPUT_AMP_CAP_OFFSET(param) \ + (((param) & HDA_PARAM_INPUT_AMP_CAP_OFFSET_MASK) >> \ + HDA_PARAM_INPUT_AMP_CAP_OFFSET_SHIFT) + +/* Output Amplifier Capabilities */ +#define HDA_PARAM_OUTPUT_AMP_CAP 0x12 + +#define HDA_PARAM_OUTPUT_AMP_CAP_MUTE_CAP_MASK 0x80000000 +#define HDA_PARAM_OUTPUT_AMP_CAP_MUTE_CAP_SHIFT 31 +#define HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE_MASK 0x007f0000 +#define HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE_SHIFT 16 +#define HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS_MASK 0x00007f00 +#define HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS_SHIFT 8 +#define HDA_PARAM_OUTPUT_AMP_CAP_OFFSET_MASK 0x0000007f +#define HDA_PARAM_OUTPUT_AMP_CAP_OFFSET_SHIFT 0 + +#define HDA_PARAM_OUTPUT_AMP_CAP_MUTE_CAP(param) \ + (((param) & HDA_PARAM_OUTPUT_AMP_CAP_MUTE_CAP_MASK) >> \ + HDA_PARAM_OUTPUT_AMP_CAP_MUTE_CAP_SHIFT) +#define HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE(param) \ + (((param) & HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE_MASK) >> \ + HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE_SHIFT) +#define HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS(param) \ + (((param) & HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS_MASK) >> \ + HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS_SHIFT) +#define HDA_PARAM_OUTPUT_AMP_CAP_OFFSET(param) \ + (((param) & HDA_PARAM_OUTPUT_AMP_CAP_OFFSET_MASK) >> \ + HDA_PARAM_OUTPUT_AMP_CAP_OFFSET_SHIFT) + +/* Connection List Length */ +#define HDA_PARAM_CONN_LIST_LENGTH 0x0e + +#define HDA_PARAM_CONN_LIST_LENGTH_LONG_FORM_MASK 0x00000080 +#define HDA_PARAM_CONN_LIST_LENGTH_LONG_FORM_SHIFT 7 +#define HDA_PARAM_CONN_LIST_LENGTH_LIST_LENGTH_MASK 0x0000007f +#define HDA_PARAM_CONN_LIST_LENGTH_LIST_LENGTH_SHIFT 0 + +#define HDA_PARAM_CONN_LIST_LENGTH_LONG_FORM(param) \ + (((param) & HDA_PARAM_CONN_LIST_LENGTH_LONG_FORM_MASK) >> \ + HDA_PARAM_CONN_LIST_LENGTH_LONG_FORM_SHIFT) +#define HDA_PARAM_CONN_LIST_LENGTH_LIST_LENGTH(param) \ + (((param) & HDA_PARAM_CONN_LIST_LENGTH_LIST_LENGTH_MASK) >> \ + HDA_PARAM_CONN_LIST_LENGTH_LIST_LENGTH_SHIFT) + +/* Supported Power States */ +#define HDA_PARAM_SUPP_POWER_STATES 0x0f + +#define HDA_PARAM_SUPP_POWER_STATES_D3_MASK 0x00000008 +#define HDA_PARAM_SUPP_POWER_STATES_D3_SHIFT 3 +#define HDA_PARAM_SUPP_POWER_STATES_D2_MASK 0x00000004 +#define HDA_PARAM_SUPP_POWER_STATES_D2_SHIFT 2 +#define HDA_PARAM_SUPP_POWER_STATES_D1_MASK 0x00000002 +#define HDA_PARAM_SUPP_POWER_STATES_D1_SHIFT 1 +#define HDA_PARAM_SUPP_POWER_STATES_D0_MASK 0x00000001 +#define HDA_PARAM_SUPP_POWER_STATES_D0_SHIFT 0 + +#define HDA_PARAM_SUPP_POWER_STATES_D3(param) \ + (((param) & HDA_PARAM_SUPP_POWER_STATES_D3_MASK) >> \ + HDA_PARAM_SUPP_POWER_STATES_D3_SHIFT) +#define HDA_PARAM_SUPP_POWER_STATES_D2(param) \ + (((param) & HDA_PARAM_SUPP_POWER_STATES_D2_MASK) >> \ + HDA_PARAM_SUPP_POWER_STATES_D2_SHIFT) +#define HDA_PARAM_SUPP_POWER_STATES_D1(param) \ + (((param) & HDA_PARAM_SUPP_POWER_STATES_D1_MASK) >> \ + HDA_PARAM_SUPP_POWER_STATES_D1_SHIFT) +#define HDA_PARAM_SUPP_POWER_STATES_D0(param) \ + (((param) & HDA_PARAM_SUPP_POWER_STATES_D0_MASK) >> \ + HDA_PARAM_SUPP_POWER_STATES_D0_SHIFT) + +/* Processing Capabilities */ +#define HDA_PARAM_PROCESSING_CAP 0x10 + +#define HDA_PARAM_PROCESSING_CAP_NUMCOEFF_MASK 0x0000ff00 +#define HDA_PARAM_PROCESSING_CAP_NUMCOEFF_SHIFT 8 +#define HDA_PARAM_PROCESSING_CAP_BENIGN_MASK 0x00000001 +#define HDA_PARAM_PROCESSING_CAP_BENIGN_SHIFT 0 + +#define HDA_PARAM_PROCESSING_CAP_NUMCOEFF(param) \ + (((param) & HDA_PARAM_PROCESSING_CAP_NUMCOEFF_MASK) >> \ + HDA_PARAM_PROCESSING_CAP_NUMCOEFF_SHIFT) +#define HDA_PARAM_PROCESSING_CAP_BENIGN(param) \ + (((param) & HDA_PARAM_PROCESSING_CAP_BENIGN_MASK) >> \ + HDA_PARAM_PROCESSING_CAP_BENIGN_SHIFT) + +/* GPIO Count */ +#define HDA_PARAM_GPIO_COUNT 0x11 + +#define HDA_PARAM_GPIO_COUNT_GPI_WAKE_MASK 0x80000000 +#define HDA_PARAM_GPIO_COUNT_GPI_WAKE_SHIFT 31 +#define HDA_PARAM_GPIO_COUNT_GPI_UNSOL_MASK 0x40000000 +#define HDA_PARAM_GPIO_COUNT_GPI_UNSOL_SHIFT 30 +#define HDA_PARAM_GPIO_COUNT_NUM_GPI_MASK 0x00ff0000 +#define HDA_PARAM_GPIO_COUNT_NUM_GPI_SHIFT 16 +#define HDA_PARAM_GPIO_COUNT_NUM_GPO_MASK 0x0000ff00 +#define HDA_PARAM_GPIO_COUNT_NUM_GPO_SHIFT 8 +#define HDA_PARAM_GPIO_COUNT_NUM_GPIO_MASK 0x000000ff +#define HDA_PARAM_GPIO_COUNT_NUM_GPIO_SHIFT 0 + +#define HDA_PARAM_GPIO_COUNT_GPI_WAKE(param) \ + (((param) & HDA_PARAM_GPIO_COUNT_GPI_WAKE_MASK) >> \ + HDA_PARAM_GPIO_COUNT_GPI_WAKE_SHIFT) +#define HDA_PARAM_GPIO_COUNT_GPI_UNSOL(param) \ + (((param) & HDA_PARAM_GPIO_COUNT_GPI_UNSOL_MASK) >> \ + HDA_PARAM_GPIO_COUNT_GPI_UNSOL_SHIFT) +#define HDA_PARAM_GPIO_COUNT_NUM_GPI(param) \ + (((param) & HDA_PARAM_GPIO_COUNT_NUM_GPI_MASK) >> \ + HDA_PARAM_GPIO_COUNT_NUM_GPI_SHIFT) +#define HDA_PARAM_GPIO_COUNT_NUM_GPO(param) \ + (((param) & HDA_PARAM_GPIO_COUNT_NUM_GPO_MASK) >> \ + HDA_PARAM_GPIO_COUNT_NUM_GPO_SHIFT) +#define HDA_PARAM_GPIO_COUNT_NUM_GPIO(param) \ + (((param) & HDA_PARAM_GPIO_COUNT_NUM_GPIO_MASK) >> \ + HDA_PARAM_GPIO_COUNT_NUM_GPIO_SHIFT) + +/* Volume Knob Capabilities */ +#define HDA_PARAM_VOLUME_KNOB_CAP 0x13 + +#define HDA_PARAM_VOLUME_KNOB_CAP_DELTA_MASK 0x00000080 +#define HDA_PARAM_VOLUME_KNOB_CAP_DELTA_SHIFT 7 +#define HDA_PARAM_VOLUME_KNOB_CAP_NUM_STEPS_MASK 0x0000007f +#define HDA_PARAM_VOLUME_KNOB_CAP_NUM_STEPS_SHIFT 0 + +#define HDA_PARAM_VOLUME_KNOB_CAP_DELTA(param) \ + (((param) & HDA_PARAM_VOLUME_KNOB_CAP_DELTA_MASK) >> \ + HDA_PARAM_VOLUME_KNOB_CAP_DELTA_SHIFT) +#define HDA_PARAM_VOLUME_KNOB_CAP_NUM_STEPS(param) \ + (((param) & HDA_PARAM_VOLUME_KNOB_CAP_NUM_STEPS_MASK) >> \ + HDA_PARAM_VOLUME_KNOB_CAP_NUM_STEPS_SHIFT) + + +#define HDA_CONFIG_DEFAULTCONF_SEQUENCE_MASK 0x0000000f +#define HDA_CONFIG_DEFAULTCONF_SEQUENCE_SHIFT 0 +#define HDA_CONFIG_DEFAULTCONF_ASSOCIATION_MASK 0x000000f0 +#define HDA_CONFIG_DEFAULTCONF_ASSOCIATION_SHIFT 4 +#define HDA_CONFIG_DEFAULTCONF_MISC_MASK 0x00000f00 +#define HDA_CONFIG_DEFAULTCONF_MISC_SHIFT 8 +#define HDA_CONFIG_DEFAULTCONF_COLOR_MASK 0x0000f000 +#define HDA_CONFIG_DEFAULTCONF_COLOR_SHIFT 12 +#define HDA_CONFIG_DEFAULTCONF_CONNECTION_TYPE_MASK 0x000f0000 +#define HDA_CONFIG_DEFAULTCONF_CONNECTION_TYPE_SHIFT 16 +#define HDA_CONFIG_DEFAULTCONF_DEVICE_MASK 0x00f00000 +#define HDA_CONFIG_DEFAULTCONF_DEVICE_SHIFT 20 +#define HDA_CONFIG_DEFAULTCONF_LOCATION_MASK 0x3f000000 +#define HDA_CONFIG_DEFAULTCONF_LOCATION_SHIFT 24 +#define HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK 0xc0000000 +#define HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_SHIFT 30 + +#define HDA_CONFIG_DEFAULTCONF_SEQUENCE(conf) \ + (((conf) & HDA_CONFIG_DEFAULTCONF_SEQUENCE_MASK) >> \ + HDA_CONFIG_DEFAULTCONF_SEQUENCE_SHIFT) +#define HDA_CONFIG_DEFAULTCONF_ASSOCIATION(conf) \ + (((conf) & HDA_CONFIG_DEFAULTCONF_ASSOCIATION_MASK) >> \ + HDA_CONFIG_DEFAULTCONF_ASSOCIATION_SHIFT) +#define HDA_CONFIG_DEFAULTCONF_MISC(conf) \ + (((conf) & HDA_CONFIG_DEFAULTCONF_MISC_MASK) >> \ + HDA_CONFIG_DEFAULTCONF_MISC_SHIFT) +#define HDA_CONFIG_DEFAULTCONF_COLOR(conf) \ + (((conf) & HDA_CONFIG_DEFAULTCONF_COLOR_MASK) >> \ + HDA_CONFIG_DEFAULTCONF_COLOR_SHIFT) +#define HDA_CONFIG_DEFAULTCONF_CONNECTION_TYPE(conf) \ + (((conf) & HDA_CONFIG_DEFAULTCONF_CONNECTION_TYPE_MASK) >> \ + HDA_CONFIG_DEFAULTCONF_CONNECTION_TYPE_SHIFT) +#define HDA_CONFIG_DEFAULTCONF_DEVICE(conf) \ + (((conf) & HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) >> \ + HDA_CONFIG_DEFAULTCONF_DEVICE_SHIFT) +#define HDA_CONFIG_DEFAULTCONF_LOCATION(conf) \ + (((conf) & HDA_CONFIG_DEFAULTCONF_LOCATION_MASK) >> \ + HDA_CONFIG_DEFAULTCONF_LOCATION_SHIFT) +#define HDA_CONFIG_DEFAULTCONF_CONNECTIVITY(conf) \ + (((conf) & HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) >> \ + HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_SHIFT) + +#define HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK (0<<30) +#define HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE (1<<30) +#define HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED (2<<30) +#define HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_BOTH (3<<30) + +#define HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_OUT (0<<20) +#define HDA_CONFIG_DEFAULTCONF_DEVICE_SPEAKER (1<<20) +#define HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT (2<<20) +#define HDA_CONFIG_DEFAULTCONF_DEVICE_CD (3<<20) +#define HDA_CONFIG_DEFAULTCONF_DEVICE_SPDIF_OUT (4<<20) +#define HDA_CONFIG_DEFAULTCONF_DEVICE_DIGITAL_OTHER_OUT (5<<20) +#define HDA_CONFIG_DEFAULTCONF_DEVICE_MODEM_LINE (6<<20) +#define HDA_CONFIG_DEFAULTCONF_DEVICE_MODEM_HANDSET (7<<20) +#define HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN (8<<20) +#define HDA_CONFIG_DEFAULTCONF_DEVICE_AUX (9<<20) +#define HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN (10<<20) +#define HDA_CONFIG_DEFAULTCONF_DEVICE_TELEPHONY (11<<20) +#define HDA_CONFIG_DEFAULTCONF_DEVICE_SPDIF_IN (12<<20) +#define HDA_CONFIG_DEFAULTCONF_DEVICE_DIGITAL_OTHER_IN (13<<20) +#define HDA_CONFIG_DEFAULTCONF_DEVICE_OTHER (15<<20) + +#endif /* _HDA_REG_H_ */ diff --git a/usr.sbin/bhyve/hdac_reg.h b/usr.sbin/bhyve/hdac_reg.h new file mode 100644 index 000000000000..35272e5135cb --- /dev/null +++ b/usr.sbin/bhyve/hdac_reg.h @@ -0,0 +1,271 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2006 Stephane E. Potvin <sepotvin@videotron.ca> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _HDAC_REG_H_ +#define _HDAC_REG_H_ + +/**************************************************************************** + * HDA Controller Register Set + ****************************************************************************/ +#define HDAC_GCAP 0x00 /* 2 - Global Capabilities*/ +#define HDAC_VMIN 0x02 /* 1 - Minor Version */ +#define HDAC_VMAJ 0x03 /* 1 - Major Version */ +#define HDAC_OUTPAY 0x04 /* 2 - Output Payload Capability */ +#define HDAC_INPAY 0x06 /* 2 - Input Payload Capability */ +#define HDAC_GCTL 0x08 /* 4 - Global Control */ +#define HDAC_WAKEEN 0x0c /* 2 - Wake Enable */ +#define HDAC_STATESTS 0x0e /* 2 - State Change Status */ +#define HDAC_GSTS 0x10 /* 2 - Global Status */ +#define HDAC_OUTSTRMPAY 0x18 /* 2 - Output Stream Payload Capability */ +#define HDAC_INSTRMPAY 0x1a /* 2 - Input Stream Payload Capability */ +#define HDAC_INTCTL 0x20 /* 4 - Interrupt Control */ +#define HDAC_INTSTS 0x24 /* 4 - Interrupt Status */ +#define HDAC_WALCLK 0x30 /* 4 - Wall Clock Counter */ +#define HDAC_SSYNC 0x38 /* 4 - Stream Synchronization */ +#define HDAC_CORBLBASE 0x40 /* 4 - CORB Lower Base Address */ +#define HDAC_CORBUBASE 0x44 /* 4 - CORB Upper Base Address */ +#define HDAC_CORBWP 0x48 /* 2 - CORB Write Pointer */ +#define HDAC_CORBRP 0x4a /* 2 - CORB Read Pointer */ +#define HDAC_CORBCTL 0x4c /* 1 - CORB Control */ +#define HDAC_CORBSTS 0x4d /* 1 - CORB Status */ +#define HDAC_CORBSIZE 0x4e /* 1 - CORB Size */ +#define HDAC_RIRBLBASE 0x50 /* 4 - RIRB Lower Base Address */ +#define HDAC_RIRBUBASE 0x54 /* 4 - RIRB Upper Base Address */ +#define HDAC_RIRBWP 0x58 /* 2 - RIRB Write Pointer */ +#define HDAC_RINTCNT 0x5a /* 2 - Response Interrupt Count */ +#define HDAC_RIRBCTL 0x5c /* 1 - RIRB Control */ +#define HDAC_RIRBSTS 0x5d /* 1 - RIRB Status */ +#define HDAC_RIRBSIZE 0x5e /* 1 - RIRB Size */ +#define HDAC_ICOI 0x60 /* 4 - Immediate Command Output Interface */ +#define HDAC_ICII 0x64 /* 4 - Immediate Command Input Interface */ +#define HDAC_ICIS 0x68 /* 2 - Immediate Command Status */ +#define HDAC_DPIBLBASE 0x70 /* 4 - DMA Position Buffer Lower Base */ +#define HDAC_DPIBUBASE 0x74 /* 4 - DMA Position Buffer Upper Base */ +#define HDAC_SDCTL0 0x80 /* 3 - Stream Descriptor Control */ +#define HDAC_SDCTL1 0x81 /* 3 - Stream Descriptor Control */ +#define HDAC_SDCTL2 0x82 /* 3 - Stream Descriptor Control */ +#define HDAC_SDSTS 0x83 /* 1 - Stream Descriptor Status */ +#define HDAC_SDLPIB 0x84 /* 4 - Link Position in Buffer */ +#define HDAC_SDCBL 0x88 /* 4 - Cyclic Buffer Length */ +#define HDAC_SDLVI 0x8C /* 2 - Last Valid Index */ +#define HDAC_SDFIFOS 0x90 /* 2 - FIFOS */ +#define HDAC_SDFMT 0x92 /* 2 - fmt */ +#define HDAC_SDBDPL 0x98 /* 4 - Buffer Descriptor Pointer Lower Base */ +#define HDAC_SDBDPU 0x9C /* 4 - Buffer Descriptor Pointer Upper Base */ + +#define _HDAC_ISDOFFSET(n, iss, oss) (0x80 + ((n) * 0x20)) +#define _HDAC_ISDCTL(n, iss, oss) (0x00 + _HDAC_ISDOFFSET(n, iss, oss)) +#define _HDAC_ISDSTS(n, iss, oss) (0x03 + _HDAC_ISDOFFSET(n, iss, oss)) +#define _HDAC_ISDPICB(n, iss, oss) (0x04 + _HDAC_ISDOFFSET(n, iss, oss)) +#define _HDAC_ISDCBL(n, iss, oss) (0x08 + _HDAC_ISDOFFSET(n, iss, oss)) +#define _HDAC_ISDLVI(n, iss, oss) (0x0c + _HDAC_ISDOFFSET(n, iss, oss)) +#define _HDAC_ISDFIFOD(n, iss, oss) (0x10 + _HDAC_ISDOFFSET(n, iss, oss)) +#define _HDAC_ISDFMT(n, iss, oss) (0x12 + _HDAC_ISDOFFSET(n, iss, oss)) +#define _HDAC_ISDBDPL(n, iss, oss) (0x18 + _HDAC_ISDOFFSET(n, iss, oss)) +#define _HDAC_ISDBDPU(n, iss, oss) (0x1c + _HDAC_ISDOFFSET(n, iss, oss)) + +#define _HDAC_OSDOFFSET(n, iss, oss) (0x80 + ((iss) * 0x20) + ((n) * 0x20)) +#define _HDAC_OSDCTL(n, iss, oss) (0x00 + _HDAC_OSDOFFSET(n, iss, oss)) +#define _HDAC_OSDSTS(n, iss, oss) (0x03 + _HDAC_OSDOFFSET(n, iss, oss)) +#define _HDAC_OSDPICB(n, iss, oss) (0x04 + _HDAC_OSDOFFSET(n, iss, oss)) +#define _HDAC_OSDCBL(n, iss, oss) (0x08 + _HDAC_OSDOFFSET(n, iss, oss)) +#define _HDAC_OSDLVI(n, iss, oss) (0x0c + _HDAC_OSDOFFSET(n, iss, oss)) +#define _HDAC_OSDFIFOD(n, iss, oss) (0x10 + _HDAC_OSDOFFSET(n, iss, oss)) +#define _HDAC_OSDFMT(n, iss, oss) (0x12 + _HDAC_OSDOFFSET(n, iss, oss)) +#define _HDAC_OSDBDPL(n, iss, oss) (0x18 + _HDAC_OSDOFFSET(n, iss, oss)) +#define _HDAC_OSDBDPU(n, iss, oss) (0x1c + _HDAC_OSDOFFSET(n, iss, oss)) + +#define _HDAC_BSDOFFSET(n, iss, oss) \ + (0x80 + ((iss) * 0x20) + ((oss) * 0x20) + ((n) * 0x20)) +#define _HDAC_BSDCTL(n, iss, oss) (0x00 + _HDAC_BSDOFFSET(n, iss, oss)) +#define _HDAC_BSDSTS(n, iss, oss) (0x03 + _HDAC_BSDOFFSET(n, iss, oss)) +#define _HDAC_BSDPICB(n, iss, oss) (0x04 + _HDAC_BSDOFFSET(n, iss, oss)) +#define _HDAC_BSDCBL(n, iss, oss) (0x08 + _HDAC_BSDOFFSET(n, iss, oss)) +#define _HDAC_BSDLVI(n, iss, oss) (0x0c + _HDAC_BSDOFFSET(n, iss, oss)) +#define _HDAC_BSDFIFOD(n, iss, oss) (0x10 + _HDAC_BSDOFFSET(n, iss, oss)) +#define _HDAC_BSDFMT(n, iss, oss) (0x12 + _HDAC_BSDOFFSET(n, iss, oss)) +#define _HDAC_BSDBDPL(n, iss, oss) (0x18 + _HDAC_BSDOFFSET(n, iss, oss)) +#define _HDAC_BSDBDBU(n, iss, oss) (0x1c + _HDAC_BSDOFFSET(n, iss, oss)) + +/**************************************************************************** + * HDA Controller Register Fields + ****************************************************************************/ + +/* GCAP - Global Capabilities */ +#define HDAC_GCAP_64OK 0x0001 +#define HDAC_GCAP_NSDO_MASK 0x0006 +#define HDAC_GCAP_NSDO_SHIFT 1 +#define HDAC_GCAP_BSS_MASK 0x00f8 +#define HDAC_GCAP_BSS_SHIFT 3 +#define HDAC_GCAP_ISS_MASK 0x0f00 +#define HDAC_GCAP_ISS_SHIFT 8 +#define HDAC_GCAP_OSS_MASK 0xf000 +#define HDAC_GCAP_OSS_SHIFT 12 + +#define HDAC_GCAP_NSDO_1SDO 0x00 +#define HDAC_GCAP_NSDO_2SDO 0x02 +#define HDAC_GCAP_NSDO_4SDO 0x04 + +#define HDAC_GCAP_BSS(gcap) \ + (((gcap) & HDAC_GCAP_BSS_MASK) >> HDAC_GCAP_BSS_SHIFT) +#define HDAC_GCAP_ISS(gcap) \ + (((gcap) & HDAC_GCAP_ISS_MASK) >> HDAC_GCAP_ISS_SHIFT) +#define HDAC_GCAP_OSS(gcap) \ + (((gcap) & HDAC_GCAP_OSS_MASK) >> HDAC_GCAP_OSS_SHIFT) +#define HDAC_GCAP_NSDO(gcap) \ + (((gcap) & HDAC_GCAP_NSDO_MASK) >> HDAC_GCAP_NSDO_SHIFT) + +/* GCTL - Global Control */ +#define HDAC_GCTL_CRST 0x00000001 +#define HDAC_GCTL_FCNTRL 0x00000002 +#define HDAC_GCTL_UNSOL 0x00000100 + +/* WAKEEN - Wake Enable */ +#define HDAC_WAKEEN_SDIWEN_MASK 0x7fff +#define HDAC_WAKEEN_SDIWEN_SHIFT 0 + +/* STATESTS - State Change Status */ +#define HDAC_STATESTS_SDIWAKE_MASK 0x7fff +#define HDAC_STATESTS_SDIWAKE_SHIFT 0 + +#define HDAC_STATESTS_SDIWAKE(statests, n) \ + (((((statests) & HDAC_STATESTS_SDIWAKE_MASK) >> \ + HDAC_STATESTS_SDIWAKE_SHIFT) >> (n)) & 0x0001) + +/* GSTS - Global Status */ +#define HDAC_GSTS_FSTS 0x0002 + +/* INTCTL - Interrut Control */ +#define HDAC_INTCTL_SIE_MASK 0x3fffffff +#define HDAC_INTCTL_SIE_SHIFT 0 +#define HDAC_INTCTL_CIE 0x40000000 +#define HDAC_INTCTL_GIE 0x80000000 + +/* INTSTS - Interrupt Status */ +#define HDAC_INTSTS_SIS_MASK 0x3fffffff +#define HDAC_INTSTS_SIS_SHIFT 0 +#define HDAC_INTSTS_CIS 0x40000000 +#define HDAC_INTSTS_GIS 0x80000000 + +/* SSYNC - Stream Synchronization */ +#define HDAC_SSYNC_SSYNC_MASK 0x3fffffff +#define HDAC_SSYNC_SSYNC_SHIFT 0 + +/* CORBWP - CORB Write Pointer */ +#define HDAC_CORBWP_CORBWP_MASK 0x00ff +#define HDAC_CORBWP_CORBWP_SHIFT 0 + +/* CORBRP - CORB Read Pointer */ +#define HDAC_CORBRP_CORBRP_MASK 0x00ff +#define HDAC_CORBRP_CORBRP_SHIFT 0 +#define HDAC_CORBRP_CORBRPRST 0x8000 + +/* CORBCTL - CORB Control */ +#define HDAC_CORBCTL_CMEIE 0x01 +#define HDAC_CORBCTL_CORBRUN 0x02 + +/* CORBSTS - CORB Status */ +#define HDAC_CORBSTS_CMEI 0x01 + +/* CORBSIZE - CORB Size */ +#define HDAC_CORBSIZE_CORBSIZE_MASK 0x03 +#define HDAC_CORBSIZE_CORBSIZE_SHIFT 0 +#define HDAC_CORBSIZE_CORBSZCAP_MASK 0xf0 +#define HDAC_CORBSIZE_CORBSZCAP_SHIFT 4 + +#define HDAC_CORBSIZE_CORBSIZE_2 0x00 +#define HDAC_CORBSIZE_CORBSIZE_16 0x01 +#define HDAC_CORBSIZE_CORBSIZE_256 0x02 + +#define HDAC_CORBSIZE_CORBSZCAP_2 0x10 +#define HDAC_CORBSIZE_CORBSZCAP_16 0x20 +#define HDAC_CORBSIZE_CORBSZCAP_256 0x40 + +#define HDAC_CORBSIZE_CORBSIZE(corbsize) \ + (((corbsize) & HDAC_CORBSIZE_CORBSIZE_MASK) >> HDAC_CORBSIZE_CORBSIZE_SHIFT) + +/* RIRBWP - RIRB Write Pointer */ +#define HDAC_RIRBWP_RIRBWP_MASK 0x00ff +#define HDAC_RIRBWP_RIRBWP_SHIFT 0 +#define HDAC_RIRBWP_RIRBWPRST 0x8000 + +/* RINTCTN - Response Interrupt Count */ +#define HDAC_RINTCNT_MASK 0x00ff +#define HDAC_RINTCNT_SHIFT 0 + +/* RIRBCTL - RIRB Control */ +#define HDAC_RIRBCTL_RINTCTL 0x01 +#define HDAC_RIRBCTL_RIRBDMAEN 0x02 +#define HDAC_RIRBCTL_RIRBOIC 0x04 + +/* RIRBSTS - RIRB Status */ +#define HDAC_RIRBSTS_RINTFL 0x01 +#define HDAC_RIRBSTS_RIRBOIS 0x04 + +/* RIRBSIZE - RIRB Size */ +#define HDAC_RIRBSIZE_RIRBSIZE_MASK 0x03 +#define HDAC_RIRBSIZE_RIRBSIZE_SHIFT 0 +#define HDAC_RIRBSIZE_RIRBSZCAP_MASK 0xf0 +#define HDAC_RIRBSIZE_RIRBSZCAP_SHIFT 4 + +#define HDAC_RIRBSIZE_RIRBSIZE_2 0x00 +#define HDAC_RIRBSIZE_RIRBSIZE_16 0x01 +#define HDAC_RIRBSIZE_RIRBSIZE_256 0x02 + +#define HDAC_RIRBSIZE_RIRBSZCAP_2 0x10 +#define HDAC_RIRBSIZE_RIRBSZCAP_16 0x20 +#define HDAC_RIRBSIZE_RIRBSZCAP_256 0x40 + +#define HDAC_RIRBSIZE_RIRBSIZE(rirbsize) \ + (((rirbsize) & HDAC_RIRBSIZE_RIRBSIZE_MASK) >> HDAC_RIRBSIZE_RIRBSIZE_SHIFT) + +/* DPLBASE - DMA Position Lower Base Address */ +#define HDAC_DPLBASE_DPLBASE_MASK 0xffffff80 +#define HDAC_DPLBASE_DPLBASE_SHIFT 7 +#define HDAC_DPLBASE_DPLBASE_DMAPBE 0x00000001 + +/* SDCTL - Stream Descriptor Control */ +#define HDAC_SDCTL_SRST 0x000001 +#define HDAC_SDCTL_RUN 0x000002 +#define HDAC_SDCTL_IOCE 0x000004 +#define HDAC_SDCTL_FEIE 0x000008 +#define HDAC_SDCTL_DEIE 0x000010 +#define HDAC_SDCTL2_STRIPE_MASK 0x03 +#define HDAC_SDCTL2_STRIPE_SHIFT 0 +#define HDAC_SDCTL2_TP 0x04 +#define HDAC_SDCTL2_DIR 0x08 +#define HDAC_SDCTL2_STRM_MASK 0xf0 +#define HDAC_SDCTL2_STRM_SHIFT 4 + +#define HDAC_SDSTS_DESE (1 << 4) +#define HDAC_SDSTS_FIFOE (1 << 3) +#define HDAC_SDSTS_BCIS (1 << 2) + +#endif /* _HDAC_REG_H_ */ diff --git a/usr.sbin/bhyve/net_utils.c b/usr.sbin/bhyve/net_utils.c index dc29124e84bd..32b15fc7f54b 100644 --- a/usr.sbin/bhyve/net_utils.c +++ b/usr.sbin/bhyve/net_utils.c @@ -21,17 +21,21 @@ * 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 "net_utils.h" -#include "bhyverun.h" -#include <md5.h> +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/types.h> #include <net/ethernet.h> -#include <string.h> -#include <stdio.h> + #include <errno.h> +#include <md5.h> +#include <stdio.h> +#include <string.h> + +#include "bhyverun.h" +#include "net_utils.h" int net_parsemac(char *mac_str, uint8_t *mac_addr) diff --git a/usr.sbin/bhyve/pci_hda.c b/usr.sbin/bhyve/pci_hda.c new file mode 100644 index 000000000000..ace88274ac91 --- /dev/null +++ b/usr.sbin/bhyve/pci_hda.c @@ -0,0 +1,1331 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2016 Alex Teaca <iateaca@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 ``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 <time.h> + +#include "pci_hda.h" +#include "bhyverun.h" +#include "pci_emul.h" +#include "hdac_reg.h" + +/* + * HDA defines + */ +#define PCIR_HDCTL 0x40 +#define INTEL_VENDORID 0x8086 +#define HDA_INTEL_82801G 0x27d8 + +#define HDA_IOSS_NO 0x08 +#define HDA_OSS_NO 0x04 +#define HDA_ISS_NO 0x04 +#define HDA_CODEC_MAX 0x0f +#define HDA_LAST_OFFSET \ + (0x2084 + ((HDA_ISS_NO) * 0x20) + ((HDA_OSS_NO) * 0x20)) +#define HDA_SET_REG_TABLE_SZ \ + (0x80 + ((HDA_ISS_NO) * 0x20) + ((HDA_OSS_NO) * 0x20)) +#define HDA_CORB_ENTRY_LEN 0x04 +#define HDA_RIRB_ENTRY_LEN 0x08 +#define HDA_BDL_ENTRY_LEN 0x10 +#define HDA_DMA_PIB_ENTRY_LEN 0x08 +#define HDA_STREAM_TAGS_CNT 0x10 +#define HDA_STREAM_REGS_BASE 0x80 +#define HDA_STREAM_REGS_LEN 0x20 + +#define HDA_DMA_ACCESS_LEN (sizeof(uint32_t)) +#define HDA_BDL_MAX_LEN 0x0100 + +#define HDAC_SDSTS_FIFORDY (1 << 5) + +#define HDA_RIRBSTS_IRQ_MASK (HDAC_RIRBSTS_RINTFL | HDAC_RIRBSTS_RIRBOIS) +#define HDA_STATESTS_IRQ_MASK ((1 << HDA_CODEC_MAX) - 1) +#define HDA_SDSTS_IRQ_MASK \ + (HDAC_SDSTS_DESE | HDAC_SDSTS_FIFOE | HDAC_SDSTS_BCIS) + +/* + * HDA data structures + */ + +struct hda_softc; + +typedef void (*hda_set_reg_handler)(struct hda_softc *sc, uint32_t offset, + uint32_t old); + +struct hda_bdle { + uint32_t addrh; + uint32_t addrl; + uint32_t ioc; + uint32_t len; +} __packed; + +struct hda_bdle_desc { + void *addr; + uint8_t ioc; + uint32_t len; +}; + +struct hda_codec_cmd_ctl { + char *name; + void *dma_vaddr; + uint8_t run; + uint16_t rp; + uint16_t size; + uint16_t wp; +}; + +struct hda_stream_desc { + uint8_t dir; + uint8_t run; + uint8_t stream; + + /* bp is the no. of bytes transferred in the current bdle */ + uint32_t bp; + /* be is the no. of bdles transferred in the bdl */ + uint32_t be; + + uint32_t bdl_cnt; + struct hda_bdle_desc bdl[HDA_BDL_MAX_LEN]; +}; + +struct hda_softc { + struct pci_devinst *pci_dev; + uint32_t regs[HDA_LAST_OFFSET]; + + uint8_t lintr; + uint8_t rirb_cnt; + uint64_t wall_clock_start; + + struct hda_codec_cmd_ctl corb; + struct hda_codec_cmd_ctl rirb; + + uint8_t codecs_no; + struct hda_codec_inst *codecs[HDA_CODEC_MAX]; + + /* Base Address of the DMA Position Buffer */ + void *dma_pib_vaddr; + + struct hda_stream_desc streams[HDA_IOSS_NO]; + /* 2 tables for output and input */ + uint8_t stream_map[2][HDA_STREAM_TAGS_CNT]; +}; + +/* + * HDA module function declarations + */ +static inline void hda_set_reg_by_offset(struct hda_softc *sc, uint32_t offset, + uint32_t value); +static inline uint32_t hda_get_reg_by_offset(struct hda_softc *sc, + uint32_t offset); +static inline void hda_set_field_by_offset(struct hda_softc *sc, + uint32_t offset, uint32_t mask, uint32_t value); + +static uint8_t hda_parse_config(const char *opts, const char *key, char *val); +static struct hda_softc *hda_init(const char *opts); +static void hda_update_intr(struct hda_softc *sc); +static void hda_response_interrupt(struct hda_softc *sc); +static int hda_codec_constructor(struct hda_softc *sc, + struct hda_codec_class *codec, const char *play, const char *rec, + const char *opts); +static struct hda_codec_class *hda_find_codec_class(const char *name); + +static int hda_send_command(struct hda_softc *sc, uint32_t verb); +static int hda_notify_codecs(struct hda_softc *sc, uint8_t run, + uint8_t stream, uint8_t dir); +static void hda_reset(struct hda_softc *sc); +static void hda_reset_regs(struct hda_softc *sc); +static void hda_stream_reset(struct hda_softc *sc, uint8_t stream_ind); +static int hda_stream_start(struct hda_softc *sc, uint8_t stream_ind); +static int hda_stream_stop(struct hda_softc *sc, uint8_t stream_ind); +static uint32_t hda_read(struct hda_softc *sc, uint32_t offset); +static int hda_write(struct hda_softc *sc, uint32_t offset, uint8_t size, + uint32_t value); + +static inline void hda_print_cmd_ctl_data(struct hda_codec_cmd_ctl *p); +static int hda_corb_start(struct hda_softc *sc); +static int hda_corb_run(struct hda_softc *sc); +static int hda_rirb_start(struct hda_softc *sc); + +static void *hda_dma_get_vaddr(struct hda_softc *sc, uint64_t dma_paddr, + size_t len); +static void hda_dma_st_dword(void *dma_vaddr, uint32_t data); +static uint32_t hda_dma_ld_dword(void *dma_vaddr); + +static inline uint8_t hda_get_stream_by_offsets(uint32_t offset, + uint8_t reg_offset); +static inline uint32_t hda_get_offset_stream(uint8_t stream_ind); + +static void hda_set_gctl(struct hda_softc *sc, uint32_t offset, uint32_t old); +static void hda_set_statests(struct hda_softc *sc, uint32_t offset, + uint32_t old); +static void hda_set_corbwp(struct hda_softc *sc, uint32_t offset, uint32_t old); +static void hda_set_corbctl(struct hda_softc *sc, uint32_t offset, + uint32_t old); +static void hda_set_rirbctl(struct hda_softc *sc, uint32_t offset, + uint32_t old); +static void hda_set_rirbsts(struct hda_softc *sc, uint32_t offset, + uint32_t old); +static void hda_set_dpiblbase(struct hda_softc *sc, uint32_t offset, + uint32_t old); +static void hda_set_sdctl(struct hda_softc *sc, uint32_t offset, uint32_t old); +static void hda_set_sdctl2(struct hda_softc *sc, uint32_t offset, uint32_t old); +static void hda_set_sdsts(struct hda_softc *sc, uint32_t offset, uint32_t old); + +static int hda_signal_state_change(struct hda_codec_inst *hci); +static int hda_response(struct hda_codec_inst *hci, uint32_t response, + uint8_t unsol); +static int hda_transfer(struct hda_codec_inst *hci, uint8_t stream, + uint8_t dir, void *buf, size_t count); + +static void hda_set_pib(struct hda_softc *sc, uint8_t stream_ind, uint32_t pib); +static uint64_t hda_get_clock_ns(void); + +/* + * PCI HDA function declarations + */ +static int pci_hda_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts); +static void pci_hda_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, + int baridx, uint64_t offset, int size, uint64_t value); +static uint64_t pci_hda_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, + int baridx, uint64_t offset, int size); +/* + * HDA global data + */ + +static const hda_set_reg_handler hda_set_reg_table[] = { + [HDAC_GCTL] = hda_set_gctl, + [HDAC_STATESTS] = hda_set_statests, + [HDAC_CORBWP] = hda_set_corbwp, + [HDAC_CORBCTL] = hda_set_corbctl, + [HDAC_RIRBCTL] = hda_set_rirbctl, + [HDAC_RIRBSTS] = hda_set_rirbsts, + [HDAC_DPIBLBASE] = hda_set_dpiblbase, + +#define HDAC_ISTREAM(n, iss, oss) \ + [_HDAC_ISDCTL(n, iss, oss)] = hda_set_sdctl, \ + [_HDAC_ISDCTL(n, iss, oss) + 2] = hda_set_sdctl2, \ + [_HDAC_ISDSTS(n, iss, oss)] = hda_set_sdsts, \ + +#define HDAC_OSTREAM(n, iss, oss) \ + [_HDAC_OSDCTL(n, iss, oss)] = hda_set_sdctl, \ + [_HDAC_OSDCTL(n, iss, oss) + 2] = hda_set_sdctl2, \ + [_HDAC_OSDSTS(n, iss, oss)] = hda_set_sdsts, \ + + HDAC_ISTREAM(0, HDA_ISS_NO, HDA_OSS_NO) + HDAC_ISTREAM(1, HDA_ISS_NO, HDA_OSS_NO) + HDAC_ISTREAM(2, HDA_ISS_NO, HDA_OSS_NO) + HDAC_ISTREAM(3, HDA_ISS_NO, HDA_OSS_NO) + + HDAC_OSTREAM(0, HDA_ISS_NO, HDA_OSS_NO) + HDAC_OSTREAM(1, HDA_ISS_NO, HDA_OSS_NO) + HDAC_OSTREAM(2, HDA_ISS_NO, HDA_OSS_NO) + HDAC_OSTREAM(3, HDA_ISS_NO, HDA_OSS_NO) + + [HDA_SET_REG_TABLE_SZ] = NULL, +}; + +static const uint16_t hda_corb_sizes[] = { + [HDAC_CORBSIZE_CORBSIZE_2] = 2, + [HDAC_CORBSIZE_CORBSIZE_16] = 16, + [HDAC_CORBSIZE_CORBSIZE_256] = 256, + [HDAC_CORBSIZE_CORBSIZE_MASK] = 0, +}; + +static const uint16_t hda_rirb_sizes[] = { + [HDAC_RIRBSIZE_RIRBSIZE_2] = 2, + [HDAC_RIRBSIZE_RIRBSIZE_16] = 16, + [HDAC_RIRBSIZE_RIRBSIZE_256] = 256, + [HDAC_RIRBSIZE_RIRBSIZE_MASK] = 0, +}; + +static struct hda_ops hops = { + .signal = hda_signal_state_change, + .response = hda_response, + .transfer = hda_transfer, +}; + +struct pci_devemu pci_de_hda = { + .pe_emu = "hda", + .pe_init = pci_hda_init, + .pe_barwrite = pci_hda_write, + .pe_barread = pci_hda_read +}; + +PCI_EMUL_SET(pci_de_hda); + +SET_DECLARE(hda_codec_class_set, struct hda_codec_class); + +#if DEBUG_HDA == 1 +FILE *dbg; +#endif + +/* + * HDA module function definitions + */ + +static inline void +hda_set_reg_by_offset(struct hda_softc *sc, uint32_t offset, uint32_t value) +{ + assert(offset < HDA_LAST_OFFSET); + sc->regs[offset] = value; +} + +static inline uint32_t +hda_get_reg_by_offset(struct hda_softc *sc, uint32_t offset) +{ + assert(offset < HDA_LAST_OFFSET); + return sc->regs[offset]; +} + +static inline void +hda_set_field_by_offset(struct hda_softc *sc, uint32_t offset, + uint32_t mask, uint32_t value) +{ + uint32_t reg_value = 0; + + reg_value = hda_get_reg_by_offset(sc, offset); + + reg_value &= ~mask; + reg_value |= (value & mask); + + hda_set_reg_by_offset(sc, offset, reg_value); +} + +static uint8_t +hda_parse_config(const char *opts, const char *key, char *val) +{ + char buf[64]; + char *s = buf; + char *tmp = NULL; + size_t len; + int i; + + if (!opts) + return (0); + + len = strlen(opts); + if (len >= sizeof(buf)) { + DPRINTF("Opts too big\n"); + return (0); + } + + DPRINTF("opts: %s\n", opts); + + strcpy(buf, opts); + + for (i = 0; i < len; i++) + if (buf[i] == ',') { + buf[i] = 0; + tmp = buf + i + 1; + break; + } + + if (!memcmp(s, key, strlen(key))) { + strncpy(val, s + strlen(key), 64); + return (1); + } + + if (!tmp) + return (0); + + s = tmp; + if (!memcmp(s, key, strlen(key))) { + strncpy(val, s + strlen(key), 64); + return (1); + } + + return (0); +} + +static struct hda_softc * +hda_init(const char *opts) +{ + struct hda_softc *sc = NULL; + struct hda_codec_class *codec = NULL; + char play[64]; + char rec[64]; + int err, p, r; + +#if DEBUG_HDA == 1 + dbg = fopen("/tmp/bhyve_hda.log", "w+"); +#endif + + DPRINTF("opts: %s\n", opts); + + sc = calloc(1, sizeof(*sc)); + if (!sc) + return (NULL); + + hda_reset_regs(sc); + + /* + * TODO search all the codecs declared in opts + * For now we play with one single codec + */ + codec = hda_find_codec_class("hda_codec"); + if (codec) { + p = hda_parse_config(opts, "play=", play); + r = hda_parse_config(opts, "rec=", rec); + DPRINTF("play: %s rec: %s\n", play, rec); + if (p | r) { + err = hda_codec_constructor(sc, codec, p ? \ + play : NULL, r ? rec : NULL, NULL); + assert(!err); + } + } + + return (sc); +} + +static void +hda_update_intr(struct hda_softc *sc) +{ + struct pci_devinst *pi = sc->pci_dev; + uint32_t intctl = hda_get_reg_by_offset(sc, HDAC_INTCTL); + uint32_t intsts = 0; + uint32_t sdsts = 0; + uint32_t rirbsts = 0; + uint32_t wakeen = 0; + uint32_t statests = 0; + uint32_t off = 0; + int i; + + /* update the CIS bits */ + rirbsts = hda_get_reg_by_offset(sc, HDAC_RIRBSTS); + if (rirbsts & (HDAC_RIRBSTS_RINTFL | HDAC_RIRBSTS_RIRBOIS)) + intsts |= HDAC_INTSTS_CIS; + + wakeen = hda_get_reg_by_offset(sc, HDAC_WAKEEN); + statests = hda_get_reg_by_offset(sc, HDAC_STATESTS); + if (statests & wakeen) + intsts |= HDAC_INTSTS_CIS; + + /* update the SIS bits */ + for (i = 0; i < HDA_IOSS_NO; i++) { + off = hda_get_offset_stream(i); + sdsts = hda_get_reg_by_offset(sc, off + HDAC_SDSTS); + if (sdsts & HDAC_SDSTS_BCIS) + intsts |= (1 << i); + } + + /* update the GIS bit */ + if (intsts) + intsts |= HDAC_INTSTS_GIS; + + hda_set_reg_by_offset(sc, HDAC_INTSTS, intsts); + + if ((intctl & HDAC_INTCTL_GIE) && ((intsts & \ + ~HDAC_INTSTS_GIS) & intctl)) { + if (!sc->lintr) { + pci_lintr_assert(pi); + sc->lintr = 1; + } + } else { + if (sc->lintr) { + pci_lintr_deassert(pi); + sc->lintr = 0; + } + } +} + +static void +hda_response_interrupt(struct hda_softc *sc) +{ + uint8_t rirbctl = hda_get_reg_by_offset(sc, HDAC_RIRBCTL); + + if ((rirbctl & HDAC_RIRBCTL_RINTCTL) && sc->rirb_cnt) { + sc->rirb_cnt = 0; + hda_set_field_by_offset(sc, HDAC_RIRBSTS, HDAC_RIRBSTS_RINTFL, + HDAC_RIRBSTS_RINTFL); + hda_update_intr(sc); + } +} + +static int +hda_codec_constructor(struct hda_softc *sc, struct hda_codec_class *codec, + const char *play, const char *rec, const char *opts) +{ + struct hda_codec_inst *hci = NULL; + + if (sc->codecs_no >= HDA_CODEC_MAX) + return (-1); + + hci = calloc(1, sizeof(struct hda_codec_inst)); + if (!hci) + return (-1); + + hci->hda = sc; + hci->hops = &hops; + hci->cad = sc->codecs_no; + hci->codec = codec; + + sc->codecs[sc->codecs_no++] = hci; + + if (!codec->init) { + DPRINTF("This codec does not implement the init function\n"); + return (-1); + } + + return (codec->init(hci, play, rec, opts)); +} + +static struct hda_codec_class * +hda_find_codec_class(const char *name) +{ + struct hda_codec_class **pdpp = NULL, *pdp = NULL; + + SET_FOREACH(pdpp, hda_codec_class_set) { + pdp = *pdpp; + if (!strcmp(pdp->name, name)) { + return (pdp); + } + } + + return (NULL); +} + +static int +hda_send_command(struct hda_softc *sc, uint32_t verb) +{ + struct hda_codec_inst *hci = NULL; + struct hda_codec_class *codec = NULL; + uint8_t cad = (verb >> HDA_CMD_CAD_SHIFT) & 0x0f; + + hci = sc->codecs[cad]; + if (!hci) + return (-1); + + DPRINTF("cad: 0x%x verb: 0x%x\n", cad, verb); + + codec = hci->codec; + assert(codec); + + if (!codec->command) { + DPRINTF("This codec does not implement the command function\n"); + return (-1); + } + + return (codec->command(hci, verb)); +} + +static int +hda_notify_codecs(struct hda_softc *sc, uint8_t run, uint8_t stream, + uint8_t dir) +{ + struct hda_codec_inst *hci = NULL; + struct hda_codec_class *codec = NULL; + int err; + int i; + + /* Notify each codec */ + for (i = 0; i < sc->codecs_no; i++) { + hci = sc->codecs[i]; + assert(hci); + + codec = hci->codec; + assert(codec); + + if (codec->notify) { + err = codec->notify(hci, run, stream, dir); + if (!err) + break; + } + } + + return (i == sc->codecs_no ? (-1) : 0); +} + +static void +hda_reset(struct hda_softc *sc) +{ + int i; + struct hda_codec_inst *hci = NULL; + struct hda_codec_class *codec = NULL; + + hda_reset_regs(sc); + + /* Reset each codec */ + for (i = 0; i < sc->codecs_no; i++) { + hci = sc->codecs[i]; + assert(hci); + + codec = hci->codec; + assert(codec); + + if (codec->reset) + codec->reset(hci); + } + + sc->wall_clock_start = hda_get_clock_ns(); +} + +static void +hda_reset_regs(struct hda_softc *sc) +{ + uint32_t off = 0; + uint8_t i; + + DPRINTF("Reset the HDA controller registers ...\n"); + + memset(sc->regs, 0, sizeof(sc->regs)); + + hda_set_reg_by_offset(sc, HDAC_GCAP, + HDAC_GCAP_64OK | + (HDA_ISS_NO << HDAC_GCAP_ISS_SHIFT) | + (HDA_OSS_NO << HDAC_GCAP_OSS_SHIFT)); + hda_set_reg_by_offset(sc, HDAC_VMAJ, 0x01); + hda_set_reg_by_offset(sc, HDAC_OUTPAY, 0x3c); + hda_set_reg_by_offset(sc, HDAC_INPAY, 0x1d); + hda_set_reg_by_offset(sc, HDAC_CORBSIZE, + HDAC_CORBSIZE_CORBSZCAP_256 | HDAC_CORBSIZE_CORBSIZE_256); + hda_set_reg_by_offset(sc, HDAC_RIRBSIZE, + HDAC_RIRBSIZE_RIRBSZCAP_256 | HDAC_RIRBSIZE_RIRBSIZE_256); + + for (i = 0; i < HDA_IOSS_NO; i++) { + off = hda_get_offset_stream(i); + hda_set_reg_by_offset(sc, off + HDAC_SDFIFOS, HDA_FIFO_SIZE); + } +} + +static void +hda_stream_reset(struct hda_softc *sc, uint8_t stream_ind) +{ + struct hda_stream_desc *st = &sc->streams[stream_ind]; + uint32_t off = hda_get_offset_stream(stream_ind); + + DPRINTF("Reset the HDA stream: 0x%x\n", stream_ind); + + /* Reset the Stream Descriptor registers */ + memset(sc->regs + HDA_STREAM_REGS_BASE + off, 0, HDA_STREAM_REGS_LEN); + + /* Reset the Stream Descriptor */ + memset(st, 0, sizeof(*st)); + + hda_set_field_by_offset(sc, off + HDAC_SDSTS, + HDAC_SDSTS_FIFORDY, HDAC_SDSTS_FIFORDY); + hda_set_field_by_offset(sc, off + HDAC_SDCTL0, + HDAC_SDCTL_SRST, HDAC_SDCTL_SRST); +} + +static int +hda_stream_start(struct hda_softc *sc, uint8_t stream_ind) +{ + struct hda_stream_desc *st = &sc->streams[stream_ind]; + struct hda_bdle_desc *bdle_desc = NULL; + struct hda_bdle *bdle = NULL; + uint32_t lvi = 0; + uint32_t bdl_cnt = 0; + uint64_t bdpl = 0; + uint64_t bdpu = 0; + uint64_t bdl_paddr = 0; + void *bdl_vaddr = NULL; + uint32_t bdle_sz = 0; + uint64_t bdle_addrl = 0; + uint64_t bdle_addrh = 0; + uint64_t bdle_paddr = 0; + void *bdle_vaddr = NULL; + uint32_t off = hda_get_offset_stream(stream_ind); + uint32_t sdctl = 0; + uint8_t strm = 0; + uint8_t dir = 0; + int i; + + assert(!st->run); + + lvi = hda_get_reg_by_offset(sc, off + HDAC_SDLVI); + bdpl = hda_get_reg_by_offset(sc, off + HDAC_SDBDPL); + bdpu = hda_get_reg_by_offset(sc, off + HDAC_SDBDPU); + + bdl_cnt = lvi + 1; + assert(bdl_cnt <= HDA_BDL_MAX_LEN); + + bdl_paddr = bdpl | (bdpu << 32); + bdl_vaddr = hda_dma_get_vaddr(sc, bdl_paddr, + HDA_BDL_ENTRY_LEN * bdl_cnt); + if (!bdl_vaddr) { + DPRINTF("Fail to get the guest virtual address\n"); + return (-1); + } + + DPRINTF("stream: 0x%x bdl_cnt: 0x%x bdl_paddr: 0x%lx\n", + stream_ind, bdl_cnt, bdl_paddr); + + st->bdl_cnt = bdl_cnt; + + bdle = (struct hda_bdle *)bdl_vaddr; + for (i = 0; i < bdl_cnt; i++, bdle++) { + bdle_sz = bdle->len; + assert(!(bdle_sz % HDA_DMA_ACCESS_LEN)); + + bdle_addrl = bdle->addrl; + bdle_addrh = bdle->addrh; + + bdle_paddr = bdle_addrl | (bdle_addrh << 32); + bdle_vaddr = hda_dma_get_vaddr(sc, bdle_paddr, bdle_sz); + if (!bdle_vaddr) { + DPRINTF("Fail to get the guest virtual address\n"); + return (-1); + } + + bdle_desc = &st->bdl[i]; + bdle_desc->addr = bdle_vaddr; + bdle_desc->len = bdle_sz; + bdle_desc->ioc = bdle->ioc; + + DPRINTF("bdle: 0x%x bdle_sz: 0x%x\n", i, bdle_sz); + } + + sdctl = hda_get_reg_by_offset(sc, off + HDAC_SDCTL0); + strm = (sdctl >> 20) & 0x0f; + dir = stream_ind >= HDA_ISS_NO; + + DPRINTF("strm: 0x%x, dir: 0x%x\n", strm, dir); + + sc->stream_map[dir][strm] = stream_ind; + st->stream = strm; + st->dir = dir; + st->bp = 0; + st->be = 0; + + hda_set_pib(sc, stream_ind, 0); + + st->run = 1; + + hda_notify_codecs(sc, 1, strm, dir); + + return (0); +} + +static int +hda_stream_stop(struct hda_softc *sc, uint8_t stream_ind) +{ + struct hda_stream_desc *st = &sc->streams[stream_ind]; + uint8_t strm = st->stream; + uint8_t dir = st->dir; + + DPRINTF("stream: 0x%x, strm: 0x%x, dir: 0x%x\n", stream_ind, strm, dir); + + st->run = 0; + + hda_notify_codecs(sc, 0, strm, dir); + + return (0); +} + +static uint32_t +hda_read(struct hda_softc *sc, uint32_t offset) +{ + if (offset == HDAC_WALCLK) + return (24 * (hda_get_clock_ns() - \ + sc->wall_clock_start) / 1000); + + return (hda_get_reg_by_offset(sc, offset)); +} + +static int +hda_write(struct hda_softc *sc, uint32_t offset, uint8_t size, uint32_t value) +{ + uint32_t old = hda_get_reg_by_offset(sc, offset); + uint32_t masks[] = {0x00000000, 0x000000ff, 0x0000ffff, + 0x00ffffff, 0xffffffff}; + hda_set_reg_handler set_reg_handler = hda_set_reg_table[offset]; + + hda_set_field_by_offset(sc, offset, masks[size], value); + + if (set_reg_handler) + set_reg_handler(sc, offset, old); + + return (0); +} + +static inline void +hda_print_cmd_ctl_data(struct hda_codec_cmd_ctl *p) +{ +#if DEBUG_HDA == 1 + char *name = p->name; +#endif + DPRINTF("%s size: %d\n", name, p->size); + DPRINTF("%s dma_vaddr: %p\n", name, p->dma_vaddr); + DPRINTF("%s wp: 0x%x\n", name, p->wp); + DPRINTF("%s rp: 0x%x\n", name, p->rp); +} + +static int +hda_corb_start(struct hda_softc *sc) +{ + struct hda_codec_cmd_ctl *corb = &sc->corb; + uint8_t corbsize = 0; + uint64_t corblbase = 0; + uint64_t corbubase = 0; + uint64_t corbpaddr = 0; + + corb->name = "CORB"; + + corbsize = hda_get_reg_by_offset(sc, HDAC_CORBSIZE) & \ + HDAC_CORBSIZE_CORBSIZE_MASK; + corb->size = hda_corb_sizes[corbsize]; + + if (!corb->size) { + DPRINTF("Invalid corb size\n"); + return (-1); + } + + corblbase = hda_get_reg_by_offset(sc, HDAC_CORBLBASE); + corbubase = hda_get_reg_by_offset(sc, HDAC_CORBUBASE); + + corbpaddr = corblbase | (corbubase << 32); + DPRINTF("CORB dma_paddr: %p\n", (void *)corbpaddr); + + corb->dma_vaddr = hda_dma_get_vaddr(sc, corbpaddr, + HDA_CORB_ENTRY_LEN * corb->size); + if (!corb->dma_vaddr) { + DPRINTF("Fail to get the guest virtual address\n"); + return (-1); + } + + corb->wp = hda_get_reg_by_offset(sc, HDAC_CORBWP); + corb->rp = hda_get_reg_by_offset(sc, HDAC_CORBRP); + + corb->run = 1; + + hda_print_cmd_ctl_data(corb); + + return (0); +} + +static int +hda_corb_run(struct hda_softc *sc) +{ + struct hda_codec_cmd_ctl *corb = &sc->corb; + uint32_t verb = 0; + int err; + + corb->wp = hda_get_reg_by_offset(sc, HDAC_CORBWP); + + while (corb->rp != corb->wp && corb->run) { + corb->rp++; + corb->rp %= corb->size; + + verb = hda_dma_ld_dword(corb->dma_vaddr + \ + HDA_CORB_ENTRY_LEN * corb->rp); + + err = hda_send_command(sc, verb); + assert(!err); + } + + hda_set_reg_by_offset(sc, HDAC_CORBRP, corb->rp); + + if (corb->run) + hda_response_interrupt(sc); + + return (0); +} + +static int +hda_rirb_start(struct hda_softc *sc) +{ + struct hda_codec_cmd_ctl *rirb = &sc->rirb; + uint8_t rirbsize = 0; + uint64_t rirblbase = 0; + uint64_t rirbubase = 0; + uint64_t rirbpaddr = 0; + + rirb->name = "RIRB"; + + rirbsize = hda_get_reg_by_offset(sc, HDAC_RIRBSIZE) & \ + HDAC_RIRBSIZE_RIRBSIZE_MASK; + rirb->size = hda_rirb_sizes[rirbsize]; + + if (!rirb->size) { + DPRINTF("Invalid rirb size\n"); + return (-1); + } + + rirblbase = hda_get_reg_by_offset(sc, HDAC_RIRBLBASE); + rirbubase = hda_get_reg_by_offset(sc, HDAC_RIRBUBASE); + + rirbpaddr = rirblbase | (rirbubase << 32); + DPRINTF("RIRB dma_paddr: %p\n", (void *)rirbpaddr); + + rirb->dma_vaddr = hda_dma_get_vaddr(sc, rirbpaddr, + HDA_RIRB_ENTRY_LEN * rirb->size); + if (!rirb->dma_vaddr) { + DPRINTF("Fail to get the guest virtual address\n"); + return (-1); + } + + rirb->wp = hda_get_reg_by_offset(sc, HDAC_RIRBWP); + rirb->rp = 0x0000; + + rirb->run = 1; + + hda_print_cmd_ctl_data(rirb); + + return (0); +} + +static void * +hda_dma_get_vaddr(struct hda_softc *sc, uint64_t dma_paddr, size_t len) +{ + struct pci_devinst *pi = sc->pci_dev; + + assert(pi); + + return (paddr_guest2host(pi->pi_vmctx, (uintptr_t)dma_paddr, len)); +} + +static void +hda_dma_st_dword(void *dma_vaddr, uint32_t data) +{ + *(uint32_t*)dma_vaddr = data; +} + +static uint32_t +hda_dma_ld_dword(void *dma_vaddr) +{ + return (*(uint32_t*)dma_vaddr); +} + +static inline uint8_t +hda_get_stream_by_offsets(uint32_t offset, uint8_t reg_offset) +{ + uint8_t stream_ind = (offset - reg_offset) >> 5; + + assert(stream_ind < HDA_IOSS_NO); + + return (stream_ind); +} + +static inline uint32_t +hda_get_offset_stream(uint8_t stream_ind) +{ + return (stream_ind << 5); +} + +static void +hda_set_gctl(struct hda_softc *sc, uint32_t offset, uint32_t old) +{ + uint32_t value = hda_get_reg_by_offset(sc, offset); + + if (!(value & HDAC_GCTL_CRST)) { + hda_reset(sc); + } +} + +static void +hda_set_statests(struct hda_softc *sc, uint32_t offset, uint32_t old) +{ + uint32_t value = hda_get_reg_by_offset(sc, offset); + + hda_set_reg_by_offset(sc, offset, old); + + /* clear the corresponding bits written by the software (guest) */ + hda_set_field_by_offset(sc, offset, value & HDA_STATESTS_IRQ_MASK, 0); + + hda_update_intr(sc); +} + +static void +hda_set_corbwp(struct hda_softc *sc, uint32_t offset, uint32_t old) +{ + hda_corb_run(sc); +} + +static void +hda_set_corbctl(struct hda_softc *sc, uint32_t offset, uint32_t old) +{ + uint32_t value = hda_get_reg_by_offset(sc, offset); + int err; + struct hda_codec_cmd_ctl *corb = NULL; + + if (value & HDAC_CORBCTL_CORBRUN) { + if (!(old & HDAC_CORBCTL_CORBRUN)) { + err = hda_corb_start(sc); + assert(!err); + } + } else { + corb = &sc->corb; + memset(corb, 0, sizeof(*corb)); + } + + hda_corb_run(sc); +} + +static void +hda_set_rirbctl(struct hda_softc *sc, uint32_t offset, uint32_t old) +{ + uint32_t value = hda_get_reg_by_offset(sc, offset); + int err; + struct hda_codec_cmd_ctl *rirb = NULL; + + if (value & HDAC_RIRBCTL_RIRBDMAEN) { + err = hda_rirb_start(sc); + assert(!err); + } else { + rirb = &sc->rirb; + memset(rirb, 0, sizeof(*rirb)); + } +} + +static void +hda_set_rirbsts(struct hda_softc *sc, uint32_t offset, uint32_t old) +{ + uint32_t value = hda_get_reg_by_offset(sc, offset); + + hda_set_reg_by_offset(sc, offset, old); + + /* clear the corresponding bits written by the software (guest) */ + hda_set_field_by_offset(sc, offset, value & HDA_RIRBSTS_IRQ_MASK, 0); + + hda_update_intr(sc); +} + +static void +hda_set_dpiblbase(struct hda_softc *sc, uint32_t offset, uint32_t old) +{ + uint32_t value = hda_get_reg_by_offset(sc, offset); + uint64_t dpiblbase = 0; + uint64_t dpibubase = 0; + uint64_t dpibpaddr = 0; + + if ((value & HDAC_DPLBASE_DPLBASE_DMAPBE) != (old & \ + HDAC_DPLBASE_DPLBASE_DMAPBE)) { + if (value & HDAC_DPLBASE_DPLBASE_DMAPBE) { + dpiblbase = value & HDAC_DPLBASE_DPLBASE_MASK; + dpibubase = hda_get_reg_by_offset(sc, HDAC_DPIBUBASE); + + dpibpaddr = dpiblbase | (dpibubase << 32); + DPRINTF("DMA Position In Buffer dma_paddr: %p\n", + (void *)dpibpaddr); + + sc->dma_pib_vaddr = hda_dma_get_vaddr(sc, dpibpaddr, + HDA_DMA_PIB_ENTRY_LEN * HDA_IOSS_NO); + if (!sc->dma_pib_vaddr) { + DPRINTF("Fail to get the guest \ + virtual address\n"); + assert(0); + } + } else { + DPRINTF("DMA Position In Buffer Reset\n"); + sc->dma_pib_vaddr = NULL; + } + } +} + +static void +hda_set_sdctl(struct hda_softc *sc, uint32_t offset, uint32_t old) +{ + uint8_t stream_ind = hda_get_stream_by_offsets(offset, HDAC_SDCTL0); + uint32_t value = hda_get_reg_by_offset(sc, offset); + int err; + + DPRINTF("stream_ind: 0x%x old: 0x%x value: 0x%x\n", + stream_ind, old, value); + + if (value & HDAC_SDCTL_SRST) { + hda_stream_reset(sc, stream_ind); + } + + if ((value & HDAC_SDCTL_RUN) != (old & HDAC_SDCTL_RUN)) { + if (value & HDAC_SDCTL_RUN) { + err = hda_stream_start(sc, stream_ind); + assert(!err); + } else { + err = hda_stream_stop(sc, stream_ind); + assert(!err); + } + } +} + +static void +hda_set_sdctl2(struct hda_softc *sc, uint32_t offset, uint32_t old) +{ + uint32_t value = hda_get_reg_by_offset(sc, offset); + + hda_set_field_by_offset(sc, offset - 2, 0x00ff0000, value << 16); +} + +static void +hda_set_sdsts(struct hda_softc *sc, uint32_t offset, uint32_t old) +{ + uint32_t value = hda_get_reg_by_offset(sc, offset); + + hda_set_reg_by_offset(sc, offset, old); + + /* clear the corresponding bits written by the software (guest) */ + hda_set_field_by_offset(sc, offset, value & HDA_SDSTS_IRQ_MASK, 0); + + hda_update_intr(sc); +} + +static int +hda_signal_state_change(struct hda_codec_inst *hci) +{ + struct hda_softc *sc = NULL; + uint32_t sdiwake = 0; + + assert(hci); + assert(hci->hda); + + DPRINTF("cad: 0x%x\n", hci->cad); + + sc = hci->hda; + sdiwake = 1 << hci->cad; + + hda_set_field_by_offset(sc, HDAC_STATESTS, sdiwake, sdiwake); + hda_update_intr(sc); + + return (0); +} + +static int +hda_response(struct hda_codec_inst *hci, uint32_t response, uint8_t unsol) +{ + struct hda_softc *sc = NULL; + struct hda_codec_cmd_ctl *rirb = NULL; + uint32_t response_ex = 0; + uint8_t rintcnt = 0; + + assert(hci); + assert(hci->cad <= HDA_CODEC_MAX); + + response_ex = hci->cad | unsol; + + sc = hci->hda; + assert(sc); + + rirb = &sc->rirb; + + if (rirb->run) { + rirb->wp++; + rirb->wp %= rirb->size; + + hda_dma_st_dword(rirb->dma_vaddr + HDA_RIRB_ENTRY_LEN * \ + rirb->wp, response); + hda_dma_st_dword(rirb->dma_vaddr + HDA_RIRB_ENTRY_LEN * \ + rirb->wp + 0x04, response_ex); + + hda_set_reg_by_offset(sc, HDAC_RIRBWP, rirb->wp); + + sc->rirb_cnt++; + } + + rintcnt = hda_get_reg_by_offset(sc, HDAC_RINTCNT); + if (sc->rirb_cnt == rintcnt) + hda_response_interrupt(sc); + + return (0); +} + +static int +hda_transfer(struct hda_codec_inst *hci, uint8_t stream, uint8_t dir, + void *buf, size_t count) +{ + struct hda_softc *sc = NULL; + struct hda_stream_desc *st = NULL; + struct hda_bdle_desc *bdl = NULL; + struct hda_bdle_desc *bdle_desc = NULL; + uint8_t stream_ind = 0; + uint32_t lpib = 0; + uint32_t off = 0; + size_t left = 0; + uint8_t irq = 0; + + assert(hci); + assert(hci->hda); + assert(buf); + assert(!(count % HDA_DMA_ACCESS_LEN)); + + if (!stream) { + DPRINTF("Invalid stream\n"); + return (-1); + } + + sc = hci->hda; + + assert(stream < HDA_STREAM_TAGS_CNT); + stream_ind = sc->stream_map[dir][stream]; + + if (!dir) + assert(stream_ind < HDA_ISS_NO); + else + assert(stream_ind >= HDA_ISS_NO && stream_ind < HDA_IOSS_NO); + + st = &sc->streams[stream_ind]; + if (!st->run) { + DPRINTF("Stream 0x%x stopped\n", stream); + return (-1); + } + + assert(st->stream == stream); + + off = hda_get_offset_stream(stream_ind); + + lpib = hda_get_reg_by_offset(sc, off + HDAC_SDLPIB); + + bdl = st->bdl; + + assert(st->be < st->bdl_cnt); + assert(st->bp < bdl[st->be].len); + + left = count; + while (left) { + bdle_desc = &bdl[st->be]; + + if (dir) + *(uint32_t *)buf = \ + hda_dma_ld_dword(bdle_desc->addr + st->bp); + else + hda_dma_st_dword(bdle_desc->addr + st->bp, + *(uint32_t *)buf); + + buf += HDA_DMA_ACCESS_LEN; + st->bp += HDA_DMA_ACCESS_LEN; + lpib += HDA_DMA_ACCESS_LEN; + left -= HDA_DMA_ACCESS_LEN; + + if (st->bp == bdle_desc->len) { + st->bp = 0; + if (bdle_desc->ioc) + irq = 1; + st->be++; + if (st->be == st->bdl_cnt) { + st->be = 0; + lpib = 0; + } + bdle_desc = &bdl[st->be]; + } + } + + hda_set_pib(sc, stream_ind, lpib); + + if (irq) { + hda_set_field_by_offset(sc, off + HDAC_SDSTS, + HDAC_SDSTS_BCIS, HDAC_SDSTS_BCIS); + hda_update_intr(sc); + } + + return (0); +} + +static void +hda_set_pib(struct hda_softc *sc, uint8_t stream_ind, uint32_t pib) +{ + uint32_t off = hda_get_offset_stream(stream_ind); + + hda_set_reg_by_offset(sc, off + HDAC_SDLPIB, pib); + /* LPIB Alias */ + hda_set_reg_by_offset(sc, 0x2000 + off + HDAC_SDLPIB, pib); + if (sc->dma_pib_vaddr) + *(uint32_t *)(sc->dma_pib_vaddr + stream_ind * \ + HDA_DMA_PIB_ENTRY_LEN) = pib; +} + +static uint64_t hda_get_clock_ns(void) +{ + struct timespec ts; + int err; + + err = clock_gettime(CLOCK_MONOTONIC, &ts); + assert(!err); + + return (ts.tv_sec * 1000000000LL + ts.tv_nsec); +} + +/* + * PCI HDA function definitions + */ +static int +pci_hda_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) +{ + struct hda_softc *sc = NULL; + + assert(ctx != NULL); + assert(pi != NULL); + + pci_set_cfgdata16(pi, PCIR_VENDOR, INTEL_VENDORID); + pci_set_cfgdata16(pi, PCIR_DEVICE, HDA_INTEL_82801G); + + pci_set_cfgdata8(pi, PCIR_SUBCLASS, PCIS_MULTIMEDIA_HDA); + pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_MULTIMEDIA); + + /* select the Intel HDA mode */ + pci_set_cfgdata8(pi, PCIR_HDCTL, 0x01); + + /* allocate one BAR register for the Memory address offsets */ + pci_emul_alloc_bar(pi, 0, PCIBAR_MEM32, HDA_LAST_OFFSET); + + /* allocate an IRQ pin for our slot */ + pci_lintr_request(pi); + + sc = hda_init(opts); + if (!sc) + return (-1); + + sc->pci_dev = pi; + pi->pi_arg = sc; + + return (0); +} + +static void +pci_hda_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, + int baridx, uint64_t offset, int size, uint64_t value) +{ + struct hda_softc *sc = pi->pi_arg; + int err; + + assert(sc); + assert(baridx == 0); + assert(size <= 4); + + DPRINTF("offset: 0x%lx value: 0x%lx\n", offset, value); + + err = hda_write(sc, offset, size, value); + assert(!err); +} + +static uint64_t +pci_hda_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, + int baridx, uint64_t offset, int size) +{ + struct hda_softc *sc = pi->pi_arg; + uint64_t value = 0; + + assert(sc); + assert(baridx == 0); + assert(size <= 4); + + value = hda_read(sc, offset); + + DPRINTF("offset: 0x%lx value: 0x%lx\n", offset, value); + + return (value); +} diff --git a/usr.sbin/bhyve/pci_hda.h b/usr.sbin/bhyve/pci_hda.h new file mode 100644 index 000000000000..8ed050cc8f40 --- /dev/null +++ b/usr.sbin/bhyve/pci_hda.h @@ -0,0 +1,92 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2016 Alex Teaca <iateaca@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 ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _HDA_EMUL_H_ +#define _HDA_EMUL_H_ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <assert.h> + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/kernel.h> + +#include "hda_reg.h" + +/* + * HDA Debug Log + */ +#define DEBUG_HDA 1 +#if DEBUG_HDA == 1 +extern FILE *dbg; +#define DPRINTF(fmt, arg...) \ +do {fprintf(dbg, "%s-%d: " fmt, __func__, __LINE__, ##arg); \ +fflush(dbg); } while (0) +#else +#define DPRINTF(fmt, arg...) +#endif + +#define HDA_FIFO_SIZE 0x100 + +struct hda_softc; +struct hda_codec_class; + +struct hda_codec_inst { + uint8_t cad; + struct hda_codec_class *codec; + struct hda_softc *hda; + struct hda_ops *hops; + void *priv; +}; + +struct hda_codec_class { + char *name; + int (*init)(struct hda_codec_inst *hci, const char *play, + const char *rec, const char *opts); + int (*reset)(struct hda_codec_inst *hci); + int (*command)(struct hda_codec_inst *hci, uint32_t cmd_data); + int (*notify)(struct hda_codec_inst *hci, uint8_t run, uint8_t stream, + uint8_t dir); +}; + +struct hda_ops { + int (*signal)(struct hda_codec_inst *hci); + int (*response)(struct hda_codec_inst *hci, uint32_t response, + uint8_t unsol); + int (*transfer)(struct hda_codec_inst *hci, uint8_t stream, + uint8_t dir, void *buf, size_t count); +}; + +#define HDA_EMUL_SET(x) DATA_SET(hda_codec_class_set, x); + +#endif /* _HDA_EMUL_H_ */ diff --git a/usr.sbin/bhyve/pci_virtio_scsi.c b/usr.sbin/bhyve/pci_virtio_scsi.c index 283dd83b6e08..9d9fa822e01d 100644 --- a/usr.sbin/bhyve/pci_virtio_scsi.c +++ b/usr.sbin/bhyve/pci_virtio_scsi.c @@ -309,7 +309,8 @@ pci_vtscsi_reset(void *vsc) /* initialize config structure */ sc->vss_config = (struct pci_vtscsi_config){ .num_queues = VTSCSI_REQUESTQ, - .seg_max = VTSCSI_MAXSEG, + /* Leave room for the request and the response. */ + .seg_max = VTSCSI_MAXSEG - 2, .max_sectors = 2, .cmd_per_lun = 1, .event_info_size = sizeof(struct pci_vtscsi_event), diff --git a/usr.sbin/bsnmpd/modules/snmp_lm75/snmp_lm75.c b/usr.sbin/bsnmpd/modules/snmp_lm75/snmp_lm75.c index 1822f7801e80..a55050b851d3 100644 --- a/usr.sbin/bsnmpd/modules/snmp_lm75/snmp_lm75.c +++ b/usr.sbin/bsnmpd/modules/snmp_lm75/snmp_lm75.c @@ -100,7 +100,6 @@ lm75_init(struct lmodule *mod, int argc __unused, char *argv[] __unused) module = mod; lm75_sensors = 0; - openlog("snmp_lm75", LOG_NDELAY | LOG_PID, LOG_DAEMON); return(0); } diff --git a/usr.sbin/bsnmpd/modules/snmp_pf/pf_snmp.c b/usr.sbin/bsnmpd/modules/snmp_pf/pf_snmp.c index 7d4398264322..d20f7bccfe26 100644 --- a/usr.sbin/bsnmpd/modules/snmp_pf/pf_snmp.c +++ b/usr.sbin/bsnmpd/modules/snmp_pf/pf_snmp.c @@ -907,7 +907,7 @@ pf_tbladdr(struct snmp_context __unused *ctx, struct snmp_value __unused *val, } int -pf_altq(struct snmp_context __unused *ctx, struct snmp_value *val, +pf_altq_num(struct snmp_context __unused *ctx, struct snmp_value *val, u_int sub, u_int __unused vindex, enum snmp_op op) { asn_subid_t which = val->var.subs[sub - 1]; diff --git a/usr.sbin/bsnmpd/modules/snmp_pf/pf_tree.def b/usr.sbin/bsnmpd/modules/snmp_pf/pf_tree.def index 1dfa14ce4c2a..b545c1e79fae 100644 --- a/usr.sbin/bsnmpd/modules/snmp_pf/pf_tree.def +++ b/usr.sbin/bsnmpd/modules/snmp_pf/pf_tree.def @@ -174,7 +174,7 @@ ) ) (10 pfAltq - (1 pfAltqQueueNumber INTEGER32 pf_altq GET) + (1 pfAltqQueueNumber INTEGER32 pf_altq_num GET) (2 pfAltqQueueTable (1 pfAltqQueueEntry : INTEGER32 pf_altqq (1 pfAltqQueueIndex INTEGER32) diff --git a/usr.sbin/kbdcontrol/kbdcontrol.c b/usr.sbin/kbdcontrol/kbdcontrol.c index 3144e44d72b3..f4651acea840 100644 --- a/usr.sbin/kbdcontrol/kbdcontrol.c +++ b/usr.sbin/kbdcontrol/kbdcontrol.c @@ -1220,9 +1220,12 @@ main(int argc, char **argv) int opt; /* Collect any -P arguments, regardless of where they appear. */ - while ((opt = getopt(argc, argv, optstring)) != -1) + while ((opt = getopt(argc, argv, optstring)) != -1) { if (opt == 'P') add_keymap_path(optarg); + if (opt == '?') + usage(); + } optind = optreset = 1; while ((opt = getopt(argc, argv, optstring)) != -1) diff --git a/usr.sbin/mountd/mountd.c b/usr.sbin/mountd/mountd.c index 7d1685914742..79d6ac7f5693 100644 --- a/usr.sbin/mountd/mountd.c +++ b/usr.sbin/mountd/mountd.c @@ -385,8 +385,8 @@ strsep_quote(char **stringp, const char *delim) *dstptr++ = *srcptr++; } - *dstptr = 0; /* Terminate the string */ *stringp = (*srcptr == '\0') ? NULL : srcptr + 1; + *dstptr = 0; /* Terminate the string */ return (retval); } diff --git a/usr.sbin/nandsim/Makefile b/usr.sbin/nandsim/Makefile deleted file mode 100644 index 9269ab5de34f..000000000000 --- a/usr.sbin/nandsim/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# $FreeBSD$ - -PROG= nandsim -SRCS= nandsim.c nandsim_rcfile.c nandsim_cfgparse.c -BINDIR= /usr/sbin -MAN= nandsim.8 - -.include <bsd.prog.mk> diff --git a/usr.sbin/nandsim/Makefile.depend b/usr.sbin/nandsim/Makefile.depend deleted file mode 100644 index 6cfaab1c3644..000000000000 --- a/usr.sbin/nandsim/Makefile.depend +++ /dev/null @@ -1,17 +0,0 @@ -# $FreeBSD$ -# Autogenerated - do NOT edit! - -DIRDEPS = \ - gnu/lib/csu \ - include \ - include/xlocale \ - lib/${CSU_DIR} \ - lib/libc \ - lib/libcompiler_rt \ - - -.include <dirdeps.mk> - -.if ${DEP_RELDIR} == ${_DEP_RELDIR} -# local dependencies - needed for -jN in clean tree -.endif diff --git a/usr.sbin/nandsim/nandsim.8 b/usr.sbin/nandsim/nandsim.8 deleted file mode 100644 index 0951cc7a1aac..000000000000 --- a/usr.sbin/nandsim/nandsim.8 +++ /dev/null @@ -1,229 +0,0 @@ -.\" Copyright (c) 2010 Semihalf -.\" 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 August 10, 2010 -.Dt NANDSIM 8 -.Os -.Sh NAME -.Nm nandsim -.Nd NAND simulator control program -.Sh SYNOPSIS -.Nm -.Ic status -.Aq ctrl_no | Fl -all | Fl a -.Op Fl v -.Nm -.Ic conf -.Aq filename -.Nm -.Ic start -.Aq ctrl_no -.Nm -.Ic mod -.Aq ctrl_no:cs_no | Fl l Aq loglevel -.Op Fl p Aq prog_time -.Op Fl e Aq erase_time -.Op Fl r Aq read_time -.Op Fl E Aq error_ratio -.Op Fl h -.Nm -.Ic stop -.Aq ctrl_no -.Nm -.Ic error -.Aq ctrl_no:cs_no -.Aq page_num -.Aq column -.Aq length -.Aq pattern -.Nm -.Ic bb -.Aq ctrl_no:cs_no -.Op blk_num,blk_num2,... -.Op Fl U -.Op Fl L -.Nm -.Ic freeze -.Op ctrl_no -.Nm -.Ic log -.Aq ctrl_no | Fl -all | Fl a -.Nm -.Ic stats -.Aq ctrl_no:cs_no -.Aq page_num -.Nm -.Ic dump -.Aq ctrl_no:cs_no -.Aq filename -.Nm -.Ic restore -.Aq ctrl_no:chip_no -.Aq filename -.Nm -.Ic destroy -.Aq ctrl_no[:cs_no] | Fl -all | Fl a -.Nm -.Ic help -.Op Fl v -.Sh COMMAND DESCRIPTION -Controllers and chips are arranged into a simple hierarchy. -There can be up to 4 controllers configured, each with 4 chip select (CS) lines. -A given chip is connected to one of the chip selects. -.Pp -Controllers are specified as -.Aq ctrl_no ; -chip selects are specified as -.Aq cs_no . -.Bl -tag -width periphlist -.It Ic status -Gets controller(s) status. If -.Fl a -or -.Fl -all -flag is specified - command will print status of every controller -currently available. -Optional flag -.Fl v -causes printing complete information about the controller, and all -chips attached to it. -.It Ic conf -Reads simulator configuration from a specified file (this includes -the simulation "layout" i.e. controllers-chips assignments). -Configuration changes for an already started simulation require a -full stop-start cycle in order to take effect i.e.: -.Bl -column -.It nandsim stop ... -.It nandsim destroy ... -.Pp -.It << edit config file >> -.Pp -.It nandsim conf ... -.It nandsim start ... -.El -.It Ic mod -Alters simulator parameters on-the-fly. -If controller number and CS pair is not specified, the general -simulator parameters (not specific to a controller or a chip) will be modified. -Changing chip's parameters requires specifying both controller number and CS -to which the given chip is connected. -Parameters which can be altered: -.Pp -General simulator related: -.Bl -tag -width flag -.It Fl l Aq log_level -change logging level to -.Aq log_level -.El -.Pp -Chip related: -.Bl -tag -width flag -.It Fl p Aq prog_time -change prog time for specified chip to -.Aq prog_time -.It Fl e Aq erase_time -change erase time for specified chip to -.Aq erase_time -.It Fl r Aq read_time -change read time for specified chip to -.Aq read_time -.It Fl E Aq error_ratio -change error ratio for specified chip to -.Aq error_ratio . -Error ratio is a number of errors per million read/write bytes. -.El -.Pp -Additionally, flag -.Fl h -will list parameters which can be altered. -.El -.Bl -tag -width periphlist -.It Ic bb -Marks/unmarks a specified block as bad. -To mark/unmark the bad condition an a block, the following parameters -have to be supplied: controller number, CS number, and at least one -block number. -It is possible to specify multiple blocks, by separating blocks numbers -with a comma. -The following options can be used for the 'bb' command: -.Bl -tag -width flag -.It Fl U -unmark the bad previously marked block as bad. -.It Fl L -list all blocks marked as bad on a given chip. -.El -.It Ic log -Prints activity log of the specified controller to stdout; if -controller number is not specified, logs for all available -controllers are printed. -.It Ic stats -Print statistics of the selected controller, chip and page. -Statistics includes read count, write count, raw read count, raw -write count, ECC stats (succeeded corrections, failed correction). -.It Ic dump -Dumps a snaphot of a single chip (including data and bad blocks -information, wearout level) into the file. -.It Ic restore -Restores chip state from a dump-file snapshot (produced previously -with the 'dump' command). -.It Ic start -Starts a controller i.e. the simulation. -.It Ic stop -Stops an already started controller; if the controller number is not -supplied, attempts to stop all currently working controllers. -.It Ic destroy -Removes existing active chip/controller and its configuration from -memory and releases the resources. -Specifying flag -.Fl a -or -.Fl -all -causes removal of every chip and controller. -Controller must be stopped in order to be destroyed. -.It Ic error -Directly overwrites a certain number of bytes in the specified page -at a given offset with a supplied pattern (which mimics the -corruption of flash contents). -.It Ic help -Prints synopsis, -.Fl v -gives more verbose output. -.It Ic freeze -Stops simulation of given controller (simulates power-loss). -All commands issues to any chip on this controller are ignored. -.El -.Sh SEE ALSO -.Xr nand 4 , -.Xr nandsim 4 , -.Xr nandsim.conf 5 -.Sh HISTORY -The -.Nm -utility first appeared in -.Fx 10.0 . -.Sh AUTHORS -This utility was written by -.An Lukasz Wojcik . diff --git a/usr.sbin/nandsim/nandsim.c b/usr.sbin/nandsim/nandsim.c deleted file mode 100644 index 10eadcbc940d..000000000000 --- a/usr.sbin/nandsim/nandsim.c +++ /dev/null @@ -1,1399 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * 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 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. - */ - -/* - * Control application for the NAND simulator. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/errno.h> -#include <sys/ioctl.h> -#include <sys/mman.h> -#include <sys/stat.h> -#include <sys/types.h> - -#include <dev/nand/nandsim.h> -#include <dev/nand/nand_dev.h> - -#include <ctype.h> -#include <fcntl.h> -#include <getopt.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <stdarg.h> -#include <unistd.h> -#include <stdlib.h> -#include <limits.h> -#include <sysexits.h> - -#include "nandsim_cfgparse.h" - -#define SIMDEVICE "/dev/nandsim.ioctl" - -#define error(fmt, args...) do { \ - printf("ERROR: " fmt "\n", ##args); } while (0) - -#define warn(fmt, args...) do { \ - printf("WARNING: " fmt "\n", ##args); } while (0) - -#define DEBUG -#undef DEBUG - -#ifdef DEBUG -#define debug(fmt, args...) do { \ - printf("NANDSIM_CONF:" fmt "\n", ##args); } while (0) -#else -#define debug(fmt, args...) do {} while(0) -#endif - -#define NANDSIM_RAM_LOG_SIZE 16384 - -#define MSG_NOTRUNNING "Controller#%d is not running.Please start" \ - " it first." -#define MSG_RUNNING "Controller#%d is already running!" -#define MSG_CTRLCHIPNEEDED "You have to specify ctrl_no:cs_no pair!" -#define MSG_STATUSACQCTRLCHIP "Could not acquire status for ctrl#%d chip#%d" -#define MSG_STATUSACQCTRL "Could not acquire status for ctrl#%d" -#define MSG_NOCHIP "There is no such chip configured (chip#%d "\ - "at ctrl#%d)!" - -#define MSG_NOCTRL "Controller#%d is not configured!" -#define MSG_NOTCONFIGDCTRLCHIP "Chip connected to ctrl#%d at cs#%d " \ - "is not configured." - -typedef int (commandfunc_t)(int , char **); - -static struct nandsim_command *getcommand(char *); -static int parse_devstring(char *, int *, int *); -static void printchip(struct sim_chip *, uint8_t); -static void printctrl(struct sim_ctrl *); -static int opendev(int *); -static commandfunc_t cmdstatus; -static commandfunc_t cmdconf; -static commandfunc_t cmdstart; -static commandfunc_t cmdstop; -static commandfunc_t cmdmod; -static commandfunc_t cmderror; -static commandfunc_t cmdbb; -static commandfunc_t cmdfreeze; -static commandfunc_t cmdlog; -static commandfunc_t cmdstats; -static commandfunc_t cmddump; -static commandfunc_t cmdrestore; -static commandfunc_t cmddestroy; -static commandfunc_t cmdhelp; -static int checkusage(int, int, char **); -static int is_chip_created(int, int, int *); -static int is_ctrl_created(int, int *); -static int is_ctrl_running(int, int *); -static int assert_chip_connected(int , int); -static int printstats(int, int, uint32_t, int); - -struct nandsim_command { - const char *cmd_name; /* Command name */ - commandfunc_t *commandfunc; /* Ptr to command function */ - uint8_t req_argc; /* Mandatory arguments count */ - const char *usagestring; /* Usage string */ -}; - -static struct nandsim_command commands[] = { - {"status", cmdstatus, 1, - "status <ctl_no|--all|-a> [-v]\n" }, - {"conf", cmdconf, 1, - "conf <filename>\n" }, - {"start", cmdstart, 1, - "start <ctrl_no>\n" }, - {"mod", cmdmod, 2, - "mod [-l <loglevel>] | <ctl_no:cs_no> [-p <prog_time>]\n" - "\t[-e <erase_time>] [-r <read_time>]\n" - "\t[-E <error_ratio>] | [-h]\n" }, - {"stop", cmdstop, 1, - "stop <ctrl_no>\n" }, - {"error", cmderror, 5, - "error <ctrl_no:cs_no> <page_num> <column> <length> <pattern>\n" }, - {"bb", cmdbb, 2, - "bb <ctl_no:cs_no> [blk_num1,blk_num2,..] [-U] [-L]\n" }, - {"freeze", cmdfreeze, 1, - "freeze [ctrl_no]\n" }, - {"log", cmdlog, 1, - "log <ctrl_no|--all|-a>\n" }, - {"stats", cmdstats, 2, - "stats <ctrl_no:cs_no> <pagenumber>\n" }, - {"dump", cmddump, 2, - "dump <ctrl_no:cs_no> <filename>\n" }, - {"restore", cmdrestore, 2, - "restore <ctrl_no:chip_no> <filename>\n" }, - {"destroy", cmddestroy, 1, - "destroy <ctrl_no[:cs_no]|--all|-a>\n" }, - {"help", cmdhelp, 0, - "help [-v]" }, - {NULL, NULL, 0, NULL}, -}; - - -/* Parse command name, and start appropriate function */ -static struct nandsim_command* -getcommand(char *arg) -{ - struct nandsim_command *opts; - - for (opts = commands; (opts != NULL) && - (opts->cmd_name != NULL); opts++) { - if (strcmp(opts->cmd_name, arg) == 0) - return (opts); - } - return (NULL); -} - -/* - * Parse given string in format <ctrl_no>:<cs_no>, if possible -- set - * ctrl and/or cs, and return 0 (success) or 1 (in case of error). - * - * ctrl == 0xff && chip == 0xff : '--all' flag specified - * ctrl != 0xff && chip != 0xff : both ctrl & chip were specified - * ctrl != 0xff && chip == 0xff : only ctrl was specified - */ -static int -parse_devstring(char *str, int *ctrl, int *cs) -{ - char *tmpstr; - unsigned int num = 0; - - /* Ignore white spaces at the beginning */ - while (isspace(*str) && (*str != '\0')) - str++; - - *ctrl = 0xff; - *cs = 0xff; - if (strcmp(str, "--all") == 0 || - strcmp(str, "-a") == 0) { - /* If --all or -a is specified, ctl==chip==0xff */ - debug("CTRL=%d CHIP=%d\n", *ctrl, *cs); - return (0); - } - /* Separate token and try to convert it to int */ - tmpstr = (char *)strtok(str, ":"); - if ((tmpstr != NULL) && (*tmpstr != '\0')) { - if (convert_arguint(tmpstr, &num) != 0) - return (1); - - if (num > MAX_SIM_DEV - 1) { - error("Invalid ctrl_no supplied: %s. Valid ctrl_no " - "value must lie between 0 and 3!", tmpstr); - return (1); - } - - *ctrl = num; - tmpstr = (char *)strtok(NULL, ":"); - - if ((tmpstr != NULL) && (*tmpstr != '\0')) { - if (convert_arguint(tmpstr, &num) != 0) - return (1); - - /* Check if chip_no is valid */ - if (num > MAX_CTRL_CS - 1) { - error("Invalid chip_no supplied: %s. Valid " - "chip_no value must lie between 0 and 3!", - tmpstr); - return (1); - } - *cs = num; - } - } else - /* Empty devstring supplied */ - return (1); - - debug("CTRL=%d CHIP=%d\n", *ctrl, *cs); - return (0); -} - -static int -opendev(int *fd) -{ - - *fd = open(SIMDEVICE, O_RDWR); - if (*fd == -1) { - error("Could not open simulator device file (%s)!", - SIMDEVICE); - return (EX_OSFILE); - } - return (EX_OK); -} - -static int -opencdev(int *cdevd, int ctrl, int chip) -{ - char fname[255]; - - sprintf(fname, "/dev/nandsim%d.%d", ctrl, chip); - *cdevd = open(fname, O_RDWR); - if (*cdevd == -1) - return (EX_NOINPUT); - - return (EX_OK); -} - -/* - * Check if given arguments count match requirements. If no, or - * --help (-h) flag is specified -- return 1 (print usage) - */ -static int -checkusage(int gargc, int argsreqd, char **gargv) -{ - - if (gargc < argsreqd + 2 || (gargc >= (argsreqd + 2) && - (strcmp(gargv[1], "--help") == 0 || - strcmp(gargv[1], "-h") == 0))) - return (1); - - return (0); -} - -static int -cmdstatus(int gargc, char **gargv) -{ - int chip = 0, ctl = 0, err = 0, fd, idx, idx2, start, stop; - uint8_t verbose = 0; - struct sim_ctrl ctrlconf; - struct sim_chip chipconf; - - err = parse_devstring(gargv[2], &ctl, &chip); - if (err) { - return (EX_USAGE); - } else if (ctl == 0xff) { - /* Every controller */ - start = 0; - stop = MAX_SIM_DEV-1; - } else { - /* Specified controller only */ - start = ctl; - stop = ctl; - } - - if (opendev(&fd) != EX_OK) - return (EX_OSFILE); - - for (idx = 0; idx < gargc; idx ++) - if (strcmp(gargv[idx], "-v") == 0 || - strcmp(gargv[idx], "--verbose") == 0) - verbose = 1; - - for (idx = start; idx <= stop; idx++) { - ctrlconf.num = idx; - err = ioctl(fd, NANDSIM_STATUS_CTRL, &ctrlconf); - if (err) { - err = EX_SOFTWARE; - error(MSG_STATUSACQCTRL, idx); - continue; - } - - printctrl(&ctrlconf); - - for (idx2 = 0; idx2 < MAX_CTRL_CS; idx2++) { - chipconf.num = idx2; - chipconf.ctrl_num = idx; - - err = ioctl(fd, NANDSIM_STATUS_CHIP, &chipconf); - if (err) { - err = EX_SOFTWARE; - error(MSG_STATUSACQCTRL, idx); - continue; - } - - printchip(&chipconf, verbose); - } - } - close(fd); - return (err); -} - -static int -cmdconf(int gargc __unused, char **gargv) -{ - int err; - - err = parse_config(gargv[2], SIMDEVICE); - if (err) - return (EX_DATAERR); - - return (EX_OK); -} - -static int -cmdstart(int gargc __unused, char **gargv) -{ - int chip = 0, ctl = 0, err = 0, fd, running, state; - - err = parse_devstring(gargv[2], &ctl, &chip); - if (err) - return (EX_USAGE); - - err = is_ctrl_created(ctl, &state); - if (err) { - return (EX_SOFTWARE); - } else if (state == 0) { - error(MSG_NOCTRL, ctl); - return (EX_SOFTWARE); - } - - err = is_ctrl_running(ctl, &running); - if (err) - return (EX_SOFTWARE); - - if (running) { - warn(MSG_RUNNING, ctl); - } else { - if (opendev(&fd) != EX_OK) - return (EX_OSFILE); - - err = ioctl(fd, NANDSIM_START_CTRL, &ctl); - close(fd); - if (err) { - error("Cannot start controller#%d", ctl); - err = EX_SOFTWARE; - } - } - return (err); -} - -static int -cmdstop(int gargc __unused, char **gargv) -{ - int chip = 0, ctl = 0, err = 0, fd, running; - - err = parse_devstring(gargv[2], &ctl, &chip); - if (err) - return (EX_USAGE); - - err = is_ctrl_running(ctl, &running); - if (err) - return (EX_SOFTWARE); - - if (!running) { - error(MSG_NOTRUNNING, ctl); - } else { - if (opendev(&fd) != EX_OK) - return (EX_OSFILE); - - err = ioctl(fd, NANDSIM_STOP_CTRL, &ctl); - close(fd); - if (err) { - error("Cannot stop controller#%d", ctl); - err = EX_SOFTWARE; - } - } - - return (err); -} - -static int -cmdmod(int gargc __unused, char **gargv) -{ - int chip, ctl, err = 0, fd = -1, i; - struct sim_mod mods; - - if (gargc >= 4) { - if (strcmp(gargv[2], "--loglevel") == 0 || strcmp(gargv[2], - "-l") == 0) { - /* Set loglevel (ctrl:chip pair independent) */ - mods.field = SIM_MOD_LOG_LEVEL; - - if (convert_arguint(gargv[3], &mods.new_value) != 0) - return (EX_SOFTWARE); - - if (opendev(&fd) != EX_OK) - return (EX_OSFILE); - - err = ioctl(fd, NANDSIM_MODIFY, &mods); - if (err) { - error("simulator parameter %s could not be " - "modified !", gargv[3]); - close(fd); - return (EX_SOFTWARE); - } - - debug("request : loglevel = %d\n", mods.new_value); - close(fd); - return (EX_OK); - } - } - - err = parse_devstring(gargv[2], &ctl, &chip); - if (err) - return (EX_USAGE); - - else if (chip == 0xff) { - error(MSG_CTRLCHIPNEEDED); - return (EX_USAGE); - } - - if (!assert_chip_connected(ctl, chip)) - return (EX_SOFTWARE); - - if (opendev(&fd) != EX_OK) - return (EX_OSFILE); - - /* Find out which flags were passed */ - for (i = 3; i < gargc; i++) { - - if (convert_arguint(gargv[i + 1], &mods.new_value) != 0) - continue; - - if (strcmp(gargv[i], "--prog-time") == 0 || - strcmp(gargv[i], "-p") == 0) { - - mods.field = SIM_MOD_PROG_TIME; - debug("request : progtime = %d\n", mods.new_value); - - } else if (strcmp(gargv[i], "--erase-time") == 0 || - strcmp(gargv[i], "-e") == 0) { - - mods.field = SIM_MOD_ERASE_TIME; - debug("request : eraseime = %d\n", mods.new_value); - - } else if (strcmp(gargv[i], "--read-time") == 0 || - strcmp(gargv[i], "-r") == 0) { - - mods.field = SIM_MOD_READ_TIME; - debug("request : read_time = %d\n", mods.new_value); - - } else if (strcmp(gargv[i], "--error-ratio") == 0 || - strcmp(gargv[i], "-E") == 0) { - - mods.field = SIM_MOD_ERROR_RATIO; - debug("request : error_ratio = %d\n", mods.new_value); - - } else { - /* Flag not recognized, or nothing specified. */ - error("Unrecognized flag:%s\n", gargv[i]); - if (fd >= 0) - close(fd); - return (EX_USAGE); - } - - mods.chip_num = chip; - mods.ctrl_num = ctl; - - /* Call appropriate ioctl */ - err = ioctl(fd, NANDSIM_MODIFY, &mods); - if (err) { - error("simulator parameter %s could not be modified! ", - gargv[i]); - continue; - } - i++; - } - close(fd); - return (EX_OK); -} - -static int -cmderror(int gargc __unused, char **gargv) -{ - uint32_t page, column, len, pattern; - int chip = 0, ctl = 0, err = 0, fd; - struct sim_error sim_err; - - err = parse_devstring(gargv[2], &ctl, &chip); - if (err) - return (EX_USAGE); - - if (chip == 0xff) { - error(MSG_CTRLCHIPNEEDED); - return (EX_USAGE); - } - - if (convert_arguint(gargv[3], &page) || - convert_arguint(gargv[4], &column) || - convert_arguint(gargv[5], &len) || - convert_arguint(gargv[6], &pattern)) - return (EX_SOFTWARE); - - if (!assert_chip_connected(ctl, chip)) - return (EX_SOFTWARE); - - sim_err.page_num = page; - sim_err.column = column; - sim_err.len = len; - sim_err.pattern = pattern; - sim_err.ctrl_num = ctl; - sim_err.chip_num = chip; - - if (opendev(&fd) != EX_OK) - return (EX_OSFILE); - - err = ioctl(fd, NANDSIM_INJECT_ERROR, &sim_err); - - close(fd); - if (err) { - error("Could not inject error !"); - return (EX_SOFTWARE); - } - return (EX_OK); -} - -static int -cmdbb(int gargc, char **gargv) -{ - struct sim_block_state bs; - struct chip_param_io cparams; - uint32_t blkidx; - int c, cdevd, chip = 0, ctl = 0, err = 0, fd, idx; - uint8_t flagL = 0, flagU = 0; - int *badblocks = NULL; - - /* Check for --list/-L or --unmark/-U flags */ - for (idx = 3; idx < gargc; idx++) { - if (strcmp(gargv[idx], "--list") == 0 || - strcmp(gargv[idx], "-L") == 0) - flagL = idx; - if (strcmp(gargv[idx], "--unmark") == 0 || - strcmp(gargv[idx], "-U") == 0) - flagU = idx; - } - - if (flagL == 2 || flagU == 2 || flagU == 3) - return (EX_USAGE); - - err = parse_devstring(gargv[2], &ctl, &chip); - if (err) { - return (EX_USAGE); - } - if (chip == 0xff || ctl == 0xff) { - error(MSG_CTRLCHIPNEEDED); - return (EX_USAGE); - } - - bs.ctrl_num = ctl; - bs.chip_num = chip; - - if (!assert_chip_connected(ctl, chip)) - return (EX_SOFTWARE); - - if (opencdev(&cdevd, ctl, chip) != EX_OK) - return (EX_OSFILE); - - err = ioctl(cdevd, NAND_IO_GET_CHIP_PARAM, &cparams); - if (err) - return (EX_SOFTWARE); - - close(cdevd); - - bs.ctrl_num = ctl; - bs.chip_num = chip; - - if (opendev(&fd) != EX_OK) - return (EX_OSFILE); - - if (flagL != 3) { - /* - * Flag -L was specified either after blocklist or was not - * specified at all. - */ - c = parse_intarray(gargv[3], &badblocks); - - for (idx = 0; idx < c; idx++) { - bs.block_num = badblocks[idx]; - /* Do not change wearout */ - bs.wearout = -1; - bs.state = (flagU == 0) ? NANDSIM_BAD_BLOCK : - NANDSIM_GOOD_BLOCK; - - err = ioctl(fd, NANDSIM_SET_BLOCK_STATE, &bs); - if (err) { - error("Could not set bad block(%d) for " - "controller (%d)!", - badblocks[idx], ctl); - err = EX_SOFTWARE; - break; - } - } - } - if (flagL != 0) { - /* If flag -L was specified (anywhere) */ - for (blkidx = 0; blkidx < cparams.blocks; blkidx++) { - bs.block_num = blkidx; - /* Do not change the wearout */ - bs.wearout = -1; - err = ioctl(fd, NANDSIM_GET_BLOCK_STATE, &bs); - if (err) { - error("Could not acquire block state"); - err = EX_SOFTWARE; - continue; - } - printf("Block#%d: wear count: %d %s\n", blkidx, - bs.wearout, - (bs.state == NANDSIM_BAD_BLOCK) ? "BAD":"GOOD"); - } - } - close(fd); - return (err); -} - -static int -cmdfreeze(int gargc __unused, char **gargv) -{ - int chip = 0, ctl = 0, err = 0, fd, i, start = 0, state, stop = 0; - struct sim_ctrl_chip ctrlchip; - - err = parse_devstring(gargv[2], &ctl, &chip); - if (err) - return (EX_USAGE); - - if (ctl == 0xff) { - error("You have to specify at least controller number"); - return (EX_USAGE); - } - - if (ctl != 0xff && chip == 0xff) { - start = 0; - stop = MAX_CTRL_CS - 1; - } else { - start = chip; - stop = chip; - } - - ctrlchip.ctrl_num = ctl; - - err = is_ctrl_running(ctl, &state); - if (err) - return (EX_SOFTWARE); - if (state == 0) { - error(MSG_NOTRUNNING, ctl); - return (EX_SOFTWARE); - } - - if (opendev(&fd) != EX_OK) - return (EX_OSFILE); - - for (i = start; i <= stop; i++) { - err = is_chip_created(ctl, i, &state); - if (err) - return (EX_SOFTWARE); - else if (state == 0) { - continue; - } - - ctrlchip.chip_num = i; - err = ioctl(fd, NANDSIM_FREEZE, &ctrlchip); - if (err) { - error("Could not freeze ctrl#%d chip#%d", ctl, i); - close(fd); - return (EX_SOFTWARE); - } - } - close(fd); - return (EX_OK); -} - -static int -cmdlog(int gargc __unused, char **gargv) -{ - struct sim_log log; - int chip = 0, ctl = 0, err = 0, fd, idx, start = 0, stop = 0; - char *logbuf; - - err = parse_devstring(gargv[2], &ctl, &chip); - if (err) - return (EX_USAGE); - - logbuf = (char *)malloc(sizeof(char) * NANDSIM_RAM_LOG_SIZE); - if (logbuf == NULL) { - error("Not enough memory to create log buffer"); - return (EX_SOFTWARE); - } - - memset(logbuf, 0, NANDSIM_RAM_LOG_SIZE); - log.log = logbuf; - log.len = NANDSIM_RAM_LOG_SIZE; - - if (ctl == 0xff) { - start = 0; - stop = MAX_SIM_DEV-1; - } else { - start = ctl; - stop = ctl; - } - - if (opendev(&fd) != EX_OK) { - free(logbuf); - return (EX_OSFILE); - } - - /* Print logs for selected controller(s) */ - for (idx = start; idx <= stop; idx++) { - log.ctrl_num = idx; - - err = ioctl(fd, NANDSIM_PRINT_LOG, &log); - if (err) { - error("Could not get log for controller %d!", idx); - continue; - } - - printf("Logs for controller#%d:\n%s\n", idx, logbuf); - } - - free(logbuf); - close(fd); - return (EX_OK); -} - -static int -cmdstats(int gargc __unused, char **gargv) -{ - int cdevd, chip = 0, ctl = 0, err = 0; - uint32_t pageno = 0; - - err = parse_devstring(gargv[2], &ctl, &chip); - - if (err) - return (EX_USAGE); - - if (chip == 0xff) { - error(MSG_CTRLCHIPNEEDED); - return (EX_USAGE); - } - - if (convert_arguint(gargv[3], &pageno) != 0) - return (EX_USAGE); - - if (!assert_chip_connected(ctl, chip)) - return (EX_SOFTWARE); - - if (opencdev(&cdevd, ctl, chip) != EX_OK) - return (EX_OSFILE); - - err = printstats(ctl, chip, pageno, cdevd); - if (err) { - close(cdevd); - return (EX_SOFTWARE); - } - close(cdevd); - return (EX_OK); -} - -static int -cmddump(int gargc __unused, char **gargv) -{ - struct sim_dump dump; - struct sim_block_state bs; - struct chip_param_io cparams; - int chip = 0, ctl = 0, err = EX_OK, fd, dumpfd; - uint32_t blkidx, bwritten = 0, totalwritten = 0; - void *buf; - - err = parse_devstring(gargv[2], &ctl, &chip); - if (err) - return (EX_USAGE); - - if (chip == 0xff || ctl == 0xff) { - error(MSG_CTRLCHIPNEEDED); - return (EX_USAGE); - } - - if (!assert_chip_connected(ctl, chip)) - return (EX_SOFTWARE); - - if (opencdev(&fd, ctl, chip) != EX_OK) - return (EX_OSFILE); - - err = ioctl(fd, NAND_IO_GET_CHIP_PARAM, &cparams); - if (err) { - error("Cannot get parameters for chip %d:%d", ctl, chip); - close(fd); - return (EX_SOFTWARE); - } - close(fd); - - dump.ctrl_num = ctl; - dump.chip_num = chip; - - dump.len = cparams.pages_per_block * (cparams.page_size + - cparams.oob_size); - - buf = malloc(dump.len); - if (buf == NULL) { - error("Could not allocate memory!"); - return (EX_SOFTWARE); - } - dump.data = buf; - - errno = 0; - dumpfd = open(gargv[3], O_WRONLY | O_CREAT, 0666); - if (dumpfd == -1) { - error("Cannot create dump file."); - free(buf); - return (EX_SOFTWARE); - } - - if (opendev(&fd)) { - close(dumpfd); - free(buf); - return (EX_SOFTWARE); - } - - bs.ctrl_num = ctl; - bs.chip_num = chip; - - /* First uint32_t in file shall contain block count */ - if (write(dumpfd, &cparams, sizeof(cparams)) < (int)sizeof(cparams)) { - error("Error writing to dumpfile!"); - close(fd); - close(dumpfd); - free(buf); - return (EX_SOFTWARE); - } - - /* - * First loop acquires blocks states and writes them to - * the dump file. - */ - for (blkidx = 0; blkidx < cparams.blocks; blkidx++) { - bs.block_num = blkidx; - err = ioctl(fd, NANDSIM_GET_BLOCK_STATE, &bs); - if (err) { - error("Could not get bad block(%d) for " - "controller (%d)!", blkidx, ctl); - close(fd); - close(dumpfd); - free(buf); - return (EX_SOFTWARE); - } - - bwritten = write(dumpfd, &bs, sizeof(bs)); - if (bwritten != sizeof(bs)) { - error("Error writing to dumpfile"); - close(fd); - close(dumpfd); - free(buf); - return (EX_SOFTWARE); - } - } - - /* Second loop dumps the data */ - for (blkidx = 0; blkidx < cparams.blocks; blkidx++) { - debug("Block#%d...", blkidx); - dump.block_num = blkidx; - - err = ioctl(fd, NANDSIM_DUMP, &dump); - if (err) { - error("Could not dump ctrl#%d chip#%d " - "block#%d", ctl, chip, blkidx); - err = EX_SOFTWARE; - break; - } - - bwritten = write(dumpfd, dump.data, dump.len); - if (bwritten != dump.len) { - error("Error writing to dumpfile"); - err = EX_SOFTWARE; - break; - } - debug("OK!\n"); - totalwritten += bwritten; - } - printf("%d out of %d B written.\n", totalwritten, dump.len * blkidx); - - close(fd); - close(dumpfd); - free(buf); - return (err); -} - -static int -cmdrestore(int gargc __unused, char **gargv) -{ - struct sim_dump dump; - struct sim_block_state bs; - struct stat filestat; - int chip = 0, ctl = 0, err = 0, fd, dumpfd = -1; - uint32_t blkidx, blksz, fsize = 0, expfilesz; - void *buf; - struct chip_param_io cparams, dumpcparams; - - err = parse_devstring(gargv[2], &ctl, &chip); - if (err) - return (EX_USAGE); - else if (ctl == 0xff) { - error(MSG_CTRLCHIPNEEDED); - return (EX_USAGE); - } - - if (!assert_chip_connected(ctl, chip)) - return (EX_SOFTWARE); - - /* Get chip geometry */ - if (opencdev(&fd, ctl, chip) != EX_OK) - return (EX_OSFILE); - - err = ioctl(fd, NAND_IO_GET_CHIP_PARAM, &cparams); - if (err) { - error("Cannot get parameters for chip %d:%d", ctl, chip); - close(fd); - return (err); - } - close(fd); - - /* Obtain dump file size */ - errno = 0; - if (stat(gargv[3], &filestat) != 0) { - error("Could not acquire file size! : %s", - strerror(errno)); - return (EX_IOERR); - } - - fsize = filestat.st_size; - blksz = cparams.pages_per_block * (cparams.page_size + - cparams.oob_size); - - /* Expected dump file size for chip */ - expfilesz = cparams.blocks * (blksz + sizeof(bs)) + sizeof(cparams); - - if (fsize != expfilesz) { - error("File size does not match chip geometry (file size: %d" - ", dump size: %d)", fsize, expfilesz); - return (EX_SOFTWARE); - } - - dumpfd = open(gargv[3], O_RDONLY); - if (dumpfd == -1) { - error("Could not open dump file!"); - return (EX_IOERR); - } - - /* Read chip params saved in dumpfile */ - read(dumpfd, &dumpcparams, sizeof(dumpcparams)); - - /* XXX */ - if (bcmp(&dumpcparams, &cparams, sizeof(cparams)) != 0) { - error("Supplied dump is created for a chip with different " - "chip configuration!"); - close(dumpfd); - return (EX_SOFTWARE); - } - - if (opendev(&fd) != EX_OK) { - close(dumpfd); - return (EX_OSFILE); - } - - buf = malloc(blksz); - if (buf == NULL) { - error("Could not allocate memory for block buffer"); - close(dumpfd); - close(fd); - return (EX_SOFTWARE); - } - - dump.ctrl_num = ctl; - dump.chip_num = chip; - dump.data = buf; - /* Restore block states and wearouts */ - for (blkidx = 0; blkidx < cparams.blocks; blkidx++) { - dump.block_num = blkidx; - if (read(dumpfd, &bs, sizeof(bs)) != sizeof(bs)) { - error("Error reading dumpfile"); - close(dumpfd); - close(fd); - free(buf); - return (EX_SOFTWARE); - } - bs.ctrl_num = ctl; - bs.chip_num = chip; - debug("BLKIDX=%d BLOCKS=%d CTRL=%d CHIP=%d STATE=%d\n" - "WEAROUT=%d BS.CTRL_NUM=%d BS.CHIP_NUM=%d\n", - blkidx, cparams.blocks, dump.ctrl_num, dump.chip_num, - bs.state, bs.wearout, bs.ctrl_num, bs.chip_num); - - err = ioctl(fd, NANDSIM_SET_BLOCK_STATE, &bs); - if (err) { - error("Could not set bad block(%d) for " - "controller: %d, chip: %d!", blkidx, ctl, chip); - close(dumpfd); - close(fd); - free(buf); - return (EX_SOFTWARE); - } - } - /* Restore data */ - for (blkidx = 0; blkidx < cparams.blocks; blkidx++) { - errno = 0; - dump.len = read(dumpfd, buf, blksz); - if (errno) { - error("Failed to read block#%d from dumpfile.", blkidx); - err = EX_SOFTWARE; - break; - } - dump.block_num = blkidx; - err = ioctl(fd, NANDSIM_RESTORE, &dump); - if (err) { - error("Could not restore block#%d of ctrl#%d chip#%d" - ": %s", blkidx, ctl, chip, strerror(errno)); - err = EX_SOFTWARE; - break; - } - } - - free(buf); - close(dumpfd); - close(fd); - return (err); - -} - -static int -cmddestroy(int gargc __unused, char **gargv) -{ - int chip = 0, ctl = 0, err = 0, fd, idx, idx2, state; - int chipstart, chipstop, ctrlstart, ctrlstop; - struct sim_chip_destroy chip_destroy; - - err = parse_devstring(gargv[2], &ctl, &chip); - - if (err) - return (EX_USAGE); - - if (ctl == 0xff) { - /* Every chip at every controller */ - ctrlstart = chipstart = 0; - ctrlstop = MAX_SIM_DEV - 1; - chipstop = MAX_CTRL_CS - 1; - } else { - ctrlstart = ctrlstop = ctl; - if (chip == 0xff) { - /* Every chip at selected controller */ - chipstart = 0; - chipstop = MAX_CTRL_CS - 1; - } else - /* Selected chip at selected controller */ - chipstart = chipstop = chip; - } - debug("CTRLSTART=%d CTRLSTOP=%d CHIPSTART=%d CHIPSTOP=%d\n", - ctrlstart, ctrlstop, chipstart, chipstop); - for (idx = ctrlstart; idx <= ctrlstop; idx++) { - err = is_ctrl_created(idx, &state); - if (err) { - error("Could not acquire ctrl#%d state. Cannot " - "destroy controller.", idx); - return (EX_SOFTWARE); - } - if (state == 0) { - continue; - } - err = is_ctrl_running(idx, &state); - if (err) { - error(MSG_STATUSACQCTRL, idx); - return (EX_SOFTWARE); - } - if (state != 0) { - error(MSG_RUNNING, ctl); - return (EX_SOFTWARE); - } - if (opendev(&fd) != EX_OK) - return (EX_OSFILE); - - for (idx2 = chipstart; idx2 <= chipstop; idx2++) { - err = is_chip_created(idx, idx2, &state); - if (err) { - error(MSG_STATUSACQCTRLCHIP, idx2, idx); - continue; - } - if (state == 0) - /* There is no such chip running */ - continue; - chip_destroy.ctrl_num = idx; - chip_destroy.chip_num = idx2; - ioctl(fd, NANDSIM_DESTROY_CHIP, - &chip_destroy); - } - /* If chip isn't explicitly specified -- destroy ctrl */ - if (chip == 0xff) { - err = ioctl(fd, NANDSIM_DESTROY_CTRL, &idx); - if (err) { - error("Could not destroy ctrl#%d", idx); - continue; - } - } - close(fd); - } - return (err); -} - -int -main(int argc, char **argv) -{ - struct nandsim_command *cmdopts; - int retcode = 0; - - if (argc < 2) { - cmdhelp(argc, argv); - retcode = EX_USAGE; - } else { - cmdopts = getcommand(argv[1]); - if (cmdopts != NULL && cmdopts->commandfunc != NULL) { - if (checkusage(argc, cmdopts->req_argc, argv) == 1) { - /* Print command specific usage */ - printf("nandsim %s", cmdopts->usagestring); - return (EX_USAGE); - } - retcode = cmdopts->commandfunc(argc, argv); - - if (retcode == EX_USAGE) { - /* Print command-specific usage */ - printf("nandsim %s", cmdopts->usagestring); - } else if (retcode == EX_OSFILE) { - error("Could not open device file"); - } - - } else { - error("Unknown command!"); - retcode = EX_USAGE; - } - } - return (retcode); -} - -static int -cmdhelp(int gargc __unused, char **gargv __unused) -{ - struct nandsim_command *opts; - - printf("usage: nandsim <command> [command params] [params]\n\n"); - - for (opts = commands; (opts != NULL) && - (opts->cmd_name != NULL); opts++) - printf("nandsim %s", opts->usagestring); - - printf("\n"); - return (EX_OK); -} - -static void -printchip(struct sim_chip *chip, uint8_t verbose) -{ - - if (chip->created == 0) - return; - if (verbose > 0) { - printf("\n[Chip info]\n"); - printf("num= %d\nctrl_num=%d\ndevice_id=%02x" - "\tmanufacturer_id=%02x\ndevice_model=%s\nmanufacturer=" - "%s\ncol_addr_cycles=%d\nrow_addr_cycles=%d" - "\npage_size=%d\noob_size=%d\npages_per_block=%d\n" - "blocks_per_lun=%d\nluns=%d\n\nprog_time=%d\n" - "erase_time=%d\nread_time=%d\n" - "error_ratio=%d\nwear_level=%d\nwrite_protect=%c\n" - "chip_width=%db\n", chip->num, chip->ctrl_num, - chip->device_id, chip->manufact_id,chip->device_model, - chip->manufacturer, chip->col_addr_cycles, - chip->row_addr_cycles, chip->page_size, - chip->oob_size, chip->pgs_per_blk, chip->blks_per_lun, - chip->luns,chip->prog_time, chip->erase_time, - chip->read_time, chip->error_ratio, chip->wear_level, - (chip->is_wp == 0) ? 'N':'Y', chip->width); - } else { - printf("[Chip info]\n"); - printf("\tnum=%d\n\tdevice_model=%s\n\tmanufacturer=%s\n" - "\tpage_size=%d\n\twrite_protect=%s\n", - chip->num, chip->device_model, chip->manufacturer, - chip->page_size, (chip->is_wp == 0) ? "NO":"YES"); - } -} - -static void -printctrl(struct sim_ctrl *ctrl) -{ - int i; - - if (ctrl->created == 0) { - printf(MSG_NOCTRL "\n", ctrl->num); - return; - } - printf("\n[Controller info]\n"); - printf("\trunning: %s\n", ctrl->running ? "yes" : "no"); - printf("\tnum cs: %d\n", ctrl->num_cs); - printf("\tecc: %d\n", ctrl->ecc); - printf("\tlog_filename: %s\n", ctrl->filename); - printf("\tecc_layout:"); - for (i = 0; i < MAX_ECC_BYTES; i++) { - if (ctrl->ecc_layout[i] == 0xffff) - break; - else - printf("%c%d", i%16 ? ' ' : '\n', - ctrl->ecc_layout[i]); - } - printf("\n"); -} - -static int -is_ctrl_running(int ctrl_no, int *running) -{ - struct sim_ctrl ctrl; - int err, fd; - - ctrl.num = ctrl_no; - if (opendev(&fd) != EX_OK) - return (EX_OSFILE); - - err = ioctl(fd, NANDSIM_STATUS_CTRL, &ctrl); - if (err) { - error(MSG_STATUSACQCTRL, ctrl_no); - close(fd); - return (err); - } - *running = ctrl.running; - close(fd); - return (0); -} - -static int -is_ctrl_created(int ctrl_no, int *created) -{ - struct sim_ctrl ctrl; - int err, fd; - - ctrl.num = ctrl_no; - - if (opendev(&fd) != EX_OK) - return (EX_OSFILE); - - err = ioctl(fd, NANDSIM_STATUS_CTRL, &ctrl); - if (err) { - error("Could not acquire conf for ctrl#%d", ctrl_no); - close(fd); - return (err); - } - *created = ctrl.created; - close(fd); - return (0); -} - -static int -is_chip_created(int ctrl_no, int chip_no, int *created) -{ - struct sim_chip chip; - int err, fd; - - chip.ctrl_num = ctrl_no; - chip.num = chip_no; - - if (opendev(&fd) != EX_OK) - return (EX_OSFILE); - - err = ioctl(fd, NANDSIM_STATUS_CHIP, &chip); - if (err) { - error("Could not acquire conf for chip#%d", chip_no); - close(fd); - return (err); - } - *created = chip.created; - close(fd); - return (0); -} - -static int -assert_chip_connected(int ctrl_no, int chip_no) -{ - int created, running; - - if (is_ctrl_created(ctrl_no, &created)) - return (0); - - if (!created) { - error(MSG_NOCTRL, ctrl_no); - return (0); - } - - if (is_chip_created(ctrl_no, chip_no, &created)) - return (0); - - if (!created) { - error(MSG_NOTCONFIGDCTRLCHIP, ctrl_no, chip_no); - return (0); - } - - if (is_ctrl_running(ctrl_no, &running)) - return (0); - - if (!running) { - error(MSG_NOTRUNNING, ctrl_no); - return (0); - } - - return (1); -} - -static int -printstats(int ctrlno, int chipno, uint32_t pageno, int cdevd) -{ - struct page_stat_io pstats; - struct block_stat_io bstats; - struct chip_param_io cparams; - uint32_t blkidx; - int err; - - /* Gather information about chip */ - err = ioctl(cdevd, NAND_IO_GET_CHIP_PARAM, &cparams); - - if (err) { - error("Could not acquire chip info for chip attached to cs#" - "%d, ctrl#%d", chipno, ctrlno); - return (EX_SOFTWARE); - } - - blkidx = (pageno / cparams.pages_per_block); - bstats.block_num = blkidx; - - err = ioctl(cdevd, NAND_IO_BLOCK_STAT, &bstats); - if (err) { - error("Could not acquire block#%d statistics!", blkidx); - return (ENXIO); - } - - printf("Block #%d erased: %d\n", blkidx, bstats.block_erased); - pstats.page_num = pageno; - - err = ioctl(cdevd, NAND_IO_PAGE_STAT, &pstats); - if (err) { - error("Could not acquire page statistics!"); - return (ENXIO); - } - - debug("BLOCKIDX = %d PAGENO (REL. TO BLK) = %d\n", blkidx, - pstats.page_num); - - printf("Page#%d : reads:%d writes:%d \n\traw reads:%d raw writes:%d " - "\n\tecc_succeeded:%d ecc_corrected:%d ecc_failed:%d\n", - pstats.page_num, pstats.page_read, pstats.page_written, - pstats.page_raw_read, pstats.page_raw_written, - pstats.ecc_succeded, pstats.ecc_corrected, pstats.ecc_failed); - return (0); -} diff --git a/usr.sbin/nandsim/nandsim_cfgparse.c b/usr.sbin/nandsim/nandsim_cfgparse.c deleted file mode 100644 index 4a310fb58a0f..000000000000 --- a/usr.sbin/nandsim/nandsim_cfgparse.c +++ /dev/null @@ -1,961 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * 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 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/errno.h> -#include <sys/ioctl.h> -#include <sys/types.h> - -#include <dev/nand/nandsim.h> - -#include <ctype.h> -#include <fcntl.h> -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <sysexits.h> -#include <unistd.h> - -#include "nandsim_cfgparse.h" - -#define warn(fmt, args...) do { \ - printf("WARNING: " fmt "\n", ##args); } while (0) - -#define error(fmt, args...) do { \ - printf("ERROR: " fmt "\n", ##args); } while (0) - -#define MSG_MANDATORYKEYMISSING "mandatory key \"%s\" value belonging to " \ - "section \"%s\" is missing!\n" - -#define DEBUG -#undef DEBUG - -#ifdef DEBUG -#define debug(fmt, args...) do { \ - printf("NANDSIM_CONF:" fmt "\n", ##args); } while (0) -#else -#define debug(fmt, args...) do {} while(0) -#endif - -#define STRBUFSIZ 2000 - -/* Macros extracts type and type size */ -#define TYPE(x) ((x) & 0xf8) -#define SIZE(x) (((x) & 0x07)) - -/* Erase/Prog/Read time max and min values */ -#define DELAYTIME_MIN 10000 -#define DELAYTIME_MAX 10000000 - -/* Structure holding configuration for controller. */ -static struct sim_ctrl ctrl_conf; -/* Structure holding configuration for chip. */ -static struct sim_chip chip_conf; - -static struct nandsim_key nandsim_ctrl_keys[] = { - {"num_cs", 1, VALUE_UINT | SIZE_8, (void *)&ctrl_conf.num_cs, 0}, - {"ctrl_num", 1, VALUE_UINT | SIZE_8, (void *)&ctrl_conf.num, 0}, - - {"ecc_layout", 1, VALUE_UINTARRAY | SIZE_16, - (void *)&ctrl_conf.ecc_layout, MAX_ECC_BYTES}, - - {"filename", 0, VALUE_STRING, - (void *)&ctrl_conf.filename, FILENAME_SIZE}, - - {"ecc", 0, VALUE_BOOL, (void *)&ctrl_conf.ecc, 0}, - {NULL, 0, 0, NULL, 0}, -}; - -static struct nandsim_key nandsim_chip_keys[] = { - {"chip_cs", 1, VALUE_UINT | SIZE_8, (void *)&chip_conf.num, 0}, - {"chip_ctrl", 1, VALUE_UINT | SIZE_8, (void *)&chip_conf.ctrl_num, - 0}, - {"device_id", 1, VALUE_UINT | SIZE_8, (void *)&chip_conf.device_id, - 0}, - {"manufacturer_id", 1, VALUE_UINT | SIZE_8, - (void *)&chip_conf.manufact_id, 0}, - {"model", 0, VALUE_STRING, (void *)&chip_conf.device_model, - DEV_MODEL_STR_SIZE}, - {"manufacturer", 0, VALUE_STRING, (void *)&chip_conf.manufacturer, - MAN_STR_SIZE}, - {"page_size", 1, VALUE_UINT | SIZE_32, (void *)&chip_conf.page_size, - 0}, - {"oob_size", 1, VALUE_UINT | SIZE_32, (void *)&chip_conf.oob_size, - 0}, - {"pages_per_block", 1, VALUE_UINT | SIZE_32, - (void *)&chip_conf.pgs_per_blk, 0}, - {"blocks_per_lun", 1, VALUE_UINT | SIZE_32, - (void *)&chip_conf.blks_per_lun, 0}, - {"luns", 1, VALUE_UINT | SIZE_32, (void *)&chip_conf.luns, 0}, - {"column_addr_cycle", 1,VALUE_UINT | SIZE_8, - (void *)&chip_conf.col_addr_cycles, 0}, - {"row_addr_cycle", 1, VALUE_UINT | SIZE_8, - (void *)&chip_conf.row_addr_cycles, 0}, - {"program_time", 0, VALUE_UINT | SIZE_32, - (void *)&chip_conf.prog_time, 0}, - {"erase_time", 0, VALUE_UINT | SIZE_32, - (void *)&chip_conf.erase_time, 0}, - {"read_time", 0, VALUE_UINT | SIZE_32, - (void *)&chip_conf.read_time, 0}, - {"width", 1, VALUE_UINT | SIZE_8, (void *)&chip_conf.width, 0}, - {"wear_out", 1, VALUE_UINT | SIZE_32, (void *)&chip_conf.wear_level, - 0}, - {"bad_block_map", 0, VALUE_UINTARRAY | SIZE_32, - (void *)&chip_conf.bad_block_map, MAX_BAD_BLOCKS}, - {NULL, 0, 0, NULL, 0}, -}; - -static struct nandsim_section sections[] = { - {"ctrl", (struct nandsim_key *)&nandsim_ctrl_keys}, - {"chip", (struct nandsim_key *)&nandsim_chip_keys}, - {NULL, NULL}, -}; - -static uint8_t logoutputtoint(char *, int *); -static uint8_t validate_chips(struct sim_chip *, int, struct sim_ctrl *, int); -static uint8_t validate_ctrls(struct sim_ctrl *, int); -static int configure_sim(const char *, struct rcfile *); -static int create_ctrls(struct rcfile *, struct sim_ctrl **, int *); -static int create_chips(struct rcfile *, struct sim_chip **, int *); -static void destroy_ctrls(struct sim_ctrl *); -static void destroy_chips(struct sim_chip *); -static int validate_section_config(struct rcfile *, const char *, int); - -int -convert_argint(char *arg, int *value) -{ - - if (arg == NULL || value == NULL) - return (EINVAL); - - errno = 0; - *value = (int)strtol(arg, NULL, 0); - if (*value == 0 && errno != 0) { - error("Cannot convert to number argument \'%s\'", arg); - return (EINVAL); - } - return (0); -} - -int -convert_arguint(char *arg, unsigned int *value) -{ - - if (arg == NULL || value == NULL) - return (EINVAL); - - errno = 0; - *value = (unsigned int)strtol(arg, NULL, 0); - if (*value == 0 && errno != 0) { - error("Cannot convert to number argument \'%s\'", arg); - return (EINVAL); - } - return (0); -} - -/* Parse given ',' separated list of bytes into buffer. */ -int -parse_intarray(char *array, int **buffer) -{ - char *tmp, *tmpstr, *origstr; - unsigned int currbufp = 0, i; - unsigned int count = 0, from = 0, to = 0; - - /* Remove square braces */ - if (array[0] == '[') - array ++; - if (array[strlen(array)-1] == ']') - array[strlen(array)-1] = ','; - - from = strlen(array); - origstr = (char *)malloc(sizeof(char) * from); - strcpy(origstr, array); - - tmpstr = (char *)strtok(array, ","); - /* First loop checks for how big int array we need to allocate */ - while (tmpstr != NULL) { - errno = 0; - if ((tmp = strchr(tmpstr, '-')) != NULL) { - *tmp = ' '; - if (convert_arguint(tmpstr, &from) || - convert_arguint(tmp, &to)) { - free(origstr); - return (EINVAL); - } - - count += to - from + 1; - } else { - if (convert_arguint(tmpstr, &from)) { - free(origstr); - return (EINVAL); - } - count++; - } - tmpstr = (char *)strtok(NULL, ","); - } - - if (count == 0) - goto out; - - /* Allocate buffer of ints */ - tmpstr = (char *)strtok(origstr, ","); - *buffer = malloc(count * sizeof(int)); - - /* Second loop is just inserting converted values into int array */ - while (tmpstr != NULL) { - errno = 0; - if ((tmp = strchr(tmpstr, '-')) != NULL) { - *tmp = ' '; - from = strtol(tmpstr, NULL, 0); - to = strtol(tmp, NULL, 0); - tmpstr = strtok(NULL, ","); - for (i = from; i <= to; i ++) - (*buffer)[currbufp++] = i; - continue; - } - errno = 0; - from = (int)strtol(tmpstr, NULL, 0); - (*buffer)[currbufp++] = from; - tmpstr = (char *)strtok(NULL, ","); - } -out: - free(origstr); - return (count); -} - -/* Convert logoutput strings literals into appropriate ints. */ -static uint8_t -logoutputtoint(char *logoutput, int *output) -{ - int out; - - if (strcmp(logoutput, "file") == 0) - out = NANDSIM_OUTPUT_FILE; - - else if (strcmp(logoutput, "console") == 0) - out = NANDSIM_OUTPUT_CONSOLE; - - else if (strcmp(logoutput, "ram") == 0) - out = NANDSIM_OUTPUT_RAM; - - else if (strcmp(logoutput, "none") == 0) - out = NANDSIM_OUTPUT_NONE; - else - out = -1; - - *output = out; - - if (out == -1) - return (EINVAL); - else - return (0); -} - -static int -configure_sim(const char *devfname, struct rcfile *f) -{ - struct sim_param sim_conf; - char buf[255]; - int err, tmpv, fd; - - err = rc_getint(f, "sim", 0, "log_level", &tmpv); - - if (tmpv < 0 || tmpv > 255 || err) { - error("Bad log level specified (%d)\n", tmpv); - return (ENOTSUP); - } else - sim_conf.log_level = tmpv; - - rc_getstring(f, "sim", 0, "log_output", 255, (char *)&buf); - - tmpv = -1; - err = logoutputtoint((char *)&buf, &tmpv); - if (err) { - error("Log output specified in config file does not seem to " - "be valid (%s)!", (char *)&buf); - return (ENOTSUP); - } - - sim_conf.log_output = tmpv; - - fd = open(devfname, O_RDWR); - if (fd == -1) { - error("could not open simulator device file (%s)!", - devfname); - return (EX_OSFILE); - } - - err = ioctl(fd, NANDSIM_SIM_PARAM, &sim_conf); - if (err) { - error("simulator parameters could not be modified: %s", - strerror(errno)); - close(fd); - return (ENXIO); - } - - close(fd); - return (EX_OK); -} - -static int -create_ctrls(struct rcfile *f, struct sim_ctrl **ctrls, int *cnt) -{ - int count, i; - struct sim_ctrl *ctrlsptr; - - count = rc_getsectionscount(f, "ctrl"); - if (count > MAX_SIM_DEV) { - error("Too many CTRL sections specified(%d)", count); - return (ENOTSUP); - } else if (count == 0) { - error("No ctrl sections specified"); - return (ENOENT); - } - - ctrlsptr = (struct sim_ctrl *)malloc(sizeof(struct sim_ctrl) * count); - if (ctrlsptr == NULL) { - error("Could not allocate memory for ctrl configuration"); - return (ENOMEM); - } - - for (i = 0; i < count; i++) { - bzero((void *)&ctrl_conf, sizeof(ctrl_conf)); - - /* - * ECC layout have to end up with 0xffff, so - * we're filling buffer with 0xff. If ecc_layout is - * defined in config file, values will be overridden. - */ - memset((void *)&ctrl_conf.ecc_layout, 0xff, - sizeof(ctrl_conf.ecc_layout)); - - if (validate_section_config(f, "ctrl", i) != 0) { - free(ctrlsptr); - return (EINVAL); - } - - if (parse_section(f, "ctrl", i) != 0) { - free(ctrlsptr); - return (EINVAL); - } - - memcpy(&ctrlsptr[i], &ctrl_conf, sizeof(ctrl_conf)); - /* Try to create ctrl with config parsed */ - debug("NUM=%d\nNUM_CS=%d\nECC=%d\nFILENAME=%s\nECC_LAYOUT[0]" - "=%d\nECC_LAYOUT[1]=%d\n\n", - ctrlsptr[i].num, ctrlsptr[i].num_cs, ctrlsptr[i].ecc, - ctrlsptr[i].filename, ctrlsptr[i].ecc_layout[0], - ctrlsptr[i].ecc_layout[1]); - } - *cnt = count; - *ctrls = ctrlsptr; - return (0); -} - -static void -destroy_ctrls(struct sim_ctrl *ctrls) -{ - - free(ctrls); -} - -static int -create_chips(struct rcfile *f, struct sim_chip **chips, int *cnt) -{ - struct sim_chip *chipsptr; - int count, i; - - count = rc_getsectionscount(f, "chip"); - if (count > (MAX_CTRL_CS * MAX_SIM_DEV)) { - error("Too many chip sections specified(%d)", count); - return (ENOTSUP); - } else if (count == 0) { - error("No chip sections specified"); - return (ENOENT); - } - - chipsptr = (struct sim_chip *)malloc(sizeof(struct sim_chip) * count); - if (chipsptr == NULL) { - error("Could not allocate memory for chip configuration"); - return (ENOMEM); - } - - for (i = 0; i < count; i++) { - bzero((void *)&chip_conf, sizeof(chip_conf)); - - /* - * Bad block map have to end up with 0xffff, so - * we're filling array with 0xff. If bad block map is - * defined in config file, values will be overridden. - */ - memset((void *)&chip_conf.bad_block_map, 0xff, - sizeof(chip_conf.bad_block_map)); - - if (validate_section_config(f, "chip", i) != 0) { - free(chipsptr); - return (EINVAL); - } - - if (parse_section(f, "chip", i) != 0) { - free(chipsptr); - return (EINVAL); - } - - memcpy(&chipsptr[i], &chip_conf, sizeof(chip_conf)); - - /* Try to create chip with config parsed */ - debug("CHIP:\nNUM=%d\nCTRL_NUM=%d\nDEVID=%d\nMANID=%d\n" - "PAGE_SZ=%d\nOOBSZ=%d\nREAD_T=%d\nDEVMODEL=%s\n" - "MAN=%s\nCOLADDRCYCLES=%d\nROWADDRCYCLES=%d\nCHWIDTH=%d\n" - "PGS/BLK=%d\nBLK/LUN=%d\nLUNS=%d\nERR_RATIO=%d\n" - "WEARLEVEL=%d\nISWP=%d\n\n\n\n", - chipsptr[i].num, chipsptr[i].ctrl_num, - chipsptr[i].device_id, chipsptr[i].manufact_id, - chipsptr[i].page_size, chipsptr[i].oob_size, - chipsptr[i].read_time, chipsptr[i].device_model, - chipsptr[i].manufacturer, chipsptr[i].col_addr_cycles, - chipsptr[i].row_addr_cycles, chipsptr[i].width, - chipsptr[i].pgs_per_blk, chipsptr[i].blks_per_lun, - chipsptr[i].luns, chipsptr[i].error_ratio, - chipsptr[i].wear_level, chipsptr[i].is_wp); - } - *cnt = count; - *chips = chipsptr; - return (0); -} - -static void -destroy_chips(struct sim_chip *chips) -{ - - free(chips); -} - -int -parse_config(char *cfgfname, const char *devfname) -{ - int err = 0, fd; - unsigned int chipsectionscnt, ctrlsectionscnt, i; - struct rcfile *f; - struct sim_chip *chips; - struct sim_ctrl *ctrls; - - err = rc_open(cfgfname, "r", &f); - if (err) { - error("could not open configuration file (%s)", cfgfname); - return (EX_NOINPUT); - } - - /* First, try to configure simulator itself. */ - if (configure_sim(devfname, f) != EX_OK) { - rc_close(f); - return (EINVAL); - } - - debug("SIM CONFIGURED!\n"); - /* Then create controllers' configs */ - if (create_ctrls(f, &ctrls, &ctrlsectionscnt) != 0) { - rc_close(f); - return (ENXIO); - } - debug("CTRLS CONFIG READ!\n"); - - /* Then create chips' configs */ - if (create_chips(f, &chips, &chipsectionscnt) != 0) { - destroy_ctrls(ctrls); - rc_close(f); - return (ENXIO); - } - debug("CHIPS CONFIG READ!\n"); - - if (validate_ctrls(ctrls, ctrlsectionscnt) != 0) { - destroy_ctrls(ctrls); - destroy_chips(chips); - rc_close(f); - return (EX_SOFTWARE); - } - if (validate_chips(chips, chipsectionscnt, ctrls, - ctrlsectionscnt) != 0) { - destroy_ctrls(ctrls); - destroy_chips(chips); - rc_close(f); - return (EX_SOFTWARE); - } - - /* Open device */ - fd = open(devfname, O_RDWR); - if (fd == -1) { - error("could not open simulator device file (%s)!", - devfname); - rc_close(f); - destroy_chips(chips); - destroy_ctrls(ctrls); - return (EX_OSFILE); - } - - debug("SIM CONFIG STARTED!\n"); - - /* At this stage, both ctrls' and chips' configs should be valid */ - for (i = 0; i < ctrlsectionscnt; i++) { - err = ioctl(fd, NANDSIM_CREATE_CTRL, &ctrls[i]); - if (err) { - if (err == EEXIST) - error("Controller#%d already created\n", - ctrls[i].num); - else if (err == EINVAL) - error("Incorrect controller number (%d)\n", - ctrls[i].num); - else - error("Could not created controller#%d\n", - ctrls[i].num); - /* Errors during controller creation stops parsing */ - close(fd); - rc_close(f); - destroy_ctrls(ctrls); - destroy_chips(chips); - return (ENXIO); - } - debug("CTRL#%d CONFIG STARTED!\n", i); - } - - for (i = 0; i < chipsectionscnt; i++) { - err = ioctl(fd, NANDSIM_CREATE_CHIP, &chips[i]); - if (err) { - if (err == EEXIST) - error("Chip#%d for controller#%d already " - "created\n", chips[i].num, - chips[i].ctrl_num); - else if (err == EINVAL) - error("Incorrect chip number (%d:%d)\n", - chips[i].num, chips[i].ctrl_num); - else - error("Could not create chip (%d:%d)\n", - chips[i].num, chips[i].ctrl_num); - error("Could not start chip#%d\n", i); - destroy_chips(chips); - destroy_ctrls(ctrls); - close(fd); - rc_close(f); - return (ENXIO); - } - } - debug("CHIPS CONFIG STARTED!\n"); - - close(fd); - rc_close(f); - destroy_chips(chips); - destroy_ctrls(ctrls); - return (0); -} - -/* - * Function tries to get appropriate value for given key, convert it to - * array of ints (of given size), and perform all the necessary checks and - * conversions. - */ -static int -get_argument_intarray(const char *sect_name, int sectno, - struct nandsim_key *key, struct rcfile *f) -{ - char strbuf[STRBUFSIZ]; - int *intbuf; - int getres; - uint32_t cnt, i = 0; - - getres = rc_getstring(f, sect_name, sectno, key->keyname, STRBUFSIZ, - (char *)&strbuf); - - if (getres != 0) { - if (key->mandatory != 0) { - error(MSG_MANDATORYKEYMISSING, key->keyname, - sect_name); - return (EINVAL); - } else - /* Non-mandatory key, not present -- skip */ - return (0); - } - cnt = parse_intarray((char *)&strbuf, &intbuf); - cnt = (cnt <= key->maxlength) ? cnt : key->maxlength; - - for (i = 0; i < cnt; i++) { - if (SIZE(key->valuetype) == SIZE_8) - *((uint8_t *)(key->field) + i) = - (uint8_t)intbuf[i]; - else if (SIZE(key->valuetype) == SIZE_16) - *((uint16_t *)(key->field) + i) = - (uint16_t)intbuf[i]; - else - *((uint32_t *)(key->field) + i) = - (uint32_t)intbuf[i]; - } - free(intbuf); - return (0); -} - -/* - * Function tries to get appropriate value for given key, convert it to - * int of certain length. - */ -static int -get_argument_int(const char *sect_name, int sectno, struct nandsim_key *key, - struct rcfile *f) -{ - int getres; - uint32_t val; - - getres = rc_getint(f, sect_name, sectno, key->keyname, &val); - if (getres != 0) { - - if (key->mandatory != 0) { - error(MSG_MANDATORYKEYMISSING, key->keyname, - sect_name); - - return (EINVAL); - } else - /* Non-mandatory key, not present -- skip */ - return (0); - } - if (SIZE(key->valuetype) == SIZE_8) - *(uint8_t *)(key->field) = (uint8_t)val; - else if (SIZE(key->valuetype) == SIZE_16) - *(uint16_t *)(key->field) = (uint16_t)val; - else - *(uint32_t *)(key->field) = (uint32_t)val; - return (0); -} - -/* Function tries to get string value for given key */ -static int -get_argument_string(const char *sect_name, int sectno, - struct nandsim_key *key, struct rcfile *f) -{ - char strbuf[STRBUFSIZ]; - int getres; - - getres = rc_getstring(f, sect_name, sectno, key->keyname, STRBUFSIZ, - strbuf); - - if (getres != 0) { - if (key->mandatory != 0) { - error(MSG_MANDATORYKEYMISSING, key->keyname, - sect_name); - return (1); - } else - /* Non-mandatory key, not present -- skip */ - return (0); - } - strncpy(key->field, (char *)&strbuf, (size_t)(key->maxlength - 1)); - return (0); -} - -/* Function tries to get on/off value for given key */ -static int -get_argument_bool(const char *sect_name, int sectno, struct nandsim_key *key, - struct rcfile *f) -{ - int getres, val; - - getres = rc_getbool(f, sect_name, sectno, key->keyname, &val); - if (getres != 0) { - if (key->mandatory != 0) { - error(MSG_MANDATORYKEYMISSING, key->keyname, - sect_name); - return (1); - } else - /* Non-mandatory key, not present -- skip */ - return (0); - } - *(uint8_t *)key->field = (uint8_t)val; - return (0); -} - -int -parse_section(struct rcfile *f, const char *sect_name, int sectno) -{ - struct nandsim_key *key; - struct nandsim_section *sect = (struct nandsim_section *)§ions; - int getres = 0; - - while (1) { - if (sect == NULL) - return (EINVAL); - - if (strcmp(sect->name, sect_name) == 0) - break; - else - sect++; - } - key = sect->keys; - do { - debug("->Section: %s, Key: %s, type: %d, size: %d", - sect_name, key->keyname, TYPE(key->valuetype), - SIZE(key->valuetype)/2); - - switch (TYPE(key->valuetype)) { - case VALUE_UINT: - /* Single int value */ - getres = get_argument_int(sect_name, sectno, key, f); - - if (getres != 0) - return (getres); - - break; - case VALUE_UINTARRAY: - /* Array of ints */ - getres = get_argument_intarray(sect_name, - sectno, key, f); - - if (getres != 0) - return (getres); - - break; - case VALUE_STRING: - /* Array of chars */ - getres = get_argument_string(sect_name, sectno, key, - f); - - if (getres != 0) - return (getres); - - break; - case VALUE_BOOL: - /* Boolean value (true/false/on/off/yes/no) */ - getres = get_argument_bool(sect_name, sectno, key, - f); - - if (getres != 0) - return (getres); - - break; - } - } while ((++key)->keyname != NULL); - - return (0); -} - -static uint8_t -validate_chips(struct sim_chip *chips, int chipcnt, - struct sim_ctrl *ctrls, int ctrlcnt) -{ - int cchipcnt, i, width, j, id, max; - - cchipcnt = chipcnt; - for (chipcnt -= 1; chipcnt >= 0; chipcnt--) { - if (chips[chipcnt].num >= MAX_CTRL_CS) { - error("chip no. too high (%d)!!\n", - chips[chipcnt].num); - return (EINVAL); - } - - if (chips[chipcnt].ctrl_num >= MAX_SIM_DEV) { - error("controller no. too high (%d)!!\n", - chips[chipcnt].ctrl_num); - return (EINVAL); - } - - if (chips[chipcnt].width != 8 && - chips[chipcnt].width != 16) { - error("invalid width:%d for chip#%d", - chips[chipcnt].width, chips[chipcnt].num); - return (EINVAL); - } - - /* Check if page size is > 512 and if its power of 2 */ - if (chips[chipcnt].page_size < 512 || - (chips[chipcnt].page_size & - (chips[chipcnt].page_size - 1)) != 0) { - error("invalid page size:%d for chip#%d at ctrl#%d!!" - "\n", chips[chipcnt].page_size, - chips[chipcnt].num, - chips[chipcnt].ctrl_num); - return (EINVAL); - } - - /* Check if controller no. ctrl_num is configured */ - for (i = 0, id = -1; i < ctrlcnt && id == -1; i++) - if (ctrls[i].num == chips[chipcnt].ctrl_num) - id = i; - - if (i == ctrlcnt && id == -1) { - error("Missing configuration for controller %d" - " (at least one chip is connected to it)", - chips[chipcnt].ctrl_num); - return (EINVAL); - } else { - /* - * Controller is configured -> check oob_size - * validity - */ - i = 0; - max = ctrls[id].ecc_layout[0]; - while (i < MAX_ECC_BYTES && - ctrls[id].ecc_layout[i] != 0xffff) { - - if (ctrls[id].ecc_layout[i] > max) - max = ctrls[id].ecc_layout[i]; - i++; - } - - if (chips[chipcnt].oob_size < (unsigned)i) { - error("OOB size for chip#%d at ctrl#%d is " - "smaller than ecc layout length!", - chips[chipcnt].num, - chips[chipcnt].ctrl_num); - exit(EINVAL); - } - - if (chips[chipcnt].oob_size < (unsigned)max) { - error("OOB size for chip#%d at ctrl#%d is " - "smaller than maximal ecc position in " - "defined layout!", chips[chipcnt].num, - chips[chipcnt].ctrl_num); - exit(EINVAL); - } - - - } - - if ((chips[chipcnt].erase_time < DELAYTIME_MIN || - chips[chipcnt].erase_time > DELAYTIME_MAX) && - chips[chipcnt].erase_time != 0) { - error("Invalid erase time value for chip#%d at " - "ctrl#%d", - chips[chipcnt].num, - chips[chipcnt].ctrl_num); - return (EINVAL); - } - - if ((chips[chipcnt].prog_time < DELAYTIME_MIN || - chips[chipcnt].prog_time > DELAYTIME_MAX) && - chips[chipcnt].prog_time != 0) { - error("Invalid prog time value for chip#%d at " - "ctr#%d!", - chips[chipcnt].num, - chips[chipcnt].ctrl_num); - return (EINVAL); - } - - if ((chips[chipcnt].read_time < DELAYTIME_MIN || - chips[chipcnt].read_time > DELAYTIME_MAX) && - chips[chipcnt].read_time != 0) { - error("Invalid read time value for chip#%d at " - "ctrl#%d!", - chips[chipcnt].num, - chips[chipcnt].ctrl_num); - return (EINVAL); - } - } - /* Check if chips attached to the same controller, have same width */ - for (i = 0; i < ctrlcnt; i++) { - width = -1; - for (j = 0; j < cchipcnt; j++) { - if (chips[j].ctrl_num == i) { - if (width == -1) { - width = chips[j].width; - } else { - if (width != chips[j].width) { - error("Chips attached to " - "ctrl#%d have different " - "widths!\n", i); - return (EINVAL); - } - } - } - } - } - - return (0); -} - -static uint8_t -validate_ctrls(struct sim_ctrl *ctrl, int ctrlcnt) -{ - for (ctrlcnt -= 1; ctrlcnt >= 0; ctrlcnt--) { - if (ctrl[ctrlcnt].num > MAX_SIM_DEV) { - error("Controller no. too high (%d)!!\n", - ctrl[ctrlcnt].num); - return (EINVAL); - } - if (ctrl[ctrlcnt].num_cs > MAX_CTRL_CS) { - error("Too many CS (%d)!!\n", ctrl[ctrlcnt].num_cs); - return (EINVAL); - } - if (ctrl[ctrlcnt].ecc != 0 && ctrl[ctrlcnt].ecc != 1) { - error("ECC is set to neither 0 nor 1 !\n"); - return (EINVAL); - } - } - - return (0); -} - -static int validate_section_config(struct rcfile *f, const char *sect_name, - int sectno) -{ - struct nandsim_key *key; - struct nandsim_section *sect; - char **keys_tbl; - int i, match; - - for (match = 0, sect = (struct nandsim_section *)§ions; - sect != NULL; sect++) { - if (strcmp(sect->name, sect_name) == 0) { - match = 1; - break; - } - } - - if (match == 0) - return (EINVAL); - - keys_tbl = rc_getkeys(f, sect_name, sectno); - if (keys_tbl == NULL) - return (ENOMEM); - - for (i = 0; keys_tbl[i] != NULL; i++) { - key = sect->keys; - match = 0; - do { - if (strcmp(keys_tbl[i], key->keyname) == 0) { - match = 1; - break; - } - } while ((++key)->keyname != NULL); - - if (match == 0) { - error("Invalid key in config file: %s\n", keys_tbl[i]); - free(keys_tbl); - return (EINVAL); - } - } - - free(keys_tbl); - return (0); -} diff --git a/usr.sbin/nandsim/nandsim_cfgparse.h b/usr.sbin/nandsim/nandsim_cfgparse.h deleted file mode 100644 index 12365666ad93..000000000000 --- a/usr.sbin/nandsim/nandsim_cfgparse.h +++ /dev/null @@ -1,88 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * 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 AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _NANDSIM_CONFPARSER_H_ -#define _NANDSIM_CONFPARSER_H_ - -#define VALUE_UINT 0x08 -#define VALUE_INT 0x10 -#define VALUE_UINTARRAY 0x18 -#define VALUE_INTARRAY 0x20 -#define VALUE_STRING 0x28 -#define VALUE_CHAR 0x40 -#define VALUE_BOOL 0x48 - -#define SIZE_8 0x01 -#define SIZE_16 0x02 -#define SIZE_32 0x04 - -#include "nandsim_rcfile.h" - -/* - * keyname = name of a key, - * mandatory = is key mandatory in section belonging to, 0=false 1=true - * valuetype = what kind of value is assigned to that key, e.g. - * VALUE_UINT | SIZE_8 -- unsigned uint size 8 bits; - * VALUE_UINTARRAY | SIZE_8 -- array of uints 8-bit long; - * VALUE_BOOL -- 'on', 'off','true','false','yes' or 'no' - * literals; - * VALUE_STRING -- strings - * field = ptr to the field that should hold value for parsed value - * maxlength = contains maximum length of an array (used only with either - * VALUE_STRING or VALUE_(U)INTARRAY value types. - */ -struct nandsim_key { - const char *keyname; - uint8_t mandatory; - uint8_t valuetype; - void *field; - uint32_t maxlength; -}; -struct nandsim_section { - const char *name; - struct nandsim_key *keys; -}; - -struct nandsim_config { - struct sim_param **simparams; - struct sim_chip **simchips; - struct sim_ctrl **simctrls; - int chipcnt; - int ctrlcnt; -}; - -int parse_intarray(char *, int **); -int parse_config(char *, const char *); -int parse_section(struct rcfile *, const char *, int); -int compare_configs(struct nandsim_config *, struct nandsim_config *); -int convert_argint(char *, int *); -int convert_arguint(char *, unsigned int *); - -#endif /* _NANDSIM_CONFPARSER_H_ */ diff --git a/usr.sbin/nandsim/nandsim_rcfile.c b/usr.sbin/nandsim/nandsim_rcfile.c deleted file mode 100644 index 8e9cca17f37b..000000000000 --- a/usr.sbin/nandsim/nandsim_rcfile.c +++ /dev/null @@ -1,442 +0,0 @@ -/* - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 1999, Boris Popov - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the author nor the names of any co-contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * from: FreeBSD: src/lib/libncp/ncpl_rcfile.c,v 1.5 2007/01/09 23:27:39 imp Exp - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); -#include <sys/types.h> -#include <sys/queue.h> -#include <ctype.h> -#include <errno.h> -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <pwd.h> -#include <unistd.h> - -#include "nandsim_rcfile.h" - -SLIST_HEAD(rcfile_head, rcfile); -static struct rcfile_head pf_head = {NULL}; -static struct rcsection *rc_findsect(struct rcfile *rcp, - const char *sectname, int sect_id); -static struct rcsection *rc_addsect(struct rcfile *rcp, - const char *sectname); -static int rc_sect_free(struct rcsection *rsp); -static struct rckey *rc_sect_findkey(struct rcsection *rsp, - const char *keyname); -static struct rckey *rc_sect_addkey(struct rcsection *rsp, const char *name, - char *value); -static void rc_key_free(struct rckey *p); -static void rc_parse(struct rcfile *rcp); - -static struct rcfile* rc_find(const char *filename); - -/* - * open rcfile and load its content, if already open - return previous handle - */ -int -rc_open(const char *filename, const char *mode,struct rcfile **rcfile) -{ - struct rcfile *rcp; - FILE *f; - rcp = rc_find(filename); - if (rcp) { - *rcfile = rcp; - return (0); - } - f = fopen (filename, mode); - if (f == NULL) - return errno; - rcp = malloc(sizeof(struct rcfile)); - if (rcp == NULL) { - fclose(f); - return ENOMEM; - } - bzero(rcp, sizeof(struct rcfile)); - rcp->rf_name = strdup(filename); - rcp->rf_f = f; - SLIST_INSERT_HEAD(&pf_head, rcp, rf_next); - rc_parse(rcp); - *rcfile = rcp; - return (0); -} - -int -rc_close(struct rcfile *rcp) -{ - struct rcsection *p,*n; - - fclose(rcp->rf_f); - for (p = SLIST_FIRST(&rcp->rf_sect); p; ) { - n = p; - p = SLIST_NEXT(p,rs_next); - rc_sect_free(n); - } - free(rcp->rf_name); - SLIST_REMOVE(&pf_head, rcp, rcfile, rf_next); - free(rcp); - return (0); -} - -static struct rcfile* -rc_find(const char *filename) -{ - struct rcfile *p; - - SLIST_FOREACH(p, &pf_head, rf_next) - if (strcmp (filename, p->rf_name) == 0) - return (p); - return (0); -} - -/* Find section with given name and id */ -static struct rcsection * -rc_findsect(struct rcfile *rcp, const char *sectname, int sect_id) -{ - struct rcsection *p; - - SLIST_FOREACH(p, &rcp->rf_sect, rs_next) - if (strcmp(p->rs_name, sectname) == 0 && p->rs_id == sect_id) - return (p); - return (NULL); -} - -static struct rcsection * -rc_addsect(struct rcfile *rcp, const char *sectname) -{ - struct rcsection *p; - int id = 0; - p = rc_findsect(rcp, sectname, 0); - if (p) { - /* - * If section with that name already exists -- add one more, - * same named, but with different id (higher by one) - */ - while (p != NULL) { - id = p->rs_id + 1; - p = rc_findsect(rcp, sectname, id); - } - } - p = malloc(sizeof(*p)); - if (!p) - return (NULL); - p->rs_name = strdup(sectname); - p->rs_id = id; - SLIST_INIT(&p->rs_keys); - SLIST_INSERT_HEAD(&rcp->rf_sect, p, rs_next); - return (p); -} - -static int -rc_sect_free(struct rcsection *rsp) -{ - struct rckey *p,*n; - - for (p = SLIST_FIRST(&rsp->rs_keys); p; ) { - n = p; - p = SLIST_NEXT(p,rk_next); - rc_key_free(n); - } - free(rsp->rs_name); - free(rsp); - return (0); -} - -static struct rckey * -rc_sect_findkey(struct rcsection *rsp, const char *keyname) -{ - struct rckey *p; - - SLIST_FOREACH(p, &rsp->rs_keys, rk_next) - if (strcmp(p->rk_name, keyname)==0) - return (p); - return (NULL); -} - -static struct rckey * -rc_sect_addkey(struct rcsection *rsp, const char *name, char *value) -{ - struct rckey *p; - p = rc_sect_findkey(rsp, name); - if (p) { - free(p->rk_value); - } else { - p = malloc(sizeof(*p)); - if (!p) - return (NULL); - SLIST_INSERT_HEAD(&rsp->rs_keys, p, rk_next); - p->rk_name = strdup(name); - } - p->rk_value = value ? strdup(value) : strdup(""); - return (p); -} - -static void -rc_key_free(struct rckey *p) -{ - free(p->rk_value); - free(p->rk_name); - free(p); -} - -enum { stNewLine, stHeader, stSkipToEOL, stGetKey, stGetValue}; - -static void -rc_parse(struct rcfile *rcp) -{ - FILE *f = rcp->rf_f; - int state = stNewLine, c; - struct rcsection *rsp = NULL; - struct rckey *rkp = NULL; - char buf[2048]; - char *next = buf, *last = &buf[sizeof(buf)-1]; - - while ((c = getc (f)) != EOF) { - if (c == '\r') - continue; - if (state == stNewLine) { - next = buf; - if (isspace(c)) - continue; /* skip leading junk */ - if (c == '[') { - state = stHeader; - rsp = NULL; - continue; - } - if (c == '#' || c == ';') { - state = stSkipToEOL; - } else { /* something meaningful */ - state = stGetKey; - } - } - if (state == stSkipToEOL || next == last) {/* ignore long lines */ - if (c == '\n') { - state = stNewLine; - next = buf; - } - continue; - } - if (state == stHeader) { - if (c == ']') { - *next = 0; - next = buf; - rsp = rc_addsect(rcp, buf); - state = stSkipToEOL; - } else - *next++ = c; - continue; - } - if (state == stGetKey) { - if (c == ' ' || c == '\t')/* side effect: 'key name='*/ - continue; /* become 'keyname=' */ - if (c == '\n') { /* silently ignore ... */ - state = stNewLine; - continue; - } - if (c != '=') { - *next++ = c; - continue; - } - *next = 0; - if (rsp == NULL) { - fprintf(stderr, "Key '%s' defined before " - "section\n", buf); - state = stSkipToEOL; - continue; - } - rkp = rc_sect_addkey(rsp, buf, NULL); - next = buf; - state = stGetValue; - continue; - } - /* only stGetValue left */ - if (state != stGetValue) { - fprintf(stderr, "Well, I can't parse file " - "'%s'\n",rcp->rf_name); - state = stSkipToEOL; - } - if (c != '\n') { - *next++ = c; - continue; - } - *next = 0; - rkp->rk_value = strdup(buf); - state = stNewLine; - rkp = NULL; - } /* while */ - if (c == EOF && state == stGetValue) { - *next = 0; - rkp->rk_value = strdup(buf); - } -} - -int -rc_getstringptr(struct rcfile *rcp, const char *section, int sect_id, - const char *key, char **dest) -{ - struct rcsection *rsp; - struct rckey *rkp; - - *dest = NULL; - rsp = rc_findsect(rcp, section, sect_id); - if (!rsp) - return (ENOENT); - rkp = rc_sect_findkey(rsp,key); - if (!rkp) - return (ENOENT); - *dest = rkp->rk_value; - return (0); -} - -int -rc_getstring(struct rcfile *rcp, const char *section, int sect_id, - const char *key, unsigned int maxlen, char *dest) -{ - char *value; - int error; - - error = rc_getstringptr(rcp, section, sect_id, key, &value); - if (error) - return (error); - if (strlen(value) >= maxlen) { - fprintf(stderr, "line too long for key '%s' in section '%s'," - "max = %d\n",key, section, maxlen); - return (EINVAL); - } - strcpy(dest,value); - return (0); -} - -int -rc_getint(struct rcfile *rcp, const char *section, int sect_id, - const char *key, int *value) -{ - struct rcsection *rsp; - struct rckey *rkp; - - rsp = rc_findsect(rcp, section, sect_id); - if (!rsp) - return (ENOENT); - rkp = rc_sect_findkey(rsp,key); - if (!rkp) - return (ENOENT); - errno = 0; - *value = strtol(rkp->rk_value,NULL,0); - if (errno) { - fprintf(stderr, "invalid int value '%s' for key '%s' in " - "section '%s'\n",rkp->rk_value,key,section); - return (errno); - } - return (0); -} - -/* - * 1,yes,true - * 0,no,false - */ -int -rc_getbool(struct rcfile *rcp, const char *section, int sect_id, - const char *key, int *value) -{ - struct rcsection *rsp; - struct rckey *rkp; - char *p; - - rsp = rc_findsect(rcp, section, sect_id); - if (!rsp) - return (ENOENT); - rkp = rc_sect_findkey(rsp,key); - if (!rkp) - return (ENOENT); - p = rkp->rk_value; - while (*p && isspace(*p)) p++; - if (*p == '0' || strcasecmp(p,"no") == 0 || - strcasecmp(p, "false") == 0 || - strcasecmp(p, "off") == 0) { - *value = 0; - return (0); - } - if (*p == '1' || strcasecmp(p,"yes") == 0 || - strcasecmp(p, "true") == 0 || - strcasecmp(p, "on") == 0) { - *value = 1; - return (0); - } - fprintf(stderr, "invalid boolean value '%s' for key '%s' in section " - "'%s' \n",p, key, section); - return (EINVAL); -} - -/* Count how many sections with given name exists in configuration. */ -int rc_getsectionscount(struct rcfile *f, const char *sectname) -{ - struct rcsection *p; - int count = 0; - - p = rc_findsect(f, sectname, 0); - if (p) { - while (p != NULL) { - count = p->rs_id + 1; - p = rc_findsect(f, sectname, count); - } - return (count); - } else - return (0); -} - -char ** -rc_getkeys(struct rcfile *rcp, const char *sectname, int sect_id) -{ - struct rcsection *rsp; - struct rckey *p; - char **names_tbl; - int i = 0, count = 0; - - rsp = rc_findsect(rcp, sectname, sect_id); - if (rsp == NULL) - return (NULL); - - SLIST_FOREACH(p, &rsp->rs_keys, rk_next) - count++; - - names_tbl = malloc(sizeof(char *) * (count + 1)); - if (names_tbl == NULL) - return (NULL); - - SLIST_FOREACH(p, &rsp->rs_keys, rk_next) - names_tbl[i++] = p->rk_name; - - names_tbl[i] = NULL; - return (names_tbl); -} - diff --git a/usr.sbin/nandsim/nandsim_rcfile.h b/usr.sbin/nandsim/nandsim_rcfile.h deleted file mode 100644 index d92ae870f0fc..000000000000 --- a/usr.sbin/nandsim/nandsim_rcfile.h +++ /dev/null @@ -1,72 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 1999, Boris Popov - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the author nor the names of any co-contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - * - * from: FreeBSD: src/lib/libncp/ncpl_rcfile.c,v 1.5 2007/01/09 23:27:39 imp Exp - */ - -#ifndef _SIMRC_H_ -#define _SIMRC_H_ - -#include <sys/queue.h> - -struct rckey { - SLIST_ENTRY(rckey) rk_next; - char *rk_name; /* key name */ - char *rk_value; /* key value */ -}; - -struct rcsection { - SLIST_ENTRY(rcsection) rs_next; - SLIST_HEAD(rckey_head,rckey) rs_keys; /* key list */ - char *rs_name; /* section name */ - int rs_id; /* allow few same named */ -}; - -struct rcfile { - SLIST_ENTRY(rcfile) rf_next; - SLIST_HEAD(rcsec_head, rcsection) rf_sect; /* sections list */ - char *rf_name; /* file name */ - FILE *rf_f; /* file desc */ -}; - -int rc_open(const char *, const char *,struct rcfile **); -int rc_close(struct rcfile *); -int rc_getstringptr(struct rcfile *, const char *, int, const char *, - char **); -int rc_getstring(struct rcfile *, const char *, int, const char *, - unsigned int, char *); -int rc_getint(struct rcfile *, const char *, int, const char *, int *); -int rc_getbool(struct rcfile *, const char *, int, const char *, int *); -int rc_getsectionscount(struct rcfile *, const char *); -char **rc_getkeys(struct rcfile *, const char *, int); - -#endif /* _SIMRC_H_ */ diff --git a/usr.sbin/nandsim/sample.conf b/usr.sbin/nandsim/sample.conf deleted file mode 100644 index bc534e109fe5..000000000000 --- a/usr.sbin/nandsim/sample.conf +++ /dev/null @@ -1,174 +0,0 @@ -#- -# Copyright (C) 2009-2012 Semihalf -# 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$ - -# -# Sample NANDsim configuration file. -# - -############################################################################# -# -# [sim] General (common) simulator configuration section. -# -[sim] -# log_level=0..255 -log_level=11 - -# log_output=[none, console, ram, file] -# -# When log_output=file is specified, each [ctrl] section must have a -# corresponding 'log_filename' field provided, which specifies log file name -# to be used. -log_output=none - -############################################################################# -# -# [ctrl] Controller configuration section. -# -# There can be a number of controllers defined for simulation, each has a -# dedicated [ctrl] section. With a given controller there are associated -# subordinate NAND chips, which are tied to chip select lines. -# -[ctrl] -# The number of this controller. -# ctrl_num=0..3 -ctrl_num=0 - -# The number of chip selects available at this controller. -# num_cs=1..4 -num_cs=1 - -# ECC enable flag. -# ecc=[on|off] -ecc=on - -# ECC layout. This is the list of byte offsets within OOB area, which comprise -# the ECC contents set. -# -# ecc_layout=[byte1, byte2-byte3, ..byten] -ecc_layout=[0-53] - -# Absolute path to the log file for this controller. -#log_filename=/var/log/nandsim-ctl0.log - - -############################################################################# -# -# [chip] Chip configuration section. -# -# There can be a number of individual NAND chip devices defined for -# simulation, and each has a dedicated [chip] section. -# -# A particular chip needs to be associated with its parent NAND controller by -# specifying the following fields: controller number (chip_ctrl) and the chip -# select line it is connected to (chip_cs). The chip can be connected to only -# a single (and unique) controller:cs pair. -# -[chip] -# The number of parent controller. This has to fit one of the controller -# instance number (ctrl_num from [ctrl] section). -# chip_ctrl=0..3 -chip_ctrl=0 - -# Chip select line. -# chip_cs=0..3 -chip_cs=0 - -# ONFI device identifier. -# device_id=0x00..0xff -device_id=0xd3 - -# ONFI manufacturer identifier. -# manufacturer_id=0x00..0xff -manufacturer_id=0xec - -# Textual description of the chip. -# model="model_name" -model="k9xxg08uxM:1GiB 3,3V 8-bit" - -# Textual name of the chip manufacturer. -# manufacturer="manufacturer name" -manufacturer="SAMSUNG" - -# page_size=[must be power of 2 and >= 512] (in bytes) -page_size=2048 -# oob_size=[>0] -oob_size=64 -# pages_per_block=n*32 -pages_per_block=64 -# blocks_per_lun=[>0] -blocks_per_lun=4096 -# luns=1..N -luns=1 -# column_addr_cycle=[1,2] -column_addr_cycle=2 -# row_addr_cycle=[1,2,3] -row_addr_cycle=3 - -# program_time= (in us) -program_time=0 -# erase_time= (in us) -erase_time=0 -# read_time= (in us) -read_time=0 -# ccs_time= (in us) -#ccs_time=200 - -# Simulate write-protect on the chip. -# write_protect=[yes|no] -#write_protect=no - -# Blocks wear-out threshold. Each block has a counter of program-erase cycles; -# when this counter reaches 'wear_out' value a given block is treated as a bad -# block (access will report error). -# -# Setting wear_out to 0 means that blocks will never wear out. -# -# wear_out=0..100000 -wear_out=50000 - -# Errors per million read/write bytes. This simulates an accidental read/write -# block error, which can happen in real devices with certain probability. Note -# this isn't a bad block condition i.e. the block at which the read/write -# operation is simulated to fail here remains usable, only the operation has -# not succeeded (this is where ECC comes into play and is supposed to correct -# such problems). -# -# error_ratio=0..1000000 -#error_ratio=50 - -# Chip data bus width. All chips connected to the same controller must have -# the same bus width. -# -# width=[8|16] -width=8 - -# Bad block map. NANDsim emulates bad block behavior upon accessing a block -# with number from the specified list. -# -# bad_block_map=[bad_block1, bad_block2-bad_block3, ..bad_blockn] -bad_block_map=[100-200] - diff --git a/usr.sbin/nandtool/Makefile b/usr.sbin/nandtool/Makefile deleted file mode 100644 index c01c2fdedbbf..000000000000 --- a/usr.sbin/nandtool/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# $FreeBSD$ - -PROG= nandtool -SRCS= nandtool.c nand_read.c nand_write.c nand_erase.c nand_info.c -SRCS+= nand_readoob.c nand_writeoob.c -BINDIR= /usr/sbin -LIBADD= geom -MAN= nandtool.8 - -.include <bsd.prog.mk> diff --git a/usr.sbin/nandtool/Makefile.depend b/usr.sbin/nandtool/Makefile.depend deleted file mode 100644 index 0220673c9076..000000000000 --- a/usr.sbin/nandtool/Makefile.depend +++ /dev/null @@ -1,20 +0,0 @@ -# $FreeBSD$ -# Autogenerated - do NOT edit! - -DIRDEPS = \ - gnu/lib/csu \ - include \ - include/xlocale \ - lib/${CSU_DIR} \ - lib/libc \ - lib/libcompiler_rt \ - lib/libexpat \ - lib/libgeom \ - lib/libsbuf \ - - -.include <dirdeps.mk> - -.if ${DEP_RELDIR} == ${_DEP_RELDIR} -# local dependencies - needed for -jN in clean tree -.endif diff --git a/usr.sbin/nandtool/nand_erase.c b/usr.sbin/nandtool/nand_erase.c deleted file mode 100644 index e9742d15ddf9..000000000000 --- a/usr.sbin/nandtool/nand_erase.c +++ /dev/null @@ -1,116 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf. - * 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 <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <sys/types.h> -#include <sys/disk.h> -#include <libgeom.h> -#include <dev/nand/nand_dev.h> -#include "nandtool.h" - -int nand_erase(struct cmd_param *params) -{ - struct chip_param_io chip_params; - char *dev; - int fd = -1, ret = 0; - off_t pos, count; - off_t start, nblocks, i; - int block_size, mult; - - if (!(dev = param_get_string(params, "dev"))) { - fprintf(stderr, "Please supply valid 'dev' parameter.\n"); - return (1); - } - - if (param_has_value(params, "count")) - count = param_get_intx(params, "count"); - else - count = 1; - - if ((fd = g_open(dev, 1)) < 0) { - perrorf("Cannot open %s", dev); - return (1); - } - - if (ioctl(fd, NAND_IO_GET_CHIP_PARAM, &chip_params) == -1) { - perrorf("Cannot ioctl(NAND_IO_GET_CHIP_PARAM)"); - ret = 1; - goto out; - } - - block_size = chip_params.page_size * chip_params.pages_per_block; - - if (param_has_value(params, "page")) { - pos = chip_params.page_size * param_get_intx(params, "page"); - mult = chip_params.page_size; - } else if (param_has_value(params, "block")) { - pos = block_size * param_get_intx(params, "block"); - mult = block_size; - } else if (param_has_value(params, "pos")) { - pos = param_get_intx(params, "pos"); - mult = 1; - } else { - /* Erase whole chip */ - if (ioctl(fd, DIOCGMEDIASIZE, &count) == -1) { - ret = 1; - goto out; - } - - pos = 0; - mult = 1; - } - - if (pos % block_size) { - fprintf(stderr, "Position must be block-size aligned!\n"); - ret = 1; - goto out; - } - - count *= mult; - start = pos / block_size; - nblocks = count / block_size; - - for (i = 0; i < nblocks; i++) { - if (g_delete(fd, (start + i) * block_size, block_size) == -1) { - perrorf("Cannot erase block %d - probably a bad block", - start + i); - ret = 1; - } - } - -out: - g_close(fd); - - return (ret); -} - diff --git a/usr.sbin/nandtool/nand_info.c b/usr.sbin/nandtool/nand_info.c deleted file mode 100644 index 79f84abd1136..000000000000 --- a/usr.sbin/nandtool/nand_info.c +++ /dev/null @@ -1,88 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf. - * 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 <stdio.h> -#include <stdlib.h> -#include <stdint.h> -#include <string.h> -#include <libgeom.h> -#include <sys/disk.h> -#include <dev/nand/nand_dev.h> -#include "nandtool.h" - -int nand_info(struct cmd_param *params) -{ - struct chip_param_io chip_params; - int fd = -1, ret = 0; - int block_size; - off_t chip_size, media_size; - const char *dev; - - if ((dev = param_get_string(params, "dev")) == NULL) { - fprintf(stderr, "Please supply 'dev' parameter, eg. " - "'dev=/dev/gnand0'\n"); - return (1); - } - - if ((fd = g_open(dev, 1)) == -1) { - perrorf("Cannot open %s", dev); - return (1); - } - - if (ioctl(fd, NAND_IO_GET_CHIP_PARAM, &chip_params) == -1) { - perrorf("Cannot ioctl(NAND_IO_GET_CHIP_PARAM)"); - ret = 1; - goto out; - } - - if (ioctl(fd, DIOCGMEDIASIZE, &media_size) == -1) { - perrorf("Cannot ioctl(DIOCGMEDIASIZE)"); - ret = 1; - goto out; - } - - block_size = chip_params.page_size * chip_params.pages_per_block; - chip_size = block_size * chip_params.blocks; - - printf("Device:\t\t\t%s\n", dev); - printf("Page size:\t\t%d bytes\n", chip_params.page_size); - printf("Block size:\t\t%d bytes (%d KB)\n", block_size, - block_size / 1024); - printf("OOB size per page:\t%d bytes\n", chip_params.oob_size); - printf("Chip size:\t\t%jd MB\n", (uintmax_t)(chip_size / 1024 / 1024)); - printf("Slice size:\t\t%jd MB\n", - (uintmax_t)(media_size / 1024 / 1024)); - -out: - g_close(fd); - - return (ret); -} diff --git a/usr.sbin/nandtool/nand_read.c b/usr.sbin/nandtool/nand_read.c deleted file mode 100644 index 395b0c3fa7f5..000000000000 --- a/usr.sbin/nandtool/nand_read.c +++ /dev/null @@ -1,141 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf. - * 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 <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <fcntl.h> -#include <libgeom.h> -#include <sys/disk.h> -#include <dev/nand/nand_dev.h> -#include "nandtool.h" - -int nand_read(struct cmd_param *params) -{ - struct chip_param_io chip_params; - int fd = -1, out_fd = -1, done = 0, ret = 0; - char *dev, *out; - int pos, count, mult, block_size; - uint8_t *buf = NULL; - - if (!(dev = param_get_string(params, "dev"))) { - fprintf(stderr, "You must specify 'dev' parameter\n"); - return (1); - } - - if ((out = param_get_string(params, "out"))) { - out_fd = open(out, O_WRONLY|O_CREAT, 0666); - if (out_fd == -1) { - perrorf("Cannot open %s for writing", out); - return (1); - } - } - - if ((fd = g_open(dev, 1)) == -1) { - perrorf("Cannot open %s", dev); - ret = 1; - goto out; - } - - if (ioctl(fd, NAND_IO_GET_CHIP_PARAM, &chip_params) == -1) { - perrorf("Cannot ioctl(NAND_IO_GET_CHIP_PARAM)"); - ret = 1; - goto out; - } - - block_size = chip_params.page_size * chip_params.pages_per_block; - - if (param_has_value(params, "page")) { - pos = chip_params.page_size * param_get_int(params, "page"); - mult = chip_params.page_size; - } else if (param_has_value(params, "block")) { - pos = block_size * param_get_int(params, "block"); - mult = block_size; - } else if (param_has_value(params, "pos")) { - pos = param_get_int(params, "pos"); - mult = 1; - if (pos % chip_params.page_size) { - fprintf(stderr, "Position must be page-size aligned!\n"); - ret = 1; - goto out; - } - } else { - fprintf(stderr, "You must specify one of: 'block', 'page'," - "'pos' arguments\n"); - ret = 1; - goto out; - } - - if (!(param_has_value(params, "count"))) - count = mult; - else - count = param_get_int(params, "count") * mult; - - if (!(buf = malloc(chip_params.page_size))) { - perrorf("Cannot allocate buffer [size %x]", - chip_params.page_size); - ret = 1; - goto out; - } - - lseek(fd, pos, SEEK_SET); - - while (done < count) { - if ((ret = read(fd, buf, chip_params.page_size)) != - (int32_t)chip_params.page_size) { - perrorf("read error (read %d bytes)", ret); - goto out; - } - - if (out_fd != -1) { - done += ret; - if ((ret = write(out_fd, buf, chip_params.page_size)) != - (int32_t)chip_params.page_size) { - perrorf("write error (written %d bytes)", ret); - ret = 1; - goto out; - } - } else { - hexdumpoffset(buf, chip_params.page_size, done); - done += ret; - } - } - -out: - g_close(fd); - if (out_fd != -1) - close(out_fd); - if (buf) - free(buf); - - return (ret); -} - diff --git a/usr.sbin/nandtool/nand_readoob.c b/usr.sbin/nandtool/nand_readoob.c deleted file mode 100644 index 6c5bb372c3e0..000000000000 --- a/usr.sbin/nandtool/nand_readoob.c +++ /dev/null @@ -1,113 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf. - * 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 <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <fcntl.h> -#include <libgeom.h> -#include <sys/types.h> -#include <sys/disk.h> -#include <dev/nand/nand_dev.h> -#include "nandtool.h" - -int nand_read_oob(struct cmd_param *params) -{ - struct chip_param_io chip_params; - struct nand_oob_rw req; - char *dev, *out; - int fd = -1, fd_out = -1, ret = 0; - int page; - uint8_t *buf = NULL; - - if ((page = param_get_int(params, "page")) < 0) { - fprintf(stderr, "You must supply valid 'page' argument.\n"); - return (1); - } - - if (!(dev = param_get_string(params, "dev"))) { - fprintf(stderr, "You must supply 'dev' argument.\n"); - return (1); - } - - if ((out = param_get_string(params, "out"))) { - if ((fd_out = open(out, O_WRONLY | O_CREAT, 0666)) == -1) { - perrorf("Cannot open %s", out); - ret = 1; - goto out; - } - } - - if ((fd = g_open(dev, 1)) == -1) { - perrorf("Cannot open %s", dev); - ret = 1; - goto out; - } - - if (ioctl(fd, NAND_IO_GET_CHIP_PARAM, &chip_params) == -1) { - perrorf("Cannot ioctl(NAND_IO_GET_CHIP_PARAM)"); - ret = 1; - goto out; - } - - buf = malloc(chip_params.oob_size); - if (buf == NULL) { - perrorf("Cannot allocate %d bytes\n", chip_params.oob_size); - ret = 1; - goto out; - } - - req.page = page; - req.len = chip_params.oob_size; - req.data = buf; - - if (ioctl(fd, NAND_IO_OOB_READ, &req) == -1) { - perrorf("Cannot read OOB from %s", dev); - ret = 1; - goto out; - } - - if (fd_out != -1) - write(fd_out, buf, chip_params.oob_size); - else - hexdump(buf, chip_params.oob_size); - -out: - close(fd_out); - - if (fd != -1) - g_close(fd); - if (buf) - free(buf); - - return (ret); -} - diff --git a/usr.sbin/nandtool/nand_write.c b/usr.sbin/nandtool/nand_write.c deleted file mode 100644 index 481f1a453538..000000000000 --- a/usr.sbin/nandtool/nand_write.c +++ /dev/null @@ -1,145 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf. - * 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 <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <fcntl.h> -#include <libgeom.h> -#include <sys/disk.h> -#include <dev/nand/nand_dev.h> -#include "nandtool.h" - -int nand_write(struct cmd_param *params) -{ - struct chip_param_io chip_params; - char *dev, *file; - int in_fd = -1, ret = 0, done = 0; - int fd, block_size, mult, pos, count; - uint8_t *buf = NULL; - - if (!(dev = param_get_string(params, "dev"))) { - fprintf(stderr, "Please supply 'dev' argument.\n"); - return (1); - } - - if (!(file = param_get_string(params, "in"))) { - fprintf(stderr, "Please supply 'in' argument.\n"); - return (1); - } - - if ((fd = g_open(dev, 1)) == -1) { - perrorf("Cannot open %s", dev); - return (1); - } - - if ((in_fd = open(file, O_RDONLY)) == -1) { - perrorf("Cannot open file %s", file); - ret = 1; - goto out; - } - - if (ioctl(fd, NAND_IO_GET_CHIP_PARAM, &chip_params) == -1) { - perrorf("Cannot ioctl(NAND_IO_GET_CHIP_PARAM)"); - ret = 1; - goto out; - } - - block_size = chip_params.page_size * chip_params.pages_per_block; - - if (param_has_value(params, "page")) { - pos = chip_params.page_size * param_get_int(params, "page"); - mult = chip_params.page_size; - } else if (param_has_value(params, "block")) { - pos = block_size * param_get_int(params, "block"); - mult = block_size; - } else if (param_has_value(params, "pos")) { - pos = param_get_int(params, "pos"); - mult = 1; - if (pos % chip_params.page_size) { - fprintf(stderr, "Position must be page-size " - "aligned!\n"); - ret = 1; - goto out; - } - } else { - fprintf(stderr, "You must specify one of: 'block', 'page'," - "'pos' arguments\n"); - ret = 1; - goto out; - } - - if (!(param_has_value(params, "count"))) - count = mult; - else - count = param_get_int(params, "count") * mult; - - if (!(buf = malloc(chip_params.page_size))) { - perrorf("Cannot allocate buffer [size %x]", - chip_params.page_size); - ret = 1; - goto out; - } - - lseek(fd, pos, SEEK_SET); - - while (done < count) { - if ((ret = read(in_fd, buf, chip_params.page_size)) != - (int32_t)chip_params.page_size) { - if (ret > 0) { - /* End of file ahead, truncate here */ - break; - } else { - perrorf("Cannot read from %s", file); - ret = 1; - goto out; - } - } - - if ((ret = write(fd, buf, chip_params.page_size)) != - (int32_t)chip_params.page_size) { - ret = 1; - goto out; - } - - done += ret; - } - -out: - g_close(fd); - if (in_fd != -1) - close(in_fd); - if (buf) - free(buf); - - return (ret); -} - diff --git a/usr.sbin/nandtool/nand_writeoob.c b/usr.sbin/nandtool/nand_writeoob.c deleted file mode 100644 index f1143b8a382a..000000000000 --- a/usr.sbin/nandtool/nand_writeoob.c +++ /dev/null @@ -1,115 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf. - * 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 <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <fcntl.h> -#include <libgeom.h> -#include <sys/disk.h> -#include <dev/nand/nand_dev.h> -#include "nandtool.h" - -int nand_write_oob(struct cmd_param *params) -{ - struct chip_param_io chip_params; - struct nand_oob_rw req; - char *dev, *in; - int fd = -1, fd_in = -1, ret = 0; - uint8_t *buf = NULL; - int page; - - if (!(dev = param_get_string(params, "dev"))) { - fprintf(stderr, "Please supply valid 'dev' parameter.\n"); - return (1); - } - - if (!(in = param_get_string(params, "in"))) { - fprintf(stderr, "Please supply valid 'in' parameter.\n"); - return (1); - } - - if ((page = param_get_int(params, "page")) < 0) { - fprintf(stderr, "Please supply valid 'page' parameter.\n"); - return (1); - } - - if ((fd = g_open(dev, 1)) == -1) { - perrorf("Cannot open %s", dev); - return (1); - } - - if ((fd_in = open(in, O_RDONLY)) == -1) { - perrorf("Cannot open %s", in); - ret = 1; - goto out; - } - - if (ioctl(fd, NAND_IO_GET_CHIP_PARAM, &chip_params) == -1) { - perrorf("Cannot ioctl(NAND_IO_GET_CHIP_PARAM)"); - ret = 1; - goto out; - } - - buf = malloc(chip_params.oob_size); - if (buf == NULL) { - perrorf("Cannot allocate %d bytes\n", chip_params.oob_size); - ret = 1; - goto out; - } - - if (read(fd_in, buf, chip_params.oob_size) == -1) { - perrorf("Cannot read from %s", in); - ret = 1; - goto out; - } - - req.page = page; - req.len = chip_params.oob_size; - req.data = buf; - - if (ioctl(fd, NAND_IO_OOB_PROG, &req) == -1) { - perrorf("Cannot write OOB to %s", dev); - ret = 1; - goto out; - } - -out: - g_close(fd); - if (fd_in != -1) - close(fd_in); - if (buf) - free(buf); - - return (ret); -} - - diff --git a/usr.sbin/nandtool/nandtool.8 b/usr.sbin/nandtool/nandtool.8 deleted file mode 100644 index 8f8f1deffddf..000000000000 --- a/usr.sbin/nandtool/nandtool.8 +++ /dev/null @@ -1,184 +0,0 @@ -.\" Copyright (c) 2010 Semihalf -.\" 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 April 10, 2012 -.Dt NANDTOOL 8 -.Os -.Sh NAME -.Nm nandtool -.Nd NAND devices swiss army knife -.Sh SYNOPSIS -.Nm -.Ar command -.Op Ar operands ... -.Sh DESCRIPTION -The -.Nm -utility can be used to perform various operations on -.Xr gnand 4 -devices (read, write, erase, -read and write OOB area and to get info about NAND flash chip). -.Pp -The following commands are available: -.Bl -tag -width ".Cm of Ns = Ns Ar file" -.It Cm read Ns -Read pages from NAND device. -.It Cm write Ns -Write pages to NAND device. -.It Cm erase Ns -Erase blocks. -Requires offset aligned to block granularity. -.It Cm info Ns -Get information about NAND chip (page size, block size, OOB area size, chip size -and media size) -.It Cm readoob Ns -Read OOB area from specified page. -.It Cm writeoob Ns -Write OOB area bound to specified page. -.It Cm help Ns -Get usage info. -.El -.Sh COMMAND read -The following operands are available for -.Nm -.Cm read -command: -.Bl -tag -width ".Cm of Ns = Ns Ar file" -.It Cm dev Ns = Ns Ar <path> -Path to a -.Xr gnand 4 -device node, required for all operations. -.It Cm out Ns = Ns Ar <file> -Output file path. If not specified, page contents -will be dumped to stdout in format similar to -.Xr hexdump 1 -.It Cm page Ns = Ns Ar <n> -Offset on device, expressed as page number. -.It Cm block Ns = Ns Ar <n> -Offset on device, expressed as block number. -.It Cm pos Ns = Ns Ar <n> -Offset on device, expressed in bytes (however, must be aligned -to page granularity). -.It Cm count Ns = Ns Ar <n> -Count of objects (pages, blocks, bytes). -.El -.Sh COMMAND readoob -The following operands are available for -.Nm -.Cm readoob -command: -.Bl -tag -width ".Cm of Ns = Ns Ar file" -.It Cm dev Ns = Ns Ar <path> -Path to NAND device node. -.It Cm page Ns = Ns Ar <n> -Offset on device, expressed as page number. -.It Cm out Ns = Ns Ar <file> -Output file path, optional. -.El -.Sh COMMAND write -The following operands are available for -.Nm -.Cm write -command: -.Bl -tag -width ".Cm of Ns = Ns Ar file" -.It Cm dev Ns = Ns Ar <path> -Path to NAND device node. -.It Cm page Ns = Ns Ar <n> -Offset on device, expressed as page number. -.It Cm block Ns = Ns Ar <n> -Offset on device, expressed as block number. -.It Cm pos Ns = Ns Ar <n> -Offset on device, expressed in bytes (however, must be aligned -to page granularity). -.It Cm in Ns = Ns Ar <file> -Input file path. -.El -.Sh COMMAND writeoob -The following operands are available for -.Nm -.Cm writeoob -command: -.Bl -tag -width ".Cm of Ns = Ns Ar file" -.It Cm dev Ns = Ns Ar <path> -Path to NAND device node. -.It Cm page Ns = Ns Ar <n> -Offset on device, expressed as page number. -.It Cm in Ns = Ns Ar <file> -Input file path. -.El -.Sh COMMAND erase -The following operands are available for -.Nm -.Cm erase -command: -.Bl -tag -width ".Cm of Ns = Ns Ar file" -.It Cm dev Ns = Ns Ar <path> -Path to NAND device node. -.It Cm page Ns = Ns Ar <n> -Offset on device, expressed as page number. -.It Cm block Ns = Ns Ar <n> -Offset on device, expressed as block number. -.It Cm pos Ns = Ns Ar <n> -Offset on device, epressed in bytes (however, must be aligned -to block granularity). -.It Cm count Ns = Ns Ar <n> -Count of objects (pages, blocks, bytes). -.El -.Pp -WARNING: The only required parameter for the \fBerase\fP command is -.Ar dev . -When no other arguments are provided the whole device is erased! -.Sh COMMAND info -There is only one operand available for -.Nm -.Cm info -command: -.Bl -tag -width ".Cm of Ns = Ns Ar file" -.It Cm dev Ns = Ns Ar <path> -Path to NAND device node. -.El -.Sh COMMAND help -There is only one operand available for -.Nm -.Cm help -command: -.Bl -tag -width ".Cm of Ns = Ns Ar file" -.It Cm topic Ns = Ns Ar <name> -Help topic. -.El -.Sh EXIT STATUS -.Ex -std -If the supplied argument -.Ar dev -points to a device node other than gnand<num> or gnand.raw<num> both -.Nm -.Cm readoob -and -.Nm -.Cm writeoob -return error. -.Sh SEE ALSO -.Xr gnand 4 diff --git a/usr.sbin/nandtool/nandtool.c b/usr.sbin/nandtool/nandtool.c deleted file mode 100644 index e87ed7342e6d..000000000000 --- a/usr.sbin/nandtool/nandtool.c +++ /dev/null @@ -1,285 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf. - * 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 <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <stdarg.h> -#include <ctype.h> -#include <sysexits.h> -#include <libgeom.h> -#include "nandtool.h" -#include "usage.h" - -int usage(struct cmd_param *); - -static const struct { - const char *name; - const char *usage; - int (*handler)(struct cmd_param *); -} commands[] = { - { "help", nand_help_usage, usage }, - { "read", nand_read_usage, nand_read }, - { "write", nand_write_usage, nand_write }, - { "erase", nand_erase_usage, nand_erase }, - { "readoob", nand_read_oob_usage, nand_read_oob }, - { "writeoob", nand_write_oob_usage, nand_write_oob }, - { "info", nand_info_usage, nand_info }, - { NULL, NULL, NULL }, -}; - -static char * -_param_get_stringx(struct cmd_param *params, const char *name, int doexit) -{ - int i; - - for (i = 0; params[i].name[0] != '\0'; i++) { - if (!strcmp(params[i].name, name)) - return params[i].value; - } - - if (doexit) { - perrorf("Missing parameter %s", name); - exit(1); - } - return (NULL); -} - -char * -param_get_string(struct cmd_param *params, const char *name) -{ - - return (_param_get_stringx(params, name, 0)); -} - -static int -_param_get_intx(struct cmd_param *params, const char *name, int doexit) -{ - int ret; - char *str = _param_get_stringx(params, name, doexit); - - if (!str) - return (-1); - - errno = 0; - ret = (int)strtol(str, (char **)NULL, 10); - if (errno) { - if (doexit) { - perrorf("Invalid value for parameter %s", name); - exit(1); - } - return (-1); - } - - return (ret); -} - -int -param_get_intx(struct cmd_param *params, const char *name) -{ - - return (_param_get_intx(params, name, 1)); -} - -int -param_get_int(struct cmd_param *params, const char *name) -{ - - return (_param_get_intx(params, name, 0)); -} - -int -param_get_boolean(struct cmd_param *params, const char *name) -{ - char *str = param_get_string(params, name); - - if (!str) - return (0); - - if (!strcmp(str, "true") || !strcmp(str, "yes")) - return (1); - - return (0); -} - -int -param_has_value(struct cmd_param *params, const char *name) -{ - int i; - - for (i = 0; params[i].name[0] != '\0'; i++) { - if (!strcmp(params[i].name, name)) - return (1); - } - - return (0); -} - -int -param_get_count(struct cmd_param *params) -{ - int i; - - for (i = 0; params[i].name[0] != '\0'; i++); - - return (i); -} - -void -hexdumpoffset(uint8_t *buf, int length, int off) -{ - int i, j; - for (i = 0; i < length; i += 16) { - printf("%08x: ", off + i); - - for (j = 0; j < 16; j++) - printf("%02x ", buf[i+j]); - - printf("| "); - - for (j = 0; j < 16; j++) { - printf("%c", isalnum(buf[i+j]) - ? buf[i+j] - : '.'); - } - - printf("\n"); - } -} - -void -hexdump(uint8_t *buf, int length) -{ - - hexdumpoffset(buf, length, 0); -} - -void * -xmalloc(size_t len) -{ - void *ret = malloc(len); - - if (!ret) { - fprintf(stderr, "Cannot allocate buffer of %zd bytes. " - "Exiting.\n", len); - exit(EX_OSERR); - } - - return (ret); -} - -void -perrorf(const char *format, ...) -{ - va_list args; - - va_start(args, format); - vfprintf(stderr, format, args); - va_end(args); - fprintf(stderr, ": %s\n", strerror(errno)); -} - -int -usage(struct cmd_param *params) -{ - int i; - - if (!params || !param_get_count(params)) { - fprintf(stderr, "Usage: nandtool <command> [arguments...]\n"); - fprintf(stderr, "Arguments are in form 'name=value'.\n\n"); - fprintf(stderr, "Available commands:\n"); - - for (i = 0; commands[i].name != NULL; i++) - fprintf(stderr, "\t%s\n", commands[i].name); - - fprintf(stderr, "\n"); - fprintf(stderr, "For information about particular command, " - "type:\n"); - fprintf(stderr, "'nandtool help topic=<command>'\n"); - } else if (param_has_value(params, "topic")) { - for (i = 0; commands[i].name != NULL; i++) { - if (!strcmp(param_get_string(params, "topic"), - commands[i].name)) { - fprintf(stderr, commands[i].usage, "nandtool"); - return (0); - } - } - - fprintf(stderr, "No such command\n"); - return (EX_SOFTWARE); - } else { - fprintf(stderr, "Wrong arguments given. Try: 'nandtool help'\n"); - } - - return (EX_USAGE); -} - -int -main(int argc, const char *argv[]) -{ - struct cmd_param *params; - int i, ret, idx; - - if (argc < 2) { - usage(NULL); - return (0); - } - - params = malloc(sizeof(struct cmd_param) * (argc - 1)); - - for (i = 2, idx = 0; i < argc; i++, idx++) { - if (sscanf(argv[i], "%63[^=]=%63s", params[idx].name, - params[idx].value) < 2) { - fprintf(stderr, "Syntax error in argument %d. " - "Argument should be in form 'name=value'.\n", i); - free(params); - return (-1); - } - } - - params[idx].name[0] = '\0'; - params[idx].value[0] = '\0'; - - for (i = 0; commands[i].name != NULL; i++) { - if (!strcmp(commands[i].name, argv[1])) { - ret = commands[i].handler(params); - free(params); - return (ret); - } - } - - free(params); - fprintf(stderr, "Unknown command. Try '%s help'\n", argv[0]); - - return (-1); -} - diff --git a/usr.sbin/nandtool/nandtool.h b/usr.sbin/nandtool/nandtool.h deleted file mode 100644 index c0dd1c095444..000000000000 --- a/usr.sbin/nandtool/nandtool.h +++ /dev/null @@ -1,59 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef __UTILS_H -#define __UTILS_H - -struct cmd_param -{ - char name[64]; - char value[64]; -}; - -char *param_get_string(struct cmd_param *, const char *); -int param_get_int(struct cmd_param *, const char *); -int param_get_intx(struct cmd_param *, const char *); -int param_get_boolean(struct cmd_param *, const char *); -int param_has_value(struct cmd_param *, const char *); -int param_get_count(struct cmd_param *); -void perrorf(const char *, ...); -void hexdumpoffset(uint8_t *, int, int); -void hexdump(uint8_t *, int); -void *xmalloc(size_t); - -/* Command handlers */ -int nand_read(struct cmd_param *); -int nand_write(struct cmd_param *); -int nand_read_oob(struct cmd_param *); -int nand_write_oob(struct cmd_param *); -int nand_erase(struct cmd_param *); -int nand_info(struct cmd_param *); - -#endif /* __UTILS_H */ diff --git a/usr.sbin/nandtool/usage.h b/usr.sbin/nandtool/usage.h deleted file mode 100644 index 0dbb70a2c99d..000000000000 --- a/usr.sbin/nandtool/usage.h +++ /dev/null @@ -1,114 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef __USAGE_H -#define __USAGE_H - -static const char nand_help_usage[] = - "Usage: %s help topic=<cmd>\n" - "\n" - "Arguments:\n" - "\tcmd\t- [help|read|write|erase|readoob|writeoob|info]\n" - "\n"; - -static const char nand_read_usage[] = - "Usage: %s read dev=<gnand_device> (block|page|pos)=n [count=n]\n" - "\n" - "Arguments:\n" - "\tdev\t- path to gnand device node\n" - "\tblock\t- starting block or\n" - "\tpage\t- starting page or\n" - "\tpos\t- starting position (in bytes, must be page-aligned)\n" - "\tout\t- output file (hexdump to stdout if not supplied)\n" - "\n" - "Note that you can only specify only one of: 'block', 'page', 'pos'\n" - "parameters at once. 'count' parameter is meaningful in terms of used\n" - "unit (page, block or byte).\n"; - -static const char nand_write_usage[] = - "Usage: %s write dev=<gnand_device> in=<file> (block|page|pos)=n [count=n]\n" - "\n" - "Arguments:\n" - "\tdev\t- path to gnand device node\n" - "\tin\t- path to input file which be writed to gnand\n" - "\tblock\t- starting block or\n" - "\tpage\t- starting page or\n" - "\tpos\t- starting position (in bytes, must be page-aligned)\n" - "\tcount\t- byte/page/block count\n" - "\n" - ""; - -static const char nand_erase_usage[] = - "Usage: %s erase dev=<gnand_device> (block|page|pos)=n [count=n]\n" - "\n" - "Arguments:\n" - "\tdev\t- path to gnand device node\n" - "\tblock\t- starting block or\n" - "\tpage\t- starting page or\n" - "\tpos\t- starting position (in bytes, muse be block-aligned)\n" - "\tcount\t- byte/page/block count\n" - "\n" - "NOTE: position and count for erase operation MUST be block-aligned\n"; - -static const char nand_read_oob_usage[] = - "Usage: %s readoob dev=<gnand_device> page=n [out=file] [count=n]\n" - "\n" - "Arguments:\n" - "\tdev\t- path to gnand device node\n" - "\tpage\t- page (page) number\n" - "\tout\t- outut file (hexdump to stdout if not supplied)\n" - "\tcount\t- page count (default is 1)\n" - "\n" - "If you supply count parameter with value other than 1, data will be\n" - "read from subsequent page's OOB areas\n"; - -static const char nand_write_oob_usage[] = - "Usage: %s writeoob dev=<gnand_device> in=<file> page=n [count=n]\n" - "\n" - "\tdev\t- path to gnand device node\n" - "\tin\t- path to file containing data which will be written\n" - "\tpage\t- page (page) number\n" - "\n" - "If you supply count parameter with value other than 1, data will be\n" - "written to subsequent page's OOB areas\n"; - -static const char nand_info_usage[] = - "Usage: %s info dev=<gnand_device>\n" - "\n" - "Arguments:\n" - "\tdev\t- path to gnand device node\n"; - -static const char nand_stats_usage[] = - "Usage: %s stats dev=<gnand_device> (page|block)=<n>\n" - "\n" - "Arguments:\n" - "\tdev\t- path to gnand device node\n"; - -#endif /* __USAGE_H */ diff --git a/usr.sbin/usbdump/usbdump.c b/usr.sbin/usbdump/usbdump.c index ef4476f55d8c..a38d08a252af 100644 --- a/usr.sbin/usbdump/usbdump.c +++ b/usr.sbin/usbdump/usbdump.c @@ -149,7 +149,9 @@ static const char *errstr_table[USB_ERR_MAX] = { [USB_ERR_NOT_LOCKED] = "NOT_LOCKED", }; -static const char *xfertype_table[4] = { +#define USB_XFERTYPE_MAX 4 + +static const char *xfertype_table[USB_XFERTYPE_MAX] = { [UE_CONTROL] = "CTRL", [UE_ISOCHRONOUS] = "ISOC", [UE_BULK] = "BULK", @@ -320,6 +322,15 @@ usb_speedstr(uint8_t speed) return (speed_table[speed]); } +static const char * +usb_xferstr(uint8_t type) +{ + if (type >= USB_XFERTYPE_MAX || xfertype_table[type] == NULL) + return ("UNKN"); + else + return (xfertype_table[type]); +} + static void print_flags(uint32_t flags) { @@ -496,7 +507,7 @@ print_apacket(const struct header_32 *hdr, const uint8_t *ptr, int ptr_len) (int)len, buf, tv.tv_usec, (int)up->up_busunit, (int)up->up_address, (up->up_type == USBPF_XFERTAP_SUBMIT) ? "SUBM" : "DONE", - xfertype_table[up->up_xfertype], + usb_xferstr(up->up_xfertype), (unsigned int)up->up_endpoint, usb_speedstr(up->up_speed), (int)up->up_frames, |