Beispiel #1
0
/*
 * read the requested number of bytes/lines from the scanner
 */
static int
mustek_read(struct ss_softc *ss, struct buf *bp)
{
	struct mustek_read_cmd cmd;
	struct scsipi_xfer *xs;
	struct scsipi_periph *periph = ss->sc_periph;
	u_long lines_to_read;
	int error;

	SC_DEBUG(periph, SCSIPI_DB1, ("mustek_read: start\n"));

	memset(&cmd, 0, sizeof(cmd));
	cmd.opcode = MUSTEK_READ;

	/* instead of the bytes, the mustek wants the number of lines */
	lines_to_read = bp->b_bcount /
	    ((ss->sio.scan_pixels_per_line * ss->sio.scan_bits_per_pixel) / 8);
	SC_DEBUG(periph, SCSIPI_DB1, ("mustek_read: read %ld lines\n",
	    lines_to_read));
	_lto3b(lines_to_read, cmd.length);

	/*
	 * go ask the adapter to do all this for us
	 */
	xs = scsipi_make_xs(periph,
	    (struct scsipi_generic *) &cmd, sizeof(cmd),
	    (u_char *) bp->b_data, bp->b_bcount,
	    MUSTEK_RETRIES, 10000, bp,
	    XS_CTL_NOSLEEP | XS_CTL_ASYNC | XS_CTL_DATA_IN);
	if (xs == NULL) {
		/*
		 * out of memory. Keep this buffer in the queue, and
		 * retry later.
		 */
		callout_reset(&ss->sc_callout, hz / 2, ssrestart,
		    periph);
		return(0);
	}
#ifdef DIAGNOSTIC
	if (BUFQ_GET(ss->buf_queue) != bp)
		panic("ssstart(): dequeued wrong buf");
#else
	BUFQ_GET(ss->buf_queue);
#endif
	error = scsipi_execute_xs(xs);
	/* with a scsipi_xfer preallocated, scsipi_command can't fail */
	KASSERT(error == 0);
	ss->sio.scan_lines -= lines_to_read;
#if 0
	if (ss->sio.scan_lines < 0)
		ss->sio.scan_lines = 0;
#endif
	ss->sio.scan_window_size -= bp->b_bcount;
#if 0
	if (ss->sio.scan_window_size < 0)
		ss->sio.scan_window_size = 0;
#endif
	return (0);
}
Beispiel #2
0
static int
scanjet_read(struct ss_softc *ss, struct buf *bp)
{
	struct scsi_rw_scanner cmd;
	struct scsipi_xfer *xs;
	struct scsipi_periph *periph = ss->sc_periph;
	int error;

	/*
	 *  Fill out the scsi command
	 */
	memset(&cmd, 0, sizeof(cmd));
	cmd.opcode = READ;

	/*
	 * Handle "fixed-block-mode" tape drives by using the
	 * block count instead of the length.
	 */
	_lto3b(bp->b_bcount, cmd.len);

	/*
	 * go ask the adapter to do all this for us
	 */
	xs = scsipi_make_xs(periph,
	    (struct scsipi_generic *) &cmd, sizeof(cmd),
	    (u_char *) bp->b_data, bp->b_bcount,
	    SCANJET_RETRIES, 100000, bp,
	    XS_CTL_NOSLEEP | XS_CTL_ASYNC | XS_CTL_DATA_IN);
	if (xs == NULL) {
		/*
		 * out of memory. Keep this buffer in the queue, and
		 * retry later.
		 */
		callout_reset(&ss->sc_callout, hz / 2, ssrestart,
		    periph);
		return(0);
	}
#ifdef DIAGNOSTIC
	if (BUFQ_GET(ss->buf_queue) != bp)
		panic("ssstart(): dequeued wrong buf");
#else
	BUFQ_GET(ss->buf_queue);
#endif
	error = scsipi_execute_xs(xs);
	/* with a scsipi_xfer preallocated, scsipi_command can't fail */
	KASSERT(error == 0);
	ss->sio.scan_window_size -= bp->b_bcount;
#if 0
	if (ss->sio.scan_window_size < 0)
		ss->sio.scan_window_size = 0;
#endif
	return (0);
}
Beispiel #3
0
void
fdfinish(struct fd_softc *fd, struct buf *bp)
{
	struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));

	/*
	 * Move this drive to the end of the queue to give others a `fair'
	 * chance.  We only force a switch if N operations are completed while
	 * another drive is waiting to be serviced, since there is a long motor
	 * startup delay whenever we switch.
	 */
	(void)BUFQ_GET(fd->sc_q);
	if (TAILQ_NEXT(fd, sc_drivechain) && ++fd->sc_ops >= 8) {
		fd->sc_ops = 0;
		TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
		if (BUFQ_PEEK(fd->sc_q) != NULL)
			TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
		else
			fd->sc_active = 0;
	}
	bp->b_resid = fd->sc_bcount;
	fd->sc_skip = 0;

#if NRND > 0
	rnd_add_uint32(&fd->rnd_source, bp->b_blkno);
#endif

	biodone(bp);
	/* turn off motor 5s from now */
	callout_reset(&fd->sc_motoroff_ch, 5 * hz, fd_motor_off, fd);
	fdc->sc_state = DEVIDLE;
}
Beispiel #4
0
/*
 * move all requests on a buffer queue to another.
 */
