summaryrefslogtreecommitdiffstats
path: root/sys/cam/scsi/scsi_cd.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/cam/scsi/scsi_cd.c')
-rw-r--r--sys/cam/scsi/scsi_cd.c438
1 files changed, 244 insertions, 194 deletions
diff --git a/sys/cam/scsi/scsi_cd.c b/sys/cam/scsi/scsi_cd.c
index 07782ba..fa85ada 100644
--- a/sys/cam/scsi/scsi_cd.c
+++ b/sys/cam/scsi/scsi_cd.c
@@ -70,6 +70,7 @@ __FBSDID("$FreeBSD$");
#include <cam/cam_periph.h>
#include <cam/cam_xpt_periph.h>
#include <cam/cam_queue.h>
+#include <cam/cam_sim.h>
#include <cam/scsi/scsi_message.h>
#include <cam/scsi/scsi_da.h>
@@ -103,7 +104,8 @@ typedef enum {
CD_FLAG_RETRY_UA = 0x0200,
CD_FLAG_VALID_MEDIA = 0x0400,
CD_FLAG_VALID_TOC = 0x0800,
- CD_FLAG_SCTX_INIT = 0x1000
+ CD_FLAG_SCTX_INIT = 0x1000,
+ CD_FLAG_OPEN = 0x2000
} cd_flags;
typedef enum {
@@ -290,9 +292,6 @@ static struct periph_driver cddriver =
PERIPHDRIVER_DECLARE(cd, cddriver);
-
-static int num_changers;
-
#ifndef CHANGER_MIN_BUSY_SECONDS
#define CHANGER_MIN_BUSY_SECONDS 5
#endif
@@ -319,15 +318,16 @@ struct cdchanger {
struct camq devq;
struct timeval start_time;
struct cd_softc *cur_device;
- struct callout_handle short_handle;
- struct callout_handle long_handle;
+ struct callout short_handle;
+ struct callout long_handle;
volatile cd_changer_flags flags;
STAILQ_ENTRY(cdchanger) changer_links;
STAILQ_HEAD(chdevlist, cd_softc) chluns;
};
+static struct mtx changerq_mtx;
static STAILQ_HEAD(changerlist, cdchanger) changerq;
-
+static int num_changers;
static void
cdinit(void)
@@ -335,6 +335,9 @@ cdinit(void)
cam_status status;
struct cam_path *path;
+ mtx_init(&changerq_mtx, "cdchangerq", "SCSI CD Changer List", MTX_DEF);
+ STAILQ_INIT(&changerq);
+
/*
* Install a global async callback. This callback will
* receive async callbacks like "new device found".
@@ -364,7 +367,6 @@ cdinit(void)
static void
cdoninvalidate(struct cam_periph *periph)
{
- int s;
struct cd_softc *softc;
struct ccb_setasync csa;
@@ -384,19 +386,11 @@ cdoninvalidate(struct cam_periph *periph)
softc->flags |= CD_FLAG_INVALID;
/*
- * Although the oninvalidate() routines are always called at
- * splsoftcam, we need to be at splbio() here to keep the buffer
- * queue from being modified while we traverse it.
- */
- s = splbio();
-
- /*
* Return all queued I/O with ENXIO.
* XXX Handle any transactions queued to the card
* with XPT_ABORT_CCB.
*/
bioq_flush(&softc->bio_queue, NULL, ENXIO);
- splx(s);
/*
* If this device is part of a changer, and it was scheduled
@@ -415,7 +409,6 @@ static void
cdcleanup(struct cam_periph *periph)
{
struct cd_softc *softc;
- int s;
softc = (struct cd_softc *)periph->softc;
@@ -426,7 +419,6 @@ cdcleanup(struct cam_periph *periph)
xpt_print(periph->path, "can't remove sysctl context\n");
}
- s = splsoftcam();
/*
* In the queued, non-active case, the device in question
* has already been removed from the changer run queue. Since this
@@ -456,8 +448,7 @@ cdcleanup(struct cam_periph *periph)
* be any bogus pointer references there.
*/
if (softc->changer->flags & CHANGER_SHORT_TMOUT_SCHED) {
- untimeout(cdshorttimeout, softc->changer,
- softc->changer->short_handle);
+ callout_stop(&softc->changer->short_handle);
softc->changer->flags &= ~CHANGER_SHORT_TMOUT_SCHED;
}
softc->changer->devq.qfrozen_cnt--;
@@ -478,26 +469,25 @@ cdcleanup(struct cam_periph *periph)
* it won't hurt to check and see if there are any left.
*/
if (softc->changer->flags & CHANGER_TIMEOUT_SCHED) {
- untimeout(cdrunchangerqueue, softc->changer,
- softc->changer->long_handle);
+ callout_stop(&softc->changer->long_handle);
softc->changer->flags &= ~CHANGER_TIMEOUT_SCHED;
}
if (softc->changer->flags & CHANGER_SHORT_TMOUT_SCHED) {
- untimeout(cdshorttimeout, softc->changer,
- softc->changer->short_handle);
+ callout_stop(&softc->changer->short_handle);
softc->changer->flags &= ~CHANGER_SHORT_TMOUT_SCHED;
}
+ mtx_lock(&changerq_mtx);
STAILQ_REMOVE(&changerq, softc->changer, cdchanger,
changer_links);
+ num_changers--;
+ mtx_unlock(&changerq_mtx);
xpt_print(periph->path, "removing changer entry\n");
free(softc->changer, M_DEVBUF);
- num_changers--;
}
disk_destroy(softc->disk);
free(softc, M_DEVBUF);
- splx(s);
}
static void
@@ -544,10 +534,8 @@ cdasync(void *callback_arg, u_int32_t code,
{
struct cd_softc *softc;
struct ccb_hdr *ccbh;
- int s;
softc = (struct cd_softc *)periph->softc;
- s = splsoftcam();
/*
* Don't fail on the expected unit attention
* that will occur.
@@ -555,7 +543,6 @@ cdasync(void *callback_arg, u_int32_t code,
softc->flags |= CD_FLAG_RETRY_UA;
LIST_FOREACH(ccbh, &softc->pending_ccbs, periph_links.le)
ccbh->ccb_state |= CD_CCB_RETRY_UA;
- splx(s);
/* FALLTHROUGH */
}
default:
@@ -572,8 +559,10 @@ cdsysctlinit(void *context, int pending)
char tmpstr[80], tmpstr2[80];
periph = (struct cam_periph *)context;
- softc = (struct cd_softc *)periph->softc;
+ if (cam_periph_acquire(periph) != CAM_REQ_CMP)
+ return;
+ softc = (struct cd_softc *)periph->softc;
snprintf(tmpstr, sizeof(tmpstr), "CAM CD unit %d", periph->unit_number);
snprintf(tmpstr2, sizeof(tmpstr2), "%d", periph->unit_number);
@@ -588,6 +577,7 @@ cdsysctlinit(void *context, int pending)
if (softc->sysctl_tree == NULL) {
printf("cdsysctlinit: unable to allocate sysctl tree\n");
mtx_unlock(&Giant);
+ cam_periph_release(periph);
return;
}
@@ -601,6 +591,7 @@ cdsysctlinit(void *context, int pending)
"Minimum CDB size");
mtx_unlock(&Giant);
+ cam_periph_release(periph);
}
/*
@@ -734,6 +725,7 @@ cdregister(struct cam_periph *periph, void *arg)
* WORM peripheral driver. WORM drives will also have the WORM
* driver attached to them.
*/
+ cam_periph_unlock(periph);
softc->disk = disk_alloc();
softc->disk->d_devstat = devstat_new_entry("cd",
periph->unit_number, 0,
@@ -747,8 +739,9 @@ cdregister(struct cam_periph *periph, void *arg)
softc->disk->d_name = "cd";
softc->disk->d_unit = periph->unit_number;
softc->disk->d_drv1 = periph;
- softc->disk->d_flags = DISKFLAG_NEEDSGIANT;
+ softc->disk->d_flags = 0;
disk_create(softc->disk, DISK_VERSION);
+ cam_periph_lock(periph);
/*
* Add an async callback so that we get
@@ -783,13 +776,11 @@ cdregister(struct cam_periph *periph, void *arg)
/* Set the changer flag in the current device's softc */
softc->flags |= CD_FLAG_CHANGER;
- if (num_changers == 0)
- STAILQ_INIT(&changerq);
-
/*
* Now, look around for an existing changer device with the
* same path and target ID as the current device.
*/
+ mtx_lock(&changerq_mtx);
for (found = 0,
nchanger = (struct cdchanger *)STAILQ_FIRST(&changerq);
nchanger != NULL;
@@ -800,6 +791,7 @@ cdregister(struct cam_periph *periph, void *arg)
break;
}
}
+ mtx_unlock(&changerq_mtx);
/*
* If we found a matching entry, just add this device to
@@ -905,8 +897,6 @@ cdregister(struct cam_periph *periph, void *arg)
goto cdregisterexit;
}
- num_changers++;
-
nchanger->path_id = cgd->ccb_h.path_id;
nchanger->target_id = cgd->ccb_h.target_id;
@@ -915,8 +905,16 @@ cdregister(struct cam_periph *periph, void *arg)
STAILQ_INIT(&nchanger->chluns);
+ callout_init_mtx(&nchanger->long_handle,
+ periph->sim->mtx, 0);
+ callout_init_mtx(&nchanger->short_handle,
+ periph->sim->mtx, 0);
+
+ mtx_lock(&changerq_mtx);
+ num_changers++;
STAILQ_INSERT_TAIL(&changerq, nchanger,
changer_links);
+ mtx_unlock(&changerq_mtx);
/*
* Create a path with lun id 0, and see if we can
@@ -978,9 +976,11 @@ cdregister(struct cam_periph *periph, void *arg)
cdregisterexit:
- /* Lock this peripheral until we are setup */
- /* Can't block */
- cam_periph_lock(periph, PRIBIO);
+ /*
+ * Refcount and block open attempts until we are setup
+ * Can't block
+ */
+ (void)cam_periph_hold(periph, PRIBIO);
if ((softc->flags & CD_FLAG_CHANGER) == 0)
xpt_schedule(periph, /*priority*/5);
@@ -996,7 +996,6 @@ cdopen(struct disk *dp)
struct cam_periph *periph;
struct cd_softc *softc;
int error;
- int s;
periph = (struct cam_periph *)dp->d_drv1;
if (periph == NULL)
@@ -1004,24 +1003,28 @@ cdopen(struct disk *dp)
softc = (struct cd_softc *)periph->softc;
- /*
- * Grab splsoftcam and hold it until we lock the peripheral.
- */
- s = splsoftcam();
+ if (cam_periph_acquire(periph) != CAM_REQ_CMP)
+ return(ENXIO);
+
+ cam_periph_lock(periph);
+
if (softc->flags & CD_FLAG_INVALID) {
- splx(s);
+ cam_periph_unlock(periph);
+ cam_periph_release(periph);
return(ENXIO);
}
- if ((error = cam_periph_lock(periph, PRIBIO | PCATCH)) != 0) {
- splx(s);
+ if ((error = cam_periph_hold(periph, PRIBIO | PCATCH)) != 0) {
+ cam_periph_unlock(periph);
+ cam_periph_release(periph);
return (error);
}
- splx(s);
-
- if (cam_periph_acquire(periph) != CAM_REQ_CMP)
- return(ENXIO);
+ /* Closes aren't symmetrical with opens, so fix up the refcounting. */
+ if (softc->flags & CD_FLAG_OPEN)
+ cam_periph_release(periph);
+ else
+ softc->flags |= CD_FLAG_OPEN;
/*
* Check for media, and set the appropriate flags. We don't bail
@@ -1030,11 +1033,11 @@ cdopen(struct disk *dp)
*/
cdcheckmedia(periph);
- cam_periph_unlock(periph);
-
CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("leaving cdopen\n"));
+ cam_periph_unhold(periph);
+ cam_periph_unlock(periph);
- return (error);
+ return (0);
}
static int
@@ -1042,7 +1045,6 @@ cdclose(struct disk *dp)
{
struct cam_periph *periph;
struct cd_softc *softc;
- int error;
periph = (struct cam_periph *)dp->d_drv1;
if (periph == NULL)
@@ -1050,8 +1052,8 @@ cdclose(struct disk *dp)
softc = (struct cd_softc *)periph->softc;
- if ((error = cam_periph_lock(periph, PRIBIO)) != 0)
- return (error);
+ cam_periph_lock(periph);
+ cam_periph_hold(periph, PRIBIO);
if ((softc->flags & CD_FLAG_DISC_REMOVABLE) != 0)
cdprevent(periph, PR_ALLOW);
@@ -1065,8 +1067,9 @@ cdclose(struct disk *dp)
/*
* We'll check the media and toc again at the next open().
*/
- softc->flags &= ~(CD_FLAG_VALID_MEDIA|CD_FLAG_VALID_TOC);
+ softc->flags &= ~(CD_FLAG_VALID_MEDIA|CD_FLAG_VALID_TOC|CD_FLAG_OPEN);
+ cam_periph_unhold(periph);
cam_periph_unlock(periph);
cam_periph_release(periph);
@@ -1077,9 +1080,6 @@ static void
cdshorttimeout(void *arg)
{
struct cdchanger *changer;
- int s;
-
- s = splsoftcam();
changer = (struct cdchanger *)arg;
@@ -1095,8 +1095,6 @@ cdshorttimeout(void *arg)
changer->flags |= CHANGER_MANUAL_CALL;
cdrunchangerqueue(changer);
}
-
- splx(s);
}
/*
@@ -1106,9 +1104,6 @@ static void
cdschedule(struct cam_periph *periph, int priority)
{
struct cd_softc *softc;
- int s;
-
- s = splsoftcam();
softc = (struct cd_softc *)periph->softc;
@@ -1147,9 +1142,6 @@ cdschedule(struct cam_periph *periph, int priority)
} else if ((softc->flags & CD_FLAG_ACTIVE)
&& ((softc->flags & CD_FLAG_SCHED_ON_COMP) == 0))
xpt_schedule(periph, priority);
-
- splx(s);
-
}
static void
@@ -1158,9 +1150,6 @@ cdrunchangerqueue(void *arg)
struct cd_softc *softc;
struct cdchanger *changer;
int called_from_timeout;
- int s;
-
- s = splsoftcam();
changer = (struct cdchanger *)arg;
@@ -1180,7 +1169,6 @@ cdrunchangerqueue(void *arg)
/* nothing to do if the queue is empty */
if (changer->devq.entries <= 0) {
- splx(s);
return;
}
@@ -1190,29 +1178,28 @@ cdrunchangerqueue(void *arg)
*/
if (changer->devq.qfrozen_cnt > 0) {
+ /*
+ * We always need to reset the frozen count and clear the
+ * active flag.
+ */
+ changer->devq.qfrozen_cnt--;
+ changer->cur_device->flags &= ~CD_FLAG_ACTIVE;
+ changer->cur_device->flags &= ~CD_FLAG_SCHED_ON_COMP;
+
if (changer->cur_device->outstanding_cmds > 0) {
changer->cur_device->flags |= CD_FLAG_SCHED_ON_COMP;
changer->cur_device->bufs_left =
changer->cur_device->outstanding_cmds;
if (called_from_timeout) {
- changer->long_handle =
- timeout(cdrunchangerqueue, changer,
- changer_max_busy_seconds * hz);
+ callout_reset(&changer->long_handle,
+ changer_max_busy_seconds * hz,
+ cdrunchangerqueue, changer);
changer->flags |= CHANGER_TIMEOUT_SCHED;
}
- splx(s);
return;
}
/*
- * We always need to reset the frozen count and clear the
- * active flag.
- */
- changer->devq.qfrozen_cnt--;
- changer->cur_device->flags &= ~CD_FLAG_ACTIVE;
- changer->cur_device->flags &= ~CD_FLAG_SCHED_ON_COMP;
-
- /*
* Check to see whether the current device has any I/O left
* to do. If so, requeue it at the end of the queue. If
* not, there is no need to requeue it.
@@ -1242,12 +1229,12 @@ cdrunchangerqueue(void *arg)
* ones so this device gets its full time quantum.
*/
if (changer->flags & CHANGER_TIMEOUT_SCHED) {
- untimeout(cdrunchangerqueue, changer, changer->long_handle);
+ callout_stop(&changer->long_handle);
changer->flags &= ~CHANGER_TIMEOUT_SCHED;
}
if (changer->flags & CHANGER_SHORT_TMOUT_SCHED) {
- untimeout(cdshorttimeout, changer, changer->short_handle);
+ callout_stop(&changer->short_handle);
changer->flags &= ~CHANGER_SHORT_TMOUT_SCHED;
}
@@ -1257,17 +1244,12 @@ cdrunchangerqueue(void *arg)
* switch time.
*/
changer->flags |= CHANGER_NEED_TIMEOUT;
-
- splx(s);
}
static void
cdchangerschedule(struct cd_softc *softc)
{
struct cdchanger *changer;
- int s;
-
- s = splsoftcam();
changer = softc->changer;
@@ -1313,18 +1295,18 @@ cdchangerschedule(struct cd_softc *softc)
* and schedule our timeouts.
*/
if ((changer->flags & CHANGER_TIMEOUT_SCHED) == 0) {
- changer->long_handle =
- timeout(cdrunchangerqueue, changer,
- changer_max_busy_seconds * hz);
+ callout_reset(&changer->long_handle,
+ changer_max_busy_seconds * hz,
+ cdrunchangerqueue, changer);
changer->flags |= CHANGER_TIMEOUT_SCHED;
} else
printf("cdchangerschedule: already have a long"
" timeout!\n");
if ((changer->flags & CHANGER_SHORT_TMOUT_SCHED) == 0) {
- changer->short_handle =
- timeout(cdshorttimeout, changer,
- changer_min_busy_seconds * hz);
+ callout_reset(&changer->short_handle,
+ changer_min_busy_seconds * hz,
+ cdshorttimeout, changer);
changer->flags |= CHANGER_SHORT_TMOUT_SCHED;
} else
printf("cdchangerschedule: already have a short "
@@ -1337,7 +1319,6 @@ cdchangerschedule(struct cd_softc *softc)
changer->flags &= ~CHANGER_NEED_TIMEOUT;
}
- splx(s);
}
static int
@@ -1366,14 +1347,10 @@ static union ccb *
cdgetccb(struct cam_periph *periph, u_int32_t priority)
{
struct cd_softc *softc;
- int s;
softc = (struct cd_softc *)periph->softc;
if (softc->flags & CD_FLAG_CHANGER) {
-
- s = splsoftcam();
-
/*
* This should work the first time this device is woken up,
* but just in case it doesn't, we use a while loop.
@@ -1396,9 +1373,9 @@ cdgetccb(struct cam_periph *periph, u_int32_t priority)
softc->changer->flags |= CHANGER_MANUAL_CALL;
cdrunchangerqueue(softc->changer);
} else
- tsleep(&softc->changer, PRIBIO, "cgticb", 0);
+ msleep(&softc->changer, periph->sim->mtx,
+ PRIBIO, "cgticb", 0);
}
- splx(s);
}
return(cam_periph_getccb(periph, priority));
}
@@ -1414,7 +1391,6 @@ cdstrategy(struct bio *bp)
{
struct cam_periph *periph;
struct cd_softc *softc;
- int s;
periph = (struct cam_periph *)bp->bio_disk->d_drv1;
if (periph == NULL) {
@@ -1422,22 +1398,16 @@ cdstrategy(struct bio *bp)
return;
}
+ cam_periph_lock(periph);
CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdstrategy\n"));
softc = (struct cd_softc *)periph->softc;
/*
- * Mask interrupts so that the pack cannot be invalidated until
- * after we are in the queue. Otherwise, we might not properly
- * clean up one of the buffers.
- */
- s = splbio();
-
- /*
* If the device has been made invalid, error out
*/
if ((softc->flags & CD_FLAG_INVALID)) {
- splx(s);
+ cam_periph_unlock(periph);
biofinish(bp, NULL, ENXIO);
return;
}
@@ -1451,7 +1421,7 @@ cdstrategy(struct bio *bp)
error = cdcheckmedia(periph);
if (error != 0) {
- splx(s);
+ cam_periph_unlock(periph);
biofinish(bp, NULL, error);
return;
}
@@ -1462,8 +1432,6 @@ cdstrategy(struct bio *bp)
*/
bioq_disksort(&softc->bio_queue, bp);
- splx(s);
-
/*
* Schedule ourselves for performing the work. We do things
* differently for changers.
@@ -1473,6 +1441,7 @@ cdstrategy(struct bio *bp)
else
cdschedule(periph, /* priority */ 1);
+ cam_periph_unlock(periph);
return;
}
@@ -1483,7 +1452,6 @@ cdstart(struct cam_periph *periph, union ccb *start_ccb)
struct bio *bp;
struct ccb_scsiio *csio;
struct scsi_read_capacity_data *rcap;
- int s;
softc = (struct cd_softc *)periph->softc;
@@ -1492,9 +1460,6 @@ cdstart(struct cam_periph *periph, union ccb *start_ccb)
switch (softc->state) {
case CD_STATE_NORMAL:
{
- int oldspl;
-
- s = splbio();
bp = bioq_first(&softc->bio_queue);
if (periph->immediate_priority <= periph->pinfo.priority) {
start_ccb->ccb_h.ccb_state = CD_CCB_WAITING;
@@ -1502,10 +1467,8 @@ cdstart(struct cam_periph *periph, union ccb *start_ccb)
SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h,
periph_links.sle);
periph->immediate_priority = CAM_PRIORITY_NONE;
- splx(s);
wakeup(&periph->ccb_list);
} else if (bp == NULL) {
- splx(s);
xpt_release_ccb(start_ccb);
} else {
bioq_remove(&softc->bio_queue, bp);
@@ -1529,15 +1492,9 @@ cdstart(struct cam_periph *periph, union ccb *start_ccb)
start_ccb->ccb_h.ccb_state = CD_CCB_BUFFER_IO;
- /*
- * Block out any asyncronous callbacks
- * while we touch the pending ccb list.
- */
- oldspl = splcam();
LIST_INSERT_HEAD(&softc->pending_ccbs,
&start_ccb->ccb_h, periph_links.le);
softc->outstanding_cmds++;
- splx(oldspl);
/* We expect a unit attention from this device */
if ((softc->flags & CD_FLAG_RETRY_UA) != 0) {
@@ -1547,7 +1504,6 @@ cdstart(struct cam_periph *periph, union ccb *start_ccb)
start_ccb->ccb_h.ccb_bp = bp;
bp = bioq_first(&softc->bio_queue);
- splx(s);
xpt_action(start_ccb);
}
@@ -1601,7 +1557,6 @@ cddone(struct cam_periph *periph, union ccb *done_ccb)
{
struct bio *bp;
int error;
- int oldspl;
bp = (struct bio *)done_ccb->ccb_h.ccb_bp;
error = 0;
@@ -1625,13 +1580,9 @@ cddone(struct cam_periph *periph, union ccb *done_ccb)
}
if (error != 0) {
- int s;
-
xpt_print(periph->path,
"cddone: got error %#x back\n", error);
- s = splbio();
bioq_flush(&softc->bio_queue, NULL, EIO);
- splx(s);
bp->bio_resid = bp->bio_bcount;
bp->bio_error = error;
bp->bio_flags |= BIO_ERROR;
@@ -1654,14 +1605,8 @@ cddone(struct cam_periph *periph, union ccb *done_ccb)
}
}
- /*
- * Block out any asyncronous callbacks
- * while we touch the pending ccb list.
- */
- oldspl = splcam();
LIST_REMOVE(&done_ccb->ccb_h, periph_links.le);
softc->outstanding_cmds--;
- splx(oldspl);
if (softc->flags & CD_FLAG_CHANGER)
cdchangerschedule(softc);
@@ -1852,7 +1797,7 @@ cddone(struct cam_periph *periph, union ccb *done_ccb)
* operation.
*/
xpt_release_ccb(done_ccb);
- cam_periph_unlock(periph);
+ cam_periph_unhold(periph);
return;
}
case CD_CCB_WAITING:
@@ -1905,12 +1850,13 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
struct cam_periph *periph;
struct cd_softc *softc;
- int error, nocopyout;
+ int nocopyout, error = 0;
periph = (struct cam_periph *)dp->d_drv1;
if (periph == NULL)
return(ENXIO);
+ cam_periph_lock(periph);
CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdioctl\n"));
softc = (struct cd_softc *)periph->softc;
@@ -1918,10 +1864,12 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
CAM_DEBUG(periph->path, CAM_DEBUG_TRACE,
("trying to do ioctl %#lx\n", cmd));
- error = cam_periph_lock(periph, PRIBIO | PCATCH);
+ if ((error = cam_periph_hold(periph, PRIBIO | PCATCH)) != 0) {
+ cam_periph_unlock(periph);
+ cam_periph_release(periph);
+ return (error);
+ }
- if (error != 0)
- return(error);
/*
* If we don't have media loaded, check for it. If still don't
* have media loaded, we can only do a load or eject.
@@ -1936,11 +1884,14 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
&& (cmd != CDIOCEJECT))
&& (IOCGROUP(cmd) == 'c')) {
error = cdcheckmedia(periph);
- if (error != 0) {
- cam_periph_unlock(periph);
- return (error);
- }
}
+ /*
+ * Drop the lock here so later mallocs can use WAITOK. The periph
+ * is essentially locked still with the cam_periph_hold call above.
+ */
+ cam_periph_unlock(periph);
+ if (error != 0)
+ return (error);
nocopyout = 0;
switch (cmd) {
@@ -1956,12 +1907,14 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
params.mode_buf = malloc(params.alloc_len, M_TEMP,
M_WAITOK | M_ZERO);
+ cam_periph_lock(periph);
CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
("trying to do CDIOCPLAYTRACKS\n"));
error = cdgetmode(periph, &params, AUDIO_PAGE);
if (error) {
free(params.mode_buf, M_TEMP);
+ cam_periph_unlock(periph);
break;
}
page = cdgetpage(&params);
@@ -1970,8 +1923,10 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
page->audio.flags |= CD_PA_IMMED;
error = cdsetmode(periph, &params);
free(params.mode_buf, M_TEMP);
- if (error)
+ if (error) {
+ cam_periph_unlock(periph);
break;
+ }
/*
* This was originally implemented with the PLAY
@@ -2033,6 +1988,7 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
args->end_track,
args->end_index);
}
+ cam_periph_unlock(periph);
}
break;
case CDIOCPLAYMSF:
@@ -2046,12 +2002,14 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
params.mode_buf = malloc(params.alloc_len, M_TEMP,
M_WAITOK | M_ZERO);
+ cam_periph_lock(periph);
CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
("trying to do CDIOCPLAYMSF\n"));
error = cdgetmode(periph, &params, AUDIO_PAGE);
if (error) {
free(params.mode_buf, M_TEMP);
+ cam_periph_unlock(periph);
break;
}
page = cdgetpage(&params);
@@ -2060,8 +2018,10 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
page->audio.flags |= CD_PA_IMMED;
error = cdsetmode(periph, &params);
free(params.mode_buf, M_TEMP);
- if (error)
+ if (error) {
+ cam_periph_unlock(periph);
break;
+ }
error = cdplaymsf(periph,
args->start_m,
args->start_s,
@@ -2069,6 +2029,7 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
args->end_m,
args->end_s,
args->end_f);
+ cam_periph_unlock(periph);
}
break;
case CDIOCPLAYBLOCKS:
@@ -2078,16 +2039,19 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
struct cd_mode_params params;
union cd_pages *page;
- CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
- ("trying to do CDIOCPLAYBLOCKS\n"));
-
params.alloc_len = sizeof(union cd_mode_data_6_10);
params.mode_buf = malloc(params.alloc_len, M_TEMP,
M_WAITOK | M_ZERO);
+ cam_periph_lock(periph);
+ CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
+ ("trying to do CDIOCPLAYBLOCKS\n"));
+
+
error = cdgetmode(periph, &params, AUDIO_PAGE);
if (error) {
free(params.mode_buf, M_TEMP);
+ cam_periph_unlock(periph);
break;
}
page = cdgetpage(&params);
@@ -2096,9 +2060,12 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
page->audio.flags |= CD_PA_IMMED;
error = cdsetmode(periph, &params);
free(params.mode_buf, M_TEMP);
- if (error)
+ if (error) {
+ cam_periph_unlock(periph);
break;
+ }
error = cdplay(periph, args->blk, args->len);
+ cam_periph_unlock(periph);
}
break;
case CDIOCREADSUBCHANNEL_SYSSPACE:
@@ -2111,12 +2078,13 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
struct cd_sub_channel_info *data;
u_int32_t len = args->data_len;
- CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
- ("trying to do CDIOCREADSUBCHANNEL\n"));
-
data = malloc(sizeof(struct cd_sub_channel_info),
M_TEMP, M_WAITOK);
+ cam_periph_lock(periph);
+ CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
+ ("trying to do CDIOCREADSUBCHANNEL\n"));
+
if ((len > sizeof(struct cd_sub_channel_info)) ||
(len < sizeof(struct cd_sub_channel_header))) {
printf(
@@ -2125,6 +2093,7 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
len);
error = EINVAL;
free(data, M_TEMP);
+ cam_periph_unlock(periph);
break;
}
@@ -2136,6 +2105,7 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
if (error) {
free(data, M_TEMP);
+ cam_periph_unlock(periph);
break;
}
if (softc->quirks & CD_Q_BCD_TRACKS)
@@ -2144,6 +2114,7 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
len = min(len, ((data->header.data_len[0] << 8) +
data->header.data_len[1] +
sizeof(struct cd_sub_channel_header)));
+ cam_periph_unlock(periph);
if (nocopyout == 0) {
if (copyout(data, args->data, len) != 0) {
error = EFAULT;
@@ -2159,15 +2130,18 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
{
struct ioc_toc_header *th;
+ th = malloc(sizeof(struct ioc_toc_header), M_TEMP,
+ M_WAITOK);
+
+ cam_periph_lock(periph);
CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
("trying to do CDIOREADTOCHEADER\n"));
- th = malloc(sizeof(struct ioc_toc_header), M_TEMP,
- M_WAITOK);
error = cdreadtoc(periph, 0, 0, (u_int8_t *)th,
sizeof (*th), /*sense_flags*/0);
if (error) {
free(th, M_TEMP);
+ cam_periph_unlock(periph);
break;
}
if (softc->quirks & CD_Q_BCD_TRACKS) {
@@ -2181,6 +2155,7 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
th->len = ntohs(th->len);
bcopy(th, addr, sizeof(*th));
free(th, M_TEMP);
+ cam_periph_unlock(periph);
}
break;
case CDIOREADTOCENTRYS:
@@ -2193,12 +2168,13 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
u_int32_t len, readlen, idx, num;
u_int32_t starting_track = te->starting_track;
- CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
- ("trying to do CDIOREADTOCENTRYS\n"));
-
data = malloc(sizeof(*data), M_TEMP, M_WAITOK);
lead = malloc(sizeof(*lead), M_TEMP, M_WAITOK);
+ cam_periph_lock(periph);
+ CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
+ ("trying to do CDIOREADTOCENTRYS\n"));
+
if (te->data_len < sizeof(struct cd_toc_entry)
|| (te->data_len % sizeof(struct cd_toc_entry)) != 0
|| (te->address_format != CD_MSF_FORMAT
@@ -2208,6 +2184,7 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
"returning EINVAL\n");
free(data, M_TEMP);
free(lead, M_TEMP);
+ cam_periph_unlock(periph);
break;
}
@@ -2217,6 +2194,7 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
if (error) {
free(data, M_TEMP);
free(lead, M_TEMP);
+ cam_periph_unlock(periph);
break;
}
@@ -2239,6 +2217,7 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
"returning EINVAL\n");
free(data, M_TEMP);
free(lead, M_TEMP);
+ cam_periph_unlock(periph);
error = EINVAL;
break;
}
@@ -2260,6 +2239,7 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
error = EINVAL;
free(data, M_TEMP);
free(lead, M_TEMP);
+ cam_periph_unlock(periph);
break;
}
num = len / sizeof(struct cd_toc_entry);
@@ -2273,6 +2253,7 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
if (error) {
free(data, M_TEMP);
free(lead, M_TEMP);
+ cam_periph_unlock(periph);
break;
}
}
@@ -2289,6 +2270,7 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
if (error) {
free(data, M_TEMP);
free(lead, M_TEMP);
+ cam_periph_unlock(periph);
break;
}
data->entries[idx - starting_track] =
@@ -2301,6 +2283,7 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
}
}
+ cam_periph_unlock(periph);
error = copyout(data->entries, te->data, len);
free(data, M_TEMP);
free(lead, M_TEMP);
@@ -2314,17 +2297,19 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
struct ioc_toc_header *th;
u_int32_t track;
+ data = malloc(sizeof(*data), M_TEMP, M_WAITOK);
+
+ cam_periph_lock(periph);
CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
("trying to do CDIOREADTOCENTRY\n"));
- data = malloc(sizeof(*data), M_TEMP, M_WAITOK);
-
if (te->address_format != CD_MSF_FORMAT
&& te->address_format != CD_LBA_FORMAT) {
printf("error in readtocentry, "
" returning EINVAL\n");
free(data, M_TEMP);
error = EINVAL;
+ cam_periph_unlock(periph);
break;
}
@@ -2333,6 +2318,7 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
sizeof (*th), /*sense_flags*/0);
if (error) {
free(data, M_TEMP);
+ cam_periph_unlock(periph);
break;
}
@@ -2355,6 +2341,7 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
" returning EINVAL\n");
free(data, M_TEMP);
error = EINVAL;
+ cam_periph_unlock(periph);
break;
}
@@ -2363,6 +2350,7 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
/*sense_flags*/0);
if (error) {
free(data, M_TEMP);
+ cam_periph_unlock(periph);
break;
}
@@ -2371,6 +2359,7 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
bcopy(&data->entry, &te->entry,
sizeof(struct cd_toc_entry));
free(data, M_TEMP);
+ cam_periph_unlock(periph);
}
break;
case CDIOCSETPATCH:
@@ -2379,15 +2368,18 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
struct cd_mode_params params;
union cd_pages *page;
- CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
- ("trying to do CDIOCSETPATCH\n"));
-
params.alloc_len = sizeof(union cd_mode_data_6_10);
params.mode_buf = malloc(params.alloc_len, M_TEMP,
M_WAITOK | M_ZERO);
+
+ cam_periph_lock(periph);
+ CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
+ ("trying to do CDIOCSETPATCH\n"));
+
error = cdgetmode(periph, &params, AUDIO_PAGE);
if (error) {
free(params.mode_buf, M_TEMP);
+ cam_periph_unlock(periph);
break;
}
page = cdgetpage(&params);
@@ -2400,6 +2392,7 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
page->audio.port[3].channels = arg->patch[3];
error = cdsetmode(periph, &params);
free(params.mode_buf, M_TEMP);
+ cam_periph_unlock(periph);
}
break;
case CDIOCGETVOL:
@@ -2408,15 +2401,18 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
struct cd_mode_params params;
union cd_pages *page;
- CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
- ("trying to do CDIOCGETVOL\n"));
-
params.alloc_len = sizeof(union cd_mode_data_6_10);
params.mode_buf = malloc(params.alloc_len, M_TEMP,
M_WAITOK | M_ZERO);
+
+ cam_periph_lock(periph);
+ CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
+ ("trying to do CDIOCGETVOL\n"));
+
error = cdgetmode(periph, &params, AUDIO_PAGE);
if (error) {
free(params.mode_buf, M_TEMP);
+ cam_periph_unlock(periph);
break;
}
page = cdgetpage(&params);
@@ -2428,6 +2424,7 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
arg->vol[2] = page->audio.port[2].volume;
arg->vol[3] = page->audio.port[3].volume;
free(params.mode_buf, M_TEMP);
+ cam_periph_unlock(periph);
}
break;
case CDIOCSETVOL:
@@ -2436,15 +2433,18 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
struct cd_mode_params params;
union cd_pages *page;
- CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
- ("trying to do CDIOCSETVOL\n"));
-
params.alloc_len = sizeof(union cd_mode_data_6_10);
params.mode_buf = malloc(params.alloc_len, M_TEMP,
M_WAITOK | M_ZERO);
+
+ cam_periph_lock(periph);
+ CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
+ ("trying to do CDIOCSETVOL\n"));
+
error = cdgetmode(periph, &params, AUDIO_PAGE);
if (error) {
free(params.mode_buf, M_TEMP);
+ cam_periph_unlock(periph);
break;
}
page = cdgetpage(&params);
@@ -2458,6 +2458,7 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
page->audio.port[2].volume = arg->vol[2];
page->audio.port[3].volume = arg->vol[3];
error = cdsetmode(periph, &params);
+ cam_periph_unlock(periph);
free(params.mode_buf, M_TEMP);
}
break;
@@ -2466,15 +2467,18 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
struct cd_mode_params params;
union cd_pages *page;
- CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
- ("trying to do CDIOCSETMONO\n"));
-
params.alloc_len = sizeof(union cd_mode_data_6_10);
params.mode_buf = malloc(params.alloc_len, M_TEMP,
M_WAITOK | M_ZERO);
+
+ cam_periph_lock(periph);
+ CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
+ ("trying to do CDIOCSETMONO\n"));
+
error = cdgetmode(periph, &params, AUDIO_PAGE);
if (error) {
free(params.mode_buf, M_TEMP);
+ cam_periph_unlock(periph);
break;
}
page = cdgetpage(&params);
@@ -2486,6 +2490,7 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
page->audio.port[2].channels = 0;
page->audio.port[3].channels = 0;
error = cdsetmode(periph, &params);
+ cam_periph_unlock(periph);
free(params.mode_buf, M_TEMP);
}
break;
@@ -2494,15 +2499,18 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
struct cd_mode_params params;
union cd_pages *page;
- CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
- ("trying to do CDIOCSETSTEREO\n"));
-
params.alloc_len = sizeof(union cd_mode_data_6_10);
params.mode_buf = malloc(params.alloc_len, M_TEMP,
M_WAITOK | M_ZERO);
+
+ cam_periph_lock(periph);
+ CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
+ ("trying to do CDIOCSETSTEREO\n"));
+
error = cdgetmode(periph, &params, AUDIO_PAGE);
if (error) {
free(params.mode_buf, M_TEMP);
+ cam_periph_unlock(periph);
break;
}
page = cdgetpage(&params);
@@ -2515,6 +2523,7 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
page->audio.port[3].channels = 0;
error = cdsetmode(periph, &params);
free(params.mode_buf, M_TEMP);
+ cam_periph_unlock(periph);
}
break;
case CDIOCSETMUTE:
@@ -2522,15 +2531,18 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
struct cd_mode_params params;
union cd_pages *page;
- CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
- ("trying to do CDIOCSETMUTE\n"));
-
params.alloc_len = sizeof(union cd_mode_data_6_10);
params.mode_buf = malloc(params.alloc_len, M_TEMP,
M_WAITOK | M_ZERO);
+
+ cam_periph_lock(periph);
+ CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
+ ("trying to do CDIOCSETMUTE\n"));
+
error = cdgetmode(periph, &params, AUDIO_PAGE);
if (error) {
free(&params, M_TEMP);
+ cam_periph_unlock(periph);
break;
}
page = cdgetpage(&params);
@@ -2541,6 +2553,7 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
page->audio.port[3].channels = 0;
error = cdsetmode(periph, &params);
free(params.mode_buf, M_TEMP);
+ cam_periph_unlock(periph);
}
break;
case CDIOCSETLEFT:
@@ -2548,16 +2561,18 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
struct cd_mode_params params;
union cd_pages *page;
- CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
- ("trying to do CDIOCSETLEFT\n"));
-
params.alloc_len = sizeof(union cd_mode_data_6_10);
params.mode_buf = malloc(params.alloc_len, M_TEMP,
M_WAITOK | M_ZERO);
-
+
+ cam_periph_lock(periph);
+ CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
+ ("trying to do CDIOCSETLEFT\n"));
+
error = cdgetmode(periph, &params, AUDIO_PAGE);
if (error) {
free(params.mode_buf, M_TEMP);
+ cam_periph_unlock(periph);
break;
}
page = cdgetpage(&params);
@@ -2568,6 +2583,7 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
page->audio.port[3].channels = 0;
error = cdsetmode(periph, &params);
free(params.mode_buf, M_TEMP);
+ cam_periph_unlock(periph);
}
break;
case CDIOCSETRIGHT:
@@ -2575,16 +2591,18 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
struct cd_mode_params params;
union cd_pages *page;
- CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
- ("trying to do CDIOCSETRIGHT\n"));
-
params.alloc_len = sizeof(union cd_mode_data_6_10);
params.mode_buf = malloc(params.alloc_len, M_TEMP,
M_WAITOK | M_ZERO);
+ cam_periph_lock(periph);
+ CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
+ ("trying to do CDIOCSETRIGHT\n"));
+
error = cdgetmode(periph, &params, AUDIO_PAGE);
if (error) {
free(params.mode_buf, M_TEMP);
+ cam_periph_unlock(periph);
break;
}
page = cdgetpage(&params);
@@ -2595,31 +2613,48 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
page->audio.port[3].channels = 0;
error = cdsetmode(periph, &params);
free(params.mode_buf, M_TEMP);
+ cam_periph_unlock(periph);
}
break;
case CDIOCRESUME:
+ cam_periph_lock(periph);
error = cdpause(periph, 1);
+ cam_periph_unlock(periph);
break;
case CDIOCPAUSE:
+ cam_periph_lock(periph);
error = cdpause(periph, 0);
+ cam_periph_unlock(periph);
break;
case CDIOCSTART:
+ cam_periph_lock(periph);
error = cdstartunit(periph, 0);
+ cam_periph_unlock(periph);
break;
case CDIOCCLOSE:
+ cam_periph_lock(periph);
error = cdstartunit(periph, 1);
+ cam_periph_unlock(periph);
break;
case CDIOCSTOP:
+ cam_periph_lock(periph);
error = cdstopunit(periph, 0);
+ cam_periph_unlock(periph);
break;
case CDIOCEJECT:
+ cam_periph_lock(periph);
error = cdstopunit(periph, 1);
+ cam_periph_unlock(periph);
break;
case CDIOCALLOW:
+ cam_periph_lock(periph);
cdprevent(periph, PR_ALLOW);
+ cam_periph_unlock(periph);
break;
case CDIOCPREVENT:
+ cam_periph_lock(periph);
cdprevent(periph, PR_PREVENT);
+ cam_periph_unlock(periph);
break;
case CDIOCSETDEBUG:
/* sc_link->flags |= (SDEV_DB1 | SDEV_DB2); */
@@ -2634,10 +2669,14 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
error = ENOTTY;
break;
case CDRIOCREADSPEED:
+ cam_periph_lock(periph);
error = cdsetspeed(periph, *(u_int32_t *)addr, CDR_MAX_SPEED);
+ cam_periph_unlock(periph);
break;
case CDRIOCWRITESPEED:
+ cam_periph_lock(periph);
error = cdsetspeed(periph, CDR_MAX_SPEED, *(u_int32_t *)addr);
+ cam_periph_unlock(periph);
break;
case DVDIOCSENDKEY:
case DVDIOCREPORTKEY: {
@@ -2645,10 +2684,12 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
authinfo = (struct dvd_authinfo *)addr;
+ cam_periph_lock(periph);
if (cmd == DVDIOCREPORTKEY)
error = cdreportkey(periph, authinfo);
else
error = cdsendkey(periph, authinfo);
+ cam_periph_unlock(periph);
break;
}
case DVDIOCREADSTRUCTURE: {
@@ -2656,21 +2697,27 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
dvdstruct = (struct dvd_struct *)addr;
+ cam_periph_lock(periph);
error = cdreaddvdstructure(periph, dvdstruct);
+ cam_periph_unlock(periph);
break;
}
default:
+ cam_periph_lock(periph);
error = cam_periph_ioctl(periph, cmd, addr, cderror);
+ cam_periph_unlock(periph);
break;
}
- cam_periph_unlock(periph);
-
+ cam_periph_lock(periph);
+ cam_periph_unhold(periph);
+
CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("leaving cdioctl\n"));
if (error && bootverbose) {
printf("scsi_cd.c::ioctl cmd=%08lx error=%d\n", cmd, error);
}
+ cam_periph_unlock(periph);
return (error);
}
@@ -2869,8 +2916,11 @@ cdsize(struct cam_periph *periph, u_int32_t *size)
ccb = cdgetccb(periph, /* priority */ 1);
+ /* XXX Should be M_WAITOK */
rcap_buf = malloc(sizeof(struct scsi_read_capacity_data),
- M_TEMP, M_WAITOK);
+ M_TEMP, M_NOWAIT);
+ if (rcap_buf == NULL)
+ return (ENOMEM);
scsi_read_capacity(&ccb->csio,
/*retries*/ 1,
OpenPOWER on IntegriCloud