示例#1
0
/*
 * sdstart looks to see if there is a buf waiting for the device
 * and that the device is not already busy. If both are true,
 * It dequeues the buf and creates a scsi command to perform the
 * transfer in the buf. The transfer request will call scsi_done
 * on completion, which will in turn call this routine again
 * so that the next queued transfer is performed.
 * The bufs are queued by the strategy routine (sdstrategy)
 *
 * This routine is also called after other non-queued requests
 * have been made of the scsi driver, to ensure that the queue
 * continues to be drained.
 */
void
sdstart(struct scsi_xfer *xs)
{
	struct scsi_link *link = xs->sc_link;
	struct sd_softc *sc = link->device_softc;
	struct buf *bp;
	u_int64_t secno;
	int nsecs;
	int read;
	struct partition *p;

	if (sc->flags & SDF_DYING) {
		scsi_xs_put(xs);
		return;
	}
	if ((link->flags & SDEV_MEDIA_LOADED) == 0) {
		bufq_drain(&sc->sc_bufq);
		scsi_xs_put(xs);
		return;
	}

	bp = bufq_dequeue(&sc->sc_bufq);
	if (bp == NULL) {
		scsi_xs_put(xs);
		return;
	}

	secno = DL_BLKTOSEC(sc->sc_dk.dk_label, bp->b_blkno);

	p = &sc->sc_dk.dk_label->d_partitions[DISKPART(bp->b_dev)];
	secno += DL_GETPOFFSET(p);
	nsecs = howmany(bp->b_bcount, sc->sc_dk.dk_label->d_secsize);
	read = bp->b_flags & B_READ;

	/*
	 *  Fill out the scsi command.  If the transfer will
	 *  fit in a "small" cdb, use it.
	 */
	if (!(link->flags & SDEV_ATAPI) &&
	    !(link->quirks & SDEV_ONLYBIG) &&
	    ((secno & 0x1fffff) == secno) &&
	    ((nsecs & 0xff) == nsecs))
		sd_cmd_rw6(xs, read, secno, nsecs);
	else if (((secno & 0xffffffff) == secno) &&
	    ((nsecs & 0xffff) == nsecs))
		sd_cmd_rw10(xs, read, secno, nsecs);
	else if (((secno & 0xffffffff) == secno) &&
	    ((nsecs & 0xffffffff) == nsecs))
		sd_cmd_rw12(xs, read, secno, nsecs);
	else
		sd_cmd_rw16(xs, read, secno, nsecs);

	xs->flags |= (read ? SCSI_DATA_IN : SCSI_DATA_OUT);
	xs->timeout = 60000;
	xs->data = bp->b_data;
	xs->datalen = bp->b_bcount;

	xs->done = sd_buf_done;
	xs->cookie = bp;
	xs->bp = bp;

	/* Instrumentation. */
	disk_busy(&sc->sc_dk);

	/* Mark disk as dirty. */
	if (!read)
		sc->flags |= SDF_DIRTY;

	scsi_xs_exec(xs);

	/* move onto the next io */
	if (ISSET(sc->flags, SDF_WAITING))
		CLR(sc->flags, SDF_WAITING);
	else if (bufq_peek(&sc->sc_bufq))
		scsi_xsh_add(&sc->sc_xsh);
}
示例#2
0
/*
 * sdstart looks to see if there is a buf waiting for the device
 * and that the device is not already busy. If both are true,
 * It dequeues the buf and creates a scsi command to perform the
 * transfer in the buf. The transfer request will call scsi_done
 * on completion, which will in turn call this routine again
 * so that the next queued transfer is performed.
 * The bufs are queued by the strategy routine (sdstrategy)
 *
 * This routine is also called after other non-queued requests
 * have been made of the scsi driver, to ensure that the queue
 * continues to be drained.
 */
void
sdstart(void *v)
{
    struct sd_softc *sc = (struct sd_softc *)v;
    struct scsi_link *link = sc->sc_link;
    struct scsi_xfer *xs;
    struct buf *bp;
    daddr64_t blkno;
    int nblks;
    int read;
    struct partition *p;
    int s;

    if (sc->flags & SDF_DYING)
        return;

    SC_DEBUG(link, SDEV_DB2, ("sdstart\n"));

    mtx_enter(&sc->sc_start_mtx);
    if (ISSET(sc->flags, SDF_STARTING)) {
        mtx_leave(&sc->sc_start_mtx);
        return;
    }

    SET(sc->flags, SDF_STARTING);
    mtx_leave(&sc->sc_start_mtx);

    CLR(sc->flags, SDF_WAITING);
    while (!ISSET(sc->flags, SDF_WAITING) &&
            (bp = sd_buf_dequeue(sc)) != NULL) {
        /*
         * If the device has become invalid, abort all the
         * reads and writes until all files have been closed and
         * re-opened
         */
        if ((link->flags & SDEV_MEDIA_LOADED) == 0) {
            bp->b_error = EIO;
            bp->b_flags |= B_ERROR;
            bp->b_resid = bp->b_bcount;
            s = splbio();
            biodone(bp);
            splx(s);
            continue;
        }

        xs = scsi_xs_get(link, SCSI_NOSLEEP);
        if (xs == NULL) {
            sd_buf_requeue(sc, bp);
            break;
        }

        blkno =
            bp->b_blkno / (sc->sc_dk.dk_label->d_secsize / DEV_BSIZE);
        p = &sc->sc_dk.dk_label->d_partitions[DISKPART(bp->b_dev)];
        blkno += DL_GETPOFFSET(p);
        nblks = howmany(bp->b_bcount, sc->sc_dk.dk_label->d_secsize);
        read = bp->b_flags & B_READ;

        /*
         *  Fill out the scsi command.  If the transfer will
         *  fit in a "small" cdb, use it.
         */
        if (!(link->flags & SDEV_ATAPI) &&
                !(link->quirks & SDEV_ONLYBIG) &&
                ((blkno & 0x1fffff) == blkno) &&
                ((nblks & 0xff) == nblks))
            sd_cmd_rw6(xs, read, blkno, nblks);
        else if (((blkno & 0xffffffff) == blkno) &&
                 ((nblks & 0xffff) == nblks))
            sd_cmd_rw10(xs, read, blkno, nblks);
        else if (((blkno & 0xffffffff) == blkno) &&
                 ((nblks & 0xffffffff) == nblks))
            sd_cmd_rw12(xs, read, blkno, nblks);
        else
            sd_cmd_rw16(xs, read, blkno, nblks);

        xs->flags |= (read ? SCSI_DATA_IN : SCSI_DATA_OUT);
        xs->timeout = 60000;
        xs->data = bp->b_data;
        xs->datalen = bp->b_bcount;

        xs->done = sd_buf_done;
        xs->cookie = bp;

        /* Instrumentation. */
        disk_busy(&sc->sc_dk);

        /* Mark disk as dirty. */
        if ((bp->b_flags & B_READ) == 0)
            sc->flags |= SDF_DIRTY;

        scsi_xs_exec(xs);
    }

    mtx_enter(&sc->sc_start_mtx);
    CLR(sc->flags, SDF_STARTING);
    mtx_leave(&sc->sc_start_mtx);
}