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