/* * 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); }
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); }
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; }
/* * 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); } }
/* * 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); } }
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; } } }
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); } }
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); } }