1 /* 2 * $Id: ch.c,v 1.3 1993/05/20 03:46:22 cgd Exp $ 3 */ 4 5 #include <sys/types.h> 6 #include <ch.h> 7 8 #include <sys/param.h> 9 #include <sys/systm.h> 10 11 #include <sys/errno.h> 12 #include <sys/ioctl.h> 13 #include <sys/buf.h> 14 #include <sys/proc.h> 15 #include <sys/user.h> 16 #include <sys/chio.h> 17 18 #if defined(OSF) 19 #define SECSIZE 512 20 #endif /* defined(OSF) */ 21 22 #include <scsi/scsi_all.h> 23 #include <scsi/scsi_changer.h> 24 #include <scsi/scsiconf.h> 25 26 27 struct scsi_xfer ch_scsi_xfer[NCH]; 28 int ch_xfer_block_wait[NCH]; 29 30 31 #define PAGESIZ 4096 32 #define STQSIZE 4 33 #define CH_RETRIES 4 34 35 36 #define MODE(z) ( (minor(z) & 0x0F) ) 37 #define UNIT(z) ( (minor(z) >> 4) ) 38 39 #ifndef MACH 40 #define ESUCCESS 0 41 #endif MACH 42 43 int ch_info_valid[NCH]; /* the info about the device is valid */ 44 int ch_initialized[NCH] ; 45 int ch_debug = 1; 46 47 int chattach(); 48 int ch_done(); 49 struct ch_data 50 { 51 int flags; 52 struct scsi_switch *sc_sw; /* address of scsi low level switch */ 53 int ctlr; /* so they know which one we want */ 54 int targ; /* our scsi target ID */ 55 int lu; /* out scsi lu */ 56 short chmo; /* Offset of first CHM */ 57 short chms; /* No. of CHM */ 58 short slots; /* No. of Storage Elements */ 59 short sloto; /* Offset of first SE */ 60 short imexs; /* No. of Import/Export Slots */ 61 short imexo; /* Offset of first IM/EX */ 62 short drives; /* No. of CTS */ 63 short driveo; /* Offset of first CTS */ 64 short rot; /* CHM can rotate */ 65 u_long op_matrix; /* possible opertaions */ 66 u_short lsterr; /* details of lasterror */ 67 u_char stor; /* posible Storage locations */ 68 }ch_data[NCH]; 69 70 #define CH_OPEN 0x01 71 #define CH_KNOWN 0x02 72 73 static int next_ch_unit = 0; 74 /***********************************************************************\ 75 * The routine called by the low level scsi routine when it discovers * 76 * A device suitable for this driver * 77 \***********************************************************************/ 78 79 int chattach(ctlr,targ,lu,scsi_switch) 80 struct scsi_switch *scsi_switch; 81 { 82 int unit,i,stat; 83 unsigned char *tbl; 84 85 if(scsi_debug & PRINTROUTINES) printf("chattach: "); 86 /*******************************************************\ 87 * Check we have the resources for another drive * 88 \*******************************************************/ 89 unit = next_ch_unit++; 90 if( unit >= NCH) 91 { 92 printf("Too many scsi changers..(%d > %d) reconfigure kernel",(unit + 1),NCH); 93 return(0); 94 } 95 /*******************************************************\ 96 * Store information needed to contact our base driver * 97 \*******************************************************/ 98 ch_data[unit].sc_sw = scsi_switch; 99 ch_data[unit].ctlr = ctlr; 100 ch_data[unit].targ = targ; 101 ch_data[unit].lu = lu; 102 103 /*******************************************************\ 104 * Use the subdriver to request information regarding * 105 * the drive. We cannot use interrupts yet, so the * 106 * request must specify this. * 107 \*******************************************************/ 108 if((ch_mode_sense(unit, SCSI_NOSLEEP | SCSI_NOMASK /*| SCSI_SILENT*/))) 109 { 110 printf(" ch%d: scsi changer, %d slot(s) %d drive(s) %d arm(s) %d i/e-slot(s) \n", 111 unit, ch_data[unit].slots, ch_data[unit].drives, ch_data[unit].chms, ch_data[unit].imexs); 112 stat=CH_KNOWN; 113 } 114 else 115 { 116 printf(" ch%d: scsi changer :- offline\n", unit); 117 stat=CH_OPEN; 118 } 119 ch_initialized[unit] = stat; 120 121 return; 122 123 } 124 125 126 127 /*******************************************************\ 128 * open the device. * 129 \*******************************************************/ 130 chopen(dev) 131 { 132 int errcode = 0; 133 int unit,mode; 134 135 unit = UNIT(dev); 136 mode = MODE(dev); 137 138 /*******************************************************\ 139 * Check the unit is legal * 140 \*******************************************************/ 141 if ( unit >= NCH ) 142 { 143 printf("ch %d > %d\n",unit,NCH); 144 errcode = ENXIO; 145 return(errcode); 146 } 147 /*******************************************************\ 148 * Only allow one at a time * 149 \*******************************************************/ 150 if(ch_data[unit].flags & CH_OPEN) 151 { 152 printf("CH%d already open\n",unit); 153 errcode = ENXIO; 154 goto bad; 155 } 156 157 if(ch_debug||(scsi_debug & (PRINTROUTINES | TRACEOPENS))) 158 printf("chopen: dev=0x%x (unit %d (of %d))\n" 159 , dev, unit, NCH); 160 /*******************************************************\ 161 * Make sure the device has been initialised * 162 \*******************************************************/ 163 164 if (!ch_initialized[unit]) 165 return(ENXIO); 166 if (ch_initialized[unit]!=CH_KNOWN) { 167 if((ch_mode_sense(unit, SCSI_NOSLEEP | SCSI_NOMASK /*| SCSI_SILENT*/))) 168 { 169 ch_initialized[unit]=CH_KNOWN; 170 } 171 else 172 { 173 printf(" ch%d: scsi changer :- offline\n", unit); 174 return(ENXIO); 175 } 176 } 177 /*******************************************************\ 178 * Check that it is still responding and ok. * 179 \*******************************************************/ 180 181 if(ch_debug || (scsi_debug & TRACEOPENS)) 182 printf("device is "); 183 if (!(ch_req_sense(unit, 0))) 184 { 185 errcode = ENXIO; 186 if(ch_debug || (scsi_debug & TRACEOPENS)) 187 printf("not responding\n"); 188 goto bad; 189 } 190 if(ch_debug || (scsi_debug & TRACEOPENS)) 191 printf("ok\n"); 192 193 if(!(ch_test_ready(unit,0))) 194 { 195 printf("ch%d not ready\n",unit); 196 return(EIO); 197 } 198 199 ch_info_valid[unit] = TRUE; 200 201 /*******************************************************\ 202 * Load the physical device parameters * 203 \*******************************************************/ 204 205 ch_data[unit].flags = CH_OPEN; 206 return(errcode); 207 bad: 208 return(errcode); 209 } 210 211 /*******************************************************\ 212 * close the device.. only called if we are the LAST * 213 * occurence of an open device * 214 \*******************************************************/ 215 chclose(dev) 216 { 217 unsigned char unit,mode; 218 219 unit = UNIT(dev); 220 mode = MODE(dev); 221 222 if(scsi_debug & TRACEOPENS) 223 printf("Closing device"); 224 ch_data[unit].flags = 0; 225 return(0); 226 } 227 228 229 230 /***************************************************************\ 231 * chstart * 232 * This routine is also called after other non-queued requests * 233 * have been made of the scsi driver, to ensure that the queue * 234 * continues to be drained. * 235 \***************************************************************/ 236 /* chstart() is called at splbio */ 237 chstart(unit) 238 { 239 int drivecount; 240 register struct buf *bp = 0; 241 register struct buf *dp; 242 struct scsi_xfer *xs; 243 int blkno, nblk; 244 245 246 if(scsi_debug & PRINTROUTINES) printf("chstart%d ",unit); 247 /*******************************************************\ 248 * See if there is a buf to do and we are not already * 249 * doing one * 250 \*******************************************************/ 251 xs=&ch_scsi_xfer[unit]; 252 if(xs->flags & INUSE) 253 { 254 return; /* unit already underway */ 255 } 256 if(ch_xfer_block_wait[unit]) /* a special awaits, let it proceed first */ 257 { 258 wakeup(&ch_xfer_block_wait[unit]); 259 return; 260 } 261 262 return; 263 264 } 265 266 267 /*******************************************************\ 268 * This routine is called by the scsi interrupt when * 269 * the transfer is complete. 270 \*******************************************************/ 271 int ch_done(unit,xs) 272 int unit; 273 struct scsi_xfer *xs; 274 { 275 struct buf *bp; 276 int retval; 277 278 if(ch_debug||(scsi_debug & PRINTROUTINES)) printf("ch_done%d ",unit); 279 if (! (xs->flags & INUSE)) 280 panic("scsi_xfer not in use!"); 281 wakeup(xs); 282 } 283 /*******************************************************\ 284 * Perform special action on behalf of the user * 285 * Knows about the internals of this device * 286 \*******************************************************/ 287 chioctl(dev, cmd, arg, mode) 288 dev_t dev; 289 int cmd; 290 caddr_t arg; 291 { 292 /* struct ch_cmd_buf *args;*/ 293 union scsi_cmd *scsi_cmd; 294 register i,j; 295 unsigned int opri; 296 int errcode = 0; 297 unsigned char unit; 298 int number,flags,ret; 299 300 /*******************************************************\ 301 * Find the device that the user is talking about * 302 \*******************************************************/ 303 flags = 0; /* give error messages, act on errors etc. */ 304 unit = UNIT(dev); 305 306 switch(cmd) 307 { 308 case CHIOOP: { 309 struct chop *ch=(struct chop *) arg; 310 if (ch_debug) 311 printf("[chtape_chop: %x]\n", ch->ch_op); 312 313 switch ((short)(ch->ch_op)) { 314 case CHGETPARAM: 315 ch->u.getparam.chmo= ch_data[unit].chmo; 316 ch->u.getparam.chms= ch_data[unit].chms; 317 ch->u.getparam.sloto= ch_data[unit].sloto; 318 ch->u.getparam.slots= ch_data[unit].slots; 319 ch->u.getparam.imexo= ch_data[unit].imexo; 320 ch->u.getparam.imexs= ch_data[unit].imexs; 321 ch->u.getparam.driveo= ch_data[unit].driveo; 322 ch->u.getparam.drives= ch_data[unit].drives; 323 ch->u.getparam.rot= ch_data[unit].rot; 324 ch->result=0; 325 return 0; 326 break; 327 case CHPOSITION: 328 return ch_position(unit,&ch->result,ch->u.position.chm, 329 ch->u.position.to, 330 flags); 331 case CHMOVE: 332 return ch_move(unit,&ch->result, ch->u.position.chm, 333 ch->u.move.from, ch->u.move.to, 334 flags); 335 case CHGETELEM: 336 return ch_getelem(unit,&ch->result, ch->u.get_elem_stat.type, 337 ch->u.get_elem_stat.from, &ch->u.get_elem_stat.elem_data, 338 flags); 339 default: 340 return EINVAL; 341 } 342 343 } 344 default: 345 return EINVAL; 346 } 347 348 return(ret?ESUCCESS:EIO); 349 } 350 351 ch_getelem(unit,stat,type,from,data,flags) 352 int unit,from,flags; 353 short *stat; 354 char *data; 355 { 356 struct scsi_read_element_status scsi_cmd; 357 char elbuf[32]; 358 int ret; 359 360 bzero(&scsi_cmd, sizeof(scsi_cmd)); 361 scsi_cmd.op_code = READ_ELEMENT_STATUS; 362 scsi_cmd.element_type_code=type; 363 scsi_cmd.starting_element_addr[0]=(from>>8)&0xff; 364 scsi_cmd.starting_element_addr[1]=from&0xff; 365 scsi_cmd.number_of_elements[1]=1; 366 scsi_cmd.allocation_length[2]=32; 367 368 if ((ret=ch_scsi_cmd(unit, 369 &scsi_cmd, 370 sizeof(scsi_cmd), 371 elbuf, 372 32, 373 100000, 374 flags) !=ESUCCESS)) { 375 *stat=ch_data[unit].lsterr; 376 bcopy(elbuf+16,data,16); 377 return ret; 378 } 379 bcopy(elbuf+16,data,16); /*Just a hack sh */ 380 return ret; 381 } 382 383 ch_move(unit,stat,chm,from,to,flags) 384 int unit,chm,from,to,flags; 385 short *stat; 386 { 387 struct scsi_move_medium scsi_cmd; 388 int ret; 389 390 bzero(&scsi_cmd, sizeof(scsi_cmd)); 391 scsi_cmd.op_code = MOVE_MEDIUM; 392 scsi_cmd.transport_element_address[0]=(chm>>8)&0xff; 393 scsi_cmd.transport_element_address[1]=chm&0xff; 394 scsi_cmd.source_address[0]=(from>>8)&0xff; 395 scsi_cmd.source_address[1]=from&0xff; 396 scsi_cmd.destination_address[0]=(to>>8)&0xff; 397 scsi_cmd.destination_address[1]=to&0xff; 398 scsi_cmd.invert=(chm&CH_INVERT)?1:0; 399 if ((ret=ch_scsi_cmd(unit, 400 &scsi_cmd, 401 sizeof(scsi_cmd), 402 NULL, 403 0, 404 100000, 405 flags) !=ESUCCESS)) { 406 *stat=ch_data[unit].lsterr; 407 return ret; 408 } 409 return ret; 410 } 411 412 ch_position(unit,stat,chm,to,flags) 413 int unit,chm,to,flags; 414 short *stat; 415 { 416 struct scsi_position_to_element scsi_cmd; 417 int ret; 418 419 bzero(&scsi_cmd, sizeof(scsi_cmd)); 420 scsi_cmd.op_code = POSITION_TO_ELEMENT; 421 scsi_cmd.transport_element_address[0]=(chm>>8)&0xff; 422 scsi_cmd.transport_element_address[1]=chm&0xff; 423 scsi_cmd.source_address[0]=(to>>8)&0xff; 424 scsi_cmd.source_address[1]=to&0xff; 425 scsi_cmd.invert=(chm&CH_INVERT)?1:0; 426 if ((ret=ch_scsi_cmd(unit, 427 &scsi_cmd, 428 sizeof(scsi_cmd), 429 NULL, 430 0, 431 100000, 432 flags) !=ESUCCESS)) { 433 *stat=ch_data[unit].lsterr; 434 return ret; 435 } 436 return ret; 437 } 438 439 /*******************************************************\ 440 * Check with the device that it is ok, (via scsi driver)* 441 \*******************************************************/ 442 ch_req_sense(unit, flags) 443 int flags; 444 { 445 struct scsi_sense_data sense; 446 struct scsi_sense scsi_cmd; 447 448 bzero(&scsi_cmd, sizeof(scsi_cmd)); 449 scsi_cmd.op_code = REQUEST_SENSE; 450 scsi_cmd.length = sizeof(sense); 451 452 if (ch_scsi_cmd(unit, 453 &scsi_cmd, 454 sizeof(struct scsi_sense), 455 &sense, 456 sizeof(sense), 457 100000, 458 flags | SCSI_DATA_IN) != 0) 459 { 460 return(FALSE); 461 } 462 else 463 return(TRUE); 464 } 465 466 /*******************************************************\ 467 * Get scsi driver to send a "are you ready" command * 468 \*******************************************************/ 469 ch_test_ready(unit,flags) 470 int unit,flags; 471 { 472 struct scsi_test_unit_ready scsi_cmd; 473 474 bzero(&scsi_cmd, sizeof(scsi_cmd)); 475 scsi_cmd.op_code = TEST_UNIT_READY; 476 477 if (ch_scsi_cmd(unit, 478 &scsi_cmd, 479 sizeof(struct scsi_test_unit_ready), 480 0, 481 0, 482 100000, 483 flags) != 0) { 484 return(FALSE); 485 } else 486 return(TRUE); 487 } 488 489 490 #ifdef __STDC__ 491 #define b2tol(a) (((unsigned)(a##_1) << 8) + (unsigned)a##_0 ) 492 #else 493 #define b2tol(a) (((unsigned)(a/**/_1) << 8) + (unsigned)a/**/_0 ) 494 #endif 495 496 /*******************************************************\ 497 * Get the scsi driver to send a full inquiry to the * 498 * device and use the results to fill out the global * 499 * parameter structure. * 500 \*******************************************************/ 501 ch_mode_sense(unit, flags) 502 int unit,flags; 503 { 504 struct scsi_mode_sense scsi_cmd; 505 u_char scsi_sense[128]; /* Can't use scsi_mode_sense_data because of */ 506 /* missing block descriptor */ 507 u_char *b; 508 int i,l; 509 510 /*******************************************************\ 511 * First check if we have it all loaded * 512 \*******************************************************/ 513 if (ch_info_valid[unit]==CH_KNOWN) return(TRUE); 514 /*******************************************************\ 515 * First do a mode sense * 516 \*******************************************************/ 517 ch_info_valid[unit] &= ~CH_KNOWN; 518 for(l=1;l>=0;l--) { 519 bzero(&scsi_cmd, sizeof(scsi_cmd)); 520 scsi_cmd.op_code = MODE_SENSE; 521 scsi_cmd.dbd = l; 522 scsi_cmd.page_code = 0x3f; /* All Pages */ 523 scsi_cmd.length = sizeof(scsi_sense); 524 /*******************************************************\ 525 * do the command, but we don't need the results * 526 * just print them for our interest's sake * 527 \*******************************************************/ 528 if (ch_scsi_cmd(unit, 529 &scsi_cmd, 530 sizeof(struct scsi_mode_sense), 531 &scsi_sense, 532 sizeof(scsi_sense), 533 5000, 534 flags | SCSI_DATA_IN) == 0) { 535 ch_info_valid[unit] = CH_KNOWN; 536 break; 537 } 538 } 539 if (ch_info_valid[unit]!=CH_KNOWN) { 540 if(!(flags & SCSI_SILENT)) 541 printf("could not mode sense for unit %d\n", unit); 542 return(FALSE); 543 } 544 l=scsi_sense[0]-3; 545 b=&scsi_sense[4]; 546 /*****************************\ 547 * To avoid alignment problems * 548 \*****************************/ 549 /*FIX THIS FOR MSB */ 550 #define p2copy(valp) (valp[1]+ (valp[0]<<8));valp+=2 551 #define p4copy(valp) (valp[3]+ (valp[2]<<8) + (valp[1]<<16) + (valp[0]<<24));valp+=4 552 #if 0 553 printf("\nmode_sense %d\n",l); 554 for(i=0;i<l+4;i++) { 555 printf("%x%c",scsi_sense[i],i%8==7?'\n':':'); 556 } 557 printf("\n"); 558 #endif 559 for(i=0;i<l;) { 560 int pc=(*b++)&0x3f; 561 int pl=*b++; 562 u_char *bb=b; 563 switch(pc) { 564 case 0x1d: 565 ch_data[unit].chmo =p2copy(bb); 566 ch_data[unit].chms =p2copy(bb); 567 ch_data[unit].sloto =p2copy(bb); 568 ch_data[unit].slots =p2copy(bb); 569 ch_data[unit].imexo =p2copy(bb); 570 ch_data[unit].imexs =p2copy(bb); 571 ch_data[unit].driveo =p2copy(bb); 572 ch_data[unit].drives =p2copy(bb); 573 break; 574 case 0x1e: 575 ch_data[unit].rot = (*b)&1; 576 break; 577 case 0x1f: 578 ch_data[unit].stor = *b&0xf; 579 bb+=2; 580 ch_data[unit].stor =p4copy(bb); 581 break; 582 default: 583 break; 584 } 585 b+=pl; 586 i+=pl+2; 587 } 588 if (ch_debug) 589 { 590 printf("unit %d: cht(%d-%d)slot(%d-%d)imex(%d-%d)cts(%d-%d) %s rotate\n", 591 unit, 592 ch_data[unit].chmo, 593 ch_data[unit].chms, 594 ch_data[unit].sloto, 595 ch_data[unit].slots, 596 ch_data[unit].imexo, 597 ch_data[unit].imexs, 598 ch_data[unit].driveo, 599 ch_data[unit].drives, 600 ch_data[unit].rot?"can":"can't"); 601 } 602 return(TRUE); 603 } 604 605 /*******************************************************\ 606 * ask the scsi driver to perform a command for us. * 607 * Call it through the switch table, and tell it which * 608 * sub-unit we want, and what target and lu we wish to * 609 * talk to. Also tell it where to find the command * 610 * how long int is. * 611 * Also tell it where to read/write the data, and how * 612 * long the data is supposed to be * 613 \*******************************************************/ 614 int ch_scsi_cmd(unit,scsi_cmd,cmdlen,data_addr,datalen,timeout,flags) 615 616 int unit,flags; 617 struct scsi_generic *scsi_cmd; 618 int cmdlen; 619 int timeout; 620 u_char *data_addr; 621 int datalen; 622 { 623 struct scsi_xfer *xs; 624 int retval; 625 int s; 626 627 if(ch_debug||(scsi_debug & PRINTROUTINES)) printf("\nch_scsi_cmd%d %x", 628 unit,scsi_cmd->opcode); 629 if(ch_data[unit].sc_sw) /* If we have a scsi driver */ 630 { 631 632 xs = &(ch_scsi_xfer[unit]); 633 if(!(flags & SCSI_NOMASK)) 634 s = splbio(); 635 ch_xfer_block_wait[unit]++; /* there is someone waiting */ 636 while (xs->flags & INUSE) 637 { 638 sleep(&ch_xfer_block_wait[unit],PRIBIO+1); 639 } 640 ch_xfer_block_wait[unit]--; 641 xs->flags = INUSE; 642 if(!(flags & SCSI_NOMASK)) 643 splx(s); 644 645 /*******************************************************\ 646 * Fill out the scsi_xfer structure * 647 \*******************************************************/ 648 xs->flags |= flags; 649 xs->adapter = ch_data[unit].ctlr; 650 xs->targ = ch_data[unit].targ; 651 xs->lu = ch_data[unit].lu; 652 xs->retries = CH_RETRIES; 653 xs->timeout = timeout; 654 xs->cmd = scsi_cmd; 655 xs->cmdlen = cmdlen; 656 xs->data = data_addr; 657 xs->datalen = datalen; 658 xs->resid = datalen; 659 xs->when_done = (flags & SCSI_NOMASK) 660 ?(int (*)())0 661 :ch_done; 662 xs->done_arg = unit; 663 xs->done_arg2 = (int)xs; 664 retry: xs->error = XS_NOERROR; 665 xs->bp = 0; 666 ch_data[unit].lsterr=0; 667 retval = (*(ch_data[unit].sc_sw->scsi_cmd))(xs); 668 switch(retval) 669 { 670 case SUCCESSFULLY_QUEUED: 671 while(!(xs->flags & ITSDONE)) 672 sleep(xs,PRIBIO+1); 673 674 case HAD_ERROR: 675 case COMPLETE: 676 switch(xs->error) 677 { 678 case XS_NOERROR: 679 retval = ESUCCESS; 680 break; 681 case XS_SENSE: 682 retval = (ch_interpret_sense(unit,xs)); 683 break; 684 case XS_DRIVER_STUFFUP: 685 retval = EIO; 686 break; 687 case XS_TIMEOUT: 688 if(xs->retries-- ) 689 { 690 xs->flags &= ~ITSDONE; 691 goto retry; 692 } 693 retval = EIO; 694 break; 695 case XS_BUSY: 696 if(xs->retries-- ) 697 { 698 xs->flags &= ~ITSDONE; 699 goto retry; 700 } 701 retval = EIO; 702 break; 703 default: 704 retval = EIO; 705 printf("st%d: unknown error category from scsi driver\n" 706 ,unit); 707 break; 708 } 709 break; 710 case TRY_AGAIN_LATER: 711 if(xs->retries-- ) 712 { 713 xs->flags &= ~ITSDONE; 714 goto retry; 715 } 716 retval = EIO; 717 break; 718 default: 719 retval = EIO; 720 } 721 xs->flags = 0; /* it's free! */ 722 chstart(unit); 723 } 724 else 725 { 726 printf("chd: not set up\n",unit); 727 return(EINVAL); 728 } 729 return(retval); 730 } 731 /***************************************************************\ 732 * Look at the returned sense and act on the error and detirmine * 733 * The unix error number to pass back... (0 = report no error) * 734 \***************************************************************/ 735 736 int ch_interpret_sense(unit,xs) 737 int unit; 738 struct scsi_xfer *xs; 739 { 740 struct scsi_sense_data *sense; 741 int key; 742 int silent = xs->flags & SCSI_SILENT; 743 744 /***************************************************************\ 745 * If errors are ok, report a success * 746 \***************************************************************/ 747 if(xs->flags & SCSI_ERR_OK) return(ESUCCESS); 748 749 /***************************************************************\ 750 * Get the sense fields and work out what CLASS * 751 \***************************************************************/ 752 sense = &(xs->sense); 753 switch(sense->error_class) 754 { 755 /***************************************************************\ 756 * If it's class 7, use the extended stuff and interpret the key * 757 \***************************************************************/ 758 case 7: 759 { 760 key=sense->ext.extended.sense_key; 761 if(sense->ext.extended.ili) 762 if(!silent) 763 { 764 printf("length error "); 765 } 766 if(sense->valid) 767 xs->resid = ntohl(*((long *)sense->ext.extended.info)); 768 if(xs->bp) 769 { 770 xs->bp->b_flags |= B_ERROR; 771 return(ESUCCESS); 772 } 773 if(sense->ext.extended.eom) 774 if(!silent) printf("end of medium "); 775 if(sense->ext.extended.filemark) 776 if(!silent) printf("filemark "); 777 if(ch_debug) 778 { 779 printf("code%x class%x valid%x\n" 780 ,sense->error_code 781 ,sense->error_class 782 ,sense->valid); 783 printf("seg%x key%x ili%x eom%x fmark%x\n" 784 ,sense->ext.extended.segment 785 ,sense->ext.extended.sense_key 786 ,sense->ext.extended.ili 787 ,sense->ext.extended.eom 788 ,sense->ext.extended.filemark); 789 printf("info: %x %x %x %x followed by %d extra bytes\n" 790 ,sense->ext.extended.info[0] 791 ,sense->ext.extended.info[1] 792 ,sense->ext.extended.info[2] 793 ,sense->ext.extended.info[3] 794 ,sense->ext.extended.extra_len); 795 printf("extra: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x\n" 796 ,sense->ext.extended.extra_bytes[0] 797 ,sense->ext.extended.extra_bytes[1] 798 ,sense->ext.extended.extra_bytes[2] 799 ,sense->ext.extended.extra_bytes[3] 800 ,sense->ext.extended.extra_bytes[4] 801 ,sense->ext.extended.extra_bytes[5] 802 ,sense->ext.extended.extra_bytes[6] 803 ,sense->ext.extended.extra_bytes[7] 804 ,sense->ext.extended.extra_bytes[8] 805 ,sense->ext.extended.extra_bytes[9] 806 ,sense->ext.extended.extra_bytes[10] 807 ,sense->ext.extended.extra_bytes[11] 808 ,sense->ext.extended.extra_bytes[12] 809 ,sense->ext.extended.extra_bytes[13] 810 ,sense->ext.extended.extra_bytes[14] 811 ,sense->ext.extended.extra_bytes[15]); 812 813 } 814 switch(key) 815 { 816 case 0x0: 817 return(ESUCCESS); 818 case 0x1: 819 if(!silent) 820 { 821 printf("st%d: soft error(corrected) ", unit); 822 if(sense->valid) 823 { 824 printf("block no. %d (decimal)\n", 825 (sense->ext.extended.info[0] <<24)| 826 (sense->ext.extended.info[1] <<16)| 827 (sense->ext.extended.info[2] <<8)| 828 (sense->ext.extended.info[3] )); 829 } 830 else 831 { 832 printf("\n"); 833 } 834 } 835 return(ESUCCESS); 836 case 0x2: 837 if(!silent) printf("st%d: not ready\n ", unit); 838 ch_data[unit].lsterr=(sense->ext.extended.info[12]<<8)| 839 sense->ext.extended.info[13] ; 840 return(ENODEV); 841 case 0x3: 842 if(!silent) 843 { 844 printf("st%d: medium error ", unit); 845 if(sense->valid) 846 { 847 printf("block no. %d (decimal)\n", 848 (sense->ext.extended.info[0] <<24)| 849 (sense->ext.extended.info[1] <<16)| 850 (sense->ext.extended.info[2] <<8)| 851 (sense->ext.extended.info[3] )); 852 } 853 else 854 { 855 printf("\n"); 856 } 857 } 858 return(EIO); 859 case 0x4: 860 if(!silent) printf("st%d: non-media hardware failure\n ", 861 unit); 862 ch_data[unit].lsterr=(sense->ext.extended.info[12]<<8)| 863 sense->ext.extended.info[13] ; 864 return(EIO); 865 case 0x5: 866 if(!silent) printf("st%d: illegal request\n ", unit); 867 ch_data[unit].lsterr=(sense->ext.extended.info[12]<<8)| 868 sense->ext.extended.info[13] ; 869 return(EINVAL); 870 case 0x6: 871 if(!silent)printf("st%d: media change\n", unit); 872 ch_data[unit].lsterr=(sense->ext.extended.info[12]<<8)| 873 sense->ext.extended.info[13] ; 874 ch_info_valid[unit] = FALSE; 875 if (ch_data[unit].flags & CH_OPEN) /* TEMP!!!! */ 876 return(EIO); 877 else 878 return(ESUCCESS); 879 case 0x7: 880 if(!silent) 881 { 882 printf("st%d: attempted protection violation " 883 , unit); 884 if(sense->valid) 885 { 886 printf("block no. %d (decimal)\n", 887 (sense->ext.extended.info[0] <<24)| 888 (sense->ext.extended.info[1] <<16)| 889 (sense->ext.extended.info[2] <<8)| 890 (sense->ext.extended.info[3] )); 891 } 892 else 893 { 894 printf("\n"); 895 } 896 } 897 return(EACCES); 898 case 0x8: 899 if(!silent) 900 { 901 printf("st%d: block wrong state (worm)\n " 902 , unit); 903 if(sense->valid) 904 { 905 printf("block no. %d (decimal)\n", 906 (sense->ext.extended.info[0] <<24)| 907 (sense->ext.extended.info[1] <<16)| 908 (sense->ext.extended.info[2] <<8)| 909 (sense->ext.extended.info[3] )); 910 } 911 else 912 { 913 printf("\n"); 914 } 915 } 916 return(EIO); 917 case 0x9: 918 if(!silent) printf("st%d: vendor unique\n", 919 unit); 920 return(EIO); 921 case 0xa: 922 if(!silent) printf("st%d: copy aborted\n ", 923 unit); 924 return(EIO); 925 case 0xb: 926 if(!silent) printf("st%d: command aborted\n ", 927 unit); 928 ch_data[unit].lsterr=(sense->ext.extended.info[12]<<8)| 929 sense->ext.extended.info[13] ; 930 return(EIO); 931 case 0xc: 932 if(!silent) 933 { 934 printf("st%d: search returned\n ", unit); 935 if(sense->valid) 936 { 937 printf("block no. %d (decimal)\n", 938 (sense->ext.extended.info[0] <<24)| 939 (sense->ext.extended.info[1] <<16)| 940 (sense->ext.extended.info[2] <<8)| 941 (sense->ext.extended.info[3] )); 942 } 943 else 944 { 945 printf("\n"); 946 } 947 } 948 return(ESUCCESS); 949 case 0xd: 950 if(!silent) printf("st%d: volume overflow\n ", 951 unit); 952 return(ENOSPC); 953 case 0xe: 954 if(!silent) 955 { 956 printf("st%d: verify miscompare\n ", unit); 957 if(sense->valid) 958 { 959 printf("block no. %d (decimal)\n", 960 (sense->ext.extended.info[0] <<24)| 961 (sense->ext.extended.info[1] <<16)| 962 (sense->ext.extended.info[2] <<8)| 963 (sense->ext.extended.info[3] )); 964 } 965 else 966 { 967 printf("\n"); 968 } 969 } 970 return(EIO); 971 case 0xf: 972 if(!silent) printf("st%d: unknown error key\n ", 973 unit); 974 return(EIO); 975 } 976 break; 977 } 978 /***************************************************************\ 979 * If it's NOT class 7, just report it. * 980 \***************************************************************/ 981 case 0: 982 case 1: 983 case 2: 984 case 3: 985 case 4: 986 case 5: 987 case 6: 988 { 989 if(!silent) printf("st%d: error class %d code %d\n", 990 unit, 991 sense->error_class, 992 sense->error_code); 993 if(sense->valid) 994 if(!silent) printf("block no. %d (decimal)\n", 995 (sense->ext.unextended.blockhi <<16), 996 + (sense->ext.unextended.blockmed <<8), 997 + (sense->ext.unextended.blocklow )); 998 } 999 return(EIO); 1000 } 1001 } 1002 1003 1004 1005