svn commit: r352714 - stable/12/sys/cam/scsi
Andriy Gapon
avg at FreeBSD.org
Wed Sep 25 19:46:18 UTC 2019
Author: avg
Date: Wed Sep 25 19:46:17 2019
New Revision: 352714
URL: https://svnweb.freebsd.org/changeset/base/352714
Log:
MFC r351599,r351600: scsi_cd: make the media check asynchronous
PR: 219857
Modified:
stable/12/sys/cam/scsi/scsi_cd.c
stable/12/sys/cam/scsi/scsi_cd.h
Directory Properties:
stable/12/ (props changed)
Modified: stable/12/sys/cam/scsi/scsi_cd.c
==============================================================================
--- stable/12/sys/cam/scsi/scsi_cd.c Wed Sep 25 19:29:09 2019 (r352713)
+++ stable/12/sys/cam/scsi/scsi_cd.c Wed Sep 25 19:46:17 2019 (r352714)
@@ -114,13 +114,21 @@ 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_MEDIA_WAIT = 0x2000,
+ CD_FLAG_MEDIA_SCAN_ACT = 0x4000
} cd_flags;
typedef enum {
CD_CCB_PROBE = 0x01,
CD_CCB_BUFFER_IO = 0x02,
- CD_CCB_TUR = 0x04,
+ CD_CCB_TUR = 0x03,
+ CD_CCB_MEDIA_PREVENT = 0x04,
+ CD_CCB_MEDIA_ALLOW = 0x05,
+ CD_CCB_MEDIA_SIZE = 0x06,
+ CD_CCB_MEDIA_TOC_HDR = 0x07,
+ CD_CCB_MEDIA_TOC_FULL = 0x08,
+ CD_CCB_MEDIA_TOC_LEAD = 0x09,
CD_CCB_TYPE_MASK = 0x0F,
CD_CCB_RETRY_UA = 0x10
} cd_ccb_state;
@@ -140,7 +148,13 @@ struct cd_toc_single {
typedef enum {
CD_STATE_PROBE,
- CD_STATE_NORMAL
+ CD_STATE_NORMAL,
+ CD_STATE_MEDIA_PREVENT,
+ CD_STATE_MEDIA_ALLOW,
+ CD_STATE_MEDIA_SIZE,
+ CD_STATE_MEDIA_TOC_HDR,
+ CD_STATE_MEDIA_TOC_FULL,
+ CD_STATE_MEDIA_TOC_LEAD
} cd_state;
struct cd_softc {
@@ -161,6 +175,8 @@ struct cd_softc {
struct sysctl_oid *sysctl_tree;
STAILQ_HEAD(, cd_mode_params) mode_queue;
struct cd_tocdata toc;
+ int toc_read_len;
+ struct cd_toc_single leadout;
struct disk *disk;
struct callout mediapoll_c;
@@ -246,8 +262,11 @@ static void cddone(struct cam_periph *periph,
static union cd_pages *cdgetpage(struct cd_mode_params *mode_params);
static int cdgetpagesize(int page_num);
static void cdprevent(struct cam_periph *periph, int action);
-static int cdcheckmedia(struct cam_periph *periph);
+static void cdmediaprobedone(struct cam_periph *periph);
+static int cdcheckmedia(struct cam_periph *periph, int do_wait);
+#if 0
static int cdsize(struct cam_periph *periph, u_int32_t *size);
+#endif
static int cd6byteworkaround(union ccb *ccb);
static int cderror(union ccb *ccb, u_int32_t cam_flags,
u_int32_t sense_flags);
@@ -755,7 +774,7 @@ cdopen(struct disk *dp)
* if we don't have media, but then we don't allow anything but the
* CDIOCEJECT/CDIOCCLOSE ioctls if there is no media.
*/
- cdcheckmedia(periph);
+ cdcheckmedia(periph, /*do_wait*/ 1);
CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("leaving cdopen\n"));
cam_periph_unhold(periph);
@@ -851,27 +870,19 @@ cdstrategy(struct bio *bp)
return;
}
- /*
- * If we don't have valid media, look for it before trying to
- * schedule the I/O.
- */
- if ((softc->flags & CD_FLAG_VALID_MEDIA) == 0) {
- int error;
-
- error = cdcheckmedia(periph);
- if (error != 0) {
- cam_periph_unlock(periph);
- biofinish(bp, NULL, error);
- return;
- }
- }
-
/*
* Place it in the queue of disk activities for this disk
*/
bioq_disksort(&softc->bio_queue, bp);
- xpt_schedule(periph, CAM_PRIORITY_NORMAL);
+ /*
+ * If we don't know that we have valid media, schedule the media
+ * check first. The I/O will get executed after the media check.
+ */
+ if ((softc->flags & CD_FLAG_VALID_MEDIA) == 0)
+ cdcheckmedia(periph, /*do_wait*/ 0);
+ else
+ xpt_schedule(periph, CAM_PRIORITY_NORMAL);
cam_periph_unlock(periph);
return;
@@ -883,7 +894,6 @@ cdstart(struct cam_periph *periph, union ccb *start_cc
struct cd_softc *softc;
struct bio *bp;
struct ccb_scsiio *csio;
- struct scsi_read_capacity_data *rcap;
softc = (struct cd_softc *)periph->softc;
@@ -964,16 +974,40 @@ cdstart(struct cam_periph *periph, union ccb *start_cc
break;
}
case CD_STATE_PROBE:
+ case CD_STATE_MEDIA_SIZE:
{
+ struct scsi_read_capacity_data *rcap;
rcap = (struct scsi_read_capacity_data *)malloc(sizeof(*rcap),
M_SCSICD, M_NOWAIT | M_ZERO);
if (rcap == NULL) {
xpt_print(periph->path,
- "cdstart: Couldn't malloc read_capacity data\n");
- /* cd_free_periph??? */
+ "%s: Couldn't malloc read_capacity data\n",
+ __func__);
+ xpt_release_ccb(start_ccb);
+ /*
+ * We can't probe because we can't allocate memory,
+ * so invalidate the peripheral. The system probably
+ * has larger problems at this stage. If we've
+ * already probed (and are re-probing capacity), we
+ * don't need to invalidate.
+ *
+ * XXX KDM need to reset probe state and kick out
+ * pending I/O.
+ */
+ if (softc->state == CD_STATE_PROBE)
+ cam_periph_invalidate(periph);
break;
}
+
+ /*
+ * Set the default capacity and sector size to something that
+ * GEOM can handle. This will get reset when a read capacity
+ * completes successfully.
+ */
+ softc->disk->d_sectorsize = 2048;
+ softc->disk->d_mediasize = 0;
+
csio = &start_ccb->csio;
scsi_read_capacity(csio,
/*retries*/ cd_retry_count,
@@ -983,11 +1017,112 @@ cdstart(struct cam_periph *periph, union ccb *start_cc
SSD_FULL_SIZE,
/*timeout*/20000);
start_ccb->ccb_h.ccb_bp = NULL;
- start_ccb->ccb_h.ccb_state = CD_CCB_PROBE;
+ if (softc->state == CD_STATE_PROBE)
+ start_ccb->ccb_h.ccb_state = CD_CCB_PROBE;
+ else
+ start_ccb->ccb_h.ccb_state = CD_CCB_MEDIA_SIZE;
xpt_action(start_ccb);
break;
}
+ case CD_STATE_MEDIA_ALLOW:
+ case CD_STATE_MEDIA_PREVENT:
+ {
+ /*
+ * If the CD is already locked, we don't need to do this.
+ * Move on to the capacity check.
+ */
+ if ((softc->flags & CD_FLAG_DISC_LOCKED) != 0) {
+ softc->state = CD_STATE_MEDIA_SIZE;
+ xpt_release_ccb(start_ccb);
+ xpt_schedule(periph, CAM_PRIORITY_NORMAL);
+ break;
+ }
+
+ scsi_prevent(&start_ccb->csio,
+ /*retries*/ cd_retry_count,
+ /*cbfcnp*/ cddone,
+ /*tag_action*/ MSG_SIMPLE_Q_TAG,
+ /*action*/ (softc->state == CD_STATE_MEDIA_ALLOW) ?
+ PR_ALLOW : PR_PREVENT,
+ /*sense_len*/ SSD_FULL_SIZE,
+ /*timeout*/ 60000);
+
+ start_ccb->ccb_h.ccb_bp = NULL;
+ if (softc->state == CD_STATE_MEDIA_ALLOW)
+ start_ccb->ccb_h.ccb_state = CD_CCB_MEDIA_ALLOW;
+ else
+ start_ccb->ccb_h.ccb_state = CD_CCB_MEDIA_PREVENT;
+ xpt_action(start_ccb);
+ break;
}
+ case CD_STATE_MEDIA_TOC_HDR: {
+ struct ioc_toc_header *toch;
+
+ bzero(&softc->toc, sizeof(softc->toc));
+
+ toch = &softc->toc.header;
+
+ scsi_read_toc(&start_ccb->csio,
+ /*retries*/ cd_retry_count,
+ /*cbfcnp*/ cddone,
+ /*tag_action*/ MSG_SIMPLE_Q_TAG,
+ /*byte1_flags*/ 0,
+ /*format*/ SRTOC_FORMAT_TOC,
+ /*track*/ 0,
+ /*data_ptr*/ (uint8_t *)toch,
+ /*dxfer_len*/ sizeof(*toch),
+ /*sense_len*/ SSD_FULL_SIZE,
+ /*timeout*/ 50000);
+ start_ccb->ccb_h.ccb_bp = NULL;
+ start_ccb->ccb_h.ccb_state = CD_CCB_MEDIA_TOC_HDR;
+ xpt_action(start_ccb);
+ break;
+ }
+ case CD_STATE_MEDIA_TOC_FULL: {
+
+ bzero(&softc->toc, sizeof(softc->toc));
+
+ scsi_read_toc(&start_ccb->csio,
+ /*retries*/ cd_retry_count,
+ /*cbfcnp*/ cddone,
+ /*tag_action*/ MSG_SIMPLE_Q_TAG,
+ /*byte1_flags*/ 0,
+ /*format*/ SRTOC_FORMAT_TOC,
+ /*track*/ 0,
+ /*data_ptr*/ (uint8_t *)&softc->toc,
+ /*dxfer_len*/ softc->toc_read_len ?
+ softc->toc_read_len :
+ sizeof(softc->toc),
+ /*sense_len*/ SSD_FULL_SIZE,
+ /*timeout*/ 50000);
+ start_ccb->ccb_h.ccb_bp = NULL;
+ start_ccb->ccb_h.ccb_state = CD_CCB_MEDIA_TOC_FULL;
+ xpt_action(start_ccb);
+ break;
+ }
+ case CD_STATE_MEDIA_TOC_LEAD: {
+ struct cd_toc_single *leadout;
+
+ leadout = &softc->leadout;
+ bzero(leadout, sizeof(*leadout));
+
+ scsi_read_toc(&start_ccb->csio,
+ /*retries*/ cd_retry_count,
+ /*cbfcnp*/ cddone,
+ /*tag_action*/ MSG_SIMPLE_Q_TAG,
+ /*byte1_flags*/ CD_MSF,
+ /*format*/ SRTOC_FORMAT_TOC,
+ /*track*/ LEADOUT,
+ /*data_ptr*/ (uint8_t *)leadout,
+ /*dxfer_len*/ sizeof(*leadout),
+ /*sense_len*/ SSD_FULL_SIZE,
+ /*timeout*/ 50000);
+ start_ccb->ccb_h.ccb_bp = NULL;
+ start_ccb->ccb_h.ccb_state = CD_CCB_MEDIA_TOC_LEAD;
+ xpt_action(start_ccb);
+ break;
+ }
+ }
}
static void
@@ -1251,6 +1386,293 @@ cddone(struct cam_periph *periph, union ccb *done_ccb)
cam_periph_release_locked(periph);
return;
}
+ case CD_CCB_MEDIA_ALLOW:
+ case CD_CCB_MEDIA_PREVENT:
+ {
+ int error;
+ int is_prevent;
+
+ error = 0;
+
+ if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
+ error = cderror(done_ccb, CAM_RETRY_SELTO,
+ SF_RETRY_UA | SF_NO_PRINT);
+ }
+ if (error == ERESTART)
+ return;
+ if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
+ cam_release_devq(done_ccb->ccb_h.path,
+ /*relsim_flags*/0,
+ /*reduction*/0,
+ /*timeout*/0,
+ /*getcount_only*/0);
+
+ /*
+ * Note that just like the original cdcheckmedia(), we do
+ * a prevent without failing the whole operation if the
+ * prevent fails. We try, but keep going if it doesn't
+ * work.
+ */
+
+ if ((done_ccb->ccb_h.ccb_state & CD_CCB_TYPE_MASK) ==
+ CD_CCB_MEDIA_PREVENT)
+ is_prevent = 1;
+ else
+ is_prevent = 0;
+
+ xpt_release_ccb(done_ccb);
+
+ if (is_prevent != 0) {
+ if (error == 0)
+ softc->flags |= CD_FLAG_DISC_LOCKED;
+ else
+ softc->flags &= ~CD_FLAG_DISC_LOCKED;
+ softc->state = CD_STATE_MEDIA_SIZE;
+ xpt_schedule(periph, CAM_PRIORITY_NORMAL);
+ } else {
+ if (error == 0)
+ softc->flags &= ~CD_FLAG_DISC_LOCKED;
+ softc->state = CD_STATE_NORMAL;
+ if (bioq_first(&softc->bio_queue) != NULL)
+ xpt_schedule(periph, CAM_PRIORITY_NORMAL);
+ }
+ return;
+ }
+ case CD_CCB_MEDIA_SIZE:
+ {
+ struct scsi_read_capacity_data *rdcap;
+ int error;
+
+ error = 0;
+ if ((csio->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
+ error = cderror(done_ccb, CAM_RETRY_SELTO,
+ SF_RETRY_UA | SF_NO_PRINT);
+ }
+ if (error == ERESTART)
+ return;
+ if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
+ cam_release_devq(done_ccb->ccb_h.path,
+ /*relsim_flags*/0,
+ /*reduction*/0,
+ /*timeout*/0,
+ /*getcount_only*/0);
+ rdcap = (struct scsi_read_capacity_data *)csio->data_ptr;
+
+ if (error == 0) {
+ softc->params.disksize =scsi_4btoul(rdcap->addr) + 1;
+ softc->params.blksize = scsi_4btoul(rdcap->length);
+
+ /* Make sure we got at least some block size. */
+ if (softc->params.blksize == 0)
+ error = EIO;
+ /*
+ * SCSI-3 mandates that the reported blocksize shall be
+ * 2048. Older drives sometimes report funny values,
+ * trim it down to 2048, or other parts of the kernel
+ * will get confused.
+ *
+ * XXX we leave drives alone that might report 512
+ * bytes, as well as drives reporting more weird
+ * sizes like perhaps 4K.
+ */
+ if (softc->params.blksize > 2048
+ && softc->params.blksize <= 2352)
+ softc->params.blksize = 2048;
+ }
+ free(rdcap, M_SCSICD);
+
+ if (error == 0) {
+ softc->disk->d_sectorsize = softc->params.blksize;
+ softc->disk->d_mediasize =
+ (off_t)softc->params.blksize *
+ softc->params.disksize;
+ softc->flags |= CD_FLAG_SAW_MEDIA | CD_FLAG_VALID_MEDIA;
+ softc->state = CD_STATE_MEDIA_TOC_HDR;
+ } else {
+ softc->flags &= ~(CD_FLAG_VALID_MEDIA |
+ CD_FLAG_VALID_TOC);
+ bioq_flush(&softc->bio_queue, NULL, EINVAL);
+ softc->state = CD_STATE_MEDIA_ALLOW;
+ cdmediaprobedone(periph);
+ }
+ xpt_release_ccb(done_ccb);
+ xpt_schedule(periph, CAM_PRIORITY_NORMAL);
+ return;
+ }
+ case CD_CCB_MEDIA_TOC_HDR:
+ case CD_CCB_MEDIA_TOC_FULL:
+ case CD_CCB_MEDIA_TOC_LEAD:
+ {
+ int error;
+ struct ioc_toc_header *toch;
+ int num_entries;
+ int cdindex;
+
+ error = 0;
+
+ if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
+ error = cderror(done_ccb, CAM_RETRY_SELTO,
+ SF_RETRY_UA | SF_NO_PRINT);
+ }
+ if (error == ERESTART)
+ return;
+
+ if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
+ cam_release_devq(done_ccb->ccb_h.path,
+ /*relsim_flags*/0,
+ /*reduction*/0,
+ /*timeout*/0,
+ /*getcount_only*/0);
+
+ /*
+ * We will get errors here for media that doesn't have a table
+ * of contents. According to the MMC-3 spec: "When a Read
+ * TOC/PMA/ATIP command is presented for a DDCD/CD-R/RW media,
+ * where the first TOC has not been recorded (no complete
+ * session) and the Format codes 0000b, 0001b, or 0010b are
+ * specified, this command shall be rejected with an INVALID
+ * FIELD IN CDB. Devices that are not capable of reading an
+ * incomplete session on DDC/CD-R/RW media shall report
+ * CANNOT READ MEDIUM - INCOMPATIBLE FORMAT."
+ *
+ * So this isn't fatal if we can't read the table of contents,
+ * it just means that the user won't be able to issue the
+ * play tracks ioctl, and likely lots of other stuff won't
+ * work either. They need to burn the CD before we can do
+ * a whole lot with it. So we don't print anything here if
+ * we get an error back.
+ *
+ * We also bail out if the drive doesn't at least give us
+ * the full TOC header.
+ */
+ if ((error != 0)
+ || ((csio->dxfer_len - csio->resid) <
+ sizeof(struct ioc_toc_header))) {
+ softc->flags &= ~CD_FLAG_VALID_TOC;
+ bzero(&softc->toc, sizeof(softc->toc));
+ /*
+ * Failing the TOC read is not an error.
+ */
+ softc->state = CD_STATE_NORMAL;
+ xpt_release_ccb(done_ccb);
+
+ cdmediaprobedone(periph);
+
+ /*
+ * Go ahead and schedule I/O execution if there is
+ * anything in the queue. It'll probably get
+ * kicked out with an error.
+ */
+ if (bioq_first(&softc->bio_queue) != NULL)
+ xpt_schedule(periph, CAM_PRIORITY_NORMAL);
+ return;
+ }
+
+ /*
+ * Note that this is NOT the storage location used for the
+ * leadout!
+ */
+ toch = &softc->toc.header;
+
+ if (softc->quirks & CD_Q_BCD_TRACKS) {
+ toch->starting_track = bcd2bin(toch->starting_track);
+ toch->ending_track = bcd2bin(toch->ending_track);
+ }
+
+ /* Number of TOC entries, plus leadout */
+ num_entries = (toch->ending_track - toch->starting_track) + 2;
+ cdindex = toch->starting_track + num_entries -1;
+
+ if ((done_ccb->ccb_h.ccb_state & CD_CCB_TYPE_MASK) ==
+ CD_CCB_MEDIA_TOC_HDR) {
+ if (num_entries <= 0) {
+ softc->flags &= ~CD_FLAG_VALID_TOC;
+ bzero(&softc->toc, sizeof(softc->toc));
+ /*
+ * Failing the TOC read is not an error.
+ */
+ softc->state = CD_STATE_NORMAL;
+ xpt_release_ccb(done_ccb);
+
+ cdmediaprobedone(periph);
+
+ /*
+ * Go ahead and schedule I/O execution if
+ * there is anything in the queue. It'll
+ * probably get kicked out with an error.
+ */
+ if (bioq_first(&softc->bio_queue) != NULL)
+ xpt_schedule(periph,
+ CAM_PRIORITY_NORMAL);
+ } else {
+ softc->toc_read_len = num_entries *
+ sizeof(struct cd_toc_entry);
+ softc->toc_read_len += sizeof(*toch);
+
+ softc->state = CD_STATE_MEDIA_TOC_FULL;
+ xpt_release_ccb(done_ccb);
+ xpt_schedule(periph, CAM_PRIORITY_NORMAL);
+ }
+
+ return;
+ } else if ((done_ccb->ccb_h.ccb_state & CD_CCB_TYPE_MASK) ==
+ CD_CCB_MEDIA_TOC_LEAD) {
+ struct cd_toc_single *leadout;
+
+ leadout = (struct cd_toc_single *)csio->data_ptr;
+ softc->toc.entries[cdindex - toch->starting_track] =
+ leadout->entry;
+ } else if (((done_ccb->ccb_h.ccb_state & CD_CCB_TYPE_MASK) ==
+ CD_CCB_MEDIA_TOC_FULL)
+ && (cdindex == toch->ending_track + 1)) {
+ /*
+ * XXX KDM is this necessary? Probably only if the
+ * drive doesn't return leadout information with the
+ * table of contents.
+ */
+ softc->state = CD_STATE_MEDIA_TOC_LEAD;
+ xpt_release_ccb(done_ccb);
+ xpt_schedule(periph, CAM_PRIORITY_NORMAL);
+ return;
+ }
+
+ if (softc->quirks & CD_Q_BCD_TRACKS) {
+ for (cdindex = 0; cdindex < num_entries - 1; cdindex++){
+ softc->toc.entries[cdindex].track =
+ bcd2bin(softc->toc.entries[cdindex].track);
+ }
+ }
+
+ softc->flags |= CD_FLAG_VALID_TOC;
+ /* If the first track is audio, correct sector size. */
+ if ((softc->toc.entries[0].control & 4) == 0) {
+ softc->disk->d_sectorsize =softc->params.blksize = 2352;
+ softc->disk->d_mediasize =
+ (off_t)softc->params.blksize *
+ softc->params.disksize;
+ }
+ softc->state = CD_STATE_NORMAL;
+
+ /*
+ * We unconditionally (re)set the blocksize each time the
+ * CD device is opened. This is because the CD can change,
+ * and therefore the blocksize might change.
+ * XXX problems here if some slice or partition is still
+ * open with the old size?
+ */
+ if ((softc->disk->d_devstat->flags & DEVSTAT_BS_UNAVAILABLE)!=0)
+ softc->disk->d_devstat->flags &=
+ ~DEVSTAT_BS_UNAVAILABLE;
+ softc->disk->d_devstat->block_size = softc->params.blksize;
+
+ xpt_release_ccb(done_ccb);
+
+ cdmediaprobedone(periph);
+
+ if (bioq_first(&softc->bio_queue) != NULL)
+ xpt_schedule(periph, CAM_PRIORITY_NORMAL);
+ return;
+ }
default:
break;
}
@@ -1343,7 +1765,7 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int f
&& ((cmd != CDIOCCLOSE)
&& (cmd != CDIOCEJECT))
&& (IOCGROUP(cmd) == 'c')) {
- error = cdcheckmedia(periph);
+ error = cdcheckmedia(periph, /*do_wait*/ 1);
if (error != 0) {
cam_periph_unhold(periph);
cam_periph_unlock(periph);
@@ -2227,11 +2649,66 @@ cdprevent(struct cam_periph *periph, int action)
}
}
+static void
+cdmediaprobedone(struct cam_periph *periph)
+{
+ struct cd_softc *softc;
+
+ softc = (struct cd_softc *)periph->softc;
+
+ softc->flags &= ~CD_FLAG_MEDIA_SCAN_ACT;
+
+ if ((softc->flags & CD_FLAG_MEDIA_WAIT) != 0) {
+ softc->flags &= ~CD_FLAG_MEDIA_WAIT;
+ wakeup(&softc->toc);
+ }
+}
+
/*
* XXX: the disk media and sector size is only really able to change
* XXX: while the device is closed.
*/
+
static int
+cdcheckmedia(struct cam_periph *periph, int do_wait)
+{
+ struct cd_softc *softc;
+ int error;
+
+ softc = (struct cd_softc *)periph->softc;
+ error = 0;
+
+ if ((do_wait != 0)
+ && ((softc->flags & CD_FLAG_MEDIA_WAIT) == 0)) {
+ softc->flags |= CD_FLAG_MEDIA_WAIT;
+ }
+ if ((softc->flags & CD_FLAG_MEDIA_SCAN_ACT) == 0) {
+ softc->state = CD_STATE_MEDIA_PREVENT;
+ softc->flags |= CD_FLAG_MEDIA_SCAN_ACT;
+ xpt_schedule(periph, CAM_PRIORITY_NORMAL);
+ }
+
+ if (do_wait == 0)
+ goto bailout;
+
+ error = msleep(&softc->toc, cam_periph_mtx(periph), PRIBIO,"cdmedia",0);
+
+ if (error != 0)
+ goto bailout;
+
+ /*
+ * Check to see whether we have a valid size from the media. We
+ * may or may not have a valid TOC.
+ */
+ if ((softc->flags & CD_FLAG_VALID_MEDIA) == 0)
+ error = EINVAL;
+bailout:
+
+ return (error);
+}
+
+#if 0
+static int
cdcheckmedia(struct cam_periph *periph)
{
struct cd_softc *softc;
@@ -2427,6 +2904,7 @@ cdsize(struct cam_periph *periph, u_int32_t *size)
return (error);
}
+#endif
static int
cd6byteworkaround(union ccb *ccb)
@@ -2650,7 +3128,6 @@ static int
cdreadtoc(struct cam_periph *periph, u_int32_t mode, u_int32_t start,
u_int8_t *data, u_int32_t len, u_int32_t sense_flags)
{
- struct scsi_read_toc *scsi_cmd;
u_int32_t ntoc;
struct ccb_scsiio *csio;
union ccb *ccb;
@@ -2663,29 +3140,18 @@ cdreadtoc(struct cam_periph *periph, u_int32_t mode, u
csio = &ccb->csio;
- cam_fill_csio(csio,
+ scsi_read_toc(csio,
/* retries */ cd_retry_count,
/* cbfcnp */ NULL,
- /* flags */ CAM_DIR_IN,
/* tag_action */ MSG_SIMPLE_Q_TAG,
+ /* byte1_flags */ (mode == CD_MSF_FORMAT) ? CD_MSF : 0,
+ /* format */ SRTOC_FORMAT_TOC,
+ /* track*/ start,
/* data_ptr */ data,
/* dxfer_len */ len,
/* sense_len */ SSD_FULL_SIZE,
- sizeof(struct scsi_read_toc),
- /* timeout */ 50000);
+ /* timeout */ 50000);
- scsi_cmd = (struct scsi_read_toc *)&csio->cdb_io.cdb_bytes;
- bzero (scsi_cmd, sizeof(*scsi_cmd));
-
- if (mode == CD_MSF_FORMAT)
- scsi_cmd->byte2 |= CD_MSF;
- scsi_cmd->from_track = start;
- /* scsi_ulto2b(ntoc, (u_int8_t *)scsi_cmd->data_len); */
- scsi_cmd->data_len[0] = (ntoc) >> 8;
- scsi_cmd->data_len[1] = (ntoc) & 0xff;
-
- scsi_cmd->op_code = READ_TOC;
-
error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
/*sense_flags*/SF_RETRY_UA | sense_flags);
@@ -3742,4 +4208,39 @@ scsi_read_dvd_structure(struct ccb_scsiio *csio, u_int
sense_len,
sizeof(*scsi_cmd),
timeout);
+}
+
+void
+scsi_read_toc(struct ccb_scsiio *csio, uint32_t retries,
+ void (*cbfcnp)(struct cam_periph *, union ccb *),
+ uint8_t tag_action, uint8_t byte1_flags, uint8_t format,
+ uint8_t track, uint8_t *data_ptr, uint32_t dxfer_len,
+ int sense_len, int timeout)
+{
+ struct scsi_read_toc *scsi_cmd;
+
+ scsi_cmd = (struct scsi_read_toc *)&csio->cdb_io.cdb_bytes;
+ bzero(scsi_cmd, sizeof(*scsi_cmd));
+ scsi_cmd->op_code = READ_TOC;
+
+ /*
+ * The structure is counting from 1, the function counting from 0.
+ * The spec counts from 0. In MMC-6, there is only one flag, the
+ * MSF flag. But we put the whole byte in for a bit a future-proofing.
+ */
+ scsi_cmd->byte2 = byte1_flags;
+ scsi_cmd->format = format;
+ scsi_cmd->from_track = track;
+ scsi_ulto2b(dxfer_len, scsi_cmd->data_len);
+
+ cam_fill_csio(csio,
+ /* retries */ retries,
+ /* cbfcnp */ cbfcnp,
+ /* flags */ CAM_DIR_IN,
+ /* tag_action */ tag_action,
+ /* data_ptr */ data_ptr,
+ /* dxfer_len */ dxfer_len,
+ /* sense_len */ sense_len,
+ sizeof(*scsi_cmd),
+ /* timeout */ timeout);
}
Modified: stable/12/sys/cam/scsi/scsi_cd.h
==============================================================================
--- stable/12/sys/cam/scsi/scsi_cd.h Wed Sep 25 19:29:09 2019 (r352713)
+++ stable/12/sys/cam/scsi/scsi_cd.h Wed Sep 25 19:46:17 2019 (r352714)
@@ -231,6 +231,12 @@ struct scsi_read_toc
u_int8_t op_code;
u_int8_t byte2;
u_int8_t format;
+#define SRTOC_FORMAT_TOC 0x00
+#define SRTOC_FORMAT_LAST_ADDR 0x01
+#define SRTOC_FORMAT_QSUB_TOC 0x02
+#define SRTOC_FORMAT_QSUB_PMA 0x03
+#define SRTOC_FORMAT_ATIP 0x04
+#define SRTOC_FORMAT_CD_TEXT 0x05
u_int8_t unused[3];
u_int8_t from_track;
u_int8_t data_len[2];
@@ -870,6 +876,12 @@ void scsi_read_dvd_structure(struct ccb_scsiio *csio,
u_int8_t agid, u_int8_t *data_ptr,
u_int32_t dxfer_len, u_int8_t sense_len,
u_int32_t timeout);
+
+void scsi_read_toc(struct ccb_scsiio *csio, uint32_t retries,
+ void (*cbfcnp)(struct cam_periph *, union ccb *),
+ uint8_t tag_action, uint8_t byte1_flags, uint8_t format,
+ uint8_t track, uint8_t *data_ptr, uint32_t dxfer_len,
+ int sense_len, int timeout);
__END_DECLS
More information about the svn-src-all
mailing list