int mcdclose(dev_t dev, int flag, int fmt, struct lwp *l) { struct mcd_softc *sc = device_lookup_private(&mcd_cd, MCDUNIT(dev)); int part = MCDPART(dev); MCD_TRACE("close: partition=%d\n", part); mutex_enter(&sc->sc_lock); switch (fmt) { case S_IFCHR: sc->sc_dk.dk_copenmask &= ~(1 << part); break; case S_IFBLK: sc->sc_dk.dk_bopenmask &= ~(1 << part); break; } sc->sc_dk.dk_openmask = sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask; if (sc->sc_dk.dk_openmask == 0) { /* XXXX Must wait for I/O to complete! */ #if 0 (void) mcd_setmode(sc, MCD_MD_SLEEP); #endif (void) mcd_setlock(sc, MCD_LK_UNLOCK); } mutex_exit(&sc->sc_lock); return 0; }
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 }
int mcdopen(dev_t dev, int flag, int fmt, struct lwp *l) { int error, part; struct mcd_softc *sc; sc = device_lookup_private(&mcd_cd, MCDUNIT(dev)); if (sc == NULL) return ENXIO; mutex_enter(&sc->sc_lock); if (sc->sc_dk.dk_openmask != 0) { /* * If any partition is open, but the disk has been invalidated, * disallow further opens. */ if ((sc->flags & MCDF_LOADED) == 0) { error = EIO; goto bad3; } } else { /* * Lock the drawer. This will also notice any pending disk * change or door open indicator and clear the MCDF_LOADED bit * if necessary. */ (void) mcd_setlock(sc, MCD_LK_LOCK); if ((sc->flags & MCDF_LOADED) == 0) { /* Partially reset the state. */ sc->lastmode = MCD_MD_UNKNOWN; sc->lastupc = MCD_UPC_UNKNOWN; sc->flags |= MCDF_LOADED; /* Set the mode, causing the disk to spin up. */ if ((error = mcd_setmode(sc, MCD_MD_COOKED)) != 0) goto bad2; /* Load the physical device parameters. */ if (mcd_get_parms(sc) != 0) { error = ENXIO; goto bad2; } /* Read the table of contents. */ if ((error = mcd_read_toc(sc)) != 0) goto bad2; /* Fabricate a disk label. */ mcdgetdisklabel(sc); } } part = MCDPART(dev); MCD_TRACE("open: partition=%d disksize=%ld blksize=%d\n", part, sc->disksize, sc->blksize); /* Check that the partition exists. */ if (part != RAW_PART && (part >= sc->sc_dk.dk_label->d_npartitions || sc->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) { error = ENXIO; goto bad; } /* Insure only one open at a time. */ switch (fmt) { case S_IFCHR: sc->sc_dk.dk_copenmask |= (1 << part); break; case S_IFBLK: sc->sc_dk.dk_bopenmask |= (1 << part); break; } sc->sc_dk.dk_openmask = sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask; mutex_exit(&sc->sc_lock); return 0; bad2: sc->flags &= ~MCDF_LOADED; bad: if (sc->sc_dk.dk_openmask == 0) { #if 0 (void) mcd_setmode(sc, MCD_MD_SLEEP); #endif (void) mcd_setlock(sc, MCD_LK_UNLOCK); } bad3: mutex_exit(&sc->sc_lock); return error; }
void mcdstrategy(struct buf *bp) { struct mcd_softc *sc; struct disklabel *lp; daddr_t blkno; int s; sc = device_lookup_private(&mcd_cd, MCDUNIT(bp->b_dev)); lp = sc->sc_dk.dk_label; /* Test validity. */ MCD_TRACE("strategy: buf=0x%p blkno=%d bcount=%d\n", bp, (int) bp->b_blkno, bp->b_bcount); if (bp->b_blkno < 0 || (bp->b_bcount % sc->blksize) != 0) { printf("%s: strategy: blkno = %" PRId64 " bcount = %d\n", device_xname(sc->sc_dev), bp->b_blkno, bp->b_bcount); bp->b_error = EINVAL; goto done; } /* If device invalidated (e.g. media change, door open), error. */ if ((sc->flags & MCDF_LOADED) == 0) { MCD_TRACE("strategy: drive not valid%s", "\n"); bp->b_error = EIO; goto done; } /* No data to read. */ if (bp->b_bcount == 0) goto done; /* * Do bounds checking, adjust transfer. if error, process. * If end of partition, just return. */ if (MCDPART(bp->b_dev) != RAW_PART && bounds_check_with_label(&sc->sc_dk, bp, (sc->flags & (MCDF_WLABEL|MCDF_LABELLING)) != 0) <= 0) goto done; /* * Now convert the block number to absolute and put it in * terms of the device's logical block size. */ blkno = bp->b_blkno / (lp->d_secsize / DEV_BSIZE); if (MCDPART(bp->b_dev) != RAW_PART) blkno += lp->d_partitions[MCDPART(bp->b_dev)].p_offset; bp->b_rawblkno = blkno; /* Queue it. */ s = splbio(); bufq_put(sc->buf_queue, bp); splx(s); if (!sc->active) mcdstart(sc); return; done: bp->b_resid = bp->b_bcount; biodone(bp); }