2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (C) 2009-2012 Semihalf
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
32 #include <sys/param.h>
33 #include <sys/types.h>
34 #include <sys/systm.h>
35 #include <sys/malloc.h>
36 #include <sys/queue.h>
37 #include <sys/fcntl.h>
39 #include <sys/namei.h>
41 #include <sys/vnode.h>
42 #include <sys/mount.h>
44 #include <dev/nand/nandsim_chip.h>
45 #include <dev/nand/nandsim_swap.h>
47 static int init_block_state(struct chip_swap *);
48 static void destroy_block_state(struct chip_swap *);
50 static int create_buffers(struct chip_swap *);
51 static void destroy_buffers(struct chip_swap *);
53 static int swap_file_open(struct chip_swap *, const char *);
54 static void swap_file_close(struct chip_swap *);
55 static int swap_file_write(struct chip_swap *, struct block_state *);
56 static int swap_file_read(struct chip_swap *, struct block_state *);
58 #define CHIP_SWAP_CMODE 0600
59 #define CHIP_SWAP_BLOCKSPACES 2
62 init_block_state(struct chip_swap *swap)
64 struct block_state *blk_state;
70 blk_state = malloc(swap->nof_blks * sizeof(struct block_state),
71 M_NANDSIM, M_WAITOK | M_ZERO);
73 for (i = 0; i < swap->nof_blks; i++)
74 blk_state[i].offset = 0xffffffff;
76 swap->blk_state = blk_state;
82 destroy_block_state(struct chip_swap *swap)
88 if (swap->blk_state != NULL)
89 free(swap->blk_state, M_NANDSIM);
93 create_buffers(struct chip_swap *swap)
95 struct block_space *block_space;
99 for (i = 0; i < CHIP_SWAP_BLOCKSPACES; i++) {
100 block_space = malloc(sizeof(*block_space), M_NANDSIM, M_WAITOK);
101 block = malloc(swap->blk_size, M_NANDSIM, M_WAITOK);
102 block_space->blk_ptr = block;
103 SLIST_INSERT_HEAD(&swap->free_bs, block_space, free_link);
104 nand_debug(NDBG_SIM,"created blk_space %p[%p]\n", block_space,
115 destroy_buffers(struct chip_swap *swap)
117 struct block_space *blk_space;
122 blk_space = SLIST_FIRST(&swap->free_bs);
124 SLIST_REMOVE_HEAD(&swap->free_bs, free_link);
125 nand_debug(NDBG_SIM,"destroyed blk_space %p[%p]\n",
126 blk_space, blk_space->blk_ptr);
127 free(blk_space->blk_ptr, M_NANDSIM);
128 free(blk_space, M_NANDSIM);
129 blk_space = SLIST_FIRST(&swap->free_bs);
132 blk_space = STAILQ_FIRST(&swap->used_bs);
134 STAILQ_REMOVE_HEAD(&swap->used_bs, used_link);
135 nand_debug(NDBG_SIM,"destroyed blk_space %p[%p]\n",
136 blk_space, blk_space->blk_ptr);
137 free(blk_space->blk_ptr, M_NANDSIM);
138 free(blk_space, M_NANDSIM);
139 blk_space = STAILQ_FIRST(&swap->used_bs);
144 swap_file_open(struct chip_swap *swap, const char *swap_file)
149 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, swap_file,
152 flags = FWRITE | FREAD | O_NOFOLLOW | O_CREAT | O_TRUNC;
154 error = vn_open(&nd, &flags, CHIP_SWAP_CMODE, NULL);
156 nand_debug(NDBG_SIM,"Cannot create swap file %s", swap_file);
157 NDFREE(&nd, NDF_ONLY_PNBUF);
161 swap->swap_cred = crhold(curthread->td_ucred);
162 NDFREE(&nd, NDF_ONLY_PNBUF);
164 /* We just unlock so we hold a reference */
165 VOP_UNLOCK(nd.ni_vp, 0);
167 swap->swap_vp = nd.ni_vp;
173 swap_file_close(struct chip_swap *swap)
179 if (swap->swap_vp == NULL)
182 vn_close(swap->swap_vp, FWRITE, swap->swap_cred, curthread);
183 crfree(swap->swap_cred);
187 swap_file_write(struct chip_swap *swap, struct block_state *blk_state)
189 struct block_space *blk_space;
196 if (swap == NULL || blk_state == NULL)
199 blk_space = blk_state->blk_sp;
200 if (blk_state->offset == -1) {
201 blk_state->offset = swap->swap_offset;
202 swap->swap_offset += swap->blk_size;
205 nand_debug(NDBG_SIM,"saving %p[%p] at %x\n",
206 blk_space, blk_space->blk_ptr, blk_state->offset);
208 bzero(&aiov, sizeof(aiov));
209 bzero(&auio, sizeof(auio));
211 aiov.iov_base = blk_space->blk_ptr;
212 aiov.iov_len = swap->blk_size;
216 auio.uio_iov = &aiov;
217 auio.uio_offset = blk_state->offset;
218 auio.uio_segflg = UIO_SYSSPACE;
219 auio.uio_rw = UIO_WRITE;
221 auio.uio_resid = swap->blk_size;
224 vn_start_write(vp, &mp, V_WAIT);
225 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
226 VOP_WRITE(vp, &auio, IO_UNIT, swap->swap_cred);
228 vn_finished_write(mp);
234 swap_file_read(struct chip_swap *swap, struct block_state *blk_state)
236 struct block_space *blk_space;
242 if (swap == NULL || blk_state == NULL)
245 blk_space = blk_state->blk_sp;
247 nand_debug(NDBG_SIM,"restore %p[%p] at %x\n",
248 blk_space, blk_space->blk_ptr, blk_state->offset);
250 bzero(&aiov, sizeof(aiov));
251 bzero(&auio, sizeof(auio));
253 aiov.iov_base = blk_space->blk_ptr;
254 aiov.iov_len = swap->blk_size;
258 auio.uio_iov = &aiov;
259 auio.uio_offset = blk_state->offset;
260 auio.uio_segflg = UIO_SYSSPACE;
261 auio.uio_rw = UIO_READ;
263 auio.uio_resid = swap->blk_size;
266 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
267 VOP_READ(vp, &auio, 0, swap->swap_cred);
274 nandsim_swap_init(const char *swap_file, uint32_t nof_blks, uint32_t blk_size)
276 struct chip_swap *swap;
279 if ((swap_file == NULL) || (nof_blks == 0) || (blk_size == 0))
282 swap = malloc(sizeof(*swap), M_NANDSIM, M_WAITOK | M_ZERO);
284 SLIST_INIT(&swap->free_bs);
285 STAILQ_INIT(&swap->used_bs);
286 swap->blk_size = blk_size;
287 swap->nof_blks = nof_blks;
289 err = init_block_state(swap);
291 nandsim_swap_destroy(swap);
295 err = create_buffers(swap);
297 nandsim_swap_destroy(swap);
301 err = swap_file_open(swap, swap_file);
303 nandsim_swap_destroy(swap);
311 nandsim_swap_destroy(struct chip_swap *swap)
317 destroy_block_state(swap);
318 destroy_buffers(swap);
319 swap_file_close(swap);
320 free(swap, M_NANDSIM);
324 get_bs(struct chip_swap *swap, uint32_t block, uint8_t writing)
326 struct block_state *blk_state, *old_blk_state = NULL;
327 struct block_space *blk_space;
329 if (swap == NULL || (block >= swap->nof_blks))
332 blk_state = &swap->blk_state[block];
333 nand_debug(NDBG_SIM,"blk_state %x\n", blk_state->status);
335 if (blk_state->status & BLOCK_ALLOCATED) {
336 blk_space = blk_state->blk_sp;
338 blk_space = SLIST_FIRST(&swap->free_bs);
340 SLIST_REMOVE_HEAD(&swap->free_bs, free_link);
341 STAILQ_INSERT_TAIL(&swap->used_bs, blk_space,
344 blk_space = STAILQ_FIRST(&swap->used_bs);
345 old_blk_state = blk_space->blk_state;
346 STAILQ_REMOVE_HEAD(&swap->used_bs, used_link);
347 STAILQ_INSERT_TAIL(&swap->used_bs, blk_space,
349 if (old_blk_state->status & BLOCK_DIRTY) {
350 swap_file_write(swap, old_blk_state);
351 old_blk_state->status &= ~BLOCK_DIRTY;
352 old_blk_state->status |= BLOCK_SWAPPED;
357 if (blk_space == NULL)
360 if (old_blk_state != NULL) {
361 old_blk_state->status &= ~BLOCK_ALLOCATED;
362 old_blk_state->blk_sp = NULL;
365 blk_state->blk_sp = blk_space;
366 blk_space->blk_state = blk_state;
368 if (!(blk_state->status & BLOCK_ALLOCATED)) {
369 if (blk_state->status & BLOCK_SWAPPED)
370 swap_file_read(swap, blk_state);
372 memset(blk_space->blk_ptr, 0xff, swap->blk_size);
373 blk_state->status |= BLOCK_ALLOCATED;
377 blk_state->status |= BLOCK_DIRTY;
379 nand_debug(NDBG_SIM,"get_bs returned %p[%p] state %x\n", blk_space,
380 blk_space->blk_ptr, blk_state->status);