scsi_cd.c revision 46747
11539Srgrimes/* 21539Srgrimes * Copyright (c) 1997 Justin T. Gibbs. 31539Srgrimes * Copyright (c) 1997, 1998, 1999 Kenneth D. Merry. 41539Srgrimes * All rights reserved. 51539Srgrimes * 61539Srgrimes * Redistribution and use in source and binary forms, with or without 71539Srgrimes * modification, are permitted provided that the following conditions 81539Srgrimes * are met: 91539Srgrimes * 1. Redistributions of source code must retain the above copyright 101539Srgrimes * notice, this list of conditions, and the following disclaimer, 111539Srgrimes * without modification, immediately at the beginning of the file. 121539Srgrimes * 2. The name of the author may not be used to endorse or promote products 131539Srgrimes * derived from this software without specific prior written permission. 141539Srgrimes * 151539Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 161539Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 171539Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 181539Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 191539Srgrimes * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 201539Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 211539Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 221539Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 231539Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 241539Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 251539Srgrimes * SUCH DAMAGE. 261539Srgrimes * 271539Srgrimes * $Id: scsi_cd.c,v 1.19 1999/05/07 07:02:57 phk Exp $ 281539Srgrimes */ 291539Srgrimes/* 301539Srgrimes * Portions of this driver taken from the original FreeBSD cd driver. 311539Srgrimes * Written by Julian Elischer (julian@tfs.com) 321539Srgrimes * for TRW Financial Systems for use under the MACH(2.5) operating system. 3323657Speter * 3455031Sbde * TRW Financial Systems, in accordance with their agreement with Carnegie 351539Srgrimes * Mellon University, makes this software available to CMU to distribute 361539Srgrimes * or use in any manner that they see fit as long as this message is kept with 371539Srgrimes * the software. For this reason TFS also grants any other persons or 387865Sbde * organisations permission to use or modify this software. 391539Srgrimes * 4033861Sbde * TFS supplies this software to be publicly redistributed 41123257Smarcel * on the understanding that TFS is not responsible for the correct 42102227Smike * functioning of this software in any circumstances. 4333861Sbde * 44103728Swollman * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 45102227Smike * 46102227Smike * from: cd.c,v 1.83 1997/05/04 15:24:22 joerg Exp $ 47102227Smike */ 4815483Sbde 4915483Sbde#include "opt_cd.h" 5015483Sbde 51102227Smike#include <sys/param.h> 52102227Smike#include <sys/systm.h> 53102227Smike#include <sys/kernel.h> 541539Srgrimes#include <sys/buf.h> 551539Srgrimes#include <sys/dkbad.h> 5699640Sobrien#include <sys/disklabel.h> 57102227Smike#include <sys/diskslice.h> 58102227Smike#include <sys/malloc.h> 59102227Smike#include <sys/conf.h> 601539Srgrimes#include <sys/cdio.h> 6199640Sobrien#include <sys/devicestat.h> 621539Srgrimes#include <sys/sysctl.h> 631539Srgrimes 64103766Sbde#include <cam/cam.h> 65103766Sbde#include <cam/cam_ccb.h> 661539Srgrimes#include <cam/cam_extend.h> 671539Srgrimes#include <cam/cam_periph.h> 681539Srgrimes#include <cam/cam_xpt_periph.h> 69103766Sbde#include <cam/cam_queue.h> 70103766Sbde 711539Srgrimes#include <cam/scsi/scsi_message.h> 721539Srgrimes#include <cam/scsi/scsi_da.h> 731539Srgrimes#include <cam/scsi/scsi_cd.h> 741539Srgrimes 751539Srgrimes#define LEADOUT 0xaa /* leadout toc entry */ 761539Srgrimes 771539Srgrimesstruct cd_params { 781539Srgrimes u_int32_t blksize; 791539Srgrimes u_long disksize; 801539Srgrimes}; 811539Srgrimes 8293032Simptypedef enum { 83153684Sphk CD_Q_NONE = 0x00, 8493032Simp CD_Q_NO_TOUCH = 0x01, 8593032Simp CD_Q_BCD_TRACKS = 0x02, 8693032Simp CD_Q_NO_CHANGER = 0x04, 8793032Simp CD_Q_CHANGER = 0x08 8893032Simp} cd_quirks; 8993032Simp 9093032Simptypedef enum { 9193032Simp CD_FLAG_INVALID = 0x001, 9293032Simp CD_FLAG_NEW_DISC = 0x002, 9393032Simp CD_FLAG_DISC_LOCKED = 0x004, 9493032Simp CD_FLAG_DISC_REMOVABLE = 0x008, 9593032Simp CD_FLAG_TAGGED_QUEUING = 0x010, 9693032Simp CD_FLAG_OPEN = 0x020, 9793032Simp CD_FLAG_CHANGER = 0x040, 9893032Simp CD_FLAG_ACTIVE = 0x080, 99103728Swollman CD_FLAG_SCHED_ON_COMP = 0x100, 100103766Sbde CD_FLAG_RETRY_UA = 0x200 101103728Swollman} cd_flags; 10293032Simp 10393032Simptypedef enum { 10493032Simp CD_CCB_PROBE = 0x01, 10593032Simp CD_CCB_BUFFER_IO = 0x02, 10693032Simp CD_CCB_WAITING = 0x03, 107103766Sbde CD_CCB_TYPE_MASK = 0x0F, 108112163Sdas CD_CCB_RETRY_UA = 0x10 109103766Sbde} cd_ccb_state; 110112163Sdas 111112163Sdastypedef enum { 1121539Srgrimes CHANGER_TIMEOUT_SCHED = 0x01, 113103012Stjr CHANGER_SHORT_TMOUT_SCHED = 0x02, 11493032Simp CHANGER_MANUAL_CALL = 0x04, 11593032Simp CHANGER_NEED_TIMEOUT = 0x08 116103012Stjr} cd_changer_flags; 1171539Srgrimes 118103728Swollman#define ccb_state ppriv_field0 119103728Swollman#define ccb_bp ppriv_ptr1 120103728Swollman 121103728Swollmantypedef enum { 122103728Swollman CD_STATE_PROBE, 123103728Swollman CD_STATE_NORMAL 124103728Swollman} cd_state; 125103728Swollman 126103728Swollmanstruct cd_softc { 127103728Swollman cam_pinfo pinfo; 128103728Swollman cd_state state; 129103728Swollman volatile cd_flags flags; 130103728Swollman struct buf_queue_head buf_queue; 131103728Swollman LIST_HEAD(, ccb_hdr) pending_ccbs; 132103728Swollman struct cd_params params; 133103728Swollman struct diskslices *cd_slices; 134103728Swollman union ccb saved_ccb; 13569201Sphk cd_quirks quirks; 136103728Swollman struct devstat device_stats; 137103728Swollman STAILQ_ENTRY(cd_softc) changer_links; 138103728Swollman struct cdchanger *changer; 139103728Swollman int bufs_left; 140103728Swollman struct cam_periph *periph; 141103728Swollman}; 142103728Swollman 143103728Swollmanstruct cd_quirk_entry { 144103728Swollman struct scsi_inquiry_pattern inq_pat; 145103766Sbde cd_quirks quirks; 146103766Sbde}; 147103728Swollman 148103728Swollman/* 149103766Sbde * These quirk entries aren't strictly necessary. Basically, what they do 150103728Swollman * is tell cdregister() up front that a device is a changer. Otherwise, it 151103728Swollman * will figure that fact out once it sees a LUN on the device that is 152103766Sbde * greater than 0. If it is known up front that a device is a changer, all 153103728Swollman * I/O to the device will go through the changer scheduling routines, as 154103728Swollman * opposed to the "normal" CD code. 155103728Swollman */ 156103728Swollmanstatic struct cd_quirk_entry cd_quirk_table[] = 157103728Swollman{ 158103728Swollman { 159103728Swollman { T_CDROM, SIP_MEDIA_REMOVABLE, "NRC", "MBR-7", "*"}, 160103728Swollman /*quirks*/ CD_Q_CHANGER 161154250Sjasone }, 162103728Swollman { 16393032Simp { T_CDROM, SIP_MEDIA_REMOVABLE, "PIONEER", "CD-ROM DRM-604X", 164171195Sscf "*"}, /* quirks */ CD_Q_CHANGER 165103728Swollman }, 1661539Srgrimes { 167103728Swollman { T_CDROM, SIP_MEDIA_REMOVABLE, "CHINON", "CD-ROM CDS-535","*"}, 168103728Swollman /* quirks */ CD_Q_BCD_TRACKS 169103728Swollman } 170103728Swollman}; 171103728Swollman 172103728Swollman#ifndef MIN 173103728Swollman#define MIN(x,y) ((x<y) ? x : y) 174103728Swollman#endif 175153707Strhodes 17693032Simp#define CD_CDEV_MAJOR 15 177103766Sbde#define CD_BDEV_MAJOR 6 17893032Simp 179103766Sbdestatic d_open_t cdopen; 180103766Sbdestatic d_close_t cdclose; 181103728Swollmanstatic d_ioctl_t cdioctl; 182108574Sjmallettstatic d_strategy_t cdstrategy; 183103728Swollmanstatic d_strategy_t cdstrategy1; 18493032Simp 185153707Strhodesstatic periph_init_t cdinit; 18693032Simpstatic periph_ctor_t cdregister; 18793032Simpstatic periph_dtor_t cdcleanup; 188103728Swollmanstatic periph_start_t cdstart; 189103728Swollmanstatic periph_oninv_t cdoninvalidate; 190103728Swollmanstatic void cdasync(void *callback_arg, u_int32_t code, 191103728Swollman struct cam_path *path, void *arg); 192103728Swollmanstatic void cdshorttimeout(void *arg); 193103728Swollmanstatic void cdschedule(struct cam_periph *periph, int priority); 194103766Sbdestatic void cdrunchangerqueue(void *arg); 195103728Swollmanstatic void cdchangerschedule(struct cd_softc *softc); 19693032Simpstatic int cdrunccb(union ccb *ccb, 19793032Simp int (*error_routine)(union ccb *ccb, 198108574Sjmallett u_int32_t cam_flags, 199108574Sjmallett u_int32_t sense_flags), 200171195Sscf u_int32_t cam_flags, u_int32_t sense_flags); 201103728Swollmanstatic union ccb *cdgetccb(struct cam_periph *periph, 202103728Swollman u_int32_t priority); 2037865Sbdestatic void cddone(struct cam_periph *periph, 20493032Simp union ccb *start_ccb); 205103728Swollmanstatic int cderror(union ccb *ccb, u_int32_t cam_flags, 206103728Swollman u_int32_t sense_flags); 207103728Swollmanstatic void cdprevent(struct cam_periph *periph, int action); 208103728Swollmanstatic int cdsize(dev_t dev, u_int32_t *size); 209103728Swollmanstatic int cdreadtoc(struct cam_periph *periph, u_int32_t mode, 21093032Simp u_int32_t start, struct cd_toc_entry *data, 211103728Swollman u_int32_t len); 212108574Sjmallettstatic int cdgetmode(struct cam_periph *periph, 213103728Swollman struct cd_mode_data *data, u_int32_t page); 2144749Satsstatic int cdsetmode(struct cam_periph *periph, 215103728Swollman struct cd_mode_data *data); 216103728Swollmanstatic int cdplay(struct cam_periph *periph, u_int32_t blk, 217103766Sbde u_int32_t len); 218103766Sbdestatic int cdreadsubchannel(struct cam_periph *periph, 219103728Swollman u_int32_t mode, u_int32_t format, 220116397Sdes int track, 221116397Sdes struct cd_sub_channel_info *data, 222116397Sdes u_int32_t len); 223116397Sdesstatic int cdplaymsf(struct cam_periph *periph, u_int32_t startm, 224116397Sdes u_int32_t starts, u_int32_t startf, 225116397Sdes u_int32_t endm, u_int32_t ends, 226116397Sdes u_int32_t endf); 227116397Sdesstatic int cdplaytracks(struct cam_periph *periph, 228116397Sdes u_int32_t strack, u_int32_t sindex, 229116831Sobrien u_int32_t etrack, u_int32_t eindex); 230116831Sobrienstatic int cdpause(struct cam_periph *periph, u_int32_t go); 231116397Sdesstatic int cdstopunit(struct cam_periph *periph, u_int32_t eject); 232116831Sobrienstatic int cdstartunit(struct cam_periph *periph); 233116831Sobrien 234116397Sdesstatic struct periph_driver cddriver = 235116397Sdes{ 23641927Sdt cdinit, "cd", 23793032Simp TAILQ_HEAD_INITIALIZER(cddriver.units), /* generation */ 0 238180658Sache}; 239180658Sache 24093032SimpDATA_SET(periphdriver_set, cddriver); 241180689Sache 242180689Sache/* For 2.2-stable support */ 243108445Sobrien#ifndef D_DISK 244103728Swollman#define D_DISK 0 24593032Simp#endif 24693032Simpstatic struct cdevsw cd_cdevsw = 24793032Simp{ 24893032Simp /*d_open*/ cdopen, 24993032Simp /*d_close*/ cdclose, 25093032Simp /*d_read*/ physread, 25193032Simp /*d_write*/ nowrite, 25293032Simp /*d_ioctl*/ cdioctl, 25393032Simp /*d_stop*/ nostop, 25493032Simp /*d_reset*/ noreset, 2551539Srgrimes /*d_devtotty*/ nodevtotty, 25693032Simp /*d_poll*/ seltrue, 257150052Sstefanf /*d_mmap*/ nommap, 258150052Sstefanf /*d_strategy*/ cdstrategy, 25993032Simp /*d_name*/ "cd", 26088399Smike /*d_spare*/ NULL, 26193032Simp /*d_maj*/ -1, 2621539Srgrimes /*d_dump*/ nodump, 26393032Simp /*d_psize*/ nopsize, 264153707Strhodes /*d_flags*/ D_DISK, 26593032Simp /*d_maxio*/ 0, 266103164Swollman /*b_maj*/ -1 267103164Swollman}; 26893032Simp 26993032Simpstatic struct extend_array *cdperiphs; 27093032Simpstatic int num_changers; 271139922Stjr 27293032Simp#ifndef CHANGER_MIN_BUSY_SECONDS 273103164Swollman#define CHANGER_MIN_BUSY_SECONDS 5 274103164Swollman#endif 27593032Simp#ifndef CHANGER_MAX_BUSY_SECONDS 27693032Simp#define CHANGER_MAX_BUSY_SECONDS 15 277156707Sandre#endif 278156707Sandre 279103728Swollmanstatic int changer_min_busy_seconds = CHANGER_MIN_BUSY_SECONDS; 280103728Swollmanstatic int changer_max_busy_seconds = CHANGER_MAX_BUSY_SECONDS; 281103766Sbde 282103766Sbde/* 28341927Sdt * XXX KDM this CAM node should be moved if we ever get more CAM sysctl 28493032Simp * variables. 285126136Sache */ 286126136SacheSYSCTL_NODE(_kern, OID_AUTO, cam, CTLFLAG_RD, 0, "CAM Subsystem"); 287103728SwollmanSYSCTL_NODE(_kern_cam, OID_AUTO, cd, CTLFLAG_RD, 0, "CAM CDROM driver"); 2881539SrgrimesSYSCTL_NODE(_kern_cam_cd, OID_AUTO, changer, CTLFLAG_RD, 0, "CD Changer"); 2891539SrgrimesSYSCTL_INT(_kern_cam_cd_changer, OID_AUTO, min_busy_seconds, CTLFLAG_RW, 2907865Sbde &changer_min_busy_seconds, 0, "Minimum changer scheduling quantum"); 291SYSCTL_INT(_kern_cam_cd_changer, OID_AUTO, max_busy_seconds, CTLFLAG_RW, 292 &changer_max_busy_seconds, 0, "Maximum changer scheduling quantum"); 293 294struct cdchanger { 295 path_id_t path_id; 296 target_id_t target_id; 297 int num_devices; 298 struct camq devq; 299 struct timeval start_time; 300 struct cd_softc *cur_device; 301 struct callout_handle short_handle; 302 struct callout_handle long_handle; 303 volatile cd_changer_flags flags; 304 STAILQ_ENTRY(cdchanger) changer_links; 305 STAILQ_HEAD(chdevlist, cd_softc) chluns; 306}; 307 308static STAILQ_HEAD(changerlist, cdchanger) changerq; 309 310void 311cdinit(void) 312{ 313 cam_status status; 314 struct cam_path *path; 315 316 /* 317 * Create our extend array for storing the devices we attach to. 318 */ 319 cdperiphs = cam_extend_new(); 320 if (cdperiphs == NULL) { 321 printf("cd: Failed to alloc extend array!\n"); 322 return; 323 } 324 325 /* 326 * Install a global async callback. This callback will 327 * receive async callbacks like "new device found". 328 */ 329 status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID, 330 CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 331 332 if (status == CAM_REQ_CMP) { 333 struct ccb_setasync csa; 334 335 xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5); 336 csa.ccb_h.func_code = XPT_SASYNC_CB; 337 csa.event_enable = AC_FOUND_DEVICE; 338 csa.callback = cdasync; 339 csa.callback_arg = NULL; 340 xpt_action((union ccb *)&csa); 341 status = csa.ccb_h.status; 342 xpt_free_path(path); 343 } 344 345 if (status != CAM_REQ_CMP) { 346 printf("cd: Failed to attach master async callback " 347 "due to status 0x%x!\n", status); 348 } else { 349 /* If we were successfull, register our devsw */ 350 cdevsw_add_generic(CD_BDEV_MAJOR, CD_CDEV_MAJOR, &cd_cdevsw); 351 } 352} 353 354static void 355cdoninvalidate(struct cam_periph *periph) 356{ 357 int s; 358 struct cd_softc *softc; 359 struct buf *q_bp; 360 struct ccb_setasync csa; 361 362 softc = (struct cd_softc *)periph->softc; 363 364 /* 365 * De-register any async callbacks. 366 */ 367 xpt_setup_ccb(&csa.ccb_h, periph->path, 368 /* priority */ 5); 369 csa.ccb_h.func_code = XPT_SASYNC_CB; 370 csa.event_enable = 0; 371 csa.callback = cdasync; 372 csa.callback_arg = periph; 373 xpt_action((union ccb *)&csa); 374 375 softc->flags |= CD_FLAG_INVALID; 376 377 /* 378 * Although the oninvalidate() routines are always called at 379 * splsoftcam, we need to be at splbio() here to keep the buffer 380 * queue from being modified while we traverse it. 381 */ 382 s = splbio(); 383 384 /* 385 * Return all queued I/O with ENXIO. 386 * XXX Handle any transactions queued to the card 387 * with XPT_ABORT_CCB. 388 */ 389 while ((q_bp = bufq_first(&softc->buf_queue)) != NULL){ 390 bufq_remove(&softc->buf_queue, q_bp); 391 q_bp->b_resid = q_bp->b_bcount; 392 q_bp->b_error = ENXIO; 393 q_bp->b_flags |= B_ERROR; 394 biodone(q_bp); 395 } 396 splx(s); 397 398 /* 399 * If this device is part of a changer, and it was scheduled 400 * to run, remove it from the run queue since we just nuked 401 * all of its scheduled I/O. 402 */ 403 if ((softc->flags & CD_FLAG_CHANGER) 404 && (softc->pinfo.index != CAM_UNQUEUED_INDEX)) 405 camq_remove(&softc->changer->devq, softc->pinfo.index); 406 407 xpt_print_path(periph->path); 408 printf("lost device\n"); 409} 410 411static void 412cdcleanup(struct cam_periph *periph) 413{ 414 struct cd_softc *softc; 415 int s; 416 417 softc = (struct cd_softc *)periph->softc; 418 419 xpt_print_path(periph->path); 420 printf("removing device entry\n"); 421 422 s = splsoftcam(); 423 /* 424 * In the queued, non-active case, the device in question 425 * has already been removed from the changer run queue. Since this 426 * device is active, we need to de-activate it, and schedule 427 * another device to run. (if there is another one to run) 428 */ 429 if ((softc->flags & CD_FLAG_CHANGER) 430 && (softc->flags & CD_FLAG_ACTIVE)) { 431 432 /* 433 * The purpose of the short timeout is soley to determine 434 * whether the current device has finished or not. Well, 435 * since we're removing the active device, we know that it 436 * is finished. So, get rid of the short timeout. 437 * Otherwise, if we're in the time period before the short 438 * timeout fires, and there are no other devices in the 439 * queue to run, there won't be any other device put in the 440 * active slot. i.e., when we call cdrunchangerqueue() 441 * below, it won't do anything. Then, when the short 442 * timeout fires, it'll look at the "current device", which 443 * we are free below, and possibly panic the kernel on a 444 * bogus pointer reference. 445 * 446 * The long timeout doesn't really matter, since we 447 * decrement the qfrozen_cnt to indicate that there is 448 * nothing in the active slot now. Therefore, there won't 449 * be any bogus pointer references there. 450 */ 451 if (softc->changer->flags & CHANGER_SHORT_TMOUT_SCHED) { 452 untimeout(cdshorttimeout, softc->changer, 453 softc->changer->short_handle); 454 softc->changer->flags &= ~CHANGER_SHORT_TMOUT_SCHED; 455 } 456 softc->changer->devq.qfrozen_cnt--; 457 softc->changer->flags |= CHANGER_MANUAL_CALL; 458 cdrunchangerqueue(softc->changer); 459 } 460 461 /* 462 * If we're removing the last device on the changer, go ahead and 463 * remove the changer device structure. 464 */ 465 if ((softc->flags & CD_FLAG_CHANGER) 466 && (--softc->changer->num_devices == 0)) { 467 468 /* 469 * Theoretically, there shouldn't be any timeouts left, but 470 * I'm not completely sure that that will be the case. So, 471 * it won't hurt to check and see if there are any left. 472 */ 473 if (softc->changer->flags & CHANGER_TIMEOUT_SCHED) { 474 untimeout(cdrunchangerqueue, softc->changer, 475 softc->changer->long_handle); 476 softc->changer->flags &= ~CHANGER_TIMEOUT_SCHED; 477 } 478 479 if (softc->changer->flags & CHANGER_SHORT_TMOUT_SCHED) { 480 untimeout(cdshorttimeout, softc->changer, 481 softc->changer->short_handle); 482 softc->changer->flags &= ~CHANGER_SHORT_TMOUT_SCHED; 483 } 484 485 STAILQ_REMOVE(&changerq, softc->changer, cdchanger, 486 changer_links); 487 xpt_print_path(periph->path); 488 printf("removing changer entry\n"); 489 free(softc->changer, M_DEVBUF); 490 num_changers--; 491 } 492 devstat_remove_entry(&softc->device_stats); 493 cam_extend_release(cdperiphs, periph->unit_number); 494 free(softc, M_DEVBUF); 495 splx(s); 496} 497 498static void 499cdasync(void *callback_arg, u_int32_t code, 500 struct cam_path *path, void *arg) 501{ 502 struct cam_periph *periph; 503 504 periph = (struct cam_periph *)callback_arg; 505 switch (code) { 506 case AC_FOUND_DEVICE: 507 { 508 struct ccb_getdev *cgd; 509 cam_status status; 510 511 cgd = (struct ccb_getdev *)arg; 512 513 if ((cgd->pd_type != T_CDROM) && (cgd->pd_type != T_WORM)) 514 break; 515 516 /* 517 * Allocate a peripheral instance for 518 * this device and start the probe 519 * process. 520 */ 521 status = cam_periph_alloc(cdregister, cdoninvalidate, 522 cdcleanup, cdstart, 523 "cd", CAM_PERIPH_BIO, 524 cgd->ccb_h.path, cdasync, 525 AC_FOUND_DEVICE, cgd); 526 527 if (status != CAM_REQ_CMP 528 && status != CAM_REQ_INPROG) 529 printf("cdasync: Unable to attach new device " 530 "due to status 0x%x\n", status); 531 532 break; 533 } 534 case AC_LOST_DEVICE: 535 cam_periph_invalidate(periph); 536 break; 537 case AC_SENT_BDR: 538 case AC_BUS_RESET: 539 { 540 struct cd_softc *softc; 541 struct ccb_hdr *ccbh; 542 int s; 543 544 softc = (struct cd_softc *)periph->softc; 545 s = splsoftcam(); 546 /* 547 * Don't fail on the expected unit attention 548 * that will occur. 549 */ 550 softc->flags |= CD_FLAG_RETRY_UA; 551 for (ccbh = LIST_FIRST(&softc->pending_ccbs); 552 ccbh != NULL; ccbh = LIST_NEXT(ccbh, periph_links.le)) 553 ccbh->ccb_state |= CD_CCB_RETRY_UA; 554 splx(s); 555 break; 556 } 557 case AC_TRANSFER_NEG: 558 case AC_SCSI_AEN: 559 case AC_UNSOL_RESEL: 560 default: 561 break; 562 } 563} 564 565static cam_status 566cdregister(struct cam_periph *periph, void *arg) 567{ 568 struct cd_softc *softc; 569 struct ccb_setasync csa; 570 struct ccb_getdev *cgd; 571 caddr_t match; 572 573 cgd = (struct ccb_getdev *)arg; 574 if (periph == NULL) { 575 printf("cdregister: periph was NULL!!\n"); 576 return(CAM_REQ_CMP_ERR); 577 } 578 if (cgd == NULL) { 579 printf("cdregister: no getdev CCB, can't register device\n"); 580 return(CAM_REQ_CMP_ERR); 581 } 582 583 softc = (struct cd_softc *)malloc(sizeof(*softc),M_DEVBUF,M_NOWAIT); 584 585 if (softc == NULL) { 586 printf("cdregister: Unable to probe new device. " 587 "Unable to allocate softc\n"); 588 return(CAM_REQ_CMP_ERR); 589 } 590 591 bzero(softc, sizeof(*softc)); 592 LIST_INIT(&softc->pending_ccbs); 593 softc->state = CD_STATE_PROBE; 594 bufq_init(&softc->buf_queue); 595 if (SID_IS_REMOVABLE(&cgd->inq_data)) 596 softc->flags |= CD_FLAG_DISC_REMOVABLE; 597 if ((cgd->inq_data.flags & SID_CmdQue) != 0) 598 softc->flags |= CD_FLAG_TAGGED_QUEUING; 599 600 periph->softc = softc; 601 softc->periph = periph; 602 603 cam_extend_set(cdperiphs, periph->unit_number, periph); 604 605 /* 606 * See if this device has any quirks. 607 */ 608 match = cam_quirkmatch((caddr_t)&cgd->inq_data, 609 (caddr_t)cd_quirk_table, 610 sizeof(cd_quirk_table)/sizeof(*cd_quirk_table), 611 sizeof(*cd_quirk_table), scsi_inquiry_match); 612 613 if (match != NULL) 614 softc->quirks = ((struct cd_quirk_entry *)match)->quirks; 615 else 616 softc->quirks = CD_Q_NONE; 617 618 /* 619 * We need to register the statistics structure for this device, 620 * but we don't have the blocksize yet for it. So, we register 621 * the structure and indicate that we don't have the blocksize 622 * yet. Unlike other SCSI peripheral drivers, we explicitly set 623 * the device type here to be CDROM, rather than just ORing in 624 * cgd->pd_type. This is because this driver can attach to either 625 * CDROM or WORM devices, and we want this peripheral driver to 626 * show up in the devstat list as a CD peripheral driver, not a 627 * WORM peripheral driver. WORM drives will also have the WORM 628 * driver attached to them. 629 */ 630 devstat_add_entry(&softc->device_stats, "cd", 631 periph->unit_number, 0, 632 DEVSTAT_BS_UNAVAILABLE, 633 DEVSTAT_TYPE_CDROM | DEVSTAT_TYPE_IF_SCSI, 634 DEVSTAT_PRIORITY_CD); 635 636 /* 637 * Add an async callback so that we get 638 * notified if this device goes away. 639 */ 640 xpt_setup_ccb(&csa.ccb_h, periph->path, 641 /* priority */ 5); 642 csa.ccb_h.func_code = XPT_SASYNC_CB; 643 csa.event_enable = AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE; 644 csa.callback = cdasync; 645 csa.callback_arg = periph; 646 xpt_action((union ccb *)&csa); 647 648 /* 649 * If the target lun is greater than 0, we most likely have a CD 650 * changer device. Check the quirk entries as well, though, just 651 * in case someone has a CD tower with one lun per drive or 652 * something like that. Also, if we know up front that a 653 * particular device is a changer, we can mark it as such starting 654 * with lun 0, instead of lun 1. It shouldn't be necessary to have 655 * a quirk entry to define something as a changer, however. 656 */ 657 if (((cgd->ccb_h.target_lun > 0) 658 && ((softc->quirks & CD_Q_NO_CHANGER) == 0)) 659 || ((softc->quirks & CD_Q_CHANGER) != 0)) { 660 struct cdchanger *nchanger; 661 struct cam_periph *nperiph; 662 struct cam_path *path; 663 cam_status status; 664 int found; 665 666 /* Set the changer flag in the current device's softc */ 667 softc->flags |= CD_FLAG_CHANGER; 668 669 if (num_changers == 0) 670 STAILQ_INIT(&changerq); 671 672 /* 673 * Now, look around for an existing changer device with the 674 * same path and target ID as the current device. 675 */ 676 for (found = 0, 677 nchanger = (struct cdchanger *)STAILQ_FIRST(&changerq); 678 nchanger != NULL; 679 nchanger = STAILQ_NEXT(nchanger, changer_links)){ 680 if ((nchanger->path_id == cgd->ccb_h.path_id) 681 && (nchanger->target_id == cgd->ccb_h.target_id)) { 682 found = 1; 683 break; 684 } 685 } 686 687 /* 688 * If we found a matching entry, just add this device to 689 * the list of devices on this changer. 690 */ 691 if (found == 1) { 692 struct chdevlist *chlunhead; 693 694 chlunhead = &nchanger->chluns; 695 696 /* 697 * XXX KDM look at consolidating this code with the 698 * code below in a separate function. 699 */ 700 701 /* 702 * Create a path with lun id 0, and see if we can 703 * find a matching device 704 */ 705 status = xpt_create_path(&path, /*periph*/ periph, 706 cgd->ccb_h.path_id, 707 cgd->ccb_h.target_id, 0); 708 709 if ((status == CAM_REQ_CMP) 710 && ((nperiph = cam_periph_find(path, "cd")) != NULL)){ 711 struct cd_softc *nsoftc; 712 713 nsoftc = (struct cd_softc *)nperiph->softc; 714 715 if ((nsoftc->flags & CD_FLAG_CHANGER) == 0){ 716 nsoftc->flags |= CD_FLAG_CHANGER; 717 nchanger->num_devices++; 718 if (camq_resize(&nchanger->devq, 719 nchanger->num_devices)!=CAM_REQ_CMP){ 720 printf("cdregister: " 721 "camq_resize " 722 "failed, changer " 723 "support may " 724 "be messed up\n"); 725 } 726 nsoftc->changer = nchanger; 727 nsoftc->pinfo.index =CAM_UNQUEUED_INDEX; 728 729 STAILQ_INSERT_TAIL(&nchanger->chluns, 730 nsoftc,changer_links); 731 } 732 } else if (status == CAM_REQ_CMP) 733 xpt_free_path(path); 734 else { 735 printf("cdregister: unable to allocate path\n" 736 "cdregister: changer support may be " 737 "broken\n"); 738 } 739 740 nchanger->num_devices++; 741 742 softc->changer = nchanger; 743 softc->pinfo.index = CAM_UNQUEUED_INDEX; 744 745 if (camq_resize(&nchanger->devq, 746 nchanger->num_devices) != CAM_REQ_CMP) { 747 printf("cdregister: camq_resize " 748 "failed, changer support may " 749 "be messed up\n"); 750 } 751 752 STAILQ_INSERT_TAIL(chlunhead, softc, changer_links); 753 } 754 /* 755 * In this case, we don't already have an entry for this 756 * particular changer, so we need to create one, add it to 757 * the queue, and queue this device on the list for this 758 * changer. Before we queue this device, however, we need 759 * to search for lun id 0 on this target, and add it to the 760 * queue first, if it exists. (and if it hasn't already 761 * been marked as part of the changer.) 762 */ 763 else { 764 nchanger = malloc(sizeof(struct cdchanger), 765 M_DEVBUF, M_NOWAIT); 766 767 if (nchanger == NULL) { 768 softc->flags &= ~CD_FLAG_CHANGER; 769 printf("cdregister: unable to malloc " 770 "changer structure\ncdregister: " 771 "changer support disabled\n"); 772 773 /* 774 * Yes, gotos can be gross but in this case 775 * I think it's justified.. 776 */ 777 goto cdregisterexit; 778 } 779 780 /* zero the structure */ 781 bzero(nchanger, sizeof(struct cdchanger)); 782 783 if (camq_init(&nchanger->devq, 1) != 0) { 784 softc->flags &= ~CD_FLAG_CHANGER; 785 printf("cdregister: changer support " 786 "disabled\n"); 787 goto cdregisterexit; 788 } 789 790 num_changers++; 791 792 nchanger->path_id = cgd->ccb_h.path_id; 793 nchanger->target_id = cgd->ccb_h.target_id; 794 795 /* this is superfluous, but it makes things clearer */ 796 nchanger->num_devices = 0; 797 798 STAILQ_INIT(&nchanger->chluns); 799 800 STAILQ_INSERT_TAIL(&changerq, nchanger, 801 changer_links); 802 803 /* 804 * Create a path with lun id 0, and see if we can 805 * find a matching device 806 */ 807 status = xpt_create_path(&path, /*periph*/ periph, 808 cgd->ccb_h.path_id, 809 cgd->ccb_h.target_id, 0); 810 811 /* 812 * If we were able to allocate the path, and if we 813 * find a matching device and it isn't already 814 * marked as part of a changer, then we add it to 815 * the current changer. 816 */ 817 if ((status == CAM_REQ_CMP) 818 && ((nperiph = cam_periph_find(path, "cd")) != NULL) 819 && ((((struct cd_softc *)periph->softc)->flags & 820 CD_FLAG_CHANGER) == 0)) { 821 struct cd_softc *nsoftc; 822 823 nsoftc = (struct cd_softc *)nperiph->softc; 824 825 nsoftc->flags |= CD_FLAG_CHANGER; 826 nchanger->num_devices++; 827 if (camq_resize(&nchanger->devq, 828 nchanger->num_devices) != CAM_REQ_CMP) { 829 printf("cdregister: camq_resize " 830 "failed, changer support may " 831 "be messed up\n"); 832 } 833 nsoftc->changer = nchanger; 834 nsoftc->pinfo.index = CAM_UNQUEUED_INDEX; 835 836 STAILQ_INSERT_TAIL(&nchanger->chluns, 837 nsoftc, changer_links); 838 } else if (status == CAM_REQ_CMP) 839 xpt_free_path(path); 840 else { 841 printf("cdregister: unable to allocate path\n" 842 "cdregister: changer support may be " 843 "broken\n"); 844 } 845 846 softc->changer = nchanger; 847 softc->pinfo.index = CAM_UNQUEUED_INDEX; 848 nchanger->num_devices++; 849 if (camq_resize(&nchanger->devq, 850 nchanger->num_devices) != CAM_REQ_CMP) { 851 printf("cdregister: camq_resize " 852 "failed, changer support may " 853 "be messed up\n"); 854 } 855 STAILQ_INSERT_TAIL(&nchanger->chluns, softc, 856 changer_links); 857 } 858 } 859 860cdregisterexit: 861 862 /* Lock this peripheral until we are setup */ 863 /* Can't block */ 864 cam_periph_lock(periph, PRIBIO); 865 866 if ((softc->flags & CD_FLAG_CHANGER) == 0) 867 xpt_schedule(periph, /*priority*/5); 868 else 869 cdschedule(periph, /*priority*/ 5); 870 871 return(CAM_REQ_CMP); 872} 873 874static int 875cdopen(dev_t dev, int flags, int fmt, struct proc *p) 876{ 877 struct disklabel label; 878 struct cam_periph *periph; 879 struct cd_softc *softc; 880 struct ccb_getdev cgd; 881 u_int32_t size; 882 int unit, error; 883 int s; 884 885 unit = dkunit(dev); 886 periph = cam_extend_get(cdperiphs, unit); 887 888 if (periph == NULL) 889 return (ENXIO); 890 891 softc = (struct cd_softc *)periph->softc; 892 893 /* 894 * Grab splsoftcam and hold it until we lock the peripheral. 895 */ 896 s = splsoftcam(); 897 if (softc->flags & CD_FLAG_INVALID) { 898 splx(s); 899 return(ENXIO); 900 } 901 902 if ((error = cam_periph_lock(periph, PRIBIO | PCATCH)) != 0) { 903 splx(s); 904 return (error); 905 } 906 907 splx(s); 908 909 if ((softc->flags & CD_FLAG_OPEN) == 0) { 910 if (cam_periph_acquire(periph) != CAM_REQ_CMP) 911 return(ENXIO); 912 softc->flags |= CD_FLAG_OPEN; 913 914 cdprevent(periph, PR_PREVENT); 915 } 916 917 /* find out the size */ 918 if ((error = cdsize(dev, &size)) != 0) { 919 if (dsisopen(softc->cd_slices) == 0) { 920 cdprevent(periph, PR_ALLOW); 921 softc->flags &= ~CD_FLAG_OPEN; 922 } 923 cam_periph_unlock(periph); 924 925 if ((softc->flags & CD_FLAG_OPEN) == 0) 926 cam_periph_release(periph); 927 928 return(error); 929 } 930 931 /* 932 * Build prototype label for whole disk. 933 * Should take information about different data tracks from the 934 * TOC and put it in the partition table. 935 */ 936 bzero(&label, sizeof(label)); 937 label.d_type = DTYPE_SCSI; 938 939 /* 940 * Grab the inquiry data to get the vendor and product names. 941 * Put them in the typename and packname for the label. 942 */ 943 xpt_setup_ccb(&cgd.ccb_h, periph->path, /*priority*/ 1); 944 cgd.ccb_h.func_code = XPT_GDEV_TYPE; 945 xpt_action((union ccb *)&cgd); 946 947 strncpy(label.d_typename, cgd.inq_data.vendor, 948 min(SID_VENDOR_SIZE, sizeof(label.d_typename))); 949 strncpy(label.d_packname, cgd.inq_data.product, 950 min(SID_PRODUCT_SIZE, sizeof(label.d_packname))); 951 952 label.d_secsize = softc->params.blksize; 953 label.d_secperunit = softc->params.disksize; 954 label.d_flags = D_REMOVABLE; 955 /* 956 * Make partition 'a' cover the whole disk. This is a temporary 957 * compatibility hack. The 'a' partition should not exist, so 958 * the slice code won't create it. The slice code will make 959 * partition (RAW_PART + 'a') cover the whole disk and fill in 960 * some more defaults. 961 */ 962 label.d_partitions[0].p_size = label.d_secperunit; 963 label.d_partitions[0].p_fstype = FS_OTHER; 964 965 /* Initialize slice tables. */ 966 error = dsopen("cd", dev, fmt, DSO_NOLABELS | DSO_ONESLICE, 967 &softc->cd_slices, &label, cdstrategy1, 968 (ds_setgeom_t *)NULL, &cd_cdevsw); 969 970 if (error == 0) { 971 /* 972 * We unconditionally (re)set the blocksize each time the 973 * CD device is opened. This is because the CD can change, 974 * and therefore the blocksize might change. 975 * XXX problems here if some slice or partition is still 976 * open with the old size? 977 */ 978 if ((softc->device_stats.flags & DEVSTAT_BS_UNAVAILABLE) != 0) 979 softc->device_stats.flags &= ~DEVSTAT_BS_UNAVAILABLE; 980 softc->device_stats.block_size = softc->params.blksize; 981 } else { 982 if ((dsisopen(softc->cd_slices) == 0) 983 && ((softc->flags & CD_FLAG_DISC_REMOVABLE) != 0)) 984 cdprevent(periph, PR_ALLOW); 985 } 986 987 cam_periph_unlock(periph); 988 989 CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("leaving cdopen\n")); 990 991 return (error); 992} 993 994static int 995cdclose(dev_t dev, int flag, int fmt, struct proc *p) 996{ 997 struct cam_periph *periph; 998 struct cd_softc *softc; 999 int unit, error; 1000 1001 unit = dkunit(dev); 1002 periph = cam_extend_get(cdperiphs, unit); 1003 if (periph == NULL) 1004 return (ENXIO); 1005 1006 softc = (struct cd_softc *)periph->softc; 1007 1008 if ((error = cam_periph_lock(periph, PRIBIO)) != 0) 1009 return (error); 1010 1011 dsclose(dev, fmt, softc->cd_slices); 1012 if (dsisopen(softc->cd_slices)) { 1013 cam_periph_unlock(periph); 1014 return (0); 1015 } 1016 1017 if ((softc->flags & CD_FLAG_DISC_REMOVABLE) != 0) 1018 cdprevent(periph, PR_ALLOW); 1019 1020 /* 1021 * Since we're closing this CD, mark the blocksize as unavailable. 1022 * It will be marked as available whence the CD is opened again. 1023 */ 1024 softc->device_stats.flags |= DEVSTAT_BS_UNAVAILABLE; 1025 1026 softc->flags &= ~CD_FLAG_OPEN; 1027 cam_periph_unlock(periph); 1028 cam_periph_release(periph); 1029 1030 return (0); 1031} 1032 1033static void 1034cdshorttimeout(void *arg) 1035{ 1036 struct cdchanger *changer; 1037 int s; 1038 1039 s = splsoftcam(); 1040 1041 changer = (struct cdchanger *)arg; 1042 1043 /* Always clear the short timeout flag, since that's what we're in */ 1044 changer->flags &= ~CHANGER_SHORT_TMOUT_SCHED; 1045 1046 /* 1047 * Check to see if there is any more pending or outstanding I/O for 1048 * this device. If not, move it out of the active slot. 1049 */ 1050 if ((bufq_first(&changer->cur_device->buf_queue) == NULL) 1051 && (changer->cur_device->device_stats.busy_count == 0)) { 1052 changer->flags |= CHANGER_MANUAL_CALL; 1053 cdrunchangerqueue(changer); 1054 } 1055 1056 splx(s); 1057} 1058 1059/* 1060 * This is a wrapper for xpt_schedule. It only applies to changers. 1061 */ 1062static void 1063cdschedule(struct cam_periph *periph, int priority) 1064{ 1065 struct cd_softc *softc; 1066 int s; 1067 1068 s = splsoftcam(); 1069 1070 softc = (struct cd_softc *)periph->softc; 1071 1072 /* 1073 * If this device isn't currently queued, and if it isn't 1074 * the active device, then we queue this device and run the 1075 * changer queue if there is no timeout scheduled to do it. 1076 * If this device is the active device, just schedule it 1077 * to run again. If this device is queued, there should be 1078 * a timeout in place already that will make sure it runs. 1079 */ 1080 if ((softc->pinfo.index == CAM_UNQUEUED_INDEX) 1081 && ((softc->flags & CD_FLAG_ACTIVE) == 0)) { 1082 /* 1083 * We don't do anything with the priority here. 1084 * This is strictly a fifo queue. 1085 */ 1086 softc->pinfo.priority = 1; 1087 softc->pinfo.generation = ++softc->changer->devq.generation; 1088 camq_insert(&softc->changer->devq, (cam_pinfo *)softc); 1089 1090 /* 1091 * Since we just put a device in the changer queue, 1092 * check and see if there is a timeout scheduled for 1093 * this changer. If so, let the timeout handle 1094 * switching this device into the active slot. If 1095 * not, manually call the timeout routine to 1096 * bootstrap things. 1097 */ 1098 if (((softc->changer->flags & CHANGER_TIMEOUT_SCHED)==0) 1099 && ((softc->changer->flags & CHANGER_NEED_TIMEOUT)==0) 1100 && ((softc->changer->flags & CHANGER_SHORT_TMOUT_SCHED)==0)){ 1101 softc->changer->flags |= CHANGER_MANUAL_CALL; 1102 cdrunchangerqueue(softc->changer); 1103 } 1104 } else if ((softc->flags & CD_FLAG_ACTIVE) 1105 && ((softc->flags & CD_FLAG_SCHED_ON_COMP) == 0)) 1106 xpt_schedule(periph, priority); 1107 1108 splx(s); 1109 1110} 1111 1112static void 1113cdrunchangerqueue(void *arg) 1114{ 1115 struct cd_softc *softc; 1116 struct cdchanger *changer; 1117 int called_from_timeout; 1118 int s; 1119 1120 s = splsoftcam(); 1121 1122 changer = (struct cdchanger *)arg; 1123 1124 /* 1125 * If we have NOT been called from cdstrategy() or cddone(), and 1126 * instead from a timeout routine, go ahead and clear the 1127 * timeout flag. 1128 */ 1129 if ((changer->flags & CHANGER_MANUAL_CALL) == 0) { 1130 changer->flags &= ~CHANGER_TIMEOUT_SCHED; 1131 called_from_timeout = 1; 1132 } else 1133 called_from_timeout = 0; 1134 1135 /* Always clear the manual call flag */ 1136 changer->flags &= ~CHANGER_MANUAL_CALL; 1137 1138 /* nothing to do if the queue is empty */ 1139 if (changer->devq.entries <= 0) { 1140 splx(s); 1141 return; 1142 } 1143 1144 /* 1145 * If the changer queue is frozen, that means we have an active 1146 * device. 1147 */ 1148 if (changer->devq.qfrozen_cnt > 0) { 1149 1150 if (changer->cur_device->device_stats.busy_count > 0) { 1151 changer->cur_device->flags |= CD_FLAG_SCHED_ON_COMP; 1152 changer->cur_device->bufs_left = 1153 changer->cur_device->device_stats.busy_count; 1154 if (called_from_timeout) { 1155 changer->long_handle = 1156 timeout(cdrunchangerqueue, changer, 1157 changer_max_busy_seconds * hz); 1158 changer->flags |= CHANGER_TIMEOUT_SCHED; 1159 } 1160 splx(s); 1161 return; 1162 } 1163 1164 /* 1165 * We always need to reset the frozen count and clear the 1166 * active flag. 1167 */ 1168 changer->devq.qfrozen_cnt--; 1169 changer->cur_device->flags &= ~CD_FLAG_ACTIVE; 1170 changer->cur_device->flags &= ~CD_FLAG_SCHED_ON_COMP; 1171 1172 /* 1173 * Check to see whether the current device has any I/O left 1174 * to do. If so, requeue it at the end of the queue. If 1175 * not, there is no need to requeue it. 1176 */ 1177 if (bufq_first(&changer->cur_device->buf_queue) != NULL) { 1178 1179 changer->cur_device->pinfo.generation = 1180 ++changer->devq.generation; 1181 camq_insert(&changer->devq, 1182 (cam_pinfo *)changer->cur_device); 1183 } 1184 } 1185 1186 softc = (struct cd_softc *)camq_remove(&changer->devq, CAMQ_HEAD); 1187 1188 changer->cur_device = softc; 1189 1190 changer->devq.qfrozen_cnt++; 1191 softc->flags |= CD_FLAG_ACTIVE; 1192 1193 /* Just in case this device is waiting */ 1194 wakeup(&softc->changer); 1195 xpt_schedule(softc->periph, /*priority*/ 1); 1196 1197 /* 1198 * Get rid of any pending timeouts, and set a flag to schedule new 1199 * ones so this device gets its full time quantum. 1200 */ 1201 if (changer->flags & CHANGER_TIMEOUT_SCHED) { 1202 untimeout(cdrunchangerqueue, changer, changer->long_handle); 1203 changer->flags &= ~CHANGER_TIMEOUT_SCHED; 1204 } 1205 1206 if (changer->flags & CHANGER_SHORT_TMOUT_SCHED) { 1207 untimeout(cdshorttimeout, changer, changer->short_handle); 1208 changer->flags &= ~CHANGER_SHORT_TMOUT_SCHED; 1209 } 1210 1211 /* 1212 * We need to schedule timeouts, but we only do this after the 1213 * first transaction has completed. This eliminates the changer 1214 * switch time. 1215 */ 1216 changer->flags |= CHANGER_NEED_TIMEOUT; 1217 1218 splx(s); 1219} 1220 1221static void 1222cdchangerschedule(struct cd_softc *softc) 1223{ 1224 struct cdchanger *changer; 1225 int s; 1226 1227 s = splsoftcam(); 1228 1229 changer = softc->changer; 1230 1231 /* 1232 * If this is a changer, and this is the current device, 1233 * and this device has at least the minimum time quantum to 1234 * run, see if we can switch it out. 1235 */ 1236 if ((softc->flags & CD_FLAG_ACTIVE) 1237 && ((changer->flags & CHANGER_SHORT_TMOUT_SCHED) == 0) 1238 && ((changer->flags & CHANGER_NEED_TIMEOUT) == 0)) { 1239 /* 1240 * We try three things here. The first is that we 1241 * check to see whether the schedule on completion 1242 * flag is set. If it is, we decrement the number 1243 * of buffers left, and if it's zero, we reschedule. 1244 * Next, we check to see whether the pending buffer 1245 * queue is empty and whether there are no 1246 * outstanding transactions. If so, we reschedule. 1247 * Next, we see if the pending buffer queue is empty. 1248 * If it is, we set the number of buffers left to 1249 * the current active buffer count and set the 1250 * schedule on complete flag. 1251 */ 1252 if (softc->flags & CD_FLAG_SCHED_ON_COMP) { 1253 if (--softc->bufs_left == 0) { 1254 softc->changer->flags |= 1255 CHANGER_MANUAL_CALL; 1256 softc->flags &= ~CD_FLAG_SCHED_ON_COMP; 1257 cdrunchangerqueue(softc->changer); 1258 } 1259 } else if ((bufq_first(&softc->buf_queue) == NULL) 1260 && (softc->device_stats.busy_count == 0)) { 1261 softc->changer->flags |= CHANGER_MANUAL_CALL; 1262 cdrunchangerqueue(softc->changer); 1263 } 1264 } else if ((softc->changer->flags & CHANGER_NEED_TIMEOUT) 1265 && (softc->flags & CD_FLAG_ACTIVE)) { 1266 1267 /* 1268 * Now that the first transaction to this 1269 * particular device has completed, we can go ahead 1270 * and schedule our timeouts. 1271 */ 1272 if ((changer->flags & CHANGER_TIMEOUT_SCHED) == 0) { 1273 changer->long_handle = 1274 timeout(cdrunchangerqueue, changer, 1275 changer_max_busy_seconds * hz); 1276 changer->flags |= CHANGER_TIMEOUT_SCHED; 1277 } else 1278 printf("cdchangerschedule: already have a long" 1279 " timeout!\n"); 1280 1281 if ((changer->flags & CHANGER_SHORT_TMOUT_SCHED) == 0) { 1282 changer->short_handle = 1283 timeout(cdshorttimeout, changer, 1284 changer_min_busy_seconds * hz); 1285 changer->flags |= CHANGER_SHORT_TMOUT_SCHED; 1286 } else 1287 printf("cdchangerschedule: already have a short " 1288 "timeout!\n"); 1289 1290 /* 1291 * We just scheduled timeouts, no need to schedule 1292 * more. 1293 */ 1294 changer->flags &= ~CHANGER_NEED_TIMEOUT; 1295 1296 } 1297 splx(s); 1298} 1299 1300static int 1301cdrunccb(union ccb *ccb, int (*error_routine)(union ccb *ccb, 1302 u_int32_t cam_flags, 1303 u_int32_t sense_flags), 1304 u_int32_t cam_flags, u_int32_t sense_flags) 1305{ 1306 struct cd_softc *softc; 1307 struct cam_periph *periph; 1308 int error; 1309 1310 periph = xpt_path_periph(ccb->ccb_h.path); 1311 softc = (struct cd_softc *)periph->softc; 1312 1313 error = cam_periph_runccb(ccb, error_routine, cam_flags, sense_flags, 1314 &softc->device_stats); 1315 1316 if (softc->flags & CD_FLAG_CHANGER) 1317 cdchangerschedule(softc); 1318 1319 return(error); 1320} 1321 1322static union ccb * 1323cdgetccb(struct cam_periph *periph, u_int32_t priority) 1324{ 1325 struct cd_softc *softc; 1326 int s; 1327 1328 softc = (struct cd_softc *)periph->softc; 1329 1330 if (softc->flags & CD_FLAG_CHANGER) { 1331 1332 s = splsoftcam(); 1333 1334 /* 1335 * This should work the first time this device is woken up, 1336 * but just in case it doesn't, we use a while loop. 1337 */ 1338 while ((softc->flags & CD_FLAG_ACTIVE) == 0) { 1339 /* 1340 * If this changer isn't already queued, queue it up. 1341 */ 1342 if (softc->pinfo.index == CAM_UNQUEUED_INDEX) { 1343 softc->pinfo.priority = 1; 1344 softc->pinfo.generation = 1345 ++softc->changer->devq.generation; 1346 camq_insert(&softc->changer->devq, 1347 (cam_pinfo *)softc); 1348 } 1349 if (((softc->changer->flags & CHANGER_TIMEOUT_SCHED)==0) 1350 && ((softc->changer->flags & CHANGER_NEED_TIMEOUT)==0) 1351 && ((softc->changer->flags 1352 & CHANGER_SHORT_TMOUT_SCHED)==0)) { 1353 softc->changer->flags |= CHANGER_MANUAL_CALL; 1354 cdrunchangerqueue(softc->changer); 1355 } else 1356 tsleep(&softc->changer, PRIBIO, "cgticb", 0); 1357 } 1358 splx(s); 1359 } 1360 return(cam_periph_getccb(periph, priority)); 1361} 1362 1363 1364/* 1365 * Actually translate the requested transfer into one the physical driver 1366 * can understand. The transfer is described by a buf and will include 1367 * only one physical transfer. 1368 */ 1369static void 1370cdstrategy(struct buf *bp) 1371{ 1372 struct cam_periph *periph; 1373 struct cd_softc *softc; 1374 u_int unit, part; 1375 int s; 1376 1377 unit = dkunit(bp->b_dev); 1378 part = dkpart(bp->b_dev); 1379 periph = cam_extend_get(cdperiphs, unit); 1380 if (periph == NULL) { 1381 bp->b_error = ENXIO; 1382 goto bad; 1383 } 1384 1385 CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdstrategy\n")); 1386 1387 softc = (struct cd_softc *)periph->softc; 1388 1389 /* 1390 * Do bounds checking, adjust transfer, and set b_pbklno. 1391 */ 1392 if (dscheck(bp, softc->cd_slices) <= 0) 1393 goto done; 1394 1395 /* 1396 * Mask interrupts so that the pack cannot be invalidated until 1397 * after we are in the queue. Otherwise, we might not properly 1398 * clean up one of the buffers. 1399 */ 1400 s = splbio(); 1401 1402 /* 1403 * If the device has been made invalid, error out 1404 */ 1405 if ((softc->flags & CD_FLAG_INVALID)) { 1406 splx(s); 1407 bp->b_error = ENXIO; 1408 goto bad; 1409 } 1410 1411 /* 1412 * Place it in the queue of disk activities for this disk 1413 */ 1414 bufqdisksort(&softc->buf_queue, bp); 1415 1416 splx(s); 1417 1418 /* 1419 * Schedule ourselves for performing the work. We do things 1420 * differently for changers. 1421 */ 1422 if ((softc->flags & CD_FLAG_CHANGER) == 0) 1423 xpt_schedule(periph, /* XXX priority */1); 1424 else 1425 cdschedule(periph, /* priority */ 1); 1426 1427 return; 1428bad: 1429 bp->b_flags |= B_ERROR; 1430done: 1431 /* 1432 * Correctly set the buf to indicate a completed xfer 1433 */ 1434 bp->b_resid = bp->b_bcount; 1435 biodone(bp); 1436 return; 1437} 1438 1439static void 1440cdstrategy1(struct buf *bp) 1441{ 1442 /* 1443 * XXX - do something to make cdstrategy() but not this block while 1444 * we're doing dsopen() and dsioctl(). 1445 */ 1446 cdstrategy(bp); 1447} 1448 1449static void 1450cdstart(struct cam_periph *periph, union ccb *start_ccb) 1451{ 1452 struct cd_softc *softc; 1453 struct buf *bp; 1454 struct ccb_scsiio *csio; 1455 struct scsi_read_capacity_data *rcap; 1456 int s; 1457 1458 softc = (struct cd_softc *)periph->softc; 1459 1460 CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdstart\n")); 1461 1462 switch (softc->state) { 1463 case CD_STATE_NORMAL: 1464 { 1465 int oldspl; 1466 1467 s = splbio(); 1468 bp = bufq_first(&softc->buf_queue); 1469 if (periph->immediate_priority <= periph->pinfo.priority) { 1470 start_ccb->ccb_h.ccb_state = CD_CCB_WAITING; 1471 1472 SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, 1473 periph_links.sle); 1474 periph->immediate_priority = CAM_PRIORITY_NONE; 1475 splx(s); 1476 wakeup(&periph->ccb_list); 1477 } else if (bp == NULL) { 1478 splx(s); 1479 xpt_release_ccb(start_ccb); 1480 } else { 1481 bufq_remove(&softc->buf_queue, bp); 1482 1483 devstat_start_transaction(&softc->device_stats); 1484 1485 scsi_read_write(&start_ccb->csio, 1486 /*retries*/4, 1487 /* cbfcnp */ cddone, 1488 (bp->b_flags & B_ORDERED) != 0 ? 1489 MSG_ORDERED_Q_TAG : 1490 MSG_SIMPLE_Q_TAG, 1491 /* read */bp->b_flags & B_READ, 1492 /* byte2 */ 0, 1493 /* minimum_cmd_size */ 10, 1494 /* lba */ bp->b_pblkno, 1495 bp->b_bcount / softc->params.blksize, 1496 /* data_ptr */ bp->b_data, 1497 /* dxfer_len */ bp->b_bcount, 1498 /* sense_len */ SSD_FULL_SIZE, 1499 /* timeout */ 30000); 1500 start_ccb->ccb_h.ccb_state = CD_CCB_BUFFER_IO; 1501 1502 1503 /* 1504 * Block out any asyncronous callbacks 1505 * while we touch the pending ccb list. 1506 */ 1507 oldspl = splcam(); 1508 LIST_INSERT_HEAD(&softc->pending_ccbs, 1509 &start_ccb->ccb_h, periph_links.le); 1510 splx(oldspl); 1511 1512 /* We expect a unit attention from this device */ 1513 if ((softc->flags & CD_FLAG_RETRY_UA) != 0) { 1514 start_ccb->ccb_h.ccb_state |= CD_CCB_RETRY_UA; 1515 softc->flags &= ~CD_FLAG_RETRY_UA; 1516 } 1517 1518 start_ccb->ccb_h.ccb_bp = bp; 1519 bp = bufq_first(&softc->buf_queue); 1520 splx(s); 1521 1522 xpt_action(start_ccb); 1523 } 1524 if (bp != NULL) { 1525 /* Have more work to do, so ensure we stay scheduled */ 1526 xpt_schedule(periph, /* XXX priority */1); 1527 } 1528 break; 1529 } 1530 case CD_STATE_PROBE: 1531 { 1532 1533 rcap = (struct scsi_read_capacity_data *)malloc(sizeof(*rcap), 1534 M_TEMP, 1535 M_NOWAIT); 1536 if (rcap == NULL) { 1537 xpt_print_path(periph->path); 1538 printf("cdstart: Couldn't malloc read_capacity data\n"); 1539 /* cd_free_periph??? */ 1540 break; 1541 } 1542 csio = &start_ccb->csio; 1543 scsi_read_capacity(csio, 1544 /*retries*/1, 1545 cddone, 1546 MSG_SIMPLE_Q_TAG, 1547 rcap, 1548 SSD_FULL_SIZE, 1549 /*timeout*/20000); 1550 start_ccb->ccb_h.ccb_bp = NULL; 1551 start_ccb->ccb_h.ccb_state = CD_CCB_PROBE; 1552 xpt_action(start_ccb); 1553 break; 1554 } 1555 } 1556} 1557 1558static void 1559cddone(struct cam_periph *periph, union ccb *done_ccb) 1560{ 1561 struct cd_softc *softc; 1562 struct ccb_scsiio *csio; 1563 1564 CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cddone\n")); 1565 1566 softc = (struct cd_softc *)periph->softc; 1567 csio = &done_ccb->csio; 1568 1569 switch (csio->ccb_h.ccb_state & CD_CCB_TYPE_MASK) { 1570 case CD_CCB_BUFFER_IO: 1571 { 1572 struct buf *bp; 1573 int error; 1574 int oldspl; 1575 1576 bp = (struct buf *)done_ccb->ccb_h.ccb_bp; 1577 error = 0; 1578 1579 if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 1580 int sf; 1581 1582 if ((done_ccb->ccb_h.ccb_state & CD_CCB_RETRY_UA) != 0) 1583 sf = SF_RETRY_UA; 1584 else 1585 sf = 0; 1586 1587 /* Retry selection timeouts */ 1588 sf |= SF_RETRY_SELTO; 1589 1590 if ((error = cderror(done_ccb, 0, sf)) == ERESTART) { 1591 /* 1592 * A retry was scheuled, so 1593 * just return. 1594 */ 1595 return; 1596 } 1597 } 1598 1599 if (error != 0) { 1600 int s; 1601 struct buf *q_bp; 1602 1603 xpt_print_path(periph->path); 1604 printf("cddone: got error %#x back\n", error); 1605 s = splbio(); 1606 while ((q_bp = bufq_first(&softc->buf_queue)) != NULL) { 1607 bufq_remove(&softc->buf_queue, q_bp); 1608 q_bp->b_resid = q_bp->b_bcount; 1609 q_bp->b_error = EIO; 1610 q_bp->b_flags |= B_ERROR; 1611 biodone(q_bp); 1612 } 1613 splx(s); 1614 bp->b_resid = bp->b_bcount; 1615 bp->b_error = error; 1616 bp->b_flags |= B_ERROR; 1617 cam_release_devq(done_ccb->ccb_h.path, 1618 /*relsim_flags*/0, 1619 /*reduction*/0, 1620 /*timeout*/0, 1621 /*getcount_only*/0); 1622 1623 } else { 1624 bp->b_resid = csio->resid; 1625 bp->b_error = 0; 1626 if (bp->b_resid != 0) { 1627 /* Short transfer ??? */ 1628 bp->b_flags |= B_ERROR; 1629 } 1630 } 1631 1632 /* 1633 * Block out any asyncronous callbacks 1634 * while we touch the pending ccb list. 1635 */ 1636 oldspl = splcam(); 1637 LIST_REMOVE(&done_ccb->ccb_h, periph_links.le); 1638 splx(oldspl); 1639 1640 devstat_end_transaction(&softc->device_stats, 1641 bp->b_bcount - bp->b_resid, 1642 done_ccb->csio.tag_action & 0xf, 1643 (bp->b_flags & B_READ) ? DEVSTAT_READ 1644 : DEVSTAT_WRITE); 1645 1646 if (softc->flags & CD_FLAG_CHANGER) 1647 cdchangerschedule(softc); 1648 1649 biodone(bp); 1650 break; 1651 } 1652 case CD_CCB_PROBE: 1653 { 1654 struct scsi_read_capacity_data *rdcap; 1655 char announce_buf[120]; /* 1656 * Currently (9/30/97) the 1657 * longest possible announce 1658 * buffer is 108 bytes, for the 1659 * first error case below. 1660 * That is 39 bytes for the 1661 * basic string, 16 bytes for the 1662 * biggest sense key (hardware 1663 * error), 52 bytes for the 1664 * text of the largest sense 1665 * qualifier valid for a CDROM, 1666 * (0x72, 0x03 or 0x04, 1667 * 0x03), and one byte for the 1668 * null terminating character. 1669 * To allow for longer strings, 1670 * the announce buffer is 120 1671 * bytes. 1672 */ 1673 struct cd_params *cdp; 1674 1675 cdp = &softc->params; 1676 1677 rdcap = (struct scsi_read_capacity_data *)csio->data_ptr; 1678 1679 cdp->disksize = scsi_4btoul (rdcap->addr) + 1; 1680 cdp->blksize = scsi_4btoul (rdcap->length); 1681 1682 if ((csio->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 1683 1684 snprintf(announce_buf, sizeof(announce_buf), 1685 "cd present [%lu x %lu byte records]", 1686 cdp->disksize, (u_long)cdp->blksize); 1687 1688 } else { 1689 int error; 1690 /* 1691 * Retry any UNIT ATTENTION type errors. They 1692 * are expected at boot. 1693 */ 1694 error = cderror(done_ccb, 0, SF_RETRY_UA | 1695 SF_NO_PRINT | SF_RETRY_SELTO); 1696 if (error == ERESTART) { 1697 /* 1698 * A retry was scheuled, so 1699 * just return. 1700 */ 1701 return; 1702 } else if (error != 0) { 1703 1704 struct scsi_sense_data *sense; 1705 int asc, ascq; 1706 int sense_key, error_code; 1707 int have_sense; 1708 cam_status status; 1709 struct ccb_getdev cgd; 1710 1711 /* Don't wedge this device's queue */ 1712 cam_release_devq(done_ccb->ccb_h.path, 1713 /*relsim_flags*/0, 1714 /*reduction*/0, 1715 /*timeout*/0, 1716 /*getcount_only*/0); 1717 1718 status = done_ccb->ccb_h.status; 1719 1720 xpt_setup_ccb(&cgd.ccb_h, 1721 done_ccb->ccb_h.path, 1722 /* priority */ 1); 1723 cgd.ccb_h.func_code = XPT_GDEV_TYPE; 1724 xpt_action((union ccb *)&cgd); 1725 1726 if (((csio->ccb_h.flags & CAM_SENSE_PHYS) != 0) 1727 || ((csio->ccb_h.flags & CAM_SENSE_PTR) != 0) 1728 || ((status & CAM_AUTOSNS_VALID) == 0)) 1729 have_sense = FALSE; 1730 else 1731 have_sense = TRUE; 1732 1733 if (have_sense) { 1734 sense = &csio->sense_data; 1735 scsi_extract_sense(sense, &error_code, 1736 &sense_key, 1737 &asc, &ascq); 1738 } 1739 /* 1740 * Attach to anything that claims to be a 1741 * CDROM or WORM device, as long as it 1742 * doesn't return a "Logical unit not 1743 * supported" (0x25) error. 1744 */ 1745 if ((have_sense) && (asc != 0x25) 1746 && (error_code == SSD_CURRENT_ERROR)) 1747 snprintf(announce_buf, 1748 sizeof(announce_buf), 1749 "Attempt to query device " 1750 "size failed: %s, %s", 1751 scsi_sense_key_text[sense_key], 1752 scsi_sense_desc(asc,ascq, 1753 &cgd.inq_data)); 1754 else if (cgd.pd_type == T_CDROM) { 1755 /* 1756 * We only print out an error for 1757 * CDROM type devices. For WORM 1758 * devices, we don't print out an 1759 * error since a few WORM devices 1760 * don't support CDROM commands. 1761 * If we have sense information, go 1762 * ahead and print it out. 1763 * Otherwise, just say that we 1764 * couldn't attach. 1765 */ 1766 1767 /* 1768 * Just print out the error, not 1769 * the full probe message, when we 1770 * don't attach. 1771 */ 1772 if (have_sense) 1773 scsi_sense_print( 1774 &done_ccb->csio); 1775 else { 1776 xpt_print_path(periph->path); 1777 printf("got CAM status %#x\n", 1778 done_ccb->ccb_h.status); 1779 } 1780 xpt_print_path(periph->path); 1781 printf("fatal error, failed" 1782 " to attach to device\n"); 1783 1784 /* 1785 * Invalidate this peripheral. 1786 */ 1787 cam_periph_invalidate(periph); 1788 1789 announce_buf[0] = '\0'; 1790 } else { 1791 1792 /* 1793 * Invalidate this peripheral. 1794 */ 1795 cam_periph_invalidate(periph); 1796 announce_buf[0] = '\0'; 1797 } 1798 } 1799 } 1800 free(rdcap, M_TEMP); 1801 if (announce_buf[0] != '\0') { 1802 xpt_announce_periph(periph, announce_buf); 1803 if (softc->flags & CD_FLAG_CHANGER) 1804 cdchangerschedule(softc); 1805 } 1806 softc->state = CD_STATE_NORMAL; 1807 /* 1808 * Since our peripheral may be invalidated by an error 1809 * above or an external event, we must release our CCB 1810 * before releasing the probe lock on the peripheral. 1811 * The peripheral will only go away once the last lock 1812 * is removed, and we need it around for the CCB release 1813 * operation. 1814 */ 1815 xpt_release_ccb(done_ccb); 1816 cam_periph_unlock(periph); 1817 return; 1818 } 1819 case CD_CCB_WAITING: 1820 { 1821 /* Caller will release the CCB */ 1822 CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, 1823 ("trying to wakeup ccbwait\n")); 1824 1825 wakeup(&done_ccb->ccb_h.cbfcnp); 1826 return; 1827 } 1828 default: 1829 break; 1830 } 1831 xpt_release_ccb(done_ccb); 1832} 1833 1834static int 1835cdioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) 1836{ 1837 1838 struct cam_periph *periph; 1839 struct cd_softc *softc; 1840 int error, unit; 1841 1842 unit = dkunit(dev); 1843 1844 periph = cam_extend_get(cdperiphs, unit); 1845 if (periph == NULL) 1846 return(ENXIO); 1847 1848 CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdioctl\n")); 1849 1850 softc = (struct cd_softc *)periph->softc; 1851 1852 CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, 1853 ("trying to do ioctl %#lx\n", cmd)); 1854 1855 error = cam_periph_lock(periph, PRIBIO | PCATCH); 1856 1857 if (error != 0) 1858 return(error); 1859 1860 switch (cmd) { 1861 1862 case CDIOCPLAYTRACKS: 1863 { 1864 struct ioc_play_track *args 1865 = (struct ioc_play_track *) addr; 1866 struct cd_mode_data *data; 1867 1868 data = malloc(sizeof(struct cd_mode_data), M_TEMP, 1869 M_WAITOK); 1870 1871 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 1872 ("trying to do CDIOCPLAYTRACKS\n")); 1873 1874 error = cdgetmode(periph, data, AUDIO_PAGE); 1875 if (error) { 1876 free(data, M_TEMP); 1877 break; 1878 } 1879 data->page.audio.flags &= ~CD_PA_SOTC; 1880 data->page.audio.flags |= CD_PA_IMMED; 1881 error = cdsetmode(periph, data); 1882 free(data, M_TEMP); 1883 if (error) 1884 break; 1885 if (softc->quirks & CD_Q_BCD_TRACKS) { 1886 args->start_track = bin2bcd(args->start_track); 1887 args->end_track = bin2bcd(args->end_track); 1888 } 1889 error = cdplaytracks(periph, 1890 args->start_track, 1891 args->start_index, 1892 args->end_track, 1893 args->end_index); 1894 } 1895 break; 1896 case CDIOCPLAYMSF: 1897 { 1898 struct ioc_play_msf *args 1899 = (struct ioc_play_msf *) addr; 1900 struct cd_mode_data *data; 1901 1902 data = malloc(sizeof(struct cd_mode_data), M_TEMP, 1903 M_WAITOK); 1904 1905 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 1906 ("trying to do CDIOCPLAYMSF\n")); 1907 1908 error = cdgetmode(periph, data, AUDIO_PAGE); 1909 if (error) { 1910 free(data, M_TEMP); 1911 break; 1912 } 1913 data->page.audio.flags &= ~CD_PA_SOTC; 1914 data->page.audio.flags |= CD_PA_IMMED; 1915 error = cdsetmode(periph, data); 1916 free(data, M_TEMP); 1917 if (error) 1918 break; 1919 error = cdplaymsf(periph, 1920 args->start_m, 1921 args->start_s, 1922 args->start_f, 1923 args->end_m, 1924 args->end_s, 1925 args->end_f); 1926 } 1927 break; 1928 case CDIOCPLAYBLOCKS: 1929 { 1930 struct ioc_play_blocks *args 1931 = (struct ioc_play_blocks *) addr; 1932 struct cd_mode_data *data; 1933 1934 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 1935 ("trying to do CDIOCPLAYBLOCKS\n")); 1936 1937 data = malloc(sizeof(struct cd_mode_data), M_TEMP, 1938 M_WAITOK); 1939 1940 error = cdgetmode(periph, data, AUDIO_PAGE); 1941 if (error) { 1942 free(data, M_TEMP); 1943 break; 1944 } 1945 data->page.audio.flags &= ~CD_PA_SOTC; 1946 data->page.audio.flags |= CD_PA_IMMED; 1947 error = cdsetmode(periph, data); 1948 free(data, M_TEMP); 1949 if (error) 1950 break; 1951 error = cdplay(periph, args->blk, args->len); 1952 } 1953 break; 1954 case CDIOCREADSUBCHANNEL: 1955 { 1956 struct ioc_read_subchannel *args 1957 = (struct ioc_read_subchannel *) addr; 1958 struct cd_sub_channel_info *data; 1959 u_int32_t len = args->data_len; 1960 1961 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 1962 ("trying to do CDIOCREADSUBCHANNEL\n")); 1963 1964 data = malloc(sizeof(struct cd_sub_channel_info), 1965 M_TEMP, M_WAITOK); 1966 1967 if ((len > sizeof(struct cd_sub_channel_info)) || 1968 (len < sizeof(struct cd_sub_channel_header))) { 1969 printf( 1970 "scsi_cd: cdioctl: " 1971 "cdioreadsubchannel: error, len=%d\n", 1972 len); 1973 error = EINVAL; 1974 free(data, M_TEMP); 1975 break; 1976 } 1977 1978 if (softc->quirks & CD_Q_BCD_TRACKS) 1979 args->track = bin2bcd(args->track); 1980 1981 error = cdreadsubchannel(periph, args->address_format, 1982 args->data_format, args->track, data, len); 1983 1984 if (error) { 1985 free(data, M_TEMP); 1986 break; 1987 } 1988 if (softc->quirks & CD_Q_BCD_TRACKS) 1989 data->what.track_info.track_number = 1990 bcd2bin(data->what.track_info.track_number); 1991 len = min(len, ((data->header.data_len[0] << 8) + 1992 data->header.data_len[1] + 1993 sizeof(struct cd_sub_channel_header))); 1994 if (copyout(data, args->data, len) != 0) { 1995 error = EFAULT; 1996 } 1997 free(data, M_TEMP); 1998 } 1999 break; 2000 2001 case CDIOREADTOCHEADER: 2002 { 2003 struct ioc_toc_header *th; 2004 2005 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 2006 ("trying to do CDIOREADTOCHEADER\n")); 2007 2008 th = malloc(sizeof(struct ioc_toc_header), M_TEMP, 2009 M_WAITOK); 2010 error = cdreadtoc(periph, 0, 0, 2011 (struct cd_toc_entry *)th, 2012 sizeof (*th)); 2013 if (error) { 2014 free(th, M_TEMP); 2015 break; 2016 } 2017 if (softc->quirks & CD_Q_BCD_TRACKS) { 2018 /* we are going to have to convert the BCD 2019 * encoding on the cd to what is expected 2020 */ 2021 th->starting_track = 2022 bcd2bin(th->starting_track); 2023 th->ending_track = bcd2bin(th->ending_track); 2024 } 2025 NTOHS(th->len); 2026 bcopy(th, addr, sizeof(*th)); 2027 free(th, M_TEMP); 2028 } 2029 break; 2030 case CDIOREADTOCENTRYS: 2031 { 2032 typedef struct { 2033 struct ioc_toc_header header; 2034 struct cd_toc_entry entries[100]; 2035 } data_t; 2036 typedef struct { 2037 struct ioc_toc_header header; 2038 struct cd_toc_entry entry; 2039 } lead_t; 2040 2041 data_t *data; 2042 lead_t *lead; 2043 struct ioc_read_toc_entry *te = 2044 (struct ioc_read_toc_entry *) addr; 2045 struct ioc_toc_header *th; 2046 u_int32_t len, readlen, idx, num; 2047 u_int32_t starting_track = te->starting_track; 2048 2049 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 2050 ("trying to do CDIOREADTOCENTRYS\n")); 2051 2052 data = malloc(sizeof(data_t), M_TEMP, M_WAITOK); 2053 lead = malloc(sizeof(lead_t), M_TEMP, M_WAITOK); 2054 2055 if (te->data_len < sizeof(struct cd_toc_entry) 2056 || (te->data_len % sizeof(struct cd_toc_entry)) != 0 2057 || (te->address_format != CD_MSF_FORMAT 2058 && te->address_format != CD_LBA_FORMAT)) { 2059 error = EINVAL; 2060 printf("scsi_cd: error in readtocentries, " 2061 "returning EINVAL\n"); 2062 free(data, M_TEMP); 2063 free(lead, M_TEMP); 2064 break; 2065 } 2066 2067 th = &data->header; 2068 error = cdreadtoc(periph, 0, 0, 2069 (struct cd_toc_entry *)th, 2070 sizeof (*th)); 2071 if (error) { 2072 free(data, M_TEMP); 2073 free(lead, M_TEMP); 2074 break; 2075 } 2076 2077 if (softc->quirks & CD_Q_BCD_TRACKS) { 2078 /* we are going to have to convert the BCD 2079 * encoding on the cd to what is expected 2080 */ 2081 th->starting_track = 2082 bcd2bin(th->starting_track); 2083 th->ending_track = bcd2bin(th->ending_track); 2084 } 2085 2086 if (starting_track == 0) 2087 starting_track = th->starting_track; 2088 else if (starting_track == LEADOUT) 2089 starting_track = th->ending_track + 1; 2090 else if (starting_track < th->starting_track || 2091 starting_track > th->ending_track + 1) { 2092 printf("scsi_cd: error in readtocentries, " 2093 "returning EINVAL\n"); 2094 free(data, M_TEMP); 2095 free(lead, M_TEMP); 2096 error = EINVAL; 2097 break; 2098 } 2099 2100 /* calculate reading length without leadout entry */ 2101 readlen = (th->ending_track - starting_track + 1) * 2102 sizeof(struct cd_toc_entry); 2103 2104 /* and with leadout entry */ 2105 len = readlen + sizeof(struct cd_toc_entry); 2106 if (te->data_len < len) { 2107 len = te->data_len; 2108 if (readlen > len) 2109 readlen = len; 2110 } 2111 if (len > sizeof(data->entries)) { 2112 printf("scsi_cd: error in readtocentries, " 2113 "returning EINVAL\n"); 2114 error = EINVAL; 2115 free(data, M_TEMP); 2116 free(lead, M_TEMP); 2117 break; 2118 } 2119 num = len / sizeof(struct cd_toc_entry); 2120 2121 if (readlen > 0) { 2122 error = cdreadtoc(periph, te->address_format, 2123 starting_track, 2124 (struct cd_toc_entry *)data, 2125 readlen + sizeof (*th)); 2126 if (error) { 2127 free(data, M_TEMP); 2128 free(lead, M_TEMP); 2129 break; 2130 } 2131 } 2132 2133 /* make leadout entry if needed */ 2134 idx = starting_track + num - 1; 2135 if (softc->quirks & CD_Q_BCD_TRACKS) 2136 th->ending_track = bcd2bin(th->ending_track); 2137 if (idx == th->ending_track + 1) { 2138 error = cdreadtoc(periph, te->address_format, 2139 LEADOUT, 2140 (struct cd_toc_entry *)lead, 2141 sizeof(*lead)); 2142 if (error) { 2143 free(data, M_TEMP); 2144 free(lead, M_TEMP); 2145 break; 2146 } 2147 data->entries[idx - starting_track] = 2148 lead->entry; 2149 } 2150 if (softc->quirks & CD_Q_BCD_TRACKS) { 2151 for (idx = 0; idx < num - 1; idx++) { 2152 data->entries[idx].track = 2153 bcd2bin(data->entries[idx].track); 2154 } 2155 } 2156 2157 error = copyout(data->entries, te->data, len); 2158 free(data, M_TEMP); 2159 free(lead, M_TEMP); 2160 } 2161 break; 2162 case CDIOREADTOCENTRY: 2163 { 2164 /* yeah yeah, this is ugly */ 2165 typedef struct { 2166 struct ioc_toc_header header; 2167 struct cd_toc_entry entry; 2168 } data_t; 2169 2170 data_t *data; 2171 struct ioc_read_toc_single_entry *te = 2172 (struct ioc_read_toc_single_entry *) addr; 2173 struct ioc_toc_header *th; 2174 u_int32_t track; 2175 2176 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 2177 ("trying to do CDIOREADTOCENTRY\n")); 2178 2179 data = malloc(sizeof(data_t), M_TEMP, M_WAITOK); 2180 2181 if (te->address_format != CD_MSF_FORMAT 2182 && te->address_format != CD_LBA_FORMAT) { 2183 printf("error in readtocentry, " 2184 " returning EINVAL\n"); 2185 free(data, M_TEMP); 2186 error = EINVAL; 2187 break; 2188 } 2189 2190 th = &data->header; 2191 error = cdreadtoc(periph, 0, 0, 2192 (struct cd_toc_entry *)th, 2193 sizeof (*th)); 2194 if (error) { 2195 free(data, M_TEMP); 2196 break; 2197 } 2198 2199 if (softc->quirks & CD_Q_BCD_TRACKS) { 2200 /* we are going to have to convert the BCD 2201 * encoding on the cd to what is expected 2202 */ 2203 th->starting_track = 2204 bcd2bin(th->starting_track); 2205 th->ending_track = bcd2bin(th->ending_track); 2206 } 2207 track = te->track; 2208 if (track == 0) 2209 track = th->starting_track; 2210 else if (track == LEADOUT) 2211 /* OK */; 2212 else if (track < th->starting_track || 2213 track > th->ending_track + 1) { 2214 printf("error in readtocentry, " 2215 " returning EINVAL\n"); 2216 free(data, M_TEMP); 2217 error = EINVAL; 2218 break; 2219 } 2220 2221 error = cdreadtoc(periph, te->address_format, track, 2222 (struct cd_toc_entry *)data, 2223 sizeof(data_t)); 2224 if (error) { 2225 free(data, M_TEMP); 2226 break; 2227 } 2228 2229 if (softc->quirks & CD_Q_BCD_TRACKS) 2230 data->entry.track = bcd2bin(data->entry.track); 2231 bcopy(&data->entry, &te->entry, 2232 sizeof(struct cd_toc_entry)); 2233 free(data, M_TEMP); 2234 } 2235 break; 2236 case CDIOCSETPATCH: 2237 { 2238 struct ioc_patch *arg = (struct ioc_patch *) addr; 2239 struct cd_mode_data *data; 2240 2241 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 2242 ("trying to do CDIOCSETPATCH\n")); 2243 2244 data = malloc(sizeof(struct cd_mode_data), M_TEMP, 2245 M_WAITOK); 2246 error = cdgetmode(periph, data, AUDIO_PAGE); 2247 if (error) { 2248 free(data, M_TEMP); 2249 break; 2250 } 2251 data->page.audio.port[LEFT_PORT].channels = 2252 arg->patch[0]; 2253 data->page.audio.port[RIGHT_PORT].channels = 2254 arg->patch[1]; 2255 data->page.audio.port[2].channels = arg->patch[2]; 2256 data->page.audio.port[3].channels = arg->patch[3]; 2257 error = cdsetmode(periph, data); 2258 free(data, M_TEMP); 2259 } 2260 break; 2261 case CDIOCGETVOL: 2262 { 2263 struct ioc_vol *arg = (struct ioc_vol *) addr; 2264 struct cd_mode_data *data; 2265 2266 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 2267 ("trying to do CDIOCGETVOL\n")); 2268 2269 data = malloc(sizeof(struct cd_mode_data), M_TEMP, 2270 M_WAITOK); 2271 error = cdgetmode(periph, data, AUDIO_PAGE); 2272 if (error) { 2273 free(data, M_TEMP); 2274 break; 2275 } 2276 arg->vol[LEFT_PORT] = 2277 data->page.audio.port[LEFT_PORT].volume; 2278 arg->vol[RIGHT_PORT] = 2279 data->page.audio.port[RIGHT_PORT].volume; 2280 arg->vol[2] = data->page.audio.port[2].volume; 2281 arg->vol[3] = data->page.audio.port[3].volume; 2282 free(data, M_TEMP); 2283 } 2284 break; 2285 case CDIOCSETVOL: 2286 { 2287 struct ioc_vol *arg = (struct ioc_vol *) addr; 2288 struct cd_mode_data *data; 2289 2290 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 2291 ("trying to do CDIOCSETVOL\n")); 2292 2293 data = malloc(sizeof(struct cd_mode_data), M_TEMP, 2294 M_WAITOK); 2295 error = cdgetmode(periph, data, AUDIO_PAGE); 2296 if (error) { 2297 free(data, M_TEMP); 2298 break; 2299 } 2300 data->page.audio.port[LEFT_PORT].channels = CHANNEL_0; 2301 data->page.audio.port[LEFT_PORT].volume = 2302 arg->vol[LEFT_PORT]; 2303 data->page.audio.port[RIGHT_PORT].channels = CHANNEL_1; 2304 data->page.audio.port[RIGHT_PORT].volume = 2305 arg->vol[RIGHT_PORT]; 2306 data->page.audio.port[2].volume = arg->vol[2]; 2307 data->page.audio.port[3].volume = arg->vol[3]; 2308 error = cdsetmode(periph, data); 2309 free(data, M_TEMP); 2310 } 2311 break; 2312 case CDIOCSETMONO: 2313 { 2314 struct cd_mode_data *data; 2315 2316 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 2317 ("trying to do CDIOCSETMONO\n")); 2318 2319 data = malloc(sizeof(struct cd_mode_data), 2320 M_TEMP, M_WAITOK); 2321 error = cdgetmode(periph, data, AUDIO_PAGE); 2322 if (error) { 2323 free(data, M_TEMP); 2324 break; 2325 } 2326 data->page.audio.port[LEFT_PORT].channels = 2327 LEFT_CHANNEL | RIGHT_CHANNEL; 2328 data->page.audio.port[RIGHT_PORT].channels = 2329 LEFT_CHANNEL | RIGHT_CHANNEL; 2330 data->page.audio.port[2].channels = 0; 2331 data->page.audio.port[3].channels = 0; 2332 error = cdsetmode(periph, data); 2333 free(data, M_TEMP); 2334 } 2335 break; 2336 case CDIOCSETSTEREO: 2337 { 2338 struct cd_mode_data *data; 2339 2340 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 2341 ("trying to do CDIOCSETSTEREO\n")); 2342 2343 data = malloc(sizeof(struct cd_mode_data), M_TEMP, 2344 M_WAITOK); 2345 error = cdgetmode(periph, data, AUDIO_PAGE); 2346 if (error) { 2347 free(data, M_TEMP); 2348 break; 2349 } 2350 data->page.audio.port[LEFT_PORT].channels = 2351 LEFT_CHANNEL; 2352 data->page.audio.port[RIGHT_PORT].channels = 2353 RIGHT_CHANNEL; 2354 data->page.audio.port[2].channels = 0; 2355 data->page.audio.port[3].channels = 0; 2356 error = cdsetmode(periph, data); 2357 free(data, M_TEMP); 2358 } 2359 break; 2360 case CDIOCSETMUTE: 2361 { 2362 struct cd_mode_data *data; 2363 2364 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 2365 ("trying to do CDIOCSETMUTE\n")); 2366 2367 data = malloc(sizeof(struct cd_mode_data), M_TEMP, 2368 M_WAITOK); 2369 error = cdgetmode(periph, data, AUDIO_PAGE); 2370 if (error) { 2371 free(data, M_TEMP); 2372 break; 2373 } 2374 data->page.audio.port[LEFT_PORT].channels = 0; 2375 data->page.audio.port[RIGHT_PORT].channels = 0; 2376 data->page.audio.port[2].channels = 0; 2377 data->page.audio.port[3].channels = 0; 2378 error = cdsetmode(periph, data); 2379 free(data, M_TEMP); 2380 } 2381 break; 2382 case CDIOCSETLEFT: 2383 { 2384 struct cd_mode_data *data; 2385 2386 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 2387 ("trying to do CDIOCSETLEFT\n")); 2388 2389 data = malloc(sizeof(struct cd_mode_data), M_TEMP, 2390 M_WAITOK); 2391 error = cdgetmode(periph, data, AUDIO_PAGE); 2392 if (error) { 2393 free(data, M_TEMP); 2394 break; 2395 } 2396 data->page.audio.port[LEFT_PORT].channels = 2397 LEFT_CHANNEL; 2398 data->page.audio.port[RIGHT_PORT].channels = 2399 LEFT_CHANNEL; 2400 data->page.audio.port[2].channels = 0; 2401 data->page.audio.port[3].channels = 0; 2402 error = cdsetmode(periph, data); 2403 free(data, M_TEMP); 2404 } 2405 break; 2406 case CDIOCSETRIGHT: 2407 { 2408 struct cd_mode_data *data; 2409 2410 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 2411 ("trying to do CDIOCSETRIGHT\n")); 2412 2413 data = malloc(sizeof(struct cd_mode_data), M_TEMP, 2414 M_WAITOK); 2415 error = cdgetmode(periph, data, AUDIO_PAGE); 2416 if (error) { 2417 free(data, M_TEMP); 2418 break; 2419 } 2420 data->page.audio.port[LEFT_PORT].channels = 2421 RIGHT_CHANNEL; 2422 data->page.audio.port[RIGHT_PORT].channels = 2423 RIGHT_CHANNEL; 2424 data->page.audio.port[2].channels = 0; 2425 data->page.audio.port[3].channels = 0; 2426 error = cdsetmode(periph, data); 2427 free(data, M_TEMP); 2428 } 2429 break; 2430 case CDIOCRESUME: 2431 error = cdpause(periph, 1); 2432 break; 2433 case CDIOCPAUSE: 2434 error = cdpause(periph, 0); 2435 break; 2436 case CDIOCSTART: 2437 error = cdstartunit(periph); 2438 break; 2439 case CDIOCSTOP: 2440 error = cdstopunit(periph, 0); 2441 break; 2442 case CDIOCEJECT: 2443 error = cdstopunit(periph, 1); 2444 break; 2445 case CDIOCALLOW: 2446 cdprevent(periph, PR_ALLOW); 2447 break; 2448 case CDIOCPREVENT: 2449 cdprevent(periph, PR_PREVENT); 2450 break; 2451 case CDIOCSETDEBUG: 2452 /* sc_link->flags |= (SDEV_DB1 | SDEV_DB2); */ 2453 error = ENOTTY; 2454 break; 2455 case CDIOCCLRDEBUG: 2456 /* sc_link->flags &= ~(SDEV_DB1 | SDEV_DB2); */ 2457 error = ENOTTY; 2458 break; 2459 case CDIOCRESET: 2460 /* return (cd_reset(periph)); */ 2461 error = ENOTTY; 2462 break; 2463 default: 2464 if (cmd == DIOCSBAD) { 2465 error = EINVAL; /* XXX */ 2466 break; 2467 } 2468 2469 /* 2470 * Check to see whether we've got a disk-type ioctl. If we 2471 * don't, dsioctl will pass back an error code of ENOIOCTL. 2472 */ 2473 error = dsioctl("cd", dev, cmd, addr, flag, &softc->cd_slices, 2474 cdstrategy1, (ds_setgeom_t *)NULL); 2475 2476 if (error != ENOIOCTL) 2477 break; 2478 2479 error = cam_periph_ioctl(periph, cmd, addr, cderror); 2480 break; 2481 } 2482 2483 cam_periph_unlock(periph); 2484 2485 CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("leaving cdioctl\n")); 2486 2487 return (error); 2488} 2489 2490static void 2491cdprevent(struct cam_periph *periph, int action) 2492{ 2493 union ccb *ccb; 2494 struct cd_softc *softc; 2495 int error; 2496 2497 CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdprevent\n")); 2498 2499 softc = (struct cd_softc *)periph->softc; 2500 2501 if (((action == PR_ALLOW) 2502 && (softc->flags & CD_FLAG_DISC_LOCKED) == 0) 2503 || ((action == PR_PREVENT) 2504 && (softc->flags & CD_FLAG_DISC_LOCKED) != 0)) { 2505 return; 2506 } 2507 2508 ccb = cdgetccb(periph, /* priority */ 1); 2509 2510 scsi_prevent(&ccb->csio, 2511 /*retries*/ 1, 2512 cddone, 2513 MSG_SIMPLE_Q_TAG, 2514 action, 2515 SSD_FULL_SIZE, 2516 /* timeout */60000); 2517 2518 error = cdrunccb(ccb, cderror, /*cam_flags*/0, 2519 /*sense_flags*/SF_RETRY_UA|SF_NO_PRINT|SF_RETRY_SELTO); 2520 2521 xpt_release_ccb(ccb); 2522 2523 if (error == 0) { 2524 if (action == PR_ALLOW) 2525 softc->flags &= ~CD_FLAG_DISC_LOCKED; 2526 else 2527 softc->flags |= CD_FLAG_DISC_LOCKED; 2528 } 2529} 2530 2531static int 2532cdsize(dev_t dev, u_int32_t *size) 2533{ 2534 struct cam_periph *periph; 2535 struct cd_softc *softc; 2536 union ccb *ccb; 2537 struct scsi_read_capacity_data *rcap_buf; 2538 int error; 2539 2540 periph = cam_extend_get(cdperiphs, dkunit(dev)); 2541 2542 if (periph == NULL) 2543 return (ENXIO); 2544 2545 CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdsize\n")); 2546 2547 softc = (struct cd_softc *)periph->softc; 2548 2549 ccb = cdgetccb(periph, /* priority */ 1); 2550 2551 rcap_buf = malloc(sizeof(struct scsi_read_capacity_data), 2552 M_TEMP, M_WAITOK); 2553 2554 scsi_read_capacity(&ccb->csio, 2555 /*retries*/ 1, 2556 cddone, 2557 MSG_SIMPLE_Q_TAG, 2558 rcap_buf, 2559 SSD_FULL_SIZE, 2560 /* timeout */20000); 2561 2562 error = cdrunccb(ccb, cderror, /*cam_flags*/0, 2563 /*sense_flags*/SF_RETRY_UA|SF_NO_PRINT|SF_RETRY_SELTO); 2564 2565 xpt_release_ccb(ccb); 2566 2567 softc->params.disksize = scsi_4btoul(rcap_buf->addr) + 1; 2568 softc->params.blksize = scsi_4btoul(rcap_buf->length); 2569 2570 free(rcap_buf, M_TEMP); 2571 *size = softc->params.disksize; 2572 2573 return (error); 2574 2575} 2576 2577static int 2578cderror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) 2579{ 2580 struct cd_softc *softc; 2581 struct cam_periph *periph; 2582 2583 periph = xpt_path_periph(ccb->ccb_h.path); 2584 softc = (struct cd_softc *)periph->softc; 2585 2586 /* 2587 * XXX 2588 * Until we have a better way of doing pack validation, 2589 * don't treat UAs as errors. 2590 */ 2591 sense_flags |= SF_RETRY_UA; 2592 return (cam_periph_error(ccb, cam_flags, sense_flags, 2593 &softc->saved_ccb)); 2594} 2595 2596/* 2597 * Read table of contents 2598 */ 2599static int 2600cdreadtoc(struct cam_periph *periph, u_int32_t mode, u_int32_t start, 2601 struct cd_toc_entry *data, u_int32_t len) 2602{ 2603 struct scsi_read_toc *scsi_cmd; 2604 u_int32_t ntoc; 2605 struct ccb_scsiio *csio; 2606 union ccb *ccb; 2607 int error; 2608 2609 ntoc = len; 2610 error = 0; 2611 2612 ccb = cdgetccb(periph, /* priority */ 1); 2613 2614 csio = &ccb->csio; 2615 2616 cam_fill_csio(csio, 2617 /* retries */ 1, 2618 /* cbfcnp */ cddone, 2619 /* flags */ CAM_DIR_IN, 2620 /* tag_action */ MSG_SIMPLE_Q_TAG, 2621 /* data_ptr */ (u_int8_t *)data, 2622 /* dxfer_len */ len, 2623 /* sense_len */ SSD_FULL_SIZE, 2624 sizeof(struct scsi_read_toc), 2625 /* timeout */ 50000); 2626 2627 scsi_cmd = (struct scsi_read_toc *)&csio->cdb_io.cdb_bytes; 2628 bzero (scsi_cmd, sizeof(*scsi_cmd)); 2629 2630 if (mode == CD_MSF_FORMAT) 2631 scsi_cmd->byte2 |= CD_MSF; 2632 scsi_cmd->from_track = start; 2633 /* scsi_ulto2b(ntoc, (u_int8_t *)scsi_cmd->data_len); */ 2634 scsi_cmd->data_len[0] = (ntoc) >> 8; 2635 scsi_cmd->data_len[1] = (ntoc) & 0xff; 2636 2637 scsi_cmd->op_code = READ_TOC; 2638 2639 error = cdrunccb(ccb, cderror, /*cam_flags*/0, 2640 /*sense_flags*/SF_RETRY_UA|SF_RETRY_SELTO); 2641 2642 xpt_release_ccb(ccb); 2643 2644 return(error); 2645} 2646 2647static int 2648cdreadsubchannel(struct cam_periph *periph, u_int32_t mode, 2649 u_int32_t format, int track, 2650 struct cd_sub_channel_info *data, u_int32_t len) 2651{ 2652 struct scsi_read_subchannel *scsi_cmd; 2653 struct ccb_scsiio *csio; 2654 union ccb *ccb; 2655 int error; 2656 2657 error = 0; 2658 2659 ccb = cdgetccb(periph, /* priority */ 1); 2660 2661 csio = &ccb->csio; 2662 2663 cam_fill_csio(csio, 2664 /* retries */ 1, 2665 /* cbfcnp */ cddone, 2666 /* flags */ CAM_DIR_IN, 2667 /* tag_action */ MSG_SIMPLE_Q_TAG, 2668 /* data_ptr */ (u_int8_t *)data, 2669 /* dxfer_len */ len, 2670 /* sense_len */ SSD_FULL_SIZE, 2671 sizeof(struct scsi_read_subchannel), 2672 /* timeout */ 50000); 2673 2674 scsi_cmd = (struct scsi_read_subchannel *)&csio->cdb_io.cdb_bytes; 2675 bzero (scsi_cmd, sizeof(*scsi_cmd)); 2676 2677 scsi_cmd->op_code = READ_SUBCHANNEL; 2678 if (mode == CD_MSF_FORMAT) 2679 scsi_cmd->byte1 |= CD_MSF; 2680 scsi_cmd->byte2 = SRS_SUBQ; 2681 scsi_cmd->subchan_format = format; 2682 scsi_cmd->track = track; 2683 scsi_ulto2b(len, (u_int8_t *)scsi_cmd->data_len); 2684 scsi_cmd->control = 0; 2685 2686 error = cdrunccb(ccb, cderror, /*cam_flags*/0, 2687 /*sense_flags*/SF_RETRY_UA|SF_RETRY_SELTO); 2688 2689 xpt_release_ccb(ccb); 2690 2691 return(error); 2692} 2693 2694 2695static int 2696cdgetmode(struct cam_periph *periph, struct cd_mode_data *data, u_int32_t page) 2697{ 2698 struct scsi_mode_sense_6 *scsi_cmd; 2699 struct ccb_scsiio *csio; 2700 union ccb *ccb; 2701 int error; 2702 2703 ccb = cdgetccb(periph, /* priority */ 1); 2704 2705 csio = &ccb->csio; 2706 2707 bzero(data, sizeof(*data)); 2708 cam_fill_csio(csio, 2709 /* retries */ 1, 2710 /* cbfcnp */ cddone, 2711 /* flags */ CAM_DIR_IN, 2712 /* tag_action */ MSG_SIMPLE_Q_TAG, 2713 /* data_ptr */ (u_int8_t *)data, 2714 /* dxfer_len */ sizeof(*data), 2715 /* sense_len */ SSD_FULL_SIZE, 2716 sizeof(struct scsi_mode_sense_6), 2717 /* timeout */ 50000); 2718 2719 scsi_cmd = (struct scsi_mode_sense_6 *)&csio->cdb_io.cdb_bytes; 2720 bzero (scsi_cmd, sizeof(*scsi_cmd)); 2721 2722 scsi_cmd->page = page; 2723 scsi_cmd->length = sizeof(*data) & 0xff; 2724 scsi_cmd->opcode = MODE_SENSE; 2725 2726 error = cdrunccb(ccb, cderror, /*cam_flags*/0, 2727 /*sense_flags*/SF_RETRY_UA|SF_RETRY_SELTO); 2728 2729 xpt_release_ccb(ccb); 2730 2731 return(error); 2732} 2733 2734static int 2735cdsetmode(struct cam_periph *periph, struct cd_mode_data *data) 2736{ 2737 struct scsi_mode_select_6 *scsi_cmd; 2738 struct ccb_scsiio *csio; 2739 union ccb *ccb; 2740 int error; 2741 2742 ccb = cdgetccb(periph, /* priority */ 1); 2743 2744 csio = &ccb->csio; 2745 2746 error = 0; 2747 2748 cam_fill_csio(csio, 2749 /* retries */ 1, 2750 /* cbfcnp */ cddone, 2751 /* flags */ CAM_DIR_OUT, 2752 /* tag_action */ MSG_SIMPLE_Q_TAG, 2753 /* data_ptr */ (u_int8_t *)data, 2754 /* dxfer_len */ sizeof(*data), 2755 /* sense_len */ SSD_FULL_SIZE, 2756 sizeof(struct scsi_mode_select_6), 2757 /* timeout */ 50000); 2758 2759 scsi_cmd = (struct scsi_mode_select_6 *)&csio->cdb_io.cdb_bytes; 2760 2761 bzero(scsi_cmd, sizeof(*scsi_cmd)); 2762 scsi_cmd->opcode = MODE_SELECT; 2763 scsi_cmd->byte2 |= SMS_PF; 2764 scsi_cmd->length = sizeof(*data) & 0xff; 2765 data->header.data_length = 0; 2766 /* 2767 * SONY drives do not allow a mode select with a medium_type 2768 * value that has just been returned by a mode sense; use a 2769 * medium_type of 0 (Default) instead. 2770 */ 2771 data->header.medium_type = 0; 2772 2773 error = cdrunccb(ccb, cderror, /*cam_flags*/0, 2774 /*sense_flags*/SF_RETRY_UA | SF_RETRY_SELTO); 2775 2776 xpt_release_ccb(ccb); 2777 2778 return(error); 2779} 2780 2781 2782static int 2783cdplay(struct cam_periph *periph, u_int32_t blk, u_int32_t len) 2784{ 2785 struct ccb_scsiio *csio; 2786 union ccb *ccb; 2787 int error; 2788 u_int8_t cdb_len; 2789 2790 error = 0; 2791 ccb = cdgetccb(periph, /* priority */ 1); 2792 csio = &ccb->csio; 2793 /* 2794 * Use the smallest possible command to perform the operation. 2795 */ 2796 if ((len & 0xffff0000) == 0) { 2797 /* 2798 * We can fit in a 10 byte cdb. 2799 */ 2800 struct scsi_play_10 *scsi_cmd; 2801 2802 scsi_cmd = (struct scsi_play_10 *)&csio->cdb_io.cdb_bytes; 2803 bzero (scsi_cmd, sizeof(*scsi_cmd)); 2804 scsi_cmd->op_code = PLAY_10; 2805 scsi_ulto4b(blk, (u_int8_t *)scsi_cmd->blk_addr); 2806 scsi_ulto2b(len, (u_int8_t *)scsi_cmd->xfer_len); 2807 cdb_len = sizeof(*scsi_cmd); 2808 } else { 2809 struct scsi_play_12 *scsi_cmd; 2810 2811 scsi_cmd = (struct scsi_play_12 *)&csio->cdb_io.cdb_bytes; 2812 bzero (scsi_cmd, sizeof(*scsi_cmd)); 2813 scsi_cmd->op_code = PLAY_12; 2814 scsi_ulto4b(blk, (u_int8_t *)scsi_cmd->blk_addr); 2815 scsi_ulto4b(len, (u_int8_t *)scsi_cmd->xfer_len); 2816 cdb_len = sizeof(*scsi_cmd); 2817 } 2818 cam_fill_csio(csio, 2819 /*retries*/2, 2820 cddone, 2821 /*flags*/CAM_DIR_NONE, 2822 MSG_SIMPLE_Q_TAG, 2823 /*dataptr*/NULL, 2824 /*datalen*/0, 2825 /*sense_len*/SSD_FULL_SIZE, 2826 cdb_len, 2827 /*timeout*/50 * 1000); 2828 2829 error = cdrunccb(ccb, cderror, /*cam_flags*/0, 2830 /*sense_flags*/SF_RETRY_UA | SF_RETRY_SELTO); 2831 2832 xpt_release_ccb(ccb); 2833 2834 return(error); 2835} 2836 2837static int 2838cdplaymsf(struct cam_periph *periph, u_int32_t startm, u_int32_t starts, 2839 u_int32_t startf, u_int32_t endm, u_int32_t ends, u_int32_t endf) 2840{ 2841 struct scsi_play_msf *scsi_cmd; 2842 struct ccb_scsiio *csio; 2843 union ccb *ccb; 2844 int error; 2845 2846 error = 0; 2847 2848 ccb = cdgetccb(periph, /* priority */ 1); 2849 2850 csio = &ccb->csio; 2851 2852 cam_fill_csio(csio, 2853 /* retries */ 1, 2854 /* cbfcnp */ cddone, 2855 /* flags */ CAM_DIR_NONE, 2856 /* tag_action */ MSG_SIMPLE_Q_TAG, 2857 /* data_ptr */ NULL, 2858 /* dxfer_len */ 0, 2859 /* sense_len */ SSD_FULL_SIZE, 2860 sizeof(struct scsi_play_msf), 2861 /* timeout */ 50000); 2862 2863 scsi_cmd = (struct scsi_play_msf *)&csio->cdb_io.cdb_bytes; 2864 bzero (scsi_cmd, sizeof(*scsi_cmd)); 2865 2866 scsi_cmd->op_code = PLAY_MSF; 2867 scsi_cmd->start_m = startm; 2868 scsi_cmd->start_s = starts; 2869 scsi_cmd->start_f = startf; 2870 scsi_cmd->end_m = endm; 2871 scsi_cmd->end_s = ends; 2872 scsi_cmd->end_f = endf; 2873 2874 error = cdrunccb(ccb, cderror, /*cam_flags*/0, 2875 /*sense_flags*/SF_RETRY_UA | SF_RETRY_SELTO); 2876 2877 xpt_release_ccb(ccb); 2878 2879 return(error); 2880} 2881 2882 2883static int 2884cdplaytracks(struct cam_periph *periph, u_int32_t strack, u_int32_t sindex, 2885 u_int32_t etrack, u_int32_t eindex) 2886{ 2887 struct scsi_play_track *scsi_cmd; 2888 struct ccb_scsiio *csio; 2889 union ccb *ccb; 2890 int error; 2891 2892 error = 0; 2893 2894 ccb = cdgetccb(periph, /* priority */ 1); 2895 2896 csio = &ccb->csio; 2897 2898 cam_fill_csio(csio, 2899 /* retries */ 1, 2900 /* cbfcnp */ cddone, 2901 /* flags */ CAM_DIR_NONE, 2902 /* tag_action */ MSG_SIMPLE_Q_TAG, 2903 /* data_ptr */ NULL, 2904 /* dxfer_len */ 0, 2905 /* sense_len */ SSD_FULL_SIZE, 2906 sizeof(struct scsi_play_track), 2907 /* timeout */ 50000); 2908 2909 scsi_cmd = (struct scsi_play_track *)&csio->cdb_io.cdb_bytes; 2910 bzero (scsi_cmd, sizeof(*scsi_cmd)); 2911 2912 scsi_cmd->op_code = PLAY_TRACK; 2913 scsi_cmd->start_track = strack; 2914 scsi_cmd->start_index = sindex; 2915 scsi_cmd->end_track = etrack; 2916 scsi_cmd->end_index = eindex; 2917 2918 error = cdrunccb(ccb, cderror, /*cam_flags*/0, 2919 /*sense_flags*/SF_RETRY_UA | SF_RETRY_SELTO); 2920 2921 xpt_release_ccb(ccb); 2922 2923 return(error); 2924} 2925 2926static int 2927cdpause(struct cam_periph *periph, u_int32_t go) 2928{ 2929 struct scsi_pause *scsi_cmd; 2930 struct ccb_scsiio *csio; 2931 union ccb *ccb; 2932 int error; 2933 2934 error = 0; 2935 2936 ccb = cdgetccb(periph, /* priority */ 1); 2937 2938 csio = &ccb->csio; 2939 2940 cam_fill_csio(csio, 2941 /* retries */ 1, 2942 /* cbfcnp */ cddone, 2943 /* flags */ CAM_DIR_NONE, 2944 /* tag_action */ MSG_SIMPLE_Q_TAG, 2945 /* data_ptr */ NULL, 2946 /* dxfer_len */ 0, 2947 /* sense_len */ SSD_FULL_SIZE, 2948 sizeof(struct scsi_pause), 2949 /* timeout */ 50000); 2950 2951 scsi_cmd = (struct scsi_pause *)&csio->cdb_io.cdb_bytes; 2952 bzero (scsi_cmd, sizeof(*scsi_cmd)); 2953 2954 scsi_cmd->op_code = PAUSE; 2955 scsi_cmd->resume = go; 2956 2957 error = cdrunccb(ccb, cderror, /*cam_flags*/0, 2958 /*sense_flags*/SF_RETRY_UA |SF_RETRY_SELTO); 2959 2960 xpt_release_ccb(ccb); 2961 2962 return(error); 2963} 2964 2965static int 2966cdstartunit(struct cam_periph *periph) 2967{ 2968 union ccb *ccb; 2969 int error; 2970 2971 error = 0; 2972 2973 ccb = cdgetccb(periph, /* priority */ 1); 2974 2975 scsi_start_stop(&ccb->csio, 2976 /* retries */ 1, 2977 /* cbfcnp */ cddone, 2978 /* tag_action */ MSG_SIMPLE_Q_TAG, 2979 /* start */ TRUE, 2980 /* load_eject */ TRUE, 2981 /* immediate */ FALSE, 2982 /* sense_len */ SSD_FULL_SIZE, 2983 /* timeout */ 50000); 2984 2985 error = cdrunccb(ccb, cderror, /*cam_flags*/0, 2986 /*sense_flags*/SF_RETRY_UA | SF_RETRY_SELTO); 2987 2988 xpt_release_ccb(ccb); 2989 2990 return(error); 2991} 2992 2993static int 2994cdstopunit(struct cam_periph *periph, u_int32_t eject) 2995{ 2996 union ccb *ccb; 2997 int error; 2998 2999 error = 0; 3000 3001 ccb = cdgetccb(periph, /* priority */ 1); 3002 3003 scsi_start_stop(&ccb->csio, 3004 /* retries */ 1, 3005 /* cbfcnp */ cddone, 3006 /* tag_action */ MSG_SIMPLE_Q_TAG, 3007 /* start */ FALSE, 3008 /* load_eject */ eject, 3009 /* immediate */ FALSE, 3010 /* sense_len */ SSD_FULL_SIZE, 3011 /* timeout */ 50000); 3012 3013 error = cdrunccb(ccb, cderror, /*cam_flags*/0, 3014 /*sense_flags*/SF_RETRY_UA | SF_RETRY_SELTO); 3015 3016 xpt_release_ccb(ccb); 3017 3018 return(error); 3019} 3020