2 * Copyright (C) 2009-2012 Semihalf
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/param.h>
31 #include <sys/types.h>
32 #include <sys/systm.h>
33 #include <sys/malloc.h>
34 #include <sys/queue.h>
35 #include <sys/fcntl.h>
37 #include <sys/namei.h>
39 #include <sys/vnode.h>
40 #include <sys/mount.h>
42 #include <dev/nand/nandsim_chip.h>
43 #include <dev/nand/nandsim_swap.h>
45 static int init_block_state(struct chip_swap *);
46 static void destroy_block_state(struct chip_swap *);
48 static int create_buffers(struct chip_swap *);
49 static void destroy_buffers(struct chip_swap *);
51 static int swap_file_open(struct chip_swap *, const char *);
52 static void swap_file_close(struct chip_swap *);
53 static int swap_file_write(struct chip_swap *, struct block_state *);
54 static int swap_file_read(struct chip_swap *, struct block_state *);
56 #define CHIP_SWAP_CMODE 0600
57 #define CHIP_SWAP_BLOCKSPACES 2
60 init_block_state(struct chip_swap *swap)
62 struct block_state *blk_state;
68 blk_state = malloc(swap->nof_blks * sizeof(struct block_state),
69 M_NANDSIM, M_WAITOK | M_ZERO);
71 for (i = 0; i < swap->nof_blks; i++)
72 blk_state[i].offset = 0xffffffff;
74 swap->blk_state = blk_state;
80 destroy_block_state(struct chip_swap *swap)
86 if (swap->blk_state != NULL)
87 free(swap->blk_state, M_NANDSIM);
91 create_buffers(struct chip_swap *swap)
93 struct block_space *block_space;
97 for (i = 0; i < CHIP_SWAP_BLOCKSPACES; i++) {
98 block_space = malloc(sizeof(*block_space), M_NANDSIM, M_WAITOK);
99 block = malloc(swap->blk_size, M_NANDSIM, M_WAITOK);
100 block_space->blk_ptr = block;
101 SLIST_INSERT_HEAD(&swap->free_bs, block_space, free_link);
102 nand_debug(NDBG_SIM,"created blk_space %p[%p]\n", block_space,
113 destroy_buffers(struct chip_swap *swap)
115 struct block_space *blk_space;
120 blk_space = SLIST_FIRST(&swap->free_bs);
122 SLIST_REMOVE_HEAD(&swap->free_bs, free_link);
123 nand_debug(NDBG_SIM,"destroyed blk_space %p[%p]\n",
124 blk_space, blk_space->blk_ptr);
125 free(blk_space->blk_ptr, M_NANDSIM);
126 free(blk_space, M_NANDSIM);
127 blk_space = SLIST_FIRST(&swap->free_bs);
130 blk_space = STAILQ_FIRST(&swap->used_bs);
132 STAILQ_REMOVE_HEAD(&swap->used_bs, used_link);
133 nand_debug(NDBG_SIM,"destroyed blk_space %p[%p]\n",
134 blk_space, blk_space->blk_ptr);
135 free(blk_space->blk_ptr, M_NANDSIM);
136 free(blk_space, M_NANDSIM);
137 blk_space = STAILQ_FIRST(&swap->used_bs);
142 swap_file_open(struct chip_swap *swap, const char *swap_file)
147 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, swap_file,
150 flags = FWRITE | FREAD | O_NOFOLLOW | O_CREAT | O_TRUNC;
152 error = vn_open(&nd, &flags, CHIP_SWAP_CMODE, NULL);
154 nand_debug(NDBG_SIM,"Cannot create swap file %s", swap_file);
155 NDFREE(&nd, NDF_ONLY_PNBUF);
159 swap->swap_cred = crhold(curthread->td_ucred);
160 NDFREE(&nd, NDF_ONLY_PNBUF);
162 /* We just unlock so we hold a reference */
163 VOP_UNLOCK(nd.ni_vp, 0);
165 swap->swap_vp = nd.ni_vp;
171 swap_file_close(struct chip_swap *swap)
177 if (swap->swap_vp == NULL)
180 vn_close(swap->swap_vp, FWRITE, swap->swap_cred, curthread);
181 crfree(swap->swap_cred);
185 swap_file_write(struct chip_swap *swap, struct block_state *blk_state)
187 struct block_space *blk_space;
194 if (swap == NULL || blk_state == NULL)
197 blk_space = blk_state->blk_sp;
198 if (blk_state->offset == -1) {
199 blk_state->offset = swap->swap_offset;
200 swap->swap_offset += swap->blk_size;
203 nand_debug(NDBG_SIM,"saving %p[%p] at %x\n",
204 blk_space, blk_space->blk_ptr, blk_state->offset);
206 bzero(&aiov, sizeof(aiov));
207 bzero(&auio, sizeof(auio));
209 aiov.iov_base = blk_space->blk_ptr;
210 aiov.iov_len = swap->blk_size;
214 auio.uio_iov = &aiov;
215 auio.uio_offset = blk_state->offset;
216 auio.uio_segflg = UIO_SYSSPACE;
217 auio.uio_rw = UIO_WRITE;
219 auio.uio_resid = swap->blk_size;
222 vn_start_write(vp, &mp, V_WAIT);
223 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
224 VOP_WRITE(vp, &auio, IO_UNIT, swap->swap_cred);
226 vn_finished_write(mp);
232 swap_file_read(struct chip_swap *swap, struct block_state *blk_state)
234 struct block_space *blk_space;
240 if (swap == NULL || blk_state == NULL)
243 blk_space = blk_state->blk_sp;
245 nand_debug(NDBG_SIM,"restore %p[%p] at %x\n",
246 blk_space, blk_space->blk_ptr, blk_state->offset);
248 bzero(&aiov, sizeof(aiov));
249 bzero(&auio, sizeof(auio));
251 aiov.iov_base = blk_space->blk_ptr;
252 aiov.iov_len = swap->blk_size;
256 auio.uio_iov = &aiov;
257 auio.uio_offset = blk_state->offset;
258 auio.uio_segflg = UIO_SYSSPACE;
259 auio.uio_rw = UIO_READ;
261 auio.uio_resid = swap->blk_size;
264 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
265 VOP_READ(vp, &auio, 0, swap->swap_cred);
272 nandsim_swap_init(const char *swap_file, uint32_t nof_blks, uint32_t blk_size)
274 struct chip_swap *swap;
277 if ((swap_file == NULL) || (nof_blks == 0) || (blk_size == 0))
280 swap = malloc(sizeof(*swap), M_NANDSIM, M_WAITOK | M_ZERO);
282 SLIST_INIT(&swap->free_bs);
283 STAILQ_INIT(&swap->used_bs);
284 swap->blk_size = blk_size;
285 swap->nof_blks = nof_blks;
287 err = init_block_state(swap);
289 nandsim_swap_destroy(swap);
293 err = create_buffers(swap);
295 nandsim_swap_destroy(swap);
299 err = swap_file_open(swap, swap_file);
301 nandsim_swap_destroy(swap);
309 nandsim_swap_destroy(struct chip_swap *swap)
315 destroy_block_state(swap);
316 destroy_buffers(swap);
317 swap_file_close(swap);
318 free(swap, M_NANDSIM);
322 get_bs(struct chip_swap *swap, uint32_t block, uint8_t writing)
324 struct block_state *blk_state, *old_blk_state = NULL;
325 struct block_space *blk_space;
327 if (swap == NULL || (block >= swap->nof_blks))
330 blk_state = &swap->blk_state[block];
331 nand_debug(NDBG_SIM,"blk_state %x\n", blk_state->status);
333 if (blk_state->status & BLOCK_ALLOCATED) {
334 blk_space = blk_state->blk_sp;
336 blk_space = SLIST_FIRST(&swap->free_bs);
338 SLIST_REMOVE_HEAD(&swap->free_bs, free_link);
339 STAILQ_INSERT_TAIL(&swap->used_bs, blk_space,
342 blk_space = STAILQ_FIRST(&swap->used_bs);
343 old_blk_state = blk_space->blk_state;
344 STAILQ_REMOVE_HEAD(&swap->used_bs, used_link);
345 STAILQ_INSERT_TAIL(&swap->used_bs, blk_space,
347 if (old_blk_state->status & BLOCK_DIRTY) {
348 swap_file_write(swap, old_blk_state);
349 old_blk_state->status &= ~BLOCK_DIRTY;
350 old_blk_state->status |= BLOCK_SWAPPED;
355 if (blk_space == NULL)
358 if (old_blk_state != NULL) {
359 old_blk_state->status &= ~BLOCK_ALLOCATED;
360 old_blk_state->blk_sp = NULL;
363 blk_state->blk_sp = blk_space;
364 blk_space->blk_state = blk_state;
366 if (!(blk_state->status & BLOCK_ALLOCATED)) {
367 if (blk_state->status & BLOCK_SWAPPED)
368 swap_file_read(swap, blk_state);
370 memset(blk_space->blk_ptr, 0xff, swap->blk_size);
371 blk_state->status |= BLOCK_ALLOCATED;
375 blk_state->status |= BLOCK_DIRTY;
377 nand_debug(NDBG_SIM,"get_bs returned %p[%p] state %x\n", blk_space,
378 blk_space->blk_ptr, blk_state->status);