Ejemplo n.º 1
0
void
emc_status(struct scsi_xfer *xs)
{
	struct scsi_link *link = xs->sc_link;
	struct emc_softc *sc = link->device_softc;

	scsi_init_inquiry(xs, SI_EVPD, EMC_VPD_SP_INFO,
	    sc->sc_pg, sizeof(*sc->sc_pg));

	xs->done = emc_status_done;

	scsi_xs_exec(xs);
}
Ejemplo n.º 2
0
void
sd_buf_done(struct scsi_xfer *xs)
{
    struct sd_softc *sc = xs->sc_link->device_softc;
    struct buf *bp = xs->cookie;

    splassert(IPL_BIO);

    disk_unbusy(&sc->sc_dk, bp->b_bcount - xs->resid,
                bp->b_flags & B_READ);

    switch (xs->error) {
    case XS_NOERROR:
        bp->b_error = 0;
        bp->b_resid = xs->resid;
        break;

    case XS_NO_CCB:
        /* The adapter is busy, requeue the buf and try it later. */
        sd_buf_requeue(sc, bp);
        scsi_xs_put(xs);
        SET(sc->flags, SDF_WAITING); /* break out of sdstart loop */
        timeout_add(&sc->sc_timeout, 1);
        return;

    case XS_SENSE:
    case XS_SHORTSENSE:
        if (scsi_interpret_sense(xs) != ERESTART)
            xs->retries = 0;

    /* FALLTHROUGH */
    case XS_BUSY:
    case XS_TIMEOUT:
        if (xs->retries--) {
            scsi_xs_exec(xs);
            return;
        }

    /* FALLTHROUGH */
    default:
        bp->b_error = EIO;
        bp->b_flags |= B_ERROR;
        bp->b_resid = bp->b_bcount;
        break;
    }

    biodone(bp);
    scsi_xs_put(xs);
    sdstart(sc); /* restart io */
}
Ejemplo n.º 3
0
void
sd_flush(struct sd_softc *sc, int flags)
{
    struct scsi_link *link = sc->sc_link;
    struct scsi_xfer *xs;
    struct scsi_synchronize_cache *cmd;

    if (link->quirks & SDEV_NOSYNCCACHE)
        return;

    /*
     * Issue a SYNCHRONIZE CACHE. Address 0, length 0 means "all remaining
     * blocks starting at address 0". Ignore ILLEGAL REQUEST in the event
     * that the command is not supported by the device.
     */

    xs = scsi_xs_get(link, flags);
    if (xs == NULL) {
        SC_DEBUG(link, SDEV_DB1, ("cache sync failed to get xs\n"));
        return;
    }

    cmd = (struct scsi_synchronize_cache *)xs->cmd;
    cmd->opcode = SYNCHRONIZE_CACHE;

    xs->cmdlen = sizeof(*cmd);
    xs->timeout = 100000;

    xs->done = sd_flush_done;

    do {
        scsi_xs_exec(xs);
        if (!ISSET(xs->flags, SCSI_POLL)) {
            while (!ISSET(xs->flags, ITSDONE))
                tsleep(xs, PRIBIO, "sdflush", 0);
        }
    } while (xs->status == XS_NO_CCB);

    if (xs->error == XS_NOERROR)
        sc->flags &= ~SDF_DIRTY;
    else
        SC_DEBUG(link, SDEV_DB1, ("cache sync failed\n"));

    scsi_xs_put(xs);
}
Ejemplo n.º 4
0
void
sd_buf_done(struct scsi_xfer *xs)
{
	struct sd_softc *sc = xs->sc_link->device_softc;
	struct buf *bp = xs->cookie;
	int error, s;

	switch (xs->error) {
	case XS_NOERROR:
		bp->b_error = 0;
		bp->b_resid = xs->resid;
		break;

	case XS_NO_CCB:
		/* The adapter is busy, requeue the buf and try it later. */
		disk_unbusy(&sc->sc_dk, bp->b_bcount - xs->resid,
		    bp->b_flags & B_READ);
		bufq_requeue(&sc->sc_bufq, bp);
		scsi_xs_put(xs);
		SET(sc->flags, SDF_WAITING);
		timeout_add(&sc->sc_timeout, 1);
		return;

	case XS_SENSE:
	case XS_SHORTSENSE:
#ifdef SCSIDEBUG
		scsi_sense_print_debug(xs);
#endif
		error = sd_interpret_sense(xs);
		if (error == 0) {
			bp->b_error = 0;
			bp->b_resid = xs->resid;
			break;
		}
		if (error != ERESTART) {
			bp->b_error = error;
			xs->retries = 0;
		}
		goto retry;

	case XS_BUSY:
		if (xs->retries) {
			if (scsi_delay(xs, 1) != ERESTART)
				xs->retries = 0;
		}
		goto retry;

	case XS_TIMEOUT:
retry:
		if (xs->retries--) {
			scsi_xs_exec(xs);
			return;
		}
		/* FALLTHROUGH */

	default:
		if (bp->b_error == 0)
			bp->b_error = EIO;
		bp->b_flags |= B_ERROR;
		bp->b_resid = bp->b_bcount;
		break;
	}

	disk_unbusy(&sc->sc_dk, bp->b_bcount - xs->resid,
	    bp->b_flags & B_READ);

	s = splbio();
	biodone(bp);
	splx(s);
	scsi_xs_put(xs);
}
Ejemplo n.º 5
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);
}
Ejemplo n.º 6
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);
}
Ejemplo n.º 7
0
/*
 * dump all of physical memory into the partition specified, starting
 * at offset 'dumplo' into the partition.
 */
