Example #1
0
int
ch_getelemstatus(struct ch_softc *sc, int first, int count, caddr_t data,
    size_t datalen, int voltag)
{
	struct scsi_read_element_status *cmd;
	struct scsi_xfer *xs;
	int error;

	/*
	 * Build SCSI command.
	 */
	xs = scsi_xs_get(sc->sc_link, SCSI_DATA_IN);
	if (xs == NULL)
		return (ENOMEM);
	xs->cmdlen = sizeof(*cmd);
	xs->data = data;
	xs->datalen = datalen;
	xs->retries = CHRETRIES;
	xs->timeout = 100000;

	cmd = (struct scsi_read_element_status *)xs->cmd;
	cmd->opcode = READ_ELEMENT_STATUS;
	_lto2b(first, cmd->sea);
	_lto2b(count, cmd->count);
	_lto3b(datalen, cmd->len);
	if (voltag)
		cmd->byte2 |= READ_ELEMENT_STATUS_VOLTAG;

	error = scsi_xs_sync(xs);
	scsi_xs_put(xs);

	return (error);
}
Example #2
0
int
emc_inquiry(struct emc_softc *sc, char *model, char *serial)
{
	u_int8_t *buffer;
	struct scsi_inquiry *cdb;
	struct scsi_xfer *xs;
	size_t length;
	int error;
	u_int8_t slen, mlen;

	length = MIN(sc->sc_path.p_link->inqdata.additional_length + 5, 255);
	if (length < 160) {
		printf("%s: FC (Legacy)\n");
		return (0);
	}

	buffer = dma_alloc(length, PR_WAITOK);

	xs = scsi_xs_get(sc->sc_path.p_link, scsi_autoconf);
	if (xs == NULL) {
		error = EBUSY;
		goto done;
	}

	cdb = (struct scsi_inquiry *)xs->cmd;
	cdb->opcode = INQUIRY;
	_lto2b(length, cdb->length);

	xs->cmdlen = sizeof(*cdb);
	xs->flags |= SCSI_DATA_IN;
	xs->data = buffer;
	xs->datalen = length;

	error = scsi_xs_sync(xs);
	scsi_xs_put(xs);

	if (error != 0)
		goto done;

	slen = buffer[160];
	if (slen == 0 || slen + 161 > length) {
		error = EIO;
		goto done;
	}

	mlen = buffer[99];
	if (mlen == 0 || slen + mlen + 161 > length) {
		error = EIO;
		goto done;
	}

	scsi_strvis(serial, buffer + 161, slen);
	scsi_strvis(model, buffer + 161 + slen, mlen);

	error = 0;
done:
	dma_free(buffer, length);
	return (error);
}
Example #3
0
int
ch_move(struct ch_softc *sc, struct changer_move *cm)
{
	struct scsi_move_medium *cmd;
	struct scsi_xfer *xs;
	int error;
	u_int16_t fromelem, toelem;

	/*
	 * Check arguments.
	 */
	if ((cm->cm_fromtype > CHET_DT) || (cm->cm_totype > CHET_DT))
		return (EINVAL);
	if ((cm->cm_fromunit > (sc->sc_counts[cm->cm_fromtype] - 1)) ||
	    (cm->cm_tounit > (sc->sc_counts[cm->cm_totype] - 1)))
		return (ENODEV);

	/*
	 * Check the request against the changer's capabilities.
	 */
	if ((sc->sc_movemask[cm->cm_fromtype] & (1 << cm->cm_totype)) == 0)
		return (EINVAL);

	/*
	 * Calculate the source and destination elements.
	 */
	fromelem = sc->sc_firsts[cm->cm_fromtype] + cm->cm_fromunit;
	toelem = sc->sc_firsts[cm->cm_totype] + cm->cm_tounit;

	/*
	 * Build the SCSI command.
	 */
	xs = scsi_xs_get(sc->sc_link, 0);
	if (xs == NULL)
		return (ENOMEM);
	xs->cmdlen = sizeof(*cmd);
	xs->retries = CHRETRIES;
	xs->timeout = 100000;

	cmd = (struct scsi_move_medium *)xs->cmd;
	cmd->opcode = MOVE_MEDIUM;
	_lto2b(sc->sc_picker, cmd->tea);
	_lto2b(fromelem, cmd->src);
	_lto2b(toelem, cmd->dst);
	if (cm->cm_flags & CM_INVERT)
		cmd->flags |= MOVE_MEDIUM_INVERT;

	error = scsi_xs_sync(xs);
	scsi_xs_put(xs);

	return (error);
}
Example #4
0
int
emc_inquiry(struct emc_softc *sc, char *model, char *serial)
{
	u_int8_t buffer[255];
	struct scsi_inquiry *cdb;
	struct scsi_xfer *xs;
	size_t length;
	int error;
	u_int8_t slen, mlen;

	length = MIN(sc->sc_path.p_link->inqdata.additional_length + 5,
	    sizeof(buffer));
	if (length < 160) {
		printf("%s: FC (Legacy)\n");
		return (0);
	}

	xs = scsi_xs_get(sc->sc_path.p_link, scsi_autoconf);
	if (xs == NULL)
		return (EBUSY);

        cdb = (struct scsi_inquiry *)xs->cmd;
        cdb->opcode = INQUIRY;
        _lto2b(length, cdb->length);

        xs->cmdlen = sizeof(*cdb);
        xs->flags |= SCSI_DATA_IN;
        xs->data = buffer;
        xs->datalen = length;

        error = scsi_xs_sync(xs);
        scsi_xs_put(xs);

	if (error != 0)
		return (error);

	slen = buffer[160];
	if (slen == 0 || slen + 161 > length)
		return (EIO);

	mlen = buffer[99];
	if (mlen == 0 || slen + mlen + 161 > length)
		return (EIO);

	scsi_strvis(serial, buffer + 161, slen);
	scsi_strvis(model, buffer + 161 + slen, mlen);

	return (0);
}
Example #5
0
int
sd_read_cap_16(struct sd_softc *sc, int flags)
{
	struct scsi_read_capacity_16 cdb;
	struct scsi_read_cap_data_16 *rdcap;
	struct scsi_xfer *xs;
	int rv = ENOMEM;

	CLR(flags, SCSI_IGNORE_ILLEGAL_REQUEST);

	rdcap = dma_alloc(sizeof(*rdcap), (ISSET(flags, SCSI_NOSLEEP) ?
	    PR_NOWAIT : PR_WAITOK) | PR_ZERO);
	if (rdcap == NULL)
		return (ENOMEM);

	xs = scsi_xs_get(sc->sc_link, flags | SCSI_DATA_IN | SCSI_SILENT);
	if (xs == NULL)
		goto done;

	bzero(&cdb, sizeof(cdb));
	cdb.opcode = READ_CAPACITY_16;
	cdb.byte2 = SRC16_SERVICE_ACTION;
	_lto4b(sizeof(*rdcap), cdb.length);

	memcpy(xs->cmd, &cdb, sizeof(cdb));
	xs->cmdlen = sizeof(cdb);
	xs->data = (void *)rdcap;
	xs->datalen = sizeof(*rdcap);
	xs->timeout = 20000;

	rv = scsi_xs_sync(xs);
	scsi_xs_put(xs);

	if (rv == 0) {
		sc->params.disksize = _8btol(rdcap->addr) + 1;
		sc->params.secsize = _4btol(rdcap->length);
		if (ISSET(_2btol(rdcap->lowest_aligned), READ_CAP_16_TPE))
			SET(sc->flags, SDF_THIN);
		else
			CLR(sc->flags, SDF_THIN);
	}

 done:
	dma_free(rdcap, sizeof(*rdcap));
	return (rv);
}
Example #6
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);
}
Example #7
0
int
ch_position(struct ch_softc *sc, struct changer_position *cp)
{
	struct scsi_position_to_element *cmd;
	struct scsi_xfer *xs;
	int error;
	u_int16_t dst;

	/*
	 * Check arguments.
	 */
	if (cp->cp_type > CHET_DT)
		return (EINVAL);
	if (cp->cp_unit > (sc->sc_counts[cp->cp_type] - 1))
		return (ENODEV);

	/*
	 * Calculate the destination element.
	 */
	dst = sc->sc_firsts[cp->cp_type] + cp->cp_unit;

	/*
	 * Build the SCSI command.
	 */
	xs = scsi_xs_get(sc->sc_link, 0);
	if (xs == NULL)
		return (ENOMEM);
	xs->cmdlen = sizeof(*cmd);
	xs->retries = CHRETRIES;
	xs->timeout = 100000;

	cmd = (struct scsi_position_to_element *)xs->cmd;
	cmd->opcode = POSITION_TO_ELEMENT;
	_lto2b(sc->sc_picker, cmd->tea);
	_lto2b(dst, cmd->dst);
	if (cp->cp_flags & CP_INVERT)
		cmd->flags |= POSITION_TO_ELEMENT_INVERT;

	error = scsi_xs_sync(xs);
	scsi_xs_put(xs);

	return (error);
}
Example #8
0
int
sd_flush(struct sd_softc *sc, int flags)
{
	struct scsi_link *link = sc->sc_link;
	struct scsi_xfer *xs;
	struct scsi_synchronize_cache *cmd;
	int error;

	if (link->quirks & SDEV_NOSYNCCACHE)
		return (0);

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

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

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

	error = scsi_xs_sync(xs);

	scsi_xs_put(xs);

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

	return (error);
}
Example #9
0
int
safte_read_config(struct safte_softc *sc)
{
	struct safte_config *config = NULL;
	struct safte_readbuf_cmd *cmd;
	struct safte_sensor *s;
	struct scsi_xfer *xs;
	int error = 0, flags = 0, i, j;

	config = dma_alloc(sizeof(*config), PR_NOWAIT);
	if (config == NULL)
		return (1);

	if (cold)
		flags |= SCSI_AUTOCONF;
	xs = scsi_xs_get(sc->sc_link, flags | SCSI_DATA_IN | SCSI_SILENT);
	if (xs == NULL) {
		error = 1;
		goto done;
	}
	xs->cmdlen = sizeof(*cmd);
	xs->data = (void *)config;
	xs->datalen = sizeof(*config);
	xs->retries = 2;
	xs->timeout = 30000;

	cmd = (struct safte_readbuf_cmd *)xs->cmd;
	cmd->opcode = READ_BUFFER;
	cmd->flags |= SAFTE_RD_MODE;
	cmd->bufferid = SAFTE_RD_CONFIG;
	cmd->length = htobe16(sizeof(*config));

	error = scsi_xs_sync(xs);
	scsi_xs_put(xs);

	if (error != 0) {
		error = 1;
		goto done;
	}

	DPRINTF(("%s: nfans: %d npwrsup: %d nslots: %d doorlock: %d ntemps: %d"
	    " alarm: %d celsius: %d ntherm: %d\n", DEVNAME(sc), config->nfans,
	    config->npwrsup, config->nslots, config->doorlock, config->ntemps,
	    config->alarm, SAFTE_CFG_CELSIUS(config->therm),
	    SAFTE_CFG_NTHERM(config->therm)));

	sc->sc_encbuflen = config->nfans * sizeof(u_int8_t) + /* fan status */
	    config->npwrsup * sizeof(u_int8_t) + /* power supply status */
	    config->nslots * sizeof(u_int8_t) + /* device scsi id (lun) */
	    sizeof(u_int8_t) + /* door lock status */
	    sizeof(u_int8_t) + /* speaker status */
	    config->ntemps * sizeof(u_int8_t) + /* temp sensors */
	    sizeof(u_int16_t); /* temp out of range sensors */

	sc->sc_encbuf = dma_alloc(sc->sc_encbuflen, PR_NOWAIT);
	if (sc->sc_encbuf == NULL) {
		error = 1;
		goto done;
	}

	sc->sc_nsensors = config->nfans + config->npwrsup + config->ntemps +
		(config->doorlock ? 1 : 0) + (config->alarm ? 1 : 0);

	sc->sc_sensors = mallocarray(sc->sc_nsensors, sizeof(struct safte_sensor),
	    M_DEVBUF, M_NOWAIT | M_ZERO);
	if (sc->sc_sensors == NULL) {
		dma_free(sc->sc_encbuf, sc->sc_encbuflen);
		sc->sc_encbuf = NULL;
		sc->sc_nsensors = 0;
		error = 1;
		goto done;
	}

	strlcpy(sc->sc_sensordev.xname, DEVNAME(sc),
	    sizeof(sc->sc_sensordev.xname));

	s = sc->sc_sensors;

	for (i = 0; i < config->nfans; i++) {
		s->se_type = SAFTE_T_FAN;
		s->se_field = (u_int8_t *)(sc->sc_encbuf + i);
		s->se_sensor.type = SENSOR_INDICATOR;
		snprintf(s->se_sensor.desc, sizeof(s->se_sensor.desc),
		    "Fan%d", i);

		s++;
	}
	j = config->nfans;

	for (i = 0; i < config->npwrsup; i++) {
		s->se_type = SAFTE_T_PWRSUP;
		s->se_field = (u_int8_t *)(sc->sc_encbuf + j + i);
		s->se_sensor.type = SENSOR_INDICATOR;
		snprintf(s->se_sensor.desc, sizeof(s->se_sensor.desc),
		    "PSU%d", i);

		s++;
	}
	j += config->npwrsup;

#if NBIO > 0
	sc->sc_nslots = config->nslots;
	sc->sc_slots = (u_int8_t *)(sc->sc_encbuf + j);
#endif
	j += config->nslots;

	if (config->doorlock) {
		s->se_type = SAFTE_T_DOORLOCK;
		s->se_field = (u_int8_t *)(sc->sc_encbuf + j);
		s->se_sensor.type = SENSOR_INDICATOR;
		strlcpy(s->se_sensor.desc, "doorlock",
		    sizeof(s->se_sensor.desc));

		s++;
	}
	j++;

	if (config->alarm) {
		s->se_type = SAFTE_T_ALARM;
		s->se_field = (u_int8_t *)(sc->sc_encbuf + j);
		s->se_sensor.type = SENSOR_INDICATOR;
		strlcpy(s->se_sensor.desc, "alarm", sizeof(s->se_sensor.desc));

		s++;
	}
	j++;

	/*
	 * stash the temp info so we can get out of range status. limit the
	 * number so the out of temp checks cant go into memory it doesnt own
	 */
	sc->sc_ntemps = (config->ntemps > 15) ? 15 : config->ntemps;
	sc->sc_temps = s;
	sc->sc_celsius = SAFTE_CFG_CELSIUS(config->therm);
	for (i = 0; i < config->ntemps; i++) {
		s->se_type = SAFTE_T_TEMP;
		s->se_field = (u_int8_t *)(sc->sc_encbuf + j + i);
		s->se_sensor.type = SENSOR_TEMP;

		s++;
	}
	j += config->ntemps;

	sc->sc_temperrs = (u_int8_t *)(sc->sc_encbuf + j);
done:
	dma_free(config, sizeof(*config));
	return (error);
}
Example #10
0
int
safte_match(struct device *parent, void *match, void *aux)
{
	struct scsi_inquiry_data *inqbuf;
	struct scsi_attach_args	*sa = aux;
	struct scsi_inquiry_data *inq = sa->sa_inqbuf;
	struct scsi_xfer *xs;
	struct safte_inq *si;
	int error, flags = 0, length;

	if (inq == NULL)
		return (0);

	/* match on dell enclosures */
	if ((inq->device & SID_TYPE) == T_PROCESSOR &&
	    SCSISPC(inq->version) == 3)
		return (2);

	if ((inq->device & SID_TYPE) != T_PROCESSOR ||
	    SCSISPC(inq->version) != 2 ||
	    (inq->response_format & SID_ANSII) != 2)
		return (0);

	length = inq->additional_length + SAFTE_EXTRA_OFFSET;
	if (length < SAFTE_INQ_LEN)
		return (0);
	if (length > sizeof(*inqbuf))
		length = sizeof(*inqbuf);

	inqbuf = dma_alloc(sizeof(*inqbuf), PR_NOWAIT | PR_ZERO);
	if (inqbuf == NULL)
		return (0);

	memset(inqbuf->extra, ' ', sizeof(inqbuf->extra));

	if (cold)
		flags |= SCSI_AUTOCONF;
	xs = scsi_xs_get(sa->sa_sc_link, flags | SCSI_DATA_IN);
	if (xs == NULL)
		goto fail;

	xs->retries = 2;
	xs->timeout = 10000;

	scsi_init_inquiry(xs, 0, 0, inqbuf, length);

	error = scsi_xs_sync(xs);
	scsi_xs_put(xs);

	if (error)
		goto fail;

	si = (struct safte_inq *)&inqbuf->extra;
	if (memcmp(si->ident, SAFTE_IDENT, sizeof(si->ident)) == 0) {
		dma_free(inqbuf, sizeof(*inqbuf));
		return (2);
	}

fail:
	dma_free(inqbuf, sizeof(*inqbuf));
	return (0);
}
Example #11
0
/*
 * dump all of physical memory into the partition specified, starting
 * at offset 'dumplo' into the partition.
 */
