Esempio n. 1
0
/*
 * Common code for read and readdir.
 */
static
int
emu_doread(struct emu_softc *sc, uint32_t handle, uint32_t len,
	   uint32_t op, struct uio *uio)
{
	int result;

	KASSERT(uio->uio_rw == UIO_READ);

	if (uio->uio_offset > (off_t)0xffffffff) {
		/* beyond the largest size the file can have; generate EOF */
		return 0;
	}

	lock_acquire(sc->e_lock);

	emu_wreg(sc, REG_HANDLE, handle);
	emu_wreg(sc, REG_IOLEN, len);
	emu_wreg(sc, REG_OFFSET, uio->uio_offset);
	emu_wreg(sc, REG_OPER, op);
	result = emu_waitdone(sc);
	if (result) {
		goto out;
	}

	membar_load_load();
	result = uiomove(sc->e_iobuf, emu_rreg(sc, REG_IOLEN), uio);

	uio->uio_offset = emu_rreg(sc, REG_OFFSET);

 out:
	lock_release(sc->e_lock);
	return result;
}
Esempio n. 2
0
/*
 * Write to a hardware-level file handle.
 */
static
int
emu_write(struct emu_softc *sc, uint32_t handle, uint32_t len,
	  struct uio *uio)
{
	int result;

	KASSERT(uio->uio_rw == UIO_WRITE);

	if (uio->uio_offset > (off_t)0xffffffff) {
		return EFBIG;
	}

	lock_acquire(sc->e_lock);

	emu_wreg(sc, REG_HANDLE, handle);
	emu_wreg(sc, REG_IOLEN, len);
	emu_wreg(sc, REG_OFFSET, uio->uio_offset);

	result = uiomove(sc->e_iobuf, len, uio);
	membar_store_store();
	if (result) {
		goto out;
	}

	emu_wreg(sc, REG_OPER, EMU_OP_WRITE);
	result = emu_waitdone(sc);

 out:
	lock_release(sc->e_lock);
	return result;
}
Esempio n. 3
0
/*
 * Routine for closing a file we opened at the hardware level.
 * This is not necessarily called at VOP_LASTCLOSE time; it's called
 * at VOP_RECLAIM time.
 */
static
int
emu_close(struct emu_softc *sc, uint32_t handle)
{
	int result;
	bool mine;
	int retries = 0;

	mine = lock_do_i_hold(sc->e_lock);
	if (!mine) {
		lock_acquire(sc->e_lock);
	}

	while (1) {
		/* Retry operation up to 10 times */

		emu_wreg(sc, REG_HANDLE, handle);
		emu_wreg(sc, REG_OPER, EMU_OP_CLOSE);
		result = emu_waitdone(sc);

		if (result==EIO && retries < 10) {
			kprintf("emu%d: I/O error on close, retrying\n",
				sc->e_unit);
			retries++;
			continue;
		}
		break;
	}

	if (!mine) {
		lock_release(sc->e_lock);
	}
	return result;
}
Esempio n. 4
0
/*
 * Common code for read and readdir.
 */
static
int
emu_doread(struct emu_softc *sc, uint32_t handle, uint32_t len,
           uint32_t op, struct uio *uio)
{
    int result;

    KASSERT(uio->uio_rw == UIO_READ);

    lock_acquire(sc->e_lock);

    emu_wreg(sc, REG_HANDLE, handle);
    emu_wreg(sc, REG_IOLEN, len);
    emu_wreg(sc, REG_OFFSET, uio->uio_offset);
    emu_wreg(sc, REG_OPER, op);
    result = emu_waitdone(sc);
    if (result) {
        goto out;
    }

    result = uiomove(sc->e_iobuf, emu_rreg(sc, REG_IOLEN), uio);

    uio->uio_offset = emu_rreg(sc, REG_OFFSET);

out:
    lock_release(sc->e_lock);
    return result;
}
Esempio n. 5
0
/*
 * Truncate a hardware-level file handle.
 */
static
int
emu_trunc(struct emu_softc *sc, uint32_t handle, off_t len)
{
    int result;

    lock_acquire(sc->e_lock);

    emu_wreg(sc, REG_HANDLE, handle);
    emu_wreg(sc, REG_IOLEN, len);
    emu_wreg(sc, REG_OPER, EMU_OP_TRUNC);
    result = emu_waitdone(sc);

    lock_release(sc->e_lock);
    return result;
}
Esempio n. 6
0
/*
 * Get the file size associated with a hardware-level file handle.
 */
static
int
emu_getsize(struct emu_softc *sc, uint32_t handle, off_t *retval)
{
	int result;

	lock_acquire(sc->e_lock);

	emu_wreg(sc, REG_HANDLE, handle);
	emu_wreg(sc, REG_OPER, EMU_OP_GETSIZE);
	result = emu_waitdone(sc);
	if (result==0) {
		*retval = emu_rreg(sc, REG_IOLEN);
	}

	lock_release(sc->e_lock);
	return result;
}
Esempio n. 7
0
/*
 * Common file open routine (for both VOP_LOOKUP and VOP_CREATE).  Not
 * for VOP_EACHOPEN. At the hardware level, we need to "open" files in
 * order to look at them, so by the time VOP_EACHOPEN is called the
 * files are already open.
 */
static
int
emu_open(struct emu_softc *sc, uint32_t handle, const char *name,
	 bool create, bool excl, mode_t mode,
	 uint32_t *newhandle, int *newisdir)
{
	uint32_t op;
	int result;

	if (strlen(name)+1 > EMU_MAXIO) {
		return ENAMETOOLONG;
	}

	if (create && excl) {
		op = EMU_OP_EXCLCREATE;
	}
	else if (create) {
		op = EMU_OP_CREATE;
	}
	else {
		op = EMU_OP_OPEN;
	}

	/* mode isn't supported (yet?) */
	(void)mode;

	lock_acquire(sc->e_lock);

	strcpy(sc->e_iobuf, name);
	membar_store_store();
	emu_wreg(sc, REG_IOLEN, strlen(name));
	emu_wreg(sc, REG_HANDLE, handle);
	emu_wreg(sc, REG_OPER, op);
	result = emu_waitdone(sc);

	if (result==0) {
		*newhandle = emu_rreg(sc, REG_HANDLE);
		*newisdir = emu_rreg(sc, REG_IOLEN)>0;
	}

	lock_release(sc->e_lock);
	return result;
}
Esempio n. 8
0
/*
 * Called by the underlying bus code when an interrupt happens
 */
void
emu_irq(void *dev)
{
	struct emu_softc *sc = dev;

	sc->e_result = emu_rreg(sc, REG_RESULT);
	emu_wreg(sc, REG_RESULT, 0);

	V(sc->e_sem);
}