scsi_cd.c revision 74840
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 74840 2001-03-27 05:45:52Z ken $ 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; 39059249Sphk q_bp->bio_error = ENXIO; 39159249Sphk q_bp->bio_flags |= BIO_ERROR; 39240603Sken biodone(q_bp); 39340603Sken } 39440603Sken splx(s); 39540603Sken 39640603Sken /* 39740603Sken * If this device is part of a changer, and it was scheduled 39840603Sken * to run, remove it from the run queue since we just nuked 39940603Sken * all of its scheduled I/O. 40040603Sken */ 40140603Sken if ((softc->flags & CD_FLAG_CHANGER) 40240603Sken && (softc->pinfo.index != CAM_UNQUEUED_INDEX)) 40340603Sken camq_remove(&softc->changer->devq, softc->pinfo.index); 40440603Sken 40540603Sken xpt_print_path(periph->path); 40640603Sken printf("lost device\n"); 40740603Sken} 40840603Sken 40940603Skenstatic void 41039213Sgibbscdcleanup(struct cam_periph *periph) 41139213Sgibbs{ 41239213Sgibbs struct cd_softc *softc; 41340603Sken int s; 41439213Sgibbs 41539213Sgibbs softc = (struct cd_softc *)periph->softc; 41639213Sgibbs 41739213Sgibbs xpt_print_path(periph->path); 41839213Sgibbs printf("removing device entry\n"); 41940603Sken 42040603Sken s = splsoftcam(); 42139213Sgibbs /* 42239213Sgibbs * In the queued, non-active case, the device in question 42339213Sgibbs * has already been removed from the changer run queue. Since this 42439213Sgibbs * device is active, we need to de-activate it, and schedule 42539213Sgibbs * another device to run. (if there is another one to run) 42639213Sgibbs */ 42739213Sgibbs if ((softc->flags & CD_FLAG_CHANGER) 42839213Sgibbs && (softc->flags & CD_FLAG_ACTIVE)) { 42939213Sgibbs 43039213Sgibbs /* 43139213Sgibbs * The purpose of the short timeout is soley to determine 43239213Sgibbs * whether the current device has finished or not. Well, 43339213Sgibbs * since we're removing the active device, we know that it 43439213Sgibbs * is finished. So, get rid of the short timeout. 43539213Sgibbs * Otherwise, if we're in the time period before the short 43639213Sgibbs * timeout fires, and there are no other devices in the 43739213Sgibbs * queue to run, there won't be any other device put in the 43839213Sgibbs * active slot. i.e., when we call cdrunchangerqueue() 43939213Sgibbs * below, it won't do anything. Then, when the short 44039213Sgibbs * timeout fires, it'll look at the "current device", which 44139213Sgibbs * we are free below, and possibly panic the kernel on a 44239213Sgibbs * bogus pointer reference. 44339213Sgibbs * 44439213Sgibbs * The long timeout doesn't really matter, since we 44539213Sgibbs * decrement the qfrozen_cnt to indicate that there is 44639213Sgibbs * nothing in the active slot now. Therefore, there won't 44739213Sgibbs * be any bogus pointer references there. 44839213Sgibbs */ 44939213Sgibbs if (softc->changer->flags & CHANGER_SHORT_TMOUT_SCHED) { 45039213Sgibbs untimeout(cdshorttimeout, softc->changer, 45139213Sgibbs softc->changer->short_handle); 45239213Sgibbs softc->changer->flags &= ~CHANGER_SHORT_TMOUT_SCHED; 45339213Sgibbs } 45439213Sgibbs softc->changer->devq.qfrozen_cnt--; 45539213Sgibbs softc->changer->flags |= CHANGER_MANUAL_CALL; 45639213Sgibbs cdrunchangerqueue(softc->changer); 45739213Sgibbs } 45839213Sgibbs 45939213Sgibbs /* 46039213Sgibbs * If we're removing the last device on the changer, go ahead and 46139213Sgibbs * remove the changer device structure. 46239213Sgibbs */ 46339213Sgibbs if ((softc->flags & CD_FLAG_CHANGER) 46439213Sgibbs && (--softc->changer->num_devices == 0)) { 46539213Sgibbs 46639213Sgibbs /* 46739213Sgibbs * Theoretically, there shouldn't be any timeouts left, but 46839213Sgibbs * I'm not completely sure that that will be the case. So, 46939213Sgibbs * it won't hurt to check and see if there are any left. 47039213Sgibbs */ 47139213Sgibbs if (softc->changer->flags & CHANGER_TIMEOUT_SCHED) { 47239213Sgibbs untimeout(cdrunchangerqueue, softc->changer, 47339213Sgibbs softc->changer->long_handle); 47439213Sgibbs softc->changer->flags &= ~CHANGER_TIMEOUT_SCHED; 47539213Sgibbs } 47639213Sgibbs 47739213Sgibbs if (softc->changer->flags & CHANGER_SHORT_TMOUT_SCHED) { 47839213Sgibbs untimeout(cdshorttimeout, softc->changer, 47939213Sgibbs softc->changer->short_handle); 48039213Sgibbs softc->changer->flags &= ~CHANGER_SHORT_TMOUT_SCHED; 48139213Sgibbs } 48239213Sgibbs 48360938Sjake STAILQ_REMOVE(&changerq, softc->changer, cdchanger, 48439213Sgibbs changer_links); 48539213Sgibbs xpt_print_path(periph->path); 48639213Sgibbs printf("removing changer entry\n"); 48739213Sgibbs free(softc->changer, M_DEVBUF); 48839213Sgibbs num_changers--; 48939213Sgibbs } 49040603Sken devstat_remove_entry(&softc->device_stats); 49139213Sgibbs cam_extend_release(cdperiphs, periph->unit_number); 49240603Sken free(softc, M_DEVBUF); 49340603Sken splx(s); 49439213Sgibbs} 49539213Sgibbs 49639213Sgibbsstatic void 49739213Sgibbscdasync(void *callback_arg, u_int32_t code, 49839213Sgibbs struct cam_path *path, void *arg) 49939213Sgibbs{ 50039213Sgibbs struct cam_periph *periph; 50139213Sgibbs 50239213Sgibbs periph = (struct cam_periph *)callback_arg; 50339213Sgibbs switch (code) { 50439213Sgibbs case AC_FOUND_DEVICE: 50539213Sgibbs { 50639213Sgibbs struct ccb_getdev *cgd; 50739213Sgibbs cam_status status; 50839213Sgibbs 50939213Sgibbs cgd = (struct ccb_getdev *)arg; 51039213Sgibbs 51156148Smjacob if (SID_TYPE(&cgd->inq_data) != T_CDROM 51256148Smjacob && SID_TYPE(&cgd->inq_data) != T_WORM) 51339213Sgibbs break; 51439213Sgibbs 51539213Sgibbs /* 51639213Sgibbs * Allocate a peripheral instance for 51739213Sgibbs * this device and start the probe 51839213Sgibbs * process. 51939213Sgibbs */ 52040603Sken status = cam_periph_alloc(cdregister, cdoninvalidate, 52140603Sken cdcleanup, cdstart, 52240603Sken "cd", CAM_PERIPH_BIO, 52340603Sken cgd->ccb_h.path, cdasync, 52440603Sken AC_FOUND_DEVICE, cgd); 52539213Sgibbs 52639213Sgibbs if (status != CAM_REQ_CMP 52739213Sgibbs && status != CAM_REQ_INPROG) 52839213Sgibbs printf("cdasync: Unable to attach new device " 52939213Sgibbs "due to status 0x%x\n", status); 53039213Sgibbs 53139213Sgibbs break; 53239213Sgibbs } 53339213Sgibbs case AC_SENT_BDR: 53439213Sgibbs case AC_BUS_RESET: 53539213Sgibbs { 53639213Sgibbs struct cd_softc *softc; 53739213Sgibbs struct ccb_hdr *ccbh; 53839213Sgibbs int s; 53939213Sgibbs 54039213Sgibbs softc = (struct cd_softc *)periph->softc; 54139213Sgibbs s = splsoftcam(); 54239213Sgibbs /* 54339213Sgibbs * Don't fail on the expected unit attention 54439213Sgibbs * that will occur. 54539213Sgibbs */ 54639213Sgibbs softc->flags |= CD_FLAG_RETRY_UA; 54771999Sphk LIST_FOREACH(ccbh, &softc->pending_ccbs, periph_links.le) 54839213Sgibbs ccbh->ccb_state |= CD_CCB_RETRY_UA; 54939213Sgibbs splx(s); 55047413Sgibbs /* FALLTHROUGH */ 55139213Sgibbs } 55239213Sgibbs default: 55347413Sgibbs cam_periph_async(periph, code, path, arg); 55439213Sgibbs break; 55539213Sgibbs } 55639213Sgibbs} 55739213Sgibbs 55839213Sgibbsstatic cam_status 55939213Sgibbscdregister(struct cam_periph *periph, void *arg) 56039213Sgibbs{ 56139213Sgibbs struct cd_softc *softc; 56239213Sgibbs struct ccb_setasync csa; 56339213Sgibbs struct ccb_getdev *cgd; 56439213Sgibbs caddr_t match; 56539213Sgibbs 56639213Sgibbs cgd = (struct ccb_getdev *)arg; 56739213Sgibbs if (periph == NULL) { 56839213Sgibbs printf("cdregister: periph was NULL!!\n"); 56939213Sgibbs return(CAM_REQ_CMP_ERR); 57039213Sgibbs } 57139213Sgibbs if (cgd == NULL) { 57239213Sgibbs printf("cdregister: no getdev CCB, can't register device\n"); 57339213Sgibbs return(CAM_REQ_CMP_ERR); 57439213Sgibbs } 57539213Sgibbs 57639213Sgibbs softc = (struct cd_softc *)malloc(sizeof(*softc),M_DEVBUF,M_NOWAIT); 57739213Sgibbs 57839213Sgibbs if (softc == NULL) { 57939213Sgibbs printf("cdregister: Unable to probe new device. " 58039213Sgibbs "Unable to allocate softc\n"); 58139213Sgibbs return(CAM_REQ_CMP_ERR); 58239213Sgibbs } 58339213Sgibbs 58439213Sgibbs bzero(softc, sizeof(*softc)); 58539213Sgibbs LIST_INIT(&softc->pending_ccbs); 58639213Sgibbs softc->state = CD_STATE_PROBE; 58759249Sphk bioq_init(&softc->bio_queue); 58839213Sgibbs if (SID_IS_REMOVABLE(&cgd->inq_data)) 58939213Sgibbs softc->flags |= CD_FLAG_DISC_REMOVABLE; 59039213Sgibbs if ((cgd->inq_data.flags & SID_CmdQue) != 0) 59139213Sgibbs softc->flags |= CD_FLAG_TAGGED_QUEUING; 59239213Sgibbs 59339213Sgibbs periph->softc = softc; 59439213Sgibbs softc->periph = periph; 59539213Sgibbs 59639213Sgibbs cam_extend_set(cdperiphs, periph->unit_number, periph); 59739213Sgibbs 59839213Sgibbs /* 59939213Sgibbs * See if this device has any quirks. 60039213Sgibbs */ 60139213Sgibbs match = cam_quirkmatch((caddr_t)&cgd->inq_data, 60239213Sgibbs (caddr_t)cd_quirk_table, 60339213Sgibbs sizeof(cd_quirk_table)/sizeof(*cd_quirk_table), 60439213Sgibbs sizeof(*cd_quirk_table), scsi_inquiry_match); 60539213Sgibbs 60639213Sgibbs if (match != NULL) 60739213Sgibbs softc->quirks = ((struct cd_quirk_entry *)match)->quirks; 60839213Sgibbs else 60939213Sgibbs softc->quirks = CD_Q_NONE; 61039213Sgibbs 61139213Sgibbs /* 61239213Sgibbs * We need to register the statistics structure for this device, 61339213Sgibbs * but we don't have the blocksize yet for it. So, we register 61439213Sgibbs * the structure and indicate that we don't have the blocksize 61539213Sgibbs * yet. Unlike other SCSI peripheral drivers, we explicitly set 61639213Sgibbs * the device type here to be CDROM, rather than just ORing in 61756148Smjacob * the device type. This is because this driver can attach to either 61839213Sgibbs * CDROM or WORM devices, and we want this peripheral driver to 61939213Sgibbs * show up in the devstat list as a CD peripheral driver, not a 62039213Sgibbs * WORM peripheral driver. WORM drives will also have the WORM 62139213Sgibbs * driver attached to them. 62239213Sgibbs */ 62339213Sgibbs devstat_add_entry(&softc->device_stats, "cd", 62439213Sgibbs periph->unit_number, 0, 62539213Sgibbs DEVSTAT_BS_UNAVAILABLE, 62643819Sken DEVSTAT_TYPE_CDROM | DEVSTAT_TYPE_IF_SCSI, 62743819Sken DEVSTAT_PRIORITY_CD); 62851836Sphk disk_create(periph->unit_number, &softc->disk, 62967928Sken DSO_ONESLICE | DSO_COMPATLABEL, 63051836Sphk &cd_cdevsw, &cddisk_cdevsw); 63139213Sgibbs 63239213Sgibbs /* 63339213Sgibbs * Add an async callback so that we get 63439213Sgibbs * notified if this device goes away. 63539213Sgibbs */ 63639213Sgibbs xpt_setup_ccb(&csa.ccb_h, periph->path, 63739213Sgibbs /* priority */ 5); 63839213Sgibbs csa.ccb_h.func_code = XPT_SASYNC_CB; 63939213Sgibbs csa.event_enable = AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE; 64039213Sgibbs csa.callback = cdasync; 64139213Sgibbs csa.callback_arg = periph; 64239213Sgibbs xpt_action((union ccb *)&csa); 64339213Sgibbs 64439213Sgibbs /* 64539213Sgibbs * If the target lun is greater than 0, we most likely have a CD 64639213Sgibbs * changer device. Check the quirk entries as well, though, just 64739213Sgibbs * in case someone has a CD tower with one lun per drive or 64839213Sgibbs * something like that. Also, if we know up front that a 64939213Sgibbs * particular device is a changer, we can mark it as such starting 65039213Sgibbs * with lun 0, instead of lun 1. It shouldn't be necessary to have 65139213Sgibbs * a quirk entry to define something as a changer, however. 65239213Sgibbs */ 65339213Sgibbs if (((cgd->ccb_h.target_lun > 0) 65439213Sgibbs && ((softc->quirks & CD_Q_NO_CHANGER) == 0)) 65539213Sgibbs || ((softc->quirks & CD_Q_CHANGER) != 0)) { 65639213Sgibbs struct cdchanger *nchanger; 65739213Sgibbs struct cam_periph *nperiph; 65839213Sgibbs struct cam_path *path; 65939213Sgibbs cam_status status; 66039213Sgibbs int found; 66139213Sgibbs 66239213Sgibbs /* Set the changer flag in the current device's softc */ 66339213Sgibbs softc->flags |= CD_FLAG_CHANGER; 66439213Sgibbs 66539213Sgibbs if (num_changers == 0) 66639213Sgibbs STAILQ_INIT(&changerq); 66739213Sgibbs 66839213Sgibbs /* 66939213Sgibbs * Now, look around for an existing changer device with the 67039213Sgibbs * same path and target ID as the current device. 67139213Sgibbs */ 67239213Sgibbs for (found = 0, 67339213Sgibbs nchanger = (struct cdchanger *)STAILQ_FIRST(&changerq); 67439213Sgibbs nchanger != NULL; 67539213Sgibbs nchanger = STAILQ_NEXT(nchanger, changer_links)){ 67639213Sgibbs if ((nchanger->path_id == cgd->ccb_h.path_id) 67739213Sgibbs && (nchanger->target_id == cgd->ccb_h.target_id)) { 67839213Sgibbs found = 1; 67939213Sgibbs break; 68039213Sgibbs } 68139213Sgibbs } 68239213Sgibbs 68339213Sgibbs /* 68439213Sgibbs * If we found a matching entry, just add this device to 68539213Sgibbs * the list of devices on this changer. 68639213Sgibbs */ 68739213Sgibbs if (found == 1) { 68839213Sgibbs struct chdevlist *chlunhead; 68939213Sgibbs 69039213Sgibbs chlunhead = &nchanger->chluns; 69139213Sgibbs 69239213Sgibbs /* 69339213Sgibbs * XXX KDM look at consolidating this code with the 69439213Sgibbs * code below in a separate function. 69539213Sgibbs */ 69639213Sgibbs 69739213Sgibbs /* 69839213Sgibbs * Create a path with lun id 0, and see if we can 69939213Sgibbs * find a matching device 70039213Sgibbs */ 70139213Sgibbs status = xpt_create_path(&path, /*periph*/ periph, 70239213Sgibbs cgd->ccb_h.path_id, 70339213Sgibbs cgd->ccb_h.target_id, 0); 70439213Sgibbs 70539213Sgibbs if ((status == CAM_REQ_CMP) 70639213Sgibbs && ((nperiph = cam_periph_find(path, "cd")) != NULL)){ 70739213Sgibbs struct cd_softc *nsoftc; 70839213Sgibbs 70939213Sgibbs nsoftc = (struct cd_softc *)nperiph->softc; 71039213Sgibbs 71139213Sgibbs if ((nsoftc->flags & CD_FLAG_CHANGER) == 0){ 71239213Sgibbs nsoftc->flags |= CD_FLAG_CHANGER; 71339213Sgibbs nchanger->num_devices++; 71439213Sgibbs if (camq_resize(&nchanger->devq, 71539213Sgibbs nchanger->num_devices)!=CAM_REQ_CMP){ 71639213Sgibbs printf("cdregister: " 71739213Sgibbs "camq_resize " 71839213Sgibbs "failed, changer " 71939213Sgibbs "support may " 72039213Sgibbs "be messed up\n"); 72139213Sgibbs } 72239213Sgibbs nsoftc->changer = nchanger; 72339213Sgibbs nsoftc->pinfo.index =CAM_UNQUEUED_INDEX; 72439213Sgibbs 72539213Sgibbs STAILQ_INSERT_TAIL(&nchanger->chluns, 72639213Sgibbs nsoftc,changer_links); 72739213Sgibbs } 72867928Sken xpt_free_path(path); 72939213Sgibbs } else if (status == CAM_REQ_CMP) 73039213Sgibbs xpt_free_path(path); 73139213Sgibbs else { 73239213Sgibbs printf("cdregister: unable to allocate path\n" 73339213Sgibbs "cdregister: changer support may be " 73439213Sgibbs "broken\n"); 73539213Sgibbs } 73639213Sgibbs 73739213Sgibbs nchanger->num_devices++; 73839213Sgibbs 73939213Sgibbs softc->changer = nchanger; 74039213Sgibbs softc->pinfo.index = CAM_UNQUEUED_INDEX; 74139213Sgibbs 74239213Sgibbs if (camq_resize(&nchanger->devq, 74339213Sgibbs nchanger->num_devices) != CAM_REQ_CMP) { 74439213Sgibbs printf("cdregister: camq_resize " 74539213Sgibbs "failed, changer support may " 74639213Sgibbs "be messed up\n"); 74739213Sgibbs } 74839213Sgibbs 74939213Sgibbs STAILQ_INSERT_TAIL(chlunhead, softc, changer_links); 75039213Sgibbs } 75139213Sgibbs /* 75239213Sgibbs * In this case, we don't already have an entry for this 75339213Sgibbs * particular changer, so we need to create one, add it to 75439213Sgibbs * the queue, and queue this device on the list for this 75539213Sgibbs * changer. Before we queue this device, however, we need 75639213Sgibbs * to search for lun id 0 on this target, and add it to the 75739213Sgibbs * queue first, if it exists. (and if it hasn't already 75839213Sgibbs * been marked as part of the changer.) 75939213Sgibbs */ 76039213Sgibbs else { 76139213Sgibbs nchanger = malloc(sizeof(struct cdchanger), 76239213Sgibbs M_DEVBUF, M_NOWAIT); 76339213Sgibbs 76439213Sgibbs if (nchanger == NULL) { 76539213Sgibbs softc->flags &= ~CD_FLAG_CHANGER; 76639213Sgibbs printf("cdregister: unable to malloc " 76739213Sgibbs "changer structure\ncdregister: " 76839213Sgibbs "changer support disabled\n"); 76939213Sgibbs 77039213Sgibbs /* 77139213Sgibbs * Yes, gotos can be gross but in this case 77239213Sgibbs * I think it's justified.. 77339213Sgibbs */ 77439213Sgibbs goto cdregisterexit; 77539213Sgibbs } 77639213Sgibbs 77739213Sgibbs /* zero the structure */ 77839213Sgibbs bzero(nchanger, sizeof(struct cdchanger)); 77939213Sgibbs 78039213Sgibbs if (camq_init(&nchanger->devq, 1) != 0) { 78139213Sgibbs softc->flags &= ~CD_FLAG_CHANGER; 78239213Sgibbs printf("cdregister: changer support " 78339213Sgibbs "disabled\n"); 78439213Sgibbs goto cdregisterexit; 78539213Sgibbs } 78639213Sgibbs 78739213Sgibbs num_changers++; 78839213Sgibbs 78939213Sgibbs nchanger->path_id = cgd->ccb_h.path_id; 79039213Sgibbs nchanger->target_id = cgd->ccb_h.target_id; 79139213Sgibbs 79239213Sgibbs /* this is superfluous, but it makes things clearer */ 79339213Sgibbs nchanger->num_devices = 0; 79439213Sgibbs 79539213Sgibbs STAILQ_INIT(&nchanger->chluns); 79639213Sgibbs 79739213Sgibbs STAILQ_INSERT_TAIL(&changerq, nchanger, 79839213Sgibbs changer_links); 79939213Sgibbs 80039213Sgibbs /* 80139213Sgibbs * Create a path with lun id 0, and see if we can 80239213Sgibbs * find a matching device 80339213Sgibbs */ 80439213Sgibbs status = xpt_create_path(&path, /*periph*/ periph, 80539213Sgibbs cgd->ccb_h.path_id, 80639213Sgibbs cgd->ccb_h.target_id, 0); 80739213Sgibbs 80839213Sgibbs /* 80939213Sgibbs * If we were able to allocate the path, and if we 81039213Sgibbs * find a matching device and it isn't already 81139213Sgibbs * marked as part of a changer, then we add it to 81239213Sgibbs * the current changer. 81339213Sgibbs */ 81439213Sgibbs if ((status == CAM_REQ_CMP) 81539213Sgibbs && ((nperiph = cam_periph_find(path, "cd")) != NULL) 81639213Sgibbs && ((((struct cd_softc *)periph->softc)->flags & 81739213Sgibbs CD_FLAG_CHANGER) == 0)) { 81839213Sgibbs struct cd_softc *nsoftc; 81939213Sgibbs 82039213Sgibbs nsoftc = (struct cd_softc *)nperiph->softc; 82139213Sgibbs 82239213Sgibbs nsoftc->flags |= CD_FLAG_CHANGER; 82339213Sgibbs nchanger->num_devices++; 82439213Sgibbs if (camq_resize(&nchanger->devq, 82539213Sgibbs nchanger->num_devices) != CAM_REQ_CMP) { 82639213Sgibbs printf("cdregister: camq_resize " 82739213Sgibbs "failed, changer support may " 82839213Sgibbs "be messed up\n"); 82939213Sgibbs } 83039213Sgibbs nsoftc->changer = nchanger; 83139213Sgibbs nsoftc->pinfo.index = CAM_UNQUEUED_INDEX; 83239213Sgibbs 83339213Sgibbs STAILQ_INSERT_TAIL(&nchanger->chluns, 83439213Sgibbs nsoftc, changer_links); 83567928Sken xpt_free_path(path); 83639213Sgibbs } else if (status == CAM_REQ_CMP) 83739213Sgibbs xpt_free_path(path); 83839213Sgibbs else { 83939213Sgibbs printf("cdregister: unable to allocate path\n" 84039213Sgibbs "cdregister: changer support may be " 84139213Sgibbs "broken\n"); 84239213Sgibbs } 84339213Sgibbs 84439213Sgibbs softc->changer = nchanger; 84539213Sgibbs softc->pinfo.index = CAM_UNQUEUED_INDEX; 84639213Sgibbs nchanger->num_devices++; 84739213Sgibbs if (camq_resize(&nchanger->devq, 84839213Sgibbs nchanger->num_devices) != CAM_REQ_CMP) { 84939213Sgibbs printf("cdregister: camq_resize " 85039213Sgibbs "failed, changer support may " 85139213Sgibbs "be messed up\n"); 85239213Sgibbs } 85339213Sgibbs STAILQ_INSERT_TAIL(&nchanger->chluns, softc, 85439213Sgibbs changer_links); 85539213Sgibbs } 85639213Sgibbs } 85739213Sgibbs 85839213Sgibbscdregisterexit: 85939213Sgibbs 86039213Sgibbs /* Lock this peripheral until we are setup */ 86139213Sgibbs /* Can't block */ 86239213Sgibbs cam_periph_lock(periph, PRIBIO); 86339213Sgibbs 86439213Sgibbs if ((softc->flags & CD_FLAG_CHANGER) == 0) 86539213Sgibbs xpt_schedule(periph, /*priority*/5); 86639213Sgibbs else 86739213Sgibbs cdschedule(periph, /*priority*/ 5); 86839213Sgibbs 86939213Sgibbs return(CAM_REQ_CMP); 87039213Sgibbs} 87139213Sgibbs 87239213Sgibbsstatic int 87339213Sgibbscdopen(dev_t dev, int flags, int fmt, struct proc *p) 87439213Sgibbs{ 87551836Sphk struct disklabel *label; 87639213Sgibbs struct cam_periph *periph; 87739213Sgibbs struct cd_softc *softc; 87840020Sken struct ccb_getdev cgd; 87939213Sgibbs u_int32_t size; 88039213Sgibbs int unit, error; 88140603Sken int s; 88239213Sgibbs 88339213Sgibbs unit = dkunit(dev); 88439213Sgibbs periph = cam_extend_get(cdperiphs, unit); 88539213Sgibbs 88639213Sgibbs if (periph == NULL) 88739213Sgibbs return (ENXIO); 88839213Sgibbs 88939213Sgibbs softc = (struct cd_softc *)periph->softc; 89039213Sgibbs 89141297Sken /* 89241297Sken * Grab splsoftcam and hold it until we lock the peripheral. 89341297Sken */ 89440603Sken s = splsoftcam(); 89540603Sken if (softc->flags & CD_FLAG_INVALID) { 89640603Sken splx(s); 89739213Sgibbs return(ENXIO); 89840603Sken } 89939213Sgibbs 90041297Sken if ((error = cam_periph_lock(periph, PRIBIO | PCATCH)) != 0) { 90141297Sken splx(s); 90239213Sgibbs return (error); 90341297Sken } 90439213Sgibbs 90541297Sken splx(s); 90641297Sken 90751836Sphk if (cam_periph_acquire(periph) != CAM_REQ_CMP) 90851836Sphk return(ENXIO); 90940020Sken 91051836Sphk cdprevent(periph, PR_PREVENT); 91139213Sgibbs 91239213Sgibbs /* find out the size */ 91339213Sgibbs if ((error = cdsize(dev, &size)) != 0) { 91451836Sphk cdprevent(periph, PR_ALLOW); 91539213Sgibbs cam_periph_unlock(periph); 91651836Sphk cam_periph_release(periph); 91739213Sgibbs return(error); 91839213Sgibbs } 91939213Sgibbs 92040020Sken /* 92168294Sken * If we get a non-zero return, revert back to not reading the 92268294Sken * label off the disk. The first track is likely audio, which 92368294Sken * won't have a disklabel. 92468294Sken */ 92568294Sken if ((error = cdfirsttrackisdata(periph)) != 0) { 92668294Sken softc->disk.d_dsflags &= ~DSO_COMPATLABEL; 92768294Sken softc->disk.d_dsflags |= DSO_NOLABELS; 92868294Sken error = 0; 92968294Sken } 93068294Sken 93168294Sken /* 93240020Sken * Build prototype label for whole disk. 93340020Sken * Should take information about different data tracks from the 93440020Sken * TOC and put it in the partition table. 93540020Sken */ 93651836Sphk label = &softc->disk.d_label; 93751836Sphk bzero(label, sizeof(*label)); 93851836Sphk label->d_type = DTYPE_SCSI; 93940020Sken 94040020Sken /* 94140020Sken * Grab the inquiry data to get the vendor and product names. 94240020Sken * Put them in the typename and packname for the label. 94340020Sken */ 94440020Sken xpt_setup_ccb(&cgd.ccb_h, periph->path, /*priority*/ 1); 94540020Sken cgd.ccb_h.func_code = XPT_GDEV_TYPE; 94640020Sken xpt_action((union ccb *)&cgd); 94740020Sken 94851836Sphk strncpy(label->d_typename, cgd.inq_data.vendor, 94951836Sphk min(SID_VENDOR_SIZE, sizeof(label->d_typename))); 95051836Sphk strncpy(label->d_packname, cgd.inq_data.product, 95151836Sphk min(SID_PRODUCT_SIZE, sizeof(label->d_packname))); 95240020Sken 95351836Sphk label->d_secsize = softc->params.blksize; 95451836Sphk label->d_secperunit = softc->params.disksize; 95551836Sphk label->d_flags = D_REMOVABLE; 95640020Sken /* 95740020Sken * Make partition 'a' cover the whole disk. This is a temporary 95840020Sken * compatibility hack. The 'a' partition should not exist, so 95940020Sken * the slice code won't create it. The slice code will make 96040020Sken * partition (RAW_PART + 'a') cover the whole disk and fill in 96140020Sken * some more defaults. 96240020Sken */ 96351836Sphk label->d_partitions[0].p_size = label->d_secperunit; 96451836Sphk label->d_partitions[0].p_fstype = FS_OTHER; 96540020Sken 96651836Sphk /* 96751836Sphk * We unconditionally (re)set the blocksize each time the 96851836Sphk * CD device is opened. This is because the CD can change, 96951836Sphk * and therefore the blocksize might change. 97051836Sphk * XXX problems here if some slice or partition is still 97151836Sphk * open with the old size? 97251836Sphk */ 97351836Sphk if ((softc->device_stats.flags & DEVSTAT_BS_UNAVAILABLE) != 0) 97451836Sphk softc->device_stats.flags &= ~DEVSTAT_BS_UNAVAILABLE; 97551836Sphk softc->device_stats.block_size = softc->params.blksize; 97640020Sken 97739213Sgibbs cam_periph_unlock(periph); 97839213Sgibbs 97939213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("leaving cdopen\n")); 98039213Sgibbs 98139213Sgibbs return (error); 98239213Sgibbs} 98339213Sgibbs 98439213Sgibbsstatic int 98539213Sgibbscdclose(dev_t dev, int flag, int fmt, struct proc *p) 98639213Sgibbs{ 98739213Sgibbs struct cam_periph *periph; 98839213Sgibbs struct cd_softc *softc; 98939213Sgibbs int unit, error; 99039213Sgibbs 99139213Sgibbs unit = dkunit(dev); 99239213Sgibbs periph = cam_extend_get(cdperiphs, unit); 99339213Sgibbs if (periph == NULL) 99439213Sgibbs return (ENXIO); 99539213Sgibbs 99639213Sgibbs softc = (struct cd_softc *)periph->softc; 99739213Sgibbs 99839213Sgibbs if ((error = cam_periph_lock(periph, PRIBIO)) != 0) 99939213Sgibbs return (error); 100039213Sgibbs 100139213Sgibbs if ((softc->flags & CD_FLAG_DISC_REMOVABLE) != 0) 100239213Sgibbs cdprevent(periph, PR_ALLOW); 100339213Sgibbs 100439213Sgibbs /* 100568294Sken * Unconditionally set the dsopen() flags back to their default 100668294Sken * state. 100768294Sken */ 100868294Sken softc->disk.d_dsflags &= ~DSO_NOLABELS; 100968294Sken softc->disk.d_dsflags |= DSO_COMPATLABEL; 101068294Sken 101168294Sken /* 101239213Sgibbs * Since we're closing this CD, mark the blocksize as unavailable. 101339213Sgibbs * It will be marked as available whence the CD is opened again. 101439213Sgibbs */ 101539213Sgibbs softc->device_stats.flags |= DEVSTAT_BS_UNAVAILABLE; 101639213Sgibbs 101739213Sgibbs cam_periph_unlock(periph); 101839213Sgibbs cam_periph_release(periph); 101939213Sgibbs 102039213Sgibbs return (0); 102139213Sgibbs} 102239213Sgibbs 102339213Sgibbsstatic void 102439213Sgibbscdshorttimeout(void *arg) 102539213Sgibbs{ 102639213Sgibbs struct cdchanger *changer; 102739213Sgibbs int s; 102839213Sgibbs 102939213Sgibbs s = splsoftcam(); 103039213Sgibbs 103139213Sgibbs changer = (struct cdchanger *)arg; 103239213Sgibbs 103339213Sgibbs /* Always clear the short timeout flag, since that's what we're in */ 103439213Sgibbs changer->flags &= ~CHANGER_SHORT_TMOUT_SCHED; 103539213Sgibbs 103639213Sgibbs /* 103739213Sgibbs * Check to see if there is any more pending or outstanding I/O for 103839213Sgibbs * this device. If not, move it out of the active slot. 103939213Sgibbs */ 104059249Sphk if ((bioq_first(&changer->cur_device->bio_queue) == NULL) 104139213Sgibbs && (changer->cur_device->device_stats.busy_count == 0)) { 104239213Sgibbs changer->flags |= CHANGER_MANUAL_CALL; 104339213Sgibbs cdrunchangerqueue(changer); 104439213Sgibbs } 104539213Sgibbs 104639213Sgibbs splx(s); 104739213Sgibbs} 104839213Sgibbs 104939213Sgibbs/* 105039213Sgibbs * This is a wrapper for xpt_schedule. It only applies to changers. 105139213Sgibbs */ 105239213Sgibbsstatic void 105339213Sgibbscdschedule(struct cam_periph *periph, int priority) 105439213Sgibbs{ 105539213Sgibbs struct cd_softc *softc; 105639213Sgibbs int s; 105739213Sgibbs 105839213Sgibbs s = splsoftcam(); 105939213Sgibbs 106039213Sgibbs softc = (struct cd_softc *)periph->softc; 106139213Sgibbs 106239213Sgibbs /* 106339213Sgibbs * If this device isn't currently queued, and if it isn't 106439213Sgibbs * the active device, then we queue this device and run the 106539213Sgibbs * changer queue if there is no timeout scheduled to do it. 106639213Sgibbs * If this device is the active device, just schedule it 106739213Sgibbs * to run again. If this device is queued, there should be 106839213Sgibbs * a timeout in place already that will make sure it runs. 106939213Sgibbs */ 107039213Sgibbs if ((softc->pinfo.index == CAM_UNQUEUED_INDEX) 107139213Sgibbs && ((softc->flags & CD_FLAG_ACTIVE) == 0)) { 107239213Sgibbs /* 107339213Sgibbs * We don't do anything with the priority here. 107439213Sgibbs * This is strictly a fifo queue. 107539213Sgibbs */ 107639213Sgibbs softc->pinfo.priority = 1; 107745442Sgibbs softc->pinfo.generation = ++softc->changer->devq.generation; 107839213Sgibbs camq_insert(&softc->changer->devq, (cam_pinfo *)softc); 107939213Sgibbs 108039213Sgibbs /* 108139213Sgibbs * Since we just put a device in the changer queue, 108239213Sgibbs * check and see if there is a timeout scheduled for 108339213Sgibbs * this changer. If so, let the timeout handle 108439213Sgibbs * switching this device into the active slot. If 108539213Sgibbs * not, manually call the timeout routine to 108639213Sgibbs * bootstrap things. 108739213Sgibbs */ 108839213Sgibbs if (((softc->changer->flags & CHANGER_TIMEOUT_SCHED)==0) 108946581Sken && ((softc->changer->flags & CHANGER_NEED_TIMEOUT)==0) 109046581Sken && ((softc->changer->flags & CHANGER_SHORT_TMOUT_SCHED)==0)){ 109139213Sgibbs softc->changer->flags |= CHANGER_MANUAL_CALL; 109239213Sgibbs cdrunchangerqueue(softc->changer); 109339213Sgibbs } 109439213Sgibbs } else if ((softc->flags & CD_FLAG_ACTIVE) 109539213Sgibbs && ((softc->flags & CD_FLAG_SCHED_ON_COMP) == 0)) 109639213Sgibbs xpt_schedule(periph, priority); 109739213Sgibbs 109839213Sgibbs splx(s); 109939213Sgibbs 110039213Sgibbs} 110139213Sgibbs 110239213Sgibbsstatic void 110339213Sgibbscdrunchangerqueue(void *arg) 110439213Sgibbs{ 110539213Sgibbs struct cd_softc *softc; 110639213Sgibbs struct cdchanger *changer; 110739213Sgibbs int called_from_timeout; 110839213Sgibbs int s; 110939213Sgibbs 111039213Sgibbs s = splsoftcam(); 111139213Sgibbs 111239213Sgibbs changer = (struct cdchanger *)arg; 111339213Sgibbs 111439213Sgibbs /* 111539213Sgibbs * If we have NOT been called from cdstrategy() or cddone(), and 111639213Sgibbs * instead from a timeout routine, go ahead and clear the 111739213Sgibbs * timeout flag. 111839213Sgibbs */ 111939213Sgibbs if ((changer->flags & CHANGER_MANUAL_CALL) == 0) { 112039213Sgibbs changer->flags &= ~CHANGER_TIMEOUT_SCHED; 112139213Sgibbs called_from_timeout = 1; 112239213Sgibbs } else 112339213Sgibbs called_from_timeout = 0; 112439213Sgibbs 112539213Sgibbs /* Always clear the manual call flag */ 112639213Sgibbs changer->flags &= ~CHANGER_MANUAL_CALL; 112739213Sgibbs 112839213Sgibbs /* nothing to do if the queue is empty */ 112939213Sgibbs if (changer->devq.entries <= 0) { 113039213Sgibbs splx(s); 113139213Sgibbs return; 113239213Sgibbs } 113339213Sgibbs 113439213Sgibbs /* 113539213Sgibbs * If the changer queue is frozen, that means we have an active 113639213Sgibbs * device. 113739213Sgibbs */ 113839213Sgibbs if (changer->devq.qfrozen_cnt > 0) { 113939213Sgibbs 114039213Sgibbs if (changer->cur_device->device_stats.busy_count > 0) { 114139213Sgibbs changer->cur_device->flags |= CD_FLAG_SCHED_ON_COMP; 114239213Sgibbs changer->cur_device->bufs_left = 114339213Sgibbs changer->cur_device->device_stats.busy_count; 114439213Sgibbs if (called_from_timeout) { 114539213Sgibbs changer->long_handle = 114639213Sgibbs timeout(cdrunchangerqueue, changer, 114739213Sgibbs changer_max_busy_seconds * hz); 114839213Sgibbs changer->flags |= CHANGER_TIMEOUT_SCHED; 114939213Sgibbs } 115039213Sgibbs splx(s); 115139213Sgibbs return; 115239213Sgibbs } 115339213Sgibbs 115439213Sgibbs /* 115539213Sgibbs * We always need to reset the frozen count and clear the 115639213Sgibbs * active flag. 115739213Sgibbs */ 115839213Sgibbs changer->devq.qfrozen_cnt--; 115939213Sgibbs changer->cur_device->flags &= ~CD_FLAG_ACTIVE; 116039213Sgibbs changer->cur_device->flags &= ~CD_FLAG_SCHED_ON_COMP; 116139213Sgibbs 116239213Sgibbs /* 116339213Sgibbs * Check to see whether the current device has any I/O left 116439213Sgibbs * to do. If so, requeue it at the end of the queue. If 116539213Sgibbs * not, there is no need to requeue it. 116639213Sgibbs */ 116759249Sphk if (bioq_first(&changer->cur_device->bio_queue) != NULL) { 116839213Sgibbs 116939213Sgibbs changer->cur_device->pinfo.generation = 117045442Sgibbs ++changer->devq.generation; 117139213Sgibbs camq_insert(&changer->devq, 117239213Sgibbs (cam_pinfo *)changer->cur_device); 117339213Sgibbs } 117439213Sgibbs } 117539213Sgibbs 117645845Sgibbs softc = (struct cd_softc *)camq_remove(&changer->devq, CAMQ_HEAD); 117739213Sgibbs 117839213Sgibbs changer->cur_device = softc; 117939213Sgibbs 118039213Sgibbs changer->devq.qfrozen_cnt++; 118139213Sgibbs softc->flags |= CD_FLAG_ACTIVE; 118239213Sgibbs 118339213Sgibbs /* Just in case this device is waiting */ 118439213Sgibbs wakeup(&softc->changer); 118539213Sgibbs xpt_schedule(softc->periph, /*priority*/ 1); 118639213Sgibbs 118739213Sgibbs /* 118839213Sgibbs * Get rid of any pending timeouts, and set a flag to schedule new 118939213Sgibbs * ones so this device gets its full time quantum. 119039213Sgibbs */ 119139213Sgibbs if (changer->flags & CHANGER_TIMEOUT_SCHED) { 119239213Sgibbs untimeout(cdrunchangerqueue, changer, changer->long_handle); 119339213Sgibbs changer->flags &= ~CHANGER_TIMEOUT_SCHED; 119439213Sgibbs } 119539213Sgibbs 119639213Sgibbs if (changer->flags & CHANGER_SHORT_TMOUT_SCHED) { 119739213Sgibbs untimeout(cdshorttimeout, changer, changer->short_handle); 119839213Sgibbs changer->flags &= ~CHANGER_SHORT_TMOUT_SCHED; 119939213Sgibbs } 120039213Sgibbs 120139213Sgibbs /* 120239213Sgibbs * We need to schedule timeouts, but we only do this after the 120339213Sgibbs * first transaction has completed. This eliminates the changer 120439213Sgibbs * switch time. 120539213Sgibbs */ 120639213Sgibbs changer->flags |= CHANGER_NEED_TIMEOUT; 120739213Sgibbs 120839213Sgibbs splx(s); 120939213Sgibbs} 121039213Sgibbs 121139213Sgibbsstatic void 121239213Sgibbscdchangerschedule(struct cd_softc *softc) 121339213Sgibbs{ 121439213Sgibbs struct cdchanger *changer; 121539213Sgibbs int s; 121639213Sgibbs 121739213Sgibbs s = splsoftcam(); 121839213Sgibbs 121939213Sgibbs changer = softc->changer; 122039213Sgibbs 122139213Sgibbs /* 122239213Sgibbs * If this is a changer, and this is the current device, 122339213Sgibbs * and this device has at least the minimum time quantum to 122439213Sgibbs * run, see if we can switch it out. 122539213Sgibbs */ 122639213Sgibbs if ((softc->flags & CD_FLAG_ACTIVE) 122739213Sgibbs && ((changer->flags & CHANGER_SHORT_TMOUT_SCHED) == 0) 122839213Sgibbs && ((changer->flags & CHANGER_NEED_TIMEOUT) == 0)) { 122939213Sgibbs /* 123039213Sgibbs * We try three things here. The first is that we 123139213Sgibbs * check to see whether the schedule on completion 123239213Sgibbs * flag is set. If it is, we decrement the number 123339213Sgibbs * of buffers left, and if it's zero, we reschedule. 123439213Sgibbs * Next, we check to see whether the pending buffer 123539213Sgibbs * queue is empty and whether there are no 123639213Sgibbs * outstanding transactions. If so, we reschedule. 123739213Sgibbs * Next, we see if the pending buffer queue is empty. 123839213Sgibbs * If it is, we set the number of buffers left to 123939213Sgibbs * the current active buffer count and set the 124039213Sgibbs * schedule on complete flag. 124139213Sgibbs */ 124239213Sgibbs if (softc->flags & CD_FLAG_SCHED_ON_COMP) { 124339213Sgibbs if (--softc->bufs_left == 0) { 124439213Sgibbs softc->changer->flags |= 124539213Sgibbs CHANGER_MANUAL_CALL; 124639213Sgibbs softc->flags &= ~CD_FLAG_SCHED_ON_COMP; 124739213Sgibbs cdrunchangerqueue(softc->changer); 124839213Sgibbs } 124959249Sphk } else if ((bioq_first(&softc->bio_queue) == NULL) 125039213Sgibbs && (softc->device_stats.busy_count == 0)) { 125139213Sgibbs softc->changer->flags |= CHANGER_MANUAL_CALL; 125239213Sgibbs cdrunchangerqueue(softc->changer); 125339213Sgibbs } 125439213Sgibbs } else if ((softc->changer->flags & CHANGER_NEED_TIMEOUT) 125539213Sgibbs && (softc->flags & CD_FLAG_ACTIVE)) { 125639213Sgibbs 125739213Sgibbs /* 125839213Sgibbs * Now that the first transaction to this 125939213Sgibbs * particular device has completed, we can go ahead 126039213Sgibbs * and schedule our timeouts. 126139213Sgibbs */ 126239213Sgibbs if ((changer->flags & CHANGER_TIMEOUT_SCHED) == 0) { 126339213Sgibbs changer->long_handle = 126439213Sgibbs timeout(cdrunchangerqueue, changer, 126539213Sgibbs changer_max_busy_seconds * hz); 126639213Sgibbs changer->flags |= CHANGER_TIMEOUT_SCHED; 126739213Sgibbs } else 126839213Sgibbs printf("cdchangerschedule: already have a long" 126939213Sgibbs " timeout!\n"); 127039213Sgibbs 127139213Sgibbs if ((changer->flags & CHANGER_SHORT_TMOUT_SCHED) == 0) { 127239213Sgibbs changer->short_handle = 127339213Sgibbs timeout(cdshorttimeout, changer, 127439213Sgibbs changer_min_busy_seconds * hz); 127539213Sgibbs changer->flags |= CHANGER_SHORT_TMOUT_SCHED; 127639213Sgibbs } else 127739213Sgibbs printf("cdchangerschedule: already have a short " 127839213Sgibbs "timeout!\n"); 127939213Sgibbs 128039213Sgibbs /* 128139213Sgibbs * We just scheduled timeouts, no need to schedule 128239213Sgibbs * more. 128339213Sgibbs */ 128439213Sgibbs changer->flags &= ~CHANGER_NEED_TIMEOUT; 128539213Sgibbs 128639213Sgibbs } 128739213Sgibbs splx(s); 128839213Sgibbs} 128939213Sgibbs 129039213Sgibbsstatic int 129139213Sgibbscdrunccb(union ccb *ccb, int (*error_routine)(union ccb *ccb, 129239213Sgibbs u_int32_t cam_flags, 129339213Sgibbs u_int32_t sense_flags), 129439213Sgibbs u_int32_t cam_flags, u_int32_t sense_flags) 129539213Sgibbs{ 129639213Sgibbs struct cd_softc *softc; 129739213Sgibbs struct cam_periph *periph; 129839213Sgibbs int error; 129939213Sgibbs 130039213Sgibbs periph = xpt_path_periph(ccb->ccb_h.path); 130139213Sgibbs softc = (struct cd_softc *)periph->softc; 130239213Sgibbs 130339213Sgibbs error = cam_periph_runccb(ccb, error_routine, cam_flags, sense_flags, 130439213Sgibbs &softc->device_stats); 130539213Sgibbs 130639213Sgibbs if (softc->flags & CD_FLAG_CHANGER) 130739213Sgibbs cdchangerschedule(softc); 130839213Sgibbs 130939213Sgibbs return(error); 131039213Sgibbs} 131139213Sgibbs 131242017Seivindstatic union ccb * 131339213Sgibbscdgetccb(struct cam_periph *periph, u_int32_t priority) 131439213Sgibbs{ 131539213Sgibbs struct cd_softc *softc; 131639213Sgibbs int s; 131739213Sgibbs 131839213Sgibbs softc = (struct cd_softc *)periph->softc; 131939213Sgibbs 132039213Sgibbs if (softc->flags & CD_FLAG_CHANGER) { 132139213Sgibbs 132239213Sgibbs s = splsoftcam(); 132339213Sgibbs 132439213Sgibbs /* 132539213Sgibbs * This should work the first time this device is woken up, 132639213Sgibbs * but just in case it doesn't, we use a while loop. 132739213Sgibbs */ 132846581Sken while ((softc->flags & CD_FLAG_ACTIVE) == 0) { 132939213Sgibbs /* 133039213Sgibbs * If this changer isn't already queued, queue it up. 133139213Sgibbs */ 133239213Sgibbs if (softc->pinfo.index == CAM_UNQUEUED_INDEX) { 133339213Sgibbs softc->pinfo.priority = 1; 133439213Sgibbs softc->pinfo.generation = 133545442Sgibbs ++softc->changer->devq.generation; 133639213Sgibbs camq_insert(&softc->changer->devq, 133739213Sgibbs (cam_pinfo *)softc); 133839213Sgibbs } 133946581Sken if (((softc->changer->flags & CHANGER_TIMEOUT_SCHED)==0) 134046581Sken && ((softc->changer->flags & CHANGER_NEED_TIMEOUT)==0) 134146581Sken && ((softc->changer->flags 134246581Sken & CHANGER_SHORT_TMOUT_SCHED)==0)) { 134339213Sgibbs softc->changer->flags |= CHANGER_MANUAL_CALL; 134439213Sgibbs cdrunchangerqueue(softc->changer); 134539213Sgibbs } else 134639213Sgibbs tsleep(&softc->changer, PRIBIO, "cgticb", 0); 134739213Sgibbs } 134839213Sgibbs splx(s); 134939213Sgibbs } 135039213Sgibbs return(cam_periph_getccb(periph, priority)); 135139213Sgibbs} 135239213Sgibbs 135339213Sgibbs 135439213Sgibbs/* 135539213Sgibbs * Actually translate the requested transfer into one the physical driver 135639213Sgibbs * can understand. The transfer is described by a buf and will include 135739213Sgibbs * only one physical transfer. 135839213Sgibbs */ 135939213Sgibbsstatic void 136059249Sphkcdstrategy(struct bio *bp) 136139213Sgibbs{ 136239213Sgibbs struct cam_periph *periph; 136339213Sgibbs struct cd_softc *softc; 136439213Sgibbs u_int unit, part; 136539213Sgibbs int s; 136639213Sgibbs 136759249Sphk unit = dkunit(bp->bio_dev); 136859249Sphk part = dkpart(bp->bio_dev); 136939213Sgibbs periph = cam_extend_get(cdperiphs, unit); 137039213Sgibbs if (periph == NULL) { 137159249Sphk bp->bio_error = ENXIO; 137239213Sgibbs goto bad; 137339213Sgibbs } 137439213Sgibbs 137539213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdstrategy\n")); 137639213Sgibbs 137739213Sgibbs softc = (struct cd_softc *)periph->softc; 137839213Sgibbs 137939213Sgibbs /* 138039213Sgibbs * Mask interrupts so that the pack cannot be invalidated until 138139213Sgibbs * after we are in the queue. Otherwise, we might not properly 138239213Sgibbs * clean up one of the buffers. 138339213Sgibbs */ 138439213Sgibbs s = splbio(); 138539213Sgibbs 138639213Sgibbs /* 138739213Sgibbs * If the device has been made invalid, error out 138839213Sgibbs */ 138939213Sgibbs if ((softc->flags & CD_FLAG_INVALID)) { 139039213Sgibbs splx(s); 139159249Sphk bp->bio_error = ENXIO; 139239213Sgibbs goto bad; 139339213Sgibbs } 139439213Sgibbs 139539213Sgibbs /* 139639213Sgibbs * Place it in the queue of disk activities for this disk 139739213Sgibbs */ 139859249Sphk bioqdisksort(&softc->bio_queue, bp); 139939213Sgibbs 140039213Sgibbs splx(s); 140139213Sgibbs 140239213Sgibbs /* 140339213Sgibbs * Schedule ourselves for performing the work. We do things 140439213Sgibbs * differently for changers. 140539213Sgibbs */ 140639213Sgibbs if ((softc->flags & CD_FLAG_CHANGER) == 0) 140739213Sgibbs xpt_schedule(periph, /* XXX priority */1); 140839213Sgibbs else 140939213Sgibbs cdschedule(periph, /* priority */ 1); 141039213Sgibbs 141139213Sgibbs return; 141239213Sgibbsbad: 141359249Sphk bp->bio_flags |= BIO_ERROR; 141439213Sgibbs /* 141539213Sgibbs * Correctly set the buf to indicate a completed xfer 141639213Sgibbs */ 141759249Sphk bp->bio_resid = bp->bio_bcount; 141839213Sgibbs biodone(bp); 141939213Sgibbs return; 142039213Sgibbs} 142139213Sgibbs 142239213Sgibbsstatic void 142339213Sgibbscdstart(struct cam_periph *periph, union ccb *start_ccb) 142439213Sgibbs{ 142539213Sgibbs struct cd_softc *softc; 142659249Sphk struct bio *bp; 142739213Sgibbs struct ccb_scsiio *csio; 142839213Sgibbs struct scsi_read_capacity_data *rcap; 142939213Sgibbs int s; 143039213Sgibbs 143139213Sgibbs softc = (struct cd_softc *)periph->softc; 143239213Sgibbs 143339213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdstart\n")); 143439213Sgibbs 143539213Sgibbs switch (softc->state) { 143639213Sgibbs case CD_STATE_NORMAL: 143739213Sgibbs { 143839213Sgibbs int oldspl; 143939213Sgibbs 144039213Sgibbs s = splbio(); 144159249Sphk bp = bioq_first(&softc->bio_queue); 144239213Sgibbs if (periph->immediate_priority <= periph->pinfo.priority) { 144339213Sgibbs start_ccb->ccb_h.ccb_state = CD_CCB_WAITING; 144439213Sgibbs 144539213Sgibbs SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, 144639213Sgibbs periph_links.sle); 144739213Sgibbs periph->immediate_priority = CAM_PRIORITY_NONE; 144839213Sgibbs splx(s); 144939213Sgibbs wakeup(&periph->ccb_list); 145039213Sgibbs } else if (bp == NULL) { 145139213Sgibbs splx(s); 145239213Sgibbs xpt_release_ccb(start_ccb); 145339213Sgibbs } else { 145459249Sphk bioq_remove(&softc->bio_queue, bp); 145539213Sgibbs 145639213Sgibbs devstat_start_transaction(&softc->device_stats); 145739213Sgibbs 145839213Sgibbs scsi_read_write(&start_ccb->csio, 145939213Sgibbs /*retries*/4, 146039213Sgibbs /* cbfcnp */ cddone, 146159249Sphk (bp->bio_flags & BIO_ORDERED) != 0 ? 146239213Sgibbs MSG_ORDERED_Q_TAG : 146339213Sgibbs MSG_SIMPLE_Q_TAG, 146459249Sphk /* read */bp->bio_cmd == BIO_READ, 146539213Sgibbs /* byte2 */ 0, 146639213Sgibbs /* minimum_cmd_size */ 10, 146759249Sphk /* lba */ bp->bio_pblkno, 146859249Sphk bp->bio_bcount / softc->params.blksize, 146959249Sphk /* data_ptr */ bp->bio_data, 147059249Sphk /* dxfer_len */ bp->bio_bcount, 147139213Sgibbs /* sense_len */ SSD_FULL_SIZE, 147239213Sgibbs /* timeout */ 30000); 147339213Sgibbs start_ccb->ccb_h.ccb_state = CD_CCB_BUFFER_IO; 147439213Sgibbs 147539213Sgibbs 147639213Sgibbs /* 147739213Sgibbs * Block out any asyncronous callbacks 147839213Sgibbs * while we touch the pending ccb list. 147939213Sgibbs */ 148039213Sgibbs oldspl = splcam(); 148139213Sgibbs LIST_INSERT_HEAD(&softc->pending_ccbs, 148239213Sgibbs &start_ccb->ccb_h, periph_links.le); 148339213Sgibbs splx(oldspl); 148439213Sgibbs 148539213Sgibbs /* We expect a unit attention from this device */ 148639213Sgibbs if ((softc->flags & CD_FLAG_RETRY_UA) != 0) { 148739213Sgibbs start_ccb->ccb_h.ccb_state |= CD_CCB_RETRY_UA; 148839213Sgibbs softc->flags &= ~CD_FLAG_RETRY_UA; 148939213Sgibbs } 149039213Sgibbs 149139213Sgibbs start_ccb->ccb_h.ccb_bp = bp; 149259249Sphk bp = bioq_first(&softc->bio_queue); 149339213Sgibbs splx(s); 149439213Sgibbs 149539213Sgibbs xpt_action(start_ccb); 149639213Sgibbs } 149739213Sgibbs if (bp != NULL) { 149839213Sgibbs /* Have more work to do, so ensure we stay scheduled */ 149939213Sgibbs xpt_schedule(periph, /* XXX priority */1); 150039213Sgibbs } 150139213Sgibbs break; 150239213Sgibbs } 150339213Sgibbs case CD_STATE_PROBE: 150439213Sgibbs { 150539213Sgibbs 150639213Sgibbs rcap = (struct scsi_read_capacity_data *)malloc(sizeof(*rcap), 150739213Sgibbs M_TEMP, 150839213Sgibbs M_NOWAIT); 150939213Sgibbs if (rcap == NULL) { 151039213Sgibbs xpt_print_path(periph->path); 151139213Sgibbs printf("cdstart: Couldn't malloc read_capacity data\n"); 151239213Sgibbs /* cd_free_periph??? */ 151339213Sgibbs break; 151439213Sgibbs } 151539213Sgibbs csio = &start_ccb->csio; 151639213Sgibbs scsi_read_capacity(csio, 151739213Sgibbs /*retries*/1, 151839213Sgibbs cddone, 151939213Sgibbs MSG_SIMPLE_Q_TAG, 152039213Sgibbs rcap, 152139213Sgibbs SSD_FULL_SIZE, 152239213Sgibbs /*timeout*/20000); 152339213Sgibbs start_ccb->ccb_h.ccb_bp = NULL; 152439213Sgibbs start_ccb->ccb_h.ccb_state = CD_CCB_PROBE; 152539213Sgibbs xpt_action(start_ccb); 152639213Sgibbs break; 152739213Sgibbs } 152839213Sgibbs } 152939213Sgibbs} 153039213Sgibbs 153139213Sgibbsstatic void 153239213Sgibbscddone(struct cam_periph *periph, union ccb *done_ccb) 153339213Sgibbs{ 153439213Sgibbs struct cd_softc *softc; 153539213Sgibbs struct ccb_scsiio *csio; 153639213Sgibbs 153739213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cddone\n")); 153839213Sgibbs 153939213Sgibbs softc = (struct cd_softc *)periph->softc; 154039213Sgibbs csio = &done_ccb->csio; 154139213Sgibbs 154239213Sgibbs switch (csio->ccb_h.ccb_state & CD_CCB_TYPE_MASK) { 154339213Sgibbs case CD_CCB_BUFFER_IO: 154439213Sgibbs { 154559249Sphk struct bio *bp; 154639213Sgibbs int error; 154739213Sgibbs int oldspl; 154839213Sgibbs 154959249Sphk bp = (struct bio *)done_ccb->ccb_h.ccb_bp; 155039213Sgibbs error = 0; 155139213Sgibbs 155239213Sgibbs if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 155339213Sgibbs int sf; 155439213Sgibbs 155539213Sgibbs if ((done_ccb->ccb_h.ccb_state & CD_CCB_RETRY_UA) != 0) 155639213Sgibbs sf = SF_RETRY_UA; 155739213Sgibbs else 155839213Sgibbs sf = 0; 155946747Sken 156074840Sken error = cderror(done_ccb, CAM_RETRY_SELTO, sf); 156174840Sken if (error == ERESTART) { 156239213Sgibbs /* 156339213Sgibbs * A retry was scheuled, so 156439213Sgibbs * just return. 156539213Sgibbs */ 156639213Sgibbs return; 156739213Sgibbs } 156839213Sgibbs } 156939213Sgibbs 157039213Sgibbs if (error != 0) { 157139213Sgibbs int s; 157259249Sphk struct bio *q_bp; 157339213Sgibbs 157439213Sgibbs xpt_print_path(periph->path); 157539213Sgibbs printf("cddone: got error %#x back\n", error); 157639213Sgibbs s = splbio(); 157759249Sphk while ((q_bp = bioq_first(&softc->bio_queue)) != NULL) { 157859249Sphk bioq_remove(&softc->bio_queue, q_bp); 157959249Sphk q_bp->bio_resid = q_bp->bio_bcount; 158059249Sphk q_bp->bio_error = EIO; 158159249Sphk q_bp->bio_flags |= BIO_ERROR; 158239213Sgibbs biodone(q_bp); 158339213Sgibbs } 158439213Sgibbs splx(s); 158559249Sphk bp->bio_resid = bp->bio_bcount; 158659249Sphk bp->bio_error = error; 158759249Sphk bp->bio_flags |= BIO_ERROR; 158839213Sgibbs cam_release_devq(done_ccb->ccb_h.path, 158939213Sgibbs /*relsim_flags*/0, 159039213Sgibbs /*reduction*/0, 159139213Sgibbs /*timeout*/0, 159239213Sgibbs /*getcount_only*/0); 159339213Sgibbs 159439213Sgibbs } else { 159559249Sphk bp->bio_resid = csio->resid; 159659249Sphk bp->bio_error = 0; 159759249Sphk if (bp->bio_resid != 0) { 159839213Sgibbs /* Short transfer ??? */ 159959249Sphk bp->bio_flags |= BIO_ERROR; 160039213Sgibbs } 160139213Sgibbs } 160239213Sgibbs 160339213Sgibbs /* 160439213Sgibbs * Block out any asyncronous callbacks 160539213Sgibbs * while we touch the pending ccb list. 160639213Sgibbs */ 160739213Sgibbs oldspl = splcam(); 160839213Sgibbs LIST_REMOVE(&done_ccb->ccb_h, periph_links.le); 160939213Sgibbs splx(oldspl); 161039213Sgibbs 161139213Sgibbs if (softc->flags & CD_FLAG_CHANGER) 161239213Sgibbs cdchangerschedule(softc); 161339213Sgibbs 161459249Sphk devstat_end_transaction_bio(&softc->device_stats, bp); 161539213Sgibbs biodone(bp); 161639213Sgibbs break; 161739213Sgibbs } 161839213Sgibbs case CD_CCB_PROBE: 161939213Sgibbs { 162039213Sgibbs struct scsi_read_capacity_data *rdcap; 162139213Sgibbs char announce_buf[120]; /* 162239213Sgibbs * Currently (9/30/97) the 162339213Sgibbs * longest possible announce 162439213Sgibbs * buffer is 108 bytes, for the 162539213Sgibbs * first error case below. 162639213Sgibbs * That is 39 bytes for the 162739213Sgibbs * basic string, 16 bytes for the 162839213Sgibbs * biggest sense key (hardware 162939213Sgibbs * error), 52 bytes for the 163039213Sgibbs * text of the largest sense 163139213Sgibbs * qualifier valid for a CDROM, 163239213Sgibbs * (0x72, 0x03 or 0x04, 163339213Sgibbs * 0x03), and one byte for the 163439213Sgibbs * null terminating character. 163539213Sgibbs * To allow for longer strings, 163639213Sgibbs * the announce buffer is 120 163739213Sgibbs * bytes. 163839213Sgibbs */ 163939213Sgibbs struct cd_params *cdp; 164039213Sgibbs 164139213Sgibbs cdp = &softc->params; 164239213Sgibbs 164339213Sgibbs rdcap = (struct scsi_read_capacity_data *)csio->data_ptr; 164439213Sgibbs 164539213Sgibbs cdp->disksize = scsi_4btoul (rdcap->addr) + 1; 164639213Sgibbs cdp->blksize = scsi_4btoul (rdcap->length); 164739213Sgibbs 164839213Sgibbs if ((csio->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 164939213Sgibbs 165041514Sarchie snprintf(announce_buf, sizeof(announce_buf), 165140020Sken "cd present [%lu x %lu byte records]", 165240020Sken cdp->disksize, (u_long)cdp->blksize); 165339213Sgibbs 165439213Sgibbs } else { 165539213Sgibbs int error; 165639213Sgibbs /* 165739213Sgibbs * Retry any UNIT ATTENTION type errors. They 165839213Sgibbs * are expected at boot. 165939213Sgibbs */ 166074840Sken error = cderror(done_ccb, CAM_RETRY_SELTO, 166174840Sken SF_RETRY_UA | SF_NO_PRINT); 166239213Sgibbs if (error == ERESTART) { 166339213Sgibbs /* 166439213Sgibbs * A retry was scheuled, so 166539213Sgibbs * just return. 166639213Sgibbs */ 166739213Sgibbs return; 166839213Sgibbs } else if (error != 0) { 166939213Sgibbs 167039213Sgibbs struct scsi_sense_data *sense; 167139213Sgibbs int asc, ascq; 167239213Sgibbs int sense_key, error_code; 167339213Sgibbs int have_sense; 167439213Sgibbs cam_status status; 167539213Sgibbs struct ccb_getdev cgd; 167639213Sgibbs 167739213Sgibbs /* Don't wedge this device's queue */ 167839213Sgibbs cam_release_devq(done_ccb->ccb_h.path, 167939213Sgibbs /*relsim_flags*/0, 168039213Sgibbs /*reduction*/0, 168139213Sgibbs /*timeout*/0, 168239213Sgibbs /*getcount_only*/0); 168339213Sgibbs 168439213Sgibbs status = done_ccb->ccb_h.status; 168539213Sgibbs 168639213Sgibbs xpt_setup_ccb(&cgd.ccb_h, 168739213Sgibbs done_ccb->ccb_h.path, 168839213Sgibbs /* priority */ 1); 168939213Sgibbs cgd.ccb_h.func_code = XPT_GDEV_TYPE; 169039213Sgibbs xpt_action((union ccb *)&cgd); 169139213Sgibbs 169239213Sgibbs if (((csio->ccb_h.flags & CAM_SENSE_PHYS) != 0) 169339213Sgibbs || ((csio->ccb_h.flags & CAM_SENSE_PTR) != 0) 169439213Sgibbs || ((status & CAM_AUTOSNS_VALID) == 0)) 169539213Sgibbs have_sense = FALSE; 169639213Sgibbs else 169739213Sgibbs have_sense = TRUE; 169839213Sgibbs 169939213Sgibbs if (have_sense) { 170039213Sgibbs sense = &csio->sense_data; 170139213Sgibbs scsi_extract_sense(sense, &error_code, 170239213Sgibbs &sense_key, 170339213Sgibbs &asc, &ascq); 170439213Sgibbs } 170539213Sgibbs /* 170646581Sken * Attach to anything that claims to be a 170746581Sken * CDROM or WORM device, as long as it 170846581Sken * doesn't return a "Logical unit not 170946581Sken * supported" (0x25) error. 171039213Sgibbs */ 171146581Sken if ((have_sense) && (asc != 0x25) 171274840Sken && (error_code == SSD_CURRENT_ERROR)) { 171374840Sken const char *sense_key_desc; 171474840Sken const char *asc_desc; 171574840Sken 171674840Sken scsi_sense_desc(sense_key, asc, ascq, 171774840Sken &cgd.inq_data, 171874840Sken &sense_key_desc, 171974840Sken &asc_desc); 172041514Sarchie snprintf(announce_buf, 172141514Sarchie sizeof(announce_buf), 172239213Sgibbs "Attempt to query device " 172339213Sgibbs "size failed: %s, %s", 172474840Sken sense_key_desc, 172574840Sken asc_desc); 172674840Sken } else if (SID_TYPE(&cgd.inq_data) == T_CDROM) { 172739213Sgibbs /* 172839213Sgibbs * We only print out an error for 172939213Sgibbs * CDROM type devices. For WORM 173039213Sgibbs * devices, we don't print out an 173139213Sgibbs * error since a few WORM devices 173239213Sgibbs * don't support CDROM commands. 173339213Sgibbs * If we have sense information, go 173439213Sgibbs * ahead and print it out. 173539213Sgibbs * Otherwise, just say that we 173639213Sgibbs * couldn't attach. 173739213Sgibbs */ 173839213Sgibbs 173939213Sgibbs /* 174039213Sgibbs * Just print out the error, not 174139213Sgibbs * the full probe message, when we 174239213Sgibbs * don't attach. 174339213Sgibbs */ 174440020Sken if (have_sense) 174540020Sken scsi_sense_print( 174640020Sken &done_ccb->csio); 174740020Sken else { 174840020Sken xpt_print_path(periph->path); 174940020Sken printf("got CAM status %#x\n", 175040020Sken done_ccb->ccb_h.status); 175140020Sken } 175240020Sken xpt_print_path(periph->path); 175340020Sken printf("fatal error, failed" 175440603Sken " to attach to device\n"); 175539213Sgibbs 175639213Sgibbs /* 175740603Sken * Invalidate this peripheral. 175839213Sgibbs */ 175939213Sgibbs cam_periph_invalidate(periph); 176040020Sken 176140020Sken announce_buf[0] = '\0'; 176239213Sgibbs } else { 176340603Sken 176439213Sgibbs /* 176540603Sken * Invalidate this peripheral. 176639213Sgibbs */ 176739213Sgibbs cam_periph_invalidate(periph); 176840020Sken announce_buf[0] = '\0'; 176939213Sgibbs } 177039213Sgibbs } 177139213Sgibbs } 177239213Sgibbs free(rdcap, M_TEMP); 177342378Smjacob if (announce_buf[0] != '\0') { 177439213Sgibbs xpt_announce_periph(periph, announce_buf); 177542378Smjacob if (softc->flags & CD_FLAG_CHANGER) 177642378Smjacob cdchangerschedule(softc); 177742378Smjacob } 177840020Sken softc->state = CD_STATE_NORMAL; 177942378Smjacob /* 178042378Smjacob * Since our peripheral may be invalidated by an error 178142378Smjacob * above or an external event, we must release our CCB 178242378Smjacob * before releasing the probe lock on the peripheral. 178342378Smjacob * The peripheral will only go away once the last lock 178442378Smjacob * is removed, and we need it around for the CCB release 178542378Smjacob * operation. 178642378Smjacob */ 178742378Smjacob xpt_release_ccb(done_ccb); 178840020Sken cam_periph_unlock(periph); 178942378Smjacob return; 179039213Sgibbs } 179139213Sgibbs case CD_CCB_WAITING: 179239213Sgibbs { 179339213Sgibbs /* Caller will release the CCB */ 179439213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, 179539213Sgibbs ("trying to wakeup ccbwait\n")); 179639213Sgibbs 179739213Sgibbs wakeup(&done_ccb->ccb_h.cbfcnp); 179839213Sgibbs return; 179939213Sgibbs } 180042378Smjacob default: 180142378Smjacob break; 180239213Sgibbs } 180339213Sgibbs xpt_release_ccb(done_ccb); 180439213Sgibbs} 180539213Sgibbs 180639213Sgibbsstatic int 180739213Sgibbscdioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) 180839213Sgibbs{ 180939213Sgibbs 181039213Sgibbs struct cam_periph *periph; 181139213Sgibbs struct cd_softc *softc; 181240020Sken int error, unit; 181339213Sgibbs 181439213Sgibbs unit = dkunit(dev); 181539213Sgibbs 181639213Sgibbs periph = cam_extend_get(cdperiphs, unit); 181739213Sgibbs if (periph == NULL) 181839213Sgibbs return(ENXIO); 181939213Sgibbs 182039213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdioctl\n")); 182139213Sgibbs 182239213Sgibbs softc = (struct cd_softc *)periph->softc; 182339213Sgibbs 182439213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, 182540020Sken ("trying to do ioctl %#lx\n", cmd)); 182639213Sgibbs 182740020Sken error = cam_periph_lock(periph, PRIBIO | PCATCH); 182839213Sgibbs 182940020Sken if (error != 0) 183040020Sken return(error); 183140020Sken 183239213Sgibbs switch (cmd) { 183339213Sgibbs 183439213Sgibbs case CDIOCPLAYTRACKS: 183539213Sgibbs { 183639213Sgibbs struct ioc_play_track *args 183739213Sgibbs = (struct ioc_play_track *) addr; 183839213Sgibbs struct cd_mode_data *data; 183939213Sgibbs 184039213Sgibbs data = malloc(sizeof(struct cd_mode_data), M_TEMP, 184139213Sgibbs M_WAITOK); 184239213Sgibbs 184339213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 184439213Sgibbs ("trying to do CDIOCPLAYTRACKS\n")); 184539213Sgibbs 184639213Sgibbs error = cdgetmode(periph, data, AUDIO_PAGE); 184739213Sgibbs if (error) { 184839213Sgibbs free(data, M_TEMP); 184939213Sgibbs break; 185039213Sgibbs } 185139213Sgibbs data->page.audio.flags &= ~CD_PA_SOTC; 185239213Sgibbs data->page.audio.flags |= CD_PA_IMMED; 185339213Sgibbs error = cdsetmode(periph, data); 185439213Sgibbs free(data, M_TEMP); 185539213Sgibbs if (error) 185639213Sgibbs break; 185739213Sgibbs if (softc->quirks & CD_Q_BCD_TRACKS) { 185839213Sgibbs args->start_track = bin2bcd(args->start_track); 185939213Sgibbs args->end_track = bin2bcd(args->end_track); 186039213Sgibbs } 186139213Sgibbs error = cdplaytracks(periph, 186239213Sgibbs args->start_track, 186339213Sgibbs args->start_index, 186439213Sgibbs args->end_track, 186539213Sgibbs args->end_index); 186639213Sgibbs } 186739213Sgibbs break; 186839213Sgibbs case CDIOCPLAYMSF: 186939213Sgibbs { 187039213Sgibbs struct ioc_play_msf *args 187139213Sgibbs = (struct ioc_play_msf *) addr; 187239213Sgibbs struct cd_mode_data *data; 187339213Sgibbs 187439213Sgibbs data = malloc(sizeof(struct cd_mode_data), M_TEMP, 187539213Sgibbs M_WAITOK); 187639213Sgibbs 187739213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 187839213Sgibbs ("trying to do CDIOCPLAYMSF\n")); 187939213Sgibbs 188039213Sgibbs error = cdgetmode(periph, data, AUDIO_PAGE); 188139213Sgibbs if (error) { 188239213Sgibbs free(data, M_TEMP); 188339213Sgibbs break; 188439213Sgibbs } 188539213Sgibbs data->page.audio.flags &= ~CD_PA_SOTC; 188639213Sgibbs data->page.audio.flags |= CD_PA_IMMED; 188739213Sgibbs error = cdsetmode(periph, data); 188839213Sgibbs free(data, M_TEMP); 188939213Sgibbs if (error) 189039213Sgibbs break; 189139213Sgibbs error = cdplaymsf(periph, 189239213Sgibbs args->start_m, 189339213Sgibbs args->start_s, 189439213Sgibbs args->start_f, 189539213Sgibbs args->end_m, 189639213Sgibbs args->end_s, 189739213Sgibbs args->end_f); 189839213Sgibbs } 189939213Sgibbs break; 190039213Sgibbs case CDIOCPLAYBLOCKS: 190139213Sgibbs { 190239213Sgibbs struct ioc_play_blocks *args 190339213Sgibbs = (struct ioc_play_blocks *) addr; 190439213Sgibbs struct cd_mode_data *data; 190539213Sgibbs 190639213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 190739213Sgibbs ("trying to do CDIOCPLAYBLOCKS\n")); 190839213Sgibbs 190939213Sgibbs data = malloc(sizeof(struct cd_mode_data), M_TEMP, 191039213Sgibbs M_WAITOK); 191139213Sgibbs 191239213Sgibbs error = cdgetmode(periph, data, AUDIO_PAGE); 191339213Sgibbs if (error) { 191439213Sgibbs free(data, M_TEMP); 191539213Sgibbs break; 191639213Sgibbs } 191739213Sgibbs data->page.audio.flags &= ~CD_PA_SOTC; 191839213Sgibbs data->page.audio.flags |= CD_PA_IMMED; 191939213Sgibbs error = cdsetmode(periph, data); 192039213Sgibbs free(data, M_TEMP); 192139213Sgibbs if (error) 192239213Sgibbs break; 192339213Sgibbs error = cdplay(periph, args->blk, args->len); 192439213Sgibbs } 192539213Sgibbs break; 192639213Sgibbs case CDIOCREADSUBCHANNEL: 192739213Sgibbs { 192839213Sgibbs struct ioc_read_subchannel *args 192939213Sgibbs = (struct ioc_read_subchannel *) addr; 193039213Sgibbs struct cd_sub_channel_info *data; 193139213Sgibbs u_int32_t len = args->data_len; 193239213Sgibbs 193339213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 193439213Sgibbs ("trying to do CDIOCREADSUBCHANNEL\n")); 193539213Sgibbs 193639213Sgibbs data = malloc(sizeof(struct cd_sub_channel_info), 193739213Sgibbs M_TEMP, M_WAITOK); 193839213Sgibbs 193939213Sgibbs if ((len > sizeof(struct cd_sub_channel_info)) || 194039213Sgibbs (len < sizeof(struct cd_sub_channel_header))) { 194139213Sgibbs printf( 194239213Sgibbs "scsi_cd: cdioctl: " 194339213Sgibbs "cdioreadsubchannel: error, len=%d\n", 194439213Sgibbs len); 194539213Sgibbs error = EINVAL; 194639213Sgibbs free(data, M_TEMP); 194739213Sgibbs break; 194839213Sgibbs } 194939213Sgibbs 195039213Sgibbs if (softc->quirks & CD_Q_BCD_TRACKS) 195139213Sgibbs args->track = bin2bcd(args->track); 195239213Sgibbs 195339213Sgibbs error = cdreadsubchannel(periph, args->address_format, 195439213Sgibbs args->data_format, args->track, data, len); 195539213Sgibbs 195639213Sgibbs if (error) { 195739213Sgibbs free(data, M_TEMP); 195839213Sgibbs break; 195939213Sgibbs } 196039213Sgibbs if (softc->quirks & CD_Q_BCD_TRACKS) 196139213Sgibbs data->what.track_info.track_number = 196239213Sgibbs bcd2bin(data->what.track_info.track_number); 196339213Sgibbs len = min(len, ((data->header.data_len[0] << 8) + 196439213Sgibbs data->header.data_len[1] + 196539213Sgibbs sizeof(struct cd_sub_channel_header))); 196639213Sgibbs if (copyout(data, args->data, len) != 0) { 196739213Sgibbs error = EFAULT; 196839213Sgibbs } 196939213Sgibbs free(data, M_TEMP); 197039213Sgibbs } 197139213Sgibbs break; 197239213Sgibbs 197339213Sgibbs case CDIOREADTOCHEADER: 197439213Sgibbs { 197539213Sgibbs struct ioc_toc_header *th; 197639213Sgibbs 197739213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 197839213Sgibbs ("trying to do CDIOREADTOCHEADER\n")); 197939213Sgibbs 198039213Sgibbs th = malloc(sizeof(struct ioc_toc_header), M_TEMP, 198139213Sgibbs M_WAITOK); 198239213Sgibbs error = cdreadtoc(periph, 0, 0, 198339213Sgibbs (struct cd_toc_entry *)th, 198439213Sgibbs sizeof (*th)); 198539213Sgibbs if (error) { 198639213Sgibbs free(th, M_TEMP); 198739213Sgibbs break; 198839213Sgibbs } 198939213Sgibbs if (softc->quirks & CD_Q_BCD_TRACKS) { 199039213Sgibbs /* we are going to have to convert the BCD 199139213Sgibbs * encoding on the cd to what is expected 199239213Sgibbs */ 199339213Sgibbs th->starting_track = 199439213Sgibbs bcd2bin(th->starting_track); 199539213Sgibbs th->ending_track = bcd2bin(th->ending_track); 199639213Sgibbs } 199739213Sgibbs NTOHS(th->len); 199839213Sgibbs bcopy(th, addr, sizeof(*th)); 199939213Sgibbs free(th, M_TEMP); 200039213Sgibbs } 200139213Sgibbs break; 200239213Sgibbs case CDIOREADTOCENTRYS: 200339213Sgibbs { 200439213Sgibbs typedef struct { 200539213Sgibbs struct ioc_toc_header header; 200639213Sgibbs struct cd_toc_entry entries[100]; 200739213Sgibbs } data_t; 200839213Sgibbs typedef struct { 200939213Sgibbs struct ioc_toc_header header; 201039213Sgibbs struct cd_toc_entry entry; 201139213Sgibbs } lead_t; 201239213Sgibbs 201339213Sgibbs data_t *data; 201439213Sgibbs lead_t *lead; 201539213Sgibbs struct ioc_read_toc_entry *te = 201639213Sgibbs (struct ioc_read_toc_entry *) addr; 201739213Sgibbs struct ioc_toc_header *th; 201839213Sgibbs u_int32_t len, readlen, idx, num; 201939213Sgibbs u_int32_t starting_track = te->starting_track; 202039213Sgibbs 202139213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 202239213Sgibbs ("trying to do CDIOREADTOCENTRYS\n")); 202339213Sgibbs 202439213Sgibbs data = malloc(sizeof(data_t), M_TEMP, M_WAITOK); 202539213Sgibbs lead = malloc(sizeof(lead_t), M_TEMP, M_WAITOK); 202639213Sgibbs 202739213Sgibbs if (te->data_len < sizeof(struct cd_toc_entry) 202839213Sgibbs || (te->data_len % sizeof(struct cd_toc_entry)) != 0 202939213Sgibbs || (te->address_format != CD_MSF_FORMAT 203039213Sgibbs && te->address_format != CD_LBA_FORMAT)) { 203139213Sgibbs error = EINVAL; 203239213Sgibbs printf("scsi_cd: error in readtocentries, " 203339213Sgibbs "returning EINVAL\n"); 203439213Sgibbs free(data, M_TEMP); 203539213Sgibbs free(lead, M_TEMP); 203639213Sgibbs break; 203739213Sgibbs } 203839213Sgibbs 203939213Sgibbs th = &data->header; 204039213Sgibbs error = cdreadtoc(periph, 0, 0, 204139213Sgibbs (struct cd_toc_entry *)th, 204239213Sgibbs sizeof (*th)); 204339213Sgibbs if (error) { 204439213Sgibbs free(data, M_TEMP); 204539213Sgibbs free(lead, M_TEMP); 204639213Sgibbs break; 204739213Sgibbs } 204839213Sgibbs 204939213Sgibbs if (softc->quirks & CD_Q_BCD_TRACKS) { 205039213Sgibbs /* we are going to have to convert the BCD 205139213Sgibbs * encoding on the cd to what is expected 205239213Sgibbs */ 205339213Sgibbs th->starting_track = 205439213Sgibbs bcd2bin(th->starting_track); 205539213Sgibbs th->ending_track = bcd2bin(th->ending_track); 205639213Sgibbs } 205739213Sgibbs 205839213Sgibbs if (starting_track == 0) 205939213Sgibbs starting_track = th->starting_track; 206039213Sgibbs else if (starting_track == LEADOUT) 206139213Sgibbs starting_track = th->ending_track + 1; 206239213Sgibbs else if (starting_track < th->starting_track || 206339213Sgibbs starting_track > th->ending_track + 1) { 206439213Sgibbs printf("scsi_cd: error in readtocentries, " 206539213Sgibbs "returning EINVAL\n"); 206639213Sgibbs free(data, M_TEMP); 206739213Sgibbs free(lead, M_TEMP); 206839213Sgibbs error = EINVAL; 206939213Sgibbs break; 207039213Sgibbs } 207139213Sgibbs 207239213Sgibbs /* calculate reading length without leadout entry */ 207339213Sgibbs readlen = (th->ending_track - starting_track + 1) * 207439213Sgibbs sizeof(struct cd_toc_entry); 207539213Sgibbs 207639213Sgibbs /* and with leadout entry */ 207739213Sgibbs len = readlen + sizeof(struct cd_toc_entry); 207839213Sgibbs if (te->data_len < len) { 207939213Sgibbs len = te->data_len; 208039213Sgibbs if (readlen > len) 208139213Sgibbs readlen = len; 208239213Sgibbs } 208339213Sgibbs if (len > sizeof(data->entries)) { 208439213Sgibbs printf("scsi_cd: error in readtocentries, " 208539213Sgibbs "returning EINVAL\n"); 208639213Sgibbs error = EINVAL; 208739213Sgibbs free(data, M_TEMP); 208839213Sgibbs free(lead, M_TEMP); 208939213Sgibbs break; 209039213Sgibbs } 209139213Sgibbs num = len / sizeof(struct cd_toc_entry); 209239213Sgibbs 209339213Sgibbs if (readlen > 0) { 209439213Sgibbs error = cdreadtoc(periph, te->address_format, 209539213Sgibbs starting_track, 209639213Sgibbs (struct cd_toc_entry *)data, 209739213Sgibbs readlen + sizeof (*th)); 209839213Sgibbs if (error) { 209939213Sgibbs free(data, M_TEMP); 210039213Sgibbs free(lead, M_TEMP); 210139213Sgibbs break; 210239213Sgibbs } 210339213Sgibbs } 210439213Sgibbs 210539213Sgibbs /* make leadout entry if needed */ 210639213Sgibbs idx = starting_track + num - 1; 210739213Sgibbs if (softc->quirks & CD_Q_BCD_TRACKS) 210839213Sgibbs th->ending_track = bcd2bin(th->ending_track); 210939213Sgibbs if (idx == th->ending_track + 1) { 211039213Sgibbs error = cdreadtoc(periph, te->address_format, 211139213Sgibbs LEADOUT, 211239213Sgibbs (struct cd_toc_entry *)lead, 211339213Sgibbs sizeof(*lead)); 211439213Sgibbs if (error) { 211539213Sgibbs free(data, M_TEMP); 211639213Sgibbs free(lead, M_TEMP); 211739213Sgibbs break; 211839213Sgibbs } 211939213Sgibbs data->entries[idx - starting_track] = 212039213Sgibbs lead->entry; 212139213Sgibbs } 212239213Sgibbs if (softc->quirks & CD_Q_BCD_TRACKS) { 212339213Sgibbs for (idx = 0; idx < num - 1; idx++) { 212439213Sgibbs data->entries[idx].track = 212539213Sgibbs bcd2bin(data->entries[idx].track); 212639213Sgibbs } 212739213Sgibbs } 212839213Sgibbs 212939213Sgibbs error = copyout(data->entries, te->data, len); 213039213Sgibbs free(data, M_TEMP); 213139213Sgibbs free(lead, M_TEMP); 213239213Sgibbs } 213339213Sgibbs break; 213439213Sgibbs case CDIOREADTOCENTRY: 213539213Sgibbs { 213639213Sgibbs /* yeah yeah, this is ugly */ 213739213Sgibbs typedef struct { 213839213Sgibbs struct ioc_toc_header header; 213939213Sgibbs struct cd_toc_entry entry; 214039213Sgibbs } data_t; 214139213Sgibbs 214239213Sgibbs data_t *data; 214339213Sgibbs struct ioc_read_toc_single_entry *te = 214439213Sgibbs (struct ioc_read_toc_single_entry *) addr; 214539213Sgibbs struct ioc_toc_header *th; 214639213Sgibbs u_int32_t track; 214739213Sgibbs 214839213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 214939213Sgibbs ("trying to do CDIOREADTOCENTRY\n")); 215039213Sgibbs 215139213Sgibbs data = malloc(sizeof(data_t), M_TEMP, M_WAITOK); 215239213Sgibbs 215339213Sgibbs if (te->address_format != CD_MSF_FORMAT 215439213Sgibbs && te->address_format != CD_LBA_FORMAT) { 215539213Sgibbs printf("error in readtocentry, " 215639213Sgibbs " returning EINVAL\n"); 215739213Sgibbs free(data, M_TEMP); 215839213Sgibbs error = EINVAL; 215939213Sgibbs break; 216039213Sgibbs } 216139213Sgibbs 216239213Sgibbs th = &data->header; 216339213Sgibbs error = cdreadtoc(periph, 0, 0, 216439213Sgibbs (struct cd_toc_entry *)th, 216539213Sgibbs sizeof (*th)); 216639213Sgibbs if (error) { 216739213Sgibbs free(data, M_TEMP); 216839213Sgibbs break; 216939213Sgibbs } 217039213Sgibbs 217139213Sgibbs if (softc->quirks & CD_Q_BCD_TRACKS) { 217239213Sgibbs /* we are going to have to convert the BCD 217339213Sgibbs * encoding on the cd to what is expected 217439213Sgibbs */ 217539213Sgibbs th->starting_track = 217639213Sgibbs bcd2bin(th->starting_track); 217739213Sgibbs th->ending_track = bcd2bin(th->ending_track); 217839213Sgibbs } 217939213Sgibbs track = te->track; 218039213Sgibbs if (track == 0) 218139213Sgibbs track = th->starting_track; 218239213Sgibbs else if (track == LEADOUT) 218339213Sgibbs /* OK */; 218439213Sgibbs else if (track < th->starting_track || 218539213Sgibbs track > th->ending_track + 1) { 218639213Sgibbs printf("error in readtocentry, " 218739213Sgibbs " returning EINVAL\n"); 218839213Sgibbs free(data, M_TEMP); 218939213Sgibbs error = EINVAL; 219039213Sgibbs break; 219139213Sgibbs } 219239213Sgibbs 219339213Sgibbs error = cdreadtoc(periph, te->address_format, track, 219439213Sgibbs (struct cd_toc_entry *)data, 219539213Sgibbs sizeof(data_t)); 219639213Sgibbs if (error) { 219739213Sgibbs free(data, M_TEMP); 219839213Sgibbs break; 219939213Sgibbs } 220039213Sgibbs 220139213Sgibbs if (softc->quirks & CD_Q_BCD_TRACKS) 220239213Sgibbs data->entry.track = bcd2bin(data->entry.track); 220339213Sgibbs bcopy(&data->entry, &te->entry, 220439213Sgibbs sizeof(struct cd_toc_entry)); 220539213Sgibbs free(data, M_TEMP); 220639213Sgibbs } 220739213Sgibbs break; 220839213Sgibbs case CDIOCSETPATCH: 220939213Sgibbs { 221039213Sgibbs struct ioc_patch *arg = (struct ioc_patch *) addr; 221139213Sgibbs struct cd_mode_data *data; 221239213Sgibbs 221339213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 221439213Sgibbs ("trying to do CDIOCSETPATCH\n")); 221539213Sgibbs 221639213Sgibbs data = malloc(sizeof(struct cd_mode_data), M_TEMP, 221739213Sgibbs M_WAITOK); 221839213Sgibbs error = cdgetmode(periph, data, AUDIO_PAGE); 221939213Sgibbs if (error) { 222039213Sgibbs free(data, M_TEMP); 222139213Sgibbs break; 222239213Sgibbs } 222339213Sgibbs data->page.audio.port[LEFT_PORT].channels = 222439213Sgibbs arg->patch[0]; 222539213Sgibbs data->page.audio.port[RIGHT_PORT].channels = 222639213Sgibbs arg->patch[1]; 222739213Sgibbs data->page.audio.port[2].channels = arg->patch[2]; 222839213Sgibbs data->page.audio.port[3].channels = arg->patch[3]; 222939213Sgibbs error = cdsetmode(periph, data); 223039213Sgibbs free(data, M_TEMP); 223139213Sgibbs } 223239213Sgibbs break; 223339213Sgibbs case CDIOCGETVOL: 223439213Sgibbs { 223539213Sgibbs struct ioc_vol *arg = (struct ioc_vol *) addr; 223639213Sgibbs struct cd_mode_data *data; 223739213Sgibbs 223839213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 223939213Sgibbs ("trying to do CDIOCGETVOL\n")); 224039213Sgibbs 224139213Sgibbs data = malloc(sizeof(struct cd_mode_data), M_TEMP, 224239213Sgibbs M_WAITOK); 224339213Sgibbs error = cdgetmode(periph, data, AUDIO_PAGE); 224439213Sgibbs if (error) { 224539213Sgibbs free(data, M_TEMP); 224639213Sgibbs break; 224739213Sgibbs } 224839213Sgibbs arg->vol[LEFT_PORT] = 224939213Sgibbs data->page.audio.port[LEFT_PORT].volume; 225039213Sgibbs arg->vol[RIGHT_PORT] = 225139213Sgibbs data->page.audio.port[RIGHT_PORT].volume; 225239213Sgibbs arg->vol[2] = data->page.audio.port[2].volume; 225339213Sgibbs arg->vol[3] = data->page.audio.port[3].volume; 225439213Sgibbs free(data, M_TEMP); 225539213Sgibbs } 225639213Sgibbs break; 225739213Sgibbs case CDIOCSETVOL: 225839213Sgibbs { 225939213Sgibbs struct ioc_vol *arg = (struct ioc_vol *) addr; 226039213Sgibbs struct cd_mode_data *data; 226139213Sgibbs 226239213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 226339213Sgibbs ("trying to do CDIOCSETVOL\n")); 226439213Sgibbs 226539213Sgibbs data = malloc(sizeof(struct cd_mode_data), M_TEMP, 226639213Sgibbs M_WAITOK); 226739213Sgibbs error = cdgetmode(periph, data, AUDIO_PAGE); 226839213Sgibbs if (error) { 226939213Sgibbs free(data, M_TEMP); 227039213Sgibbs break; 227139213Sgibbs } 227239213Sgibbs data->page.audio.port[LEFT_PORT].channels = CHANNEL_0; 227339213Sgibbs data->page.audio.port[LEFT_PORT].volume = 227439213Sgibbs arg->vol[LEFT_PORT]; 227539213Sgibbs data->page.audio.port[RIGHT_PORT].channels = CHANNEL_1; 227639213Sgibbs data->page.audio.port[RIGHT_PORT].volume = 227739213Sgibbs arg->vol[RIGHT_PORT]; 227839213Sgibbs data->page.audio.port[2].volume = arg->vol[2]; 227939213Sgibbs data->page.audio.port[3].volume = arg->vol[3]; 228039213Sgibbs error = cdsetmode(periph, data); 228139213Sgibbs free(data, M_TEMP); 228239213Sgibbs } 228339213Sgibbs break; 228439213Sgibbs case CDIOCSETMONO: 228539213Sgibbs { 228639213Sgibbs struct cd_mode_data *data; 228739213Sgibbs 228839213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 228939213Sgibbs ("trying to do CDIOCSETMONO\n")); 229039213Sgibbs 229139213Sgibbs data = malloc(sizeof(struct cd_mode_data), 229239213Sgibbs M_TEMP, M_WAITOK); 229339213Sgibbs error = cdgetmode(periph, data, AUDIO_PAGE); 229439213Sgibbs if (error) { 229539213Sgibbs free(data, M_TEMP); 229639213Sgibbs break; 229739213Sgibbs } 229839213Sgibbs data->page.audio.port[LEFT_PORT].channels = 229939213Sgibbs LEFT_CHANNEL | RIGHT_CHANNEL; 230039213Sgibbs data->page.audio.port[RIGHT_PORT].channels = 230139213Sgibbs LEFT_CHANNEL | RIGHT_CHANNEL; 230239213Sgibbs data->page.audio.port[2].channels = 0; 230339213Sgibbs data->page.audio.port[3].channels = 0; 230439213Sgibbs error = cdsetmode(periph, data); 230539213Sgibbs free(data, M_TEMP); 230639213Sgibbs } 230739213Sgibbs break; 230839213Sgibbs case CDIOCSETSTEREO: 230939213Sgibbs { 231039213Sgibbs struct cd_mode_data *data; 231139213Sgibbs 231239213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 231339213Sgibbs ("trying to do CDIOCSETSTEREO\n")); 231439213Sgibbs 231539213Sgibbs data = malloc(sizeof(struct cd_mode_data), M_TEMP, 231639213Sgibbs M_WAITOK); 231739213Sgibbs error = cdgetmode(periph, data, AUDIO_PAGE); 231839213Sgibbs if (error) { 231939213Sgibbs free(data, M_TEMP); 232039213Sgibbs break; 232139213Sgibbs } 232239213Sgibbs data->page.audio.port[LEFT_PORT].channels = 232339213Sgibbs LEFT_CHANNEL; 232439213Sgibbs data->page.audio.port[RIGHT_PORT].channels = 232539213Sgibbs RIGHT_CHANNEL; 232639213Sgibbs data->page.audio.port[2].channels = 0; 232739213Sgibbs data->page.audio.port[3].channels = 0; 232839213Sgibbs error = cdsetmode(periph, data); 232939213Sgibbs free(data, M_TEMP); 233039213Sgibbs } 233139213Sgibbs break; 233239213Sgibbs case CDIOCSETMUTE: 233339213Sgibbs { 233439213Sgibbs struct cd_mode_data *data; 233539213Sgibbs 233639213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 233739213Sgibbs ("trying to do CDIOCSETMUTE\n")); 233839213Sgibbs 233939213Sgibbs data = malloc(sizeof(struct cd_mode_data), M_TEMP, 234039213Sgibbs M_WAITOK); 234139213Sgibbs error = cdgetmode(periph, data, AUDIO_PAGE); 234239213Sgibbs if (error) { 234339213Sgibbs free(data, M_TEMP); 234439213Sgibbs break; 234539213Sgibbs } 234639213Sgibbs data->page.audio.port[LEFT_PORT].channels = 0; 234739213Sgibbs data->page.audio.port[RIGHT_PORT].channels = 0; 234839213Sgibbs data->page.audio.port[2].channels = 0; 234939213Sgibbs data->page.audio.port[3].channels = 0; 235039213Sgibbs error = cdsetmode(periph, data); 235139213Sgibbs free(data, M_TEMP); 235239213Sgibbs } 235339213Sgibbs break; 235439213Sgibbs case CDIOCSETLEFT: 235539213Sgibbs { 235639213Sgibbs struct cd_mode_data *data; 235739213Sgibbs 235839213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 235939213Sgibbs ("trying to do CDIOCSETLEFT\n")); 236039213Sgibbs 236139213Sgibbs data = malloc(sizeof(struct cd_mode_data), M_TEMP, 236239213Sgibbs M_WAITOK); 236339213Sgibbs error = cdgetmode(periph, data, AUDIO_PAGE); 236439213Sgibbs if (error) { 236539213Sgibbs free(data, M_TEMP); 236639213Sgibbs break; 236739213Sgibbs } 236839213Sgibbs data->page.audio.port[LEFT_PORT].channels = 236939213Sgibbs LEFT_CHANNEL; 237039213Sgibbs data->page.audio.port[RIGHT_PORT].channels = 237139213Sgibbs LEFT_CHANNEL; 237239213Sgibbs data->page.audio.port[2].channels = 0; 237339213Sgibbs data->page.audio.port[3].channels = 0; 237439213Sgibbs error = cdsetmode(periph, data); 237539213Sgibbs free(data, M_TEMP); 237639213Sgibbs } 237739213Sgibbs break; 237839213Sgibbs case CDIOCSETRIGHT: 237939213Sgibbs { 238039213Sgibbs struct cd_mode_data *data; 238139213Sgibbs 238239213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 238339213Sgibbs ("trying to do CDIOCSETRIGHT\n")); 238439213Sgibbs 238539213Sgibbs data = malloc(sizeof(struct cd_mode_data), M_TEMP, 238639213Sgibbs M_WAITOK); 238739213Sgibbs error = cdgetmode(periph, data, AUDIO_PAGE); 238839213Sgibbs if (error) { 238939213Sgibbs free(data, M_TEMP); 239039213Sgibbs break; 239139213Sgibbs } 239239213Sgibbs data->page.audio.port[LEFT_PORT].channels = 239339213Sgibbs RIGHT_CHANNEL; 239439213Sgibbs data->page.audio.port[RIGHT_PORT].channels = 239539213Sgibbs RIGHT_CHANNEL; 239639213Sgibbs data->page.audio.port[2].channels = 0; 239739213Sgibbs data->page.audio.port[3].channels = 0; 239839213Sgibbs error = cdsetmode(periph, data); 239939213Sgibbs free(data, M_TEMP); 240039213Sgibbs } 240139213Sgibbs break; 240239213Sgibbs case CDIOCRESUME: 240339213Sgibbs error = cdpause(periph, 1); 240439213Sgibbs break; 240539213Sgibbs case CDIOCPAUSE: 240639213Sgibbs error = cdpause(periph, 0); 240739213Sgibbs break; 240839213Sgibbs case CDIOCSTART: 240939213Sgibbs error = cdstartunit(periph); 241039213Sgibbs break; 241139213Sgibbs case CDIOCSTOP: 241239213Sgibbs error = cdstopunit(periph, 0); 241339213Sgibbs break; 241439213Sgibbs case CDIOCEJECT: 241539213Sgibbs error = cdstopunit(periph, 1); 241639213Sgibbs break; 241739213Sgibbs case CDIOCALLOW: 241839213Sgibbs cdprevent(periph, PR_ALLOW); 241939213Sgibbs break; 242039213Sgibbs case CDIOCPREVENT: 242139213Sgibbs cdprevent(periph, PR_PREVENT); 242239213Sgibbs break; 242339213Sgibbs case CDIOCSETDEBUG: 242439213Sgibbs /* sc_link->flags |= (SDEV_DB1 | SDEV_DB2); */ 242539213Sgibbs error = ENOTTY; 242639213Sgibbs break; 242739213Sgibbs case CDIOCCLRDEBUG: 242839213Sgibbs /* sc_link->flags &= ~(SDEV_DB1 | SDEV_DB2); */ 242939213Sgibbs error = ENOTTY; 243039213Sgibbs break; 243139213Sgibbs case CDIOCRESET: 243239213Sgibbs /* return (cd_reset(periph)); */ 243339213Sgibbs error = ENOTTY; 243439213Sgibbs break; 243560422Sken case DVDIOCSENDKEY: 243660422Sken case DVDIOCREPORTKEY: { 243760422Sken struct dvd_authinfo *authinfo; 243860422Sken 243960422Sken authinfo = (struct dvd_authinfo *)addr; 244060422Sken 244160422Sken if (cmd == DVDIOCREPORTKEY) 244260422Sken error = cdreportkey(periph, authinfo); 244360422Sken else 244460422Sken error = cdsendkey(periph, authinfo); 244560422Sken break; 244660422Sken } 244760422Sken case DVDIOCREADSTRUCTURE: { 244860422Sken struct dvd_struct *dvdstruct; 244960422Sken 245060422Sken dvdstruct = (struct dvd_struct *)addr; 245160422Sken 245260422Sken error = cdreaddvdstructure(periph, dvdstruct); 245360422Sken 245460422Sken break; 245560422Sken } 245639213Sgibbs default: 245739213Sgibbs error = cam_periph_ioctl(periph, cmd, addr, cderror); 245839213Sgibbs break; 245939213Sgibbs } 246039213Sgibbs 246140020Sken cam_periph_unlock(periph); 246240020Sken 246339213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("leaving cdioctl\n")); 246439213Sgibbs 246539213Sgibbs return (error); 246639213Sgibbs} 246739213Sgibbs 246839213Sgibbsstatic void 246939213Sgibbscdprevent(struct cam_periph *periph, int action) 247039213Sgibbs{ 247139213Sgibbs union ccb *ccb; 247239213Sgibbs struct cd_softc *softc; 247339213Sgibbs int error; 247439213Sgibbs 247539213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdprevent\n")); 247639213Sgibbs 247739213Sgibbs softc = (struct cd_softc *)periph->softc; 247839213Sgibbs 247939213Sgibbs if (((action == PR_ALLOW) 248039213Sgibbs && (softc->flags & CD_FLAG_DISC_LOCKED) == 0) 248139213Sgibbs || ((action == PR_PREVENT) 248239213Sgibbs && (softc->flags & CD_FLAG_DISC_LOCKED) != 0)) { 248339213Sgibbs return; 248439213Sgibbs } 248539213Sgibbs 248639213Sgibbs ccb = cdgetccb(periph, /* priority */ 1); 248739213Sgibbs 248839213Sgibbs scsi_prevent(&ccb->csio, 248939213Sgibbs /*retries*/ 1, 249039213Sgibbs cddone, 249139213Sgibbs MSG_SIMPLE_Q_TAG, 249239213Sgibbs action, 249339213Sgibbs SSD_FULL_SIZE, 249439213Sgibbs /* timeout */60000); 249539213Sgibbs 249674840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 249774840Sken /*sense_flags*/SF_RETRY_UA|SF_NO_PRINT); 249839213Sgibbs 249939213Sgibbs xpt_release_ccb(ccb); 250039213Sgibbs 250139213Sgibbs if (error == 0) { 250239213Sgibbs if (action == PR_ALLOW) 250339213Sgibbs softc->flags &= ~CD_FLAG_DISC_LOCKED; 250439213Sgibbs else 250539213Sgibbs softc->flags |= CD_FLAG_DISC_LOCKED; 250639213Sgibbs } 250739213Sgibbs} 250839213Sgibbs 250939213Sgibbsstatic int 251039213Sgibbscdsize(dev_t dev, u_int32_t *size) 251139213Sgibbs{ 251239213Sgibbs struct cam_periph *periph; 251339213Sgibbs struct cd_softc *softc; 251439213Sgibbs union ccb *ccb; 251539213Sgibbs struct scsi_read_capacity_data *rcap_buf; 251639213Sgibbs int error; 251739213Sgibbs 251839213Sgibbs periph = cam_extend_get(cdperiphs, dkunit(dev)); 251939213Sgibbs 252039213Sgibbs if (periph == NULL) 252139213Sgibbs return (ENXIO); 252239213Sgibbs 252339213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdsize\n")); 252439213Sgibbs 252539213Sgibbs softc = (struct cd_softc *)periph->softc; 252639213Sgibbs 252739213Sgibbs ccb = cdgetccb(periph, /* priority */ 1); 252839213Sgibbs 252939213Sgibbs rcap_buf = malloc(sizeof(struct scsi_read_capacity_data), 253039213Sgibbs M_TEMP, M_WAITOK); 253139213Sgibbs 253239213Sgibbs scsi_read_capacity(&ccb->csio, 253339213Sgibbs /*retries*/ 1, 253439213Sgibbs cddone, 253539213Sgibbs MSG_SIMPLE_Q_TAG, 253639213Sgibbs rcap_buf, 253739213Sgibbs SSD_FULL_SIZE, 253839213Sgibbs /* timeout */20000); 253939213Sgibbs 254074840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 254174840Sken /*sense_flags*/SF_RETRY_UA|SF_NO_PRINT); 254239213Sgibbs 254339213Sgibbs xpt_release_ccb(ccb); 254439213Sgibbs 254539213Sgibbs softc->params.disksize = scsi_4btoul(rcap_buf->addr) + 1; 254639213Sgibbs softc->params.blksize = scsi_4btoul(rcap_buf->length); 254760806Sjoerg /* 254860806Sjoerg * SCSI-3 mandates that the reported blocksize shall be 2048. 254960806Sjoerg * Older drives sometimes report funny values, trim it down to 255060806Sjoerg * 2048, or other parts of the kernel will get confused. 255160806Sjoerg * 255260806Sjoerg * XXX we leave drives alone that might report 512 bytes, as 255360806Sjoerg * well as drives reporting more weird sizes like perhaps 4K. 255460806Sjoerg */ 255560806Sjoerg if (softc->params.blksize > 2048 && softc->params.blksize <= 2352) 255660806Sjoerg softc->params.blksize = 2048; 255739213Sgibbs 255839213Sgibbs free(rcap_buf, M_TEMP); 255939213Sgibbs *size = softc->params.disksize; 256039213Sgibbs 256139213Sgibbs return (error); 256239213Sgibbs 256339213Sgibbs} 256439213Sgibbs 256568294Sken/* 256668294Sken * The idea here is to try to figure out whether the first track is data or 256768294Sken * audio. If it is data, we can at least attempt to read a disklabel off 256868294Sken * the first sector of the disk. If it is audio, there won't be a 256968294Sken * disklabel. 257068294Sken * 257168294Sken * This routine returns 0 if the first track is data, and non-zero if there 257268294Sken * is an error or the first track is audio. (If either non-zero case, we 257368294Sken * should not attempt to read the disklabel.) 257468294Sken */ 257539213Sgibbsstatic int 257668294Skencdfirsttrackisdata(struct cam_periph *periph) 257768294Sken{ 257868294Sken struct cdtocdata { 257968294Sken struct ioc_toc_header header; 258068294Sken struct cd_toc_entry entries[100]; 258168294Sken }; 258268294Sken struct cd_softc *softc; 258368294Sken struct ioc_toc_header *th; 258468294Sken struct cdtocdata *data; 258568294Sken int num_entries, i; 258668294Sken int error, first_track_audio; 258768294Sken 258868294Sken error = 0; 258968294Sken first_track_audio = -1; 259068294Sken 259168294Sken softc = (struct cd_softc *)periph->softc; 259268294Sken 259368294Sken data = malloc(sizeof(struct cdtocdata), M_TEMP, M_WAITOK); 259468294Sken 259568294Sken th = &data->header; 259668294Sken error = cdreadtoc(periph, 0, 0, (struct cd_toc_entry *)data, 259768294Sken sizeof(*data)); 259868294Sken 259968294Sken if (error) 260068294Sken goto bailout; 260168294Sken 260268294Sken if (softc->quirks & CD_Q_BCD_TRACKS) { 260368294Sken /* we are going to have to convert the BCD 260468294Sken * encoding on the cd to what is expected 260568294Sken */ 260668294Sken th->starting_track = 260768294Sken bcd2bin(th->starting_track); 260868294Sken th->ending_track = bcd2bin(th->ending_track); 260968294Sken } 261068294Sken th->len = scsi_2btoul((u_int8_t *)&th->len); 261168294Sken 261268294Sken if ((th->len - 2) > 0) 261368294Sken num_entries = (th->len - 2) / sizeof(struct cd_toc_entry); 261468294Sken else 261568294Sken num_entries = 0; 261668294Sken 261768294Sken for (i = 0; i < num_entries; i++) { 261868294Sken if (data->entries[i].track == th->starting_track) { 261968294Sken if (data->entries[i].control & 0x4) 262068294Sken first_track_audio = 0; 262168294Sken else 262268294Sken first_track_audio = 1; 262368294Sken break; 262468294Sken } 262568294Sken } 262668294Sken 262768294Sken if (first_track_audio == -1) 262868294Sken error = ENOENT; 262968294Sken else if (first_track_audio == 1) 263068294Sken error = EINVAL; 263168294Sken else 263268294Sken error = 0; 263368294Skenbailout: 263468294Sken free(data, M_TEMP); 263568294Sken 263668294Sken return(error); 263768294Sken} 263868294Sken 263968294Skenstatic int 264039213Sgibbscderror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) 264139213Sgibbs{ 264239213Sgibbs struct cd_softc *softc; 264339213Sgibbs struct cam_periph *periph; 264439213Sgibbs 264539213Sgibbs periph = xpt_path_periph(ccb->ccb_h.path); 264639213Sgibbs softc = (struct cd_softc *)periph->softc; 264739213Sgibbs 264839514Sgibbs /* 264939514Sgibbs * XXX 265039514Sgibbs * Until we have a better way of doing pack validation, 265139514Sgibbs * don't treat UAs as errors. 265239514Sgibbs */ 265339514Sgibbs sense_flags |= SF_RETRY_UA; 265439213Sgibbs return (cam_periph_error(ccb, cam_flags, sense_flags, 265539213Sgibbs &softc->saved_ccb)); 265639213Sgibbs} 265739213Sgibbs 265839213Sgibbs/* 265939213Sgibbs * Read table of contents 266039213Sgibbs */ 266139213Sgibbsstatic int 266239213Sgibbscdreadtoc(struct cam_periph *periph, u_int32_t mode, u_int32_t start, 266339213Sgibbs struct cd_toc_entry *data, u_int32_t len) 266439213Sgibbs{ 266539213Sgibbs struct scsi_read_toc *scsi_cmd; 266639213Sgibbs u_int32_t ntoc; 266739213Sgibbs struct ccb_scsiio *csio; 266839213Sgibbs union ccb *ccb; 266939213Sgibbs int error; 267039213Sgibbs 267139213Sgibbs ntoc = len; 267239213Sgibbs error = 0; 267339213Sgibbs 267439213Sgibbs ccb = cdgetccb(periph, /* priority */ 1); 267539213Sgibbs 267639213Sgibbs csio = &ccb->csio; 267739213Sgibbs 267839213Sgibbs cam_fill_csio(csio, 267939213Sgibbs /* retries */ 1, 268039213Sgibbs /* cbfcnp */ cddone, 268139213Sgibbs /* flags */ CAM_DIR_IN, 268239213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 268339213Sgibbs /* data_ptr */ (u_int8_t *)data, 268439213Sgibbs /* dxfer_len */ len, 268539213Sgibbs /* sense_len */ SSD_FULL_SIZE, 268639213Sgibbs sizeof(struct scsi_read_toc), 268739213Sgibbs /* timeout */ 50000); 268839213Sgibbs 268939213Sgibbs scsi_cmd = (struct scsi_read_toc *)&csio->cdb_io.cdb_bytes; 269039213Sgibbs bzero (scsi_cmd, sizeof(*scsi_cmd)); 269139213Sgibbs 269239213Sgibbs if (mode == CD_MSF_FORMAT) 269339213Sgibbs scsi_cmd->byte2 |= CD_MSF; 269439213Sgibbs scsi_cmd->from_track = start; 269539213Sgibbs /* scsi_ulto2b(ntoc, (u_int8_t *)scsi_cmd->data_len); */ 269639213Sgibbs scsi_cmd->data_len[0] = (ntoc) >> 8; 269739213Sgibbs scsi_cmd->data_len[1] = (ntoc) & 0xff; 269839213Sgibbs 269939213Sgibbs scsi_cmd->op_code = READ_TOC; 270039213Sgibbs 270174840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 270274840Sken /*sense_flags*/SF_RETRY_UA); 270339213Sgibbs 270439213Sgibbs xpt_release_ccb(ccb); 270539213Sgibbs 270639213Sgibbs return(error); 270739213Sgibbs} 270839213Sgibbs 270939213Sgibbsstatic int 271039213Sgibbscdreadsubchannel(struct cam_periph *periph, u_int32_t mode, 271139213Sgibbs u_int32_t format, int track, 271239213Sgibbs struct cd_sub_channel_info *data, u_int32_t len) 271339213Sgibbs{ 271439213Sgibbs struct scsi_read_subchannel *scsi_cmd; 271539213Sgibbs struct ccb_scsiio *csio; 271639213Sgibbs union ccb *ccb; 271739213Sgibbs int error; 271839213Sgibbs 271939213Sgibbs error = 0; 272039213Sgibbs 272139213Sgibbs ccb = cdgetccb(periph, /* priority */ 1); 272239213Sgibbs 272339213Sgibbs csio = &ccb->csio; 272439213Sgibbs 272539213Sgibbs cam_fill_csio(csio, 272639213Sgibbs /* retries */ 1, 272739213Sgibbs /* cbfcnp */ cddone, 272839213Sgibbs /* flags */ CAM_DIR_IN, 272939213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 273039213Sgibbs /* data_ptr */ (u_int8_t *)data, 273139213Sgibbs /* dxfer_len */ len, 273239213Sgibbs /* sense_len */ SSD_FULL_SIZE, 273339213Sgibbs sizeof(struct scsi_read_subchannel), 273439213Sgibbs /* timeout */ 50000); 273539213Sgibbs 273639213Sgibbs scsi_cmd = (struct scsi_read_subchannel *)&csio->cdb_io.cdb_bytes; 273739213Sgibbs bzero (scsi_cmd, sizeof(*scsi_cmd)); 273839213Sgibbs 273939213Sgibbs scsi_cmd->op_code = READ_SUBCHANNEL; 274039213Sgibbs if (mode == CD_MSF_FORMAT) 274139213Sgibbs scsi_cmd->byte1 |= CD_MSF; 274239213Sgibbs scsi_cmd->byte2 = SRS_SUBQ; 274339213Sgibbs scsi_cmd->subchan_format = format; 274439213Sgibbs scsi_cmd->track = track; 274539213Sgibbs scsi_ulto2b(len, (u_int8_t *)scsi_cmd->data_len); 274639213Sgibbs scsi_cmd->control = 0; 274739213Sgibbs 274874840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 274974840Sken /*sense_flags*/SF_RETRY_UA); 275039213Sgibbs 275139213Sgibbs xpt_release_ccb(ccb); 275239213Sgibbs 275339213Sgibbs return(error); 275439213Sgibbs} 275539213Sgibbs 275639213Sgibbs 275739213Sgibbsstatic int 275839213Sgibbscdgetmode(struct cam_periph *periph, struct cd_mode_data *data, u_int32_t page) 275939213Sgibbs{ 276039213Sgibbs struct scsi_mode_sense_6 *scsi_cmd; 276139213Sgibbs struct ccb_scsiio *csio; 276239213Sgibbs union ccb *ccb; 276339213Sgibbs int error; 276439213Sgibbs 276539213Sgibbs ccb = cdgetccb(periph, /* priority */ 1); 276639213Sgibbs 276739213Sgibbs csio = &ccb->csio; 276839213Sgibbs 276939213Sgibbs bzero(data, sizeof(*data)); 277039213Sgibbs cam_fill_csio(csio, 277139213Sgibbs /* retries */ 1, 277239213Sgibbs /* cbfcnp */ cddone, 277339213Sgibbs /* flags */ CAM_DIR_IN, 277439213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 277539213Sgibbs /* data_ptr */ (u_int8_t *)data, 277639213Sgibbs /* dxfer_len */ sizeof(*data), 277739213Sgibbs /* sense_len */ SSD_FULL_SIZE, 277839213Sgibbs sizeof(struct scsi_mode_sense_6), 277939213Sgibbs /* timeout */ 50000); 278039213Sgibbs 278139213Sgibbs scsi_cmd = (struct scsi_mode_sense_6 *)&csio->cdb_io.cdb_bytes; 278239213Sgibbs bzero (scsi_cmd, sizeof(*scsi_cmd)); 278339213Sgibbs 278439213Sgibbs scsi_cmd->page = page; 278539213Sgibbs scsi_cmd->length = sizeof(*data) & 0xff; 278639213Sgibbs scsi_cmd->opcode = MODE_SENSE; 278739213Sgibbs 278874840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 278974840Sken /*sense_flags*/SF_RETRY_UA); 279039213Sgibbs 279139213Sgibbs xpt_release_ccb(ccb); 279239213Sgibbs 279339213Sgibbs return(error); 279439213Sgibbs} 279539213Sgibbs 279639213Sgibbsstatic int 279739213Sgibbscdsetmode(struct cam_periph *periph, struct cd_mode_data *data) 279839213Sgibbs{ 279939213Sgibbs struct scsi_mode_select_6 *scsi_cmd; 280039213Sgibbs struct ccb_scsiio *csio; 280139213Sgibbs union ccb *ccb; 280239213Sgibbs int error; 280339213Sgibbs 280439213Sgibbs ccb = cdgetccb(periph, /* priority */ 1); 280539213Sgibbs 280639213Sgibbs csio = &ccb->csio; 280739213Sgibbs 280839213Sgibbs error = 0; 280939213Sgibbs 281039213Sgibbs cam_fill_csio(csio, 281139213Sgibbs /* retries */ 1, 281239213Sgibbs /* cbfcnp */ cddone, 281339531Sken /* flags */ CAM_DIR_OUT, 281439213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 281539213Sgibbs /* data_ptr */ (u_int8_t *)data, 281639213Sgibbs /* dxfer_len */ sizeof(*data), 281739213Sgibbs /* sense_len */ SSD_FULL_SIZE, 281839213Sgibbs sizeof(struct scsi_mode_select_6), 281939213Sgibbs /* timeout */ 50000); 282039213Sgibbs 282139213Sgibbs scsi_cmd = (struct scsi_mode_select_6 *)&csio->cdb_io.cdb_bytes; 282239213Sgibbs 282339213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 282439213Sgibbs scsi_cmd->opcode = MODE_SELECT; 282539213Sgibbs scsi_cmd->byte2 |= SMS_PF; 282639213Sgibbs scsi_cmd->length = sizeof(*data) & 0xff; 282739213Sgibbs data->header.data_length = 0; 282839213Sgibbs /* 282939213Sgibbs * SONY drives do not allow a mode select with a medium_type 283039213Sgibbs * value that has just been returned by a mode sense; use a 283139213Sgibbs * medium_type of 0 (Default) instead. 283239213Sgibbs */ 283339213Sgibbs data->header.medium_type = 0; 283439213Sgibbs 283574840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 283674840Sken /*sense_flags*/SF_RETRY_UA); 283739213Sgibbs 283839213Sgibbs xpt_release_ccb(ccb); 283939213Sgibbs 284039213Sgibbs return(error); 284139213Sgibbs} 284239213Sgibbs 284339213Sgibbs 284439213Sgibbsstatic int 284539213Sgibbscdplay(struct cam_periph *periph, u_int32_t blk, u_int32_t len) 284639213Sgibbs{ 284739531Sken struct ccb_scsiio *csio; 284839213Sgibbs union ccb *ccb; 284939213Sgibbs int error; 285039531Sken u_int8_t cdb_len; 285139213Sgibbs 285239213Sgibbs error = 0; 285339213Sgibbs ccb = cdgetccb(periph, /* priority */ 1); 285439213Sgibbs csio = &ccb->csio; 285539531Sken /* 285639531Sken * Use the smallest possible command to perform the operation. 285739531Sken */ 285839531Sken if ((len & 0xffff0000) == 0) { 285939531Sken /* 286039531Sken * We can fit in a 10 byte cdb. 286139531Sken */ 286239531Sken struct scsi_play_10 *scsi_cmd; 286339213Sgibbs 286439531Sken scsi_cmd = (struct scsi_play_10 *)&csio->cdb_io.cdb_bytes; 286539531Sken bzero (scsi_cmd, sizeof(*scsi_cmd)); 286639531Sken scsi_cmd->op_code = PLAY_10; 286739531Sken scsi_ulto4b(blk, (u_int8_t *)scsi_cmd->blk_addr); 286839531Sken scsi_ulto2b(len, (u_int8_t *)scsi_cmd->xfer_len); 286939531Sken cdb_len = sizeof(*scsi_cmd); 287039531Sken } else { 287139531Sken struct scsi_play_12 *scsi_cmd; 287239213Sgibbs 287339531Sken scsi_cmd = (struct scsi_play_12 *)&csio->cdb_io.cdb_bytes; 287439531Sken bzero (scsi_cmd, sizeof(*scsi_cmd)); 287539531Sken scsi_cmd->op_code = PLAY_12; 287639531Sken scsi_ulto4b(blk, (u_int8_t *)scsi_cmd->blk_addr); 287739531Sken scsi_ulto4b(len, (u_int8_t *)scsi_cmd->xfer_len); 287839531Sken cdb_len = sizeof(*scsi_cmd); 287939531Sken } 288039531Sken cam_fill_csio(csio, 288139531Sken /*retries*/2, 288239531Sken cddone, 288339531Sken /*flags*/CAM_DIR_NONE, 288439531Sken MSG_SIMPLE_Q_TAG, 288539531Sken /*dataptr*/NULL, 288639531Sken /*datalen*/0, 288739531Sken /*sense_len*/SSD_FULL_SIZE, 288839531Sken cdb_len, 288939531Sken /*timeout*/50 * 1000); 289039213Sgibbs 289174840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 289274840Sken /*sense_flags*/SF_RETRY_UA); 289339213Sgibbs 289439213Sgibbs xpt_release_ccb(ccb); 289539213Sgibbs 289639213Sgibbs return(error); 289739213Sgibbs} 289839213Sgibbs 289939213Sgibbsstatic int 290039213Sgibbscdplaymsf(struct cam_periph *periph, u_int32_t startm, u_int32_t starts, 290139213Sgibbs u_int32_t startf, u_int32_t endm, u_int32_t ends, u_int32_t endf) 290239213Sgibbs{ 290339213Sgibbs struct scsi_play_msf *scsi_cmd; 290439213Sgibbs struct ccb_scsiio *csio; 290539213Sgibbs union ccb *ccb; 290639213Sgibbs int error; 290739213Sgibbs 290839213Sgibbs error = 0; 290939213Sgibbs 291039213Sgibbs ccb = cdgetccb(periph, /* priority */ 1); 291139213Sgibbs 291239213Sgibbs csio = &ccb->csio; 291339213Sgibbs 291439213Sgibbs cam_fill_csio(csio, 291539213Sgibbs /* retries */ 1, 291639213Sgibbs /* cbfcnp */ cddone, 291739531Sken /* flags */ CAM_DIR_NONE, 291839213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 291939213Sgibbs /* data_ptr */ NULL, 292039213Sgibbs /* dxfer_len */ 0, 292139213Sgibbs /* sense_len */ SSD_FULL_SIZE, 292239213Sgibbs sizeof(struct scsi_play_msf), 292339213Sgibbs /* timeout */ 50000); 292439213Sgibbs 292539213Sgibbs scsi_cmd = (struct scsi_play_msf *)&csio->cdb_io.cdb_bytes; 292639213Sgibbs bzero (scsi_cmd, sizeof(*scsi_cmd)); 292739213Sgibbs 292839213Sgibbs scsi_cmd->op_code = PLAY_MSF; 292939213Sgibbs scsi_cmd->start_m = startm; 293039213Sgibbs scsi_cmd->start_s = starts; 293139213Sgibbs scsi_cmd->start_f = startf; 293239213Sgibbs scsi_cmd->end_m = endm; 293339213Sgibbs scsi_cmd->end_s = ends; 293439213Sgibbs scsi_cmd->end_f = endf; 293539213Sgibbs 293674840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 293774840Sken /*sense_flags*/SF_RETRY_UA); 293839213Sgibbs 293939213Sgibbs xpt_release_ccb(ccb); 294039213Sgibbs 294139213Sgibbs return(error); 294239213Sgibbs} 294339213Sgibbs 294439213Sgibbs 294539213Sgibbsstatic int 294639213Sgibbscdplaytracks(struct cam_periph *periph, u_int32_t strack, u_int32_t sindex, 294739213Sgibbs u_int32_t etrack, u_int32_t eindex) 294839213Sgibbs{ 294939213Sgibbs struct scsi_play_track *scsi_cmd; 295039213Sgibbs struct ccb_scsiio *csio; 295139213Sgibbs union ccb *ccb; 295239213Sgibbs int error; 295339213Sgibbs 295439213Sgibbs error = 0; 295539213Sgibbs 295639213Sgibbs ccb = cdgetccb(periph, /* priority */ 1); 295739213Sgibbs 295839213Sgibbs csio = &ccb->csio; 295939213Sgibbs 296039213Sgibbs cam_fill_csio(csio, 296139213Sgibbs /* retries */ 1, 296239213Sgibbs /* cbfcnp */ cddone, 296339531Sken /* flags */ CAM_DIR_NONE, 296439213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 296539213Sgibbs /* data_ptr */ NULL, 296639213Sgibbs /* dxfer_len */ 0, 296739213Sgibbs /* sense_len */ SSD_FULL_SIZE, 296839213Sgibbs sizeof(struct scsi_play_track), 296939213Sgibbs /* timeout */ 50000); 297039213Sgibbs 297139213Sgibbs scsi_cmd = (struct scsi_play_track *)&csio->cdb_io.cdb_bytes; 297239213Sgibbs bzero (scsi_cmd, sizeof(*scsi_cmd)); 297339213Sgibbs 297439213Sgibbs scsi_cmd->op_code = PLAY_TRACK; 297539213Sgibbs scsi_cmd->start_track = strack; 297639213Sgibbs scsi_cmd->start_index = sindex; 297739213Sgibbs scsi_cmd->end_track = etrack; 297839213Sgibbs scsi_cmd->end_index = eindex; 297939213Sgibbs 298074840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 298174840Sken /*sense_flags*/SF_RETRY_UA); 298239213Sgibbs 298339213Sgibbs xpt_release_ccb(ccb); 298439213Sgibbs 298539213Sgibbs return(error); 298639213Sgibbs} 298739213Sgibbs 298839213Sgibbsstatic int 298939213Sgibbscdpause(struct cam_periph *periph, u_int32_t go) 299039213Sgibbs{ 299139213Sgibbs struct scsi_pause *scsi_cmd; 299239213Sgibbs struct ccb_scsiio *csio; 299339213Sgibbs union ccb *ccb; 299439213Sgibbs int error; 299539213Sgibbs 299639213Sgibbs error = 0; 299739213Sgibbs 299839213Sgibbs ccb = cdgetccb(periph, /* priority */ 1); 299939213Sgibbs 300039213Sgibbs csio = &ccb->csio; 300139213Sgibbs 300239213Sgibbs cam_fill_csio(csio, 300339213Sgibbs /* retries */ 1, 300439213Sgibbs /* cbfcnp */ cddone, 300539531Sken /* flags */ CAM_DIR_NONE, 300639213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 300739213Sgibbs /* data_ptr */ NULL, 300839213Sgibbs /* dxfer_len */ 0, 300939213Sgibbs /* sense_len */ SSD_FULL_SIZE, 301039213Sgibbs sizeof(struct scsi_pause), 301139213Sgibbs /* timeout */ 50000); 301239213Sgibbs 301339213Sgibbs scsi_cmd = (struct scsi_pause *)&csio->cdb_io.cdb_bytes; 301439213Sgibbs bzero (scsi_cmd, sizeof(*scsi_cmd)); 301539213Sgibbs 301639213Sgibbs scsi_cmd->op_code = PAUSE; 301739213Sgibbs scsi_cmd->resume = go; 301839213Sgibbs 301974840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 302074840Sken /*sense_flags*/SF_RETRY_UA); 302139213Sgibbs 302239213Sgibbs xpt_release_ccb(ccb); 302339213Sgibbs 302439213Sgibbs return(error); 302539213Sgibbs} 302639213Sgibbs 302739213Sgibbsstatic int 302839213Sgibbscdstartunit(struct cam_periph *periph) 302939213Sgibbs{ 303039213Sgibbs union ccb *ccb; 303139213Sgibbs int error; 303239213Sgibbs 303339213Sgibbs error = 0; 303439213Sgibbs 303539213Sgibbs ccb = cdgetccb(periph, /* priority */ 1); 303639213Sgibbs 303739213Sgibbs scsi_start_stop(&ccb->csio, 303839213Sgibbs /* retries */ 1, 303939213Sgibbs /* cbfcnp */ cddone, 304039213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 304139213Sgibbs /* start */ TRUE, 304269577Sjoerg /* load_eject */ FALSE, 304339213Sgibbs /* immediate */ FALSE, 304439213Sgibbs /* sense_len */ SSD_FULL_SIZE, 304539213Sgibbs /* timeout */ 50000); 304639213Sgibbs 304774840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 304874840Sken /*sense_flags*/SF_RETRY_UA); 304939213Sgibbs 305039213Sgibbs xpt_release_ccb(ccb); 305139213Sgibbs 305239213Sgibbs return(error); 305339213Sgibbs} 305439213Sgibbs 305539213Sgibbsstatic int 305639213Sgibbscdstopunit(struct cam_periph *periph, u_int32_t eject) 305739213Sgibbs{ 305839213Sgibbs union ccb *ccb; 305939213Sgibbs int error; 306039213Sgibbs 306139213Sgibbs error = 0; 306239213Sgibbs 306339213Sgibbs ccb = cdgetccb(periph, /* priority */ 1); 306439213Sgibbs 306539213Sgibbs scsi_start_stop(&ccb->csio, 306639213Sgibbs /* retries */ 1, 306739213Sgibbs /* cbfcnp */ cddone, 306839213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 306939213Sgibbs /* start */ FALSE, 307039213Sgibbs /* load_eject */ eject, 307139213Sgibbs /* immediate */ FALSE, 307239213Sgibbs /* sense_len */ SSD_FULL_SIZE, 307339213Sgibbs /* timeout */ 50000); 307439213Sgibbs 307574840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 307674840Sken /*sense_flags*/SF_RETRY_UA); 307739213Sgibbs 307839213Sgibbs xpt_release_ccb(ccb); 307939213Sgibbs 308039213Sgibbs return(error); 308139213Sgibbs} 308260422Sken 308360422Skenstatic int 308460422Skencdreportkey(struct cam_periph *periph, struct dvd_authinfo *authinfo) 308560422Sken{ 308660422Sken union ccb *ccb; 308760422Sken u_int8_t *databuf; 308860422Sken u_int32_t lba; 308960422Sken int error; 309060422Sken int length; 309160422Sken 309260422Sken error = 0; 309360422Sken databuf = NULL; 309460422Sken lba = 0; 309560422Sken 309660422Sken ccb = cdgetccb(periph, /* priority */ 1); 309760422Sken 309860422Sken switch (authinfo->format) { 309960422Sken case DVD_REPORT_AGID: 310060422Sken length = sizeof(struct scsi_report_key_data_agid); 310160422Sken break; 310260422Sken case DVD_REPORT_CHALLENGE: 310360422Sken length = sizeof(struct scsi_report_key_data_challenge); 310460422Sken break; 310560422Sken case DVD_REPORT_KEY1: 310660422Sken length = sizeof(struct scsi_report_key_data_key1_key2); 310760422Sken break; 310860422Sken case DVD_REPORT_TITLE_KEY: 310960422Sken length = sizeof(struct scsi_report_key_data_title); 311060422Sken /* The lba field is only set for the title key */ 311160422Sken lba = authinfo->lba; 311260422Sken break; 311360422Sken case DVD_REPORT_ASF: 311460422Sken length = sizeof(struct scsi_report_key_data_asf); 311560422Sken break; 311660422Sken case DVD_REPORT_RPC: 311760422Sken length = sizeof(struct scsi_report_key_data_rpc); 311860422Sken break; 311960422Sken case DVD_INVALIDATE_AGID: 312060422Sken length = 0; 312160422Sken break; 312260422Sken default: 312360422Sken error = EINVAL; 312460422Sken goto bailout; 312560422Sken break; /* NOTREACHED */ 312660422Sken } 312760422Sken 312860422Sken if (length != 0) { 312967888Sdwmalone databuf = malloc(length, M_DEVBUF, M_WAITOK | M_ZERO); 313060422Sken } else 313160422Sken databuf = NULL; 313260422Sken 313360422Sken 313460422Sken scsi_report_key(&ccb->csio, 313560422Sken /* retries */ 1, 313660422Sken /* cbfcnp */ cddone, 313760422Sken /* tag_action */ MSG_SIMPLE_Q_TAG, 313860422Sken /* lba */ lba, 313960422Sken /* agid */ authinfo->agid, 314060422Sken /* key_format */ authinfo->format, 314160422Sken /* data_ptr */ databuf, 314260422Sken /* dxfer_len */ length, 314360422Sken /* sense_len */ SSD_FULL_SIZE, 314460422Sken /* timeout */ 50000); 314560422Sken 314674840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 314774840Sken /*sense_flags*/SF_RETRY_UA); 314860422Sken 314960422Sken if (error != 0) 315060422Sken goto bailout; 315160422Sken 315260422Sken if (ccb->csio.resid != 0) { 315360422Sken xpt_print_path(periph->path); 315460422Sken printf("warning, residual for report key command is %d\n", 315560422Sken ccb->csio.resid); 315660422Sken } 315760422Sken 315860422Sken switch(authinfo->format) { 315960422Sken case DVD_REPORT_AGID: { 316060422Sken struct scsi_report_key_data_agid *agid_data; 316160422Sken 316260422Sken agid_data = (struct scsi_report_key_data_agid *)databuf; 316360422Sken 316460422Sken authinfo->agid = (agid_data->agid & RKD_AGID_MASK) >> 316560422Sken RKD_AGID_SHIFT; 316660422Sken break; 316760422Sken } 316860422Sken case DVD_REPORT_CHALLENGE: { 316960422Sken struct scsi_report_key_data_challenge *chal_data; 317060422Sken 317160422Sken chal_data = (struct scsi_report_key_data_challenge *)databuf; 317260422Sken 317360422Sken bcopy(chal_data->challenge_key, authinfo->keychal, 317460422Sken min(sizeof(chal_data->challenge_key), 317560422Sken sizeof(authinfo->keychal))); 317660422Sken break; 317760422Sken } 317860422Sken case DVD_REPORT_KEY1: { 317960422Sken struct scsi_report_key_data_key1_key2 *key1_data; 318060422Sken 318160422Sken key1_data = (struct scsi_report_key_data_key1_key2 *)databuf; 318260422Sken 318360422Sken bcopy(key1_data->key1, authinfo->keychal, 318460422Sken min(sizeof(key1_data->key1), sizeof(authinfo->keychal))); 318560422Sken break; 318660422Sken } 318760422Sken case DVD_REPORT_TITLE_KEY: { 318860422Sken struct scsi_report_key_data_title *title_data; 318960422Sken 319060422Sken title_data = (struct scsi_report_key_data_title *)databuf; 319160422Sken 319260422Sken authinfo->cpm = (title_data->byte0 & RKD_TITLE_CPM) >> 319360422Sken RKD_TITLE_CPM_SHIFT; 319460422Sken authinfo->cp_sec = (title_data->byte0 & RKD_TITLE_CP_SEC) >> 319560422Sken RKD_TITLE_CP_SEC_SHIFT; 319660422Sken authinfo->cgms = (title_data->byte0 & RKD_TITLE_CMGS_MASK) >> 319760422Sken RKD_TITLE_CMGS_SHIFT; 319860422Sken bcopy(title_data->title_key, authinfo->keychal, 319960422Sken min(sizeof(title_data->title_key), 320060422Sken sizeof(authinfo->keychal))); 320160422Sken break; 320260422Sken } 320360422Sken case DVD_REPORT_ASF: { 320460422Sken struct scsi_report_key_data_asf *asf_data; 320560422Sken 320660422Sken asf_data = (struct scsi_report_key_data_asf *)databuf; 320760422Sken 320860422Sken authinfo->asf = asf_data->success & RKD_ASF_SUCCESS; 320960422Sken break; 321060422Sken } 321160422Sken case DVD_REPORT_RPC: { 321260422Sken struct scsi_report_key_data_rpc *rpc_data; 321360422Sken 321460422Sken rpc_data = (struct scsi_report_key_data_rpc *)databuf; 321560422Sken 321660422Sken authinfo->reg_type = (rpc_data->byte4 & RKD_RPC_TYPE_MASK) >> 321760422Sken RKD_RPC_TYPE_SHIFT; 321860422Sken authinfo->vend_rsts = 321960422Sken (rpc_data->byte4 & RKD_RPC_VENDOR_RESET_MASK) >> 322060422Sken RKD_RPC_VENDOR_RESET_SHIFT; 322160422Sken authinfo->user_rsts = rpc_data->byte4 & RKD_RPC_USER_RESET_MASK; 322271752Sken authinfo->region = rpc_data->region_mask; 322371752Sken authinfo->rpc_scheme = rpc_data->rpc_scheme1; 322460422Sken break; 322560422Sken } 322660422Sken case DVD_INVALIDATE_AGID: 322760422Sken break; 322860422Sken default: 322960422Sken /* This should be impossible, since we checked above */ 323060422Sken error = EINVAL; 323160422Sken goto bailout; 323260422Sken break; /* NOTREACHED */ 323360422Sken } 323460422Skenbailout: 323560422Sken if (databuf != NULL) 323660422Sken free(databuf, M_DEVBUF); 323760422Sken 323860422Sken xpt_release_ccb(ccb); 323960422Sken 324060422Sken return(error); 324160422Sken} 324260422Sken 324360422Skenstatic int 324460422Skencdsendkey(struct cam_periph *periph, struct dvd_authinfo *authinfo) 324560422Sken{ 324660422Sken union ccb *ccb; 324760422Sken u_int8_t *databuf; 324860422Sken int length; 324960422Sken int error; 325060422Sken 325160422Sken error = 0; 325260422Sken databuf = NULL; 325360422Sken 325460422Sken ccb = cdgetccb(periph, /* priority */ 1); 325560422Sken 325660422Sken switch(authinfo->format) { 325760422Sken case DVD_SEND_CHALLENGE: { 325860422Sken struct scsi_report_key_data_challenge *challenge_data; 325960422Sken 326060422Sken length = sizeof(*challenge_data); 326160422Sken 326267888Sdwmalone challenge_data = malloc(length, M_DEVBUF, M_WAITOK | M_ZERO); 326360422Sken 326460422Sken databuf = (u_int8_t *)challenge_data; 326560422Sken 326660422Sken scsi_ulto2b(length - sizeof(challenge_data->data_len), 326760422Sken challenge_data->data_len); 326860422Sken 326960422Sken bcopy(authinfo->keychal, challenge_data->challenge_key, 327060422Sken min(sizeof(authinfo->keychal), 327160422Sken sizeof(challenge_data->challenge_key))); 327260422Sken break; 327360422Sken } 327460422Sken case DVD_SEND_KEY2: { 327560422Sken struct scsi_report_key_data_key1_key2 *key2_data; 327660422Sken 327760422Sken length = sizeof(*key2_data); 327860422Sken 327967888Sdwmalone key2_data = malloc(length, M_DEVBUF, M_WAITOK | M_ZERO); 328060422Sken 328160422Sken databuf = (u_int8_t *)key2_data; 328260422Sken 328360422Sken scsi_ulto2b(length - sizeof(key2_data->data_len), 328460422Sken key2_data->data_len); 328560422Sken 328660422Sken bcopy(authinfo->keychal, key2_data->key1, 328760422Sken min(sizeof(authinfo->keychal), sizeof(key2_data->key1))); 328860422Sken 328960422Sken break; 329060422Sken } 329160422Sken case DVD_SEND_RPC: { 329260422Sken struct scsi_send_key_data_rpc *rpc_data; 329360422Sken 329460422Sken length = sizeof(*rpc_data); 329560422Sken 329667888Sdwmalone rpc_data = malloc(length, M_DEVBUF, M_WAITOK | M_ZERO); 329760422Sken 329860422Sken databuf = (u_int8_t *)rpc_data; 329960422Sken 330060422Sken scsi_ulto2b(length - sizeof(rpc_data->data_len), 330160422Sken rpc_data->data_len); 330260422Sken 330360422Sken rpc_data->region_code = authinfo->region; 330460422Sken break; 330560422Sken } 330660422Sken default: 330760422Sken error = EINVAL; 330860422Sken goto bailout; 330960422Sken break; /* NOTREACHED */ 331060422Sken } 331160422Sken 331260422Sken scsi_send_key(&ccb->csio, 331360422Sken /* retries */ 1, 331460422Sken /* cbfcnp */ cddone, 331560422Sken /* tag_action */ MSG_SIMPLE_Q_TAG, 331660422Sken /* agid */ authinfo->agid, 331760422Sken /* key_format */ authinfo->format, 331860422Sken /* data_ptr */ databuf, 331960422Sken /* dxfer_len */ length, 332060422Sken /* sense_len */ SSD_FULL_SIZE, 332160422Sken /* timeout */ 50000); 332260422Sken 332374840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 332474840Sken /*sense_flags*/SF_RETRY_UA); 332560422Sken 332660422Skenbailout: 332760422Sken 332860422Sken if (databuf != NULL) 332960422Sken free(databuf, M_DEVBUF); 333060422Sken 333160422Sken xpt_release_ccb(ccb); 333260422Sken 333360422Sken return(error); 333460422Sken} 333560422Sken 333660422Skenstatic int 333760422Skencdreaddvdstructure(struct cam_periph *periph, struct dvd_struct *dvdstruct) 333860422Sken{ 333960422Sken union ccb *ccb; 334060422Sken u_int8_t *databuf; 334160422Sken u_int32_t address; 334260422Sken int error; 334360422Sken int length; 334460422Sken 334560422Sken error = 0; 334660422Sken databuf = NULL; 334760422Sken /* The address is reserved for many of the formats */ 334860422Sken address = 0; 334960422Sken 335060422Sken ccb = cdgetccb(periph, /* priority */ 1); 335160422Sken 335260422Sken switch(dvdstruct->format) { 335360422Sken case DVD_STRUCT_PHYSICAL: 335460422Sken length = sizeof(struct scsi_read_dvd_struct_data_physical); 335560422Sken break; 335660422Sken case DVD_STRUCT_COPYRIGHT: 335760422Sken length = sizeof(struct scsi_read_dvd_struct_data_copyright); 335860422Sken break; 335960422Sken case DVD_STRUCT_DISCKEY: 336060422Sken length = sizeof(struct scsi_read_dvd_struct_data_disc_key); 336160422Sken break; 336260422Sken case DVD_STRUCT_BCA: 336360422Sken length = sizeof(struct scsi_read_dvd_struct_data_bca); 336460422Sken break; 336560422Sken case DVD_STRUCT_MANUFACT: 336660422Sken length = sizeof(struct scsi_read_dvd_struct_data_manufacturer); 336760422Sken break; 336860422Sken case DVD_STRUCT_CMI: 336960422Sken error = ENODEV; 337060422Sken goto bailout; 337160422Sken#ifdef notyet 337260422Sken length = sizeof(struct scsi_read_dvd_struct_data_copy_manage); 337360422Sken address = dvdstruct->address; 337460422Sken#endif 337560422Sken break; /* NOTREACHED */ 337660422Sken case DVD_STRUCT_PROTDISCID: 337760422Sken length = sizeof(struct scsi_read_dvd_struct_data_prot_discid); 337860422Sken break; 337960422Sken case DVD_STRUCT_DISCKEYBLOCK: 338060422Sken length = sizeof(struct scsi_read_dvd_struct_data_disc_key_blk); 338160422Sken break; 338260422Sken case DVD_STRUCT_DDS: 338360422Sken length = sizeof(struct scsi_read_dvd_struct_data_dds); 338460422Sken break; 338560422Sken case DVD_STRUCT_MEDIUM_STAT: 338660422Sken length = sizeof(struct scsi_read_dvd_struct_data_medium_status); 338760422Sken break; 338860422Sken case DVD_STRUCT_SPARE_AREA: 338960422Sken length = sizeof(struct scsi_read_dvd_struct_data_spare_area); 339060422Sken break; 339160422Sken case DVD_STRUCT_RMD_LAST: 339260422Sken error = ENODEV; 339360422Sken goto bailout; 339460422Sken#ifdef notyet 339560422Sken length = sizeof(struct scsi_read_dvd_struct_data_rmd_borderout); 339660422Sken address = dvdstruct->address; 339760422Sken#endif 339860422Sken break; /* NOTREACHED */ 339960422Sken case DVD_STRUCT_RMD_RMA: 340060422Sken error = ENODEV; 340160422Sken goto bailout; 340260422Sken#ifdef notyet 340360422Sken length = sizeof(struct scsi_read_dvd_struct_data_rmd); 340460422Sken address = dvdstruct->address; 340560422Sken#endif 340660422Sken break; /* NOTREACHED */ 340760422Sken case DVD_STRUCT_PRERECORDED: 340860422Sken length = sizeof(struct scsi_read_dvd_struct_data_leadin); 340960422Sken break; 341060422Sken case DVD_STRUCT_UNIQUEID: 341160422Sken length = sizeof(struct scsi_read_dvd_struct_data_disc_id); 341260422Sken break; 341360422Sken case DVD_STRUCT_DCB: 341460422Sken error = ENODEV; 341560422Sken goto bailout; 341660422Sken#ifdef notyet 341760422Sken length = sizeof(struct scsi_read_dvd_struct_data_dcb); 341860422Sken address = dvdstruct->address; 341960422Sken#endif 342060422Sken break; /* NOTREACHED */ 342160422Sken case DVD_STRUCT_LIST: 342260422Sken /* 342360422Sken * This is the maximum allocation length for the READ DVD 342460422Sken * STRUCTURE command. There's nothing in the MMC3 spec 342560422Sken * that indicates a limit in the amount of data that can 342660422Sken * be returned from this call, other than the limits 342760422Sken * imposed by the 2-byte length variables. 342860422Sken */ 342960422Sken length = 65535; 343060422Sken break; 343160422Sken default: 343260422Sken error = EINVAL; 343360422Sken goto bailout; 343460422Sken break; /* NOTREACHED */ 343560422Sken } 343660422Sken 343760422Sken if (length != 0) { 343867888Sdwmalone databuf = malloc(length, M_DEVBUF, M_WAITOK | M_ZERO); 343960422Sken } else 344060422Sken databuf = NULL; 344160422Sken 344260422Sken scsi_read_dvd_structure(&ccb->csio, 344360422Sken /* retries */ 1, 344460422Sken /* cbfcnp */ cddone, 344560422Sken /* tag_action */ MSG_SIMPLE_Q_TAG, 344660422Sken /* lba */ address, 344760422Sken /* layer_number */ dvdstruct->layer_num, 344860422Sken /* key_format */ dvdstruct->format, 344960422Sken /* agid */ dvdstruct->agid, 345060422Sken /* data_ptr */ databuf, 345160422Sken /* dxfer_len */ length, 345260422Sken /* sense_len */ SSD_FULL_SIZE, 345360422Sken /* timeout */ 50000); 345460422Sken 345574840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 345674840Sken /*sense_flags*/SF_RETRY_UA); 345760422Sken 345860422Sken if (error != 0) 345960422Sken goto bailout; 346060422Sken 346160422Sken switch(dvdstruct->format) { 346260422Sken case DVD_STRUCT_PHYSICAL: { 346360422Sken struct scsi_read_dvd_struct_data_layer_desc *inlayer; 346460422Sken struct dvd_layer *outlayer; 346560422Sken struct scsi_read_dvd_struct_data_physical *phys_data; 346660422Sken 346760422Sken phys_data = 346860422Sken (struct scsi_read_dvd_struct_data_physical *)databuf; 346960422Sken inlayer = &phys_data->layer_desc; 347060422Sken outlayer = (struct dvd_layer *)&dvdstruct->data; 347160422Sken 347260422Sken dvdstruct->length = sizeof(*inlayer); 347360422Sken 347460422Sken outlayer->book_type = (inlayer->book_type_version & 347560422Sken RDSD_BOOK_TYPE_MASK) >> RDSD_BOOK_TYPE_SHIFT; 347660422Sken outlayer->book_version = (inlayer->book_type_version & 347760422Sken RDSD_BOOK_VERSION_MASK); 347860422Sken outlayer->disc_size = (inlayer->disc_size_max_rate & 347960422Sken RDSD_DISC_SIZE_MASK) >> RDSD_DISC_SIZE_SHIFT; 348060422Sken outlayer->max_rate = (inlayer->disc_size_max_rate & 348160422Sken RDSD_MAX_RATE_MASK); 348260422Sken outlayer->nlayers = (inlayer->layer_info & 348360422Sken RDSD_NUM_LAYERS_MASK) >> RDSD_NUM_LAYERS_SHIFT; 348460422Sken outlayer->track_path = (inlayer->layer_info & 348560422Sken RDSD_TRACK_PATH_MASK) >> RDSD_TRACK_PATH_SHIFT; 348660422Sken outlayer->layer_type = (inlayer->layer_info & 348760422Sken RDSD_LAYER_TYPE_MASK); 348860422Sken outlayer->linear_density = (inlayer->density & 348960422Sken RDSD_LIN_DENSITY_MASK) >> RDSD_LIN_DENSITY_SHIFT; 349060422Sken outlayer->track_density = (inlayer->density & 349160422Sken RDSD_TRACK_DENSITY_MASK); 349260422Sken outlayer->bca = (inlayer->bca & RDSD_BCA_MASK) >> 349360422Sken RDSD_BCA_SHIFT; 349460422Sken outlayer->start_sector = scsi_3btoul(inlayer->main_data_start); 349560422Sken outlayer->end_sector = scsi_3btoul(inlayer->main_data_end); 349660422Sken outlayer->end_sector_l0 = 349760422Sken scsi_3btoul(inlayer->end_sector_layer0); 349860422Sken break; 349960422Sken } 350060422Sken case DVD_STRUCT_COPYRIGHT: { 350160422Sken struct scsi_read_dvd_struct_data_copyright *copy_data; 350260422Sken 350360422Sken copy_data = (struct scsi_read_dvd_struct_data_copyright *) 350460422Sken databuf; 350560422Sken 350660422Sken dvdstruct->cpst = copy_data->cps_type; 350760422Sken dvdstruct->rmi = copy_data->region_info; 350860422Sken dvdstruct->length = 0; 350960422Sken 351060422Sken break; 351160422Sken } 351260422Sken default: 351360422Sken /* 351460422Sken * Tell the user what the overall length is, no matter 351560422Sken * what we can actually fit in the data buffer. 351660422Sken */ 351760422Sken dvdstruct->length = length - ccb->csio.resid - 351860422Sken sizeof(struct scsi_read_dvd_struct_data_header); 351960422Sken 352060422Sken /* 352160422Sken * But only actually copy out the smaller of what we read 352260422Sken * in or what the structure can take. 352360422Sken */ 352460422Sken bcopy(databuf + sizeof(struct scsi_read_dvd_struct_data_header), 352560422Sken dvdstruct->data, 352660422Sken min(sizeof(dvdstruct->data), dvdstruct->length)); 352760422Sken break; 352860422Sken } 352960422Skenbailout: 353060422Sken 353160422Sken if (databuf != NULL) 353260422Sken free(databuf, M_DEVBUF); 353360422Sken 353460422Sken xpt_release_ccb(ccb); 353560422Sken 353660422Sken return(error); 353760422Sken} 353860422Sken 353960422Skenvoid 354060422Skenscsi_report_key(struct ccb_scsiio *csio, u_int32_t retries, 354160422Sken void (*cbfcnp)(struct cam_periph *, union ccb *), 354260422Sken u_int8_t tag_action, u_int32_t lba, u_int8_t agid, 354360422Sken u_int8_t key_format, u_int8_t *data_ptr, u_int32_t dxfer_len, 354460422Sken u_int8_t sense_len, u_int32_t timeout) 354560422Sken{ 354660422Sken struct scsi_report_key *scsi_cmd; 354760422Sken 354860422Sken scsi_cmd = (struct scsi_report_key *)&csio->cdb_io.cdb_bytes; 354960422Sken bzero(scsi_cmd, sizeof(*scsi_cmd)); 355060422Sken scsi_cmd->opcode = REPORT_KEY; 355160422Sken scsi_ulto4b(lba, scsi_cmd->lba); 355260422Sken scsi_ulto2b(dxfer_len, scsi_cmd->alloc_len); 355360422Sken scsi_cmd->agid_keyformat = (agid << RK_KF_AGID_SHIFT) | 355460422Sken (key_format & RK_KF_KEYFORMAT_MASK); 355560422Sken 355660422Sken cam_fill_csio(csio, 355760422Sken retries, 355860422Sken cbfcnp, 355960422Sken /*flags*/ (dxfer_len == 0) ? CAM_DIR_NONE : CAM_DIR_IN, 356060422Sken tag_action, 356160422Sken /*data_ptr*/ data_ptr, 356260422Sken /*dxfer_len*/ dxfer_len, 356360422Sken sense_len, 356460422Sken sizeof(*scsi_cmd), 356560422Sken timeout); 356660422Sken} 356760422Sken 356860422Skenvoid 356960422Skenscsi_send_key(struct ccb_scsiio *csio, u_int32_t retries, 357060422Sken void (*cbfcnp)(struct cam_periph *, union ccb *), 357160422Sken u_int8_t tag_action, u_int8_t agid, u_int8_t key_format, 357260422Sken u_int8_t *data_ptr, u_int32_t dxfer_len, u_int8_t sense_len, 357360422Sken u_int32_t timeout) 357460422Sken{ 357560422Sken struct scsi_send_key *scsi_cmd; 357660422Sken 357760422Sken scsi_cmd = (struct scsi_send_key *)&csio->cdb_io.cdb_bytes; 357860422Sken bzero(scsi_cmd, sizeof(*scsi_cmd)); 357960422Sken scsi_cmd->opcode = SEND_KEY; 358060422Sken 358160422Sken scsi_ulto2b(dxfer_len, scsi_cmd->param_len); 358260422Sken scsi_cmd->agid_keyformat = (agid << RK_KF_AGID_SHIFT) | 358360422Sken (key_format & RK_KF_KEYFORMAT_MASK); 358460422Sken 358560422Sken cam_fill_csio(csio, 358660422Sken retries, 358760422Sken cbfcnp, 358860422Sken /*flags*/ CAM_DIR_OUT, 358960422Sken tag_action, 359060422Sken /*data_ptr*/ data_ptr, 359160422Sken /*dxfer_len*/ dxfer_len, 359260422Sken sense_len, 359360422Sken sizeof(*scsi_cmd), 359460422Sken timeout); 359560422Sken} 359660422Sken 359760422Sken 359860422Skenvoid 359960422Skenscsi_read_dvd_structure(struct ccb_scsiio *csio, u_int32_t retries, 360060422Sken void (*cbfcnp)(struct cam_periph *, union ccb *), 360160422Sken u_int8_t tag_action, u_int32_t address, 360260422Sken u_int8_t layer_number, u_int8_t format, u_int8_t agid, 360360422Sken u_int8_t *data_ptr, u_int32_t dxfer_len, 360460422Sken u_int8_t sense_len, u_int32_t timeout) 360560422Sken{ 360660422Sken struct scsi_read_dvd_structure *scsi_cmd; 360760422Sken 360860422Sken scsi_cmd = (struct scsi_read_dvd_structure *)&csio->cdb_io.cdb_bytes; 360960422Sken bzero(scsi_cmd, sizeof(*scsi_cmd)); 361060422Sken scsi_cmd->opcode = READ_DVD_STRUCTURE; 361160422Sken 361260422Sken scsi_ulto4b(address, scsi_cmd->address); 361360422Sken scsi_cmd->layer_number = layer_number; 361460422Sken scsi_cmd->format = format; 361560422Sken scsi_ulto2b(dxfer_len, scsi_cmd->alloc_len); 361660422Sken /* The AGID is the top two bits of this byte */ 361760422Sken scsi_cmd->agid = agid << 6; 361860422Sken 361960422Sken cam_fill_csio(csio, 362060422Sken retries, 362160422Sken cbfcnp, 362260422Sken /*flags*/ CAM_DIR_IN, 362360422Sken tag_action, 362460422Sken /*data_ptr*/ data_ptr, 362560422Sken /*dxfer_len*/ dxfer_len, 362660422Sken sense_len, 362760422Sken sizeof(*scsi_cmd), 362860422Sken timeout); 362960422Sken} 3630