aboutsummaryrefslogtreecommitdiff
path: root/sys/cam
diff options
context:
space:
mode:
authorKenneth D. Merry <ken@FreeBSD.org>2000-11-04 02:05:25 +0000
committerKenneth D. Merry <ken@FreeBSD.org>2000-11-04 02:05:25 +0000
commit1087fd198e5243ff14992a8c4dbd876b281baa1a (patch)
tree778f32da890083413556f474f7bd53c9ee14c66b /sys/cam
parent70cf0d7ec34bb8b8e775891d25b814abab57f14c (diff)
Notes
Diffstat (limited to 'sys/cam')
-rw-r--r--sys/cam/scsi/scsi_cd.c93
1 files changed, 93 insertions, 0 deletions
diff --git a/sys/cam/scsi/scsi_cd.c b/sys/cam/scsi/scsi_cd.c
index 8025560b747e..662327e9cfc4 100644
--- a/sys/cam/scsi/scsi_cd.c
+++ b/sys/cam/scsi/scsi_cd.c
@@ -207,6 +207,7 @@ static int cderror(union ccb *ccb, u_int32_t cam_flags,
u_int32_t sense_flags);
static void cdprevent(struct cam_periph *periph, int action);
static int cdsize(dev_t dev, u_int32_t *size);
+static int cdfirsttrackisdata(struct cam_periph *periph);
static int cdreadtoc(struct cam_periph *periph, u_int32_t mode,
u_int32_t start, struct cd_toc_entry *data,
u_int32_t len);
@@ -920,6 +921,17 @@ cdopen(dev_t dev, int flags, int fmt, struct proc *p)
}
/*
+ * If we get a non-zero return, revert back to not reading the
+ * label off the disk. The first track is likely audio, which
+ * won't have a disklabel.
+ */
+ if ((error = cdfirsttrackisdata(periph)) != 0) {
+ softc->disk.d_dsflags &= ~DSO_COMPATLABEL;
+ softc->disk.d_dsflags |= DSO_NOLABELS;
+ error = 0;
+ }
+
+ /*
* Build prototype label for whole disk.
* Should take information about different data tracks from the
* TOC and put it in the partition table.
@@ -993,6 +1005,13 @@ cdclose(dev_t dev, int flag, int fmt, struct proc *p)
cdprevent(periph, PR_ALLOW);
/*
+ * Unconditionally set the dsopen() flags back to their default
+ * state.
+ */
+ softc->disk.d_dsflags &= ~DSO_NOLABELS;
+ softc->disk.d_dsflags |= DSO_COMPATLABEL;
+
+ /*
* Since we're closing this CD, mark the blocksize as unavailable.
* It will be marked as available whence the CD is opened again.
*/
@@ -2542,6 +2561,80 @@ cdsize(dev_t dev, u_int32_t *size)
}
+/*
+ * The idea here is to try to figure out whether the first track is data or
+ * audio. If it is data, we can at least attempt to read a disklabel off
+ * the first sector of the disk. If it is audio, there won't be a
+ * disklabel.
+ *
+ * This routine returns 0 if the first track is data, and non-zero if there
+ * is an error or the first track is audio. (If either non-zero case, we
+ * should not attempt to read the disklabel.)
+ */
+static int
+cdfirsttrackisdata(struct cam_periph *periph)
+{
+ struct cdtocdata {
+ struct ioc_toc_header header;
+ struct cd_toc_entry entries[100];
+ };
+ struct cd_softc *softc;
+ struct ioc_toc_header *th;
+ struct cdtocdata *data;
+ int num_entries, i;
+ int error, first_track_audio;
+
+ error = 0;
+ first_track_audio = -1;
+
+ softc = (struct cd_softc *)periph->softc;
+
+ data = malloc(sizeof(struct cdtocdata), M_TEMP, M_WAITOK);
+
+ th = &data->header;
+ error = cdreadtoc(periph, 0, 0, (struct cd_toc_entry *)data,
+ sizeof(*data));
+
+ if (error)
+ goto bailout;
+
+ if (softc->quirks & CD_Q_BCD_TRACKS) {
+ /* we are going to have to convert the BCD
+ * encoding on the cd to what is expected
+ */
+ th->starting_track =
+ bcd2bin(th->starting_track);
+ th->ending_track = bcd2bin(th->ending_track);
+ }
+ th->len = scsi_2btoul((u_int8_t *)&th->len);
+
+ if ((th->len - 2) > 0)
+ num_entries = (th->len - 2) / sizeof(struct cd_toc_entry);
+ else
+ num_entries = 0;
+
+ for (i = 0; i < num_entries; i++) {
+ if (data->entries[i].track == th->starting_track) {
+ if (data->entries[i].control & 0x4)
+ first_track_audio = 0;
+ else
+ first_track_audio = 1;
+ break;
+ }
+ }
+
+ if (first_track_audio == -1)
+ error = ENOENT;
+ else if (first_track_audio == 1)
+ error = EINVAL;
+ else
+ error = 0;
+bailout:
+ free(data, M_TEMP);
+
+ return(error);
+}
+
static int
cderror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
{