Example #1
0
int
cd_setvol(struct cd_softc *cd, const struct ioc_vol *arg, int flags)
{
	union scsi_mode_sense_buf *data;
	struct cd_audio_page *audio = NULL;
	u_int8_t mask_volume[4];
	int error, big;

	data = malloc(sizeof(*data), M_TEMP, M_NOWAIT);
	if (data == NULL)
		return (ENOMEM);

	error = scsi_do_mode_sense(cd->sc_link,
	    AUDIO_PAGE | SMS_PAGE_CTRL_CHANGEABLE, data, (void **)&audio, NULL,
	    NULL, NULL, sizeof(*audio), flags, NULL);
	if (error == 0 && audio == NULL)
		error = EIO;
	if (error != 0) {
		free(data, M_TEMP);
		return (error);
	}

	mask_volume[0] = audio->port[0].volume;
	mask_volume[1] = audio->port[1].volume;
	mask_volume[2] = audio->port[2].volume;
	mask_volume[3] = audio->port[3].volume;

	error = scsi_do_mode_sense(cd->sc_link, AUDIO_PAGE, data,
	    (void **)&audio, NULL, NULL, NULL, sizeof(*audio), flags, &big);
	if (error == 0 && audio == NULL)
		error = EIO;
	if (error != 0) {
		free(data, M_TEMP);
		return (error);
	}

	audio->port[0].volume = arg->vol[0] & mask_volume[0];
	audio->port[1].volume = arg->vol[1] & mask_volume[1];
	audio->port[2].volume = arg->vol[2] & mask_volume[2];
	audio->port[3].volume = arg->vol[3] & mask_volume[3];

	if (big)
		error = scsi_mode_select_big(cd->sc_link, SMS_PF,
		    &data->hdr_big, flags, 20000);
	else
		error = scsi_mode_select(cd->sc_link, SMS_PF,
		    &data->hdr, flags, 20000);

	free(data, M_TEMP);
	return (error);
}
Example #2
0
int
cd_getvol(struct cd_softc *cd, struct ioc_vol *arg, int flags)
{
	union scsi_mode_sense_buf *data;
	struct cd_audio_page *audio = NULL;
	int error;

	data = malloc(sizeof(*data), M_TEMP, M_NOWAIT);
	if (data == NULL)
		return (ENOMEM);

	error = scsi_do_mode_sense(cd->sc_link, AUDIO_PAGE, data,
	    (void **)&audio, NULL, NULL, NULL, sizeof(*audio), flags, NULL);
	if (error == 0 && audio == NULL)
		error = EIO;

	if (error == 0) {
		arg->vol[0] = audio->port[0].volume;
		arg->vol[1] = audio->port[1].volume;
		arg->vol[2] = audio->port[2].volume;
		arg->vol[3] = audio->port[3].volume;
	}

	free(data, M_TEMP);
	return (0);
}
Example #3
0
int
cd_setchan(struct cd_softc *cd, int p0, int p1, int p2, int p3, int flags)
{
	union scsi_mode_sense_buf *data;
	struct cd_audio_page *audio = NULL;
	int error, big;

	data = malloc(sizeof(*data), M_TEMP, M_NOWAIT);
	if (data == NULL)
		return (ENOMEM);

	error = scsi_do_mode_sense(cd->sc_link, AUDIO_PAGE, data,
	    (void **)&audio, NULL, NULL, NULL, sizeof(*audio), flags, &big);
	if (error == 0 && audio == NULL)
		error = EIO;

	if (error == 0) {
		audio->port[LEFT_PORT].channels = p0;
		audio->port[RIGHT_PORT].channels = p1;
		audio->port[2].channels = p2;
		audio->port[3].channels = p3;
		if (big)
			error = scsi_mode_select_big(cd->sc_link, SMS_PF,
			    &data->hdr_big, flags, 20000);
		else
			error = scsi_mode_select(cd->sc_link, SMS_PF,
			    &data->hdr, flags, 20000);
	}

	free(data, M_TEMP);
	return (error);
}
Example #4
0
int
cd_set_pa_immed(struct cd_softc *cd, int flags)
{
	union scsi_mode_sense_buf *data;
	struct cd_audio_page *audio = NULL;
	int error, oflags, big;

	if (cd->sc_link->flags & SDEV_ATAPI)
		/* XXX Noop? */
		return (0);

	data = malloc(sizeof(*data), M_TEMP, M_NOWAIT);
	if (data == NULL)
		return (ENOMEM);

	error = scsi_do_mode_sense(cd->sc_link, AUDIO_PAGE, data,
	    (void **)&audio, NULL, NULL, NULL, sizeof(*audio), flags, &big);
	if (error == 0 && audio == NULL)
		error = EIO;

	if (error == 0) {
		oflags = audio->flags;
		audio->flags &= ~CD_PA_SOTC;
		audio->flags |= CD_PA_IMMED;
		if (audio->flags != oflags) {
			if (big)
				error = scsi_mode_select_big(cd->sc_link,
				    SMS_PF, &data->hdr_big, flags,
				    20000);
			else
				error = scsi_mode_select(cd->sc_link, SMS_PF,
				    &data->hdr, flags, 20000);
		}
	}

	free(data, M_TEMP);
	return (error);
}
Example #5
0
int
sd_ioctl_cache(struct sd_softc *sc, long cmd, struct dk_cache *dkc)
{
	union scsi_mode_sense_buf *buf;
	struct page_caching_mode *mode = NULL;
	u_int wrcache, rdcache;
	int big;
	int rv;

	if (ISSET(sc->sc_link->flags, SDEV_UMASS))
		return (EOPNOTSUPP);

	/* see if the adapter has special handling */
	rv = scsi_do_ioctl(sc->sc_link, cmd, (caddr_t)dkc, 0);
	if (rv != ENOTTY)
		return (rv);

	buf = dma_alloc(sizeof(*buf), PR_WAITOK);
	if (buf == NULL)
		return (ENOMEM);

	rv = scsi_do_mode_sense(sc->sc_link, PAGE_CACHING_MODE,
	    buf, (void **)&mode, NULL, NULL, NULL,
	    sizeof(*mode) - 4, scsi_autoconf | SCSI_SILENT, &big);
	if (rv != 0)
		goto done;

	if ((mode == NULL) || (!DISK_PGCODE(mode, PAGE_CACHING_MODE))) {
		rv = EIO;
		goto done;
	}

	wrcache = (ISSET(mode->flags, PG_CACHE_FL_WCE) ? 1 : 0);
	rdcache = (ISSET(mode->flags, PG_CACHE_FL_RCD) ? 0 : 1);

	switch (cmd) {
	case DIOCGCACHE:
		dkc->wrcache = wrcache;
		dkc->rdcache = rdcache;
		break;

	case DIOCSCACHE:
		if (dkc->wrcache == wrcache && dkc->rdcache == rdcache)
			break;

		if (dkc->wrcache)
			SET(mode->flags, PG_CACHE_FL_WCE);
		else
			CLR(mode->flags, PG_CACHE_FL_WCE);

		if (dkc->rdcache)
			CLR(mode->flags, PG_CACHE_FL_RCD);
		else
			SET(mode->flags, PG_CACHE_FL_RCD);

		if (big) {
			rv = scsi_mode_select_big(sc->sc_link, SMS_PF,
			    &buf->hdr_big, scsi_autoconf | SCSI_SILENT, 20000);
		} else {
			rv = scsi_mode_select(sc->sc_link, SMS_PF,
			    &buf->hdr, scsi_autoconf | SCSI_SILENT, 20000);
		}
		break;
	}

done:
	dma_free(buf, sizeof(*buf));
	return (rv);
}
Example #6
0
/*
 * Fill out the disk parameter structure. Return SDGP_RESULT_OK if the
 * structure is correctly filled in, SDGP_RESULT_OFFLINE otherwise. The caller
 * is responsible for clearing the SDEV_MEDIA_LOADED flag if the structure
 * cannot be completed.
 */
