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