After so many people have been bugging me :), finally implement

read-mode access to CD-ROM media in the worm(4) driver.  No whistles
and bells yet, like all the CDIO* commands, but at least a start.

In order to do this, i had to slightly rearrange the semantics of an
open(2) on the worm driver: now, opening it with O_NONBLOCK set means
no actual IO operations will be intended but only ioctls are to be
processed.  This mode is used by wormcontrol(8) to prepare a track
and/or session.

I have only been able to test this on a 2.2-GAMMA system by now, and
only the !DEVFS part is tested yet.  Also, i have only done a dummy
burn so far, but wouldn't expect many surprises else.  Report bugs to
me ASAP, if there's reasonable demand and i hear no objections, i
might consider merging it into the 2.2 branch as well.
This commit is contained in:
Joerg Wunsch 1997-02-06 22:19:44 +00:00
parent e040f03b1c
commit ab865e3435
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=22354

View file

@ -46,13 +46,6 @@
* $FreeBSD$
*/
/* XXX This is PRELIMINARY.
*
* Until Bruce finishes the slice stuff there will be no partitions.
* When it is finished I hope to hoist the partition code up into
* "scsi_driver" and use common code for all devices.
*/
#include "opt_bounce.h"
#include "opt_scsi.h"
@ -99,7 +92,9 @@ struct scsi_data
u_int32_t n_blks; /* Number of blocks (0 for bogus) */
u_int32_t blk_size; /* Size of each blocks */
#ifdef DEVFS
void *devfs_token; /* more elaborate later */
void *b_devfs_token;
void *c_devfs_token;
void *ctl_devfs_token;
#endif
struct worm_quirks *quirks; /* model-specific functions */
@ -113,6 +108,7 @@ struct scsi_data
#define WORMFL_DISK_PREPED 0x01 /* disk parameters have been spec'ed */
#define WORMFL_TRACK_PREPED 0x02 /* track parameters have been spec'ed */
#define WORMFL_WRITTEN 0x04 /* track has been written */
#define WORMFL_IOCTL_ONLY 0x08 /* O_NDELAY, only ioctls allowed */
};
static void wormstart(u_int32_t unit, u_int32_t flags);
@ -148,10 +144,11 @@ static d_ioctl_t wormioctl;
static d_strategy_t wormstrategy;
#define CDEV_MAJOR 62
static struct cdevsw worm_cdevsw =
{ wormopen, wormclose, rawread, rawwrite, /*62*/
wormioctl, nostop, nullreset, nodevtotty,/* worm */
seltrue, nommap, wormstrategy };
#define BDEV_MAJOR 23
static struct cdevsw worm_cdevsw;
static struct bdevsw worm_bdevsw =
{ wormopen, wormclose, wormstrategy, wormioctl, /*23*/
nodump, nopsize, 0, "worm", &worm_cdevsw, -1 };
static int
@ -250,12 +247,15 @@ wormattach(struct scsi_link *sc_link)
#ifdef DEVFS
mynor = wormunit(sc_link->dev);
worm->devfs_token =
worm->b_devfs_token =
devfs_add_devswf(&worm_bdevsw, mynor,
DV_BLK, 0, 0, 0444, "worm%d", mynor);
worm->c_devfs_token =
devfs_add_devswf(&worm_cdevsw, mynor,
DV_CHR, 0, 0, 0600, "rworm%d", mynor);
worm->devfs_token =
DV_CHR, 0, 0, 0644, "rworm%d", mynor);
worm->ctl_devfs_token =
devfs_add_devswf(&worm_cdevsw, mynor | SCSI_CONTROL_MASK,
DV_CHR, 0, 0, 0600, "rworm%d.ctl", mynor);
DV_CHR, 0, 0, 0600, "rworm%d.ctl", mynor);
#endif
return 0;
}
@ -374,6 +374,15 @@ worm_strategy(struct buf *bp, struct scsi_link *sc_link)
unit = wormunit(bp->b_dev);
worm = sc_link->sd;
if ((worm->worm_flags & WORMFL_IOCTL_ONLY) != 0) {
SC_DEBUG(sc_link, SDEV_DB3,
("attempted IO on ioctl-only descriptor\n"));
bp->b_error = EBADF;
bp->b_flags |= B_ERROR;
biodone(bp);
return;
}
/*
* The ugly modulo operation is necessary since audio tracks
* have a block size of 2352 bytes.
@ -382,7 +391,11 @@ worm_strategy(struct buf *bp, struct scsi_link *sc_link)
bp->b_blkno * DEV_BSIZE > worm->n_blks * worm->blk_size||
(bp->b_bcount % worm->blk_size) != 0) {
SC_DEBUG(sc_link, SDEV_DB3,
("worm block size / capacity error") );
("worm block size / capacity error, "
"b_blkno = %d, n_blks = %d, blk_size = %d, "
"b_bcount = %d\n",
bp->b_blkno, worm->n_blks, worm->blk_size,
bp->b_bcount) );
bp->b_error = EIO;
bp->b_flags |= B_ERROR;
biodone(bp);
@ -453,13 +466,13 @@ worm_open(dev_t dev, int flags, int fmt, struct proc *p,
/*
* The semantics of the "flags" is as follows:
*
* If the device has been opened O_RDONLY, no write will be
* allowed, and the command sequence is only subject to the
* restrictions as in worm_ioctl() below.
* If the device has been opened with O_NONBLOCK set, no
* actual IO will be allowed, and the command sequence is only
* subject to the restrictions as in worm_ioctl() below.
*
* If the device is to be opened with O_RDWR/O_WRONLY, the
* disk and track must have been prepared accordingly by
* preceding ioctls (on an O_RDONLY descriptor for the device),
* preceding ioctls (on an O_NONBLOCK descriptor for the device),
* or a sequence error will result here.
*/
if ((flags & FWRITE) != 0 &&
@ -467,11 +480,12 @@ worm_open(dev_t dev, int flags, int fmt, struct proc *p,
SC_DEBUG(sc_link, SDEV_DB3, ("sequence error\n"));
return ENXIO;
}
/*
* Next time actually take notice of error returns
* Next time actually take notice of error returns,
* unit attn errors are now errors.
*/
sc_link->flags |= SDEV_OPEN; /* unit attn errors are now errors */
sc_link->flags |= SDEV_OPEN;
if (scsi_test_unit_ready(sc_link, SCSI_SILENT) != 0) {
SC_DEBUG(sc_link, SDEV_DB3, ("not ready\n"));
@ -481,26 +495,35 @@ worm_open(dev_t dev, int flags, int fmt, struct proc *p,
return ENXIO;
}
/*
* XXX The check might go away if we wanna support CDROM, too.
*/
if ((flags & FWRITE) != 0) {
if ((flags & O_NONBLOCK) == 0) {
scsi_start_unit(sc_link, SCSI_SILENT);
scsi_prevent(sc_link, PR_PREVENT, SCSI_SILENT);
}
if((flags & FWRITE) != 0 &&
((error = worm_rezero_unit(sc_link)) != 0 ||
(error = worm_size(sc_link, 0)) != 0 ||
(error = (worm->quirks->prepare_track)
(sc_link, worm->audio, worm->preemp)) != 0)) {
SC_DEBUG(sc_link, SDEV_DB3,
("rezero, get size, or prepare_track failed\n"));
scsi_stop_unit(sc_link, 0, SCSI_SILENT);
scsi_prevent(sc_link, PR_ALLOW, SCSI_SILENT);
worm->worm_flags &= ~WORMFL_TRACK_PREPED;
sc_link->flags &= ~SDEV_OPEN;
}
if((flags & FWRITE) != 0) {
if ((error = worm_rezero_unit(sc_link)) != 0 ||
(error = worm_size(sc_link, 0)) != 0 ||
(error = (worm->quirks->prepare_track)
(sc_link, worm->audio, worm->preemp)) != 0) {
SC_DEBUG(sc_link, SDEV_DB3,
("rezero, get size, or prepare_track failed\n"));
scsi_stop_unit(sc_link, 0, SCSI_SILENT);
scsi_prevent(sc_link, PR_ALLOW, SCSI_SILENT);
worm->worm_flags &= ~WORMFL_TRACK_PREPED;
sc_link->flags &= ~SDEV_OPEN;
}
} else {
/* read/only */
if ((error = worm_size(sc_link, 0)) != 0) {
SC_DEBUG(sc_link, SDEV_DB3,
("get size failed\n"));
scsi_stop_unit(sc_link, 0, SCSI_SILENT);
scsi_prevent(sc_link, PR_ALLOW, SCSI_SILENT);
worm->worm_flags &= ~WORMFL_TRACK_PREPED;
sc_link->flags &= ~SDEV_OPEN;
}
}
} else
worm->worm_flags |= WORMFL_IOCTL_ONLY;
return error;
}
@ -510,18 +533,25 @@ worm_close(dev_t dev, int flags, int fmt, struct proc *p,
struct scsi_link *sc_link)
{
struct scsi_data *worm = sc_link->sd;
errval error;
scsi_stop_unit(sc_link, 0, SCSI_SILENT);
scsi_prevent(sc_link, PR_ALLOW, SCSI_SILENT);
error = 0;
sc_link->flags &= ~SDEV_OPEN;
if ((worm->worm_flags & WORMFL_IOCTL_ONLY) == 0) {
scsi_stop_unit(sc_link, 0, SCSI_SILENT);
scsi_prevent(sc_link, PR_ALLOW, SCSI_SILENT);
if((flags & FWRITE) != 0) {
worm->worm_flags &= ~WORMFL_TRACK_PREPED;
(worm->quirks->finalize_track)(sc_link);
sc_link->flags &= ~SDEV_OPEN;
if ((flags & FWRITE) != 0) {
worm->worm_flags &= ~WORMFL_TRACK_PREPED;
error = (worm->quirks->finalize_track)(sc_link);
}
}
sc_link->flags &= ~SDEV_OPEN;
worm->worm_flags &= ~WORMFL_IOCTL_ONLY;
return 0;
return error;
}
/*
@ -675,11 +705,9 @@ worm_quirk_select(struct scsi_link *sc_link, u_int32_t unit,
static void
worm_drvinit(void *unused)
{
dev_t dev;
if (! worm_devsw_installed) {
dev = makedev(CDEV_MAJOR, 0);
cdevsw_add(&dev, &worm_cdevsw, NULL);
if (!worm_devsw_installed) {
bdevsw_add_generic(BDEV_MAJOR, CDEV_MAJOR, &worm_bdevsw);
worm_devsw_installed = 1;
}
}