int
sd_get_parms(struct sd_softc *sc, struct disk_parms *dp, int flags)
{
	union scsi_mode_sense_buf *buf = NULL;
	struct page_rigid_geometry *rigid = NULL;
	struct page_flex_geometry *flex = NULL;
	struct page_reduced_geometry *reduced = NULL;
	u_char *page0 = NULL;
	u_int32_t heads = 0, sectors = 0, cyls = 0, secsize = 0;
	int err = 0, big;

	if (sd_size(sc, flags) != 0)
		return (SDGP_RESULT_OFFLINE);

	if (ISSET(sc->flags, SDF_THIN) && sd_thin_params(sc, flags) != 0) {
		/* we dont know the unmap limits, so we cant use thin shizz */
		CLR(sc->flags, SDF_THIN);
	}

	buf = dma_alloc(sizeof(*buf), PR_NOWAIT);
	if (buf == NULL)
		goto validate;

	/*
	 * Ask for page 0 (vendor specific) mode sense data to find
	 * READONLY info. The only thing USB devices will ask for. 
	 */
	err = scsi_do_mode_sense(sc->sc_link, 0, buf, (void **)&page0,
	    NULL, NULL, NULL, 1, flags | SCSI_SILENT, &big);
	if (err == 0) {
		if (big && buf->hdr_big.dev_spec & SMH_DSP_WRITE_PROT)
			SET(sc->sc_link->flags, SDEV_READONLY);
		else if (!big && buf->hdr.dev_spec & SMH_DSP_WRITE_PROT)
			SET(sc->sc_link->flags, SDEV_READONLY);
		else
			CLR(sc->sc_link->flags, SDEV_READONLY);
	}

	/*
	 * Many UMASS devices choke when asked about their geometry. Most
	 * don't have a meaningful geometry anyway, so just fake it if
	 * scsi_size() worked.
	 */
	if ((sc->sc_link->flags & SDEV_UMASS) && (dp->disksize > 0))
		goto validate;

	switch (sc->sc_link->inqdata.device & SID_TYPE) {
	case T_OPTICAL:
		/* No more information needed or available. */
		break;

	case T_RDIRECT:
		/* T_RDIRECT supports only PAGE_REDUCED_GEOMETRY (6). */
		err = scsi_do_mode_sense(sc->sc_link, PAGE_REDUCED_GEOMETRY,
		    buf, (void **)&reduced, NULL, NULL, &secsize,
		    sizeof(*reduced), flags | SCSI_SILENT, NULL);
		if (!err && reduced &&
		    DISK_PGCODE(reduced, PAGE_REDUCED_GEOMETRY)) {
			if (dp->disksize == 0)
				dp->disksize = _5btol(reduced->sectors);
			if (secsize == 0)
				secsize = _2btol(reduced->bytes_s);
		}
		break;

	default:
		/*
		 * NOTE: Some devices leave off the last four bytes of 
		 * PAGE_RIGID_GEOMETRY and PAGE_FLEX_GEOMETRY mode sense pages.
		 * The only information in those four bytes is RPM information
		 * so accept the page. The extra bytes will be zero and RPM will
		 * end up with the default value of 3600.
		 */
		if (((sc->sc_link->flags & SDEV_ATAPI) == 0) ||
		    ((sc->sc_link->flags & SDEV_REMOVABLE) == 0))
			err = scsi_do_mode_sense(sc->sc_link,
			    PAGE_RIGID_GEOMETRY, buf, (void **)&rigid, NULL,
			    NULL, &secsize, sizeof(*rigid) - 4,
			    flags | SCSI_SILENT, NULL);
		if (!err && rigid && DISK_PGCODE(rigid, PAGE_RIGID_GEOMETRY)) {
			heads = rigid->nheads;
			cyls = _3btol(rigid->ncyl);
			if (heads * cyls > 0)
				sectors = dp->disksize / (heads * cyls);
		} else {
			err = scsi_do_mode_sense(sc->sc_link,
			    PAGE_FLEX_GEOMETRY, buf, (void **)&flex, NULL, NULL,
			    &secsize, sizeof(*flex) - 4,
			    flags | SCSI_SILENT, NULL);
			if (!err && flex &&
			    DISK_PGCODE(flex, PAGE_FLEX_GEOMETRY)) {
				sectors = flex->ph_sec_tr;
				heads = flex->nheads;
				cyls = _2btol(flex->ncyl);
				if (secsize == 0)
					secsize = _2btol(flex->bytes_s);
				if (dp->disksize == 0)
					dp->disksize = heads * cyls * sectors;
			}
		}
		break;
	}

validate:
	if (buf)
		dma_free(buf, sizeof(*buf));

	if (dp->disksize == 0)
		return (SDGP_RESULT_OFFLINE);

	if (dp->secsize == 0)
		dp->secsize = (secsize == 0) ? 512 : secsize;

	/*
	 * Restrict secsize values to powers of two between 512 and 64k.
	 */
	switch (dp->secsize) {
	case 0x200:	/* == 512, == DEV_BSIZE on all architectures. */
	case 0x400:
	case 0x800:
	case 0x1000:
	case 0x2000:
	case 0x4000:
	case 0x8000:
	case 0x10000:
		break;
	default:
		SC_DEBUG(sc->sc_link, SDEV_DB1,
		    ("sd_get_parms: bad secsize: %#x\n", dp->secsize));
		return (SDGP_RESULT_OFFLINE);
	}

	/*
	 * XXX THINK ABOUT THIS!!  Using values such that sectors * heads *
	 * cyls is <= disk_size can lead to wasted space. We need a more
	 * careful calculation/validation to make everything work out
	 * optimally.
	 */
	if (dp->disksize > 0xffffffff && (dp->heads * dp->sectors) < 0xffff) {
		dp->heads = 511;
		dp->sectors = 255;
		cyls = 0;
	} else {
		/*
		 * Use standard geometry values for anything we still don't
		 * know.
		 */
		dp->heads = (heads == 0) ? 255 : heads;
		dp->sectors = (sectors == 0) ? 63 : sectors;
	}

	dp->cyls = (cyls == 0) ? dp->disksize / (dp->heads * dp->sectors) :
	    cyls;

	if (dp->cyls == 0) {
		dp->heads = dp->cyls = 1;
		dp->sectors = dp->disksize;
	}

	return (SDGP_RESULT_OK);
}
Example #7
0
/*
 * Fill out the disk parameter structure. Return SDGP_RESULT_OK if the
 * structure is correctly filled in, SDGP_RESULT_OFFLINE otherwise. The caller
 * is responsible for clearing the SDEV_MEDIA_LOADED flag if the structure
 * cannot be completed.
 */
