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