scsi_cd.c revision 76362
139213Sgibbs/* 239213Sgibbs * Copyright (c) 1997 Justin T. Gibbs. 371752Sken * Copyright (c) 1997, 1998, 1999, 2000, 2001 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 * 2750477Speter * $FreeBSD: head/sys/cam/scsi/scsi_cd.c 76362 2001-05-08 08:30:48Z phk $ 2839213Sgibbs */ 2939213Sgibbs/* 3039213Sgibbs * Portions of this driver taken from the original FreeBSD cd driver. 3139213Sgibbs * Written by Julian Elischer (julian@tfs.com) 3239213Sgibbs * for TRW Financial Systems for use under the MACH(2.5) operating system. 3339213Sgibbs * 3439213Sgibbs * TRW Financial Systems, in accordance with their agreement with Carnegie 3539213Sgibbs * Mellon University, makes this software available to CMU to distribute 3639213Sgibbs * or use in any manner that they see fit as long as this message is kept with 3739213Sgibbs * the software. For this reason TFS also grants any other persons or 3839213Sgibbs * organisations permission to use or modify this software. 3939213Sgibbs * 4039213Sgibbs * TFS supplies this software to be publicly redistributed 4139213Sgibbs * on the understanding that TFS is not responsible for the correct 4239213Sgibbs * functioning of this software in any circumstances. 4339213Sgibbs * 4439213Sgibbs * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 4539213Sgibbs * 4639213Sgibbs * from: cd.c,v 1.83 1997/05/04 15:24:22 joerg Exp $ 4739213Sgibbs */ 4839213Sgibbs 4940020Sken#include "opt_cd.h" 5039213Sgibbs 5139213Sgibbs#include <sys/param.h> 5239213Sgibbs#include <sys/systm.h> 5339213Sgibbs#include <sys/kernel.h> 5460041Sphk#include <sys/bio.h> 5551836Sphk#include <sys/conf.h> 5651836Sphk#include <sys/disk.h> 5739213Sgibbs#include <sys/malloc.h> 5839213Sgibbs#include <sys/cdio.h> 5960422Sken#include <sys/dvdio.h> 6039213Sgibbs#include <sys/devicestat.h> 6139213Sgibbs#include <sys/sysctl.h> 6239213Sgibbs 6339213Sgibbs#include <cam/cam.h> 6439213Sgibbs#include <cam/cam_ccb.h> 6539213Sgibbs#include <cam/cam_extend.h> 6639213Sgibbs#include <cam/cam_periph.h> 6739213Sgibbs#include <cam/cam_xpt_periph.h> 6839213Sgibbs#include <cam/cam_queue.h> 6939213Sgibbs 7039213Sgibbs#include <cam/scsi/scsi_message.h> 7139213Sgibbs#include <cam/scsi/scsi_da.h> 7239213Sgibbs#include <cam/scsi/scsi_cd.h> 7339213Sgibbs 7439213Sgibbs#define LEADOUT 0xaa /* leadout toc entry */ 7539213Sgibbs 7639213Sgibbsstruct cd_params { 7739213Sgibbs u_int32_t blksize; 7839213Sgibbs u_long disksize; 7939213Sgibbs}; 8039213Sgibbs 8139213Sgibbstypedef enum { 8239213Sgibbs CD_Q_NONE = 0x00, 8339213Sgibbs CD_Q_NO_TOUCH = 0x01, 8439213Sgibbs CD_Q_BCD_TRACKS = 0x02, 8539213Sgibbs CD_Q_NO_CHANGER = 0x04, 8639213Sgibbs CD_Q_CHANGER = 0x08 8739213Sgibbs} cd_quirks; 8839213Sgibbs 8939213Sgibbstypedef enum { 9039213Sgibbs CD_FLAG_INVALID = 0x001, 9139213Sgibbs CD_FLAG_NEW_DISC = 0x002, 9239213Sgibbs CD_FLAG_DISC_LOCKED = 0x004, 9339213Sgibbs CD_FLAG_DISC_REMOVABLE = 0x008, 9439213Sgibbs CD_FLAG_TAGGED_QUEUING = 0x010, 9539213Sgibbs CD_FLAG_CHANGER = 0x040, 9639213Sgibbs CD_FLAG_ACTIVE = 0x080, 9739213Sgibbs CD_FLAG_SCHED_ON_COMP = 0x100, 9839213Sgibbs CD_FLAG_RETRY_UA = 0x200 9939213Sgibbs} cd_flags; 10039213Sgibbs 10139213Sgibbstypedef enum { 10239213Sgibbs CD_CCB_PROBE = 0x01, 10339213Sgibbs CD_CCB_BUFFER_IO = 0x02, 10439213Sgibbs CD_CCB_WAITING = 0x03, 10539213Sgibbs CD_CCB_TYPE_MASK = 0x0F, 10639213Sgibbs CD_CCB_RETRY_UA = 0x10 10739213Sgibbs} cd_ccb_state; 10839213Sgibbs 10939213Sgibbstypedef enum { 11039213Sgibbs CHANGER_TIMEOUT_SCHED = 0x01, 11139213Sgibbs CHANGER_SHORT_TMOUT_SCHED = 0x02, 11239213Sgibbs CHANGER_MANUAL_CALL = 0x04, 11339213Sgibbs CHANGER_NEED_TIMEOUT = 0x08 11439213Sgibbs} cd_changer_flags; 11539213Sgibbs 11639213Sgibbs#define ccb_state ppriv_field0 11739213Sgibbs#define ccb_bp ppriv_ptr1 11839213Sgibbs 11939213Sgibbstypedef enum { 12039213Sgibbs CD_STATE_PROBE, 12139213Sgibbs CD_STATE_NORMAL 12239213Sgibbs} cd_state; 12339213Sgibbs 12439213Sgibbsstruct cd_softc { 12539213Sgibbs cam_pinfo pinfo; 12639213Sgibbs cd_state state; 12746581Sken volatile cd_flags flags; 12859249Sphk struct bio_queue_head bio_queue; 12960938Sjake LIST_HEAD(, ccb_hdr) pending_ccbs; 13039213Sgibbs struct cd_params params; 13151836Sphk struct disk disk; 13239213Sgibbs union ccb saved_ccb; 13339213Sgibbs cd_quirks quirks; 13439213Sgibbs struct devstat device_stats; 13560938Sjake STAILQ_ENTRY(cd_softc) changer_links; 13639213Sgibbs struct cdchanger *changer; 13739213Sgibbs int bufs_left; 13839213Sgibbs struct cam_periph *periph; 13939213Sgibbs}; 14039213Sgibbs 14139213Sgibbsstruct cd_quirk_entry { 14239213Sgibbs struct scsi_inquiry_pattern inq_pat; 14339213Sgibbs cd_quirks quirks; 14439213Sgibbs}; 14539213Sgibbs 14639213Sgibbs/* 14739213Sgibbs * These quirk entries aren't strictly necessary. Basically, what they do 14839213Sgibbs * is tell cdregister() up front that a device is a changer. Otherwise, it 14939213Sgibbs * will figure that fact out once it sees a LUN on the device that is 15039213Sgibbs * greater than 0. If it is known up front that a device is a changer, all 15139213Sgibbs * I/O to the device will go through the changer scheduling routines, as 15239213Sgibbs * opposed to the "normal" CD code. 15339213Sgibbs */ 15439213Sgibbsstatic struct cd_quirk_entry cd_quirk_table[] = 15539213Sgibbs{ 15639213Sgibbs { 15739213Sgibbs { T_CDROM, SIP_MEDIA_REMOVABLE, "NRC", "MBR-7", "*"}, 15839213Sgibbs /*quirks*/ CD_Q_CHANGER 15939213Sgibbs }, 16039213Sgibbs { 16154451Sken { T_CDROM, SIP_MEDIA_REMOVABLE, "PIONEER", "CD-ROM DRM*", 16239213Sgibbs "*"}, /* quirks */ CD_Q_CHANGER 16340262Sken }, 16440262Sken { 16567752Sken { T_CDROM, SIP_MEDIA_REMOVABLE, "NAKAMICH", "MJ-*", "*"}, 16667752Sken /* quirks */ CD_Q_CHANGER 16767752Sken }, 16867752Sken { 16940262Sken { T_CDROM, SIP_MEDIA_REMOVABLE, "CHINON", "CD-ROM CDS-535","*"}, 17040262Sken /* quirks */ CD_Q_BCD_TRACKS 17139213Sgibbs } 17239213Sgibbs}; 17339213Sgibbs 17439213Sgibbs#ifndef MIN 17539213Sgibbs#define MIN(x,y) ((x<y) ? x : y) 17639213Sgibbs#endif 17739213Sgibbs 17839213Sgibbs#define CD_CDEV_MAJOR 15 17939213Sgibbs 18039213Sgibbsstatic d_open_t cdopen; 18139213Sgibbsstatic d_close_t cdclose; 18239213Sgibbsstatic d_ioctl_t cdioctl; 18339213Sgibbsstatic d_strategy_t cdstrategy; 18439213Sgibbs 18539213Sgibbsstatic periph_init_t cdinit; 18639213Sgibbsstatic periph_ctor_t cdregister; 18739213Sgibbsstatic periph_dtor_t cdcleanup; 18839213Sgibbsstatic periph_start_t cdstart; 18940603Skenstatic periph_oninv_t cdoninvalidate; 19039213Sgibbsstatic void cdasync(void *callback_arg, u_int32_t code, 19139213Sgibbs struct cam_path *path, void *arg); 19239213Sgibbsstatic void cdshorttimeout(void *arg); 19339213Sgibbsstatic void cdschedule(struct cam_periph *periph, int priority); 19439213Sgibbsstatic void cdrunchangerqueue(void *arg); 19539213Sgibbsstatic void cdchangerschedule(struct cd_softc *softc); 19639213Sgibbsstatic int cdrunccb(union ccb *ccb, 19739213Sgibbs int (*error_routine)(union ccb *ccb, 19839213Sgibbs u_int32_t cam_flags, 19939213Sgibbs u_int32_t sense_flags), 20039213Sgibbs u_int32_t cam_flags, u_int32_t sense_flags); 20142531Seivindstatic union ccb *cdgetccb(struct cam_periph *periph, 20239213Sgibbs u_int32_t priority); 20339213Sgibbsstatic void cddone(struct cam_periph *periph, 20439213Sgibbs union ccb *start_ccb); 20539213Sgibbsstatic int cderror(union ccb *ccb, u_int32_t cam_flags, 20639213Sgibbs u_int32_t sense_flags); 20739213Sgibbsstatic void cdprevent(struct cam_periph *periph, int action); 20839213Sgibbsstatic int cdsize(dev_t dev, u_int32_t *size); 20968294Skenstatic int cdfirsttrackisdata(struct cam_periph *periph); 21039213Sgibbsstatic int cdreadtoc(struct cam_periph *periph, u_int32_t mode, 21139213Sgibbs u_int32_t start, struct cd_toc_entry *data, 21239213Sgibbs u_int32_t len); 21339213Sgibbsstatic int cdgetmode(struct cam_periph *periph, 21439213Sgibbs struct cd_mode_data *data, u_int32_t page); 21539213Sgibbsstatic int cdsetmode(struct cam_periph *periph, 21639213Sgibbs struct cd_mode_data *data); 21739213Sgibbsstatic int cdplay(struct cam_periph *periph, u_int32_t blk, 21839213Sgibbs u_int32_t len); 21939213Sgibbsstatic int cdreadsubchannel(struct cam_periph *periph, 22039213Sgibbs u_int32_t mode, u_int32_t format, 22139213Sgibbs int track, 22239213Sgibbs struct cd_sub_channel_info *data, 22339213Sgibbs u_int32_t len); 22439213Sgibbsstatic int cdplaymsf(struct cam_periph *periph, u_int32_t startm, 22539213Sgibbs u_int32_t starts, u_int32_t startf, 22639213Sgibbs u_int32_t endm, u_int32_t ends, 22739213Sgibbs u_int32_t endf); 22839213Sgibbsstatic int cdplaytracks(struct cam_periph *periph, 22939213Sgibbs u_int32_t strack, u_int32_t sindex, 23039213Sgibbs u_int32_t etrack, u_int32_t eindex); 23139213Sgibbsstatic int cdpause(struct cam_periph *periph, u_int32_t go); 23239213Sgibbsstatic int cdstopunit(struct cam_periph *periph, u_int32_t eject); 23339213Sgibbsstatic int cdstartunit(struct cam_periph *periph); 23460422Skenstatic int cdreportkey(struct cam_periph *periph, 23560422Sken struct dvd_authinfo *authinfo); 23660422Skenstatic int cdsendkey(struct cam_periph *periph, 23760422Sken struct dvd_authinfo *authinfo); 23860422Skenstatic int cdreaddvdstructure(struct cam_periph *periph, 23960422Sken struct dvd_struct *dvdstruct); 24039213Sgibbs 24139213Sgibbsstatic struct periph_driver cddriver = 24239213Sgibbs{ 24339213Sgibbs cdinit, "cd", 24439213Sgibbs TAILQ_HEAD_INITIALIZER(cddriver.units), /* generation */ 0 24539213Sgibbs}; 24639213Sgibbs 24772119SpeterPERIPHDRIVER_DECLARE(cd, cddriver); 24839213Sgibbs 24939213Sgibbs/* For 2.2-stable support */ 25039213Sgibbs#ifndef D_DISK 25139213Sgibbs#define D_DISK 0 25239213Sgibbs#endif 25347625Sphkstatic struct cdevsw cd_cdevsw = { 25447625Sphk /* open */ cdopen, 25547625Sphk /* close */ cdclose, 25647625Sphk /* read */ physread, 25767928Sken /* write */ physwrite, 25847625Sphk /* ioctl */ cdioctl, 25947625Sphk /* poll */ nopoll, 26047625Sphk /* mmap */ nommap, 26147625Sphk /* strategy */ cdstrategy, 26247625Sphk /* name */ "cd", 26347625Sphk /* maj */ CD_CDEV_MAJOR, 26447625Sphk /* dump */ nodump, 26547625Sphk /* psize */ nopsize, 26647625Sphk /* flags */ D_DISK, 26739213Sgibbs}; 26851836Sphkstatic struct cdevsw cddisk_cdevsw; 26939213Sgibbs 27039213Sgibbsstatic struct extend_array *cdperiphs; 27139213Sgibbsstatic int num_changers; 27239213Sgibbs 27339213Sgibbs#ifndef CHANGER_MIN_BUSY_SECONDS 27446747Sken#define CHANGER_MIN_BUSY_SECONDS 5 27539213Sgibbs#endif 27639213Sgibbs#ifndef CHANGER_MAX_BUSY_SECONDS 27746747Sken#define CHANGER_MAX_BUSY_SECONDS 15 27839213Sgibbs#endif 27939213Sgibbs 28039213Sgibbsstatic int changer_min_busy_seconds = CHANGER_MIN_BUSY_SECONDS; 28139213Sgibbsstatic int changer_max_busy_seconds = CHANGER_MAX_BUSY_SECONDS; 28239213Sgibbs 28339213Sgibbs/* 28439213Sgibbs * XXX KDM this CAM node should be moved if we ever get more CAM sysctl 28539213Sgibbs * variables. 28639213Sgibbs */ 28739213SgibbsSYSCTL_NODE(_kern, OID_AUTO, cam, CTLFLAG_RD, 0, "CAM Subsystem"); 28839213SgibbsSYSCTL_NODE(_kern_cam, OID_AUTO, cd, CTLFLAG_RD, 0, "CAM CDROM driver"); 28939213SgibbsSYSCTL_NODE(_kern_cam_cd, OID_AUTO, changer, CTLFLAG_RD, 0, "CD Changer"); 29039213SgibbsSYSCTL_INT(_kern_cam_cd_changer, OID_AUTO, min_busy_seconds, CTLFLAG_RW, 29139213Sgibbs &changer_min_busy_seconds, 0, "Minimum changer scheduling quantum"); 29239213SgibbsSYSCTL_INT(_kern_cam_cd_changer, OID_AUTO, max_busy_seconds, CTLFLAG_RW, 29339213Sgibbs &changer_max_busy_seconds, 0, "Maximum changer scheduling quantum"); 29439213Sgibbs 29539213Sgibbsstruct cdchanger { 29639213Sgibbs path_id_t path_id; 29739213Sgibbs target_id_t target_id; 29839213Sgibbs int num_devices; 29939213Sgibbs struct camq devq; 30039213Sgibbs struct timeval start_time; 30139213Sgibbs struct cd_softc *cur_device; 30239213Sgibbs struct callout_handle short_handle; 30339213Sgibbs struct callout_handle long_handle; 30446581Sken volatile cd_changer_flags flags; 30560938Sjake STAILQ_ENTRY(cdchanger) changer_links; 30660938Sjake STAILQ_HEAD(chdevlist, cd_softc) chluns; 30739213Sgibbs}; 30839213Sgibbs 30960938Sjakestatic STAILQ_HEAD(changerlist, cdchanger) changerq; 31039213Sgibbs 31139213Sgibbsvoid 31239213Sgibbscdinit(void) 31339213Sgibbs{ 31439213Sgibbs cam_status status; 31539213Sgibbs struct cam_path *path; 31639213Sgibbs 31739213Sgibbs /* 31839213Sgibbs * Create our extend array for storing the devices we attach to. 31939213Sgibbs */ 32039213Sgibbs cdperiphs = cam_extend_new(); 32139213Sgibbs if (cdperiphs == NULL) { 32239213Sgibbs printf("cd: Failed to alloc extend array!\n"); 32339213Sgibbs return; 32439213Sgibbs } 32539213Sgibbs 32639213Sgibbs /* 32739213Sgibbs * Install a global async callback. This callback will 32839213Sgibbs * receive async callbacks like "new device found". 32939213Sgibbs */ 33039213Sgibbs status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID, 33139213Sgibbs CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 33239213Sgibbs 33339213Sgibbs if (status == CAM_REQ_CMP) { 33439213Sgibbs struct ccb_setasync csa; 33539213Sgibbs 33639213Sgibbs xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5); 33739213Sgibbs csa.ccb_h.func_code = XPT_SASYNC_CB; 33839213Sgibbs csa.event_enable = AC_FOUND_DEVICE; 33939213Sgibbs csa.callback = cdasync; 34039213Sgibbs csa.callback_arg = NULL; 34139213Sgibbs xpt_action((union ccb *)&csa); 34239213Sgibbs status = csa.ccb_h.status; 34339213Sgibbs xpt_free_path(path); 34439213Sgibbs } 34539213Sgibbs 34639213Sgibbs if (status != CAM_REQ_CMP) { 34739213Sgibbs printf("cd: Failed to attach master async callback " 34839213Sgibbs "due to status 0x%x!\n", status); 34939213Sgibbs } 35039213Sgibbs} 35139213Sgibbs 35239213Sgibbsstatic void 35340603Skencdoninvalidate(struct cam_periph *periph) 35440603Sken{ 35540603Sken int s; 35640603Sken struct cd_softc *softc; 35759249Sphk struct bio *q_bp; 35840603Sken struct ccb_setasync csa; 35940603Sken 36040603Sken softc = (struct cd_softc *)periph->softc; 36140603Sken 36240603Sken /* 36340603Sken * De-register any async callbacks. 36440603Sken */ 36540603Sken xpt_setup_ccb(&csa.ccb_h, periph->path, 36640603Sken /* priority */ 5); 36740603Sken csa.ccb_h.func_code = XPT_SASYNC_CB; 36840603Sken csa.event_enable = 0; 36940603Sken csa.callback = cdasync; 37040603Sken csa.callback_arg = periph; 37140603Sken xpt_action((union ccb *)&csa); 37240603Sken 37340603Sken softc->flags |= CD_FLAG_INVALID; 37440603Sken 37540603Sken /* 37640603Sken * Although the oninvalidate() routines are always called at 37740603Sken * splsoftcam, we need to be at splbio() here to keep the buffer 37840603Sken * queue from being modified while we traverse it. 37940603Sken */ 38040603Sken s = splbio(); 38140603Sken 38240603Sken /* 38340603Sken * Return all queued I/O with ENXIO. 38440603Sken * XXX Handle any transactions queued to the card 38540603Sken * with XPT_ABORT_CCB. 38640603Sken */ 38759249Sphk while ((q_bp = bioq_first(&softc->bio_queue)) != NULL){ 38859249Sphk bioq_remove(&softc->bio_queue, q_bp); 38959249Sphk q_bp->bio_resid = q_bp->bio_bcount; 39076322Sphk biofinish(q_bp, NULL, ENXIO); 39140603Sken } 39240603Sken splx(s); 39340603Sken 39440603Sken /* 39540603Sken * If this device is part of a changer, and it was scheduled 39640603Sken * to run, remove it from the run queue since we just nuked 39740603Sken * all of its scheduled I/O. 39840603Sken */ 39940603Sken if ((softc->flags & CD_FLAG_CHANGER) 40040603Sken && (softc->pinfo.index != CAM_UNQUEUED_INDEX)) 40140603Sken camq_remove(&softc->changer->devq, softc->pinfo.index); 40240603Sken 40340603Sken xpt_print_path(periph->path); 40440603Sken printf("lost device\n"); 40540603Sken} 40640603Sken 40740603Skenstatic void 40839213Sgibbscdcleanup(struct cam_periph *periph) 40939213Sgibbs{ 41039213Sgibbs struct cd_softc *softc; 41140603Sken int s; 41239213Sgibbs 41339213Sgibbs softc = (struct cd_softc *)periph->softc; 41439213Sgibbs 41539213Sgibbs xpt_print_path(periph->path); 41639213Sgibbs printf("removing device entry\n"); 41740603Sken 41840603Sken s = splsoftcam(); 41939213Sgibbs /* 42039213Sgibbs * In the queued, non-active case, the device in question 42139213Sgibbs * has already been removed from the changer run queue. Since this 42239213Sgibbs * device is active, we need to de-activate it, and schedule 42339213Sgibbs * another device to run. (if there is another one to run) 42439213Sgibbs */ 42539213Sgibbs if ((softc->flags & CD_FLAG_CHANGER) 42639213Sgibbs && (softc->flags & CD_FLAG_ACTIVE)) { 42739213Sgibbs 42839213Sgibbs /* 42939213Sgibbs * The purpose of the short timeout is soley to determine 43039213Sgibbs * whether the current device has finished or not. Well, 43139213Sgibbs * since we're removing the active device, we know that it 43239213Sgibbs * is finished. So, get rid of the short timeout. 43339213Sgibbs * Otherwise, if we're in the time period before the short 43439213Sgibbs * timeout fires, and there are no other devices in the 43539213Sgibbs * queue to run, there won't be any other device put in the 43639213Sgibbs * active slot. i.e., when we call cdrunchangerqueue() 43739213Sgibbs * below, it won't do anything. Then, when the short 43839213Sgibbs * timeout fires, it'll look at the "current device", which 43939213Sgibbs * we are free below, and possibly panic the kernel on a 44039213Sgibbs * bogus pointer reference. 44139213Sgibbs * 44239213Sgibbs * The long timeout doesn't really matter, since we 44339213Sgibbs * decrement the qfrozen_cnt to indicate that there is 44439213Sgibbs * nothing in the active slot now. Therefore, there won't 44539213Sgibbs * be any bogus pointer references there. 44639213Sgibbs */ 44739213Sgibbs if (softc->changer->flags & CHANGER_SHORT_TMOUT_SCHED) { 44839213Sgibbs untimeout(cdshorttimeout, softc->changer, 44939213Sgibbs softc->changer->short_handle); 45039213Sgibbs softc->changer->flags &= ~CHANGER_SHORT_TMOUT_SCHED; 45139213Sgibbs } 45239213Sgibbs softc->changer->devq.qfrozen_cnt--; 45339213Sgibbs softc->changer->flags |= CHANGER_MANUAL_CALL; 45439213Sgibbs cdrunchangerqueue(softc->changer); 45539213Sgibbs } 45639213Sgibbs 45739213Sgibbs /* 45839213Sgibbs * If we're removing the last device on the changer, go ahead and 45939213Sgibbs * remove the changer device structure. 46039213Sgibbs */ 46139213Sgibbs if ((softc->flags & CD_FLAG_CHANGER) 46239213Sgibbs && (--softc->changer->num_devices == 0)) { 46339213Sgibbs 46439213Sgibbs /* 46539213Sgibbs * Theoretically, there shouldn't be any timeouts left, but 46639213Sgibbs * I'm not completely sure that that will be the case. So, 46739213Sgibbs * it won't hurt to check and see if there are any left. 46839213Sgibbs */ 46939213Sgibbs if (softc->changer->flags & CHANGER_TIMEOUT_SCHED) { 47039213Sgibbs untimeout(cdrunchangerqueue, softc->changer, 47139213Sgibbs softc->changer->long_handle); 47239213Sgibbs softc->changer->flags &= ~CHANGER_TIMEOUT_SCHED; 47339213Sgibbs } 47439213Sgibbs 47539213Sgibbs if (softc->changer->flags & CHANGER_SHORT_TMOUT_SCHED) { 47639213Sgibbs untimeout(cdshorttimeout, softc->changer, 47739213Sgibbs softc->changer->short_handle); 47839213Sgibbs softc->changer->flags &= ~CHANGER_SHORT_TMOUT_SCHED; 47939213Sgibbs } 48039213Sgibbs 48160938Sjake STAILQ_REMOVE(&changerq, softc->changer, cdchanger, 48239213Sgibbs changer_links); 48339213Sgibbs xpt_print_path(periph->path); 48439213Sgibbs printf("removing changer entry\n"); 48539213Sgibbs free(softc->changer, M_DEVBUF); 48639213Sgibbs num_changers--; 48739213Sgibbs } 48840603Sken devstat_remove_entry(&softc->device_stats); 48939213Sgibbs cam_extend_release(cdperiphs, periph->unit_number); 49040603Sken free(softc, M_DEVBUF); 49140603Sken splx(s); 49239213Sgibbs} 49339213Sgibbs 49439213Sgibbsstatic void 49539213Sgibbscdasync(void *callback_arg, u_int32_t code, 49639213Sgibbs struct cam_path *path, void *arg) 49739213Sgibbs{ 49839213Sgibbs struct cam_periph *periph; 49939213Sgibbs 50039213Sgibbs periph = (struct cam_periph *)callback_arg; 50139213Sgibbs switch (code) { 50239213Sgibbs case AC_FOUND_DEVICE: 50339213Sgibbs { 50439213Sgibbs struct ccb_getdev *cgd; 50539213Sgibbs cam_status status; 50639213Sgibbs 50739213Sgibbs cgd = (struct ccb_getdev *)arg; 50839213Sgibbs 50956148Smjacob if (SID_TYPE(&cgd->inq_data) != T_CDROM 51056148Smjacob && SID_TYPE(&cgd->inq_data) != T_WORM) 51139213Sgibbs break; 51239213Sgibbs 51339213Sgibbs /* 51439213Sgibbs * Allocate a peripheral instance for 51539213Sgibbs * this device and start the probe 51639213Sgibbs * process. 51739213Sgibbs */ 51840603Sken status = cam_periph_alloc(cdregister, cdoninvalidate, 51940603Sken cdcleanup, cdstart, 52040603Sken "cd", CAM_PERIPH_BIO, 52140603Sken cgd->ccb_h.path, cdasync, 52240603Sken AC_FOUND_DEVICE, cgd); 52339213Sgibbs 52439213Sgibbs if (status != CAM_REQ_CMP 52539213Sgibbs && status != CAM_REQ_INPROG) 52639213Sgibbs printf("cdasync: Unable to attach new device " 52739213Sgibbs "due to status 0x%x\n", status); 52839213Sgibbs 52939213Sgibbs break; 53039213Sgibbs } 53139213Sgibbs case AC_SENT_BDR: 53239213Sgibbs case AC_BUS_RESET: 53339213Sgibbs { 53439213Sgibbs struct cd_softc *softc; 53539213Sgibbs struct ccb_hdr *ccbh; 53639213Sgibbs int s; 53739213Sgibbs 53839213Sgibbs softc = (struct cd_softc *)periph->softc; 53939213Sgibbs s = splsoftcam(); 54039213Sgibbs /* 54139213Sgibbs * Don't fail on the expected unit attention 54239213Sgibbs * that will occur. 54339213Sgibbs */ 54439213Sgibbs softc->flags |= CD_FLAG_RETRY_UA; 54571999Sphk LIST_FOREACH(ccbh, &softc->pending_ccbs, periph_links.le) 54639213Sgibbs ccbh->ccb_state |= CD_CCB_RETRY_UA; 54739213Sgibbs splx(s); 54847413Sgibbs /* FALLTHROUGH */ 54939213Sgibbs } 55039213Sgibbs default: 55147413Sgibbs cam_periph_async(periph, code, path, arg); 55239213Sgibbs break; 55339213Sgibbs } 55439213Sgibbs} 55539213Sgibbs 55639213Sgibbsstatic cam_status 55739213Sgibbscdregister(struct cam_periph *periph, void *arg) 55839213Sgibbs{ 55939213Sgibbs struct cd_softc *softc; 56039213Sgibbs struct ccb_setasync csa; 56139213Sgibbs struct ccb_getdev *cgd; 56239213Sgibbs caddr_t match; 56339213Sgibbs 56439213Sgibbs cgd = (struct ccb_getdev *)arg; 56539213Sgibbs if (periph == NULL) { 56639213Sgibbs printf("cdregister: periph was NULL!!\n"); 56739213Sgibbs return(CAM_REQ_CMP_ERR); 56839213Sgibbs } 56939213Sgibbs if (cgd == NULL) { 57039213Sgibbs printf("cdregister: no getdev CCB, can't register device\n"); 57139213Sgibbs return(CAM_REQ_CMP_ERR); 57239213Sgibbs } 57339213Sgibbs 57439213Sgibbs softc = (struct cd_softc *)malloc(sizeof(*softc),M_DEVBUF,M_NOWAIT); 57539213Sgibbs 57639213Sgibbs if (softc == NULL) { 57739213Sgibbs printf("cdregister: Unable to probe new device. " 57839213Sgibbs "Unable to allocate softc\n"); 57939213Sgibbs return(CAM_REQ_CMP_ERR); 58039213Sgibbs } 58139213Sgibbs 58239213Sgibbs bzero(softc, sizeof(*softc)); 58339213Sgibbs LIST_INIT(&softc->pending_ccbs); 58439213Sgibbs softc->state = CD_STATE_PROBE; 58559249Sphk bioq_init(&softc->bio_queue); 58639213Sgibbs if (SID_IS_REMOVABLE(&cgd->inq_data)) 58739213Sgibbs softc->flags |= CD_FLAG_DISC_REMOVABLE; 58839213Sgibbs if ((cgd->inq_data.flags & SID_CmdQue) != 0) 58939213Sgibbs softc->flags |= CD_FLAG_TAGGED_QUEUING; 59039213Sgibbs 59139213Sgibbs periph->softc = softc; 59239213Sgibbs softc->periph = periph; 59339213Sgibbs 59439213Sgibbs cam_extend_set(cdperiphs, periph->unit_number, periph); 59539213Sgibbs 59639213Sgibbs /* 59739213Sgibbs * See if this device has any quirks. 59839213Sgibbs */ 59939213Sgibbs match = cam_quirkmatch((caddr_t)&cgd->inq_data, 60039213Sgibbs (caddr_t)cd_quirk_table, 60139213Sgibbs sizeof(cd_quirk_table)/sizeof(*cd_quirk_table), 60239213Sgibbs sizeof(*cd_quirk_table), scsi_inquiry_match); 60339213Sgibbs 60439213Sgibbs if (match != NULL) 60539213Sgibbs softc->quirks = ((struct cd_quirk_entry *)match)->quirks; 60639213Sgibbs else 60739213Sgibbs softc->quirks = CD_Q_NONE; 60839213Sgibbs 60939213Sgibbs /* 61039213Sgibbs * We need to register the statistics structure for this device, 61139213Sgibbs * but we don't have the blocksize yet for it. So, we register 61239213Sgibbs * the structure and indicate that we don't have the blocksize 61339213Sgibbs * yet. Unlike other SCSI peripheral drivers, we explicitly set 61439213Sgibbs * the device type here to be CDROM, rather than just ORing in 61556148Smjacob * the device type. This is because this driver can attach to either 61639213Sgibbs * CDROM or WORM devices, and we want this peripheral driver to 61739213Sgibbs * show up in the devstat list as a CD peripheral driver, not a 61839213Sgibbs * WORM peripheral driver. WORM drives will also have the WORM 61939213Sgibbs * driver attached to them. 62039213Sgibbs */ 62139213Sgibbs devstat_add_entry(&softc->device_stats, "cd", 62239213Sgibbs periph->unit_number, 0, 62339213Sgibbs DEVSTAT_BS_UNAVAILABLE, 62443819Sken DEVSTAT_TYPE_CDROM | DEVSTAT_TYPE_IF_SCSI, 62543819Sken DEVSTAT_PRIORITY_CD); 62651836Sphk disk_create(periph->unit_number, &softc->disk, 62767928Sken DSO_ONESLICE | DSO_COMPATLABEL, 62851836Sphk &cd_cdevsw, &cddisk_cdevsw); 62939213Sgibbs 63039213Sgibbs /* 63139213Sgibbs * Add an async callback so that we get 63239213Sgibbs * notified if this device goes away. 63339213Sgibbs */ 63439213Sgibbs xpt_setup_ccb(&csa.ccb_h, periph->path, 63539213Sgibbs /* priority */ 5); 63639213Sgibbs csa.ccb_h.func_code = XPT_SASYNC_CB; 63739213Sgibbs csa.event_enable = AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE; 63839213Sgibbs csa.callback = cdasync; 63939213Sgibbs csa.callback_arg = periph; 64039213Sgibbs xpt_action((union ccb *)&csa); 64139213Sgibbs 64239213Sgibbs /* 64339213Sgibbs * If the target lun is greater than 0, we most likely have a CD 64439213Sgibbs * changer device. Check the quirk entries as well, though, just 64539213Sgibbs * in case someone has a CD tower with one lun per drive or 64639213Sgibbs * something like that. Also, if we know up front that a 64739213Sgibbs * particular device is a changer, we can mark it as such starting 64839213Sgibbs * with lun 0, instead of lun 1. It shouldn't be necessary to have 64939213Sgibbs * a quirk entry to define something as a changer, however. 65039213Sgibbs */ 65139213Sgibbs if (((cgd->ccb_h.target_lun > 0) 65239213Sgibbs && ((softc->quirks & CD_Q_NO_CHANGER) == 0)) 65339213Sgibbs || ((softc->quirks & CD_Q_CHANGER) != 0)) { 65439213Sgibbs struct cdchanger *nchanger; 65539213Sgibbs struct cam_periph *nperiph; 65639213Sgibbs struct cam_path *path; 65739213Sgibbs cam_status status; 65839213Sgibbs int found; 65939213Sgibbs 66039213Sgibbs /* Set the changer flag in the current device's softc */ 66139213Sgibbs softc->flags |= CD_FLAG_CHANGER; 66239213Sgibbs 66339213Sgibbs if (num_changers == 0) 66439213Sgibbs STAILQ_INIT(&changerq); 66539213Sgibbs 66639213Sgibbs /* 66739213Sgibbs * Now, look around for an existing changer device with the 66839213Sgibbs * same path and target ID as the current device. 66939213Sgibbs */ 67039213Sgibbs for (found = 0, 67139213Sgibbs nchanger = (struct cdchanger *)STAILQ_FIRST(&changerq); 67239213Sgibbs nchanger != NULL; 67339213Sgibbs nchanger = STAILQ_NEXT(nchanger, changer_links)){ 67439213Sgibbs if ((nchanger->path_id == cgd->ccb_h.path_id) 67539213Sgibbs && (nchanger->target_id == cgd->ccb_h.target_id)) { 67639213Sgibbs found = 1; 67739213Sgibbs break; 67839213Sgibbs } 67939213Sgibbs } 68039213Sgibbs 68139213Sgibbs /* 68239213Sgibbs * If we found a matching entry, just add this device to 68339213Sgibbs * the list of devices on this changer. 68439213Sgibbs */ 68539213Sgibbs if (found == 1) { 68639213Sgibbs struct chdevlist *chlunhead; 68739213Sgibbs 68839213Sgibbs chlunhead = &nchanger->chluns; 68939213Sgibbs 69039213Sgibbs /* 69139213Sgibbs * XXX KDM look at consolidating this code with the 69239213Sgibbs * code below in a separate function. 69339213Sgibbs */ 69439213Sgibbs 69539213Sgibbs /* 69639213Sgibbs * Create a path with lun id 0, and see if we can 69739213Sgibbs * find a matching device 69839213Sgibbs */ 69939213Sgibbs status = xpt_create_path(&path, /*periph*/ periph, 70039213Sgibbs cgd->ccb_h.path_id, 70139213Sgibbs cgd->ccb_h.target_id, 0); 70239213Sgibbs 70339213Sgibbs if ((status == CAM_REQ_CMP) 70439213Sgibbs && ((nperiph = cam_periph_find(path, "cd")) != NULL)){ 70539213Sgibbs struct cd_softc *nsoftc; 70639213Sgibbs 70739213Sgibbs nsoftc = (struct cd_softc *)nperiph->softc; 70839213Sgibbs 70939213Sgibbs if ((nsoftc->flags & CD_FLAG_CHANGER) == 0){ 71039213Sgibbs nsoftc->flags |= CD_FLAG_CHANGER; 71139213Sgibbs nchanger->num_devices++; 71239213Sgibbs if (camq_resize(&nchanger->devq, 71339213Sgibbs nchanger->num_devices)!=CAM_REQ_CMP){ 71439213Sgibbs printf("cdregister: " 71539213Sgibbs "camq_resize " 71639213Sgibbs "failed, changer " 71739213Sgibbs "support may " 71839213Sgibbs "be messed up\n"); 71939213Sgibbs } 72039213Sgibbs nsoftc->changer = nchanger; 72139213Sgibbs nsoftc->pinfo.index =CAM_UNQUEUED_INDEX; 72239213Sgibbs 72339213Sgibbs STAILQ_INSERT_TAIL(&nchanger->chluns, 72439213Sgibbs nsoftc,changer_links); 72539213Sgibbs } 72667928Sken xpt_free_path(path); 72739213Sgibbs } else if (status == CAM_REQ_CMP) 72839213Sgibbs xpt_free_path(path); 72939213Sgibbs else { 73039213Sgibbs printf("cdregister: unable to allocate path\n" 73139213Sgibbs "cdregister: changer support may be " 73239213Sgibbs "broken\n"); 73339213Sgibbs } 73439213Sgibbs 73539213Sgibbs nchanger->num_devices++; 73639213Sgibbs 73739213Sgibbs softc->changer = nchanger; 73839213Sgibbs softc->pinfo.index = CAM_UNQUEUED_INDEX; 73939213Sgibbs 74039213Sgibbs if (camq_resize(&nchanger->devq, 74139213Sgibbs nchanger->num_devices) != CAM_REQ_CMP) { 74239213Sgibbs printf("cdregister: camq_resize " 74339213Sgibbs "failed, changer support may " 74439213Sgibbs "be messed up\n"); 74539213Sgibbs } 74639213Sgibbs 74739213Sgibbs STAILQ_INSERT_TAIL(chlunhead, softc, changer_links); 74839213Sgibbs } 74939213Sgibbs /* 75039213Sgibbs * In this case, we don't already have an entry for this 75139213Sgibbs * particular changer, so we need to create one, add it to 75239213Sgibbs * the queue, and queue this device on the list for this 75339213Sgibbs * changer. Before we queue this device, however, we need 75439213Sgibbs * to search for lun id 0 on this target, and add it to the 75539213Sgibbs * queue first, if it exists. (and if it hasn't already 75639213Sgibbs * been marked as part of the changer.) 75739213Sgibbs */ 75839213Sgibbs else { 75939213Sgibbs nchanger = malloc(sizeof(struct cdchanger), 76039213Sgibbs M_DEVBUF, M_NOWAIT); 76139213Sgibbs 76239213Sgibbs if (nchanger == NULL) { 76339213Sgibbs softc->flags &= ~CD_FLAG_CHANGER; 76439213Sgibbs printf("cdregister: unable to malloc " 76539213Sgibbs "changer structure\ncdregister: " 76639213Sgibbs "changer support disabled\n"); 76739213Sgibbs 76839213Sgibbs /* 76939213Sgibbs * Yes, gotos can be gross but in this case 77039213Sgibbs * I think it's justified.. 77139213Sgibbs */ 77239213Sgibbs goto cdregisterexit; 77339213Sgibbs } 77439213Sgibbs 77539213Sgibbs /* zero the structure */ 77639213Sgibbs bzero(nchanger, sizeof(struct cdchanger)); 77739213Sgibbs 77839213Sgibbs if (camq_init(&nchanger->devq, 1) != 0) { 77939213Sgibbs softc->flags &= ~CD_FLAG_CHANGER; 78039213Sgibbs printf("cdregister: changer support " 78139213Sgibbs "disabled\n"); 78239213Sgibbs goto cdregisterexit; 78339213Sgibbs } 78439213Sgibbs 78539213Sgibbs num_changers++; 78639213Sgibbs 78739213Sgibbs nchanger->path_id = cgd->ccb_h.path_id; 78839213Sgibbs nchanger->target_id = cgd->ccb_h.target_id; 78939213Sgibbs 79039213Sgibbs /* this is superfluous, but it makes things clearer */ 79139213Sgibbs nchanger->num_devices = 0; 79239213Sgibbs 79339213Sgibbs STAILQ_INIT(&nchanger->chluns); 79439213Sgibbs 79539213Sgibbs STAILQ_INSERT_TAIL(&changerq, nchanger, 79639213Sgibbs changer_links); 79739213Sgibbs 79839213Sgibbs /* 79939213Sgibbs * Create a path with lun id 0, and see if we can 80039213Sgibbs * find a matching device 80139213Sgibbs */ 80239213Sgibbs status = xpt_create_path(&path, /*periph*/ periph, 80339213Sgibbs cgd->ccb_h.path_id, 80439213Sgibbs cgd->ccb_h.target_id, 0); 80539213Sgibbs 80639213Sgibbs /* 80739213Sgibbs * If we were able to allocate the path, and if we 80839213Sgibbs * find a matching device and it isn't already 80939213Sgibbs * marked as part of a changer, then we add it to 81039213Sgibbs * the current changer. 81139213Sgibbs */ 81239213Sgibbs if ((status == CAM_REQ_CMP) 81339213Sgibbs && ((nperiph = cam_periph_find(path, "cd")) != NULL) 81439213Sgibbs && ((((struct cd_softc *)periph->softc)->flags & 81539213Sgibbs CD_FLAG_CHANGER) == 0)) { 81639213Sgibbs struct cd_softc *nsoftc; 81739213Sgibbs 81839213Sgibbs nsoftc = (struct cd_softc *)nperiph->softc; 81939213Sgibbs 82039213Sgibbs nsoftc->flags |= CD_FLAG_CHANGER; 82139213Sgibbs nchanger->num_devices++; 82239213Sgibbs if (camq_resize(&nchanger->devq, 82339213Sgibbs nchanger->num_devices) != CAM_REQ_CMP) { 82439213Sgibbs printf("cdregister: camq_resize " 82539213Sgibbs "failed, changer support may " 82639213Sgibbs "be messed up\n"); 82739213Sgibbs } 82839213Sgibbs nsoftc->changer = nchanger; 82939213Sgibbs nsoftc->pinfo.index = CAM_UNQUEUED_INDEX; 83039213Sgibbs 83139213Sgibbs STAILQ_INSERT_TAIL(&nchanger->chluns, 83239213Sgibbs nsoftc, changer_links); 83367928Sken xpt_free_path(path); 83439213Sgibbs } else if (status == CAM_REQ_CMP) 83539213Sgibbs xpt_free_path(path); 83639213Sgibbs else { 83739213Sgibbs printf("cdregister: unable to allocate path\n" 83839213Sgibbs "cdregister: changer support may be " 83939213Sgibbs "broken\n"); 84039213Sgibbs } 84139213Sgibbs 84239213Sgibbs softc->changer = nchanger; 84339213Sgibbs softc->pinfo.index = CAM_UNQUEUED_INDEX; 84439213Sgibbs nchanger->num_devices++; 84539213Sgibbs if (camq_resize(&nchanger->devq, 84639213Sgibbs nchanger->num_devices) != CAM_REQ_CMP) { 84739213Sgibbs printf("cdregister: camq_resize " 84839213Sgibbs "failed, changer support may " 84939213Sgibbs "be messed up\n"); 85039213Sgibbs } 85139213Sgibbs STAILQ_INSERT_TAIL(&nchanger->chluns, softc, 85239213Sgibbs changer_links); 85339213Sgibbs } 85439213Sgibbs } 85539213Sgibbs 85639213Sgibbscdregisterexit: 85739213Sgibbs 85839213Sgibbs /* Lock this peripheral until we are setup */ 85939213Sgibbs /* Can't block */ 86039213Sgibbs cam_periph_lock(periph, PRIBIO); 86139213Sgibbs 86239213Sgibbs if ((softc->flags & CD_FLAG_CHANGER) == 0) 86339213Sgibbs xpt_schedule(periph, /*priority*/5); 86439213Sgibbs else 86539213Sgibbs cdschedule(periph, /*priority*/ 5); 86639213Sgibbs 86739213Sgibbs return(CAM_REQ_CMP); 86839213Sgibbs} 86939213Sgibbs 87039213Sgibbsstatic int 87139213Sgibbscdopen(dev_t dev, int flags, int fmt, struct proc *p) 87239213Sgibbs{ 87351836Sphk struct disklabel *label; 87439213Sgibbs struct cam_periph *periph; 87539213Sgibbs struct cd_softc *softc; 87640020Sken struct ccb_getdev cgd; 87739213Sgibbs u_int32_t size; 87839213Sgibbs int unit, error; 87940603Sken int s; 88039213Sgibbs 88139213Sgibbs unit = dkunit(dev); 88239213Sgibbs periph = cam_extend_get(cdperiphs, unit); 88339213Sgibbs 88439213Sgibbs if (periph == NULL) 88539213Sgibbs return (ENXIO); 88639213Sgibbs 88739213Sgibbs softc = (struct cd_softc *)periph->softc; 88839213Sgibbs 88941297Sken /* 89041297Sken * Grab splsoftcam and hold it until we lock the peripheral. 89141297Sken */ 89240603Sken s = splsoftcam(); 89340603Sken if (softc->flags & CD_FLAG_INVALID) { 89440603Sken splx(s); 89539213Sgibbs return(ENXIO); 89640603Sken } 89739213Sgibbs 89841297Sken if ((error = cam_periph_lock(periph, PRIBIO | PCATCH)) != 0) { 89941297Sken splx(s); 90039213Sgibbs return (error); 90141297Sken } 90239213Sgibbs 90341297Sken splx(s); 90441297Sken 90551836Sphk if (cam_periph_acquire(periph) != CAM_REQ_CMP) 90651836Sphk return(ENXIO); 90740020Sken 90851836Sphk cdprevent(periph, PR_PREVENT); 90939213Sgibbs 91039213Sgibbs /* find out the size */ 91139213Sgibbs if ((error = cdsize(dev, &size)) != 0) { 91251836Sphk cdprevent(periph, PR_ALLOW); 91339213Sgibbs cam_periph_unlock(periph); 91451836Sphk cam_periph_release(periph); 91539213Sgibbs return(error); 91639213Sgibbs } 91739213Sgibbs 91840020Sken /* 91968294Sken * If we get a non-zero return, revert back to not reading the 92068294Sken * label off the disk. The first track is likely audio, which 92168294Sken * won't have a disklabel. 92268294Sken */ 92368294Sken if ((error = cdfirsttrackisdata(periph)) != 0) { 92468294Sken softc->disk.d_dsflags &= ~DSO_COMPATLABEL; 92568294Sken softc->disk.d_dsflags |= DSO_NOLABELS; 92668294Sken error = 0; 92768294Sken } 92868294Sken 92968294Sken /* 93040020Sken * Build prototype label for whole disk. 93140020Sken * Should take information about different data tracks from the 93240020Sken * TOC and put it in the partition table. 93340020Sken */ 93451836Sphk label = &softc->disk.d_label; 93551836Sphk bzero(label, sizeof(*label)); 93651836Sphk label->d_type = DTYPE_SCSI; 93740020Sken 93840020Sken /* 93940020Sken * Grab the inquiry data to get the vendor and product names. 94040020Sken * Put them in the typename and packname for the label. 94140020Sken */ 94240020Sken xpt_setup_ccb(&cgd.ccb_h, periph->path, /*priority*/ 1); 94340020Sken cgd.ccb_h.func_code = XPT_GDEV_TYPE; 94440020Sken xpt_action((union ccb *)&cgd); 94540020Sken 94651836Sphk strncpy(label->d_typename, cgd.inq_data.vendor, 94751836Sphk min(SID_VENDOR_SIZE, sizeof(label->d_typename))); 94851836Sphk strncpy(label->d_packname, cgd.inq_data.product, 94951836Sphk min(SID_PRODUCT_SIZE, sizeof(label->d_packname))); 95040020Sken 95151836Sphk label->d_secsize = softc->params.blksize; 95251836Sphk label->d_secperunit = softc->params.disksize; 95351836Sphk label->d_flags = D_REMOVABLE; 95440020Sken /* 95540020Sken * Make partition 'a' cover the whole disk. This is a temporary 95640020Sken * compatibility hack. The 'a' partition should not exist, so 95740020Sken * the slice code won't create it. The slice code will make 95840020Sken * partition (RAW_PART + 'a') cover the whole disk and fill in 95940020Sken * some more defaults. 96040020Sken */ 96151836Sphk label->d_partitions[0].p_size = label->d_secperunit; 96251836Sphk label->d_partitions[0].p_fstype = FS_OTHER; 96340020Sken 96451836Sphk /* 96551836Sphk * We unconditionally (re)set the blocksize each time the 96651836Sphk * CD device is opened. This is because the CD can change, 96751836Sphk * and therefore the blocksize might change. 96851836Sphk * XXX problems here if some slice or partition is still 96951836Sphk * open with the old size? 97051836Sphk */ 97151836Sphk if ((softc->device_stats.flags & DEVSTAT_BS_UNAVAILABLE) != 0) 97251836Sphk softc->device_stats.flags &= ~DEVSTAT_BS_UNAVAILABLE; 97351836Sphk softc->device_stats.block_size = softc->params.blksize; 97440020Sken 97539213Sgibbs cam_periph_unlock(periph); 97639213Sgibbs 97739213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("leaving cdopen\n")); 97839213Sgibbs 97939213Sgibbs return (error); 98039213Sgibbs} 98139213Sgibbs 98239213Sgibbsstatic int 98339213Sgibbscdclose(dev_t dev, int flag, int fmt, struct proc *p) 98439213Sgibbs{ 98539213Sgibbs struct cam_periph *periph; 98639213Sgibbs struct cd_softc *softc; 98739213Sgibbs int unit, error; 98839213Sgibbs 98939213Sgibbs unit = dkunit(dev); 99039213Sgibbs periph = cam_extend_get(cdperiphs, unit); 99139213Sgibbs if (periph == NULL) 99239213Sgibbs return (ENXIO); 99339213Sgibbs 99439213Sgibbs softc = (struct cd_softc *)periph->softc; 99539213Sgibbs 99639213Sgibbs if ((error = cam_periph_lock(periph, PRIBIO)) != 0) 99739213Sgibbs return (error); 99839213Sgibbs 99939213Sgibbs if ((softc->flags & CD_FLAG_DISC_REMOVABLE) != 0) 100039213Sgibbs cdprevent(periph, PR_ALLOW); 100139213Sgibbs 100239213Sgibbs /* 100368294Sken * Unconditionally set the dsopen() flags back to their default 100468294Sken * state. 100568294Sken */ 100668294Sken softc->disk.d_dsflags &= ~DSO_NOLABELS; 100768294Sken softc->disk.d_dsflags |= DSO_COMPATLABEL; 100868294Sken 100968294Sken /* 101039213Sgibbs * Since we're closing this CD, mark the blocksize as unavailable. 101139213Sgibbs * It will be marked as available whence the CD is opened again. 101239213Sgibbs */ 101339213Sgibbs softc->device_stats.flags |= DEVSTAT_BS_UNAVAILABLE; 101439213Sgibbs 101539213Sgibbs cam_periph_unlock(periph); 101639213Sgibbs cam_periph_release(periph); 101739213Sgibbs 101839213Sgibbs return (0); 101939213Sgibbs} 102039213Sgibbs 102139213Sgibbsstatic void 102239213Sgibbscdshorttimeout(void *arg) 102339213Sgibbs{ 102439213Sgibbs struct cdchanger *changer; 102539213Sgibbs int s; 102639213Sgibbs 102739213Sgibbs s = splsoftcam(); 102839213Sgibbs 102939213Sgibbs changer = (struct cdchanger *)arg; 103039213Sgibbs 103139213Sgibbs /* Always clear the short timeout flag, since that's what we're in */ 103239213Sgibbs changer->flags &= ~CHANGER_SHORT_TMOUT_SCHED; 103339213Sgibbs 103439213Sgibbs /* 103539213Sgibbs * Check to see if there is any more pending or outstanding I/O for 103639213Sgibbs * this device. If not, move it out of the active slot. 103739213Sgibbs */ 103859249Sphk if ((bioq_first(&changer->cur_device->bio_queue) == NULL) 103939213Sgibbs && (changer->cur_device->device_stats.busy_count == 0)) { 104039213Sgibbs changer->flags |= CHANGER_MANUAL_CALL; 104139213Sgibbs cdrunchangerqueue(changer); 104239213Sgibbs } 104339213Sgibbs 104439213Sgibbs splx(s); 104539213Sgibbs} 104639213Sgibbs 104739213Sgibbs/* 104839213Sgibbs * This is a wrapper for xpt_schedule. It only applies to changers. 104939213Sgibbs */ 105039213Sgibbsstatic void 105139213Sgibbscdschedule(struct cam_periph *periph, int priority) 105239213Sgibbs{ 105339213Sgibbs struct cd_softc *softc; 105439213Sgibbs int s; 105539213Sgibbs 105639213Sgibbs s = splsoftcam(); 105739213Sgibbs 105839213Sgibbs softc = (struct cd_softc *)periph->softc; 105939213Sgibbs 106039213Sgibbs /* 106139213Sgibbs * If this device isn't currently queued, and if it isn't 106239213Sgibbs * the active device, then we queue this device and run the 106339213Sgibbs * changer queue if there is no timeout scheduled to do it. 106439213Sgibbs * If this device is the active device, just schedule it 106539213Sgibbs * to run again. If this device is queued, there should be 106639213Sgibbs * a timeout in place already that will make sure it runs. 106739213Sgibbs */ 106839213Sgibbs if ((softc->pinfo.index == CAM_UNQUEUED_INDEX) 106939213Sgibbs && ((softc->flags & CD_FLAG_ACTIVE) == 0)) { 107039213Sgibbs /* 107139213Sgibbs * We don't do anything with the priority here. 107239213Sgibbs * This is strictly a fifo queue. 107339213Sgibbs */ 107439213Sgibbs softc->pinfo.priority = 1; 107545442Sgibbs softc->pinfo.generation = ++softc->changer->devq.generation; 107639213Sgibbs camq_insert(&softc->changer->devq, (cam_pinfo *)softc); 107739213Sgibbs 107839213Sgibbs /* 107939213Sgibbs * Since we just put a device in the changer queue, 108039213Sgibbs * check and see if there is a timeout scheduled for 108139213Sgibbs * this changer. If so, let the timeout handle 108239213Sgibbs * switching this device into the active slot. If 108339213Sgibbs * not, manually call the timeout routine to 108439213Sgibbs * bootstrap things. 108539213Sgibbs */ 108639213Sgibbs if (((softc->changer->flags & CHANGER_TIMEOUT_SCHED)==0) 108746581Sken && ((softc->changer->flags & CHANGER_NEED_TIMEOUT)==0) 108846581Sken && ((softc->changer->flags & CHANGER_SHORT_TMOUT_SCHED)==0)){ 108939213Sgibbs softc->changer->flags |= CHANGER_MANUAL_CALL; 109039213Sgibbs cdrunchangerqueue(softc->changer); 109139213Sgibbs } 109239213Sgibbs } else if ((softc->flags & CD_FLAG_ACTIVE) 109339213Sgibbs && ((softc->flags & CD_FLAG_SCHED_ON_COMP) == 0)) 109439213Sgibbs xpt_schedule(periph, priority); 109539213Sgibbs 109639213Sgibbs splx(s); 109739213Sgibbs 109839213Sgibbs} 109939213Sgibbs 110039213Sgibbsstatic void 110139213Sgibbscdrunchangerqueue(void *arg) 110239213Sgibbs{ 110339213Sgibbs struct cd_softc *softc; 110439213Sgibbs struct cdchanger *changer; 110539213Sgibbs int called_from_timeout; 110639213Sgibbs int s; 110739213Sgibbs 110839213Sgibbs s = splsoftcam(); 110939213Sgibbs 111039213Sgibbs changer = (struct cdchanger *)arg; 111139213Sgibbs 111239213Sgibbs /* 111339213Sgibbs * If we have NOT been called from cdstrategy() or cddone(), and 111439213Sgibbs * instead from a timeout routine, go ahead and clear the 111539213Sgibbs * timeout flag. 111639213Sgibbs */ 111739213Sgibbs if ((changer->flags & CHANGER_MANUAL_CALL) == 0) { 111839213Sgibbs changer->flags &= ~CHANGER_TIMEOUT_SCHED; 111939213Sgibbs called_from_timeout = 1; 112039213Sgibbs } else 112139213Sgibbs called_from_timeout = 0; 112239213Sgibbs 112339213Sgibbs /* Always clear the manual call flag */ 112439213Sgibbs changer->flags &= ~CHANGER_MANUAL_CALL; 112539213Sgibbs 112639213Sgibbs /* nothing to do if the queue is empty */ 112739213Sgibbs if (changer->devq.entries <= 0) { 112839213Sgibbs splx(s); 112939213Sgibbs return; 113039213Sgibbs } 113139213Sgibbs 113239213Sgibbs /* 113339213Sgibbs * If the changer queue is frozen, that means we have an active 113439213Sgibbs * device. 113539213Sgibbs */ 113639213Sgibbs if (changer->devq.qfrozen_cnt > 0) { 113739213Sgibbs 113839213Sgibbs if (changer->cur_device->device_stats.busy_count > 0) { 113939213Sgibbs changer->cur_device->flags |= CD_FLAG_SCHED_ON_COMP; 114039213Sgibbs changer->cur_device->bufs_left = 114139213Sgibbs changer->cur_device->device_stats.busy_count; 114239213Sgibbs if (called_from_timeout) { 114339213Sgibbs changer->long_handle = 114439213Sgibbs timeout(cdrunchangerqueue, changer, 114539213Sgibbs changer_max_busy_seconds * hz); 114639213Sgibbs changer->flags |= CHANGER_TIMEOUT_SCHED; 114739213Sgibbs } 114839213Sgibbs splx(s); 114939213Sgibbs return; 115039213Sgibbs } 115139213Sgibbs 115239213Sgibbs /* 115339213Sgibbs * We always need to reset the frozen count and clear the 115439213Sgibbs * active flag. 115539213Sgibbs */ 115639213Sgibbs changer->devq.qfrozen_cnt--; 115739213Sgibbs changer->cur_device->flags &= ~CD_FLAG_ACTIVE; 115839213Sgibbs changer->cur_device->flags &= ~CD_FLAG_SCHED_ON_COMP; 115939213Sgibbs 116039213Sgibbs /* 116139213Sgibbs * Check to see whether the current device has any I/O left 116239213Sgibbs * to do. If so, requeue it at the end of the queue. If 116339213Sgibbs * not, there is no need to requeue it. 116439213Sgibbs */ 116559249Sphk if (bioq_first(&changer->cur_device->bio_queue) != NULL) { 116639213Sgibbs 116739213Sgibbs changer->cur_device->pinfo.generation = 116845442Sgibbs ++changer->devq.generation; 116939213Sgibbs camq_insert(&changer->devq, 117039213Sgibbs (cam_pinfo *)changer->cur_device); 117139213Sgibbs } 117239213Sgibbs } 117339213Sgibbs 117445845Sgibbs softc = (struct cd_softc *)camq_remove(&changer->devq, CAMQ_HEAD); 117539213Sgibbs 117639213Sgibbs changer->cur_device = softc; 117739213Sgibbs 117839213Sgibbs changer->devq.qfrozen_cnt++; 117939213Sgibbs softc->flags |= CD_FLAG_ACTIVE; 118039213Sgibbs 118139213Sgibbs /* Just in case this device is waiting */ 118239213Sgibbs wakeup(&softc->changer); 118339213Sgibbs xpt_schedule(softc->periph, /*priority*/ 1); 118439213Sgibbs 118539213Sgibbs /* 118639213Sgibbs * Get rid of any pending timeouts, and set a flag to schedule new 118739213Sgibbs * ones so this device gets its full time quantum. 118839213Sgibbs */ 118939213Sgibbs if (changer->flags & CHANGER_TIMEOUT_SCHED) { 119039213Sgibbs untimeout(cdrunchangerqueue, changer, changer->long_handle); 119139213Sgibbs changer->flags &= ~CHANGER_TIMEOUT_SCHED; 119239213Sgibbs } 119339213Sgibbs 119439213Sgibbs if (changer->flags & CHANGER_SHORT_TMOUT_SCHED) { 119539213Sgibbs untimeout(cdshorttimeout, changer, changer->short_handle); 119639213Sgibbs changer->flags &= ~CHANGER_SHORT_TMOUT_SCHED; 119739213Sgibbs } 119839213Sgibbs 119939213Sgibbs /* 120039213Sgibbs * We need to schedule timeouts, but we only do this after the 120139213Sgibbs * first transaction has completed. This eliminates the changer 120239213Sgibbs * switch time. 120339213Sgibbs */ 120439213Sgibbs changer->flags |= CHANGER_NEED_TIMEOUT; 120539213Sgibbs 120639213Sgibbs splx(s); 120739213Sgibbs} 120839213Sgibbs 120939213Sgibbsstatic void 121039213Sgibbscdchangerschedule(struct cd_softc *softc) 121139213Sgibbs{ 121239213Sgibbs struct cdchanger *changer; 121339213Sgibbs int s; 121439213Sgibbs 121539213Sgibbs s = splsoftcam(); 121639213Sgibbs 121739213Sgibbs changer = softc->changer; 121839213Sgibbs 121939213Sgibbs /* 122039213Sgibbs * If this is a changer, and this is the current device, 122139213Sgibbs * and this device has at least the minimum time quantum to 122239213Sgibbs * run, see if we can switch it out. 122339213Sgibbs */ 122439213Sgibbs if ((softc->flags & CD_FLAG_ACTIVE) 122539213Sgibbs && ((changer->flags & CHANGER_SHORT_TMOUT_SCHED) == 0) 122639213Sgibbs && ((changer->flags & CHANGER_NEED_TIMEOUT) == 0)) { 122739213Sgibbs /* 122839213Sgibbs * We try three things here. The first is that we 122939213Sgibbs * check to see whether the schedule on completion 123039213Sgibbs * flag is set. If it is, we decrement the number 123139213Sgibbs * of buffers left, and if it's zero, we reschedule. 123239213Sgibbs * Next, we check to see whether the pending buffer 123339213Sgibbs * queue is empty and whether there are no 123439213Sgibbs * outstanding transactions. If so, we reschedule. 123539213Sgibbs * Next, we see if the pending buffer queue is empty. 123639213Sgibbs * If it is, we set the number of buffers left to 123739213Sgibbs * the current active buffer count and set the 123839213Sgibbs * schedule on complete flag. 123939213Sgibbs */ 124039213Sgibbs if (softc->flags & CD_FLAG_SCHED_ON_COMP) { 124139213Sgibbs if (--softc->bufs_left == 0) { 124239213Sgibbs softc->changer->flags |= 124339213Sgibbs CHANGER_MANUAL_CALL; 124439213Sgibbs softc->flags &= ~CD_FLAG_SCHED_ON_COMP; 124539213Sgibbs cdrunchangerqueue(softc->changer); 124639213Sgibbs } 124759249Sphk } else if ((bioq_first(&softc->bio_queue) == NULL) 124839213Sgibbs && (softc->device_stats.busy_count == 0)) { 124939213Sgibbs softc->changer->flags |= CHANGER_MANUAL_CALL; 125039213Sgibbs cdrunchangerqueue(softc->changer); 125139213Sgibbs } 125239213Sgibbs } else if ((softc->changer->flags & CHANGER_NEED_TIMEOUT) 125339213Sgibbs && (softc->flags & CD_FLAG_ACTIVE)) { 125439213Sgibbs 125539213Sgibbs /* 125639213Sgibbs * Now that the first transaction to this 125739213Sgibbs * particular device has completed, we can go ahead 125839213Sgibbs * and schedule our timeouts. 125939213Sgibbs */ 126039213Sgibbs if ((changer->flags & CHANGER_TIMEOUT_SCHED) == 0) { 126139213Sgibbs changer->long_handle = 126239213Sgibbs timeout(cdrunchangerqueue, changer, 126339213Sgibbs changer_max_busy_seconds * hz); 126439213Sgibbs changer->flags |= CHANGER_TIMEOUT_SCHED; 126539213Sgibbs } else 126639213Sgibbs printf("cdchangerschedule: already have a long" 126739213Sgibbs " timeout!\n"); 126839213Sgibbs 126939213Sgibbs if ((changer->flags & CHANGER_SHORT_TMOUT_SCHED) == 0) { 127039213Sgibbs changer->short_handle = 127139213Sgibbs timeout(cdshorttimeout, changer, 127239213Sgibbs changer_min_busy_seconds * hz); 127339213Sgibbs changer->flags |= CHANGER_SHORT_TMOUT_SCHED; 127439213Sgibbs } else 127539213Sgibbs printf("cdchangerschedule: already have a short " 127639213Sgibbs "timeout!\n"); 127739213Sgibbs 127839213Sgibbs /* 127939213Sgibbs * We just scheduled timeouts, no need to schedule 128039213Sgibbs * more. 128139213Sgibbs */ 128239213Sgibbs changer->flags &= ~CHANGER_NEED_TIMEOUT; 128339213Sgibbs 128439213Sgibbs } 128539213Sgibbs splx(s); 128639213Sgibbs} 128739213Sgibbs 128839213Sgibbsstatic int 128939213Sgibbscdrunccb(union ccb *ccb, int (*error_routine)(union ccb *ccb, 129039213Sgibbs u_int32_t cam_flags, 129139213Sgibbs u_int32_t sense_flags), 129239213Sgibbs u_int32_t cam_flags, u_int32_t sense_flags) 129339213Sgibbs{ 129439213Sgibbs struct cd_softc *softc; 129539213Sgibbs struct cam_periph *periph; 129639213Sgibbs int error; 129739213Sgibbs 129839213Sgibbs periph = xpt_path_periph(ccb->ccb_h.path); 129939213Sgibbs softc = (struct cd_softc *)periph->softc; 130039213Sgibbs 130139213Sgibbs error = cam_periph_runccb(ccb, error_routine, cam_flags, sense_flags, 130239213Sgibbs &softc->device_stats); 130339213Sgibbs 130439213Sgibbs if (softc->flags & CD_FLAG_CHANGER) 130539213Sgibbs cdchangerschedule(softc); 130639213Sgibbs 130739213Sgibbs return(error); 130839213Sgibbs} 130939213Sgibbs 131042017Seivindstatic union ccb * 131139213Sgibbscdgetccb(struct cam_periph *periph, u_int32_t priority) 131239213Sgibbs{ 131339213Sgibbs struct cd_softc *softc; 131439213Sgibbs int s; 131539213Sgibbs 131639213Sgibbs softc = (struct cd_softc *)periph->softc; 131739213Sgibbs 131839213Sgibbs if (softc->flags & CD_FLAG_CHANGER) { 131939213Sgibbs 132039213Sgibbs s = splsoftcam(); 132139213Sgibbs 132239213Sgibbs /* 132339213Sgibbs * This should work the first time this device is woken up, 132439213Sgibbs * but just in case it doesn't, we use a while loop. 132539213Sgibbs */ 132646581Sken while ((softc->flags & CD_FLAG_ACTIVE) == 0) { 132739213Sgibbs /* 132839213Sgibbs * If this changer isn't already queued, queue it up. 132939213Sgibbs */ 133039213Sgibbs if (softc->pinfo.index == CAM_UNQUEUED_INDEX) { 133139213Sgibbs softc->pinfo.priority = 1; 133239213Sgibbs softc->pinfo.generation = 133345442Sgibbs ++softc->changer->devq.generation; 133439213Sgibbs camq_insert(&softc->changer->devq, 133539213Sgibbs (cam_pinfo *)softc); 133639213Sgibbs } 133746581Sken if (((softc->changer->flags & CHANGER_TIMEOUT_SCHED)==0) 133846581Sken && ((softc->changer->flags & CHANGER_NEED_TIMEOUT)==0) 133946581Sken && ((softc->changer->flags 134046581Sken & CHANGER_SHORT_TMOUT_SCHED)==0)) { 134139213Sgibbs softc->changer->flags |= CHANGER_MANUAL_CALL; 134239213Sgibbs cdrunchangerqueue(softc->changer); 134339213Sgibbs } else 134439213Sgibbs tsleep(&softc->changer, PRIBIO, "cgticb", 0); 134539213Sgibbs } 134639213Sgibbs splx(s); 134739213Sgibbs } 134839213Sgibbs return(cam_periph_getccb(periph, priority)); 134939213Sgibbs} 135039213Sgibbs 135139213Sgibbs 135239213Sgibbs/* 135339213Sgibbs * Actually translate the requested transfer into one the physical driver 135439213Sgibbs * can understand. The transfer is described by a buf and will include 135539213Sgibbs * only one physical transfer. 135639213Sgibbs */ 135739213Sgibbsstatic void 135859249Sphkcdstrategy(struct bio *bp) 135939213Sgibbs{ 136039213Sgibbs struct cam_periph *periph; 136139213Sgibbs struct cd_softc *softc; 136239213Sgibbs u_int unit, part; 136339213Sgibbs int s; 136439213Sgibbs 136559249Sphk unit = dkunit(bp->bio_dev); 136659249Sphk part = dkpart(bp->bio_dev); 136739213Sgibbs periph = cam_extend_get(cdperiphs, unit); 136839213Sgibbs if (periph == NULL) { 136976362Sphk biofinish(bp, NULL, ENXIO); 137076362Sphk return; 137139213Sgibbs } 137239213Sgibbs 137339213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdstrategy\n")); 137439213Sgibbs 137539213Sgibbs softc = (struct cd_softc *)periph->softc; 137639213Sgibbs 137739213Sgibbs /* 137839213Sgibbs * Mask interrupts so that the pack cannot be invalidated until 137939213Sgibbs * after we are in the queue. Otherwise, we might not properly 138039213Sgibbs * clean up one of the buffers. 138139213Sgibbs */ 138239213Sgibbs s = splbio(); 138339213Sgibbs 138439213Sgibbs /* 138539213Sgibbs * If the device has been made invalid, error out 138639213Sgibbs */ 138739213Sgibbs if ((softc->flags & CD_FLAG_INVALID)) { 138839213Sgibbs splx(s); 138976362Sphk biofinish(bp, NULL, ENXIO); 139076362Sphk return; 139139213Sgibbs } 139239213Sgibbs 139339213Sgibbs /* 139439213Sgibbs * Place it in the queue of disk activities for this disk 139539213Sgibbs */ 139659249Sphk bioqdisksort(&softc->bio_queue, bp); 139739213Sgibbs 139839213Sgibbs splx(s); 139939213Sgibbs 140039213Sgibbs /* 140139213Sgibbs * Schedule ourselves for performing the work. We do things 140239213Sgibbs * differently for changers. 140339213Sgibbs */ 140439213Sgibbs if ((softc->flags & CD_FLAG_CHANGER) == 0) 140539213Sgibbs xpt_schedule(periph, /* XXX priority */1); 140639213Sgibbs else 140739213Sgibbs cdschedule(periph, /* priority */ 1); 140839213Sgibbs 140939213Sgibbs return; 141039213Sgibbs} 141139213Sgibbs 141239213Sgibbsstatic void 141339213Sgibbscdstart(struct cam_periph *periph, union ccb *start_ccb) 141439213Sgibbs{ 141539213Sgibbs struct cd_softc *softc; 141659249Sphk struct bio *bp; 141739213Sgibbs struct ccb_scsiio *csio; 141839213Sgibbs struct scsi_read_capacity_data *rcap; 141939213Sgibbs int s; 142039213Sgibbs 142139213Sgibbs softc = (struct cd_softc *)periph->softc; 142239213Sgibbs 142339213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdstart\n")); 142439213Sgibbs 142539213Sgibbs switch (softc->state) { 142639213Sgibbs case CD_STATE_NORMAL: 142739213Sgibbs { 142839213Sgibbs int oldspl; 142939213Sgibbs 143039213Sgibbs s = splbio(); 143159249Sphk bp = bioq_first(&softc->bio_queue); 143239213Sgibbs if (periph->immediate_priority <= periph->pinfo.priority) { 143339213Sgibbs start_ccb->ccb_h.ccb_state = CD_CCB_WAITING; 143439213Sgibbs 143539213Sgibbs SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, 143639213Sgibbs periph_links.sle); 143739213Sgibbs periph->immediate_priority = CAM_PRIORITY_NONE; 143839213Sgibbs splx(s); 143939213Sgibbs wakeup(&periph->ccb_list); 144039213Sgibbs } else if (bp == NULL) { 144139213Sgibbs splx(s); 144239213Sgibbs xpt_release_ccb(start_ccb); 144339213Sgibbs } else { 144459249Sphk bioq_remove(&softc->bio_queue, bp); 144539213Sgibbs 144639213Sgibbs devstat_start_transaction(&softc->device_stats); 144739213Sgibbs 144839213Sgibbs scsi_read_write(&start_ccb->csio, 144939213Sgibbs /*retries*/4, 145039213Sgibbs /* cbfcnp */ cddone, 145159249Sphk (bp->bio_flags & BIO_ORDERED) != 0 ? 145239213Sgibbs MSG_ORDERED_Q_TAG : 145339213Sgibbs MSG_SIMPLE_Q_TAG, 145459249Sphk /* read */bp->bio_cmd == BIO_READ, 145539213Sgibbs /* byte2 */ 0, 145639213Sgibbs /* minimum_cmd_size */ 10, 145759249Sphk /* lba */ bp->bio_pblkno, 145859249Sphk bp->bio_bcount / softc->params.blksize, 145959249Sphk /* data_ptr */ bp->bio_data, 146059249Sphk /* dxfer_len */ bp->bio_bcount, 146139213Sgibbs /* sense_len */ SSD_FULL_SIZE, 146239213Sgibbs /* timeout */ 30000); 146339213Sgibbs start_ccb->ccb_h.ccb_state = CD_CCB_BUFFER_IO; 146439213Sgibbs 146539213Sgibbs 146639213Sgibbs /* 146739213Sgibbs * Block out any asyncronous callbacks 146839213Sgibbs * while we touch the pending ccb list. 146939213Sgibbs */ 147039213Sgibbs oldspl = splcam(); 147139213Sgibbs LIST_INSERT_HEAD(&softc->pending_ccbs, 147239213Sgibbs &start_ccb->ccb_h, periph_links.le); 147339213Sgibbs splx(oldspl); 147439213Sgibbs 147539213Sgibbs /* We expect a unit attention from this device */ 147639213Sgibbs if ((softc->flags & CD_FLAG_RETRY_UA) != 0) { 147739213Sgibbs start_ccb->ccb_h.ccb_state |= CD_CCB_RETRY_UA; 147839213Sgibbs softc->flags &= ~CD_FLAG_RETRY_UA; 147939213Sgibbs } 148039213Sgibbs 148139213Sgibbs start_ccb->ccb_h.ccb_bp = bp; 148259249Sphk bp = bioq_first(&softc->bio_queue); 148339213Sgibbs splx(s); 148439213Sgibbs 148539213Sgibbs xpt_action(start_ccb); 148639213Sgibbs } 148739213Sgibbs if (bp != NULL) { 148839213Sgibbs /* Have more work to do, so ensure we stay scheduled */ 148939213Sgibbs xpt_schedule(periph, /* XXX priority */1); 149039213Sgibbs } 149139213Sgibbs break; 149239213Sgibbs } 149339213Sgibbs case CD_STATE_PROBE: 149439213Sgibbs { 149539213Sgibbs 149639213Sgibbs rcap = (struct scsi_read_capacity_data *)malloc(sizeof(*rcap), 149739213Sgibbs M_TEMP, 149839213Sgibbs M_NOWAIT); 149939213Sgibbs if (rcap == NULL) { 150039213Sgibbs xpt_print_path(periph->path); 150139213Sgibbs printf("cdstart: Couldn't malloc read_capacity data\n"); 150239213Sgibbs /* cd_free_periph??? */ 150339213Sgibbs break; 150439213Sgibbs } 150539213Sgibbs csio = &start_ccb->csio; 150639213Sgibbs scsi_read_capacity(csio, 150739213Sgibbs /*retries*/1, 150839213Sgibbs cddone, 150939213Sgibbs MSG_SIMPLE_Q_TAG, 151039213Sgibbs rcap, 151139213Sgibbs SSD_FULL_SIZE, 151239213Sgibbs /*timeout*/20000); 151339213Sgibbs start_ccb->ccb_h.ccb_bp = NULL; 151439213Sgibbs start_ccb->ccb_h.ccb_state = CD_CCB_PROBE; 151539213Sgibbs xpt_action(start_ccb); 151639213Sgibbs break; 151739213Sgibbs } 151839213Sgibbs } 151939213Sgibbs} 152039213Sgibbs 152139213Sgibbsstatic void 152239213Sgibbscddone(struct cam_periph *periph, union ccb *done_ccb) 152339213Sgibbs{ 152439213Sgibbs struct cd_softc *softc; 152539213Sgibbs struct ccb_scsiio *csio; 152639213Sgibbs 152739213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cddone\n")); 152839213Sgibbs 152939213Sgibbs softc = (struct cd_softc *)periph->softc; 153039213Sgibbs csio = &done_ccb->csio; 153139213Sgibbs 153239213Sgibbs switch (csio->ccb_h.ccb_state & CD_CCB_TYPE_MASK) { 153339213Sgibbs case CD_CCB_BUFFER_IO: 153439213Sgibbs { 153559249Sphk struct bio *bp; 153639213Sgibbs int error; 153739213Sgibbs int oldspl; 153839213Sgibbs 153959249Sphk bp = (struct bio *)done_ccb->ccb_h.ccb_bp; 154039213Sgibbs error = 0; 154139213Sgibbs 154239213Sgibbs if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 154339213Sgibbs int sf; 154439213Sgibbs 154539213Sgibbs if ((done_ccb->ccb_h.ccb_state & CD_CCB_RETRY_UA) != 0) 154639213Sgibbs sf = SF_RETRY_UA; 154739213Sgibbs else 154839213Sgibbs sf = 0; 154946747Sken 155074840Sken error = cderror(done_ccb, CAM_RETRY_SELTO, sf); 155174840Sken if (error == ERESTART) { 155239213Sgibbs /* 155339213Sgibbs * A retry was scheuled, so 155439213Sgibbs * just return. 155539213Sgibbs */ 155639213Sgibbs return; 155739213Sgibbs } 155839213Sgibbs } 155939213Sgibbs 156039213Sgibbs if (error != 0) { 156139213Sgibbs int s; 156259249Sphk struct bio *q_bp; 156339213Sgibbs 156439213Sgibbs xpt_print_path(periph->path); 156539213Sgibbs printf("cddone: got error %#x back\n", error); 156639213Sgibbs s = splbio(); 156759249Sphk while ((q_bp = bioq_first(&softc->bio_queue)) != NULL) { 156859249Sphk bioq_remove(&softc->bio_queue, q_bp); 156959249Sphk q_bp->bio_resid = q_bp->bio_bcount; 157076322Sphk biofinish(q_bp, NULL, EIO); 157139213Sgibbs } 157239213Sgibbs splx(s); 157359249Sphk bp->bio_resid = bp->bio_bcount; 157459249Sphk bp->bio_error = error; 157559249Sphk bp->bio_flags |= BIO_ERROR; 157639213Sgibbs cam_release_devq(done_ccb->ccb_h.path, 157739213Sgibbs /*relsim_flags*/0, 157839213Sgibbs /*reduction*/0, 157939213Sgibbs /*timeout*/0, 158039213Sgibbs /*getcount_only*/0); 158139213Sgibbs 158239213Sgibbs } else { 158359249Sphk bp->bio_resid = csio->resid; 158459249Sphk bp->bio_error = 0; 158559249Sphk if (bp->bio_resid != 0) { 158639213Sgibbs /* Short transfer ??? */ 158759249Sphk bp->bio_flags |= BIO_ERROR; 158839213Sgibbs } 158939213Sgibbs } 159039213Sgibbs 159139213Sgibbs /* 159239213Sgibbs * Block out any asyncronous callbacks 159339213Sgibbs * while we touch the pending ccb list. 159439213Sgibbs */ 159539213Sgibbs oldspl = splcam(); 159639213Sgibbs LIST_REMOVE(&done_ccb->ccb_h, periph_links.le); 159739213Sgibbs splx(oldspl); 159839213Sgibbs 159939213Sgibbs if (softc->flags & CD_FLAG_CHANGER) 160039213Sgibbs cdchangerschedule(softc); 160139213Sgibbs 160276322Sphk biofinish(bp, &softc->device_stats, 0); 160339213Sgibbs break; 160439213Sgibbs } 160539213Sgibbs case CD_CCB_PROBE: 160639213Sgibbs { 160739213Sgibbs struct scsi_read_capacity_data *rdcap; 160839213Sgibbs char announce_buf[120]; /* 160939213Sgibbs * Currently (9/30/97) the 161039213Sgibbs * longest possible announce 161139213Sgibbs * buffer is 108 bytes, for the 161239213Sgibbs * first error case below. 161339213Sgibbs * That is 39 bytes for the 161439213Sgibbs * basic string, 16 bytes for the 161539213Sgibbs * biggest sense key (hardware 161639213Sgibbs * error), 52 bytes for the 161739213Sgibbs * text of the largest sense 161839213Sgibbs * qualifier valid for a CDROM, 161939213Sgibbs * (0x72, 0x03 or 0x04, 162039213Sgibbs * 0x03), and one byte for the 162139213Sgibbs * null terminating character. 162239213Sgibbs * To allow for longer strings, 162339213Sgibbs * the announce buffer is 120 162439213Sgibbs * bytes. 162539213Sgibbs */ 162639213Sgibbs struct cd_params *cdp; 162739213Sgibbs 162839213Sgibbs cdp = &softc->params; 162939213Sgibbs 163039213Sgibbs rdcap = (struct scsi_read_capacity_data *)csio->data_ptr; 163139213Sgibbs 163239213Sgibbs cdp->disksize = scsi_4btoul (rdcap->addr) + 1; 163339213Sgibbs cdp->blksize = scsi_4btoul (rdcap->length); 163439213Sgibbs 163539213Sgibbs if ((csio->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 163639213Sgibbs 163741514Sarchie snprintf(announce_buf, sizeof(announce_buf), 163840020Sken "cd present [%lu x %lu byte records]", 163940020Sken cdp->disksize, (u_long)cdp->blksize); 164039213Sgibbs 164139213Sgibbs } else { 164239213Sgibbs int error; 164339213Sgibbs /* 164439213Sgibbs * Retry any UNIT ATTENTION type errors. They 164539213Sgibbs * are expected at boot. 164639213Sgibbs */ 164774840Sken error = cderror(done_ccb, CAM_RETRY_SELTO, 164874840Sken SF_RETRY_UA | SF_NO_PRINT); 164939213Sgibbs if (error == ERESTART) { 165039213Sgibbs /* 165139213Sgibbs * A retry was scheuled, so 165239213Sgibbs * just return. 165339213Sgibbs */ 165439213Sgibbs return; 165539213Sgibbs } else if (error != 0) { 165639213Sgibbs 165739213Sgibbs struct scsi_sense_data *sense; 165839213Sgibbs int asc, ascq; 165939213Sgibbs int sense_key, error_code; 166039213Sgibbs int have_sense; 166139213Sgibbs cam_status status; 166239213Sgibbs struct ccb_getdev cgd; 166339213Sgibbs 166439213Sgibbs /* Don't wedge this device's queue */ 166539213Sgibbs cam_release_devq(done_ccb->ccb_h.path, 166639213Sgibbs /*relsim_flags*/0, 166739213Sgibbs /*reduction*/0, 166839213Sgibbs /*timeout*/0, 166939213Sgibbs /*getcount_only*/0); 167039213Sgibbs 167139213Sgibbs status = done_ccb->ccb_h.status; 167239213Sgibbs 167339213Sgibbs xpt_setup_ccb(&cgd.ccb_h, 167439213Sgibbs done_ccb->ccb_h.path, 167539213Sgibbs /* priority */ 1); 167639213Sgibbs cgd.ccb_h.func_code = XPT_GDEV_TYPE; 167739213Sgibbs xpt_action((union ccb *)&cgd); 167839213Sgibbs 167939213Sgibbs if (((csio->ccb_h.flags & CAM_SENSE_PHYS) != 0) 168039213Sgibbs || ((csio->ccb_h.flags & CAM_SENSE_PTR) != 0) 168139213Sgibbs || ((status & CAM_AUTOSNS_VALID) == 0)) 168239213Sgibbs have_sense = FALSE; 168339213Sgibbs else 168439213Sgibbs have_sense = TRUE; 168539213Sgibbs 168639213Sgibbs if (have_sense) { 168739213Sgibbs sense = &csio->sense_data; 168839213Sgibbs scsi_extract_sense(sense, &error_code, 168939213Sgibbs &sense_key, 169039213Sgibbs &asc, &ascq); 169139213Sgibbs } 169239213Sgibbs /* 169346581Sken * Attach to anything that claims to be a 169446581Sken * CDROM or WORM device, as long as it 169546581Sken * doesn't return a "Logical unit not 169646581Sken * supported" (0x25) error. 169739213Sgibbs */ 169846581Sken if ((have_sense) && (asc != 0x25) 169974840Sken && (error_code == SSD_CURRENT_ERROR)) { 170074840Sken const char *sense_key_desc; 170174840Sken const char *asc_desc; 170274840Sken 170374840Sken scsi_sense_desc(sense_key, asc, ascq, 170474840Sken &cgd.inq_data, 170574840Sken &sense_key_desc, 170674840Sken &asc_desc); 170741514Sarchie snprintf(announce_buf, 170841514Sarchie sizeof(announce_buf), 170939213Sgibbs "Attempt to query device " 171039213Sgibbs "size failed: %s, %s", 171174840Sken sense_key_desc, 171274840Sken asc_desc); 171374840Sken } else if (SID_TYPE(&cgd.inq_data) == T_CDROM) { 171439213Sgibbs /* 171539213Sgibbs * We only print out an error for 171639213Sgibbs * CDROM type devices. For WORM 171739213Sgibbs * devices, we don't print out an 171839213Sgibbs * error since a few WORM devices 171939213Sgibbs * don't support CDROM commands. 172039213Sgibbs * If we have sense information, go 172139213Sgibbs * ahead and print it out. 172239213Sgibbs * Otherwise, just say that we 172339213Sgibbs * couldn't attach. 172439213Sgibbs */ 172539213Sgibbs 172639213Sgibbs /* 172739213Sgibbs * Just print out the error, not 172839213Sgibbs * the full probe message, when we 172939213Sgibbs * don't attach. 173039213Sgibbs */ 173140020Sken if (have_sense) 173240020Sken scsi_sense_print( 173340020Sken &done_ccb->csio); 173440020Sken else { 173540020Sken xpt_print_path(periph->path); 173640020Sken printf("got CAM status %#x\n", 173740020Sken done_ccb->ccb_h.status); 173840020Sken } 173940020Sken xpt_print_path(periph->path); 174040020Sken printf("fatal error, failed" 174140603Sken " to attach to device\n"); 174239213Sgibbs 174339213Sgibbs /* 174440603Sken * Invalidate this peripheral. 174539213Sgibbs */ 174639213Sgibbs cam_periph_invalidate(periph); 174740020Sken 174840020Sken announce_buf[0] = '\0'; 174939213Sgibbs } else { 175040603Sken 175139213Sgibbs /* 175240603Sken * Invalidate this peripheral. 175339213Sgibbs */ 175439213Sgibbs cam_periph_invalidate(periph); 175540020Sken announce_buf[0] = '\0'; 175639213Sgibbs } 175739213Sgibbs } 175839213Sgibbs } 175939213Sgibbs free(rdcap, M_TEMP); 176042378Smjacob if (announce_buf[0] != '\0') { 176139213Sgibbs xpt_announce_periph(periph, announce_buf); 176242378Smjacob if (softc->flags & CD_FLAG_CHANGER) 176342378Smjacob cdchangerschedule(softc); 176442378Smjacob } 176540020Sken softc->state = CD_STATE_NORMAL; 176642378Smjacob /* 176742378Smjacob * Since our peripheral may be invalidated by an error 176842378Smjacob * above or an external event, we must release our CCB 176942378Smjacob * before releasing the probe lock on the peripheral. 177042378Smjacob * The peripheral will only go away once the last lock 177142378Smjacob * is removed, and we need it around for the CCB release 177242378Smjacob * operation. 177342378Smjacob */ 177442378Smjacob xpt_release_ccb(done_ccb); 177540020Sken cam_periph_unlock(periph); 177642378Smjacob return; 177739213Sgibbs } 177839213Sgibbs case CD_CCB_WAITING: 177939213Sgibbs { 178039213Sgibbs /* Caller will release the CCB */ 178139213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, 178239213Sgibbs ("trying to wakeup ccbwait\n")); 178339213Sgibbs 178439213Sgibbs wakeup(&done_ccb->ccb_h.cbfcnp); 178539213Sgibbs return; 178639213Sgibbs } 178742378Smjacob default: 178842378Smjacob break; 178939213Sgibbs } 179039213Sgibbs xpt_release_ccb(done_ccb); 179139213Sgibbs} 179239213Sgibbs 179339213Sgibbsstatic int 179439213Sgibbscdioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) 179539213Sgibbs{ 179639213Sgibbs 179739213Sgibbs struct cam_periph *periph; 179839213Sgibbs struct cd_softc *softc; 179940020Sken int error, unit; 180039213Sgibbs 180139213Sgibbs unit = dkunit(dev); 180239213Sgibbs 180339213Sgibbs periph = cam_extend_get(cdperiphs, unit); 180439213Sgibbs if (periph == NULL) 180539213Sgibbs return(ENXIO); 180639213Sgibbs 180739213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdioctl\n")); 180839213Sgibbs 180939213Sgibbs softc = (struct cd_softc *)periph->softc; 181039213Sgibbs 181139213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, 181240020Sken ("trying to do ioctl %#lx\n", cmd)); 181339213Sgibbs 181440020Sken error = cam_periph_lock(periph, PRIBIO | PCATCH); 181539213Sgibbs 181640020Sken if (error != 0) 181740020Sken return(error); 181840020Sken 181939213Sgibbs switch (cmd) { 182039213Sgibbs 182139213Sgibbs case CDIOCPLAYTRACKS: 182239213Sgibbs { 182339213Sgibbs struct ioc_play_track *args 182439213Sgibbs = (struct ioc_play_track *) addr; 182539213Sgibbs struct cd_mode_data *data; 182639213Sgibbs 182739213Sgibbs data = malloc(sizeof(struct cd_mode_data), M_TEMP, 182839213Sgibbs M_WAITOK); 182939213Sgibbs 183039213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 183139213Sgibbs ("trying to do CDIOCPLAYTRACKS\n")); 183239213Sgibbs 183339213Sgibbs error = cdgetmode(periph, data, AUDIO_PAGE); 183439213Sgibbs if (error) { 183539213Sgibbs free(data, M_TEMP); 183639213Sgibbs break; 183739213Sgibbs } 183839213Sgibbs data->page.audio.flags &= ~CD_PA_SOTC; 183939213Sgibbs data->page.audio.flags |= CD_PA_IMMED; 184039213Sgibbs error = cdsetmode(periph, data); 184139213Sgibbs free(data, M_TEMP); 184239213Sgibbs if (error) 184339213Sgibbs break; 184439213Sgibbs if (softc->quirks & CD_Q_BCD_TRACKS) { 184539213Sgibbs args->start_track = bin2bcd(args->start_track); 184639213Sgibbs args->end_track = bin2bcd(args->end_track); 184739213Sgibbs } 184839213Sgibbs error = cdplaytracks(periph, 184939213Sgibbs args->start_track, 185039213Sgibbs args->start_index, 185139213Sgibbs args->end_track, 185239213Sgibbs args->end_index); 185339213Sgibbs } 185439213Sgibbs break; 185539213Sgibbs case CDIOCPLAYMSF: 185639213Sgibbs { 185739213Sgibbs struct ioc_play_msf *args 185839213Sgibbs = (struct ioc_play_msf *) addr; 185939213Sgibbs struct cd_mode_data *data; 186039213Sgibbs 186139213Sgibbs data = malloc(sizeof(struct cd_mode_data), M_TEMP, 186239213Sgibbs M_WAITOK); 186339213Sgibbs 186439213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 186539213Sgibbs ("trying to do CDIOCPLAYMSF\n")); 186639213Sgibbs 186739213Sgibbs error = cdgetmode(periph, data, AUDIO_PAGE); 186839213Sgibbs if (error) { 186939213Sgibbs free(data, M_TEMP); 187039213Sgibbs break; 187139213Sgibbs } 187239213Sgibbs data->page.audio.flags &= ~CD_PA_SOTC; 187339213Sgibbs data->page.audio.flags |= CD_PA_IMMED; 187439213Sgibbs error = cdsetmode(periph, data); 187539213Sgibbs free(data, M_TEMP); 187639213Sgibbs if (error) 187739213Sgibbs break; 187839213Sgibbs error = cdplaymsf(periph, 187939213Sgibbs args->start_m, 188039213Sgibbs args->start_s, 188139213Sgibbs args->start_f, 188239213Sgibbs args->end_m, 188339213Sgibbs args->end_s, 188439213Sgibbs args->end_f); 188539213Sgibbs } 188639213Sgibbs break; 188739213Sgibbs case CDIOCPLAYBLOCKS: 188839213Sgibbs { 188939213Sgibbs struct ioc_play_blocks *args 189039213Sgibbs = (struct ioc_play_blocks *) addr; 189139213Sgibbs struct cd_mode_data *data; 189239213Sgibbs 189339213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 189439213Sgibbs ("trying to do CDIOCPLAYBLOCKS\n")); 189539213Sgibbs 189639213Sgibbs data = malloc(sizeof(struct cd_mode_data), M_TEMP, 189739213Sgibbs M_WAITOK); 189839213Sgibbs 189939213Sgibbs error = cdgetmode(periph, data, AUDIO_PAGE); 190039213Sgibbs if (error) { 190139213Sgibbs free(data, M_TEMP); 190239213Sgibbs break; 190339213Sgibbs } 190439213Sgibbs data->page.audio.flags &= ~CD_PA_SOTC; 190539213Sgibbs data->page.audio.flags |= CD_PA_IMMED; 190639213Sgibbs error = cdsetmode(periph, data); 190739213Sgibbs free(data, M_TEMP); 190839213Sgibbs if (error) 190939213Sgibbs break; 191039213Sgibbs error = cdplay(periph, args->blk, args->len); 191139213Sgibbs } 191239213Sgibbs break; 191339213Sgibbs case CDIOCREADSUBCHANNEL: 191439213Sgibbs { 191539213Sgibbs struct ioc_read_subchannel *args 191639213Sgibbs = (struct ioc_read_subchannel *) addr; 191739213Sgibbs struct cd_sub_channel_info *data; 191839213Sgibbs u_int32_t len = args->data_len; 191939213Sgibbs 192039213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 192139213Sgibbs ("trying to do CDIOCREADSUBCHANNEL\n")); 192239213Sgibbs 192339213Sgibbs data = malloc(sizeof(struct cd_sub_channel_info), 192439213Sgibbs M_TEMP, M_WAITOK); 192539213Sgibbs 192639213Sgibbs if ((len > sizeof(struct cd_sub_channel_info)) || 192739213Sgibbs (len < sizeof(struct cd_sub_channel_header))) { 192839213Sgibbs printf( 192939213Sgibbs "scsi_cd: cdioctl: " 193039213Sgibbs "cdioreadsubchannel: error, len=%d\n", 193139213Sgibbs len); 193239213Sgibbs error = EINVAL; 193339213Sgibbs free(data, M_TEMP); 193439213Sgibbs break; 193539213Sgibbs } 193639213Sgibbs 193739213Sgibbs if (softc->quirks & CD_Q_BCD_TRACKS) 193839213Sgibbs args->track = bin2bcd(args->track); 193939213Sgibbs 194039213Sgibbs error = cdreadsubchannel(periph, args->address_format, 194139213Sgibbs args->data_format, args->track, data, len); 194239213Sgibbs 194339213Sgibbs if (error) { 194439213Sgibbs free(data, M_TEMP); 194539213Sgibbs break; 194639213Sgibbs } 194739213Sgibbs if (softc->quirks & CD_Q_BCD_TRACKS) 194839213Sgibbs data->what.track_info.track_number = 194939213Sgibbs bcd2bin(data->what.track_info.track_number); 195039213Sgibbs len = min(len, ((data->header.data_len[0] << 8) + 195139213Sgibbs data->header.data_len[1] + 195239213Sgibbs sizeof(struct cd_sub_channel_header))); 195339213Sgibbs if (copyout(data, args->data, len) != 0) { 195439213Sgibbs error = EFAULT; 195539213Sgibbs } 195639213Sgibbs free(data, M_TEMP); 195739213Sgibbs } 195839213Sgibbs break; 195939213Sgibbs 196039213Sgibbs case CDIOREADTOCHEADER: 196139213Sgibbs { 196239213Sgibbs struct ioc_toc_header *th; 196339213Sgibbs 196439213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 196539213Sgibbs ("trying to do CDIOREADTOCHEADER\n")); 196639213Sgibbs 196739213Sgibbs th = malloc(sizeof(struct ioc_toc_header), M_TEMP, 196839213Sgibbs M_WAITOK); 196939213Sgibbs error = cdreadtoc(periph, 0, 0, 197039213Sgibbs (struct cd_toc_entry *)th, 197139213Sgibbs sizeof (*th)); 197239213Sgibbs if (error) { 197339213Sgibbs free(th, M_TEMP); 197439213Sgibbs break; 197539213Sgibbs } 197639213Sgibbs if (softc->quirks & CD_Q_BCD_TRACKS) { 197739213Sgibbs /* we are going to have to convert the BCD 197839213Sgibbs * encoding on the cd to what is expected 197939213Sgibbs */ 198039213Sgibbs th->starting_track = 198139213Sgibbs bcd2bin(th->starting_track); 198239213Sgibbs th->ending_track = bcd2bin(th->ending_track); 198339213Sgibbs } 198439213Sgibbs NTOHS(th->len); 198539213Sgibbs bcopy(th, addr, sizeof(*th)); 198639213Sgibbs free(th, M_TEMP); 198739213Sgibbs } 198839213Sgibbs break; 198939213Sgibbs case CDIOREADTOCENTRYS: 199039213Sgibbs { 199139213Sgibbs typedef struct { 199239213Sgibbs struct ioc_toc_header header; 199339213Sgibbs struct cd_toc_entry entries[100]; 199439213Sgibbs } data_t; 199539213Sgibbs typedef struct { 199639213Sgibbs struct ioc_toc_header header; 199739213Sgibbs struct cd_toc_entry entry; 199839213Sgibbs } lead_t; 199939213Sgibbs 200039213Sgibbs data_t *data; 200139213Sgibbs lead_t *lead; 200239213Sgibbs struct ioc_read_toc_entry *te = 200339213Sgibbs (struct ioc_read_toc_entry *) addr; 200439213Sgibbs struct ioc_toc_header *th; 200539213Sgibbs u_int32_t len, readlen, idx, num; 200639213Sgibbs u_int32_t starting_track = te->starting_track; 200739213Sgibbs 200839213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 200939213Sgibbs ("trying to do CDIOREADTOCENTRYS\n")); 201039213Sgibbs 201139213Sgibbs data = malloc(sizeof(data_t), M_TEMP, M_WAITOK); 201239213Sgibbs lead = malloc(sizeof(lead_t), M_TEMP, M_WAITOK); 201339213Sgibbs 201439213Sgibbs if (te->data_len < sizeof(struct cd_toc_entry) 201539213Sgibbs || (te->data_len % sizeof(struct cd_toc_entry)) != 0 201639213Sgibbs || (te->address_format != CD_MSF_FORMAT 201739213Sgibbs && te->address_format != CD_LBA_FORMAT)) { 201839213Sgibbs error = EINVAL; 201939213Sgibbs printf("scsi_cd: error in readtocentries, " 202039213Sgibbs "returning EINVAL\n"); 202139213Sgibbs free(data, M_TEMP); 202239213Sgibbs free(lead, M_TEMP); 202339213Sgibbs break; 202439213Sgibbs } 202539213Sgibbs 202639213Sgibbs th = &data->header; 202739213Sgibbs error = cdreadtoc(periph, 0, 0, 202839213Sgibbs (struct cd_toc_entry *)th, 202939213Sgibbs sizeof (*th)); 203039213Sgibbs if (error) { 203139213Sgibbs free(data, M_TEMP); 203239213Sgibbs free(lead, M_TEMP); 203339213Sgibbs break; 203439213Sgibbs } 203539213Sgibbs 203639213Sgibbs if (softc->quirks & CD_Q_BCD_TRACKS) { 203739213Sgibbs /* we are going to have to convert the BCD 203839213Sgibbs * encoding on the cd to what is expected 203939213Sgibbs */ 204039213Sgibbs th->starting_track = 204139213Sgibbs bcd2bin(th->starting_track); 204239213Sgibbs th->ending_track = bcd2bin(th->ending_track); 204339213Sgibbs } 204439213Sgibbs 204539213Sgibbs if (starting_track == 0) 204639213Sgibbs starting_track = th->starting_track; 204739213Sgibbs else if (starting_track == LEADOUT) 204839213Sgibbs starting_track = th->ending_track + 1; 204939213Sgibbs else if (starting_track < th->starting_track || 205039213Sgibbs starting_track > th->ending_track + 1) { 205139213Sgibbs printf("scsi_cd: error in readtocentries, " 205239213Sgibbs "returning EINVAL\n"); 205339213Sgibbs free(data, M_TEMP); 205439213Sgibbs free(lead, M_TEMP); 205539213Sgibbs error = EINVAL; 205639213Sgibbs break; 205739213Sgibbs } 205839213Sgibbs 205939213Sgibbs /* calculate reading length without leadout entry */ 206039213Sgibbs readlen = (th->ending_track - starting_track + 1) * 206139213Sgibbs sizeof(struct cd_toc_entry); 206239213Sgibbs 206339213Sgibbs /* and with leadout entry */ 206439213Sgibbs len = readlen + sizeof(struct cd_toc_entry); 206539213Sgibbs if (te->data_len < len) { 206639213Sgibbs len = te->data_len; 206739213Sgibbs if (readlen > len) 206839213Sgibbs readlen = len; 206939213Sgibbs } 207039213Sgibbs if (len > sizeof(data->entries)) { 207139213Sgibbs printf("scsi_cd: error in readtocentries, " 207239213Sgibbs "returning EINVAL\n"); 207339213Sgibbs error = EINVAL; 207439213Sgibbs free(data, M_TEMP); 207539213Sgibbs free(lead, M_TEMP); 207639213Sgibbs break; 207739213Sgibbs } 207839213Sgibbs num = len / sizeof(struct cd_toc_entry); 207939213Sgibbs 208039213Sgibbs if (readlen > 0) { 208139213Sgibbs error = cdreadtoc(periph, te->address_format, 208239213Sgibbs starting_track, 208339213Sgibbs (struct cd_toc_entry *)data, 208439213Sgibbs readlen + sizeof (*th)); 208539213Sgibbs if (error) { 208639213Sgibbs free(data, M_TEMP); 208739213Sgibbs free(lead, M_TEMP); 208839213Sgibbs break; 208939213Sgibbs } 209039213Sgibbs } 209139213Sgibbs 209239213Sgibbs /* make leadout entry if needed */ 209339213Sgibbs idx = starting_track + num - 1; 209439213Sgibbs if (softc->quirks & CD_Q_BCD_TRACKS) 209539213Sgibbs th->ending_track = bcd2bin(th->ending_track); 209639213Sgibbs if (idx == th->ending_track + 1) { 209739213Sgibbs error = cdreadtoc(periph, te->address_format, 209839213Sgibbs LEADOUT, 209939213Sgibbs (struct cd_toc_entry *)lead, 210039213Sgibbs sizeof(*lead)); 210139213Sgibbs if (error) { 210239213Sgibbs free(data, M_TEMP); 210339213Sgibbs free(lead, M_TEMP); 210439213Sgibbs break; 210539213Sgibbs } 210639213Sgibbs data->entries[idx - starting_track] = 210739213Sgibbs lead->entry; 210839213Sgibbs } 210939213Sgibbs if (softc->quirks & CD_Q_BCD_TRACKS) { 211039213Sgibbs for (idx = 0; idx < num - 1; idx++) { 211139213Sgibbs data->entries[idx].track = 211239213Sgibbs bcd2bin(data->entries[idx].track); 211339213Sgibbs } 211439213Sgibbs } 211539213Sgibbs 211639213Sgibbs error = copyout(data->entries, te->data, len); 211739213Sgibbs free(data, M_TEMP); 211839213Sgibbs free(lead, M_TEMP); 211939213Sgibbs } 212039213Sgibbs break; 212139213Sgibbs case CDIOREADTOCENTRY: 212239213Sgibbs { 212339213Sgibbs /* yeah yeah, this is ugly */ 212439213Sgibbs typedef struct { 212539213Sgibbs struct ioc_toc_header header; 212639213Sgibbs struct cd_toc_entry entry; 212739213Sgibbs } data_t; 212839213Sgibbs 212939213Sgibbs data_t *data; 213039213Sgibbs struct ioc_read_toc_single_entry *te = 213139213Sgibbs (struct ioc_read_toc_single_entry *) addr; 213239213Sgibbs struct ioc_toc_header *th; 213339213Sgibbs u_int32_t track; 213439213Sgibbs 213539213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 213639213Sgibbs ("trying to do CDIOREADTOCENTRY\n")); 213739213Sgibbs 213839213Sgibbs data = malloc(sizeof(data_t), M_TEMP, M_WAITOK); 213939213Sgibbs 214039213Sgibbs if (te->address_format != CD_MSF_FORMAT 214139213Sgibbs && te->address_format != CD_LBA_FORMAT) { 214239213Sgibbs printf("error in readtocentry, " 214339213Sgibbs " returning EINVAL\n"); 214439213Sgibbs free(data, M_TEMP); 214539213Sgibbs error = EINVAL; 214639213Sgibbs break; 214739213Sgibbs } 214839213Sgibbs 214939213Sgibbs th = &data->header; 215039213Sgibbs error = cdreadtoc(periph, 0, 0, 215139213Sgibbs (struct cd_toc_entry *)th, 215239213Sgibbs sizeof (*th)); 215339213Sgibbs if (error) { 215439213Sgibbs free(data, M_TEMP); 215539213Sgibbs break; 215639213Sgibbs } 215739213Sgibbs 215839213Sgibbs if (softc->quirks & CD_Q_BCD_TRACKS) { 215939213Sgibbs /* we are going to have to convert the BCD 216039213Sgibbs * encoding on the cd to what is expected 216139213Sgibbs */ 216239213Sgibbs th->starting_track = 216339213Sgibbs bcd2bin(th->starting_track); 216439213Sgibbs th->ending_track = bcd2bin(th->ending_track); 216539213Sgibbs } 216639213Sgibbs track = te->track; 216739213Sgibbs if (track == 0) 216839213Sgibbs track = th->starting_track; 216939213Sgibbs else if (track == LEADOUT) 217039213Sgibbs /* OK */; 217139213Sgibbs else if (track < th->starting_track || 217239213Sgibbs track > th->ending_track + 1) { 217339213Sgibbs printf("error in readtocentry, " 217439213Sgibbs " returning EINVAL\n"); 217539213Sgibbs free(data, M_TEMP); 217639213Sgibbs error = EINVAL; 217739213Sgibbs break; 217839213Sgibbs } 217939213Sgibbs 218039213Sgibbs error = cdreadtoc(periph, te->address_format, track, 218139213Sgibbs (struct cd_toc_entry *)data, 218239213Sgibbs sizeof(data_t)); 218339213Sgibbs if (error) { 218439213Sgibbs free(data, M_TEMP); 218539213Sgibbs break; 218639213Sgibbs } 218739213Sgibbs 218839213Sgibbs if (softc->quirks & CD_Q_BCD_TRACKS) 218939213Sgibbs data->entry.track = bcd2bin(data->entry.track); 219039213Sgibbs bcopy(&data->entry, &te->entry, 219139213Sgibbs sizeof(struct cd_toc_entry)); 219239213Sgibbs free(data, M_TEMP); 219339213Sgibbs } 219439213Sgibbs break; 219539213Sgibbs case CDIOCSETPATCH: 219639213Sgibbs { 219739213Sgibbs struct ioc_patch *arg = (struct ioc_patch *) addr; 219839213Sgibbs struct cd_mode_data *data; 219939213Sgibbs 220039213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 220139213Sgibbs ("trying to do CDIOCSETPATCH\n")); 220239213Sgibbs 220339213Sgibbs data = malloc(sizeof(struct cd_mode_data), M_TEMP, 220439213Sgibbs M_WAITOK); 220539213Sgibbs error = cdgetmode(periph, data, AUDIO_PAGE); 220639213Sgibbs if (error) { 220739213Sgibbs free(data, M_TEMP); 220839213Sgibbs break; 220939213Sgibbs } 221039213Sgibbs data->page.audio.port[LEFT_PORT].channels = 221139213Sgibbs arg->patch[0]; 221239213Sgibbs data->page.audio.port[RIGHT_PORT].channels = 221339213Sgibbs arg->patch[1]; 221439213Sgibbs data->page.audio.port[2].channels = arg->patch[2]; 221539213Sgibbs data->page.audio.port[3].channels = arg->patch[3]; 221639213Sgibbs error = cdsetmode(periph, data); 221739213Sgibbs free(data, M_TEMP); 221839213Sgibbs } 221939213Sgibbs break; 222039213Sgibbs case CDIOCGETVOL: 222139213Sgibbs { 222239213Sgibbs struct ioc_vol *arg = (struct ioc_vol *) addr; 222339213Sgibbs struct cd_mode_data *data; 222439213Sgibbs 222539213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 222639213Sgibbs ("trying to do CDIOCGETVOL\n")); 222739213Sgibbs 222839213Sgibbs data = malloc(sizeof(struct cd_mode_data), M_TEMP, 222939213Sgibbs M_WAITOK); 223039213Sgibbs error = cdgetmode(periph, data, AUDIO_PAGE); 223139213Sgibbs if (error) { 223239213Sgibbs free(data, M_TEMP); 223339213Sgibbs break; 223439213Sgibbs } 223539213Sgibbs arg->vol[LEFT_PORT] = 223639213Sgibbs data->page.audio.port[LEFT_PORT].volume; 223739213Sgibbs arg->vol[RIGHT_PORT] = 223839213Sgibbs data->page.audio.port[RIGHT_PORT].volume; 223939213Sgibbs arg->vol[2] = data->page.audio.port[2].volume; 224039213Sgibbs arg->vol[3] = data->page.audio.port[3].volume; 224139213Sgibbs free(data, M_TEMP); 224239213Sgibbs } 224339213Sgibbs break; 224439213Sgibbs case CDIOCSETVOL: 224539213Sgibbs { 224639213Sgibbs struct ioc_vol *arg = (struct ioc_vol *) addr; 224739213Sgibbs struct cd_mode_data *data; 224839213Sgibbs 224939213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 225039213Sgibbs ("trying to do CDIOCSETVOL\n")); 225139213Sgibbs 225239213Sgibbs data = malloc(sizeof(struct cd_mode_data), M_TEMP, 225339213Sgibbs M_WAITOK); 225439213Sgibbs error = cdgetmode(periph, data, AUDIO_PAGE); 225539213Sgibbs if (error) { 225639213Sgibbs free(data, M_TEMP); 225739213Sgibbs break; 225839213Sgibbs } 225939213Sgibbs data->page.audio.port[LEFT_PORT].channels = CHANNEL_0; 226039213Sgibbs data->page.audio.port[LEFT_PORT].volume = 226139213Sgibbs arg->vol[LEFT_PORT]; 226239213Sgibbs data->page.audio.port[RIGHT_PORT].channels = CHANNEL_1; 226339213Sgibbs data->page.audio.port[RIGHT_PORT].volume = 226439213Sgibbs arg->vol[RIGHT_PORT]; 226539213Sgibbs data->page.audio.port[2].volume = arg->vol[2]; 226639213Sgibbs data->page.audio.port[3].volume = arg->vol[3]; 226739213Sgibbs error = cdsetmode(periph, data); 226839213Sgibbs free(data, M_TEMP); 226939213Sgibbs } 227039213Sgibbs break; 227139213Sgibbs case CDIOCSETMONO: 227239213Sgibbs { 227339213Sgibbs struct cd_mode_data *data; 227439213Sgibbs 227539213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 227639213Sgibbs ("trying to do CDIOCSETMONO\n")); 227739213Sgibbs 227839213Sgibbs data = malloc(sizeof(struct cd_mode_data), 227939213Sgibbs M_TEMP, M_WAITOK); 228039213Sgibbs error = cdgetmode(periph, data, AUDIO_PAGE); 228139213Sgibbs if (error) { 228239213Sgibbs free(data, M_TEMP); 228339213Sgibbs break; 228439213Sgibbs } 228539213Sgibbs data->page.audio.port[LEFT_PORT].channels = 228639213Sgibbs LEFT_CHANNEL | RIGHT_CHANNEL; 228739213Sgibbs data->page.audio.port[RIGHT_PORT].channels = 228839213Sgibbs LEFT_CHANNEL | RIGHT_CHANNEL; 228939213Sgibbs data->page.audio.port[2].channels = 0; 229039213Sgibbs data->page.audio.port[3].channels = 0; 229139213Sgibbs error = cdsetmode(periph, data); 229239213Sgibbs free(data, M_TEMP); 229339213Sgibbs } 229439213Sgibbs break; 229539213Sgibbs case CDIOCSETSTEREO: 229639213Sgibbs { 229739213Sgibbs struct cd_mode_data *data; 229839213Sgibbs 229939213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 230039213Sgibbs ("trying to do CDIOCSETSTEREO\n")); 230139213Sgibbs 230239213Sgibbs data = malloc(sizeof(struct cd_mode_data), M_TEMP, 230339213Sgibbs M_WAITOK); 230439213Sgibbs error = cdgetmode(periph, data, AUDIO_PAGE); 230539213Sgibbs if (error) { 230639213Sgibbs free(data, M_TEMP); 230739213Sgibbs break; 230839213Sgibbs } 230939213Sgibbs data->page.audio.port[LEFT_PORT].channels = 231039213Sgibbs LEFT_CHANNEL; 231139213Sgibbs data->page.audio.port[RIGHT_PORT].channels = 231239213Sgibbs RIGHT_CHANNEL; 231339213Sgibbs data->page.audio.port[2].channels = 0; 231439213Sgibbs data->page.audio.port[3].channels = 0; 231539213Sgibbs error = cdsetmode(periph, data); 231639213Sgibbs free(data, M_TEMP); 231739213Sgibbs } 231839213Sgibbs break; 231939213Sgibbs case CDIOCSETMUTE: 232039213Sgibbs { 232139213Sgibbs struct cd_mode_data *data; 232239213Sgibbs 232339213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 232439213Sgibbs ("trying to do CDIOCSETMUTE\n")); 232539213Sgibbs 232639213Sgibbs data = malloc(sizeof(struct cd_mode_data), M_TEMP, 232739213Sgibbs M_WAITOK); 232839213Sgibbs error = cdgetmode(periph, data, AUDIO_PAGE); 232939213Sgibbs if (error) { 233039213Sgibbs free(data, M_TEMP); 233139213Sgibbs break; 233239213Sgibbs } 233339213Sgibbs data->page.audio.port[LEFT_PORT].channels = 0; 233439213Sgibbs data->page.audio.port[RIGHT_PORT].channels = 0; 233539213Sgibbs data->page.audio.port[2].channels = 0; 233639213Sgibbs data->page.audio.port[3].channels = 0; 233739213Sgibbs error = cdsetmode(periph, data); 233839213Sgibbs free(data, M_TEMP); 233939213Sgibbs } 234039213Sgibbs break; 234139213Sgibbs case CDIOCSETLEFT: 234239213Sgibbs { 234339213Sgibbs struct cd_mode_data *data; 234439213Sgibbs 234539213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 234639213Sgibbs ("trying to do CDIOCSETLEFT\n")); 234739213Sgibbs 234839213Sgibbs data = malloc(sizeof(struct cd_mode_data), M_TEMP, 234939213Sgibbs M_WAITOK); 235039213Sgibbs error = cdgetmode(periph, data, AUDIO_PAGE); 235139213Sgibbs if (error) { 235239213Sgibbs free(data, M_TEMP); 235339213Sgibbs break; 235439213Sgibbs } 235539213Sgibbs data->page.audio.port[LEFT_PORT].channels = 235639213Sgibbs LEFT_CHANNEL; 235739213Sgibbs data->page.audio.port[RIGHT_PORT].channels = 235839213Sgibbs LEFT_CHANNEL; 235939213Sgibbs data->page.audio.port[2].channels = 0; 236039213Sgibbs data->page.audio.port[3].channels = 0; 236139213Sgibbs error = cdsetmode(periph, data); 236239213Sgibbs free(data, M_TEMP); 236339213Sgibbs } 236439213Sgibbs break; 236539213Sgibbs case CDIOCSETRIGHT: 236639213Sgibbs { 236739213Sgibbs struct cd_mode_data *data; 236839213Sgibbs 236939213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 237039213Sgibbs ("trying to do CDIOCSETRIGHT\n")); 237139213Sgibbs 237239213Sgibbs data = malloc(sizeof(struct cd_mode_data), M_TEMP, 237339213Sgibbs M_WAITOK); 237439213Sgibbs error = cdgetmode(periph, data, AUDIO_PAGE); 237539213Sgibbs if (error) { 237639213Sgibbs free(data, M_TEMP); 237739213Sgibbs break; 237839213Sgibbs } 237939213Sgibbs data->page.audio.port[LEFT_PORT].channels = 238039213Sgibbs RIGHT_CHANNEL; 238139213Sgibbs data->page.audio.port[RIGHT_PORT].channels = 238239213Sgibbs RIGHT_CHANNEL; 238339213Sgibbs data->page.audio.port[2].channels = 0; 238439213Sgibbs data->page.audio.port[3].channels = 0; 238539213Sgibbs error = cdsetmode(periph, data); 238639213Sgibbs free(data, M_TEMP); 238739213Sgibbs } 238839213Sgibbs break; 238939213Sgibbs case CDIOCRESUME: 239039213Sgibbs error = cdpause(periph, 1); 239139213Sgibbs break; 239239213Sgibbs case CDIOCPAUSE: 239339213Sgibbs error = cdpause(periph, 0); 239439213Sgibbs break; 239539213Sgibbs case CDIOCSTART: 239639213Sgibbs error = cdstartunit(periph); 239739213Sgibbs break; 239839213Sgibbs case CDIOCSTOP: 239939213Sgibbs error = cdstopunit(periph, 0); 240039213Sgibbs break; 240139213Sgibbs case CDIOCEJECT: 240239213Sgibbs error = cdstopunit(periph, 1); 240339213Sgibbs break; 240439213Sgibbs case CDIOCALLOW: 240539213Sgibbs cdprevent(periph, PR_ALLOW); 240639213Sgibbs break; 240739213Sgibbs case CDIOCPREVENT: 240839213Sgibbs cdprevent(periph, PR_PREVENT); 240939213Sgibbs break; 241039213Sgibbs case CDIOCSETDEBUG: 241139213Sgibbs /* sc_link->flags |= (SDEV_DB1 | SDEV_DB2); */ 241239213Sgibbs error = ENOTTY; 241339213Sgibbs break; 241439213Sgibbs case CDIOCCLRDEBUG: 241539213Sgibbs /* sc_link->flags &= ~(SDEV_DB1 | SDEV_DB2); */ 241639213Sgibbs error = ENOTTY; 241739213Sgibbs break; 241839213Sgibbs case CDIOCRESET: 241939213Sgibbs /* return (cd_reset(periph)); */ 242039213Sgibbs error = ENOTTY; 242139213Sgibbs break; 242260422Sken case DVDIOCSENDKEY: 242360422Sken case DVDIOCREPORTKEY: { 242460422Sken struct dvd_authinfo *authinfo; 242560422Sken 242660422Sken authinfo = (struct dvd_authinfo *)addr; 242760422Sken 242860422Sken if (cmd == DVDIOCREPORTKEY) 242960422Sken error = cdreportkey(periph, authinfo); 243060422Sken else 243160422Sken error = cdsendkey(periph, authinfo); 243260422Sken break; 243360422Sken } 243460422Sken case DVDIOCREADSTRUCTURE: { 243560422Sken struct dvd_struct *dvdstruct; 243660422Sken 243760422Sken dvdstruct = (struct dvd_struct *)addr; 243860422Sken 243960422Sken error = cdreaddvdstructure(periph, dvdstruct); 244060422Sken 244160422Sken break; 244260422Sken } 244339213Sgibbs default: 244439213Sgibbs error = cam_periph_ioctl(periph, cmd, addr, cderror); 244539213Sgibbs break; 244639213Sgibbs } 244739213Sgibbs 244840020Sken cam_periph_unlock(periph); 244940020Sken 245039213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("leaving cdioctl\n")); 245139213Sgibbs 245239213Sgibbs return (error); 245339213Sgibbs} 245439213Sgibbs 245539213Sgibbsstatic void 245639213Sgibbscdprevent(struct cam_periph *periph, int action) 245739213Sgibbs{ 245839213Sgibbs union ccb *ccb; 245939213Sgibbs struct cd_softc *softc; 246039213Sgibbs int error; 246139213Sgibbs 246239213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdprevent\n")); 246339213Sgibbs 246439213Sgibbs softc = (struct cd_softc *)periph->softc; 246539213Sgibbs 246639213Sgibbs if (((action == PR_ALLOW) 246739213Sgibbs && (softc->flags & CD_FLAG_DISC_LOCKED) == 0) 246839213Sgibbs || ((action == PR_PREVENT) 246939213Sgibbs && (softc->flags & CD_FLAG_DISC_LOCKED) != 0)) { 247039213Sgibbs return; 247139213Sgibbs } 247239213Sgibbs 247339213Sgibbs ccb = cdgetccb(periph, /* priority */ 1); 247439213Sgibbs 247539213Sgibbs scsi_prevent(&ccb->csio, 247639213Sgibbs /*retries*/ 1, 247739213Sgibbs cddone, 247839213Sgibbs MSG_SIMPLE_Q_TAG, 247939213Sgibbs action, 248039213Sgibbs SSD_FULL_SIZE, 248139213Sgibbs /* timeout */60000); 248239213Sgibbs 248374840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 248474840Sken /*sense_flags*/SF_RETRY_UA|SF_NO_PRINT); 248539213Sgibbs 248639213Sgibbs xpt_release_ccb(ccb); 248739213Sgibbs 248839213Sgibbs if (error == 0) { 248939213Sgibbs if (action == PR_ALLOW) 249039213Sgibbs softc->flags &= ~CD_FLAG_DISC_LOCKED; 249139213Sgibbs else 249239213Sgibbs softc->flags |= CD_FLAG_DISC_LOCKED; 249339213Sgibbs } 249439213Sgibbs} 249539213Sgibbs 249639213Sgibbsstatic int 249739213Sgibbscdsize(dev_t dev, u_int32_t *size) 249839213Sgibbs{ 249939213Sgibbs struct cam_periph *periph; 250039213Sgibbs struct cd_softc *softc; 250139213Sgibbs union ccb *ccb; 250239213Sgibbs struct scsi_read_capacity_data *rcap_buf; 250339213Sgibbs int error; 250439213Sgibbs 250539213Sgibbs periph = cam_extend_get(cdperiphs, dkunit(dev)); 250639213Sgibbs 250739213Sgibbs if (periph == NULL) 250839213Sgibbs return (ENXIO); 250939213Sgibbs 251039213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdsize\n")); 251139213Sgibbs 251239213Sgibbs softc = (struct cd_softc *)periph->softc; 251339213Sgibbs 251439213Sgibbs ccb = cdgetccb(periph, /* priority */ 1); 251539213Sgibbs 251639213Sgibbs rcap_buf = malloc(sizeof(struct scsi_read_capacity_data), 251739213Sgibbs M_TEMP, M_WAITOK); 251839213Sgibbs 251939213Sgibbs scsi_read_capacity(&ccb->csio, 252039213Sgibbs /*retries*/ 1, 252139213Sgibbs cddone, 252239213Sgibbs MSG_SIMPLE_Q_TAG, 252339213Sgibbs rcap_buf, 252439213Sgibbs SSD_FULL_SIZE, 252539213Sgibbs /* timeout */20000); 252639213Sgibbs 252774840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 252874840Sken /*sense_flags*/SF_RETRY_UA|SF_NO_PRINT); 252939213Sgibbs 253039213Sgibbs xpt_release_ccb(ccb); 253139213Sgibbs 253239213Sgibbs softc->params.disksize = scsi_4btoul(rcap_buf->addr) + 1; 253339213Sgibbs softc->params.blksize = scsi_4btoul(rcap_buf->length); 253460806Sjoerg /* 253560806Sjoerg * SCSI-3 mandates that the reported blocksize shall be 2048. 253660806Sjoerg * Older drives sometimes report funny values, trim it down to 253760806Sjoerg * 2048, or other parts of the kernel will get confused. 253860806Sjoerg * 253960806Sjoerg * XXX we leave drives alone that might report 512 bytes, as 254060806Sjoerg * well as drives reporting more weird sizes like perhaps 4K. 254160806Sjoerg */ 254260806Sjoerg if (softc->params.blksize > 2048 && softc->params.blksize <= 2352) 254360806Sjoerg softc->params.blksize = 2048; 254439213Sgibbs 254539213Sgibbs free(rcap_buf, M_TEMP); 254639213Sgibbs *size = softc->params.disksize; 254739213Sgibbs 254839213Sgibbs return (error); 254939213Sgibbs 255039213Sgibbs} 255139213Sgibbs 255268294Sken/* 255368294Sken * The idea here is to try to figure out whether the first track is data or 255468294Sken * audio. If it is data, we can at least attempt to read a disklabel off 255568294Sken * the first sector of the disk. If it is audio, there won't be a 255668294Sken * disklabel. 255768294Sken * 255868294Sken * This routine returns 0 if the first track is data, and non-zero if there 255968294Sken * is an error or the first track is audio. (If either non-zero case, we 256068294Sken * should not attempt to read the disklabel.) 256168294Sken */ 256239213Sgibbsstatic int 256368294Skencdfirsttrackisdata(struct cam_periph *periph) 256468294Sken{ 256568294Sken struct cdtocdata { 256668294Sken struct ioc_toc_header header; 256768294Sken struct cd_toc_entry entries[100]; 256868294Sken }; 256968294Sken struct cd_softc *softc; 257068294Sken struct ioc_toc_header *th; 257168294Sken struct cdtocdata *data; 257268294Sken int num_entries, i; 257368294Sken int error, first_track_audio; 257468294Sken 257568294Sken error = 0; 257668294Sken first_track_audio = -1; 257768294Sken 257868294Sken softc = (struct cd_softc *)periph->softc; 257968294Sken 258068294Sken data = malloc(sizeof(struct cdtocdata), M_TEMP, M_WAITOK); 258168294Sken 258268294Sken th = &data->header; 258368294Sken error = cdreadtoc(periph, 0, 0, (struct cd_toc_entry *)data, 258468294Sken sizeof(*data)); 258568294Sken 258668294Sken if (error) 258768294Sken goto bailout; 258868294Sken 258968294Sken if (softc->quirks & CD_Q_BCD_TRACKS) { 259068294Sken /* we are going to have to convert the BCD 259168294Sken * encoding on the cd to what is expected 259268294Sken */ 259368294Sken th->starting_track = 259468294Sken bcd2bin(th->starting_track); 259568294Sken th->ending_track = bcd2bin(th->ending_track); 259668294Sken } 259768294Sken th->len = scsi_2btoul((u_int8_t *)&th->len); 259868294Sken 259968294Sken if ((th->len - 2) > 0) 260068294Sken num_entries = (th->len - 2) / sizeof(struct cd_toc_entry); 260168294Sken else 260268294Sken num_entries = 0; 260368294Sken 260468294Sken for (i = 0; i < num_entries; i++) { 260568294Sken if (data->entries[i].track == th->starting_track) { 260668294Sken if (data->entries[i].control & 0x4) 260768294Sken first_track_audio = 0; 260868294Sken else 260968294Sken first_track_audio = 1; 261068294Sken break; 261168294Sken } 261268294Sken } 261368294Sken 261468294Sken if (first_track_audio == -1) 261568294Sken error = ENOENT; 261668294Sken else if (first_track_audio == 1) 261768294Sken error = EINVAL; 261868294Sken else 261968294Sken error = 0; 262068294Skenbailout: 262168294Sken free(data, M_TEMP); 262268294Sken 262368294Sken return(error); 262468294Sken} 262568294Sken 262668294Skenstatic int 262739213Sgibbscderror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) 262839213Sgibbs{ 262939213Sgibbs struct cd_softc *softc; 263039213Sgibbs struct cam_periph *periph; 263139213Sgibbs 263239213Sgibbs periph = xpt_path_periph(ccb->ccb_h.path); 263339213Sgibbs softc = (struct cd_softc *)periph->softc; 263439213Sgibbs 263539514Sgibbs /* 263639514Sgibbs * XXX 263739514Sgibbs * Until we have a better way of doing pack validation, 263839514Sgibbs * don't treat UAs as errors. 263939514Sgibbs */ 264039514Sgibbs sense_flags |= SF_RETRY_UA; 264139213Sgibbs return (cam_periph_error(ccb, cam_flags, sense_flags, 264239213Sgibbs &softc->saved_ccb)); 264339213Sgibbs} 264439213Sgibbs 264539213Sgibbs/* 264639213Sgibbs * Read table of contents 264739213Sgibbs */ 264839213Sgibbsstatic int 264939213Sgibbscdreadtoc(struct cam_periph *periph, u_int32_t mode, u_int32_t start, 265039213Sgibbs struct cd_toc_entry *data, u_int32_t len) 265139213Sgibbs{ 265239213Sgibbs struct scsi_read_toc *scsi_cmd; 265339213Sgibbs u_int32_t ntoc; 265439213Sgibbs struct ccb_scsiio *csio; 265539213Sgibbs union ccb *ccb; 265639213Sgibbs int error; 265739213Sgibbs 265839213Sgibbs ntoc = len; 265939213Sgibbs error = 0; 266039213Sgibbs 266139213Sgibbs ccb = cdgetccb(periph, /* priority */ 1); 266239213Sgibbs 266339213Sgibbs csio = &ccb->csio; 266439213Sgibbs 266539213Sgibbs cam_fill_csio(csio, 266639213Sgibbs /* retries */ 1, 266739213Sgibbs /* cbfcnp */ cddone, 266839213Sgibbs /* flags */ CAM_DIR_IN, 266939213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 267039213Sgibbs /* data_ptr */ (u_int8_t *)data, 267139213Sgibbs /* dxfer_len */ len, 267239213Sgibbs /* sense_len */ SSD_FULL_SIZE, 267339213Sgibbs sizeof(struct scsi_read_toc), 267439213Sgibbs /* timeout */ 50000); 267539213Sgibbs 267639213Sgibbs scsi_cmd = (struct scsi_read_toc *)&csio->cdb_io.cdb_bytes; 267739213Sgibbs bzero (scsi_cmd, sizeof(*scsi_cmd)); 267839213Sgibbs 267939213Sgibbs if (mode == CD_MSF_FORMAT) 268039213Sgibbs scsi_cmd->byte2 |= CD_MSF; 268139213Sgibbs scsi_cmd->from_track = start; 268239213Sgibbs /* scsi_ulto2b(ntoc, (u_int8_t *)scsi_cmd->data_len); */ 268339213Sgibbs scsi_cmd->data_len[0] = (ntoc) >> 8; 268439213Sgibbs scsi_cmd->data_len[1] = (ntoc) & 0xff; 268539213Sgibbs 268639213Sgibbs scsi_cmd->op_code = READ_TOC; 268739213Sgibbs 268874840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 268974840Sken /*sense_flags*/SF_RETRY_UA); 269039213Sgibbs 269139213Sgibbs xpt_release_ccb(ccb); 269239213Sgibbs 269339213Sgibbs return(error); 269439213Sgibbs} 269539213Sgibbs 269639213Sgibbsstatic int 269739213Sgibbscdreadsubchannel(struct cam_periph *periph, u_int32_t mode, 269839213Sgibbs u_int32_t format, int track, 269939213Sgibbs struct cd_sub_channel_info *data, u_int32_t len) 270039213Sgibbs{ 270139213Sgibbs struct scsi_read_subchannel *scsi_cmd; 270239213Sgibbs struct ccb_scsiio *csio; 270339213Sgibbs union ccb *ccb; 270439213Sgibbs int error; 270539213Sgibbs 270639213Sgibbs error = 0; 270739213Sgibbs 270839213Sgibbs ccb = cdgetccb(periph, /* priority */ 1); 270939213Sgibbs 271039213Sgibbs csio = &ccb->csio; 271139213Sgibbs 271239213Sgibbs cam_fill_csio(csio, 271339213Sgibbs /* retries */ 1, 271439213Sgibbs /* cbfcnp */ cddone, 271539213Sgibbs /* flags */ CAM_DIR_IN, 271639213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 271739213Sgibbs /* data_ptr */ (u_int8_t *)data, 271839213Sgibbs /* dxfer_len */ len, 271939213Sgibbs /* sense_len */ SSD_FULL_SIZE, 272039213Sgibbs sizeof(struct scsi_read_subchannel), 272139213Sgibbs /* timeout */ 50000); 272239213Sgibbs 272339213Sgibbs scsi_cmd = (struct scsi_read_subchannel *)&csio->cdb_io.cdb_bytes; 272439213Sgibbs bzero (scsi_cmd, sizeof(*scsi_cmd)); 272539213Sgibbs 272639213Sgibbs scsi_cmd->op_code = READ_SUBCHANNEL; 272739213Sgibbs if (mode == CD_MSF_FORMAT) 272839213Sgibbs scsi_cmd->byte1 |= CD_MSF; 272939213Sgibbs scsi_cmd->byte2 = SRS_SUBQ; 273039213Sgibbs scsi_cmd->subchan_format = format; 273139213Sgibbs scsi_cmd->track = track; 273239213Sgibbs scsi_ulto2b(len, (u_int8_t *)scsi_cmd->data_len); 273339213Sgibbs scsi_cmd->control = 0; 273439213Sgibbs 273574840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 273674840Sken /*sense_flags*/SF_RETRY_UA); 273739213Sgibbs 273839213Sgibbs xpt_release_ccb(ccb); 273939213Sgibbs 274039213Sgibbs return(error); 274139213Sgibbs} 274239213Sgibbs 274339213Sgibbs 274439213Sgibbsstatic int 274539213Sgibbscdgetmode(struct cam_periph *periph, struct cd_mode_data *data, u_int32_t page) 274639213Sgibbs{ 274739213Sgibbs struct scsi_mode_sense_6 *scsi_cmd; 274839213Sgibbs struct ccb_scsiio *csio; 274939213Sgibbs union ccb *ccb; 275039213Sgibbs int error; 275139213Sgibbs 275239213Sgibbs ccb = cdgetccb(periph, /* priority */ 1); 275339213Sgibbs 275439213Sgibbs csio = &ccb->csio; 275539213Sgibbs 275639213Sgibbs bzero(data, sizeof(*data)); 275739213Sgibbs cam_fill_csio(csio, 275839213Sgibbs /* retries */ 1, 275939213Sgibbs /* cbfcnp */ cddone, 276039213Sgibbs /* flags */ CAM_DIR_IN, 276139213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 276239213Sgibbs /* data_ptr */ (u_int8_t *)data, 276339213Sgibbs /* dxfer_len */ sizeof(*data), 276439213Sgibbs /* sense_len */ SSD_FULL_SIZE, 276539213Sgibbs sizeof(struct scsi_mode_sense_6), 276639213Sgibbs /* timeout */ 50000); 276739213Sgibbs 276839213Sgibbs scsi_cmd = (struct scsi_mode_sense_6 *)&csio->cdb_io.cdb_bytes; 276939213Sgibbs bzero (scsi_cmd, sizeof(*scsi_cmd)); 277039213Sgibbs 277139213Sgibbs scsi_cmd->page = page; 277239213Sgibbs scsi_cmd->length = sizeof(*data) & 0xff; 277339213Sgibbs scsi_cmd->opcode = MODE_SENSE; 277439213Sgibbs 277574840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 277674840Sken /*sense_flags*/SF_RETRY_UA); 277739213Sgibbs 277839213Sgibbs xpt_release_ccb(ccb); 277939213Sgibbs 278039213Sgibbs return(error); 278139213Sgibbs} 278239213Sgibbs 278339213Sgibbsstatic int 278439213Sgibbscdsetmode(struct cam_periph *periph, struct cd_mode_data *data) 278539213Sgibbs{ 278639213Sgibbs struct scsi_mode_select_6 *scsi_cmd; 278739213Sgibbs struct ccb_scsiio *csio; 278839213Sgibbs union ccb *ccb; 278939213Sgibbs int error; 279039213Sgibbs 279139213Sgibbs ccb = cdgetccb(periph, /* priority */ 1); 279239213Sgibbs 279339213Sgibbs csio = &ccb->csio; 279439213Sgibbs 279539213Sgibbs error = 0; 279639213Sgibbs 279739213Sgibbs cam_fill_csio(csio, 279839213Sgibbs /* retries */ 1, 279939213Sgibbs /* cbfcnp */ cddone, 280039531Sken /* flags */ CAM_DIR_OUT, 280139213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 280239213Sgibbs /* data_ptr */ (u_int8_t *)data, 280339213Sgibbs /* dxfer_len */ sizeof(*data), 280439213Sgibbs /* sense_len */ SSD_FULL_SIZE, 280539213Sgibbs sizeof(struct scsi_mode_select_6), 280639213Sgibbs /* timeout */ 50000); 280739213Sgibbs 280839213Sgibbs scsi_cmd = (struct scsi_mode_select_6 *)&csio->cdb_io.cdb_bytes; 280939213Sgibbs 281039213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 281139213Sgibbs scsi_cmd->opcode = MODE_SELECT; 281239213Sgibbs scsi_cmd->byte2 |= SMS_PF; 281339213Sgibbs scsi_cmd->length = sizeof(*data) & 0xff; 281439213Sgibbs data->header.data_length = 0; 281539213Sgibbs /* 281639213Sgibbs * SONY drives do not allow a mode select with a medium_type 281739213Sgibbs * value that has just been returned by a mode sense; use a 281839213Sgibbs * medium_type of 0 (Default) instead. 281939213Sgibbs */ 282039213Sgibbs data->header.medium_type = 0; 282139213Sgibbs 282274840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 282374840Sken /*sense_flags*/SF_RETRY_UA); 282439213Sgibbs 282539213Sgibbs xpt_release_ccb(ccb); 282639213Sgibbs 282739213Sgibbs return(error); 282839213Sgibbs} 282939213Sgibbs 283039213Sgibbs 283139213Sgibbsstatic int 283239213Sgibbscdplay(struct cam_periph *periph, u_int32_t blk, u_int32_t len) 283339213Sgibbs{ 283439531Sken struct ccb_scsiio *csio; 283539213Sgibbs union ccb *ccb; 283639213Sgibbs int error; 283739531Sken u_int8_t cdb_len; 283839213Sgibbs 283939213Sgibbs error = 0; 284039213Sgibbs ccb = cdgetccb(periph, /* priority */ 1); 284139213Sgibbs csio = &ccb->csio; 284239531Sken /* 284339531Sken * Use the smallest possible command to perform the operation. 284439531Sken */ 284539531Sken if ((len & 0xffff0000) == 0) { 284639531Sken /* 284739531Sken * We can fit in a 10 byte cdb. 284839531Sken */ 284939531Sken struct scsi_play_10 *scsi_cmd; 285039213Sgibbs 285139531Sken scsi_cmd = (struct scsi_play_10 *)&csio->cdb_io.cdb_bytes; 285239531Sken bzero (scsi_cmd, sizeof(*scsi_cmd)); 285339531Sken scsi_cmd->op_code = PLAY_10; 285439531Sken scsi_ulto4b(blk, (u_int8_t *)scsi_cmd->blk_addr); 285539531Sken scsi_ulto2b(len, (u_int8_t *)scsi_cmd->xfer_len); 285639531Sken cdb_len = sizeof(*scsi_cmd); 285739531Sken } else { 285839531Sken struct scsi_play_12 *scsi_cmd; 285939213Sgibbs 286039531Sken scsi_cmd = (struct scsi_play_12 *)&csio->cdb_io.cdb_bytes; 286139531Sken bzero (scsi_cmd, sizeof(*scsi_cmd)); 286239531Sken scsi_cmd->op_code = PLAY_12; 286339531Sken scsi_ulto4b(blk, (u_int8_t *)scsi_cmd->blk_addr); 286439531Sken scsi_ulto4b(len, (u_int8_t *)scsi_cmd->xfer_len); 286539531Sken cdb_len = sizeof(*scsi_cmd); 286639531Sken } 286739531Sken cam_fill_csio(csio, 286839531Sken /*retries*/2, 286939531Sken cddone, 287039531Sken /*flags*/CAM_DIR_NONE, 287139531Sken MSG_SIMPLE_Q_TAG, 287239531Sken /*dataptr*/NULL, 287339531Sken /*datalen*/0, 287439531Sken /*sense_len*/SSD_FULL_SIZE, 287539531Sken cdb_len, 287639531Sken /*timeout*/50 * 1000); 287739213Sgibbs 287874840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 287974840Sken /*sense_flags*/SF_RETRY_UA); 288039213Sgibbs 288139213Sgibbs xpt_release_ccb(ccb); 288239213Sgibbs 288339213Sgibbs return(error); 288439213Sgibbs} 288539213Sgibbs 288639213Sgibbsstatic int 288739213Sgibbscdplaymsf(struct cam_periph *periph, u_int32_t startm, u_int32_t starts, 288839213Sgibbs u_int32_t startf, u_int32_t endm, u_int32_t ends, u_int32_t endf) 288939213Sgibbs{ 289039213Sgibbs struct scsi_play_msf *scsi_cmd; 289139213Sgibbs struct ccb_scsiio *csio; 289239213Sgibbs union ccb *ccb; 289339213Sgibbs int error; 289439213Sgibbs 289539213Sgibbs error = 0; 289639213Sgibbs 289739213Sgibbs ccb = cdgetccb(periph, /* priority */ 1); 289839213Sgibbs 289939213Sgibbs csio = &ccb->csio; 290039213Sgibbs 290139213Sgibbs cam_fill_csio(csio, 290239213Sgibbs /* retries */ 1, 290339213Sgibbs /* cbfcnp */ cddone, 290439531Sken /* flags */ CAM_DIR_NONE, 290539213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 290639213Sgibbs /* data_ptr */ NULL, 290739213Sgibbs /* dxfer_len */ 0, 290839213Sgibbs /* sense_len */ SSD_FULL_SIZE, 290939213Sgibbs sizeof(struct scsi_play_msf), 291039213Sgibbs /* timeout */ 50000); 291139213Sgibbs 291239213Sgibbs scsi_cmd = (struct scsi_play_msf *)&csio->cdb_io.cdb_bytes; 291339213Sgibbs bzero (scsi_cmd, sizeof(*scsi_cmd)); 291439213Sgibbs 291539213Sgibbs scsi_cmd->op_code = PLAY_MSF; 291639213Sgibbs scsi_cmd->start_m = startm; 291739213Sgibbs scsi_cmd->start_s = starts; 291839213Sgibbs scsi_cmd->start_f = startf; 291939213Sgibbs scsi_cmd->end_m = endm; 292039213Sgibbs scsi_cmd->end_s = ends; 292139213Sgibbs scsi_cmd->end_f = endf; 292239213Sgibbs 292374840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 292474840Sken /*sense_flags*/SF_RETRY_UA); 292539213Sgibbs 292639213Sgibbs xpt_release_ccb(ccb); 292739213Sgibbs 292839213Sgibbs return(error); 292939213Sgibbs} 293039213Sgibbs 293139213Sgibbs 293239213Sgibbsstatic int 293339213Sgibbscdplaytracks(struct cam_periph *periph, u_int32_t strack, u_int32_t sindex, 293439213Sgibbs u_int32_t etrack, u_int32_t eindex) 293539213Sgibbs{ 293639213Sgibbs struct scsi_play_track *scsi_cmd; 293739213Sgibbs struct ccb_scsiio *csio; 293839213Sgibbs union ccb *ccb; 293939213Sgibbs int error; 294039213Sgibbs 294139213Sgibbs error = 0; 294239213Sgibbs 294339213Sgibbs ccb = cdgetccb(periph, /* priority */ 1); 294439213Sgibbs 294539213Sgibbs csio = &ccb->csio; 294639213Sgibbs 294739213Sgibbs cam_fill_csio(csio, 294839213Sgibbs /* retries */ 1, 294939213Sgibbs /* cbfcnp */ cddone, 295039531Sken /* flags */ CAM_DIR_NONE, 295139213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 295239213Sgibbs /* data_ptr */ NULL, 295339213Sgibbs /* dxfer_len */ 0, 295439213Sgibbs /* sense_len */ SSD_FULL_SIZE, 295539213Sgibbs sizeof(struct scsi_play_track), 295639213Sgibbs /* timeout */ 50000); 295739213Sgibbs 295839213Sgibbs scsi_cmd = (struct scsi_play_track *)&csio->cdb_io.cdb_bytes; 295939213Sgibbs bzero (scsi_cmd, sizeof(*scsi_cmd)); 296039213Sgibbs 296139213Sgibbs scsi_cmd->op_code = PLAY_TRACK; 296239213Sgibbs scsi_cmd->start_track = strack; 296339213Sgibbs scsi_cmd->start_index = sindex; 296439213Sgibbs scsi_cmd->end_track = etrack; 296539213Sgibbs scsi_cmd->end_index = eindex; 296639213Sgibbs 296774840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 296874840Sken /*sense_flags*/SF_RETRY_UA); 296939213Sgibbs 297039213Sgibbs xpt_release_ccb(ccb); 297139213Sgibbs 297239213Sgibbs return(error); 297339213Sgibbs} 297439213Sgibbs 297539213Sgibbsstatic int 297639213Sgibbscdpause(struct cam_periph *periph, u_int32_t go) 297739213Sgibbs{ 297839213Sgibbs struct scsi_pause *scsi_cmd; 297939213Sgibbs struct ccb_scsiio *csio; 298039213Sgibbs union ccb *ccb; 298139213Sgibbs int error; 298239213Sgibbs 298339213Sgibbs error = 0; 298439213Sgibbs 298539213Sgibbs ccb = cdgetccb(periph, /* priority */ 1); 298639213Sgibbs 298739213Sgibbs csio = &ccb->csio; 298839213Sgibbs 298939213Sgibbs cam_fill_csio(csio, 299039213Sgibbs /* retries */ 1, 299139213Sgibbs /* cbfcnp */ cddone, 299239531Sken /* flags */ CAM_DIR_NONE, 299339213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 299439213Sgibbs /* data_ptr */ NULL, 299539213Sgibbs /* dxfer_len */ 0, 299639213Sgibbs /* sense_len */ SSD_FULL_SIZE, 299739213Sgibbs sizeof(struct scsi_pause), 299839213Sgibbs /* timeout */ 50000); 299939213Sgibbs 300039213Sgibbs scsi_cmd = (struct scsi_pause *)&csio->cdb_io.cdb_bytes; 300139213Sgibbs bzero (scsi_cmd, sizeof(*scsi_cmd)); 300239213Sgibbs 300339213Sgibbs scsi_cmd->op_code = PAUSE; 300439213Sgibbs scsi_cmd->resume = go; 300539213Sgibbs 300674840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 300774840Sken /*sense_flags*/SF_RETRY_UA); 300839213Sgibbs 300939213Sgibbs xpt_release_ccb(ccb); 301039213Sgibbs 301139213Sgibbs return(error); 301239213Sgibbs} 301339213Sgibbs 301439213Sgibbsstatic int 301539213Sgibbscdstartunit(struct cam_periph *periph) 301639213Sgibbs{ 301739213Sgibbs union ccb *ccb; 301839213Sgibbs int error; 301939213Sgibbs 302039213Sgibbs error = 0; 302139213Sgibbs 302239213Sgibbs ccb = cdgetccb(periph, /* priority */ 1); 302339213Sgibbs 302439213Sgibbs scsi_start_stop(&ccb->csio, 302539213Sgibbs /* retries */ 1, 302639213Sgibbs /* cbfcnp */ cddone, 302739213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 302839213Sgibbs /* start */ TRUE, 302969577Sjoerg /* load_eject */ FALSE, 303039213Sgibbs /* immediate */ FALSE, 303139213Sgibbs /* sense_len */ SSD_FULL_SIZE, 303239213Sgibbs /* timeout */ 50000); 303339213Sgibbs 303474840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 303574840Sken /*sense_flags*/SF_RETRY_UA); 303639213Sgibbs 303739213Sgibbs xpt_release_ccb(ccb); 303839213Sgibbs 303939213Sgibbs return(error); 304039213Sgibbs} 304139213Sgibbs 304239213Sgibbsstatic int 304339213Sgibbscdstopunit(struct cam_periph *periph, u_int32_t eject) 304439213Sgibbs{ 304539213Sgibbs union ccb *ccb; 304639213Sgibbs int error; 304739213Sgibbs 304839213Sgibbs error = 0; 304939213Sgibbs 305039213Sgibbs ccb = cdgetccb(periph, /* priority */ 1); 305139213Sgibbs 305239213Sgibbs scsi_start_stop(&ccb->csio, 305339213Sgibbs /* retries */ 1, 305439213Sgibbs /* cbfcnp */ cddone, 305539213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 305639213Sgibbs /* start */ FALSE, 305739213Sgibbs /* load_eject */ eject, 305839213Sgibbs /* immediate */ FALSE, 305939213Sgibbs /* sense_len */ SSD_FULL_SIZE, 306039213Sgibbs /* timeout */ 50000); 306139213Sgibbs 306274840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 306374840Sken /*sense_flags*/SF_RETRY_UA); 306439213Sgibbs 306539213Sgibbs xpt_release_ccb(ccb); 306639213Sgibbs 306739213Sgibbs return(error); 306839213Sgibbs} 306960422Sken 307060422Skenstatic int 307160422Skencdreportkey(struct cam_periph *periph, struct dvd_authinfo *authinfo) 307260422Sken{ 307360422Sken union ccb *ccb; 307460422Sken u_int8_t *databuf; 307560422Sken u_int32_t lba; 307660422Sken int error; 307760422Sken int length; 307860422Sken 307960422Sken error = 0; 308060422Sken databuf = NULL; 308160422Sken lba = 0; 308260422Sken 308360422Sken ccb = cdgetccb(periph, /* priority */ 1); 308460422Sken 308560422Sken switch (authinfo->format) { 308660422Sken case DVD_REPORT_AGID: 308760422Sken length = sizeof(struct scsi_report_key_data_agid); 308860422Sken break; 308960422Sken case DVD_REPORT_CHALLENGE: 309060422Sken length = sizeof(struct scsi_report_key_data_challenge); 309160422Sken break; 309260422Sken case DVD_REPORT_KEY1: 309360422Sken length = sizeof(struct scsi_report_key_data_key1_key2); 309460422Sken break; 309560422Sken case DVD_REPORT_TITLE_KEY: 309660422Sken length = sizeof(struct scsi_report_key_data_title); 309760422Sken /* The lba field is only set for the title key */ 309860422Sken lba = authinfo->lba; 309960422Sken break; 310060422Sken case DVD_REPORT_ASF: 310160422Sken length = sizeof(struct scsi_report_key_data_asf); 310260422Sken break; 310360422Sken case DVD_REPORT_RPC: 310460422Sken length = sizeof(struct scsi_report_key_data_rpc); 310560422Sken break; 310660422Sken case DVD_INVALIDATE_AGID: 310760422Sken length = 0; 310860422Sken break; 310960422Sken default: 311060422Sken error = EINVAL; 311160422Sken goto bailout; 311260422Sken break; /* NOTREACHED */ 311360422Sken } 311460422Sken 311560422Sken if (length != 0) { 311667888Sdwmalone databuf = malloc(length, M_DEVBUF, M_WAITOK | M_ZERO); 311760422Sken } else 311860422Sken databuf = NULL; 311960422Sken 312060422Sken 312160422Sken scsi_report_key(&ccb->csio, 312260422Sken /* retries */ 1, 312360422Sken /* cbfcnp */ cddone, 312460422Sken /* tag_action */ MSG_SIMPLE_Q_TAG, 312560422Sken /* lba */ lba, 312660422Sken /* agid */ authinfo->agid, 312760422Sken /* key_format */ authinfo->format, 312860422Sken /* data_ptr */ databuf, 312960422Sken /* dxfer_len */ length, 313060422Sken /* sense_len */ SSD_FULL_SIZE, 313160422Sken /* timeout */ 50000); 313260422Sken 313374840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 313474840Sken /*sense_flags*/SF_RETRY_UA); 313560422Sken 313660422Sken if (error != 0) 313760422Sken goto bailout; 313860422Sken 313960422Sken if (ccb->csio.resid != 0) { 314060422Sken xpt_print_path(periph->path); 314160422Sken printf("warning, residual for report key command is %d\n", 314260422Sken ccb->csio.resid); 314360422Sken } 314460422Sken 314560422Sken switch(authinfo->format) { 314660422Sken case DVD_REPORT_AGID: { 314760422Sken struct scsi_report_key_data_agid *agid_data; 314860422Sken 314960422Sken agid_data = (struct scsi_report_key_data_agid *)databuf; 315060422Sken 315160422Sken authinfo->agid = (agid_data->agid & RKD_AGID_MASK) >> 315260422Sken RKD_AGID_SHIFT; 315360422Sken break; 315460422Sken } 315560422Sken case DVD_REPORT_CHALLENGE: { 315660422Sken struct scsi_report_key_data_challenge *chal_data; 315760422Sken 315860422Sken chal_data = (struct scsi_report_key_data_challenge *)databuf; 315960422Sken 316060422Sken bcopy(chal_data->challenge_key, authinfo->keychal, 316160422Sken min(sizeof(chal_data->challenge_key), 316260422Sken sizeof(authinfo->keychal))); 316360422Sken break; 316460422Sken } 316560422Sken case DVD_REPORT_KEY1: { 316660422Sken struct scsi_report_key_data_key1_key2 *key1_data; 316760422Sken 316860422Sken key1_data = (struct scsi_report_key_data_key1_key2 *)databuf; 316960422Sken 317060422Sken bcopy(key1_data->key1, authinfo->keychal, 317160422Sken min(sizeof(key1_data->key1), sizeof(authinfo->keychal))); 317260422Sken break; 317360422Sken } 317460422Sken case DVD_REPORT_TITLE_KEY: { 317560422Sken struct scsi_report_key_data_title *title_data; 317660422Sken 317760422Sken title_data = (struct scsi_report_key_data_title *)databuf; 317860422Sken 317960422Sken authinfo->cpm = (title_data->byte0 & RKD_TITLE_CPM) >> 318060422Sken RKD_TITLE_CPM_SHIFT; 318160422Sken authinfo->cp_sec = (title_data->byte0 & RKD_TITLE_CP_SEC) >> 318260422Sken RKD_TITLE_CP_SEC_SHIFT; 318360422Sken authinfo->cgms = (title_data->byte0 & RKD_TITLE_CMGS_MASK) >> 318460422Sken RKD_TITLE_CMGS_SHIFT; 318560422Sken bcopy(title_data->title_key, authinfo->keychal, 318660422Sken min(sizeof(title_data->title_key), 318760422Sken sizeof(authinfo->keychal))); 318860422Sken break; 318960422Sken } 319060422Sken case DVD_REPORT_ASF: { 319160422Sken struct scsi_report_key_data_asf *asf_data; 319260422Sken 319360422Sken asf_data = (struct scsi_report_key_data_asf *)databuf; 319460422Sken 319560422Sken authinfo->asf = asf_data->success & RKD_ASF_SUCCESS; 319660422Sken break; 319760422Sken } 319860422Sken case DVD_REPORT_RPC: { 319960422Sken struct scsi_report_key_data_rpc *rpc_data; 320060422Sken 320160422Sken rpc_data = (struct scsi_report_key_data_rpc *)databuf; 320260422Sken 320360422Sken authinfo->reg_type = (rpc_data->byte4 & RKD_RPC_TYPE_MASK) >> 320460422Sken RKD_RPC_TYPE_SHIFT; 320560422Sken authinfo->vend_rsts = 320660422Sken (rpc_data->byte4 & RKD_RPC_VENDOR_RESET_MASK) >> 320760422Sken RKD_RPC_VENDOR_RESET_SHIFT; 320860422Sken authinfo->user_rsts = rpc_data->byte4 & RKD_RPC_USER_RESET_MASK; 320971752Sken authinfo->region = rpc_data->region_mask; 321071752Sken authinfo->rpc_scheme = rpc_data->rpc_scheme1; 321160422Sken break; 321260422Sken } 321360422Sken case DVD_INVALIDATE_AGID: 321460422Sken break; 321560422Sken default: 321660422Sken /* This should be impossible, since we checked above */ 321760422Sken error = EINVAL; 321860422Sken goto bailout; 321960422Sken break; /* NOTREACHED */ 322060422Sken } 322160422Skenbailout: 322260422Sken if (databuf != NULL) 322360422Sken free(databuf, M_DEVBUF); 322460422Sken 322560422Sken xpt_release_ccb(ccb); 322660422Sken 322760422Sken return(error); 322860422Sken} 322960422Sken 323060422Skenstatic int 323160422Skencdsendkey(struct cam_periph *periph, struct dvd_authinfo *authinfo) 323260422Sken{ 323360422Sken union ccb *ccb; 323460422Sken u_int8_t *databuf; 323560422Sken int length; 323660422Sken int error; 323760422Sken 323860422Sken error = 0; 323960422Sken databuf = NULL; 324060422Sken 324160422Sken ccb = cdgetccb(periph, /* priority */ 1); 324260422Sken 324360422Sken switch(authinfo->format) { 324460422Sken case DVD_SEND_CHALLENGE: { 324560422Sken struct scsi_report_key_data_challenge *challenge_data; 324660422Sken 324760422Sken length = sizeof(*challenge_data); 324860422Sken 324967888Sdwmalone challenge_data = malloc(length, M_DEVBUF, M_WAITOK | M_ZERO); 325060422Sken 325160422Sken databuf = (u_int8_t *)challenge_data; 325260422Sken 325360422Sken scsi_ulto2b(length - sizeof(challenge_data->data_len), 325460422Sken challenge_data->data_len); 325560422Sken 325660422Sken bcopy(authinfo->keychal, challenge_data->challenge_key, 325760422Sken min(sizeof(authinfo->keychal), 325860422Sken sizeof(challenge_data->challenge_key))); 325960422Sken break; 326060422Sken } 326160422Sken case DVD_SEND_KEY2: { 326260422Sken struct scsi_report_key_data_key1_key2 *key2_data; 326360422Sken 326460422Sken length = sizeof(*key2_data); 326560422Sken 326667888Sdwmalone key2_data = malloc(length, M_DEVBUF, M_WAITOK | M_ZERO); 326760422Sken 326860422Sken databuf = (u_int8_t *)key2_data; 326960422Sken 327060422Sken scsi_ulto2b(length - sizeof(key2_data->data_len), 327160422Sken key2_data->data_len); 327260422Sken 327360422Sken bcopy(authinfo->keychal, key2_data->key1, 327460422Sken min(sizeof(authinfo->keychal), sizeof(key2_data->key1))); 327560422Sken 327660422Sken break; 327760422Sken } 327860422Sken case DVD_SEND_RPC: { 327960422Sken struct scsi_send_key_data_rpc *rpc_data; 328060422Sken 328160422Sken length = sizeof(*rpc_data); 328260422Sken 328367888Sdwmalone rpc_data = malloc(length, M_DEVBUF, M_WAITOK | M_ZERO); 328460422Sken 328560422Sken databuf = (u_int8_t *)rpc_data; 328660422Sken 328760422Sken scsi_ulto2b(length - sizeof(rpc_data->data_len), 328860422Sken rpc_data->data_len); 328960422Sken 329060422Sken rpc_data->region_code = authinfo->region; 329160422Sken break; 329260422Sken } 329360422Sken default: 329460422Sken error = EINVAL; 329560422Sken goto bailout; 329660422Sken break; /* NOTREACHED */ 329760422Sken } 329860422Sken 329960422Sken scsi_send_key(&ccb->csio, 330060422Sken /* retries */ 1, 330160422Sken /* cbfcnp */ cddone, 330260422Sken /* tag_action */ MSG_SIMPLE_Q_TAG, 330360422Sken /* agid */ authinfo->agid, 330460422Sken /* key_format */ authinfo->format, 330560422Sken /* data_ptr */ databuf, 330660422Sken /* dxfer_len */ length, 330760422Sken /* sense_len */ SSD_FULL_SIZE, 330860422Sken /* timeout */ 50000); 330960422Sken 331074840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 331174840Sken /*sense_flags*/SF_RETRY_UA); 331260422Sken 331360422Skenbailout: 331460422Sken 331560422Sken if (databuf != NULL) 331660422Sken free(databuf, M_DEVBUF); 331760422Sken 331860422Sken xpt_release_ccb(ccb); 331960422Sken 332060422Sken return(error); 332160422Sken} 332260422Sken 332360422Skenstatic int 332460422Skencdreaddvdstructure(struct cam_periph *periph, struct dvd_struct *dvdstruct) 332560422Sken{ 332660422Sken union ccb *ccb; 332760422Sken u_int8_t *databuf; 332860422Sken u_int32_t address; 332960422Sken int error; 333060422Sken int length; 333160422Sken 333260422Sken error = 0; 333360422Sken databuf = NULL; 333460422Sken /* The address is reserved for many of the formats */ 333560422Sken address = 0; 333660422Sken 333760422Sken ccb = cdgetccb(periph, /* priority */ 1); 333860422Sken 333960422Sken switch(dvdstruct->format) { 334060422Sken case DVD_STRUCT_PHYSICAL: 334160422Sken length = sizeof(struct scsi_read_dvd_struct_data_physical); 334260422Sken break; 334360422Sken case DVD_STRUCT_COPYRIGHT: 334460422Sken length = sizeof(struct scsi_read_dvd_struct_data_copyright); 334560422Sken break; 334660422Sken case DVD_STRUCT_DISCKEY: 334760422Sken length = sizeof(struct scsi_read_dvd_struct_data_disc_key); 334860422Sken break; 334960422Sken case DVD_STRUCT_BCA: 335060422Sken length = sizeof(struct scsi_read_dvd_struct_data_bca); 335160422Sken break; 335260422Sken case DVD_STRUCT_MANUFACT: 335360422Sken length = sizeof(struct scsi_read_dvd_struct_data_manufacturer); 335460422Sken break; 335560422Sken case DVD_STRUCT_CMI: 335660422Sken error = ENODEV; 335760422Sken goto bailout; 335860422Sken#ifdef notyet 335960422Sken length = sizeof(struct scsi_read_dvd_struct_data_copy_manage); 336060422Sken address = dvdstruct->address; 336160422Sken#endif 336260422Sken break; /* NOTREACHED */ 336360422Sken case DVD_STRUCT_PROTDISCID: 336460422Sken length = sizeof(struct scsi_read_dvd_struct_data_prot_discid); 336560422Sken break; 336660422Sken case DVD_STRUCT_DISCKEYBLOCK: 336760422Sken length = sizeof(struct scsi_read_dvd_struct_data_disc_key_blk); 336860422Sken break; 336960422Sken case DVD_STRUCT_DDS: 337060422Sken length = sizeof(struct scsi_read_dvd_struct_data_dds); 337160422Sken break; 337260422Sken case DVD_STRUCT_MEDIUM_STAT: 337360422Sken length = sizeof(struct scsi_read_dvd_struct_data_medium_status); 337460422Sken break; 337560422Sken case DVD_STRUCT_SPARE_AREA: 337660422Sken length = sizeof(struct scsi_read_dvd_struct_data_spare_area); 337760422Sken break; 337860422Sken case DVD_STRUCT_RMD_LAST: 337960422Sken error = ENODEV; 338060422Sken goto bailout; 338160422Sken#ifdef notyet 338260422Sken length = sizeof(struct scsi_read_dvd_struct_data_rmd_borderout); 338360422Sken address = dvdstruct->address; 338460422Sken#endif 338560422Sken break; /* NOTREACHED */ 338660422Sken case DVD_STRUCT_RMD_RMA: 338760422Sken error = ENODEV; 338860422Sken goto bailout; 338960422Sken#ifdef notyet 339060422Sken length = sizeof(struct scsi_read_dvd_struct_data_rmd); 339160422Sken address = dvdstruct->address; 339260422Sken#endif 339360422Sken break; /* NOTREACHED */ 339460422Sken case DVD_STRUCT_PRERECORDED: 339560422Sken length = sizeof(struct scsi_read_dvd_struct_data_leadin); 339660422Sken break; 339760422Sken case DVD_STRUCT_UNIQUEID: 339860422Sken length = sizeof(struct scsi_read_dvd_struct_data_disc_id); 339960422Sken break; 340060422Sken case DVD_STRUCT_DCB: 340160422Sken error = ENODEV; 340260422Sken goto bailout; 340360422Sken#ifdef notyet 340460422Sken length = sizeof(struct scsi_read_dvd_struct_data_dcb); 340560422Sken address = dvdstruct->address; 340660422Sken#endif 340760422Sken break; /* NOTREACHED */ 340860422Sken case DVD_STRUCT_LIST: 340960422Sken /* 341060422Sken * This is the maximum allocation length for the READ DVD 341160422Sken * STRUCTURE command. There's nothing in the MMC3 spec 341260422Sken * that indicates a limit in the amount of data that can 341360422Sken * be returned from this call, other than the limits 341460422Sken * imposed by the 2-byte length variables. 341560422Sken */ 341660422Sken length = 65535; 341760422Sken break; 341860422Sken default: 341960422Sken error = EINVAL; 342060422Sken goto bailout; 342160422Sken break; /* NOTREACHED */ 342260422Sken } 342360422Sken 342460422Sken if (length != 0) { 342567888Sdwmalone databuf = malloc(length, M_DEVBUF, M_WAITOK | M_ZERO); 342660422Sken } else 342760422Sken databuf = NULL; 342860422Sken 342960422Sken scsi_read_dvd_structure(&ccb->csio, 343060422Sken /* retries */ 1, 343160422Sken /* cbfcnp */ cddone, 343260422Sken /* tag_action */ MSG_SIMPLE_Q_TAG, 343360422Sken /* lba */ address, 343460422Sken /* layer_number */ dvdstruct->layer_num, 343560422Sken /* key_format */ dvdstruct->format, 343660422Sken /* agid */ dvdstruct->agid, 343760422Sken /* data_ptr */ databuf, 343860422Sken /* dxfer_len */ length, 343960422Sken /* sense_len */ SSD_FULL_SIZE, 344060422Sken /* timeout */ 50000); 344160422Sken 344274840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 344374840Sken /*sense_flags*/SF_RETRY_UA); 344460422Sken 344560422Sken if (error != 0) 344660422Sken goto bailout; 344760422Sken 344860422Sken switch(dvdstruct->format) { 344960422Sken case DVD_STRUCT_PHYSICAL: { 345060422Sken struct scsi_read_dvd_struct_data_layer_desc *inlayer; 345160422Sken struct dvd_layer *outlayer; 345260422Sken struct scsi_read_dvd_struct_data_physical *phys_data; 345360422Sken 345460422Sken phys_data = 345560422Sken (struct scsi_read_dvd_struct_data_physical *)databuf; 345660422Sken inlayer = &phys_data->layer_desc; 345760422Sken outlayer = (struct dvd_layer *)&dvdstruct->data; 345860422Sken 345960422Sken dvdstruct->length = sizeof(*inlayer); 346060422Sken 346160422Sken outlayer->book_type = (inlayer->book_type_version & 346260422Sken RDSD_BOOK_TYPE_MASK) >> RDSD_BOOK_TYPE_SHIFT; 346360422Sken outlayer->book_version = (inlayer->book_type_version & 346460422Sken RDSD_BOOK_VERSION_MASK); 346560422Sken outlayer->disc_size = (inlayer->disc_size_max_rate & 346660422Sken RDSD_DISC_SIZE_MASK) >> RDSD_DISC_SIZE_SHIFT; 346760422Sken outlayer->max_rate = (inlayer->disc_size_max_rate & 346860422Sken RDSD_MAX_RATE_MASK); 346960422Sken outlayer->nlayers = (inlayer->layer_info & 347060422Sken RDSD_NUM_LAYERS_MASK) >> RDSD_NUM_LAYERS_SHIFT; 347160422Sken outlayer->track_path = (inlayer->layer_info & 347260422Sken RDSD_TRACK_PATH_MASK) >> RDSD_TRACK_PATH_SHIFT; 347360422Sken outlayer->layer_type = (inlayer->layer_info & 347460422Sken RDSD_LAYER_TYPE_MASK); 347560422Sken outlayer->linear_density = (inlayer->density & 347660422Sken RDSD_LIN_DENSITY_MASK) >> RDSD_LIN_DENSITY_SHIFT; 347760422Sken outlayer->track_density = (inlayer->density & 347860422Sken RDSD_TRACK_DENSITY_MASK); 347960422Sken outlayer->bca = (inlayer->bca & RDSD_BCA_MASK) >> 348060422Sken RDSD_BCA_SHIFT; 348160422Sken outlayer->start_sector = scsi_3btoul(inlayer->main_data_start); 348260422Sken outlayer->end_sector = scsi_3btoul(inlayer->main_data_end); 348360422Sken outlayer->end_sector_l0 = 348460422Sken scsi_3btoul(inlayer->end_sector_layer0); 348560422Sken break; 348660422Sken } 348760422Sken case DVD_STRUCT_COPYRIGHT: { 348860422Sken struct scsi_read_dvd_struct_data_copyright *copy_data; 348960422Sken 349060422Sken copy_data = (struct scsi_read_dvd_struct_data_copyright *) 349160422Sken databuf; 349260422Sken 349360422Sken dvdstruct->cpst = copy_data->cps_type; 349460422Sken dvdstruct->rmi = copy_data->region_info; 349560422Sken dvdstruct->length = 0; 349660422Sken 349760422Sken break; 349860422Sken } 349960422Sken default: 350060422Sken /* 350160422Sken * Tell the user what the overall length is, no matter 350260422Sken * what we can actually fit in the data buffer. 350360422Sken */ 350460422Sken dvdstruct->length = length - ccb->csio.resid - 350560422Sken sizeof(struct scsi_read_dvd_struct_data_header); 350660422Sken 350760422Sken /* 350860422Sken * But only actually copy out the smaller of what we read 350960422Sken * in or what the structure can take. 351060422Sken */ 351160422Sken bcopy(databuf + sizeof(struct scsi_read_dvd_struct_data_header), 351260422Sken dvdstruct->data, 351360422Sken min(sizeof(dvdstruct->data), dvdstruct->length)); 351460422Sken break; 351560422Sken } 351660422Skenbailout: 351760422Sken 351860422Sken if (databuf != NULL) 351960422Sken free(databuf, M_DEVBUF); 352060422Sken 352160422Sken xpt_release_ccb(ccb); 352260422Sken 352360422Sken return(error); 352460422Sken} 352560422Sken 352660422Skenvoid 352760422Skenscsi_report_key(struct ccb_scsiio *csio, u_int32_t retries, 352860422Sken void (*cbfcnp)(struct cam_periph *, union ccb *), 352960422Sken u_int8_t tag_action, u_int32_t lba, u_int8_t agid, 353060422Sken u_int8_t key_format, u_int8_t *data_ptr, u_int32_t dxfer_len, 353160422Sken u_int8_t sense_len, u_int32_t timeout) 353260422Sken{ 353360422Sken struct scsi_report_key *scsi_cmd; 353460422Sken 353560422Sken scsi_cmd = (struct scsi_report_key *)&csio->cdb_io.cdb_bytes; 353660422Sken bzero(scsi_cmd, sizeof(*scsi_cmd)); 353760422Sken scsi_cmd->opcode = REPORT_KEY; 353860422Sken scsi_ulto4b(lba, scsi_cmd->lba); 353960422Sken scsi_ulto2b(dxfer_len, scsi_cmd->alloc_len); 354060422Sken scsi_cmd->agid_keyformat = (agid << RK_KF_AGID_SHIFT) | 354160422Sken (key_format & RK_KF_KEYFORMAT_MASK); 354260422Sken 354360422Sken cam_fill_csio(csio, 354460422Sken retries, 354560422Sken cbfcnp, 354660422Sken /*flags*/ (dxfer_len == 0) ? CAM_DIR_NONE : CAM_DIR_IN, 354760422Sken tag_action, 354860422Sken /*data_ptr*/ data_ptr, 354960422Sken /*dxfer_len*/ dxfer_len, 355060422Sken sense_len, 355160422Sken sizeof(*scsi_cmd), 355260422Sken timeout); 355360422Sken} 355460422Sken 355560422Skenvoid 355660422Skenscsi_send_key(struct ccb_scsiio *csio, u_int32_t retries, 355760422Sken void (*cbfcnp)(struct cam_periph *, union ccb *), 355860422Sken u_int8_t tag_action, u_int8_t agid, u_int8_t key_format, 355960422Sken u_int8_t *data_ptr, u_int32_t dxfer_len, u_int8_t sense_len, 356060422Sken u_int32_t timeout) 356160422Sken{ 356260422Sken struct scsi_send_key *scsi_cmd; 356360422Sken 356460422Sken scsi_cmd = (struct scsi_send_key *)&csio->cdb_io.cdb_bytes; 356560422Sken bzero(scsi_cmd, sizeof(*scsi_cmd)); 356660422Sken scsi_cmd->opcode = SEND_KEY; 356760422Sken 356860422Sken scsi_ulto2b(dxfer_len, scsi_cmd->param_len); 356960422Sken scsi_cmd->agid_keyformat = (agid << RK_KF_AGID_SHIFT) | 357060422Sken (key_format & RK_KF_KEYFORMAT_MASK); 357160422Sken 357260422Sken cam_fill_csio(csio, 357360422Sken retries, 357460422Sken cbfcnp, 357560422Sken /*flags*/ CAM_DIR_OUT, 357660422Sken tag_action, 357760422Sken /*data_ptr*/ data_ptr, 357860422Sken /*dxfer_len*/ dxfer_len, 357960422Sken sense_len, 358060422Sken sizeof(*scsi_cmd), 358160422Sken timeout); 358260422Sken} 358360422Sken 358460422Sken 358560422Skenvoid 358660422Skenscsi_read_dvd_structure(struct ccb_scsiio *csio, u_int32_t retries, 358760422Sken void (*cbfcnp)(struct cam_periph *, union ccb *), 358860422Sken u_int8_t tag_action, u_int32_t address, 358960422Sken u_int8_t layer_number, u_int8_t format, u_int8_t agid, 359060422Sken u_int8_t *data_ptr, u_int32_t dxfer_len, 359160422Sken u_int8_t sense_len, u_int32_t timeout) 359260422Sken{ 359360422Sken struct scsi_read_dvd_structure *scsi_cmd; 359460422Sken 359560422Sken scsi_cmd = (struct scsi_read_dvd_structure *)&csio->cdb_io.cdb_bytes; 359660422Sken bzero(scsi_cmd, sizeof(*scsi_cmd)); 359760422Sken scsi_cmd->opcode = READ_DVD_STRUCTURE; 359860422Sken 359960422Sken scsi_ulto4b(address, scsi_cmd->address); 360060422Sken scsi_cmd->layer_number = layer_number; 360160422Sken scsi_cmd->format = format; 360260422Sken scsi_ulto2b(dxfer_len, scsi_cmd->alloc_len); 360360422Sken /* The AGID is the top two bits of this byte */ 360460422Sken scsi_cmd->agid = agid << 6; 360560422Sken 360660422Sken cam_fill_csio(csio, 360760422Sken retries, 360860422Sken cbfcnp, 360960422Sken /*flags*/ CAM_DIR_IN, 361060422Sken tag_action, 361160422Sken /*data_ptr*/ data_ptr, 361260422Sken /*dxfer_len*/ dxfer_len, 361360422Sken sense_len, 361460422Sken sizeof(*scsi_cmd), 361560422Sken timeout); 361660422Sken} 3617