-/* $OpenBSD: cd.c,v 1.53 2000/04/18 05:53:17 csapuntz Exp $ */
+/* $OpenBSD: cd.c,v 1.54 2000/04/18 06:34:18 csapuntz Exp $ */
/* $NetBSD: cd.c,v 1.100 1997/04/02 02:29:30 mycroft Exp $ */
/*
#include <sys/proc.h>
#include <sys/conf.h>
#include <sys/scsiio.h>
+#include <sys/vnode.h>
#include <scsi/scsi_all.h>
#include <scsi/cd.h>
#define CDOUTSTANDING 4
#define CDUNIT(z) DISKUNIT(z)
+#define CDMINOR(unit, part) DISKMINOR(unit, part)
#define CDPART(z) DISKPART(z)
#define MAKECDDEV(maj, unit, part) MAKEDISKDEV(maj, unit, part)
int cdmatch __P((struct device *, void *, void *));
void cdattach __P((struct device *, struct device *, void *));
+int cdactivate __P((struct device *, enum devact));
+int cddetach __P((struct device *, int));
+void cdzeroref __P((struct device *));
+
void cdstart __P((void *));
void cdminphys __P((struct buf *));
void cdgetdisklabel __P((dev_t, struct cd_softc *, struct disklabel *,
int dvd_read_struct __P((struct cd_softc *, union dvd_struct *));
struct cfattach cd_ca = {
- sizeof(struct cd_softc), cdmatch, cdattach
+ sizeof(struct cd_softc), cdmatch, cdattach,
+ cddetach, cdactivate, cdzeroref
};
struct cfdriver cd_cd = {
#define cdlock(softc) disk_lock(&(softc)->sc_dk)
#define cdunlock(softc) disk_unlock(&(softc)->sc_dk)
+#define cdlookup(unit) (struct cd_softc *)device_lookup(&cd_cd, (unit))
int
cdmatch(parent, match, aux)
printf("\n");
}
+
+int
+cdactivate(self, act)
+ struct device *self;
+ enum devact act;
+{
+ int rv = 0;
+
+ switch (act) {
+ case DVACT_ACTIVATE:
+ break;
+
+ case DVACT_DEACTIVATE:
+ /*
+ * Nothing to do; we key off the device's DVF_ACTIVATE.
+ */
+ break;
+ }
+ return (rv);
+}
+
+
+int
+cddetach(self, flags)
+ struct device *self;
+ int flags;
+{
+ struct cd_softc *sc = (struct cd_softc *)self;
+ struct buf *dp, *bp;
+ int s, bmaj, cmaj, mn;
+
+ /* Remove unprocessed buffers from queue */
+ s = splbio();
+ for (dp = &sc->buf_queue; (bp = dp->b_actf) != NULL; ) {
+ dp->b_actf = bp->b_actf;
+
+ bp->b_error = ENXIO;
+ bp->b_flags |= B_ERROR;
+ biodone(bp);
+ }
+ splx(s);
+
+ /* locate the major number */
+ mn = CDMINOR(self->dv_unit, 0);
+
+ for (bmaj = 0; bmaj < nblkdev; bmaj++)
+ if (bdevsw[bmaj].d_open == cdopen)
+ vdevgone(bmaj, mn, mn + MAXPARTITIONS - 1, VBLK);
+ for (cmaj = 0; cmaj < nchrdev; cmaj++)
+ if (cdevsw[cmaj].d_open == cdopen)
+ vdevgone(cmaj, mn, mn + MAXPARTITIONS - 1, VCHR);
+ return (0);
+}
+
+void
+cdzeroref(self)
+ struct device *self;
+{
+ struct cd_softc *cd = (struct cd_softc *)self;
+
+ /* Detach disk. */
+ disk_detach(&cd->sc_dk);
+}
+
+
/*
* open the device. Make sure the partition info is a up-to-date as can be.
*/
int error;
unit = CDUNIT(dev);
- if (unit >= cd_cd.cd_ndevs)
- return ENXIO;
- cd = cd_cd.cd_devs[unit];
- if (!cd)
+ cd = cdlookup(unit);
+ if (cd == NULL)
return ENXIO;
sc_link = cd->sc_link;
("cdopen: dev=0x%x (unit %d (of %d), partition %d)\n", dev, unit,
cd_cd.cd_ndevs, CDPART(dev)));
- if ((error = cdlock(cd)) != 0)
+ if ((error = cdlock(cd)) != 0) {
+ device_unref(&cd->sc_dev);
return error;
-
-#ifdef CDDA
- /*
- * We can't open the block device if the drive is in CDDA
- * mode. If we allow such opens, either the drive will get
- * quite unhappy about undersized I/O or the BSD I/O subsystem
- * will start trashing memory with disk transfers overrunning
- * the end of their buffers. Either way, it's Bad.
- */
- if (cd->flags & CDF_CDDAMODE && fmt == S_IFBLK)
- return EBUSY;
-#endif
+ }
if (cd->sc_dk.dk_openmask != 0) {
/*
error = EIO;
goto bad3;
}
-#ifdef CDDA
- /*
- * If it's in CDDA mode, process may only open the
- * raw partition
- */
- if (cd->flags & CDF_CDDAMODE && part != RAW_PART) {
- error = EBUSY;
- goto bad3;
- }
-#endif
} else {
/* Check that it is still responding and ok. */
error = scsi_test_unit_ready(sc_link,
SC_DEBUG(sc_link, SDEV_DB3, ("open complete\n"));
cdunlock(cd);
+ device_unref(&cd->sc_dev);
return 0;
bad2:
bad3:
cdunlock(cd);
+ device_unref(&cd->sc_dev);
return error;
}
int flag, fmt;
struct proc *p;
{
- struct cd_softc *cd = cd_cd.cd_devs[CDUNIT(dev)];
+ struct cd_softc *cd;
int part = CDPART(dev);
int error;
- if ((error = cdlock(cd)) != 0)
+ cd = cdlookup(CDUNIT(dev));
+ if (cd == NULL)
+ return ENXIO;
+
+ if ((error = cdlock(cd)) != 0) {
+ device_unref(&cd->sc_dev);
return error;
+ }
switch (fmt) {
case S_IFCHR:
}
cdunlock(cd);
+
+ device_unref(&cd->sc_dev);
return 0;
}
cdstrategy(bp)
struct buf *bp;
{
- struct cd_softc *cd = cd_cd.cd_devs[CDUNIT(bp->b_dev)];
+ struct cd_softc *cd;
int opri;
+ if ((cd = cdlookup(CDUNIT(bp->b_dev))) == NULL) {
+ bp->b_error = ENXIO;
+ goto bad;
+ }
+
SC_DEBUG(cd->sc_link, SDEV_DB2, ("cdstrategy "));
SC_DEBUG(cd->sc_link, SDEV_DB1,
("%ld bytes @ blk %d\n", bp->b_bcount, bp->b_blkno));
if (bp->b_bcount == 0)
goto done;
-#ifdef CDDA
- /*
- * If in CDDA mode, return immediately (the user must issue
- * SCSI read commands directly using SCIOCCOMMAND). The BSD
- * I/O subsystem just can't deal with bizzare block sizes like
- * those used for CD-DA frames.
- */
- if (cd->flags & CDF_CDDAMODE) {
- bp->b_error = EIO;
- goto bad;
- }
-#endif
/*
* Do bounds checking, adjust transfer. if error, process.
* If end of partition, just return.
* not doing anything, otherwise just wait for completion
*/
cdstart(cd);
-
+
+ device_unref(&cd->sc_dev);
splx(opri);
return;
*/
bp->b_resid = bp->b_bcount;
biodone(bp);
+ if (cd != NULL)
+ device_unref(&cd->sc_dev);
}
/*
cdminphys(bp)
struct buf *bp;
{
- struct cd_softc *cd = cd_cd.cd_devs[CDUNIT(bp->b_dev)];
+ struct cd_softc *cd;
long max;
+ cd = cdlookup(CDUNIT(bp->b_dev));
+ if (cd == NULL)
+ return;
+
/*
* If the device is ancient, we want to make sure that
* the transfer fits into a 6-byte cdb.
int flag;
struct proc *p;
{
- struct cd_softc *cd = cd_cd.cd_devs[CDUNIT(dev)];
+ struct cd_softc *cd;
int part = CDPART(dev);
- int error;
+ int error = 0;
+
+ cd = cdlookup(CDUNIT(dev));
+ if (cd == NULL)
+ return ENXIO;
SC_DEBUG(cd->sc_link, SDEV_DB2, ("cdioctl 0x%lx ", cmd));
/* FALLTHROUGH */
default:
if ((cd->sc_link->flags & SDEV_OPEN) == 0)
- return (ENODEV);
+ error = ENODEV;
else
- return (EIO);
+ error = EIO;
+ goto exit;
}
}
case DIOCRLDINFO:
cdgetdisklabel(dev, cd, cd->sc_dk.dk_label,
cd->sc_dk.dk_cpulabel, 0);
- return 0;
+ break;
case DIOCGDINFO:
case DIOCGPDINFO:
*(struct disklabel *)addr = *(cd->sc_dk.dk_label);
- return 0;
+ break;
case DIOCGPART:
((struct partinfo *)addr)->disklab = cd->sc_dk.dk_label;
((struct partinfo *)addr)->part =
&cd->sc_dk.dk_label->d_partitions[CDPART(dev)];
- return 0;
+ break;
case DIOCWDINFO:
case DIOCSDINFO:
- if ((flag & FWRITE) == 0)
- return EBADF;
+ if ((flag & FWRITE) == 0) {
+ error = EBADF;
+ break;
+ }
if ((error = cdlock(cd)) != 0)
- return error;
+ break;
+
cd->flags |= CDF_LABELLING;
error = setdisklabel(cd->sc_dk.dk_label,
cd->flags &= ~CDF_LABELLING;
cdunlock(cd);
- return error;
-
+ break;
+
case DIOCWLABEL:
- return EBADF;
+ error = EBADF;
+ break;
case CDIOCPLAYTRACKS: {
struct ioc_play_track *args = (struct ioc_play_track *)addr;
if ((error = (*cd->sc_ops->cdo_set_pa_immed)(cd, 0)) != 0)
- return (error);
- return (cd_play_tracks(cd, args->start_track,
- args->start_index, args->end_track, args->end_index));
+ 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->sc_ops->cdo_set_pa_immed)(cd, 0)) != 0)
- return (error);
- return (cd_play_msf(cd, args->start_m, args->start_s,
- args->start_f, args->end_m, args->end_s, args->end_f));
+ 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->sc_ops->cdo_set_pa_immed)(cd, 0)) != 0)
- return (error);
- return (cd_play(cd, args->blk, args->len));
+ break;
+ error = cd_play(cd, args->blk, args->len);
+ break;
}
case CDIOCREADSUBCHANNEL: {
struct ioc_read_subchannel *args
struct cd_sub_channel_info data;
int len = args->data_len;
if (len > sizeof(data) ||
- len < sizeof(struct cd_sub_channel_header))
- return EINVAL;
+ 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)
- return error;
+ break;
len = min(len, _2btol(data.header.data_len) +
sizeof(struct cd_sub_channel_header));
- return copyout(&data, args->data, len);
+ 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)
- return (error);
- if (cd->sc_link->quirks & ADEV_LITTLETOC) {
+ break;
+ if (cd->sc_link->quirks & ADEV_LITTLETOC)
th.len = letoh16(th.len);
- } else
+ else
th.len = ntohs(th.len);
bcopy(&th, addr, sizeof(th));
- return (0);
+ break;
}
case CDIOREADTOCENTRYS: {
struct cd_toc *toc;
struct cd_toc_entry *cte;
int len = te->data_len;
int ntracks;
- int res;
MALLOC (toc, struct cd_toc *, sizeof (struct cd_toc),
M_DEVBUF, M_WAITOK);
if (len > sizeof(toc->entries) ||
len < sizeof(struct cd_toc_entry)) {
FREE(toc, M_DEVBUF);
- return (EINVAL);
+ 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_DEVBUF);
- return (error);
+ break;
}
if (te->address_format == CD_LBA_FORMAT)
for (ntracks =
len = min(len, th->len - (sizeof(th->starting_track) +
sizeof(th->ending_track)));
- res = copyout(toc->entries, te->data, len);
+ error = copyout(toc->entries, te->data, len);
FREE(toc, M_DEVBUF);
-
- return (res);
+ break;
}
case CDIOREADMSADDR: {
struct cd_toc *toc;
int sessno = *(int*)addr;
struct cd_toc_entry *cte;
- if (sessno != 0)
- return (EINVAL);
+ if (sessno != 0) {
+ error = EINVAL;
+ break;
+ }
MALLOC (toc, struct cd_toc *, sizeof (struct cd_toc),
M_DEVBUF, M_WAITOK);
if (error) {
FREE(toc, M_DEVBUF);
- return (error);
+ break;
}
cte = &toc->entries[0];
#endif
} else
cte->addr.lba = ntohl(cte->addr.lba);
- if (cd->sc_link->quirks & ADEV_LITTLETOC) {
+ if (cd->sc_link->quirks & ADEV_LITTLETOC)
toc->header.len = letoh16(toc->header.len);
- } else
+ else
toc->header.len = ntohs(toc->header.len);
*(int*)addr = (toc->header.len >= 10 && cte->track > 1) ?
cte->addr.lba : 0;
FREE(toc, M_DEVBUF);
- return 0;
+ break;
}
case CDIOCSETPATCH: {
struct ioc_patch *arg = (struct ioc_patch *)addr;
- return ((*cd->sc_ops->cdo_setchan)(cd, arg->patch[0],
- arg->patch[1], arg->patch[2], arg->patch[3], 0));
+ error = (*cd->sc_ops->cdo_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;
- return ((*cd->sc_ops->cdo_getvol)(cd, arg, 0));
+ error = (*cd->sc_ops->cdo_getvol)(cd, arg, 0);
+ break;
}
case CDIOCSETVOL: {
struct ioc_vol *arg = (struct ioc_vol *)addr;
- return ((*cd->sc_ops->cdo_setvol)(cd, arg, 0));
+ error = (*cd->sc_ops->cdo_setvol)(cd, arg, 0);
+ break;
}
case CDIOCSETMONO:
- return ((*cd->sc_ops->cdo_setchan)(cd, BOTH_CHANNEL,
- BOTH_CHANNEL, MUTE_CHANNEL, MUTE_CHANNEL, 0));
+ error = (*cd->sc_ops->cdo_setchan)(cd, BOTH_CHANNEL,
+ BOTH_CHANNEL, MUTE_CHANNEL, MUTE_CHANNEL, 0);
+ break;
case CDIOCSETSTEREO:
- return ((*cd->sc_ops->cdo_setchan)(cd, LEFT_CHANNEL,
- RIGHT_CHANNEL, MUTE_CHANNEL, MUTE_CHANNEL, 0));
+ error = (*cd->sc_ops->cdo_setchan)(cd, LEFT_CHANNEL,
+ RIGHT_CHANNEL, MUTE_CHANNEL, MUTE_CHANNEL, 0);
+ break;
case CDIOCSETMUTE:
- return ((*cd->sc_ops->cdo_setchan)(cd, MUTE_CHANNEL,
- MUTE_CHANNEL, MUTE_CHANNEL, MUTE_CHANNEL, 0));
+ error = (*cd->sc_ops->cdo_setchan)(cd, MUTE_CHANNEL,
+ MUTE_CHANNEL, MUTE_CHANNEL, MUTE_CHANNEL, 0);
+ break;
case CDIOCSETLEFT:
- return ((*cd->sc_ops->cdo_setchan)(cd, LEFT_CHANNEL,
- LEFT_CHANNEL, MUTE_CHANNEL, MUTE_CHANNEL, 0));
+ error = (*cd->sc_ops->cdo_setchan)(cd, LEFT_CHANNEL,
+ LEFT_CHANNEL, MUTE_CHANNEL, MUTE_CHANNEL, 0);
+ break;
case CDIOCSETRIGHT:
- return ((*cd->sc_ops->cdo_setchan)(cd, RIGHT_CHANNEL,
- RIGHT_CHANNEL, MUTE_CHANNEL, MUTE_CHANNEL, 0));
+ error = (*cd->sc_ops->cdo_setchan)(cd, RIGHT_CHANNEL,
+ RIGHT_CHANNEL, MUTE_CHANNEL, MUTE_CHANNEL, 0);
+ break;
+
case CDIOCRESUME:
- return cd_pause(cd, 1);
+ error = cd_pause(cd, 1);
+ break;
+
case CDIOCPAUSE:
- return cd_pause(cd, 0);
+ error = cd_pause(cd, 0);
+ break;
case CDIOCSTART:
- return scsi_start(cd->sc_link, SSS_START, 0);
+ error = scsi_start(cd->sc_link, SSS_START, 0);
+ break;
+
case CDIOCSTOP:
- return scsi_start(cd->sc_link, SSS_STOP, 0);
+ error = scsi_start(cd->sc_link, SSS_STOP, 0);
+ break;
+
case CDIOCCLOSE:
- return (scsi_start(cd->sc_link, SSS_START|SSS_LOEJ,
- SCSI_IGNORE_NOT_READY | SCSI_IGNORE_MEDIA_CHANGE));
+ 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 != MTOFFL)
- return EIO;
+ if (((struct mtop *)addr)->mt_op != MTOFFL) {
+ error = EIO;
+ break;
+ }
/* FALLTHROUGH */
case CDIOCEJECT: /* FALLTHROUGH */
case DIOCEJECT:
cd->sc_link->flags |= SDEV_EJECTING;
- return 0;
+ break;
case CDIOCALLOW:
- return scsi_prevent(cd->sc_link, PR_ALLOW, 0);
+ error = scsi_prevent(cd->sc_link, PR_ALLOW, 0);
+ break;
case CDIOCPREVENT:
- return scsi_prevent(cd->sc_link, PR_PREVENT, 0);
+ error = scsi_prevent(cd->sc_link, PR_PREVENT, 0);
+ break;
case DIOCLOCK:
- return scsi_prevent(cd->sc_link,
+ error = scsi_prevent(cd->sc_link,
(*(int *)addr) ? PR_PREVENT : PR_ALLOW, 0);
+ break;
case CDIOCSETDEBUG:
cd->sc_link->flags |= (SDEV_DB1 | SDEV_DB2);
- return 0;
+ break;
case CDIOCCLRDEBUG:
cd->sc_link->flags &= ~(SDEV_DB1 | SDEV_DB2);
- return 0;
-#ifdef CDDA
- case CDIOCSETCDDA: {
- int onoff = *(int *)addr;
- /* select CD-DA mode */
- struct scsi_cd_mode_data data;
-
- if (CDPART(dev) != RAW_PART)
- return ENOTTY;
- if ((error = cd_get_mode(cd, &data, AUDIO_PAGE)) != 0)
- return error;
- if (onoff) {
- /* turn it on */
- if (cd->flags & CDF_CDDAMODE)
- return EALREADY;
- /*
- * do not permit changing of block size if the block
- * device is open, or if some other partition (not
- * a raw partition) is open.
- */
- if (cd->sc_dk.dk_bopenmask ||
- (cd->sc_dk.dk_copenmask & ~(1 << RAW_PART)))
- return EBUSY;
-
- data.blk_desc.density = CD_DA_DENSITY_CODE;
- data.blk_desc.blklen[0] = (CD_DA_BLKSIZ >> 16) & 0xff;
- data.blk_desc.blklen[1] = (CD_DA_BLKSIZ >> 8) & 0xff;
- data.blk_desc.blklen[2] = CD_DA_BLKSIZ & 0xff;
-
- if (cd_set_mode(cd, &data) != 0)
- return EIO;
-
- cd->orig_params = cd->params;
- cd->flags |= CDF_CDDAMODE;
- } else {
- if (!(cd->flags & CDF_CDDAMODE))
- return EALREADY;
- /* turn it off */
- data.blk_desc.density = CD_NORMAL_DENSITY_CODE;
- data.blk_desc.blklen[0] = (cd->orig_params.blksize >> 16) & 0xff;
- data.blk_desc.blklen[1] = (cd->orig_params.blksize >> 8) & 0xff;
- data.blk_desc.blklen[2] = (cd->orig_params.blksize) & 0xff;
-
- if (cd_set_mode(cd, &data) != 0)
- return EIO;
-
- cd->flags &= ~CDF_CDDAMODE;
- cd->params = cd->orig_params;
- }
- if (cd_get_parms(cd, 0) != 0) {
- data.blk_desc.density = CD_NORMAL_DENSITY_CODE;
- data.blk_desc.blklen[0] = (cd->orig_params.blksize >> 16) & 0xff;
- data.blk_desc.blklen[1] = (cd->orig_params.blksize >> 8) & 0xff;
- data.blk_desc.blklen[2] = (cd->orig_params.blksize) & 0xff;
- (void) cd_set_mode(cd, &data); /* it better work...! */
- cd->params = cd->orig_params;
- return EIO;
- }
- return 0;
- }
-#endif
-
+ break;
case CDIOCRESET:
case SCIOCRESET:
- return (cd_reset(cd));
+ error = cd_reset(cd);
+ break;
case CDIOCLOADUNLOAD: {
struct ioc_load_unload *args = (struct ioc_load_unload *)addr;
- return ((*cd->sc_ops->cdo_load_unload)(cd, args->options,
- args->slot));
+ error = (*cd->sc_ops->cdo_load_unload)(cd, args->options,
+ args->slot);
+ break;
}
case DVD_AUTH:
- return (dvd_auth(cd, (union dvd_authinfo *)addr));
-
+ error = dvd_auth(cd, (union dvd_authinfo *)addr);
+ break;
case DVD_READ_STRUCT:
- return (dvd_read_struct(cd, (union dvd_struct *)addr));
-
+ error = dvd_read_struct(cd, (union dvd_struct *)addr);
+ break;
default:
- if (CDPART(dev) != RAW_PART)
- return ENOTTY;
- return scsi_do_ioctl(cd->sc_link, dev, cmd, addr, flag, p);
+ if (CDPART(dev) != RAW_PART) {
+ error = ENOTTY;
+ break;
+ }
+ error = scsi_do_ioctl(cd->sc_link, dev, cmd, addr, flag, p);
+ break;
}
-#ifdef DIAGNOSTIC
- panic("cdioctl: impossible");
-#endif
+ exit:
+
+ device_unref(&cd->sc_dev);
+ return (error);
}
/*