scsi_cd.c revision 47413
139213Sgibbs/* 239213Sgibbs * Copyright (c) 1997 Justin T. Gibbs. 343819Sken * Copyright (c) 1997, 1998, 1999 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 * 2747413Sgibbs * $Id: scsi_cd.c,v 1.20 1999/05/09 01:25:24 ken Exp $ 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> 5439213Sgibbs#include <sys/buf.h> 5539213Sgibbs#include <sys/dkbad.h> 5639213Sgibbs#include <sys/disklabel.h> 5739213Sgibbs#include <sys/diskslice.h> 5839213Sgibbs#include <sys/malloc.h> 5939213Sgibbs#include <sys/conf.h> 6039213Sgibbs#include <sys/cdio.h> 6139213Sgibbs#include <sys/devicestat.h> 6239213Sgibbs#include <sys/sysctl.h> 6339213Sgibbs 6439213Sgibbs#include <cam/cam.h> 6539213Sgibbs#include <cam/cam_ccb.h> 6639213Sgibbs#include <cam/cam_extend.h> 6739213Sgibbs#include <cam/cam_periph.h> 6839213Sgibbs#include <cam/cam_xpt_periph.h> 6939213Sgibbs#include <cam/cam_queue.h> 7039213Sgibbs 7139213Sgibbs#include <cam/scsi/scsi_message.h> 7239213Sgibbs#include <cam/scsi/scsi_da.h> 7339213Sgibbs#include <cam/scsi/scsi_cd.h> 7439213Sgibbs 7539213Sgibbs#define LEADOUT 0xaa /* leadout toc entry */ 7639213Sgibbs 7739213Sgibbsstruct cd_params { 7839213Sgibbs u_int32_t blksize; 7939213Sgibbs u_long disksize; 8039213Sgibbs}; 8139213Sgibbs 8239213Sgibbstypedef enum { 8339213Sgibbs CD_Q_NONE = 0x00, 8439213Sgibbs CD_Q_NO_TOUCH = 0x01, 8539213Sgibbs CD_Q_BCD_TRACKS = 0x02, 8639213Sgibbs CD_Q_NO_CHANGER = 0x04, 8739213Sgibbs CD_Q_CHANGER = 0x08 8839213Sgibbs} cd_quirks; 8939213Sgibbs 9039213Sgibbstypedef enum { 9139213Sgibbs CD_FLAG_INVALID = 0x001, 9239213Sgibbs CD_FLAG_NEW_DISC = 0x002, 9339213Sgibbs CD_FLAG_DISC_LOCKED = 0x004, 9439213Sgibbs CD_FLAG_DISC_REMOVABLE = 0x008, 9539213Sgibbs CD_FLAG_TAGGED_QUEUING = 0x010, 9639213Sgibbs CD_FLAG_OPEN = 0x020, 9739213Sgibbs CD_FLAG_CHANGER = 0x040, 9839213Sgibbs CD_FLAG_ACTIVE = 0x080, 9939213Sgibbs CD_FLAG_SCHED_ON_COMP = 0x100, 10039213Sgibbs CD_FLAG_RETRY_UA = 0x200 10139213Sgibbs} cd_flags; 10239213Sgibbs 10339213Sgibbstypedef enum { 10439213Sgibbs CD_CCB_PROBE = 0x01, 10539213Sgibbs CD_CCB_BUFFER_IO = 0x02, 10639213Sgibbs CD_CCB_WAITING = 0x03, 10739213Sgibbs CD_CCB_TYPE_MASK = 0x0F, 10839213Sgibbs CD_CCB_RETRY_UA = 0x10 10939213Sgibbs} cd_ccb_state; 11039213Sgibbs 11139213Sgibbstypedef enum { 11239213Sgibbs CHANGER_TIMEOUT_SCHED = 0x01, 11339213Sgibbs CHANGER_SHORT_TMOUT_SCHED = 0x02, 11439213Sgibbs CHANGER_MANUAL_CALL = 0x04, 11539213Sgibbs CHANGER_NEED_TIMEOUT = 0x08 11639213Sgibbs} cd_changer_flags; 11739213Sgibbs 11839213Sgibbs#define ccb_state ppriv_field0 11939213Sgibbs#define ccb_bp ppriv_ptr1 12039213Sgibbs 12139213Sgibbstypedef enum { 12239213Sgibbs CD_STATE_PROBE, 12339213Sgibbs CD_STATE_NORMAL 12439213Sgibbs} cd_state; 12539213Sgibbs 12639213Sgibbsstruct cd_softc { 12739213Sgibbs cam_pinfo pinfo; 12839213Sgibbs cd_state state; 12946581Sken volatile cd_flags flags; 13039213Sgibbs struct buf_queue_head buf_queue; 13139213Sgibbs LIST_HEAD(, ccb_hdr) pending_ccbs; 13239213Sgibbs struct cd_params params; 13339213Sgibbs struct diskslices *cd_slices; 13439213Sgibbs union ccb saved_ccb; 13539213Sgibbs cd_quirks quirks; 13639213Sgibbs struct devstat device_stats; 13739213Sgibbs STAILQ_ENTRY(cd_softc) changer_links; 13839213Sgibbs struct cdchanger *changer; 13939213Sgibbs int bufs_left; 14039213Sgibbs struct cam_periph *periph; 14139213Sgibbs}; 14239213Sgibbs 14339213Sgibbsstruct cd_quirk_entry { 14439213Sgibbs struct scsi_inquiry_pattern inq_pat; 14539213Sgibbs cd_quirks quirks; 14639213Sgibbs}; 14739213Sgibbs 14839213Sgibbs/* 14939213Sgibbs * These quirk entries aren't strictly necessary. Basically, what they do 15039213Sgibbs * is tell cdregister() up front that a device is a changer. Otherwise, it 15139213Sgibbs * will figure that fact out once it sees a LUN on the device that is 15239213Sgibbs * greater than 0. If it is known up front that a device is a changer, all 15339213Sgibbs * I/O to the device will go through the changer scheduling routines, as 15439213Sgibbs * opposed to the "normal" CD code. 15539213Sgibbs */ 15639213Sgibbsstatic struct cd_quirk_entry cd_quirk_table[] = 15739213Sgibbs{ 15839213Sgibbs { 15939213Sgibbs { T_CDROM, SIP_MEDIA_REMOVABLE, "NRC", "MBR-7", "*"}, 16039213Sgibbs /*quirks*/ CD_Q_CHANGER 16139213Sgibbs }, 16239213Sgibbs { 16339213Sgibbs { T_CDROM, SIP_MEDIA_REMOVABLE, "PIONEER", "CD-ROM DRM-604X", 16439213Sgibbs "*"}, /* quirks */ CD_Q_CHANGER 16540262Sken }, 16640262Sken { 16740262Sken { T_CDROM, SIP_MEDIA_REMOVABLE, "CHINON", "CD-ROM CDS-535","*"}, 16840262Sken /* quirks */ CD_Q_BCD_TRACKS 16939213Sgibbs } 17039213Sgibbs}; 17139213Sgibbs 17239213Sgibbs#ifndef MIN 17339213Sgibbs#define MIN(x,y) ((x<y) ? x : y) 17439213Sgibbs#endif 17539213Sgibbs 17639213Sgibbs#define CD_CDEV_MAJOR 15 17739213Sgibbs#define CD_BDEV_MAJOR 6 17839213Sgibbs 17939213Sgibbsstatic d_open_t cdopen; 18039213Sgibbsstatic d_close_t cdclose; 18139213Sgibbsstatic d_ioctl_t cdioctl; 18239213Sgibbsstatic d_strategy_t cdstrategy; 18340020Skenstatic d_strategy_t cdstrategy1; 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); 23339213Sgibbs 23439213Sgibbsstatic struct periph_driver cddriver = 23539213Sgibbs{ 23639213Sgibbs cdinit, "cd", 23739213Sgibbs TAILQ_HEAD_INITIALIZER(cddriver.units), /* generation */ 0 23839213Sgibbs}; 23939213Sgibbs 24039213SgibbsDATA_SET(periphdriver_set, cddriver); 24139213Sgibbs 24239213Sgibbs/* For 2.2-stable support */ 24339213Sgibbs#ifndef D_DISK 24439213Sgibbs#define D_DISK 0 24539213Sgibbs#endif 24639213Sgibbsstatic struct cdevsw cd_cdevsw = 24739213Sgibbs{ 24839213Sgibbs /*d_open*/ cdopen, 24939213Sgibbs /*d_close*/ cdclose, 25046625Sphk /*d_read*/ physread, 25139213Sgibbs /*d_write*/ nowrite, 25239213Sgibbs /*d_ioctl*/ cdioctl, 25339213Sgibbs /*d_stop*/ nostop, 25439213Sgibbs /*d_reset*/ noreset, 25539213Sgibbs /*d_devtotty*/ nodevtotty, 25639213Sgibbs /*d_poll*/ seltrue, 25739213Sgibbs /*d_mmap*/ nommap, 25839213Sgibbs /*d_strategy*/ cdstrategy, 25939213Sgibbs /*d_name*/ "cd", 26039213Sgibbs /*d_spare*/ NULL, 26139213Sgibbs /*d_maj*/ -1, 26239213Sgibbs /*d_dump*/ nodump, 26339213Sgibbs /*d_psize*/ nopsize, 26439213Sgibbs /*d_flags*/ D_DISK, 26539213Sgibbs /*d_maxio*/ 0, 26639213Sgibbs /*b_maj*/ -1 26739213Sgibbs}; 26839213Sgibbs 26939213Sgibbsstatic struct extend_array *cdperiphs; 27039213Sgibbsstatic int num_changers; 27139213Sgibbs 27239213Sgibbs#ifndef CHANGER_MIN_BUSY_SECONDS 27346747Sken#define CHANGER_MIN_BUSY_SECONDS 5 27439213Sgibbs#endif 27539213Sgibbs#ifndef CHANGER_MAX_BUSY_SECONDS 27646747Sken#define CHANGER_MAX_BUSY_SECONDS 15 27739213Sgibbs#endif 27839213Sgibbs 27939213Sgibbsstatic int changer_min_busy_seconds = CHANGER_MIN_BUSY_SECONDS; 28039213Sgibbsstatic int changer_max_busy_seconds = CHANGER_MAX_BUSY_SECONDS; 28139213Sgibbs 28239213Sgibbs/* 28339213Sgibbs * XXX KDM this CAM node should be moved if we ever get more CAM sysctl 28439213Sgibbs * variables. 28539213Sgibbs */ 28639213SgibbsSYSCTL_NODE(_kern, OID_AUTO, cam, CTLFLAG_RD, 0, "CAM Subsystem"); 28739213SgibbsSYSCTL_NODE(_kern_cam, OID_AUTO, cd, CTLFLAG_RD, 0, "CAM CDROM driver"); 28839213SgibbsSYSCTL_NODE(_kern_cam_cd, OID_AUTO, changer, CTLFLAG_RD, 0, "CD Changer"); 28939213SgibbsSYSCTL_INT(_kern_cam_cd_changer, OID_AUTO, min_busy_seconds, CTLFLAG_RW, 29039213Sgibbs &changer_min_busy_seconds, 0, "Minimum changer scheduling quantum"); 29139213SgibbsSYSCTL_INT(_kern_cam_cd_changer, OID_AUTO, max_busy_seconds, CTLFLAG_RW, 29239213Sgibbs &changer_max_busy_seconds, 0, "Maximum changer scheduling quantum"); 29339213Sgibbs 29439213Sgibbsstruct cdchanger { 29539213Sgibbs path_id_t path_id; 29639213Sgibbs target_id_t target_id; 29739213Sgibbs int num_devices; 29839213Sgibbs struct camq devq; 29939213Sgibbs struct timeval start_time; 30039213Sgibbs struct cd_softc *cur_device; 30139213Sgibbs struct callout_handle short_handle; 30239213Sgibbs struct callout_handle long_handle; 30346581Sken volatile cd_changer_flags flags; 30439213Sgibbs STAILQ_ENTRY(cdchanger) changer_links; 30539213Sgibbs STAILQ_HEAD(chdevlist, cd_softc) chluns; 30639213Sgibbs}; 30739213Sgibbs 30842017Seivindstatic STAILQ_HEAD(changerlist, cdchanger) changerq; 30939213Sgibbs 31039213Sgibbsvoid 31139213Sgibbscdinit(void) 31239213Sgibbs{ 31339213Sgibbs cam_status status; 31439213Sgibbs struct cam_path *path; 31539213Sgibbs 31639213Sgibbs /* 31739213Sgibbs * Create our extend array for storing the devices we attach to. 31839213Sgibbs */ 31939213Sgibbs cdperiphs = cam_extend_new(); 32039213Sgibbs if (cdperiphs == NULL) { 32139213Sgibbs printf("cd: Failed to alloc extend array!\n"); 32239213Sgibbs return; 32339213Sgibbs } 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 } else { 34939213Sgibbs /* If we were successfull, register our devsw */ 35039213Sgibbs cdevsw_add_generic(CD_BDEV_MAJOR, CD_CDEV_MAJOR, &cd_cdevsw); 35139213Sgibbs } 35239213Sgibbs} 35339213Sgibbs 35439213Sgibbsstatic void 35540603Skencdoninvalidate(struct cam_periph *periph) 35640603Sken{ 35740603Sken int s; 35840603Sken struct cd_softc *softc; 35940603Sken struct buf *q_bp; 36040603Sken struct ccb_setasync csa; 36140603Sken 36240603Sken softc = (struct cd_softc *)periph->softc; 36340603Sken 36440603Sken /* 36540603Sken * De-register any async callbacks. 36640603Sken */ 36740603Sken xpt_setup_ccb(&csa.ccb_h, periph->path, 36840603Sken /* priority */ 5); 36940603Sken csa.ccb_h.func_code = XPT_SASYNC_CB; 37040603Sken csa.event_enable = 0; 37140603Sken csa.callback = cdasync; 37240603Sken csa.callback_arg = periph; 37340603Sken xpt_action((union ccb *)&csa); 37440603Sken 37540603Sken softc->flags |= CD_FLAG_INVALID; 37640603Sken 37740603Sken /* 37840603Sken * Although the oninvalidate() routines are always called at 37940603Sken * splsoftcam, we need to be at splbio() here to keep the buffer 38040603Sken * queue from being modified while we traverse it. 38140603Sken */ 38240603Sken s = splbio(); 38340603Sken 38440603Sken /* 38540603Sken * Return all queued I/O with ENXIO. 38640603Sken * XXX Handle any transactions queued to the card 38740603Sken * with XPT_ABORT_CCB. 38840603Sken */ 38940603Sken while ((q_bp = bufq_first(&softc->buf_queue)) != NULL){ 39040603Sken bufq_remove(&softc->buf_queue, q_bp); 39140603Sken q_bp->b_resid = q_bp->b_bcount; 39240603Sken q_bp->b_error = ENXIO; 39340603Sken q_bp->b_flags |= B_ERROR; 39440603Sken biodone(q_bp); 39540603Sken } 39640603Sken splx(s); 39740603Sken 39840603Sken /* 39940603Sken * If this device is part of a changer, and it was scheduled 40040603Sken * to run, remove it from the run queue since we just nuked 40140603Sken * all of its scheduled I/O. 40240603Sken */ 40340603Sken if ((softc->flags & CD_FLAG_CHANGER) 40440603Sken && (softc->pinfo.index != CAM_UNQUEUED_INDEX)) 40540603Sken camq_remove(&softc->changer->devq, softc->pinfo.index); 40640603Sken 40740603Sken xpt_print_path(periph->path); 40840603Sken printf("lost device\n"); 40940603Sken} 41040603Sken 41140603Skenstatic void 41239213Sgibbscdcleanup(struct cam_periph *periph) 41339213Sgibbs{ 41439213Sgibbs struct cd_softc *softc; 41540603Sken int s; 41639213Sgibbs 41739213Sgibbs softc = (struct cd_softc *)periph->softc; 41839213Sgibbs 41939213Sgibbs xpt_print_path(periph->path); 42039213Sgibbs printf("removing device entry\n"); 42140603Sken 42240603Sken s = splsoftcam(); 42339213Sgibbs /* 42439213Sgibbs * In the queued, non-active case, the device in question 42539213Sgibbs * has already been removed from the changer run queue. Since this 42639213Sgibbs * device is active, we need to de-activate it, and schedule 42739213Sgibbs * another device to run. (if there is another one to run) 42839213Sgibbs */ 42939213Sgibbs if ((softc->flags & CD_FLAG_CHANGER) 43039213Sgibbs && (softc->flags & CD_FLAG_ACTIVE)) { 43139213Sgibbs 43239213Sgibbs /* 43339213Sgibbs * The purpose of the short timeout is soley to determine 43439213Sgibbs * whether the current device has finished or not. Well, 43539213Sgibbs * since we're removing the active device, we know that it 43639213Sgibbs * is finished. So, get rid of the short timeout. 43739213Sgibbs * Otherwise, if we're in the time period before the short 43839213Sgibbs * timeout fires, and there are no other devices in the 43939213Sgibbs * queue to run, there won't be any other device put in the 44039213Sgibbs * active slot. i.e., when we call cdrunchangerqueue() 44139213Sgibbs * below, it won't do anything. Then, when the short 44239213Sgibbs * timeout fires, it'll look at the "current device", which 44339213Sgibbs * we are free below, and possibly panic the kernel on a 44439213Sgibbs * bogus pointer reference. 44539213Sgibbs * 44639213Sgibbs * The long timeout doesn't really matter, since we 44739213Sgibbs * decrement the qfrozen_cnt to indicate that there is 44839213Sgibbs * nothing in the active slot now. Therefore, there won't 44939213Sgibbs * be any bogus pointer references there. 45039213Sgibbs */ 45139213Sgibbs if (softc->changer->flags & CHANGER_SHORT_TMOUT_SCHED) { 45239213Sgibbs untimeout(cdshorttimeout, softc->changer, 45339213Sgibbs softc->changer->short_handle); 45439213Sgibbs softc->changer->flags &= ~CHANGER_SHORT_TMOUT_SCHED; 45539213Sgibbs } 45639213Sgibbs softc->changer->devq.qfrozen_cnt--; 45739213Sgibbs softc->changer->flags |= CHANGER_MANUAL_CALL; 45839213Sgibbs cdrunchangerqueue(softc->changer); 45939213Sgibbs } 46039213Sgibbs 46139213Sgibbs /* 46239213Sgibbs * If we're removing the last device on the changer, go ahead and 46339213Sgibbs * remove the changer device structure. 46439213Sgibbs */ 46539213Sgibbs if ((softc->flags & CD_FLAG_CHANGER) 46639213Sgibbs && (--softc->changer->num_devices == 0)) { 46739213Sgibbs 46839213Sgibbs /* 46939213Sgibbs * Theoretically, there shouldn't be any timeouts left, but 47039213Sgibbs * I'm not completely sure that that will be the case. So, 47139213Sgibbs * it won't hurt to check and see if there are any left. 47239213Sgibbs */ 47339213Sgibbs if (softc->changer->flags & CHANGER_TIMEOUT_SCHED) { 47439213Sgibbs untimeout(cdrunchangerqueue, softc->changer, 47539213Sgibbs softc->changer->long_handle); 47639213Sgibbs softc->changer->flags &= ~CHANGER_TIMEOUT_SCHED; 47739213Sgibbs } 47839213Sgibbs 47939213Sgibbs if (softc->changer->flags & CHANGER_SHORT_TMOUT_SCHED) { 48039213Sgibbs untimeout(cdshorttimeout, softc->changer, 48139213Sgibbs softc->changer->short_handle); 48239213Sgibbs softc->changer->flags &= ~CHANGER_SHORT_TMOUT_SCHED; 48339213Sgibbs } 48439213Sgibbs 48539213Sgibbs STAILQ_REMOVE(&changerq, softc->changer, cdchanger, 48639213Sgibbs changer_links); 48739213Sgibbs xpt_print_path(periph->path); 48839213Sgibbs printf("removing changer entry\n"); 48939213Sgibbs free(softc->changer, M_DEVBUF); 49039213Sgibbs num_changers--; 49139213Sgibbs } 49240603Sken devstat_remove_entry(&softc->device_stats); 49339213Sgibbs cam_extend_release(cdperiphs, periph->unit_number); 49440603Sken free(softc, M_DEVBUF); 49540603Sken splx(s); 49639213Sgibbs} 49739213Sgibbs 49839213Sgibbsstatic void 49939213Sgibbscdasync(void *callback_arg, u_int32_t code, 50039213Sgibbs struct cam_path *path, void *arg) 50139213Sgibbs{ 50239213Sgibbs struct cam_periph *periph; 50339213Sgibbs 50439213Sgibbs periph = (struct cam_periph *)callback_arg; 50539213Sgibbs switch (code) { 50639213Sgibbs case AC_FOUND_DEVICE: 50739213Sgibbs { 50839213Sgibbs struct ccb_getdev *cgd; 50939213Sgibbs cam_status status; 51039213Sgibbs 51139213Sgibbs cgd = (struct ccb_getdev *)arg; 51239213Sgibbs 51339213Sgibbs if ((cgd->pd_type != T_CDROM) && (cgd->pd_type != T_WORM)) 51439213Sgibbs break; 51539213Sgibbs 51639213Sgibbs /* 51739213Sgibbs * Allocate a peripheral instance for 51839213Sgibbs * this device and start the probe 51939213Sgibbs * process. 52039213Sgibbs */ 52140603Sken status = cam_periph_alloc(cdregister, cdoninvalidate, 52240603Sken cdcleanup, cdstart, 52340603Sken "cd", CAM_PERIPH_BIO, 52440603Sken cgd->ccb_h.path, cdasync, 52540603Sken AC_FOUND_DEVICE, cgd); 52639213Sgibbs 52739213Sgibbs if (status != CAM_REQ_CMP 52839213Sgibbs && status != CAM_REQ_INPROG) 52939213Sgibbs printf("cdasync: Unable to attach new device " 53039213Sgibbs "due to status 0x%x\n", status); 53139213Sgibbs 53239213Sgibbs break; 53339213Sgibbs } 53439213Sgibbs case AC_SENT_BDR: 53539213Sgibbs case AC_BUS_RESET: 53639213Sgibbs { 53739213Sgibbs struct cd_softc *softc; 53839213Sgibbs struct ccb_hdr *ccbh; 53939213Sgibbs int s; 54039213Sgibbs 54139213Sgibbs softc = (struct cd_softc *)periph->softc; 54239213Sgibbs s = splsoftcam(); 54339213Sgibbs /* 54439213Sgibbs * Don't fail on the expected unit attention 54539213Sgibbs * that will occur. 54639213Sgibbs */ 54739213Sgibbs softc->flags |= CD_FLAG_RETRY_UA; 54839213Sgibbs for (ccbh = LIST_FIRST(&softc->pending_ccbs); 54939213Sgibbs ccbh != NULL; ccbh = LIST_NEXT(ccbh, periph_links.le)) 55039213Sgibbs ccbh->ccb_state |= CD_CCB_RETRY_UA; 55139213Sgibbs splx(s); 55247413Sgibbs /* FALLTHROUGH */ 55339213Sgibbs } 55439213Sgibbs default: 55547413Sgibbs cam_periph_async(periph, code, path, arg); 55639213Sgibbs break; 55739213Sgibbs } 55839213Sgibbs} 55939213Sgibbs 56039213Sgibbsstatic cam_status 56139213Sgibbscdregister(struct cam_periph *periph, void *arg) 56239213Sgibbs{ 56339213Sgibbs struct cd_softc *softc; 56439213Sgibbs struct ccb_setasync csa; 56539213Sgibbs struct ccb_getdev *cgd; 56639213Sgibbs caddr_t match; 56739213Sgibbs 56839213Sgibbs cgd = (struct ccb_getdev *)arg; 56939213Sgibbs if (periph == NULL) { 57039213Sgibbs printf("cdregister: periph was NULL!!\n"); 57139213Sgibbs return(CAM_REQ_CMP_ERR); 57239213Sgibbs } 57339213Sgibbs if (cgd == NULL) { 57439213Sgibbs printf("cdregister: no getdev CCB, can't register device\n"); 57539213Sgibbs return(CAM_REQ_CMP_ERR); 57639213Sgibbs } 57739213Sgibbs 57839213Sgibbs softc = (struct cd_softc *)malloc(sizeof(*softc),M_DEVBUF,M_NOWAIT); 57939213Sgibbs 58039213Sgibbs if (softc == NULL) { 58139213Sgibbs printf("cdregister: Unable to probe new device. " 58239213Sgibbs "Unable to allocate softc\n"); 58339213Sgibbs return(CAM_REQ_CMP_ERR); 58439213Sgibbs } 58539213Sgibbs 58639213Sgibbs bzero(softc, sizeof(*softc)); 58739213Sgibbs LIST_INIT(&softc->pending_ccbs); 58839213Sgibbs softc->state = CD_STATE_PROBE; 58939213Sgibbs bufq_init(&softc->buf_queue); 59039213Sgibbs if (SID_IS_REMOVABLE(&cgd->inq_data)) 59139213Sgibbs softc->flags |= CD_FLAG_DISC_REMOVABLE; 59239213Sgibbs if ((cgd->inq_data.flags & SID_CmdQue) != 0) 59339213Sgibbs softc->flags |= CD_FLAG_TAGGED_QUEUING; 59439213Sgibbs 59539213Sgibbs periph->softc = softc; 59639213Sgibbs softc->periph = periph; 59739213Sgibbs 59839213Sgibbs cam_extend_set(cdperiphs, periph->unit_number, periph); 59939213Sgibbs 60039213Sgibbs /* 60139213Sgibbs * See if this device has any quirks. 60239213Sgibbs */ 60339213Sgibbs match = cam_quirkmatch((caddr_t)&cgd->inq_data, 60439213Sgibbs (caddr_t)cd_quirk_table, 60539213Sgibbs sizeof(cd_quirk_table)/sizeof(*cd_quirk_table), 60639213Sgibbs sizeof(*cd_quirk_table), scsi_inquiry_match); 60739213Sgibbs 60839213Sgibbs if (match != NULL) 60939213Sgibbs softc->quirks = ((struct cd_quirk_entry *)match)->quirks; 61039213Sgibbs else 61139213Sgibbs softc->quirks = CD_Q_NONE; 61239213Sgibbs 61339213Sgibbs /* 61439213Sgibbs * We need to register the statistics structure for this device, 61539213Sgibbs * but we don't have the blocksize yet for it. So, we register 61639213Sgibbs * the structure and indicate that we don't have the blocksize 61739213Sgibbs * yet. Unlike other SCSI peripheral drivers, we explicitly set 61839213Sgibbs * the device type here to be CDROM, rather than just ORing in 61939213Sgibbs * cgd->pd_type. This is because this driver can attach to either 62039213Sgibbs * CDROM or WORM devices, and we want this peripheral driver to 62139213Sgibbs * show up in the devstat list as a CD peripheral driver, not a 62239213Sgibbs * WORM peripheral driver. WORM drives will also have the WORM 62339213Sgibbs * driver attached to them. 62439213Sgibbs */ 62539213Sgibbs devstat_add_entry(&softc->device_stats, "cd", 62639213Sgibbs periph->unit_number, 0, 62739213Sgibbs DEVSTAT_BS_UNAVAILABLE, 62843819Sken DEVSTAT_TYPE_CDROM | DEVSTAT_TYPE_IF_SCSI, 62943819Sken DEVSTAT_PRIORITY_CD); 63039213Sgibbs 63139213Sgibbs /* 63239213Sgibbs * Add an async callback so that we get 63339213Sgibbs * notified if this device goes away. 63439213Sgibbs */ 63539213Sgibbs xpt_setup_ccb(&csa.ccb_h, periph->path, 63639213Sgibbs /* priority */ 5); 63739213Sgibbs csa.ccb_h.func_code = XPT_SASYNC_CB; 63839213Sgibbs csa.event_enable = AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE; 63939213Sgibbs csa.callback = cdasync; 64039213Sgibbs csa.callback_arg = periph; 64139213Sgibbs xpt_action((union ccb *)&csa); 64239213Sgibbs 64339213Sgibbs /* 64439213Sgibbs * If the target lun is greater than 0, we most likely have a CD 64539213Sgibbs * changer device. Check the quirk entries as well, though, just 64639213Sgibbs * in case someone has a CD tower with one lun per drive or 64739213Sgibbs * something like that. Also, if we know up front that a 64839213Sgibbs * particular device is a changer, we can mark it as such starting 64939213Sgibbs * with lun 0, instead of lun 1. It shouldn't be necessary to have 65039213Sgibbs * a quirk entry to define something as a changer, however. 65139213Sgibbs */ 65239213Sgibbs if (((cgd->ccb_h.target_lun > 0) 65339213Sgibbs && ((softc->quirks & CD_Q_NO_CHANGER) == 0)) 65439213Sgibbs || ((softc->quirks & CD_Q_CHANGER) != 0)) { 65539213Sgibbs struct cdchanger *nchanger; 65639213Sgibbs struct cam_periph *nperiph; 65739213Sgibbs struct cam_path *path; 65839213Sgibbs cam_status status; 65939213Sgibbs int found; 66039213Sgibbs 66139213Sgibbs /* Set the changer flag in the current device's softc */ 66239213Sgibbs softc->flags |= CD_FLAG_CHANGER; 66339213Sgibbs 66439213Sgibbs if (num_changers == 0) 66539213Sgibbs STAILQ_INIT(&changerq); 66639213Sgibbs 66739213Sgibbs /* 66839213Sgibbs * Now, look around for an existing changer device with the 66939213Sgibbs * same path and target ID as the current device. 67039213Sgibbs */ 67139213Sgibbs for (found = 0, 67239213Sgibbs nchanger = (struct cdchanger *)STAILQ_FIRST(&changerq); 67339213Sgibbs nchanger != NULL; 67439213Sgibbs nchanger = STAILQ_NEXT(nchanger, changer_links)){ 67539213Sgibbs if ((nchanger->path_id == cgd->ccb_h.path_id) 67639213Sgibbs && (nchanger->target_id == cgd->ccb_h.target_id)) { 67739213Sgibbs found = 1; 67839213Sgibbs break; 67939213Sgibbs } 68039213Sgibbs } 68139213Sgibbs 68239213Sgibbs /* 68339213Sgibbs * If we found a matching entry, just add this device to 68439213Sgibbs * the list of devices on this changer. 68539213Sgibbs */ 68639213Sgibbs if (found == 1) { 68739213Sgibbs struct chdevlist *chlunhead; 68839213Sgibbs 68939213Sgibbs chlunhead = &nchanger->chluns; 69039213Sgibbs 69139213Sgibbs /* 69239213Sgibbs * XXX KDM look at consolidating this code with the 69339213Sgibbs * code below in a separate function. 69439213Sgibbs */ 69539213Sgibbs 69639213Sgibbs /* 69739213Sgibbs * Create a path with lun id 0, and see if we can 69839213Sgibbs * find a matching device 69939213Sgibbs */ 70039213Sgibbs status = xpt_create_path(&path, /*periph*/ periph, 70139213Sgibbs cgd->ccb_h.path_id, 70239213Sgibbs cgd->ccb_h.target_id, 0); 70339213Sgibbs 70439213Sgibbs if ((status == CAM_REQ_CMP) 70539213Sgibbs && ((nperiph = cam_periph_find(path, "cd")) != NULL)){ 70639213Sgibbs struct cd_softc *nsoftc; 70739213Sgibbs 70839213Sgibbs nsoftc = (struct cd_softc *)nperiph->softc; 70939213Sgibbs 71039213Sgibbs if ((nsoftc->flags & CD_FLAG_CHANGER) == 0){ 71139213Sgibbs nsoftc->flags |= CD_FLAG_CHANGER; 71239213Sgibbs nchanger->num_devices++; 71339213Sgibbs if (camq_resize(&nchanger->devq, 71439213Sgibbs nchanger->num_devices)!=CAM_REQ_CMP){ 71539213Sgibbs printf("cdregister: " 71639213Sgibbs "camq_resize " 71739213Sgibbs "failed, changer " 71839213Sgibbs "support may " 71939213Sgibbs "be messed up\n"); 72039213Sgibbs } 72139213Sgibbs nsoftc->changer = nchanger; 72239213Sgibbs nsoftc->pinfo.index =CAM_UNQUEUED_INDEX; 72339213Sgibbs 72439213Sgibbs STAILQ_INSERT_TAIL(&nchanger->chluns, 72539213Sgibbs nsoftc,changer_links); 72639213Sgibbs } 72739213Sgibbs } else if (status == CAM_REQ_CMP) 72839213Sgibbs xpt_free_path(path); 72939213Sgibbs else { 73039213Sgibbs printf("cdregister: unable to allocate path\n" 73139213Sgibbs "cdregister: changer support may be " 73239213Sgibbs "broken\n"); 73339213Sgibbs } 73439213Sgibbs 73539213Sgibbs nchanger->num_devices++; 73639213Sgibbs 73739213Sgibbs softc->changer = nchanger; 73839213Sgibbs softc->pinfo.index = CAM_UNQUEUED_INDEX; 73939213Sgibbs 74039213Sgibbs if (camq_resize(&nchanger->devq, 74139213Sgibbs nchanger->num_devices) != CAM_REQ_CMP) { 74239213Sgibbs printf("cdregister: camq_resize " 74339213Sgibbs "failed, changer support may " 74439213Sgibbs "be messed up\n"); 74539213Sgibbs } 74639213Sgibbs 74739213Sgibbs STAILQ_INSERT_TAIL(chlunhead, softc, changer_links); 74839213Sgibbs } 74939213Sgibbs /* 75039213Sgibbs * In this case, we don't already have an entry for this 75139213Sgibbs * particular changer, so we need to create one, add it to 75239213Sgibbs * the queue, and queue this device on the list for this 75339213Sgibbs * changer. Before we queue this device, however, we need 75439213Sgibbs * to search for lun id 0 on this target, and add it to the 75539213Sgibbs * queue first, if it exists. (and if it hasn't already 75639213Sgibbs * been marked as part of the changer.) 75739213Sgibbs */ 75839213Sgibbs else { 75939213Sgibbs nchanger = malloc(sizeof(struct cdchanger), 76039213Sgibbs M_DEVBUF, M_NOWAIT); 76139213Sgibbs 76239213Sgibbs if (nchanger == NULL) { 76339213Sgibbs softc->flags &= ~CD_FLAG_CHANGER; 76439213Sgibbs printf("cdregister: unable to malloc " 76539213Sgibbs "changer structure\ncdregister: " 76639213Sgibbs "changer support disabled\n"); 76739213Sgibbs 76839213Sgibbs /* 76939213Sgibbs * Yes, gotos can be gross but in this case 77039213Sgibbs * I think it's justified.. 77139213Sgibbs */ 77239213Sgibbs goto cdregisterexit; 77339213Sgibbs } 77439213Sgibbs 77539213Sgibbs /* zero the structure */ 77639213Sgibbs bzero(nchanger, sizeof(struct cdchanger)); 77739213Sgibbs 77839213Sgibbs if (camq_init(&nchanger->devq, 1) != 0) { 77939213Sgibbs softc->flags &= ~CD_FLAG_CHANGER; 78039213Sgibbs printf("cdregister: changer support " 78139213Sgibbs "disabled\n"); 78239213Sgibbs goto cdregisterexit; 78339213Sgibbs } 78439213Sgibbs 78539213Sgibbs num_changers++; 78639213Sgibbs 78739213Sgibbs nchanger->path_id = cgd->ccb_h.path_id; 78839213Sgibbs nchanger->target_id = cgd->ccb_h.target_id; 78939213Sgibbs 79039213Sgibbs /* this is superfluous, but it makes things clearer */ 79139213Sgibbs nchanger->num_devices = 0; 79239213Sgibbs 79339213Sgibbs STAILQ_INIT(&nchanger->chluns); 79439213Sgibbs 79539213Sgibbs STAILQ_INSERT_TAIL(&changerq, nchanger, 79639213Sgibbs changer_links); 79739213Sgibbs 79839213Sgibbs /* 79939213Sgibbs * Create a path with lun id 0, and see if we can 80039213Sgibbs * find a matching device 80139213Sgibbs */ 80239213Sgibbs status = xpt_create_path(&path, /*periph*/ periph, 80339213Sgibbs cgd->ccb_h.path_id, 80439213Sgibbs cgd->ccb_h.target_id, 0); 80539213Sgibbs 80639213Sgibbs /* 80739213Sgibbs * If we were able to allocate the path, and if we 80839213Sgibbs * find a matching device and it isn't already 80939213Sgibbs * marked as part of a changer, then we add it to 81039213Sgibbs * the current changer. 81139213Sgibbs */ 81239213Sgibbs if ((status == CAM_REQ_CMP) 81339213Sgibbs && ((nperiph = cam_periph_find(path, "cd")) != NULL) 81439213Sgibbs && ((((struct cd_softc *)periph->softc)->flags & 81539213Sgibbs CD_FLAG_CHANGER) == 0)) { 81639213Sgibbs struct cd_softc *nsoftc; 81739213Sgibbs 81839213Sgibbs nsoftc = (struct cd_softc *)nperiph->softc; 81939213Sgibbs 82039213Sgibbs nsoftc->flags |= CD_FLAG_CHANGER; 82139213Sgibbs nchanger->num_devices++; 82239213Sgibbs if (camq_resize(&nchanger->devq, 82339213Sgibbs nchanger->num_devices) != CAM_REQ_CMP) { 82439213Sgibbs printf("cdregister: camq_resize " 82539213Sgibbs "failed, changer support may " 82639213Sgibbs "be messed up\n"); 82739213Sgibbs } 82839213Sgibbs nsoftc->changer = nchanger; 82939213Sgibbs nsoftc->pinfo.index = CAM_UNQUEUED_INDEX; 83039213Sgibbs 83139213Sgibbs STAILQ_INSERT_TAIL(&nchanger->chluns, 83239213Sgibbs nsoftc, changer_links); 83339213Sgibbs } else if (status == CAM_REQ_CMP) 83439213Sgibbs xpt_free_path(path); 83539213Sgibbs else { 83639213Sgibbs printf("cdregister: unable to allocate path\n" 83739213Sgibbs "cdregister: changer support may be " 83839213Sgibbs "broken\n"); 83939213Sgibbs } 84039213Sgibbs 84139213Sgibbs softc->changer = nchanger; 84239213Sgibbs softc->pinfo.index = CAM_UNQUEUED_INDEX; 84339213Sgibbs nchanger->num_devices++; 84439213Sgibbs if (camq_resize(&nchanger->devq, 84539213Sgibbs nchanger->num_devices) != CAM_REQ_CMP) { 84639213Sgibbs printf("cdregister: camq_resize " 84739213Sgibbs "failed, changer support may " 84839213Sgibbs "be messed up\n"); 84939213Sgibbs } 85039213Sgibbs STAILQ_INSERT_TAIL(&nchanger->chluns, softc, 85139213Sgibbs changer_links); 85239213Sgibbs } 85339213Sgibbs } 85439213Sgibbs 85539213Sgibbscdregisterexit: 85639213Sgibbs 85739213Sgibbs /* Lock this peripheral until we are setup */ 85839213Sgibbs /* Can't block */ 85939213Sgibbs cam_periph_lock(periph, PRIBIO); 86039213Sgibbs 86139213Sgibbs if ((softc->flags & CD_FLAG_CHANGER) == 0) 86239213Sgibbs xpt_schedule(periph, /*priority*/5); 86339213Sgibbs else 86439213Sgibbs cdschedule(periph, /*priority*/ 5); 86539213Sgibbs 86639213Sgibbs return(CAM_REQ_CMP); 86739213Sgibbs} 86839213Sgibbs 86939213Sgibbsstatic int 87039213Sgibbscdopen(dev_t dev, int flags, int fmt, struct proc *p) 87139213Sgibbs{ 87240020Sken struct disklabel label; 87339213Sgibbs struct cam_periph *periph; 87439213Sgibbs struct cd_softc *softc; 87540020Sken struct ccb_getdev cgd; 87639213Sgibbs u_int32_t size; 87739213Sgibbs int unit, error; 87840603Sken int s; 87939213Sgibbs 88039213Sgibbs unit = dkunit(dev); 88139213Sgibbs periph = cam_extend_get(cdperiphs, unit); 88239213Sgibbs 88339213Sgibbs if (periph == NULL) 88439213Sgibbs return (ENXIO); 88539213Sgibbs 88639213Sgibbs softc = (struct cd_softc *)periph->softc; 88739213Sgibbs 88841297Sken /* 88941297Sken * Grab splsoftcam and hold it until we lock the peripheral. 89041297Sken */ 89140603Sken s = splsoftcam(); 89240603Sken if (softc->flags & CD_FLAG_INVALID) { 89340603Sken splx(s); 89439213Sgibbs return(ENXIO); 89540603Sken } 89639213Sgibbs 89741297Sken if ((error = cam_periph_lock(periph, PRIBIO | PCATCH)) != 0) { 89841297Sken splx(s); 89939213Sgibbs return (error); 90041297Sken } 90139213Sgibbs 90241297Sken splx(s); 90341297Sken 90439213Sgibbs if ((softc->flags & CD_FLAG_OPEN) == 0) { 90539213Sgibbs if (cam_periph_acquire(periph) != CAM_REQ_CMP) 90639213Sgibbs return(ENXIO); 90739213Sgibbs softc->flags |= CD_FLAG_OPEN; 90840020Sken 90940020Sken cdprevent(periph, PR_PREVENT); 91039213Sgibbs } 91139213Sgibbs 91239213Sgibbs /* find out the size */ 91339213Sgibbs if ((error = cdsize(dev, &size)) != 0) { 91440020Sken if (dsisopen(softc->cd_slices) == 0) { 91540020Sken cdprevent(periph, PR_ALLOW); 91640020Sken softc->flags &= ~CD_FLAG_OPEN; 91740020Sken } 91839213Sgibbs cam_periph_unlock(periph); 91939213Sgibbs 92040020Sken if ((softc->flags & CD_FLAG_OPEN) == 0) 92140020Sken cam_periph_release(periph); 92240020Sken 92339213Sgibbs return(error); 92439213Sgibbs } 92539213Sgibbs 92640020Sken /* 92740020Sken * Build prototype label for whole disk. 92840020Sken * Should take information about different data tracks from the 92940020Sken * TOC and put it in the partition table. 93040020Sken */ 93140020Sken bzero(&label, sizeof(label)); 93240020Sken label.d_type = DTYPE_SCSI; 93340020Sken 93440020Sken /* 93540020Sken * Grab the inquiry data to get the vendor and product names. 93640020Sken * Put them in the typename and packname for the label. 93740020Sken */ 93840020Sken xpt_setup_ccb(&cgd.ccb_h, periph->path, /*priority*/ 1); 93940020Sken cgd.ccb_h.func_code = XPT_GDEV_TYPE; 94040020Sken xpt_action((union ccb *)&cgd); 94140020Sken 94240020Sken strncpy(label.d_typename, cgd.inq_data.vendor, 94340020Sken min(SID_VENDOR_SIZE, sizeof(label.d_typename))); 94440020Sken strncpy(label.d_packname, cgd.inq_data.product, 94540020Sken min(SID_PRODUCT_SIZE, sizeof(label.d_packname))); 94640020Sken 94740020Sken label.d_secsize = softc->params.blksize; 94840020Sken label.d_secperunit = softc->params.disksize; 94940020Sken label.d_flags = D_REMOVABLE; 95040020Sken /* 95140020Sken * Make partition 'a' cover the whole disk. This is a temporary 95240020Sken * compatibility hack. The 'a' partition should not exist, so 95340020Sken * the slice code won't create it. The slice code will make 95440020Sken * partition (RAW_PART + 'a') cover the whole disk and fill in 95540020Sken * some more defaults. 95640020Sken */ 95740020Sken label.d_partitions[0].p_size = label.d_secperunit; 95840020Sken label.d_partitions[0].p_fstype = FS_OTHER; 95940020Sken 96040020Sken /* Initialize slice tables. */ 96140020Sken error = dsopen("cd", dev, fmt, DSO_NOLABELS | DSO_ONESLICE, 96242590Seivind &softc->cd_slices, &label, cdstrategy1, 96340020Sken (ds_setgeom_t *)NULL, &cd_cdevsw); 96440020Sken 96539213Sgibbs if (error == 0) { 96639213Sgibbs /* 96739213Sgibbs * We unconditionally (re)set the blocksize each time the 96839213Sgibbs * CD device is opened. This is because the CD can change, 96939213Sgibbs * and therefore the blocksize might change. 97040020Sken * XXX problems here if some slice or partition is still 97140020Sken * open with the old size? 97239213Sgibbs */ 97339213Sgibbs if ((softc->device_stats.flags & DEVSTAT_BS_UNAVAILABLE) != 0) 97439213Sgibbs softc->device_stats.flags &= ~DEVSTAT_BS_UNAVAILABLE; 97539213Sgibbs softc->device_stats.block_size = softc->params.blksize; 97639213Sgibbs } else { 97739213Sgibbs if ((dsisopen(softc->cd_slices) == 0) 97839213Sgibbs && ((softc->flags & CD_FLAG_DISC_REMOVABLE) != 0)) 97939213Sgibbs cdprevent(periph, PR_ALLOW); 98039213Sgibbs } 98139213Sgibbs 98239213Sgibbs cam_periph_unlock(periph); 98339213Sgibbs 98439213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("leaving cdopen\n")); 98539213Sgibbs 98639213Sgibbs return (error); 98739213Sgibbs} 98839213Sgibbs 98939213Sgibbsstatic int 99039213Sgibbscdclose(dev_t dev, int flag, int fmt, struct proc *p) 99139213Sgibbs{ 99239213Sgibbs struct cam_periph *periph; 99339213Sgibbs struct cd_softc *softc; 99439213Sgibbs int unit, error; 99539213Sgibbs 99639213Sgibbs unit = dkunit(dev); 99739213Sgibbs periph = cam_extend_get(cdperiphs, unit); 99839213Sgibbs if (periph == NULL) 99939213Sgibbs return (ENXIO); 100039213Sgibbs 100139213Sgibbs softc = (struct cd_softc *)periph->softc; 100239213Sgibbs 100339213Sgibbs if ((error = cam_periph_lock(periph, PRIBIO)) != 0) 100439213Sgibbs return (error); 100539213Sgibbs 100639213Sgibbs dsclose(dev, fmt, softc->cd_slices); 100740020Sken if (dsisopen(softc->cd_slices)) { 100840020Sken cam_periph_unlock(periph); 100940020Sken return (0); 101040020Sken } 101139213Sgibbs 101239213Sgibbs if ((softc->flags & CD_FLAG_DISC_REMOVABLE) != 0) 101339213Sgibbs cdprevent(periph, PR_ALLOW); 101439213Sgibbs 101539213Sgibbs /* 101639213Sgibbs * Since we're closing this CD, mark the blocksize as unavailable. 101739213Sgibbs * It will be marked as available whence the CD is opened again. 101839213Sgibbs */ 101939213Sgibbs softc->device_stats.flags |= DEVSTAT_BS_UNAVAILABLE; 102039213Sgibbs 102139213Sgibbs softc->flags &= ~CD_FLAG_OPEN; 102239213Sgibbs cam_periph_unlock(periph); 102339213Sgibbs cam_periph_release(periph); 102439213Sgibbs 102539213Sgibbs return (0); 102639213Sgibbs} 102739213Sgibbs 102839213Sgibbsstatic void 102939213Sgibbscdshorttimeout(void *arg) 103039213Sgibbs{ 103139213Sgibbs struct cdchanger *changer; 103239213Sgibbs int s; 103339213Sgibbs 103439213Sgibbs s = splsoftcam(); 103539213Sgibbs 103639213Sgibbs changer = (struct cdchanger *)arg; 103739213Sgibbs 103839213Sgibbs /* Always clear the short timeout flag, since that's what we're in */ 103939213Sgibbs changer->flags &= ~CHANGER_SHORT_TMOUT_SCHED; 104039213Sgibbs 104139213Sgibbs /* 104239213Sgibbs * Check to see if there is any more pending or outstanding I/O for 104339213Sgibbs * this device. If not, move it out of the active slot. 104439213Sgibbs */ 104539213Sgibbs if ((bufq_first(&changer->cur_device->buf_queue) == NULL) 104639213Sgibbs && (changer->cur_device->device_stats.busy_count == 0)) { 104739213Sgibbs changer->flags |= CHANGER_MANUAL_CALL; 104839213Sgibbs cdrunchangerqueue(changer); 104939213Sgibbs } 105039213Sgibbs 105139213Sgibbs splx(s); 105239213Sgibbs} 105339213Sgibbs 105439213Sgibbs/* 105539213Sgibbs * This is a wrapper for xpt_schedule. It only applies to changers. 105639213Sgibbs */ 105739213Sgibbsstatic void 105839213Sgibbscdschedule(struct cam_periph *periph, int priority) 105939213Sgibbs{ 106039213Sgibbs struct cd_softc *softc; 106139213Sgibbs int s; 106239213Sgibbs 106339213Sgibbs s = splsoftcam(); 106439213Sgibbs 106539213Sgibbs softc = (struct cd_softc *)periph->softc; 106639213Sgibbs 106739213Sgibbs /* 106839213Sgibbs * If this device isn't currently queued, and if it isn't 106939213Sgibbs * the active device, then we queue this device and run the 107039213Sgibbs * changer queue if there is no timeout scheduled to do it. 107139213Sgibbs * If this device is the active device, just schedule it 107239213Sgibbs * to run again. If this device is queued, there should be 107339213Sgibbs * a timeout in place already that will make sure it runs. 107439213Sgibbs */ 107539213Sgibbs if ((softc->pinfo.index == CAM_UNQUEUED_INDEX) 107639213Sgibbs && ((softc->flags & CD_FLAG_ACTIVE) == 0)) { 107739213Sgibbs /* 107839213Sgibbs * We don't do anything with the priority here. 107939213Sgibbs * This is strictly a fifo queue. 108039213Sgibbs */ 108139213Sgibbs softc->pinfo.priority = 1; 108245442Sgibbs softc->pinfo.generation = ++softc->changer->devq.generation; 108339213Sgibbs camq_insert(&softc->changer->devq, (cam_pinfo *)softc); 108439213Sgibbs 108539213Sgibbs /* 108639213Sgibbs * Since we just put a device in the changer queue, 108739213Sgibbs * check and see if there is a timeout scheduled for 108839213Sgibbs * this changer. If so, let the timeout handle 108939213Sgibbs * switching this device into the active slot. If 109039213Sgibbs * not, manually call the timeout routine to 109139213Sgibbs * bootstrap things. 109239213Sgibbs */ 109339213Sgibbs if (((softc->changer->flags & CHANGER_TIMEOUT_SCHED)==0) 109446581Sken && ((softc->changer->flags & CHANGER_NEED_TIMEOUT)==0) 109546581Sken && ((softc->changer->flags & CHANGER_SHORT_TMOUT_SCHED)==0)){ 109639213Sgibbs softc->changer->flags |= CHANGER_MANUAL_CALL; 109739213Sgibbs cdrunchangerqueue(softc->changer); 109839213Sgibbs } 109939213Sgibbs } else if ((softc->flags & CD_FLAG_ACTIVE) 110039213Sgibbs && ((softc->flags & CD_FLAG_SCHED_ON_COMP) == 0)) 110139213Sgibbs xpt_schedule(periph, priority); 110239213Sgibbs 110339213Sgibbs splx(s); 110439213Sgibbs 110539213Sgibbs} 110639213Sgibbs 110739213Sgibbsstatic void 110839213Sgibbscdrunchangerqueue(void *arg) 110939213Sgibbs{ 111039213Sgibbs struct cd_softc *softc; 111139213Sgibbs struct cdchanger *changer; 111239213Sgibbs int called_from_timeout; 111339213Sgibbs int s; 111439213Sgibbs 111539213Sgibbs s = splsoftcam(); 111639213Sgibbs 111739213Sgibbs changer = (struct cdchanger *)arg; 111839213Sgibbs 111939213Sgibbs /* 112039213Sgibbs * If we have NOT been called from cdstrategy() or cddone(), and 112139213Sgibbs * instead from a timeout routine, go ahead and clear the 112239213Sgibbs * timeout flag. 112339213Sgibbs */ 112439213Sgibbs if ((changer->flags & CHANGER_MANUAL_CALL) == 0) { 112539213Sgibbs changer->flags &= ~CHANGER_TIMEOUT_SCHED; 112639213Sgibbs called_from_timeout = 1; 112739213Sgibbs } else 112839213Sgibbs called_from_timeout = 0; 112939213Sgibbs 113039213Sgibbs /* Always clear the manual call flag */ 113139213Sgibbs changer->flags &= ~CHANGER_MANUAL_CALL; 113239213Sgibbs 113339213Sgibbs /* nothing to do if the queue is empty */ 113439213Sgibbs if (changer->devq.entries <= 0) { 113539213Sgibbs splx(s); 113639213Sgibbs return; 113739213Sgibbs } 113839213Sgibbs 113939213Sgibbs /* 114039213Sgibbs * If the changer queue is frozen, that means we have an active 114139213Sgibbs * device. 114239213Sgibbs */ 114339213Sgibbs if (changer->devq.qfrozen_cnt > 0) { 114439213Sgibbs 114539213Sgibbs if (changer->cur_device->device_stats.busy_count > 0) { 114639213Sgibbs changer->cur_device->flags |= CD_FLAG_SCHED_ON_COMP; 114739213Sgibbs changer->cur_device->bufs_left = 114839213Sgibbs changer->cur_device->device_stats.busy_count; 114939213Sgibbs if (called_from_timeout) { 115039213Sgibbs changer->long_handle = 115139213Sgibbs timeout(cdrunchangerqueue, changer, 115239213Sgibbs changer_max_busy_seconds * hz); 115339213Sgibbs changer->flags |= CHANGER_TIMEOUT_SCHED; 115439213Sgibbs } 115539213Sgibbs splx(s); 115639213Sgibbs return; 115739213Sgibbs } 115839213Sgibbs 115939213Sgibbs /* 116039213Sgibbs * We always need to reset the frozen count and clear the 116139213Sgibbs * active flag. 116239213Sgibbs */ 116339213Sgibbs changer->devq.qfrozen_cnt--; 116439213Sgibbs changer->cur_device->flags &= ~CD_FLAG_ACTIVE; 116539213Sgibbs changer->cur_device->flags &= ~CD_FLAG_SCHED_ON_COMP; 116639213Sgibbs 116739213Sgibbs /* 116839213Sgibbs * Check to see whether the current device has any I/O left 116939213Sgibbs * to do. If so, requeue it at the end of the queue. If 117039213Sgibbs * not, there is no need to requeue it. 117139213Sgibbs */ 117239213Sgibbs if (bufq_first(&changer->cur_device->buf_queue) != NULL) { 117339213Sgibbs 117439213Sgibbs changer->cur_device->pinfo.generation = 117545442Sgibbs ++changer->devq.generation; 117639213Sgibbs camq_insert(&changer->devq, 117739213Sgibbs (cam_pinfo *)changer->cur_device); 117839213Sgibbs } 117939213Sgibbs } 118039213Sgibbs 118145845Sgibbs softc = (struct cd_softc *)camq_remove(&changer->devq, CAMQ_HEAD); 118239213Sgibbs 118339213Sgibbs changer->cur_device = softc; 118439213Sgibbs 118539213Sgibbs changer->devq.qfrozen_cnt++; 118639213Sgibbs softc->flags |= CD_FLAG_ACTIVE; 118739213Sgibbs 118839213Sgibbs /* Just in case this device is waiting */ 118939213Sgibbs wakeup(&softc->changer); 119039213Sgibbs xpt_schedule(softc->periph, /*priority*/ 1); 119139213Sgibbs 119239213Sgibbs /* 119339213Sgibbs * Get rid of any pending timeouts, and set a flag to schedule new 119439213Sgibbs * ones so this device gets its full time quantum. 119539213Sgibbs */ 119639213Sgibbs if (changer->flags & CHANGER_TIMEOUT_SCHED) { 119739213Sgibbs untimeout(cdrunchangerqueue, changer, changer->long_handle); 119839213Sgibbs changer->flags &= ~CHANGER_TIMEOUT_SCHED; 119939213Sgibbs } 120039213Sgibbs 120139213Sgibbs if (changer->flags & CHANGER_SHORT_TMOUT_SCHED) { 120239213Sgibbs untimeout(cdshorttimeout, changer, changer->short_handle); 120339213Sgibbs changer->flags &= ~CHANGER_SHORT_TMOUT_SCHED; 120439213Sgibbs } 120539213Sgibbs 120639213Sgibbs /* 120739213Sgibbs * We need to schedule timeouts, but we only do this after the 120839213Sgibbs * first transaction has completed. This eliminates the changer 120939213Sgibbs * switch time. 121039213Sgibbs */ 121139213Sgibbs changer->flags |= CHANGER_NEED_TIMEOUT; 121239213Sgibbs 121339213Sgibbs splx(s); 121439213Sgibbs} 121539213Sgibbs 121639213Sgibbsstatic void 121739213Sgibbscdchangerschedule(struct cd_softc *softc) 121839213Sgibbs{ 121939213Sgibbs struct cdchanger *changer; 122039213Sgibbs int s; 122139213Sgibbs 122239213Sgibbs s = splsoftcam(); 122339213Sgibbs 122439213Sgibbs changer = softc->changer; 122539213Sgibbs 122639213Sgibbs /* 122739213Sgibbs * If this is a changer, and this is the current device, 122839213Sgibbs * and this device has at least the minimum time quantum to 122939213Sgibbs * run, see if we can switch it out. 123039213Sgibbs */ 123139213Sgibbs if ((softc->flags & CD_FLAG_ACTIVE) 123239213Sgibbs && ((changer->flags & CHANGER_SHORT_TMOUT_SCHED) == 0) 123339213Sgibbs && ((changer->flags & CHANGER_NEED_TIMEOUT) == 0)) { 123439213Sgibbs /* 123539213Sgibbs * We try three things here. The first is that we 123639213Sgibbs * check to see whether the schedule on completion 123739213Sgibbs * flag is set. If it is, we decrement the number 123839213Sgibbs * of buffers left, and if it's zero, we reschedule. 123939213Sgibbs * Next, we check to see whether the pending buffer 124039213Sgibbs * queue is empty and whether there are no 124139213Sgibbs * outstanding transactions. If so, we reschedule. 124239213Sgibbs * Next, we see if the pending buffer queue is empty. 124339213Sgibbs * If it is, we set the number of buffers left to 124439213Sgibbs * the current active buffer count and set the 124539213Sgibbs * schedule on complete flag. 124639213Sgibbs */ 124739213Sgibbs if (softc->flags & CD_FLAG_SCHED_ON_COMP) { 124839213Sgibbs if (--softc->bufs_left == 0) { 124939213Sgibbs softc->changer->flags |= 125039213Sgibbs CHANGER_MANUAL_CALL; 125139213Sgibbs softc->flags &= ~CD_FLAG_SCHED_ON_COMP; 125239213Sgibbs cdrunchangerqueue(softc->changer); 125339213Sgibbs } 125439213Sgibbs } else if ((bufq_first(&softc->buf_queue) == NULL) 125539213Sgibbs && (softc->device_stats.busy_count == 0)) { 125639213Sgibbs softc->changer->flags |= CHANGER_MANUAL_CALL; 125739213Sgibbs cdrunchangerqueue(softc->changer); 125839213Sgibbs } 125939213Sgibbs } else if ((softc->changer->flags & CHANGER_NEED_TIMEOUT) 126039213Sgibbs && (softc->flags & CD_FLAG_ACTIVE)) { 126139213Sgibbs 126239213Sgibbs /* 126339213Sgibbs * Now that the first transaction to this 126439213Sgibbs * particular device has completed, we can go ahead 126539213Sgibbs * and schedule our timeouts. 126639213Sgibbs */ 126739213Sgibbs if ((changer->flags & CHANGER_TIMEOUT_SCHED) == 0) { 126839213Sgibbs changer->long_handle = 126939213Sgibbs timeout(cdrunchangerqueue, changer, 127039213Sgibbs changer_max_busy_seconds * hz); 127139213Sgibbs changer->flags |= CHANGER_TIMEOUT_SCHED; 127239213Sgibbs } else 127339213Sgibbs printf("cdchangerschedule: already have a long" 127439213Sgibbs " timeout!\n"); 127539213Sgibbs 127639213Sgibbs if ((changer->flags & CHANGER_SHORT_TMOUT_SCHED) == 0) { 127739213Sgibbs changer->short_handle = 127839213Sgibbs timeout(cdshorttimeout, changer, 127939213Sgibbs changer_min_busy_seconds * hz); 128039213Sgibbs changer->flags |= CHANGER_SHORT_TMOUT_SCHED; 128139213Sgibbs } else 128239213Sgibbs printf("cdchangerschedule: already have a short " 128339213Sgibbs "timeout!\n"); 128439213Sgibbs 128539213Sgibbs /* 128639213Sgibbs * We just scheduled timeouts, no need to schedule 128739213Sgibbs * more. 128839213Sgibbs */ 128939213Sgibbs changer->flags &= ~CHANGER_NEED_TIMEOUT; 129039213Sgibbs 129139213Sgibbs } 129239213Sgibbs splx(s); 129339213Sgibbs} 129439213Sgibbs 129539213Sgibbsstatic int 129639213Sgibbscdrunccb(union ccb *ccb, int (*error_routine)(union ccb *ccb, 129739213Sgibbs u_int32_t cam_flags, 129839213Sgibbs u_int32_t sense_flags), 129939213Sgibbs u_int32_t cam_flags, u_int32_t sense_flags) 130039213Sgibbs{ 130139213Sgibbs struct cd_softc *softc; 130239213Sgibbs struct cam_periph *periph; 130339213Sgibbs int error; 130439213Sgibbs 130539213Sgibbs periph = xpt_path_periph(ccb->ccb_h.path); 130639213Sgibbs softc = (struct cd_softc *)periph->softc; 130739213Sgibbs 130839213Sgibbs error = cam_periph_runccb(ccb, error_routine, cam_flags, sense_flags, 130939213Sgibbs &softc->device_stats); 131039213Sgibbs 131139213Sgibbs if (softc->flags & CD_FLAG_CHANGER) 131239213Sgibbs cdchangerschedule(softc); 131339213Sgibbs 131439213Sgibbs return(error); 131539213Sgibbs} 131639213Sgibbs 131742017Seivindstatic union ccb * 131839213Sgibbscdgetccb(struct cam_periph *periph, u_int32_t priority) 131939213Sgibbs{ 132039213Sgibbs struct cd_softc *softc; 132139213Sgibbs int s; 132239213Sgibbs 132339213Sgibbs softc = (struct cd_softc *)periph->softc; 132439213Sgibbs 132539213Sgibbs if (softc->flags & CD_FLAG_CHANGER) { 132639213Sgibbs 132739213Sgibbs s = splsoftcam(); 132839213Sgibbs 132939213Sgibbs /* 133039213Sgibbs * This should work the first time this device is woken up, 133139213Sgibbs * but just in case it doesn't, we use a while loop. 133239213Sgibbs */ 133346581Sken while ((softc->flags & CD_FLAG_ACTIVE) == 0) { 133439213Sgibbs /* 133539213Sgibbs * If this changer isn't already queued, queue it up. 133639213Sgibbs */ 133739213Sgibbs if (softc->pinfo.index == CAM_UNQUEUED_INDEX) { 133839213Sgibbs softc->pinfo.priority = 1; 133939213Sgibbs softc->pinfo.generation = 134045442Sgibbs ++softc->changer->devq.generation; 134139213Sgibbs camq_insert(&softc->changer->devq, 134239213Sgibbs (cam_pinfo *)softc); 134339213Sgibbs } 134446581Sken if (((softc->changer->flags & CHANGER_TIMEOUT_SCHED)==0) 134546581Sken && ((softc->changer->flags & CHANGER_NEED_TIMEOUT)==0) 134646581Sken && ((softc->changer->flags 134746581Sken & CHANGER_SHORT_TMOUT_SCHED)==0)) { 134839213Sgibbs softc->changer->flags |= CHANGER_MANUAL_CALL; 134939213Sgibbs cdrunchangerqueue(softc->changer); 135039213Sgibbs } else 135139213Sgibbs tsleep(&softc->changer, PRIBIO, "cgticb", 0); 135239213Sgibbs } 135339213Sgibbs splx(s); 135439213Sgibbs } 135539213Sgibbs return(cam_periph_getccb(periph, priority)); 135639213Sgibbs} 135739213Sgibbs 135839213Sgibbs 135939213Sgibbs/* 136039213Sgibbs * Actually translate the requested transfer into one the physical driver 136139213Sgibbs * can understand. The transfer is described by a buf and will include 136239213Sgibbs * only one physical transfer. 136339213Sgibbs */ 136439213Sgibbsstatic void 136539213Sgibbscdstrategy(struct buf *bp) 136639213Sgibbs{ 136739213Sgibbs struct cam_periph *periph; 136839213Sgibbs struct cd_softc *softc; 136939213Sgibbs u_int unit, part; 137039213Sgibbs int s; 137139213Sgibbs 137239213Sgibbs unit = dkunit(bp->b_dev); 137339213Sgibbs part = dkpart(bp->b_dev); 137439213Sgibbs periph = cam_extend_get(cdperiphs, unit); 137539213Sgibbs if (periph == NULL) { 137639213Sgibbs bp->b_error = ENXIO; 137739213Sgibbs goto bad; 137839213Sgibbs } 137939213Sgibbs 138039213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdstrategy\n")); 138139213Sgibbs 138239213Sgibbs softc = (struct cd_softc *)periph->softc; 138339213Sgibbs 138439213Sgibbs /* 138539213Sgibbs * Do bounds checking, adjust transfer, and set b_pbklno. 138639213Sgibbs */ 138739213Sgibbs if (dscheck(bp, softc->cd_slices) <= 0) 138839213Sgibbs goto done; 138939213Sgibbs 139039213Sgibbs /* 139139213Sgibbs * Mask interrupts so that the pack cannot be invalidated until 139239213Sgibbs * after we are in the queue. Otherwise, we might not properly 139339213Sgibbs * clean up one of the buffers. 139439213Sgibbs */ 139539213Sgibbs s = splbio(); 139639213Sgibbs 139739213Sgibbs /* 139839213Sgibbs * If the device has been made invalid, error out 139939213Sgibbs */ 140039213Sgibbs if ((softc->flags & CD_FLAG_INVALID)) { 140139213Sgibbs splx(s); 140239213Sgibbs bp->b_error = ENXIO; 140339213Sgibbs goto bad; 140439213Sgibbs } 140539213Sgibbs 140639213Sgibbs /* 140739213Sgibbs * Place it in the queue of disk activities for this disk 140839213Sgibbs */ 140939213Sgibbs bufqdisksort(&softc->buf_queue, bp); 141039213Sgibbs 141139213Sgibbs splx(s); 141239213Sgibbs 141339213Sgibbs /* 141439213Sgibbs * Schedule ourselves for performing the work. We do things 141539213Sgibbs * differently for changers. 141639213Sgibbs */ 141739213Sgibbs if ((softc->flags & CD_FLAG_CHANGER) == 0) 141839213Sgibbs xpt_schedule(periph, /* XXX priority */1); 141939213Sgibbs else 142039213Sgibbs cdschedule(periph, /* priority */ 1); 142139213Sgibbs 142239213Sgibbs return; 142339213Sgibbsbad: 142439213Sgibbs bp->b_flags |= B_ERROR; 142539213Sgibbsdone: 142639213Sgibbs /* 142739213Sgibbs * Correctly set the buf to indicate a completed xfer 142839213Sgibbs */ 142939213Sgibbs bp->b_resid = bp->b_bcount; 143039213Sgibbs biodone(bp); 143139213Sgibbs return; 143239213Sgibbs} 143339213Sgibbs 143439213Sgibbsstatic void 143540020Skencdstrategy1(struct buf *bp) 143640020Sken{ 143740020Sken /* 143840020Sken * XXX - do something to make cdstrategy() but not this block while 143940020Sken * we're doing dsopen() and dsioctl(). 144040020Sken */ 144140020Sken cdstrategy(bp); 144240020Sken} 144340020Sken 144440020Skenstatic void 144539213Sgibbscdstart(struct cam_periph *periph, union ccb *start_ccb) 144639213Sgibbs{ 144739213Sgibbs struct cd_softc *softc; 144839213Sgibbs struct buf *bp; 144939213Sgibbs struct ccb_scsiio *csio; 145039213Sgibbs struct scsi_read_capacity_data *rcap; 145139213Sgibbs int s; 145239213Sgibbs 145339213Sgibbs softc = (struct cd_softc *)periph->softc; 145439213Sgibbs 145539213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdstart\n")); 145639213Sgibbs 145739213Sgibbs switch (softc->state) { 145839213Sgibbs case CD_STATE_NORMAL: 145939213Sgibbs { 146039213Sgibbs int oldspl; 146139213Sgibbs 146239213Sgibbs s = splbio(); 146339213Sgibbs bp = bufq_first(&softc->buf_queue); 146439213Sgibbs if (periph->immediate_priority <= periph->pinfo.priority) { 146539213Sgibbs start_ccb->ccb_h.ccb_state = CD_CCB_WAITING; 146639213Sgibbs 146739213Sgibbs SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, 146839213Sgibbs periph_links.sle); 146939213Sgibbs periph->immediate_priority = CAM_PRIORITY_NONE; 147039213Sgibbs splx(s); 147139213Sgibbs wakeup(&periph->ccb_list); 147239213Sgibbs } else if (bp == NULL) { 147339213Sgibbs splx(s); 147439213Sgibbs xpt_release_ccb(start_ccb); 147539213Sgibbs } else { 147639213Sgibbs bufq_remove(&softc->buf_queue, bp); 147739213Sgibbs 147839213Sgibbs devstat_start_transaction(&softc->device_stats); 147939213Sgibbs 148039213Sgibbs scsi_read_write(&start_ccb->csio, 148139213Sgibbs /*retries*/4, 148239213Sgibbs /* cbfcnp */ cddone, 148339213Sgibbs (bp->b_flags & B_ORDERED) != 0 ? 148439213Sgibbs MSG_ORDERED_Q_TAG : 148539213Sgibbs MSG_SIMPLE_Q_TAG, 148639213Sgibbs /* read */bp->b_flags & B_READ, 148739213Sgibbs /* byte2 */ 0, 148839213Sgibbs /* minimum_cmd_size */ 10, 148939213Sgibbs /* lba */ bp->b_pblkno, 149039213Sgibbs bp->b_bcount / softc->params.blksize, 149139213Sgibbs /* data_ptr */ bp->b_data, 149239213Sgibbs /* dxfer_len */ bp->b_bcount, 149339213Sgibbs /* sense_len */ SSD_FULL_SIZE, 149439213Sgibbs /* timeout */ 30000); 149539213Sgibbs start_ccb->ccb_h.ccb_state = CD_CCB_BUFFER_IO; 149639213Sgibbs 149739213Sgibbs 149839213Sgibbs /* 149939213Sgibbs * Block out any asyncronous callbacks 150039213Sgibbs * while we touch the pending ccb list. 150139213Sgibbs */ 150239213Sgibbs oldspl = splcam(); 150339213Sgibbs LIST_INSERT_HEAD(&softc->pending_ccbs, 150439213Sgibbs &start_ccb->ccb_h, periph_links.le); 150539213Sgibbs splx(oldspl); 150639213Sgibbs 150739213Sgibbs /* We expect a unit attention from this device */ 150839213Sgibbs if ((softc->flags & CD_FLAG_RETRY_UA) != 0) { 150939213Sgibbs start_ccb->ccb_h.ccb_state |= CD_CCB_RETRY_UA; 151039213Sgibbs softc->flags &= ~CD_FLAG_RETRY_UA; 151139213Sgibbs } 151239213Sgibbs 151339213Sgibbs start_ccb->ccb_h.ccb_bp = bp; 151439213Sgibbs bp = bufq_first(&softc->buf_queue); 151539213Sgibbs splx(s); 151639213Sgibbs 151739213Sgibbs xpt_action(start_ccb); 151839213Sgibbs } 151939213Sgibbs if (bp != NULL) { 152039213Sgibbs /* Have more work to do, so ensure we stay scheduled */ 152139213Sgibbs xpt_schedule(periph, /* XXX priority */1); 152239213Sgibbs } 152339213Sgibbs break; 152439213Sgibbs } 152539213Sgibbs case CD_STATE_PROBE: 152639213Sgibbs { 152739213Sgibbs 152839213Sgibbs rcap = (struct scsi_read_capacity_data *)malloc(sizeof(*rcap), 152939213Sgibbs M_TEMP, 153039213Sgibbs M_NOWAIT); 153139213Sgibbs if (rcap == NULL) { 153239213Sgibbs xpt_print_path(periph->path); 153339213Sgibbs printf("cdstart: Couldn't malloc read_capacity data\n"); 153439213Sgibbs /* cd_free_periph??? */ 153539213Sgibbs break; 153639213Sgibbs } 153739213Sgibbs csio = &start_ccb->csio; 153839213Sgibbs scsi_read_capacity(csio, 153939213Sgibbs /*retries*/1, 154039213Sgibbs cddone, 154139213Sgibbs MSG_SIMPLE_Q_TAG, 154239213Sgibbs rcap, 154339213Sgibbs SSD_FULL_SIZE, 154439213Sgibbs /*timeout*/20000); 154539213Sgibbs start_ccb->ccb_h.ccb_bp = NULL; 154639213Sgibbs start_ccb->ccb_h.ccb_state = CD_CCB_PROBE; 154739213Sgibbs xpt_action(start_ccb); 154839213Sgibbs break; 154939213Sgibbs } 155039213Sgibbs } 155139213Sgibbs} 155239213Sgibbs 155339213Sgibbsstatic void 155439213Sgibbscddone(struct cam_periph *periph, union ccb *done_ccb) 155539213Sgibbs{ 155639213Sgibbs struct cd_softc *softc; 155739213Sgibbs struct ccb_scsiio *csio; 155839213Sgibbs 155939213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cddone\n")); 156039213Sgibbs 156139213Sgibbs softc = (struct cd_softc *)periph->softc; 156239213Sgibbs csio = &done_ccb->csio; 156339213Sgibbs 156439213Sgibbs switch (csio->ccb_h.ccb_state & CD_CCB_TYPE_MASK) { 156539213Sgibbs case CD_CCB_BUFFER_IO: 156639213Sgibbs { 156739213Sgibbs struct buf *bp; 156839213Sgibbs int error; 156939213Sgibbs int oldspl; 157039213Sgibbs 157139213Sgibbs bp = (struct buf *)done_ccb->ccb_h.ccb_bp; 157239213Sgibbs error = 0; 157339213Sgibbs 157439213Sgibbs if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 157539213Sgibbs int sf; 157639213Sgibbs 157739213Sgibbs if ((done_ccb->ccb_h.ccb_state & CD_CCB_RETRY_UA) != 0) 157839213Sgibbs sf = SF_RETRY_UA; 157939213Sgibbs else 158039213Sgibbs sf = 0; 158146747Sken 158246747Sken /* Retry selection timeouts */ 158346747Sken sf |= SF_RETRY_SELTO; 158446747Sken 158539213Sgibbs if ((error = cderror(done_ccb, 0, sf)) == ERESTART) { 158639213Sgibbs /* 158739213Sgibbs * A retry was scheuled, so 158839213Sgibbs * just return. 158939213Sgibbs */ 159039213Sgibbs return; 159139213Sgibbs } 159239213Sgibbs } 159339213Sgibbs 159439213Sgibbs if (error != 0) { 159539213Sgibbs int s; 159639213Sgibbs struct buf *q_bp; 159739213Sgibbs 159839213Sgibbs xpt_print_path(periph->path); 159939213Sgibbs printf("cddone: got error %#x back\n", error); 160039213Sgibbs s = splbio(); 160139213Sgibbs while ((q_bp = bufq_first(&softc->buf_queue)) != NULL) { 160239213Sgibbs bufq_remove(&softc->buf_queue, q_bp); 160339213Sgibbs q_bp->b_resid = q_bp->b_bcount; 160439213Sgibbs q_bp->b_error = EIO; 160539213Sgibbs q_bp->b_flags |= B_ERROR; 160639213Sgibbs biodone(q_bp); 160739213Sgibbs } 160839213Sgibbs splx(s); 160939213Sgibbs bp->b_resid = bp->b_bcount; 161039213Sgibbs bp->b_error = error; 161139213Sgibbs bp->b_flags |= B_ERROR; 161239213Sgibbs cam_release_devq(done_ccb->ccb_h.path, 161339213Sgibbs /*relsim_flags*/0, 161439213Sgibbs /*reduction*/0, 161539213Sgibbs /*timeout*/0, 161639213Sgibbs /*getcount_only*/0); 161739213Sgibbs 161839213Sgibbs } else { 161939213Sgibbs bp->b_resid = csio->resid; 162039213Sgibbs bp->b_error = 0; 162139213Sgibbs if (bp->b_resid != 0) { 162239213Sgibbs /* Short transfer ??? */ 162339213Sgibbs bp->b_flags |= B_ERROR; 162439213Sgibbs } 162539213Sgibbs } 162639213Sgibbs 162739213Sgibbs /* 162839213Sgibbs * Block out any asyncronous callbacks 162939213Sgibbs * while we touch the pending ccb list. 163039213Sgibbs */ 163139213Sgibbs oldspl = splcam(); 163239213Sgibbs LIST_REMOVE(&done_ccb->ccb_h, periph_links.le); 163339213Sgibbs splx(oldspl); 163439213Sgibbs 163539213Sgibbs devstat_end_transaction(&softc->device_stats, 163639213Sgibbs bp->b_bcount - bp->b_resid, 163739213Sgibbs done_ccb->csio.tag_action & 0xf, 163839213Sgibbs (bp->b_flags & B_READ) ? DEVSTAT_READ 163939213Sgibbs : DEVSTAT_WRITE); 164039213Sgibbs 164139213Sgibbs if (softc->flags & CD_FLAG_CHANGER) 164239213Sgibbs cdchangerschedule(softc); 164339213Sgibbs 164439213Sgibbs biodone(bp); 164539213Sgibbs break; 164639213Sgibbs } 164739213Sgibbs case CD_CCB_PROBE: 164839213Sgibbs { 164939213Sgibbs struct scsi_read_capacity_data *rdcap; 165039213Sgibbs char announce_buf[120]; /* 165139213Sgibbs * Currently (9/30/97) the 165239213Sgibbs * longest possible announce 165339213Sgibbs * buffer is 108 bytes, for the 165439213Sgibbs * first error case below. 165539213Sgibbs * That is 39 bytes for the 165639213Sgibbs * basic string, 16 bytes for the 165739213Sgibbs * biggest sense key (hardware 165839213Sgibbs * error), 52 bytes for the 165939213Sgibbs * text of the largest sense 166039213Sgibbs * qualifier valid for a CDROM, 166139213Sgibbs * (0x72, 0x03 or 0x04, 166239213Sgibbs * 0x03), and one byte for the 166339213Sgibbs * null terminating character. 166439213Sgibbs * To allow for longer strings, 166539213Sgibbs * the announce buffer is 120 166639213Sgibbs * bytes. 166739213Sgibbs */ 166839213Sgibbs struct cd_params *cdp; 166939213Sgibbs 167039213Sgibbs cdp = &softc->params; 167139213Sgibbs 167239213Sgibbs rdcap = (struct scsi_read_capacity_data *)csio->data_ptr; 167339213Sgibbs 167439213Sgibbs cdp->disksize = scsi_4btoul (rdcap->addr) + 1; 167539213Sgibbs cdp->blksize = scsi_4btoul (rdcap->length); 167639213Sgibbs 167739213Sgibbs if ((csio->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 167839213Sgibbs 167941514Sarchie snprintf(announce_buf, sizeof(announce_buf), 168040020Sken "cd present [%lu x %lu byte records]", 168140020Sken cdp->disksize, (u_long)cdp->blksize); 168239213Sgibbs 168339213Sgibbs } else { 168439213Sgibbs int error; 168539213Sgibbs /* 168639213Sgibbs * Retry any UNIT ATTENTION type errors. They 168739213Sgibbs * are expected at boot. 168839213Sgibbs */ 168946747Sken error = cderror(done_ccb, 0, SF_RETRY_UA | 169046747Sken SF_NO_PRINT | SF_RETRY_SELTO); 169139213Sgibbs if (error == ERESTART) { 169239213Sgibbs /* 169339213Sgibbs * A retry was scheuled, so 169439213Sgibbs * just return. 169539213Sgibbs */ 169639213Sgibbs return; 169739213Sgibbs } else if (error != 0) { 169839213Sgibbs 169939213Sgibbs struct scsi_sense_data *sense; 170039213Sgibbs int asc, ascq; 170139213Sgibbs int sense_key, error_code; 170239213Sgibbs int have_sense; 170339213Sgibbs cam_status status; 170439213Sgibbs struct ccb_getdev cgd; 170539213Sgibbs 170639213Sgibbs /* Don't wedge this device's queue */ 170739213Sgibbs cam_release_devq(done_ccb->ccb_h.path, 170839213Sgibbs /*relsim_flags*/0, 170939213Sgibbs /*reduction*/0, 171039213Sgibbs /*timeout*/0, 171139213Sgibbs /*getcount_only*/0); 171239213Sgibbs 171339213Sgibbs status = done_ccb->ccb_h.status; 171439213Sgibbs 171539213Sgibbs xpt_setup_ccb(&cgd.ccb_h, 171639213Sgibbs done_ccb->ccb_h.path, 171739213Sgibbs /* priority */ 1); 171839213Sgibbs cgd.ccb_h.func_code = XPT_GDEV_TYPE; 171939213Sgibbs xpt_action((union ccb *)&cgd); 172039213Sgibbs 172139213Sgibbs if (((csio->ccb_h.flags & CAM_SENSE_PHYS) != 0) 172239213Sgibbs || ((csio->ccb_h.flags & CAM_SENSE_PTR) != 0) 172339213Sgibbs || ((status & CAM_AUTOSNS_VALID) == 0)) 172439213Sgibbs have_sense = FALSE; 172539213Sgibbs else 172639213Sgibbs have_sense = TRUE; 172739213Sgibbs 172839213Sgibbs if (have_sense) { 172939213Sgibbs sense = &csio->sense_data; 173039213Sgibbs scsi_extract_sense(sense, &error_code, 173139213Sgibbs &sense_key, 173239213Sgibbs &asc, &ascq); 173339213Sgibbs } 173439213Sgibbs /* 173546581Sken * Attach to anything that claims to be a 173646581Sken * CDROM or WORM device, as long as it 173746581Sken * doesn't return a "Logical unit not 173846581Sken * supported" (0x25) error. 173939213Sgibbs */ 174046581Sken if ((have_sense) && (asc != 0x25) 174139213Sgibbs && (error_code == SSD_CURRENT_ERROR)) 174241514Sarchie snprintf(announce_buf, 174341514Sarchie sizeof(announce_buf), 174439213Sgibbs "Attempt to query device " 174539213Sgibbs "size failed: %s, %s", 174639213Sgibbs scsi_sense_key_text[sense_key], 174739213Sgibbs scsi_sense_desc(asc,ascq, 174839213Sgibbs &cgd.inq_data)); 174939213Sgibbs else if (cgd.pd_type == T_CDROM) { 175039213Sgibbs /* 175139213Sgibbs * We only print out an error for 175239213Sgibbs * CDROM type devices. For WORM 175339213Sgibbs * devices, we don't print out an 175439213Sgibbs * error since a few WORM devices 175539213Sgibbs * don't support CDROM commands. 175639213Sgibbs * If we have sense information, go 175739213Sgibbs * ahead and print it out. 175839213Sgibbs * Otherwise, just say that we 175939213Sgibbs * couldn't attach. 176039213Sgibbs */ 176139213Sgibbs 176239213Sgibbs /* 176339213Sgibbs * Just print out the error, not 176439213Sgibbs * the full probe message, when we 176539213Sgibbs * don't attach. 176639213Sgibbs */ 176740020Sken if (have_sense) 176840020Sken scsi_sense_print( 176940020Sken &done_ccb->csio); 177040020Sken else { 177140020Sken xpt_print_path(periph->path); 177240020Sken printf("got CAM status %#x\n", 177340020Sken done_ccb->ccb_h.status); 177440020Sken } 177540020Sken xpt_print_path(periph->path); 177640020Sken printf("fatal error, failed" 177740603Sken " to attach to device\n"); 177839213Sgibbs 177939213Sgibbs /* 178040603Sken * Invalidate this peripheral. 178139213Sgibbs */ 178239213Sgibbs cam_periph_invalidate(periph); 178340020Sken 178440020Sken announce_buf[0] = '\0'; 178539213Sgibbs } else { 178640603Sken 178739213Sgibbs /* 178840603Sken * Invalidate this peripheral. 178939213Sgibbs */ 179039213Sgibbs cam_periph_invalidate(periph); 179140020Sken announce_buf[0] = '\0'; 179239213Sgibbs } 179339213Sgibbs } 179439213Sgibbs } 179539213Sgibbs free(rdcap, M_TEMP); 179642378Smjacob if (announce_buf[0] != '\0') { 179739213Sgibbs xpt_announce_periph(periph, announce_buf); 179842378Smjacob if (softc->flags & CD_FLAG_CHANGER) 179942378Smjacob cdchangerschedule(softc); 180042378Smjacob } 180140020Sken softc->state = CD_STATE_NORMAL; 180242378Smjacob /* 180342378Smjacob * Since our peripheral may be invalidated by an error 180442378Smjacob * above or an external event, we must release our CCB 180542378Smjacob * before releasing the probe lock on the peripheral. 180642378Smjacob * The peripheral will only go away once the last lock 180742378Smjacob * is removed, and we need it around for the CCB release 180842378Smjacob * operation. 180942378Smjacob */ 181042378Smjacob xpt_release_ccb(done_ccb); 181140020Sken cam_periph_unlock(periph); 181242378Smjacob return; 181339213Sgibbs } 181439213Sgibbs case CD_CCB_WAITING: 181539213Sgibbs { 181639213Sgibbs /* Caller will release the CCB */ 181739213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, 181839213Sgibbs ("trying to wakeup ccbwait\n")); 181939213Sgibbs 182039213Sgibbs wakeup(&done_ccb->ccb_h.cbfcnp); 182139213Sgibbs return; 182239213Sgibbs } 182342378Smjacob default: 182442378Smjacob break; 182539213Sgibbs } 182639213Sgibbs xpt_release_ccb(done_ccb); 182739213Sgibbs} 182839213Sgibbs 182939213Sgibbsstatic int 183039213Sgibbscdioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) 183139213Sgibbs{ 183239213Sgibbs 183339213Sgibbs struct cam_periph *periph; 183439213Sgibbs struct cd_softc *softc; 183540020Sken int error, unit; 183639213Sgibbs 183739213Sgibbs unit = dkunit(dev); 183839213Sgibbs 183939213Sgibbs periph = cam_extend_get(cdperiphs, unit); 184039213Sgibbs if (periph == NULL) 184139213Sgibbs return(ENXIO); 184239213Sgibbs 184339213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdioctl\n")); 184439213Sgibbs 184539213Sgibbs softc = (struct cd_softc *)periph->softc; 184639213Sgibbs 184739213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, 184840020Sken ("trying to do ioctl %#lx\n", cmd)); 184939213Sgibbs 185040020Sken error = cam_periph_lock(periph, PRIBIO | PCATCH); 185139213Sgibbs 185240020Sken if (error != 0) 185340020Sken return(error); 185440020Sken 185539213Sgibbs switch (cmd) { 185639213Sgibbs 185739213Sgibbs case CDIOCPLAYTRACKS: 185839213Sgibbs { 185939213Sgibbs struct ioc_play_track *args 186039213Sgibbs = (struct ioc_play_track *) addr; 186139213Sgibbs struct cd_mode_data *data; 186239213Sgibbs 186339213Sgibbs data = malloc(sizeof(struct cd_mode_data), M_TEMP, 186439213Sgibbs M_WAITOK); 186539213Sgibbs 186639213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 186739213Sgibbs ("trying to do CDIOCPLAYTRACKS\n")); 186839213Sgibbs 186939213Sgibbs error = cdgetmode(periph, data, AUDIO_PAGE); 187039213Sgibbs if (error) { 187139213Sgibbs free(data, M_TEMP); 187239213Sgibbs break; 187339213Sgibbs } 187439213Sgibbs data->page.audio.flags &= ~CD_PA_SOTC; 187539213Sgibbs data->page.audio.flags |= CD_PA_IMMED; 187639213Sgibbs error = cdsetmode(periph, data); 187739213Sgibbs free(data, M_TEMP); 187839213Sgibbs if (error) 187939213Sgibbs break; 188039213Sgibbs if (softc->quirks & CD_Q_BCD_TRACKS) { 188139213Sgibbs args->start_track = bin2bcd(args->start_track); 188239213Sgibbs args->end_track = bin2bcd(args->end_track); 188339213Sgibbs } 188439213Sgibbs error = cdplaytracks(periph, 188539213Sgibbs args->start_track, 188639213Sgibbs args->start_index, 188739213Sgibbs args->end_track, 188839213Sgibbs args->end_index); 188939213Sgibbs } 189039213Sgibbs break; 189139213Sgibbs case CDIOCPLAYMSF: 189239213Sgibbs { 189339213Sgibbs struct ioc_play_msf *args 189439213Sgibbs = (struct ioc_play_msf *) addr; 189539213Sgibbs struct cd_mode_data *data; 189639213Sgibbs 189739213Sgibbs data = malloc(sizeof(struct cd_mode_data), M_TEMP, 189839213Sgibbs M_WAITOK); 189939213Sgibbs 190039213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 190139213Sgibbs ("trying to do CDIOCPLAYMSF\n")); 190239213Sgibbs 190339213Sgibbs error = cdgetmode(periph, data, AUDIO_PAGE); 190439213Sgibbs if (error) { 190539213Sgibbs free(data, M_TEMP); 190639213Sgibbs break; 190739213Sgibbs } 190839213Sgibbs data->page.audio.flags &= ~CD_PA_SOTC; 190939213Sgibbs data->page.audio.flags |= CD_PA_IMMED; 191039213Sgibbs error = cdsetmode(periph, data); 191139213Sgibbs free(data, M_TEMP); 191239213Sgibbs if (error) 191339213Sgibbs break; 191439213Sgibbs error = cdplaymsf(periph, 191539213Sgibbs args->start_m, 191639213Sgibbs args->start_s, 191739213Sgibbs args->start_f, 191839213Sgibbs args->end_m, 191939213Sgibbs args->end_s, 192039213Sgibbs args->end_f); 192139213Sgibbs } 192239213Sgibbs break; 192339213Sgibbs case CDIOCPLAYBLOCKS: 192439213Sgibbs { 192539213Sgibbs struct ioc_play_blocks *args 192639213Sgibbs = (struct ioc_play_blocks *) addr; 192739213Sgibbs struct cd_mode_data *data; 192839213Sgibbs 192939213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 193039213Sgibbs ("trying to do CDIOCPLAYBLOCKS\n")); 193139213Sgibbs 193239213Sgibbs data = malloc(sizeof(struct cd_mode_data), M_TEMP, 193339213Sgibbs M_WAITOK); 193439213Sgibbs 193539213Sgibbs error = cdgetmode(periph, data, AUDIO_PAGE); 193639213Sgibbs if (error) { 193739213Sgibbs free(data, M_TEMP); 193839213Sgibbs break; 193939213Sgibbs } 194039213Sgibbs data->page.audio.flags &= ~CD_PA_SOTC; 194139213Sgibbs data->page.audio.flags |= CD_PA_IMMED; 194239213Sgibbs error = cdsetmode(periph, data); 194339213Sgibbs free(data, M_TEMP); 194439213Sgibbs if (error) 194539213Sgibbs break; 194639213Sgibbs error = cdplay(periph, args->blk, args->len); 194739213Sgibbs } 194839213Sgibbs break; 194939213Sgibbs case CDIOCREADSUBCHANNEL: 195039213Sgibbs { 195139213Sgibbs struct ioc_read_subchannel *args 195239213Sgibbs = (struct ioc_read_subchannel *) addr; 195339213Sgibbs struct cd_sub_channel_info *data; 195439213Sgibbs u_int32_t len = args->data_len; 195539213Sgibbs 195639213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 195739213Sgibbs ("trying to do CDIOCREADSUBCHANNEL\n")); 195839213Sgibbs 195939213Sgibbs data = malloc(sizeof(struct cd_sub_channel_info), 196039213Sgibbs M_TEMP, M_WAITOK); 196139213Sgibbs 196239213Sgibbs if ((len > sizeof(struct cd_sub_channel_info)) || 196339213Sgibbs (len < sizeof(struct cd_sub_channel_header))) { 196439213Sgibbs printf( 196539213Sgibbs "scsi_cd: cdioctl: " 196639213Sgibbs "cdioreadsubchannel: error, len=%d\n", 196739213Sgibbs len); 196839213Sgibbs error = EINVAL; 196939213Sgibbs free(data, M_TEMP); 197039213Sgibbs break; 197139213Sgibbs } 197239213Sgibbs 197339213Sgibbs if (softc->quirks & CD_Q_BCD_TRACKS) 197439213Sgibbs args->track = bin2bcd(args->track); 197539213Sgibbs 197639213Sgibbs error = cdreadsubchannel(periph, args->address_format, 197739213Sgibbs args->data_format, args->track, data, len); 197839213Sgibbs 197939213Sgibbs if (error) { 198039213Sgibbs free(data, M_TEMP); 198139213Sgibbs break; 198239213Sgibbs } 198339213Sgibbs if (softc->quirks & CD_Q_BCD_TRACKS) 198439213Sgibbs data->what.track_info.track_number = 198539213Sgibbs bcd2bin(data->what.track_info.track_number); 198639213Sgibbs len = min(len, ((data->header.data_len[0] << 8) + 198739213Sgibbs data->header.data_len[1] + 198839213Sgibbs sizeof(struct cd_sub_channel_header))); 198939213Sgibbs if (copyout(data, args->data, len) != 0) { 199039213Sgibbs error = EFAULT; 199139213Sgibbs } 199239213Sgibbs free(data, M_TEMP); 199339213Sgibbs } 199439213Sgibbs break; 199539213Sgibbs 199639213Sgibbs case CDIOREADTOCHEADER: 199739213Sgibbs { 199839213Sgibbs struct ioc_toc_header *th; 199939213Sgibbs 200039213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 200139213Sgibbs ("trying to do CDIOREADTOCHEADER\n")); 200239213Sgibbs 200339213Sgibbs th = malloc(sizeof(struct ioc_toc_header), M_TEMP, 200439213Sgibbs M_WAITOK); 200539213Sgibbs error = cdreadtoc(periph, 0, 0, 200639213Sgibbs (struct cd_toc_entry *)th, 200739213Sgibbs sizeof (*th)); 200839213Sgibbs if (error) { 200939213Sgibbs free(th, M_TEMP); 201039213Sgibbs break; 201139213Sgibbs } 201239213Sgibbs if (softc->quirks & CD_Q_BCD_TRACKS) { 201339213Sgibbs /* we are going to have to convert the BCD 201439213Sgibbs * encoding on the cd to what is expected 201539213Sgibbs */ 201639213Sgibbs th->starting_track = 201739213Sgibbs bcd2bin(th->starting_track); 201839213Sgibbs th->ending_track = bcd2bin(th->ending_track); 201939213Sgibbs } 202039213Sgibbs NTOHS(th->len); 202139213Sgibbs bcopy(th, addr, sizeof(*th)); 202239213Sgibbs free(th, M_TEMP); 202339213Sgibbs } 202439213Sgibbs break; 202539213Sgibbs case CDIOREADTOCENTRYS: 202639213Sgibbs { 202739213Sgibbs typedef struct { 202839213Sgibbs struct ioc_toc_header header; 202939213Sgibbs struct cd_toc_entry entries[100]; 203039213Sgibbs } data_t; 203139213Sgibbs typedef struct { 203239213Sgibbs struct ioc_toc_header header; 203339213Sgibbs struct cd_toc_entry entry; 203439213Sgibbs } lead_t; 203539213Sgibbs 203639213Sgibbs data_t *data; 203739213Sgibbs lead_t *lead; 203839213Sgibbs struct ioc_read_toc_entry *te = 203939213Sgibbs (struct ioc_read_toc_entry *) addr; 204039213Sgibbs struct ioc_toc_header *th; 204139213Sgibbs u_int32_t len, readlen, idx, num; 204239213Sgibbs u_int32_t starting_track = te->starting_track; 204339213Sgibbs 204439213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 204539213Sgibbs ("trying to do CDIOREADTOCENTRYS\n")); 204639213Sgibbs 204739213Sgibbs data = malloc(sizeof(data_t), M_TEMP, M_WAITOK); 204839213Sgibbs lead = malloc(sizeof(lead_t), M_TEMP, M_WAITOK); 204939213Sgibbs 205039213Sgibbs if (te->data_len < sizeof(struct cd_toc_entry) 205139213Sgibbs || (te->data_len % sizeof(struct cd_toc_entry)) != 0 205239213Sgibbs || (te->address_format != CD_MSF_FORMAT 205339213Sgibbs && te->address_format != CD_LBA_FORMAT)) { 205439213Sgibbs error = EINVAL; 205539213Sgibbs printf("scsi_cd: error in readtocentries, " 205639213Sgibbs "returning EINVAL\n"); 205739213Sgibbs free(data, M_TEMP); 205839213Sgibbs free(lead, M_TEMP); 205939213Sgibbs break; 206039213Sgibbs } 206139213Sgibbs 206239213Sgibbs th = &data->header; 206339213Sgibbs error = cdreadtoc(periph, 0, 0, 206439213Sgibbs (struct cd_toc_entry *)th, 206539213Sgibbs sizeof (*th)); 206639213Sgibbs if (error) { 206739213Sgibbs free(data, M_TEMP); 206839213Sgibbs free(lead, M_TEMP); 206939213Sgibbs break; 207039213Sgibbs } 207139213Sgibbs 207239213Sgibbs if (softc->quirks & CD_Q_BCD_TRACKS) { 207339213Sgibbs /* we are going to have to convert the BCD 207439213Sgibbs * encoding on the cd to what is expected 207539213Sgibbs */ 207639213Sgibbs th->starting_track = 207739213Sgibbs bcd2bin(th->starting_track); 207839213Sgibbs th->ending_track = bcd2bin(th->ending_track); 207939213Sgibbs } 208039213Sgibbs 208139213Sgibbs if (starting_track == 0) 208239213Sgibbs starting_track = th->starting_track; 208339213Sgibbs else if (starting_track == LEADOUT) 208439213Sgibbs starting_track = th->ending_track + 1; 208539213Sgibbs else if (starting_track < th->starting_track || 208639213Sgibbs starting_track > th->ending_track + 1) { 208739213Sgibbs printf("scsi_cd: error in readtocentries, " 208839213Sgibbs "returning EINVAL\n"); 208939213Sgibbs free(data, M_TEMP); 209039213Sgibbs free(lead, M_TEMP); 209139213Sgibbs error = EINVAL; 209239213Sgibbs break; 209339213Sgibbs } 209439213Sgibbs 209539213Sgibbs /* calculate reading length without leadout entry */ 209639213Sgibbs readlen = (th->ending_track - starting_track + 1) * 209739213Sgibbs sizeof(struct cd_toc_entry); 209839213Sgibbs 209939213Sgibbs /* and with leadout entry */ 210039213Sgibbs len = readlen + sizeof(struct cd_toc_entry); 210139213Sgibbs if (te->data_len < len) { 210239213Sgibbs len = te->data_len; 210339213Sgibbs if (readlen > len) 210439213Sgibbs readlen = len; 210539213Sgibbs } 210639213Sgibbs if (len > sizeof(data->entries)) { 210739213Sgibbs printf("scsi_cd: error in readtocentries, " 210839213Sgibbs "returning EINVAL\n"); 210939213Sgibbs error = EINVAL; 211039213Sgibbs free(data, M_TEMP); 211139213Sgibbs free(lead, M_TEMP); 211239213Sgibbs break; 211339213Sgibbs } 211439213Sgibbs num = len / sizeof(struct cd_toc_entry); 211539213Sgibbs 211639213Sgibbs if (readlen > 0) { 211739213Sgibbs error = cdreadtoc(periph, te->address_format, 211839213Sgibbs starting_track, 211939213Sgibbs (struct cd_toc_entry *)data, 212039213Sgibbs readlen + sizeof (*th)); 212139213Sgibbs if (error) { 212239213Sgibbs free(data, M_TEMP); 212339213Sgibbs free(lead, M_TEMP); 212439213Sgibbs break; 212539213Sgibbs } 212639213Sgibbs } 212739213Sgibbs 212839213Sgibbs /* make leadout entry if needed */ 212939213Sgibbs idx = starting_track + num - 1; 213039213Sgibbs if (softc->quirks & CD_Q_BCD_TRACKS) 213139213Sgibbs th->ending_track = bcd2bin(th->ending_track); 213239213Sgibbs if (idx == th->ending_track + 1) { 213339213Sgibbs error = cdreadtoc(periph, te->address_format, 213439213Sgibbs LEADOUT, 213539213Sgibbs (struct cd_toc_entry *)lead, 213639213Sgibbs sizeof(*lead)); 213739213Sgibbs if (error) { 213839213Sgibbs free(data, M_TEMP); 213939213Sgibbs free(lead, M_TEMP); 214039213Sgibbs break; 214139213Sgibbs } 214239213Sgibbs data->entries[idx - starting_track] = 214339213Sgibbs lead->entry; 214439213Sgibbs } 214539213Sgibbs if (softc->quirks & CD_Q_BCD_TRACKS) { 214639213Sgibbs for (idx = 0; idx < num - 1; idx++) { 214739213Sgibbs data->entries[idx].track = 214839213Sgibbs bcd2bin(data->entries[idx].track); 214939213Sgibbs } 215039213Sgibbs } 215139213Sgibbs 215239213Sgibbs error = copyout(data->entries, te->data, len); 215339213Sgibbs free(data, M_TEMP); 215439213Sgibbs free(lead, M_TEMP); 215539213Sgibbs } 215639213Sgibbs break; 215739213Sgibbs case CDIOREADTOCENTRY: 215839213Sgibbs { 215939213Sgibbs /* yeah yeah, this is ugly */ 216039213Sgibbs typedef struct { 216139213Sgibbs struct ioc_toc_header header; 216239213Sgibbs struct cd_toc_entry entry; 216339213Sgibbs } data_t; 216439213Sgibbs 216539213Sgibbs data_t *data; 216639213Sgibbs struct ioc_read_toc_single_entry *te = 216739213Sgibbs (struct ioc_read_toc_single_entry *) addr; 216839213Sgibbs struct ioc_toc_header *th; 216939213Sgibbs u_int32_t track; 217039213Sgibbs 217139213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 217239213Sgibbs ("trying to do CDIOREADTOCENTRY\n")); 217339213Sgibbs 217439213Sgibbs data = malloc(sizeof(data_t), M_TEMP, M_WAITOK); 217539213Sgibbs 217639213Sgibbs if (te->address_format != CD_MSF_FORMAT 217739213Sgibbs && te->address_format != CD_LBA_FORMAT) { 217839213Sgibbs printf("error in readtocentry, " 217939213Sgibbs " returning EINVAL\n"); 218039213Sgibbs free(data, M_TEMP); 218139213Sgibbs error = EINVAL; 218239213Sgibbs break; 218339213Sgibbs } 218439213Sgibbs 218539213Sgibbs th = &data->header; 218639213Sgibbs error = cdreadtoc(periph, 0, 0, 218739213Sgibbs (struct cd_toc_entry *)th, 218839213Sgibbs sizeof (*th)); 218939213Sgibbs if (error) { 219039213Sgibbs free(data, M_TEMP); 219139213Sgibbs break; 219239213Sgibbs } 219339213Sgibbs 219439213Sgibbs if (softc->quirks & CD_Q_BCD_TRACKS) { 219539213Sgibbs /* we are going to have to convert the BCD 219639213Sgibbs * encoding on the cd to what is expected 219739213Sgibbs */ 219839213Sgibbs th->starting_track = 219939213Sgibbs bcd2bin(th->starting_track); 220039213Sgibbs th->ending_track = bcd2bin(th->ending_track); 220139213Sgibbs } 220239213Sgibbs track = te->track; 220339213Sgibbs if (track == 0) 220439213Sgibbs track = th->starting_track; 220539213Sgibbs else if (track == LEADOUT) 220639213Sgibbs /* OK */; 220739213Sgibbs else if (track < th->starting_track || 220839213Sgibbs track > th->ending_track + 1) { 220939213Sgibbs printf("error in readtocentry, " 221039213Sgibbs " returning EINVAL\n"); 221139213Sgibbs free(data, M_TEMP); 221239213Sgibbs error = EINVAL; 221339213Sgibbs break; 221439213Sgibbs } 221539213Sgibbs 221639213Sgibbs error = cdreadtoc(periph, te->address_format, track, 221739213Sgibbs (struct cd_toc_entry *)data, 221839213Sgibbs sizeof(data_t)); 221939213Sgibbs if (error) { 222039213Sgibbs free(data, M_TEMP); 222139213Sgibbs break; 222239213Sgibbs } 222339213Sgibbs 222439213Sgibbs if (softc->quirks & CD_Q_BCD_TRACKS) 222539213Sgibbs data->entry.track = bcd2bin(data->entry.track); 222639213Sgibbs bcopy(&data->entry, &te->entry, 222739213Sgibbs sizeof(struct cd_toc_entry)); 222839213Sgibbs free(data, M_TEMP); 222939213Sgibbs } 223039213Sgibbs break; 223139213Sgibbs case CDIOCSETPATCH: 223239213Sgibbs { 223339213Sgibbs struct ioc_patch *arg = (struct ioc_patch *) addr; 223439213Sgibbs struct cd_mode_data *data; 223539213Sgibbs 223639213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 223739213Sgibbs ("trying to do CDIOCSETPATCH\n")); 223839213Sgibbs 223939213Sgibbs data = malloc(sizeof(struct cd_mode_data), M_TEMP, 224039213Sgibbs M_WAITOK); 224139213Sgibbs error = cdgetmode(periph, data, AUDIO_PAGE); 224239213Sgibbs if (error) { 224339213Sgibbs free(data, M_TEMP); 224439213Sgibbs break; 224539213Sgibbs } 224639213Sgibbs data->page.audio.port[LEFT_PORT].channels = 224739213Sgibbs arg->patch[0]; 224839213Sgibbs data->page.audio.port[RIGHT_PORT].channels = 224939213Sgibbs arg->patch[1]; 225039213Sgibbs data->page.audio.port[2].channels = arg->patch[2]; 225139213Sgibbs data->page.audio.port[3].channels = arg->patch[3]; 225239213Sgibbs error = cdsetmode(periph, data); 225339213Sgibbs free(data, M_TEMP); 225439213Sgibbs } 225539213Sgibbs break; 225639213Sgibbs case CDIOCGETVOL: 225739213Sgibbs { 225839213Sgibbs struct ioc_vol *arg = (struct ioc_vol *) addr; 225939213Sgibbs struct cd_mode_data *data; 226039213Sgibbs 226139213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 226239213Sgibbs ("trying to do CDIOCGETVOL\n")); 226339213Sgibbs 226439213Sgibbs data = malloc(sizeof(struct cd_mode_data), M_TEMP, 226539213Sgibbs M_WAITOK); 226639213Sgibbs error = cdgetmode(periph, data, AUDIO_PAGE); 226739213Sgibbs if (error) { 226839213Sgibbs free(data, M_TEMP); 226939213Sgibbs break; 227039213Sgibbs } 227139213Sgibbs arg->vol[LEFT_PORT] = 227239213Sgibbs data->page.audio.port[LEFT_PORT].volume; 227339213Sgibbs arg->vol[RIGHT_PORT] = 227439213Sgibbs data->page.audio.port[RIGHT_PORT].volume; 227539213Sgibbs arg->vol[2] = data->page.audio.port[2].volume; 227639213Sgibbs arg->vol[3] = data->page.audio.port[3].volume; 227739213Sgibbs free(data, M_TEMP); 227839213Sgibbs } 227939213Sgibbs break; 228039213Sgibbs case CDIOCSETVOL: 228139213Sgibbs { 228239213Sgibbs struct ioc_vol *arg = (struct ioc_vol *) addr; 228339213Sgibbs struct cd_mode_data *data; 228439213Sgibbs 228539213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 228639213Sgibbs ("trying to do CDIOCSETVOL\n")); 228739213Sgibbs 228839213Sgibbs data = malloc(sizeof(struct cd_mode_data), M_TEMP, 228939213Sgibbs M_WAITOK); 229039213Sgibbs error = cdgetmode(periph, data, AUDIO_PAGE); 229139213Sgibbs if (error) { 229239213Sgibbs free(data, M_TEMP); 229339213Sgibbs break; 229439213Sgibbs } 229539213Sgibbs data->page.audio.port[LEFT_PORT].channels = CHANNEL_0; 229639213Sgibbs data->page.audio.port[LEFT_PORT].volume = 229739213Sgibbs arg->vol[LEFT_PORT]; 229839213Sgibbs data->page.audio.port[RIGHT_PORT].channels = CHANNEL_1; 229939213Sgibbs data->page.audio.port[RIGHT_PORT].volume = 230039213Sgibbs arg->vol[RIGHT_PORT]; 230139213Sgibbs data->page.audio.port[2].volume = arg->vol[2]; 230239213Sgibbs data->page.audio.port[3].volume = arg->vol[3]; 230339213Sgibbs error = cdsetmode(periph, data); 230439213Sgibbs free(data, M_TEMP); 230539213Sgibbs } 230639213Sgibbs break; 230739213Sgibbs case CDIOCSETMONO: 230839213Sgibbs { 230939213Sgibbs struct cd_mode_data *data; 231039213Sgibbs 231139213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 231239213Sgibbs ("trying to do CDIOCSETMONO\n")); 231339213Sgibbs 231439213Sgibbs data = malloc(sizeof(struct cd_mode_data), 231539213Sgibbs M_TEMP, M_WAITOK); 231639213Sgibbs error = cdgetmode(periph, data, AUDIO_PAGE); 231739213Sgibbs if (error) { 231839213Sgibbs free(data, M_TEMP); 231939213Sgibbs break; 232039213Sgibbs } 232139213Sgibbs data->page.audio.port[LEFT_PORT].channels = 232239213Sgibbs LEFT_CHANNEL | RIGHT_CHANNEL; 232339213Sgibbs data->page.audio.port[RIGHT_PORT].channels = 232439213Sgibbs LEFT_CHANNEL | RIGHT_CHANNEL; 232539213Sgibbs data->page.audio.port[2].channels = 0; 232639213Sgibbs data->page.audio.port[3].channels = 0; 232739213Sgibbs error = cdsetmode(periph, data); 232839213Sgibbs free(data, M_TEMP); 232939213Sgibbs } 233039213Sgibbs break; 233139213Sgibbs case CDIOCSETSTEREO: 233239213Sgibbs { 233339213Sgibbs struct cd_mode_data *data; 233439213Sgibbs 233539213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 233639213Sgibbs ("trying to do CDIOCSETSTEREO\n")); 233739213Sgibbs 233839213Sgibbs data = malloc(sizeof(struct cd_mode_data), M_TEMP, 233939213Sgibbs M_WAITOK); 234039213Sgibbs error = cdgetmode(periph, data, AUDIO_PAGE); 234139213Sgibbs if (error) { 234239213Sgibbs free(data, M_TEMP); 234339213Sgibbs break; 234439213Sgibbs } 234539213Sgibbs data->page.audio.port[LEFT_PORT].channels = 234639213Sgibbs LEFT_CHANNEL; 234739213Sgibbs data->page.audio.port[RIGHT_PORT].channels = 234839213Sgibbs RIGHT_CHANNEL; 234939213Sgibbs data->page.audio.port[2].channels = 0; 235039213Sgibbs data->page.audio.port[3].channels = 0; 235139213Sgibbs error = cdsetmode(periph, data); 235239213Sgibbs free(data, M_TEMP); 235339213Sgibbs } 235439213Sgibbs break; 235539213Sgibbs case CDIOCSETMUTE: 235639213Sgibbs { 235739213Sgibbs struct cd_mode_data *data; 235839213Sgibbs 235939213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 236039213Sgibbs ("trying to do CDIOCSETMUTE\n")); 236139213Sgibbs 236239213Sgibbs data = malloc(sizeof(struct cd_mode_data), M_TEMP, 236339213Sgibbs M_WAITOK); 236439213Sgibbs error = cdgetmode(periph, data, AUDIO_PAGE); 236539213Sgibbs if (error) { 236639213Sgibbs free(data, M_TEMP); 236739213Sgibbs break; 236839213Sgibbs } 236939213Sgibbs data->page.audio.port[LEFT_PORT].channels = 0; 237039213Sgibbs data->page.audio.port[RIGHT_PORT].channels = 0; 237139213Sgibbs data->page.audio.port[2].channels = 0; 237239213Sgibbs data->page.audio.port[3].channels = 0; 237339213Sgibbs error = cdsetmode(periph, data); 237439213Sgibbs free(data, M_TEMP); 237539213Sgibbs } 237639213Sgibbs break; 237739213Sgibbs case CDIOCSETLEFT: 237839213Sgibbs { 237939213Sgibbs struct cd_mode_data *data; 238039213Sgibbs 238139213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 238239213Sgibbs ("trying to do CDIOCSETLEFT\n")); 238339213Sgibbs 238439213Sgibbs data = malloc(sizeof(struct cd_mode_data), M_TEMP, 238539213Sgibbs M_WAITOK); 238639213Sgibbs error = cdgetmode(periph, data, AUDIO_PAGE); 238739213Sgibbs if (error) { 238839213Sgibbs free(data, M_TEMP); 238939213Sgibbs break; 239039213Sgibbs } 239139213Sgibbs data->page.audio.port[LEFT_PORT].channels = 239239213Sgibbs LEFT_CHANNEL; 239339213Sgibbs data->page.audio.port[RIGHT_PORT].channels = 239439213Sgibbs LEFT_CHANNEL; 239539213Sgibbs data->page.audio.port[2].channels = 0; 239639213Sgibbs data->page.audio.port[3].channels = 0; 239739213Sgibbs error = cdsetmode(periph, data); 239839213Sgibbs free(data, M_TEMP); 239939213Sgibbs } 240039213Sgibbs break; 240139213Sgibbs case CDIOCSETRIGHT: 240239213Sgibbs { 240339213Sgibbs struct cd_mode_data *data; 240439213Sgibbs 240539213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 240639213Sgibbs ("trying to do CDIOCSETRIGHT\n")); 240739213Sgibbs 240839213Sgibbs data = malloc(sizeof(struct cd_mode_data), M_TEMP, 240939213Sgibbs M_WAITOK); 241039213Sgibbs error = cdgetmode(periph, data, AUDIO_PAGE); 241139213Sgibbs if (error) { 241239213Sgibbs free(data, M_TEMP); 241339213Sgibbs break; 241439213Sgibbs } 241539213Sgibbs data->page.audio.port[LEFT_PORT].channels = 241639213Sgibbs RIGHT_CHANNEL; 241739213Sgibbs data->page.audio.port[RIGHT_PORT].channels = 241839213Sgibbs RIGHT_CHANNEL; 241939213Sgibbs data->page.audio.port[2].channels = 0; 242039213Sgibbs data->page.audio.port[3].channels = 0; 242139213Sgibbs error = cdsetmode(periph, data); 242239213Sgibbs free(data, M_TEMP); 242339213Sgibbs } 242439213Sgibbs break; 242539213Sgibbs case CDIOCRESUME: 242639213Sgibbs error = cdpause(periph, 1); 242739213Sgibbs break; 242839213Sgibbs case CDIOCPAUSE: 242939213Sgibbs error = cdpause(periph, 0); 243039213Sgibbs break; 243139213Sgibbs case CDIOCSTART: 243239213Sgibbs error = cdstartunit(periph); 243339213Sgibbs break; 243439213Sgibbs case CDIOCSTOP: 243539213Sgibbs error = cdstopunit(periph, 0); 243639213Sgibbs break; 243739213Sgibbs case CDIOCEJECT: 243839213Sgibbs error = cdstopunit(periph, 1); 243939213Sgibbs break; 244039213Sgibbs case CDIOCALLOW: 244139213Sgibbs cdprevent(periph, PR_ALLOW); 244239213Sgibbs break; 244339213Sgibbs case CDIOCPREVENT: 244439213Sgibbs cdprevent(periph, PR_PREVENT); 244539213Sgibbs break; 244639213Sgibbs case CDIOCSETDEBUG: 244739213Sgibbs /* sc_link->flags |= (SDEV_DB1 | SDEV_DB2); */ 244839213Sgibbs error = ENOTTY; 244939213Sgibbs break; 245039213Sgibbs case CDIOCCLRDEBUG: 245139213Sgibbs /* sc_link->flags &= ~(SDEV_DB1 | SDEV_DB2); */ 245239213Sgibbs error = ENOTTY; 245339213Sgibbs break; 245439213Sgibbs case CDIOCRESET: 245539213Sgibbs /* return (cd_reset(periph)); */ 245639213Sgibbs error = ENOTTY; 245739213Sgibbs break; 245839213Sgibbs default: 245939213Sgibbs if (cmd == DIOCSBAD) { 246039213Sgibbs error = EINVAL; /* XXX */ 246139213Sgibbs break; 246239213Sgibbs } 246339213Sgibbs 246439213Sgibbs /* 246539213Sgibbs * Check to see whether we've got a disk-type ioctl. If we 246639213Sgibbs * don't, dsioctl will pass back an error code of ENOIOCTL. 246739213Sgibbs */ 246839213Sgibbs error = dsioctl("cd", dev, cmd, addr, flag, &softc->cd_slices, 246942590Seivind cdstrategy1, (ds_setgeom_t *)NULL); 247039213Sgibbs 247139213Sgibbs if (error != ENOIOCTL) 247239213Sgibbs break; 247339213Sgibbs 247439213Sgibbs error = cam_periph_ioctl(periph, cmd, addr, cderror); 247539213Sgibbs break; 247639213Sgibbs } 247739213Sgibbs 247840020Sken cam_periph_unlock(periph); 247940020Sken 248039213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("leaving cdioctl\n")); 248139213Sgibbs 248239213Sgibbs return (error); 248339213Sgibbs} 248439213Sgibbs 248539213Sgibbsstatic void 248639213Sgibbscdprevent(struct cam_periph *periph, int action) 248739213Sgibbs{ 248839213Sgibbs union ccb *ccb; 248939213Sgibbs struct cd_softc *softc; 249039213Sgibbs int error; 249139213Sgibbs 249239213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdprevent\n")); 249339213Sgibbs 249439213Sgibbs softc = (struct cd_softc *)periph->softc; 249539213Sgibbs 249639213Sgibbs if (((action == PR_ALLOW) 249739213Sgibbs && (softc->flags & CD_FLAG_DISC_LOCKED) == 0) 249839213Sgibbs || ((action == PR_PREVENT) 249939213Sgibbs && (softc->flags & CD_FLAG_DISC_LOCKED) != 0)) { 250039213Sgibbs return; 250139213Sgibbs } 250239213Sgibbs 250339213Sgibbs ccb = cdgetccb(periph, /* priority */ 1); 250439213Sgibbs 250539213Sgibbs scsi_prevent(&ccb->csio, 250639213Sgibbs /*retries*/ 1, 250739213Sgibbs cddone, 250839213Sgibbs MSG_SIMPLE_Q_TAG, 250939213Sgibbs action, 251039213Sgibbs SSD_FULL_SIZE, 251139213Sgibbs /* timeout */60000); 251239213Sgibbs 251339213Sgibbs error = cdrunccb(ccb, cderror, /*cam_flags*/0, 251446747Sken /*sense_flags*/SF_RETRY_UA|SF_NO_PRINT|SF_RETRY_SELTO); 251539213Sgibbs 251639213Sgibbs xpt_release_ccb(ccb); 251739213Sgibbs 251839213Sgibbs if (error == 0) { 251939213Sgibbs if (action == PR_ALLOW) 252039213Sgibbs softc->flags &= ~CD_FLAG_DISC_LOCKED; 252139213Sgibbs else 252239213Sgibbs softc->flags |= CD_FLAG_DISC_LOCKED; 252339213Sgibbs } 252439213Sgibbs} 252539213Sgibbs 252639213Sgibbsstatic int 252739213Sgibbscdsize(dev_t dev, u_int32_t *size) 252839213Sgibbs{ 252939213Sgibbs struct cam_periph *periph; 253039213Sgibbs struct cd_softc *softc; 253139213Sgibbs union ccb *ccb; 253239213Sgibbs struct scsi_read_capacity_data *rcap_buf; 253339213Sgibbs int error; 253439213Sgibbs 253539213Sgibbs periph = cam_extend_get(cdperiphs, dkunit(dev)); 253639213Sgibbs 253739213Sgibbs if (periph == NULL) 253839213Sgibbs return (ENXIO); 253939213Sgibbs 254039213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdsize\n")); 254139213Sgibbs 254239213Sgibbs softc = (struct cd_softc *)periph->softc; 254339213Sgibbs 254439213Sgibbs ccb = cdgetccb(periph, /* priority */ 1); 254539213Sgibbs 254639213Sgibbs rcap_buf = malloc(sizeof(struct scsi_read_capacity_data), 254739213Sgibbs M_TEMP, M_WAITOK); 254839213Sgibbs 254939213Sgibbs scsi_read_capacity(&ccb->csio, 255039213Sgibbs /*retries*/ 1, 255139213Sgibbs cddone, 255239213Sgibbs MSG_SIMPLE_Q_TAG, 255339213Sgibbs rcap_buf, 255439213Sgibbs SSD_FULL_SIZE, 255539213Sgibbs /* timeout */20000); 255639213Sgibbs 255739213Sgibbs error = cdrunccb(ccb, cderror, /*cam_flags*/0, 255846747Sken /*sense_flags*/SF_RETRY_UA|SF_NO_PRINT|SF_RETRY_SELTO); 255939213Sgibbs 256039213Sgibbs xpt_release_ccb(ccb); 256139213Sgibbs 256239213Sgibbs softc->params.disksize = scsi_4btoul(rcap_buf->addr) + 1; 256339213Sgibbs softc->params.blksize = scsi_4btoul(rcap_buf->length); 256439213Sgibbs 256539213Sgibbs free(rcap_buf, M_TEMP); 256639213Sgibbs *size = softc->params.disksize; 256739213Sgibbs 256839213Sgibbs return (error); 256939213Sgibbs 257039213Sgibbs} 257139213Sgibbs 257239213Sgibbsstatic int 257339213Sgibbscderror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) 257439213Sgibbs{ 257539213Sgibbs struct cd_softc *softc; 257639213Sgibbs struct cam_periph *periph; 257739213Sgibbs 257839213Sgibbs periph = xpt_path_periph(ccb->ccb_h.path); 257939213Sgibbs softc = (struct cd_softc *)periph->softc; 258039213Sgibbs 258139514Sgibbs /* 258239514Sgibbs * XXX 258339514Sgibbs * Until we have a better way of doing pack validation, 258439514Sgibbs * don't treat UAs as errors. 258539514Sgibbs */ 258639514Sgibbs sense_flags |= SF_RETRY_UA; 258739213Sgibbs return (cam_periph_error(ccb, cam_flags, sense_flags, 258839213Sgibbs &softc->saved_ccb)); 258939213Sgibbs} 259039213Sgibbs 259139213Sgibbs/* 259239213Sgibbs * Read table of contents 259339213Sgibbs */ 259439213Sgibbsstatic int 259539213Sgibbscdreadtoc(struct cam_periph *periph, u_int32_t mode, u_int32_t start, 259639213Sgibbs struct cd_toc_entry *data, u_int32_t len) 259739213Sgibbs{ 259839213Sgibbs struct scsi_read_toc *scsi_cmd; 259939213Sgibbs u_int32_t ntoc; 260039213Sgibbs struct ccb_scsiio *csio; 260139213Sgibbs union ccb *ccb; 260239213Sgibbs int error; 260339213Sgibbs 260439213Sgibbs ntoc = len; 260539213Sgibbs error = 0; 260639213Sgibbs 260739213Sgibbs ccb = cdgetccb(periph, /* priority */ 1); 260839213Sgibbs 260939213Sgibbs csio = &ccb->csio; 261039213Sgibbs 261139213Sgibbs cam_fill_csio(csio, 261239213Sgibbs /* retries */ 1, 261339213Sgibbs /* cbfcnp */ cddone, 261439213Sgibbs /* flags */ CAM_DIR_IN, 261539213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 261639213Sgibbs /* data_ptr */ (u_int8_t *)data, 261739213Sgibbs /* dxfer_len */ len, 261839213Sgibbs /* sense_len */ SSD_FULL_SIZE, 261939213Sgibbs sizeof(struct scsi_read_toc), 262039213Sgibbs /* timeout */ 50000); 262139213Sgibbs 262239213Sgibbs scsi_cmd = (struct scsi_read_toc *)&csio->cdb_io.cdb_bytes; 262339213Sgibbs bzero (scsi_cmd, sizeof(*scsi_cmd)); 262439213Sgibbs 262539213Sgibbs if (mode == CD_MSF_FORMAT) 262639213Sgibbs scsi_cmd->byte2 |= CD_MSF; 262739213Sgibbs scsi_cmd->from_track = start; 262839213Sgibbs /* scsi_ulto2b(ntoc, (u_int8_t *)scsi_cmd->data_len); */ 262939213Sgibbs scsi_cmd->data_len[0] = (ntoc) >> 8; 263039213Sgibbs scsi_cmd->data_len[1] = (ntoc) & 0xff; 263139213Sgibbs 263239213Sgibbs scsi_cmd->op_code = READ_TOC; 263339213Sgibbs 263439213Sgibbs error = cdrunccb(ccb, cderror, /*cam_flags*/0, 263546747Sken /*sense_flags*/SF_RETRY_UA|SF_RETRY_SELTO); 263639213Sgibbs 263739213Sgibbs xpt_release_ccb(ccb); 263839213Sgibbs 263939213Sgibbs return(error); 264039213Sgibbs} 264139213Sgibbs 264239213Sgibbsstatic int 264339213Sgibbscdreadsubchannel(struct cam_periph *periph, u_int32_t mode, 264439213Sgibbs u_int32_t format, int track, 264539213Sgibbs struct cd_sub_channel_info *data, u_int32_t len) 264639213Sgibbs{ 264739213Sgibbs struct scsi_read_subchannel *scsi_cmd; 264839213Sgibbs struct ccb_scsiio *csio; 264939213Sgibbs union ccb *ccb; 265039213Sgibbs int error; 265139213Sgibbs 265239213Sgibbs error = 0; 265339213Sgibbs 265439213Sgibbs ccb = cdgetccb(periph, /* priority */ 1); 265539213Sgibbs 265639213Sgibbs csio = &ccb->csio; 265739213Sgibbs 265839213Sgibbs cam_fill_csio(csio, 265939213Sgibbs /* retries */ 1, 266039213Sgibbs /* cbfcnp */ cddone, 266139213Sgibbs /* flags */ CAM_DIR_IN, 266239213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 266339213Sgibbs /* data_ptr */ (u_int8_t *)data, 266439213Sgibbs /* dxfer_len */ len, 266539213Sgibbs /* sense_len */ SSD_FULL_SIZE, 266639213Sgibbs sizeof(struct scsi_read_subchannel), 266739213Sgibbs /* timeout */ 50000); 266839213Sgibbs 266939213Sgibbs scsi_cmd = (struct scsi_read_subchannel *)&csio->cdb_io.cdb_bytes; 267039213Sgibbs bzero (scsi_cmd, sizeof(*scsi_cmd)); 267139213Sgibbs 267239213Sgibbs scsi_cmd->op_code = READ_SUBCHANNEL; 267339213Sgibbs if (mode == CD_MSF_FORMAT) 267439213Sgibbs scsi_cmd->byte1 |= CD_MSF; 267539213Sgibbs scsi_cmd->byte2 = SRS_SUBQ; 267639213Sgibbs scsi_cmd->subchan_format = format; 267739213Sgibbs scsi_cmd->track = track; 267839213Sgibbs scsi_ulto2b(len, (u_int8_t *)scsi_cmd->data_len); 267939213Sgibbs scsi_cmd->control = 0; 268039213Sgibbs 268139213Sgibbs error = cdrunccb(ccb, cderror, /*cam_flags*/0, 268246747Sken /*sense_flags*/SF_RETRY_UA|SF_RETRY_SELTO); 268339213Sgibbs 268439213Sgibbs xpt_release_ccb(ccb); 268539213Sgibbs 268639213Sgibbs return(error); 268739213Sgibbs} 268839213Sgibbs 268939213Sgibbs 269039213Sgibbsstatic int 269139213Sgibbscdgetmode(struct cam_periph *periph, struct cd_mode_data *data, u_int32_t page) 269239213Sgibbs{ 269339213Sgibbs struct scsi_mode_sense_6 *scsi_cmd; 269439213Sgibbs struct ccb_scsiio *csio; 269539213Sgibbs union ccb *ccb; 269639213Sgibbs int error; 269739213Sgibbs 269839213Sgibbs ccb = cdgetccb(periph, /* priority */ 1); 269939213Sgibbs 270039213Sgibbs csio = &ccb->csio; 270139213Sgibbs 270239213Sgibbs bzero(data, sizeof(*data)); 270339213Sgibbs cam_fill_csio(csio, 270439213Sgibbs /* retries */ 1, 270539213Sgibbs /* cbfcnp */ cddone, 270639213Sgibbs /* flags */ CAM_DIR_IN, 270739213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 270839213Sgibbs /* data_ptr */ (u_int8_t *)data, 270939213Sgibbs /* dxfer_len */ sizeof(*data), 271039213Sgibbs /* sense_len */ SSD_FULL_SIZE, 271139213Sgibbs sizeof(struct scsi_mode_sense_6), 271239213Sgibbs /* timeout */ 50000); 271339213Sgibbs 271439213Sgibbs scsi_cmd = (struct scsi_mode_sense_6 *)&csio->cdb_io.cdb_bytes; 271539213Sgibbs bzero (scsi_cmd, sizeof(*scsi_cmd)); 271639213Sgibbs 271739213Sgibbs scsi_cmd->page = page; 271839213Sgibbs scsi_cmd->length = sizeof(*data) & 0xff; 271939213Sgibbs scsi_cmd->opcode = MODE_SENSE; 272039213Sgibbs 272139213Sgibbs error = cdrunccb(ccb, cderror, /*cam_flags*/0, 272246747Sken /*sense_flags*/SF_RETRY_UA|SF_RETRY_SELTO); 272339213Sgibbs 272439213Sgibbs xpt_release_ccb(ccb); 272539213Sgibbs 272639213Sgibbs return(error); 272739213Sgibbs} 272839213Sgibbs 272939213Sgibbsstatic int 273039213Sgibbscdsetmode(struct cam_periph *periph, struct cd_mode_data *data) 273139213Sgibbs{ 273239213Sgibbs struct scsi_mode_select_6 *scsi_cmd; 273339213Sgibbs struct ccb_scsiio *csio; 273439213Sgibbs union ccb *ccb; 273539213Sgibbs int error; 273639213Sgibbs 273739213Sgibbs ccb = cdgetccb(periph, /* priority */ 1); 273839213Sgibbs 273939213Sgibbs csio = &ccb->csio; 274039213Sgibbs 274139213Sgibbs error = 0; 274239213Sgibbs 274339213Sgibbs cam_fill_csio(csio, 274439213Sgibbs /* retries */ 1, 274539213Sgibbs /* cbfcnp */ cddone, 274639531Sken /* flags */ CAM_DIR_OUT, 274739213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 274839213Sgibbs /* data_ptr */ (u_int8_t *)data, 274939213Sgibbs /* dxfer_len */ sizeof(*data), 275039213Sgibbs /* sense_len */ SSD_FULL_SIZE, 275139213Sgibbs sizeof(struct scsi_mode_select_6), 275239213Sgibbs /* timeout */ 50000); 275339213Sgibbs 275439213Sgibbs scsi_cmd = (struct scsi_mode_select_6 *)&csio->cdb_io.cdb_bytes; 275539213Sgibbs 275639213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 275739213Sgibbs scsi_cmd->opcode = MODE_SELECT; 275839213Sgibbs scsi_cmd->byte2 |= SMS_PF; 275939213Sgibbs scsi_cmd->length = sizeof(*data) & 0xff; 276039213Sgibbs data->header.data_length = 0; 276139213Sgibbs /* 276239213Sgibbs * SONY drives do not allow a mode select with a medium_type 276339213Sgibbs * value that has just been returned by a mode sense; use a 276439213Sgibbs * medium_type of 0 (Default) instead. 276539213Sgibbs */ 276639213Sgibbs data->header.medium_type = 0; 276739213Sgibbs 276839213Sgibbs error = cdrunccb(ccb, cderror, /*cam_flags*/0, 276946747Sken /*sense_flags*/SF_RETRY_UA | SF_RETRY_SELTO); 277039213Sgibbs 277139213Sgibbs xpt_release_ccb(ccb); 277239213Sgibbs 277339213Sgibbs return(error); 277439213Sgibbs} 277539213Sgibbs 277639213Sgibbs 277739213Sgibbsstatic int 277839213Sgibbscdplay(struct cam_periph *periph, u_int32_t blk, u_int32_t len) 277939213Sgibbs{ 278039531Sken struct ccb_scsiio *csio; 278139213Sgibbs union ccb *ccb; 278239213Sgibbs int error; 278339531Sken u_int8_t cdb_len; 278439213Sgibbs 278539213Sgibbs error = 0; 278639213Sgibbs ccb = cdgetccb(periph, /* priority */ 1); 278739213Sgibbs csio = &ccb->csio; 278839531Sken /* 278939531Sken * Use the smallest possible command to perform the operation. 279039531Sken */ 279139531Sken if ((len & 0xffff0000) == 0) { 279239531Sken /* 279339531Sken * We can fit in a 10 byte cdb. 279439531Sken */ 279539531Sken struct scsi_play_10 *scsi_cmd; 279639213Sgibbs 279739531Sken scsi_cmd = (struct scsi_play_10 *)&csio->cdb_io.cdb_bytes; 279839531Sken bzero (scsi_cmd, sizeof(*scsi_cmd)); 279939531Sken scsi_cmd->op_code = PLAY_10; 280039531Sken scsi_ulto4b(blk, (u_int8_t *)scsi_cmd->blk_addr); 280139531Sken scsi_ulto2b(len, (u_int8_t *)scsi_cmd->xfer_len); 280239531Sken cdb_len = sizeof(*scsi_cmd); 280339531Sken } else { 280439531Sken struct scsi_play_12 *scsi_cmd; 280539213Sgibbs 280639531Sken scsi_cmd = (struct scsi_play_12 *)&csio->cdb_io.cdb_bytes; 280739531Sken bzero (scsi_cmd, sizeof(*scsi_cmd)); 280839531Sken scsi_cmd->op_code = PLAY_12; 280939531Sken scsi_ulto4b(blk, (u_int8_t *)scsi_cmd->blk_addr); 281039531Sken scsi_ulto4b(len, (u_int8_t *)scsi_cmd->xfer_len); 281139531Sken cdb_len = sizeof(*scsi_cmd); 281239531Sken } 281339531Sken cam_fill_csio(csio, 281439531Sken /*retries*/2, 281539531Sken cddone, 281639531Sken /*flags*/CAM_DIR_NONE, 281739531Sken MSG_SIMPLE_Q_TAG, 281839531Sken /*dataptr*/NULL, 281939531Sken /*datalen*/0, 282039531Sken /*sense_len*/SSD_FULL_SIZE, 282139531Sken cdb_len, 282239531Sken /*timeout*/50 * 1000); 282339213Sgibbs 282439213Sgibbs error = cdrunccb(ccb, cderror, /*cam_flags*/0, 282546747Sken /*sense_flags*/SF_RETRY_UA | SF_RETRY_SELTO); 282639213Sgibbs 282739213Sgibbs xpt_release_ccb(ccb); 282839213Sgibbs 282939213Sgibbs return(error); 283039213Sgibbs} 283139213Sgibbs 283239213Sgibbsstatic int 283339213Sgibbscdplaymsf(struct cam_periph *periph, u_int32_t startm, u_int32_t starts, 283439213Sgibbs u_int32_t startf, u_int32_t endm, u_int32_t ends, u_int32_t endf) 283539213Sgibbs{ 283639213Sgibbs struct scsi_play_msf *scsi_cmd; 283739213Sgibbs struct ccb_scsiio *csio; 283839213Sgibbs union ccb *ccb; 283939213Sgibbs int error; 284039213Sgibbs 284139213Sgibbs error = 0; 284239213Sgibbs 284339213Sgibbs ccb = cdgetccb(periph, /* priority */ 1); 284439213Sgibbs 284539213Sgibbs csio = &ccb->csio; 284639213Sgibbs 284739213Sgibbs cam_fill_csio(csio, 284839213Sgibbs /* retries */ 1, 284939213Sgibbs /* cbfcnp */ cddone, 285039531Sken /* flags */ CAM_DIR_NONE, 285139213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 285239213Sgibbs /* data_ptr */ NULL, 285339213Sgibbs /* dxfer_len */ 0, 285439213Sgibbs /* sense_len */ SSD_FULL_SIZE, 285539213Sgibbs sizeof(struct scsi_play_msf), 285639213Sgibbs /* timeout */ 50000); 285739213Sgibbs 285839213Sgibbs scsi_cmd = (struct scsi_play_msf *)&csio->cdb_io.cdb_bytes; 285939213Sgibbs bzero (scsi_cmd, sizeof(*scsi_cmd)); 286039213Sgibbs 286139213Sgibbs scsi_cmd->op_code = PLAY_MSF; 286239213Sgibbs scsi_cmd->start_m = startm; 286339213Sgibbs scsi_cmd->start_s = starts; 286439213Sgibbs scsi_cmd->start_f = startf; 286539213Sgibbs scsi_cmd->end_m = endm; 286639213Sgibbs scsi_cmd->end_s = ends; 286739213Sgibbs scsi_cmd->end_f = endf; 286839213Sgibbs 286939213Sgibbs error = cdrunccb(ccb, cderror, /*cam_flags*/0, 287046747Sken /*sense_flags*/SF_RETRY_UA | SF_RETRY_SELTO); 287139213Sgibbs 287239213Sgibbs xpt_release_ccb(ccb); 287339213Sgibbs 287439213Sgibbs return(error); 287539213Sgibbs} 287639213Sgibbs 287739213Sgibbs 287839213Sgibbsstatic int 287939213Sgibbscdplaytracks(struct cam_periph *periph, u_int32_t strack, u_int32_t sindex, 288039213Sgibbs u_int32_t etrack, u_int32_t eindex) 288139213Sgibbs{ 288239213Sgibbs struct scsi_play_track *scsi_cmd; 288339213Sgibbs struct ccb_scsiio *csio; 288439213Sgibbs union ccb *ccb; 288539213Sgibbs int error; 288639213Sgibbs 288739213Sgibbs error = 0; 288839213Sgibbs 288939213Sgibbs ccb = cdgetccb(periph, /* priority */ 1); 289039213Sgibbs 289139213Sgibbs csio = &ccb->csio; 289239213Sgibbs 289339213Sgibbs cam_fill_csio(csio, 289439213Sgibbs /* retries */ 1, 289539213Sgibbs /* cbfcnp */ cddone, 289639531Sken /* flags */ CAM_DIR_NONE, 289739213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 289839213Sgibbs /* data_ptr */ NULL, 289939213Sgibbs /* dxfer_len */ 0, 290039213Sgibbs /* sense_len */ SSD_FULL_SIZE, 290139213Sgibbs sizeof(struct scsi_play_track), 290239213Sgibbs /* timeout */ 50000); 290339213Sgibbs 290439213Sgibbs scsi_cmd = (struct scsi_play_track *)&csio->cdb_io.cdb_bytes; 290539213Sgibbs bzero (scsi_cmd, sizeof(*scsi_cmd)); 290639213Sgibbs 290739213Sgibbs scsi_cmd->op_code = PLAY_TRACK; 290839213Sgibbs scsi_cmd->start_track = strack; 290939213Sgibbs scsi_cmd->start_index = sindex; 291039213Sgibbs scsi_cmd->end_track = etrack; 291139213Sgibbs scsi_cmd->end_index = eindex; 291239213Sgibbs 291339213Sgibbs error = cdrunccb(ccb, cderror, /*cam_flags*/0, 291446747Sken /*sense_flags*/SF_RETRY_UA | SF_RETRY_SELTO); 291539213Sgibbs 291639213Sgibbs xpt_release_ccb(ccb); 291739213Sgibbs 291839213Sgibbs return(error); 291939213Sgibbs} 292039213Sgibbs 292139213Sgibbsstatic int 292239213Sgibbscdpause(struct cam_periph *periph, u_int32_t go) 292339213Sgibbs{ 292439213Sgibbs struct scsi_pause *scsi_cmd; 292539213Sgibbs struct ccb_scsiio *csio; 292639213Sgibbs union ccb *ccb; 292739213Sgibbs int error; 292839213Sgibbs 292939213Sgibbs error = 0; 293039213Sgibbs 293139213Sgibbs ccb = cdgetccb(periph, /* priority */ 1); 293239213Sgibbs 293339213Sgibbs csio = &ccb->csio; 293439213Sgibbs 293539213Sgibbs cam_fill_csio(csio, 293639213Sgibbs /* retries */ 1, 293739213Sgibbs /* cbfcnp */ cddone, 293839531Sken /* flags */ CAM_DIR_NONE, 293939213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 294039213Sgibbs /* data_ptr */ NULL, 294139213Sgibbs /* dxfer_len */ 0, 294239213Sgibbs /* sense_len */ SSD_FULL_SIZE, 294339213Sgibbs sizeof(struct scsi_pause), 294439213Sgibbs /* timeout */ 50000); 294539213Sgibbs 294639213Sgibbs scsi_cmd = (struct scsi_pause *)&csio->cdb_io.cdb_bytes; 294739213Sgibbs bzero (scsi_cmd, sizeof(*scsi_cmd)); 294839213Sgibbs 294939213Sgibbs scsi_cmd->op_code = PAUSE; 295039213Sgibbs scsi_cmd->resume = go; 295139213Sgibbs 295239213Sgibbs error = cdrunccb(ccb, cderror, /*cam_flags*/0, 295346747Sken /*sense_flags*/SF_RETRY_UA |SF_RETRY_SELTO); 295439213Sgibbs 295539213Sgibbs xpt_release_ccb(ccb); 295639213Sgibbs 295739213Sgibbs return(error); 295839213Sgibbs} 295939213Sgibbs 296039213Sgibbsstatic int 296139213Sgibbscdstartunit(struct cam_periph *periph) 296239213Sgibbs{ 296339213Sgibbs union ccb *ccb; 296439213Sgibbs int error; 296539213Sgibbs 296639213Sgibbs error = 0; 296739213Sgibbs 296839213Sgibbs ccb = cdgetccb(periph, /* priority */ 1); 296939213Sgibbs 297039213Sgibbs scsi_start_stop(&ccb->csio, 297139213Sgibbs /* retries */ 1, 297239213Sgibbs /* cbfcnp */ cddone, 297339213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 297439213Sgibbs /* start */ TRUE, 297539213Sgibbs /* load_eject */ TRUE, 297639213Sgibbs /* immediate */ FALSE, 297739213Sgibbs /* sense_len */ SSD_FULL_SIZE, 297839213Sgibbs /* timeout */ 50000); 297939213Sgibbs 298039213Sgibbs error = cdrunccb(ccb, cderror, /*cam_flags*/0, 298146747Sken /*sense_flags*/SF_RETRY_UA | SF_RETRY_SELTO); 298239213Sgibbs 298339213Sgibbs xpt_release_ccb(ccb); 298439213Sgibbs 298539213Sgibbs return(error); 298639213Sgibbs} 298739213Sgibbs 298839213Sgibbsstatic int 298939213Sgibbscdstopunit(struct cam_periph *periph, u_int32_t eject) 299039213Sgibbs{ 299139213Sgibbs union ccb *ccb; 299239213Sgibbs int error; 299339213Sgibbs 299439213Sgibbs error = 0; 299539213Sgibbs 299639213Sgibbs ccb = cdgetccb(periph, /* priority */ 1); 299739213Sgibbs 299839213Sgibbs scsi_start_stop(&ccb->csio, 299939213Sgibbs /* retries */ 1, 300039213Sgibbs /* cbfcnp */ cddone, 300139213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 300239213Sgibbs /* start */ FALSE, 300339213Sgibbs /* load_eject */ eject, 300439213Sgibbs /* immediate */ FALSE, 300539213Sgibbs /* sense_len */ SSD_FULL_SIZE, 300639213Sgibbs /* timeout */ 50000); 300739213Sgibbs 300839213Sgibbs error = cdrunccb(ccb, cderror, /*cam_flags*/0, 300946747Sken /*sense_flags*/SF_RETRY_UA | SF_RETRY_SELTO); 301039213Sgibbs 301139213Sgibbs xpt_release_ccb(ccb); 301239213Sgibbs 301339213Sgibbs return(error); 301439213Sgibbs} 3015