scsi_cd.c revision 104880
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 104880 2002-10-11 10:35:17Z phk $ 2839213Sgibbs */ 2939213Sgibbs/* 3039213Sgibbs * Portions of this driver taken from the original FreeBSD cd driver. 3139213Sgibbs * Written by Julian Elischer (julian@tfs.com) 3239213Sgibbs * for TRW Financial Systems for use under the MACH(2.5) operating system. 3339213Sgibbs * 3439213Sgibbs * TRW Financial Systems, in accordance with their agreement with Carnegie 3539213Sgibbs * Mellon University, makes this software available to CMU to distribute 3639213Sgibbs * or use in any manner that they see fit as long as this message is kept with 3739213Sgibbs * the software. For this reason TFS also grants any other persons or 3839213Sgibbs * organisations permission to use or modify this software. 3939213Sgibbs * 4039213Sgibbs * TFS supplies this software to be publicly redistributed 4139213Sgibbs * on the understanding that TFS is not responsible for the correct 4239213Sgibbs * functioning of this software in any circumstances. 4339213Sgibbs * 4439213Sgibbs * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 4539213Sgibbs * 4639213Sgibbs * from: cd.c,v 1.83 1997/05/04 15:24:22 joerg Exp $ 4739213Sgibbs */ 4839213Sgibbs 4940020Sken#include "opt_cd.h" 5039213Sgibbs 5139213Sgibbs#include <sys/param.h> 5239213Sgibbs#include <sys/systm.h> 5339213Sgibbs#include <sys/kernel.h> 5460041Sphk#include <sys/bio.h> 5551836Sphk#include <sys/conf.h> 5651836Sphk#include <sys/disk.h> 5739213Sgibbs#include <sys/malloc.h> 5839213Sgibbs#include <sys/cdio.h> 5960422Sken#include <sys/dvdio.h> 6039213Sgibbs#include <sys/devicestat.h> 6139213Sgibbs#include <sys/sysctl.h> 6239213Sgibbs 6339213Sgibbs#include <cam/cam.h> 6439213Sgibbs#include <cam/cam_ccb.h> 6539213Sgibbs#include <cam/cam_periph.h> 6639213Sgibbs#include <cam/cam_xpt_periph.h> 6739213Sgibbs#include <cam/cam_queue.h> 6839213Sgibbs 6939213Sgibbs#include <cam/scsi/scsi_message.h> 7039213Sgibbs#include <cam/scsi/scsi_da.h> 7139213Sgibbs#include <cam/scsi/scsi_cd.h> 7239213Sgibbs 7339213Sgibbs#define LEADOUT 0xaa /* leadout toc entry */ 7439213Sgibbs 7539213Sgibbsstruct cd_params { 7639213Sgibbs u_int32_t blksize; 7739213Sgibbs u_long disksize; 7839213Sgibbs}; 7939213Sgibbs 8039213Sgibbstypedef enum { 8139213Sgibbs CD_Q_NONE = 0x00, 8239213Sgibbs CD_Q_NO_TOUCH = 0x01, 8339213Sgibbs CD_Q_BCD_TRACKS = 0x02, 8439213Sgibbs CD_Q_NO_CHANGER = 0x04, 8539213Sgibbs CD_Q_CHANGER = 0x08 8639213Sgibbs} cd_quirks; 8739213Sgibbs 8839213Sgibbstypedef enum { 8939213Sgibbs CD_FLAG_INVALID = 0x001, 9039213Sgibbs CD_FLAG_NEW_DISC = 0x002, 9139213Sgibbs CD_FLAG_DISC_LOCKED = 0x004, 9239213Sgibbs CD_FLAG_DISC_REMOVABLE = 0x008, 9339213Sgibbs CD_FLAG_TAGGED_QUEUING = 0x010, 9439213Sgibbs CD_FLAG_CHANGER = 0x040, 9539213Sgibbs CD_FLAG_ACTIVE = 0x080, 9639213Sgibbs CD_FLAG_SCHED_ON_COMP = 0x100, 9739213Sgibbs CD_FLAG_RETRY_UA = 0x200 9839213Sgibbs} cd_flags; 9939213Sgibbs 10039213Sgibbstypedef enum { 10139213Sgibbs CD_CCB_PROBE = 0x01, 10239213Sgibbs CD_CCB_BUFFER_IO = 0x02, 10339213Sgibbs CD_CCB_WAITING = 0x03, 10439213Sgibbs CD_CCB_TYPE_MASK = 0x0F, 10539213Sgibbs CD_CCB_RETRY_UA = 0x10 10639213Sgibbs} cd_ccb_state; 10739213Sgibbs 10839213Sgibbstypedef enum { 10939213Sgibbs CHANGER_TIMEOUT_SCHED = 0x01, 11039213Sgibbs CHANGER_SHORT_TMOUT_SCHED = 0x02, 11139213Sgibbs CHANGER_MANUAL_CALL = 0x04, 11239213Sgibbs CHANGER_NEED_TIMEOUT = 0x08 11339213Sgibbs} cd_changer_flags; 11439213Sgibbs 11539213Sgibbs#define ccb_state ppriv_field0 11639213Sgibbs#define ccb_bp ppriv_ptr1 11739213Sgibbs 11839213Sgibbstypedef enum { 11939213Sgibbs CD_STATE_PROBE, 12039213Sgibbs CD_STATE_NORMAL 12139213Sgibbs} cd_state; 12239213Sgibbs 12339213Sgibbsstruct cd_softc { 12439213Sgibbs cam_pinfo pinfo; 12539213Sgibbs cd_state state; 12646581Sken volatile cd_flags flags; 12759249Sphk struct bio_queue_head bio_queue; 12860938Sjake LIST_HEAD(, ccb_hdr) pending_ccbs; 12939213Sgibbs struct cd_params params; 13039213Sgibbs union ccb saved_ccb; 13139213Sgibbs cd_quirks quirks; 13239213Sgibbs struct devstat device_stats; 13360938Sjake STAILQ_ENTRY(cd_softc) changer_links; 13439213Sgibbs struct cdchanger *changer; 13539213Sgibbs int bufs_left; 13639213Sgibbs struct cam_periph *periph; 137104456Sphk dev_t dev; 138104880Sphk eventhandler_tag clonetag; 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); 20939213Sgibbsstatic int cdreadtoc(struct cam_periph *periph, u_int32_t mode, 21039213Sgibbs u_int32_t start, struct cd_toc_entry *data, 21139213Sgibbs u_int32_t len); 21239213Sgibbsstatic int cdgetmode(struct cam_periph *periph, 21339213Sgibbs struct cd_mode_data *data, u_int32_t page); 21439213Sgibbsstatic int cdsetmode(struct cam_periph *periph, 21539213Sgibbs struct cd_mode_data *data); 21639213Sgibbsstatic int cdplay(struct cam_periph *periph, u_int32_t blk, 21739213Sgibbs u_int32_t len); 21839213Sgibbsstatic int cdreadsubchannel(struct cam_periph *periph, 21939213Sgibbs u_int32_t mode, u_int32_t format, 22039213Sgibbs int track, 22139213Sgibbs struct cd_sub_channel_info *data, 22239213Sgibbs u_int32_t len); 22339213Sgibbsstatic int cdplaymsf(struct cam_periph *periph, u_int32_t startm, 22439213Sgibbs u_int32_t starts, u_int32_t startf, 22539213Sgibbs u_int32_t endm, u_int32_t ends, 22639213Sgibbs u_int32_t endf); 22739213Sgibbsstatic int cdplaytracks(struct cam_periph *periph, 22839213Sgibbs u_int32_t strack, u_int32_t sindex, 22939213Sgibbs u_int32_t etrack, u_int32_t eindex); 23039213Sgibbsstatic int cdpause(struct cam_periph *periph, u_int32_t go); 23139213Sgibbsstatic int cdstopunit(struct cam_periph *periph, u_int32_t eject); 23239213Sgibbsstatic int cdstartunit(struct cam_periph *periph); 23360422Skenstatic int cdreportkey(struct cam_periph *periph, 23460422Sken struct dvd_authinfo *authinfo); 23560422Skenstatic int cdsendkey(struct cam_periph *periph, 23660422Sken struct dvd_authinfo *authinfo); 23760422Skenstatic int cdreaddvdstructure(struct cam_periph *periph, 23860422Sken struct dvd_struct *dvdstruct); 23939213Sgibbs 24039213Sgibbsstatic struct periph_driver cddriver = 24139213Sgibbs{ 24239213Sgibbs cdinit, "cd", 24339213Sgibbs TAILQ_HEAD_INITIALIZER(cddriver.units), /* generation */ 0 24439213Sgibbs}; 24539213Sgibbs 24672119SpeterPERIPHDRIVER_DECLARE(cd, cddriver); 24739213Sgibbs 24847625Sphkstatic struct cdevsw cd_cdevsw = { 24947625Sphk /* open */ cdopen, 25047625Sphk /* close */ cdclose, 25147625Sphk /* read */ physread, 25267928Sken /* write */ physwrite, 25347625Sphk /* ioctl */ cdioctl, 25447625Sphk /* poll */ nopoll, 25547625Sphk /* mmap */ nommap, 25647625Sphk /* strategy */ cdstrategy, 25747625Sphk /* name */ "cd", 25847625Sphk /* maj */ CD_CDEV_MAJOR, 25947625Sphk /* dump */ nodump, 26047625Sphk /* psize */ nopsize, 26147625Sphk /* flags */ D_DISK, 26239213Sgibbs}; 26339213Sgibbs 26439213Sgibbsstatic int num_changers; 26539213Sgibbs 26639213Sgibbs#ifndef CHANGER_MIN_BUSY_SECONDS 26746747Sken#define CHANGER_MIN_BUSY_SECONDS 5 26839213Sgibbs#endif 26939213Sgibbs#ifndef CHANGER_MAX_BUSY_SECONDS 27046747Sken#define CHANGER_MAX_BUSY_SECONDS 15 27139213Sgibbs#endif 27239213Sgibbs 27339213Sgibbsstatic int changer_min_busy_seconds = CHANGER_MIN_BUSY_SECONDS; 27439213Sgibbsstatic int changer_max_busy_seconds = CHANGER_MAX_BUSY_SECONDS; 27539213Sgibbs 27639213SgibbsSYSCTL_NODE(_kern_cam, OID_AUTO, cd, CTLFLAG_RD, 0, "CAM CDROM driver"); 27739213SgibbsSYSCTL_NODE(_kern_cam_cd, OID_AUTO, changer, CTLFLAG_RD, 0, "CD Changer"); 27839213SgibbsSYSCTL_INT(_kern_cam_cd_changer, OID_AUTO, min_busy_seconds, CTLFLAG_RW, 27939213Sgibbs &changer_min_busy_seconds, 0, "Minimum changer scheduling quantum"); 28039213SgibbsSYSCTL_INT(_kern_cam_cd_changer, OID_AUTO, max_busy_seconds, CTLFLAG_RW, 28139213Sgibbs &changer_max_busy_seconds, 0, "Maximum changer scheduling quantum"); 28239213Sgibbs 28339213Sgibbsstruct cdchanger { 28439213Sgibbs path_id_t path_id; 28539213Sgibbs target_id_t target_id; 28639213Sgibbs int num_devices; 28739213Sgibbs struct camq devq; 28839213Sgibbs struct timeval start_time; 28939213Sgibbs struct cd_softc *cur_device; 29039213Sgibbs struct callout_handle short_handle; 29139213Sgibbs struct callout_handle long_handle; 29246581Sken volatile cd_changer_flags flags; 29360938Sjake STAILQ_ENTRY(cdchanger) changer_links; 29460938Sjake STAILQ_HEAD(chdevlist, cd_softc) chluns; 29539213Sgibbs}; 29639213Sgibbs 29760938Sjakestatic STAILQ_HEAD(changerlist, cdchanger) changerq; 29839213Sgibbs 299104094Sphkstatic void 300104880Sphkcdclone(void *arg, char *name, int namelen, dev_t *dev) 301104880Sphk{ 302104880Sphk struct cd_softc *softc; 303104880Sphk const char *p; 304104880Sphk int l; 305104880Sphk 306104880Sphk softc = arg; 307104880Sphk p = devtoname(softc->dev); 308104880Sphk l = strlen(p); 309104880Sphk if (bcmp(name, p, l)) 310104880Sphk return; 311104880Sphk if (name[l] != 'a' && name[l] != 'c') 312104880Sphk return; 313104880Sphk if (name[l + 1] != '\0') 314104880Sphk return; 315104880Sphk *dev = softc->dev; 316104880Sphk return; 317104880Sphk} 318104880Sphk 319104880Sphkstatic void 32039213Sgibbscdinit(void) 32139213Sgibbs{ 32239213Sgibbs cam_status status; 32339213Sgibbs struct cam_path *path; 32439213Sgibbs 32539213Sgibbs /* 32639213Sgibbs * Install a global async callback. This callback will 32739213Sgibbs * receive async callbacks like "new device found". 32839213Sgibbs */ 32939213Sgibbs status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID, 33039213Sgibbs CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 33139213Sgibbs 33239213Sgibbs if (status == CAM_REQ_CMP) { 33339213Sgibbs struct ccb_setasync csa; 33439213Sgibbs 33539213Sgibbs xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5); 33639213Sgibbs csa.ccb_h.func_code = XPT_SASYNC_CB; 33739213Sgibbs csa.event_enable = AC_FOUND_DEVICE; 33839213Sgibbs csa.callback = cdasync; 33939213Sgibbs csa.callback_arg = NULL; 34039213Sgibbs xpt_action((union ccb *)&csa); 34139213Sgibbs status = csa.ccb_h.status; 34239213Sgibbs xpt_free_path(path); 34339213Sgibbs } 34439213Sgibbs 34539213Sgibbs if (status != CAM_REQ_CMP) { 34639213Sgibbs printf("cd: Failed to attach master async callback " 34739213Sgibbs "due to status 0x%x!\n", status); 34839213Sgibbs } 34939213Sgibbs} 35039213Sgibbs 35139213Sgibbsstatic void 35240603Skencdoninvalidate(struct cam_periph *periph) 35340603Sken{ 35440603Sken int s; 35540603Sken struct cd_softc *softc; 35659249Sphk struct bio *q_bp; 35740603Sken struct ccb_setasync csa; 35840603Sken 35940603Sken softc = (struct cd_softc *)periph->softc; 36040603Sken 36140603Sken /* 36240603Sken * De-register any async callbacks. 36340603Sken */ 36440603Sken xpt_setup_ccb(&csa.ccb_h, periph->path, 36540603Sken /* priority */ 5); 36640603Sken csa.ccb_h.func_code = XPT_SASYNC_CB; 36740603Sken csa.event_enable = 0; 36840603Sken csa.callback = cdasync; 36940603Sken csa.callback_arg = periph; 37040603Sken xpt_action((union ccb *)&csa); 37140603Sken 37240603Sken softc->flags |= CD_FLAG_INVALID; 37340603Sken 37440603Sken /* 37540603Sken * Although the oninvalidate() routines are always called at 37640603Sken * splsoftcam, we need to be at splbio() here to keep the buffer 37740603Sken * queue from being modified while we traverse it. 37840603Sken */ 37940603Sken s = splbio(); 38040603Sken 38140603Sken /* 38240603Sken * Return all queued I/O with ENXIO. 38340603Sken * XXX Handle any transactions queued to the card 38440603Sken * with XPT_ABORT_CCB. 38540603Sken */ 38659249Sphk while ((q_bp = bioq_first(&softc->bio_queue)) != NULL){ 38759249Sphk bioq_remove(&softc->bio_queue, q_bp); 38859249Sphk q_bp->bio_resid = q_bp->bio_bcount; 38976322Sphk biofinish(q_bp, NULL, ENXIO); 39040603Sken } 39140603Sken splx(s); 39240603Sken 39340603Sken /* 39440603Sken * If this device is part of a changer, and it was scheduled 39540603Sken * to run, remove it from the run queue since we just nuked 39640603Sken * all of its scheduled I/O. 39740603Sken */ 39840603Sken if ((softc->flags & CD_FLAG_CHANGER) 39940603Sken && (softc->pinfo.index != CAM_UNQUEUED_INDEX)) 40040603Sken camq_remove(&softc->changer->devq, softc->pinfo.index); 40140603Sken 40240603Sken xpt_print_path(periph->path); 40340603Sken printf("lost device\n"); 40440603Sken} 40540603Sken 40640603Skenstatic void 40739213Sgibbscdcleanup(struct cam_periph *periph) 40839213Sgibbs{ 40939213Sgibbs struct cd_softc *softc; 41040603Sken int s; 41139213Sgibbs 41239213Sgibbs softc = (struct cd_softc *)periph->softc; 41339213Sgibbs 41439213Sgibbs xpt_print_path(periph->path); 41539213Sgibbs printf("removing device entry\n"); 41640603Sken 41740603Sken s = splsoftcam(); 41839213Sgibbs /* 41939213Sgibbs * In the queued, non-active case, the device in question 42039213Sgibbs * has already been removed from the changer run queue. Since this 42139213Sgibbs * device is active, we need to de-activate it, and schedule 42239213Sgibbs * another device to run. (if there is another one to run) 42339213Sgibbs */ 42439213Sgibbs if ((softc->flags & CD_FLAG_CHANGER) 42539213Sgibbs && (softc->flags & CD_FLAG_ACTIVE)) { 42639213Sgibbs 42739213Sgibbs /* 42839213Sgibbs * The purpose of the short timeout is soley to determine 42939213Sgibbs * whether the current device has finished or not. Well, 43039213Sgibbs * since we're removing the active device, we know that it 43139213Sgibbs * is finished. So, get rid of the short timeout. 43239213Sgibbs * Otherwise, if we're in the time period before the short 43339213Sgibbs * timeout fires, and there are no other devices in the 43439213Sgibbs * queue to run, there won't be any other device put in the 43539213Sgibbs * active slot. i.e., when we call cdrunchangerqueue() 43639213Sgibbs * below, it won't do anything. Then, when the short 43739213Sgibbs * timeout fires, it'll look at the "current device", which 43839213Sgibbs * we are free below, and possibly panic the kernel on a 43939213Sgibbs * bogus pointer reference. 44039213Sgibbs * 44139213Sgibbs * The long timeout doesn't really matter, since we 44239213Sgibbs * decrement the qfrozen_cnt to indicate that there is 44339213Sgibbs * nothing in the active slot now. Therefore, there won't 44439213Sgibbs * be any bogus pointer references there. 44539213Sgibbs */ 44639213Sgibbs if (softc->changer->flags & CHANGER_SHORT_TMOUT_SCHED) { 44739213Sgibbs untimeout(cdshorttimeout, softc->changer, 44839213Sgibbs softc->changer->short_handle); 44939213Sgibbs softc->changer->flags &= ~CHANGER_SHORT_TMOUT_SCHED; 45039213Sgibbs } 45139213Sgibbs softc->changer->devq.qfrozen_cnt--; 45239213Sgibbs softc->changer->flags |= CHANGER_MANUAL_CALL; 45339213Sgibbs cdrunchangerqueue(softc->changer); 45439213Sgibbs } 45539213Sgibbs 45639213Sgibbs /* 45739213Sgibbs * If we're removing the last device on the changer, go ahead and 45839213Sgibbs * remove the changer device structure. 45939213Sgibbs */ 46039213Sgibbs if ((softc->flags & CD_FLAG_CHANGER) 46139213Sgibbs && (--softc->changer->num_devices == 0)) { 46239213Sgibbs 46339213Sgibbs /* 46439213Sgibbs * Theoretically, there shouldn't be any timeouts left, but 46539213Sgibbs * I'm not completely sure that that will be the case. So, 46639213Sgibbs * it won't hurt to check and see if there are any left. 46739213Sgibbs */ 46839213Sgibbs if (softc->changer->flags & CHANGER_TIMEOUT_SCHED) { 46939213Sgibbs untimeout(cdrunchangerqueue, softc->changer, 47039213Sgibbs softc->changer->long_handle); 47139213Sgibbs softc->changer->flags &= ~CHANGER_TIMEOUT_SCHED; 47239213Sgibbs } 47339213Sgibbs 47439213Sgibbs if (softc->changer->flags & CHANGER_SHORT_TMOUT_SCHED) { 47539213Sgibbs untimeout(cdshorttimeout, softc->changer, 47639213Sgibbs softc->changer->short_handle); 47739213Sgibbs softc->changer->flags &= ~CHANGER_SHORT_TMOUT_SCHED; 47839213Sgibbs } 47939213Sgibbs 48060938Sjake STAILQ_REMOVE(&changerq, softc->changer, cdchanger, 48139213Sgibbs changer_links); 48239213Sgibbs xpt_print_path(periph->path); 48339213Sgibbs printf("removing changer entry\n"); 48439213Sgibbs free(softc->changer, M_DEVBUF); 48539213Sgibbs num_changers--; 48639213Sgibbs } 48740603Sken devstat_remove_entry(&softc->device_stats); 488104456Sphk destroy_dev(softc->dev); 489104880Sphk EVENTHANDLER_DEREGISTER(dev_clone, softc->clonetag); 49040603Sken free(softc, M_DEVBUF); 49140603Sken splx(s); 49239213Sgibbs} 49339213Sgibbs 49439213Sgibbsstatic void 49539213Sgibbscdasync(void *callback_arg, u_int32_t code, 49639213Sgibbs struct cam_path *path, void *arg) 49739213Sgibbs{ 49839213Sgibbs struct cam_periph *periph; 49939213Sgibbs 50039213Sgibbs periph = (struct cam_periph *)callback_arg; 50139213Sgibbs switch (code) { 50239213Sgibbs case AC_FOUND_DEVICE: 50339213Sgibbs { 50439213Sgibbs struct ccb_getdev *cgd; 50539213Sgibbs cam_status status; 50639213Sgibbs 50739213Sgibbs cgd = (struct ccb_getdev *)arg; 50879177Smjacob if (cgd == NULL) 50979177Smjacob break; 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 /* 59739213Sgibbs * See if this device has any quirks. 59839213Sgibbs */ 59939213Sgibbs match = cam_quirkmatch((caddr_t)&cgd->inq_data, 60039213Sgibbs (caddr_t)cd_quirk_table, 60139213Sgibbs sizeof(cd_quirk_table)/sizeof(*cd_quirk_table), 60239213Sgibbs sizeof(*cd_quirk_table), scsi_inquiry_match); 60339213Sgibbs 60439213Sgibbs if (match != NULL) 60539213Sgibbs softc->quirks = ((struct cd_quirk_entry *)match)->quirks; 60639213Sgibbs else 60739213Sgibbs softc->quirks = CD_Q_NONE; 60839213Sgibbs 60939213Sgibbs /* 61039213Sgibbs * We need to register the statistics structure for this device, 61139213Sgibbs * but we don't have the blocksize yet for it. So, we register 61239213Sgibbs * the structure and indicate that we don't have the blocksize 61339213Sgibbs * yet. Unlike other SCSI peripheral drivers, we explicitly set 61439213Sgibbs * the device type here to be CDROM, rather than just ORing in 61556148Smjacob * the device type. This is because this driver can attach to either 61639213Sgibbs * CDROM or WORM devices, and we want this peripheral driver to 61739213Sgibbs * show up in the devstat list as a CD peripheral driver, not a 61839213Sgibbs * WORM peripheral driver. WORM drives will also have the WORM 61939213Sgibbs * driver attached to them. 62039213Sgibbs */ 62139213Sgibbs devstat_add_entry(&softc->device_stats, "cd", 62239213Sgibbs periph->unit_number, 0, 62339213Sgibbs DEVSTAT_BS_UNAVAILABLE, 62443819Sken DEVSTAT_TYPE_CDROM | DEVSTAT_TYPE_IF_SCSI, 62543819Sken DEVSTAT_PRIORITY_CD); 626104456Sphk softc->dev = make_dev(&cd_cdevsw, periph->unit_number, 627104456Sphk UID_ROOT, GID_OPERATOR, 0640, "cd%d", periph->unit_number); 628104456Sphk softc->dev->si_drv1 = periph; 629104880Sphk softc->clonetag = 630104880Sphk EVENTHANDLER_REGISTER(dev_clone, cdclone, softc, 1000); 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 87383366Sjuliancdopen(dev_t dev, int flags, int fmt, struct thread *td) 87439213Sgibbs{ 87539213Sgibbs struct cam_periph *periph; 87639213Sgibbs struct cd_softc *softc; 87739213Sgibbs u_int32_t size; 878101940Snjl int error; 87940603Sken int s; 88039213Sgibbs 881101940Snjl periph = (struct cam_periph *)dev->si_drv1; 88239213Sgibbs if (periph == NULL) 88339213Sgibbs return (ENXIO); 88439213Sgibbs 88539213Sgibbs softc = (struct cd_softc *)periph->softc; 88639213Sgibbs 88741297Sken /* 88841297Sken * Grab splsoftcam and hold it until we lock the peripheral. 88941297Sken */ 89040603Sken s = splsoftcam(); 89140603Sken if (softc->flags & CD_FLAG_INVALID) { 89240603Sken splx(s); 89339213Sgibbs return(ENXIO); 89440603Sken } 89539213Sgibbs 89641297Sken if ((error = cam_periph_lock(periph, PRIBIO | PCATCH)) != 0) { 89741297Sken splx(s); 89839213Sgibbs return (error); 89941297Sken } 90039213Sgibbs 90141297Sken splx(s); 90241297Sken 90351836Sphk if (cam_periph_acquire(periph) != CAM_REQ_CMP) 90451836Sphk return(ENXIO); 90540020Sken 90651836Sphk cdprevent(periph, PR_PREVENT); 90739213Sgibbs 90839213Sgibbs /* find out the size */ 90939213Sgibbs if ((error = cdsize(dev, &size)) != 0) { 91051836Sphk cdprevent(periph, PR_ALLOW); 91139213Sgibbs cam_periph_unlock(periph); 91251836Sphk cam_periph_release(periph); 91339213Sgibbs return(error); 91439213Sgibbs } 91539213Sgibbs 91640020Sken /* 91751836Sphk * We unconditionally (re)set the blocksize each time the 91851836Sphk * CD device is opened. This is because the CD can change, 91951836Sphk * and therefore the blocksize might change. 92051836Sphk * XXX problems here if some slice or partition is still 92151836Sphk * open with the old size? 92251836Sphk */ 92351836Sphk if ((softc->device_stats.flags & DEVSTAT_BS_UNAVAILABLE) != 0) 92451836Sphk softc->device_stats.flags &= ~DEVSTAT_BS_UNAVAILABLE; 92551836Sphk softc->device_stats.block_size = softc->params.blksize; 92640020Sken 92739213Sgibbs cam_periph_unlock(periph); 92839213Sgibbs 92939213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("leaving cdopen\n")); 93039213Sgibbs 93139213Sgibbs return (error); 93239213Sgibbs} 93339213Sgibbs 93439213Sgibbsstatic int 93583366Sjuliancdclose(dev_t dev, int flag, int fmt, struct thread *td) 93639213Sgibbs{ 93739213Sgibbs struct cam_periph *periph; 93839213Sgibbs struct cd_softc *softc; 939101940Snjl int error; 94039213Sgibbs 941101940Snjl periph = (struct cam_periph *)dev->si_drv1; 94239213Sgibbs if (periph == NULL) 94339213Sgibbs return (ENXIO); 94439213Sgibbs 94539213Sgibbs softc = (struct cd_softc *)periph->softc; 94639213Sgibbs 94739213Sgibbs if ((error = cam_periph_lock(periph, PRIBIO)) != 0) 94839213Sgibbs return (error); 94939213Sgibbs 95039213Sgibbs if ((softc->flags & CD_FLAG_DISC_REMOVABLE) != 0) 95139213Sgibbs cdprevent(periph, PR_ALLOW); 95239213Sgibbs 95339213Sgibbs /* 95439213Sgibbs * Since we're closing this CD, mark the blocksize as unavailable. 95539213Sgibbs * It will be marked as available whence the CD is opened again. 95639213Sgibbs */ 95739213Sgibbs softc->device_stats.flags |= DEVSTAT_BS_UNAVAILABLE; 95839213Sgibbs 95939213Sgibbs cam_periph_unlock(periph); 96039213Sgibbs cam_periph_release(periph); 96139213Sgibbs 96239213Sgibbs return (0); 96339213Sgibbs} 96439213Sgibbs 96539213Sgibbsstatic void 96639213Sgibbscdshorttimeout(void *arg) 96739213Sgibbs{ 96839213Sgibbs struct cdchanger *changer; 96939213Sgibbs int s; 97039213Sgibbs 97139213Sgibbs s = splsoftcam(); 97239213Sgibbs 97339213Sgibbs changer = (struct cdchanger *)arg; 97439213Sgibbs 97539213Sgibbs /* Always clear the short timeout flag, since that's what we're in */ 97639213Sgibbs changer->flags &= ~CHANGER_SHORT_TMOUT_SCHED; 97739213Sgibbs 97839213Sgibbs /* 97939213Sgibbs * Check to see if there is any more pending or outstanding I/O for 98039213Sgibbs * this device. If not, move it out of the active slot. 98139213Sgibbs */ 98259249Sphk if ((bioq_first(&changer->cur_device->bio_queue) == NULL) 98339213Sgibbs && (changer->cur_device->device_stats.busy_count == 0)) { 98439213Sgibbs changer->flags |= CHANGER_MANUAL_CALL; 98539213Sgibbs cdrunchangerqueue(changer); 98639213Sgibbs } 98739213Sgibbs 98839213Sgibbs splx(s); 98939213Sgibbs} 99039213Sgibbs 99139213Sgibbs/* 99239213Sgibbs * This is a wrapper for xpt_schedule. It only applies to changers. 99339213Sgibbs */ 99439213Sgibbsstatic void 99539213Sgibbscdschedule(struct cam_periph *periph, int priority) 99639213Sgibbs{ 99739213Sgibbs struct cd_softc *softc; 99839213Sgibbs int s; 99939213Sgibbs 100039213Sgibbs s = splsoftcam(); 100139213Sgibbs 100239213Sgibbs softc = (struct cd_softc *)periph->softc; 100339213Sgibbs 100439213Sgibbs /* 100539213Sgibbs * If this device isn't currently queued, and if it isn't 100639213Sgibbs * the active device, then we queue this device and run the 100739213Sgibbs * changer queue if there is no timeout scheduled to do it. 100839213Sgibbs * If this device is the active device, just schedule it 100939213Sgibbs * to run again. If this device is queued, there should be 101039213Sgibbs * a timeout in place already that will make sure it runs. 101139213Sgibbs */ 101239213Sgibbs if ((softc->pinfo.index == CAM_UNQUEUED_INDEX) 101339213Sgibbs && ((softc->flags & CD_FLAG_ACTIVE) == 0)) { 101439213Sgibbs /* 101539213Sgibbs * We don't do anything with the priority here. 101639213Sgibbs * This is strictly a fifo queue. 101739213Sgibbs */ 101839213Sgibbs softc->pinfo.priority = 1; 101945442Sgibbs softc->pinfo.generation = ++softc->changer->devq.generation; 102039213Sgibbs camq_insert(&softc->changer->devq, (cam_pinfo *)softc); 102139213Sgibbs 102239213Sgibbs /* 102339213Sgibbs * Since we just put a device in the changer queue, 102439213Sgibbs * check and see if there is a timeout scheduled for 102539213Sgibbs * this changer. If so, let the timeout handle 102639213Sgibbs * switching this device into the active slot. If 102739213Sgibbs * not, manually call the timeout routine to 102839213Sgibbs * bootstrap things. 102939213Sgibbs */ 103039213Sgibbs if (((softc->changer->flags & CHANGER_TIMEOUT_SCHED)==0) 103146581Sken && ((softc->changer->flags & CHANGER_NEED_TIMEOUT)==0) 103246581Sken && ((softc->changer->flags & CHANGER_SHORT_TMOUT_SCHED)==0)){ 103339213Sgibbs softc->changer->flags |= CHANGER_MANUAL_CALL; 103439213Sgibbs cdrunchangerqueue(softc->changer); 103539213Sgibbs } 103639213Sgibbs } else if ((softc->flags & CD_FLAG_ACTIVE) 103739213Sgibbs && ((softc->flags & CD_FLAG_SCHED_ON_COMP) == 0)) 103839213Sgibbs xpt_schedule(periph, priority); 103939213Sgibbs 104039213Sgibbs splx(s); 104139213Sgibbs 104239213Sgibbs} 104339213Sgibbs 104439213Sgibbsstatic void 104539213Sgibbscdrunchangerqueue(void *arg) 104639213Sgibbs{ 104739213Sgibbs struct cd_softc *softc; 104839213Sgibbs struct cdchanger *changer; 104939213Sgibbs int called_from_timeout; 105039213Sgibbs int s; 105139213Sgibbs 105239213Sgibbs s = splsoftcam(); 105339213Sgibbs 105439213Sgibbs changer = (struct cdchanger *)arg; 105539213Sgibbs 105639213Sgibbs /* 105739213Sgibbs * If we have NOT been called from cdstrategy() or cddone(), and 105839213Sgibbs * instead from a timeout routine, go ahead and clear the 105939213Sgibbs * timeout flag. 106039213Sgibbs */ 106139213Sgibbs if ((changer->flags & CHANGER_MANUAL_CALL) == 0) { 106239213Sgibbs changer->flags &= ~CHANGER_TIMEOUT_SCHED; 106339213Sgibbs called_from_timeout = 1; 106439213Sgibbs } else 106539213Sgibbs called_from_timeout = 0; 106639213Sgibbs 106739213Sgibbs /* Always clear the manual call flag */ 106839213Sgibbs changer->flags &= ~CHANGER_MANUAL_CALL; 106939213Sgibbs 107039213Sgibbs /* nothing to do if the queue is empty */ 107139213Sgibbs if (changer->devq.entries <= 0) { 107239213Sgibbs splx(s); 107339213Sgibbs return; 107439213Sgibbs } 107539213Sgibbs 107639213Sgibbs /* 107739213Sgibbs * If the changer queue is frozen, that means we have an active 107839213Sgibbs * device. 107939213Sgibbs */ 108039213Sgibbs if (changer->devq.qfrozen_cnt > 0) { 108139213Sgibbs 108239213Sgibbs if (changer->cur_device->device_stats.busy_count > 0) { 108339213Sgibbs changer->cur_device->flags |= CD_FLAG_SCHED_ON_COMP; 108439213Sgibbs changer->cur_device->bufs_left = 108539213Sgibbs changer->cur_device->device_stats.busy_count; 108639213Sgibbs if (called_from_timeout) { 108739213Sgibbs changer->long_handle = 108839213Sgibbs timeout(cdrunchangerqueue, changer, 108939213Sgibbs changer_max_busy_seconds * hz); 109039213Sgibbs changer->flags |= CHANGER_TIMEOUT_SCHED; 109139213Sgibbs } 109239213Sgibbs splx(s); 109339213Sgibbs return; 109439213Sgibbs } 109539213Sgibbs 109639213Sgibbs /* 109739213Sgibbs * We always need to reset the frozen count and clear the 109839213Sgibbs * active flag. 109939213Sgibbs */ 110039213Sgibbs changer->devq.qfrozen_cnt--; 110139213Sgibbs changer->cur_device->flags &= ~CD_FLAG_ACTIVE; 110239213Sgibbs changer->cur_device->flags &= ~CD_FLAG_SCHED_ON_COMP; 110339213Sgibbs 110439213Sgibbs /* 110539213Sgibbs * Check to see whether the current device has any I/O left 110639213Sgibbs * to do. If so, requeue it at the end of the queue. If 110739213Sgibbs * not, there is no need to requeue it. 110839213Sgibbs */ 110959249Sphk if (bioq_first(&changer->cur_device->bio_queue) != NULL) { 111039213Sgibbs 111139213Sgibbs changer->cur_device->pinfo.generation = 111245442Sgibbs ++changer->devq.generation; 111339213Sgibbs camq_insert(&changer->devq, 111439213Sgibbs (cam_pinfo *)changer->cur_device); 111539213Sgibbs } 111639213Sgibbs } 111739213Sgibbs 111845845Sgibbs softc = (struct cd_softc *)camq_remove(&changer->devq, CAMQ_HEAD); 111939213Sgibbs 112039213Sgibbs changer->cur_device = softc; 112139213Sgibbs 112239213Sgibbs changer->devq.qfrozen_cnt++; 112339213Sgibbs softc->flags |= CD_FLAG_ACTIVE; 112439213Sgibbs 112539213Sgibbs /* Just in case this device is waiting */ 112639213Sgibbs wakeup(&softc->changer); 112739213Sgibbs xpt_schedule(softc->periph, /*priority*/ 1); 112839213Sgibbs 112939213Sgibbs /* 113039213Sgibbs * Get rid of any pending timeouts, and set a flag to schedule new 113139213Sgibbs * ones so this device gets its full time quantum. 113239213Sgibbs */ 113339213Sgibbs if (changer->flags & CHANGER_TIMEOUT_SCHED) { 113439213Sgibbs untimeout(cdrunchangerqueue, changer, changer->long_handle); 113539213Sgibbs changer->flags &= ~CHANGER_TIMEOUT_SCHED; 113639213Sgibbs } 113739213Sgibbs 113839213Sgibbs if (changer->flags & CHANGER_SHORT_TMOUT_SCHED) { 113939213Sgibbs untimeout(cdshorttimeout, changer, changer->short_handle); 114039213Sgibbs changer->flags &= ~CHANGER_SHORT_TMOUT_SCHED; 114139213Sgibbs } 114239213Sgibbs 114339213Sgibbs /* 114439213Sgibbs * We need to schedule timeouts, but we only do this after the 114539213Sgibbs * first transaction has completed. This eliminates the changer 114639213Sgibbs * switch time. 114739213Sgibbs */ 114839213Sgibbs changer->flags |= CHANGER_NEED_TIMEOUT; 114939213Sgibbs 115039213Sgibbs splx(s); 115139213Sgibbs} 115239213Sgibbs 115339213Sgibbsstatic void 115439213Sgibbscdchangerschedule(struct cd_softc *softc) 115539213Sgibbs{ 115639213Sgibbs struct cdchanger *changer; 115739213Sgibbs int s; 115839213Sgibbs 115939213Sgibbs s = splsoftcam(); 116039213Sgibbs 116139213Sgibbs changer = softc->changer; 116239213Sgibbs 116339213Sgibbs /* 116439213Sgibbs * If this is a changer, and this is the current device, 116539213Sgibbs * and this device has at least the minimum time quantum to 116639213Sgibbs * run, see if we can switch it out. 116739213Sgibbs */ 116839213Sgibbs if ((softc->flags & CD_FLAG_ACTIVE) 116939213Sgibbs && ((changer->flags & CHANGER_SHORT_TMOUT_SCHED) == 0) 117039213Sgibbs && ((changer->flags & CHANGER_NEED_TIMEOUT) == 0)) { 117139213Sgibbs /* 117239213Sgibbs * We try three things here. The first is that we 117339213Sgibbs * check to see whether the schedule on completion 117439213Sgibbs * flag is set. If it is, we decrement the number 117539213Sgibbs * of buffers left, and if it's zero, we reschedule. 117639213Sgibbs * Next, we check to see whether the pending buffer 117739213Sgibbs * queue is empty and whether there are no 117839213Sgibbs * outstanding transactions. If so, we reschedule. 117939213Sgibbs * Next, we see if the pending buffer queue is empty. 118039213Sgibbs * If it is, we set the number of buffers left to 118139213Sgibbs * the current active buffer count and set the 118239213Sgibbs * schedule on complete flag. 118339213Sgibbs */ 118439213Sgibbs if (softc->flags & CD_FLAG_SCHED_ON_COMP) { 118539213Sgibbs if (--softc->bufs_left == 0) { 118639213Sgibbs softc->changer->flags |= 118739213Sgibbs CHANGER_MANUAL_CALL; 118839213Sgibbs softc->flags &= ~CD_FLAG_SCHED_ON_COMP; 118939213Sgibbs cdrunchangerqueue(softc->changer); 119039213Sgibbs } 119159249Sphk } else if ((bioq_first(&softc->bio_queue) == NULL) 119239213Sgibbs && (softc->device_stats.busy_count == 0)) { 119339213Sgibbs softc->changer->flags |= CHANGER_MANUAL_CALL; 119439213Sgibbs cdrunchangerqueue(softc->changer); 119539213Sgibbs } 119639213Sgibbs } else if ((softc->changer->flags & CHANGER_NEED_TIMEOUT) 119739213Sgibbs && (softc->flags & CD_FLAG_ACTIVE)) { 119839213Sgibbs 119939213Sgibbs /* 120039213Sgibbs * Now that the first transaction to this 120139213Sgibbs * particular device has completed, we can go ahead 120239213Sgibbs * and schedule our timeouts. 120339213Sgibbs */ 120439213Sgibbs if ((changer->flags & CHANGER_TIMEOUT_SCHED) == 0) { 120539213Sgibbs changer->long_handle = 120639213Sgibbs timeout(cdrunchangerqueue, changer, 120739213Sgibbs changer_max_busy_seconds * hz); 120839213Sgibbs changer->flags |= CHANGER_TIMEOUT_SCHED; 120939213Sgibbs } else 121039213Sgibbs printf("cdchangerschedule: already have a long" 121139213Sgibbs " timeout!\n"); 121239213Sgibbs 121339213Sgibbs if ((changer->flags & CHANGER_SHORT_TMOUT_SCHED) == 0) { 121439213Sgibbs changer->short_handle = 121539213Sgibbs timeout(cdshorttimeout, changer, 121639213Sgibbs changer_min_busy_seconds * hz); 121739213Sgibbs changer->flags |= CHANGER_SHORT_TMOUT_SCHED; 121839213Sgibbs } else 121939213Sgibbs printf("cdchangerschedule: already have a short " 122039213Sgibbs "timeout!\n"); 122139213Sgibbs 122239213Sgibbs /* 122339213Sgibbs * We just scheduled timeouts, no need to schedule 122439213Sgibbs * more. 122539213Sgibbs */ 122639213Sgibbs changer->flags &= ~CHANGER_NEED_TIMEOUT; 122739213Sgibbs 122839213Sgibbs } 122939213Sgibbs splx(s); 123039213Sgibbs} 123139213Sgibbs 123239213Sgibbsstatic int 123339213Sgibbscdrunccb(union ccb *ccb, int (*error_routine)(union ccb *ccb, 123439213Sgibbs u_int32_t cam_flags, 123539213Sgibbs u_int32_t sense_flags), 123639213Sgibbs u_int32_t cam_flags, u_int32_t sense_flags) 123739213Sgibbs{ 123839213Sgibbs struct cd_softc *softc; 123939213Sgibbs struct cam_periph *periph; 124039213Sgibbs int error; 124139213Sgibbs 124239213Sgibbs periph = xpt_path_periph(ccb->ccb_h.path); 124339213Sgibbs softc = (struct cd_softc *)periph->softc; 124439213Sgibbs 124539213Sgibbs error = cam_periph_runccb(ccb, error_routine, cam_flags, sense_flags, 124639213Sgibbs &softc->device_stats); 124739213Sgibbs 124839213Sgibbs if (softc->flags & CD_FLAG_CHANGER) 124939213Sgibbs cdchangerschedule(softc); 125039213Sgibbs 125139213Sgibbs return(error); 125239213Sgibbs} 125339213Sgibbs 125442017Seivindstatic union ccb * 125539213Sgibbscdgetccb(struct cam_periph *periph, u_int32_t priority) 125639213Sgibbs{ 125739213Sgibbs struct cd_softc *softc; 125839213Sgibbs int s; 125939213Sgibbs 126039213Sgibbs softc = (struct cd_softc *)periph->softc; 126139213Sgibbs 126239213Sgibbs if (softc->flags & CD_FLAG_CHANGER) { 126339213Sgibbs 126439213Sgibbs s = splsoftcam(); 126539213Sgibbs 126639213Sgibbs /* 126739213Sgibbs * This should work the first time this device is woken up, 126839213Sgibbs * but just in case it doesn't, we use a while loop. 126939213Sgibbs */ 127046581Sken while ((softc->flags & CD_FLAG_ACTIVE) == 0) { 127139213Sgibbs /* 127239213Sgibbs * If this changer isn't already queued, queue it up. 127339213Sgibbs */ 127439213Sgibbs if (softc->pinfo.index == CAM_UNQUEUED_INDEX) { 127539213Sgibbs softc->pinfo.priority = 1; 127639213Sgibbs softc->pinfo.generation = 127745442Sgibbs ++softc->changer->devq.generation; 127839213Sgibbs camq_insert(&softc->changer->devq, 127939213Sgibbs (cam_pinfo *)softc); 128039213Sgibbs } 128146581Sken if (((softc->changer->flags & CHANGER_TIMEOUT_SCHED)==0) 128246581Sken && ((softc->changer->flags & CHANGER_NEED_TIMEOUT)==0) 128346581Sken && ((softc->changer->flags 128446581Sken & CHANGER_SHORT_TMOUT_SCHED)==0)) { 128539213Sgibbs softc->changer->flags |= CHANGER_MANUAL_CALL; 128639213Sgibbs cdrunchangerqueue(softc->changer); 128739213Sgibbs } else 128839213Sgibbs tsleep(&softc->changer, PRIBIO, "cgticb", 0); 128939213Sgibbs } 129039213Sgibbs splx(s); 129139213Sgibbs } 129239213Sgibbs return(cam_periph_getccb(periph, priority)); 129339213Sgibbs} 129439213Sgibbs 129539213Sgibbs 129639213Sgibbs/* 129739213Sgibbs * Actually translate the requested transfer into one the physical driver 129839213Sgibbs * can understand. The transfer is described by a buf and will include 129939213Sgibbs * only one physical transfer. 130039213Sgibbs */ 130139213Sgibbsstatic void 130259249Sphkcdstrategy(struct bio *bp) 130339213Sgibbs{ 130439213Sgibbs struct cam_periph *periph; 130539213Sgibbs struct cd_softc *softc; 130639213Sgibbs int s; 130739213Sgibbs 1308101940Snjl periph = (struct cam_periph *)bp->bio_dev->si_drv1; 130939213Sgibbs if (periph == NULL) { 131076362Sphk biofinish(bp, NULL, ENXIO); 131176362Sphk return; 131239213Sgibbs } 131339213Sgibbs 131439213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdstrategy\n")); 131539213Sgibbs 131639213Sgibbs softc = (struct cd_softc *)periph->softc; 131739213Sgibbs 131839213Sgibbs /* 131939213Sgibbs * Mask interrupts so that the pack cannot be invalidated until 132039213Sgibbs * after we are in the queue. Otherwise, we might not properly 132139213Sgibbs * clean up one of the buffers. 132239213Sgibbs */ 132339213Sgibbs s = splbio(); 132439213Sgibbs 132539213Sgibbs /* 132639213Sgibbs * If the device has been made invalid, error out 132739213Sgibbs */ 132839213Sgibbs if ((softc->flags & CD_FLAG_INVALID)) { 132939213Sgibbs splx(s); 133076362Sphk biofinish(bp, NULL, ENXIO); 133176362Sphk return; 133239213Sgibbs } 133339213Sgibbs 133439213Sgibbs /* 133539213Sgibbs * Place it in the queue of disk activities for this disk 133639213Sgibbs */ 133759249Sphk bioqdisksort(&softc->bio_queue, bp); 133839213Sgibbs 133939213Sgibbs splx(s); 134039213Sgibbs 134139213Sgibbs /* 134239213Sgibbs * Schedule ourselves for performing the work. We do things 134339213Sgibbs * differently for changers. 134439213Sgibbs */ 134539213Sgibbs if ((softc->flags & CD_FLAG_CHANGER) == 0) 134639213Sgibbs xpt_schedule(periph, /* XXX priority */1); 134739213Sgibbs else 134839213Sgibbs cdschedule(periph, /* priority */ 1); 134939213Sgibbs 135039213Sgibbs return; 135139213Sgibbs} 135239213Sgibbs 135339213Sgibbsstatic void 135439213Sgibbscdstart(struct cam_periph *periph, union ccb *start_ccb) 135539213Sgibbs{ 135639213Sgibbs struct cd_softc *softc; 135759249Sphk struct bio *bp; 135839213Sgibbs struct ccb_scsiio *csio; 135939213Sgibbs struct scsi_read_capacity_data *rcap; 136039213Sgibbs int s; 136139213Sgibbs 136239213Sgibbs softc = (struct cd_softc *)periph->softc; 136339213Sgibbs 136439213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdstart\n")); 136539213Sgibbs 136639213Sgibbs switch (softc->state) { 136739213Sgibbs case CD_STATE_NORMAL: 136839213Sgibbs { 136939213Sgibbs int oldspl; 137039213Sgibbs 137139213Sgibbs s = splbio(); 137259249Sphk bp = bioq_first(&softc->bio_queue); 137339213Sgibbs if (periph->immediate_priority <= periph->pinfo.priority) { 137439213Sgibbs start_ccb->ccb_h.ccb_state = CD_CCB_WAITING; 137539213Sgibbs 137639213Sgibbs SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, 137739213Sgibbs periph_links.sle); 137839213Sgibbs periph->immediate_priority = CAM_PRIORITY_NONE; 137939213Sgibbs splx(s); 138039213Sgibbs wakeup(&periph->ccb_list); 138139213Sgibbs } else if (bp == NULL) { 138239213Sgibbs splx(s); 138339213Sgibbs xpt_release_ccb(start_ccb); 138439213Sgibbs } else { 138559249Sphk bioq_remove(&softc->bio_queue, bp); 138639213Sgibbs 138739213Sgibbs devstat_start_transaction(&softc->device_stats); 138839213Sgibbs 138939213Sgibbs scsi_read_write(&start_ccb->csio, 139039213Sgibbs /*retries*/4, 139139213Sgibbs /* cbfcnp */ cddone, 139291062Sphk MSG_SIMPLE_Q_TAG, 139359249Sphk /* read */bp->bio_cmd == BIO_READ, 139439213Sgibbs /* byte2 */ 0, 139539213Sgibbs /* minimum_cmd_size */ 10, 1396104611Sphk /* lba */ bp->bio_blkno / 1397104611Sphk (softc->params.blksize / DEV_BSIZE), 139859249Sphk bp->bio_bcount / softc->params.blksize, 139959249Sphk /* data_ptr */ bp->bio_data, 140059249Sphk /* dxfer_len */ bp->bio_bcount, 140139213Sgibbs /* sense_len */ SSD_FULL_SIZE, 140239213Sgibbs /* timeout */ 30000); 140339213Sgibbs start_ccb->ccb_h.ccb_state = CD_CCB_BUFFER_IO; 140439213Sgibbs 140539213Sgibbs 140639213Sgibbs /* 140739213Sgibbs * Block out any asyncronous callbacks 140839213Sgibbs * while we touch the pending ccb list. 140939213Sgibbs */ 141039213Sgibbs oldspl = splcam(); 141139213Sgibbs LIST_INSERT_HEAD(&softc->pending_ccbs, 141239213Sgibbs &start_ccb->ccb_h, periph_links.le); 141339213Sgibbs splx(oldspl); 141439213Sgibbs 141539213Sgibbs /* We expect a unit attention from this device */ 141639213Sgibbs if ((softc->flags & CD_FLAG_RETRY_UA) != 0) { 141739213Sgibbs start_ccb->ccb_h.ccb_state |= CD_CCB_RETRY_UA; 141839213Sgibbs softc->flags &= ~CD_FLAG_RETRY_UA; 141939213Sgibbs } 142039213Sgibbs 142139213Sgibbs start_ccb->ccb_h.ccb_bp = bp; 142259249Sphk bp = bioq_first(&softc->bio_queue); 142339213Sgibbs splx(s); 142439213Sgibbs 142539213Sgibbs xpt_action(start_ccb); 142639213Sgibbs } 142739213Sgibbs if (bp != NULL) { 142839213Sgibbs /* Have more work to do, so ensure we stay scheduled */ 142939213Sgibbs xpt_schedule(periph, /* XXX priority */1); 143039213Sgibbs } 143139213Sgibbs break; 143239213Sgibbs } 143339213Sgibbs case CD_STATE_PROBE: 143439213Sgibbs { 143539213Sgibbs 143639213Sgibbs rcap = (struct scsi_read_capacity_data *)malloc(sizeof(*rcap), 143739213Sgibbs M_TEMP, 143839213Sgibbs M_NOWAIT); 143939213Sgibbs if (rcap == NULL) { 144039213Sgibbs xpt_print_path(periph->path); 144139213Sgibbs printf("cdstart: Couldn't malloc read_capacity data\n"); 144239213Sgibbs /* cd_free_periph??? */ 144339213Sgibbs break; 144439213Sgibbs } 144539213Sgibbs csio = &start_ccb->csio; 144639213Sgibbs scsi_read_capacity(csio, 144739213Sgibbs /*retries*/1, 144839213Sgibbs cddone, 144939213Sgibbs MSG_SIMPLE_Q_TAG, 145039213Sgibbs rcap, 145139213Sgibbs SSD_FULL_SIZE, 145239213Sgibbs /*timeout*/20000); 145339213Sgibbs start_ccb->ccb_h.ccb_bp = NULL; 145439213Sgibbs start_ccb->ccb_h.ccb_state = CD_CCB_PROBE; 145539213Sgibbs xpt_action(start_ccb); 145639213Sgibbs break; 145739213Sgibbs } 145839213Sgibbs } 145939213Sgibbs} 146039213Sgibbs 146139213Sgibbsstatic void 146239213Sgibbscddone(struct cam_periph *periph, union ccb *done_ccb) 146339213Sgibbs{ 146439213Sgibbs struct cd_softc *softc; 146539213Sgibbs struct ccb_scsiio *csio; 146639213Sgibbs 146739213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cddone\n")); 146839213Sgibbs 146939213Sgibbs softc = (struct cd_softc *)periph->softc; 147039213Sgibbs csio = &done_ccb->csio; 147139213Sgibbs 147239213Sgibbs switch (csio->ccb_h.ccb_state & CD_CCB_TYPE_MASK) { 147339213Sgibbs case CD_CCB_BUFFER_IO: 147439213Sgibbs { 147559249Sphk struct bio *bp; 147639213Sgibbs int error; 147739213Sgibbs int oldspl; 147839213Sgibbs 147959249Sphk bp = (struct bio *)done_ccb->ccb_h.ccb_bp; 148039213Sgibbs error = 0; 148139213Sgibbs 148239213Sgibbs if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 148339213Sgibbs int sf; 148439213Sgibbs 148539213Sgibbs if ((done_ccb->ccb_h.ccb_state & CD_CCB_RETRY_UA) != 0) 148639213Sgibbs sf = SF_RETRY_UA; 148739213Sgibbs else 148839213Sgibbs sf = 0; 148946747Sken 149074840Sken error = cderror(done_ccb, CAM_RETRY_SELTO, sf); 149174840Sken if (error == ERESTART) { 149239213Sgibbs /* 149339213Sgibbs * A retry was scheuled, so 149439213Sgibbs * just return. 149539213Sgibbs */ 149639213Sgibbs return; 149739213Sgibbs } 149839213Sgibbs } 149939213Sgibbs 150039213Sgibbs if (error != 0) { 150139213Sgibbs int s; 150259249Sphk struct bio *q_bp; 150339213Sgibbs 150439213Sgibbs xpt_print_path(periph->path); 150539213Sgibbs printf("cddone: got error %#x back\n", error); 150639213Sgibbs s = splbio(); 150759249Sphk while ((q_bp = bioq_first(&softc->bio_queue)) != NULL) { 150859249Sphk bioq_remove(&softc->bio_queue, q_bp); 150959249Sphk q_bp->bio_resid = q_bp->bio_bcount; 151076322Sphk biofinish(q_bp, NULL, EIO); 151139213Sgibbs } 151239213Sgibbs splx(s); 151359249Sphk bp->bio_resid = bp->bio_bcount; 151459249Sphk bp->bio_error = error; 151559249Sphk bp->bio_flags |= BIO_ERROR; 151639213Sgibbs cam_release_devq(done_ccb->ccb_h.path, 151739213Sgibbs /*relsim_flags*/0, 151839213Sgibbs /*reduction*/0, 151939213Sgibbs /*timeout*/0, 152039213Sgibbs /*getcount_only*/0); 152139213Sgibbs 152239213Sgibbs } else { 152359249Sphk bp->bio_resid = csio->resid; 152459249Sphk bp->bio_error = 0; 152559249Sphk if (bp->bio_resid != 0) { 1526104456Sphk /* 1527104456Sphk * Short transfer ??? 1528104456Sphk * XXX: not sure this is correct for partial 1529104456Sphk * transfers at EOM 1530104456Sphk */ 153159249Sphk bp->bio_flags |= BIO_ERROR; 153239213Sgibbs } 153339213Sgibbs } 153439213Sgibbs 153539213Sgibbs /* 153639213Sgibbs * Block out any asyncronous callbacks 153739213Sgibbs * while we touch the pending ccb list. 153839213Sgibbs */ 153939213Sgibbs oldspl = splcam(); 154039213Sgibbs LIST_REMOVE(&done_ccb->ccb_h, periph_links.le); 154139213Sgibbs splx(oldspl); 154239213Sgibbs 154339213Sgibbs if (softc->flags & CD_FLAG_CHANGER) 154439213Sgibbs cdchangerschedule(softc); 154539213Sgibbs 154676322Sphk biofinish(bp, &softc->device_stats, 0); 154739213Sgibbs break; 154839213Sgibbs } 154939213Sgibbs case CD_CCB_PROBE: 155039213Sgibbs { 155139213Sgibbs struct scsi_read_capacity_data *rdcap; 155239213Sgibbs char announce_buf[120]; /* 155339213Sgibbs * Currently (9/30/97) the 155439213Sgibbs * longest possible announce 155539213Sgibbs * buffer is 108 bytes, for the 155639213Sgibbs * first error case below. 155739213Sgibbs * That is 39 bytes for the 155839213Sgibbs * basic string, 16 bytes for the 155939213Sgibbs * biggest sense key (hardware 156039213Sgibbs * error), 52 bytes for the 156139213Sgibbs * text of the largest sense 156239213Sgibbs * qualifier valid for a CDROM, 156339213Sgibbs * (0x72, 0x03 or 0x04, 156439213Sgibbs * 0x03), and one byte for the 156539213Sgibbs * null terminating character. 156639213Sgibbs * To allow for longer strings, 156739213Sgibbs * the announce buffer is 120 156839213Sgibbs * bytes. 156939213Sgibbs */ 157039213Sgibbs struct cd_params *cdp; 157139213Sgibbs 157239213Sgibbs cdp = &softc->params; 157339213Sgibbs 157439213Sgibbs rdcap = (struct scsi_read_capacity_data *)csio->data_ptr; 157539213Sgibbs 157639213Sgibbs cdp->disksize = scsi_4btoul (rdcap->addr) + 1; 157739213Sgibbs cdp->blksize = scsi_4btoul (rdcap->length); 157839213Sgibbs 157939213Sgibbs if ((csio->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 158039213Sgibbs 158141514Sarchie snprintf(announce_buf, sizeof(announce_buf), 158240020Sken "cd present [%lu x %lu byte records]", 158340020Sken cdp->disksize, (u_long)cdp->blksize); 158439213Sgibbs 158539213Sgibbs } else { 158639213Sgibbs int error; 158739213Sgibbs /* 158839213Sgibbs * Retry any UNIT ATTENTION type errors. They 158939213Sgibbs * are expected at boot. 159039213Sgibbs */ 159174840Sken error = cderror(done_ccb, CAM_RETRY_SELTO, 159274840Sken SF_RETRY_UA | SF_NO_PRINT); 159339213Sgibbs if (error == ERESTART) { 159439213Sgibbs /* 159539213Sgibbs * A retry was scheuled, so 159639213Sgibbs * just return. 159739213Sgibbs */ 159839213Sgibbs return; 159939213Sgibbs } else if (error != 0) { 160039213Sgibbs 160139213Sgibbs struct scsi_sense_data *sense; 160239213Sgibbs int asc, ascq; 160339213Sgibbs int sense_key, error_code; 160439213Sgibbs int have_sense; 160539213Sgibbs cam_status status; 160639213Sgibbs struct ccb_getdev cgd; 160739213Sgibbs 160839213Sgibbs /* Don't wedge this device's queue */ 160939213Sgibbs cam_release_devq(done_ccb->ccb_h.path, 161039213Sgibbs /*relsim_flags*/0, 161139213Sgibbs /*reduction*/0, 161239213Sgibbs /*timeout*/0, 161339213Sgibbs /*getcount_only*/0); 161439213Sgibbs 161539213Sgibbs status = done_ccb->ccb_h.status; 161639213Sgibbs 161739213Sgibbs xpt_setup_ccb(&cgd.ccb_h, 161839213Sgibbs done_ccb->ccb_h.path, 161939213Sgibbs /* priority */ 1); 162039213Sgibbs cgd.ccb_h.func_code = XPT_GDEV_TYPE; 162139213Sgibbs xpt_action((union ccb *)&cgd); 162239213Sgibbs 162339213Sgibbs if (((csio->ccb_h.flags & CAM_SENSE_PHYS) != 0) 162439213Sgibbs || ((csio->ccb_h.flags & CAM_SENSE_PTR) != 0) 162539213Sgibbs || ((status & CAM_AUTOSNS_VALID) == 0)) 162639213Sgibbs have_sense = FALSE; 162739213Sgibbs else 162839213Sgibbs have_sense = TRUE; 162939213Sgibbs 163039213Sgibbs if (have_sense) { 163139213Sgibbs sense = &csio->sense_data; 163239213Sgibbs scsi_extract_sense(sense, &error_code, 163339213Sgibbs &sense_key, 163439213Sgibbs &asc, &ascq); 163539213Sgibbs } 163639213Sgibbs /* 163746581Sken * Attach to anything that claims to be a 163846581Sken * CDROM or WORM device, as long as it 163946581Sken * doesn't return a "Logical unit not 164046581Sken * supported" (0x25) error. 164139213Sgibbs */ 164246581Sken if ((have_sense) && (asc != 0x25) 164374840Sken && (error_code == SSD_CURRENT_ERROR)) { 164474840Sken const char *sense_key_desc; 164574840Sken const char *asc_desc; 164674840Sken 164774840Sken scsi_sense_desc(sense_key, asc, ascq, 164874840Sken &cgd.inq_data, 164974840Sken &sense_key_desc, 165074840Sken &asc_desc); 165141514Sarchie snprintf(announce_buf, 165241514Sarchie sizeof(announce_buf), 165339213Sgibbs "Attempt to query device " 165439213Sgibbs "size failed: %s, %s", 165574840Sken sense_key_desc, 165674840Sken asc_desc); 165782850Sken } else if ((have_sense == 0) 165882850Sken && ((status & CAM_STATUS_MASK) == 165982850Sken CAM_SCSI_STATUS_ERROR) 166082850Sken && (csio->scsi_status == 166182850Sken SCSI_STATUS_BUSY)) { 166282850Sken snprintf(announce_buf, 166382850Sken sizeof(announce_buf), 166482850Sken "Attempt to query device " 166582850Sken "size failed: SCSI Status: %s", 166682850Sken scsi_status_string(csio)); 166774840Sken } else if (SID_TYPE(&cgd.inq_data) == T_CDROM) { 166839213Sgibbs /* 166939213Sgibbs * We only print out an error for 167039213Sgibbs * CDROM type devices. For WORM 167139213Sgibbs * devices, we don't print out an 167239213Sgibbs * error since a few WORM devices 167339213Sgibbs * don't support CDROM commands. 167439213Sgibbs * If we have sense information, go 167539213Sgibbs * ahead and print it out. 167639213Sgibbs * Otherwise, just say that we 167739213Sgibbs * couldn't attach. 167839213Sgibbs */ 167939213Sgibbs 168039213Sgibbs /* 168139213Sgibbs * Just print out the error, not 168239213Sgibbs * the full probe message, when we 168339213Sgibbs * don't attach. 168439213Sgibbs */ 168540020Sken if (have_sense) 168640020Sken scsi_sense_print( 168740020Sken &done_ccb->csio); 168840020Sken else { 168940020Sken xpt_print_path(periph->path); 169040020Sken printf("got CAM status %#x\n", 169140020Sken done_ccb->ccb_h.status); 169240020Sken } 169340020Sken xpt_print_path(periph->path); 169440020Sken printf("fatal error, failed" 169540603Sken " to attach to device\n"); 169639213Sgibbs 169739213Sgibbs /* 169840603Sken * Invalidate this peripheral. 169939213Sgibbs */ 170039213Sgibbs cam_periph_invalidate(periph); 170140020Sken 170240020Sken announce_buf[0] = '\0'; 170339213Sgibbs } else { 170440603Sken 170539213Sgibbs /* 170640603Sken * Invalidate this peripheral. 170739213Sgibbs */ 170839213Sgibbs cam_periph_invalidate(periph); 170940020Sken announce_buf[0] = '\0'; 171039213Sgibbs } 171139213Sgibbs } 171239213Sgibbs } 171339213Sgibbs free(rdcap, M_TEMP); 171442378Smjacob if (announce_buf[0] != '\0') { 171539213Sgibbs xpt_announce_periph(periph, announce_buf); 171642378Smjacob if (softc->flags & CD_FLAG_CHANGER) 171742378Smjacob cdchangerschedule(softc); 171842378Smjacob } 171940020Sken softc->state = CD_STATE_NORMAL; 172042378Smjacob /* 172142378Smjacob * Since our peripheral may be invalidated by an error 172242378Smjacob * above or an external event, we must release our CCB 172342378Smjacob * before releasing the probe lock on the peripheral. 172442378Smjacob * The peripheral will only go away once the last lock 172542378Smjacob * is removed, and we need it around for the CCB release 172642378Smjacob * operation. 172742378Smjacob */ 172842378Smjacob xpt_release_ccb(done_ccb); 172940020Sken cam_periph_unlock(periph); 173042378Smjacob return; 173139213Sgibbs } 173239213Sgibbs case CD_CCB_WAITING: 173339213Sgibbs { 173439213Sgibbs /* Caller will release the CCB */ 173539213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, 173639213Sgibbs ("trying to wakeup ccbwait\n")); 173739213Sgibbs 173839213Sgibbs wakeup(&done_ccb->ccb_h.cbfcnp); 173939213Sgibbs return; 174039213Sgibbs } 174142378Smjacob default: 174242378Smjacob break; 174339213Sgibbs } 174439213Sgibbs xpt_release_ccb(done_ccb); 174539213Sgibbs} 174639213Sgibbs 174739213Sgibbsstatic int 174883366Sjuliancdioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct thread *td) 174939213Sgibbs{ 175039213Sgibbs 175139213Sgibbs struct cam_periph *periph; 175239213Sgibbs struct cd_softc *softc; 1753101940Snjl int error; 175439213Sgibbs 1755101940Snjl periph = (struct cam_periph *)dev->si_drv1; 175639213Sgibbs if (periph == NULL) 175739213Sgibbs return(ENXIO); 175839213Sgibbs 175939213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdioctl\n")); 176039213Sgibbs 176139213Sgibbs softc = (struct cd_softc *)periph->softc; 176239213Sgibbs 176339213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, 176440020Sken ("trying to do ioctl %#lx\n", cmd)); 176539213Sgibbs 176640020Sken error = cam_periph_lock(periph, PRIBIO | PCATCH); 176739213Sgibbs 176840020Sken if (error != 0) 176940020Sken return(error); 177040020Sken 177139213Sgibbs switch (cmd) { 177239213Sgibbs 1773104456Sphk case DIOCGMEDIASIZE: 1774104456Sphk *(off_t *)addr = 1775104456Sphk (off_t)softc->params.blksize * softc->params.disksize; 1776104456Sphk break; 1777104456Sphk case DIOCGSECTORSIZE: 1778104456Sphk *(u_int *)addr = softc->params.blksize; 1779104456Sphk break; 1780104456Sphk 178139213Sgibbs case CDIOCPLAYTRACKS: 178239213Sgibbs { 178339213Sgibbs struct ioc_play_track *args 178439213Sgibbs = (struct ioc_play_track *) addr; 178539213Sgibbs struct cd_mode_data *data; 178639213Sgibbs 178739213Sgibbs data = malloc(sizeof(struct cd_mode_data), M_TEMP, 178839213Sgibbs M_WAITOK); 178939213Sgibbs 179039213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 179139213Sgibbs ("trying to do CDIOCPLAYTRACKS\n")); 179239213Sgibbs 179339213Sgibbs error = cdgetmode(periph, data, AUDIO_PAGE); 179439213Sgibbs if (error) { 179539213Sgibbs free(data, M_TEMP); 179639213Sgibbs break; 179739213Sgibbs } 179839213Sgibbs data->page.audio.flags &= ~CD_PA_SOTC; 179939213Sgibbs data->page.audio.flags |= CD_PA_IMMED; 180039213Sgibbs error = cdsetmode(periph, data); 180139213Sgibbs free(data, M_TEMP); 180239213Sgibbs if (error) 180339213Sgibbs break; 180439213Sgibbs if (softc->quirks & CD_Q_BCD_TRACKS) { 180539213Sgibbs args->start_track = bin2bcd(args->start_track); 180639213Sgibbs args->end_track = bin2bcd(args->end_track); 180739213Sgibbs } 180839213Sgibbs error = cdplaytracks(periph, 180939213Sgibbs args->start_track, 181039213Sgibbs args->start_index, 181139213Sgibbs args->end_track, 181239213Sgibbs args->end_index); 181339213Sgibbs } 181439213Sgibbs break; 181539213Sgibbs case CDIOCPLAYMSF: 181639213Sgibbs { 181739213Sgibbs struct ioc_play_msf *args 181839213Sgibbs = (struct ioc_play_msf *) addr; 181939213Sgibbs struct cd_mode_data *data; 182039213Sgibbs 182139213Sgibbs data = malloc(sizeof(struct cd_mode_data), M_TEMP, 182239213Sgibbs M_WAITOK); 182339213Sgibbs 182439213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 182539213Sgibbs ("trying to do CDIOCPLAYMSF\n")); 182639213Sgibbs 182739213Sgibbs error = cdgetmode(periph, data, AUDIO_PAGE); 182839213Sgibbs if (error) { 182939213Sgibbs free(data, M_TEMP); 183039213Sgibbs break; 183139213Sgibbs } 183239213Sgibbs data->page.audio.flags &= ~CD_PA_SOTC; 183339213Sgibbs data->page.audio.flags |= CD_PA_IMMED; 183439213Sgibbs error = cdsetmode(periph, data); 183539213Sgibbs free(data, M_TEMP); 183639213Sgibbs if (error) 183739213Sgibbs break; 183839213Sgibbs error = cdplaymsf(periph, 183939213Sgibbs args->start_m, 184039213Sgibbs args->start_s, 184139213Sgibbs args->start_f, 184239213Sgibbs args->end_m, 184339213Sgibbs args->end_s, 184439213Sgibbs args->end_f); 184539213Sgibbs } 184639213Sgibbs break; 184739213Sgibbs case CDIOCPLAYBLOCKS: 184839213Sgibbs { 184939213Sgibbs struct ioc_play_blocks *args 185039213Sgibbs = (struct ioc_play_blocks *) addr; 185139213Sgibbs struct cd_mode_data *data; 185239213Sgibbs 185339213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 185439213Sgibbs ("trying to do CDIOCPLAYBLOCKS\n")); 185539213Sgibbs 185639213Sgibbs data = malloc(sizeof(struct cd_mode_data), M_TEMP, 185739213Sgibbs M_WAITOK); 185839213Sgibbs 185939213Sgibbs error = cdgetmode(periph, data, AUDIO_PAGE); 186039213Sgibbs if (error) { 186139213Sgibbs free(data, M_TEMP); 186239213Sgibbs break; 186339213Sgibbs } 186439213Sgibbs data->page.audio.flags &= ~CD_PA_SOTC; 186539213Sgibbs data->page.audio.flags |= CD_PA_IMMED; 186639213Sgibbs error = cdsetmode(periph, data); 186739213Sgibbs free(data, M_TEMP); 186839213Sgibbs if (error) 186939213Sgibbs break; 187039213Sgibbs error = cdplay(periph, args->blk, args->len); 187139213Sgibbs } 187239213Sgibbs break; 187339213Sgibbs case CDIOCREADSUBCHANNEL: 187439213Sgibbs { 187539213Sgibbs struct ioc_read_subchannel *args 187639213Sgibbs = (struct ioc_read_subchannel *) addr; 187739213Sgibbs struct cd_sub_channel_info *data; 187839213Sgibbs u_int32_t len = args->data_len; 187939213Sgibbs 188039213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 188139213Sgibbs ("trying to do CDIOCREADSUBCHANNEL\n")); 188239213Sgibbs 188339213Sgibbs data = malloc(sizeof(struct cd_sub_channel_info), 188439213Sgibbs M_TEMP, M_WAITOK); 188539213Sgibbs 188639213Sgibbs if ((len > sizeof(struct cd_sub_channel_info)) || 188739213Sgibbs (len < sizeof(struct cd_sub_channel_header))) { 188839213Sgibbs printf( 188939213Sgibbs "scsi_cd: cdioctl: " 189039213Sgibbs "cdioreadsubchannel: error, len=%d\n", 189139213Sgibbs len); 189239213Sgibbs error = EINVAL; 189339213Sgibbs free(data, M_TEMP); 189439213Sgibbs break; 189539213Sgibbs } 189639213Sgibbs 189739213Sgibbs if (softc->quirks & CD_Q_BCD_TRACKS) 189839213Sgibbs args->track = bin2bcd(args->track); 189939213Sgibbs 190039213Sgibbs error = cdreadsubchannel(periph, args->address_format, 190139213Sgibbs args->data_format, args->track, data, len); 190239213Sgibbs 190339213Sgibbs if (error) { 190439213Sgibbs free(data, M_TEMP); 190539213Sgibbs break; 190639213Sgibbs } 190739213Sgibbs if (softc->quirks & CD_Q_BCD_TRACKS) 190839213Sgibbs data->what.track_info.track_number = 190939213Sgibbs bcd2bin(data->what.track_info.track_number); 191039213Sgibbs len = min(len, ((data->header.data_len[0] << 8) + 191139213Sgibbs data->header.data_len[1] + 191239213Sgibbs sizeof(struct cd_sub_channel_header))); 191339213Sgibbs if (copyout(data, args->data, len) != 0) { 191439213Sgibbs error = EFAULT; 191539213Sgibbs } 191639213Sgibbs free(data, M_TEMP); 191739213Sgibbs } 191839213Sgibbs break; 191939213Sgibbs 192039213Sgibbs case CDIOREADTOCHEADER: 192139213Sgibbs { 192239213Sgibbs struct ioc_toc_header *th; 192339213Sgibbs 192439213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 192539213Sgibbs ("trying to do CDIOREADTOCHEADER\n")); 192639213Sgibbs 192739213Sgibbs th = malloc(sizeof(struct ioc_toc_header), M_TEMP, 192839213Sgibbs M_WAITOK); 192939213Sgibbs error = cdreadtoc(periph, 0, 0, 193039213Sgibbs (struct cd_toc_entry *)th, 193139213Sgibbs sizeof (*th)); 193239213Sgibbs if (error) { 193339213Sgibbs free(th, M_TEMP); 193439213Sgibbs break; 193539213Sgibbs } 193639213Sgibbs if (softc->quirks & CD_Q_BCD_TRACKS) { 193739213Sgibbs /* we are going to have to convert the BCD 193839213Sgibbs * encoding on the cd to what is expected 193939213Sgibbs */ 194039213Sgibbs th->starting_track = 194139213Sgibbs bcd2bin(th->starting_track); 194239213Sgibbs th->ending_track = bcd2bin(th->ending_track); 194339213Sgibbs } 194490868Smike th->len = ntohs(th->len); 194539213Sgibbs bcopy(th, addr, sizeof(*th)); 194639213Sgibbs free(th, M_TEMP); 194739213Sgibbs } 194839213Sgibbs break; 194939213Sgibbs case CDIOREADTOCENTRYS: 195039213Sgibbs { 195139213Sgibbs typedef struct { 195239213Sgibbs struct ioc_toc_header header; 195339213Sgibbs struct cd_toc_entry entries[100]; 195439213Sgibbs } data_t; 195539213Sgibbs typedef struct { 195639213Sgibbs struct ioc_toc_header header; 195739213Sgibbs struct cd_toc_entry entry; 195839213Sgibbs } lead_t; 195939213Sgibbs 196039213Sgibbs data_t *data; 196139213Sgibbs lead_t *lead; 196239213Sgibbs struct ioc_read_toc_entry *te = 196339213Sgibbs (struct ioc_read_toc_entry *) addr; 196439213Sgibbs struct ioc_toc_header *th; 196539213Sgibbs u_int32_t len, readlen, idx, num; 196639213Sgibbs u_int32_t starting_track = te->starting_track; 196739213Sgibbs 196839213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 196939213Sgibbs ("trying to do CDIOREADTOCENTRYS\n")); 197039213Sgibbs 197139213Sgibbs data = malloc(sizeof(data_t), M_TEMP, M_WAITOK); 197239213Sgibbs lead = malloc(sizeof(lead_t), M_TEMP, M_WAITOK); 197339213Sgibbs 197439213Sgibbs if (te->data_len < sizeof(struct cd_toc_entry) 197539213Sgibbs || (te->data_len % sizeof(struct cd_toc_entry)) != 0 197639213Sgibbs || (te->address_format != CD_MSF_FORMAT 197739213Sgibbs && te->address_format != CD_LBA_FORMAT)) { 197839213Sgibbs error = EINVAL; 197939213Sgibbs printf("scsi_cd: error in readtocentries, " 198039213Sgibbs "returning EINVAL\n"); 198139213Sgibbs free(data, M_TEMP); 198239213Sgibbs free(lead, M_TEMP); 198339213Sgibbs break; 198439213Sgibbs } 198539213Sgibbs 198639213Sgibbs th = &data->header; 198739213Sgibbs error = cdreadtoc(periph, 0, 0, 198839213Sgibbs (struct cd_toc_entry *)th, 198939213Sgibbs sizeof (*th)); 199039213Sgibbs if (error) { 199139213Sgibbs free(data, M_TEMP); 199239213Sgibbs free(lead, M_TEMP); 199339213Sgibbs break; 199439213Sgibbs } 199539213Sgibbs 199639213Sgibbs if (softc->quirks & CD_Q_BCD_TRACKS) { 199739213Sgibbs /* we are going to have to convert the BCD 199839213Sgibbs * encoding on the cd to what is expected 199939213Sgibbs */ 200039213Sgibbs th->starting_track = 200139213Sgibbs bcd2bin(th->starting_track); 200239213Sgibbs th->ending_track = bcd2bin(th->ending_track); 200339213Sgibbs } 200439213Sgibbs 200539213Sgibbs if (starting_track == 0) 200639213Sgibbs starting_track = th->starting_track; 200739213Sgibbs else if (starting_track == LEADOUT) 200839213Sgibbs starting_track = th->ending_track + 1; 200939213Sgibbs else if (starting_track < th->starting_track || 201039213Sgibbs starting_track > th->ending_track + 1) { 201139213Sgibbs printf("scsi_cd: error in readtocentries, " 201239213Sgibbs "returning EINVAL\n"); 201339213Sgibbs free(data, M_TEMP); 201439213Sgibbs free(lead, M_TEMP); 201539213Sgibbs error = EINVAL; 201639213Sgibbs break; 201739213Sgibbs } 201839213Sgibbs 201939213Sgibbs /* calculate reading length without leadout entry */ 202039213Sgibbs readlen = (th->ending_track - starting_track + 1) * 202139213Sgibbs sizeof(struct cd_toc_entry); 202239213Sgibbs 202339213Sgibbs /* and with leadout entry */ 202439213Sgibbs len = readlen + sizeof(struct cd_toc_entry); 202539213Sgibbs if (te->data_len < len) { 202639213Sgibbs len = te->data_len; 202739213Sgibbs if (readlen > len) 202839213Sgibbs readlen = len; 202939213Sgibbs } 203039213Sgibbs if (len > sizeof(data->entries)) { 203139213Sgibbs printf("scsi_cd: error in readtocentries, " 203239213Sgibbs "returning EINVAL\n"); 203339213Sgibbs error = EINVAL; 203439213Sgibbs free(data, M_TEMP); 203539213Sgibbs free(lead, M_TEMP); 203639213Sgibbs break; 203739213Sgibbs } 203839213Sgibbs num = len / sizeof(struct cd_toc_entry); 203939213Sgibbs 204039213Sgibbs if (readlen > 0) { 204139213Sgibbs error = cdreadtoc(periph, te->address_format, 204239213Sgibbs starting_track, 204339213Sgibbs (struct cd_toc_entry *)data, 204439213Sgibbs readlen + sizeof (*th)); 204539213Sgibbs if (error) { 204639213Sgibbs free(data, M_TEMP); 204739213Sgibbs free(lead, M_TEMP); 204839213Sgibbs break; 204939213Sgibbs } 205039213Sgibbs } 205139213Sgibbs 205239213Sgibbs /* make leadout entry if needed */ 205339213Sgibbs idx = starting_track + num - 1; 205439213Sgibbs if (softc->quirks & CD_Q_BCD_TRACKS) 205539213Sgibbs th->ending_track = bcd2bin(th->ending_track); 205639213Sgibbs if (idx == th->ending_track + 1) { 205739213Sgibbs error = cdreadtoc(periph, te->address_format, 205839213Sgibbs LEADOUT, 205939213Sgibbs (struct cd_toc_entry *)lead, 206039213Sgibbs sizeof(*lead)); 206139213Sgibbs if (error) { 206239213Sgibbs free(data, M_TEMP); 206339213Sgibbs free(lead, M_TEMP); 206439213Sgibbs break; 206539213Sgibbs } 206639213Sgibbs data->entries[idx - starting_track] = 206739213Sgibbs lead->entry; 206839213Sgibbs } 206939213Sgibbs if (softc->quirks & CD_Q_BCD_TRACKS) { 207039213Sgibbs for (idx = 0; idx < num - 1; idx++) { 207139213Sgibbs data->entries[idx].track = 207239213Sgibbs bcd2bin(data->entries[idx].track); 207339213Sgibbs } 207439213Sgibbs } 207539213Sgibbs 207639213Sgibbs error = copyout(data->entries, te->data, len); 207739213Sgibbs free(data, M_TEMP); 207839213Sgibbs free(lead, M_TEMP); 207939213Sgibbs } 208039213Sgibbs break; 208139213Sgibbs case CDIOREADTOCENTRY: 208239213Sgibbs { 208339213Sgibbs /* yeah yeah, this is ugly */ 208439213Sgibbs typedef struct { 208539213Sgibbs struct ioc_toc_header header; 208639213Sgibbs struct cd_toc_entry entry; 208739213Sgibbs } data_t; 208839213Sgibbs 208939213Sgibbs data_t *data; 209039213Sgibbs struct ioc_read_toc_single_entry *te = 209139213Sgibbs (struct ioc_read_toc_single_entry *) addr; 209239213Sgibbs struct ioc_toc_header *th; 209339213Sgibbs u_int32_t track; 209439213Sgibbs 209539213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 209639213Sgibbs ("trying to do CDIOREADTOCENTRY\n")); 209739213Sgibbs 209839213Sgibbs data = malloc(sizeof(data_t), M_TEMP, M_WAITOK); 209939213Sgibbs 210039213Sgibbs if (te->address_format != CD_MSF_FORMAT 210139213Sgibbs && te->address_format != CD_LBA_FORMAT) { 210239213Sgibbs printf("error in readtocentry, " 210339213Sgibbs " returning EINVAL\n"); 210439213Sgibbs free(data, M_TEMP); 210539213Sgibbs error = EINVAL; 210639213Sgibbs break; 210739213Sgibbs } 210839213Sgibbs 210939213Sgibbs th = &data->header; 211039213Sgibbs error = cdreadtoc(periph, 0, 0, 211139213Sgibbs (struct cd_toc_entry *)th, 211239213Sgibbs sizeof (*th)); 211339213Sgibbs if (error) { 211439213Sgibbs free(data, M_TEMP); 211539213Sgibbs break; 211639213Sgibbs } 211739213Sgibbs 211839213Sgibbs if (softc->quirks & CD_Q_BCD_TRACKS) { 211939213Sgibbs /* we are going to have to convert the BCD 212039213Sgibbs * encoding on the cd to what is expected 212139213Sgibbs */ 212239213Sgibbs th->starting_track = 212339213Sgibbs bcd2bin(th->starting_track); 212439213Sgibbs th->ending_track = bcd2bin(th->ending_track); 212539213Sgibbs } 212639213Sgibbs track = te->track; 212739213Sgibbs if (track == 0) 212839213Sgibbs track = th->starting_track; 212939213Sgibbs else if (track == LEADOUT) 213039213Sgibbs /* OK */; 213139213Sgibbs else if (track < th->starting_track || 213239213Sgibbs track > th->ending_track + 1) { 213339213Sgibbs printf("error in readtocentry, " 213439213Sgibbs " returning EINVAL\n"); 213539213Sgibbs free(data, M_TEMP); 213639213Sgibbs error = EINVAL; 213739213Sgibbs break; 213839213Sgibbs } 213939213Sgibbs 214039213Sgibbs error = cdreadtoc(periph, te->address_format, track, 214139213Sgibbs (struct cd_toc_entry *)data, 214239213Sgibbs sizeof(data_t)); 214339213Sgibbs if (error) { 214439213Sgibbs free(data, M_TEMP); 214539213Sgibbs break; 214639213Sgibbs } 214739213Sgibbs 214839213Sgibbs if (softc->quirks & CD_Q_BCD_TRACKS) 214939213Sgibbs data->entry.track = bcd2bin(data->entry.track); 215039213Sgibbs bcopy(&data->entry, &te->entry, 215139213Sgibbs sizeof(struct cd_toc_entry)); 215239213Sgibbs free(data, M_TEMP); 215339213Sgibbs } 215439213Sgibbs break; 215539213Sgibbs case CDIOCSETPATCH: 215639213Sgibbs { 215739213Sgibbs struct ioc_patch *arg = (struct ioc_patch *) addr; 215839213Sgibbs struct cd_mode_data *data; 215939213Sgibbs 216039213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 216139213Sgibbs ("trying to do CDIOCSETPATCH\n")); 216239213Sgibbs 216339213Sgibbs data = malloc(sizeof(struct cd_mode_data), M_TEMP, 216439213Sgibbs M_WAITOK); 216539213Sgibbs error = cdgetmode(periph, data, AUDIO_PAGE); 216639213Sgibbs if (error) { 216739213Sgibbs free(data, M_TEMP); 216839213Sgibbs break; 216939213Sgibbs } 217039213Sgibbs data->page.audio.port[LEFT_PORT].channels = 217139213Sgibbs arg->patch[0]; 217239213Sgibbs data->page.audio.port[RIGHT_PORT].channels = 217339213Sgibbs arg->patch[1]; 217439213Sgibbs data->page.audio.port[2].channels = arg->patch[2]; 217539213Sgibbs data->page.audio.port[3].channels = arg->patch[3]; 217639213Sgibbs error = cdsetmode(periph, data); 217739213Sgibbs free(data, M_TEMP); 217839213Sgibbs } 217939213Sgibbs break; 218039213Sgibbs case CDIOCGETVOL: 218139213Sgibbs { 218239213Sgibbs struct ioc_vol *arg = (struct ioc_vol *) addr; 218339213Sgibbs struct cd_mode_data *data; 218439213Sgibbs 218539213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 218639213Sgibbs ("trying to do CDIOCGETVOL\n")); 218739213Sgibbs 218839213Sgibbs data = malloc(sizeof(struct cd_mode_data), M_TEMP, 218939213Sgibbs M_WAITOK); 219039213Sgibbs error = cdgetmode(periph, data, AUDIO_PAGE); 219139213Sgibbs if (error) { 219239213Sgibbs free(data, M_TEMP); 219339213Sgibbs break; 219439213Sgibbs } 219539213Sgibbs arg->vol[LEFT_PORT] = 219639213Sgibbs data->page.audio.port[LEFT_PORT].volume; 219739213Sgibbs arg->vol[RIGHT_PORT] = 219839213Sgibbs data->page.audio.port[RIGHT_PORT].volume; 219939213Sgibbs arg->vol[2] = data->page.audio.port[2].volume; 220039213Sgibbs arg->vol[3] = data->page.audio.port[3].volume; 220139213Sgibbs free(data, M_TEMP); 220239213Sgibbs } 220339213Sgibbs break; 220439213Sgibbs case CDIOCSETVOL: 220539213Sgibbs { 220639213Sgibbs struct ioc_vol *arg = (struct ioc_vol *) addr; 220739213Sgibbs struct cd_mode_data *data; 220839213Sgibbs 220939213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 221039213Sgibbs ("trying to do CDIOCSETVOL\n")); 221139213Sgibbs 221239213Sgibbs data = malloc(sizeof(struct cd_mode_data), M_TEMP, 221339213Sgibbs M_WAITOK); 221439213Sgibbs error = cdgetmode(periph, data, AUDIO_PAGE); 221539213Sgibbs if (error) { 221639213Sgibbs free(data, M_TEMP); 221739213Sgibbs break; 221839213Sgibbs } 221939213Sgibbs data->page.audio.port[LEFT_PORT].channels = CHANNEL_0; 222039213Sgibbs data->page.audio.port[LEFT_PORT].volume = 222139213Sgibbs arg->vol[LEFT_PORT]; 222239213Sgibbs data->page.audio.port[RIGHT_PORT].channels = CHANNEL_1; 222339213Sgibbs data->page.audio.port[RIGHT_PORT].volume = 222439213Sgibbs arg->vol[RIGHT_PORT]; 222539213Sgibbs data->page.audio.port[2].volume = arg->vol[2]; 222639213Sgibbs data->page.audio.port[3].volume = arg->vol[3]; 222739213Sgibbs error = cdsetmode(periph, data); 222839213Sgibbs free(data, M_TEMP); 222939213Sgibbs } 223039213Sgibbs break; 223139213Sgibbs case CDIOCSETMONO: 223239213Sgibbs { 223339213Sgibbs struct cd_mode_data *data; 223439213Sgibbs 223539213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 223639213Sgibbs ("trying to do CDIOCSETMONO\n")); 223739213Sgibbs 223839213Sgibbs data = malloc(sizeof(struct cd_mode_data), 223939213Sgibbs M_TEMP, M_WAITOK); 224039213Sgibbs error = cdgetmode(periph, data, AUDIO_PAGE); 224139213Sgibbs if (error) { 224239213Sgibbs free(data, M_TEMP); 224339213Sgibbs break; 224439213Sgibbs } 224539213Sgibbs data->page.audio.port[LEFT_PORT].channels = 224639213Sgibbs LEFT_CHANNEL | RIGHT_CHANNEL; 224739213Sgibbs data->page.audio.port[RIGHT_PORT].channels = 224839213Sgibbs LEFT_CHANNEL | RIGHT_CHANNEL; 224939213Sgibbs data->page.audio.port[2].channels = 0; 225039213Sgibbs data->page.audio.port[3].channels = 0; 225139213Sgibbs error = cdsetmode(periph, data); 225239213Sgibbs free(data, M_TEMP); 225339213Sgibbs } 225439213Sgibbs break; 225539213Sgibbs case CDIOCSETSTEREO: 225639213Sgibbs { 225739213Sgibbs struct cd_mode_data *data; 225839213Sgibbs 225939213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 226039213Sgibbs ("trying to do CDIOCSETSTEREO\n")); 226139213Sgibbs 226239213Sgibbs data = malloc(sizeof(struct cd_mode_data), M_TEMP, 226339213Sgibbs M_WAITOK); 226439213Sgibbs error = cdgetmode(periph, data, AUDIO_PAGE); 226539213Sgibbs if (error) { 226639213Sgibbs free(data, M_TEMP); 226739213Sgibbs break; 226839213Sgibbs } 226939213Sgibbs data->page.audio.port[LEFT_PORT].channels = 227039213Sgibbs LEFT_CHANNEL; 227139213Sgibbs data->page.audio.port[RIGHT_PORT].channels = 227239213Sgibbs RIGHT_CHANNEL; 227339213Sgibbs data->page.audio.port[2].channels = 0; 227439213Sgibbs data->page.audio.port[3].channels = 0; 227539213Sgibbs error = cdsetmode(periph, data); 227639213Sgibbs free(data, M_TEMP); 227739213Sgibbs } 227839213Sgibbs break; 227939213Sgibbs case CDIOCSETMUTE: 228039213Sgibbs { 228139213Sgibbs struct cd_mode_data *data; 228239213Sgibbs 228339213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 228439213Sgibbs ("trying to do CDIOCSETMUTE\n")); 228539213Sgibbs 228639213Sgibbs data = malloc(sizeof(struct cd_mode_data), M_TEMP, 228739213Sgibbs M_WAITOK); 228839213Sgibbs error = cdgetmode(periph, data, AUDIO_PAGE); 228939213Sgibbs if (error) { 229039213Sgibbs free(data, M_TEMP); 229139213Sgibbs break; 229239213Sgibbs } 229339213Sgibbs data->page.audio.port[LEFT_PORT].channels = 0; 229439213Sgibbs data->page.audio.port[RIGHT_PORT].channels = 0; 229539213Sgibbs data->page.audio.port[2].channels = 0; 229639213Sgibbs data->page.audio.port[3].channels = 0; 229739213Sgibbs error = cdsetmode(periph, data); 229839213Sgibbs free(data, M_TEMP); 229939213Sgibbs } 230039213Sgibbs break; 230139213Sgibbs case CDIOCSETLEFT: 230239213Sgibbs { 230339213Sgibbs struct cd_mode_data *data; 230439213Sgibbs 230539213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 230639213Sgibbs ("trying to do CDIOCSETLEFT\n")); 230739213Sgibbs 230839213Sgibbs data = malloc(sizeof(struct cd_mode_data), M_TEMP, 230939213Sgibbs M_WAITOK); 231039213Sgibbs error = cdgetmode(periph, data, AUDIO_PAGE); 231139213Sgibbs if (error) { 231239213Sgibbs free(data, M_TEMP); 231339213Sgibbs break; 231439213Sgibbs } 231539213Sgibbs data->page.audio.port[LEFT_PORT].channels = 231639213Sgibbs LEFT_CHANNEL; 231739213Sgibbs data->page.audio.port[RIGHT_PORT].channels = 231839213Sgibbs LEFT_CHANNEL; 231939213Sgibbs data->page.audio.port[2].channels = 0; 232039213Sgibbs data->page.audio.port[3].channels = 0; 232139213Sgibbs error = cdsetmode(periph, data); 232239213Sgibbs free(data, M_TEMP); 232339213Sgibbs } 232439213Sgibbs break; 232539213Sgibbs case CDIOCSETRIGHT: 232639213Sgibbs { 232739213Sgibbs struct cd_mode_data *data; 232839213Sgibbs 232939213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 233039213Sgibbs ("trying to do CDIOCSETRIGHT\n")); 233139213Sgibbs 233239213Sgibbs data = malloc(sizeof(struct cd_mode_data), M_TEMP, 233339213Sgibbs M_WAITOK); 233439213Sgibbs error = cdgetmode(periph, data, AUDIO_PAGE); 233539213Sgibbs if (error) { 233639213Sgibbs free(data, M_TEMP); 233739213Sgibbs break; 233839213Sgibbs } 233939213Sgibbs data->page.audio.port[LEFT_PORT].channels = 234039213Sgibbs RIGHT_CHANNEL; 234139213Sgibbs data->page.audio.port[RIGHT_PORT].channels = 234239213Sgibbs RIGHT_CHANNEL; 234339213Sgibbs data->page.audio.port[2].channels = 0; 234439213Sgibbs data->page.audio.port[3].channels = 0; 234539213Sgibbs error = cdsetmode(periph, data); 234639213Sgibbs free(data, M_TEMP); 234739213Sgibbs } 234839213Sgibbs break; 234939213Sgibbs case CDIOCRESUME: 235039213Sgibbs error = cdpause(periph, 1); 235139213Sgibbs break; 235239213Sgibbs case CDIOCPAUSE: 235339213Sgibbs error = cdpause(periph, 0); 235439213Sgibbs break; 235539213Sgibbs case CDIOCSTART: 235639213Sgibbs error = cdstartunit(periph); 235739213Sgibbs break; 235839213Sgibbs case CDIOCSTOP: 235939213Sgibbs error = cdstopunit(periph, 0); 236039213Sgibbs break; 236139213Sgibbs case CDIOCEJECT: 236239213Sgibbs error = cdstopunit(periph, 1); 236339213Sgibbs break; 236439213Sgibbs case CDIOCALLOW: 236539213Sgibbs cdprevent(periph, PR_ALLOW); 236639213Sgibbs break; 236739213Sgibbs case CDIOCPREVENT: 236839213Sgibbs cdprevent(periph, PR_PREVENT); 236939213Sgibbs break; 237039213Sgibbs case CDIOCSETDEBUG: 237139213Sgibbs /* sc_link->flags |= (SDEV_DB1 | SDEV_DB2); */ 237239213Sgibbs error = ENOTTY; 237339213Sgibbs break; 237439213Sgibbs case CDIOCCLRDEBUG: 237539213Sgibbs /* sc_link->flags &= ~(SDEV_DB1 | SDEV_DB2); */ 237639213Sgibbs error = ENOTTY; 237739213Sgibbs break; 237839213Sgibbs case CDIOCRESET: 237939213Sgibbs /* return (cd_reset(periph)); */ 238039213Sgibbs error = ENOTTY; 238139213Sgibbs break; 238260422Sken case DVDIOCSENDKEY: 238360422Sken case DVDIOCREPORTKEY: { 238460422Sken struct dvd_authinfo *authinfo; 238560422Sken 238660422Sken authinfo = (struct dvd_authinfo *)addr; 238760422Sken 238860422Sken if (cmd == DVDIOCREPORTKEY) 238960422Sken error = cdreportkey(periph, authinfo); 239060422Sken else 239160422Sken error = cdsendkey(periph, authinfo); 239260422Sken break; 2393104456Sphk } 239460422Sken case DVDIOCREADSTRUCTURE: { 239560422Sken struct dvd_struct *dvdstruct; 239660422Sken 239760422Sken dvdstruct = (struct dvd_struct *)addr; 239860422Sken 239960422Sken error = cdreaddvdstructure(periph, dvdstruct); 240060422Sken 240160422Sken break; 240260422Sken } 240339213Sgibbs default: 240439213Sgibbs error = cam_periph_ioctl(periph, cmd, addr, cderror); 240539213Sgibbs break; 240639213Sgibbs } 240739213Sgibbs 240840020Sken cam_periph_unlock(periph); 240940020Sken 241039213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("leaving cdioctl\n")); 2411104456Sphk if (error && bootverbose) { 2412104456Sphk printf("scsi_cd.c::ioctl cmd=%08lx error=%d\n", cmd, error); 2413104456Sphk } 241439213Sgibbs 241539213Sgibbs return (error); 241639213Sgibbs} 241739213Sgibbs 241839213Sgibbsstatic void 241939213Sgibbscdprevent(struct cam_periph *periph, int action) 242039213Sgibbs{ 242139213Sgibbs union ccb *ccb; 242239213Sgibbs struct cd_softc *softc; 242339213Sgibbs int error; 242439213Sgibbs 242539213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdprevent\n")); 242639213Sgibbs 242739213Sgibbs softc = (struct cd_softc *)periph->softc; 242839213Sgibbs 242939213Sgibbs if (((action == PR_ALLOW) 243039213Sgibbs && (softc->flags & CD_FLAG_DISC_LOCKED) == 0) 243139213Sgibbs || ((action == PR_PREVENT) 243239213Sgibbs && (softc->flags & CD_FLAG_DISC_LOCKED) != 0)) { 243339213Sgibbs return; 243439213Sgibbs } 243539213Sgibbs 243639213Sgibbs ccb = cdgetccb(periph, /* priority */ 1); 243739213Sgibbs 243839213Sgibbs scsi_prevent(&ccb->csio, 243939213Sgibbs /*retries*/ 1, 244039213Sgibbs cddone, 244139213Sgibbs MSG_SIMPLE_Q_TAG, 244239213Sgibbs action, 244339213Sgibbs SSD_FULL_SIZE, 244439213Sgibbs /* timeout */60000); 244539213Sgibbs 244674840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 244774840Sken /*sense_flags*/SF_RETRY_UA|SF_NO_PRINT); 244839213Sgibbs 244939213Sgibbs xpt_release_ccb(ccb); 245039213Sgibbs 245139213Sgibbs if (error == 0) { 245239213Sgibbs if (action == PR_ALLOW) 245339213Sgibbs softc->flags &= ~CD_FLAG_DISC_LOCKED; 245439213Sgibbs else 245539213Sgibbs softc->flags |= CD_FLAG_DISC_LOCKED; 245639213Sgibbs } 245739213Sgibbs} 245839213Sgibbs 245939213Sgibbsstatic int 246039213Sgibbscdsize(dev_t dev, u_int32_t *size) 246139213Sgibbs{ 246239213Sgibbs struct cam_periph *periph; 246339213Sgibbs struct cd_softc *softc; 246439213Sgibbs union ccb *ccb; 246539213Sgibbs struct scsi_read_capacity_data *rcap_buf; 246639213Sgibbs int error; 246739213Sgibbs 2468101940Snjl periph = (struct cam_periph *)dev->si_drv1; 246939213Sgibbs if (periph == NULL) 247039213Sgibbs return (ENXIO); 247139213Sgibbs 247239213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdsize\n")); 247339213Sgibbs 247439213Sgibbs softc = (struct cd_softc *)periph->softc; 247539213Sgibbs 247639213Sgibbs ccb = cdgetccb(periph, /* priority */ 1); 247739213Sgibbs 247839213Sgibbs rcap_buf = malloc(sizeof(struct scsi_read_capacity_data), 247939213Sgibbs M_TEMP, M_WAITOK); 248039213Sgibbs 248139213Sgibbs scsi_read_capacity(&ccb->csio, 248239213Sgibbs /*retries*/ 1, 248339213Sgibbs cddone, 248439213Sgibbs MSG_SIMPLE_Q_TAG, 248539213Sgibbs rcap_buf, 248639213Sgibbs SSD_FULL_SIZE, 248739213Sgibbs /* timeout */20000); 248839213Sgibbs 248974840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 249074840Sken /*sense_flags*/SF_RETRY_UA|SF_NO_PRINT); 249139213Sgibbs 249239213Sgibbs xpt_release_ccb(ccb); 249339213Sgibbs 249439213Sgibbs softc->params.disksize = scsi_4btoul(rcap_buf->addr) + 1; 249539213Sgibbs softc->params.blksize = scsi_4btoul(rcap_buf->length); 249660806Sjoerg /* 249760806Sjoerg * SCSI-3 mandates that the reported blocksize shall be 2048. 249860806Sjoerg * Older drives sometimes report funny values, trim it down to 249960806Sjoerg * 2048, or other parts of the kernel will get confused. 250060806Sjoerg * 250160806Sjoerg * XXX we leave drives alone that might report 512 bytes, as 250260806Sjoerg * well as drives reporting more weird sizes like perhaps 4K. 250360806Sjoerg */ 250460806Sjoerg if (softc->params.blksize > 2048 && softc->params.blksize <= 2352) 250560806Sjoerg softc->params.blksize = 2048; 250639213Sgibbs 250739213Sgibbs free(rcap_buf, M_TEMP); 250839213Sgibbs *size = softc->params.disksize; 250939213Sgibbs 251039213Sgibbs return (error); 251139213Sgibbs 251239213Sgibbs} 251339213Sgibbs 251439213Sgibbsstatic int 251539213Sgibbscderror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) 251639213Sgibbs{ 251739213Sgibbs struct cd_softc *softc; 251839213Sgibbs struct cam_periph *periph; 251939213Sgibbs 252039213Sgibbs periph = xpt_path_periph(ccb->ccb_h.path); 252139213Sgibbs softc = (struct cd_softc *)periph->softc; 252239213Sgibbs 252339514Sgibbs /* 252439514Sgibbs * XXX 252539514Sgibbs * Until we have a better way of doing pack validation, 252639514Sgibbs * don't treat UAs as errors. 252739514Sgibbs */ 252839514Sgibbs sense_flags |= SF_RETRY_UA; 252939213Sgibbs return (cam_periph_error(ccb, cam_flags, sense_flags, 253039213Sgibbs &softc->saved_ccb)); 253139213Sgibbs} 253239213Sgibbs 253339213Sgibbs/* 253439213Sgibbs * Read table of contents 253539213Sgibbs */ 253639213Sgibbsstatic int 253739213Sgibbscdreadtoc(struct cam_periph *periph, u_int32_t mode, u_int32_t start, 253839213Sgibbs struct cd_toc_entry *data, u_int32_t len) 253939213Sgibbs{ 254039213Sgibbs struct scsi_read_toc *scsi_cmd; 254139213Sgibbs u_int32_t ntoc; 254239213Sgibbs struct ccb_scsiio *csio; 254339213Sgibbs union ccb *ccb; 254439213Sgibbs int error; 254539213Sgibbs 254639213Sgibbs ntoc = len; 254739213Sgibbs error = 0; 254839213Sgibbs 254939213Sgibbs ccb = cdgetccb(periph, /* priority */ 1); 255039213Sgibbs 255139213Sgibbs csio = &ccb->csio; 255239213Sgibbs 255339213Sgibbs cam_fill_csio(csio, 255439213Sgibbs /* retries */ 1, 255539213Sgibbs /* cbfcnp */ cddone, 255639213Sgibbs /* flags */ CAM_DIR_IN, 255739213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 255839213Sgibbs /* data_ptr */ (u_int8_t *)data, 255939213Sgibbs /* dxfer_len */ len, 256039213Sgibbs /* sense_len */ SSD_FULL_SIZE, 256139213Sgibbs sizeof(struct scsi_read_toc), 256239213Sgibbs /* timeout */ 50000); 256339213Sgibbs 256439213Sgibbs scsi_cmd = (struct scsi_read_toc *)&csio->cdb_io.cdb_bytes; 256539213Sgibbs bzero (scsi_cmd, sizeof(*scsi_cmd)); 256639213Sgibbs 256739213Sgibbs if (mode == CD_MSF_FORMAT) 256839213Sgibbs scsi_cmd->byte2 |= CD_MSF; 256939213Sgibbs scsi_cmd->from_track = start; 257039213Sgibbs /* scsi_ulto2b(ntoc, (u_int8_t *)scsi_cmd->data_len); */ 257139213Sgibbs scsi_cmd->data_len[0] = (ntoc) >> 8; 257239213Sgibbs scsi_cmd->data_len[1] = (ntoc) & 0xff; 257339213Sgibbs 257439213Sgibbs scsi_cmd->op_code = READ_TOC; 257539213Sgibbs 257674840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 257774840Sken /*sense_flags*/SF_RETRY_UA); 257839213Sgibbs 257939213Sgibbs xpt_release_ccb(ccb); 258039213Sgibbs 258139213Sgibbs return(error); 258239213Sgibbs} 258339213Sgibbs 258439213Sgibbsstatic int 258539213Sgibbscdreadsubchannel(struct cam_periph *periph, u_int32_t mode, 258639213Sgibbs u_int32_t format, int track, 258739213Sgibbs struct cd_sub_channel_info *data, u_int32_t len) 258839213Sgibbs{ 258939213Sgibbs struct scsi_read_subchannel *scsi_cmd; 259039213Sgibbs struct ccb_scsiio *csio; 259139213Sgibbs union ccb *ccb; 259239213Sgibbs int error; 259339213Sgibbs 259439213Sgibbs error = 0; 259539213Sgibbs 259639213Sgibbs ccb = cdgetccb(periph, /* priority */ 1); 259739213Sgibbs 259839213Sgibbs csio = &ccb->csio; 259939213Sgibbs 260039213Sgibbs cam_fill_csio(csio, 260139213Sgibbs /* retries */ 1, 260239213Sgibbs /* cbfcnp */ cddone, 260339213Sgibbs /* flags */ CAM_DIR_IN, 260439213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 260539213Sgibbs /* data_ptr */ (u_int8_t *)data, 260639213Sgibbs /* dxfer_len */ len, 260739213Sgibbs /* sense_len */ SSD_FULL_SIZE, 260839213Sgibbs sizeof(struct scsi_read_subchannel), 260939213Sgibbs /* timeout */ 50000); 261039213Sgibbs 261139213Sgibbs scsi_cmd = (struct scsi_read_subchannel *)&csio->cdb_io.cdb_bytes; 261239213Sgibbs bzero (scsi_cmd, sizeof(*scsi_cmd)); 261339213Sgibbs 261439213Sgibbs scsi_cmd->op_code = READ_SUBCHANNEL; 261539213Sgibbs if (mode == CD_MSF_FORMAT) 261639213Sgibbs scsi_cmd->byte1 |= CD_MSF; 261739213Sgibbs scsi_cmd->byte2 = SRS_SUBQ; 261839213Sgibbs scsi_cmd->subchan_format = format; 261939213Sgibbs scsi_cmd->track = track; 262039213Sgibbs scsi_ulto2b(len, (u_int8_t *)scsi_cmd->data_len); 262139213Sgibbs scsi_cmd->control = 0; 262239213Sgibbs 262374840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 262474840Sken /*sense_flags*/SF_RETRY_UA); 262539213Sgibbs 262639213Sgibbs xpt_release_ccb(ccb); 262739213Sgibbs 262839213Sgibbs return(error); 262939213Sgibbs} 263039213Sgibbs 263139213Sgibbs 263239213Sgibbsstatic int 263339213Sgibbscdgetmode(struct cam_periph *periph, struct cd_mode_data *data, u_int32_t page) 263439213Sgibbs{ 263539213Sgibbs struct scsi_mode_sense_6 *scsi_cmd; 263639213Sgibbs struct ccb_scsiio *csio; 263739213Sgibbs union ccb *ccb; 263839213Sgibbs int error; 263939213Sgibbs 264039213Sgibbs ccb = cdgetccb(periph, /* priority */ 1); 264139213Sgibbs 264239213Sgibbs csio = &ccb->csio; 264339213Sgibbs 264439213Sgibbs bzero(data, sizeof(*data)); 264539213Sgibbs cam_fill_csio(csio, 264639213Sgibbs /* retries */ 1, 264739213Sgibbs /* cbfcnp */ cddone, 264839213Sgibbs /* flags */ CAM_DIR_IN, 264939213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 265039213Sgibbs /* data_ptr */ (u_int8_t *)data, 265139213Sgibbs /* dxfer_len */ sizeof(*data), 265239213Sgibbs /* sense_len */ SSD_FULL_SIZE, 265339213Sgibbs sizeof(struct scsi_mode_sense_6), 265439213Sgibbs /* timeout */ 50000); 265539213Sgibbs 265639213Sgibbs scsi_cmd = (struct scsi_mode_sense_6 *)&csio->cdb_io.cdb_bytes; 265739213Sgibbs bzero (scsi_cmd, sizeof(*scsi_cmd)); 265839213Sgibbs 265939213Sgibbs scsi_cmd->page = page; 266039213Sgibbs scsi_cmd->length = sizeof(*data) & 0xff; 266139213Sgibbs scsi_cmd->opcode = MODE_SENSE; 266239213Sgibbs 266374840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 266474840Sken /*sense_flags*/SF_RETRY_UA); 266539213Sgibbs 266639213Sgibbs xpt_release_ccb(ccb); 266739213Sgibbs 266839213Sgibbs return(error); 266939213Sgibbs} 267039213Sgibbs 267139213Sgibbsstatic int 267239213Sgibbscdsetmode(struct cam_periph *periph, struct cd_mode_data *data) 267339213Sgibbs{ 267439213Sgibbs struct scsi_mode_select_6 *scsi_cmd; 267539213Sgibbs struct ccb_scsiio *csio; 267639213Sgibbs union ccb *ccb; 267739213Sgibbs int error; 267839213Sgibbs 267939213Sgibbs ccb = cdgetccb(periph, /* priority */ 1); 268039213Sgibbs 268139213Sgibbs csio = &ccb->csio; 268239213Sgibbs 268339213Sgibbs error = 0; 268439213Sgibbs 268539213Sgibbs cam_fill_csio(csio, 268639213Sgibbs /* retries */ 1, 268739213Sgibbs /* cbfcnp */ cddone, 268839531Sken /* flags */ CAM_DIR_OUT, 268939213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 269039213Sgibbs /* data_ptr */ (u_int8_t *)data, 269139213Sgibbs /* dxfer_len */ sizeof(*data), 269239213Sgibbs /* sense_len */ SSD_FULL_SIZE, 269339213Sgibbs sizeof(struct scsi_mode_select_6), 269439213Sgibbs /* timeout */ 50000); 269539213Sgibbs 269639213Sgibbs scsi_cmd = (struct scsi_mode_select_6 *)&csio->cdb_io.cdb_bytes; 269739213Sgibbs 269839213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 269939213Sgibbs scsi_cmd->opcode = MODE_SELECT; 270039213Sgibbs scsi_cmd->byte2 |= SMS_PF; 270139213Sgibbs scsi_cmd->length = sizeof(*data) & 0xff; 270239213Sgibbs data->header.data_length = 0; 270339213Sgibbs /* 270439213Sgibbs * SONY drives do not allow a mode select with a medium_type 270539213Sgibbs * value that has just been returned by a mode sense; use a 270639213Sgibbs * medium_type of 0 (Default) instead. 270739213Sgibbs */ 270839213Sgibbs data->header.medium_type = 0; 270939213Sgibbs 271074840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 271174840Sken /*sense_flags*/SF_RETRY_UA); 271239213Sgibbs 271339213Sgibbs xpt_release_ccb(ccb); 271439213Sgibbs 271539213Sgibbs return(error); 271639213Sgibbs} 271739213Sgibbs 271839213Sgibbs 271939213Sgibbsstatic int 272039213Sgibbscdplay(struct cam_periph *periph, u_int32_t blk, u_int32_t len) 272139213Sgibbs{ 272239531Sken struct ccb_scsiio *csio; 272339213Sgibbs union ccb *ccb; 272439213Sgibbs int error; 272539531Sken u_int8_t cdb_len; 272639213Sgibbs 272739213Sgibbs error = 0; 272839213Sgibbs ccb = cdgetccb(periph, /* priority */ 1); 272939213Sgibbs csio = &ccb->csio; 273039531Sken /* 273139531Sken * Use the smallest possible command to perform the operation. 273239531Sken */ 273339531Sken if ((len & 0xffff0000) == 0) { 273439531Sken /* 273539531Sken * We can fit in a 10 byte cdb. 273639531Sken */ 273739531Sken struct scsi_play_10 *scsi_cmd; 273839213Sgibbs 273939531Sken scsi_cmd = (struct scsi_play_10 *)&csio->cdb_io.cdb_bytes; 274039531Sken bzero (scsi_cmd, sizeof(*scsi_cmd)); 274139531Sken scsi_cmd->op_code = PLAY_10; 274239531Sken scsi_ulto4b(blk, (u_int8_t *)scsi_cmd->blk_addr); 274339531Sken scsi_ulto2b(len, (u_int8_t *)scsi_cmd->xfer_len); 274439531Sken cdb_len = sizeof(*scsi_cmd); 274539531Sken } else { 274639531Sken struct scsi_play_12 *scsi_cmd; 274739213Sgibbs 274839531Sken scsi_cmd = (struct scsi_play_12 *)&csio->cdb_io.cdb_bytes; 274939531Sken bzero (scsi_cmd, sizeof(*scsi_cmd)); 275039531Sken scsi_cmd->op_code = PLAY_12; 275139531Sken scsi_ulto4b(blk, (u_int8_t *)scsi_cmd->blk_addr); 275239531Sken scsi_ulto4b(len, (u_int8_t *)scsi_cmd->xfer_len); 275339531Sken cdb_len = sizeof(*scsi_cmd); 275439531Sken } 275539531Sken cam_fill_csio(csio, 275639531Sken /*retries*/2, 275739531Sken cddone, 275839531Sken /*flags*/CAM_DIR_NONE, 275939531Sken MSG_SIMPLE_Q_TAG, 276039531Sken /*dataptr*/NULL, 276139531Sken /*datalen*/0, 276239531Sken /*sense_len*/SSD_FULL_SIZE, 276339531Sken cdb_len, 276439531Sken /*timeout*/50 * 1000); 276539213Sgibbs 276674840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 276774840Sken /*sense_flags*/SF_RETRY_UA); 276839213Sgibbs 276939213Sgibbs xpt_release_ccb(ccb); 277039213Sgibbs 277139213Sgibbs return(error); 277239213Sgibbs} 277339213Sgibbs 277439213Sgibbsstatic int 277539213Sgibbscdplaymsf(struct cam_periph *periph, u_int32_t startm, u_int32_t starts, 277639213Sgibbs u_int32_t startf, u_int32_t endm, u_int32_t ends, u_int32_t endf) 277739213Sgibbs{ 277839213Sgibbs struct scsi_play_msf *scsi_cmd; 277939213Sgibbs struct ccb_scsiio *csio; 278039213Sgibbs union ccb *ccb; 278139213Sgibbs int error; 278239213Sgibbs 278339213Sgibbs error = 0; 278439213Sgibbs 278539213Sgibbs ccb = cdgetccb(periph, /* priority */ 1); 278639213Sgibbs 278739213Sgibbs csio = &ccb->csio; 278839213Sgibbs 278939213Sgibbs cam_fill_csio(csio, 279039213Sgibbs /* retries */ 1, 279139213Sgibbs /* cbfcnp */ cddone, 279239531Sken /* flags */ CAM_DIR_NONE, 279339213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 279439213Sgibbs /* data_ptr */ NULL, 279539213Sgibbs /* dxfer_len */ 0, 279639213Sgibbs /* sense_len */ SSD_FULL_SIZE, 279739213Sgibbs sizeof(struct scsi_play_msf), 279839213Sgibbs /* timeout */ 50000); 279939213Sgibbs 280039213Sgibbs scsi_cmd = (struct scsi_play_msf *)&csio->cdb_io.cdb_bytes; 280139213Sgibbs bzero (scsi_cmd, sizeof(*scsi_cmd)); 280239213Sgibbs 280339213Sgibbs scsi_cmd->op_code = PLAY_MSF; 280439213Sgibbs scsi_cmd->start_m = startm; 280539213Sgibbs scsi_cmd->start_s = starts; 280639213Sgibbs scsi_cmd->start_f = startf; 280739213Sgibbs scsi_cmd->end_m = endm; 280839213Sgibbs scsi_cmd->end_s = ends; 280939213Sgibbs scsi_cmd->end_f = endf; 281039213Sgibbs 281174840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 281274840Sken /*sense_flags*/SF_RETRY_UA); 281339213Sgibbs 281439213Sgibbs xpt_release_ccb(ccb); 281539213Sgibbs 281639213Sgibbs return(error); 281739213Sgibbs} 281839213Sgibbs 281939213Sgibbs 282039213Sgibbsstatic int 282139213Sgibbscdplaytracks(struct cam_periph *periph, u_int32_t strack, u_int32_t sindex, 282239213Sgibbs u_int32_t etrack, u_int32_t eindex) 282339213Sgibbs{ 282439213Sgibbs struct scsi_play_track *scsi_cmd; 282539213Sgibbs struct ccb_scsiio *csio; 282639213Sgibbs union ccb *ccb; 282739213Sgibbs int error; 282839213Sgibbs 282939213Sgibbs error = 0; 283039213Sgibbs 283139213Sgibbs ccb = cdgetccb(periph, /* priority */ 1); 283239213Sgibbs 283339213Sgibbs csio = &ccb->csio; 283439213Sgibbs 283539213Sgibbs cam_fill_csio(csio, 283639213Sgibbs /* retries */ 1, 283739213Sgibbs /* cbfcnp */ cddone, 283839531Sken /* flags */ CAM_DIR_NONE, 283939213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 284039213Sgibbs /* data_ptr */ NULL, 284139213Sgibbs /* dxfer_len */ 0, 284239213Sgibbs /* sense_len */ SSD_FULL_SIZE, 284339213Sgibbs sizeof(struct scsi_play_track), 284439213Sgibbs /* timeout */ 50000); 284539213Sgibbs 284639213Sgibbs scsi_cmd = (struct scsi_play_track *)&csio->cdb_io.cdb_bytes; 284739213Sgibbs bzero (scsi_cmd, sizeof(*scsi_cmd)); 284839213Sgibbs 284939213Sgibbs scsi_cmd->op_code = PLAY_TRACK; 285039213Sgibbs scsi_cmd->start_track = strack; 285139213Sgibbs scsi_cmd->start_index = sindex; 285239213Sgibbs scsi_cmd->end_track = etrack; 285339213Sgibbs scsi_cmd->end_index = eindex; 285439213Sgibbs 285574840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 285674840Sken /*sense_flags*/SF_RETRY_UA); 285739213Sgibbs 285839213Sgibbs xpt_release_ccb(ccb); 285939213Sgibbs 286039213Sgibbs return(error); 286139213Sgibbs} 286239213Sgibbs 286339213Sgibbsstatic int 286439213Sgibbscdpause(struct cam_periph *periph, u_int32_t go) 286539213Sgibbs{ 286639213Sgibbs struct scsi_pause *scsi_cmd; 286739213Sgibbs struct ccb_scsiio *csio; 286839213Sgibbs union ccb *ccb; 286939213Sgibbs int error; 287039213Sgibbs 287139213Sgibbs error = 0; 287239213Sgibbs 287339213Sgibbs ccb = cdgetccb(periph, /* priority */ 1); 287439213Sgibbs 287539213Sgibbs csio = &ccb->csio; 287639213Sgibbs 287739213Sgibbs cam_fill_csio(csio, 287839213Sgibbs /* retries */ 1, 287939213Sgibbs /* cbfcnp */ cddone, 288039531Sken /* flags */ CAM_DIR_NONE, 288139213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 288239213Sgibbs /* data_ptr */ NULL, 288339213Sgibbs /* dxfer_len */ 0, 288439213Sgibbs /* sense_len */ SSD_FULL_SIZE, 288539213Sgibbs sizeof(struct scsi_pause), 288639213Sgibbs /* timeout */ 50000); 288739213Sgibbs 288839213Sgibbs scsi_cmd = (struct scsi_pause *)&csio->cdb_io.cdb_bytes; 288939213Sgibbs bzero (scsi_cmd, sizeof(*scsi_cmd)); 289039213Sgibbs 289139213Sgibbs scsi_cmd->op_code = PAUSE; 289239213Sgibbs scsi_cmd->resume = go; 289339213Sgibbs 289474840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 289574840Sken /*sense_flags*/SF_RETRY_UA); 289639213Sgibbs 289739213Sgibbs xpt_release_ccb(ccb); 289839213Sgibbs 289939213Sgibbs return(error); 290039213Sgibbs} 290139213Sgibbs 290239213Sgibbsstatic int 290339213Sgibbscdstartunit(struct cam_periph *periph) 290439213Sgibbs{ 290539213Sgibbs union ccb *ccb; 290639213Sgibbs int error; 290739213Sgibbs 290839213Sgibbs error = 0; 290939213Sgibbs 291039213Sgibbs ccb = cdgetccb(periph, /* priority */ 1); 291139213Sgibbs 291239213Sgibbs scsi_start_stop(&ccb->csio, 291339213Sgibbs /* retries */ 1, 291439213Sgibbs /* cbfcnp */ cddone, 291539213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 291639213Sgibbs /* start */ TRUE, 291769577Sjoerg /* load_eject */ FALSE, 291839213Sgibbs /* immediate */ FALSE, 291939213Sgibbs /* sense_len */ SSD_FULL_SIZE, 292039213Sgibbs /* timeout */ 50000); 292139213Sgibbs 292274840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 292374840Sken /*sense_flags*/SF_RETRY_UA); 292439213Sgibbs 292539213Sgibbs xpt_release_ccb(ccb); 292639213Sgibbs 292739213Sgibbs return(error); 292839213Sgibbs} 292939213Sgibbs 293039213Sgibbsstatic int 293139213Sgibbscdstopunit(struct cam_periph *periph, u_int32_t eject) 293239213Sgibbs{ 293339213Sgibbs union ccb *ccb; 293439213Sgibbs int error; 293539213Sgibbs 293639213Sgibbs error = 0; 293739213Sgibbs 293839213Sgibbs ccb = cdgetccb(periph, /* priority */ 1); 293939213Sgibbs 294039213Sgibbs scsi_start_stop(&ccb->csio, 294139213Sgibbs /* retries */ 1, 294239213Sgibbs /* cbfcnp */ cddone, 294339213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 294439213Sgibbs /* start */ FALSE, 294539213Sgibbs /* load_eject */ eject, 294639213Sgibbs /* immediate */ FALSE, 294739213Sgibbs /* sense_len */ SSD_FULL_SIZE, 294839213Sgibbs /* timeout */ 50000); 294939213Sgibbs 295074840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 295174840Sken /*sense_flags*/SF_RETRY_UA); 295239213Sgibbs 295339213Sgibbs xpt_release_ccb(ccb); 295439213Sgibbs 295539213Sgibbs return(error); 295639213Sgibbs} 295760422Sken 295860422Skenstatic int 295960422Skencdreportkey(struct cam_periph *periph, struct dvd_authinfo *authinfo) 296060422Sken{ 296160422Sken union ccb *ccb; 296260422Sken u_int8_t *databuf; 296360422Sken u_int32_t lba; 296460422Sken int error; 296560422Sken int length; 296660422Sken 296760422Sken error = 0; 296860422Sken databuf = NULL; 296960422Sken lba = 0; 297060422Sken 297160422Sken ccb = cdgetccb(periph, /* priority */ 1); 297260422Sken 297360422Sken switch (authinfo->format) { 297460422Sken case DVD_REPORT_AGID: 297560422Sken length = sizeof(struct scsi_report_key_data_agid); 297660422Sken break; 297760422Sken case DVD_REPORT_CHALLENGE: 297860422Sken length = sizeof(struct scsi_report_key_data_challenge); 297960422Sken break; 298060422Sken case DVD_REPORT_KEY1: 298160422Sken length = sizeof(struct scsi_report_key_data_key1_key2); 298260422Sken break; 298360422Sken case DVD_REPORT_TITLE_KEY: 298460422Sken length = sizeof(struct scsi_report_key_data_title); 298560422Sken /* The lba field is only set for the title key */ 298660422Sken lba = authinfo->lba; 298760422Sken break; 298860422Sken case DVD_REPORT_ASF: 298960422Sken length = sizeof(struct scsi_report_key_data_asf); 299060422Sken break; 299160422Sken case DVD_REPORT_RPC: 299260422Sken length = sizeof(struct scsi_report_key_data_rpc); 299360422Sken break; 299460422Sken case DVD_INVALIDATE_AGID: 299560422Sken length = 0; 299660422Sken break; 299760422Sken default: 299860422Sken error = EINVAL; 299960422Sken goto bailout; 300060422Sken break; /* NOTREACHED */ 300160422Sken } 300260422Sken 300360422Sken if (length != 0) { 300467888Sdwmalone databuf = malloc(length, M_DEVBUF, M_WAITOK | M_ZERO); 300560422Sken } else 300660422Sken databuf = NULL; 300760422Sken 300860422Sken 300960422Sken scsi_report_key(&ccb->csio, 301060422Sken /* retries */ 1, 301160422Sken /* cbfcnp */ cddone, 301260422Sken /* tag_action */ MSG_SIMPLE_Q_TAG, 301360422Sken /* lba */ lba, 301460422Sken /* agid */ authinfo->agid, 301560422Sken /* key_format */ authinfo->format, 301660422Sken /* data_ptr */ databuf, 301760422Sken /* dxfer_len */ length, 301860422Sken /* sense_len */ SSD_FULL_SIZE, 301960422Sken /* timeout */ 50000); 302060422Sken 302174840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 302274840Sken /*sense_flags*/SF_RETRY_UA); 302360422Sken 302460422Sken if (error != 0) 302560422Sken goto bailout; 302660422Sken 302760422Sken if (ccb->csio.resid != 0) { 302860422Sken xpt_print_path(periph->path); 302960422Sken printf("warning, residual for report key command is %d\n", 303060422Sken ccb->csio.resid); 303160422Sken } 303260422Sken 303360422Sken switch(authinfo->format) { 303460422Sken case DVD_REPORT_AGID: { 303560422Sken struct scsi_report_key_data_agid *agid_data; 303660422Sken 303760422Sken agid_data = (struct scsi_report_key_data_agid *)databuf; 303860422Sken 303960422Sken authinfo->agid = (agid_data->agid & RKD_AGID_MASK) >> 304060422Sken RKD_AGID_SHIFT; 304160422Sken break; 304260422Sken } 304360422Sken case DVD_REPORT_CHALLENGE: { 304460422Sken struct scsi_report_key_data_challenge *chal_data; 304560422Sken 304660422Sken chal_data = (struct scsi_report_key_data_challenge *)databuf; 304760422Sken 304860422Sken bcopy(chal_data->challenge_key, authinfo->keychal, 304960422Sken min(sizeof(chal_data->challenge_key), 305060422Sken sizeof(authinfo->keychal))); 305160422Sken break; 305260422Sken } 305360422Sken case DVD_REPORT_KEY1: { 305460422Sken struct scsi_report_key_data_key1_key2 *key1_data; 305560422Sken 305660422Sken key1_data = (struct scsi_report_key_data_key1_key2 *)databuf; 305760422Sken 305860422Sken bcopy(key1_data->key1, authinfo->keychal, 305960422Sken min(sizeof(key1_data->key1), sizeof(authinfo->keychal))); 306060422Sken break; 306160422Sken } 306260422Sken case DVD_REPORT_TITLE_KEY: { 306360422Sken struct scsi_report_key_data_title *title_data; 306460422Sken 306560422Sken title_data = (struct scsi_report_key_data_title *)databuf; 306660422Sken 306760422Sken authinfo->cpm = (title_data->byte0 & RKD_TITLE_CPM) >> 306860422Sken RKD_TITLE_CPM_SHIFT; 306960422Sken authinfo->cp_sec = (title_data->byte0 & RKD_TITLE_CP_SEC) >> 307060422Sken RKD_TITLE_CP_SEC_SHIFT; 307160422Sken authinfo->cgms = (title_data->byte0 & RKD_TITLE_CMGS_MASK) >> 307260422Sken RKD_TITLE_CMGS_SHIFT; 307360422Sken bcopy(title_data->title_key, authinfo->keychal, 307460422Sken min(sizeof(title_data->title_key), 307560422Sken sizeof(authinfo->keychal))); 307660422Sken break; 307760422Sken } 307860422Sken case DVD_REPORT_ASF: { 307960422Sken struct scsi_report_key_data_asf *asf_data; 308060422Sken 308160422Sken asf_data = (struct scsi_report_key_data_asf *)databuf; 308260422Sken 308360422Sken authinfo->asf = asf_data->success & RKD_ASF_SUCCESS; 308460422Sken break; 308560422Sken } 308660422Sken case DVD_REPORT_RPC: { 308760422Sken struct scsi_report_key_data_rpc *rpc_data; 308860422Sken 308960422Sken rpc_data = (struct scsi_report_key_data_rpc *)databuf; 309060422Sken 309160422Sken authinfo->reg_type = (rpc_data->byte4 & RKD_RPC_TYPE_MASK) >> 309260422Sken RKD_RPC_TYPE_SHIFT; 309360422Sken authinfo->vend_rsts = 309460422Sken (rpc_data->byte4 & RKD_RPC_VENDOR_RESET_MASK) >> 309560422Sken RKD_RPC_VENDOR_RESET_SHIFT; 309660422Sken authinfo->user_rsts = rpc_data->byte4 & RKD_RPC_USER_RESET_MASK; 309771752Sken authinfo->region = rpc_data->region_mask; 309871752Sken authinfo->rpc_scheme = rpc_data->rpc_scheme1; 309960422Sken break; 310060422Sken } 310160422Sken case DVD_INVALIDATE_AGID: 310260422Sken break; 310360422Sken default: 310460422Sken /* This should be impossible, since we checked above */ 310560422Sken error = EINVAL; 310660422Sken goto bailout; 310760422Sken break; /* NOTREACHED */ 310860422Sken } 310960422Skenbailout: 311060422Sken if (databuf != NULL) 311160422Sken free(databuf, M_DEVBUF); 311260422Sken 311360422Sken xpt_release_ccb(ccb); 311460422Sken 311560422Sken return(error); 311660422Sken} 311760422Sken 311860422Skenstatic int 311960422Skencdsendkey(struct cam_periph *periph, struct dvd_authinfo *authinfo) 312060422Sken{ 312160422Sken union ccb *ccb; 312260422Sken u_int8_t *databuf; 312360422Sken int length; 312460422Sken int error; 312560422Sken 312660422Sken error = 0; 312760422Sken databuf = NULL; 312860422Sken 312960422Sken ccb = cdgetccb(periph, /* priority */ 1); 313060422Sken 313160422Sken switch(authinfo->format) { 313260422Sken case DVD_SEND_CHALLENGE: { 313360422Sken struct scsi_report_key_data_challenge *challenge_data; 313460422Sken 313560422Sken length = sizeof(*challenge_data); 313660422Sken 313767888Sdwmalone challenge_data = malloc(length, M_DEVBUF, M_WAITOK | M_ZERO); 313860422Sken 313960422Sken databuf = (u_int8_t *)challenge_data; 314060422Sken 314160422Sken scsi_ulto2b(length - sizeof(challenge_data->data_len), 314260422Sken challenge_data->data_len); 314360422Sken 314460422Sken bcopy(authinfo->keychal, challenge_data->challenge_key, 314560422Sken min(sizeof(authinfo->keychal), 314660422Sken sizeof(challenge_data->challenge_key))); 314760422Sken break; 314860422Sken } 314960422Sken case DVD_SEND_KEY2: { 315060422Sken struct scsi_report_key_data_key1_key2 *key2_data; 315160422Sken 315260422Sken length = sizeof(*key2_data); 315360422Sken 315467888Sdwmalone key2_data = malloc(length, M_DEVBUF, M_WAITOK | M_ZERO); 315560422Sken 315660422Sken databuf = (u_int8_t *)key2_data; 315760422Sken 315860422Sken scsi_ulto2b(length - sizeof(key2_data->data_len), 315960422Sken key2_data->data_len); 316060422Sken 316160422Sken bcopy(authinfo->keychal, key2_data->key1, 316260422Sken min(sizeof(authinfo->keychal), sizeof(key2_data->key1))); 316360422Sken 316460422Sken break; 316560422Sken } 316660422Sken case DVD_SEND_RPC: { 316760422Sken struct scsi_send_key_data_rpc *rpc_data; 316860422Sken 316960422Sken length = sizeof(*rpc_data); 317060422Sken 317167888Sdwmalone rpc_data = malloc(length, M_DEVBUF, M_WAITOK | M_ZERO); 317260422Sken 317360422Sken databuf = (u_int8_t *)rpc_data; 317460422Sken 317560422Sken scsi_ulto2b(length - sizeof(rpc_data->data_len), 317660422Sken rpc_data->data_len); 317760422Sken 317860422Sken rpc_data->region_code = authinfo->region; 317960422Sken break; 318060422Sken } 318160422Sken default: 318260422Sken error = EINVAL; 318360422Sken goto bailout; 318460422Sken break; /* NOTREACHED */ 318560422Sken } 318660422Sken 318760422Sken scsi_send_key(&ccb->csio, 318860422Sken /* retries */ 1, 318960422Sken /* cbfcnp */ cddone, 319060422Sken /* tag_action */ MSG_SIMPLE_Q_TAG, 319160422Sken /* agid */ authinfo->agid, 319260422Sken /* key_format */ authinfo->format, 319360422Sken /* data_ptr */ databuf, 319460422Sken /* dxfer_len */ length, 319560422Sken /* sense_len */ SSD_FULL_SIZE, 319660422Sken /* timeout */ 50000); 319760422Sken 319874840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 319974840Sken /*sense_flags*/SF_RETRY_UA); 320060422Sken 320160422Skenbailout: 320260422Sken 320360422Sken if (databuf != NULL) 320460422Sken free(databuf, M_DEVBUF); 320560422Sken 320660422Sken xpt_release_ccb(ccb); 320760422Sken 320860422Sken return(error); 320960422Sken} 321060422Sken 321160422Skenstatic int 321260422Skencdreaddvdstructure(struct cam_periph *periph, struct dvd_struct *dvdstruct) 321360422Sken{ 321460422Sken union ccb *ccb; 321560422Sken u_int8_t *databuf; 321660422Sken u_int32_t address; 321760422Sken int error; 321860422Sken int length; 321960422Sken 322060422Sken error = 0; 322160422Sken databuf = NULL; 322260422Sken /* The address is reserved for many of the formats */ 322360422Sken address = 0; 322460422Sken 322560422Sken ccb = cdgetccb(periph, /* priority */ 1); 322660422Sken 322760422Sken switch(dvdstruct->format) { 322860422Sken case DVD_STRUCT_PHYSICAL: 322960422Sken length = sizeof(struct scsi_read_dvd_struct_data_physical); 323060422Sken break; 323160422Sken case DVD_STRUCT_COPYRIGHT: 323260422Sken length = sizeof(struct scsi_read_dvd_struct_data_copyright); 323360422Sken break; 323460422Sken case DVD_STRUCT_DISCKEY: 323560422Sken length = sizeof(struct scsi_read_dvd_struct_data_disc_key); 323660422Sken break; 323760422Sken case DVD_STRUCT_BCA: 323860422Sken length = sizeof(struct scsi_read_dvd_struct_data_bca); 323960422Sken break; 324060422Sken case DVD_STRUCT_MANUFACT: 324160422Sken length = sizeof(struct scsi_read_dvd_struct_data_manufacturer); 324260422Sken break; 324360422Sken case DVD_STRUCT_CMI: 324460422Sken error = ENODEV; 324560422Sken goto bailout; 324660422Sken#ifdef notyet 324760422Sken length = sizeof(struct scsi_read_dvd_struct_data_copy_manage); 324860422Sken address = dvdstruct->address; 324960422Sken#endif 325060422Sken break; /* NOTREACHED */ 325160422Sken case DVD_STRUCT_PROTDISCID: 325260422Sken length = sizeof(struct scsi_read_dvd_struct_data_prot_discid); 325360422Sken break; 325460422Sken case DVD_STRUCT_DISCKEYBLOCK: 325560422Sken length = sizeof(struct scsi_read_dvd_struct_data_disc_key_blk); 325660422Sken break; 325760422Sken case DVD_STRUCT_DDS: 325860422Sken length = sizeof(struct scsi_read_dvd_struct_data_dds); 325960422Sken break; 326060422Sken case DVD_STRUCT_MEDIUM_STAT: 326160422Sken length = sizeof(struct scsi_read_dvd_struct_data_medium_status); 326260422Sken break; 326360422Sken case DVD_STRUCT_SPARE_AREA: 326460422Sken length = sizeof(struct scsi_read_dvd_struct_data_spare_area); 326560422Sken break; 326660422Sken case DVD_STRUCT_RMD_LAST: 326760422Sken error = ENODEV; 326860422Sken goto bailout; 326960422Sken#ifdef notyet 327060422Sken length = sizeof(struct scsi_read_dvd_struct_data_rmd_borderout); 327160422Sken address = dvdstruct->address; 327260422Sken#endif 327360422Sken break; /* NOTREACHED */ 327460422Sken case DVD_STRUCT_RMD_RMA: 327560422Sken error = ENODEV; 327660422Sken goto bailout; 327760422Sken#ifdef notyet 327860422Sken length = sizeof(struct scsi_read_dvd_struct_data_rmd); 327960422Sken address = dvdstruct->address; 328060422Sken#endif 328160422Sken break; /* NOTREACHED */ 328260422Sken case DVD_STRUCT_PRERECORDED: 328360422Sken length = sizeof(struct scsi_read_dvd_struct_data_leadin); 328460422Sken break; 328560422Sken case DVD_STRUCT_UNIQUEID: 328660422Sken length = sizeof(struct scsi_read_dvd_struct_data_disc_id); 328760422Sken break; 328860422Sken case DVD_STRUCT_DCB: 328960422Sken error = ENODEV; 329060422Sken goto bailout; 329160422Sken#ifdef notyet 329260422Sken length = sizeof(struct scsi_read_dvd_struct_data_dcb); 329360422Sken address = dvdstruct->address; 329460422Sken#endif 329560422Sken break; /* NOTREACHED */ 329660422Sken case DVD_STRUCT_LIST: 329760422Sken /* 329860422Sken * This is the maximum allocation length for the READ DVD 329960422Sken * STRUCTURE command. There's nothing in the MMC3 spec 330060422Sken * that indicates a limit in the amount of data that can 330160422Sken * be returned from this call, other than the limits 330260422Sken * imposed by the 2-byte length variables. 330360422Sken */ 330460422Sken length = 65535; 330560422Sken break; 330660422Sken default: 330760422Sken error = EINVAL; 330860422Sken goto bailout; 330960422Sken break; /* NOTREACHED */ 331060422Sken } 331160422Sken 331260422Sken if (length != 0) { 331367888Sdwmalone databuf = malloc(length, M_DEVBUF, M_WAITOK | M_ZERO); 331460422Sken } else 331560422Sken databuf = NULL; 331660422Sken 331760422Sken scsi_read_dvd_structure(&ccb->csio, 331860422Sken /* retries */ 1, 331960422Sken /* cbfcnp */ cddone, 332060422Sken /* tag_action */ MSG_SIMPLE_Q_TAG, 332160422Sken /* lba */ address, 332260422Sken /* layer_number */ dvdstruct->layer_num, 332360422Sken /* key_format */ dvdstruct->format, 332460422Sken /* agid */ dvdstruct->agid, 332560422Sken /* data_ptr */ databuf, 332660422Sken /* dxfer_len */ length, 332760422Sken /* sense_len */ SSD_FULL_SIZE, 332860422Sken /* timeout */ 50000); 332960422Sken 333074840Sken error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, 333174840Sken /*sense_flags*/SF_RETRY_UA); 333260422Sken 333360422Sken if (error != 0) 333460422Sken goto bailout; 333560422Sken 333660422Sken switch(dvdstruct->format) { 333760422Sken case DVD_STRUCT_PHYSICAL: { 333860422Sken struct scsi_read_dvd_struct_data_layer_desc *inlayer; 333960422Sken struct dvd_layer *outlayer; 334060422Sken struct scsi_read_dvd_struct_data_physical *phys_data; 334160422Sken 334260422Sken phys_data = 334360422Sken (struct scsi_read_dvd_struct_data_physical *)databuf; 334460422Sken inlayer = &phys_data->layer_desc; 334560422Sken outlayer = (struct dvd_layer *)&dvdstruct->data; 334660422Sken 334760422Sken dvdstruct->length = sizeof(*inlayer); 334860422Sken 334960422Sken outlayer->book_type = (inlayer->book_type_version & 335060422Sken RDSD_BOOK_TYPE_MASK) >> RDSD_BOOK_TYPE_SHIFT; 335160422Sken outlayer->book_version = (inlayer->book_type_version & 335260422Sken RDSD_BOOK_VERSION_MASK); 335360422Sken outlayer->disc_size = (inlayer->disc_size_max_rate & 335460422Sken RDSD_DISC_SIZE_MASK) >> RDSD_DISC_SIZE_SHIFT; 335560422Sken outlayer->max_rate = (inlayer->disc_size_max_rate & 335660422Sken RDSD_MAX_RATE_MASK); 335760422Sken outlayer->nlayers = (inlayer->layer_info & 335860422Sken RDSD_NUM_LAYERS_MASK) >> RDSD_NUM_LAYERS_SHIFT; 335960422Sken outlayer->track_path = (inlayer->layer_info & 336060422Sken RDSD_TRACK_PATH_MASK) >> RDSD_TRACK_PATH_SHIFT; 336160422Sken outlayer->layer_type = (inlayer->layer_info & 336260422Sken RDSD_LAYER_TYPE_MASK); 336360422Sken outlayer->linear_density = (inlayer->density & 336460422Sken RDSD_LIN_DENSITY_MASK) >> RDSD_LIN_DENSITY_SHIFT; 336560422Sken outlayer->track_density = (inlayer->density & 336660422Sken RDSD_TRACK_DENSITY_MASK); 336760422Sken outlayer->bca = (inlayer->bca & RDSD_BCA_MASK) >> 336860422Sken RDSD_BCA_SHIFT; 336960422Sken outlayer->start_sector = scsi_3btoul(inlayer->main_data_start); 337060422Sken outlayer->end_sector = scsi_3btoul(inlayer->main_data_end); 337160422Sken outlayer->end_sector_l0 = 337260422Sken scsi_3btoul(inlayer->end_sector_layer0); 337360422Sken break; 337460422Sken } 337560422Sken case DVD_STRUCT_COPYRIGHT: { 337660422Sken struct scsi_read_dvd_struct_data_copyright *copy_data; 337760422Sken 337860422Sken copy_data = (struct scsi_read_dvd_struct_data_copyright *) 337960422Sken databuf; 338060422Sken 338160422Sken dvdstruct->cpst = copy_data->cps_type; 338260422Sken dvdstruct->rmi = copy_data->region_info; 338360422Sken dvdstruct->length = 0; 338460422Sken 338560422Sken break; 338660422Sken } 338760422Sken default: 338860422Sken /* 338960422Sken * Tell the user what the overall length is, no matter 339060422Sken * what we can actually fit in the data buffer. 339160422Sken */ 339260422Sken dvdstruct->length = length - ccb->csio.resid - 339360422Sken sizeof(struct scsi_read_dvd_struct_data_header); 339460422Sken 339560422Sken /* 339660422Sken * But only actually copy out the smaller of what we read 339760422Sken * in or what the structure can take. 339860422Sken */ 339960422Sken bcopy(databuf + sizeof(struct scsi_read_dvd_struct_data_header), 340060422Sken dvdstruct->data, 340160422Sken min(sizeof(dvdstruct->data), dvdstruct->length)); 340260422Sken break; 340360422Sken } 340460422Skenbailout: 340560422Sken 340660422Sken if (databuf != NULL) 340760422Sken free(databuf, M_DEVBUF); 340860422Sken 340960422Sken xpt_release_ccb(ccb); 341060422Sken 341160422Sken return(error); 341260422Sken} 341360422Sken 341460422Skenvoid 341560422Skenscsi_report_key(struct ccb_scsiio *csio, u_int32_t retries, 341660422Sken void (*cbfcnp)(struct cam_periph *, union ccb *), 341760422Sken u_int8_t tag_action, u_int32_t lba, u_int8_t agid, 341860422Sken u_int8_t key_format, u_int8_t *data_ptr, u_int32_t dxfer_len, 341960422Sken u_int8_t sense_len, u_int32_t timeout) 342060422Sken{ 342160422Sken struct scsi_report_key *scsi_cmd; 342260422Sken 342360422Sken scsi_cmd = (struct scsi_report_key *)&csio->cdb_io.cdb_bytes; 342460422Sken bzero(scsi_cmd, sizeof(*scsi_cmd)); 342560422Sken scsi_cmd->opcode = REPORT_KEY; 342660422Sken scsi_ulto4b(lba, scsi_cmd->lba); 342760422Sken scsi_ulto2b(dxfer_len, scsi_cmd->alloc_len); 342860422Sken scsi_cmd->agid_keyformat = (agid << RK_KF_AGID_SHIFT) | 342960422Sken (key_format & RK_KF_KEYFORMAT_MASK); 343060422Sken 343160422Sken cam_fill_csio(csio, 343260422Sken retries, 343360422Sken cbfcnp, 343460422Sken /*flags*/ (dxfer_len == 0) ? CAM_DIR_NONE : CAM_DIR_IN, 343560422Sken tag_action, 343660422Sken /*data_ptr*/ data_ptr, 343760422Sken /*dxfer_len*/ dxfer_len, 343860422Sken sense_len, 343960422Sken sizeof(*scsi_cmd), 344060422Sken timeout); 344160422Sken} 344260422Sken 344360422Skenvoid 344460422Skenscsi_send_key(struct ccb_scsiio *csio, u_int32_t retries, 344560422Sken void (*cbfcnp)(struct cam_periph *, union ccb *), 344660422Sken u_int8_t tag_action, u_int8_t agid, u_int8_t key_format, 344760422Sken u_int8_t *data_ptr, u_int32_t dxfer_len, u_int8_t sense_len, 344860422Sken u_int32_t timeout) 344960422Sken{ 345060422Sken struct scsi_send_key *scsi_cmd; 345160422Sken 345260422Sken scsi_cmd = (struct scsi_send_key *)&csio->cdb_io.cdb_bytes; 345360422Sken bzero(scsi_cmd, sizeof(*scsi_cmd)); 345460422Sken scsi_cmd->opcode = SEND_KEY; 345560422Sken 345660422Sken scsi_ulto2b(dxfer_len, scsi_cmd->param_len); 345760422Sken scsi_cmd->agid_keyformat = (agid << RK_KF_AGID_SHIFT) | 345860422Sken (key_format & RK_KF_KEYFORMAT_MASK); 345960422Sken 346060422Sken cam_fill_csio(csio, 346160422Sken retries, 346260422Sken cbfcnp, 346360422Sken /*flags*/ CAM_DIR_OUT, 346460422Sken tag_action, 346560422Sken /*data_ptr*/ data_ptr, 346660422Sken /*dxfer_len*/ dxfer_len, 346760422Sken sense_len, 346860422Sken sizeof(*scsi_cmd), 346960422Sken timeout); 347060422Sken} 347160422Sken 347260422Sken 347360422Skenvoid 347460422Skenscsi_read_dvd_structure(struct ccb_scsiio *csio, u_int32_t retries, 347560422Sken void (*cbfcnp)(struct cam_periph *, union ccb *), 347660422Sken u_int8_t tag_action, u_int32_t address, 347760422Sken u_int8_t layer_number, u_int8_t format, u_int8_t agid, 347860422Sken u_int8_t *data_ptr, u_int32_t dxfer_len, 347960422Sken u_int8_t sense_len, u_int32_t timeout) 348060422Sken{ 348160422Sken struct scsi_read_dvd_structure *scsi_cmd; 348260422Sken 348360422Sken scsi_cmd = (struct scsi_read_dvd_structure *)&csio->cdb_io.cdb_bytes; 348460422Sken bzero(scsi_cmd, sizeof(*scsi_cmd)); 348560422Sken scsi_cmd->opcode = READ_DVD_STRUCTURE; 348660422Sken 348760422Sken scsi_ulto4b(address, scsi_cmd->address); 348860422Sken scsi_cmd->layer_number = layer_number; 348960422Sken scsi_cmd->format = format; 349060422Sken scsi_ulto2b(dxfer_len, scsi_cmd->alloc_len); 349160422Sken /* The AGID is the top two bits of this byte */ 349260422Sken scsi_cmd->agid = agid << 6; 349360422Sken 349460422Sken cam_fill_csio(csio, 349560422Sken retries, 349660422Sken cbfcnp, 349760422Sken /*flags*/ CAM_DIR_IN, 349860422Sken tag_action, 349960422Sken /*data_ptr*/ data_ptr, 350060422Sken /*dxfer_len*/ dxfer_len, 350160422Sken sense_len, 350260422Sken sizeof(*scsi_cmd), 350360422Sken timeout); 350460422Sken} 3505