|
|
1.1 ! root 1: /* ! 2: * Written by Julian Elischer ([email protected]) ! 3: * for TRW Financial Systems for use under the MACH(2.5) operating system. ! 4: * ! 5: * TRW Financial Systems, in accordance with their agreement with Carnegie ! 6: * Mellon University, makes this software available to CMU to distribute ! 7: * or use in any manner that they see fit as long as this message is kept with ! 8: * the software. For this reason TFS also grants any other persons or ! 9: * organisations permission to use or modify this software. ! 10: * ! 11: * TFS supplies this software to be publicly redistributed ! 12: * on the understanding that TFS is not responsible for the correct ! 13: * functioning of this software in any circumstances. ! 14: * ! 15: */ ! 16: ! 17: /* ! 18: * Ported to run under 386BSD by Julian Elischer ([email protected]) Sept 1992 ! 19: * ! 20: * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE ! 21: * -------------------- ----- ---------------------- ! 22: * CURRENT PATCH LEVEL: 1 00098 ! 23: * -------------------- ----- ---------------------- ! 24: * ! 25: * 16 Feb 93 Julian Elischer ADDED for SCSI system ! 26: */ ! 27: ! 28: #define SPLCD splbio ! 29: #define ESUCCESS 0 ! 30: #include <cd.h> ! 31: #include <sys/types.h> ! 32: #include <sys/param.h> ! 33: #include <sys/dkbad.h> ! 34: #include <sys/systm.h> ! 35: #include <sys/conf.h> ! 36: #include <sys/file.h> ! 37: #include <sys/stat.h> ! 38: #include <sys/ioctl.h> ! 39: #include <sys/buf.h> ! 40: #include <sys/uio.h> ! 41: #include <sys/malloc.h> ! 42: #include <sys/cdio.h> ! 43: ! 44: #include <sys/errno.h> ! 45: #include <sys/disklabel.h> ! 46: #include <scsi/scsi_all.h> ! 47: #include <scsi/scsi_cd.h> ! 48: #include <scsi/scsi_disk.h> /* rw_big and start_stop come from there */ ! 49: #include <scsi/scsiconf.h> ! 50: ! 51: long int cdstrats,cdqueues; ! 52: ! 53: ! 54: #ifdef DDB ! 55: int Debugger(); ! 56: #else ! 57: #define Debugger() ! 58: #endif ! 59: ! 60: ! 61: #define PAGESIZ 4096 ! 62: #define SECSIZE 2048 /* XXX */ /* default only */ ! 63: #define CDOUTSTANDING 2 ! 64: #define CDQSIZE 4 ! 65: #define CD_RETRIES 4 ! 66: ! 67: #define UNITSHIFT 3 ! 68: #define PARTITION(z) (minor(z) & 0x07) ! 69: #define RAW_PART 3 ! 70: #define UNIT(z) ( (minor(z) >> UNITSHIFT) ) ! 71: ! 72: ! 73: extern int hz; ! 74: int cd_done(); ! 75: int cdstrategy(); ! 76: int cd_debug = 0; ! 77: ! 78: struct buf cd_buf_queue[NCD]; ! 79: struct scsi_xfer cd_scsi_xfer[NCD][CDOUTSTANDING]; /* XXX */ ! 80: struct scsi_xfer *cd_free_xfer[NCD]; ! 81: int cd_xfer_block_wait[NCD]; ! 82: ! 83: struct cd_data ! 84: { ! 85: int flags; ! 86: #define CDVALID 0x02 /* PARAMS LOADED */ ! 87: #define CDINIT 0x04 /* device has been init'd */ ! 88: #define CDWAIT 0x08 /* device has someone waiting */ ! 89: #define CDHAVELABEL 0x10 /* have read the label */ ! 90: struct scsi_switch *sc_sw; /* address of scsi low level switch */ ! 91: int ctlr; /* so they know which one we want */ ! 92: int targ; /* our scsi target ID */ ! 93: int lu; /* out scsi lu */ ! 94: int cmdscount; /* cmds allowed outstanding by board*/ ! 95: struct cd_parms ! 96: { ! 97: int blksize; ! 98: u_long disksize; /* total number sectors */ ! 99: }params; ! 100: struct disklabel disklabel; ! 101: int partflags[MAXPARTITIONS]; /* per partition flags */ ! 102: #define CDOPEN 0x01 ! 103: int openparts; /* one bit for each open partition */ ! 104: }cd_data[NCD]; ! 105: ! 106: #define CD_STOP 0 ! 107: #define CD_START 1 ! 108: #define CD_EJECT -2 ! 109: ! 110: ! 111: static int next_cd_unit = 0; ! 112: /***********************************************************************\ ! 113: * The routine called by the low level scsi routine when it discovers * ! 114: * A device suitable for this driver * ! 115: \***********************************************************************/ ! 116: int cdattach(ctlr,targ,lu,scsi_switch) ! 117: struct scsi_switch *scsi_switch; ! 118: { ! 119: int unit,i; ! 120: unsigned char *tbl; ! 121: struct cd_data *cd; ! 122: struct cd_parms *dp; ! 123: ! 124: unit = next_cd_unit++; ! 125: cd = cd_data + unit; ! 126: dp = &(cd->params); ! 127: if(scsi_debug & PRINTROUTINES) printf("cdattach: "); ! 128: /*******************************************************\ ! 129: * Check we have the resources for another drive * ! 130: \*******************************************************/ ! 131: if( unit >= NCD) ! 132: { ! 133: printf("Too many scsi CDs..(%d > %d) reconfigure kernel",(unit + 1),NCD); ! 134: return(0); ! 135: } ! 136: /*******************************************************\ ! 137: * Store information needed to contact our base driver * ! 138: \*******************************************************/ ! 139: cd->sc_sw = scsi_switch; ! 140: cd->ctlr = ctlr; ! 141: cd->targ = targ; ! 142: cd->lu = lu; ! 143: cd->cmdscount = CDOUTSTANDING; /* XXX (ask the board) */ ! 144: ! 145: ! 146: i = cd->cmdscount; ! 147: while(i-- ) ! 148: { ! 149: cd_scsi_xfer[unit][i].next = cd_free_xfer[unit]; ! 150: cd_free_xfer[unit] = &cd_scsi_xfer[unit][i]; ! 151: } ! 152: /*******************************************************\ ! 153: * Use the subdriver to request information regarding * ! 154: * the drive. We cannot use interrupts yet, so the * ! 155: * request must specify this. * ! 156: \*******************************************************/ ! 157: cd_get_parms(unit, SCSI_NOSLEEP | SCSI_NOMASK); ! 158: if(dp->disksize) ! 159: { ! 160: printf("cd present\n"); ! 161: } ! 162: else ! 163: { ! 164: printf("drive empty\n"); ! 165: } ! 166: cd->flags |= CDINIT; ! 167: return; ! 168: ! 169: } ! 170: ! 171: ! 172: ! 173: /*******************************************************\ ! 174: * open the device. Make sure the partition info * ! 175: * is a up-to-date as can be. * ! 176: \*******************************************************/ ! 177: cdopen(dev) ! 178: { ! 179: int errcode = 0; ! 180: int unit, part; ! 181: struct cd_parms cd_parms; ! 182: struct cd_data *cd ; ! 183: ! 184: unit = UNIT(dev); ! 185: part = PARTITION(dev); ! 186: cd = cd_data + unit; ! 187: if(scsi_debug & (PRINTROUTINES | TRACEOPENS)) ! 188: printf("cdopen: dev=0x%x (unit %d (of %d),partition %d)\n" ! 189: , dev, unit, NCD, part); ! 190: /*******************************************************\ ! 191: * Check the unit is legal * ! 192: \*******************************************************/ ! 193: if ( unit >= NCD ) ! 194: { ! 195: return(ENXIO); ! 196: } ! 197: /*******************************************************\ ! 198: * Make sure the disk has been initialised * ! 199: * At some point in the future, get the scsi driver * ! 200: * to look for a new device if we are not initted * ! 201: \*******************************************************/ ! 202: if (! (cd->flags & CDINIT)) ! 203: return(ENXIO); ! 204: ! 205: /*******************************************************\ ! 206: * If it's been invalidated, and not everybody has * ! 207: * closed it then forbid re-entry. * ! 208: * (may have changed media) * ! 209: \*******************************************************/ ! 210: if ((! (cd->flags & CDVALID)) ! 211: && ( cd->openparts)) ! 212: return(ENXIO); ! 213: /*******************************************************\ ! 214: * Check that it is still responding and ok. * ! 215: * if the media has been changed this will result in a * ! 216: * "unit attention" error which the error code will * ! 217: * disregard because the CDVALID flag is not yet set * ! 218: \*******************************************************/ ! 219: if (cd_req_sense(unit, SCSI_SILENT) != 0) { ! 220: if(scsi_debug & TRACEOPENS) ! 221: printf("not reponding\n"); ! 222: return(ENXIO); ! 223: } ! 224: if(scsi_debug & TRACEOPENS) ! 225: printf("Device present\n"); ! 226: /*******************************************************\ ! 227: * In case it is a funny one, tell it to start * ! 228: * not needed for hard drives * ! 229: \*******************************************************/ ! 230: cd_start_unit(unit,part,CD_START); ! 231: cd_prevent_unit(unit,PR_PREVENT,SCSI_SILENT); ! 232: if(scsi_debug & TRACEOPENS) ! 233: printf("started "); ! 234: /*******************************************************\ ! 235: * Load the physical device parameters * ! 236: \*******************************************************/ ! 237: cd_get_parms(unit, 0); ! 238: if(scsi_debug & TRACEOPENS) ! 239: printf("Params loaded "); ! 240: /*******************************************************\ ! 241: * Load the partition info if not already loaded * ! 242: \*******************************************************/ ! 243: cdgetdisklabel(unit); ! 244: if(scsi_debug & TRACEOPENS) ! 245: printf("Disklabel fabricated "); ! 246: /*******************************************************\ ! 247: * Check the partition is legal * ! 248: \*******************************************************/ ! 249: if (( part >= cd->disklabel.d_npartitions ) ! 250: && (part != RAW_PART)) ! 251: { ! 252: if(scsi_debug & TRACEOPENS) ! 253: printf("partition %d > %d\n",part ! 254: ,cd->disklabel.d_npartitions); ! 255: cd_prevent_unit(unit,PR_ALLOW,SCSI_SILENT); ! 256: return(ENXIO); ! 257: } ! 258: /*******************************************************\ ! 259: * Check that the partition exists * ! 260: \*******************************************************/ ! 261: if (( cd->disklabel.d_partitions[part].p_fstype != FS_UNUSED ) ! 262: || (part == RAW_PART)) ! 263: { ! 264: cd->partflags[part] |= CDOPEN; ! 265: cd->openparts |= (1 << part); ! 266: if(scsi_debug & TRACEOPENS) ! 267: printf("open complete\n"); ! 268: cd->flags |= CDVALID; ! 269: } ! 270: else ! 271: { ! 272: if(scsi_debug & TRACEOPENS) ! 273: printf("part %d type UNUSED\n",part); ! 274: cd_prevent_unit(unit,PR_ALLOW,SCSI_SILENT); ! 275: return(ENXIO); ! 276: } ! 277: return(0); ! 278: } ! 279: ! 280: /*******************************************************\ ! 281: * Get ownership of a scsi_xfer structure * ! 282: * If need be, sleep on it, until it comes free * ! 283: \*******************************************************/ ! 284: struct scsi_xfer *cd_get_xs(unit,flags) ! 285: int flags; ! 286: int unit; ! 287: { ! 288: struct scsi_xfer *xs; ! 289: int s; ! 290: ! 291: if(flags & (SCSI_NOSLEEP | SCSI_NOMASK)) ! 292: { ! 293: if (xs = cd_free_xfer[unit]) ! 294: { ! 295: cd_free_xfer[unit] = xs->next; ! 296: xs->flags = 0; ! 297: } ! 298: } ! 299: else ! 300: { ! 301: s = SPLCD(); ! 302: while (!(xs = cd_free_xfer[unit])) ! 303: { ! 304: cd_xfer_block_wait[unit]++; /* someone waiting! */ ! 305: sleep((caddr_t)&cd_free_xfer[unit], PRIBIO+1); ! 306: cd_xfer_block_wait[unit]--; ! 307: } ! 308: cd_free_xfer[unit] = xs->next; ! 309: splx(s); ! 310: xs->flags = 0; ! 311: } ! 312: return(xs); ! 313: } ! 314: ! 315: /*******************************************************\ ! 316: * Free a scsi_xfer, wake processes waiting for it * ! 317: \*******************************************************/ ! 318: cd_free_xs(unit,xs,flags) ! 319: struct scsi_xfer *xs; ! 320: int unit; ! 321: int flags; ! 322: { ! 323: int s; ! 324: ! 325: if(flags & SCSI_NOMASK) ! 326: { ! 327: if (cd_xfer_block_wait[unit]) ! 328: { ! 329: printf("doing a wakeup from NOMASK mode\n"); ! 330: wakeup((caddr_t)&cd_free_xfer[unit]); ! 331: } ! 332: xs->next = cd_free_xfer[unit]; ! 333: cd_free_xfer[unit] = xs; ! 334: } ! 335: else ! 336: { ! 337: s = SPLCD(); ! 338: if (cd_xfer_block_wait[unit]) ! 339: wakeup((caddr_t)&cd_free_xfer[unit]); ! 340: xs->next = cd_free_xfer[unit]; ! 341: cd_free_xfer[unit] = xs; ! 342: splx(s); ! 343: } ! 344: } ! 345: ! 346: /*******************************************************\ ! 347: * trim the size of the transfer if needed, * ! 348: * called by physio * ! 349: * basically the smaller of our max and the scsi driver's* ! 350: * minphys (note we have no max ourselves) * ! 351: \*******************************************************/ ! 352: /* Trim buffer length if buffer-size is bigger than page size */ ! 353: void cdminphys(bp) ! 354: struct buf *bp; ! 355: { ! 356: (*(cd_data[UNIT(bp->b_dev)].sc_sw->scsi_minphys))(bp); ! 357: } ! 358: ! 359: /*******************************************************\ ! 360: * Actually translate the requested transfer into * ! 361: * one the physical driver can understand * ! 362: * The transfer is described by a buf and will include * ! 363: * only one physical transfer. * ! 364: \*******************************************************/ ! 365: ! 366: int cdstrategy(bp) ! 367: struct buf *bp; ! 368: { ! 369: struct buf *dp; ! 370: unsigned int opri; ! 371: struct cd_data *cd ; ! 372: int unit; ! 373: ! 374: cdstrats++; ! 375: unit = UNIT((bp->b_dev)); ! 376: cd = cd_data + unit; ! 377: if(scsi_debug & PRINTROUTINES) printf("\ncdstrategy "); ! 378: if(scsi_debug & SHOWREQUESTS) printf("cd%d: %d bytes @ blk%d\n", ! 379: unit,bp->b_bcount,bp->b_blkno); ! 380: cdminphys(bp); ! 381: /*******************************************************\ ! 382: * If the device has been made invalid, error out * ! 383: * maybe the media changed * ! 384: \*******************************************************/ ! 385: if(!(cd->flags & CDVALID)) ! 386: { ! 387: bp->b_error = EIO; ! 388: goto bad; ! 389: } ! 390: /*******************************************************\ ! 391: * can't ever write to a CD * ! 392: \*******************************************************/ ! 393: if ((bp->b_flags & B_READ) == 0) { ! 394: bp->b_error = EROFS; ! 395: goto bad; ! 396: } ! 397: /*******************************************************\ ! 398: * If it's a null transfer, return immediatly * ! 399: \*******************************************************/ ! 400: if (bp->b_bcount == 0) { ! 401: goto done; ! 402: } ! 403: ! 404: /*******************************************************\ ! 405: * Decide which unit and partition we are talking about * ! 406: \*******************************************************/ ! 407: if(PARTITION(bp->b_dev) != RAW_PART) ! 408: { ! 409: if (!(cd->flags & CDHAVELABEL)) ! 410: { ! 411: bp->b_error = EIO; ! 412: goto bad; ! 413: } ! 414: /* ! 415: * do bounds checking, adjust transfer. if error, process. ! 416: * if end of partition, just return ! 417: */ ! 418: if (bounds_check_with_label(bp,&cd->disklabel,1) <= 0) ! 419: goto done; ! 420: /* otherwise, process transfer request */ ! 421: } ! 422: ! 423: opri = SPLCD(); ! 424: dp = &cd_buf_queue[unit]; ! 425: ! 426: /*******************************************************\ ! 427: * Place it in the queue of disk activities for this disk* ! 428: \*******************************************************/ ! 429: disksort(dp, bp); ! 430: ! 431: /*******************************************************\ ! 432: * Tell the device to get going on the transfer if it's * ! 433: * not doing anything, otherwise just wait for completion* ! 434: \*******************************************************/ ! 435: cdstart(unit); ! 436: ! 437: splx(opri); ! 438: return; ! 439: bad: ! 440: bp->b_flags |= B_ERROR; ! 441: done: ! 442: ! 443: /*******************************************************\ ! 444: * Correctly set the buf to indicate a completed xfer * ! 445: \*******************************************************/ ! 446: bp->b_resid = bp->b_bcount; ! 447: biodone(bp); ! 448: return; ! 449: } ! 450: ! 451: /***************************************************************\ ! 452: * cdstart looks to see if there is a buf waiting for the device * ! 453: * and that the device is not already busy. If both are true, * ! 454: * It deques the buf and creates a scsi command to perform the * ! 455: * transfer in the buf. The transfer request will call cd_done * ! 456: * on completion, which will in turn call this routine again * ! 457: * so that the next queued transfer is performed. * ! 458: * The bufs are queued by the strategy routine (cdstrategy) * ! 459: * * ! 460: * This routine is also called after other non-queued requests * ! 461: * have been made of the scsi driver, to ensure that the queue * ! 462: * continues to be drained. * ! 463: * * ! 464: * must be called at the correct (highish) spl level * ! 465: \***************************************************************/ ! 466: /* cdstart() is called at SPLCD from cdstrategy and cd_done*/ ! 467: cdstart(unit) ! 468: int unit; ! 469: { ! 470: register struct buf *bp = 0; ! 471: register struct buf *dp; ! 472: struct scsi_xfer *xs; ! 473: struct scsi_rw_big cmd; ! 474: int blkno, nblk; ! 475: struct cd_data *cd = cd_data + unit; ! 476: struct partition *p ; ! 477: ! 478: if(scsi_debug & PRINTROUTINES) printf("cdstart%d ",unit); ! 479: /*******************************************************\ ! 480: * See if there is a buf to do and we are not already * ! 481: * doing one * ! 482: \*******************************************************/ ! 483: if(!cd_free_xfer[unit]) ! 484: { ! 485: return; /* none for us, unit already underway */ ! 486: } ! 487: ! 488: if(cd_xfer_block_wait[unit]) /* there is one, but a special waits */ ! 489: { ! 490: return; /* give the special that's waiting a chance to run */ ! 491: } ! 492: ! 493: ! 494: dp = &cd_buf_queue[unit]; ! 495: if ((bp = dp->b_actf) != NULL) /* yes, an assign */ ! 496: { ! 497: dp->b_actf = bp->av_forw; ! 498: } ! 499: else ! 500: { ! 501: return; ! 502: } ! 503: ! 504: xs=cd_get_xs(unit,0); /* ok we can grab it */ ! 505: xs->flags = INUSE; /* Now ours */ ! 506: /***************************************************************\ ! 507: * Should reject all queued entries if CDVALID is not true * ! 508: \***************************************************************/ ! 509: if(!(cd->flags & CDVALID)) ! 510: { ! 511: goto bad; /* no I/O.. media changed or something */ ! 512: } ! 513: ! 514: /*******************************************************\ ! 515: * We have a buf, now we should move the data into * ! 516: * a scsi_xfer definition and try start it * ! 517: \*******************************************************/ ! 518: /*******************************************************\ ! 519: * First, translate the block to absolute * ! 520: * and put it in terms of the logical blocksize of the * ! 521: * device.. * ! 522: \*******************************************************/ ! 523: p = cd->disklabel.d_partitions + PARTITION(bp->b_dev); ! 524: blkno = ((bp->b_blkno / (cd->params.blksize/512)) + p->p_offset); ! 525: nblk = (bp->b_bcount + (cd->params.blksize - 1)) / (cd->params.blksize); ! 526: ! 527: /*******************************************************\ ! 528: * Fill out the scsi command * ! 529: \*******************************************************/ ! 530: bzero(&cmd, sizeof(cmd)); ! 531: cmd.op_code = READ_BIG; ! 532: cmd.addr_3 = (blkno & 0xff000000) >> 24; ! 533: cmd.addr_2 = (blkno & 0xff0000) >> 16; ! 534: cmd.addr_1 = (blkno & 0xff00) >> 8; ! 535: cmd.addr_0 = blkno & 0xff; ! 536: cmd.length2 = (nblk & 0xff00) >> 8; ! 537: cmd.length1 = (nblk & 0xff); ! 538: /*******************************************************\ ! 539: * Fill out the scsi_xfer structure * ! 540: * Note: we cannot sleep as we may be an interrupt * ! 541: \*******************************************************/ ! 542: xs->flags |= SCSI_NOSLEEP; ! 543: xs->adapter = cd->ctlr; ! 544: xs->targ = cd->targ; ! 545: xs->lu = cd->lu; ! 546: xs->retries = CD_RETRIES; ! 547: xs->timeout = 10000;/* 10000 millisecs for a disk !*/ ! 548: xs->cmd = (struct scsi_generic *)&cmd; ! 549: xs->cmdlen = sizeof(cmd); ! 550: xs->resid = bp->b_bcount; ! 551: xs->when_done = cd_done; ! 552: xs->done_arg = unit; ! 553: xs->done_arg2 = (int)xs; ! 554: xs->error = XS_NOERROR; ! 555: xs->bp = bp; ! 556: xs->data = (u_char *)bp->b_un.b_addr; ! 557: xs->datalen = bp->b_bcount; ! 558: ! 559: /*******************************************************\ ! 560: * Pass all this info to the scsi driver. * ! 561: \*******************************************************/ ! 562: if ( (*(cd->sc_sw->scsi_cmd))(xs) != SUCCESSFULLY_QUEUED) ! 563: { ! 564: printf("cd%d: oops not queued",unit); ! 565: goto bad; ! 566: } ! 567: cdqueues++; ! 568: return; ! 569: bad: xs->error = XS_DRIVER_STUFFUP; ! 570: cd_done(unit,xs); ! 571: } ! 572: ! 573: /*******************************************************\ ! 574: * This routine is called by the scsi interrupt when * ! 575: * the transfer is complete. (or failed) * ! 576: \*******************************************************/ ! 577: int cd_done(unit,xs) ! 578: int unit; ! 579: struct scsi_xfer *xs; ! 580: { ! 581: struct buf *bp; ! 582: int retval; ! 583: ! 584: if(scsi_debug & PRINTROUTINES) printf("cd_done%d ",unit); ! 585: if (! (xs->flags & INUSE)) /* paranoia always pays off */ ! 586: panic("scsi_xfer not in use!"); ! 587: if(bp = xs->bp) ! 588: { ! 589: switch(xs->error) ! 590: { ! 591: case XS_NOERROR: ! 592: bp->b_error = 0; ! 593: bp->b_resid = 0; ! 594: break; ! 595: ! 596: case XS_SENSE: ! 597: retval = (cd_interpret_sense(unit,xs)); ! 598: if(retval) ! 599: { ! 600: bp->b_flags |= B_ERROR; ! 601: bp->b_error = retval; ! 602: } ! 603: break; ! 604: ! 605: case XS_TIMEOUT: ! 606: printf("cd%d timeout\n",unit); ! 607: ! 608: case XS_BUSY: ! 609: /***********************************\ ! 610: * Just resubmit it straight back to * ! 611: * the SCSI driver to try it again * ! 612: \***********************************/ ! 613: if(xs->retries--) ! 614: { ! 615: xs->error = XS_NOERROR; ! 616: xs->flags &= ~ITSDONE; ! 617: if ( (*(cd_data[unit].sc_sw->scsi_cmd))(xs) ! 618: == SUCCESSFULLY_QUEUED) ! 619: { /* shhh! don't wake the job, ok? */ ! 620: /* don't tell cdstart either, */ ! 621: return; ! 622: } ! 623: /* xs->error is set by the scsi driver */ ! 624: } /* Fall through */ ! 625: ! 626: case XS_DRIVER_STUFFUP: ! 627: bp->b_flags |= B_ERROR; ! 628: bp->b_error = EIO; ! 629: break; ! 630: default: ! 631: printf("cd%d: unknown error category from scsi driver\n" ! 632: ,unit); ! 633: } ! 634: biodone(bp); ! 635: cd_free_xs(unit,xs,0); ! 636: cdstart(unit); /* If there's anything waiting.. do it */ ! 637: } ! 638: else /* special has finished */ ! 639: { ! 640: wakeup(xs); ! 641: } ! 642: } ! 643: /*******************************************************\ ! 644: * Perform special action on behalf of the user * ! 645: * Knows about the internals of this device * ! 646: \*******************************************************/ ! 647: cdioctl(dev_t dev, int cmd, caddr_t addr, int flag) ! 648: { ! 649: int error = 0; ! 650: unsigned int opri; ! 651: unsigned char unit, part; ! 652: register struct cd_data *cd; ! 653: ! 654: ! 655: /*******************************************************\ ! 656: * Find the device that the user is talking about * ! 657: \*******************************************************/ ! 658: unit = UNIT(dev); ! 659: part = PARTITION(dev); ! 660: cd = &cd_data[unit]; ! 661: if(scsi_debug & PRINTROUTINES) printf("cdioctl%d ",unit); ! 662: ! 663: /*******************************************************\ ! 664: * If the device is not valid.. abandon ship * ! 665: \*******************************************************/ ! 666: if (!(cd_data[unit].flags & CDVALID)) ! 667: return(EIO); ! 668: switch(cmd) ! 669: { ! 670: ! 671: case DIOCSBAD: ! 672: error = EINVAL; ! 673: break; ! 674: ! 675: case DIOCGDINFO: ! 676: *(struct disklabel *)addr = cd->disklabel; ! 677: break; ! 678: ! 679: case DIOCGPART: ! 680: ((struct partinfo *)addr)->disklab = &cd->disklabel; ! 681: ((struct partinfo *)addr)->part = ! 682: &cd->disklabel.d_partitions[PARTITION(dev)]; ! 683: break; ! 684: ! 685: case DIOCWDINFO: ! 686: case DIOCSDINFO: ! 687: if ((flag & FWRITE) == 0) ! 688: error = EBADF; ! 689: else ! 690: error = setdisklabel(&cd->disklabel, ! 691: (struct disklabel *)addr, ! 692: /*(cd->flags & DKFL_BSDLABEL) ? cd->openparts : */0, ! 693: 0); ! 694: if (error == 0) { ! 695: cd->flags |= CDHAVELABEL; ! 696: } ! 697: break; ! 698: ! 699: case DIOCWLABEL: ! 700: error = EBADF; ! 701: break; ! 702: ! 703: case CDIOCPLAYTRACKS: ! 704: { ! 705: struct ioc_play_track *args ! 706: = (struct ioc_play_track *)addr; ! 707: struct cd_mode_data data; ! 708: if(error = cd_get_mode(unit,&data,AUDIO_PAGE)) ! 709: break; ! 710: data.page.audio.sotc = 0; ! 711: data.page.audio.immed = 1; ! 712: if(error = cd_set_mode(unit,&data)) ! 713: break; ! 714: return(cd_play_tracks(unit ! 715: ,args->start_track ! 716: ,args->start_index ! 717: ,args->end_track ! 718: ,args->end_index ! 719: )); ! 720: } ! 721: break; ! 722: case CDIOCPLAYBLOCKS: ! 723: { ! 724: struct ioc_play_blocks *args ! 725: = (struct ioc_play_blocks *)addr; ! 726: struct cd_mode_data data; ! 727: if(error = cd_get_mode(unit,&data,AUDIO_PAGE)) ! 728: break; ! 729: data.page.audio.sotc = 0; ! 730: data.page.audio.immed = 1; ! 731: if(error = cd_set_mode(unit,&data)) ! 732: break; ! 733: return(cd_play(unit,args->blk,args->len)); ! 734: ! 735: ! 736: } ! 737: break; ! 738: case CDIOCREADSUBCHANNEL: ! 739: { ! 740: struct ioc_read_subchannel *args ! 741: = (struct ioc_read_subchannel *)addr; ! 742: struct cd_sub_channel_info data; ! 743: int len=args->data_len; ! 744: if(len>sizeof(data)|| ! 745: len<sizeof(struct cd_sub_channel_header)) { ! 746: error=EINVAL; ! 747: break; ! 748: } ! 749: if(error = cd_read_subchannel(unit,args->address_format, ! 750: args->data_format,args->track,&data,len)) { ! 751: break; ! 752: } ! 753: len=MIN(len,((data.header.data_len[0]<<8)+data.header.data_len[1]+ ! 754: sizeof(struct cd_sub_channel_header))); ! 755: if(copyout(&data,args->data,len)!=0) { ! 756: error=EFAULT; ! 757: } ! 758: } ! 759: break; ! 760: case CDIOREADTOCHEADER: ! 761: { ! 762: struct ioc_toc_header th; ! 763: if( error = cd_read_toc(unit,0,0,&th,sizeof(th))) ! 764: break; ! 765: th.len=(th.len&0xff)<<8+((th.len>>8)&0xff); ! 766: bcopy(&th,addr,sizeof(th)); ! 767: } ! 768: break; ! 769: case CDIOREADTOCENTRYS: ! 770: { ! 771: struct ioc_read_toc_entry *te= ! 772: (struct ioc_read_toc_entry *)addr; ! 773: struct cd_toc_entry data[65]; ! 774: struct ioc_toc_header *th; ! 775: int len=te->data_len; ! 776: th=(struct ioc_toc_header *)data; ! 777: ! 778: if(len>sizeof(data) || len<sizeof(struct cd_toc_entry)) { ! 779: error=EINVAL; ! 780: break; ! 781: } ! 782: if(error = cd_read_toc(unit,te->address_format, ! 783: te->starting_track, ! 784: data, ! 785: len)) ! 786: break; ! 787: len=MIN(len,((((th->len&0xff)<<8)+((th->len>>8)))+ ! 788: sizeof(*th))); ! 789: if(copyout(th,te->data,len)!=0) { ! 790: error=EFAULT; ! 791: } ! 792: ! 793: } ! 794: break; ! 795: case CDIOCSETPATCH: ! 796: { ! 797: struct ioc_patch *arg = (struct ioc_patch *)addr; ! 798: struct cd_mode_data data; ! 799: if(error = cd_get_mode(unit,&data,AUDIO_PAGE)) ! 800: break; ! 801: data.page.audio.port[LEFT_PORT].channels = arg->patch[0]; ! 802: data.page.audio.port[RIGHT_PORT].channels = arg->patch[1]; ! 803: data.page.audio.port[2].channels = arg->patch[2]; ! 804: data.page.audio.port[3].channels = arg->patch[3]; ! 805: if(error = cd_set_mode(unit,&data)) ! 806: break; ! 807: } ! 808: break; ! 809: case CDIOCGETVOL: ! 810: { ! 811: struct ioc_vol *arg = (struct ioc_vol *)addr; ! 812: struct cd_mode_data data; ! 813: if(error = cd_get_mode(unit,&data,AUDIO_PAGE)) ! 814: break; ! 815: arg->vol[LEFT_PORT] = data.page.audio.port[LEFT_PORT].volume; ! 816: arg->vol[RIGHT_PORT] = data.page.audio.port[RIGHT_PORT].volume; ! 817: arg->vol[2] = data.page.audio.port[2].volume; ! 818: arg->vol[3] = data.page.audio.port[3].volume; ! 819: } ! 820: break; ! 821: case CDIOCSETVOL: ! 822: { ! 823: struct ioc_vol *arg = (struct ioc_vol *)addr; ! 824: struct cd_mode_data data; ! 825: if(error = cd_get_mode(unit,&data,AUDIO_PAGE)) ! 826: break; ! 827: data.page.audio.port[LEFT_PORT].volume = arg->vol[LEFT_PORT]; ! 828: data.page.audio.port[RIGHT_PORT].volume = arg->vol[RIGHT_PORT]; ! 829: data.page.audio.port[2].volume = arg->vol[2]; ! 830: data.page.audio.port[3].volume = arg->vol[3]; ! 831: if(error = cd_set_mode(unit,&data)) ! 832: break; ! 833: } ! 834: break; ! 835: case CDIOCSETMONO: ! 836: { ! 837: struct ioc_vol *arg = (struct ioc_vol *)addr; ! 838: struct cd_mode_data data; ! 839: if(error = cd_get_mode(unit,&data,AUDIO_PAGE)) ! 840: break; ! 841: data.page.audio.port[LEFT_PORT].channels = LEFT_CHANNEL|RIGHT_CHANNEL|4|8; ! 842: data.page.audio.port[RIGHT_PORT].channels = LEFT_CHANNEL|RIGHT_CHANNEL; ! 843: data.page.audio.port[2].channels = 0; ! 844: data.page.audio.port[3].channels = 0; ! 845: if(error = cd_set_mode(unit,&data)) ! 846: break; ! 847: } ! 848: break; ! 849: case CDIOCSETSTERIO: ! 850: { ! 851: struct ioc_vol *arg = (struct ioc_vol *)addr; ! 852: struct cd_mode_data data; ! 853: if(error = cd_get_mode(unit,&data,AUDIO_PAGE)) ! 854: break; ! 855: data.page.audio.port[LEFT_PORT].channels = LEFT_CHANNEL; ! 856: data.page.audio.port[RIGHT_PORT].channels = RIGHT_CHANNEL; ! 857: data.page.audio.port[2].channels = 0; ! 858: data.page.audio.port[3].channels = 0; ! 859: if(error = cd_set_mode(unit,&data)) ! 860: break; ! 861: } ! 862: break; ! 863: case CDIOCSETMUTE: ! 864: { ! 865: struct ioc_vol *arg = (struct ioc_vol *)addr; ! 866: struct cd_mode_data data; ! 867: if(error = cd_get_mode(unit,&data,AUDIO_PAGE)) ! 868: break; ! 869: data.page.audio.port[LEFT_PORT].channels = 0; ! 870: data.page.audio.port[RIGHT_PORT].channels = 0; ! 871: data.page.audio.port[2].channels = 0; ! 872: data.page.audio.port[3].channels = 0; ! 873: if(error = cd_set_mode(unit,&data)) ! 874: break; ! 875: } ! 876: break; ! 877: case CDIOCSETLEFT: ! 878: { ! 879: struct ioc_vol *arg = (struct ioc_vol *)addr; ! 880: struct cd_mode_data data; ! 881: if(error = cd_get_mode(unit,&data,AUDIO_PAGE)) ! 882: break; ! 883: data.page.audio.port[LEFT_PORT].channels = 15; ! 884: data.page.audio.port[RIGHT_PORT].channels = 15; ! 885: data.page.audio.port[2].channels = 15; ! 886: data.page.audio.port[3].channels = 15; ! 887: if(error = cd_set_mode(unit,&data)) ! 888: break; ! 889: } ! 890: break; ! 891: case CDIOCSETRIGHT: ! 892: { ! 893: struct ioc_vol *arg = (struct ioc_vol *)addr; ! 894: struct cd_mode_data data; ! 895: if(error = cd_get_mode(unit,&data,AUDIO_PAGE)) ! 896: break; ! 897: data.page.audio.port[LEFT_PORT].channels = RIGHT_CHANNEL; ! 898: data.page.audio.port[RIGHT_PORT].channels = RIGHT_CHANNEL; ! 899: data.page.audio.port[2].channels = 0; ! 900: data.page.audio.port[3].channels = 0; ! 901: if(error = cd_set_mode(unit,&data)) ! 902: break; ! 903: } ! 904: break; ! 905: case CDIOCRESUME: ! 906: error = cd_pause(unit,1); ! 907: break; ! 908: case CDIOCPAUSE: ! 909: error = cd_pause(unit,0); ! 910: break; ! 911: case CDIOCSTART: ! 912: error = cd_start_unit(unit,part,CD_START); ! 913: break; ! 914: case CDIOCSTOP: ! 915: error = cd_start_unit(unit,part,CD_STOP); ! 916: break; ! 917: case CDIOCEJECT: ! 918: error = cd_start_unit(unit,part,CD_EJECT); ! 919: break; ! 920: case CDIOCSETDEBUG: ! 921: scsi_debug = 0xfff; cd_debug = 0xfff; ! 922: break; ! 923: case CDIOCCLRDEBUG: ! 924: scsi_debug = 0; cd_debug = 0; ! 925: break; ! 926: case CDIOCRESET: ! 927: return(cd_reset(unit)); ! 928: break; ! 929: default: ! 930: error = ENOTTY; ! 931: break; ! 932: } ! 933: return (error); ! 934: } ! 935: ! 936: ! 937: /*******************************************************\ ! 938: * Load the label information on the named device * ! 939: * * ! 940: * EVENTUALLY take information about different * ! 941: * data tracks from the TOC and put it in the disklabel * ! 942: \*******************************************************/ ! 943: int cdgetdisklabel(unit) ! 944: unsigned char unit; ! 945: { ! 946: /*unsigned int n, m;*/ ! 947: char *errstring; ! 948: struct dos_partition *dos_partition_p; ! 949: struct cd_data *cd = cd_data + unit; ! 950: ! 951: /*******************************************************\ ! 952: * If the inflo is already loaded, use it * ! 953: \*******************************************************/ ! 954: if(cd->flags & CDHAVELABEL) return; ! 955: ! 956: bzero(&cd->disklabel,sizeof(struct disklabel)); ! 957: /*******************************************************\ ! 958: * make partition 3 the whole disk in case of failure * ! 959: * then get pdinfo * ! 960: \*******************************************************/ ! 961: strncpy(cd->disklabel.d_typename,"scsi cd_rom",16); ! 962: strncpy(cd->disklabel.d_packname,"ficticious",16); ! 963: cd->disklabel.d_secsize = cd->params.blksize; /* as long as it's not 0 */ ! 964: cd->disklabel.d_nsectors = 100; ! 965: cd->disklabel.d_ntracks = 1; ! 966: cd->disklabel.d_ncylinders = (cd->params.disksize / 100) + 1; ! 967: cd->disklabel.d_secpercyl = 100; ! 968: cd->disklabel.d_secperunit = cd->params.disksize; ! 969: cd->disklabel.d_rpm = 300; ! 970: cd->disklabel.d_interleave = 1; ! 971: cd->disklabel.d_flags = D_REMOVABLE; ! 972: ! 973: cd->disklabel.d_npartitions = 1; ! 974: cd->disklabel.d_partitions[0].p_offset = 0; ! 975: cd->disklabel.d_partitions[0].p_size = cd->params.disksize; ! 976: cd->disklabel.d_partitions[0].p_fstype = 9; ! 977: ! 978: cd->disklabel.d_magic = DISKMAGIC; ! 979: cd->disklabel.d_magic2 = DISKMAGIC; ! 980: cd->disklabel.d_checksum = dkcksum(&(cd->disklabel)); ! 981: ! 982: /*******************************************************\ ! 983: * Signal to other users and routines that we now have a * ! 984: * disklabel that represents the media (maybe) * ! 985: \*******************************************************/ ! 986: cd->flags |= CDHAVELABEL; ! 987: return(ESUCCESS); ! 988: } ! 989: ! 990: /*******************************************************\ ! 991: * Find out form the device what it's capacity is * ! 992: \*******************************************************/ ! 993: cd_size(unit, flags) ! 994: { ! 995: struct scsi_read_cd_cap_data rdcap; ! 996: struct scsi_read_cd_capacity scsi_cmd; ! 997: int size; ! 998: int blksize; ! 999: ! 1000: /*******************************************************\ ! 1001: * make up a scsi command and ask the scsi driver to do * ! 1002: * it for you. * ! 1003: \*******************************************************/ ! 1004: bzero(&scsi_cmd, sizeof(scsi_cmd)); ! 1005: scsi_cmd.op_code = READ_CD_CAPACITY; ! 1006: ! 1007: /*******************************************************\ ! 1008: * If the command works, interpret the result as a 4 byte* ! 1009: * number of blocks * ! 1010: \*******************************************************/ ! 1011: if (cd_scsi_cmd(unit, ! 1012: &scsi_cmd, ! 1013: sizeof(scsi_cmd), ! 1014: &rdcap, ! 1015: sizeof(rdcap), ! 1016: 2000, ! 1017: flags) != 0) ! 1018: { ! 1019: printf("could not get size of unit %d\n", unit); ! 1020: return(0); ! 1021: } else { ! 1022: size = rdcap.addr_0 + 1 ; ! 1023: size += rdcap.addr_1 << 8; ! 1024: size += rdcap.addr_2 << 16; ! 1025: size += rdcap.addr_3 << 24; ! 1026: blksize = rdcap.length_0 ; ! 1027: blksize += rdcap.length_1 << 8; ! 1028: blksize += rdcap.length_2 << 16; ! 1029: blksize += rdcap.length_3 << 24; ! 1030: } ! 1031: if(cd_debug)printf("cd%d: %d %d byte blocks\n",unit,size,blksize); ! 1032: cd_data[unit].params.disksize = size; ! 1033: cd_data[unit].params.blksize = blksize; ! 1034: return(size); ! 1035: } ! 1036: ! 1037: /*******************************************************\ ! 1038: * Check with the device that it is ok, (via scsi driver)* ! 1039: \*******************************************************/ ! 1040: cd_req_sense(unit, flags) ! 1041: { ! 1042: struct scsi_sense_data sense_data; ! 1043: struct scsi_sense scsi_cmd; ! 1044: ! 1045: bzero(&scsi_cmd, sizeof(scsi_cmd)); ! 1046: scsi_cmd.op_code = REQUEST_SENSE; ! 1047: scsi_cmd.length = sizeof(sense_data); ! 1048: ! 1049: if (cd_scsi_cmd(unit, ! 1050: &scsi_cmd, ! 1051: sizeof(scsi_cmd), ! 1052: &sense_data, ! 1053: sizeof(sense_data), ! 1054: 2000, ! 1055: flags) != 0) ! 1056: { ! 1057: return(ENXIO); ! 1058: } ! 1059: else ! 1060: return(0); ! 1061: } ! 1062: ! 1063: /*******************************************************\ ! 1064: * Get the requested page into the buffer given * ! 1065: \*******************************************************/ ! 1066: cd_get_mode(unit,data,page) ! 1067: int unit; ! 1068: struct cd_mode_data *data; ! 1069: int page; ! 1070: { ! 1071: struct scsi_mode_sense scsi_cmd; ! 1072: int retval; ! 1073: ! 1074: bzero(&scsi_cmd, sizeof(scsi_cmd)); ! 1075: bzero(data,sizeof(*data)); ! 1076: scsi_cmd.op_code = MODE_SENSE; ! 1077: scsi_cmd.page_code = page; ! 1078: scsi_cmd.length = sizeof(*data) & 0xff; ! 1079: retval = cd_scsi_cmd(unit, ! 1080: &scsi_cmd, ! 1081: sizeof(scsi_cmd), ! 1082: data, ! 1083: sizeof(*data), ! 1084: 20000, /* should be immed */ ! 1085: 0); ! 1086: return (retval); ! 1087: } ! 1088: /*******************************************************\ ! 1089: * Get the requested page into the buffer given * ! 1090: \*******************************************************/ ! 1091: cd_set_mode(unit,data) ! 1092: int unit; ! 1093: struct cd_mode_data *data; ! 1094: { ! 1095: struct scsi_mode_select scsi_cmd; ! 1096: ! 1097: bzero(&scsi_cmd, sizeof(scsi_cmd)); ! 1098: scsi_cmd.op_code = MODE_SELECT; ! 1099: scsi_cmd.pf = 1; ! 1100: scsi_cmd.length = sizeof(*data) & 0xff; ! 1101: data->header.data_length = 0; ! 1102: /*show_mem(data,sizeof(*data));/**/ ! 1103: return (cd_scsi_cmd(unit, ! 1104: &scsi_cmd, ! 1105: sizeof(scsi_cmd), ! 1106: data, ! 1107: sizeof(*data), ! 1108: 20000, /* should be immed */ ! 1109: 0) ! 1110: ); ! 1111: } ! 1112: /*******************************************************\ ! 1113: * Get scsi driver to send a "start playing" command * ! 1114: \*******************************************************/ ! 1115: cd_play(unit,blk,len) ! 1116: int unit,blk,len; ! 1117: { ! 1118: struct scsi_play scsi_cmd; ! 1119: int retval; ! 1120: ! 1121: bzero(&scsi_cmd, sizeof(scsi_cmd)); ! 1122: scsi_cmd.op_code = PLAY; ! 1123: scsi_cmd.blk_addr[0] = (blk >> 24) & 0xff; ! 1124: scsi_cmd.blk_addr[1] = (blk >> 16) & 0xff; ! 1125: scsi_cmd.blk_addr[2] = (blk >> 8) & 0xff; ! 1126: scsi_cmd.blk_addr[3] = blk & 0xff; ! 1127: scsi_cmd.xfer_len[0] = (len >> 8) & 0xff; ! 1128: scsi_cmd.xfer_len[1] = len & 0xff; ! 1129: retval = cd_scsi_cmd(unit, ! 1130: &scsi_cmd, ! 1131: sizeof(scsi_cmd), ! 1132: 0, ! 1133: 0, ! 1134: 200000, /* should be immed */ ! 1135: 0); ! 1136: return(retval); ! 1137: } ! 1138: /*******************************************************\ ! 1139: * Get scsi driver to send a "start playing" command * ! 1140: \*******************************************************/ ! 1141: cd_play_big(unit,blk,len) ! 1142: int unit,blk,len; ! 1143: { ! 1144: struct scsi_play_big scsi_cmd; ! 1145: int retval; ! 1146: ! 1147: bzero(&scsi_cmd, sizeof(scsi_cmd)); ! 1148: scsi_cmd.op_code = PLAY_BIG; ! 1149: scsi_cmd.blk_addr[0] = (blk >> 24) & 0xff; ! 1150: scsi_cmd.blk_addr[1] = (blk >> 16) & 0xff; ! 1151: scsi_cmd.blk_addr[2] = (blk >> 8) & 0xff; ! 1152: scsi_cmd.blk_addr[3] = blk & 0xff; ! 1153: scsi_cmd.xfer_len[0] = (len >> 24) & 0xff; ! 1154: scsi_cmd.xfer_len[1] = (len >> 16) & 0xff; ! 1155: scsi_cmd.xfer_len[2] = (len >> 8) & 0xff; ! 1156: scsi_cmd.xfer_len[3] = len & 0xff; ! 1157: retval = cd_scsi_cmd(unit, ! 1158: &scsi_cmd, ! 1159: sizeof(scsi_cmd), ! 1160: 0, ! 1161: 0, ! 1162: 20000, /* should be immed */ ! 1163: 0); ! 1164: return(retval); ! 1165: } ! 1166: /*******************************************************\ ! 1167: * Get scsi driver to send a "start playing" command * ! 1168: \*******************************************************/ ! 1169: cd_play_tracks(unit,strack,sindex,etrack,eindex) ! 1170: int unit,strack,sindex,etrack,eindex; ! 1171: { ! 1172: struct scsi_play_track scsi_cmd; ! 1173: int retval; ! 1174: ! 1175: bzero(&scsi_cmd, sizeof(scsi_cmd)); ! 1176: scsi_cmd.op_code = PLAY_TRACK; ! 1177: scsi_cmd.start_track = strack; ! 1178: scsi_cmd.start_index = sindex; ! 1179: scsi_cmd.end_track = etrack; ! 1180: scsi_cmd.end_index = eindex; ! 1181: retval = cd_scsi_cmd(unit, ! 1182: &scsi_cmd, ! 1183: sizeof(scsi_cmd), ! 1184: 0, ! 1185: 0, ! 1186: 20000, /* should be immed */ ! 1187: 0); ! 1188: return(retval); ! 1189: } ! 1190: /*******************************************************\ ! 1191: * Get scsi driver to send a "start up" command * ! 1192: \*******************************************************/ ! 1193: cd_pause(unit,go) ! 1194: int unit,go; ! 1195: { ! 1196: struct scsi_pause scsi_cmd; ! 1197: ! 1198: bzero(&scsi_cmd, sizeof(scsi_cmd)); ! 1199: scsi_cmd.op_code = PAUSE; ! 1200: scsi_cmd.resume = go; ! 1201: ! 1202: return (cd_scsi_cmd(unit, ! 1203: &scsi_cmd, ! 1204: sizeof(scsi_cmd), ! 1205: 0, ! 1206: 0, ! 1207: 2000, ! 1208: 0)); ! 1209: } ! 1210: /*******************************************************\ ! 1211: * Get scsi driver to send a "start up" command * ! 1212: \*******************************************************/ ! 1213: cd_reset(unit) ! 1214: int unit; ! 1215: { ! 1216: return(cd_scsi_cmd(unit,0,0,0,0,2000,SCSI_RESET)); ! 1217: } ! 1218: /*******************************************************\ ! 1219: * Get scsi driver to send a "start up" command * ! 1220: \*******************************************************/ ! 1221: cd_start_unit(unit,part,type) ! 1222: { ! 1223: struct scsi_start_stop scsi_cmd; ! 1224: ! 1225: if(type==CD_EJECT && (cd_data[unit].openparts&~(1<<part)) == 0 ) { ! 1226: cd_prevent_unit(unit,CD_EJECT,0); ! 1227: } ! 1228: ! 1229: bzero(&scsi_cmd, sizeof(scsi_cmd)); ! 1230: scsi_cmd.op_code = START_STOP; ! 1231: scsi_cmd.start = type==CD_START?1:0; ! 1232: scsi_cmd.loej = type==CD_EJECT?1:0; ! 1233: ! 1234: if (cd_scsi_cmd(unit, ! 1235: &scsi_cmd, ! 1236: sizeof(scsi_cmd), ! 1237: 0, ! 1238: 0, ! 1239: 2000, ! 1240: 0) != 0) { ! 1241: return(ENXIO); ! 1242: } else ! 1243: return(0); ! 1244: } ! 1245: /*******************************************************\ ! 1246: * Prevent or allow the user to remove the disk * ! 1247: \*******************************************************/ ! 1248: cd_prevent_unit(unit,type,flags) ! 1249: int unit,type,flags; ! 1250: { ! 1251: struct scsi_prevent scsi_cmd; ! 1252: ! 1253: if(type==CD_EJECT || type==PR_PREVENT || cd_data[unit].openparts == 0 ) { ! 1254: bzero(&scsi_cmd, sizeof(scsi_cmd)); ! 1255: scsi_cmd.op_code = PREVENT_ALLOW; ! 1256: scsi_cmd.prevent=type==CD_EJECT?PR_ALLOW:type; ! 1257: if (cd_scsi_cmd(unit, ! 1258: &scsi_cmd, ! 1259: sizeof(struct scsi_prevent), ! 1260: 0, ! 1261: 0, ! 1262: 5000, ! 1263: 0) != 0) ! 1264: { ! 1265: if(!(flags & SCSI_SILENT)) ! 1266: printf("cannot prevent/allow on cd%d\n", unit); ! 1267: return(0); ! 1268: } ! 1269: } ! 1270: return(1); ! 1271: } ! 1272: ! 1273: /******************************************************\ ! 1274: * Read Subchannel * ! 1275: \******************************************************/ ! 1276: ! 1277: cd_read_subchannel(unit,mode,format,track,data,len) ! 1278: int unit,mode,format,len; ! 1279: struct cd_sub_channel_info *data; ! 1280: { ! 1281: struct scsi_read_subchannel scsi_cmd; ! 1282: int error; ! 1283: ! 1284: bzero(&scsi_cmd,sizeof(scsi_cmd)); ! 1285: ! 1286: scsi_cmd.op_code=READ_SUBCHANNEL; ! 1287: if(mode==CD_MSF_FORMAT) ! 1288: scsi_cmd.msf=1; ! 1289: scsi_cmd.subQ=1; ! 1290: scsi_cmd.subchan_format=format; ! 1291: scsi_cmd.track=track; ! 1292: scsi_cmd.data_len[0]=(len)>>8; ! 1293: scsi_cmd.data_len[1]=(len)&0xff; ! 1294: return cd_scsi_cmd(unit, ! 1295: &scsi_cmd, ! 1296: sizeof(struct scsi_read_subchannel), ! 1297: data, ! 1298: len, ! 1299: 5000, ! 1300: 0); ! 1301: } ! 1302: ! 1303: /*******************************************************\ ! 1304: * Read Table of contents * ! 1305: \*******************************************************/ ! 1306: cd_read_toc(unit,mode,start,data,len) ! 1307: int unit,mode,start,len; ! 1308: struct cd_toc_entry *data; ! 1309: { ! 1310: struct scsi_read_toc scsi_cmd; ! 1311: int error; ! 1312: int ntoc; ! 1313: ! 1314: bzero(&scsi_cmd,sizeof(scsi_cmd)); ! 1315: /*if(len!=sizeof(struct ioc_toc_header)) ! 1316: ntoc=((len)-sizeof(struct ioc_toc_header))/sizeof(struct cd_toc_entry); ! 1317: else*/ ! 1318: ntoc=len; ! 1319: ! 1320: scsi_cmd.op_code=READ_TOC; ! 1321: if(mode==CD_MSF_FORMAT) ! 1322: scsi_cmd.msf=1; ! 1323: scsi_cmd.from_track=start; ! 1324: scsi_cmd.data_len[0]=(ntoc)>>8; ! 1325: scsi_cmd.data_len[1]=(ntoc)&0xff; ! 1326: return cd_scsi_cmd(unit, ! 1327: &scsi_cmd, ! 1328: sizeof(struct scsi_read_toc), ! 1329: data, ! 1330: len, ! 1331: 5000, ! 1332: 0); ! 1333: } ! 1334: ! 1335: ! 1336: #define b2tol(a) (((unsigned)(a##_1) << 8) + (unsigned)a##_0 ) ! 1337: ! 1338: /*******************************************************\ ! 1339: * Get the scsi driver to send a full inquiry to the * ! 1340: * device and use the results to fill out the disk * ! 1341: * parameter structure. * ! 1342: \*******************************************************/ ! 1343: ! 1344: int cd_get_parms(unit, flags) ! 1345: { ! 1346: struct cd_data *cd = cd_data + unit; ! 1347: ! 1348: /*******************************************************\ ! 1349: * First check if we have it all loaded * ! 1350: \*******************************************************/ ! 1351: if(cd->flags & CDVALID) return(0); ! 1352: /*******************************************************\ ! 1353: * give a number of sectors so that sec * trks * cyls * ! 1354: * is <= disk_size * ! 1355: \*******************************************************/ ! 1356: if(cd_size(unit, flags)) ! 1357: { ! 1358: cd->flags |= CDVALID; ! 1359: return(0); ! 1360: } ! 1361: else ! 1362: { ! 1363: return(ENXIO); ! 1364: } ! 1365: } ! 1366: ! 1367: /*******************************************************\ ! 1368: * close the device.. only called if we are the LAST * ! 1369: * occurence of an open device * ! 1370: \*******************************************************/ ! 1371: cdclose(dev) ! 1372: dev_t dev; ! 1373: { ! 1374: unsigned char unit, part; ! 1375: unsigned int old_priority; ! 1376: ! 1377: unit = UNIT(dev); ! 1378: part = PARTITION(dev); ! 1379: if(scsi_debug & TRACEOPENS) ! 1380: printf("closing cd%d part %d\n",unit,part); ! 1381: cd_data[unit].partflags[part] &= ~CDOPEN; ! 1382: cd_data[unit].openparts &= ~(1 << part); ! 1383: cd_prevent_unit(unit,PR_ALLOW,SCSI_SILENT); ! 1384: return(0); ! 1385: } ! 1386: ! 1387: /*******************************************************\ ! 1388: * ask the scsi driver to perform a command for us. * ! 1389: * Call it through the switch table, and tell it which * ! 1390: * sub-unit we want, and what target and lu we wish to * ! 1391: * talk to. Also tell it where to find the command * ! 1392: * how long int is. * ! 1393: * Also tell it where to read/write the data, and how * ! 1394: * long the data is supposed to be * ! 1395: \*******************************************************/ ! 1396: int cd_scsi_cmd(unit,scsi_cmd,cmdlen,data_addr,datalen,timeout,flags) ! 1397: ! 1398: int unit,flags; ! 1399: struct scsi_generic *scsi_cmd; ! 1400: int cmdlen; ! 1401: int timeout; ! 1402: u_char *data_addr; ! 1403: int datalen; ! 1404: { ! 1405: struct scsi_xfer *xs; ! 1406: int retval; ! 1407: int s; ! 1408: struct cd_data *cd = cd_data + unit; ! 1409: ! 1410: if(scsi_debug & PRINTROUTINES) printf("\ncd_scsi_cmd%d ",unit); ! 1411: if(cd->sc_sw) /* If we have a scsi driver */ ! 1412: { ! 1413: xs = cd_get_xs(unit,flags); /* should wait unless booting */ ! 1414: if(!xs) ! 1415: { ! 1416: printf("cd_scsi_cmd%d: controller busy" ! 1417: " (this should never happen)\n",unit); ! 1418: return(EBUSY); ! 1419: } ! 1420: xs->flags |= INUSE; ! 1421: /*******************************************************\ ! 1422: * Fill out the scsi_xfer structure * ! 1423: \*******************************************************/ ! 1424: xs->flags |= flags; ! 1425: xs->adapter = cd->ctlr; ! 1426: xs->targ = cd->targ; ! 1427: xs->lu = cd->lu; ! 1428: xs->retries = CD_RETRIES; ! 1429: xs->timeout = timeout; ! 1430: xs->cmd = scsi_cmd; ! 1431: xs->cmdlen = cmdlen; ! 1432: xs->data = data_addr; ! 1433: xs->datalen = datalen; ! 1434: xs->resid = datalen; ! 1435: xs->when_done = (flags & SCSI_NOMASK) ! 1436: ?(int (*)())0 ! 1437: :cd_done; ! 1438: xs->done_arg = unit; ! 1439: xs->done_arg2 = (int)xs; ! 1440: retry: xs->error = XS_NOERROR; ! 1441: xs->bp = 0; ! 1442: retval = (*(cd->sc_sw->scsi_cmd))(xs); ! 1443: switch(retval) ! 1444: { ! 1445: case SUCCESSFULLY_QUEUED: ! 1446: s = splbio(); ! 1447: while(!(xs->flags & ITSDONE)) ! 1448: sleep(xs,PRIBIO+1); ! 1449: splx(s); ! 1450: ! 1451: case HAD_ERROR: ! 1452: /*printf("err = %d ",xs->error);*/ ! 1453: switch(xs->error) ! 1454: { ! 1455: case XS_NOERROR: ! 1456: retval = ESUCCESS; ! 1457: break; ! 1458: case XS_SENSE: ! 1459: retval = (cd_interpret_sense(unit,xs)); ! 1460: break; ! 1461: case XS_DRIVER_STUFFUP: ! 1462: retval = EIO; ! 1463: break; ! 1464: ! 1465: ! 1466: case XS_BUSY: ! 1467: case XS_TIMEOUT: ! 1468: if(xs->retries-- ) ! 1469: { ! 1470: xs->flags &= ~ITSDONE; ! 1471: goto retry; ! 1472: } ! 1473: retval = EIO; ! 1474: break; ! 1475: default: ! 1476: retval = EIO; ! 1477: printf("cd%d: unknown error category from scsi driver\n" ! 1478: ,unit); ! 1479: } ! 1480: break; ! 1481: case COMPLETE: ! 1482: retval = ESUCCESS; ! 1483: break; ! 1484: case TRY_AGAIN_LATER: ! 1485: if(xs->retries-- ) ! 1486: { ! 1487: if(tsleep( 0,PRIBIO + 2,"retry",hz * 2)) ! 1488: { ! 1489: xs->flags &= ~ITSDONE; ! 1490: goto retry; ! 1491: } ! 1492: } ! 1493: retval = EIO; ! 1494: break; ! 1495: default: ! 1496: retval = EIO; ! 1497: } ! 1498: cd_free_xs(unit,xs,flags); ! 1499: cdstart(unit); /* check if anything is waiting fr the xs */ ! 1500: } ! 1501: else ! 1502: { ! 1503: printf("cd%d: not set up\n",unit); ! 1504: return(EINVAL); ! 1505: } ! 1506: return(retval); ! 1507: } ! 1508: /***************************************************************\ ! 1509: * Look at the returned sense and act on the error and detirmine * ! 1510: * The unix error number to pass back... (0 = report no error) * ! 1511: \***************************************************************/ ! 1512: ! 1513: int cd_interpret_sense(unit,xs) ! 1514: int unit; ! 1515: struct scsi_xfer *xs; ! 1516: { ! 1517: struct scsi_sense_data *sense; ! 1518: int key; ! 1519: int silent; ! 1520: ! 1521: /***************************************************************\ ! 1522: * If the flags say errs are ok, then always return ok. * ! 1523: \***************************************************************/ ! 1524: if (xs->flags & SCSI_ERR_OK) return(ESUCCESS); ! 1525: silent = (xs->flags & SCSI_SILENT); ! 1526: ! 1527: sense = &(xs->sense); ! 1528: switch(sense->error_class) ! 1529: { ! 1530: case 7: ! 1531: { ! 1532: key=sense->ext.extended.sense_key; ! 1533: switch(key) ! 1534: { ! 1535: case 0x0: ! 1536: return(ESUCCESS); ! 1537: case 0x1: ! 1538: if(!silent) ! 1539: { ! 1540: printf("cd%d: soft error(corrected) ", unit); ! 1541: if(sense->valid) ! 1542: { ! 1543: printf("block no. %d (decimal)", ! 1544: (sense->ext.extended.info[0] <<24), ! 1545: (sense->ext.extended.info[1] <<16), ! 1546: (sense->ext.extended.info[2] <<8), ! 1547: (sense->ext.extended.info[3] )); ! 1548: } ! 1549: printf("\n"); ! 1550: } ! 1551: return(ESUCCESS); ! 1552: case 0x2: ! 1553: if(!silent)printf("cd%d: not ready\n ", ! 1554: unit); ! 1555: return(ENODEV); ! 1556: case 0x3: ! 1557: if(!silent) ! 1558: { ! 1559: printf("cd%d: medium error ", unit); ! 1560: if(sense->valid) ! 1561: { ! 1562: printf("block no. %d (decimal)", ! 1563: (sense->ext.extended.info[0] <<24), ! 1564: (sense->ext.extended.info[1] <<16), ! 1565: (sense->ext.extended.info[2] <<8), ! 1566: (sense->ext.extended.info[3] )); ! 1567: } ! 1568: printf("\n"); ! 1569: } ! 1570: return(EIO); ! 1571: case 0x4: ! 1572: if(!silent)printf("cd%d: non-media hardware failure\n ", ! 1573: unit); ! 1574: return(EIO); ! 1575: case 0x5: ! 1576: if(!silent)printf("cd%d: illegal request\n ", ! 1577: unit); ! 1578: return(EINVAL); ! 1579: case 0x6: ! 1580: if(!silent)printf("cd%d: Unit attention.\n ", unit); ! 1581: if (cd_data[unit].openparts) ! 1582: cd_data[unit].flags &= ~(CDVALID | CDHAVELABEL); ! 1583: { ! 1584: return(EIO); ! 1585: } ! 1586: return(ESUCCESS); ! 1587: case 0x7: ! 1588: if(!silent) ! 1589: { ! 1590: printf("cd%d: attempted protection violation ", ! 1591: unit); ! 1592: if(sense->valid) ! 1593: { ! 1594: printf("block no. %d (decimal)\n", ! 1595: (sense->ext.extended.info[0] <<24), ! 1596: (sense->ext.extended.info[1] <<16), ! 1597: (sense->ext.extended.info[2] <<8), ! 1598: (sense->ext.extended.info[3] )); ! 1599: } ! 1600: printf("\n"); ! 1601: } ! 1602: return(EACCES); ! 1603: case 0x8: ! 1604: if(!silent) ! 1605: { ! 1606: printf("cd%d: block wrong state (worm)\n ", ! 1607: unit); ! 1608: if(sense->valid) ! 1609: { ! 1610: printf("block no. %d (decimal)\n", ! 1611: (sense->ext.extended.info[0] <<24), ! 1612: (sense->ext.extended.info[1] <<16), ! 1613: (sense->ext.extended.info[2] <<8), ! 1614: (sense->ext.extended.info[3] )); ! 1615: } ! 1616: printf("\n"); ! 1617: } ! 1618: return(EIO); ! 1619: case 0x9: ! 1620: if(!silent)printf("cd%d: vendor unique\n", ! 1621: unit); ! 1622: return(EIO); ! 1623: case 0xa: ! 1624: if(!silent)printf("cd%d: copy aborted\n ", ! 1625: unit); ! 1626: return(EIO); ! 1627: case 0xb: ! 1628: if(!silent)printf("cd%d: command aborted\n ", ! 1629: unit); ! 1630: return(EIO); ! 1631: case 0xc: ! 1632: if(!silent) ! 1633: { ! 1634: printf("cd%d: search returned\n ", ! 1635: unit); ! 1636: if(sense->valid) ! 1637: { ! 1638: printf("block no. %d (decimal)\n", ! 1639: (sense->ext.extended.info[0] <<24), ! 1640: (sense->ext.extended.info[1] <<16), ! 1641: (sense->ext.extended.info[2] <<8), ! 1642: (sense->ext.extended.info[3] )); ! 1643: } ! 1644: printf("\n"); ! 1645: } ! 1646: return(ESUCCESS); ! 1647: case 0xd: ! 1648: if(!silent)printf("cd%d: volume overflow\n ", ! 1649: unit); ! 1650: return(ENOSPC); ! 1651: case 0xe: ! 1652: if(!silent) ! 1653: { ! 1654: printf("cd%d: verify miscompare\n ", ! 1655: unit); ! 1656: if(sense->valid) ! 1657: { ! 1658: printf("block no. %d (decimal)\n", ! 1659: (sense->ext.extended.info[0] <<24), ! 1660: (sense->ext.extended.info[1] <<16), ! 1661: (sense->ext.extended.info[2] <<8), ! 1662: (sense->ext.extended.info[3] )); ! 1663: } ! 1664: printf("\n"); ! 1665: } ! 1666: return(EIO); ! 1667: case 0xf: ! 1668: if(!silent)printf("cd%d: unknown error key\n ", ! 1669: unit); ! 1670: return(EIO); ! 1671: } ! 1672: break; ! 1673: } ! 1674: case 0: ! 1675: case 1: ! 1676: case 2: ! 1677: case 3: ! 1678: case 4: ! 1679: case 5: ! 1680: case 6: ! 1681: { ! 1682: if(!silent)printf("cd%d: error class %d code %d\n", ! 1683: unit, ! 1684: sense->error_class, ! 1685: sense->error_code); ! 1686: if(sense->valid) ! 1687: if(!silent)printf("block no. %d (decimal)\n", ! 1688: (sense->ext.unextended.blockhi <<16), ! 1689: + (sense->ext.unextended.blockmed <<8), ! 1690: + (sense->ext.unextended.blocklow )); ! 1691: } ! 1692: return(EIO); ! 1693: } ! 1694: } ! 1695: ! 1696: ! 1697: ! 1698: ! 1699: int ! 1700: cdsize(dev_t dev) ! 1701: { ! 1702: return (-1); ! 1703: } ! 1704: ! 1705: show_mem(address,num) ! 1706: unsigned char *address; ! 1707: int num; ! 1708: { ! 1709: int x,y; ! 1710: printf("------------------------------"); ! 1711: for (y = 0; y<num; y += 1) ! 1712: { ! 1713: if(!(y % 16)) ! 1714: printf("\n%03d: ",y); ! 1715: printf("%02x ",*address++); ! 1716: } ! 1717: printf("\n------------------------------\n"); ! 1718: } ! 1719:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.