|
|
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.