1139743Simp/*- 239213Sgibbs * Copyright (c) 1997 Justin T. Gibbs. 3111206Sken * Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2003 Kenneth D. Merry. 439213Sgibbs * All rights reserved. 539213Sgibbs * 639213Sgibbs * Redistribution and use in source and binary forms, with or without 739213Sgibbs * modification, are permitted provided that the following conditions 839213Sgibbs * are met: 939213Sgibbs * 1. Redistributions of source code must retain the above copyright 1039213Sgibbs * notice, this list of conditions, and the following disclaimer, 1139213Sgibbs * without modification, immediately at the beginning of the file. 1239213Sgibbs * 2. The name of the author may not be used to endorse or promote products 1339213Sgibbs * derived from this software without specific prior written permission. 1439213Sgibbs * 1539213Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1639213Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1739213Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1839213Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 1939213Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2039213Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2139213Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2239213Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2339213Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2439213Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2539213Sgibbs * SUCH DAMAGE. 2639213Sgibbs */ 27116162Sobrien 28139743Simp/*- 2939213Sgibbs * Portions of this driver taken from the original FreeBSD cd driver. 3039213Sgibbs * Written by Julian Elischer (julian@tfs.com) 3139213Sgibbs * for TRW Financial Systems for use under the MACH(2.5) operating system. 3239213Sgibbs * 3339213Sgibbs * TRW Financial Systems, in accordance with their agreement with Carnegie 3439213Sgibbs * Mellon University, makes this software available to CMU to distribute 3539213Sgibbs * or use in any manner that they see fit as long as this message is kept with 3639213Sgibbs * the software. For this reason TFS also grants any other persons or 3739213Sgibbs * organisations permission to use or modify this software. 3839213Sgibbs * 3939213Sgibbs * TFS supplies this software to be publicly redistributed 4039213Sgibbs * on the understanding that TFS is not responsible for the correct 4139213Sgibbs * functioning of this software in any circumstances. 4239213Sgibbs * 4339213Sgibbs * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 4439213Sgibbs * 4539213Sgibbs * from: cd.c,v 1.83 1997/05/04 15:24:22 joerg Exp $ 4639213Sgibbs */ 4739213Sgibbs 48116162Sobrien#include <sys/cdefs.h> 49116162Sobrien__FBSDID("$FreeBSD: stable/11/sys/cam/scsi/scsi_cd.c 355863 2019-12-17 20:30:32Z ken $"); 50116162Sobrien 5140020Sken#include "opt_cd.h" 5239213Sgibbs 5339213Sgibbs#include <sys/param.h> 5439213Sgibbs#include <sys/systm.h> 5539213Sgibbs#include <sys/kernel.h> 5660041Sphk#include <sys/bio.h> 5751836Sphk#include <sys/conf.h> 5851836Sphk#include <sys/disk.h> 5939213Sgibbs#include <sys/malloc.h> 6039213Sgibbs#include <sys/cdio.h> 61105421Snjl#include <sys/cdrio.h> 6260422Sken#include <sys/dvdio.h> 6339213Sgibbs#include <sys/devicestat.h> 6439213Sgibbs#include <sys/sysctl.h> 65119708Sken#include <sys/taskqueue.h> 66120599Sphk#include <geom/geom_disk.h> 6739213Sgibbs 6839213Sgibbs#include <cam/cam.h> 6939213Sgibbs#include <cam/cam_ccb.h> 7039213Sgibbs#include <cam/cam_periph.h> 7139213Sgibbs#include <cam/cam_xpt_periph.h> 7239213Sgibbs#include <cam/cam_queue.h> 73168752Sscottl#include <cam/cam_sim.h> 7439213Sgibbs 7539213Sgibbs#include <cam/scsi/scsi_message.h> 7639213Sgibbs#include <cam/scsi/scsi_da.h> 7739213Sgibbs#include <cam/scsi/scsi_cd.h> 7839213Sgibbs 7939213Sgibbs#define LEADOUT 0xaa /* leadout toc entry */ 8039213Sgibbs 8139213Sgibbsstruct cd_params { 8239213Sgibbs u_int32_t blksize; 8339213Sgibbs u_long disksize; 8439213Sgibbs}; 8539213Sgibbs 8639213Sgibbstypedef enum { 87111206Sken CD_Q_NONE = 0x00, 88111206Sken CD_Q_NO_TOUCH = 0x01, 89111206Sken CD_Q_BCD_TRACKS = 0x02, 90278111Smav CD_Q_10_BYTE_ONLY = 0x10, 91278111Smav CD_Q_RETRY_BUSY = 0x40 9239213Sgibbs} cd_quirks; 9339213Sgibbs 94250792Ssmh#define CD_Q_BIT_STRING \ 95250792Ssmh "\020" \ 96250792Ssmh "\001NO_TOUCH" \ 97250792Ssmh "\002BCD_TRACKS" \ 98278111Smav "\00510_BYTE_ONLY" \ 99278111Smav "\007RETRY_BUSY" 100250792Ssmh 10139213Sgibbstypedef enum { 102120884Sthomas CD_FLAG_INVALID = 0x0001, 103120884Sthomas CD_FLAG_NEW_DISC = 0x0002, 104120884Sthomas CD_FLAG_DISC_LOCKED = 0x0004, 105120884Sthomas CD_FLAG_DISC_REMOVABLE = 0x0008, 106238886Smav CD_FLAG_SAW_MEDIA = 0x0010, 107120884Sthomas CD_FLAG_ACTIVE = 0x0080, 108120884Sthomas CD_FLAG_SCHED_ON_COMP = 0x0100, 109120884Sthomas CD_FLAG_RETRY_UA = 0x0200, 110120884Sthomas CD_FLAG_VALID_MEDIA = 0x0400, 111120884Sthomas CD_FLAG_VALID_TOC = 0x0800, 112352715Savg CD_FLAG_SCTX_INIT = 0x1000, 113352715Savg CD_FLAG_MEDIA_WAIT = 0x2000, 114352715Savg CD_FLAG_MEDIA_SCAN_ACT = 0x4000 11539213Sgibbs} cd_flags; 11639213Sgibbs 11739213Sgibbstypedef enum { 11839213Sgibbs CD_CCB_PROBE = 0x01, 11939213Sgibbs CD_CCB_BUFFER_IO = 0x02, 120352715Savg CD_CCB_TUR = 0x03, 121352715Savg CD_CCB_MEDIA_PREVENT = 0x04, 122352715Savg CD_CCB_MEDIA_ALLOW = 0x05, 123352715Savg CD_CCB_MEDIA_SIZE = 0x06, 124352715Savg CD_CCB_MEDIA_TOC_HDR = 0x07, 125352715Savg CD_CCB_MEDIA_TOC_FULL = 0x08, 126352715Savg CD_CCB_MEDIA_TOC_LEAD = 0x09, 12739213Sgibbs CD_CCB_TYPE_MASK = 0x0F, 12839213Sgibbs CD_CCB_RETRY_UA = 0x10 12939213Sgibbs} cd_ccb_state; 13039213Sgibbs 13139213Sgibbs#define ccb_state ppriv_field0 13239213Sgibbs#define ccb_bp ppriv_ptr1 13339213Sgibbs 134111206Skenstruct cd_tocdata { 135111206Sken struct ioc_toc_header header; 136111206Sken struct cd_toc_entry entries[100]; 137111206Sken}; 138111206Sken 139111206Skenstruct cd_toc_single { 140111206Sken struct ioc_toc_header header; 141111206Sken struct cd_toc_entry entry; 142111206Sken}; 143111206Sken 14439213Sgibbstypedef enum { 14539213Sgibbs CD_STATE_PROBE, 146352715Savg CD_STATE_NORMAL, 147352715Savg CD_STATE_MEDIA_PREVENT, 148352715Savg CD_STATE_MEDIA_ALLOW, 149352715Savg CD_STATE_MEDIA_SIZE, 150352715Savg CD_STATE_MEDIA_TOC_HDR, 151352715Savg CD_STATE_MEDIA_TOC_FULL, 152352715Savg CD_STATE_MEDIA_TOC_LEAD 15339213Sgibbs} cd_state; 15439213Sgibbs 15539213Sgibbsstruct cd_softc { 15639213Sgibbs cam_pinfo pinfo; 15739213Sgibbs cd_state state; 15846581Sken volatile cd_flags flags; 15959249Sphk struct bio_queue_head bio_queue; 16060938Sjake LIST_HEAD(, ccb_hdr) pending_ccbs; 16139213Sgibbs struct cd_params params; 16239213Sgibbs union ccb saved_ccb; 16339213Sgibbs cd_quirks quirks; 16439213Sgibbs struct cam_periph *periph; 165111206Sken int minimum_command_size; 166112262Sphk int outstanding_cmds; 167238886Smav int tur; 168119708Sken struct task sysctl_task; 169111206Sken struct sysctl_ctx_list sysctl_ctx; 170111206Sken struct sysctl_oid *sysctl_tree; 171111206Sken STAILQ_HEAD(, cd_mode_params) mode_queue; 172111206Sken struct cd_tocdata toc; 173352715Savg int toc_read_len; 174352715Savg struct cd_toc_single leadout; 175125975Sphk struct disk *disk; 176238886Smav struct callout mediapoll_c; 17739213Sgibbs}; 17839213Sgibbs 179111206Skenstruct cd_page_sizes { 180111206Sken int page; 181111206Sken int page_size; 182111206Sken}; 183111206Sken 184111206Skenstatic struct cd_page_sizes cd_page_size_table[] = 185111206Sken{ 186111206Sken { AUDIO_PAGE, sizeof(struct cd_audio_page)} 187111206Sken}; 188111206Sken 18939213Sgibbsstruct cd_quirk_entry { 19039213Sgibbs struct scsi_inquiry_pattern inq_pat; 19139213Sgibbs cd_quirks quirks; 19239213Sgibbs}; 19339213Sgibbs 19439213Sgibbs/* 195111206Sken * NOTE ON 10_BYTE_ONLY quirks: Any 10_BYTE_ONLY quirks MUST be because 196111206Sken * your device hangs when it gets a 10 byte command. Adding a quirk just 197111206Sken * to get rid of the informative diagnostic message is not acceptable. All 198111206Sken * 10_BYTE_ONLY quirks must be documented in full in a PR (which should be 199111206Sken * referenced in a comment along with the quirk) , and must be approved by 200111206Sken * ken@FreeBSD.org. Any quirks added that don't adhere to this policy may 201111206Sken * be removed until the submitter can explain why they are needed. 202111206Sken * 10_BYTE_ONLY quirks will be removed (as they will no longer be necessary) 203111206Sken * when the CAM_NEW_TRAN_CODE work is done. 20439213Sgibbs */ 20539213Sgibbsstatic struct cd_quirk_entry cd_quirk_table[] = 20639213Sgibbs{ 20739213Sgibbs { 20840262Sken { T_CDROM, SIP_MEDIA_REMOVABLE, "CHINON", "CD-ROM CDS-535","*"}, 20940262Sken /* quirks */ CD_Q_BCD_TRACKS 210278111Smav }, 211278111Smav { 212278111Smav /* 213278111Smav * VMware returns BUSY status when storage has transient 214278111Smav * connectivity problems, so better wait. 215278111Smav */ 216278111Smav {T_CDROM, SIP_MEDIA_REMOVABLE, "NECVMWar", "VMware IDE CDR10", "*"}, 217278111Smav /*quirks*/ CD_Q_RETRY_BUSY 21839213Sgibbs } 21939213Sgibbs}; 22039213Sgibbs 221120599Sphkstatic disk_open_t cdopen; 222120599Sphkstatic disk_close_t cdclose; 223120599Sphkstatic disk_ioctl_t cdioctl; 224120599Sphkstatic disk_strategy_t cdstrategy; 22539213Sgibbs 22639213Sgibbsstatic periph_init_t cdinit; 22739213Sgibbsstatic periph_ctor_t cdregister; 22839213Sgibbsstatic periph_dtor_t cdcleanup; 22939213Sgibbsstatic periph_start_t cdstart; 23040603Skenstatic periph_oninv_t cdoninvalidate; 23139213Sgibbsstatic void cdasync(void *callback_arg, u_int32_t code, 23239213Sgibbs struct cam_path *path, void *arg); 233111206Skenstatic int cdcmdsizesysctl(SYSCTL_HANDLER_ARGS); 23439213Sgibbsstatic int cdrunccb(union ccb *ccb, 23539213Sgibbs int (*error_routine)(union ccb *ccb, 23639213Sgibbs u_int32_t cam_flags, 23739213Sgibbs u_int32_t sense_flags), 23839213Sgibbs u_int32_t cam_flags, u_int32_t sense_flags); 23939213Sgibbsstatic void cddone(struct cam_periph *periph, 24039213Sgibbs union ccb *start_ccb); 241111206Skenstatic union cd_pages *cdgetpage(struct cd_mode_params *mode_params); 242111206Skenstatic int cdgetpagesize(int page_num); 243111206Skenstatic void cdprevent(struct cam_periph *periph, int action); 244352715Savgstatic void cdmediaprobedone(struct cam_periph *periph); 245352715Savgstatic int cdcheckmedia(struct cam_periph *periph, int do_wait); 246352715Savg#if 0 247111206Skenstatic int cdsize(struct cam_periph *periph, u_int32_t *size); 248352715Savg#endif 249111206Skenstatic int cd6byteworkaround(union ccb *ccb); 25039213Sgibbsstatic int cderror(union ccb *ccb, u_int32_t cam_flags, 25139213Sgibbs u_int32_t sense_flags); 252352717Savgstatic int cdreadtoc(struct cam_periph *periph, u_int32_t mode, 253352717Savg u_int32_t start, u_int8_t *data, 254111206Sken u_int32_t len, u_int32_t sense_flags); 255352717Savgstatic int cdgetmode(struct cam_periph *periph, 256111206Sken struct cd_mode_params *data, u_int32_t page); 25739213Sgibbsstatic int cdsetmode(struct cam_periph *periph, 258111206Sken struct cd_mode_params *data); 259352717Savgstatic int cdplay(struct cam_periph *periph, u_int32_t blk, 26039213Sgibbs u_int32_t len); 261352717Savgstatic int cdreadsubchannel(struct cam_periph *periph, 262352717Savg u_int32_t mode, u_int32_t format, 263352717Savg int track, 264352717Savg struct cd_sub_channel_info *data, 26539213Sgibbs u_int32_t len); 266352717Savgstatic int cdplaymsf(struct cam_periph *periph, u_int32_t startm, 267352717Savg u_int32_t starts, u_int32_t startf, 268352717Savg u_int32_t endm, u_int32_t ends, 26939213Sgibbs u_int32_t endf); 270352717Savgstatic int cdplaytracks(struct cam_periph *periph, 27139213Sgibbs u_int32_t strack, u_int32_t sindex, 27239213Sgibbs u_int32_t etrack, u_int32_t eindex); 27339213Sgibbsstatic int cdpause(struct cam_periph *periph, u_int32_t go); 27439213Sgibbsstatic int cdstopunit(struct cam_periph *periph, u_int32_t eject); 275111206Skenstatic int cdstartunit(struct cam_periph *periph, int load); 276105421Snjlstatic int cdsetspeed(struct cam_periph *periph, 277105421Snjl u_int32_t rdspeed, u_int32_t wrspeed); 27860422Skenstatic int cdreportkey(struct cam_periph *periph, 27960422Sken struct dvd_authinfo *authinfo); 28060422Skenstatic int cdsendkey(struct cam_periph *periph, 28160422Sken struct dvd_authinfo *authinfo); 28260422Skenstatic int cdreaddvdstructure(struct cam_periph *periph, 28360422Sken struct dvd_struct *dvdstruct); 284238886Smavstatic timeout_t cdmediapoll; 28539213Sgibbs 28639213Sgibbsstatic struct periph_driver cddriver = 28739213Sgibbs{ 28839213Sgibbs cdinit, "cd", 28939213Sgibbs TAILQ_HEAD_INITIALIZER(cddriver.units), /* generation */ 0 29039213Sgibbs}; 29139213Sgibbs 29272119SpeterPERIPHDRIVER_DECLARE(cd, cddriver); 29339213Sgibbs 294238886Smav#ifndef CD_DEFAULT_POLL_PERIOD 295238886Smav#define CD_DEFAULT_POLL_PERIOD 3 296238886Smav#endif 297186882Simp#ifndef CD_DEFAULT_RETRY 298186882Simp#define CD_DEFAULT_RETRY 4 299186882Simp#endif 300237689Simp#ifndef CD_DEFAULT_TIMEOUT 301237689Simp#define CD_DEFAULT_TIMEOUT 30000 302237689Simp#endif 30339213Sgibbs 304238886Smavstatic int cd_poll_period = CD_DEFAULT_POLL_PERIOD; 305186882Simpstatic int cd_retry_count = CD_DEFAULT_RETRY; 306237689Simpstatic int cd_timeout = CD_DEFAULT_TIMEOUT; 30739213Sgibbs 308227309Sedstatic SYSCTL_NODE(_kern_cam, OID_AUTO, cd, CTLFLAG_RD, 0, "CAM CDROM driver"); 309267992ShselaskySYSCTL_INT(_kern_cam_cd, OID_AUTO, poll_period, CTLFLAG_RWTUN, 310238886Smav &cd_poll_period, 0, "Media polling period in seconds"); 311267992ShselaskySYSCTL_INT(_kern_cam_cd, OID_AUTO, retry_count, CTLFLAG_RWTUN, 312186882Simp &cd_retry_count, 0, "Normal I/O retry count"); 313267992ShselaskySYSCTL_INT(_kern_cam_cd, OID_AUTO, timeout, CTLFLAG_RWTUN, 314237689Simp &cd_timeout, 0, "Timeout, in us, for read operations"); 31539213Sgibbs 316227293Sedstatic MALLOC_DEFINE(M_SCSICD, "scsi_cd", "scsi_cd buffers"); 317169562Sscottl 318104880Sphkstatic void 31939213Sgibbscdinit(void) 32039213Sgibbs{ 32139213Sgibbs cam_status status; 32239213Sgibbs 32339213Sgibbs /* 32439213Sgibbs * Install a global async callback. This callback will 32539213Sgibbs * receive async callbacks like "new device found". 32639213Sgibbs */ 327169605Sscottl status = xpt_register_async(AC_FOUND_DEVICE, cdasync, NULL, NULL); 32839213Sgibbs 32939213Sgibbs if (status != CAM_REQ_CMP) { 33039213Sgibbs printf("cd: Failed to attach master async callback " 33139213Sgibbs "due to status 0x%x!\n", status); 33239213Sgibbs } 33339213Sgibbs} 33439213Sgibbs 335237518Sken/* 336237518Sken * Callback from GEOM, called when it has finished cleaning up its 337237518Sken * resources. 338237518Sken */ 33939213Sgibbsstatic void 340237518Skencddiskgonecb(struct disk *dp) 341237518Sken{ 342237518Sken struct cam_periph *periph; 343237518Sken 344237518Sken periph = (struct cam_periph *)dp->d_drv1; 345237518Sken cam_periph_release(periph); 346237518Sken} 347237518Sken 348237518Skenstatic void 34940603Skencdoninvalidate(struct cam_periph *periph) 35040603Sken{ 35140603Sken struct cd_softc *softc; 35240603Sken 35340603Sken softc = (struct cd_softc *)periph->softc; 35440603Sken 35540603Sken /* 35640603Sken * De-register any async callbacks. 35740603Sken */ 358169605Sscottl xpt_register_async(0, cdasync, periph, periph->path); 35940603Sken 36040603Sken softc->flags |= CD_FLAG_INVALID; 36140603Sken 36240603Sken /* 36340603Sken * Return all queued I/O with ENXIO. 36440603Sken * XXX Handle any transactions queued to the card 36540603Sken * with XPT_ABORT_CCB. 36640603Sken */ 367112946Sphk bioq_flush(&softc->bio_queue, NULL, ENXIO); 36840603Sken 369152565Sjdp disk_gone(softc->disk); 37040603Sken} 37140603Sken 37240603Skenstatic void 37339213Sgibbscdcleanup(struct cam_periph *periph) 37439213Sgibbs{ 37539213Sgibbs struct cd_softc *softc; 37639213Sgibbs 37739213Sgibbs softc = (struct cd_softc *)periph->softc; 37839213Sgibbs 379168786Sscottl cam_periph_unlock(periph); 380188503Sjhb if ((softc->flags & CD_FLAG_SCTX_INIT) != 0 381188503Sjhb && sysctl_ctx_free(&softc->sysctl_ctx) != 0) { 382188503Sjhb xpt_print(periph->path, "can't remove sysctl context\n"); 383188503Sjhb } 384188503Sjhb 385238886Smav callout_drain(&softc->mediapoll_c); 386125975Sphk disk_destroy(softc->disk); 387188503Sjhb free(softc, M_DEVBUF); 388168786Sscottl cam_periph_lock(periph); 38939213Sgibbs} 39039213Sgibbs 39139213Sgibbsstatic void 39239213Sgibbscdasync(void *callback_arg, u_int32_t code, 39339213Sgibbs struct cam_path *path, void *arg) 39439213Sgibbs{ 39539213Sgibbs struct cam_periph *periph; 396238886Smav struct cd_softc *softc; 39739213Sgibbs 39839213Sgibbs periph = (struct cam_periph *)callback_arg; 39939213Sgibbs switch (code) { 40039213Sgibbs case AC_FOUND_DEVICE: 40139213Sgibbs { 40239213Sgibbs struct ccb_getdev *cgd; 40339213Sgibbs cam_status status; 40439213Sgibbs 40539213Sgibbs cgd = (struct ccb_getdev *)arg; 40679177Smjacob if (cgd == NULL) 40779177Smjacob break; 40839213Sgibbs 409195534Sscottl if (cgd->protocol != PROTO_SCSI) 410195534Sscottl break; 411287289Smav if (SID_QUAL(&cgd->inq_data) != SID_QUAL_LU_CONNECTED) 412287289Smav break; 41356148Smjacob if (SID_TYPE(&cgd->inq_data) != T_CDROM 41456148Smjacob && SID_TYPE(&cgd->inq_data) != T_WORM) 41539213Sgibbs break; 41639213Sgibbs 41739213Sgibbs /* 41839213Sgibbs * Allocate a peripheral instance for 41939213Sgibbs * this device and start the probe 42039213Sgibbs * process. 42139213Sgibbs */ 42240603Sken status = cam_periph_alloc(cdregister, cdoninvalidate, 42340603Sken cdcleanup, cdstart, 42440603Sken "cd", CAM_PERIPH_BIO, 425256843Smav path, cdasync, 42640603Sken AC_FOUND_DEVICE, cgd); 42739213Sgibbs 42839213Sgibbs if (status != CAM_REQ_CMP 42939213Sgibbs && status != CAM_REQ_INPROG) 43039213Sgibbs printf("cdasync: Unable to attach new device " 43139213Sgibbs "due to status 0x%x\n", status); 43239213Sgibbs 43339213Sgibbs break; 43439213Sgibbs } 435238886Smav case AC_UNIT_ATTENTION: 436238886Smav { 437238886Smav union ccb *ccb; 438238886Smav int error_code, sense_key, asc, ascq; 439238886Smav 440238886Smav softc = (struct cd_softc *)periph->softc; 441238886Smav ccb = (union ccb *)arg; 442238886Smav 443238886Smav /* 444238886Smav * Handle all media change UNIT ATTENTIONs except 445238886Smav * our own, as they will be handled by cderror(). 446238886Smav */ 447238886Smav if (xpt_path_periph(ccb->ccb_h.path) != periph && 448238886Smav scsi_extract_sense_ccb(ccb, 449238886Smav &error_code, &sense_key, &asc, &ascq)) { 450238886Smav if (asc == 0x28 && ascq == 0x00) 451238886Smav disk_media_changed(softc->disk, M_NOWAIT); 452238886Smav } 453238886Smav cam_periph_async(periph, code, path, arg); 454238886Smav break; 455238886Smav } 456238886Smav case AC_SCSI_AEN: 457238886Smav softc = (struct cd_softc *)periph->softc; 458238886Smav if (softc->state == CD_STATE_NORMAL && !softc->tur) { 459238886Smav if (cam_periph_acquire(periph) == CAM_REQ_CMP) { 460238886Smav softc->tur = 1; 461245310Smav xpt_schedule(periph, CAM_PRIORITY_NORMAL); 462238886Smav } 463238886Smav } 464238886Smav /* FALLTHROUGH */ 46539213Sgibbs case AC_SENT_BDR: 46639213Sgibbs case AC_BUS_RESET: 46739213Sgibbs { 46839213Sgibbs struct ccb_hdr *ccbh; 46939213Sgibbs 47039213Sgibbs softc = (struct cd_softc *)periph->softc; 47139213Sgibbs /* 47239213Sgibbs * Don't fail on the expected unit attention 47339213Sgibbs * that will occur. 47439213Sgibbs */ 47539213Sgibbs softc->flags |= CD_FLAG_RETRY_UA; 47671999Sphk LIST_FOREACH(ccbh, &softc->pending_ccbs, periph_links.le) 47739213Sgibbs ccbh->ccb_state |= CD_CCB_RETRY_UA; 47847413Sgibbs /* FALLTHROUGH */ 47939213Sgibbs } 48039213Sgibbs default: 48147413Sgibbs cam_periph_async(periph, code, path, arg); 48239213Sgibbs break; 48339213Sgibbs } 48439213Sgibbs} 48539213Sgibbs 486119708Skenstatic void 487119708Skencdsysctlinit(void *context, int pending) 488119708Sken{ 489119708Sken struct cam_periph *periph; 490119708Sken struct cd_softc *softc; 491327228Smav char tmpstr[32], tmpstr2[16]; 492119708Sken 493119708Sken periph = (struct cam_periph *)context; 494168752Sscottl if (cam_periph_acquire(periph) != CAM_REQ_CMP) 495168752Sscottl return; 496168752Sscottl 497119708Sken softc = (struct cd_softc *)periph->softc; 498119708Sken snprintf(tmpstr, sizeof(tmpstr), "CAM CD unit %d", periph->unit_number); 499119708Sken snprintf(tmpstr2, sizeof(tmpstr2), "%d", periph->unit_number); 500119708Sken 501119708Sken sysctl_ctx_init(&softc->sysctl_ctx); 502120884Sthomas softc->flags |= CD_FLAG_SCTX_INIT; 503119708Sken softc->sysctl_tree = SYSCTL_ADD_NODE(&softc->sysctl_ctx, 504119708Sken SYSCTL_STATIC_CHILDREN(_kern_cam_cd), OID_AUTO, 505119708Sken tmpstr2, CTLFLAG_RD, 0, tmpstr); 506119708Sken 507119708Sken if (softc->sysctl_tree == NULL) { 508119708Sken printf("cdsysctlinit: unable to allocate sysctl tree\n"); 509168752Sscottl cam_periph_release(periph); 510119708Sken return; 511119708Sken } 512119708Sken 513119708Sken /* 514119708Sken * Now register the sysctl handler, so the user can the value on 515119708Sken * the fly. 516119708Sken */ 517119708Sken SYSCTL_ADD_PROC(&softc->sysctl_ctx,SYSCTL_CHILDREN(softc->sysctl_tree), 518119708Sken OID_AUTO, "minimum_cmd_size", CTLTYPE_INT | CTLFLAG_RW, 519119708Sken &softc->minimum_command_size, 0, cdcmdsizesysctl, "I", 520119708Sken "Minimum CDB size"); 521119708Sken 522168752Sscottl cam_periph_release(periph); 523119708Sken} 524119708Sken 525111206Sken/* 526111206Sken * We have a handler function for this so we can check the values when the 527111206Sken * user sets them, instead of every time we look at them. 528111206Sken */ 529111206Skenstatic int 530111206Skencdcmdsizesysctl(SYSCTL_HANDLER_ARGS) 531111206Sken{ 532111206Sken int error, value; 533111206Sken 534111206Sken value = *(int *)arg1; 535111206Sken 536111206Sken error = sysctl_handle_int(oidp, &value, 0, req); 537111206Sken 538111206Sken if ((error != 0) 539111206Sken || (req->newptr == NULL)) 540111206Sken return (error); 541111206Sken 542111206Sken /* 543111206Sken * The only real values we can have here are 6 or 10. I don't 544111206Sken * really forsee having 12 be an option at any time in the future. 545111206Sken * So if the user sets something less than or equal to 6, we'll set 546111206Sken * it to 6. If he sets something greater than 6, we'll set it to 10. 547111206Sken * 548111206Sken * I suppose we could just return an error here for the wrong values, 549111206Sken * but I don't think it's necessary to do so, as long as we can 550111206Sken * determine the user's intent without too much trouble. 551111206Sken */ 552111206Sken if (value < 6) 553111206Sken value = 6; 554111206Sken else if (value > 6) 555111206Sken value = 10; 556111206Sken 557111206Sken *(int *)arg1 = value; 558111206Sken 559111206Sken return (0); 560111206Sken} 561111206Sken 56239213Sgibbsstatic cam_status 56339213Sgibbscdregister(struct cam_periph *periph, void *arg) 56439213Sgibbs{ 56539213Sgibbs struct cd_softc *softc; 566118105Snjl struct ccb_pathinq cpi; 56739213Sgibbs struct ccb_getdev *cgd; 568119708Sken char tmpstr[80]; 56939213Sgibbs caddr_t match; 57039213Sgibbs 57139213Sgibbs cgd = (struct ccb_getdev *)arg; 57239213Sgibbs if (cgd == NULL) { 57339213Sgibbs printf("cdregister: no getdev CCB, can't register device\n"); 57439213Sgibbs return(CAM_REQ_CMP_ERR); 57539213Sgibbs } 57639213Sgibbs 577203931Smav softc = (struct cd_softc *)malloc(sizeof(*softc),M_DEVBUF, 578203931Smav M_NOWAIT | M_ZERO); 57939213Sgibbs if (softc == NULL) { 58039213Sgibbs printf("cdregister: Unable to probe new device. " 581352717Savg "Unable to allocate softc\n"); 58239213Sgibbs return(CAM_REQ_CMP_ERR); 58339213Sgibbs } 58439213Sgibbs 58539213Sgibbs LIST_INIT(&softc->pending_ccbs); 586111206Sken STAILQ_INIT(&softc->mode_queue); 58739213Sgibbs softc->state = CD_STATE_PROBE; 58859249Sphk bioq_init(&softc->bio_queue); 58939213Sgibbs if (SID_IS_REMOVABLE(&cgd->inq_data)) 59039213Sgibbs softc->flags |= CD_FLAG_DISC_REMOVABLE; 59139213Sgibbs 59239213Sgibbs periph->softc = softc; 59339213Sgibbs softc->periph = periph; 59439213Sgibbs 59539213Sgibbs /* 59639213Sgibbs * See if this device has any quirks. 59739213Sgibbs */ 59839213Sgibbs match = cam_quirkmatch((caddr_t)&cgd->inq_data, 59939213Sgibbs (caddr_t)cd_quirk_table, 600298431Spfg nitems(cd_quirk_table), 60139213Sgibbs sizeof(*cd_quirk_table), scsi_inquiry_match); 60239213Sgibbs 60339213Sgibbs if (match != NULL) 60439213Sgibbs softc->quirks = ((struct cd_quirk_entry *)match)->quirks; 60539213Sgibbs else 60639213Sgibbs softc->quirks = CD_Q_NONE; 60739213Sgibbs 608118105Snjl /* Check if the SIM does not want 6 byte commands */ 609350804Smav xpt_path_inq(&cpi, periph->path); 610118105Snjl if (cpi.ccb_h.status == CAM_REQ_CMP && (cpi.hba_misc & PIM_NO_6_BYTE)) 611118105Snjl softc->quirks |= CD_Q_10_BYTE_ONLY; 612118105Snjl 613119708Sken TASK_INIT(&softc->sysctl_task, 0, cdsysctlinit, periph); 614111206Sken 615111206Sken /* The default is 6 byte commands, unless quirked otherwise */ 616111206Sken if (softc->quirks & CD_Q_10_BYTE_ONLY) 617111206Sken softc->minimum_command_size = 10; 618111206Sken else 619111206Sken softc->minimum_command_size = 6; 620111206Sken 621223557Sgibbs /* 622223557Sgibbs * Refcount and block open attempts until we are setup 623223557Sgibbs * Can't block 624223557Sgibbs */ 625220686Sjh (void)cam_periph_hold(periph, PRIBIO); 626220686Sjh cam_periph_unlock(periph); 62739213Sgibbs /* 628111206Sken * Load the user's default, if any. 629111206Sken */ 630111206Sken snprintf(tmpstr, sizeof(tmpstr), "kern.cam.cd.%d.minimum_cmd_size", 631111206Sken periph->unit_number); 632111206Sken TUNABLE_INT_FETCH(tmpstr, &softc->minimum_command_size); 633111206Sken 634111206Sken /* 6 and 10 are the only permissible values here. */ 635111206Sken if (softc->minimum_command_size < 6) 636111206Sken softc->minimum_command_size = 6; 637111206Sken else if (softc->minimum_command_size > 6) 638111206Sken softc->minimum_command_size = 10; 639111206Sken 640111206Sken /* 64139213Sgibbs * We need to register the statistics structure for this device, 64239213Sgibbs * but we don't have the blocksize yet for it. So, we register 64339213Sgibbs * the structure and indicate that we don't have the blocksize 64439213Sgibbs * yet. Unlike other SCSI peripheral drivers, we explicitly set 64539213Sgibbs * the device type here to be CDROM, rather than just ORing in 64656148Smjacob * the device type. This is because this driver can attach to either 64739213Sgibbs * CDROM or WORM devices, and we want this peripheral driver to 64839213Sgibbs * show up in the devstat list as a CD peripheral driver, not a 64939213Sgibbs * WORM peripheral driver. WORM drives will also have the WORM 65039213Sgibbs * driver attached to them. 65139213Sgibbs */ 652125975Sphk softc->disk = disk_alloc(); 653220644Smav softc->disk->d_devstat = devstat_new_entry("cd", 65439213Sgibbs periph->unit_number, 0, 655220644Smav DEVSTAT_BS_UNAVAILABLE, 656220644Smav DEVSTAT_TYPE_CDROM | 657220644Smav XPORT_DEVSTAT_TYPE(cpi.transport), 65843819Sken DEVSTAT_PRIORITY_CD); 659125975Sphk softc->disk->d_open = cdopen; 660125975Sphk softc->disk->d_close = cdclose; 661125975Sphk softc->disk->d_strategy = cdstrategy; 662237518Sken softc->disk->d_gone = cddiskgonecb; 663125975Sphk softc->disk->d_ioctl = cdioctl; 664125975Sphk softc->disk->d_name = "cd"; 665219056Snwhitehorn cam_strvis(softc->disk->d_descr, cgd->inq_data.vendor, 666219056Snwhitehorn sizeof(cgd->inq_data.vendor), sizeof(softc->disk->d_descr)); 667219056Snwhitehorn strlcat(softc->disk->d_descr, " ", sizeof(softc->disk->d_descr)); 668219056Snwhitehorn cam_strvis(&softc->disk->d_descr[strlen(softc->disk->d_descr)], 669219056Snwhitehorn cgd->inq_data.product, sizeof(cgd->inq_data.product), 670219056Snwhitehorn sizeof(softc->disk->d_descr) - strlen(softc->disk->d_descr)); 671125975Sphk softc->disk->d_unit = periph->unit_number; 672125975Sphk softc->disk->d_drv1 = periph; 673200171Smav if (cpi.maxio == 0) 674200171Smav softc->disk->d_maxsize = DFLTPHYS; /* traditional default */ 675200171Smav else if (cpi.maxio > MAXPHYS) 676200171Smav softc->disk->d_maxsize = MAXPHYS; /* for safety */ 677200171Smav else 678200171Smav softc->disk->d_maxsize = cpi.maxio; 679168752Sscottl softc->disk->d_flags = 0; 680210471Smav softc->disk->d_hba_vendor = cpi.hba_vendor; 681210471Smav softc->disk->d_hba_device = cpi.hba_device; 682210471Smav softc->disk->d_hba_subvendor = cpi.hba_subvendor; 683210471Smav softc->disk->d_hba_subdevice = cpi.hba_subdevice; 684237518Sken 685237518Sken /* 686237518Sken * Acquire a reference to the periph before we register with GEOM. 687237518Sken * We'll release this reference once GEOM calls us back (via 688237518Sken * dadiskgonecb()) telling us that our provider has been freed. 689237518Sken */ 690237518Sken if (cam_periph_acquire(periph) != CAM_REQ_CMP) { 691237518Sken xpt_print(periph->path, "%s: lost periph during " 692237518Sken "registration!\n", __func__); 693237518Sken cam_periph_lock(periph); 694237518Sken return (CAM_REQ_CMP_ERR); 695237518Sken } 696237518Sken 697125975Sphk disk_create(softc->disk, DISK_VERSION); 698168752Sscottl cam_periph_lock(periph); 69939213Sgibbs 70039213Sgibbs /* 70139213Sgibbs * Add an async callback so that we get 70239213Sgibbs * notified if this device goes away. 70339213Sgibbs */ 704238886Smav xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE | 705238886Smav AC_SCSI_AEN | AC_UNIT_ATTENTION, cdasync, periph, periph->path); 70639213Sgibbs 70739213Sgibbs /* 708238886Smav * Schedule a periodic media polling events. 709238886Smav */ 710256843Smav callout_init_mtx(&softc->mediapoll_c, cam_periph_mtx(periph), 0); 711238886Smav if ((softc->flags & CD_FLAG_DISC_REMOVABLE) && 712238886Smav (cgd->inq_flags & SID_AEN) == 0 && 713238886Smav cd_poll_period != 0) 714238886Smav callout_reset(&softc->mediapoll_c, cd_poll_period * hz, 715238886Smav cdmediapoll, periph); 716238886Smav 717264295Smav xpt_schedule(periph, CAM_PRIORITY_DEV); 71839213Sgibbs return(CAM_REQ_CMP); 71939213Sgibbs} 72039213Sgibbs 72139213Sgibbsstatic int 722120599Sphkcdopen(struct disk *dp) 72339213Sgibbs{ 72439213Sgibbs struct cam_periph *periph; 72539213Sgibbs struct cd_softc *softc; 726101940Snjl int error; 72739213Sgibbs 728120599Sphk periph = (struct cam_periph *)dp->d_drv1; 72939213Sgibbs softc = (struct cd_softc *)periph->softc; 73039213Sgibbs 731168752Sscottl if (cam_periph_acquire(periph) != CAM_REQ_CMP) 732168752Sscottl return(ENXIO); 733168752Sscottl 734168752Sscottl cam_periph_lock(periph); 735168752Sscottl 73640603Sken if (softc->flags & CD_FLAG_INVALID) { 737237518Sken cam_periph_release_locked(periph); 738168752Sscottl cam_periph_unlock(periph); 73939213Sgibbs return(ENXIO); 74040603Sken } 74139213Sgibbs 742168752Sscottl if ((error = cam_periph_hold(periph, PRIBIO | PCATCH)) != 0) { 743237518Sken cam_periph_release_locked(periph); 744168752Sscottl cam_periph_unlock(periph); 74539213Sgibbs return (error); 74641297Sken } 74739213Sgibbs 748236602Smav CAM_DEBUG(periph->path, CAM_DEBUG_TRACE | CAM_DEBUG_PERIPH, 749236602Smav ("cdopen\n")); 750236602Smav 75140020Sken /* 752111206Sken * Check for media, and set the appropriate flags. We don't bail 753111206Sken * if we don't have media, but then we don't allow anything but the 754111206Sken * CDIOCEJECT/CDIOCCLOSE ioctls if there is no media. 75551836Sphk */ 756352715Savg cdcheckmedia(periph, /*do_wait*/ 1); 75740020Sken 758168752Sscottl CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("leaving cdopen\n")); 759168752Sscottl cam_periph_unhold(periph); 76039213Sgibbs 761237518Sken cam_periph_unlock(periph); 762186371Sscottl 763168752Sscottl return (0); 76439213Sgibbs} 76539213Sgibbs 76639213Sgibbsstatic int 767120599Sphkcdclose(struct disk *dp) 76839213Sgibbs{ 76939213Sgibbs struct cam_periph *periph; 77039213Sgibbs struct cd_softc *softc; 77139213Sgibbs 772120599Sphk periph = (struct cam_periph *)dp->d_drv1; 77339213Sgibbs softc = (struct cd_softc *)periph->softc; 77439213Sgibbs 775168752Sscottl cam_periph_lock(periph); 776237336Smav if (cam_periph_hold(periph, PRIBIO) != 0) { 777237335Smav cam_periph_unlock(periph); 778237335Smav cam_periph_release(periph); 779237335Smav return (0); 780237335Smav } 78139213Sgibbs 782236602Smav CAM_DEBUG(periph->path, CAM_DEBUG_TRACE | CAM_DEBUG_PERIPH, 783236602Smav ("cdclose\n")); 784236602Smav 78539213Sgibbs if ((softc->flags & CD_FLAG_DISC_REMOVABLE) != 0) 78639213Sgibbs cdprevent(periph, PR_ALLOW); 78739213Sgibbs 78839213Sgibbs /* 78939213Sgibbs * Since we're closing this CD, mark the blocksize as unavailable. 790111206Sken * It will be marked as available when the CD is opened again. 79139213Sgibbs */ 792125975Sphk softc->disk->d_devstat->flags |= DEVSTAT_BS_UNAVAILABLE; 79339213Sgibbs 794111206Sken /* 795111206Sken * We'll check the media and toc again at the next open(). 796111206Sken */ 797237518Sken softc->flags &= ~(CD_FLAG_VALID_MEDIA|CD_FLAG_VALID_TOC); 798111206Sken 799168752Sscottl cam_periph_unhold(periph); 800237518Sken cam_periph_release_locked(periph); 80139213Sgibbs cam_periph_unlock(periph); 80239213Sgibbs 80339213Sgibbs return (0); 80439213Sgibbs} 80539213Sgibbs 80639213Sgibbsstatic int 80739213Sgibbscdrunccb(union ccb *ccb, int (*error_routine)(union ccb *ccb, 80839213Sgibbs u_int32_t cam_flags, 80939213Sgibbs u_int32_t sense_flags), 81039213Sgibbs u_int32_t cam_flags, u_int32_t sense_flags) 81139213Sgibbs{ 81239213Sgibbs struct cd_softc *softc; 81339213Sgibbs struct cam_periph *periph; 81439213Sgibbs int error; 81539213Sgibbs 81639213Sgibbs periph = xpt_path_periph(ccb->ccb_h.path); 81739213Sgibbs softc = (struct cd_softc *)periph->softc; 81839213Sgibbs 81939213Sgibbs error = cam_periph_runccb(ccb, error_routine, cam_flags, sense_flags, 820125975Sphk softc->disk->d_devstat); 82139213Sgibbs 82239213Sgibbs return(error); 82339213Sgibbs} 82439213Sgibbs 82539213Sgibbs/* 82639213Sgibbs * Actually translate the requested transfer into one the physical driver 82739213Sgibbs * can understand. The transfer is described by a buf and will include 82839213Sgibbs * only one physical transfer. 82939213Sgibbs */ 83039213Sgibbsstatic void 83159249Sphkcdstrategy(struct bio *bp) 83239213Sgibbs{ 83339213Sgibbs struct cam_periph *periph; 83439213Sgibbs struct cd_softc *softc; 83539213Sgibbs 836120599Sphk periph = (struct cam_periph *)bp->bio_disk->d_drv1; 837168752Sscottl cam_periph_lock(periph); 838236602Smav CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, 839236602Smav ("cdstrategy(%p)\n", bp)); 84039213Sgibbs 84139213Sgibbs softc = (struct cd_softc *)periph->softc; 84239213Sgibbs 84339213Sgibbs /* 84439213Sgibbs * If the device has been made invalid, error out 84539213Sgibbs */ 84639213Sgibbs if ((softc->flags & CD_FLAG_INVALID)) { 847168752Sscottl cam_periph_unlock(periph); 84876362Sphk biofinish(bp, NULL, ENXIO); 84976362Sphk return; 85039213Sgibbs } 85139213Sgibbs 85239213Sgibbs /* 85339213Sgibbs * Place it in the queue of disk activities for this disk 85439213Sgibbs */ 855112946Sphk bioq_disksort(&softc->bio_queue, bp); 85639213Sgibbs 857352715Savg /* 858352717Savg * If we don't know that we have valid media, schedule the media 859352715Savg * check first. The I/O will get executed after the media check. 860352715Savg */ 861352715Savg if ((softc->flags & CD_FLAG_VALID_MEDIA) == 0) 862352715Savg cdcheckmedia(periph, /*do_wait*/ 0); 863352715Savg else 864352715Savg xpt_schedule(periph, CAM_PRIORITY_NORMAL); 86539213Sgibbs 866168752Sscottl cam_periph_unlock(periph); 86739213Sgibbs return; 86839213Sgibbs} 86939213Sgibbs 87039213Sgibbsstatic void 87139213Sgibbscdstart(struct cam_periph *periph, union ccb *start_ccb) 87239213Sgibbs{ 87339213Sgibbs struct cd_softc *softc; 87459249Sphk struct bio *bp; 87539213Sgibbs struct ccb_scsiio *csio; 87639213Sgibbs 87739213Sgibbs softc = (struct cd_softc *)periph->softc; 87839213Sgibbs 87939213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdstart\n")); 88039213Sgibbs 88139213Sgibbs switch (softc->state) { 88239213Sgibbs case CD_STATE_NORMAL: 88339213Sgibbs { 88459249Sphk bp = bioq_first(&softc->bio_queue); 885256843Smav if (bp == NULL) { 886238886Smav if (softc->tur) { 887238886Smav softc->tur = 0; 888238886Smav csio = &start_ccb->csio; 889238886Smav scsi_test_unit_ready(csio, 890238886Smav /*retries*/ cd_retry_count, 891238886Smav cddone, 892238886Smav MSG_SIMPLE_Q_TAG, 893238886Smav SSD_FULL_SIZE, 894238886Smav cd_timeout); 895238886Smav start_ccb->ccb_h.ccb_bp = NULL; 896238886Smav start_ccb->ccb_h.ccb_state = CD_CCB_TUR; 897238886Smav xpt_action(start_ccb); 898238886Smav } else 899238886Smav xpt_release_ccb(start_ccb); 90039213Sgibbs } else { 901238886Smav if (softc->tur) { 902238886Smav softc->tur = 0; 903238886Smav cam_periph_release_locked(periph); 904238886Smav } 90559249Sphk bioq_remove(&softc->bio_queue, bp); 90639213Sgibbs 90739213Sgibbs scsi_read_write(&start_ccb->csio, 908203108Smav /*retries*/ cd_retry_count, 90939213Sgibbs /* cbfcnp */ cddone, 91091062Sphk MSG_SIMPLE_Q_TAG, 911248519Skib /* read */bp->bio_cmd == BIO_READ ? 912248519Skib SCSI_RW_READ : SCSI_RW_WRITE, 91339213Sgibbs /* byte2 */ 0, 91439213Sgibbs /* minimum_cmd_size */ 10, 915121209Sphk /* lba */ bp->bio_offset / 916121209Sphk softc->params.blksize, 91759249Sphk bp->bio_bcount / softc->params.blksize, 91859249Sphk /* data_ptr */ bp->bio_data, 91959249Sphk /* dxfer_len */ bp->bio_bcount, 920237689Simp /* sense_len */ cd_retry_count ? 921237689Simp SSD_FULL_SIZE : SF_NO_PRINT, 922237689Simp /* timeout */ cd_timeout); 923228808Smav /* Use READ CD command for audio tracks. */ 924228808Smav if (softc->params.blksize == 2352) { 925228808Smav start_ccb->csio.cdb_io.cdb_bytes[0] = READ_CD; 926228808Smav start_ccb->csio.cdb_io.cdb_bytes[9] = 0xf8; 927228847Smav start_ccb->csio.cdb_io.cdb_bytes[10] = 0; 928228847Smav start_ccb->csio.cdb_io.cdb_bytes[11] = 0; 929228847Smav start_ccb->csio.cdb_len = 12; 930228808Smav } 93139213Sgibbs start_ccb->ccb_h.ccb_state = CD_CCB_BUFFER_IO; 93239213Sgibbs 93339213Sgibbs LIST_INSERT_HEAD(&softc->pending_ccbs, 93439213Sgibbs &start_ccb->ccb_h, periph_links.le); 935112262Sphk softc->outstanding_cmds++; 93639213Sgibbs 93739213Sgibbs /* We expect a unit attention from this device */ 93839213Sgibbs if ((softc->flags & CD_FLAG_RETRY_UA) != 0) { 93939213Sgibbs start_ccb->ccb_h.ccb_state |= CD_CCB_RETRY_UA; 94039213Sgibbs softc->flags &= ~CD_FLAG_RETRY_UA; 94139213Sgibbs } 94239213Sgibbs 94339213Sgibbs start_ccb->ccb_h.ccb_bp = bp; 94459249Sphk bp = bioq_first(&softc->bio_queue); 94539213Sgibbs 94639213Sgibbs xpt_action(start_ccb); 94739213Sgibbs } 948256843Smav if (bp != NULL || softc->tur) { 94939213Sgibbs /* Have more work to do, so ensure we stay scheduled */ 950256843Smav xpt_schedule(periph, CAM_PRIORITY_NORMAL); 95139213Sgibbs } 95239213Sgibbs break; 95339213Sgibbs } 95439213Sgibbs case CD_STATE_PROBE: 955352715Savg case CD_STATE_MEDIA_SIZE: 95639213Sgibbs { 957352715Savg struct scsi_read_capacity_data *rcap; 95839213Sgibbs 95939213Sgibbs rcap = (struct scsi_read_capacity_data *)malloc(sizeof(*rcap), 960203931Smav M_SCSICD, M_NOWAIT | M_ZERO); 96139213Sgibbs if (rcap == NULL) { 962164906Smjacob xpt_print(periph->path, 963352715Savg "%s: Couldn't malloc read_capacity data\n", 964352715Savg __func__); 965352715Savg xpt_release_ccb(start_ccb); 966352715Savg /* 967352715Savg * We can't probe because we can't allocate memory, 968352715Savg * so invalidate the peripheral. The system probably 969352715Savg * has larger problems at this stage. If we've 970352715Savg * already probed (and are re-probing capacity), we 971352715Savg * don't need to invalidate. 972352715Savg * 973352715Savg * XXX KDM need to reset probe state and kick out 974352715Savg * pending I/O. 975352715Savg */ 976352715Savg if (softc->state == CD_STATE_PROBE) 977352715Savg cam_periph_invalidate(periph); 97839213Sgibbs break; 97939213Sgibbs } 980352715Savg 981352715Savg /* 982352715Savg * Set the default capacity and sector size to something that 983352715Savg * GEOM can handle. This will get reset when a read capacity 984352715Savg * completes successfully. 985352715Savg */ 986352715Savg softc->disk->d_sectorsize = 2048; 987352715Savg softc->disk->d_mediasize = 0; 988352715Savg 98939213Sgibbs csio = &start_ccb->csio; 99039213Sgibbs scsi_read_capacity(csio, 991203108Smav /*retries*/ cd_retry_count, 99239213Sgibbs cddone, 99339213Sgibbs MSG_SIMPLE_Q_TAG, 99439213Sgibbs rcap, 99539213Sgibbs SSD_FULL_SIZE, 99639213Sgibbs /*timeout*/20000); 99739213Sgibbs start_ccb->ccb_h.ccb_bp = NULL; 998352715Savg if (softc->state == CD_STATE_PROBE) 999352715Savg start_ccb->ccb_h.ccb_state = CD_CCB_PROBE; 1000352715Savg else 1001352715Savg start_ccb->ccb_h.ccb_state = CD_CCB_MEDIA_SIZE; 100239213Sgibbs xpt_action(start_ccb); 100339213Sgibbs break; 100439213Sgibbs } 1005352715Savg case CD_STATE_MEDIA_ALLOW: 1006352715Savg case CD_STATE_MEDIA_PREVENT: 1007352715Savg { 1008352715Savg /* 1009352715Savg * If the CD is already locked, we don't need to do this. 1010352715Savg * Move on to the capacity check. 1011352715Savg */ 1012355863Sken if (softc->state == CD_STATE_MEDIA_PREVENT 1013355863Sken && (softc->flags & CD_FLAG_DISC_LOCKED) != 0) { 1014352715Savg softc->state = CD_STATE_MEDIA_SIZE; 1015352715Savg xpt_release_ccb(start_ccb); 1016352715Savg xpt_schedule(periph, CAM_PRIORITY_NORMAL); 1017352715Savg break; 1018352715Savg } 1019352715Savg 1020352717Savg scsi_prevent(&start_ccb->csio, 1021352715Savg /*retries*/ cd_retry_count, 1022352715Savg /*cbfcnp*/ cddone, 1023352715Savg /*tag_action*/ MSG_SIMPLE_Q_TAG, 1024352715Savg /*action*/ (softc->state == CD_STATE_MEDIA_ALLOW) ? 1025352715Savg PR_ALLOW : PR_PREVENT, 1026352715Savg /*sense_len*/ SSD_FULL_SIZE, 1027352715Savg /*timeout*/ 60000); 1028352715Savg 1029352715Savg start_ccb->ccb_h.ccb_bp = NULL; 1030352715Savg if (softc->state == CD_STATE_MEDIA_ALLOW) 1031352715Savg start_ccb->ccb_h.ccb_state = CD_CCB_MEDIA_ALLOW; 1032352715Savg else 1033352715Savg start_ccb->ccb_h.ccb_state = CD_CCB_MEDIA_PREVENT; 1034352715Savg xpt_action(start_ccb); 1035352715Savg break; 103639213Sgibbs } 1037352715Savg case CD_STATE_MEDIA_TOC_HDR: { 1038352715Savg struct ioc_toc_header *toch; 1039352717Savg 1040352715Savg bzero(&softc->toc, sizeof(softc->toc)); 1041352715Savg 1042352715Savg toch = &softc->toc.header; 1043352715Savg 1044352715Savg scsi_read_toc(&start_ccb->csio, 1045352715Savg /*retries*/ cd_retry_count, 1046352715Savg /*cbfcnp*/ cddone, 1047352715Savg /*tag_action*/ MSG_SIMPLE_Q_TAG, 1048352715Savg /*byte1_flags*/ 0, 1049352715Savg /*format*/ SRTOC_FORMAT_TOC, 1050352715Savg /*track*/ 0, 1051352717Savg /*data_ptr*/ (uint8_t *)toch, 1052352715Savg /*dxfer_len*/ sizeof(*toch), 1053352715Savg /*sense_len*/ SSD_FULL_SIZE, 1054352715Savg /*timeout*/ 50000); 1055352715Savg start_ccb->ccb_h.ccb_bp = NULL; 1056352715Savg start_ccb->ccb_h.ccb_state = CD_CCB_MEDIA_TOC_HDR; 1057352715Savg xpt_action(start_ccb); 1058352715Savg break; 1059352715Savg } 1060352715Savg case CD_STATE_MEDIA_TOC_FULL: { 1061352715Savg 1062352715Savg bzero(&softc->toc, sizeof(softc->toc)); 1063352715Savg 1064352715Savg scsi_read_toc(&start_ccb->csio, 1065352715Savg /*retries*/ cd_retry_count, 1066352715Savg /*cbfcnp*/ cddone, 1067352715Savg /*tag_action*/ MSG_SIMPLE_Q_TAG, 1068352715Savg /*byte1_flags*/ 0, 1069352715Savg /*format*/ SRTOC_FORMAT_TOC, 1070352715Savg /*track*/ 0, 1071352715Savg /*data_ptr*/ (uint8_t *)&softc->toc, 1072352715Savg /*dxfer_len*/ softc->toc_read_len ? 1073352715Savg softc->toc_read_len : 1074352715Savg sizeof(softc->toc), 1075352715Savg /*sense_len*/ SSD_FULL_SIZE, 1076352715Savg /*timeout*/ 50000); 1077352715Savg start_ccb->ccb_h.ccb_bp = NULL; 1078352715Savg start_ccb->ccb_h.ccb_state = CD_CCB_MEDIA_TOC_FULL; 1079352715Savg xpt_action(start_ccb); 1080352715Savg break; 1081352715Savg } 1082352715Savg case CD_STATE_MEDIA_TOC_LEAD: { 1083352715Savg struct cd_toc_single *leadout; 1084352715Savg 1085352715Savg leadout = &softc->leadout; 1086352715Savg bzero(leadout, sizeof(*leadout)); 1087352715Savg 1088352715Savg scsi_read_toc(&start_ccb->csio, 1089352715Savg /*retries*/ cd_retry_count, 1090352715Savg /*cbfcnp*/ cddone, 1091352715Savg /*tag_action*/ MSG_SIMPLE_Q_TAG, 1092352715Savg /*byte1_flags*/ CD_MSF, 1093352715Savg /*format*/ SRTOC_FORMAT_TOC, 1094352715Savg /*track*/ LEADOUT, 1095352717Savg /*data_ptr*/ (uint8_t *)leadout, 1096352715Savg /*dxfer_len*/ sizeof(*leadout), 1097352715Savg /*sense_len*/ SSD_FULL_SIZE, 1098352715Savg /*timeout*/ 50000); 1099352715Savg start_ccb->ccb_h.ccb_bp = NULL; 1100352715Savg start_ccb->ccb_h.ccb_state = CD_CCB_MEDIA_TOC_LEAD; 1101352715Savg xpt_action(start_ccb); 1102352715Savg break; 1103352715Savg } 1104352715Savg } 110539213Sgibbs} 110639213Sgibbs 110739213Sgibbsstatic void 110839213Sgibbscddone(struct cam_periph *periph, union ccb *done_ccb) 1109352717Savg{ 111039213Sgibbs struct cd_softc *softc; 111139213Sgibbs struct ccb_scsiio *csio; 111239213Sgibbs 111339213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cddone\n")); 111439213Sgibbs 111539213Sgibbs softc = (struct cd_softc *)periph->softc; 111639213Sgibbs csio = &done_ccb->csio; 111739213Sgibbs 111839213Sgibbs switch (csio->ccb_h.ccb_state & CD_CCB_TYPE_MASK) { 111939213Sgibbs case CD_CCB_BUFFER_IO: 112039213Sgibbs { 112159249Sphk struct bio *bp; 112239213Sgibbs int error; 112339213Sgibbs 112459249Sphk bp = (struct bio *)done_ccb->ccb_h.ccb_bp; 112539213Sgibbs error = 0; 112639213Sgibbs 112739213Sgibbs if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 112839213Sgibbs int sf; 112939213Sgibbs 113039213Sgibbs if ((done_ccb->ccb_h.ccb_state & CD_CCB_RETRY_UA) != 0) 113139213Sgibbs sf = SF_RETRY_UA; 113239213Sgibbs else 113339213Sgibbs sf = 0; 113446747Sken 113574840Sken error = cderror(done_ccb, CAM_RETRY_SELTO, sf); 113674840Sken if (error == ERESTART) { 113739213Sgibbs /* 113839213Sgibbs * A retry was scheuled, so 113939213Sgibbs * just return. 114039213Sgibbs */ 114139213Sgibbs return; 114239213Sgibbs } 114339213Sgibbs } 114439213Sgibbs 114539213Sgibbs if (error != 0) { 1146164906Smjacob xpt_print(periph->path, 1147164906Smjacob "cddone: got error %#x back\n", error); 1148112946Sphk bioq_flush(&softc->bio_queue, NULL, EIO); 114959249Sphk bp->bio_resid = bp->bio_bcount; 115059249Sphk bp->bio_error = error; 115159249Sphk bp->bio_flags |= BIO_ERROR; 1152199279Smav if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 1153199279Smav cam_release_devq(done_ccb->ccb_h.path, 115439213Sgibbs /*relsim_flags*/0, 115539213Sgibbs /*reduction*/0, 115639213Sgibbs /*timeout*/0, 115739213Sgibbs /*getcount_only*/0); 115839213Sgibbs 115939213Sgibbs } else { 116059249Sphk bp->bio_resid = csio->resid; 116159249Sphk bp->bio_error = 0; 116259249Sphk if (bp->bio_resid != 0) { 1163104456Sphk /* 1164352717Savg * Short transfer ??? 1165104456Sphk * XXX: not sure this is correct for partial 1166104456Sphk * transfers at EOM 1167104456Sphk */ 116859249Sphk bp->bio_flags |= BIO_ERROR; 116939213Sgibbs } 117039213Sgibbs } 117139213Sgibbs 117239213Sgibbs LIST_REMOVE(&done_ccb->ccb_h, periph_links.le); 1173112262Sphk softc->outstanding_cmds--; 117439213Sgibbs 1175157806Smaxim biofinish(bp, NULL, 0); 117639213Sgibbs break; 117739213Sgibbs } 117839213Sgibbs case CD_CCB_PROBE: 117939213Sgibbs { 118039213Sgibbs struct scsi_read_capacity_data *rdcap; 118139213Sgibbs char announce_buf[120]; /* 118239213Sgibbs * Currently (9/30/97) the 118339213Sgibbs * longest possible announce 118439213Sgibbs * buffer is 108 bytes, for the 118539213Sgibbs * first error case below. 118639213Sgibbs * That is 39 bytes for the 118739213Sgibbs * basic string, 16 bytes for the 118839213Sgibbs * biggest sense key (hardware 118939213Sgibbs * error), 52 bytes for the 119039213Sgibbs * text of the largest sense 119139213Sgibbs * qualifier valid for a CDROM, 119239213Sgibbs * (0x72, 0x03 or 0x04, 119339213Sgibbs * 0x03), and one byte for the 119439213Sgibbs * null terminating character. 119539213Sgibbs * To allow for longer strings, 119639213Sgibbs * the announce buffer is 120 119739213Sgibbs * bytes. 119839213Sgibbs */ 119939213Sgibbs struct cd_params *cdp; 1200241410Smav int error; 120139213Sgibbs 120239213Sgibbs cdp = &softc->params; 120339213Sgibbs 120439213Sgibbs rdcap = (struct scsi_read_capacity_data *)csio->data_ptr; 1205352717Savg 120639213Sgibbs cdp->disksize = scsi_4btoul (rdcap->addr) + 1; 120739213Sgibbs cdp->blksize = scsi_4btoul (rdcap->length); 120839213Sgibbs 1209241410Smav /* 1210241410Smav * Retry any UNIT ATTENTION type errors. They 1211241410Smav * are expected at boot. 1212241410Smav */ 1213241410Smav if ((csio->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP || 1214241410Smav (error = cderror(done_ccb, CAM_RETRY_SELTO, 1215241410Smav SF_RETRY_UA | SF_NO_PRINT)) == 0) { 121641514Sarchie snprintf(announce_buf, sizeof(announce_buf), 1217289138Smav "%juMB (%ju %u byte sectors)", 1218289138Smav ((uintmax_t)cdp->disksize * cdp->blksize) / 1219289138Smav (1024 * 1024), 1220289138Smav (uintmax_t)cdp->disksize, cdp->blksize); 122139213Sgibbs } else { 122239213Sgibbs if (error == ERESTART) { 122339213Sgibbs /* 122439213Sgibbs * A retry was scheuled, so 122539213Sgibbs * just return. 122639213Sgibbs */ 122739213Sgibbs return; 1228241410Smav } else { 122939213Sgibbs int asc, ascq; 123039213Sgibbs int sense_key, error_code; 123139213Sgibbs int have_sense; 123239213Sgibbs cam_status status; 123339213Sgibbs struct ccb_getdev cgd; 123439213Sgibbs 123539213Sgibbs /* Don't wedge this device's queue */ 1236199279Smav if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 1237199279Smav cam_release_devq(done_ccb->ccb_h.path, 123839213Sgibbs /*relsim_flags*/0, 123939213Sgibbs /*reduction*/0, 124039213Sgibbs /*timeout*/0, 124139213Sgibbs /*getcount_only*/0); 124239213Sgibbs 124339213Sgibbs status = done_ccb->ccb_h.status; 124439213Sgibbs 1245352717Savg xpt_setup_ccb(&cgd.ccb_h, 124639213Sgibbs done_ccb->ccb_h.path, 1247198382Smav CAM_PRIORITY_NORMAL); 124839213Sgibbs cgd.ccb_h.func_code = XPT_GDEV_TYPE; 124939213Sgibbs xpt_action((union ccb *)&cgd); 125039213Sgibbs 1251237478Smav if (scsi_extract_sense_ccb(done_ccb, 1252237478Smav &error_code, &sense_key, &asc, &ascq)) 1253237478Smav have_sense = TRUE; 1254237478Smav else 125539213Sgibbs have_sense = FALSE; 125639213Sgibbs 125739213Sgibbs /* 125846581Sken * Attach to anything that claims to be a 125946581Sken * CDROM or WORM device, as long as it 126046581Sken * doesn't return a "Logical unit not 126146581Sken * supported" (0x25) error. 126239213Sgibbs */ 126346581Sken if ((have_sense) && (asc != 0x25) 1264332461Smav && (error_code == SSD_CURRENT_ERROR 1265332461Smav || error_code == SSD_DESC_CURRENT_ERROR)) { 126674840Sken const char *sense_key_desc; 126774840Sken const char *asc_desc; 126874840Sken 126974840Sken scsi_sense_desc(sense_key, asc, ascq, 127074840Sken &cgd.inq_data, 127174840Sken &sense_key_desc, 127274840Sken &asc_desc); 127341514Sarchie snprintf(announce_buf, 127441514Sarchie sizeof(announce_buf), 127539213Sgibbs "Attempt to query device " 127639213Sgibbs "size failed: %s, %s", 127774840Sken sense_key_desc, 127874840Sken asc_desc); 1279352717Savg } else if ((have_sense == 0) 1280352717Savg && ((status & CAM_STATUS_MASK) == 1281352717Savg CAM_SCSI_STATUS_ERROR) 1282352717Savg && (csio->scsi_status == 1283352717Savg SCSI_STATUS_BUSY)) { 1284352717Savg snprintf(announce_buf, 128582850Sken sizeof(announce_buf), 1286352717Savg "Attempt to query device " 1287352717Savg "size failed: SCSI Status: %s", 128882850Sken scsi_status_string(csio)); 128974840Sken } else if (SID_TYPE(&cgd.inq_data) == T_CDROM) { 129039213Sgibbs /* 129139213Sgibbs * We only print out an error for 129239213Sgibbs * CDROM type devices. For WORM 129339213Sgibbs * devices, we don't print out an 129439213Sgibbs * error since a few WORM devices 129539213Sgibbs * don't support CDROM commands. 129639213Sgibbs * If we have sense information, go 129739213Sgibbs * ahead and print it out. 1298352717Savg * Otherwise, just say that we 129939213Sgibbs * couldn't attach. 130039213Sgibbs */ 130139213Sgibbs 130239213Sgibbs /* 130339213Sgibbs * Just print out the error, not 130439213Sgibbs * the full probe message, when we 130539213Sgibbs * don't attach. 130639213Sgibbs */ 130740020Sken if (have_sense) 130840020Sken scsi_sense_print( 130940020Sken &done_ccb->csio); 131040020Sken else { 1311164906Smjacob xpt_print(periph->path, 1312164906Smjacob "got CAM status %#x\n", 1313164906Smjacob done_ccb->ccb_h.status); 131440020Sken } 1315164906Smjacob xpt_print(periph->path, "fatal error, " 1316164906Smjacob "failed to attach to device\n"); 131739213Sgibbs /* 131840603Sken * Invalidate this peripheral. 131939213Sgibbs */ 132039213Sgibbs cam_periph_invalidate(periph); 132140020Sken 132240020Sken announce_buf[0] = '\0'; 132339213Sgibbs } else { 132440603Sken 132539213Sgibbs /* 132640603Sken * Invalidate this peripheral. 132739213Sgibbs */ 132839213Sgibbs cam_periph_invalidate(periph); 132940020Sken announce_buf[0] = '\0'; 133039213Sgibbs } 133139213Sgibbs } 133239213Sgibbs } 1333169562Sscottl free(rdcap, M_SCSICD); 133442378Smjacob if (announce_buf[0] != '\0') { 133539213Sgibbs xpt_announce_periph(periph, announce_buf); 1336250792Ssmh xpt_announce_quirks(periph, softc->quirks, 1337250792Ssmh CD_Q_BIT_STRING); 1338119708Sken /* 1339119708Sken * Create our sysctl variables, now that we know 1340119708Sken * we have successfully attached. 1341119708Sken */ 1342119708Sken taskqueue_enqueue(taskqueue_thread,&softc->sysctl_task); 134342378Smjacob } 1344352717Savg softc->state = CD_STATE_NORMAL; 134542378Smjacob /* 134642378Smjacob * Since our peripheral may be invalidated by an error 134742378Smjacob * above or an external event, we must release our CCB 134842378Smjacob * before releasing the probe lock on the peripheral. 134942378Smjacob * The peripheral will only go away once the last lock 135042378Smjacob * is removed, and we need it around for the CCB release 135142378Smjacob * operation. 135242378Smjacob */ 135342378Smjacob xpt_release_ccb(done_ccb); 1354168752Sscottl cam_periph_unhold(periph); 135542378Smjacob return; 135639213Sgibbs } 1357238886Smav case CD_CCB_TUR: 1358238886Smav { 1359238886Smav if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 1360238886Smav 1361238886Smav if (cderror(done_ccb, CAM_RETRY_SELTO, 1362238886Smav SF_RETRY_UA | SF_NO_RECOVERY | SF_NO_PRINT) == 1363238886Smav ERESTART) 1364238886Smav return; 1365238886Smav if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 1366238886Smav cam_release_devq(done_ccb->ccb_h.path, 1367238886Smav /*relsim_flags*/0, 1368238886Smav /*reduction*/0, 1369238886Smav /*timeout*/0, 1370238886Smav /*getcount_only*/0); 1371238886Smav } 1372238886Smav xpt_release_ccb(done_ccb); 1373238886Smav cam_periph_release_locked(periph); 1374238886Smav return; 1375238886Smav } 1376352717Savg case CD_CCB_MEDIA_ALLOW: 1377352715Savg case CD_CCB_MEDIA_PREVENT: 1378352715Savg { 1379352715Savg int error; 1380352715Savg int is_prevent; 1381352715Savg 1382352715Savg error = 0; 1383352715Savg 1384352715Savg if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 1385352715Savg error = cderror(done_ccb, CAM_RETRY_SELTO, 1386352715Savg SF_RETRY_UA | SF_NO_PRINT); 1387352715Savg } 1388352715Savg if (error == ERESTART) 1389352715Savg return; 1390352715Savg if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 1391352715Savg cam_release_devq(done_ccb->ccb_h.path, 1392352715Savg /*relsim_flags*/0, 1393352715Savg /*reduction*/0, 1394352715Savg /*timeout*/0, 1395352715Savg /*getcount_only*/0); 1396352715Savg 1397352715Savg /* 1398352715Savg * Note that just like the original cdcheckmedia(), we do 1399352715Savg * a prevent without failing the whole operation if the 1400352715Savg * prevent fails. We try, but keep going if it doesn't 1401352715Savg * work. 1402352715Savg */ 1403352715Savg 1404352715Savg if ((done_ccb->ccb_h.ccb_state & CD_CCB_TYPE_MASK) == 1405352715Savg CD_CCB_MEDIA_PREVENT) 1406352715Savg is_prevent = 1; 1407352715Savg else 1408352715Savg is_prevent = 0; 1409352715Savg 1410352715Savg xpt_release_ccb(done_ccb); 1411352715Savg 1412352715Savg if (is_prevent != 0) { 1413352715Savg if (error == 0) 1414352715Savg softc->flags |= CD_FLAG_DISC_LOCKED; 1415352715Savg else 1416352715Savg softc->flags &= ~CD_FLAG_DISC_LOCKED; 1417352715Savg softc->state = CD_STATE_MEDIA_SIZE; 1418352715Savg xpt_schedule(periph, CAM_PRIORITY_NORMAL); 1419352715Savg } else { 1420352715Savg if (error == 0) 1421352715Savg softc->flags &= ~CD_FLAG_DISC_LOCKED; 1422352715Savg softc->state = CD_STATE_NORMAL; 1423352715Savg if (bioq_first(&softc->bio_queue) != NULL) 1424352715Savg xpt_schedule(periph, CAM_PRIORITY_NORMAL); 1425352715Savg } 1426352715Savg return; 1427352715Savg } 1428352715Savg case CD_CCB_MEDIA_SIZE: 1429352715Savg { 1430352715Savg struct scsi_read_capacity_data *rdcap; 1431352715Savg int error; 1432352715Savg 1433352715Savg error = 0; 1434352715Savg if ((csio->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 1435352715Savg error = cderror(done_ccb, CAM_RETRY_SELTO, 1436352715Savg SF_RETRY_UA | SF_NO_PRINT); 1437352715Savg } 1438352715Savg if (error == ERESTART) 1439352715Savg return; 1440352715Savg if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 1441352715Savg cam_release_devq(done_ccb->ccb_h.path, 1442352715Savg /*relsim_flags*/0, 1443352715Savg /*reduction*/0, 1444352715Savg /*timeout*/0, 1445352715Savg /*getcount_only*/0); 1446352715Savg rdcap = (struct scsi_read_capacity_data *)csio->data_ptr; 1447352715Savg 1448352715Savg if (error == 0) { 1449352715Savg softc->params.disksize =scsi_4btoul(rdcap->addr) + 1; 1450352715Savg softc->params.blksize = scsi_4btoul(rdcap->length); 1451352715Savg 1452352715Savg /* Make sure we got at least some block size. */ 1453352715Savg if (softc->params.blksize == 0) 1454352715Savg error = EIO; 1455352715Savg /* 1456352715Savg * SCSI-3 mandates that the reported blocksize shall be 1457352715Savg * 2048. Older drives sometimes report funny values, 1458352715Savg * trim it down to 2048, or other parts of the kernel 1459352715Savg * will get confused. 1460352715Savg * 1461352715Savg * XXX we leave drives alone that might report 512 1462352715Savg * bytes, as well as drives reporting more weird 1463352715Savg * sizes like perhaps 4K. 1464352715Savg */ 1465352715Savg if (softc->params.blksize > 2048 1466352715Savg && softc->params.blksize <= 2352) 1467352715Savg softc->params.blksize = 2048; 1468352715Savg } 1469352715Savg free(rdcap, M_SCSICD); 1470352715Savg 1471352715Savg if (error == 0) { 1472352715Savg softc->disk->d_sectorsize = softc->params.blksize; 1473352715Savg softc->disk->d_mediasize = 1474352715Savg (off_t)softc->params.blksize * 1475352715Savg softc->params.disksize; 1476352715Savg softc->flags |= CD_FLAG_SAW_MEDIA | CD_FLAG_VALID_MEDIA; 1477352715Savg softc->state = CD_STATE_MEDIA_TOC_HDR; 1478352715Savg } else { 1479352715Savg softc->flags &= ~(CD_FLAG_VALID_MEDIA | 1480352715Savg CD_FLAG_VALID_TOC); 1481352715Savg bioq_flush(&softc->bio_queue, NULL, EINVAL); 1482352715Savg softc->state = CD_STATE_MEDIA_ALLOW; 1483352715Savg cdmediaprobedone(periph); 1484352715Savg } 1485352715Savg xpt_release_ccb(done_ccb); 1486352715Savg xpt_schedule(periph, CAM_PRIORITY_NORMAL); 1487352715Savg return; 1488352715Savg } 1489352715Savg case CD_CCB_MEDIA_TOC_HDR: 1490352715Savg case CD_CCB_MEDIA_TOC_FULL: 1491352715Savg case CD_CCB_MEDIA_TOC_LEAD: 1492352715Savg { 1493352715Savg int error; 1494352715Savg struct ioc_toc_header *toch; 1495352715Savg int num_entries; 1496352715Savg int cdindex; 1497352715Savg 1498352715Savg error = 0; 1499352715Savg 1500352715Savg if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 1501352715Savg error = cderror(done_ccb, CAM_RETRY_SELTO, 1502352715Savg SF_RETRY_UA | SF_NO_PRINT); 1503352715Savg } 1504352715Savg if (error == ERESTART) 1505352715Savg return; 1506352715Savg 1507352715Savg if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 1508352715Savg cam_release_devq(done_ccb->ccb_h.path, 1509352715Savg /*relsim_flags*/0, 1510352715Savg /*reduction*/0, 1511352715Savg /*timeout*/0, 1512352715Savg /*getcount_only*/0); 1513352715Savg 1514352715Savg /* 1515352715Savg * We will get errors here for media that doesn't have a table 1516352717Savg * of contents. According to the MMC-3 spec: "When a Read 1517352715Savg * TOC/PMA/ATIP command is presented for a DDCD/CD-R/RW media, 1518352715Savg * where the first TOC has not been recorded (no complete 1519352715Savg * session) and the Format codes 0000b, 0001b, or 0010b are 1520352717Savg * specified, this command shall be rejected with an INVALID 1521352717Savg * FIELD IN CDB. Devices that are not capable of reading an 1522352715Savg * incomplete session on DDC/CD-R/RW media shall report 1523352715Savg * CANNOT READ MEDIUM - INCOMPATIBLE FORMAT." 1524352715Savg * 1525352715Savg * So this isn't fatal if we can't read the table of contents, 1526352715Savg * it just means that the user won't be able to issue the 1527352715Savg * play tracks ioctl, and likely lots of other stuff won't 1528352715Savg * work either. They need to burn the CD before we can do 1529352715Savg * a whole lot with it. So we don't print anything here if 1530352715Savg * we get an error back. 1531352715Savg * 1532352715Savg * We also bail out if the drive doesn't at least give us 1533352715Savg * the full TOC header. 1534352715Savg */ 1535352715Savg if ((error != 0) 1536352715Savg || ((csio->dxfer_len - csio->resid) < 1537352715Savg sizeof(struct ioc_toc_header))) { 1538352715Savg softc->flags &= ~CD_FLAG_VALID_TOC; 1539352715Savg bzero(&softc->toc, sizeof(softc->toc)); 1540352715Savg /* 1541352715Savg * Failing the TOC read is not an error. 1542352715Savg */ 1543352715Savg softc->state = CD_STATE_NORMAL; 1544352715Savg xpt_release_ccb(done_ccb); 1545352715Savg 1546352715Savg cdmediaprobedone(periph); 1547352715Savg 1548352715Savg /* 1549352715Savg * Go ahead and schedule I/O execution if there is 1550352715Savg * anything in the queue. It'll probably get 1551352715Savg * kicked out with an error. 1552352715Savg */ 1553352715Savg if (bioq_first(&softc->bio_queue) != NULL) 1554352715Savg xpt_schedule(periph, CAM_PRIORITY_NORMAL); 1555352715Savg return; 1556352715Savg } 1557352715Savg 1558352715Savg /* 1559352715Savg * Note that this is NOT the storage location used for the 1560352715Savg * leadout! 1561352715Savg */ 1562352715Savg toch = &softc->toc.header; 1563352715Savg 1564352715Savg if (softc->quirks & CD_Q_BCD_TRACKS) { 1565352715Savg toch->starting_track = bcd2bin(toch->starting_track); 1566352715Savg toch->ending_track = bcd2bin(toch->ending_track); 1567352715Savg } 1568352715Savg 1569352715Savg /* Number of TOC entries, plus leadout */ 1570352715Savg num_entries = (toch->ending_track - toch->starting_track) + 2; 1571352715Savg cdindex = toch->starting_track + num_entries -1; 1572352715Savg 1573352715Savg if ((done_ccb->ccb_h.ccb_state & CD_CCB_TYPE_MASK) == 1574352715Savg CD_CCB_MEDIA_TOC_HDR) { 1575352715Savg if (num_entries <= 0) { 1576352715Savg softc->flags &= ~CD_FLAG_VALID_TOC; 1577352715Savg bzero(&softc->toc, sizeof(softc->toc)); 1578352715Savg /* 1579352715Savg * Failing the TOC read is not an error. 1580352715Savg */ 1581352715Savg softc->state = CD_STATE_NORMAL; 1582352715Savg xpt_release_ccb(done_ccb); 1583352715Savg 1584352715Savg cdmediaprobedone(periph); 1585352715Savg 1586352715Savg /* 1587352715Savg * Go ahead and schedule I/O execution if 1588352715Savg * there is anything in the queue. It'll 1589352715Savg * probably get kicked out with an error. 1590352715Savg */ 1591352715Savg if (bioq_first(&softc->bio_queue) != NULL) 1592352715Savg xpt_schedule(periph, 1593352715Savg CAM_PRIORITY_NORMAL); 1594352715Savg } else { 1595352715Savg softc->toc_read_len = num_entries * 1596352715Savg sizeof(struct cd_toc_entry); 1597352715Savg softc->toc_read_len += sizeof(*toch); 1598352715Savg 1599352715Savg softc->state = CD_STATE_MEDIA_TOC_FULL; 1600352715Savg xpt_release_ccb(done_ccb); 1601352715Savg xpt_schedule(periph, CAM_PRIORITY_NORMAL); 1602352715Savg } 1603352715Savg 1604352715Savg return; 1605352715Savg } else if ((done_ccb->ccb_h.ccb_state & CD_CCB_TYPE_MASK) == 1606352715Savg CD_CCB_MEDIA_TOC_LEAD) { 1607352715Savg struct cd_toc_single *leadout; 1608352715Savg 1609352715Savg leadout = (struct cd_toc_single *)csio->data_ptr; 1610352715Savg softc->toc.entries[cdindex - toch->starting_track] = 1611352715Savg leadout->entry; 1612352715Savg } else if (((done_ccb->ccb_h.ccb_state & CD_CCB_TYPE_MASK) == 1613352715Savg CD_CCB_MEDIA_TOC_FULL) 1614352715Savg && (cdindex == toch->ending_track + 1)) { 1615352715Savg /* 1616352715Savg * XXX KDM is this necessary? Probably only if the 1617352715Savg * drive doesn't return leadout information with the 1618352715Savg * table of contents. 1619352715Savg */ 1620352715Savg softc->state = CD_STATE_MEDIA_TOC_LEAD; 1621352715Savg xpt_release_ccb(done_ccb); 1622352715Savg xpt_schedule(periph, CAM_PRIORITY_NORMAL); 1623352715Savg return; 1624352715Savg } 1625352715Savg 1626352715Savg if (softc->quirks & CD_Q_BCD_TRACKS) { 1627352715Savg for (cdindex = 0; cdindex < num_entries - 1; cdindex++){ 1628352715Savg softc->toc.entries[cdindex].track = 1629352715Savg bcd2bin(softc->toc.entries[cdindex].track); 1630352715Savg } 1631352715Savg } 1632352715Savg 1633352715Savg softc->flags |= CD_FLAG_VALID_TOC; 1634352715Savg /* If the first track is audio, correct sector size. */ 1635352715Savg if ((softc->toc.entries[0].control & 4) == 0) { 1636352715Savg softc->disk->d_sectorsize =softc->params.blksize = 2352; 1637352715Savg softc->disk->d_mediasize = 1638352715Savg (off_t)softc->params.blksize * 1639352715Savg softc->params.disksize; 1640352715Savg } 1641352715Savg softc->state = CD_STATE_NORMAL; 1642352715Savg 1643352715Savg /* 1644352715Savg * We unconditionally (re)set the blocksize each time the 1645352715Savg * CD device is opened. This is because the CD can change, 1646352715Savg * and therefore the blocksize might change. 1647352715Savg * XXX problems here if some slice or partition is still 1648352715Savg * open with the old size? 1649352715Savg */ 1650352715Savg if ((softc->disk->d_devstat->flags & DEVSTAT_BS_UNAVAILABLE)!=0) 1651352715Savg softc->disk->d_devstat->flags &= 1652352715Savg ~DEVSTAT_BS_UNAVAILABLE; 1653352715Savg softc->disk->d_devstat->block_size = softc->params.blksize; 1654352715Savg 1655352715Savg xpt_release_ccb(done_ccb); 1656352715Savg 1657352715Savg cdmediaprobedone(periph); 1658352715Savg 1659352715Savg if (bioq_first(&softc->bio_queue) != NULL) 1660352715Savg xpt_schedule(periph, CAM_PRIORITY_NORMAL); 1661352715Savg return; 1662352715Savg } 166342378Smjacob default: 166442378Smjacob break; 166539213Sgibbs } 166639213Sgibbs xpt_release_ccb(done_ccb); 166739213Sgibbs} 166839213Sgibbs 1669111206Skenstatic union cd_pages * 1670111206Skencdgetpage(struct cd_mode_params *mode_params) 1671111206Sken{ 1672111206Sken union cd_pages *page; 1673111206Sken 1674111206Sken if (mode_params->cdb_size == 10) 1675111206Sken page = (union cd_pages *)find_mode_page_10( 1676111206Sken (struct scsi_mode_header_10 *)mode_params->mode_buf); 1677111206Sken else 1678111206Sken page = (union cd_pages *)find_mode_page_6( 1679111206Sken (struct scsi_mode_header_6 *)mode_params->mode_buf); 1680111206Sken 1681111206Sken return (page); 1682111206Sken} 1683111206Sken 168439213Sgibbsstatic int 1685111206Skencdgetpagesize(int page_num) 1686111206Sken{ 1687299180Spfg u_int i; 1688111206Sken 1689298431Spfg for (i = 0; i < nitems(cd_page_size_table); i++) { 1690111206Sken if (cd_page_size_table[i].page == page_num) 1691111206Sken return (cd_page_size_table[i].page_size); 1692111206Sken } 1693111206Sken 1694111206Sken return (-1); 1695111206Sken} 1696111206Sken 1697111206Skenstatic int 1698120599Sphkcdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td) 169939213Sgibbs{ 170039213Sgibbs 170139213Sgibbs struct cam_periph *periph; 170239213Sgibbs struct cd_softc *softc; 1703349629Smarkj int error = 0; 170439213Sgibbs 1705120599Sphk periph = (struct cam_periph *)dp->d_drv1; 1706168752Sscottl cam_periph_lock(periph); 170739213Sgibbs 170839213Sgibbs softc = (struct cd_softc *)periph->softc; 170939213Sgibbs 1710236602Smav CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, 1711236602Smav ("cdioctl(%#lx)\n", cmd)); 171239213Sgibbs 1713168752Sscottl if ((error = cam_periph_hold(periph, PRIBIO | PCATCH)) != 0) { 1714168752Sscottl cam_periph_unlock(periph); 1715168752Sscottl cam_periph_release(periph); 1716168752Sscottl return (error); 1717168752Sscottl } 171839213Sgibbs 1719111206Sken /* 1720111206Sken * If we don't have media loaded, check for it. If still don't 1721111206Sken * have media loaded, we can only do a load or eject. 1722144135Sken * 1723144135Sken * We only care whether media is loaded if this is a cd-specific ioctl 1724144135Sken * (thus the IOCGROUP check below). Note that this will break if 1725144135Sken * anyone adds any ioctls into the switch statement below that don't 1726144135Sken * have their ioctl group set to 'c'. 1727111206Sken */ 1728111206Sken if (((softc->flags & CD_FLAG_VALID_MEDIA) == 0) 1729111206Sken && ((cmd != CDIOCCLOSE) 1730144135Sken && (cmd != CDIOCEJECT)) 1731144135Sken && (IOCGROUP(cmd) == 'c')) { 1732352715Savg error = cdcheckmedia(periph, /*do_wait*/ 1); 1733171529Skan if (error != 0) { 1734171529Skan cam_periph_unhold(periph); 1735171529Skan cam_periph_unlock(periph); 1736171529Skan return (error); 1737171529Skan } 1738111206Sken } 1739168752Sscottl /* 1740168752Sscottl * Drop the lock here so later mallocs can use WAITOK. The periph 1741168752Sscottl * is essentially locked still with the cam_periph_hold call above. 1742168752Sscottl */ 1743168752Sscottl cam_periph_unlock(periph); 174440020Sken 174539213Sgibbs switch (cmd) { 174639213Sgibbs 174739213Sgibbs case CDIOCPLAYTRACKS: 174839213Sgibbs { 174939213Sgibbs struct ioc_play_track *args 175039213Sgibbs = (struct ioc_play_track *) addr; 1751111206Sken struct cd_mode_params params; 1752111206Sken union cd_pages *page; 175339213Sgibbs 1754111206Sken params.alloc_len = sizeof(union cd_mode_data_6_10); 1755169562Sscottl params.mode_buf = malloc(params.alloc_len, M_SCSICD, 1756111206Sken M_WAITOK | M_ZERO); 175739213Sgibbs 1758168752Sscottl cam_periph_lock(periph); 1759352717Savg CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 176039213Sgibbs ("trying to do CDIOCPLAYTRACKS\n")); 176139213Sgibbs 1762111206Sken error = cdgetmode(periph, ¶ms, AUDIO_PAGE); 176339213Sgibbs if (error) { 1764169562Sscottl free(params.mode_buf, M_SCSICD); 1765168752Sscottl cam_periph_unlock(periph); 176639213Sgibbs break; 176739213Sgibbs } 1768111206Sken page = cdgetpage(¶ms); 1769111206Sken 1770111206Sken page->audio.flags &= ~CD_PA_SOTC; 1771111206Sken page->audio.flags |= CD_PA_IMMED; 1772111206Sken error = cdsetmode(periph, ¶ms); 1773169562Sscottl free(params.mode_buf, M_SCSICD); 1774168752Sscottl if (error) { 1775168752Sscottl cam_periph_unlock(periph); 177639213Sgibbs break; 1777168752Sscottl } 1778111206Sken 1779111206Sken /* 1780111206Sken * This was originally implemented with the PLAY 1781111206Sken * AUDIO TRACK INDEX command, but that command was 1782111206Sken * deprecated after SCSI-2. Most (all?) SCSI CDROM 1783111206Sken * drives support it but ATAPI and ATAPI-derivative 1784111206Sken * drives don't seem to support it. So we keep a 1785111206Sken * cache of the table of contents and translate 1786111206Sken * track numbers to MSF format. 1787111206Sken */ 1788111206Sken if (softc->flags & CD_FLAG_VALID_TOC) { 1789111206Sken union msf_lba *sentry, *eentry; 1790111206Sken int st, et; 1791111206Sken 1792111206Sken if (args->end_track < 1793111206Sken softc->toc.header.ending_track + 1) 1794111206Sken args->end_track++; 1795111206Sken if (args->end_track > 1796111206Sken softc->toc.header.ending_track + 1) 1797111206Sken args->end_track = 1798111206Sken softc->toc.header.ending_track + 1; 1799111206Sken st = args->start_track - 1800111206Sken softc->toc.header.starting_track; 1801111206Sken et = args->end_track - 1802111206Sken softc->toc.header.starting_track; 1803111206Sken if ((st < 0) 1804111206Sken || (et < 0) 1805352717Savg || (st > (softc->toc.header.ending_track - 1806111206Sken softc->toc.header.starting_track))) { 1807111206Sken error = EINVAL; 1808240701Stijl cam_periph_unlock(periph); 1809111206Sken break; 1810111206Sken } 1811111206Sken sentry = &softc->toc.entries[st].addr; 1812111206Sken eentry = &softc->toc.entries[et].addr; 1813111206Sken error = cdplaymsf(periph, 1814111206Sken sentry->msf.minute, 1815111206Sken sentry->msf.second, 1816111206Sken sentry->msf.frame, 1817111206Sken eentry->msf.minute, 1818111206Sken eentry->msf.second, 1819111206Sken eentry->msf.frame); 1820111206Sken } else { 1821111206Sken /* 1822111206Sken * If we don't have a valid TOC, try the 1823111206Sken * play track index command. It is part of 1824111206Sken * the SCSI-2 spec, but was removed in the 1825111206Sken * MMC specs. ATAPI and ATAPI-derived 1826111206Sken * drives don't support it. 1827111206Sken */ 1828111206Sken if (softc->quirks & CD_Q_BCD_TRACKS) { 1829111206Sken args->start_track = 1830111206Sken bin2bcd(args->start_track); 1831111206Sken args->end_track = 1832111206Sken bin2bcd(args->end_track); 1833111206Sken } 1834111206Sken error = cdplaytracks(periph, 1835111206Sken args->start_track, 1836111206Sken args->start_index, 1837111206Sken args->end_track, 1838111206Sken args->end_index); 183939213Sgibbs } 1840168752Sscottl cam_periph_unlock(periph); 184139213Sgibbs } 184239213Sgibbs break; 184339213Sgibbs case CDIOCPLAYMSF: 184439213Sgibbs { 184539213Sgibbs struct ioc_play_msf *args 184639213Sgibbs = (struct ioc_play_msf *) addr; 1847111206Sken struct cd_mode_params params; 1848111206Sken union cd_pages *page; 184939213Sgibbs 1850111206Sken params.alloc_len = sizeof(union cd_mode_data_6_10); 1851169562Sscottl params.mode_buf = malloc(params.alloc_len, M_SCSICD, 1852111206Sken M_WAITOK | M_ZERO); 185339213Sgibbs 1854168752Sscottl cam_periph_lock(periph); 1855352717Savg CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 185639213Sgibbs ("trying to do CDIOCPLAYMSF\n")); 185739213Sgibbs 1858111206Sken error = cdgetmode(periph, ¶ms, AUDIO_PAGE); 185939213Sgibbs if (error) { 1860169562Sscottl free(params.mode_buf, M_SCSICD); 1861168752Sscottl cam_periph_unlock(periph); 186239213Sgibbs break; 186339213Sgibbs } 1864111206Sken page = cdgetpage(¶ms); 1865111206Sken 1866111206Sken page->audio.flags &= ~CD_PA_SOTC; 1867111206Sken page->audio.flags |= CD_PA_IMMED; 1868111206Sken error = cdsetmode(periph, ¶ms); 1869169562Sscottl free(params.mode_buf, M_SCSICD); 1870168752Sscottl if (error) { 1871168752Sscottl cam_periph_unlock(periph); 187239213Sgibbs break; 1873168752Sscottl } 187439213Sgibbs error = cdplaymsf(periph, 187539213Sgibbs args->start_m, 187639213Sgibbs args->start_s, 187739213Sgibbs args->start_f, 187839213Sgibbs args->end_m, 187939213Sgibbs args->end_s, 188039213Sgibbs args->end_f); 1881168752Sscottl cam_periph_unlock(periph); 188239213Sgibbs } 188339213Sgibbs break; 188439213Sgibbs case CDIOCPLAYBLOCKS: 188539213Sgibbs { 188639213Sgibbs struct ioc_play_blocks *args 188739213Sgibbs = (struct ioc_play_blocks *) addr; 1888111206Sken struct cd_mode_params params; 1889111206Sken union cd_pages *page; 189039213Sgibbs 1891111206Sken params.alloc_len = sizeof(union cd_mode_data_6_10); 1892169562Sscottl params.mode_buf = malloc(params.alloc_len, M_SCSICD, 1893111206Sken M_WAITOK | M_ZERO); 189439213Sgibbs 1895168752Sscottl cam_periph_lock(periph); 1896352717Savg CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 1897168752Sscottl ("trying to do CDIOCPLAYBLOCKS\n")); 1898168752Sscottl 1899168752Sscottl 1900111206Sken error = cdgetmode(periph, ¶ms, AUDIO_PAGE); 190139213Sgibbs if (error) { 1902169562Sscottl free(params.mode_buf, M_SCSICD); 1903168752Sscottl cam_periph_unlock(periph); 190439213Sgibbs break; 190539213Sgibbs } 1906111206Sken page = cdgetpage(¶ms); 1907111206Sken 1908111206Sken page->audio.flags &= ~CD_PA_SOTC; 1909111206Sken page->audio.flags |= CD_PA_IMMED; 1910111206Sken error = cdsetmode(periph, ¶ms); 1911169562Sscottl free(params.mode_buf, M_SCSICD); 1912168752Sscottl if (error) { 1913168752Sscottl cam_periph_unlock(periph); 191439213Sgibbs break; 1915168752Sscottl } 191639213Sgibbs error = cdplay(periph, args->blk, args->len); 1917168752Sscottl cam_periph_unlock(periph); 191839213Sgibbs } 191939213Sgibbs break; 192039213Sgibbs case CDIOCREADSUBCHANNEL: 192139213Sgibbs { 192239213Sgibbs struct ioc_read_subchannel *args 192339213Sgibbs = (struct ioc_read_subchannel *) addr; 192439213Sgibbs struct cd_sub_channel_info *data; 192539213Sgibbs u_int32_t len = args->data_len; 192639213Sgibbs 1927352717Savg data = malloc(sizeof(struct cd_sub_channel_info), 1928203931Smav M_SCSICD, M_WAITOK | M_ZERO); 1929168752Sscottl 1930168752Sscottl cam_periph_lock(periph); 1931352717Savg CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 193239213Sgibbs ("trying to do CDIOCREADSUBCHANNEL\n")); 193339213Sgibbs 193439213Sgibbs if ((len > sizeof(struct cd_sub_channel_info)) || 193539213Sgibbs (len < sizeof(struct cd_sub_channel_header))) { 193639213Sgibbs printf( 193739213Sgibbs "scsi_cd: cdioctl: " 193839213Sgibbs "cdioreadsubchannel: error, len=%d\n", 193939213Sgibbs len); 194039213Sgibbs error = EINVAL; 1941169562Sscottl free(data, M_SCSICD); 1942168752Sscottl cam_periph_unlock(periph); 194339213Sgibbs break; 194439213Sgibbs } 194539213Sgibbs 194639213Sgibbs if (softc->quirks & CD_Q_BCD_TRACKS) 194739213Sgibbs args->track = bin2bcd(args->track); 194839213Sgibbs 194939213Sgibbs error = cdreadsubchannel(periph, args->address_format, 195039213Sgibbs args->data_format, args->track, data, len); 195139213Sgibbs 195239213Sgibbs if (error) { 1953169562Sscottl free(data, M_SCSICD); 1954168752Sscottl cam_periph_unlock(periph); 1955352717Savg break; 195639213Sgibbs } 195739213Sgibbs if (softc->quirks & CD_Q_BCD_TRACKS) 195839213Sgibbs data->what.track_info.track_number = 195939213Sgibbs bcd2bin(data->what.track_info.track_number); 196039213Sgibbs len = min(len, ((data->header.data_len[0] << 8) + 196139213Sgibbs data->header.data_len[1] + 196239213Sgibbs sizeof(struct cd_sub_channel_header))); 1963168752Sscottl cam_periph_unlock(periph); 1964349629Smarkj error = copyout(data, args->data, len); 1965169562Sscottl free(data, M_SCSICD); 196639213Sgibbs } 196739213Sgibbs break; 196839213Sgibbs 196939213Sgibbs case CDIOREADTOCHEADER: 197039213Sgibbs { 197139213Sgibbs struct ioc_toc_header *th; 197239213Sgibbs 1973169562Sscottl th = malloc(sizeof(struct ioc_toc_header), M_SCSICD, 1974203931Smav M_WAITOK | M_ZERO); 1975168752Sscottl 1976168752Sscottl cam_periph_lock(periph); 1977352717Savg CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 197839213Sgibbs ("trying to do CDIOREADTOCHEADER\n")); 197939213Sgibbs 1980352717Savg error = cdreadtoc(periph, 0, 0, (u_int8_t *)th, 1981221585Savg sizeof (*th), /*sense_flags*/SF_NO_PRINT); 198239213Sgibbs if (error) { 1983169562Sscottl free(th, M_SCSICD); 1984168752Sscottl cam_periph_unlock(periph); 198539213Sgibbs break; 198639213Sgibbs } 198739213Sgibbs if (softc->quirks & CD_Q_BCD_TRACKS) { 198839213Sgibbs /* we are going to have to convert the BCD 198939213Sgibbs * encoding on the cd to what is expected 199039213Sgibbs */ 1991352717Savg th->starting_track = 199239213Sgibbs bcd2bin(th->starting_track); 199339213Sgibbs th->ending_track = bcd2bin(th->ending_track); 199439213Sgibbs } 199590868Smike th->len = ntohs(th->len); 199639213Sgibbs bcopy(th, addr, sizeof(*th)); 1997169562Sscottl free(th, M_SCSICD); 1998168752Sscottl cam_periph_unlock(periph); 199939213Sgibbs } 200039213Sgibbs break; 200139213Sgibbs case CDIOREADTOCENTRYS: 200239213Sgibbs { 2003111206Sken struct cd_tocdata *data; 2004111206Sken struct cd_toc_single *lead; 200539213Sgibbs struct ioc_read_toc_entry *te = 200639213Sgibbs (struct ioc_read_toc_entry *) addr; 200739213Sgibbs struct ioc_toc_header *th; 200839213Sgibbs u_int32_t len, readlen, idx, num; 200939213Sgibbs u_int32_t starting_track = te->starting_track; 201039213Sgibbs 2011203931Smav data = malloc(sizeof(*data), M_SCSICD, M_WAITOK | M_ZERO); 2012203931Smav lead = malloc(sizeof(*lead), M_SCSICD, M_WAITOK | M_ZERO); 2013168752Sscottl 2014168752Sscottl cam_periph_lock(periph); 2015352717Savg CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 201639213Sgibbs ("trying to do CDIOREADTOCENTRYS\n")); 201739213Sgibbs 201839213Sgibbs if (te->data_len < sizeof(struct cd_toc_entry) 201939213Sgibbs || (te->data_len % sizeof(struct cd_toc_entry)) != 0 202039213Sgibbs || (te->address_format != CD_MSF_FORMAT 202139213Sgibbs && te->address_format != CD_LBA_FORMAT)) { 202239213Sgibbs error = EINVAL; 202339213Sgibbs printf("scsi_cd: error in readtocentries, " 202439213Sgibbs "returning EINVAL\n"); 2025169562Sscottl free(data, M_SCSICD); 2026169562Sscottl free(lead, M_SCSICD); 2027168752Sscottl cam_periph_unlock(periph); 202839213Sgibbs break; 202939213Sgibbs } 203039213Sgibbs 203139213Sgibbs th = &data->header; 2032352717Savg error = cdreadtoc(periph, 0, 0, (u_int8_t *)th, 2033111206Sken sizeof (*th), /*sense_flags*/0); 203439213Sgibbs if (error) { 2035169562Sscottl free(data, M_SCSICD); 2036169562Sscottl free(lead, M_SCSICD); 2037168752Sscottl cam_periph_unlock(periph); 203839213Sgibbs break; 203939213Sgibbs } 204039213Sgibbs 204139213Sgibbs if (softc->quirks & CD_Q_BCD_TRACKS) { 204239213Sgibbs /* we are going to have to convert the BCD 204339213Sgibbs * encoding on the cd to what is expected 204439213Sgibbs */ 204539213Sgibbs th->starting_track = 204639213Sgibbs bcd2bin(th->starting_track); 204739213Sgibbs th->ending_track = bcd2bin(th->ending_track); 204839213Sgibbs } 204939213Sgibbs 205039213Sgibbs if (starting_track == 0) 205139213Sgibbs starting_track = th->starting_track; 205239213Sgibbs else if (starting_track == LEADOUT) 205339213Sgibbs starting_track = th->ending_track + 1; 205439213Sgibbs else if (starting_track < th->starting_track || 205539213Sgibbs starting_track > th->ending_track + 1) { 205639213Sgibbs printf("scsi_cd: error in readtocentries, " 205739213Sgibbs "returning EINVAL\n"); 2058169562Sscottl free(data, M_SCSICD); 2059169562Sscottl free(lead, M_SCSICD); 2060168752Sscottl cam_periph_unlock(periph); 206139213Sgibbs error = EINVAL; 206239213Sgibbs break; 206339213Sgibbs } 206439213Sgibbs 206539213Sgibbs /* calculate reading length without leadout entry */ 206639213Sgibbs readlen = (th->ending_track - starting_track + 1) * 206739213Sgibbs sizeof(struct cd_toc_entry); 206839213Sgibbs 206939213Sgibbs /* and with leadout entry */ 207039213Sgibbs len = readlen + sizeof(struct cd_toc_entry); 207139213Sgibbs if (te->data_len < len) { 207239213Sgibbs len = te->data_len; 207339213Sgibbs if (readlen > len) 207439213Sgibbs readlen = len; 207539213Sgibbs } 207639213Sgibbs if (len > sizeof(data->entries)) { 207739213Sgibbs printf("scsi_cd: error in readtocentries, " 207839213Sgibbs "returning EINVAL\n"); 207939213Sgibbs error = EINVAL; 2080169562Sscottl free(data, M_SCSICD); 2081169562Sscottl free(lead, M_SCSICD); 2082168752Sscottl cam_periph_unlock(periph); 208339213Sgibbs break; 208439213Sgibbs } 208539213Sgibbs num = len / sizeof(struct cd_toc_entry); 208639213Sgibbs 208739213Sgibbs if (readlen > 0) { 208839213Sgibbs error = cdreadtoc(periph, te->address_format, 208939213Sgibbs starting_track, 2090111206Sken (u_int8_t *)data, 2091111206Sken readlen + sizeof (*th), 2092111206Sken /*sense_flags*/0); 209339213Sgibbs if (error) { 2094169562Sscottl free(data, M_SCSICD); 2095169562Sscottl free(lead, M_SCSICD); 2096168752Sscottl cam_periph_unlock(periph); 209739213Sgibbs break; 209839213Sgibbs } 209939213Sgibbs } 210039213Sgibbs 210139213Sgibbs /* make leadout entry if needed */ 210239213Sgibbs idx = starting_track + num - 1; 210339213Sgibbs if (softc->quirks & CD_Q_BCD_TRACKS) 210439213Sgibbs th->ending_track = bcd2bin(th->ending_track); 210539213Sgibbs if (idx == th->ending_track + 1) { 210639213Sgibbs error = cdreadtoc(periph, te->address_format, 2107111206Sken LEADOUT, (u_int8_t *)lead, 2108111206Sken sizeof(*lead), 2109111206Sken /*sense_flags*/0); 211039213Sgibbs if (error) { 2111169562Sscottl free(data, M_SCSICD); 2112169562Sscottl free(lead, M_SCSICD); 2113168752Sscottl cam_periph_unlock(periph); 211439213Sgibbs break; 211539213Sgibbs } 2116352717Savg data->entries[idx - starting_track] = 211739213Sgibbs lead->entry; 211839213Sgibbs } 211939213Sgibbs if (softc->quirks & CD_Q_BCD_TRACKS) { 212039213Sgibbs for (idx = 0; idx < num - 1; idx++) { 212139213Sgibbs data->entries[idx].track = 212239213Sgibbs bcd2bin(data->entries[idx].track); 212339213Sgibbs } 212439213Sgibbs } 212539213Sgibbs 2126168752Sscottl cam_periph_unlock(periph); 212739213Sgibbs error = copyout(data->entries, te->data, len); 2128169562Sscottl free(data, M_SCSICD); 2129169562Sscottl free(lead, M_SCSICD); 213039213Sgibbs } 213139213Sgibbs break; 213239213Sgibbs case CDIOREADTOCENTRY: 213339213Sgibbs { 2134111206Sken struct cd_toc_single *data; 213539213Sgibbs struct ioc_read_toc_single_entry *te = 213639213Sgibbs (struct ioc_read_toc_single_entry *) addr; 213739213Sgibbs struct ioc_toc_header *th; 213839213Sgibbs u_int32_t track; 213939213Sgibbs 2140203931Smav data = malloc(sizeof(*data), M_SCSICD, M_WAITOK | M_ZERO); 2141168752Sscottl 2142168752Sscottl cam_periph_lock(periph); 2143352717Savg CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 214439213Sgibbs ("trying to do CDIOREADTOCENTRY\n")); 214539213Sgibbs 214639213Sgibbs if (te->address_format != CD_MSF_FORMAT 214739213Sgibbs && te->address_format != CD_LBA_FORMAT) { 214839213Sgibbs printf("error in readtocentry, " 214939213Sgibbs " returning EINVAL\n"); 2150169562Sscottl free(data, M_SCSICD); 215139213Sgibbs error = EINVAL; 2152168752Sscottl cam_periph_unlock(periph); 215339213Sgibbs break; 215439213Sgibbs } 215539213Sgibbs 215639213Sgibbs th = &data->header; 2157111206Sken error = cdreadtoc(periph, 0, 0, (u_int8_t *)th, 2158111206Sken sizeof (*th), /*sense_flags*/0); 215939213Sgibbs if (error) { 2160169562Sscottl free(data, M_SCSICD); 2161168752Sscottl cam_periph_unlock(periph); 216239213Sgibbs break; 216339213Sgibbs } 216439213Sgibbs 216539213Sgibbs if (softc->quirks & CD_Q_BCD_TRACKS) { 216639213Sgibbs /* we are going to have to convert the BCD 216739213Sgibbs * encoding on the cd to what is expected 216839213Sgibbs */ 216939213Sgibbs th->starting_track = 217039213Sgibbs bcd2bin(th->starting_track); 217139213Sgibbs th->ending_track = bcd2bin(th->ending_track); 217239213Sgibbs } 217339213Sgibbs track = te->track; 217439213Sgibbs if (track == 0) 217539213Sgibbs track = th->starting_track; 217639213Sgibbs else if (track == LEADOUT) 217739213Sgibbs /* OK */; 217839213Sgibbs else if (track < th->starting_track || 217939213Sgibbs track > th->ending_track + 1) { 218039213Sgibbs printf("error in readtocentry, " 218139213Sgibbs " returning EINVAL\n"); 2182169562Sscottl free(data, M_SCSICD); 218339213Sgibbs error = EINVAL; 2184168752Sscottl cam_periph_unlock(periph); 218539213Sgibbs break; 218639213Sgibbs } 218739213Sgibbs 218839213Sgibbs error = cdreadtoc(periph, te->address_format, track, 2189111206Sken (u_int8_t *)data, sizeof(*data), 2190111206Sken /*sense_flags*/0); 219139213Sgibbs if (error) { 2192169562Sscottl free(data, M_SCSICD); 2193168752Sscottl cam_periph_unlock(periph); 219439213Sgibbs break; 219539213Sgibbs } 219639213Sgibbs 219739213Sgibbs if (softc->quirks & CD_Q_BCD_TRACKS) 219839213Sgibbs data->entry.track = bcd2bin(data->entry.track); 219939213Sgibbs bcopy(&data->entry, &te->entry, 220039213Sgibbs sizeof(struct cd_toc_entry)); 2201169562Sscottl free(data, M_SCSICD); 2202168752Sscottl cam_periph_unlock(periph); 220339213Sgibbs } 220439213Sgibbs break; 220539213Sgibbs case CDIOCSETPATCH: 220639213Sgibbs { 2207111206Sken struct ioc_patch *arg = (struct ioc_patch *)addr; 2208111206Sken struct cd_mode_params params; 2209111206Sken union cd_pages *page; 221039213Sgibbs 2211168752Sscottl params.alloc_len = sizeof(union cd_mode_data_6_10); 2212352717Savg params.mode_buf = malloc(params.alloc_len, M_SCSICD, 2213168752Sscottl M_WAITOK | M_ZERO); 2214168752Sscottl 2215168752Sscottl cam_periph_lock(periph); 2216352717Savg CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 221739213Sgibbs ("trying to do CDIOCSETPATCH\n")); 221839213Sgibbs 2219111206Sken error = cdgetmode(periph, ¶ms, AUDIO_PAGE); 222039213Sgibbs if (error) { 2221169562Sscottl free(params.mode_buf, M_SCSICD); 2222168752Sscottl cam_periph_unlock(periph); 222339213Sgibbs break; 222439213Sgibbs } 2225111206Sken page = cdgetpage(¶ms); 2226111206Sken 2227352717Savg page->audio.port[LEFT_PORT].channels = 222839213Sgibbs arg->patch[0]; 2229352717Savg page->audio.port[RIGHT_PORT].channels = 223039213Sgibbs arg->patch[1]; 2231111206Sken page->audio.port[2].channels = arg->patch[2]; 2232111206Sken page->audio.port[3].channels = arg->patch[3]; 2233111206Sken error = cdsetmode(periph, ¶ms); 2234169562Sscottl free(params.mode_buf, M_SCSICD); 2235168752Sscottl cam_periph_unlock(periph); 223639213Sgibbs } 223739213Sgibbs break; 223839213Sgibbs case CDIOCGETVOL: 223939213Sgibbs { 224039213Sgibbs struct ioc_vol *arg = (struct ioc_vol *) addr; 2241111206Sken struct cd_mode_params params; 2242111206Sken union cd_pages *page; 224339213Sgibbs 2244168752Sscottl params.alloc_len = sizeof(union cd_mode_data_6_10); 2245352717Savg params.mode_buf = malloc(params.alloc_len, M_SCSICD, 2246168752Sscottl M_WAITOK | M_ZERO); 2247168752Sscottl 2248168752Sscottl cam_periph_lock(periph); 2249352717Savg CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 225039213Sgibbs ("trying to do CDIOCGETVOL\n")); 225139213Sgibbs 2252111206Sken error = cdgetmode(periph, ¶ms, AUDIO_PAGE); 225339213Sgibbs if (error) { 2254169562Sscottl free(params.mode_buf, M_SCSICD); 2255168752Sscottl cam_periph_unlock(periph); 225639213Sgibbs break; 225739213Sgibbs } 2258111206Sken page = cdgetpage(¶ms); 2259111206Sken 2260352717Savg arg->vol[LEFT_PORT] = 2261111206Sken page->audio.port[LEFT_PORT].volume; 2262352717Savg arg->vol[RIGHT_PORT] = 2263111206Sken page->audio.port[RIGHT_PORT].volume; 2264111206Sken arg->vol[2] = page->audio.port[2].volume; 2265111206Sken arg->vol[3] = page->audio.port[3].volume; 2266169562Sscottl free(params.mode_buf, M_SCSICD); 2267168752Sscottl cam_periph_unlock(periph); 226839213Sgibbs } 226939213Sgibbs break; 227039213Sgibbs case CDIOCSETVOL: 227139213Sgibbs { 227239213Sgibbs struct ioc_vol *arg = (struct ioc_vol *) addr; 2273111206Sken struct cd_mode_params params; 2274111206Sken union cd_pages *page; 227539213Sgibbs 2276168752Sscottl params.alloc_len = sizeof(union cd_mode_data_6_10); 2277352717Savg params.mode_buf = malloc(params.alloc_len, M_SCSICD, 2278168752Sscottl M_WAITOK | M_ZERO); 2279168752Sscottl 2280168752Sscottl cam_periph_lock(periph); 2281352717Savg CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 228239213Sgibbs ("trying to do CDIOCSETVOL\n")); 228339213Sgibbs 2284111206Sken error = cdgetmode(periph, ¶ms, AUDIO_PAGE); 228539213Sgibbs if (error) { 2286169562Sscottl free(params.mode_buf, M_SCSICD); 2287168752Sscottl cam_periph_unlock(periph); 228839213Sgibbs break; 228939213Sgibbs } 2290111206Sken page = cdgetpage(¶ms); 2291111206Sken 2292111206Sken page->audio.port[LEFT_PORT].channels = CHANNEL_0; 2293352717Savg page->audio.port[LEFT_PORT].volume = 229439213Sgibbs arg->vol[LEFT_PORT]; 2295111206Sken page->audio.port[RIGHT_PORT].channels = CHANNEL_1; 2296352717Savg page->audio.port[RIGHT_PORT].volume = 229739213Sgibbs arg->vol[RIGHT_PORT]; 2298111206Sken page->audio.port[2].volume = arg->vol[2]; 2299111206Sken page->audio.port[3].volume = arg->vol[3]; 2300111206Sken error = cdsetmode(periph, ¶ms); 2301168752Sscottl cam_periph_unlock(periph); 2302169562Sscottl free(params.mode_buf, M_SCSICD); 230339213Sgibbs } 230439213Sgibbs break; 230539213Sgibbs case CDIOCSETMONO: 230639213Sgibbs { 2307111206Sken struct cd_mode_params params; 2308111206Sken union cd_pages *page; 230939213Sgibbs 2310168752Sscottl params.alloc_len = sizeof(union cd_mode_data_6_10); 2311169562Sscottl params.mode_buf = malloc(params.alloc_len, M_SCSICD, 2312168752Sscottl M_WAITOK | M_ZERO); 2313168752Sscottl 2314168752Sscottl cam_periph_lock(periph); 2315352717Savg CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 231639213Sgibbs ("trying to do CDIOCSETMONO\n")); 231739213Sgibbs 2318111206Sken error = cdgetmode(periph, ¶ms, AUDIO_PAGE); 231939213Sgibbs if (error) { 2320169562Sscottl free(params.mode_buf, M_SCSICD); 2321168752Sscottl cam_periph_unlock(periph); 232239213Sgibbs break; 232339213Sgibbs } 2324111206Sken page = cdgetpage(¶ms); 2325111206Sken 2326352717Savg page->audio.port[LEFT_PORT].channels = 232739213Sgibbs LEFT_CHANNEL | RIGHT_CHANNEL; 2328352717Savg page->audio.port[RIGHT_PORT].channels = 232939213Sgibbs LEFT_CHANNEL | RIGHT_CHANNEL; 2330111206Sken page->audio.port[2].channels = 0; 2331111206Sken page->audio.port[3].channels = 0; 2332111206Sken error = cdsetmode(periph, ¶ms); 2333168752Sscottl cam_periph_unlock(periph); 2334169562Sscottl free(params.mode_buf, M_SCSICD); 233539213Sgibbs } 233639213Sgibbs break; 233739213Sgibbs case CDIOCSETSTEREO: 233839213Sgibbs { 2339111206Sken struct cd_mode_params params; 2340111206Sken union cd_pages *page; 234139213Sgibbs 2342168752Sscottl params.alloc_len = sizeof(union cd_mode_data_6_10); 2343169562Sscottl params.mode_buf = malloc(params.alloc_len, M_SCSICD, 2344168752Sscottl M_WAITOK | M_ZERO); 2345168752Sscottl 2346168752Sscottl cam_periph_lock(periph); 2347352717Savg CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 234839213Sgibbs ("trying to do CDIOCSETSTEREO\n")); 234939213Sgibbs 2350111206Sken error = cdgetmode(periph, ¶ms, AUDIO_PAGE); 235139213Sgibbs if (error) { 2352169562Sscottl free(params.mode_buf, M_SCSICD); 2353168752Sscottl cam_periph_unlock(periph); 235439213Sgibbs break; 235539213Sgibbs } 2356111206Sken page = cdgetpage(¶ms); 2357111206Sken 2358352717Savg page->audio.port[LEFT_PORT].channels = 235939213Sgibbs LEFT_CHANNEL; 2360352717Savg page->audio.port[RIGHT_PORT].channels = 236139213Sgibbs RIGHT_CHANNEL; 2362111206Sken page->audio.port[2].channels = 0; 2363111206Sken page->audio.port[3].channels = 0; 2364111206Sken error = cdsetmode(periph, ¶ms); 2365169562Sscottl free(params.mode_buf, M_SCSICD); 2366168752Sscottl cam_periph_unlock(periph); 236739213Sgibbs } 236839213Sgibbs break; 236939213Sgibbs case CDIOCSETMUTE: 237039213Sgibbs { 2371111206Sken struct cd_mode_params params; 2372111206Sken union cd_pages *page; 237339213Sgibbs 2374168752Sscottl params.alloc_len = sizeof(union cd_mode_data_6_10); 2375169562Sscottl params.mode_buf = malloc(params.alloc_len, M_SCSICD, 2376168752Sscottl M_WAITOK | M_ZERO); 2377168752Sscottl 2378168752Sscottl cam_periph_lock(periph); 2379352717Savg CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 238039213Sgibbs ("trying to do CDIOCSETMUTE\n")); 238139213Sgibbs 2382111206Sken error = cdgetmode(periph, ¶ms, AUDIO_PAGE); 238339213Sgibbs if (error) { 2384208800Savg free(params.mode_buf, M_SCSICD); 2385168752Sscottl cam_periph_unlock(periph); 238639213Sgibbs break; 238739213Sgibbs } 2388111206Sken page = cdgetpage(¶ms); 2389111206Sken 2390111206Sken page->audio.port[LEFT_PORT].channels = 0; 2391111206Sken page->audio.port[RIGHT_PORT].channels = 0; 2392111206Sken page->audio.port[2].channels = 0; 2393111206Sken page->audio.port[3].channels = 0; 2394111206Sken error = cdsetmode(periph, ¶ms); 2395169562Sscottl free(params.mode_buf, M_SCSICD); 2396168752Sscottl cam_periph_unlock(periph); 239739213Sgibbs } 239839213Sgibbs break; 239939213Sgibbs case CDIOCSETLEFT: 240039213Sgibbs { 2401111206Sken struct cd_mode_params params; 2402111206Sken union cd_pages *page; 240339213Sgibbs 2404168752Sscottl params.alloc_len = sizeof(union cd_mode_data_6_10); 2405169562Sscottl params.mode_buf = malloc(params.alloc_len, M_SCSICD, 2406168752Sscottl M_WAITOK | M_ZERO); 2407168752Sscottl 2408168752Sscottl cam_periph_lock(periph); 2409352717Savg CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 241039213Sgibbs ("trying to do CDIOCSETLEFT\n")); 241139213Sgibbs 2412111206Sken error = cdgetmode(periph, ¶ms, AUDIO_PAGE); 241339213Sgibbs if (error) { 2414169562Sscottl free(params.mode_buf, M_SCSICD); 2415168752Sscottl cam_periph_unlock(periph); 241639213Sgibbs break; 241739213Sgibbs } 2418111206Sken page = cdgetpage(¶ms); 2419111206Sken 2420111206Sken page->audio.port[LEFT_PORT].channels = LEFT_CHANNEL; 2421111206Sken page->audio.port[RIGHT_PORT].channels = LEFT_CHANNEL; 2422111206Sken page->audio.port[2].channels = 0; 2423111206Sken page->audio.port[3].channels = 0; 2424111206Sken error = cdsetmode(periph, ¶ms); 2425169562Sscottl free(params.mode_buf, M_SCSICD); 2426168752Sscottl cam_periph_unlock(periph); 242739213Sgibbs } 242839213Sgibbs break; 242939213Sgibbs case CDIOCSETRIGHT: 243039213Sgibbs { 2431111206Sken struct cd_mode_params params; 2432111206Sken union cd_pages *page; 243339213Sgibbs 2434111206Sken params.alloc_len = sizeof(union cd_mode_data_6_10); 2435169562Sscottl params.mode_buf = malloc(params.alloc_len, M_SCSICD, 2436111206Sken M_WAITOK | M_ZERO); 2437111206Sken 2438168752Sscottl cam_periph_lock(periph); 2439352717Savg CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 2440168752Sscottl ("trying to do CDIOCSETRIGHT\n")); 2441168752Sscottl 2442111206Sken error = cdgetmode(periph, ¶ms, AUDIO_PAGE); 244339213Sgibbs if (error) { 2444169562Sscottl free(params.mode_buf, M_SCSICD); 2445168752Sscottl cam_periph_unlock(periph); 244639213Sgibbs break; 244739213Sgibbs } 2448111206Sken page = cdgetpage(¶ms); 2449111206Sken 2450111206Sken page->audio.port[LEFT_PORT].channels = RIGHT_CHANNEL; 2451111206Sken page->audio.port[RIGHT_PORT].channels = RIGHT_CHANNEL; 2452111206Sken page->audio.port[2].channels = 0; 2453111206Sken page->audio.port[3].channels = 0; 2454111206Sken error = cdsetmode(periph, ¶ms); 2455169562Sscottl free(params.mode_buf, M_SCSICD); 2456168752Sscottl cam_periph_unlock(periph); 245739213Sgibbs } 245839213Sgibbs break; 245939213Sgibbs case CDIOCRESUME: 2460168752Sscottl cam_periph_lock(periph); 246139213Sgibbs error = cdpause(periph, 1); 2462168752Sscottl cam_periph_unlock(periph); 246339213Sgibbs break; 246439213Sgibbs case CDIOCPAUSE: 2465168752Sscottl cam_periph_lock(periph); 246639213Sgibbs error = cdpause(periph, 0); 2467168752Sscottl cam_periph_unlock(periph); 246839213Sgibbs break; 246939213Sgibbs case CDIOCSTART: 2470168752Sscottl cam_periph_lock(periph); 2471111206Sken error = cdstartunit(periph, 0); 2472168752Sscottl cam_periph_unlock(periph); 247339213Sgibbs break; 2474111206Sken case CDIOCCLOSE: 2475168752Sscottl cam_periph_lock(periph); 2476111206Sken error = cdstartunit(periph, 1); 2477168752Sscottl cam_periph_unlock(periph); 2478111206Sken break; 247939213Sgibbs case CDIOCSTOP: 2480168752Sscottl cam_periph_lock(periph); 248139213Sgibbs error = cdstopunit(periph, 0); 2482168752Sscottl cam_periph_unlock(periph); 248339213Sgibbs break; 248439213Sgibbs case CDIOCEJECT: 2485168752Sscottl cam_periph_lock(periph); 248639213Sgibbs error = cdstopunit(periph, 1); 2487168752Sscottl cam_periph_unlock(periph); 248839213Sgibbs break; 248939213Sgibbs case CDIOCALLOW: 2490168752Sscottl cam_periph_lock(periph); 249139213Sgibbs cdprevent(periph, PR_ALLOW); 2492168752Sscottl cam_periph_unlock(periph); 249339213Sgibbs break; 249439213Sgibbs case CDIOCPREVENT: 2495168752Sscottl cam_periph_lock(periph); 249639213Sgibbs cdprevent(periph, PR_PREVENT); 2497168752Sscottl cam_periph_unlock(periph); 249839213Sgibbs break; 249939213Sgibbs case CDIOCSETDEBUG: 250039213Sgibbs /* sc_link->flags |= (SDEV_DB1 | SDEV_DB2); */ 250139213Sgibbs error = ENOTTY; 250239213Sgibbs break; 250339213Sgibbs case CDIOCCLRDEBUG: 250439213Sgibbs /* sc_link->flags &= ~(SDEV_DB1 | SDEV_DB2); */ 250539213Sgibbs error = ENOTTY; 250639213Sgibbs break; 250739213Sgibbs case CDIOCRESET: 250839213Sgibbs /* return (cd_reset(periph)); */ 250939213Sgibbs error = ENOTTY; 251039213Sgibbs break; 2511105421Snjl case CDRIOCREADSPEED: 2512168752Sscottl cam_periph_lock(periph); 2513105421Snjl error = cdsetspeed(periph, *(u_int32_t *)addr, CDR_MAX_SPEED); 2514168752Sscottl cam_periph_unlock(periph); 2515105421Snjl break; 2516105421Snjl case CDRIOCWRITESPEED: 2517168752Sscottl cam_periph_lock(periph); 2518105421Snjl error = cdsetspeed(periph, CDR_MAX_SPEED, *(u_int32_t *)addr); 2519168752Sscottl cam_periph_unlock(periph); 2520105421Snjl break; 2521229395Smav case CDRIOCGETBLOCKSIZE: 2522229395Smav *(int *)addr = softc->params.blksize; 2523229395Smav break; 2524229395Smav case CDRIOCSETBLOCKSIZE: 2525229395Smav if (*(int *)addr <= 0) { 2526229395Smav error = EINVAL; 2527229395Smav break; 2528229395Smav } 2529229395Smav softc->disk->d_sectorsize = softc->params.blksize = *(int *)addr; 2530229395Smav break; 253160422Sken case DVDIOCSENDKEY: 253260422Sken case DVDIOCREPORTKEY: { 253360422Sken struct dvd_authinfo *authinfo; 253460422Sken 253560422Sken authinfo = (struct dvd_authinfo *)addr; 253660422Sken 253760422Sken if (cmd == DVDIOCREPORTKEY) 253860422Sken error = cdreportkey(periph, authinfo); 253960422Sken else 254060422Sken error = cdsendkey(periph, authinfo); 254160422Sken break; 2542104456Sphk } 254360422Sken case DVDIOCREADSTRUCTURE: { 254460422Sken struct dvd_struct *dvdstruct; 254560422Sken 254660422Sken dvdstruct = (struct dvd_struct *)addr; 254760422Sken 254860422Sken error = cdreaddvdstructure(periph, dvdstruct); 254960422Sken 255060422Sken break; 255160422Sken } 255239213Sgibbs default: 2553168752Sscottl cam_periph_lock(periph); 255439213Sgibbs error = cam_periph_ioctl(periph, cmd, addr, cderror); 2555168752Sscottl cam_periph_unlock(periph); 255639213Sgibbs break; 255739213Sgibbs } 255839213Sgibbs 2559168752Sscottl cam_periph_lock(periph); 2560168752Sscottl cam_periph_unhold(periph); 2561352717Savg 256239213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("leaving cdioctl\n")); 2563104456Sphk if (error && bootverbose) { 2564104456Sphk printf("scsi_cd.c::ioctl cmd=%08lx error=%d\n", cmd, error); 2565104456Sphk } 2566168752Sscottl cam_periph_unlock(periph); 256739213Sgibbs 256839213Sgibbs return (error); 256939213Sgibbs} 257039213Sgibbs 257139213Sgibbsstatic void 257239213Sgibbscdprevent(struct cam_periph *periph, int action) 257339213Sgibbs{ 257439213Sgibbs union ccb *ccb; 257539213Sgibbs struct cd_softc *softc; 257639213Sgibbs int error; 257739213Sgibbs 257839213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdprevent\n")); 257939213Sgibbs 258039213Sgibbs softc = (struct cd_softc *)periph->softc; 2581352717Savg 258239213Sgibbs if (((action == PR_ALLOW) 258339213Sgibbs && (softc->flags & CD_FLAG_DISC_LOCKED) == 0) 258439213Sgibbs || ((action == PR_PREVENT) 258539213Sgibbs && (softc->flags & CD_FLAG_DISC_LOCKED) != 0)) { 258639213Sgibbs return; 258739213Sgibbs } 2588352717Savg 2589264295Smav ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); 259039213Sgibbs 2591352717Savg scsi_prevent(&ccb->csio, 2592203108Smav /*retries*/ cd_retry_count, 259339213Sgibbs cddone, 259439213Sgibbs MSG_SIMPLE_Q_TAG, 259539213Sgibbs action, 259639213Sgibbs SSD_FULL_SIZE, 259739213Sgibbs /* timeout */60000); 2598352717Savg 259974840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 260074840Sken /*sense_flags*/SF_RETRY_UA|SF_NO_PRINT); 260139213Sgibbs 260239213Sgibbs xpt_release_ccb(ccb); 260339213Sgibbs 260439213Sgibbs if (error == 0) { 260539213Sgibbs if (action == PR_ALLOW) 260639213Sgibbs softc->flags &= ~CD_FLAG_DISC_LOCKED; 260739213Sgibbs else 260839213Sgibbs softc->flags |= CD_FLAG_DISC_LOCKED; 260939213Sgibbs } 261039213Sgibbs} 261139213Sgibbs 2612352715Savgstatic void 2613352715Savgcdmediaprobedone(struct cam_periph *periph) 2614352715Savg{ 2615352715Savg struct cd_softc *softc; 2616352715Savg 2617352715Savg softc = (struct cd_softc *)periph->softc; 2618352715Savg 2619352715Savg softc->flags &= ~CD_FLAG_MEDIA_SCAN_ACT; 2620352715Savg 2621352715Savg if ((softc->flags & CD_FLAG_MEDIA_WAIT) != 0) { 2622352715Savg softc->flags &= ~CD_FLAG_MEDIA_WAIT; 2623352715Savg wakeup(&softc->toc); 2624352715Savg } 2625352715Savg} 2626352715Savg 2627120599Sphk/* 2628120599Sphk * XXX: the disk media and sector size is only really able to change 2629120599Sphk * XXX: while the device is closed. 2630120599Sphk */ 2631352715Savg 263239213Sgibbsstatic int 2633352715Savgcdcheckmedia(struct cam_periph *periph, int do_wait) 2634352715Savg{ 2635352715Savg struct cd_softc *softc; 2636352715Savg int error; 2637352715Savg 2638352715Savg softc = (struct cd_softc *)periph->softc; 2639352715Savg error = 0; 2640352715Savg 2641352715Savg if ((do_wait != 0) 2642352715Savg && ((softc->flags & CD_FLAG_MEDIA_WAIT) == 0)) { 2643352715Savg softc->flags |= CD_FLAG_MEDIA_WAIT; 2644352715Savg } 2645352715Savg if ((softc->flags & CD_FLAG_MEDIA_SCAN_ACT) == 0) { 2646352715Savg softc->state = CD_STATE_MEDIA_PREVENT; 2647352715Savg softc->flags |= CD_FLAG_MEDIA_SCAN_ACT; 2648352715Savg xpt_schedule(periph, CAM_PRIORITY_NORMAL); 2649352715Savg } 2650352715Savg 2651352715Savg if (do_wait == 0) 2652352715Savg goto bailout; 2653352715Savg 2654352715Savg error = msleep(&softc->toc, cam_periph_mtx(periph), PRIBIO,"cdmedia",0); 2655352717Savg 2656352715Savg if (error != 0) 2657352715Savg goto bailout; 2658352715Savg 2659352715Savg /* 2660352715Savg * Check to see whether we have a valid size from the media. We 2661352715Savg * may or may not have a valid TOC. 2662352715Savg */ 2663352715Savg if ((softc->flags & CD_FLAG_VALID_MEDIA) == 0) 2664352715Savg error = EINVAL; 2665352715Savgbailout: 2666352715Savg 2667352715Savg return (error); 2668352715Savg} 2669352715Savg 2670352715Savg#if 0 2671352715Savgstatic int 2672111206Skencdcheckmedia(struct cam_periph *periph) 267339213Sgibbs{ 267439213Sgibbs struct cd_softc *softc; 2675111206Sken struct ioc_toc_header *toch; 2676111206Sken struct cd_toc_single leadout; 2677111206Sken u_int32_t size, toclen; 2678111206Sken int error, num_entries, cdindex; 2679111206Sken 2680111206Sken softc = (struct cd_softc *)periph->softc; 2681111206Sken 2682111206Sken cdprevent(periph, PR_PREVENT); 2683134824Sphk softc->disk->d_sectorsize = 2048; 2684125975Sphk softc->disk->d_mediasize = 0; 2685111206Sken 2686111206Sken /* 2687111206Sken * Get the disc size and block size. If we can't get it, we don't 2688111206Sken * have media, most likely. 2689111206Sken */ 2690111206Sken if ((error = cdsize(periph, &size)) != 0) { 2691111206Sken softc->flags &= ~(CD_FLAG_VALID_MEDIA|CD_FLAG_VALID_TOC); 2692111206Sken cdprevent(periph, PR_ALLOW); 2693111206Sken return (error); 2694206648Savg } else { 2695238886Smav softc->flags |= CD_FLAG_SAW_MEDIA | CD_FLAG_VALID_MEDIA; 2696206648Savg softc->disk->d_sectorsize = softc->params.blksize; 2697206648Savg softc->disk->d_mediasize = 2698206648Savg (off_t)softc->params.blksize * softc->params.disksize; 2699206648Savg } 2700111206Sken 2701111206Sken /* 2702111206Sken * Now we check the table of contents. This (currently) is only 2703111206Sken * used for the CDIOCPLAYTRACKS ioctl. It may be used later to do 2704111206Sken * things like present a separate entry in /dev for each track, 2705111206Sken * like that acd(4) driver does. 2706111206Sken */ 2707111206Sken bzero(&softc->toc, sizeof(softc->toc)); 2708111206Sken toch = &softc->toc.header; 2709111206Sken /* 2710111206Sken * We will get errors here for media that doesn't have a table of 2711111206Sken * contents. According to the MMC-3 spec: "When a Read TOC/PMA/ATIP 2712111206Sken * command is presented for a DDCD/CD-R/RW media, where the first TOC 2713111206Sken * has not been recorded (no complete session) and the Format codes 2714111206Sken * 0000b, 0001b, or 0010b are specified, this command shall be rejected 2715111206Sken * with an INVALID FIELD IN CDB. Devices that are not capable of 2716111206Sken * reading an incomplete session on DDC/CD-R/RW media shall report 2717111206Sken * CANNOT READ MEDIUM - INCOMPATIBLE FORMAT." 2718111206Sken * 2719111206Sken * So this isn't fatal if we can't read the table of contents, it 2720111206Sken * just means that the user won't be able to issue the play tracks 2721111206Sken * ioctl, and likely lots of other stuff won't work either. They 2722111206Sken * need to burn the CD before we can do a whole lot with it. So 2723111206Sken * we don't print anything here if we get an error back. 2724111206Sken */ 2725111206Sken error = cdreadtoc(periph, 0, 0, (u_int8_t *)toch, sizeof(*toch), 2726111206Sken SF_NO_PRINT); 2727111206Sken /* 2728111206Sken * Errors in reading the table of contents aren't fatal, we just 2729111206Sken * won't have a valid table of contents cached. 2730111206Sken */ 2731111206Sken if (error != 0) { 2732111206Sken error = 0; 2733111206Sken bzero(&softc->toc, sizeof(softc->toc)); 2734111206Sken goto bailout; 2735111206Sken } 2736111206Sken 2737111206Sken if (softc->quirks & CD_Q_BCD_TRACKS) { 2738111206Sken toch->starting_track = bcd2bin(toch->starting_track); 2739111206Sken toch->ending_track = bcd2bin(toch->ending_track); 2740111206Sken } 2741111206Sken 2742111206Sken /* Number of TOC entries, plus leadout */ 2743111206Sken num_entries = (toch->ending_track - toch->starting_track) + 2; 2744111206Sken 2745111206Sken if (num_entries <= 0) 2746111206Sken goto bailout; 2747111206Sken 2748111206Sken toclen = num_entries * sizeof(struct cd_toc_entry); 2749111206Sken 2750111206Sken error = cdreadtoc(periph, CD_MSF_FORMAT, toch->starting_track, 2751111206Sken (u_int8_t *)&softc->toc, toclen + sizeof(*toch), 2752111206Sken SF_NO_PRINT); 2753111206Sken if (error != 0) { 2754111206Sken error = 0; 2755111206Sken bzero(&softc->toc, sizeof(softc->toc)); 2756111206Sken goto bailout; 2757111206Sken } 2758111206Sken 2759111206Sken if (softc->quirks & CD_Q_BCD_TRACKS) { 2760111206Sken toch->starting_track = bcd2bin(toch->starting_track); 2761111206Sken toch->ending_track = bcd2bin(toch->ending_track); 2762111206Sken } 2763111206Sken /* 2764111206Sken * XXX KDM is this necessary? Probably only if the drive doesn't 2765111206Sken * return leadout information with the table of contents. 2766111206Sken */ 2767111206Sken cdindex = toch->starting_track + num_entries -1; 2768111206Sken if (cdindex == toch->ending_track + 1) { 2769111206Sken 2770352717Savg error = cdreadtoc(periph, CD_MSF_FORMAT, LEADOUT, 2771111206Sken (u_int8_t *)&leadout, sizeof(leadout), 2772111206Sken SF_NO_PRINT); 2773111206Sken if (error != 0) { 2774111206Sken error = 0; 2775111206Sken goto bailout; 2776111206Sken } 2777111206Sken softc->toc.entries[cdindex - toch->starting_track] = 2778111206Sken leadout.entry; 2779111206Sken } 2780111206Sken if (softc->quirks & CD_Q_BCD_TRACKS) { 2781111206Sken for (cdindex = 0; cdindex < num_entries - 1; cdindex++) { 2782111206Sken softc->toc.entries[cdindex].track = 2783111206Sken bcd2bin(softc->toc.entries[cdindex].track); 2784111206Sken } 2785111206Sken } 2786111206Sken 2787111206Sken softc->flags |= CD_FLAG_VALID_TOC; 2788111206Sken 2789228808Smav /* If the first track is audio, correct sector size. */ 2790228808Smav if ((softc->toc.entries[0].control & 4) == 0) { 2791228808Smav softc->disk->d_sectorsize = softc->params.blksize = 2352; 2792228808Smav softc->disk->d_mediasize = 2793228808Smav (off_t)softc->params.blksize * softc->params.disksize; 2794228808Smav } 2795228808Smav 2796111206Skenbailout: 2797111206Sken 2798111206Sken /* 2799111206Sken * We unconditionally (re)set the blocksize each time the 2800111206Sken * CD device is opened. This is because the CD can change, 2801111206Sken * and therefore the blocksize might change. 2802111206Sken * XXX problems here if some slice or partition is still 2803111206Sken * open with the old size? 2804111206Sken */ 2805125975Sphk if ((softc->disk->d_devstat->flags & DEVSTAT_BS_UNAVAILABLE) != 0) 2806125975Sphk softc->disk->d_devstat->flags &= ~DEVSTAT_BS_UNAVAILABLE; 2807125975Sphk softc->disk->d_devstat->block_size = softc->params.blksize; 2808111206Sken 2809111206Sken return (error); 2810111206Sken} 2811111206Sken 2812111206Skenstatic int 2813111206Skencdsize(struct cam_periph *periph, u_int32_t *size) 2814111206Sken{ 2815111206Sken struct cd_softc *softc; 281639213Sgibbs union ccb *ccb; 281739213Sgibbs struct scsi_read_capacity_data *rcap_buf; 281839213Sgibbs int error; 281939213Sgibbs 282039213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdsize\n")); 282139213Sgibbs 282239213Sgibbs softc = (struct cd_softc *)periph->softc; 2823352717Savg 2824264295Smav ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); 282539213Sgibbs 2826168752Sscottl /* XXX Should be M_WAITOK */ 2827352717Savg rcap_buf = malloc(sizeof(struct scsi_read_capacity_data), 2828203931Smav M_SCSICD, M_NOWAIT | M_ZERO); 2829168752Sscottl if (rcap_buf == NULL) 2830168752Sscottl return (ENOMEM); 283139213Sgibbs 2832352717Savg scsi_read_capacity(&ccb->csio, 2833203108Smav /*retries*/ cd_retry_count, 283439213Sgibbs cddone, 283539213Sgibbs MSG_SIMPLE_Q_TAG, 283639213Sgibbs rcap_buf, 283739213Sgibbs SSD_FULL_SIZE, 283839213Sgibbs /* timeout */20000); 283939213Sgibbs 284074840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 284174840Sken /*sense_flags*/SF_RETRY_UA|SF_NO_PRINT); 284239213Sgibbs 284339213Sgibbs xpt_release_ccb(ccb); 284439213Sgibbs 284539213Sgibbs softc->params.disksize = scsi_4btoul(rcap_buf->addr) + 1; 284639213Sgibbs softc->params.blksize = scsi_4btoul(rcap_buf->length); 2847203931Smav /* Make sure we got at least some block size. */ 2848203931Smav if (error == 0 && softc->params.blksize == 0) 2849203931Smav error = EIO; 285060806Sjoerg /* 285160806Sjoerg * SCSI-3 mandates that the reported blocksize shall be 2048. 285260806Sjoerg * Older drives sometimes report funny values, trim it down to 285360806Sjoerg * 2048, or other parts of the kernel will get confused. 285460806Sjoerg * 285560806Sjoerg * XXX we leave drives alone that might report 512 bytes, as 285660806Sjoerg * well as drives reporting more weird sizes like perhaps 4K. 285760806Sjoerg */ 285860806Sjoerg if (softc->params.blksize > 2048 && softc->params.blksize <= 2352) 285960806Sjoerg softc->params.blksize = 2048; 286039213Sgibbs 2861169562Sscottl free(rcap_buf, M_SCSICD); 286239213Sgibbs *size = softc->params.disksize; 286339213Sgibbs 286439213Sgibbs return (error); 286539213Sgibbs 286639213Sgibbs} 2867352715Savg#endif 286839213Sgibbs 286939213Sgibbsstatic int 2870111206Skencd6byteworkaround(union ccb *ccb) 2871111206Sken{ 2872111206Sken u_int8_t *cdb; 2873111206Sken struct cam_periph *periph; 2874111206Sken struct cd_softc *softc; 2875111206Sken struct cd_mode_params *params; 2876111206Sken int frozen, found; 2877111206Sken 2878111206Sken periph = xpt_path_periph(ccb->ccb_h.path); 2879111206Sken softc = (struct cd_softc *)periph->softc; 2880111206Sken 2881111206Sken cdb = ccb->csio.cdb_io.cdb_bytes; 2882111206Sken 2883111206Sken if ((ccb->ccb_h.flags & CAM_CDB_POINTER) 2884111206Sken || ((cdb[0] != MODE_SENSE_6) 2885111206Sken && (cdb[0] != MODE_SELECT_6))) 2886111206Sken return (0); 2887111206Sken 2888111206Sken /* 2889111206Sken * Because there is no convenient place to stash the overall 2890111206Sken * cd_mode_params structure pointer, we have to grab it like this. 2891111206Sken * This means that ALL MODE_SENSE and MODE_SELECT requests in the 2892111206Sken * cd(4) driver MUST go through cdgetmode() and cdsetmode()! 2893111206Sken * 2894111206Sken * XXX It would be nice if, at some point, we could increase the 2895111206Sken * number of available peripheral private pointers. Both pointers 2896111206Sken * are currently used in most every peripheral driver. 2897111206Sken */ 2898111206Sken found = 0; 2899111206Sken 2900111206Sken STAILQ_FOREACH(params, &softc->mode_queue, links) { 2901111206Sken if (params->mode_buf == ccb->csio.data_ptr) { 2902111206Sken found = 1; 2903111206Sken break; 2904111206Sken } 2905111206Sken } 2906111206Sken 2907111206Sken /* 2908111206Sken * This shouldn't happen. All mode sense and mode select 2909111206Sken * operations in the cd(4) driver MUST go through cdgetmode() and 2910111206Sken * cdsetmode()! 2911111206Sken */ 2912111206Sken if (found == 0) { 2913164906Smjacob xpt_print(periph->path, 2914164906Smjacob "mode buffer not found in mode queue!\n"); 2915111206Sken return (0); 2916111206Sken } 2917111206Sken 2918111206Sken params->cdb_size = 10; 2919111206Sken softc->minimum_command_size = 10; 2920164906Smjacob xpt_print(ccb->ccb_h.path, 2921164906Smjacob "%s(6) failed, increasing minimum CDB size to 10 bytes\n", 2922164906Smjacob (cdb[0] == MODE_SENSE_6) ? "MODE_SENSE" : "MODE_SELECT"); 2923111206Sken 2924111206Sken if (cdb[0] == MODE_SENSE_6) { 2925111206Sken struct scsi_mode_sense_10 ms10; 2926111206Sken struct scsi_mode_sense_6 *ms6; 2927111206Sken int len; 2928111206Sken 2929111206Sken ms6 = (struct scsi_mode_sense_6 *)cdb; 2930111206Sken 2931111206Sken bzero(&ms10, sizeof(ms10)); 2932352717Savg ms10.opcode = MODE_SENSE_10; 2933352717Savg ms10.byte2 = ms6->byte2; 2934352717Savg ms10.page = ms6->page; 2935111206Sken 2936111206Sken /* 2937111206Sken * 10 byte mode header, block descriptor, 2938111206Sken * sizeof(union cd_pages) 2939111206Sken */ 2940111206Sken len = sizeof(struct cd_mode_data_10); 2941111206Sken ccb->csio.dxfer_len = len; 2942111206Sken 2943111206Sken scsi_ulto2b(len, ms10.length); 2944111206Sken ms10.control = ms6->control; 2945111206Sken bcopy(&ms10, cdb, 10); 2946111206Sken ccb->csio.cdb_len = 10; 2947111206Sken } else { 2948111206Sken struct scsi_mode_select_10 ms10; 2949111206Sken struct scsi_mode_select_6 *ms6; 2950111206Sken struct scsi_mode_header_6 *header6; 2951111206Sken struct scsi_mode_header_10 *header10; 2952111206Sken struct scsi_mode_page_header *page_header; 2953111206Sken int blk_desc_len, page_num, page_size, len; 2954111206Sken 2955111206Sken ms6 = (struct scsi_mode_select_6 *)cdb; 2956111206Sken 2957111206Sken bzero(&ms10, sizeof(ms10)); 2958111206Sken ms10.opcode = MODE_SELECT_10; 2959111206Sken ms10.byte2 = ms6->byte2; 2960111206Sken 2961111206Sken header6 = (struct scsi_mode_header_6 *)params->mode_buf; 2962111206Sken header10 = (struct scsi_mode_header_10 *)params->mode_buf; 2963111206Sken 2964111206Sken page_header = find_mode_page_6(header6); 2965111206Sken page_num = page_header->page_code; 2966111206Sken 2967111206Sken blk_desc_len = header6->blk_desc_len; 2968111206Sken 2969111206Sken page_size = cdgetpagesize(page_num); 2970111206Sken 2971111206Sken if (page_size != (page_header->page_length + 2972111206Sken sizeof(*page_header))) 2973111206Sken page_size = page_header->page_length + 2974111206Sken sizeof(*page_header); 2975111206Sken 2976111206Sken len = sizeof(*header10) + blk_desc_len + page_size; 2977111206Sken 2978111206Sken len = min(params->alloc_len, len); 2979111206Sken 2980111206Sken /* 2981111206Sken * Since the 6 byte parameter header is shorter than the 10 2982111206Sken * byte parameter header, we need to copy the actual mode 2983111206Sken * page data, and the block descriptor, if any, so things wind 2984111206Sken * up in the right place. The regions will overlap, but 2985111206Sken * bcopy() does the right thing. 2986111206Sken */ 2987111206Sken bcopy(params->mode_buf + sizeof(*header6), 2988111206Sken params->mode_buf + sizeof(*header10), 2989111206Sken len - sizeof(*header10)); 2990111206Sken 2991111206Sken /* Make sure these fields are set correctly. */ 2992111206Sken scsi_ulto2b(0, header10->data_length); 2993111206Sken header10->medium_type = 0; 2994111206Sken scsi_ulto2b(blk_desc_len, header10->blk_desc_len); 2995111206Sken 2996111206Sken ccb->csio.dxfer_len = len; 2997111206Sken 2998111206Sken scsi_ulto2b(len, ms10.length); 2999111206Sken ms10.control = ms6->control; 3000111206Sken bcopy(&ms10, cdb, 10); 3001111206Sken ccb->csio.cdb_len = 10; 3002111206Sken } 3003111206Sken 3004111206Sken frozen = (ccb->ccb_h.status & CAM_DEV_QFRZN) != 0; 3005111206Sken ccb->ccb_h.status = CAM_REQUEUE_REQ; 3006111206Sken xpt_action(ccb); 3007111206Sken if (frozen) { 3008111206Sken cam_release_devq(ccb->ccb_h.path, 3009111206Sken /*relsim_flags*/0, 3010111206Sken /*openings*/0, 3011111206Sken /*timeout*/0, 3012111206Sken /*getcount_only*/0); 3013111206Sken } 3014111206Sken 3015111206Sken return (ERESTART); 3016111206Sken} 3017111206Sken 3018111206Skenstatic int 301939213Sgibbscderror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) 302039213Sgibbs{ 302139213Sgibbs struct cd_softc *softc; 302239213Sgibbs struct cam_periph *periph; 3023237478Smav int error, error_code, sense_key, asc, ascq; 302439213Sgibbs 302539213Sgibbs periph = xpt_path_periph(ccb->ccb_h.path); 302639213Sgibbs softc = (struct cd_softc *)periph->softc; 302739213Sgibbs 3028111206Sken error = 0; 3029111206Sken 303039514Sgibbs /* 3031111206Sken * We use a status of CAM_REQ_INVALID as shorthand -- if a 6 byte 3032111206Sken * CDB comes back with this particular error, try transforming it 3033111206Sken * into the 10 byte version. 3034111206Sken */ 3035111206Sken if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INVALID) { 3036111206Sken error = cd6byteworkaround(ccb); 3037237478Smav } else if (scsi_extract_sense_ccb(ccb, 3038237478Smav &error_code, &sense_key, &asc, &ascq)) { 3039111206Sken if (sense_key == SSD_KEY_ILLEGAL_REQUEST) 3040237478Smav error = cd6byteworkaround(ccb); 3041238886Smav else if (sense_key == SSD_KEY_UNIT_ATTENTION && 3042238886Smav asc == 0x28 && ascq == 0x00) 3043238886Smav disk_media_changed(softc->disk, M_NOWAIT); 3044238886Smav else if (sense_key == SSD_KEY_NOT_READY && 3045238886Smav asc == 0x3a && (softc->flags & CD_FLAG_SAW_MEDIA)) { 3046238886Smav softc->flags &= ~CD_FLAG_SAW_MEDIA; 3047238886Smav disk_media_gone(softc->disk, M_NOWAIT); 3048238886Smav } 3049111206Sken } 3050111206Sken 3051111206Sken if (error == ERESTART) 3052111206Sken return (error); 3053111206Sken 3054111206Sken /* 305539514Sgibbs * XXX 305639514Sgibbs * Until we have a better way of doing pack validation, 305739514Sgibbs * don't treat UAs as errors. 305839514Sgibbs */ 305939514Sgibbs sense_flags |= SF_RETRY_UA; 3060278111Smav 3061278111Smav if (softc->quirks & CD_Q_RETRY_BUSY) 3062278111Smav sense_flags |= SF_RETRY_BUSY; 306339213Sgibbs return (cam_periph_error(ccb, cam_flags, sense_flags, 306439213Sgibbs &softc->saved_ccb)); 306539213Sgibbs} 306639213Sgibbs 3067238886Smavstatic void 3068238886Smavcdmediapoll(void *arg) 3069238886Smav{ 3070238886Smav struct cam_periph *periph = arg; 3071238886Smav struct cd_softc *softc = periph->softc; 3072238886Smav 3073245310Smav if (softc->state == CD_STATE_NORMAL && !softc->tur && 3074245310Smav softc->outstanding_cmds == 0) { 3075238886Smav if (cam_periph_acquire(periph) == CAM_REQ_CMP) { 3076238886Smav softc->tur = 1; 3077245310Smav xpt_schedule(periph, CAM_PRIORITY_NORMAL); 3078238886Smav } 3079238886Smav } 3080238886Smav /* Queue us up again */ 3081238886Smav if (cd_poll_period != 0) 3082238886Smav callout_schedule(&softc->mediapoll_c, cd_poll_period * hz); 3083238886Smav} 3084238886Smav 308539213Sgibbs/* 308639213Sgibbs * Read table of contents 308739213Sgibbs */ 3088352717Savgstatic int 3089352717Savgcdreadtoc(struct cam_periph *periph, u_int32_t mode, u_int32_t start, 3090111206Sken u_int8_t *data, u_int32_t len, u_int32_t sense_flags) 309139213Sgibbs{ 309239213Sgibbs u_int32_t ntoc; 309339213Sgibbs struct ccb_scsiio *csio; 309439213Sgibbs union ccb *ccb; 309539213Sgibbs int error; 309639213Sgibbs 309739213Sgibbs ntoc = len; 309839213Sgibbs error = 0; 309939213Sgibbs 3100264295Smav ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); 310139213Sgibbs 310239213Sgibbs csio = &ccb->csio; 310339213Sgibbs 3104352715Savg scsi_read_toc(csio, 3105352717Savg /* retries */ cd_retry_count, 310639213Sgibbs /* cbfcnp */ cddone, 310739213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 3108352715Savg /* byte1_flags */ (mode == CD_MSF_FORMAT) ? CD_MSF : 0, 3109352715Savg /* format */ SRTOC_FORMAT_TOC, 3110352715Savg /* track*/ start, 3111111206Sken /* data_ptr */ data, 311239213Sgibbs /* dxfer_len */ len, 311339213Sgibbs /* sense_len */ SSD_FULL_SIZE, 3114352715Savg /* timeout */ 50000); 311539213Sgibbs 311674840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 3117111206Sken /*sense_flags*/SF_RETRY_UA | sense_flags); 311839213Sgibbs 311939213Sgibbs xpt_release_ccb(ccb); 312039213Sgibbs 312139213Sgibbs return(error); 312239213Sgibbs} 312339213Sgibbs 312439213Sgibbsstatic int 3125352717Savgcdreadsubchannel(struct cam_periph *periph, u_int32_t mode, 3126352717Savg u_int32_t format, int track, 3127352717Savg struct cd_sub_channel_info *data, u_int32_t len) 312839213Sgibbs{ 312939213Sgibbs struct scsi_read_subchannel *scsi_cmd; 313039213Sgibbs struct ccb_scsiio *csio; 313139213Sgibbs union ccb *ccb; 313239213Sgibbs int error; 313339213Sgibbs 313439213Sgibbs error = 0; 313539213Sgibbs 3136264295Smav ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); 313739213Sgibbs 313839213Sgibbs csio = &ccb->csio; 313939213Sgibbs 3140352717Savg cam_fill_csio(csio, 3141352717Savg /* retries */ cd_retry_count, 314239213Sgibbs /* cbfcnp */ cddone, 314339213Sgibbs /* flags */ CAM_DIR_IN, 314439213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 314539213Sgibbs /* data_ptr */ (u_int8_t *)data, 314639213Sgibbs /* dxfer_len */ len, 314739213Sgibbs /* sense_len */ SSD_FULL_SIZE, 314839213Sgibbs sizeof(struct scsi_read_subchannel), 3149352717Savg /* timeout */ 50000); 315039213Sgibbs 315139213Sgibbs scsi_cmd = (struct scsi_read_subchannel *)&csio->cdb_io.cdb_bytes; 315239213Sgibbs bzero (scsi_cmd, sizeof(*scsi_cmd)); 315339213Sgibbs 315439213Sgibbs scsi_cmd->op_code = READ_SUBCHANNEL; 315539213Sgibbs if (mode == CD_MSF_FORMAT) 315639213Sgibbs scsi_cmd->byte1 |= CD_MSF; 315739213Sgibbs scsi_cmd->byte2 = SRS_SUBQ; 315839213Sgibbs scsi_cmd->subchan_format = format; 315939213Sgibbs scsi_cmd->track = track; 316039213Sgibbs scsi_ulto2b(len, (u_int8_t *)scsi_cmd->data_len); 316139213Sgibbs scsi_cmd->control = 0; 316239213Sgibbs 316374840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 316474840Sken /*sense_flags*/SF_RETRY_UA); 316539213Sgibbs 316639213Sgibbs xpt_release_ccb(ccb); 316739213Sgibbs 316839213Sgibbs return(error); 316939213Sgibbs} 317039213Sgibbs 317139213Sgibbs 3172111206Sken/* 3173111206Sken * All MODE_SENSE requests in the cd(4) driver MUST go through this 3174111206Sken * routine. See comments in cd6byteworkaround() for details. 3175111206Sken */ 317639213Sgibbsstatic int 3177111206Skencdgetmode(struct cam_periph *periph, struct cd_mode_params *data, 3178111206Sken u_int32_t page) 317939213Sgibbs{ 3180111206Sken struct ccb_scsiio *csio; 3181111206Sken struct cd_softc *softc; 318239213Sgibbs union ccb *ccb; 3183111206Sken int param_len; 318439213Sgibbs int error; 318539213Sgibbs 3186111206Sken softc = (struct cd_softc *)periph->softc; 3187111206Sken 3188264295Smav ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); 318939213Sgibbs 319039213Sgibbs csio = &ccb->csio; 319139213Sgibbs 3192111206Sken data->cdb_size = softc->minimum_command_size; 3193111206Sken if (data->cdb_size < 10) 3194111206Sken param_len = sizeof(struct cd_mode_data); 3195111206Sken else 3196111206Sken param_len = sizeof(struct cd_mode_data_10); 319739213Sgibbs 3198111206Sken /* Don't say we've got more room than we actually allocated */ 3199111206Sken param_len = min(param_len, data->alloc_len); 320039213Sgibbs 3201111206Sken scsi_mode_sense_len(csio, 3202203108Smav /* retries */ cd_retry_count, 3203111206Sken /* cbfcnp */ cddone, 3204111206Sken /* tag_action */ MSG_SIMPLE_Q_TAG, 3205111206Sken /* dbd */ 0, 3206111206Sken /* page_code */ SMS_PAGE_CTRL_CURRENT, 3207111206Sken /* page */ page, 3208111206Sken /* param_buf */ data->mode_buf, 3209111206Sken /* param_len */ param_len, 3210111206Sken /* minimum_cmd_size */ softc->minimum_command_size, 3211111206Sken /* sense_len */ SSD_FULL_SIZE, 3212111206Sken /* timeout */ 50000); 321339213Sgibbs 3214111206Sken /* 3215111206Sken * It would be nice not to have to do this, but there's no 3216111206Sken * available pointer in the CCB that would allow us to stuff the 3217111206Sken * mode params structure in there and retrieve it in 3218111206Sken * cd6byteworkaround(), so we can set the cdb size. The cdb size 3219111206Sken * lets the caller know what CDB size we ended up using, so they 3220111206Sken * can find the actual mode page offset. 3221111206Sken */ 3222111206Sken STAILQ_INSERT_TAIL(&softc->mode_queue, data, links); 3223111206Sken 322474840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 322574840Sken /*sense_flags*/SF_RETRY_UA); 322639213Sgibbs 322739213Sgibbs xpt_release_ccb(ccb); 322839213Sgibbs 3229111206Sken STAILQ_REMOVE(&softc->mode_queue, data, cd_mode_params, links); 3230111206Sken 3231111206Sken /* 3232111206Sken * This is a bit of belt-and-suspenders checking, but if we run 3233111206Sken * into a situation where the target sends back multiple block 3234111206Sken * descriptors, we might not have enough space in the buffer to 3235111206Sken * see the whole mode page. Better to return an error than 3236111206Sken * potentially access memory beyond our malloced region. 3237111206Sken */ 3238111206Sken if (error == 0) { 3239111206Sken u_int32_t data_len; 3240111206Sken 3241111206Sken if (data->cdb_size == 10) { 3242111206Sken struct scsi_mode_header_10 *hdr10; 3243111206Sken 3244111206Sken hdr10 = (struct scsi_mode_header_10 *)data->mode_buf; 3245111206Sken data_len = scsi_2btoul(hdr10->data_length); 3246111206Sken data_len += sizeof(hdr10->data_length); 3247111206Sken } else { 3248111206Sken struct scsi_mode_header_6 *hdr6; 3249111206Sken 3250111206Sken hdr6 = (struct scsi_mode_header_6 *)data->mode_buf; 3251111206Sken data_len = hdr6->data_length; 3252111206Sken data_len += sizeof(hdr6->data_length); 3253111206Sken } 3254111206Sken 3255111206Sken /* 3256111206Sken * Complain if there is more mode data available than we 3257111206Sken * allocated space for. This could potentially happen if 3258111206Sken * we miscalculated the page length for some reason, if the 3259111206Sken * drive returns multiple block descriptors, or if it sets 3260111206Sken * the data length incorrectly. 3261111206Sken */ 3262111206Sken if (data_len > data->alloc_len) { 3263164906Smjacob xpt_print(periph->path, "allocated modepage %d length " 3264164906Smjacob "%d < returned length %d\n", page, data->alloc_len, 3265164906Smjacob data_len); 3266111206Sken error = ENOSPC; 3267111206Sken } 3268111206Sken } 3269111206Sken return (error); 327039213Sgibbs} 327139213Sgibbs 3272111206Sken/* 3273111206Sken * All MODE_SELECT requests in the cd(4) driver MUST go through this 3274111206Sken * routine. See comments in cd6byteworkaround() for details. 3275111206Sken */ 327639213Sgibbsstatic int 3277111206Skencdsetmode(struct cam_periph *periph, struct cd_mode_params *data) 327839213Sgibbs{ 3279111206Sken struct ccb_scsiio *csio; 3280111206Sken struct cd_softc *softc; 328139213Sgibbs union ccb *ccb; 3282111206Sken int cdb_size, param_len; 328339213Sgibbs int error; 328439213Sgibbs 3285111206Sken softc = (struct cd_softc *)periph->softc; 3286111206Sken 3287264295Smav ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); 328839213Sgibbs 328939213Sgibbs csio = &ccb->csio; 329039213Sgibbs 329139213Sgibbs error = 0; 329239213Sgibbs 329339213Sgibbs /* 3294111206Sken * If the data is formatted for the 10 byte version of the mode 3295111206Sken * select parameter list, we need to use the 10 byte CDB. 3296111206Sken * Otherwise, we use whatever the stored minimum command size. 329739213Sgibbs */ 3298111206Sken if (data->cdb_size == 10) 3299111206Sken cdb_size = data->cdb_size; 3300111206Sken else 3301111206Sken cdb_size = softc->minimum_command_size; 330239213Sgibbs 3303111206Sken if (cdb_size >= 10) { 3304111206Sken struct scsi_mode_header_10 *mode_header; 3305111206Sken u_int32_t data_len; 3306111206Sken 3307111206Sken mode_header = (struct scsi_mode_header_10 *)data->mode_buf; 3308111206Sken 3309111206Sken data_len = scsi_2btoul(mode_header->data_length); 3310111206Sken 3311111206Sken scsi_ulto2b(0, mode_header->data_length); 3312111206Sken /* 3313111206Sken * SONY drives do not allow a mode select with a medium_type 3314111206Sken * value that has just been returned by a mode sense; use a 3315111206Sken * medium_type of 0 (Default) instead. 3316111206Sken */ 3317111206Sken mode_header->medium_type = 0; 3318111206Sken 3319111206Sken /* 3320111206Sken * Pass back whatever the drive passed to us, plus the size 3321111206Sken * of the data length field. 3322111206Sken */ 3323111206Sken param_len = data_len + sizeof(mode_header->data_length); 3324111206Sken 3325111206Sken } else { 3326111206Sken struct scsi_mode_header_6 *mode_header; 3327111206Sken 3328111206Sken mode_header = (struct scsi_mode_header_6 *)data->mode_buf; 3329111206Sken 3330111206Sken param_len = mode_header->data_length + 1; 3331111206Sken 3332111206Sken mode_header->data_length = 0; 3333111206Sken /* 3334111206Sken * SONY drives do not allow a mode select with a medium_type 3335111206Sken * value that has just been returned by a mode sense; use a 3336111206Sken * medium_type of 0 (Default) instead. 3337111206Sken */ 3338111206Sken mode_header->medium_type = 0; 3339111206Sken } 3340111206Sken 3341111206Sken /* Don't say we've got more room than we actually allocated */ 3342111206Sken param_len = min(param_len, data->alloc_len); 3343111206Sken 3344111206Sken scsi_mode_select_len(csio, 3345203108Smav /* retries */ cd_retry_count, 3346111206Sken /* cbfcnp */ cddone, 3347111206Sken /* tag_action */ MSG_SIMPLE_Q_TAG, 3348111206Sken /* scsi_page_fmt */ 1, 3349111206Sken /* save_pages */ 0, 3350111206Sken /* param_buf */ data->mode_buf, 3351111206Sken /* param_len */ param_len, 3352111206Sken /* minimum_cmd_size */ cdb_size, 3353111206Sken /* sense_len */ SSD_FULL_SIZE, 3354111206Sken /* timeout */ 50000); 3355111206Sken 3356111206Sken /* See comments in cdgetmode() and cd6byteworkaround(). */ 3357111206Sken STAILQ_INSERT_TAIL(&softc->mode_queue, data, links); 3358111206Sken 335974840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 336074840Sken /*sense_flags*/SF_RETRY_UA); 336139213Sgibbs 336239213Sgibbs xpt_release_ccb(ccb); 336339213Sgibbs 3364111206Sken STAILQ_REMOVE(&softc->mode_queue, data, cd_mode_params, links); 3365111206Sken 3366111206Sken return (error); 336739213Sgibbs} 336839213Sgibbs 336939213Sgibbs 3370352717Savgstatic int 337139213Sgibbscdplay(struct cam_periph *periph, u_int32_t blk, u_int32_t len) 337239213Sgibbs{ 337339531Sken struct ccb_scsiio *csio; 337439213Sgibbs union ccb *ccb; 337539213Sgibbs int error; 337639531Sken u_int8_t cdb_len; 337739213Sgibbs 337839213Sgibbs error = 0; 3379264295Smav ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); 338039213Sgibbs csio = &ccb->csio; 338139531Sken /* 338239531Sken * Use the smallest possible command to perform the operation. 338339531Sken */ 338439531Sken if ((len & 0xffff0000) == 0) { 338539531Sken /* 338639531Sken * We can fit in a 10 byte cdb. 338739531Sken */ 338839531Sken struct scsi_play_10 *scsi_cmd; 338939213Sgibbs 339039531Sken scsi_cmd = (struct scsi_play_10 *)&csio->cdb_io.cdb_bytes; 339139531Sken bzero (scsi_cmd, sizeof(*scsi_cmd)); 339239531Sken scsi_cmd->op_code = PLAY_10; 339339531Sken scsi_ulto4b(blk, (u_int8_t *)scsi_cmd->blk_addr); 339439531Sken scsi_ulto2b(len, (u_int8_t *)scsi_cmd->xfer_len); 339539531Sken cdb_len = sizeof(*scsi_cmd); 339639531Sken } else { 339739531Sken struct scsi_play_12 *scsi_cmd; 339839213Sgibbs 339939531Sken scsi_cmd = (struct scsi_play_12 *)&csio->cdb_io.cdb_bytes; 340039531Sken bzero (scsi_cmd, sizeof(*scsi_cmd)); 340139531Sken scsi_cmd->op_code = PLAY_12; 340239531Sken scsi_ulto4b(blk, (u_int8_t *)scsi_cmd->blk_addr); 340339531Sken scsi_ulto4b(len, (u_int8_t *)scsi_cmd->xfer_len); 340439531Sken cdb_len = sizeof(*scsi_cmd); 340539531Sken } 340639531Sken cam_fill_csio(csio, 3407203108Smav /*retries*/ cd_retry_count, 340839531Sken cddone, 340939531Sken /*flags*/CAM_DIR_NONE, 341039531Sken MSG_SIMPLE_Q_TAG, 341139531Sken /*dataptr*/NULL, 341239531Sken /*datalen*/0, 341339531Sken /*sense_len*/SSD_FULL_SIZE, 341439531Sken cdb_len, 341539531Sken /*timeout*/50 * 1000); 341639213Sgibbs 341774840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 341874840Sken /*sense_flags*/SF_RETRY_UA); 341939213Sgibbs 342039213Sgibbs xpt_release_ccb(ccb); 342139213Sgibbs 342239213Sgibbs return(error); 342339213Sgibbs} 342439213Sgibbs 342539213Sgibbsstatic int 342639213Sgibbscdplaymsf(struct cam_periph *periph, u_int32_t startm, u_int32_t starts, 342739213Sgibbs u_int32_t startf, u_int32_t endm, u_int32_t ends, u_int32_t endf) 342839213Sgibbs{ 342939213Sgibbs struct scsi_play_msf *scsi_cmd; 343039213Sgibbs struct ccb_scsiio *csio; 343139213Sgibbs union ccb *ccb; 343239213Sgibbs int error; 343339213Sgibbs 343439213Sgibbs error = 0; 343539213Sgibbs 3436264295Smav ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); 343739213Sgibbs 343839213Sgibbs csio = &ccb->csio; 343939213Sgibbs 3440352717Savg cam_fill_csio(csio, 3441352717Savg /* retries */ cd_retry_count, 344239213Sgibbs /* cbfcnp */ cddone, 344339531Sken /* flags */ CAM_DIR_NONE, 344439213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 344539213Sgibbs /* data_ptr */ NULL, 344639213Sgibbs /* dxfer_len */ 0, 344739213Sgibbs /* sense_len */ SSD_FULL_SIZE, 344839213Sgibbs sizeof(struct scsi_play_msf), 3449352717Savg /* timeout */ 50000); 345039213Sgibbs 345139213Sgibbs scsi_cmd = (struct scsi_play_msf *)&csio->cdb_io.cdb_bytes; 345239213Sgibbs bzero (scsi_cmd, sizeof(*scsi_cmd)); 345339213Sgibbs 345439213Sgibbs scsi_cmd->op_code = PLAY_MSF; 345539213Sgibbs scsi_cmd->start_m = startm; 345639213Sgibbs scsi_cmd->start_s = starts; 345739213Sgibbs scsi_cmd->start_f = startf; 345839213Sgibbs scsi_cmd->end_m = endm; 345939213Sgibbs scsi_cmd->end_s = ends; 3460352717Savg scsi_cmd->end_f = endf; 346139213Sgibbs 346274840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 346374840Sken /*sense_flags*/SF_RETRY_UA); 3464352717Savg 346539213Sgibbs xpt_release_ccb(ccb); 346639213Sgibbs 346739213Sgibbs return(error); 346839213Sgibbs} 346939213Sgibbs 347039213Sgibbs 347139213Sgibbsstatic int 347239213Sgibbscdplaytracks(struct cam_periph *periph, u_int32_t strack, u_int32_t sindex, 347339213Sgibbs u_int32_t etrack, u_int32_t eindex) 347439213Sgibbs{ 347539213Sgibbs struct scsi_play_track *scsi_cmd; 347639213Sgibbs struct ccb_scsiio *csio; 347739213Sgibbs union ccb *ccb; 347839213Sgibbs int error; 347939213Sgibbs 348039213Sgibbs error = 0; 348139213Sgibbs 3482264295Smav ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); 348339213Sgibbs 348439213Sgibbs csio = &ccb->csio; 348539213Sgibbs 3486352717Savg cam_fill_csio(csio, 3487352717Savg /* retries */ cd_retry_count, 348839213Sgibbs /* cbfcnp */ cddone, 348939531Sken /* flags */ CAM_DIR_NONE, 349039213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 349139213Sgibbs /* data_ptr */ NULL, 349239213Sgibbs /* dxfer_len */ 0, 349339213Sgibbs /* sense_len */ SSD_FULL_SIZE, 349439213Sgibbs sizeof(struct scsi_play_track), 3495352717Savg /* timeout */ 50000); 349639213Sgibbs 349739213Sgibbs scsi_cmd = (struct scsi_play_track *)&csio->cdb_io.cdb_bytes; 349839213Sgibbs bzero (scsi_cmd, sizeof(*scsi_cmd)); 349939213Sgibbs 350039213Sgibbs scsi_cmd->op_code = PLAY_TRACK; 350139213Sgibbs scsi_cmd->start_track = strack; 350239213Sgibbs scsi_cmd->start_index = sindex; 350339213Sgibbs scsi_cmd->end_track = etrack; 350439213Sgibbs scsi_cmd->end_index = eindex; 350539213Sgibbs 350674840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 350774840Sken /*sense_flags*/SF_RETRY_UA); 350839213Sgibbs 350939213Sgibbs xpt_release_ccb(ccb); 351039213Sgibbs 351139213Sgibbs return(error); 351239213Sgibbs} 351339213Sgibbs 351439213Sgibbsstatic int 351539213Sgibbscdpause(struct cam_periph *periph, u_int32_t go) 351639213Sgibbs{ 351739213Sgibbs struct scsi_pause *scsi_cmd; 351839213Sgibbs struct ccb_scsiio *csio; 351939213Sgibbs union ccb *ccb; 352039213Sgibbs int error; 352139213Sgibbs 352239213Sgibbs error = 0; 352339213Sgibbs 3524264295Smav ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); 352539213Sgibbs 352639213Sgibbs csio = &ccb->csio; 352739213Sgibbs 3528352717Savg cam_fill_csio(csio, 3529352717Savg /* retries */ cd_retry_count, 353039213Sgibbs /* cbfcnp */ cddone, 353139531Sken /* flags */ CAM_DIR_NONE, 353239213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 353339213Sgibbs /* data_ptr */ NULL, 353439213Sgibbs /* dxfer_len */ 0, 353539213Sgibbs /* sense_len */ SSD_FULL_SIZE, 353639213Sgibbs sizeof(struct scsi_pause), 3537352717Savg /* timeout */ 50000); 353839213Sgibbs 353939213Sgibbs scsi_cmd = (struct scsi_pause *)&csio->cdb_io.cdb_bytes; 354039213Sgibbs bzero (scsi_cmd, sizeof(*scsi_cmd)); 354139213Sgibbs 354239213Sgibbs scsi_cmd->op_code = PAUSE; 354339213Sgibbs scsi_cmd->resume = go; 354439213Sgibbs 354574840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 354674840Sken /*sense_flags*/SF_RETRY_UA); 354739213Sgibbs 354839213Sgibbs xpt_release_ccb(ccb); 354939213Sgibbs 355039213Sgibbs return(error); 355139213Sgibbs} 355239213Sgibbs 355339213Sgibbsstatic int 3554111206Skencdstartunit(struct cam_periph *periph, int load) 355539213Sgibbs{ 355639213Sgibbs union ccb *ccb; 355739213Sgibbs int error; 355839213Sgibbs 355939213Sgibbs error = 0; 356039213Sgibbs 3561264295Smav ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); 356239213Sgibbs 356339213Sgibbs scsi_start_stop(&ccb->csio, 3564203108Smav /* retries */ cd_retry_count, 356539213Sgibbs /* cbfcnp */ cddone, 356639213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 356739213Sgibbs /* start */ TRUE, 3568111206Sken /* load_eject */ load, 356939213Sgibbs /* immediate */ FALSE, 357039213Sgibbs /* sense_len */ SSD_FULL_SIZE, 357139213Sgibbs /* timeout */ 50000); 357239213Sgibbs 357374840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 357474840Sken /*sense_flags*/SF_RETRY_UA); 357539213Sgibbs 357639213Sgibbs xpt_release_ccb(ccb); 357739213Sgibbs 357839213Sgibbs return(error); 357939213Sgibbs} 358039213Sgibbs 358139213Sgibbsstatic int 358239213Sgibbscdstopunit(struct cam_periph *periph, u_int32_t eject) 358339213Sgibbs{ 358439213Sgibbs union ccb *ccb; 358539213Sgibbs int error; 358639213Sgibbs 358739213Sgibbs error = 0; 358839213Sgibbs 3589264295Smav ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); 359039213Sgibbs 359139213Sgibbs scsi_start_stop(&ccb->csio, 3592203108Smav /* retries */ cd_retry_count, 359339213Sgibbs /* cbfcnp */ cddone, 359439213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 359539213Sgibbs /* start */ FALSE, 359639213Sgibbs /* load_eject */ eject, 359739213Sgibbs /* immediate */ FALSE, 359839213Sgibbs /* sense_len */ SSD_FULL_SIZE, 359939213Sgibbs /* timeout */ 50000); 360039213Sgibbs 360174840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 360274840Sken /*sense_flags*/SF_RETRY_UA); 360339213Sgibbs 360439213Sgibbs xpt_release_ccb(ccb); 360539213Sgibbs 360639213Sgibbs return(error); 360739213Sgibbs} 360860422Sken 360960422Skenstatic int 3610105421Snjlcdsetspeed(struct cam_periph *periph, u_int32_t rdspeed, u_int32_t wrspeed) 3611105421Snjl{ 3612105421Snjl struct scsi_set_speed *scsi_cmd; 3613105421Snjl struct ccb_scsiio *csio; 3614105421Snjl union ccb *ccb; 3615105421Snjl int error; 3616105421Snjl 3617105421Snjl error = 0; 3618264295Smav ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); 3619105421Snjl csio = &ccb->csio; 3620105421Snjl 3621107193Snjl /* Preserve old behavior: units in multiples of CDROM speed */ 3622107193Snjl if (rdspeed < 177) 3623107193Snjl rdspeed *= 177; 3624107193Snjl if (wrspeed < 177) 3625107193Snjl wrspeed *= 177; 3626107193Snjl 3627105421Snjl cam_fill_csio(csio, 3628203108Smav /* retries */ cd_retry_count, 3629105421Snjl /* cbfcnp */ cddone, 3630105421Snjl /* flags */ CAM_DIR_NONE, 3631105421Snjl /* tag_action */ MSG_SIMPLE_Q_TAG, 3632105421Snjl /* data_ptr */ NULL, 3633105421Snjl /* dxfer_len */ 0, 3634105421Snjl /* sense_len */ SSD_FULL_SIZE, 3635105421Snjl sizeof(struct scsi_set_speed), 3636352717Savg /* timeout */ 50000); 3637105421Snjl 3638105421Snjl scsi_cmd = (struct scsi_set_speed *)&csio->cdb_io.cdb_bytes; 3639105421Snjl bzero(scsi_cmd, sizeof(*scsi_cmd)); 3640105421Snjl 3641105421Snjl scsi_cmd->opcode = SET_CD_SPEED; 3642105421Snjl scsi_ulto2b(rdspeed, scsi_cmd->readspeed); 3643105421Snjl scsi_ulto2b(wrspeed, scsi_cmd->writespeed); 3644105421Snjl 3645105421Snjl error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 3646105421Snjl /*sense_flags*/SF_RETRY_UA); 3647105421Snjl 3648105421Snjl xpt_release_ccb(ccb); 3649105421Snjl 3650105421Snjl return(error); 3651105421Snjl} 3652105421Snjl 3653105421Snjlstatic int 365460422Skencdreportkey(struct cam_periph *periph, struct dvd_authinfo *authinfo) 365560422Sken{ 365660422Sken union ccb *ccb; 365760422Sken u_int8_t *databuf; 365860422Sken u_int32_t lba; 365960422Sken int error; 366060422Sken int length; 366160422Sken 366260422Sken error = 0; 366360422Sken databuf = NULL; 366460422Sken lba = 0; 366560422Sken 366660422Sken switch (authinfo->format) { 366760422Sken case DVD_REPORT_AGID: 366860422Sken length = sizeof(struct scsi_report_key_data_agid); 366960422Sken break; 367060422Sken case DVD_REPORT_CHALLENGE: 367160422Sken length = sizeof(struct scsi_report_key_data_challenge); 367260422Sken break; 367360422Sken case DVD_REPORT_KEY1: 367460422Sken length = sizeof(struct scsi_report_key_data_key1_key2); 367560422Sken break; 367660422Sken case DVD_REPORT_TITLE_KEY: 367760422Sken length = sizeof(struct scsi_report_key_data_title); 367860422Sken /* The lba field is only set for the title key */ 367960422Sken lba = authinfo->lba; 368060422Sken break; 368160422Sken case DVD_REPORT_ASF: 368260422Sken length = sizeof(struct scsi_report_key_data_asf); 368360422Sken break; 368460422Sken case DVD_REPORT_RPC: 368560422Sken length = sizeof(struct scsi_report_key_data_rpc); 368660422Sken break; 368760422Sken case DVD_INVALIDATE_AGID: 368860422Sken length = 0; 368960422Sken break; 369060422Sken default: 3691200036Sscottl return (EINVAL); 369260422Sken } 369360422Sken 369460422Sken if (length != 0) { 3695111119Simp databuf = malloc(length, M_DEVBUF, M_WAITOK | M_ZERO); 369660422Sken } else 369760422Sken databuf = NULL; 369860422Sken 3699200036Sscottl cam_periph_lock(periph); 3700264295Smav ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); 370160422Sken 370260422Sken scsi_report_key(&ccb->csio, 3703203108Smav /* retries */ cd_retry_count, 370460422Sken /* cbfcnp */ cddone, 370560422Sken /* tag_action */ MSG_SIMPLE_Q_TAG, 370660422Sken /* lba */ lba, 370760422Sken /* agid */ authinfo->agid, 370860422Sken /* key_format */ authinfo->format, 370960422Sken /* data_ptr */ databuf, 371060422Sken /* dxfer_len */ length, 371160422Sken /* sense_len */ SSD_FULL_SIZE, 371260422Sken /* timeout */ 50000); 371360422Sken 371474840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 371574840Sken /*sense_flags*/SF_RETRY_UA); 371660422Sken 371760422Sken if (error != 0) 371860422Sken goto bailout; 371960422Sken 372060422Sken if (ccb->csio.resid != 0) { 3721164906Smjacob xpt_print(periph->path, "warning, residual for report key " 3722164906Smjacob "command is %d\n", ccb->csio.resid); 372360422Sken } 372460422Sken 372560422Sken switch(authinfo->format) { 372660422Sken case DVD_REPORT_AGID: { 372760422Sken struct scsi_report_key_data_agid *agid_data; 372860422Sken 372960422Sken agid_data = (struct scsi_report_key_data_agid *)databuf; 373060422Sken 373160422Sken authinfo->agid = (agid_data->agid & RKD_AGID_MASK) >> 373260422Sken RKD_AGID_SHIFT; 373360422Sken break; 373460422Sken } 373560422Sken case DVD_REPORT_CHALLENGE: { 373660422Sken struct scsi_report_key_data_challenge *chal_data; 373760422Sken 373860422Sken chal_data = (struct scsi_report_key_data_challenge *)databuf; 373960422Sken 374060422Sken bcopy(chal_data->challenge_key, authinfo->keychal, 374160422Sken min(sizeof(chal_data->challenge_key), 374260422Sken sizeof(authinfo->keychal))); 374360422Sken break; 374460422Sken } 374560422Sken case DVD_REPORT_KEY1: { 374660422Sken struct scsi_report_key_data_key1_key2 *key1_data; 374760422Sken 374860422Sken key1_data = (struct scsi_report_key_data_key1_key2 *)databuf; 374960422Sken 375060422Sken bcopy(key1_data->key1, authinfo->keychal, 375160422Sken min(sizeof(key1_data->key1), sizeof(authinfo->keychal))); 375260422Sken break; 375360422Sken } 375460422Sken case DVD_REPORT_TITLE_KEY: { 375560422Sken struct scsi_report_key_data_title *title_data; 375660422Sken 375760422Sken title_data = (struct scsi_report_key_data_title *)databuf; 375860422Sken 375960422Sken authinfo->cpm = (title_data->byte0 & RKD_TITLE_CPM) >> 376060422Sken RKD_TITLE_CPM_SHIFT; 376160422Sken authinfo->cp_sec = (title_data->byte0 & RKD_TITLE_CP_SEC) >> 376260422Sken RKD_TITLE_CP_SEC_SHIFT; 376360422Sken authinfo->cgms = (title_data->byte0 & RKD_TITLE_CMGS_MASK) >> 376460422Sken RKD_TITLE_CMGS_SHIFT; 376560422Sken bcopy(title_data->title_key, authinfo->keychal, 376660422Sken min(sizeof(title_data->title_key), 376760422Sken sizeof(authinfo->keychal))); 376860422Sken break; 376960422Sken } 377060422Sken case DVD_REPORT_ASF: { 377160422Sken struct scsi_report_key_data_asf *asf_data; 377260422Sken 377360422Sken asf_data = (struct scsi_report_key_data_asf *)databuf; 377460422Sken 377560422Sken authinfo->asf = asf_data->success & RKD_ASF_SUCCESS; 377660422Sken break; 377760422Sken } 377860422Sken case DVD_REPORT_RPC: { 377960422Sken struct scsi_report_key_data_rpc *rpc_data; 378060422Sken 378160422Sken rpc_data = (struct scsi_report_key_data_rpc *)databuf; 378260422Sken 378360422Sken authinfo->reg_type = (rpc_data->byte4 & RKD_RPC_TYPE_MASK) >> 378460422Sken RKD_RPC_TYPE_SHIFT; 378560422Sken authinfo->vend_rsts = 378660422Sken (rpc_data->byte4 & RKD_RPC_VENDOR_RESET_MASK) >> 378760422Sken RKD_RPC_VENDOR_RESET_SHIFT; 378860422Sken authinfo->user_rsts = rpc_data->byte4 & RKD_RPC_USER_RESET_MASK; 378971752Sken authinfo->region = rpc_data->region_mask; 379071752Sken authinfo->rpc_scheme = rpc_data->rpc_scheme1; 379160422Sken break; 379260422Sken } 379360422Sken case DVD_INVALIDATE_AGID: 379460422Sken break; 379560422Sken default: 379660422Sken /* This should be impossible, since we checked above */ 379760422Sken error = EINVAL; 379860422Sken goto bailout; 379960422Sken break; /* NOTREACHED */ 380060422Sken } 3801200036Sscottl 380260422Skenbailout: 3803200036Sscottl xpt_release_ccb(ccb); 3804200036Sscottl cam_periph_unlock(periph); 3805200036Sscottl 380660422Sken if (databuf != NULL) 380760422Sken free(databuf, M_DEVBUF); 380860422Sken 380960422Sken return(error); 381060422Sken} 381160422Sken 381260422Skenstatic int 381360422Skencdsendkey(struct cam_periph *periph, struct dvd_authinfo *authinfo) 381460422Sken{ 381560422Sken union ccb *ccb; 381660422Sken u_int8_t *databuf; 381760422Sken int length; 381860422Sken int error; 381960422Sken 382060422Sken error = 0; 382160422Sken databuf = NULL; 382260422Sken 382360422Sken switch(authinfo->format) { 382460422Sken case DVD_SEND_CHALLENGE: { 382560422Sken struct scsi_report_key_data_challenge *challenge_data; 382660422Sken 382760422Sken length = sizeof(*challenge_data); 382860422Sken 3829111119Simp challenge_data = malloc(length, M_DEVBUF, M_WAITOK | M_ZERO); 383060422Sken 383160422Sken databuf = (u_int8_t *)challenge_data; 383260422Sken 383360422Sken scsi_ulto2b(length - sizeof(challenge_data->data_len), 383460422Sken challenge_data->data_len); 383560422Sken 383660422Sken bcopy(authinfo->keychal, challenge_data->challenge_key, 383760422Sken min(sizeof(authinfo->keychal), 383860422Sken sizeof(challenge_data->challenge_key))); 383960422Sken break; 384060422Sken } 384160422Sken case DVD_SEND_KEY2: { 384260422Sken struct scsi_report_key_data_key1_key2 *key2_data; 384360422Sken 384460422Sken length = sizeof(*key2_data); 384560422Sken 3846111119Simp key2_data = malloc(length, M_DEVBUF, M_WAITOK | M_ZERO); 384760422Sken 384860422Sken databuf = (u_int8_t *)key2_data; 384960422Sken 385060422Sken scsi_ulto2b(length - sizeof(key2_data->data_len), 385160422Sken key2_data->data_len); 385260422Sken 385360422Sken bcopy(authinfo->keychal, key2_data->key1, 385460422Sken min(sizeof(authinfo->keychal), sizeof(key2_data->key1))); 385560422Sken 385660422Sken break; 385760422Sken } 385860422Sken case DVD_SEND_RPC: { 385960422Sken struct scsi_send_key_data_rpc *rpc_data; 386060422Sken 386160422Sken length = sizeof(*rpc_data); 386260422Sken 3863111119Simp rpc_data = malloc(length, M_DEVBUF, M_WAITOK | M_ZERO); 386460422Sken 386560422Sken databuf = (u_int8_t *)rpc_data; 386660422Sken 386760422Sken scsi_ulto2b(length - sizeof(rpc_data->data_len), 386860422Sken rpc_data->data_len); 386960422Sken 387060422Sken rpc_data->region_code = authinfo->region; 387160422Sken break; 387260422Sken } 387360422Sken default: 3874200036Sscottl return (EINVAL); 387560422Sken } 387660422Sken 3877200036Sscottl cam_periph_lock(periph); 3878264295Smav ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); 3879200036Sscottl 388060422Sken scsi_send_key(&ccb->csio, 3881203108Smav /* retries */ cd_retry_count, 388260422Sken /* cbfcnp */ cddone, 388360422Sken /* tag_action */ MSG_SIMPLE_Q_TAG, 388460422Sken /* agid */ authinfo->agid, 388560422Sken /* key_format */ authinfo->format, 388660422Sken /* data_ptr */ databuf, 388760422Sken /* dxfer_len */ length, 388860422Sken /* sense_len */ SSD_FULL_SIZE, 388960422Sken /* timeout */ 50000); 389060422Sken 389174840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 389274840Sken /*sense_flags*/SF_RETRY_UA); 389360422Sken 3894200036Sscottl xpt_release_ccb(ccb); 3895200036Sscottl cam_periph_unlock(periph); 389660422Sken 389760422Sken if (databuf != NULL) 389860422Sken free(databuf, M_DEVBUF); 389960422Sken 390060422Sken return(error); 390160422Sken} 390260422Sken 390360422Skenstatic int 390460422Skencdreaddvdstructure(struct cam_periph *periph, struct dvd_struct *dvdstruct) 390560422Sken{ 390660422Sken union ccb *ccb; 390760422Sken u_int8_t *databuf; 390860422Sken u_int32_t address; 390960422Sken int error; 391060422Sken int length; 391160422Sken 391260422Sken error = 0; 391360422Sken databuf = NULL; 391460422Sken /* The address is reserved for many of the formats */ 391560422Sken address = 0; 391660422Sken 391760422Sken switch(dvdstruct->format) { 391860422Sken case DVD_STRUCT_PHYSICAL: 391960422Sken length = sizeof(struct scsi_read_dvd_struct_data_physical); 392060422Sken break; 392160422Sken case DVD_STRUCT_COPYRIGHT: 392260422Sken length = sizeof(struct scsi_read_dvd_struct_data_copyright); 392360422Sken break; 392460422Sken case DVD_STRUCT_DISCKEY: 392560422Sken length = sizeof(struct scsi_read_dvd_struct_data_disc_key); 392660422Sken break; 392760422Sken case DVD_STRUCT_BCA: 392860422Sken length = sizeof(struct scsi_read_dvd_struct_data_bca); 392960422Sken break; 393060422Sken case DVD_STRUCT_MANUFACT: 393160422Sken length = sizeof(struct scsi_read_dvd_struct_data_manufacturer); 393260422Sken break; 393360422Sken case DVD_STRUCT_CMI: 3934200036Sscottl return (ENODEV); 393560422Sken case DVD_STRUCT_PROTDISCID: 393660422Sken length = sizeof(struct scsi_read_dvd_struct_data_prot_discid); 393760422Sken break; 393860422Sken case DVD_STRUCT_DISCKEYBLOCK: 393960422Sken length = sizeof(struct scsi_read_dvd_struct_data_disc_key_blk); 394060422Sken break; 394160422Sken case DVD_STRUCT_DDS: 394260422Sken length = sizeof(struct scsi_read_dvd_struct_data_dds); 394360422Sken break; 394460422Sken case DVD_STRUCT_MEDIUM_STAT: 394560422Sken length = sizeof(struct scsi_read_dvd_struct_data_medium_status); 394660422Sken break; 394760422Sken case DVD_STRUCT_SPARE_AREA: 394860422Sken length = sizeof(struct scsi_read_dvd_struct_data_spare_area); 394960422Sken break; 395060422Sken case DVD_STRUCT_RMD_LAST: 3951200036Sscottl return (ENODEV); 395260422Sken case DVD_STRUCT_RMD_RMA: 3953200036Sscottl return (ENODEV); 395460422Sken case DVD_STRUCT_PRERECORDED: 395560422Sken length = sizeof(struct scsi_read_dvd_struct_data_leadin); 395660422Sken break; 395760422Sken case DVD_STRUCT_UNIQUEID: 395860422Sken length = sizeof(struct scsi_read_dvd_struct_data_disc_id); 395960422Sken break; 396060422Sken case DVD_STRUCT_DCB: 3961200036Sscottl return (ENODEV); 396260422Sken case DVD_STRUCT_LIST: 396360422Sken /* 396460422Sken * This is the maximum allocation length for the READ DVD 396560422Sken * STRUCTURE command. There's nothing in the MMC3 spec 396660422Sken * that indicates a limit in the amount of data that can 396760422Sken * be returned from this call, other than the limits 396860422Sken * imposed by the 2-byte length variables. 396960422Sken */ 397060422Sken length = 65535; 397160422Sken break; 397260422Sken default: 3973200036Sscottl return (EINVAL); 397460422Sken } 397560422Sken 397660422Sken if (length != 0) { 3977111119Simp databuf = malloc(length, M_DEVBUF, M_WAITOK | M_ZERO); 397860422Sken } else 397960422Sken databuf = NULL; 398060422Sken 3981200036Sscottl cam_periph_lock(periph); 3982264295Smav ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); 3983200036Sscottl 398460422Sken scsi_read_dvd_structure(&ccb->csio, 3985203108Smav /* retries */ cd_retry_count, 398660422Sken /* cbfcnp */ cddone, 398760422Sken /* tag_action */ MSG_SIMPLE_Q_TAG, 398860422Sken /* lba */ address, 398960422Sken /* layer_number */ dvdstruct->layer_num, 399060422Sken /* key_format */ dvdstruct->format, 399160422Sken /* agid */ dvdstruct->agid, 399260422Sken /* data_ptr */ databuf, 399360422Sken /* dxfer_len */ length, 399460422Sken /* sense_len */ SSD_FULL_SIZE, 399560422Sken /* timeout */ 50000); 399660422Sken 399774840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 399874840Sken /*sense_flags*/SF_RETRY_UA); 399960422Sken 400060422Sken if (error != 0) 400160422Sken goto bailout; 400260422Sken 400360422Sken switch(dvdstruct->format) { 400460422Sken case DVD_STRUCT_PHYSICAL: { 400560422Sken struct scsi_read_dvd_struct_data_layer_desc *inlayer; 400660422Sken struct dvd_layer *outlayer; 400760422Sken struct scsi_read_dvd_struct_data_physical *phys_data; 400860422Sken 400960422Sken phys_data = 401060422Sken (struct scsi_read_dvd_struct_data_physical *)databuf; 401160422Sken inlayer = &phys_data->layer_desc; 401260422Sken outlayer = (struct dvd_layer *)&dvdstruct->data; 401360422Sken 401460422Sken dvdstruct->length = sizeof(*inlayer); 401560422Sken 401660422Sken outlayer->book_type = (inlayer->book_type_version & 401760422Sken RDSD_BOOK_TYPE_MASK) >> RDSD_BOOK_TYPE_SHIFT; 401860422Sken outlayer->book_version = (inlayer->book_type_version & 401960422Sken RDSD_BOOK_VERSION_MASK); 402060422Sken outlayer->disc_size = (inlayer->disc_size_max_rate & 402160422Sken RDSD_DISC_SIZE_MASK) >> RDSD_DISC_SIZE_SHIFT; 402260422Sken outlayer->max_rate = (inlayer->disc_size_max_rate & 402360422Sken RDSD_MAX_RATE_MASK); 402460422Sken outlayer->nlayers = (inlayer->layer_info & 402560422Sken RDSD_NUM_LAYERS_MASK) >> RDSD_NUM_LAYERS_SHIFT; 402660422Sken outlayer->track_path = (inlayer->layer_info & 402760422Sken RDSD_TRACK_PATH_MASK) >> RDSD_TRACK_PATH_SHIFT; 402860422Sken outlayer->layer_type = (inlayer->layer_info & 402960422Sken RDSD_LAYER_TYPE_MASK); 403060422Sken outlayer->linear_density = (inlayer->density & 403160422Sken RDSD_LIN_DENSITY_MASK) >> RDSD_LIN_DENSITY_SHIFT; 403260422Sken outlayer->track_density = (inlayer->density & 403360422Sken RDSD_TRACK_DENSITY_MASK); 403460422Sken outlayer->bca = (inlayer->bca & RDSD_BCA_MASK) >> 403560422Sken RDSD_BCA_SHIFT; 403660422Sken outlayer->start_sector = scsi_3btoul(inlayer->main_data_start); 403760422Sken outlayer->end_sector = scsi_3btoul(inlayer->main_data_end); 403860422Sken outlayer->end_sector_l0 = 403960422Sken scsi_3btoul(inlayer->end_sector_layer0); 404060422Sken break; 404160422Sken } 404260422Sken case DVD_STRUCT_COPYRIGHT: { 404360422Sken struct scsi_read_dvd_struct_data_copyright *copy_data; 404460422Sken 404560422Sken copy_data = (struct scsi_read_dvd_struct_data_copyright *) 404660422Sken databuf; 404760422Sken 404860422Sken dvdstruct->cpst = copy_data->cps_type; 404960422Sken dvdstruct->rmi = copy_data->region_info; 405060422Sken dvdstruct->length = 0; 405160422Sken 405260422Sken break; 405360422Sken } 405460422Sken default: 405560422Sken /* 405660422Sken * Tell the user what the overall length is, no matter 405760422Sken * what we can actually fit in the data buffer. 405860422Sken */ 4059352717Savg dvdstruct->length = length - ccb->csio.resid - 406060422Sken sizeof(struct scsi_read_dvd_struct_data_header); 406160422Sken 406260422Sken /* 406360422Sken * But only actually copy out the smaller of what we read 406460422Sken * in or what the structure can take. 406560422Sken */ 406660422Sken bcopy(databuf + sizeof(struct scsi_read_dvd_struct_data_header), 406760422Sken dvdstruct->data, 406860422Sken min(sizeof(dvdstruct->data), dvdstruct->length)); 406960422Sken break; 407060422Sken } 4071200036Sscottl 407260422Skenbailout: 4073200036Sscottl xpt_release_ccb(ccb); 4074200036Sscottl cam_periph_unlock(periph); 407560422Sken 407660422Sken if (databuf != NULL) 407760422Sken free(databuf, M_DEVBUF); 407860422Sken 407960422Sken return(error); 408060422Sken} 408160422Sken 408260422Skenvoid 408360422Skenscsi_report_key(struct ccb_scsiio *csio, u_int32_t retries, 408460422Sken void (*cbfcnp)(struct cam_periph *, union ccb *), 408560422Sken u_int8_t tag_action, u_int32_t lba, u_int8_t agid, 408660422Sken u_int8_t key_format, u_int8_t *data_ptr, u_int32_t dxfer_len, 408760422Sken u_int8_t sense_len, u_int32_t timeout) 408860422Sken{ 408960422Sken struct scsi_report_key *scsi_cmd; 409060422Sken 409160422Sken scsi_cmd = (struct scsi_report_key *)&csio->cdb_io.cdb_bytes; 409260422Sken bzero(scsi_cmd, sizeof(*scsi_cmd)); 409360422Sken scsi_cmd->opcode = REPORT_KEY; 409460422Sken scsi_ulto4b(lba, scsi_cmd->lba); 409560422Sken scsi_ulto2b(dxfer_len, scsi_cmd->alloc_len); 409660422Sken scsi_cmd->agid_keyformat = (agid << RK_KF_AGID_SHIFT) | 409760422Sken (key_format & RK_KF_KEYFORMAT_MASK); 409860422Sken 409960422Sken cam_fill_csio(csio, 410060422Sken retries, 410160422Sken cbfcnp, 410260422Sken /*flags*/ (dxfer_len == 0) ? CAM_DIR_NONE : CAM_DIR_IN, 410360422Sken tag_action, 410460422Sken /*data_ptr*/ data_ptr, 410560422Sken /*dxfer_len*/ dxfer_len, 410660422Sken sense_len, 410760422Sken sizeof(*scsi_cmd), 410860422Sken timeout); 410960422Sken} 411060422Sken 411160422Skenvoid 411260422Skenscsi_send_key(struct ccb_scsiio *csio, u_int32_t retries, 411360422Sken void (*cbfcnp)(struct cam_periph *, union ccb *), 411460422Sken u_int8_t tag_action, u_int8_t agid, u_int8_t key_format, 411560422Sken u_int8_t *data_ptr, u_int32_t dxfer_len, u_int8_t sense_len, 411660422Sken u_int32_t timeout) 411760422Sken{ 411860422Sken struct scsi_send_key *scsi_cmd; 411960422Sken 412060422Sken scsi_cmd = (struct scsi_send_key *)&csio->cdb_io.cdb_bytes; 412160422Sken bzero(scsi_cmd, sizeof(*scsi_cmd)); 412260422Sken scsi_cmd->opcode = SEND_KEY; 412360422Sken 412460422Sken scsi_ulto2b(dxfer_len, scsi_cmd->param_len); 412560422Sken scsi_cmd->agid_keyformat = (agid << RK_KF_AGID_SHIFT) | 412660422Sken (key_format & RK_KF_KEYFORMAT_MASK); 412760422Sken 412860422Sken cam_fill_csio(csio, 412960422Sken retries, 413060422Sken cbfcnp, 413160422Sken /*flags*/ CAM_DIR_OUT, 413260422Sken tag_action, 413360422Sken /*data_ptr*/ data_ptr, 413460422Sken /*dxfer_len*/ dxfer_len, 413560422Sken sense_len, 413660422Sken sizeof(*scsi_cmd), 413760422Sken timeout); 413860422Sken} 413960422Sken 414060422Sken 414160422Skenvoid 414260422Skenscsi_read_dvd_structure(struct ccb_scsiio *csio, u_int32_t retries, 414360422Sken void (*cbfcnp)(struct cam_periph *, union ccb *), 414460422Sken u_int8_t tag_action, u_int32_t address, 414560422Sken u_int8_t layer_number, u_int8_t format, u_int8_t agid, 414660422Sken u_int8_t *data_ptr, u_int32_t dxfer_len, 414760422Sken u_int8_t sense_len, u_int32_t timeout) 414860422Sken{ 414960422Sken struct scsi_read_dvd_structure *scsi_cmd; 415060422Sken 415160422Sken scsi_cmd = (struct scsi_read_dvd_structure *)&csio->cdb_io.cdb_bytes; 415260422Sken bzero(scsi_cmd, sizeof(*scsi_cmd)); 415360422Sken scsi_cmd->opcode = READ_DVD_STRUCTURE; 415460422Sken 415560422Sken scsi_ulto4b(address, scsi_cmd->address); 415660422Sken scsi_cmd->layer_number = layer_number; 415760422Sken scsi_cmd->format = format; 415860422Sken scsi_ulto2b(dxfer_len, scsi_cmd->alloc_len); 415960422Sken /* The AGID is the top two bits of this byte */ 416060422Sken scsi_cmd->agid = agid << 6; 416160422Sken 416260422Sken cam_fill_csio(csio, 416360422Sken retries, 416460422Sken cbfcnp, 416560422Sken /*flags*/ CAM_DIR_IN, 416660422Sken tag_action, 416760422Sken /*data_ptr*/ data_ptr, 416860422Sken /*dxfer_len*/ dxfer_len, 416960422Sken sense_len, 417060422Sken sizeof(*scsi_cmd), 417160422Sken timeout); 417260422Sken} 4173352715Savg 4174352715Savgvoid 4175352715Savgscsi_read_toc(struct ccb_scsiio *csio, uint32_t retries, 4176352715Savg void (*cbfcnp)(struct cam_periph *, union ccb *), 4177352715Savg uint8_t tag_action, uint8_t byte1_flags, uint8_t format, 4178352715Savg uint8_t track, uint8_t *data_ptr, uint32_t dxfer_len, 4179352715Savg int sense_len, int timeout) 4180352715Savg{ 4181352715Savg struct scsi_read_toc *scsi_cmd; 4182352715Savg 4183352715Savg scsi_cmd = (struct scsi_read_toc *)&csio->cdb_io.cdb_bytes; 4184352715Savg bzero(scsi_cmd, sizeof(*scsi_cmd)); 4185352715Savg scsi_cmd->op_code = READ_TOC; 4186352715Savg 4187352715Savg /* 4188352715Savg * The structure is counting from 1, the function counting from 0. 4189352715Savg * The spec counts from 0. In MMC-6, there is only one flag, the 4190352715Savg * MSF flag. But we put the whole byte in for a bit a future-proofing. 4191352715Savg */ 4192352715Savg scsi_cmd->byte2 = byte1_flags; 4193352715Savg scsi_cmd->format = format; 4194352715Savg scsi_cmd->from_track = track; 4195352715Savg scsi_ulto2b(dxfer_len, scsi_cmd->data_len); 4196352715Savg 4197352717Savg cam_fill_csio(csio, 4198352717Savg /* retries */ retries, 4199352715Savg /* cbfcnp */ cbfcnp, 4200352715Savg /* flags */ CAM_DIR_IN, 4201352715Savg /* tag_action */ tag_action, 4202352715Savg /* data_ptr */ data_ptr, 4203352715Savg /* dxfer_len */ dxfer_len, 4204352715Savg /* sense_len */ sense_len, 4205352715Savg sizeof(*scsi_cmd), 4206352717Savg /* timeout */ timeout); 4207352715Savg} 4208