Annotation of sys/scsi/cd.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: cd.c,v 1.132 2007/06/20 18:15:47 deraadt Exp $ */
! 2: /* $NetBSD: cd.c,v 1.100 1997/04/02 02:29:30 mycroft Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1994, 1995, 1997 Charles M. Hannum. All rights reserved.
! 6: *
! 7: * Redistribution and use in source and binary forms, with or without
! 8: * modification, are permitted provided that the following conditions
! 9: * are met:
! 10: * 1. Redistributions of source code must retain the above copyright
! 11: * notice, this list of conditions and the following disclaimer.
! 12: * 2. Redistributions in binary form must reproduce the above copyright
! 13: * notice, this list of conditions and the following disclaimer in the
! 14: * documentation and/or other materials provided with the distribution.
! 15: * 3. All advertising materials mentioning features or use of this software
! 16: * must display the following acknowledgement:
! 17: * This product includes software developed by Charles M. Hannum.
! 18: * 4. The name of the author may not be used to endorse or promote products
! 19: * derived from this software without specific prior written permission.
! 20: *
! 21: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 22: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 23: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 24: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 25: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 26: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 27: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 28: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 29: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
! 30: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 31: */
! 32:
! 33: /*
! 34: * Originally written by Julian Elischer (julian@tfs.com)
! 35: * for TRW Financial Systems for use under the MACH(2.5) operating system.
! 36: *
! 37: * TRW Financial Systems, in accordance with their agreement with Carnegie
! 38: * Mellon University, makes this software available to CMU to distribute
! 39: * or use in any manner that they see fit as long as this message is kept with
! 40: * the software. For this reason TFS also grants any other persons or
! 41: * organisations permission to use or modify this software.
! 42: *
! 43: * TFS supplies this software to be publicly redistributed
! 44: * on the understanding that TFS is not responsible for the correct
! 45: * functioning of this software in any circumstances.
! 46: *
! 47: * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
! 48: */
! 49:
! 50: #include <sys/types.h>
! 51: #include <sys/param.h>
! 52: #include <sys/systm.h>
! 53: #include <sys/timeout.h>
! 54: #include <sys/file.h>
! 55: #include <sys/stat.h>
! 56: #include <sys/ioctl.h>
! 57: #include <sys/mtio.h>
! 58: #include <sys/buf.h>
! 59: #include <sys/uio.h>
! 60: #include <sys/malloc.h>
! 61: #include <sys/errno.h>
! 62: #include <sys/device.h>
! 63: #include <sys/disklabel.h>
! 64: #include <sys/disk.h>
! 65: #include <sys/cdio.h>
! 66: #include <sys/proc.h>
! 67: #include <sys/conf.h>
! 68: #include <sys/scsiio.h>
! 69: #include <sys/vnode.h>
! 70:
! 71: #include <scsi/scsi_all.h>
! 72: #include <scsi/cd.h>
! 73: #include <scsi/scsi_disk.h> /* rw_big and start_stop come from there */
! 74: #include <scsi/scsiconf.h>
! 75:
! 76:
! 77: #include <ufs/ffs/fs.h> /* for BBSIZE and SBSIZE */
! 78:
! 79: #define CDOUTSTANDING 4
! 80:
! 81: #define MAXTRACK 99
! 82: #define CD_BLOCK_OFFSET 150
! 83: #define CD_FRAMES 75
! 84: #define CD_SECS 60
! 85:
! 86: struct cd_toc {
! 87: struct ioc_toc_header header;
! 88: struct cd_toc_entry entries[MAXTRACK+1]; /* One extra for the */
! 89: /* leadout */
! 90: };
! 91:
! 92: int cdmatch(struct device *, void *, void *);
! 93: void cdattach(struct device *, struct device *, void *);
! 94: int cdactivate(struct device *, enum devact);
! 95: int cddetach(struct device *, int);
! 96:
! 97: void cdstart(void *);
! 98: void cdrestart(void *);
! 99: void cdminphys(struct buf *);
! 100: void cdgetdisklabel(dev_t, struct cd_softc *, struct disklabel *, int);
! 101: void cddone(struct scsi_xfer *);
! 102: u_long cd_size(struct cd_softc *, int);
! 103: void cd_kill_buffers(struct cd_softc *);
! 104: void lba2msf(u_long, u_char *, u_char *, u_char *);
! 105: u_long msf2lba(u_char, u_char, u_char);
! 106: int cd_setchan(struct cd_softc *, int, int, int, int, int);
! 107: int cd_getvol(struct cd_softc *cd, struct ioc_vol *, int);
! 108: int cd_setvol(struct cd_softc *, const struct ioc_vol *, int);
! 109: int cd_load_unload(struct cd_softc *, int, int);
! 110: int cd_set_pa_immed(struct cd_softc *, int);
! 111: int cd_play(struct cd_softc *, int, int);
! 112: int cd_play_tracks(struct cd_softc *, int, int, int, int);
! 113: int cd_play_msf(struct cd_softc *, int, int, int, int, int, int);
! 114: int cd_pause(struct cd_softc *, int);
! 115: int cd_reset(struct cd_softc *);
! 116: int cd_read_subchannel(struct cd_softc *, int, int, int,
! 117: struct cd_sub_channel_info *, int );
! 118: int cd_read_toc(struct cd_softc *, int, int, void *, int, int);
! 119: int cd_get_parms(struct cd_softc *, int);
! 120: int cd_load_toc(struct cd_softc *, struct cd_toc *, int);
! 121: int cd_interpret_sense(struct scsi_xfer *);
! 122:
! 123: int dvd_auth(struct cd_softc *, union dvd_authinfo *);
! 124: int dvd_read_physical(struct cd_softc *, union dvd_struct *);
! 125: int dvd_read_copyright(struct cd_softc *, union dvd_struct *);
! 126: int dvd_read_disckey(struct cd_softc *, union dvd_struct *);
! 127: int dvd_read_bca(struct cd_softc *, union dvd_struct *);
! 128: int dvd_read_manufact(struct cd_softc *, union dvd_struct *);
! 129: int dvd_read_struct(struct cd_softc *, union dvd_struct *);
! 130:
! 131: void cd_powerhook(int why, void *arg);
! 132:
! 133: struct cfattach cd_ca = {
! 134: sizeof(struct cd_softc), cdmatch, cdattach,
! 135: cddetach, cdactivate
! 136: };
! 137:
! 138: struct cfdriver cd_cd = {
! 139: NULL, "cd", DV_DISK
! 140: };
! 141:
! 142: struct dkdriver cddkdriver = { cdstrategy };
! 143:
! 144: struct scsi_device cd_switch = {
! 145: cd_interpret_sense,
! 146: cdstart, /* we have a queue, which is started by this */
! 147: NULL, /* we do not have an async handler */
! 148: cddone, /* deal with stats at interrupt time */
! 149: };
! 150:
! 151: const struct scsi_inquiry_pattern cd_patterns[] = {
! 152: {T_CDROM, T_REMOV,
! 153: "", "", ""},
! 154: {T_WORM, T_REMOV,
! 155: "", "", ""},
! 156: {T_DIRECT, T_REMOV,
! 157: "NEC CD-ROM DRIVE:260", "", ""},
! 158: #if 0
! 159: {T_CDROM, T_REMOV, /* more luns */
! 160: "PIONEER ", "CD-ROM DRM-600 ", ""},
! 161: #endif
! 162: };
! 163:
! 164: #define cdlock(softc) disk_lock(&(softc)->sc_dk)
! 165: #define cdunlock(softc) disk_unlock(&(softc)->sc_dk)
! 166: #define cdlookup(unit) (struct cd_softc *)device_lookup(&cd_cd, (unit))
! 167:
! 168: int
! 169: cdmatch(struct device *parent, void *match, void *aux)
! 170: {
! 171: struct scsi_attach_args *sa = aux;
! 172: int priority;
! 173:
! 174: scsi_inqmatch(sa->sa_inqbuf, cd_patterns,
! 175: sizeof(cd_patterns)/sizeof(cd_patterns[0]), sizeof(cd_patterns[0]),
! 176: &priority);
! 177: return (priority);
! 178: }
! 179:
! 180: /*
! 181: * The routine called by the low level scsi routine when it discovers
! 182: * A device suitable for this driver
! 183: */
! 184: void
! 185: cdattach(struct device *parent, struct device *self, void *aux)
! 186: {
! 187: struct scsi_attach_args *sa = aux;
! 188: struct scsi_link *sc_link = sa->sa_sc_link;
! 189: struct cd_softc *cd = (struct cd_softc *)self;
! 190:
! 191: SC_DEBUG(sc_link, SDEV_DB2, ("cdattach:\n"));
! 192:
! 193: /*
! 194: * Store information needed to contact our base driver
! 195: */
! 196: cd->sc_link = sc_link;
! 197: sc_link->device = &cd_switch;
! 198: sc_link->device_softc = cd;
! 199: if (sc_link->openings > CDOUTSTANDING)
! 200: sc_link->openings = CDOUTSTANDING;
! 201:
! 202: /*
! 203: * Initialize and attach the disk structure.
! 204: */
! 205: cd->sc_dk.dk_driver = &cddkdriver;
! 206: cd->sc_dk.dk_name = cd->sc_dev.dv_xname;
! 207: disk_attach(&cd->sc_dk);
! 208:
! 209: /*
! 210: * Note if this device is ancient. This is used in cdminphys().
! 211: */
! 212: if (!(sc_link->flags & SDEV_ATAPI) &&
! 213: SCSISPC(sa->sa_inqbuf->version) == 0)
! 214: cd->flags |= CDF_ANCIENT;
! 215:
! 216: printf("\n");
! 217:
! 218: timeout_set(&cd->sc_timeout, cdrestart, cd);
! 219:
! 220: if ((cd->sc_cdpwrhook = powerhook_establish(cd_powerhook, cd)) == NULL)
! 221: printf("%s: WARNING: unable to establish power hook\n",
! 222: cd->sc_dev.dv_xname);
! 223: }
! 224:
! 225:
! 226: int
! 227: cdactivate(struct device *self, enum devact act)
! 228: {
! 229: int rv = 0;
! 230:
! 231: switch (act) {
! 232: case DVACT_ACTIVATE:
! 233: break;
! 234:
! 235: case DVACT_DEACTIVATE:
! 236: /*
! 237: * Nothing to do; we key off the device's DVF_ACTIVATE.
! 238: */
! 239: break;
! 240: }
! 241: return (rv);
! 242: }
! 243:
! 244:
! 245: int
! 246: cddetach(struct device *self, int flags)
! 247: {
! 248: struct cd_softc *cd = (struct cd_softc *)self;
! 249: int bmaj, cmaj, mn;
! 250:
! 251: cd_kill_buffers(cd);
! 252:
! 253: /* Locate the lowest minor number to be detached. */
! 254: mn = DISKMINOR(self->dv_unit, 0);
! 255:
! 256: for (bmaj = 0; bmaj < nblkdev; bmaj++)
! 257: if (bdevsw[bmaj].d_open == cdopen)
! 258: vdevgone(bmaj, mn, mn + MAXPARTITIONS - 1, VBLK);
! 259: for (cmaj = 0; cmaj < nchrdev; cmaj++)
! 260: if (cdevsw[cmaj].d_open == cdopen)
! 261: vdevgone(cmaj, mn, mn + MAXPARTITIONS - 1, VCHR);
! 262:
! 263: /* Get rid of the power hook. */
! 264: if (cd->sc_cdpwrhook != NULL)
! 265: powerhook_disestablish(cd->sc_cdpwrhook);
! 266:
! 267: /* Detach disk. */
! 268: disk_detach(&cd->sc_dk);
! 269:
! 270: return (0);
! 271: }
! 272:
! 273: /*
! 274: * Open the device. Make sure the partition info is as up-to-date as can be.
! 275: */
! 276: int
! 277: cdopen(dev_t dev, int flag, int fmt, struct proc *p)
! 278: {
! 279: struct scsi_link *sc_link;
! 280: struct cd_softc *cd;
! 281: int error = 0, part, rawopen, unit;
! 282:
! 283: unit = DISKUNIT(dev);
! 284: part = DISKPART(dev);
! 285:
! 286: rawopen = (part == RAW_PART) && (fmt == S_IFCHR);
! 287:
! 288: cd = cdlookup(unit);
! 289: if (cd == NULL)
! 290: return (ENXIO);
! 291:
! 292: sc_link = cd->sc_link;
! 293: SC_DEBUG(sc_link, SDEV_DB1,
! 294: ("cdopen: dev=0x%x (unit %d (of %d), partition %d)\n", dev, unit,
! 295: cd_cd.cd_ndevs, part));
! 296:
! 297: if ((error = cdlock(cd)) != 0) {
! 298: device_unref(&cd->sc_dev);
! 299: return (error);
! 300: }
! 301:
! 302: if (cd->sc_dk.dk_openmask != 0) {
! 303: /*
! 304: * If any partition is open, but the disk has been invalidated,
! 305: * disallow further opens.
! 306: */
! 307: if ((sc_link->flags & SDEV_MEDIA_LOADED) == 0) {
! 308: if (rawopen)
! 309: goto out;
! 310: error = EIO;
! 311: goto bad;
! 312: }
! 313: } else {
! 314: /*
! 315: * Check that it is still responding and ok. Drive can be in
! 316: * progress of loading media so use increased retries number
! 317: * and don't ignore NOT_READY.
! 318: */
! 319:
! 320: /* Use cd_interpret_sense() now. */
! 321: sc_link->flags |= SDEV_OPEN;
! 322:
! 323: error = scsi_test_unit_ready(sc_link, TEST_READY_RETRIES,
! 324: (rawopen ? SCSI_SILENT : 0) | SCSI_IGNORE_ILLEGAL_REQUEST |
! 325: SCSI_IGNORE_MEDIA_CHANGE);
! 326:
! 327: /* Start the cd spinning if necessary. */
! 328: if (error == EIO)
! 329: error = scsi_start(sc_link, SSS_START,
! 330: SCSI_IGNORE_ILLEGAL_REQUEST |
! 331: SCSI_IGNORE_MEDIA_CHANGE | SCSI_SILENT);
! 332:
! 333: if (error) {
! 334: if (rawopen) {
! 335: error = 0;
! 336: goto out;
! 337: } else
! 338: goto bad;
! 339: }
! 340:
! 341: /* Lock the cd in. */
! 342: error = scsi_prevent(sc_link, PR_PREVENT,
! 343: SCSI_IGNORE_ILLEGAL_REQUEST | SCSI_IGNORE_MEDIA_CHANGE);
! 344: if (error)
! 345: goto bad;
! 346:
! 347: /* Load the physical device parameters. */
! 348: sc_link->flags |= SDEV_MEDIA_LOADED;
! 349: if (cd_get_parms(cd, 0) != 0) {
! 350: sc_link->flags &= ~SDEV_MEDIA_LOADED;
! 351: error = ENXIO;
! 352: goto bad;
! 353: }
! 354: SC_DEBUG(sc_link, SDEV_DB3, ("Params loaded\n"));
! 355:
! 356: /* Fabricate a disk label. */
! 357: cdgetdisklabel(dev, cd, cd->sc_dk.dk_label, 0);
! 358: SC_DEBUG(sc_link, SDEV_DB3, ("Disklabel fabricated\n"));
! 359: }
! 360:
! 361: /* Check that the partition exists. */
! 362: if (part != RAW_PART && (part >= cd->sc_dk.dk_label->d_npartitions ||
! 363: cd->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) {
! 364: error = ENXIO;
! 365: goto bad;
! 366: }
! 367:
! 368: out: /* Insure only one open at a time. */
! 369: switch (fmt) {
! 370: case S_IFCHR:
! 371: cd->sc_dk.dk_copenmask |= (1 << part);
! 372: break;
! 373: case S_IFBLK:
! 374: cd->sc_dk.dk_bopenmask |= (1 << part);
! 375: break;
! 376: }
! 377: cd->sc_dk.dk_openmask = cd->sc_dk.dk_copenmask | cd->sc_dk.dk_bopenmask;
! 378: sc_link->flags |= SDEV_OPEN;
! 379: SC_DEBUG(sc_link, SDEV_DB3, ("open complete\n"));
! 380:
! 381: /* It's OK to fall through because dk_openmask is now non-zero. */
! 382: bad:
! 383: if (cd->sc_dk.dk_openmask == 0) {
! 384: scsi_prevent(sc_link, PR_ALLOW,
! 385: SCSI_IGNORE_ILLEGAL_REQUEST | SCSI_IGNORE_MEDIA_CHANGE);
! 386: sc_link->flags &= ~(SDEV_OPEN | SDEV_MEDIA_LOADED);
! 387: }
! 388:
! 389: cdunlock(cd);
! 390: device_unref(&cd->sc_dev);
! 391: return (error);
! 392: }
! 393:
! 394: /*
! 395: * Close the device. Only called if we are the last occurrence of an open
! 396: * device.
! 397: */
! 398: int
! 399: cdclose(dev_t dev, int flag, int fmt, struct proc *p)
! 400: {
! 401: struct cd_softc *cd;
! 402: int part = DISKPART(dev);
! 403: int error;
! 404:
! 405: cd = cdlookup(DISKUNIT(dev));
! 406: if (cd == NULL)
! 407: return ENXIO;
! 408:
! 409: if ((error = cdlock(cd)) != 0) {
! 410: device_unref(&cd->sc_dev);
! 411: return error;
! 412: }
! 413:
! 414: switch (fmt) {
! 415: case S_IFCHR:
! 416: cd->sc_dk.dk_copenmask &= ~(1 << part);
! 417: break;
! 418: case S_IFBLK:
! 419: cd->sc_dk.dk_bopenmask &= ~(1 << part);
! 420: break;
! 421: }
! 422: cd->sc_dk.dk_openmask = cd->sc_dk.dk_copenmask | cd->sc_dk.dk_bopenmask;
! 423:
! 424: if (cd->sc_dk.dk_openmask == 0) {
! 425: /* XXXX Must wait for I/O to complete! */
! 426:
! 427: scsi_prevent(cd->sc_link, PR_ALLOW,
! 428: SCSI_IGNORE_ILLEGAL_REQUEST | SCSI_IGNORE_NOT_READY);
! 429: cd->sc_link->flags &= ~(SDEV_OPEN | SDEV_MEDIA_LOADED);
! 430:
! 431: if (cd->sc_link->flags & SDEV_EJECTING) {
! 432: scsi_start(cd->sc_link, SSS_STOP|SSS_LOEJ, 0);
! 433:
! 434: cd->sc_link->flags &= ~SDEV_EJECTING;
! 435: }
! 436:
! 437: timeout_del(&cd->sc_timeout);
! 438: }
! 439:
! 440: cdunlock(cd);
! 441:
! 442: device_unref(&cd->sc_dev);
! 443: return 0;
! 444: }
! 445:
! 446: /*
! 447: * Actually translate the requested transfer into one the physical driver can
! 448: * understand. The transfer is described by a buf and will include only one
! 449: * physical transfer.
! 450: */
! 451: void
! 452: cdstrategy(struct buf *bp)
! 453: {
! 454: struct cd_softc *cd;
! 455: int s;
! 456:
! 457: if ((cd = cdlookup(DISKUNIT(bp->b_dev))) == NULL) {
! 458: bp->b_error = ENXIO;
! 459: goto bad;
! 460: }
! 461:
! 462: SC_DEBUG(cd->sc_link, SDEV_DB2, ("cdstrategy: %ld bytes @ blk %d\n",
! 463: bp->b_bcount, bp->b_blkno));
! 464: /*
! 465: * If the device has been made invalid, error out
! 466: * maybe the media changed, or no media loaded
! 467: */
! 468: if ((cd->sc_link->flags & SDEV_MEDIA_LOADED) == 0) {
! 469: bp->b_error = EIO;
! 470: goto bad;
! 471: }
! 472: /*
! 473: * The transfer must be a whole number of blocks.
! 474: */
! 475: if ((bp->b_bcount % cd->sc_dk.dk_label->d_secsize) != 0) {
! 476: bp->b_error = EINVAL;
! 477: goto bad;
! 478: }
! 479: /*
! 480: * If it's a null transfer, return immediately
! 481: */
! 482: if (bp->b_bcount == 0)
! 483: goto done;
! 484:
! 485: /*
! 486: * Do bounds checking, adjust transfer. if error, process.
! 487: * If end of partition, just return.
! 488: */
! 489: if (DISKPART(bp->b_dev) != RAW_PART &&
! 490: bounds_check_with_label(bp, cd->sc_dk.dk_label,
! 491: (cd->flags & (CDF_WLABEL|CDF_LABELLING)) != 0) <= 0)
! 492: goto done;
! 493:
! 494: s = splbio();
! 495:
! 496: /*
! 497: * Place it in the queue of disk activities for this disk
! 498: */
! 499: disksort(&cd->buf_queue, bp);
! 500:
! 501: /*
! 502: * Tell the device to get going on the transfer if it's
! 503: * not doing anything, otherwise just wait for completion
! 504: */
! 505: cdstart(cd);
! 506:
! 507: device_unref(&cd->sc_dev);
! 508: splx(s);
! 509: return;
! 510:
! 511: bad:
! 512: bp->b_flags |= B_ERROR;
! 513: done:
! 514: /*
! 515: * Correctly set the buf to indicate a completed xfer
! 516: */
! 517: bp->b_resid = bp->b_bcount;
! 518: s = splbio();
! 519: biodone(bp);
! 520: splx(s);
! 521: if (cd != NULL)
! 522: device_unref(&cd->sc_dev);
! 523: }
! 524:
! 525: /*
! 526: * cdstart looks to see if there is a buf waiting for the device
! 527: * and that the device is not already busy. If both are true,
! 528: * It deques the buf and creates a scsi command to perform the
! 529: * transfer in the buf. The transfer request will call scsi_done
! 530: * on completion, which will in turn call this routine again
! 531: * so that the next queued transfer is performed.
! 532: * The bufs are queued by the strategy routine (cdstrategy)
! 533: *
! 534: * This routine is also called after other non-queued requests
! 535: * have been made of the scsi driver, to ensure that the queue
! 536: * continues to be drained.
! 537: *
! 538: * must be called at the correct (highish) spl level
! 539: * cdstart() is called at splbio from cdstrategy, cdrestart and scsi_done
! 540: */
! 541: void
! 542: cdstart(void *v)
! 543: {
! 544: struct cd_softc *cd = v;
! 545: struct scsi_link *sc_link = cd->sc_link;
! 546: struct buf *bp = 0;
! 547: struct buf *dp;
! 548: struct scsi_rw_big cmd_big;
! 549: struct scsi_rw cmd_small;
! 550: struct scsi_generic *cmdp;
! 551: int blkno, nblks, cmdlen, error;
! 552: struct partition *p;
! 553:
! 554: splassert(IPL_BIO);
! 555:
! 556: SC_DEBUG(sc_link, SDEV_DB2, ("cdstart\n"));
! 557: /*
! 558: * Check if the device has room for another command
! 559: */
! 560: while (sc_link->openings > 0) {
! 561: /*
! 562: * there is excess capacity, but a special waits
! 563: * It'll need the adapter as soon as we clear out of the
! 564: * way and let it run (user level wait).
! 565: */
! 566: if (sc_link->flags & SDEV_WAITING) {
! 567: sc_link->flags &= ~SDEV_WAITING;
! 568: wakeup((caddr_t)sc_link);
! 569: return;
! 570: }
! 571:
! 572: /*
! 573: * See if there is a buf with work for us to do..
! 574: */
! 575: dp = &cd->buf_queue;
! 576: if ((bp = dp->b_actf) == NULL) /* yes, an assign */
! 577: return;
! 578: dp->b_actf = bp->b_actf;
! 579:
! 580: /*
! 581: * If the deivce has become invalid, abort all the
! 582: * reads and writes until all files have been closed and
! 583: * re-opened
! 584: */
! 585: if ((sc_link->flags & SDEV_MEDIA_LOADED) == 0) {
! 586: bp->b_error = EIO;
! 587: bp->b_flags |= B_ERROR;
! 588: bp->b_resid = bp->b_bcount;
! 589: biodone(bp);
! 590: continue;
! 591: }
! 592:
! 593: /*
! 594: * We have a buf, now we should make a command
! 595: *
! 596: * First, translate the block to absolute and put it in terms
! 597: * of the logical blocksize of the device.
! 598: */
! 599: blkno =
! 600: bp->b_blkno / (cd->sc_dk.dk_label->d_secsize / DEV_BSIZE);
! 601: p = &cd->sc_dk.dk_label->d_partitions[DISKPART(bp->b_dev)];
! 602: blkno += DL_GETPOFFSET(p);
! 603: nblks = howmany(bp->b_bcount, cd->sc_dk.dk_label->d_secsize);
! 604:
! 605: /*
! 606: * Fill out the scsi command. If the transfer will
! 607: * fit in a "small" cdb, use it.
! 608: */
! 609: if (!(sc_link->flags & SDEV_ATAPI) &&
! 610: !(sc_link->quirks & SDEV_ONLYBIG) &&
! 611: ((blkno & 0x1fffff) == blkno) &&
! 612: ((nblks & 0xff) == nblks)) {
! 613: /*
! 614: * We can fit in a small cdb.
! 615: */
! 616: bzero(&cmd_small, sizeof(cmd_small));
! 617: cmd_small.opcode = (bp->b_flags & B_READ) ?
! 618: READ_COMMAND : WRITE_COMMAND;
! 619: _lto3b(blkno, cmd_small.addr);
! 620: cmd_small.length = nblks & 0xff;
! 621: cmdlen = sizeof(cmd_small);
! 622: cmdp = (struct scsi_generic *)&cmd_small;
! 623: } else {
! 624: /*
! 625: * Need a large cdb.
! 626: */
! 627: bzero(&cmd_big, sizeof(cmd_big));
! 628: cmd_big.opcode = (bp->b_flags & B_READ) ?
! 629: READ_BIG : WRITE_BIG;
! 630: _lto4b(blkno, cmd_big.addr);
! 631: _lto2b(nblks, cmd_big.length);
! 632: cmdlen = sizeof(cmd_big);
! 633: cmdp = (struct scsi_generic *)&cmd_big;
! 634: }
! 635:
! 636: /* Instrumentation. */
! 637: disk_busy(&cd->sc_dk);
! 638:
! 639: /*
! 640: * Call the routine that chats with the adapter.
! 641: * Note: we cannot sleep as we may be an interrupt
! 642: */
! 643: error = scsi_scsi_cmd(sc_link, cmdp, cmdlen,
! 644: (u_char *) bp->b_data, bp->b_bcount, CDRETRIES, 30000, bp,
! 645: SCSI_NOSLEEP | ((bp->b_flags & B_READ) ? SCSI_DATA_IN :
! 646: SCSI_DATA_OUT));
! 647: switch (error) {
! 648: case 0:
! 649: timeout_del(&cd->sc_timeout);
! 650: break;
! 651: case EAGAIN:
! 652: /*
! 653: * The device can't start another i/o. Try again later.
! 654: */
! 655: dp->b_actf = bp;
! 656: disk_unbusy(&cd->sc_dk, 0, 0);
! 657: timeout_add(&cd->sc_timeout, 1);
! 658: return;
! 659: default:
! 660: disk_unbusy(&cd->sc_dk, 0, 0);
! 661: printf("%s: not queued, error %d\n",
! 662: cd->sc_dev.dv_xname, error);
! 663: break;
! 664: }
! 665: }
! 666: }
! 667:
! 668: void
! 669: cdrestart(void *v)
! 670: {
! 671: int s;
! 672:
! 673: s = splbio();
! 674: cdstart(v);
! 675: splx(s);
! 676: }
! 677:
! 678: void
! 679: cddone(struct scsi_xfer *xs)
! 680: {
! 681: struct cd_softc *cd = xs->sc_link->device_softc;
! 682:
! 683: if (xs->bp != NULL)
! 684: disk_unbusy(&cd->sc_dk, xs->bp->b_bcount - xs->bp->b_resid,
! 685: (xs->bp->b_flags & B_READ));
! 686: }
! 687:
! 688: void
! 689: cdminphys(struct buf *bp)
! 690: {
! 691: struct cd_softc *cd;
! 692: long max;
! 693:
! 694: cd = cdlookup(DISKUNIT(bp->b_dev));
! 695: if (cd == NULL)
! 696: return;
! 697:
! 698: /*
! 699: * If the device is ancient, we want to make sure that
! 700: * the transfer fits into a 6-byte cdb.
! 701: *
! 702: * XXX Note that the SCSI-I spec says that 256-block transfers
! 703: * are allowed in a 6-byte read/write, and are specified
! 704: * by setting the "length" to 0. However, we're conservative
! 705: * here, allowing only 255-block transfers in case an
! 706: * ancient device gets confused by length == 0. A length of 0
! 707: * in a 10-byte read/write actually means 0 blocks.
! 708: */
! 709: if (cd->flags & CDF_ANCIENT) {
! 710: max = cd->sc_dk.dk_label->d_secsize * 0xff;
! 711:
! 712: if (bp->b_bcount > max)
! 713: bp->b_bcount = max;
! 714: }
! 715:
! 716: (*cd->sc_link->adapter->scsi_minphys)(bp);
! 717:
! 718: device_unref(&cd->sc_dev);
! 719: }
! 720:
! 721: int
! 722: cdread(dev_t dev, struct uio *uio, int ioflag)
! 723: {
! 724:
! 725: return (physio(cdstrategy, NULL, dev, B_READ, cdminphys, uio));
! 726: }
! 727:
! 728: int
! 729: cdwrite(dev_t dev, struct uio *uio, int ioflag)
! 730: {
! 731:
! 732: return (physio(cdstrategy, NULL, dev, B_WRITE, cdminphys, uio));
! 733: }
! 734:
! 735: /*
! 736: * conversion between minute-seconde-frame and logical block address
! 737: * addresses format
! 738: */
! 739: void
! 740: lba2msf (lba, m, s, f)
! 741: u_long lba;
! 742: u_char *m, *s, *f;
! 743: {
! 744: u_long tmp;
! 745:
! 746: tmp = lba + CD_BLOCK_OFFSET; /* offset of first logical frame */
! 747: tmp &= 0xffffff; /* negative lbas use only 24 bits */
! 748: *m = tmp / (CD_SECS * CD_FRAMES);
! 749: tmp %= (CD_SECS * CD_FRAMES);
! 750: *s = tmp / CD_FRAMES;
! 751: *f = tmp % CD_FRAMES;
! 752: }
! 753:
! 754: u_long
! 755: msf2lba (m, s, f)
! 756: u_char m, s, f;
! 757: {
! 758:
! 759: return ((((m * CD_SECS) + s) * CD_FRAMES + f) - CD_BLOCK_OFFSET);
! 760: }
! 761:
! 762:
! 763: /*
! 764: * Perform special action on behalf of the user.
! 765: * Knows about the internals of this device
! 766: */
! 767: int
! 768: cdioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
! 769: {
! 770: struct cd_softc *cd;
! 771: struct disklabel *lp;
! 772: int part = DISKPART(dev);
! 773: int error = 0;
! 774:
! 775: cd = cdlookup(DISKUNIT(dev));
! 776: if (cd == NULL)
! 777: return ENXIO;
! 778:
! 779: SC_DEBUG(cd->sc_link, SDEV_DB2, ("cdioctl 0x%lx\n", cmd));
! 780:
! 781: /*
! 782: * If the device is not valid.. abandon ship
! 783: */
! 784: if ((cd->sc_link->flags & SDEV_MEDIA_LOADED) == 0) {
! 785: switch (cmd) {
! 786: case DIOCWLABEL:
! 787: case DIOCLOCK:
! 788: case DIOCEJECT:
! 789: case SCIOCIDENTIFY:
! 790: case SCIOCCOMMAND:
! 791: case SCIOCDEBUG:
! 792: case CDIOCLOADUNLOAD:
! 793: case SCIOCRESET:
! 794: case CDIOCGETVOL:
! 795: case CDIOCSETVOL:
! 796: case CDIOCSETMONO:
! 797: case CDIOCSETSTEREO:
! 798: case CDIOCSETMUTE:
! 799: case CDIOCSETLEFT:
! 800: case CDIOCSETRIGHT:
! 801: case CDIOCCLOSE:
! 802: case CDIOCEJECT:
! 803: case CDIOCALLOW:
! 804: case CDIOCPREVENT:
! 805: case CDIOCSETDEBUG:
! 806: case CDIOCCLRDEBUG:
! 807: case CDIOCRESET:
! 808: case DVD_AUTH:
! 809: case DVD_READ_STRUCT:
! 810: case MTIOCTOP:
! 811: if (part == RAW_PART)
! 812: break;
! 813: /* FALLTHROUGH */
! 814: default:
! 815: if ((cd->sc_link->flags & SDEV_OPEN) == 0)
! 816: error = ENODEV;
! 817: else
! 818: error = EIO;
! 819: goto exit;
! 820: }
! 821: }
! 822:
! 823: switch (cmd) {
! 824: case DIOCRLDINFO:
! 825: lp = malloc(sizeof(*lp), M_TEMP, M_WAITOK);
! 826: cdgetdisklabel(dev, cd, lp, 0);
! 827: bcopy(lp, cd->sc_dk.dk_label, sizeof(*lp));
! 828: free(lp, M_TEMP);
! 829: break;
! 830: case DIOCGDINFO:
! 831: case DIOCGPDINFO:
! 832: *(struct disklabel *)addr = *(cd->sc_dk.dk_label);
! 833: break;
! 834:
! 835: case DIOCGPART:
! 836: ((struct partinfo *)addr)->disklab = cd->sc_dk.dk_label;
! 837: ((struct partinfo *)addr)->part =
! 838: &cd->sc_dk.dk_label->d_partitions[DISKPART(dev)];
! 839: break;
! 840:
! 841: case DIOCWDINFO:
! 842: case DIOCSDINFO:
! 843: if ((flag & FWRITE) == 0) {
! 844: error = EBADF;
! 845: break;
! 846: }
! 847:
! 848: if ((error = cdlock(cd)) != 0)
! 849: break;
! 850:
! 851: cd->flags |= CDF_LABELLING;
! 852:
! 853: error = setdisklabel(cd->sc_dk.dk_label,
! 854: (struct disklabel *)addr, /*cd->sc_dk.dk_openmask : */0);
! 855: if (error == 0) {
! 856: }
! 857:
! 858: cd->flags &= ~CDF_LABELLING;
! 859: cdunlock(cd);
! 860: break;
! 861:
! 862: case DIOCWLABEL:
! 863: error = EBADF;
! 864: break;
! 865:
! 866: case CDIOCPLAYTRACKS: {
! 867: struct ioc_play_track *args = (struct ioc_play_track *)addr;
! 868:
! 869: if ((error = cd_set_pa_immed(cd, 0)) != 0)
! 870: break;
! 871: error = cd_play_tracks(cd, args->start_track,
! 872: args->start_index, args->end_track, args->end_index);
! 873: break;
! 874: }
! 875: case CDIOCPLAYMSF: {
! 876: struct ioc_play_msf *args = (struct ioc_play_msf *)addr;
! 877:
! 878: if ((error = cd_set_pa_immed(cd, 0)) != 0)
! 879: break;
! 880: error = cd_play_msf(cd, args->start_m, args->start_s,
! 881: args->start_f, args->end_m, args->end_s, args->end_f);
! 882: break;
! 883: }
! 884: case CDIOCPLAYBLOCKS: {
! 885: struct ioc_play_blocks *args = (struct ioc_play_blocks *)addr;
! 886:
! 887: if ((error = cd_set_pa_immed(cd, 0)) != 0)
! 888: break;
! 889: error = cd_play(cd, args->blk, args->len);
! 890: break;
! 891: }
! 892: case CDIOCREADSUBCHANNEL: {
! 893: struct ioc_read_subchannel *args
! 894: = (struct ioc_read_subchannel *)addr;
! 895: struct cd_sub_channel_info data;
! 896: int len = args->data_len;
! 897: if (len > sizeof(data) ||
! 898: len < sizeof(struct cd_sub_channel_header)) {
! 899: error = EINVAL;
! 900: break;
! 901: }
! 902: error = cd_read_subchannel(cd, args->address_format,
! 903: args->data_format, args->track,
! 904: &data, len);
! 905: if (error)
! 906: break;
! 907: len = min(len, _2btol(data.header.data_len) +
! 908: sizeof(struct cd_sub_channel_header));
! 909: error = copyout(&data, args->data, len);
! 910: break;
! 911: }
! 912: case CDIOREADTOCHEADER: {
! 913: struct ioc_toc_header th;
! 914:
! 915: if ((error = cd_read_toc(cd, 0, 0, &th, sizeof(th), 0)) != 0)
! 916: break;
! 917: if (cd->sc_link->quirks & ADEV_LITTLETOC)
! 918: th.len = letoh16(th.len);
! 919: else
! 920: th.len = betoh16(th.len);
! 921: bcopy(&th, addr, sizeof(th));
! 922: break;
! 923: }
! 924: case CDIOREADTOCENTRYS: {
! 925: struct cd_toc *toc;
! 926: struct ioc_read_toc_entry *te =
! 927: (struct ioc_read_toc_entry *)addr;
! 928: struct ioc_toc_header *th;
! 929: struct cd_toc_entry *cte;
! 930: int len = te->data_len;
! 931: int ntracks;
! 932:
! 933: MALLOC(toc, struct cd_toc *, sizeof(struct cd_toc), M_TEMP,
! 934: M_WAITOK);
! 935: bzero(toc, sizeof(*toc));
! 936:
! 937: th = &toc->header;
! 938:
! 939: if (len > sizeof(toc->entries) ||
! 940: len < sizeof(struct cd_toc_entry)) {
! 941: FREE(toc, M_TEMP);
! 942: error = EINVAL;
! 943: break;
! 944: }
! 945: error = cd_read_toc(cd, te->address_format, te->starting_track,
! 946: toc, len + sizeof(struct ioc_toc_header), 0);
! 947: if (error) {
! 948: FREE(toc, M_TEMP);
! 949: break;
! 950: }
! 951: if (te->address_format == CD_LBA_FORMAT)
! 952: for (ntracks =
! 953: th->ending_track - th->starting_track + 1;
! 954: ntracks >= 0; ntracks--) {
! 955: cte = &toc->entries[ntracks];
! 956: cte->addr_type = CD_LBA_FORMAT;
! 957: if (cd->sc_link->quirks & ADEV_LITTLETOC) {
! 958: #if BYTE_ORDER == BIG_ENDIAN
! 959: swap16_multi((u_int16_t *)&cte->addr,
! 960: sizeof(cte->addr) / 2);
! 961: #endif
! 962: } else
! 963: cte->addr.lba = betoh32(cte->addr.lba);
! 964: }
! 965: if (cd->sc_link->quirks & ADEV_LITTLETOC) {
! 966: th->len = letoh16(th->len);
! 967: } else
! 968: th->len = betoh16(th->len);
! 969: len = min(len, th->len - (sizeof(th->starting_track) +
! 970: sizeof(th->ending_track)));
! 971:
! 972: error = copyout(toc->entries, te->data, len);
! 973: FREE(toc, M_TEMP);
! 974: break;
! 975: }
! 976: case CDIOREADMSADDR: {
! 977: struct cd_toc *toc;
! 978: int sessno = *(int *)addr;
! 979: struct cd_toc_entry *cte;
! 980:
! 981: if (sessno != 0) {
! 982: error = EINVAL;
! 983: break;
! 984: }
! 985:
! 986: MALLOC(toc, struct cd_toc *, sizeof(struct cd_toc), M_TEMP,
! 987: M_WAITOK);
! 988: bzero(toc, sizeof(*toc));
! 989:
! 990: error = cd_read_toc(cd, 0, 0, toc,
! 991: sizeof(struct ioc_toc_header) + sizeof(struct cd_toc_entry),
! 992: 0x40 /* control word for "get MS info" */);
! 993:
! 994: if (error) {
! 995: FREE(toc, M_TEMP);
! 996: break;
! 997: }
! 998:
! 999: cte = &toc->entries[0];
! 1000: if (cd->sc_link->quirks & ADEV_LITTLETOC) {
! 1001: #if BYTE_ORDER == BIG_ENDIAN
! 1002: swap16_multi((u_int16_t *)&cte->addr,
! 1003: sizeof(cte->addr) / 2);
! 1004: #endif
! 1005: } else
! 1006: cte->addr.lba = betoh32(cte->addr.lba);
! 1007: if (cd->sc_link->quirks & ADEV_LITTLETOC)
! 1008: toc->header.len = letoh16(toc->header.len);
! 1009: else
! 1010: toc->header.len = betoh16(toc->header.len);
! 1011:
! 1012: *(int *)addr = (toc->header.len >= 10 && cte->track > 1) ?
! 1013: cte->addr.lba : 0;
! 1014: FREE(toc, M_TEMP);
! 1015: break;
! 1016: }
! 1017: case CDIOCSETPATCH: {
! 1018: struct ioc_patch *arg = (struct ioc_patch *)addr;
! 1019:
! 1020: error = cd_setchan(cd, arg->patch[0], arg->patch[1],
! 1021: arg->patch[2], arg->patch[3], 0);
! 1022: break;
! 1023: }
! 1024: case CDIOCGETVOL: {
! 1025: struct ioc_vol *arg = (struct ioc_vol *)addr;
! 1026:
! 1027: error = cd_getvol(cd, arg, 0);
! 1028: break;
! 1029: }
! 1030: case CDIOCSETVOL: {
! 1031: struct ioc_vol *arg = (struct ioc_vol *)addr;
! 1032:
! 1033: error = cd_setvol(cd, arg, 0);
! 1034: break;
! 1035: }
! 1036:
! 1037: case CDIOCSETMONO:
! 1038: error = cd_setchan(cd, BOTH_CHANNEL, BOTH_CHANNEL, MUTE_CHANNEL,
! 1039: MUTE_CHANNEL, 0);
! 1040: break;
! 1041:
! 1042: case CDIOCSETSTEREO:
! 1043: error = cd_setchan(cd, LEFT_CHANNEL, RIGHT_CHANNEL,
! 1044: MUTE_CHANNEL, MUTE_CHANNEL, 0);
! 1045: break;
! 1046:
! 1047: case CDIOCSETMUTE:
! 1048: error = cd_setchan(cd, MUTE_CHANNEL, MUTE_CHANNEL, MUTE_CHANNEL,
! 1049: MUTE_CHANNEL, 0);
! 1050: break;
! 1051:
! 1052: case CDIOCSETLEFT:
! 1053: error = cd_setchan(cd, LEFT_CHANNEL, LEFT_CHANNEL, MUTE_CHANNEL,
! 1054: MUTE_CHANNEL, 0);
! 1055: break;
! 1056:
! 1057: case CDIOCSETRIGHT:
! 1058: error = cd_setchan(cd, RIGHT_CHANNEL, RIGHT_CHANNEL,
! 1059: MUTE_CHANNEL, MUTE_CHANNEL, 0);
! 1060: break;
! 1061:
! 1062: case CDIOCRESUME:
! 1063: error = cd_pause(cd, 1);
! 1064: break;
! 1065:
! 1066: case CDIOCPAUSE:
! 1067: error = cd_pause(cd, 0);
! 1068: break;
! 1069: case CDIOCSTART:
! 1070: error = scsi_start(cd->sc_link, SSS_START, 0);
! 1071: break;
! 1072:
! 1073: case CDIOCSTOP:
! 1074: error = scsi_start(cd->sc_link, SSS_STOP, 0);
! 1075: break;
! 1076:
! 1077: close_tray:
! 1078: case CDIOCCLOSE:
! 1079: error = scsi_start(cd->sc_link, SSS_START|SSS_LOEJ,
! 1080: SCSI_IGNORE_NOT_READY | SCSI_IGNORE_MEDIA_CHANGE);
! 1081: break;
! 1082:
! 1083: case MTIOCTOP:
! 1084: if (((struct mtop *)addr)->mt_op == MTRETEN)
! 1085: goto close_tray;
! 1086: if (((struct mtop *)addr)->mt_op != MTOFFL) {
! 1087: error = EIO;
! 1088: break;
! 1089: }
! 1090: /* FALLTHROUGH */
! 1091: case CDIOCEJECT: /* FALLTHROUGH */
! 1092: case DIOCEJECT:
! 1093: cd->sc_link->flags |= SDEV_EJECTING;
! 1094: break;
! 1095: case CDIOCALLOW:
! 1096: error = scsi_prevent(cd->sc_link, PR_ALLOW, 0);
! 1097: break;
! 1098: case CDIOCPREVENT:
! 1099: error = scsi_prevent(cd->sc_link, PR_PREVENT, 0);
! 1100: break;
! 1101: case DIOCLOCK:
! 1102: error = scsi_prevent(cd->sc_link,
! 1103: (*(int *)addr) ? PR_PREVENT : PR_ALLOW, 0);
! 1104: break;
! 1105: case CDIOCSETDEBUG:
! 1106: cd->sc_link->flags |= (SDEV_DB1 | SDEV_DB2);
! 1107: break;
! 1108: case CDIOCCLRDEBUG:
! 1109: cd->sc_link->flags &= ~(SDEV_DB1 | SDEV_DB2);
! 1110: break;
! 1111: case CDIOCRESET:
! 1112: case SCIOCRESET:
! 1113: error = cd_reset(cd);
! 1114: break;
! 1115: case CDIOCLOADUNLOAD: {
! 1116: struct ioc_load_unload *args = (struct ioc_load_unload *)addr;
! 1117:
! 1118: error = cd_load_unload(cd, args->options, args->slot);
! 1119: break;
! 1120: }
! 1121:
! 1122: case DVD_AUTH:
! 1123: error = dvd_auth(cd, (union dvd_authinfo *)addr);
! 1124: break;
! 1125: case DVD_READ_STRUCT:
! 1126: error = dvd_read_struct(cd, (union dvd_struct *)addr);
! 1127: break;
! 1128: default:
! 1129: if (DISKPART(dev) != RAW_PART) {
! 1130: error = ENOTTY;
! 1131: break;
! 1132: }
! 1133: error = scsi_do_ioctl(cd->sc_link, dev, cmd, addr, flag, p);
! 1134: break;
! 1135: }
! 1136:
! 1137: exit:
! 1138:
! 1139: device_unref(&cd->sc_dev);
! 1140: return (error);
! 1141: }
! 1142:
! 1143: /*
! 1144: * Load the label information on the named device
! 1145: * Actually fabricate a disklabel
! 1146: *
! 1147: * EVENTUALLY take information about different
! 1148: * data tracks from the TOC and put it in the disklabel
! 1149: */
! 1150: void
! 1151: cdgetdisklabel(dev_t dev, struct cd_softc *cd, struct disklabel *lp,
! 1152: int spoofonly)
! 1153: {
! 1154: struct cd_toc *toc;
! 1155: char *errstring;
! 1156: int tocidx, n, audioonly = 1;
! 1157:
! 1158: bzero(lp, sizeof(struct disklabel));
! 1159:
! 1160: MALLOC(toc, struct cd_toc *, sizeof(struct cd_toc), M_TEMP, M_WAITOK);
! 1161: bzero(toc, sizeof(*toc));
! 1162:
! 1163: lp->d_secsize = cd->params.blksize;
! 1164: lp->d_ntracks = 1;
! 1165: lp->d_nsectors = 100;
! 1166: lp->d_secpercyl = 100;
! 1167: lp->d_ncylinders = (cd->params.disksize / 100) + 1;
! 1168:
! 1169: if (cd->sc_link->flags & SDEV_ATAPI) {
! 1170: strncpy(lp->d_typename, "ATAPI CD-ROM", sizeof(lp->d_typename));
! 1171: lp->d_type = DTYPE_ATAPI;
! 1172: } else {
! 1173: strncpy(lp->d_typename, "SCSI CD-ROM", sizeof(lp->d_typename));
! 1174: lp->d_type = DTYPE_SCSI;
! 1175: }
! 1176:
! 1177: strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
! 1178: DL_SETDSIZE(lp, cd->params.disksize);
! 1179: lp->d_rpm = 300;
! 1180: lp->d_interleave = 1;
! 1181: lp->d_version = 1;
! 1182:
! 1183: /* XXX - these values for BBSIZE and SBSIZE assume ffs */
! 1184: lp->d_bbsize = BBSIZE;
! 1185: lp->d_sbsize = SBSIZE;
! 1186:
! 1187: lp->d_magic = DISKMAGIC;
! 1188: lp->d_magic2 = DISKMAGIC;
! 1189: lp->d_checksum = dkcksum(lp);
! 1190:
! 1191: if (cd_load_toc(cd, toc, CD_LBA_FORMAT)) {
! 1192: audioonly = 0; /* No valid TOC found == not an audio CD. */
! 1193: goto done;
! 1194: }
! 1195:
! 1196: n = toc->header.ending_track - toc->header.starting_track + 1;
! 1197: for (tocidx = 0; tocidx < n; tocidx++)
! 1198: if (toc->entries[tocidx].control & 4) {
! 1199: audioonly = 0; /* Found a non-audio track. */
! 1200: goto done;
! 1201: }
! 1202:
! 1203: done:
! 1204: free(toc, M_TEMP);
! 1205:
! 1206: if (!audioonly) {
! 1207: errstring = readdisklabel(DISKLABELDEV(dev), cdstrategy, lp,
! 1208: spoofonly);
! 1209: /*if (errstring)
! 1210: printf("%s: %s\n", cd->sc_dev.dv_xname, errstring);*/
! 1211: }
! 1212: }
! 1213:
! 1214: /*
! 1215: * Find out from the device what its capacity is
! 1216: */
! 1217: u_long
! 1218: cd_size(struct cd_softc *cd, int flags)
! 1219: {
! 1220: struct scsi_read_cd_cap_data rdcap;
! 1221: struct scsi_read_cd_capacity scsi_cmd;
! 1222: u_long size;
! 1223: int blksize;
! 1224:
! 1225: /* Reasonable defaults for drives that don't support
! 1226: READ_CD_CAPACITY */
! 1227: cd->params.blksize = 2048;
! 1228: cd->params.disksize = 400000;
! 1229:
! 1230: if (cd->sc_link->quirks & ADEV_NOCAPACITY)
! 1231: goto exit;
! 1232:
! 1233: /*
! 1234: * make up a scsi command and ask the scsi driver to do
! 1235: * it for you.
! 1236: */
! 1237: bzero(&scsi_cmd, sizeof(scsi_cmd));
! 1238: scsi_cmd.opcode = READ_CD_CAPACITY;
! 1239:
! 1240: /*
! 1241: * If the command works, interpret the result as a 4 byte
! 1242: * number of blocks and a blocksize
! 1243: */
! 1244: if (scsi_scsi_cmd(cd->sc_link,
! 1245: (struct scsi_generic *)&scsi_cmd, sizeof(scsi_cmd),
! 1246: (u_char *)&rdcap, sizeof(rdcap), CDRETRIES, 20000, NULL,
! 1247: flags | SCSI_DATA_IN) != 0)
! 1248: goto exit;
! 1249:
! 1250: blksize = _4btol(rdcap.length);
! 1251: if ((blksize < 512) || ((blksize & 511) != 0))
! 1252: blksize = 2048; /* some drives lie ! */
! 1253: cd->params.blksize = blksize;
! 1254:
! 1255: size = _4btol(rdcap.addr) + 1;
! 1256: if (size < 100)
! 1257: size = 400000; /* ditto */
! 1258: cd->params.disksize = size;
! 1259:
! 1260: exit:
! 1261: SC_DEBUG(cd->sc_link, SDEV_DB2, ("cd_size: %d %ld\n", blksize, size));
! 1262: return (cd->params.disksize);
! 1263: }
! 1264:
! 1265: int
! 1266: cd_setchan(struct cd_softc *cd, int p0, int p1, int p2, int p3, int flags)
! 1267: {
! 1268: union scsi_mode_sense_buf *data;
! 1269: struct cd_audio_page *audio = NULL;
! 1270: int error, big;
! 1271:
! 1272: data = malloc(sizeof(*data), M_TEMP, M_NOWAIT);
! 1273: if (data == NULL)
! 1274: return (ENOMEM);
! 1275:
! 1276: error = scsi_do_mode_sense(cd->sc_link, AUDIO_PAGE, data,
! 1277: (void **)&audio, NULL, NULL, NULL, sizeof(*audio), flags, &big);
! 1278: if (error == 0 && audio == NULL)
! 1279: error = EIO;
! 1280:
! 1281: if (error == 0) {
! 1282: audio->port[LEFT_PORT].channels = p0;
! 1283: audio->port[RIGHT_PORT].channels = p1;
! 1284: audio->port[2].channels = p2;
! 1285: audio->port[3].channels = p3;
! 1286: if (big)
! 1287: error = scsi_mode_select_big(cd->sc_link, SMS_PF,
! 1288: &data->hdr_big, flags, 20000);
! 1289: else
! 1290: error = scsi_mode_select(cd->sc_link, SMS_PF,
! 1291: &data->hdr, flags, 20000);
! 1292: }
! 1293:
! 1294: free(data, M_TEMP);
! 1295: return (error);
! 1296: }
! 1297:
! 1298: int
! 1299: cd_getvol(struct cd_softc *cd, struct ioc_vol *arg, int flags)
! 1300: {
! 1301: union scsi_mode_sense_buf *data;
! 1302: struct cd_audio_page *audio = NULL;
! 1303: int error;
! 1304:
! 1305: data = malloc(sizeof(*data), M_TEMP, M_NOWAIT);
! 1306: if (data == NULL)
! 1307: return (ENOMEM);
! 1308:
! 1309: error = scsi_do_mode_sense(cd->sc_link, AUDIO_PAGE, data,
! 1310: (void **)&audio, NULL, NULL, NULL, sizeof(*audio), flags, NULL);
! 1311: if (error == 0 && audio == NULL)
! 1312: error = EIO;
! 1313:
! 1314: if (error == 0) {
! 1315: arg->vol[0] = audio->port[0].volume;
! 1316: arg->vol[1] = audio->port[1].volume;
! 1317: arg->vol[2] = audio->port[2].volume;
! 1318: arg->vol[3] = audio->port[3].volume;
! 1319: }
! 1320:
! 1321: free(data, M_TEMP);
! 1322: return (0);
! 1323: }
! 1324:
! 1325: int
! 1326: cd_setvol(struct cd_softc *cd, const struct ioc_vol *arg, int flags)
! 1327: {
! 1328: union scsi_mode_sense_buf *data;
! 1329: struct cd_audio_page *audio = NULL;
! 1330: u_int8_t mask_volume[4];
! 1331: int error, big;
! 1332:
! 1333: data = malloc(sizeof(*data), M_TEMP, M_NOWAIT);
! 1334: if (data == NULL)
! 1335: return (ENOMEM);
! 1336:
! 1337: error = scsi_do_mode_sense(cd->sc_link,
! 1338: AUDIO_PAGE | SMS_PAGE_CTRL_CHANGEABLE, data, (void **)&audio, NULL,
! 1339: NULL, NULL, sizeof(*audio), flags, NULL);
! 1340: if (error == 0 && audio == NULL)
! 1341: error = EIO;
! 1342: if (error != 0) {
! 1343: free(data, M_TEMP);
! 1344: return (error);
! 1345: }
! 1346:
! 1347: mask_volume[0] = audio->port[0].volume;
! 1348: mask_volume[1] = audio->port[1].volume;
! 1349: mask_volume[2] = audio->port[2].volume;
! 1350: mask_volume[3] = audio->port[3].volume;
! 1351:
! 1352: error = scsi_do_mode_sense(cd->sc_link, AUDIO_PAGE, data,
! 1353: (void **)&audio, NULL, NULL, NULL, sizeof(*audio), flags, &big);
! 1354: if (error == 0 && audio == NULL)
! 1355: error = EIO;
! 1356: if (error != 0) {
! 1357: free(data, M_TEMP);
! 1358: return (error);
! 1359: }
! 1360:
! 1361: audio->port[0].volume = arg->vol[0] & mask_volume[0];
! 1362: audio->port[1].volume = arg->vol[1] & mask_volume[1];
! 1363: audio->port[2].volume = arg->vol[2] & mask_volume[2];
! 1364: audio->port[3].volume = arg->vol[3] & mask_volume[3];
! 1365:
! 1366: if (big)
! 1367: error = scsi_mode_select_big(cd->sc_link, SMS_PF,
! 1368: &data->hdr_big, flags, 20000);
! 1369: else
! 1370: error = scsi_mode_select(cd->sc_link, SMS_PF,
! 1371: &data->hdr, flags, 20000);
! 1372:
! 1373: free(data, M_TEMP);
! 1374: return (error);
! 1375: }
! 1376:
! 1377: int
! 1378: cd_load_unload(struct cd_softc *cd, int options, int slot)
! 1379: {
! 1380: struct scsi_load_unload cmd;
! 1381:
! 1382: bzero(&cmd, sizeof(cmd));
! 1383: cmd.opcode = LOAD_UNLOAD;
! 1384: cmd.options = options; /* ioctl uses ATAPI values */
! 1385: cmd.slot = slot;
! 1386:
! 1387: return (scsi_scsi_cmd(cd->sc_link, (struct scsi_generic *)&cmd,
! 1388: sizeof(cmd), 0, 0, CDRETRIES, 200000, NULL, 0));
! 1389: }
! 1390:
! 1391: int
! 1392: cd_set_pa_immed(struct cd_softc *cd, int flags)
! 1393: {
! 1394: union scsi_mode_sense_buf *data;
! 1395: struct cd_audio_page *audio = NULL;
! 1396: int error, oflags, big;
! 1397:
! 1398: if (cd->sc_link->flags & SDEV_ATAPI)
! 1399: /* XXX Noop? */
! 1400: return (0);
! 1401:
! 1402: data = malloc(sizeof(*data), M_TEMP, M_NOWAIT);
! 1403: if (data == NULL)
! 1404: return (ENOMEM);
! 1405:
! 1406: error = scsi_do_mode_sense(cd->sc_link, AUDIO_PAGE, data,
! 1407: (void **)&audio, NULL, NULL, NULL, sizeof(*audio), flags, &big);
! 1408: if (error == 0 && audio == NULL)
! 1409: error = EIO;
! 1410:
! 1411: if (error == 0) {
! 1412: oflags = audio->flags;
! 1413: audio->flags &= ~CD_PA_SOTC;
! 1414: audio->flags |= CD_PA_IMMED;
! 1415: if (audio->flags != oflags) {
! 1416: if (big)
! 1417: error = scsi_mode_select_big(cd->sc_link,
! 1418: SMS_PF, &data->hdr_big, flags,
! 1419: 20000);
! 1420: else
! 1421: error = scsi_mode_select(cd->sc_link, SMS_PF,
! 1422: &data->hdr, flags, 20000);
! 1423: }
! 1424: }
! 1425:
! 1426: free(data, M_TEMP);
! 1427: return (error);
! 1428: }
! 1429:
! 1430: /*
! 1431: * Get scsi driver to send a "start playing" command
! 1432: */
! 1433: int
! 1434: cd_play(struct cd_softc *cd, int blkno, int nblks)
! 1435: {
! 1436: struct scsi_play scsi_cmd;
! 1437:
! 1438: bzero(&scsi_cmd, sizeof(scsi_cmd));
! 1439: scsi_cmd.opcode = PLAY;
! 1440: _lto4b(blkno, scsi_cmd.blk_addr);
! 1441: _lto2b(nblks, scsi_cmd.xfer_len);
! 1442: return (scsi_scsi_cmd(cd->sc_link,
! 1443: (struct scsi_generic *)&scsi_cmd, sizeof(scsi_cmd),
! 1444: 0, 0, CDRETRIES, 200000, NULL, 0));
! 1445: }
! 1446:
! 1447: /*
! 1448: * Get scsi driver to send a "start playing" command
! 1449: */
! 1450: int
! 1451: cd_play_tracks(struct cd_softc *cd, int strack, int sindex, int etrack,
! 1452: int eindex)
! 1453: {
! 1454: struct cd_toc *toc;
! 1455: u_char endf, ends, endm;
! 1456: int error;
! 1457:
! 1458: if (!etrack)
! 1459: return (EIO);
! 1460: if (strack > etrack)
! 1461: return (EINVAL);
! 1462:
! 1463: MALLOC(toc, struct cd_toc *, sizeof(struct cd_toc), M_TEMP, M_WAITOK);
! 1464: bzero(toc, sizeof(*toc));
! 1465:
! 1466: if ((error = cd_load_toc(cd, toc, CD_MSF_FORMAT)) != 0)
! 1467: goto done;
! 1468:
! 1469: if (++etrack > (toc->header.ending_track+1))
! 1470: etrack = toc->header.ending_track+1;
! 1471:
! 1472: strack -= toc->header.starting_track;
! 1473: etrack -= toc->header.starting_track;
! 1474: if (strack < 0) {
! 1475: error = EINVAL;
! 1476: goto done;
! 1477: }
! 1478:
! 1479: /*
! 1480: * The track ends one frame before the next begins. The last track
! 1481: * is taken care of by the leadoff track.
! 1482: */
! 1483: endm = toc->entries[etrack].addr.msf.minute;
! 1484: ends = toc->entries[etrack].addr.msf.second;
! 1485: endf = toc->entries[etrack].addr.msf.frame;
! 1486: if (endf-- == 0) {
! 1487: endf = CD_FRAMES - 1;
! 1488: if (ends-- == 0) {
! 1489: ends = CD_SECS - 1;
! 1490: if (endm-- == 0) {
! 1491: error = EINVAL;
! 1492: goto done;
! 1493: }
! 1494: }
! 1495: }
! 1496:
! 1497: error = cd_play_msf(cd, toc->entries[strack].addr.msf.minute,
! 1498: toc->entries[strack].addr.msf.second,
! 1499: toc->entries[strack].addr.msf.frame,
! 1500: endm, ends, endf);
! 1501:
! 1502: done:
! 1503: FREE(toc, M_TEMP);
! 1504: return (error);
! 1505: }
! 1506:
! 1507: /*
! 1508: * Get scsi driver to send a "play msf" command
! 1509: */
! 1510: int
! 1511: cd_play_msf(struct cd_softc *cd, int startm, int starts, int startf, int endm,
! 1512: int ends, int endf)
! 1513: {
! 1514: struct scsi_play_msf scsi_cmd;
! 1515:
! 1516: bzero(&scsi_cmd, sizeof(scsi_cmd));
! 1517: scsi_cmd.opcode = PLAY_MSF;
! 1518: scsi_cmd.start_m = startm;
! 1519: scsi_cmd.start_s = starts;
! 1520: scsi_cmd.start_f = startf;
! 1521: scsi_cmd.end_m = endm;
! 1522: scsi_cmd.end_s = ends;
! 1523: scsi_cmd.end_f = endf;
! 1524: return (scsi_scsi_cmd(cd->sc_link,
! 1525: (struct scsi_generic *)&scsi_cmd, sizeof(scsi_cmd),
! 1526: 0, 0, CDRETRIES, 20000, NULL, 0));
! 1527: }
! 1528:
! 1529: /*
! 1530: * Get scsi driver to send a "start up" command
! 1531: */
! 1532: int
! 1533: cd_pause(struct cd_softc *cd, int go)
! 1534: {
! 1535: struct scsi_pause scsi_cmd;
! 1536:
! 1537: bzero(&scsi_cmd, sizeof(scsi_cmd));
! 1538: scsi_cmd.opcode = PAUSE;
! 1539: scsi_cmd.resume = go;
! 1540: return scsi_scsi_cmd(cd->sc_link, (struct scsi_generic *)&scsi_cmd,
! 1541: sizeof(scsi_cmd), 0, 0, CDRETRIES, 2000, NULL, 0);
! 1542: }
! 1543:
! 1544: /*
! 1545: * Get scsi driver to send a "RESET" command
! 1546: */
! 1547: int
! 1548: cd_reset(struct cd_softc *cd)
! 1549: {
! 1550: return scsi_scsi_cmd(cd->sc_link, 0, 0, 0, 0, CDRETRIES, 2000, NULL,
! 1551: SCSI_RESET);
! 1552: }
! 1553:
! 1554: /*
! 1555: * Read subchannel
! 1556: */
! 1557: int
! 1558: cd_read_subchannel(struct cd_softc *cd, int mode, int format, int track,
! 1559: struct cd_sub_channel_info *data, int len)
! 1560: {
! 1561: struct scsi_read_subchannel scsi_cmd;
! 1562:
! 1563: bzero(&scsi_cmd, sizeof(scsi_cmd));
! 1564: scsi_cmd.opcode = READ_SUBCHANNEL;
! 1565: if (mode == CD_MSF_FORMAT)
! 1566: scsi_cmd.byte2 |= CD_MSF;
! 1567: scsi_cmd.byte3 = SRS_SUBQ;
! 1568: scsi_cmd.subchan_format = format;
! 1569: scsi_cmd.track = track;
! 1570: _lto2b(len, scsi_cmd.data_len);
! 1571: return scsi_scsi_cmd(cd->sc_link, (struct scsi_generic *)&scsi_cmd,
! 1572: sizeof(struct scsi_read_subchannel), (u_char *)data, len,
! 1573: CDRETRIES, 5000, NULL, SCSI_DATA_IN|SCSI_SILENT);
! 1574: }
! 1575:
! 1576: /*
! 1577: * Read table of contents
! 1578: */
! 1579: int
! 1580: cd_read_toc(struct cd_softc *cd, int mode, int start, void *data, int len,
! 1581: int control)
! 1582: {
! 1583: struct scsi_read_toc scsi_cmd;
! 1584:
! 1585: bzero(&scsi_cmd, sizeof(scsi_cmd));
! 1586: bzero(data, len);
! 1587:
! 1588: scsi_cmd.opcode = READ_TOC;
! 1589: if (mode == CD_MSF_FORMAT)
! 1590: scsi_cmd.byte2 |= CD_MSF;
! 1591: scsi_cmd.from_track = start;
! 1592: _lto2b(len, scsi_cmd.data_len);
! 1593: scsi_cmd.control = control;
! 1594:
! 1595: return scsi_scsi_cmd(cd->sc_link, (struct scsi_generic *)&scsi_cmd,
! 1596: sizeof(struct scsi_read_toc), (u_char *)data, len, CDRETRIES,
! 1597: 5000, NULL, SCSI_DATA_IN | SCSI_IGNORE_ILLEGAL_REQUEST);
! 1598: }
! 1599:
! 1600: int
! 1601: cd_load_toc(struct cd_softc *cd, struct cd_toc *toc, int fmt)
! 1602: {
! 1603: int n, len, error;
! 1604:
! 1605: error = cd_read_toc(cd, 0, 0, toc, sizeof(toc->header), 0);
! 1606:
! 1607: if (error == 0) {
! 1608: if (toc->header.ending_track < toc->header.starting_track)
! 1609: return (EIO);
! 1610: /* +2 to account for leading out track. */
! 1611: n = toc->header.ending_track - toc->header.starting_track + 2;
! 1612: len = n * sizeof(struct cd_toc_entry) + sizeof(toc->header);
! 1613: error = cd_read_toc(cd, fmt, 0, toc, len, 0);
! 1614: }
! 1615:
! 1616: return (error);
! 1617: }
! 1618:
! 1619:
! 1620: /*
! 1621: * Get the scsi driver to send a full inquiry to the device and use the
! 1622: * results to fill out the disk parameter structure.
! 1623: */
! 1624: int
! 1625: cd_get_parms(struct cd_softc *cd, int flags)
! 1626: {
! 1627: /*
! 1628: * give a number of sectors so that sec * trks * cyls
! 1629: * is <= disk_size
! 1630: */
! 1631: if (cd_size(cd, flags) == 0)
! 1632: return (ENXIO);
! 1633: return (0);
! 1634: }
! 1635:
! 1636: daddr64_t
! 1637: cdsize(dev_t dev)
! 1638: {
! 1639:
! 1640: /* CD-ROMs are read-only. */
! 1641: return -1;
! 1642: }
! 1643:
! 1644: int
! 1645: cddump(dev_t dev, daddr64_t blkno, caddr_t va, size_t size)
! 1646: {
! 1647: /* Not implemented. */
! 1648: return ENXIO;
! 1649: }
! 1650:
! 1651: #define dvd_copy_key(dst, src) bcopy((src), (dst), DVD_KEY_SIZE)
! 1652: #define dvd_copy_challenge(dst, src) bcopy((src), (dst), DVD_CHALLENGE_SIZE)
! 1653:
! 1654: int
! 1655: dvd_auth(struct cd_softc *cd, union dvd_authinfo *a)
! 1656: {
! 1657: struct scsi_generic cmd;
! 1658: u_int8_t buf[20];
! 1659: int error;
! 1660:
! 1661: bzero(cmd.bytes, sizeof(cmd.bytes));
! 1662: bzero(buf, sizeof(buf));
! 1663:
! 1664: switch (a->type) {
! 1665: case DVD_LU_SEND_AGID:
! 1666: cmd.opcode = GPCMD_REPORT_KEY;
! 1667: cmd.bytes[8] = 8;
! 1668: cmd.bytes[9] = 0 | (0 << 6);
! 1669: error = scsi_scsi_cmd(cd->sc_link, &cmd, sizeof(cmd), buf, 8,
! 1670: CDRETRIES, 30000, NULL, SCSI_DATA_IN);
! 1671: if (error)
! 1672: return (error);
! 1673: a->lsa.agid = buf[7] >> 6;
! 1674: return (0);
! 1675:
! 1676: case DVD_LU_SEND_CHALLENGE:
! 1677: cmd.opcode = GPCMD_REPORT_KEY;
! 1678: cmd.bytes[8] = 16;
! 1679: cmd.bytes[9] = 1 | (a->lsc.agid << 6);
! 1680: error = scsi_scsi_cmd(cd->sc_link, &cmd, sizeof(cmd), buf, 16,
! 1681: CDRETRIES, 30000, NULL, SCSI_DATA_IN);
! 1682: if (error)
! 1683: return (error);
! 1684: dvd_copy_challenge(a->lsc.chal, &buf[4]);
! 1685: return (0);
! 1686:
! 1687: case DVD_LU_SEND_KEY1:
! 1688: cmd.opcode = GPCMD_REPORT_KEY;
! 1689: cmd.bytes[8] = 12;
! 1690: cmd.bytes[9] = 2 | (a->lsk.agid << 6);
! 1691: error = scsi_scsi_cmd(cd->sc_link, &cmd, sizeof(cmd), buf, 12,
! 1692: CDRETRIES, 30000, NULL, SCSI_DATA_IN);
! 1693: if (error)
! 1694: return (error);
! 1695: dvd_copy_key(a->lsk.key, &buf[4]);
! 1696: return (0);
! 1697:
! 1698: case DVD_LU_SEND_TITLE_KEY:
! 1699: cmd.opcode = GPCMD_REPORT_KEY;
! 1700: _lto4b(a->lstk.lba, &cmd.bytes[1]);
! 1701: cmd.bytes[8] = 12;
! 1702: cmd.bytes[9] = 4 | (a->lstk.agid << 6);
! 1703: error = scsi_scsi_cmd(cd->sc_link, &cmd, sizeof(cmd), buf, 12,
! 1704: CDRETRIES, 30000, NULL, SCSI_DATA_IN);
! 1705: if (error)
! 1706: return (error);
! 1707: a->lstk.cpm = (buf[4] >> 7) & 1;
! 1708: a->lstk.cp_sec = (buf[4] >> 6) & 1;
! 1709: a->lstk.cgms = (buf[4] >> 4) & 3;
! 1710: dvd_copy_key(a->lstk.title_key, &buf[5]);
! 1711: return (0);
! 1712:
! 1713: case DVD_LU_SEND_ASF:
! 1714: cmd.opcode = GPCMD_REPORT_KEY;
! 1715: cmd.bytes[8] = 8;
! 1716: cmd.bytes[9] = 5 | (a->lsasf.agid << 6);
! 1717: error = scsi_scsi_cmd(cd->sc_link, &cmd, sizeof(cmd), buf, 8,
! 1718: CDRETRIES, 30000, NULL, SCSI_DATA_IN);
! 1719: if (error)
! 1720: return (error);
! 1721: a->lsasf.asf = buf[7] & 1;
! 1722: return (0);
! 1723:
! 1724: case DVD_HOST_SEND_CHALLENGE:
! 1725: cmd.opcode = GPCMD_SEND_KEY;
! 1726: cmd.bytes[8] = 16;
! 1727: cmd.bytes[9] = 1 | (a->hsc.agid << 6);
! 1728: buf[1] = 14;
! 1729: dvd_copy_challenge(&buf[4], a->hsc.chal);
! 1730: error = scsi_scsi_cmd(cd->sc_link, &cmd, sizeof(cmd), buf, 16,
! 1731: CDRETRIES, 30000, NULL, SCSI_DATA_OUT);
! 1732: if (error)
! 1733: return (error);
! 1734: a->type = DVD_LU_SEND_KEY1;
! 1735: return (0);
! 1736:
! 1737: case DVD_HOST_SEND_KEY2:
! 1738: cmd.opcode = GPCMD_SEND_KEY;
! 1739: cmd.bytes[8] = 12;
! 1740: cmd.bytes[9] = 3 | (a->hsk.agid << 6);
! 1741: buf[1] = 10;
! 1742: dvd_copy_key(&buf[4], a->hsk.key);
! 1743: error = scsi_scsi_cmd(cd->sc_link, &cmd, sizeof(cmd), buf, 12,
! 1744: CDRETRIES, 30000, NULL, SCSI_DATA_OUT);
! 1745: if (error) {
! 1746: a->type = DVD_AUTH_FAILURE;
! 1747: return (error);
! 1748: }
! 1749: a->type = DVD_AUTH_ESTABLISHED;
! 1750: return (0);
! 1751:
! 1752: case DVD_INVALIDATE_AGID:
! 1753: cmd.opcode = GPCMD_REPORT_KEY;
! 1754: cmd.bytes[9] = 0x3f | (a->lsa.agid << 6);
! 1755: error = scsi_scsi_cmd(cd->sc_link, &cmd, sizeof(cmd), buf, 16,
! 1756: CDRETRIES, 30000, NULL, 0);
! 1757: if (error)
! 1758: return (error);
! 1759: return (0);
! 1760:
! 1761: case DVD_LU_SEND_RPC_STATE:
! 1762: cmd.opcode = GPCMD_REPORT_KEY;
! 1763: cmd.bytes[8] = 8;
! 1764: cmd.bytes[9] = 8 | (0 << 6);
! 1765: error = scsi_scsi_cmd(cd->sc_link, &cmd, sizeof(cmd), buf, 8,
! 1766: CDRETRIES, 30000, NULL, SCSI_DATA_IN);
! 1767: if (error)
! 1768: return (error);
! 1769: a->lrpcs.type = (buf[4] >> 6) & 3;
! 1770: a->lrpcs.vra = (buf[4] >> 3) & 7;
! 1771: a->lrpcs.ucca = (buf[4]) & 7;
! 1772: a->lrpcs.region_mask = buf[5];
! 1773: a->lrpcs.rpc_scheme = buf[6];
! 1774: return (0);
! 1775:
! 1776: case DVD_HOST_SEND_RPC_STATE:
! 1777: cmd.opcode = GPCMD_SEND_KEY;
! 1778: cmd.bytes[8] = 8;
! 1779: cmd.bytes[9] = 6 | (0 << 6);
! 1780: buf[1] = 6;
! 1781: buf[4] = a->hrpcs.pdrc;
! 1782: error = scsi_scsi_cmd(cd->sc_link, &cmd, sizeof(cmd), buf, 8,
! 1783: CDRETRIES, 30000, NULL, SCSI_DATA_OUT);
! 1784: if (error)
! 1785: return (error);
! 1786: return (0);
! 1787:
! 1788: default:
! 1789: return (ENOTTY);
! 1790: }
! 1791: }
! 1792:
! 1793: int
! 1794: dvd_read_physical(cd, s)
! 1795: struct cd_softc *cd;
! 1796: union dvd_struct *s;
! 1797: {
! 1798: struct scsi_generic cmd;
! 1799: u_int8_t buf[4 + 4 * 20], *bufp;
! 1800: int error;
! 1801: struct dvd_layer *layer;
! 1802: int i;
! 1803:
! 1804: bzero(cmd.bytes, sizeof(cmd.bytes));
! 1805: bzero(buf, sizeof(buf));
! 1806: cmd.opcode = GPCMD_READ_DVD_STRUCTURE;
! 1807: cmd.bytes[6] = s->type;
! 1808: _lto2b(sizeof(buf), &cmd.bytes[7]);
! 1809:
! 1810: cmd.bytes[5] = s->physical.layer_num;
! 1811: error = scsi_scsi_cmd(cd->sc_link, &cmd, sizeof(cmd), buf, sizeof(buf),
! 1812: CDRETRIES, 30000, NULL, SCSI_DATA_IN);
! 1813: if (error)
! 1814: return (error);
! 1815: for (i = 0, bufp = &buf[4], layer = &s->physical.layer[0]; i < 4;
! 1816: i++, bufp += 20, layer++) {
! 1817: bzero(layer, sizeof(*layer));
! 1818: layer->book_version = bufp[0] & 0xf;
! 1819: layer->book_type = bufp[0] >> 4;
! 1820: layer->min_rate = bufp[1] & 0xf;
! 1821: layer->disc_size = bufp[1] >> 4;
! 1822: layer->layer_type = bufp[2] & 0xf;
! 1823: layer->track_path = (bufp[2] >> 4) & 1;
! 1824: layer->nlayers = (bufp[2] >> 5) & 3;
! 1825: layer->track_density = bufp[3] & 0xf;
! 1826: layer->linear_density = bufp[3] >> 4;
! 1827: layer->start_sector = _4btol(&bufp[4]);
! 1828: layer->end_sector = _4btol(&bufp[8]);
! 1829: layer->end_sector_l0 = _4btol(&bufp[12]);
! 1830: layer->bca = bufp[16] >> 7;
! 1831: }
! 1832: return (0);
! 1833: }
! 1834:
! 1835: int
! 1836: dvd_read_copyright(cd, s)
! 1837: struct cd_softc *cd;
! 1838: union dvd_struct *s;
! 1839: {
! 1840: struct scsi_generic cmd;
! 1841: u_int8_t buf[8];
! 1842: int error;
! 1843:
! 1844: bzero(cmd.bytes, sizeof(cmd.bytes));
! 1845: bzero(buf, sizeof(buf));
! 1846: cmd.opcode = GPCMD_READ_DVD_STRUCTURE;
! 1847: cmd.bytes[6] = s->type;
! 1848: _lto2b(sizeof(buf), &cmd.bytes[7]);
! 1849:
! 1850: cmd.bytes[5] = s->copyright.layer_num;
! 1851: error = scsi_scsi_cmd(cd->sc_link, &cmd, sizeof(cmd), buf, sizeof(buf),
! 1852: CDRETRIES, 30000, NULL, SCSI_DATA_IN);
! 1853: if (error)
! 1854: return (error);
! 1855: s->copyright.cpst = buf[4];
! 1856: s->copyright.rmi = buf[5];
! 1857: return (0);
! 1858: }
! 1859:
! 1860: int
! 1861: dvd_read_disckey(cd, s)
! 1862: struct cd_softc *cd;
! 1863: union dvd_struct *s;
! 1864: {
! 1865: struct scsi_read_dvd_structure cmd;
! 1866: struct scsi_read_dvd_structure_data *buf;
! 1867: int error;
! 1868:
! 1869: buf = malloc(sizeof(*buf), M_TEMP, M_WAITOK);
! 1870: if (buf == NULL)
! 1871: return (ENOMEM);
! 1872: bzero(buf, sizeof(*buf));
! 1873:
! 1874: bzero(&cmd, sizeof(cmd));
! 1875: cmd.opcode = GPCMD_READ_DVD_STRUCTURE;
! 1876: cmd.format = s->type;
! 1877: cmd.agid = s->disckey.agid << 6;
! 1878: _lto2b(sizeof(*buf), cmd.length);
! 1879:
! 1880: error = scsi_scsi_cmd(cd->sc_link, (struct scsi_generic *)&cmd,
! 1881: sizeof(cmd), (u_char *)buf, sizeof(*buf), CDRETRIES, 30000, NULL,
! 1882: SCSI_DATA_IN);
! 1883: if (error == 0)
! 1884: bcopy(buf->data, s->disckey.value, sizeof(s->disckey.value));
! 1885:
! 1886: free(buf, M_TEMP);
! 1887: return (error);
! 1888: }
! 1889:
! 1890: int
! 1891: dvd_read_bca(cd, s)
! 1892: struct cd_softc *cd;
! 1893: union dvd_struct *s;
! 1894: {
! 1895: struct scsi_generic cmd;
! 1896: u_int8_t buf[4 + 188];
! 1897: int error;
! 1898:
! 1899: bzero(cmd.bytes, sizeof(cmd.bytes));
! 1900: bzero(buf, sizeof(buf));
! 1901: cmd.opcode = GPCMD_READ_DVD_STRUCTURE;
! 1902: cmd.bytes[6] = s->type;
! 1903: _lto2b(sizeof(buf), &cmd.bytes[7]);
! 1904:
! 1905: error = scsi_scsi_cmd(cd->sc_link, &cmd, sizeof(cmd), buf, sizeof(buf),
! 1906: CDRETRIES, 30000, NULL, SCSI_DATA_IN);
! 1907: if (error)
! 1908: return (error);
! 1909: s->bca.len = _2btol(&buf[0]);
! 1910: if (s->bca.len < 12 || s->bca.len > 188)
! 1911: return (EIO);
! 1912: bcopy(&buf[4], s->bca.value, s->bca.len);
! 1913: return (0);
! 1914: }
! 1915:
! 1916: int
! 1917: dvd_read_manufact(cd, s)
! 1918: struct cd_softc *cd;
! 1919: union dvd_struct *s;
! 1920: {
! 1921: struct scsi_read_dvd_structure cmd;
! 1922: struct scsi_read_dvd_structure_data *buf;
! 1923: int error;
! 1924:
! 1925: buf = malloc(sizeof(*buf), M_TEMP, M_WAITOK);
! 1926: if (buf == NULL)
! 1927: return (ENOMEM);
! 1928: bzero(buf, sizeof(*buf));
! 1929:
! 1930: bzero(&cmd, sizeof(cmd));
! 1931: cmd.opcode = GPCMD_READ_DVD_STRUCTURE;
! 1932: cmd.format = s->type;
! 1933: _lto2b(sizeof(*buf), cmd.length);
! 1934:
! 1935: error = scsi_scsi_cmd(cd->sc_link, (struct scsi_generic *)&cmd,
! 1936: sizeof(cmd), (u_char *)buf, sizeof(*buf), CDRETRIES, 30000, NULL,
! 1937: SCSI_DATA_IN);
! 1938: if (error == 0) {
! 1939: s->manufact.len = _2btol(buf->len);
! 1940: if (s->manufact.len >= 0 && s->manufact.len <= 2048)
! 1941: bcopy(buf->data, s->manufact.value, s->manufact.len);
! 1942: else
! 1943: error = EIO;
! 1944: }
! 1945:
! 1946: free(buf, M_TEMP);
! 1947: return (error);
! 1948: }
! 1949:
! 1950: int
! 1951: dvd_read_struct(cd, s)
! 1952: struct cd_softc *cd;
! 1953: union dvd_struct *s;
! 1954: {
! 1955:
! 1956: switch (s->type) {
! 1957: case DVD_STRUCT_PHYSICAL:
! 1958: return (dvd_read_physical(cd, s));
! 1959: case DVD_STRUCT_COPYRIGHT:
! 1960: return (dvd_read_copyright(cd, s));
! 1961: case DVD_STRUCT_DISCKEY:
! 1962: return (dvd_read_disckey(cd, s));
! 1963: case DVD_STRUCT_BCA:
! 1964: return (dvd_read_bca(cd, s));
! 1965: case DVD_STRUCT_MANUFACT:
! 1966: return (dvd_read_manufact(cd, s));
! 1967: default:
! 1968: return (EINVAL);
! 1969: }
! 1970: }
! 1971:
! 1972: void
! 1973: cd_powerhook(int why, void *arg)
! 1974: {
! 1975: struct cd_softc *cd = arg;
! 1976:
! 1977: /*
! 1978: * When resuming, hardware may have forgotten we locked it. So if
! 1979: * there are any open partitions, lock the CD.
! 1980: */
! 1981: if (why == PWR_RESUME && cd->sc_dk.dk_openmask != 0)
! 1982: scsi_prevent(cd->sc_link, PR_PREVENT,
! 1983: SCSI_IGNORE_ILLEGAL_REQUEST | SCSI_IGNORE_MEDIA_CHANGE);
! 1984: }
! 1985:
! 1986: int
! 1987: cd_interpret_sense(struct scsi_xfer *xs)
! 1988: {
! 1989: struct scsi_sense_data *sense = &xs->sense;
! 1990: struct scsi_link *sc_link = xs->sc_link;
! 1991: u_int8_t skey = sense->flags & SSD_KEY;
! 1992: u_int8_t serr = sense->error_code & SSD_ERRCODE;
! 1993:
! 1994: if (((sc_link->flags & SDEV_OPEN) == 0) ||
! 1995: (serr != SSD_ERRCODE_CURRENT && serr != SSD_ERRCODE_DEFERRED))
! 1996: return (EJUSTRETURN); /* let the generic code handle it */
! 1997:
! 1998: /*
! 1999: * We do custom processing in cd for the unit becoming ready
! 2000: * case. We do not allow xs->retries to be decremented on the
! 2001: * "Unit Becoming Ready" case. This is because CD drives
! 2002: * report "Unit Becoming Ready" when loading media and can
! 2003: * take a long time. Rather than having a massive timeout for
! 2004: * all operations (which would cause other problems), we allow
! 2005: * operations to wait (but be interruptable with Ctrl-C)
! 2006: * forever as long as the drive is reporting that it is
! 2007: * becoming ready. All other cases of not being ready are
! 2008: * handled by the default handler.
! 2009: */
! 2010: switch(skey) {
! 2011: case SKEY_NOT_READY:
! 2012: if ((xs->flags & SCSI_IGNORE_NOT_READY) != 0)
! 2013: return (0);
! 2014: if (ASC_ASCQ(sense) == SENSE_NOT_READY_BECOMING_READY) {
! 2015: SC_DEBUG(sc_link, SDEV_DB1, ("not ready: busy (%#x)\n",
! 2016: sense->add_sense_code_qual));
! 2017: /* don't count this as a retry */
! 2018: xs->retries++;
! 2019: return (scsi_delay(xs, 1));
! 2020: }
! 2021: break;
! 2022: /* XXX more to come here for a few other cases */
! 2023: default:
! 2024: break;
! 2025: }
! 2026: return (EJUSTRETURN); /* use generic handler in scsi_base */
! 2027: }
! 2028:
! 2029: /*
! 2030: * Remove unprocessed buffers from queue.
! 2031: */
! 2032: void
! 2033: cd_kill_buffers(struct cd_softc *cd)
! 2034: {
! 2035: struct buf *dp, *bp;
! 2036: int s;
! 2037:
! 2038: s = splbio();
! 2039: for (dp = &cd->buf_queue; (bp = dp->b_actf) != NULL; ) {
! 2040: dp->b_actf = bp->b_actf;
! 2041:
! 2042: bp->b_error = ENXIO;
! 2043: bp->b_flags |= B_ERROR;
! 2044: biodone(bp);
! 2045: }
! 2046: splx(s);
! 2047: }
CVSweb