Esempio n. 1
0
int
safte_bio_blink(struct safte_softc *sc, struct bioc_blink *blink)
{
	struct safte_writebuf_cmd	cmd;
	struct safte_slotop		*op;
	int				slot;
	int				flags;
	int				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 = malloc(sizeof(struct safte_slotop), M_TEMP, 0);

	memset(op, 0, sizeof(struct safte_slotop));
	op->opcode = SAFTE_WRITE_SLOTOP;
	op->slot = slot;
	op->flags |= wantblink ? SAFTE_SLOTOP_IDENTIFY : 0;

	memset(&cmd, 0, sizeof(cmd));
	cmd.opcode = WRITE_BUFFER;
	cmd.flags |= SAFTE_WR_MODE;
	cmd.length = htobe16(sizeof(struct safte_slotop));
	flags = SCSI_DATA_OUT;
#ifndef SCSIDEBUG
	flags |= SCSI_SILENT;
#endif
	if (cold)
		flags |= SCSI_AUTOCONF;

	if (scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd,
	    sizeof(cmd), (u_char *)op, sizeof(struct safte_slotop),
	    2, 30000, NULL, flags) != 0) {
		free(op, M_TEMP);
		return (EIO);
	}

	free(op, M_TEMP);

	return (0);
}
Esempio n. 2
0
/*
 * Get scsi driver to send a "start up" command
 */
int
cd_pause(struct cd_softc *cd, int go)
{
	struct scsi_pause scsi_cmd;

	bzero(&scsi_cmd, sizeof(scsi_cmd));
	scsi_cmd.opcode = PAUSE;
	scsi_cmd.resume = go;
	return scsi_scsi_cmd(cd->sc_link, (struct scsi_generic *)&scsi_cmd,
	    sizeof(scsi_cmd), 0, 0, SCSI_RETRIES, 2000, NULL, 0);
}
Esempio n. 3
0
/*
 * Get scsi driver to send a "start playing" command
 */
int
cd_play(struct cd_softc *cd, int blkno, int nblks)
{
	struct scsi_play scsi_cmd;

	bzero(&scsi_cmd, sizeof(scsi_cmd));
	scsi_cmd.opcode = PLAY;
	_lto4b(blkno, scsi_cmd.blk_addr);
	_lto2b(nblks, scsi_cmd.xfer_len);
	return (scsi_scsi_cmd(cd->sc_link,
	    (struct scsi_generic *)&scsi_cmd, sizeof(scsi_cmd),
	    0, 0, SCSI_RETRIES, 200000, NULL, 0));
}
Esempio n. 4
0
int
cd_load_unload(struct cd_softc *cd, int options, int slot)
{
	struct scsi_load_unload cmd;

	bzero(&cmd, sizeof(cmd));
	cmd.opcode = LOAD_UNLOAD;
	cmd.options = options;    /* ioctl uses ATAPI values */
	cmd.slot = slot;

	return (scsi_scsi_cmd(cd->sc_link, (struct scsi_generic *)&cmd,
	    sizeof(cmd), 0, 0, SCSI_RETRIES, 200000, NULL, 0));
}
Esempio n. 5
0
int
safte_match(struct device *parent, void *match, void *aux)
{
	struct scsi_attach_args		*sa = aux;
	struct scsi_inquiry_data	*inq = sa->sa_inqbuf;
	struct scsi_inquiry_data	inqbuf;
	struct scsi_inquiry		cmd;
	struct safte_inq		*si = (struct safte_inq *)&inqbuf.extra;
	int				length, flags;

	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);

	memset(&cmd, 0, sizeof(cmd));
	cmd.opcode = INQUIRY;
	_lto2b(length, cmd.length);

	memset(&inqbuf, 0, sizeof(inqbuf));
	memset(&inqbuf.extra, ' ', sizeof(inqbuf.extra));

	flags = SCSI_DATA_IN;
	if (cold)
		flags |= SCSI_AUTOCONF;

	if (scsi_scsi_cmd(sa->sa_sc_link, (struct scsi_generic *)&cmd,
	    sizeof(cmd), (u_char *)&inqbuf, length, 2, 10000, NULL,
	    flags) != 0)
		return (0);

	if (memcmp(si->ident, SAFTE_IDENT, sizeof(si->ident)) == 0)
		return (2);

	return (0);
}
Esempio n. 6
0
/*
 * Read subchannel
 */
