]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/nand/nandsim.c
Deprecate a number of less used 10 and 10/100 Ethernet devices.
[FreeBSD/FreeBSD.git] / sys / dev / nand / nandsim.c
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
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
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
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
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
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
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
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
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
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
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 *
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
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
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
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
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
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
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
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
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
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);