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