diff options
| author | Alan Somers <asomers@FreeBSD.org> | 2019-06-27 23:50:54 +0000 |
|---|---|---|
| committer | Alan Somers <asomers@FreeBSD.org> | 2019-06-27 23:50:54 +0000 |
| commit | 7f49ce7a0b5f0d501d233308d73ccb1bf191a68b (patch) | |
| tree | e83ad4ddd396607f9b0ea1a3a8262ce92aa3fcf9 /sys | |
| parent | c1afff113ceec2c78b96b2e52379cb5a9275d5fb (diff) | |
| parent | e3680954376d380b897066a542ba7cf0b7ba9124 (diff) | |
Notes
Diffstat (limited to 'sys')
226 files changed, 2642 insertions, 23474 deletions
diff --git a/sys/amd64/amd64/pmap.c b/sys/amd64/amd64/pmap.c index d7a35b5c9cfc0..a0a2eb0baa6bb 100644 --- a/sys/amd64/amd64/pmap.c +++ b/sys/amd64/amd64/pmap.c @@ -484,6 +484,9 @@ static struct pmap_invl_gen pmap_invl_gen_head = { .next = NULL, }; static u_long pmap_invl_gen = 1; +static int pmap_invl_waiters; +static struct callout pmap_invl_callout; +static bool pmap_invl_callout_inited; #define PMAP_ASSERT_NOT_IN_DI() \ KASSERT(pmap_not_in_di(), ("DI already started")) @@ -538,6 +541,34 @@ pmap_thread_init_invl_gen_l(struct thread *td) invl_gen->gen = 0; } +static void +pmap_delayed_invl_wait_block(u_long *m_gen, u_long *invl_gen) +{ + struct turnstile *ts; + + ts = turnstile_trywait(&invl_gen_ts); + if (*m_gen > atomic_load_long(invl_gen)) + turnstile_wait(ts, NULL, TS_SHARED_QUEUE); + else + turnstile_cancel(ts); +} + +static void +pmap_delayed_invl_finish_unblock(u_long new_gen) +{ + struct turnstile *ts; + + turnstile_chain_lock(&invl_gen_ts); + ts = turnstile_lookup(&invl_gen_ts); + if (new_gen != 0) + pmap_invl_gen = new_gen; + if (ts != NULL) { + turnstile_broadcast(ts, TS_SHARED_QUEUE); + turnstile_unpend(ts); + } + turnstile_chain_unlock(&invl_gen_ts); +} + /* * Start a new Delayed Invalidation (DI) block of code, executed by * the current thread. Within a DI block, the current thread may @@ -582,24 +613,15 @@ static void pmap_delayed_invl_finish_l(void) { struct pmap_invl_gen *invl_gen, *next; - struct turnstile *ts; invl_gen = &curthread->td_md.md_invl_gen; KASSERT(invl_gen->gen != 0, ("missed invl_start")); mtx_lock(&invl_gen_mtx); next = LIST_NEXT(invl_gen, link); - if (next == NULL) { - turnstile_chain_lock(&invl_gen_ts); - ts = turnstile_lookup(&invl_gen_ts); - pmap_invl_gen = invl_gen->gen; - if (ts != NULL) { - turnstile_broadcast(ts, TS_SHARED_QUEUE); - turnstile_unpend(ts); - } - turnstile_chain_unlock(&invl_gen_ts); - } else { + if (next == NULL) + pmap_delayed_invl_finish_unblock(invl_gen->gen); + else next->gen = invl_gen->gen; - } LIST_REMOVE(invl_gen, link); mtx_unlock(&invl_gen_mtx); invl_gen->gen = 0; @@ -856,6 +878,8 @@ again: goto again; } critical_exit(); + if (atomic_load_int(&pmap_invl_waiters) > 0) + pmap_delayed_invl_finish_unblock(0); if (invl_gen->saved_pri != 0) { thread_lock(td); sched_prio(td, invl_gen->saved_pri); @@ -888,6 +912,9 @@ DB_SHOW_COMMAND(di_queue, pmap_di_queue) static long invl_wait; SYSCTL_LONG(_vm_pmap, OID_AUTO, invl_wait, CTLFLAG_RD, &invl_wait, 0, "Number of times DI invalidation blocked pmap_remove_all/write"); +static long invl_wait_slow; +SYSCTL_LONG(_vm_pmap, OID_AUTO, invl_wait_slow, CTLFLAG_RD, &invl_wait_slow, 0, + "Number of slow invalidation waits for lockless DI"); #endif static u_long * @@ -897,6 +924,27 @@ pmap_delayed_invl_genp(vm_page_t m) return (&pv_invl_gen[pa_index(VM_PAGE_TO_PHYS(m)) % NPV_LIST_LOCKS]); } +static void +pmap_delayed_invl_callout_func(void *arg __unused) +{ + + if (atomic_load_int(&pmap_invl_waiters) == 0) + return; + pmap_delayed_invl_finish_unblock(0); +} + +static void +pmap_delayed_invl_callout_init(void *arg __unused) +{ + + if (pmap_di_locked()) + return; + callout_init(&pmap_invl_callout, 1); + pmap_invl_callout_inited = true; +} +SYSINIT(pmap_di_callout, SI_SUB_CPU + 1, SI_ORDER_ANY, + pmap_delayed_invl_callout_init, NULL); + /* * Ensure that all currently executing DI blocks, that need to flush * TLB for the given page m, actually flushed the TLB at the time the @@ -914,7 +962,6 @@ pmap_delayed_invl_genp(vm_page_t m) static void pmap_delayed_invl_wait_l(vm_page_t m) { - struct turnstile *ts; u_long *m_gen; #ifdef PV_STATS bool accounted = false; @@ -928,11 +975,7 @@ pmap_delayed_invl_wait_l(vm_page_t m) accounted = true; } #endif - ts = turnstile_trywait(&invl_gen_ts); - if (*m_gen > pmap_invl_gen) - turnstile_wait(ts, NULL, TS_SHARED_QUEUE); - else - turnstile_cancel(ts); + pmap_delayed_invl_wait_block(m_gen, &pmap_invl_gen); } } @@ -940,19 +983,53 @@ static void pmap_delayed_invl_wait_u(vm_page_t m) { u_long *m_gen; -#ifdef PV_STATS - bool accounted = false; -#endif + struct lock_delay_arg lda; + bool fast; + fast = true; m_gen = pmap_delayed_invl_genp(m); + lock_delay_arg_init(&lda, &di_delay); while (*m_gen > atomic_load_long(&pmap_invl_gen_head.gen)) { -#ifdef PV_STATS - if (!accounted) { - atomic_add_long(&invl_wait, 1); - accounted = true; + if (fast || !pmap_invl_callout_inited) { + PV_STAT(atomic_add_long(&invl_wait, 1)); + lock_delay(&lda); + fast = false; + } else { + /* + * The page's invalidation generation number + * is still below the current thread's number. + * Prepare to block so that we do not waste + * CPU cycles or worse, suffer livelock. + * + * Since it is impossible to block without + * racing with pmap_delayed_invl_finish_u(), + * prepare for the race by incrementing + * pmap_invl_waiters and arming a 1-tick + * callout which will unblock us if we lose + * the race. + */ + atomic_add_int(&pmap_invl_waiters, 1); + + /* + * Re-check the current thread's invalidation + * generation after incrementing + * pmap_invl_waiters, so that there is no race + * with pmap_delayed_invl_finish_u() setting + * the page generation and checking + * pmap_invl_waiters. The only race allowed + * is for a missed unblock, which is handled + * by the callout. + */ + if (*m_gen > + atomic_load_long(&pmap_invl_gen_head.gen)) { + callout_reset(&pmap_invl_callout, 1, + pmap_delayed_invl_callout_func, NULL); + PV_STAT(atomic_add_long(&invl_wait_slow, 1)); + pmap_delayed_invl_wait_block(m_gen, + &pmap_invl_gen_head.gen); + } + atomic_add_int(&pmap_invl_waiters, -1); } -#endif - kern_yield(PRI_USER); } } @@ -4921,6 +4998,7 @@ pmap_remove(pmap_t pmap, vm_offset_t sva, vm_offset_t eva) pmap_delayed_invl_start(); PMAP_LOCK(pmap); + pmap_pkru_on_remove(pmap, sva, eva); /* * special handling of removing one page. a very @@ -5014,7 +5092,6 @@ pmap_remove(pmap_t pmap, vm_offset_t sva, vm_offset_t eva) out: if (anyvalid) pmap_invalidate_all(pmap); - pmap_pkru_on_remove(pmap, sva, eva); PMAP_UNLOCK(pmap); pmap_delayed_invl_finish(); vm_page_free_pages_toq(&free, true); diff --git a/sys/amd64/conf/GENERIC b/sys/amd64/conf/GENERIC index 520f64734bb98..f04b60f3ca666 100644 --- a/sys/amd64/conf/GENERIC +++ b/sys/amd64/conf/GENERIC @@ -309,7 +309,6 @@ device wpi # Intel 3945ABG wireless NICs. # Pseudo devices. device crypto # core crypto support device loop # Network loopback -device random # Entropy device device padlock_rng # VIA Padlock RNG device rdrand_rng # Intel Bull Mountain RNG device ether # Ethernet support diff --git a/sys/amd64/conf/MINIMAL b/sys/amd64/conf/MINIMAL index 481a7ce96e44a..211e00e7de46a 100644 --- a/sys/amd64/conf/MINIMAL +++ b/sys/amd64/conf/MINIMAL @@ -10,7 +10,7 @@ # some features (ACL, GJOURNAL) that GENERIC includes. # o acpi as a module has been reported flakey and not well tested, so # is included in the kernel. -# o random is included due to uncertaty... +# o (non-loaded) random is included due to uncertainty... # o Many networking things are included # # For now, please run changes to these list past imp@freebsd.org @@ -131,7 +131,6 @@ device agp # support several AGP chipsets # Pseudo devices. device loop # Network loopback -device random # Entropy device device padlock_rng # VIA Padlock RNG device rdrand_rng # Intel Bull Mountain RNG device ether # Ethernet support diff --git a/sys/amd64/sgx/sgx.c b/sys/amd64/sgx/sgx.c index d47d4a3596a50..3d45b60de3ef5 100644 --- a/sys/amd64/sgx/sgx.c +++ b/sys/amd64/sgx/sgx.c @@ -358,7 +358,7 @@ sgx_page_remove(struct sgx_softc *sc, vm_page_t p) uint64_t offs; vm_page_lock(p); - vm_page_remove(p); + (void)vm_page_remove(p); vm_page_unlock(p); dprintf("%s: p->pidx %ld\n", __func__, p->pindex); diff --git a/sys/amd64/vmm/vmm_instruction_emul.c b/sys/amd64/vmm/vmm_instruction_emul.c index 230da1881ef0d..f3afa23d82812 100644 --- a/sys/amd64/vmm/vmm_instruction_emul.c +++ b/sys/amd64/vmm/vmm_instruction_emul.c @@ -78,6 +78,7 @@ enum { VIE_OP_TYPE_BITTEST, VIE_OP_TYPE_TWOB_GRP15, VIE_OP_TYPE_ADD, + VIE_OP_TYPE_TEST, VIE_OP_TYPE_LAST }; @@ -221,6 +222,12 @@ static const struct vie_op one_byte_opcodes[256] = { .op_byte = 0x8F, .op_type = VIE_OP_TYPE_POP, }, + [0xF7] = { + /* XXX Group 3 extended opcode - not just TEST */ + .op_byte = 0xF7, + .op_type = VIE_OP_TYPE_TEST, + .op_flags = VIE_OP_F_IMM, + }, [0xFF] = { /* XXX Group 5 extended opcode - not just PUSH */ .op_byte = 0xFF, @@ -450,6 +457,41 @@ getaddflags(int opsize, uint64_t x, uint64_t y) return (getaddflags64(x, y)); } +/* + * Return the status flags that would result from doing (x & y). + */ +#define GETANDFLAGS(sz) \ +static u_long \ +getandflags##sz(uint##sz##_t x, uint##sz##_t y) \ +{ \ + u_long rflags; \ + \ + __asm __volatile("and %2,%1; pushfq; popq %0" : \ + "=r" (rflags), "+r" (x) : "m" (y)); \ + return (rflags); \ +} struct __hack + +GETANDFLAGS(8); +GETANDFLAGS(16); +GETANDFLAGS(32); +GETANDFLAGS(64); + +static u_long +getandflags(int opsize, uint64_t x, uint64_t y) +{ + KASSERT(opsize == 1 || opsize == 2 || opsize == 4 || opsize == 8, + ("getandflags: invalid operand size %d", opsize)); + + if (opsize == 1) + return (getandflags8(x, y)); + else if (opsize == 2) + return (getandflags16(x, y)); + else if (opsize == 4) + return (getandflags32(x, y)); + else + return (getandflags64(x, y)); +} + static int emulate_mov(void *vm, int vcpuid, uint64_t gpa, struct vie *vie, mem_region_read_t memread, mem_region_write_t memwrite, void *arg) @@ -1219,6 +1261,55 @@ emulate_cmp(void *vm, int vcpuid, uint64_t gpa, struct vie *vie, } static int +emulate_test(void *vm, int vcpuid, uint64_t gpa, struct vie *vie, + mem_region_read_t memread, mem_region_write_t memwrite, void *arg) +{ + int error, size; + uint64_t op1, rflags, rflags2; + + size = vie->opsize; + error = EINVAL; + + switch (vie->op.op_byte) { + case 0xF7: + /* + * F7 /0 test r/m16, imm16 + * F7 /0 test r/m32, imm32 + * REX.W + F7 /0 test r/m64, imm32 sign-extended to 64 + * + * Test mem (ModRM:r/m) with immediate and set status + * flags according to the results. The comparison is + * performed by anding the immediate from the first + * operand and then setting the status flags. + */ + if ((vie->reg & 7) != 0) + return (EINVAL); + + error = memread(vm, vcpuid, gpa, &op1, size, arg); + if (error) + return (error); + + rflags2 = getandflags(size, op1, vie->immediate); + break; + default: + return (EINVAL); + } + error = vie_read_register(vm, vcpuid, VM_REG_GUEST_RFLAGS, &rflags); + if (error) + return (error); + + /* + * OF and CF are cleared; the SF, ZF and PF flags are set according + * to the result; AF is undefined. + */ + rflags &= ~RFLAGS_STATUS_BITS; + rflags |= rflags2 & (PSL_PF | PSL_Z | PSL_N); + + error = vie_update_register(vm, vcpuid, VM_REG_GUEST_RFLAGS, rflags, 8); + return (error); +} + +static int emulate_add(void *vm, int vcpuid, uint64_t gpa, struct vie *vie, mem_region_read_t memread, mem_region_write_t memwrite, void *arg) { @@ -1643,6 +1734,10 @@ vmm_emulate_instruction(void *vm, int vcpuid, uint64_t gpa, struct vie *vie, error = emulate_add(vm, vcpuid, gpa, vie, memread, memwrite, memarg); break; + case VIE_OP_TYPE_TEST: + error = emulate_test(vm, vcpuid, gpa, vie, + memread, memwrite, memarg); + break; default: error = EINVAL; break; diff --git a/sys/arm/allwinner/files.allwinner b/sys/arm/allwinner/files.allwinner index 73367b391c3ab..dd801c016d49a 100644 --- a/sys/arm/allwinner/files.allwinner +++ b/sys/arm/allwinner/files.allwinner @@ -28,7 +28,6 @@ dev/usb/controller/generic_ohci.c optional ohci dev/usb/controller/generic_usb_if.m optional ohci arm/allwinner/aw_sid.c optional aw_sid arm/allwinner/aw_thermal.c optional aw_thermal -dev/iicbus/sy8106a.c optional sy8106a arm/allwinner/aw_cir.c optional aw_cir evdev arm/allwinner/aw_reset.c standard diff --git a/sys/arm/conf/ALPINE b/sys/arm/conf/ALPINE index 6b35f120aefb7..76689b5805c9b 100644 --- a/sys/arm/conf/ALPINE +++ b/sys/arm/conf/ALPINE @@ -41,7 +41,6 @@ device al_udma # Universal DMA # Pseudo devices device loop -device random device pty device md device gpio diff --git a/sys/arm/conf/ARMADA38X b/sys/arm/conf/ARMADA38X index 29ea724172be5..b82c18d79c527 100644 --- a/sys/arm/conf/ARMADA38X +++ b/sys/arm/conf/ARMADA38X @@ -25,7 +25,6 @@ options SMP options VM_KMEM_SIZE_MAX=0x9CCD000 # Pseudo devices -device random device pty device loop device md diff --git a/sys/arm/conf/ARMADAXP b/sys/arm/conf/ARMADAXP index 5e891e51fba78..7f73d69ece7a3 100644 --- a/sys/arm/conf/ARMADAXP +++ b/sys/arm/conf/ARMADAXP @@ -46,7 +46,6 @@ options NO_FFS_SNAPSHOT options NO_SWAPPING # Pseudo devices -device random device pty device loop device md diff --git a/sys/arm/conf/DB-78XXX b/sys/arm/conf/DB-78XXX index aa474bcc43a13..44df77cf45f1b 100644 --- a/sys/arm/conf/DB-78XXX +++ b/sys/arm/conf/DB-78XXX @@ -20,7 +20,6 @@ options GEOM_PART_BSD # BSD partition scheme options GEOM_PART_MBR # MBR partition scheme options TMPFS # Efficient memory filesystem options FFS # Berkeley Fast Filesystem -options NANDFS # NAND Filesystem options NFSCL # Network Filesystem Client options NFSLOCKD # Network Lock Manager options NFS_ROOT # NFS usable as /, requires NFSCL @@ -45,7 +44,6 @@ device pci # Pseudo devices device loop device md -device random # Serial ports device uart @@ -75,9 +73,6 @@ device ds133x # SATA device mvs -# NAND -device nand - # GPIO device gpio diff --git a/sys/arm/conf/DB-88F5XXX b/sys/arm/conf/DB-88F5XXX index 0199e8663336c..a13a7002332d7 100644 --- a/sys/arm/conf/DB-88F5XXX +++ b/sys/arm/conf/DB-88F5XXX @@ -44,7 +44,6 @@ device pci # Pseudo devices device md device loop -device random # Serial ports device uart diff --git a/sys/arm/conf/DB-88F6XXX b/sys/arm/conf/DB-88F6XXX index fa2810c971225..66a385ddbe408 100644 --- a/sys/arm/conf/DB-88F6XXX +++ b/sys/arm/conf/DB-88F6XXX @@ -17,7 +17,6 @@ options INET # InterNETworking options INET6 # IPv6 communications protocols options TCP_HHOOK # hhook(9) framework for TCP options FFS # Berkeley Fast Filesystem -options NANDFS # NAND Filesystem options NFSCL # Network Filesystem Client options NFSLOCKD # Network Lock Manager options NFS_ROOT # NFS usable as /, requires NFSCL @@ -46,7 +45,6 @@ device pci # Pseudo devices device loop device md -device random # Serial ports device uart @@ -79,9 +77,6 @@ device twsi # SATA device mvs -# NAND -device nand - # GPIO device gpio diff --git a/sys/arm/conf/DOCKSTAR b/sys/arm/conf/DOCKSTAR index 5684d29ef87b4..6f26d42908019 100644 --- a/sys/arm/conf/DOCKSTAR +++ b/sys/arm/conf/DOCKSTAR @@ -68,7 +68,6 @@ device gif # IPv6 and IPv4 tunneling device loop # Network loopback device md # Memory/malloc disk device pty # BSD-style compatibility pseudo ttys -device random # Entropy device device tuntap # Packet tunnel. device ether # Required for all ethernet devices device vlan # 802.1Q VLAN support diff --git a/sys/arm/conf/DREAMPLUG-1001 b/sys/arm/conf/DREAMPLUG-1001 index 5d6928470e5de..18b2dee86face 100644 --- a/sys/arm/conf/DREAMPLUG-1001 +++ b/sys/arm/conf/DREAMPLUG-1001 @@ -71,7 +71,6 @@ device gif # IPv6 and IPv4 tunneling device loop # Network loopback device md # Memory/malloc disk device pty # BSD-style compatibility pseudo ttys -device random # Entropy device device tuntap # Packet tunnel. device ether # Required for all ethernet devices device vlan # 802.1Q VLAN support @@ -158,14 +157,6 @@ options ALTQ_PRIQ # Priority Queueing options ALTQ_NOPCC # Required if the TSC is unusable #options ALTQ_DEBUG -# To use this configuration with the (rare) model 1001N (nand flash), -# create a kernel config file that looks like this: -# -# include DREAMPLUG-1001 -# nomakeoptions FDT_DTS_FILE -# makeoptions FDT_DTS_FILE=dreamplug-1001N.dts -# device nand - # Flattened Device Tree options FDT # Configure using FDT/DTB data options FDT_DTB_STATIC diff --git a/sys/arm/conf/EFIKA_MX b/sys/arm/conf/EFIKA_MX index 248060b6cf049..be5f5f35570dc 100644 --- a/sys/arm/conf/EFIKA_MX +++ b/sys/arm/conf/EFIKA_MX @@ -57,7 +57,6 @@ device bpf # Berkeley packet filter # Pseudo devices. device loop # Network loopback -device random # Entropy device device ether # Ethernet support #device vlan # 802.1Q VLAN support #device tuntap # Packet tunnel. diff --git a/sys/arm/conf/GENERIC b/sys/arm/conf/GENERIC index d32baa63a6673..34be5898c7eb8 100644 --- a/sys/arm/conf/GENERIC +++ b/sys/arm/conf/GENERIC @@ -121,7 +121,6 @@ device pl011 device pty device snp device md # Memory "disks" -device random # Entropy device device firmware # firmware assist module device pl310 # PL310 L2 cache controller device psci @@ -175,6 +174,9 @@ device ti_spi # ADC support device ti_adc +# PWM +device pwm + # Watchdog support # If we don't enable the watchdog driver, the BealeBone could potentially # reboot automatically because the boot loader might have enabled the diff --git a/sys/arm/conf/IMX53 b/sys/arm/conf/IMX53 index 7b7d67bbca9c9..be18afda6094b 100644 --- a/sys/arm/conf/IMX53 +++ b/sys/arm/conf/IMX53 @@ -44,7 +44,6 @@ device bpf # Berkeley packet filter # Pseudo devices. device loop # Network loopback -device random # Entropy device device ether # Ethernet support #device vlan # 802.1Q VLAN support #device tuntap # Packet tunnel. diff --git a/sys/arm/conf/IMX6 b/sys/arm/conf/IMX6 index 3baf9f06f039f..4dbebdfccd1fa 100644 --- a/sys/arm/conf/IMX6 +++ b/sys/arm/conf/IMX6 @@ -49,7 +49,6 @@ device mpcore_timer # Pseudo devices. device loop # Network loopback -device random # Entropy device device vlan # 802.1Q VLAN support device tuntap # Packet tunnel. device md # Memory "disks" diff --git a/sys/arm/conf/NOTES b/sys/arm/conf/NOTES index 559146b580145..518cf4050ad92 100644 --- a/sys/arm/conf/NOTES +++ b/sys/arm/conf/NOTES @@ -1,44 +1,22 @@ # $FreeBSD$ -machine arm - -cpu CPU_ARM9E - -files "../mv/files.mv" -files "../mv/discovery/files.db78xxx" -files "../mv/kirkwood/files.kirkwood" -files "../mv/orion/files.db88f5xxx" -files "../mv/orion/files.ts7800" - -makeoptions CONF_CFLAGS+="-march=armv5te" -makeoptions LDFLAGS="-zmuldefs" -makeoptions KERNPHYSADDR=0x00000000 - options FDT -options SOC_MV_DISCOVERY -options SOC_MV_KIRKWOOD -options SOC_MV_ORION - -options ARM_MANY_BOARD -device nand - -# IIC -device twsi - -nooptions SMP -nooptions MAXCPU +# Undo options from sys/conf/NOTES that we do not want... nooptions COMPAT_FREEBSD4 nooptions COMPAT_FREEBSD5 nooptions COMPAT_FREEBSD6 nooptions COMPAT_FREEBSD7 nooptions COMPAT_FREEBSD9 -nooption PPC_PROBE_CHIPSET +nooptions PPC_PROBE_CHIPSET +nooptions MAXCPU # value is set in machine/param.h + +# Devices in sys/conf/NOTES for which no such hardware exists on arm, +# or the drivers don't compile... nodevice fdc nodevice sym -nodevice ukbd nodevice sc nodevice blank_saver @@ -58,28 +36,9 @@ nodevice cxgbe nodevice cxgbev nodevice snd_cmi -# -# Enable the kernel DTrace hooks which are required to load the DTrace -# kernel modules. -# -options KDTRACE_HOOKS - -# DTrace core -# NOTE: introduces CDDL-licensed components into the kernel -#device dtrace - -# DTrace modules -#device dtrace_profile -#device dtrace_sdt -#device dtrace_fbt -#device dtrace_systrace -#device dtrace_prototype -#device dtnfscl -#device dtmalloc - -# Alternatively include all the DTrace modules -#device dtraceall - -# These aren't known to work on arm and/or don't compile nodevice mpr nodevice mps + +# Add devices which are specific to various arm platforms... + +device twsi # i2c controller on Marvel and Allwinner diff --git a/sys/arm/conf/NOTES.armv5 b/sys/arm/conf/NOTES.armv5 new file mode 100644 index 0000000000000..1e8825980448d --- /dev/null +++ b/sys/arm/conf/NOTES.armv5 @@ -0,0 +1,33 @@ +# armv5-specific changes for doing a LINT build. +# +# The contents of sys/conf/NOTES, sys/arm/conf/NOTES, and this file are +# concatenated (in that order) to create the LINT-V5 kernel config file. +# +# $FreeBSD$ + +#NO_UNIVERSE + +machine arm arm +cpu CPU_ARM9E + +files "../mv/files.mv" +files "../mv/discovery/files.db78xxx" +files "../mv/kirkwood/files.kirkwood" +files "../mv/orion/files.db88f5xxx" +files "../mv/orion/files.ts7800" + +makeoptions CONF_CFLAGS+="-march=armv5te" +makeoptions LDFLAGS="-zmuldefs" +makeoptions KERNPHYSADDR=0x00000000 + +# Undo options from sys/conf/NOTES that we do not want... + +nooptions SMP # All armv5 are single-core + +# Add options for armv5 that are not in sys/conf/NOTES... + +options ARM_MANY_BOARD + +options SOC_MV_DISCOVERY +options SOC_MV_KIRKWOOD +options SOC_MV_ORION diff --git a/sys/arm/conf/NOTES.armv7 b/sys/arm/conf/NOTES.armv7 new file mode 100644 index 0000000000000..e8a19034b001e --- /dev/null +++ b/sys/arm/conf/NOTES.armv7 @@ -0,0 +1,64 @@ +# armv7-specific changes for doing a LINT build. +# +# The contents of sys/conf/NOTES, sys/arm/conf/NOTES, and this file are +# concatenated (in that order) to create the LINT-V7 kernel config file. +# +# $FreeBSD$ + + +#NO_UNIVERSE + +machine arm armv7 +cpu CPU_CORTEXA +cpu CPU_MV_PJ4B +makeoptions CONF_CFLAGS+="-march=armv7a" + +# Add options for armv7 that are not in sys/conf/NOTES... + +options ARM_L2_PIPT # Only L2 PIPT is supported +options FREEBSD_BOOT_LOADER # Process metadata passed from loader(8) +options INTRNG # Include INTRNG framework +options LINUX_BOOT_ABI # Process metadata passed from U-Boot +options PLATFORM # Include platform_if support +options SMP # Most v7 SoCs are multicore +options VFP # Enable floating point hardware support + +# NOTE: dtrace introduces CDDL-licensed components into the kernel +device dtrace # dtrace core +device dtraceall # include all dtrace modules +options KDTRACE_HOOKS + +# Add misc devices which are specific to various arm platforms... + +device generic_timer # ARM Generic Timer +device gic # Interrupt controller +device gpio # gpio interface and bus +device mpcore_timer # ARM MPCore Timer +device pl310 # PL310 L2 cache controller +device pmu # PMU support (for CCNT). + +# Add EXT_RESOURCES pseudo devices... + +options EXT_RESOURCES +device clk +device phy +device hwreset +device nvmem +device regulator +device syscon + +# Build SOC-specific modules... + +makeoptions MODULES_EXTRA+="allwinner" +makeoptions MODULES_EXTRA+="arm_ti" +makeoptions MODULES_EXTRA+="imx" + +# Build dtb files... + +makeoptions MODULES_EXTRA+="dtb/allwinner" +makeoptions MODULES_EXTRA+="dtb/am335x" +makeoptions MODULES_EXTRA+="dtb/imx6" +makeoptions MODULES_EXTRA+="dtb/nvidia" +makeoptions MODULES_EXTRA+="dtb/omap4" +makeoptions MODULES_EXTRA+="dtb/rpi" +makeoptions MODULES_EXTRA+="dtb/zynq" diff --git a/sys/arm/conf/RPI-B b/sys/arm/conf/RPI-B index e1f132105c207..e456d33742b80 100644 --- a/sys/arm/conf/RPI-B +++ b/sys/arm/conf/RPI-B @@ -65,7 +65,6 @@ device iicbus device bcm2835_bsc device md -device random # Entropy device # USB support device usb diff --git a/sys/arm/conf/RT1310 b/sys/arm/conf/RT1310 index 3ade997821be8..08fde3516ac16 100644 --- a/sys/arm/conf/RT1310 +++ b/sys/arm/conf/RT1310 @@ -51,7 +51,6 @@ options WITNESS_SKIPSPIN # Don't run witness on spinlocks for speed device loop device md device pty -device random # Serial ports device uart diff --git a/sys/arm/conf/SHEEVAPLUG b/sys/arm/conf/SHEEVAPLUG index ff60f82bcf60d..d7d161956ce43 100644 --- a/sys/arm/conf/SHEEVAPLUG +++ b/sys/arm/conf/SHEEVAPLUG @@ -19,7 +19,6 @@ options INET # InterNETworking options INET6 # IPv6 communications protocols options TCP_HHOOK # hhook(9) framework for TCP options FFS # Berkeley Fast Filesystem -options NANDFS # NAND Filesystem options NFSCL # Network Filesystem Client options NFSLOCKD # Network Lock Manager options NFS_ROOT # NFS usable as /, requires NFSCL @@ -46,7 +45,6 @@ options BOOTP_WIRED_TO=mge0 # Pseudo devices device loop -device random # Serial ports device uart @@ -73,9 +71,6 @@ device scbus device pass device da -# NAND -device nand - # GPIO device gpio diff --git a/sys/arm/conf/SOCFPGA b/sys/arm/conf/SOCFPGA index b740ef1b84c97..cd78e17e08a4a 100644 --- a/sys/arm/conf/SOCFPGA +++ b/sys/arm/conf/SOCFPGA @@ -58,7 +58,6 @@ device dwmmc # Pseudo devices device loop -device random device pty device md device gpio diff --git a/sys/arm/conf/TEGRA124 b/sys/arm/conf/TEGRA124 index a830519d909e6..c44939b673015 100644 --- a/sys/arm/conf/TEGRA124 +++ b/sys/arm/conf/TEGRA124 @@ -43,7 +43,6 @@ device regulator # Pseudo devices. device loop # Network loopback -device random # Entropy device device vlan # 802.1Q VLAN support #device tuntap # Packet tunnel. device md # Memory "disks" diff --git a/sys/arm/conf/TS7800 b/sys/arm/conf/TS7800 index 17b237af46ddd..15e9a77342d51 100644 --- a/sys/arm/conf/TS7800 +++ b/sys/arm/conf/TS7800 @@ -45,7 +45,6 @@ device pci # Pseudo devices device md device loop -device random # Serial ports device uart diff --git a/sys/arm/conf/VERSATILEPB b/sys/arm/conf/VERSATILEPB index 8c3e76cc2e874..3312f6d4f9e8a 100644 --- a/sys/arm/conf/VERSATILEPB +++ b/sys/arm/conf/VERSATILEPB @@ -66,7 +66,6 @@ options SC_DFLT_FONT # compile font in makeoptions SC_DFLT_FONT=cp437 device md -device random # Entropy device options PLATFORM diff --git a/sys/arm/conf/VYBRID b/sys/arm/conf/VYBRID index 4ff18320df1ad..b114c6e3e9238 100644 --- a/sys/arm/conf/VYBRID +++ b/sys/arm/conf/VYBRID @@ -26,7 +26,6 @@ makeoptions WERROR="-Werror" options SCHED_4BSD # 4BSD scheduler options PLATFORM # Platform based SoC -#options NANDFS # NAND Filesystem #options SMP # Enable multiple cores # NFS root from boopt/dhcp @@ -37,7 +36,6 @@ options PLATFORM # Platform based SoC #options BOOTP_WIRED_TO=ffec0 #options ROOTDEVNAME=\"nfs:10.5.0.1:/tftpboot/cosmic\" -#options ROOTDEVNAME=\"nandfs:/dev/gnand0s.root\" options ROOTDEVNAME=\"ufs:/dev/da0\" options MUTEX_NOINLINE @@ -59,7 +57,6 @@ device sdhci # generic sdhci # Pseudo devices device loop -device random device pty device md device gpio @@ -81,8 +78,6 @@ device pass #device atadisk #device mvs -device nand - # Serial ports device uart diff --git a/sys/arm/conf/ZEDBOARD b/sys/arm/conf/ZEDBOARD index 274d96642d6b1..187d636c2e490 100644 --- a/sys/arm/conf/ZEDBOARD +++ b/sys/arm/conf/ZEDBOARD @@ -48,7 +48,6 @@ device pl310 # PL310 L2 cache controller device mpcore_timer device loop -device random device ether device cgem # Zynq-7000 gig ethernet device device mii diff --git a/sys/arm/freescale/vybrid/vf_nfc.c b/sys/arm/freescale/vybrid/vf_nfc.c deleted file mode 100644 index cdefa2564864f..0000000000000 --- a/sys/arm/freescale/vybrid/vf_nfc.c +++ /dev/null @@ -1,528 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2013 Ruslan Bukin <br@bsdpad.com> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * Vybrid Family NAND Flash Controller (NFC) - * Chapter 31, Vybrid Reference Manual, Rev. 5, 07/2013 - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/proc.h> -#include <sys/bus.h> -#include <sys/conf.h> -#include <sys/kernel.h> -#include <sys/module.h> -#include <sys/malloc.h> -#include <sys/rman.h> -#include <sys/lock.h> -#include <sys/mutex.h> -#include <sys/time.h> - -#include <dev/ofw/ofw_bus.h> -#include <dev/ofw/ofw_bus_subr.h> -#include <dev/nand/nand.h> -#include <dev/nand/nandbus.h> - -#include <machine/bus.h> - -#include "nfc_if.h" - -#include <arm/freescale/vybrid/vf_common.h> - -enum addr_type { - ADDR_NONE, - ADDR_ID, - ADDR_ROW, - ADDR_ROWCOL -}; - -struct fsl_nfc_fcm { - uint32_t addr_bits; - enum addr_type addr_type; - uint32_t col_addr_bits; - uint32_t row_addr_bits; - u_int read_ptr; - u_int addr_ptr; - u_int command; - u_int code; -}; - -struct vf_nand_softc { - struct nand_softc nand_dev; - bus_space_handle_t bsh; - bus_space_tag_t bst; - struct resource *res[2]; - struct fsl_nfc_fcm fcm; -}; - -static struct resource_spec nfc_spec[] = { - { SYS_RES_MEMORY, 0, RF_ACTIVE }, - { SYS_RES_IRQ, 0, RF_ACTIVE }, - { -1, 0 } -}; - -static int vf_nand_attach(device_t); -static int vf_nand_probe(device_t); -static int vf_nand_send_command(device_t, uint8_t); -static int vf_nand_send_address(device_t, uint8_t); -static int vf_nand_start_command(device_t); -static uint8_t vf_nand_read_byte(device_t); -static void vf_nand_read_buf(device_t, void *, uint32_t); -static void vf_nand_write_buf(device_t, void *, uint32_t); -static int vf_nand_select_cs(device_t, uint8_t); -static int vf_nand_read_rnb(device_t); - -#define CMD_READ_PAGE 0x7EE0 -#define CMD_PROG_PAGE 0x7FC0 -#define CMD_PROG_PAGE_DMA 0xFFC8 -#define CMD_ERASE 0x4EC0 -#define CMD_READ_ID 0x4804 -#define CMD_READ_STATUS 0x4068 -#define CMD_RESET 0x4040 -#define CMD_RANDOM_IN 0x7140 -#define CMD_RANDOM_OUT 0x70E0 - -#define CMD_BYTE2_PROG_PAGE 0x10 -#define CMD_BYTE2_PAGE_READ 0x30 -#define CMD_BYTE2_ERASE 0xD0 - -#define NFC_CMD1 0x3F00 /* Flash command 1 */ -#define NFC_CMD2 0x3F04 /* Flash command 2 */ -#define NFC_CAR 0x3F08 /* Column address */ -#define NFC_RAR 0x3F0C /* Row address */ -#define NFC_RPT 0x3F10 /* Flash command repeat */ -#define NFC_RAI 0x3F14 /* Row address increment */ -#define NFC_SR1 0x3F18 /* Flash status 1 */ -#define NFC_SR2 0x3F1C /* Flash status 2 */ -#define NFC_DMA_CH1 0x3F20 /* DMA channel 1 address */ -#define NFC_DMACFG 0x3F24 /* DMA configuration */ -#define NFC_SWAP 0x3F28 /* Cach swap */ -#define NFC_SECSZ 0x3F2C /* Sector size */ -#define NFC_CFG 0x3F30 /* Flash configuration */ -#define NFC_DMA_CH2 0x3F34 /* DMA channel 2 address */ -#define NFC_ISR 0x3F38 /* Interrupt status */ - -#define ECCMODE_SHIFT 17 -#define AIAD_SHIFT 5 -#define AIBN_SHIFT 4 -#define PAGECOUNT_SHIFT 0 -#define BITWIDTH_SHIFT 7 -#define BITWIDTH8 0 -#define BITWIDTH16 1 -#define PAGECOUNT_MASK 0xf - -#define CMD2_BYTE1_SHIFT 24 -#define CMD2_CODE_SHIFT 8 -#define CMD2_BUFNO_SHIFT 1 -#define CMD2_START_SHIFT 0 - -static device_method_t vf_nand_methods[] = { - DEVMETHOD(device_probe, vf_nand_probe), - DEVMETHOD(device_attach, vf_nand_attach), - DEVMETHOD(nfc_start_command, vf_nand_start_command), - DEVMETHOD(nfc_send_command, vf_nand_send_command), - DEVMETHOD(nfc_send_address, vf_nand_send_address), - DEVMETHOD(nfc_read_byte, vf_nand_read_byte), - DEVMETHOD(nfc_read_buf, vf_nand_read_buf), - DEVMETHOD(nfc_write_buf, vf_nand_write_buf), - DEVMETHOD(nfc_select_cs, vf_nand_select_cs), - DEVMETHOD(nfc_read_rnb, vf_nand_read_rnb), - { 0, 0 }, -}; - -static driver_t vf_nand_driver = { - "nand", - vf_nand_methods, - sizeof(struct vf_nand_softc), -}; - -static devclass_t vf_nand_devclass; -DRIVER_MODULE(vf_nand, simplebus, vf_nand_driver, vf_nand_devclass, 0, 0); - -static int -vf_nand_probe(device_t dev) -{ - - if (!ofw_bus_status_okay(dev)) - return (ENXIO); - - if (!ofw_bus_is_compatible(dev, "fsl,mvf600-nand")) - return (ENXIO); - - device_set_desc(dev, "Vybrid Family NAND controller"); - return (BUS_PROBE_DEFAULT); -} - -static int -vf_nand_attach(device_t dev) -{ - struct vf_nand_softc *sc; - int err; - int reg; - - sc = device_get_softc(dev); - if (bus_alloc_resources(dev, nfc_spec, sc->res)) { - device_printf(dev, "could not allocate resources!\n"); - return (ENXIO); - } - - sc->bst = rman_get_bustag(sc->res[0]); - sc->bsh = rman_get_bushandle(sc->res[0]); - - /* Size in bytes of one elementary transfer unit */ - WRITE4(sc, NFC_SECSZ, 2048); - - /* Flash mode width */ - reg = READ4(sc, NFC_CFG); - reg |= (BITWIDTH16 << BITWIDTH_SHIFT); - - /* No correction, ECC bypass */ - reg &= ~(0x7 << ECCMODE_SHIFT); - - /* Disable Auto-incrementing of flash row address */ - reg &= ~(0x1 << AIAD_SHIFT); - - /* Disable Auto-incrementing of buffer numbers */ - reg &= ~(0x1 << AIBN_SHIFT); - - /* - * Number of virtual pages (in one physical flash page) - * to be programmed or read, etc. - */ - reg &= ~(PAGECOUNT_MASK); - reg |= (1 << PAGECOUNT_SHIFT); - WRITE4(sc, NFC_CFG, reg); - - nand_init(&sc->nand_dev, dev, NAND_ECC_NONE, 0, 0, NULL, NULL); - err = nandbus_create(dev); - return (err); -} - -static int -vf_nand_start_command(device_t dev) -{ - struct vf_nand_softc *sc; - struct fsl_nfc_fcm *fcm; - int reg; - - sc = device_get_softc(dev); - fcm = &sc->fcm; - - nand_debug(NDBG_DRV,"vf_nand: start command %x", fcm->command); - - /* CMD2 */ - reg = READ4(sc, NFC_CMD2); - reg &= ~(0xff << CMD2_BYTE1_SHIFT); - reg |= (fcm->command << CMD2_BYTE1_SHIFT); - WRITE4(sc, NFC_CMD2, reg); - - /* CMD1 */ - if ((fcm->command == NAND_CMD_READ) || - (fcm->command == NAND_CMD_PROG) || - (fcm->command == NAND_CMD_ERASE)) { - reg = READ4(sc, NFC_CMD1); - reg &= ~(0xff << 24); - - if (fcm->command == NAND_CMD_READ) - reg |= (CMD_BYTE2_PAGE_READ << 24); - else if (fcm->command == NAND_CMD_PROG) - reg |= (CMD_BYTE2_PROG_PAGE << 24); - else if (fcm->command == NAND_CMD_ERASE) - reg |= (CMD_BYTE2_ERASE << 24); - - WRITE4(sc, NFC_CMD1, reg); - } - - /* We work with 1st buffer */ - reg = READ4(sc, NFC_CMD2); - reg &= ~(0xf << CMD2_BUFNO_SHIFT); - reg |= (0 << CMD2_BUFNO_SHIFT); - WRITE4(sc, NFC_CMD2, reg); - - /* Cmd CODE */ - reg = READ4(sc, NFC_CMD2); - reg &= ~(0xffff << CMD2_CODE_SHIFT); - reg |= (fcm->code << CMD2_CODE_SHIFT); - WRITE4(sc, NFC_CMD2, reg); - - /* Col */ - if (fcm->addr_type == ADDR_ROWCOL) { - reg = READ4(sc, NFC_CAR); - reg &= ~(0xffff); - reg |= fcm->col_addr_bits; - nand_debug(NDBG_DRV,"setting CAR to 0x%08x\n", reg); - WRITE4(sc, NFC_CAR, reg); - } - - /* Row */ - reg = READ4(sc, NFC_RAR); - reg &= ~(0xffffff); - if (fcm->addr_type == ADDR_ID) - reg |= fcm->addr_bits; - else - reg |= fcm->row_addr_bits; - WRITE4(sc, NFC_RAR, reg); - - /* Start */ - reg = READ4(sc, NFC_CMD2); - reg |= (1 << CMD2_START_SHIFT); - WRITE4(sc, NFC_CMD2, reg); - - /* Wait command completion */ - while (READ4(sc, NFC_CMD2) & (1 << CMD2_START_SHIFT)) - ; - - return (0); -} - -static int -vf_nand_send_command(device_t dev, uint8_t command) -{ - struct vf_nand_softc *sc; - struct fsl_nfc_fcm *fcm; - - nand_debug(NDBG_DRV,"vf_nand: send command %x", command); - - sc = device_get_softc(dev); - fcm = &sc->fcm; - - if ((command == NAND_CMD_READ_END) || - (command == NAND_CMD_PROG_END) || - (command == NAND_CMD_ERASE_END)) { - return (0); - } - - fcm->command = command; - - fcm->code = 0; - fcm->read_ptr = 0; - fcm->addr_type = 0; - fcm->addr_bits = 0; - - fcm->addr_ptr = 0; - fcm->col_addr_bits = 0; - fcm->row_addr_bits = 0; - - switch (command) { - case NAND_CMD_READ: - fcm->code = CMD_READ_PAGE; - fcm->addr_type = ADDR_ROWCOL; - break; - case NAND_CMD_PROG: - fcm->code = CMD_PROG_PAGE; - fcm->addr_type = ADDR_ROWCOL; - break; - case NAND_CMD_PROG_END: - break; - case NAND_CMD_ERASE_END: - break; - case NAND_CMD_RESET: - fcm->code = CMD_RESET; - break; - case NAND_CMD_READ_ID: - fcm->code = CMD_READ_ID; - fcm->addr_type = ADDR_ID; - break; - case NAND_CMD_READ_PARAMETER: - fcm->code = CMD_READ_PAGE; - fcm->addr_type = ADDR_ID; - break; - case NAND_CMD_STATUS: - fcm->code = CMD_READ_STATUS; - break; - case NAND_CMD_ERASE: - fcm->code = CMD_ERASE; - fcm->addr_type = ADDR_ROW; - break; - default: - nand_debug(NDBG_DRV, "unknown command %d\n", command); - return (1); - } - - return (0); -} - -static int -vf_nand_send_address(device_t dev, uint8_t addr) -{ - struct vf_nand_softc *sc; - struct fsl_nfc_fcm *fcm; - - nand_debug(NDBG_DRV,"vf_nand: send address %x", addr); - sc = device_get_softc(dev); - fcm = &sc->fcm; - - nand_debug(NDBG_DRV, "setting addr #%d to 0x%02x\n", fcm->addr_ptr, addr); - - if (fcm->addr_type == ADDR_ID) { - fcm->addr_bits = addr; - } else if (fcm->addr_type == ADDR_ROWCOL) { - - if (fcm->addr_ptr < 2) - fcm->col_addr_bits |= (addr << (fcm->addr_ptr * 8)); - else - fcm->row_addr_bits |= (addr << ((fcm->addr_ptr - 2) * 8)); - - } else if (fcm->addr_type == ADDR_ROW) - fcm->row_addr_bits |= (addr << (fcm->addr_ptr * 8)); - - fcm->addr_ptr += 1; - - return (0); -} - -static uint8_t -vf_nand_read_byte(device_t dev) -{ - struct vf_nand_softc *sc; - struct fsl_nfc_fcm *fcm; - uint8_t data; - int sr1, sr2; - int b; - - sc = device_get_softc(dev); - fcm = &sc->fcm; - - sr1 = READ4(sc, NFC_SR1); - sr2 = READ4(sc, NFC_SR2); - - data = 0; - if (fcm->addr_type == ADDR_ID) { - b = 32 - ((fcm->read_ptr + 1) * 8); - data = (sr1 >> b) & 0xff; - fcm->read_ptr++; - } else if (fcm->command == NAND_CMD_STATUS) { - data = sr2 & 0xff; - } - - nand_debug(NDBG_DRV,"vf_nand: read %x", data); - return (data); -} - -static void -vf_nand_read_buf(device_t dev, void* buf, uint32_t len) -{ - struct vf_nand_softc *sc; - struct fsl_nfc_fcm *fcm; - uint16_t *tmp; - uint8_t *b; - int i; - - b = (uint8_t*)buf; - sc = device_get_softc(dev); - fcm = &sc->fcm; - - nand_debug(NDBG_DRV, "vf_nand: read_buf len %d", len); - - if (fcm->command == NAND_CMD_READ_PARAMETER) { - tmp = malloc(len, M_DEVBUF, M_NOWAIT); - bus_read_region_2(sc->res[0], 0x0, tmp, len); - - for (i = 0; i < len; i += 2) { - b[i] = tmp[i+1]; - b[i+1] = tmp[i]; - } - - free(tmp, M_DEVBUF); - -#ifdef NAND_DEBUG - for (i = 0; i < len; i++) { - if (!(i % 16)) - printf("%s", i == 0 ? "vf_nand:\n" : "\n"); - printf(" %x", b[i]); - if (i == len - 1) - printf("\n"); - } -#endif - - } else { - - for (i = 0; i < len; i++) { - b[i] = READ1(sc, i); - -#ifdef NAND_DEBUG - if (!(i % 16)) - printf("%s", i == 0 ? "vf_nand:\n" : "\n"); - printf(" %x", b[i]); - if (i == len - 1) - printf("\n"); -#endif - } - - } -} - -static void -vf_nand_write_buf(device_t dev, void* buf, uint32_t len) -{ - struct vf_nand_softc *sc; - struct fsl_nfc_fcm *fcm; - uint8_t *b; - int i; - - b = (uint8_t*)buf; - sc = device_get_softc(dev); - fcm = &sc->fcm; - - nand_debug(NDBG_DRV,"vf_nand: write_buf len %d", len); - - for (i = 0; i < len; i++) { - WRITE1(sc, i, b[i]); - -#ifdef NAND_DEBUG - if (!(i % 16)) - printf("%s", i == 0 ? "vf_nand:\n" : "\n"); - printf(" %x", b[i]); - if (i == len - 1) - printf("\n"); -#endif - - } -} - -static int -vf_nand_select_cs(device_t dev, uint8_t cs) -{ - - if (cs > 0) - return (ENODEV); - - return (0); -} - -static int -vf_nand_read_rnb(device_t dev) -{ - - /* no-op */ - return (0); /* ready */ -} diff --git a/sys/arm/mv/files.arm7 b/sys/arm/mv/files.arm7 index d27357480cae5..a6138042bc805 100644 --- a/sys/arm/mv/files.arm7 +++ b/sys/arm/mv/files.arm7 @@ -29,7 +29,6 @@ dev/iicbus/twsi/mv_twsi.c optional twsi dev/mge/if_mge.c optional mge dev/neta/if_mvneta_fdt.c optional neta fdt dev/neta/if_mvneta.c optional neta mdio mii -dev/nand/nfc_mv.c optional nand dev/mvs/mvs_soc.c optional mvs dev/uart/uart_dev_ns8250.c optional uart dev/uart/uart_dev_snps.c optional uart diff --git a/sys/arm/mv/files.mv b/sys/arm/mv/files.mv index ee027f0594415..1dc45105450c8 100644 --- a/sys/arm/mv/files.mv +++ b/sys/arm/mv/files.mv @@ -26,7 +26,6 @@ dev/iicbus/twsi/mv_twsi.c optional twsi dev/mge/if_mge.c optional mge dev/neta/if_mvneta_fdt.c optional neta fdt dev/neta/if_mvneta.c optional neta mdio mii -dev/nand/nfc_mv.c optional nand dev/mvs/mvs_soc.c optional mvs dev/uart/uart_dev_ns8250.c optional uart dev/uart/uart_dev_snps.c optional uart diff --git a/sys/arm/ti/am335x/am335x_ehrpwm.c b/sys/arm/ti/am335x/am335x_ehrpwm.c index 53cb3bb782493..cbb947038ba99 100644 --- a/sys/arm/ti/am335x/am335x_ehrpwm.c +++ b/sys/arm/ti/am335x/am335x_ehrpwm.c @@ -45,21 +45,43 @@ __FBSDID("$FreeBSD$"); #include <dev/ofw/ofw_bus.h> #include <dev/ofw/ofw_bus_subr.h> +#include "pwmbus_if.h" + #include "am335x_pwm.h" +/******************************************************************************* + * Enhanced resolution PWM driver. Many of the advanced featues of the hardware + * are not supported by this driver. What is implemented here is simple + * variable-duty-cycle PWM output. + * + * Note that this driver was historically configured using a set of sysctl + * variables/procs, and later gained support for the PWM(9) API. The sysctl + * code is still present to support existing apps, but that interface is + * considered deprecated. + * + * An important caveat is that the original sysctl interface and the new PWM API + * cannot both be used at once. If both interfaces are used to change + * configuration, it's quite likely you won't get the expected results. Also, + * reading the sysctl values after configuring via PWM will not return the right + * results. + ******************************************************************************/ + /* In ticks */ #define DEFAULT_PWM_PERIOD 1000 #define PWM_CLOCK 100000000UL +#define NS_PER_SEC 1000000000 + #define PWM_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) #define PWM_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) +#define PWM_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_mtx, MA_OWNED) #define PWM_LOCK_INIT(_sc) mtx_init(&(_sc)->sc_mtx, \ device_get_nameunit(_sc->sc_dev), "am335x_ehrpwm softc", MTX_DEF) #define PWM_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_mtx) -#define EPWM_READ2(_sc, reg) bus_read_2((_sc)->sc_mem_res, reg); +#define EPWM_READ2(_sc, reg) bus_read_2((_sc)->sc_mem_res, reg) #define EPWM_WRITE2(_sc, reg, value) \ - bus_write_2((_sc)->sc_mem_res, reg, value); + bus_write_2((_sc)->sc_mem_res, reg, value) #define EPWM_TBCTL 0x00 #define TBCTL_FREERUN (2 << 14) @@ -119,6 +141,11 @@ __FBSDID("$FreeBSD$"); #define AQCTL_ZRO_TOGGLE (3 << 0) #define EPWM_AQSFRC 0x1a #define EPWM_AQCSFRC 0x1c +#define AQCSFRC_OFF 0 +#define AQCSFRC_LO 1 +#define AQCSFRC_HI 2 +#define AQCSFRC_MASK 3 +#define AQCSFRC(chan, hilo) ((hilo) << (2 * chan)) /* Trip-Zone module */ #define EPWM_TZCTL 0x28 @@ -135,12 +162,21 @@ static device_detach_t am335x_ehrpwm_detach; static int am335x_ehrpwm_clkdiv[8] = { 1, 2, 4, 8, 16, 32, 64, 128 }; +struct ehrpwm_channel { + u_int duty; /* on duration, in ns */ + bool enabled; /* channel enabled? */ + bool inverted; /* signal inverted? */ +}; +#define NUM_CHANNELS 2 + struct am335x_ehrpwm_softc { device_t sc_dev; + device_t sc_busdev; struct mtx sc_mtx; struct resource *sc_mem_res; int sc_mem_rid; - /* sysctl for configuration */ + + /* Things used for configuration via sysctl [deprecated]. */ int sc_pwm_clkdiv; int sc_pwm_freq; struct sysctl_oid *sc_clkdiv_oid; @@ -151,23 +187,130 @@ struct am335x_ehrpwm_softc { uint32_t sc_pwm_period; uint32_t sc_pwm_dutyA; uint32_t sc_pwm_dutyB; -}; -static device_method_t am335x_ehrpwm_methods[] = { - DEVMETHOD(device_probe, am335x_ehrpwm_probe), - DEVMETHOD(device_attach, am335x_ehrpwm_attach), - DEVMETHOD(device_detach, am335x_ehrpwm_detach), - - DEVMETHOD_END + /* Things used for configuration via pwm(9) api. */ + u_int sc_clkfreq; /* frequency in Hz */ + u_int sc_clktick; /* duration in ns */ + u_int sc_period; /* duration in ns */ + struct ehrpwm_channel sc_channels[NUM_CHANNELS]; }; -static driver_t am335x_ehrpwm_driver = { - "am335x_ehrpwm", - am335x_ehrpwm_methods, - sizeof(struct am335x_ehrpwm_softc), +static struct ofw_compat_data compat_data[] = { + {"ti,am33xx-ehrpwm", true}, + {NULL, false}, }; +SIMPLEBUS_PNP_INFO(compat_data); -static devclass_t am335x_ehrpwm_devclass; +static void +am335x_ehrpwm_cfg_duty(struct am335x_ehrpwm_softc *sc, u_int chan, u_int duty) +{ + u_int tbcmp; + + if (duty == 0) + tbcmp = 0; + else + tbcmp = max(1, duty / sc->sc_clktick); + + sc->sc_channels[chan].duty = tbcmp * sc->sc_clktick; + + PWM_LOCK_ASSERT(sc); + EPWM_WRITE2(sc, (chan == 0) ? EPWM_CMPA : EPWM_CMPB, tbcmp); +} + +static void +am335x_ehrpwm_cfg_enable(struct am335x_ehrpwm_softc *sc, u_int chan, bool enable) +{ + uint16_t regval; + + sc->sc_channels[chan].enabled = enable; + + /* + * Turn off any existing software-force of the channel, then force + * it in the right direction (high or low) if it's not being enabled. + */ + PWM_LOCK_ASSERT(sc); + regval = EPWM_READ2(sc, EPWM_AQCSFRC); + regval &= ~AQCSFRC(chan, AQCSFRC_MASK); + if (!sc->sc_channels[chan].enabled) { + if (sc->sc_channels[chan].inverted) + regval |= AQCSFRC(chan, AQCSFRC_HI); + else + regval |= AQCSFRC(chan, AQCSFRC_LO); + } + EPWM_WRITE2(sc, EPWM_AQCSFRC, regval); +} + +static bool +am335x_ehrpwm_cfg_period(struct am335x_ehrpwm_softc *sc, u_int period) +{ + uint16_t regval; + u_int clkdiv, hspclkdiv, pwmclk, pwmtick, tbprd; + + /* Can't do a period shorter than 2 clock ticks. */ + if (period < 2 * NS_PER_SEC / PWM_CLOCK) { + sc->sc_clkfreq = 0; + sc->sc_clktick = 0; + sc->sc_period = 0; + return (false); + } + + /* + * Figure out how much we have to divide down the base 100MHz clock so + * that we can express the requested period as a 16-bit tick count. + */ + tbprd = 0; + for (clkdiv = 0; clkdiv < 8; ++clkdiv) { + const u_int cd = 1 << clkdiv; + for (hspclkdiv = 0; hspclkdiv < 8; ++hspclkdiv) { + const u_int cdhs = max(1, hspclkdiv * 2); + pwmclk = PWM_CLOCK / (cd * cdhs); + pwmtick = NS_PER_SEC / pwmclk; + if (period / pwmtick < 65536) { + tbprd = period / pwmtick; + break; + } + } + if (tbprd != 0) + break; + } + + /* Handle requested period too long for available clock divisors. */ + if (tbprd == 0) + return (false); + + /* + * If anything has changed from the current settings, reprogram the + * clock divisors and period register. + */ + if (sc->sc_clkfreq != pwmclk || sc->sc_clktick != pwmtick || + sc->sc_period != tbprd * pwmtick) { + + sc->sc_clkfreq = pwmclk; + sc->sc_clktick = pwmtick; + sc->sc_period = tbprd * pwmtick; + + PWM_LOCK_ASSERT(sc); + regval = EPWM_READ2(sc, EPWM_TBCTL); + regval &= ~(TBCTL_CLKDIV_MASK | TBCTL_HSPCLKDIV_MASK); + regval |= TBCTL_CLKDIV(clkdiv) | TBCTL_HSPCLKDIV(hspclkdiv); + EPWM_WRITE2(sc, EPWM_TBCTL, regval); + EPWM_WRITE2(sc, EPWM_TBPRD, tbprd - 1); +#if 0 + device_printf(sc->sc_dev, "clkdiv %u hspclkdiv %u tbprd %u " + "clkfreq %u Hz clktick %u ns period got %u requested %u\n", + clkdiv, hspclkdiv, tbprd - 1, + sc->sc_clkfreq, sc->sc_clktick, sc->sc_period, period); +#endif + /* + * If the period changed, that invalidates the current CMP + * registers (duty values), just zero them out. + */ + am335x_ehrpwm_cfg_duty(sc, 0, 0); + am335x_ehrpwm_cfg_duty(sc, 1, 0); + } + + return (true); +} static void am335x_ehrpwm_freq(struct am335x_ehrpwm_softc *sc) @@ -331,13 +474,89 @@ am335x_ehrpwm_sysctl_period(SYSCTL_HANDLER_ARGS) } static int +am335x_ehrpwm_channel_count(device_t dev, u_int *nchannel) +{ + + *nchannel = NUM_CHANNELS; + + return (0); +} + +static int +am335x_ehrpwm_channel_config(device_t dev, u_int channel, u_int period, u_int duty) +{ + struct am335x_ehrpwm_softc *sc; + bool status; + + if (channel >= NUM_CHANNELS) + return (EINVAL); + + sc = device_get_softc(dev); + + PWM_LOCK(sc); + status = am335x_ehrpwm_cfg_period(sc, period); + if (status) + am335x_ehrpwm_cfg_duty(sc, channel, duty); + PWM_UNLOCK(sc); + + return (status ? 0 : EINVAL); +} + +static int +am335x_ehrpwm_channel_get_config(device_t dev, u_int channel, + u_int *period, u_int *duty) +{ + struct am335x_ehrpwm_softc *sc; + + if (channel >= NUM_CHANNELS) + return (EINVAL); + + sc = device_get_softc(dev); + *period = sc->sc_period; + *duty = sc->sc_channels[channel].duty; + return (0); +} + +static int +am335x_ehrpwm_channel_enable(device_t dev, u_int channel, bool enable) +{ + struct am335x_ehrpwm_softc *sc; + + if (channel >= NUM_CHANNELS) + return (EINVAL); + + sc = device_get_softc(dev); + + PWM_LOCK(sc); + am335x_ehrpwm_cfg_enable(sc, channel, enable); + PWM_UNLOCK(sc); + + return (0); +} + +static int +am335x_ehrpwm_channel_is_enabled(device_t dev, u_int channel, bool *enabled) +{ + struct am335x_ehrpwm_softc *sc; + + if (channel >= NUM_CHANNELS) + return (EINVAL); + + sc = device_get_softc(dev); + + *enabled = sc->sc_channels[channel].enabled; + + return (0); +} + +static int am335x_ehrpwm_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); - if (!ofw_bus_is_compatible(dev, "ti,am33xx-ehrpwm")) + if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) return (ENXIO); device_set_desc(dev, "AM335x EHRPWM"); @@ -365,7 +584,7 @@ am335x_ehrpwm_attach(device_t dev) goto fail; } - /* Init backlight interface */ + /* Init sysctl interface */ ctx = device_get_sysctl_ctx(sc->sc_dev); tree = device_get_sysctl_tree(sc->sc_dev); @@ -414,7 +633,13 @@ am335x_ehrpwm_attach(device_t dev) EPWM_WRITE2(sc, EPWM_TZCTL, 0xf); reg = EPWM_READ2(sc, EPWM_TZFLG); - return (0); + if ((sc->sc_busdev = device_add_child(dev, "pwmbus", -1)) == NULL) { + device_printf(dev, "Cannot add child pwmbus\n"); + // This driver can still do things even without the bus child. + } + + bus_generic_probe(dev); + return (bus_generic_attach(dev)); fail: PWM_LOCK_DESTROY(sc); if (sc->sc_mem_res) @@ -428,13 +653,22 @@ static int am335x_ehrpwm_detach(device_t dev) { struct am335x_ehrpwm_softc *sc; + int error; sc = device_get_softc(dev); + if ((error = bus_generic_detach(sc->sc_dev)) != 0) + return (error); + PWM_LOCK(sc); + + if (sc->sc_busdev != NULL) + device_delete_child(dev, sc->sc_busdev); + if (sc->sc_mem_res) bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_mem_rid, sc->sc_mem_res); + PWM_UNLOCK(sc); PWM_LOCK_DESTROY(sc); @@ -442,6 +676,44 @@ am335x_ehrpwm_detach(device_t dev) return (0); } +static phandle_t +am335x_ehrpwm_get_node(device_t bus, device_t dev) +{ + + /* + * Share our controller node with our pwmbus child; it instantiates + * devices by walking the children contained within our node. + */ + return ofw_bus_get_node(bus); +} + +static device_method_t am335x_ehrpwm_methods[] = { + DEVMETHOD(device_probe, am335x_ehrpwm_probe), + DEVMETHOD(device_attach, am335x_ehrpwm_attach), + DEVMETHOD(device_detach, am335x_ehrpwm_detach), + + /* ofw_bus_if */ + DEVMETHOD(ofw_bus_get_node, am335x_ehrpwm_get_node), + + /* pwm interface */ + DEVMETHOD(pwmbus_channel_count, am335x_ehrpwm_channel_count), + DEVMETHOD(pwmbus_channel_config, am335x_ehrpwm_channel_config), + DEVMETHOD(pwmbus_channel_get_config, am335x_ehrpwm_channel_get_config), + DEVMETHOD(pwmbus_channel_enable, am335x_ehrpwm_channel_enable), + DEVMETHOD(pwmbus_channel_is_enabled, am335x_ehrpwm_channel_is_enabled), + + DEVMETHOD_END +}; + +static driver_t am335x_ehrpwm_driver = { + "pwm", + am335x_ehrpwm_methods, + sizeof(struct am335x_ehrpwm_softc), +}; + +static devclass_t am335x_ehrpwm_devclass; + DRIVER_MODULE(am335x_ehrpwm, am335x_pwmss, am335x_ehrpwm_driver, am335x_ehrpwm_devclass, 0, 0); MODULE_VERSION(am335x_ehrpwm, 1); MODULE_DEPEND(am335x_ehrpwm, am335x_pwmss, 1, 1, 1); +MODULE_DEPEND(am335x_ehrpwm, pwmbus, 1, 1, 1); diff --git a/sys/arm64/acpica/acpi_iort.c b/sys/arm64/acpica/acpi_iort.c index edd87474c9c93..10a501254bc60 100644 --- a/sys/arm64/acpica/acpi_iort.c +++ b/sys/arm64/acpica/acpi_iort.c @@ -370,19 +370,44 @@ srat_resolve_its_pxm(ACPI_SUBTABLE_HEADER *entry, void *arg) ACPI_SRAT_GIC_ITS_AFFINITY *gicits; struct iort_node *its_node; struct iort_its_entry *its_entry; - int i, matches; + int *map_counts; + int i, matches, dom; if (entry->Type != ACPI_SRAT_TYPE_GIC_ITS_AFFINITY) return; matches = 0; + map_counts = arg; gicits = (ACPI_SRAT_GIC_ITS_AFFINITY *)entry; + dom = acpi_map_pxm_to_vm_domainid(gicits->ProximityDomain); + + /* + * Catch firmware and config errors. map_counts keeps a + * count of ProximityDomain values mapping to a domain ID + */ +#if MAXMEMDOM > 1 + if (dom == -1) + printf("Firmware Error: Proximity Domain %d could not be" + " mapped for GIC ITS ID %d!\n", + gicits->ProximityDomain, gicits->ItsId); +#endif + /* use dom + 1 as index to handle the case where dom == -1 */ + i = ++map_counts[dom + 1]; + if (i > 1) { +#ifdef NUMA + if (dom != -1) + printf("ERROR: Multiple Proximity Domains map to the" + " same NUMA domain %d!\n", dom); +#else + printf("WARNING: multiple Proximity Domains in SRAT but NUMA" + " NOT enabled!\n"); +#endif + } TAILQ_FOREACH(its_node, &its_groups, next) { its_entry = its_node->entries.its; for (i = 0; i < its_node->nentries; i++, its_entry++) { if (its_entry->its_id == gicits->ItsId) { - its_entry->pxm = acpi_map_pxm_to_vm_domainid( - gicits->ProximityDomain); + its_entry->pxm = dom; matches++; } } @@ -401,6 +426,7 @@ iort_post_process_its(void) ACPI_TABLE_MADT *madt; ACPI_TABLE_SRAT *srat; vm_paddr_t madt_pa, srat_pa; + int map_counts[MAXMEMDOM + 1] = { 0 }; /* Check ITS block in MADT */ madt_pa = acpi_find_table(ACPI_SIG_MADT); @@ -417,7 +443,7 @@ iort_post_process_its(void) srat = acpi_map_table(srat_pa, ACPI_SIG_SRAT); KASSERT(srat != NULL, ("can't map SRAT!")); acpi_walk_subtables(srat + 1, (char *)srat + srat->Header.Length, - srat_resolve_its_pxm, NULL); + srat_resolve_its_pxm, map_counts); acpi_unmap_table(srat); } return (0); diff --git a/sys/arm64/arm64/freebsd32_machdep.c b/sys/arm64/arm64/freebsd32_machdep.c index aeac4605f2f5c..2e25fe062b194 100644 --- a/sys/arm64/arm64/freebsd32_machdep.c +++ b/sys/arm64/arm64/freebsd32_machdep.c @@ -122,6 +122,7 @@ static void get_fpcontext32(struct thread *td, mcontext32_vfp_t *mcp) { struct pcb *curpcb; + int i; critical_enter(); curpcb = curthread->td_pcb; @@ -137,8 +138,8 @@ get_fpcontext32(struct thread *td, mcontext32_vfp_t *mcp) ("Called get_fpcontext while the kernel is using the VFP")); KASSERT((curpcb->pcb_fpflags & ~PCB_FP_USERMASK) == 0, ("Non-userspace FPU flags set in get_fpcontext")); - memcpy(mcp->mcv_reg, curpcb->pcb_fpustate.vfp_regs, - sizeof(mcp->mcv_reg)); + for (i = 0; i < 32; i++) + mcp->mcv_reg[i] = (uint64_t)curpcb->pcb_fpustate.vfp_regs[i]; mcp->mcv_fpscr = VFP_FPSCR_FROM_SRCR(curpcb->pcb_fpustate.vfp_fpcr, curpcb->pcb_fpustate.vfp_fpsr); } @@ -149,13 +150,14 @@ static void set_fpcontext32(struct thread *td, mcontext32_vfp_t *mcp) { struct pcb *pcb; + int i; critical_enter(); pcb = td->td_pcb; if (td == curthread) vfp_discard(td); - memcpy(pcb->pcb_fpustate.vfp_regs, mcp->mcv_reg, - sizeof(pcb->pcb_fpustate.vfp_regs)); + for (i = 0; i < 32; i++) + pcb->pcb_fpustate.vfp_regs[i] = mcp->mcv_reg[i]; pcb->pcb_fpustate.vfp_fpsr = VFP_FPSR_FROM_FPSCR(mcp->mcv_fpscr); pcb->pcb_fpustate.vfp_fpcr = VFP_FPSR_FROM_FPSCR(mcp->mcv_fpscr); critical_exit(); diff --git a/sys/arm64/arm64/gic_v3.c b/sys/arm64/arm64/gic_v3.c index af08ee992bb6a..a83ef576e30ed 100644 --- a/sys/arm64/arm64/gic_v3.c +++ b/sys/arm64/arm64/gic_v3.c @@ -390,10 +390,6 @@ gic_v3_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) case GICV3_IVAR_NIRQS: *result = (NIRQ - sc->gic_nirqs) / sc->gic_nchildren; return (0); - case GICV3_IVAR_REDIST_VADDR: - *result = (uintptr_t)rman_get_virtual( - &sc->gic_redists.pcpu[PCPU_GET(cpuid)]->res); - return (0); case GICV3_IVAR_REDIST: *result = (uintptr_t)sc->gic_redists.pcpu[PCPU_GET(cpuid)]; return (0); diff --git a/sys/arm64/arm64/gic_v3_var.h b/sys/arm64/arm64/gic_v3_var.h index 27dec4d721903..1257484a5e578 100644 --- a/sys/arm64/arm64/gic_v3_var.h +++ b/sys/arm64/arm64/gic_v3_var.h @@ -94,11 +94,10 @@ MALLOC_DECLARE(M_GIC_V3); /* ivars */ #define GICV3_IVAR_NIRQS 1000 -#define GICV3_IVAR_REDIST_VADDR 1001 +/* 1001 was GICV3_IVAR_REDIST_VADDR */ #define GICV3_IVAR_REDIST 1002 __BUS_ACCESSOR(gicv3, nirqs, GICV3, NIRQS, u_int); -__BUS_ACCESSOR(gicv3, redist_vaddr, GICV3, REDIST_VADDR, void *); __BUS_ACCESSOR(gicv3, redist, GICV3, REDIST, void *); /* Device methods */ diff --git a/sys/arm64/arm64/gicv3_its.c b/sys/arm64/arm64/gicv3_its.c index f347a36c12cc9..2701a7e8df0a1 100644 --- a/sys/arm64/arm64/gicv3_its.c +++ b/sys/arm64/arm64/gicv3_its.c @@ -747,9 +747,7 @@ gicv3_its_attach(device_t dev) if (domain < MAXMEMDOM) CPU_COPY(&cpuset_domain[domain], &sc->sc_cpus); } else { - /* XXX : cannot handle more than one ITS per cpu */ - if (device_get_unit(dev) == 0) - CPU_COPY(&all_cpus, &sc->sc_cpus); + CPU_COPY(&all_cpus, &sc->sc_cpus); } /* Allocate the command circular buffer */ diff --git a/sys/arm64/arm64/machdep.c b/sys/arm64/arm64/machdep.c index b8ecfc08e676f..4356add12aa0a 100644 --- a/sys/arm64/arm64/machdep.c +++ b/sys/arm64/arm64/machdep.c @@ -194,6 +194,16 @@ fill_regs(struct thread *td, struct reg *regs) memcpy(regs->x, frame->tf_x, sizeof(regs->x)); +#ifdef COMPAT_FREEBSD32 + /* + * We may be called here for a 32bits process, if we're using a + * 64bits debugger. If so, put PC and SPSR where it expects it. + */ + if (SV_PROC_FLAG(td->td_proc, SV_ILP32)) { + regs->x[15] = frame->tf_elr; + regs->x[16] = frame->tf_spsr; + } +#endif return (0); } @@ -211,6 +221,17 @@ set_regs(struct thread *td, struct reg *regs) memcpy(frame->tf_x, regs->x, sizeof(frame->tf_x)); +#ifdef COMPAT_FREEBSD32 + if (SV_PROC_FLAG(td->td_proc, SV_ILP32)) { + /* + * We may be called for a 32bits process if we're using + * a 64bits debugger. If so, get PC and SPSR from where + * it put it. + */ + frame->tf_elr = regs->x[15]; + frame->tf_spsr = regs->x[16] & PSR_FLAGS; + } +#endif return (0); } @@ -283,8 +304,9 @@ fill_regs32(struct thread *td, struct reg32 *regs) tf = td->td_frame; for (i = 0; i < 13; i++) regs->r[i] = tf->tf_x[i]; - regs->r_sp = tf->tf_sp; - regs->r_lr = tf->tf_lr; + /* For arm32, SP is r13 and LR is r14 */ + regs->r_sp = tf->tf_x[13]; + regs->r_lr = tf->tf_x[14]; regs->r_pc = tf->tf_elr; regs->r_cpsr = tf->tf_spsr; @@ -300,8 +322,9 @@ set_regs32(struct thread *td, struct reg32 *regs) tf = td->td_frame; for (i = 0; i < 13; i++) tf->tf_x[i] = regs->r[i]; - tf->tf_sp = regs->r_sp; - tf->tf_lr = regs->r_lr; + /* For arm 32, SP is r13 an LR is r14 */ + tf->tf_x[13] = regs->r_sp; + tf->tf_x[14] = regs->r_lr; tf->tf_elr = regs->r_pc; tf->tf_spsr = regs->r_cpsr; diff --git a/sys/arm64/arm64/pmap.c b/sys/arm64/arm64/pmap.c index df34873025dd2..bf74bb55f0388 100644 --- a/sys/arm64/arm64/pmap.c +++ b/sys/arm64/arm64/pmap.c @@ -2510,6 +2510,82 @@ pmap_remove_l3(pmap_t pmap, pt_entry_t *l3, vm_offset_t va, } /* + * Remove the specified range of addresses from the L3 page table that is + * identified by the given L2 entry. + */ +static void +pmap_remove_l3_range(pmap_t pmap, pd_entry_t l2e, vm_offset_t sva, + vm_offset_t eva, struct spglist *free, struct rwlock **lockp) +{ + struct md_page *pvh; + struct rwlock *new_lock; + pt_entry_t *l3, old_l3; + vm_offset_t va; + vm_page_t m; + + PMAP_LOCK_ASSERT(pmap, MA_OWNED); + KASSERT(rounddown2(sva, L2_SIZE) + L2_SIZE == roundup2(eva, L2_SIZE), + ("pmap_remove_l3_range: range crosses an L3 page table boundary")); + va = eva; + for (l3 = pmap_l2_to_l3(&l2e, sva); sva != eva; l3++, sva += L3_SIZE) { + if (!pmap_l3_valid(pmap_load(l3))) { + if (va != eva) { + pmap_invalidate_range(pmap, va, sva); + va = eva; + } + continue; + } + old_l3 = pmap_load_clear(l3); + if ((old_l3 & ATTR_SW_WIRED) != 0) + pmap->pm_stats.wired_count--; + pmap_resident_count_dec(pmap, 1); + if ((old_l3 & ATTR_SW_MANAGED) != 0) { + m = PHYS_TO_VM_PAGE(old_l3 & ~ATTR_MASK); + if (pmap_page_dirty(old_l3)) + vm_page_dirty(m); + if ((old_l3 & ATTR_AF) != 0) + vm_page_aflag_set(m, PGA_REFERENCED); + new_lock = PHYS_TO_PV_LIST_LOCK(VM_PAGE_TO_PHYS(m)); + if (new_lock != *lockp) { + if (*lockp != NULL) { + /* + * Pending TLB invalidations must be + * performed before the PV list lock is + * released. Otherwise, a concurrent + * pmap_remove_all() on a physical page + * could return while a stale TLB entry + * still provides access to that page. + */ + if (va != eva) { + pmap_invalidate_range(pmap, va, + sva); + va = eva; + } + rw_wunlock(*lockp); + } + *lockp = new_lock; + rw_wlock(*lockp); + } + pmap_pvh_free(&m->md, pmap, sva); + if (TAILQ_EMPTY(&m->md.pv_list) && + (m->flags & PG_FICTITIOUS) == 0) { + pvh = pa_to_pvh(VM_PAGE_TO_PHYS(m)); + if (TAILQ_EMPTY(&pvh->pv_list)) + vm_page_aflag_clear(m, PGA_WRITEABLE); + } + } + if (va == eva) + va = sva; + if (pmap_unuse_pt(pmap, sva, l2e, free)) { + sva += L3_SIZE; + break; + } + } + if (va != eva) + pmap_invalidate_range(pmap, va, sva); +} + +/* * Remove the given range of addresses from the specified map. * * It is assumed that the start and end are properly @@ -2519,9 +2595,9 @@ void pmap_remove(pmap_t pmap, vm_offset_t sva, vm_offset_t eva) { struct rwlock *lock; - vm_offset_t va, va_next; + vm_offset_t va_next; pd_entry_t *l0, *l1, *l2; - pt_entry_t l3_paddr, *l3; + pt_entry_t l3_paddr; struct spglist free; /* @@ -2594,28 +2670,8 @@ pmap_remove(pmap_t pmap, vm_offset_t sva, vm_offset_t eva) if (va_next > eva) va_next = eva; - va = va_next; - for (l3 = pmap_l2_to_l3(l2, sva); sva != va_next; l3++, - sva += L3_SIZE) { - if (l3 == NULL) - panic("l3 == NULL"); - if (pmap_load(l3) == 0) { - if (va != va_next) { - pmap_invalidate_range(pmap, va, sva); - va = va_next; - } - continue; - } - if (va == va_next) - va = sva; - if (pmap_remove_l3(pmap, l3, sva, l3_paddr, &free, - &lock)) { - sva += L3_SIZE; - break; - } - } - if (va != va_next) - pmap_invalidate_range(pmap, va, sva); + pmap_remove_l3_range(pmap, l3_paddr, sva, va_next, &free, + &lock); } if (lock != NULL) rw_wunlock(lock); @@ -3352,7 +3408,7 @@ validate: __func__, pmap, va, new_l3); } } else { - /* New mappig */ + /* New mapping */ pmap_load_store(l3, new_l3); dsb(ishst); } @@ -3419,8 +3475,7 @@ pmap_enter_l2(pmap_t pmap, vm_offset_t va, pd_entry_t new_l2, u_int flags, vm_page_t m, struct rwlock **lockp) { struct spglist free; - pd_entry_t *l2, *l3, old_l2; - vm_offset_t sva; + pd_entry_t *l2, old_l2; vm_page_t l2pg, mt; PMAP_LOCK_ASSERT(pmap, MA_OWNED); @@ -3449,13 +3504,8 @@ pmap_enter_l2(pmap_t pmap, vm_offset_t va, pd_entry_t new_l2, u_int flags, (void)pmap_remove_l2(pmap, l2, va, pmap_load(pmap_l1(pmap, va)), &free, lockp); else - for (sva = va; sva < va + L2_SIZE; sva += PAGE_SIZE) { - l3 = pmap_l2_to_l3(l2, sva); - if (pmap_l3_valid(pmap_load(l3)) && - pmap_remove_l3(pmap, l3, sva, old_l2, &free, - lockp) != 0) - break; - } + pmap_remove_l3_range(pmap, old_l2, va, va + L2_SIZE, + &free, lockp); vm_page_free_pages_toq(&free, true); if (va >= VM_MAXUSER_ADDRESS) { /* @@ -3656,6 +3706,9 @@ pmap_enter_quick_locked(pmap_t pmap, vm_offset_t va, vm_page_t m, l3 = pmap_l2_to_l3(pde, va); } + /* + * Abort if a mapping already exists. + */ if (pmap_load(l3) != 0) { if (mpte != NULL) { mpte->wire_count--; @@ -3705,7 +3758,15 @@ pmap_enter_quick_locked(pmap_t pmap, vm_offset_t va, vm_page_t m, cpu_icache_sync_range(PHYS_TO_DMAP(pa), PAGE_SIZE); pmap_load_store(l3, l3_val); + + /* + * XXX In principle, because this L3 entry was invalid, we should not + * need to perform a TLB invalidation here. However, in practice, + * when simply performing a "dsb ishst" here, processes are being + * terminated due to bus errors and segmentation violations. + */ pmap_invalidate_page(pmap, va); + return (mpte); } diff --git a/sys/arm64/conf/GENERIC b/sys/arm64/conf/GENERIC index 8e3f04fe1db1b..2adee9db99d4a 100644 --- a/sys/arm64/conf/GENERIC +++ b/sys/arm64/conf/GENERIC @@ -293,7 +293,6 @@ device aw_cir # Pseudo devices. device crypto # core crypto support device loop # Network loopback -device random # Entropy device device ether # Ethernet support device vlan # 802.1Q VLAN support device tuntap # Packet tunnel. diff --git a/sys/cam/ata/ata_all.c b/sys/cam/ata/ata_all.c index 76d65ae5e4052..9a4cdbed071ba 100644 --- a/sys/cam/ata/ata_all.c +++ b/sys/cam/ata/ata_all.c @@ -1238,3 +1238,28 @@ ata_zac_mgmt_in(struct ccb_ataio *ataio, uint32_t retries, ataio->aux = auxiliary; } } + +void +ata_param_fixup(struct ata_params *ident_buf) +{ + int16_t *ptr; + + for (ptr = (int16_t *)ident_buf; + ptr < (int16_t *)ident_buf + sizeof(struct ata_params)/2; ptr++) { + *ptr = le16toh(*ptr); + } + if (strncmp(ident_buf->model, "FX", 2) && + strncmp(ident_buf->model, "NEC", 3) && + strncmp(ident_buf->model, "Pioneer", 7) && + strncmp(ident_buf->model, "SHARP", 5)) { + ata_bswap(ident_buf->model, sizeof(ident_buf->model)); + ata_bswap(ident_buf->revision, sizeof(ident_buf->revision)); + ata_bswap(ident_buf->serial, sizeof(ident_buf->serial)); + } + ata_btrim(ident_buf->model, sizeof(ident_buf->model)); + ata_bpack(ident_buf->model, ident_buf->model, sizeof(ident_buf->model)); + ata_btrim(ident_buf->revision, sizeof(ident_buf->revision)); + ata_bpack(ident_buf->revision, ident_buf->revision, sizeof(ident_buf->revision)); + ata_btrim(ident_buf->serial, sizeof(ident_buf->serial)); + ata_bpack(ident_buf->serial, ident_buf->serial, sizeof(ident_buf->serial)); +} diff --git a/sys/cam/ata/ata_all.h b/sys/cam/ata/ata_all.h index 087d6820f9808..ca635253511c4 100644 --- a/sys/cam/ata/ata_all.h +++ b/sys/cam/ata/ata_all.h @@ -135,6 +135,7 @@ void ata_read_log(struct ccb_ataio *ataio, uint32_t retries, uint16_t block_count, uint32_t protocol, uint8_t *data_ptr, uint32_t dxfer_len, uint32_t timeout); +void ata_param_fixup(struct ata_params *ident_buf); void ata_bswap(int8_t *buf, int len); void ata_btrim(int8_t *buf, int len); void ata_bpack(int8_t *src, int8_t *dst, int len); diff --git a/sys/cam/ata/ata_xpt.c b/sys/cam/ata/ata_xpt.c index 94dc435b099b7..017db8854b088 100644 --- a/sys/cam/ata/ata_xpt.c +++ b/sys/cam/ata/ata_xpt.c @@ -893,14 +893,13 @@ noerror: case PROBE_IDENTIFY: { struct ccb_pathinq cpi; - int16_t *ptr; int veto = 0; + /* + * Convert to host byte order, and fix the strings. + */ ident_buf = &softc->ident_data; - for (ptr = (int16_t *)ident_buf; - ptr < (int16_t *)ident_buf + sizeof(struct ata_params)/2; ptr++) { - *ptr = le16toh(*ptr); - } + ata_param_fixup(ident_buf); /* * Allow others to veto this ATA disk attachment. This @@ -912,20 +911,6 @@ noerror: goto device_fail; } - if (strncmp(ident_buf->model, "FX", 2) && - strncmp(ident_buf->model, "NEC", 3) && - strncmp(ident_buf->model, "Pioneer", 7) && - strncmp(ident_buf->model, "SHARP", 5)) { - ata_bswap(ident_buf->model, sizeof(ident_buf->model)); - ata_bswap(ident_buf->revision, sizeof(ident_buf->revision)); - ata_bswap(ident_buf->serial, sizeof(ident_buf->serial)); - } - ata_btrim(ident_buf->model, sizeof(ident_buf->model)); - ata_bpack(ident_buf->model, ident_buf->model, sizeof(ident_buf->model)); - ata_btrim(ident_buf->revision, sizeof(ident_buf->revision)); - ata_bpack(ident_buf->revision, ident_buf->revision, sizeof(ident_buf->revision)); - ata_btrim(ident_buf->serial, sizeof(ident_buf->serial)); - ata_bpack(ident_buf->serial, ident_buf->serial, sizeof(ident_buf->serial)); /* Device may need spin-up before IDENTIFY become valid. */ if ((ident_buf->specconf == 0x37c8 || ident_buf->specconf == 0x738c) && diff --git a/sys/cam/cam_xpt.c b/sys/cam/cam_xpt.c index 2217ecc6d2ff2..4736c7212a2c8 100644 --- a/sys/cam/cam_xpt.c +++ b/sys/cam/cam_xpt.c @@ -1244,6 +1244,7 @@ xpt_getattr(char *buf, size_t len, const char *attr, struct cam_path *path) { int ret = -1, l, o; struct ccb_dev_advinfo cdai; + struct scsi_vpd_device_id *did; struct scsi_vpd_id_descriptor *idd; xpt_path_assert(path, MA_OWNED); @@ -1253,6 +1254,7 @@ xpt_getattr(char *buf, size_t len, const char *attr, struct cam_path *path) cdai.ccb_h.func_code = XPT_DEV_ADVINFO; cdai.flags = CDAI_FLAG_NONE; cdai.bufsiz = len; + cdai.buf = buf; if (!strcmp(attr, "GEOM::ident")) cdai.buftype = CDAI_TYPE_SERIAL_NUM; @@ -1262,44 +1264,49 @@ xpt_getattr(char *buf, size_t len, const char *attr, struct cam_path *path) strcmp(attr, "GEOM::lunname") == 0) { cdai.buftype = CDAI_TYPE_SCSI_DEVID; cdai.bufsiz = CAM_SCSI_DEVID_MAXLEN; + cdai.buf = malloc(cdai.bufsiz, M_CAMXPT, M_NOWAIT); + if (cdai.buf == NULL) { + ret = ENOMEM; + goto out; + } } else goto out; - cdai.buf = malloc(cdai.bufsiz, M_CAMXPT, M_NOWAIT|M_ZERO); - if (cdai.buf == NULL) { - ret = ENOMEM; - goto out; - } xpt_action((union ccb *)&cdai); /* can only be synchronous */ if ((cdai.ccb_h.status & CAM_DEV_QFRZN) != 0) cam_release_devq(cdai.ccb_h.path, 0, 0, 0, FALSE); if (cdai.provsiz == 0) goto out; - if (cdai.buftype == CDAI_TYPE_SCSI_DEVID) { + switch(cdai.buftype) { + case CDAI_TYPE_SCSI_DEVID: + did = (struct scsi_vpd_device_id *)cdai.buf; if (strcmp(attr, "GEOM::lunid") == 0) { - idd = scsi_get_devid((struct scsi_vpd_device_id *)cdai.buf, - cdai.provsiz, scsi_devid_is_lun_naa); + idd = scsi_get_devid(did, cdai.provsiz, + scsi_devid_is_lun_naa); if (idd == NULL) - idd = scsi_get_devid((struct scsi_vpd_device_id *)cdai.buf, - cdai.provsiz, scsi_devid_is_lun_eui64); + idd = scsi_get_devid(did, cdai.provsiz, + scsi_devid_is_lun_eui64); if (idd == NULL) - idd = scsi_get_devid((struct scsi_vpd_device_id *)cdai.buf, - cdai.provsiz, scsi_devid_is_lun_uuid); + idd = scsi_get_devid(did, cdai.provsiz, + scsi_devid_is_lun_uuid); if (idd == NULL) - idd = scsi_get_devid((struct scsi_vpd_device_id *)cdai.buf, - cdai.provsiz, scsi_devid_is_lun_md5); + idd = scsi_get_devid(did, cdai.provsiz, + scsi_devid_is_lun_md5); } else idd = NULL; + if (idd == NULL) - idd = scsi_get_devid((struct scsi_vpd_device_id *)cdai.buf, - cdai.provsiz, scsi_devid_is_lun_t10); + idd = scsi_get_devid(did, cdai.provsiz, + scsi_devid_is_lun_t10); if (idd == NULL) - idd = scsi_get_devid((struct scsi_vpd_device_id *)cdai.buf, - cdai.provsiz, scsi_devid_is_lun_name); + idd = scsi_get_devid(did, cdai.provsiz, + scsi_devid_is_lun_name); if (idd == NULL) - goto out; + break; + ret = 0; - if ((idd->proto_codeset & SVPD_ID_CODESET_MASK) == SVPD_ID_CODESET_ASCII) { + if ((idd->proto_codeset & SVPD_ID_CODESET_MASK) == + SVPD_ID_CODESET_ASCII) { if (idd->length < len) { for (l = 0; l < idd->length; l++) buf[l] = idd->identifier[l] ? @@ -1307,40 +1314,50 @@ xpt_getattr(char *buf, size_t len, const char *attr, struct cam_path *path) buf[l] = 0; } else ret = EFAULT; - } else if ((idd->proto_codeset & SVPD_ID_CODESET_MASK) == SVPD_ID_CODESET_UTF8) { + break; + } + if ((idd->proto_codeset & SVPD_ID_CODESET_MASK) == + SVPD_ID_CODESET_UTF8) { l = strnlen(idd->identifier, idd->length); if (l < len) { bcopy(idd->identifier, buf, l); buf[l] = 0; } else ret = EFAULT; - } else if ((idd->id_type & SVPD_ID_TYPE_MASK) == SVPD_ID_TYPE_UUID - && idd->identifier[0] == 0x10) { - if ((idd->length - 2) * 2 + 4 < len) { - for (l = 2, o = 0; l < idd->length; l++) { - if (l == 6 || l == 8 || l == 10 || l == 12) - o += sprintf(buf + o, "-"); - o += sprintf(buf + o, "%02x", - idd->identifier[l]); - } - } else - ret = EFAULT; - } else { - if (idd->length * 2 < len) { - for (l = 0; l < idd->length; l++) - sprintf(buf + l * 2, "%02x", - idd->identifier[l]); - } else + break; + } + if ((idd->id_type & SVPD_ID_TYPE_MASK) == + SVPD_ID_TYPE_UUID && idd->identifier[0] == 0x10) { + if ((idd->length - 2) * 2 + 4 >= len) { ret = EFAULT; + break; + } + for (l = 2, o = 0; l < idd->length; l++) { + if (l == 6 || l == 8 || l == 10 || l == 12) + o += sprintf(buf + o, "-"); + o += sprintf(buf + o, "%02x", + idd->identifier[l]); + } + break; } - } else { - ret = 0; - if (strlcpy(buf, cdai.buf, len) >= len) + if (idd->length * 2 < len) { + for (l = 0; l < idd->length; l++) + sprintf(buf + l * 2, "%02x", + idd->identifier[l]); + } else + ret = EFAULT; + break; + default: + if (cdai.provsiz < len) { + cdai.buf[cdai.provsiz] = 0; + ret = 0; + } else ret = EFAULT; + break; } out: - if (cdai.buf != NULL) + if ((char *)cdai.buf != buf) free(cdai.buf, M_CAMXPT); return ret; } diff --git a/sys/cam/ctl/ctl_error.c b/sys/cam/ctl/ctl_error.c index 17e9e3a51d800..dae4deb9e5e7b 100644 --- a/sys/cam/ctl/ctl_error.c +++ b/sys/cam/ctl/ctl_error.c @@ -81,6 +81,12 @@ ctl_set_sense_data_va(struct scsi_sense_data *sense_data, u_int *sense_len, */ if (sense_format == SSD_TYPE_NONE) { /* + * SPC-3 and up require some UAs to be returned as fixed. + */ + if (asc == 0x29 || (asc == 0x2A && ascq == 0x01)) + sense_format = SSD_TYPE_FIXED; + else + /* * If the format isn't specified, we only return descriptor * sense if the LUN exists and descriptor sense is turned * on for that LUN. diff --git a/sys/cam/scsi/scsi_all.c b/sys/cam/scsi/scsi_all.c index 1d92c4d8e915f..5ab37e3f64164 100644 --- a/sys/cam/scsi/scsi_all.c +++ b/sys/cam/scsi/scsi_all.c @@ -5574,6 +5574,7 @@ scsi_devid_is_naa_ieee_reg(uint8_t *bufp) { struct scsi_vpd_id_descriptor *descr; struct scsi_vpd_id_naa_basic *naa; + int n; descr = (struct scsi_vpd_id_descriptor *)bufp; naa = (struct scsi_vpd_id_naa_basic *)descr->identifier; @@ -5581,7 +5582,8 @@ scsi_devid_is_naa_ieee_reg(uint8_t *bufp) return 0; if (descr->length < sizeof(struct scsi_vpd_id_naa_ieee_reg)) return 0; - if ((naa->naa >> SVPD_ID_NAA_NAA_SHIFT) != SVPD_ID_NAA_IEEE_REG) + n = naa->naa >> SVPD_ID_NAA_NAA_SHIFT; + if (n != SVPD_ID_NAA_LOCAL_REG && n != SVPD_ID_NAA_IEEE_REG) return 0; return 1; } diff --git a/sys/cam/scsi/scsi_da.c b/sys/cam/scsi/scsi_da.c index a89c40e19a7b6..f2f60d35b2e28 100644 --- a/sys/cam/scsi/scsi_da.c +++ b/sys/cam/scsi/scsi_da.c @@ -64,6 +64,9 @@ __FBSDID("$FreeBSD$"); #include <cam/cam_ccb.h> #include <cam/cam_periph.h> #include <cam/cam_xpt_periph.h> +#ifdef _KERNEL +#include <cam/cam_xpt_internal.h> +#endif /* _KERNEL */ #include <cam/cam_sim.h> #include <cam/cam_iosched.h> @@ -3613,15 +3616,7 @@ out: break; } - ata_params = (struct ata_params*) - malloc(sizeof(*ata_params), M_SCSIDA,M_NOWAIT|M_ZERO); - - if (ata_params == NULL) { - xpt_print(periph->path, "Couldn't malloc ata_params " - "data\n"); - /* da_free_periph??? */ - break; - } + ata_params = &periph->path->device->ident_data; scsi_ata_identify(&start_ccb->csio, /*retries*/da_retry_count, @@ -5192,7 +5187,7 @@ dadone_probeata(struct cam_periph *periph, union ccb *done_ccb) struct da_softc *softc; u_int32_t priority; int continue_probe; - int error, i; + int error; int16_t *ptr; CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("dadone_probeata\n")); @@ -5210,8 +5205,7 @@ dadone_probeata(struct cam_periph *periph, union ccb *done_ccb) if ((csio->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { uint16_t old_rate; - for (i = 0; i < sizeof(*ata_params) / 2; i++) - ptr[i] = le16toh(ptr[i]); + ata_param_fixup(ata_params); if (ata_params->support_dsm & ATA_SUPPORT_DSM_TRIM && (softc->quirks & DA_Q_NO_UNMAP) == 0) { dadeleteflag(softc, DA_DELETE_ATA_TRIM, 1); @@ -5295,7 +5289,6 @@ dadone_probeata(struct cam_periph *periph, union ccb *done_ccb) } } - free(ata_params, M_SCSIDA); if ((softc->zone_mode == DA_ZONE_HOST_AWARE) || (softc->zone_mode == DA_ZONE_HOST_MANAGED)) { /* diff --git a/sys/cam/scsi/scsi_enc.c b/sys/cam/scsi/scsi_enc.c index 363f27db5f784..ec190232fff97 100644 --- a/sys/cam/scsi/scsi_enc.c +++ b/sys/cam/scsi/scsi_enc.c @@ -81,6 +81,17 @@ static enctyp enc_type(struct ccb_getdev *); SYSCTL_NODE(_kern_cam, OID_AUTO, enc, CTLFLAG_RD, 0, "CAM Enclosure Services driver"); +#if defined(DEBUG) || defined(ENC_DEBUG) +int enc_verbose = 1; +#else +int enc_verbose = 0; +#endif +SYSCTL_INT(_kern_cam_enc, OID_AUTO, verbose, CTLFLAG_RWTUN, + &enc_verbose, 0, "Enable verbose logging"); + +const char *elm_type_names[] = ELM_TYPE_NAMES; +CTASSERT(nitems(elm_type_names) - 1 == ELMTYP_LAST); + static struct periph_driver encdriver = { enc_init, "ses", TAILQ_HEAD_INITIALIZER(encdriver.units), /* generation */ 0 @@ -232,11 +243,17 @@ enc_async(void *callback_arg, uint32_t code, struct cam_path *path, void *arg) struct enc_softc *softc; softc = (struct enc_softc *)periph->softc; - if (xpt_path_path_id(periph->path) != path_id - || softc == NULL - || (softc->enc_flags & ENC_FLAG_INITIALIZED) - == 0 - || softc->enc_vec.device_found == NULL) + + /* Check this SEP is ready. */ + if (softc == NULL || (softc->enc_flags & + ENC_FLAG_INITIALIZED) == 0 || + softc->enc_vec.device_found == NULL) + continue; + + /* Check this SEP may manage this device. */ + if (xpt_path_path_id(periph->path) != path_id && + (softc->enc_type != ENC_SEMB_SES || + cgd->protocol != PROTO_ATA)) continue; softc->enc_vec.device_found(softc); @@ -432,7 +449,7 @@ enc_ioctl(struct cdev *dev, u_long cmd, caddr_t arg_addr, int flag, encioc_element_t kelm; kelm.elm_idx = i; kelm.elm_subenc_id = cache->elm_map[i].subenclosure; - kelm.elm_type = cache->elm_map[i].enctype; + kelm.elm_type = cache->elm_map[i].elm_type; error = copyout(&kelm, &uelm[i], sizeof(kelm)); if (error) break; @@ -684,14 +701,8 @@ enc_type(struct ccb_getdev *cgd) buflen = min(sizeof(cgd->inq_data), SID_ADDITIONAL_LENGTH(&cgd->inq_data)); - if ((iqd[0] & 0x1f) == T_ENCLOSURE) { - if ((iqd[2] & 0x7) > 2) { - return (ENC_SES); - } else { - return (ENC_SES_SCSI2); - } - return (ENC_NONE); - } + if ((iqd[0] & 0x1f) == T_ENCLOSURE) + return (ENC_SES); #ifdef SES_ENABLE_PASSTHROUGH if ((iqd[6] & 0x40) && (iqd[2] & 0x7) >= 2) { @@ -928,7 +939,6 @@ enc_ctor(struct cam_periph *periph, void *arg) switch (enc->enc_type) { case ENC_SES: - case ENC_SES_SCSI2: case ENC_SES_PASSTHROUGH: case ENC_SEMB_SES: err = ses_softc_init(enc); @@ -1017,17 +1027,14 @@ enc_ctor(struct cam_periph *periph, void *arg) case ENC_NONE: tname = "No ENC device"; break; - case ENC_SES_SCSI2: - tname = "SCSI-2 ENC Device"; - break; case ENC_SES: - tname = "SCSI-3 ENC Device"; + tname = "SES Device"; break; case ENC_SES_PASSTHROUGH: - tname = "ENC Passthrough Device"; + tname = "SES Passthrough Device"; break; case ENC_SAFT: - tname = "SAF-TE Compliant Device"; + tname = "SAF-TE Device"; break; case ENC_SEMB_SES: tname = "SEMB SES Device"; diff --git a/sys/cam/scsi/scsi_enc.h b/sys/cam/scsi/scsi_enc.h index fc7e3bd3f1c6b..f9abe099e337c 100644 --- a/sys/cam/scsi/scsi_enc.h +++ b/sys/cam/scsi/scsi_enc.h @@ -120,10 +120,42 @@ typedef enum { ELMTYP_SCSI_INI = 0x15, ELMTYP_SUBENC = 0x16, ELMTYP_ARRAY_DEV = 0x17, - ELMTYP_SAS_EXP = 0x18, /* SAS expander */ - ELMTYP_SAS_CONN = 0x19 /* SAS connector */ + ELMTYP_SAS_EXP = 0x18, /* SAS Expander */ + ELMTYP_SAS_CONN = 0x19, /* SAS Connector */ + ELMTYP_LAST = ELMTYP_SAS_CONN } elm_type_t; +#define ELM_TYPE_NAMES { \ + "Unspecified", \ + "Device Slot", \ + "Power Supply", \ + "Cooling", \ + "Temperature Sensors", \ + "Door", \ + "Audible alarm", \ + "Enclosure Services Controller Electronics", \ + "SCC Controller Electronics", \ + "Nonvolatile Cache", \ + "Invalid Operation Reason", \ + "Uninterruptible Power Supply", \ + "Display", \ + "Key Pad Entry", \ + "Enclosure", \ + "SCSI Port/Transceiver", \ + "Language", \ + "Communication Port", \ + "Voltage Sensor", \ + "Current Sensor", \ + "SCSI Target Port", \ + "SCSI Initiator Port", \ + "Simple Subenclosure", \ + "Array Device Slot", \ + "SAS Expander", \ + "SAS Connector" \ +} + +extern const char *elm_type_names[]; + typedef struct encioc_element { /* Element Index */ unsigned int elm_idx; diff --git a/sys/cam/scsi/scsi_enc_internal.h b/sys/cam/scsi/scsi_enc_internal.h index 0d4bdffda4f9a..293da3ee7386b 100644 --- a/sys/cam/scsi/scsi_enc_internal.h +++ b/sys/cam/scsi/scsi_enc_internal.h @@ -36,17 +36,15 @@ #ifndef __SCSI_ENC_INTERNAL_H__ #define __SCSI_ENC_INTERNAL_H__ +#include <sys/sysctl.h> + typedef struct enc_element { - uint32_t - enctype : 8, /* enclosure type */ - subenclosure : 8, /* subenclosure id */ - svalid : 1, /* enclosure information valid */ - overall_status_elem: 1,/* - * This object represents generic - * status about all objects of this - * type. - */ - priv : 14; /* private data, per object */ + uint8_t elm_idx; /* index of element */ + uint8_t elm_type; /* element type */ + uint8_t subenclosure; /* subenclosure id */ + uint8_t type_elm_idx; /* index of element within type */ + uint8_t svalid; /* enclosure information valid */ + uint16_t priv; /* private data, per object */ uint8_t encstat[4]; /* state && stats */ uint8_t *physical_path; /* Device physical path data. */ u_int physical_path_len; /* Length of device path data. */ @@ -55,10 +53,8 @@ typedef struct enc_element { typedef enum { ENC_NONE, - ENC_SES_SCSI2, ENC_SES, ENC_SES_PASSTHROUGH, - ENC_SEN, ENC_SAFT, ENC_SEMB_SES, ENC_SEMB_SAFT @@ -206,6 +202,9 @@ enc_softc_init_t ses_softc_init; /* SAF-TE interface */ enc_softc_init_t safte_softc_init; +SYSCTL_DECL(_kern_cam_enc); +extern int enc_verbose; + /* Helper macros */ MALLOC_DECLARE(M_SCSIENC); #define ENC_CFLAGS CAM_RETRY_SELTO @@ -218,7 +217,7 @@ MALLOC_DECLARE(M_SCSIENC); #else #define ENC_DLOG if (0) enc_log #endif -#define ENC_VLOG if (bootverbose) enc_log +#define ENC_VLOG if (enc_verbose) enc_log #define ENC_MALLOC(amt) malloc(amt, M_SCSIENC, M_NOWAIT) #define ENC_MALLOCZ(amt) malloc(amt, M_SCSIENC, M_ZERO|M_NOWAIT) /* Cast away const avoiding GCC warnings. */ diff --git a/sys/cam/scsi/scsi_enc_safte.c b/sys/cam/scsi/scsi_enc_safte.c index 8afcc323991a6..94219cde7a89b 100644 --- a/sys/cam/scsi/scsi_enc_safte.c +++ b/sys/cam/scsi/scsi_enc_safte.c @@ -227,7 +227,6 @@ static char *safte_2little = "Too Little Data Returned (%d) at line %d\n"; } int emulate_array_devices = 1; -SYSCTL_DECL(_kern_cam_enc); SYSCTL_INT(_kern_cam_enc, OID_AUTO, emulate_array_devices, CTLFLAG_RWTUN, &emulate_array_devices, 0, "Emulate Array Devices for SAF-TE"); @@ -302,21 +301,21 @@ safte_process_config(enc_softc_t *enc, struct enc_fsm_state *state, * in later fetches of status. */ for (i = 0; i < cfg->Nfans; i++) - enc->enc_cache.elm_map[r++].enctype = ELMTYP_FAN; + enc->enc_cache.elm_map[r++].elm_type = ELMTYP_FAN; cfg->pwroff = (uint8_t) r; for (i = 0; i < cfg->Npwr; i++) - enc->enc_cache.elm_map[r++].enctype = ELMTYP_POWER; + enc->enc_cache.elm_map[r++].elm_type = ELMTYP_POWER; for (i = 0; i < cfg->DoorLock; i++) - enc->enc_cache.elm_map[r++].enctype = ELMTYP_DOORLOCK; + enc->enc_cache.elm_map[r++].elm_type = ELMTYP_DOORLOCK; if (cfg->Nspkrs > 0) - enc->enc_cache.elm_map[r++].enctype = ELMTYP_ALARM; + enc->enc_cache.elm_map[r++].elm_type = ELMTYP_ALARM; for (i = 0; i < cfg->Ntherm; i++) - enc->enc_cache.elm_map[r++].enctype = ELMTYP_THERM; + enc->enc_cache.elm_map[r++].elm_type = ELMTYP_THERM; for (i = 0; i <= cfg->Ntstats; i++) - enc->enc_cache.elm_map[r++].enctype = ELMTYP_THERM; + enc->enc_cache.elm_map[r++].elm_type = ELMTYP_THERM; cfg->slotoff = (uint8_t) r; for (i = 0; i < cfg->Nslots; i++) - enc->enc_cache.elm_map[r++].enctype = + enc->enc_cache.elm_map[r++].elm_type = emulate_array_devices ? ELMTYP_ARRAY_DEV : ELMTYP_DEVICE; @@ -506,7 +505,7 @@ safte_process_status(enc_softc_t *enc, struct enc_fsm_state *state, */ for (i = 0; i < cfg->Nslots; i++) { SAFT_BAIL(r, xfer_len); - if (cache->elm_map[cfg->slotoff + i].enctype == ELMTYP_DEVICE) + if (cache->elm_map[cfg->slotoff + i].elm_type == ELMTYP_DEVICE) cache->elm_map[cfg->slotoff + i].encstat[1] = buf[r]; r++; } @@ -679,7 +678,7 @@ safte_process_slotstatus(enc_softc_t *enc, struct enc_fsm_state *state, oid = cfg->slotoff; for (r = i = 0; i < cfg->Nslots; i++, r += 4) { SAFT_BAIL(r+3, xfer_len); - if (cache->elm_map[oid].enctype == ELMTYP_ARRAY_DEV) + if (cache->elm_map[oid].elm_type == ELMTYP_ARRAY_DEV) cache->elm_map[oid].encstat[1] = 0; cache->elm_map[oid].encstat[2] &= SESCTL_RQSID; cache->elm_map[oid].encstat[3] = 0; @@ -706,7 +705,7 @@ safte_process_slotstatus(enc_softc_t *enc, struct enc_fsm_state *state, cache->elm_map[oid].encstat[3] |= SESCTL_RQSFLT; if (buf[r+0] & 0x40) cache->elm_map[oid].encstat[0] |= SESCTL_PRDFAIL; - if (cache->elm_map[oid].enctype == ELMTYP_ARRAY_DEV) { + if (cache->elm_map[oid].elm_type == ELMTYP_ARRAY_DEV) { if (buf[r+0] & 0x01) cache->elm_map[oid].encstat[1] |= 0x80; if (buf[r+0] & 0x04) @@ -772,7 +771,7 @@ safte_fill_control_request(enc_softc_t *enc, struct enc_fsm_state *state, } else { ep = &enc->enc_cache.elm_map[idx]; - switch (ep->enctype) { + switch (ep->elm_type) { case ELMTYP_DEVICE: case ELMTYP_ARRAY_DEV: switch (cfg->current_request_stage) { @@ -782,7 +781,7 @@ safte_fill_control_request(enc_softc_t *enc, struct enc_fsm_state *state, ep->priv |= 0x40; if (req->elm_stat[3] & SESCTL_RQSFLT) ep->priv |= 0x02; - if (ep->enctype == ELMTYP_ARRAY_DEV) { + if (ep->elm_type == ELMTYP_ARRAY_DEV) { if (req->elm_stat[1] & 0x01) ep->priv |= 0x200; if (req->elm_stat[1] & 0x02) @@ -971,7 +970,7 @@ safte_process_control_request(enc_softc_t *enc, struct enc_fsm_state *state, if (idx == SES_SETSTATUS_ENC_IDX) type = -1; else - type = enc->enc_cache.elm_map[idx].enctype; + type = enc->enc_cache.elm_map[idx].elm_type; if (type == ELMTYP_DEVICE || type == ELMTYP_ARRAY_DEV) enc_update_request(enc, SAFTE_UPDATE_READSLOTSTATUS); else diff --git a/sys/cam/scsi/scsi_enc_ses.c b/sys/cam/scsi/scsi_enc_ses.c index 5e9d2dc94d2d2..e5a18d5d9a45f 100644 --- a/sys/cam/scsi/scsi_enc_ses.c +++ b/sys/cam/scsi/scsi_enc_ses.c @@ -102,6 +102,7 @@ typedef struct ses_addl_status { union { union ses_fcobj_hdr *fc; union ses_elm_sas_hdr *sas; + struct ses_elm_ata_hdr *ata; } proto_hdr; union ses_addl_data proto_data; /* array sizes stored in header */ } ses_add_status_t; @@ -444,6 +445,7 @@ ses_iter_next(struct ses_iterator *iter) iter->type_element_index = ITERATOR_INDEX_END; iter->global_element_index = ITERATOR_INDEX_END; iter->individual_element_index = ITERATOR_INDEX_END; + iter->saved_individual_element_index = ITERATOR_INDEX_END; return (NULL); } @@ -468,17 +470,12 @@ ses_iter_next(struct ses_iterator *iter) */ iter->type_index++; iter->type_element_index = 0; - iter->saved_individual_element_index - = iter->individual_element_index; iter->individual_element_index = ITERATOR_INDEX_INVALID; } if (iter->type_element_index > 0) { - if (iter->type_element_index == 1) { - iter->individual_element_index - = iter->saved_individual_element_index; - } - iter->individual_element_index++; + iter->individual_element_index = + ++iter->saved_individual_element_index; } return (&iter->cache->elm_map[iter->global_element_index]); @@ -829,14 +826,6 @@ ses_devids_iter(enc_softc_t *enc, enc_element_t *elm, elmpriv = elm->elm_private; addl = &(elmpriv->addl); - /* - * Don't assume this object has additional status information, or - * that it is a SAS device, or that it is a device slot device. - */ - if (addl->hdr == NULL || addl->proto_hdr.sas == NULL - || addl->proto_data.sasdev_phys == NULL) - return; - devid_record_size = SVPD_DEVICE_ID_DESC_HDR_LEN + sizeof(struct scsi_vpd_id_naa_ieee_reg); for (i = 0; i < addl->proto_hdr.sas->base_hdr.num_phys; i++) { @@ -954,11 +943,40 @@ static void ses_paths_iter(enc_softc_t *enc, enc_element_t *elm, ses_path_callback_t *callback, void *callback_arg) { - ses_path_iter_args_t args; + ses_element_t *elmpriv; + struct ses_addl_status *addl; + + elmpriv = elm->elm_private; + addl = &(elmpriv->addl); + + if (addl->hdr == NULL) + return; - args.callback = callback; - args.callback_arg = callback_arg; - ses_devids_iter(enc, elm, ses_path_iter_devid_callback, &args); + if (addl->proto_hdr.sas != NULL && + addl->proto_data.sasdev_phys != NULL) { + ses_path_iter_args_t args; + + args.callback = callback; + args.callback_arg = callback_arg; + ses_devids_iter(enc, elm, ses_path_iter_devid_callback, &args); + } else if (addl->proto_hdr.ata != NULL) { + struct cam_path *path; + struct ccb_getdev cgd; + + if (xpt_create_path(&path, /*periph*/NULL, + scsi_4btoul(addl->proto_hdr.ata->bus), + scsi_4btoul(addl->proto_hdr.ata->target), 0) + != CAM_REQ_CMP) + return; + + xpt_setup_ccb(&cgd.ccb_h, path, CAM_PRIORITY_NORMAL); + cgd.ccb_h.func_code = XPT_GDEV_TYPE; + xpt_action((union ccb *)&cgd); + if (cgd.ccb_h.status == CAM_REQ_CMP) + callback(enc, elm, path, callback_arg); + + xpt_free_path(path); + } } /** @@ -1063,6 +1081,10 @@ ses_set_physpath(enc_softc_t *enc, enc_element_t *elm, ret = EIO; devid = NULL; + elmpriv = elm->elm_private; + if (elmpriv->addl.hdr == NULL) + goto out; + /* * Assemble the components of the physical path starting with * the device ID of the enclosure itself. @@ -1095,7 +1117,6 @@ ses_set_physpath(enc_softc_t *enc, enc_element_t *elm, scsi_8btou64(idd->identifier), iter->type_index, iter->type_element_index); /* Append the element descriptor if one exists */ - elmpriv = elm->elm_private; if (elmpriv->descr != NULL && elmpriv->descr_len > 0) { sbuf_cat(&sb, "/elmdesc@"); for (i = 0, c = elmpriv->descr; i < elmpriv->descr_len; @@ -1461,9 +1482,10 @@ ses_process_config(enc_softc_t *enc, struct enc_fsm_state *state, iter.global_element_index, iter.type_index, nelm, iter.type_element_index); thdr = ses_cache->ses_types[iter.type_index].hdr; + element->elm_idx = iter.global_element_index; + element->elm_type = thdr->etype_elm_type; element->subenclosure = thdr->etype_subenc; - element->enctype = thdr->etype_elm_type; - element->overall_status_elem = iter.type_element_index == 0; + element->type_elm_idx = iter.type_element_index; element->elm_private = malloc(sizeof(ses_element_t), M_SCSIENC, M_WAITOK|M_ZERO); ENC_DLOG(enc, "%s: creating elmpriv %d(%d,%d) subenc %d " @@ -1667,6 +1689,8 @@ static int ses_get_elm_addlstatus_fc(enc_softc_t *, enc_cache_t *, uint8_t *, int); static int ses_get_elm_addlstatus_sas(enc_softc_t *, enc_cache_t *, uint8_t *, int, int, int, int); +static int ses_get_elm_addlstatus_ata(enc_softc_t *, enc_cache_t *, uint8_t *, + int, int, int, int); /** * \brief Parse the additional status element data for each object. @@ -1685,7 +1709,6 @@ ses_process_elm_addlstatus(enc_softc_t *enc, struct enc_fsm_state *state, struct ses_iterator iter, titer; int eip; int err; - int ignore_index = 0; int length; int offset; enc_cache_t *enc_cache; @@ -1756,7 +1779,7 @@ ses_process_elm_addlstatus(enc_softc_t *enc, struct enc_fsm_state *state, elm_hdr = (struct ses_elm_addlstatus_base_hdr *)&buf[offset]; eip = ses_elm_addlstatus_eip(elm_hdr); - if (eip && !ignore_index) { + if (eip) { struct ses_elm_addlstatus_eip_hdr *eip_hdr; int expected_index, index; ses_elem_index_type_t index_type; @@ -1769,17 +1792,44 @@ ses_process_elm_addlstatus(enc_softc_t *enc, struct enc_fsm_state *state, index_type = SES_ELEM_INDEX_INDIVIDUAL; expected_index = iter.individual_element_index; } + if (eip_hdr->element_index < expected_index) { + ENC_VLOG(enc, "%s: provided %selement index " + "%d is lower then expected %d\n", + __func__, (eip_hdr->byte2 & + SES_ADDL_EIP_EIIOE) ? "global " : "", + eip_hdr->element_index, expected_index); + goto badindex; + } titer = iter; telement = ses_iter_seek_to(&titer, eip_hdr->element_index, index_type); - if (telement != NULL && - (ses_typehasaddlstatus(enc, titer.type_index) != - TYPE_ADDLSTATUS_NONE || - titer.type_index > ELMTYP_SAS_CONN)) { + if (telement == NULL) { + ENC_VLOG(enc, "%s: provided %selement index " + "%d does not exist\n", __func__, + (eip_hdr->byte2 & SES_ADDL_EIP_EIIOE) ? + "global " : "", eip_hdr->element_index); + goto badindex; + } + if (ses_typehasaddlstatus(enc, titer.type_index) == + TYPE_ADDLSTATUS_NONE) { + ENC_VLOG(enc, "%s: provided %selement index " + "%d can't have additional status\n", + __func__, + (eip_hdr->byte2 & SES_ADDL_EIP_EIIOE) ? + "global " : "", eip_hdr->element_index); +badindex: + /* + * If we expected mandatory element, we may + * guess it was just a wrong index and we may + * use the status. If element was optional, + * then we have no idea where status belongs. + */ + if (status_type == TYPE_ADDLSTATUS_OPTIONAL) + break; + } else { iter = titer; element = telement; - } else - ignore_index = 1; + } if (eip_hdr->byte2 & SES_ADDL_EIP_EIIOE) index = iter.global_element_index; @@ -1796,40 +1846,46 @@ ses_process_elm_addlstatus(enc_softc_t *enc, struct enc_fsm_state *state, } } elmpriv = element->elm_private; - elmpriv->addl.hdr = elm_hdr; ENC_DLOG(enc, "%s: global element index=%d, type index=%d " "type element index=%d, offset=0x%x, " "byte0=0x%x, length=0x%x\n", __func__, iter.global_element_index, iter.type_index, - iter.type_element_index, offset, elmpriv->addl.hdr->byte0, - elmpriv->addl.hdr->length); + iter.type_element_index, offset, elm_hdr->byte0, + elm_hdr->length); /* Skip to after the length field */ offset += sizeof(struct ses_elm_addlstatus_base_hdr); /* Make sure the descriptor is within bounds */ - if ((offset + elmpriv->addl.hdr->length) > length) { + if ((offset + elm_hdr->length) > length) { ENC_VLOG(enc, "Element %d Beyond End " "of Additional Element Status Descriptors\n", iter.global_element_index); break; } + /* Skip elements marked as invalid. */ + if (ses_elm_addlstatus_invalid(elm_hdr)) { + offset += elm_hdr->length; + continue; + } + elmpriv->addl.hdr = elm_hdr; + /* Advance to the protocol data, skipping eip bytes if needed */ offset += (eip * SES_EIP_HDR_EXTRA_LEN); - proto_info_len = elmpriv->addl.hdr->length + proto_info_len = elm_hdr->length - (eip * SES_EIP_HDR_EXTRA_LEN); /* Errors in this block are ignored as they are non-fatal */ - switch(ses_elm_addlstatus_proto(elmpriv->addl.hdr)) { + switch(ses_elm_addlstatus_proto(elm_hdr)) { case SPSP_PROTO_FC: - if (elmpriv->addl.hdr->length == 0) + if (elm_hdr->length == 0) break; ses_get_elm_addlstatus_fc(enc, enc_cache, &buf[offset], proto_info_len); break; case SPSP_PROTO_SAS: - if (elmpriv->addl.hdr->length <= 2) + if (elm_hdr->length <= 2) break; ses_get_elm_addlstatus_sas(enc, enc_cache, &buf[offset], @@ -1837,10 +1893,17 @@ ses_process_elm_addlstatus(enc_softc_t *enc, struct enc_fsm_state *state, eip, iter.type_index, iter.global_element_index); break; + case SPSP_PROTO_ATA: + ses_get_elm_addlstatus_ata(enc, enc_cache, + &buf[offset], + proto_info_len, + eip, iter.type_index, + iter.global_element_index); + break; default: ENC_VLOG(enc, "Element %d: Unknown Additional Element " "Protocol 0x%x\n", iter.global_element_index, - ses_elm_addlstatus_proto(elmpriv->addl.hdr)); + ses_elm_addlstatus_proto(elm_hdr)); break; } @@ -2165,18 +2228,16 @@ ses_get_elm_addlstatus_fc(enc_softc_t *enc, enc_cache_t *enc_cache, } #define SES_PRINT_PORTS(p, type) do { \ - sbuf_printf(sbp, " %s(", type); \ - if (((p) & SES_SASOBJ_DEV_PHY_PROTOMASK) == 0) \ - sbuf_printf(sbp, " None"); \ - else { \ + if (((p) & SES_SASOBJ_DEV_PHY_PROTOMASK) != 0) { \ + sbuf_printf(sbp, " %s (", type); \ if ((p) & SES_SASOBJ_DEV_PHY_SMP) \ sbuf_printf(sbp, " SMP"); \ if ((p) & SES_SASOBJ_DEV_PHY_STP) \ sbuf_printf(sbp, " STP"); \ if ((p) & SES_SASOBJ_DEV_PHY_SSP) \ sbuf_printf(sbp, " SSP"); \ + sbuf_printf(sbp, " )"); \ } \ - sbuf_printf(sbp, " )"); \ } while(0) /** @@ -2186,11 +2247,10 @@ ses_get_elm_addlstatus_fc(enc_softc_t *enc, enc_cache_t *enc_cache, * \param sesname SES device name associated with the object. * \param sbp Sbuf to print to. * \param obj The object to print the data for. - * \param periph_name Peripheral string associated with the object. */ static void ses_print_addl_data_sas_type0(char *sesname, struct sbuf *sbp, - enc_element_t *obj, char *periph_name) + enc_element_t *obj) { int i; ses_element_t *elmpriv; @@ -2199,16 +2259,12 @@ ses_print_addl_data_sas_type0(char *sesname, struct sbuf *sbp, elmpriv = obj->elm_private; addl = &(elmpriv->addl); - if (addl->proto_hdr.sas == NULL) - return; - sbuf_printf(sbp, "%s: %s: SAS Device Slot Element:", - sesname, periph_name); - sbuf_printf(sbp, " %d Phys", addl->proto_hdr.sas->base_hdr.num_phys); + sbuf_printf(sbp, ", SAS Slot: %d%s phys", + addl->proto_hdr.sas->base_hdr.num_phys, + ses_elm_sas_type0_not_all_phys(addl->proto_hdr.sas) ? "+" : ""); if (ses_elm_addlstatus_eip(addl->hdr)) - sbuf_printf(sbp, " at Slot %d", + sbuf_printf(sbp, " at slot %d", addl->proto_hdr.sas->type0_eip.dev_slot_num); - if (ses_elm_sas_type0_not_all_phys(addl->proto_hdr.sas)) - sbuf_printf(sbp, ", Not All Phys"); sbuf_printf(sbp, "\n"); if (addl->proto_data.sasdev_phys == NULL) return; @@ -2219,9 +2275,8 @@ ses_print_addl_data_sas_type0(char *sesname, struct sbuf *sbp, /* Spec says all other fields are specific values */ sbuf_printf(sbp, " SATA device\n"); else { - sbuf_printf(sbp, " SAS device type %d id %d\n", + sbuf_printf(sbp, " SAS device type %d phy %d", ses_elm_sas_dev_phy_dev_type(phy), phy->phy_id); - sbuf_printf(sbp, "%s: phy %d: protocols:", sesname, i); SES_PRINT_PORTS(phy->initiator_ports, "Initiator"); SES_PRINT_PORTS(phy->target_ports, "Target"); sbuf_printf(sbp, "\n"); @@ -2235,32 +2290,16 @@ ses_print_addl_data_sas_type0(char *sesname, struct sbuf *sbp, #undef SES_PRINT_PORTS /** - * \brief Report whether a given enclosure object is an expander. - * - * \param enc SES softc associated with object. - * \param obj Enclosure object to report for. - * - * \return 1 if true, 0 otherwise. - */ -static int -ses_obj_is_expander(enc_softc_t *enc, enc_element_t *obj) -{ - return (obj->enctype == ELMTYP_SAS_EXP); -} - -/** * \brief Print the additional element status data for this object, for SAS * type 1 objects. See SES2 r20 Sections 6.1.13.3.3 and 6.1.13.3.4. * - * \param enc SES enclosure, needed for type identification. * \param sesname SES device name associated with the object. * \param sbp Sbuf to print to. * \param obj The object to print the data for. - * \param periph_name Peripheral string associated with the object. */ static void -ses_print_addl_data_sas_type1(enc_softc_t *enc, char *sesname, - struct sbuf *sbp, enc_element_t *obj, char *periph_name) +ses_print_addl_data_sas_type1(char *sesname, struct sbuf *sbp, + enc_element_t *obj) { int i, num_phys; ses_element_t *elmpriv; @@ -2270,12 +2309,10 @@ ses_print_addl_data_sas_type1(enc_softc_t *enc, char *sesname, elmpriv = obj->elm_private; addl = &(elmpriv->addl); - if (addl->proto_hdr.sas == NULL) - return; - sbuf_printf(sbp, "%s: %s: SAS ", sesname, periph_name); - if (ses_obj_is_expander(enc, obj)) { + sbuf_printf(sbp, ", SAS "); + if (obj->elm_type == ELMTYP_SAS_EXP) { num_phys = addl->proto_hdr.sas->base_hdr.num_phys; - sbuf_printf(sbp, "Expander: %d Phys", num_phys); + sbuf_printf(sbp, "Expander: %d phys", num_phys); if (addl->proto_data.sasexp_phys == NULL) return; for (i = 0;i < num_phys;i++) { @@ -2286,7 +2323,7 @@ ses_print_addl_data_sas_type1(enc_softc_t *enc, char *sesname, } } else { num_phys = addl->proto_hdr.sas->base_hdr.num_phys; - sbuf_printf(sbp, "Port: %d Phys", num_phys); + sbuf_printf(sbp, "Port: %d phys", num_phys); if (addl->proto_data.sasport_phys == NULL) return; for (i = 0;i < num_phys;i++) { @@ -2302,6 +2339,24 @@ ses_print_addl_data_sas_type1(enc_softc_t *enc, char *sesname, } /** + * \brief Print the additional element status data for this object, for + * ATA objects. + * + * \param sbp Sbuf to print to. + * \param obj The object to print the data for. + */ +static void +ses_print_addl_data_ata(struct sbuf *sbp, enc_element_t *obj) +{ + ses_element_t *elmpriv = obj->elm_private; + struct ses_addl_status *addl = &elmpriv->addl; + struct ses_elm_ata_hdr *ata = addl->proto_hdr.ata; + + sbuf_printf(sbp, ", SATA Slot: scbus%d target %d\n", + scsi_4btoul(ata->bus), scsi_4btoul(ata->target)); +} + +/** * \brief Print the additional element status data for this object. * * \param enc SES softc associated with the object. @@ -2332,27 +2387,45 @@ ses_print_addl_data(enc_softc_t *enc, enc_element_t *obj) sbuf_printf(&sesname, "%s%d", enc->periph->periph_name, enc->periph->unit_number); sbuf_finish(&sesname); + sbuf_printf(&out, "%s: %s in ", sbuf_data(&sesname), sbuf_data(&name)); if (elmpriv->descr != NULL) - sbuf_printf(&out, "%s: %s: Element descriptor: '%s'\n", - sbuf_data(&sesname), sbuf_data(&name), elmpriv->descr); + sbuf_printf(&out, "'%s'", elmpriv->descr); + else { + if (obj->elm_type <= ELMTYP_LAST) + sbuf_cat(&out, elm_type_names[obj->elm_type]); + else + sbuf_printf(&out, "<Type 0x%02x>", obj->elm_type); + sbuf_printf(&out, " %d", obj->type_elm_idx); + if (obj->subenclosure != 0) + sbuf_printf(&out, " of subenc %d", obj->subenclosure); + } switch(ses_elm_addlstatus_proto(addl->hdr)) { + case SPSP_PROTO_FC: + goto noaddl; /* stubbed for now */ case SPSP_PROTO_SAS: + if (addl->proto_hdr.sas == NULL) + goto noaddl; switch(ses_elm_sas_descr_type(addl->proto_hdr.sas)) { case SES_SASOBJ_TYPE_SLOT: ses_print_addl_data_sas_type0(sbuf_data(&sesname), - &out, obj, sbuf_data(&name)); + &out, obj); break; case SES_SASOBJ_TYPE_OTHER: - ses_print_addl_data_sas_type1(enc, sbuf_data(&sesname), - &out, obj, sbuf_data(&name)); + ses_print_addl_data_sas_type1(sbuf_data(&sesname), + &out, obj); break; default: - break; + goto noaddl; } break; - case SPSP_PROTO_FC: /* stubbed for now */ + case SPSP_PROTO_ATA: + if (addl->proto_hdr.ata == NULL) + goto noaddl; + ses_print_addl_data_ata(&out, obj); break; default: +noaddl: + sbuf_cat(&out, "\n"); break; } sbuf_finish(&out); @@ -2457,7 +2530,7 @@ ses_get_elm_addlstatus_sas_type1(enc_softc_t *enc, enc_cache_t *enc_cache, goto out; /* Process expanders differently from other type1 cases */ - if (ses_obj_is_expander(enc, obj)) { + if (obj->elm_type == ELMTYP_SAS_EXP) { offset += sizeof(struct ses_elm_sas_type1_expander_hdr); physz = addl->proto_hdr.sas->base_hdr.num_phys * sizeof(struct ses_elm_sas_expander_phy); @@ -2565,6 +2638,53 @@ out: return (err); } +/** + * \brief Update the softc with the additional element status data for this + * object, for ATA objects. + * + * \param enc SES softc to be updated. + * \param buf The additional element status response buffer. + * \param bufsiz Size of the response buffer. + * \param eip The EIP bit value. + * \param tidx Type index for this object. + * \param nobj Number of objects attached to the SES softc. + * + * \return 0 on success, errno otherwise. + */ +static int +ses_get_elm_addlstatus_ata(enc_softc_t *enc, enc_cache_t *enc_cache, + uint8_t *buf, int bufsiz, int eip, int tidx, + int nobj) +{ + int err; + ses_cache_t *ses_cache; + + if (bufsiz < sizeof(struct ses_elm_ata_hdr)) { + err = EIO; + goto out; + } + + ses_cache = enc_cache->private; + switch(ses_cache->ses_types[tidx].hdr->etype_elm_type) { + case ELMTYP_DEVICE: + case ELMTYP_ARRAY_DEV: + break; + default: + ENC_VLOG(enc, "Element %d has Additional Status, " + "invalid for SES element type 0x%x\n", nobj, + ses_cache->ses_types[tidx].hdr->etype_elm_type); + err = ENODEV; + goto out; + } + + ((ses_element_t *)enc_cache->elm_map[nobj].elm_private) + ->addl.proto_hdr.ata = (struct ses_elm_ata_hdr *)buf; + err = 0; + +out: + return (err); +} + static void ses_softc_invalidate(enc_softc_t *enc) { diff --git a/sys/cam/scsi/scsi_ses.h b/sys/cam/scsi/scsi_ses.h index 779b3a97a00d2..b9c69cbcfe308 100644 --- a/sys/cam/scsi/scsi_ses.h +++ b/sys/cam/scsi/scsi_ses.h @@ -2181,15 +2181,27 @@ struct ses_status_page_hdr { #define SESCTL_DISABLE 0x20 #define SESCTL_RSTSWAP 0x10 - -/* Control bits, Device Elements, byte 2 */ -#define SESCTL_DRVLCK 0x40 /* "DO NOT REMOVE" */ +/* Control bits, Array Device Slot Elements, byte 1 */ +#define SESCTL_RQSOK 0x80 /* RQST OK */ +#define SESCTL_RQSRSV 0x40 /* RQST RSVD DEVICE */ +#define SESCTL_RQSSPR 0x20 /* RQST HOT SPARE */ +#define SESCTL_RQSCCH 0x10 /* RQST CONS CHECK */ +#define SESCTL_RQSCRA 0x08 /* RQST IN CRIT ARRAY */ +#define SESCTL_RQSFAA 0x04 /* RQST IN FAILED ARRAY */ +#define SESCTL_RQSRR 0x02 /* RQST REBUI/REMAP */ +#define SESCTL_RQSRRA 0x01 /* RQST R/R ABORT */ +/* Control bits, [Array] Device Slot Elements, byte 2 */ +#define SESCTL_RQSACT 0x80 /* RQST ACTIVE */ +#define SESCTL_DRVLCK 0x40 /* DO NOT REMOVE */ +#define SESCTL_RQSMSN 0x10 /* RQST MISSING */ #define SESCTL_RQSINS 0x08 /* RQST INSERT */ #define SESCTL_RQSRMV 0x04 /* RQST REMOVE */ #define SESCTL_RQSID 0x02 /* RQST IDENT */ -/* Control bits, Device Elements, byte 3 */ +/* Control bits, [Array] Device Slot Elements, byte 3 */ #define SESCTL_RQSFLT 0x20 /* RQST FAULT */ #define SESCTL_DEVOFF 0x10 /* DEVICE OFF */ +#define SESCTL_ENBYPA 0x08 /* ENABLE BYP A */ +#define SESCTL_ENBYPB 0x04 /* ENABLE BYP B */ /* Control bits, Generic, byte 3 */ #define SESCTL_RQSTFAIL 0x40 @@ -2399,6 +2411,17 @@ union ses_elm_sas_hdr { int ses_elm_sas_type0_not_all_phys(union ses_elm_sas_hdr *); int ses_elm_sas_descr_type(union ses_elm_sas_hdr *); +/* + * This structure for SPSP_PROTO_ATA is not defined by SES specs, + * but purely my own design to make AHCI EM interoperate with SES. + * Since no other software I know can talk to SEMB, and we do not + * expose this this outside, it should be safe to do what we want. + */ +struct ses_elm_ata_hdr { + uint8_t bus[4]; + uint8_t target[4]; +}; + struct ses_elm_addlstatus_base_hdr { uint8_t byte0; /* diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_objset.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_objset.c index 2e36e0e5eec1a..71d9cd7b6f172 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_objset.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_objset.c @@ -1334,6 +1334,8 @@ dmu_objset_sync(objset_t *os, zio_t *pio, dmu_tx_t *tx) zio_t *zio; list_t *list; dbuf_dirty_record_t *dr; + int num_sublists; + multilist_t *ml; blkptr_t *blkptr_copy = kmem_alloc(sizeof (*os->os_rootbp), KM_SLEEP); *blkptr_copy = *os->os_rootbp; @@ -1402,10 +1404,13 @@ dmu_objset_sync(objset_t *os, zio_t *pio, dmu_tx_t *tx) } } - for (int i = 0; - i < multilist_get_num_sublists(os->os_dirty_dnodes[txgoff]); i++) { + ml = os->os_dirty_dnodes[txgoff]; + num_sublists = multilist_get_num_sublists(ml); + for (int i = 0; i < num_sublists; i++) { + if (multilist_sublist_is_empty_idx(ml, i)) + continue; sync_dnodes_arg_t *sda = kmem_alloc(sizeof (*sda), KM_SLEEP); - sda->sda_list = os->os_dirty_dnodes[txgoff]; + sda->sda_list = ml; sda->sda_sublist_idx = i; sda->sda_tx = tx; (void) taskq_dispatch(dmu_objset_pool(os)->dp_sync_taskq, @@ -1619,6 +1624,8 @@ userquota_updates_task(void *arg) void dmu_objset_do_userquota_updates(objset_t *os, dmu_tx_t *tx) { + int num_sublists; + if (!dmu_objset_userused_enabled(os)) return; @@ -1632,8 +1639,10 @@ dmu_objset_do_userquota_updates(objset_t *os, dmu_tx_t *tx) DMU_OT_USERGROUP_USED, DMU_OT_NONE, 0, tx)); } - for (int i = 0; - i < multilist_get_num_sublists(os->os_synced_dnodes); i++) { + num_sublists = multilist_get_num_sublists(os->os_synced_dnodes); + for (int i = 0; i < num_sublists; i++) { + if (multilist_sublist_is_empty_idx(os->os_synced_dnodes, i)) + continue; userquota_updates_arg_t *uua = kmem_alloc(sizeof (*uua), KM_SLEEP); uua->uua_os = os; diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/multilist.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/multilist.c index b61d1358c8a83..f517454d3d6da 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/multilist.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/multilist.c @@ -360,6 +360,28 @@ multilist_sublist_remove(multilist_sublist_t *mls, void *obj) list_remove(&mls->mls_list, obj); } +int +multilist_sublist_is_empty(multilist_sublist_t *mls) +{ + ASSERT(MUTEX_HELD(&mls->mls_lock)); + return (list_is_empty(&mls->mls_list)); +} + +int +multilist_sublist_is_empty_idx(multilist_t *ml, unsigned int sublist_idx) +{ + multilist_sublist_t *mls; + int empty; + + ASSERT3U(sublist_idx, <, ml->ml_num_sublists); + mls = &ml->ml_sublists[sublist_idx]; + ASSERT(!MUTEX_HELD(&mls->mls_lock)); + mutex_enter(&mls->mls_lock); + empty = list_is_empty(&mls->mls_list); + mutex_exit(&mls->mls_lock); + return (empty); +} + void * multilist_sublist_head(multilist_sublist_t *mls) { diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/multilist.h b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/multilist.h index 7f386fb7c3bec..a3b44e60eb97b 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/multilist.h +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/multilist.h @@ -89,6 +89,8 @@ void multilist_sublist_insert_head(multilist_sublist_t *, void *); void multilist_sublist_insert_tail(multilist_sublist_t *, void *); void multilist_sublist_move_forward(multilist_sublist_t *mls, void *obj); void multilist_sublist_remove(multilist_sublist_t *, void *); +int multilist_sublist_is_empty(multilist_sublist_t *); +int multilist_sublist_is_empty_idx(multilist_t *, unsigned int); void *multilist_sublist_head(multilist_sublist_t *); void *multilist_sublist_tail(multilist_sublist_t *); diff --git a/sys/compat/linuxkpi/common/include/asm/atomic-long.h b/sys/compat/linuxkpi/common/include/asm/atomic-long.h index d7f839f2541f5..108d7f4f7b3a3 100644 --- a/sys/compat/linuxkpi/common/include/asm/atomic-long.h +++ b/sys/compat/linuxkpi/common/include/asm/atomic-long.h @@ -42,6 +42,7 @@ typedef struct { } atomic_long_t; #define atomic_long_add(i, v) atomic_long_add_return((i), (v)) +#define atomic_long_sub(i, v) atomic_long_add_return(-(i), (v)) #define atomic_long_inc_return(v) atomic_long_add_return(1, (v)) #define atomic_long_inc_not_zero(v) atomic_long_add_unless((v), 1, 0) diff --git a/sys/compat/linuxkpi/common/include/linux/rculist.h b/sys/compat/linuxkpi/common/include/linux/rculist.h index e4823de7a3bf7..0a4ad499c3807 100644 --- a/sys/compat/linuxkpi/common/include/linux/rculist.h +++ b/sys/compat/linuxkpi/common/include/linux/rculist.h @@ -33,6 +33,25 @@ #include <linux/list.h> #include <linux/rcupdate.h> +#define list_entry_rcu(ptr, type, member) \ + container_of(READ_ONCE(ptr), type, member) + +#define list_next_rcu(head) (*((struct list_head **)(&(head)->next))) + +#define list_for_each_entry_rcu(pos, head, member) \ + for (pos = list_entry_rcu((head)->next, typeof(*(pos)), member); \ + &(pos)->member != (head); \ + pos = list_entry_rcu((pos)->member.next, typeof(*(pos)), member)) + +static inline void +list_add_rcu(struct list_head *new, struct list_head *prev) +{ + new->next = prev->next; + new->prev = prev; + rcu_assign_pointer(list_next_rcu(prev), new); + prev->prev = new; +} + #define hlist_first_rcu(head) (*((struct hlist_node **)(&(head)->first))) #define hlist_next_rcu(node) (*((struct hlist_node **)(&(node)->next))) #define hlist_pprev_rcu(node) (*((struct hlist_node **)((node)->pprev))) @@ -47,8 +66,12 @@ hlist_add_behind_rcu(struct hlist_node *n, struct hlist_node *prev) n->next->pprev = &n->next; } -#define hlist_for_each_entry_rcu(pos, head, member) \ - hlist_for_each_entry(pos, head, member) +#define hlist_for_each_entry_rcu(pos, head, member) \ + for (pos = hlist_entry_safe (rcu_dereference_raw(hlist_first_rcu(head)),\ + typeof(*(pos)), member); \ + (pos); \ + pos = hlist_entry_safe(rcu_dereference_raw(hlist_next_rcu( \ + &(pos)->member)), typeof(*(pos)), member)) static inline void hlist_del_rcu(struct hlist_node *n) diff --git a/sys/conf/NOTES b/sys/conf/NOTES index 30ae142ba29b3..dfa5ff68d802d 100644 --- a/sys/conf/NOTES +++ b/sys/conf/NOTES @@ -1170,9 +1170,6 @@ options NFS_DEBUG # Enable NFS Debugging # options EXT2FS -# Cryptographically secure random number generator; /dev/random -device random - # The system memory devices; /dev/mem, /dev/kmem device mem @@ -2424,14 +2421,19 @@ device iicoc # OpenCores I2C controller support # I2C peripheral devices # +device ad7418 # Analog Devices temp and voltage sensor device ds1307 # Dallas DS1307 RTC and compatible device ds13rtc # All Dallas/Maxim ds13xx chips device ds1672 # Dallas DS1672 RTC device ds3231 # Dallas DS3231 RTC + temperature device icee # AT24Cxxx and compatible EEPROMs +device isl12xx # Intersil ISL12xx RTC device lm75 # LM75 compatible temperature sensor device nxprtc # NXP RTCs: PCA/PFC212x PCA/PCF85xx +device rtc8583 # Epson RTC-8583 device s35390a # Seiko Instruments S-35390A RTC +device sy8106a # Silergy Corp. SY8106A buck regulator +device syr827 # Silergy Corp. DC/DC regulator # Parallel-Port Bus # @@ -2479,6 +2481,22 @@ device pps device lpbb device pcfclock +# General Purpose I/O pins +device gpio # gpio interfaces and bus support +device gpiobacklight # sysctl control of gpio-based backlight +device gpioiic # i2c via gpio bitbang +device gpiokeys # kbd(4) glue for gpio-based key input +device gpioled # led(4) gpio glue +device gpiopower # event handler for gpio-based powerdown +device gpiopps # Pulse per second input from gpio pin +device gpioregulator # extres/regulator glue for gpio pin +device gpiospi # SPI via gpio bitbang +device gpioths # 1-wire temp/humidity sensor on gpio pin + +# Pulse width modulation +device pwmbus # pwm interface and bus support +device pwmc # userland control access to pwm outputs + # # Etherswitch framework and drivers # diff --git a/sys/conf/files b/sys/conf/files index dd67e0ec7a684..c62a9e285e47e 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -686,14 +686,14 @@ crypto/des/des_ecb.c optional crypto | ipsec | ipsec_support | netsmb crypto/des/des_setkey.c optional crypto | ipsec | ipsec_support | netsmb crypto/rc4/rc4.c optional netgraph_mppc_encryption | kgssapi crypto/rijndael/rijndael-alg-fst.c optional crypto | ekcd | geom_bde | \ - ipsec | ipsec_support | random !random_loadable | wlan_ccmp -crypto/rijndael/rijndael-api-fst.c optional ekcd | geom_bde | random !random_loadable + ipsec | ipsec_support | !random_loadable | wlan_ccmp +crypto/rijndael/rijndael-api-fst.c optional ekcd | geom_bde | !random_loadable crypto/rijndael/rijndael-api.c optional crypto | ipsec | ipsec_support | \ wlan_ccmp crypto/sha1.c optional carp | crypto | ether | ipsec | \ ipsec_support | netgraph_mppc_encryption | sctp crypto/sha2/sha256c.c optional crypto | ekcd | geom_bde | ipsec | \ - ipsec_support | random !random_loadable | sctp | zfs + ipsec_support | !random_loadable | sctp | zfs crypto/sha2/sha512c.c optional crypto | geom_bde | ipsec | \ ipsec_support | zfs crypto/skein/skein.c optional crypto | zfs @@ -1708,7 +1708,7 @@ dev/fdt/fdt_clock_if.m optional fdt fdt_clock dev/fdt/fdt_common.c optional fdt dev/fdt/fdt_pinctrl.c optional fdt fdt_pinctrl dev/fdt/fdt_pinctrl_if.m optional fdt fdt_pinctrl -dev/fdt/fdt_slicer.c optional fdt cfi | fdt nand | fdt mx25l | fdt n25q | fdt at45d +dev/fdt/fdt_slicer.c optional fdt cfi | fdt mx25l | fdt n25q | fdt at45d dev/fdt/fdt_static_dtb.S optional fdt fdt_dtb_static \ dependency "${FDT_DTS_FILE:T:R}.dtb" dev/fdt/simplebus.c optional fdt @@ -1751,7 +1751,7 @@ dev/gpio/gpiospi.c optional gpiospi dev/gpio/gpioths.c optional gpioths dev/gpio/gpio_if.m optional gpio dev/gpio/gpiobus_if.m optional gpio -dev/gpio/gpiopps.c optional gpiopps +dev/gpio/gpiopps.c optional gpiopps fdt dev/gpio/ofw_gpiobus.c optional fdt gpio dev/hifn/hifn7751.c optional hifn dev/hme/if_hme.c optional hme @@ -1775,7 +1775,7 @@ dev/iicbus/ds13rtc.c optional ds13rtc | ds133x | ds1374 dev/iicbus/ds1672.c optional ds1672 dev/iicbus/ds3231.c optional ds3231 dev/iicbus/rtc8583.c optional rtc8583 -dev/iicbus/syr827.c optional ext_resources syr827 +dev/iicbus/syr827.c optional syr827 ext_resources fdt dev/iicbus/icee.c optional icee dev/iicbus/if_ic.c optional ic dev/iicbus/iic.c optional iic @@ -1792,7 +1792,9 @@ dev/iicbus/isl12xx.c optional isl12xx dev/iicbus/lm75.c optional lm75 dev/iicbus/nxprtc.c optional nxprtc | pcf8563 dev/iicbus/ofw_iicbus.c optional fdt iicbus +dev/iicbus/rtc8583.c optional rtc8583 dev/iicbus/s35390a.c optional s35390a +dev/iicbus/sy8106a.c optional sy8106a ext_resources fdt dev/iir/iir.c optional iir dev/iir/iir_ctrl.c optional iir dev/iir/iir_pci.c optional iir pci @@ -2455,21 +2457,6 @@ dev/mxge/mxge_ethp_z8e.c optional mxge pci dev/mxge/mxge_rss_eth_z8e.c optional mxge pci dev/mxge/mxge_rss_ethp_z8e.c optional mxge pci dev/my/if_my.c optional my -dev/nand/nand.c optional nand -dev/nand/nand_bbt.c optional nand -dev/nand/nand_cdev.c optional nand -dev/nand/nand_generic.c optional nand -dev/nand/nand_geom.c optional nand -dev/nand/nand_id.c optional nand -dev/nand/nandbus.c optional nand -dev/nand/nandbus_if.m optional nand -dev/nand/nand_if.m optional nand -dev/nand/nandsim.c optional nandsim nand -dev/nand/nandsim_chip.c optional nandsim nand -dev/nand/nandsim_ctrl.c optional nandsim nand -dev/nand/nandsim_log.c optional nandsim nand -dev/nand/nandsim_swap.c optional nandsim nand -dev/nand/nfc_if.m optional nand dev/netmap/if_ptnet.c optional netmap inet dev/netmap/netmap.c optional netmap dev/netmap/netmap_bdg.c optional netmap @@ -2766,11 +2753,11 @@ rt2860.fw optional rt2860fw | ralfw \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "rt2860.fw" -dev/random/random_infra.c optional random -dev/random/random_harvestq.c optional random -dev/random/randomdev.c optional random !random_loadable -dev/random/fortuna.c optional random !random_loadable -dev/random/hash.c optional random !random_loadable +dev/random/random_infra.c standard +dev/random/random_harvestq.c standard +dev/random/randomdev.c optional !random_loadable +dev/random/fortuna.c optional !random_loadable +dev/random/hash.c optional !random_loadable dev/rc/rc.c optional rc dev/rccgpio/rccgpio.c optional rccgpio gpio dev/re/if_re.c optional re @@ -3497,20 +3484,6 @@ fs/msdosfs/msdosfs_iconv.c optional msdosfs_iconv fs/msdosfs/msdosfs_lookup.c optional msdosfs fs/msdosfs/msdosfs_vfsops.c optional msdosfs fs/msdosfs/msdosfs_vnops.c optional msdosfs -fs/nandfs/bmap.c optional nandfs -fs/nandfs/nandfs_alloc.c optional nandfs -fs/nandfs/nandfs_bmap.c optional nandfs -fs/nandfs/nandfs_buffer.c optional nandfs -fs/nandfs/nandfs_cleaner.c optional nandfs -fs/nandfs/nandfs_cpfile.c optional nandfs -fs/nandfs/nandfs_dat.c optional nandfs -fs/nandfs/nandfs_dir.c optional nandfs -fs/nandfs/nandfs_ifile.c optional nandfs -fs/nandfs/nandfs_segment.c optional nandfs -fs/nandfs/nandfs_subr.c optional nandfs -fs/nandfs/nandfs_sufile.c optional nandfs -fs/nandfs/nandfs_vfsops.c optional nandfs -fs/nandfs/nandfs_vnops.c optional nandfs fs/nfs/nfs_commonkrpc.c optional nfscl | nfsd fs/nfs/nfs_commonsubs.c optional nfscl | nfsd fs/nfs/nfs_commonport.c optional nfscl | nfsd @@ -3598,7 +3571,7 @@ geom/geom_disk.c standard geom/geom_dump.c standard geom/geom_event.c standard geom/geom_fox.c optional geom_fox -geom/geom_flashmap.c optional fdt cfi | fdt nand | fdt mx25l | mmcsd | fdt n25q | fdt at45d +geom/geom_flashmap.c optional fdt cfi | fdt mx25l | mmcsd | fdt n25q | fdt at45d geom/geom_io.c standard geom/geom_kern.c standard geom/geom_map.c optional geom_map diff --git a/sys/conf/files.amd64 b/sys/conf/files.amd64 index 1d399122c50c2..81cd730a5c343 100644 --- a/sys/conf/files.amd64 +++ b/sys/conf/files.amd64 @@ -389,6 +389,9 @@ dev/qlxgbe/ql_isr.c optional qlxgbe pci dev/qlxgbe/ql_misc.c optional qlxgbe pci dev/qlxgbe/ql_os.c optional qlxgbe pci dev/qlxgbe/ql_reset.c optional qlxgbe pci +dev/qlxgbe/ql_fw.c optional qlxgbe pci +dev/qlxgbe/ql_boot.c optional qlxgbe pci +dev/qlxgbe/ql_minidump.c optional qlxgbe pci dev/qlnx/qlnxe/ecore_cxt.c optional qlnxe pci \ compile-with "${LINUXKPI_C}" dev/qlnx/qlnxe/ecore_dbg_fw_funcs.c optional qlnxe pci \ diff --git a/sys/conf/files.arm b/sys/conf/files.arm index 6134b20e11772..8d890144b277b 100644 --- a/sys/conf/files.arm +++ b/sys/conf/files.arm @@ -166,6 +166,12 @@ cloudabi32_vdso_blob.o optional compat_cloudabi32 \ clean "cloudabi32_vdso_blob.o" # +# +ukbdmap.h optional ukbd_dflt_keymap \ + compile-with "kbdcontrol -P ${S:S/sys$/share/}/vt/keymaps -P ${S:S/sys$/share/}/syscons/keymaps -L ${UKBD_DFLT_KEYMAP} | sed -e 's/^static keymap_t.* = /static keymap_t key_map = /' -e 's/^static accentmap_t.* = /static accentmap_t accent_map = /' > ukbdmap.h" \ + no-obj no-implicit-rule before-depend \ + clean "ukbdmap.h" + # Annapurna support arm/annapurna/alpine/alpine_ccu.c optional al_ccu fdt arm/annapurna/alpine/alpine_nb_service.c optional al_nb_service fdt diff --git a/sys/conf/files.arm64 b/sys/conf/files.arm64 index f8d9beba599da..b8c0234252935 100644 --- a/sys/conf/files.arm64 +++ b/sys/conf/files.arm64 @@ -87,7 +87,7 @@ arm/broadcom/bcm2835/bcm2835_ft5406.c optional evdev bcm2835_ft5406 soc_brcm_bc arm/broadcom/bcm2835/bcm2835_gpio.c optional gpio soc_brcm_bcm2837 fdt arm/broadcom/bcm2835/bcm2835_intr.c optional soc_brcm_bcm2837 fdt arm/broadcom/bcm2835/bcm2835_mbox.c optional soc_brcm_bcm2837 fdt -arm/broadcom/bcm2835/bcm2835_rng.c optional random !random_loadable soc_brcm_bcm2837 fdt +arm/broadcom/bcm2835/bcm2835_rng.c optional !random_loadable soc_brcm_bcm2837 fdt arm/broadcom/bcm2835/bcm2835_sdhci.c optional sdhci soc_brcm_bcm2837 fdt arm/broadcom/bcm2835/bcm2835_sdhost.c optional sdhci soc_brcm_bcm2837 fdt arm/broadcom/bcm2835/bcm2835_spi.c optional bcm2835_spi soc_brcm_bcm2837 fdt diff --git a/sys/conf/files.powerpc b/sys/conf/files.powerpc index cbda69a0d7cf0..5383595b1411c 100644 --- a/sys/conf/files.powerpc +++ b/sys/conf/files.powerpc @@ -43,8 +43,6 @@ dev/iicbus/max6690.c optional max6690 powermac dev/iicbus/ofw_iicbus.c optional iicbus aim dev/ipmi/ipmi.c optional ipmi dev/ipmi/ipmi_opal.c optional powernv ipmi -dev/nand/nfc_fsl.c optional nand mpc85xx -dev/nand/nfc_rb.c optional nand mpc85xx # Most ofw stuff below is brought in by conf/files for options FDT, but # we always want it, even on non-FDT platforms. dev/fdt/simplebus.c standard @@ -62,7 +60,7 @@ dev/ofw/ofw_standard.c optional aim powerpc dev/ofw/ofw_subr.c standard dev/powermac_nvram/powermac_nvram.c optional powermac_nvram powermac dev/quicc/quicc_bfe_fdt.c optional quicc mpc85xx -dev/random/darn.c optional powerpc64 random !random_loadable +dev/random/darn.c optional powerpc64 !random_loadable dev/scc/scc_bfe_macio.c optional scc powermac dev/sdhci/fsl_sdhci.c optional mpc85xx sdhci dev/sec/sec.c optional sec mpc85xx diff --git a/sys/conf/kern.opts.mk b/sys/conf/kern.opts.mk index 33aa0bcba9892..58f125efbd061 100644 --- a/sys/conf/kern.opts.mk +++ b/sys/conf/kern.opts.mk @@ -52,7 +52,6 @@ __DEFAULT_YES_OPTIONS = \ __DEFAULT_NO_OPTIONS = \ EXTRA_TCP_STACKS \ KERNEL_RETPOLINE \ - NAND \ OFED \ RATELIMIT diff --git a/sys/conf/makeLINT.mk b/sys/conf/makeLINT.mk index 52dddf5a97d74..d3a414c14ff6f 100644 --- a/sys/conf/makeLINT.mk +++ b/sys/conf/makeLINT.mk @@ -47,6 +47,11 @@ LINT: ${NOTES} ${MAKELINT_SED} echo "nodevice txp" >> ${.TARGET}-NOIP echo "nodevice netmap" >> ${.TARGET}-NOIP .endif +.if ${TARGET} == "arm" + cat ${.TARGET} ${.CURDIR}/NOTES.armv5 > ${.TARGET}-V5 + cat ${.TARGET} ${.CURDIR}/NOTES.armv7 > ${.TARGET}-V7 + rm ${.TARGET} +.endif .if ${TARGET} == "mips" echo "machine ${TARGET} ${TARGET_ARCH}" >> ${.TARGET} .endif diff --git a/sys/conf/options b/sys/conf/options index df394936b9d41..c4c3bb7eed67d 100644 --- a/sys/conf/options +++ b/sys/conf/options @@ -256,7 +256,6 @@ FDESCFS opt_dontuse.h FFS opt_dontuse.h FUSEFS opt_dontuse.h MSDOSFS opt_dontuse.h -NANDFS opt_dontuse.h NULLFS opt_dontuse.h PROCFS opt_dontuse.h PSEUDOFS opt_dontuse.h @@ -734,7 +733,6 @@ DEV_PCI opt_pci.h DEV_PF opt_pf.h DEV_PFLOG opt_pf.h DEV_PFSYNC opt_pf.h -DEV_RANDOM opt_global.h DEV_SPLASH opt_splash.h DEV_VLAN opt_vlan.h @@ -863,6 +861,12 @@ AH_INTERRUPT_DEBUGGING opt_ah.h # XXX do not use this for AR9130 AH_AR5416_INTERRUPT_MITIGATION opt_ah.h +# options for the Altera mSGDMA driver (altera_msgdma) +ALTERA_MSGDMA_DESC_STD opt_altera_msgdma.h +ALTERA_MSGDMA_DESC_EXT opt_altera_msgdma.h +ALTERA_MSGDMA_DESC_PF_STD opt_altera_msgdma.h +ALTERA_MSGDMA_DESC_PF_EXT opt_altera_msgdma.h + # options for the Broadcom BCM43xx driver (bwi) BWI_DEBUG opt_bwi.h BWI_DEBUG_VERBOSE opt_bwi.h diff --git a/sys/contrib/ipfilter/netinet/fil.c b/sys/contrib/ipfilter/netinet/fil.c index a0d008dbd2d72..1d142165c3411 100644 --- a/sys/contrib/ipfilter/netinet/fil.c +++ b/sys/contrib/ipfilter/netinet/fil.c @@ -1723,29 +1723,31 @@ ipf_pr_ipv4hdr(fin) * calculate the byte offset that it represents. */ off &= IP_MF|IP_OFFMASK; + if (off == 1 && p == IPPROTO_TCP) { + fin->fin_flx |= FI_SHORT; /* RFC 3128 */ + DT1(ipf_fi_tcp_frag_off_1, fr_info_t *, fin); + } if (off != 0) { int morefrag = off & IP_MF; fi->fi_flx |= FI_FRAG; off &= IP_OFFMASK; - if (off != 0) { - fin->fin_flx |= FI_FRAGBODY; - off <<= 3; - if ((off + fin->fin_dlen > 65535) || - (fin->fin_dlen == 0) || - ((morefrag != 0) && ((fin->fin_dlen & 7) != 0))) { - /* - * The length of the packet, starting at its - * offset cannot exceed 65535 (0xffff) as the - * length of an IP packet is only 16 bits. - * - * Any fragment that isn't the last fragment - * must have a length greater than 0 and it - * must be an even multiple of 8. - */ - fi->fi_flx |= FI_BAD; - DT1(ipf_fi_bad_fragbody_gt_65535, fr_info_t *, fin); - } + fin->fin_flx |= FI_FRAGBODY; + off <<= 3; + if ((off + fin->fin_dlen > 65535) || + (fin->fin_dlen == 0) || + ((morefrag != 0) && ((fin->fin_dlen & 7) != 0))) { + /* + * The length of the packet, starting at its + * offset cannot exceed 65535 (0xffff) as the + * length of an IP packet is only 16 bits. + * + * Any fragment that isn't the last fragment + * must have a length greater than 0 and it + * must be an even multiple of 8. + */ + fi->fi_flx |= FI_BAD; + DT1(ipf_fi_bad_fragbody_gt_65535, fr_info_t *, fin); } } fin->fin_off = off; @@ -7472,10 +7474,6 @@ ipf_resolvedest(softc, base, fdp, v) } fdp->fd_ptr = ifp; - if ((ifp != NULL) && (ifp != (void *)-1)) { - fdp->fd_local = ipf_deliverlocal(softc, v, ifp, &fdp->fd_ip6); - } - return errval; } diff --git a/sys/contrib/ipfilter/netinet/ip_compat.h b/sys/contrib/ipfilter/netinet/ip_compat.h index 777495b39aed4..75f4d7c116ce4 100644 --- a/sys/contrib/ipfilter/netinet/ip_compat.h +++ b/sys/contrib/ipfilter/netinet/ip_compat.h @@ -829,190 +829,9 @@ typedef struct tcpiphdr tcpiphdr_t; #undef IPOPT_AH #define IPOPT_AH 256+IPPROTO_AH -#ifndef TCPOPT_EOL -# define TCPOPT_EOL 0 -#endif -#ifndef TCPOPT_NOP -# define TCPOPT_NOP 1 -#endif -#ifndef TCPOPT_MAXSEG -# define TCPOPT_MAXSEG 2 -#endif -#ifndef TCPOLEN_MAXSEG -# define TCPOLEN_MAXSEG 4 -#endif -#ifndef TCPOPT_WINDOW -# define TCPOPT_WINDOW 3 -#endif -#ifndef TCPOLEN_WINDOW -# define TCPOLEN_WINDOW 3 -#endif -#ifndef TCPOPT_SACK_PERMITTED -# define TCPOPT_SACK_PERMITTED 4 -#endif -#ifndef TCPOLEN_SACK_PERMITTED -# define TCPOLEN_SACK_PERMITTED 2 -#endif -#ifndef TCPOPT_SACK -# define TCPOPT_SACK 5 -#endif -#ifndef TCPOPT_TIMESTAMP -# define TCPOPT_TIMESTAMP 8 -#endif +# define ICMP_UNREACH_ADMIN_PROHIBIT ICMP_UNREACH_FILTER_PROHIB +# define ICMP_UNREACH_FILTER ICMP_UNREACH_FILTER_PROHIB -#ifndef ICMP_MINLEN -# define ICMP_MINLEN 8 -#endif -#ifndef ICMP_ECHOREPLY -# define ICMP_ECHOREPLY 0 -#endif -#ifndef ICMP_UNREACH -# define ICMP_UNREACH 3 -#endif -#ifndef ICMP_UNREACH_NET -# define ICMP_UNREACH_NET 0 -#endif -#ifndef ICMP_UNREACH_HOST -# define ICMP_UNREACH_HOST 1 -#endif -#ifndef ICMP_UNREACH_PROTOCOL -# define ICMP_UNREACH_PROTOCOL 2 -#endif -#ifndef ICMP_UNREACH_PORT -# define ICMP_UNREACH_PORT 3 -#endif -#ifndef ICMP_UNREACH_NEEDFRAG -# define ICMP_UNREACH_NEEDFRAG 4 -#endif -#ifndef ICMP_UNREACH_SRCFAIL -# define ICMP_UNREACH_SRCFAIL 5 -#endif -#ifndef ICMP_UNREACH_NET_UNKNOWN -# define ICMP_UNREACH_NET_UNKNOWN 6 -#endif -#ifndef ICMP_UNREACH_HOST_UNKNOWN -# define ICMP_UNREACH_HOST_UNKNOWN 7 -#endif -#ifndef ICMP_UNREACH_ISOLATED -# define ICMP_UNREACH_ISOLATED 8 -#endif -#ifndef ICMP_UNREACH_NET_PROHIB -# define ICMP_UNREACH_NET_PROHIB 9 -#endif -#ifndef ICMP_UNREACH_HOST_PROHIB -# define ICMP_UNREACH_HOST_PROHIB 10 -#endif -#ifndef ICMP_UNREACH_TOSNET -# define ICMP_UNREACH_TOSNET 11 -#endif -#ifndef ICMP_UNREACH_TOSHOST -# define ICMP_UNREACH_TOSHOST 12 -#endif -#ifndef ICMP_UNREACH_ADMIN_PROHIBIT -# define ICMP_UNREACH_ADMIN_PROHIBIT 13 -#endif -#ifndef ICMP_UNREACH_FILTER -# define ICMP_UNREACH_FILTER 13 -#endif -#ifndef ICMP_UNREACH_HOST_PRECEDENCE -# define ICMP_UNREACH_HOST_PRECEDENCE 14 -#endif -#ifndef ICMP_UNREACH_PRECEDENCE_CUTOFF -# define ICMP_UNREACH_PRECEDENCE_CUTOFF 15 -#endif -#ifndef ICMP_SOURCEQUENCH -# define ICMP_SOURCEQUENCH 4 -#endif -#ifndef ICMP_REDIRECT_NET -# define ICMP_REDIRECT_NET 0 -#endif -#ifndef ICMP_REDIRECT_HOST -# define ICMP_REDIRECT_HOST 1 -#endif -#ifndef ICMP_REDIRECT_TOSNET -# define ICMP_REDIRECT_TOSNET 2 -#endif -#ifndef ICMP_REDIRECT_TOSHOST -# define ICMP_REDIRECT_TOSHOST 3 -#endif -#ifndef ICMP_ALTHOSTADDR -# define ICMP_ALTHOSTADDR 6 -#endif -#ifndef ICMP_TIMXCEED -# define ICMP_TIMXCEED 11 -#endif -#ifndef ICMP_TIMXCEED_INTRANS -# define ICMP_TIMXCEED_INTRANS 0 -#endif -#ifndef ICMP_TIMXCEED_REASS -# define ICMP_TIMXCEED_REASS 1 -#endif -#ifndef ICMP_PARAMPROB -# define ICMP_PARAMPROB 12 -#endif -#ifndef ICMP_PARAMPROB_ERRATPTR -# define ICMP_PARAMPROB_ERRATPTR 0 -#endif -#ifndef ICMP_PARAMPROB_OPTABSENT -# define ICMP_PARAMPROB_OPTABSENT 1 -#endif -#ifndef ICMP_PARAMPROB_LENGTH -# define ICMP_PARAMPROB_LENGTH 2 -#endif -#ifndef ICMP_TSTAMP -# define ICMP_TSTAMP 13 -#endif -#ifndef ICMP_TSTAMPREPLY -# define ICMP_TSTAMPREPLY 14 -#endif -#ifndef ICMP_IREQ -# define ICMP_IREQ 15 -#endif -#ifndef ICMP_IREQREPLY -# define ICMP_IREQREPLY 16 -#endif -#ifndef ICMP_MASKREQ -# define ICMP_MASKREQ 17 -#endif -#ifndef ICMP_MASKREPLY -# define ICMP_MASKREPLY 18 -#endif -#ifndef ICMP_TRACEROUTE -# define ICMP_TRACEROUTE 30 -#endif -#ifndef ICMP_DATACONVERR -# define ICMP_DATACONVERR 31 -#endif -#ifndef ICMP_MOBILE_REDIRECT -# define ICMP_MOBILE_REDIRECT 32 -#endif -#ifndef ICMP_IPV6_WHEREAREYOU -# define ICMP_IPV6_WHEREAREYOU 33 -#endif -#ifndef ICMP_IPV6_IAMHERE -# define ICMP_IPV6_IAMHERE 34 -#endif -#ifndef ICMP_MOBILE_REGREQUEST -# define ICMP_MOBILE_REGREQUEST 35 -#endif -#ifndef ICMP_MOBILE_REGREPLY -# define ICMP_MOBILE_REGREPLY 36 -#endif -#ifndef ICMP_SKIP -# define ICMP_SKIP 39 -#endif -#ifndef ICMP_PHOTURIS -# define ICMP_PHOTURIS 40 -#endif -#ifndef ICMP_PHOTURIS_UNKNOWN_INDEX -# define ICMP_PHOTURIS_UNKNOWN_INDEX 1 -#endif -#ifndef ICMP_PHOTURIS_AUTH_FAILED -# define ICMP_PHOTURIS_AUTH_FAILED 2 -#endif -#ifndef ICMP_PHOTURIS_DECRYPT_FAILED -# define ICMP_PHOTURIS_DECRYPT_FAILED 3 -#endif #ifndef IPVERSION # define IPVERSION 4 #endif diff --git a/sys/contrib/ipfilter/netinet/ip_fil.h b/sys/contrib/ipfilter/netinet/ip_fil.h index f3185c6458d7f..032cf0dea853f 100644 --- a/sys/contrib/ipfilter/netinet/ip_fil.h +++ b/sys/contrib/ipfilter/netinet/ip_fil.h @@ -560,7 +560,6 @@ typedef struct frdest { addrfamily_t fd_addr; fr_dtypes_t fd_type; int fd_name; - int fd_local; } frdest_t; #define fd_ip6 fd_addr.adf_addr diff --git a/sys/ddb/db_ps.c b/sys/ddb/db_ps.c index 72bf0edd91618..82e50e0ca85d2 100644 --- a/sys/ddb/db_ps.c +++ b/sys/ddb/db_ps.c @@ -481,7 +481,7 @@ DB_SHOW_COMMAND(proc, db_show_proc) dump_args(p); db_printf("\n"); } - db_printf(" repear: %p reapsubtree: %d\n", + db_printf(" reaper: %p reapsubtree: %d\n", p->p_reaper, p->p_reapsubtree); db_printf(" sigparent: %d\n", p->p_sigparent); db_printf(" vmspace: %p\n", p->p_vmspace); diff --git a/sys/dev/ahci/ahci.c b/sys/dev/ahci/ahci.c index 4a17fb535498f..435661107e955 100644 --- a/sys/dev/ahci/ahci.c +++ b/sys/dev/ahci/ahci.c @@ -186,6 +186,7 @@ ahci_attach(device_t dev) ctlr->ccc = 0; resource_int_value(device_get_name(dev), device_get_unit(dev), "ccc", &ctlr->ccc); + mtx_init(&ctlr->ch_mtx, "AHCI channels lock", NULL, MTX_DEF); /* Setup our own memory management for channels. */ ctlr->sc_iomem.rm_start = rman_get_start(ctlr->r_mem); @@ -379,6 +380,7 @@ ahci_detach(device_t dev) /* Free memory. */ rman_fini(&ctlr->sc_iomem); ahci_free_mem(dev); + mtx_destroy(&ctlr->ch_mtx); return (0); } @@ -666,6 +668,50 @@ ahci_get_dma_tag(device_t dev, device_t child) return (ctlr->dma_tag); } +void +ahci_attached(device_t dev, struct ahci_channel *ch) +{ + struct ahci_controller *ctlr = device_get_softc(dev); + + mtx_lock(&ctlr->ch_mtx); + ctlr->ch[ch->unit] = ch; + mtx_unlock(&ctlr->ch_mtx); +} + +void +ahci_detached(device_t dev, struct ahci_channel *ch) +{ + struct ahci_controller *ctlr = device_get_softc(dev); + + mtx_lock(&ctlr->ch_mtx); + mtx_lock(&ch->mtx); + ctlr->ch[ch->unit] = NULL; + mtx_unlock(&ch->mtx); + mtx_unlock(&ctlr->ch_mtx); +} + +struct ahci_channel * +ahci_getch(device_t dev, int n) +{ + struct ahci_controller *ctlr = device_get_softc(dev); + struct ahci_channel *ch; + + KASSERT(n >= 0 && n < AHCI_MAX_PORTS, ("Bad channel number %d", n)); + mtx_lock(&ctlr->ch_mtx); + ch = ctlr->ch[n]; + if (ch != NULL) + mtx_lock(&ch->mtx); + mtx_unlock(&ctlr->ch_mtx); + return (ch); +} + +void +ahci_putch(struct ahci_channel *ch) +{ + + mtx_unlock(&ch->mtx); +} + static int ahci_ch_probe(device_t dev) { @@ -824,6 +870,7 @@ ahci_ch_attach(device_t dev) ahci_ch_pm, ch); } mtx_unlock(&ch->mtx); + ahci_attached(device_get_parent(dev), ch); ctx = device_get_sysctl_ctx(dev); tree = device_get_sysctl_tree(dev); SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "disable_phy", @@ -849,6 +896,7 @@ ahci_ch_detach(device_t dev) { struct ahci_channel *ch = device_get_softc(dev); + ahci_detached(device_get_parent(dev), ch); mtx_lock(&ch->mtx); xpt_async(AC_LOST_DEVICE, ch->path, NULL); /* Forget about reset. */ diff --git a/sys/dev/ahci/ahci.h b/sys/dev/ahci/ahci.h index fc53d346f17fc..27b3970dadfc1 100644 --- a/sys/dev/ahci/ahci.h +++ b/sys/dev/ahci/ahci.h @@ -524,6 +524,8 @@ struct ahci_controller { } interrupt[AHCI_MAX_PORTS]; void (*ch_start)(struct ahci_channel *); int dma_coherent; /* DMA is cache-coherent */ + struct mtx ch_mtx; /* Lock for attached channels */ + struct ahci_channel *ch[AHCI_MAX_PORTS]; /* Attached channels */ }; enum ahci_err_type { @@ -654,5 +656,11 @@ int ahci_ctlr_reset(device_t dev); int ahci_ctlr_setup(device_t dev); void ahci_free_mem(device_t dev); +/* Functions to allow AHCI EM to access other channels. */ +void ahci_attached(device_t dev, struct ahci_channel *ch); +void ahci_detached(device_t dev, struct ahci_channel *ch); +struct ahci_channel * ahci_getch(device_t dev, int n); +void ahci_putch(struct ahci_channel *ch); + extern devclass_t ahci_devclass; diff --git a/sys/dev/ahci/ahciem.c b/sys/dev/ahci/ahciem.c index 9bb4d97177630..a6f22fac56393 100644 --- a/sys/dev/ahci/ahciem.c +++ b/sys/dev/ahci/ahciem.c @@ -294,14 +294,14 @@ ahci_em_setleds(device_t dev, int c) enc = device_get_softc(dev); val = 0; - if (enc->status[c][2] & 0x80) /* Activity */ + if (enc->status[c][2] & SESCTL_RQSACT) /* Activity */ val |= (1 << 0); - if (enc->status[c][2] & SESCTL_RQSID) /* Identification */ + if (enc->status[c][1] & SESCTL_RQSRR) /* Rebuild */ + val |= (1 << 6) | (1 << 3); + else if (enc->status[c][2] & SESCTL_RQSID) /* Identification */ val |= (1 << 3); else if (enc->status[c][3] & SESCTL_RQSFLT) /* Fault */ val |= (1 << 6); - else if (enc->status[c][1] & 0x02) /* Rebuild */ - val |= (1 << 6) | (1 << 3); timeout = 10000; while (ATA_INL(enc->r_memc, 0) & (AHCI_EM_TM | AHCI_EM_RST) && @@ -366,9 +366,12 @@ static void ahci_em_emulate_ses_on_led(device_t dev, union ccb *ccb) { struct ahci_enclosure *enc; + struct ahci_channel *ch; struct ses_status_page *page; struct ses_status_array_dev_slot *ads, *ads0; struct ses_elm_desc_hdr *elmd; + struct ses_elm_addlstatus_eip_hdr *elma; + struct ses_elm_ata_hdr *elmb; uint8_t *buf; int i; @@ -391,7 +394,7 @@ ahci_em_emulate_ses_on_led(device_t dev, union ccb *ccb) strncpy(&buf[3], device_get_nameunit(dev), 7); strncpy(&buf[10], "AHCI ", SID_VENDOR_SIZE); strncpy(&buf[18], "SGPIO Enclosure ", SID_PRODUCT_SIZE); - strncpy(&buf[34], "1.00", SID_REVISION_SIZE); + strncpy(&buf[34], "2.00", SID_REVISION_SIZE); strncpy(&buf[39], "0001", 4); strncpy(&buf[43], "S-E-S ", 6); strncpy(&buf[49], "2.00", 4); @@ -403,14 +406,15 @@ ahci_em_emulate_ses_on_led(device_t dev, union ccb *ccb) page = (struct ses_status_page *)buf; if (ccb->ataio.cmd.lba_low == 0x02 && ccb->ataio.cmd.features == 0x00 && - ccb->ataio.cmd.sector_count >= 2) { + ccb->ataio.cmd.sector_count >= 3) { bzero(buf, ccb->ataio.dxfer_len); page->hdr.page_code = 0; - scsi_ulto2b(4, page->hdr.length); - buf[4] = 0; - buf[5] = 1; - buf[6] = 2; - buf[7] = 7; + scsi_ulto2b(5, page->hdr.length); + buf[4] = 0x00; + buf[5] = 0x01; + buf[6] = 0x02; + buf[7] = 0x07; + buf[8] = 0x0a; ccb->ccb_h.status = CAM_REQ_CMP; goto out; } @@ -418,26 +422,30 @@ ahci_em_emulate_ses_on_led(device_t dev, union ccb *ccb) /* SEMB RECEIVE DIAGNOSTIC RESULT (1) */ if (ccb->ataio.cmd.lba_low == 0x02 && ccb->ataio.cmd.features == 0x01 && - ccb->ataio.cmd.sector_count >= 13) { + ccb->ataio.cmd.sector_count >= 16) { struct ses_enc_desc *ed; struct ses_elm_type_desc *td; bzero(buf, ccb->ataio.dxfer_len); page->hdr.page_code = 0x01; - scsi_ulto2b(4 + 4 + 36 + 4, page->hdr.length); + scsi_ulto2b(4 + sizeof(*ed) + sizeof(*td) + 11, + page->hdr.length); ed = (struct ses_enc_desc *)&buf[8]; ed->byte0 = 0x11; ed->subenc_id = 0; ed->num_types = 1; ed->length = 36; + ed->logical_id[0] = 0x30; /* NAA Locally Assigned. */ + strncpy(&ed->logical_id[1], device_get_nameunit(dev), 7); strncpy(ed->vendor_id, "AHCI ", SID_VENDOR_SIZE); strncpy(ed->product_id, "SGPIO Enclosure ", SID_PRODUCT_SIZE); - strncpy(ed->product_rev, " ", SID_REVISION_SIZE); + strncpy(ed->product_rev, "2.00", SID_REVISION_SIZE); td = (struct ses_elm_type_desc *)ses_enc_desc_next(ed); td->etype_elm_type = 0x17; td->etype_maxelt = enc->channels; td->etype_subenc = 0; - td->etype_txt_len = 0; + td->etype_txt_len = 11; + snprintf((char *)(td + 1), 12, "Drive Slots"); ccb->ccb_h.status = CAM_REQ_CMP; goto out; } @@ -453,10 +461,22 @@ ahci_em_emulate_ses_on_led(device_t dev, union ccb *ccb) for (i = 0; i < enc->channels; i++) { ads = &page->elements[i + 1].array_dev_slot; memcpy(ads, enc->status[i], 4); - ads->common.bytes[0] |= - (enc->ichannels & (1 << i)) ? - SES_OBJSTAT_UNKNOWN : - SES_OBJSTAT_NOTINSTALLED; + ch = ahci_getch(device_get_parent(dev), i); + if (ch == NULL) { + ads->common.bytes[0] |= SES_OBJSTAT_UNKNOWN; + continue; + } + if (ch->pm_present) + ads->common.bytes[0] |= SES_OBJSTAT_UNKNOWN; + else if (ch->devices) + ads->common.bytes[0] |= SES_OBJSTAT_OK; + else if (ch->disablephy) + ads->common.bytes[0] |= SES_OBJSTAT_NOTAVAIL; + else + ads->common.bytes[0] |= SES_OBJSTAT_NOTINSTALLED; + if (ch->disablephy) + ads->common.bytes[3] |= SESCTL_DEVOFF; + ahci_putch(ch); } ccb->ccb_h.status = CAM_REQ_CMP; goto out; @@ -471,21 +491,21 @@ ahci_em_emulate_ses_on_led(device_t dev, union ccb *ccb) ads = &page->elements[i + 1].array_dev_slot; if (ads->common.bytes[0] & SESCTL_CSEL) { enc->status[i][0] = 0; - enc->status[i][1] = - ads->bytes[0] & 0x02; - enc->status[i][2] = - ads->bytes[1] & (0x80 | SESCTL_RQSID); - enc->status[i][3] = - ads->bytes[2] & SESCTL_RQSFLT; + enc->status[i][1] = ads->bytes[0] & + SESCTL_RQSRR; + enc->status[i][2] = ads->bytes[1] & + (SESCTL_RQSACT | SESCTL_RQSID); + enc->status[i][3] = ads->bytes[2] & + SESCTL_RQSFLT; ahci_em_setleds(dev, i); } else if (ads0->common.bytes[0] & SESCTL_CSEL) { enc->status[i][0] = 0; - enc->status[i][1] = - ads0->bytes[0] & 0x02; - enc->status[i][2] = - ads0->bytes[1] & (0x80 | SESCTL_RQSID); - enc->status[i][3] = - ads0->bytes[2] & SESCTL_RQSFLT; + enc->status[i][1] = ads0->bytes[0] & + SESCTL_RQSRR; + enc->status[i][2] = ads0->bytes[1] & + (SESCTL_RQSACT | SESCTL_RQSID); + enc->status[i][3] = ads0->bytes[2] & + SESCTL_RQSFLT; ahci_em_setleds(dev, i); } } @@ -496,15 +516,48 @@ ahci_em_emulate_ses_on_led(device_t dev, union ccb *ccb) /* SEMB RECEIVE DIAGNOSTIC RESULT (7) */ if (ccb->ataio.cmd.lba_low == 0x02 && ccb->ataio.cmd.features == 0x07 && - ccb->ataio.cmd.sector_count >= (3 + 3 * enc->channels)) { + ccb->ataio.cmd.sector_count >= (6 + 3 * enc->channels)) { bzero(buf, ccb->ataio.dxfer_len); page->hdr.page_code = 0x07; - scsi_ulto2b(4 + 4 + 12 * enc->channels, + scsi_ulto2b(4 + 15 + 11 * enc->channels, page->hdr.length); + elmd = (struct ses_elm_desc_hdr *)&buf[8]; + scsi_ulto2b(11, elmd->length); + snprintf((char *)(elmd + 1), 12, "Drive Slots"); + for (i = 0; i < enc->channels; i++) { + elmd = (struct ses_elm_desc_hdr *)&buf[8 + 15 + 11 * i]; + scsi_ulto2b(7, elmd->length); + snprintf((char *)(elmd + 1), 8, "Slot %02d", i); + } + ccb->ccb_h.status = CAM_REQ_CMP; + goto out; + } + + /* SEMB RECEIVE DIAGNOSTIC RESULT (a) */ + if (ccb->ataio.cmd.lba_low == 0x02 && + ccb->ataio.cmd.features == 0x0a && + ccb->ataio.cmd.sector_count >= (2 + 3 * enc->channels)) { + bzero(buf, ccb->ataio.dxfer_len); + page->hdr.page_code = 0x0a; + scsi_ulto2b(4 + (sizeof(*elma) + sizeof(*elmb)) * enc->channels, page->hdr.length); for (i = 0; i < enc->channels; i++) { - elmd = (struct ses_elm_desc_hdr *)&buf[8 + 4 + 12 * i]; - scsi_ulto2b(8, elmd->length); - snprintf((char *)(elmd + 1), 9, "SLOT %03d", i); + elma = (struct ses_elm_addlstatus_eip_hdr *)&buf[ + 8 + (sizeof(*elma) + sizeof(*elmb)) * i]; + elma->base.byte0 = 0x10 | SPSP_PROTO_ATA; + elma->base.length = 2 + sizeof(*elmb); + elma->byte2 = 0x01; + elma->element_index = 1 + i; + ch = ahci_getch(device_get_parent(dev), i); + if (ch == NULL) { + elma->base.byte0 |= 0x80; + continue; + } + if (ch->devices == 0 || ch->pm_present) + elma->base.byte0 |= 0x80; + elmb = (struct ses_elm_ata_hdr *)(elma + 1); + scsi_ulto4b(cam_sim_path(ch->sim), elmb->bus); + scsi_ulto4b(0, elmb->target); + ahci_putch(ch); } ccb->ccb_h.status = CAM_REQ_CMP; goto out; diff --git a/sys/dev/altera/msgdma/msgdma.c b/sys/dev/altera/msgdma/msgdma.c index c60c7ccfe3521..9acb313f91f59 100644 --- a/sys/dev/altera/msgdma/msgdma.c +++ b/sys/dev/altera/msgdma/msgdma.c @@ -60,6 +60,7 @@ __FBSDID("$FreeBSD$"); #include <dev/xdma/xdma.h> #include "xdma_if.h" +#include "opt_altera_msgdma.h" #include <dev/altera/msgdma/msgdma.h> @@ -470,8 +471,8 @@ msgdma_channel_submit_sg(device_t dev, struct xdma_channel *xchan, struct msgdma_channel *chan; struct msgdma_desc *desc; struct msgdma_softc *sc; - uint32_t src_addr_lo; - uint32_t dst_addr_lo; + bus_addr_t src_addr_lo; + bus_addr_t dst_addr_lo; uint32_t len; uint32_t tmp; int i; @@ -481,14 +482,18 @@ msgdma_channel_submit_sg(device_t dev, struct xdma_channel *xchan, chan = (struct msgdma_channel *)xchan->chan; for (i = 0; i < sg_n; i++) { - src_addr_lo = (uint32_t)sg[i].src_addr; - dst_addr_lo = (uint32_t)sg[i].dst_addr; + src_addr_lo = sg[i].src_addr; + dst_addr_lo = sg[i].dst_addr; len = (uint32_t)sg[i].len; dprintf("%s: src %x dst %x len %d\n", __func__, src_addr_lo, dst_addr_lo, len); desc = chan->descs[chan->idx_head]; +#if defined(ALTERA_MSGDMA_DESC_EXT) || defined(ALTERA_MSGDMA_DESC_PF_EXT) + desc->read_hi = htole32(src_addr_lo >> 32); + desc->write_hi = htole32(dst_addr_lo >> 32); +#endif desc->read_lo = htole32(src_addr_lo); desc->write_lo = htole32(dst_addr_lo); desc->length = htole32(len); diff --git a/sys/dev/altera/msgdma/msgdma.h b/sys/dev/altera/msgdma/msgdma.h index e10a233902a2d..498fb93d86bf5 100644 --- a/sys/dev/altera/msgdma/msgdma.h +++ b/sys/dev/altera/msgdma/msgdma.h @@ -30,6 +30,8 @@ * $FreeBSD$ */ +#include "opt_altera_msgdma.h" + /* Altera mSGDMA registers. */ #define DMA_STATUS 0x00 #define STATUS_RESETTING (1 << 6) @@ -75,15 +77,36 @@ #define WRITE4_DESC(_sc, _reg, _val) \ bus_space_write_4(_sc->bst_d, _sc->bsh_d, _reg, htole32(_val)) -/* Prefetcher-disabled descriptor format. */ -struct msgdma_desc_nonpf { - uint32_t src_addr; - uint32_t dst_addr; +#if defined(ALTERA_MSGDMA_DESC_STD) + +/* Standard descriptor format with prefetcher disabled. */ +struct msgdma_desc { + uint32_t read_lo; + uint32_t write_lo; uint32_t length; uint32_t control; }; -/* Prefetcher-enabled descriptor format. */ +#elif defined(ALTERA_MSGDMA_DESC_EXT) + +/* Extended descriptor format with prefetcher disabled. */ +struct msgdma_desc { + uint32_t read_lo; + uint32_t write_lo; + uint32_t length; + uint8_t write_burst; + uint8_t read_burst; + uint16_t seq_num; + uint16_t write_stride; + uint16_t read_stride; + uint32_t read_hi; + uint32_t write_hi; + uint32_t control; +}; + +#elif defined(ALTERA_MSGDMA_DESC_PF_STD) + +/* Standard descriptor format with prefetcher enabled. */ struct msgdma_desc { uint32_t read_lo; uint32_t write_lo; @@ -94,3 +117,34 @@ struct msgdma_desc { uint32_t reserved; uint32_t control; }; + +#elif defined(ALTERA_MSGDMA_DESC_PF_EXT) + +/* Extended descriptor format with prefetcher enabled. */ +struct msgdma_desc { + uint32_t read_lo; + uint32_t write_lo; + uint32_t length; + uint32_t next; + uint32_t transferred; + uint32_t status; + uint32_t reserved; + uint8_t write_burst; + uint8_t read_burst; + uint16_t seq_num; + uint16_t write_stride; + uint16_t read_stride; + uint32_t read_hi; + uint32_t write_hi; + uint32_t next_hi; + uint32_t reserved1; + uint32_t reserved2; + uint32_t reserved3; + uint32_t control; +}; + +#else + +#error "mSGDMA descriptor format (kernel option) is not set." + +#endif diff --git a/sys/dev/cxgbe/tom/t4_cpl_io.c b/sys/dev/cxgbe/tom/t4_cpl_io.c index 27ef745c764c0..fd4f376d86762 100644 --- a/sys/dev/cxgbe/tom/t4_cpl_io.c +++ b/sys/dev/cxgbe/tom/t4_cpl_io.c @@ -74,7 +74,7 @@ __FBSDID("$FreeBSD$"); #include "tom/t4_tom.h" static void t4_aiotx_cancel(struct kaiocb *job); -static void t4_aiotx_queue_toep(struct toepcb *toep); +static void t4_aiotx_queue_toep(struct socket *so, struct toepcb *toep); static size_t aiotx_mbuf_pgoff(struct mbuf *m) @@ -785,7 +785,7 @@ t4_push_frames(struct adapter *sc, struct toepcb *toep, int drop) if (sowwakeup) { if (!TAILQ_EMPTY( &toep->aiotx_jobq)) - t4_aiotx_queue_toep( + t4_aiotx_queue_toep(so, toep); sowwakeup_locked(so); } else @@ -829,7 +829,7 @@ t4_push_frames(struct adapter *sc, struct toepcb *toep, int drop) } if (sowwakeup) { if (!TAILQ_EMPTY(&toep->aiotx_jobq)) - t4_aiotx_queue_toep(toep); + t4_aiotx_queue_toep(so, toep); sowwakeup_locked(so); } else SOCKBUF_UNLOCK(sb); @@ -1821,7 +1821,7 @@ do_fw4_ack(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m) tls_ofld->sb_off -= plen; } if (!TAILQ_EMPTY(&toep->aiotx_jobq)) - t4_aiotx_queue_toep(toep); + t4_aiotx_queue_toep(so, toep); sowwakeup_locked(so); /* unlocks so_snd */ } SOCKBUF_UNLOCK_ASSERT(sb); @@ -2195,10 +2195,10 @@ static void t4_aiotx_task(void *context, int pending) { struct toepcb *toep = context; - struct inpcb *inp = toep->inp; - struct socket *so = inp->inp_socket; + struct socket *so; struct kaiocb *job; + so = toep->aiotx_so; CURVNET_SET(toep->vnet); SOCKBUF_LOCK(&so->so_snd); while (!TAILQ_EMPTY(&toep->aiotx_jobq) && sowriteable(so)) { @@ -2209,15 +2209,17 @@ t4_aiotx_task(void *context, int pending) t4_aiotx_process_job(toep, so, job); } - toep->aiotx_task_active = false; + toep->aiotx_so = NULL; SOCKBUF_UNLOCK(&so->so_snd); CURVNET_RESTORE(); free_toepcb(toep); + SOCK_LOCK(so); + sorele(so); } static void -t4_aiotx_queue_toep(struct toepcb *toep) +t4_aiotx_queue_toep(struct socket *so, struct toepcb *toep) { SOCKBUF_LOCK_ASSERT(&toep->inp->inp_socket->so_snd); @@ -2225,9 +2227,10 @@ t4_aiotx_queue_toep(struct toepcb *toep) CTR3(KTR_CXGBE, "%s: queueing aiotx task for tid %d, active = %s", __func__, toep->tid, toep->aiotx_task_active ? "true" : "false"); #endif - if (toep->aiotx_task_active) + if (toep->aiotx_so != NULL) return; - toep->aiotx_task_active = true; + soref(so); + toep->aiotx_so = so; hold_toepcb(toep); soaio_enqueue(&toep->aiotx_task); } @@ -2284,7 +2287,7 @@ t4_aio_queue_aiotx(struct socket *so, struct kaiocb *job) panic("new job was cancelled"); TAILQ_INSERT_TAIL(&toep->aiotx_jobq, job, list); if (sowriteable(so)) - t4_aiotx_queue_toep(toep); + t4_aiotx_queue_toep(so, toep); SOCKBUF_UNLOCK(&so->so_snd); return (0); } diff --git a/sys/dev/cxgbe/tom/t4_ddp.c b/sys/dev/cxgbe/tom/t4_ddp.c index 47062e634bbf0..f3f03e0faa2c4 100644 --- a/sys/dev/cxgbe/tom/t4_ddp.c +++ b/sys/dev/cxgbe/tom/t4_ddp.c @@ -220,7 +220,7 @@ release_ddp_resources(struct toepcb *toep) int i; DDP_LOCK(toep); - toep->flags |= DDP_DEAD; + toep->ddp.flags |= DDP_DEAD; for (i = 0; i < nitems(toep->ddp.db); i++) { free_ddp_buffer(toep->td, &toep->ddp.db[i]); } diff --git a/sys/dev/cxgbe/tom/t4_tom.h b/sys/dev/cxgbe/tom/t4_tom.h index db9e50cd39e16..d4ff4490abad8 100644 --- a/sys/dev/cxgbe/tom/t4_tom.h +++ b/sys/dev/cxgbe/tom/t4_tom.h @@ -194,7 +194,7 @@ struct toepcb { TAILQ_HEAD(, kaiocb) aiotx_jobq; struct task aiotx_task; - bool aiotx_task_active; + struct socket *aiotx_so; /* Tx software descriptor */ uint8_t txsd_total; diff --git a/sys/dev/drm2/ttm/ttm_bo_vm.c b/sys/dev/drm2/ttm/ttm_bo_vm.c index 6f7184857ce6f..43d027fc5cd91 100644 --- a/sys/dev/drm2/ttm/ttm_bo_vm.c +++ b/sys/dev/drm2/ttm/ttm_bo_vm.c @@ -115,7 +115,7 @@ ttm_bo_vm_fault(vm_object_t vm_obj, vm_ooffset_t offset, vm_object_pip_add(vm_obj, 1); if (*mres != NULL) { vm_page_lock(*mres); - vm_page_remove(*mres); + (void)vm_page_remove(*mres); vm_page_unlock(*mres); } retry: diff --git a/sys/dev/gpio/gpiobus.c b/sys/dev/gpio/gpiobus.c index 133b72185d7f4..64fadb382a02f 100644 --- a/sys/dev/gpio/gpiobus.c +++ b/sys/dev/gpio/gpiobus.c @@ -255,13 +255,6 @@ gpiobus_alloc_ivars(struct gpiobus_ivar *devi) M_NOWAIT | M_ZERO); if (devi->pins == NULL) return (ENOMEM); - devi->flags = malloc(sizeof(uint32_t) * devi->npins, M_DEVBUF, - M_NOWAIT | M_ZERO); - if (devi->flags == NULL) { - free(devi->pins, M_DEVBUF); - return (ENOMEM); - } - return (0); } @@ -269,14 +262,11 @@ void gpiobus_free_ivars(struct gpiobus_ivar *devi) { - if (devi->flags) { - free(devi->flags, M_DEVBUF); - devi->flags = NULL; - } if (devi->pins) { free(devi->pins, M_DEVBUF); devi->pins = NULL; } + devi->npins = 0; } int @@ -326,6 +316,34 @@ gpiobus_release_pin(device_t bus, uint32_t pin) } static int +gpiobus_acquire_child_pins(device_t dev, device_t child) +{ + struct gpiobus_ivar *devi = GPIOBUS_IVAR(child); + int i; + + for (i = 0; i < devi->npins; i++) { + /* Reserve the GPIO pin. */ + if (gpiobus_acquire_pin(dev, devi->pins[i]) != 0) { + device_printf(child, "cannot acquire pin %d\n", + devi->pins[i]); + while (--i >= 0) { + (void)gpiobus_release_pin(dev, + devi->pins[i]); + } + gpiobus_free_ivars(devi); + return (EBUSY); + } + } + for (i = 0; i < devi->npins; i++) { + /* Use the child name as pin name. */ + GPIOBUS_PIN_SETNAME(dev, devi->pins[i], + device_get_nameunit(child)); + + } + return (0); +} + +static int gpiobus_parse_pins(struct gpiobus_softc *sc, device_t child, int mask) { struct gpiobus_ivar *devi = GPIOBUS_IVAR(child); @@ -349,17 +367,66 @@ gpiobus_parse_pins(struct gpiobus_softc *sc, device_t child, int mask) for (i = 0; i < 32; i++) { if ((mask & (1 << i)) == 0) continue; - /* Reserve the GPIO pin. */ - if (gpiobus_acquire_pin(sc->sc_busdev, i) != 0) { - gpiobus_free_ivars(devi); - return (EINVAL); - } devi->pins[npins++] = i; - /* Use the child name as pin name. */ - GPIOBUS_PIN_SETNAME(sc->sc_busdev, i, - device_get_nameunit(child)); } + if (gpiobus_acquire_child_pins(sc->sc_busdev, child) != 0) + return (EINVAL); + return (0); +} + +static int +gpiobus_parse_pin_list(struct gpiobus_softc *sc, device_t child, + const char *pins) +{ + struct gpiobus_ivar *devi = GPIOBUS_IVAR(child); + const char *p; + char *endp; + unsigned long pin; + int i, npins; + + npins = 0; + p = pins; + for (;;) { + pin = strtoul(p, &endp, 0); + if (endp == p) + break; + npins++; + if (*endp == '\0') + break; + p = endp + 1; + } + + if (*endp != '\0') { + device_printf(child, "garbage in the pin list: %s\n", endp); + return (EINVAL); + } + if (npins == 0) { + device_printf(child, "empty pin list\n"); + return (EINVAL); + } + + devi->npins = npins; + if (gpiobus_alloc_ivars(devi) != 0) { + device_printf(child, "cannot allocate device ivars\n"); + return (EINVAL); + } + + i = 0; + p = pins; + for (;;) { + pin = strtoul(p, &endp, 0); + + devi->pins[i] = pin; + + if (*endp == '\0') + break; + i++; + p = endp + 1; + } + + if (gpiobus_acquire_child_pins(sc->sc_busdev, child) != 0) + return (EINVAL); return (0); } @@ -539,15 +606,26 @@ gpiobus_hinted_child(device_t bus, const char *dname, int dunit) struct gpiobus_softc *sc = GPIOBUS_SOFTC(bus); struct gpiobus_ivar *devi; device_t child; - int irq, pins; + const char *pins; + int irq, pinmask; child = BUS_ADD_CHILD(bus, 0, dname, dunit); devi = GPIOBUS_IVAR(child); - resource_int_value(dname, dunit, "pins", &pins); - if (gpiobus_parse_pins(sc, child, pins)) { - resource_list_free(&devi->rl); - free(devi, M_DEVBUF); - device_delete_child(bus, child); + if (resource_int_value(dname, dunit, "pins", &pinmask) == 0) { + if (gpiobus_parse_pins(sc, child, pinmask)) { + resource_list_free(&devi->rl); + free(devi, M_DEVBUF); + device_delete_child(bus, child); + return; + } + } + else if (resource_string_value(dname, dunit, "pin_list", &pins) == 0) { + if (gpiobus_parse_pin_list(sc, child, pins)) { + resource_list_free(&devi->rl); + free(devi, M_DEVBUF); + device_delete_child(bus, child); + return; + } } if (resource_int_value(dname, dunit, "irq", &irq) == 0) { if (bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1) != 0) @@ -574,6 +652,61 @@ gpiobus_set_resource(device_t dev, device_t child, int type, int rid, return (0); } +static int +gpiobus_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) +{ + struct gpiobus_ivar *devi; + + devi = GPIOBUS_IVAR(child); + switch (which) { + case GPIOBUS_IVAR_NPINS: + *result = devi->npins; + break; + case GPIOBUS_IVAR_PINS: + /* Children do not ever need to directly examine this. */ + return (ENOTSUP); + default: + return (ENOENT); + } + + return (0); +} + +static int +gpiobus_write_ivar(device_t dev, device_t child, int which, uintptr_t value) +{ + struct gpiobus_ivar *devi; + const uint32_t *ptr; + int i; + + devi = GPIOBUS_IVAR(child); + switch (which) { + case GPIOBUS_IVAR_NPINS: + /* GPIO ivars are set once. */ + if (devi->npins != 0) { + return (EBUSY); + } + devi->npins = value; + if (gpiobus_alloc_ivars(devi) != 0) { + device_printf(child, "cannot allocate device ivars\n"); + devi->npins = 0; + return (ENOMEM); + } + break; + case GPIOBUS_IVAR_PINS: + ptr = (const uint32_t *)value; + for (i = 0; i < devi->npins; i++) + devi->pins[i] = ptr[i]; + if (gpiobus_acquire_child_pins(dev, child) != 0) + return (EBUSY); + break; + default: + return (ENOENT); + } + + return (0); +} + static struct resource * gpiobus_alloc_resource(device_t bus, device_t child, int type, int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) @@ -833,6 +966,8 @@ static device_method_t gpiobus_methods[] = { DEVMETHOD(bus_child_pnpinfo_str, gpiobus_child_pnpinfo_str), DEVMETHOD(bus_child_location_str, gpiobus_child_location_str), DEVMETHOD(bus_hinted_child, gpiobus_hinted_child), + DEVMETHOD(bus_read_ivar, gpiobus_read_ivar), + DEVMETHOD(bus_write_ivar, gpiobus_write_ivar), /* GPIO protocol */ DEVMETHOD(gpiobus_acquire_bus, gpiobus_acquire_bus), diff --git a/sys/dev/gpio/gpiobusvar.h b/sys/dev/gpio/gpiobusvar.h index 5aa363a23daf8..08f0ccf904d02 100644 --- a/sys/dev/gpio/gpiobusvar.h +++ b/sys/dev/gpio/gpiobusvar.h @@ -107,10 +107,22 @@ struct gpiobus_ivar { struct resource_list rl; /* isr resource list */ uint32_t npins; /* pins total */ - uint32_t *flags; /* pins flags */ uint32_t *pins; /* pins map */ }; +enum gpiobus_ivars { + GPIOBUS_IVAR_NPINS = 10500, + GPIOBUS_IVAR_PINS, +}; + +#define GPIOBUS_ACCESSOR(var, ivar, type) \ + __BUS_ACCESSOR(gpiobus, var, GPIOBUS, ivar, type) + +GPIOBUS_ACCESSOR(npins, NPINS, uint32_t) +GPIOBUS_ACCESSOR(pins, PINS, const uint32_t *) + +#undef GPIOBUS_ACCESSOR + #ifdef FDT struct ofw_gpiobus_devinfo { struct gpiobus_ivar opd_dinfo; diff --git a/sys/dev/gpio/ofw_gpiobus.c b/sys/dev/gpio/ofw_gpiobus.c index 698701c8769d0..3c48c62feed3a 100644 --- a/sys/dev/gpio/ofw_gpiobus.c +++ b/sys/dev/gpio/ofw_gpiobus.c @@ -321,10 +321,8 @@ ofw_gpiobus_setup_devinfo(device_t bus, device_t child, phandle_t node) ofw_gpiobus_destroy_devinfo(bus, dinfo); return (NULL); } - for (i = 0; i < devi->npins; i++) { - devi->flags[i] = pins[i].flags; + for (i = 0; i < devi->npins; i++) devi->pins[i] = pins[i].pin; - } free(pins, M_DEVBUF); /* Parse the interrupt resources. */ if (ofw_bus_intr_to_rl(bus, node, &dinfo->opd_dinfo.rl, NULL) != 0) { diff --git a/sys/dev/iicbus/ad7418.c b/sys/dev/iicbus/ad7418.c index 457b3626c8efa..0345977687909 100644 --- a/sys/dev/iicbus/ad7418.c +++ b/sys/dev/iicbus/ad7418.c @@ -35,18 +35,9 @@ __FBSDID("$FreeBSD$"); #include <sys/lock.h> #include <sys/module.h> #include <sys/bus.h> -#include <sys/resource.h> -#include <sys/rman.h> #include <sys/sysctl.h> #include <sys/sx.h> -#include <machine/bus.h> -#include <machine/cpu.h> -#include <machine/cpufunc.h> -#include <machine/frame.h> -#include <machine/resource.h> -#include <machine/intr.h> - #include <dev/iicbus/iiconf.h> #include "iicbus_if.h" diff --git a/sys/dev/nand/nand.c b/sys/dev/nand/nand.c deleted file mode 100644 index 6997ef7f8a0d6..0000000000000 --- a/sys/dev/nand/nand.c +++ /dev/null @@ -1,826 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/socket.h> -#include <sys/malloc.h> -#include <sys/module.h> -#include <sys/bus.h> -#include <sys/lock.h> -#include <sys/mutex.h> -#include <sys/callout.h> -#include <sys/sysctl.h> - -#include <dev/nand/nand.h> -#include <dev/nand/nandbus.h> -#include <dev/nand/nand_ecc_pos.h> -#include "nfc_if.h" -#include "nand_if.h" -#include "nandbus_if.h" -#include <machine/stdarg.h> - -#define NAND_RESET_DELAY 1000 /* tRST */ -#define NAND_ERASE_DELAY 3000 /* tBERS */ -#define NAND_PROG_DELAY 700 /* tPROG */ -#define NAND_READ_DELAY 50 /* tR */ - -#define BIT0(x) ((x) & 0x1) -#define BIT1(x) (BIT0(x >> 1)) -#define BIT2(x) (BIT0(x >> 2)) -#define BIT3(x) (BIT0(x >> 3)) -#define BIT4(x) (BIT0(x >> 4)) -#define BIT5(x) (BIT0(x >> 5)) -#define BIT6(x) (BIT0(x >> 6)) -#define BIT7(x) (BIT0(x >> 7)) - -#define SOFTECC_SIZE 256 -#define SOFTECC_BYTES 3 - -int nand_debug_flag = 0; -SYSCTL_INT(_debug, OID_AUTO, nand_debug, CTLFLAG_RWTUN, &nand_debug_flag, 0, - "NAND subsystem debug flag"); - -MALLOC_DEFINE(M_NAND, "NAND", "NAND dynamic data"); - -static void calculate_ecc(const uint8_t *, uint8_t *); -static int correct_ecc(uint8_t *, uint8_t *, uint8_t *); - -void -nand_debug(int level, const char *fmt, ...) -{ - va_list ap; - - if (!(nand_debug_flag & level)) - return; - va_start(ap, fmt); - vprintf(fmt, ap); - va_end(ap); - printf("\n"); -} - -void -nand_init(struct nand_softc *nand, device_t dev, int ecc_mode, - int ecc_bytes, int ecc_size, uint16_t *eccposition, char *cdev_name) -{ - - nand->ecc.eccmode = ecc_mode; - nand->chip_cdev_name = cdev_name; - - if (ecc_mode == NAND_ECC_SOFT) { - nand->ecc.eccbytes = SOFTECC_BYTES; - nand->ecc.eccsize = SOFTECC_SIZE; - } else if (ecc_mode != NAND_ECC_NONE) { - nand->ecc.eccbytes = ecc_bytes; - nand->ecc.eccsize = ecc_size; - if (eccposition) - nand->ecc.eccpositions = eccposition; - } -} - -void -nand_onfi_set_params(struct nand_chip *chip, struct onfi_chip_params *params) -{ - struct chip_geom *cg; - - cg = &chip->chip_geom; - - init_chip_geom(cg, params->luns, params->blocks_per_lun, - params->pages_per_block, params->bytes_per_page, - params->spare_bytes_per_page); - chip->t_bers = params->t_bers; - chip->t_prog = params->t_prog; - chip->t_r = params->t_r; - chip->t_ccs = params->t_ccs; - - if (params->features & ONFI_FEAT_16BIT) - chip->flags |= NAND_16_BIT; -} - -void -nand_set_params(struct nand_chip *chip, struct nand_params *params) -{ - struct chip_geom *cg; - uint32_t blocks_per_chip; - - cg = &chip->chip_geom; - blocks_per_chip = (params->chip_size << 20) / - (params->page_size * params->pages_per_block); - - init_chip_geom(cg, 1, blocks_per_chip, - params->pages_per_block, params->page_size, - params->oob_size); - - chip->t_bers = NAND_ERASE_DELAY; - chip->t_prog = NAND_PROG_DELAY; - chip->t_r = NAND_READ_DELAY; - chip->t_ccs = 0; - - if (params->flags & NAND_16_BIT) - chip->flags |= NAND_16_BIT; -} - -int -nand_init_stat(struct nand_chip *chip) -{ - struct block_stat *blk_stat; - struct page_stat *pg_stat; - struct chip_geom *cg; - uint32_t blks, pgs; - - cg = &chip->chip_geom; - blks = cg->blks_per_lun * cg->luns; - blk_stat = malloc(sizeof(struct block_stat) * blks, M_NAND, - M_WAITOK | M_ZERO); - if (!blk_stat) - return (ENOMEM); - - pgs = blks * cg->pgs_per_blk; - pg_stat = malloc(sizeof(struct page_stat) * pgs, M_NAND, - M_WAITOK | M_ZERO); - if (!pg_stat) { - free(blk_stat, M_NAND); - return (ENOMEM); - } - - chip->blk_stat = blk_stat; - chip->pg_stat = pg_stat; - - return (0); -} - -void -nand_destroy_stat(struct nand_chip *chip) -{ - - free(chip->pg_stat, M_NAND); - free(chip->blk_stat, M_NAND); -} - -int -init_chip_geom(struct chip_geom *cg, uint32_t luns, uint32_t blks_per_lun, - uint32_t pgs_per_blk, uint32_t pg_size, uint32_t oob_size) -{ - int shift; - - if (!cg) - return (-1); - - cg->luns = luns; - cg->blks_per_lun = blks_per_lun; - cg->blks_per_chip = blks_per_lun * luns; - cg->pgs_per_blk = pgs_per_blk; - - cg->page_size = pg_size; - cg->oob_size = oob_size; - cg->block_size = cg->page_size * cg->pgs_per_blk; - cg->chip_size = cg->block_size * cg->blks_per_chip; - - shift = fls(cg->pgs_per_blk - 1); - cg->pg_mask = (1 << shift) - 1; - cg->blk_shift = shift; - - if (cg->blks_per_lun > 0) { - shift = fls(cg->blks_per_lun - 1); - cg->blk_mask = ((1 << shift) - 1) << cg->blk_shift; - } else { - shift = 0; - cg->blk_mask = 0; - } - - cg->lun_shift = shift + cg->blk_shift; - shift = fls(cg->luns - 1); - cg->lun_mask = ((1 << shift) - 1) << cg->lun_shift; - - nand_debug(NDBG_NAND, "Masks: lun 0x%x blk 0x%x page 0x%x\n" - "Shifts: lun %d blk %d", - cg->lun_mask, cg->blk_mask, cg->pg_mask, - cg->lun_shift, cg->blk_shift); - - return (0); -} - -int -nand_row_to_blkpg(struct chip_geom *cg, uint32_t row, uint32_t *lun, - uint32_t *blk, uint32_t *pg) -{ - - if (!cg || !lun || !blk || !pg) - return (-1); - - if (row & ~(cg->lun_mask | cg->blk_mask | cg->pg_mask)) { - nand_debug(NDBG_NAND,"Address out of bounds\n"); - return (-1); - } - - *lun = (row & cg->lun_mask) >> cg->lun_shift; - *blk = (row & cg->blk_mask) >> cg->blk_shift; - *pg = (row & cg->pg_mask); - - nand_debug(NDBG_NAND,"address %x-%x-%x\n", *lun, *blk, *pg); - - return (0); -} - -int page_to_row(struct chip_geom *cg, uint32_t page, uint32_t *row) -{ - uint32_t lun, block, pg_in_blk; - - if (!cg || !row) - return (-1); - - block = page / cg->pgs_per_blk; - pg_in_blk = page % cg->pgs_per_blk; - - lun = block / cg->blks_per_lun; - block = block % cg->blks_per_lun; - - *row = (lun << cg->lun_shift) & cg->lun_mask; - *row |= ((block << cg->blk_shift) & cg->blk_mask); - *row |= (pg_in_blk & cg->pg_mask); - - return (0); -} - -int -nand_check_page_boundary(struct nand_chip *chip, uint32_t page) -{ - struct chip_geom* cg; - - cg = &chip->chip_geom; - if (page >= (cg->pgs_per_blk * cg->blks_per_lun * cg->luns)) { - nand_debug(NDBG_GEN,"%s: page number too big %#x\n", - __func__, page); - return (1); - } - - return (0); -} - -void -nand_get_chip_param(struct nand_chip *chip, struct chip_param_io *param) -{ - struct chip_geom *cg; - - cg = &chip->chip_geom; - param->page_size = cg->page_size; - param->oob_size = cg->oob_size; - - param->blocks = cg->blks_per_lun * cg->luns; - param->pages_per_block = cg->pgs_per_blk; -} - -static uint16_t * -default_software_ecc_positions(struct nand_chip *chip) -{ - /* If positions have been set already, use them. */ - if (chip->nand->ecc.eccpositions) - return (chip->nand->ecc.eccpositions); - - /* - * XXX Note that the following logic isn't really sufficient, especially - * in the ONFI case where the number of ECC bytes can be dictated by - * values in the parameters page, and that could lead to needing more - * byte positions than exist within the tables of software-ecc defaults. - */ - if (chip->chip_geom.oob_size >= 128) - return (default_software_ecc_positions_128); - if (chip->chip_geom.oob_size >= 64) - return (default_software_ecc_positions_64); - else if (chip->chip_geom.oob_size >= 16) - return (default_software_ecc_positions_16); - - return (NULL); -} - -static void -calculate_ecc(const uint8_t *buf, uint8_t *ecc) -{ - uint8_t p8, byte; - int i; - - memset(ecc, 0, 3); - - for (i = 0; i < 256; i++) { - byte = buf[i]; - ecc[0] ^= (BIT0(byte) ^ BIT2(byte) ^ BIT4(byte) ^ - BIT6(byte)) << 2; - ecc[0] ^= (BIT1(byte) ^ BIT3(byte) ^ BIT5(byte) ^ - BIT7(byte)) << 3; - ecc[0] ^= (BIT0(byte) ^ BIT1(byte) ^ BIT4(byte) ^ - BIT5(byte)) << 4; - ecc[0] ^= (BIT2(byte) ^ BIT3(byte) ^ BIT6(byte) ^ - BIT7(byte)) << 5; - ecc[0] ^= (BIT0(byte) ^ BIT1(byte) ^ BIT2(byte) ^ - BIT3(byte)) << 6; - ecc[0] ^= (BIT4(byte) ^ BIT5(byte) ^ BIT6(byte) ^ - BIT7(byte)) << 7; - - p8 = BIT0(byte) ^ BIT1(byte) ^ BIT2(byte) ^ - BIT3(byte) ^ BIT4(byte) ^ BIT5(byte) ^ BIT6(byte) ^ - BIT7(byte); - - if (p8) { - ecc[2] ^= (0x1 << BIT0(i)); - ecc[2] ^= (0x4 << BIT1(i)); - ecc[2] ^= (0x10 << BIT2(i)); - ecc[2] ^= (0x40 << BIT3(i)); - - ecc[1] ^= (0x1 << BIT4(i)); - ecc[1] ^= (0x4 << BIT5(i)); - ecc[1] ^= (0x10 << BIT6(i)); - ecc[1] ^= (0x40 << BIT7(i)); - } - } - ecc[0] = ~ecc[0]; - ecc[1] = ~ecc[1]; - ecc[2] = ~ecc[2]; - ecc[0] |= 3; -} - -static int -correct_ecc(uint8_t *buf, uint8_t *calc_ecc, uint8_t *read_ecc) -{ - uint8_t ecc0, ecc1, ecc2, onesnum, bit, byte; - uint16_t addr = 0; - - ecc0 = calc_ecc[0] ^ read_ecc[0]; - ecc1 = calc_ecc[1] ^ read_ecc[1]; - ecc2 = calc_ecc[2] ^ read_ecc[2]; - - if (!ecc0 && !ecc1 && !ecc2) - return (ECC_OK); - - addr = BIT3(ecc0) | (BIT5(ecc0) << 1) | (BIT7(ecc0) << 2); - addr |= (BIT1(ecc2) << 3) | (BIT3(ecc2) << 4) | - (BIT5(ecc2) << 5) | (BIT7(ecc2) << 6); - addr |= (BIT1(ecc1) << 7) | (BIT3(ecc1) << 8) | - (BIT5(ecc1) << 9) | (BIT7(ecc1) << 10); - - onesnum = 0; - while (ecc0 || ecc1 || ecc2) { - if (ecc0 & 1) - onesnum++; - if (ecc1 & 1) - onesnum++; - if (ecc2 & 1) - onesnum++; - - ecc0 >>= 1; - ecc1 >>= 1; - ecc2 >>= 1; - } - - if (onesnum == 11) { - /* Correctable error */ - bit = addr & 7; - byte = addr >> 3; - buf[byte] ^= (1 << bit); - return (ECC_CORRECTABLE); - } else if (onesnum == 1) { - /* ECC error */ - return (ECC_ERROR_ECC); - } else { - /* Uncorrectable error */ - return (ECC_UNCORRECTABLE); - } - - return (0); -} - -int -nand_softecc_get(device_t dev, uint8_t *buf, int pagesize, uint8_t *ecc) -{ - int steps = pagesize / SOFTECC_SIZE; - int i = 0, j = 0; - - for (; i < (steps * SOFTECC_BYTES); - i += SOFTECC_BYTES, j += SOFTECC_SIZE) { - calculate_ecc(&buf[j], &ecc[i]); - } - - return (0); -} - -int -nand_softecc_correct(device_t dev, uint8_t *buf, int pagesize, - uint8_t *readecc, uint8_t *calcecc) -{ - int steps = pagesize / SOFTECC_SIZE; - int i = 0, j = 0, ret = 0; - - for (i = 0; i < (steps * SOFTECC_BYTES); - i += SOFTECC_BYTES, j += SOFTECC_SIZE) { - ret += correct_ecc(&buf[j], &calcecc[i], &readecc[i]); - if (ret < 0) - return (ret); - } - - return (ret); -} - -static int -offset_to_page(struct chip_geom *cg, uint32_t offset) -{ - - return (offset / cg->page_size); -} - -int -nand_read_pages(struct nand_chip *chip, uint32_t offset, void *buf, - uint32_t len) -{ - struct chip_geom *cg; - struct nand_ecc_data *eccd; - struct page_stat *pg_stat; - device_t nandbus; - void *oob = NULL; - uint8_t *ptr; - uint16_t *eccpos = NULL; - uint32_t page, num, steps = 0; - int i, retval = 0, needwrite; - - nand_debug(NDBG_NAND,"%p read page %x[%x]", chip, offset, len); - cg = &chip->chip_geom; - eccd = &chip->nand->ecc; - page = offset_to_page(cg, offset); - num = len / cg->page_size; - - if (eccd->eccmode != NAND_ECC_NONE) { - steps = cg->page_size / eccd->eccsize; - eccpos = default_software_ecc_positions(chip); - oob = malloc(cg->oob_size, M_NAND, M_WAITOK); - } - - nandbus = device_get_parent(chip->dev); - NANDBUS_LOCK(nandbus); - NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num); - - ptr = (uint8_t *)buf; - while (num--) { - pg_stat = &(chip->pg_stat[page]); - - if (NAND_READ_PAGE(chip->dev, page, ptr, cg->page_size, 0)) { - retval = ENXIO; - break; - } - - if (eccd->eccmode != NAND_ECC_NONE) { - if (NAND_GET_ECC(chip->dev, ptr, eccd->ecccalculated, - &needwrite)) { - retval = ENXIO; - break; - } - nand_debug(NDBG_ECC,"%s: ECC calculated:", - __func__); - if (nand_debug_flag & NDBG_ECC) - for (i = 0; i < (eccd->eccbytes * steps); i++) - printf("%x ", eccd->ecccalculated[i]); - - nand_debug(NDBG_ECC,"\n"); - - if (NAND_READ_OOB(chip->dev, page, oob, cg->oob_size, - 0)) { - retval = ENXIO; - break; - } - for (i = 0; i < (eccd->eccbytes * steps); i++) - eccd->eccread[i] = ((uint8_t *)oob)[eccpos[i]]; - - nand_debug(NDBG_ECC,"%s: ECC read:", __func__); - if (nand_debug_flag & NDBG_ECC) - for (i = 0; i < (eccd->eccbytes * steps); i++) - printf("%x ", eccd->eccread[i]); - nand_debug(NDBG_ECC,"\n"); - - retval = NAND_CORRECT_ECC(chip->dev, ptr, eccd->eccread, - eccd->ecccalculated); - - nand_debug(NDBG_ECC, "NAND_CORRECT_ECC() returned %d", - retval); - - if (retval == 0) - pg_stat->ecc_stat.ecc_succeded++; - else if (retval > 0) { - pg_stat->ecc_stat.ecc_corrected += retval; - retval = ECC_CORRECTABLE; - } else { - pg_stat->ecc_stat.ecc_failed++; - break; - } - } - - pg_stat->page_read++; - page++; - ptr += cg->page_size; - } - - NANDBUS_UNLOCK(nandbus); - - if (oob) - free(oob, M_NAND); - - return (retval); -} - -int -nand_read_pages_raw(struct nand_chip *chip, uint32_t offset, void *buf, - uint32_t len) -{ - struct chip_geom *cg; - device_t nandbus; - uint8_t *ptr; - uint32_t page, num, end, begin = 0, begin_off; - int retval = 0; - - cg = &chip->chip_geom; - page = offset_to_page(cg, offset); - begin_off = offset - page * cg->page_size; - if (begin_off) { - begin = cg->page_size - begin_off; - len -= begin; - } - num = len / cg->page_size; - end = len % cg->page_size; - - nandbus = device_get_parent(chip->dev); - NANDBUS_LOCK(nandbus); - NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num); - - ptr = (uint8_t *)buf; - if (begin_off) { - if (NAND_READ_PAGE(chip->dev, page, ptr, begin, begin_off)) { - NANDBUS_UNLOCK(nandbus); - return (ENXIO); - } - - page++; - ptr += begin; - } - - while (num--) { - if (NAND_READ_PAGE(chip->dev, page, ptr, cg->page_size, 0)) { - NANDBUS_UNLOCK(nandbus); - return (ENXIO); - } - - page++; - ptr += cg->page_size; - } - - if (end) - if (NAND_READ_PAGE(chip->dev, page, ptr, end, 0)) { - NANDBUS_UNLOCK(nandbus); - return (ENXIO); - } - - NANDBUS_UNLOCK(nandbus); - - return (retval); -} - - -int -nand_prog_pages(struct nand_chip *chip, uint32_t offset, uint8_t *buf, - uint32_t len) -{ - struct chip_geom *cg; - struct page_stat *pg_stat; - struct nand_ecc_data *eccd; - device_t nandbus; - uint32_t page, num; - uint8_t *oob = NULL; - uint16_t *eccpos = NULL; - int steps = 0, i, needwrite, err = 0; - - nand_debug(NDBG_NAND,"%p prog page %x[%x]", chip, offset, len); - - eccd = &chip->nand->ecc; - cg = &chip->chip_geom; - page = offset_to_page(cg, offset); - num = len / cg->page_size; - - if (eccd->eccmode != NAND_ECC_NONE) { - steps = cg->page_size / eccd->eccsize; - oob = malloc(cg->oob_size, M_NAND, M_WAITOK); - eccpos = default_software_ecc_positions(chip); - } - - nandbus = device_get_parent(chip->dev); - NANDBUS_LOCK(nandbus); - NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num); - - while (num--) { - if (NAND_PROGRAM_PAGE(chip->dev, page, buf, cg->page_size, 0)) { - err = ENXIO; - break; - } - - if (eccd->eccmode != NAND_ECC_NONE) { - if (NAND_GET_ECC(chip->dev, buf, &eccd->ecccalculated, - &needwrite)) { - err = ENXIO; - break; - } - nand_debug(NDBG_ECC,"ECC calculated:"); - if (nand_debug_flag & NDBG_ECC) - for (i = 0; i < (eccd->eccbytes * steps); i++) - printf("%x ", eccd->ecccalculated[i]); - - nand_debug(NDBG_ECC,"\n"); - - if (needwrite) { - if (NAND_READ_OOB(chip->dev, page, oob, cg->oob_size, - 0)) { - err = ENXIO; - break; - } - - for (i = 0; i < (eccd->eccbytes * steps); i++) - oob[eccpos[i]] = eccd->ecccalculated[i]; - - if (NAND_PROGRAM_OOB(chip->dev, page, oob, - cg->oob_size, 0)) { - err = ENXIO; - break; - } - } - } - - pg_stat = &(chip->pg_stat[page]); - pg_stat->page_written++; - - page++; - buf += cg->page_size; - } - - NANDBUS_UNLOCK(nandbus); - - if (oob) - free(oob, M_NAND); - - return (err); -} - -int -nand_prog_pages_raw(struct nand_chip *chip, uint32_t offset, void *buf, - uint32_t len) -{ - struct chip_geom *cg; - device_t nandbus; - uint8_t *ptr; - uint32_t page, num, end, begin = 0, begin_off; - int retval = 0; - - cg = &chip->chip_geom; - page = offset_to_page(cg, offset); - begin_off = offset - page * cg->page_size; - if (begin_off) { - begin = cg->page_size - begin_off; - len -= begin; - } - num = len / cg->page_size; - end = len % cg->page_size; - - nandbus = device_get_parent(chip->dev); - NANDBUS_LOCK(nandbus); - NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num); - - ptr = (uint8_t *)buf; - if (begin_off) { - if (NAND_PROGRAM_PAGE(chip->dev, page, ptr, begin, begin_off)) { - NANDBUS_UNLOCK(nandbus); - return (ENXIO); - } - - page++; - ptr += begin; - } - - while (num--) { - if (NAND_PROGRAM_PAGE(chip->dev, page, ptr, cg->page_size, 0)) { - NANDBUS_UNLOCK(nandbus); - return (ENXIO); - } - - page++; - ptr += cg->page_size; - } - - if (end) - retval = NAND_PROGRAM_PAGE(chip->dev, page, ptr, end, 0); - - NANDBUS_UNLOCK(nandbus); - - return (retval); -} - -int -nand_read_oob(struct nand_chip *chip, uint32_t page, void *buf, - uint32_t len) -{ - device_t nandbus; - int retval = 0; - - nandbus = device_get_parent(chip->dev); - NANDBUS_LOCK(nandbus); - NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num); - - retval = NAND_READ_OOB(chip->dev, page, buf, len, 0); - - NANDBUS_UNLOCK(nandbus); - - return (retval); -} - - -int -nand_prog_oob(struct nand_chip *chip, uint32_t page, void *buf, - uint32_t len) -{ - device_t nandbus; - int retval = 0; - - nandbus = device_get_parent(chip->dev); - NANDBUS_LOCK(nandbus); - NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num); - - retval = NAND_PROGRAM_OOB(chip->dev, page, buf, len, 0); - - NANDBUS_UNLOCK(nandbus); - - return (retval); -} - -int -nand_erase_blocks(struct nand_chip *chip, off_t offset, size_t len) -{ - device_t nandbus; - struct chip_geom *cg; - uint32_t block, num_blocks; - int err = 0; - - cg = &chip->chip_geom; - if ((offset % cg->block_size) || (len % cg->block_size)) - return (EINVAL); - - block = offset / cg->block_size; - num_blocks = len / cg->block_size; - nand_debug(NDBG_NAND,"%p erase blocks %d[%d]", chip, block, num_blocks); - - nandbus = device_get_parent(chip->dev); - NANDBUS_LOCK(nandbus); - NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num); - - while (num_blocks--) { - if (!nand_check_bad_block(chip, block)) { - if (NAND_ERASE_BLOCK(chip->dev, block)) { - nand_debug(NDBG_NAND,"%p erase blocks %d error", - chip, block); - nand_mark_bad_block(chip, block); - err = ENXIO; - } - } else - err = ENXIO; - - block++; - } - - NANDBUS_UNLOCK(nandbus); - - if (err) - nand_update_bbt(chip); - - return (err); -} - -MODULE_VERSION(nand, 1); diff --git a/sys/dev/nand/nand.h b/sys/dev/nand/nand.h deleted file mode 100644 index 06902601b8d0e..0000000000000 --- a/sys/dev/nand/nand.h +++ /dev/null @@ -1,415 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _DEV_NAND_H_ -#define _DEV_NAND_H_ - -#include <sys/bus.h> -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/lock.h> -#include <sys/sx.h> -#include <sys/taskqueue.h> -#include <sys/queue.h> -#include <sys/bio.h> -#include <sys/lock.h> -#include <sys/mutex.h> -#include <sys/malloc.h> - -#include <dev/nand/nand_dev.h> - -MALLOC_DECLARE(M_NAND); - -/* Read commands */ -#define NAND_CMD_READ 0x00 -#define NAND_CMD_CHNG_READ_COL 0x05 -#define NAND_CMD_READ_END 0x30 -#define NAND_CMD_READ_CACHE 0x31 -#define NAND_CMD_READ_CPBK 0x35 -#define NAND_CMD_READ_CACHE_END 0x3F -#define NAND_CMD_CHNG_READ_COL_END 0xE0 - -/* Erase commands */ -#define NAND_CMD_ERASE 0x60 -#define NAND_CMD_ERASE_END 0xD0 -#define NAND_CMD_ERASE_INTLV 0xD1 - -/* Program commands */ -#define NAND_CMD_PROG 0x80 -#define NAND_CMD_CHNG_WRITE_COL 0x85 -#define NAND_CMD_PROG_END 0x10 -#define NAND_CMD_PROG_INTLV 0x11 -#define NAND_CMD_PROG_CACHE 0x15 - -/* Misc commands */ -#define NAND_CMD_STATUS 0x70 -#define NAND_CMD_STATUS_ENH 0x78 -#define NAND_CMD_READ_ID 0x90 -#define NAND_CMD_READ_PARAMETER 0xec -#define NAND_CMD_READ_UNIQUE_ID 0xed -#define NAND_CMD_GET_FEATURE 0xee -#define NAND_CMD_SET_FEATURE 0xef - -/* Reset commands */ -#define NAND_CMD_SYNCH_RESET 0xfc -#define NAND_CMD_RESET 0xff - -/* Small page flash commands */ -#define NAND_CMD_SMALLA 0x00 -#define NAND_CMD_SMALLB 0x01 -#define NAND_CMD_SMALLOOB 0x50 - -#define NAND_STATUS_FAIL 0x1 -#define NAND_STATUS_FAILC 0x2 -#define NAND_STATUS_ARDY 0x20 -#define NAND_STATUS_RDY 0x40 -#define NAND_STATUS_WP 0x80 - -#define NAND_LP_OOB_COLUMN_START 0x800 -#define NAND_LP_OOBSZ 0x40 -#define NAND_SP_OOB_COLUMN_START 0x200 -#define NAND_SP_OOBSZ 0x10 - -#define PAGE_PARAM_LENGTH 0x100 -#define PAGE_PARAMETER_DEF 0x0 -#define PAGE_PARAMETER_RED_1 0x100 -#define PAGE_PARAMETER_RED_2 0x200 - -#define ONFI_SIG_ADDR 0x20 - -#define NAND_MAX_CHIPS 0x4 -#define NAND_MAX_OOBSZ 512 -#define NAND_MAX_PAGESZ 16384 - -#define NAND_SMALL_PAGE_SIZE 0x200 - -#define NAND_16_BIT 0x00000001 - -#define NAND_ECC_NONE 0x0 -#define NAND_ECC_SOFT 0x1 -#define NAND_ECC_FULLHW 0x2 -#define NAND_ECC_PARTHW 0x4 -#define NAND_ECC_MODE_MASK 0x7 - -#define ECC_OK 0 -#define ECC_CORRECTABLE 1 -#define ECC_ERROR_ECC (-1) -#define ECC_UNCORRECTABLE (-2) - -#define NAND_MAN_SAMSUNG 0xec -#define NAND_MAN_HYNIX 0xad -#define NAND_MAN_STMICRO 0x20 -#define NAND_MAN_MICRON 0x2c - -struct nand_id { - uint8_t man_id; - uint8_t dev_id; -}; - -struct nand_params { - struct nand_id id; - char *name; - uint32_t chip_size; - uint32_t page_size; - uint32_t oob_size; - uint32_t pages_per_block; - uint32_t flags; -}; - -/* nand debug levels */ -#define NDBG_NAND 0x01 -#define NDBG_CDEV 0x02 -#define NDBG_GEN 0x04 -#define NDBG_GEOM 0x08 -#define NDBG_BUS 0x10 -#define NDBG_SIM 0x20 -#define NDBG_CTRL 0x40 -#define NDBG_DRV 0x80 -#define NDBG_ECC 0x100 - -/* nand_debug_function */ -void nand_debug(int level, const char *fmt, ...); -extern int nand_debug_flag; - -/* ONFI features bit*/ -#define ONFI_FEAT_16BIT 0x01 -#define ONFI_FEAT_MULT_LUN 0x02 -#define ONFI_FEAT_INTLV_OPS 0x04 -#define ONFI_FEAT_CPBK_RESTRICT 0x08 -#define ONFI_FEAT_SRC_SYNCH 0x10 - -/* ONFI optional commands bits */ -#define ONFI_OPTCOM_PROG_CACHE 0x01 -#define ONFI_OPTCOM_READ_CACHE 0x02 -#define ONFI_OPTCOM_GETSET_FEAT 0x04 -#define ONFI_OPTCOM_STATUS_ENH 0x08 -#define ONFI_OPTCOM_COPYBACK 0x10 -#define ONFI_OPTCOM_UNIQUE_ID 0x20 - - -/* Layout of parameter page is defined in ONFI */ -struct onfi_params { - char signature[4]; - uint16_t rev; - uint16_t features; - uint16_t optional_commands; - uint8_t primary_advanced_command; - uint8_t res1; - uint16_t extended_parameter_page_length; - uint8_t parameter_page_count; - uint8_t res2[17]; - char manufacturer_name[12]; - char device_model[20]; - uint8_t manufacturer_id; - uint8_t manufacture_date_yy; - uint8_t manufacture_date_ww; - uint8_t res3[13]; - uint32_t bytes_per_page; - uint16_t spare_bytes_per_page; - uint32_t bytes_per_partial_page; - uint16_t spare_bytes_per_partial_page; - uint32_t pages_per_block; - uint32_t blocks_per_lun; - uint8_t luns; - uint8_t address_cycles; - uint8_t bits_per_cell; - uint16_t max_bad_block_per_lun; - uint16_t block_endurance; - uint8_t guaranteed_valid_blocks; - uint16_t valid_block_endurance; - uint8_t programs_per_page; - uint8_t partial_prog_attr; - uint8_t bits_of_ecc; - uint8_t interleaved_addr_bits; - uint8_t interleaved_oper_attr; - uint8_t eznand_support; - uint8_t res4[12]; - uint8_t pin_capacitance; - uint16_t asynch_timing_mode_support; - uint16_t asynch_prog_cache_timing_mode_support; - uint16_t t_prog; /* us, max page program time */ - uint16_t t_bers; /* us, max block erase time */ - uint16_t t_r; /* us, max page read time */ - uint16_t t_ccs; /* ns, min change column setup time */ - uint16_t source_synch_timing_mode_support; - uint8_t source_synch_feat; - uint16_t clk_input_capacitance; - uint16_t io_capacitance; - uint16_t input_capacitance; - uint8_t input_capacitance_max; - uint8_t driver_strength_support; - uint16_t t_r_interleaved; - uint16_t t_adl; - uint16_t t_r_eznand; - uint8_t nv_ddr2_features; - uint8_t nv_ddr2_warmup_cycles; - uint8_t res5[4]; - uint16_t vendor_rev; - uint8_t vendor_spec[88]; - uint16_t crc; -}__attribute__((packed)); -CTASSERT(sizeof(struct onfi_params) == 256); - -struct onfi_chip_params { - uint32_t blocks_per_lun; - uint32_t pages_per_block; - uint32_t bytes_per_page; - uint32_t spare_bytes_per_page; - uint16_t t_bers; - uint16_t t_prog; - uint16_t t_r; - uint16_t t_ccs; - uint16_t features; - uint8_t address_cycles; - uint8_t luns; -}; - -struct nand_ecc_data { - int eccsize; /* Number of data bytes per ECC step */ - int eccmode; - int eccbytes; /* Number of ECC bytes per step */ - - uint16_t *eccpositions; /* Positions of ecc bytes */ - uint8_t ecccalculated[NAND_MAX_OOBSZ]; - uint8_t eccread[NAND_MAX_OOBSZ]; -}; - -struct ecc_stat { - uint32_t ecc_succeded; - uint32_t ecc_corrected; - uint32_t ecc_failed; -}; - -struct page_stat { - struct ecc_stat ecc_stat; - uint32_t page_read; - uint32_t page_raw_read; - uint32_t page_written; - uint32_t page_raw_written; -}; - -struct block_stat { - uint32_t block_erased; -}; - -struct chip_geom { - uint32_t chip_size; - uint32_t block_size; - uint32_t page_size; - uint32_t oob_size; - - uint32_t luns; - uint32_t blks_per_lun; - uint32_t blks_per_chip; - uint32_t pgs_per_blk; - - uint32_t pg_mask; - uint32_t blk_mask; - uint32_t lun_mask; - uint8_t blk_shift; - uint8_t lun_shift; -}; - -struct nand_chip { - device_t dev; - struct nand_id id; - struct chip_geom chip_geom; - - uint16_t t_prog; /* us, max page program time */ - uint16_t t_bers; /* us, max block erase time */ - uint16_t t_r; /* us, max page read time */ - uint16_t t_ccs; /* ns, min change column setup time */ - uint8_t num; - uint8_t flags; - - struct page_stat *pg_stat; - struct block_stat *blk_stat; - struct nand_softc *nand; - struct nand_bbt *bbt; - struct nand_ops *ops; - struct cdev *cdev; - - struct disk *ndisk; - struct disk *rdisk; - struct bio_queue_head bioq; /* bio queue */ - struct mtx qlock; /* bioq lock */ - struct taskqueue *tq; /* private task queue for i/o request */ - struct task iotask; /* i/o processing */ - -}; - -struct nand_softc { - uint8_t flags; - - char *chip_cdev_name; - struct nand_ecc_data ecc; -}; - -/* NAND ops */ -int nand_erase_blocks(struct nand_chip *chip, off_t offset, size_t len); -int nand_prog_pages(struct nand_chip *chip, uint32_t offset, uint8_t *buf, - uint32_t len); -int nand_read_pages(struct nand_chip *chip, uint32_t offset, void *buf, - uint32_t len); -int nand_read_pages_raw(struct nand_chip *chip, uint32_t offset, void *buf, - uint32_t len); -int nand_prog_pages_raw(struct nand_chip *chip, uint32_t offset, void *buf, - uint32_t len); -int nand_read_oob(struct nand_chip *chip, uint32_t page, void *buf, - uint32_t len); -int nand_prog_oob(struct nand_chip *chip, uint32_t page, void *buf, - uint32_t len); - -int nand_select_cs(device_t dev, uint8_t cs); - -int nand_read_parameter(struct nand_softc *nand, struct onfi_params *param); -int nand_synch_reset(struct nand_softc *nand); -int nand_chng_read_col(device_t dev, uint32_t col, void *buf, size_t len); -int nand_chng_write_col(device_t dev, uint32_t col, void *buf, size_t len); -int nand_get_feature(device_t dev, uint8_t feat, void* buf); -int nand_set_feature(device_t dev, uint8_t feat, void* buf); - - -int nand_erase_block_intlv(device_t dev, uint32_t block); -int nand_copyback_read(device_t dev, uint32_t page, uint32_t col, - void *buf, size_t len); -int nand_copyback_prog(device_t dev, uint32_t page, uint32_t col, - void *buf, size_t len); -int nand_copyback_prog_intlv(device_t dev, uint32_t page); -int nand_prog_cache(device_t dev, uint32_t page, uint32_t col, - void *buf, size_t len, uint8_t end); -int nand_prog_intlv(device_t dev, uint32_t page, uint32_t col, - void *buf, size_t len); -int nand_read_cache(device_t dev, uint32_t page, uint32_t col, - void *buf, size_t len, uint8_t end); - -int nand_write_ecc(struct nand_softc *nand, uint32_t page, uint8_t *data); -int nand_read_ecc(struct nand_softc *nand, uint32_t page, uint8_t *data); - -int nand_softecc_get(device_t dev, uint8_t *buf, int pagesize, uint8_t *ecc); -int nand_softecc_correct(device_t dev, uint8_t *buf, int pagesize, - uint8_t *readecc, uint8_t *calcecc); - -/* Chip initialization */ -void nand_init(struct nand_softc *nand, device_t dev, int ecc_mode, - int ecc_bytes, int ecc_size, uint16_t* eccposition, char* cdev_name); -void nand_detach(struct nand_softc *nand); -struct nand_params *nand_get_params(struct nand_id *id); - -void nand_onfi_set_params(struct nand_chip *chip, struct onfi_chip_params *params); -void nand_set_params(struct nand_chip *chip, struct nand_params *params); -int nand_init_stat(struct nand_chip *chip); -void nand_destroy_stat(struct nand_chip *chip); - -/* BBT */ -int nand_init_bbt(struct nand_chip *chip); -void nand_destroy_bbt(struct nand_chip *chip); -int nand_update_bbt(struct nand_chip *chip); -int nand_mark_bad_block(struct nand_chip* chip, uint32_t block_num); -int nand_check_bad_block(struct nand_chip* chip, uint32_t block_num); - -/* cdev creation/removal */ -int nand_make_dev(struct nand_chip* chip); -void nand_destroy_dev(struct nand_chip *chip); - -int create_geom_disk(struct nand_chip* chip); -int create_geom_raw_disk(struct nand_chip *chip); -void destroy_geom_disk(struct nand_chip *chip); -void destroy_geom_raw_disk(struct nand_chip *chip); - -int init_chip_geom(struct chip_geom* cg, uint32_t luns, uint32_t blks_per_lun, - uint32_t pgs_per_blk, uint32_t pg_size, uint32_t oob_size); -int nand_row_to_blkpg(struct chip_geom *cg, uint32_t row, uint32_t *lun, - uint32_t *blk, uint32_t *pg); -int page_to_row(struct chip_geom *cg, uint32_t page, uint32_t *row); -int nand_check_page_boundary(struct nand_chip *chip, uint32_t page); -void nand_get_chip_param(struct nand_chip *chip, struct chip_param_io *param); - -#endif /* _DEV_NAND_H_ */ diff --git a/sys/dev/nand/nand_bbt.c b/sys/dev/nand/nand_bbt.c deleted file mode 100644 index d99ed67523a20..0000000000000 --- a/sys/dev/nand/nand_bbt.c +++ /dev/null @@ -1,275 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include <sys/cdefs.h> - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/socket.h> -#include <sys/malloc.h> -#include <sys/bus.h> - -#include <dev/nand/nand.h> - -#include "nand_if.h" - -#define BBT_PRIMARY_PATTERN 0x01020304 -#define BBT_SECONDARY_PATTERN 0x05060708 - -enum bbt_place { - BBT_NONE, - BBT_PRIMARY, - BBT_SECONDARY -}; - -struct nand_bbt { - struct nand_chip *chip; - uint32_t primary_map; - uint32_t secondary_map; - enum bbt_place active; - struct bbt_header *hdr; - uint32_t tab_len; - uint32_t *table; -}; - -struct bbt_header { - uint32_t pattern; - int32_t seq_nr; -}; - -static int nand_bbt_save(struct nand_bbt *); -static int nand_bbt_load_hdr(struct nand_bbt *, struct bbt_header *, int8_t); -static int nand_bbt_load_table(struct nand_bbt *); -static int nand_bbt_prescan(struct nand_bbt *); - -int -nand_init_bbt(struct nand_chip *chip) -{ - struct chip_geom *cg; - struct nand_bbt *bbt; - int err; - - cg = &chip->chip_geom; - - bbt = malloc(sizeof(struct nand_bbt), M_NAND, M_ZERO | M_WAITOK); - if (!bbt) { - device_printf(chip->dev, - "Cannot allocate memory for bad block struct"); - return (ENOMEM); - } - - bbt->chip = chip; - bbt->active = BBT_NONE; - bbt->primary_map = cg->chip_size - cg->block_size; - bbt->secondary_map = cg->chip_size - 2 * cg->block_size; - bbt->tab_len = cg->blks_per_chip * sizeof(uint32_t); - bbt->hdr = malloc(sizeof(struct bbt_header) + bbt->tab_len, M_NAND, - M_WAITOK); - if (!bbt->hdr) { - device_printf(chip->dev, "Cannot allocate %d bytes for BB " - "Table", bbt->tab_len); - free(bbt, M_NAND); - return (ENOMEM); - } - bbt->hdr->seq_nr = 0; - bbt->table = (uint32_t *)((uint8_t *)bbt->hdr + - sizeof(struct bbt_header)); - - err = nand_bbt_load_table(bbt); - if (err) { - free(bbt->table, M_NAND); - free(bbt, M_NAND); - return (err); - } - - chip->bbt = bbt; - if (bbt->active == BBT_NONE) { - bbt->active = BBT_PRIMARY; - memset(bbt->table, 0xff, bbt->tab_len); - nand_bbt_prescan(bbt); - nand_bbt_save(bbt); - } else - device_printf(chip->dev, "Found BBT table for chip\n"); - - return (0); -} - -void -nand_destroy_bbt(struct nand_chip *chip) -{ - - if (chip->bbt) { - nand_bbt_save(chip->bbt); - - free(chip->bbt->hdr, M_NAND); - free(chip->bbt, M_NAND); - chip->bbt = NULL; - } -} - -int -nand_update_bbt(struct nand_chip *chip) -{ - - nand_bbt_save(chip->bbt); - - return (0); -} - -static int -nand_bbt_save(struct nand_bbt *bbt) -{ - enum bbt_place next; - uint32_t addr; - int32_t err; - - if (bbt->active == BBT_PRIMARY) { - addr = bbt->secondary_map; - bbt->hdr->pattern = BBT_SECONDARY_PATTERN; - next = BBT_SECONDARY; - } else { - addr = bbt->primary_map; - bbt->hdr->pattern = BBT_PRIMARY_PATTERN; - next = BBT_PRIMARY; - } - - err = nand_erase_blocks(bbt->chip, addr, - bbt->chip->chip_geom.block_size); - if (err) - return (err); - - bbt->hdr->seq_nr++; - - err = nand_prog_pages_raw(bbt->chip, addr, bbt->hdr, - bbt->tab_len + sizeof(struct bbt_header)); - if (err) - return (err); - - bbt->active = next; - return (0); -} - -static int -nand_bbt_load_hdr(struct nand_bbt *bbt, struct bbt_header *hdr, int8_t primary) -{ - uint32_t addr; - - if (primary) - addr = bbt->primary_map; - else - addr = bbt->secondary_map; - - return (nand_read_pages_raw(bbt->chip, addr, hdr, - sizeof(struct bbt_header))); -} - -static int -nand_bbt_load_table(struct nand_bbt *bbt) -{ - struct bbt_header hdr1, hdr2; - uint32_t address = 0; - int err = 0; - - bzero(&hdr1, sizeof(hdr1)); - bzero(&hdr2, sizeof(hdr2)); - - nand_bbt_load_hdr(bbt, &hdr1, 1); - if (hdr1.pattern == BBT_PRIMARY_PATTERN) { - bbt->active = BBT_PRIMARY; - address = bbt->primary_map; - } else - bzero(&hdr1, sizeof(hdr1)); - - - nand_bbt_load_hdr(bbt, &hdr2, 0); - if ((hdr2.pattern == BBT_SECONDARY_PATTERN) && - (hdr2.seq_nr > hdr1.seq_nr)) { - bbt->active = BBT_SECONDARY; - address = bbt->secondary_map; - } else - bzero(&hdr2, sizeof(hdr2)); - - if (bbt->active != BBT_NONE) - err = nand_read_pages_raw(bbt->chip, address, bbt->hdr, - bbt->tab_len + sizeof(struct bbt_header)); - - return (err); -} - -static int -nand_bbt_prescan(struct nand_bbt *bbt) -{ - int32_t i; - uint8_t bad; - bool printed_hash = 0; - - device_printf(bbt->chip->dev, "No BBT found. Prescan chip...\n"); - for (i = 0; i < bbt->chip->chip_geom.blks_per_chip; i++) { - if (NAND_IS_BLK_BAD(bbt->chip->dev, i, &bad)) - return (ENXIO); - - if (bad) { - device_printf(bbt->chip->dev, "Bad block(%d)\n", i); - bbt->table[i] = 0x0FFFFFFF; - } - if (!(i % 100)) { - printf("#"); - printed_hash = 1; - } - } - - if (printed_hash) - printf("\n"); - - return (0); -} - -int -nand_check_bad_block(struct nand_chip *chip, uint32_t block_number) -{ - - if (!chip || !chip->bbt) - return (0); - - if ((chip->bbt->table[block_number] & 0xF0000000) == 0) - return (1); - - return (0); -} - -int -nand_mark_bad_block(struct nand_chip *chip, uint32_t block_number) -{ - - chip->bbt->table[block_number] = 0x0FFFFFFF; - - return (0); -} diff --git a/sys/dev/nand/nand_cdev.c b/sys/dev/nand/nand_cdev.c deleted file mode 100644 index 53c62dbc29135..0000000000000 --- a/sys/dev/nand/nand_cdev.c +++ /dev/null @@ -1,454 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/conf.h> -#include <sys/bus.h> -#include <sys/malloc.h> -#include <sys/uio.h> -#include <sys/bio.h> - -#include <dev/nand/nand.h> -#include <dev/nand/nandbus.h> -#include <dev/nand/nand_dev.h> -#include "nand_if.h" -#include "nandbus_if.h" - -static int nand_page_stat(struct nand_chip *, struct page_stat_io *); -static int nand_block_stat(struct nand_chip *, struct block_stat_io *); - -static d_ioctl_t nand_ioctl; -static d_open_t nand_open; -static d_strategy_t nand_strategy; - -static struct cdevsw nand_cdevsw = { - .d_version = D_VERSION, - .d_name = "nand", - .d_open = nand_open, - .d_read = physread, - .d_write = physwrite, - .d_ioctl = nand_ioctl, - .d_strategy = nand_strategy, -}; - -static int -offset_to_page(struct chip_geom *cg, uint32_t offset) -{ - - return (offset / cg->page_size); -} - -static int -offset_to_page_off(struct chip_geom *cg, uint32_t offset) -{ - - return (offset % cg->page_size); -} - -int -nand_make_dev(struct nand_chip *chip) -{ - struct nandbus_ivar *ivar; - device_t parent, nandbus; - int parent_unit, unit; - char *name; - - ivar = device_get_ivars(chip->dev); - nandbus = device_get_parent(chip->dev); - - if (ivar->chip_cdev_name) { - name = ivar->chip_cdev_name; - - /* - * If we got distinct name for chip device we can enumarete it - * based on contoller number. - */ - parent = device_get_parent(nandbus); - } else { - name = "nand"; - parent = nandbus; - } - - parent_unit = device_get_unit(parent); - unit = parent_unit * 4 + chip->num; - chip->cdev = make_dev(&nand_cdevsw, unit, UID_ROOT, GID_WHEEL, - 0666, "%s%d.%d", name, parent_unit, chip->num); - - if (chip->cdev == NULL) - return (ENXIO); - - if (bootverbose) - device_printf(chip->dev, "Created cdev %s%d.%d for chip " - "[0x%0x, 0x%0x]\n", name, parent_unit, chip->num, - ivar->man_id, ivar->dev_id); - - chip->cdev->si_drv1 = chip; - - return (0); -} - -void -nand_destroy_dev(struct nand_chip *chip) -{ - - if (chip->cdev) - destroy_dev(chip->cdev); -} - -static int -nand_open(struct cdev *dev, int oflags, int devtype, struct thread *td) -{ - - return (0); -} - -static int -nand_read(struct nand_chip *chip, uint32_t offset, void *buf, uint32_t len) -{ - struct chip_geom *cg; - device_t nandbus; - int start_page, count, off, err = 0; - uint8_t *ptr, *tmp; - - nand_debug(NDBG_CDEV, "Read from chip%d [%p] at %d\n", chip->num, - chip, offset); - - nandbus = device_get_parent(chip->dev); - NANDBUS_LOCK(nandbus); - NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num); - - cg = &chip->chip_geom; - start_page = offset_to_page(cg, offset); - off = offset_to_page_off(cg, offset); - count = (len > cg->page_size - off) ? cg->page_size - off : len; - - ptr = (uint8_t *)buf; - while (len > 0) { - if (len < cg->page_size) { - tmp = malloc(cg->page_size, M_NAND, M_WAITOK); - if (!tmp) { - err = ENOMEM; - break; - } - err = NAND_READ_PAGE(chip->dev, start_page, - tmp, cg->page_size, 0); - if (err) { - free(tmp, M_NAND); - break; - } - bcopy(tmp + off, ptr, count); - free(tmp, M_NAND); - } else { - err = NAND_READ_PAGE(chip->dev, start_page, - ptr, cg->page_size, 0); - if (err) - break; - } - - len -= count; - start_page++; - ptr += count; - count = (len > cg->page_size) ? cg->page_size : len; - off = 0; - } - - NANDBUS_UNLOCK(nandbus); - return (err); -} - -static int -nand_write(struct nand_chip *chip, uint32_t offset, void* buf, uint32_t len) -{ - struct chip_geom *cg; - device_t nandbus; - int off, start_page, err = 0; - uint8_t *ptr; - - nand_debug(NDBG_CDEV, "Write to chip %d [%p] at %d\n", chip->num, - chip, offset); - - nandbus = device_get_parent(chip->dev); - NANDBUS_LOCK(nandbus); - NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num); - - cg = &chip->chip_geom; - start_page = offset_to_page(cg, offset); - off = offset_to_page_off(cg, offset); - - if (off != 0 || (len % cg->page_size) != 0) { - printf("Not aligned write start [0x%08x] size [0x%08x]\n", - off, len); - NANDBUS_UNLOCK(nandbus); - return (EINVAL); - } - - ptr = (uint8_t *)buf; - while (len > 0) { - err = NAND_PROGRAM_PAGE(chip->dev, start_page, ptr, - cg->page_size, 0); - if (err) - break; - - len -= cg->page_size; - start_page++; - ptr += cg->page_size; - } - - NANDBUS_UNLOCK(nandbus); - return (err); -} - -static void -nand_strategy(struct bio *bp) -{ - struct nand_chip *chip; - struct cdev *dev; - int err = 0; - - dev = bp->bio_dev; - chip = dev->si_drv1; - - nand_debug(NDBG_CDEV, "Strategy %s on chip %d [%p]\n", - bp->bio_cmd == BIO_READ ? "READ" : "WRITE", - chip->num, chip); - - if (bp->bio_cmd == BIO_READ) { - err = nand_read(chip, - bp->bio_offset & 0xffffffff, - bp->bio_data, bp->bio_bcount); - } else { - err = nand_write(chip, - bp->bio_offset & 0xffffffff, - bp->bio_data, bp->bio_bcount); - } - - if (err == 0) - bp->bio_resid = 0; - else { - bp->bio_error = EIO; - bp->bio_flags |= BIO_ERROR; - bp->bio_resid = bp->bio_bcount; - } - - biodone(bp); -} - -static int -nand_oob_access(struct nand_chip *chip, uint32_t page, uint32_t offset, - uint32_t len, uint8_t *data, uint8_t write) -{ - struct chip_geom *cg; - uint8_t *buf = NULL; - int ret = 0; - - cg = &chip->chip_geom; - - buf = malloc(cg->oob_size, M_NAND, M_WAITOK); - if (!buf) - return (ENOMEM); - - memset(buf, 0xff, cg->oob_size); - - if (!write) { - ret = nand_read_oob(chip, page, buf, cg->oob_size); - copyout(buf, data, len); - } else { - copyin(data, buf, len); - ret = nand_prog_oob(chip, page, buf, cg->oob_size); - } - - free(buf, M_NAND); - - return (ret); -} - -static int -nand_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, - struct thread *td) -{ - struct nand_chip *chip; - struct chip_geom *cg; - struct nand_oob_rw *oob_rw = NULL; - struct nand_raw_rw *raw_rw = NULL; - device_t nandbus; - size_t bufsize = 0, len = 0; - size_t raw_size; - off_t off; - uint8_t *buf = NULL; - int ret = 0; - uint8_t status; - - chip = (struct nand_chip *)dev->si_drv1; - cg = &chip->chip_geom; - nandbus = device_get_parent(chip->dev); - - if ((cmd == NAND_IO_RAW_READ) || (cmd == NAND_IO_RAW_PROG)) { - raw_rw = (struct nand_raw_rw *)data; - raw_size = cg->pgs_per_blk * (cg->page_size + cg->oob_size); - - /* Check if len is not bigger than chip size */ - if (raw_rw->len > raw_size) - return (EFBIG); - - /* - * Do not ask for too much memory, in case of large transfers - * read/write in 16-pages chunks - */ - bufsize = 16 * (cg->page_size + cg->oob_size); - if (raw_rw->len < bufsize) - bufsize = raw_rw->len; - - buf = malloc(bufsize, M_NAND, M_WAITOK); - len = raw_rw->len; - off = 0; - } - switch(cmd) { - case NAND_IO_ERASE: - ret = nand_erase_blocks(chip, ((off_t *)data)[0], - ((off_t *)data)[1]); - break; - - case NAND_IO_OOB_READ: - oob_rw = (struct nand_oob_rw *)data; - ret = nand_oob_access(chip, oob_rw->page, 0, - oob_rw->len, oob_rw->data, 0); - break; - - case NAND_IO_OOB_PROG: - oob_rw = (struct nand_oob_rw *)data; - ret = nand_oob_access(chip, oob_rw->page, 0, - oob_rw->len, oob_rw->data, 1); - break; - - case NAND_IO_GET_STATUS: - NANDBUS_LOCK(nandbus); - ret = NANDBUS_GET_STATUS(nandbus, &status); - if (ret == 0) - *(uint8_t *)data = status; - NANDBUS_UNLOCK(nandbus); - break; - - case NAND_IO_RAW_PROG: - while (len > 0) { - if (len < bufsize) - bufsize = len; - ret = copyin(raw_rw->data + off, buf, bufsize); - if (ret) - break; - ret = nand_prog_pages_raw(chip, raw_rw->off + off, buf, - bufsize); - if (ret) - break; - len -= bufsize; - off += bufsize; - } - break; - - case NAND_IO_RAW_READ: - while (len > 0) { - if (len < bufsize) - bufsize = len; - - ret = nand_read_pages_raw(chip, raw_rw->off + off, buf, - bufsize); - if (ret) - break; - - ret = copyout(buf, raw_rw->data + off, bufsize); - if (ret) - break; - len -= bufsize; - off += bufsize; - } - break; - - case NAND_IO_PAGE_STAT: - ret = nand_page_stat(chip, (struct page_stat_io *)data); - break; - - case NAND_IO_BLOCK_STAT: - ret = nand_block_stat(chip, (struct block_stat_io *)data); - break; - - case NAND_IO_GET_CHIP_PARAM: - nand_get_chip_param(chip, (struct chip_param_io *)data); - break; - - default: - printf("Unknown nand_ioctl request \n"); - ret = EIO; - } - - if (buf) - free(buf, M_NAND); - - return (ret); -} - -static int -nand_page_stat(struct nand_chip *chip, struct page_stat_io *page_stat) -{ - struct chip_geom *cg; - struct page_stat *stat; - int num_pages; - - cg = &chip->chip_geom; - num_pages = cg->pgs_per_blk * cg->blks_per_lun * cg->luns; - if (page_stat->page_num >= num_pages) - return (EINVAL); - - stat = &chip->pg_stat[page_stat->page_num]; - page_stat->page_read = stat->page_read; - page_stat->page_written = stat->page_written; - page_stat->page_raw_read = stat->page_raw_read; - page_stat->page_raw_written = stat->page_raw_written; - page_stat->ecc_succeded = stat->ecc_stat.ecc_succeded; - page_stat->ecc_corrected = stat->ecc_stat.ecc_corrected; - page_stat->ecc_failed = stat->ecc_stat.ecc_failed; - - return (0); -} - -static int -nand_block_stat(struct nand_chip *chip, struct block_stat_io *block_stat) -{ - struct chip_geom *cg; - uint32_t block_num = block_stat->block_num; - - cg = &chip->chip_geom; - if (block_num >= cg->blks_per_lun * cg->luns) - return (EINVAL); - - block_stat->block_erased = chip->blk_stat[block_num].block_erased; - - return (0); -} diff --git a/sys/dev/nand/nand_dev.h b/sys/dev/nand/nand_dev.h deleted file mode 100644 index bd00c4d4b3b4d..0000000000000 --- a/sys/dev/nand/nand_dev.h +++ /dev/null @@ -1,92 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _DEV_NAND_CDEV_H_ -#define _DEV_NAND_CDEV_H_ - -#include <sys/ioccom.h> -#include <sys/param.h> - -struct nand_raw_rw { - off_t off; - off_t len; - uint8_t *data; -}; - -struct nand_oob_rw { - uint32_t page; - off_t len; - uint8_t *data; -}; - -#define NAND_IOCTL_GROUP 'N' -#define NAND_IO_ERASE _IOWR(NAND_IOCTL_GROUP, 0x0, off_t[2]) - -#define NAND_IO_OOB_READ _IOWR(NAND_IOCTL_GROUP, 0x1, struct nand_oob_rw) - -#define NAND_IO_OOB_PROG _IOWR(NAND_IOCTL_GROUP, 0x2, struct nand_oob_rw) - -#define NAND_IO_RAW_READ _IOWR(NAND_IOCTL_GROUP, 0x3, struct nand_raw_rw) - -#define NAND_IO_RAW_PROG _IOWR(NAND_IOCTL_GROUP, 0x4, struct nand_raw_rw) - -#define NAND_IO_GET_STATUS _IOWR(NAND_IOCTL_GROUP, 0x5, uint8_t) - -struct page_stat_io { - uint32_t page_num; - uint32_t page_read; - uint32_t page_written; - uint32_t page_raw_read; - uint32_t page_raw_written; - uint32_t ecc_succeded; - uint32_t ecc_corrected; - uint32_t ecc_failed; -}; -#define NAND_IO_PAGE_STAT _IOWR(NAND_IOCTL_GROUP, 0x6, \ - struct page_stat_io) - -struct block_stat_io { - uint32_t block_num; - uint32_t block_erased; -}; -#define NAND_IO_BLOCK_STAT _IOWR(NAND_IOCTL_GROUP, 0x7, \ - struct block_stat_io) - -struct chip_param_io { - uint32_t page_size; - uint32_t oob_size; - - uint32_t blocks; - uint32_t pages_per_block; -}; -#define NAND_IO_GET_CHIP_PARAM _IOWR(NAND_IOCTL_GROUP, 0x8, \ - struct chip_param_io) - -#endif /* _DEV_NAND_CDEV_H_ */ diff --git a/sys/dev/nand/nand_ecc_pos.h b/sys/dev/nand/nand_ecc_pos.h deleted file mode 100644 index 835f45e6c0836..0000000000000 --- a/sys/dev/nand/nand_ecc_pos.h +++ /dev/null @@ -1,58 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _DEV_NAND_ECC_POS_H_ -#define _DEV_NAND_ECC_POS_H_ - -static uint16_t default_software_ecc_positions_16[] = {2, 0, 1, 7, 4, 6}; - -static uint16_t default_software_ecc_positions_64[] = { - - 42, 40, 41, 45, 43, 44, 48, 46, - 47, 51, 49, 50, 54, 52, 53, 57, - 55, 56, 60, 58, 59, 63, 61, 62 -}; - -static uint16_t default_software_ecc_positions_128[] = { - 8, 9, 10, 11, 12, 13, - 18, 19, 20, 21, 22, 23, - 28, 29, 30, 31, 32, 33, - 38, 39, 40, 41, 42, 43, - 48, 49, 50, 51, 52, 53, - 58, 59, 60, 61, 62, 63, - 68, 69, 70, 71, 72, 73, - 78, 79, 80, 81, 82, 83, - 88, 89, 90, 91, 92, 93, - 98, 99, 100, 101, 102, 103, - 108, 109, 110, 111, 112, 113, - 118, 119, 120, 121, 122, 123, -}; -#endif /* _DEV_NAND_ECC_POS_H_ */ - diff --git a/sys/dev/nand/nand_generic.c b/sys/dev/nand/nand_generic.c deleted file mode 100644 index cc6ef9bd57b07..0000000000000 --- a/sys/dev/nand/nand_generic.c +++ /dev/null @@ -1,1366 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* Generic NAND driver */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/proc.h> -#include <sys/bus.h> -#include <sys/conf.h> -#include <sys/endian.h> -#include <sys/kernel.h> -#include <sys/module.h> -#include <sys/rman.h> -#include <sys/lock.h> -#include <sys/mutex.h> -#include <sys/time.h> -#include <sys/malloc.h> - -#include <dev/nand/nand.h> -#include <dev/nand/nandbus.h> -#include "nfc_if.h" -#include "nand_if.h" -#include "nandbus_if.h" - - -static int onfi_nand_probe(device_t dev); -static int large_nand_probe(device_t dev); -static int small_nand_probe(device_t dev); -static int generic_nand_attach(device_t dev); -static int generic_nand_detach(device_t dev); - -static int generic_erase_block(device_t, uint32_t); -static int generic_erase_block_intlv(device_t, uint32_t); -static int generic_read_page (device_t, uint32_t, void *, uint32_t, uint32_t); -static int generic_read_oob(device_t, uint32_t, void *, uint32_t, uint32_t); -static int generic_program_page(device_t, uint32_t, void *, uint32_t, uint32_t); -static int generic_program_page_intlv(device_t, uint32_t, void *, uint32_t, - uint32_t); -static int generic_program_oob(device_t, uint32_t, void *, uint32_t, uint32_t); -static int generic_is_blk_bad(device_t, uint32_t, uint8_t *); -static int generic_get_ecc(device_t, void *, void *, int *); -static int generic_correct_ecc(device_t, void *, void *, void *); - -static int small_read_page(device_t, uint32_t, void *, uint32_t, uint32_t); -static int small_read_oob(device_t, uint32_t, void *, uint32_t, uint32_t); -static int small_program_page(device_t, uint32_t, void *, uint32_t, uint32_t); -static int small_program_oob(device_t, uint32_t, void *, uint32_t, uint32_t); - -static int onfi_is_blk_bad(device_t, uint32_t, uint8_t *); -static int onfi_read_parameter(struct nand_chip *, struct onfi_chip_params *); - -static int nand_send_address(device_t, int32_t, int32_t, int8_t); - -static device_method_t onand_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, onfi_nand_probe), - DEVMETHOD(device_attach, generic_nand_attach), - DEVMETHOD(device_detach, generic_nand_detach), - - DEVMETHOD(nand_read_page, generic_read_page), - DEVMETHOD(nand_program_page, generic_program_page), - DEVMETHOD(nand_program_page_intlv, generic_program_page_intlv), - DEVMETHOD(nand_read_oob, generic_read_oob), - DEVMETHOD(nand_program_oob, generic_program_oob), - DEVMETHOD(nand_erase_block, generic_erase_block), - DEVMETHOD(nand_erase_block_intlv, generic_erase_block_intlv), - - DEVMETHOD(nand_is_blk_bad, onfi_is_blk_bad), - DEVMETHOD(nand_get_ecc, generic_get_ecc), - DEVMETHOD(nand_correct_ecc, generic_correct_ecc), - { 0, 0 } -}; - -static device_method_t lnand_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, large_nand_probe), - DEVMETHOD(device_attach, generic_nand_attach), - DEVMETHOD(device_detach, generic_nand_detach), - - DEVMETHOD(nand_read_page, generic_read_page), - DEVMETHOD(nand_program_page, generic_program_page), - DEVMETHOD(nand_read_oob, generic_read_oob), - DEVMETHOD(nand_program_oob, generic_program_oob), - DEVMETHOD(nand_erase_block, generic_erase_block), - - DEVMETHOD(nand_is_blk_bad, generic_is_blk_bad), - DEVMETHOD(nand_get_ecc, generic_get_ecc), - DEVMETHOD(nand_correct_ecc, generic_correct_ecc), - { 0, 0 } -}; - -static device_method_t snand_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, small_nand_probe), - DEVMETHOD(device_attach, generic_nand_attach), - DEVMETHOD(device_detach, generic_nand_detach), - - DEVMETHOD(nand_read_page, small_read_page), - DEVMETHOD(nand_program_page, small_program_page), - DEVMETHOD(nand_read_oob, small_read_oob), - DEVMETHOD(nand_program_oob, small_program_oob), - DEVMETHOD(nand_erase_block, generic_erase_block), - - DEVMETHOD(nand_is_blk_bad, generic_is_blk_bad), - DEVMETHOD(nand_get_ecc, generic_get_ecc), - DEVMETHOD(nand_correct_ecc, generic_correct_ecc), - { 0, 0 } -}; - -devclass_t onand_devclass; -devclass_t lnand_devclass; -devclass_t snand_devclass; - -driver_t onand_driver = { - "onand", - onand_methods, - sizeof(struct nand_chip) -}; - -driver_t lnand_driver = { - "lnand", - lnand_methods, - sizeof(struct nand_chip) -}; - -driver_t snand_driver = { - "snand", - snand_methods, - sizeof(struct nand_chip) -}; - -DRIVER_MODULE(onand, nandbus, onand_driver, onand_devclass, 0, 0); -DRIVER_MODULE(lnand, nandbus, lnand_driver, lnand_devclass, 0, 0); -DRIVER_MODULE(snand, nandbus, snand_driver, snand_devclass, 0, 0); - -static int -onfi_nand_probe(device_t dev) -{ - struct nandbus_ivar *ivar; - - ivar = device_get_ivars(dev); - if (ivar && ivar->is_onfi) { - device_set_desc(dev, "ONFI compliant NAND"); - return (BUS_PROBE_DEFAULT); - } - - return (ENODEV); -} - -static int -large_nand_probe(device_t dev) -{ - struct nandbus_ivar *ivar; - - ivar = device_get_ivars(dev); - if (ivar && !ivar->is_onfi && ivar->params->page_size >= 512) { - device_set_desc(dev, ivar->params->name); - return (BUS_PROBE_DEFAULT); - } - - return (ENODEV); -} - -static int -small_nand_probe(device_t dev) -{ - struct nandbus_ivar *ivar; - - ivar = device_get_ivars(dev); - if (ivar && !ivar->is_onfi && ivar->params->page_size == 512) { - device_set_desc(dev, ivar->params->name); - return (BUS_PROBE_DEFAULT); - } - - return (ENODEV); -} - -static int -generic_nand_attach(device_t dev) -{ - struct nand_chip *chip; - struct nandbus_ivar *ivar; - struct onfi_chip_params *onfi_chip_params; - device_t nandbus, nfc; - int err; - - chip = device_get_softc(dev); - chip->dev = dev; - - ivar = device_get_ivars(dev); - chip->id.man_id = ivar->man_id; - chip->id.dev_id = ivar->dev_id; - chip->num = ivar->cs; - - /* TODO remove when HW ECC supported */ - nandbus = device_get_parent(dev); - nfc = device_get_parent(nandbus); - - chip->nand = device_get_softc(nfc); - - if (ivar->is_onfi) { - onfi_chip_params = malloc(sizeof(struct onfi_chip_params), - M_NAND, M_WAITOK | M_ZERO); - - if (onfi_read_parameter(chip, onfi_chip_params)) { - nand_debug(NDBG_GEN,"Could not read parameter page!\n"); - free(onfi_chip_params, M_NAND); - return (ENXIO); - } - - nand_onfi_set_params(chip, onfi_chip_params); - /* Set proper column and row cycles */ - ivar->cols = (onfi_chip_params->address_cycles >> 4) & 0xf; - ivar->rows = onfi_chip_params->address_cycles & 0xf; - free(onfi_chip_params, M_NAND); - - } else { - nand_set_params(chip, ivar->params); - } - - err = nand_init_stat(chip); - if (err) { - generic_nand_detach(dev); - return (err); - } - - err = nand_init_bbt(chip); - if (err) { - generic_nand_detach(dev); - return (err); - } - - err = nand_make_dev(chip); - if (err) { - generic_nand_detach(dev); - return (err); - } - - err = create_geom_disk(chip); - if (err) { - generic_nand_detach(dev); - return (err); - } - - return (0); -} - -static int -generic_nand_detach(device_t dev) -{ - struct nand_chip *chip; - - chip = device_get_softc(dev); - - nand_destroy_bbt(chip); - destroy_geom_disk(chip); - nand_destroy_dev(chip); - nand_destroy_stat(chip); - - return (0); -} - -static int -can_write(device_t nandbus) -{ - uint8_t status; - - if (NANDBUS_WAIT_READY(nandbus, &status)) - return (0); - - if (!(status & NAND_STATUS_WP)) { - nand_debug(NDBG_GEN,"Chip is write-protected"); - return (0); - } - - return (1); -} - -static int -check_fail(device_t nandbus) -{ - uint8_t status; - - NANDBUS_WAIT_READY(nandbus, &status); - if (status & NAND_STATUS_FAIL) { - nand_debug(NDBG_GEN,"Status failed %x", status); - return (ENXIO); - } - - return (0); -} - -static uint16_t -onfi_crc(const void *buf, size_t buflen) -{ - int i, j; - uint16_t crc; - const uint8_t *bufptr; - - bufptr = buf; - crc = 0x4f4e; - for (j = 0; j < buflen; j++) { - crc ^= *bufptr++ << 8; - for (i = 0; i < 8; i++) - if (crc & 0x8000) - crc = (crc << 1) ^ 0x8005; - else - crc <<= 1; - } - return crc; -} - -static int -onfi_read_parameter(struct nand_chip *chip, struct onfi_chip_params *chip_params) -{ - device_t nandbus; - struct onfi_params params; - int found, sigcount, trycopy; - - nand_debug(NDBG_GEN,"read parameter"); - - nandbus = device_get_parent(chip->dev); - - NANDBUS_SELECT_CS(nandbus, chip->num); - - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_READ_PARAMETER)) - return (ENXIO); - - if (nand_send_address(chip->dev, -1, -1, PAGE_PARAMETER_DEF)) - return (ENXIO); - - if (NANDBUS_START_COMMAND(nandbus)) - return (ENXIO); - - /* - * XXX Bogus DELAY, we really need a nandbus_wait_ready() here, but it's - * not accessible from here (static to nandbus). - */ - DELAY(1000); - - /* - * The ONFI spec mandates a minimum of three copies of the parameter - * data, so loop up to 3 times trying to find good data. Each copy is - * validated by a signature of "ONFI" and a crc. There is a very strange - * rule that the signature is valid if any 2 of the 4 bytes are correct. - */ - for (found= 0, trycopy = 0; !found && trycopy < 3; trycopy++) { - NANDBUS_READ_BUFFER(nandbus, ¶ms, sizeof(struct onfi_params)); - sigcount = params.signature[0] == 'O'; - sigcount += params.signature[1] == 'N'; - sigcount += params.signature[2] == 'F'; - sigcount += params.signature[3] == 'I'; - if (sigcount < 2) - continue; - if (onfi_crc(¶ms, 254) != params.crc) - continue; - found = 1; - } - if (!found) - return (ENXIO); - - chip_params->luns = params.luns; - chip_params->blocks_per_lun = le32dec(¶ms.blocks_per_lun); - chip_params->pages_per_block = le32dec(¶ms.pages_per_block); - chip_params->bytes_per_page = le32dec(¶ms.bytes_per_page); - chip_params->spare_bytes_per_page = le16dec(¶ms.spare_bytes_per_page); - chip_params->t_bers = le16dec(¶ms.t_bers); - chip_params->t_prog = le16dec(¶ms.t_prog); - chip_params->t_r = le16dec(¶ms.t_r); - chip_params->t_ccs = le16dec(¶ms.t_ccs); - chip_params->features = le16dec(¶ms.features); - chip_params->address_cycles = params.address_cycles; - - return (0); -} - -static int -send_read_page(device_t nand, uint8_t start_command, uint8_t end_command, - uint32_t row, uint32_t column) -{ - device_t nandbus = device_get_parent(nand); - - if (NANDBUS_SEND_COMMAND(nandbus, start_command)) - return (ENXIO); - - if (nand_send_address(nand, row, column, -1)) - return (ENXIO); - - if (NANDBUS_SEND_COMMAND(nandbus, end_command)) - return (ENXIO); - - if (NANDBUS_START_COMMAND(nandbus)) - return (ENXIO); - - return (0); -} - -static int -generic_read_page(device_t nand, uint32_t page, void *buf, uint32_t len, - uint32_t offset) -{ - struct nand_chip *chip; - struct page_stat *pg_stat; - device_t nandbus; - uint32_t row; - - nand_debug(NDBG_GEN,"%p raw read page %x[%x] at %x", nand, page, len, offset); - chip = device_get_softc(nand); - nandbus = device_get_parent(nand); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - - if (send_read_page(nand, NAND_CMD_READ, NAND_CMD_READ_END, row, - offset)) - return (ENXIO); - - DELAY(chip->t_r); - - NANDBUS_READ_BUFFER(nandbus, buf, len); - - if (check_fail(nandbus)) - return (ENXIO); - - pg_stat = &(chip->pg_stat[page]); - pg_stat->page_raw_read++; - - return (0); -} - -static int -generic_read_oob(device_t nand, uint32_t page, void* buf, uint32_t len, - uint32_t offset) -{ - struct nand_chip *chip; - device_t nandbus; - uint32_t row; - - nand_debug(NDBG_GEN,"%p raw read oob %x[%x] at %x", nand, page, len, offset); - chip = device_get_softc(nand); - nandbus = device_get_parent(nand); - - if (nand_check_page_boundary(chip, page)) { - nand_debug(NDBG_GEN,"page boundary check failed: %08x\n", page); - return (ENXIO); - } - - page_to_row(&chip->chip_geom, page, &row); - - offset += chip->chip_geom.page_size; - - if (send_read_page(nand, NAND_CMD_READ, NAND_CMD_READ_END, row, - offset)) - return (ENXIO); - - DELAY(chip->t_r); - - NANDBUS_READ_BUFFER(nandbus, buf, len); - - if (check_fail(nandbus)) - return (ENXIO); - - return (0); -} - -static int -send_start_program_page(device_t nand, uint32_t row, uint32_t column) -{ - device_t nandbus = device_get_parent(nand); - - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_PROG)) - return (ENXIO); - - if (nand_send_address(nand, row, column, -1)) - return (ENXIO); - - return (0); -} - -static int -send_end_program_page(device_t nandbus, uint8_t end_command) -{ - - if (NANDBUS_SEND_COMMAND(nandbus, end_command)) - return (ENXIO); - - if (NANDBUS_START_COMMAND(nandbus)) - return (ENXIO); - - return (0); -} - -static int -generic_program_page(device_t nand, uint32_t page, void *buf, uint32_t len, - uint32_t offset) -{ - struct nand_chip *chip; - struct page_stat *pg_stat; - device_t nandbus; - uint32_t row; - - nand_debug(NDBG_GEN,"%p raw prog page %x[%x] at %x", nand, page, len, - offset); - chip = device_get_softc(nand); - nandbus = device_get_parent(nand); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - - if (!can_write(nandbus)) - return (ENXIO); - - if (send_start_program_page(nand, row, offset)) - return (ENXIO); - - NANDBUS_WRITE_BUFFER(nandbus, buf, len); - - if (send_end_program_page(nandbus, NAND_CMD_PROG_END)) - return (ENXIO); - - DELAY(chip->t_prog); - - if (check_fail(nandbus)) - return (ENXIO); - - pg_stat = &(chip->pg_stat[page]); - pg_stat->page_raw_written++; - - return (0); -} - -static int -generic_program_page_intlv(device_t nand, uint32_t page, void *buf, - uint32_t len, uint32_t offset) -{ - struct nand_chip *chip; - struct page_stat *pg_stat; - device_t nandbus; - uint32_t row; - - nand_debug(NDBG_GEN,"%p raw prog page %x[%x] at %x", nand, page, len, offset); - chip = device_get_softc(nand); - nandbus = device_get_parent(nand); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - - if (!can_write(nandbus)) - return (ENXIO); - - if (send_start_program_page(nand, row, offset)) - return (ENXIO); - - NANDBUS_WRITE_BUFFER(nandbus, buf, len); - - if (send_end_program_page(nandbus, NAND_CMD_PROG_INTLV)) - return (ENXIO); - - DELAY(chip->t_prog); - - if (check_fail(nandbus)) - return (ENXIO); - - pg_stat = &(chip->pg_stat[page]); - pg_stat->page_raw_written++; - - return (0); -} - -static int -generic_program_oob(device_t nand, uint32_t page, void* buf, uint32_t len, - uint32_t offset) -{ - struct nand_chip *chip; - device_t nandbus; - uint32_t row; - - nand_debug(NDBG_GEN,"%p raw prog oob %x[%x] at %x", nand, page, len, - offset); - chip = device_get_softc(nand); - nandbus = device_get_parent(nand); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - offset += chip->chip_geom.page_size; - - if (!can_write(nandbus)) - return (ENXIO); - - if (send_start_program_page(nand, row, offset)) - return (ENXIO); - - NANDBUS_WRITE_BUFFER(nandbus, buf, len); - - if (send_end_program_page(nandbus, NAND_CMD_PROG_END)) - return (ENXIO); - - DELAY(chip->t_prog); - - if (check_fail(nandbus)) - return (ENXIO); - - return (0); -} - -static int -send_erase_block(device_t nand, uint32_t row, uint8_t second_command) -{ - device_t nandbus = device_get_parent(nand); - - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_ERASE)) - return (ENXIO); - - if (nand_send_address(nand, row, -1, -1)) - return (ENXIO); - - if (NANDBUS_SEND_COMMAND(nandbus, second_command)) - return (ENXIO); - - if (NANDBUS_START_COMMAND(nandbus)) - return (ENXIO); - - return (0); -} - -static int -generic_erase_block(device_t nand, uint32_t block) -{ - struct block_stat *blk_stat; - struct nand_chip *chip; - device_t nandbus; - int row; - - nand_debug(NDBG_GEN,"%p erase block %x", nand, block); - nandbus = device_get_parent(nand); - chip = device_get_softc(nand); - - if (block >= (chip->chip_geom.blks_per_lun * chip->chip_geom.luns)) - return (ENXIO); - - row = (block << chip->chip_geom.blk_shift) & - chip->chip_geom.blk_mask; - - nand_debug(NDBG_GEN,"%p erase block row %x", nand, row); - - if (!can_write(nandbus)) - return (ENXIO); - - send_erase_block(nand, row, NAND_CMD_ERASE_END); - - DELAY(chip->t_bers); - - if (check_fail(nandbus)) - return (ENXIO); - - blk_stat = &(chip->blk_stat[block]); - blk_stat->block_erased++; - - return (0); -} - -static int -generic_erase_block_intlv(device_t nand, uint32_t block) -{ - struct block_stat *blk_stat; - struct nand_chip *chip; - device_t nandbus; - int row; - - nand_debug(NDBG_GEN,"%p erase block %x", nand, block); - nandbus = device_get_parent(nand); - chip = device_get_softc(nand); - - if (block >= (chip->chip_geom.blks_per_lun * chip->chip_geom.luns)) - return (ENXIO); - - row = (block << chip->chip_geom.blk_shift) & - chip->chip_geom.blk_mask; - - if (!can_write(nandbus)) - return (ENXIO); - - send_erase_block(nand, row, NAND_CMD_ERASE_INTLV); - - DELAY(chip->t_bers); - - if (check_fail(nandbus)) - return (ENXIO); - - blk_stat = &(chip->blk_stat[block]); - blk_stat->block_erased++; - - return (0); - -} - -static int -onfi_is_blk_bad(device_t device, uint32_t block_number, uint8_t *bad) -{ - struct nand_chip *chip; - int page_number, i, j, err; - uint8_t *oob; - - chip = device_get_softc(device); - - oob = malloc(chip->chip_geom.oob_size, M_NAND, M_WAITOK); - - page_number = block_number * chip->chip_geom.pgs_per_blk; - *bad = 0; - /* Check OOB of first and last page */ - for (i = 0; i < 2; i++, page_number+= chip->chip_geom.pgs_per_blk - 1) { - err = generic_read_oob(device, page_number, oob, - chip->chip_geom.oob_size, 0); - if (err) { - device_printf(device, "%s: cannot allocate oob\n", - __func__); - free(oob, M_NAND); - return (ENOMEM); - } - - for (j = 0; j < chip->chip_geom.oob_size; j++) { - if (!oob[j]) { - *bad = 1; - free(oob, M_NAND); - return (0); - } - } - } - - free(oob, M_NAND); - - return (0); -} - -static int -send_small_read_page(device_t nand, uint8_t start_command, - uint32_t row, uint32_t column) -{ - device_t nandbus = device_get_parent(nand); - - if (NANDBUS_SEND_COMMAND(nandbus, start_command)) - return (ENXIO); - - if (nand_send_address(nand, row, column, -1)) - return (ENXIO); - - if (NANDBUS_START_COMMAND(nandbus)) - return (ENXIO); - - return (0); -} - - -static int -small_read_page(device_t nand, uint32_t page, void *buf, uint32_t len, - uint32_t offset) -{ - struct nand_chip *chip; - struct page_stat *pg_stat; - device_t nandbus; - uint32_t row; - - nand_debug(NDBG_GEN,"%p small read page %x[%x] at %x", nand, page, len, offset); - chip = device_get_softc(nand); - nandbus = device_get_parent(nand); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - - if (offset < 256) { - if (send_small_read_page(nand, NAND_CMD_SMALLA, row, offset)) - return (ENXIO); - } else { - offset -= 256; - if (send_small_read_page(nandbus, NAND_CMD_SMALLB, row, offset)) - return (ENXIO); - } - - DELAY(chip->t_r); - - NANDBUS_READ_BUFFER(nandbus, buf, len); - - if (check_fail(nandbus)) - return (ENXIO); - - pg_stat = &(chip->pg_stat[page]); - pg_stat->page_raw_read++; - - return (0); -} - -static int -small_read_oob(device_t nand, uint32_t page, void *buf, uint32_t len, - uint32_t offset) -{ - struct nand_chip *chip; - struct page_stat *pg_stat; - device_t nandbus; - uint32_t row; - - nand_debug(NDBG_GEN,"%p small read oob %x[%x] at %x", nand, page, len, offset); - chip = device_get_softc(nand); - nandbus = device_get_parent(nand); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - - if (send_small_read_page(nand, NAND_CMD_SMALLOOB, row, 0)) - return (ENXIO); - - DELAY(chip->t_r); - - NANDBUS_READ_BUFFER(nandbus, buf, len); - - if (check_fail(nandbus)) - return (ENXIO); - - pg_stat = &(chip->pg_stat[page]); - pg_stat->page_raw_read++; - - return (0); -} - -static int -small_program_page(device_t nand, uint32_t page, void* buf, uint32_t len, - uint32_t offset) -{ - struct nand_chip *chip; - device_t nandbus; - uint32_t row; - - nand_debug(NDBG_GEN,"%p small prog page %x[%x] at %x", nand, page, len, offset); - chip = device_get_softc(nand); - nandbus = device_get_parent(nand); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - - if (!can_write(nandbus)) - return (ENXIO); - - if (offset < 256) { - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_SMALLA)) - return (ENXIO); - } else { - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_SMALLB)) - return (ENXIO); - } - - if (send_start_program_page(nand, row, offset)) - return (ENXIO); - - NANDBUS_WRITE_BUFFER(nandbus, buf, len); - - if (send_end_program_page(nandbus, NAND_CMD_PROG_END)) - return (ENXIO); - - DELAY(chip->t_prog); - - if (check_fail(nandbus)) - return (ENXIO); - - return (0); -} - -static int -small_program_oob(device_t nand, uint32_t page, void* buf, uint32_t len, - uint32_t offset) -{ - struct nand_chip *chip; - device_t nandbus; - uint32_t row; - - nand_debug(NDBG_GEN,"%p small prog oob %x[%x] at %x", nand, page, len, offset); - chip = device_get_softc(nand); - nandbus = device_get_parent(nand); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - - if (!can_write(nandbus)) - return (ENXIO); - - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_SMALLOOB)) - return (ENXIO); - - if (send_start_program_page(nand, row, offset)) - return (ENXIO); - - NANDBUS_WRITE_BUFFER(nandbus, buf, len); - - if (send_end_program_page(nandbus, NAND_CMD_PROG_END)) - return (ENXIO); - - DELAY(chip->t_prog); - - if (check_fail(nandbus)) - return (ENXIO); - - return (0); -} - -int -nand_send_address(device_t nand, int32_t row, int32_t col, int8_t id) -{ - struct nandbus_ivar *ivar; - device_t nandbus; - uint8_t addr; - int err = 0; - int i; - - nandbus = device_get_parent(nand); - ivar = device_get_ivars(nand); - - if (id != -1) { - nand_debug(NDBG_GEN,"send_address: send id %02x", id); - err = NANDBUS_SEND_ADDRESS(nandbus, id); - } - - if (!err && col != -1) { - for (i = 0; i < ivar->cols; i++, col >>= 8) { - addr = (uint8_t)(col & 0xff); - nand_debug(NDBG_GEN,"send_address: send address column " - "%02x", addr); - err = NANDBUS_SEND_ADDRESS(nandbus, addr); - if (err) - break; - } - } - - if (!err && row != -1) { - for (i = 0; i < ivar->rows; i++, row >>= 8) { - addr = (uint8_t)(row & 0xff); - nand_debug(NDBG_GEN,"send_address: send address row " - "%02x", addr); - err = NANDBUS_SEND_ADDRESS(nandbus, addr); - if (err) - break; - } - } - - return (err); -} - -static int -generic_is_blk_bad(device_t dev, uint32_t block, uint8_t *bad) -{ - struct nand_chip *chip; - int page_number, err, i; - uint8_t *oob; - - chip = device_get_softc(dev); - - oob = malloc(chip->chip_geom.oob_size, M_NAND, M_WAITOK); - - page_number = block * chip->chip_geom.pgs_per_blk; - *bad = 0; - - /* Check OOB of first and second page */ - for (i = 0; i < 2; i++) { - err = NAND_READ_OOB(dev, page_number + i, oob, - chip->chip_geom.oob_size, 0); - if (err) { - device_printf(dev, "%s: cannot allocate OOB\n", - __func__); - free(oob, M_NAND); - return (ENOMEM); - } - - if (!oob[0]) { - *bad = 1; - free(oob, M_NAND); - return (0); - } - } - - free(oob, M_NAND); - - return (0); -} - -static int -generic_get_ecc(device_t dev, void *buf, void *ecc, int *needwrite) -{ - struct nand_chip *chip = device_get_softc(dev); - struct chip_geom *cg = &chip->chip_geom; - - return (NANDBUS_GET_ECC(device_get_parent(dev), buf, cg->page_size, - ecc, needwrite)); -} - -static int -generic_correct_ecc(device_t dev, void *buf, void *readecc, void *calcecc) -{ - struct nand_chip *chip = device_get_softc(dev); - struct chip_geom *cg = &chip->chip_geom; - - return (NANDBUS_CORRECT_ECC(device_get_parent(dev), buf, - cg->page_size, readecc, calcecc)); -} - - -#if 0 -int -nand_chng_read_col(device_t nand, uint32_t col, void *buf, size_t len) -{ - struct nand_chip *chip; - device_t nandbus; - - chip = device_get_softc(nand); - nandbus = device_get_parent(nand); - - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_CHNG_READ_COL)) - return (ENXIO); - - if (NANDBUS_SEND_ADDRESS(nandbus, -1, col, -1)) - return (ENXIO); - - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_CHNG_READ_COL_END)) - return (ENXIO); - - if (NANDBUS_START_COMMAND(nandbus)) - return (ENXIO); - - if (buf != NULL && len > 0) - NANDBUS_READ_BUFFER(nandbus, buf, len); - - return (0); -} - -int -nand_chng_write_col(device_t dev, uint32_t col, void *buf, - size_t len) -{ - struct nand_chip *chip; - device_t nandbus; - - chip = device_get_softc(dev); - nandbus = device_get_parent(dev); - - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_CHNG_WRITE_COL)) - return (ENXIO); - - if (NANDBUS_SEND_ADDRESS(nandbus, -1, col, -1)) - return (ENXIO); - - if (buf != NULL && len > 0) - NANDBUS_WRITE_BUFFER(nandbus, buf, len); - - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_CHNG_READ_COL_END)) - return (ENXIO); - - if (NANDBUS_START_COMMAND(nandbus)) - return (ENXIO); - - return (0); -} - -int -nand_copyback_read(device_t dev, uint32_t page, uint32_t col, - void *buf, size_t len) -{ - struct nand_chip *chip; - struct page_stat *pg_stat; - device_t nandbus; - uint32_t row; - - nand_debug(NDBG_GEN," raw read page %x[%x] at %x", page, col, len); - chip = device_get_softc(dev); - nandbus = device_get_parent(dev); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - - if (send_read_page(nand, NAND_CMD_READ, NAND_CMD_READ_CPBK, row, 0)) - return (ENXIO); - - DELAY(chip->t_r); - if (check_fail(nandbus)) - return (ENXIO); - - if (buf != NULL && len > 0) - NANDBUS_READ_BUFFER(nandbus, buf, len); - - pg_stat = &(chip->pg_stat[page]); - pg_stat->page_raw_read++; - - return (0); -} - -int -nand_copyback_prog(device_t dev, uint32_t page, uint32_t col, - void *buf, size_t len) -{ - struct nand_chip *chip; - struct page_stat *pg_stat; - device_t nandbus; - uint32_t row; - - nand_debug(NDBG_GEN,"copyback prog page %x[%x]", page, len); - chip = device_get_softc(dev); - nandbus = device_get_parent(dev); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - - if (!can_write(nandbus)) - return (ENXIO); - - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_CHNG_WRITE_COL)) - return (ENXIO); - - if (NANDBUS_SEND_ADDRESS(nandbus, row, col, -1)) - return (ENXIO); - - if (buf != NULL && len > 0) - NANDBUS_WRITE_BUFFER(nandbus, buf, len); - - if (send_end_program_page(nandbus, NAND_CMD_PROG_END)) - return (ENXIO); - - DELAY(chip->t_prog); - - if (check_fail(nandbus)) - return (ENXIO); - - pg_stat = &(chip->pg_stat[page]); - pg_stat->page_raw_written++; - - return (0); -} - -int -nand_copyback_prog_intlv(device_t dev, uint32_t page) -{ - struct nand_chip *chip; - struct page_stat *pg_stat; - device_t nandbus; - uint32_t row; - - nand_debug(NDBG_GEN,"cache prog page %x", page); - chip = device_get_softc(dev); - nandbus = device_get_parent(dev); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - - if (!can_write(nandbus)) - return (ENXIO); - - if (send_start_program_page(nand, row, 0)) - return (ENXIO); - - if (send_end_program_page(nandbus, NAND_CMD_PROG_INTLV)) - return (ENXIO); - - DELAY(chip->t_prog); - - if (check_fail(nandbus)) - return (ENXIO); - - pg_stat = &(chip->pg_stat[page]); - pg_stat->page_raw_written++; - - return (0); -} - -int -nand_prog_cache(device_t dev, uint32_t page, uint32_t col, - void *buf, size_t len, uint8_t end) -{ - struct nand_chip *chip; - struct page_stat *pg_stat; - device_t nandbus; - uint32_t row; - uint8_t command; - - nand_debug(NDBG_GEN,"cache prog page %x[%x]", page, len); - chip = device_get_softc(dev); - nandbus = device_get_parent(dev); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - - if (!can_write(nandbus)) - return (ENXIO); - - if (send_start_program_page(dev, row, 0)) - return (ENXIO); - - NANDBUS_WRITE_BUFFER(nandbus, buf, len); - - if (end) - command = NAND_CMD_PROG_END; - else - command = NAND_CMD_PROG_CACHE; - - if (send_end_program_page(nandbus, command)) - return (ENXIO); - - DELAY(chip->t_prog); - - if (check_fail(nandbus)) - return (ENXIO); - - pg_stat = &(chip->pg_stat[page]); - pg_stat->page_raw_written++; - - return (0); -} - -int -nand_read_cache(device_t dev, uint32_t page, uint32_t col, - void *buf, size_t len, uint8_t end) -{ - struct nand_chip *chip; - struct page_stat *pg_stat; - device_t nandbus; - uint32_t row; - uint8_t command; - - nand_debug(NDBG_GEN,"cache read page %x[%x] ", page, len); - chip = device_get_softc(dev); - nandbus = device_get_parent(dev); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - - if (page != -1) { - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_READ)) - return (ENXIO); - - if (NANDBUS_SEND_ADDRESS(nandbus, row, col, -1)) - return (ENXIO); - } - - if (end) - command = NAND_CMD_READ_CACHE_END; - else - command = NAND_CMD_READ_CACHE; - - if (NANDBUS_SEND_COMMAND(nandbus, command)) - return (ENXIO); - - if (NANDBUS_START_COMMAND(nandbus)) - return (ENXIO); - - DELAY(chip->t_r); - if (check_fail(nandbus)) - return (ENXIO); - - if (buf != NULL && len > 0) - NANDBUS_READ_BUFFER(nandbus, buf, len); - - pg_stat = &(chip->pg_stat[page]); - pg_stat->page_raw_read++; - - return (0); -} - -int -nand_get_feature(device_t dev, uint8_t feat, void *buf) -{ - struct nand_chip *chip; - device_t nandbus; - - nand_debug(NDBG_GEN,"nand get feature"); - - chip = device_get_softc(dev); - nandbus = device_get_parent(dev); - - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_GET_FEATURE)) - return (ENXIO); - - if (NANDBUS_SEND_ADDRESS(nandbus, -1, -1, feat)) - return (ENXIO); - - if (NANDBUS_START_COMMAND(nandbus)) - return (ENXIO); - - DELAY(chip->t_r); - NANDBUS_READ_BUFFER(nandbus, buf, 4); - - return (0); -} - -int -nand_set_feature(device_t dev, uint8_t feat, void *buf) -{ - struct nand_chip *chip; - device_t nandbus; - - nand_debug(NDBG_GEN,"nand set feature"); - - chip = device_get_softc(dev); - nandbus = device_get_parent(dev); - - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_SET_FEATURE)) - return (ENXIO); - - if (NANDBUS_SEND_ADDRESS(nandbus, -1, -1, feat)) - return (ENXIO); - - NANDBUS_WRITE_BUFFER(nandbus, buf, 4); - - if (NANDBUS_START_COMMAND(nandbus)) - return (ENXIO); - - return (0); -} -#endif diff --git a/sys/dev/nand/nand_geom.c b/sys/dev/nand/nand_geom.c deleted file mode 100644 index b814ffc4e0a9a..0000000000000 --- a/sys/dev/nand/nand_geom.c +++ /dev/null @@ -1,467 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/conf.h> -#include <sys/bus.h> -#include <sys/malloc.h> -#include <sys/uio.h> -#include <sys/bio.h> -#include <geom/geom.h> -#include <geom/geom_disk.h> - -#include <dev/nand/nand.h> -#include <dev/nand/nandbus.h> -#include <dev/nand/nand_dev.h> -#include "nand_if.h" -#include "nandbus_if.h" - -#define BIO_NAND_STD ((void *)1) -#define BIO_NAND_RAW ((void *)2) - -static disk_ioctl_t nand_ioctl; -static disk_getattr_t nand_getattr; -static disk_strategy_t nand_strategy; -static disk_strategy_t nand_strategy_raw; - -static int -nand_read(struct nand_chip *chip, uint32_t offset, void *buf, uint32_t len) -{ - - nand_debug(NDBG_GEOM, "Read from chip %d [%p] at %d", chip->num, chip, - offset); - - return (nand_read_pages(chip, offset, buf, len)); -} - -static int -nand_write(struct nand_chip *chip, uint32_t offset, void* buf, uint32_t len) -{ - - nand_debug(NDBG_GEOM, "Write to chip %d [%p] at %d", chip->num, chip, - offset); - - return (nand_prog_pages(chip, offset, buf, len)); -} - -static int -nand_read_raw(struct nand_chip *chip, uint32_t offset, void *buf, uint32_t len) -{ - nand_debug(NDBG_GEOM, "Raw read from chip %d [%p] at %d", chip->num, - chip, offset); - - return (nand_read_pages_raw(chip, offset, buf, len)); -} - -static int -nand_write_raw(struct nand_chip *chip, uint32_t offset, void *buf, uint32_t len) -{ - - nand_debug(NDBG_GEOM, "Raw write to chip %d [%p] at %d", chip->num, - chip, offset); - - return (nand_prog_pages_raw(chip, offset, buf, len)); -} - -static void -nand_strategy(struct bio *bp) -{ - struct nand_chip *chip; - - chip = (struct nand_chip *)bp->bio_disk->d_drv1; - - bp->bio_driver1 = BIO_NAND_STD; - - nand_debug(NDBG_GEOM, "Strategy %s on chip %d [%p]", - bp->bio_cmd == BIO_READ ? "READ" : - (bp->bio_cmd == BIO_WRITE ? "WRITE" : - (bp->bio_cmd == BIO_DELETE ? "DELETE" : "UNKNOWN")), - chip->num, chip); - - mtx_lock(&chip->qlock); - bioq_insert_tail(&chip->bioq, bp); - mtx_unlock(&chip->qlock); - taskqueue_enqueue(chip->tq, &chip->iotask); -} - -static void -nand_strategy_raw(struct bio *bp) -{ - struct nand_chip *chip; - - chip = (struct nand_chip *)bp->bio_disk->d_drv1; - - /* Inform taskqueue that it's a raw access */ - bp->bio_driver1 = BIO_NAND_RAW; - - nand_debug(NDBG_GEOM, "Strategy %s on chip %d [%p]", - bp->bio_cmd == BIO_READ ? "READ" : - (bp->bio_cmd == BIO_WRITE ? "WRITE" : - (bp->bio_cmd == BIO_DELETE ? "DELETE" : "UNKNOWN")), - chip->num, chip); - - mtx_lock(&chip->qlock); - bioq_insert_tail(&chip->bioq, bp); - mtx_unlock(&chip->qlock); - taskqueue_enqueue(chip->tq, &chip->iotask); -} - -static int -nand_oob_access(struct nand_chip *chip, uint32_t page, uint32_t offset, - uint32_t len, uint8_t *data, uint8_t write) -{ - struct chip_geom *cg; - int ret = 0; - - cg = &chip->chip_geom; - - if (!write) - ret = nand_read_oob(chip, page, data, cg->oob_size); - else - ret = nand_prog_oob(chip, page, data, cg->oob_size); - - return (ret); -} - -static int -nand_getattr(struct bio *bp) -{ - struct nand_chip *chip; - struct chip_geom *cg; - device_t dev; - int val; - - if (bp->bio_disk == NULL || bp->bio_disk->d_drv1 == NULL) - return (ENXIO); - - chip = (struct nand_chip *)bp->bio_disk->d_drv1; - cg = &(chip->chip_geom); - - dev = device_get_parent(chip->dev); - dev = device_get_parent(dev); - - if (strcmp(bp->bio_attribute, "NAND::device") == 0) { - if (bp->bio_length != sizeof(dev)) - return (EFAULT); - bcopy(&dev, bp->bio_data, sizeof(dev)); - } else { - if (strcmp(bp->bio_attribute, "NAND::oobsize") == 0) - val = cg->oob_size; - else if (strcmp(bp->bio_attribute, "NAND::pagesize") == 0) - val = cg->page_size; - else if (strcmp(bp->bio_attribute, "NAND::blocksize") == 0) - val = cg->block_size; - else - return (-1); - if (bp->bio_length != sizeof(val)) - return (EFAULT); - bcopy(&val, bp->bio_data, sizeof(val)); - } - bp->bio_completed = bp->bio_length; - return (0); -} - -static int -nand_ioctl(struct disk *ndisk, u_long cmd, void *data, int fflag, - struct thread *td) -{ - struct nand_chip *chip; - struct chip_geom *cg; - struct nand_oob_rw *oob_rw = NULL; - struct nand_raw_rw *raw_rw = NULL; - device_t nandbus; - size_t bufsize = 0, len = 0; - size_t raw_size; - off_t off; - uint8_t *buf = NULL; - int ret = 0; - uint8_t status; - - chip = (struct nand_chip *)ndisk->d_drv1; - cg = &chip->chip_geom; - nandbus = device_get_parent(chip->dev); - - if ((cmd == NAND_IO_RAW_READ) || (cmd == NAND_IO_RAW_PROG)) { - raw_rw = (struct nand_raw_rw *)data; - raw_size = cg->pgs_per_blk * (cg->page_size + cg->oob_size); - - /* Check if len is not bigger than chip size */ - if (raw_rw->len > raw_size) - return (EFBIG); - - /* - * Do not ask for too much memory, in case of large transfers - * read/write in 16-pages chunks - */ - bufsize = 16 * (cg->page_size + cg->oob_size); - if (raw_rw->len < bufsize) - bufsize = raw_rw->len; - - buf = malloc(bufsize, M_NAND, M_WAITOK); - len = raw_rw->len; - off = 0; - } - - switch (cmd) { - case NAND_IO_ERASE: - ret = nand_erase_blocks(chip, ((off_t *)data)[0], - ((off_t *)data)[1]); - break; - - case NAND_IO_OOB_READ: - oob_rw = (struct nand_oob_rw *)data; - ret = nand_oob_access(chip, oob_rw->page, 0, - oob_rw->len, oob_rw->data, 0); - break; - - case NAND_IO_OOB_PROG: - oob_rw = (struct nand_oob_rw *)data; - ret = nand_oob_access(chip, oob_rw->page, 0, - oob_rw->len, oob_rw->data, 1); - break; - - case NAND_IO_GET_STATUS: - NANDBUS_LOCK(nandbus); - ret = NANDBUS_GET_STATUS(nandbus, &status); - if (ret == 0) - *(uint8_t *)data = status; - NANDBUS_UNLOCK(nandbus); - break; - - case NAND_IO_RAW_PROG: - while (len > 0) { - if (len < bufsize) - bufsize = len; - - ret = copyin(raw_rw->data + off, buf, bufsize); - if (ret) - break; - ret = nand_prog_pages_raw(chip, raw_rw->off + off, buf, - bufsize); - if (ret) - break; - len -= bufsize; - off += bufsize; - } - break; - - case NAND_IO_RAW_READ: - while (len > 0) { - if (len < bufsize) - bufsize = len; - - ret = nand_read_pages_raw(chip, raw_rw->off + off, buf, - bufsize); - if (ret) - break; - - ret = copyout(buf, raw_rw->data + off, bufsize); - if (ret) - break; - len -= bufsize; - off += bufsize; - } - break; - - case NAND_IO_GET_CHIP_PARAM: - nand_get_chip_param(chip, (struct chip_param_io *)data); - break; - - default: - printf("Unknown nand_ioctl request \n"); - ret = EIO; - } - - if (buf) - free(buf, M_NAND); - - return (ret); -} - -static void -nand_io_proc(void *arg, int pending) -{ - struct nand_chip *chip = arg; - struct bio *bp; - int err = 0; - - for (;;) { - mtx_lock(&chip->qlock); - bp = bioq_takefirst(&chip->bioq); - mtx_unlock(&chip->qlock); - if (bp == NULL) - break; - - if (bp->bio_driver1 == BIO_NAND_STD) { - if (bp->bio_cmd == BIO_READ) { - err = nand_read(chip, - bp->bio_offset & 0xffffffff, - bp->bio_data, bp->bio_bcount); - } else if (bp->bio_cmd == BIO_WRITE) { - err = nand_write(chip, - bp->bio_offset & 0xffffffff, - bp->bio_data, bp->bio_bcount); - } - } else if (bp->bio_driver1 == BIO_NAND_RAW) { - if (bp->bio_cmd == BIO_READ) { - err = nand_read_raw(chip, - bp->bio_offset & 0xffffffff, - bp->bio_data, bp->bio_bcount); - } else if (bp->bio_cmd == BIO_WRITE) { - err = nand_write_raw(chip, - bp->bio_offset & 0xffffffff, - bp->bio_data, bp->bio_bcount); - } - } else - panic("Unknown access type in bio->bio_driver1\n"); - - if (bp->bio_cmd == BIO_DELETE) { - nand_debug(NDBG_GEOM, "Delete on chip%d offset %lld " - "length %ld\n", chip->num, bp->bio_offset, - bp->bio_bcount); - err = nand_erase_blocks(chip, - bp->bio_offset & 0xffffffff, - bp->bio_bcount); - } - - if (err == 0 || err == ECC_CORRECTABLE) - bp->bio_resid = 0; - else { - nand_debug(NDBG_GEOM,"nand_[read|write|erase_blocks] " - "error: %d\n", err); - - bp->bio_error = EIO; - bp->bio_flags |= BIO_ERROR; - bp->bio_resid = bp->bio_bcount; - } - biodone(bp); - } -} - -int -create_geom_disk(struct nand_chip *chip) -{ - struct disk *ndisk, *rdisk; - - /* Create the disk device */ - ndisk = disk_alloc(); - ndisk->d_strategy = nand_strategy; - ndisk->d_ioctl = nand_ioctl; - ndisk->d_getattr = nand_getattr; - ndisk->d_name = "gnand"; - ndisk->d_drv1 = chip; - ndisk->d_maxsize = chip->chip_geom.block_size; - ndisk->d_sectorsize = chip->chip_geom.page_size; - ndisk->d_mediasize = chip->chip_geom.chip_size; - ndisk->d_unit = chip->num + - 10 * device_get_unit(device_get_parent(chip->dev)); - - /* - * When using BBT, make two last blocks of device unavailable - * to user (because those are used to store BBT table). - */ - if (chip->bbt != NULL) - ndisk->d_mediasize -= (2 * chip->chip_geom.block_size); - - ndisk->d_flags = DISKFLAG_CANDELETE; - - snprintf(ndisk->d_ident, sizeof(ndisk->d_ident), - "nand: Man:0x%02x Dev:0x%02x", chip->id.man_id, chip->id.dev_id); - ndisk->d_rotation_rate = DISK_RR_NON_ROTATING; - - disk_create(ndisk, DISK_VERSION); - - /* Create the RAW disk device */ - rdisk = disk_alloc(); - rdisk->d_strategy = nand_strategy_raw; - rdisk->d_ioctl = nand_ioctl; - rdisk->d_getattr = nand_getattr; - rdisk->d_name = "gnand.raw"; - rdisk->d_drv1 = chip; - rdisk->d_maxsize = chip->chip_geom.block_size; - rdisk->d_sectorsize = chip->chip_geom.page_size; - rdisk->d_mediasize = chip->chip_geom.chip_size; - rdisk->d_unit = chip->num + - 10 * device_get_unit(device_get_parent(chip->dev)); - - rdisk->d_flags = DISKFLAG_CANDELETE; - - snprintf(rdisk->d_ident, sizeof(rdisk->d_ident), - "nand_raw: Man:0x%02x Dev:0x%02x", chip->id.man_id, - chip->id.dev_id); - rdisk->d_rotation_rate = DISK_RR_NON_ROTATING; - - disk_create(rdisk, DISK_VERSION); - - chip->ndisk = ndisk; - chip->rdisk = rdisk; - - mtx_init(&chip->qlock, "NAND I/O lock", NULL, MTX_DEF); - bioq_init(&chip->bioq); - - TASK_INIT(&chip->iotask, 0, nand_io_proc, chip); - chip->tq = taskqueue_create("nand_taskq", M_WAITOK, - taskqueue_thread_enqueue, &chip->tq); - taskqueue_start_threads(&chip->tq, 1, PI_DISK, "nand taskq"); - - if (bootverbose) - device_printf(chip->dev, "Created gnand%d for chip [0x%0x, " - "0x%0x]\n", ndisk->d_unit, chip->id.man_id, - chip->id.dev_id); - - return (0); -} - -void -destroy_geom_disk(struct nand_chip *chip) -{ - struct bio *bp; - - taskqueue_free(chip->tq); - disk_destroy(chip->ndisk); - disk_destroy(chip->rdisk); - - mtx_lock(&chip->qlock); - for (;;) { - bp = bioq_takefirst(&chip->bioq); - if (bp == NULL) - break; - bp->bio_error = EIO; - bp->bio_flags |= BIO_ERROR; - bp->bio_resid = bp->bio_bcount; - - biodone(bp); - } - mtx_unlock(&chip->qlock); - - mtx_destroy(&chip->qlock); -} diff --git a/sys/dev/nand/nand_id.c b/sys/dev/nand/nand_id.c deleted file mode 100644 index 7259c951bfc93..0000000000000 --- a/sys/dev/nand/nand_id.c +++ /dev/null @@ -1,70 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> - -#include <dev/nand/nand.h> - -struct nand_params nand_ids[] = { - { { NAND_MAN_SAMSUNG, 0x75 }, "Samsung K9F5608U0B NAND 32MiB 8-bit", - 0x20, 0x200, 0x10, 0x20, 0 }, - { { NAND_MAN_SAMSUNG, 0xf1 }, "Samsung K9F1G08U0A NAND 128MiB 3,3V 8-bit", - 0x80, 0x800, 0x40, 0x40, 0 }, - { { NAND_MAN_SAMSUNG, 0xda }, "Samsung K9F2G08U0A NAND 256MiB 3,3V 8-bit", - 0x100, 0x800, 0x40, 0x40, 0 }, - { { NAND_MAN_SAMSUNG, 0xdc }, "Samsung NAND 512MiB 3,3V 8-bit", - 0x200, 0x800, 0x40, 0x40, 0 }, - { { NAND_MAN_SAMSUNG, 0xd3 }, "Samsung NAND 1GiB 3,3V 8-bit", - 0x400, 0x800, 0x40, 0x40, 0 }, - { { NAND_MAN_HYNIX, 0x76 }, "Hynix NAND 64MiB 3,3V 8-bit", - 0x40, 0x200, 0x10, 0x20, 0 }, - { { NAND_MAN_HYNIX, 0xdc }, "Hynix NAND 512MiB 3,3V 8-bit", - 0x200, 0x800, 0x40, 0x40, 0 }, - { { NAND_MAN_HYNIX, 0x79 }, "Hynix NAND 128MB 3,3V 8-bit", - 0x80, 0x200, 0x10, 0x20, 0 }, - { { NAND_MAN_STMICRO, 0xf1 }, "STMicro 128MB 3,3V 8-bit", - 0x80, 2048, 64, 0x40, 0 }, - { { NAND_MAN_MICRON, 0xcc }, "Micron NAND 512MiB 3,3V 16-bit", - 0x200, 2048, 64, 0x40, 0 }, -}; - -struct nand_params *nand_get_params(struct nand_id *id) -{ - int i; - - for (i = 0; i < nitems(nand_ids); i++) - if (nand_ids[i].id.man_id == id->man_id && - nand_ids[i].id.dev_id == id->dev_id) - return (&nand_ids[i]); - - return (NULL); -} diff --git a/sys/dev/nand/nand_if.m b/sys/dev/nand/nand_if.m deleted file mode 100644 index 49c8879b68902..0000000000000 --- a/sys/dev/nand/nand_if.m +++ /dev/null @@ -1,168 +0,0 @@ -#- -# Copyright (C) 2009-2012 Semihalf -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -# SUCH DAMAGE. -# -# $FreeBSD$ - -# NAND chip interface description -# - -#include <sys/bus.h> -#include <dev/nand/nand.h> - -INTERFACE nand; - -CODE { - static int nand_method_not_supported(device_t dev) - { - return (ENOENT); - } -}; - -# Read NAND page -# -# Return values: -# 0: Success -# -METHOD int read_page { - device_t dev; - uint32_t page; - void* buf; - uint32_t len; - uint32_t offset; -}; - -# Program NAND page -# -# Return values: -# 0: Success -# -METHOD int program_page { - device_t dev; - uint32_t page; - void* buf; - uint32_t len; - uint32_t offset; -}; - -# Program NAND page interleaved -# -# Return values: -# 0: Success -# -METHOD int program_page_intlv { - device_t dev; - uint32_t page; - void* buf; - uint32_t len; - uint32_t offset; -} DEFAULT nand_method_not_supported; - -# Read NAND oob -# -# Return values: -# 0: Success -# -METHOD int read_oob { - device_t dev; - uint32_t page; - void* buf; - uint32_t len; - uint32_t offset; -}; - -# Program NAND oob -# -# Return values: -# 0: Success -# -METHOD int program_oob { - device_t dev; - uint32_t page; - void* buf; - uint32_t len; - uint32_t offset; -}; - -# Erase NAND block -# -# Return values: -# 0: Success -# -METHOD int erase_block { - device_t dev; - uint32_t block; -}; - -# Erase NAND block interleaved -# -# Return values: -# 0: Success -# -METHOD int erase_block_intlv { - device_t dev; - uint32_t block; -} DEFAULT nand_method_not_supported; - -# NAND get status -# -# Return values: -# 0: Success -# -METHOD int get_status { - device_t dev; - uint8_t *status; -}; - -# NAND check if block is bad -# -# Return values: -# 0: Success -# -METHOD int is_blk_bad { - device_t dev; - uint32_t block_number; - uint8_t *bad; -}; - -# NAND get ECC -# -# -METHOD int get_ecc { - device_t dev; - void *buf; - void *ecc; - int *needwrite; -}; - -# NAND correct ECC -# -# -METHOD int correct_ecc { - device_t dev; - void *buf; - void *readecc; - void *calcecc; -}; - diff --git a/sys/dev/nand/nandbus.c b/sys/dev/nand/nandbus.c deleted file mode 100644 index 003c1797af644..0000000000000 --- a/sys/dev/nand/nandbus.c +++ /dev/null @@ -1,542 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/socket.h> -#include <sys/malloc.h> -#include <sys/module.h> -#include <sys/bus.h> -#include <sys/proc.h> -#include <sys/lock.h> -#include <sys/mutex.h> -#include <sys/condvar.h> - -#include <dev/nand/nand.h> -#include <dev/nand/nandbus.h> -#include "nand_if.h" -#include "nandbus_if.h" -#include "nfc_if.h" - -#define NAND_NCS 4 - -static int nandbus_probe(device_t dev); -static int nandbus_attach(device_t dev); -static int nandbus_detach(device_t dev); - -static int nandbus_child_location_str(device_t, device_t, char *, size_t); -static int nandbus_child_pnpinfo_str(device_t, device_t, char *, size_t); - -static int nandbus_get_status(device_t, uint8_t *); -static void nandbus_read_buffer(device_t, void *, uint32_t); -static int nandbus_select_cs(device_t, uint8_t); -static int nandbus_send_command(device_t, uint8_t); -static int nandbus_send_address(device_t, uint8_t); -static int nandbus_start_command(device_t); -static int nandbus_wait_ready(device_t, uint8_t *); -static void nandbus_write_buffer(device_t, void *, uint32_t); -static int nandbus_get_ecc(device_t, void *, uint32_t, void *, int *); -static int nandbus_correct_ecc(device_t, void *, int, void *, void *); -static void nandbus_lock(device_t); -static void nandbus_unlock(device_t); - -static int nand_readid(device_t, uint8_t *, uint8_t *); -static int nand_probe_onfi(device_t, uint8_t *); -static int nand_reset(device_t); - -struct nandbus_softc { - device_t dev; - struct cv nandbus_cv; - struct mtx nandbus_mtx; - uint8_t busy; -}; - -static device_method_t nandbus_methods[] = { - /* device interface */ - DEVMETHOD(device_probe, nandbus_probe), - DEVMETHOD(device_attach, nandbus_attach), - DEVMETHOD(device_detach, nandbus_detach), - DEVMETHOD(device_shutdown, bus_generic_shutdown), - - /* bus interface */ - DEVMETHOD(bus_print_child, bus_generic_print_child), - DEVMETHOD(bus_driver_added, bus_generic_driver_added), - DEVMETHOD(bus_child_pnpinfo_str, nandbus_child_pnpinfo_str), - DEVMETHOD(bus_child_location_str, nandbus_child_location_str), - - /* nandbus interface */ - DEVMETHOD(nandbus_get_status, nandbus_get_status), - DEVMETHOD(nandbus_read_buffer, nandbus_read_buffer), - DEVMETHOD(nandbus_select_cs, nandbus_select_cs), - DEVMETHOD(nandbus_send_command, nandbus_send_command), - DEVMETHOD(nandbus_send_address, nandbus_send_address), - DEVMETHOD(nandbus_start_command,nandbus_start_command), - DEVMETHOD(nandbus_wait_ready, nandbus_wait_ready), - DEVMETHOD(nandbus_write_buffer, nandbus_write_buffer), - DEVMETHOD(nandbus_get_ecc, nandbus_get_ecc), - DEVMETHOD(nandbus_correct_ecc, nandbus_correct_ecc), - DEVMETHOD(nandbus_lock, nandbus_lock), - DEVMETHOD(nandbus_unlock, nandbus_unlock), - { 0, 0 } -}; - -devclass_t nandbus_devclass; - -driver_t nandbus_driver = { - "nandbus", - nandbus_methods, - sizeof(struct nandbus_softc) -}; - -DRIVER_MODULE(nandbus, nand, nandbus_driver, nandbus_devclass, 0, 0); - -int -nandbus_create(device_t nfc) -{ - device_t child; - - child = device_add_child(nfc, "nandbus", -1); - if (!child) - return (ENODEV); - - bus_generic_attach(nfc); - - return(0); -} - -void -nandbus_destroy(device_t nfc) -{ - device_t *children; - int nchildren, i; - - mtx_lock(&Giant); - /* Detach & delete all children */ - if (!device_get_children(nfc, &children, &nchildren)) { - for (i = 0; i < nchildren; i++) - device_delete_child(nfc, children[i]); - - free(children, M_TEMP); - } - mtx_unlock(&Giant); -} - -static int -nandbus_probe(device_t dev) -{ - - device_set_desc(dev, "NAND bus"); - - return (0); -} - -static int -nandbus_attach(device_t dev) -{ - device_t child, nfc; - struct nand_id chip_id; - struct nandbus_softc *sc; - struct nandbus_ivar *ivar; - struct nand_softc *nfc_sc; - struct nand_params *chip_params; - uint8_t cs, onfi; - - sc = device_get_softc(dev); - sc->dev = dev; - - nfc = device_get_parent(dev); - nfc_sc = device_get_softc(nfc); - - mtx_init(&sc->nandbus_mtx, "nandbus lock", NULL, MTX_DEF); - cv_init(&sc->nandbus_cv, "nandbus cv"); - - /* Check each possible CS for existing nand devices */ - for (cs = 0; cs < NAND_NCS; cs++) { - nand_debug(NDBG_BUS,"probe chip select %x", cs); - - /* Select & reset chip */ - if (nandbus_select_cs(dev, cs)) - break; - - if (nand_reset(dev)) - continue; - - /* Read manufacturer and device id */ - if (nand_readid(dev, &chip_id.man_id, &chip_id.dev_id)) - continue; - - if (chip_id.man_id == 0xff) - continue; - - /* - * First try to get info from the table. If that fails, see if - * the chip can provide ONFI info. We check the table first to - * allow table entries to override info from chips that are - * known to provide bad ONFI data. - */ - onfi = 0; - chip_params = nand_get_params(&chip_id); - if (chip_params == NULL) { - nand_probe_onfi(dev, &onfi); - } - - /* - * At this point it appears there is a chip at this chipselect, - * so if we can't work with it, whine about it. - */ - if (chip_params == NULL && onfi == 0) { - if (bootverbose || (nand_debug_flag & NDBG_BUS)) - printf("Chip params not found, chipsel: %d " - "(manuf: 0x%0x, chipid: 0x%0x, onfi: %d)\n", - cs, chip_id.man_id, chip_id.dev_id, onfi); - continue; - } - - ivar = malloc(sizeof(struct nandbus_ivar), - M_NAND, M_WAITOK); - - if (onfi == 1) { - ivar->cs = cs; - ivar->cols = 0; - ivar->rows = 0; - ivar->params = NULL; - ivar->man_id = chip_id.man_id; - ivar->dev_id = chip_id.dev_id; - ivar->is_onfi = onfi; - ivar->chip_cdev_name = nfc_sc->chip_cdev_name; - - child = device_add_child(dev, NULL, -1); - device_set_ivars(child, ivar); - continue; - } - - ivar->cs = cs; - ivar->cols = 1; - ivar->rows = 2; - ivar->params = chip_params; - ivar->man_id = chip_id.man_id; - ivar->dev_id = chip_id.dev_id; - ivar->is_onfi = onfi; - ivar->chip_cdev_name = nfc_sc->chip_cdev_name; - - /* - * Check what type of device we have. - * devices bigger than 32MiB have on more row (3) - */ - if (chip_params->chip_size > 32) - ivar->rows++; - /* Large page devices have one more col (2) */ - if (chip_params->chip_size >= 128 && - chip_params->page_size > 512) - ivar->cols++; - - child = device_add_child(dev, NULL, -1); - device_set_ivars(child, ivar); - } - - bus_generic_attach(dev); - return (0); -} - -static int -nandbus_detach(device_t dev) -{ - struct nandbus_softc *sc; - - sc = device_get_softc(dev); - - bus_generic_detach(dev); - - mtx_destroy(&sc->nandbus_mtx); - cv_destroy(&sc->nandbus_cv); - - return (0); -} - -static int -nandbus_child_location_str(device_t bus, device_t child, char *buf, - size_t buflen) -{ - struct nandbus_ivar *ivar = device_get_ivars(child); - - snprintf(buf, buflen, "at cs#%d", ivar->cs); - return (0); -} - -static int -nandbus_child_pnpinfo_str(device_t bus, device_t child, char *buf, - size_t buflen) -{ - // XXX man id, model id ???? - *buf = '\0'; - return (0); -} - -static int -nand_readid(device_t bus, uint8_t *man_id, uint8_t *dev_id) -{ - device_t nfc; - - if (!bus || !man_id || !dev_id) - return (EINVAL); - - nand_debug(NDBG_BUS,"read id"); - - nfc = device_get_parent(bus); - - if (NFC_SEND_COMMAND(nfc, NAND_CMD_READ_ID)) { - nand_debug(NDBG_BUS,"Error : could not send READ ID command"); - return (ENXIO); - } - - if (NFC_SEND_ADDRESS(nfc, 0)) { - nand_debug(NDBG_BUS,"Error : could not sent address to chip"); - return (ENXIO); - } - - if (NFC_START_COMMAND(nfc) != 0) { - nand_debug(NDBG_BUS,"Error : could not start command"); - return (ENXIO); - } - - DELAY(25); - - *man_id = NFC_READ_BYTE(nfc); - *dev_id = NFC_READ_BYTE(nfc); - - nand_debug(NDBG_BUS,"manufacturer id: %x chip id: %x", *man_id, - *dev_id); - - return (0); -} - -static int -nand_probe_onfi(device_t bus, uint8_t *onfi_compliant) -{ - device_t nfc; - char onfi_id[] = {'O', 'N', 'F', 'I', '\0'}; - int i; - - nand_debug(NDBG_BUS,"probing ONFI"); - - nfc = device_get_parent(bus); - - if (NFC_SEND_COMMAND(nfc, NAND_CMD_READ_ID)) { - nand_debug(NDBG_BUS,"Error : could not sent READ ID command"); - return (ENXIO); - } - - if (NFC_SEND_ADDRESS(nfc, ONFI_SIG_ADDR)) { - nand_debug(NDBG_BUS,"Error : could not sent address to chip"); - return (ENXIO); - } - - if (NFC_START_COMMAND(nfc) != 0) { - nand_debug(NDBG_BUS,"Error : could not start command"); - return (ENXIO); - } - for (i = 0; onfi_id[i] != '\0'; i++) - if (NFC_READ_BYTE(nfc) != onfi_id[i]) { - nand_debug(NDBG_BUS,"ONFI non-compliant"); - *onfi_compliant = 0; - return (0); - } - - nand_debug(NDBG_BUS,"ONFI compliant"); - *onfi_compliant = 1; - - return (0); -} - -static int -nand_reset(device_t bus) -{ - device_t nfc; - nand_debug(NDBG_BUS,"resetting..."); - - nfc = device_get_parent(bus); - - if (NFC_SEND_COMMAND(nfc, NAND_CMD_RESET) != 0) { - nand_debug(NDBG_BUS,"Error : could not sent RESET command"); - return (ENXIO); - } - - if (NFC_START_COMMAND(nfc) != 0) { - nand_debug(NDBG_BUS,"Error : could not start RESET command"); - return (ENXIO); - } - - DELAY(1000); - - return (0); -} - -void -nandbus_lock(device_t dev) -{ - struct nandbus_softc *sc; - - sc = device_get_softc(dev); - - mtx_lock(&sc->nandbus_mtx); - if (sc->busy) - cv_wait(&sc->nandbus_cv, &sc->nandbus_mtx); - sc->busy = 1; - mtx_unlock(&sc->nandbus_mtx); -} - -void -nandbus_unlock(device_t dev) -{ - struct nandbus_softc *sc; - - sc = device_get_softc(dev); - - mtx_lock(&sc->nandbus_mtx); - sc->busy = 0; - cv_signal(&sc->nandbus_cv); - mtx_unlock(&sc->nandbus_mtx); -} - -int -nandbus_select_cs(device_t dev, uint8_t cs) -{ - - return (NFC_SELECT_CS(device_get_parent(dev), cs)); -} - -int -nandbus_send_command(device_t dev, uint8_t command) -{ - int err; - - if ((err = NFC_SEND_COMMAND(device_get_parent(dev), command))) - nand_debug(NDBG_BUS,"Err: Could not send command %x, err %x", - command, err); - - return (err); -} - -int -nandbus_send_address(device_t dev, uint8_t address) -{ - int err; - - if ((err = NFC_SEND_ADDRESS(device_get_parent(dev), address))) - nand_debug(NDBG_BUS,"Err: Could not send address %x, err %x", - address, err); - - return (err); -} - -int -nandbus_start_command(device_t dev) -{ - int err; - - if ((err = NFC_START_COMMAND(device_get_parent(dev)))) - nand_debug(NDBG_BUS,"Err: Could not start command, err %x", - err); - - return (err); -} - -void -nandbus_read_buffer(device_t dev, void *buf, uint32_t len) -{ - - NFC_READ_BUF(device_get_parent(dev), buf, len); -} - -void -nandbus_write_buffer(device_t dev, void *buf, uint32_t len) -{ - - NFC_WRITE_BUF(device_get_parent(dev), buf, len); -} - -int -nandbus_get_status(device_t dev, uint8_t *status) -{ - int err; - - if ((err = NANDBUS_SEND_COMMAND(dev, NAND_CMD_STATUS))) - return (err); - if ((err = NANDBUS_START_COMMAND(dev))) - return (err); - - *status = NFC_READ_BYTE(device_get_parent(dev)); - - return (0); -} - -int -nandbus_wait_ready(device_t dev, uint8_t *status) -{ - struct timeval tv, tv2; - - tv2.tv_sec = 0; - tv2.tv_usec = 50 * 5000; /* 250ms */ - - getmicrotime(&tv); - timevaladd(&tv, &tv2); - - do { - if (NANDBUS_GET_STATUS(dev, status)) - return (ENXIO); - - if (*status & NAND_STATUS_RDY) - return (0); - - getmicrotime(&tv2); - } while (timevalcmp(&tv2, &tv, <=)); - - return (EBUSY); -} - -int -nandbus_get_ecc(device_t dev, void *buf, uint32_t pagesize, void *ecc, - int *needwrite) -{ - - return (NFC_GET_ECC(device_get_parent(dev), buf, pagesize, ecc, needwrite)); -} - -int -nandbus_correct_ecc(device_t dev, void *buf, int pagesize, void *readecc, - void *calcecc) -{ - - return (NFC_CORRECT_ECC(device_get_parent(dev), buf, pagesize, - readecc, calcecc)); -} - diff --git a/sys/dev/nand/nandbus.h b/sys/dev/nand/nandbus.h deleted file mode 100644 index 6dd4cbf26daa8..0000000000000 --- a/sys/dev/nand/nandbus.h +++ /dev/null @@ -1,51 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _NANDBUS_H_ -#define _NANDBUS_H_ - -struct nandbus_ivar { - uint8_t cs; - uint8_t cols; - uint8_t rows; - uint8_t man_id; - uint8_t dev_id; - uint8_t is_onfi; - char *chip_cdev_name; - struct nand_params *params; -}; - -extern devclass_t nandbus_devclass; -extern driver_t nandbus_driver; - -int nandbus_create(device_t nfc); -void nandbus_destroy(device_t nfc); - -#endif /* _NANDBUS_H_ */ diff --git a/sys/dev/nand/nandbus_if.m b/sys/dev/nand/nandbus_if.m deleted file mode 100644 index e914e18de6616..0000000000000 --- a/sys/dev/nand/nandbus_if.m +++ /dev/null @@ -1,100 +0,0 @@ -#- -# Copyright (C) 2009-2012 Semihalf -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -# SUCH DAMAGE. -# -# $FreeBSD$ - -# NAND bus interface description -# - -#include <sys/bus.h> -#include <dev/nand/nand.h> - -INTERFACE nandbus; - -METHOD int get_status { - device_t dev; - uint8_t * status; -}; - -METHOD void read_buffer { - device_t dev; - void * buf; - uint32_t len; -}; - -METHOD int select_cs { - device_t dev; - uint8_t cs; -}; - -METHOD int send_command { - device_t dev; - uint8_t command; -}; - -METHOD int send_address { - device_t dev; - uint8_t address; -}; - -METHOD int start_command { - device_t dev; -}; - -METHOD int wait_ready { - device_t dev; - uint8_t * status; -} - -METHOD void write_buffer { - device_t dev; - void * buf; - uint32_t len; -}; - -METHOD int get_ecc { - device_t dev; - void * buf; - uint32_t pagesize; - void * ecc; - int * needwrite; -}; - -METHOD int correct_ecc { - device_t dev; - void * buf; - int pagesize; - void * readecc; - void * calcecc; -}; - -METHOD void lock { - device_t dev; -}; - -METHOD void unlock { - device_t dev; -}; - diff --git a/sys/dev/nand/nandsim.c b/sys/dev/nand/nandsim.c deleted file mode 100644 index 4639a15700a20..0000000000000 --- a/sys/dev/nand/nandsim.c +++ /dev/null @@ -1,670 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* Simulated NAND controller driver */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/proc.h> -#include <sys/bus.h> -#include <sys/conf.h> -#include <sys/kernel.h> -#include <sys/module.h> -#include <sys/malloc.h> - -#include <dev/nand/nand.h> -#include <dev/nand/nandsim.h> -#include <dev/nand/nandsim_chip.h> -#include <dev/nand/nandsim_log.h> -#include <dev/nand/nandsim_swap.h> - -struct sim_param sim; -struct sim_ctrl_conf ctrls[MAX_SIM_DEV]; - -static struct cdev *nandsim_dev; -static d_ioctl_t nandsim_ioctl; - -static void nandsim_init_sim_param(struct sim_param *); -static int nandsim_create_ctrl(struct sim_ctrl *); -static int nandsim_destroy_ctrl(int); -static int nandsim_ctrl_status(struct sim_ctrl *); -static int nandsim_create_chip(struct sim_chip *); -static int nandsim_destroy_chip(struct sim_ctrl_chip *); -static int nandsim_chip_status(struct sim_chip *); -static int nandsim_start_ctrl(int); -static int nandsim_stop_ctrl(int); -static int nandsim_inject_error(struct sim_error *); -static int nandsim_get_block_state(struct sim_block_state *); -static int nandsim_set_block_state(struct sim_block_state *); -static int nandsim_modify(struct sim_mod *); -static int nandsim_dump(struct sim_dump *); -static int nandsim_restore(struct sim_dump *); -static int nandsim_freeze(struct sim_ctrl_chip *); -static void nandsim_print_log(struct sim_log *); -static struct nandsim_chip *get_nandsim_chip(uint8_t, uint8_t); - -static struct cdevsw nandsim_cdevsw = { - .d_version = D_VERSION, - .d_flags = D_NEEDGIANT, - .d_ioctl = nandsim_ioctl, - .d_name = "nandsim", -}; - -int -nandsim_ioctl(struct cdev *dev, u_long cmd, caddr_t data, - int flags, struct thread *td) -{ - int ret = 0; - - switch (cmd) { - case NANDSIM_SIM_PARAM: - nandsim_init_sim_param((struct sim_param *)data); - break; - case NANDSIM_CREATE_CTRL: - ret = nandsim_create_ctrl((struct sim_ctrl *)data); - break; - case NANDSIM_DESTROY_CTRL: - ret = nandsim_destroy_ctrl(*(int *)data); - break; - case NANDSIM_STATUS_CTRL: - ret = nandsim_ctrl_status((struct sim_ctrl *)data); - break; - case NANDSIM_CREATE_CHIP: - ret = nandsim_create_chip((struct sim_chip *)data); - break; - case NANDSIM_DESTROY_CHIP: - ret = nandsim_destroy_chip((struct sim_ctrl_chip *)data); - break; - case NANDSIM_STATUS_CHIP: - ret = nandsim_chip_status((struct sim_chip *)data); - break; - case NANDSIM_MODIFY: - ret = nandsim_modify((struct sim_mod *)data); - break; - case NANDSIM_START_CTRL: - ret = nandsim_start_ctrl(*(int *)data); - break; - case NANDSIM_STOP_CTRL: - ret = nandsim_stop_ctrl(*(int *)data); - break; - case NANDSIM_INJECT_ERROR: - ret = nandsim_inject_error((struct sim_error *)data); - break; - case NANDSIM_SET_BLOCK_STATE: - ret = nandsim_set_block_state((struct sim_block_state *)data); - break; - case NANDSIM_GET_BLOCK_STATE: - ret = nandsim_get_block_state((struct sim_block_state *)data); - break; - case NANDSIM_PRINT_LOG: - nandsim_print_log((struct sim_log *)data); - break; - case NANDSIM_DUMP: - ret = nandsim_dump((struct sim_dump *)data); - break; - case NANDSIM_RESTORE: - ret = nandsim_restore((struct sim_dump *)data); - break; - case NANDSIM_FREEZE: - ret = nandsim_freeze((struct sim_ctrl_chip *)data); - break; - default: - ret = EINVAL; - break; - } - - return (ret); -} - -static void -nandsim_init_sim_param(struct sim_param *param) -{ - - if (!param) - return; - - nand_debug(NDBG_SIM,"log level:%d output %d", param->log_level, - param->log_output); - nandsim_log_level = param->log_level; - nandsim_log_output = param->log_output; -} - -static int -nandsim_create_ctrl(struct sim_ctrl *ctrl) -{ - struct sim_ctrl_conf *sim_ctrl; - - nand_debug(NDBG_SIM,"create controller num:%d cs:%d",ctrl->num, - ctrl->num_cs); - - if (ctrl->num >= MAX_SIM_DEV) { - return (EINVAL); - } - - sim_ctrl = &ctrls[ctrl->num]; - if(sim_ctrl->created) - return (EEXIST); - - sim_ctrl->num = ctrl->num; - sim_ctrl->num_cs = ctrl->num_cs; - sim_ctrl->ecc = ctrl->ecc; - memcpy(sim_ctrl->ecc_layout, ctrl->ecc_layout, - MAX_ECC_BYTES * sizeof(ctrl->ecc_layout[0])); - strlcpy(sim_ctrl->filename, ctrl->filename, - FILENAME_SIZE); - sim_ctrl->created = 1; - - return (0); -} - -static int -nandsim_destroy_ctrl(int ctrl_num) -{ - - nand_debug(NDBG_SIM,"destroy controller num:%d", ctrl_num); - - if (ctrl_num >= MAX_SIM_DEV) { - return (EINVAL); - } - - if (!ctrls[ctrl_num].created) { - return (ENODEV); - } - - if (ctrls[ctrl_num].running) { - return (EBUSY); - } - - memset(&ctrls[ctrl_num], 0, sizeof(ctrls[ctrl_num])); - - return (0); -} - -static int -nandsim_ctrl_status(struct sim_ctrl *ctrl) -{ - - nand_debug(NDBG_SIM,"status controller num:%d cs:%d",ctrl->num, - ctrl->num_cs); - - if (ctrl->num >= MAX_SIM_DEV) { - return (EINVAL); - } - - ctrl->num_cs = ctrls[ctrl->num].num_cs; - ctrl->ecc = ctrls[ctrl->num].ecc; - memcpy(ctrl->ecc_layout, ctrls[ctrl->num].ecc_layout, - MAX_ECC_BYTES * sizeof(ctrl->ecc_layout[0])); - strlcpy(ctrl->filename, ctrls[ctrl->num].filename, - FILENAME_SIZE); - ctrl->running = ctrls[ctrl->num].running; - ctrl->created = ctrls[ctrl->num].created; - - return (0); -} - -static int -nandsim_create_chip(struct sim_chip *chip) -{ - struct sim_chip *sim_chip; - - nand_debug(NDBG_SIM,"create chip num:%d at ctrl:%d", chip->num, - chip->ctrl_num); - - if (chip->ctrl_num >= MAX_SIM_DEV || - chip->num >= MAX_CTRL_CS) { - return (EINVAL); - } - - if (ctrls[chip->ctrl_num].chips[chip->num]) { - return (EEXIST); - } - - sim_chip = malloc(sizeof(*sim_chip), M_NANDSIM, - M_WAITOK); - if (sim_chip == NULL) { - return (ENOMEM); - } - - memcpy(sim_chip, chip, sizeof(*sim_chip)); - ctrls[chip->ctrl_num].chips[chip->num] = sim_chip; - sim_chip->created = 1; - - return (0); -} - -static int -nandsim_destroy_chip(struct sim_ctrl_chip *chip) -{ - struct sim_ctrl_conf *ctrl_conf; - - nand_debug(NDBG_SIM,"destroy chip num:%d at ctrl:%d", chip->chip_num, - chip->ctrl_num); - - if (chip->ctrl_num >= MAX_SIM_DEV || - chip->chip_num >= MAX_CTRL_CS) - return (EINVAL); - - ctrl_conf = &ctrls[chip->ctrl_num]; - - if (!ctrl_conf->created || !ctrl_conf->chips[chip->chip_num]) - return (ENODEV); - - if (ctrl_conf->running) - return (EBUSY); - - free(ctrl_conf->chips[chip->chip_num], M_NANDSIM); - ctrl_conf->chips[chip->chip_num] = NULL; - - return (0); -} - -static int -nandsim_chip_status(struct sim_chip *chip) -{ - struct sim_ctrl_conf *ctrl_conf; - - nand_debug(NDBG_SIM,"status for chip num:%d at ctrl:%d", chip->num, - chip->ctrl_num); - - if (chip->ctrl_num >= MAX_SIM_DEV && - chip->num >= MAX_CTRL_CS) - return (EINVAL); - - ctrl_conf = &ctrls[chip->ctrl_num]; - if (!ctrl_conf->chips[chip->num]) - chip->created = 0; - else - memcpy(chip, ctrl_conf->chips[chip->num], sizeof(*chip)); - - return (0); -} - -static int -nandsim_start_ctrl(int num) -{ - device_t nexus, ndev; - devclass_t nexus_devclass; - int ret = 0; - - nand_debug(NDBG_SIM,"start ctlr num:%d", num); - - if (num >= MAX_SIM_DEV) - return (EINVAL); - - if (!ctrls[num].created) - return (ENODEV); - - if (ctrls[num].running) - return (EBUSY); - - /* We will add our device as a child of the nexus0 device */ - if (!(nexus_devclass = devclass_find("nexus")) || - !(nexus = devclass_get_device(nexus_devclass, 0))) - return (EFAULT); - - /* - * Create a newbus device representing this frontend instance - * - * XXX powerpc nexus doesn't implement bus_add_child, so child - * must be added by device_add_child(). - */ -#if defined(__powerpc__) - ndev = device_add_child(nexus, "nandsim", num); -#else - ndev = BUS_ADD_CHILD(nexus, 0, "nandsim", num); -#endif - if (!ndev) - return (EFAULT); - - mtx_lock(&Giant); - ret = device_probe_and_attach(ndev); - mtx_unlock(&Giant); - - if (ret == 0) { - ctrls[num].sim_ctrl_dev = ndev; - ctrls[num].running = 1; - } - - return (ret); -} - -static int -nandsim_stop_ctrl(int num) -{ - device_t nexus; - devclass_t nexus_devclass; - int ret = 0; - - nand_debug(NDBG_SIM,"stop controller num:%d", num); - - if (num >= MAX_SIM_DEV) { - return (EINVAL); - } - - if (!ctrls[num].created || !ctrls[num].running) { - return (ENODEV); - } - - /* We will add our device as a child of the nexus0 device */ - if (!(nexus_devclass = devclass_find("nexus")) || - !(nexus = devclass_get_device(nexus_devclass, 0))) { - return (ENODEV); - } - - mtx_lock(&Giant); - if (ctrls[num].sim_ctrl_dev) { - ret = device_delete_child(nexus, ctrls[num].sim_ctrl_dev); - ctrls[num].sim_ctrl_dev = NULL; - } - mtx_unlock(&Giant); - - ctrls[num].running = 0; - - return (ret); -} - -static struct nandsim_chip * -get_nandsim_chip(uint8_t ctrl_num, uint8_t chip_num) -{ - struct nandsim_softc *sc; - - if (!ctrls[ctrl_num].sim_ctrl_dev) - return (NULL); - - sc = device_get_softc(ctrls[ctrl_num].sim_ctrl_dev); - return (sc->chips[chip_num]); -} - -static void -nandsim_print_log(struct sim_log *sim_log) -{ - struct nandsim_softc *sc; - int len1, len2; - - if (!ctrls[sim_log->ctrl_num].sim_ctrl_dev) - return; - - sc = device_get_softc(ctrls[sim_log->ctrl_num].sim_ctrl_dev); - if (sc->log_buff) { - len1 = strlen(&sc->log_buff[sc->log_idx + 1]); - if (len1 >= sim_log->len) - len1 = sim_log->len; - copyout(&sc->log_buff[sc->log_idx + 1], sim_log->log, len1); - len2 = strlen(sc->log_buff); - if (len2 >= (sim_log->len - len1)) - len2 = (sim_log->len - len1); - copyout(sc->log_buff, &sim_log->log[len1], len2); - sim_log->len = len1 + len2; - } -} - -static int -nandsim_inject_error(struct sim_error *error) -{ - struct nandsim_chip *chip; - struct block_space *bs; - struct onfi_params *param; - int page, page_size, block, offset; - - nand_debug(NDBG_SIM,"inject error for chip %d at ctrl %d\n", - error->chip_num, error->ctrl_num); - - if (error->ctrl_num >= MAX_SIM_DEV || - error->chip_num >= MAX_CTRL_CS) - return (EINVAL); - - if (!ctrls[error->ctrl_num].created || !ctrls[error->ctrl_num].running) - return (ENODEV); - - chip = get_nandsim_chip(error->ctrl_num, error->chip_num); - param = &chip->params; - page_size = param->bytes_per_page + param->spare_bytes_per_page; - block = error->page_num / param->pages_per_block; - page = error->page_num % param->pages_per_block; - - bs = get_bs(chip->swap, block, 1); - if (!bs) - return (EINVAL); - - offset = (page * page_size) + error->column; - memset(&bs->blk_ptr[offset], error->pattern, error->len); - - return (0); -} - -static int -nandsim_set_block_state(struct sim_block_state *bs) -{ - struct onfi_params *params; - struct nandsim_chip *chip; - int blocks; - - nand_debug(NDBG_SIM,"set block state for %d:%d block %d\n", - bs->chip_num, bs->ctrl_num, bs->block_num); - - if (bs->ctrl_num >= MAX_SIM_DEV || - bs->chip_num >= MAX_CTRL_CS) - return (EINVAL); - - chip = get_nandsim_chip(bs->ctrl_num, bs->chip_num); - params = &chip->params; - blocks = params->luns * params->blocks_per_lun; - - if (bs->block_num > blocks) - return (EINVAL); - - chip->blk_state[bs->block_num].is_bad = bs->state; - - if (bs->wearout >= 0) - chip->blk_state[bs->block_num].wear_lev = bs->wearout; - - return (0); -} - -static int -nandsim_get_block_state(struct sim_block_state *bs) -{ - struct onfi_params *params; - struct nandsim_chip *chip; - int blocks; - - if (bs->ctrl_num >= MAX_SIM_DEV || - bs->chip_num >= MAX_CTRL_CS) - return (EINVAL); - - nand_debug(NDBG_SIM,"get block state for %d:%d block %d\n", - bs->chip_num, bs->ctrl_num, bs->block_num); - - chip = get_nandsim_chip(bs->ctrl_num, bs->chip_num); - params = &chip->params; - blocks = params->luns * params->blocks_per_lun; - - if (bs->block_num > blocks) - return (EINVAL); - - bs->state = chip->blk_state[bs->block_num].is_bad; - bs->wearout = chip->blk_state[bs->block_num].wear_lev; - - return (0); -} - -static int -nandsim_dump(struct sim_dump *dump) -{ - struct nandsim_chip *chip; - struct block_space *bs; - int blk_size; - - nand_debug(NDBG_SIM,"dump chip %d %d\n", dump->ctrl_num, dump->chip_num); - - if (dump->ctrl_num >= MAX_SIM_DEV || - dump->chip_num >= MAX_CTRL_CS) - return (EINVAL); - - chip = get_nandsim_chip(dump->ctrl_num, dump->chip_num); - blk_size = chip->cg.block_size + - (chip->cg.oob_size * chip->cg.pgs_per_blk); - - bs = get_bs(chip->swap, dump->block_num, 0); - if (!bs) - return (EINVAL); - - if (dump->len > blk_size) - dump->len = blk_size; - - copyout(bs->blk_ptr, dump->data, dump->len); - - return (0); -} - -static int -nandsim_restore(struct sim_dump *dump) -{ - struct nandsim_chip *chip; - struct block_space *bs; - int blk_size; - - nand_debug(NDBG_SIM,"restore chip %d %d\n", dump->ctrl_num, - dump->chip_num); - - if (dump->ctrl_num >= MAX_SIM_DEV || - dump->chip_num >= MAX_CTRL_CS) - return (EINVAL); - - chip = get_nandsim_chip(dump->ctrl_num, dump->chip_num); - blk_size = chip->cg.block_size + - (chip->cg.oob_size * chip->cg.pgs_per_blk); - - bs = get_bs(chip->swap, dump->block_num, 1); - if (!bs) - return (EINVAL); - - if (dump->len > blk_size) - dump->len = blk_size; - - - copyin(dump->data, bs->blk_ptr, dump->len); - - return (0); -} - -static int -nandsim_freeze(struct sim_ctrl_chip *ctrl_chip) -{ - struct nandsim_chip *chip; - - if (ctrl_chip->ctrl_num >= MAX_SIM_DEV || - ctrl_chip->chip_num >= MAX_CTRL_CS) - return (EINVAL); - - chip = get_nandsim_chip(ctrl_chip->ctrl_num, ctrl_chip->chip_num); - nandsim_chip_freeze(chip); - - return (0); -} - -static int -nandsim_modify(struct sim_mod *mod) -{ - struct sim_chip *sim_conf = NULL; - struct nandsim_chip *sim_chip = NULL; - - nand_debug(NDBG_SIM,"modify ctlr %d chip %d", mod->ctrl_num, - mod->chip_num); - - if (mod->field != SIM_MOD_LOG_LEVEL) { - if (mod->ctrl_num >= MAX_SIM_DEV || - mod->chip_num >= MAX_CTRL_CS) - return (EINVAL); - - sim_conf = ctrls[mod->ctrl_num].chips[mod->chip_num]; - sim_chip = get_nandsim_chip(mod->ctrl_num, mod->chip_num); - } - - switch (mod->field) { - case SIM_MOD_LOG_LEVEL: - nandsim_log_level = mod->new_value; - break; - case SIM_MOD_ERASE_TIME: - sim_conf->erase_time = sim_chip->erase_delay = mod->new_value; - break; - case SIM_MOD_PROG_TIME: - sim_conf->prog_time = sim_chip->prog_delay = mod->new_value; - break; - case SIM_MOD_READ_TIME: - sim_conf->read_time = sim_chip->read_delay = mod->new_value; - break; - case SIM_MOD_ERROR_RATIO: - sim_conf->error_ratio = mod->new_value; - sim_chip->error_ratio = mod->new_value; - break; - default: - break; - } - - return (0); -} -static int -nandsim_modevent(module_t mod __unused, int type, void *data __unused) -{ - struct sim_ctrl_chip chip_ctrl; - int i, j; - - switch (type) { - case MOD_LOAD: - nandsim_dev = make_dev(&nandsim_cdevsw, 0, - UID_ROOT, GID_WHEEL, 0600, "nandsim.ioctl"); - break; - case MOD_UNLOAD: - for (i = 0; i < MAX_SIM_DEV; i++) { - nandsim_stop_ctrl(i); - chip_ctrl.ctrl_num = i; - for (j = 0; j < MAX_CTRL_CS; j++) { - chip_ctrl.chip_num = j; - nandsim_destroy_chip(&chip_ctrl); - } - nandsim_destroy_ctrl(i); - } - destroy_dev(nandsim_dev); - break; - case MOD_SHUTDOWN: - break; - default: - return (EOPNOTSUPP); - } - return (0); -} - -DEV_MODULE(nandsim, nandsim_modevent, NULL); -MODULE_VERSION(nandsim, 1); -MODULE_DEPEND(nandsim, nand, 1, 1, 1); -MODULE_DEPEND(nandsim, alq, 1, 1, 1); diff --git a/sys/dev/nand/nandsim.h b/sys/dev/nand/nandsim.h deleted file mode 100644 index d4b225113bfd6..0000000000000 --- a/sys/dev/nand/nandsim.h +++ /dev/null @@ -1,177 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _NANDSIM_H_ -#define _NANDSIM_H_ - -#include <sys/ioccom.h> -#include <sys/types.h> - -#define MAX_SIM_DEV 4 -#define MAX_CTRL_CS 4 -#define MAX_ECC_BYTES 512 -#define MAX_BAD_BLOCKS 512 -#define DEV_MODEL_STR_SIZE 21 -#define MAN_STR_SIZE 13 -#define FILENAME_SIZE 20 - -#define MAX_CHIPS (MAX_SIM_DEV*MAX_CTRL_CS) - -#define NANDSIM_OUTPUT_NONE 0x0 -#define NANDSIM_OUTPUT_CONSOLE 0x1 -#define NANDSIM_OUTPUT_RAM 0x2 -#define NANDSIM_OUTPUT_FILE 0x3 - -struct sim_ctrl_chip { - uint8_t ctrl_num; - uint8_t chip_num; -}; - -#define NANDSIM_BASE 'A' - -struct sim_param { - uint8_t log_level; - uint8_t log_output; -}; - -#define NANDSIM_SIM_PARAM _IOW(NANDSIM_BASE, 1, struct sim_param) - -struct sim_ctrl { - uint8_t running; - uint8_t created; - uint8_t num; - uint8_t num_cs; - uint8_t ecc; - char filename[FILENAME_SIZE]; - uint16_t ecc_layout[MAX_ECC_BYTES]; -}; -#define NANDSIM_CREATE_CTRL _IOW(NANDSIM_BASE, 2, struct sim_ctrl) -#define NANDSIM_DESTROY_CTRL _IOW(NANDSIM_BASE, 3, int) - -struct sim_chip { - uint8_t num; - uint8_t ctrl_num; - uint8_t created; - uint8_t device_id; - uint8_t manufact_id; - char device_model[DEV_MODEL_STR_SIZE]; - char manufacturer[MAN_STR_SIZE]; - uint8_t col_addr_cycles; - uint8_t row_addr_cycles; - uint8_t features; - uint8_t width; - uint32_t page_size; - uint32_t oob_size; - uint32_t pgs_per_blk; - uint32_t blks_per_lun; - uint32_t luns; - - uint32_t prog_time; - uint32_t erase_time; - uint32_t read_time; - uint32_t ccs_time; - - uint32_t error_ratio; - uint32_t wear_level; - uint32_t bad_block_map[MAX_BAD_BLOCKS]; - uint8_t is_wp; -}; - -#define NANDSIM_CREATE_CHIP _IOW(NANDSIM_BASE, 3, struct sim_chip) - -struct sim_chip_destroy { - uint8_t ctrl_num; - uint8_t chip_num; -}; -#define NANDSIM_DESTROY_CHIP _IOW(NANDSIM_BASE, 4, struct sim_chip_destroy) - -#define NANDSIM_START_CTRL _IOW(NANDSIM_BASE, 5, int) -#define NANDSIM_STOP_CTRL _IOW(NANDSIM_BASE, 6, int) -#define NANDSIM_RESTART_CTRL _IOW(NANDSIM_BASE, 7, int) - -#define NANDSIM_STATUS_CTRL _IOWR(NANDSIM_BASE, 8, struct sim_ctrl) -#define NANDSIM_STATUS_CHIP _IOWR(NANDSIM_BASE, 9, struct sim_chip) - -struct sim_mod { - uint8_t chip_num; - uint8_t ctrl_num; - uint32_t field; - uint32_t new_value; -}; -#define SIM_MOD_LOG_LEVEL 0 -#define SIM_MOD_ERASE_TIME 1 -#define SIM_MOD_PROG_TIME 2 -#define SIM_MOD_READ_TIME 3 -#define SIM_MOD_CCS_TIME 4 -#define SIM_MOD_ERROR_RATIO 5 - -#define NANDSIM_MODIFY _IOW(NANDSIM_BASE, 10, struct sim_mod) -#define NANDSIM_FREEZE _IOW(NANDSIM_BASE, 11, struct sim_ctrl_chip) - -struct sim_error { - uint8_t ctrl_num; - uint8_t chip_num; - uint32_t page_num; - uint32_t column; - uint32_t len; - uint32_t pattern; -}; -#define NANDSIM_INJECT_ERROR _IOW(NANDSIM_BASE, 20, struct sim_error) - -#define NANDSIM_GOOD_BLOCK 0 -#define NANDSIM_BAD_BLOCK 1 -struct sim_block_state { - uint8_t ctrl_num; - uint8_t chip_num; - uint32_t block_num; - int wearout; - uint8_t state; -}; -#define NANDSIM_SET_BLOCK_STATE _IOW(NANDSIM_BASE, 21, struct sim_block_state) -#define NANDSIM_GET_BLOCK_STATE _IOWR(NANDSIM_BASE, 22, struct sim_block_state) - -struct sim_log { - uint8_t ctrl_num; - char* log; - size_t len; -}; -#define NANDSIM_PRINT_LOG _IOWR(NANDSIM_BASE, 23, struct sim_log) - -struct sim_dump { - uint8_t ctrl_num; - uint8_t chip_num; - uint32_t block_num; - uint32_t len; - void* data; -}; -#define NANDSIM_DUMP _IOWR(NANDSIM_BASE, 24, struct sim_dump) -#define NANDSIM_RESTORE _IOWR(NANDSIM_BASE, 25, struct sim_dump) - -#endif /* _NANDSIM_H_ */ diff --git a/sys/dev/nand/nandsim_chip.c b/sys/dev/nand/nandsim_chip.c deleted file mode 100644 index b7ab83b9d2083..0000000000000 --- a/sys/dev/nand/nandsim_chip.c +++ /dev/null @@ -1,898 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/types.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/lock.h> -#include <sys/malloc.h> -#include <sys/module.h> -#include <sys/mutex.h> -#include <sys/proc.h> -#include <sys/sched.h> -#include <sys/kthread.h> -#include <sys/unistd.h> - -#include <dev/nand/nand.h> -#include <dev/nand/nandsim_chip.h> -#include <dev/nand/nandsim_log.h> -#include <dev/nand/nandsim_swap.h> - -MALLOC_DEFINE(M_NANDSIM, "NANDsim", "NANDsim dynamic data"); - -#define NANDSIM_CHIP_LOCK(chip) mtx_lock(&(chip)->ns_lock) -#define NANDSIM_CHIP_UNLOCK(chip) mtx_unlock(&(chip)->ns_lock) - -static nandsim_evh_t erase_evh; -static nandsim_evh_t idle_evh; -static nandsim_evh_t poweron_evh; -static nandsim_evh_t reset_evh; -static nandsim_evh_t read_evh; -static nandsim_evh_t readid_evh; -static nandsim_evh_t readparam_evh; -static nandsim_evh_t write_evh; - -static void nandsim_loop(void *); -static void nandsim_undefined(struct nandsim_chip *, uint8_t); -static void nandsim_bad_address(struct nandsim_chip *, uint8_t *); -static void nandsim_ignore_address(struct nandsim_chip *, uint8_t); -static void nandsim_sm_error(struct nandsim_chip *); -static void nandsim_start_handler(struct nandsim_chip *, nandsim_evh_t); - -static void nandsim_callout_eh(void *); -static int nandsim_delay(struct nandsim_chip *, int); - -static int nandsim_bbm_init(struct nandsim_chip *, uint32_t, uint32_t *); -static int nandsim_blk_state_init(struct nandsim_chip *, uint32_t, uint32_t); -static void nandsim_blk_state_destroy(struct nandsim_chip *); -static int nandchip_is_block_valid(struct nandsim_chip *, int); - -static void nandchip_set_status(struct nandsim_chip *, uint8_t); -static void nandchip_clear_status(struct nandsim_chip *, uint8_t); - -struct proc *nandsim_proc; - -struct nandsim_chip * -nandsim_chip_init(struct nandsim_softc* sc, uint8_t chip_num, - struct sim_chip *sim_chip) -{ - struct nandsim_chip *chip; - struct onfi_params *chip_param; - char swapfile[20]; - uint32_t size; - int error; - - chip = malloc(sizeof(*chip), M_NANDSIM, M_WAITOK | M_ZERO); - - mtx_init(&chip->ns_lock, "nandsim lock", NULL, MTX_DEF); - callout_init(&chip->ns_callout, 1); - STAILQ_INIT(&chip->nandsim_events); - - chip->chip_num = chip_num; - chip->ctrl_num = sim_chip->ctrl_num; - chip->sc = sc; - - if (!sim_chip->is_wp) - nandchip_set_status(chip, NAND_STATUS_WP); - - chip_param = &chip->params; - - chip->id.dev_id = sim_chip->device_id; - chip->id.man_id = sim_chip->manufact_id; - - chip->error_ratio = sim_chip->error_ratio; - chip->wear_level = sim_chip->wear_level; - chip->prog_delay = sim_chip->prog_time; - chip->erase_delay = sim_chip->erase_time; - chip->read_delay = sim_chip->read_time; - - chip_param->t_prog = sim_chip->prog_time; - chip_param->t_bers = sim_chip->erase_time; - chip_param->t_r = sim_chip->read_time; - bcopy("onfi", &chip_param->signature, 4); - - chip_param->manufacturer_id = sim_chip->manufact_id; - strncpy(chip_param->manufacturer_name, sim_chip->manufacturer, 12); - chip_param->manufacturer_name[11] = 0; - strncpy(chip_param->device_model, sim_chip->device_model, 20); - chip_param->device_model[19] = 0; - - chip_param->bytes_per_page = sim_chip->page_size; - chip_param->spare_bytes_per_page = sim_chip->oob_size; - chip_param->pages_per_block = sim_chip->pgs_per_blk; - chip_param->blocks_per_lun = sim_chip->blks_per_lun; - chip_param->luns = sim_chip->luns; - - init_chip_geom(&chip->cg, chip_param->luns, chip_param->blocks_per_lun, - chip_param->pages_per_block, chip_param->bytes_per_page, - chip_param->spare_bytes_per_page); - - chip_param->address_cycles = sim_chip->row_addr_cycles | - (sim_chip->col_addr_cycles << 4); - chip_param->features = sim_chip->features; - if (sim_chip->width == 16) - chip_param->features |= ONFI_FEAT_16BIT; - - size = chip_param->blocks_per_lun * chip_param->luns; - - error = nandsim_blk_state_init(chip, size, sim_chip->wear_level); - if (error) { - mtx_destroy(&chip->ns_lock); - free(chip, M_NANDSIM); - return (NULL); - } - - error = nandsim_bbm_init(chip, size, sim_chip->bad_block_map); - if (error) { - mtx_destroy(&chip->ns_lock); - nandsim_blk_state_destroy(chip); - free(chip, M_NANDSIM); - return (NULL); - } - - nandsim_start_handler(chip, poweron_evh); - - nand_debug(NDBG_SIM,"Create thread for chip%d [%8p]", chip->chip_num, - chip); - /* Create chip thread */ - error = kproc_kthread_add(nandsim_loop, chip, &nandsim_proc, - &chip->nandsim_td, RFSTOPPED | RFHIGHPID, - 0, "nandsim", "chip"); - if (error) { - mtx_destroy(&chip->ns_lock); - nandsim_blk_state_destroy(chip); - free(chip, M_NANDSIM); - return (NULL); - } - - thread_lock(chip->nandsim_td); - sched_class(chip->nandsim_td, PRI_REALTIME); - sched_add(chip->nandsim_td, SRQ_BORING); - thread_unlock(chip->nandsim_td); - - size = (chip_param->bytes_per_page + - chip_param->spare_bytes_per_page) * - chip_param->pages_per_block; - - sprintf(swapfile, "chip%d%d.swp", chip->ctrl_num, chip->chip_num); - chip->swap = nandsim_swap_init(swapfile, chip_param->blocks_per_lun * - chip_param->luns, size); - if (!chip->swap) - nandsim_chip_destroy(chip); - - /* Wait for new thread to enter main loop */ - tsleep(chip->nandsim_td, PWAIT, "ns_chip", 1 * hz); - - return (chip); -} - -static int -nandsim_blk_state_init(struct nandsim_chip *chip, uint32_t size, - uint32_t wear_lev) -{ - int i; - - if (!chip || size == 0) - return (-1); - - chip->blk_state = malloc(size * sizeof(struct nandsim_block_state), - M_NANDSIM, M_WAITOK | M_ZERO); - - for (i = 0; i < size; i++) { - if (wear_lev) - chip->blk_state[i].wear_lev = wear_lev; - else - chip->blk_state[i].wear_lev = -1; - } - - return (0); -} - -static void -nandsim_blk_state_destroy(struct nandsim_chip *chip) -{ - - if (chip && chip->blk_state) - free(chip->blk_state, M_NANDSIM); -} - -static int -nandsim_bbm_init(struct nandsim_chip *chip, uint32_t size, - uint32_t *sim_bbm) -{ - uint32_t index; - int i; - - if ((chip == NULL) || (size == 0)) - return (-1); - - if (chip->blk_state == NULL) - return (-1); - - if (sim_bbm == NULL) - return (0); - - for (i = 0; i < MAX_BAD_BLOCKS; i++) { - index = sim_bbm[i]; - - if (index == 0xffffffff) - break; - else if (index > size) - return (-1); - else - chip->blk_state[index].is_bad = 1; - } - - return (0); -} - -void -nandsim_chip_destroy(struct nandsim_chip *chip) -{ - struct nandsim_ev *ev; - - ev = create_event(chip, NANDSIM_EV_EXIT, 0); - if (ev) - send_event(ev); -} - -void -nandsim_chip_freeze(struct nandsim_chip *chip) -{ - - chip->flags |= NANDSIM_CHIP_FROZEN; -} - -static void -nandsim_loop(void *arg) -{ - struct nandsim_chip *chip = (struct nandsim_chip *)arg; - struct nandsim_ev *ev; - - nand_debug(NDBG_SIM,"Start main loop for chip%d [%8p]", chip->chip_num, - chip); - for(;;) { - NANDSIM_CHIP_LOCK(chip); - if (!(chip->flags & NANDSIM_CHIP_ACTIVE)) { - chip->flags |= NANDSIM_CHIP_ACTIVE; - wakeup(chip->nandsim_td); - } - - if (STAILQ_EMPTY(&chip->nandsim_events)) { - nand_debug(NDBG_SIM,"Chip%d [%8p] going sleep", - chip->chip_num, chip); - msleep(chip, &chip->ns_lock, PRIBIO, "nandev", 0); - } - - ev = STAILQ_FIRST(&chip->nandsim_events); - STAILQ_REMOVE_HEAD(&chip->nandsim_events, links); - NANDSIM_CHIP_UNLOCK(chip); - if (ev->type == NANDSIM_EV_EXIT) { - NANDSIM_CHIP_LOCK(chip); - destroy_event(ev); - wakeup(ev); - while (!STAILQ_EMPTY(&chip->nandsim_events)) { - ev = STAILQ_FIRST(&chip->nandsim_events); - STAILQ_REMOVE_HEAD(&chip->nandsim_events, - links); - destroy_event(ev); - wakeup(ev); - } - NANDSIM_CHIP_UNLOCK(chip); - nandsim_log(chip, NANDSIM_LOG_SM, "destroyed\n"); - mtx_destroy(&chip->ns_lock); - nandsim_blk_state_destroy(chip); - nandsim_swap_destroy(chip->swap); - free(chip, M_NANDSIM); - nandsim_proc = NULL; - - kthread_exit(); - } - - if (!(chip->flags & NANDSIM_CHIP_FROZEN)) { - nand_debug(NDBG_SIM,"Chip [%x] get event [%x]", - chip->chip_num, ev->type); - chip->ev_handler(chip, ev->type, ev->data); - } - - wakeup(ev); - destroy_event(ev); - } - -} - -struct nandsim_ev * -create_event(struct nandsim_chip *chip, uint8_t type, uint8_t data_size) -{ - struct nandsim_ev *ev; - - ev = malloc(sizeof(*ev), M_NANDSIM, M_NOWAIT | M_ZERO); - if (!ev) { - nand_debug(NDBG_SIM,"Cannot create event"); - return (NULL); - } - - if (data_size > 0) - ev->data = malloc(sizeof(*ev), M_NANDSIM, M_NOWAIT | M_ZERO); - ev->type = type; - ev->chip = chip; - - return (ev); -} - -void -destroy_event(struct nandsim_ev *ev) -{ - - if (ev->data) - free(ev->data, M_NANDSIM); - free(ev, M_NANDSIM); -} - -int -send_event(struct nandsim_ev *ev) -{ - struct nandsim_chip *chip = ev->chip; - - if (!(chip->flags & NANDSIM_CHIP_FROZEN)) { - nand_debug(NDBG_SIM,"Chip%d [%p] send event %x", - chip->chip_num, chip, ev->type); - - NANDSIM_CHIP_LOCK(chip); - STAILQ_INSERT_TAIL(&chip->nandsim_events, ev, links); - NANDSIM_CHIP_UNLOCK(chip); - - wakeup(chip); - if ((ev->type != NANDSIM_EV_TIMEOUT) && chip->nandsim_td && - (curthread != chip->nandsim_td)) - tsleep(ev, PWAIT, "ns_ev", 5 * hz); - } - - return (0); -} - -static void -nandsim_callout_eh(void *arg) -{ - struct nandsim_ev *ev = (struct nandsim_ev *)arg; - - send_event(ev); -} - -static int -nandsim_delay(struct nandsim_chip *chip, int timeout) -{ - struct nandsim_ev *ev; - struct timeval delay; - int tm; - - nand_debug(NDBG_SIM,"Chip[%d] Set delay: %d", chip->chip_num, timeout); - - ev = create_event(chip, NANDSIM_EV_TIMEOUT, 0); - if (!ev) - return (-1); - - chip->sm_state = NANDSIM_STATE_TIMEOUT; - tm = (timeout/10000) * (hz / 100); - if (callout_reset(&chip->ns_callout, tm, nandsim_callout_eh, ev)) - return (-1); - - delay.tv_sec = chip->read_delay / 1000000; - delay.tv_usec = chip->read_delay % 1000000; - timevaladd(&chip->delay_tv, &delay); - - return (0); -} - -static void -nandsim_start_handler(struct nandsim_chip *chip, nandsim_evh_t evh) -{ - struct nandsim_ev *ev; - - chip->ev_handler = evh; - - nand_debug(NDBG_SIM,"Start handler %p for chip%d [%p]", evh, - chip->chip_num, chip); - ev = create_event(chip, NANDSIM_EV_START, 0); - if (!ev) - nandsim_sm_error(chip); - - send_event(ev); -} - -static void -nandchip_set_data(struct nandsim_chip *chip, uint8_t *data, uint32_t len, - uint32_t idx) -{ - - nand_debug(NDBG_SIM,"Chip [%x] data %p [%x] at %x", chip->chip_num, - data, len, idx); - chip->data.data_ptr = data; - chip->data.size = len; - chip->data.index = idx; -} - -static int -nandchip_chip_space(struct nandsim_chip *chip, int32_t row, int32_t column, - size_t size, uint8_t writing) -{ - struct block_space *blk_space; - uint32_t lun, block, page, offset, block_size; - int err; - - block_size = chip->cg.block_size + - (chip->cg.oob_size * chip->cg.pgs_per_blk); - - err = nand_row_to_blkpg(&chip->cg, row, &lun, &block, &page); - if (err) { - nand_debug(NDBG_SIM,"cannot get address\n"); - return (-1); - } - - if (!nandchip_is_block_valid(chip, block)) { - nandchip_set_data(chip, NULL, 0, 0); - return (-1); - } - - blk_space = get_bs(chip->swap, block, writing); - if (!blk_space) { - nandchip_set_data(chip, NULL, 0, 0); - return (-1); - } - - if (size > block_size) - size = block_size; - - if (size == block_size) { - offset = 0; - column = 0; - } else - offset = page * (chip->cg.page_size + chip->cg.oob_size); - - nandchip_set_data(chip, &blk_space->blk_ptr[offset], size, column); - - return (0); -} - -static int -nandchip_get_addr_byte(struct nandsim_chip *chip, void *data, uint32_t *value) -{ - int ncycles = 0; - uint8_t byte; - uint8_t *buffer; - - buffer = (uint8_t *)value; - byte = *((uint8_t *)data); - - KASSERT((chip->sm_state == NANDSIM_STATE_WAIT_ADDR_ROW || - chip->sm_state == NANDSIM_STATE_WAIT_ADDR_COL), - ("unexpected state")); - - if (chip->sm_state == NANDSIM_STATE_WAIT_ADDR_ROW) { - ncycles = chip->params.address_cycles & 0xf; - buffer[chip->sm_addr_cycle++] = byte; - } else if (chip->sm_state == NANDSIM_STATE_WAIT_ADDR_COL) { - ncycles = (chip->params.address_cycles >> 4) & 0xf; - buffer[chip->sm_addr_cycle++] = byte; - } - - nand_debug(NDBG_SIM, "Chip [%x] read addr byte: %02x (%d of %d)\n", - chip->chip_num, byte, chip->sm_addr_cycle, ncycles); - - if (chip->sm_addr_cycle == ncycles) { - chip->sm_addr_cycle = 0; - return (0); - } - - return (1); -} - -static int -nandchip_is_block_valid(struct nandsim_chip *chip, int block_num) -{ - - if (!chip || !chip->blk_state) - return (0); - - if (chip->blk_state[block_num].wear_lev == 0 || - chip->blk_state[block_num].is_bad) - return (0); - - return (1); -} - -static void -nandchip_set_status(struct nandsim_chip *chip, uint8_t flags) -{ - - chip->chip_status |= flags; -} - -static void -nandchip_clear_status(struct nandsim_chip *chip, uint8_t flags) -{ - - chip->chip_status &= ~flags; -} - -uint8_t -nandchip_get_status(struct nandsim_chip *chip) -{ - return (chip->chip_status); -} - -void -nandsim_chip_timeout(struct nandsim_chip *chip) -{ - struct timeval tv; - - getmicrotime(&tv); - - if (chip->sm_state == NANDSIM_STATE_TIMEOUT && - timevalcmp(&tv, &chip->delay_tv, >=)) { - nandchip_set_status(chip, NAND_STATUS_RDY); - } -} -void -poweron_evh(struct nandsim_chip *chip, uint32_t type, void *data) -{ - uint8_t cmd; - - if (type == NANDSIM_EV_START) - chip->sm_state = NANDSIM_STATE_IDLE; - else if (type == NANDSIM_EV_CMD) { - cmd = *(uint8_t *)data; - switch(cmd) { - case NAND_CMD_RESET: - nandsim_log(chip, NANDSIM_LOG_SM, "in RESET state\n"); - nandsim_start_handler(chip, reset_evh); - break; - default: - nandsim_undefined(chip, type); - break; - } - } else - nandsim_undefined(chip, type); -} - -void -idle_evh(struct nandsim_chip *chip, uint32_t type, void *data) -{ - uint8_t cmd; - - if (type == NANDSIM_EV_START) { - nandsim_log(chip, NANDSIM_LOG_SM, "in IDLE state\n"); - chip->sm_state = NANDSIM_STATE_WAIT_CMD; - } else if (type == NANDSIM_EV_CMD) { - nandchip_clear_status(chip, NAND_STATUS_FAIL); - getmicrotime(&chip->delay_tv); - cmd = *(uint8_t *)data; - switch(cmd) { - case NAND_CMD_READ_ID: - nandsim_start_handler(chip, readid_evh); - break; - case NAND_CMD_READ_PARAMETER: - nandsim_start_handler(chip, readparam_evh); - break; - case NAND_CMD_READ: - nandsim_start_handler(chip, read_evh); - break; - case NAND_CMD_PROG: - nandsim_start_handler(chip, write_evh); - break; - case NAND_CMD_ERASE: - nandsim_start_handler(chip, erase_evh); - break; - default: - nandsim_undefined(chip, type); - break; - } - } else - nandsim_undefined(chip, type); -} - -void -readid_evh(struct nandsim_chip *chip, uint32_t type, void *data) -{ - struct onfi_params *params; - uint8_t addr; - - params = &chip->params; - - if (type == NANDSIM_EV_START) { - nandsim_log(chip, NANDSIM_LOG_SM, "in READID state\n"); - chip->sm_state = NANDSIM_STATE_WAIT_ADDR_BYTE; - } else if (type == NANDSIM_EV_ADDR) { - - addr = *((uint8_t *)data); - - if (addr == 0x0) - nandchip_set_data(chip, (uint8_t *)&chip->id, 2, 0); - else if (addr == ONFI_SIG_ADDR) - nandchip_set_data(chip, (uint8_t *)¶ms->signature, - 4, 0); - else - nandsim_bad_address(chip, &addr); - - nandsim_start_handler(chip, idle_evh); - } else - nandsim_undefined(chip, type); -} - -void -readparam_evh(struct nandsim_chip *chip, uint32_t type, void *data) -{ - struct onfi_params *params; - uint8_t addr; - - params = &chip->params; - - if (type == NANDSIM_EV_START) { - nandsim_log(chip, NANDSIM_LOG_SM, "in READPARAM state\n"); - chip->sm_state = NANDSIM_STATE_WAIT_ADDR_BYTE; - } else if (type == NANDSIM_EV_ADDR) { - addr = *((uint8_t *)data); - - if (addr == 0) { - nandchip_set_data(chip, (uint8_t *)params, - sizeof(*params), 0); - } else - nandsim_bad_address(chip, &addr); - - nandsim_start_handler(chip, idle_evh); - } else - nandsim_undefined(chip, type); -} - -void -read_evh(struct nandsim_chip *chip, uint32_t type, void *data) -{ - static uint32_t column = 0, row = 0; - uint32_t size; - uint8_t cmd; - - size = chip->cg.page_size + chip->cg.oob_size; - - switch (type) { - case NANDSIM_EV_START: - nandsim_log(chip, NANDSIM_LOG_SM, "in READ state\n"); - chip->sm_state = NANDSIM_STATE_WAIT_ADDR_COL; - break; - case NANDSIM_EV_ADDR: - if (chip->sm_state == NANDSIM_STATE_WAIT_ADDR_COL) { - if (nandchip_get_addr_byte(chip, data, &column)) - break; - - chip->sm_state = NANDSIM_STATE_WAIT_ADDR_ROW; - } else if (chip->sm_state == NANDSIM_STATE_WAIT_ADDR_ROW) { - if (nandchip_get_addr_byte(chip, data, &row)) - break; - - chip->sm_state = NANDSIM_STATE_WAIT_CMD; - } else - nandsim_ignore_address(chip, *((uint8_t *)data)); - break; - case NANDSIM_EV_CMD: - cmd = *(uint8_t *)data; - if (chip->sm_state == NANDSIM_STATE_WAIT_CMD && - cmd == NAND_CMD_READ_END) { - if (chip->read_delay != 0 && - nandsim_delay(chip, chip->read_delay) == 0) - nandchip_clear_status(chip, NAND_STATUS_RDY); - else { - nandchip_chip_space(chip, row, column, size, 0); - nandchip_set_status(chip, NAND_STATUS_RDY); - nandsim_start_handler(chip, idle_evh); - } - } else - nandsim_undefined(chip, type); - break; - case NANDSIM_EV_TIMEOUT: - if (chip->sm_state == NANDSIM_STATE_TIMEOUT) { - nandchip_chip_space(chip, row, column, size, 0); - nandchip_set_status(chip, NAND_STATUS_RDY); - nandsim_start_handler(chip, idle_evh); - } else - nandsim_undefined(chip, type); - break; - } -} -void -write_evh(struct nandsim_chip *chip, uint32_t type, void *data) -{ - static uint32_t column, row; - uint32_t size; - uint8_t cmd; - int err; - - size = chip->cg.page_size + chip->cg.oob_size; - - switch(type) { - case NANDSIM_EV_START: - nandsim_log(chip, NANDSIM_LOG_SM, "in WRITE state\n"); - chip->sm_state = NANDSIM_STATE_WAIT_ADDR_COL; - break; - case NANDSIM_EV_ADDR: - if (chip->sm_state == NANDSIM_STATE_WAIT_ADDR_COL) { - if (nandchip_get_addr_byte(chip, data, &column)) - break; - - chip->sm_state = NANDSIM_STATE_WAIT_ADDR_ROW; - } else if (chip->sm_state == NANDSIM_STATE_WAIT_ADDR_ROW) { - if (nandchip_get_addr_byte(chip, data, &row)) - break; - - err = nandchip_chip_space(chip, row, column, size, 1); - if (err == -1) - nandchip_set_status(chip, NAND_STATUS_FAIL); - - chip->sm_state = NANDSIM_STATE_WAIT_CMD; - } else - nandsim_ignore_address(chip, *((uint8_t *)data)); - break; - case NANDSIM_EV_CMD: - cmd = *(uint8_t *)data; - if (chip->sm_state == NANDSIM_STATE_WAIT_CMD && - cmd == NAND_CMD_PROG_END) { - if (chip->prog_delay != 0 && - nandsim_delay(chip, chip->prog_delay) == 0) - nandchip_clear_status(chip, NAND_STATUS_RDY); - else { - nandchip_set_status(chip, NAND_STATUS_RDY); - nandsim_start_handler(chip, idle_evh); - } - } else - nandsim_undefined(chip, type); - break; - case NANDSIM_EV_TIMEOUT: - if (chip->sm_state == NANDSIM_STATE_TIMEOUT) { - nandsim_start_handler(chip, idle_evh); - nandchip_set_status(chip, NAND_STATUS_RDY); - } else - nandsim_undefined(chip, type); - break; - } -} - -void -erase_evh(struct nandsim_chip *chip, uint32_t type, void *data) -{ - static uint32_t row, block_size; - uint32_t lun, block, page; - int err; - uint8_t cmd; - - block_size = chip->cg.block_size + - (chip->cg.oob_size * chip->cg.pgs_per_blk); - - switch (type) { - case NANDSIM_EV_START: - nandsim_log(chip, NANDSIM_LOG_SM, "in ERASE state\n"); - chip->sm_state = NANDSIM_STATE_WAIT_ADDR_ROW; - break; - case NANDSIM_EV_CMD: - cmd = *(uint8_t *)data; - if (chip->sm_state == NANDSIM_STATE_WAIT_CMD && - cmd == NAND_CMD_ERASE_END) { - if (chip->data.data_ptr != NULL && - chip->data.size == block_size) - memset(chip->data.data_ptr, 0xff, block_size); - else - nand_debug(NDBG_SIM,"Bad block erase data\n"); - - err = nand_row_to_blkpg(&chip->cg, row, &lun, - &block, &page); - if (!err) { - if (chip->blk_state[block].wear_lev > 0) - chip->blk_state[block].wear_lev--; - } - - if (chip->erase_delay != 0 && - nandsim_delay(chip, chip->erase_delay) == 0) - nandchip_clear_status(chip, NAND_STATUS_RDY); - else { - nandchip_set_status(chip, NAND_STATUS_RDY); - nandsim_start_handler(chip, idle_evh); - } - } else - nandsim_undefined(chip, type); - break; - case NANDSIM_EV_ADDR: - if (chip->sm_state == NANDSIM_STATE_WAIT_ADDR_ROW) { - if (nandchip_get_addr_byte(chip, data, &row)) - break; - - err = nandchip_chip_space(chip, row, 0, block_size, 1); - if (err == -1) { - nandchip_set_status(chip, NAND_STATUS_FAIL); - } - chip->sm_state = NANDSIM_STATE_WAIT_CMD; - } else - nandsim_ignore_address(chip, *((uint8_t *)data)); - break; - case NANDSIM_EV_TIMEOUT: - if (chip->sm_state == NANDSIM_STATE_TIMEOUT) { - nandchip_set_status(chip, NAND_STATUS_RDY); - nandsim_start_handler(chip, idle_evh); - } else - nandsim_undefined(chip, type); - break; - } -} - -void -reset_evh(struct nandsim_chip *chip, uint32_t type, void *data) -{ - - if (type == NANDSIM_EV_START) { - nandsim_log(chip, NANDSIM_LOG_SM, "in RESET state\n"); - chip->sm_state = NANDSIM_STATE_TIMEOUT; - nandchip_set_data(chip, NULL, 0, 0); - DELAY(500); - nandsim_start_handler(chip, idle_evh); - } else - nandsim_undefined(chip, type); -} - -static void -nandsim_undefined(struct nandsim_chip *chip, uint8_t type) -{ - - nandsim_log(chip, NANDSIM_LOG_ERR, - "ERR: Chip received ev %x in state %x\n", - type, chip->sm_state); - nandsim_start_handler(chip, idle_evh); -} - -static void -nandsim_bad_address(struct nandsim_chip *chip, uint8_t *addr) -{ - - nandsim_log(chip, NANDSIM_LOG_ERR, - "ERR: Chip received out of range address" - "%02x%02x - %02x%02x%02x\n", addr[0], addr[1], addr[2], - addr[3], addr[4]); -} - -static void -nandsim_ignore_address(struct nandsim_chip *chip, uint8_t byte) -{ - nandsim_log(chip, NANDSIM_LOG_SM, "ignored address byte: %d\n", byte); -} - -static void -nandsim_sm_error(struct nandsim_chip *chip) -{ - - nandsim_log(chip, NANDSIM_LOG_ERR, "ERR: State machine error." - "Restart required.\n"); -} diff --git a/sys/dev/nand/nandsim_chip.h b/sys/dev/nand/nandsim_chip.h deleted file mode 100644 index 86ced5ea2bf27..0000000000000 --- a/sys/dev/nand/nandsim_chip.h +++ /dev/null @@ -1,161 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _NANDSIM_CHIP_H -#define _NANDSIM_CHIP_H - -#include <sys/malloc.h> -#include <sys/callout.h> -#include <dev/nand/nand.h> -#include <dev/nand/nandsim.h> -#include <dev/nand/nandsim_swap.h> - -MALLOC_DECLARE(M_NANDSIM); - -#define MAX_CS_NUM 4 -struct nandsim_chip; - -typedef void nandsim_evh_t(struct nandsim_chip *chip, uint32_t ev, void *data); - -enum addr_type { - ADDR_NONE, - ADDR_ID, - ADDR_ROW, - ADDR_ROWCOL -}; - -struct nandsim_softc { - struct nand_softc nand_dev; - device_t dev; - - struct nandsim_chip *chips[MAX_CS_NUM]; - struct nandsim_chip *active_chip; - - uint8_t address_cycle; - enum addr_type address_type; - int log_idx; - char *log_buff; - struct alq *alq; -}; - -struct nandsim_ev { - STAILQ_ENTRY(nandsim_ev) links; - struct nandsim_chip *chip; - uint8_t type; - void *data; -}; - -struct nandsim_data { - uint8_t *data_ptr; - uint32_t index; - uint32_t size; -}; - -struct nandsim_block_state { - int32_t wear_lev; - uint8_t is_bad; -}; - -#define NANDSIM_CHIP_ACTIVE 0x1 -#define NANDSIM_CHIP_FROZEN 0x2 -#define NANDSIM_CHIP_GET_STATUS 0x4 - -struct nandsim_chip { - struct nandsim_softc *sc; - struct thread *nandsim_td; - - STAILQ_HEAD(, nandsim_ev) nandsim_events; - nandsim_evh_t *ev_handler; - struct mtx ns_lock; - struct callout ns_callout; - - struct chip_geom cg; - struct nand_id id; - struct onfi_params params; - struct nandsim_data data; - struct nandsim_block_state *blk_state; - - struct chip_swap *swap; - - uint32_t error_ratio; - uint32_t wear_level; - uint32_t sm_state; - uint32_t sm_addr_cycle; - - uint32_t erase_delay; - uint32_t prog_delay; - uint32_t read_delay; - struct timeval delay_tv; - - uint8_t flags; - uint8_t chip_status; - uint8_t ctrl_num; - uint8_t chip_num; -}; - -struct sim_ctrl_conf { - uint8_t num; - uint8_t num_cs; - uint8_t ecc; - uint8_t running; - uint8_t created; - device_t sim_ctrl_dev; - struct sim_chip *chips[MAX_CTRL_CS]; - uint16_t ecc_layout[MAX_ECC_BYTES]; - char filename[FILENAME_SIZE]; -}; - -#define NANDSIM_STATE_IDLE 0x0 -#define NANDSIM_STATE_WAIT_ADDR_BYTE 0x1 -#define NANDSIM_STATE_WAIT_CMD 0x2 -#define NANDSIM_STATE_TIMEOUT 0x3 -#define NANDSIM_STATE_WAIT_ADDR_ROW 0x4 -#define NANDSIM_STATE_WAIT_ADDR_COL 0x5 - -#define NANDSIM_EV_START 0x1 -#define NANDSIM_EV_CMD 0x2 -#define NANDSIM_EV_ADDR 0x3 -#define NANDSIM_EV_TIMEOUT 0x4 -#define NANDSIM_EV_EXIT 0xff - -struct nandsim_chip *nandsim_chip_init(struct nandsim_softc *, - uint8_t, struct sim_chip *); -void nandsim_chip_destroy(struct nandsim_chip *); -void nandsim_chip_freeze(struct nandsim_chip *); -void nandsim_chip_timeout(struct nandsim_chip *); -int nandsim_chip_check_bad_block(struct nandsim_chip *, int); - -uint8_t nandchip_get_status(struct nandsim_chip *); - -void destroy_event(struct nandsim_ev *); -int send_event(struct nandsim_ev *); -struct nandsim_ev *create_event(struct nandsim_chip *, uint8_t, uint8_t); - -#endif /* _NANDSIM_CHIP_H */ diff --git a/sys/dev/nand/nandsim_ctrl.c b/sys/dev/nand/nandsim_ctrl.c deleted file mode 100644 index bc203902fe7e8..0000000000000 --- a/sys/dev/nand/nandsim_ctrl.c +++ /dev/null @@ -1,398 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* Simulated NAND controller driver */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/proc.h> -#include <sys/bus.h> -#include <sys/conf.h> -#include <sys/kernel.h> -#include <sys/module.h> -#include <sys/rman.h> -#include <sys/lock.h> -#include <sys/mutex.h> -#include <sys/time.h> - -#include <dev/nand/nand.h> -#include <dev/nand/nandbus.h> -#include <dev/nand/nandsim.h> -#include <dev/nand/nandsim_log.h> -#include <dev/nand/nandsim_chip.h> -#include "nfc_if.h" - -#define ADDRESS_SIZE 5 - -extern struct sim_ctrl_conf ctrls[MAX_SIM_DEV]; - -static void byte_corrupt(struct nandsim_chip *, uint8_t *); - -static int nandsim_attach(device_t); -static int nandsim_detach(device_t); -static int nandsim_probe(device_t); - -static uint8_t nandsim_read_byte(device_t); -static uint16_t nandsim_read_word(device_t); -static int nandsim_select_cs(device_t, uint8_t); -static void nandsim_write_byte(device_t, uint8_t); -static void nandsim_write_word(device_t, uint16_t); -static void nandsim_read_buf(device_t, void *, uint32_t); -static void nandsim_write_buf(device_t, void *, uint32_t); -static int nandsim_send_command(device_t, uint8_t); -static int nandsim_send_address(device_t, uint8_t); - -static device_method_t nandsim_methods[] = { - DEVMETHOD(device_probe, nandsim_probe), - DEVMETHOD(device_attach, nandsim_attach), - DEVMETHOD(device_detach, nandsim_detach), - - DEVMETHOD(nfc_select_cs, nandsim_select_cs), - DEVMETHOD(nfc_send_command, nandsim_send_command), - DEVMETHOD(nfc_send_address, nandsim_send_address), - DEVMETHOD(nfc_read_byte, nandsim_read_byte), - DEVMETHOD(nfc_read_word, nandsim_read_word), - DEVMETHOD(nfc_write_byte, nandsim_write_byte), - DEVMETHOD(nfc_read_buf, nandsim_read_buf), - DEVMETHOD(nfc_write_buf, nandsim_write_buf), - - { 0, 0 }, -}; - -static driver_t nandsim_driver = { - "nandsim", - nandsim_methods, - sizeof(struct nandsim_softc), -}; - -static devclass_t nandsim_devclass; -DRIVER_MODULE(nandsim, nexus, nandsim_driver, nandsim_devclass, 0, 0); -DRIVER_MODULE(nandbus, nandsim, nandbus_driver, nandbus_devclass, 0, 0); - -static int -nandsim_probe(device_t dev) -{ - - device_set_desc(dev, "NAND controller simulator"); - return (BUS_PROBE_DEFAULT); -} - -static int -nandsim_attach(device_t dev) -{ - struct nandsim_softc *sc; - struct sim_ctrl_conf *params; - struct sim_chip *chip; - uint16_t *eccpos; - int i, err; - - sc = device_get_softc(dev); - params = &ctrls[device_get_unit(dev)]; - - if (strlen(params->filename) == 0) - snprintf(params->filename, FILENAME_SIZE, "ctrl%d.log", - params->num); - - nandsim_log_init(sc, params->filename); - for (i = 0; i < params->num_cs; i++) { - chip = params->chips[i]; - if (chip && chip->device_id != 0) { - sc->chips[i] = nandsim_chip_init(sc, i, chip); - if (chip->features & ONFI_FEAT_16BIT) - sc->nand_dev.flags |= NAND_16_BIT; - } - } - - if (params->ecc_layout[0] != 0xffff) - eccpos = params->ecc_layout; - else - eccpos = NULL; - - nand_init(&sc->nand_dev, dev, params->ecc, 0, 0, eccpos, "nandsim"); - - err = nandbus_create(dev); - - return (err); -} - -static int -nandsim_detach(device_t dev) -{ - struct nandsim_softc *sc; - struct sim_ctrl_conf *params; - int i; - - sc = device_get_softc(dev); - params = &ctrls[device_get_unit(dev)]; - - for (i = 0; i < params->num_cs; i++) - if (sc->chips[i] != NULL) - nandsim_chip_destroy(sc->chips[i]); - - nandsim_log_close(sc); - - return (0); -} - -static int -nandsim_select_cs(device_t dev, uint8_t cs) -{ - struct nandsim_softc *sc; - - sc = device_get_softc(dev); - - if (cs >= MAX_CS_NUM) - return (EINVAL); - - sc->active_chip = sc->chips[cs]; - - if (sc->active_chip) - nandsim_log(sc->active_chip, NANDSIM_LOG_EV, - "Select cs %d\n", cs); - - return (0); -} - -static int -nandsim_send_command(device_t dev, uint8_t command) -{ - struct nandsim_softc *sc; - struct nandsim_chip *chip; - struct nandsim_ev *ev; - - sc = device_get_softc(dev); - chip = sc->active_chip; - - if (chip == NULL) - return (0); - - nandsim_log(chip, NANDSIM_LOG_EV, "Send command %x\n", command); - - switch (command) { - case NAND_CMD_READ_ID: - case NAND_CMD_READ_PARAMETER: - sc->address_type = ADDR_ID; - break; - case NAND_CMD_ERASE: - sc->address_type = ADDR_ROW; - break; - case NAND_CMD_READ: - case NAND_CMD_PROG: - sc->address_type = ADDR_ROWCOL; - break; - default: - sc->address_type = ADDR_NONE; - break; - } - - if (command == NAND_CMD_STATUS) - chip->flags |= NANDSIM_CHIP_GET_STATUS; - else { - ev = create_event(chip, NANDSIM_EV_CMD, 1); - *(uint8_t *)ev->data = command; - send_event(ev); - } - - return (0); -} - -static int -nandsim_send_address(device_t dev, uint8_t addr) -{ - struct nandsim_ev *ev; - struct nandsim_softc *sc; - struct nandsim_chip *chip; - - sc = device_get_softc(dev); - chip = sc->active_chip; - - if (chip == NULL) - return (0); - - KASSERT((sc->address_type != ADDR_NONE), ("unexpected address")); - nandsim_log(chip, NANDSIM_LOG_EV, "Send addr %x\n", addr); - - ev = create_event(chip, NANDSIM_EV_ADDR, 1); - - *((uint8_t *)(ev->data)) = addr; - - send_event(ev); - return (0); -} - -static uint8_t -nandsim_read_byte(device_t dev) -{ - struct nandsim_softc *sc; - struct nandsim_chip *chip; - uint8_t ret = 0xff; - - sc = device_get_softc(dev); - chip = sc->active_chip; - - if (chip && !(chip->flags & NANDSIM_CHIP_FROZEN)) { - if (chip->flags & NANDSIM_CHIP_GET_STATUS) { - nandsim_chip_timeout(chip); - ret = nandchip_get_status(chip); - chip->flags &= ~NANDSIM_CHIP_GET_STATUS; - } else if (chip->data.index < chip->data.size) { - ret = chip->data.data_ptr[chip->data.index++]; - byte_corrupt(chip, &ret); - } - nandsim_log(chip, NANDSIM_LOG_DATA, "read %02x\n", ret); - } - - return (ret); -} - -static uint16_t -nandsim_read_word(device_t dev) -{ - struct nandsim_softc *sc; - struct nandsim_chip *chip; - uint16_t *data_ptr; - uint16_t ret = 0xffff; - uint8_t *byte_ret = (uint8_t *)&ret; - - sc = device_get_softc(dev); - chip = sc->active_chip; - - if (chip && !(chip->flags & NANDSIM_CHIP_FROZEN)) { - if (chip->data.index < chip->data.size - 1) { - data_ptr = - (uint16_t *)&(chip->data.data_ptr[chip->data.index]); - ret = *data_ptr; - chip->data.index += 2; - byte_corrupt(chip, byte_ret); - byte_corrupt(chip, byte_ret + 1); - } - nandsim_log(chip, NANDSIM_LOG_DATA, "read %04x\n", ret); - } - - return (ret); -} - -static void -nandsim_write_byte(device_t dev, uint8_t byte) -{ - struct nandsim_softc *sc; - struct nandsim_chip *chip; - - sc = device_get_softc(dev); - chip = sc->active_chip; - - if (chip && !(chip->flags & NANDSIM_CHIP_FROZEN) && - (chip->data.index < chip->data.size)) { - byte_corrupt(chip, &byte); - chip->data.data_ptr[chip->data.index] &= byte; - chip->data.index++; - nandsim_log(chip, NANDSIM_LOG_DATA, "write %02x\n", byte); - } -} - -static void -nandsim_write_word(device_t dev, uint16_t word) -{ - struct nandsim_softc *sc; - struct nandsim_chip *chip; - uint16_t *data_ptr; - uint8_t *byte_ptr = (uint8_t *)&word; - - sc = device_get_softc(dev); - chip = sc->active_chip; - - if (chip && !(chip->flags & NANDSIM_CHIP_FROZEN)) { - if ((chip->data.index + 1) < chip->data.size) { - byte_corrupt(chip, byte_ptr); - byte_corrupt(chip, byte_ptr + 1); - data_ptr = - (uint16_t *)&(chip->data.data_ptr[chip->data.index]); - *data_ptr &= word; - chip->data.index += 2; - } - - nandsim_log(chip, NANDSIM_LOG_DATA, "write %04x\n", word); - } -} - -static void -nandsim_read_buf(device_t dev, void *buf, uint32_t len) -{ - struct nandsim_softc *sc; - uint16_t *buf16 = (uint16_t *)buf; - uint8_t *buf8 = (uint8_t *)buf; - int i; - - sc = device_get_softc(dev); - - if (sc->nand_dev.flags & NAND_16_BIT) { - for (i = 0; i < len / 2; i++) - buf16[i] = nandsim_read_word(dev); - } else { - for (i = 0; i < len; i++) - buf8[i] = nandsim_read_byte(dev); - } -} - -static void -nandsim_write_buf(device_t dev, void *buf, uint32_t len) -{ - struct nandsim_softc *sc; - uint16_t *buf16 = (uint16_t *)buf; - uint8_t *buf8 = (uint8_t *)buf; - int i; - - sc = device_get_softc(dev); - - if (sc->nand_dev.flags & NAND_16_BIT) { - for (i = 0; i < len / 2; i++) - nandsim_write_word(dev, buf16[i]); - } else { - for (i = 0; i < len; i++) - nandsim_write_byte(dev, buf8[i]); - } -} - -static void -byte_corrupt(struct nandsim_chip *chip, uint8_t *byte) -{ - uint32_t rand; - uint8_t bit; - - rand = random(); - if ((rand % 1000000) < chip->error_ratio) { - bit = rand % 8; - if (*byte & (1 << bit)) - *byte &= ~(1 << bit); - else - *byte |= (1 << bit); - } -} diff --git a/sys/dev/nand/nandsim_log.c b/sys/dev/nand/nandsim_log.c deleted file mode 100644 index 0bd316ace4e2d..0000000000000 --- a/sys/dev/nand/nandsim_log.c +++ /dev/null @@ -1,188 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/module.h> -#include <sys/malloc.h> -#include <sys/proc.h> -#include <sys/alq.h> -#include <sys/time.h> - -#include <machine/stdarg.h> - -#include <dev/nand/nandsim_log.h> - -int nandsim_log_level; -int nandsim_log_output; -int log_size = NANDSIM_RAM_LOG_SIZE; - -static int nandsim_entry_size = NANDSIM_ENTRY_SIZE; -static int nandsim_entry_count = NANDSIM_ENTRY_COUNT; -static int str_index = 0; -static char string[NANDSIM_ENTRY_SIZE + 1] = {0}; - -int -nandsim_log_init(struct nandsim_softc *sc, char *filename) -{ - int error = 0; - - if (nandsim_log_output == NANDSIM_OUTPUT_FILE) { - error = alq_open(&sc->alq, filename, - curthread->td_ucred, 0644, - nandsim_entry_size, nandsim_entry_count); - } else if (nandsim_log_output == NANDSIM_OUTPUT_RAM) { - sc->log_buff = malloc(log_size, M_NANDSIM, M_WAITOK | M_ZERO); - if (!sc->log_buff) - error = ENOMEM; - } - - return (error); -} - -void -nandsim_log_close(struct nandsim_softc *sc) -{ - - if (nandsim_log_output == NANDSIM_OUTPUT_FILE) { - memset(&string[str_index], 0, NANDSIM_ENTRY_SIZE - str_index); - alq_write(sc->alq, (void *) string, ALQ_NOWAIT); - str_index = 0; - string[0] = '\0'; - alq_close(sc->alq); - } else if (nandsim_log_output == NANDSIM_OUTPUT_RAM) { - free(sc->log_buff, M_NANDSIM); - sc->log_buff = NULL; - } -} - -void -nandsim_log(struct nandsim_chip *chip, int level, const char *fmt, ...) -{ - char hdr[TIME_STR_SIZE]; - char tmp[NANDSIM_ENTRY_SIZE]; - struct nandsim_softc *sc; - struct timeval currtime; - va_list ap; - int hdr_len, len, rest; - - if (nandsim_log_output == NANDSIM_OUTPUT_NONE) - return; - - if (chip == NULL) - return; - - sc = chip->sc; - if (!sc->alq && nandsim_log_output == NANDSIM_OUTPUT_FILE) - return; - - if (level <= nandsim_log_level) { - microtime(&currtime); - hdr_len = sprintf(hdr, "%08jd.%08li [chip:%d, ctrl:%d]: ", - (intmax_t)currtime.tv_sec, currtime.tv_usec, - chip->chip_num, chip->ctrl_num); - - switch(nandsim_log_output) { - case NANDSIM_OUTPUT_CONSOLE: - printf("%s", hdr); - va_start(ap, fmt); - vprintf(fmt, ap); - va_end(ap); - break; - case NANDSIM_OUTPUT_RAM: - va_start(ap, fmt); - len = vsnprintf(tmp, NANDSIM_ENTRY_SIZE - 1, fmt, ap); - tmp[NANDSIM_ENTRY_SIZE - 1] = 0; - va_end(ap); - - rest = log_size - sc->log_idx - 1; - if (rest >= hdr_len) { - bcopy(hdr, &sc->log_buff[sc->log_idx], - hdr_len); - sc->log_idx += hdr_len; - sc->log_buff[sc->log_idx] = 0; - } else { - bcopy(hdr, &sc->log_buff[sc->log_idx], rest); - bcopy(&hdr[rest], sc->log_buff, - hdr_len - rest); - sc->log_idx = hdr_len - rest; - sc->log_buff[sc->log_idx] = 0; - } - - rest = log_size - sc->log_idx - 1; - if (rest >= len) { - bcopy(tmp, &sc->log_buff[sc->log_idx], len); - sc->log_idx += len; - sc->log_buff[sc->log_idx] = 0; - } else { - bcopy(tmp, &sc->log_buff[sc->log_idx], rest); - bcopy(&tmp[rest], sc->log_buff, len - rest); - sc->log_idx = len - rest; - sc->log_buff[sc->log_idx] = 0; - } - - break; - - case NANDSIM_OUTPUT_FILE: - va_start(ap, fmt); - len = vsnprintf(tmp, NANDSIM_ENTRY_SIZE - 1, fmt, ap); - tmp[NANDSIM_ENTRY_SIZE - 1] = 0; - va_end(ap); - - rest = NANDSIM_ENTRY_SIZE - str_index; - if (rest >= hdr_len) { - strcat(string, hdr); - str_index += hdr_len; - } else { - strlcat(string, hdr, NANDSIM_ENTRY_SIZE + 1); - alq_write(sc->alq, (void *) string, - ALQ_NOWAIT); - strcpy(string, &hdr[rest]); - str_index = hdr_len - rest; - } - rest = NANDSIM_ENTRY_SIZE - str_index; - if (rest >= len) { - strcat(string, tmp); - str_index += len; - } else { - strlcat(string, tmp, NANDSIM_ENTRY_SIZE + 1); - alq_write(sc->alq, (void *) string, - ALQ_NOWAIT); - strcpy(string, &tmp[rest]); - str_index = len - rest; - } - break; - default: - break; - } - } -} diff --git a/sys/dev/nand/nandsim_log.h b/sys/dev/nand/nandsim_log.h deleted file mode 100644 index 5e5a055a40533..0000000000000 --- a/sys/dev/nand/nandsim_log.h +++ /dev/null @@ -1,54 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _NANDSIM_LOG_H -#define _NANDSIM_LOG_H - -#include <dev/nand/nandsim_chip.h> - -#define NANDSIM_ENTRY_SIZE 128 -#define NANDSIM_ENTRY_COUNT 1024 -#define NANDSIM_RAM_LOG_SIZE 16384 -#define TIME_STR_SIZE 40 - -#define NANDSIM_LOG_ERR 1 -#define NANDSIM_LOG_SM 5 -#define NANDSIM_LOG_EV 10 -#define NANDSIM_LOG_DATA 15 - -extern int nandsim_log_level; -extern int nandsim_log_output; - -int nandsim_log_init(struct nandsim_softc *, char *); -void nandsim_log_close(struct nandsim_softc *); -void nandsim_log(struct nandsim_chip *, int, const char *, ...); - -#endif /* _NANDSIM_LOG_H */ - diff --git a/sys/dev/nand/nandsim_swap.c b/sys/dev/nand/nandsim_swap.c deleted file mode 100644 index 78e14e9557bd5..0000000000000 --- a/sys/dev/nand/nandsim_swap.c +++ /dev/null @@ -1,383 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/types.h> -#include <sys/systm.h> -#include <sys/malloc.h> -#include <sys/queue.h> -#include <sys/fcntl.h> -#include <sys/proc.h> -#include <sys/namei.h> -#include <sys/lock.h> -#include <sys/vnode.h> -#include <sys/mount.h> - -#include <dev/nand/nandsim_chip.h> -#include <dev/nand/nandsim_swap.h> - -static int init_block_state(struct chip_swap *); -static void destroy_block_state(struct chip_swap *); - -static int create_buffers(struct chip_swap *); -static void destroy_buffers(struct chip_swap *); - -static int swap_file_open(struct chip_swap *, const char *); -static void swap_file_close(struct chip_swap *); -static int swap_file_write(struct chip_swap *, struct block_state *); -static int swap_file_read(struct chip_swap *, struct block_state *); - -#define CHIP_SWAP_CMODE 0600 -#define CHIP_SWAP_BLOCKSPACES 2 - -static int -init_block_state(struct chip_swap *swap) -{ - struct block_state *blk_state; - int i; - - if (swap == NULL) - return (-1); - - blk_state = malloc(swap->nof_blks * sizeof(struct block_state), - M_NANDSIM, M_WAITOK | M_ZERO); - - for (i = 0; i < swap->nof_blks; i++) - blk_state[i].offset = 0xffffffff; - - swap->blk_state = blk_state; - - return (0); -} - -static void -destroy_block_state(struct chip_swap *swap) -{ - - if (swap == NULL) - return; - - if (swap->blk_state != NULL) - free(swap->blk_state, M_NANDSIM); -} - -static int -create_buffers(struct chip_swap *swap) -{ - struct block_space *block_space; - void *block; - int i; - - for (i = 0; i < CHIP_SWAP_BLOCKSPACES; i++) { - block_space = malloc(sizeof(*block_space), M_NANDSIM, M_WAITOK); - block = malloc(swap->blk_size, M_NANDSIM, M_WAITOK); - block_space->blk_ptr = block; - SLIST_INSERT_HEAD(&swap->free_bs, block_space, free_link); - nand_debug(NDBG_SIM,"created blk_space %p[%p]\n", block_space, - block); - } - - if (i == 0) - return (-1); - - return (0); -} - -static void -destroy_buffers(struct chip_swap *swap) -{ - struct block_space *blk_space; - - if (swap == NULL) - return; - - blk_space = SLIST_FIRST(&swap->free_bs); - while (blk_space) { - SLIST_REMOVE_HEAD(&swap->free_bs, free_link); - nand_debug(NDBG_SIM,"destroyed blk_space %p[%p]\n", - blk_space, blk_space->blk_ptr); - free(blk_space->blk_ptr, M_NANDSIM); - free(blk_space, M_NANDSIM); - blk_space = SLIST_FIRST(&swap->free_bs); - } - - blk_space = STAILQ_FIRST(&swap->used_bs); - while (blk_space) { - STAILQ_REMOVE_HEAD(&swap->used_bs, used_link); - nand_debug(NDBG_SIM,"destroyed blk_space %p[%p]\n", - blk_space, blk_space->blk_ptr); - free(blk_space->blk_ptr, M_NANDSIM); - free(blk_space, M_NANDSIM); - blk_space = STAILQ_FIRST(&swap->used_bs); - } -} - -static int -swap_file_open(struct chip_swap *swap, const char *swap_file) -{ - struct nameidata nd; - int flags, error; - - NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, swap_file, - curthread); - - flags = FWRITE | FREAD | O_NOFOLLOW | O_CREAT | O_TRUNC; - - error = vn_open(&nd, &flags, CHIP_SWAP_CMODE, NULL); - if (error) { - nand_debug(NDBG_SIM,"Cannot create swap file %s", swap_file); - NDFREE(&nd, NDF_ONLY_PNBUF); - return (error); - } - - swap->swap_cred = crhold(curthread->td_ucred); - NDFREE(&nd, NDF_ONLY_PNBUF); - - /* We just unlock so we hold a reference */ - VOP_UNLOCK(nd.ni_vp, 0); - - swap->swap_vp = nd.ni_vp; - - return (0); -} - -static void -swap_file_close(struct chip_swap *swap) -{ - - if (swap == NULL) - return; - - if (swap->swap_vp == NULL) - return; - - vn_close(swap->swap_vp, FWRITE, swap->swap_cred, curthread); - crfree(swap->swap_cred); -} - -static int -swap_file_write(struct chip_swap *swap, struct block_state *blk_state) -{ - struct block_space *blk_space; - struct thread *td; - struct mount *mp; - struct vnode *vp; - struct uio auio; - struct iovec aiov; - - if (swap == NULL || blk_state == NULL) - return (-1); - - blk_space = blk_state->blk_sp; - if (blk_state->offset == -1) { - blk_state->offset = swap->swap_offset; - swap->swap_offset += swap->blk_size; - } - - nand_debug(NDBG_SIM,"saving %p[%p] at %x\n", - blk_space, blk_space->blk_ptr, blk_state->offset); - - bzero(&aiov, sizeof(aiov)); - bzero(&auio, sizeof(auio)); - - aiov.iov_base = blk_space->blk_ptr; - aiov.iov_len = swap->blk_size; - td = curthread; - vp = swap->swap_vp; - - auio.uio_iov = &aiov; - auio.uio_offset = blk_state->offset; - auio.uio_segflg = UIO_SYSSPACE; - auio.uio_rw = UIO_WRITE; - auio.uio_iovcnt = 1; - auio.uio_resid = swap->blk_size; - auio.uio_td = td; - - vn_start_write(vp, &mp, V_WAIT); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); - VOP_WRITE(vp, &auio, IO_UNIT, swap->swap_cred); - VOP_UNLOCK(vp, 0); - vn_finished_write(mp); - - return (0); -} - -static int -swap_file_read(struct chip_swap *swap, struct block_state *blk_state) -{ - struct block_space *blk_space; - struct thread *td; - struct vnode *vp; - struct uio auio; - struct iovec aiov; - - if (swap == NULL || blk_state == NULL) - return (-1); - - blk_space = blk_state->blk_sp; - - nand_debug(NDBG_SIM,"restore %p[%p] at %x\n", - blk_space, blk_space->blk_ptr, blk_state->offset); - - bzero(&aiov, sizeof(aiov)); - bzero(&auio, sizeof(auio)); - - aiov.iov_base = blk_space->blk_ptr; - aiov.iov_len = swap->blk_size; - td = curthread; - vp = swap->swap_vp; - - auio.uio_iov = &aiov; - auio.uio_offset = blk_state->offset; - auio.uio_segflg = UIO_SYSSPACE; - auio.uio_rw = UIO_READ; - auio.uio_iovcnt = 1; - auio.uio_resid = swap->blk_size; - auio.uio_td = td; - - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); - VOP_READ(vp, &auio, 0, swap->swap_cred); - VOP_UNLOCK(vp, 0); - - return (0); -} - -struct chip_swap * -nandsim_swap_init(const char *swap_file, uint32_t nof_blks, uint32_t blk_size) -{ - struct chip_swap *swap; - int err = 0; - - if ((swap_file == NULL) || (nof_blks == 0) || (blk_size == 0)) - return (NULL); - - swap = malloc(sizeof(*swap), M_NANDSIM, M_WAITOK | M_ZERO); - - SLIST_INIT(&swap->free_bs); - STAILQ_INIT(&swap->used_bs); - swap->blk_size = blk_size; - swap->nof_blks = nof_blks; - - err = init_block_state(swap); - if (err) { - nandsim_swap_destroy(swap); - return (NULL); - } - - err = create_buffers(swap); - if (err) { - nandsim_swap_destroy(swap); - return (NULL); - } - - err = swap_file_open(swap, swap_file); - if (err) { - nandsim_swap_destroy(swap); - return (NULL); - } - - return (swap); -} - -void -nandsim_swap_destroy(struct chip_swap *swap) -{ - - if (swap == NULL) - return; - - destroy_block_state(swap); - destroy_buffers(swap); - swap_file_close(swap); - free(swap, M_NANDSIM); -} - -struct block_space * -get_bs(struct chip_swap *swap, uint32_t block, uint8_t writing) -{ - struct block_state *blk_state, *old_blk_state = NULL; - struct block_space *blk_space; - - if (swap == NULL || (block >= swap->nof_blks)) - return (NULL); - - blk_state = &swap->blk_state[block]; - nand_debug(NDBG_SIM,"blk_state %x\n", blk_state->status); - - if (blk_state->status & BLOCK_ALLOCATED) { - blk_space = blk_state->blk_sp; - } else { - blk_space = SLIST_FIRST(&swap->free_bs); - if (blk_space) { - SLIST_REMOVE_HEAD(&swap->free_bs, free_link); - STAILQ_INSERT_TAIL(&swap->used_bs, blk_space, - used_link); - } else { - blk_space = STAILQ_FIRST(&swap->used_bs); - old_blk_state = blk_space->blk_state; - STAILQ_REMOVE_HEAD(&swap->used_bs, used_link); - STAILQ_INSERT_TAIL(&swap->used_bs, blk_space, - used_link); - if (old_blk_state->status & BLOCK_DIRTY) { - swap_file_write(swap, old_blk_state); - old_blk_state->status &= ~BLOCK_DIRTY; - old_blk_state->status |= BLOCK_SWAPPED; - } - } - } - - if (blk_space == NULL) - return (NULL); - - if (old_blk_state != NULL) { - old_blk_state->status &= ~BLOCK_ALLOCATED; - old_blk_state->blk_sp = NULL; - } - - blk_state->blk_sp = blk_space; - blk_space->blk_state = blk_state; - - if (!(blk_state->status & BLOCK_ALLOCATED)) { - if (blk_state->status & BLOCK_SWAPPED) - swap_file_read(swap, blk_state); - else - memset(blk_space->blk_ptr, 0xff, swap->blk_size); - blk_state->status |= BLOCK_ALLOCATED; - } - - if (writing) - blk_state->status |= BLOCK_DIRTY; - - nand_debug(NDBG_SIM,"get_bs returned %p[%p] state %x\n", blk_space, - blk_space->blk_ptr, blk_state->status); - - return (blk_space); -} diff --git a/sys/dev/nand/nandsim_swap.h b/sys/dev/nand/nandsim_swap.h deleted file mode 100644 index c9eb0be63a9cd..0000000000000 --- a/sys/dev/nand/nandsim_swap.h +++ /dev/null @@ -1,66 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _NANDSIM_SWAP_CHIP_H_ -#define _NANDSIM_SWAP_CHIP_H_ - -struct block_space { - SLIST_ENTRY(block_space) free_link; - STAILQ_ENTRY(block_space) used_link; - struct block_state *blk_state; - uint8_t *blk_ptr; -}; - -#define BLOCK_ALLOCATED 0x1 -#define BLOCK_SWAPPED 0x2 -#define BLOCK_DIRTY 0x4 - -struct block_state { - struct block_space *blk_sp; - uint32_t offset; - uint8_t status; -}; - -struct chip_swap { - struct block_state *blk_state; - SLIST_HEAD(,block_space) free_bs; - STAILQ_HEAD(,block_space) used_bs; - struct ucred *swap_cred; - struct vnode *swap_vp; - uint32_t swap_offset; - uint32_t blk_size; - uint32_t nof_blks; -}; - -struct chip_swap *nandsim_swap_init(const char *, uint32_t, uint32_t); -void nandsim_swap_destroy(struct chip_swap *); -struct block_space *get_bs(struct chip_swap *, uint32_t, uint8_t); - -#endif /* _NANDSIM_SWAP_CHIP_H_ */ diff --git a/sys/dev/nand/nfc_fsl.c b/sys/dev/nand/nfc_fsl.c deleted file mode 100644 index 992cfeb784fe5..0000000000000 --- a/sys/dev/nand/nfc_fsl.c +++ /dev/null @@ -1,717 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2012 Juniper Networks, Inc. - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -/* - * TODO : - * - * -- test support for small pages - * -- support for reading ONFI parameters - * -- support for cached and interleaving commands - * -- proper setting of AL bits in FMR - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/proc.h> -#include <sys/bus.h> -#include <sys/conf.h> -#include <sys/kernel.h> -#include <sys/module.h> -#include <sys/malloc.h> -#include <sys/rman.h> -#include <sys/sysctl.h> -#include <sys/time.h> -#include <sys/kdb.h> - -#include <machine/bus.h> - -#include <dev/ofw/ofw_bus.h> -#include <dev/ofw/ofw_bus_subr.h> - -#include <powerpc/mpc85xx/lbc.h> - -#include <dev/nand/nand.h> -#include <dev/nand/nandbus.h> - -#include "nfc_fsl.h" - -#include "nfc_if.h" - -#define LBC_READ(regname) lbc_read_reg(dev, (LBC85XX_ ## regname)) -#define LBC_WRITE(regname, val) lbc_write_reg(dev, (LBC85XX_ ## regname), val) - -enum addr_type { - ADDR_NONE, - ADDR_ID, - ADDR_ROW, - ADDR_ROWCOL -}; - -struct fsl_nfc_fcm { - /* Read-only after initialization */ - uint32_t reg_fmr; - - /* To be preserved across "start_command" */ - u_int buf_ofs; - u_int read_ptr; - u_int status:1; - - /* Command state -- cleared by "start_command" */ - uint32_t fcm_startzero; - uint32_t reg_fcr; - uint32_t reg_fir; - uint32_t reg_mdr; - uint32_t reg_fbcr; - uint32_t reg_fbar; - uint32_t reg_fpar; - u_int cmdnr; - u_int opnr; - u_int pg_ofs; - enum addr_type addr_type; - u_int addr_bytes; - u_int row_addr; - u_int column_addr; - u_int data_fir:8; - uint32_t fcm_endzero; -}; - -struct fsl_nand_softc { - struct nand_softc nand_dev; - device_t dev; - struct resource *res; - int rid; /* Resourceid */ - struct lbc_devinfo *dinfo; - struct fsl_nfc_fcm fcm; - uint8_t col_cycles; - uint8_t row_cycles; - uint16_t pgsz; /* Page size */ -}; - -static int fsl_nand_attach(device_t dev); -static int fsl_nand_probe(device_t dev); -static int fsl_nand_detach(device_t dev); - -static int fsl_nfc_select_cs(device_t dev, uint8_t cs); -static int fsl_nfc_read_rnb(device_t dev); -static int fsl_nfc_send_command(device_t dev, uint8_t command); -static int fsl_nfc_send_address(device_t dev, uint8_t address); -static uint8_t fsl_nfc_read_byte(device_t dev); -static int fsl_nfc_start_command(device_t dev); -static void fsl_nfc_read_buf(device_t dev, void *buf, uint32_t len); -static void fsl_nfc_write_buf(device_t dev, void *buf, uint32_t len); - -static device_method_t fsl_nand_methods[] = { - DEVMETHOD(device_probe, fsl_nand_probe), - DEVMETHOD(device_attach, fsl_nand_attach), - DEVMETHOD(device_detach, fsl_nand_detach), - - DEVMETHOD(nfc_select_cs, fsl_nfc_select_cs), - DEVMETHOD(nfc_read_rnb, fsl_nfc_read_rnb), - DEVMETHOD(nfc_start_command, fsl_nfc_start_command), - DEVMETHOD(nfc_send_command, fsl_nfc_send_command), - DEVMETHOD(nfc_send_address, fsl_nfc_send_address), - DEVMETHOD(nfc_read_byte, fsl_nfc_read_byte), - DEVMETHOD(nfc_read_buf, fsl_nfc_read_buf), - DEVMETHOD(nfc_write_buf, fsl_nfc_write_buf), - { 0, 0 }, -}; - -static driver_t fsl_nand_driver = { - "nand", - fsl_nand_methods, - sizeof(struct fsl_nand_softc), -}; - -static devclass_t fsl_nand_devclass; - -DRIVER_MODULE(fsl_nand, lbc, fsl_nand_driver, fsl_nand_devclass, - 0, 0); - -static int fsl_nand_build_address(device_t dev, uint32_t page, uint32_t column); -static int fsl_nand_chip_preprobe(device_t dev, struct nand_id *id); - -#ifdef NAND_DEBUG_TIMING -static device_t fcm_devs[8]; -#endif - -#define CMD_SHIFT(cmd_num) (24 - ((cmd_num) * 8)) -#define OP_SHIFT(op_num) (28 - ((op_num) * 4)) - -#define FSL_LARGE_PAGE_SIZE (2112) -#define FSL_SMALL_PAGE_SIZE (528) - -static void -fsl_nand_init_regs(struct fsl_nand_softc *sc) -{ - uint32_t or_v, br_v; - device_t dev; - - dev = sc->dev; - - sc->fcm.reg_fmr = (15 << FMR_CWTO_SHIFT); - - /* - * Setup 4 row cycles and hope that chip ignores superfluous address - * bytes. - */ - sc->fcm.reg_fmr |= (2 << FMR_AL_SHIFT); - - /* Reprogram BR(x) */ - br_v = lbc_read_reg(dev, LBC85XX_BR(sc->dinfo->di_bank)); - br_v &= 0xffff8000; - br_v |= 1 << 11; /* 8-bit port size */ - br_v |= 0 << 9; /* No ECC checking and generation */ - br_v |= 1 << 5; /* FCM machine */ - br_v |= 1; /* Valid */ - lbc_write_reg(dev, LBC85XX_BR(sc->dinfo->di_bank), br_v); - - /* Reprogram OR(x) */ - or_v = lbc_read_reg(dev, LBC85XX_OR(sc->dinfo->di_bank)); - or_v &= 0xfffffc00; - or_v |= 0x03AE; /* Default POR timing */ - lbc_write_reg(dev, LBC85XX_OR(sc->dinfo->di_bank), or_v); - - if (or_v & OR_FCM_PAGESIZE) { - sc->pgsz = FSL_LARGE_PAGE_SIZE; - sc->col_cycles = 2; - nand_debug(NDBG_DRV, "%s: large page NAND device at #%d", - device_get_nameunit(dev), sc->dinfo->di_bank); - } else { - sc->pgsz = FSL_SMALL_PAGE_SIZE; - sc->col_cycles = 1; - nand_debug(NDBG_DRV, "%s: small page NAND device at #%d", - device_get_nameunit(dev), sc->dinfo->di_bank); - } -} - -static int -fsl_nand_probe(device_t dev) -{ - - if (!ofw_bus_is_compatible(dev, "fsl,elbc-fcm-nand")) - return (ENXIO); - - device_set_desc(dev, "Freescale localbus FCM Controller"); - return (BUS_PROBE_DEFAULT); -} - -static int -fsl_nand_attach(device_t dev) -{ - struct fsl_nand_softc *sc; - struct nand_id id; - struct nand_params *param; - uint32_t num_pages; - - sc = device_get_softc(dev); - sc->dev = dev; - sc->dinfo = device_get_ivars(dev); - - sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->rid, - RF_ACTIVE); - if (sc->res == NULL) { - device_printf(dev, "could not allocate resources!\n"); - return (ENXIO); - } - - bzero(&sc->fcm, sizeof(sc->fcm)); - - /* Init register and check if HW ECC turned on */ - fsl_nand_init_regs(sc); - - /* Chip is probed, so determine number of row address cycles */ - fsl_nand_chip_preprobe(dev, &id); - param = nand_get_params(&id); - if (param != NULL) { - num_pages = (param->chip_size << 20) / param->page_size; - while(num_pages) { - sc->row_cycles++; - num_pages >>= 8; - } - - sc->fcm.reg_fmr &= ~(FMR_AL); - sc->fcm.reg_fmr |= (sc->row_cycles - 2) << FMR_AL_SHIFT; - } - - nand_init(&sc->nand_dev, dev, NAND_ECC_SOFT, 0, 0, NULL, NULL); - -#ifdef NAND_DEBUG_TIMING - fcm_devs[sc->dinfo->di_bank] = dev; -#endif - - return (nandbus_create(dev)); -} - -static int -fsl_nand_detach(device_t dev) -{ - struct fsl_nand_softc *sc; - - sc = device_get_softc(dev); - - if (sc->res != NULL) - bus_release_resource(dev, SYS_RES_MEMORY, sc->rid, sc->res); - - return (0); -} - -static int -fsl_nfc_select_cs(device_t dev, uint8_t cs) -{ - - // device_printf(dev, "%s(cs=%u)\n", __func__, cs); - return ((cs > 0) ? EINVAL : 0); -} - -static int -fsl_nfc_read_rnb(device_t dev) -{ - - // device_printf(dev, "%s()\n", __func__); - return (0); -} - -static int -fsl_nfc_send_command(device_t dev, uint8_t command) -{ - struct fsl_nand_softc *sc; - struct fsl_nfc_fcm *fcm; - uint8_t fir_op; - - // device_printf(dev, "%s(command=%u)\n", __func__, command); - - sc = device_get_softc(dev); - fcm = &sc->fcm; - - if (command == NAND_CMD_PROG_END) { - fcm->reg_fir |= (FIR_OP_WB << OP_SHIFT(fcm->opnr)); - fcm->opnr++; - } - fcm->reg_fcr |= command << CMD_SHIFT(fcm->cmdnr); - fir_op = (fcm->cmdnr == 0) ? FIR_OP_CW0 : FIR_OP_CM(fcm->cmdnr); - fcm->cmdnr++; - - fcm->reg_fir |= (fir_op << OP_SHIFT(fcm->opnr)); - fcm->opnr++; - - switch (command) { - case NAND_CMD_READ_ID: - fcm->data_fir = FIR_OP_RBW; - fcm->addr_type = ADDR_ID; - break; - case NAND_CMD_SMALLOOB: - fcm->pg_ofs += 256; - /*FALLTHROUGH*/ - case NAND_CMD_SMALLB: - fcm->pg_ofs += 256; - /*FALLTHROUGH*/ - case NAND_CMD_READ: /* NAND_CMD_SMALLA */ - fcm->data_fir = FIR_OP_RBW; - fcm->addr_type = ADDR_ROWCOL; - break; - case NAND_CMD_STATUS: - fcm->data_fir = FIR_OP_RS; - fcm->status = 1; - break; - case NAND_CMD_ERASE: - fcm->addr_type = ADDR_ROW; - break; - case NAND_CMD_PROG: - fcm->addr_type = ADDR_ROWCOL; - break; - } - return (0); -} - -static int -fsl_nfc_send_address(device_t dev, uint8_t addr) -{ - struct fsl_nand_softc *sc; - struct fsl_nfc_fcm *fcm; - uint32_t addr_bits; - - // device_printf(dev, "%s(address=%u)\n", __func__, addr); - - sc = device_get_softc(dev); - fcm = &sc->fcm; - - KASSERT(fcm->addr_type != ADDR_NONE, - ("controller doesn't expect address cycle")); - - addr_bits = addr; - - if (fcm->addr_type == ADDR_ID) { - fcm->reg_fir |= (FIR_OP_UA << OP_SHIFT(fcm->opnr)); - fcm->opnr++; - - fcm->reg_fbcr = 5; - fcm->reg_fbar = 0; - fcm->reg_fpar = 0; - fcm->reg_mdr = addr_bits; - fcm->buf_ofs = 0; - fcm->read_ptr = 0; - return (0); - } - - if (fcm->addr_type == ADDR_ROW) { - addr_bits <<= fcm->addr_bytes * 8; - fcm->row_addr |= addr_bits; - fcm->addr_bytes++; - if (fcm->addr_bytes < sc->row_cycles) - return (0); - } else { - if (fcm->addr_bytes < sc->col_cycles) { - addr_bits <<= fcm->addr_bytes * 8; - fcm->column_addr |= addr_bits; - } else { - addr_bits <<= (fcm->addr_bytes - sc->col_cycles) * 8; - fcm->row_addr |= addr_bits; - } - fcm->addr_bytes++; - if (fcm->addr_bytes < (sc->row_cycles + sc->col_cycles)) - return (0); - } - - return (fsl_nand_build_address(dev, fcm->row_addr, fcm->column_addr)); -} - -static int -fsl_nand_build_address(device_t dev, uint32_t row, uint32_t column) -{ - struct fsl_nand_softc *sc; - struct fsl_nfc_fcm *fcm; - uint32_t byte_count = 0; - uint32_t block_address = 0; - uint32_t page_address = 0; - - sc = device_get_softc(dev); - fcm = &sc->fcm; - - fcm->read_ptr = 0; - fcm->buf_ofs = 0; - - if (fcm->addr_type == ADDR_ROWCOL) { - fcm->reg_fir |= (FIR_OP_CA << OP_SHIFT(fcm->opnr)); - fcm->opnr++; - - column += fcm->pg_ofs; - fcm->pg_ofs = 0; - - page_address |= column; - - if (column != 0) { - byte_count = sc->pgsz - column; - fcm->read_ptr = column; - } - } - - fcm->reg_fir |= (FIR_OP_PA << OP_SHIFT(fcm->opnr)); - fcm->opnr++; - - if (sc->pgsz == FSL_LARGE_PAGE_SIZE) { - block_address = row >> 6; - page_address |= ((row << FPAR_LP_PI_SHIFT) & FPAR_LP_PI); - fcm->buf_ofs = (row & 1) * 4096; - } else { - block_address = row >> 5; - page_address |= ((row << FPAR_SP_PI_SHIFT) & FPAR_SP_PI); - fcm->buf_ofs = (row & 7) * 1024; - } - - fcm->reg_fbcr = byte_count; - fcm->reg_fbar = block_address; - fcm->reg_fpar = page_address; - return (0); -} - -static int -fsl_nfc_start_command(device_t dev) -{ - struct fsl_nand_softc *sc; - struct fsl_nfc_fcm *fcm; - uint32_t fmr, ltesr_v; - int error, timeout; - - // device_printf(dev, "%s()\n", __func__); - - sc = device_get_softc(dev); - fcm = &sc->fcm; - - fmr = fcm->reg_fmr | FMR_OP; - - if (fcm->data_fir) - fcm->reg_fir |= (fcm->data_fir << OP_SHIFT(fcm->opnr)); - - LBC_WRITE(FIR, fcm->reg_fir); - LBC_WRITE(FCR, fcm->reg_fcr); - - LBC_WRITE(FMR, fmr); - - LBC_WRITE(FBCR, fcm->reg_fbcr); - LBC_WRITE(FBAR, fcm->reg_fbar); - LBC_WRITE(FPAR, fcm->reg_fpar); - - if (fcm->addr_type == ADDR_ID) - LBC_WRITE(MDR, fcm->reg_mdr); - - nand_debug(NDBG_DRV, "BEFORE:\nFMR=%#x, FIR=%#x, FCR=%#x", fmr, - fcm->reg_fir, fcm->reg_fcr); - nand_debug(NDBG_DRV, "MDR=%#x, FBAR=%#x, FPAR=%#x, FBCR=%#x", - LBC_READ(MDR), fcm->reg_fbar, fcm->reg_fpar, fcm->reg_fbcr); - - LBC_WRITE(LSOR, sc->dinfo->di_bank); - - timeout = (cold) ? FSL_FCM_WAIT_TIMEOUT : ~0; - error = 0; - ltesr_v = LBC_READ(LTESR); - while (!error && (ltesr_v & LTESR_CC) == 0) { - if (cold) { - DELAY(1000); - timeout--; - if (timeout < 0) - error = EWOULDBLOCK; - } else - error = tsleep(device_get_parent(sc->dev), PRIBIO, - "nfcfsl", hz); - ltesr_v = LBC_READ(LTESR); - } - if (error) - nand_debug(NDBG_DRV, "Command complete wait timeout\n"); - - nand_debug(NDBG_DRV, "AFTER:\nLTESR=%#x, LTEDR=%#x, LTEIR=%#x," - " LTEATR=%#x, LTEAR=%#x, LTECCR=%#x", ltesr_v, - LBC_READ(LTEDR), LBC_READ(LTEIR), LBC_READ(LTEATR), - LBC_READ(LTEAR), LBC_READ(LTECCR)); - - bzero(&fcm->fcm_startzero, - __rangeof(struct fsl_nfc_fcm, fcm_startzero, fcm_endzero)); - - if (fcm->status) - sc->fcm.reg_mdr = LBC_READ(MDR); - - /* Even if timeout occurred, we should perform steps below */ - LBC_WRITE(LTESR, ltesr_v); - LBC_WRITE(LTEATR, 0); - - return (error); -} - -static uint8_t -fsl_nfc_read_byte(device_t dev) -{ - struct fsl_nand_softc *sc = device_get_softc(dev); - uint32_t offset; - - // device_printf(dev, "%s()\n", __func__); - - /* - * LBC controller allows us to read status into a MDR instead of FCM - * buffer. If last operation requested before read_byte() was STATUS, - * then return MDR instead of reading a single byte from a buffer. - */ - if (sc->fcm.status) { - sc->fcm.status = 0; - return (sc->fcm.reg_mdr); - } - - KASSERT(sc->fcm.read_ptr < sc->pgsz, - ("Attempt to read beyond buffer %x %x", sc->fcm.read_ptr, - sc->pgsz)); - - offset = sc->fcm.buf_ofs + sc->fcm.read_ptr; - sc->fcm.read_ptr++; - return (bus_read_1(sc->res, offset)); -} - -static void -fsl_nfc_read_buf(device_t dev, void *buf, uint32_t len) -{ - struct fsl_nand_softc *sc = device_get_softc(dev); - uint32_t offset; - int bytesleft = 0; - - // device_printf(dev, "%s(buf=%p, len=%u)\n", __func__, buf, len); - - nand_debug(NDBG_DRV, "REQUEST OF 0x%0x B (BIB=0x%0x, NTR=0x%0x)", - len, sc->pgsz, sc->fcm.read_ptr); - - bytesleft = MIN((unsigned int)len, sc->pgsz - sc->fcm.read_ptr); - - offset = sc->fcm.buf_ofs + sc->fcm.read_ptr; - bus_read_region_1(sc->res, offset, buf, bytesleft); - sc->fcm.read_ptr += bytesleft; -} - -static void -fsl_nfc_write_buf(device_t dev, void *buf, uint32_t len) -{ - struct fsl_nand_softc *sc = device_get_softc(dev); - uint32_t offset; - int bytesleft = 0; - - // device_printf(dev, "%s(buf=%p, len=%u)\n", __func__, buf, len); - - KASSERT(len <= sc->pgsz - sc->fcm.read_ptr, - ("Attempt to write beyond buffer")); - - bytesleft = MIN((unsigned int)len, sc->pgsz - sc->fcm.read_ptr); - - nand_debug(NDBG_DRV, "REQUEST TO WRITE 0x%0x (BIB=0x%0x, NTR=0x%0x)", - bytesleft, sc->pgsz, sc->fcm.read_ptr); - - offset = sc->fcm.buf_ofs + sc->fcm.read_ptr; - bus_write_region_1(sc->res, offset, buf, bytesleft); - sc->fcm.read_ptr += bytesleft; -} - -static int -fsl_nand_chip_preprobe(device_t dev, struct nand_id *id) -{ - - if (fsl_nfc_send_command(dev, NAND_CMD_RESET) != 0) - return (ENXIO); - - if (fsl_nfc_start_command(dev) != 0) - return (ENXIO); - - DELAY(1000); - - if (fsl_nfc_send_command(dev, NAND_CMD_READ_ID)) - return (ENXIO); - - if (fsl_nfc_send_address(dev, 0)) - return (ENXIO); - - if (fsl_nfc_start_command(dev) != 0) - return (ENXIO); - - DELAY(25); - - id->man_id = fsl_nfc_read_byte(dev); - id->dev_id = fsl_nfc_read_byte(dev); - - nand_debug(NDBG_DRV, "manufacturer id: %x chip id: %x", - id->man_id, id->dev_id); - - return (0); -} - -#ifdef NAND_DEBUG_TIMING - -static SYSCTL_NODE(_debug, OID_AUTO, fcm, CTLFLAG_RD, 0, "FCM timing"); - -static u_int csct = 1; /* 22: Chip select to command time (trlx). */ -SYSCTL_UINT(_debug_fcm, OID_AUTO, csct, CTLFLAG_RW, &csct, 1, - "Chip select to command time: determines how far in advance -LCSn is " - "asserted prior to any bus activity during a NAND Flash access handled " - "by the FCM. This helps meet chip-select setup times for slow memories."); - -static u_int cst = 1; /* 23: Command setup time (trlx). */ -SYSCTL_UINT(_debug_fcm, OID_AUTO, cst, CTLFLAG_RW, &cst, 1, - "Command setup time: determines the delay of -LFWE assertion relative to " - "the command, address, or data change when the external memory access " - "is handled by the FCM."); - -static u_int cht = 1; /* 24: Command hold time (trlx). */ -SYSCTL_UINT(_debug_fcm, OID_AUTO, cht, CTLFLAG_RW, &cht, 1, - "Command hold time: determines the -LFWE negation prior to the command, " - "address, or data change when the external memory access is handled by " - "the FCM."); - -static u_int scy = 2; /* 25-27: Cycle length in bus clocks */ -SYSCTL_UINT(_debug_fcm, OID_AUTO, scy, CTLFLAG_RW, &scy, 2, - "Cycle length in bus clocks: see RM"); - -static u_int rst = 1; /* 28: Read setup time (trlx). */ -SYSCTL_UINT(_debug_fcm, OID_AUTO, rst, CTLFLAG_RW, &rst, 1, - "Read setup time: determines the delay of -LFRE assertion relative to " - "sampling of read data when the external memory access is handled by " - "the FCM."); - -static u_int trlx = 1; /* 29: Timing relaxed. */ -SYSCTL_UINT(_debug_fcm, OID_AUTO, trlx, CTLFLAG_RW, &trlx, 1, - "Timing relaxed: modifies the settings of timing parameters for slow " - "memories. See RM"); - -static u_int ehtr = 1; /* 30: Extended hold time on read accesses. */ -SYSCTL_UINT(_debug_fcm, OID_AUTO, ehtr, CTLFLAG_RW, &ehtr, 1, - "Extended hold time on read accesses: indicates with TRLX how many " - "cycles are inserted between a read access from the current bank and " - "the next access."); - -static u_int -fsl_nand_get_timing(void) -{ - u_int timing; - - timing = ((csct & 1) << 9) | ((cst & 1) << 8) | ((cht & 1) << 7) | - ((scy & 7) << 4) | ((rst & 1) << 3) | ((trlx & 1) << 2) | - ((ehtr & 1) << 1); - - printf("nfc_fsl: timing = %u\n", timing); - return (timing); -} - -static int -fsl_sysctl_program(SYSCTL_HANDLER_ARGS) -{ - struct fsl_nand_softc *sc; - int error, i; - device_t dev; - uint32_t or_v; - - error = sysctl_wire_old_buffer(req, sizeof(int)); - if (error == 0) { - i = 0; - error = sysctl_handle_int(oidp, &i, 0, req); - } - if (error != 0 || req->newptr == NULL) - return (error); - - for (i = 0; i < 8; i++) { - dev = fcm_devs[i]; - if (dev == NULL) - continue; - sc = device_get_softc(dev); - - /* Reprogram OR(x) */ - or_v = lbc_read_reg(dev, LBC85XX_OR(sc->dinfo->di_bank)); - or_v &= 0xfffffc00; - or_v |= fsl_nand_get_timing(); - lbc_write_reg(dev, LBC85XX_OR(sc->dinfo->di_bank), or_v); - } - return (0); -} - -SYSCTL_PROC(_debug_fcm, OID_AUTO, program, CTLTYPE_INT | CTLFLAG_RW, NULL, 0, - fsl_sysctl_program, "I", "write to program FCM with current values"); - -#endif /* NAND_DEBUG_TIMING */ diff --git a/sys/dev/nand/nfc_fsl.h b/sys/dev/nand/nfc_fsl.h deleted file mode 100644 index 5410da5581712..0000000000000 --- a/sys/dev/nand/nfc_fsl.h +++ /dev/null @@ -1,99 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2012 Juniper Networks, Inc. - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _NAND_NFC_FSL_H_ -#define _NAND_NFC_FSL_H_ - -/* LBC BR/OR Registers layout definitions */ -#define BR_V 0x00000001 -#define BR_V_SHIFT 0 -#define BR_MSEL 0x000000E0 -#define BR_MSEL_SHIFT 5 -#define BR_DECC_CHECK_MODE 0x00000600 -#define BR_DECC_CHECK_GEN 0x00000400 - -#define OR_FCM_PAGESIZE 0x00000400 - -/* Options definitions */ -#define NAND_OPT_ECC_MODE_HW 1 -#define NAND_OPT_ECC_MODE_SOFT (1 << 1) - -/* FMR - Flash Mode Register */ -#define FMR_CWTO 0xF000 -#define FMR_CWTO_SHIFT 12 -#define FMR_BOOT 0x0800 -#define FMR_ECCM 0x0100 -#define FMR_AL 0x0030 -#define FMR_AL_SHIFT 4 -#define FMR_OP 0x0003 -#define FMR_OP_SHIFT 0 - -#define FIR_OP_NOP 0x0 /* No operation and end of sequence */ -#define FIR_OP_CA 0x1 /* Issue current column address */ -#define FIR_OP_PA 0x2 /* Issue current block+page address */ -#define FIR_OP_UA 0x3 /* Issue user defined address */ -#define FIR_OP_CM(x) (4 + (x)) /* Issue command from FCR[CMD(x)] */ -#define FIR_OP_WB 0x8 /* Write FBCR bytes from FCM buffer */ -#define FIR_OP_WS 0x9 /* Write 1 or 2 bytes from MDR[AS] */ -#define FIR_OP_RB 0xA /* Read FBCR bytes to FCM buffer */ -#define FIR_OP_RS 0xB /* Read 1 or 2 bytes to MDR[AS] */ -#define FIR_OP_CW0 0xC /* Wait then issue FCR[CMD0] */ -#define FIR_OP_CW1 0xD /* Wait then issue FCR[CMD1] */ -#define FIR_OP_RBW 0xE /* Wait then read FBCR bytes */ -#define FIR_OP_RSW 0xF /* Wait then read 1 or 2 bytes */ - -/* LTESR - Transfer Error Status Register */ -#define LTESR_BM 0x80000000 -#define LTESR_FCT 0x40000000 -#define LTESR_PAR 0x20000000 -#define LTESR_WP 0x04000000 -#define LTESR_ATMW 0x00800000 -#define LTESR_ATMR 0x00400000 -#define LTESR_CS 0x00080000 -#define LTESR_CC 0x00000001 - -#define LTESR_NAND_MASK (LTESR_FCT | LTESR_CC | LTESR_CS) - -/* FPAR - Flash Page Address Register */ -#define FPAR_SP_PI 0x00007C00 -#define FPAR_SP_PI_SHIFT 10 -#define FPAR_SP_MS 0x00000200 -#define FPAR_SP_CI 0x000001FF -#define FPAR_SP_CI_SHIFT 0 -#define FPAR_LP_PI 0x0003F000 -#define FPAR_LP_PI_SHIFT 12 -#define FPAR_LP_MS 0x00000800 -#define FPAR_LP_CI 0x000007FF -#define FPAR_LP_CI_SHIFT 0 - -#define FSL_FCM_WAIT_TIMEOUT 10 - -#endif /* _NAND_NFC_FSL_H_ */ diff --git a/sys/dev/nand/nfc_if.m b/sys/dev/nand/nfc_if.m deleted file mode 100644 index a4e1099220acc..0000000000000 --- a/sys/dev/nand/nfc_if.m +++ /dev/null @@ -1,165 +0,0 @@ -#- -# Copyright (C) 2009-2012 Semihalf -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -# SUCH DAMAGE. -# -# $FreeBSD$ - -# NAND controller interface description -# - -#include <sys/bus.h> -#include <dev/nand/nand.h> - -INTERFACE nfc; - -CODE { - static int nfc_default_method(device_t dev) - { - return (0); - } - - static int nfc_softecc_get(device_t dev, void *buf, int pagesize, - void *ecc, int *needwrite) - { - *needwrite = 1; - return (nand_softecc_get(dev, buf, pagesize, ecc)); - } - - static int nfc_softecc_correct(device_t dev, void *buf, int pagesize, - void *readecc, void *calcecc) - { - return (nand_softecc_correct(dev, buf, pagesize, readecc, - calcecc)); - } -}; - -# Send command to a NAND chip -# -# Return values: -# 0: Success -# -METHOD int send_command { - device_t dev; - uint8_t command; -}; - -# Send address to a NAND chip -# -# Return values: -# 0: Success -# -METHOD int send_address { - device_t dev; - uint8_t address; -}; - -# Read byte -# -# Return values: -# byte read -# -METHOD uint8_t read_byte { - device_t dev; -}; - -# Write byte -# -METHOD void write_byte { - device_t dev; - uint8_t byte; -}; - -# Read word -# -# Return values: -# word read -# -METHOD uint16_t read_word { - device_t dev; -}; - -# Write word -# -METHOD void write_word { - device_t dev; - uint16_t word; -}; - -# Read buf -# -METHOD void read_buf { - device_t dev; - void *buf; - uint32_t len; -}; - -# Write buf -# -METHOD void write_buf { - device_t dev; - void *buf; - uint32_t len; -}; - -# Select CS -# -METHOD int select_cs { - device_t dev; - uint8_t cs; -}; - -# Read ready/busy signal -# -METHOD int read_rnb { - device_t dev; -}; - -# Start command -# -# Return values: -# 0: Success -# -METHOD int start_command { - device_t dev; -} DEFAULT nfc_default_method; - -# Generate ECC or get it from H/W -# -METHOD int get_ecc { - device_t dev; - void *buf; - int pagesize; - void *ecc; - int *needwrite; -} DEFAULT nfc_softecc_get; - -# Correct ECC -# -METHOD int correct_ecc { - device_t dev; - void *buf; - int pagesize; - void *readecc; - void *calcecc; -} DEFAULT nfc_softecc_correct; diff --git a/sys/dev/nand/nfc_mv.c b/sys/dev/nand/nfc_mv.c deleted file mode 100644 index 0d78d34d9912c..0000000000000 --- a/sys/dev/nand/nfc_mv.c +++ /dev/null @@ -1,238 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* Integrated NAND controller driver */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/proc.h> -#include <sys/bus.h> -#include <sys/conf.h> -#include <sys/kernel.h> -#include <sys/module.h> -#include <sys/malloc.h> -#include <sys/rman.h> -#include <sys/lock.h> -#include <sys/mutex.h> -#include <sys/time.h> - -#include <machine/bus.h> -#include <machine/fdt.h> -#include <arm/mv/mvvar.h> -#include <arm/mv/mvwin.h> - -#include <dev/ofw/ofw_bus.h> -#include <dev/ofw/ofw_bus_subr.h> - -#include <dev/nand/nand.h> -#include <dev/nand/nandbus.h> -#include "nfc_if.h" - -#define MV_NAND_DATA (0x00) -#define MV_NAND_COMMAND (0x01) -#define MV_NAND_ADDRESS (0x02) - -struct mv_nand_softc { - struct nand_softc nand_dev; - bus_space_handle_t sc_handle; - bus_space_tag_t sc_tag; - struct resource *res; - int rid; -}; - -static int mv_nand_attach(device_t); -static int mv_nand_probe(device_t); -static int mv_nand_send_command(device_t, uint8_t); -static int mv_nand_send_address(device_t, uint8_t); -static uint8_t mv_nand_read_byte(device_t); -static void mv_nand_read_buf(device_t, void *, uint32_t); -static void mv_nand_write_buf(device_t, void *, uint32_t); -static int mv_nand_select_cs(device_t, uint8_t); -static int mv_nand_read_rnb(device_t); - -static device_method_t mv_nand_methods[] = { - DEVMETHOD(device_probe, mv_nand_probe), - DEVMETHOD(device_attach, mv_nand_attach), - - DEVMETHOD(nfc_send_command, mv_nand_send_command), - DEVMETHOD(nfc_send_address, mv_nand_send_address), - DEVMETHOD(nfc_read_byte, mv_nand_read_byte), - DEVMETHOD(nfc_read_buf, mv_nand_read_buf), - DEVMETHOD(nfc_write_buf, mv_nand_write_buf), - DEVMETHOD(nfc_select_cs, mv_nand_select_cs), - DEVMETHOD(nfc_read_rnb, mv_nand_read_rnb), - - { 0, 0 }, -}; - -static driver_t mv_nand_driver = { - "nand", - mv_nand_methods, - sizeof(struct mv_nand_softc), -}; - -static devclass_t mv_nand_devclass; -DRIVER_MODULE(mv_nand, localbus, mv_nand_driver, mv_nand_devclass, 0, 0); - -static int -mv_nand_probe(device_t dev) -{ - - if (!ofw_bus_is_compatible(dev, "mrvl,nfc")) - return (ENXIO); - - device_set_desc(dev, "Marvell NAND controller"); - return (BUS_PROBE_DEFAULT); -} - -static int -mv_nand_attach(device_t dev) -{ - struct mv_nand_softc *sc; - int err; - - sc = device_get_softc(dev); - sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->rid, - RF_ACTIVE); - if (sc->res == NULL) { - device_printf(dev, "could not allocate resources!\n"); - return (ENXIO); - } - - sc->sc_tag = rman_get_bustag(sc->res); - sc->sc_handle = rman_get_bushandle(sc->res); - - nand_init(&sc->nand_dev, dev, NAND_ECC_SOFT, 0, 0, NULL, NULL); - - err = nandbus_create(dev); - - return (err); -} - -static int -mv_nand_send_command(device_t dev, uint8_t command) -{ - struct mv_nand_softc *sc; - - nand_debug(NDBG_DRV,"mv_nand: send command %x", command); - - sc = device_get_softc(dev); - bus_space_write_1(sc->sc_tag, sc->sc_handle, MV_NAND_COMMAND, command); - return (0); -} - -static int -mv_nand_send_address(device_t dev, uint8_t addr) -{ - struct mv_nand_softc *sc; - - nand_debug(NDBG_DRV,"mv_nand: send address %x", addr); - - sc = device_get_softc(dev); - bus_space_write_1(sc->sc_tag, sc->sc_handle, MV_NAND_ADDRESS, addr); - return (0); -} - -static uint8_t -mv_nand_read_byte(device_t dev) -{ - struct mv_nand_softc *sc; - uint8_t data; - - sc = device_get_softc(dev); - data = bus_space_read_1(sc->sc_tag, sc->sc_handle, MV_NAND_DATA); - - nand_debug(NDBG_DRV,"mv_nand: read %x", data); - - return (data); -} - -static void -mv_nand_read_buf(device_t dev, void* buf, uint32_t len) -{ - struct mv_nand_softc *sc; - int i; - uint8_t *b = (uint8_t*)buf; - - sc = device_get_softc(dev); - - for (i = 0; i < len; i++) { - b[i] = bus_space_read_1(sc->sc_tag, sc->sc_handle, - MV_NAND_DATA); -#ifdef NAND_DEBUG - if (!(i % 16)) - printf("%s", i == 0 ? "mv_nand:\n" : "\n"); - printf(" %x", b[i]); - if (i == len - 1) - printf("\n"); -#endif - } -} - -static void -mv_nand_write_buf(device_t dev, void* buf, uint32_t len) -{ - struct mv_nand_softc *sc; - int i; - uint8_t *b = (uint8_t*)buf; - - sc = device_get_softc(dev); - - for (i = 0; i < len; i++) { -#ifdef NAND_DEBUG - if (!(i % 16)) - printf("%s", i == 0 ? "mv_nand:\n" : "\n"); - printf(" %x", b[i]); - if (i == len - 1) - printf("\n"); -#endif - bus_space_write_1(sc->sc_tag, sc->sc_handle, MV_NAND_DATA, - b[i]); - } -} - -static int -mv_nand_select_cs(device_t dev, uint8_t cs) -{ - - if (cs > 0) - return (ENODEV); - - return (0); -} - -static int -mv_nand_read_rnb(device_t dev) -{ - - /* no-op */ - return (0); /* ready */ -} diff --git a/sys/dev/nand/nfc_rb.c b/sys/dev/nand/nfc_rb.c deleted file mode 100644 index 1102b3abb9c41..0000000000000 --- a/sys/dev/nand/nfc_rb.c +++ /dev/null @@ -1,321 +0,0 @@ -/*- - * Copyright (C) 2015 Justin Hibbits - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* RouterBoard 600/800 NAND controller driver. */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/bus.h> -#include <sys/kernel.h> -#include <sys/module.h> -#include <sys/malloc.h> -#include <sys/rman.h> -#include <sys/slicer.h> - -#include <geom/geom_disk.h> - -#include <machine/bus.h> - -#include <dev/ofw/ofw_bus.h> -#include <dev/ofw/ofw_bus_subr.h> - -#include <dev/nand/nand.h> -#include <dev/nand/nandbus.h> - -#include <powerpc/mpc85xx/mpc85xx.h> - -#include "nfc_if.h" -#include "gpio_if.h" - -#define RB_NAND_DATA (0x00) - -struct rb_nand_softc { - struct nand_softc nand_dev; - struct resource *sc_mem; - int rid; - device_t sc_gpio; - uint32_t sc_rdy_pin; - uint32_t sc_nce_pin; - uint32_t sc_cle_pin; - uint32_t sc_ale_pin; -}; - -static int rb_nand_attach(device_t); -static int rb_nand_probe(device_t); -static int rb_nand_send_command(device_t, uint8_t); -static int rb_nand_send_address(device_t, uint8_t); -static uint8_t rb_nand_read_byte(device_t); -static void rb_nand_read_buf(device_t, void *, uint32_t); -static void rb_nand_write_buf(device_t, void *, uint32_t); -static int rb_nand_select_cs(device_t, uint8_t); -static int rb_nand_read_rnb(device_t); - -static device_method_t rb_nand_methods[] = { - DEVMETHOD(device_probe, rb_nand_probe), - DEVMETHOD(device_attach, rb_nand_attach), - - DEVMETHOD(nfc_send_command, rb_nand_send_command), - DEVMETHOD(nfc_send_address, rb_nand_send_address), - DEVMETHOD(nfc_read_byte, rb_nand_read_byte), - DEVMETHOD(nfc_read_buf, rb_nand_read_buf), - DEVMETHOD(nfc_write_buf, rb_nand_write_buf), - DEVMETHOD(nfc_select_cs, rb_nand_select_cs), - DEVMETHOD(nfc_read_rnb, rb_nand_read_rnb), - - { 0, 0 }, -}; - -static driver_t rb_nand_driver = { - "nand", - rb_nand_methods, - sizeof(struct rb_nand_softc), -}; - -static devclass_t rb_nand_devclass; -DRIVER_MODULE(rb_nand, ofwbus, rb_nand_driver, rb_nand_devclass, 0, 0); - -#if 0 -static const struct nand_ecc_data rb_ecc = { - .eccsize = 6, - .eccmode = NAND_ECC_SOFT, - .eccbytes = 6, - .eccpositions = { 8, 9, 10, 13, 14, 15 }, -}; -#endif - -/* Slicer operates on the NAND controller, so we have to find the chip. */ -static int -rb_nand_slicer(device_t dev, const char *provider __unused, - struct flash_slice *slices, int *nslices) -{ - struct nand_chip *chip; - device_t *children; - int n; - - if (device_get_children(dev, &children, &n) != 0) { - panic("Slicer called on controller with no child!"); - } - dev = children[0]; - free(children, M_TEMP); - - if (device_get_children(dev, &children, &n) != 0) { - panic("Slicer called on controller with nandbus but no child!"); - } - dev = children[0]; - free(children, M_TEMP); - - chip = device_get_softc(dev); - *nslices = 2; - slices[0].base = 0; - slices[0].size = 4 * 1024 * 1024; - slices[0].label = "boot"; - - slices[1].base = 4 * 1024 * 1024; - slices[1].size = chip->ndisk->d_mediasize - slices[0].size; - slices[1].label = "rootfs"; - - return (0); -} - -static int -rb_nand_probe(device_t dev) -{ - const char *device_type; - - device_type = ofw_bus_get_type(dev); - - if (!device_type || strcmp(device_type, "rb,nand")) - return (ENXIO); - - device_set_desc(dev, "RouterBoard 333/600/800 NAND controller"); - return (BUS_PROBE_DEFAULT); -} - -static int -rb_nand_attach(device_t dev) -{ - struct rb_nand_softc *sc; - phandle_t node; - uint32_t ale[2],cle[2],nce[2],rdy[2]; - u_long size,start; - int err; - - sc = device_get_softc(dev); - node = ofw_bus_get_node(dev); - - if (OF_getprop(node, "ale", ale, sizeof(ale)) <= 0) { - return (ENXIO); - } - if (OF_getprop(node, "cle", cle, sizeof(cle)) <= 0) { - return (ENXIO); - } - if (OF_getprop(node, "nce", nce, sizeof(nce)) <= 0) { - return (ENXIO); - } - if (OF_getprop(node, "rdy", rdy, sizeof(rdy)) <= 0) { - return (ENXIO); - } - - if (ale[0] != cle[0] || ale[0] != nce[0] || ale[0] != rdy[0]) { - device_printf(dev, "GPIO handles for signals must match.\n"); - return (ENXIO); - } - sc->sc_ale_pin = ale[1]; - sc->sc_cle_pin = cle[1]; - sc->sc_nce_pin = nce[1]; - sc->sc_rdy_pin = rdy[1]; - - sc->sc_gpio = OF_device_from_xref(ale[0]); - if (sc->sc_gpio == NULL) { - device_printf(dev, "No GPIO resource found!\n"); - return (ENXIO); - } - - sc->sc_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->rid, - RF_ACTIVE); - if (sc->sc_mem == NULL) { - device_printf(dev, "could not allocate resources!\n"); - return (ENXIO); - } - - start = rman_get_start(sc->sc_mem); - size = rman_get_size(sc->sc_mem); - if (law_enable(OCP85XX_TGTIF_LBC, start, size) != 0) { - bus_release_resource(dev, SYS_RES_MEMORY, sc->rid, sc->sc_mem); - device_printf(dev, "could not allocate local address window.\n"); - return (ENXIO); - } - - flash_register_slicer(rb_nand_slicer, FLASH_SLICES_TYPE_NAND, TRUE); - - nand_init(&sc->nand_dev, dev, NAND_ECC_SOFT, 0, 0, NULL, NULL); - - err = nandbus_create(dev); - - return (err); -} - -static int -rb_nand_send_command(device_t dev, uint8_t command) -{ - struct rb_nand_softc *sc; - - nand_debug(NDBG_DRV,"rb_nand: send command %x", command); - - sc = device_get_softc(dev); - GPIO_PIN_SET(sc->sc_gpio, sc->sc_cle_pin, 1); - GPIO_PIN_SET(sc->sc_gpio, sc->sc_ale_pin, 0); - GPIO_PIN_SET(sc->sc_gpio, sc->sc_nce_pin, 0); - bus_write_1(sc->sc_mem, RB_NAND_DATA, command); - GPIO_PIN_SET(sc->sc_gpio, sc->sc_cle_pin, 0); - return (0); -} - -static int -rb_nand_send_address(device_t dev, uint8_t addr) -{ - struct rb_nand_softc *sc; - - nand_debug(NDBG_DRV,"rb_nand: send address %x", addr); - - sc = device_get_softc(dev); - GPIO_PIN_SET(sc->sc_gpio, sc->sc_cle_pin, 0); - GPIO_PIN_SET(sc->sc_gpio, sc->sc_ale_pin, 1); - GPIO_PIN_SET(sc->sc_gpio, sc->sc_nce_pin, 0); - bus_write_1(sc->sc_mem, RB_NAND_DATA, addr); - GPIO_PIN_SET(sc->sc_gpio, sc->sc_ale_pin, 0); - return (0); -} - -static uint8_t -rb_nand_read_byte(device_t dev) -{ - struct rb_nand_softc *sc; - uint8_t data; - - sc = device_get_softc(dev); - data = bus_read_1(sc->sc_mem, RB_NAND_DATA); - - nand_debug(NDBG_DRV,"rb_nand: read %x", data); - - return (data); -} - -static void -rb_nand_read_buf(device_t dev, void* buf, uint32_t len) -{ - struct rb_nand_softc *sc; - - sc = device_get_softc(dev); - - bus_read_region_1(sc->sc_mem, RB_NAND_DATA, buf, len); -} - -static void -rb_nand_write_buf(device_t dev, void* buf, uint32_t len) -{ - struct rb_nand_softc *sc; - int i; - uint8_t *b = (uint8_t*)buf; - - sc = device_get_softc(dev); - - for (i = 0; i < len; i++) { -#ifdef NAND_DEBUG - if (!(i % 16)) - printf("%s", i == 0 ? "rb_nand:\n" : "\n"); - printf(" %x", b[i]); - if (i == len - 1) - printf("\n"); -#endif - bus_write_1(sc->sc_mem, RB_NAND_DATA, b[i]); - } -} - -static int -rb_nand_select_cs(device_t dev, uint8_t cs) -{ - - if (cs > 0) - return (ENODEV); - - return (0); -} - -static int -rb_nand_read_rnb(device_t dev) -{ - struct rb_nand_softc *sc; - uint32_t rdy_bit; - - sc = device_get_softc(dev); - GPIO_PIN_GET(sc->sc_gpio, sc->sc_rdy_pin, &rdy_bit); - - return (rdy_bit); /* ready */ -} diff --git a/sys/dev/ow/owc_gpiobus.c b/sys/dev/ow/owc_gpiobus.c index f03d01432b03f..24a18789bea88 100644 --- a/sys/dev/ow/owc_gpiobus.c +++ b/sys/dev/ow/owc_gpiobus.c @@ -416,5 +416,7 @@ static driver_t owc_gpiobus_driver = { sizeof(struct owc_gpiobus_softc), }; -DRIVER_MODULE(owc_gpiobus_fdt, gpiobus, owc_gpiobus_driver, owc_gpiobus_devclass, 0, 0); -MODULE_DEPEND(owc_gpiobus_fdt, ow, 1, 1, 1); +DRIVER_MODULE(owc_gpiobus, gpiobus, owc_gpiobus_driver, owc_gpiobus_devclass, 0, 0); +MODULE_DEPEND(owc_gpiobus, ow, 1, 1, 1); +MODULE_DEPEND(owc_gpiobus, gpiobus, 1, 1, 1); +MODULE_VERSION(owc_gpiobus, 1); diff --git a/sys/dev/usb/usb_hub_acpi.c b/sys/dev/usb/usb_hub_acpi.c index 5dd9f06ebaa45..b536a3d282e9e 100644 --- a/sys/dev/usb/usb_hub_acpi.c +++ b/sys/dev/usb/usb_hub_acpi.c @@ -243,13 +243,14 @@ acpi_uhub_parse_pld(device_t dev, unsigned int port, ACPI_HANDLE ah) } ACPI_STATUS -acpi_uhub_find_rh(device_t dev, ACPI_HANDLE * ah){ +acpi_uhub_find_rh(device_t dev, ACPI_HANDLE * ah) +{ device_t grand; ACPI_HANDLE gah; + *ah = NULL; grand = device_get_parent(device_get_parent(dev)); if ((gah = acpi_get_handle(grand)) == NULL) { - *ah = NULL; return AE_ERROR; } return AcpiWalkNamespace(ACPI_TYPE_DEVICE, gah, 1, @@ -257,7 +258,8 @@ acpi_uhub_find_rh(device_t dev, ACPI_HANDLE * ah){ } ACPI_STATUS -acpi_usb_hub_port_probe_cb(ACPI_HANDLE ah, UINT32 lv, void *ctx, void **rv){ +acpi_usb_hub_port_probe_cb(ACPI_HANDLE ah, UINT32 lv, void *ctx, void **rv) +{ ACPI_DEVICE_INFO *devinfo; device_t dev = ctx; struct acpi_uhub_softc *sc = device_get_softc(dev); @@ -281,7 +283,8 @@ acpi_usb_hub_port_probe_cb(ACPI_HANDLE ah, UINT32 lv, void *ctx, void **rv){ } ACPI_STATUS -acpi_usb_hub_port_probe(device_t dev, ACPI_HANDLE ah){ +acpi_usb_hub_port_probe(device_t dev, ACPI_HANDLE ah) +{ return AcpiWalkNamespace(ACPI_TYPE_DEVICE, ah, 1, acpi_usb_hub_port_probe_cb, @@ -293,6 +296,9 @@ acpi_uhub_root_probe(device_t dev) ACPI_HANDLE ah; ACPI_STATUS status; + if(acpi_disabled("usb")) { + return ENXIO; + } status = acpi_uhub_find_rh(dev, &ah); if (ACPI_SUCCESS(status) && ah != NULL @@ -308,7 +314,7 @@ acpi_uhub_probe(device_t dev) { ACPI_HANDLE ah = acpi_get_handle(dev); - if (ah && (uhub_probe(dev) <= 0)) { + if (!acpi_disabled("usb") && ah && (uhub_probe(dev) <= 0)) { /*success prior than non - acpi hub*/ return (BUS_PROBE_DEFAULT + 1); } @@ -335,7 +341,6 @@ acpi_uhub_root_attach(device_t dev) sc->nports = uh->nports; sc->porthandle = malloc(sizeof(ACPI_HANDLE) * uh->nports, M_USBDEV, M_WAITOK | M_ZERO); - acpi_uhub_find_rh(dev, &devhandle); acpi_usb_hub_port_probe(dev, devhandle); return 0; diff --git a/sys/dev/virtio/scsi/virtio_scsi.c b/sys/dev/virtio/scsi/virtio_scsi.c index ec98178d5697d..6f2dfbcac5a46 100644 --- a/sys/dev/virtio/scsi/virtio_scsi.c +++ b/sys/dev/virtio/scsi/virtio_scsi.c @@ -81,6 +81,7 @@ static void vtscsi_read_config(struct vtscsi_softc *, struct virtio_scsi_config *); static int vtscsi_maximum_segments(struct vtscsi_softc *, int); static int vtscsi_alloc_virtqueues(struct vtscsi_softc *); +static void vtscsi_check_sizes(struct vtscsi_softc *); static void vtscsi_write_device_config(struct vtscsi_softc *); static int vtscsi_reinit(struct vtscsi_softc *); @@ -311,6 +312,8 @@ vtscsi_attach(device_t dev) goto fail; } + vtscsi_check_sizes(sc); + error = vtscsi_init_event_vq(sc); if (error) { device_printf(dev, "cannot populate the eventvq\n"); @@ -478,6 +481,26 @@ vtscsi_alloc_virtqueues(struct vtscsi_softc *sc) } static void +vtscsi_check_sizes(struct vtscsi_softc *sc) +{ + int rqsize; + + if ((sc->vtscsi_flags & VTSCSI_FLAG_INDIRECT) == 0) { + /* + * Ensure the assertions in virtqueue_enqueue(), + * even if the hypervisor reports a bad seg_max. + */ + rqsize = virtqueue_size(sc->vtscsi_request_vq); + if (sc->vtscsi_max_nsegs > rqsize) { + device_printf(sc->vtscsi_dev, + "clamping seg_max (%d %d)\n", sc->vtscsi_max_nsegs, + rqsize); + sc->vtscsi_max_nsegs = rqsize; + } + } +} + +static void vtscsi_write_device_config(struct vtscsi_softc *sc) { diff --git a/sys/fs/cuse/cuse.c b/sys/fs/cuse/cuse.c index 578bf3eda74f7..765fe308af7bb 100644 --- a/sys/fs/cuse/cuse.c +++ b/sys/fs/cuse/cuse.c @@ -671,8 +671,6 @@ cuse_server_unref(struct cuse_server *pcs) TAILQ_REMOVE(&cuse_server_head, pcs, entry); - cuse_free_unit_by_id_locked(pcs, -1); - while ((pcsd = TAILQ_FIRST(&pcs->hdev)) != NULL) { TAILQ_REMOVE(&pcs->hdev, pcsd, entry); cuse_unlock(); @@ -680,6 +678,8 @@ cuse_server_unref(struct cuse_server *pcs) cuse_lock(); } + cuse_free_unit_by_id_locked(pcs, -1); + while ((mem = TAILQ_FIRST(&pcs->hmem)) != NULL) { TAILQ_REMOVE(&pcs->hmem, mem, entry); cuse_unlock(); @@ -699,12 +699,38 @@ cuse_server_unref(struct cuse_server *pcs) free(pcs, M_CUSE); } +static int +cuse_server_do_close(struct cuse_server *pcs) +{ + int retval; + + cuse_lock(); + cuse_server_is_closing(pcs); + /* final client wakeup, if any */ + cuse_server_wakeup_all_client_locked(pcs); + + knlist_clear(&pcs->selinfo.si_note, 1); + + retval = pcs->refs; + cuse_unlock(); + + return (retval); +} + static void cuse_server_free(void *arg) { struct cuse_server *pcs = arg; - /* drop refcount */ + /* + * The final server unref should be done by the server thread + * to prevent deadlock in the client cdevpriv destructor, + * which cannot destroy itself. + */ + while (cuse_server_do_close(pcs) != 1) + pause("W", hz); + + /* drop final refcount */ cuse_server_unref(pcs); } @@ -746,21 +772,10 @@ static int cuse_server_close(struct cdev *dev, int fflag, int devtype, struct thread *td) { struct cuse_server *pcs; - int error; - error = cuse_server_get(&pcs); - if (error != 0) - goto done; + if (cuse_server_get(&pcs) == 0) + cuse_server_do_close(pcs); - cuse_lock(); - cuse_server_is_closing(pcs); - /* final client wakeup, if any */ - cuse_server_wakeup_all_client_locked(pcs); - - knlist_clear(&pcs->selinfo.si_note, 1); - cuse_unlock(); - -done: return (0); } diff --git a/sys/fs/fifofs/fifo_vnops.c b/sys/fs/fifofs/fifo_vnops.c index 96dd05a183236..b4fefbde79a67 100644 --- a/sys/fs/fifofs/fifo_vnops.c +++ b/sys/fs/fifofs/fifo_vnops.c @@ -174,7 +174,7 @@ fifo_open(ap) if (fip->fi_writers > 0) wakeup(&fip->fi_writers); } - fp->f_seqcount = fpipe->pipe_wgen - fip->fi_writers; + fp->f_pipegen = fpipe->pipe_wgen - fip->fi_writers; } if (ap->a_mode & FWRITE) { if ((ap->a_mode & O_NONBLOCK) && fip->fi_readers == 0) { diff --git a/sys/fs/nandfs/bmap.c b/sys/fs/nandfs/bmap.c deleted file mode 100644 index 5721cf0157bc7..0000000000000 --- a/sys/fs/nandfs/bmap.c +++ /dev/null @@ -1,625 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/namei.h> -#include <sys/kernel.h> -#include <sys/stat.h> -#include <sys/buf.h> -#include <sys/bio.h> -#include <sys/proc.h> -#include <sys/mount.h> -#include <sys/vnode.h> -#include <sys/signalvar.h> -#include <sys/malloc.h> -#include <sys/dirent.h> -#include <sys/lockf.h> -#include <sys/ktr.h> -#include <sys/kdb.h> - -#include <vm/vm.h> -#include <vm/vm_extern.h> -#include <vm/vm_object.h> -#include <vm/vnode_pager.h> - -#include <machine/_inttypes.h> - -#include <vm/vm.h> -#include <vm/vm_extern.h> -#include <vm/vm_object.h> -#include <vm/vnode_pager.h> - -#include "nandfs_mount.h" -#include "nandfs.h" -#include "nandfs_subr.h" -#include "bmap.h" - -static int bmap_getlbns(struct nandfs_node *, nandfs_lbn_t, - struct nandfs_indir *, int *); - -int -bmap_lookup(struct nandfs_node *node, nandfs_lbn_t lblk, nandfs_daddr_t *vblk) -{ - struct nandfs_inode *ip; - struct nandfs_indir a[NANDFS_NIADDR + 1], *ap; - nandfs_daddr_t daddr; - struct buf *bp; - int error; - int num, *nump; - - DPRINTF(BMAP, ("%s: node %p lblk %jx enter\n", __func__, node, lblk)); - ip = &node->nn_inode; - - ap = a; - nump = # - - error = bmap_getlbns(node, lblk, ap, nump); - if (error) - return (error); - - if (num == 0) { - *vblk = ip->i_db[lblk]; - return (0); - } - - DPRINTF(BMAP, ("%s: node %p lblk=%jx trying ip->i_ib[%x]\n", __func__, - node, lblk, ap->in_off)); - daddr = ip->i_ib[ap->in_off]; - for (bp = NULL, ++ap; --num; ap++) { - if (daddr == 0) { - DPRINTF(BMAP, ("%s: node %p lblk=%jx returning with " - "vblk 0\n", __func__, node, lblk)); - *vblk = 0; - return (0); - } - if (ap->in_lbn == lblk) { - DPRINTF(BMAP, ("%s: node %p lblk=%jx ap->in_lbn=%jx " - "returning address of indirect block (%jx)\n", - __func__, node, lblk, ap->in_lbn, daddr)); - *vblk = daddr; - return (0); - } - - DPRINTF(BMAP, ("%s: node %p lblk=%jx reading block " - "ap->in_lbn=%jx\n", __func__, node, lblk, ap->in_lbn)); - - error = nandfs_bread_meta(node, ap->in_lbn, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - - daddr = ((nandfs_daddr_t *)bp->b_data)[ap->in_off]; - brelse(bp); - } - - DPRINTF(BMAP, ("%s: node %p lblk=%jx returning with %jx\n", __func__, - node, lblk, daddr)); - *vblk = daddr; - - return (0); -} - -int -bmap_dirty_meta(struct nandfs_node *node, nandfs_lbn_t lblk, int force) -{ - struct nandfs_indir a[NANDFS_NIADDR+1], *ap; -#ifdef DEBUG - nandfs_daddr_t daddr; -#endif - struct buf *bp; - int error; - int num, *nump; - - DPRINTF(BMAP, ("%s: node %p lblk=%jx\n", __func__, node, lblk)); - - ap = a; - nump = # - - error = bmap_getlbns(node, lblk, ap, nump); - if (error) - return (error); - - /* - * Direct block, nothing to do - */ - if (num == 0) - return (0); - - DPRINTF(BMAP, ("%s: node %p reading blocks\n", __func__, node)); - - for (bp = NULL, ++ap; --num; ap++) { - error = nandfs_bread_meta(node, ap->in_lbn, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - -#ifdef DEBUG - daddr = ((nandfs_daddr_t *)bp->b_data)[ap->in_off]; - MPASS(daddr != 0 || node->nn_ino == 3); -#endif - - error = nandfs_dirty_buf_meta(bp, force); - if (error) - return (error); - } - - return (0); -} - -int -bmap_insert_block(struct nandfs_node *node, nandfs_lbn_t lblk, - nandfs_daddr_t vblk) -{ - struct nandfs_inode *ip; - struct nandfs_indir a[NANDFS_NIADDR+1], *ap; - struct buf *bp; - nandfs_daddr_t daddr; - int error; - int num, *nump, i; - - DPRINTF(BMAP, ("%s: node %p lblk=%jx vblk=%jx\n", __func__, node, lblk, - vblk)); - - ip = &node->nn_inode; - - ap = a; - nump = # - - error = bmap_getlbns(node, lblk, ap, nump); - if (error) - return (error); - - DPRINTF(BMAP, ("%s: node %p lblk=%jx vblk=%jx got num=%d\n", __func__, - node, lblk, vblk, num)); - - if (num == 0) { - DPRINTF(BMAP, ("%s: node %p lblk=%jx direct block\n", __func__, - node, lblk)); - ip->i_db[lblk] = vblk; - return (0); - } - - DPRINTF(BMAP, ("%s: node %p lblk=%jx indirect block level %d\n", - __func__, node, lblk, ap->in_off)); - - if (num == 1) { - DPRINTF(BMAP, ("%s: node %p lblk=%jx indirect block: inserting " - "%jx as vblk for indirect block %d\n", __func__, node, - lblk, vblk, ap->in_off)); - ip->i_ib[ap->in_off] = vblk; - return (0); - } - - bp = NULL; - daddr = ip->i_ib[a[0].in_off]; - for (i = 1; i < num; i++) { - if (bp) - brelse(bp); - if (daddr == 0) { - DPRINTF(BMAP, ("%s: node %p lblk=%jx vblk=%jx create " - "block %jx %d\n", __func__, node, lblk, vblk, - a[i].in_lbn, a[i].in_off)); - error = nandfs_bcreate_meta(node, a[i].in_lbn, NOCRED, - 0, &bp); - if (error) - return (error); - } else { - DPRINTF(BMAP, ("%s: node %p lblk=%jx vblk=%jx read " - "block %jx %d\n", __func__, node, daddr, vblk, - a[i].in_lbn, a[i].in_off)); - error = nandfs_bread_meta(node, a[i].in_lbn, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - } - daddr = ((nandfs_daddr_t *)bp->b_data)[a[i].in_off]; - } - i--; - - DPRINTF(BMAP, - ("%s: bmap node %p lblk=%jx vblk=%jx inserting vblk level %d at " - "offset %d at %jx\n", __func__, node, lblk, vblk, i, a[i].in_off, - daddr)); - - if (!bp) { - nandfs_error("%s: cannot find indirect block\n", __func__); - return (-1); - } - ((nandfs_daddr_t *)bp->b_data)[a[i].in_off] = vblk; - - error = nandfs_dirty_buf_meta(bp, 0); - if (error) { - nandfs_warning("%s: dirty failed buf: %p\n", __func__, bp); - return (error); - } - DPRINTF(BMAP, ("%s: exiting node %p lblk=%jx vblk=%jx\n", __func__, - node, lblk, vblk)); - - return (error); -} - -CTASSERT(NANDFS_NIADDR <= 3); -#define SINGLE 0 /* index of single indirect block */ -#define DOUBLE 1 /* index of double indirect block */ -#define TRIPLE 2 /* index of triple indirect block */ - -static __inline nandfs_lbn_t -lbn_offset(struct nandfs_device *fsdev, int level) -{ - nandfs_lbn_t res; - - for (res = 1; level > 0; level--) - res *= MNINDIR(fsdev); - return (res); -} - -static nandfs_lbn_t -blocks_inside(struct nandfs_device *fsdev, int level, struct nandfs_indir *nip) -{ - nandfs_lbn_t blocks; - - for (blocks = 1; level >= SINGLE; level--, nip++) { - MPASS(nip->in_off >= 0 && nip->in_off < MNINDIR(fsdev)); - blocks += nip->in_off * lbn_offset(fsdev, level); - } - - return (blocks); -} - -static int -bmap_truncate_indirect(struct nandfs_node *node, int level, nandfs_lbn_t *left, - int *cleaned, struct nandfs_indir *ap, struct nandfs_indir *fp, - nandfs_daddr_t *copy) -{ - struct buf *bp; - nandfs_lbn_t i, lbn, nlbn, factor, tosub; - struct nandfs_device *fsdev; - int error, lcleaned, modified; - - DPRINTF(BMAP, ("%s: node %p level %d left %jx\n", __func__, - node, level, *left)); - - fsdev = node->nn_nandfsdev; - - MPASS(ap->in_off >= 0 && ap->in_off < MNINDIR(fsdev)); - - factor = lbn_offset(fsdev, level); - lbn = ap->in_lbn; - - error = nandfs_bread_meta(node, lbn, NOCRED, 0, &bp); - if (error) { - if (bp != NULL) - brelse(bp); - return (error); - } - - bcopy(bp->b_data, copy, fsdev->nd_blocksize); - bqrelse(bp); - - modified = 0; - - i = ap->in_off; - - if (ap != fp) - ap++; - for (nlbn = lbn + 1 - i * factor; i >= 0 && *left > 0; i--, - nlbn += factor) { - lcleaned = 0; - - DPRINTF(BMAP, - ("%s: node %p i=%jx nlbn=%jx left=%jx ap=%p vblk %jx\n", - __func__, node, i, nlbn, *left, ap, copy[i])); - - if (copy[i] == 0) { - tosub = blocks_inside(fsdev, level - 1, ap); - if (tosub > *left) - tosub = 0; - - *left -= tosub; - } else { - if (level > SINGLE) { - if (ap == fp) - ap->in_lbn = nlbn; - - error = bmap_truncate_indirect(node, level - 1, - left, &lcleaned, ap, fp, - copy + MNINDIR(fsdev)); - if (error) - return (error); - } else { - error = nandfs_bdestroy(node, copy[i]); - if (error) - return (error); - lcleaned = 1; - *left -= 1; - } - } - - if (lcleaned) { - if (level > SINGLE) { - error = nandfs_vblock_end(fsdev, copy[i]); - if (error) - return (error); - } - copy[i] = 0; - modified++; - } - - ap = fp; - } - - if (i == -1) - *cleaned = 1; - - error = nandfs_bread_meta(node, lbn, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - if (modified) - bcopy(copy, bp->b_data, fsdev->nd_blocksize); - - /* Force success even if we can't dirty the buffer metadata when freeing space */ - nandfs_dirty_buf_meta(bp, 1); - - return (0); -} - -int -bmap_truncate_mapping(struct nandfs_node *node, nandfs_lbn_t lastblk, - nandfs_lbn_t todo) -{ - struct nandfs_inode *ip; - struct nandfs_indir a[NANDFS_NIADDR + 1], f[NANDFS_NIADDR], *ap; - nandfs_daddr_t indir_lbn[NANDFS_NIADDR]; - nandfs_daddr_t *copy; - int error, level; - nandfs_lbn_t left, tosub; - struct nandfs_device *fsdev; - int cleaned, i; - int num, *nump; - - DPRINTF(BMAP, ("%s: node %p lastblk %jx truncating by %jx\n", __func__, - node, lastblk, todo)); - - ip = &node->nn_inode; - fsdev = node->nn_nandfsdev; - - ap = a; - nump = # - - error = bmap_getlbns(node, lastblk, ap, nump); - if (error) - return (error); - - indir_lbn[SINGLE] = -NANDFS_NDADDR; - indir_lbn[DOUBLE] = indir_lbn[SINGLE] - MNINDIR(fsdev) - 1; - indir_lbn[TRIPLE] = indir_lbn[DOUBLE] - MNINDIR(fsdev) - * MNINDIR(fsdev) - 1; - - for (i = 0; i < NANDFS_NIADDR; i++) { - f[i].in_off = MNINDIR(fsdev) - 1; - f[i].in_lbn = 0xdeadbeef; - } - - left = todo; - -#ifdef DEBUG - a[num].in_off = -1; -#endif - - ap++; - num -= 2; - - if (num < 0) - goto direct; - - copy = malloc(MNINDIR(fsdev) * sizeof(nandfs_daddr_t) * (num + 1), - M_NANDFSTEMP, M_WAITOK); - - for (level = num; level >= SINGLE && left > 0; level--) { - cleaned = 0; - - if (ip->i_ib[level] == 0) { - tosub = blocks_inside(fsdev, level, ap); - if (tosub > left) - left = 0; - else - left -= tosub; - } else { - if (ap == f) - ap->in_lbn = indir_lbn[level]; - error = bmap_truncate_indirect(node, level, &left, - &cleaned, ap, f, copy); - if (error) { - free(copy, M_NANDFSTEMP); - nandfs_error("%s: error %d when truncate " - "at level %d\n", __func__, error, level); - return (error); - } - } - - if (cleaned) { - nandfs_vblock_end(fsdev, ip->i_ib[level]); - ip->i_ib[level] = 0; - } - - ap = f; - } - - free(copy, M_NANDFSTEMP); - -direct: - if (num < 0) - i = lastblk; - else - i = NANDFS_NDADDR - 1; - - for (; i >= 0 && left > 0; i--) { - if (ip->i_db[i] != 0) { - error = nandfs_bdestroy(node, ip->i_db[i]); - if (error) { - nandfs_error("%s: cannot destroy " - "block %jx, error %d\n", __func__, - (uintmax_t)ip->i_db[i], error); - return (error); - } - ip->i_db[i] = 0; - } - - left--; - } - - KASSERT(left == 0, - ("truncated wrong number of blocks (%jd should be 0)", left)); - - return (error); -} - -nandfs_lbn_t -get_maxfilesize(struct nandfs_device *fsdev) -{ - struct nandfs_indir f[NANDFS_NIADDR]; - nandfs_lbn_t max; - int i; - - max = NANDFS_NDADDR; - - for (i = 0; i < NANDFS_NIADDR; i++) { - f[i].in_off = MNINDIR(fsdev) - 1; - max += blocks_inside(fsdev, i, f); - } - - max *= fsdev->nd_blocksize; - - return (max); -} - -/* - * This is ufs_getlbns with minor modifications. - */ -/* - * Create an array of logical block number/offset pairs which represent the - * path of indirect blocks required to access a data block. The first "pair" - * contains the logical block number of the appropriate single, double or - * triple indirect block and the offset into the inode indirect block array. - * Note, the logical block number of the inode single/double/triple indirect - * block appears twice in the array, once with the offset into the i_ib and - * once with the offset into the page itself. - */ -static int -bmap_getlbns(struct nandfs_node *node, nandfs_lbn_t bn, struct nandfs_indir *ap, int *nump) -{ - nandfs_daddr_t blockcnt; - nandfs_lbn_t metalbn, realbn; - struct nandfs_device *fsdev; - int i, numlevels, off; - - fsdev = node->nn_nandfsdev; - - DPRINTF(BMAP, ("%s: node %p bn=%jx mnindir=%zd enter\n", __func__, - node, bn, MNINDIR(fsdev))); - - if (nump) - *nump = 0; - numlevels = 0; - realbn = bn; - - if (bn < 0) - bn = -bn; - - /* The first NANDFS_NDADDR blocks are direct blocks. */ - if (bn < NANDFS_NDADDR) - return (0); - - /* - * Determine the number of levels of indirection. After this loop - * is done, blockcnt indicates the number of data blocks possible - * at the previous level of indirection, and NANDFS_NIADDR - i is the - * number of levels of indirection needed to locate the requested block. - */ - for (blockcnt = 1, i = NANDFS_NIADDR, bn -= NANDFS_NDADDR;; i--, bn -= blockcnt) { - DPRINTF(BMAP, ("%s: blockcnt=%jd i=%d bn=%jd\n", __func__, - blockcnt, i, bn)); - if (i == 0) - return (EFBIG); - blockcnt *= MNINDIR(fsdev); - if (bn < blockcnt) - break; - } - - /* Calculate the address of the first meta-block. */ - if (realbn >= 0) - metalbn = -(realbn - bn + NANDFS_NIADDR - i); - else - metalbn = -(-realbn - bn + NANDFS_NIADDR - i); - - /* - * At each iteration, off is the offset into the bap array which is - * an array of disk addresses at the current level of indirection. - * The logical block number and the offset in that block are stored - * into the argument array. - */ - ap->in_lbn = metalbn; - ap->in_off = off = NANDFS_NIADDR - i; - - DPRINTF(BMAP, ("%s: initial: ap->in_lbn=%jx ap->in_off=%d\n", __func__, - metalbn, off)); - - ap++; - for (++numlevels; i <= NANDFS_NIADDR; i++) { - /* If searching for a meta-data block, quit when found. */ - if (metalbn == realbn) - break; - - blockcnt /= MNINDIR(fsdev); - off = (bn / blockcnt) % MNINDIR(fsdev); - - ++numlevels; - ap->in_lbn = metalbn; - ap->in_off = off; - - DPRINTF(BMAP, ("%s: in_lbn=%jx in_off=%d\n", __func__, - ap->in_lbn, ap->in_off)); - ++ap; - - metalbn -= -1 + off * blockcnt; - } - if (nump) - *nump = numlevels; - - DPRINTF(BMAP, ("%s: numlevels=%d\n", __func__, numlevels)); - - return (0); -} diff --git a/sys/fs/nandfs/bmap.h b/sys/fs/nandfs/bmap.h deleted file mode 100644 index a4784f7a88f98..0000000000000 --- a/sys/fs/nandfs/bmap.h +++ /dev/null @@ -1,42 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _BMAP_H -#define _BMAP_H - -#include "nandfs_fs.h" - -int bmap_lookup(struct nandfs_node *, nandfs_lbn_t, nandfs_daddr_t *); -int bmap_insert_block(struct nandfs_node *, nandfs_lbn_t, nandfs_daddr_t); -int bmap_truncate_mapping(struct nandfs_node *, nandfs_lbn_t, nandfs_lbn_t); -int bmap_dirty_meta(struct nandfs_node *, nandfs_lbn_t, int); - -nandfs_lbn_t get_maxfilesize(struct nandfs_device *); - -#endif /* _BMAP_H */ diff --git a/sys/fs/nandfs/nandfs.h b/sys/fs/nandfs/nandfs.h deleted file mode 100644 index 9a9b28a1bc0ba..0000000000000 --- a/sys/fs/nandfs/nandfs.h +++ /dev/null @@ -1,312 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf - * Copyright (c) 2008, 2009 Reinoud Zandijk - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * From: NetBSD: nilfs.h,v 1.1 2009/07/18 16:31:42 reinoud - * - * $FreeBSD$ - */ - -#ifndef _FS_NANDFS_NANDFS_H_ -#define _FS_NANDFS_NANDFS_H_ - -#include <sys/param.h> -#include <sys/proc.h> -#include <sys/condvar.h> -#include <sys/lock.h> -#include <sys/mutex.h> - -#include <sys/queue.h> -#include <sys/uio.h> -#include <sys/mutex.h> - -#include <sys/disk.h> -#include <sys/kthread.h> -#include "nandfs_fs.h" - -MALLOC_DECLARE(M_NANDFSTEMP); - -/* Debug categories */ -#define NANDFS_DEBUG_VOLUMES 0x000001 -#define NANDFS_DEBUG_BLOCK 0x000004 -#define NANDFS_DEBUG_LOCKING 0x000008 -#define NANDFS_DEBUG_NODE 0x000010 -#define NANDFS_DEBUG_LOOKUP 0x000020 -#define NANDFS_DEBUG_READDIR 0x000040 -#define NANDFS_DEBUG_TRANSLATE 0x000080 -#define NANDFS_DEBUG_STRATEGY 0x000100 -#define NANDFS_DEBUG_READ 0x000200 -#define NANDFS_DEBUG_WRITE 0x000400 -#define NANDFS_DEBUG_IFILE 0x000800 -#define NANDFS_DEBUG_ATTR 0x001000 -#define NANDFS_DEBUG_EXTATTR 0x002000 -#define NANDFS_DEBUG_ALLOC 0x004000 -#define NANDFS_DEBUG_CPFILE 0x008000 -#define NANDFS_DEBUG_DIRHASH 0x010000 -#define NANDFS_DEBUG_NOTIMPL 0x020000 -#define NANDFS_DEBUG_SHEDULE 0x040000 -#define NANDFS_DEBUG_SEG 0x080000 -#define NANDFS_DEBUG_SYNC 0x100000 -#define NANDFS_DEBUG_PARANOIA 0x200000 -#define NANDFS_DEBUG_VNCALL 0x400000 -#define NANDFS_DEBUG_BUF 0x1000000 -#define NANDFS_DEBUG_BMAP 0x2000000 -#define NANDFS_DEBUG_DAT 0x4000000 -#define NANDFS_DEBUG_GENERIC 0x8000000 -#define NANDFS_DEBUG_CLEAN 0x10000000 - -extern int nandfs_verbose; - -#define DPRINTF(name, arg) { \ - if (nandfs_verbose & NANDFS_DEBUG_##name) {\ - printf arg;\ - };\ - } -#define DPRINTFIF(name, cond, arg) { \ - if (nandfs_verbose & NANDFS_DEBUG_##name) { \ - if (cond) printf arg;\ - };\ - } - -#define VFSTONANDFS(mp) ((struct nandfsmount *)((mp)->mnt_data)) -#define VTON(vp) ((struct nandfs_node *)(vp)->v_data) -#define NTOV(xp) ((xp)->nn_vnode) - -int nandfs_init(struct vfsconf *); -int nandfs_uninit(struct vfsconf *); - -extern struct vop_vector nandfs_vnodeops; -extern struct vop_vector nandfs_system_vnodeops; - -struct nandfs_node; - -/* Structure and derivatives */ -struct nandfs_mdt { - uint32_t entries_per_block; - uint32_t entries_per_group; - uint32_t blocks_per_group; - uint32_t groups_per_desc_block; /* desc is super group */ - uint32_t blocks_per_desc_block; /* desc is super group */ -}; - -struct nandfs_segment { - LIST_ENTRY(nandfs_segment) seg_link; - - struct nandfs_device *fsdev; - - TAILQ_HEAD(, buf) segsum; - TAILQ_HEAD(, buf) data; - - uint64_t seg_num; - uint64_t seg_next; - uint64_t start_block; - uint32_t num_blocks; - - uint32_t nblocks; - uint32_t nbinfos; - uint32_t segsum_blocks; - uint32_t segsum_bytes; - uint32_t bytes_left; - char *current_off; -}; - -struct nandfs_seginfo { - LIST_HEAD( ,nandfs_segment) seg_list; - struct nandfs_segment *curseg; - struct nandfs_device *fsdev; - uint32_t blocks; - uint8_t reiterate; -}; - -#define NANDFS_FSSTOR_FAILED 1 -struct nandfs_fsarea { - int offset; - int flags; - int last_used; -}; - -extern int nandfs_cleaner_enable; -extern int nandfs_cleaner_interval; -extern int nandfs_cleaner_segments; - -struct nandfs_device { - struct vnode *nd_devvp; - struct g_consumer *nd_gconsumer; - - struct thread *nd_syncer; - struct thread *nd_cleaner; - int nd_syncer_exit; - int nd_cleaner_exit; - - struct nandfs_fsarea nd_fsarea[NANDFS_NFSAREAS]; - int nd_last_fsarea; - - STAILQ_HEAD(nandfs_mnts, nandfsmount) nd_mounts; - SLIST_ENTRY(nandfs_device) nd_next_device; - - /* FS structures */ - struct nandfs_fsdata nd_fsdata; - struct nandfs_super_block nd_super; - struct nandfs_segment_summary nd_last_segsum; - struct nandfs_super_root nd_super_root; - struct nandfs_node *nd_dat_node; - struct nandfs_node *nd_cp_node; - struct nandfs_node *nd_su_node; - struct nandfs_node *nd_gc_node; - - struct nandfs_mdt nd_dat_mdt; - struct nandfs_mdt nd_ifile_mdt; - - struct timespec nd_ts; - - /* Synchronization */ - struct mtx nd_mutex; - struct mtx nd_sync_mtx; - struct cv nd_sync_cv; - struct mtx nd_clean_mtx; - struct cv nd_clean_cv; - struct lock nd_seg_const; - - struct nandfs_seginfo *nd_seginfo; - - /* FS geometry */ - uint64_t nd_devsize; - uint64_t nd_maxfilesize; - uint32_t nd_blocksize; - uint32_t nd_erasesize; - - uint32_t nd_devblocksize; - - uint32_t nd_segs_reserved; - - /* Segment usage */ - uint64_t nd_clean_segs; - uint64_t *nd_free_base; - uint64_t nd_free_count; - uint64_t nd_dirty_bufs; - - /* Running values */ - uint64_t nd_seg_sequence; - uint64_t nd_seg_num; - uint64_t nd_next_seg_num; - uint64_t nd_last_pseg; - uint64_t nd_last_cno; - uint64_t nd_last_ino; - uint64_t nd_fakevblk; - - int nd_mount_state; - int nd_refcnt; - int nd_syncing; - int nd_cleaning; -}; - -extern SLIST_HEAD(_nandfs_devices, nandfs_device) nandfs_devices; - -#define NANDFS_FORCE_SYNCER 0x1 -#define NANDFS_UMOUNT 0x2 - -#define SYNCER_UMOUNT 0x0 -#define SYNCER_VFS_SYNC 0x1 -#define SYNCER_BDFLUSH 0x2 -#define SYNCER_FFORCE 0x3 -#define SYNCER_FSYNC 0x4 -#define SYNCER_ROUPD 0x5 - -static __inline int -nandfs_writelockflags(struct nandfs_device *fsdev, int flags) -{ - int error = 0; - - if (lockstatus(&fsdev->nd_seg_const) != LK_EXCLUSIVE) - error = lockmgr(&fsdev->nd_seg_const, flags | LK_SHARED, NULL); - - return (error); -} - -static __inline void -nandfs_writeunlock(struct nandfs_device *fsdev) -{ - - if (lockstatus(&fsdev->nd_seg_const) != LK_EXCLUSIVE) - lockmgr(&(fsdev)->nd_seg_const, LK_RELEASE, NULL); -} - -#define NANDFS_WRITELOCKFLAGS(fsdev, flags) nandfs_writelockflags(fsdev, flags) - -#define NANDFS_WRITELOCK(fsdev) NANDFS_WRITELOCKFLAGS(fsdev, 0) - -#define NANDFS_WRITEUNLOCK(fsdev) nandfs_writeunlock(fsdev) - -#define NANDFS_WRITEASSERT(fsdev) lockmgr_assert(&(fsdev)->nd_seg_const, KA_LOCKED) - -/* Specific mountpoint; head or a checkpoint/snapshot */ -struct nandfsmount { - STAILQ_ENTRY(nandfsmount) nm_next_mount; - - struct mount *nm_vfs_mountp; - struct nandfs_device *nm_nandfsdev; - struct nandfs_args nm_mount_args; - struct nandfs_node *nm_ifile_node; - - uint8_t nm_flags; - int8_t nm_ronly; -}; - -struct nandfs_node { - struct vnode *nn_vnode; - struct nandfsmount *nn_nmp; - struct nandfs_device *nn_nandfsdev; - struct lockf *nn_lockf; - - uint64_t nn_ino; - struct nandfs_inode nn_inode; - - uint64_t nn_diroff; - uint32_t nn_flags; -}; - -#define IN_ACCESS 0x0001 /* Inode access time update request */ -#define IN_CHANGE 0x0002 /* Inode change time update request */ -#define IN_UPDATE 0x0004 /* Inode was written to; update mtime*/ -#define IN_MODIFIED 0x0008 /* node has been modified */ -#define IN_RENAME 0x0010 /* node is being renamed. */ - -/* File permissions. */ -#define IEXEC 0000100 /* Executable. */ -#define IWRITE 0000200 /* Writeable. */ -#define IREAD 0000400 /* Readable. */ -#define ISVTX 0001000 /* Sticky bit. */ -#define ISGID 0002000 /* Set-gid. */ -#define ISUID 0004000 /* Set-uid. */ - -#define PRINT_NODE_FLAGS \ - "\10\1IN_ACCESS\2IN_CHANGE\3IN_UPDATE\4IN_MODIFIED\5IN_RENAME" - -#define NANDFS_GATHER(x) ((x)->b_flags |= B_FS_FLAG1) -#define NANDFS_UNGATHER(x) ((x)->b_flags &= ~B_FS_FLAG1) -#define NANDFS_ISGATHERED(x) ((x)->b_flags & B_FS_FLAG1) - -#endif /* !_FS_NANDFS_NANDFS_H_ */ diff --git a/sys/fs/nandfs/nandfs_alloc.c b/sys/fs/nandfs/nandfs_alloc.c deleted file mode 100644 index afff174d130d5..0000000000000 --- a/sys/fs/nandfs/nandfs_alloc.c +++ /dev/null @@ -1,366 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/conf.h> -#include <sys/kernel.h> -#include <sys/lock.h> -#include <sys/malloc.h> -#include <sys/mount.h> -#include <sys/mutex.h> -#include <sys/namei.h> -#include <sys/sysctl.h> -#include <sys/vnode.h> -#include <sys/buf.h> -#include <sys/bio.h> - -#include <vm/vm.h> -#include <vm/vm_param.h> -#include <vm/vm_kern.h> -#include <vm/vm_page.h> - -#include <fs/nandfs/nandfs_mount.h> -#include <fs/nandfs/nandfs.h> -#include <fs/nandfs/nandfs_subr.h> - -static void -nandfs_get_desc_block_nr(struct nandfs_mdt *mdt, uint64_t desc, - uint64_t *desc_block) -{ - - *desc_block = desc * mdt->blocks_per_desc_block; -} - -static void -nandfs_get_group_block_nr(struct nandfs_mdt *mdt, uint64_t group, - uint64_t *group_block) -{ - uint64_t desc, group_off; - - desc = group / mdt->groups_per_desc_block; - group_off = group % mdt->groups_per_desc_block; - *group_block = desc * mdt->blocks_per_desc_block + - 1 + group_off * mdt->blocks_per_group; -} - -static void -init_desc_block(struct nandfs_mdt *mdt, uint8_t *block_data) -{ - struct nandfs_block_group_desc *desc; - uint32_t i; - - desc = (struct nandfs_block_group_desc *) block_data; - for (i = 0; i < mdt->groups_per_desc_block; i++) - desc[i].bg_nfrees = mdt->entries_per_group; -} - -int -nandfs_find_free_entry(struct nandfs_mdt *mdt, struct nandfs_node *node, - struct nandfs_alloc_request *req) -{ - nandfs_daddr_t desc, group, maxgroup, maxdesc, pos = 0; - nandfs_daddr_t start_group, start_desc; - nandfs_daddr_t desc_block, group_block; - nandfs_daddr_t file_blocks; - struct nandfs_block_group_desc *descriptors; - struct buf *bp, *bp2; - uint32_t *mask, i, mcount, msize; - int error; - - file_blocks = node->nn_inode.i_blocks; - maxgroup = 0x100000000ull / mdt->entries_per_group; - maxdesc = maxgroup / mdt->groups_per_desc_block; - start_group = req->entrynum / mdt->entries_per_group; - start_desc = start_group / mdt->groups_per_desc_block; - - bp = bp2 = NULL; -restart: - for (desc = start_desc; desc < maxdesc; desc++) { - nandfs_get_desc_block_nr(mdt, desc, &desc_block); - - if (bp) - brelse(bp); - if (desc_block < file_blocks) { - error = nandfs_bread(node, desc_block, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - } else { - error = nandfs_bcreate(node, desc_block, NOCRED, 0, - &bp); - if (error) - return (error); - file_blocks++; - init_desc_block(mdt, bp->b_data); - } - - descriptors = (struct nandfs_block_group_desc *) bp->b_data; - for (group = start_group; group < mdt->groups_per_desc_block; - group++) { - if (descriptors[group].bg_nfrees > 0) { - nandfs_get_group_block_nr(mdt, group, - &group_block); - - if (bp2) - brelse(bp2); - if (group_block < file_blocks) { - error = nandfs_bread(node, group_block, - NOCRED, 0, &bp2); - if (error) { - brelse(bp); - return (error); - } - } else { - error = nandfs_bcreate(node, - group_block, NOCRED, 0, &bp2); - if (error) - return (error); - file_blocks++; - } - mask = (uint32_t *)bp2->b_data; - msize = (sizeof(uint32_t) * __CHAR_BIT); - mcount = mdt->entries_per_group / msize; - for (i = 0; i < mcount; i++) { - if (mask[i] == UINT32_MAX) - continue; - - pos = ffs(~mask[i]) - 1; - pos += (msize * i); - pos += (group * mdt->entries_per_group); - pos += desc * group * - mdt->groups_per_desc_block * - mdt->entries_per_group; - goto found; - } - } - } - start_group = 0; - } - - if (start_desc != 0) { - maxdesc = start_desc; - start_desc = 0; - req->entrynum = 0; - goto restart; - } - - return (ENOENT); - -found: - req->entrynum = pos; - req->bp_desc = bp; - req->bp_bitmap = bp2; - DPRINTF(ALLOC, ("%s: desc: %p bitmap: %p entry: %#jx\n", - __func__, req->bp_desc, req->bp_bitmap, (uintmax_t)pos)); - - return (0); -} - -int -nandfs_find_entry(struct nandfs_mdt* mdt, struct nandfs_node *nnode, - struct nandfs_alloc_request *req) -{ - uint64_t dblock, bblock, eblock; - uint32_t offset; - int error; - - nandfs_mdt_trans_blk(mdt, req->entrynum, &dblock, &bblock, &eblock, - &offset); - - error = nandfs_bread(nnode, dblock, NOCRED, 0, &req->bp_desc); - if (error) { - brelse(req->bp_desc); - return (error); - } - - error = nandfs_bread(nnode, bblock, NOCRED, 0, &req->bp_bitmap); - if (error) { - brelse(req->bp_desc); - brelse(req->bp_bitmap); - return (error); - } - - error = nandfs_bread(nnode, eblock, NOCRED, 0, &req->bp_entry); - if (error) { - brelse(req->bp_desc); - brelse(req->bp_bitmap); - brelse(req->bp_entry); - return (error); - } - - DPRINTF(ALLOC, - ("%s: desc_buf: %p bitmap_buf %p entry_buf %p offset %x\n", - __func__, req->bp_desc, req->bp_bitmap, req->bp_entry, offset)); - - return (0); -} - -static __inline void -nandfs_calc_idx_entry(struct nandfs_mdt* mdt, uint32_t entrynum, - uint64_t *group, uint64_t *bitmap_idx, uint64_t *bitmap_off) -{ - - /* Find group_desc index */ - entrynum = entrynum % - (mdt->entries_per_group * mdt->groups_per_desc_block); - *group = entrynum / mdt->entries_per_group; - /* Find bitmap index and bit offset */ - entrynum = entrynum % mdt->entries_per_group; - *bitmap_idx = entrynum / (sizeof(uint32_t) * __CHAR_BIT); - *bitmap_off = entrynum % (sizeof(uint32_t) * __CHAR_BIT); -} - -int -nandfs_free_entry(struct nandfs_mdt* mdt, struct nandfs_alloc_request *req) -{ - struct nandfs_block_group_desc *descriptors; - uint64_t bitmap_idx, bitmap_off; - uint64_t group; - uint32_t *mask, maskrw; - - nandfs_calc_idx_entry(mdt, req->entrynum, &group, &bitmap_idx, - &bitmap_off); - - DPRINTF(ALLOC, ("nandfs_free_entry: req->entrynum=%jx bitmap_idx=%jx" - " bitmap_off=%jx group=%jx\n", (uintmax_t)req->entrynum, - (uintmax_t)bitmap_idx, (uintmax_t)bitmap_off, (uintmax_t)group)); - - /* Update counter of free entries for group */ - descriptors = (struct nandfs_block_group_desc *) req->bp_desc->b_data; - descriptors[group].bg_nfrees++; - - /* Set bit to indicate that entry is taken */ - mask = (uint32_t *)req->bp_bitmap->b_data; - maskrw = mask[bitmap_idx]; - KASSERT(maskrw & (1 << bitmap_off), ("freeing unallocated vblock")); - maskrw &= ~(1 << bitmap_off); - mask[bitmap_idx] = maskrw; - - /* Make descriptor, bitmap and entry buffer dirty */ - if (nandfs_dirty_buf(req->bp_desc, 0) == 0) { - nandfs_dirty_buf(req->bp_bitmap, 1); - nandfs_dirty_buf(req->bp_entry, 1); - } else { - brelse(req->bp_bitmap); - brelse(req->bp_entry); - return (-1); - } - - return (0); -} - -int -nandfs_alloc_entry(struct nandfs_mdt* mdt, struct nandfs_alloc_request *req) -{ - struct nandfs_block_group_desc *descriptors; - uint64_t bitmap_idx, bitmap_off; - uint64_t group; - uint32_t *mask, maskrw; - - nandfs_calc_idx_entry(mdt, req->entrynum, &group, &bitmap_idx, - &bitmap_off); - - DPRINTF(ALLOC, ("nandfs_alloc_entry: req->entrynum=%jx bitmap_idx=%jx" - " bitmap_off=%jx group=%jx\n", (uintmax_t)req->entrynum, - (uintmax_t)bitmap_idx, (uintmax_t)bitmap_off, (uintmax_t)group)); - - /* Update counter of free entries for group */ - descriptors = (struct nandfs_block_group_desc *) req->bp_desc->b_data; - descriptors[group].bg_nfrees--; - - /* Clear bit to indicate that entry is free */ - mask = (uint32_t *)req->bp_bitmap->b_data; - maskrw = mask[bitmap_idx]; - maskrw |= 1 << bitmap_off; - mask[bitmap_idx] = maskrw; - - /* Make descriptor, bitmap and entry buffer dirty */ - if (nandfs_dirty_buf(req->bp_desc, 0) == 0) { - nandfs_dirty_buf(req->bp_bitmap, 1); - nandfs_dirty_buf(req->bp_entry, 1); - } else { - brelse(req->bp_bitmap); - brelse(req->bp_entry); - return (-1); - } - - return (0); -} - -void -nandfs_abort_entry(struct nandfs_alloc_request *req) -{ - - brelse(req->bp_desc); - brelse(req->bp_bitmap); - brelse(req->bp_entry); -} - -int -nandfs_get_entry_block(struct nandfs_mdt *mdt, struct nandfs_node *node, - struct nandfs_alloc_request *req, uint32_t *entry, int create) -{ - struct buf *bp; - nandfs_lbn_t blocknr; - int error; - - /* Find buffer number for given entry */ - nandfs_mdt_trans(mdt, req->entrynum, &blocknr, entry); - DPRINTF(ALLOC, ("%s: ino %#jx entrynum:%#jx block:%#jx entry:%x\n", - __func__, (uintmax_t)node->nn_ino, (uintmax_t)req->entrynum, - (uintmax_t)blocknr, *entry)); - - /* Read entry block or create if 'create' parameter is not zero */ - bp = NULL; - - if (blocknr < node->nn_inode.i_blocks) - error = nandfs_bread(node, blocknr, NOCRED, 0, &bp); - else if (create) - error = nandfs_bcreate(node, blocknr, NOCRED, 0, &bp); - else - error = E2BIG; - - if (error) { - DPRINTF(ALLOC, ("%s: ino %#jx block %#jx entry %x error %d\n", - __func__, (uintmax_t)node->nn_ino, (uintmax_t)blocknr, - *entry, error)); - if (bp) - brelse(bp); - return (error); - } - - MPASS(nandfs_vblk_get(bp) != 0 || node->nn_ino == NANDFS_DAT_INO); - - req->bp_entry = bp; - return (0); -} diff --git a/sys/fs/nandfs/nandfs_bmap.c b/sys/fs/nandfs/nandfs_bmap.c deleted file mode 100644 index 6a1c2b0775d59..0000000000000 --- a/sys/fs/nandfs/nandfs_bmap.c +++ /dev/null @@ -1,232 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf - * Copyright (c) 2008, 2009 Reinoud Zandijk - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * From: NetBSD: nilfs_subr.c,v 1.4 2009/07/29 17:06:57 reinoud - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/namei.h> -#include <sys/kernel.h> -#include <sys/stat.h> -#include <sys/buf.h> -#include <sys/bio.h> -#include <sys/proc.h> -#include <sys/mount.h> -#include <sys/vnode.h> -#include <sys/signalvar.h> -#include <sys/malloc.h> -#include <sys/dirent.h> -#include <sys/lockf.h> -#include <sys/ktr.h> - -#include <vm/vm.h> -#include <vm/vm_extern.h> -#include <vm/vm_object.h> -#include <vm/vnode_pager.h> - -#include <machine/_inttypes.h> - -#include <vm/vm.h> -#include <vm/vm_extern.h> -#include <vm/vm_object.h> -#include <vm/vnode_pager.h> - -#include "nandfs_mount.h" -#include "nandfs.h" -#include "nandfs_subr.h" -#include "bmap.h" - -nandfs_lbn_t -nandfs_get_maxfilesize(struct nandfs_device *fsdev) -{ - - return (get_maxfilesize(fsdev)); -} - -int -nandfs_bmap_lookup(struct nandfs_node *node, nandfs_lbn_t lblk, - nandfs_daddr_t *vblk) -{ - int error = 0; - - if (node->nn_ino == NANDFS_GC_INO && lblk >= 0) - *vblk = lblk; - else - error = bmap_lookup(node, lblk, vblk); - - DPRINTF(TRANSLATE, ("%s: error %d ino %#jx lblocknr %#jx -> %#jx\n", - __func__, error, (uintmax_t)node->nn_ino, (uintmax_t)lblk, - (uintmax_t)*vblk)); - - if (error) - nandfs_error("%s: returned %d", __func__, error); - - return (error); -} - -int -nandfs_bmap_insert_block(struct nandfs_node *node, nandfs_lbn_t lblk, - struct buf *bp) -{ - struct nandfs_device *fsdev; - nandfs_daddr_t vblk; - int error; - - fsdev = node->nn_nandfsdev; - - vblk = 0; - if (node->nn_ino != NANDFS_DAT_INO) { - error = nandfs_vblock_alloc(fsdev, &vblk); - if (error) - return (error); - } - - nandfs_buf_set(bp, NANDFS_VBLK_ASSIGNED); - nandfs_vblk_set(bp, vblk); - - error = bmap_insert_block(node, lblk, vblk); - if (error) { - nandfs_vblock_free(fsdev, vblk); - return (error); - } - - return (0); -} - -int -nandfs_bmap_dirty_blocks(struct nandfs_node *node, struct buf *bp, int force) -{ - int error; - - error = bmap_dirty_meta(node, bp->b_lblkno, force); - if (error) - nandfs_error("%s: cannot dirty buffer %p\n", - __func__, bp); - - return (error); -} - -static int -nandfs_bmap_update_mapping(struct nandfs_node *node, nandfs_lbn_t lblk, - nandfs_daddr_t blknr) -{ - int error; - - DPRINTF(BMAP, - ("%s: node: %p ino: %#jx lblk: %#jx vblk: %#jx\n", - __func__, node, (uintmax_t)node->nn_ino, (uintmax_t)lblk, - (uintmax_t)blknr)); - - error = bmap_insert_block(node, lblk, blknr); - - return (error); -} - -int -nandfs_bmap_update_block(struct nandfs_node *node, struct buf *bp, - nandfs_lbn_t blknr) -{ - nandfs_lbn_t lblk; - int error; - - lblk = bp->b_lblkno; - nandfs_vblk_set(bp, blknr); - - DPRINTF(BMAP, ("%s: node: %p ino: %#jx bp: %p lblk: %#jx blk: %#jx\n", - __func__, node, (uintmax_t)node->nn_ino, bp, - (uintmax_t)lblk, (uintmax_t)blknr)); - - error = nandfs_bmap_update_mapping(node, lblk, blknr); - if (error) { - nandfs_error("%s: cannot update lblk:%jx to blk:%jx for " - "node:%p, error:%d\n", __func__, (uintmax_t)lblk, - (uintmax_t)blknr, node, error); - return (error); - } - - return (error); -} - -int -nandfs_bmap_update_dat(struct nandfs_node *node, nandfs_daddr_t oldblk, - struct buf *bp) -{ - struct nandfs_device *fsdev; - nandfs_daddr_t vblk = 0; - int error; - - if (node->nn_ino == NANDFS_DAT_INO) - return (0); - - if (nandfs_buf_check(bp, NANDFS_VBLK_ASSIGNED)) { - nandfs_buf_clear(bp, NANDFS_VBLK_ASSIGNED); - return (0); - } - - fsdev = node->nn_nandfsdev; - - /* First alloc new virtual block.... */ - error = nandfs_vblock_alloc(fsdev, &vblk); - if (error) - return (error); - - error = nandfs_bmap_update_block(node, bp, vblk); - if (error) - return (error); - - /* Then we can end up with old one */ - nandfs_vblock_end(fsdev, oldblk); - - DPRINTF(BMAP, - ("%s: ino %#jx block %#jx: update vblk %#jx to %#jx\n", - __func__, (uintmax_t)node->nn_ino, (uintmax_t)bp->b_lblkno, - (uintmax_t)oldblk, (uintmax_t)vblk)); - return (error); -} - -int -nandfs_bmap_truncate_mapping(struct nandfs_node *node, nandfs_lbn_t oblk, - nandfs_lbn_t nblk) -{ - nandfs_lbn_t todo; - int error; - - todo = oblk - nblk; - - DPRINTF(BMAP, ("%s: node %p oblk %jx nblk %jx truncate by %jx\n", - __func__, node, oblk, nblk, todo)); - - error = bmap_truncate_mapping(node, oblk, todo); - if (error) - return (error); - - return (error); -} diff --git a/sys/fs/nandfs/nandfs_buffer.c b/sys/fs/nandfs/nandfs_buffer.c deleted file mode 100644 index 57089718554fd..0000000000000 --- a/sys/fs/nandfs/nandfs_buffer.c +++ /dev/null @@ -1,85 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/conf.h> -#include <sys/kernel.h> -#include <sys/lock.h> -#include <sys/malloc.h> -#include <sys/mount.h> -#include <sys/mutex.h> -#include <sys/buf.h> -#include <sys/namei.h> -#include <sys/vnode.h> -#include <sys/bio.h> - -#include <fs/nandfs/nandfs_mount.h> -#include <fs/nandfs/nandfs.h> -#include <fs/nandfs/nandfs_subr.h> - -struct buf * -nandfs_geteblk(int size, int flags) -{ - struct buf *bp; - - /* - * XXX - * Right now we can call geteblk with GB_NOWAIT_BD flag, which means - * it can return NULL. But we cannot afford to get NULL, hence this panic. - */ - bp = geteblk(size, flags); - if (bp == NULL) - panic("geteblk returned NULL"); - - return (bp); -} - -void -nandfs_dirty_bufs_increment(struct nandfs_device *fsdev) -{ - - mtx_lock(&fsdev->nd_mutex); - KASSERT(fsdev->nd_dirty_bufs >= 0, ("negative nd_dirty_bufs")); - fsdev->nd_dirty_bufs++; - mtx_unlock(&fsdev->nd_mutex); -} - -void -nandfs_dirty_bufs_decrement(struct nandfs_device *fsdev) -{ - - mtx_lock(&fsdev->nd_mutex); - KASSERT(fsdev->nd_dirty_bufs > 0, - ("decrementing not-positive nd_dirty_bufs")); - fsdev->nd_dirty_bufs--; - mtx_unlock(&fsdev->nd_mutex); -} diff --git a/sys/fs/nandfs/nandfs_cleaner.c b/sys/fs/nandfs/nandfs_cleaner.c deleted file mode 100644 index 3241c8701bfca..0000000000000 --- a/sys/fs/nandfs/nandfs_cleaner.c +++ /dev/null @@ -1,622 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/conf.h> -#include <sys/kernel.h> -#include <sys/lock.h> -#include <sys/malloc.h> -#include <sys/mount.h> -#include <sys/mutex.h> -#include <sys/buf.h> -#include <sys/namei.h> -#include <sys/vnode.h> -#include <sys/bio.h> - -#include <fs/nandfs/nandfs_mount.h> -#include <fs/nandfs/nandfs.h> -#include <fs/nandfs/nandfs_subr.h> - -#define NANDFS_CLEANER_KILL 1 - -static void nandfs_cleaner(struct nandfs_device *); -static int nandfs_cleaner_clean_segments(struct nandfs_device *, - struct nandfs_vinfo *, uint32_t, struct nandfs_period *, uint32_t, - struct nandfs_bdesc *, uint32_t, uint64_t *, uint32_t); - -static int -nandfs_process_bdesc(struct nandfs_device *nffsdev, struct nandfs_bdesc *bd, - uint64_t nmembs); - -static void -nandfs_wakeup_wait_cleaner(struct nandfs_device *fsdev, int reason) -{ - - mtx_lock(&fsdev->nd_clean_mtx); - if (reason == NANDFS_CLEANER_KILL) - fsdev->nd_cleaner_exit = 1; - if (fsdev->nd_cleaning == 0) { - fsdev->nd_cleaning = 1; - wakeup(&fsdev->nd_cleaning); - } - cv_wait(&fsdev->nd_clean_cv, &fsdev->nd_clean_mtx); - mtx_unlock(&fsdev->nd_clean_mtx); -} - -int -nandfs_start_cleaner(struct nandfs_device *fsdev) -{ - int error; - - MPASS(fsdev->nd_cleaner == NULL); - - fsdev->nd_cleaner_exit = 0; - - error = kthread_add((void(*)(void *))nandfs_cleaner, fsdev, NULL, - &fsdev->nd_cleaner, 0, 0, "nandfs_cleaner"); - if (error) - printf("nandfs: could not start cleaner: %d\n", error); - - return (error); -} - -int -nandfs_stop_cleaner(struct nandfs_device *fsdev) -{ - - MPASS(fsdev->nd_cleaner != NULL); - nandfs_wakeup_wait_cleaner(fsdev, NANDFS_CLEANER_KILL); - fsdev->nd_cleaner = NULL; - - DPRINTF(CLEAN, ("cleaner stopped\n")); - return (0); -} - -static int -nandfs_cleaner_finished(struct nandfs_device *fsdev) -{ - int exit; - - mtx_lock(&fsdev->nd_clean_mtx); - fsdev->nd_cleaning = 0; - if (!fsdev->nd_cleaner_exit) { - DPRINTF(CLEAN, ("%s: sleep\n", __func__)); - msleep(&fsdev->nd_cleaning, &fsdev->nd_clean_mtx, PRIBIO, "-", - hz * nandfs_cleaner_interval); - } - exit = fsdev->nd_cleaner_exit; - cv_broadcast(&fsdev->nd_clean_cv); - mtx_unlock(&fsdev->nd_clean_mtx); - if (exit) { - DPRINTF(CLEAN, ("%s: no longer active\n", __func__)); - return (1); - } - - return (0); -} - -static void -print_suinfo(struct nandfs_suinfo *suinfo, int nsegs) -{ - int i; - - for (i = 0; i < nsegs; i++) { - DPRINTF(CLEAN, ("%jx %jd %c%c%c %10u\n", - suinfo[i].nsi_num, suinfo[i].nsi_lastmod, - (suinfo[i].nsi_flags & - (NANDFS_SEGMENT_USAGE_ACTIVE) ? 'a' : '-'), - (suinfo[i].nsi_flags & - (NANDFS_SEGMENT_USAGE_DIRTY) ? 'd' : '-'), - (suinfo[i].nsi_flags & - (NANDFS_SEGMENT_USAGE_ERROR) ? 'e' : '-'), - suinfo[i].nsi_blocks)); - } -} - -static int -nandfs_cleaner_vblock_is_alive(struct nandfs_device *fsdev, - struct nandfs_vinfo *vinfo, struct nandfs_cpinfo *cp, uint32_t ncps) -{ - int64_t idx, min, max; - - if (vinfo->nvi_end >= fsdev->nd_last_cno) - return (1); - - if (ncps == 0) - return (0); - - if (vinfo->nvi_end < cp[0].nci_cno || - vinfo->nvi_start > cp[ncps - 1].nci_cno) - return (0); - - idx = min = 0; - max = ncps - 1; - while (min <= max) { - idx = (min + max) / 2; - if (vinfo->nvi_start == cp[idx].nci_cno) - return (1); - if (vinfo->nvi_start < cp[idx].nci_cno) - max = idx - 1; - else - min = idx + 1; - } - - return (vinfo->nvi_end >= cp[idx].nci_cno); -} - -static void -nandfs_cleaner_vinfo_mark_alive(struct nandfs_device *fsdev, - struct nandfs_vinfo *vinfo, uint32_t nmembs, struct nandfs_cpinfo *cp, - uint32_t ncps) -{ - uint32_t i; - - for (i = 0; i < nmembs; i++) - vinfo[i].nvi_alive = - nandfs_cleaner_vblock_is_alive(fsdev, &vinfo[i], cp, ncps); -} - -static int -nandfs_cleaner_bdesc_is_alive(struct nandfs_device *fsdev, - struct nandfs_bdesc *bdesc) -{ - int alive; - - alive = bdesc->bd_oblocknr == bdesc->bd_blocknr; - if (!alive) - MPASS(abs(bdesc->bd_oblocknr - bdesc->bd_blocknr) > 2); - - return (alive); -} - -static void -nandfs_cleaner_bdesc_mark_alive(struct nandfs_device *fsdev, - struct nandfs_bdesc *bdesc, uint32_t nmembs) -{ - uint32_t i; - - for (i = 0; i < nmembs; i++) - bdesc[i].bd_alive = nandfs_cleaner_bdesc_is_alive(fsdev, - &bdesc[i]); -} - -static void -nandfs_cleaner_iterate_psegment(struct nandfs_device *fsdev, - struct nandfs_segment_summary *segsum, union nandfs_binfo *binfo, - nandfs_daddr_t blk, struct nandfs_vinfo **vipp, struct nandfs_bdesc **bdpp) -{ - int i; - - DPRINTF(CLEAN, ("%s nbinfos %x\n", __func__, segsum->ss_nbinfos)); - for (i = 0; i < segsum->ss_nbinfos; i++) { - if (binfo[i].bi_v.bi_ino == NANDFS_DAT_INO) { - (*bdpp)->bd_oblocknr = blk + segsum->ss_nblocks - - segsum->ss_nbinfos + i; - /* - * XXX Hack - */ - if (segsum->ss_flags & NANDFS_SS_SR) - (*bdpp)->bd_oblocknr--; - (*bdpp)->bd_level = binfo[i].bi_dat.bi_level; - (*bdpp)->bd_offset = binfo[i].bi_dat.bi_blkoff; - (*bdpp)++; - } else { - (*vipp)->nvi_ino = binfo[i].bi_v.bi_ino; - (*vipp)->nvi_vblocknr = binfo[i].bi_v.bi_vblocknr; - (*vipp)++; - } - } -} - -static int -nandfs_cleaner_iterate_segment(struct nandfs_device *fsdev, uint64_t segno, - struct nandfs_vinfo **vipp, struct nandfs_bdesc **bdpp, int *select) -{ - struct nandfs_segment_summary *segsum; - union nandfs_binfo *binfo; - struct buf *bp; - uint32_t nblocks; - nandfs_daddr_t curr, start, end; - int error = 0; - - nandfs_get_segment_range(fsdev, segno, &start, &end); - - DPRINTF(CLEAN, ("%s: segno %jx start %jx end %jx\n", __func__, segno, - start, end)); - - *select = 0; - - for (curr = start; curr < end; curr += nblocks) { - error = nandfs_dev_bread(fsdev, curr, NOCRED, 0, &bp); - if (error) { - brelse(bp); - nandfs_error("%s: couldn't load segment summary of %jx: %d\n", - __func__, segno, error); - return (error); - } - - segsum = (struct nandfs_segment_summary *)bp->b_data; - binfo = (union nandfs_binfo *)(bp->b_data + segsum->ss_bytes); - - if (!nandfs_segsum_valid(segsum)) { - brelse(bp); - nandfs_error("nandfs: invalid summary of segment %jx\n", segno); - return (error); - } - - DPRINTF(CLEAN, ("%s: %jx magic %x bytes %x nblocks %x nbinfos " - "%x\n", __func__, segno, segsum->ss_magic, segsum->ss_bytes, - segsum->ss_nblocks, segsum->ss_nbinfos)); - - nandfs_cleaner_iterate_psegment(fsdev, segsum, binfo, curr, - vipp, bdpp); - nblocks = segsum->ss_nblocks; - brelse(bp); - } - - if (error == 0) - *select = 1; - - return (error); -} - -static int -nandfs_cleaner_choose_segment(struct nandfs_device *fsdev, uint64_t **segpp, - uint64_t nsegs, uint64_t *rseg) -{ - struct nandfs_suinfo *suinfo; - uint64_t i, ssegs; - int error; - - suinfo = malloc(sizeof(*suinfo) * nsegs, M_NANDFSTEMP, - M_ZERO | M_WAITOK); - - if (*rseg >= fsdev->nd_fsdata.f_nsegments) - *rseg = 0; - -retry: - error = nandfs_get_segment_info_filter(fsdev, suinfo, nsegs, *rseg, - &ssegs, NANDFS_SEGMENT_USAGE_DIRTY, - NANDFS_SEGMENT_USAGE_ACTIVE | NANDFS_SEGMENT_USAGE_ERROR | - NANDFS_SEGMENT_USAGE_GC); - if (error) { - nandfs_error("%s:%d", __FILE__, __LINE__); - goto out; - } - if (ssegs == 0 && *rseg != 0) { - *rseg = 0; - goto retry; - } - if (ssegs > 0) { - print_suinfo(suinfo, ssegs); - - for (i = 0; i < ssegs; i++) { - (**segpp) = suinfo[i].nsi_num; - (*segpp)++; - } - *rseg = suinfo[i - 1].nsi_num + 1; - } - -out: - free(suinfo, M_NANDFSTEMP); - return (error); -} - -static int -nandfs_cleaner_body(struct nandfs_device *fsdev, uint64_t *rseg) -{ - struct nandfs_vinfo *vinfo, *vip, *vipi; - struct nandfs_bdesc *bdesc, *bdp, *bdpi; - struct nandfs_cpstat cpstat; - struct nandfs_cpinfo *cpinfo = NULL; - uint64_t *segnums, *segp; - int select, selected; - int error = 0; - int nsegs; - int i; - - nsegs = nandfs_cleaner_segments; - - vip = vinfo = malloc(sizeof(*vinfo) * - fsdev->nd_fsdata.f_blocks_per_segment * nsegs, M_NANDFSTEMP, - M_ZERO | M_WAITOK); - bdp = bdesc = malloc(sizeof(*bdesc) * - fsdev->nd_fsdata.f_blocks_per_segment * nsegs, M_NANDFSTEMP, - M_ZERO | M_WAITOK); - segp = segnums = malloc(sizeof(*segnums) * nsegs, M_NANDFSTEMP, - M_WAITOK); - - error = nandfs_cleaner_choose_segment(fsdev, &segp, nsegs, rseg); - if (error) { - nandfs_error("%s:%d", __FILE__, __LINE__); - goto out; - } - - if (segnums == segp) - goto out; - - selected = 0; - for (i = 0; i < segp - segnums; i++) { - error = nandfs_cleaner_iterate_segment(fsdev, segnums[i], &vip, - &bdp, &select); - if (error) { - /* - * XXX deselect (see below)? - */ - goto out; - } - if (!select) - segnums[i] = NANDFS_NOSEGMENT; - else { - error = nandfs_markgc_segment(fsdev, segnums[i]); - if (error) { - nandfs_error("%s:%d\n", __FILE__, __LINE__); - goto out; - } - selected++; - } - } - - if (selected == 0) { - MPASS(vinfo == vip); - MPASS(bdesc == bdp); - goto out; - } - - error = nandfs_get_cpstat(fsdev->nd_cp_node, &cpstat); - if (error) { - nandfs_error("%s:%d\n", __FILE__, __LINE__); - goto out; - } - - if (cpstat.ncp_nss != 0) { - cpinfo = malloc(sizeof(struct nandfs_cpinfo) * cpstat.ncp_nss, - M_NANDFSTEMP, M_WAITOK); - error = nandfs_get_cpinfo(fsdev->nd_cp_node, 1, NANDFS_SNAPSHOT, - cpinfo, cpstat.ncp_nss, NULL); - if (error) { - nandfs_error("%s:%d\n", __FILE__, __LINE__); - goto out_locked; - } - } - - NANDFS_WRITELOCK(fsdev); - DPRINTF(CLEAN, ("%s: got lock\n", __func__)); - - error = nandfs_get_dat_vinfo(fsdev, vinfo, vip - vinfo); - if (error) { - nandfs_error("%s:%d\n", __FILE__, __LINE__); - goto out_locked; - } - - nandfs_cleaner_vinfo_mark_alive(fsdev, vinfo, vip - vinfo, cpinfo, - cpstat.ncp_nss); - - error = nandfs_get_dat_bdescs(fsdev, bdesc, bdp - bdesc); - if (error) { - nandfs_error("%s:%d\n", __FILE__, __LINE__); - goto out_locked; - } - - nandfs_cleaner_bdesc_mark_alive(fsdev, bdesc, bdp - bdesc); - - DPRINTF(CLEAN, ("got:\n")); - for (vipi = vinfo; vipi < vip; vipi++) { - DPRINTF(CLEAN, ("v ino %jx vblocknr %jx start %jx end %jx " - "alive %d\n", vipi->nvi_ino, vipi->nvi_vblocknr, - vipi->nvi_start, vipi->nvi_end, vipi->nvi_alive)); - } - for (bdpi = bdesc; bdpi < bdp; bdpi++) { - DPRINTF(CLEAN, ("b oblocknr %jx blocknr %jx offset %jx " - "alive %d\n", bdpi->bd_oblocknr, bdpi->bd_blocknr, - bdpi->bd_offset, bdpi->bd_alive)); - } - DPRINTF(CLEAN, ("end list\n")); - - error = nandfs_cleaner_clean_segments(fsdev, vinfo, vip - vinfo, NULL, - 0, bdesc, bdp - bdesc, segnums, segp - segnums); - if (error) - nandfs_error("%s:%d\n", __FILE__, __LINE__); - -out_locked: - NANDFS_WRITEUNLOCK(fsdev); -out: - free(cpinfo, M_NANDFSTEMP); - free(segnums, M_NANDFSTEMP); - free(bdesc, M_NANDFSTEMP); - free(vinfo, M_NANDFSTEMP); - - return (error); -} - -static void -nandfs_cleaner(struct nandfs_device *fsdev) -{ - uint64_t checked_seg = 0; - int error; - - while (!nandfs_cleaner_finished(fsdev)) { - if (!nandfs_cleaner_enable || rebooting) - continue; - - DPRINTF(CLEAN, ("%s: run started\n", __func__)); - - fsdev->nd_cleaning = 1; - - error = nandfs_cleaner_body(fsdev, &checked_seg); - - DPRINTF(CLEAN, ("%s: run finished error %d\n", __func__, - error)); - } - - DPRINTF(CLEAN, ("%s: exiting\n", __func__)); - kthread_exit(); -} - -static int -nandfs_cleaner_clean_segments(struct nandfs_device *nffsdev, - struct nandfs_vinfo *vinfo, uint32_t nvinfo, - struct nandfs_period *pd, uint32_t npd, - struct nandfs_bdesc *bdesc, uint32_t nbdesc, - uint64_t *segments, uint32_t nsegs) -{ - struct nandfs_node *gc; - struct buf *bp; - uint32_t i; - int error = 0; - - gc = nffsdev->nd_gc_node; - - DPRINTF(CLEAN, ("%s: enter\n", __func__)); - - VOP_LOCK(NTOV(gc), LK_EXCLUSIVE); - for (i = 0; i < nvinfo; i++) { - if (!vinfo[i].nvi_alive) - continue; - DPRINTF(CLEAN, ("%s: read vblknr:%#jx blk:%#jx\n", - __func__, (uintmax_t)vinfo[i].nvi_vblocknr, - (uintmax_t)vinfo[i].nvi_blocknr)); - error = nandfs_bread(nffsdev->nd_gc_node, vinfo[i].nvi_blocknr, - NULL, 0, &bp); - if (error) { - nandfs_error("%s:%d", __FILE__, __LINE__); - VOP_UNLOCK(NTOV(gc), 0); - goto out; - } - nandfs_vblk_set(bp, vinfo[i].nvi_vblocknr); - nandfs_buf_set(bp, NANDFS_VBLK_ASSIGNED); - nandfs_dirty_buf(bp, 1); - } - VOP_UNLOCK(NTOV(gc), 0); - - /* Delete checkpoints */ - for (i = 0; i < npd; i++) { - DPRINTF(CLEAN, ("delete checkpoint: %jx\n", - (uintmax_t)pd[i].p_start)); - error = nandfs_delete_cp(nffsdev->nd_cp_node, pd[i].p_start, - pd[i].p_end); - if (error) { - nandfs_error("%s:%d", __FILE__, __LINE__); - goto out; - } - } - - /* Update vblocks */ - for (i = 0; i < nvinfo; i++) { - if (vinfo[i].nvi_alive) - continue; - DPRINTF(CLEAN, ("freeing vblknr: %jx\n", vinfo[i].nvi_vblocknr)); - error = nandfs_vblock_free(nffsdev, vinfo[i].nvi_vblocknr); - if (error) { - nandfs_error("%s:%d", __FILE__, __LINE__); - goto out; - } - } - - error = nandfs_process_bdesc(nffsdev, bdesc, nbdesc); - if (error) { - nandfs_error("%s:%d", __FILE__, __LINE__); - goto out; - } - - /* Add segments to clean */ - if (nffsdev->nd_free_count) { - nffsdev->nd_free_base = realloc(nffsdev->nd_free_base, - (nffsdev->nd_free_count + nsegs) * sizeof(uint64_t), - M_NANDFSTEMP, M_WAITOK | M_ZERO); - memcpy(&nffsdev->nd_free_base[nffsdev->nd_free_count], segments, - nsegs * sizeof(uint64_t)); - nffsdev->nd_free_count += nsegs; - } else { - nffsdev->nd_free_base = malloc(nsegs * sizeof(uint64_t), - M_NANDFSTEMP, M_WAITOK|M_ZERO); - memcpy(nffsdev->nd_free_base, segments, - nsegs * sizeof(uint64_t)); - nffsdev->nd_free_count = nsegs; - } - -out: - - DPRINTF(CLEAN, ("%s: exit error %d\n", __func__, error)); - - return (error); -} - -static int -nandfs_process_bdesc(struct nandfs_device *nffsdev, struct nandfs_bdesc *bd, - uint64_t nmembs) -{ - struct nandfs_node *dat_node; - struct buf *bp; - uint64_t i; - int error; - - dat_node = nffsdev->nd_dat_node; - - VOP_LOCK(NTOV(dat_node), LK_EXCLUSIVE); - - for (i = 0; i < nmembs; i++) { - if (!bd[i].bd_alive) - continue; - DPRINTF(CLEAN, ("%s: idx %jx offset %jx\n", - __func__, i, bd[i].bd_offset)); - if (bd[i].bd_level) { - error = nandfs_bread_meta(dat_node, bd[i].bd_offset, - NULL, 0, &bp); - if (error) { - nandfs_error("%s: cannot read dat node " - "level:%d\n", __func__, bd[i].bd_level); - brelse(bp); - VOP_UNLOCK(NTOV(dat_node), 0); - return (error); - } - nandfs_dirty_buf_meta(bp, 1); - nandfs_bmap_dirty_blocks(VTON(bp->b_vp), bp, 1); - } else { - error = nandfs_bread(dat_node, bd[i].bd_offset, NULL, - 0, &bp); - if (error) { - nandfs_error("%s: cannot read dat node\n", - __func__); - brelse(bp); - VOP_UNLOCK(NTOV(dat_node), 0); - return (error); - } - nandfs_dirty_buf(bp, 1); - } - DPRINTF(CLEAN, ("%s: bp: %p\n", __func__, bp)); - } - - VOP_UNLOCK(NTOV(dat_node), 0); - - return (0); -} diff --git a/sys/fs/nandfs/nandfs_cpfile.c b/sys/fs/nandfs/nandfs_cpfile.c deleted file mode 100644 index 8c9a695879e42..0000000000000 --- a/sys/fs/nandfs/nandfs_cpfile.c +++ /dev/null @@ -1,778 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/conf.h> -#include <sys/kernel.h> -#include <sys/lock.h> -#include <sys/malloc.h> -#include <sys/mount.h> -#include <sys/mutex.h> -#include <sys/namei.h> -#include <sys/sysctl.h> -#include <sys/vnode.h> -#include <sys/buf.h> -#include <sys/bio.h> - -#include <vm/vm.h> -#include <vm/vm_param.h> -#include <vm/vm_kern.h> -#include <vm/vm_page.h> - -#include "nandfs_mount.h" -#include "nandfs.h" -#include "nandfs_subr.h" - - -static int -nandfs_checkpoint_size(struct nandfs_device *fsdev) -{ - - return (fsdev->nd_fsdata.f_checkpoint_size); -} - -static int -nandfs_checkpoint_blk_offset(struct nandfs_device *fsdev, uint64_t cn, - uint64_t *blk, uint64_t *offset) -{ - uint64_t off; - uint16_t cp_size, cp_per_blk; - - KASSERT((cn), ("checkpoing cannot be zero")); - - cp_size = fsdev->nd_fsdata.f_checkpoint_size; - cp_per_blk = fsdev->nd_blocksize / cp_size; - off = roundup(sizeof(struct nandfs_cpfile_header), cp_size) / cp_size; - off += (cn - 1); - - *blk = off / cp_per_blk; - *offset = (off % cp_per_blk) * cp_size; - - return (0); -} - -static int -nandfs_checkpoint_blk_remaining(struct nandfs_device *fsdev, uint64_t cn, - uint64_t blk, uint64_t offset) -{ - uint16_t cp_size, cp_remaining; - - cp_size = fsdev->nd_fsdata.f_checkpoint_size; - cp_remaining = (fsdev->nd_blocksize - offset) / cp_size; - - return (cp_remaining); -} - -int -nandfs_get_checkpoint(struct nandfs_device *fsdev, struct nandfs_node *cp_node, - uint64_t cn) -{ - struct buf *bp; - uint64_t blk, offset; - int error; - - if (cn != fsdev->nd_last_cno && cn != (fsdev->nd_last_cno + 1)) { - return (-1); - } - - error = nandfs_bread(cp_node, 0, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (-1); - } - - error = nandfs_dirty_buf(bp, 0); - if (error) - return (-1); - - - nandfs_checkpoint_blk_offset(fsdev, cn, &blk, &offset); - - if (blk != 0) { - if (blk < cp_node->nn_inode.i_blocks) - error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp); - else - error = nandfs_bcreate(cp_node, blk, NOCRED, 0, &bp); - if (error) { - if (bp) - brelse(bp); - return (-1); - } - - nandfs_dirty_buf(bp, 1); - } - - DPRINTF(CPFILE, ("%s: cn:%#jx entry block:%#jx offset:%#jx\n", - __func__, (uintmax_t)cn, (uintmax_t)blk, (uintmax_t)offset)); - - return (0); -} - -int -nandfs_set_checkpoint(struct nandfs_device *fsdev, struct nandfs_node *cp_node, - uint64_t cn, struct nandfs_inode *ifile_inode, uint64_t nblocks) -{ - struct nandfs_cpfile_header *cnh; - struct nandfs_checkpoint *cnp; - struct buf *bp; - uint64_t blk, offset; - int error; - - if (cn != fsdev->nd_last_cno && cn != (fsdev->nd_last_cno + 1)) { - nandfs_error("%s: trying to set invalid chekpoint %jx - %jx\n", - __func__, cn, fsdev->nd_last_cno); - return (-1); - } - - error = nandfs_bread(cp_node, 0, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return error; - } - - cnh = (struct nandfs_cpfile_header *) bp->b_data; - cnh->ch_ncheckpoints++; - - nandfs_checkpoint_blk_offset(fsdev, cn, &blk, &offset); - - if(blk != 0) { - brelse(bp); - error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return error; - } - } - - cnp = (struct nandfs_checkpoint *)((uint8_t *)bp->b_data + offset); - cnp->cp_flags = 0; - cnp->cp_checkpoints_count = 1; - memset(&cnp->cp_snapshot_list, 0, sizeof(struct nandfs_snapshot_list)); - cnp->cp_cno = cn; - cnp->cp_create = fsdev->nd_ts.tv_sec; - cnp->cp_nblk_inc = nblocks; - cnp->cp_blocks_count = 0; - memcpy (&cnp->cp_ifile_inode, ifile_inode, sizeof(cnp->cp_ifile_inode)); - - DPRINTF(CPFILE, ("%s: cn:%#jx ctime:%#jx nblk:%#jx\n", - __func__, (uintmax_t)cn, (uintmax_t)cnp->cp_create, - (uintmax_t)nblocks)); - - brelse(bp); - return (0); -} - -static int -nandfs_cp_mounted(struct nandfs_device *nandfsdev, uint64_t cno) -{ - struct nandfsmount *nmp; - int mounted = 0; - - mtx_lock(&nandfsdev->nd_mutex); - /* No double-mounting of the same checkpoint */ - STAILQ_FOREACH(nmp, &nandfsdev->nd_mounts, nm_next_mount) { - if (nmp->nm_mount_args.cpno == cno) { - mounted = 1; - break; - } - } - mtx_unlock(&nandfsdev->nd_mutex); - - return (mounted); -} - -static int -nandfs_cp_set_snapshot(struct nandfs_node *cp_node, uint64_t cno) -{ - struct nandfs_device *fsdev; - struct nandfs_cpfile_header *cnh; - struct nandfs_checkpoint *cnp; - struct nandfs_snapshot_list *list; - struct buf *bp; - uint64_t blk, prev_blk, offset; - uint64_t curr, prev; - int error; - - fsdev = cp_node->nn_nandfsdev; - - /* Get snapshot data */ - nandfs_checkpoint_blk_offset(fsdev, cno, &blk, &offset); - error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - cnp = (struct nandfs_checkpoint *)(bp->b_data + offset); - if (cnp->cp_flags & NANDFS_CHECKPOINT_INVALID) { - brelse(bp); - return (ENOENT); - } - if ((cnp->cp_flags & NANDFS_CHECKPOINT_SNAPSHOT)) { - brelse(bp); - return (EINVAL); - } - - brelse(bp); - /* Get list from header */ - error = nandfs_bread(cp_node, 0, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - - cnh = (struct nandfs_cpfile_header *) bp->b_data; - list = &cnh->ch_snapshot_list; - prev = list->ssl_prev; - brelse(bp); - prev_blk = ~(0); - curr = 0; - while (prev > cno) { - curr = prev; - nandfs_checkpoint_blk_offset(fsdev, prev, &prev_blk, &offset); - error = nandfs_bread(cp_node, prev_blk, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - cnp = (struct nandfs_checkpoint *)(bp->b_data + offset); - list = &cnp->cp_snapshot_list; - prev = list->ssl_prev; - brelse(bp); - } - - if (curr == 0) { - nandfs_bread(cp_node, 0, NOCRED, 0, &bp); - cnh = (struct nandfs_cpfile_header *) bp->b_data; - list = &cnh->ch_snapshot_list; - } else { - nandfs_checkpoint_blk_offset(fsdev, curr, &blk, &offset); - error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - cnp = (struct nandfs_checkpoint *)(bp->b_data + offset); - list = &cnp->cp_snapshot_list; - } - - list->ssl_prev = cno; - error = nandfs_dirty_buf(bp, 0); - if (error) - return (error); - - - /* Update snapshot for cno */ - nandfs_checkpoint_blk_offset(fsdev, cno, &blk, &offset); - error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - cnp = (struct nandfs_checkpoint *)(bp->b_data + offset); - list = &cnp->cp_snapshot_list; - list->ssl_prev = prev; - list->ssl_next = curr; - cnp->cp_flags |= NANDFS_CHECKPOINT_SNAPSHOT; - nandfs_dirty_buf(bp, 1); - - if (prev == 0) { - nandfs_bread(cp_node, 0, NOCRED, 0, &bp); - cnh = (struct nandfs_cpfile_header *) bp->b_data; - list = &cnh->ch_snapshot_list; - } else { - /* Update snapshot list for prev */ - nandfs_checkpoint_blk_offset(fsdev, prev, &blk, &offset); - error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - cnp = (struct nandfs_checkpoint *)(bp->b_data + offset); - list = &cnp->cp_snapshot_list; - } - list->ssl_next = cno; - nandfs_dirty_buf(bp, 1); - - /* Update header */ - error = nandfs_bread(cp_node, 0, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - cnh = (struct nandfs_cpfile_header *) bp->b_data; - cnh->ch_nsnapshots++; - nandfs_dirty_buf(bp, 1); - - return (0); -} - -static int -nandfs_cp_clr_snapshot(struct nandfs_node *cp_node, uint64_t cno) -{ - struct nandfs_device *fsdev; - struct nandfs_cpfile_header *cnh; - struct nandfs_checkpoint *cnp; - struct nandfs_snapshot_list *list; - struct buf *bp; - uint64_t blk, offset, snapshot_cnt; - uint64_t next, prev; - int error; - - fsdev = cp_node->nn_nandfsdev; - - /* Get snapshot data */ - nandfs_checkpoint_blk_offset(fsdev, cno, &blk, &offset); - error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - cnp = (struct nandfs_checkpoint *)(bp->b_data + offset); - if (cnp->cp_flags & NANDFS_CHECKPOINT_INVALID) { - brelse(bp); - return (ENOENT); - } - if (!(cnp->cp_flags & NANDFS_CHECKPOINT_SNAPSHOT)) { - brelse(bp); - return (EINVAL); - } - - list = &cnp->cp_snapshot_list; - next = list->ssl_next; - prev = list->ssl_prev; - brelse(bp); - - /* Get previous snapshot */ - if (prev != 0) { - nandfs_checkpoint_blk_offset(fsdev, prev, &blk, &offset); - error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - cnp = (struct nandfs_checkpoint *)(bp->b_data + offset); - list = &cnp->cp_snapshot_list; - } else { - nandfs_bread(cp_node, 0, NOCRED, 0, &bp); - cnh = (struct nandfs_cpfile_header *) bp->b_data; - list = &cnh->ch_snapshot_list; - } - - list->ssl_next = next; - error = nandfs_dirty_buf(bp, 0); - if (error) - return (error); - - /* Get next snapshot */ - if (next != 0) { - nandfs_checkpoint_blk_offset(fsdev, next, &blk, &offset); - error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - cnp = (struct nandfs_checkpoint *)(bp->b_data + offset); - list = &cnp->cp_snapshot_list; - } else { - nandfs_bread(cp_node, 0, NOCRED, 0, &bp); - cnh = (struct nandfs_cpfile_header *) bp->b_data; - list = &cnh->ch_snapshot_list; - } - list->ssl_prev = prev; - nandfs_dirty_buf(bp, 1); - - /* Update snapshot list for cno */ - nandfs_checkpoint_blk_offset(fsdev, cno, &blk, &offset); - error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - cnp = (struct nandfs_checkpoint *)(bp->b_data + offset); - list = &cnp->cp_snapshot_list; - list->ssl_prev = 0; - list->ssl_next = 0; - cnp->cp_flags &= !NANDFS_CHECKPOINT_SNAPSHOT; - nandfs_dirty_buf(bp, 1); - - /* Update header */ - error = nandfs_bread(cp_node, 0, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - cnh = (struct nandfs_cpfile_header *) bp->b_data; - snapshot_cnt = cnh->ch_nsnapshots; - snapshot_cnt--; - cnh->ch_nsnapshots = snapshot_cnt; - nandfs_dirty_buf(bp, 1); - - return (0); -} - -int -nandfs_chng_cpmode(struct nandfs_node *node, struct nandfs_cpmode *ncpm) -{ - struct nandfs_device *fsdev; - uint64_t cno = ncpm->ncpm_cno; - int mode = ncpm->ncpm_mode; - int ret; - - fsdev = node->nn_nandfsdev; - VOP_LOCK(NTOV(node), LK_EXCLUSIVE); - switch (mode) { - case NANDFS_CHECKPOINT: - if (nandfs_cp_mounted(fsdev, cno)) { - ret = EBUSY; - } else - ret = nandfs_cp_clr_snapshot(node, cno); - break; - case NANDFS_SNAPSHOT: - ret = nandfs_cp_set_snapshot(node, cno); - break; - default: - ret = EINVAL; - break; - } - VOP_UNLOCK(NTOV(node), 0); - - return (ret); -} - -static void -nandfs_cpinfo_fill(struct nandfs_checkpoint *cnp, struct nandfs_cpinfo *nci) -{ - - nci->nci_flags = cnp->cp_flags; - nci->nci_pad = 0; - nci->nci_cno = cnp->cp_cno; - nci->nci_create = cnp->cp_create; - nci->nci_nblk_inc = cnp->cp_nblk_inc; - nci->nci_blocks_count = cnp->cp_blocks_count; - nci->nci_next = cnp->cp_snapshot_list.ssl_next; - DPRINTF(CPFILE, ("%s: cn:%#jx ctime:%#jx\n", - __func__, (uintmax_t)cnp->cp_cno, - (uintmax_t)cnp->cp_create)); -} - -static int -nandfs_get_cpinfo_cp(struct nandfs_node *node, uint64_t cno, - struct nandfs_cpinfo *nci, uint32_t mnmembs, uint32_t *nmembs) -{ - struct nandfs_device *fsdev; - struct buf *bp; - uint64_t blk, offset, last_cno, i; - uint16_t remaining; - int error; -#ifdef INVARIANTS - uint64_t testblk, testoffset; -#endif - - if (cno == 0) { - return (ENOENT); - } - - if (mnmembs < 1) { - return (EINVAL); - } - - fsdev = node->nn_nandfsdev; - last_cno = fsdev->nd_last_cno; - DPRINTF(CPFILE, ("%s: cno:%#jx mnmembs: %#jx last:%#jx\n", __func__, - (uintmax_t)cno, (uintmax_t)mnmembs, - (uintmax_t)fsdev->nd_last_cno)); - - /* - * do { - * get block - * read checkpoints until we hit last checkpoint, end of block or - * requested number - * } while (last read checkpoint <= last checkpoint on fs && - * read checkpoints < request number); - */ - *nmembs = i = 0; - do { - nandfs_checkpoint_blk_offset(fsdev, cno, &blk, &offset); - remaining = nandfs_checkpoint_blk_remaining(fsdev, cno, - blk, offset); - error = nandfs_bread(node, blk, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - - while (cno <= last_cno && i < mnmembs && remaining) { -#ifdef INVARIANTS - nandfs_checkpoint_blk_offset(fsdev, cno, &testblk, - &testoffset); - KASSERT(testblk == blk, ("testblk != blk")); - KASSERT(testoffset == offset, ("testoffset != offset")); -#endif - DPRINTF(CPFILE, ("%s: cno %#jx\n", __func__, - (uintmax_t)cno)); - - nandfs_cpinfo_fill((struct nandfs_checkpoint *) - (bp->b_data + offset), nci); - offset += nandfs_checkpoint_size(fsdev); - i++; - nci++; - cno++; - (*nmembs)++; - remaining--; - } - brelse(bp); - } while (cno <= last_cno && i < mnmembs); - - return (0); -} - -static int -nandfs_get_cpinfo_sp(struct nandfs_node *node, uint64_t cno, - struct nandfs_cpinfo *nci, uint32_t mnmembs, uint32_t *nmembs) -{ - struct nandfs_checkpoint *cnp; - struct nandfs_cpfile_header *cnh; - struct nandfs_device *fsdev; - struct buf *bp = NULL; - uint64_t curr = 0; - uint64_t blk, offset, curr_cno; - uint32_t flag; - int i, error; - - if (cno == 0 || cno == ~(0)) - return (ENOENT); - - fsdev = node->nn_nandfsdev; - curr_cno = cno; - - if (nmembs) - *nmembs = 0; - if (curr_cno == 1) { - /* Get list from header */ - error = nandfs_bread(node, 0, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - cnh = (struct nandfs_cpfile_header *) bp->b_data; - curr_cno = cnh->ch_snapshot_list.ssl_next; - brelse(bp); - bp = NULL; - - /* No snapshots */ - if (curr_cno == 0) - return (0); - } - - for (i = 0; i < mnmembs; i++, nci++) { - nandfs_checkpoint_blk_offset(fsdev, curr_cno, &blk, &offset); - if (i == 0 || curr != blk) { - if (bp) - brelse(bp); - error = nandfs_bread(node, blk, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (ENOENT); - } - curr = blk; - } - cnp = (struct nandfs_checkpoint *)(bp->b_data + offset); - flag = cnp->cp_flags; - if (!(flag & NANDFS_CHECKPOINT_SNAPSHOT) || - (flag & NANDFS_CHECKPOINT_INVALID)) - break; - - nci->nci_flags = flag; - nci->nci_pad = 0; - nci->nci_cno = cnp->cp_cno; - nci->nci_create = cnp->cp_create; - nci->nci_nblk_inc = cnp->cp_nblk_inc; - nci->nci_blocks_count = cnp->cp_blocks_count; - nci->nci_next = cnp->cp_snapshot_list.ssl_next; - if (nmembs) - (*nmembs)++; - - curr_cno = nci->nci_next; - if (!curr_cno) - break; - } - - brelse(bp); - - return (0); -} - -int -nandfs_get_cpinfo(struct nandfs_node *node, uint64_t cno, uint16_t flags, - struct nandfs_cpinfo *nci, uint32_t nmembs, uint32_t *nnmembs) -{ - int error; - - VOP_LOCK(NTOV(node), LK_EXCLUSIVE); - switch (flags) { - case NANDFS_CHECKPOINT: - error = nandfs_get_cpinfo_cp(node, cno, nci, nmembs, nnmembs); - break; - case NANDFS_SNAPSHOT: - error = nandfs_get_cpinfo_sp(node, cno, nci, nmembs, nnmembs); - break; - default: - error = EINVAL; - break; - } - VOP_UNLOCK(NTOV(node), 0); - - return (error); -} - -int -nandfs_get_cpinfo_ioctl(struct nandfs_node *node, struct nandfs_argv *nargv) -{ - struct nandfs_cpinfo *nci; - uint64_t cno = nargv->nv_index; - void *buf = (void *)((uintptr_t)nargv->nv_base); - uint16_t flags = nargv->nv_flags; - uint32_t nmembs = 0; - int error; - - if (nargv->nv_nmembs > NANDFS_CPINFO_MAX) - return (EINVAL); - - nci = malloc(sizeof(struct nandfs_cpinfo) * nargv->nv_nmembs, - M_NANDFSTEMP, M_WAITOK | M_ZERO); - - error = nandfs_get_cpinfo(node, cno, flags, nci, nargv->nv_nmembs, &nmembs); - - if (error == 0) { - nargv->nv_nmembs = nmembs; - error = copyout(nci, buf, - sizeof(struct nandfs_cpinfo) * nmembs); - } - - free(nci, M_NANDFSTEMP); - return (error); -} - -int -nandfs_delete_cp(struct nandfs_node *node, uint64_t start, uint64_t end) -{ - struct nandfs_checkpoint *cnp; - struct nandfs_device *fsdev; - struct buf *bp; - uint64_t cno = start, blk, offset; - int error; - - DPRINTF(CPFILE, ("%s: delete cno %jx-%jx\n", __func__, start, end)); - VOP_LOCK(NTOV(node), LK_EXCLUSIVE); - fsdev = node->nn_nandfsdev; - for (cno = start; cno <= end; cno++) { - if (!cno) - continue; - - nandfs_checkpoint_blk_offset(fsdev, cno, &blk, &offset); - error = nandfs_bread(node, blk, NOCRED, 0, &bp); - if (error) { - VOP_UNLOCK(NTOV(node), 0); - brelse(bp); - return (error); - } - - cnp = (struct nandfs_checkpoint *)(bp->b_data + offset); - if (cnp->cp_flags & NANDFS_CHECKPOINT_SNAPSHOT) { - brelse(bp); - VOP_UNLOCK(NTOV(node), 0); - return (0); - } - - cnp->cp_flags |= NANDFS_CHECKPOINT_INVALID; - - error = nandfs_dirty_buf(bp, 0); - if (error) - return (error); - } - VOP_UNLOCK(NTOV(node), 0); - - return (0); -} - -int -nandfs_make_snap(struct nandfs_device *fsdev, uint64_t *cno) -{ - struct nandfs_cpmode cpm; - int error; - - *cno = cpm.ncpm_cno = fsdev->nd_last_cno; - cpm.ncpm_mode = NANDFS_SNAPSHOT; - error = nandfs_chng_cpmode(fsdev->nd_cp_node, &cpm); - return (error); -} - -int -nandfs_delete_snap(struct nandfs_device *fsdev, uint64_t cno) -{ - struct nandfs_cpmode cpm; - int error; - - cpm.ncpm_cno = cno; - cpm.ncpm_mode = NANDFS_CHECKPOINT; - error = nandfs_chng_cpmode(fsdev->nd_cp_node, &cpm); - return (error); -} - -int nandfs_get_cpstat(struct nandfs_node *cp_node, struct nandfs_cpstat *ncp) -{ - struct nandfs_device *fsdev; - struct nandfs_cpfile_header *cnh; - struct buf *bp; - int error; - - VOP_LOCK(NTOV(cp_node), LK_EXCLUSIVE); - fsdev = cp_node->nn_nandfsdev; - - /* Get header */ - error = nandfs_bread(cp_node, 0, NOCRED, 0, &bp); - if (error) { - brelse(bp); - VOP_UNLOCK(NTOV(cp_node), 0); - return (error); - } - cnh = (struct nandfs_cpfile_header *) bp->b_data; - ncp->ncp_cno = fsdev->nd_last_cno; - ncp->ncp_ncps = cnh->ch_ncheckpoints; - ncp->ncp_nss = cnh->ch_nsnapshots; - DPRINTF(CPFILE, ("%s: cno:%#jx ncps:%#jx nss:%#jx\n", - __func__, ncp->ncp_cno, ncp->ncp_ncps, ncp->ncp_nss)); - brelse(bp); - VOP_UNLOCK(NTOV(cp_node), 0); - - return (0); -} diff --git a/sys/fs/nandfs/nandfs_dat.c b/sys/fs/nandfs/nandfs_dat.c deleted file mode 100644 index e81a117589f82..0000000000000 --- a/sys/fs/nandfs/nandfs_dat.c +++ /dev/null @@ -1,346 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/conf.h> -#include <sys/kernel.h> -#include <sys/lock.h> -#include <sys/malloc.h> -#include <sys/mount.h> -#include <sys/mutex.h> -#include <sys/namei.h> -#include <sys/sysctl.h> -#include <sys/vnode.h> -#include <sys/buf.h> -#include <sys/bio.h> - -#include <vm/vm.h> -#include <vm/vm_param.h> -#include <vm/vm_kern.h> -#include <vm/vm_page.h> - -#include <fs/nandfs/nandfs_mount.h> -#include <fs/nandfs/nandfs.h> -#include <fs/nandfs/nandfs_subr.h> - -int -nandfs_vblock_alloc(struct nandfs_device *nandfsdev, nandfs_daddr_t *vblock) -{ - struct nandfs_node *dat; - struct nandfs_mdt *mdt; - struct nandfs_alloc_request req; - struct nandfs_dat_entry *dat_entry; - uint64_t start; - uint32_t entry; - int locked, error; - - dat = nandfsdev->nd_dat_node; - mdt = &nandfsdev->nd_dat_mdt; - start = nandfsdev->nd_last_cno + 1; - - locked = NANDFS_VOP_ISLOCKED(NTOV(dat)); - if (!locked) - VOP_LOCK(NTOV(dat), LK_EXCLUSIVE); - req.entrynum = 0; - - /* Alloc vblock number */ - error = nandfs_find_free_entry(mdt, dat, &req); - if (error) { - nandfs_error("%s: cannot find free vblk entry\n", - __func__); - if (!locked) - VOP_UNLOCK(NTOV(dat), 0); - return (error); - } - - /* Read/create buffer */ - error = nandfs_get_entry_block(mdt, dat, &req, &entry, 1); - if (error) { - nandfs_error("%s: cannot get free vblk entry\n", - __func__); - nandfs_abort_entry(&req); - if (!locked) - VOP_UNLOCK(NTOV(dat), 0); - return (error); - } - - /* Fill out vblock data */ - dat_entry = (struct nandfs_dat_entry *) req.bp_entry->b_data; - dat_entry[entry].de_start = start; - dat_entry[entry].de_end = UINTMAX_MAX; - dat_entry[entry].de_blocknr = 0; - - /* Commit allocation */ - error = nandfs_alloc_entry(mdt, &req); - if (error) { - nandfs_error("%s: cannot get free vblk entry\n", - __func__); - if (!locked) - VOP_UNLOCK(NTOV(dat), 0); - return (error); - } - - /* Return allocated vblock */ - *vblock = req.entrynum; - DPRINTF(DAT, ("%s: allocated vblock %#jx\n", - __func__, (uintmax_t)*vblock)); - - if (!locked) - VOP_UNLOCK(NTOV(dat), 0); - return (error); -} - -int -nandfs_vblock_assign(struct nandfs_device *nandfsdev, nandfs_daddr_t vblock, - nandfs_lbn_t block) -{ - struct nandfs_node *dat; - struct nandfs_mdt *mdt; - struct nandfs_alloc_request req; - struct nandfs_dat_entry *dat_entry; - uint32_t entry; - int locked, error; - - dat = nandfsdev->nd_dat_node; - mdt = &nandfsdev->nd_dat_mdt; - - locked = NANDFS_VOP_ISLOCKED(NTOV(dat)); - if (!locked) - VOP_LOCK(NTOV(dat), LK_EXCLUSIVE); - req.entrynum = vblock; - - error = nandfs_get_entry_block(mdt, dat, &req, &entry, 0); - if (!error) { - dat_entry = (struct nandfs_dat_entry *) req.bp_entry->b_data; - dat_entry[entry].de_blocknr = block; - - DPRINTF(DAT, ("%s: assing vblock %jx->%jx\n", - __func__, (uintmax_t)vblock, (uintmax_t)block)); - - /* - * It is mostly called from syncer() so - * we want to force making buf dirty - */ - error = nandfs_dirty_buf(req.bp_entry, 1); - } - - if (!locked) - VOP_UNLOCK(NTOV(dat), 0); - - return (error); -} - -int -nandfs_vblock_end(struct nandfs_device *nandfsdev, nandfs_daddr_t vblock) -{ - struct nandfs_node *dat; - struct nandfs_mdt *mdt; - struct nandfs_alloc_request req; - struct nandfs_dat_entry *dat_entry; - uint64_t end; - uint32_t entry; - int locked, error; - - dat = nandfsdev->nd_dat_node; - mdt = &nandfsdev->nd_dat_mdt; - end = nandfsdev->nd_last_cno; - - locked = NANDFS_VOP_ISLOCKED(NTOV(dat)); - if (!locked) - VOP_LOCK(NTOV(dat), LK_EXCLUSIVE); - req.entrynum = vblock; - - error = nandfs_get_entry_block(mdt, dat, &req, &entry, 0); - if (!error) { - dat_entry = (struct nandfs_dat_entry *) req.bp_entry->b_data; - dat_entry[entry].de_end = end; - DPRINTF(DAT, ("%s: end vblock %#jx at checkpoint %#jx\n", - __func__, (uintmax_t)vblock, (uintmax_t)end)); - - /* - * It is mostly called from syncer() so - * we want to force making buf dirty - */ - error = nandfs_dirty_buf(req.bp_entry, 1); - } - - if (!locked) - VOP_UNLOCK(NTOV(dat), 0); - - return (error); -} - -int -nandfs_vblock_free(struct nandfs_device *nandfsdev, nandfs_daddr_t vblock) -{ - struct nandfs_node *dat; - struct nandfs_mdt *mdt; - struct nandfs_alloc_request req; - int error; - - dat = nandfsdev->nd_dat_node; - mdt = &nandfsdev->nd_dat_mdt; - - VOP_LOCK(NTOV(dat), LK_EXCLUSIVE); - req.entrynum = vblock; - - error = nandfs_find_entry(mdt, dat, &req); - if (!error) { - DPRINTF(DAT, ("%s: vblk %#jx\n", __func__, (uintmax_t)vblock)); - nandfs_free_entry(mdt, &req); - } - - VOP_UNLOCK(NTOV(dat), 0); - return (error); -} - -int -nandfs_get_dat_vinfo_ioctl(struct nandfs_device *nandfsdev, struct nandfs_argv *nargv) -{ - struct nandfs_vinfo *vinfo; - size_t size; - int error; - - if (nargv->nv_nmembs > NANDFS_VINFO_MAX) - return (EINVAL); - - size = sizeof(struct nandfs_vinfo) * nargv->nv_nmembs; - vinfo = malloc(size, M_NANDFSTEMP, M_WAITOK|M_ZERO); - - error = copyin((void *)(uintptr_t)nargv->nv_base, vinfo, size); - if (error) { - free(vinfo, M_NANDFSTEMP); - return (error); - } - - error = nandfs_get_dat_vinfo(nandfsdev, vinfo, nargv->nv_nmembs); - if (error == 0) - error = copyout(vinfo, (void *)(uintptr_t)nargv->nv_base, size); - free(vinfo, M_NANDFSTEMP); - return (error); -} - -int -nandfs_get_dat_vinfo(struct nandfs_device *nandfsdev, struct nandfs_vinfo *vinfo, - uint32_t nmembs) -{ - struct nandfs_node *dat; - struct nandfs_mdt *mdt; - struct nandfs_alloc_request req; - struct nandfs_dat_entry *dat_entry; - uint32_t i, idx; - int error = 0; - - dat = nandfsdev->nd_dat_node; - mdt = &nandfsdev->nd_dat_mdt; - - DPRINTF(DAT, ("%s: nmembs %#x\n", __func__, nmembs)); - - VOP_LOCK(NTOV(dat), LK_EXCLUSIVE); - - for (i = 0; i < nmembs; i++) { - req.entrynum = vinfo[i].nvi_vblocknr; - - error = nandfs_get_entry_block(mdt, dat,&req, &idx, 0); - if (error) - break; - - dat_entry = ((struct nandfs_dat_entry *) req.bp_entry->b_data); - vinfo[i].nvi_start = dat_entry[idx].de_start; - vinfo[i].nvi_end = dat_entry[idx].de_end; - vinfo[i].nvi_blocknr = dat_entry[idx].de_blocknr; - - DPRINTF(DAT, ("%s: vinfo: %jx[%jx-%jx]->%jx\n", - __func__, vinfo[i].nvi_vblocknr, vinfo[i].nvi_start, - vinfo[i].nvi_end, vinfo[i].nvi_blocknr)); - - brelse(req.bp_entry); - } - - VOP_UNLOCK(NTOV(dat), 0); - return (error); -} - -int -nandfs_get_dat_bdescs_ioctl(struct nandfs_device *nffsdev, - struct nandfs_argv *nargv) -{ - struct nandfs_bdesc *bd; - size_t size; - int error; - - size = nargv->nv_nmembs * sizeof(struct nandfs_bdesc); - bd = malloc(size, M_NANDFSTEMP, M_WAITOK); - error = copyin((void *)(uintptr_t)nargv->nv_base, bd, size); - if (error) { - free(bd, M_NANDFSTEMP); - return (error); - } - - error = nandfs_get_dat_bdescs(nffsdev, bd, nargv->nv_nmembs); - - if (error == 0) - error = copyout(bd, (void *)(uintptr_t)nargv->nv_base, size); - - free(bd, M_NANDFSTEMP); - return (error); -} - -int -nandfs_get_dat_bdescs(struct nandfs_device *nffsdev, struct nandfs_bdesc *bd, - uint32_t nmembs) -{ - struct nandfs_node *dat_node; - uint64_t map; - uint32_t i; - int error = 0; - - dat_node = nffsdev->nd_dat_node; - - VOP_LOCK(NTOV(dat_node), LK_EXCLUSIVE); - - for (i = 0; i < nmembs; i++) { - DPRINTF(CLEAN, - ("%s: bd ino:%#jx oblk:%#jx blocknr:%#jx off:%#jx\n", - __func__, (uintmax_t)bd[i].bd_ino, - (uintmax_t)bd[i].bd_oblocknr, (uintmax_t)bd[i].bd_blocknr, - (uintmax_t)bd[i].bd_offset)); - - error = nandfs_bmap_lookup(dat_node, bd[i].bd_offset, &map); - if (error) - break; - bd[i].bd_blocknr = map; - } - - VOP_UNLOCK(NTOV(dat_node), 0); - return (error); -} diff --git a/sys/fs/nandfs/nandfs_dir.c b/sys/fs/nandfs/nandfs_dir.c deleted file mode 100644 index 404edecfaa08f..0000000000000 --- a/sys/fs/nandfs/nandfs_dir.c +++ /dev/null @@ -1,316 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf - * Copyright (c) 2008, 2009 Reinoud Zandijk - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * From: NetBSD: nilfs_subr.c,v 1.4 2009/07/29 17:06:57 reinoud - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/namei.h> -#include <sys/kernel.h> -#include <sys/stat.h> -#include <sys/buf.h> -#include <sys/bio.h> -#include <sys/proc.h> -#include <sys/mount.h> -#include <sys/vnode.h> -#include <sys/signalvar.h> -#include <sys/malloc.h> -#include <sys/dirent.h> -#include <sys/lockf.h> - -#include <vm/vm.h> -#include <vm/vm_extern.h> - -#include "nandfs_mount.h" -#include "nandfs.h" -#include "nandfs_subr.h" - -int -nandfs_add_dirent(struct vnode *dvp, uint64_t ino, char *nameptr, long namelen, - uint8_t type) -{ - struct nandfs_node *dir_node = VTON(dvp); - struct nandfs_dir_entry *dirent, *pdirent; - uint32_t blocksize = dir_node->nn_nandfsdev->nd_blocksize; - uint64_t filesize = dir_node->nn_inode.i_size; - uint64_t inode_blks = dir_node->nn_inode.i_blocks; - uint32_t off, rest; - uint8_t *pos; - struct buf *bp; - int error; - - pdirent = NULL; - bp = NULL; - if (inode_blks) { - error = nandfs_bread(dir_node, inode_blks - 1, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - - pos = bp->b_data; - off = 0; - while (off < blocksize) { - pdirent = (struct nandfs_dir_entry *) (pos + off); - if (!pdirent->rec_len) { - pdirent = NULL; - break; - } - off += pdirent->rec_len; - } - - if (pdirent) - rest = pdirent->rec_len - - NANDFS_DIR_REC_LEN(pdirent->name_len); - else - rest = blocksize; - - if (rest < NANDFS_DIR_REC_LEN(namelen)) { - /* Do not update pdirent as new block is created */ - pdirent = NULL; - brelse(bp); - /* Set to NULL to create new */ - bp = NULL; - filesize += rest; - } - } - - /* If no bp found create new */ - if (!bp) { - error = nandfs_bcreate(dir_node, inode_blks, NOCRED, 0, &bp); - if (error) - return (error); - off = 0; - pos = bp->b_data; - } - - /* Modify pdirent if exists */ - if (pdirent) { - DPRINTF(LOOKUP, ("modify pdirent %p\n", pdirent)); - /* modify last de */ - off -= pdirent->rec_len; - pdirent->rec_len = - NANDFS_DIR_REC_LEN(pdirent->name_len); - off += pdirent->rec_len; - } - - /* Create new dirent */ - dirent = (struct nandfs_dir_entry *) (pos + off); - dirent->rec_len = blocksize - off; - dirent->inode = ino; - dirent->name_len = namelen; - memset(dirent->name, 0, NANDFS_DIR_NAME_LEN(namelen)); - memcpy(dirent->name, nameptr, namelen); - dirent->file_type = type; - - filesize += NANDFS_DIR_REC_LEN(dirent->name_len); - - DPRINTF(LOOKUP, ("create dir_entry '%.*s' at %p with size %x " - "new filesize: %jx\n", - (int)namelen, dirent->name, dirent, dirent->rec_len, - (uintmax_t)filesize)); - - error = nandfs_dirty_buf(bp, 0); - if (error) - return (error); - - dir_node->nn_inode.i_size = filesize; - dir_node->nn_flags |= IN_CHANGE | IN_UPDATE; - vnode_pager_setsize(dvp, filesize); - - return (0); -} - -int -nandfs_remove_dirent(struct vnode *dvp, struct nandfs_node *node, - struct componentname *cnp) -{ - struct nandfs_node *dir_node; - struct nandfs_dir_entry *dirent, *pdirent; - struct buf *bp; - uint64_t filesize, blocknr, ino, offset; - uint32_t blocksize, limit, off; - uint16_t newsize; - uint8_t *pos; - int error, found; - - dir_node = VTON(dvp); - filesize = dir_node->nn_inode.i_size; - if (!filesize) - return (0); - - if (node) { - offset = node->nn_diroff; - ino = node->nn_ino; - } else { - offset = dir_node->nn_diroff; - ino = NANDFS_WHT_INO; - } - - dirent = pdirent = NULL; - blocksize = dir_node->nn_nandfsdev->nd_blocksize; - blocknr = offset / blocksize; - - DPRINTF(LOOKUP, ("rm direntry dvp %p node %p ino %#jx at off %#jx\n", - dvp, node, (uintmax_t)ino, (uintmax_t)offset)); - - error = nandfs_bread(dir_node, blocknr, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - - pos = bp->b_data; - off = 0; - found = 0; - limit = offset % blocksize; - pdirent = (struct nandfs_dir_entry *) bp->b_data; - while (off <= limit) { - dirent = (struct nandfs_dir_entry *) (pos + off); - - if ((off == limit) && - (dirent->inode == ino)) { - found = 1; - break; - } - if (dirent->inode != 0) - pdirent = dirent; - off += dirent->rec_len; - } - - if (!found) { - nandfs_error("cannot find entry to remove"); - brelse(bp); - return (error); - } - DPRINTF(LOOKUP, - ("rm dirent ino %#jx at %#x with size %#x\n", - (uintmax_t)dirent->inode, off, dirent->rec_len)); - - newsize = (uintptr_t)dirent - (uintptr_t)pdirent; - newsize += dirent->rec_len; - pdirent->rec_len = newsize; - dirent->inode = 0; - error = nandfs_dirty_buf(bp, 0); - if (error) - return (error); - - dir_node->nn_flags |= IN_CHANGE | IN_UPDATE; - /* If last one modify filesize */ - if ((offset + NANDFS_DIR_REC_LEN(dirent->name_len)) == filesize) { - filesize = blocknr * blocksize + - ((uintptr_t)pdirent - (uintptr_t)pos) + - NANDFS_DIR_REC_LEN(pdirent->name_len); - dir_node->nn_inode.i_size = filesize; - } - - return (0); -} - -int -nandfs_update_parent_dir(struct vnode *dvp, uint64_t newparent) -{ - struct nandfs_dir_entry *dirent; - struct nandfs_node *dir_node; - struct buf *bp; - int error; - - dir_node = VTON(dvp); - error = nandfs_bread(dir_node, 0, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - dirent = (struct nandfs_dir_entry *)bp->b_data; - dirent->inode = newparent; - error = nandfs_dirty_buf(bp, 0); - if (error) - return (error); - - return (0); -} - -int -nandfs_update_dirent(struct vnode *dvp, struct nandfs_node *fnode, - struct nandfs_node *tnode) -{ - struct nandfs_node *dir_node; - struct nandfs_dir_entry *dirent; - struct buf *bp; - uint64_t file_size, blocknr; - uint32_t blocksize, off; - uint8_t *pos; - int error; - - dir_node = VTON(dvp); - file_size = dir_node->nn_inode.i_size; - if (!file_size) - return (0); - - DPRINTF(LOOKUP, - ("chg direntry dvp %p ino %#jx to in %#jx at off %#jx\n", - dvp, (uintmax_t)tnode->nn_ino, (uintmax_t)fnode->nn_ino, - (uintmax_t)tnode->nn_diroff)); - - blocksize = dir_node->nn_nandfsdev->nd_blocksize; - blocknr = tnode->nn_diroff / blocksize; - off = tnode->nn_diroff % blocksize; - error = nandfs_bread(dir_node, blocknr, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - - pos = bp->b_data; - dirent = (struct nandfs_dir_entry *) (pos + off); - KASSERT((dirent->inode == tnode->nn_ino), - ("direntry mismatch")); - - dirent->inode = fnode->nn_ino; - error = nandfs_dirty_buf(bp, 0); - if (error) - return (error); - - return (0); -} - -int -nandfs_init_dir(struct vnode *dvp, uint64_t ino, uint64_t parent_ino) -{ - - if (nandfs_add_dirent(dvp, parent_ino, "..", 2, DT_DIR) || - nandfs_add_dirent(dvp, ino, ".", 1, DT_DIR)) { - nandfs_error("%s: cannot initialize dir ino:%jd(pino:%jd)\n", - __func__, ino, parent_ino); - return (-1); - } - return (0); -} diff --git a/sys/fs/nandfs/nandfs_fs.h b/sys/fs/nandfs/nandfs_fs.h deleted file mode 100644 index 9cb440ebcb906..0000000000000 --- a/sys/fs/nandfs/nandfs_fs.h +++ /dev/null @@ -1,567 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf - * Copyright (c) 2008, 2009 Reinoud Zandijk - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Original definitions written by Koji Sato <koji@osrg.net> - * and Ryusuke Konishi <ryusuke@osrg.net> - * From: NetBSD: nandfs_fs.h,v 1.1 2009/07/18 16:31:42 reinoud - * - * $FreeBSD$ - */ - -#ifndef _NANDFS_FS_H -#define _NANDFS_FS_H - -#include <sys/uuid.h> - -#define MNINDIR(fsdev) ((fsdev)->nd_blocksize / sizeof(nandfs_daddr_t)) - -/* - * Inode structure. There are a few dedicated inode numbers that are - * defined here first. - */ -#define NANDFS_WHT_INO 1 /* Whiteout ino */ -#define NANDFS_ROOT_INO 2 /* Root file inode */ -#define NANDFS_DAT_INO 3 /* DAT file */ -#define NANDFS_CPFILE_INO 4 /* checkpoint file */ -#define NANDFS_SUFILE_INO 5 /* segment usage file */ -#define NANDFS_IFILE_INO 6 /* ifile */ -#define NANDFS_GC_INO 7 /* Cleanerd node */ -#define NANDFS_ATIME_INO 8 /* Atime file (reserved) */ -#define NANDFS_XATTR_INO 9 /* Xattribute file (reserved) */ -#define NANDFS_SKETCH_INO 10 /* Sketch file (obsolete) */ -#define NANDFS_USER_INO 11 /* First user's file inode number */ - -#define NANDFS_SYS_NODE(ino) \ - (((ino) >= NANDFS_DAT_INO) && ((ino) <= NANDFS_GC_INO)) - -#define NANDFS_NDADDR 12 /* Direct addresses in inode. */ -#define NANDFS_NIADDR 3 /* Indirect addresses in inode. */ - -typedef int64_t nandfs_daddr_t; -typedef int64_t nandfs_lbn_t; - -struct nandfs_inode { - uint64_t i_blocks; /* 0: size in device blocks */ - uint64_t i_size; /* 8: size in bytes */ - uint64_t i_ctime; /* 16: creation time in seconds */ - uint64_t i_mtime; /* 24: modification time in seconds part*/ - uint32_t i_ctime_nsec; /* 32: creation time nanoseconds part */ - uint32_t i_mtime_nsec; /* 36: modification time in nanoseconds */ - uint32_t i_uid; /* 40: user id */ - uint32_t i_gid; /* 44: group id */ - uint16_t i_mode; /* 48: file mode */ - uint16_t i_links_count; /* 50: number of references to the inode*/ - uint32_t i_flags; /* 52: NANDFS_*_FL flags */ - nandfs_daddr_t i_special; /* 56: special */ - nandfs_daddr_t i_db[NANDFS_NDADDR]; /* 64: Direct disk blocks. */ - nandfs_daddr_t i_ib[NANDFS_NIADDR]; /* 160: Indirect disk blocks. */ - uint64_t i_xattr; /* 184: reserved for extended attributes*/ - uint32_t i_generation; /* 192: file generation for NFS */ - uint32_t i_pad[15]; /* 196: make it 64 bits aligned */ -}; - -#ifdef _KERNEL -CTASSERT(sizeof(struct nandfs_inode) == 256); -#endif - -/* - * Each checkpoint/snapshot has a super root. - * - * The super root holds the inodes of the three system files: `dat', `cp' and - * 'su' files. All other FS state is defined by those. - * - * It is CRC checksum'ed and time stamped. - */ - -struct nandfs_super_root { - uint32_t sr_sum; /* check-sum */ - uint16_t sr_bytes; /* byte count of this structure */ - uint16_t sr_flags; /* reserved for flags */ - uint64_t sr_nongc_ctime; /* timestamp, not for cleaner(?) */ - struct nandfs_inode sr_dat; /* DAT, virt->phys translation inode */ - struct nandfs_inode sr_cpfile; /* CP, checkpoints inode */ - struct nandfs_inode sr_sufile; /* SU, segment usage inode */ -}; - -#define NANDFS_SR_MDT_OFFSET(inode_size, i) \ - ((uint32_t)&((struct nandfs_super_root *)0)->sr_dat + \ - (inode_size) * (i)) - -#define NANDFS_SR_DAT_OFFSET(inode_size) NANDFS_SR_MDT_OFFSET(inode_size, 0) -#define NANDFS_SR_CPFILE_OFFSET(inode_size) NANDFS_SR_MDT_OFFSET(inode_size, 1) -#define NANDFS_SR_SUFILE_OFFSET(inode_size) NANDFS_SR_MDT_OFFSET(inode_size, 2) -#define NANDFS_SR_BYTES (sizeof(struct nandfs_super_root)) - -/* - * The superblock describes the basic structure and mount history. It also - * records some sizes of structures found on the disc for sanity checks. - * - * The superblock is stored at two places: NANDFS_SB_OFFSET_BYTES and - * NANDFS_SB2_OFFSET_BYTES. - */ - -/* File system states stored on media in superblock's sbp->s_state */ -#define NANDFS_VALID_FS 0x0001 /* cleanly unmounted and all is ok */ -#define NANDFS_ERROR_FS 0x0002 /* there were errors detected, fsck */ -#define NANDFS_RESIZE_FS 0x0004 /* resize required, XXX unknown flag*/ -#define NANDFS_MOUNT_STATE_BITS "\20\1VALID_FS\2ERROR_FS\3RESIZE_FS" - -/* - * Brief description of control structures: - * - * NANDFS_NFSAREAS first blocks contain fsdata and some amount of super blocks. - * Simple round-robin policy is used in order to choose which block will - * contain new super block. - * - * Simple case with 2 blocks: - * 1: fsdata sblock1 [sblock3 [sblock5 ..]] - * 2: fsdata sblock2 [sblock4 [sblock6 ..]] - */ -struct nandfs_fsdata { - uint16_t f_magic; - uint16_t f_bytes; - - uint32_t f_sum; /* checksum of fsdata */ - uint32_t f_rev_level; /* major disk format revision */ - - uint64_t f_ctime; /* creation time (execution time - of newfs) */ - /* Block size represented as: blocksize = 1 << (f_log_block_size + 10) */ - uint32_t f_log_block_size; - - uint16_t f_inode_size; /* size of an inode */ - uint16_t f_dat_entry_size; /* size of a dat entry */ - uint16_t f_checkpoint_size; /* size of a checkpoint */ - uint16_t f_segment_usage_size; /* size of a segment usage */ - - uint16_t f_sbbytes; /* byte count of CRC calculation - for super blocks. s_reserved - is excluded! */ - - uint16_t f_errors; /* behaviour on detecting errors */ - - uint32_t f_erasesize; - uint64_t f_nsegments; /* number of segm. in filesystem */ - nandfs_daddr_t f_first_data_block; /* 1st seg disk block number */ - uint32_t f_blocks_per_segment; /* number of blocks per segment */ - uint32_t f_r_segments_percentage; /* reserved segments percentage */ - - struct uuid f_uuid; /* 128-bit uuid for volume */ - char f_volume_name[16]; /* volume name */ - uint32_t f_pad[104]; -} __packed; - -#ifdef _KERNEL -CTASSERT(sizeof(struct nandfs_fsdata) == 512); -#endif - -struct nandfs_super_block { - uint16_t s_magic; /* magic value for identification */ - - uint32_t s_sum; /* check sum of super block */ - - uint64_t s_last_cno; /* last checkpoint number */ - uint64_t s_last_pseg; /* addr part. segm. written last */ - uint64_t s_last_seq; /* seq.number of seg written last */ - uint64_t s_free_blocks_count; /* free blocks count */ - - uint64_t s_mtime; /* mount time */ - uint64_t s_wtime; /* write time */ - uint16_t s_state; /* file system state */ - - char s_last_mounted[64]; /* directory where last mounted */ - - uint32_t s_c_interval; /* commit interval of segment */ - uint32_t s_c_block_max; /* threshold of data amount for - the segment construction */ - uint32_t s_reserved[32]; /* padding to end of the block */ -} __packed; - -#ifdef _KERNEL -CTASSERT(sizeof(struct nandfs_super_block) == 256); -#endif - -#define NANDFS_FSDATA_MAGIC 0xf8da -#define NANDFS_SUPER_MAGIC 0x8008 - -#define NANDFS_NFSAREAS 4 -#define NANDFS_DATA_OFFSET_BYTES(esize) (NANDFS_NFSAREAS * (esize)) - -#define NANDFS_SBLOCK_OFFSET_BYTES (sizeof(struct nandfs_fsdata)) - -#define NANDFS_DEF_BLOCKSIZE 4096 -#define NANDFS_MIN_BLOCKSIZE 512 - -#define NANDFS_DEF_ERASESIZE (2 << 16) - -#define NANDFS_MIN_SEGSIZE NANDFS_DEF_ERASESIZE - -#define NANDFS_CURRENT_REV 9 /* current major revision */ - -#define NANDFS_FSDATA_CRC_BYTES offsetof(struct nandfs_fsdata, f_pad) -/* Bytes count of super_block for CRC-calculation */ -#define NANDFS_SB_BYTES offsetof(struct nandfs_super_block, s_reserved) - -/* Maximal count of links to a file */ -#define NANDFS_LINK_MAX 32000 - -/* - * Structure of a directory entry. - * - * Note that they can't span blocks; the rec_len fills out. - */ - -#define NANDFS_NAME_LEN 255 -struct nandfs_dir_entry { - uint64_t inode; /* inode number */ - uint16_t rec_len; /* directory entry length */ - uint8_t name_len; /* name length */ - uint8_t file_type; - char name[NANDFS_NAME_LEN]; /* file name */ - char pad; -}; - -/* - * NANDFS_DIR_PAD defines the directory entries boundaries - * - * NOTE: It must be a multiple of 8 - */ -#define NANDFS_DIR_PAD 8 -#define NANDFS_DIR_ROUND (NANDFS_DIR_PAD - 1) -#define NANDFS_DIR_NAME_OFFSET (offsetof(struct nandfs_dir_entry, name)) -#define NANDFS_DIR_REC_LEN(name_len) \ - (((name_len) + NANDFS_DIR_NAME_OFFSET + NANDFS_DIR_ROUND) \ - & ~NANDFS_DIR_ROUND) -#define NANDFS_DIR_NAME_LEN(name_len) \ - (NANDFS_DIR_REC_LEN(name_len) - NANDFS_DIR_NAME_OFFSET) - -/* - * NiLFS/NANDFS devides the disc into fixed length segments. Each segment is - * filled with one or more partial segments of variable lengths. - * - * Each partial segment has a segment summary header followed by updates of - * files and optionally a super root. - */ - -/* - * Virtual to physical block translation information. For data blocks it maps - * logical block number bi_blkoff to virtual block nr bi_vblocknr. For non - * datablocks it is the virtual block number assigned to an indirect block - * and has no bi_blkoff. The physical block number is the next - * available data block in the partial segment after all the binfo's. - */ -struct nandfs_binfo_v { - uint64_t bi_ino; /* file's inode */ - uint64_t bi_vblocknr; /* assigned virtual block number */ - uint64_t bi_blkoff; /* for file's logical block number */ -}; - -/* - * DAT allocation. For data blocks just the logical block number that maps on - * the next available data block in the partial segment after the binfo's. - */ -struct nandfs_binfo_dat { - uint64_t bi_ino; - uint64_t bi_blkoff; /* DAT file's logical block number */ - uint8_t bi_level; /* whether this is meta block */ - uint8_t bi_pad[7]; -}; - -#ifdef _KERNEL -CTASSERT(sizeof(struct nandfs_binfo_v) == sizeof(struct nandfs_binfo_dat)); -#endif - -/* Convenience union for both types of binfo's */ -union nandfs_binfo { - struct nandfs_binfo_v bi_v; - struct nandfs_binfo_dat bi_dat; -}; - -/* Indirect buffers path */ -struct nandfs_indir { - nandfs_daddr_t in_lbn; - int in_off; -}; - -/* The (partial) segment summary */ -struct nandfs_segment_summary { - uint32_t ss_datasum; /* CRC of complete data block */ - uint32_t ss_sumsum; /* CRC of segment summary only */ - uint32_t ss_magic; /* magic to identify segment summary */ - uint16_t ss_bytes; /* size of segment summary structure */ - uint16_t ss_flags; /* NANDFS_SS_* flags */ - uint64_t ss_seq; /* sequence number of this segm. sum */ - uint64_t ss_create; /* creation timestamp in seconds */ - uint64_t ss_next; /* blocknumber of next segment */ - uint32_t ss_nblocks; /* number of blocks used by summary */ - uint32_t ss_nbinfos; /* number of binfo structures */ - uint32_t ss_sumbytes; /* total size of segment summary */ - uint32_t ss_pad; - /* stream of binfo structures */ -}; - -#define NANDFS_SEGSUM_MAGIC 0x8e680011 /* segment summary magic number */ - -/* Segment summary flags */ -#define NANDFS_SS_LOGBGN 0x0001 /* begins a logical segment */ -#define NANDFS_SS_LOGEND 0x0002 /* ends a logical segment */ -#define NANDFS_SS_SR 0x0004 /* has super root */ -#define NANDFS_SS_SYNDT 0x0008 /* includes data only updates */ -#define NANDFS_SS_GC 0x0010 /* segment written for cleaner operation */ -#define NANDFS_SS_FLAG_BITS "\20\1LOGBGN\2LOGEND\3SR\4SYNDT\5GC" - -/* Segment summary constrains */ -#define NANDFS_SEG_MIN_BLOCKS 16 /* minimum number of blocks in a - full segment */ -#define NANDFS_PSEG_MIN_BLOCKS 2 /* minimum number of blocks in a - partial segment */ -#define NANDFS_MIN_NRSVSEGS 8 /* minimum number of reserved - segments */ - -/* - * Structure of DAT/inode file. - * - * A DAT file is divided into groups. The maximum number of groups is the - * number of block group descriptors that fit into one block; this descriptor - * only gives the number of free entries in the associated group. - * - * Each group has a block sized bitmap indicating if an entry is taken or - * empty. Each bit stands for a DAT entry. - * - * The inode file has exactly the same format only the entries are inode - * entries. - */ - -struct nandfs_block_group_desc { - uint32_t bg_nfrees; /* num. free entries in block group */ -}; - -/* DAT entry in a super root's DAT file */ -struct nandfs_dat_entry { - uint64_t de_blocknr; /* block number */ - uint64_t de_start; /* valid from checkpoint */ - uint64_t de_end; /* valid till checkpoint */ - uint64_t de_rsv; /* reserved for future use */ -}; - -/* - * Structure of CP file. - * - * A snapshot is just a checkpoint only it's protected against removal by the - * cleaner. The snapshots are kept on a double linked list of checkpoints. - */ -struct nandfs_snapshot_list { - uint64_t ssl_next; /* checkpoint nr. forward */ - uint64_t ssl_prev; /* checkpoint nr. back */ -}; - -/* Checkpoint entry structure */ -struct nandfs_checkpoint { - uint32_t cp_flags; /* NANDFS_CHECKPOINT_* flags */ - uint32_t cp_checkpoints_count; /* ZERO, not used anymore? */ - struct nandfs_snapshot_list cp_snapshot_list; /* list of snapshots */ - uint64_t cp_cno; /* checkpoint number */ - uint64_t cp_create; /* creation timestamp */ - uint64_t cp_nblk_inc; /* number of blocks incremented */ - uint64_t cp_blocks_count; /* reserved (might be deleted) */ - struct nandfs_inode cp_ifile_inode; /* inode file inode */ -}; - -/* Checkpoint flags */ -#define NANDFS_CHECKPOINT_SNAPSHOT 1 -#define NANDFS_CHECKPOINT_INVALID 2 -#define NANDFS_CHECKPOINT_SKETCH 4 -#define NANDFS_CHECKPOINT_MINOR 8 -#define NANDFS_CHECKPOINT_BITS "\20\1SNAPSHOT\2INVALID\3SKETCH\4MINOR" - -/* Header of the checkpoint file */ -struct nandfs_cpfile_header { - uint64_t ch_ncheckpoints; /* number of checkpoints */ - uint64_t ch_nsnapshots; /* number of snapshots */ - struct nandfs_snapshot_list ch_snapshot_list; /* snapshot list */ -}; - -#define NANDFS_CPFILE_FIRST_CHECKPOINT_OFFSET \ - ((sizeof(struct nandfs_cpfile_header) + \ - sizeof(struct nandfs_checkpoint) - 1) / \ - sizeof(struct nandfs_checkpoint)) - - -#define NANDFS_NOSEGMENT 0xffffffff - -/* - * Structure of SU file. - * - * The segment usage file sums up how each of the segments are used. They are - * indexed by their segment number. - */ - -/* Segment usage entry */ -struct nandfs_segment_usage { - uint64_t su_lastmod; /* last modified timestamp */ - uint32_t su_nblocks; /* number of blocks in segment */ - uint32_t su_flags; /* NANDFS_SEGMENT_USAGE_* flags */ -}; - -/* Segment usage flag */ -#define NANDFS_SEGMENT_USAGE_ACTIVE 1 -#define NANDFS_SEGMENT_USAGE_DIRTY 2 -#define NANDFS_SEGMENT_USAGE_ERROR 4 -#define NANDFS_SEGMENT_USAGE_GC 8 -#define NANDFS_SEGMENT_USAGE_BITS "\20\1ACTIVE\2DIRTY\3ERROR" - -/* Header of the segment usage file */ -struct nandfs_sufile_header { - uint64_t sh_ncleansegs; /* number of segments marked clean */ - uint64_t sh_ndirtysegs; /* number of segments marked dirty */ - uint64_t sh_last_alloc; /* last allocated segment number */ -}; - -#define NANDFS_SUFILE_FIRST_SEGMENT_USAGE_OFFSET \ - ((sizeof(struct nandfs_sufile_header) + \ - sizeof(struct nandfs_segment_usage) - 1) / \ - sizeof(struct nandfs_segment_usage)) - -struct nandfs_seg_stat { - uint64_t nss_nsegs; - uint64_t nss_ncleansegs; - uint64_t nss_ndirtysegs; - uint64_t nss_ctime; - uint64_t nss_nongc_ctime; - uint64_t nss_prot_seq; -}; - -enum { - NANDFS_CHECKPOINT, - NANDFS_SNAPSHOT -}; - -#define NANDFS_CPINFO_MAX 512 - -struct nandfs_cpinfo { - uint32_t nci_flags; - uint32_t nci_pad; - uint64_t nci_cno; - uint64_t nci_create; - uint64_t nci_nblk_inc; - uint64_t nci_blocks_count; - uint64_t nci_next; -}; - -#define NANDFS_SEGMENTS_MAX 512 - -struct nandfs_suinfo { - uint64_t nsi_num; - uint64_t nsi_lastmod; - uint32_t nsi_blocks; - uint32_t nsi_flags; -}; - -#define NANDFS_VINFO_MAX 512 - -struct nandfs_vinfo { - uint64_t nvi_ino; - uint64_t nvi_vblocknr; - uint64_t nvi_start; - uint64_t nvi_end; - uint64_t nvi_blocknr; - int nvi_alive; -}; - -struct nandfs_cpmode { - uint64_t ncpm_cno; - uint32_t ncpm_mode; - uint32_t ncpm_pad; -}; - -struct nandfs_argv { - uint64_t nv_base; - uint32_t nv_nmembs; - uint16_t nv_size; - uint16_t nv_flags; - uint64_t nv_index; -}; - -struct nandfs_cpstat { - uint64_t ncp_cno; - uint64_t ncp_ncps; - uint64_t ncp_nss; -}; - -struct nandfs_period { - uint64_t p_start; - uint64_t p_end; -}; - -struct nandfs_vdesc { - uint64_t vd_ino; - uint64_t vd_cno; - uint64_t vd_vblocknr; - struct nandfs_period vd_period; - uint64_t vd_blocknr; - uint64_t vd_offset; - uint32_t vd_flags; - uint32_t vd_pad; -}; - -struct nandfs_bdesc { - uint64_t bd_ino; - uint64_t bd_oblocknr; - uint64_t bd_blocknr; - uint64_t bd_offset; - uint32_t bd_level; - uint32_t bd_alive; -}; - -#ifndef _KERNEL -#ifndef MNAMELEN -#define MNAMELEN 1024 -#endif -#endif - -struct nandfs_fsinfo { - struct nandfs_fsdata fs_fsdata; - struct nandfs_super_block fs_super; - char fs_dev[MNAMELEN]; -}; - -#define NANDFS_MAX_MOUNTS 65535 - -#define NANDFS_IOCTL_GET_SUSTAT _IOR('N', 100, struct nandfs_seg_stat) -#define NANDFS_IOCTL_CHANGE_CPMODE _IOWR('N', 101, struct nandfs_cpmode) -#define NANDFS_IOCTL_GET_CPINFO _IOWR('N', 102, struct nandfs_argv) -#define NANDFS_IOCTL_DELETE_CP _IOWR('N', 103, uint64_t[2]) -#define NANDFS_IOCTL_GET_CPSTAT _IOR('N', 104, struct nandfs_cpstat) -#define NANDFS_IOCTL_GET_SUINFO _IOWR('N', 105, struct nandfs_argv) -#define NANDFS_IOCTL_GET_VINFO _IOWR('N', 106, struct nandfs_argv) -#define NANDFS_IOCTL_GET_BDESCS _IOWR('N', 107, struct nandfs_argv) -#define NANDFS_IOCTL_GET_FSINFO _IOR('N', 108, struct nandfs_fsinfo) -#define NANDFS_IOCTL_MAKE_SNAP _IOWR('N', 109, uint64_t) -#define NANDFS_IOCTL_DELETE_SNAP _IOWR('N', 110, uint64_t) -#define NANDFS_IOCTL_SYNC _IOWR('N', 111, uint64_t) - -#endif /* _NANDFS_FS_H */ diff --git a/sys/fs/nandfs/nandfs_ifile.c b/sys/fs/nandfs/nandfs_ifile.c deleted file mode 100644 index 2c10bbac1ffea..0000000000000 --- a/sys/fs/nandfs/nandfs_ifile.c +++ /dev/null @@ -1,215 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/conf.h> -#include <sys/kernel.h> -#include <sys/lock.h> -#include <sys/malloc.h> -#include <sys/mount.h> -#include <sys/mutex.h> -#include <sys/namei.h> -#include <sys/sysctl.h> -#include <sys/vnode.h> -#include <sys/buf.h> -#include <sys/bio.h> - -#include <vm/vm.h> -#include <vm/vm_param.h> -#include <vm/vm_kern.h> -#include <vm/vm_page.h> - -#include <fs/nandfs/nandfs_mount.h> -#include <fs/nandfs/nandfs.h> -#include <fs/nandfs/nandfs_subr.h> - -int -nandfs_node_create(struct nandfsmount *nmp, struct nandfs_node **node, - uint16_t mode) -{ - struct nandfs_alloc_request req; - struct nandfs_device *nandfsdev; - struct nandfs_mdt *mdt; - struct nandfs_node *ifile; - struct nandfs_inode *inode; - struct vnode *vp; - uint32_t entry; - int error = 0; - - nandfsdev = nmp->nm_nandfsdev; - mdt = &nandfsdev->nd_ifile_mdt; - ifile = nmp->nm_ifile_node; - vp = NTOV(ifile); - - VOP_LOCK(vp, LK_EXCLUSIVE); - /* Allocate new inode in ifile */ - req.entrynum = nandfsdev->nd_last_ino + 1; - error = nandfs_find_free_entry(mdt, ifile, &req); - if (error) { - VOP_UNLOCK(vp, 0); - return (error); - } - - error = nandfs_get_entry_block(mdt, ifile, &req, &entry, 1); - if (error) { - VOP_UNLOCK(vp, 0); - return (error); - } - - /* Inode initialization */ - inode = ((struct nandfs_inode *) req.bp_entry->b_data) + entry; - nandfs_inode_init(inode, mode); - - error = nandfs_alloc_entry(mdt, &req); - if (error) { - VOP_UNLOCK(vp, 0); - return (error); - } - - VOP_UNLOCK(vp, 0); - - nandfsdev->nd_last_ino = req.entrynum; - error = nandfs_get_node(nmp, req.entrynum, node); - DPRINTF(IFILE, ("%s: node: %p ino: %#jx\n", - __func__, node, (uintmax_t)((*node)->nn_ino))); - - return (error); -} - -int -nandfs_node_destroy(struct nandfs_node *node) -{ - struct nandfs_alloc_request req; - struct nandfsmount *nmp; - struct nandfs_mdt *mdt; - struct nandfs_node *ifile; - struct vnode *vp; - int error = 0; - - nmp = node->nn_nmp; - req.entrynum = node->nn_ino; - mdt = &nmp->nm_nandfsdev->nd_ifile_mdt; - ifile = nmp->nm_ifile_node; - vp = NTOV(ifile); - - DPRINTF(IFILE, ("%s: destroy node: %p ino: %#jx\n", - __func__, node, (uintmax_t)node->nn_ino)); - VOP_LOCK(vp, LK_EXCLUSIVE); - - error = nandfs_find_entry(mdt, ifile, &req); - if (error) { - nandfs_error("%s: finding entry error:%d node %p(%jx)", - __func__, error, node, node->nn_ino); - VOP_UNLOCK(vp, 0); - return (error); - } - - nandfs_inode_destroy(&node->nn_inode); - - error = nandfs_free_entry(mdt, &req); - if (error) { - nandfs_error("%s: freing entry error:%d node %p(%jx)", - __func__, error, node, node->nn_ino); - VOP_UNLOCK(vp, 0); - return (error); - } - - VOP_UNLOCK(vp, 0); - DPRINTF(IFILE, ("%s: freed node %p ino %#jx\n", - __func__, node, (uintmax_t)node->nn_ino)); - return (error); -} - -int -nandfs_node_update(struct nandfs_node *node) -{ - struct nandfs_alloc_request req; - struct nandfsmount *nmp; - struct nandfs_mdt *mdt; - struct nandfs_node *ifile; - struct nandfs_inode *inode; - uint32_t index; - int error = 0; - - nmp = node->nn_nmp; - ifile = nmp->nm_ifile_node; - ASSERT_VOP_LOCKED(NTOV(ifile), __func__); - - req.entrynum = node->nn_ino; - mdt = &nmp->nm_nandfsdev->nd_ifile_mdt; - - DPRINTF(IFILE, ("%s: node:%p ino:%#jx\n", - __func__, &node->nn_inode, (uintmax_t)node->nn_ino)); - - error = nandfs_get_entry_block(mdt, ifile, &req, &index, 0); - if (error) { - printf("nandfs_get_entry_block returned with ERROR=%d\n", - error); - return (error); - } - - inode = ((struct nandfs_inode *) req.bp_entry->b_data) + index; - memcpy(inode, &node->nn_inode, sizeof(*inode)); - error = nandfs_dirty_buf(req.bp_entry, 0); - - return (error); -} - -int -nandfs_get_node_entry(struct nandfsmount *nmp, struct nandfs_inode **inode, - uint64_t ino, struct buf **bp) -{ - struct nandfs_alloc_request req; - struct nandfs_mdt *mdt; - struct nandfs_node *ifile; - struct vnode *vp; - uint32_t index; - int error = 0; - - req.entrynum = ino; - mdt = &nmp->nm_nandfsdev->nd_ifile_mdt; - ifile = nmp->nm_ifile_node; - vp = NTOV(ifile); - - VOP_LOCK(vp, LK_EXCLUSIVE); - error = nandfs_get_entry_block(mdt, ifile, &req, &index, 0); - if (error) { - VOP_UNLOCK(vp, 0); - return (error); - } - - *inode = ((struct nandfs_inode *) req.bp_entry->b_data) + index; - *bp = req.bp_entry; - VOP_UNLOCK(vp, 0); - return (0); -} - diff --git a/sys/fs/nandfs/nandfs_mount.h b/sys/fs/nandfs/nandfs_mount.h deleted file mode 100644 index cc6e30eb0bbd7..0000000000000 --- a/sys/fs/nandfs/nandfs_mount.h +++ /dev/null @@ -1,52 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-4-Clause - * - * Copyright (c) 2008, 2009 Reinoud Zandijk - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed for the - * NetBSD Project. See http://www.NetBSD.org/ for - * information about NetBSD. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * From: NetBSD: nilfs_mount.h,v 1.1 2009/07/18 16:31:42 reinoud - * - * $FreeBSD$ - */ - -#ifndef _FS_NANDFS_NANDFS_MOUNT_H_ -#define _FS_NANDFS_NANDFS_MOUNT_H_ - -/* - * Arguments to mount NANDFS filingsystem. - */ - -struct nandfs_args { - char *fspec; /* mount specifier */ - int64_t cpno; /* checkpoint number */ -}; - -#endif /* !_FS_NANDFS_NANDFS_MOUNT_H_ */ - diff --git a/sys/fs/nandfs/nandfs_segment.c b/sys/fs/nandfs/nandfs_segment.c deleted file mode 100644 index 36efc89af4099..0000000000000 --- a/sys/fs/nandfs/nandfs_segment.c +++ /dev/null @@ -1,1314 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include "opt_ddb.h" - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/conf.h> -#include <sys/gsb_crc32.h> -#include <sys/kernel.h> -#include <sys/lock.h> -#include <sys/malloc.h> -#include <sys/mount.h> -#include <sys/mutex.h> -#include <sys/namei.h> -#include <sys/rwlock.h> -#include <sys/sysctl.h> -#include <sys/vnode.h> -#include <sys/buf.h> -#include <sys/bio.h> -#include <sys/libkern.h> - -#include <ddb/ddb.h> - -#include <vm/vm.h> -#include <vm/vm_param.h> -#include <vm/vm_kern.h> -#include <vm/vm_page.h> - -#include <geom/geom.h> -#include <geom/geom_vfs.h> - -#include <fs/nandfs/nandfs_mount.h> -#include <fs/nandfs/nandfs.h> -#include <fs/nandfs/nandfs_subr.h> - -static int -nandfs_new_segment(struct nandfs_device *fsdev) -{ - int error = 0; - uint64_t new; - - error = nandfs_alloc_segment(fsdev, &new); - if (!error) { - fsdev->nd_seg_num = fsdev->nd_next_seg_num; - fsdev->nd_next_seg_num = new; - } - DPRINTF(SYNC, ("%s: new segment %jx next %jx error %d\n", - __func__, (uintmax_t)fsdev->nd_seg_num, (uintmax_t)new, error)); - if (error) - nandfs_error("%s: cannot create segment error %d\n", - __func__, error); - - return (error); -} - -static int -create_segment(struct nandfs_seginfo *seginfo) -{ - struct nandfs_segment *seg; - struct nandfs_device *fsdev; - struct nandfs_segment *prev; - struct buf *bp; - uint64_t start_block, curr; - uint32_t blks_per_seg, nblocks; - int error; - - fsdev = seginfo->fsdev; - prev = seginfo->curseg; - blks_per_seg = fsdev->nd_fsdata.f_blocks_per_segment; - nblocks = fsdev->nd_last_segsum.ss_nblocks; - - if (!prev) { - vfs_timestamp(&fsdev->nd_ts); - /* Touch current segment */ - error = nandfs_touch_segment(fsdev, fsdev->nd_seg_num); - if (error) { - nandfs_error("%s: cannot preallocate segment %jx\n", - __func__, fsdev->nd_seg_num); - return (error); - } - error = nandfs_touch_segment(fsdev, 0); - if (error) { - nandfs_error("%s: cannot dirty block with segment 0\n", - __func__); - return (error); - } - start_block = fsdev->nd_last_pseg + (uint64_t)nblocks; - /* - * XXX Hack - */ - if (blks_per_seg - (start_block % blks_per_seg) - 1 == 0) - start_block++; - curr = nandfs_get_segnum_of_block(fsdev, start_block); - /* Allocate new segment if last one is full */ - if (fsdev->nd_seg_num != curr) { - error = nandfs_new_segment(fsdev); - if (error) { - nandfs_error("%s: cannot create new segment\n", - __func__); - return (error); - } - /* - * XXX Hack - */ - nandfs_get_segment_range(fsdev, fsdev->nd_seg_num, &start_block, NULL); - } - } else { - nandfs_get_segment_range(fsdev, fsdev->nd_next_seg_num, - &start_block, NULL); - - /* Touch current segment and allocate and touch new one */ - error = nandfs_new_segment(fsdev); - if (error) { - nandfs_error("%s: cannot create next segment\n", - __func__); - return (error); - } - - /* Reiterate in case new buf is dirty */ - seginfo->reiterate = 1; - } - - /* Allocate and initialize nandfs_segment structure */ - seg = malloc(sizeof(*seg), M_DEVBUF, M_WAITOK|M_ZERO); - TAILQ_INIT(&seg->segsum); - TAILQ_INIT(&seg->data); - seg->fsdev = fsdev; - seg->start_block = start_block; - seg->num_blocks = blks_per_seg - (start_block % blks_per_seg) - 1; - seg->seg_num = fsdev->nd_seg_num; - seg->seg_next = fsdev->nd_next_seg_num; - seg->segsum_blocks = 1; - seg->bytes_left = fsdev->nd_blocksize - - sizeof(struct nandfs_segment_summary); - seg->segsum_bytes = sizeof(struct nandfs_segment_summary); - - /* Allocate buffer for segment summary */ - bp = getblk(fsdev->nd_devvp, nandfs_block_to_dblock(fsdev, - seg->start_block), fsdev->nd_blocksize, 0, 0, 0); - bzero(bp->b_data, seginfo->fsdev->nd_blocksize); - bp->b_bufobj = &seginfo->fsdev->nd_devvp->v_bufobj; - bp->b_flags |= B_MANAGED; - - /* Add buffer to segment */ - TAILQ_INSERT_TAIL(&seg->segsum, bp, b_cluster.cluster_entry); - seg->current_off = bp->b_data + sizeof(struct nandfs_segment_summary); - - DPRINTF(SYNC, ("%s: seg %p : initial settings: start %#jx size :%#x\n", - __func__, seg, (uintmax_t)seg->start_block, seg->num_blocks)); - DPRINTF(SYNC, ("%s: seg->seg_num %#jx cno %#jx next %#jx\n", __func__, - (uintmax_t)seg->seg_num, (uintmax_t)(fsdev->nd_last_cno + 1), - (uintmax_t)seg->seg_next)); - - if (!prev) - LIST_INSERT_HEAD(&seginfo->seg_list, seg, seg_link); - else - LIST_INSERT_AFTER(prev, seg, seg_link); - - seginfo->curseg = seg; - - return (0); -} - -static int -delete_segment(struct nandfs_seginfo *seginfo) -{ - struct nandfs_segment *seg, *tseg; - struct buf *bp, *tbp; - - LIST_FOREACH_SAFE(seg, &seginfo->seg_list, seg_link, tseg) { - TAILQ_FOREACH_SAFE(bp, &seg->segsum, b_cluster.cluster_entry, - tbp) { - TAILQ_REMOVE(&seg->segsum, bp, b_cluster.cluster_entry); - bp->b_flags &= ~B_MANAGED; - brelse(bp); - } - - LIST_REMOVE(seg, seg_link); - free(seg, M_DEVBUF); - } - - return (0); -} - -static int -create_seginfo(struct nandfs_device *fsdev, struct nandfs_seginfo **seginfo) -{ - struct nandfs_seginfo *info; - - info = malloc(sizeof(*info), M_DEVBUF, M_WAITOK); - - LIST_INIT(&info->seg_list); - info->fsdev = fsdev; - info->curseg = NULL; - info->blocks = 0; - *seginfo = info; - fsdev->nd_seginfo = info; - return (0); -} - -static int -delete_seginfo(struct nandfs_seginfo *seginfo) -{ - struct nandfs_device *nffsdev; - - nffsdev = seginfo->fsdev; - delete_segment(seginfo); - nffsdev->nd_seginfo = NULL; - free(seginfo, M_DEVBUF); - - return (0); -} - -static int -nandfs_create_superroot_block(struct nandfs_seginfo *seginfo, - struct buf **newbp) -{ - struct buf *bp; - int error; - - bp = nandfs_geteblk(seginfo->fsdev->nd_blocksize, GB_NOWAIT_BD); - - bzero(bp->b_data, seginfo->fsdev->nd_blocksize); - bp->b_bufobj = &seginfo->fsdev->nd_devvp->v_bufobj; - bp->b_flags |= B_MANAGED; - - if (!(seginfo->curseg) || !seginfo->curseg->num_blocks) { - error = create_segment(seginfo); - if (error) { - brelse(bp); - nandfs_error("%s: no segment for superroot\n", - __func__); - return (error); - } - } - - TAILQ_INSERT_TAIL(&seginfo->curseg->data, bp, b_cluster.cluster_entry); - - seginfo->curseg->nblocks++; - seginfo->curseg->num_blocks--; - seginfo->blocks++; - - *newbp = bp; - return (0); -} - -static int -nandfs_add_superroot(struct nandfs_seginfo *seginfo) -{ - struct nandfs_device *fsdev; - struct nandfs_super_root *sr; - struct buf *bp = NULL; - uint64_t crc_skip; - uint32_t crc_calc; - int error; - - fsdev = seginfo->fsdev; - - error = nandfs_create_superroot_block(seginfo, &bp); - if (error) { - nandfs_error("%s: cannot add superroot\n", __func__); - return (error); - } - - sr = (struct nandfs_super_root *)bp->b_data; - /* Save superroot CRC */ - sr->sr_bytes = NANDFS_SR_BYTES; - sr->sr_flags = 0; - sr->sr_nongc_ctime = 0; - - memcpy(&sr->sr_dat, &fsdev->nd_dat_node->nn_inode, - sizeof(struct nandfs_inode)); - memcpy(&sr->sr_cpfile, &fsdev->nd_cp_node->nn_inode, - sizeof(struct nandfs_inode)); - memcpy(&sr->sr_sufile, &fsdev->nd_su_node->nn_inode, - sizeof(struct nandfs_inode)); - - crc_skip = sizeof(sr->sr_sum); - crc_calc = crc32((uint8_t *)sr + crc_skip, NANDFS_SR_BYTES - crc_skip); - - sr->sr_sum = crc_calc; - - bp->b_flags |= B_MANAGED; - bp->b_bufobj = &seginfo->fsdev->nd_devvp->v_bufobj; - - bp->b_flags &= ~B_INVAL; - nandfs_dirty_bufs_increment(fsdev); - DPRINTF(SYNC, ("%s: bp:%p\n", __func__, bp)); - - return (0); -} - -static int -nandfs_add_segsum_block(struct nandfs_seginfo *seginfo, struct buf **newbp) -{ - struct nandfs_device *fsdev; - nandfs_daddr_t blk; - struct buf *bp; - int error; - - if (!(seginfo->curseg) || seginfo->curseg->num_blocks <= 1) { - error = create_segment(seginfo); - if (error) { - nandfs_error("%s: error:%d when creating segment\n", - __func__, error); - return (error); - } - *newbp = TAILQ_FIRST(&seginfo->curseg->segsum); - return (0); - } - - fsdev = seginfo->fsdev; - blk = nandfs_block_to_dblock(fsdev, seginfo->curseg->start_block + - seginfo->curseg->segsum_blocks); - - bp = getblk(fsdev->nd_devvp, blk, fsdev->nd_blocksize, 0, 0, 0); - - bzero(bp->b_data, seginfo->fsdev->nd_blocksize); - bp->b_bufobj = &seginfo->fsdev->nd_devvp->v_bufobj; - bp->b_flags |= B_MANAGED; - - TAILQ_INSERT_TAIL(&seginfo->curseg->segsum, bp, - b_cluster.cluster_entry); - seginfo->curseg->num_blocks--; - - seginfo->curseg->segsum_blocks++; - seginfo->curseg->bytes_left = seginfo->fsdev->nd_blocksize; - seginfo->curseg->current_off = bp->b_data; - seginfo->blocks++; - - *newbp = bp; - - DPRINTF(SYNC, ("%s: bp %p\n", __func__, bp)); - - return (0); -} - -static int -nandfs_add_blocks(struct nandfs_seginfo *seginfo, struct nandfs_node *node, - struct buf *bp) -{ - union nandfs_binfo *binfo; - struct buf *seg_bp; - int error; - - if (!(seginfo->curseg) || !seginfo->curseg->num_blocks) { - error = create_segment(seginfo); - if (error) { - nandfs_error("%s: error:%d when creating segment\n", - __func__, error); - return (error); - } - } - - if (seginfo->curseg->bytes_left < sizeof(union nandfs_binfo)) { - error = nandfs_add_segsum_block(seginfo, &seg_bp); - if (error) { - nandfs_error("%s: error:%d when adding segsum\n", - __func__, error); - return (error); - } - } - binfo = (union nandfs_binfo *)seginfo->curseg->current_off; - - if (node->nn_ino != NANDFS_DAT_INO) { - binfo->bi_v.bi_blkoff = bp->b_lblkno; - binfo->bi_v.bi_ino = node->nn_ino; - } else { - binfo->bi_dat.bi_blkoff = bp->b_lblkno; - binfo->bi_dat.bi_ino = node->nn_ino; - if (NANDFS_IS_INDIRECT(bp)) - binfo->bi_dat.bi_level = 1; - else - binfo->bi_dat.bi_level = 0; - } - binfo++; - - seginfo->curseg->bytes_left -= sizeof(union nandfs_binfo); - seginfo->curseg->segsum_bytes += sizeof(union nandfs_binfo); - seginfo->curseg->current_off = (char *)binfo; - - TAILQ_INSERT_TAIL(&seginfo->curseg->data, bp, b_cluster.cluster_entry); - - seginfo->curseg->nbinfos++; - seginfo->curseg->nblocks++; - seginfo->curseg->num_blocks--; - seginfo->blocks++; - - DPRINTF(SYNC, ("%s: bp (%p) number %x (left %x)\n", - __func__, bp, seginfo->curseg->nblocks, - seginfo->curseg->num_blocks)); - return (0); -} - -static int -nandfs_iterate_dirty_buf(struct vnode *vp, struct nandfs_seginfo *seginfo, - uint8_t hold) -{ - struct buf *bp, *tbd; - struct bufobj *bo; - struct nandfs_node *node; - int error; - - node = VTON(vp); - bo = &vp->v_bufobj; - - ASSERT_VOP_ELOCKED(vp, __func__); - - /* Iterate dirty data bufs */ - TAILQ_FOREACH_SAFE(bp, &bo->bo_dirty.bv_hd, b_bobufs, tbd) { - DPRINTF(SYNC, ("%s: vp (%p): bp (%p) with lblkno %jx ino %jx " - "add buf\n", __func__, vp, bp, bp->b_lblkno, node->nn_ino)); - - if (!(NANDFS_ISGATHERED(bp))) { - error = nandfs_bmap_update_dat(node, - nandfs_vblk_get(bp), bp); - if (error) - return (error); - NANDFS_GATHER(bp); - nandfs_add_blocks(seginfo, node, bp); - } - } - - return (0); -} - -static int -nandfs_iterate_system_vnode(struct nandfs_node *node, - struct nandfs_seginfo *seginfo) -{ - struct vnode *vp; - int nblocks; - uint8_t hold = 0; - - if (node->nn_ino != NANDFS_IFILE_INO) - hold = 1; - - vp = NTOV(node); - - nblocks = vp->v_bufobj.bo_dirty.bv_cnt; - DPRINTF(SYNC, ("%s: vp (%p): nblocks %x ino %jx\n", - __func__, vp, nblocks, node->nn_ino)); - - if (nblocks) - nandfs_iterate_dirty_buf(vp, seginfo, hold); - - return (0); -} - -static int -nandfs_iterate_dirty_vnodes(struct mount *mp, struct nandfs_seginfo *seginfo) -{ - struct nandfs_node *nandfs_node; - struct vnode *vp, *mvp; - struct thread *td; - struct bufobj *bo; - int error, update; - - td = curthread; - - MNT_VNODE_FOREACH_ACTIVE(vp, mp, mvp) { - update = 0; - - if (mp->mnt_syncer == vp || VOP_ISLOCKED(vp)) { - VI_UNLOCK(vp); - continue; - } - if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK | LK_NOWAIT, td) != 0) - continue; - - nandfs_node = VTON(vp); - if (nandfs_node->nn_flags & IN_MODIFIED) { - nandfs_node->nn_flags &= ~(IN_MODIFIED); - update = 1; - } - - bo = &vp->v_bufobj; - BO_LOCK(bo); - if (vp->v_bufobj.bo_dirty.bv_cnt) { - error = nandfs_iterate_dirty_buf(vp, seginfo, 0); - if (error) { - nandfs_error("%s: cannot iterate vnode:%p " - "err:%d\n", __func__, vp, error); - vput(vp); - BO_UNLOCK(bo); - return (error); - } - update = 1; - } else - vput(vp); - BO_UNLOCK(bo); - - if (update) - nandfs_node_update(nandfs_node); - } - - return (0); -} - -static int -nandfs_update_phys_block(struct nandfs_device *fsdev, struct buf *bp, - uint64_t phys_blknr, union nandfs_binfo *binfo) -{ - struct nandfs_node *node, *dat; - struct vnode *vp; - uint64_t new_blknr; - int error; - - vp = bp->b_vp; - node = VTON(vp); - new_blknr = nandfs_vblk_get(bp); - dat = fsdev->nd_dat_node; - - DPRINTF(BMAP, ("%s: ino %#jx lblk %#jx: vblk %#jx -> %#jx\n", - __func__, (uintmax_t)node->nn_ino, (uintmax_t)bp->b_lblkno, - (uintmax_t)new_blknr, (uintmax_t)phys_blknr)); - - if (node->nn_ino != NANDFS_DAT_INO) { - KASSERT((new_blknr != 0), ("vblk for bp %p is 0", bp)); - - nandfs_vblock_assign(fsdev, new_blknr, phys_blknr); - binfo->bi_v.bi_vblocknr = new_blknr; - binfo->bi_v.bi_blkoff = bp->b_lblkno; - binfo->bi_v.bi_ino = node->nn_ino; - } else { - VOP_LOCK(NTOV(dat), LK_EXCLUSIVE); - error = nandfs_bmap_update_block(node, bp, phys_blknr); - if (error) { - nandfs_error("%s: error updating block:%jx for bp:%p\n", - __func__, (uintmax_t)phys_blknr, bp); - VOP_UNLOCK(NTOV(dat), 0); - return (error); - } - VOP_UNLOCK(NTOV(dat), 0); - binfo->bi_dat.bi_blkoff = bp->b_lblkno; - binfo->bi_dat.bi_ino = node->nn_ino; - if (NANDFS_IS_INDIRECT(bp)) - binfo->bi_dat.bi_level = 1; - else - binfo->bi_dat.bi_level = 0; - } - - return (0); -} - -#define NBINFO(off) ((off) + sizeof(union nandfs_binfo)) -static int -nandfs_segment_assign_pblk(struct nandfs_segment *nfsseg) -{ - struct nandfs_device *fsdev; - union nandfs_binfo *binfo; - struct buf *bp, *seg_bp; - uint64_t blocknr; - uint32_t curr_off, blocksize; - int error; - - fsdev = nfsseg->fsdev; - blocksize = fsdev->nd_blocksize; - - blocknr = nfsseg->start_block + nfsseg->segsum_blocks; - seg_bp = TAILQ_FIRST(&nfsseg->segsum); - DPRINTF(SYNC, ("%s: seg:%p segsum bp:%p data:%p\n", - __func__, nfsseg, seg_bp, seg_bp->b_data)); - - binfo = (union nandfs_binfo *)(seg_bp->b_data + - sizeof(struct nandfs_segment_summary)); - curr_off = sizeof(struct nandfs_segment_summary); - - TAILQ_FOREACH(bp, &nfsseg->data, b_cluster.cluster_entry) { - KASSERT((bp->b_vp), ("bp %p has not vp", bp)); - - DPRINTF(BMAP, ("\n\n%s: assign buf %p for ino %#jx next %p\n", - __func__, bp, (uintmax_t)VTON(bp->b_vp)->nn_ino, - TAILQ_NEXT(bp, b_cluster.cluster_entry))); - - if (NBINFO(curr_off) > blocksize) { - seg_bp = TAILQ_NEXT(seg_bp, b_cluster.cluster_entry); - binfo = (union nandfs_binfo *)seg_bp->b_data; - curr_off = 0; - DPRINTF(SYNC, ("%s: next segsum %p data %p\n", - __func__, seg_bp, seg_bp->b_data)); - } - - error = nandfs_update_phys_block(fsdev, bp, blocknr, binfo); - if (error) { - nandfs_error("%s: err:%d when updatinng phys block:%jx" - " for bp:%p and binfo:%p\n", __func__, error, - (uintmax_t)blocknr, bp, binfo); - return (error); - } - binfo++; - curr_off = NBINFO(curr_off); - - blocknr++; - } - - return (0); -} - -static int -nandfs_seginfo_assign_pblk(struct nandfs_seginfo *seginfo) -{ - struct nandfs_segment *nfsseg; - int error = 0; - - LIST_FOREACH(nfsseg, &seginfo->seg_list, seg_link) { - error = nandfs_segment_assign_pblk(nfsseg); - if (error) - break; - } - - return (error); -} - -static struct nandfs_segment_summary * -nandfs_fill_segsum(struct nandfs_segment *seg, int has_sr) -{ - struct nandfs_segment_summary *ss; - struct nandfs_device *fsdev; - struct buf *bp; - uint32_t rest, segsum_size, blocksize, crc_calc; - uint16_t flags; - uint8_t *crc_area, crc_skip; - - DPRINTF(SYNC, ("%s: seg %#jx nblocks %#x sumbytes %#x\n", - __func__, (uintmax_t) seg->seg_num, - seg->nblocks + seg->segsum_blocks, - seg->segsum_bytes)); - - fsdev = seg->fsdev; - - flags = NANDFS_SS_LOGBGN | NANDFS_SS_LOGEND; - if (has_sr) - flags |= NANDFS_SS_SR; - - bp = TAILQ_FIRST(&seg->segsum); - ss = (struct nandfs_segment_summary *) bp->b_data; - ss->ss_magic = NANDFS_SEGSUM_MAGIC; - ss->ss_bytes = sizeof(struct nandfs_segment_summary); - ss->ss_flags = flags; - ss->ss_seq = ++(fsdev->nd_seg_sequence); - ss->ss_create = fsdev->nd_ts.tv_sec; - nandfs_get_segment_range(fsdev, seg->seg_next, &ss->ss_next, NULL); - ss->ss_nblocks = seg->nblocks + seg->segsum_blocks; - ss->ss_nbinfos = seg->nbinfos; - ss->ss_sumbytes = seg->segsum_bytes; - - crc_skip = sizeof(ss->ss_datasum) + sizeof(ss->ss_sumsum); - blocksize = seg->fsdev->nd_blocksize; - - segsum_size = seg->segsum_bytes - crc_skip; - rest = min(seg->segsum_bytes, blocksize) - crc_skip; - crc_area = (uint8_t *)ss + crc_skip; - crc_calc = ~0U; - while (segsum_size > 0) { - crc_calc = crc32_raw(crc_area, rest, crc_calc); - segsum_size -= rest; - if (!segsum_size) - break; - bp = TAILQ_NEXT(bp, b_cluster.cluster_entry); - crc_area = (uint8_t *)bp->b_data; - rest = segsum_size <= blocksize ? segsum_size : blocksize; - } - ss->ss_sumsum = crc_calc ^ ~0U; - - return (ss); - -} - -static int -nandfs_save_buf(struct buf *bp, uint64_t blocknr, struct nandfs_device *fsdev) -{ - struct bufobj *bo; - int error; - - bo = &fsdev->nd_devvp->v_bufobj; - - bp->b_blkno = nandfs_block_to_dblock(fsdev, blocknr); - bp->b_iooffset = dbtob(bp->b_blkno); - - KASSERT(bp->b_bufobj != NULL, ("no bufobj for %p", bp)); - if (bp->b_bufobj != bo) { - BO_LOCK(bp->b_bufobj); - BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, - BO_LOCKPTR(bp->b_bufobj)); - KASSERT(BUF_ISLOCKED(bp), ("Problem with locking buffer")); - } - - DPRINTF(SYNC, ("%s: buf: %p offset %#jx blk %#jx size %#x\n", - __func__, bp, (uintmax_t)bp->b_offset, (uintmax_t)blocknr, - fsdev->nd_blocksize)); - - NANDFS_UNGATHER(bp); - nandfs_buf_clear(bp, 0xffffffff); - bp->b_flags &= ~(B_ASYNC|B_INVAL|B_MANAGED); - error = bwrite(bp); - if (error) { - nandfs_error("%s: error:%d when writing buffer:%p\n", - __func__, error, bp); - return (error); - } - return (error); -} - -static void -nandfs_clean_buf(struct nandfs_device *fsdev, struct buf *bp) -{ - - DPRINTF(SYNC, ("%s: buf: %p\n", __func__, bp)); - - NANDFS_UNGATHER(bp); - nandfs_buf_clear(bp, 0xffffffff); - bp->b_flags &= ~(B_ASYNC|B_INVAL|B_MANAGED); - nandfs_undirty_buf_fsdev(fsdev, bp); -} - -static void -nandfs_clean_segblocks(struct nandfs_segment *seg, uint8_t unlock) -{ - struct nandfs_device *fsdev = seg->fsdev; - struct nandfs_segment *next_seg; - struct buf *bp, *tbp, *next_bp; - struct vnode *vp, *next_vp; - - VOP_LOCK(fsdev->nd_devvp, LK_EXCLUSIVE); - TAILQ_FOREACH_SAFE(bp, &seg->segsum, b_cluster.cluster_entry, tbp) { - TAILQ_REMOVE(&seg->segsum, bp, b_cluster.cluster_entry); - nandfs_clean_buf(fsdev, bp); - } - - TAILQ_FOREACH_SAFE(bp, &seg->data, b_cluster.cluster_entry, tbp) { - TAILQ_REMOVE(&seg->data, bp, b_cluster.cluster_entry); - - /* - * If bp is not super-root and vnode is not currently - * locked lock it. - */ - vp = bp->b_vp; - next_vp = NULL; - next_bp = TAILQ_NEXT(bp, b_cluster.cluster_entry); - if (!next_bp) { - next_seg = LIST_NEXT(seg, seg_link); - if (next_seg) - next_bp = TAILQ_FIRST(&next_seg->data); - } - - if (next_bp) - next_vp = next_bp->b_vp; - - nandfs_clean_buf(fsdev, bp); - - if (unlock && vp != NULL && next_vp != vp && - !NANDFS_SYS_NODE(VTON(vp)->nn_ino)) - vput(vp); - - nandfs_dirty_bufs_decrement(fsdev); - } - - VOP_UNLOCK(fsdev->nd_devvp, 0); -} - -static int -nandfs_save_segblocks(struct nandfs_segment *seg, uint8_t unlock) -{ - struct nandfs_device *fsdev = seg->fsdev; - struct nandfs_segment *next_seg; - struct buf *bp, *tbp, *next_bp; - struct vnode *vp, *next_vp; - uint64_t blocknr; - uint32_t i = 0; - int error = 0; - - VOP_LOCK(fsdev->nd_devvp, LK_EXCLUSIVE); - TAILQ_FOREACH_SAFE(bp, &seg->segsum, b_cluster.cluster_entry, tbp) { - TAILQ_REMOVE(&seg->segsum, bp, b_cluster.cluster_entry); - blocknr = seg->start_block + i; - error = nandfs_save_buf(bp, blocknr, fsdev); - if (error) { - nandfs_error("%s: error saving buf: %p blocknr:%jx\n", - __func__, bp, (uintmax_t)blocknr); - goto out; - } - i++; - } - - i = 0; - TAILQ_FOREACH_SAFE(bp, &seg->data, b_cluster.cluster_entry, tbp) { - TAILQ_REMOVE(&seg->data, bp, b_cluster.cluster_entry); - - blocknr = seg->start_block + seg->segsum_blocks + i; - /* - * If bp is not super-root and vnode is not currently - * locked lock it. - */ - vp = bp->b_vp; - next_vp = NULL; - next_bp = TAILQ_NEXT(bp, b_cluster.cluster_entry); - if (!next_bp) { - next_seg = LIST_NEXT(seg, seg_link); - if (next_seg) - next_bp = TAILQ_FIRST(&next_seg->data); - } - - if (next_bp) - next_vp = next_bp->b_vp; - - error = nandfs_save_buf(bp, blocknr, fsdev); - if (error) { - nandfs_error("%s: error saving buf: %p blknr: %jx\n", - __func__, bp, (uintmax_t)blocknr); - if (unlock && vp != NULL && next_vp != vp && - !NANDFS_SYS_NODE(VTON(vp)->nn_ino)) - vput(vp); - goto out; - } - - if (unlock && vp != NULL && next_vp != vp && - !NANDFS_SYS_NODE(VTON(vp)->nn_ino)) - vput(vp); - - i++; - nandfs_dirty_bufs_decrement(fsdev); - } -out: - if (error) { - nandfs_clean_segblocks(seg, unlock); - VOP_UNLOCK(fsdev->nd_devvp, 0); - return (error); - } - - VOP_UNLOCK(fsdev->nd_devvp, 0); - return (error); -} - - -static void -clean_seginfo(struct nandfs_seginfo *seginfo, uint8_t unlock) -{ - struct nandfs_segment *seg; - - DPRINTF(SYNC, ("%s: seginfo %p\n", __func__, seginfo)); - - LIST_FOREACH(seg, &seginfo->seg_list, seg_link) { - nandfs_clean_segblocks(seg, unlock); - } -} - -static int -save_seginfo(struct nandfs_seginfo *seginfo, uint8_t unlock) -{ - struct nandfs_segment *seg; - struct nandfs_device *fsdev; - struct nandfs_segment_summary *ss; - int error = 0; - - fsdev = seginfo->fsdev; - - DPRINTF(SYNC, ("%s: seginfo %p\n", __func__, seginfo)); - - LIST_FOREACH(seg, &seginfo->seg_list, seg_link) { - if (LIST_NEXT(seg, seg_link)) { - nandfs_fill_segsum(seg, 0); - error = nandfs_save_segblocks(seg, unlock); - if (error) { - nandfs_error("%s: error:%d saving seg:%p\n", - __func__, error, seg); - goto out; - } - } else { - ss = nandfs_fill_segsum(seg, 1); - fsdev->nd_last_segsum = *ss; - error = nandfs_save_segblocks(seg, unlock); - if (error) { - nandfs_error("%s: error:%d saving seg:%p\n", - __func__, error, seg); - goto out; - } - fsdev->nd_last_cno++; - fsdev->nd_last_pseg = seg->start_block; - } - } -out: - if (error) - clean_seginfo(seginfo, unlock); - return (error); -} - -static void -nandfs_invalidate_bufs(struct nandfs_device *fsdev, uint64_t segno) -{ - uint64_t start, end; - struct buf *bp, *tbd; - struct bufobj *bo; - - nandfs_get_segment_range(fsdev, segno, &start, &end); - - bo = &NTOV(fsdev->nd_gc_node)->v_bufobj; - - BO_LOCK(bo); -restart_locked_gc: - TAILQ_FOREACH_SAFE(bp, &bo->bo_clean.bv_hd, b_bobufs, tbd) { - if (!(bp->b_lblkno >= start && bp->b_lblkno <= end)) - continue; - - if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL)) - goto restart_locked_gc; - - bremfree(bp); - bp->b_flags |= (B_INVAL | B_RELBUF); - bp->b_flags &= ~(B_ASYNC | B_MANAGED); - BO_UNLOCK(bo); - brelse(bp); - BO_LOCK(bo); - } - BO_UNLOCK(bo); -} - -/* Process segments marks to free by cleaner */ -static void -nandfs_process_segments(struct nandfs_device *fsdev) -{ - uint64_t saved_segment; - int i; - - if (fsdev->nd_free_base) { - saved_segment = nandfs_get_segnum_of_block(fsdev, - fsdev->nd_super.s_last_pseg); - for (i = 0; i < fsdev->nd_free_count; i++) { - if (fsdev->nd_free_base[i] == NANDFS_NOSEGMENT) - continue; - /* Update superblock if clearing segment point by it */ - if (fsdev->nd_free_base[i] == saved_segment) { - nandfs_write_superblock(fsdev); - saved_segment = nandfs_get_segnum_of_block( - fsdev, fsdev->nd_super.s_last_pseg); - } - nandfs_invalidate_bufs(fsdev, fsdev->nd_free_base[i]); - nandfs_clear_segment(fsdev, fsdev->nd_free_base[i]); - } - - free(fsdev->nd_free_base, M_NANDFSTEMP); - fsdev->nd_free_base = NULL; - fsdev->nd_free_count = 0; - } -} - -/* Collect and write dirty buffers */ -int -nandfs_sync_file(struct vnode *vp) -{ - struct nandfs_device *fsdev; - struct nandfs_node *nandfs_node; - struct nandfsmount *nmp; - struct nandfs_node *dat, *su, *ifile, *cp; - struct nandfs_seginfo *seginfo = NULL; - struct nandfs_segment *seg; - int update, error; - int cno_changed; - - ASSERT_VOP_LOCKED(vp, __func__); - DPRINTF(SYNC, ("%s: START\n", __func__)); - - error = 0; - nmp = VFSTONANDFS(vp->v_mount); - fsdev = nmp->nm_nandfsdev; - - dat = fsdev->nd_dat_node; - su = fsdev->nd_su_node; - cp = fsdev->nd_cp_node; - ifile = nmp->nm_ifile_node; - - NANDFS_WRITEASSERT(fsdev); - if (lockmgr(&fsdev->nd_seg_const, LK_UPGRADE, NULL) != 0) { - DPRINTF(SYNC, ("%s: lost shared lock\n", __func__)); - if (lockmgr(&fsdev->nd_seg_const, LK_EXCLUSIVE, NULL) != 0) - panic("couldn't lock exclusive"); - } - DPRINTF(SYNC, ("%s: got lock\n", __func__)); - - VOP_LOCK(NTOV(su), LK_EXCLUSIVE); - create_seginfo(fsdev, &seginfo); - - update = 0; - - nandfs_node = VTON(vp); - if (nandfs_node->nn_flags & IN_MODIFIED) { - nandfs_node->nn_flags &= ~(IN_MODIFIED); - update = 1; - } - - if (vp->v_bufobj.bo_dirty.bv_cnt) { - error = nandfs_iterate_dirty_buf(vp, seginfo, 0); - if (error) { - clean_seginfo(seginfo, 0); - delete_seginfo(seginfo); - VOP_UNLOCK(NTOV(su), 0); - lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL); - nandfs_error("%s: err:%d iterating dirty bufs vp:%p", - __func__, error, vp); - return (error); - } - update = 1; - } - - if (update) { - VOP_LOCK(NTOV(ifile), LK_EXCLUSIVE); - error = nandfs_node_update(nandfs_node); - if (error) { - clean_seginfo(seginfo, 0); - delete_seginfo(seginfo); - VOP_UNLOCK(NTOV(ifile), 0); - VOP_UNLOCK(NTOV(su), 0); - lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL); - nandfs_error("%s: err:%d updating vp:%p", - __func__, error, vp); - return (error); - } - VOP_UNLOCK(NTOV(ifile), 0); - } - - cno_changed = 0; - if (seginfo->blocks) { - VOP_LOCK(NTOV(cp), LK_EXCLUSIVE); - cno_changed = 1; - /* Create new checkpoint */ - error = nandfs_get_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1); - if (error) { - clean_seginfo(seginfo, 0); - delete_seginfo(seginfo); - VOP_UNLOCK(NTOV(cp), 0); - VOP_UNLOCK(NTOV(su), 0); - lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL); - nandfs_error("%s: err:%d getting cp:%jx", - __func__, error, fsdev->nd_last_cno + 1); - return (error); - } - - /* Reiterate all blocks and assign physical block number */ - nandfs_seginfo_assign_pblk(seginfo); - - /* Fill checkpoint data */ - error = nandfs_set_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1, - &ifile->nn_inode, seginfo->blocks); - if (error) { - clean_seginfo(seginfo, 0); - delete_seginfo(seginfo); - VOP_UNLOCK(NTOV(cp), 0); - VOP_UNLOCK(NTOV(su), 0); - lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL); - nandfs_error("%s: err:%d setting cp:%jx", - __func__, error, fsdev->nd_last_cno + 1); - return (error); - } - - VOP_UNLOCK(NTOV(cp), 0); - LIST_FOREACH(seg, &seginfo->seg_list, seg_link) - nandfs_update_segment(fsdev, seg->seg_num, - seg->nblocks + seg->segsum_blocks); - - VOP_LOCK(NTOV(dat), LK_EXCLUSIVE); - error = save_seginfo(seginfo, 0); - if (error) { - clean_seginfo(seginfo, 0); - delete_seginfo(seginfo); - VOP_UNLOCK(NTOV(dat), 0); - VOP_UNLOCK(NTOV(su), 0); - lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL); - nandfs_error("%s: err:%d updating seg", - __func__, error); - return (error); - } - VOP_UNLOCK(NTOV(dat), 0); - } - - VOP_UNLOCK(NTOV(su), 0); - - delete_seginfo(seginfo); - lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL); - - if (cno_changed && !error) { - if (nandfs_cps_between_sblocks != 0 && - fsdev->nd_last_cno % nandfs_cps_between_sblocks == 0) - nandfs_write_superblock(fsdev); - } - - ASSERT_VOP_LOCKED(vp, __func__); - DPRINTF(SYNC, ("%s: END error %d\n", __func__, error)); - return (error); -} - -int -nandfs_segment_constructor(struct nandfsmount *nmp, int flags) -{ - struct nandfs_device *fsdev; - struct nandfs_seginfo *seginfo = NULL; - struct nandfs_segment *seg; - struct nandfs_node *dat, *su, *ifile, *cp, *gc; - int cno_changed, error; - - DPRINTF(SYNC, ("%s: START\n", __func__)); - fsdev = nmp->nm_nandfsdev; - - lockmgr(&fsdev->nd_seg_const, LK_EXCLUSIVE, NULL); - DPRINTF(SYNC, ("%s: git lock\n", __func__)); -again: - create_seginfo(fsdev, &seginfo); - - dat = fsdev->nd_dat_node; - su = fsdev->nd_su_node; - cp = fsdev->nd_cp_node; - gc = fsdev->nd_gc_node; - ifile = nmp->nm_ifile_node; - - VOP_LOCK(NTOV(su), LK_EXCLUSIVE); - VOP_LOCK(NTOV(ifile), LK_EXCLUSIVE); - VOP_LOCK(NTOV(gc), LK_EXCLUSIVE); - VOP_LOCK(NTOV(cp), LK_EXCLUSIVE); - - nandfs_iterate_system_vnode(gc, seginfo); - nandfs_iterate_dirty_vnodes(nmp->nm_vfs_mountp, seginfo); - nandfs_iterate_system_vnode(ifile, seginfo); - nandfs_iterate_system_vnode(su, seginfo); - - cno_changed = 0; - if (seginfo->blocks || flags) { - cno_changed = 1; - /* Create new checkpoint */ - error = nandfs_get_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1); - if (error) { - clean_seginfo(seginfo, 0); - delete_seginfo(seginfo); - goto error_locks; - } - - /* Collect blocks from system files */ - nandfs_iterate_system_vnode(cp, seginfo); - nandfs_iterate_system_vnode(su, seginfo); - VOP_LOCK(NTOV(dat), LK_EXCLUSIVE); - nandfs_iterate_system_vnode(dat, seginfo); - VOP_UNLOCK(NTOV(dat), 0); -reiterate: - seginfo->reiterate = 0; - nandfs_iterate_system_vnode(su, seginfo); - VOP_LOCK(NTOV(dat), LK_EXCLUSIVE); - nandfs_iterate_system_vnode(dat, seginfo); - VOP_UNLOCK(NTOV(dat), 0); - if (seginfo->reiterate) - goto reiterate; - if (!(seginfo->curseg) || !seginfo->curseg->num_blocks) { - error = create_segment(seginfo); - if (error) { - clean_seginfo(seginfo, 0); - delete_seginfo(seginfo); - goto error_locks; - } - goto reiterate; - } - - /* Reiterate all blocks and assign physical block number */ - nandfs_seginfo_assign_pblk(seginfo); - - /* Fill superroot */ - error = nandfs_add_superroot(seginfo); - if (error) { - clean_seginfo(seginfo, 0); - delete_seginfo(seginfo); - goto error_locks; - } - KASSERT(!(seginfo->reiterate), ("reiteration after superroot")); - - /* Fill checkpoint data */ - nandfs_set_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1, - &ifile->nn_inode, seginfo->blocks); - - LIST_FOREACH(seg, &seginfo->seg_list, seg_link) - nandfs_update_segment(fsdev, seg->seg_num, - seg->nblocks + seg->segsum_blocks); - - VOP_LOCK(NTOV(dat), LK_EXCLUSIVE); - error = save_seginfo(seginfo, 1); - if (error) { - clean_seginfo(seginfo, 1); - delete_seginfo(seginfo); - goto error_dat; - } - VOP_UNLOCK(NTOV(dat), 0); - } - - VOP_UNLOCK(NTOV(cp), 0); - VOP_UNLOCK(NTOV(gc), 0); - VOP_UNLOCK(NTOV(ifile), 0); - - nandfs_process_segments(fsdev); - - VOP_UNLOCK(NTOV(su), 0); - - delete_seginfo(seginfo); - - /* - * XXX: a hack, will go away soon - */ - if ((NTOV(dat)->v_bufobj.bo_dirty.bv_cnt != 0 || - NTOV(cp)->v_bufobj.bo_dirty.bv_cnt != 0 || - NTOV(gc)->v_bufobj.bo_dirty.bv_cnt != 0 || - NTOV(ifile)->v_bufobj.bo_dirty.bv_cnt != 0 || - NTOV(su)->v_bufobj.bo_dirty.bv_cnt != 0) && - (flags & NANDFS_UMOUNT)) { - DPRINTF(SYNC, ("%s: RERUN\n", __func__)); - goto again; - } - - MPASS(fsdev->nd_free_base == NULL); - - lockmgr(&fsdev->nd_seg_const, LK_RELEASE, NULL); - - if (cno_changed) { - if ((nandfs_cps_between_sblocks != 0 && - fsdev->nd_last_cno % nandfs_cps_between_sblocks == 0) || - flags & NANDFS_UMOUNT) - nandfs_write_superblock(fsdev); - } - - DPRINTF(SYNC, ("%s: END\n", __func__)); - return (0); -error_dat: - VOP_UNLOCK(NTOV(dat), 0); -error_locks: - VOP_UNLOCK(NTOV(cp), 0); - VOP_UNLOCK(NTOV(gc), 0); - VOP_UNLOCK(NTOV(ifile), 0); - VOP_UNLOCK(NTOV(su), 0); - lockmgr(&fsdev->nd_seg_const, LK_RELEASE, NULL); - - return (error); -} - -#ifdef DDB -/* - * Show details about the given NANDFS mount point. - */ -DB_SHOW_COMMAND(nandfs, db_show_nandfs) -{ - struct mount *mp; - struct nandfs_device *nffsdev; - struct nandfs_segment *seg; - struct nandfsmount *nmp; - struct buf *bp; - struct vnode *vp; - - if (!have_addr) { - db_printf("\nUsage: show nandfs <mount_addr>\n"); - return; - } - - mp = (struct mount *)addr; - db_printf("%p %s on %s (%s)\n", mp, mp->mnt_stat.f_mntfromname, - mp->mnt_stat.f_mntonname, mp->mnt_stat.f_fstypename); - - - nmp = (struct nandfsmount *)(mp->mnt_data); - nffsdev = nmp->nm_nandfsdev; - db_printf("dev vnode:%p\n", nffsdev->nd_devvp); - db_printf("blocksize:%jx last cno:%jx last pseg:%jx seg num:%jx\n", - (uintmax_t)nffsdev->nd_blocksize, (uintmax_t)nffsdev->nd_last_cno, - (uintmax_t)nffsdev->nd_last_pseg, (uintmax_t)nffsdev->nd_seg_num); - db_printf("system nodes: dat:%p cp:%p su:%p ifile:%p gc:%p\n", - nffsdev->nd_dat_node, nffsdev->nd_cp_node, nffsdev->nd_su_node, - nmp->nm_ifile_node, nffsdev->nd_gc_node); - - if (nffsdev->nd_seginfo != NULL) { - LIST_FOREACH(seg, &nffsdev->nd_seginfo->seg_list, seg_link) { - db_printf("seg: %p\n", seg); - TAILQ_FOREACH(bp, &seg->segsum, - b_cluster.cluster_entry) - db_printf("segbp %p\n", bp); - TAILQ_FOREACH(bp, &seg->data, - b_cluster.cluster_entry) { - vp = bp->b_vp; - db_printf("bp:%p bp->b_vp:%p ino:%jx\n", bp, vp, - (uintmax_t)(vp ? VTON(vp)->nn_ino : 0)); - } - } - } -} -#endif diff --git a/sys/fs/nandfs/nandfs_subr.c b/sys/fs/nandfs/nandfs_subr.c deleted file mode 100644 index 0a3f65a505438..0000000000000 --- a/sys/fs/nandfs/nandfs_subr.c +++ /dev/null @@ -1,1091 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf - * Copyright (c) 2008, 2009 Reinoud Zandijk - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * From: NetBSD: nilfs_subr.c,v 1.4 2009/07/29 17:06:57 reinoud - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/gsb_crc32.h> -#include <sys/namei.h> -#include <sys/resourcevar.h> -#include <sys/kernel.h> -#include <sys/file.h> -#include <sys/stat.h> -#include <sys/buf.h> -#include <sys/bio.h> -#include <sys/proc.h> -#include <sys/mount.h> -#include <sys/vnode.h> -#include <sys/signalvar.h> -#include <sys/malloc.h> -#include <sys/dirent.h> -#include <sys/lockf.h> -#include <sys/libkern.h> - -#include <geom/geom.h> -#include <geom/geom_vfs.h> - -#include <vm/vm.h> -#include <vm/vm_extern.h> - -#include <machine/_inttypes.h> -#include "nandfs_mount.h" -#include "nandfs.h" -#include "nandfs_subr.h" - -MALLOC_DEFINE(M_NANDFSMNT, "nandfs_mount", "NANDFS mount"); -MALLOC_DEFINE(M_NANDFSTEMP, "nandfs_tmt", "NANDFS tmp"); - -uma_zone_t nandfs_node_zone; - -void nandfs_bdflush(struct bufobj *bo, struct buf *bp); -int nandfs_bufsync(struct bufobj *bo, int waitfor); - -struct buf_ops buf_ops_nandfs = { - .bop_name = "buf_ops_nandfs", - .bop_write = bufwrite, - .bop_strategy = bufstrategy, - .bop_sync = nandfs_bufsync, - .bop_bdflush = nandfs_bdflush, -}; - -int -nandfs_bufsync(struct bufobj *bo, int waitfor) -{ - struct vnode *vp; - int error = 0; - - vp = bo2vnode(bo); - - ASSERT_VOP_LOCKED(vp, __func__); - error = nandfs_sync_file(vp); - if (error) - nandfs_warning("%s: cannot flush buffers err:%d\n", - __func__, error); - - return (error); -} - -void -nandfs_bdflush(bo, bp) - struct bufobj *bo; - struct buf *bp; -{ - struct vnode *vp; - int error; - - if (bo->bo_dirty.bv_cnt <= ((dirtybufthresh * 8) / 10)) - return; - - vp = bp->b_vp; - if (NANDFS_SYS_NODE(VTON(vp)->nn_ino)) - return; - - if (NANDFS_IS_INDIRECT(bp)) - return; - - error = nandfs_sync_file(vp); - if (error) - nandfs_warning("%s: cannot flush buffers err:%d\n", - __func__, error); -} - -int -nandfs_init(struct vfsconf *vfsp) -{ - - nandfs_node_zone = uma_zcreate("nandfs node zone", - sizeof(struct nandfs_node), NULL, NULL, NULL, NULL, 0, 0); - - return (0); -} - -int -nandfs_uninit(struct vfsconf *vfsp) -{ - - uma_zdestroy(nandfs_node_zone); - return (0); -} - -/* Basic calculators */ -uint64_t -nandfs_get_segnum_of_block(struct nandfs_device *nandfsdev, - nandfs_daddr_t blocknr) -{ - uint64_t segnum, blks_per_seg; - - MPASS(blocknr >= nandfsdev->nd_fsdata.f_first_data_block); - - blks_per_seg = nandfsdev->nd_fsdata.f_blocks_per_segment; - - segnum = blocknr / blks_per_seg; - segnum -= nandfsdev->nd_fsdata.f_first_data_block / blks_per_seg; - - DPRINTF(SYNC, ("%s: returning blocknr %jx -> segnum %jx\n", __func__, - blocknr, segnum)); - - return (segnum); -} - -void -nandfs_get_segment_range(struct nandfs_device *nandfsdev, uint64_t segnum, - uint64_t *seg_start, uint64_t *seg_end) -{ - uint64_t blks_per_seg; - - blks_per_seg = nandfsdev->nd_fsdata.f_blocks_per_segment; - *seg_start = nandfsdev->nd_fsdata.f_first_data_block + - blks_per_seg * segnum; - if (seg_end != NULL) - *seg_end = *seg_start + blks_per_seg -1; -} - -void nandfs_calc_mdt_consts(struct nandfs_device *nandfsdev, - struct nandfs_mdt *mdt, int entry_size) -{ - uint32_t blocksize = nandfsdev->nd_blocksize; - - mdt->entries_per_group = blocksize * 8; - mdt->entries_per_block = blocksize / entry_size; - - mdt->blocks_per_group = - (mdt->entries_per_group -1) / mdt->entries_per_block + 1 + 1; - mdt->groups_per_desc_block = - blocksize / sizeof(struct nandfs_block_group_desc); - mdt->blocks_per_desc_block = - mdt->groups_per_desc_block * mdt->blocks_per_group + 1; -} - -int -nandfs_dev_bread(struct nandfs_device *nandfsdev, nandfs_lbn_t blocknr, - struct ucred *cred, int flags, struct buf **bpp) -{ - int blk2dev = nandfsdev->nd_blocksize / DEV_BSIZE; - int error; - - DPRINTF(BLOCK, ("%s: read from block %jx vp %p\n", __func__, - blocknr * blk2dev, nandfsdev->nd_devvp)); - error = bread(nandfsdev->nd_devvp, blocknr * blk2dev, - nandfsdev->nd_blocksize, NOCRED, bpp); - if (error) - nandfs_error("%s: cannot read from device - blk:%jx\n", - __func__, blocknr); - return (error); -} - -/* Read on a node */ -int -nandfs_bread(struct nandfs_node *node, nandfs_lbn_t blocknr, - struct ucred *cred, int flags, struct buf **bpp) -{ - nandfs_daddr_t vblk; - int error; - - DPRINTF(BLOCK, ("%s: vp:%p lbn:%#jx\n", __func__, NTOV(node), - blocknr)); - - error = bread(NTOV(node), blocknr, node->nn_nandfsdev->nd_blocksize, - cred, bpp); - - KASSERT(error == 0, ("%s: vp:%p lbn:%#jx err:%d\n", __func__, - NTOV(node), blocknr, error)); - - if (!nandfs_vblk_get(*bpp) && - ((*bpp)->b_flags & B_CACHE) && node->nn_ino != NANDFS_DAT_INO) { - nandfs_bmap_lookup(node, blocknr, &vblk); - nandfs_vblk_set(*bpp, vblk); - } - return (error); -} - -int -nandfs_bread_meta(struct nandfs_node *node, nandfs_lbn_t blocknr, - struct ucred *cred, int flags, struct buf **bpp) -{ - nandfs_daddr_t vblk; - int error; - - DPRINTF(BLOCK, ("%s: vp:%p lbn:%#jx\n", __func__, NTOV(node), - blocknr)); - - error = bread(NTOV(node), blocknr, node->nn_nandfsdev->nd_blocksize, - cred, bpp); - - KASSERT(error == 0, ("%s: vp:%p lbn:%#jx err:%d\n", __func__, - NTOV(node), blocknr, error)); - - if (!nandfs_vblk_get(*bpp) && - ((*bpp)->b_flags & B_CACHE) && node->nn_ino != NANDFS_DAT_INO) { - nandfs_bmap_lookup(node, blocknr, &vblk); - nandfs_vblk_set(*bpp, vblk); - } - - return (error); -} - -int -nandfs_bdestroy(struct nandfs_node *node, nandfs_daddr_t vblk) -{ - int error; - - if (!NANDFS_SYS_NODE(node->nn_ino)) - NANDFS_WRITEASSERT(node->nn_nandfsdev); - - error = nandfs_vblock_end(node->nn_nandfsdev, vblk); - if (error) { - nandfs_error("%s: ending vblk: %jx failed\n", - __func__, (uintmax_t)vblk); - return (error); - } - node->nn_inode.i_blocks--; - - return (0); -} - -int -nandfs_bcreate(struct nandfs_node *node, nandfs_lbn_t blocknr, - struct ucred *cred, int flags, struct buf **bpp) -{ - int error; - - ASSERT_VOP_LOCKED(NTOV(node), __func__); - if (!NANDFS_SYS_NODE(node->nn_ino)) - NANDFS_WRITEASSERT(node->nn_nandfsdev); - - DPRINTF(BLOCK, ("%s: vp:%p lbn:%#jx\n", __func__, NTOV(node), - blocknr)); - - *bpp = getblk(NTOV(node), blocknr, node->nn_nandfsdev->nd_blocksize, - 0, 0, 0); - - KASSERT((*bpp), ("%s: vp:%p lbn:%#jx\n", __func__, - NTOV(node), blocknr)); - - if (*bpp) { - vfs_bio_clrbuf(*bpp); - (*bpp)->b_blkno = ~(0); /* To avoid VOP_BMAP in bdwrite */ - error = nandfs_bmap_insert_block(node, blocknr, *bpp); - if (error) { - nandfs_warning("%s: failed bmap insert node:%p" - " blk:%jx\n", __func__, node, blocknr); - brelse(*bpp); - return (error); - } - node->nn_inode.i_blocks++; - - return (0); - } - - return (-1); -} - -int -nandfs_bcreate_meta(struct nandfs_node *node, nandfs_lbn_t blocknr, - struct ucred *cred, int flags, struct buf **bpp) -{ - struct nandfs_device *fsdev; - nandfs_daddr_t vblk; - int error; - - ASSERT_VOP_LOCKED(NTOV(node), __func__); - NANDFS_WRITEASSERT(node->nn_nandfsdev); - - DPRINTF(BLOCK, ("%s: vp:%p lbn:%#jx\n", __func__, NTOV(node), - blocknr)); - - fsdev = node->nn_nandfsdev; - - *bpp = getblk(NTOV(node), blocknr, node->nn_nandfsdev->nd_blocksize, - 0, 0, 0); - - KASSERT((*bpp), ("%s: vp:%p lbn:%#jx\n", __func__, - NTOV(node), blocknr)); - - memset((*bpp)->b_data, 0, fsdev->nd_blocksize); - - vfs_bio_clrbuf(*bpp); - (*bpp)->b_blkno = ~(0); /* To avoid VOP_BMAP in bdwrite */ - - nandfs_buf_set(*bpp, NANDFS_VBLK_ASSIGNED); - - if (node->nn_ino != NANDFS_DAT_INO) { - error = nandfs_vblock_alloc(fsdev, &vblk); - if (error) { - nandfs_buf_clear(*bpp, NANDFS_VBLK_ASSIGNED); - brelse(*bpp); - return (error); - } - } else - vblk = fsdev->nd_fakevblk++; - - nandfs_vblk_set(*bpp, vblk); - - nandfs_bmap_insert_block(node, blocknr, *bpp); - return (0); -} - -/* Translate index to a file block number and an entry */ -void -nandfs_mdt_trans(struct nandfs_mdt *mdt, uint64_t index, - nandfs_lbn_t *blocknr, uint32_t *entry_in_block) -{ - uint64_t blknr; - uint64_t group, group_offset, blocknr_in_group; - uint64_t desc_block, desc_offset; - - /* Calculate our offset in the file */ - group = index / mdt->entries_per_group; - group_offset = index % mdt->entries_per_group; - desc_block = group / mdt->groups_per_desc_block; - desc_offset = group % mdt->groups_per_desc_block; - blocknr_in_group = group_offset / mdt->entries_per_block; - - /* To descgroup offset */ - blknr = 1 + desc_block * mdt->blocks_per_desc_block; - - /* To group offset */ - blknr += desc_offset * mdt->blocks_per_group; - - /* To actual file block */ - blknr += 1 + blocknr_in_group; - - *blocknr = blknr; - *entry_in_block = group_offset % mdt->entries_per_block; -} - -void -nandfs_mdt_trans_blk(struct nandfs_mdt *mdt, uint64_t index, - uint64_t *desc, uint64_t *bitmap, nandfs_lbn_t *blocknr, - uint32_t *entry_in_block) -{ - uint64_t blknr; - uint64_t group, group_offset, blocknr_in_group; - uint64_t desc_block, desc_offset; - - /* Calculate our offset in the file */ - group = index / mdt->entries_per_group; - group_offset = index % mdt->entries_per_group; - desc_block = group / mdt->groups_per_desc_block; - desc_offset = group % mdt->groups_per_desc_block; - blocknr_in_group = group_offset / mdt->entries_per_block; - - /* To descgroup offset */ - *desc = desc_block * mdt->blocks_per_desc_block; - blknr = 1 + desc_block * mdt->blocks_per_desc_block; - - /* To group offset */ - blknr += desc_offset * mdt->blocks_per_group; - *bitmap = blknr; - - /* To actual file block */ - blknr += 1 + blocknr_in_group; - - *blocknr = blknr; - *entry_in_block = group_offset % mdt->entries_per_block; - - DPRINTF(ALLOC, - ("%s: desc_buf: %jx bitmap_buf: %jx entry_buf: %jx entry: %x\n", - __func__, (uintmax_t)*desc, (uintmax_t)*bitmap, - (uintmax_t)*blocknr, *entry_in_block)); -} - -int -nandfs_vtop(struct nandfs_node *node, nandfs_daddr_t vblocknr, - nandfs_daddr_t *pblocknr) -{ - struct nandfs_node *dat_node; - struct nandfs_dat_entry *entry; - struct buf *bp; - nandfs_lbn_t ldatblknr; - uint32_t entry_in_block; - int locked, error; - - if (node->nn_ino == NANDFS_DAT_INO || node->nn_ino == NANDFS_GC_INO) { - *pblocknr = vblocknr; - return (0); - } - - /* only translate valid vblocknrs */ - if (vblocknr == 0) - return (0); - - dat_node = node->nn_nandfsdev->nd_dat_node; - nandfs_mdt_trans(&node->nn_nandfsdev->nd_dat_mdt, vblocknr, &ldatblknr, - &entry_in_block); - - locked = NANDFS_VOP_ISLOCKED(NTOV(dat_node)); - if (!locked) - VOP_LOCK(NTOV(dat_node), LK_SHARED); - error = nandfs_bread(dat_node, ldatblknr, NOCRED, 0, &bp); - if (error) { - DPRINTF(TRANSLATE, ("vtop: can't read in DAT block %#jx!\n", - (uintmax_t)ldatblknr)); - brelse(bp); - VOP_UNLOCK(NTOV(dat_node), 0); - return (error); - } - - /* Get our translation */ - entry = ((struct nandfs_dat_entry *) bp->b_data) + entry_in_block; - DPRINTF(TRANSLATE, ("\tentry %p data %p entry_in_block %x\n", - entry, bp->b_data, entry_in_block)) - DPRINTF(TRANSLATE, ("\tvblk %#jx -> %#jx for cp [%#jx-%#jx]\n", - (uintmax_t)vblocknr, (uintmax_t)entry->de_blocknr, - (uintmax_t)entry->de_start, (uintmax_t)entry->de_end)); - - *pblocknr = entry->de_blocknr; - brelse(bp); - if (!locked) - VOP_UNLOCK(NTOV(dat_node), 0); - - MPASS(*pblocknr >= node->nn_nandfsdev->nd_fsdata.f_first_data_block || - *pblocknr == 0); - - return (0); -} - -int -nandfs_segsum_valid(struct nandfs_segment_summary *segsum) -{ - - return (segsum->ss_magic == NANDFS_SEGSUM_MAGIC); -} - -int -nandfs_load_segsum(struct nandfs_device *fsdev, nandfs_daddr_t blocknr, - struct nandfs_segment_summary *segsum) -{ - struct buf *bp; - int error; - - DPRINTF(VOLUMES, ("nandfs: try segsum at block %jx\n", - (uintmax_t)blocknr)); - - error = nandfs_dev_bread(fsdev, blocknr, NOCRED, 0, &bp); - if (error) - return (error); - - memcpy(segsum, bp->b_data, sizeof(struct nandfs_segment_summary)); - brelse(bp); - - if (!nandfs_segsum_valid(segsum)) { - DPRINTF(VOLUMES, ("%s: bad magic pseg:%jx\n", __func__, - blocknr)); - return (EINVAL); - } - - return (error); -} - -static int -nandfs_load_super_root(struct nandfs_device *nandfsdev, - struct nandfs_segment_summary *segsum, uint64_t pseg) -{ - struct nandfs_super_root super_root; - struct buf *bp; - uint64_t blocknr; - uint32_t super_root_crc, comp_crc; - int off, error; - - /* Check if there is a superroot */ - if ((segsum->ss_flags & NANDFS_SS_SR) == 0) { - DPRINTF(VOLUMES, ("%s: no super root in pseg:%jx\n", __func__, - pseg)); - return (ENOENT); - } - - /* Get our super root, located at the end of the pseg */ - blocknr = pseg + segsum->ss_nblocks - 1; - DPRINTF(VOLUMES, ("%s: try at %#jx\n", __func__, (uintmax_t)blocknr)); - - error = nandfs_dev_bread(nandfsdev, blocknr, NOCRED, 0, &bp); - if (error) - return (error); - - memcpy(&super_root, bp->b_data, sizeof(struct nandfs_super_root)); - brelse(bp); - - /* Check super root CRC */ - super_root_crc = super_root.sr_sum; - off = sizeof(super_root.sr_sum); - comp_crc = crc32((uint8_t *)&super_root + off, - NANDFS_SR_BYTES - off); - - if (super_root_crc != comp_crc) { - DPRINTF(VOLUMES, ("%s: invalid crc:%#x [expect:%#x]\n", - __func__, super_root_crc, comp_crc)); - return (EINVAL); - } - - nandfsdev->nd_super_root = super_root; - DPRINTF(VOLUMES, ("%s: got valid superroot\n", __func__)); - - return (0); -} - -/* - * Search for the last super root recorded. - */ -int -nandfs_search_super_root(struct nandfs_device *nandfsdev) -{ - struct nandfs_super_block *super; - struct nandfs_segment_summary segsum; - uint64_t seg_start, seg_end, cno, seq, create, pseg; - uint64_t segnum; - int error, found; - - error = found = 0; - - /* Search for last super root */ - pseg = nandfsdev->nd_super.s_last_pseg; - segnum = nandfs_get_segnum_of_block(nandfsdev, pseg); - - cno = nandfsdev->nd_super.s_last_cno; - create = seq = 0; - DPRINTF(VOLUMES, ("%s: start in pseg %#jx\n", __func__, - (uintmax_t)pseg)); - - for (;;) { - error = nandfs_load_segsum(nandfsdev, pseg, &segsum); - if (error) - break; - - if (segsum.ss_seq < seq || segsum.ss_create < create) - break; - - /* Try to load super root */ - if (segsum.ss_flags & NANDFS_SS_SR) { - error = nandfs_load_super_root(nandfsdev, &segsum, pseg); - if (error) - break; /* confused */ - found = 1; - - super = &nandfsdev->nd_super; - nandfsdev->nd_last_segsum = segsum; - super->s_last_pseg = pseg; - super->s_last_cno = cno++; - super->s_last_seq = segsum.ss_seq; - super->s_state = NANDFS_VALID_FS; - seq = segsum.ss_seq; - create = segsum.ss_create; - } else { - seq = segsum.ss_seq; - create = segsum.ss_create; - } - - /* Calculate next partial segment location */ - pseg += segsum.ss_nblocks; - DPRINTF(VOLUMES, ("%s: next partial seg is %jx\n", __func__, - (uintmax_t)pseg)); - - /* Did we reach the end of the segment? if so, go to the next */ - nandfs_get_segment_range(nandfsdev, segnum, &seg_start, - &seg_end); - if (pseg >= seg_end) { - pseg = segsum.ss_next; - DPRINTF(VOLUMES, - (" partial seg oor next is %jx[%jx - %jx]\n", - (uintmax_t)pseg, (uintmax_t)seg_start, - (uintmax_t)seg_end)); - } - segnum = nandfs_get_segnum_of_block(nandfsdev, pseg); - } - - if (error && !found) - return (error); - - return (0); -} - -int -nandfs_get_node_raw(struct nandfs_device *nandfsdev, struct nandfsmount *nmp, - uint64_t ino, struct nandfs_inode *inode, struct nandfs_node **nodep) -{ - struct nandfs_node *node; - struct vnode *nvp; - struct mount *mp; - int error; - - *nodep = NULL; - - /* Associate with mountpoint if present */ - if (nmp) { - mp = nmp->nm_vfs_mountp; - error = getnewvnode("nandfs", mp, &nandfs_vnodeops, &nvp); - if (error) - return (error); - } else { - mp = NULL; - error = getnewvnode("snandfs", mp, &nandfs_system_vnodeops, - &nvp); - if (error) - return (error); - } - - if (mp) - NANDFS_WRITELOCK(nandfsdev); - - DPRINTF(IFILE, ("%s: ino: %#jx -> vp: %p\n", - __func__, (uintmax_t)ino, nvp)); - /* Lock node */ - lockmgr(nvp->v_vnlock, LK_EXCLUSIVE, NULL); - - if (mp) { - error = insmntque(nvp, mp); - if (error != 0) { - *nodep = NULL; - return (error); - } - } - - node = uma_zalloc(nandfs_node_zone, M_WAITOK | M_ZERO); - - /* Crosslink */ - node->nn_vnode = nvp; - nvp->v_bufobj.bo_ops = &buf_ops_nandfs; - node->nn_nmp = nmp; - node->nn_nandfsdev = nandfsdev; - nvp->v_data = node; - - /* Initiase NANDFS node */ - node->nn_ino = ino; - if (inode != NULL) - node->nn_inode = *inode; - - nandfs_vinit(nvp, ino); - - /* Return node */ - *nodep = node; - DPRINTF(IFILE, ("%s: ino:%#jx vp:%p node:%p\n", - __func__, (uintmax_t)ino, nvp, *nodep)); - - return (0); -} - -int -nandfs_get_node(struct nandfsmount *nmp, uint64_t ino, - struct nandfs_node **nodep) -{ - struct nandfs_device *nandfsdev; - struct nandfs_inode inode, *entry; - struct vnode *nvp, *vpp; - struct thread *td; - struct buf *bp; - uint64_t ivblocknr; - uint32_t entry_in_block; - int error; - - /* Look up node in hash table */ - td = curthread; - *nodep = NULL; - - if ((ino < NANDFS_ATIME_INO) && (ino != NANDFS_ROOT_INO)) { - printf("nandfs_get_node: system ino %"PRIu64" not in mount " - "point!\n", ino); - return (ENOENT); - } - - error = vfs_hash_get(nmp->nm_vfs_mountp, ino, LK_EXCLUSIVE, td, &nvp, - NULL, NULL); - if (error) - return (error); - - if (nvp != NULL) { - *nodep = (struct nandfs_node *)nvp->v_data; - return (0); - } - - /* Look up inode structure in mountpoints ifile */ - nandfsdev = nmp->nm_nandfsdev; - nandfs_mdt_trans(&nandfsdev->nd_ifile_mdt, ino, &ivblocknr, - &entry_in_block); - - VOP_LOCK(NTOV(nmp->nm_ifile_node), LK_SHARED); - error = nandfs_bread(nmp->nm_ifile_node, ivblocknr, NOCRED, 0, &bp); - if (error) { - brelse(bp); - VOP_UNLOCK(NTOV(nmp->nm_ifile_node), 0); - return (ENOENT); - } - - /* Get inode entry */ - entry = (struct nandfs_inode *) bp->b_data + entry_in_block; - memcpy(&inode, entry, sizeof(struct nandfs_inode)); - brelse(bp); - VOP_UNLOCK(NTOV(nmp->nm_ifile_node), 0); - - /* Get node */ - error = nandfs_get_node_raw(nmp->nm_nandfsdev, nmp, ino, &inode, nodep); - if (error) { - *nodep = NULL; - return (error); - } - - nvp = (*nodep)->nn_vnode; - error = vfs_hash_insert(nvp, ino, 0, td, &vpp, NULL, NULL); - if (error) { - *nodep = NULL; - return (error); - } - - return (error); -} - -void -nandfs_dispose_node(struct nandfs_node **nodep) -{ - struct nandfs_node *node; - struct vnode *vp; - - /* Protect against rogue values */ - node = *nodep; - if (!node) { - return; - } - DPRINTF(NODE, ("nandfs_dispose_node: %p\n", *nodep)); - - vp = NTOV(node); - vp->v_data = NULL; - - /* Free our associated memory */ - uma_zfree(nandfs_node_zone, node); - - *nodep = NULL; -} - -int -nandfs_lookup_name_in_dir(struct vnode *dvp, const char *name, int namelen, - uint64_t *ino, int *found, uint64_t *off) -{ - struct nandfs_node *dir_node = VTON(dvp); - struct nandfs_dir_entry *ndirent; - struct buf *bp; - uint64_t file_size, diroffset, blkoff; - uint64_t blocknr; - uint32_t blocksize = dir_node->nn_nandfsdev->nd_blocksize; - uint8_t *pos, name_len; - int error; - - *found = 0; - - DPRINTF(VNCALL, ("%s: %s file\n", __func__, name)); - if (dvp->v_type != VDIR) { - return (ENOTDIR); - } - - /* Get directory filesize */ - file_size = dir_node->nn_inode.i_size; - - /* Walk the directory */ - diroffset = 0; - blocknr = 0; - blkoff = 0; - error = nandfs_bread(dir_node, blocknr, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (EIO); - } - - while (diroffset < file_size) { - if (blkoff >= blocksize) { - blkoff = 0; blocknr++; - brelse(bp); - error = nandfs_bread(dir_node, blocknr, NOCRED, 0, - &bp); - if (error) { - brelse(bp); - return (EIO); - } - } - - /* Read in one dirent */ - pos = (uint8_t *) bp->b_data + blkoff; - ndirent = (struct nandfs_dir_entry *) pos; - name_len = ndirent->name_len; - - if ((name_len == namelen) && - (strncmp(name, ndirent->name, name_len) == 0) && - (ndirent->inode != 0)) { - *ino = ndirent->inode; - *off = diroffset; - DPRINTF(LOOKUP, ("found `%.*s` with ino %"PRIx64"\n", - name_len, ndirent->name, *ino)); - *found = 1; - break; - } - - /* Advance */ - diroffset += ndirent->rec_len; - blkoff += ndirent->rec_len; - } - brelse(bp); - - return (error); -} - -int -nandfs_get_fsinfo(struct nandfsmount *nmp, struct nandfs_fsinfo *fsinfo) -{ - struct nandfs_device *fsdev; - - fsdev = nmp->nm_nandfsdev; - - memcpy(&fsinfo->fs_fsdata, &fsdev->nd_fsdata, sizeof(fsdev->nd_fsdata)); - memcpy(&fsinfo->fs_super, &fsdev->nd_super, sizeof(fsdev->nd_super)); - snprintf(fsinfo->fs_dev, sizeof(fsinfo->fs_dev), - "%s", nmp->nm_vfs_mountp->mnt_stat.f_mntfromname); - - return (0); -} - -void -nandfs_inode_init(struct nandfs_inode *inode, uint16_t mode) -{ - struct timespec ts; - - vfs_timestamp(&ts); - - inode->i_blocks = 0; - inode->i_size = 0; - inode->i_ctime = ts.tv_sec; - inode->i_ctime_nsec = ts.tv_nsec; - inode->i_mtime = ts.tv_sec; - inode->i_mtime_nsec = ts.tv_nsec; - inode->i_mode = mode; - inode->i_links_count = 1; - if (S_ISDIR(mode)) - inode->i_links_count = 2; - inode->i_flags = 0; - - inode->i_special = 0; - memset(inode->i_db, 0, sizeof(inode->i_db)); - memset(inode->i_ib, 0, sizeof(inode->i_ib)); -} - -void -nandfs_inode_destroy(struct nandfs_inode *inode) -{ - - MPASS(inode->i_blocks == 0); - bzero(inode, sizeof(*inode)); -} - -int -nandfs_fs_full(struct nandfs_device *nffsdev) -{ - uint64_t space, bps; - - bps = nffsdev->nd_fsdata.f_blocks_per_segment; - space = (nffsdev->nd_clean_segs - 1) * bps; - - DPRINTF(BUF, ("%s: bufs:%jx space:%jx\n", __func__, - (uintmax_t)nffsdev->nd_dirty_bufs, (uintmax_t)space)); - - if (nffsdev->nd_dirty_bufs + (nffsdev->nd_segs_reserved * bps) >= space) - return (1); - - return (0); -} - -static int -_nandfs_dirty_buf(struct buf *bp, int dirty_meta, int force) -{ - struct nandfs_device *nffsdev; - struct nandfs_node *node; - uint64_t ino, bps; - - if (NANDFS_ISGATHERED(bp)) { - bqrelse(bp); - return (0); - } - if ((bp->b_flags & (B_MANAGED | B_DELWRI)) == (B_MANAGED | B_DELWRI)) { - bqrelse(bp); - return (0); - } - - node = VTON(bp->b_vp); - nffsdev = node->nn_nandfsdev; - DPRINTF(BUF, ("%s: buf:%p\n", __func__, bp)); - ino = node->nn_ino; - - if (nandfs_fs_full(nffsdev) && !NANDFS_SYS_NODE(ino) && !force) { - brelse(bp); - return (ENOSPC); - } - - bp->b_flags |= B_MANAGED; - bdwrite(bp); - - nandfs_dirty_bufs_increment(nffsdev); - - KASSERT((bp->b_vp), ("vp missing for bp")); - KASSERT((nandfs_vblk_get(bp) || ino == NANDFS_DAT_INO), - ("bp vblk is 0")); - - /* - * To maintain consistency of FS we need to force making - * meta buffers dirty, even if free space is low. - */ - if (dirty_meta && ino != NANDFS_GC_INO) - nandfs_bmap_dirty_blocks(VTON(bp->b_vp), bp, 1); - - bps = nffsdev->nd_fsdata.f_blocks_per_segment; - - if (nffsdev->nd_dirty_bufs >= (bps * nandfs_max_dirty_segs)) { - mtx_lock(&nffsdev->nd_sync_mtx); - if (nffsdev->nd_syncing == 0) { - DPRINTF(SYNC, ("%s: wakeup gc\n", __func__)); - nffsdev->nd_syncing = 1; - wakeup(&nffsdev->nd_syncing); - } - mtx_unlock(&nffsdev->nd_sync_mtx); - } - - return (0); -} - -int -nandfs_dirty_buf(struct buf *bp, int force) -{ - - return (_nandfs_dirty_buf(bp, 1, force)); -} - -int -nandfs_dirty_buf_meta(struct buf *bp, int force) -{ - - return (_nandfs_dirty_buf(bp, 0, force)); -} - -void -nandfs_undirty_buf_fsdev(struct nandfs_device *nffsdev, struct buf *bp) -{ - - BUF_ASSERT_HELD(bp); - - if (bp->b_flags & B_DELWRI) { - bp->b_flags &= ~(B_DELWRI|B_MANAGED); - nandfs_dirty_bufs_decrement(nffsdev); - } - /* - * Since it is now being written, we can clear its deferred write flag. - */ - bp->b_flags &= ~B_DEFERRED; - - brelse(bp); -} - -void -nandfs_undirty_buf(struct buf *bp) -{ - struct nandfs_node *node; - - node = VTON(bp->b_vp); - - nandfs_undirty_buf_fsdev(node->nn_nandfsdev, bp); -} - -void -nandfs_vblk_set(struct buf *bp, nandfs_daddr_t blocknr) -{ - - nandfs_daddr_t *vblk = (nandfs_daddr_t *)(&bp->b_fsprivate1); - *vblk = blocknr; -} - -nandfs_daddr_t -nandfs_vblk_get(struct buf *bp) -{ - - nandfs_daddr_t *vblk = (nandfs_daddr_t *)(&bp->b_fsprivate1); - return (*vblk); -} - -void -nandfs_buf_set(struct buf *bp, uint32_t bits) -{ - uintptr_t flags; - - flags = (uintptr_t)bp->b_fsprivate3; - flags |= (uintptr_t)bits; - bp->b_fsprivate3 = (void *)flags; -} - -void -nandfs_buf_clear(struct buf *bp, uint32_t bits) -{ - uintptr_t flags; - - flags = (uintptr_t)bp->b_fsprivate3; - flags &= ~(uintptr_t)bits; - bp->b_fsprivate3 = (void *)flags; -} - -int -nandfs_buf_check(struct buf *bp, uint32_t bits) -{ - uintptr_t flags; - - flags = (uintptr_t)bp->b_fsprivate3; - if (flags & bits) - return (1); - return (0); -} - -int -nandfs_erase(struct nandfs_device *fsdev, off_t offset, size_t size) -{ - DPRINTF(BLOCK, ("%s: performing erase at offset %jx size %zx\n", - __func__, offset, size)); - - MPASS(size % fsdev->nd_erasesize == 0); - - return (g_delete_data(fsdev->nd_gconsumer, offset, size)); -} - -int -nandfs_vop_islocked(struct vnode *vp) -{ - int islocked; - - islocked = VOP_ISLOCKED(vp); - return (islocked == LK_EXCLUSIVE || islocked == LK_SHARED); -} - -nandfs_daddr_t -nandfs_block_to_dblock(struct nandfs_device *fsdev, nandfs_lbn_t block) -{ - - return (btodb(block * fsdev->nd_blocksize)); -} diff --git a/sys/fs/nandfs/nandfs_subr.h b/sys/fs/nandfs/nandfs_subr.h deleted file mode 100644 index 36c2c9dc2ff2d..0000000000000 --- a/sys/fs/nandfs/nandfs_subr.h +++ /dev/null @@ -1,240 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf - * Copyright (c) 2008, 2009 Reinoud Zandijk - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * From: NetBSD: nilfs_subr.h,v 1.1 2009/07/18 16:31:42 reinoud - * - * $FreeBSD$ - */ - -#ifndef _FS_NANDFS_NANDFS_SUBR_H_ -#define _FS_NANDFS_NANDFS_SUBR_H_ - -struct nandfs_mdt; - -struct nandfs_alloc_request -{ - uint64_t entrynum; - struct buf *bp_desc; - struct buf *bp_bitmap; - struct buf *bp_entry; -}; - -/* Segment creation */ -void nandfs_wakeup_wait_sync(struct nandfs_device *, int); -int nandfs_segment_constructor(struct nandfsmount *, int); -int nandfs_sync_file(struct vnode *); - -/* Basic calculators */ -uint64_t nandfs_get_segnum_of_block(struct nandfs_device *, nandfs_daddr_t); -void nandfs_get_segment_range(struct nandfs_device *, uint64_t, uint64_t *, - uint64_t *); -void nandfs_calc_mdt_consts(struct nandfs_device *, struct nandfs_mdt *, int); - -/* Log reading / volume helpers */ -int nandfs_search_super_root(struct nandfs_device *); - -/* Reading */ -int nandfs_dev_bread(struct nandfs_device *, nandfs_daddr_t, struct ucred *, - int, struct buf **); -int nandfs_bread(struct nandfs_node *, nandfs_lbn_t, struct ucred *, int, - struct buf **); -int nandfs_bread_meta(struct nandfs_node *, nandfs_lbn_t, struct ucred *, int, - struct buf **); -int nandfs_bdestroy(struct nandfs_node *, nandfs_daddr_t); -int nandfs_bcreate(struct nandfs_node *, nandfs_lbn_t, struct ucred *, int, - struct buf **); -int nandfs_bcreate_meta(struct nandfs_node *, nandfs_lbn_t, struct ucred *, - int, struct buf **); -int nandfs_bread_create(struct nandfs_node *, nandfs_lbn_t, struct ucred *, - int, struct buf **); - -/* vtop operations */ -int nandfs_vtop(struct nandfs_node *, nandfs_daddr_t, nandfs_daddr_t *); - -/* Node action implementators */ -int nandfs_vinit(struct vnode *, uint64_t); -int nandfs_get_node(struct nandfsmount *, uint64_t, struct nandfs_node **); -int nandfs_get_node_raw(struct nandfs_device *, struct nandfsmount *, uint64_t, - struct nandfs_inode *, struct nandfs_node **); -void nandfs_dispose_node(struct nandfs_node **); - -void nandfs_itimes(struct vnode *); -int nandfs_lookup_name_in_dir(struct vnode *, const char *, int, uint64_t *, - int *, uint64_t *); -int nandfs_create_node(struct vnode *, struct vnode **, struct vattr *, - struct componentname *); -void nandfs_delete_node(struct nandfs_node *); - -int nandfs_chsize(struct vnode *, u_quad_t, struct ucred *); -int nandfs_dir_detach(struct nandfsmount *, struct nandfs_node *, - struct nandfs_node *, struct componentname *); -int nandfs_dir_attach(struct nandfsmount *, struct nandfs_node *, - struct nandfs_node *, struct vattr *, struct componentname *); - -int nandfs_dirty_buf(struct buf *, int); -int nandfs_dirty_buf_meta(struct buf *, int); -int nandfs_fs_full(struct nandfs_device *); -void nandfs_undirty_buf_fsdev(struct nandfs_device *, struct buf *); -void nandfs_undirty_buf(struct buf *); - -void nandfs_clear_buf(struct buf *); -void nandfs_buf_set(struct buf *, uint32_t); -void nandfs_buf_clear(struct buf *, uint32_t); -int nandfs_buf_check(struct buf *, uint32_t); - -int nandfs_find_free_entry(struct nandfs_mdt *, struct nandfs_node *, - struct nandfs_alloc_request *); -int nandfs_find_entry(struct nandfs_mdt *, struct nandfs_node *, - struct nandfs_alloc_request *); -int nandfs_alloc_entry(struct nandfs_mdt *, struct nandfs_alloc_request *); -void nandfs_abort_entry(struct nandfs_alloc_request *); -int nandfs_free_entry(struct nandfs_mdt *, struct nandfs_alloc_request *); -int nandfs_get_entry_block(struct nandfs_mdt *, struct nandfs_node *, - struct nandfs_alloc_request *, uint32_t *, int); - -/* Inode management. */ -int nandfs_node_create(struct nandfsmount *, struct nandfs_node **, uint16_t); -int nandfs_node_destroy(struct nandfs_node *); -int nandfs_node_update(struct nandfs_node *); -int nandfs_get_node_entry(struct nandfsmount *, struct nandfs_inode **, - uint64_t, struct buf **); -void nandfs_mdt_trans_blk(struct nandfs_mdt *, uint64_t, uint64_t *, - uint64_t *, nandfs_lbn_t *, uint32_t *); - -/* vblock management */ -void nandfs_mdt_trans(struct nandfs_mdt *, uint64_t, nandfs_lbn_t *, uint32_t *); -int nandfs_vblock_alloc(struct nandfs_device *, nandfs_daddr_t *); -int nandfs_vblock_end(struct nandfs_device *, nandfs_daddr_t); -int nandfs_vblock_assign(struct nandfs_device *, nandfs_daddr_t, - nandfs_lbn_t); -int nandfs_vblock_free(struct nandfs_device *, nandfs_daddr_t); - -/* Checkpoint management */ -int nandfs_get_checkpoint(struct nandfs_device *, struct nandfs_node *, - uint64_t); -int nandfs_set_checkpoint(struct nandfs_device *, struct nandfs_node *, - uint64_t, struct nandfs_inode *, uint64_t); - -/* Segment management */ -int nandfs_alloc_segment(struct nandfs_device *, uint64_t *); -int nandfs_update_segment(struct nandfs_device *, uint64_t, uint32_t); -int nandfs_free_segment(struct nandfs_device *, uint64_t); -int nandfs_clear_segment(struct nandfs_device *, uint64_t); -int nandfs_touch_segment(struct nandfs_device *, uint64_t); -int nandfs_markgc_segment(struct nandfs_device *, uint64_t); - -int nandfs_bmap_insert_block(struct nandfs_node *, nandfs_lbn_t, struct buf *); -int nandfs_bmap_update_block(struct nandfs_node *, struct buf *, nandfs_lbn_t); -int nandfs_bmap_update_dat(struct nandfs_node *, nandfs_daddr_t, struct buf *); -int nandfs_bmap_dirty_blocks(struct nandfs_node *, struct buf *, int); -int nandfs_bmap_truncate_mapping(struct nandfs_node *, nandfs_lbn_t, - nandfs_lbn_t); -int nandfs_bmap_lookup(struct nandfs_node *, nandfs_lbn_t, nandfs_daddr_t *); - -/* dirent */ -int nandfs_add_dirent(struct vnode *, uint64_t, char *, long, uint8_t); -int nandfs_remove_dirent(struct vnode *, struct nandfs_node *, - struct componentname *); -int nandfs_update_dirent(struct vnode *, struct nandfs_node *, - struct nandfs_node *); -int nandfs_init_dir(struct vnode *, uint64_t, uint64_t); -int nandfs_update_parent_dir(struct vnode *, uint64_t); - -void nandfs_vblk_set(struct buf *, nandfs_daddr_t); -nandfs_daddr_t nandfs_vblk_get(struct buf *); - -void nandfs_inode_init(struct nandfs_inode *, uint16_t); -void nandfs_inode_destroy(struct nandfs_inode *); - -/* ioctl */ -int nandfs_get_seg_stat(struct nandfs_device *, struct nandfs_seg_stat *); -int nandfs_chng_cpmode(struct nandfs_node *, struct nandfs_cpmode *); -int nandfs_get_cpinfo_ioctl(struct nandfs_node *, struct nandfs_argv *); -int nandfs_delete_cp(struct nandfs_node *, uint64_t start, uint64_t); -int nandfs_make_snap(struct nandfs_device *, uint64_t *); -int nandfs_delete_snap(struct nandfs_device *, uint64_t); -int nandfs_get_cpstat(struct nandfs_node *, struct nandfs_cpstat *); -int nandfs_get_segment_info_ioctl(struct nandfs_device *, struct nandfs_argv *); -int nandfs_get_dat_vinfo_ioctl(struct nandfs_device *, struct nandfs_argv *); -int nandfs_get_dat_bdescs_ioctl(struct nandfs_device *, struct nandfs_argv *); -int nandfs_get_fsinfo(struct nandfsmount *, struct nandfs_fsinfo *); - -int nandfs_get_cpinfo(struct nandfs_node *, uint64_t, uint16_t, - struct nandfs_cpinfo *, uint32_t, uint32_t *); - -nandfs_lbn_t nandfs_get_maxfilesize(struct nandfs_device *); - -int nandfs_write_superblock(struct nandfs_device *); - -extern int nandfs_sync_interval; -extern int nandfs_max_dirty_segs; -extern int nandfs_cps_between_sblocks; - -struct buf *nandfs_geteblk(int, int); - -void nandfs_dirty_bufs_increment(struct nandfs_device *); -void nandfs_dirty_bufs_decrement(struct nandfs_device *); - -int nandfs_start_cleaner(struct nandfs_device *); -int nandfs_stop_cleaner(struct nandfs_device *); - -int nandfs_segsum_valid(struct nandfs_segment_summary *); -int nandfs_load_segsum(struct nandfs_device *, nandfs_daddr_t, - struct nandfs_segment_summary *); -int nandfs_get_segment_info(struct nandfs_device *, struct nandfs_suinfo *, - uint32_t, uint64_t); -int nandfs_get_segment_info_filter(struct nandfs_device *, - struct nandfs_suinfo *, uint32_t, uint64_t, uint64_t *, uint32_t, uint32_t); -int nandfs_get_dat_vinfo(struct nandfs_device *, struct nandfs_vinfo *, - uint32_t); -int nandfs_get_dat_bdescs(struct nandfs_device *, struct nandfs_bdesc *, - uint32_t); - -#define NANDFS_VBLK_ASSIGNED 1 - -#define NANDFS_IS_INDIRECT(bp) ((bp)->b_lblkno < 0) - -int nandfs_erase(struct nandfs_device *, off_t, size_t); - -#define NANDFS_VOP_ISLOCKED(vp) nandfs_vop_islocked((vp)) -int nandfs_vop_islocked(struct vnode *vp); - -nandfs_daddr_t nandfs_block_to_dblock(struct nandfs_device *, nandfs_lbn_t); - -#define DEBUG_MODE -#if defined(DEBUG_MODE) -#define nandfs_error panic -#define nandfs_warning printf -#elif defined(TEST_MODE) -#define nandfs_error printf -#define nandfs_warning printf -#else -#define nandfs_error(...) -#define nandfs_warning(...) -#endif - -#endif /* !_FS_NANDFS_NANDFS_SUBR_H_ */ diff --git a/sys/fs/nandfs/nandfs_sufile.c b/sys/fs/nandfs/nandfs_sufile.c deleted file mode 100644 index 5276008de096c..0000000000000 --- a/sys/fs/nandfs/nandfs_sufile.c +++ /dev/null @@ -1,571 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/conf.h> -#include <sys/kernel.h> -#include <sys/lock.h> -#include <sys/malloc.h> -#include <sys/mount.h> -#include <sys/mutex.h> -#include <sys/namei.h> -#include <sys/sysctl.h> -#include <sys/vnode.h> -#include <sys/buf.h> -#include <sys/bio.h> - -#include <vm/vm.h> -#include <vm/vm_param.h> -#include <vm/vm_kern.h> -#include <vm/vm_page.h> - -#include <geom/geom.h> -#include <geom/geom_vfs.h> - -#include <fs/nandfs/nandfs_mount.h> -#include <fs/nandfs/nandfs.h> -#include <fs/nandfs/nandfs_subr.h> - -#define SU_USAGE_OFF(bp, offset) \ - ((struct nandfs_segment_usage *)((bp)->b_data + offset)) - -static int -nandfs_seg_usage_blk_offset(struct nandfs_device *fsdev, uint64_t seg, - uint64_t *blk, uint64_t *offset) -{ - uint64_t off; - uint16_t seg_size; - - seg_size = fsdev->nd_fsdata.f_segment_usage_size; - - off = roundup(sizeof(struct nandfs_sufile_header), seg_size); - off += (seg * seg_size); - - *blk = off / fsdev->nd_blocksize; - *offset = off % fsdev->nd_blocksize; - return (0); -} - -/* Alloc new segment */ -int -nandfs_alloc_segment(struct nandfs_device *fsdev, uint64_t *seg) -{ - struct nandfs_node *su_node; - struct nandfs_sufile_header *su_header; - struct nandfs_segment_usage *su_usage; - struct buf *bp_header, *bp; - uint64_t blk, vblk, offset, i, rest, nsegments; - uint16_t seg_size; - int error, found; - - seg_size = fsdev->nd_fsdata.f_segment_usage_size; - nsegments = fsdev->nd_fsdata.f_nsegments; - - su_node = fsdev->nd_su_node; - ASSERT_VOP_LOCKED(NTOV(su_node), __func__); - - /* Read header buffer */ - error = nandfs_bread(su_node, 0, NOCRED, 0, &bp_header); - if (error) { - brelse(bp_header); - return (error); - } - - su_header = (struct nandfs_sufile_header *)bp_header->b_data; - - /* Get last allocated segment */ - i = su_header->sh_last_alloc + 1; - - found = 0; - bp = NULL; - while (!found) { - nandfs_seg_usage_blk_offset(fsdev, i, &blk, &offset); - if(blk != 0) { - error = nandfs_bmap_lookup(su_node, blk, &vblk); - if (error) { - nandfs_error("%s: cannot find vblk for blk " - "blk:%jx\n", __func__, blk); - return (error); - } - if (vblk) - error = nandfs_bread(su_node, blk, NOCRED, 0, - &bp); - else - error = nandfs_bcreate(su_node, blk, NOCRED, 0, - &bp); - if (error) { - nandfs_error("%s: cannot create/read " - "vblk:%jx\n", __func__, vblk); - if (bp) - brelse(bp); - return (error); - } - - su_usage = SU_USAGE_OFF(bp, offset); - } else { - su_usage = SU_USAGE_OFF(bp_header, offset); - bp = bp_header; - } - - rest = (fsdev->nd_blocksize - offset) / seg_size; - /* Go through all su usage in block */ - while (rest) { - /* When last check start from beginning */ - if (i == nsegments) - break; - - if (!su_usage->su_flags) { - su_usage->su_flags = 1; - found = 1; - break; - } - su_usage++; - i++; - - /* If all checked return error */ - if (i == su_header->sh_last_alloc) { - DPRINTF(SEG, ("%s: cannot allocate segment \n", - __func__)); - brelse(bp_header); - if (blk != 0) - brelse(bp); - return (1); - } - rest--; - } - if (!found) { - /* Otherwise read another block */ - if (blk != 0) - brelse(bp); - if (i == nsegments) { - blk = 0; - i = 0; - } else - blk++; - offset = 0; - } - } - - if (found) { - *seg = i; - su_header->sh_last_alloc = i; - su_header->sh_ncleansegs--; - su_header->sh_ndirtysegs++; - - fsdev->nd_super.s_free_blocks_count = su_header->sh_ncleansegs * - fsdev->nd_fsdata.f_blocks_per_segment; - fsdev->nd_clean_segs--; - - /* - * It is mostly called from syncer() so we want to force - * making buf dirty. - */ - error = nandfs_dirty_buf(bp_header, 1); - if (error) { - if (bp && bp != bp_header) - brelse(bp); - return (error); - } - if (bp && bp != bp_header) - nandfs_dirty_buf(bp, 1); - - DPRINTF(SEG, ("%s: seg:%#jx\n", __func__, (uintmax_t)i)); - - return (0); - } - - DPRINTF(SEG, ("%s: failed\n", __func__)); - - return (1); -} - -/* - * Make buffer dirty, it will be updated soon but first it need to be - * gathered by syncer. - */ -int -nandfs_touch_segment(struct nandfs_device *fsdev, uint64_t seg) -{ - struct nandfs_node *su_node; - struct buf *bp; - uint64_t blk, offset; - int error; - - su_node = fsdev->nd_su_node; - ASSERT_VOP_LOCKED(NTOV(su_node), __func__); - - nandfs_seg_usage_blk_offset(fsdev, seg, &blk, &offset); - - error = nandfs_bread(su_node, blk, NOCRED, 0, &bp); - if (error) { - brelse(bp); - nandfs_error("%s: cannot preallocate new segment\n", __func__); - return (error); - } else - nandfs_dirty_buf(bp, 1); - - DPRINTF(SEG, ("%s: seg:%#jx\n", __func__, (uintmax_t)seg)); - return (error); -} - -/* Update block count of segment */ -int -nandfs_update_segment(struct nandfs_device *fsdev, uint64_t seg, uint32_t nblks) -{ - struct nandfs_node *su_node; - struct nandfs_segment_usage *su_usage; - struct buf *bp; - uint64_t blk, offset; - int error; - - su_node = fsdev->nd_su_node; - ASSERT_VOP_LOCKED(NTOV(su_node), __func__); - - nandfs_seg_usage_blk_offset(fsdev, seg, &blk, &offset); - - error = nandfs_bread(su_node, blk, NOCRED, 0, &bp); - if (error) { - nandfs_error("%s: read block:%jx to update\n", - __func__, blk); - brelse(bp); - return (error); - } - - su_usage = SU_USAGE_OFF(bp, offset); - su_usage->su_lastmod = fsdev->nd_ts.tv_sec; - su_usage->su_flags = NANDFS_SEGMENT_USAGE_DIRTY; - su_usage->su_nblocks += nblks; - - DPRINTF(SEG, ("%s: seg:%#jx inc:%#x cur:%#x\n", __func__, - (uintmax_t)seg, nblks, su_usage->su_nblocks)); - - nandfs_dirty_buf(bp, 1); - - return (0); -} - -/* Make segment free */ -int -nandfs_free_segment(struct nandfs_device *fsdev, uint64_t seg) -{ - struct nandfs_node *su_node; - struct nandfs_sufile_header *su_header; - struct nandfs_segment_usage *su_usage; - struct buf *bp_header, *bp; - uint64_t blk, offset; - int error; - - su_node = fsdev->nd_su_node; - ASSERT_VOP_LOCKED(NTOV(su_node), __func__); - - /* Read su header */ - error = nandfs_bread(su_node, 0, NOCRED, 0, &bp_header); - if (error) { - brelse(bp_header); - return (error); - } - - su_header = (struct nandfs_sufile_header *)bp_header->b_data; - nandfs_seg_usage_blk_offset(fsdev, seg, &blk, &offset); - - /* Read su usage block if other than su header block */ - if (blk != 0) { - error = nandfs_bread(su_node, blk, NOCRED, 0, &bp); - if (error) { - brelse(bp); - brelse(bp_header); - return (error); - } - } else - bp = bp_header; - - /* Reset su usage data */ - su_usage = SU_USAGE_OFF(bp, offset); - su_usage->su_lastmod = fsdev->nd_ts.tv_sec; - su_usage->su_nblocks = 0; - su_usage->su_flags = 0; - - /* Update clean/dirty counter in header */ - su_header->sh_ncleansegs++; - su_header->sh_ndirtysegs--; - - /* - * Make buffers dirty, called by cleaner - * so force dirty even if no much space left - * on device - */ - nandfs_dirty_buf(bp_header, 1); - if (bp != bp_header) - nandfs_dirty_buf(bp, 1); - - /* Update free block count */ - fsdev->nd_super.s_free_blocks_count = su_header->sh_ncleansegs * - fsdev->nd_fsdata.f_blocks_per_segment; - fsdev->nd_clean_segs++; - - DPRINTF(SEG, ("%s: seg:%#jx\n", __func__, (uintmax_t)seg)); - - return (0); -} - -static int -nandfs_bad_segment(struct nandfs_device *fsdev, uint64_t seg) -{ - struct nandfs_node *su_node; - struct nandfs_segment_usage *su_usage; - struct buf *bp; - uint64_t blk, offset; - int error; - - su_node = fsdev->nd_su_node; - ASSERT_VOP_LOCKED(NTOV(su_node), __func__); - - nandfs_seg_usage_blk_offset(fsdev, seg, &blk, &offset); - - error = nandfs_bread(su_node, blk, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - - su_usage = SU_USAGE_OFF(bp, offset); - su_usage->su_lastmod = fsdev->nd_ts.tv_sec; - su_usage->su_flags = NANDFS_SEGMENT_USAGE_ERROR; - - DPRINTF(SEG, ("%s: seg:%#jx\n", __func__, (uintmax_t)seg)); - - nandfs_dirty_buf(bp, 1); - - return (0); -} - -int -nandfs_markgc_segment(struct nandfs_device *fsdev, uint64_t seg) -{ - struct nandfs_node *su_node; - struct nandfs_segment_usage *su_usage; - struct buf *bp; - uint64_t blk, offset; - int error; - - su_node = fsdev->nd_su_node; - - VOP_LOCK(NTOV(su_node), LK_EXCLUSIVE); - - nandfs_seg_usage_blk_offset(fsdev, seg, &blk, &offset); - - error = nandfs_bread(su_node, blk, NOCRED, 0, &bp); - if (error) { - brelse(bp); - VOP_UNLOCK(NTOV(su_node), 0); - return (error); - } - - su_usage = SU_USAGE_OFF(bp, offset); - MPASS((su_usage->su_flags & NANDFS_SEGMENT_USAGE_GC) == 0); - su_usage->su_flags |= NANDFS_SEGMENT_USAGE_GC; - - brelse(bp); - VOP_UNLOCK(NTOV(su_node), 0); - - DPRINTF(SEG, ("%s: seg:%#jx\n", __func__, (uintmax_t)seg)); - - return (0); -} - -int -nandfs_clear_segment(struct nandfs_device *fsdev, uint64_t seg) -{ - uint64_t offset, segsize; - uint32_t bps, bsize; - int error = 0; - - bps = fsdev->nd_fsdata.f_blocks_per_segment; - bsize = fsdev->nd_blocksize; - segsize = bsize * bps; - nandfs_get_segment_range(fsdev, seg, &offset, NULL); - offset *= bsize; - - DPRINTF(SEG, ("%s: seg:%#jx\n", __func__, (uintmax_t)seg)); - - /* Erase it and mark it bad when fail */ - if (nandfs_erase(fsdev, offset, segsize)) - error = nandfs_bad_segment(fsdev, seg); - - if (error) - return (error); - - /* Mark it free */ - error = nandfs_free_segment(fsdev, seg); - - return (error); -} - -int -nandfs_get_seg_stat(struct nandfs_device *nandfsdev, - struct nandfs_seg_stat *nss) -{ - struct nandfs_sufile_header *suhdr; - struct nandfs_node *su_node; - struct buf *bp; - int err; - - su_node = nandfsdev->nd_su_node; - - NANDFS_WRITELOCK(nandfsdev); - VOP_LOCK(NTOV(su_node), LK_SHARED); - err = nandfs_bread(nandfsdev->nd_su_node, 0, NOCRED, 0, &bp); - if (err) { - brelse(bp); - VOP_UNLOCK(NTOV(su_node), 0); - NANDFS_WRITEUNLOCK(nandfsdev); - return (-1); - } - - suhdr = (struct nandfs_sufile_header *)bp->b_data; - nss->nss_nsegs = nandfsdev->nd_fsdata.f_nsegments; - nss->nss_ncleansegs = suhdr->sh_ncleansegs; - nss->nss_ndirtysegs = suhdr->sh_ndirtysegs; - nss->nss_ctime = 0; - nss->nss_nongc_ctime = nandfsdev->nd_ts.tv_sec; - nss->nss_prot_seq = nandfsdev->nd_seg_sequence; - - brelse(bp); - VOP_UNLOCK(NTOV(su_node), 0); - - NANDFS_WRITEUNLOCK(nandfsdev); - - return (0); -} - -int -nandfs_get_segment_info_ioctl(struct nandfs_device *fsdev, - struct nandfs_argv *nargv) -{ - struct nandfs_suinfo *nsi; - int error; - - if (nargv->nv_nmembs > NANDFS_SEGMENTS_MAX) - return (EINVAL); - - nsi = malloc(sizeof(struct nandfs_suinfo) * nargv->nv_nmembs, - M_NANDFSTEMP, M_WAITOK | M_ZERO); - - error = nandfs_get_segment_info(fsdev, nsi, nargv->nv_nmembs, - nargv->nv_index); - - if (error == 0) - error = copyout(nsi, (void *)(uintptr_t)nargv->nv_base, - sizeof(struct nandfs_suinfo) * nargv->nv_nmembs); - - free(nsi, M_NANDFSTEMP); - return (error); -} - -int -nandfs_get_segment_info(struct nandfs_device *fsdev, struct nandfs_suinfo *nsi, - uint32_t nmembs, uint64_t segment) -{ - - return (nandfs_get_segment_info_filter(fsdev, nsi, nmembs, segment, - NULL, 0, 0)); -} - -int -nandfs_get_segment_info_filter(struct nandfs_device *fsdev, - struct nandfs_suinfo *nsi, uint32_t nmembs, uint64_t segment, - uint64_t *nsegs, uint32_t filter, uint32_t nfilter) -{ - struct nandfs_segment_usage *su; - struct nandfs_node *su_node; - struct buf *bp; - uint64_t curr, blocknr, blockoff, i; - uint32_t flags; - int err = 0; - - curr = ~(0); - - lockmgr(&fsdev->nd_seg_const, LK_EXCLUSIVE, NULL); - su_node = fsdev->nd_su_node; - - VOP_LOCK(NTOV(su_node), LK_SHARED); - - bp = NULL; - if (nsegs != NULL) - *nsegs = 0; - for (i = 0; i < nmembs; segment++) { - if (segment == fsdev->nd_fsdata.f_nsegments) - break; - - nandfs_seg_usage_blk_offset(fsdev, segment, &blocknr, - &blockoff); - - if (i == 0 || curr != blocknr) { - if (bp != NULL) - brelse(bp); - err = nandfs_bread(su_node, blocknr, NOCRED, - 0, &bp); - if (err) { - goto out; - } - curr = blocknr; - } - - su = SU_USAGE_OFF(bp, blockoff); - flags = su->su_flags; - if (segment == fsdev->nd_seg_num || - segment == fsdev->nd_next_seg_num) - flags |= NANDFS_SEGMENT_USAGE_ACTIVE; - - if (nfilter != 0 && (flags & nfilter) != 0) - continue; - if (filter != 0 && (flags & filter) == 0) - continue; - - nsi->nsi_num = segment; - nsi->nsi_lastmod = su->su_lastmod; - nsi->nsi_blocks = su->su_nblocks; - nsi->nsi_flags = flags; - nsi++; - i++; - if (nsegs != NULL) - (*nsegs)++; - } - -out: - if (bp != NULL) - brelse(bp); - VOP_UNLOCK(NTOV(su_node), 0); - lockmgr(&fsdev->nd_seg_const, LK_RELEASE, NULL); - - return (err); -} diff --git a/sys/fs/nandfs/nandfs_vfsops.c b/sys/fs/nandfs/nandfs_vfsops.c deleted file mode 100644 index f703044728ef8..0000000000000 --- a/sys/fs/nandfs/nandfs_vfsops.c +++ /dev/null @@ -1,1601 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf - * Copyright (c) 2008, 2009 Reinoud Zandijk - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * From: NetBSD: nilfs_vfsops.c,v 1.1 2009/07/18 16:31:42 reinoud Exp - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/fcntl.h> -#include <sys/gsb_crc32.h> -#include <sys/kernel.h> -#include <sys/lock.h> -#include <sys/malloc.h> -#include <sys/mount.h> -#include <sys/namei.h> -#include <sys/proc.h> -#include <sys/priv.h> -#include <sys/vnode.h> -#include <sys/buf.h> -#include <sys/sysctl.h> -#include <sys/libkern.h> - -#include <geom/geom.h> -#include <geom/geom_vfs.h> - -#include <machine/_inttypes.h> - -#include <fs/nandfs/nandfs_mount.h> -#include <fs/nandfs/nandfs.h> -#include <fs/nandfs/nandfs_subr.h> - -static MALLOC_DEFINE(M_NANDFSMNT, "nandfs_mount", "NANDFS mount structure"); - -#define NANDFS_SET_SYSTEMFILE(vp) { \ - (vp)->v_vflag |= VV_SYSTEM; \ - vref(vp); \ - vput(vp); } - -#define NANDFS_UNSET_SYSTEMFILE(vp) { \ - VOP_LOCK(vp, LK_EXCLUSIVE); \ - MPASS(vp->v_bufobj.bo_dirty.bv_cnt == 0); \ - (vp)->v_vflag &= ~VV_SYSTEM; \ - vgone(vp); \ - vput(vp); } - -/* Globals */ -struct _nandfs_devices nandfs_devices; - -/* Parameters */ -int nandfs_verbose = 0; - -static void -nandfs_tunable_init(void *arg) -{ - - TUNABLE_INT_FETCH("vfs.nandfs.verbose", &nandfs_verbose); -} -SYSINIT(nandfs_tunables, SI_SUB_VFS, SI_ORDER_ANY, nandfs_tunable_init, NULL); - -static SYSCTL_NODE(_vfs, OID_AUTO, nandfs, CTLFLAG_RD, 0, "NAND filesystem"); -static SYSCTL_NODE(_vfs_nandfs, OID_AUTO, mount, CTLFLAG_RD, 0, - "NANDFS mountpoints"); -SYSCTL_INT(_vfs_nandfs, OID_AUTO, verbose, CTLFLAG_RW, &nandfs_verbose, 0, ""); - -#define NANDFS_CONSTR_INTERVAL 5 -int nandfs_sync_interval = NANDFS_CONSTR_INTERVAL; /* sync every 5 seconds */ -SYSCTL_UINT(_vfs_nandfs, OID_AUTO, sync_interval, CTLFLAG_RW, - &nandfs_sync_interval, 0, ""); - -#define NANDFS_MAX_DIRTY_SEGS 5 -int nandfs_max_dirty_segs = NANDFS_MAX_DIRTY_SEGS; /* sync when 5 dirty seg */ -SYSCTL_UINT(_vfs_nandfs, OID_AUTO, max_dirty_segs, CTLFLAG_RW, - &nandfs_max_dirty_segs, 0, ""); - -#define NANDFS_CPS_BETWEEN_SBLOCKS 5 -int nandfs_cps_between_sblocks = NANDFS_CPS_BETWEEN_SBLOCKS; /* write superblock every 5 checkpoints */ -SYSCTL_UINT(_vfs_nandfs, OID_AUTO, cps_between_sblocks, CTLFLAG_RW, - &nandfs_cps_between_sblocks, 0, ""); - -#define NANDFS_CLEANER_ENABLE 1 -int nandfs_cleaner_enable = NANDFS_CLEANER_ENABLE; -SYSCTL_UINT(_vfs_nandfs, OID_AUTO, cleaner_enable, CTLFLAG_RW, - &nandfs_cleaner_enable, 0, ""); - -#define NANDFS_CLEANER_INTERVAL 5 -int nandfs_cleaner_interval = NANDFS_CLEANER_INTERVAL; -SYSCTL_UINT(_vfs_nandfs, OID_AUTO, cleaner_interval, CTLFLAG_RW, - &nandfs_cleaner_interval, 0, ""); - -#define NANDFS_CLEANER_SEGMENTS 5 -int nandfs_cleaner_segments = NANDFS_CLEANER_SEGMENTS; -SYSCTL_UINT(_vfs_nandfs, OID_AUTO, cleaner_segments, CTLFLAG_RW, - &nandfs_cleaner_segments, 0, ""); - -static int nandfs_mountfs(struct vnode *devvp, struct mount *mp); -static vfs_mount_t nandfs_mount; -static vfs_root_t nandfs_root; -static vfs_statfs_t nandfs_statfs; -static vfs_unmount_t nandfs_unmount; -static vfs_vget_t nandfs_vget; -static vfs_sync_t nandfs_sync; -static const char *nandfs_opts[] = { - "snap", "from", "noatime", NULL -}; - -/* System nodes */ -static int -nandfs_create_system_nodes(struct nandfs_device *nandfsdev) -{ - int error; - - error = nandfs_get_node_raw(nandfsdev, NULL, NANDFS_DAT_INO, - &nandfsdev->nd_super_root.sr_dat, &nandfsdev->nd_dat_node); - if (error) - goto errorout; - - error = nandfs_get_node_raw(nandfsdev, NULL, NANDFS_CPFILE_INO, - &nandfsdev->nd_super_root.sr_cpfile, &nandfsdev->nd_cp_node); - if (error) - goto errorout; - - error = nandfs_get_node_raw(nandfsdev, NULL, NANDFS_SUFILE_INO, - &nandfsdev->nd_super_root.sr_sufile, &nandfsdev->nd_su_node); - if (error) - goto errorout; - - error = nandfs_get_node_raw(nandfsdev, NULL, NANDFS_GC_INO, - NULL, &nandfsdev->nd_gc_node); - if (error) - goto errorout; - - NANDFS_SET_SYSTEMFILE(NTOV(nandfsdev->nd_dat_node)); - NANDFS_SET_SYSTEMFILE(NTOV(nandfsdev->nd_cp_node)); - NANDFS_SET_SYSTEMFILE(NTOV(nandfsdev->nd_su_node)); - NANDFS_SET_SYSTEMFILE(NTOV(nandfsdev->nd_gc_node)); - - DPRINTF(VOLUMES, ("System vnodes: dat: %p cp: %p su: %p\n", - NTOV(nandfsdev->nd_dat_node), NTOV(nandfsdev->nd_cp_node), - NTOV(nandfsdev->nd_su_node))); - return (0); - -errorout: - nandfs_dispose_node(&nandfsdev->nd_gc_node); - nandfs_dispose_node(&nandfsdev->nd_dat_node); - nandfs_dispose_node(&nandfsdev->nd_cp_node); - nandfs_dispose_node(&nandfsdev->nd_su_node); - - return (error); -} - -static void -nandfs_release_system_nodes(struct nandfs_device *nandfsdev) -{ - - if (!nandfsdev) - return; - if (nandfsdev->nd_refcnt > 0) - return; - - if (nandfsdev->nd_gc_node) - NANDFS_UNSET_SYSTEMFILE(NTOV(nandfsdev->nd_gc_node)); - if (nandfsdev->nd_dat_node) - NANDFS_UNSET_SYSTEMFILE(NTOV(nandfsdev->nd_dat_node)); - if (nandfsdev->nd_cp_node) - NANDFS_UNSET_SYSTEMFILE(NTOV(nandfsdev->nd_cp_node)); - if (nandfsdev->nd_su_node) - NANDFS_UNSET_SYSTEMFILE(NTOV(nandfsdev->nd_su_node)); -} - -static int -nandfs_check_fsdata_crc(struct nandfs_fsdata *fsdata) -{ - uint32_t fsdata_crc, comp_crc; - - if (fsdata->f_magic != NANDFS_FSDATA_MAGIC) - return (0); - - /* Preserve CRC */ - fsdata_crc = fsdata->f_sum; - - /* Calculate */ - fsdata->f_sum = (0); - comp_crc = crc32((uint8_t *)fsdata, fsdata->f_bytes); - - /* Restore */ - fsdata->f_sum = fsdata_crc; - - /* Check CRC */ - return (fsdata_crc == comp_crc); -} - -static int -nandfs_check_superblock_crc(struct nandfs_fsdata *fsdata, - struct nandfs_super_block *super) -{ - uint32_t super_crc, comp_crc; - - /* Check super block magic */ - if (super->s_magic != NANDFS_SUPER_MAGIC) - return (0); - - /* Preserve CRC */ - super_crc = super->s_sum; - - /* Calculate */ - super->s_sum = (0); - comp_crc = crc32((uint8_t *)super, fsdata->f_sbbytes); - - /* Restore */ - super->s_sum = super_crc; - - /* Check CRC */ - return (super_crc == comp_crc); -} - -static void -nandfs_calc_superblock_crc(struct nandfs_fsdata *fsdata, - struct nandfs_super_block *super) -{ - uint32_t comp_crc; - - /* Calculate */ - super->s_sum = 0; - comp_crc = crc32((uint8_t *)super, fsdata->f_sbbytes); - - /* Restore */ - super->s_sum = comp_crc; -} - -static int -nandfs_is_empty(u_char *area, int size) -{ - int i; - - for (i = 0; i < size; i++) - if (area[i] != 0xff) - return (0); - - return (1); -} - -static __inline int -nandfs_sblocks_in_esize(struct nandfs_device *fsdev) -{ - - return ((fsdev->nd_erasesize - NANDFS_SBLOCK_OFFSET_BYTES) / - sizeof(struct nandfs_super_block)); -} - -static __inline int -nandfs_max_sblocks(struct nandfs_device *fsdev) -{ - - return (NANDFS_NFSAREAS * nandfs_sblocks_in_esize(fsdev)); -} - -static __inline int -nandfs_sblocks_in_block(struct nandfs_device *fsdev) -{ - - return (fsdev->nd_devblocksize / sizeof(struct nandfs_super_block)); -} - -#if 0 -static __inline int -nandfs_sblocks_in_first_block(struct nandfs_device *fsdev) -{ - int n; - - n = nandfs_sblocks_in_block(fsdev) - - NANDFS_SBLOCK_OFFSET_BYTES / sizeof(struct nandfs_super_block); - if (n < 0) - n = 0; - - return (n); -} -#endif - -static int -nandfs_write_superblock_at(struct nandfs_device *fsdev, - struct nandfs_fsarea *fstp) -{ - struct nandfs_super_block *super, *supert; - struct buf *bp; - int sb_per_sector, sbs_in_fsd, read_block; - int index, pos, error; - off_t offset; - - DPRINTF(SYNC, ("%s: last_used %d nandfs_sblocks_in_esize %d\n", - __func__, fstp->last_used, nandfs_sblocks_in_esize(fsdev))); - if (fstp->last_used == nandfs_sblocks_in_esize(fsdev) - 1) - index = 0; - else - index = fstp->last_used + 1; - - super = &fsdev->nd_super; - supert = NULL; - - sb_per_sector = nandfs_sblocks_in_block(fsdev); - sbs_in_fsd = sizeof(struct nandfs_fsdata) / - sizeof(struct nandfs_super_block); - index += sbs_in_fsd; - offset = fstp->offset; - - DPRINTF(SYNC, ("%s: offset %#jx s_last_pseg %#jx s_last_cno %#jx " - "s_last_seq %#jx wtime %jd index %d\n", __func__, offset, - super->s_last_pseg, super->s_last_cno, super->s_last_seq, - super->s_wtime, index)); - - read_block = btodb(offset + rounddown(index, sb_per_sector) * - sizeof(struct nandfs_super_block)); - - DPRINTF(SYNC, ("%s: read_block %#x\n", __func__, read_block)); - - if (index == sbs_in_fsd) { - error = nandfs_erase(fsdev, offset, fsdev->nd_erasesize); - if (error) - return (error); - - error = bread(fsdev->nd_devvp, btodb(offset), - fsdev->nd_devblocksize, NOCRED, &bp); - if (error) { - printf("NANDFS: couldn't read initial data: %d\n", - error); - brelse(bp); - return (error); - } - memcpy(bp->b_data, &fsdev->nd_fsdata, sizeof(fsdev->nd_fsdata)); - /* - * 0xff-out the rest. This bp could be cached, so potentially - * b_data contains stale super blocks. - * - * We don't mind cached bp since most of the time we just add - * super blocks to already 0xff-out b_data and don't need to - * perform actual read. - */ - if (fsdev->nd_devblocksize > sizeof(fsdev->nd_fsdata)) - memset(bp->b_data + sizeof(fsdev->nd_fsdata), 0xff, - fsdev->nd_devblocksize - sizeof(fsdev->nd_fsdata)); - error = bwrite(bp); - if (error) { - printf("NANDFS: cannot rewrite initial data at %jx\n", - offset); - return (error); - } - } - - error = bread(fsdev->nd_devvp, read_block, fsdev->nd_devblocksize, - NOCRED, &bp); - if (error) { - brelse(bp); - return (error); - } - - supert = (struct nandfs_super_block *)(bp->b_data); - pos = index % sb_per_sector; - - DPRINTF(SYNC, ("%s: storing at %d\n", __func__, pos)); - memcpy(&supert[pos], super, sizeof(struct nandfs_super_block)); - - /* - * See comment above in code that performs erase. - */ - if (pos == 0) - memset(&supert[1], 0xff, - (sb_per_sector - 1) * sizeof(struct nandfs_super_block)); - - error = bwrite(bp); - if (error) { - printf("NANDFS: cannot update superblock at %jx\n", offset); - return (error); - } - - DPRINTF(SYNC, ("%s: fstp->last_used %d -> %d\n", __func__, - fstp->last_used, index - sbs_in_fsd)); - fstp->last_used = index - sbs_in_fsd; - - return (0); -} - -int -nandfs_write_superblock(struct nandfs_device *fsdev) -{ - struct nandfs_super_block *super; - struct timespec ts; - int error; - int i, j; - - vfs_timestamp(&ts); - - super = &fsdev->nd_super; - - super->s_last_pseg = fsdev->nd_last_pseg; - super->s_last_cno = fsdev->nd_last_cno; - super->s_last_seq = fsdev->nd_seg_sequence; - super->s_wtime = ts.tv_sec; - - nandfs_calc_superblock_crc(&fsdev->nd_fsdata, super); - - error = 0; - for (i = 0, j = fsdev->nd_last_fsarea; i < NANDFS_NFSAREAS; - i++, j = (j + 1 % NANDFS_NFSAREAS)) { - if (fsdev->nd_fsarea[j].flags & NANDFS_FSSTOR_FAILED) { - DPRINTF(SYNC, ("%s: skipping %d\n", __func__, j)); - continue; - } - error = nandfs_write_superblock_at(fsdev, &fsdev->nd_fsarea[j]); - if (error) { - printf("NANDFS: writing superblock at offset %d failed:" - "%d\n", j * fsdev->nd_erasesize, error); - fsdev->nd_fsarea[j].flags |= NANDFS_FSSTOR_FAILED; - } else - break; - } - - if (i == NANDFS_NFSAREAS) { - printf("NANDFS: superblock was not written\n"); - /* - * TODO: switch to read-only? - */ - return (error); - } else - fsdev->nd_last_fsarea = (j + 1) % NANDFS_NFSAREAS; - - return (0); -} - -static int -nandfs_select_fsdata(struct nandfs_device *fsdev, - struct nandfs_fsdata *fsdatat, struct nandfs_fsdata **fsdata, int nfsds) -{ - int i; - - *fsdata = NULL; - for (i = 0; i < nfsds; i++) { - DPRINTF(VOLUMES, ("%s: i %d f_magic %x f_crc %x\n", __func__, - i, fsdatat[i].f_magic, fsdatat[i].f_sum)); - if (!nandfs_check_fsdata_crc(&fsdatat[i])) - continue; - *fsdata = &fsdatat[i]; - break; - } - - return (*fsdata != NULL ? 0 : EINVAL); -} - -static int -nandfs_select_sb(struct nandfs_device *fsdev, - struct nandfs_super_block *supert, struct nandfs_super_block **super, - int nsbs) -{ - int i; - - *super = NULL; - for (i = 0; i < nsbs; i++) { - if (!nandfs_check_superblock_crc(&fsdev->nd_fsdata, &supert[i])) - continue; - DPRINTF(SYNC, ("%s: i %d s_last_cno %jx s_magic %x " - "s_wtime %jd\n", __func__, i, supert[i].s_last_cno, - supert[i].s_magic, supert[i].s_wtime)); - if (*super == NULL || supert[i].s_last_cno > - (*super)->s_last_cno) - *super = &supert[i]; - } - - return (*super != NULL ? 0 : EINVAL); -} - -static int -nandfs_read_structures_at(struct nandfs_device *fsdev, - struct nandfs_fsarea *fstp, struct nandfs_fsdata *fsdata, - struct nandfs_super_block *super) -{ - struct nandfs_super_block *tsuper, *tsuperd; - struct buf *bp; - int error, read_size; - int i; - int offset; - - offset = fstp->offset; - - if (fsdev->nd_erasesize > MAXBSIZE) - read_size = MAXBSIZE; - else - read_size = fsdev->nd_erasesize; - - error = bread(fsdev->nd_devvp, btodb(offset), read_size, NOCRED, &bp); - if (error) { - printf("couldn't read: %d\n", error); - brelse(bp); - fstp->flags |= NANDFS_FSSTOR_FAILED; - return (error); - } - - tsuper = super; - - memcpy(fsdata, bp->b_data, sizeof(struct nandfs_fsdata)); - memcpy(tsuper, (bp->b_data + sizeof(struct nandfs_fsdata)), - read_size - sizeof(struct nandfs_fsdata)); - brelse(bp); - - tsuper += (read_size - sizeof(struct nandfs_fsdata)) / - sizeof(struct nandfs_super_block); - - for (i = 1; i < fsdev->nd_erasesize / read_size; i++) { - error = bread(fsdev->nd_devvp, btodb(offset + i * read_size), - read_size, NOCRED, &bp); - if (error) { - printf("couldn't read: %d\n", error); - brelse(bp); - fstp->flags |= NANDFS_FSSTOR_FAILED; - return (error); - } - memcpy(tsuper, bp->b_data, read_size); - tsuper += read_size / sizeof(struct nandfs_super_block); - brelse(bp); - } - - tsuper -= 1; - fstp->last_used = nandfs_sblocks_in_esize(fsdev) - 1; - for (tsuperd = super - 1; (tsuper != tsuperd); tsuper -= 1) { - if (nandfs_is_empty((u_char *)tsuper, sizeof(*tsuper))) - fstp->last_used--; - else - break; - } - - DPRINTF(VOLUMES, ("%s: last_used %d\n", __func__, fstp->last_used)); - - return (0); -} - -static int -nandfs_read_structures(struct nandfs_device *fsdev) -{ - struct nandfs_fsdata *fsdata, *fsdatat; - struct nandfs_super_block *sblocks, *ssblock; - u_int nsbs, nfsds, i; - int error = 0; - int nrsbs; - - nfsds = NANDFS_NFSAREAS; - nsbs = nandfs_max_sblocks(fsdev); - - fsdatat = malloc(sizeof(struct nandfs_fsdata) * nfsds, M_NANDFSTEMP, - M_WAITOK | M_ZERO); - sblocks = malloc(sizeof(struct nandfs_super_block) * nsbs, M_NANDFSTEMP, - M_WAITOK | M_ZERO); - - nrsbs = 0; - for (i = 0; i < NANDFS_NFSAREAS; i++) { - fsdev->nd_fsarea[i].offset = i * fsdev->nd_erasesize; - error = nandfs_read_structures_at(fsdev, &fsdev->nd_fsarea[i], - &fsdatat[i], sblocks + nrsbs); - if (error) - continue; - nrsbs += (fsdev->nd_fsarea[i].last_used + 1); - if (fsdev->nd_fsarea[fsdev->nd_last_fsarea].last_used > - fsdev->nd_fsarea[i].last_used) - fsdev->nd_last_fsarea = i; - } - - if (nrsbs == 0) { - printf("nandfs: no valid superblocks found\n"); - error = EINVAL; - goto out; - } - - error = nandfs_select_fsdata(fsdev, fsdatat, &fsdata, nfsds); - if (error) - goto out; - memcpy(&fsdev->nd_fsdata, fsdata, sizeof(struct nandfs_fsdata)); - - error = nandfs_select_sb(fsdev, sblocks, &ssblock, nsbs); - if (error) - goto out; - - memcpy(&fsdev->nd_super, ssblock, sizeof(struct nandfs_super_block)); -out: - free(fsdatat, M_NANDFSTEMP); - free(sblocks, M_NANDFSTEMP); - - if (error == 0) - DPRINTF(VOLUMES, ("%s: selected sb with w_time %jd " - "last_pseg %#jx\n", __func__, fsdev->nd_super.s_wtime, - fsdev->nd_super.s_last_pseg)); - - return (error); -} - -static void -nandfs_unmount_base(struct nandfs_device *nandfsdev) -{ - int error; - - if (!nandfsdev) - return; - - /* Remove all our information */ - error = vinvalbuf(nandfsdev->nd_devvp, V_SAVE, 0, 0); - if (error) { - /* - * Flushing buffers failed when fs was umounting, can't do - * much now, just printf error and continue with umount. - */ - nandfs_error("%s(): error:%d when umounting FS\n", - __func__, error); - } - - /* Release the device's system nodes */ - nandfs_release_system_nodes(nandfsdev); -} - -static void -nandfs_get_ncleanseg(struct nandfs_device *nandfsdev) -{ - struct nandfs_seg_stat nss; - - nandfs_get_seg_stat(nandfsdev, &nss); - nandfsdev->nd_clean_segs = nss.nss_ncleansegs; - DPRINTF(VOLUMES, ("nandfs_mount: clean segs: %jx\n", - (uintmax_t)nandfsdev->nd_clean_segs)); -} - - -static int -nandfs_mount_base(struct nandfs_device *nandfsdev, struct mount *mp, - struct nandfs_args *args) -{ - uint32_t log_blocksize; - int error; - - /* Flush out any old buffers remaining from a previous use. */ - if ((error = vinvalbuf(nandfsdev->nd_devvp, V_SAVE, 0, 0))) - return (error); - - error = nandfs_read_structures(nandfsdev); - if (error) { - printf("nandfs: could not get valid filesystem structures\n"); - return (error); - } - - if (nandfsdev->nd_fsdata.f_rev_level != NANDFS_CURRENT_REV) { - printf("nandfs: unsupported file system revision: %d " - "(supported is %d).\n", nandfsdev->nd_fsdata.f_rev_level, - NANDFS_CURRENT_REV); - return (EINVAL); - } - - if (nandfsdev->nd_fsdata.f_erasesize != nandfsdev->nd_erasesize) { - printf("nandfs: erasesize mismatch (device %#x, fs %#x)\n", - nandfsdev->nd_erasesize, nandfsdev->nd_fsdata.f_erasesize); - return (EINVAL); - } - - /* Get our blocksize */ - log_blocksize = nandfsdev->nd_fsdata.f_log_block_size; - nandfsdev->nd_blocksize = (uint64_t) 1 << (log_blocksize + 10); - DPRINTF(VOLUMES, ("%s: blocksize:%x\n", __func__, - nandfsdev->nd_blocksize)); - - DPRINTF(VOLUMES, ("%s: accepted super block with cp %#jx\n", __func__, - (uintmax_t)nandfsdev->nd_super.s_last_cno)); - - /* Calculate dat structure parameters */ - nandfs_calc_mdt_consts(nandfsdev, &nandfsdev->nd_dat_mdt, - nandfsdev->nd_fsdata.f_dat_entry_size); - nandfs_calc_mdt_consts(nandfsdev, &nandfsdev->nd_ifile_mdt, - nandfsdev->nd_fsdata.f_inode_size); - - /* Search for the super root and roll forward when needed */ - if (nandfs_search_super_root(nandfsdev)) { - printf("Cannot find valid SuperRoot\n"); - return (EINVAL); - } - - nandfsdev->nd_mount_state = nandfsdev->nd_super.s_state; - if (nandfsdev->nd_mount_state != NANDFS_VALID_FS) { - printf("FS is seriously damaged, needs repairing\n"); - printf("aborting mount\n"); - return (EINVAL); - } - - /* - * FS should be ok now. The superblock and the last segsum could be - * updated from the repair so extract running values again. - */ - nandfsdev->nd_last_pseg = nandfsdev->nd_super.s_last_pseg; - nandfsdev->nd_seg_sequence = nandfsdev->nd_super.s_last_seq; - nandfsdev->nd_seg_num = nandfs_get_segnum_of_block(nandfsdev, - nandfsdev->nd_last_pseg); - nandfsdev->nd_next_seg_num = nandfs_get_segnum_of_block(nandfsdev, - nandfsdev->nd_last_segsum.ss_next); - nandfsdev->nd_ts.tv_sec = nandfsdev->nd_last_segsum.ss_create; - nandfsdev->nd_last_cno = nandfsdev->nd_super.s_last_cno; - nandfsdev->nd_fakevblk = 1; - /* - * FIXME: bogus calculation. Should use actual number of usable segments - * instead of total amount. - */ - nandfsdev->nd_segs_reserved = - nandfsdev->nd_fsdata.f_nsegments * - nandfsdev->nd_fsdata.f_r_segments_percentage / 100; - nandfsdev->nd_last_ino = NANDFS_USER_INO; - DPRINTF(VOLUMES, ("%s: last_pseg %#jx last_cno %#jx last_seq %#jx\n" - "fsdev: last_seg: seq %#jx num %#jx, next_seg_num %#jx " - "segs_reserved %#jx\n", - __func__, (uintmax_t)nandfsdev->nd_last_pseg, - (uintmax_t)nandfsdev->nd_last_cno, - (uintmax_t)nandfsdev->nd_seg_sequence, - (uintmax_t)nandfsdev->nd_seg_sequence, - (uintmax_t)nandfsdev->nd_seg_num, - (uintmax_t)nandfsdev->nd_next_seg_num, - (uintmax_t)nandfsdev->nd_segs_reserved)); - - DPRINTF(VOLUMES, ("nandfs_mount: accepted super root\n")); - - /* Create system vnodes for DAT, CP and SEGSUM */ - error = nandfs_create_system_nodes(nandfsdev); - if (error) - nandfs_unmount_base(nandfsdev); - - nandfs_get_ncleanseg(nandfsdev); - - return (error); -} - -static void -nandfs_unmount_device(struct nandfs_device *nandfsdev) -{ - - /* Is there anything? */ - if (nandfsdev == NULL) - return; - - /* Remove the device only if we're the last reference */ - nandfsdev->nd_refcnt--; - if (nandfsdev->nd_refcnt >= 1) - return; - - MPASS(nandfsdev->nd_syncer == NULL); - MPASS(nandfsdev->nd_cleaner == NULL); - MPASS(nandfsdev->nd_free_base == NULL); - - /* Unmount our base */ - nandfs_unmount_base(nandfsdev); - - /* Remove from our device list */ - SLIST_REMOVE(&nandfs_devices, nandfsdev, nandfs_device, nd_next_device); - - DROP_GIANT(); - g_topology_lock(); - g_vfs_close(nandfsdev->nd_gconsumer); - g_topology_unlock(); - PICKUP_GIANT(); - - DPRINTF(VOLUMES, ("closing device\n")); - - /* Clear our mount reference and release device node */ - vrele(nandfsdev->nd_devvp); - - dev_rel(nandfsdev->nd_devvp->v_rdev); - - /* Free our device info */ - cv_destroy(&nandfsdev->nd_sync_cv); - mtx_destroy(&nandfsdev->nd_sync_mtx); - cv_destroy(&nandfsdev->nd_clean_cv); - mtx_destroy(&nandfsdev->nd_clean_mtx); - mtx_destroy(&nandfsdev->nd_mutex); - lockdestroy(&nandfsdev->nd_seg_const); - free(nandfsdev, M_NANDFSMNT); -} - -static int -nandfs_check_mounts(struct nandfs_device *nandfsdev, struct mount *mp, - struct nandfs_args *args) -{ - struct nandfsmount *nmp; - uint64_t last_cno; - - /* no double-mounting of the same checkpoint */ - STAILQ_FOREACH(nmp, &nandfsdev->nd_mounts, nm_next_mount) { - if (nmp->nm_mount_args.cpno == args->cpno) - return (EBUSY); - } - - /* Allow readonly mounts without questioning here */ - if (mp->mnt_flag & MNT_RDONLY) - return (0); - - /* Read/write mount */ - STAILQ_FOREACH(nmp, &nandfsdev->nd_mounts, nm_next_mount) { - /* Only one RW mount on this device! */ - if ((nmp->nm_vfs_mountp->mnt_flag & MNT_RDONLY)==0) - return (EROFS); - /* RDONLY on last mountpoint is device busy */ - last_cno = nmp->nm_nandfsdev->nd_super.s_last_cno; - if (nmp->nm_mount_args.cpno == last_cno) - return (EBUSY); - } - - /* OK for now */ - return (0); -} - -static int -nandfs_mount_device(struct vnode *devvp, struct mount *mp, - struct nandfs_args *args, struct nandfs_device **nandfsdev_p) -{ - struct nandfs_device *nandfsdev; - struct g_provider *pp; - struct g_consumer *cp; - struct cdev *dev; - uint32_t erasesize; - int error, size; - int ronly; - - DPRINTF(VOLUMES, ("Mounting NANDFS device\n")); - - ronly = (mp->mnt_flag & MNT_RDONLY) != 0; - - /* Look up device in our nandfs_mountpoints */ - *nandfsdev_p = NULL; - SLIST_FOREACH(nandfsdev, &nandfs_devices, nd_next_device) - if (nandfsdev->nd_devvp == devvp) - break; - - if (nandfsdev) { - DPRINTF(VOLUMES, ("device already mounted\n")); - error = nandfs_check_mounts(nandfsdev, mp, args); - if (error) - return error; - nandfsdev->nd_refcnt++; - *nandfsdev_p = nandfsdev; - - if (!ronly) { - DROP_GIANT(); - g_topology_lock(); - error = g_access(nandfsdev->nd_gconsumer, 0, 1, 0); - g_topology_unlock(); - PICKUP_GIANT(); - } - return (error); - } - - vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); - dev = devvp->v_rdev; - dev_ref(dev); - DROP_GIANT(); - g_topology_lock(); - error = g_vfs_open(devvp, &cp, "nandfs", ronly ? 0 : 1); - pp = g_dev_getprovider(dev); - g_topology_unlock(); - PICKUP_GIANT(); - VOP_UNLOCK(devvp, 0); - if (error) { - dev_rel(dev); - return (error); - } - - nandfsdev = malloc(sizeof(struct nandfs_device), M_NANDFSMNT, M_WAITOK | M_ZERO); - - /* Initialise */ - nandfsdev->nd_refcnt = 1; - nandfsdev->nd_devvp = devvp; - nandfsdev->nd_syncing = 0; - nandfsdev->nd_cleaning = 0; - nandfsdev->nd_gconsumer = cp; - cv_init(&nandfsdev->nd_sync_cv, "nandfssync"); - mtx_init(&nandfsdev->nd_sync_mtx, "nffssyncmtx", NULL, MTX_DEF); - cv_init(&nandfsdev->nd_clean_cv, "nandfsclean"); - mtx_init(&nandfsdev->nd_clean_mtx, "nffscleanmtx", NULL, MTX_DEF); - mtx_init(&nandfsdev->nd_mutex, "nandfsdev lock", NULL, MTX_DEF); - lockinit(&nandfsdev->nd_seg_const, PVFS, "nffssegcon", VLKTIMEOUT, - LK_CANRECURSE); - STAILQ_INIT(&nandfsdev->nd_mounts); - - nandfsdev->nd_devsize = pp->mediasize; - nandfsdev->nd_devblocksize = pp->sectorsize; - - size = sizeof(erasesize); - error = g_io_getattr("NAND::blocksize", nandfsdev->nd_gconsumer, &size, - &erasesize); - if (error) { - DPRINTF(VOLUMES, ("couldn't get erasesize: %d\n", error)); - - if (error == ENOIOCTL || error == EOPNOTSUPP) { - /* - * We conclude that this is not NAND storage - */ - erasesize = NANDFS_DEF_ERASESIZE; - } else { - DROP_GIANT(); - g_topology_lock(); - g_vfs_close(nandfsdev->nd_gconsumer); - g_topology_unlock(); - PICKUP_GIANT(); - dev_rel(dev); - free(nandfsdev, M_NANDFSMNT); - return (error); - } - } - nandfsdev->nd_erasesize = erasesize; - - DPRINTF(VOLUMES, ("%s: erasesize %x\n", __func__, - nandfsdev->nd_erasesize)); - - /* Register nandfs_device in list */ - SLIST_INSERT_HEAD(&nandfs_devices, nandfsdev, nd_next_device); - - error = nandfs_mount_base(nandfsdev, mp, args); - if (error) { - /* Remove all our information */ - nandfs_unmount_device(nandfsdev); - return (EINVAL); - } - - nandfsdev->nd_maxfilesize = nandfs_get_maxfilesize(nandfsdev); - - *nandfsdev_p = nandfsdev; - DPRINTF(VOLUMES, ("NANDFS device mounted ok\n")); - - return (0); -} - -static int -nandfs_mount_checkpoint(struct nandfsmount *nmp) -{ - struct nandfs_cpfile_header *cphdr; - struct nandfs_checkpoint *cp; - struct nandfs_inode ifile_inode; - struct nandfs_node *cp_node; - struct buf *bp; - uint64_t ncp, nsn, cpno, fcpno, blocknr, last_cno; - uint32_t off, dlen; - int cp_per_block, error; - - cpno = nmp->nm_mount_args.cpno; - if (cpno == 0) - cpno = nmp->nm_nandfsdev->nd_super.s_last_cno; - - DPRINTF(VOLUMES, ("%s: trying to mount checkpoint number %"PRIu64"\n", - __func__, cpno)); - - cp_node = nmp->nm_nandfsdev->nd_cp_node; - - VOP_LOCK(NTOV(cp_node), LK_SHARED); - /* Get cpfile header from 1st block of cp file */ - error = nandfs_bread(cp_node, 0, NOCRED, 0, &bp); - if (error) { - brelse(bp); - VOP_UNLOCK(NTOV(cp_node), 0); - return (error); - } - - cphdr = (struct nandfs_cpfile_header *) bp->b_data; - ncp = cphdr->ch_ncheckpoints; - nsn = cphdr->ch_nsnapshots; - - brelse(bp); - - DPRINTF(VOLUMES, ("mount_nandfs: checkpoint header read in\n")); - DPRINTF(VOLUMES, ("\tNumber of checkpoints %"PRIu64"\n", ncp)); - DPRINTF(VOLUMES, ("\tNumber of snapshots %"PRIu64"\n", nsn)); - - /* Read in our specified checkpoint */ - dlen = nmp->nm_nandfsdev->nd_fsdata.f_checkpoint_size; - cp_per_block = nmp->nm_nandfsdev->nd_blocksize / dlen; - - fcpno = cpno + NANDFS_CPFILE_FIRST_CHECKPOINT_OFFSET - 1; - blocknr = fcpno / cp_per_block; - off = (fcpno % cp_per_block) * dlen; - error = nandfs_bread(cp_node, blocknr, NOCRED, 0, &bp); - if (error) { - brelse(bp); - VOP_UNLOCK(NTOV(cp_node), 0); - printf("mount_nandfs: couldn't read cp block %"PRIu64"\n", - fcpno); - return (EINVAL); - } - - /* Needs to be a valid checkpoint */ - cp = (struct nandfs_checkpoint *) ((uint8_t *) bp->b_data + off); - if (cp->cp_flags & NANDFS_CHECKPOINT_INVALID) { - printf("mount_nandfs: checkpoint marked invalid\n"); - brelse(bp); - VOP_UNLOCK(NTOV(cp_node), 0); - return (EINVAL); - } - - /* Is this really the checkpoint we want? */ - if (cp->cp_cno != cpno) { - printf("mount_nandfs: checkpoint file corrupt? " - "expected cpno %"PRIu64", found cpno %"PRIu64"\n", - cpno, cp->cp_cno); - brelse(bp); - VOP_UNLOCK(NTOV(cp_node), 0); - return (EINVAL); - } - - /* Check if it's a snapshot ! */ - last_cno = nmp->nm_nandfsdev->nd_super.s_last_cno; - if (cpno != last_cno) { - /* Only allow snapshots if not mounting on the last cp */ - if ((cp->cp_flags & NANDFS_CHECKPOINT_SNAPSHOT) == 0) { - printf( "mount_nandfs: checkpoint %"PRIu64" is not a " - "snapshot\n", cpno); - brelse(bp); - VOP_UNLOCK(NTOV(cp_node), 0); - return (EINVAL); - } - } - - ifile_inode = cp->cp_ifile_inode; - brelse(bp); - - /* Get ifile inode */ - error = nandfs_get_node_raw(nmp->nm_nandfsdev, NULL, NANDFS_IFILE_INO, - &ifile_inode, &nmp->nm_ifile_node); - if (error) { - printf("mount_nandfs: can't read ifile node\n"); - VOP_UNLOCK(NTOV(cp_node), 0); - return (EINVAL); - } - - NANDFS_SET_SYSTEMFILE(NTOV(nmp->nm_ifile_node)); - VOP_UNLOCK(NTOV(cp_node), 0); - /* Get root node? */ - - return (0); -} - -static void -free_nandfs_mountinfo(struct mount *mp) -{ - struct nandfsmount *nmp = VFSTONANDFS(mp); - - if (nmp == NULL) - return; - - free(nmp, M_NANDFSMNT); -} - -void -nandfs_wakeup_wait_sync(struct nandfs_device *nffsdev, int reason) -{ - char *reasons[] = { - "umount", - "vfssync", - "bdflush", - "fforce", - "fsync", - "ro_upd" - }; - - DPRINTF(SYNC, ("%s: %s\n", __func__, reasons[reason])); - mtx_lock(&nffsdev->nd_sync_mtx); - if (nffsdev->nd_syncing) - cv_wait(&nffsdev->nd_sync_cv, &nffsdev->nd_sync_mtx); - if (reason == SYNCER_UMOUNT) - nffsdev->nd_syncer_exit = 1; - nffsdev->nd_syncing = 1; - wakeup(&nffsdev->nd_syncing); - cv_wait(&nffsdev->nd_sync_cv, &nffsdev->nd_sync_mtx); - - mtx_unlock(&nffsdev->nd_sync_mtx); -} - -static void -nandfs_gc_finished(struct nandfs_device *nffsdev, int exit) -{ - int error; - - mtx_lock(&nffsdev->nd_sync_mtx); - nffsdev->nd_syncing = 0; - DPRINTF(SYNC, ("%s: cleaner finish\n", __func__)); - cv_broadcast(&nffsdev->nd_sync_cv); - mtx_unlock(&nffsdev->nd_sync_mtx); - if (!exit) { - error = tsleep(&nffsdev->nd_syncing, PRIBIO, "-", - hz * nandfs_sync_interval); - DPRINTF(SYNC, ("%s: cleaner waked up: %d\n", - __func__, error)); - } -} - -static void -nandfs_syncer(struct nandfsmount *nmp) -{ - struct nandfs_device *nffsdev; - struct mount *mp; - int flags, error; - - mp = nmp->nm_vfs_mountp; - nffsdev = nmp->nm_nandfsdev; - tsleep(&nffsdev->nd_syncing, PRIBIO, "-", hz * nandfs_sync_interval); - - while (!nffsdev->nd_syncer_exit) { - DPRINTF(SYNC, ("%s: syncer run\n", __func__)); - nffsdev->nd_syncing = 1; - - flags = (nmp->nm_flags & (NANDFS_FORCE_SYNCER | NANDFS_UMOUNT)); - - error = nandfs_segment_constructor(nmp, flags); - if (error) - nandfs_error("%s: error:%d when creating segments\n", - __func__, error); - - nmp->nm_flags &= ~flags; - - nandfs_gc_finished(nffsdev, 0); - } - - MPASS(nffsdev->nd_cleaner == NULL); - error = nandfs_segment_constructor(nmp, - NANDFS_FORCE_SYNCER | NANDFS_UMOUNT); - if (error) - nandfs_error("%s: error:%d when creating segments\n", - __func__, error); - nandfs_gc_finished(nffsdev, 1); - nffsdev->nd_syncer = NULL; - MPASS(nffsdev->nd_free_base == NULL); - - DPRINTF(SYNC, ("%s: exiting\n", __func__)); - kthread_exit(); -} - -static int -start_syncer(struct nandfsmount *nmp) -{ - int error; - - MPASS(nmp->nm_nandfsdev->nd_syncer == NULL); - - DPRINTF(SYNC, ("%s: start syncer\n", __func__)); - - nmp->nm_nandfsdev->nd_syncer_exit = 0; - - error = kthread_add((void(*)(void *))nandfs_syncer, nmp, NULL, - &nmp->nm_nandfsdev->nd_syncer, 0, 0, "nandfs_syncer"); - - if (error) - printf("nandfs: could not start syncer: %d\n", error); - - return (error); -} - -static int -stop_syncer(struct nandfsmount *nmp) -{ - - MPASS(nmp->nm_nandfsdev->nd_syncer != NULL); - - nandfs_wakeup_wait_sync(nmp->nm_nandfsdev, SYNCER_UMOUNT); - - DPRINTF(SYNC, ("%s: stop syncer\n", __func__)); - return (0); -} - -/* - * Mount null layer - */ -static int -nandfs_mount(struct mount *mp) -{ - struct nandfsmount *nmp; - struct vnode *devvp; - struct nameidata nd; - struct vfsoptlist *opts; - struct thread *td; - char *from; - int error = 0, flags; - - DPRINTF(VOLUMES, ("%s: mp = %p\n", __func__, (void *)mp)); - - td = curthread; - opts = mp->mnt_optnew; - - if (vfs_filteropt(opts, nandfs_opts)) - return (EINVAL); - - /* - * Update is a no-op - */ - if (mp->mnt_flag & MNT_UPDATE) { - nmp = VFSTONANDFS(mp); - if (vfs_flagopt(mp->mnt_optnew, "export", NULL, 0)) { - return (error); - } - if (!(nmp->nm_ronly) && vfs_flagopt(opts, "ro", NULL, 0)) { - vn_start_write(NULL, &mp, V_WAIT); - error = VFS_SYNC(mp, MNT_WAIT); - if (error) - return (error); - vn_finished_write(mp); - - flags = WRITECLOSE; - if (mp->mnt_flag & MNT_FORCE) - flags |= FORCECLOSE; - - nandfs_wakeup_wait_sync(nmp->nm_nandfsdev, - SYNCER_ROUPD); - error = vflush(mp, 0, flags, td); - if (error) - return (error); - - nandfs_stop_cleaner(nmp->nm_nandfsdev); - stop_syncer(nmp); - DROP_GIANT(); - g_topology_lock(); - g_access(nmp->nm_nandfsdev->nd_gconsumer, 0, -1, 0); - g_topology_unlock(); - PICKUP_GIANT(); - MNT_ILOCK(mp); - mp->mnt_flag |= MNT_RDONLY; - MNT_IUNLOCK(mp); - nmp->nm_ronly = 1; - - } else if ((nmp->nm_ronly) && - !vfs_flagopt(opts, "ro", NULL, 0)) { - /* - * Don't allow read-write snapshots. - */ - if (nmp->nm_mount_args.cpno != 0) - return (EROFS); - /* - * If upgrade to read-write by non-root, then verify - * that user has necessary permissions on the device. - */ - devvp = nmp->nm_nandfsdev->nd_devvp; - vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); - error = VOP_ACCESS(devvp, VREAD | VWRITE, - td->td_ucred, td); - if (error) { - error = priv_check(td, PRIV_VFS_MOUNT_PERM); - if (error) { - VOP_UNLOCK(devvp, 0); - return (error); - } - } - - VOP_UNLOCK(devvp, 0); - DROP_GIANT(); - g_topology_lock(); - error = g_access(nmp->nm_nandfsdev->nd_gconsumer, 0, 1, - 0); - g_topology_unlock(); - PICKUP_GIANT(); - if (error) - return (error); - - MNT_ILOCK(mp); - mp->mnt_flag &= ~MNT_RDONLY; - MNT_IUNLOCK(mp); - error = start_syncer(nmp); - if (error == 0) - error = nandfs_start_cleaner(nmp->nm_nandfsdev); - if (error) { - DROP_GIANT(); - g_topology_lock(); - g_access(nmp->nm_nandfsdev->nd_gconsumer, 0, -1, - 0); - g_topology_unlock(); - PICKUP_GIANT(); - return (error); - } - - nmp->nm_ronly = 0; - } - return (0); - } - - from = vfs_getopts(opts, "from", &error); - if (error) - return (error); - - /* - * Find device node - */ - NDINIT(&nd, LOOKUP, FOLLOW|LOCKLEAF, UIO_SYSSPACE, from, curthread); - error = namei(&nd); - if (error) - return (error); - NDFREE(&nd, NDF_ONLY_PNBUF); - - devvp = nd.ni_vp; - - if (!vn_isdisk(devvp, &error)) { - vput(devvp); - return (error); - } - - /* Check the access rights on the mount device */ - error = VOP_ACCESS(devvp, VREAD, curthread->td_ucred, curthread); - if (error) - error = priv_check(curthread, PRIV_VFS_MOUNT_PERM); - if (error) { - vput(devvp); - return (error); - } - - vfs_getnewfsid(mp); - - error = nandfs_mountfs(devvp, mp); - if (error) - return (error); - vfs_mountedfrom(mp, from); - - return (0); -} - -static int -nandfs_mountfs(struct vnode *devvp, struct mount *mp) -{ - struct nandfsmount *nmp = NULL; - struct nandfs_args *args = NULL; - struct nandfs_device *nandfsdev; - char *from; - int error, ronly; - char *cpno; - - ronly = (mp->mnt_flag & MNT_RDONLY) != 0; - - if (devvp->v_rdev->si_iosize_max != 0) - mp->mnt_iosize_max = devvp->v_rdev->si_iosize_max; - VOP_UNLOCK(devvp, 0); - - if (mp->mnt_iosize_max > MAXPHYS) - mp->mnt_iosize_max = MAXPHYS; - - from = vfs_getopts(mp->mnt_optnew, "from", &error); - if (error) - goto error; - - error = vfs_getopt(mp->mnt_optnew, "snap", (void **)&cpno, NULL); - if (error == ENOENT) - cpno = NULL; - else if (error) - goto error; - - args = (struct nandfs_args *)malloc(sizeof(struct nandfs_args), - M_NANDFSMNT, M_WAITOK | M_ZERO); - - if (cpno != NULL) - args->cpno = strtoul(cpno, (char **)NULL, 10); - else - args->cpno = 0; - args->fspec = from; - - if (args->cpno != 0 && !ronly) { - error = EROFS; - goto error; - } - - printf("WARNING: NANDFS is considered to be a highly experimental " - "feature in FreeBSD.\n"); - - error = nandfs_mount_device(devvp, mp, args, &nandfsdev); - if (error) - goto error; - - nmp = (struct nandfsmount *) malloc(sizeof(struct nandfsmount), - M_NANDFSMNT, M_WAITOK | M_ZERO); - - mp->mnt_data = nmp; - nmp->nm_vfs_mountp = mp; - nmp->nm_ronly = ronly; - MNT_ILOCK(mp); - mp->mnt_flag |= MNT_LOCAL; - mp->mnt_kern_flag |= MNTK_USES_BCACHE; - MNT_IUNLOCK(mp); - nmp->nm_nandfsdev = nandfsdev; - /* Add our mountpoint */ - STAILQ_INSERT_TAIL(&nandfsdev->nd_mounts, nmp, nm_next_mount); - - if (args->cpno > nandfsdev->nd_last_cno) { - printf("WARNING: supplied checkpoint number (%jd) is greater " - "than last known checkpoint on filesystem (%jd). Mounting" - " checkpoint %jd\n", (uintmax_t)args->cpno, - (uintmax_t)nandfsdev->nd_last_cno, - (uintmax_t)nandfsdev->nd_last_cno); - args->cpno = nandfsdev->nd_last_cno; - } - - /* Setting up other parameters */ - nmp->nm_mount_args = *args; - free(args, M_NANDFSMNT); - error = nandfs_mount_checkpoint(nmp); - if (error) { - nandfs_unmount(mp, MNT_FORCE); - goto unmounted; - } - - if (!ronly) { - error = start_syncer(nmp); - if (error == 0) - error = nandfs_start_cleaner(nmp->nm_nandfsdev); - if (error) - nandfs_unmount(mp, MNT_FORCE); - } - - return (0); - -error: - if (args != NULL) - free(args, M_NANDFSMNT); - - if (nmp != NULL) { - free(nmp, M_NANDFSMNT); - mp->mnt_data = NULL; - } -unmounted: - return (error); -} - -static int -nandfs_unmount(struct mount *mp, int mntflags) -{ - struct nandfs_device *nandfsdev; - struct nandfsmount *nmp; - int error; - int flags = 0; - - DPRINTF(VOLUMES, ("%s: mp = %p\n", __func__, (void *)mp)); - - if (mntflags & MNT_FORCE) - flags |= FORCECLOSE; - - nmp = mp->mnt_data; - nandfsdev = nmp->nm_nandfsdev; - - error = vflush(mp, 0, flags | SKIPSYSTEM, curthread); - if (error) - return (error); - - if (!(nmp->nm_ronly)) { - nandfs_stop_cleaner(nandfsdev); - stop_syncer(nmp); - } - - if (nmp->nm_ifile_node) - NANDFS_UNSET_SYSTEMFILE(NTOV(nmp->nm_ifile_node)); - - /* Remove our mount point */ - STAILQ_REMOVE(&nandfsdev->nd_mounts, nmp, nandfsmount, nm_next_mount); - - /* Unmount the device itself when we're the last one */ - nandfs_unmount_device(nandfsdev); - - free_nandfs_mountinfo(mp); - - /* - * Finally, throw away the null_mount structure - */ - mp->mnt_data = 0; - MNT_ILOCK(mp); - mp->mnt_flag &= ~MNT_LOCAL; - MNT_IUNLOCK(mp); - - return (0); -} - -static int -nandfs_statfs(struct mount *mp, struct statfs *sbp) -{ - struct nandfsmount *nmp; - struct nandfs_device *nandfsdev; - struct nandfs_fsdata *fsdata; - struct nandfs_super_block *sb; - struct nandfs_block_group_desc *groups; - struct nandfs_node *ifile; - struct nandfs_mdt *mdt; - struct buf *bp; - int i, error; - uint32_t entries_per_group; - uint64_t files = 0; - - nmp = mp->mnt_data; - nandfsdev = nmp->nm_nandfsdev; - fsdata = &nandfsdev->nd_fsdata; - sb = &nandfsdev->nd_super; - ifile = nmp->nm_ifile_node; - mdt = &nandfsdev->nd_ifile_mdt; - entries_per_group = mdt->entries_per_group; - - VOP_LOCK(NTOV(ifile), LK_SHARED); - error = nandfs_bread(ifile, 0, NOCRED, 0, &bp); - if (error) { - brelse(bp); - VOP_UNLOCK(NTOV(ifile), 0); - return (error); - } - - groups = (struct nandfs_block_group_desc *)bp->b_data; - - for (i = 0; i < mdt->groups_per_desc_block; i++) - files += (entries_per_group - groups[i].bg_nfrees); - - brelse(bp); - VOP_UNLOCK(NTOV(ifile), 0); - - sbp->f_bsize = nandfsdev->nd_blocksize; - sbp->f_iosize = sbp->f_bsize; - sbp->f_blocks = fsdata->f_blocks_per_segment * fsdata->f_nsegments; - sbp->f_bfree = sb->s_free_blocks_count; - sbp->f_bavail = sbp->f_bfree; - sbp->f_files = files; - sbp->f_ffree = 0; - return (0); -} - -static int -nandfs_root(struct mount *mp, int flags, struct vnode **vpp) -{ - struct nandfsmount *nmp = VFSTONANDFS(mp); - struct nandfs_node *node; - int error; - - error = nandfs_get_node(nmp, NANDFS_ROOT_INO, &node); - if (error) - return (error); - - KASSERT(NTOV(node)->v_vflag & VV_ROOT, - ("root_vp->v_vflag & VV_ROOT")); - - *vpp = NTOV(node); - - return (error); -} - -static int -nandfs_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) -{ - struct nandfsmount *nmp = VFSTONANDFS(mp); - struct nandfs_node *node; - int error; - - error = nandfs_get_node(nmp, ino, &node); - if (node) - *vpp = NTOV(node); - - return (error); -} - -static int -nandfs_sync(struct mount *mp, int waitfor) -{ - struct nandfsmount *nmp = VFSTONANDFS(mp); - - DPRINTF(SYNC, ("%s: mp %p waitfor %d\n", __func__, mp, waitfor)); - - /* - * XXX: A hack to be removed soon - */ - if (waitfor == MNT_LAZY) - return (0); - if (waitfor == MNT_SUSPEND) - return (0); - nandfs_wakeup_wait_sync(nmp->nm_nandfsdev, SYNCER_VFS_SYNC); - return (0); -} - -static struct vfsops nandfs_vfsops = { - .vfs_init = nandfs_init, - .vfs_mount = nandfs_mount, - .vfs_root = nandfs_root, - .vfs_statfs = nandfs_statfs, - .vfs_uninit = nandfs_uninit, - .vfs_unmount = nandfs_unmount, - .vfs_vget = nandfs_vget, - .vfs_sync = nandfs_sync, -}; - -VFS_SET(nandfs_vfsops, nandfs, VFCF_LOOPBACK); diff --git a/sys/fs/nandfs/nandfs_vnops.c b/sys/fs/nandfs/nandfs_vnops.c deleted file mode 100644 index 5027d6adbbc1a..0000000000000 --- a/sys/fs/nandfs/nandfs_vnops.c +++ /dev/null @@ -1,2454 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf - * Copyright (c) 2008, 2009 Reinoud Zandijk - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * From: NetBSD: nilfs_vnops.c,v 1.2 2009/08/26 03:40:48 elad - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/conf.h> -#include <sys/kernel.h> -#include <sys/lock.h> -#include <sys/lockf.h> -#include <sys/malloc.h> -#include <sys/mount.h> -#include <sys/mutex.h> -#include <sys/namei.h> -#include <sys/sysctl.h> -#include <sys/unistd.h> -#include <sys/vnode.h> -#include <sys/buf.h> -#include <sys/bio.h> -#include <sys/fcntl.h> -#include <sys/dirent.h> -#include <sys/rwlock.h> -#include <sys/stat.h> -#include <sys/priv.h> - -#include <vm/vm.h> -#include <vm/vm_extern.h> -#include <vm/vm_object.h> -#include <vm/vnode_pager.h> - -#include <machine/_inttypes.h> - -#include <fs/nandfs/nandfs_mount.h> -#include <fs/nandfs/nandfs.h> -#include <fs/nandfs/nandfs_subr.h> - -extern uma_zone_t nandfs_node_zone; -static void nandfs_read_filebuf(struct nandfs_node *, struct buf *); -static void nandfs_itimes_locked(struct vnode *); -static int nandfs_truncate(struct vnode *, uint64_t); - -static vop_pathconf_t nandfs_pathconf; - -#define UPDATE_CLOSE 0 -#define UPDATE_WAIT 0 - -static int -nandfs_inactive(struct vop_inactive_args *ap) -{ - struct vnode *vp = ap->a_vp; - struct nandfs_node *node = VTON(vp); - int error = 0; - - DPRINTF(VNCALL, ("%s: vp:%p node:%p\n", __func__, vp, node)); - - if (node == NULL) { - DPRINTF(NODE, ("%s: inactive NULL node\n", __func__)); - return (0); - } - - if (node->nn_inode.i_mode != 0 && !(node->nn_inode.i_links_count)) { - nandfs_truncate(vp, 0); - error = nandfs_node_destroy(node); - if (error) - nandfs_error("%s: destroy node: %p\n", __func__, node); - node->nn_flags = 0; - vrecycle(vp); - } - - return (error); -} - -static int -nandfs_reclaim(struct vop_reclaim_args *ap) -{ - struct vnode *vp = ap->a_vp; - struct nandfs_node *nandfs_node = VTON(vp); - struct nandfs_device *fsdev = nandfs_node->nn_nandfsdev; - uint64_t ino = nandfs_node->nn_ino; - - DPRINTF(VNCALL, ("%s: vp:%p node:%p\n", __func__, vp, nandfs_node)); - - /* Invalidate all entries to a particular vnode. */ - cache_purge(vp); - - /* Destroy the vm object and flush associated pages. */ - vnode_destroy_vobject(vp); - - /* Remove from vfs hash if not system vnode */ - if (!NANDFS_SYS_NODE(nandfs_node->nn_ino)) - vfs_hash_remove(vp); - - /* Dispose all node knowledge */ - nandfs_dispose_node(&nandfs_node); - - if (!NANDFS_SYS_NODE(ino)) - NANDFS_WRITEUNLOCK(fsdev); - - return (0); -} - -static int -nandfs_read(struct vop_read_args *ap) -{ - struct vnode *vp = ap->a_vp; - struct nandfs_node *node = VTON(vp); - struct nandfs_device *nandfsdev = node->nn_nandfsdev; - struct uio *uio = ap->a_uio; - struct buf *bp; - uint64_t size; - uint32_t blocksize; - off_t bytesinfile; - ssize_t toread, off; - daddr_t lbn; - ssize_t resid; - int error = 0; - - if (uio->uio_resid == 0) - return (0); - - size = node->nn_inode.i_size; - if (uio->uio_offset >= size) - return (0); - - blocksize = nandfsdev->nd_blocksize; - bytesinfile = size - uio->uio_offset; - - resid = omin(uio->uio_resid, bytesinfile); - - while (resid) { - lbn = uio->uio_offset / blocksize; - off = uio->uio_offset & (blocksize - 1); - - toread = omin(resid, blocksize - off); - - DPRINTF(READ, ("nandfs_read bn: 0x%jx toread: 0x%zx (0x%x)\n", - (uintmax_t)lbn, toread, blocksize)); - - error = nandfs_bread(node, lbn, NOCRED, 0, &bp); - if (error) { - brelse(bp); - break; - } - - error = uiomove(bp->b_data + off, toread, uio); - if (error) { - brelse(bp); - break; - } - - brelse(bp); - resid -= toread; - } - - return (error); -} - -static int -nandfs_write(struct vop_write_args *ap) -{ - struct nandfs_device *fsdev; - struct nandfs_node *node; - struct vnode *vp; - struct uio *uio; - struct buf *bp; - uint64_t file_size, vblk; - uint32_t blocksize; - ssize_t towrite, off; - daddr_t lbn; - ssize_t resid; - int error, ioflag, modified; - - vp = ap->a_vp; - uio = ap->a_uio; - ioflag = ap->a_ioflag; - node = VTON(vp); - fsdev = node->nn_nandfsdev; - - if (nandfs_fs_full(fsdev)) - return (ENOSPC); - - DPRINTF(WRITE, ("nandfs_write called %#zx at %#jx\n", - uio->uio_resid, (uintmax_t)uio->uio_offset)); - - if (uio->uio_offset < 0) - return (EINVAL); - if (uio->uio_resid == 0) - return (0); - - blocksize = fsdev->nd_blocksize; - file_size = node->nn_inode.i_size; - - switch (vp->v_type) { - case VREG: - if (ioflag & IO_APPEND) - uio->uio_offset = file_size; - break; - case VDIR: - return (EISDIR); - case VLNK: - break; - default: - panic("%s: bad file type vp: %p", __func__, vp); - } - - /* If explicitly asked to append, uio_offset can be wrong? */ - if (ioflag & IO_APPEND) - uio->uio_offset = file_size; - - resid = uio->uio_resid; - modified = error = 0; - - while (uio->uio_resid) { - lbn = uio->uio_offset / blocksize; - off = uio->uio_offset & (blocksize - 1); - - towrite = omin(uio->uio_resid, blocksize - off); - - DPRINTF(WRITE, ("%s: lbn: 0x%jd toread: 0x%zx (0x%x)\n", - __func__, (uintmax_t)lbn, towrite, blocksize)); - - error = nandfs_bmap_lookup(node, lbn, &vblk); - if (error) - break; - - DPRINTF(WRITE, ("%s: lbn: 0x%jd toread: 0x%zx (0x%x) " - "vblk=%jx\n", __func__, (uintmax_t)lbn, towrite, blocksize, - vblk)); - - if (vblk != 0) - error = nandfs_bread(node, lbn, NOCRED, 0, &bp); - else - error = nandfs_bcreate(node, lbn, NOCRED, 0, &bp); - - DPRINTF(WRITE, ("%s: vp %p bread bp %p lbn %#jx\n", __func__, - vp, bp, (uintmax_t)lbn)); - if (error) { - if (bp) - brelse(bp); - break; - } - - error = uiomove((char *)bp->b_data + off, (int)towrite, uio); - if (error) - break; - - error = nandfs_dirty_buf(bp, 0); - if (error) - break; - - modified++; - } - - /* XXX proper handling when only part of file was properly written */ - if (modified) { - if (resid > uio->uio_resid && ap->a_cred && - ap->a_cred->cr_uid != 0) - node->nn_inode.i_mode &= ~(ISUID | ISGID); - - if (file_size < uio->uio_offset + uio->uio_resid) { - node->nn_inode.i_size = uio->uio_offset + - uio->uio_resid; - node->nn_flags |= IN_CHANGE | IN_UPDATE; - vnode_pager_setsize(vp, uio->uio_offset + - uio->uio_resid); - nandfs_itimes(vp); - } - } - - DPRINTF(WRITE, ("%s: return:%d\n", __func__, error)); - - return (error); -} - -static int -nandfs_lookup(struct vop_cachedlookup_args *ap) -{ - struct vnode *dvp, **vpp; - struct componentname *cnp; - struct ucred *cred; - struct thread *td; - struct nandfs_node *dir_node, *node; - struct nandfsmount *nmp; - uint64_t ino, off; - const char *name; - int namelen, nameiop, islastcn, mounted_ro; - int error, found; - - DPRINTF(VNCALL, ("%s\n", __func__)); - - dvp = ap->a_dvp; - vpp = ap->a_vpp; - *vpp = NULL; - - cnp = ap->a_cnp; - cred = cnp->cn_cred; - td = cnp->cn_thread; - - dir_node = VTON(dvp); - nmp = dir_node->nn_nmp; - - /* Simplify/clarification flags */ - nameiop = cnp->cn_nameiop; - islastcn = cnp->cn_flags & ISLASTCN; - mounted_ro = dvp->v_mount->mnt_flag & MNT_RDONLY; - - /* - * If requesting a modify on the last path element on a read-only - * filingsystem, reject lookup; - */ - if (islastcn && mounted_ro && (nameiop == DELETE || nameiop == RENAME)) - return (EROFS); - - if (dir_node->nn_inode.i_links_count == 0) - return (ENOENT); - - /* - * Obviously, the file is not (anymore) in the namecache, we have to - * search for it. There are three basic cases: '.', '..' and others. - * - * Following the guidelines of VOP_LOOKUP manpage and tmpfs. - */ - error = 0; - if ((cnp->cn_namelen == 1) && (cnp->cn_nameptr[0] == '.')) { - DPRINTF(LOOKUP, ("\tlookup '.'\n")); - /* Special case 1 '.' */ - VREF(dvp); - *vpp = dvp; - /* Done */ - } else if (cnp->cn_flags & ISDOTDOT) { - /* Special case 2 '..' */ - DPRINTF(LOOKUP, ("\tlookup '..'\n")); - - /* Get our node */ - name = ".."; - namelen = 2; - error = nandfs_lookup_name_in_dir(dvp, name, namelen, &ino, - &found, &off); - if (error) - goto out; - if (!found) - error = ENOENT; - - /* First unlock parent */ - VOP_UNLOCK(dvp, 0); - - if (error == 0) { - DPRINTF(LOOKUP, ("\tfound '..'\n")); - /* Try to create/reuse the node */ - error = nandfs_get_node(nmp, ino, &node); - - if (!error) { - DPRINTF(LOOKUP, - ("\tnode retrieved/created OK\n")); - *vpp = NTOV(node); - } - } - - /* Try to relock parent */ - vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); - } else { - DPRINTF(LOOKUP, ("\tlookup file\n")); - /* All other files */ - /* Look up filename in the directory returning its inode */ - name = cnp->cn_nameptr; - namelen = cnp->cn_namelen; - error = nandfs_lookup_name_in_dir(dvp, name, namelen, - &ino, &found, &off); - if (error) - goto out; - if (!found) { - DPRINTF(LOOKUP, ("\tNOT found\n")); - /* - * UGH, didn't find name. If we're creating or - * renaming on the last name this is OK and we ought - * to return EJUSTRETURN if its allowed to be created. - */ - error = ENOENT; - if ((nameiop == CREATE || nameiop == RENAME) && - islastcn) { - error = VOP_ACCESS(dvp, VWRITE, cred, td); - if (!error) { - /* keep the component name */ - cnp->cn_flags |= SAVENAME; - error = EJUSTRETURN; - } - } - /* Done */ - } else { - if (ino == NANDFS_WHT_INO) - cnp->cn_flags |= ISWHITEOUT; - - if ((cnp->cn_flags & ISWHITEOUT) && - (nameiop == LOOKUP)) - return (ENOENT); - - if ((nameiop == DELETE) && islastcn) { - if ((cnp->cn_flags & ISWHITEOUT) && - (cnp->cn_flags & DOWHITEOUT)) { - cnp->cn_flags |= SAVENAME; - dir_node->nn_diroff = off; - return (EJUSTRETURN); - } - - error = VOP_ACCESS(dvp, VWRITE, cred, - cnp->cn_thread); - if (error) - return (error); - - /* Try to create/reuse the node */ - error = nandfs_get_node(nmp, ino, &node); - if (!error) { - *vpp = NTOV(node); - node->nn_diroff = off; - } - - if ((dir_node->nn_inode.i_mode & ISVTX) && - cred->cr_uid != 0 && - cred->cr_uid != dir_node->nn_inode.i_uid && - node->nn_inode.i_uid != cred->cr_uid) { - vput(*vpp); - *vpp = NULL; - return (EPERM); - } - } else if ((nameiop == RENAME) && islastcn) { - error = VOP_ACCESS(dvp, VWRITE, cred, - cnp->cn_thread); - if (error) - return (error); - - /* Try to create/reuse the node */ - error = nandfs_get_node(nmp, ino, &node); - if (!error) { - *vpp = NTOV(node); - node->nn_diroff = off; - } - } else { - /* Try to create/reuse the node */ - error = nandfs_get_node(nmp, ino, &node); - if (!error) { - *vpp = NTOV(node); - node->nn_diroff = off; - } - } - } - } - -out: - /* - * Store result in the cache if requested. If we are creating a file, - * the file might not be found and thus putting it into the namecache - * might be seen as negative caching. - */ - if ((cnp->cn_flags & MAKEENTRY) != 0) - cache_enter(dvp, *vpp, cnp); - - return (error); - -} - -static int -nandfs_getattr(struct vop_getattr_args *ap) -{ - struct vnode *vp = ap->a_vp; - struct vattr *vap = ap->a_vap; - struct nandfs_node *node = VTON(vp); - struct nandfs_inode *inode = &node->nn_inode; - - DPRINTF(VNCALL, ("%s: vp: %p\n", __func__, vp)); - nandfs_itimes(vp); - - /* Basic info */ - VATTR_NULL(vap); - vap->va_atime.tv_sec = inode->i_mtime; - vap->va_atime.tv_nsec = inode->i_mtime_nsec; - vap->va_mtime.tv_sec = inode->i_mtime; - vap->va_mtime.tv_nsec = inode->i_mtime_nsec; - vap->va_ctime.tv_sec = inode->i_ctime; - vap->va_ctime.tv_nsec = inode->i_ctime_nsec; - vap->va_type = IFTOVT(inode->i_mode); - vap->va_mode = inode->i_mode & ~S_IFMT; - vap->va_nlink = inode->i_links_count; - vap->va_uid = inode->i_uid; - vap->va_gid = inode->i_gid; - vap->va_rdev = inode->i_special; - vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; - vap->va_fileid = node->nn_ino; - vap->va_size = inode->i_size; - vap->va_blocksize = node->nn_nandfsdev->nd_blocksize; - vap->va_gen = 0; - vap->va_flags = inode->i_flags; - vap->va_bytes = inode->i_blocks * vap->va_blocksize; - vap->va_filerev = 0; - vap->va_vaflags = 0; - - return (0); -} - -static int -nandfs_vtruncbuf(struct vnode *vp, uint64_t nblks) -{ - struct nandfs_device *nffsdev; - struct bufobj *bo; - struct buf *bp, *nbp; - - bo = &vp->v_bufobj; - nffsdev = VTON(vp)->nn_nandfsdev; - - ASSERT_VOP_LOCKED(vp, "nandfs_truncate"); -restart: - BO_LOCK(bo); -restart_locked: - TAILQ_FOREACH_SAFE(bp, &bo->bo_clean.bv_hd, b_bobufs, nbp) { - if (bp->b_lblkno < nblks) - continue; - if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL)) - goto restart_locked; - - bremfree(bp); - bp->b_flags |= (B_INVAL | B_RELBUF); - bp->b_flags &= ~(B_ASYNC | B_MANAGED); - BO_UNLOCK(bo); - brelse(bp); - BO_LOCK(bo); - } - - TAILQ_FOREACH_SAFE(bp, &bo->bo_dirty.bv_hd, b_bobufs, nbp) { - if (bp->b_lblkno < nblks) - continue; - if (BUF_LOCK(bp, - LK_EXCLUSIVE | LK_SLEEPFAIL | LK_INTERLOCK, - BO_LOCKPTR(bo)) == ENOLCK) - goto restart; - bp->b_flags |= (B_INVAL | B_RELBUF); - bp->b_flags &= ~(B_ASYNC | B_MANAGED); - brelse(bp); - nandfs_dirty_bufs_decrement(nffsdev); - BO_LOCK(bo); - } - - BO_UNLOCK(bo); - - return (0); -} - -static int -nandfs_truncate(struct vnode *vp, uint64_t newsize) -{ - struct nandfs_device *nffsdev; - struct nandfs_node *node; - struct nandfs_inode *inode; - struct buf *bp = NULL; - uint64_t oblks, nblks, vblk, size, rest; - int error; - - node = VTON(vp); - nffsdev = node->nn_nandfsdev; - inode = &node->nn_inode; - - /* Calculate end of file */ - size = inode->i_size; - - if (newsize == size) { - node->nn_flags |= IN_CHANGE | IN_UPDATE; - nandfs_itimes(vp); - return (0); - } - - if (newsize > size) { - inode->i_size = newsize; - vnode_pager_setsize(vp, newsize); - node->nn_flags |= IN_CHANGE | IN_UPDATE; - nandfs_itimes(vp); - return (0); - } - - nblks = howmany(newsize, nffsdev->nd_blocksize); - oblks = howmany(size, nffsdev->nd_blocksize); - rest = newsize % nffsdev->nd_blocksize; - - if (rest) { - error = nandfs_bmap_lookup(node, nblks - 1, &vblk); - if (error) - return (error); - - if (vblk != 0) - error = nandfs_bread(node, nblks - 1, NOCRED, 0, &bp); - else - error = nandfs_bcreate(node, nblks - 1, NOCRED, 0, &bp); - - if (error) { - if (bp) - brelse(bp); - return (error); - } - - bzero((char *)bp->b_data + rest, - (u_int)(nffsdev->nd_blocksize - rest)); - error = nandfs_dirty_buf(bp, 0); - if (error) - return (error); - } - - DPRINTF(VNCALL, ("%s: vp %p oblks %jx nblks %jx\n", __func__, vp, oblks, - nblks)); - - error = nandfs_bmap_truncate_mapping(node, oblks - 1, nblks - 1); - if (error) { - if (bp) - nandfs_undirty_buf(bp); - return (error); - } - - error = nandfs_vtruncbuf(vp, nblks); - if (error) { - if (bp) - nandfs_undirty_buf(bp); - return (error); - } - - inode->i_size = newsize; - vnode_pager_setsize(vp, newsize); - node->nn_flags |= IN_CHANGE | IN_UPDATE; - nandfs_itimes(vp); - - return (error); -} - -static void -nandfs_itimes_locked(struct vnode *vp) -{ - struct nandfs_node *node; - struct nandfs_inode *inode; - struct timespec ts; - - ASSERT_VI_LOCKED(vp, __func__); - - node = VTON(vp); - inode = &node->nn_inode; - - if ((node->nn_flags & (IN_ACCESS | IN_CHANGE | IN_UPDATE)) == 0) - return; - - if (((vp->v_mount->mnt_kern_flag & - (MNTK_SUSPENDED | MNTK_SUSPEND)) == 0) || - (node->nn_flags & (IN_CHANGE | IN_UPDATE))) - node->nn_flags |= IN_MODIFIED; - - vfs_timestamp(&ts); - if (node->nn_flags & IN_UPDATE) { - inode->i_mtime = ts.tv_sec; - inode->i_mtime_nsec = ts.tv_nsec; - } - if (node->nn_flags & IN_CHANGE) { - inode->i_ctime = ts.tv_sec; - inode->i_ctime_nsec = ts.tv_nsec; - } - - node->nn_flags &= ~(IN_ACCESS | IN_CHANGE | IN_UPDATE); -} - -void -nandfs_itimes(struct vnode *vp) -{ - - VI_LOCK(vp); - nandfs_itimes_locked(vp); - VI_UNLOCK(vp); -} - -static int -nandfs_chmod(struct vnode *vp, int mode, struct ucred *cred, struct thread *td) -{ - struct nandfs_node *node = VTON(vp); - struct nandfs_inode *inode = &node->nn_inode; - uint16_t nmode; - int error = 0; - - DPRINTF(VNCALL, ("%s: vp %p, mode %x, cred %p, td %p\n", __func__, vp, - mode, cred, td)); - /* - * To modify the permissions on a file, must possess VADMIN - * for that file. - */ - if ((error = VOP_ACCESS(vp, VADMIN, cred, td))) - return (error); - - /* - * Privileged processes may set the sticky bit on non-directories, - * as well as set the setgid bit on a file with a group that the - * process is not a member of. Both of these are allowed in - * jail(8). - */ - if (vp->v_type != VDIR && (mode & S_ISTXT)) { - if (priv_check_cred(cred, PRIV_VFS_STICKYFILE)) - return (EFTYPE); - } - if (!groupmember(inode->i_gid, cred) && (mode & ISGID)) { - error = priv_check_cred(cred, PRIV_VFS_SETGID); - if (error) - return (error); - } - - /* - * Deny setting setuid if we are not the file owner. - */ - if ((mode & ISUID) && inode->i_uid != cred->cr_uid) { - error = priv_check_cred(cred, PRIV_VFS_ADMIN); - if (error) - return (error); - } - - nmode = inode->i_mode; - nmode &= ~ALLPERMS; - nmode |= (mode & ALLPERMS); - inode->i_mode = nmode; - node->nn_flags |= IN_CHANGE; - - DPRINTF(VNCALL, ("%s: to mode %x\n", __func__, nmode)); - - return (error); -} - -static int -nandfs_chown(struct vnode *vp, uid_t uid, gid_t gid, struct ucred *cred, - struct thread *td) -{ - struct nandfs_node *node = VTON(vp); - struct nandfs_inode *inode = &node->nn_inode; - uid_t ouid; - gid_t ogid; - int error = 0; - - if (uid == (uid_t)VNOVAL) - uid = inode->i_uid; - if (gid == (gid_t)VNOVAL) - gid = inode->i_gid; - /* - * To modify the ownership of a file, must possess VADMIN for that - * file. - */ - if ((error = VOP_ACCESSX(vp, VWRITE_OWNER, cred, td))) - return (error); - /* - * To change the owner of a file, or change the group of a file to a - * group of which we are not a member, the caller must have - * privilege. - */ - if (((uid != inode->i_uid && uid != cred->cr_uid) || - (gid != inode->i_gid && !groupmember(gid, cred))) && - (error = priv_check_cred(cred, PRIV_VFS_CHOWN))) - return (error); - ogid = inode->i_gid; - ouid = inode->i_uid; - - inode->i_gid = gid; - inode->i_uid = uid; - - node->nn_flags |= IN_CHANGE; - if ((inode->i_mode & (ISUID | ISGID)) && - (ouid != uid || ogid != gid)) { - if (priv_check_cred(cred, PRIV_VFS_RETAINSUGID)) - inode->i_mode &= ~(ISUID | ISGID); - } - DPRINTF(VNCALL, ("%s: vp %p, cred %p, td %p - ret OK\n", __func__, vp, - cred, td)); - return (0); -} - -static int -nandfs_setattr(struct vop_setattr_args *ap) -{ - struct vnode *vp = ap->a_vp; - struct nandfs_node *node = VTON(vp); - struct nandfs_inode *inode = &node->nn_inode; - struct vattr *vap = ap->a_vap; - struct ucred *cred = ap->a_cred; - struct thread *td = curthread; - uint32_t flags; - int error = 0; - - if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) || - (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) || - (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) || - (vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) { - DPRINTF(VNCALL, ("%s: unsettable attribute\n", __func__)); - return (EINVAL); - } - - if (vap->va_flags != VNOVAL) { - DPRINTF(VNCALL, ("%s: vp:%p td:%p flags:%lx\n", __func__, vp, - td, vap->va_flags)); - - if (vp->v_mount->mnt_flag & MNT_RDONLY) - return (EROFS); - /* - * Callers may only modify the file flags on objects they - * have VADMIN rights for. - */ - if ((error = VOP_ACCESS(vp, VADMIN, cred, td))) - return (error); - /* - * Unprivileged processes are not permitted to unset system - * flags, or modify flags if any system flags are set. - * Privileged non-jail processes may not modify system flags - * if securelevel > 0 and any existing system flags are set. - * Privileged jail processes behave like privileged non-jail - * processes if the PR_ALLOW_CHFLAGS permission bit is set; - * otherwise, they behave like unprivileged processes. - */ - - flags = inode->i_flags; - if (!priv_check_cred(cred, PRIV_VFS_SYSFLAGS)) { - if (flags & (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND)) { - error = securelevel_gt(cred, 0); - if (error) - return (error); - } - /* Snapshot flag cannot be set or cleared */ - if (((vap->va_flags & SF_SNAPSHOT) != 0 && - (flags & SF_SNAPSHOT) == 0) || - ((vap->va_flags & SF_SNAPSHOT) == 0 && - (flags & SF_SNAPSHOT) != 0)) - return (EPERM); - - inode->i_flags = vap->va_flags; - } else { - if (flags & (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND) || - (vap->va_flags & UF_SETTABLE) != vap->va_flags) - return (EPERM); - - flags &= SF_SETTABLE; - flags |= (vap->va_flags & UF_SETTABLE); - inode->i_flags = flags; - } - node->nn_flags |= IN_CHANGE; - if (vap->va_flags & (IMMUTABLE | APPEND)) - return (0); - } - if (inode->i_flags & (IMMUTABLE | APPEND)) - return (EPERM); - - if (vap->va_size != (u_quad_t)VNOVAL) { - DPRINTF(VNCALL, ("%s: vp:%p td:%p size:%jx\n", __func__, vp, td, - (uintmax_t)vap->va_size)); - - switch (vp->v_type) { - case VDIR: - return (EISDIR); - case VLNK: - case VREG: - if (vp->v_mount->mnt_flag & MNT_RDONLY) - return (EROFS); - if ((inode->i_flags & SF_SNAPSHOT) != 0) - return (EPERM); - break; - default: - return (0); - } - - if (vap->va_size > node->nn_nandfsdev->nd_maxfilesize) - return (EFBIG); - - KASSERT((vp->v_type == VREG), ("Set size %d", vp->v_type)); - nandfs_truncate(vp, vap->va_size); - node->nn_flags |= IN_CHANGE; - - return (0); - } - - if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) { - if (vp->v_mount->mnt_flag & MNT_RDONLY) - return (EROFS); - DPRINTF(VNCALL, ("%s: vp:%p td:%p uid/gid %x/%x\n", __func__, - vp, td, vap->va_uid, vap->va_gid)); - error = nandfs_chown(vp, vap->va_uid, vap->va_gid, cred, td); - if (error) - return (error); - } - - if (vap->va_mode != (mode_t)VNOVAL) { - if (vp->v_mount->mnt_flag & MNT_RDONLY) - return (EROFS); - DPRINTF(VNCALL, ("%s: vp:%p td:%p mode %x\n", __func__, vp, td, - vap->va_mode)); - - error = nandfs_chmod(vp, (int)vap->va_mode, cred, td); - if (error) - return (error); - } - if (vap->va_atime.tv_sec != VNOVAL || - vap->va_mtime.tv_sec != VNOVAL || - vap->va_birthtime.tv_sec != VNOVAL) { - DPRINTF(VNCALL, ("%s: vp:%p td:%p time a/m/b %jx/%jx/%jx\n", - __func__, vp, td, (uintmax_t)vap->va_atime.tv_sec, - (uintmax_t)vap->va_mtime.tv_sec, - (uintmax_t)vap->va_birthtime.tv_sec)); - - if (vap->va_atime.tv_sec != VNOVAL) - node->nn_flags |= IN_ACCESS; - if (vap->va_mtime.tv_sec != VNOVAL) - node->nn_flags |= IN_CHANGE | IN_UPDATE; - if (vap->va_birthtime.tv_sec != VNOVAL) - node->nn_flags |= IN_MODIFIED; - nandfs_itimes(vp); - return (0); - } - - return (0); -} - -static int -nandfs_open(struct vop_open_args *ap) -{ - struct nandfs_node *node = VTON(ap->a_vp); - uint64_t filesize; - - DPRINTF(VNCALL, ("nandfs_open called ap->a_mode %x\n", ap->a_mode)); - - if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK) - return (EOPNOTSUPP); - - if ((node->nn_inode.i_flags & APPEND) && - (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE) - return (EPERM); - - filesize = node->nn_inode.i_size; - vnode_create_vobject(ap->a_vp, filesize, ap->a_td); - - return (0); -} - -static int -nandfs_close(struct vop_close_args *ap) -{ - struct vnode *vp = ap->a_vp; - struct nandfs_node *node = VTON(vp); - - DPRINTF(VNCALL, ("%s: vp %p node %p\n", __func__, vp, node)); - - mtx_lock(&vp->v_interlock); - if (vp->v_usecount > 1) - nandfs_itimes_locked(vp); - mtx_unlock(&vp->v_interlock); - - return (0); -} - -static int -nandfs_check_possible(struct vnode *vp, struct vattr *vap, mode_t mode) -{ - - /* Check if we are allowed to write */ - switch (vap->va_type) { - case VDIR: - case VLNK: - case VREG: - /* - * Normal nodes: check if we're on a read-only mounted - * filingsystem and bomb out if we're trying to write. - */ - if ((mode & VMODIFY_PERMS) && (vp->v_mount->mnt_flag & MNT_RDONLY)) - return (EROFS); - break; - case VBLK: - case VCHR: - case VSOCK: - case VFIFO: - /* - * Special nodes: even on read-only mounted filingsystems - * these are allowed to be written to if permissions allow. - */ - break; - default: - /* No idea what this is */ - return (EINVAL); - } - - /* No one may write immutable files */ - if ((mode & VWRITE) && (VTON(vp)->nn_inode.i_flags & IMMUTABLE)) - return (EPERM); - - return (0); -} - -static int -nandfs_check_permitted(struct vnode *vp, struct vattr *vap, mode_t mode, - struct ucred *cred) -{ - - return (vaccess(vp->v_type, vap->va_mode, vap->va_uid, vap->va_gid, mode, - cred, NULL)); -} - -static int -nandfs_advlock(struct vop_advlock_args *ap) -{ - struct nandfs_node *nvp; - quad_t size; - - nvp = VTON(ap->a_vp); - size = nvp->nn_inode.i_size; - return (lf_advlock(ap, &(nvp->nn_lockf), size)); -} - -static int -nandfs_access(struct vop_access_args *ap) -{ - struct vnode *vp = ap->a_vp; - accmode_t accmode = ap->a_accmode; - struct ucred *cred = ap->a_cred; - struct vattr vap; - int error; - - DPRINTF(VNCALL, ("%s: vp:%p mode: %x\n", __func__, vp, accmode)); - - error = VOP_GETATTR(vp, &vap, NULL); - if (error) - return (error); - - error = nandfs_check_possible(vp, &vap, accmode); - if (error) - return (error); - - error = nandfs_check_permitted(vp, &vap, accmode, cred); - - return (error); -} - -static int -nandfs_print(struct vop_print_args *ap) -{ - struct vnode *vp = ap->a_vp; - struct nandfs_node *nvp = VTON(vp); - - printf("\tvp=%p, nandfs_node=%p\n", vp, nvp); - printf("nandfs inode %#jx\n", (uintmax_t)nvp->nn_ino); - printf("flags = 0x%b\n", (u_int)nvp->nn_flags, PRINT_NODE_FLAGS); - - return (0); -} - -static void -nandfs_read_filebuf(struct nandfs_node *node, struct buf *bp) -{ - struct nandfs_device *nandfsdev = node->nn_nandfsdev; - struct buf *nbp; - nandfs_daddr_t vblk, pblk; - nandfs_lbn_t from; - uint32_t blocksize; - int error = 0; - int blk2dev = nandfsdev->nd_blocksize / DEV_BSIZE; - - /* - * Translate all the block sectors into a series of buffers to read - * asynchronously from the nandfs device. Note that this lookup may - * induce readin's too. - */ - - blocksize = nandfsdev->nd_blocksize; - if (bp->b_bcount / blocksize != 1) - panic("invalid b_count in bp %p\n", bp); - - from = bp->b_blkno; - - DPRINTF(READ, ("\tread in from inode %#jx blkno %#jx" - " count %#lx\n", (uintmax_t)node->nn_ino, from, - bp->b_bcount)); - - /* Get virtual block numbers for the vnode's buffer span */ - error = nandfs_bmap_lookup(node, from, &vblk); - if (error) { - bp->b_error = EINVAL; - bp->b_ioflags |= BIO_ERROR; - bufdone(bp); - return; - } - - /* Translate virtual block numbers to physical block numbers */ - error = nandfs_vtop(node, vblk, &pblk); - if (error) { - bp->b_error = EINVAL; - bp->b_ioflags |= BIO_ERROR; - bufdone(bp); - return; - } - - /* Issue translated blocks */ - bp->b_resid = bp->b_bcount; - - /* Note virtual block 0 marks not mapped */ - if (vblk == 0) { - vfs_bio_clrbuf(bp); - bufdone(bp); - return; - } - - nbp = bp; - nbp->b_blkno = pblk * blk2dev; - bp->b_iooffset = dbtob(nbp->b_blkno); - MPASS(bp->b_iooffset >= 0); - BO_STRATEGY(&nandfsdev->nd_devvp->v_bufobj, nbp); - nandfs_vblk_set(bp, vblk); - DPRINTF(READ, ("read_filebuf : ino %#jx blk %#jx -> " - "%#jx -> %#jx [bp %p]\n", (uintmax_t)node->nn_ino, - (uintmax_t)(from), (uintmax_t)vblk, - (uintmax_t)pblk, nbp)); -} - -static void -nandfs_write_filebuf(struct nandfs_node *node, struct buf *bp) -{ - struct nandfs_device *nandfsdev = node->nn_nandfsdev; - - bp->b_iooffset = dbtob(bp->b_blkno); - MPASS(bp->b_iooffset >= 0); - BO_STRATEGY(&nandfsdev->nd_devvp->v_bufobj, bp); -} - -static int -nandfs_strategy(struct vop_strategy_args *ap) -{ - struct vnode *vp = ap->a_vp; - struct buf *bp = ap->a_bp; - struct nandfs_node *node = VTON(vp); - - - /* check if we ought to be here */ - KASSERT((vp->v_type != VBLK && vp->v_type != VCHR), - ("nandfs_strategy on type %d", vp->v_type)); - - /* Translate if needed and pass on */ - if (bp->b_iocmd == BIO_READ) { - nandfs_read_filebuf(node, bp); - return (0); - } - - /* Send to segment collector */ - nandfs_write_filebuf(node, bp); - return (0); -} - -static int -nandfs_readdir(struct vop_readdir_args *ap) -{ - struct uio *uio = ap->a_uio; - struct vnode *vp = ap->a_vp; - struct nandfs_node *node = VTON(vp); - struct nandfs_dir_entry *ndirent; - struct dirent dirent; - struct buf *bp; - uint64_t file_size, diroffset, transoffset, blkoff; - uint64_t blocknr; - uint32_t blocksize = node->nn_nandfsdev->nd_blocksize; - uint8_t *pos, name_len; - int error; - - DPRINTF(READDIR, ("nandfs_readdir called\n")); - - if (vp->v_type != VDIR) - return (ENOTDIR); - - file_size = node->nn_inode.i_size; - DPRINTF(READDIR, ("nandfs_readdir filesize %jd resid %zd\n", - (uintmax_t)file_size, uio->uio_resid )); - - /* We are called just as long as we keep on pushing data in */ - error = 0; - if ((uio->uio_offset < file_size) && - (uio->uio_resid >= sizeof(struct dirent))) { - diroffset = uio->uio_offset; - transoffset = diroffset; - - blocknr = diroffset / blocksize; - blkoff = diroffset % blocksize; - error = nandfs_bread(node, blocknr, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (EIO); - } - while (diroffset < file_size) { - DPRINTF(READDIR, ("readdir : offset = %"PRIu64"\n", - diroffset)); - if (blkoff >= blocksize) { - blkoff = 0; blocknr++; - brelse(bp); - error = nandfs_bread(node, blocknr, NOCRED, 0, - &bp); - if (error) { - brelse(bp); - return (EIO); - } - } - - /* Read in one dirent */ - pos = (uint8_t *)bp->b_data + blkoff; - ndirent = (struct nandfs_dir_entry *)pos; - - name_len = ndirent->name_len; - memset(&dirent, 0, sizeof(dirent)); - dirent.d_fileno = ndirent->inode; - if (dirent.d_fileno) { - dirent.d_type = ndirent->file_type; - dirent.d_namlen = name_len; - strncpy(dirent.d_name, ndirent->name, name_len); - dirent.d_reclen = GENERIC_DIRSIZ(&dirent); - /* NOTE: d_off is the offset of the *next* entry. */ - dirent.d_off = diroffset + ndirent->rec_len; - dirent_terminate(&dirent); - DPRINTF(READDIR, ("copying `%*.*s`\n", name_len, - name_len, dirent.d_name)); - } - - /* - * If there isn't enough space in the uio to return a - * whole dirent, break off read - */ - if (uio->uio_resid < GENERIC_DIRSIZ(&dirent)) - break; - - /* Transfer */ - if (dirent.d_fileno) - uiomove(&dirent, dirent.d_reclen, uio); - - /* Advance */ - diroffset += ndirent->rec_len; - blkoff += ndirent->rec_len; - - /* Remember the last entry we transferred */ - transoffset = diroffset; - } - brelse(bp); - - /* Pass on last transferred offset */ - uio->uio_offset = transoffset; - } - - if (ap->a_eofflag) - *ap->a_eofflag = (uio->uio_offset >= file_size); - - return (error); -} - -static int -nandfs_dirempty(struct vnode *dvp, uint64_t parentino, struct ucred *cred) -{ - struct nandfs_node *dnode = VTON(dvp); - struct nandfs_dir_entry *dirent; - uint64_t file_size = dnode->nn_inode.i_size; - uint64_t blockcount = dnode->nn_inode.i_blocks; - uint64_t blocknr; - uint32_t blocksize = dnode->nn_nandfsdev->nd_blocksize; - uint32_t limit; - uint32_t off; - uint8_t *pos; - struct buf *bp; - int error; - - DPRINTF(LOOKUP, ("%s: dvp %p parentino %#jx cred %p\n", __func__, dvp, - (uintmax_t)parentino, cred)); - - KASSERT((file_size != 0), ("nandfs_dirempty for NULL dir %p", dvp)); - - blocknr = 0; - while (blocknr < blockcount) { - error = nandfs_bread(dnode, blocknr, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (0); - } - - pos = (uint8_t *)bp->b_data; - off = 0; - - if (blocknr == (blockcount - 1)) - limit = file_size % blocksize; - else - limit = blocksize; - - while (off < limit) { - dirent = (struct nandfs_dir_entry *)(pos + off); - off += dirent->rec_len; - - if (dirent->inode == 0) - continue; - - switch (dirent->name_len) { - case 0: - break; - case 1: - if (dirent->name[0] != '.') - goto notempty; - - KASSERT(dirent->inode == dnode->nn_ino, - (".'s inode does not match dir")); - break; - case 2: - if (dirent->name[0] != '.' && - dirent->name[1] != '.') - goto notempty; - - KASSERT(dirent->inode == parentino, - ("..'s inode does not match parent")); - break; - default: - goto notempty; - } - } - - brelse(bp); - blocknr++; - } - - return (1); -notempty: - brelse(bp); - return (0); -} - -static int -nandfs_link(struct vop_link_args *ap) -{ - struct vnode *tdvp = ap->a_tdvp; - struct vnode *vp = ap->a_vp; - struct componentname *cnp = ap->a_cnp; - struct nandfs_node *node = VTON(vp); - struct nandfs_inode *inode = &node->nn_inode; - int error; - - if (inode->i_links_count >= NANDFS_LINK_MAX) - return (EMLINK); - - if (inode->i_flags & (IMMUTABLE | APPEND)) - return (EPERM); - - /* Update link count */ - inode->i_links_count++; - - /* Add dir entry */ - error = nandfs_add_dirent(tdvp, node->nn_ino, cnp->cn_nameptr, - cnp->cn_namelen, IFTODT(inode->i_mode)); - if (error) { - inode->i_links_count--; - } - - node->nn_flags |= IN_CHANGE; - nandfs_itimes(vp); - DPRINTF(VNCALL, ("%s: tdvp %p vp %p cnp %p\n", - __func__, tdvp, vp, cnp)); - - return (0); -} - -static int -nandfs_create(struct vop_create_args *ap) -{ - struct vnode *dvp = ap->a_dvp; - struct vnode **vpp = ap->a_vpp; - struct componentname *cnp = ap->a_cnp; - uint16_t mode = MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode); - struct nandfs_node *dir_node = VTON(dvp); - struct nandfsmount *nmp = dir_node->nn_nmp; - struct nandfs_node *node; - int error; - - DPRINTF(VNCALL, ("%s: dvp %p\n", __func__, dvp)); - - if (nandfs_fs_full(dir_node->nn_nandfsdev)) - return (ENOSPC); - - /* Create new vnode/inode */ - error = nandfs_node_create(nmp, &node, mode); - if (error) - return (error); - node->nn_inode.i_gid = dir_node->nn_inode.i_gid; - node->nn_inode.i_uid = cnp->cn_cred->cr_uid; - - /* Add new dir entry */ - error = nandfs_add_dirent(dvp, node->nn_ino, cnp->cn_nameptr, - cnp->cn_namelen, IFTODT(mode)); - if (error) { - if (nandfs_node_destroy(node)) { - nandfs_error("%s: error destroying node %p\n", - __func__, node); - } - return (error); - } - *vpp = NTOV(node); - if ((cnp->cn_flags & MAKEENTRY) != 0) - cache_enter(dvp, *vpp, cnp); - - DPRINTF(VNCALL, ("created file vp %p nandnode %p ino %jx\n", *vpp, node, - (uintmax_t)node->nn_ino)); - return (0); -} - -static int -nandfs_remove(struct vop_remove_args *ap) -{ - struct vnode *vp = ap->a_vp; - struct vnode *dvp = ap->a_dvp; - struct nandfs_node *node = VTON(vp); - struct nandfs_node *dnode = VTON(dvp); - struct componentname *cnp = ap->a_cnp; - - DPRINTF(VNCALL, ("%s: dvp %p vp %p nandnode %p ino %#jx link %d\n", - __func__, dvp, vp, node, (uintmax_t)node->nn_ino, - node->nn_inode.i_links_count)); - - if (vp->v_type == VDIR) - return (EISDIR); - - /* Files marked as immutable or append-only cannot be deleted. */ - if ((node->nn_inode.i_flags & (IMMUTABLE | APPEND | NOUNLINK)) || - (dnode->nn_inode.i_flags & APPEND)) - return (EPERM); - - nandfs_remove_dirent(dvp, node, cnp); - node->nn_inode.i_links_count--; - node->nn_flags |= IN_CHANGE; - - return (0); -} - -/* - * Check if source directory is in the path of the target directory. - * Target is supplied locked, source is unlocked. - * The target is always vput before returning. - */ -static int -nandfs_checkpath(struct nandfs_node *src, struct nandfs_node *dest, - struct ucred *cred) -{ - struct vnode *vp; - int error, rootino; - struct nandfs_dir_entry dirent; - - vp = NTOV(dest); - if (src->nn_ino == dest->nn_ino) { - error = EEXIST; - goto out; - } - rootino = NANDFS_ROOT_INO; - error = 0; - if (dest->nn_ino == rootino) - goto out; - - for (;;) { - if (vp->v_type != VDIR) { - error = ENOTDIR; - break; - } - - error = vn_rdwr(UIO_READ, vp, (caddr_t)&dirent, - NANDFS_DIR_REC_LEN(2), (off_t)0, UIO_SYSSPACE, - IO_NODELOCKED | IO_NOMACCHECK, cred, NOCRED, - NULL, NULL); - if (error != 0) - break; - if (dirent.name_len != 2 || - dirent.name[0] != '.' || - dirent.name[1] != '.') { - error = ENOTDIR; - break; - } - if (dirent.inode == src->nn_ino) { - error = EINVAL; - break; - } - if (dirent.inode == rootino) - break; - vput(vp); - if ((error = VFS_VGET(vp->v_mount, dirent.inode, - LK_EXCLUSIVE, &vp)) != 0) { - vp = NULL; - break; - } - } - -out: - if (error == ENOTDIR) - printf("checkpath: .. not a directory\n"); - if (vp != NULL) - vput(vp); - return (error); -} - -static int -nandfs_rename(struct vop_rename_args *ap) -{ - struct vnode *tvp = ap->a_tvp; - struct vnode *tdvp = ap->a_tdvp; - struct vnode *fvp = ap->a_fvp; - struct vnode *fdvp = ap->a_fdvp; - struct componentname *tcnp = ap->a_tcnp; - struct componentname *fcnp = ap->a_fcnp; - int doingdirectory = 0, oldparent = 0, newparent = 0; - int error = 0; - - struct nandfs_node *fdnode, *fnode, *fnode1; - struct nandfs_node *tdnode = VTON(tdvp); - struct nandfs_node *tnode; - - uint32_t tdflags, fflags, fdflags; - uint16_t mode; - - DPRINTF(VNCALL, ("%s: fdvp:%p fvp:%p tdvp:%p tdp:%p\n", __func__, fdvp, - fvp, tdvp, tvp)); - - /* - * Check for cross-device rename. - */ - if ((fvp->v_mount != tdvp->v_mount) || - (tvp && (fvp->v_mount != tvp->v_mount))) { - error = EXDEV; -abortit: - if (tdvp == tvp) - vrele(tdvp); - else - vput(tdvp); - if (tvp) - vput(tvp); - vrele(fdvp); - vrele(fvp); - return (error); - } - - tdflags = tdnode->nn_inode.i_flags; - if (tvp && - ((VTON(tvp)->nn_inode.i_flags & (NOUNLINK | IMMUTABLE | APPEND)) || - (tdflags & APPEND))) { - error = EPERM; - goto abortit; - } - - /* - * Renaming a file to itself has no effect. The upper layers should - * not call us in that case. Temporarily just warn if they do. - */ - if (fvp == tvp) { - printf("nandfs_rename: fvp == tvp (can't happen)\n"); - error = 0; - goto abortit; - } - - if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0) - goto abortit; - - fdnode = VTON(fdvp); - fnode = VTON(fvp); - - if (fnode->nn_inode.i_links_count >= NANDFS_LINK_MAX) { - VOP_UNLOCK(fvp, 0); - error = EMLINK; - goto abortit; - } - - fflags = fnode->nn_inode.i_flags; - fdflags = fdnode->nn_inode.i_flags; - - if ((fflags & (NOUNLINK | IMMUTABLE | APPEND)) || - (fdflags & APPEND)) { - VOP_UNLOCK(fvp, 0); - error = EPERM; - goto abortit; - } - - mode = fnode->nn_inode.i_mode; - if ((mode & S_IFMT) == S_IFDIR) { - /* - * Avoid ".", "..", and aliases of "." for obvious reasons. - */ - - if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') || - (fdvp == fvp) || - ((fcnp->cn_flags | tcnp->cn_flags) & ISDOTDOT) || - (fnode->nn_flags & IN_RENAME)) { - VOP_UNLOCK(fvp, 0); - error = EINVAL; - goto abortit; - } - fnode->nn_flags |= IN_RENAME; - doingdirectory = 1; - DPRINTF(VNCALL, ("%s: doingdirectory dvp %p\n", __func__, - tdvp)); - oldparent = fdnode->nn_ino; - } - - vrele(fdvp); - - tnode = NULL; - if (tvp) - tnode = VTON(tvp); - - /* - * Bump link count on fvp while we are moving stuff around. If we - * crash before completing the work, the link count may be wrong - * but correctable. - */ - fnode->nn_inode.i_links_count++; - - /* Check for in path moving XXX */ - error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_thread); - VOP_UNLOCK(fvp, 0); - if (oldparent != tdnode->nn_ino) - newparent = tdnode->nn_ino; - if (doingdirectory && newparent) { - if (error) /* write access check above */ - goto bad; - if (tnode != NULL) - vput(tvp); - - error = nandfs_checkpath(fnode, tdnode, tcnp->cn_cred); - if (error) - goto out; - - VREF(tdvp); - error = relookup(tdvp, &tvp, tcnp); - if (error) - goto out; - vrele(tdvp); - tdnode = VTON(tdvp); - tnode = NULL; - if (tvp) - tnode = VTON(tvp); - } - - /* - * If the target doesn't exist, link the target to the source and - * unlink the source. Otherwise, rewrite the target directory to - * reference the source and remove the original entry. - */ - - if (tvp == NULL) { - /* - * Account for ".." in new directory. - */ - if (doingdirectory && fdvp != tdvp) - tdnode->nn_inode.i_links_count++; - - DPRINTF(VNCALL, ("%s: new entry in dvp:%p\n", __func__, tdvp)); - /* - * Add name in new directory. - */ - error = nandfs_add_dirent(tdvp, fnode->nn_ino, tcnp->cn_nameptr, - tcnp->cn_namelen, IFTODT(fnode->nn_inode.i_mode)); - if (error) { - if (doingdirectory && fdvp != tdvp) - tdnode->nn_inode.i_links_count--; - goto bad; - } - - vput(tdvp); - } else { - /* - * If the parent directory is "sticky", then the user must - * own the parent directory, or the destination of the rename, - * otherwise the destination may not be changed (except by - * root). This implements append-only directories. - */ - if ((tdnode->nn_inode.i_mode & S_ISTXT) && - tcnp->cn_cred->cr_uid != 0 && - tcnp->cn_cred->cr_uid != tdnode->nn_inode.i_uid && - tnode->nn_inode.i_uid != tcnp->cn_cred->cr_uid) { - error = EPERM; - goto bad; - } - /* - * Target must be empty if a directory and have no links - * to it. Also, ensure source and target are compatible - * (both directories, or both not directories). - */ - mode = tnode->nn_inode.i_mode; - if ((mode & S_IFMT) == S_IFDIR) { - if (!nandfs_dirempty(tvp, tdnode->nn_ino, - tcnp->cn_cred)) { - error = ENOTEMPTY; - goto bad; - } - if (!doingdirectory) { - error = ENOTDIR; - goto bad; - } - /* - * Update name cache since directory is going away. - */ - cache_purge(tdvp); - } else if (doingdirectory) { - error = EISDIR; - goto bad; - } - - DPRINTF(VNCALL, ("%s: update entry dvp:%p\n", __func__, tdvp)); - /* - * Change name tcnp in tdvp to point at fvp. - */ - error = nandfs_update_dirent(tdvp, fnode, tnode); - if (error) - goto bad; - - if (doingdirectory && !newparent) - tdnode->nn_inode.i_links_count--; - - vput(tdvp); - - tnode->nn_inode.i_links_count--; - vput(tvp); - tnode = NULL; - } - - /* - * Unlink the source. - */ - fcnp->cn_flags &= ~MODMASK; - fcnp->cn_flags |= LOCKPARENT | LOCKLEAF; - VREF(fdvp); - error = relookup(fdvp, &fvp, fcnp); - if (error == 0) - vrele(fdvp); - if (fvp != NULL) { - fnode1 = VTON(fvp); - fdnode = VTON(fdvp); - } else { - /* - * From name has disappeared. - */ - if (doingdirectory) - panic("nandfs_rename: lost dir entry"); - vrele(ap->a_fvp); - return (0); - } - - DPRINTF(VNCALL, ("%s: unlink source fnode:%p\n", __func__, fnode)); - - /* - * Ensure that the directory entry still exists and has not - * changed while the new name has been entered. If the source is - * a file then the entry may have been unlinked or renamed. In - * either case there is no further work to be done. If the source - * is a directory then it cannot have been rmdir'ed; its link - * count of three would cause a rmdir to fail with ENOTEMPTY. - * The IN_RENAME flag ensures that it cannot be moved by another - * rename. - */ - if (fnode != fnode1) { - if (doingdirectory) - panic("nandfs: lost dir entry"); - } else { - /* - * If the source is a directory with a - * new parent, the link count of the old - * parent directory must be decremented - * and ".." set to point to the new parent. - */ - if (doingdirectory && newparent) { - DPRINTF(VNCALL, ("%s: new parent %#jx -> %#jx\n", - __func__, (uintmax_t) oldparent, - (uintmax_t) newparent)); - error = nandfs_update_parent_dir(fvp, newparent); - if (!error) { - fdnode->nn_inode.i_links_count--; - fdnode->nn_flags |= IN_CHANGE; - } - } - error = nandfs_remove_dirent(fdvp, fnode, fcnp); - if (!error) { - fnode->nn_inode.i_links_count--; - fnode->nn_flags |= IN_CHANGE; - } - fnode->nn_flags &= ~IN_RENAME; - } - if (fdnode) - vput(fdvp); - if (fnode) - vput(fvp); - vrele(ap->a_fvp); - return (error); - -bad: - DPRINTF(VNCALL, ("%s: error:%d\n", __func__, error)); - if (tnode) - vput(NTOV(tnode)); - vput(NTOV(tdnode)); -out: - if (doingdirectory) - fnode->nn_flags &= ~IN_RENAME; - if (vn_lock(fvp, LK_EXCLUSIVE) == 0) { - fnode->nn_inode.i_links_count--; - fnode->nn_flags |= IN_CHANGE; - fnode->nn_flags &= ~IN_RENAME; - vput(fvp); - } else - vrele(fvp); - return (error); -} - -static int -nandfs_mkdir(struct vop_mkdir_args *ap) -{ - struct vnode *dvp = ap->a_dvp; - struct vnode **vpp = ap->a_vpp; - struct componentname *cnp = ap->a_cnp; - struct nandfs_node *dir_node = VTON(dvp); - struct nandfs_inode *dir_inode = &dir_node->nn_inode; - struct nandfs_node *node; - struct nandfsmount *nmp = dir_node->nn_nmp; - uint16_t mode = MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode); - int error; - - DPRINTF(VNCALL, ("%s: dvp %p\n", __func__, dvp)); - - if (nandfs_fs_full(dir_node->nn_nandfsdev)) - return (ENOSPC); - - if (dir_inode->i_links_count >= NANDFS_LINK_MAX) - return (EMLINK); - - error = nandfs_node_create(nmp, &node, mode); - if (error) - return (error); - - node->nn_inode.i_gid = dir_node->nn_inode.i_gid; - node->nn_inode.i_uid = cnp->cn_cred->cr_uid; - - *vpp = NTOV(node); - - error = nandfs_add_dirent(dvp, node->nn_ino, cnp->cn_nameptr, - cnp->cn_namelen, IFTODT(mode)); - if (error) { - vput(*vpp); - return (error); - } - - dir_node->nn_inode.i_links_count++; - dir_node->nn_flags |= IN_CHANGE; - - error = nandfs_init_dir(NTOV(node), node->nn_ino, dir_node->nn_ino); - if (error) { - vput(NTOV(node)); - return (error); - } - - DPRINTF(VNCALL, ("created dir vp %p nandnode %p ino %jx\n", *vpp, node, - (uintmax_t)node->nn_ino)); - return (0); -} - -static int -nandfs_mknod(struct vop_mknod_args *ap) -{ - struct vnode *dvp = ap->a_dvp; - struct vnode **vpp = ap->a_vpp; - struct vattr *vap = ap->a_vap; - uint16_t mode = MAKEIMODE(vap->va_type, vap->va_mode); - struct componentname *cnp = ap->a_cnp; - struct nandfs_node *dir_node = VTON(dvp); - struct nandfsmount *nmp = dir_node->nn_nmp; - struct nandfs_node *node; - int error; - - if (nandfs_fs_full(dir_node->nn_nandfsdev)) - return (ENOSPC); - - error = nandfs_node_create(nmp, &node, mode); - if (error) - return (error); - node->nn_inode.i_gid = dir_node->nn_inode.i_gid; - node->nn_inode.i_uid = cnp->cn_cred->cr_uid; - if (vap->va_rdev != VNOVAL) - node->nn_inode.i_special = vap->va_rdev; - - *vpp = NTOV(node); - - if (nandfs_add_dirent(dvp, node->nn_ino, cnp->cn_nameptr, - cnp->cn_namelen, IFTODT(mode))) { - vput(*vpp); - return (ENOTDIR); - } - - node->nn_flags |= IN_ACCESS | IN_CHANGE | IN_UPDATE; - - return (0); -} - -static int -nandfs_symlink(struct vop_symlink_args *ap) -{ - struct vnode **vpp = ap->a_vpp; - struct vnode *dvp = ap->a_dvp; - uint16_t mode = MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode); - struct componentname *cnp = ap->a_cnp; - struct nandfs_node *dir_node = VTON(dvp); - struct nandfsmount *nmp = dir_node->nn_nmp; - struct nandfs_node *node; - int len, error; - - if (nandfs_fs_full(dir_node->nn_nandfsdev)) - return (ENOSPC); - - error = nandfs_node_create(nmp, &node, S_IFLNK | mode); - if (error) - return (error); - node->nn_inode.i_gid = dir_node->nn_inode.i_gid; - node->nn_inode.i_uid = cnp->cn_cred->cr_uid; - - *vpp = NTOV(node); - - if (nandfs_add_dirent(dvp, node->nn_ino, cnp->cn_nameptr, - cnp->cn_namelen, IFTODT(mode))) { - vput(*vpp); - return (ENOTDIR); - } - - - len = strlen(ap->a_target); - error = vn_rdwr(UIO_WRITE, *vpp, __DECONST(void *, ap->a_target), - len, (off_t)0, UIO_SYSSPACE, IO_NODELOCKED | IO_NOMACCHECK, - cnp->cn_cred, NOCRED, NULL, NULL); - if (error) - vput(*vpp); - - return (error); -} - -static int -nandfs_readlink(struct vop_readlink_args *ap) -{ - struct vnode *vp = ap->a_vp; - - return (VOP_READ(vp, ap->a_uio, 0, ap->a_cred)); -} - -static int -nandfs_rmdir(struct vop_rmdir_args *ap) -{ - struct vnode *vp = ap->a_vp; - struct vnode *dvp = ap->a_dvp; - struct componentname *cnp = ap->a_cnp; - struct nandfs_node *node, *dnode; - uint32_t dflag, flag; - int error = 0; - - node = VTON(vp); - dnode = VTON(dvp); - - /* Files marked as immutable or append-only cannot be deleted. */ - if ((node->nn_inode.i_flags & (IMMUTABLE | APPEND | NOUNLINK)) || - (dnode->nn_inode.i_flags & APPEND)) - return (EPERM); - - DPRINTF(VNCALL, ("%s: dvp %p vp %p nandnode %p ino %#jx\n", __func__, - dvp, vp, node, (uintmax_t)node->nn_ino)); - - if (node->nn_inode.i_links_count < 2) - return (EINVAL); - - if (!nandfs_dirempty(vp, dnode->nn_ino, cnp->cn_cred)) - return (ENOTEMPTY); - - /* Files marked as immutable or append-only cannot be deleted. */ - dflag = dnode->nn_inode.i_flags; - flag = node->nn_inode.i_flags; - if ((dflag & APPEND) || - (flag & (NOUNLINK | IMMUTABLE | APPEND))) { - return (EPERM); - } - - if (vp->v_mountedhere != 0) - return (EINVAL); - - nandfs_remove_dirent(dvp, node, cnp); - dnode->nn_inode.i_links_count -= 1; - dnode->nn_flags |= IN_CHANGE; - - cache_purge(dvp); - - error = nandfs_truncate(vp, (uint64_t)0); - if (error) - return (error); - - node->nn_inode.i_links_count -= 2; - node->nn_flags |= IN_CHANGE; - - cache_purge(vp); - - return (error); -} - -static int -nandfs_fsync(struct vop_fsync_args *ap) -{ - struct vnode *vp = ap->a_vp; - struct nandfs_node *node = VTON(vp); - int locked; - - DPRINTF(VNCALL, ("%s: vp %p nandnode %p ino %#jx\n", __func__, vp, - node, (uintmax_t)node->nn_ino)); - - /* - * Start syncing vnode only if inode was modified or - * there are some dirty buffers - */ - if (VTON(vp)->nn_flags & IN_MODIFIED || - vp->v_bufobj.bo_dirty.bv_cnt) { - locked = VOP_ISLOCKED(vp); - VOP_UNLOCK(vp, 0); - nandfs_wakeup_wait_sync(node->nn_nandfsdev, SYNCER_FSYNC); - VOP_LOCK(vp, locked | LK_RETRY); - } - - return (0); -} - -static int -nandfs_bmap(struct vop_bmap_args *ap) -{ - struct vnode *vp = ap->a_vp; - struct nandfs_node *nnode = VTON(vp); - struct nandfs_device *nandfsdev = nnode->nn_nandfsdev; - nandfs_daddr_t l2vmap, v2pmap; - int error; - int blk2dev = nandfsdev->nd_blocksize / DEV_BSIZE; - - DPRINTF(VNCALL, ("%s: vp %p nandnode %p ino %#jx\n", __func__, vp, - nnode, (uintmax_t)nnode->nn_ino)); - - if (ap->a_bop != NULL) - *ap->a_bop = &nandfsdev->nd_devvp->v_bufobj; - if (ap->a_bnp == NULL) - return (0); - if (ap->a_runp != NULL) - *ap->a_runp = 0; - if (ap->a_runb != NULL) - *ap->a_runb = 0; - - /* - * Translate all the block sectors into a series of buffers to read - * asynchronously from the nandfs device. Note that this lookup may - * induce readin's too. - */ - - /* Get virtual block numbers for the vnode's buffer span */ - error = nandfs_bmap_lookup(nnode, ap->a_bn, &l2vmap); - if (error) - return (-1); - - /* Translate virtual block numbers to physical block numbers */ - error = nandfs_vtop(nnode, l2vmap, &v2pmap); - if (error) - return (-1); - - /* Note virtual block 0 marks not mapped */ - if (l2vmap == 0) - *ap->a_bnp = -1; - else - *ap->a_bnp = v2pmap * blk2dev; /* in DEV_BSIZE */ - - DPRINTF(VNCALL, ("%s: vp %p nandnode %p ino %#jx lblk %jx -> blk %jx\n", - __func__, vp, nnode, (uintmax_t)nnode->nn_ino, (uintmax_t)ap->a_bn, - (uintmax_t)*ap->a_bnp )); - - return (0); -} - -static void -nandfs_force_syncer(struct nandfsmount *nmp) -{ - - nmp->nm_flags |= NANDFS_FORCE_SYNCER; - nandfs_wakeup_wait_sync(nmp->nm_nandfsdev, SYNCER_FFORCE); -} - -static int -nandfs_ioctl(struct vop_ioctl_args *ap) -{ - struct vnode *vp = ap->a_vp; - u_long command = ap->a_command; - caddr_t data = ap->a_data; - struct nandfs_node *node = VTON(vp); - struct nandfs_device *nandfsdev = node->nn_nandfsdev; - struct nandfsmount *nmp = node->nn_nmp; - uint64_t *tab, *cno; - struct nandfs_seg_stat *nss; - struct nandfs_cpmode *ncpm; - struct nandfs_argv *nargv; - struct nandfs_cpstat *ncp; - int error; - - DPRINTF(VNCALL, ("%s: %x\n", __func__, (uint32_t)command)); - - error = priv_check(ap->a_td, PRIV_VFS_MOUNT); - if (error) - return (error); - - if (nmp->nm_ronly) { - switch (command) { - case NANDFS_IOCTL_GET_FSINFO: - case NANDFS_IOCTL_GET_SUSTAT: - case NANDFS_IOCTL_GET_CPINFO: - case NANDFS_IOCTL_GET_CPSTAT: - case NANDFS_IOCTL_GET_SUINFO: - case NANDFS_IOCTL_GET_VINFO: - case NANDFS_IOCTL_GET_BDESCS: - break; - default: - return (EROFS); - } - } - - switch (command) { - case NANDFS_IOCTL_GET_FSINFO: - error = nandfs_get_fsinfo(nmp, (struct nandfs_fsinfo *)data); - break; - case NANDFS_IOCTL_GET_SUSTAT: - nss = (struct nandfs_seg_stat *)data; - error = nandfs_get_seg_stat(nandfsdev, nss); - break; - case NANDFS_IOCTL_CHANGE_CPMODE: - ncpm = (struct nandfs_cpmode *)data; - error = nandfs_chng_cpmode(nandfsdev->nd_cp_node, ncpm); - nandfs_force_syncer(nmp); - break; - case NANDFS_IOCTL_GET_CPINFO: - nargv = (struct nandfs_argv *)data; - error = nandfs_get_cpinfo_ioctl(nandfsdev->nd_cp_node, nargv); - break; - case NANDFS_IOCTL_DELETE_CP: - tab = (uint64_t *)data; - error = nandfs_delete_cp(nandfsdev->nd_cp_node, tab[0], tab[1]); - nandfs_force_syncer(nmp); - break; - case NANDFS_IOCTL_GET_CPSTAT: - ncp = (struct nandfs_cpstat *)data; - error = nandfs_get_cpstat(nandfsdev->nd_cp_node, ncp); - break; - case NANDFS_IOCTL_GET_SUINFO: - nargv = (struct nandfs_argv *)data; - error = nandfs_get_segment_info_ioctl(nandfsdev, nargv); - break; - case NANDFS_IOCTL_GET_VINFO: - nargv = (struct nandfs_argv *)data; - error = nandfs_get_dat_vinfo_ioctl(nandfsdev, nargv); - break; - case NANDFS_IOCTL_GET_BDESCS: - nargv = (struct nandfs_argv *)data; - error = nandfs_get_dat_bdescs_ioctl(nandfsdev, nargv); - break; - case NANDFS_IOCTL_SYNC: - cno = (uint64_t *)data; - nandfs_force_syncer(nmp); - *cno = nandfsdev->nd_last_cno; - error = 0; - break; - case NANDFS_IOCTL_MAKE_SNAP: - cno = (uint64_t *)data; - error = nandfs_make_snap(nandfsdev, cno); - nandfs_force_syncer(nmp); - break; - case NANDFS_IOCTL_DELETE_SNAP: - cno = (uint64_t *)data; - error = nandfs_delete_snap(nandfsdev, *cno); - nandfs_force_syncer(nmp); - break; - default: - error = ENOTTY; - break; - } - - return (error); -} - -/* - * Whiteout vnode call - */ -static int -nandfs_whiteout(struct vop_whiteout_args *ap) -{ - struct vnode *dvp = ap->a_dvp; - struct componentname *cnp = ap->a_cnp; - int error = 0; - - switch (ap->a_flags) { - case LOOKUP: - return (0); - case CREATE: - /* Create a new directory whiteout */ -#ifdef INVARIANTS - if ((cnp->cn_flags & SAVENAME) == 0) - panic("nandfs_whiteout: missing name"); -#endif - error = nandfs_add_dirent(dvp, NANDFS_WHT_INO, cnp->cn_nameptr, - cnp->cn_namelen, DT_WHT); - break; - - case DELETE: - /* Remove an existing directory whiteout */ - cnp->cn_flags &= ~DOWHITEOUT; - error = nandfs_remove_dirent(dvp, NULL, cnp); - break; - default: - panic("nandf_whiteout: unknown op: %d", ap->a_flags); - } - - return (error); -} - -static int -nandfs_pathconf(struct vop_pathconf_args *ap) -{ - int error; - - error = 0; - switch (ap->a_name) { - case _PC_LINK_MAX: - *ap->a_retval = NANDFS_LINK_MAX; - break; - case _PC_NAME_MAX: - *ap->a_retval = NANDFS_NAME_LEN; - break; - case _PC_PIPE_BUF: - if (ap->a_vp->v_type == VDIR || ap->a_vp->v_type == VFIFO) - *ap->a_retval = PIPE_BUF; - else - error = EINVAL; - break; - case _PC_CHOWN_RESTRICTED: - *ap->a_retval = 1; - break; - case _PC_NO_TRUNC: - *ap->a_retval = 1; - break; - case _PC_ALLOC_SIZE_MIN: - *ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_bsize; - break; - case _PC_FILESIZEBITS: - *ap->a_retval = 64; - break; - case _PC_REC_INCR_XFER_SIZE: - *ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_iosize; - break; - case _PC_REC_MAX_XFER_SIZE: - *ap->a_retval = -1; /* means ``unlimited'' */ - break; - case _PC_REC_MIN_XFER_SIZE: - *ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_iosize; - break; - default: - error = vop_stdpathconf(ap); - break; - } - return (error); -} - -static int -nandfs_vnlock1(struct vop_lock1_args *ap) -{ - struct vnode *vp = ap->a_vp; - struct nandfs_node *node = VTON(vp); - int error, vi_locked; - - /* - * XXX can vnode go away while we are sleeping? - */ - vi_locked = mtx_owned(&vp->v_interlock); - if (vi_locked) - VI_UNLOCK(vp); - error = NANDFS_WRITELOCKFLAGS(node->nn_nandfsdev, - ap->a_flags & LK_NOWAIT); - if (vi_locked && !error) - VI_LOCK(vp); - if (error) - return (error); - - error = vop_stdlock(ap); - if (error) { - NANDFS_WRITEUNLOCK(node->nn_nandfsdev); - return (error); - } - - return (0); -} - -static int -nandfs_vnunlock(struct vop_unlock_args *ap) -{ - struct vnode *vp = ap->a_vp; - struct nandfs_node *node = VTON(vp); - int error; - - error = vop_stdunlock(ap); - if (error) - return (error); - - NANDFS_WRITEUNLOCK(node->nn_nandfsdev); - - return (0); -} - -/* - * Global vfs data structures - */ -struct vop_vector nandfs_vnodeops = { - .vop_default = &default_vnodeops, - .vop_access = nandfs_access, - .vop_advlock = nandfs_advlock, - .vop_bmap = nandfs_bmap, - .vop_close = nandfs_close, - .vop_create = nandfs_create, - .vop_fsync = nandfs_fsync, - .vop_getattr = nandfs_getattr, - .vop_inactive = nandfs_inactive, - .vop_cachedlookup = nandfs_lookup, - .vop_ioctl = nandfs_ioctl, - .vop_link = nandfs_link, - .vop_lookup = vfs_cache_lookup, - .vop_mkdir = nandfs_mkdir, - .vop_mknod = nandfs_mknod, - .vop_open = nandfs_open, - .vop_pathconf = nandfs_pathconf, - .vop_print = nandfs_print, - .vop_read = nandfs_read, - .vop_readdir = nandfs_readdir, - .vop_readlink = nandfs_readlink, - .vop_reclaim = nandfs_reclaim, - .vop_remove = nandfs_remove, - .vop_rename = nandfs_rename, - .vop_rmdir = nandfs_rmdir, - .vop_whiteout = nandfs_whiteout, - .vop_write = nandfs_write, - .vop_setattr = nandfs_setattr, - .vop_strategy = nandfs_strategy, - .vop_symlink = nandfs_symlink, - .vop_lock1 = nandfs_vnlock1, - .vop_unlock = nandfs_vnunlock, -}; - -struct vop_vector nandfs_system_vnodeops = { - .vop_default = &default_vnodeops, - .vop_close = nandfs_close, - .vop_inactive = nandfs_inactive, - .vop_reclaim = nandfs_reclaim, - .vop_strategy = nandfs_strategy, - .vop_fsync = nandfs_fsync, - .vop_bmap = nandfs_bmap, - .vop_access = VOP_PANIC, - .vop_advlock = VOP_PANIC, - .vop_create = VOP_PANIC, - .vop_getattr = VOP_PANIC, - .vop_cachedlookup = VOP_PANIC, - .vop_ioctl = VOP_PANIC, - .vop_link = VOP_PANIC, - .vop_lookup = VOP_PANIC, - .vop_mkdir = VOP_PANIC, - .vop_mknod = VOP_PANIC, - .vop_open = VOP_PANIC, - .vop_pathconf = VOP_PANIC, - .vop_print = VOP_PANIC, - .vop_read = VOP_PANIC, - .vop_readdir = VOP_PANIC, - .vop_readlink = VOP_PANIC, - .vop_remove = VOP_PANIC, - .vop_rename = VOP_PANIC, - .vop_rmdir = VOP_PANIC, - .vop_whiteout = VOP_PANIC, - .vop_write = VOP_PANIC, - .vop_setattr = VOP_PANIC, - .vop_symlink = VOP_PANIC, -}; - -static int -nandfsfifo_close(struct vop_close_args *ap) -{ - struct vnode *vp = ap->a_vp; - struct nandfs_node *node = VTON(vp); - - DPRINTF(VNCALL, ("%s: vp %p node %p\n", __func__, vp, node)); - - mtx_lock(&vp->v_interlock); - if (vp->v_usecount > 1) - nandfs_itimes_locked(vp); - mtx_unlock(&vp->v_interlock); - - return (fifo_specops.vop_close(ap)); -} - -struct vop_vector nandfs_fifoops = { - .vop_default = &fifo_specops, - .vop_fsync = VOP_PANIC, - .vop_access = nandfs_access, - .vop_close = nandfsfifo_close, - .vop_getattr = nandfs_getattr, - .vop_inactive = nandfs_inactive, - .vop_pathconf = nandfs_pathconf, - .vop_print = nandfs_print, - .vop_read = VOP_PANIC, - .vop_reclaim = nandfs_reclaim, - .vop_setattr = nandfs_setattr, - .vop_write = VOP_PANIC, - .vop_lock1 = nandfs_vnlock1, - .vop_unlock = nandfs_vnunlock, -}; - -int -nandfs_vinit(struct vnode *vp, uint64_t ino) -{ - struct nandfs_node *node; - - ASSERT_VOP_LOCKED(vp, __func__); - - node = VTON(vp); - - /* Check if we're fetching the root */ - if (ino == NANDFS_ROOT_INO) - vp->v_vflag |= VV_ROOT; - - if (ino != NANDFS_GC_INO) - vp->v_type = IFTOVT(node->nn_inode.i_mode); - else - vp->v_type = VREG; - - if (vp->v_type == VFIFO) - vp->v_op = &nandfs_fifoops; - - return (0); -} diff --git a/sys/fs/smbfs/smbfs_io.c b/sys/fs/smbfs/smbfs_io.c index 4edba5c761e7f..fa6a140242137 100644 --- a/sys/fs/smbfs/smbfs_io.c +++ b/sys/fs/smbfs/smbfs_io.c @@ -375,9 +375,6 @@ smbfs_doio(struct vnode *vp, struct buf *bp, struct ucred *cr, struct thread *td */ if (error == EINTR || (!error && (bp->b_flags & B_NEEDCOMMIT))) { - int s; - - s = splbio(); bp->b_flags &= ~(B_INVAL|B_NOCACHE); if ((bp->b_flags & B_ASYNC) == 0) bp->b_flags |= B_EINTR; @@ -387,7 +384,6 @@ smbfs_doio(struct vnode *vp, struct buf *bp, struct ucred *cr, struct thread *td } if ((bp->b_flags & B_ASYNC) == 0) bp->b_flags |= B_EINTR; - splx(s); } else { if (error) { bp->b_ioflags |= BIO_ERROR; diff --git a/sys/geom/geom_flashmap.c b/sys/geom/geom_flashmap.c index ac7344a34bb61..71007a4f7936d 100644 --- a/sys/geom/geom_flashmap.c +++ b/sys/geom/geom_flashmap.c @@ -43,8 +43,6 @@ __FBSDID("$FreeBSD$"); #include <geom/geom_flashmap.h> #include <geom/geom_slice.h> -#include <dev/nand/nand_dev.h> - struct g_flashmap_slice { off_t sl_start; off_t sl_end; @@ -65,7 +63,6 @@ static struct { { "MMC::device", NULL } }; -static g_ioctl_t g_flashmap_ioctl; static g_taste_t g_flashmap_taste; static int g_flashmap_load(device_t dev, struct g_provider *pp, @@ -127,26 +124,6 @@ g_flashmap_modify(struct g_flashmap *gfp, struct g_geom *gp, return (0); } -static int -g_flashmap_ioctl(struct g_provider *pp, u_long cmd, void *data, int fflag, - struct thread *td) -{ - struct g_consumer *cp; - struct g_geom *gp; - - if (cmd != NAND_IO_GET_CHIP_PARAM) - return (ENOIOCTL); - - cp = LIST_FIRST(&pp->geom->consumer); - if (cp == NULL) - return (ENOIOCTL); - gp = cp->provider->geom; - if (gp->ioctl == NULL) - return (ENOIOCTL); - - return (gp->ioctl(cp->provider, cmd, data, fflag, td)); -} - static struct g_geom * g_flashmap_taste(struct g_class *mp, struct g_provider *pp, int flags) { @@ -245,7 +222,6 @@ static struct g_class g_flashmap_class = { .name = FLASHMAP_CLASS_NAME, .version = G_VERSION, .taste = g_flashmap_taste, - .ioctl = g_flashmap_ioctl, }; DECLARE_GEOM_CLASS(g_flashmap_class, g_flashmap); diff --git a/sys/i386/conf/GENERIC b/sys/i386/conf/GENERIC index dab73ee51da6e..ddeabf5952c8b 100644 --- a/sys/i386/conf/GENERIC +++ b/sys/i386/conf/GENERIC @@ -292,7 +292,6 @@ device wpi # Intel 3945ABG wireless NICs. # Pseudo devices. device crypto # core crypto support device loop # Network loopback -device random # Entropy device device padlock_rng # VIA Padlock RNG device rdrand_rng # Intel Bull Mountain RNG device ether # Ethernet support diff --git a/sys/i386/conf/MINIMAL b/sys/i386/conf/MINIMAL index 0b0bd23f40b40..0f1d268d013ee 100644 --- a/sys/i386/conf/MINIMAL +++ b/sys/i386/conf/MINIMAL @@ -10,7 +10,7 @@ # some features (ACL, GJOURNAL) that GENERIC includes. # o acpi as a module has been reported flakey and not well tested, so # is included in the kernel. -# o random is included due to uncertaty... +# o (non-loaded) random is included due to uncertainty... # o Many networking things are included # # For now, please run changes to these list past imp@freebsd.org @@ -132,7 +132,6 @@ device agp # support several AGP chipsets # Pseudo devices. device loop # Network loopback -device random # Entropy device device padlock_rng # VIA Padlock RNG device rdrand_rng # Intel Bull Mountain RNG device ether # Ethernet support diff --git a/sys/kern/Make.tags.inc b/sys/kern/Make.tags.inc index 50aed68dbf40d..cdefa98a32f65 100644 --- a/sys/kern/Make.tags.inc +++ b/sys/kern/Make.tags.inc @@ -28,7 +28,6 @@ COMM= ${SYS}/sys/vnode.h \ ${SYS}/fs/fifofs/*.[ch] \ ${SYS}/fs/fuse/*.[ch] \ ${SYS}/fs/msdosfs/*.[ch] \ - ${SYS}/fs/nandfs/*.[ch] \ ${SYS}/fs/nfs/*.[ch] \ ${SYS}/fs/nfsclient/*.[ch] \ ${SYS}/fs/nfsserver/*.[ch] \ @@ -82,7 +81,6 @@ COMMDIR2= ${SYS}/dev/alc \ ${SYS}/fs/fifofs \ ${SYS}/fs/fuse \ ${SYS}/fs/msdosfs \ - ${SYS}/fs/nandfs \ ${SYS}/fs/nfs \ ${SYS}/fs/nfsclient \ ${SYS}/fs/nfsserver \ diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index 4d09eea37d562..4bc1a1546820b 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -780,7 +780,9 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) } if (arg >= 0) { bsize = fp->f_vnode->v_mount->mnt_stat.f_iosize; - fp->f_seqcount = (arg + bsize - 1) / bsize; + arg = MIN(arg, INT_MAX - bsize + 1); + fp->f_seqcount = MIN(IO_SEQMAX, + (arg + bsize - 1) / bsize); atomic_set_int(&fp->f_flag, FRDAHEAD); } else { atomic_clear_int(&fp->f_flag, FRDAHEAD); diff --git a/sys/kern/kern_mib.c b/sys/kern/kern_mib.c index a92f6488c39f3..54cdff1482472 100644 --- a/sys/kern/kern_mib.c +++ b/sys/kern/kern_mib.c @@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$"); #include "opt_config.h" #include <sys/param.h> +#include <sys/boot.h> #include <sys/jail.h> #include <sys/kernel.h> #include <sys/limits.h> @@ -136,7 +137,7 @@ SYSCTL_INT(_kern, KERN_SAVED_IDS, saved_ids, CTLFLAG_RD|CTLFLAG_CAPRD, SYSCTL_NULL_INT_PTR, 0, "Whether saved set-group/user ID is available"); #endif -char kernelname[MAXPATHLEN] = "/boot/kernel/kernel"; /* XXX bloat */ +char kernelname[MAXPATHLEN] = PATH_KERNEL; /* XXX bloat */ SYSCTL_STRING(_kern, KERN_BOOTFILE, bootfile, CTLFLAG_RW | CTLFLAG_MPSAFE, kernelname, sizeof kernelname, "Name of kernel file booted"); diff --git a/sys/kern/kern_rangelock.c b/sys/kern/kern_rangelock.c index 35bd6e864d374..b434ac4b4c1c7 100644 --- a/sys/kern/kern_rangelock.c +++ b/sys/kern/kern_rangelock.c @@ -141,15 +141,33 @@ out: static void rangelock_unlock_locked(struct rangelock *lock, struct rl_q_entry *entry, - struct mtx *ilk) + struct mtx *ilk, bool do_calc_block) { MPASS(lock != NULL && entry != NULL && ilk != NULL); mtx_assert(ilk, MA_OWNED); - KASSERT(entry != lock->rl_currdep, ("stuck currdep")); + + if (!do_calc_block) { + /* + * This is the case where rangelock_enqueue() has been called + * with trylock == true and just inserted this entry in the + * queue. + * If rl_currdep is this entry, rl_currdep needs to + * be set to the next entry in the rl_waiters list. + * However, since this entry is the last entry in the + * list, the next entry is NULL. + */ + if (lock->rl_currdep == entry) { + KASSERT(TAILQ_NEXT(lock->rl_currdep, rl_q_link) == NULL, + ("rangelock_enqueue: next entry not NULL")); + lock->rl_currdep = NULL; + } + } else + KASSERT(entry != lock->rl_currdep, ("stuck currdep")); TAILQ_REMOVE(&lock->rl_waiters, entry, rl_q_link); - rangelock_calc_block(lock); + if (do_calc_block) + rangelock_calc_block(lock); mtx_unlock(ilk); if (curthread->td_rlqe == NULL) curthread->td_rlqe = entry; @@ -164,7 +182,7 @@ rangelock_unlock(struct rangelock *lock, void *cookie, struct mtx *ilk) MPASS(lock != NULL && cookie != NULL && ilk != NULL); mtx_lock(ilk); - rangelock_unlock_locked(lock, cookie, ilk); + rangelock_unlock_locked(lock, cookie, ilk, true); } /* @@ -185,7 +203,7 @@ rangelock_unlock_range(struct rangelock *lock, void *cookie, off_t start, mtx_lock(ilk); if (entry->rl_q_end == end) { - rangelock_unlock_locked(lock, cookie, ilk); + rangelock_unlock_locked(lock, cookie, ilk, true); return (NULL); } entry->rl_q_end = end; @@ -196,11 +214,11 @@ rangelock_unlock_range(struct rangelock *lock, void *cookie, off_t start, /* * Add the lock request to the queue of the pending requests for - * rangelock. Sleep until the request can be granted. + * rangelock. Sleep until the request can be granted unless trylock == true. */ static void * rangelock_enqueue(struct rangelock *lock, off_t start, off_t end, int mode, - struct mtx *ilk) + struct mtx *ilk, bool trylock) { struct rl_q_entry *entry; struct thread *td; @@ -226,11 +244,28 @@ rangelock_enqueue(struct rangelock *lock, off_t start, off_t end, int mode, */ TAILQ_INSERT_TAIL(&lock->rl_waiters, entry, rl_q_link); + /* + * If rl_currdep == NULL, there is no entry waiting for a conflicting + * range to be resolved, so set rl_currdep to this entry. If there is + * no conflicting entry for this entry, rl_currdep will be set back to + * NULL by rangelock_calc_block(). + */ if (lock->rl_currdep == NULL) lock->rl_currdep = entry; rangelock_calc_block(lock); - while (!(entry->rl_q_flags & RL_LOCK_GRANTED)) + while (!(entry->rl_q_flags & RL_LOCK_GRANTED)) { + if (trylock) { + /* + * For this case, the range is not actually locked + * yet, but removal from the list requires the same + * steps, except for not doing a rangelock_calc_block() + * call, since rangelock_calc_block() was called above. + */ + rangelock_unlock_locked(lock, entry, ilk, false); + return (NULL); + } msleep(entry, ilk, 0, "range", 0); + } mtx_unlock(ilk); return (entry); } @@ -239,12 +274,28 @@ void * rangelock_rlock(struct rangelock *lock, off_t start, off_t end, struct mtx *ilk) { - return (rangelock_enqueue(lock, start, end, RL_LOCK_READ, ilk)); + return (rangelock_enqueue(lock, start, end, RL_LOCK_READ, ilk, false)); +} + +void * +rangelock_tryrlock(struct rangelock *lock, off_t start, off_t end, + struct mtx *ilk) +{ + + return (rangelock_enqueue(lock, start, end, RL_LOCK_READ, ilk, true)); } void * rangelock_wlock(struct rangelock *lock, off_t start, off_t end, struct mtx *ilk) { - return (rangelock_enqueue(lock, start, end, RL_LOCK_WRITE, ilk)); + return (rangelock_enqueue(lock, start, end, RL_LOCK_WRITE, ilk, false)); +} + +void * +rangelock_trywlock(struct rangelock *lock, off_t start, off_t end, + struct mtx *ilk) +{ + + return (rangelock_enqueue(lock, start, end, RL_LOCK_WRITE, ilk, true)); } diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index 044865a489a69..8a1ee1e53cbe1 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -3415,10 +3415,16 @@ corefile_open_last(struct thread *td, char *name, int indexpos, } if (oldvp != NULL) { - if (nextvp == NULL) - nextvp = oldvp; - else + if (nextvp == NULL) { + if ((td->td_proc->p_flag & P_SUGID) != 0) { + error = EFAULT; + vnode_close_locked(td, oldvp); + } else { + nextvp = oldvp; + } + } else { vnode_close_locked(td, oldvp); + } } if (error != 0) { if (nextvp != NULL) @@ -3538,6 +3544,8 @@ corefile_open(const char *comm, uid_t uid, pid_t pid, struct thread *td, oflags = VN_OPEN_NOAUDIT | VN_OPEN_NAMECACHE | (capmode_coredump ? VN_OPEN_NOCAPCHECK : 0); flags = O_CREAT | FWRITE | O_NOFOLLOW; + if ((td->td_proc->p_flag & P_SUGID) != 0) + flags |= O_EXCL; NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, name, td); error = vn_open_cred(&nd, &flags, cmode, oflags, td->td_ucred, @@ -3614,10 +3622,11 @@ coredump(struct thread *td) /* * Don't dump to non-regular files or files with links. - * Do not dump into system files. + * Do not dump into system files. Effective user must own the corefile. */ if (vp->v_type != VREG || VOP_GETATTR(vp, &vattr, cred) != 0 || - vattr.va_nlink != 1 || (vp->v_vflag & VV_SYSTEM) != 0) { + vattr.va_nlink != 1 || (vp->v_vflag & VV_SYSTEM) != 0 || + vattr.va_uid != cred->cr_uid) { VOP_UNLOCK(vp, 0); error = EFAULT; goto out; diff --git a/sys/kern/sys_pipe.c b/sys/kern/sys_pipe.c index eafb902601d7f..3c04e8607a718 100644 --- a/sys/kern/sys_pipe.c +++ b/sys/kern/sys_pipe.c @@ -1414,7 +1414,7 @@ pipe_poll(struct file *fp, int events, struct ucred *active_cred, levents = events & (POLLIN | POLLINIGNEOF | POLLPRI | POLLRDNORM | POLLRDBAND); if (rpipe->pipe_state & PIPE_NAMED && fp->f_flag & FREAD && levents && - fp->f_seqcount == rpipe->pipe_wgen) + fp->f_pipegen == rpipe->pipe_wgen) events |= POLLINIGNEOF; if ((events & POLLINIGNEOF) == 0) { diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c index e38f8c06bbb36..05be168e8a841 100644 --- a/sys/kern/uipc_socket.c +++ b/sys/kern/uipc_socket.c @@ -1044,7 +1044,7 @@ sofree(struct socket *so) * * We used to do a lot of socket buffer and socket locking here, as * well as invoke sorflush() and perform wakeups. The direct call to - * dom_dispose() and sbrelease_internal() are an inlining of what was + * dom_dispose() and sbdestroy() are an inlining of what was * necessary from sorflush(). * * Notice that the socket buffer and kqueue state are torn down diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c index 7871e536b56e5..aba141c262494 100644 --- a/sys/kern/vfs_vnops.c +++ b/sys/kern/vfs_vnops.c @@ -499,9 +499,8 @@ sequential_heuristic(struct uio *uio, struct file *fp) * closely related to the best I/O size for real disks than * to any block size used by software. */ - fp->f_seqcount += howmany(uio->uio_resid, 16384); - if (fp->f_seqcount > IO_SEQMAX) - fp->f_seqcount = IO_SEQMAX; + fp->f_seqcount += lmin(IO_SEQMAX, + howmany(uio->uio_resid, 16384)); return (fp->f_seqcount << IO_SEQSHIFT); } diff --git a/sys/mips/conf/BCM b/sys/mips/conf/BCM index 5c2753279a234..27d93766c3549 100644 --- a/sys/mips/conf/BCM +++ b/sys/mips/conf/BCM @@ -82,7 +82,6 @@ device uart #Base device loop device ether -device random device md #Performance diff --git a/sys/mips/conf/BERI_DE4_BASE b/sys/mips/conf/BERI_DE4_BASE index 0985d60e60d1a..7719009ccf5ae 100644 --- a/sys/mips/conf/BERI_DE4_BASE +++ b/sys/mips/conf/BERI_DE4_BASE @@ -44,6 +44,7 @@ options DEVICE_POLLING # # DMA support # +options ALTERA_MSGDMA_DESC_PF_STD device xdma device altera_softdma device altera_msgdma diff --git a/sys/mips/conf/DIR-825B1 b/sys/mips/conf/DIR-825B1 index 80a1d17c0ac08..8b43cf1b22ca9 100644 --- a/sys/mips/conf/DIR-825B1 +++ b/sys/mips/conf/DIR-825B1 @@ -21,7 +21,6 @@ hints "DIR-825B1.hints" # Since the kernel image must fit inside 1024KiB, we have to build almost # everything as modules. -# nodevice random nodevice gpio nodevice gpioled nodevice gif diff --git a/sys/mips/conf/ERL b/sys/mips/conf/ERL index f12f6228bd95d..a0e79450c871d 100644 --- a/sys/mips/conf/ERL +++ b/sys/mips/conf/ERL @@ -149,7 +149,6 @@ device wlan_amrr # AMRR transmit rate control algorithm # Pseudo devices. device loop # Network loopback -device random # Entropy device device ether # Ethernet support device vlan # 802.1Q VLAN support device tuntap # Packet tunnel. diff --git a/sys/mips/conf/JZ4780 b/sys/mips/conf/JZ4780 index a3716cbe48733..459f908857a64 100644 --- a/sys/mips/conf/JZ4780 +++ b/sys/mips/conf/JZ4780 @@ -68,7 +68,6 @@ device miibus device bpf device md device uart -device random device fdt_pinctrl diff --git a/sys/mips/conf/OCTEON1 b/sys/mips/conf/OCTEON1 index 6c536f0d6ed46..256b66eff71fd 100644 --- a/sys/mips/conf/OCTEON1 +++ b/sys/mips/conf/OCTEON1 @@ -184,7 +184,6 @@ device ral # Ralink Technology RT2500 wireless NICs. # Pseudo devices. device loop # Network loopback -device random # Entropy device device ether # Ethernet support device vlan # 802.1Q VLAN support device tuntap # Packet tunnel. diff --git a/sys/mips/conf/PB92 b/sys/mips/conf/PB92 index 4d3e890d0f968..64a0e6db120b8 100644 --- a/sys/mips/conf/PB92 +++ b/sys/mips/conf/PB92 @@ -133,5 +133,4 @@ device loop device ether #device md #device bpf -device random #device if_bridge diff --git a/sys/mips/conf/PICOSTATION_M2HP b/sys/mips/conf/PICOSTATION_M2HP index e331f7764d2db..38e3d69c05091 100644 --- a/sys/mips/conf/PICOSTATION_M2HP +++ b/sys/mips/conf/PICOSTATION_M2HP @@ -68,6 +68,3 @@ device arswitch # Enable GPIO device gpio device gpioled - -# RNG -device random diff --git a/sys/mips/conf/WZR-300HP b/sys/mips/conf/WZR-300HP index 217e444f1b896..dd767888a1e98 100644 --- a/sys/mips/conf/WZR-300HP +++ b/sys/mips/conf/WZR-300HP @@ -49,4 +49,4 @@ device hwpmc # load these via modules, shrink kernel nodevice if_bridge nodevice bridgestp -nodevice random +options RANDOM_LOADABLE diff --git a/sys/mips/conf/WZR-HPAG300H b/sys/mips/conf/WZR-HPAG300H index b46f9de3eb8d6..3337af682f2c4 100644 --- a/sys/mips/conf/WZR-HPAG300H +++ b/sys/mips/conf/WZR-HPAG300H @@ -49,4 +49,4 @@ device hwpmc # load these via modules, shrink kernel nodevice if_bridge nodevice bridgestp -nodevice random +options RANDOM_LOADABLE diff --git a/sys/mips/conf/X1000 b/sys/mips/conf/X1000 index 907ea814de8f5..8f10337218a5c 100644 --- a/sys/mips/conf/X1000 +++ b/sys/mips/conf/X1000 @@ -63,7 +63,6 @@ device miibus device bpf device md device uart -device random device fdt_pinctrl diff --git a/sys/mips/conf/std.AR5312 b/sys/mips/conf/std.AR5312 index a3b055bfb743e..56a45cb4c869e 100644 --- a/sys/mips/conf/std.AR5312 +++ b/sys/mips/conf/std.AR5312 @@ -72,7 +72,6 @@ device loop device ether device md device bpf -device random options ARGE_DEBUG # Enable if_arge debugging for now diff --git a/sys/mips/conf/std.AR5315 b/sys/mips/conf/std.AR5315 index c9f85f6c08135..74a888c32f85c 100644 --- a/sys/mips/conf/std.AR5315 +++ b/sys/mips/conf/std.AR5315 @@ -72,7 +72,6 @@ device loop device ether device md device bpf -device random options ARGE_DEBUG # Enable if_arge debugging for now diff --git a/sys/mips/conf/std.AR_MIPS_BASE b/sys/mips/conf/std.AR_MIPS_BASE index 37544a9b66603..ab0947a391ea9 100644 --- a/sys/mips/conf/std.AR_MIPS_BASE +++ b/sys/mips/conf/std.AR_MIPS_BASE @@ -25,9 +25,6 @@ makeoptions MODULES_OVERRIDE+="gpio ar71xx if_gif if_vlan if_gre if_tuntap" makeoptions MODULES_OVERRIDE+="if_bridge bridgestp usb" makeoptions MODULES_OVERRIDE+="alq" -# Random - required during early boot! -device random - # net80211 options IEEE80211_DEBUG options IEEE80211_SUPPORT_MESH diff --git a/sys/mips/conf/std.BERI b/sys/mips/conf/std.BERI index 903af51875afc..07f907b760df6 100644 --- a/sys/mips/conf/std.BERI +++ b/sys/mips/conf/std.BERI @@ -61,5 +61,4 @@ device ether device geom_map device loop device md -device random device snp diff --git a/sys/mips/conf/std.MALTA b/sys/mips/conf/std.MALTA index 4c1965650fba5..26940db1b92f4 100644 --- a/sys/mips/conf/std.MALTA +++ b/sys/mips/conf/std.MALTA @@ -55,4 +55,3 @@ device miibus device bpf device md device uart -device random diff --git a/sys/mips/conf/std.XLP b/sys/mips/conf/std.XLP index 5330c19b36577..cbc13746fd063 100644 --- a/sys/mips/conf/std.XLP +++ b/sys/mips/conf/std.XLP @@ -66,7 +66,6 @@ makeoptions FDT_DTS_FILE=xlp-basic.dts # Pseudo device loop -device random device md device bpf diff --git a/sys/mips/mediatek/std.mediatek b/sys/mips/mediatek/std.mediatek index 7806da8f099a2..d8c351aab36ff 100644 --- a/sys/mips/mediatek/std.mediatek +++ b/sys/mips/mediatek/std.mediatek @@ -74,9 +74,6 @@ device fdt_pinctrl # UART support device uart -# random support -device random - # loop device support device loop diff --git a/sys/mips/mediatek/std.rt2880 b/sys/mips/mediatek/std.rt2880 index 8040585e9cb94..397a0bc322daf 100644 --- a/sys/mips/mediatek/std.rt2880 +++ b/sys/mips/mediatek/std.rt2880 @@ -73,9 +73,6 @@ device fdt_pinctrl # UART support device uart -# random support -device random - # loop device support device loop diff --git a/sys/modules/Makefile b/sys/modules/Makefile index a9a5c5ed98efd..876a13f19ea92 100644 --- a/sys/modules/Makefile +++ b/sys/modules/Makefile @@ -255,8 +255,6 @@ SUBDIR= \ ${_mwlfw} \ mxge \ my \ - ${_nandfs} \ - ${_nandsim} \ ${_nctgpio} \ ${_ndis} \ ${_netgraph} \ @@ -489,11 +487,6 @@ _mlx5ib= mlx5ib .endif .endif -.if ${MK_NAND} != "no" || defined(ALL_MODULES) -_nandfs= nandfs -_nandsim= nandsim -.endif - .if ${MK_NETGRAPH} != "no" || defined(ALL_MODULES) _netgraph= netgraph .endif diff --git a/sys/modules/nand/Makefile b/sys/modules/nand/Makefile deleted file mode 100644 index c9d9962e897f4..0000000000000 --- a/sys/modules/nand/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# $FreeBSD$ - -.PATH: ${SRCTOP}/sys/dev/nand - -KMOD = nand -SRCS= nand.c nand_bbt.c nand_cdev.c nand_generic.c nand_geom.c \ - nand_id.c nandbus.c nandbus_if.c nand_if.c nfc_if.c \ - nand_if.h device_if.h bus_if.h nfc_if.h nandbus_if.h - -.include <bsd.kmod.mk> diff --git a/sys/modules/nandfs/Makefile b/sys/modules/nandfs/Makefile deleted file mode 100644 index f13858c57c7b2..0000000000000 --- a/sys/modules/nandfs/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# $FreeBSD$ - -.PATH: ${SRCTOP}/sys/fs/nandfs - -KMOD= nandfs -SRCS= vnode_if.h opt_ddb.h \ - bmap.c nandfs_bmap.c nandfs_dir.c nandfs_subr.c nandfs_vfsops.c \ - nandfs_vnops.c nandfs_alloc.c nandfs_cpfile.c nandfs_dat.c \ - nandfs_ifile.c nandfs_segment.c nandfs_sufile.c nandfs_buffer.c \ - nandfs_cleaner.c - -.include <bsd.kmod.mk> diff --git a/sys/modules/nandsim/Makefile b/sys/modules/nandsim/Makefile deleted file mode 100644 index 4f0aeca9eb4b7..0000000000000 --- a/sys/modules/nandsim/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# $FreeBSD$ - -.PATH: ${SRCTOP}/sys/dev/nand - -KMOD= nandsim -SRCS= nandsim.c nandsim_chip.c nandsim_swap.c nandsim_ctrl.c nandsim_log.c\ - bus_if.h device_if.h vnode_if.h nfc_if.h nand_if.h - -.include <bsd.kmod.mk> diff --git a/sys/net/if_vxlan.c b/sys/net/if_vxlan.c index 81065bcec4319..5e35baae2dbc0 100644 --- a/sys/net/if_vxlan.c +++ b/sys/net/if_vxlan.c @@ -1134,7 +1134,7 @@ vxlan_socket_mc_join_group(struct vxlan_socket *vso, * If we really need to, we can of course look in the INP's * membership list: * sotoinpcb(vso->vxlso_sock)->inp_moptions-> - * imo_membership[]->inm_ifp + * imo_head[]->imf_inm->inm_ifp * similarly to imo_match_group(). */ source->in4.sin_addr = local->in4.sin_addr; diff --git a/sys/net/iflib.c b/sys/net/iflib.c index d932e9373be0a..e33c2bec61e26 100644 --- a/sys/net/iflib.c +++ b/sys/net/iflib.c @@ -3580,10 +3580,10 @@ iflib_txq_drain(struct ifmp_ring *r, uint32_t cidx, uint32_t pidx) iflib_txq_t txq = r->cookie; if_ctx_t ctx = txq->ift_ctx; if_t ifp = ctx->ifc_ifp; - struct mbuf **mp, *m; - int i, count, consumed, pkt_sent, bytes_sent, mcast_sent, avail; - int reclaimed, err, in_use_prev, desc_used; - bool do_prefetch, ring, rang; + struct mbuf *m, **mp; + int avail, bytes_sent, consumed, count, err, i, in_use_prev; + int mcast_sent, pkt_sent, reclaimed, txq_avail; + bool do_prefetch, rang, ring; if (__predict_false(!(if_getdrvflags(ifp) & IFF_DRV_RUNNING) || !LINK_ACTIVE(ctx))) { @@ -3621,16 +3621,15 @@ iflib_txq_drain(struct ifmp_ring *r, uint32_t cidx, uint32_t pidx) avail, ctx->ifc_flags, TXQ_AVAIL(txq)); #endif do_prefetch = (ctx->ifc_flags & IFC_PREFETCH); - avail = TXQ_AVAIL(txq); + txq_avail = TXQ_AVAIL(txq); err = 0; - for (desc_used = i = 0; i < count && avail > MAX_TX_DESC(ctx) + 2; i++) { + for (i = 0; i < count && txq_avail > MAX_TX_DESC(ctx) + 2; i++) { int rem = do_prefetch ? count - i : 0; mp = _ring_peek_one(r, cidx, i, rem); MPASS(mp != NULL && *mp != NULL); if (__predict_false(*mp == (struct mbuf *)txq)) { consumed++; - reclaimed++; continue; } in_use_prev = txq->ift_in_use; @@ -3649,10 +3648,9 @@ iflib_txq_drain(struct ifmp_ring *r, uint32_t cidx, uint32_t pidx) DBG_COUNTER_INC(tx_sent); bytes_sent += m->m_pkthdr.len; mcast_sent += !!(m->m_flags & M_MCAST); - avail = TXQ_AVAIL(txq); + txq_avail = TXQ_AVAIL(txq); txq->ift_db_pending += (txq->ift_in_use - in_use_prev); - desc_used += (txq->ift_in_use - in_use_prev); ETHER_BPF_MTAP(ifp, m); if (__predict_false(!(ifp->if_drv_flags & IFF_DRV_RUNNING))) break; @@ -6155,9 +6153,6 @@ iflib_tx_credits_update(if_ctx_t ctx, iflib_txq_t txq) int credits_pre = txq->ift_cidx_processed; #endif - if (ctx->isc_txd_credits_update == NULL) - return (0); - bus_dmamap_sync(txq->ift_ifdi->idi_tag, txq->ift_ifdi->idi_map, BUS_DMASYNC_POSTREAD); if ((credits = ctx->isc_txd_credits_update(ctx->ifc_softc, txq->ift_id, true)) == 0) diff --git a/sys/net/vnet.h b/sys/net/vnet.h index b4168750e0263..a8c9887ed506b 100644 --- a/sys/net/vnet.h +++ b/sys/net/vnet.h @@ -273,7 +273,8 @@ extern struct sx vnet_sxlock; /* struct _hack is to stop this from being used with static data */ #define VNET_DEFINE(t, n) \ struct _hack; t VNET_NAME(n) __section(VNET_SETNAME) __used -#if defined(KLD_MODULE) && (defined(__aarch64__) || defined(__riscv)) +#if defined(KLD_MODULE) && (defined(__aarch64__) || defined(__riscv) \ + || defined(__powerpc64__)) /* * As with DPCPU_DEFINE_STATIC we are unable to mark this data as static * in modules on some architectures. diff --git a/sys/netinet/in.h b/sys/netinet/in.h index 148d51eff36ae..cfa168f99be68 100644 --- a/sys/netinet/in.h +++ b/sys/netinet/in.h @@ -505,13 +505,9 @@ __END_DECLS #define IP_DEFAULT_MULTICAST_LOOP 1 /* normally hear sends if a member */ /* - * The imo_membership vector for each socket is now dynamically allocated at - * run-time, bounded by USHRT_MAX, and is reallocated when needed, sized - * according to a power-of-two increment. + * Limit for IPv4 multicast memberships */ -#define IP_MIN_MEMBERSHIPS 31 #define IP_MAX_MEMBERSHIPS 4095 -#define IP_MAX_SOURCE_FILTER 1024 /* XXX to be unused */ /* * Default resource limits for IPv4 multicast source filtering. diff --git a/sys/netinet/in_mcast.c b/sys/netinet/in_mcast.c index 2980c1a463caa..ac5c6a03ab549 100644 --- a/sys/netinet/in_mcast.c +++ b/sys/netinet/in_mcast.c @@ -94,7 +94,9 @@ static MALLOC_DEFINE(M_IPMSOURCE, "ip_msource", /* * Locking: - * - Lock order is: Giant, INP_WLOCK, IN_MULTI_LIST_LOCK, IGMP_LOCK, IF_ADDR_LOCK. + * + * - Lock order is: Giant, IN_MULTI_LOCK, INP_WLOCK, + * IN_MULTI_LIST_LOCK, IGMP_LOCK, IF_ADDR_LOCK. * - The IF_ADDR_LOCK is implicitly taken by inm_lookup() earlier, however * it can be taken by code in net/if.c also. * - ip_moptions and in_mfilter are covered by the INP_WLOCK. @@ -144,12 +146,11 @@ static int imf_prune(struct in_mfilter *, const struct sockaddr_in *); static void imf_purge(struct in_mfilter *); static void imf_rollback(struct in_mfilter *); static void imf_reap(struct in_mfilter *); -static int imo_grow(struct ip_moptions *); -static size_t imo_match_group(const struct ip_moptions *, +static struct in_mfilter * + imo_match_group(const struct ip_moptions *, const struct ifnet *, const struct sockaddr *); static struct in_msource * - imo_match_source(const struct ip_moptions *, const size_t, - const struct sockaddr *); + imo_match_source(struct in_mfilter *, const struct sockaddr *); static void ims_merge(struct ip_msource *ims, const struct in_msource *lims, const int rollback); static int in_getmulti(struct ifnet *, const struct in_addr *, @@ -333,6 +334,26 @@ imf_init(struct in_mfilter *imf, const int st0, const int st1) imf->imf_st[1] = st1; } +struct in_mfilter * +ip_mfilter_alloc(const int mflags, const int st0, const int st1) +{ + struct in_mfilter *imf; + + imf = malloc(sizeof(*imf), M_INMFILTER, mflags); + if (imf != NULL) + imf_init(imf, st0, st1); + + return (imf); +} + +void +ip_mfilter_free(struct in_mfilter *imf) +{ + + imf_purge(imf); + free(imf, M_INMFILTER); +} + /* * Function for looking up an in_multi record for an IPv4 multicast address * on a given interface. ifp must be valid. If no record found, return NULL. @@ -379,89 +400,30 @@ inm_lookup(struct ifnet *ifp, const struct in_addr ina) } /* - * Resize the ip_moptions vector to the next power-of-two minus 1. - * May be called with locks held; do not sleep. - */ -static int -imo_grow(struct ip_moptions *imo) -{ - struct in_multi **nmships; - struct in_multi **omships; - struct in_mfilter *nmfilters; - struct in_mfilter *omfilters; - size_t idx; - size_t newmax; - size_t oldmax; - - nmships = NULL; - nmfilters = NULL; - omships = imo->imo_membership; - omfilters = imo->imo_mfilters; - oldmax = imo->imo_max_memberships; - newmax = ((oldmax + 1) * 2) - 1; - - if (newmax <= IP_MAX_MEMBERSHIPS) { - nmships = (struct in_multi **)realloc(omships, - sizeof(struct in_multi *) * newmax, M_IPMOPTS, M_NOWAIT); - nmfilters = (struct in_mfilter *)realloc(omfilters, - sizeof(struct in_mfilter) * newmax, M_INMFILTER, M_NOWAIT); - if (nmships != NULL && nmfilters != NULL) { - /* Initialize newly allocated source filter heads. */ - for (idx = oldmax; idx < newmax; idx++) { - imf_init(&nmfilters[idx], MCAST_UNDEFINED, - MCAST_EXCLUDE); - } - imo->imo_max_memberships = newmax; - imo->imo_membership = nmships; - imo->imo_mfilters = nmfilters; - } - } - - if (nmships == NULL || nmfilters == NULL) { - if (nmships != NULL) - free(nmships, M_IPMOPTS); - if (nmfilters != NULL) - free(nmfilters, M_INMFILTER); - return (ETOOMANYREFS); - } - - return (0); -} - -/* * Find an IPv4 multicast group entry for this ip_moptions instance * which matches the specified group, and optionally an interface. * Return its index into the array, or -1 if not found. */ -static size_t +static struct in_mfilter * imo_match_group(const struct ip_moptions *imo, const struct ifnet *ifp, const struct sockaddr *group) { const struct sockaddr_in *gsin; - struct in_multi **pinm; - int idx; - int nmships; + struct in_mfilter *imf; + struct in_multi *inm; gsin = (const struct sockaddr_in *)group; - /* The imo_membership array may be lazy allocated. */ - if (imo->imo_membership == NULL || imo->imo_num_memberships == 0) - return (-1); - - nmships = imo->imo_num_memberships; - pinm = &imo->imo_membership[0]; - for (idx = 0; idx < nmships; idx++, pinm++) { - if (*pinm == NULL) + IP_MFILTER_FOREACH(imf, &imo->imo_head) { + inm = imf->imf_inm; + if (inm == NULL) continue; - if ((ifp == NULL || ((*pinm)->inm_ifp == ifp)) && - in_hosteq((*pinm)->inm_addr, gsin->sin_addr)) { + if ((ifp == NULL || (inm->inm_ifp == ifp)) && + in_hosteq(inm->inm_addr, gsin->sin_addr)) { break; } } - if (idx >= nmships) - idx = -1; - - return (idx); + return (imf); } /* @@ -472,22 +434,13 @@ imo_match_group(const struct ip_moptions *imo, const struct ifnet *ifp, * it exists, which may not be the desired behaviour. */ static struct in_msource * -imo_match_source(const struct ip_moptions *imo, const size_t gidx, - const struct sockaddr *src) +imo_match_source(struct in_mfilter *imf, const struct sockaddr *src) { struct ip_msource find; - struct in_mfilter *imf; struct ip_msource *ims; const sockunion_t *psa; KASSERT(src->sa_family == AF_INET, ("%s: !AF_INET", __func__)); - KASSERT(gidx != -1 && gidx < imo->imo_num_memberships, - ("%s: invalid index %d\n", __func__, (int)gidx)); - - /* The imo_mfilters array may be lazy allocated. */ - if (imo->imo_mfilters == NULL) - return (NULL); - imf = &imo->imo_mfilters[gidx]; /* Source trees are keyed in host byte order. */ psa = (const sockunion_t *)src; @@ -507,14 +460,14 @@ int imo_multi_filter(const struct ip_moptions *imo, const struct ifnet *ifp, const struct sockaddr *group, const struct sockaddr *src) { - size_t gidx; + struct in_mfilter *imf; struct in_msource *ims; int mode; KASSERT(ifp != NULL, ("%s: null ifp", __func__)); - gidx = imo_match_group(imo, ifp, group); - if (gidx == -1) + imf = imo_match_group(imo, ifp, group); + if (imf == NULL) return (MCAST_NOTGMEMBER); /* @@ -526,8 +479,8 @@ imo_multi_filter(const struct ip_moptions *imo, const struct ifnet *ifp, * NOTE: We are comparing group state here at IGMP t1 (now) * with socket-layer t0 (since last downcall). */ - mode = imo->imo_mfilters[gidx].imf_st[1]; - ims = imo_match_source(imo, gidx, src); + mode = imf->imf_st[1]; + ims = imo_match_source(imf, src); if ((ims == NULL && mode == MCAST_INCLUDE) || (ims != NULL && ims->imsl_st[0] != mode)) @@ -1452,7 +1405,6 @@ inp_block_unblock_source(struct inpcb *inp, struct sockopt *sopt) struct ip_moptions *imo; struct in_msource *ims; struct in_multi *inm; - size_t idx; uint16_t fmode; int error, doblock; @@ -1531,20 +1483,18 @@ inp_block_unblock_source(struct inpcb *inp, struct sockopt *sopt) if (!IN_MULTICAST(ntohl(gsa->sin.sin_addr.s_addr))) return (EINVAL); + IN_MULTI_LOCK(); + /* * Check if we are actually a member of this group. */ imo = inp_findmoptions(inp); - idx = imo_match_group(imo, ifp, &gsa->sa); - if (idx == -1 || imo->imo_mfilters == NULL) { + imf = imo_match_group(imo, ifp, &gsa->sa); + if (imf == NULL) { error = EADDRNOTAVAIL; goto out_inp_locked; } - - KASSERT(imo->imo_mfilters != NULL, - ("%s: imo_mfilters not allocated", __func__)); - imf = &imo->imo_mfilters[idx]; - inm = imo->imo_membership[idx]; + inm = imf->imf_inm; /* * Attempting to use the delta-based API on an @@ -1562,7 +1512,7 @@ inp_block_unblock_source(struct inpcb *inp, struct sockopt *sopt) * Asked to unblock, but nothing to unblock. * If adding a new block entry, allocate it. */ - ims = imo_match_source(imo, idx, &ssa->sa); + ims = imo_match_source(imf, &ssa->sa); if ((ims != NULL && doblock) || (ims == NULL && !doblock)) { CTR3(KTR_IGMPV3, "%s: source 0x%08x %spresent", __func__, ntohl(ssa->sin.sin_addr.s_addr), doblock ? "" : "not "); @@ -1593,14 +1543,13 @@ inp_block_unblock_source(struct inpcb *inp, struct sockopt *sopt) /* * Begin state merge transaction at IGMP layer. */ - IN_MULTI_LOCK(); CTR1(KTR_IGMPV3, "%s: merge inm state", __func__); IN_MULTI_LIST_LOCK(); error = inm_merge(inm, imf); if (error) { CTR1(KTR_IGMPV3, "%s: failed to merge inm state", __func__); IN_MULTI_LIST_UNLOCK(); - goto out_in_multi_locked; + goto out_imf_rollback; } CTR1(KTR_IGMPV3, "%s: doing igmp downcall", __func__); @@ -1609,9 +1558,6 @@ inp_block_unblock_source(struct inpcb *inp, struct sockopt *sopt) if (error) CTR1(KTR_IGMPV3, "%s: failed igmp downcall", __func__); -out_in_multi_locked: - - IN_MULTI_UNLOCK(); out_imf_rollback: if (error) imf_rollback(imf); @@ -1622,6 +1568,7 @@ out_imf_rollback: out_inp_locked: INP_WUNLOCK(inp); + IN_MULTI_UNLOCK(); return (error); } @@ -1636,9 +1583,6 @@ static struct ip_moptions * inp_findmoptions(struct inpcb *inp) { struct ip_moptions *imo; - struct in_multi **immp; - struct in_mfilter *imfp; - size_t idx; INP_WLOCK(inp); if (inp->inp_moptions != NULL) @@ -1647,29 +1591,16 @@ inp_findmoptions(struct inpcb *inp) INP_WUNLOCK(inp); imo = malloc(sizeof(*imo), M_IPMOPTS, M_WAITOK); - immp = malloc(sizeof(*immp) * IP_MIN_MEMBERSHIPS, M_IPMOPTS, - M_WAITOK | M_ZERO); - imfp = malloc(sizeof(struct in_mfilter) * IP_MIN_MEMBERSHIPS, - M_INMFILTER, M_WAITOK); imo->imo_multicast_ifp = NULL; imo->imo_multicast_addr.s_addr = INADDR_ANY; imo->imo_multicast_vif = -1; imo->imo_multicast_ttl = IP_DEFAULT_MULTICAST_TTL; imo->imo_multicast_loop = in_mcast_loop; - imo->imo_num_memberships = 0; - imo->imo_max_memberships = IP_MIN_MEMBERSHIPS; - imo->imo_membership = immp; - - /* Initialize per-group source filters. */ - for (idx = 0; idx < IP_MIN_MEMBERSHIPS; idx++) - imf_init(&imfp[idx], MCAST_UNDEFINED, MCAST_EXCLUDE); - imo->imo_mfilters = imfp; + STAILQ_INIT(&imo->imo_head); INP_WLOCK(inp); if (inp->inp_moptions != NULL) { - free(imfp, M_INMFILTER); - free(immp, M_IPMOPTS); free(imo, M_IPMOPTS); return (inp->inp_moptions); } @@ -1680,32 +1611,25 @@ inp_findmoptions(struct inpcb *inp) static void inp_gcmoptions(struct ip_moptions *imo) { - struct in_mfilter *imf; + struct in_mfilter *imf; struct in_multi *inm; struct ifnet *ifp; - size_t idx, nmships; - nmships = imo->imo_num_memberships; - for (idx = 0; idx < nmships; ++idx) { - imf = imo->imo_mfilters ? &imo->imo_mfilters[idx] : NULL; - if (imf) - imf_leave(imf); - inm = imo->imo_membership[idx]; - ifp = inm->inm_ifp; - if (ifp != NULL) { - CURVNET_SET(ifp->if_vnet); - (void)in_leavegroup(inm, imf); - CURVNET_RESTORE(); - } else { - (void)in_leavegroup(inm, imf); + while ((imf = ip_mfilter_first(&imo->imo_head)) != NULL) { + ip_mfilter_remove(&imo->imo_head, imf); + + imf_leave(imf); + if ((inm = imf->imf_inm) != NULL) { + if ((ifp = inm->inm_ifp) != NULL) { + CURVNET_SET(ifp->if_vnet); + (void)in_leavegroup(inm, imf); + CURVNET_RESTORE(); + } else { + (void)in_leavegroup(inm, imf); + } } - if (imf) - imf_purge(imf); + ip_mfilter_free(imf); } - - if (imo->imo_mfilters) - free(imo->imo_mfilters, M_INMFILTER); - free(imo->imo_membership, M_IPMOPTS); free(imo, M_IPMOPTS); } @@ -1741,7 +1665,7 @@ inp_get_source_filters(struct inpcb *inp, struct sockopt *sopt) struct sockaddr_storage *ptss; struct sockaddr_storage *tss; int error; - size_t idx, nsrcs, ncsrcs; + size_t nsrcs, ncsrcs; INP_WLOCK_ASSERT(inp); @@ -1768,12 +1692,11 @@ inp_get_source_filters(struct inpcb *inp, struct sockopt *sopt) * Lookup group on the socket. */ gsa = (sockunion_t *)&msfr.msfr_group; - idx = imo_match_group(imo, ifp, &gsa->sa); - if (idx == -1 || imo->imo_mfilters == NULL) { + imf = imo_match_group(imo, ifp, &gsa->sa); + if (imf == NULL) { INP_WUNLOCK(inp); return (EADDRNOTAVAIL); } - imf = &imo->imo_mfilters[idx]; /* * Ignore memberships which are in limbo. @@ -2033,14 +1956,11 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt) struct ip_moptions *imo; struct in_multi *inm; struct in_msource *lims; - size_t idx; int error, is_new; ifp = NULL; - imf = NULL; lims = NULL; error = 0; - is_new = 0; memset(&gsr, 0, sizeof(struct group_source_req)); gsa = (sockunion_t *)&gsr.gsr_group; @@ -2148,13 +2068,25 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt) if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) return (EADDRNOTAVAIL); + IN_MULTI_LOCK(); + + /* + * Find the membership in the membership list. + */ imo = inp_findmoptions(inp); - idx = imo_match_group(imo, ifp, &gsa->sa); - if (idx == -1) { + imf = imo_match_group(imo, ifp, &gsa->sa); + if (imf == NULL) { is_new = 1; + inm = NULL; + + if (ip_mfilter_count(&imo->imo_head) >= IP_MAX_MEMBERSHIPS) { + error = ENOMEM; + goto out_inp_locked; + } } else { - inm = imo->imo_membership[idx]; - imf = &imo->imo_mfilters[idx]; + is_new = 0; + inm = imf->imf_inm; + if (ssa->ss.ss_family != AF_UNSPEC) { /* * MCAST_JOIN_SOURCE_GROUP on an exclusive membership @@ -2181,7 +2113,7 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt) * full-state SSM API with the delta-based API, * which is discouraged in the relevant RFCs. */ - lims = imo_match_source(imo, idx, &ssa->sa); + lims = imo_match_source(imf, &ssa->sa); if (lims != NULL /*&& lims->imsl_st[1] == MCAST_INCLUDE*/) { error = EADDRNOTAVAIL; @@ -2214,27 +2146,6 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt) */ INP_WLOCK_ASSERT(inp); - if (is_new) { - if (imo->imo_num_memberships == imo->imo_max_memberships) { - error = imo_grow(imo); - if (error) - goto out_inp_locked; - } - /* - * Allocate the new slot upfront so we can deal with - * grafting the new source filter in same code path - * as for join-source on existing membership. - */ - idx = imo->imo_num_memberships; - imo->imo_membership[idx] = NULL; - imo->imo_num_memberships++; - KASSERT(imo->imo_mfilters != NULL, - ("%s: imf_mfilters vector was not allocated", __func__)); - imf = &imo->imo_mfilters[idx]; - KASSERT(RB_EMPTY(&imf->imf_sources), - ("%s: imf_sources not empty", __func__)); - } - /* * Graft new source into filter list for this inpcb's * membership of the group. The in_multi may not have @@ -2250,7 +2161,11 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt) /* Membership starts in IN mode */ if (is_new) { CTR1(KTR_IGMPV3, "%s: new join w/source", __func__); - imf_init(imf, MCAST_UNDEFINED, MCAST_INCLUDE); + imf = ip_mfilter_alloc(M_NOWAIT, MCAST_UNDEFINED, MCAST_INCLUDE); + if (imf == NULL) { + error = ENOMEM; + goto out_inp_locked; + } } else { CTR2(KTR_IGMPV3, "%s: %s source", __func__, "allow"); } @@ -2259,34 +2174,41 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt) CTR1(KTR_IGMPV3, "%s: merge imf state failed", __func__); error = ENOMEM; - goto out_imo_free; + goto out_inp_locked; } } else { /* No address specified; Membership starts in EX mode */ if (is_new) { CTR1(KTR_IGMPV3, "%s: new join w/o source", __func__); - imf_init(imf, MCAST_UNDEFINED, MCAST_EXCLUDE); + imf = ip_mfilter_alloc(M_NOWAIT, MCAST_UNDEFINED, MCAST_EXCLUDE); + if (imf == NULL) { + error = ENOMEM; + goto out_inp_locked; + } } } /* * Begin state merge transaction at IGMP layer. */ - in_pcbref(inp); - INP_WUNLOCK(inp); - IN_MULTI_LOCK(); - if (is_new) { + in_pcbref(inp); + INP_WUNLOCK(inp); + error = in_joingroup_locked(ifp, &gsa->sin.sin_addr, imf, - &inm); + &imf->imf_inm); + + INP_WLOCK(inp); + if (in_pcbrele_wlocked(inp)) { + error = ENXIO; + goto out_inp_unlocked; + } if (error) { CTR1(KTR_IGMPV3, "%s: in_joingroup_locked failed", __func__); - IN_MULTI_LIST_UNLOCK(); - goto out_imo_free; + goto out_inp_locked; } - inm_acquire(inm); - imo->imo_membership[idx] = inm; + inm_acquire(imf->imf_inm); } else { CTR1(KTR_IGMPV3, "%s: merge inm state", __func__); IN_MULTI_LIST_LOCK(); @@ -2295,7 +2217,9 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt) CTR1(KTR_IGMPV3, "%s: failed to merge inm state", __func__); IN_MULTI_LIST_UNLOCK(); - goto out_in_multi_locked; + imf_rollback(imf); + imf_reap(imf); + goto out_inp_locked; } CTR1(KTR_IGMPV3, "%s: doing igmp downcall", __func__); error = igmp_change_state(inm); @@ -2303,40 +2227,30 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt) if (error) { CTR1(KTR_IGMPV3, "%s: failed igmp downcall", __func__); - goto out_in_multi_locked; + imf_rollback(imf); + imf_reap(imf); + goto out_inp_locked; } } + if (is_new) + ip_mfilter_insert(&imo->imo_head, imf); -out_in_multi_locked: + imf_commit(imf); + imf = NULL; +out_inp_locked: + INP_WUNLOCK(inp); +out_inp_unlocked: IN_MULTI_UNLOCK(); - INP_WLOCK(inp); - if (in_pcbrele_wlocked(inp)) - return (ENXIO); - if (error) { - imf_rollback(imf); - if (is_new) - imf_purge(imf); - else - imf_reap(imf); - } else { - imf_commit(imf); - } -out_imo_free: - if (error && is_new) { - inm = imo->imo_membership[idx]; - if (inm != NULL) { + if (is_new && imf) { + if (imf->imf_inm != NULL) { IN_MULTI_LIST_LOCK(); - inm_release_deferred(inm); + inm_release_deferred(imf->imf_inm); IN_MULTI_LIST_UNLOCK(); } - imo->imo_membership[idx] = NULL; - --imo->imo_num_memberships; + ip_mfilter_free(imf); } - -out_inp_locked: - INP_WUNLOCK(inp); return (error); } @@ -2355,12 +2269,12 @@ inp_leave_group(struct inpcb *inp, struct sockopt *sopt) struct ip_moptions *imo; struct in_msource *ims; struct in_multi *inm; - size_t idx; - int error, is_final; + int error; + bool is_final; ifp = NULL; error = 0; - is_final = 1; + is_final = true; memset(&gsr, 0, sizeof(struct group_source_req)); gsa = (sockunion_t *)&gsr.gsr_group; @@ -2460,20 +2374,21 @@ inp_leave_group(struct inpcb *inp, struct sockopt *sopt) if (!IN_MULTICAST(ntohl(gsa->sin.sin_addr.s_addr))) return (EINVAL); + IN_MULTI_LOCK(); + /* - * Find the membership in the membership array. + * Find the membership in the membership list. */ imo = inp_findmoptions(inp); - idx = imo_match_group(imo, ifp, &gsa->sa); - if (idx == -1) { + imf = imo_match_group(imo, ifp, &gsa->sa); + if (imf == NULL) { error = EADDRNOTAVAIL; goto out_inp_locked; } - inm = imo->imo_membership[idx]; - imf = &imo->imo_mfilters[idx]; + inm = imf->imf_inm; if (ssa->ss.ss_family != AF_UNSPEC) - is_final = 0; + is_final = false; /* * Begin state merge transaction at socket layer. @@ -2485,13 +2400,14 @@ inp_leave_group(struct inpcb *inp, struct sockopt *sopt) * MCAST_LEAVE_SOURCE_GROUP is only valid for inclusive memberships. */ if (is_final) { + ip_mfilter_remove(&imo->imo_head, imf); imf_leave(imf); } else { if (imf->imf_st[0] == MCAST_EXCLUDE) { error = EADDRNOTAVAIL; goto out_inp_locked; } - ims = imo_match_source(imo, idx, &ssa->sa); + ims = imo_match_source(imf, &ssa->sa); if (ims == NULL) { CTR3(KTR_IGMPV3, "%s: source 0x%08x %spresent", __func__, ntohl(ssa->sin.sin_addr.s_addr), "not "); @@ -2510,17 +2426,7 @@ inp_leave_group(struct inpcb *inp, struct sockopt *sopt) /* * Begin state merge transaction at IGMP layer. */ - in_pcbref(inp); - INP_WUNLOCK(inp); - IN_MULTI_LOCK(); - - if (is_final) { - /* - * Give up the multicast address record to which - * the membership points. - */ - (void)in_leavegroup_locked(inm, imf); - } else { + if (!is_final) { CTR1(KTR_IGMPV3, "%s: merge inm state", __func__); IN_MULTI_LIST_LOCK(); error = inm_merge(inm, imf); @@ -2528,7 +2434,9 @@ inp_leave_group(struct inpcb *inp, struct sockopt *sopt) CTR1(KTR_IGMPV3, "%s: failed to merge inm state", __func__); IN_MULTI_LIST_UNLOCK(); - goto out_in_multi_locked; + imf_rollback(imf); + imf_reap(imf); + goto out_inp_locked; } CTR1(KTR_IGMPV3, "%s: doing igmp downcall", __func__); @@ -2537,38 +2445,27 @@ inp_leave_group(struct inpcb *inp, struct sockopt *sopt) if (error) { CTR1(KTR_IGMPV3, "%s: failed igmp downcall", __func__); + imf_rollback(imf); + imf_reap(imf); + goto out_inp_locked; } } - -out_in_multi_locked: - - IN_MULTI_UNLOCK(); - INP_WLOCK(inp); - if (in_pcbrele_wlocked(inp)) - return (ENXIO); - - if (error) - imf_rollback(imf); - else - imf_commit(imf); - + imf_commit(imf); imf_reap(imf); - if (is_final) { - /* Remove the gap in the membership and filter array. */ - KASSERT(RB_EMPTY(&imf->imf_sources), - ("%s: imf_sources not empty", __func__)); - for (++idx; idx < imo->imo_num_memberships; ++idx) { - imo->imo_membership[idx - 1] = imo->imo_membership[idx]; - imo->imo_mfilters[idx - 1] = imo->imo_mfilters[idx]; - } - imf_init(&imo->imo_mfilters[idx - 1], MCAST_UNDEFINED, - MCAST_EXCLUDE); - imo->imo_num_memberships--; - } - out_inp_locked: INP_WUNLOCK(inp); + + if (is_final && imf) { + /* + * Give up the multicast address record to which + * the membership points. + */ + (void) in_leavegroup_locked(imf->imf_inm, imf); + ip_mfilter_free(imf); + } + + IN_MULTI_UNLOCK(); return (error); } @@ -2658,7 +2555,6 @@ inp_set_source_filters(struct inpcb *inp, struct sockopt *sopt) struct in_mfilter *imf; struct ip_moptions *imo; struct in_multi *inm; - size_t idx; int error; error = sooptcopyin(sopt, &msfr, sizeof(struct __msfilterreq), @@ -2690,18 +2586,19 @@ inp_set_source_filters(struct inpcb *inp, struct sockopt *sopt) if (ifp == NULL) return (EADDRNOTAVAIL); + IN_MULTI_LOCK(); + /* * Take the INP write lock. * Check if this socket is a member of this group. */ imo = inp_findmoptions(inp); - idx = imo_match_group(imo, ifp, &gsa->sa); - if (idx == -1 || imo->imo_mfilters == NULL) { + imf = imo_match_group(imo, ifp, &gsa->sa); + if (imf == NULL) { error = EADDRNOTAVAIL; goto out_inp_locked; } - inm = imo->imo_membership[idx]; - imf = &imo->imo_mfilters[idx]; + inm = imf->imf_inm; /* * Begin state merge transaction at socket layer. @@ -2778,7 +2675,6 @@ inp_set_source_filters(struct inpcb *inp, struct sockopt *sopt) goto out_imf_rollback; INP_WLOCK_ASSERT(inp); - IN_MULTI_LOCK(); /* * Begin state merge transaction at IGMP layer. @@ -2789,7 +2685,7 @@ inp_set_source_filters(struct inpcb *inp, struct sockopt *sopt) if (error) { CTR1(KTR_IGMPV3, "%s: failed to merge inm state", __func__); IN_MULTI_LIST_UNLOCK(); - goto out_in_multi_locked; + goto out_imf_rollback; } CTR1(KTR_IGMPV3, "%s: doing igmp downcall", __func__); @@ -2798,10 +2694,6 @@ inp_set_source_filters(struct inpcb *inp, struct sockopt *sopt) if (error) CTR1(KTR_IGMPV3, "%s: failed igmp downcall", __func__); -out_in_multi_locked: - - IN_MULTI_UNLOCK(); - out_imf_rollback: if (error) imf_rollback(imf); @@ -2812,6 +2704,7 @@ out_imf_rollback: out_inp_locked: INP_WUNLOCK(inp); + IN_MULTI_UNLOCK(); return (error); } diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c index 17fa348955958..b68475afa6557 100644 --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -86,6 +86,9 @@ __FBSDID("$FreeBSD$"); #if defined(INET) || defined(INET6) #include <netinet/in.h> #include <netinet/in_pcb.h> +#ifdef INET +#include <netinet/in_var.h> +#endif #include <netinet/ip_var.h> #include <netinet/tcp_var.h> #ifdef TCPHPTS @@ -93,16 +96,13 @@ __FBSDID("$FreeBSD$"); #endif #include <netinet/udp.h> #include <netinet/udp_var.h> -#endif -#ifdef INET -#include <netinet/in_var.h> -#endif #ifdef INET6 #include <netinet/ip6.h> #include <netinet6/in6_pcb.h> #include <netinet6/in6_var.h> #include <netinet6/ip6_var.h> #endif /* INET6 */ +#endif #include <netipsec/ipsec_support.h> @@ -1779,8 +1779,9 @@ void in_pcbpurgeif0(struct inpcbinfo *pcbinfo, struct ifnet *ifp) { struct inpcb *inp; + struct in_multi *inm; + struct in_mfilter *imf; struct ip_moptions *imo; - int i, gap; INP_INFO_WLOCK(pcbinfo); CK_LIST_FOREACH(inp, pcbinfo->ipi_listhead, inp_list) { @@ -1801,17 +1802,18 @@ in_pcbpurgeif0(struct inpcbinfo *pcbinfo, struct ifnet *ifp) * * XXX This can all be deferred to an epoch_call */ - for (i = 0, gap = 0; i < imo->imo_num_memberships; - i++) { - if (imo->imo_membership[i]->inm_ifp == ifp) { - IN_MULTI_LOCK_ASSERT(); - in_leavegroup_locked(imo->imo_membership[i], NULL); - gap++; - } else if (gap != 0) - imo->imo_membership[i - gap] = - imo->imo_membership[i]; +restart: + IP_MFILTER_FOREACH(imf, &imo->imo_head) { + if ((inm = imf->imf_inm) == NULL) + continue; + if (inm->inm_ifp != ifp) + continue; + ip_mfilter_remove(&imo->imo_head, imf); + IN_MULTI_LOCK_ASSERT(); + in_leavegroup_locked(inm, NULL); + ip_mfilter_free(imf); + goto restart; } - imo->imo_num_memberships -= gap; } INP_WUNLOCK(inp); } diff --git a/sys/netinet/in_var.h b/sys/netinet/in_var.h index 5b7a464bd3e82..50112481f2364 100644 --- a/sys/netinet/in_var.h +++ b/sys/netinet/in_var.h @@ -232,9 +232,61 @@ struct in_mfilter { struct ip_msource_tree imf_sources; /* source list for (S,G) */ u_long imf_nsrc; /* # of source entries */ uint8_t imf_st[2]; /* state before/at commit */ + struct in_multi *imf_inm; /* associated multicast address */ + STAILQ_ENTRY(in_mfilter) imf_entry; /* list entry */ }; /* + * Helper types and functions for IPv4 multicast filters. + */ +STAILQ_HEAD(ip_mfilter_head, in_mfilter); + +struct in_mfilter *ip_mfilter_alloc(int mflags, int st0, int st1); +void ip_mfilter_free(struct in_mfilter *); + +static inline void +ip_mfilter_init(struct ip_mfilter_head *head) +{ + + STAILQ_INIT(head); +} + +static inline struct in_mfilter * +ip_mfilter_first(const struct ip_mfilter_head *head) +{ + + return (STAILQ_FIRST(head)); +} + +static inline void +ip_mfilter_insert(struct ip_mfilter_head *head, struct in_mfilter *imf) +{ + + STAILQ_INSERT_TAIL(head, imf, imf_entry); +} + +static inline void +ip_mfilter_remove(struct ip_mfilter_head *head, struct in_mfilter *imf) +{ + + STAILQ_REMOVE(head, imf, in_mfilter, imf_entry); +} + +#define IP_MFILTER_FOREACH(imf, head) \ + STAILQ_FOREACH(imf, head, imf_entry) + +static inline size_t +ip_mfilter_count(struct ip_mfilter_head *head) +{ + struct in_mfilter *imf; + size_t num = 0; + + STAILQ_FOREACH(imf, head, imf_entry) + num++; + return (num); +} + +/* * IPv4 group descriptor. * * For every entry on an ifnet's if_multiaddrs list which represents diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c index 9c24fb9fdd67b..819a0f9c75e6b 100644 --- a/sys/netinet/ip_carp.c +++ b/sys/netinet/ip_carp.c @@ -1371,25 +1371,24 @@ carp_multicast_setup(struct carp_if *cif, sa_family_t sa) case AF_INET: { struct ip_moptions *imo = &cif->cif_imo; + struct in_mfilter *imf; struct in_addr addr; - if (imo->imo_membership) + if (ip_mfilter_first(&imo->imo_head) != NULL) return (0); - imo->imo_membership = (struct in_multi **)malloc( - (sizeof(struct in_multi *) * IP_MIN_MEMBERSHIPS), M_CARP, - M_WAITOK); - imo->imo_mfilters = NULL; - imo->imo_max_memberships = IP_MIN_MEMBERSHIPS; + imf = ip_mfilter_alloc(M_WAITOK, 0, 0); + ip_mfilter_init(&imo->imo_head); imo->imo_multicast_vif = -1; addr.s_addr = htonl(INADDR_CARP_GROUP); if ((error = in_joingroup(ifp, &addr, NULL, - &imo->imo_membership[0])) != 0) { - free(imo->imo_membership, M_CARP); + &imf->imf_inm)) != 0) { + ip_mfilter_free(imf); break; } - imo->imo_num_memberships++; + + ip_mfilter_insert(&imo->imo_head, imf); imo->imo_multicast_ifp = ifp; imo->imo_multicast_ttl = CARP_DFLTTL; imo->imo_multicast_loop = 0; @@ -1400,17 +1399,16 @@ carp_multicast_setup(struct carp_if *cif, sa_family_t sa) case AF_INET6: { struct ip6_moptions *im6o = &cif->cif_im6o; + struct in6_mfilter *im6f[2]; struct in6_addr in6; - struct in6_multi *in6m; - if (im6o->im6o_membership) + if (ip6_mfilter_first(&im6o->im6o_head)) return (0); - im6o->im6o_membership = (struct in6_multi **)malloc( - (sizeof(struct in6_multi *) * IPV6_MIN_MEMBERSHIPS), M_CARP, - M_ZERO | M_WAITOK); - im6o->im6o_mfilters = NULL; - im6o->im6o_max_memberships = IPV6_MIN_MEMBERSHIPS; + im6f[0] = ip6_mfilter_alloc(M_WAITOK, 0, 0); + im6f[1] = ip6_mfilter_alloc(M_WAITOK, 0, 0); + + ip6_mfilter_init(&im6o->im6o_head); im6o->im6o_multicast_hlim = CARP_DFLTTL; im6o->im6o_multicast_ifp = ifp; @@ -1419,17 +1417,15 @@ carp_multicast_setup(struct carp_if *cif, sa_family_t sa) in6.s6_addr16[0] = htons(0xff02); in6.s6_addr8[15] = 0x12; if ((error = in6_setscope(&in6, ifp, NULL)) != 0) { - free(im6o->im6o_membership, M_CARP); + ip6_mfilter_free(im6f[0]); + ip6_mfilter_free(im6f[1]); break; } - in6m = NULL; - if ((error = in6_joingroup(ifp, &in6, NULL, &in6m, 0)) != 0) { - free(im6o->im6o_membership, M_CARP); + if ((error = in6_joingroup(ifp, &in6, NULL, &im6f[0]->im6f_in6m, 0)) != 0) { + ip6_mfilter_free(im6f[0]); + ip6_mfilter_free(im6f[1]); break; } - in6m_acquire(in6m); - im6o->im6o_membership[0] = in6m; - im6o->im6o_num_memberships++; /* Join solicited multicast address. */ bzero(&in6, sizeof(in6)); @@ -1438,20 +1434,21 @@ carp_multicast_setup(struct carp_if *cif, sa_family_t sa) in6.s6_addr32[2] = htonl(1); in6.s6_addr32[3] = 0; in6.s6_addr8[12] = 0xff; + if ((error = in6_setscope(&in6, ifp, NULL)) != 0) { - in6_leavegroup(im6o->im6o_membership[0], NULL); - free(im6o->im6o_membership, M_CARP); + ip6_mfilter_free(im6f[0]); + ip6_mfilter_free(im6f[1]); break; } - in6m = NULL; - if ((error = in6_joingroup(ifp, &in6, NULL, &in6m, 0)) != 0) { - in6_leavegroup(im6o->im6o_membership[0], NULL); - free(im6o->im6o_membership, M_CARP); + + if ((error = in6_joingroup(ifp, &in6, NULL, &im6f[1]->im6f_in6m, 0)) != 0) { + in6_leavegroup(im6f[0]->im6f_in6m, NULL); + ip6_mfilter_free(im6f[0]); + ip6_mfilter_free(im6f[1]); break; } - in6m_acquire(in6m); - im6o->im6o_membership[1] = in6m; - im6o->im6o_num_memberships++; + ip6_mfilter_insert(&im6o->im6o_head, im6f[0]); + ip6_mfilter_insert(&im6o->im6o_head, im6f[1]); break; } #endif @@ -1466,35 +1463,38 @@ carp_multicast_setup(struct carp_if *cif, sa_family_t sa) static void carp_multicast_cleanup(struct carp_if *cif, sa_family_t sa) { - +#ifdef INET + struct ip_moptions *imo = &cif->cif_imo; + struct in_mfilter *imf; +#endif +#ifdef INET6 + struct ip6_moptions *im6o = &cif->cif_im6o; + struct in6_mfilter *im6f; +#endif sx_assert(&carp_sx, SA_XLOCKED); switch (sa) { #ifdef INET case AF_INET: - if (cif->cif_naddrs == 0) { - struct ip_moptions *imo = &cif->cif_imo; - - in_leavegroup(imo->imo_membership[0], NULL); - KASSERT(imo->imo_mfilters == NULL, - ("%s: imo_mfilters != NULL", __func__)); - free(imo->imo_membership, M_CARP); - imo->imo_membership = NULL; + if (cif->cif_naddrs != 0) + break; + while ((imf = ip_mfilter_first(&imo->imo_head)) != NULL) { + ip_mfilter_remove(&imo->imo_head, imf); + in_leavegroup(imf->imf_inm, NULL); + ip_mfilter_free(imf); } break; #endif #ifdef INET6 case AF_INET6: - if (cif->cif_naddrs6 == 0) { - struct ip6_moptions *im6o = &cif->cif_im6o; + if (cif->cif_naddrs6 != 0) + break; - in6_leavegroup(im6o->im6o_membership[0], NULL); - in6_leavegroup(im6o->im6o_membership[1], NULL); - KASSERT(im6o->im6o_mfilters == NULL, - ("%s: im6o_mfilters != NULL", __func__)); - free(im6o->im6o_membership, M_CARP); - im6o->im6o_membership = NULL; + while ((im6f = ip6_mfilter_first(&im6o->im6o_head)) != NULL) { + ip6_mfilter_remove(&im6o->im6o_head, im6f); + in6_leavegroup(im6f->im6f_in6m, NULL); + ip6_mfilter_free(im6f); } break; #endif diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h index de0cc29db1d21..7a01c82ba58b6 100644 --- a/sys/netinet/ip_fw.h +++ b/sys/netinet/ip_fw.h @@ -293,6 +293,7 @@ enum ipfw_opcodes { /* arguments (4 byte each) */ O_EXTERNAL_DATA, /* variable length data */ O_SKIP_ACTION, /* none */ + O_TCPMSS, /* arg1=MSS value */ O_LAST_OPCODE /* not an opcode! */ }; diff --git a/sys/netinet/ip_mroute.c b/sys/netinet/ip_mroute.c index 0439d353575dc..14ebb6ef10079 100644 --- a/sys/netinet/ip_mroute.c +++ b/sys/netinet/ip_mroute.c @@ -1680,7 +1680,6 @@ static void send_packet(struct vif *vifp, struct mbuf *m) { struct ip_moptions imo; - struct in_multi *imm[2]; int error __unused; VIF_LOCK_ASSERT(); @@ -1689,9 +1688,7 @@ send_packet(struct vif *vifp, struct mbuf *m) imo.imo_multicast_ttl = mtod(m, struct ip *)->ip_ttl - 1; imo.imo_multicast_loop = 1; imo.imo_multicast_vif = -1; - imo.imo_num_memberships = 0; - imo.imo_max_memberships = 2; - imo.imo_membership = &imm[0]; + STAILQ_INIT(&imo.imo_head); /* * Re-entrancy should not be a problem here, because diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c index 99b8c3662be50..2a7eb7f562862 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -109,20 +109,24 @@ extern int in_mcast_loop; extern struct protosw inetsw[]; static inline int -ip_output_pfil(struct mbuf **mp, struct ifnet *ifp, struct inpcb *inp, - struct sockaddr_in *dst, int *fibnum, int *error) +ip_output_pfil(struct mbuf **mp, struct ifnet *ifp, int flags, + struct inpcb *inp, struct sockaddr_in *dst, int *fibnum, int *error) { struct m_tag *fwd_tag = NULL; struct mbuf *m; struct in_addr odst; struct ip *ip; + int pflags = PFIL_OUT; + + if (flags & IP_FORWARDING) + pflags |= PFIL_FWD; m = *mp; ip = mtod(m, struct ip *); /* Run through list of hooks for output packets. */ odst.s_addr = ip->ip_dst.s_addr; - switch (pfil_run_hooks(V_inet_pfil_head, mp, ifp, PFIL_OUT, inp)) { + switch (pfil_run_hooks(V_inet_pfil_head, mp, ifp, pflags, inp)) { case PFIL_DROPPED: *error = EPERM; /* FALLTHROUGH */ @@ -653,7 +657,8 @@ sendit: /* Jump over all PFIL processing if hooks are not active. */ if (PFIL_HOOKED_OUT(V_inet_pfil_head)) { - switch (ip_output_pfil(&m, ifp, inp, dst, &fibnum, &error)) { + switch (ip_output_pfil(&m, ifp, flags, inp, dst, &fibnum, + &error)) { case 1: /* Finished */ goto done; diff --git a/sys/netinet/ip_var.h b/sys/netinet/ip_var.h index 38602efb3f4e4..7580a7b452129 100644 --- a/sys/netinet/ip_var.h +++ b/sys/netinet/ip_var.h @@ -82,6 +82,7 @@ struct ipoption { char ipopt_list[MAX_IPOPTLEN]; /* options proper */ }; +#if defined(_NETINET_IN_VAR_H_) && defined(_KERNEL) /* * Structure attached to inpcb.ip_moptions and * passed to ip_output when IP multicast options are in use. @@ -93,12 +94,11 @@ struct ip_moptions { u_long imo_multicast_vif; /* vif num outgoing multicasts */ u_char imo_multicast_ttl; /* TTL for outgoing multicasts */ u_char imo_multicast_loop; /* 1 => hear sends if a member */ - u_short imo_num_memberships; /* no. memberships this socket */ - u_short imo_max_memberships; /* max memberships this socket */ - struct in_multi **imo_membership; /* group memberships */ - struct in_mfilter *imo_mfilters; /* source filters */ - struct epoch_context imo_epoch_ctx; + struct ip_mfilter_head imo_head; /* group membership list */ }; +#else +struct ip_moptions; +#endif struct ipstat { uint64_t ips_total; /* total packets received */ diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c index 4ac87cb0d4706..8f767305f97d8 100644 --- a/sys/netinet/tcp_subr.c +++ b/sys/netinet/tcp_subr.c @@ -798,8 +798,12 @@ register_tcp_functions_as_names(struct tcp_function_block *blk, int wait, } } + if (blk->tfb_flags & TCP_FUNC_BEING_REMOVED) { + *num_names = 0; + return (EINVAL); + } + refcount_init(&blk->tfb_refcnt, 0); - blk->tfb_flags = 0; blk->tfb_id = atomic_fetchadd_int(&next_tcp_stack_id, 1); for (i = 0; i < *num_names; i++) { n = malloc(sizeof(struct tcp_function), M_TCPFUNCTIONS, wait); diff --git a/sys/netinet6/in6.h b/sys/netinet6/in6.h index 37d6ad40289e5..56ab11460af2b 100644 --- a/sys/netinet6/in6.h +++ b/sys/netinet6/in6.h @@ -523,11 +523,8 @@ struct route_in6 { #define IPV6_DEFAULT_MULTICAST_LOOP 1 /* normally hear sends if a member */ /* - * The im6o_membership vector for each socket is now dynamically allocated at - * run-time, bounded by USHRT_MAX, and is reallocated when needed, sized - * according to a power-of-two increment. + * Limit for IPv6 multicast memberships */ -#define IPV6_MIN_MEMBERSHIPS 31 #define IPV6_MAX_MEMBERSHIPS 4095 /* diff --git a/sys/netinet6/in6_ifattach.c b/sys/netinet6/in6_ifattach.c index a1a707449bf21..7ce680f2f91ad 100644 --- a/sys/netinet6/in6_ifattach.c +++ b/sys/netinet6/in6_ifattach.c @@ -774,9 +774,11 @@ _in6_ifdetach(struct ifnet *ifp, int purgeulp) in6_purgeaddr(ifa); } if (purgeulp) { + IN6_MULTI_LOCK(); in6_pcbpurgeif0(&V_udbinfo, ifp); in6_pcbpurgeif0(&V_ulitecbinfo, ifp); in6_pcbpurgeif0(&V_ripcbinfo, ifp); + IN6_MULTI_UNLOCK(); } /* leave from all multicast groups joined */ in6_purgemaddrs(ifp); diff --git a/sys/netinet6/in6_mcast.c b/sys/netinet6/in6_mcast.c index 5557a7c765640..f68b0a84d17db 100644 --- a/sys/netinet6/in6_mcast.c +++ b/sys/netinet6/in6_mcast.c @@ -102,7 +102,8 @@ RB_GENERATE(ip6_msource_tree, ip6_msource, im6s_link, ip6_msource_cmp); /* * Locking: - * - Lock order is: Giant, INP_WLOCK, IN6_MULTI_LOCK, MLD_LOCK, IF_ADDR_LOCK. + * - Lock order is: Giant, IN6_MULTI_LOCK, INP_WLOCK, + * IN6_MULTI_LIST_LOCK, MLD_LOCK, IF_ADDR_LOCK. * - The IF_ADDR_LOCK is implicitly taken by in6m_lookup() earlier, however * it can be taken by code in net/if.c also. * - ip6_moptions and in6_mfilter are covered by the INP_WLOCK. @@ -134,12 +135,11 @@ static int im6f_prune(struct in6_mfilter *, const struct sockaddr_in6 *); static void im6f_purge(struct in6_mfilter *); static void im6f_rollback(struct in6_mfilter *); static void im6f_reap(struct in6_mfilter *); -static int im6o_grow(struct ip6_moptions *); -static size_t im6o_match_group(const struct ip6_moptions *, +static struct in6_mfilter * + im6o_match_group(const struct ip6_moptions *, const struct ifnet *, const struct sockaddr *); static struct in6_msource * - im6o_match_source(const struct ip6_moptions *, const size_t, - const struct sockaddr *); + im6o_match_source(struct in6_mfilter *, const struct sockaddr *); static void im6s_merge(struct ip6_msource *ims, const struct in6_msource *lims, const int rollback); static int in6_getmulti(struct ifnet *, const struct in6_addr *, @@ -228,55 +228,25 @@ im6f_init(struct in6_mfilter *imf, const int st0, const int st1) imf->im6f_st[1] = st1; } -/* - * Resize the ip6_moptions vector to the next power-of-two minus 1. - * May be called with locks held; do not sleep. - */ -static int -im6o_grow(struct ip6_moptions *imo) +struct in6_mfilter * +ip6_mfilter_alloc(const int mflags, const int st0, const int st1) { - struct in6_multi **nmships; - struct in6_multi **omships; - struct in6_mfilter *nmfilters; - struct in6_mfilter *omfilters; - size_t idx; - size_t newmax; - size_t oldmax; + struct in6_mfilter *imf; - nmships = NULL; - nmfilters = NULL; - omships = imo->im6o_membership; - omfilters = imo->im6o_mfilters; - oldmax = imo->im6o_max_memberships; - newmax = ((oldmax + 1) * 2) - 1; + imf = malloc(sizeof(*imf), M_IN6MFILTER, mflags); - if (newmax <= IPV6_MAX_MEMBERSHIPS) { - nmships = (struct in6_multi **)realloc(omships, - sizeof(struct in6_multi *) * newmax, M_IP6MOPTS, M_NOWAIT); - nmfilters = (struct in6_mfilter *)realloc(omfilters, - sizeof(struct in6_mfilter) * newmax, M_IN6MFILTER, - M_NOWAIT); - if (nmships != NULL && nmfilters != NULL) { - /* Initialize newly allocated source filter heads. */ - for (idx = oldmax; idx < newmax; idx++) { - im6f_init(&nmfilters[idx], MCAST_UNDEFINED, - MCAST_EXCLUDE); - } - imo->im6o_max_memberships = newmax; - imo->im6o_membership = nmships; - imo->im6o_mfilters = nmfilters; - } - } + if (imf != NULL) + im6f_init(imf, st0, st1); - if (nmships == NULL || nmfilters == NULL) { - if (nmships != NULL) - free(nmships, M_IP6MOPTS); - if (nmfilters != NULL) - free(nmfilters, M_IN6MFILTER); - return (ETOOMANYREFS); - } + return (imf); +} - return (0); +void +ip6_mfilter_free(struct in6_mfilter *imf) +{ + + im6f_purge(imf); + free(imf, M_IN6MFILTER); } /* @@ -284,36 +254,27 @@ im6o_grow(struct ip6_moptions *imo) * which matches the specified group, and optionally an interface. * Return its index into the array, or -1 if not found. */ -static size_t +static struct in6_mfilter * im6o_match_group(const struct ip6_moptions *imo, const struct ifnet *ifp, const struct sockaddr *group) { const struct sockaddr_in6 *gsin6; - struct in6_multi **pinm; - int idx; - int nmships; + struct in6_mfilter *imf; + struct in6_multi *inm; - gsin6 = (const struct sockaddr_in6 *)group; + gsin6 = (const struct sockaddr_in6 *)group; - /* The im6o_membership array may be lazy allocated. */ - if (imo->im6o_membership == NULL || imo->im6o_num_memberships == 0) - return (-1); - - nmships = imo->im6o_num_memberships; - pinm = &imo->im6o_membership[0]; - for (idx = 0; idx < nmships; idx++, pinm++) { - if (*pinm == NULL) + IP6_MFILTER_FOREACH(imf, &imo->im6o_head) { + inm = imf->im6f_in6m; + if (inm == NULL) continue; - if ((ifp == NULL || ((*pinm)->in6m_ifp == ifp)) && - IN6_ARE_ADDR_EQUAL(&(*pinm)->in6m_addr, + if ((ifp == NULL || (inm->in6m_ifp == ifp)) && + IN6_ARE_ADDR_EQUAL(&inm->in6m_addr, &gsin6->sin6_addr)) { break; } } - if (idx >= nmships) - idx = -1; - - return (idx); + return (imf); } /* @@ -328,22 +289,13 @@ im6o_match_group(const struct ip6_moptions *imo, const struct ifnet *ifp, * it exists, which may not be the desired behaviour. */ static struct in6_msource * -im6o_match_source(const struct ip6_moptions *imo, const size_t gidx, - const struct sockaddr *src) +im6o_match_source(struct in6_mfilter *imf, const struct sockaddr *src) { struct ip6_msource find; - struct in6_mfilter *imf; struct ip6_msource *ims; const sockunion_t *psa; KASSERT(src->sa_family == AF_INET6, ("%s: !AF_INET6", __func__)); - KASSERT(gidx != -1 && gidx < imo->im6o_num_memberships, - ("%s: invalid index %d\n", __func__, (int)gidx)); - - /* The im6o_mfilters array may be lazy allocated. */ - if (imo->im6o_mfilters == NULL) - return (NULL); - imf = &imo->im6o_mfilters[gidx]; psa = (const sockunion_t *)src; find.im6s_addr = psa->sin6.sin6_addr; @@ -363,14 +315,14 @@ int im6o_mc_filter(const struct ip6_moptions *imo, const struct ifnet *ifp, const struct sockaddr *group, const struct sockaddr *src) { - size_t gidx; + struct in6_mfilter *imf; struct in6_msource *ims; int mode; KASSERT(ifp != NULL, ("%s: null ifp", __func__)); - gidx = im6o_match_group(imo, ifp, group); - if (gidx == -1) + imf = im6o_match_group(imo, ifp, group); + if (imf == NULL) return (MCAST_NOTGMEMBER); /* @@ -382,8 +334,8 @@ im6o_mc_filter(const struct ip6_moptions *imo, const struct ifnet *ifp, * NOTE: We are comparing group state here at MLD t1 (now) * with socket-layer t0 (since last downcall). */ - mode = imo->im6o_mfilters[gidx].im6f_st[1]; - ims = im6o_match_source(imo, gidx, src); + mode = imf->im6f_st[1]; + ims = im6o_match_source(imf, src); if ((ims == NULL && mode == MCAST_INCLUDE) || (ims != NULL && ims->im6sl_st[0] != mode)) @@ -1447,7 +1399,6 @@ in6p_block_unblock_source(struct inpcb *inp, struct sockopt *sopt) struct ip6_moptions *imo; struct in6_msource *ims; struct in6_multi *inm; - size_t idx; uint16_t fmode; int error, doblock; #ifdef KTR @@ -1504,16 +1455,12 @@ in6p_block_unblock_source(struct inpcb *inp, struct sockopt *sopt) * Check if we are actually a member of this group. */ imo = in6p_findmoptions(inp); - idx = im6o_match_group(imo, ifp, &gsa->sa); - if (idx == -1 || imo->im6o_mfilters == NULL) { + imf = im6o_match_group(imo, ifp, &gsa->sa); + if (imf == NULL) { error = EADDRNOTAVAIL; goto out_in6p_locked; } - - KASSERT(imo->im6o_mfilters != NULL, - ("%s: im6o_mfilters not allocated", __func__)); - imf = &imo->im6o_mfilters[idx]; - inm = imo->im6o_membership[idx]; + inm = imf->im6f_in6m; /* * Attempting to use the delta-based API on an @@ -1531,7 +1478,7 @@ in6p_block_unblock_source(struct inpcb *inp, struct sockopt *sopt) * Asked to unblock, but nothing to unblock. * If adding a new block entry, allocate it. */ - ims = im6o_match_source(imo, idx, &ssa->sa); + ims = im6o_match_source(imf, &ssa->sa); if ((ims != NULL && doblock) || (ims == NULL && !doblock)) { CTR3(KTR_MLD, "%s: source %s %spresent", __func__, ip6_sprintf(ip6tbuf, &ssa->sin6.sin6_addr), @@ -1601,9 +1548,6 @@ static struct ip6_moptions * in6p_findmoptions(struct inpcb *inp) { struct ip6_moptions *imo; - struct in6_multi **immp; - struct in6_mfilter *imfp; - size_t idx; INP_WLOCK(inp); if (inp->in6p_moptions != NULL) @@ -1612,27 +1556,14 @@ in6p_findmoptions(struct inpcb *inp) INP_WUNLOCK(inp); imo = malloc(sizeof(*imo), M_IP6MOPTS, M_WAITOK); - immp = malloc(sizeof(*immp) * IPV6_MIN_MEMBERSHIPS, M_IP6MOPTS, - M_WAITOK | M_ZERO); - imfp = malloc(sizeof(struct in6_mfilter) * IPV6_MIN_MEMBERSHIPS, - M_IN6MFILTER, M_WAITOK); imo->im6o_multicast_ifp = NULL; imo->im6o_multicast_hlim = V_ip6_defmcasthlim; imo->im6o_multicast_loop = in6_mcast_loop; - imo->im6o_num_memberships = 0; - imo->im6o_max_memberships = IPV6_MIN_MEMBERSHIPS; - imo->im6o_membership = immp; - - /* Initialize per-group source filters. */ - for (idx = 0; idx < IPV6_MIN_MEMBERSHIPS; idx++) - im6f_init(&imfp[idx], MCAST_UNDEFINED, MCAST_EXCLUDE); - imo->im6o_mfilters = imfp; + STAILQ_INIT(&imo->im6o_head); INP_WLOCK(inp); if (inp->in6p_moptions != NULL) { - free(imfp, M_IN6MFILTER); - free(immp, M_IP6MOPTS); free(imo, M_IP6MOPTS); return (inp->in6p_moptions); } @@ -1652,33 +1583,26 @@ in6p_findmoptions(struct inpcb *inp) static void inp_gcmoptions(struct ip6_moptions *imo) { - struct in6_mfilter *imf; + struct in6_mfilter *imf; struct in6_multi *inm; struct ifnet *ifp; - size_t idx, nmships; - nmships = imo->im6o_num_memberships; - for (idx = 0; idx < nmships; ++idx) { - imf = imo->im6o_mfilters ? &imo->im6o_mfilters[idx] : NULL; - if (imf) - im6f_leave(imf); - inm = imo->im6o_membership[idx]; - ifp = inm->in6m_ifp; - if (ifp != NULL) { - CURVNET_SET(ifp->if_vnet); - (void)in6_leavegroup(inm, imf); - CURVNET_RESTORE(); - } else { - (void)in6_leavegroup(inm, imf); - } - if (imf) - im6f_purge(imf); - } + while ((imf = ip6_mfilter_first(&imo->im6o_head)) != NULL) { + ip6_mfilter_remove(&imo->im6o_head, imf); - if (imo->im6o_mfilters) - free(imo->im6o_mfilters, M_IN6MFILTER); - free(imo->im6o_membership, M_IP6MOPTS); - free(imo, M_IP6MOPTS); + im6f_leave(imf); + if ((inm = imf->im6f_in6m) != NULL) { + if ((ifp = inm->in6m_ifp) != NULL) { + CURVNET_SET(ifp->if_vnet); + (void)in6_leavegroup(inm, imf); + CURVNET_RESTORE(); + } else { + (void)in6_leavegroup(inm, imf); + } + } + ip6_mfilter_free(imf); + } + free(imo, M_IP6MOPTS); } void @@ -1707,7 +1631,7 @@ in6p_get_source_filters(struct inpcb *inp, struct sockopt *sopt) struct sockaddr_storage *ptss; struct sockaddr_storage *tss; int error; - size_t idx, nsrcs, ncsrcs; + size_t nsrcs, ncsrcs; INP_WLOCK_ASSERT(inp); @@ -1741,12 +1665,11 @@ in6p_get_source_filters(struct inpcb *inp, struct sockopt *sopt) /* * Lookup group on the socket. */ - idx = im6o_match_group(imo, ifp, &gsa->sa); - if (idx == -1 || imo->im6o_mfilters == NULL) { + imf = im6o_match_group(imo, ifp, &gsa->sa); + if (imf == NULL) { INP_WUNLOCK(inp); return (EADDRNOTAVAIL); } - imf = &imo->im6o_mfilters[idx]; /* * Ignore memberships which are in limbo. @@ -1943,15 +1866,12 @@ in6p_join_group(struct inpcb *inp, struct sockopt *sopt) struct ip6_moptions *imo; struct in6_multi *inm; struct in6_msource *lims; - size_t idx; int error, is_new; SLIST_INIT(&inmh); ifp = NULL; - imf = NULL; lims = NULL; error = 0; - is_new = 0; memset(&gsr, 0, sizeof(struct group_source_req)); gsa = (sockunion_t *)&gsr.gsr_group; @@ -2052,13 +1972,25 @@ in6p_join_group(struct inpcb *inp, struct sockopt *sopt) */ (void)in6_setscope(&gsa->sin6.sin6_addr, ifp, NULL); + IN6_MULTI_LOCK(); + + /* + * Find the membership in the membership list. + */ imo = in6p_findmoptions(inp); - idx = im6o_match_group(imo, ifp, &gsa->sa); - if (idx == -1) { + imf = im6o_match_group(imo, ifp, &gsa->sa); + if (imf == NULL) { is_new = 1; + inm = NULL; + + if (ip6_mfilter_count(&imo->im6o_head) >= IPV6_MAX_MEMBERSHIPS) { + error = ENOMEM; + goto out_in6p_locked; + } } else { - inm = imo->im6o_membership[idx]; - imf = &imo->im6o_mfilters[idx]; + is_new = 0; + inm = imf->im6f_in6m; + if (ssa->ss.ss_family != AF_UNSPEC) { /* * MCAST_JOIN_SOURCE_GROUP on an exclusive membership @@ -2085,7 +2017,7 @@ in6p_join_group(struct inpcb *inp, struct sockopt *sopt) * full-state SSM API with the delta-based API, * which is discouraged in the relevant RFCs. */ - lims = im6o_match_source(imo, idx, &ssa->sa); + lims = im6o_match_source(imf, &ssa->sa); if (lims != NULL /*&& lims->im6sl_st[1] == MCAST_INCLUDE*/) { error = EADDRNOTAVAIL; @@ -2113,27 +2045,6 @@ in6p_join_group(struct inpcb *inp, struct sockopt *sopt) */ INP_WLOCK_ASSERT(inp); - if (is_new) { - if (imo->im6o_num_memberships == imo->im6o_max_memberships) { - error = im6o_grow(imo); - if (error) - goto out_in6p_locked; - } - /* - * Allocate the new slot upfront so we can deal with - * grafting the new source filter in same code path - * as for join-source on existing membership. - */ - idx = imo->im6o_num_memberships; - imo->im6o_membership[idx] = NULL; - imo->im6o_num_memberships++; - KASSERT(imo->im6o_mfilters != NULL, - ("%s: im6f_mfilters vector was not allocated", __func__)); - imf = &imo->im6o_mfilters[idx]; - KASSERT(RB_EMPTY(&imf->im6f_sources), - ("%s: im6f_sources not empty", __func__)); - } - /* * Graft new source into filter list for this inpcb's * membership of the group. The in6_multi may not have @@ -2149,7 +2060,11 @@ in6p_join_group(struct inpcb *inp, struct sockopt *sopt) /* Membership starts in IN mode */ if (is_new) { CTR1(KTR_MLD, "%s: new join w/source", __func__); - im6f_init(imf, MCAST_UNDEFINED, MCAST_INCLUDE); + imf = ip6_mfilter_alloc(M_NOWAIT, MCAST_UNDEFINED, MCAST_INCLUDE); + if (imf == NULL) { + error = ENOMEM; + goto out_in6p_locked; + } } else { CTR2(KTR_MLD, "%s: %s source", __func__, "allow"); } @@ -2158,81 +2073,88 @@ in6p_join_group(struct inpcb *inp, struct sockopt *sopt) CTR1(KTR_MLD, "%s: merge imf state failed", __func__); error = ENOMEM; - goto out_im6o_free; + goto out_in6p_locked; } } else { /* No address specified; Membership starts in EX mode */ if (is_new) { CTR1(KTR_MLD, "%s: new join w/o source", __func__); - im6f_init(imf, MCAST_UNDEFINED, MCAST_EXCLUDE); + imf = ip6_mfilter_alloc(M_NOWAIT, MCAST_UNDEFINED, MCAST_EXCLUDE); + if (imf == NULL) { + error = ENOMEM; + goto out_in6p_locked; + } } } /* * Begin state merge transaction at MLD layer. */ - in_pcbref(inp); - INP_WUNLOCK(inp); - IN6_MULTI_LOCK(); - if (is_new) { + in_pcbref(inp); + INP_WUNLOCK(inp); + error = in6_joingroup_locked(ifp, &gsa->sin6.sin6_addr, imf, - &inm, 0); + &imf->im6f_in6m, 0); + + INP_WLOCK(inp); + if (in_pcbrele_wlocked(inp)) { + error = ENXIO; + goto out_in6p_unlocked; + } if (error) { - IN6_MULTI_UNLOCK(); - goto out_im6o_free; + goto out_in6p_locked; } /* * NOTE: Refcount from in6_joingroup_locked() * is protecting membership. */ - imo->im6o_membership[idx] = inm; } else { CTR1(KTR_MLD, "%s: merge inm state", __func__); IN6_MULTI_LIST_LOCK(); error = in6m_merge(inm, imf); - if (error) + if (error) { CTR1(KTR_MLD, "%s: failed to merge inm state", __func__); - else { - CTR1(KTR_MLD, "%s: doing mld downcall", __func__); - error = mld_change_state(inm, 0); - if (error) - CTR1(KTR_MLD, "%s: failed mld downcall", - __func__); + IN6_MULTI_LIST_UNLOCK(); + im6f_rollback(imf); + im6f_reap(imf); + goto out_in6p_locked; } + CTR1(KTR_MLD, "%s: doing mld downcall", __func__); + error = mld_change_state(inm, 0); IN6_MULTI_LIST_UNLOCK(); - } - IN6_MULTI_UNLOCK(); - INP_WLOCK(inp); - if (in_pcbrele_wlocked(inp)) - return (ENXIO); - if (error) { - im6f_rollback(imf); - if (is_new) - im6f_purge(imf); - else + if (error) { + CTR1(KTR_MLD, "%s: failed mld downcall", + __func__); + im6f_rollback(imf); im6f_reap(imf); - } else { - im6f_commit(imf); - } - -out_im6o_free: - if (error && is_new) { - inm = imo->im6o_membership[idx]; - if (inm != NULL) { - IN6_MULTI_LIST_LOCK(); - in6m_rele_locked(&inmh, inm); - IN6_MULTI_LIST_UNLOCK(); + goto out_in6p_locked; } - imo->im6o_membership[idx] = NULL; - --imo->im6o_num_memberships; } + if (is_new) + ip6_mfilter_insert(&imo->im6o_head, imf); + + im6f_commit(imf); + imf = NULL; + out_in6p_locked: INP_WUNLOCK(inp); - in6m_release_list_deferred(&inmh); +out_in6p_unlocked: + IN6_MULTI_UNLOCK(); + + if (is_new && imf) { + if (imf->im6f_in6m != NULL) { + struct in6_multi_head inmh; + + SLIST_INIT(&inmh); + SLIST_INSERT_HEAD(&inmh, imf->im6f_in6m, in6m_defer); + in6m_release_list_deferred(&inmh); + } + ip6_mfilter_free(imf); + } return (error); } @@ -2251,8 +2173,8 @@ in6p_leave_group(struct inpcb *inp, struct sockopt *sopt) struct in6_msource *ims; struct in6_multi *inm; uint32_t ifindex; - size_t idx; - int error, is_final; + int error; + bool is_final; #ifdef KTR char ip6tbuf[INET6_ADDRSTRLEN]; #endif @@ -2260,7 +2182,7 @@ in6p_leave_group(struct inpcb *inp, struct sockopt *sopt) ifp = NULL; ifindex = 0; error = 0; - is_final = 1; + is_final = true; memset(&gsr, 0, sizeof(struct group_source_req)); gsa = (sockunion_t *)&gsr.gsr_group; @@ -2378,20 +2300,21 @@ in6p_leave_group(struct inpcb *inp, struct sockopt *sopt) CTR2(KTR_MLD, "%s: ifp = %p", __func__, ifp); KASSERT(ifp != NULL, ("%s: ifp did not resolve", __func__)); + IN6_MULTI_LOCK(); + /* - * Find the membership in the membership array. + * Find the membership in the membership list. */ imo = in6p_findmoptions(inp); - idx = im6o_match_group(imo, ifp, &gsa->sa); - if (idx == -1) { + imf = im6o_match_group(imo, ifp, &gsa->sa); + if (imf == NULL) { error = EADDRNOTAVAIL; goto out_in6p_locked; } - inm = imo->im6o_membership[idx]; - imf = &imo->im6o_mfilters[idx]; + inm = imf->im6f_in6m; if (ssa->ss.ss_family != AF_UNSPEC) - is_final = 0; + is_final = false; /* * Begin state merge transaction at socket layer. @@ -2403,13 +2326,14 @@ in6p_leave_group(struct inpcb *inp, struct sockopt *sopt) * MCAST_LEAVE_SOURCE_GROUP is only valid for inclusive memberships. */ if (is_final) { + ip6_mfilter_remove(&imo->im6o_head, imf); im6f_leave(imf); } else { if (imf->im6f_st[0] == MCAST_EXCLUDE) { error = EADDRNOTAVAIL; goto out_in6p_locked; } - ims = im6o_match_source(imo, idx, &ssa->sa); + ims = im6o_match_source(imf, &ssa->sa); if (ims == NULL) { CTR3(KTR_MLD, "%s: source %p %spresent", __func__, ip6_sprintf(ip6tbuf, &ssa->sin6.sin6_addr), @@ -2429,60 +2353,47 @@ in6p_leave_group(struct inpcb *inp, struct sockopt *sopt) /* * Begin state merge transaction at MLD layer. */ - in_pcbref(inp); - INP_WUNLOCK(inp); - IN6_MULTI_LOCK(); - - if (is_final) { - /* - * Give up the multicast address record to which - * the membership points. - */ - (void)in6_leavegroup_locked(inm, imf); - } else { + if (!is_final) { CTR1(KTR_MLD, "%s: merge inm state", __func__); IN6_MULTI_LIST_LOCK(); error = in6m_merge(inm, imf); - if (error) + if (error) { CTR1(KTR_MLD, "%s: failed to merge inm state", __func__); - else { - CTR1(KTR_MLD, "%s: doing mld downcall", __func__); - error = mld_change_state(inm, 0); - if (error) - CTR1(KTR_MLD, "%s: failed mld downcall", - __func__); + IN6_MULTI_LIST_UNLOCK(); + im6f_rollback(imf); + im6f_reap(imf); + goto out_in6p_locked; } + + CTR1(KTR_MLD, "%s: doing mld downcall", __func__); + error = mld_change_state(inm, 0); IN6_MULTI_LIST_UNLOCK(); + if (error) { + CTR1(KTR_MLD, "%s: failed mld downcall", + __func__); + im6f_rollback(imf); + im6f_reap(imf); + goto out_in6p_locked; + } } - IN6_MULTI_UNLOCK(); - INP_WLOCK(inp); - if (in_pcbrele_wlocked(inp)) - return (ENXIO); - - if (error) - im6f_rollback(imf); - else - im6f_commit(imf); - + im6f_commit(imf); im6f_reap(imf); - if (is_final) { - /* Remove the gap in the membership array. */ - KASSERT(RB_EMPTY(&imf->im6f_sources), - ("%s: im6f_sources not empty", __func__)); - for (++idx; idx < imo->im6o_num_memberships; ++idx) { - imo->im6o_membership[idx - 1] = imo->im6o_membership[idx]; - imo->im6o_mfilters[idx - 1] = imo->im6o_mfilters[idx]; - } - im6f_init(&imo->im6o_mfilters[idx - 1], MCAST_UNDEFINED, - MCAST_EXCLUDE); - imo->im6o_num_memberships--; - } - out_in6p_locked: INP_WUNLOCK(inp); + + if (is_final && imf) { + /* + * Give up the multicast address record to which + * the membership points. + */ + (void)in6_leavegroup_locked(inm, imf); + ip6_mfilter_free(imf); + } + + IN6_MULTI_UNLOCK(); return (error); } @@ -2540,7 +2451,6 @@ in6p_set_source_filters(struct inpcb *inp, struct sockopt *sopt) struct in6_mfilter *imf; struct ip6_moptions *imo; struct in6_multi *inm; - size_t idx; int error; error = sooptcopyin(sopt, &msfr, sizeof(struct __msfilterreq), @@ -2577,13 +2487,12 @@ in6p_set_source_filters(struct inpcb *inp, struct sockopt *sopt) * Check if this socket is a member of this group. */ imo = in6p_findmoptions(inp); - idx = im6o_match_group(imo, ifp, &gsa->sa); - if (idx == -1 || imo->im6o_mfilters == NULL) { + imf = im6o_match_group(imo, ifp, &gsa->sa); + if (imf == NULL) { error = EADDRNOTAVAIL; goto out_in6p_locked; } - inm = imo->im6o_membership[idx]; - imf = &imo->im6o_mfilters[idx]; + inm = imf->im6f_in6m; /* * Begin state merge transaction at socket layer. diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c index c27464b1e3e75..abad883dc623e 100644 --- a/sys/netinet6/in6_pcb.c +++ b/sys/netinet6/in6_pcb.c @@ -802,8 +802,9 @@ void in6_pcbpurgeif0(struct inpcbinfo *pcbinfo, struct ifnet *ifp) { struct inpcb *in6p; + struct in6_multi *inm; + struct in6_mfilter *imf; struct ip6_moptions *im6o; - int i, gap; INP_INFO_WLOCK(pcbinfo); CK_LIST_FOREACH(in6p, pcbinfo->ipi_listhead, inp_list) { @@ -824,18 +825,18 @@ in6_pcbpurgeif0(struct inpcbinfo *pcbinfo, struct ifnet *ifp) * Drop multicast group membership if we joined * through the interface being detached. */ - gap = 0; - for (i = 0; i < im6o->im6o_num_memberships; i++) { - if (im6o->im6o_membership[i]->in6m_ifp == - ifp) { - in6_leavegroup(im6o->im6o_membership[i], NULL); - gap++; - } else if (gap != 0) { - im6o->im6o_membership[i - gap] = - im6o->im6o_membership[i]; - } +restart: + IP6_MFILTER_FOREACH(imf, &im6o->im6o_head) { + if ((inm = imf->im6f_in6m) == NULL) + continue; + if (inm->in6m_ifp != ifp) + continue; + ip6_mfilter_remove(&im6o->im6o_head, imf); + IN6_MULTI_LOCK_ASSERT(); + in6_leavegroup_locked(inm, NULL); + ip6_mfilter_free(imf); + goto restart; } - im6o->im6o_num_memberships -= gap; } INP_WUNLOCK(in6p); } diff --git a/sys/netinet6/in6_var.h b/sys/netinet6/in6_var.h index 3e965c2d4b320..3e535310b29e1 100644 --- a/sys/netinet6/in6_var.h +++ b/sys/netinet6/in6_var.h @@ -602,9 +602,61 @@ struct in6_mfilter { struct ip6_msource_tree im6f_sources; /* source list for (S,G) */ u_long im6f_nsrc; /* # of source entries */ uint8_t im6f_st[2]; /* state before/at commit */ + struct in6_multi *im6f_in6m; /* associated multicast address */ + STAILQ_ENTRY(in6_mfilter) im6f_entry; /* list entry */ }; /* + * Helper types and functions for IPv4 multicast filters. + */ +STAILQ_HEAD(ip6_mfilter_head, in6_mfilter); + +struct in6_mfilter *ip6_mfilter_alloc(int mflags, int st0, int st1); +void ip6_mfilter_free(struct in6_mfilter *); + +static inline void +ip6_mfilter_init(struct ip6_mfilter_head *head) +{ + + STAILQ_INIT(head); +} + +static inline struct in6_mfilter * +ip6_mfilter_first(const struct ip6_mfilter_head *head) +{ + + return (STAILQ_FIRST(head)); +} + +static inline void +ip6_mfilter_insert(struct ip6_mfilter_head *head, struct in6_mfilter *imf) +{ + + STAILQ_INSERT_TAIL(head, imf, im6f_entry); +} + +static inline void +ip6_mfilter_remove(struct ip6_mfilter_head *head, struct in6_mfilter *imf) +{ + + STAILQ_REMOVE(head, imf, in6_mfilter, im6f_entry); +} + +#define IP6_MFILTER_FOREACH(imf, head) \ + STAILQ_FOREACH(imf, head, im6f_entry) + +static inline size_t +ip6_mfilter_count(struct ip6_mfilter_head *head) +{ + struct in6_mfilter *imf; + size_t num = 0; + + STAILQ_FOREACH(imf, head, im6f_entry) + num++; + return (num); +} + +/* * Legacy KAME IPv6 multicast membership descriptor. */ struct in6_multi_mship { diff --git a/sys/netinet6/ip6_var.h b/sys/netinet6/ip6_var.h index 40f502abcd087..45ee4425fb745 100644 --- a/sys/netinet6/ip6_var.h +++ b/sys/netinet6/ip6_var.h @@ -110,6 +110,7 @@ struct ip6_direct_ctx { uint32_t ip6dc_off; /* offset to next header */ }; +#if defined(_NETINET6_IN6_VAR_H_) && defined(_KERNEL) /* * Structure attached to inpcb.in6p_moptions and * passed to ip6_output when IPv6 multicast options are in use. @@ -119,13 +120,11 @@ struct ip6_moptions { struct ifnet *im6o_multicast_ifp; /* ifp for outgoing multicasts */ u_char im6o_multicast_hlim; /* hoplimit for outgoing multicasts */ u_char im6o_multicast_loop; /* 1 >= hear sends if a member */ - u_short im6o_num_memberships; /* no. memberships this socket */ - u_short im6o_max_memberships; /* max memberships this socket */ - struct in6_multi **im6o_membership; /* group memberships */ - struct in6_mfilter *im6o_mfilters; /* source filters */ - struct epoch_context imo6_epoch_ctx; + struct ip6_mfilter_head im6o_head; /* group membership list */ }; - +#else +struct ip6_moptions; +#endif /* * Control options for outgoing packets */ diff --git a/sys/netipsec/key.c b/sys/netipsec/key.c index d54427410b925..82a84a4125385 100644 --- a/sys/netipsec/key.c +++ b/sys/netipsec/key.c @@ -7164,7 +7164,7 @@ key_register(struct socket *so, struct mbuf *m, const struct sadb_msghdr *mhp) return key_senderror(so, m, ENOBUFS); MGETHDR(n, M_NOWAIT, MT_DATA); - if (len > MHLEN) { + if (n != NULL && len > MHLEN) { if (!(MCLGET(n, M_NOWAIT))) { m_freem(n); n = NULL; diff --git a/sys/netpfil/ipfw/ip_fw2.c b/sys/netpfil/ipfw/ip_fw2.c index a4a3830132eb5..535be037b6cca 100644 --- a/sys/netpfil/ipfw/ip_fw2.c +++ b/sys/netpfil/ipfw/ip_fw2.c @@ -331,10 +331,10 @@ ipopts_match(struct ip *ip, ipfw_insn *cmd) } static int -tcpopts_match(struct tcphdr *tcp, ipfw_insn *cmd) +tcpopts_parse(struct tcphdr *tcp, uint16_t *mss) { - int optlen, bits = 0; u_char *cp = (u_char *)(tcp + 1); + int optlen, bits = 0; int x = (tcp->th_off << 2) - sizeof(struct tcphdr); for (; x > 0; x -= optlen, cp += optlen) { @@ -350,12 +350,13 @@ tcpopts_match(struct tcphdr *tcp, ipfw_insn *cmd) } switch (opt) { - default: break; case TCPOPT_MAXSEG: bits |= IP_FW_TCPOPT_MSS; + if (mss != NULL) + *mss = be16dec(cp + 2); break; case TCPOPT_WINDOW: @@ -370,10 +371,16 @@ tcpopts_match(struct tcphdr *tcp, ipfw_insn *cmd) case TCPOPT_TIMESTAMP: bits |= IP_FW_TCPOPT_TS; break; - } } - return (flags_match(cmd, bits)); + return (bits); +} + +static int +tcpopts_match(struct tcphdr *tcp, ipfw_insn *cmd) +{ + + return (flags_match(cmd, tcpopts_parse(tcp, NULL))); } static int @@ -1712,6 +1719,11 @@ do { \ default: break; } + } else { + if (offset == 1 && proto == IPPROTO_TCP) { + /* RFC 3128 */ + goto pullup_failed; + } } UPDATE_POINTERS(); @@ -2316,6 +2328,31 @@ do { \ TCP(ulp)->th_ack); break; + case O_TCPMSS: + if (proto == IPPROTO_TCP && + (args->f_id._flags & TH_SYN) != 0 && + ulp != NULL) { + uint16_t mss, *p; + int i; + + PULLUP_LEN(hlen, ulp, + (TCP(ulp)->th_off << 2)); + if ((tcpopts_parse(TCP(ulp), &mss) & + IP_FW_TCPOPT_MSS) == 0) + break; + if (cmdlen == 1) { + match = (cmd->arg1 == mss); + break; + } + /* Otherwise we have ranges. */ + p = ((ipfw_insn_u16 *)cmd)->ports; + i = cmdlen - 1; + for (; !match && i > 0; i--, p += 2) + match = (mss >= p[0] && + mss <= p[1]); + } + break; + case O_TCPWIN: if (proto == IPPROTO_TCP && offset == 0) { uint16_t x; @@ -3332,6 +3369,7 @@ vnet_ipfw_init(const void *unused) /* fill and insert the default rule */ rule = ipfw_alloc_rule(chain, sizeof(struct ip_fw)); + rule->flags |= IPFW_RULE_NOOPT; rule->cmd_len = 1; rule->cmd[0].len = 1; rule->cmd[0].opcode = default_to_accept ? O_ACCEPT : O_DENY; diff --git a/sys/netpfil/ipfw/ip_fw_sockopt.c b/sys/netpfil/ipfw/ip_fw_sockopt.c index a83e754476335..297b01ca7d3da 100644 --- a/sys/netpfil/ipfw/ip_fw_sockopt.c +++ b/sys/netpfil/ipfw/ip_fw_sockopt.c @@ -1176,7 +1176,9 @@ move_objects(struct ip_fw_chain *ch, ipfw_range_tlv *rt) } } return (c); -}/* +} + +/* * Changes set of given rule rannge @rt * with each other. * @@ -1907,6 +1909,7 @@ check_ipfw_rule_body(ipfw_insn *cmd, int cmd_len, struct rule_check_info *ci) case O_IPTTL: case O_IPLEN: case O_TCPDATALEN: + case O_TCPMSS: case O_TCPWIN: case O_TAGGED: if (cmdlen < 1 || cmdlen > 31) diff --git a/sys/netpfil/pf/if_pfsync.c b/sys/netpfil/pf/if_pfsync.c index 45b1e090f95c9..0566593b76169 100644 --- a/sys/netpfil/pf/if_pfsync.c +++ b/sys/netpfil/pf/if_pfsync.c @@ -264,7 +264,7 @@ static void pfsync_push(struct pfsync_bucket *); static void pfsync_push_all(struct pfsync_softc *); static void pfsyncintr(void *); static int pfsync_multicast_setup(struct pfsync_softc *, struct ifnet *, - void *); + struct in_mfilter *imf); static void pfsync_multicast_cleanup(struct pfsync_softc *); static void pfsync_pointers_init(void); static void pfsync_pointers_uninit(void); @@ -430,8 +430,7 @@ pfsync_clone_destroy(struct ifnet *ifp) pfsync_drop(sc); if_free(ifp); - if (sc->sc_imo.imo_membership) - pfsync_multicast_cleanup(sc); + pfsync_multicast_cleanup(sc); mtx_destroy(&sc->sc_mtx); mtx_destroy(&sc->sc_bulk_mtx); @@ -1373,10 +1372,9 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data) case SIOCSETPFSYNC: { - struct ip_moptions *imo = &sc->sc_imo; + struct in_mfilter *imf = NULL; struct ifnet *sifp; struct ip *ip; - void *mship = NULL; if ((error = priv_check(curthread, PRIV_NETINET_PF)) != 0) return (error); @@ -1396,8 +1394,7 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data) pfsyncr.pfsyncr_syncpeer.s_addr == 0 || pfsyncr.pfsyncr_syncpeer.s_addr == htonl(INADDR_PFSYNC_GROUP))) - mship = malloc((sizeof(struct in_multi *) * - IP_MIN_MEMBERSHIPS), M_PFSYNC, M_WAITOK | M_ZERO); + imf = ip_mfilter_alloc(M_WAITOK, 0, 0); PFSYNC_LOCK(sc); if (pfsyncr.pfsyncr_syncpeer.s_addr == 0) @@ -1419,8 +1416,7 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data) if (sc->sc_sync_if) if_rele(sc->sc_sync_if); sc->sc_sync_if = NULL; - if (imo->imo_membership) - pfsync_multicast_cleanup(sc); + pfsync_multicast_cleanup(sc); PFSYNC_UNLOCK(sc); break; } @@ -1436,14 +1432,13 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data) PFSYNC_BUCKET_UNLOCK(&sc->sc_buckets[c]); } - if (imo->imo_membership) - pfsync_multicast_cleanup(sc); + pfsync_multicast_cleanup(sc); if (sc->sc_sync_peer.s_addr == htonl(INADDR_PFSYNC_GROUP)) { - error = pfsync_multicast_setup(sc, sifp, mship); + error = pfsync_multicast_setup(sc, sifp, imf); if (error) { if_rele(sifp); - free(mship, M_PFSYNC); + ip_mfilter_free(imf); PFSYNC_UNLOCK(sc); return (error); } @@ -2353,7 +2348,8 @@ pfsyncintr(void *arg) } static int -pfsync_multicast_setup(struct pfsync_softc *sc, struct ifnet *ifp, void *mship) +pfsync_multicast_setup(struct pfsync_softc *sc, struct ifnet *ifp, + struct in_mfilter *imf) { struct ip_moptions *imo = &sc->sc_imo; int error; @@ -2361,16 +2357,14 @@ pfsync_multicast_setup(struct pfsync_softc *sc, struct ifnet *ifp, void *mship) if (!(ifp->if_flags & IFF_MULTICAST)) return (EADDRNOTAVAIL); - imo->imo_membership = (struct in_multi **)mship; - imo->imo_max_memberships = IP_MIN_MEMBERSHIPS; imo->imo_multicast_vif = -1; if ((error = in_joingroup(ifp, &sc->sc_sync_peer, NULL, - &imo->imo_membership[0])) != 0) { - imo->imo_membership = NULL; + &imf->imf_inm)) != 0) return (error); - } - imo->imo_num_memberships++; + + ip_mfilter_init(&imo->imo_head); + ip_mfilter_insert(&imo->imo_head, imf); imo->imo_multicast_ifp = ifp; imo->imo_multicast_ttl = PFSYNC_DFLTTL; imo->imo_multicast_loop = 0; @@ -2382,10 +2376,13 @@ static void pfsync_multicast_cleanup(struct pfsync_softc *sc) { struct ip_moptions *imo = &sc->sc_imo; + struct in_mfilter *imf; - in_leavegroup(imo->imo_membership[0], NULL); - free(imo->imo_membership, M_PFSYNC); - imo->imo_membership = NULL; + while ((imf = ip_mfilter_first(&imo->imo_head)) != NULL) { + ip_mfilter_remove(&imo->imo_head, imf); + in_leavegroup(imf->imf_inm, NULL); + ip_mfilter_free(imf); + } imo->imo_multicast_ifp = NULL; } @@ -2404,7 +2401,7 @@ pfsync_detach_ifnet(struct ifnet *ifp) * is going away. We do need to ensure we don't try to do * cleanup later. */ - sc->sc_imo.imo_membership = NULL; + ip_mfilter_init(&sc->sc_imo.imo_head); sc->sc_imo.imo_multicast_ifp = NULL; sc->sc_sync_if = NULL; } diff --git a/sys/powerpc/conf/GENERIC b/sys/powerpc/conf/GENERIC index dc19d7a85598c..78d83c9ba12de 100644 --- a/sys/powerpc/conf/GENERIC +++ b/sys/powerpc/conf/GENERIC @@ -162,7 +162,6 @@ device fxp # Intel EtherExpress PRO/100B (82557, 82558) # Pseudo devices. device crypto # core crypto support device loop # Network loopback -device random # Entropy device device ether # Ethernet support device vlan # 802.1Q VLAN support device tuntap # Packet tunnel. diff --git a/sys/powerpc/conf/GENERIC64 b/sys/powerpc/conf/GENERIC64 index dc3d54e371c9a..409062047b244 100644 --- a/sys/powerpc/conf/GENERIC64 +++ b/sys/powerpc/conf/GENERIC64 @@ -183,7 +183,6 @@ device rl # RealTek 8129/8139 # Pseudo devices. device crypto # core crypto support device loop # Network loopback -device random # Entropy device device ether # Ethernet support device vlan # 802.1Q VLAN support device tuntap # Packet tunnel. diff --git a/sys/powerpc/conf/MPC85XX b/sys/powerpc/conf/MPC85XX index 3eeba5f54ec47..7962bdc22db07 100644 --- a/sys/powerpc/conf/MPC85XX +++ b/sys/powerpc/conf/MPC85XX @@ -93,7 +93,6 @@ device mmcsd device pass device pci device quicc -device random #device rl device scbus device scc diff --git a/sys/powerpc/conf/MPC85XXSPE b/sys/powerpc/conf/MPC85XXSPE index 1d649c1b36b9b..2cea302361a37 100644 --- a/sys/powerpc/conf/MPC85XXSPE +++ b/sys/powerpc/conf/MPC85XXSPE @@ -94,7 +94,6 @@ device mmcsd device pass device pci device quicc -device random #device rl device scbus device scc diff --git a/sys/powerpc/conf/QORIQ64 b/sys/powerpc/conf/QORIQ64 index eecc0eb8e06b2..1661829a6d25e 100644 --- a/sys/powerpc/conf/QORIQ64 +++ b/sys/powerpc/conf/QORIQ64 @@ -99,7 +99,6 @@ device mmc device mmcsd device pass device pci -device random #device rl device scbus device scc diff --git a/sys/powerpc/conf/dpaa/DPAA b/sys/powerpc/conf/dpaa/DPAA index 2cbc908ec1206..4aa24c188accf 100644 --- a/sys/powerpc/conf/dpaa/DPAA +++ b/sys/powerpc/conf/dpaa/DPAA @@ -96,7 +96,6 @@ device pci # Pseudo devices device ether # Ethernet support device loop # Network loopback -device random # Entropy device device bpf # Berkeley packet filter device md # Memory "disks" diff --git a/sys/powerpc/include/trap.h b/sys/powerpc/include/trap.h index 5017a7535d292..56b789c248ef9 100644 --- a/sys/powerpc/include/trap.h +++ b/sys/powerpc/include/trap.h @@ -130,7 +130,7 @@ /* Macros to extract register information */ #define EXC_ALI_RST(dsisr) ((dsisr >> 5) & 0x1f) /* source or target */ #define EXC_ALI_RA(dsisr) (dsisr & 0x1f) -#define EXC_ALI_SPE_REG(instr) ((instr >> 21) & 0x1f) +#define EXC_ALI_INST_RST(instr) ((instr >> 21) & 0x1f) /* * SRR1 bits for program exception traps. These identify what caused diff --git a/sys/powerpc/powerpc/machdep.c b/sys/powerpc/powerpc/machdep.c index 6fb874e31d9cb..0bd6a11197abd 100644 --- a/sys/powerpc/powerpc/machdep.c +++ b/sys/powerpc/powerpc/machdep.c @@ -595,3 +595,16 @@ bzero(void *buf, size_t len) len--; } } + +/* __stack_chk_fail_local() is called in secure-plt (32-bit). */ +#if !defined(__powerpc64__) +extern void __stack_chk_fail(void); +void __stack_chk_fail_local(void); + +void +__stack_chk_fail_local(void) +{ + + __stack_chk_fail(); +} +#endif diff --git a/sys/powerpc/powerpc/trap.c b/sys/powerpc/powerpc/trap.c index 0200c7bbd1428..3cc04fbc75ad8 100644 --- a/sys/powerpc/powerpc/trap.c +++ b/sys/powerpc/powerpc/trap.c @@ -788,7 +788,7 @@ static int fix_unaligned(struct thread *td, struct trapframe *frame) { struct thread *fputhread; -#ifdef __SPE__ +#ifdef BOOKE uint32_t inst; #endif int indicator, reg; @@ -799,7 +799,7 @@ fix_unaligned(struct thread *td, struct trapframe *frame) if (indicator & ESR_SPE) { if (copyin((void *)frame->srr0, &inst, sizeof(inst)) != 0) return (-1); - reg = EXC_ALI_SPE_REG(inst); + reg = EXC_ALI_INST_RST(inst); fpr = (double *)td->td_pcb->pcb_vec.vr[reg]; fputhread = PCPU_GET(vecthread); @@ -829,12 +829,22 @@ fix_unaligned(struct thread *td, struct trapframe *frame) return (0); } #else +#ifdef BOOKE + indicator = (frame->cpu.booke.esr & ESR_ST) ? EXC_ALI_STFD : EXC_ALI_LFD; +#else indicator = EXC_ALI_OPCODE_INDICATOR(frame->cpu.aim.dsisr); +#endif switch (indicator) { case EXC_ALI_LFD: case EXC_ALI_STFD: +#ifdef BOOKE + if (copyin((void *)frame->srr0, &inst, sizeof(inst)) != 0) + return (-1); + reg = EXC_ALI_INST_RST(inst); +#else reg = EXC_ALI_RST(frame->cpu.aim.dsisr); +#endif fpr = &td->td_pcb->pcb_fpu.fpr[reg].fpr; fputhread = PCPU_GET(fputhread); diff --git a/sys/riscv/conf/GENERIC b/sys/riscv/conf/GENERIC index 559e9166daa95..5b647977879fd 100644 --- a/sys/riscv/conf/GENERIC +++ b/sys/riscv/conf/GENERIC @@ -137,7 +137,6 @@ options ZSTDIO # zstd-compressed kernel and user dumps # Pseudo devices. device crypto # core crypto support device loop # Network loopback -device random # Entropy device device ether # Ethernet support device vlan # 802.1Q VLAN support device tuntap # Packet tunnel. diff --git a/sys/sparc64/conf/GENERIC b/sys/sparc64/conf/GENERIC index 285adadf332c0..75fe3f8425775 100644 --- a/sys/sparc64/conf/GENERIC +++ b/sys/sparc64/conf/GENERIC @@ -224,7 +224,6 @@ device ath_rate_sample # SampleRate tx rate control for ath # Pseudo devices. device crypto # core crypto support device loop # Network loopback -device random # Entropy device device ether # Ethernet support device vlan # 802.1Q VLAN support device tuntap # Packet tunnel. diff --git a/sys/sys/_types.h b/sys/sys/_types.h index 22a37c53389ae..020ba025ea98c 100644 --- a/sys/sys/_types.h +++ b/sys/sys/_types.h @@ -68,6 +68,7 @@ typedef unsigned int __useconds_t; /* microseconds (unsigned) */ typedef int __cpuwhich_t; /* which parameter for cpuset. */ typedef int __cpulevel_t; /* level parameter for cpuset. */ typedef int __cpusetid_t; /* cpuset identifier. */ +typedef __int64_t __daddr_t; /* bwrite(3), FIOBMAP2, etc */ /* * Unusual type definitions. diff --git a/sys/sys/boot.h b/sys/sys/boot.h index 68b9e1e0daf3e..7874d96637364 100644 --- a/sys/sys/boot.h +++ b/sys/sys/boot.h @@ -32,6 +32,8 @@ #ifndef _SYS_BOOT_H_ #define _SYS_BOOT_H_ +#define PATH_KERNEL "/boot/kernel/kernel" + int boot_env_to_howto(void); void boot_howto_to_env(int howto); int boot_parse_arg(char *v); diff --git a/sys/sys/file.h b/sys/sys/file.h index 82af5e6b1bbe4..942380c1647f1 100644 --- a/sys/sys/file.h +++ b/sys/sys/file.h @@ -179,7 +179,10 @@ struct file { /* * DTYPE_VNODE specific fields. */ - int f_seqcount; /* (a) Count of sequential accesses. */ + union { + int16_t f_seqcount; /* (a) Count of sequential accesses. */ + int f_pipegen; + }; off_t f_nextoff; /* next expected read/write offset. */ union { struct cdev_privdata *fvn_cdevpriv; diff --git a/sys/sys/filio.h b/sys/sys/filio.h index e85db9cff4d1e..c5cf3d4432e97 100644 --- a/sys/sys/filio.h +++ b/sys/sys/filio.h @@ -40,7 +40,7 @@ #ifndef _SYS_FILIO_H_ #define _SYS_FILIO_H_ -#include <sys/types.h> +#include <sys/_types.h> #include <sys/ioccom.h> /* Generic file-descriptor ioctl's. */ @@ -64,12 +64,12 @@ struct fiodgname_arg { #define FIOSEEKDATA _IOWR('f', 97, off_t) /* SEEK_DATA */ #define FIOSEEKHOLE _IOWR('f', 98, off_t) /* SEEK_HOLE */ struct fiobmap2_arg { - int64_t bn; - int runp; - int runb; + __daddr_t bn; + int runp; + int runb; }; -/* Get the file's bmap info for the logical block bn */ -#define FIOBMAP2 _IOWR('f', 99, struct fiobmap2_arg) +/* Get the file's bmap info for the logical block bn. */ +#define FIOBMAP2 _IOWR('f', 99, struct fiobmap2_arg) #ifdef _KERNEL #ifdef COMPAT_FREEBSD32 diff --git a/sys/sys/mman.h b/sys/sys/mman.h index b2fad0e475799..1b1b4bcc2cb92 100644 --- a/sys/sys/mman.h +++ b/sys/sys/mman.h @@ -55,6 +55,14 @@ #define PROT_READ 0x01 /* pages can be read */ #define PROT_WRITE 0x02 /* pages can be written */ #define PROT_EXEC 0x04 /* pages can be executed */ +#if __BSD_VISIBLE +#define _PROT_ALL (PROT_READ | PROT_WRITE | PROT_EXEC) +#define PROT_EXTRACT(prot) ((prot) & _PROT_ALL) + +#define _PROT_MAX_SHIFT 16 +#define PROT_MAX(prot) ((prot) << _PROT_MAX_SHIFT) +#define PROT_MAX_EXTRACT(prot) (((prot) >> _PROT_MAX_SHIFT) & _PROT_ALL) +#endif /* * Flags contain sharing type and options. diff --git a/sys/sys/param.h b/sys/sys/param.h index 2534537558c53..9a68762388f2d 100644 --- a/sys/sys/param.h +++ b/sys/sys/param.h @@ -60,7 +60,7 @@ * in the range 5 to 9. */ #undef __FreeBSD_version -#define __FreeBSD_version 1300032 /* Master, propagated to newvers */ +#define __FreeBSD_version 1300034 /* Master, propagated to newvers */ /* * __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD, diff --git a/sys/sys/pcpu.h b/sys/sys/pcpu.h index 38785cd26c94c..3672d6070deb7 100644 --- a/sys/sys/pcpu.h +++ b/sys/sys/pcpu.h @@ -85,7 +85,8 @@ extern uintptr_t dpcpu_off[]; /* struct _hack is to stop this from being used with the static keyword. */ #define DPCPU_DEFINE(t, n) \ struct _hack; t DPCPU_NAME(n) __section(DPCPU_SETNAME) __used -#if defined(KLD_MODULE) && (defined(__aarch64__) || defined(__riscv)) +#if defined(KLD_MODULE) && (defined(__aarch64__) || defined(__riscv) \ + || defined(__powerpc64__)) /* * On some architectures the compiler will use PC-relative load to * find the address of DPCPU data with the static keyword. We then diff --git a/sys/sys/pmckern.h b/sys/sys/pmckern.h index e892d658a1ca2..5b337f8d76df0 100644 --- a/sys/sys/pmckern.h +++ b/sys/sys/pmckern.h @@ -226,7 +226,7 @@ do { \ */ #define PMC_CALL_HOOK_UNLOCKED(t, cmd, arg) \ do { \ - if (pmc_hook != NULL) \ + if (pmc_hook != NULL) \ (pmc_hook)((t), (cmd), (arg)); \ } while (0) diff --git a/sys/sys/random.h b/sys/sys/random.h index aa8c5f02c32e1..8bcbe470cfc11 100644 --- a/sys/sys/random.h +++ b/sys/sys/random.h @@ -37,26 +37,9 @@ struct uio; -#if defined(DEV_RANDOM) void read_random(void *, u_int); int read_random_uio(struct uio *, bool); bool is_random_seeded(void); -#else -static __inline int -read_random_uio(void *a __unused, u_int b __unused) -{ - return (0); -} -static __inline void -read_random(void *a __unused, u_int b __unused) -{ -} -static __inline bool -is_random_seeded(void) -{ - return (false); -} -#endif /* * Note: if you add or remove members of random_entropy_source, remember to @@ -101,7 +84,6 @@ _Static_assert(ENTROPYSOURCE <= 32, #define RANDOM_LEGACY_BOOT_ENTROPY_MODULE "/boot/entropy" #define RANDOM_CACHED_BOOT_ENTROPY_MODULE "boot_entropy_cache" -#if defined(DEV_RANDOM) extern u_int hc_source_mask; void random_harvest_queue_(const void *, u_int, enum random_entropy_source); void random_harvest_fast_(const void *, u_int); @@ -133,13 +115,6 @@ random_harvest_direct(const void *entropy, u_int size, enum random_entropy_sourc void random_harvest_register_source(enum random_entropy_source); void random_harvest_deregister_source(enum random_entropy_source); -#else -#define random_harvest_queue(a, b, c) do {} while (0) -#define random_harvest_fast(a, b, c) do {} while (0) -#define random_harvest_direct(a, b, c) do {} while (0) -#define random_harvest_register_source(a) do {} while (0) -#define random_harvest_deregister_source(a) do {} while (0) -#endif #if defined(RANDOM_ENABLE_UMA) #define random_harvest_fast_uma(a, b, c) random_harvest_fast(a, b, c) diff --git a/sys/sys/rangelock.h b/sys/sys/rangelock.h index 732bd9406d481..9a8a107aed8f4 100644 --- a/sys/sys/rangelock.h +++ b/sys/sys/rangelock.h @@ -75,8 +75,12 @@ void *rangelock_unlock_range(struct rangelock *lock, void *cookie, off_t start, off_t end, struct mtx *ilk); void *rangelock_rlock(struct rangelock *lock, off_t start, off_t end, struct mtx *ilk); +void *rangelock_tryrlock(struct rangelock *lock, off_t start, off_t end, + struct mtx *ilk); void *rangelock_wlock(struct rangelock *lock, off_t start, off_t end, struct mtx *ilk); +void *rangelock_trywlock(struct rangelock *lock, off_t start, off_t end, + struct mtx *ilk); void rlqentry_free(struct rl_q_entry *rlqe); #endif /* _KERNEL */ diff --git a/sys/sys/types.h b/sys/sys/types.h index 39d8d63262e8b..c3ece22e58b83 100644 --- a/sys/sys/types.h +++ b/sys/sys/types.h @@ -101,7 +101,7 @@ typedef __clockid_t clockid_t; #endif typedef __critical_t critical_t; /* Critical section value */ -typedef __int64_t daddr_t; /* disk address */ +typedef __daddr_t daddr_t; /* disk address */ #ifndef _DEV_T_DECLARED typedef __dev_t dev_t; /* device number or struct cdev */ diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h index 50eae14026afd..9c0dc25f3f83b 100644 --- a/sys/sys/vnode.h +++ b/sys/sys/vnode.h @@ -722,8 +722,12 @@ int vn_io_fault_pgmove(vm_page_t ma[], vm_offset_t offset, int xfersize, VI_MTX(vp)) #define vn_rangelock_rlock(vp, start, end) \ rangelock_rlock(&(vp)->v_rl, (start), (end), VI_MTX(vp)) +#define vn_rangelock_tryrlock(vp, start, end) \ + rangelock_tryrlock(&(vp)->v_rl, (start), (end), VI_MTX(vp)) #define vn_rangelock_wlock(vp, start, end) \ rangelock_wlock(&(vp)->v_rl, (start), (end), VI_MTX(vp)) +#define vn_rangelock_trywlock(vp, start, end) \ + rangelock_trywlock(&(vp)->v_rl, (start), (end), VI_MTX(vp)) int vfs_cache_lookup(struct vop_lookup_args *ap); void vfs_timestamp(struct timespec *); diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c index 3a4a20b8565c0..8d43e5528e185 100644 --- a/sys/ufs/ffs/ffs_softdep.c +++ b/sys/ufs/ffs/ffs_softdep.c @@ -2110,7 +2110,6 @@ pagedep_find(pagedephd, ino, lbn, pagedeppp) * Look up a pagedep. Return 1 if found, 0 otherwise. * If not found, allocate if DEPALLOC flag is passed. * Found or allocated entry is returned in pagedeppp. - * This routine must be called with splbio interrupts blocked. */ static int pagedep_lookup(mp, bp, ino, lbn, flags, pagedeppp) @@ -2202,7 +2201,6 @@ inodedep_find(inodedephd, inum, inodedeppp) * Look up an inodedep. Return 1 if found, 0 if not found. * If not found, allocate if DEPALLOC flag is passed. * Found or allocated entry is returned in inodedeppp. - * This routine must be called with splbio interrupts blocked. */ static int inodedep_lookup(mp, inum, flags, inodedeppp) @@ -5478,7 +5476,6 @@ jnewblk_merge(new, old, wkhd) /* * Replace an old allocdirect dependency with a newer one. - * This routine must be called with splbio interrupts blocked. */ static void allocdirect_merge(adphead, newadp, oldadp) @@ -7534,7 +7531,6 @@ free_newblk(newblk) /* * Free a newdirblk. Clear the NEWBLOCK flag on its associated pagedep. - * This routine must be called with splbio interrupts blocked. */ static void free_newdirblk(newdirblk) @@ -7665,7 +7661,6 @@ softdep_freefile(pvp, ino, mode) /* * Check to see if an inode has never been written to disk. If * so free the inodedep and return success, otherwise return failure. - * This routine must be called with splbio interrupts blocked. * * If we still have a bitmap dependency, then the inode has never * been written to disk. Drop the dependency as it is no longer @@ -8897,8 +8892,7 @@ cancel_diradd(dap, dirrem, jremref, dotremref, dotdotremref) } /* - * Free a diradd dependency structure. This routine must be called - * with splbio interrupts blocked. + * Free a diradd dependency structure. */ static void free_diradd(dap, wkhd) @@ -11195,9 +11189,7 @@ softdep_disk_write_complete(bp) } /* - * Called from within softdep_disk_write_complete above. Note that - * this routine is always called from interrupt level with further - * splbio interrupts blocked. + * Called from within softdep_disk_write_complete above. */ static void handle_allocdirect_partdone(adp, wkhd) @@ -11209,6 +11201,7 @@ handle_allocdirect_partdone(adp, wkhd) struct inodedep *inodedep; long bsize; + LOCK_OWNED(VFSTOUFS(adp->ad_block.nb_list.wk_mp)); if ((adp->ad_state & ALLCOMPLETE) != ALLCOMPLETE) return; /* @@ -11818,7 +11811,6 @@ handle_written_indirdep(indirdep, bp, bpp, flags) /* * Process a diradd entry after its dependent inode has been written. - * This routine must be called with splbio interrupts blocked. */ static void diradd_inode_written(dap, inodedep) @@ -11826,6 +11818,7 @@ diradd_inode_written(dap, inodedep) struct inodedep *inodedep; { + LOCK_OWNED(VFSTOUFS(dap->da_list.wk_mp)); dap->da_state |= COMPLETE; complete_diradd(dap); WORKLIST_INSERT(&inodedep->id_pendinghd, &dap->da_list); @@ -12386,8 +12379,7 @@ retry: /* * Merge the a new inode dependency list (such as id_newinoupdt) into an - * old inode dependency list (such as id_inoupdt). This routine must be - * called with splbio interrupts blocked. + * old inode dependency list (such as id_inoupdt). */ static void merge_inode_lists(newlisthead, oldlisthead) @@ -12397,6 +12389,8 @@ merge_inode_lists(newlisthead, oldlisthead) struct allocdirect *listadp, *newadp; newadp = TAILQ_FIRST(newlisthead); + if (newadp != NULL) + LOCK_OWNED(VFSTOUFS(newadp->ad_block.nb_list.wk_mp)); for (listadp = TAILQ_FIRST(oldlisthead); listadp && newadp;) { if (listadp->ad_offset < newadp->ad_offset) { listadp = TAILQ_NEXT(listadp, ad_next); @@ -12891,7 +12885,6 @@ out: /* * Flush the dependencies associated with an inodedep. - * Called with splbio blocked. */ static int flush_inodedep_deps(vp, mp, ino) @@ -12956,7 +12949,6 @@ restart: /* * Flush an inode dependency list. - * Called with splbio blocked. */ static int flush_deplist(listhead, waitfor, errorp) @@ -13098,7 +13090,6 @@ flush_newblk_dep(vp, mp, lbn) /* * Eliminate a pagedep dependency by flushing out all its diradd dependencies. - * Called with splbio blocked. */ static int flush_pagedep_deps(pvp, mp, diraddhdp) diff --git a/sys/vm/device_pager.c b/sys/vm/device_pager.c index c27d60869deff..7dce4778f9513 100644 --- a/sys/vm/device_pager.c +++ b/sys/vm/device_pager.c @@ -236,7 +236,7 @@ cdev_pager_free_page(vm_object_t object, vm_page_t m) KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("unmanaged %p", m)); pmap_remove_all(m); vm_page_lock(m); - vm_page_remove(m); + (void)vm_page_remove(m); vm_page_unlock(m); } else if (object->type == OBJT_DEVICE) dev_pager_free_page(object, m); diff --git a/sys/vm/vm_fault.c b/sys/vm/vm_fault.c index 4268db264d52b..ae0103595ae7d 100644 --- a/sys/vm/vm_fault.c +++ b/sys/vm/vm_fault.c @@ -1144,7 +1144,7 @@ readrest: fs.object == fs.first_object->backing_object) { vm_page_lock(fs.m); vm_page_dequeue(fs.m); - vm_page_remove(fs.m); + (void)vm_page_remove(fs.m); vm_page_unlock(fs.m); vm_page_lock(fs.first_m); vm_page_replace_checked(fs.m, fs.first_object, diff --git a/sys/vm/vm_map.c b/sys/vm/vm_map.c index 9120317020700..38afe6308cc83 100644 --- a/sys/vm/vm_map.c +++ b/sys/vm/vm_map.c @@ -2472,11 +2472,8 @@ again: VM_MAP_RANGE_CHECK(map, start, end); - if (vm_map_lookup_entry(map, start, &entry)) { - vm_map_clip_start(map, entry, start); - } else { + if (!vm_map_lookup_entry(map, start, &entry)) entry = entry->next; - } /* * Make a first pass to check for protection violations. @@ -2515,6 +2512,7 @@ again: * now will do cow due to allowed write (e.g. debugger sets * breakpoint on text segment) */ + vm_map_clip_start(map, entry, start); for (current = entry; current->start < end; current = current->next) { vm_map_clip_end(map, current, end); diff --git a/sys/vm/vm_mmap.c b/sys/vm/vm_mmap.c index cd483527af712..24864889060ca 100644 --- a/sys/vm/vm_mmap.c +++ b/sys/vm/vm_mmap.c @@ -103,6 +103,9 @@ SYSCTL_INT(_vm, OID_AUTO, old_mlock, CTLFLAG_RWTUN, &old_mlock, 0, static int mincore_mapped = 1; SYSCTL_INT(_vm, OID_AUTO, mincore_mapped, CTLFLAG_RWTUN, &mincore_mapped, 0, "mincore reports mappings, not residency"); +static int imply_prot_max = 0; +SYSCTL_INT(_vm, OID_AUTO, imply_prot_max, CTLFLAG_RWTUN, &imply_prot_max, 0, + "Imply maximum page permissions in mmap() when none are specified"); #ifdef MAP_32BIT #define MAP_32BIT_MAX_ADDR ((vm_offset_t)1 << 31) @@ -187,9 +190,25 @@ kern_mmap(struct thread *td, uintptr_t addr0, size_t len, int prot, int flags, vm_offset_t addr; vm_size_t pageoff, size; vm_prot_t cap_maxprot; - int align, error; + int align, error, max_prot; cap_rights_t rights; + if ((prot & ~(_PROT_ALL | PROT_MAX(_PROT_ALL))) != 0) + return (EINVAL); + max_prot = PROT_MAX_EXTRACT(prot); + prot = PROT_EXTRACT(prot); + if (max_prot != 0 && (max_prot & prot) != prot) + return (EINVAL); + /* + * Always honor PROT_MAX if set. If not, default to all + * permissions unless we're implying maximum permissions. + * + * XXX: should be tunable per process and ABI. + */ + if (max_prot == 0) + max_prot = (imply_prot_max && prot != PROT_NONE) ? + prot : _PROT_ALL; + vms = td->td_proc->p_vmspace; fp = NULL; AUDIT_ARG_FD(fd); @@ -335,7 +354,7 @@ kern_mmap(struct thread *td, uintptr_t addr0, size_t len, int prot, int flags, * This relies on VM_PROT_* matching PROT_*. */ error = vm_mmap_object(&vms->vm_map, &addr, size, prot, - VM_PROT_ALL, flags, NULL, pos, FALSE, td); + max_prot, flags, NULL, pos, FALSE, td); } else { /* * Mapping file, get fp for validation and don't let the @@ -363,7 +382,7 @@ kern_mmap(struct thread *td, uintptr_t addr0, size_t len, int prot, int flags, /* This relies on VM_PROT_* matching PROT_*. */ error = fo_mmap(fp, &vms->vm_map, &addr, size, prot, - cap_maxprot, flags, pos, td); + max_prot & cap_maxprot, flags, pos, td); } if (error == 0) @@ -594,9 +613,13 @@ kern_mprotect(struct thread *td, uintptr_t addr0, size_t size, int prot) { vm_offset_t addr; vm_size_t pageoff; + int vm_error, max_prot; addr = addr0; - prot = (prot & VM_PROT_ALL); + if ((prot & ~(_PROT_ALL | PROT_MAX(_PROT_ALL))) != 0) + return (EINVAL); + max_prot = PROT_MAX_EXTRACT(prot); + prot = PROT_EXTRACT(prot); pageoff = (addr & PAGE_MASK); addr -= pageoff; size += pageoff; @@ -610,8 +633,18 @@ kern_mprotect(struct thread *td, uintptr_t addr0, size_t size, int prot) if (addr + size < addr) return (EINVAL); - switch (vm_map_protect(&td->td_proc->p_vmspace->vm_map, addr, - addr + size, prot, FALSE)) { + vm_error = KERN_SUCCESS; + if (max_prot != 0) { + if ((max_prot & prot) != prot) + return (EINVAL); + vm_error = vm_map_protect(&td->td_proc->p_vmspace->vm_map, + addr, addr + size, max_prot, TRUE); + } + if (vm_error == KERN_SUCCESS) + vm_error = vm_map_protect(&td->td_proc->p_vmspace->vm_map, + addr, addr + size, prot, FALSE); + + switch (vm_error) { case KERN_SUCCESS: return (0); case KERN_PROTECTION_FAILURE: diff --git a/sys/vm/vm_object.c b/sys/vm/vm_object.c index 9fd90f04b6d97..7c3575e646cf8 100644 --- a/sys/vm/vm_object.c +++ b/sys/vm/vm_object.c @@ -1595,10 +1595,8 @@ vm_object_collapse_scan(vm_object_t object, int op) vm_page_lock(p); KASSERT(!pmap_page_is_mapped(p), ("freeing mapped page %p", p)); - if (!vm_page_wired(p)) + if (vm_page_remove(p)) vm_page_free(p); - else - vm_page_remove(p); vm_page_unlock(p); continue; } @@ -1639,10 +1637,8 @@ vm_object_collapse_scan(vm_object_t object, int op) vm_page_lock(p); KASSERT(!pmap_page_is_mapped(p), ("freeing mapped page %p", p)); - if (!vm_page_wired(p)) + if (vm_page_remove(p)) vm_page_free(p); - else - vm_page_remove(p); vm_page_unlock(p); continue; } diff --git a/sys/vm/vm_page.c b/sys/vm/vm_page.c index a90961ce57b55..e43817b812a0e 100644 --- a/sys/vm/vm_page.c +++ b/sys/vm/vm_page.c @@ -1458,20 +1458,21 @@ vm_page_insert_radixdone(vm_page_t m, vm_object_t object, vm_page_t mpred) * vm_page_remove: * * Removes the specified page from its containing object, but does not - * invalidate any backing storage. + * invalidate any backing storage. Return true if the page may be safely + * freed and false otherwise. * * The object must be locked. The page must be locked if it is managed. */ -void +bool vm_page_remove(vm_page_t m) { vm_object_t object; vm_page_t mrem; + object = m->object; + if ((m->oflags & VPO_UNMANAGED) == 0) vm_page_assert_locked(m); - if ((object = m->object) == NULL) - return; VM_OBJECT_ASSERT_WLOCKED(object); if (vm_page_xbusied(m)) vm_page_xunbusy_maybelocked(m); @@ -1495,6 +1496,7 @@ vm_page_remove(vm_page_t m) vdrop(object->handle); m->object = NULL; + return (!vm_page_wired(m)); } /* @@ -1665,7 +1667,7 @@ vm_page_rename(vm_page_t m, vm_object_t new_object, vm_pindex_t new_pindex) */ m->pindex = opidx; vm_page_lock(m); - vm_page_remove(m); + (void)vm_page_remove(m); /* Return back to the new pindex to complete vm_page_insert(). */ m->pindex = new_pindex; @@ -3436,7 +3438,8 @@ vm_page_free_prep(vm_page_t m) if (vm_page_sbusied(m)) panic("vm_page_free_prep: freeing busy page %p", m); - vm_page_remove(m); + if (m->object != NULL) + (void)vm_page_remove(m); /* * If fictitious remove object association and diff --git a/sys/vm/vm_page.h b/sys/vm/vm_page.h index d1938d2a1bd88..57f9f6e9081ce 100644 --- a/sys/vm/vm_page.h +++ b/sys/vm/vm_page.h @@ -561,7 +561,7 @@ bool vm_page_reclaim_contig(int req, u_long npages, vm_paddr_t low, bool vm_page_reclaim_contig_domain(int domain, int req, u_long npages, vm_paddr_t low, vm_paddr_t high, u_long alignment, vm_paddr_t boundary); void vm_page_reference(vm_page_t m); -void vm_page_remove (vm_page_t); +bool vm_page_remove(vm_page_t); int vm_page_rename (vm_page_t, vm_object_t, vm_pindex_t); vm_page_t vm_page_replace(vm_page_t mnew, vm_object_t object, vm_pindex_t pindex); |
