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