FreeBSD Bugzilla – Attachment 195055 Details for
Bug 219857
panic in scsi_cd code
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Proposed patch to make the media check async
scsi_cd.async_check.20180629.txt (text/plain), 21.87 KB, created by
Kenneth D. Merry
on 2018-07-11 15:37:18 UTC
(
hide
)
Description:
Proposed patch to make the media check async
Filename:
MIME Type:
Creator:
Kenneth D. Merry
Created:
2018-07-11 15:37:18 UTC
Size:
21.87 KB
patch
obsolete
>Index: scsi_cd.c >=================================================================== >--- scsi_cd.c (revision 335477) >+++ scsi_cd.c (working copy) >@@ -112,13 +112,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; >@@ -138,7 +146,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 { >@@ -159,6 +173,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; > >@@ -233,7 +249,8 @@ 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); > static int cdsize(struct cam_periph *periph, u_int32_t *size); > static int cd6byteworkaround(union ccb *ccb); > static int cderror(union ccb *ccb, u_int32_t cam_flags, >@@ -742,7 +759,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); >@@ -838,27 +855,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; >@@ -870,7 +879,6 @@ cdstart(struct cam_periph *periph, union ccb *star > struct cd_softc *softc; > struct bio *bp; > struct ccb_scsiio *csio; >- struct scsi_read_capacity_data *rcap; > > softc = (struct cd_softc *)periph->softc; > >@@ -951,16 +959,40 @@ cdstart(struct cam_periph *periph, union ccb *star > 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, >@@ -970,11 +1002,112 @@ cdstart(struct cam_periph *periph, union ccb *star > 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 >@@ -1238,6 +1371,293 @@ cddone(struct cam_periph *periph, union ccb *done_ > 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; > } >@@ -1307,7 +1727,7 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, i > && ((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); >@@ -2197,11 +2617,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; >@@ -2341,6 +2816,7 @@ bailout: > > return (error); > } >+#endif > > static int > cdsize(struct cam_periph *periph, u_int32_t *size) >@@ -2620,7 +3096,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; >@@ -2633,29 +3108,18 @@ cdreadtoc(struct cam_periph *periph, u_int32_t mod > > 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); > >@@ -3713,3 +4177,38 @@ scsi_read_dvd_structure(struct ccb_scsiio *csio, u > 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); >+} >Index: scsi_cd.h >=================================================================== >--- scsi_cd.h (revision 335477) >+++ scsi_cd.h (working copy) >@@ -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]; >@@ -871,6 +877,12 @@ void scsi_read_dvd_structure(struct ccb_scsiio *cs > 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 > > #endif /*_SCSI_SCSI_CD_H*/
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 219857
: 195055 |
195314
|
195315
|
209512