Esempio n. 1
0
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);
}
Esempio n. 2
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);
}
Esempio n. 3
0
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);
}
Esempio n. 4
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);
}
Esempio n. 5
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);
}
Esempio n. 6
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);
}
Esempio n. 7
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);
}
Esempio n. 8
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);
}
Esempio n. 9
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);
}
Esempio n. 10
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);
}
Esempio n. 11
0
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);
}