int
cd_read_subchannel(struct cd_softc *cd, int mode, int format, int track,
    struct cd_sub_channel_info *data, int len)
{
	struct scsi_read_subchannel scsi_cmd;

	bzero(&scsi_cmd, sizeof(scsi_cmd));
	scsi_cmd.opcode = READ_SUBCHANNEL;
	if (mode == CD_MSF_FORMAT)
		scsi_cmd.byte2 |= CD_MSF;
	scsi_cmd.byte3 = SRS_SUBQ;
	scsi_cmd.subchan_format = format;
	scsi_cmd.track = track;
	_lto2b(len, scsi_cmd.data_len);
	return scsi_scsi_cmd(cd->sc_link, (struct scsi_generic *)&scsi_cmd,
	    sizeof(struct scsi_read_subchannel), (u_char *)data, len,
	    SCSI_RETRIES, 5000, NULL, SCSI_DATA_IN|SCSI_SILENT);
}
Esempio n. 7
0
/*
 * Get scsi driver to send a "play msf" command
 */
int
cd_play_msf(struct cd_softc *cd, int startm, int starts, int startf, int endm,
    int ends, int endf)
{
	struct scsi_play_msf scsi_cmd;

	bzero(&scsi_cmd, sizeof(scsi_cmd));
	scsi_cmd.opcode = PLAY_MSF;
	scsi_cmd.start_m = startm;
	scsi_cmd.start_s = starts;
	scsi_cmd.start_f = startf;
	scsi_cmd.end_m = endm;
	scsi_cmd.end_s = ends;
	scsi_cmd.end_f = endf;
	return (scsi_scsi_cmd(cd->sc_link,
	    (struct scsi_generic *)&scsi_cmd, sizeof(scsi_cmd),
	    0, 0, SCSI_RETRIES, 20000, NULL, 0));
}
Esempio n. 8
0
/*
 * Read table of contents
 */
int
cd_read_toc(struct cd_softc *cd, int mode, int start, void *data, int len,
    int control)
{
	struct scsi_read_toc scsi_cmd;

	bzero(&scsi_cmd, sizeof(scsi_cmd));
	bzero(data, len);

	scsi_cmd.opcode = READ_TOC;
	if (mode == CD_MSF_FORMAT)
		scsi_cmd.byte2 |= CD_MSF;
	scsi_cmd.from_track = start;
	_lto2b(len, scsi_cmd.data_len);
	scsi_cmd.control = control;

	return scsi_scsi_cmd(cd->sc_link, (struct scsi_generic *)&scsi_cmd,
	    sizeof(struct scsi_read_toc), (u_char *)data, len, SCSI_RETRIES,
	    5000, NULL, SCSI_DATA_IN | SCSI_IGNORE_ILLEGAL_REQUEST);
}
Esempio n. 9
0
void
safte_read_encstat(void *arg)
{
	struct safte_softc		*sc = (struct safte_softc *)arg;
	struct safte_readbuf_cmd	cmd;
	int				flags, i;
	struct safte_sensor		*s;
	u_int16_t			oot;

	rw_enter_write(&sc->sc_lock);

	memset(&cmd, 0, sizeof(cmd));
	cmd.opcode = READ_BUFFER;
	cmd.flags |= SAFTE_RD_MODE;
	cmd.bufferid = SAFTE_RD_ENCSTAT;
	cmd.length = htobe16(sc->sc_encbuflen);
	flags = SCSI_DATA_IN;
#ifndef SCSIDEBUG
	flags |= SCSI_SILENT;
#endif

	if (cold)
		flags |= SCSI_AUTOCONF;

	if (scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd,
	    sizeof(cmd), sc->sc_encbuf, sc->sc_encbuflen, 2, 30000, NULL,
	    flags) != 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 = betoh16(*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);
}
Esempio n. 10
0
int
safte_read_config(struct safte_softc *sc)
{
	struct safte_readbuf_cmd	cmd;
	struct safte_config		config;
	struct safte_sensor		*s;
	int				flags, i, j;

	memset(&cmd, 0, sizeof(cmd));
	cmd.opcode = READ_BUFFER;
	cmd.flags |= SAFTE_RD_MODE;
	cmd.bufferid = SAFTE_RD_CONFIG;
	cmd.length = htobe16(sizeof(config));
	flags = SCSI_DATA_IN;
#ifndef SCSIDEBUG
	flags |= SCSI_SILENT;
#endif

	if (cold)
		flags |= SCSI_AUTOCONF;

	if (scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd,
	    sizeof(cmd), (u_char *)&config, sizeof(config), 2, 30000, NULL,
	    flags) != 0)
		return (1);

	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 = malloc(sc->sc_encbuflen, M_DEVBUF, M_NOWAIT);
	if (sc->sc_encbuf == NULL)
		return (1);

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

	sc->sc_sensors = malloc(sc->sc_nsensors * sizeof(struct safte_sensor),
	    M_DEVBUF, M_NOWAIT | M_ZERO);
	if (sc->sc_sensors == NULL) {
		free(sc->sc_encbuf, M_DEVBUF);
		sc->sc_encbuf = NULL;
		sc->sc_nsensors = 0;
		return (1);
	}

	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_int16_t *)(sc->sc_encbuf + j);

	return (0);
}
Esempio n. 11
0
/*
 * cdstart 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 deques 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 (cdstrategy)
 *
 * 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.
 *
 * must be called at the correct (highish) spl level
 * cdstart() is called at splbio from cdstrategy, cdrestart and scsi_done
 */
