Ejemplo n.º 1
0
/*
 * Get the scsi driver to send a full inquiry to the device and use the
 * results to fill out the disk parameter structure.
 */
int
cd_get_parms(struct cd_softc *cd, int flags)
{
	/* Reasonable defaults for drives that don't support READ_CAPACITY */
	cd->params.blksize = 2048;
	cd->params.disksize = 400000;

	if (cd->sc_link->quirks & ADEV_NOCAPACITY)
		return (0);

	cd->params.disksize = scsi_size(cd->sc_link, flags,
	    &cd->params.blksize);

	if ((cd->params.blksize < 512) || ((cd->params.blksize & 511) != 0))
		cd->params.blksize = 2048;	/* some drives lie ! */

	if (cd->params.disksize < 100)
		cd->params.disksize = 400000;

	return (0);
}
Ejemplo n.º 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;
    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);
}