int
sd_get_parms(struct sd_softc *sc, struct disk_parms *dp, int flags)
{
    union scsi_mode_sense_buf *buf = NULL;
    struct page_rigid_geometry *rigid;
    struct page_flex_geometry *flex;
    struct page_reduced_geometry *reduced;
    u_int32_t heads = 0, sectors = 0, cyls = 0, blksize = 0, ssblksize;
    u_int16_t rpm = 0;

    dp->disksize = scsi_size(sc->sc_link, flags, &ssblksize);

    /*
     * Many UMASS devices choke when asked about their geometry. Most
     * don't have a meaningful geometry anyway, so just fake it if
     * scsi_size() worked.
     */
    if ((sc->sc_link->flags & SDEV_UMASS) && (dp->disksize > 0))
        goto validate;	 /* N.B. buf will be NULL at validate. */

    buf = malloc(sizeof(*buf), M_TEMP, M_NOWAIT);
    if (buf == NULL)
        goto validate;

    switch (sc->sc_link->inqdata.device & SID_TYPE) {
    case T_OPTICAL:
        /* No more information needed or available. */
        break;

    case T_RDIRECT:
        /* T_RDIRECT supports only PAGE_REDUCED_GEOMETRY (6). */
        scsi_do_mode_sense(sc->sc_link, PAGE_REDUCED_GEOMETRY, buf,
                           (void **)&reduced, NULL, NULL, &blksize, sizeof(*reduced),
                           flags | SCSI_SILENT, NULL);
        if (DISK_PGCODE(reduced, PAGE_REDUCED_GEOMETRY)) {
            if (dp->disksize == 0)
                dp->disksize = _5btol(reduced->sectors);
            if (blksize == 0)
                blksize = _2btol(reduced->bytes_s);
        }
        break;

    default:
        /*
         * NOTE: Some devices leave off the last four bytes of
         * PAGE_RIGID_GEOMETRY and PAGE_FLEX_GEOMETRY mode sense pages.
         * The only information in those four bytes is RPM information
         * so accept the page. The extra bytes will be zero and RPM will
         * end up with the default value of 3600.
         */
        rigid = NULL;
        if (((sc->sc_link->flags & SDEV_ATAPI) == 0) ||
                ((sc->sc_link->flags & SDEV_REMOVABLE) == 0))
            scsi_do_mode_sense(sc->sc_link, PAGE_RIGID_GEOMETRY,
                               buf, (void **)&rigid, NULL, NULL, &blksize,
                               sizeof(*rigid) - 4, flags | SCSI_SILENT, NULL);
        if (DISK_PGCODE(rigid, PAGE_RIGID_GEOMETRY)) {
            heads = rigid->nheads;
            cyls = _3btol(rigid->ncyl);
            rpm = _2btol(rigid->rpm);
            if (heads * cyls > 0)
                sectors = dp->disksize / (heads * cyls);
        } else {
            scsi_do_mode_sense(sc->sc_link, PAGE_FLEX_GEOMETRY,
                               buf, (void **)&flex, NULL, NULL, &blksize,
                               sizeof(*flex) - 4, flags | SCSI_SILENT, NULL);
            if (DISK_PGCODE(flex, PAGE_FLEX_GEOMETRY)) {
                sectors = flex->ph_sec_tr;
                heads = flex->nheads;
                cyls = _2btol(flex->ncyl);
                rpm = _2btol(flex->rpm);
                if (blksize == 0)
                    blksize = _2btol(flex->bytes_s);
                if (dp->disksize == 0)
                    dp->disksize = heads * cyls * sectors;
            }
        }
        break;
    }

validate:
    if (buf)
        free(buf, M_TEMP);

    if (dp->disksize == 0)
        return (SDGP_RESULT_OFFLINE);

    if (ssblksize > 0)
        dp->blksize = ssblksize;
    else
        dp->blksize = (blksize == 0) ? 512 : blksize;

    /*
     * Restrict blksize values to powers of two between 512 and 64k.
     */
    switch (dp->blksize) {
    case 0x200:	/* == 512, == DEV_BSIZE on all architectures. */
    case 0x400:
    case 0x800:
    case 0x1000:
    case 0x2000:
    case 0x4000:
    case 0x8000:
    case 0x10000:
        break;
    default:
        SC_DEBUG(sc->sc_link, SDEV_DB1,
                 ("sd_get_parms: bad blksize: %#x\n", dp->blksize));
        return (SDGP_RESULT_OFFLINE);
    }

    /*
     * XXX THINK ABOUT THIS!!  Using values such that sectors * heads *
     * cyls is <= disk_size can lead to wasted space. We need a more
     * careful calculation/validation to make everything work out
     * optimally.
     */
    if (dp->disksize > 0xffffffff && (dp->heads * dp->sectors) < 0xffff) {
        dp->heads = 511;
        dp->sectors = 255;
        cyls = 0;
    } else {
        /*
         * Use standard geometry values for anything we still don't
         * know.
         */
        dp->heads = (heads == 0) ? 255 : heads;
        dp->sectors = (sectors == 0) ? 63 : sectors;
        dp->rot_rate = (rpm == 0) ? 3600 : rpm;
    }

    dp->cyls = (cyls == 0) ? dp->disksize / (dp->heads * dp->sectors) :
               cyls;

    if (dp->cyls == 0) {
        dp->heads = dp->cyls = 1;
        dp->sectors = dp->disksize;
    }

    return (SDGP_RESULT_OK);
}
Example #8
0
/*
 * Ask the device about itself and fill in the parameters in our
 * softc.
 */
