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