int bmdioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) { struct bmd_softc *sc; struct disklabel dl; int error; DPRINTF(("%s%d %ld\n", __func__, BMD_UNIT(dev), cmd)); sc = device_lookup_private(&bmd_cd, BMD_UNIT(dev)); if (sc == NULL) return ENXIO; error = disk_ioctl(&sc->sc_dkdev, dev, cmd, data, flag, l); if (error != EPASSTHROUGH) return error; switch (cmd) { case DIOCWDINFO: if ((flag & FWRITE) == 0) return EBADF; error = setdisklabel(&dl, (struct disklabel *)data, 0, NULL); if (error) return error; error = writedisklabel(dev, bmdstrategy, &dl, NULL); return error; default: return EINVAL; } return 0; }
int rdioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *p) { struct rd_softc *sc; struct disklabel *lp; int error = 0; sc = rdlookup(DISKUNIT(dev)); if (sc == NULL) return (ENXIO); switch (cmd) { case DIOCRLDINFO: lp = malloc(sizeof(*lp), M_TEMP, M_WAITOK); rdgetdisklabel(dev, sc, lp, 0); bcopy(lp, sc->sc_dk.dk_label, sizeof(*lp)); free(lp, M_TEMP); goto done; case DIOCGPDINFO: rdgetdisklabel(dev, sc, (struct disklabel *)data, 1); goto done; case DIOCGDINFO: *(struct disklabel *)data = *(sc->sc_dk.dk_label); goto done; case DIOCGPART: ((struct partinfo *)data)->disklab = sc->sc_dk.dk_label; ((struct partinfo *)data)->part = &sc->sc_dk.dk_label->d_partitions[DISKPART(dev)]; goto done; case DIOCWDINFO: case DIOCSDINFO: if ((fflag & FWRITE) == 0) { error = EBADF; goto done; } if ((error = disk_lock(&sc->sc_dk)) != 0) goto done; error = setdisklabel(sc->sc_dk.dk_label, (struct disklabel *)data, sc->sc_dk.dk_openmask); if (error == 0) { if (cmd == DIOCWDINFO) error = writedisklabel(DISKLABELDEV(dev), rdstrategy, sc->sc_dk.dk_label); } disk_unlock(&sc->sc_dk); goto done; } done: device_unref(&sc->sc_dev); return (error); }
/*ARGSUSED*/ io_return_t scdisk_set_status( dev_t dev, target_info_t *tgt, dev_flavor_t flavor, dev_status_t status, mach_msg_type_number_t status_count) { io_return_t error = D_SUCCESS; struct disklabel *lp; lp = &tgt->dev_info.disk.l; tgt->lun = rzlun(dev); switch (flavor) { case DIOCSRETRIES: if (status_count != sizeof(int)) return D_INVALID_SIZE; scsi_bbr_retries = *(int *)status; break; case DIOCWLABEL: if (*(int*)status) tgt->flags |= TGT_WRITE_LABEL; else tgt->flags &= ~TGT_WRITE_LABEL; break; case DIOCSDINFO: case DIOCWDINFO: if (status_count != sizeof(struct disklabel) / sizeof(int)) return D_INVALID_SIZE; error = setdisklabel(lp, (struct disklabel*) status); if (error || (flavor == DIOCSDINFO)) return error; error = scdisk_writelabel(tgt); break; #if notyet case DIOCWFORMAT: case DIOCSBAD: /* ?? how ? */ #endif default: #ifdef i386 error = scsi_i386_set_status(dev, tgt, flavor, status, status_count); #else /* i386 */ #ifdef PPC return(scsi_ppc_set_status(dev, tgt, flavor, status, status_count)); #else /* PPC */ return(D_INVALID_OPERATION); #endif /* PPC */ error = D_INVALID_OPERATION; #endif /* i386 */ } return error; }
int prestoioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *proc) { struct presto_softc *sc; int unit; int error; unit = DISKUNIT(dev); sc = (struct presto_softc *)device_lookup(&presto_cd, unit); switch (cmd) { case DIOCGDINFO: bcopy(sc->sc_dk.dk_label, data, sizeof(struct disklabel)); return (0); case DIOCSDINFO: if ((flag & FWRITE) == 0) return (EBADF); error = setdisklabel(sc->sc_dk.dk_label, (struct disklabel *)data, /*sd->sc_dk.dk_openmask : */0, sc->sc_dk.dk_cpulabel); return (error); case DIOCWDINFO: if ((flag & FWRITE) == 0) return (EBADF); error = setdisklabel(sc->sc_dk.dk_label, (struct disklabel *)data, /*sd->sc_dk.dk_openmask : */0, sc->sc_dk.dk_cpulabel); if (error == 0) { error = writedisklabel(DISKLABELDEV(dev), prestostrategy, sc->sc_dk.dk_label, sc->sc_dk.dk_cpulabel); } return (error); default: return (EINVAL); } }
int wdioctl(dev_t dev, u_long xfer, caddr_t addr, int flag, struct proc *p) { struct wd_softc *wd; struct disklabel *lp; int error = 0; WDCDEBUG_PRINT(("wdioctl\n"), DEBUG_FUNCS); wd = wdlookup(DISKUNIT(dev)); if (wd == NULL) return ENXIO; if ((wd->sc_flags & WDF_LOADED) == 0) { error = EIO; goto exit; } switch (xfer) { case DIOCRLDINFO: lp = malloc(sizeof(*lp), M_TEMP, M_WAITOK); wdgetdisklabel(dev, wd, lp, 0); bcopy(lp, wd->sc_dk.dk_label, sizeof(*lp)); free(lp, M_TEMP, 0); goto exit; case DIOCGPDINFO: wdgetdisklabel(dev, wd, (struct disklabel *)addr, 1); goto exit; case DIOCGDINFO: *(struct disklabel *)addr = *(wd->sc_dk.dk_label); goto exit; case DIOCGPART: ((struct partinfo *)addr)->disklab = wd->sc_dk.dk_label; ((struct partinfo *)addr)->part = &wd->sc_dk.dk_label->d_partitions[DISKPART(dev)]; goto exit; case DIOCWDINFO: case DIOCSDINFO: if ((flag & FWRITE) == 0) { error = EBADF; goto exit; } if ((error = disk_lock(&wd->sc_dk)) != 0) goto exit; error = setdisklabel(wd->sc_dk.dk_label, (struct disklabel *)addr, wd->sc_dk.dk_openmask); if (error == 0) { if (wd->drvp->state > RECAL) wd->drvp->drive_flags |= DRIVE_RESET; if (xfer == DIOCWDINFO) error = writedisklabel(DISKLABELDEV(dev), wdstrategy, wd->sc_dk.dk_label); } disk_unlock(&wd->sc_dk); goto exit; #ifdef notyet case DIOCWFORMAT: if ((flag & FWRITE) == 0) return EBADF; { struct format_op *fop; struct iovec aiov; struct uio auio; fop = (struct format_op *)addr; aiov.iov_base = fop->df_buf; aiov.iov_len = fop->df_count; auio.uio_iov = &aiov; auio.uio_iovcnt = 1; auio.uio_resid = fop->df_count; auio.uio_segflg = 0; auio.uio_offset = fop->df_startblk * wd->sc_dk.dk_label->d_secsize; auio.uio_procp = p; error = physio(wdformat, dev, B_WRITE, minphys, &auio); fop->df_count -= auio.uio_resid; fop->df_reg[0] = wdc->sc_status; fop->df_reg[1] = wdc->sc_error; goto exit; } #endif default: error = wdc_ioctl(wd->drvp, xfer, addr, flag, p); goto exit; } #ifdef DIAGNOSTIC panic("wdioctl: impossible"); #endif exit: device_unref(&wd->sc_dev); return (error); }
int fdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l) { struct fd_softc *fd = device_lookup_private(&fd_cd, FDUNIT(dev)); struct fdformat_parms *form_parms; struct fdformat_cmd *form_cmd; struct ne7_fd_formb *fd_formb; struct disklabel buffer; int error; unsigned int scratch; int il[FD_MAX_NSEC + 1]; int i, j; #ifdef __HAVE_OLD_DISKLABEL struct disklabel newlabel; #endif switch (cmd) { case DIOCGDINFO: #ifdef __HAVE_OLD_DISKLABEL case ODIOCGDINFO: #endif memset(&buffer, 0, sizeof(buffer)); buffer.d_secpercyl = fd->sc_type->seccyl; buffer.d_type = DTYPE_FLOPPY; buffer.d_secsize = FDC_BSIZE; if (readdisklabel(dev, fdstrategy, &buffer, NULL) != NULL) return EINVAL; #ifdef __HAVE_OLD_DISKLABEL if (cmd == ODIOCGDINFO) { if (buffer.d_npartitions > OLDMAXPARTITIONS) return ENOTTY; memcpy(addr, &buffer, sizeof (struct olddisklabel)); } else #endif *(struct disklabel *)addr = buffer; return 0; case DIOCWLABEL: if ((flag & FWRITE) == 0) return EBADF; /* XXX do something */ return 0; case DIOCWDINFO: #ifdef __HAVE_OLD_DISKLABEL case ODIOCWDINFO: #endif { struct disklabel *lp; if ((flag & FWRITE) == 0) return EBADF; #ifdef __HAVE_OLD_DISKLABEL if (cmd == ODIOCWDINFO) { memset(&newlabel, 0, sizeof newlabel); memcpy(&newlabel, addr, sizeof (struct olddisklabel)); lp = &newlabel; } else #endif lp = (struct disklabel *)addr; error = setdisklabel(&buffer, lp, 0, NULL); if (error) return error; error = writedisklabel(dev, fdstrategy, &buffer, NULL); return error; } case FDIOCGETFORMAT: form_parms = (struct fdformat_parms *)addr; form_parms->fdformat_version = FDFORMAT_VERSION; form_parms->nbps = 128 * (1 << fd->sc_type->secsize); form_parms->ncyl = fd->sc_type->cyls; form_parms->nspt = fd->sc_type->sectrac; form_parms->ntrk = fd->sc_type->heads; form_parms->stepspercyl = fd->sc_type->step; form_parms->gaplen = fd->sc_type->gap2; form_parms->fillbyte = fd->sc_type->fillbyte; form_parms->interleave = fd->sc_type->interleave; switch (fd->sc_type->rate) { case FDC_500KBPS: form_parms->xfer_rate = 500 * 1024; break; case FDC_300KBPS: form_parms->xfer_rate = 300 * 1024; break; case FDC_250KBPS: form_parms->xfer_rate = 250 * 1024; break; default: return EINVAL; } return 0; case FDIOCSETFORMAT: if((flag & FWRITE) == 0) return EBADF; /* must be opened for writing */ form_parms = (struct fdformat_parms *)addr; if (form_parms->fdformat_version != FDFORMAT_VERSION) return EINVAL; /* wrong version of formatting prog */ scratch = form_parms->nbps >> 7; if ((form_parms->nbps & 0x7f) || ffs(scratch) == 0 || scratch & ~(1 << (ffs(scratch)-1))) /* not a power-of-two multiple of 128 */ return EINVAL; switch (form_parms->xfer_rate) { case 500 * 1024: fd->sc_type->rate = FDC_500KBPS; break; case 300 * 1024: fd->sc_type->rate = FDC_300KBPS; break; case 250 * 1024: fd->sc_type->rate = FDC_250KBPS; break; default: return EINVAL; } if (form_parms->nspt > FD_MAX_NSEC || form_parms->fillbyte > 0xff || form_parms->interleave > 0xff) return EINVAL; fd->sc_type->sectrac = form_parms->nspt; if (form_parms->ntrk != 2 && form_parms->ntrk != 1) return EINVAL; fd->sc_type->heads = form_parms->ntrk; fd->sc_type->seccyl = form_parms->nspt * form_parms->ntrk; fd->sc_type->secsize = ffs(scratch)-1; fd->sc_type->gap2 = form_parms->gaplen; fd->sc_type->cyls = form_parms->ncyl; fd->sc_type->size = fd->sc_type->seccyl * form_parms->ncyl * form_parms->nbps / DEV_BSIZE; fd->sc_type->step = form_parms->stepspercyl; fd->sc_type->fillbyte = form_parms->fillbyte; fd->sc_type->interleave = form_parms->interleave; return 0; case FDIOCFORMAT_TRACK: if((flag & FWRITE) == 0) return EBADF; /* must be opened for writing */ form_cmd = (struct fdformat_cmd *)addr; if (form_cmd->formatcmd_version != FDFORMAT_VERSION) return EINVAL; /* wrong version of formatting prog */ if (form_cmd->head >= fd->sc_type->heads || form_cmd->cylinder >= fd->sc_type->cyls) { return EINVAL; } fd_formb = malloc(sizeof(struct ne7_fd_formb), M_TEMP, M_NOWAIT); if (fd_formb == 0) return ENOMEM; fd_formb->head = form_cmd->head; fd_formb->cyl = form_cmd->cylinder; fd_formb->transfer_rate = fd->sc_type->rate; fd_formb->fd_formb_secshift = fd->sc_type->secsize; fd_formb->fd_formb_nsecs = fd->sc_type->sectrac; fd_formb->fd_formb_gaplen = fd->sc_type->gap2; fd_formb->fd_formb_fillbyte = fd->sc_type->fillbyte; memset(il, 0, sizeof il); for (j = 0, i = 1; i <= fd_formb->fd_formb_nsecs; i++) { while (il[(j%fd_formb->fd_formb_nsecs)+1]) j++; il[(j%fd_formb->fd_formb_nsecs)+1] = i; j += fd->sc_type->interleave; } for (i = 0; i < fd_formb->fd_formb_nsecs; i++) { fd_formb->fd_formb_cylno(i) = form_cmd->cylinder; fd_formb->fd_formb_headno(i) = form_cmd->head; fd_formb->fd_formb_secno(i) = il[i+1]; fd_formb->fd_formb_secsize(i) = fd->sc_type->secsize; } error = fdformat(dev, fd_formb, l); free(fd_formb, M_TEMP); return error; case FDIOCGETOPTS: /* get drive options */ *(int *)addr = fd->sc_opts; return 0; case FDIOCSETOPTS: /* set drive options */ fd->sc_opts = *(int *)addr; return 0; default: return ENOTTY; } #ifdef DIAGNOSTIC panic("fdioctl: impossible"); #endif }
int ccdioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) { int unit = ccdunit(dev); int i, j, lookedup = 0, error = 0; int part, pmask, s; struct ccd_softc *cs; struct ccd_ioctl *ccio = (struct ccd_ioctl *)data; struct ccddevice ccd; char **cpp; struct vnode **vpp; vaddr_t min, max; if (unit >= numccd) return (ENXIO); cs = &ccd_softc[unit]; if (cmd != CCDIOCSET && !(cs->sc_flags & CCDF_INITED)) return (ENXIO); /* access control */ switch (cmd) { case CCDIOCSET: case CCDIOCCLR: case DIOCWDINFO: case DIOCSDINFO: case DIOCWLABEL: if ((flag & FWRITE) == 0) return (EBADF); } bzero(&ccd, sizeof(ccd)); switch (cmd) { case CCDIOCSET: if (cs->sc_flags & CCDF_INITED) return (EBUSY); if (ccio->ccio_ndisks == 0 || ccio->ccio_ndisks > INT_MAX || ccio->ccio_ileave < 0) return (EINVAL); if ((error = ccdlock(cs)) != 0) return (error); /* Fill in some important bits. */ ccd.ccd_unit = unit; ccd.ccd_interleave = ccio->ccio_ileave; ccd.ccd_flags = ccio->ccio_flags & CCDF_USERMASK; /* XXX the new code is unstable still */ ccd.ccd_flags |= CCDF_OLD; /* * Interleaving which is not a multiple of the click size * must use the old I/O code (by design) */ if (ccio->ccio_ileave % (PAGE_SIZE / DEV_BSIZE) != 0) ccd.ccd_flags |= CCDF_OLD; /* * Allocate space for and copy in the array of * componet pathnames and device numbers. */ cpp = malloc(ccio->ccio_ndisks * sizeof(char *), M_DEVBUF, M_WAITOK); vpp = malloc(ccio->ccio_ndisks * sizeof(struct vnode *), M_DEVBUF, M_WAITOK); error = copyin((caddr_t)ccio->ccio_disks, (caddr_t)cpp, ccio->ccio_ndisks * sizeof(char **)); if (error) { free(vpp, M_DEVBUF); free(cpp, M_DEVBUF); ccdunlock(cs); return (error); } for (i = 0; i < ccio->ccio_ndisks; ++i) { CCD_DPRINTF(CCDB_INIT, ("ccdioctl: component %d: %p, lookedup = %d\n", i, cpp[i], lookedup)); if ((error = ccdlookup(cpp[i], p, &vpp[i])) != 0) { for (j = 0; j < lookedup; ++j) (void)vn_close(vpp[j], FREAD|FWRITE, p->p_ucred, p); free(vpp, M_DEVBUF); free(cpp, M_DEVBUF); ccdunlock(cs); return (error); } ++lookedup; } ccd.ccd_cpp = cpp; ccd.ccd_vpp = vpp; ccd.ccd_ndev = ccio->ccio_ndisks; /* * Initialize the ccd. Fills in the softc for us. */ if ((error = ccdinit(&ccd, cpp, p)) != 0) { for (j = 0; j < lookedup; ++j) (void)vn_close(vpp[j], FREAD|FWRITE, p->p_ucred, p); bzero(&ccd_softc[unit], sizeof(struct ccd_softc)); free(vpp, M_DEVBUF); free(cpp, M_DEVBUF); ccdunlock(cs); return (error); } /* * The ccd has been successfully initialized, so * we can place it into the array. Don't try to * read the disklabel until the disk has been attached, * because space for the disklabel is allocated * in disk_attach(); */ bcopy(&ccd, &ccddevs[unit], sizeof(ccd)); ccio->ccio_unit = unit; ccio->ccio_size = cs->sc_size; /* * If we use the optimized protocol we need some kvm space * for the component buffers. Allocate it here. * * XXX I'd like to have a more dynamic way of acquiring kvm * XXX space, but that is problematic as we are not allowed * XXX to lock the kernel_map in interrupt context. It is * XXX doable via a freelist implementation though. */ if (!ccdmap && !(ccd.ccd_flags & CCDF_OLD)) { min = vm_map_min(kernel_map); ccdmap = uvm_km_suballoc(kernel_map, &min, &max, CCD_CLUSTERS * MAXBSIZE, VM_MAP_INTRSAFE, FALSE, NULL); } /* Attach the disk. */ cs->sc_dkdev.dk_name = cs->sc_xname; disk_attach(&cs->sc_dkdev); /* Try and read the disklabel. */ ccdgetdisklabel(dev, cs, cs->sc_dkdev.dk_label, cs->sc_dkdev.dk_cpulabel, 0); ccdunlock(cs); break; case CCDIOCCLR: if ((error = ccdlock(cs)) != 0) return (error); /* * Don't unconfigure if any other partitions are open * or if both the character and block flavors of this * partition are open. */ part = DISKPART(dev); pmask = (1 << part); if ((cs->sc_dkdev.dk_openmask & ~pmask) || ((cs->sc_dkdev.dk_bopenmask & pmask) && (cs->sc_dkdev.dk_copenmask & pmask))) { ccdunlock(cs); return (EBUSY); } /* * Free ccd_softc information and clear entry. */ /* Close the components and free their pathnames. */ for (i = 0; i < cs->sc_nccdisks; ++i) { /* * XXX: this close could potentially fail and * cause Bad Things. Maybe we need to force * the close to happen? */ #ifdef DIAGNOSTIC CCD_DCALL(CCDB_VNODE, vprint("CCDIOCCLR: vnode info", cs->sc_cinfo[i].ci_vp)); #endif (void)vn_close(cs->sc_cinfo[i].ci_vp, FREAD|FWRITE, p->p_ucred, p); free(cs->sc_cinfo[i].ci_path, M_DEVBUF); } /* Free interleave index. */ for (i = 0; cs->sc_itable[i].ii_ndisk; ++i) free(cs->sc_itable[i].ii_index, M_DEVBUF); /* Free component info and interleave table. */ free(cs->sc_cinfo, M_DEVBUF); free(cs->sc_itable, M_DEVBUF); cs->sc_flags &= ~CCDF_INITED; /* * Free ccddevice information and clear entry. */ free(ccddevs[unit].ccd_cpp, M_DEVBUF); free(ccddevs[unit].ccd_vpp, M_DEVBUF); bcopy(&ccd, &ccddevs[unit], sizeof(ccd)); /* Detatch the disk. */ disk_detach(&cs->sc_dkdev); /* This must be atomic. */ s = splhigh(); ccdunlock(cs); bzero(cs, sizeof(struct ccd_softc)); splx(s); break; case DIOCGPDINFO: { struct cpu_disklabel osdep; if ((error = ccdlock(cs)) != 0) return (error); ccdgetdisklabel(dev, cs, (struct disklabel *)data, &osdep, 1); ccdunlock(cs); break; } case DIOCGDINFO: *(struct disklabel *)data = *(cs->sc_dkdev.dk_label); break; case DIOCGPART: ((struct partinfo *)data)->disklab = cs->sc_dkdev.dk_label; ((struct partinfo *)data)->part = &cs->sc_dkdev.dk_label->d_partitions[DISKPART(dev)]; break; case DIOCWDINFO: case DIOCSDINFO: if ((error = ccdlock(cs)) != 0) return (error); cs->sc_flags |= CCDF_LABELLING; error = setdisklabel(cs->sc_dkdev.dk_label, (struct disklabel *)data, 0, cs->sc_dkdev.dk_cpulabel); if (error == 0) { if (cmd == DIOCWDINFO) error = writedisklabel(CCDLABELDEV(dev), ccdstrategy, cs->sc_dkdev.dk_label, cs->sc_dkdev.dk_cpulabel); } cs->sc_flags &= ~CCDF_LABELLING; ccdunlock(cs); if (error) return (error); break; case DIOCWLABEL: if (*(int *)data != 0) cs->sc_flags |= CCDF_WLABEL; else cs->sc_flags &= ~CCDF_WLABEL; break; default: return (ENOTTY); } return (0); }
/* * The ioctl routine. */ int hd_ioctl(dev_t dev, int cmd, caddr_t addr, int flag) { u_int major = major(dev); u_int unit = dkunit(dev); u_int part = dkpart(dev); struct disk *du; int error = 0; #ifdef MONITOR printf("hd_ioctl: Called with dev=%d, cmd=0x%x, flag=%d by %s\n", dev,cmd,flag,myprocname(returnlink_(dev))); printf("DIOCGDINFO:%x DIOCGPART:%x DIOCSDINFO:%x \n\tDIOCWLABEL:%x DIOCWDINFO:%x\n", DIOCGDINFO,DIOCGPART,DIOCSDINFO,DIOCWLABEL,DIOCWDINFO); #endif if ((unit >= MAXDISKS) || (part >= MAXPARTITIONS)) return(ENXIO); du = &hd[major].disk[unit]; switch(cmd) { case DIOCGDINFO: *(struct disklabel *)addr = du->dk_lab; #ifdef DEBUG printf("hd_ioctl: dev_bsize = %d\n",du->dk_lab.d_secsize); #endif break; case DIOCGPART: ((struct partinfo *)addr)->disklab = &du->dk_lab; ((struct partinfo *)addr)->part = &du->dk_lab.d_partitions[part]; break; case DIOCSDINFO: if ((flag & FWRITE) == 0) error = EBADF; else error = setdisklabel(&du->dk_lab, (struct disklabel *)addr,0); /* XXX AMS Set this info at controller as well. */ break; case DIOCWLABEL: if ((flag & FWRITE) == 0) error = EBADF; else du->dk_wlabel = *(int *)addr; break; case DIOCWDINFO: if ((flag & FWRITE) == 0) { error = EBADF; } else if ((error = setdisklabel(&du->dk_lab, (struct disklabel *)addr,0)) == 0) { int wlab; /* XXX AMS Set this info at controller as well. */ wlab = du->dk_wlabel; du->dk_wlabel = 1; error = writedisklabel(dev,hd_strategy, &du->dk_lab,part); du->dk_wlabel = wlab; } break; default: error = ENOTTY; break; } return(error); }
int dk_ioctl(struct dk_softc *dksc, dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) { const struct dkdriver *dkd = dksc->sc_dkdev.dk_driver; struct disklabel *lp; struct disk *dk = &dksc->sc_dkdev; #ifdef __HAVE_OLD_DISKLABEL struct disklabel newlabel; #endif int error; DPRINTF_FOLLOW(("%s(%s, %p, 0x%"PRIx64", 0x%lx)\n", __func__, dksc->sc_xname, dksc, dev, cmd)); /* ensure that the pseudo disk is open for writes for these commands */ switch (cmd) { case DIOCSDINFO: case DIOCWDINFO: #ifdef __HAVE_OLD_DISKLABEL case ODIOCSDINFO: case ODIOCWDINFO: #endif case DIOCKLABEL: case DIOCWLABEL: case DIOCAWEDGE: case DIOCDWEDGE: case DIOCSSTRATEGY: if ((flag & FWRITE) == 0) return EBADF; } /* ensure that the pseudo-disk is initialized for these */ switch (cmd) { case DIOCGDINFO: case DIOCSDINFO: case DIOCWDINFO: case DIOCGPARTINFO: case DIOCKLABEL: case DIOCWLABEL: case DIOCGDEFLABEL: case DIOCAWEDGE: case DIOCDWEDGE: case DIOCLWEDGES: case DIOCMWEDGES: case DIOCCACHESYNC: #ifdef __HAVE_OLD_DISKLABEL case ODIOCGDINFO: case ODIOCSDINFO: case ODIOCWDINFO: case ODIOCGDEFLABEL: #endif if ((dksc->sc_flags & DKF_INITED) == 0) return ENXIO; } error = disk_ioctl(dk, dev, cmd, data, flag, l); if (error != EPASSTHROUGH) return error; else error = 0; switch (cmd) { case DIOCWDINFO: case DIOCSDINFO: #ifdef __HAVE_OLD_DISKLABEL case ODIOCWDINFO: case ODIOCSDINFO: #endif #ifdef __HAVE_OLD_DISKLABEL if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) { memset(&newlabel, 0, sizeof newlabel); memcpy(&newlabel, data, sizeof (struct olddisklabel)); lp = &newlabel; } else #endif lp = (struct disklabel *)data; mutex_enter(&dk->dk_openlock); dksc->sc_flags |= DKF_LABELLING; error = setdisklabel(dksc->sc_dkdev.dk_label, lp, 0, dksc->sc_dkdev.dk_cpulabel); if (error == 0) { if (cmd == DIOCWDINFO #ifdef __HAVE_OLD_DISKLABEL || cmd == ODIOCWDINFO #endif ) error = writedisklabel(DKLABELDEV(dev), dkd->d_strategy, dksc->sc_dkdev.dk_label, dksc->sc_dkdev.dk_cpulabel); } dksc->sc_flags &= ~DKF_LABELLING; mutex_exit(&dk->dk_openlock); break; case DIOCKLABEL: if (*(int *)data != 0) dksc->sc_flags |= DKF_KLABEL; else dksc->sc_flags &= ~DKF_KLABEL; break; case DIOCWLABEL: if (*(int *)data != 0) dksc->sc_flags |= DKF_WLABEL; else dksc->sc_flags &= ~DKF_WLABEL; break; case DIOCGDEFLABEL: dk_getdefaultlabel(dksc, (struct disklabel *)data); break; #ifdef __HAVE_OLD_DISKLABEL case ODIOCGDEFLABEL: dk_getdefaultlabel(dksc, &newlabel); if (newlabel.d_npartitions > OLDMAXPARTITIONS) return ENOTTY; memcpy(data, &newlabel, sizeof (struct olddisklabel)); break; #endif case DIOCGSTRATEGY: { struct disk_strategy *dks = (void *)data; mutex_enter(&dksc->sc_iolock); strlcpy(dks->dks_name, bufq_getstrategyname(dksc->sc_bufq), sizeof(dks->dks_name)); mutex_exit(&dksc->sc_iolock); dks->dks_paramlen = 0; return 0; } case DIOCSSTRATEGY: { struct disk_strategy *dks = (void *)data; struct bufq_state *new; struct bufq_state *old; if (dks->dks_param != NULL) { return EINVAL; } dks->dks_name[sizeof(dks->dks_name) - 1] = 0; /* ensure term */ error = bufq_alloc(&new, dks->dks_name, BUFQ_EXACT|BUFQ_SORT_RAWBLOCK); if (error) { return error; } mutex_enter(&dksc->sc_iolock); old = dksc->sc_bufq; bufq_move(new, old); dksc->sc_bufq = new; mutex_exit(&dksc->sc_iolock); bufq_free(old); return 0; } default: error = ENOTTY; } return error; }
int maruioctl (dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) { ENTERSC(dev); DB("maruioctl(%d, %ld, %p, %d, %p)\n", dev, cmd, data, flag, p); switch (cmd) { case MARUIOCATTACH: { struct maru_ioc_attach *ma = (struct maru_ioc_attach *)data; int fd = ma->ma_kue_fd; struct filedesc *fdp = p->p_fd; struct file *fp; int err; struct stat st; struct kue_kapi *kapi; if (ma->ma_size < 512 * 16 * 32) EXITSC(EINVAL); if (fd>=fdp->fd_nfiles || (fp=fdp->fd_ofiles[fd]) == NULL) EXITSC(EBADF); if (fp->f_type != DTYPE_VNODE) EXITSC(ENOENT); /* some fool handed us a socket */ /* ok, so, this is cheating a little :) */ err = vn_stat((struct vnode *)fp->f_data, &st, p); if (err) EXITSC(err); /* pull in a pointer to the kue kernel api. we need * this hack in order to avoid nasty limitations in netbsd's * kernel linker: symbols from one module * are not linked against symbols from another, only * the kernel image. we splinter a little wood */ err = fp->f_ops->fo_ioctl(fp, KUEIOCGKAPI, (caddr_t)&kapi, p); DB("post ioctl"); if (err) EXITSC(err); DB("post ioctl:2"); /* now install our hooks of evil */ sc->sc_kapi = kapi; DB("post ioctl:3"); kapi->ka_read2_hook = maru_kue_read2_callback; DB("post ioctl:4"); kapi->ka_free_hook = maru_kue_free_callback; kapi->ka_write_hook = maru_kue_write_callback; disk_attach(&sc->sc_dkdev); memcpy(&sc->sc_size, &ma->ma_size, sizeof sc->sc_size); sc->sc_flags|=MUF_INITED; maru_getdisklabel(sc); } break; case DIOCGDINFO: maru_getdefaultlabel(sc, (struct disklabel*)data); break; case DIOCGPART: ((struct partinfo *)data)->disklab = sc->sc_dkdev.dk_label; ((struct partinfo *)data)->part = &sc->sc_dkdev.dk_label->d_partitions[DISKPART(dev)]; break; case DIOCWDINFO: case DIOCSDINFO: { int err; sc->sc_flags |= MUF_LABELING; /* marustrategy maybe called by writedisklabel() */ err = setdisklabel(sc->sc_dkdev.dk_label, (struct disklabel *)data, 0, sc->sc_dkdev.dk_cpulabel); if (!err) { if (cmd == DIOCWDINFO) err = writedisklabel(MARULABELDEV(dev), marustrategy, sc->sc_dkdev.dk_label, sc->sc_dkdev.dk_cpulabel); } sc->sc_flags &= ~MUF_LABELING; if (err) EXITSC(err); } break; case DIOCWLABEL: if (*(int *)data != 0) sc->sc_flags |= MUF_WLABEL; else sc->sc_flags &= ~MUF_WLABEL; break; case DIOCGDEFLABEL: maru_getdefaultlabel(sc, (struct disklabel*)data); break; default: return (ENOTTY); } EXITSC(0); }
int ofdisk_ioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) { struct ofdisk_softc *of = device_lookup_private(&ofdisk_cd, DISKUNIT(dev)); int error; #ifdef __HAVE_OLD_DISKLABEL struct disklabel newlabel; #endif switch (cmd) { case DIOCGDINFO: *(struct disklabel *)data = *of->sc_dk.dk_label; return 0; #ifdef __HAVE_OLD_DISKLABEL case ODIOCGDINFO: newlabel = *of->sc_dk.dk_label; if (newlabel.d_npartitions > OLDMAXPARTITIONS) return ENOTTY; memcpy(data, &newlabel, sizeof (struct olddisklabel)); return 0; #endif case DIOCGPART: ((struct partinfo *)data)->disklab = of->sc_dk.dk_label; ((struct partinfo *)data)->part = &of->sc_dk.dk_label->d_partitions[DISKPART(dev)]; return 0; case DIOCWDINFO: case DIOCSDINFO: #ifdef __HAVE_OLD_DISKLABEL case ODIOCWDINFO: case ODIOCSDINFO: #endif { struct disklabel *lp; #ifdef __HAVE_OLD_DISKLABEL if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) { memset(&newlabel, 0, sizeof newlabel); memcpy(&newlabel, data, sizeof (struct olddisklabel)); lp = &newlabel; } else #endif lp = (struct disklabel *)data; if ((flag & FWRITE) == 0) return EBADF; mutex_enter(&of->sc_dk.dk_openlock); error = setdisklabel(of->sc_dk.dk_label, lp, /*of->sc_dk.dk_openmask */0, of->sc_dk.dk_cpulabel); if (error == 0 && cmd == DIOCWDINFO #ifdef __HAVE_OLD_DISKLABEL || xfer == ODIOCWDINFO #endif ) error = writedisklabel(MAKEDISKDEV(major(dev), DISKUNIT(dev), RAW_PART), ofdisk_strategy, of->sc_dk.dk_label, of->sc_dk.dk_cpulabel); mutex_exit(&of->sc_dk.dk_openlock); return error; } case DIOCGDEFLABEL: ofdisk_getdefaultlabel(of, (struct disklabel *)data); return 0; #ifdef __HAVE_OLD_DISKLABEL case DIOCGDEFLABEL: ofdisk_getdefaultlabel(of, &newlabel); if (newlabel.d_npartitions > OLDMAXPARTITIONS) return ENOTTY; memcpy(data, &newlabel, sizeof (struct olddisklabel)); return 0; #endif case DIOCAWEDGE: { struct dkwedge_info *dkw = (void *) data; if (OFDISK_FLOPPY_P(of)) return (ENOTTY); if ((flag & FWRITE) == 0) return (EBADF); /* If the ioctl happens here, the parent is us. */ strlcpy(dkw->dkw_parent, device_xname(of->sc_dev), sizeof(dkw->dkw_parent)); return (dkwedge_add(dkw)); } case DIOCDWEDGE: { struct dkwedge_info *dkw = (void *) data; if (OFDISK_FLOPPY_P(of)) return (ENOTTY); if ((flag & FWRITE) == 0) return (EBADF); /* If the ioctl happens here, the parent is us. */ strlcpy(dkw->dkw_parent, device_xname(of->sc_dev), sizeof(dkw->dkw_parent)); return (dkwedge_del(dkw)); } case DIOCLWEDGES: { struct dkwedge_list *dkwl = (void *) data; if (OFDISK_FLOPPY_P(of)) return (ENOTTY); return (dkwedge_list(&of->sc_dk, dkwl, l)); } default: return ENOTTY; } }
int fdioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) { struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)]; struct disklabel *lp; int error; switch (cmd) { case MTIOCTOP: if (((struct mtop *)addr)->mt_op != MTOFFL) return EIO; return (0); case DIOCRLDINFO: lp = malloc(sizeof(*lp), M_TEMP, M_WAITOK); fdgetdisklabel(dev, fd, lp, 0); bcopy(lp, fd->sc_dk.dk_label, sizeof(*lp)); free(lp, M_TEMP); return 0; case DIOCGPDINFO: fdgetdisklabel(dev, fd, (struct disklabel *)addr, 1); return 0; case DIOCGDINFO: *(struct disklabel *)addr = *(fd->sc_dk.dk_label); return 0; case DIOCGPART: ((struct partinfo *)addr)->disklab = fd->sc_dk.dk_label; ((struct partinfo *)addr)->part = &fd->sc_dk.dk_label->d_partitions[FDPART(dev)]; return 0; case DIOCWDINFO: case DIOCSDINFO: if ((flag & FWRITE) == 0) return EBADF; error = setdisklabel(fd->sc_dk.dk_label, (struct disklabel *)addr, 0); if (error == 0) { if (cmd == DIOCWDINFO) error = writedisklabel(DISKLABELDEV(dev), fdstrategy, fd->sc_dk.dk_label); } return error; case FD_FORM: if((flag & FWRITE) == 0) return EBADF; /* must be opened for writing */ else if(((struct fd_formb *)addr)->format_version != FD_FORMAT_VERSION) return EINVAL; /* wrong version of formatting prog */ else return fdformat(dev, (struct fd_formb *)addr, p); break; case FD_GTYPE: /* get drive type */ *(struct fd_type *)addr = *fd->sc_type; return 0; case FD_GOPTS: /* get drive options */ *(int *)addr = fd->sc_opts; return 0; case FD_SOPTS: /* set drive options */ fd->sc_opts = *(int *)addr; return 0; default: return ENOTTY; } #ifdef DIAGNOSTIC panic("fdioctl: impossible"); #endif }
/* * I/O controls. */ int raioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) { struct disklabel *lp, *tp; struct ra_softc *ra = mscp_device_lookup(dev); int error = 0; #ifdef __HAVE_OLD_DISKLABEL struct disklabel newlabel; #endif lp = ra->ra_disk.dk_label; switch (cmd) { case DIOCGDINFO: memcpy(data, lp, sizeof (struct disklabel)); break; #ifdef __HAVE_OLD_DISKLABEL case ODIOCGDINFO: memcpy(&newlabel, lp, sizeof newlabel); if (newlabel.d_npartitions > OLDMAXPARTITIONS) return ENOTTY; memcpy(data, &newlabel, sizeof (struct olddisklabel)); break; #endif case DIOCGPART: ((struct partinfo *)data)->disklab = lp; ((struct partinfo *)data)->part = &lp->d_partitions[DISKPART(dev)]; break; case DIOCWDINFO: case DIOCSDINFO: #ifdef __HAVE_OLD_DISKLABEL case ODIOCWDINFO: case ODIOCSDINFO: if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) { memset(&newlabel, 0, sizeof newlabel); memcpy(&newlabel, data, sizeof (struct olddisklabel)); tp = &newlabel; } else #endif tp = (struct disklabel *)data; if ((flag & FWRITE) == 0) error = EBADF; else { mutex_enter(&ra->ra_disk.dk_openlock); error = setdisklabel(lp, tp, 0, 0); if ((error == 0) && (cmd == DIOCWDINFO #ifdef __HAVE_OLD_DISKLABEL || cmd == ODIOCWDINFO #endif )) { ra->ra_wlabel = 1; error = writedisklabel(dev, rastrategy, lp,0); ra->ra_wlabel = 0; } mutex_exit(&ra->ra_disk.dk_openlock); } break; case DIOCWLABEL: if ((flag & FWRITE) == 0) error = EBADF; else ra->ra_wlabel = 1; break; case DIOCGDEFLABEL: #ifdef __HAVE_OLD_DISKLABEL case ODIOCGDEFLABEL: if (cmd == ODIOCGDEFLABEL) tp = &newlabel; else #endif tp = (struct disklabel *)data; memset(tp, 0, sizeof(struct disklabel)); tp->d_secsize = lp->d_secsize; tp->d_nsectors = lp->d_nsectors; tp->d_ntracks = lp->d_ntracks; tp->d_ncylinders = lp->d_ncylinders; tp->d_secpercyl = lp->d_secpercyl; tp->d_secperunit = lp->d_secperunit; tp->d_type = DTYPE_MSCP; tp->d_rpm = 3600; rrmakelabel(tp, ra->ra_mediaid); #ifdef __HAVE_OLD_DISKLABEL if (cmd == ODIOCGDEFLABEL) { if (tp->d_npartitions > OLDMAXPARTITIONS) return ENOTTY; memcpy(data, tp, sizeof (struct olddisklabel)); } #endif break; case DIOCAWEDGE: { struct dkwedge_info *dkw = (void *) data; if ((flag & FWRITE) == 0) return (EBADF); /* If the ioctl happens here, the parent is us. */ strlcpy(dkw->dkw_parent, device_xname(ra->ra_dev), sizeof(dkw->dkw_parent)); return (dkwedge_add(dkw)); } case DIOCDWEDGE: { struct dkwedge_info *dkw = (void *) data; if ((flag & FWRITE) == 0) return (EBADF); /* If the ioctl happens here, the parent is us. */ strlcpy(dkw->dkw_parent, device_xname(ra->ra_dev), sizeof(dkw->dkw_parent)); return (dkwedge_del(dkw)); } case DIOCLWEDGES: { struct dkwedge_list *dkwl = (void *) data; return (dkwedge_list(&ra->ra_disk, dkwl, l)); } default: error = ENOTTY; break; } return (error); }
/* ARGSUSED */ static int vndioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) { bool force; int unit = vndunit(dev); struct vnd_softc *vnd; struct vnd_ioctl *vio; struct vattr vattr; struct pathbuf *pb; struct nameidata nd; int error, part, pmask; uint64_t geomsize; int fflags; #ifdef __HAVE_OLD_DISKLABEL struct disklabel newlabel; #endif struct dkwedge_info *dkw; struct dkwedge_list *dkwl; #ifdef DEBUG if (vnddebug & VDB_FOLLOW) printf("vndioctl(0x%"PRIx64", 0x%lx, %p, 0x%x, %p): unit %d\n", dev, cmd, data, flag, l->l_proc, unit); #endif vnd = device_lookup_private(&vnd_cd, unit); if (vnd == NULL && #ifdef COMPAT_30 cmd != VNDIOCGET30 && #endif #ifdef COMPAT_50 cmd != VNDIOCGET50 && #endif cmd != VNDIOCGET) return ENXIO; vio = (struct vnd_ioctl *)data; /* Must be open for writes for these commands... */ switch (cmd) { case VNDIOCSET: case VNDIOCCLR: #ifdef COMPAT_50 case VNDIOCSET50: case VNDIOCCLR50: #endif case DIOCSDINFO: case DIOCWDINFO: #ifdef __HAVE_OLD_DISKLABEL case ODIOCSDINFO: case ODIOCWDINFO: #endif case DIOCKLABEL: case DIOCWLABEL: if ((flag & FWRITE) == 0) return EBADF; } /* Must be initialized for these... */ switch (cmd) { case VNDIOCCLR: #ifdef VNDIOCCLR50 case VNDIOCCLR50: #endif case DIOCGDINFO: case DIOCSDINFO: case DIOCWDINFO: case DIOCGPART: case DIOCKLABEL: case DIOCWLABEL: case DIOCGDEFLABEL: case DIOCCACHESYNC: #ifdef __HAVE_OLD_DISKLABEL case ODIOCGDINFO: case ODIOCSDINFO: case ODIOCWDINFO: case ODIOCGDEFLABEL: #endif if ((vnd->sc_flags & VNF_INITED) == 0) return ENXIO; } switch (cmd) { #ifdef VNDIOCSET50 case VNDIOCSET50: #endif case VNDIOCSET: if (vnd->sc_flags & VNF_INITED) return EBUSY; if ((error = vndlock(vnd)) != 0) return error; fflags = FREAD; if ((vio->vnd_flags & VNDIOF_READONLY) == 0) fflags |= FWRITE; error = pathbuf_copyin(vio->vnd_file, &pb); if (error) { goto unlock_and_exit; } NDINIT(&nd, LOOKUP, FOLLOW, pb); if ((error = vn_open(&nd, fflags, 0)) != 0) { pathbuf_destroy(pb); goto unlock_and_exit; } KASSERT(l); error = VOP_GETATTR(nd.ni_vp, &vattr, l->l_cred); if (!error && nd.ni_vp->v_type != VREG) error = EOPNOTSUPP; if (!error && vattr.va_bytes < vattr.va_size) /* File is definitely sparse, use vn_rdwr() */ vnd->sc_flags |= VNF_USE_VN_RDWR; if (error) { VOP_UNLOCK(nd.ni_vp); goto close_and_exit; } /* If using a compressed file, initialize its info */ /* (or abort with an error if kernel has no compression) */ if (vio->vnd_flags & VNF_COMP) { #ifdef VND_COMPRESSION struct vnd_comp_header *ch; int i; u_int32_t comp_size; u_int32_t comp_maxsize; /* allocate space for compresed file header */ ch = malloc(sizeof(struct vnd_comp_header), M_TEMP, M_WAITOK); /* read compressed file header */ error = vn_rdwr(UIO_READ, nd.ni_vp, (void *)ch, sizeof(struct vnd_comp_header), 0, UIO_SYSSPACE, IO_UNIT|IO_NODELOCKED, l->l_cred, NULL, NULL); if (error) { free(ch, M_TEMP); VOP_UNLOCK(nd.ni_vp); goto close_and_exit; } /* save some header info */ vnd->sc_comp_blksz = ntohl(ch->block_size); /* note last offset is the file byte size */ vnd->sc_comp_numoffs = ntohl(ch->num_blocks)+1; free(ch, M_TEMP); if (vnd->sc_comp_blksz == 0 || vnd->sc_comp_blksz % DEV_BSIZE !=0) { VOP_UNLOCK(nd.ni_vp); error = EINVAL; goto close_and_exit; } if (sizeof(struct vnd_comp_header) + sizeof(u_int64_t) * vnd->sc_comp_numoffs > vattr.va_size) { VOP_UNLOCK(nd.ni_vp); error = EINVAL; goto close_and_exit; } /* set decompressed file size */ vattr.va_size = ((u_quad_t)vnd->sc_comp_numoffs - 1) * (u_quad_t)vnd->sc_comp_blksz; /* allocate space for all the compressed offsets */ vnd->sc_comp_offsets = malloc(sizeof(u_int64_t) * vnd->sc_comp_numoffs, M_DEVBUF, M_WAITOK); /* read in the offsets */ error = vn_rdwr(UIO_READ, nd.ni_vp, (void *)vnd->sc_comp_offsets, sizeof(u_int64_t) * vnd->sc_comp_numoffs, sizeof(struct vnd_comp_header), UIO_SYSSPACE, IO_UNIT|IO_NODELOCKED, l->l_cred, NULL, NULL); if (error) { VOP_UNLOCK(nd.ni_vp); goto close_and_exit; } /* * find largest block size (used for allocation limit). * Also convert offset to native byte order. */ comp_maxsize = 0; for (i = 0; i < vnd->sc_comp_numoffs - 1; i++) { vnd->sc_comp_offsets[i] = be64toh(vnd->sc_comp_offsets[i]); comp_size = be64toh(vnd->sc_comp_offsets[i + 1]) - vnd->sc_comp_offsets[i]; if (comp_size > comp_maxsize) comp_maxsize = comp_size; } vnd->sc_comp_offsets[vnd->sc_comp_numoffs - 1] = be64toh(vnd->sc_comp_offsets[vnd->sc_comp_numoffs - 1]); /* create compressed data buffer */ vnd->sc_comp_buff = malloc(comp_maxsize, M_DEVBUF, M_WAITOK); /* create decompressed buffer */ vnd->sc_comp_decombuf = malloc(vnd->sc_comp_blksz, M_DEVBUF, M_WAITOK); vnd->sc_comp_buffblk = -1; /* Initialize decompress stream */ memset(&vnd->sc_comp_stream, 0, sizeof(z_stream)); vnd->sc_comp_stream.zalloc = vnd_alloc; vnd->sc_comp_stream.zfree = vnd_free; error = inflateInit2(&vnd->sc_comp_stream, MAX_WBITS); if (error) { if (vnd->sc_comp_stream.msg) printf("vnd%d: compressed file, %s\n", unit, vnd->sc_comp_stream.msg); VOP_UNLOCK(nd.ni_vp); error = EINVAL; goto close_and_exit; } vnd->sc_flags |= VNF_COMP | VNF_READONLY; #else /* !VND_COMPRESSION */ VOP_UNLOCK(nd.ni_vp); error = EOPNOTSUPP; goto close_and_exit; #endif /* VND_COMPRESSION */ } VOP_UNLOCK(nd.ni_vp); vnd->sc_vp = nd.ni_vp; vnd->sc_size = btodb(vattr.va_size); /* note truncation */ /* * Use pseudo-geometry specified. If none was provided, * use "standard" Adaptec fictitious geometry. */ if (vio->vnd_flags & VNDIOF_HASGEOM) { memcpy(&vnd->sc_geom, &vio->vnd_geom, sizeof(vio->vnd_geom)); /* * Sanity-check the sector size. * XXX Don't allow secsize < DEV_BSIZE. Should * XXX we? */ if (vnd->sc_geom.vng_secsize < DEV_BSIZE || (vnd->sc_geom.vng_secsize % DEV_BSIZE) != 0 || vnd->sc_geom.vng_ncylinders == 0 || (vnd->sc_geom.vng_ntracks * vnd->sc_geom.vng_nsectors) == 0) { error = EINVAL; goto close_and_exit; } /* * Compute the size (in DEV_BSIZE blocks) specified * by the geometry. */ geomsize = (vnd->sc_geom.vng_nsectors * vnd->sc_geom.vng_ntracks * vnd->sc_geom.vng_ncylinders) * (vnd->sc_geom.vng_secsize / DEV_BSIZE); /* * Sanity-check the size against the specified * geometry. */ if (vnd->sc_size < geomsize) { error = EINVAL; goto close_and_exit; } } else if (vnd->sc_size >= (32 * 64)) { /* * Size must be at least 2048 DEV_BSIZE blocks * (1M) in order to use this geometry. */ vnd->sc_geom.vng_secsize = DEV_BSIZE; vnd->sc_geom.vng_nsectors = 32; vnd->sc_geom.vng_ntracks = 64; vnd->sc_geom.vng_ncylinders = vnd->sc_size / (64 * 32); } else { vnd->sc_geom.vng_secsize = DEV_BSIZE; vnd->sc_geom.vng_nsectors = 1; vnd->sc_geom.vng_ntracks = 1; vnd->sc_geom.vng_ncylinders = vnd->sc_size; } vnd_set_geometry(vnd); if (vio->vnd_flags & VNDIOF_READONLY) { vnd->sc_flags |= VNF_READONLY; } if ((error = vndsetcred(vnd, l->l_cred)) != 0) goto close_and_exit; vndthrottle(vnd, vnd->sc_vp); vio->vnd_osize = dbtob(vnd->sc_size); #ifdef VNDIOCSET50 if (cmd != VNDIOCSET50) #endif vio->vnd_size = dbtob(vnd->sc_size); vnd->sc_flags |= VNF_INITED; /* create the kernel thread, wait for it to be up */ error = kthread_create(PRI_NONE, 0, NULL, vndthread, vnd, &vnd->sc_kthread, "%s", device_xname(vnd->sc_dev)); if (error) goto close_and_exit; while ((vnd->sc_flags & VNF_KTHREAD) == 0) { tsleep(&vnd->sc_kthread, PRIBIO, "vndthr", 0); } #ifdef DEBUG if (vnddebug & VDB_INIT) printf("vndioctl: SET vp %p size 0x%lx %d/%d/%d/%d\n", vnd->sc_vp, (unsigned long) vnd->sc_size, vnd->sc_geom.vng_secsize, vnd->sc_geom.vng_nsectors, vnd->sc_geom.vng_ntracks, vnd->sc_geom.vng_ncylinders); #endif /* Attach the disk. */ disk_attach(&vnd->sc_dkdev); disk_blocksize(&vnd->sc_dkdev, vnd->sc_geom.vng_secsize); /* Initialize the xfer and buffer pools. */ pool_init(&vnd->sc_vxpool, sizeof(struct vndxfer), 0, 0, 0, "vndxpl", NULL, IPL_BIO); vndunlock(vnd); pathbuf_destroy(pb); /* Discover wedges on this disk */ dkwedge_discover(&vnd->sc_dkdev); break; close_and_exit: (void) vn_close(nd.ni_vp, fflags, l->l_cred); pathbuf_destroy(pb); unlock_and_exit: #ifdef VND_COMPRESSION /* free any allocated memory (for compressed file) */ if (vnd->sc_comp_offsets) { free(vnd->sc_comp_offsets, M_DEVBUF); vnd->sc_comp_offsets = NULL; } if (vnd->sc_comp_buff) { free(vnd->sc_comp_buff, M_DEVBUF); vnd->sc_comp_buff = NULL; } if (vnd->sc_comp_decombuf) { free(vnd->sc_comp_decombuf, M_DEVBUF); vnd->sc_comp_decombuf = NULL; } #endif /* VND_COMPRESSION */ vndunlock(vnd); return error; #ifdef VNDIOCCLR50 case VNDIOCCLR50: #endif case VNDIOCCLR: part = DISKPART(dev); pmask = (1 << part); force = (vio->vnd_flags & VNDIOF_FORCE) != 0; if ((error = vnddoclear(vnd, pmask, minor(dev), force)) != 0) return error; break; #ifdef COMPAT_30 case VNDIOCGET30: { struct vnd_user30 *vnu; struct vattr va; vnu = (struct vnd_user30 *)data; KASSERT(l); switch (error = vnd_cget(l, unit, &vnu->vnu_unit, &va)) { case 0: vnu->vnu_dev = va.va_fsid; vnu->vnu_ino = va.va_fileid; break; case -1: /* unused is not an error */ vnu->vnu_dev = 0; vnu->vnu_ino = 0; break; default: return error; } break; } #endif #ifdef COMPAT_50 case VNDIOCGET50: { struct vnd_user50 *vnu; struct vattr va; vnu = (struct vnd_user50 *)data; KASSERT(l); switch (error = vnd_cget(l, unit, &vnu->vnu_unit, &va)) { case 0: vnu->vnu_dev = va.va_fsid; vnu->vnu_ino = va.va_fileid; break; case -1: /* unused is not an error */ vnu->vnu_dev = 0; vnu->vnu_ino = 0; break; default: return error; } break; } #endif case VNDIOCGET: { struct vnd_user *vnu; struct vattr va; vnu = (struct vnd_user *)data; KASSERT(l); switch (error = vnd_cget(l, unit, &vnu->vnu_unit, &va)) { case 0: vnu->vnu_dev = va.va_fsid; vnu->vnu_ino = va.va_fileid; break; case -1: /* unused is not an error */ vnu->vnu_dev = 0; vnu->vnu_ino = 0; break; default: return error; } break; } case DIOCGDINFO: *(struct disklabel *)data = *(vnd->sc_dkdev.dk_label); break; #ifdef __HAVE_OLD_DISKLABEL case ODIOCGDINFO: newlabel = *(vnd->sc_dkdev.dk_label); if (newlabel.d_npartitions > OLDMAXPARTITIONS) return ENOTTY; memcpy(data, &newlabel, sizeof (struct olddisklabel)); break; #endif case DIOCGPART: ((struct partinfo *)data)->disklab = vnd->sc_dkdev.dk_label; ((struct partinfo *)data)->part = &vnd->sc_dkdev.dk_label->d_partitions[DISKPART(dev)]; break; case DIOCWDINFO: case DIOCSDINFO: #ifdef __HAVE_OLD_DISKLABEL case ODIOCWDINFO: case ODIOCSDINFO: #endif { struct disklabel *lp; if ((error = vndlock(vnd)) != 0) return error; vnd->sc_flags |= VNF_LABELLING; #ifdef __HAVE_OLD_DISKLABEL if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) { memset(&newlabel, 0, sizeof newlabel); memcpy(&newlabel, data, sizeof (struct olddisklabel)); lp = &newlabel; } else #endif lp = (struct disklabel *)data; error = setdisklabel(vnd->sc_dkdev.dk_label, lp, 0, vnd->sc_dkdev.dk_cpulabel); if (error == 0) { if (cmd == DIOCWDINFO #ifdef __HAVE_OLD_DISKLABEL || cmd == ODIOCWDINFO #endif ) error = writedisklabel(VNDLABELDEV(dev), vndstrategy, vnd->sc_dkdev.dk_label, vnd->sc_dkdev.dk_cpulabel); } vnd->sc_flags &= ~VNF_LABELLING; vndunlock(vnd); if (error) return error; break; } case DIOCKLABEL: if (*(int *)data != 0) vnd->sc_flags |= VNF_KLABEL; else vnd->sc_flags &= ~VNF_KLABEL; break; case DIOCWLABEL: if (*(int *)data != 0) vnd->sc_flags |= VNF_WLABEL; else vnd->sc_flags &= ~VNF_WLABEL; break; case DIOCGDEFLABEL: vndgetdefaultlabel(vnd, (struct disklabel *)data); break; #ifdef __HAVE_OLD_DISKLABEL case ODIOCGDEFLABEL: vndgetdefaultlabel(vnd, &newlabel); if (newlabel.d_npartitions > OLDMAXPARTITIONS) return ENOTTY; memcpy(data, &newlabel, sizeof (struct olddisklabel)); break; #endif case DIOCCACHESYNC: vn_lock(vnd->sc_vp, LK_EXCLUSIVE | LK_RETRY); error = VOP_FSYNC(vnd->sc_vp, vnd->sc_cred, FSYNC_WAIT | FSYNC_DATAONLY | FSYNC_CACHE, 0, 0); VOP_UNLOCK(vnd->sc_vp); return error; case DIOCAWEDGE: dkw = (void *) data; if ((flag & FWRITE) == 0) return EBADF; /* If the ioctl happens here, the parent is us. */ strlcpy(dkw->dkw_parent, device_xname(vnd->sc_dev), sizeof(dkw->dkw_parent)); return dkwedge_add(dkw); case DIOCDWEDGE: dkw = (void *) data; if ((flag & FWRITE) == 0) return EBADF; /* If the ioctl happens here, the parent is us. */ strlcpy(dkw->dkw_parent, device_xname(vnd->sc_dev), sizeof(dkw->dkw_parent)); return dkwedge_del(dkw); case DIOCLWEDGES: dkwl = (void *) data; return dkwedge_list(&vnd->sc_dkdev, dkwl, l); default: return ENOTTY; } return 0; }
int dk_ioctl(struct dk_intf *di, struct dk_softc *dksc, dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) { struct disklabel *lp; struct disk *dk; #ifdef __HAVE_OLD_DISKLABEL struct disklabel newlabel; #endif int error = 0; DPRINTF_FOLLOW(("dk_ioctl(%s, %p, 0x%"PRIx64", 0x%lx)\n", di->di_dkname, dksc, dev, cmd)); /* ensure that the pseudo disk is open for writes for these commands */ switch (cmd) { case DIOCSDINFO: case DIOCWDINFO: #ifdef __HAVE_OLD_DISKLABEL case ODIOCSDINFO: case ODIOCWDINFO: #endif case DIOCWLABEL: case DIOCAWEDGE: case DIOCDWEDGE: if ((flag & FWRITE) == 0) return EBADF; } /* ensure that the pseudo-disk is initialized for these */ switch (cmd) { #ifdef DIOCGSECTORSIZE case DIOCGSECTORSIZE: case DIOCGMEDIASIZE: #endif case DIOCGDINFO: case DIOCSDINFO: case DIOCWDINFO: case DIOCGPART: case DIOCWLABEL: case DIOCGDEFLABEL: case DIOCAWEDGE: case DIOCDWEDGE: case DIOCLWEDGES: case DIOCCACHESYNC: #ifdef __HAVE_OLD_DISKLABEL case ODIOCGDINFO: case ODIOCSDINFO: case ODIOCWDINFO: case ODIOCGDEFLABEL: #endif if ((dksc->sc_flags & DKF_INITED) == 0) return ENXIO; } switch (cmd) { #ifdef DIOCGSECTORSIZE case DIOCGSECTORSIZE: *(u_int *)data = dksc->sc_dkdev.dk_geom.dg_secsize; return 0; case DIOCGMEDIASIZE: *(off_t *)data = (off_t)dksc->sc_dkdev.dk_geom.dg_secsize * dksc->sc_dkdev.dk_geom.dg_nsectors; return 0; #endif case DIOCGDINFO: *(struct disklabel *)data = *(dksc->sc_dkdev.dk_label); break; #ifdef __HAVE_OLD_DISKLABEL case ODIOCGDINFO: newlabel = *(dksc->sc_dkdev.dk_label); if (newlabel.d_npartitions > OLDMAXPARTITIONS) return ENOTTY; memcpy(data, &newlabel, sizeof (struct olddisklabel)); break; #endif case DIOCGPART: ((struct partinfo *)data)->disklab = dksc->sc_dkdev.dk_label; ((struct partinfo *)data)->part = &dksc->sc_dkdev.dk_label->d_partitions[DISKPART(dev)]; break; case DIOCWDINFO: case DIOCSDINFO: #ifdef __HAVE_OLD_DISKLABEL case ODIOCWDINFO: case ODIOCSDINFO: #endif #ifdef __HAVE_OLD_DISKLABEL if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) { memset(&newlabel, 0, sizeof newlabel); memcpy(&newlabel, data, sizeof (struct olddisklabel)); lp = &newlabel; } else #endif lp = (struct disklabel *)data; dk = &dksc->sc_dkdev; mutex_enter(&dk->dk_openlock); dksc->sc_flags |= DKF_LABELLING; error = setdisklabel(dksc->sc_dkdev.dk_label, lp, 0, dksc->sc_dkdev.dk_cpulabel); if (error == 0) { if (cmd == DIOCWDINFO #ifdef __HAVE_OLD_DISKLABEL || cmd == ODIOCWDINFO #endif ) error = writedisklabel(DKLABELDEV(dev), di->di_strategy, dksc->sc_dkdev.dk_label, dksc->sc_dkdev.dk_cpulabel); } dksc->sc_flags &= ~DKF_LABELLING; mutex_exit(&dk->dk_openlock); break; case DIOCWLABEL: if (*(int *)data != 0) dksc->sc_flags |= DKF_WLABEL; else dksc->sc_flags &= ~DKF_WLABEL; break; case DIOCGDEFLABEL: dk_getdefaultlabel(di, dksc, (struct disklabel *)data); break; #ifdef __HAVE_OLD_DISKLABEL case ODIOCGDEFLABEL: dk_getdefaultlabel(di, dksc, &newlabel); if (newlabel.d_npartitions > OLDMAXPARTITIONS) return ENOTTY; memcpy(data, &newlabel, sizeof (struct olddisklabel)); break; #endif case DIOCAWEDGE: { struct dkwedge_info *dkw = (void *)data; if ((flag & FWRITE) == 0) return (EBADF); /* If the ioctl happens here, the parent is us. */ strcpy(dkw->dkw_parent, dksc->sc_dkdev.dk_name); return (dkwedge_add(dkw)); } case DIOCDWEDGE: { struct dkwedge_info *dkw = (void *)data; if ((flag & FWRITE) == 0) return (EBADF); /* If the ioctl happens here, the parent is us. */ strcpy(dkw->dkw_parent, dksc->sc_dkdev.dk_name); return (dkwedge_del(dkw)); } case DIOCLWEDGES: { struct dkwedge_list *dkwl = (void *)data; return (dkwedge_list(&dksc->sc_dkdev, dkwl, l)); } case DIOCGSTRATEGY: { struct disk_strategy *dks = (void *)data; int s; s = splbio(); strlcpy(dks->dks_name, bufq_getstrategyname(dksc->sc_bufq), sizeof(dks->dks_name)); splx(s); dks->dks_paramlen = 0; return 0; } case DIOCSSTRATEGY: { struct disk_strategy *dks = (void *)data; struct bufq_state *new; struct bufq_state *old; int s; if ((flag & FWRITE) == 0) { return EBADF; } if (dks->dks_param != NULL) { return EINVAL; } dks->dks_name[sizeof(dks->dks_name) - 1] = 0; /* ensure term */ error = bufq_alloc(&new, dks->dks_name, BUFQ_EXACT|BUFQ_SORT_RAWBLOCK); if (error) { return error; } s = splbio(); old = dksc->sc_bufq; bufq_move(new, old); dksc->sc_bufq = new; splx(s); bufq_free(old); return 0; } default: error = ENOTTY; } return error; }
/* * Perform special action on behalf of the user * Knows about the internals of this device */ int sdioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) { struct sd_softc *sc; struct disklabel *lp; int error = 0; int part = DISKPART(dev); sc = sdlookup(DISKUNIT(dev)); if (sc == NULL) return (ENXIO); if (sc->flags & SDF_DYING) { device_unref(&sc->sc_dev); return (ENXIO); } SC_DEBUG(sc->sc_link, SDEV_DB2, ("sdioctl 0x%lx\n", cmd)); /* * If the device is not valid.. abandon ship */ if ((sc->sc_link->flags & SDEV_MEDIA_LOADED) == 0) { switch (cmd) { case DIOCLOCK: case DIOCEJECT: case SCIOCIDENTIFY: case SCIOCCOMMAND: case SCIOCDEBUG: if (part == RAW_PART) break; /* FALLTHROUGH */ default: if ((sc->sc_link->flags & SDEV_OPEN) == 0) { error = ENODEV; goto exit; } else { error = EIO; goto exit; } } } switch (cmd) { case DIOCRLDINFO: lp = malloc(sizeof(*lp), M_TEMP, M_WAITOK); sdgetdisklabel(dev, sc, lp, 0); bcopy(lp, sc->sc_dk.dk_label, sizeof(*lp)); free(lp, M_TEMP); goto exit; case DIOCGPDINFO: sdgetdisklabel(dev, sc, (struct disklabel *)addr, 1); goto exit; case DIOCGDINFO: *(struct disklabel *)addr = *(sc->sc_dk.dk_label); goto exit; case DIOCGPART: ((struct partinfo *)addr)->disklab = sc->sc_dk.dk_label; ((struct partinfo *)addr)->part = &sc->sc_dk.dk_label->d_partitions[DISKPART(dev)]; goto exit; case DIOCWDINFO: case DIOCSDINFO: if ((flag & FWRITE) == 0) { error = EBADF; goto exit; } if ((error = disk_lock(&sc->sc_dk)) != 0) goto exit; error = setdisklabel(sc->sc_dk.dk_label, (struct disklabel *)addr, sc->sc_dk.dk_openmask); if (error == 0) { if (cmd == DIOCWDINFO) error = writedisklabel(DISKLABELDEV(dev), sdstrategy, sc->sc_dk.dk_label); } disk_unlock(&sc->sc_dk); goto exit; case DIOCLOCK: error = scsi_prevent(sc->sc_link, (*(int *)addr) ? PR_PREVENT : PR_ALLOW, 0); goto exit; case MTIOCTOP: if (((struct mtop *)addr)->mt_op != MTOFFL) { error = EIO; goto exit; } /* FALLTHROUGH */ case DIOCEJECT: if ((sc->sc_link->flags & SDEV_REMOVABLE) == 0) { error = ENOTTY; goto exit; } sc->sc_link->flags |= SDEV_EJECTING; goto exit; case DIOCINQ: error = scsi_do_ioctl(sc->sc_link, cmd, addr, flag); if (error == ENOTTY) error = sd_ioctl_inquiry(sc, (struct dk_inquiry *)addr); goto exit; case DIOCSCACHE: if (!ISSET(flag, FWRITE)) { error = EBADF; goto exit; } /* FALLTHROUGH */ case DIOCGCACHE: error = sd_ioctl_cache(sc, cmd, (struct dk_cache *)addr); goto exit; case DIOCCACHESYNC: if (!ISSET(flag, FWRITE)) { error = EBADF; goto exit; } if ((sc->flags & SDF_DIRTY) != 0 || *(int *)addr != 0) error = sd_flush(sc, 0); return (error); default: if (part != RAW_PART) { error = ENOTTY; goto exit; } error = scsi_do_ioctl(sc->sc_link, cmd, addr, flag); } exit: device_unref(&sc->sc_dev); return (error); }
int mcdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l) { struct mcd_softc *sc = device_lookup_private(&mcd_cd, MCDUNIT(dev)); int error; int part; #ifdef __HAVE_OLD_DISKLABEL struct disklabel newlabel; #endif MCD_TRACE("ioctl: cmd=0x%lx\n", cmd); if ((sc->flags & MCDF_LOADED) == 0) return EIO; error = disk_ioctl(&sc->sc_dk, dev, cmd, addr, flag, l); if (error != EPASSTHROUGH) return error; part = MCDPART(dev); switch (cmd) { case DIOCWDINFO: case DIOCSDINFO: #ifdef __HAVE_OLD_DISKLABEL case ODIOCWDINFO: case ODIOCSDINFO: #endif { struct disklabel *lp; if ((flag & FWRITE) == 0) return EBADF; #ifdef __HAVE_OLD_DISKLABEL if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) { memset(&newlabel, 0, sizeof newlabel); memcpy(&newlabel, addr, sizeof (struct olddisklabel)); lp = &newlabel; } else #endif lp = addr; mutex_enter(&sc->sc_lock); sc->flags |= MCDF_LABELLING; error = setdisklabel(sc->sc_dk.dk_label, lp, /*sc->sc_dk.dk_openmask : */0, sc->sc_dk.dk_cpulabel); if (error == 0) { } sc->flags &= ~MCDF_LABELLING; mutex_exit(&sc->sc_lock); return error; } case DIOCWLABEL: return EBADF; case DIOCGDEFLABEL: mcdgetdefaultlabel(sc, addr); return 0; #ifdef __HAVE_OLD_DISKLABEL case ODIOCGDEFLABEL: mcdgetdefaultlabel(sc, &newlabel); if (newlabel.d_npartitions > OLDMAXPARTITIONS) return ENOTTY; memcpy(addr, &newlabel, sizeof (struct olddisklabel)); return 0; #endif case CDIOCPLAYTRACKS: return mcd_playtracks(sc, addr); case CDIOCPLAYMSF: return mcd_playmsf(sc, addr); case CDIOCPLAYBLOCKS: return mcd_playblocks(sc, addr); case CDIOCREADSUBCHANNEL: { struct cd_sub_channel_info info; error = mcd_read_subchannel(sc, addr, &info); if (error != 0) { struct ioc_read_subchannel *ch = addr; error = copyout(&info, ch->data, ch->data_len); } return error; } case CDIOCREADSUBCHANNEL_BUF: return mcd_read_subchannel(sc, addr, &((struct ioc_read_subchannel_buf *)addr)->info); case CDIOREADTOCHEADER: return mcd_toc_header(sc, addr); case CDIOREADTOCENTRYS: { struct cd_toc_entry entries[MCD_MAXTOCS]; struct ioc_read_toc_entry *te = addr; int count; if (te->data_len > sizeof entries) return EINVAL; error = mcd_toc_entries(sc, te, entries, &count); if (error == 0) /* Copy the data back. */ error = copyout(entries, te->data, min(te->data_len, count * sizeof(struct cd_toc_entry))); return error; } case CDIOREADTOCENTRIES_BUF: { struct ioc_read_toc_entry_buf *te = addr; int count; if (te->req.data_len > sizeof te->entry) return EINVAL; return mcd_toc_entries(sc, &te->req, te->entry, &count); } case CDIOCSETPATCH: case CDIOCGETVOL: case CDIOCSETVOL: case CDIOCSETMONO: case CDIOCSETSTEREO: case CDIOCSETMUTE: case CDIOCSETLEFT: case CDIOCSETRIGHT: return EINVAL; case CDIOCRESUME: return mcd_resume(sc); case CDIOCPAUSE: return mcd_pause(sc); case CDIOCSTART: return EINVAL; case CDIOCSTOP: return mcd_stop(sc); case DIOCEJECT: if (*(int *)addr == 0) { /* * Don't force eject: check that we are the only * partition open. If so, unlock it. */ if ((sc->sc_dk.dk_openmask & ~(1 << part)) == 0 && sc->sc_dk.dk_bopenmask + sc->sc_dk.dk_copenmask == sc->sc_dk.dk_openmask) { error = mcd_setlock(sc, MCD_LK_UNLOCK); if (error) return (error); } else { return (EBUSY); } } /* FALLTHROUGH */ case CDIOCEJECT: /* FALLTHROUGH */ case ODIOCEJECT: return mcd_eject(sc); case CDIOCALLOW: return mcd_setlock(sc, MCD_LK_UNLOCK); case CDIOCPREVENT: return mcd_setlock(sc, MCD_LK_LOCK); case DIOCLOCK: return mcd_setlock(sc, (*(int *)addr) ? MCD_LK_LOCK : MCD_LK_UNLOCK); case CDIOCSETDEBUG: sc->debug = 1; return 0; case CDIOCCLRDEBUG: sc->debug = 0; return 0; case CDIOCRESET: return mcd_hard_reset(sc); default: return ENOTTY; } #ifdef DIAGNOSTIC panic("mcdioctl: impossible"); #endif }
/* ARGSUSED */ int vndioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) { int unit = DISKUNIT(dev); struct disklabel *lp; struct vnd_softc *sc; struct vnd_ioctl *vio; struct vnd_user *vnu; struct vattr vattr; struct nameidata nd; int error, part, pmask; DNPRINTF(VDB_FOLLOW, "vndioctl(%x, %lx, %p, %x, %p): unit %d\n", dev, cmd, addr, flag, p, unit); error = suser(p, 0); if (error) return (error); if (unit >= numvnd) return (ENXIO); sc = &vnd_softc[unit]; vio = (struct vnd_ioctl *)addr; switch (cmd) { case VNDIOCSET: if (sc->sc_flags & VNF_INITED) return (EBUSY); /* Geometry eventually has to fit into label fields */ if (vio->vnd_secsize > UINT_MAX || vio->vnd_ntracks > UINT_MAX || vio->vnd_nsectors > UINT_MAX) return (EINVAL); if ((error = disk_lock(&sc->sc_dk)) != 0) return (error); if ((error = copyinstr(vio->vnd_file, sc->sc_file, sizeof(sc->sc_file), NULL))) { disk_unlock(&sc->sc_dk); return (error); } /* Set geometry for device. */ sc->sc_secsize = vio->vnd_secsize; sc->sc_ntracks = vio->vnd_ntracks; sc->sc_nsectors = vio->vnd_nsectors; /* * Open for read and write first. This lets vn_open() weed out * directories, sockets, etc. so we don't have to worry about * them. */ NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, vio->vnd_file, p); sc->sc_flags &= ~VNF_READONLY; error = vn_open(&nd, FREAD|FWRITE, 0); if (error == EROFS) { sc->sc_flags |= VNF_READONLY; error = vn_open(&nd, FREAD, 0); } if (error) { disk_unlock(&sc->sc_dk); return (error); } if (nd.ni_vp->v_type == VBLK) sc->sc_size = vndbdevsize(nd.ni_vp, p); else { error = VOP_GETATTR(nd.ni_vp, &vattr, p->p_ucred, p); if (error) { VOP_UNLOCK(nd.ni_vp, 0, p); vn_close(nd.ni_vp, VNDRW(sc), p->p_ucred, p); disk_unlock(&sc->sc_dk); return (error); } sc->sc_size = vattr.va_size / sc->sc_secsize; } VOP_UNLOCK(nd.ni_vp, 0, p); sc->sc_vp = nd.ni_vp; if ((error = vndsetcred(sc, p->p_ucred)) != 0) { (void) vn_close(nd.ni_vp, VNDRW(sc), p->p_ucred, p); disk_unlock(&sc->sc_dk); return (error); } if (vio->vnd_keylen > 0) { char key[BLF_MAXUTILIZED]; if (vio->vnd_keylen > sizeof(key)) vio->vnd_keylen = sizeof(key); if ((error = copyin(vio->vnd_key, key, vio->vnd_keylen)) != 0) { (void) vn_close(nd.ni_vp, VNDRW(sc), p->p_ucred, p); disk_unlock(&sc->sc_dk); return (error); } sc->sc_keyctx = malloc(sizeof(*sc->sc_keyctx), M_DEVBUF, M_WAITOK); blf_key(sc->sc_keyctx, key, vio->vnd_keylen); explicit_bzero(key, vio->vnd_keylen); } else sc->sc_keyctx = NULL; vio->vnd_size = sc->sc_size * sc->sc_secsize; sc->sc_flags |= VNF_INITED; DNPRINTF(VDB_INIT, "vndioctl: SET vp %p size %llx\n", sc->sc_vp, (unsigned long long)sc->sc_size); /* Attach the disk. */ sc->sc_dk.dk_name = sc->sc_dev.dv_xname; disk_attach(&sc->sc_dev, &sc->sc_dk); disk_unlock(&sc->sc_dk); break; case VNDIOCCLR: if ((sc->sc_flags & VNF_INITED) == 0) return (ENXIO); if ((error = disk_lock(&sc->sc_dk)) != 0) return (error); /* * Don't unconfigure if any other partitions are open * or if both the character and block flavors of this * partition are open. */ part = DISKPART(dev); pmask = (1 << part); if ((sc->sc_dk.dk_openmask & ~pmask) || ((sc->sc_dk.dk_bopenmask & pmask) && (sc->sc_dk.dk_copenmask & pmask))) { disk_unlock(&sc->sc_dk); return (EBUSY); } vndclear(sc); DNPRINTF(VDB_INIT, "vndioctl: CLRed\n"); /* Free crypto key */ if (sc->sc_keyctx) { explicit_bzero(sc->sc_keyctx, sizeof(*sc->sc_keyctx)); free(sc->sc_keyctx, M_DEVBUF, sizeof(*sc->sc_keyctx)); } /* Detach the disk. */ disk_detach(&sc->sc_dk); disk_unlock(&sc->sc_dk); break; case VNDIOCGET: vnu = (struct vnd_user *)addr; if (vnu->vnu_unit == -1) vnu->vnu_unit = unit; if (vnu->vnu_unit >= numvnd) return (ENXIO); if (vnu->vnu_unit < 0) return (EINVAL); sc = &vnd_softc[vnu->vnu_unit]; if (sc->sc_flags & VNF_INITED) { error = VOP_GETATTR(sc->sc_vp, &vattr, p->p_ucred, p); if (error) return (error); strlcpy(vnu->vnu_file, sc->sc_file, sizeof(vnu->vnu_file)); vnu->vnu_dev = vattr.va_fsid; vnu->vnu_ino = vattr.va_fileid; } else { vnu->vnu_dev = 0; vnu->vnu_ino = 0; } break; case DIOCRLDINFO: if ((sc->sc_flags & VNF_HAVELABEL) == 0) return (ENOTTY); lp = malloc(sizeof(*lp), M_TEMP, M_WAITOK); vndgetdisklabel(dev, sc, lp, 0); *(sc->sc_dk.dk_label) = *lp; free(lp, M_TEMP, sizeof(*lp)); return (0); case DIOCGPDINFO: if ((sc->sc_flags & VNF_HAVELABEL) == 0) return (ENOTTY); vndgetdisklabel(dev, sc, (struct disklabel *)addr, 1); return (0); case DIOCGDINFO: if ((sc->sc_flags & VNF_HAVELABEL) == 0) return (ENOTTY); *(struct disklabel *)addr = *(sc->sc_dk.dk_label); return (0); case DIOCGPART: if ((sc->sc_flags & VNF_HAVELABEL) == 0) return (ENOTTY); ((struct partinfo *)addr)->disklab = sc->sc_dk.dk_label; ((struct partinfo *)addr)->part = &sc->sc_dk.dk_label->d_partitions[DISKPART(dev)]; return (0); case DIOCWDINFO: case DIOCSDINFO: if ((sc->sc_flags & VNF_HAVELABEL) == 0) return (ENOTTY); if ((flag & FWRITE) == 0) return (EBADF); if ((error = disk_lock(&sc->sc_dk)) != 0) return (error); error = setdisklabel(sc->sc_dk.dk_label, (struct disklabel *)addr, /* sc->sc_dk.dk_openmask */ 0); if (error == 0) { if (cmd == DIOCWDINFO) error = writedisklabel(DISKLABELDEV(dev), vndstrategy, sc->sc_dk.dk_label); } disk_unlock(&sc->sc_dk); return (error); default: return (ENOTTY); } return (0); }
int edmcaioctl(dev_t dev, u_long xfer, void *addr, int flag, struct lwp *l) { struct ed_softc *ed = device_lookup_private(&ed_cd, DISKUNIT(dev)); int error; ATADEBUG_PRINT(("edioctl\n"), DEBUG_FUNCS); if ((ed->sc_flags & WDF_LOADED) == 0) return EIO; error = disk_ioctl(&ed->sc_dk, dev, xfer, addr, flag, l); if (error != EPASSTHROUGH) return error; switch (xfer) { case DIOCWDINFO: case DIOCSDINFO: { struct disklabel *lp; lp = (struct disklabel *)addr; if ((flag & FWRITE) == 0) return EBADF; mutex_enter(&ed->sc_dk.dk_openlock); ed->sc_flags |= WDF_LABELLING; error = setdisklabel(ed->sc_dk.dk_label, lp, /*wd->sc_dk.dk_openmask : */0, ed->sc_dk.dk_cpulabel); if (error == 0) { #if 0 if (wd->drvp->state > RECAL) wd->drvp->drive_flags |= ATA_DRIVE_RESET; #endif if (xfer == DIOCWDINFO) error = writedisklabel(EDLABELDEV(dev), edmcastrategy, ed->sc_dk.dk_label, ed->sc_dk.dk_cpulabel); } ed->sc_flags &= ~WDF_LABELLING; mutex_exit(&ed->sc_dk.dk_openlock); return (error); } case DIOCKLABEL: if (*(int *)addr) ed->sc_flags |= WDF_KLABEL; else ed->sc_flags &= ~WDF_KLABEL; return 0; case DIOCWLABEL: if ((flag & FWRITE) == 0) return EBADF; if (*(int *)addr) ed->sc_flags |= WDF_WLABEL; else ed->sc_flags &= ~WDF_WLABEL; return 0; case DIOCGDEFLABEL: edgetdefaultlabel(ed, (struct disklabel *)addr); return 0; #if 0 case DIOCWFORMAT: if ((flag & FWRITE) == 0) return EBADF; { register struct format_op *fop; struct iovec aiov; struct uio auio; fop = (struct format_op *)addr; aiov.iov_base = fop->df_buf; aiov.iov_len = fop->df_count; auio.uio_iov = &aiov; auio.uio_iovcnt = 1; auio.uio_resid = fop->df_count; auio.uio_segflg = 0; auio.uio_offset = fop->df_startblk * wd->sc_dk.dk_label->d_secsize; auio.uio_lwp = l; error = physio(wdformat, NULL, dev, B_WRITE, minphys, &auio); fop->df_count -= auio.uio_resid; fop->df_reg[0] = wdc->sc_status; fop->df_reg[1] = wdc->sc_error; return error; } #endif default: return ENOTTY; } #ifdef DIAGNOSTIC panic("edioctl: impossible"); #endif }
/* * Perform special action on behalf of the user. * Knows about the internals of this device */ int cdioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) { struct cd_softc *cd; struct disklabel *lp; int part = DISKPART(dev); int error = 0; cd = cdlookup(DISKUNIT(dev)); if (cd == NULL) return ENXIO; SC_DEBUG(cd->sc_link, SDEV_DB2, ("cdioctl 0x%lx\n", cmd)); /* * If the device is not valid.. abandon ship */ if ((cd->sc_link->flags & SDEV_MEDIA_LOADED) == 0) { switch (cmd) { case DIOCWLABEL: case DIOCLOCK: case DIOCEJECT: case SCIOCIDENTIFY: case SCIOCCOMMAND: case SCIOCDEBUG: case CDIOCLOADUNLOAD: case SCIOCRESET: case CDIOCGETVOL: case CDIOCSETVOL: case CDIOCSETMONO: case CDIOCSETSTEREO: case CDIOCSETMUTE: case CDIOCSETLEFT: case CDIOCSETRIGHT: case CDIOCCLOSE: case CDIOCEJECT: case CDIOCALLOW: case CDIOCPREVENT: case CDIOCSETDEBUG: case CDIOCCLRDEBUG: case CDIOCRESET: case DVD_AUTH: case DVD_READ_STRUCT: case MTIOCTOP: if (part == RAW_PART) break; /* FALLTHROUGH */ default: if ((cd->sc_link->flags & SDEV_OPEN) == 0) error = ENODEV; else error = EIO; goto exit; } } switch (cmd) { case DIOCRLDINFO: lp = malloc(sizeof(*lp), M_TEMP, M_WAITOK); cdgetdisklabel(dev, cd, lp, 0); bcopy(lp, cd->sc_dk.dk_label, sizeof(*lp)); free(lp, M_TEMP); break; case DIOCGDINFO: case DIOCGPDINFO: *(struct disklabel *)addr = *(cd->sc_dk.dk_label); break; case DIOCGPART: ((struct partinfo *)addr)->disklab = cd->sc_dk.dk_label; ((struct partinfo *)addr)->part = &cd->sc_dk.dk_label->d_partitions[DISKPART(dev)]; break; case DIOCWDINFO: case DIOCSDINFO: if ((flag & FWRITE) == 0) { error = EBADF; break; } if ((error = cdlock(cd)) != 0) break; cd->flags |= CDF_LABELLING; error = setdisklabel(cd->sc_dk.dk_label, (struct disklabel *)addr, /*cd->sc_dk.dk_openmask : */0); if (error == 0) { } cd->flags &= ~CDF_LABELLING; cdunlock(cd); break; case DIOCWLABEL: error = EBADF; break; case CDIOCPLAYTRACKS: { struct ioc_play_track *args = (struct ioc_play_track *)addr; if ((error = cd_set_pa_immed(cd, 0)) != 0) break; error = cd_play_tracks(cd, args->start_track, args->start_index, args->end_track, args->end_index); break; } case CDIOCPLAYMSF: { struct ioc_play_msf *args = (struct ioc_play_msf *)addr; if ((error = cd_set_pa_immed(cd, 0)) != 0) break; error = cd_play_msf(cd, args->start_m, args->start_s, args->start_f, args->end_m, args->end_s, args->end_f); break; } case CDIOCPLAYBLOCKS: { struct ioc_play_blocks *args = (struct ioc_play_blocks *)addr; if ((error = cd_set_pa_immed(cd, 0)) != 0) break; error = cd_play(cd, args->blk, args->len); break; } case CDIOCREADSUBCHANNEL: { struct ioc_read_subchannel *args = (struct ioc_read_subchannel *)addr; struct cd_sub_channel_info data; int len = args->data_len; if (len > sizeof(data) || len < sizeof(struct cd_sub_channel_header)) { error = EINVAL; break; } error = cd_read_subchannel(cd, args->address_format, args->data_format, args->track, &data, len); if (error) break; len = min(len, _2btol(data.header.data_len) + sizeof(struct cd_sub_channel_header)); error = copyout(&data, args->data, len); break; } case CDIOREADTOCHEADER: { struct ioc_toc_header th; if ((error = cd_read_toc(cd, 0, 0, &th, sizeof(th), 0)) != 0) break; if (cd->sc_link->quirks & ADEV_LITTLETOC) th.len = letoh16(th.len); else th.len = betoh16(th.len); bcopy(&th, addr, sizeof(th)); break; } case CDIOREADTOCENTRYS: { struct cd_toc *toc; struct ioc_read_toc_entry *te = (struct ioc_read_toc_entry *)addr; struct ioc_toc_header *th; struct cd_toc_entry *cte; int len = te->data_len; int ntracks; toc = malloc(sizeof(*toc), M_TEMP, M_WAITOK | M_ZERO); th = &toc->header; if (len > sizeof(toc->entries) || len < sizeof(struct cd_toc_entry)) { free(toc, M_TEMP); error = EINVAL; break; } error = cd_read_toc(cd, te->address_format, te->starting_track, toc, len + sizeof(struct ioc_toc_header), 0); if (error) { free(toc, M_TEMP); break; } if (te->address_format == CD_LBA_FORMAT) for (ntracks = th->ending_track - th->starting_track + 1; ntracks >= 0; ntracks--) { cte = &toc->entries[ntracks]; cte->addr_type = CD_LBA_FORMAT; if (cd->sc_link->quirks & ADEV_LITTLETOC) { #if BYTE_ORDER == BIG_ENDIAN swap16_multi((u_int16_t *)&cte->addr, sizeof(cte->addr) / 2); #endif } else cte->addr.lba = betoh32(cte->addr.lba); } if (cd->sc_link->quirks & ADEV_LITTLETOC) { th->len = letoh16(th->len); } else th->len = betoh16(th->len); len = min(len, th->len - (sizeof(th->starting_track) + sizeof(th->ending_track))); error = copyout(toc->entries, te->data, len); free(toc, M_TEMP); break; } case CDIOREADMSADDR: { struct cd_toc *toc; int sessno = *(int *)addr; struct cd_toc_entry *cte; if (sessno != 0) { error = EINVAL; break; } toc = malloc(sizeof(*toc), M_TEMP, M_WAITOK | M_ZERO); error = cd_read_toc(cd, 0, 0, toc, sizeof(struct ioc_toc_header) + sizeof(struct cd_toc_entry), 0x40 /* control word for "get MS info" */); if (error) { free(toc, M_TEMP); break; } cte = &toc->entries[0]; if (cd->sc_link->quirks & ADEV_LITTLETOC) { #if BYTE_ORDER == BIG_ENDIAN swap16_multi((u_int16_t *)&cte->addr, sizeof(cte->addr) / 2); #endif } else cte->addr.lba = betoh32(cte->addr.lba); if (cd->sc_link->quirks & ADEV_LITTLETOC) toc->header.len = letoh16(toc->header.len); else toc->header.len = betoh16(toc->header.len); *(int *)addr = (toc->header.len >= 10 && cte->track > 1) ? cte->addr.lba : 0; free(toc, M_TEMP); break; } case CDIOCSETPATCH: { struct ioc_patch *arg = (struct ioc_patch *)addr; error = cd_setchan(cd, arg->patch[0], arg->patch[1], arg->patch[2], arg->patch[3], 0); break; } case CDIOCGETVOL: { struct ioc_vol *arg = (struct ioc_vol *)addr; error = cd_getvol(cd, arg, 0); break; } case CDIOCSETVOL: { struct ioc_vol *arg = (struct ioc_vol *)addr; error = cd_setvol(cd, arg, 0); break; } case CDIOCSETMONO: error = cd_setchan(cd, BOTH_CHANNEL, BOTH_CHANNEL, MUTE_CHANNEL, MUTE_CHANNEL, 0); break; case CDIOCSETSTEREO: error = cd_setchan(cd, LEFT_CHANNEL, RIGHT_CHANNEL, MUTE_CHANNEL, MUTE_CHANNEL, 0); break; case CDIOCSETMUTE: error = cd_setchan(cd, MUTE_CHANNEL, MUTE_CHANNEL, MUTE_CHANNEL, MUTE_CHANNEL, 0); break; case CDIOCSETLEFT: error = cd_setchan(cd, LEFT_CHANNEL, LEFT_CHANNEL, MUTE_CHANNEL, MUTE_CHANNEL, 0); break; case CDIOCSETRIGHT: error = cd_setchan(cd, RIGHT_CHANNEL, RIGHT_CHANNEL, MUTE_CHANNEL, MUTE_CHANNEL, 0); break; case CDIOCRESUME: error = cd_pause(cd, 1); break; case CDIOCPAUSE: error = cd_pause(cd, 0); break; case CDIOCSTART: error = scsi_start(cd->sc_link, SSS_START, 0); break; case CDIOCSTOP: error = scsi_start(cd->sc_link, SSS_STOP, 0); break; close_tray: case CDIOCCLOSE: error = scsi_start(cd->sc_link, SSS_START|SSS_LOEJ, SCSI_IGNORE_NOT_READY | SCSI_IGNORE_MEDIA_CHANGE); break; case MTIOCTOP: if (((struct mtop *)addr)->mt_op == MTRETEN) goto close_tray; if (((struct mtop *)addr)->mt_op != MTOFFL) { error = EIO; break; } /* FALLTHROUGH */ case CDIOCEJECT: /* FALLTHROUGH */ case DIOCEJECT: cd->sc_link->flags |= SDEV_EJECTING; break; case CDIOCALLOW: error = scsi_prevent(cd->sc_link, PR_ALLOW, 0); break; case CDIOCPREVENT: error = scsi_prevent(cd->sc_link, PR_PREVENT, 0); break; case DIOCLOCK: error = scsi_prevent(cd->sc_link, (*(int *)addr) ? PR_PREVENT : PR_ALLOW, 0); break; case CDIOCSETDEBUG: cd->sc_link->flags |= (SDEV_DB1 | SDEV_DB2); break; case CDIOCCLRDEBUG: cd->sc_link->flags &= ~(SDEV_DB1 | SDEV_DB2); break; case CDIOCRESET: case SCIOCRESET: error = cd_reset(cd); break; case CDIOCLOADUNLOAD: { struct ioc_load_unload *args = (struct ioc_load_unload *)addr; error = cd_load_unload(cd, args->options, args->slot); break; } case DVD_AUTH: error = dvd_auth(cd, (union dvd_authinfo *)addr); break; case DVD_READ_STRUCT: error = dvd_read_struct(cd, (union dvd_struct *)addr); break; default: if (DISKPART(dev) != RAW_PART) { error = ENOTTY; break; } error = scsi_do_ioctl(cd->sc_link, dev, cmd, addr, flag, p); break; } exit: device_unref(&cd->sc_dev); return (error); }
/* ARGSUSED */ int ldioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct proc *p) { struct ld_softc *sc; int part, unit, error; #ifdef __HAVE_OLD_DISKLABEL struct disklabel newlabel; #endif struct disklabel *lp; unit = DISKUNIT(dev); part = DISKPART(dev); sc = device_lookup(&ld_cd, unit); error = 0; switch (cmd) { case DIOCGDINFO: memcpy(addr, sc->sc_dk.dk_label, sizeof(struct disklabel)); return (0); #ifdef __HAVE_OLD_DISKLABEL case ODIOCGDINFO: newlabel = *(sc->sc_dk.dk_label); if (newlabel.d_npartitions > OLDMAXPARTITIONS) return ENOTTY; memcpy(addr, &newlabel, sizeof(struct olddisklabel)); return (0); #endif case DIOCGPART: ((struct partinfo *)addr)->disklab = sc->sc_dk.dk_label; ((struct partinfo *)addr)->part = &sc->sc_dk.dk_label->d_partitions[part]; break; case DIOCWDINFO: case DIOCSDINFO: #ifdef __HAVE_OLD_DISKLABEL case ODIOCWDINFO: case ODIOCSDINFO: if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) { memset(&newlabel, 0, sizeof newlabel); memcpy(&newlabel, addr, sizeof (struct olddisklabel)); lp = &newlabel; } else #endif lp = (struct disklabel *)addr; if ((flag & FWRITE) == 0) return (EBADF); if ((error = ldlock(sc)) != 0) return (error); sc->sc_flags |= LDF_LABELLING; error = setdisklabel(sc->sc_dk.dk_label, lp, /*sc->sc_dk.dk_openmask : */0, sc->sc_dk.dk_cpulabel); if (error == 0 && (cmd == DIOCWDINFO #ifdef __HAVE_OLD_DISKLABEL || cmd == ODIOCWDINFO #endif )) error = writedisklabel( MAKEDISKDEV(major(dev), DISKUNIT(dev), RAW_PART), ldstrategy, sc->sc_dk.dk_label, sc->sc_dk.dk_cpulabel); sc->sc_flags &= ~LDF_LABELLING; ldunlock(sc); break; case DIOCWLABEL: if ((flag & FWRITE) == 0) return (EBADF); if (*(int *)addr) sc->sc_flags |= LDF_WLABEL; else sc->sc_flags &= ~LDF_WLABEL; break; case DIOCGDEFLABEL: ldgetdefaultlabel(sc, (struct disklabel *)addr); break; #ifdef __HAVE_OLD_DISKLABEL case ODIOCGDEFLABEL: ldgetdefaultlabel(sc, &newlabel); if (newlabel.d_npartitions > OLDMAXPARTITIONS) return ENOTTY; memcpy(addr, &newlabel, sizeof (struct olddisklabel)); break; #endif default: error = ENOTTY; break; } return (error); }