/*- * Copyright (C) 2009-2012 Semihalf * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include MALLOC_DEFINE(M_NANDSIM, "NANDsim", "NANDsim dynamic data"); #define NANDSIM_CHIP_LOCK(chip) mtx_lock(&(chip)->ns_lock) #define NANDSIM_CHIP_UNLOCK(chip) mtx_unlock(&(chip)->ns_lock) static nandsim_evh_t erase_evh; static nandsim_evh_t idle_evh; static nandsim_evh_t poweron_evh; static nandsim_evh_t reset_evh; static nandsim_evh_t read_evh; static nandsim_evh_t readid_evh; static nandsim_evh_t readparam_evh; static nandsim_evh_t write_evh; static void nandsim_loop(void *); static void nandsim_undefined(struct nandsim_chip *, uint8_t); static void nandsim_bad_address(struct nandsim_chip *, uint8_t *); static void nandsim_ignore_address(struct nandsim_chip *, uint8_t); static void nandsim_sm_error(struct nandsim_chip *); static void nandsim_start_handler(struct nandsim_chip *, nandsim_evh_t); static void nandsim_callout_eh(void *); static int nandsim_delay(struct nandsim_chip *, int); static int nandsim_bbm_init(struct nandsim_chip *, uint32_t, uint32_t *); static int nandsim_blk_state_init(struct nandsim_chip *, uint32_t, uint32_t); static void nandsim_blk_state_destroy(struct nandsim_chip *); static int nandchip_is_block_valid(struct nandsim_chip *, int); static void nandchip_set_status(struct nandsim_chip *, uint8_t); static void nandchip_clear_status(struct nandsim_chip *, uint8_t); struct proc *nandsim_proc; struct nandsim_chip * nandsim_chip_init(struct nandsim_softc* sc, uint8_t chip_num, struct sim_chip *sim_chip) { struct nandsim_chip *chip; struct onfi_params *chip_param; char swapfile[20]; uint32_t size; int error; chip = malloc(sizeof(*chip), M_NANDSIM, M_WAITOK | M_ZERO); if (!chip) return (NULL); mtx_init(&chip->ns_lock, "nandsim lock", NULL, MTX_DEF); callout_init(&chip->ns_callout, CALLOUT_MPSAFE); STAILQ_INIT(&chip->nandsim_events); chip->chip_num = chip_num; chip->ctrl_num = sim_chip->ctrl_num; chip->sc = sc; if (!sim_chip->is_wp) nandchip_set_status(chip, NAND_STATUS_WP); chip_param = &chip->params; chip->id.dev_id = sim_chip->device_id; chip->id.man_id = sim_chip->manufact_id; chip->error_ratio = sim_chip->error_ratio; chip->wear_level = sim_chip->wear_level; chip->prog_delay = sim_chip->prog_time; chip->erase_delay = sim_chip->erase_time; chip->read_delay = sim_chip->read_time; chip_param->t_prog = sim_chip->prog_time; chip_param->t_bers = sim_chip->erase_time; chip_param->t_r = sim_chip->read_time; bcopy("onfi", &chip_param->signature, 4); chip_param->manufacturer_id = sim_chip->manufact_id; strncpy(chip_param->manufacturer_name, sim_chip->manufacturer, 12); chip_param->manufacturer_name[11] = 0; strncpy(chip_param->device_model, sim_chip->device_model, 20); chip_param->device_model[19] = 0; chip_param->bytes_per_page = sim_chip->page_size; chip_param->spare_bytes_per_page = sim_chip->oob_size; chip_param->pages_per_block = sim_chip->pgs_per_blk; chip_param->blocks_per_lun = sim_chip->blks_per_lun; chip_param->luns = sim_chip->luns; init_chip_geom(&chip->cg, chip_param->luns, chip_param->blocks_per_lun, chip_param->pages_per_block, chip_param->bytes_per_page, chip_param->spare_bytes_per_page); chip_param->address_cycles = sim_chip->row_addr_cycles | (sim_chip->col_addr_cycles << 4); chip_param->features = sim_chip->features; if (sim_chip->width == 16) chip_param->features |= ONFI_FEAT_16BIT; size = chip_param->blocks_per_lun * chip_param->luns; error = nandsim_blk_state_init(chip, size, sim_chip->wear_level); if (error) { mtx_destroy(&chip->ns_lock); free(chip, M_NANDSIM); return (NULL); } error = nandsim_bbm_init(chip, size, sim_chip->bad_block_map); if (error) { mtx_destroy(&chip->ns_lock); nandsim_blk_state_destroy(chip); free(chip, M_NANDSIM); return (NULL); } nandsim_start_handler(chip, poweron_evh); nand_debug(NDBG_SIM,"Create thread for chip%d [%8p]", chip->chip_num, chip); /* Create chip thread */ error = kproc_kthread_add(nandsim_loop, chip, &nandsim_proc, &chip->nandsim_td, RFSTOPPED | RFHIGHPID, 0, "nandsim", "chip"); if (error) { mtx_destroy(&chip->ns_lock); nandsim_blk_state_destroy(chip); free(chip, M_NANDSIM); return (NULL); } thread_lock(chip->nandsim_td); sched_class(chip->nandsim_td, PRI_REALTIME); sched_add(chip->nandsim_td, SRQ_BORING); thread_unlock(chip->nandsim_td); size = (chip_param->bytes_per_page + chip_param->spare_bytes_per_page) * chip_param->pages_per_block; sprintf(swapfile, "chip%d%d.swp", chip->ctrl_num, chip->chip_num); chip->swap = nandsim_swap_init(swapfile, chip_param->blocks_per_lun * chip_param->luns, size); if (!chip->swap) nandsim_chip_destroy(chip); /* Wait for new thread to enter main loop */ tsleep(chip->nandsim_td, PWAIT, "ns_chip", 1 * hz); return (chip); } static int nandsim_blk_state_init(struct nandsim_chip *chip, uint32_t size, uint32_t wear_lev) { int i; if (!chip || size == 0) return (-1); chip->blk_state = malloc(size * sizeof(struct nandsim_block_state), M_NANDSIM, M_WAITOK | M_ZERO); if (!chip->blk_state) { return (-1); } for (i = 0; i < size; i++) { if (wear_lev) chip->blk_state[i].wear_lev = wear_lev; else chip->blk_state[i].wear_lev = -1; } return (0); } static void nandsim_blk_state_destroy(struct nandsim_chip *chip) { if (chip && chip->blk_state) free(chip->blk_state, M_NANDSIM); } static int nandsim_bbm_init(struct nandsim_chip *chip, uint32_t size, uint32_t *sim_bbm) { uint32_t index; int i; if ((chip == NULL) || (size == 0)) return (-1); if (chip->blk_state == NULL) return (-1); if (sim_bbm == NULL) return (0); for (i = 0; i < MAX_BAD_BLOCKS; i++) { index = sim_bbm[i]; if (index == 0xffffffff) break; else if (index > size) return (-1); else chip->blk_state[index].is_bad = 1; } return (0); } void nandsim_chip_destroy(struct nandsim_chip *chip) { struct nandsim_ev *ev; ev = create_event(chip, NANDSIM_EV_EXIT, 0); if (ev) send_event(ev); } void nandsim_chip_freeze(struct nandsim_chip *chip) { chip->flags |= NANDSIM_CHIP_FROZEN; } static void nandsim_loop(void *arg) { struct nandsim_chip *chip = (struct nandsim_chip *)arg; struct nandsim_ev *ev; nand_debug(NDBG_SIM,"Start main loop for chip%d [%8p]", chip->chip_num, chip); for(;;) { NANDSIM_CHIP_LOCK(chip); if (!(chip->flags & NANDSIM_CHIP_ACTIVE)) { chip->flags |= NANDSIM_CHIP_ACTIVE; wakeup(chip->nandsim_td); } if (STAILQ_EMPTY(&chip->nandsim_events)) { nand_debug(NDBG_SIM,"Chip%d [%8p] going sleep", chip->chip_num, chip); msleep(chip, &chip->ns_lock, PRIBIO, "nandev", 0); } ev = STAILQ_FIRST(&chip->nandsim_events); STAILQ_REMOVE_HEAD(&chip->nandsim_events, links); NANDSIM_CHIP_UNLOCK(chip); if (ev->type == NANDSIM_EV_EXIT) { NANDSIM_CHIP_LOCK(chip); destroy_event(ev); wakeup(ev); while (!STAILQ_EMPTY(&chip->nandsim_events)) { ev = STAILQ_FIRST(&chip->nandsim_events); STAILQ_REMOVE_HEAD(&chip->nandsim_events, links); destroy_event(ev); wakeup(ev); }; NANDSIM_CHIP_UNLOCK(chip); nandsim_log(chip, NANDSIM_LOG_SM, "destroyed\n"); mtx_destroy(&chip->ns_lock); nandsim_blk_state_destroy(chip); nandsim_swap_destroy(chip->swap); free(chip, M_NANDSIM); nandsim_proc = NULL; kthread_exit(); } if (!(chip->flags & NANDSIM_CHIP_FROZEN)) { nand_debug(NDBG_SIM,"Chip [%x] get event [%x]", chip->chip_num, ev->type); chip->ev_handler(chip, ev->type, ev->data); } wakeup(ev); destroy_event(ev); } } struct nandsim_ev * create_event(struct nandsim_chip *chip, uint8_t type, uint8_t data_size) { struct nandsim_ev *ev; ev = malloc(sizeof(*ev), M_NANDSIM, M_NOWAIT | M_ZERO); if (!ev) { nand_debug(NDBG_SIM,"Cannot create event"); return (NULL); } if (data_size > 0) ev->data = malloc(sizeof(*ev), M_NANDSIM, M_NOWAIT | M_ZERO); ev->type = type; ev->chip = chip; return (ev); } void destroy_event(struct nandsim_ev *ev) { if (ev->data) free(ev->data, M_NANDSIM); free(ev, M_NANDSIM); } int send_event(struct nandsim_ev *ev) { struct nandsim_chip *chip = ev->chip; if (!(chip->flags & NANDSIM_CHIP_FROZEN)) { nand_debug(NDBG_SIM,"Chip%d [%p] send event %x", chip->chip_num, chip, ev->type); NANDSIM_CHIP_LOCK(chip); STAILQ_INSERT_TAIL(&chip->nandsim_events, ev, links); NANDSIM_CHIP_UNLOCK(chip); wakeup(chip); if ((ev->type != NANDSIM_EV_TIMEOUT) && chip->nandsim_td && (curthread != chip->nandsim_td)) tsleep(ev, PWAIT, "ns_ev", 5 * hz); } return (0); } static void nandsim_callout_eh(void *arg) { struct nandsim_ev *ev = (struct nandsim_ev *)arg; send_event(ev); } static int nandsim_delay(struct nandsim_chip *chip, int timeout) { struct nandsim_ev *ev; struct timeval delay; int tm; nand_debug(NDBG_SIM,"Chip[%d] Set delay: %d", chip->chip_num, timeout); ev = create_event(chip, NANDSIM_EV_TIMEOUT, 0); if (!ev) return (-1); chip->sm_state = NANDSIM_STATE_TIMEOUT; tm = (timeout/10000) * (hz / 100); if (callout_reset(&chip->ns_callout, tm, nandsim_callout_eh, ev)) return (-1); delay.tv_sec = chip->read_delay / 1000000; delay.tv_usec = chip->read_delay % 1000000; timevaladd(&chip->delay_tv, &delay); return (0); } static void nandsim_start_handler(struct nandsim_chip *chip, nandsim_evh_t evh) { struct nandsim_ev *ev; chip->ev_handler = evh; nand_debug(NDBG_SIM,"Start handler %p for chip%d [%p]", evh, chip->chip_num, chip); ev = create_event(chip, NANDSIM_EV_START, 0); if (!ev) nandsim_sm_error(chip); send_event(ev); } static void nandchip_set_data(struct nandsim_chip *chip, uint8_t *data, uint32_t len, uint32_t idx) { nand_debug(NDBG_SIM,"Chip [%x] data %p [%x] at %x", chip->chip_num, data, len, idx); chip->data.data_ptr = data; chip->data.size = len; chip->data.index = idx; } static int nandchip_chip_space(struct nandsim_chip *chip, int32_t row, int32_t column, size_t size, uint8_t writing) { struct block_space *blk_space; uint32_t lun, block, page, offset, block_size; int err; block_size = chip->cg.block_size + (chip->cg.oob_size * chip->cg.pgs_per_blk); err = nand_row_to_blkpg(&chip->cg, row, &lun, &block, &page); if (err) { nand_debug(NDBG_SIM,"cannot get address\n"); return (-1); } if (!nandchip_is_block_valid(chip, block)) { nandchip_set_data(chip, NULL, 0, 0); return (-1); } blk_space = get_bs(chip->swap, block, writing); if (!blk_space) { nandchip_set_data(chip, NULL, 0, 0); return (-1); } if (size > block_size) size = block_size; if (size == block_size) { offset = 0; column = 0; } else offset = page * (chip->cg.page_size + chip->cg.oob_size); nandchip_set_data(chip, &blk_space->blk_ptr[offset], size, column); return (0); } static int nandchip_get_addr_byte(struct nandsim_chip *chip, void *data, uint32_t *value) { int ncycles = 0; uint8_t byte; uint8_t *buffer; buffer = (uint8_t *)value; byte = *((uint8_t *)data); KASSERT((chip->sm_state == NANDSIM_STATE_WAIT_ADDR_ROW || chip->sm_state == NANDSIM_STATE_WAIT_ADDR_COL), ("unexpected state")); if (chip->sm_state == NANDSIM_STATE_WAIT_ADDR_ROW) { ncycles = chip->params.address_cycles & 0xf; buffer[chip->sm_addr_cycle++] = byte; } else if (chip->sm_state == NANDSIM_STATE_WAIT_ADDR_COL) { ncycles = (chip->params.address_cycles >> 4) & 0xf; buffer[chip->sm_addr_cycle++] = byte; } nand_debug(NDBG_SIM, "Chip [%x] read addr byte: %02x (%d of %d)\n", chip->chip_num, byte, chip->sm_addr_cycle, ncycles); if (chip->sm_addr_cycle == ncycles) { chip->sm_addr_cycle = 0; return (0); } return (1); } static int nandchip_is_block_valid(struct nandsim_chip *chip, int block_num) { if (!chip || !chip->blk_state) return (0); if (chip->blk_state[block_num].wear_lev == 0 || chip->blk_state[block_num].is_bad) return (0); return (1); } static void nandchip_set_status(struct nandsim_chip *chip, uint8_t flags) { chip->chip_status |= flags; } static void nandchip_clear_status(struct nandsim_chip *chip, uint8_t flags) { chip->chip_status &= ~flags; } uint8_t nandchip_get_status(struct nandsim_chip *chip) { return (chip->chip_status); } void nandsim_chip_timeout(struct nandsim_chip *chip) { struct timeval tv; getmicrotime(&tv); if (chip->sm_state == NANDSIM_STATE_TIMEOUT && timevalcmp(&tv, &chip->delay_tv, >=)) { nandchip_set_status(chip, NAND_STATUS_RDY); } } void poweron_evh(struct nandsim_chip *chip, uint32_t type, void *data) { uint8_t cmd; if (type == NANDSIM_EV_START) chip->sm_state = NANDSIM_STATE_IDLE; else if (type == NANDSIM_EV_CMD) { cmd = *(uint8_t *)data; switch(cmd) { case NAND_CMD_RESET: nandsim_log(chip, NANDSIM_LOG_SM, "in RESET state\n"); nandsim_start_handler(chip, reset_evh); break; default: nandsim_undefined(chip, type); break; } } else nandsim_undefined(chip, type); } void idle_evh(struct nandsim_chip *chip, uint32_t type, void *data) { uint8_t cmd; if (type == NANDSIM_EV_START) { nandsim_log(chip, NANDSIM_LOG_SM, "in IDLE state\n"); chip->sm_state = NANDSIM_STATE_WAIT_CMD; } else if (type == NANDSIM_EV_CMD) { nandchip_clear_status(chip, NAND_STATUS_FAIL); getmicrotime(&chip->delay_tv); cmd = *(uint8_t *)data; switch(cmd) { case NAND_CMD_READ_ID: nandsim_start_handler(chip, readid_evh); break; case NAND_CMD_READ_PARAMETER: nandsim_start_handler(chip, readparam_evh); break; case NAND_CMD_READ: nandsim_start_handler(chip, read_evh); break; case NAND_CMD_PROG: nandsim_start_handler(chip, write_evh); break; case NAND_CMD_ERASE: nandsim_start_handler(chip, erase_evh); break; default: nandsim_undefined(chip, type); break; } } else nandsim_undefined(chip, type); } void readid_evh(struct nandsim_chip *chip, uint32_t type, void *data) { struct onfi_params *params; uint8_t addr; params = &chip->params; if (type == NANDSIM_EV_START) { nandsim_log(chip, NANDSIM_LOG_SM, "in READID state\n"); chip->sm_state = NANDSIM_STATE_WAIT_ADDR_BYTE; } else if (type == NANDSIM_EV_ADDR) { addr = *((uint8_t *)data); if (addr == 0x0) nandchip_set_data(chip, (uint8_t *)&chip->id, 2, 0); else if (addr == ONFI_SIG_ADDR) nandchip_set_data(chip, (uint8_t *)¶ms->signature, 4, 0); else nandsim_bad_address(chip, &addr); nandsim_start_handler(chip, idle_evh); } else nandsim_undefined(chip, type); } void readparam_evh(struct nandsim_chip *chip, uint32_t type, void *data) { struct onfi_params *params; uint8_t addr; params = &chip->params; if (type == NANDSIM_EV_START) { nandsim_log(chip, NANDSIM_LOG_SM, "in READPARAM state\n"); chip->sm_state = NANDSIM_STATE_WAIT_ADDR_BYTE; } else if (type == NANDSIM_EV_ADDR) { addr = *((uint8_t *)data); if (addr == 0) { nandchip_set_data(chip, (uint8_t *)params, sizeof(*params), 0); } else nandsim_bad_address(chip, &addr); nandsim_start_handler(chip, idle_evh); } else nandsim_undefined(chip, type); } void read_evh(struct nandsim_chip *chip, uint32_t type, void *data) { static uint32_t column = 0, row = 0; uint32_t size; uint8_t cmd; size = chip->cg.page_size + chip->cg.oob_size; switch (type) { case NANDSIM_EV_START: nandsim_log(chip, NANDSIM_LOG_SM, "in READ state\n"); chip->sm_state = NANDSIM_STATE_WAIT_ADDR_COL; break; case NANDSIM_EV_ADDR: if (chip->sm_state == NANDSIM_STATE_WAIT_ADDR_COL) { if (nandchip_get_addr_byte(chip, data, &column)) break; chip->sm_state = NANDSIM_STATE_WAIT_ADDR_ROW; } else if (chip->sm_state == NANDSIM_STATE_WAIT_ADDR_ROW) { if (nandchip_get_addr_byte(chip, data, &row)) break; chip->sm_state = NANDSIM_STATE_WAIT_CMD; } else nandsim_ignore_address(chip, *((uint8_t *)data)); break; case NANDSIM_EV_CMD: cmd = *(uint8_t *)data; if (chip->sm_state == NANDSIM_STATE_WAIT_CMD && cmd == NAND_CMD_READ_END) { if (chip->read_delay != 0 && nandsim_delay(chip, chip->read_delay) == 0) nandchip_clear_status(chip, NAND_STATUS_RDY); else { nandchip_chip_space(chip, row, column, size, 0); nandchip_set_status(chip, NAND_STATUS_RDY); nandsim_start_handler(chip, idle_evh); } } else nandsim_undefined(chip, type); break; case NANDSIM_EV_TIMEOUT: if (chip->sm_state == NANDSIM_STATE_TIMEOUT) { nandchip_chip_space(chip, row, column, size, 0); nandchip_set_status(chip, NAND_STATUS_RDY); nandsim_start_handler(chip, idle_evh); } else nandsim_undefined(chip, type); break; } } void write_evh(struct nandsim_chip *chip, uint32_t type, void *data) { static uint32_t column, row; uint32_t size; uint8_t cmd; int err; size = chip->cg.page_size + chip->cg.oob_size; switch(type) { case NANDSIM_EV_START: nandsim_log(chip, NANDSIM_LOG_SM, "in WRITE state\n"); chip->sm_state = NANDSIM_STATE_WAIT_ADDR_COL; break; case NANDSIM_EV_ADDR: if (chip->sm_state == NANDSIM_STATE_WAIT_ADDR_COL) { if (nandchip_get_addr_byte(chip, data, &column)) break; chip->sm_state = NANDSIM_STATE_WAIT_ADDR_ROW; } else if (chip->sm_state == NANDSIM_STATE_WAIT_ADDR_ROW) { if (nandchip_get_addr_byte(chip, data, &row)) break; err = nandchip_chip_space(chip, row, column, size, 1); if (err == -1) nandchip_set_status(chip, NAND_STATUS_FAIL); chip->sm_state = NANDSIM_STATE_WAIT_CMD; } else nandsim_ignore_address(chip, *((uint8_t *)data)); break; case NANDSIM_EV_CMD: cmd = *(uint8_t *)data; if (chip->sm_state == NANDSIM_STATE_WAIT_CMD && cmd == NAND_CMD_PROG_END) { if (chip->prog_delay != 0 && nandsim_delay(chip, chip->prog_delay) == 0) nandchip_clear_status(chip, NAND_STATUS_RDY); else { nandchip_set_status(chip, NAND_STATUS_RDY); nandsim_start_handler(chip, idle_evh); } } else nandsim_undefined(chip, type); break; case NANDSIM_EV_TIMEOUT: if (chip->sm_state == NANDSIM_STATE_TIMEOUT) { nandsim_start_handler(chip, idle_evh); nandchip_set_status(chip, NAND_STATUS_RDY); } else nandsim_undefined(chip, type); break; } } void erase_evh(struct nandsim_chip *chip, uint32_t type, void *data) { static uint32_t row, block_size; uint32_t lun, block, page; int err; uint8_t cmd; block_size = chip->cg.block_size + (chip->cg.oob_size * chip->cg.pgs_per_blk); switch (type) { case NANDSIM_EV_START: nandsim_log(chip, NANDSIM_LOG_SM, "in ERASE state\n"); chip->sm_state = NANDSIM_STATE_WAIT_ADDR_ROW; break; case NANDSIM_EV_CMD: cmd = *(uint8_t *)data; if (chip->sm_state == NANDSIM_STATE_WAIT_CMD && cmd == NAND_CMD_ERASE_END) { if (chip->data.data_ptr != NULL && chip->data.size == block_size) memset(chip->data.data_ptr, 0xff, block_size); else nand_debug(NDBG_SIM,"Bad block erase data\n"); err = nand_row_to_blkpg(&chip->cg, row, &lun, &block, &page); if (!err) { if (chip->blk_state[block].wear_lev > 0) chip->blk_state[block].wear_lev--; } if (chip->erase_delay != 0 && nandsim_delay(chip, chip->erase_delay) == 0) nandchip_clear_status(chip, NAND_STATUS_RDY); else { nandchip_set_status(chip, NAND_STATUS_RDY); nandsim_start_handler(chip, idle_evh); } } else nandsim_undefined(chip, type); break; case NANDSIM_EV_ADDR: if (chip->sm_state == NANDSIM_STATE_WAIT_ADDR_ROW) { if (nandchip_get_addr_byte(chip, data, &row)) break; err = nandchip_chip_space(chip, row, 0, block_size, 1); if (err == -1) { nandchip_set_status(chip, NAND_STATUS_FAIL); } chip->sm_state = NANDSIM_STATE_WAIT_CMD; } else nandsim_ignore_address(chip, *((uint8_t *)data)); break; case NANDSIM_EV_TIMEOUT: if (chip->sm_state == NANDSIM_STATE_TIMEOUT) { nandchip_set_status(chip, NAND_STATUS_RDY); nandsim_start_handler(chip, idle_evh); } else nandsim_undefined(chip, type); break; } } void reset_evh(struct nandsim_chip *chip, uint32_t type, void *data) { if (type == NANDSIM_EV_START) { nandsim_log(chip, NANDSIM_LOG_SM, "in RESET state\n"); chip->sm_state = NANDSIM_STATE_TIMEOUT; nandchip_set_data(chip, NULL, 0, 0); DELAY(500); nandsim_start_handler(chip, idle_evh); } else nandsim_undefined(chip, type); } static void nandsim_undefined(struct nandsim_chip *chip, uint8_t type) { nandsim_log(chip, NANDSIM_LOG_ERR, "ERR: Chip received ev %x in state %x\n", type, chip->sm_state); nandsim_start_handler(chip, idle_evh); } static void nandsim_bad_address(struct nandsim_chip *chip, uint8_t *addr) { nandsim_log(chip, NANDSIM_LOG_ERR, "ERR: Chip received out of range address" "%02x%02x - %02x%02x%02x\n", addr[0], addr[1], addr[2], addr[3], addr[4]); } static void nandsim_ignore_address(struct nandsim_chip *chip, uint8_t byte) { nandsim_log(chip, NANDSIM_LOG_SM, "ignored address byte: %d\n", byte); } static void nandsim_sm_error(struct nandsim_chip *chip) { nandsim_log(chip, NANDSIM_LOG_ERR, "ERR: State machine error." "Restart required.\n"); }