static int create_buffers(struct chip_swap *swap) { struct block_space *block_space; void *block; int i; for (i = 0; i < CHIP_SWAP_BLOCKSPACES; i++) { block_space = malloc(sizeof(*block_space), M_NANDSIM, M_WAITOK); block = malloc(swap->blk_size, M_NANDSIM, M_WAITOK); block_space->blk_ptr = block; SLIST_INSERT_HEAD(&swap->free_bs, block_space, free_link); nand_debug(NDBG_SIM,"created blk_space %p[%p]\n", block_space, block); } if (i == 0) return (-1); return (0); }
static void nand_strategy_raw(struct bio *bp) { struct nand_chip *chip; chip = (struct nand_chip *)bp->bio_disk->d_drv1; /* Inform taskqueue that it's a raw access */ bp->bio_driver1 = BIO_NAND_RAW; nand_debug(NDBG_GEOM, "Strategy %s on chip %d [%p]", (bp->bio_cmd & BIO_READ) == BIO_READ ? "READ" : ((bp->bio_cmd & BIO_WRITE) == BIO_WRITE ? "WRITE" : ((bp->bio_cmd & BIO_DELETE) == BIO_DELETE ? "DELETE" : "UNKNOWN")), chip->num, chip); mtx_lock(&chip->qlock); bioq_insert_tail(&chip->bioq, bp); mtx_unlock(&chip->qlock); taskqueue_enqueue(chip->tq, &chip->iotask); }
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 int nandsim_ctrl_status(struct sim_ctrl *ctrl) { nand_debug(NDBG_SIM,"status controller num:%d cs:%d",ctrl->num, ctrl->num_cs); if (ctrl->num >= MAX_SIM_DEV) { return (EINVAL); } ctrl->num_cs = ctrls[ctrl->num].num_cs; ctrl->ecc = ctrls[ctrl->num].ecc; memcpy(ctrl->ecc_layout, ctrls[ctrl->num].ecc_layout, MAX_ECC_BYTES * sizeof(ctrl->ecc_layout[0])); strlcpy(ctrl->filename, ctrls[ctrl->num].filename, FILENAME_SIZE); ctrl->running = ctrls[ctrl->num].running; ctrl->created = ctrls[ctrl->num].created; return (0); }
static int nandsim_destroy_ctrl(int ctrl_num) { nand_debug(NDBG_SIM,"destroy controller num:%d", ctrl_num); if (ctrl_num >= MAX_SIM_DEV) { return (EINVAL); } if (!ctrls[ctrl_num].created) { return (ENODEV); } if (ctrls[ctrl_num].running) { return (EBUSY); } memset(&ctrls[ctrl_num], 0, sizeof(ctrls[ctrl_num])); return (0); }
static int swap_file_read(struct chip_swap *swap, struct block_state *blk_state) { struct block_space *blk_space; struct thread *td; struct vnode *vp; struct uio auio; struct iovec aiov; if (swap == NULL || blk_state == NULL) return (-1); blk_space = blk_state->blk_sp; nand_debug(NDBG_SIM,"restore %p[%p] at %x\n", blk_space, blk_space->blk_ptr, blk_state->offset); bzero(&aiov, sizeof(aiov)); bzero(&auio, sizeof(auio)); aiov.iov_base = blk_space->blk_ptr; aiov.iov_len = swap->blk_size; td = curthread; vp = swap->swap_vp; auio.uio_iov = &aiov; auio.uio_offset = blk_state->offset; auio.uio_segflg = UIO_SYSSPACE; auio.uio_rw = UIO_READ; auio.uio_iovcnt = 1; auio.uio_resid = swap->blk_size; auio.uio_td = td; vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); VOP_READ(vp, &auio, 0, swap->swap_cred); VOP_UNLOCK(vp, 0); return (0); }
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 int nand_probe_onfi(device_t bus, uint8_t *onfi_compliant) { device_t nfc; char onfi_id[] = {'O', 'N', 'F', 'I', '\0'}; int i; nand_debug(NDBG_BUS,"probing ONFI"); nfc = device_get_parent(bus); if (NFC_SEND_COMMAND(nfc, NAND_CMD_READ_ID)) { nand_debug(NDBG_BUS,"Error : could not sent READ ID command"); return (ENXIO); } if (NFC_SEND_ADDRESS(nfc, ONFI_SIG_ADDR)) { nand_debug(NDBG_BUS,"Error : could not sent address to chip"); return (ENXIO); } if (NFC_START_COMMAND(nfc) != 0) { nand_debug(NDBG_BUS,"Error : could not start command"); return (ENXIO); } for (i = 0; onfi_id[i] != '\0'; i++) if (NFC_READ_BYTE(nfc) != onfi_id[i]) { nand_debug(NDBG_BUS,"ONFI non-compliant"); *onfi_compliant = 0; return (0); } nand_debug(NDBG_BUS,"ONFI compliant"); *onfi_compliant = 1; return (0); }
static int nandbus_attach(device_t dev) { device_t child, nfc; struct nand_id chip_id; struct nandbus_softc *sc; struct nandbus_ivar *ivar; struct nand_softc *nfc_sc; struct nand_params *chip_params; uint8_t cs, onfi; sc = device_get_softc(dev); sc->dev = dev; nfc = device_get_parent(dev); nfc_sc = device_get_softc(nfc); mtx_init(&sc->nandbus_mtx, "nandbus lock", NULL, MTX_DEF); cv_init(&sc->nandbus_cv, "nandbus cv"); /* Check each possible CS for existing nand devices */ for (cs = 0; cs < NAND_NCS; cs++) { nand_debug(NDBG_BUS,"probe chip select %x", cs); /* Select & reset chip */ if (nandbus_select_cs(dev, cs)) break; if (nand_reset(dev)) continue; /* Read manufacturer and device id */ if (nand_readid(dev, &chip_id.man_id, &chip_id.dev_id)) continue; if (chip_id.man_id == 0xff) continue; /* * First try to get info from the table. If that fails, see if * the chip can provide ONFI info. We check the table first to * allow table entries to override info from chips that are * known to provide bad ONFI data. */ onfi = 0; chip_params = nand_get_params(&chip_id); if (chip_params == NULL) { nand_probe_onfi(dev, &onfi); } /* * At this point it appears there is a chip at this chipselect, * so if we can't work with it, whine about it. */ if (chip_params == NULL && onfi == 0) { if (bootverbose || (nand_debug_flag & NDBG_BUS)) printf("Chip params not found, chipsel: %d " "(manuf: 0x%0x, chipid: 0x%0x, onfi: %d)\n", cs, chip_id.man_id, chip_id.dev_id, onfi); continue; } ivar = malloc(sizeof(struct nandbus_ivar), M_NAND, M_WAITOK); if (onfi == 1) { ivar->cs = cs; ivar->cols = 0; ivar->rows = 0; ivar->params = NULL; ivar->man_id = chip_id.man_id; ivar->dev_id = chip_id.dev_id; ivar->is_onfi = onfi; ivar->chip_cdev_name = nfc_sc->chip_cdev_name; child = device_add_child(dev, NULL, -1); device_set_ivars(child, ivar); continue; } ivar->cs = cs; ivar->cols = 1; ivar->rows = 2; ivar->params = chip_params; ivar->man_id = chip_id.man_id; ivar->dev_id = chip_id.dev_id; ivar->is_onfi = onfi; ivar->chip_cdev_name = nfc_sc->chip_cdev_name; /* * Check what type of device we have. * devices bigger than 32MiB have on more row (3) */ if (chip_params->chip_size > 32) ivar->rows++; /* Large page devices have one more col (2) */ if (chip_params->chip_size >= 128 && chip_params->page_size > 512) ivar->cols++; child = device_add_child(dev, NULL, -1); device_set_ivars(child, ivar); } bus_generic_attach(dev); return (0); }
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, 1); 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); }
struct block_space * get_bs(struct chip_swap *swap, uint32_t block, uint8_t writing) { struct block_state *blk_state, *old_blk_state = NULL; struct block_space *blk_space; if (swap == NULL || (block >= swap->nof_blks)) return (NULL); blk_state = &swap->blk_state[block]; nand_debug(NDBG_SIM,"blk_state %x\n", blk_state->status); if (blk_state->status & BLOCK_ALLOCATED) { blk_space = blk_state->blk_sp; } else { blk_space = SLIST_FIRST(&swap->free_bs); if (blk_space) { SLIST_REMOVE_HEAD(&swap->free_bs, free_link); STAILQ_INSERT_TAIL(&swap->used_bs, blk_space, used_link); } else { blk_space = STAILQ_FIRST(&swap->used_bs); old_blk_state = blk_space->blk_state; STAILQ_REMOVE_HEAD(&swap->used_bs, used_link); STAILQ_INSERT_TAIL(&swap->used_bs, blk_space, used_link); if (old_blk_state->status & BLOCK_DIRTY) { swap_file_write(swap, old_blk_state); old_blk_state->status &= ~BLOCK_DIRTY; old_blk_state->status |= BLOCK_SWAPPED; } } } if (blk_space == NULL) return (NULL); if (old_blk_state != NULL) { old_blk_state->status &= ~BLOCK_ALLOCATED; old_blk_state->blk_sp = NULL; } blk_state->blk_sp = blk_space; blk_space->blk_state = blk_state; if (!(blk_state->status & BLOCK_ALLOCATED)) { if (blk_state->status & BLOCK_SWAPPED) swap_file_read(swap, blk_state); else memset(blk_space->blk_ptr, 0xff, swap->blk_size); blk_state->status |= BLOCK_ALLOCATED; } if (writing) blk_state->status |= BLOCK_DIRTY; nand_debug(NDBG_SIM,"get_bs returned %p[%p] state %x\n", blk_space, blk_space->blk_ptr, blk_state->status); return (blk_space); }