xref: /freebsd-12.1/sys/dev/nand/nandsim.c (revision f8db2270)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (C) 2009-2012 Semihalf
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
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.
15  *
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
26  * SUCH DAMAGE.
27  */
28 
29 /* Simulated NAND controller driver */
30 
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33 
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/proc.h>
37 #include <sys/bus.h>
38 #include <sys/conf.h>
39 #include <sys/kernel.h>
40 #include <sys/module.h>
41 #include <sys/malloc.h>
42 
43 #include <dev/nand/nand.h>
44 #include <dev/nand/nandsim.h>
45 #include <dev/nand/nandsim_chip.h>
46 #include <dev/nand/nandsim_log.h>
47 #include <dev/nand/nandsim_swap.h>
48 
49 struct sim_param sim;
50 struct sim_ctrl_conf ctrls[MAX_SIM_DEV];
51 
52 static struct cdev *nandsim_dev;
53 static d_ioctl_t nandsim_ioctl;
54 
55 static void nandsim_init_sim_param(struct sim_param *);
56 static int nandsim_create_ctrl(struct sim_ctrl *);
57 static int nandsim_destroy_ctrl(int);
58 static int nandsim_ctrl_status(struct sim_ctrl *);
59 static int nandsim_create_chip(struct sim_chip *);
60 static int nandsim_destroy_chip(struct sim_ctrl_chip *);
61 static int nandsim_chip_status(struct sim_chip *);
62 static int nandsim_start_ctrl(int);
63 static int nandsim_stop_ctrl(int);
64 static int nandsim_inject_error(struct sim_error *);
65 static int nandsim_get_block_state(struct sim_block_state *);
66 static int nandsim_set_block_state(struct sim_block_state *);
67 static int nandsim_modify(struct sim_mod *);
68 static int nandsim_dump(struct sim_dump *);
69 static int nandsim_restore(struct sim_dump *);
70 static int nandsim_freeze(struct sim_ctrl_chip *);
71 static void nandsim_print_log(struct sim_log *);
72 static struct nandsim_chip *get_nandsim_chip(uint8_t, uint8_t);
73 
74 static struct cdevsw nandsim_cdevsw = {
75 	.d_version =    D_VERSION,
76 	.d_flags =	D_NEEDGIANT,
77 	.d_ioctl =      nandsim_ioctl,
78 	.d_name =       "nandsim",
79 };
80 
81 int
nandsim_ioctl(struct cdev * dev,u_long cmd,caddr_t data,int flags,struct thread * td)82 nandsim_ioctl(struct cdev *dev, u_long cmd, caddr_t data,
83     int flags, struct thread *td)
84 {
85 	int ret = 0;
86 
87 	switch (cmd) {
88 	case NANDSIM_SIM_PARAM:
89 		nandsim_init_sim_param((struct sim_param *)data);
90 		break;
91 	case NANDSIM_CREATE_CTRL:
92 		ret = nandsim_create_ctrl((struct sim_ctrl *)data);
93 		break;
94 	case NANDSIM_DESTROY_CTRL:
95 		ret = nandsim_destroy_ctrl(*(int *)data);
96 		break;
97 	case NANDSIM_STATUS_CTRL:
98 		ret = nandsim_ctrl_status((struct sim_ctrl *)data);
99 		break;
100 	case NANDSIM_CREATE_CHIP:
101 		ret = nandsim_create_chip((struct sim_chip *)data);
102 		break;
103 	case NANDSIM_DESTROY_CHIP:
104 		ret = nandsim_destroy_chip((struct sim_ctrl_chip *)data);
105 		break;
106 	case NANDSIM_STATUS_CHIP:
107 		ret = nandsim_chip_status((struct sim_chip *)data);
108 		break;
109 	case NANDSIM_MODIFY:
110 		ret = nandsim_modify((struct sim_mod *)data);
111 		break;
112 	case NANDSIM_START_CTRL:
113 		ret = nandsim_start_ctrl(*(int *)data);
114 		break;
115 	case NANDSIM_STOP_CTRL:
116 		ret = nandsim_stop_ctrl(*(int *)data);
117 		break;
118 	case NANDSIM_INJECT_ERROR:
119 		ret = nandsim_inject_error((struct sim_error *)data);
120 		break;
121 	case NANDSIM_SET_BLOCK_STATE:
122 		ret = nandsim_set_block_state((struct sim_block_state *)data);
123 		break;
124 	case NANDSIM_GET_BLOCK_STATE:
125 		ret = nandsim_get_block_state((struct sim_block_state *)data);
126 		break;
127 	case NANDSIM_PRINT_LOG:
128 		nandsim_print_log((struct sim_log *)data);
129 		break;
130 	case NANDSIM_DUMP:
131 		ret = nandsim_dump((struct sim_dump *)data);
132 		break;
133 	case NANDSIM_RESTORE:
134 		ret = nandsim_restore((struct sim_dump *)data);
135 		break;
136 	case NANDSIM_FREEZE:
137 		ret = nandsim_freeze((struct sim_ctrl_chip *)data);
138 		break;
139 	default:
140 		ret = EINVAL;
141 		break;
142 	}
143 
144 	return (ret);
145 }
146 
147 static void
nandsim_init_sim_param(struct sim_param * param)148 nandsim_init_sim_param(struct sim_param *param)
149 {
150 
151 	if (!param)
152 		return;
153 
154 	nand_debug(NDBG_SIM,"log level:%d output %d", param->log_level,
155 	    param->log_output);
156 	nandsim_log_level = param->log_level;
157 	nandsim_log_output = param->log_output;
158 }
159 
160 static int
nandsim_create_ctrl(struct sim_ctrl * ctrl)161 nandsim_create_ctrl(struct sim_ctrl *ctrl)
162 {
163 	struct sim_ctrl_conf *sim_ctrl;
164 
165 	nand_debug(NDBG_SIM,"create controller num:%d cs:%d",ctrl->num,
166 	    ctrl->num_cs);
167 
168 	if (ctrl->num >= MAX_SIM_DEV) {
169 		return (EINVAL);
170 	}
171 
172 	sim_ctrl = &ctrls[ctrl->num];
173 	if(sim_ctrl->created)
174 		return (EEXIST);
175 
176 	sim_ctrl->num = ctrl->num;
177 	sim_ctrl->num_cs = ctrl->num_cs;
178 	sim_ctrl->ecc = ctrl->ecc;
179 	memcpy(sim_ctrl->ecc_layout, ctrl->ecc_layout,
180 	    MAX_ECC_BYTES * sizeof(ctrl->ecc_layout[0]));
181 	strlcpy(sim_ctrl->filename, ctrl->filename,
182 	    FILENAME_SIZE);
183 	sim_ctrl->created = 1;
184 
185 	return (0);
186 }
187 
188 static int
nandsim_destroy_ctrl(int ctrl_num)189 nandsim_destroy_ctrl(int ctrl_num)
190 {
191 
192 	nand_debug(NDBG_SIM,"destroy controller num:%d", ctrl_num);
193 
194 	if (ctrl_num >= MAX_SIM_DEV) {
195 		return (EINVAL);
196 	}
197 
198 	if (!ctrls[ctrl_num].created) {
199 		return (ENODEV);
200 	}
201 
202 	if (ctrls[ctrl_num].running) {
203 		return (EBUSY);
204 	}
205 
206 	memset(&ctrls[ctrl_num], 0, sizeof(ctrls[ctrl_num]));
207 
208 	return (0);
209 }
210 
211 static int
nandsim_ctrl_status(struct sim_ctrl * ctrl)212 nandsim_ctrl_status(struct sim_ctrl *ctrl)
213 {
214 
215 	nand_debug(NDBG_SIM,"status controller num:%d cs:%d",ctrl->num,
216 	    ctrl->num_cs);
217 
218 	if (ctrl->num >= MAX_SIM_DEV) {
219 		return (EINVAL);
220 	}
221 
222 	ctrl->num_cs = ctrls[ctrl->num].num_cs;
223 	ctrl->ecc = ctrls[ctrl->num].ecc;
224 	memcpy(ctrl->ecc_layout, ctrls[ctrl->num].ecc_layout,
225 	    MAX_ECC_BYTES * sizeof(ctrl->ecc_layout[0]));
226 	strlcpy(ctrl->filename, ctrls[ctrl->num].filename,
227 	    FILENAME_SIZE);
228 	ctrl->running = ctrls[ctrl->num].running;
229 	ctrl->created = ctrls[ctrl->num].created;
230 
231 	return (0);
232 }
233 
234 static int
nandsim_create_chip(struct sim_chip * chip)235 nandsim_create_chip(struct sim_chip *chip)
236 {
237 	struct sim_chip *sim_chip;
238 
239 	nand_debug(NDBG_SIM,"create chip num:%d at ctrl:%d", chip->num,
240 	    chip->ctrl_num);
241 
242 	if (chip->ctrl_num >= MAX_SIM_DEV ||
243 	    chip->num >= MAX_CTRL_CS) {
244 		return (EINVAL);
245 	}
246 
247 	if (ctrls[chip->ctrl_num].chips[chip->num]) {
248 		return (EEXIST);
249 	}
250 
251 	sim_chip = malloc(sizeof(*sim_chip), M_NANDSIM,
252 	    M_WAITOK);
253 	if (sim_chip == NULL) {
254 		return (ENOMEM);
255 	}
256 
257 	memcpy(sim_chip, chip, sizeof(*sim_chip));
258 	ctrls[chip->ctrl_num].chips[chip->num] = sim_chip;
259 	sim_chip->created = 1;
260 
261 	return (0);
262 }
263 
264 static int
nandsim_destroy_chip(struct sim_ctrl_chip * chip)265 nandsim_destroy_chip(struct sim_ctrl_chip *chip)
266 {
267 	struct sim_ctrl_conf *ctrl_conf;
268 
269 	nand_debug(NDBG_SIM,"destroy chip num:%d at ctrl:%d", chip->chip_num,
270 	    chip->ctrl_num);
271 
272 	if (chip->ctrl_num >= MAX_SIM_DEV ||
273 	    chip->chip_num >= MAX_CTRL_CS)
274 		return (EINVAL);
275 
276 	ctrl_conf = &ctrls[chip->ctrl_num];
277 
278 	if (!ctrl_conf->created || !ctrl_conf->chips[chip->chip_num])
279 		return (ENODEV);
280 
281 	if (ctrl_conf->running)
282 		return (EBUSY);
283 
284 	free(ctrl_conf->chips[chip->chip_num], M_NANDSIM);
285 	ctrl_conf->chips[chip->chip_num] = NULL;
286 
287 	return (0);
288 }
289 
290 static int
nandsim_chip_status(struct sim_chip * chip)291 nandsim_chip_status(struct sim_chip *chip)
292 {
293 	struct sim_ctrl_conf *ctrl_conf;
294 
295 	nand_debug(NDBG_SIM,"status for chip num:%d at ctrl:%d", chip->num,
296 	    chip->ctrl_num);
297 
298 	if (chip->ctrl_num >= MAX_SIM_DEV ||
299 	    chip->num >= MAX_CTRL_CS)
300 		return (EINVAL);
301 
302 	ctrl_conf = &ctrls[chip->ctrl_num];
303 	if (!ctrl_conf->chips[chip->num])
304 		chip->created = 0;
305 	else
306 		memcpy(chip, ctrl_conf->chips[chip->num], sizeof(*chip));
307 
308 	return (0);
309 }
310 
311 static int
nandsim_start_ctrl(int num)312 nandsim_start_ctrl(int num)
313 {
314 	device_t nexus, ndev;
315 	devclass_t nexus_devclass;
316 	int ret = 0;
317 
318 	nand_debug(NDBG_SIM,"start ctlr num:%d", num);
319 
320 	if (num >= MAX_SIM_DEV)
321 		return (EINVAL);
322 
323 	if (!ctrls[num].created)
324 		return (ENODEV);
325 
326 	if (ctrls[num].running)
327 		return (EBUSY);
328 
329 	/* We will add our device as a child of the nexus0 device */
330 	if (!(nexus_devclass = devclass_find("nexus")) ||
331 	    !(nexus = devclass_get_device(nexus_devclass, 0)))
332 		return (EFAULT);
333 
334 	/*
335 	 * Create a newbus device representing this frontend instance
336 	 *
337 	 * XXX powerpc nexus doesn't implement bus_add_child, so child
338 	 * must be added by device_add_child().
339 	 */
340 #if defined(__powerpc__)
341 	ndev = device_add_child(nexus, "nandsim", num);
342 #else
343 	ndev = BUS_ADD_CHILD(nexus, 0, "nandsim", num);
344 #endif
345 	if (!ndev)
346 		return (EFAULT);
347 
348 	mtx_lock(&Giant);
349 	ret = device_probe_and_attach(ndev);
350 	mtx_unlock(&Giant);
351 
352 	if (ret == 0) {
353 		ctrls[num].sim_ctrl_dev = ndev;
354 		ctrls[num].running = 1;
355 	}
356 
357 	return (ret);
358 }
359 
360 static int
nandsim_stop_ctrl(int num)361 nandsim_stop_ctrl(int num)
362 {
363 	device_t nexus;
364 	devclass_t nexus_devclass;
365 	int ret = 0;
366 
367 	nand_debug(NDBG_SIM,"stop controller num:%d", num);
368 
369 	if (num >= MAX_SIM_DEV) {
370 		return (EINVAL);
371 	}
372 
373 	if (!ctrls[num].created || !ctrls[num].running) {
374 		return (ENODEV);
375 	}
376 
377 	/* We will add our device as a child of the nexus0 device */
378 	if (!(nexus_devclass = devclass_find("nexus")) ||
379 	    !(nexus = devclass_get_device(nexus_devclass, 0))) {
380 		return (ENODEV);
381 	}
382 
383 	mtx_lock(&Giant);
384 	if (ctrls[num].sim_ctrl_dev) {
385 		ret = device_delete_child(nexus, ctrls[num].sim_ctrl_dev);
386 		ctrls[num].sim_ctrl_dev = NULL;
387 	}
388 	mtx_unlock(&Giant);
389 
390 	ctrls[num].running = 0;
391 
392 	return (ret);
393 }
394 
395 static struct nandsim_chip *
get_nandsim_chip(uint8_t ctrl_num,uint8_t chip_num)396 get_nandsim_chip(uint8_t ctrl_num, uint8_t chip_num)
397 {
398 	struct nandsim_softc *sc;
399 
400 	if (!ctrls[ctrl_num].sim_ctrl_dev)
401 		return (NULL);
402 
403 	sc = device_get_softc(ctrls[ctrl_num].sim_ctrl_dev);
404 	return (sc->chips[chip_num]);
405 }
406 
407 static void
nandsim_print_log(struct sim_log * sim_log)408 nandsim_print_log(struct sim_log *sim_log)
409 {
410 	struct nandsim_softc *sc;
411 	int len1, len2;
412 
413 	if (!ctrls[sim_log->ctrl_num].sim_ctrl_dev)
414 		return;
415 
416 	sc = device_get_softc(ctrls[sim_log->ctrl_num].sim_ctrl_dev);
417 	if (sc->log_buff) {
418 		len1 = strlen(&sc->log_buff[sc->log_idx + 1]);
419 		if (len1 >= sim_log->len)
420 			len1 = sim_log->len;
421 		copyout(&sc->log_buff[sc->log_idx + 1], sim_log->log, len1);
422 		len2 = strlen(sc->log_buff);
423 		if (len2 >= (sim_log->len - len1))
424 			len2 = (sim_log->len - len1);
425 		copyout(sc->log_buff, &sim_log->log[len1], len2);
426 		sim_log->len = len1 + len2;
427 	}
428 }
429 
430 static int
nandsim_inject_error(struct sim_error * error)431 nandsim_inject_error(struct sim_error *error)
432 {
433 	struct nandsim_chip *chip;
434 	struct block_space *bs;
435 	struct onfi_params *param;
436 	int page, page_size, block, offset;
437 
438 	nand_debug(NDBG_SIM,"inject error for chip %d at ctrl %d\n",
439 	    error->chip_num, error->ctrl_num);
440 
441 	if (error->ctrl_num >= MAX_SIM_DEV ||
442 	    error->chip_num >= MAX_CTRL_CS)
443 		return (EINVAL);
444 
445 	if (!ctrls[error->ctrl_num].created || !ctrls[error->ctrl_num].running)
446 		return (ENODEV);
447 
448 	chip = get_nandsim_chip(error->ctrl_num, error->chip_num);
449 	param = &chip->params;
450 	page_size = param->bytes_per_page + param->spare_bytes_per_page;
451 	block = error->page_num / param->pages_per_block;
452 	page = error->page_num % param->pages_per_block;
453 
454 	bs = get_bs(chip->swap, block, 1);
455 	if (!bs)
456 		return (EINVAL);
457 
458 	offset = (page * page_size) + error->column;
459 	memset(&bs->blk_ptr[offset], error->pattern, error->len);
460 
461 	return (0);
462 }
463 
464 static int
nandsim_set_block_state(struct sim_block_state * bs)465 nandsim_set_block_state(struct sim_block_state *bs)
466 {
467 	struct onfi_params *params;
468 	struct nandsim_chip *chip;
469 	int blocks;
470 
471 	nand_debug(NDBG_SIM,"set block state for %d:%d block %d\n",
472 	    bs->chip_num, bs->ctrl_num, bs->block_num);
473 
474 	if (bs->ctrl_num >= MAX_SIM_DEV ||
475 	    bs->chip_num >= MAX_CTRL_CS)
476 		return (EINVAL);
477 
478 	chip = get_nandsim_chip(bs->ctrl_num, bs->chip_num);
479 	params = &chip->params;
480 	blocks = params->luns * params->blocks_per_lun;
481 
482 	if (bs->block_num > blocks)
483 		return (EINVAL);
484 
485 	chip->blk_state[bs->block_num].is_bad = bs->state;
486 
487 	if (bs->wearout >= 0)
488 		chip->blk_state[bs->block_num].wear_lev = bs->wearout;
489 
490 	return (0);
491 }
492 
493 static int
nandsim_get_block_state(struct sim_block_state * bs)494 nandsim_get_block_state(struct sim_block_state *bs)
495 {
496 	struct onfi_params *params;
497 	struct nandsim_chip *chip;
498 	int blocks;
499 
500 	if (bs->ctrl_num >= MAX_SIM_DEV ||
501 	    bs->chip_num >= MAX_CTRL_CS)
502 		return (EINVAL);
503 
504 	nand_debug(NDBG_SIM,"get block state for %d:%d block %d\n",
505 	    bs->chip_num, bs->ctrl_num, bs->block_num);
506 
507 	chip = get_nandsim_chip(bs->ctrl_num, bs->chip_num);
508 	params = &chip->params;
509 	blocks = params->luns * params->blocks_per_lun;
510 
511 	if (bs->block_num > blocks)
512 		return (EINVAL);
513 
514 	bs->state = chip->blk_state[bs->block_num].is_bad;
515 	bs->wearout = chip->blk_state[bs->block_num].wear_lev;
516 
517 	return (0);
518 }
519 
520 static int
nandsim_dump(struct sim_dump * dump)521 nandsim_dump(struct sim_dump *dump)
522 {
523 	struct nandsim_chip *chip;
524 	struct block_space *bs;
525 	int blk_size;
526 
527 	nand_debug(NDBG_SIM,"dump chip %d %d\n", dump->ctrl_num, dump->chip_num);
528 
529 	if (dump->ctrl_num >= MAX_SIM_DEV ||
530 	    dump->chip_num >= MAX_CTRL_CS)
531 		return (EINVAL);
532 
533 	chip = get_nandsim_chip(dump->ctrl_num, dump->chip_num);
534 	blk_size = chip->cg.block_size +
535 	    (chip->cg.oob_size * chip->cg.pgs_per_blk);
536 
537 	bs = get_bs(chip->swap, dump->block_num, 0);
538 	if (!bs)
539 		return (EINVAL);
540 
541 	if (dump->len > blk_size)
542 		dump->len = blk_size;
543 
544 	copyout(bs->blk_ptr, dump->data, dump->len);
545 
546 	return (0);
547 }
548 
549 static int
nandsim_restore(struct sim_dump * dump)550 nandsim_restore(struct sim_dump *dump)
551 {
552 	struct nandsim_chip *chip;
553 	struct block_space *bs;
554 	int blk_size;
555 
556 	nand_debug(NDBG_SIM,"restore chip %d %d\n", dump->ctrl_num,
557 	    dump->chip_num);
558 
559 	if (dump->ctrl_num >= MAX_SIM_DEV ||
560 	    dump->chip_num >= MAX_CTRL_CS)
561 		return (EINVAL);
562 
563 	chip = get_nandsim_chip(dump->ctrl_num, dump->chip_num);
564 	blk_size = chip->cg.block_size +
565 	    (chip->cg.oob_size * chip->cg.pgs_per_blk);
566 
567 	bs = get_bs(chip->swap, dump->block_num, 1);
568 	if (!bs)
569 		return (EINVAL);
570 
571 	if (dump->len > blk_size)
572 		dump->len = blk_size;
573 
574 
575 	copyin(dump->data, bs->blk_ptr, dump->len);
576 
577 	return (0);
578 }
579 
580 static int
nandsim_freeze(struct sim_ctrl_chip * ctrl_chip)581 nandsim_freeze(struct sim_ctrl_chip *ctrl_chip)
582 {
583 	struct nandsim_chip *chip;
584 
585 	if (ctrl_chip->ctrl_num >= MAX_SIM_DEV ||
586 	    ctrl_chip->chip_num >= MAX_CTRL_CS)
587 		return (EINVAL);
588 
589 	chip = get_nandsim_chip(ctrl_chip->ctrl_num, ctrl_chip->chip_num);
590 	nandsim_chip_freeze(chip);
591 
592 	return (0);
593 }
594 
595 static int
nandsim_modify(struct sim_mod * mod)596 nandsim_modify(struct sim_mod *mod)
597 {
598 	struct sim_chip *sim_conf = NULL;
599 	struct nandsim_chip *sim_chip = NULL;
600 
601 	nand_debug(NDBG_SIM,"modify ctlr %d chip %d", mod->ctrl_num,
602 	    mod->chip_num);
603 
604 	if (mod->field != SIM_MOD_LOG_LEVEL) {
605 		if (mod->ctrl_num >= MAX_SIM_DEV ||
606 		    mod->chip_num >= MAX_CTRL_CS)
607 			return (EINVAL);
608 
609 		sim_conf = ctrls[mod->ctrl_num].chips[mod->chip_num];
610 		sim_chip = get_nandsim_chip(mod->ctrl_num, mod->chip_num);
611 	}
612 
613 	switch (mod->field) {
614 	case SIM_MOD_LOG_LEVEL:
615 		nandsim_log_level = mod->new_value;
616 		break;
617 	case SIM_MOD_ERASE_TIME:
618 		sim_conf->erase_time = sim_chip->erase_delay = mod->new_value;
619 		break;
620 	case SIM_MOD_PROG_TIME:
621 		sim_conf->prog_time = sim_chip->prog_delay = mod->new_value;
622 		break;
623 	case SIM_MOD_READ_TIME:
624 		sim_conf->read_time = sim_chip->read_delay = mod->new_value;
625 		break;
626 	case SIM_MOD_ERROR_RATIO:
627 		sim_conf->error_ratio = mod->new_value;
628 		sim_chip->error_ratio = mod->new_value;
629 		break;
630 	default:
631 		break;
632 	}
633 
634 	return (0);
635 }
636 static int
nandsim_modevent(module_t mod __unused,int type,void * data __unused)637 nandsim_modevent(module_t mod __unused, int type, void *data __unused)
638 {
639 	struct sim_ctrl_chip chip_ctrl;
640 	int i, j;
641 
642 	switch (type) {
643 	case MOD_LOAD:
644 		nandsim_dev = make_dev(&nandsim_cdevsw, 0,
645 		    UID_ROOT, GID_WHEEL, 0600, "nandsim.ioctl");
646 		break;
647 	case MOD_UNLOAD:
648 		for (i = 0; i < MAX_SIM_DEV; i++) {
649 			nandsim_stop_ctrl(i);
650 			chip_ctrl.ctrl_num = i;
651 			for (j = 0; j < MAX_CTRL_CS; j++) {
652 				chip_ctrl.chip_num = j;
653 				nandsim_destroy_chip(&chip_ctrl);
654 			}
655 			nandsim_destroy_ctrl(i);
656 		}
657 		destroy_dev(nandsim_dev);
658 		break;
659 	case MOD_SHUTDOWN:
660 		break;
661 	default:
662 		return (EOPNOTSUPP);
663 	}
664 	return (0);
665 }
666 
667 DEV_MODULE(nandsim, nandsim_modevent, NULL);
668 MODULE_VERSION(nandsim, 1);
669 MODULE_DEPEND(nandsim, nand, 1, 1, 1);
670 MODULE_DEPEND(nandsim, alq, 1, 1, 1);
671