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