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