Index: head/etc/mtree/BSD.include.dist =================================================================== --- head/etc/mtree/BSD.include.dist +++ head/etc/mtree/BSD.include.dist @@ -138,8 +138,6 @@ mpilib .. .. - nand - .. nvme .. ofw @@ -183,8 +181,6 @@ fdescfs .. msdosfs - .. - nandfs .. nfs .. Index: head/include/Makefile =================================================================== --- head/include/Makefile +++ head/include/Makefile @@ -48,7 +48,7 @@ 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 @@ 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 @@ 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 @@ ${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 @@ ${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 \ Index: head/lib/Makefile =================================================================== --- head/lib/Makefile +++ head/lib/Makefile @@ -174,7 +174,6 @@ 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 Index: head/lib/libnandfs/Makefile =================================================================== --- head/lib/libnandfs/Makefile +++ head/lib/libnandfs/Makefile @@ -1,10 +0,0 @@ -# $FreeBSD$ - -PACKAGE=lib${LIB} -LIB= nandfs -SRCS+= nandfs.c -INCS= libnandfs.h - -CFLAGS += -I${.CURDIR} - -.include Index: head/lib/libnandfs/Makefile.depend =================================================================== --- head/lib/libnandfs/Makefile.depend +++ head/lib/libnandfs/Makefile.depend @@ -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 - -.if ${DEP_RELDIR} == ${_DEP_RELDIR} -# local dependencies - needed for -jN in clean tree -.endif Index: head/lib/libnandfs/libnandfs.h =================================================================== --- head/lib/libnandfs/libnandfs.h +++ head/lib/libnandfs/libnandfs.h @@ -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 */ Index: head/lib/libnandfs/nandfs.c =================================================================== --- head/lib/libnandfs/nandfs.c +++ head/lib/libnandfs/nandfs.c @@ -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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#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); -} Index: head/sbin/Makefile =================================================================== --- head/sbin/Makefile +++ head/sbin/Makefile @@ -79,8 +79,6 @@ 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 Index: head/sbin/camcontrol/camcontrol.c =================================================================== --- head/sbin/camcontrol/camcontrol.c +++ head/sbin/camcontrol/camcontrol.c @@ -2326,11 +2326,9 @@ } } - 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; } @@ -2347,6 +2345,26 @@ free(ptr); 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; Index: head/sbin/nandfs/Makefile =================================================================== --- head/sbin/nandfs/Makefile +++ head/sbin/nandfs/Makefile @@ -1,10 +0,0 @@ -# $FreeBSD$ - -PACKAGE=nandfs -PROG= nandfs -SRCS= nandfs.c lssnap.c mksnap.c rmsnap.c -MAN= nandfs.8 - -LIBADD= nandfs - -.include Index: head/sbin/nandfs/Makefile.depend =================================================================== --- head/sbin/nandfs/Makefile.depend +++ head/sbin/nandfs/Makefile.depend @@ -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 - -.if ${DEP_RELDIR} == ${_DEP_RELDIR} -# local dependencies - needed for -jN in clean tree -.endif Index: head/sbin/nandfs/lssnap.c =================================================================== --- head/sbin/nandfs/lssnap.c +++ head/sbin/nandfs/lssnap.c @@ -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 -__FBSDID("$FreeBSD$"); -#include - -#include -#include -#include -#include - -#include -#include - -#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); -} Index: head/sbin/nandfs/mksnap.c =================================================================== --- head/sbin/nandfs/mksnap.c +++ head/sbin/nandfs/mksnap.c @@ -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 -__FBSDID("$FreeBSD$"); -#include - -#include -#include - -#include -#include - -#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); -} Index: head/sbin/nandfs/nandfs.h =================================================================== --- head/sbin/nandfs/nandfs.h +++ head/sbin/nandfs/nandfs.h @@ -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 */ Index: head/sbin/nandfs/nandfs.8 =================================================================== --- head/sbin/nandfs/nandfs.8 +++ head/sbin/nandfs/nandfs.8 @@ -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 . Index: head/sbin/nandfs/nandfs.c =================================================================== --- head/sbin/nandfs/nandfs.c +++ head/sbin/nandfs/nandfs.c @@ -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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include - -#include "nandfs.h" - -static void -usage(void) -{ - - fprintf(stderr, "usage: nandfs [lssnap | mksnap | rmsnap ] " - "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); -} Index: head/sbin/nandfs/rmsnap.c =================================================================== --- head/sbin/nandfs/rmsnap.c +++ head/sbin/nandfs/rmsnap.c @@ -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 -__FBSDID("$FreeBSD$"); -#include - -#include -#include -#include -#include - -#include -#include - -#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); -} Index: head/sbin/newfs_nandfs/Makefile =================================================================== --- head/sbin/newfs_nandfs/Makefile +++ head/sbin/newfs_nandfs/Makefile @@ -1,9 +0,0 @@ -# $FreeBSD$ - -PACKAGE=nandfs -PROG= newfs_nandfs -MAN= newfs_nandfs.8 - -LIBADD= geom - -.include Index: head/sbin/newfs_nandfs/Makefile.depend =================================================================== --- head/sbin/newfs_nandfs/Makefile.depend +++ head/sbin/newfs_nandfs/Makefile.depend @@ -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 - -.if ${DEP_RELDIR} == ${_DEP_RELDIR} -# local dependencies - needed for -jN in clean tree -.endif Index: head/sbin/newfs_nandfs/newfs_nandfs.8 =================================================================== --- head/sbin/newfs_nandfs/newfs_nandfs.8 +++ head/sbin/newfs_nandfs/newfs_nandfs.8 @@ -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 Index: head/sbin/newfs_nandfs/newfs_nandfs.c =================================================================== --- head/sbin/newfs_nandfs/newfs_nandfs.c +++ head/sbin/newfs_nandfs/newfs_nandfs.c @@ -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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#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); -} - - Index: head/share/man/man4/Makefile =================================================================== --- head/share/man/man4/Makefile +++ head/share/man/man4/Makefile @@ -303,8 +303,6 @@ mx25l.4 \ mxge.4 \ my.4 \ - nand.4 \ - nandsim.4 \ ${_ndis.4} \ net80211.4 \ netdump.4 \ Index: head/share/man/man4/nand.4 =================================================================== --- head/share/man/man4/nand.4 +++ head/share/man/man4/nand.4 @@ -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 . Index: head/share/man/man4/nandsim.4 =================================================================== --- head/share/man/man4/nandsim.4 +++ head/share/man/man4/nandsim.4 @@ -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 . Index: head/share/man/man5/Makefile =================================================================== --- head/share/man/man5/Makefile +++ head/share/man/man5/Makefile @@ -101,10 +101,6 @@ MAN+= hesiod.conf.5 .endif -.if ${MK_NAND} != "no" -MAN+= nandfs.5 -.endif - .if ${MK_PF} != "no" MAN+= pf.conf.5 \ pf.os.5 Index: head/share/man/man5/nandfs.5 =================================================================== --- head/share/man/man5/nandfs.5 +++ head/share/man/man5/nandfs.5 @@ -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/ /mnt" -.Pp -or: -.Dl "mount_nandfs /dev/ /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 . Index: head/share/mk/bsd.libnames.mk =================================================================== --- head/share/mk/bsd.libnames.mk +++ head/share/mk/bsd.libnames.mk @@ -104,7 +104,6 @@ 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 Index: head/share/mk/src.libnames.mk =================================================================== --- head/share/mk/src.libnames.mk +++ head/share/mk/src.libnames.mk @@ -135,7 +135,6 @@ memstat \ mp \ mt \ - nandfs \ ncurses \ ncursesw \ netgraph \ Index: head/share/mk/src.opts.mk =================================================================== --- head/share/mk/src.opts.mk +++ head/share/mk/src.opts.mk @@ -206,7 +206,6 @@ LOADER_FORCE_LE \ LOADER_VERBOSE \ LOADER_VERIEXEC_PASS_MANIFEST \ - NAND \ OFED_EXTRA \ OPENLDAP \ RPCBIND_WARMSTART_SUPPORT \ Index: head/stand/arm/uboot/conf.c =================================================================== --- head/stand/arm/uboot/conf.c +++ head/stand/arm/uboot/conf.c @@ -59,9 +59,6 @@ #if defined(LOADER_EXT2FS_SUPPORT) &ext2fs_fsops, #endif -#if defined(LOADER_NANDFS_SUPPORT) - &nandfs_fsops, -#endif #if defined(LOADER_NFS_SUPPORT) &nfs_fsops, #endif Index: head/stand/arm/uboot/version =================================================================== --- head/stand/arm/uboot/version +++ head/stand/arm/uboot/version @@ -3,6 +3,7 @@ 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. Index: head/stand/common/part.h =================================================================== --- head/stand/common/part.h +++ head/stand/common/part.h @@ -45,7 +45,6 @@ PART_EFI, PART_FREEBSD, PART_FREEBSD_BOOT, - PART_FREEBSD_NANDFS, PART_FREEBSD_UFS, PART_FREEBSD_ZFS, PART_FREEBSD_SWAP, Index: head/stand/common/part.c =================================================================== --- head/stand/common/part.c +++ head/stand/common/part.c @@ -57,7 +57,6 @@ 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 @@ { 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 @@ 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 @@ { switch (type) { - case FS_NANDFS: - return (PART_FREEBSD_NANDFS); case FS_SWAP: return (PART_FREEBSD_SWAP); case FS_BSDFFS: @@ -527,8 +521,6 @@ { 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: Index: head/stand/i386/loader/conf.c =================================================================== --- head/stand/i386/loader/conf.c +++ head/stand/i386/loader/conf.c @@ -84,9 +84,6 @@ #if defined(LOADER_CD9660_SUPPORT) &cd9660_fsops, #endif -#if defined(LOADER_NANDFS_SUPPORT) - &nandfs_fsops, -#endif #ifdef LOADER_NFS_SUPPORT &nfs_fsops, #endif Index: head/stand/libsa/Makefile =================================================================== --- head/stand/libsa/Makefile +++ head/stand/libsa/Makefile @@ -145,9 +145,6 @@ 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 Index: head/stand/libsa/nandfs.c =================================================================== --- head/stand/libsa/nandfs.c +++ head/stand/libsa/nandfs.c @@ -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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#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); -} Index: head/stand/libsa/stand.h =================================================================== --- head/stand/libsa/stand.h +++ head/stand/libsa/stand.h @@ -119,7 +119,6 @@ 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; Index: head/stand/loader.mk =================================================================== --- head/stand/loader.mk +++ head/stand/loader.mk @@ -99,9 +99,6 @@ .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 Index: head/stand/mips/uboot/conf.c =================================================================== --- head/stand/mips/uboot/conf.c +++ head/stand/mips/uboot/conf.c @@ -62,9 +62,6 @@ #if defined(LOADER_EXT2FS_SUPPORT) &ext2fs_fsops, #endif -#if defined(LOADER_NANDFS_SUPPORT) - &nandfs_fsops, -#endif #if defined(LOADER_NFS_SUPPORT) &nfs_fsops, #endif Index: head/stand/mips/uboot/version =================================================================== --- head/stand/mips/uboot/version +++ head/stand/mips/uboot/version @@ -3,6 +3,7 @@ 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. Index: head/sys/arm/conf/DB-78XXX =================================================================== --- head/sys/arm/conf/DB-78XXX +++ head/sys/arm/conf/DB-78XXX @@ -74,9 +74,6 @@ # SATA device mvs -# NAND -device nand - # GPIO device gpio Index: head/sys/arm/conf/DB-88F6XXX =================================================================== --- head/sys/arm/conf/DB-88F6XXX +++ head/sys/arm/conf/DB-88F6XXX @@ -78,9 +78,6 @@ # SATA device mvs -# NAND -device nand - # GPIO device gpio Index: head/sys/arm/conf/DREAMPLUG-1001 =================================================================== --- head/sys/arm/conf/DREAMPLUG-1001 +++ head/sys/arm/conf/DREAMPLUG-1001 @@ -157,14 +157,6 @@ 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 Index: head/sys/arm/conf/NOTES.armv5 =================================================================== --- head/sys/arm/conf/NOTES.armv5 +++ head/sys/arm/conf/NOTES.armv5 @@ -31,8 +31,3 @@ options SOC_MV_DISCOVERY options SOC_MV_KIRKWOOD options SOC_MV_ORION - -# Add devices which are specific to various arm platforms... - -device nand - Index: head/sys/arm/conf/SHEEVAPLUG =================================================================== --- head/sys/arm/conf/SHEEVAPLUG +++ head/sys/arm/conf/SHEEVAPLUG @@ -72,9 +72,6 @@ device pass device da -# NAND -device nand - # GPIO device gpio Index: head/sys/arm/conf/VYBRID =================================================================== --- head/sys/arm/conf/VYBRID +++ head/sys/arm/conf/VYBRID @@ -37,7 +37,6 @@ #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 @@ -79,8 +78,6 @@ #device ata #device atadisk #device mvs - -device nand # Serial ports device uart Index: head/sys/arm/freescale/vybrid/vf_nfc.c =================================================================== --- head/sys/arm/freescale/vybrid/vf_nfc.c +++ head/sys/arm/freescale/vybrid/vf_nfc.c @@ -1,528 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2013 Ruslan Bukin - * 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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include "nfc_if.h" - -#include - -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 */ -} Index: head/sys/arm/mv/files.arm7 =================================================================== --- head/sys/arm/mv/files.arm7 +++ head/sys/arm/mv/files.arm7 @@ -29,7 +29,6 @@ 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 Index: head/sys/arm/mv/files.mv =================================================================== --- head/sys/arm/mv/files.mv +++ head/sys/arm/mv/files.mv @@ -26,7 +26,6 @@ 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 Index: head/sys/cam/ata/ata_all.h =================================================================== --- head/sys/cam/ata/ata_all.h +++ head/sys/cam/ata/ata_all.h @@ -135,7 +135,6 @@ 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); Index: head/sys/cam/ata/ata_all.c =================================================================== --- head/sys/cam/ata/ata_all.c +++ head/sys/cam/ata/ata_all.c @@ -1238,28 +1238,3 @@ 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)); -} Index: head/sys/cam/ata/ata_xpt.c =================================================================== --- head/sys/cam/ata/ata_xpt.c +++ head/sys/cam/ata/ata_xpt.c @@ -893,13 +893,14 @@ 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; - ata_param_fixup(ident_buf); + for (ptr = (int16_t *)ident_buf; + ptr < (int16_t *)ident_buf + sizeof(struct ata_params)/2; ptr++) { + *ptr = le16toh(*ptr); + } /* * Allow others to veto this ATA disk attachment. This @@ -911,6 +912,20 @@ 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) && Index: head/sys/cam/scsi/scsi_da.c =================================================================== --- head/sys/cam/scsi/scsi_da.c +++ head/sys/cam/scsi/scsi_da.c @@ -64,9 +64,6 @@ #include #include #include -#ifdef _KERNEL -#include -#endif /* _KERNEL */ #include #include @@ -3616,8 +3613,16 @@ break; } - ata_params = &periph->path->device->ident_data; + 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; + } + scsi_ata_identify(&start_ccb->csio, /*retries*/da_retry_count, /*cbfcnp*/dadone_probeata, @@ -5187,7 +5192,7 @@ struct da_softc *softc; u_int32_t priority; int continue_probe; - int error; + int error, i; int16_t *ptr; CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("dadone_probeata\n")); @@ -5205,7 +5210,8 @@ if ((csio->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { uint16_t old_rate; - ata_param_fixup(ata_params); + for (i = 0; i < sizeof(*ata_params) / 2; i++) + ptr[i] = le16toh(ptr[i]); if (ata_params->support_dsm & ATA_SUPPORT_DSM_TRIM && (softc->quirks & DA_Q_NO_UNMAP) == 0) { dadeleteflag(softc, DA_DELETE_ATA_TRIM, 1); @@ -5289,6 +5295,7 @@ } } + free(ata_params, M_SCSIDA); if ((softc->zone_mode == DA_ZONE_HOST_AWARE) || (softc->zone_mode == DA_ZONE_HOST_MANAGED)) { /* Index: head/sys/conf/files =================================================================== --- head/sys/conf/files +++ head/sys/conf/files @@ -1708,7 +1708,7 @@ 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 @@ -2457,21 +2457,6 @@ 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 @@ -3499,20 +3484,6 @@ 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 @@ -3600,7 +3571,7 @@ 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 Index: head/sys/conf/files.powerpc =================================================================== --- head/sys/conf/files.powerpc +++ head/sys/conf/files.powerpc @@ -43,8 +43,6 @@ 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 Index: head/sys/conf/kern.opts.mk =================================================================== --- head/sys/conf/kern.opts.mk +++ head/sys/conf/kern.opts.mk @@ -52,7 +52,6 @@ __DEFAULT_NO_OPTIONS = \ EXTRA_TCP_STACKS \ KERNEL_RETPOLINE \ - NAND \ OFED \ RATELIMIT Index: head/sys/dev/nand/nand.h =================================================================== --- head/sys/dev/nand/nand.h +++ head/sys/dev/nand/nand.h @@ -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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -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_ */ Index: head/sys/dev/nand/nand.c =================================================================== --- head/sys/dev/nand/nand.c +++ head/sys/dev/nand/nand.c @@ -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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include "nfc_if.h" -#include "nand_if.h" -#include "nandbus_if.h" -#include - -#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); Index: head/sys/dev/nand/nand_bbt.c =================================================================== --- head/sys/dev/nand/nand_bbt.c +++ head/sys/dev/nand/nand_bbt.c @@ -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 - -#include -#include -#include -#include -#include -#include - -#include - -#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); -} Index: head/sys/dev/nand/nand_cdev.c =================================================================== --- head/sys/dev/nand/nand_cdev.c +++ head/sys/dev/nand/nand_cdev.c @@ -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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#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); -} Index: head/sys/dev/nand/nand_dev.h =================================================================== --- head/sys/dev/nand/nand_dev.h +++ head/sys/dev/nand/nand_dev.h @@ -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 -#include - -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_ */ Index: head/sys/dev/nand/nand_ecc_pos.h =================================================================== --- head/sys/dev/nand/nand_ecc_pos.h +++ head/sys/dev/nand/nand_ecc_pos.h @@ -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_ */ - Index: head/sys/dev/nand/nand_generic.c =================================================================== --- head/sys/dev/nand/nand_generic.c +++ head/sys/dev/nand/nand_generic.c @@ -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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#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 Index: head/sys/dev/nand/nand_geom.c =================================================================== --- head/sys/dev/nand/nand_geom.c +++ head/sys/dev/nand/nand_geom.c @@ -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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#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); -} Index: head/sys/dev/nand/nand_id.c =================================================================== --- head/sys/dev/nand/nand_id.c +++ head/sys/dev/nand/nand_id.c @@ -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 -__FBSDID("$FreeBSD$"); - -#include -#include - -#include - -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); -} Index: head/sys/dev/nand/nand_if.m =================================================================== --- head/sys/dev/nand/nand_if.m +++ head/sys/dev/nand/nand_if.m @@ -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 -#include - -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; -}; - Index: head/sys/dev/nand/nandbus.h =================================================================== --- head/sys/dev/nand/nandbus.h +++ head/sys/dev/nand/nandbus.h @@ -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_ */ Index: head/sys/dev/nand/nandbus.c =================================================================== --- head/sys/dev/nand/nandbus.c +++ head/sys/dev/nand/nandbus.c @@ -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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#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)); -} - Index: head/sys/dev/nand/nandbus_if.m =================================================================== --- head/sys/dev/nand/nandbus_if.m +++ head/sys/dev/nand/nandbus_if.m @@ -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 -#include - -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; -}; - Index: head/sys/dev/nand/nandsim.h =================================================================== --- head/sys/dev/nand/nandsim.h +++ head/sys/dev/nand/nandsim.h @@ -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 -#include - -#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_ */ Index: head/sys/dev/nand/nandsim.c =================================================================== --- head/sys/dev/nand/nandsim.c +++ head/sys/dev/nand/nandsim.c @@ -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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -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); Index: head/sys/dev/nand/nandsim_chip.h =================================================================== --- head/sys/dev/nand/nandsim_chip.h +++ head/sys/dev/nand/nandsim_chip.h @@ -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 -#include -#include -#include -#include - -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 */ Index: head/sys/dev/nand/nandsim_chip.c =================================================================== --- head/sys/dev/nand/nandsim_chip.c +++ head/sys/dev/nand/nandsim_chip.c @@ -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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -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"); -} Index: head/sys/dev/nand/nandsim_ctrl.c =================================================================== --- head/sys/dev/nand/nandsim_ctrl.c +++ head/sys/dev/nand/nandsim_ctrl.c @@ -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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#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); - } -} Index: head/sys/dev/nand/nandsim_log.h =================================================================== --- head/sys/dev/nand/nandsim_log.h +++ head/sys/dev/nand/nandsim_log.h @@ -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 - -#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 */ - Index: head/sys/dev/nand/nandsim_log.c =================================================================== --- head/sys/dev/nand/nandsim_log.c +++ head/sys/dev/nand/nandsim_log.c @@ -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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -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; - } - } -} Index: head/sys/dev/nand/nandsim_swap.h =================================================================== --- head/sys/dev/nand/nandsim_swap.h +++ head/sys/dev/nand/nandsim_swap.h @@ -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_ */ Index: head/sys/dev/nand/nandsim_swap.c =================================================================== --- head/sys/dev/nand/nandsim_swap.c +++ head/sys/dev/nand/nandsim_swap.c @@ -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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -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); -} Index: head/sys/dev/nand/nfc_fsl.h =================================================================== --- head/sys/dev/nand/nfc_fsl.h +++ head/sys/dev/nand/nfc_fsl.h @@ -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_ */ Index: head/sys/dev/nand/nfc_fsl.c =================================================================== --- head/sys/dev/nand/nfc_fsl.c +++ head/sys/dev/nand/nfc_fsl.c @@ -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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include - -#include -#include - -#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 */ Index: head/sys/dev/nand/nfc_if.m =================================================================== --- head/sys/dev/nand/nfc_if.m +++ head/sys/dev/nand/nfc_if.m @@ -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 -#include - -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; Index: head/sys/dev/nand/nfc_mv.c =================================================================== --- head/sys/dev/nand/nfc_mv.c +++ head/sys/dev/nand/nfc_mv.c @@ -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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -#include -#include -#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 */ -} Index: head/sys/dev/nand/nfc_rb.c =================================================================== --- head/sys/dev/nand/nfc_rb.c +++ head/sys/dev/nand/nfc_rb.c @@ -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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include -#include - -#include -#include - -#include - -#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 */ -} Index: head/sys/fs/nandfs/bmap.h =================================================================== --- head/sys/fs/nandfs/bmap.h +++ head/sys/fs/nandfs/bmap.h @@ -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 */ Index: head/sys/fs/nandfs/bmap.c =================================================================== --- head/sys/fs/nandfs/bmap.c +++ head/sys/fs/nandfs/bmap.c @@ -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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#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); -} Index: head/sys/fs/nandfs/nandfs.h =================================================================== --- head/sys/fs/nandfs/nandfs.h +++ head/sys/fs/nandfs/nandfs.h @@ -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 -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#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_ */ Index: head/sys/fs/nandfs/nandfs_alloc.c =================================================================== --- head/sys/fs/nandfs/nandfs_alloc.c +++ head/sys/fs/nandfs/nandfs_alloc.c @@ -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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -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); -} Index: head/sys/fs/nandfs/nandfs_bmap.c =================================================================== --- head/sys/fs/nandfs/nandfs_bmap.c +++ head/sys/fs/nandfs/nandfs_bmap.c @@ -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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#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); -} Index: head/sys/fs/nandfs/nandfs_buffer.c =================================================================== --- head/sys/fs/nandfs/nandfs_buffer.c +++ head/sys/fs/nandfs/nandfs_buffer.c @@ -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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -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); -} Index: head/sys/fs/nandfs/nandfs_cleaner.c =================================================================== --- head/sys/fs/nandfs/nandfs_cleaner.c +++ head/sys/fs/nandfs/nandfs_cleaner.c @@ -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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#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); -} Index: head/sys/fs/nandfs/nandfs_cpfile.c =================================================================== --- head/sys/fs/nandfs/nandfs_cpfile.c +++ head/sys/fs/nandfs/nandfs_cpfile.c @@ -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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#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); -} Index: head/sys/fs/nandfs/nandfs_dat.c =================================================================== --- head/sys/fs/nandfs/nandfs_dat.c +++ head/sys/fs/nandfs/nandfs_dat.c @@ -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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -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); -} Index: head/sys/fs/nandfs/nandfs_dir.c =================================================================== --- head/sys/fs/nandfs/nandfs_dir.c +++ head/sys/fs/nandfs/nandfs_dir.c @@ -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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#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); -} Index: head/sys/fs/nandfs/nandfs_fs.h =================================================================== --- head/sys/fs/nandfs/nandfs_fs.h +++ head/sys/fs/nandfs/nandfs_fs.h @@ -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 - * and Ryusuke Konishi - * 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 - -#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 */ Index: head/sys/fs/nandfs/nandfs_ifile.c =================================================================== --- head/sys/fs/nandfs/nandfs_ifile.c +++ head/sys/fs/nandfs/nandfs_ifile.c @@ -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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -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); -} - Index: head/sys/fs/nandfs/nandfs_mount.h =================================================================== --- head/sys/fs/nandfs/nandfs_mount.h +++ head/sys/fs/nandfs/nandfs_mount.h @@ -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_ */ - Index: head/sys/fs/nandfs/nandfs_segment.c =================================================================== --- head/sys/fs/nandfs/nandfs_segment.c +++ head/sys/fs/nandfs/nandfs_segment.c @@ -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 -__FBSDID("$FreeBSD$"); - -#include "opt_ddb.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -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 \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 Index: head/sys/fs/nandfs/nandfs_subr.h =================================================================== --- head/sys/fs/nandfs/nandfs_subr.h +++ head/sys/fs/nandfs/nandfs_subr.h @@ -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_ */ Index: head/sys/fs/nandfs/nandfs_subr.c =================================================================== --- head/sys/fs/nandfs/nandfs_subr.c +++ head/sys/fs/nandfs/nandfs_subr.c @@ -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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include -#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)); -} Index: head/sys/fs/nandfs/nandfs_sufile.c =================================================================== --- head/sys/fs/nandfs/nandfs_sufile.c +++ head/sys/fs/nandfs/nandfs_sufile.c @@ -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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -#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); -} Index: head/sys/fs/nandfs/nandfs_vfsops.c =================================================================== --- head/sys/fs/nandfs/nandfs_vfsops.c +++ head/sys/fs/nandfs/nandfs_vfsops.c @@ -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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#include -#include -#include - -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); Index: head/sys/fs/nandfs/nandfs_vnops.c =================================================================== --- head/sys/fs/nandfs/nandfs_vnops.c +++ head/sys/fs/nandfs/nandfs_vnops.c @@ -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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include -#include -#include - -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); -} Index: head/sys/fs/smbfs/smbfs_io.c =================================================================== --- head/sys/fs/smbfs/smbfs_io.c +++ head/sys/fs/smbfs/smbfs_io.c @@ -375,6 +375,9 @@ */ 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; @@ -384,6 +387,7 @@ } if ((bp->b_flags & B_ASYNC) == 0) bp->b_flags |= B_EINTR; + splx(s); } else { if (error) { bp->b_ioflags |= BIO_ERROR; Index: head/sys/geom/geom_flashmap.c =================================================================== --- head/sys/geom/geom_flashmap.c +++ head/sys/geom/geom_flashmap.c @@ -43,8 +43,6 @@ #include #include -#include - struct g_flashmap_slice { off_t sl_start; off_t sl_end; @@ -65,7 +63,6 @@ { "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 @@ 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 @@ .name = FLASHMAP_CLASS_NAME, .version = G_VERSION, .taste = g_flashmap_taste, - .ioctl = g_flashmap_ioctl, }; DECLARE_GEOM_CLASS(g_flashmap_class, g_flashmap); Index: head/sys/modules/Makefile =================================================================== --- head/sys/modules/Makefile +++ head/sys/modules/Makefile @@ -255,8 +255,6 @@ ${_mwlfw} \ mxge \ my \ - ${_nandfs} \ - ${_nandsim} \ ${_nctgpio} \ ${_ndis} \ ${_netgraph} \ @@ -487,11 +485,6 @@ _mlx4ib= mlx4ib _mlx5ib= mlx5ib .endif -.endif - -.if ${MK_NAND} != "no" || defined(ALL_MODULES) -_nandfs= nandfs -_nandsim= nandsim .endif .if ${MK_NETGRAPH} != "no" || defined(ALL_MODULES) Index: head/sys/modules/nand/Makefile =================================================================== --- head/sys/modules/nand/Makefile +++ head/sys/modules/nand/Makefile @@ -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 Index: head/sys/modules/nandfs/Makefile =================================================================== --- head/sys/modules/nandfs/Makefile +++ head/sys/modules/nandfs/Makefile @@ -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 Index: head/sys/modules/nandsim/Makefile =================================================================== --- head/sys/modules/nandsim/Makefile +++ head/sys/modules/nandsim/Makefile @@ -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 Index: head/sys/sys/param.h =================================================================== --- head/sys/sys/param.h +++ head/sys/sys/param.h @@ -60,7 +60,7 @@ * in the range 5 to 9. */ #undef __FreeBSD_version -#define __FreeBSD_version 1300033 /* Master, propagated to newvers */ +#define __FreeBSD_version 1300034 /* Master, propagated to newvers */ /* * __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD, Index: head/targets/pseudo/userland/Makefile.depend =================================================================== --- head/targets/pseudo/userland/Makefile.depend +++ head/targets/pseudo/userland/Makefile.depend @@ -772,15 +772,6 @@ 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 \ Index: head/targets/pseudo/userland/lib/Makefile.depend =================================================================== --- head/targets/pseudo/userland/lib/Makefile.depend +++ head/targets/pseudo/userland/lib/Makefile.depend @@ -215,10 +215,6 @@ DIRDEPS+= stand/libsa32 .endif -.if ${MK_NAND} != "no" -DIRDEPS+= lib/libnandfs -.endif - .if ${MK_CASPER} != "no" DIRDEPS+= \ lib/libcasper/libcasper \ Index: head/usr.bin/vtfontcvt/vtfontcvt.c =================================================================== --- head/usr.bin/vtfontcvt/vtfontcvt.c +++ head/usr.bin/vtfontcvt/vtfontcvt.c @@ -335,11 +335,9 @@ break; } } - } 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); + } else if (strncmp(ln, "FONTBOUNDINGBOX ", 16) == 0 && + sscanf(ln + 16, "%d %d %d %d", &fbbw, &fbbh, &fbbox, + &fbboy) == 4) { set_width(fbbw); set_height(fbbh); break; @@ -355,9 +353,8 @@ linenum++; ln[length - 1] = '\0'; - if (strncmp(ln, "DWIDTH ", 7) == 0) { - if (sscanf(ln + 7, "%d %d", &dwidth, &dwy) != 2) - errx(1, "invalid DWIDTH at line %u", linenum); + if (strncmp(ln, "DWIDTH ", 7) == 0 && + sscanf(ln + 7, "%d %d", &dwidth, &dwy) == 2) { if (dwy != 0 || (dwidth != fbbw && dwidth * 2 != fbbw)) errx(1, "bitmap with unsupported DWIDTH %d %d at line %u", dwidth, dwy, linenum); Index: head/usr.sbin/Makefile =================================================================== --- head/usr.sbin/Makefile +++ head/usr.sbin/Makefile @@ -166,8 +166,6 @@ 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 Index: head/usr.sbin/bhyve/Makefile =================================================================== --- head/usr.sbin/bhyve/Makefile +++ head/usr.sbin/bhyve/Makefile @@ -16,7 +16,6 @@ SRCS= \ atkbdc.c \ acpi.c \ - audio.c \ bhyvegc.c \ bhyverun.c \ block_if.c \ @@ -28,7 +27,6 @@ dbgport.c \ fwctl.c \ gdb.c \ - hda_codec.c \ inout.c \ ioapic.c \ mem.c \ @@ -38,7 +36,6 @@ pci_ahci.c \ pci_e82545.c \ pci_emul.c \ - pci_hda.c \ pci_fbuf.c \ pci_hostbridge.c \ pci_irq.c \ Index: head/usr.sbin/bhyve/audio.h =================================================================== --- head/usr.sbin/bhyve/audio.h +++ head/usr.sbin/bhyve/audio.h @@ -1,86 +0,0 @@ -/*- - * Copyright (c) 2016 Alex Teaca - * 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 -#include - -/* - * 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_ */ Index: head/usr.sbin/bhyve/audio.c =================================================================== --- head/usr.sbin/bhyve/audio.c +++ head/usr.sbin/bhyve/audio.c @@ -1,282 +0,0 @@ -/*- - * Copyright (c) 2016 Alex Teaca - * 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 -__FBSDID("$FreeBSD$"); - -#ifndef WITHOUT_CAPSICUM -#include -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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; -} Index: head/usr.sbin/bhyve/bhyve.8 =================================================================== --- head/usr.sbin/bhyve/bhyve.8 +++ head/usr.sbin/bhyve/bhyve.8 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd June 24, 2019 +.Dd December 11, 2018 .Dt BHYVE 8 .Os .Sh NAME @@ -248,8 +248,6 @@ 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. @@ -476,16 +474,6 @@ 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 Index: head/usr.sbin/bhyve/hda_codec.c =================================================================== --- head/usr.sbin/bhyve/hda_codec.c +++ head/usr.sbin/bhyve/hda_codec.c @@ -1,950 +0,0 @@ -/*- - * Copyright (c) 2016 Alex Teaca - * 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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include - -#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); -} Index: head/usr.sbin/bhyve/hda_reg.h =================================================================== --- head/usr.sbin/bhyve/hda_reg.h +++ head/usr.sbin/bhyve/hda_reg.h @@ -1,1367 +0,0 @@ -/*- - * Copyright (c) 2006 Stephane E. Potvin - * 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_ */ Index: head/usr.sbin/bhyve/hdac_reg.h =================================================================== --- head/usr.sbin/bhyve/hdac_reg.h +++ head/usr.sbin/bhyve/hdac_reg.h @@ -1,269 +0,0 @@ -/*- - * Copyright (c) 2006 Stephane E. Potvin - * 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_ */ Index: head/usr.sbin/bhyve/pci_hda.h =================================================================== --- head/usr.sbin/bhyve/pci_hda.h +++ head/usr.sbin/bhyve/pci_hda.h @@ -1,90 +0,0 @@ -/*- - * Copyright (c) 2016 Alex Teaca - * 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 -#include -#include -#include -#include - -#include -#include -#include - -#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_ */ Index: head/usr.sbin/bhyve/pci_hda.c =================================================================== --- head/usr.sbin/bhyve/pci_hda.c +++ head/usr.sbin/bhyve/pci_hda.c @@ -1,1330 +0,0 @@ -/*- - * Copyright (c) 2016 Alex Teaca - * 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 -__FBSDID("$FreeBSD$"); - -#include - -#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; - int len; - int i; - - if (!opts) - return (0); - - len = strlen(opts); - - if (len >= 64) { - 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); -} Index: head/usr.sbin/nandsim/Makefile =================================================================== --- head/usr.sbin/nandsim/Makefile +++ head/usr.sbin/nandsim/Makefile @@ -1,8 +0,0 @@ -# $FreeBSD$ - -PROG= nandsim -SRCS= nandsim.c nandsim_rcfile.c nandsim_cfgparse.c -BINDIR= /usr/sbin -MAN= nandsim.8 - -.include Index: head/usr.sbin/nandsim/Makefile.depend =================================================================== --- head/usr.sbin/nandsim/Makefile.depend +++ head/usr.sbin/nandsim/Makefile.depend @@ -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 - -.if ${DEP_RELDIR} == ${_DEP_RELDIR} -# local dependencies - needed for -jN in clean tree -.endif Index: head/usr.sbin/nandsim/nandsim.8 =================================================================== --- head/usr.sbin/nandsim/nandsim.8 +++ head/usr.sbin/nandsim/nandsim.8 @@ -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 . Index: head/usr.sbin/nandsim/nandsim.c =================================================================== --- head/usr.sbin/nandsim/nandsim.c +++ head/usr.sbin/nandsim/nandsim.c @@ -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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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 [-v]\n" }, - {"conf", cmdconf, 1, - "conf \n" }, - {"start", cmdstart, 1, - "start \n" }, - {"mod", cmdmod, 2, - "mod [-l ] | [-p ]\n" - "\t[-e ] [-r ]\n" - "\t[-E ] | [-h]\n" }, - {"stop", cmdstop, 1, - "stop \n" }, - {"error", cmderror, 5, - "error \n" }, - {"bb", cmdbb, 2, - "bb [blk_num1,blk_num2,..] [-U] [-L]\n" }, - {"freeze", cmdfreeze, 1, - "freeze [ctrl_no]\n" }, - {"log", cmdlog, 1, - "log \n" }, - {"stats", cmdstats, 2, - "stats \n" }, - {"dump", cmddump, 2, - "dump \n" }, - {"restore", cmdrestore, 2, - "restore \n" }, - {"destroy", cmddestroy, 1, - "destroy \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 :, 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 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); -} Index: head/usr.sbin/nandsim/nandsim_cfgparse.h =================================================================== --- head/usr.sbin/nandsim/nandsim_cfgparse.h +++ head/usr.sbin/nandsim/nandsim_cfgparse.h @@ -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_ */ Index: head/usr.sbin/nandsim/nandsim_cfgparse.c =================================================================== --- head/usr.sbin/nandsim/nandsim_cfgparse.c +++ head/usr.sbin/nandsim/nandsim_cfgparse.c @@ -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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include - -#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); -} Index: head/usr.sbin/nandsim/nandsim_rcfile.h =================================================================== --- head/usr.sbin/nandsim/nandsim_rcfile.h +++ head/usr.sbin/nandsim/nandsim_rcfile.h @@ -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 - -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_ */ Index: head/usr.sbin/nandsim/nandsim_rcfile.c =================================================================== --- head/usr.sbin/nandsim/nandsim_rcfile.c +++ head/usr.sbin/nandsim/nandsim_rcfile.c @@ -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 -__FBSDID("$FreeBSD$"); -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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); -} - Index: head/usr.sbin/nandsim/sample.conf =================================================================== --- head/usr.sbin/nandsim/sample.conf +++ head/usr.sbin/nandsim/sample.conf @@ -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] - Index: head/usr.sbin/nandtool/Makefile =================================================================== --- head/usr.sbin/nandtool/Makefile +++ head/usr.sbin/nandtool/Makefile @@ -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 Index: head/usr.sbin/nandtool/Makefile.depend =================================================================== --- head/usr.sbin/nandtool/Makefile.depend +++ head/usr.sbin/nandtool/Makefile.depend @@ -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 - -.if ${DEP_RELDIR} == ${_DEP_RELDIR} -# local dependencies - needed for -jN in clean tree -.endif Index: head/usr.sbin/nandtool/nand_erase.c =================================================================== --- head/usr.sbin/nandtool/nand_erase.c +++ head/usr.sbin/nandtool/nand_erase.c @@ -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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#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); -} - Index: head/usr.sbin/nandtool/nand_info.c =================================================================== --- head/usr.sbin/nandtool/nand_info.c +++ head/usr.sbin/nandtool/nand_info.c @@ -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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#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); -} Index: head/usr.sbin/nandtool/nand_read.c =================================================================== --- head/usr.sbin/nandtool/nand_read.c +++ head/usr.sbin/nandtool/nand_read.c @@ -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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#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); -} - Index: head/usr.sbin/nandtool/nand_readoob.c =================================================================== --- head/usr.sbin/nandtool/nand_readoob.c +++ head/usr.sbin/nandtool/nand_readoob.c @@ -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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#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); -} - Index: head/usr.sbin/nandtool/nand_write.c =================================================================== --- head/usr.sbin/nandtool/nand_write.c +++ head/usr.sbin/nandtool/nand_write.c @@ -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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#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); -} - Index: head/usr.sbin/nandtool/nand_writeoob.c =================================================================== --- head/usr.sbin/nandtool/nand_writeoob.c +++ head/usr.sbin/nandtool/nand_writeoob.c @@ -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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#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); -} - - Index: head/usr.sbin/nandtool/nandtool.h =================================================================== --- head/usr.sbin/nandtool/nandtool.h +++ head/usr.sbin/nandtool/nandtool.h @@ -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 */ Index: head/usr.sbin/nandtool/nandtool.8 =================================================================== --- head/usr.sbin/nandtool/nandtool.8 +++ head/usr.sbin/nandtool/nandtool.8 @@ -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 to a -.Xr gnand 4 -device node, required for all operations. -.It Cm out Ns = Ns Ar -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 -Offset on device, expressed as page number. -.It Cm block Ns = Ns Ar -Offset on device, expressed as block number. -.It Cm pos Ns = Ns Ar -Offset on device, expressed in bytes (however, must be aligned -to page granularity). -.It Cm count Ns = Ns Ar -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 to NAND device node. -.It Cm page Ns = Ns Ar -Offset on device, expressed as page number. -.It Cm out Ns = Ns Ar -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 to NAND device node. -.It Cm page Ns = Ns Ar -Offset on device, expressed as page number. -.It Cm block Ns = Ns Ar -Offset on device, expressed as block number. -.It Cm pos Ns = Ns Ar -Offset on device, expressed in bytes (however, must be aligned -to page granularity). -.It Cm in Ns = Ns Ar -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 to NAND device node. -.It Cm page Ns = Ns Ar -Offset on device, expressed as page number. -.It Cm in Ns = Ns Ar -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 to NAND device node. -.It Cm page Ns = Ns Ar -Offset on device, expressed as page number. -.It Cm block Ns = Ns Ar -Offset on device, expressed as block number. -.It Cm pos Ns = Ns Ar -Offset on device, epressed in bytes (however, must be aligned -to block granularity). -.It Cm count Ns = Ns Ar -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 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 -Help topic. -.El -.Sh EXIT STATUS -.Ex -std -If the supplied argument -.Ar dev -points to a device node other than gnand or gnand.raw both -.Nm -.Cm readoob -and -.Nm -.Cm writeoob -return error. -.Sh SEE ALSO -.Xr gnand 4 Index: head/usr.sbin/nandtool/nandtool.c =================================================================== --- head/usr.sbin/nandtool/nandtool.c +++ head/usr.sbin/nandtool/nandtool.c @@ -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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#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 [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='\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); -} - Index: head/usr.sbin/nandtool/usage.h =================================================================== --- head/usr.sbin/nandtool/usage.h +++ head/usr.sbin/nandtool/usage.h @@ -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=\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= (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= in= (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= (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= 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= in= 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=\n" - "\n" - "Arguments:\n" - "\tdev\t- path to gnand device node\n"; - -static const char nand_stats_usage[] = - "Usage: %s stats dev= (page|block)=\n" - "\n" - "Arguments:\n" - "\tdev\t- path to gnand device node\n"; - -#endif /* __USAGE_H */