示例#1
0
int
scsi_ioc_cmd(struct scsi_link *link, scsireq_t *screq)
{
	struct scsi_xfer *xs;
	int err = 0;

	if (screq->cmdlen > sizeof(struct scsi_generic))
		return (EFAULT);
	if (screq->datalen > MAXPHYS)
		return (EINVAL);

	xs = scsi_xs_get(link, 0);
	if (xs == NULL)
		return (ENOMEM);

	memcpy(xs->cmd, screq->cmd, screq->cmdlen);
	xs->cmdlen = screq->cmdlen;

	if (screq->datalen > 0) {
		xs->data = dma_alloc(screq->datalen, PR_WAITOK | PR_ZERO);
		if (xs->data == NULL) {
			err = ENOMEM;
			goto err;
		}
		xs->datalen = screq->datalen;
	}

	if (screq->flags & SCCMD_READ)
		xs->flags |= SCSI_DATA_IN;
	if (screq->flags & SCCMD_WRITE) {
		if (screq->datalen > 0) {
			err = copyin(screq->databuf, xs->data, screq->datalen);
			if (err != 0)
				goto err;
		}

		xs->flags |= SCSI_DATA_OUT;
	}

	xs->flags |= SCSI_SILENT;	/* User is responsible for errors. */
	xs->timeout = screq->timeout;
	xs->retries = 0; /* user must do the retries *//* ignored */

	scsi_xs_sync(xs);

	screq->retsts = 0;
	screq->status = xs->status;
	switch (xs->error) {
	case XS_NOERROR:
		/* probably rubbish */
		screq->datalen_used = xs->datalen - xs->resid;
		screq->retsts = SCCMD_OK;
		break;
	case XS_SENSE:
#ifdef SCSIDEBUG
		scsi_sense_print_debug(xs);
#endif
		screq->senselen_used = min(sizeof(xs->sense),
		    sizeof(screq->sense));
		bcopy(&xs->sense, screq->sense, screq->senselen_used);
		screq->retsts = SCCMD_SENSE;
		break;
	case XS_SHORTSENSE:
#ifdef SCSIDEBUG
		scsi_sense_print_debug(xs);
#endif
		printf("XS_SHORTSENSE\n");
		screq->senselen_used = min(sizeof(xs->sense),
		    sizeof(screq->sense));
		bcopy(&xs->sense, screq->sense, screq->senselen_used);
		screq->retsts = SCCMD_UNKNOWN;
		break;
	case XS_DRIVER_STUFFUP:
		screq->retsts = SCCMD_UNKNOWN;
		break;
	case XS_TIMEOUT:
		screq->retsts = SCCMD_TIMEOUT;
		break;
	case XS_BUSY:
		screq->retsts = SCCMD_BUSY;
		break;
	default:
		screq->retsts = SCCMD_UNKNOWN;
		break;
	}

	if (screq->datalen > 0 && screq->flags & SCCMD_READ) {
		err = copyout(xs->data, screq->databuf, screq->datalen);
		if (err != 0)
			goto err;
	}

err:
	if (xs->data)
		dma_free(xs->data, screq->datalen);
	scsi_xs_put(xs);

	return (err);
}
示例#2
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);
}
示例#3
0
int
scsi_ioc_ata_cmd(struct scsi_link *link, atareq_t *atareq)
{
	struct scsi_xfer *xs;
	struct scsi_ata_passthru_12 *cdb;
	int err = 0;

	if (atareq->datalen > MAXPHYS)
		return (EINVAL);

	xs = scsi_xs_get(link, 0);
	if (xs == NULL)
		return (ENOMEM);

	cdb = (struct scsi_ata_passthru_12 *)xs->cmd;
	cdb->opcode = ATA_PASSTHRU_12;

	if (atareq->datalen > 0) {
		if (atareq->flags & ATACMD_READ) {
			cdb->count_proto = ATA_PASSTHRU_PROTO_PIO_DATAIN;
			cdb->flags = ATA_PASSTHRU_T_DIR_READ;
		} else {
			cdb->count_proto = ATA_PASSTHRU_PROTO_PIO_DATAOUT;
			cdb->flags = ATA_PASSTHRU_T_DIR_WRITE;
		}
		cdb->flags |= ATA_PASSTHRU_T_LEN_SECTOR_COUNT;
	} else {
		cdb->count_proto = ATA_PASSTHRU_PROTO_NON_DATA;
		cdb->flags = ATA_PASSTHRU_T_LEN_NONE;
	}
	cdb->features = atareq->features;
	cdb->sector_count = atareq->sec_count;
	cdb->lba_low = atareq->sec_num;
	cdb->lba_mid = atareq->cylinder;
	cdb->lba_high = atareq->cylinder >> 8;
	cdb->device = atareq->head & 0x0f;
	cdb->command = atareq->command;

	xs->cmdlen = sizeof(*cdb);

	if (atareq->datalen > 0) {
		xs->data = dma_alloc(atareq->datalen, PR_WAITOK | PR_ZERO);
		if (xs->data == NULL) {
			err = ENOMEM;
			goto err;
		}
		xs->datalen = atareq->datalen;
	}

	if (atareq->flags & ATACMD_READ)
		xs->flags |= SCSI_DATA_IN;
	if (atareq->flags & ATACMD_WRITE) {
		if (atareq->datalen > 0) {
			err = copyin(atareq->databuf, xs->data,
			    atareq->datalen);
			if (err != 0)
				goto err;
		}

		xs->flags |= SCSI_DATA_OUT;
	}

	xs->flags |= SCSI_SILENT;	/* User is responsible for errors. */
	xs->retries = 0; /* user must do the retries *//* ignored */

	scsi_xs_sync(xs);

	atareq->retsts = ATACMD_ERROR;
	switch (xs->error) {
	case XS_SENSE:
	case XS_SHORTSENSE:
#ifdef SCSIDEBUG
		scsi_sense_print_debug(xs);
#endif
		/* XXX this is not right */
	case XS_NOERROR:
		atareq->retsts = ATACMD_OK;
		break;
	default:
		atareq->retsts = ATACMD_ERROR;
		break;
	}

	if (atareq->datalen > 0 && atareq->flags & ATACMD_READ) {
		err = copyout(xs->data, atareq->databuf, atareq->datalen);
		if (err != 0)
			goto err;
	}

err:
	if (xs->data)
		dma_free(xs->data, atareq->datalen);
	scsi_xs_put(xs);

	return (err);
}