void
bufq_move(struct bufq_state *dst, struct bufq_state *src)
{
	struct buf *bp;

	while ((bp = BUFQ_GET(src)) != NULL) {
		BUFQ_PUT(dst, bp);
	}
}
Beispiel #5
0
/*
 * Drain a device buffer queue.
 */
void
bufq_drain(struct bufq_state *bufq)
{
	struct buf *bp;

	while ((bp = BUFQ_GET(bufq)) != NULL) {
		bp->b_error = EIO;
		bp->b_resid = bp->b_bcount;
		biodone(bp);
	}
}
Beispiel #6
0
void
dk_start(struct dk_intf *di, struct dk_softc *dksc)
{
	struct	buf *bp;

	DPRINTF_FOLLOW(("dk_start(%s, %p)\n", di->di_dkname, dksc));

	/* Process the work queue */
	while ((bp = BUFQ_GET(dksc->sc_bufq)) != NULL) {
		if (di->di_diskstart(dksc, bp) != 0) {
			BUFQ_PUT(dksc->sc_bufq, bp);
			break;
		}
	}
}
Beispiel #7
0
static int
md_server_loop(struct md_softc *sc)
{
    struct buf *bp;
    void *addr;	/* user space address */
    size_t off;	/* offset into "device" */
    size_t xfer;	/* amount to transfer */
    int error;

    for (;;) {
        /* Wait for some work to arrive. */
        while ((bp = BUFQ_GET(sc->sc_buflist)) == NULL) {
            error = tsleep((void *)sc, md_sleep_pri, "md_idle", 0);
            if (error)
                return error;
        }

        /* Do the transfer to/from user space. */
        error = 0;
        bp->b_resid = bp->b_bcount;
        off = (bp->b_blkno << DEV_BSHIFT);
        if (off >= sc->sc_size) {
            if (bp->b_flags & B_READ)
                goto done;	/* EOF (not an error) */
            error = EIO;
            goto done;
        }
        xfer = bp->b_resid;
        if (xfer > (sc->sc_size - off))
            xfer = (sc->sc_size - off);
        addr = (char *)sc->sc_addr + off;
        if (bp->b_flags & B_READ)
            error = copyin(addr, bp->b_data, xfer);
        else
            error = copyout(bp->b_data, addr, xfer);
        if (!error)
            bp->b_resid -= xfer;

done:
        if (error) {
            bp->b_error = error;
        }
        biodone(bp);
    }
}
Beispiel #8
0
void
hdcstart(struct hdcsoftc *sc, struct buf *ob)
{
	struct hdc9224_UDCreg * const p = &sc->sc_creg;
	struct disklabel *lp;
	struct rdsoftc *rd;
	struct buf *bp;
	int cn, sn, tn, bn, blks;
	volatile char ch;

	if (sc->sc_active)
		return; /* Already doing something */

	if (ob == 0) {
		bp = BUFQ_GET(sc->sc_q);
		if (bp == NULL)
			return; /* Nothing to do */
		sc->sc_bufaddr = bp->b_data;
		sc->sc_diskblk = bp->b_rawblkno;
		sc->sc_bytecnt = bp->b_bcount;
		sc->sc_retries = 0;
		bp->b_resid = 0;
	} else
		bp = ob;

	rd = device_lookup_private(&rd_cd, DISKUNIT(bp->b_dev));
	hdc_rdselect(sc, rd->sc_drive);
	sc->sc_active = bp;

	bn = sc->sc_diskblk;
	lp = rd->sc_disk.dk_label;
        if (bn) {
                cn = bn / lp->d_secpercyl;
                sn = bn % lp->d_secpercyl;
                tn = sn / lp->d_nsectors;
                sn = sn % lp->d_nsectors;
        } else
                cn = sn = tn = 0;

	cn++; /* first cylinder is reserved */

	bzero(p, sizeof(struct hdc9224_UDCreg));

	/*
	 * Tricky thing: the controller do itself only increase the sector
	 * number, not the track or cylinder number. Therefore the driver
	 * is not allowed to have transfers that crosses track boundaries.
	 */
	blks = sc->sc_bytecnt/DEV_BSIZE;
	if ((sn + blks) > lp->d_nsectors)
		blks = lp->d_nsectors - sn;

	p->udc_dsect = sn;
	p->udc_dcyl = cn & 0xff;
	p->udc_dhead = ((cn >> 4) & 0x70) | tn;
	p->udc_scnt = blks;

	p->udc_rtcnt = UDC_RC_RTRYCNT;
	p->udc_mode = UDC_MD_HDD;
	p->udc_term = UDC_TC_CRCPRE|UDC_TC_INTDONE|UDC_TC_TDELDAT|UDC_TC_TWRFLT;
	hdc_writeregs(sc);

	/* Count up vars */
	sc->sc_xfer = blks * DEV_BSIZE;

	ch = HDC_RSTAT; /* Avoid pending interrupts */
	WAIT;
	vsbus_clrintr(sc->sc_intbit); /* Clear pending int's */

	if (bp->b_flags & B_READ) {
		HDC_WCMD(DKC_CMD_READ_HDD);
	} else {
		vsbus_copyfromproc(bp->b_proc, sc->sc_bufaddr, sc->sc_dmabase,
		    sc->sc_xfer);
		HDC_WCMD(DKC_CMD_WRITE_HDD);
	}
}