void
cdstart(void *v)
{
	struct cd_softc *cd = v;
	struct scsi_link *sc_link = cd->sc_link;
	struct buf *bp = 0;
	struct buf *dp;
	struct scsi_rw_big cmd_big;
	struct scsi_rw cmd_small;
	struct scsi_generic *cmdp;
	int blkno, nblks, cmdlen, error;
	struct partition *p;

	splassert(IPL_BIO);

	SC_DEBUG(sc_link, SDEV_DB2, ("cdstart\n"));
	/*
	 * Check if the device has room for another command
	 */
	while (sc_link->openings > 0) {
		/*
		 * there is excess capacity, but a special waits
		 * It'll need the adapter as soon as we clear out of the
		 * way and let it run (user level wait).
		 */
		if (sc_link->flags & SDEV_WAITING) {
			sc_link->flags &= ~SDEV_WAITING;
			wakeup((caddr_t)sc_link);
			return;
		}

		/*
		 * See if there is a buf with work for us to do..
		 */
		dp = &cd->buf_queue;
		if ((bp = dp->b_actf) == NULL)	/* yes, an assign */
			return;
		dp->b_actf = bp->b_actf;

		/*
		 * If the device has become invalid, abort all the
		 * reads and writes until all files have been closed and
		 * re-opened
		 */
		if ((sc_link->flags & SDEV_MEDIA_LOADED) == 0) {
			bp->b_error = EIO;
			bp->b_flags |= B_ERROR;
			bp->b_resid = bp->b_bcount;
			biodone(bp);
			continue;
		}

		/*
		 * We have a buf, now we should make a command
		 *
		 * First, translate the block to absolute and put it in terms
		 * of the logical blocksize of the device.
		 */
		blkno =
		    bp->b_blkno / (cd->sc_dk.dk_label->d_secsize / DEV_BSIZE);
		p = &cd->sc_dk.dk_label->d_partitions[DISKPART(bp->b_dev)];
		blkno += DL_GETPOFFSET(p);
		nblks = howmany(bp->b_bcount, cd->sc_dk.dk_label->d_secsize);

		/*
		 *  Fill out the scsi command.  If the transfer will
		 *  fit in a "small" cdb, use it.
		 */
		if (!(sc_link->flags & SDEV_ATAPI) &&
		    !(sc_link->quirks & SDEV_ONLYBIG) && 
		    ((blkno & 0x1fffff) == blkno) &&
		    ((nblks & 0xff) == nblks)) {
			/*
			 * We can fit in a small cdb.
			 */
			bzero(&cmd_small, sizeof(cmd_small));
			cmd_small.opcode = (bp->b_flags & B_READ) ?
			    READ_COMMAND : WRITE_COMMAND;
			_lto3b(blkno, cmd_small.addr);
			cmd_small.length = nblks & 0xff;
			cmdlen = sizeof(cmd_small);
			cmdp = (struct scsi_generic *)&cmd_small;
		} else {
			/*
			 * Need a large cdb.
			 */
			bzero(&cmd_big, sizeof(cmd_big));
			cmd_big.opcode = (bp->b_flags & B_READ) ?
			    READ_BIG : WRITE_BIG;
			_lto4b(blkno, cmd_big.addr);
			_lto2b(nblks, cmd_big.length);
			cmdlen = sizeof(cmd_big);
			cmdp = (struct scsi_generic *)&cmd_big;
		}

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

		/*
		 * Call the routine that chats with the adapter.
		 * Note: we cannot sleep as we may be an interrupt
		 */
		error = scsi_scsi_cmd(sc_link, cmdp, cmdlen,
		    (u_char *) bp->b_data, bp->b_bcount, SCSI_RETRIES, 30000,
		    bp, SCSI_NOSLEEP | ((bp->b_flags & B_READ) ? SCSI_DATA_IN :
		    SCSI_DATA_OUT));
		switch (error) {
		case 0:
			timeout_del(&cd->sc_timeout);
			break;
		case EAGAIN:
			/*
			 * The device can't start another i/o. Try again later.
			 */
			dp->b_actf = bp;
			disk_unbusy(&cd->sc_dk, 0, 0);
			timeout_add(&cd->sc_timeout, 1);
			return;
		default:
			disk_unbusy(&cd->sc_dk, 0, 0);
			printf("%s: not queued, error %d\n",
			    cd->sc_dev.dv_xname, error);
			break;
		}
	}
}
Esempio n. 12
0
int
dvd_auth(struct cd_softc *cd, union dvd_authinfo *a)
{
	struct scsi_generic cmd;
	u_int8_t buf[20];
	int error;

	bzero(cmd.bytes, sizeof(cmd.bytes));
	bzero(buf, sizeof(buf));

	switch (a->type) {
	case DVD_LU_SEND_AGID:
		cmd.opcode = GPCMD_REPORT_KEY;
		cmd.bytes[8] = 8;
		cmd.bytes[9] = 0 | (0 << 6);
		error = scsi_scsi_cmd(cd->sc_link, &cmd, sizeof(cmd), buf, 8,
		    SCSI_RETRIES, 30000, NULL, SCSI_DATA_IN);
		if (error)
			return (error);
		a->lsa.agid = buf[7] >> 6;
		return (0);

	case DVD_LU_SEND_CHALLENGE:
		cmd.opcode = GPCMD_REPORT_KEY;
		cmd.bytes[8] = 16;
		cmd.bytes[9] = 1 | (a->lsc.agid << 6);
		error = scsi_scsi_cmd(cd->sc_link, &cmd, sizeof(cmd), buf, 16,
		    SCSI_RETRIES, 30000, NULL, SCSI_DATA_IN);
		if (error)
			return (error);
		dvd_copy_challenge(a->lsc.chal, &buf[4]);
		return (0);

	case DVD_LU_SEND_KEY1:
		cmd.opcode = GPCMD_REPORT_KEY;
		cmd.bytes[8] = 12;
		cmd.bytes[9] = 2 | (a->lsk.agid << 6);
		error = scsi_scsi_cmd(cd->sc_link, &cmd, sizeof(cmd), buf, 12,
		    SCSI_RETRIES, 30000, NULL, SCSI_DATA_IN);
		if (error)
			return (error);
		dvd_copy_key(a->lsk.key, &buf[4]);
		return (0);

	case DVD_LU_SEND_TITLE_KEY:
		cmd.opcode = GPCMD_REPORT_KEY;
		_lto4b(a->lstk.lba, &cmd.bytes[1]);
		cmd.bytes[8] = 12;
		cmd.bytes[9] = 4 | (a->lstk.agid << 6);
		error = scsi_scsi_cmd(cd->sc_link, &cmd, sizeof(cmd), buf, 12,
		    SCSI_RETRIES, 30000, NULL, SCSI_DATA_IN);
		if (error)
			return (error);
		a->lstk.cpm = (buf[4] >> 7) & 1;
		a->lstk.cp_sec = (buf[4] >> 6) & 1;
		a->lstk.cgms = (buf[4] >> 4) & 3;
		dvd_copy_key(a->lstk.title_key, &buf[5]);
		return (0);

	case DVD_LU_SEND_ASF:
		cmd.opcode = GPCMD_REPORT_KEY;
		cmd.bytes[8] = 8;
		cmd.bytes[9] = 5 | (a->lsasf.agid << 6);
		error = scsi_scsi_cmd(cd->sc_link, &cmd, sizeof(cmd), buf, 8,
		    SCSI_RETRIES, 30000, NULL, SCSI_DATA_IN);
		if (error)
			return (error);
		a->lsasf.asf = buf[7] & 1;
		return (0);

	case DVD_HOST_SEND_CHALLENGE:
		cmd.opcode = GPCMD_SEND_KEY;
		cmd.bytes[8] = 16;
		cmd.bytes[9] = 1 | (a->hsc.agid << 6);
		buf[1] = 14;
		dvd_copy_challenge(&buf[4], a->hsc.chal);
		error = scsi_scsi_cmd(cd->sc_link, &cmd, sizeof(cmd), buf, 16,
		    SCSI_RETRIES, 30000, NULL, SCSI_DATA_OUT);
		if (error)
			return (error);
		a->type = DVD_LU_SEND_KEY1;
		return (0);

	case DVD_HOST_SEND_KEY2:
		cmd.opcode = GPCMD_SEND_KEY;
		cmd.bytes[8] = 12;
		cmd.bytes[9] = 3 | (a->hsk.agid << 6);
		buf[1] = 10;
		dvd_copy_key(&buf[4], a->hsk.key);
		error = scsi_scsi_cmd(cd->sc_link, &cmd, sizeof(cmd), buf, 12,
		    SCSI_RETRIES, 30000, NULL, SCSI_DATA_OUT);
		if (error) {
			a->type = DVD_AUTH_FAILURE;
			return (error);
		}
		a->type = DVD_AUTH_ESTABLISHED;
		return (0);

	case DVD_INVALIDATE_AGID:
		cmd.opcode = GPCMD_REPORT_KEY;
		cmd.bytes[9] = 0x3f | (a->lsa.agid << 6);
		error = scsi_scsi_cmd(cd->sc_link, &cmd, sizeof(cmd), buf, 16,
		    SCSI_RETRIES, 30000, NULL, 0);
		if (error)
			return (error);
		return (0);

	case DVD_LU_SEND_RPC_STATE:
		cmd.opcode = GPCMD_REPORT_KEY;
		cmd.bytes[8] = 8;
		cmd.bytes[9] = 8 | (0 << 6);
		error = scsi_scsi_cmd(cd->sc_link, &cmd, sizeof(cmd), buf, 8,
		    SCSI_RETRIES, 30000, NULL, SCSI_DATA_IN);
		if (error)
			return (error);
		a->lrpcs.type = (buf[4] >> 6) & 3;
		a->lrpcs.vra = (buf[4] >> 3) & 7;
		a->lrpcs.ucca = (buf[4]) & 7;
		a->lrpcs.region_mask = buf[5];
		a->lrpcs.rpc_scheme = buf[6];
		return (0);

	case DVD_HOST_SEND_RPC_STATE:
		cmd.opcode = GPCMD_SEND_KEY;
		cmd.bytes[8] = 8;
		cmd.bytes[9] = 6 | (0 << 6);
		buf[1] = 6;
		buf[4] = a->hrpcs.pdrc;
		error = scsi_scsi_cmd(cd->sc_link, &cmd, sizeof(cmd), buf, 8,
		    SCSI_RETRIES, 30000, NULL, SCSI_DATA_OUT);
		if (error)
			return (error);
		return (0);

	default:
		return (ENOTTY);
	}
}
Esempio n. 13
0
/*
 * Get scsi driver to send a "RESET" command
 */
int
cd_reset(struct cd_softc *cd)
{
	return scsi_scsi_cmd(cd->sc_link, 0, 0, 0, 0, SCSI_RETRIES, 2000, NULL,
	    SCSI_RESET);
}