int
sddump(dev_t dev, daddr_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;
	u_int32_t sectorsize;	/* size of a disk sector */
	u_int64_t nsects;	/* number of sectors in partition */
	u_int64_t sectoff;	/* sector offset of partition */
	u_int64_t totwrt;	/* total number of sectors left to write */
	u_int32_t nwrt;		/* current number of sectors to write */
	struct scsi_xfer *xs;	/* ... convenience */
	int rv;

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

	/* 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;
	if ((blkno % DL_BLKSPERSEC(lp)) != 0)
		return EFAULT;
	totwrt = size / sectorsize;
	blkno = DL_BLKTOSEC(lp, blkno);

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

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

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

	while (totwrt > 0) {
		if (totwrt > UINT32_MAX)
			nwrt = UINT32_MAX;
		else
			nwrt = totwrt;

#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_DATA_OUT;
		xs->data = va;
		xs->datalen = nwrt * sectorsize;

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

		rv = scsi_xs_sync(xs);
		scsi_xs_put(xs);
		if (rv != 0)
			return (ENXIO);
#else	/* SD_DUMP_NOT_TRUSTED */
		/* Let's just talk about this first... */
		printf("sd%d: dump addr 0x%x, blk %lld\n", unit, va,
		    (long long)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);
}
Example #12
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);
}
Example #13
0
int
ch_exchange(struct ch_softc *sc, struct changer_exchange *ce)
{
	struct scsi_exchange_medium *cmd;
	struct scsi_xfer *xs;
	int error;
	u_int16_t src, dst1, dst2;

	/*
	 * Check arguments.
	 */
	if ((ce->ce_srctype > CHET_DT) || (ce->ce_fdsttype > CHET_DT) ||
	    (ce->ce_sdsttype > CHET_DT))
		return (EINVAL);
	if ((ce->ce_srcunit > (sc->sc_counts[ce->ce_srctype] - 1)) ||
	    (ce->ce_fdstunit > (sc->sc_counts[ce->ce_fdsttype] - 1)) ||
	    (ce->ce_sdstunit > (sc->sc_counts[ce->ce_sdsttype] - 1)))
		return (ENODEV);

	/*
	 * Check the request against the changer's capabilities.
	 */
	if (((sc->sc_exchangemask[ce->ce_srctype] &
	    (1 << ce->ce_fdsttype)) == 0) ||
	    ((sc->sc_exchangemask[ce->ce_fdsttype] &
	    (1 << ce->ce_sdsttype)) == 0))
		return (EINVAL);

	/*
	 * Calculate the source and destination elements.
	 */
	src = sc->sc_firsts[ce->ce_srctype] + ce->ce_srcunit;
	dst1 = sc->sc_firsts[ce->ce_fdsttype] + ce->ce_fdstunit;
	dst2 = sc->sc_firsts[ce->ce_sdsttype] + ce->ce_sdstunit;

	/*
	 * Build the SCSI command.
	 */
	xs = scsi_xs_get(sc->sc_link, 0);
	if (xs == NULL)
		return (ENOMEM);
	xs->cmdlen = sizeof(*cmd);
	xs->retries = CHRETRIES;
	xs->timeout = 100000;

	cmd = (struct scsi_exchange_medium *)xs->cmd;
	cmd->opcode = EXCHANGE_MEDIUM;
	_lto2b(sc->sc_picker, cmd->tea);
	_lto2b(src, cmd->src);
	_lto2b(dst1, cmd->fdst);
	_lto2b(dst2, cmd->sdst);
	if (ce->ce_flags & CE_INVERT1)
		cmd->flags |= EXCHANGE_MEDIUM_INV1;
	if (ce->ce_flags & CE_INVERT2)
		cmd->flags |= EXCHANGE_MEDIUM_INV2;

	error = scsi_xs_sync(xs);
	scsi_xs_put(xs);

	return (error);
}
Example #14
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);
}
Example #15
0
void
safte_read_encstat(void *arg)
{
	struct safte_readbuf_cmd *cmd;
	struct safte_sensor *s;
	struct safte_softc *sc = (struct safte_softc *)arg;
	struct scsi_xfer *xs;
	int error, i, flags = 0;
	u_int16_t oot;

	rw_enter_write(&sc->sc_lock);

	if (cold)
		flags |= SCSI_AUTOCONF;
	xs = scsi_xs_get(sc->sc_link, flags | SCSI_DATA_IN | SCSI_SILENT);
	if (xs == NULL) {
		rw_exit_write(&sc->sc_lock);
		return;
	}
	xs->cmdlen = sizeof(*cmd);
	xs->data = sc->sc_encbuf;
	xs->datalen = sc->sc_encbuflen;
	xs->retries = 2;
	xs->timeout = 30000;

	cmd = (struct safte_readbuf_cmd *)xs->cmd;
	cmd->opcode = READ_BUFFER;
	cmd->flags |= SAFTE_RD_MODE;
	cmd->bufferid = SAFTE_RD_ENCSTAT;
	cmd->length = htobe16(sc->sc_encbuflen);

	error = scsi_xs_sync(xs);
	scsi_xs_put(xs);

	if (error != 0) {
		rw_exit_write(&sc->sc_lock);
		return;
	}

	for (i = 0; i < sc->sc_nsensors; i++) {
		s = &sc->sc_sensors[i];
		s->se_sensor.flags &= ~SENSOR_FUNKNOWN;

		DPRINTF(("%s: %d type: %d field: 0x%02x\n", DEVNAME(sc), i,
		    s->se_type, *s->se_field));

		switch (s->se_type) {
		case SAFTE_T_FAN:
			switch (*s->se_field) {
			case SAFTE_FAN_OP:
				s->se_sensor.value = 1;
				s->se_sensor.status = SENSOR_S_OK;
				break;
			case SAFTE_FAN_MF:
				s->se_sensor.value = 0;
				s->se_sensor.status = SENSOR_S_CRIT;
				break;
			case SAFTE_FAN_NOTINST:
			case SAFTE_FAN_UNKNOWN:
			default:
				s->se_sensor.value = 0;
				s->se_sensor.status = SENSOR_S_UNKNOWN;
				s->se_sensor.flags |= SENSOR_FUNKNOWN;
				break;
			}
			break;

		case SAFTE_T_PWRSUP:
			switch (*s->se_field) {
			case SAFTE_PWR_OP_ON:
				s->se_sensor.value = 1;
				s->se_sensor.status = SENSOR_S_OK;
				break;
			case SAFTE_PWR_OP_OFF:
				s->se_sensor.value = 0;
				s->se_sensor.status = SENSOR_S_OK;
				break;
			case SAFTE_PWR_MF_ON:
				s->se_sensor.value = 1;
				s->se_sensor.status = SENSOR_S_CRIT;
				break;
			case SAFTE_PWR_MF_OFF:
				s->se_sensor.value = 0;
				s->se_sensor.status = SENSOR_S_CRIT;
				break;
			case SAFTE_PWR_NOTINST:
			case SAFTE_PWR_PRESENT:
			case SAFTE_PWR_UNKNOWN:
				s->se_sensor.value = 0;
				s->se_sensor.status = SENSOR_S_UNKNOWN;
				s->se_sensor.flags |= SENSOR_FUNKNOWN;
				break;
			}
			break;

		case SAFTE_T_DOORLOCK:
			switch (*s->se_field) {
			case SAFTE_DOOR_LOCKED:
				s->se_sensor.value = 1;
				s->se_sensor.status = SENSOR_S_OK;
				break;
			case SAFTE_DOOR_UNLOCKED:
				s->se_sensor.value = 0;
				s->se_sensor.status = SENSOR_S_CRIT;
				break;
			case SAFTE_DOOR_UNKNOWN:
				s->se_sensor.value = 0;
				s->se_sensor.status = SENSOR_S_CRIT;
				s->se_sensor.flags |= SENSOR_FUNKNOWN;
				break;
			}
			break;

		case SAFTE_T_ALARM:
			switch (*s->se_field) {
			case SAFTE_SPKR_OFF:
				s->se_sensor.value = 0;
				s->se_sensor.status = SENSOR_S_OK;
				break;
			case SAFTE_SPKR_ON:
				s->se_sensor.value = 1;
				s->se_sensor.status = SENSOR_S_CRIT;
				break;
			}
			break;

		case SAFTE_T_TEMP:
			s->se_sensor.value = safte_temp2uK(*s->se_field,
			    sc->sc_celsius);
			break;
		}
	}

	oot = _2btol(sc->sc_temperrs);
	for (i = 0; i < sc->sc_ntemps; i++)
		sc->sc_temps[i].se_sensor.status =
		    (oot & (1 << i)) ? SENSOR_S_CRIT : SENSOR_S_OK;

	rw_exit_write(&sc->sc_lock);
}
Example #16
0
int
safte_bio_blink(struct safte_softc *sc, struct bioc_blink *blink)
{
	struct safte_writebuf_cmd *cmd;
	struct safte_slotop *op;
	struct scsi_xfer *xs;
	int error, slot, flags = 0, wantblink;

	switch (blink->bb_status) {
	case BIOC_SBBLINK:
		wantblink = 1;
		break;
	case BIOC_SBUNBLINK:
		wantblink = 0;
		break;
	default:
		return (EINVAL);
	}

	rw_enter_read(&sc->sc_lock);
	for (slot = 0; slot < sc->sc_nslots; slot++) {
		if (sc->sc_slots[slot] == blink->bb_target)
			break;
	}
	rw_exit_read(&sc->sc_lock);

	if (slot >= sc->sc_nslots)
		return (ENODEV);

	op = dma_alloc(sizeof(*op), PR_WAITOK | PR_ZERO);

	op->opcode = SAFTE_WRITE_SLOTOP;
	op->slot = slot;
	op->flags |= wantblink ? SAFTE_SLOTOP_IDENTIFY : 0;

	if (cold)
		flags |= SCSI_AUTOCONF;
	xs = scsi_xs_get(sc->sc_link, flags | SCSI_DATA_OUT | SCSI_SILENT);
	if (xs == NULL) {
		dma_free(op, sizeof(*op));
		return (ENOMEM);
	}
	xs->cmdlen = sizeof(*cmd);
	xs->data = (void *)op;
	xs->datalen = sizeof(*op);
	xs->retries = 2;
	xs->timeout = 30000;

	cmd = (struct safte_writebuf_cmd *)xs->cmd;
	cmd->opcode = WRITE_BUFFER;
	cmd->flags |= SAFTE_WR_MODE;
	cmd->length = htobe16(sizeof(struct safte_slotop));

	error = scsi_xs_sync(xs);
	scsi_xs_put(xs);

	if (error != 0) {
		error = EIO;
	}
	dma_free(op, sizeof(*op));

	return (error);
}
Example #17
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);
}