int
sddump(dev_t dev, daddr64_t blkno, caddr_t va, size_t size)
{
    struct sd_softc *sc;	/* disk unit to do the I/O */
    struct disklabel *lp;	/* disk's disklabel */
    int	unit, part;
    int	sectorsize;	/* size of a disk sector */
    daddr64_t	nsects;		/* number of sectors in partition */
    daddr64_t	sectoff;	/* sector offset of partition */
    int	totwrt;		/* total number of sectors left to write */
    int	nwrt;		/* current number of sectors to write */
    struct scsi_xfer *xs;	/* ... convenience */

    /* Check if recursive dump; if so, punt. */
    if (sddoingadump)
        return EFAULT;

    /* Mark as active early. */
    sddoingadump = 1;

    unit = DISKUNIT(dev);	/* Decompose unit & partition. */
    part = DISKPART(dev);

    /* Check for acceptable drive number. */
    if (unit >= sd_cd.cd_ndevs || (sc = sd_cd.cd_devs[unit]) == NULL)
        return ENXIO;

    /*
     * XXX Can't do this check, since the media might have been
     * XXX marked `invalid' by successful unmounting of all
     * XXX filesystems.
     */
#if 0
    /* Make sure it was initialized. */
    if ((sc->sc_link->flags & SDEV_MEDIA_LOADED) != SDEV_MEDIA_LOADED)
        return ENXIO;
#endif

    /* Convert to disk sectors.  Request must be a multiple of size. */
    lp = sc->sc_dk.dk_label;
    sectorsize = lp->d_secsize;
    if ((size % sectorsize) != 0)
        return EFAULT;
    totwrt = size / sectorsize;
    blkno = dbtob(blkno) / sectorsize;	/* blkno in DEV_BSIZE units */

    nsects = DL_GETPSIZE(&lp->d_partitions[part]);
    sectoff = DL_GETPOFFSET(&lp->d_partitions[part]);

    /* Check transfer bounds against partition size. */
    if ((blkno < 0) || ((blkno + totwrt) > nsects))
        return EINVAL;

    /* Offset block number to start of partition. */
    blkno += sectoff;

    while (totwrt > 0) {
        nwrt = totwrt;		/* XXX */

#ifndef	SD_DUMP_NOT_TRUSTED
        xs = scsi_xs_get(sc->sc_link, SCSI_NOSLEEP);
        if (xs == NULL)
            return (ENOMEM);

        xs->timeout = 10000;
        xs->flags = SCSI_POLL | SCSI_NOSLEEP | SCSI_DATA_OUT;
        xs->data = va;
        xs->datalen = nwrt * sectorsize;

        sd_cmd_rw10(xs, 0, blkno, nwrt); /* XXX */

        scsi_xs_exec(xs);
        if (xs->error != XS_NOERROR)
            return (ENXIO);
        scsi_xs_put(xs);
#else	/* SD_DUMP_NOT_TRUSTED */
        /* Let's just talk about this first... */
        printf("sd%d: dump addr 0x%x, blk %d\n", unit, va, blkno);
        delay(500 * 1000);	/* half a second */
#endif	/* SD_DUMP_NOT_TRUSTED */

        /* update block count */
        totwrt -= nwrt;
        blkno += nwrt;
        va += sectorsize * nwrt;
    }

    sddoingadump = 0;

    return (0);
}