Example #1
0
static int
sd_get_simplifiedparms(struct sd_softc *sd)
{
	struct {
		struct scsi_mode_parameter_header_6 header;
		/* no block descriptor */
		uint8_t pg_code; /* page code (should be 6) */
		uint8_t pg_length; /* page length (should be 11) */
		uint8_t wcd; /* bit0: cache disable */
		uint8_t lbs[2]; /* logical block size */
		uint8_t size[5]; /* number of log. blocks */
		uint8_t pp; /* power/performance */
		uint8_t flags;
		uint8_t resvd;
	} scsipi_sense;
	struct disk_parms *dp = &sd->sc_params;
	uint64_t blocks;
	int error, blksize;

	/*
	 * sd_read_capacity (ie "read capacity") and mode sense page 6
	 * give the same information. Do both for now, and check
	 * for consistency.
	 * XXX probably differs for removable media
	 */
	dp->blksize = SD_DEFAULT_BLKSIZE;
	if ((blocks = sd_read_capacity(sd, &blksize)) == 0)
		return SDGP_RESULT_OFFLINE;		/* XXX? */

	error = scsi_mode_sense(sd, SMS_DBD, 6,
	    &scsipi_sense.header, sizeof(scsipi_sense));

	if (error != 0)
		return SDGP_RESULT_OFFLINE;		/* XXX? */

	dp->blksize = blksize;
	if (!sd_validate_blksize(dp->blksize))
		dp->blksize = _2btol(scsipi_sense.lbs);
	if (!sd_validate_blksize(dp->blksize))
		dp->blksize = SD_DEFAULT_BLKSIZE;

	/*
	 * Create a pseudo-geometry.
	 */
	dp->heads = 64;
	dp->sectors = 32;
	dp->cyls = blocks / (dp->heads * dp->sectors);
	dp->disksize = _5btol(scsipi_sense.size);
	if (dp->disksize <= UINT32_MAX && dp->disksize != blocks) {
		printf("RBC size: mode sense=%llu, get cap=%llu\n",
		       (unsigned long long)dp->disksize,
		       (unsigned long long)blocks);
		dp->disksize = blocks;
	}
	dp->disksize512 = (dp->disksize * dp->blksize) / DEV_BSIZE;

	return SDGP_RESULT_OK;
}
Example #2
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 #3
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);
}