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