int
ch_get_params(struct ch_softc *sc, int flags)
{
	union scsi_mode_sense_buf *data;
	struct page_element_address_assignment *ea;
	struct page_device_capabilities *cap;
	int error, from;
	u_int8_t *moves, *exchanges;

	data = dma_alloc(sizeof(*data), PR_NOWAIT);
	if (data == NULL)
		return (ENOMEM);

	/*
	 * Grab info from the element address assignment page (0x1d).
	 */
	error = scsi_do_mode_sense(sc->sc_link, 0x1d, data,
	    (void **)&ea, NULL, NULL, NULL, sizeof(*ea), flags, NULL);
	if (error == 0 && ea == NULL)
		error = EIO;
	if (error != 0) {
#ifdef CHANGER_DEBUG
		printf("%s: could not sense element address page\n",
		    sc->sc_dev.dv_xname);
#endif
		dma_free(data, sizeof(*data));
		return (error);
	}

	sc->sc_firsts[CHET_MT] = _2btol(ea->mtea);
	sc->sc_counts[CHET_MT] = _2btol(ea->nmte);
	sc->sc_firsts[CHET_ST] = _2btol(ea->fsea);
	sc->sc_counts[CHET_ST] = _2btol(ea->nse);
	sc->sc_firsts[CHET_IE] = _2btol(ea->fieea);
	sc->sc_counts[CHET_IE] = _2btol(ea->niee);
	sc->sc_firsts[CHET_DT] = _2btol(ea->fdtea);
	sc->sc_counts[CHET_DT] = _2btol(ea->ndte);

	/* XXX Ask for transport geometry page. */

	/*
	 * Grab info from the capabilities page (0x1f).
	 */
	error = scsi_do_mode_sense(sc->sc_link, 0x1f, data,
	    (void **)&cap, NULL, NULL, NULL, sizeof(*cap), flags, NULL);
	if (cap == NULL)
		error = EIO;
	if (error != 0) {
#ifdef CHANGER_DEBUG
		printf("%s: could not sense capabilities page\n",
		    sc->sc_dev.dv_xname);
#endif
		dma_free(data, sizeof(*data));
		return (error);
	}

	bzero(sc->sc_movemask, sizeof(sc->sc_movemask));
	bzero(sc->sc_exchangemask, sizeof(sc->sc_exchangemask));
	moves = &cap->move_from_mt;
	exchanges = &cap->exchange_with_mt;
	for (from = CHET_MT; from <= CHET_DT; ++from) {
		sc->sc_movemask[from] = moves[from];
		sc->sc_exchangemask[from] = exchanges[from];
	}

	sc->sc_link->flags |= SDEV_MEDIA_LOADED;
	dma_free(data, sizeof(*data));
	return (0);
}