5ce1f1e3c6572bd0cd4beef8111a4d53f2a594b5
[debian/amanda] / changer-src / scsi-changer-driver.c
1 static char rcsid[] = "$Id: scsi-changer-driver.c,v 1.52.2.1 2006/11/01 13:55:55 martinea Exp $";
2 /*
3  * Interface to control a tape robot/library connected to the SCSI bus
4  *
5  * Copyright (c) Thomas Hepper th@ant.han.de
6  */
7
8 #include <amanda.h>
9
10 #include "arglist.h"
11 /*
12 #ifdef HAVE_STDIO_H
13 */
14 #include <stdio.h>
15 /*
16 #endif
17 */
18 #ifdef  HAVE_STDLIB_H
19 #include <stdlib.h>
20 #endif
21 #ifdef HAVE_FCNTL_H
22 #include <fcntl.h>
23 #endif
24 #ifdef HAVE_ERRNO_H
25 #include <errno.h>
26 #endif
27 #ifdef HAVE_STRING_H
28 #include <string.h>
29 #endif
30 #ifdef HAVE_UNISTD_H
31 #include <unistd.h>
32 #endif
33 #
34 #ifdef STDC_HEADERS
35 #include <stdarg.h>
36 #else
37 #include <varargs.h>
38 #endif
39
40 #include "scsi-defs.h"
41
42 #include "tapeio.h"
43
44 extern FILE *debug_file;
45 extern changer_t *changer;    /* Needed for the infos about emubarcode and labelfile */
46
47 int PrintInquiry(SCSIInquiry_T *);
48 int GenericElementStatus(int DeviceFD, int InitStatus);
49 int SDXElementStatus(int DeviceFD, int InitStatus);
50 int DLT448ElementStatus(int DeviceFD, int InitStatus);
51 ElementInfo_T *LookupElement(int addr);
52 int GenericResetStatus(int DeviceFD);
53 int RequestSense(int, ExtendedRequestSense_T *, int  );
54 void dump_hex(u_char *, size_t, int, int);
55 void TerminateString(char *string, size_t length);
56 void ChgExit(char *, char *, int);
57 int BarCode(int fd);
58 int LogSense(int fd);
59 int SenseHandler(int fd, u_char flag, u_char SenseKey, u_char AdditionalSenseCode, u_char AdditionalSenseCodeQualifier, RequestSense_T *buffer);
60
61 int SCSI_AlignElements(int DeviceFD, size_t MTE, size_t DTE, size_t STE);
62
63 int DoNothing0(void);
64 int DoNothing1(int);
65 int DoNothing2(int, int);
66 int DoNothing3(int, int, int);
67
68 int GenericMove(int, int, int);
69 int SDXMove(int, int, int);
70 int CheckMove(ElementInfo_T *from, ElementInfo_T *to);
71 int GenericRewind(int);
72 /* int GenericStatus(void); */
73 int GenericFree(void);
74 int TapeStatus(void);                   /* Is the tape loaded ? */
75 int DLT4000Eject(char *Device, int type);
76 int GenericEject(char *Device, int type);
77 int SCSI_LogSenseClean(char *Device);           /* Does the tape need a clean */
78 int GenericClean(char *Device);                 /* Does the tape need a clean */
79 int GenericBarCode(int DeviceFD);               /* Do we have Barcode reader support */
80 int NoBarCode(int DeviceFD);
81
82 int GenericSearch(void);
83 void Inventory(char *labelfile, int drive, int eject, int start, int stop, int clean);
84
85 int TreeFrogBarCode(int DeviceFD);
86 int EXB_BarCode(int DeviceFD);
87 int GenericSenseHandler(int fd, u_char flags, u_char SenseKey, u_char AdditionalSenseCode, u_char AdditionalSenseCodeQualifier, RequestSense_T *);
88
89 ElementInfo_T *LookupElement(int address);
90 int eject_tape(char *tapedev, int type);
91 int unload(int fd, int drive, int slot);
92 int load(int fd, int drive, int slot);
93 int GetElementStatus(int DeviceFD);
94 int drive_loaded(int fd, int drivenum);
95
96 /*
97  * Log Pages Decode
98  */
99 void WriteErrorCountersPage(LogParameter_T *, size_t);
100 void ReadErrorCountersPage(LogParameter_T *, size_t);
101 void C1553APage30(LogParameter_T *, size_t);
102 void C1553APage37(LogParameter_T *, size_t);
103 void EXB85058HEPage39(LogParameter_T *, size_t);
104 void EXB85058HEPage3c(LogParameter_T *, size_t);
105 int Decode(LogParameter_T *, unsigned *);
106 int DecodeModeSense(u_char *buffer, size_t offset, char *pstring, char block, FILE *out);
107
108 int SCSI_Run(int DeviceFD,
109              Direction_T Direction,
110              CDB_T CDB,
111              size_t CDB_Length,
112              void *DataBuffer,
113              size_t DataBufferLength,
114              RequestSense_T *pRequestSense,
115              size_t RequestSenseLength);
116
117 int SCSI_Move(int DeviceFD, u_char chm, int from, int to);
118 int SCSI_LoadUnload(int DeviceFD, RequestSense_T *pRequestSense, u_char byte1, u_char load);
119 int SCSI_TestUnitReady(int, RequestSense_T *);
120 int SCSI_ModeSense(int DeviceFD, u_char *buffer, u_char size, u_char byte1, u_char byte2);
121 int SCSI_ModeSelect(int DeviceFD,
122                     u_char *buffer,
123                     u_char length,
124                     u_char save,
125                     u_char mode,
126                     u_char lun);
127
128 int SCSI_ReadElementStatus(int DeviceFD,
129                            u_char type,
130                            u_char lun,
131                            u_char VolTag,
132                            int StartAddress,
133                            size_t NoOfElements,
134                            size_t DescriptorSize,
135                            u_char **data);
136
137 FILE *StatFile;
138 static int barcode;   /* cache the result from the BarCode function */
139
140 SC_COM_T SCSICommand[] = {
141   {0x00,
142    6,
143    "TEST UNIT READY"},
144   {0x01,
145    6,
146    "REWIND"},
147   {0x03,
148    6,
149    "REQUEST SENSE"},
150   {0x07,
151    6,
152    "INITIALIZE ELEMENT STATUS"},
153   {0x12,
154    6,
155    "INQUIRY"},
156   {0x13,
157    6,
158    "ERASE"},
159   {0x15,
160    6,
161    "MODE SELECT"},
162   {0x1A,
163    6,
164    "MODE SENSE"},
165   {0x1B,
166    6,
167    "UNLOAD"},
168   {0x4D,
169    10,
170    "LOG SENSE"},
171   {0xA5,
172    12,
173    "MOVE MEDIUM"},
174   { 0xE5,
175     12,
176    "VENDOR SPECIFIC"},
177   {0xB8,
178    12,
179    "READ ELEMENT STATUS"},
180   {0, 0, 0}
181 };
182
183 ChangerCMD_T ChangerIO[] = {
184   {"generic_changer",
185    "Generic driver changer [generic_changer]",
186    GenericMove,
187    GenericElementStatus,
188    GenericResetStatus,
189    GenericFree,
190    GenericEject,
191    GenericClean,
192    GenericRewind,
193    GenericBarCode,
194    GenericSearch,
195    GenericSenseHandler},
196   /* HP Devices */
197   {"C1553A",
198    "HP Auto Loader [C1553A]",
199    GenericMove,
200    GenericElementStatus,
201    DoNothing1,
202    GenericFree,
203    GenericEject,
204    GenericClean,
205    GenericRewind,
206    GenericBarCode,
207    GenericSearch,
208    GenericSenseHandler},
209   /* Exabyte Devices */
210   {"EXB-10e",
211    "Exabyte Robot [EXB-10e]",
212    GenericMove,
213    GenericElementStatus,
214    GenericResetStatus,
215    GenericFree,
216    GenericEject,
217    GenericClean,
218    GenericRewind,
219    GenericBarCode,
220    GenericSearch,
221    GenericSenseHandler},
222   {"EXB-120",
223    "Exabyte Robot [EXB-120]",
224    GenericMove,
225    GenericElementStatus,
226    GenericResetStatus,
227    GenericFree,
228    GenericEject,
229    GenericClean,
230    GenericRewind,
231    EXB_BarCode,
232    GenericSearch,
233    GenericSenseHandler},
234   {"EXB-210",
235    "Exabyte Robot [EXB-210]",
236    GenericMove,
237    GenericElementStatus,
238    GenericResetStatus,
239    GenericFree,
240    GenericEject,
241    GenericClean,
242    GenericRewind,
243    EXB_BarCode,
244    GenericSearch,
245    GenericSenseHandler},
246   {"EXB-85058HE-0000",
247    "Exabyte Tape [EXB-85058HE-0000]",
248    DoNothing3,
249    DoNothing2,
250    DoNothing1,
251    DoNothing0,
252    GenericEject,
253    GenericClean,
254    GenericRewind,
255    GenericBarCode,
256    GenericSearch,
257    GenericSenseHandler},
258   /* Tandberg Devices */
259   {"TDS 1420",
260    "Tandberg Robot (TDS 1420)",
261    GenericMove,
262    GenericElementStatus,
263    GenericResetStatus,
264    GenericFree,
265    GenericEject,
266    GenericClean,
267    GenericRewind,
268    GenericBarCode,
269    GenericSearch,
270    GenericSenseHandler},
271     /* ADIC Devices */
272   {"VLS DLT",
273    "ADIC VLS DLT Library [VLS DLT]",
274    GenericMove,
275    GenericElementStatus,
276    GenericResetStatus,
277    GenericFree,
278    GenericEject,
279    GenericClean,
280    GenericRewind,
281    GenericBarCode,
282    GenericSearch,
283    GenericSenseHandler},
284   {"VLS SDX",
285    "ADIC VLS DLT Library [VLS SDX]",
286    SDXMove,
287    SDXElementStatus,
288    GenericResetStatus,
289    GenericFree,
290    GenericEject,
291    GenericClean,
292    GenericRewind,
293    GenericBarCode,
294    GenericSearch,
295    GenericSenseHandler},
296   {"FastStor DLT",
297    "ADIC FastStor DLT Library [FastStor DLT]",
298    SDXMove,
299    DLT448ElementStatus,
300    GenericResetStatus,
301    GenericFree,
302    GenericEject,
303    GenericClean,
304    GenericRewind,
305    GenericBarCode,
306    GenericSearch,
307    GenericSenseHandler},
308   {"Scalar DLT 448",
309    "ADIC DLT 448 [Scalar DLT 448]",
310    GenericMove,
311    DLT448ElementStatus,
312    GenericResetStatus,
313    GenericFree,
314    GenericEject,
315    GenericClean,
316    GenericRewind,
317    GenericBarCode,
318    GenericSearch,
319    GenericSenseHandler},
320    /* Sepctra Logic Devices */
321   {"215",
322    "Spectra Logic TreeFrog[215]",
323    GenericMove,
324    GenericElementStatus,
325    GenericResetStatus,
326    GenericFree,
327    GenericEject,
328    GenericClean,
329    GenericRewind,
330    TreeFrogBarCode,
331    GenericSearch,
332    GenericSenseHandler},
333   /* BreeceHill Q7 */
334   {"Quad 7",
335    "Breece Hill Quad 7",
336    GenericMove,
337    GenericElementStatus,
338    GenericResetStatus,
339    GenericFree,
340    GenericEject,
341    GenericClean,
342    GenericRewind,
343    GenericBarCode,
344    GenericSearch,
345    GenericSenseHandler},
346   /* Quantum Devices */
347   {"L500",
348    "ATL [L500]",
349    GenericMove,
350    GenericElementStatus,
351    GenericResetStatus,
352    GenericFree,
353    GenericEject,
354    GenericClean,
355    GenericRewind,
356    GenericBarCode,
357    GenericSearch,
358    GenericSenseHandler},
359   /*
360    * And now the tape devices
361    */
362   /* The generic handler if nothing matches */
363   {"generic_tape",
364    "Generic driver tape [generic_tape]",
365    GenericMove,
366    GenericElementStatus,
367    GenericResetStatus,
368    GenericFree,
369    GenericEject,
370    GenericClean,
371    GenericRewind,
372    NoBarCode,
373    GenericSearch,
374    GenericSenseHandler},
375   {"DLT8000",
376    "DLT Tape [DLT8000]",
377    DoNothing3,
378    DoNothing2,
379    DoNothing1,
380    DoNothing0,
381    DLT4000Eject,
382    GenericClean,
383    GenericRewind,
384    GenericBarCode,
385    GenericSearch,
386    GenericSenseHandler},
387   {"DLT7000",
388    "DLT Tape [DLT7000]",
389    DoNothing3,
390    DoNothing2,
391    DoNothing1,
392    DoNothing0,
393    DLT4000Eject,
394    GenericClean,
395    GenericRewind,
396    GenericBarCode,
397    GenericSearch,
398    GenericSenseHandler},
399   {"DLT4000",
400    "DLT Tape [DLT4000]",
401    DoNothing3,
402    DoNothing2,
403    DoNothing1,
404    DoNothing0,
405    DLT4000Eject,
406    GenericClean,
407    GenericRewind,
408    NoBarCode,
409    GenericSearch,
410    GenericSenseHandler},
411   {"SLR100",
412    "Tandberg SLR100",
413    GenericMove,
414    GenericElementStatus,
415    GenericResetStatus,
416    GenericFree,
417    GenericEject,
418    SCSI_LogSenseClean,
419    GenericRewind,
420    NoBarCode,
421    GenericSearch,
422    GenericSenseHandler},
423    {NULL, NULL, NULL,NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}
424 };
425
426
427 LogPageDecode_T DecodePages[] = {
428   {2,
429    "C1553A",
430    WriteErrorCountersPage},
431   {3,
432    "C1553A",
433    ReadErrorCountersPage},
434   {0x30,
435    "C1553A",
436    C1553APage30},
437   {0x37,
438    "C1553A",
439    C1553APage37},
440   {2,
441    "*",
442    WriteErrorCountersPage},
443   {3,
444    "*",
445    ReadErrorCountersPage},
446   {0x39,
447    "EXB-85058HE-0000",
448    EXB85058HEPage39},
449   {0x3c,
450    "EXB-85058HE-0000",
451    EXB85058HEPage3c},
452   {0, NULL, NULL}
453 };
454
455
456 int ElementStatusValid = 0;         /* Set if the READ ELEMENT STATUS was OK, an no error is pending */
457 int LibModeSenseValid = 0;          /* Set if we did an scussefull MODE SENSE */
458
459 char *SlotArgs = 0;
460 /* Pointer to MODE SENSE Pages */
461 u_char *pModePage = NULL;
462 EAAPage_T *pEAAPage = NULL;
463 DeviceCapabilitiesPage_T *pDeviceCapabilitiesPage = NULL;
464 u_char *pVendorUnique = NULL;
465
466 /*
467  *  New way, every element type has its on array
468  * which is dynamic allocated by the ElementStatus function,
469 */
470 ElementInfo_T *pMTE = NULL; /*Medium Transport Element */
471 ElementInfo_T *pSTE = NULL; /*Storage Element */
472 ElementInfo_T *pIEE = NULL; /*Import Export Element */
473 ElementInfo_T *pDTE = NULL; /*Data Transfer Element */
474 size_t MTE = 0;                /*Counter for the above element types */
475 size_t STE = 0;
476 size_t IEE = 0;
477 size_t DTE = 0;
478
479 char *chgscsi_datestamp = NULL;       /* Result pointer for tape_rdlabel */
480 char *chgscsi_label = NULL;           /* Result pointer for tape_rdlabel */
481 char *chgscsi_result = NULL;          /* Needed for the result string of MapBarCode */
482
483 /*
484  * First all functions which are called from extern
485  */
486
487
488 /*
489  * Print the scsi-changer-driver version
490  */
491
492 void
493 ChangerDriverVersion(void)
494 {
495   DebugPrint(DEBUG_ERROR, SECTION_INFO, "scsi-changer-driver: %s\n",rcsid);
496   SCSI_OS_Version();
497 }
498
499 /*
500  * Try to generate an template which can be used as an example for the config file
501  *
502  */
503 void
504 PrintConf(void)
505 {
506   extern OpenFiles_T *pDev;
507   int count;
508   char *cwd;
509
510   printf("# Please replace every ??? with the correct parameter. It is not possible\n");
511   printf("# to guess everything :-)\n");
512   printf("# If the option is not needed, cleanmax for example if you have no cleaning\n");
513   printf("# tape remove the line.\n");
514   printf("#\n");
515   printf("number_configs   1   # Number of configs, you can have more than 1 config\n");
516   printf("                     # if you have for example more than one drive, or you\n");
517   printf("                     # to split your lib to use different dump levels\n");
518   printf("                     #\n");
519   printf("emubarcode       1   # If you drive has no barcode reader this will try\n");
520   printf("                     # keep an inventory of your tapes to find them faster\n");
521   printf("                     #\n");
522   printf("havebarcode      0   # Set this to 1 if you have an library with an installed\n");
523   printf("                     # barcode reader\n");
524   printf("                     #\n");
525   printf("debuglevel       0:0 # For debuging, see the docs /docs/TAPE-CHANGER\n");
526   printf("                     #\n");
527   printf("eject            ??? # set this to 1 if your drive needs an eject before move\n");
528   printf("                     #\n");
529   printf("sleep            ??? # How long to wait after an eject command before moving\n");
530   printf("                     # the tape\n");
531   printf("                     #\n");
532
533   for (count = 0; count < CHG_MAXDEV ; count++)
534     {
535       if (pDev[count].dev)
536         {
537           if (pDev[count].inquiry != NULL && pDev[count].inquiry->type == TYPE_CHANGER)
538             {
539               printf("changerdev   %s # This is the device to communicate with the robot\n", pDev[count].dev);
540               break;
541             }
542         }
543     }
544
545   /*
546    * Did we reach the end of the list ?
547    * If no we found an changer and now we try to
548    * get the element status for the count of slots
549    */
550   if (count < CHG_MAXDEV)
551     {
552       pDev[count].functions->function_status(count, 1);
553     } else {
554       printf("changerdev   ??? # Ups nothing found. Please check the docs\n");
555     }
556
557   printf("                     #\n");
558   printf("                     # Here now comes the config for the first tape\n");
559   printf("config             0 # This value is the one which is used in the amanda\n");
560   printf("                     # config file to tell the chg-scsi programm which tape\n");
561   printf("                     # and which slots to use\n");
562   printf("                     #\n");
563   printf("cleancart        ??? # The slot where the cleaning tape is located\n");
564   printf("                     # remove it if you have no cleaning tape\n");
565   printf("                     #\n");
566   printf("drivenum           0 # Which tape drive to use if there are more than one drive\n");
567   printf("                     #\n");
568   printf("dev              ??? # Which is the raw device to read/write data from the tape\n");
569   printf("                     # It is important to use the non rewinding tape, like\n");
570   printf("                     # /dev/nrst0 on linux, /dev/nrsa0 on BSD ....\n");
571   printf("                     #\n");
572
573   /*
574    * OK now lets see if we have an direct SCSI channel
575    * to the tape
576    * If not thats not a problem
577    */
578   for (count = 0; count < CHG_MAXDEV; count++)
579     {
580       if (pDev[count].dev)
581         {
582           if (pDev[count].inquiry != NULL && pDev[count].inquiry->type == TYPE_TAPE)
583             {
584               printf("scsitapedev   %s # This is the device to communicate with the tape\n", pDev[count].dev);
585               printf("                     # to get some device stats, not so importatn, and\n");
586               printf("                     # if you run in problems delete it complete\n");
587               printf("                     #\n");
588               break;
589             }
590         }
591     }
592
593
594   if (STE != 0)
595     {
596       printf("startuse          0  # Which is the first slot to use\n");
597       printf("                     #\n");
598       printf("enduse            " SIZE_T_FMT "  # Which is the last slot to use\n", STE);
599     } else {
600       printf("startuse         ??? # Which is the first slot to use\n");
601       printf("                     #\n");
602       printf("enduse           ??? # Which is the last slot to use\n");
603     }
604       printf("                     # decrement this value by 1 if you have an\n");
605       printf("                     # cleaning tape in the last slot\n");
606       printf("                     #\n");
607
608   if ((cwd = getcwd(NULL, 0)) == NULL) {
609       cwd = "<unknown>";
610   }
611
612   printf("statfile %s/tape0-slot #\n",cwd);
613   printf("cleanfile %s/tape0-clean #\n", cwd);
614   printf("usagecount %s/tape0-totaltime #\n", cwd);
615   printf("tapestatus %s/tape0-tapestatus #\n", cwd);
616   printf("labelfile %s/labelfile #\n", cwd);
617 }
618
619
620
621 /*
622  * Try to create a list of tapes and labels which are in the current
623  * magazin. The drive must be empty !!
624  *
625  * labelfile -> file name of the db
626  * drive -> which drive should we use
627  * eject -> the tape device needs an eject before move
628  * start -> start at slot start
629  * stop  -> stop at slot stop
630  * clean -> if we have an cleaning tape than this is the slot number of it
631  *
632  * return
633  * 0  -> fail
634  * 1  -> successfull
635  *
636  * ToDo:
637  * Check if the tape/changer is ready for the next move
638  * If an tape is loaded unload it and do initialize element status to
639  * get all labels if an bar code reader is installed
640  */
641 void
642 Inventory(
643     char *      labelfile,
644     int         drive,
645     int         eject,
646     int         start,
647     int         stop,
648     int         clean)
649 {
650   extern OpenFiles_T *pDev;
651   size_t x;
652   static int inv_done = 0;      /* Inventory function called ?, marker to disable recursion */
653   MBC_T *pbarcoderes;           /* Here we will pass the parameter to MapBarCode and get the result */
654
655   (void)start;  /* Quiet unused parameter warning */
656   (void)stop;   /* Quiet unused parameter warning */
657
658   DebugPrint(DEBUG_INFO,SECTION_MAP_BARCODE, "##### START Inventory\n");
659   pbarcoderes = alloc(SIZEOF(MBC_T));
660   memset(pbarcoderes, 0 , SIZEOF(MBC_T));
661
662   if (inv_done != 0)
663     {
664       DebugPrint(DEBUG_INFO,SECTION_MAP_BARCODE, "##### STOP inv_done -> %d Inventory\n",inv_done);
665       free(pbarcoderes);
666       return;
667       /*NOTREACHED*/
668     }
669   inv_done = 1;
670   barcode = BarCode(INDEX_CHANGER);
671
672   pbarcoderes->action = RESET_VALID;
673
674   MapBarCode(labelfile,pbarcoderes);
675
676   /*
677    * Check if an tape is loaded, if yes unload it
678    * and do an INIT ELEMENT STATUS
679    */
680
681   if (pDTE[0].status == 'F')
682     {
683       if (eject)
684         {
685           (void)eject_tape("", eject);
686         }
687       (void)unload(INDEX_TAPE, 0, 0);
688     }
689
690   GenericResetStatus(INDEX_CHANGER);
691
692   for (x = 0; x < STE; x++)
693     {
694       if (x == (size_t)clean)
695         {
696           continue;
697         }
698
699       /*
700        * Load the tape, on error try the next
701        * error could be an empty slot for example
702        */
703       if (load(INDEX_CHANGER, drive, x ) != 0)
704         {
705           DebugPrint(DEBUG_ERROR,SECTION_MAP_BARCODE, "Load drive(%d) from(%d) failed\n", drive, x);
706           continue;
707         }
708
709       /*
710        * Wait until the tape is ready
711        */
712       Tape_Ready(INDEX_TAPECTL, 60);
713
714       SCSI_CloseDevice(INDEX_TAPE);
715
716       if ((chgscsi_result = (char *)tape_rdlabel(pDev[INDEX_TAPE].dev, &chgscsi_datestamp, &chgscsi_label)) == NULL)
717       {
718         pbarcoderes->action = UPDATE_SLOT;
719         strncpy(pbarcoderes->data.voltag, chgscsi_label,
720                 SIZEOF(pbarcoderes->data.voltag));
721         pbarcoderes->data.slot = x;
722         pbarcoderes->data.from = 0;
723         pbarcoderes->data.LoadCount = 1;
724         if (BarCode(INDEX_CHANGER) == 1)
725           {
726             strncpy(pbarcoderes->data.barcode, pDTE[drive].VolTag,
727                     SIZEOF(pbarcoderes->data.barcode));
728             MapBarCode(labelfile, pbarcoderes);
729           } else {
730             MapBarCode(labelfile, pbarcoderes);
731           }
732       } else {
733         DebugPrint(DEBUG_ERROR,SECTION_MAP_BARCODE, "Read label failed\n");
734       }
735
736       if (eject)
737         {
738           (void)eject_tape("", eject);
739         }
740
741       (void)unload(INDEX_TAPE, drive, x);
742     }
743   DebugPrint(DEBUG_INFO,SECTION_MAP_BARCODE, "##### STOP Inventory\n");
744   free(pbarcoderes);
745 }
746
747 /*
748  * Check if the slot ist empty
749  * slot -> slot number to check
750  */
751 int
752 isempty(
753     int         fd,
754     int         slot)
755 {
756   extern OpenFiles_T *pDev;
757   DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### START isempty\n");
758
759   if (ElementStatusValid == 0)
760     {
761       if ( pDev[fd].functions->function_status(fd, 1) != 0)
762         {
763           DebugPrint(DEBUG_ERROR,SECTION_TAPE,"##### STOP isempty [-1]\n");
764           return(-1);
765           /*NOTREACHED*/
766         }
767     }
768
769   if (pSTE[slot].status == 'E')
770     {
771       DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### STOP isempty [1]\n");
772       return(1);
773       /*NOTREACHED*/
774     }
775   DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### STOP isempty [0]\n");
776   return(0);
777 }
778
779 int
780 get_clean_state(
781     char *tapedev)
782 {
783   extern OpenFiles_T *pDev;
784   /* Return 1 if cleaning is needed */
785   int ret;
786
787   DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### START get_clean_state\n");
788
789   if (pDev[INDEX_TAPECTL].SCSI == 0)
790     {
791       DebugPrint(DEBUG_ERROR,SECTION_TAPE,"##### STOP get_clean_state [-1]\n");
792       return(-1);
793       /*NOTREACHED*/
794     }
795   ret=pDev[INDEX_TAPECTL].functions->function_clean(tapedev);
796   DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### STOP get_clean_state [%d]\n", ret);
797   return(ret);
798 }
799
800 /*
801  * eject the tape
802  * The parameter tapedev is not used.
803  * Type describes if we should force the SCSI eject if available
804  * normal eject is done with the ioctl
805  */
806 /* This function ejects the tape from the drive */
807
808 int
809 eject_tape(
810     char *      tapedev,
811     int         type)
812 {
813   extern OpenFiles_T *pDev;
814   int ret;
815
816   DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### START eject_tape %s\n",tapedev);
817   if (pDev[INDEX_TAPECTL].functions == NULL)
818     return(-1);
819
820   /*
821    * Try to read the label
822    */
823   if (pDev[INDEX_TAPE].avail == 1 && (changer->emubarcode == 1 || BarCode(INDEX_CHANGER)))
824     {
825
826       if (pDev[INDEX_TAPECTL].SCSI == 1 && pDev[INDEX_TAPECTL].avail) {
827         DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### eject_tape rewind\n");
828         pDev[INDEX_TAPECTL].functions->function_rewind(INDEX_TAPECTL);
829       } else {
830         DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### eject_tape rewind2\n");
831         pDev[INDEX_TAPE].functions->function_rewind(INDEX_TAPE);
832       }
833
834       if (pDev[INDEX_TAPE].devopen == 1)
835         {
836           DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### eject_tape close\n");
837           SCSI_CloseDevice(INDEX_TAPE);
838         }
839
840       DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### tape_eject tape_rdlabel\n");
841       chgscsi_result = (char *)tape_rdlabel(pDev[INDEX_TAPE].dev, &chgscsi_datestamp, &chgscsi_label);
842     }
843
844   if (pDev[INDEX_TAPECTL].SCSI == 1 && pDev[INDEX_TAPECTL].avail == 1 && type == 1)
845     {
846       DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### tape_eject eject\n");
847       ret=pDev[INDEX_TAPECTL].functions->function_eject(tapedev, type);
848       DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### STOP (SCSI)eject_tape [%d]\n", ret);
849       return(ret);
850       /*NOTREACHED*/
851     }
852
853   if (pDev[INDEX_TAPE].avail == 1)
854     {
855       ret=Tape_Ioctl(INDEX_TAPE, IOCTL_EJECT);
856       DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### STOP (ioctl)eject_tape [%d]\n", ret);
857       return(ret);
858       /*NOTREACHED*/
859     }
860
861   DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### STOP eject_tape [-1]\n");
862   return(-1);
863 }
864
865
866 /* Find an empty slot, starting at start, ending at start+count */
867 int
868 find_empty(
869     int fd,
870     int start,
871     int count)
872 {
873   extern OpenFiles_T *pDev;
874   size_t x;
875   size_t end;
876
877   DebugPrint(DEBUG_INFO,SECTION_ELEMENT,"###### START find_empty\n");
878
879   if (ElementStatusValid == 0)
880     {
881       if ( pDev[fd].functions->function_status(fd , 1) != 0)
882         {
883           DebugPrint(DEBUG_ERROR,SECTION_ELEMENT,
884                      "###### END find_empty [-1]\n");
885           return((ssize_t)-1);
886           /*NOTREACHED*/
887         }
888     }
889
890   if (count == 0)
891     {
892       end = STE;
893     } else {
894       end = start + count;
895     }
896
897   if (end > STE)
898     {
899       end = STE;
900     }
901
902   DebugPrint(DEBUG_INFO, SECTION_ELEMENT,
903              "start at " SIZE_T_FMT ", end at " SIZE_T_FMT "\n",
904              (SIZE_T_FMT_TYPE)start,
905              (SIZE_T_FMT_TYPE)end);
906
907   for (x = start; x < end; x++)
908     {
909       if (pSTE[x].status == 'E')
910         {
911           DebugPrint(DEBUG_INFO,SECTION_ELEMENT,
912                      "###### END find_empty [" SIZE_T_FMT "]\n", x);
913           return((ssize_t)x);
914           /*NOTREACHED*/
915         }
916     }
917   DebugPrint(DEBUG_ERROR,SECTION_ELEMENT,"###### END find_empty [-1]\n");
918   return((ssize_t)-1);
919 }
920
921 /*
922  * See if the tape is loaded based on the information we
923  * got back from the ReadElementStatus
924  * return values
925  * -1 -> Error (Fatal)
926  * 0  -> drive is empty
927  * 1  -> drive is loaded
928  */
929 int
930 drive_loaded(
931     int         fd,
932     int         drivenum)
933 {
934   extern OpenFiles_T *pDev;
935
936   DebugPrint(DEBUG_INFO,SECTION_TAPE,"###### START drive_loaded\n");
937   DebugPrint(DEBUG_INFO,SECTION_TAPE,"%-20s : fd %d drivenum %d \n", "drive_loaded", fd, drivenum);
938
939
940   if (ElementStatusValid == 0)
941     {
942       if (pDev[INDEX_CHANGER].functions->function_status(INDEX_CHANGER, 1) != 0)
943         {
944           DebugPrint(DEBUG_ERROR,SECTION_TAPE,"Fatal error\n");
945           return(-1);
946           /*NOTREACHED*/
947         }
948     }
949
950   if (pDTE[drivenum].status == 'E') {
951     DebugPrint(DEBUG_INFO,SECTION_TAPE,"###### STOP drive_loaded (empty)\n");
952     return(0);
953     /*NOTREACHED*/
954   }
955   DebugPrint(DEBUG_INFO,SECTION_TAPE,"###### STOP drive_loaded (not empty)\n");
956   return(1);
957 }
958
959
960 /*
961  * unload the specified drive into the specified slot
962  * (storage element)
963  *
964  * TODO:
965  * Check if the MTE is empty
966  */
967 int
968 unload(
969     int         fd,
970     int         drive,
971     int         slot)
972 {
973   extern OpenFiles_T *pDev;
974   extern int do_inventory;
975   MBC_T *pbarcoderes;
976
977   DebugPrint(DEBUG_INFO, SECTION_TAPE,"###### START unload\n");
978   DebugPrint(DEBUG_INFO, SECTION_TAPE,"%-20s : fd %d, slot %d, drive %d \n", "unload", fd, slot, drive);
979   pbarcoderes = alloc(SIZEOF(MBC_T));
980   memset(pbarcoderes, 0, SIZEOF(MBC_T));
981
982   /*
983    * If the Element Status is not valid try to
984    * init it
985    */
986   if (ElementStatusValid == 0)
987     {
988       if (pDev[INDEX_CHANGER].functions->function_status(INDEX_CHANGER , 1) != 0)
989         {
990           DebugPrint(DEBUG_ERROR, SECTION_TAPE,"Element Status not valid, reset failed\n");
991           DebugPrint(DEBUG_ERROR, SECTION_TAPE,"##### STOP unload (-1)\n");
992           free(pbarcoderes);
993           return(-1);
994           /*NOTREACHED*/
995         }
996     }
997
998   DebugPrint(DEBUG_INFO, SECTION_TAPE,"%-20s : unload drive %d[%d] slot %d[%d]\n", "unload",
999              drive,
1000              pDTE[drive].address,
1001              slot,
1002              pSTE[slot].address);
1003
1004   /*
1005    * Unloading an empty tape unit makes no sense
1006    * so return with an error
1007    */
1008   if (pDTE[drive].status == 'E')
1009     {
1010       DebugPrint(DEBUG_ERROR, SECTION_TAPE,"unload : Drive %d address %d is empty\n", drive, pDTE[drive].address);
1011       DebugPrint(DEBUG_ERROR, SECTION_TAPE,"##### STOP unload (-1)\n");
1012       free(pbarcoderes);
1013       return(-1);
1014       /*NOTREACHED*/
1015     }
1016
1017   /*
1018    * If the destination slot is full
1019    * try to find an enpty slot
1020    */
1021   if (pSTE[slot].status == 'F')
1022     {
1023       DebugPrint(DEBUG_INFO, SECTION_TAPE,"unload : Slot %d address %d is full\n", drive, pSTE[slot].address);
1024       if ( ElementStatusValid == 0)
1025         {
1026           DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "unload: Element Status not valid, can't find an empty slot\n");
1027           free(pbarcoderes);
1028           return(-1);
1029           /*NOTREACHED*/
1030         }
1031
1032       slot = find_empty(fd, 0, 0);
1033       if (slot == -1 )
1034       {
1035               DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "unload: No Empty slot found\n");
1036               free(pbarcoderes);
1037               return(-1);
1038               /*NOTREACHED*/
1039       }
1040       DebugPrint(DEBUG_INFO, SECTION_TAPE,"unload : found empty one, try to unload to slot %d\n", slot);
1041     }
1042
1043
1044
1045   /*
1046    * If eject is not set we must read the label info
1047    */
1048
1049   if (changer->eject == 0)
1050     {
1051       if (pDev[INDEX_TAPE].avail == 1 && (changer->emubarcode == 1 || BarCode(INDEX_CHANGER)))
1052         {
1053
1054           if (pDev[INDEX_TAPECTL].SCSI == 1 && pDev[INDEX_TAPECTL].avail) {
1055             pDev[INDEX_TAPECTL].functions->function_rewind(INDEX_TAPECTL);
1056           } else {
1057             pDev[INDEX_TAPE].functions->function_rewind(INDEX_TAPE);
1058           }
1059
1060           if (pDev[INDEX_TAPE].devopen == 1)
1061             {
1062               SCSI_CloseDevice(INDEX_TAPE);
1063             }
1064
1065           chgscsi_result = (char *)tape_rdlabel(pDev[INDEX_TAPE].dev, &chgscsi_datestamp, &chgscsi_label);
1066         }
1067     }
1068
1069   /*
1070    * Do the unload/move
1071    */
1072   if (pDev[INDEX_CHANGER].functions->function_move(INDEX_CHANGER,
1073            pDTE[drive].address, pSTE[slot].address) != 0) {
1074       DebugPrint(DEBUG_ERROR, SECTION_TAPE,"##### STOP unload (-1 move failed)\n");
1075       free(pbarcoderes);
1076       return(-1);
1077       /*NOTREACHED*/
1078     }
1079
1080
1081   /*
1082    * Update the Status
1083    */
1084   if (pDev[INDEX_CHANGER].functions->function_status(INDEX_CHANGER , 1) != 0)
1085     {
1086       DebugPrint(DEBUG_ERROR, SECTION_TAPE,"##### STOP unload (-1 update status failed)\n");
1087       free(pbarcoderes);
1088       return(-1);
1089       /*NOTREACHED*/
1090     }
1091
1092   /*
1093    * Did we get an error from tape_rdlabel
1094    * if no update the vol/label mapping
1095    * If chgscsi_label is NULL don't do it
1096    */
1097   if (chgscsi_result  == NULL && chgscsi_label != NULL && changer->labelfile != NULL)
1098   {
1099     /*
1100      * OK this is only needed if we have emubarcode set
1101      * There we need an exact inventory to get the search function working
1102      * and returning correct results
1103      */
1104     if (BarCode(INDEX_CHANGER) == 0 && changer->emubarcode == 1)
1105       {
1106         /*
1107          * We got something, update the db
1108          * but before check if the db has as entry the slot
1109          * to where we placed the tape, if no force an inventory
1110          */
1111         pbarcoderes->action = FIND_SLOT;
1112         strncpy(pbarcoderes->data.voltag, chgscsi_label,
1113                 SIZEOF(pbarcoderes->data.voltag));
1114         strncpy(pbarcoderes->data.barcode, pSTE[slot].VolTag,
1115                SIZEOF(pbarcoderes->data.barcode));
1116         pbarcoderes->data.slot = 0;
1117         pbarcoderes->data.from = 0;
1118         pbarcoderes->data.LoadCount = 0;
1119
1120
1121         if ( MapBarCode(changer->labelfile, pbarcoderes) == 0) /* Nothing known about this, do an Inventory */
1122           {
1123             do_inventory = 1;
1124           } else {
1125             if (slot != pbarcoderes->data.slot)
1126               {
1127                 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"Slot DB out of sync, slot %d != map %d",slot, pbarcoderes->data.slot);
1128                 do_inventory = 1;
1129               }
1130           }
1131       }
1132   }
1133
1134   DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### STOP unload(0)\n");
1135   free(pbarcoderes);
1136   return(0);
1137 }
1138
1139
1140 /*
1141  * load the media from the specified element (slot) into the
1142  * specified data transfer unit (drive)
1143  * fd     -> pointer to the internal device structure pDev
1144  * driver -> which drive in the library
1145  * slot   -> the slot number from where to load
1146  *
1147  * return -> 0 = success
1148  *           !0 = failure
1149  */
1150 int
1151 load(
1152     int         fd,
1153     int         drive,
1154     int         slot)
1155 {
1156   char *result = NULL;          /* Needed for the result of tape_rdlabel */
1157   int ret;
1158   extern OpenFiles_T *pDev;
1159   extern int do_inventory;
1160   MBC_T *pbarcoderes;
1161
1162   DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"###### START load\n");
1163   DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"%-20s : fd %d, drive %d, slot %d \n", "load", fd, drive, slot);
1164   pbarcoderes = alloc(SIZEOF(MBC_T));
1165   memset(pbarcoderes, 0 , SIZEOF(MBC_T));
1166
1167   if (ElementStatusValid == 0)
1168       {
1169           if (pDev[fd].functions->function_status(fd, 1) != 0)
1170               {
1171                 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"##### STOP load (-1)\n");
1172                 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"##### STOP load (-1 update status failed)\n");
1173                 free(pbarcoderes);
1174                 return(-1);
1175                 /*NOTREACHED*/
1176               }
1177       }
1178
1179   /*
1180    * Check if the requested slot is in the range of available slots
1181    * The library starts counting at 1, we start at 0, so if the request slot
1182    * is ge than the value we got from the ModeSense fail with an return value
1183    * of 2
1184    */
1185   if ((size_t)slot >= STE)
1186     {
1187       DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"load : slot %d ge STE %d\n",slot, STE);
1188       ChgExit("load", "slot >= STE", FATAL);
1189       /*NOTREACHED*/
1190     }
1191
1192   /*
1193    * And the same for the tape drives
1194    */
1195   if (drive >= (int)DTE)
1196     {
1197       DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"load : drive %d ge DTE %d\n",drive, DTE);
1198       ChgExit("load", "drive >= DTE", FATAL);
1199       /*NOTREACHED*/
1200     }
1201
1202   DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"load : load drive %d[%d] slot %d[%d]\n",drive,
1203              pDTE[drive].address,
1204              slot,
1205              pSTE[slot].address);
1206
1207   if (pDTE[drive].status == 'F')
1208     {
1209       DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"load : Drive %d address %d is full\n", drive, pDTE[drive].address);
1210       DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"##### STOP load (-1 update status failed)\n");
1211       free(pbarcoderes);
1212       return(-1);
1213       /*NOTREACHED*/
1214     }
1215
1216   if (pSTE[slot].status == 'E')
1217     {
1218       DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"load : Slot %d address %d is empty\n", drive, pSTE[slot].address);
1219       DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"##### STOP load (-1 update status failed)\n");
1220       free(pbarcoderes);
1221       return(-1);
1222       /*NOTREACHED*/
1223     }
1224
1225   ret = pDev[fd].functions->function_move(fd, pSTE[slot].address, pDTE[drive].address);
1226
1227   /*
1228    * Update the Status
1229    */
1230   if (pDev[fd].functions->function_status(fd, 1) != 0)
1231       {
1232         DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"##### STOP load (-1 update status failed)\n");
1233         free(pbarcoderes);
1234         return(-1);
1235         /*NOTREACHED*/
1236       }
1237
1238   /*
1239    * Try to read the label
1240    * and update the label/slot database
1241    */
1242   if (pDev[INDEX_TAPE].avail == 1 && (changer->emubarcode == 1 || BarCode(INDEX_CHANGER)))
1243     {
1244
1245       if (pDev[INDEX_TAPECTL].SCSI == 1 && pDev[INDEX_TAPECTL].avail) {
1246         pDev[INDEX_TAPECTL].functions->function_rewind(INDEX_TAPECTL);
1247       } else {
1248         pDev[INDEX_TAPE].functions->function_rewind(INDEX_TAPE);
1249       }
1250
1251       if (pDev[INDEX_TAPE].devopen == 1)
1252         {
1253           SCSI_CloseDevice(INDEX_TAPE);
1254         }
1255
1256       result = (char *)tape_rdlabel(pDev[INDEX_TAPE].dev, &chgscsi_datestamp, &chgscsi_label);
1257     }
1258
1259   /*
1260    * Did we get an error from tape_rdlabel
1261    * if no update the vol/label mapping
1262    */
1263   if (result  == NULL && changer->labelfile != NULL && chgscsi_label != NULL )
1264     {
1265       /*
1266        * We got something, update the db
1267        * but before check if the db has as entry the slot
1268        * to where we placed the tape, if no force an inventory
1269        */
1270       strncpy(pbarcoderes->data.voltag, chgscsi_label,
1271               SIZEOF(pbarcoderes->data.voltag));
1272       pbarcoderes->data.slot = 0;
1273       pbarcoderes->data.from = 0;
1274       pbarcoderes->data.LoadCount = 0;
1275
1276
1277       /*
1278        * If we have an barcode reader we only do an update
1279        * If emubarcode is set we check if the
1280        * info in the DB is up to date, if no we set the do_inventory flag
1281        */
1282
1283       if (BarCode(INDEX_CHANGER) == 1 && changer->emubarcode == 0)
1284         {
1285           pbarcoderes->action = UPDATE_SLOT;
1286           strncpy(pbarcoderes->data.barcode, pDTE[drive].VolTag,
1287                   SIZEOF(pbarcoderes->data.barcode));
1288           pbarcoderes->data.LoadCount = 1;
1289           pbarcoderes->data.slot = slot;
1290           MapBarCode(changer->labelfile, pbarcoderes);
1291         }
1292
1293       if (BarCode(INDEX_CHANGER) == 0 && changer->emubarcode == 1)
1294         {
1295           pbarcoderes->action = FIND_SLOT;
1296           if (MapBarCode(changer->labelfile, pbarcoderes) == 0) /* Nothing found, do an inventory */
1297             {
1298               do_inventory = 1;
1299             } else { /* We got something, is it correct ? */
1300               if (slot != pbarcoderes->data.slot && do_inventory == 0)
1301                 {
1302                   DebugPrint(DEBUG_ERROR, SECTION_TAPE,"Slot DB out of sync, slot %d != map %d",slot, pbarcoderes->data.slot);
1303                   ChgExit("Load", "Label DB out of sync", FATAL);
1304                   /*NOTREACHED*/
1305                 } else { /* OK, so increment the load count */
1306                   pbarcoderes->action = UPDATE_SLOT;
1307                   pbarcoderes->data.LoadCount = 1;
1308                   pbarcoderes->data.slot = slot;
1309                   MapBarCode(changer->labelfile, pbarcoderes);
1310                 }
1311             }
1312         }
1313
1314       if (BarCode(INDEX_CHANGER) == 1 && changer->emubarcode == 1)
1315         {
1316           ChgExit("Load", "BarCode == 1 and emubarcode == 1", FATAL);
1317           /*NOTREACHED*/
1318         }
1319
1320       DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"##### STOP load (%d)\n",ret);
1321       free(pbarcoderes);
1322       return(ret);
1323       /*NOTREACHED*/
1324     }
1325     DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"##### STOP load (%d)\n",ret);
1326     free(pbarcoderes);
1327     return(ret);
1328 }
1329
1330 /*
1331  * Returns the number of Storage Slots which the library has
1332  * fd -> pointer to the internal devie structure pDev
1333  * return -> Number of slots
1334  */
1335 int
1336 get_slot_count(
1337     int fd)
1338 {
1339   extern OpenFiles_T *pDev;
1340
1341   DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"###### START get_slot_count\n");
1342   DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"%-20s : fd %d\n", "get_slot_count", fd);
1343
1344   if (ElementStatusValid == 0)
1345     {
1346       pDev[fd].functions->function_status(fd, 1);
1347     }
1348   DebugPrint(DEBUG_INFO, SECTION_ELEMENT,
1349              "##### STOP get_slot_count (" SIZE_T_FMT ")\n",
1350              (SIZE_T_FMT_TYPE)STE);
1351   return((ssize_t)STE);
1352   /*
1353    * return the number of slots in the robot
1354    * to the caller
1355    */
1356 }
1357
1358
1359 /*
1360  * retreive the number of data-transfer devices /Tape drives)
1361  * fd     -> pointer to the internal devie structure pDev
1362  * return -> -1 on failure
1363  */
1364 int
1365 get_drive_count(
1366     int fd)
1367 {
1368
1369   extern OpenFiles_T *pDev;
1370
1371   DebugPrint(DEBUG_INFO, SECTION_SCSI,"###### START get_drive_count\n");
1372   DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-20s : fd %d\n", "get_drive_count", fd);
1373
1374   if (ElementStatusValid == 0)
1375       {
1376           if ( pDev[fd].functions->function_status(fd, 1) != 0)
1377             {
1378                 DebugPrint(DEBUG_ERROR, SECTION_SCSI, "Error getting drive count\n");
1379                 DebugPrint(DEBUG_ERROR, SECTION_SCSI, "##### STOP get_drive_count (-1)\n");
1380                 return(-1);
1381                 /*NOTREACHED*/
1382             }
1383       }
1384   DebugPrint(DEBUG_INFO, SECTION_SCSI,
1385              "###### STOP get_drive_count (" SIZE_T_FMT " drives)\n",
1386              (SIZE_T_FMT_TYPE)DTE);
1387   return((ssize_t)DTE);
1388 }
1389
1390 /*
1391  * Now the internal functions
1392  */
1393
1394 /*
1395  * Open the device and placeit in the list of open files
1396  * The OS has to decide if it is an SCSI Commands capable device
1397  */
1398
1399 int
1400 OpenDevice(
1401     int         ip,
1402     char *      DeviceName,
1403     char *      ConfigName,
1404     char *      ident)
1405 {
1406   extern OpenFiles_T *pDev;
1407   char tmpstr[16];
1408   ChangerCMD_T *p = (ChangerCMD_T *)&ChangerIO;
1409
1410   if (!ConfigName)
1411         return 1;
1412   if (!DeviceName)
1413         return 1;
1414
1415   DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### START OpenDevice\n");
1416   DebugPrint(DEBUG_INFO, SECTION_SCSI,"OpenDevice : %s\n", DeviceName);
1417
1418   pDev[ip].ConfigName = strdup(ConfigName);
1419   pDev[ip].dev = strdup(DeviceName);
1420
1421   if (SCSI_OpenDevice(ip) != 0 )
1422     {
1423       if (ident != NULL)   /* Override by config */
1424       {
1425         while(p->ident != NULL)
1426           {
1427             if (strcmp(ident, p->ident) == 0)
1428               {
1429                 pDev[ip].functions = p;
1430                 strncpy(pDev[ip].ident, ident, 17);
1431                 DebugPrint(DEBUG_INFO, SECTION_SCSI,"override using ident = %s, type = %s\n",p->ident, p->type);
1432                 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP OpenDevice\n");
1433                 return(1);
1434                 /*NOTREACHED*/
1435               }
1436             p++;
1437           }
1438           ChgExit("OpenDevice", "ident not found", FATAL);
1439           /*NOTREACHED*/
1440       } else {
1441         while(p->ident != NULL)
1442           {
1443             if (strcmp(pDev[ip].ident, p->ident) == 0)
1444               {
1445                 pDev[ip].functions = p;
1446                 DebugPrint(DEBUG_INFO, SECTION_SCSI,"using ident = %s, type = %s\n",p->ident, p->type);
1447                 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP OpenDevice\n");
1448                 return(1);
1449                 /*NOTREACHED*/
1450               }
1451             p++;
1452           }
1453       }
1454       /* Nothing matching found, try generic */
1455       /* divide generic in generic_type, where type is the */
1456       /* num returned by the inquiry command */
1457       p = (ChangerCMD_T *)&ChangerIO;
1458       snprintf(&tmpstr[0], SIZEOF(tmpstr), "%s_%s","generic",pDev[0].type);
1459       DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### OpenDevice trying GENERIC Device %s\n",tmpstr);
1460       while(p->ident != NULL)
1461         {
1462           if (strcmp(tmpstr, p->ident) == 0)
1463             {
1464               pDev[ip].functions = p;
1465               DebugPrint(DEBUG_INFO, SECTION_SCSI,"using ident = %s, type = %s\n",p->ident, p->type);
1466               DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP OpenDevice\n");
1467               return(1);
1468               /*NOTREACHED*/
1469             }
1470           p++;
1471         }
1472     } else { /* Something failed, lets see what */
1473       DebugPrint(DEBUG_ERROR, SECTION_SCSI,"##### STOP OpenDevice failed\n");
1474     }
1475   pDev[ip].functions = NULL;
1476   DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP OpenDevice (nothing found) !!\n");
1477   return(0);
1478 }
1479
1480
1481 /*
1482  * This functions checks if the library has an barcode reader.
1483  * fd     -> pointer to the internal devie structure pDev
1484  */
1485 int
1486 BarCode(
1487     int         fd)
1488 {
1489   int ret;
1490   extern OpenFiles_T *pDev;
1491
1492   DebugPrint(DEBUG_INFO, SECTION_BARCODE,"##### START BarCode\n");
1493   DebugPrint(DEBUG_INFO, SECTION_BARCODE,"%-20s : fd %d\n", "BarCode", fd);
1494
1495   DebugPrint(DEBUG_INFO, SECTION_BARCODE,"Ident = [%s], function = [%s]\n", pDev[fd].ident,
1496              pDev[fd].functions->ident);
1497   ret = pDev[fd].functions->function_barcode(fd);
1498   DebugPrint(DEBUG_INFO, SECTION_BARCODE,"##### STOP BarCode (%d)\n",ret);
1499   return(ret);
1500 }
1501
1502
1503 /*
1504  * This functions check if the tape drive is ready
1505  *
1506  * fd     -> pointer to the internal devie structure pDev
1507  * wait -> time to wait for the ready status
1508  *
1509  */
1510 int
1511 Tape_Ready(
1512     int         fd,
1513     time_t      wait_time)
1514 {
1515   extern OpenFiles_T *pDev;
1516   int done;
1517   int ret;
1518   time_t cnt = 0;
1519
1520   RequestSense_T *pRequestSense;
1521   DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### START Tape_Ready\n");
1522
1523   /*
1524    * Which device should we use to get the
1525    * tape status
1526    */
1527
1528   /*
1529    * First the ioctl tapedevice
1530    */
1531   if (pDev[INDEX_TAPE].avail == 1)
1532     {
1533       fd = INDEX_TAPE;
1534     }
1535
1536   /*
1537    * But if available and can do SCSI
1538    * the scsitapedev
1539    */
1540   if (pDev[INDEX_TAPECTL].avail == 1 && pDev[INDEX_TAPECTL].SCSI == 1)
1541     {
1542       fd = INDEX_TAPECTL;
1543     }
1544
1545   if (pDev[fd].avail == 1 && pDev[fd].SCSI == 0)
1546     {
1547       DebugPrint(DEBUG_INFO, SECTION_TAPE,"Tape_Ready : Can't send SCSI commands, try ioctl\n");
1548       /*
1549        * Do we get an non negative result.
1550        * If yes this function is available
1551        * and we can use it to get the status
1552        * of the tape
1553        */
1554       ret = Tape_Status(fd);
1555       if (ret >= 0)
1556         {
1557           while (cnt < wait_time)
1558             {
1559               if ( ret & TAPE_ONLINE)
1560                 {
1561                   DebugPrint(DEBUG_INFO, SECTION_TAPE,"Tape_Ready : Ready after %d seconds\n",cnt);
1562                   DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### STOP Tape_Ready\n");
1563                   return(0);
1564                   /*NOTREACHED*/
1565                 }
1566               cnt++;
1567               sleep(1);
1568               ret = Tape_Status(fd);
1569             }
1570
1571           DebugPrint(DEBUG_INFO, SECTION_TAPE,"Tape_Ready : not ready, stop after %d seconds\n",cnt);
1572           DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### STOP Tape_Ready\n");
1573           return(0);
1574           /*NOTREACHED*/
1575
1576         }
1577         DebugPrint(DEBUG_INFO, SECTION_TAPE,"Tape_Ready : no ioctl interface, will sleep for %d seconds\n", wait_time);
1578         sleep(wait_time);
1579         DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### STOP Tape_Ready\n");
1580         return(0);
1581         /*NOTREACHED*/
1582     }
1583
1584   pRequestSense = alloc(SIZEOF(RequestSense_T));
1585
1586   /*
1587    * Ignore errors at this point
1588    */
1589   GenericRewind(fd);
1590
1591   /*
1592    * Wait until we get an ready condition
1593    */
1594
1595   done = 0;
1596   while (!done && (cnt < wait_time))
1597     {
1598       ret = SCSI_TestUnitReady(fd, pRequestSense );
1599       switch (ret)
1600         {
1601         case SCSI_OK:
1602           done = 1;
1603           break;
1604         case SCSI_SENSE:
1605           switch (SenseHandler(fd, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
1606             {
1607             case SENSE_NO:
1608               DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeReady (TestUnitReady) SENSE_NO\n");
1609               done = 1;
1610               break;
1611             case SENSE_TAPE_NOT_ONLINE:
1612               DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeReady (TestUnitReady) SENSE_TAPE_NOT_ONLINE\n");
1613               break;
1614             case SENSE_IGNORE:
1615               DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeReady (TestUnitReady) SENSE_IGNORE\n");
1616               done = 1;
1617               break;
1618             case SENSE_ABORT:
1619               DebugPrint(DEBUG_ERROR, SECTION_SCSI,"TapeReady (TestUnitReady) SENSE_ABORT\n");
1620               amfree(pRequestSense);
1621               return(-1);
1622               /*NOTREACHED*/
1623             case SENSE_RETRY:
1624               DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeReady (TestUnitReady) SENSE_RETRY\n");
1625               break;
1626             default:
1627               DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeReady (TestUnitReady) default (SENSE)\n");
1628               done = 1;
1629               break;
1630             }
1631           break;
1632         case SCSI_ERROR:
1633           DebugPrint(DEBUG_ERROR, SECTION_SCSI,"TapeReady (TestUnitReady) SCSI_ERROR\n");
1634           free(pRequestSense);
1635           return(-1);
1636           /*NOTREACHED*/
1637         case SCSI_BUSY:
1638           DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeReady (TestUnitReady) SCSI_BUSY\n");
1639           break;
1640         case SCSI_CHECK:
1641           DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeReady (TestUnitReady) SCSI_CHECK\n");
1642           break;
1643         default:
1644           DebugPrint(DEBUG_ERROR, SECTION_SCSI,"TapeReady (TestUnitReady) unknown (%d)\n",ret);
1645           break;
1646         }
1647       sleep(1);
1648       cnt++;
1649     }
1650
1651   amfree(pRequestSense);
1652   DebugPrint(DEBUG_INFO, SECTION_TAPE,"Tape_Ready after %d sec\n", cnt);
1653   DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### STOP Tape_Ready\n");
1654   return(0);
1655 }
1656
1657
1658 int
1659 DecodeSCSI(
1660     CDB_T       CDB,
1661     char *      string)
1662 {
1663   SC_COM_T *pSCSICommand;
1664   int x;
1665
1666   DebugPrint(DEBUG_INFO, SECTION_SCSI, "##### START DecodeSCSI\n");
1667   pSCSICommand = (SC_COM_T *)&SCSICommand;
1668
1669   while (pSCSICommand->name != NULL)
1670     {
1671       if (CDB[0] == pSCSICommand->command)
1672         {
1673           DebugPrint(DEBUG_INFO, SECTION_SCSI,"%s %s", string, pSCSICommand->name);
1674           for (x=0; x < pSCSICommand->length; x++)
1675             {
1676               DebugPrint(DEBUG_INFO, SECTION_SCSI," %02X", CDB[x]);
1677             }
1678           DebugPrint(DEBUG_INFO, SECTION_SCSI,"\n");
1679           DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP DecodeSCSI\n");
1680           return(0);
1681           /*NOTREACHED*/
1682         }
1683       pSCSICommand++;
1684     }
1685   DebugPrint(DEBUG_INFO, SECTION_SCSI,"Not found %X\n", CDB[0]);
1686   DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP DecodeSCSI\n");
1687   return(0);
1688 }
1689
1690 int
1691 DecodeModeSense(
1692     u_char *    buffer,
1693     size_t      offset,
1694     char *      pstring,
1695     char        block,
1696     FILE *      out)
1697 {
1698   ReadWriteErrorRecoveryPage_T *prp;
1699   DisconnectReconnectPage_T *pdrp;
1700   size_t length = (size_t)buffer[0] - 4 - offset;
1701
1702   (void)pstring;        /* Quiet unused parameter warning */
1703
1704   DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### START DecodeModeSense\n");
1705
1706   dump_hex(buffer, 255, DEBUG_INFO, SECTION_SCSI);
1707
1708   /* Jump over the Parameter List header  and an offset if we have something
1709    * Unknown at the start (ADIC-218) at the moment
1710    *
1711    */
1712   buffer = buffer + 4 + offset;
1713
1714   DebugPrint(DEBUG_INFO, SECTION_SCSI,"buffer length = %d\n", length);
1715
1716   if (block) /* Do we have an block descriptor page ?*/
1717     {
1718       if (out != NULL)
1719          fprintf(out, "DecodeModeSense : Density Code %x\n", (unsigned)buffer[0]);
1720       buffer++;
1721
1722       if (out != NULL)
1723         fprintf(out, "DecodeModeSense : Number of Blocks %d\n", V3(buffer));
1724       buffer = buffer + 4;
1725
1726       if (out != NULL)
1727         fprintf(out, "DecodeModeSense : Block Length %d\n", V3(buffer));
1728       buffer = buffer + 3;
1729     }
1730
1731   while (length > 0)
1732     {
1733       switch (*buffer & 0x3f)
1734         {
1735         case 0:
1736             pVendorUnique = buffer;
1737             buffer++;
1738             break;
1739         case 0x1:
1740           prp = (ReadWriteErrorRecoveryPage_T *)buffer;
1741           if (out != NULL)
1742           {
1743                 fprintf(out, "DecodeModeSense : Read/Write Error Recovery Page\n");
1744                 fprintf(out,"\tTransfer Block            %d\n", prp->tb);
1745                 fprintf(out,"\tEnable Early Recovery     %d\n", prp->eer);
1746                 fprintf(out,"\tPost Error                %d\n", prp->per);
1747                 fprintf(out,"\tDisable Transfer on Error %d\n", prp->dte);
1748                 fprintf(out,"\tDisable ECC Correction    %d\n", prp->dcr);
1749                 fprintf(out,"\tRead Retry Count          %d\n", prp->ReadRetryCount);
1750                 fprintf(out,"\tWrite Retry Count         %d\n", prp->WriteRetryCount);
1751           }
1752           buffer++;
1753           break;
1754         case 0x2:
1755           pdrp = (DisconnectReconnectPage_T *)buffer;
1756           if (out != NULL)
1757           {
1758                 fprintf(out, "DecodeModeSense : Disconnect/Reconnect Page\n");
1759                 fprintf(out,"\tBuffer Full Ratio     %d\n", pdrp->BufferFullRatio);
1760                 fprintf(out,"\tBuffer Empty Ratio    %d\n", pdrp->BufferEmptyRatio);
1761                 fprintf(out,"\tBus Inactivity Limit  %d\n",
1762                   V2(pdrp->BusInactivityLimit));
1763                 fprintf(out,"\tDisconnect Time Limit %d\n",
1764                   V2(pdrp->DisconnectTimeLimit));
1765                 fprintf(out,"\tConnect Time Limit    %d\n",
1766                   V2(pdrp->ConnectTimeLimit));
1767                 fprintf(out,"\tMaximum Burst Size    %d\n",
1768                   V2(pdrp->MaximumBurstSize));
1769                 fprintf(out,"\tDTDC                  %d\n", pdrp->DTDC);
1770           }
1771           buffer++;
1772           break;
1773         case 0x1d:
1774           pEAAPage = (EAAPage_T *)buffer;
1775           if (out != NULL)
1776           {
1777                 fprintf(out,"DecodeModeSense : Element Address Assignment Page\n");
1778                 fprintf(out,"\tMedium Transport Element Address     %d\n",
1779                     V2(pEAAPage->MediumTransportElementAddress));
1780                 fprintf(out,"\tNumber of Medium Transport Elements  %d\n",
1781                     V2(pEAAPage->NoMediumTransportElements));
1782                 fprintf(out, "\tFirst Storage Element Address       %d\n",
1783                     V2(pEAAPage->FirstStorageElementAddress));
1784                 fprintf(out, "\tNumber of  Storage Elements         %d\n",
1785                     V2(pEAAPage->NoStorageElements));
1786                 fprintf(out, "\tFirst Import/Export Element Address %d\n",
1787                     V2(pEAAPage->FirstImportExportElementAddress));
1788                 fprintf(out, "\tNumber of  ImportExport Elements    %d\n",
1789                     V2(pEAAPage->NoImportExportElements));
1790                 fprintf(out, "\tFirst Data Transfer Element Address %d\n",
1791                     V2(pEAAPage->FirstDataTransferElementAddress));
1792                 fprintf(out, "\tNumber of  Data Transfer Elements   %d\n",
1793                     V2(pEAAPage->NoDataTransferElements));
1794           }
1795           buffer++;
1796           break;
1797         case 0x1f:
1798           pDeviceCapabilitiesPage = (DeviceCapabilitiesPage_T *)buffer;
1799           if (out != NULL)
1800           {
1801                 fprintf(out, "DecodeModeSense : MT can store data cartridges %d\n",
1802                     pDeviceCapabilitiesPage->MT);
1803                 fprintf(out, "DecodeModeSense : ST can store data cartridges %d\n",
1804                     pDeviceCapabilitiesPage->ST);
1805                 fprintf(out, "DecodeModeSense : IE can store data cartridges %d\n",
1806                     pDeviceCapabilitiesPage->IE);
1807                 fprintf(out, "DecodeModeSense : DT can store data cartridges %d\n",
1808                     pDeviceCapabilitiesPage->DT);
1809                 fprintf(out, "DecodeModeSense : MT to MT %d\n",
1810                     pDeviceCapabilitiesPage->MT2MT);
1811                 fprintf(out, "DecodeModeSense : MT to ST %d\n",
1812                     pDeviceCapabilitiesPage->MT2ST);
1813                 fprintf(out, "DecodeModeSense : MT to IE %d\n",
1814                     pDeviceCapabilitiesPage->MT2IE);
1815                 fprintf(out, "DecodeModeSense : MT to DT %d\n",
1816                     pDeviceCapabilitiesPage->MT2DT);
1817                 fprintf(out, "DecodeModeSense : ST to MT %d\n",
1818                     pDeviceCapabilitiesPage->ST2ST);
1819                 fprintf(out, "DecodeModeSense : ST to MT %d\n",
1820                     pDeviceCapabilitiesPage->ST2ST);
1821                 fprintf(out, "DecodeModeSense : ST to DT %d\n",
1822                     pDeviceCapabilitiesPage->ST2DT);
1823                 fprintf(out, "DecodeModeSense : IE to MT %d\n",
1824                     pDeviceCapabilitiesPage->IE2MT);
1825                 fprintf(out, "DecodeModeSense : IE to ST %d\n",
1826                     pDeviceCapabilitiesPage->IE2IE);
1827                 fprintf(out, "DecodeModeSense : IE to ST %d\n",
1828                     pDeviceCapabilitiesPage->IE2DT);
1829                 fprintf(out, "DecodeModeSense : IE to ST %d\n",
1830                     pDeviceCapabilitiesPage->IE2DT);
1831                 fprintf(out, "DecodeModeSense : DT to MT %d\n",
1832                     pDeviceCapabilitiesPage->DT2MT);
1833                 fprintf(out, "DecodeModeSense : DT to ST %d\n",
1834                     pDeviceCapabilitiesPage->DT2ST);
1835                 fprintf(out, "DecodeModeSense : DT to IE %d\n",
1836                     pDeviceCapabilitiesPage->DT2IE);
1837                 fprintf(out, "DecodeModeSense : DT to DT %d\n",
1838                     pDeviceCapabilitiesPage->DT2DT);
1839           }
1840           buffer++;
1841           break;
1842         default:
1843           buffer++;  /* set pointer to the length information */
1844           break;
1845         }
1846       /* Error if *buffer (length) is 0 */
1847       if (*buffer == 0)
1848         {
1849           /*           EAAPage = NULL; */
1850           /*           DeviceCapabilitiesPage = NULL; */
1851           return(-1);
1852           /*NOTREACHED*/
1853         }
1854       length = length - (size_t)*buffer - 2;
1855       buffer = buffer + (size_t)*buffer + 1;
1856     }
1857   return(0);
1858 }
1859
1860 int
1861 DecodeSense(
1862     RequestSense_T *    sense,
1863     char *              pstring,
1864     FILE *              out)
1865 {
1866   if (out == NULL)
1867     {
1868       return(0);
1869       /*NOTREACHED*/
1870     }
1871   fprintf(out,"##### START DecodeSense\n");
1872   fprintf(out,"%sSense Keys\n", pstring);
1873   if (sense->ErrorCode == 0x70)
1874     {
1875     fprintf(out,"\tExtended Sense                     \n");
1876     } else {
1877       fprintf(out,"\tErrorCode                     %02x\n", sense->ErrorCode);
1878       fprintf(out,"\tValid                         %d\n", sense->Valid);
1879     }
1880   fprintf(out,"\tASC                           %02X\n", sense->AdditionalSenseCode);
1881   fprintf(out,"\tASCQ                          %02X\n", sense->AdditionalSenseCodeQualifier);
1882   fprintf(out,"\tSense key                     %02X\n", sense->SenseKey);
1883   switch (sense->SenseKey)
1884     {
1885     case 0:
1886       fprintf(out,"\t\tNo Sense\n");
1887       break;
1888     case 1:
1889       fprintf(out,"\t\tRecoverd Error\n");
1890       break;
1891     case 2:
1892       fprintf(out,"\t\tNot Ready\n");
1893       break;
1894     case 3:
1895       fprintf(out,"\t\tMedium Error\n");
1896       break;
1897     case 4:
1898       fprintf(out,"\t\tHardware Error\n");
1899       break;
1900     case 5:
1901       fprintf(out,"\t\tIllegal Request\n");
1902       break;
1903     case 6:
1904       fprintf(out,"\t\tUnit Attention\n");
1905       break;
1906     case 7:
1907       fprintf(out,"\t\tData Protect\n");
1908       break;
1909     case 8:
1910       fprintf(out,"\t\tBlank Check\n");
1911       break;
1912     case 9:
1913       fprintf(out,"\t\tVendor uniq\n");
1914       break;
1915     case 0xa:
1916       fprintf(out,"\t\tCopy Aborted\n");
1917       break;
1918     case 0xb:
1919       fprintf(out,"\t\tAborted Command\n");
1920       break;
1921     case 0xc:
1922       fprintf(out,"\t\tEqual\n");
1923       break;
1924     case 0xd:
1925       fprintf(out,"\t\tVolume Overflow\n");
1926       break;
1927     case 0xe:
1928       fprintf(out,"\t\tMiscompare\n");
1929       break;
1930     case 0xf:
1931       fprintf(out,"\t\tReserved\n");
1932       break;
1933     }
1934   return(0);
1935 }
1936
1937 int
1938 DecodeExtSense(
1939     ExtendedRequestSense_T *    sense,
1940     char *                      pstring,
1941     FILE *                      out)
1942 {
1943   ExtendedRequestSense_T *p;
1944
1945   fprintf(out,"##### START DecodeExtSense\n");
1946   p = sense;
1947
1948   fprintf(out,"%sExtended Sense\n", pstring);
1949   DecodeSense((RequestSense_T *)p, pstring, out);
1950   fprintf(out,"\tLog Parameter Page Code         %02X\n", sense->LogParameterPageCode);
1951   fprintf(out,"\tLog Parameter Code              %02X\n", sense->LogParameterCode);
1952   fprintf(out,"\tUnderrun/Overrun Counter        %02X\n", sense->UnderrunOverrunCounter);
1953   fprintf(out,"\tRead/Write Error Counter        %d\n", V3((char *)sense->ReadWriteDataErrorCounter));
1954   if (sense->AdditionalSenseLength > (u_char)sizeof(RequestSense_T))
1955     {
1956       if (sense->PF)
1957         fprintf(out,"\tPower Fail\n");
1958       if (sense->BPE)
1959         fprintf(out,"\tSCSI Bus Parity Error\n");
1960       if (sense->FPE)
1961         fprintf(out,"\tFormatted Buffer parity Error\n");
1962       if (sense->ME)
1963         fprintf(out,"\tMedia Error\n");
1964       if (sense->ECO)
1965         fprintf(out,"\tError Counter Overflow\n");
1966       if (sense->TME)
1967         fprintf(out,"\tTapeMotion Error\n");
1968       if (sense->TNP)
1969         fprintf(out,"\tTape Not Present\n");
1970       if (sense->LBOT)
1971         fprintf(out,"\tLogical Beginning of tape\n");
1972       if (sense->TMD)
1973         fprintf(out,"\tTape Mark Detect Error\n");
1974       if (sense->WP)
1975         fprintf(out,"\tWrite Protect\n");
1976       if (sense->FMKE)
1977         fprintf(out,"\tFilemark Error\n");
1978       if (sense->URE)
1979         fprintf(out,"\tUnder Run Error\n");
1980       if (sense->WEI)
1981         fprintf(out,"\tWrite Error 1\n");
1982       if (sense->SSE)
1983         fprintf(out,"\tServo System Error\n");
1984       if (sense->FE)
1985         fprintf(out,"\tFormatter Error\n");
1986       if (sense->UCLN)
1987         fprintf(out,"\tCleaning Cartridge is empty\n");
1988       if (sense->RRR)
1989         fprintf(out,"\tReverse Retries Required\n");
1990       if (sense->CLND)
1991         fprintf(out,"\tTape Drive has been cleaned\n");
1992       if (sense->CLN)
1993         fprintf(out,"\tTape Drive needs to be cleaned\n");
1994       if (sense->PEOT)
1995         fprintf(out,"\tPhysical End of Tape\n");
1996       if (sense->WSEB)
1997         fprintf(out,"\tWrite Splice Error\n");
1998       if (sense->WSEO)
1999         fprintf(out,"\tWrite Splice Error\n");
2000       fprintf(out,"\tRemaing 1024 byte tape blocks   %d\n", V3((char *)sense->RemainingTape));
2001       fprintf(out,"\tTracking Retry Counter          %02X\n", sense->TrackingRetryCounter);
2002       fprintf(out,"\tRead/Write Retry Counter        %02X\n", sense->ReadWriteRetryCounter);
2003       fprintf(out,"\tFault Sympton Code              %02X\n", sense->FaultSymptomCode);
2004     }
2005   return(0);
2006 }
2007
2008 int
2009 PrintInquiry(
2010     SCSIInquiry_T *     SCSIInquiry)
2011 {
2012   DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### START PrintInquiry\n");
2013   DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-15s %x\n", "qualifier", SCSIInquiry->qualifier);
2014   DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-15s %x\n", "type", SCSIInquiry->type);
2015   DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-15s %x\n", "data_format", SCSIInquiry->data_format);
2016   DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-15s %X\n", "ansi_version", SCSIInquiry->ansi_version);
2017   DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-15s %X\n", "ecma_version", SCSIInquiry->ecma_version);
2018   DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-15s %X\n", "iso_version", SCSIInquiry->iso_version);
2019   DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-15s %X\n", "type_modifier", SCSIInquiry->type_modifier);
2020   DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-15s %x\n", "removable", SCSIInquiry->removable);
2021   DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-15s %.8s\n", "vendor_info", SCSIInquiry->vendor_info);
2022   DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-15s %.16s\n", "prod_ident", SCSIInquiry->prod_ident);
2023   DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-15s %.4s\n", "prod_version", SCSIInquiry->prod_version);
2024   DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-15s %.19s\n", "vendor_specific", SCSIInquiry->vendor_specific);
2025   return(0);
2026 }
2027
2028
2029 int
2030 DoNothing0(void)
2031 {
2032   dbprintf(("##### START DoNothing\n"));
2033   return(0);
2034 }
2035
2036 int
2037 DoNothing1(
2038     int         unused1)
2039 {
2040   (void)unused1;        /* Quiet unused parameter warning */
2041
2042   dbprintf(("##### START DoNothing\n"));
2043   return(0);
2044 }
2045
2046 int
2047 DoNothing2(
2048     int         unused1,
2049     int         unused2)
2050 {
2051   (void)unused1;        /* Quiet unused parameter warning */
2052   (void)unused2;        /* Quiet unused parameter warning */
2053
2054   dbprintf(("##### START DoNothing\n"));
2055   return(0);
2056 }
2057
2058 int
2059 DoNothing3(
2060     int         unused1,
2061     int         unused2,
2062     int         unused3)
2063 {
2064   (void)unused1;        /* Quiet unused parameter warning */
2065   (void)unused2;        /* Quiet unused parameter warning */
2066   (void)unused3;        /* Quiet unused parameter warning */
2067
2068   dbprintf(("##### START DoNothing\n"));
2069   return(0);
2070 }
2071
2072 int
2073 GenericFree(void)
2074 {
2075   dbprintf(("##### START GenericFree\n"));
2076   return(0);
2077 }
2078
2079 int
2080 GenericSearch(void)
2081 {
2082   dbprintf(("##### START GenericSearch\n"));
2083   return(0);
2084 }
2085
2086 int
2087 TreeFrogBarCode(
2088     int DeviceFD)
2089 {
2090   extern OpenFiles_T *pDev;
2091
2092   ModePageTreeFrogVendorUnique_T *pVendor;
2093
2094   dbprintf(("##### START TreeFrogBarCode\n"));
2095   if (pModePage == NULL)
2096     {
2097       pModePage = alloc(0xff);
2098     }
2099
2100   if (SCSI_ModeSense(DeviceFD, pModePage, 0xff, 0x0, 0x3f) == 0)
2101     {
2102       DecodeModeSense(pModePage, 0, "TreeFrogBarCode :", 0, debug_file);
2103
2104       if (pVendorUnique == NULL)
2105       {
2106          dbprintf(("TreeFrogBarCode : no pVendorUnique\n"));
2107          return(0);
2108          /*NOTREACHED*/
2109       }
2110       pVendor = ( ModePageTreeFrogVendorUnique_T *)pVendorUnique;
2111
2112       dbprintf(("TreeFrogBarCode : EBARCO %d\n", pVendor->EBARCO));
2113       dbprintf(("TreeFrogCheckSum : CHKSUM  %d\n", pVendor->CHKSUM));
2114
2115       dump_hex((u_char *)pDev[INDEX_CHANGER].inquiry, INQUIRY_SIZE, DEBUG_INFO, SECTION_ELEMENT);
2116       return(pVendor->EBARCO);
2117       /*NOTREACHED*/
2118     }
2119   return(0);
2120 }
2121
2122 int
2123 EXB_BarCode(
2124     int         DeviceFD)
2125 {
2126   extern OpenFiles_T *pDev;
2127
2128   ModePageEXB120VendorUnique_T *pVendor;
2129   ModePageEXB120VendorUnique_T *pVendorWork;
2130
2131   DebugPrint(DEBUG_INFO, SECTION_BARCODE,"##### START EXB_BarCode\n");
2132   if (pModePage == NULL && LibModeSenseValid == 0)
2133     {
2134       pModePage = alloc(0xff);
2135
2136       if (SCSI_ModeSense(DeviceFD, pModePage, 0xff, 0x8, 0x3f) == 0)
2137         {
2138           DecodeModeSense(pModePage, 0, "EXB_BarCode :", 0, debug_file);
2139           LibModeSenseValid = 1;
2140         } else {
2141           LibModeSenseValid = -1;
2142         }
2143     }
2144
2145   if (LibModeSenseValid == 1)
2146     {
2147       if (pVendorUnique == NULL)
2148         {
2149          DebugPrint(DEBUG_INFO, SECTION_BARCODE,"EXB_BarCode : no pVendorUnique\n");
2150          return(0);
2151          /*NOTREACHED*/
2152       }
2153       pVendor = ( ModePageEXB120VendorUnique_T *)pVendorUnique;
2154
2155       DebugPrint(DEBUG_INFO, SECTION_BARCODE,"EXB_BarCode : NBL %d\n", pVendor->NBL);
2156       DebugPrint(DEBUG_INFO, SECTION_BARCODE,"EXB_BarCode : PS  %d\n", pVendor->PS);
2157       if (pVendor->NBL == 1 && pVendor->PS == 1 )
2158         {
2159           pVendorWork = alloc((size_t)pVendor->ParameterListLength + 2);
2160           DebugPrint(DEBUG_INFO, SECTION_BARCODE,"EXB_BarCode : setting NBL to 1\n");
2161           memcpy(pVendorWork, pVendor, (size_t)pVendor->ParameterListLength + 2);
2162           pVendorWork->NBL = 0;
2163           pVendorWork->PS = 0;
2164           pVendorWork->RSVD0 = 0;
2165           if (SCSI_ModeSelect(DeviceFD, (u_char *)pVendorWork, (u_char)(pVendorWork->ParameterListLength + 2), 0, 1, 0) == 0)
2166             {
2167               DebugPrint(DEBUG_INFO, SECTION_BARCODE,"EXB_BarCode : SCSI_ModeSelect OK\n");
2168               /* Hack !!!!!!
2169                */
2170               pVendor->NBL = 0;
2171
2172               /* And now again !!!
2173                */
2174               GenericResetStatus(DeviceFD);
2175             } else {
2176               DebugPrint(DEBUG_INFO, SECTION_BARCODE,"EXB_BarCode : SCSI_ModeSelect failed\n");
2177             }
2178             amfree(pVendorWork);
2179         }
2180       dump_hex((u_char *)pDev[INDEX_CHANGER].inquiry, INQUIRY_SIZE, DEBUG_INFO, SECTION_BARCODE);
2181       DebugPrint(DEBUG_INFO, SECTION_BARCODE,"EXB_BarCode : vendor_specific[19] %x\n",
2182                  pDev[INDEX_CHANGER].inquiry->vendor_specific[19]);
2183     }
2184   return(1);
2185 }
2186
2187 int
2188 NoBarCode(
2189     int DeviceFD)
2190 {
2191   (void)DeviceFD;       /* Quiet unused parameter warning */
2192
2193   DebugPrint(DEBUG_INFO, SECTION_BARCODE,"##### START NoBarCode\n");
2194   DebugPrint(DEBUG_INFO, SECTION_BARCODE,"##### STOP  NoBarCode\n");
2195   return(0);
2196 }
2197
2198 int
2199 GenericBarCode(
2200     int         DeviceFD)
2201 {
2202   (void)DeviceFD;       /* Quiet unused parameter warning */
2203
2204   DebugPrint(DEBUG_INFO, SECTION_BARCODE,"##### START GenericBarCode\n");
2205   if ( changer->havebarcode  >= 1)
2206     {
2207       DebugPrint(DEBUG_INFO, SECTION_BARCODE,"##### STOP GenericBarCode (havebarcode) => %d\n",changer->havebarcode);
2208       return(1);
2209       /*NOTREACHED*/
2210     }
2211   DebugPrint(DEBUG_INFO, SECTION_BARCODE,"##### STOP GenericBarCode => 0\n");
2212   return(0);
2213 }
2214
2215 int
2216 SenseHandler(
2217     int                 DeviceFD,
2218     u_char              flag,
2219     u_char              SenseKey,
2220     u_char              AdditionalSenseCode,
2221     u_char              AdditionalSenseCodeQualifier,
2222     RequestSense_T *    buffer)
2223 {
2224   extern OpenFiles_T *pDev;
2225   int ret = 0;
2226   dbprintf(("##### START SenseHandler\n"));
2227   if (pDev[DeviceFD].inqdone == 1)
2228     {
2229       dbprintf(("Ident = [%s], function = [%s]\n", pDev[DeviceFD].ident,
2230                 pDev[DeviceFD].functions->ident));
2231       ret = pDev[DeviceFD].functions->function_error(DeviceFD, flag, SenseKey, AdditionalSenseCode, AdditionalSenseCodeQualifier, buffer);
2232     } else {
2233       dbprintf(("    Ups no sense\n"));
2234     }
2235   dbprintf(("#### STOP SenseHandler\n"));
2236   return(ret);
2237 }
2238
2239 /*
2240  * Try to get information about the tape,
2241  * Tape loaded ? Online etc
2242  * Use the mtio ioctl to get the information if no SCSI Path
2243  * to the tape drive is available.
2244  *
2245  * TODO:
2246  * Pass an parameter to identify which unit to use
2247  * if there are more than one
2248  * Implement the SCSI path if available
2249 */
2250 int
2251 TapeStatus(void)
2252 {
2253   extern OpenFiles_T *pDev;
2254   int ret;
2255   int done;
2256   int cnt;
2257   RequestSense_T *pRequestSense;
2258
2259   DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### START TapeStatus\n");
2260
2261   /*
2262    * If it is an device which understand SCSI commands the
2263    * normal ioctl (MTIOCGET for example) may fail
2264    * So try an Inquiry
2265    */
2266   if (pDev[INDEX_TAPECTL].SCSI == 1)
2267     {
2268       pRequestSense = alloc(SIZEOF(RequestSense_T));
2269       memset(pRequestSense, 0, SIZEOF(RequestSense_T));
2270
2271       for (done = 0, cnt = 0; !done && (cnt < 60); cnt++)
2272         {
2273           ret = SCSI_TestUnitReady(INDEX_TAPECTL, pRequestSense);
2274           DebugPrint(DEBUG_INFO, SECTION_SCSI, "TapeStatus TestUnitReady ret %d\n",ret);
2275           switch (ret)
2276             {
2277             case SCSI_OK:
2278             case SCSI_SENSE:
2279               switch (SenseHandler(INDEX_TAPECTL, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
2280                 {
2281                 case SENSE_IGNORE:
2282                 case SENSE_NO:
2283                   DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeStatus (TestUnitReady) SENSE_NO\n");
2284                   pDTE[0].status = 'F';
2285                   DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### FULL\n");
2286                   done = 1;
2287                   break;
2288
2289                 case SENSE_TAPE_NOT_ONLINE:
2290                   DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeStatus (TestUnitReady) SENSE_TAPE_NOT_ONLINE\n");
2291                   pDTE[0].status = 'E';
2292                   DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### EMPTY\n");
2293                   done = 1;
2294                   break;
2295
2296                 case SENSE_ABORT:
2297                   DebugPrint(DEBUG_ERROR, SECTION_SCSI,"TapeStatus (TestUnitReady) SENSE_ABORT\n");
2298                   done = 1;
2299                   break;
2300
2301                 case SENSE_RETRY:
2302                   DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeStatus (TestUnitReady) SENSE_RETRY\n");
2303                   break;
2304
2305                 default:
2306                   DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeStatus (TestUnitReady) default (SENSE)\n");
2307                   break;
2308                 }
2309               break;
2310
2311             case SCSI_ERROR:
2312               DebugPrint(DEBUG_ERROR, SECTION_SCSI,"TapeStatus (TestUnitReady) SCSI_ERROR\n");
2313               done = 1;
2314               break;
2315
2316             case SCSI_BUSY:
2317               DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeStatus (TestUnitReady) SCSI_BUSY\n");
2318               break;
2319
2320             case SCSI_CHECK:
2321               DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeStatus (TestUnitReady) SCSI_CHECK\n");
2322               break;
2323
2324             default:
2325               DebugPrint(DEBUG_ERROR, SECTION_SCSI,"TapeStatus (TestUnitReady) unknown (%d)\n",ret);
2326               break;
2327
2328             }
2329           if (!done)
2330             sleep(2);
2331         }
2332         amfree(pRequestSense);
2333     } else {
2334       ret = Tape_Status(INDEX_TAPE);
2335       if ( ret & TAPE_ONLINE)
2336         {
2337           pDTE[0].status ='F';
2338           DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### FULL\n");
2339         } else {
2340           pDTE[0].status = 'E';
2341           DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### EMPTY\n");
2342         }
2343       DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### STOP TapeStatus\n");
2344     }
2345     return(0);
2346 }
2347
2348 int
2349 DLT4000Eject(
2350     char *      Device,
2351     int         type)
2352 {
2353   extern OpenFiles_T *pDev;
2354
2355   RequestSense_T *pRequestSense;
2356   ExtendedRequestSense_T *pExtendedRequestSense;
2357   int ret;
2358   int cnt = 0;
2359   int done;
2360
2361   (void)Device; /* Quiet unused parameter warning */
2362
2363   dbprintf(("##### START DLT4000Eject\n"));
2364
2365   pRequestSense = alloc(SIZEOF(RequestSense_T));
2366   pExtendedRequestSense = alloc(SIZEOF(ExtendedRequestSense_T));
2367
2368   if ( type > 1)
2369     {
2370       dbprintf(("DLT4000Eject : use mtio ioctl for eject on %s\n", pDev[INDEX_TAPE].dev));
2371       free(pExtendedRequestSense);
2372       free(pRequestSense);
2373       return(Tape_Ioctl(INDEX_TAPE, IOCTL_EJECT));
2374       /*NOTREACHED*/
2375     }
2376
2377
2378
2379   if (pDev[INDEX_TAPECTL].SCSI == 0)
2380     {
2381       dbprintf(("DLT4000Eject : Device %s not able to receive SCSI commands\n", pDev[INDEX_TAPE].dev));
2382       free(pExtendedRequestSense);
2383       free(pRequestSense);
2384       return(Tape_Ioctl(INDEX_TAPE, IOCTL_EJECT));
2385       /*NOTREACHED*/
2386     }
2387
2388
2389   dbprintf(("DLT4000Eject : SCSI eject on %s = %s\n", pDev[INDEX_TAPECTL].dev, pDev[INDEX_TAPECTL].ConfigName));
2390
2391   RequestSense(INDEX_TAPECTL, pExtendedRequestSense, 0);
2392   DecodeExtSense(pExtendedRequestSense, "DLT4000Eject : ", debug_file);
2393   /* Unload the tape, 0 ==  wait for success
2394    * 0 == unload
2395    */
2396   ret = SCSI_LoadUnload(INDEX_TAPECTL, pRequestSense, 0, 0);
2397
2398   RequestSense(INDEX_TAPECTL, pExtendedRequestSense, 0);
2399   DecodeExtSense(pExtendedRequestSense, "DLT4000Eject : ", debug_file);
2400
2401   /* < 0 == fatal */
2402   if (ret >= 0) {
2403       free(pExtendedRequestSense);
2404       free(pRequestSense);
2405       return(-1);
2406       /*NOTREACHED*/
2407     }
2408
2409   done = 0;
2410   while (!done && cnt < 300)
2411     {
2412       ret = SCSI_TestUnitReady(INDEX_TAPECTL, pRequestSense);
2413       DebugPrint(DEBUG_INFO, SECTION_SCSI, "DLT4000Eject TestUnitReady ret %d\n",ret);
2414       switch (ret)
2415         {
2416         case SCSI_OK:
2417           done = 1;
2418           break;
2419         case SCSI_SENSE:
2420           switch (SenseHandler(INDEX_TAPECTL, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
2421             {
2422             case SENSE_NO:
2423               DebugPrint(DEBUG_INFO, SECTION_SCSI,"DLT4000Eject (TestUnitReady) SENSE_NO\n");
2424               done = 1;
2425               break;
2426             case SENSE_TAPE_NOT_ONLINE:
2427               DebugPrint(DEBUG_INFO, SECTION_SCSI,"DLT4000Eject (TestUnitReady) SENSE_TAPE_NOT_ONLINE\n");
2428               done = 1;
2429               break;
2430             case SENSE_IGNORE:
2431               DebugPrint(DEBUG_INFO, SECTION_SCSI,"DLT4000Eject (TestUnitReady) SENSE_IGNORE\n");
2432               done = 1;
2433               break;
2434             case SENSE_ABORT:
2435               DebugPrint(DEBUG_ERROR, SECTION_SCSI,"DLT4000Eject (TestUnitReady) SENSE_ABORT\n");
2436               free(pExtendedRequestSense);
2437               free(pRequestSense);
2438               return(-1);
2439               /*NOTREACHED*/
2440             case SENSE_RETRY:
2441               DebugPrint(DEBUG_INFO, SECTION_SCSI,"DLT4000Eject (TestUnitReady) SENSE_RETRY\n");
2442               break;
2443             default:
2444               DebugPrint(DEBUG_INFO, SECTION_SCSI,"DLT4000Eject (TestUnitReady) default (SENSE)\n");
2445               done = 1;
2446               break;
2447             }
2448           break;
2449         case SCSI_ERROR:
2450           DebugPrint(DEBUG_ERROR, SECTION_SCSI,"DLT4000Eject (TestUnitReady) SCSI_ERROR\n");
2451           free(pExtendedRequestSense);
2452           free(pRequestSense);
2453           return(-1);
2454           /*NOTREACHED*/
2455         case SCSI_BUSY:
2456           DebugPrint(DEBUG_INFO, SECTION_SCSI,"DLT4000Eject (TestUnitReady) SCSI_BUSY\n");
2457           break;
2458         case SCSI_CHECK:
2459           DebugPrint(DEBUG_INFO, SECTION_SCSI,"DLT4000Eject (TestUnitReady) SCSI_CHECK\n");
2460           break;
2461         default:
2462           DebugPrint(DEBUG_ERROR, SECTION_SCSI,"DLT4000Eject (TestUnitReady) unknown (%d)\n",ret);
2463           break;
2464         }
2465
2466       cnt++;
2467       sleep(2);
2468     }
2469
2470   dbprintf(("DLT4000Eject : Ready after %d sec, done = %d\n", cnt * 2, done));
2471
2472   free(pExtendedRequestSense);
2473   free(pRequestSense);
2474
2475   return(0);
2476 }
2477
2478 /*
2479  * Ejects an tape either with the ioctl interface
2480  * or by using the SCSI interface if available.
2481  *
2482  * TODO:
2483  * Before unload check if there is an tape in the drive
2484  *
2485  */
2486 int
2487 GenericEject(
2488     char *      Device,
2489     int         type)
2490 {
2491   extern OpenFiles_T *pDev;
2492   RequestSense_T *pRequestSense;
2493   int ret;
2494   int cnt = 0;
2495   int done;
2496
2497   (void)Device; /* Quiet unused parameter warning */
2498   (void)type;   /* Quiet unused parameter warning */
2499
2500   DebugPrint(DEBUG_INFO, SECTION_TAPE, "##### START GenericEject\n");
2501
2502   pRequestSense = alloc(SIZEOF(RequestSense_T));
2503
2504   DebugPrint(DEBUG_INFO, SECTION_TAPE,"GenericEject : SCSI eject on %s = %s\n",
2505              pDev[INDEX_TAPECTL].dev, pDev[INDEX_TAPECTL].ConfigName);
2506
2507   /*
2508    * Can we use SCSI commands ?
2509    */
2510   if (pDev[INDEX_TAPECTL].SCSI == 1)
2511     {
2512       LogSense(INDEX_TAPECTL);
2513       /*
2514        * Unload the tape, 1 == don't wait for success
2515        * 0 == unload
2516        */
2517       ret = SCSI_LoadUnload(INDEX_TAPECTL, pRequestSense, 1, 0);
2518
2519       /* < 0 == fatal */
2520       if (ret < 0) {
2521         DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericEject SCSI_LoadUnload failed\n");
2522         free(pRequestSense);
2523         return(-1);
2524         /*NOTREACHED*/
2525       }
2526
2527       done = 0;
2528       while (!done && cnt < 300)
2529         {
2530           ret = SCSI_TestUnitReady(INDEX_TAPECTL, pRequestSense);
2531           DebugPrint(DEBUG_INFO, SECTION_SCSI, "GenericEject TestUnitReady ret %d\n",ret);
2532           switch (ret)
2533             {
2534             case SCSI_OK:
2535             case SCSI_SENSE:
2536               switch (SenseHandler(INDEX_TAPECTL, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
2537                 {
2538                 case SENSE_NO:
2539                   DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericEject (TestUnitReady) SENSE_NO\n");
2540                   break;
2541                 case SENSE_TAPE_NOT_ONLINE:
2542                   DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericEject (TestUnitReady) SENSE_TAPE_NOT_ONLINE\n");
2543                   done = 1;
2544                   break;
2545                 case SENSE_IGNORE:
2546                   DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericEject (TestUnitReady) SENSE_IGNORE\n");
2547                   break;
2548                 case SENSE_ABORT:
2549                   DebugPrint(DEBUG_ERROR, SECTION_SCSI,"GenericEject (TestUnitReady) SENSE_ABORT\n");
2550                   free(pRequestSense);
2551                   return(-1);
2552                   /*NOTREACHED*/
2553                 case SENSE_RETRY:
2554                   DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericEject (TestUnitReady) SENSE_RETRY\n");
2555                   break;
2556                 default:
2557                   DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericEject (TestUnitReady) default (SENSE)\n");
2558                   break;
2559                 }
2560               break;
2561             case SCSI_ERROR:
2562               DebugPrint(DEBUG_ERROR, SECTION_SCSI,"GenericEject (TestUnitReady) SCSI_ERROR\n");
2563               free(pRequestSense);
2564               return(-1);
2565               /*NOTREACHED*/
2566             case SCSI_BUSY:
2567               DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericEject (TestUnitReady) SCSI_BUSY\n");
2568               break;
2569             case SCSI_CHECK:
2570               DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericEject (TestUnitReady) SCSI_CHECK\n");
2571               break;
2572             default:
2573               DebugPrint(DEBUG_ERROR, SECTION_SCSI,"GenericEject (TestUnitReady) unknown (%d)\n",ret);
2574               break;
2575             }
2576           cnt++;
2577           sleep(2);
2578         }
2579     } else {
2580       DebugPrint(DEBUG_INFO, SECTION_TAPE,"GenericEject : Device can't understand SCSI try ioctl\n");
2581       Tape_Ioctl(INDEX_TAPECTL, IOCTL_EJECT);
2582     }
2583   DebugPrint(DEBUG_INFO, SECTION_TAPE,
2584              "GenericEject : Ready after %d sec\n", cnt * 2);
2585   free(pRequestSense);
2586   return(0);
2587 }
2588
2589 /*
2590  * Rewind the tape
2591  *
2592  * TODO:
2593  * Make the retry counter an config option,
2594  *
2595  * Return:
2596  * -1 -> error
2597  * 0  -> success
2598  */
2599 int
2600 GenericRewind(
2601     int         DeviceFD)
2602 {
2603   CDB_T CDB;
2604   extern OpenFiles_T *pDev;
2605   RequestSense_T *pRequestSense;
2606   char *errstr;                    /* Used by tape_rewind */
2607   int ret;
2608   int cnt = 0;
2609   int done;
2610
2611   DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### START GenericRewind pDEV -> %d\n",DeviceFD);
2612
2613
2614   /*
2615    * If we can use the SCSI device than use it, else use the ioctl
2616    * function
2617    */
2618   if (pDev[DeviceFD].SCSI == 1)
2619     {
2620       pRequestSense = alloc(SIZEOF(RequestSense_T));
2621
2622       /*
2623        * Before doing the rewind check if the tape is ready to accept commands
2624        */
2625
2626       done = 0;
2627       while (!done)
2628         {
2629           ret = SCSI_TestUnitReady(DeviceFD, (RequestSense_T *)pRequestSense );
2630           DebugPrint(DEBUG_INFO, SECTION_TAPE, "GenericRewind (TestUnitReady) ret %d\n",ret);
2631           switch (ret)
2632             {
2633             case SCSI_OK:
2634               done = 1;
2635               break;
2636             case SCSI_SENSE:
2637               switch (SenseHandler(DeviceFD, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
2638                 {
2639                 case SENSE_NO:
2640                   DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) SENSE_NO\n");
2641                   done = 1;
2642                   break;
2643                 case SENSE_TAPE_NOT_ONLINE:
2644                   DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) SENSE_TAPE_NOT_ONLINE\n");
2645                   free(pRequestSense);
2646                   return(-1);
2647                   /*NOTREACHED*/
2648                 case SENSE_IGNORE:
2649                   DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) SENSE_IGNORE\n");
2650                   done = 1;
2651                   break;
2652                 case SENSE_ABORT:
2653                   DebugPrint(DEBUG_ERROR, SECTION_SCSI,"GenericRewind (TestUnitReady) SENSE_ABORT\n");
2654                   free(pRequestSense);
2655                   return(-1);
2656                   /*NOTREACHED*/
2657                 case SENSE_RETRY:
2658                   DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) SENSE_RETRY\n");
2659                   break;
2660                 default:
2661                   DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) default (SENSE)\n");
2662                   done = 1;
2663                   break;
2664                 }  /* switch (SenseHandler(DeviceFD, 0, pRequestSense->SenseKey.... */
2665               break;
2666
2667             case SCSI_ERROR:
2668               DebugPrint(DEBUG_ERROR, SECTION_SCSI,"GenericRewind (TestUnitReady) SCSI_ERROR\n");
2669               free(pRequestSense);
2670               return(-1);
2671               /*NOTREACHED*/
2672
2673             case SCSI_BUSY:
2674               DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) SCSI_BUSY\n");
2675               break;
2676             case SCSI_CHECK:
2677               DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) SCSI_CHECK\n");
2678               break;
2679             default:
2680               DebugPrint(DEBUG_ERROR, SECTION_SCSI,"GenericRewind (TestUnitReady) unknown (%d)\n",ret);
2681               break;
2682             }
2683
2684           sleep(1);
2685           DebugPrint(DEBUG_INFO, SECTION_TAPE," Wait .... (%d)\n",cnt);
2686           if (cnt > 180)
2687             {
2688               DebugPrint(DEBUG_ERROR, SECTION_TAPE,"##### STOP GenericRewind (-1)\n");
2689               free(pRequestSense);
2690               return(-1);
2691               /*NOTREACHED*/
2692             }
2693         } /* while !done */
2694
2695       cnt = 0;
2696
2697       CDB[0] = SC_COM_REWIND;
2698       CDB[1] = 1;
2699       CDB[2] = 0;
2700       CDB[3] = 0;
2701       CDB[4] = 0;
2702       CDB[5] = 0;
2703
2704       done = 0;
2705       while (!done)
2706         {
2707           ret = SCSI_Run(DeviceFD, Input, CDB, 6,
2708                          NULL, 0,
2709                          pRequestSense,
2710                          SIZEOF(RequestSense_T));
2711
2712           DecodeSense(pRequestSense, "GenericRewind : ", debug_file);
2713
2714           if (ret > 0)
2715             {
2716               if (pRequestSense->SenseKey != UNIT_ATTENTION)
2717                 {
2718                   done = 1;
2719                 }
2720             }
2721           if (ret == 0)
2722             {
2723               done = 1;
2724             }
2725           if (ret < 0)
2726             {
2727               DebugPrint(DEBUG_INFO, SECTION_TAPE,"GenericRewind : failed %d\n", ret);
2728               done = 1;
2729             }
2730         }
2731
2732       done = 0;
2733       while (!done && (cnt < 300))
2734         {
2735           ret = SCSI_TestUnitReady(DeviceFD, pRequestSense);
2736           DebugPrint(DEBUG_INFO, SECTION_SCSI, "GenericRewind TestUnitReady ret %d\n",ret);
2737           switch (ret)
2738             {
2739             case SCSI_OK:
2740               done = 1;
2741               break;
2742             case SCSI_SENSE:
2743               switch (SenseHandler(DeviceFD, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
2744                 {
2745                 case SENSE_NO:
2746                   DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) SENSE_NO\n");
2747                   done = 1;
2748                   break;
2749                 case SENSE_TAPE_NOT_ONLINE:
2750                   DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) SENSE_TAPE_NOT_ONLINE\n");
2751                   free(pRequestSense);
2752                   return(-1);
2753                   /*NOTREACHED*/
2754                 case SENSE_IGNORE:
2755                   DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) SENSE_IGNORE\n");
2756                   done = 1;
2757                   break;
2758                 case SENSE_ABORT:
2759                   DebugPrint(DEBUG_ERROR, SECTION_SCSI,"GenericRewind (TestUnitReady) SENSE_ABORT\n");
2760                   free(pRequestSense);
2761                   return(-1);
2762                   /*NOTREACHED*/
2763                 case SENSE_RETRY:
2764                   DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) SENSE_RETRY\n");
2765                   break;
2766                 default:
2767                   DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) default (SENSE)\n");
2768                   done = 1;
2769                   break;
2770                 }
2771               break;
2772             case SCSI_ERROR:
2773               DebugPrint(DEBUG_ERROR, SECTION_SCSI,"GenericRewind (TestUnitReady) SCSI_ERROR\n");
2774               return(-1);
2775               /*NOTREACHED*/
2776
2777             case SCSI_BUSY:
2778               DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) SCSI_BUSY\n");
2779               break;
2780             case SCSI_CHECK:
2781               DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) SCSI_CHECK\n");
2782               break;
2783             default:
2784               DebugPrint(DEBUG_ERROR, SECTION_SCSI,"GenericRewind (TestUnitReady) unknown (%d)\n",ret);
2785               break;
2786             }
2787
2788           cnt++;
2789           sleep(2);
2790         }
2791
2792       amfree(pRequestSense);
2793
2794       DebugPrint(DEBUG_INFO, SECTION_TAPE,"GenericRewind : Ready after %d sec, "
2795                         "done = %d\n", cnt * 2, done);
2796       DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### STOP GenericRewind (0)\n");
2797     } else {
2798       DebugPrint(DEBUG_INFO, SECTION_TAPE,"GenericRewind : use ioctl rewind\n");
2799       if (pDev[DeviceFD].devopen == 1)
2800         {
2801           DebugPrint(DEBUG_INFO, SECTION_TAPE,"Close Device\n");
2802           SCSI_CloseDevice(DeviceFD);
2803         }
2804       /* We don't retry if it fails; that is left to the vtape driver. */
2805       if ((errstr = tape_rewind(pDev[DeviceFD].dev)) == NULL) {
2806           DebugPrint(DEBUG_INFO, SECTION_TAPE,"Rewind OK,\n", cnt);
2807       } else {
2808           DebugPrint(DEBUG_ERROR, SECTION_TAPE,"Rewind failed %s\n",errstr);
2809           DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### STOP GenericRewind (-1)\n");
2810           return(-1);
2811           /*NOTREACHED*/
2812       }
2813       DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### STOP GenericRewind (0)\n");
2814     }
2815
2816   return(0);
2817 }
2818
2819
2820 /*
2821  * Check if the tape has the tape clean
2822  * bit set in the return of an request sense
2823  *
2824  */
2825 int
2826 GenericClean(
2827     char *      Device)
2828 {
2829   extern OpenFiles_T *pDev;
2830   ExtendedRequestSense_T ExtRequestSense;
2831   int ret = 0;
2832
2833   (void)Device; /* Quiet unused parameter warning */
2834
2835   DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### START GenericClean\n");
2836   if (pDev[INDEX_TAPECTL].SCSI == 0)
2837       {
2838           DebugPrint(DEBUG_ERROR, SECTION_TAPE,"GenericClean : can't send SCSI commands\n");
2839           DebugPrint(DEBUG_ERROR, SECTION_TAPE,"##### STOP GenericClean\n");
2840           return(0);
2841           /*NOTREACHED*/
2842       }
2843
2844   /*
2845    * Request Sense Data, reset the counter
2846    */
2847   if ( RequestSense(INDEX_TAPECTL, &ExtRequestSense, 1) == 0)
2848     {
2849
2850       DecodeExtSense(&ExtRequestSense, "GenericClean : ", debug_file);
2851       if(ExtRequestSense.CLN) {
2852         ret = 1;
2853       } else {
2854         ret = 0;
2855       }
2856     } else {
2857       DebugPrint(DEBUG_ERROR, SECTION_TAPE,"Got error from RequestSense\n");
2858     }
2859   DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### STOP GenericClean (%d)\n",ret);
2860   return(ret);
2861 }
2862
2863 int
2864 SCSI_LogSenseClean(
2865     char *      Device)
2866
2867   extern OpenFiles_T *pDev;
2868   CDB_T CDB;
2869   RequestSense_T *pRequestSense;
2870   int ret = 0;
2871   u_char *buffer;
2872   size_t size = 128;
2873       
2874   (void)Device; /* Quiet unused parameter warning */
2875   DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### START SCSI_LogSenseClean\n");
2876   if (pDev[INDEX_TAPECTL].SCSI == 0)
2877       {
2878           DebugPrint(DEBUG_ERROR, SECTION_TAPE,"SCSILogSenseClean : can't send SCSI commands\n");
2879           DebugPrint(DEBUG_ERROR, SECTION_TAPE,"##### STOP SCSI_LogSenseClean\n");
2880           return(0);
2881           /*NOTREACHED*/
2882       }
2883
2884    if (NULL ==  (buffer = alloc(size))){
2885           DebugPrint(DEBUG_ERROR, SECTION_TAPE,"SCSI_LogSenseClean : can't alloc buffer\n");
2886           DebugPrint(DEBUG_ERROR, SECTION_TAPE,"##### STOP SCSI_LogSenseClean\n");
2887           return(0);
2888    }
2889    if (NULL == (pRequestSense = alloc(SIZEOF(RequestSense_T)))){
2890           DebugPrint(DEBUG_ERROR, SECTION_TAPE,"SCSI_LogSenseClean : can't alloc memory\n");
2891           DebugPrint(DEBUG_ERROR, SECTION_TAPE,"##### STOP SCSI_LogSenseClean\n");
2892           return(0);
2893    }
2894    
2895    memset(buffer, 0, size);
2896    CDB[0] = SC_COM_LOG_SENSE;
2897    CDB[1] = 0;
2898    CDB[2] = (u_char)(0x40 | 0x33);/* 0x40 for current values 0x33 Head Cleaning Page*/
2899    CDB[3] = 0;
2900    CDB[4] = 0;
2901    CDB[5] = 0;
2902    CDB[6] = 00;
2903    MSB2(&CDB[7], size);
2904    CDB[9] = 0;
2905
2906    if (SCSI_Run(INDEX_TAPECTL, Input, CDB, 10,
2907                            buffer,
2908                            size,
2909                            pRequestSense,
2910                            SIZEOF(RequestSense_T)) != 0)
2911      {
2912        DecodeSense(pRequestSense, "SCSI_LogSenseClean : ",debug_file);
2913        free(pRequestSense);
2914        free(buffer);
2915        DebugPrint(DEBUG_ERROR, SECTION_TAPE,"##### STOP SCSI_LogSenseClean (0) Page could not be read.\n");
2916        return(0);
2917        /*NOTREACHED*/
2918      }
2919   if (1==(0x1 & buffer[8])){ /* Bit 0 of the 4th byte in the Clean Head Log Parameter, which are the bytes */
2920                             /* 4 to 8 on the Log Sense Page 0x33                                          */
2921     ret = 1;
2922   }else {
2923     ret = 0; 
2924   }  
2925   DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### STOP SCSI_LogSenseClean (%d)\n",ret);
2926   free(pRequestSense);
2927   free(buffer);
2928   return(ret);
2929 }
2930
2931 int
2932 GenericResetStatus(
2933     int         DeviceFD)
2934 {
2935   CDB_T CDB;
2936   RequestSense_T *pRequestSense;
2937   int ret = 0;
2938   int retry = 1;
2939
2940   DebugPrint(DEBUG_INFO, SECTION_ELEMENT, "##### START GenericResetStatus\n");
2941
2942   pRequestSense = alloc(SIZEOF(RequestSense_T));
2943
2944   while (retry)
2945     {
2946       CDB[0] = SC_COM_IES;   /* */
2947       CDB[1] = 0;
2948       CDB[2] = 0;
2949       CDB[3] = 0;
2950       CDB[4] = 0;
2951       CDB[5] = 0;
2952
2953
2954       ret = SCSI_Run(DeviceFD, Input, CDB, 6,
2955                                 NULL, 0,
2956                                 pRequestSense,
2957                                 SIZEOF(RequestSense_T));
2958
2959       if (ret < 0)
2960         {
2961           /*        fprintf(stderr, "%s: Request Sense[Inquiry]: %02X", */
2962           /*                "chs", ((u_char *) &pRequestSense)[0]); */
2963           /*        for (i = 1; i < SIZEOF(RequestSense_T); i++)                */
2964           /*          fprintf(stderr, " %02X", ((u_char *) &pRequestSense)[i]); */
2965           /*        fprintf(stderr, "\n");    */
2966           free(pRequestSense);
2967           return(ret);
2968           /*NOTREACHED*/
2969         }
2970       if ( ret > 0 )
2971         {
2972           switch (SenseHandler(DeviceFD, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
2973             {
2974             case SENSE_IGNORE:
2975               free(pRequestSense);
2976               return(0);
2977               /*NOTREACHED*/
2978             case SENSE_ABORT:
2979               free(pRequestSense);
2980               return(-1);
2981               /*NOTREACHED*/
2982             case SENSE_RETRY:
2983               retry++;
2984               if (retry < MAX_RETRIES )
2985                 {
2986                   DebugPrint(DEBUG_INFO, SECTION_ELEMENT, "GenericResetStatus : retry %d\n", retry);
2987                   sleep(2);
2988                 } else {
2989                   DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "GenericResetStatus : return (-1)\n");
2990                   free(pRequestSense);
2991                   return(-1);
2992                   /*NOTREACHED*/
2993                 }
2994               break;
2995             default:
2996               DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "GenericResetStatus :  (default) return (-1)\n");
2997               free(pRequestSense);
2998               return(-1);
2999               /*NOTREACHED*/
3000             }
3001         }
3002       if (ret == 0)
3003         retry = 0;
3004     }
3005   DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "##### STOP GenericResetStatus (%d)\n",ret);
3006   free(pRequestSense);
3007   return(ret);
3008 }
3009
3010 /* GenericSenseHandler
3011  * Handles the conditions/sense wich is returned by an SCSI command
3012  * pwork is an pointer to the structure OpenFiles_T, which is filled with information
3013  * about the device to which we talk. Information are for example
3014  * The vendor, the ident, which fd, etc. This strucure is filled when we open the
3015  * device
3016  * flag tells how to handle the information passed in the buffer,
3017  * 0 -> Sense Key available
3018  * 1 -> No Sense key available
3019  * buffer is a pointer to the data from the request sense result.
3020  *
3021  * TODO:
3022  * Limit recursion, may run in an infinite loop
3023  */
3024 int
3025 GenericSenseHandler(
3026     int                 ip,
3027     u_char              flag,
3028     u_char              SenseKey,
3029     u_char              AdditionalSenseCode,
3030     u_char              AdditionalSenseCodeQualifier,
3031     RequestSense_T *    pRequestSense)
3032 {
3033   extern OpenFiles_T *pDev;
3034   int ret;
3035   char *info = NULL;
3036
3037   dbprintf(("##### START GenericSenseHandler\n"));
3038
3039   DecodeSense(pRequestSense, "GenericSenseHandler : ", debug_file);
3040
3041   ret = Sense2Action(pDev[ip].ident,
3042                      pDev[ip].inquiry->type,
3043                      flag, SenseKey,
3044                      AdditionalSenseCode,
3045                      AdditionalSenseCodeQualifier,
3046                      &info);
3047
3048   dbprintf(("##### STOP GenericSenseHandler\n"));
3049   return(ret);
3050 }
3051
3052 /*
3053  * Do the move. We don't address the MTE element (the gripper)
3054  * here. We assume that the library use the right MTE.
3055  * The difference to GenericMove is that we do an align element
3056  * before the move.
3057  *
3058  * Return:
3059  *         == 0 -> success
3060  *         != 0 -> error either from the SCSI command or from
3061  *                 the element handling
3062  * TODO:
3063 */
3064 int
3065 SDXMove(
3066     int         DeviceFD,
3067     int         from,
3068     int         to)
3069 {
3070   extern OpenFiles_T *pDev;
3071   ElementInfo_T *pfrom;
3072   ElementInfo_T *pto;
3073   int ret;
3074   int tapestat;
3075   int moveok;
3076   int SDX_MTE = 0;      /* This are parameters  passed */
3077   int SDX_STE = -1;     /* to                          */
3078   int SDX_DTE = -1;     /* AlignElements               */
3079
3080   DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### START SDXMove\n");
3081
3082   DebugPrint(DEBUG_INFO, SECTION_MOVE,"%-20s : from = %d, to = %d\n", "SDXMove", from, to);
3083
3084
3085   if ((pfrom = LookupElement(from)) == NULL)
3086     {
3087       DebugPrint(DEBUG_INFO, SECTION_MOVE,"SDXMove : ElementInfo for %d not found\n", from);
3088       DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP SDXMove\n");
3089       return(-1);
3090       /*NOTREACHED*/
3091     }
3092
3093   if ((pto = LookupElement(to)) == NULL)
3094     {
3095       DebugPrint(DEBUG_INFO, SECTION_MOVE,"SDXMove : ElementInfo for %d not found\n", to);
3096       DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP SDXMove\n");
3097       return(-1);
3098       /*NOTREACHED*/
3099     }
3100
3101   if (pfrom->status == 'E')
3102     {
3103       DebugPrint(DEBUG_INFO, SECTION_MOVE,"SDXMove : from %d is empty\n", from);
3104       DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP SDXMove\n");
3105       return(-1);
3106       /*NOTREACHED*/
3107     }
3108
3109   if (pto->status == 'F')
3110     {
3111       switch (pto->status)
3112       {
3113          case CHANGER:
3114            break;
3115          case STORAGE:
3116            DebugPrint(DEBUG_INFO, SECTION_MOVE,"SDXMove : Destination Element %d Type %d is full\n",
3117                 pto->address, pto->type);
3118             to = find_empty(DeviceFD, 0, 0);
3119             if (to == -1 )
3120             {
3121                     DebugPrint(DEBUG_ERROR, SECTION_MOVE,"SDXMove : no empty slot found for unload\n");
3122                     return(-1);
3123                     /*NOTREACHED*/
3124             }
3125             DebugPrint(DEBUG_INFO, SECTION_MOVE,"SDXMove : Unload to %d\n", to);
3126             if ((pto = LookupElement(to)) == NULL)
3127             {
3128               DebugPrint(DEBUG_INFO, SECTION_MOVE, "SDXMove : ElementInfo for %d not found\n", to);
3129               DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP SDXMove\n");
3130               return(-1);
3131               /*NOTREACHED*/
3132             }
3133            break;
3134          case IMPORT:
3135            break;
3136          case TAPETYPE:
3137            break;
3138       }
3139     }
3140
3141   moveok = CheckMove(pfrom, pto);
3142
3143   switch (pto->type)
3144   {
3145     case TAPETYPE:
3146       SDX_DTE = pto->address;
3147       break;
3148     case STORAGE:
3149      SDX_STE = pto->address;
3150      break;
3151     case IMPORT:
3152      SDX_STE = pto->address;
3153      break;
3154   }
3155
3156   switch (pfrom->type)
3157   {
3158     case TAPETYPE:
3159       SDX_DTE = pfrom->address;
3160       break;
3161     case STORAGE:
3162      SDX_STE = pfrom->address;
3163      break;
3164     case IMPORT:
3165      SDX_STE = pfrom->address;
3166      break;
3167   }
3168
3169   if (SDX_DTE >= 0 && SDX_STE >= 0)
3170   {
3171     ret = SCSI_AlignElements(DeviceFD, SDX_MTE, SDX_DTE, SDX_STE);
3172     DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### SCSI_AlignElemnts ret = %d\n",ret);
3173     if (ret != 0 )
3174     {
3175       DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP SDXMove\n");
3176       return(-1);
3177       /*NOTREACHED*/
3178     }
3179   } else {
3180     DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### Error setting STE/DTE %d/%d\n", SDX_STE, SDX_DTE);
3181     DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP SDXMove\n");
3182     return(-1);
3183     /*NOTREACHED*/
3184   }
3185
3186   /*
3187    * If from is a tape we must check if it is loaded
3188    * and if yes we have to eject it
3189   */
3190   if (pfrom->type == TAPETYPE)
3191   {
3192     tapestat = Tape_Status(INDEX_TAPE);
3193     if ( tapestat & TAPE_ONLINE)
3194     {
3195       if (pDev[INDEX_TAPECTL].SCSI == 1)
3196       {
3197         ret = eject_tape(pDev[INDEX_TAPECTL].dev,1);
3198       } else {
3199         ret = eject_tape(pDev[INDEX_TAPE].dev,2);
3200       }
3201     }
3202   }
3203
3204   if ((ret == 0) && moveok)
3205   {
3206     ret = SCSI_Move(DeviceFD, 0, from, to);
3207   } else {
3208     DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP SDXMove\n");
3209     return(ret);
3210     /*NOTREACHED*/
3211   }
3212   DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP SDXMove\n");
3213   return(ret);
3214 }
3215
3216 /*
3217  * Do the move. We don't address the MTE element (the gripper)
3218  * here. We assume that the library use the right MTE
3219  *
3220  * Return:
3221  *         == 0 -> success
3222  *         != 0 -> error either from the SCSI command or from
3223  *                 the element handling
3224  * TODO:
3225 */
3226 int
3227 GenericMove(
3228     int         DeviceFD,
3229     int         from,
3230     int         to)
3231 {
3232   ElementInfo_T *pfrom;
3233   ElementInfo_T *pto;
3234   int ret = 0;
3235
3236   DebugPrint(DEBUG_INFO, SECTION_MOVE, "##### START GenericMove\n");
3237
3238   DebugPrint(DEBUG_INFO, SECTION_MOVE, "%-20s : from = %d, to = %d\n", "GenericMove", from, to);
3239
3240
3241   if ((pfrom = LookupElement(from)) == NULL)
3242     {
3243       DebugPrint(DEBUG_INFO, SECTION_MOVE, "GenericMove : ElementInfo for %d not found\n", from);
3244       DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP GenericMove\n");
3245       return(-1);
3246       /*NOTREACHED*/
3247     }
3248
3249   if ((pto = LookupElement(to)) == NULL)
3250     {
3251       DebugPrint(DEBUG_INFO, SECTION_MOVE, "GenericMove : ElementInfo for %d not found\n", to);
3252       DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP GenericMove\n");
3253       return(-1);
3254       /*NOTREACHED*/
3255     }
3256
3257   if (pfrom->status == 'E')
3258     {
3259       DebugPrint(DEBUG_INFO, SECTION_MOVE, "GenericMove : from %d is empty\n", from);
3260       DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP GenericMove\n");
3261       return(-1);
3262       /*NOTREACHED*/
3263     }
3264
3265   if (pto->status == 'F')
3266     {
3267       DebugPrint(DEBUG_INFO, SECTION_MOVE, "GenericMove : Destination Element %d Type %d is full\n",
3268                  pto->address, pto->type);
3269       to = find_empty(DeviceFD, 0, 0);
3270       if ( to == -1)
3271       {
3272               DebugPrint(DEBUG_ERROR, SECTION_MOVE, "GenericMove : no empty slot found\n");
3273               return(-1);
3274               /*NOTREACHED*/
3275       }
3276       DebugPrint(DEBUG_INFO, SECTION_MOVE, "GenericMove : Unload to %d\n", to);
3277       if ((pto = LookupElement(to)) == NULL)
3278         {
3279           DebugPrint(DEBUG_ERROR, SECTION_MOVE, " Ups should not happen\n");
3280           DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP GenericMove\n");
3281           return(-1);
3282           /*NOTREACHED*/
3283         }
3284     }
3285
3286   if (CheckMove(pfrom, pto))
3287     {
3288       ret = SCSI_Move(DeviceFD, 0, from, to);
3289     }
3290
3291   DebugPrint(DEBUG_INFO, SECTION_MOVE, "GenericMove : SCSI_Move return (%d)\n", ret);
3292   DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP GenericMove\n");
3293   return(ret);
3294 }
3295
3296 /*
3297  * Check if a move based on the information we got from the Mode Sense command
3298  * is legal
3299  * Return Values:
3300  * 1 => OK
3301  * 0 => Not OK
3302  */
3303
3304 int
3305 CheckMove(
3306     ElementInfo_T *     from,
3307     ElementInfo_T *     to)
3308 {
3309         int moveok = 0;
3310
3311         DebugPrint(DEBUG_INFO, SECTION_MOVE, "##### START CheckMove\n");
3312         if (pDeviceCapabilitiesPage != NULL )
3313           {
3314             DebugPrint(DEBUG_INFO, SECTION_MOVE, "CheckMove : checking if move from %d to %d is legal\n", from->address, to->address);
3315             switch (from->type)
3316               {
3317               case CHANGER:
3318                 DebugPrint(DEBUG_INFO, SECTION_MOVE, "CheckMove : MT2");
3319                 switch (to->type)
3320                   {
3321                   case CHANGER:
3322                     if (pDeviceCapabilitiesPage->MT2MT == 1)
3323                       {
3324                         DebugPrint(DEBUG_INFO, SECTION_MOVE, "MT\n");
3325                         moveok = 1;
3326                       }
3327                     break;
3328                   case STORAGE:
3329                     if (pDeviceCapabilitiesPage->MT2ST == 1)
3330                       {
3331                         DebugPrint(DEBUG_INFO, SECTION_MOVE, "ST\n");
3332                         moveok = 1;
3333                       }
3334                     break;
3335                   case IMPORT:
3336                     if (pDeviceCapabilitiesPage->MT2IE == 1)
3337                       {
3338                         DebugPrint(DEBUG_INFO, SECTION_MOVE, "IE\n");
3339                         moveok = 1;
3340                       }
3341                     break;
3342                   case TAPETYPE:
3343                     if (pDeviceCapabilitiesPage->MT2DT == 1)
3344                       {
3345                         DebugPrint(DEBUG_INFO, SECTION_MOVE, "DT\n");
3346                         moveok = 1;
3347                       }
3348                     break;
3349                   default:
3350                     break;
3351                   }
3352                 break;
3353               case STORAGE:
3354                 DebugPrint(DEBUG_INFO, SECTION_MOVE, "CheckMove : ST2");
3355                 switch (to->type)
3356                   {
3357                   case CHANGER:
3358                     if (pDeviceCapabilitiesPage->ST2MT == 1)
3359                       {
3360                         DebugPrint(DEBUG_INFO, SECTION_MOVE, "MT\n");
3361                         moveok = 1;
3362                       }
3363                     break;
3364                   case STORAGE:
3365                     if (pDeviceCapabilitiesPage->ST2ST == 1)
3366                       {
3367                         DebugPrint(DEBUG_INFO, SECTION_MOVE, "ST\n");
3368                         moveok = 1;
3369                       }
3370                     break;
3371                   case IMPORT:
3372                     if (pDeviceCapabilitiesPage->ST2IE == 1)
3373                       {
3374                         DebugPrint(DEBUG_INFO, SECTION_MOVE, "IE\n");
3375                         moveok = 1;
3376                       }
3377                     break;
3378                   case TAPETYPE:
3379                     if (pDeviceCapabilitiesPage->ST2DT == 1)
3380                       {
3381                         DebugPrint(DEBUG_INFO, SECTION_MOVE, "DT\n");
3382                         moveok = 1;
3383                       }
3384                     break;
3385                   default:
3386                     break;
3387                   }
3388                 break;
3389               case IMPORT:
3390                 DebugPrint(DEBUG_INFO, SECTION_MOVE, "CheckMove : IE2");
3391                 switch (to->type)
3392                   {
3393                   case CHANGER:
3394                     if (pDeviceCapabilitiesPage->IE2MT == 1)
3395                       {
3396                         DebugPrint(DEBUG_INFO, SECTION_MOVE, "MT\n");
3397                         moveok = 1;
3398                       }
3399                     break;
3400                   case STORAGE:
3401                     if (pDeviceCapabilitiesPage->IE2ST == 1)
3402                       {
3403                         DebugPrint(DEBUG_INFO, SECTION_MOVE, "ST\n");
3404                         moveok = 1;
3405                       }
3406                     break;
3407                   case IMPORT:
3408                     if (pDeviceCapabilitiesPage->IE2IE == 1)
3409                       {
3410                         DebugPrint(DEBUG_INFO, SECTION_MOVE, "IE\n");
3411                         moveok = 1;
3412                       }
3413                     break;
3414                   case TAPETYPE:
3415                     if (pDeviceCapabilitiesPage->IE2DT == 1)
3416                       {
3417                         DebugPrint(DEBUG_INFO, SECTION_MOVE, "DT\n");
3418                         moveok = 1;
3419                       }
3420                     break;
3421                   default:
3422                     break;
3423                   }
3424                 break;
3425               case TAPETYPE:
3426                 DebugPrint(DEBUG_INFO, SECTION_MOVE, "CheckMove : DT2");
3427                 switch (to->type)
3428                   {
3429                   case CHANGER:
3430                     if (pDeviceCapabilitiesPage->DT2MT == 1)
3431                       {
3432                         DebugPrint(DEBUG_INFO, SECTION_MOVE, "MT\n");
3433                         moveok = 1;
3434                       }
3435                     break;
3436                   case STORAGE:
3437                     if (pDeviceCapabilitiesPage->DT2ST == 1)
3438                       {
3439                         DebugPrint(DEBUG_INFO, SECTION_MOVE, "ST\n");
3440                         moveok = 1;
3441                       }
3442                     break;
3443                   case IMPORT:
3444                     if (pDeviceCapabilitiesPage->DT2IE == 1)
3445                       {
3446                         DebugPrint(DEBUG_INFO, SECTION_MOVE, "IE\n");
3447                         moveok = 1;
3448                       }
3449                     break;
3450                   case TAPETYPE:
3451                     if (pDeviceCapabilitiesPage->DT2DT == 1)
3452                       {
3453                         DebugPrint(DEBUG_INFO, SECTION_MOVE, "DT\n");
3454                         moveok = 1;
3455                       }
3456                     break;
3457                   default:
3458                     break;
3459                   }
3460                 break;
3461               default:
3462                 break;
3463               }
3464           } else {
3465             DebugPrint(DEBUG_INFO, SECTION_MOVE, "CheckMove : pDeviceCapabilitiesPage == NULL");
3466             /*
3467               ChgExit("CheckMove", "DeviceCapabilitiesPage == NULL", FATAL);
3468             */
3469             moveok=1;
3470           }
3471
3472         DebugPrint(DEBUG_INFO, SECTION_MOVE, "###### STOP CheckMove\n");
3473         return(moveok);
3474 }
3475
3476 /*
3477  */
3478
3479 int
3480 GetCurrentSlot(
3481     int         fd,
3482     int         drive)
3483 {
3484   extern OpenFiles_T *pDev;
3485   size_t x;
3486   dbprintf(("##### START GetCurrentSlot\n"));
3487
3488   (void)fd;     /* Quiet unused parameter warning */
3489
3490   if (pDev[0].SCSI == 0)
3491       {
3492           dbprintf(("GetCurrentSlot : can't send SCSI commands\n"));
3493           return(-1);
3494           /*NOTREACHED*/
3495       }
3496
3497   if (ElementStatusValid == 0)
3498     {
3499       if (pDev[0].functions->function_status(0, 1) != 0)
3500         {
3501           return(-1);
3502           /*NOTREACHED*/
3503         }
3504     }
3505
3506   /* If the from address is the as the same as the tape address skip it */
3507   if (pDTE[drive].from >= 0 && pDTE[drive].from != pDTE[drive].address)
3508     {
3509       for (x = 0; x < STE;x++)
3510         {
3511           if (pSTE[x].address == pDTE[drive].from)
3512             return(x);
3513             /*NOTREACHED*/
3514         }
3515       return(-1);
3516       /*NOTREACHED*/
3517     }
3518
3519   for (x = 0; x < STE;x++)
3520     {
3521       if (pSTE[x].status == 'E') {
3522           return(x);
3523           /*NOTREACHED*/
3524         }
3525     }
3526
3527   /* Ups nothing loaded */
3528   return(-1);
3529 }
3530
3531
3532
3533 /*
3534  * Reworked function to get the ElementStatus
3535  * This function will first call the GetElementStatus
3536  * function to get the Element status,
3537  * and than check if there are abnormal conditions.
3538  *
3539  * If there are error conditions try to fix them
3540  *
3541  */
3542 int
3543 GenericElementStatus(
3544     int         DeviceFD,
3545     int         InitStatus)
3546 {
3547   int MTEError = 0;
3548   int STEError = 0;
3549   int IEEError = 0;
3550   int DTEError = 0;
3551
3552   extern OpenFiles_T *pDev;
3553
3554   int error = 0;    /* If set do an INIT ELEMENT STATUS */
3555   size_t x;         /* The standard loop counter :-) */
3556   int retry = 2;    /* Redo it if an error has been reset */
3557
3558   (void)InitStatus;     /* Quiet unused parameter warning */
3559
3560   DebugPrint(DEBUG_INFO, SECTION_ELEMENT, "##### START GenericElementStatus\n");
3561
3562   if (pEAAPage == NULL)
3563     {
3564       /*
3565        * If this pointer is null
3566        * then try to read the parameter with MODE SENSE
3567        *
3568        */
3569       if (pModePage == NULL && LibModeSenseValid == 0)
3570         {
3571           pModePage = alloc(0xff);
3572
3573           if (SCSI_ModeSense(DeviceFD, pModePage, 0xff, 0x8, 0x3f) == 0)
3574             {
3575               LibModeSenseValid = 1;
3576               DecodeModeSense(pModePage, 0, "GenericElementStatus :", 0, debug_file);
3577             } else {
3578               DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"GetElementStatus : failed SCSI_ModeSense\n");
3579               LibModeSenseValid = -1;
3580             }
3581         }
3582     }
3583
3584   while ((GetElementStatus(DeviceFD) == 0) && (retry-- > 0))
3585     {
3586       for (x = 0; x < MTE; x++)
3587         {
3588           if (pMTE[x].ASC > 0)
3589             {
3590               switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pMTE[x].ASC, pMTE[x].ASCQ, (RequestSense_T *)&pMTE[x]))
3591                 {
3592                 case SENSE_IES:
3593                   MTEError = 1;
3594                   error = 1;
3595                   break;
3596                 case SENSE_ABORT:
3597                   DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "GenericElementStatus : Abort on MTE\n");
3598                   return(-1);
3599                   /*NOTREACHED*/
3600                 }
3601             }
3602         }
3603
3604       for (x = 0; x < IEE; x++)
3605         {
3606           if (pIEE[x].ASC > 0)
3607             {
3608               switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pIEE[x].ASC, pIEE[x].ASCQ, (RequestSense_T *)&pIEE[x]))
3609                 {
3610                 case SENSE_IES:
3611                   IEEError = 1;
3612                   error = 1;
3613                   break;
3614                 case SENSE_ABORT:
3615                   DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "GenericElementStatus : Abort on IEE\n");
3616                   return(-1);
3617                   /*NOTREACHED*/
3618                 }
3619             }
3620         }
3621
3622
3623       for (x = 0; x < STE; x++)
3624         {
3625           if (pSTE[x].ASC > 0)
3626             {
3627               switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pSTE[x].ASC, pSTE[x].ASCQ, (RequestSense_T *)&pSTE[x]))
3628                 {
3629                 case SENSE_IES:
3630                   STEError = 1;
3631                   error = 1;
3632                   break;
3633                 case SENSE_ABORT:
3634                   DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "GenericElementStatus : Abort on IES\n");
3635                   return(-1);
3636                   /*NOTREACHED*/
3637                 }
3638             }
3639         }
3640
3641       for (x = 0; x < DTE; x++)
3642         {
3643           if (pDTE[x].ASC > 0)
3644             {
3645               switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pDTE[x].ASC, pDTE[x].ASCQ, (RequestSense_T *)&pDTE[x]))
3646                 {
3647                 case SENSE_IES:
3648                   DTEError = 1;
3649                   error = 1;
3650                   break;
3651                 case SENSE_ABORT:
3652                   DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "GenericElementStatus : Abort on DTE\n");
3653                   return(-1);
3654                   /*NOTREACHED*/
3655                 }
3656             }
3657         }
3658
3659       /*
3660        * OK, we have an error, do an INIT ELMENT
3661        * For the tape if not handled by the robot we have
3662        * to do some extra checks
3663        */
3664       if (error == 1)
3665         {
3666           if (GenericResetStatus(DeviceFD) != 0)
3667             {
3668               ElementStatusValid = 0;
3669               DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "GenericElementStatus : Can't init status STEError(%d) MTEError(%d) DTEError(%d) IEEError(%d)\n", STEError, MTEError, DTEError, IEEError);
3670               return(-1);
3671               /*NOTREACHED*/
3672             }
3673           error = 0;
3674         }
3675
3676       if (DTEError == 1)
3677         {
3678           TapeStatus();
3679           /*
3680            * If the status is empty to an move from tape to tape
3681            * This is if the tape is ejected, but not unloaded
3682            */
3683           if (pDTE[0].status == 'E')
3684             {
3685               DebugPrint(DEBUG_INFO, SECTION_ELEMENT, "GenericElementStatus : try to move tape to tape drive\n");
3686               pDev[DeviceFD].functions->function_move(DeviceFD, pDTE[0].address, pDTE[0].address);
3687             }
3688         }
3689           /* Done GetElementStatus */
3690     }
3691
3692   if (error != 0)
3693     {
3694       DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "GenericElementStatus : Can't init status (after loop)\n");
3695       return(-1);
3696       /*NOTREACHED*/
3697     }
3698
3699   ElementStatusValid = 1;
3700   DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "#### STOP GenericElementStatus\n");
3701   return(0);
3702 }
3703
3704
3705 /*
3706  * This is for the ADIC changer, it seems that they have an diferent
3707  * offset in the mode sense data before the first mode page (+12)
3708  */
3709 int
3710 DLT448ElementStatus(
3711     int         DeviceFD,
3712     int         InitStatus)
3713 {
3714   int DTEError = 0;
3715
3716   extern OpenFiles_T *pDev;
3717
3718   int error = 0;   /* If set do an INIT ELEMENT STATUS */
3719   size_t x;        /* The standard loop counter :-) */
3720   int loop = 2;    /* Redo it if an error has been reset */
3721
3722   (void)InitStatus;     /* Quiet unused parameter warning */
3723
3724   DebugPrint(DEBUG_INFO, SECTION_ELEMENT, "##### START DLT448ElementStatus\n");
3725
3726   if (pEAAPage == NULL)
3727     {
3728       /*
3729        * If this pointer is null
3730        * then try to read the parameter with MODE SENSE
3731        *
3732        */
3733       if (pModePage == NULL && LibModeSenseValid == 0)
3734         {
3735           pModePage = alloc(0xff);
3736
3737           if (SCSI_ModeSense(DeviceFD, pModePage, 0xff, 0x8, 0x3f) == 0)
3738             {
3739               LibModeSenseValid = 1;
3740               DecodeModeSense(pModePage, 12, "DLT448ElementStatus :", 0, debug_file);
3741             } else {
3742               DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"DLT448ElementStatus : failed SCSI_ModeSense\n");
3743               LibModeSenseValid = -1;
3744             }
3745         }
3746     }
3747
3748   while (GetElementStatus(DeviceFD) == 0 && loop-- > 0)
3749     {
3750       for (x = 0; x < MTE; x++)
3751         {
3752           if (pMTE[x].ASC > 0)
3753             {
3754               switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pMTE[x].ASC, pMTE[x].ASCQ, (RequestSense_T *)&pMTE[x]))
3755                 {
3756                 case SENSE_IES:
3757                   error = 1;
3758                   break;
3759                 case SENSE_ABORT:
3760                   DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "DLT448ElementStatus : Abort on MTE\n");
3761                   return(-1);
3762                   /*NOTREACHED*/
3763                 }
3764             }
3765         }
3766
3767       for (x = 0; x < IEE; x++)
3768         {
3769           if (pIEE[x].ASC > 0)
3770             {
3771               switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pIEE[x].ASC, pIEE[x].ASCQ, (RequestSense_T *)&pIEE[x]))
3772                 {
3773                 case SENSE_IES:
3774                   error = 1;
3775                   break;
3776                 case SENSE_ABORT:
3777                   DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "DLT448ElementStatus : Abort on IEE\n");
3778                   return(-1);
3779                   /*NOTREACHED*/
3780                 }
3781             }
3782         }
3783
3784
3785       for (x = 0; x < STE; x++)
3786         {
3787           /*
3788            * Needed for the hack to guess the tape status if an error
3789            * for the tape is pending
3790            */
3791           if (pSTE[x].ASC > 0)
3792             {
3793               switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pSTE[x].ASC, pSTE[x].ASCQ, (RequestSense_T *)&pSTE[x]))
3794                 {
3795                 case SENSE_IES:
3796                   error = 1;
3797                   break;
3798                 case SENSE_ABORT:
3799                   DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "DLT448ElementStatus : Abort on IES\n");
3800                   return(-1);
3801                   /*NOTREACHED*/
3802                 }
3803             }
3804         }
3805
3806       for (x = 0; x < DTE; x++)
3807         {
3808           if (pDTE[x].ASC > 0)
3809             {
3810               switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pDTE[x].ASC, pDTE[x].ASCQ, (RequestSense_T *)&pDTE[x]))
3811                 {
3812                 case SENSE_IES:
3813                   DTEError = 1;
3814                   error = 1;
3815                   break;
3816                 case SENSE_ABORT:
3817                   DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "DLT448ElementStatus : Abort on DTE\n");
3818                   return(-1);
3819                   /*NOTREACHED*/
3820                 }
3821             }
3822         }
3823
3824       /*
3825        * OK, we have an error, do an INIT ELMENT
3826        * For the tape if not handled by the robot we have
3827        * to do some extra checks
3828        */
3829       if (error == 1)
3830         {
3831           if (GenericResetStatus(DeviceFD) != 0)
3832             {
3833               ElementStatusValid = 0;
3834               DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "DLT448ElementStatus : Can't init status\n");
3835               return(-1);
3836               /*NOTREACHED*/
3837             }
3838           error = 0;
3839         }
3840
3841       if (DTEError == 1)
3842         {
3843           TapeStatus();
3844           /*
3845            * If the status is empty to an move from tape to tape
3846            * This is if the tape is ejected, but not unloaded
3847            */
3848           if (pDTE[0].status == 'E')
3849             {
3850               DebugPrint(DEBUG_INFO, SECTION_ELEMENT, "DLT448ElementStatus : try to move tape to tape drive\n");
3851               pDev[DeviceFD].functions->function_move(DeviceFD, pDTE[0].address, pDTE[0].address);
3852             }
3853         }
3854           /* Done GetElementStatus */
3855     }
3856
3857   if (error != 0)
3858     {
3859       DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "DLT448ElementStatus : Can't init status (after loop)\n");
3860       return(-1);
3861       /*NOTREACHED*/
3862     }
3863
3864   ElementStatusValid = 1;
3865   DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "#### STOP DLT448ElementStatus\n");
3866   return(0);
3867 }
3868
3869
3870 /*
3871  * Much the same like GenericElementStatus but
3872  * it seemes that for the STE Elements ASC/ASCQ is not set
3873  * on an error, only the except bit is set
3874 */
3875 int
3876 SDXElementStatus(
3877     int         DeviceFD,
3878     int         InitStatus)
3879 {
3880   int error = 0;   /* If set do an INIT ELEMENT STATUS */
3881   size_t x;        /* The standard loop counter :-) */
3882   int loop = 2;    /* Redo it if an error has been reset */
3883
3884   (void)InitStatus;     /* Quiet unused parameter warning */
3885
3886   DebugPrint(DEBUG_INFO, SECTION_ELEMENT, "##### START SDXElementStatus\n");
3887
3888   if (pEAAPage == NULL)
3889     {
3890       /*
3891        * If this pointer is null
3892        * then try to read the parameter with MODE SENSE
3893        *
3894        */
3895       if (pModePage == NULL && LibModeSenseValid == 0)
3896         {
3897           pModePage = alloc(0xff);
3898
3899           if (SCSI_ModeSense(DeviceFD, pModePage, 0xff, 0x8, 0x3f) == 0)
3900             {
3901               LibModeSenseValid = 1;
3902               DecodeModeSense(pModePage, 0, "SDXElementStatus :", 0, debug_file);
3903             } else {
3904               DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"SDXElementStatus : failed SCSI_ModeSense\n");
3905               LibModeSenseValid = -1;
3906             }
3907         }
3908     }
3909
3910   while (GetElementStatus(DeviceFD) == 0 && loop--)
3911     {
3912       error = 0;
3913       for (x = 0; x < MTE; x++)
3914         {
3915           if (pMTE[x].ASC > 0)
3916             {
3917               switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pMTE[x].ASC, pMTE[x].ASCQ, (RequestSense_T *)&pMTE[x]))
3918                 {
3919                 case SENSE_IES:
3920                   error = 1;
3921                   break;
3922                 case SENSE_ABORT:
3923                   DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "SDXElementStatus : Abort on MTE\n");
3924                   return(-1);
3925                   /*NOTREACHED*/
3926                 }
3927             }
3928         }
3929
3930       for (x = 0; x < IEE; x++)
3931         {
3932           if (pIEE[x].ASC > 0)
3933             {
3934               switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pIEE[x].ASC, pIEE[x].ASCQ, (RequestSense_T *)&pIEE[x]))
3935                 {
3936                 case SENSE_IES:
3937                   error = 1;
3938                   break;
3939                 case SENSE_ABORT:
3940                   DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "SDXElementStatus : Abort on IEE\n");
3941                   return(-1);
3942                   /*NOTREACHED*/
3943                 }
3944             }
3945         }
3946
3947
3948       for (x = 0; x < STE; x++)
3949         {
3950           if (pSTE[x].ASC > 0)
3951             {
3952               switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pSTE[x].ASC, pSTE[x].ASCQ, (RequestSense_T *)&pSTE[x]))
3953                 {
3954                 case SENSE_IES:
3955                   error = 1;
3956                   break;
3957                 case SENSE_ABORT:
3958                   DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "SDXElementStatus : Abort on IES\n");
3959                   return(-1);
3960                   /*NOTREACHED*/
3961                 }
3962             }
3963         }
3964
3965       for (x = 0; x < DTE; x++)
3966         {
3967           if (pDTE[x].ASC > 0)
3968             {
3969               switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pDTE[x].ASC, pDTE[x].ASCQ, (RequestSense_T *)&pDTE[x]))
3970                 {
3971                 case SENSE_IES:
3972                   /*
3973                   error = 1;
3974                   */
3975                   break;
3976                 case SENSE_ABORT:
3977                   DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "SDXElementStatus : Abort on DTE\n");
3978                   return(-1);
3979                   /*NOTREACHED*/
3980                 }
3981             }
3982         }
3983
3984       /*
3985        * OK, we have an error, do an INIT ELMENT
3986        * For the tape if not handled by the robot we have
3987        * to do some extra checks
3988        */
3989       if (error == 1)
3990         {
3991           if (GenericResetStatus(DeviceFD) != 0)
3992             {
3993               ElementStatusValid = 0;
3994               DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "SDXElementStatus : Can't init status\n");
3995               return(-1);
3996               /*NOTREACHED*/
3997             }
3998         }
3999
4000       /* Done GetElementStatus */
4001     }
4002
4003   if (error != 0)
4004     {
4005       DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "SDXElementStatus : Can't init status\n");
4006       return(-1);
4007       /*NOTREACHED*/
4008     }
4009
4010   ElementStatusValid = 1;
4011   TapeStatus();
4012   DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "#### STOP SDXElementStatus\n");
4013   return(0);
4014 }
4015
4016
4017 /*
4018  * Reads the element information from the library. There are 2 ways to do this.
4019  * Either check the result from the mode sense page to see which types of elements
4020  * are available (STE/DTE/MTE....), or do an read element status with the option give
4021  * me all and than check what is available.
4022  *
4023  * Only do the read, error handling is done by the calling function
4024  *
4025  * Return Values:
4026  * < 0   -> Error
4027  * == 0  -> OK
4028  *
4029  * TODO:
4030  */
4031 int
4032 GetElementStatus(
4033     int DeviceFD)
4034 {
4035   u_char *DataBuffer = NULL;
4036   size_t DataBufferLength;
4037   ElementStatusData_T *ElementStatusData;
4038   ElementStatusPage_T *ElementStatusPage;
4039   MediumTransportElementDescriptor_T *MediumTransportElementDescriptor;
4040   StorageElementDescriptor_T *StorageElementDescriptor;
4041   DataTransferElementDescriptor_T *DataTransferElementDescriptor;
4042   ImportExportElementDescriptor_T *ImportExportElementDescriptor;
4043   size_t x;
4044   size_t offset;
4045   size_t length;        /* Length of an Element */
4046   size_t NoOfElements;
4047
4048   DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"##### START GetElementStatus\n");
4049
4050   barcode = BarCode(DeviceFD);
4051
4052   /*
4053    * If the MODE_SENSE was successfull we use this Information to read the Elelement Info
4054    */
4055   if (pEAAPage != NULL)
4056     {
4057       DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Reading Element Status with the info from mode sense\n");
4058       /* First the Medim Transport*/
4059       if (V2(pEAAPage->NoMediumTransportElements)  > 0)
4060         {
4061           MTE = V2(pEAAPage->NoMediumTransportElements) ;
4062           pMTE = alloc(SIZEOF(ElementInfo_T) * MTE);
4063           memset(pMTE, 0, SIZEOF(ElementInfo_T) * MTE);
4064
4065           if (SCSI_ReadElementStatus(DeviceFD,
4066                                      CHANGER,
4067                                      0,
4068                                      (u_char)barcode,
4069                                      V2(pEAAPage->MediumTransportElementAddress),
4070                                      (MTE + (size_t)1),
4071                                      SIZEOF(MediumTransportElementDescriptor_T),
4072                                      &DataBuffer) != 0)
4073             {
4074               ChgExit("genericElementStatus","Can't read MTE status", FATAL);
4075               /*NOTREACHED*/
4076             }
4077           // ElementStatusData = (ElementStatusData_T *)DataBuffer;
4078           offset = SIZEOF(ElementStatusData_T);
4079
4080           ElementStatusPage = (ElementStatusPage_T *)&DataBuffer[offset];
4081           offset = offset + SIZEOF(ElementStatusPage_T);
4082           length = V2(ElementStatusPage->length);
4083
4084           DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"MTE Length %d(%d)\n", length,
4085                         SIZEOF(MediumTransportElementDescriptor_T));
4086
4087           for (x = 0; x < MTE; x++)
4088             {
4089               MediumTransportElementDescriptor = (MediumTransportElementDescriptor_T *)&DataBuffer[offset];
4090
4091               if (ElementStatusPage->pvoltag == 1)
4092                 {
4093                   strncpy((char *)pMTE[x].VolTag,
4094                           (char *)MediumTransportElementDescriptor->pvoltag,
4095                           TAG_SIZE);
4096                   TerminateString(pMTE[x].VolTag, TAG_SIZE+1);
4097                 }
4098
4099               pMTE[x].type = ElementStatusPage->type;
4100               pMTE[x].address = V2(MediumTransportElementDescriptor->address);
4101               pMTE[x].except = MediumTransportElementDescriptor->except;
4102               pMTE[x].full = MediumTransportElementDescriptor->full;
4103               if (MediumTransportElementDescriptor->full > 0)
4104                 {
4105                   pMTE[x].status = 'F';
4106                 } else {
4107                   pMTE[x].status = 'E';
4108                 }
4109
4110               if (length >= 5)
4111                 {
4112                   pMTE[x].ASC = MediumTransportElementDescriptor->asc;
4113                 } else {
4114                   DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASC MTE\n");
4115                 }
4116
4117               if (length >= 6)
4118                 {
4119                   pMTE[x].ASCQ = MediumTransportElementDescriptor->ascq;
4120                 } else {
4121                   DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASCQ MTE\n");
4122                 }
4123
4124               if (length >= 0xa)
4125                 {
4126                   if (MediumTransportElementDescriptor->svalid == 1)
4127                     {
4128                       pMTE[x].from = V2(MediumTransportElementDescriptor->source);
4129                     } else {
4130                       pMTE[x].from = -1;
4131                     }
4132                 } else {
4133                   DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip source MTE\n");
4134                 }
4135               offset = offset + length;
4136             }
4137             free(DataBuffer);
4138             DataBuffer = NULL;
4139         }
4140       /*
4141        * Storage Elements
4142        */
4143       if ( V2(pEAAPage->NoStorageElements)  > 0)
4144         {
4145           free(pSTE);
4146           STE = V2(pEAAPage->NoStorageElements);
4147           pSTE = alloc(SIZEOF(ElementInfo_T) * STE);
4148           memset(pSTE, 0, SIZEOF(ElementInfo_T) * STE);
4149
4150           if (SCSI_ReadElementStatus(DeviceFD,
4151                                      STORAGE,
4152                                      0,
4153                                      (u_char)barcode,
4154                                      V2(pEAAPage->FirstStorageElementAddress),
4155                                      STE,
4156                                      SIZEOF(StorageElementDescriptor_T),
4157                                      &DataBuffer) != 0)
4158             {
4159               ChgExit("GetElementStatus", "Can't read STE status", FATAL);
4160               /*NOTREACHED*/
4161             }
4162           assert(DataBuffer != NULL);
4163
4164           // ElementStatusData = (ElementStatusData_T *)DataBuffer;
4165           offset = SIZEOF(ElementStatusData_T);
4166
4167           ElementStatusPage = (ElementStatusPage_T *)&DataBuffer[offset];
4168           offset = offset + SIZEOF(ElementStatusPage_T);
4169           length = V2(ElementStatusPage->length);
4170           DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"STE Length %d\n",length);
4171
4172           for (x = 0; x < STE; x++)
4173             {
4174               StorageElementDescriptor = (StorageElementDescriptor_T *)&DataBuffer[offset];
4175               if (ElementStatusPage->pvoltag == 1)
4176                 {
4177                   strncpy(pSTE[x].VolTag,
4178                           (char *)StorageElementDescriptor->pvoltag,
4179                           TAG_SIZE);
4180                   TerminateString(pSTE[x].VolTag, TAG_SIZE+1);
4181                 }
4182
4183
4184               pSTE[x].type = ElementStatusPage->type;
4185               pSTE[x].address = V2(StorageElementDescriptor->address);
4186               pSTE[x].except = StorageElementDescriptor->except;
4187               pSTE[x].full = StorageElementDescriptor->full;
4188               if (StorageElementDescriptor->full > 0)
4189                 {
4190                   pSTE[x].status = 'F';
4191                 } else {
4192                   pSTE[x].status = 'E';
4193                 }
4194
4195               if (length >= 5)
4196                 {
4197                   pSTE[x].ASC = StorageElementDescriptor->asc;
4198                 } else {
4199                   DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASC STE\n");
4200                 }
4201
4202               if (length >= 6)
4203                 {
4204                   pSTE[x].ASCQ = StorageElementDescriptor->ascq;
4205                 } else {
4206                   DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASCQ STE\n");
4207                 }
4208
4209               if (length >= 0xa)
4210                 {
4211                   if (StorageElementDescriptor->svalid == 1)
4212                     {
4213                       pSTE[x].from = V2(StorageElementDescriptor->source);
4214                     } else {
4215                       pSTE[x].from = -1;
4216                     }
4217                 } else {
4218                   DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip source STE\n");
4219                 }
4220
4221               offset = offset + length;
4222             }
4223             free(DataBuffer);
4224             DataBuffer = NULL;
4225         }
4226       /*
4227        * Import/Export Elements
4228        */
4229       if ( V2(pEAAPage->NoImportExportElements) > 0)
4230         {
4231           free(pIEE);
4232           IEE = V2(pEAAPage->NoImportExportElements);
4233           pIEE = alloc(SIZEOF(ElementInfo_T) * IEE);
4234           memset(pIEE, 0, SIZEOF(ElementInfo_T) * IEE);
4235
4236           if (SCSI_ReadElementStatus(DeviceFD,
4237                                      IMPORT,
4238                                      0,
4239                                      (u_char)barcode,
4240                                      V2(pEAAPage->FirstImportExportElementAddress),
4241                                      IEE,
4242                                      SIZEOF(ImportExportElementDescriptor_T),
4243                                      &DataBuffer) != 0)
4244             {
4245               ChgExit("GetElementStatus", "Can't read IEE status", FATAL);
4246               /*NOTREACHED*/
4247             }
4248           assert(DataBuffer != NULL);
4249
4250           // ElementStatusData = (ElementStatusData_T *)DataBuffer;
4251           offset = SIZEOF(ElementStatusData_T);
4252
4253           ElementStatusPage = (ElementStatusPage_T *)&DataBuffer[offset];
4254           offset = offset + SIZEOF(ElementStatusPage_T);
4255           length = V2(ElementStatusPage->length);
4256           DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"IEE Length %d\n",length);
4257
4258           for (x = 0; x < IEE; x++)
4259             {
4260               ImportExportElementDescriptor = (ImportExportElementDescriptor_T *)&DataBuffer[offset];
4261               if (ElementStatusPage->pvoltag == 1)
4262                 {
4263                   strncpy(pIEE[x].VolTag,
4264                           (char *)ImportExportElementDescriptor->pvoltag,
4265                           TAG_SIZE);
4266                   TerminateString(pIEE[x].VolTag, TAG_SIZE+1);
4267                 }
4268               pIEE[x].type = ElementStatusPage->type;
4269               pIEE[x].address = V2(ImportExportElementDescriptor->address);
4270               pIEE[x].except = ImportExportElementDescriptor->except;
4271               pIEE[x].full = ImportExportElementDescriptor->full;
4272               if (ImportExportElementDescriptor->full > 0)
4273                 {
4274                   pIEE[x].status = 'F';
4275                 } else {
4276                   pIEE[x].status = 'E';
4277                 }
4278
4279               if (length >= 5)
4280                 {
4281                   pIEE[x].ASC = ImportExportElementDescriptor->asc;
4282                 } else {
4283                   DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASC IEE\n");
4284                 }
4285
4286               if (length >= 6)
4287                 {
4288                   pIEE[x].ASCQ = ImportExportElementDescriptor->ascq;
4289                 } else {
4290                   DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASCQ IEE\n");
4291                 }
4292
4293               if (length >= 0xa)
4294                 {
4295                   if (ImportExportElementDescriptor->svalid == 1)
4296                     {
4297                       pIEE[x].from = V2(ImportExportElementDescriptor->source);
4298                     } else {
4299                       pIEE[x].from = -1;
4300                     }
4301                 } else {
4302                   DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip source IEE\n");
4303                 }
4304
4305               offset = offset + length;
4306             }
4307             free(DataBuffer);
4308             DataBuffer = NULL;
4309         }
4310       /*
4311        * Data Transfer Elements
4312        */
4313       if (V2(pEAAPage->NoDataTransferElements) >0)
4314         {
4315           free(pDTE);
4316           DTE = V2(pEAAPage->NoDataTransferElements) ;
4317           pDTE = alloc(SIZEOF(ElementInfo_T) * DTE);
4318           memset(pDTE, 0, SIZEOF(ElementInfo_T) * DTE);
4319
4320           if (SCSI_ReadElementStatus(DeviceFD,
4321                                      TAPETYPE,
4322                                      0,
4323                                      (u_char)barcode,
4324                                      V2(pEAAPage->FirstDataTransferElementAddress),
4325                                      DTE,
4326                                      SIZEOF(DataTransferElementDescriptor_T),
4327                                      &DataBuffer) != 0)
4328             {
4329               ChgExit("GenericElementStatus", "Can't read DTE status", FATAL);
4330               /*NOTREACHED*/
4331             }
4332           assert(DataBuffer != NULL);
4333
4334           // ElementStatusData = (ElementStatusData_T *)DataBuffer;
4335           offset = SIZEOF(ElementStatusData_T);
4336
4337           ElementStatusPage = (ElementStatusPage_T *)&DataBuffer[offset];
4338           offset = offset + SIZEOF(ElementStatusPage_T);
4339           length = V2(ElementStatusPage->length);
4340           DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"DTE Length %d\n",length);
4341
4342           for (x = 0; x < DTE; x++)
4343             {
4344               DataTransferElementDescriptor = (DataTransferElementDescriptor_T *)&DataBuffer[offset];
4345               if (ElementStatusPage->pvoltag == 1)
4346                 {
4347                   strncpy(pDTE[x].VolTag,
4348                           (char *)DataTransferElementDescriptor->pvoltag,
4349                           TAG_SIZE);
4350                   TerminateString(pDTE[x].VolTag, TAG_SIZE+1);
4351                 }
4352               pDTE[x].type = ElementStatusPage->type;
4353               pDTE[x].address = V2(DataTransferElementDescriptor->address);
4354               pDTE[x].except = DataTransferElementDescriptor->except;
4355               pDTE[x].scsi = DataTransferElementDescriptor->scsi;
4356               pDTE[x].full = DataTransferElementDescriptor->full;
4357               if (DataTransferElementDescriptor->full > 0)
4358                 {
4359                   pDTE[x].status = 'F';
4360                 } else {
4361                   pDTE[x].status = 'E';
4362                 }
4363
4364               if (length >= 5)
4365               {
4366                 pDTE[x].ASC = DataTransferElementDescriptor->asc;
4367               } else {
4368                 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASC DTE\n");
4369               }
4370
4371               if (length >= 6)
4372                 {
4373                   pDTE[x].ASCQ = DataTransferElementDescriptor->ascq;
4374               } else {
4375                 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASCQ DTE\n");
4376               }
4377
4378               if (length >= 0xa)
4379                 {
4380                   if (DataTransferElementDescriptor->svalid == 1)
4381                     {
4382                       pDTE[x].from = V2(DataTransferElementDescriptor->source);
4383                     } else {
4384                       pDTE[x].from = -1;
4385                     }
4386                 } else {
4387                   DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip source STE\n");
4388                 }
4389
4390               offset = offset + length;
4391             }
4392             free(DataBuffer);
4393             DataBuffer = NULL;
4394         }
4395     } else {
4396       /*
4397        * And now the old way, when we get here the read mode sense page has failed ...
4398        */
4399       DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Reading Element Status the old way .... (max 255 elements)\n");
4400       if (SCSI_ReadElementStatus(DeviceFD,
4401                                  0,
4402                                  0,
4403                                  (u_char)barcode,
4404                                  0,
4405                                  (size_t)0xff,
4406                                  (size_t)0x7f,
4407                                  &DataBuffer) != 0)
4408         {
4409           ChgExit("GenericElementStatus","Can't get ElementStatus", FATAL);
4410           /*NOTREACHED*/
4411         }
4412       assert(DataBuffer != NULL);
4413
4414       ElementStatusData = (ElementStatusData_T *)DataBuffer;
4415       DataBufferLength = V3(ElementStatusData->count);
4416
4417       offset = SIZEOF(ElementStatusData_T);
4418
4419       while (offset < DataBufferLength)
4420         {
4421           ElementStatusPage = (ElementStatusPage_T *)&DataBuffer[offset];
4422           NoOfElements = V3(ElementStatusPage->count) / V2(ElementStatusPage->length);
4423           offset = offset + SIZEOF(ElementStatusPage_T);
4424           length = V2(ElementStatusPage->length);
4425
4426           switch (ElementStatusPage->type)
4427             {
4428             case CHANGER:
4429               free(pMTE);
4430               MTE = NoOfElements;
4431               pMTE = alloc(SIZEOF(ElementInfo_T) * MTE);
4432               memset(pMTE, 0, SIZEOF(ElementInfo_T) * MTE);
4433
4434               for (x = 0; x < NoOfElements; x++)
4435                 {
4436                   MediumTransportElementDescriptor = (MediumTransportElementDescriptor_T *)&DataBuffer[offset];
4437                   if (ElementStatusPage->pvoltag == 1)
4438                     {
4439                       strncpy(pMTE[x].VolTag,
4440                               (char *)MediumTransportElementDescriptor->pvoltag,
4441                               TAG_SIZE);
4442                       TerminateString(pMTE[x].VolTag, TAG_SIZE+1);
4443                     }
4444                   pMTE[x].type = ElementStatusPage->type;
4445                   pMTE[x].address = V2(MediumTransportElementDescriptor->address);
4446                   pMTE[x].except = MediumTransportElementDescriptor->except;
4447                   pMTE[x].full = MediumTransportElementDescriptor->full;
4448                   if (MediumTransportElementDescriptor->full > 0)
4449                     {
4450                       pMTE[x].status = 'F';
4451                     } else {
4452                       pMTE[x].status = 'E';
4453                     }
4454
4455                   if (length >= 5)
4456                     {
4457                       pMTE[x].ASC = MediumTransportElementDescriptor->asc;
4458                     } else {
4459                       DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASC MTE\n");
4460                     }
4461
4462                   if (length >= 6)
4463                     {
4464                       pMTE[x].ASCQ = MediumTransportElementDescriptor->ascq;
4465                     } else {
4466                       DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASCQ MTE\n");
4467                     }
4468
4469                   if (length >= 0xa)
4470                     {
4471                       if (MediumTransportElementDescriptor->svalid == 1)
4472                         {
4473                           pMTE[x].from = V2(MediumTransportElementDescriptor->source);
4474                         } else {
4475                           pMTE[x].from = -1;
4476                         }
4477                     } else {
4478                       DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip source MTE\n");
4479                     }
4480
4481                   offset = offset + length;
4482                 }
4483               break;
4484             case STORAGE:
4485               free(pSTE);
4486               STE = NoOfElements;
4487               pSTE = alloc(SIZEOF(ElementInfo_T) * STE);
4488               memset(pSTE, 0, SIZEOF(ElementInfo_T) * STE);
4489
4490               for (x = 0; x < NoOfElements; x++)
4491                 {
4492                   StorageElementDescriptor = (StorageElementDescriptor_T *)&DataBuffer[offset];
4493                   if (ElementStatusPage->pvoltag == 1)
4494                     {
4495                       strncpy(pSTE[x].VolTag,
4496                               (char *)StorageElementDescriptor->pvoltag,
4497                               TAG_SIZE);
4498                       TerminateString(pSTE[x].VolTag, TAG_SIZE+1);
4499                     }
4500
4501                   pSTE[x].type = ElementStatusPage->type;
4502                   pSTE[x].address = V2(StorageElementDescriptor->address);
4503                   pSTE[x].except = StorageElementDescriptor->except;
4504                   pSTE[x].full = StorageElementDescriptor->full;
4505                   if (StorageElementDescriptor->full > 0)
4506                     {
4507                       pSTE[x].status = 'F';
4508                     } else {
4509                       pSTE[x].status = 'E';
4510                     }
4511
4512                   if (length >= 5)
4513                     {
4514                       pSTE[x].ASC = StorageElementDescriptor->asc;
4515                     } else {
4516                       DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASC STE\n");
4517                     }
4518
4519                   if (length >= 6)
4520                     {
4521                       pSTE[x].ASCQ = StorageElementDescriptor->ascq;
4522                     } else {
4523                       DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASCQ STE\n");
4524                     }
4525
4526                   if (length >= 0xa)
4527                     {
4528                       if (StorageElementDescriptor->svalid == 1)
4529                         {
4530                           pSTE[x].from = V2(StorageElementDescriptor->source);
4531                         } else {
4532                           pSTE[x].from = -1;
4533                         }
4534                     } else {
4535                       DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip source STE\n");
4536                     }
4537
4538                   offset = offset + length;
4539                 }
4540               break;
4541             case IMPORT:
4542               free(pIEE);
4543               IEE = NoOfElements;
4544               pIEE = alloc(SIZEOF(ElementInfo_T) * IEE);
4545               memset(pIEE, 0, SIZEOF(ElementInfo_T) * IEE);
4546
4547               for (x = 0; x < NoOfElements; x++)
4548                 {
4549                   ImportExportElementDescriptor = (ImportExportElementDescriptor_T *)&DataBuffer[offset];
4550                   if (ElementStatusPage->pvoltag == 1)
4551                     {
4552                       strncpy(pIEE[x].VolTag,
4553                               (char *)ImportExportElementDescriptor->pvoltag,
4554                               TAG_SIZE);
4555                       TerminateString(pIEE[x].VolTag, TAG_SIZE+1);
4556                     }
4557                   ImportExportElementDescriptor = (ImportExportElementDescriptor_T *)&DataBuffer[offset];
4558                   pIEE[x].type = ElementStatusPage->type;
4559                   pIEE[x].address = V2(ImportExportElementDescriptor->address);
4560                   pIEE[x].except = ImportExportElementDescriptor->except;
4561                   pIEE[x].full = ImportExportElementDescriptor->full;
4562                   if (ImportExportElementDescriptor->full > 0)
4563                     {
4564                       pIEE[x].status = 'F';
4565                     } else {
4566                       pIEE[x].status = 'E';
4567                     }
4568
4569                   if (length >= 5)
4570                     {
4571                       pIEE[x].ASC = ImportExportElementDescriptor->asc;
4572                     } else {
4573                       DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASC IEE\n");
4574                     }
4575
4576                   if (length >= 6)
4577                     {
4578                       pIEE[x].ASCQ = ImportExportElementDescriptor->ascq;
4579                     } else {
4580                       DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASCQ IEE\n");
4581                     }
4582
4583                   if (length >= 0xa)
4584                     {
4585                       if (ImportExportElementDescriptor->svalid == 1)
4586                         {
4587                           pIEE[x].from = V2(ImportExportElementDescriptor->source);
4588                         } else {
4589                           pIEE[x].from = -1;
4590                         }
4591                     } else {
4592                       DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip source IEE\n");
4593                     }
4594
4595                   offset = offset + length;
4596                 }
4597               break;
4598             case TAPETYPE:
4599               free(pDTE);
4600               DTE = NoOfElements;
4601               pDTE = alloc(SIZEOF(ElementInfo_T) * DTE);
4602               memset(pDTE, 0, SIZEOF(ElementInfo_T) * DTE);
4603
4604               for (x = 0; x < NoOfElements; x++)
4605                 {
4606                   DataTransferElementDescriptor = (DataTransferElementDescriptor_T *)&DataBuffer[offset];
4607                   if (ElementStatusPage->pvoltag == 1)
4608                     {
4609                       strncpy(pSTE[x].VolTag,
4610                               (char *)DataTransferElementDescriptor->pvoltag,
4611                               TAG_SIZE);
4612                       TerminateString(pSTE[x].VolTag, TAG_SIZE+1);
4613                     }
4614                   pDTE[x].type = ElementStatusPage->type;
4615                   pDTE[x].address = V2(DataTransferElementDescriptor->address);
4616                   pDTE[x].except = DataTransferElementDescriptor->except;
4617                   pDTE[x].scsi = DataTransferElementDescriptor->scsi;
4618                   pDTE[x].full = DataTransferElementDescriptor->full;
4619                   if (DataTransferElementDescriptor->full > 0)
4620                     {
4621                       pDTE[x].status = 'F';
4622                     } else {
4623                       pDTE[x].status = 'E';
4624                     }
4625
4626                   if (length >= 5)
4627                     {
4628                       pDTE[x].ASC = DataTransferElementDescriptor->asc;
4629                     } else {
4630                       DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASC DTE\n");
4631                     }
4632
4633                   if (length >= 6)
4634                     {
4635                       pDTE[x].ASCQ = DataTransferElementDescriptor->ascq;
4636                     } else {
4637                       DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASCQ DTE\n");
4638                     }
4639
4640                   if (length >= 0xa)
4641                     {
4642                       if (DataTransferElementDescriptor->svalid == 1)
4643                         {
4644                           pDTE[x].from = V2(DataTransferElementDescriptor->source);
4645                         } else {
4646                           pDTE[x].from = -1;
4647                         }
4648                     } else {
4649                       DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip source STE\n");
4650                     }
4651
4652                   offset = offset + length;
4653                 }
4654               break;
4655             default:
4656               offset = offset + length;
4657               DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"GetElementStatus : UnGknown Type %d\n",ElementStatusPage->type);
4658               break;
4659             }
4660         }
4661         free(DataBuffer);
4662     }
4663
4664   DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"\n\n\tMedia Transport Elements (robot arms) :\n");
4665
4666   for ( x = 0; x < MTE; x++)
4667     DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"\t\tElement #%04d %c\n\t\t\tEXCEPT = %02x\n\t\t\tASC = %02X ASCQ = %02X\n\t\t\tType %d From = %04d\n\t\t\tTAG = %s\n",
4668               pMTE[x].address, pMTE[x].status, pMTE[x].except, pMTE[x].ASC,
4669               pMTE[x].ASCQ, pMTE[x].type, pMTE[x].from, pMTE[x].VolTag);
4670
4671   DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"\n\n\tStorage Elements (Media slots) :\n");
4672
4673   for ( x = 0; x < STE; x++)
4674     DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"\t\tElement #%04d %c\n\t\t\tEXCEPT = %02X\n\t\t\tASC = %02X ASCQ = %02X\n\t\t\tType %d From = %04d\n\t\t\tTAG = %s\n",
4675               pSTE[x].address, pSTE[x].status, pSTE[x].except, pSTE[x].ASC,
4676               pSTE[x].ASCQ, pSTE[x].type, pSTE[x].from, pSTE[x].VolTag);
4677
4678   DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"\n\n\tData Transfer Elements (tape drives) :\n");
4679
4680   for ( x = 0; x < DTE; x++)
4681     DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"\t\tElement #%04d %c\n\t\t\tEXCEPT = %02X\n\t\t\tASC = %02X ASCQ = %02X\n\t\t\tType %d From = %04d\n\t\t\tTAG = %s\n\t\t\tSCSI ADDRESS = %d\n",
4682               pDTE[x].address, pDTE[x].status, pDTE[x].except, pDTE[x].ASC,
4683               pDTE[x].ASCQ, pDTE[x].type, pDTE[x].from, pDTE[x].VolTag,pDTE[x].scsi);
4684
4685   DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"\n\n\tImport/Export Elements  :\n");
4686
4687   for ( x = 0; x < IEE; x++)
4688     DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"\t\tElement #%04d %c\n\t\t\tEXCEPT = %02X\n\t\t\t\tASC = %02X ASCQ = %02X\n\t\t\tType %d From = %04d\n\t\t\tTAG = %s\n",
4689                pIEE[x].address, pIEE[x].status, pIEE[x].except, pIEE[x].ASC,
4690                pIEE[x].ASCQ, pIEE[x].type, pIEE[x].from, pIEE[x].VolTag);
4691
4692
4693
4694   return(0);
4695 }
4696
4697 /*
4698  * Get sense data
4699  * If ClearErrorCounters is set the counters will be reset.
4700  * Used by GenericClean for example
4701  *
4702  * TODO
4703  */
4704 int
4705 RequestSense(
4706     int                         DeviceFD,
4707     ExtendedRequestSense_T *    ExtendedRequestSense,
4708     int                         ClearErrorCounters)
4709 {
4710   CDB_T CDB;
4711   int ret;
4712
4713   DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### START RequestSense\n");
4714
4715   CDB[0] = SC_COM_REQUEST_SENSE;               /* REQUEST SENSE */
4716   CDB[1] = 0;                                  /* Logical Unit Number = 0, Reserved */
4717   CDB[2] = 0;                                  /* Reserved */
4718   CDB[3] = 0;                                  /* Reserved */
4719   CDB[4] = (u_char)sizeof(ExtendedRequestSense_T);   /* Allocation Length */
4720   CDB[5] = (u_char)((ClearErrorCounters << 7) & 0x80); /*  */
4721
4722   memset(ExtendedRequestSense, 0, SIZEOF(ExtendedRequestSense_T));
4723
4724   ret = SCSI_Run(DeviceFD, Input, CDB, 6,
4725                  (char *) ExtendedRequestSense,
4726                  SIZEOF(ExtendedRequestSense_T),
4727                  (RequestSense_T *) ExtendedRequestSense,
4728                  SIZEOF(ExtendedRequestSense_T));
4729
4730
4731   if (ret < 0)
4732     {
4733       DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP RequestSense (%d)\n",ret);
4734       return(ret);
4735       /*NOTREACHED*/
4736     }
4737
4738   if ( ret > 0)
4739     {
4740       DecodeExtSense(ExtendedRequestSense, "RequestSense : ",debug_file);
4741       DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP RequestSense (%d)\n", ExtendedRequestSense->SenseKey);
4742       return(ExtendedRequestSense->SenseKey);
4743       /*NOTREACHED*/
4744     }
4745
4746   dump_hex((u_char *)ExtendedRequestSense ,
4747            SIZEOF(ExtendedRequestSense_T),
4748            DEBUG_INFO, SECTION_SCSI);
4749   DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP RequestSense (0)\n");
4750   return(0);
4751 }
4752
4753
4754 /*
4755  * Lookup function pointer for device ....
4756  */
4757
4758
4759 ElementInfo_T *
4760 LookupElement(
4761     int         address)
4762 {
4763   size_t x;
4764
4765   dbprintf(("##### START LookupElement\n"));
4766
4767   if (DTE > 0)
4768     {
4769       for (x = 0; x < DTE; x++)
4770         {
4771           if (pDTE[x].address == address)
4772           {
4773             dbprintf(("##### STOP LookupElement (DTE)\n"));
4774             return(&pDTE[x]);
4775             /*NOTREACHED*/
4776           }
4777         }
4778     }
4779
4780   if (MTE > 0)
4781     {
4782       for (x = 0; x < MTE; x++)
4783         {
4784           if (pMTE[x].address == address)
4785           {
4786             dbprintf(("##### STOP LookupElement (MTE)\n"));
4787             return(&pMTE[x]);
4788             /*NOTREACHED*/
4789           }
4790         }
4791     }
4792
4793   if (STE > 0)
4794     {
4795       for (x = 0; x < STE; x++)
4796         {
4797           if (pSTE[x].address == address)
4798           {
4799             dbprintf(("##### STOP LookupElement (STE)\n"));
4800             return(&pSTE[x]);
4801             /*NOTREACHED*/
4802           }
4803         }
4804     }
4805
4806   if (IEE > 0)
4807     {
4808       for ( x = 0; x < IEE; x++)
4809         {
4810           if (pIEE[x].address == address)
4811           {
4812             dbprintf(("##### STOP LookupElement (IEE)\n"));
4813             return(&pIEE[x]);
4814             /*NOTREACHED*/
4815           }
4816         }
4817     }
4818   return(NULL);
4819 }
4820
4821 /*
4822  * Here comes everything what decode the log Pages
4823  *
4824  * TODO:
4825  * Fix the result handling from TestUnitReady
4826  *
4827  */
4828 int
4829 LogSense(
4830     int         DeviceFD)
4831 {
4832   extern OpenFiles_T *pDev;
4833   CDB_T CDB;
4834   RequestSense_T *pRequestSense;
4835   LogSenseHeader_T *LogSenseHeader;
4836   LogParameter_T *LogParameter;
4837   struct LogPageDecode *p;
4838   int found;
4839   extern char *tapestatfile;
4840   int i;
4841   unsigned ParameterCode;
4842   unsigned value;
4843   size_t length;
4844   int count;
4845   u_char *buffer;
4846   u_char *logpages;
4847   size_t nologpages;
4848   size_t size = 128;
4849
4850   (void)DeviceFD;       /* Quiet unused parameter warning */
4851
4852   DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### START LogSense\n");
4853
4854   if ((tapestatfile != NULL) && (pDev[INDEX_TAPECTL].SCSI == 1) &&
4855       ((StatFile = fopen(tapestatfile,"a")) != NULL))
4856     {
4857       pRequestSense = alloc(SIZEOF(RequestSense_T));
4858
4859       if (GenericRewind(INDEX_TAPECTL) < 0)
4860         {
4861           DebugPrint(DEBUG_INFO, SECTION_TAPE,"LogSense : Rewind failed\n");
4862           free(pRequestSense);
4863           fclose(StatFile);
4864           return(0);
4865           /*NOTREACHED*/
4866         }
4867       /*
4868        * Try to read the tape label
4869        */
4870       if (pDev[INDEX_TAPE].inqdone == 1)
4871         {
4872           if (pDev[INDEX_TAPE].devopen == 1)
4873             {
4874               SCSI_CloseDevice(INDEX_TAPE);
4875             }
4876
4877           if ((chgscsi_result = (char *)tape_rdlabel(pDev[INDEX_TAPE].dev, &chgscsi_datestamp, &chgscsi_label)) == NULL)
4878             {
4879               fprintf(StatFile, "==== %s ==== %s ====\n", chgscsi_datestamp, chgscsi_label);
4880             } else {
4881               fprintf(StatFile, "%s\n", chgscsi_result);
4882             }
4883         }
4884
4885       buffer = alloc(size);
4886       memset(buffer, 0, size);
4887       /*
4888        * Get the known log pages
4889        */
4890
4891       CDB[0] = SC_COM_LOG_SENSE;
4892       CDB[1] = 0;
4893       CDB[2] = 0x40;    /* 0x40 for current values */
4894       CDB[3] = 0;
4895       CDB[4] = 0;
4896       CDB[5] = 0;
4897       CDB[6] = 00;
4898       MSB2(&CDB[7], size);
4899       CDB[9] = 0;
4900
4901       if (SCSI_Run(INDEX_TAPECTL, Input, CDB, 10,
4902                               buffer,
4903                               size,
4904                               pRequestSense,
4905                               SIZEOF(RequestSense_T)) != 0)
4906         {
4907           DecodeSense(pRequestSense, "LogSense : ",debug_file);
4908           free(pRequestSense);
4909           free(buffer);
4910           fclose(StatFile);
4911           return(0);
4912           /*NOTREACHED*/
4913         }
4914
4915       LogSenseHeader = (LogSenseHeader_T *)buffer;
4916       nologpages = V2(LogSenseHeader->PageLength);
4917       logpages = alloc(nologpages);
4918
4919       memcpy(logpages, buffer + SIZEOF(LogSenseHeader_T), nologpages);
4920
4921       for (count = 0; count < (int)nologpages; count++) {
4922         if (logpages[count] != 0  ) {
4923           memset(buffer, 0, size);
4924           CDB[0] = SC_COM_LOG_SENSE;
4925           CDB[1] = 0;
4926           CDB[2] = (u_char)(0x40 | logpages[count]);/* 0x40 for current values */
4927           CDB[3] = 0;
4928           CDB[4] = 0;
4929           CDB[5] = 0;
4930           CDB[6] = 00;
4931           MSB2(&CDB[7], size);
4932           CDB[9] = 0;
4933
4934           if (SCSI_Run(INDEX_TAPECTL, Input, CDB, 10,
4935                                   buffer,
4936                                   size,
4937                                   pRequestSense,
4938                                   SIZEOF(RequestSense_T)) != 0)
4939             {
4940               DecodeSense(pRequestSense, "LogSense : ",debug_file);
4941               free(pRequestSense);
4942               free(logpages);
4943               free(buffer);
4944               fclose(StatFile);
4945               return(0);
4946               /*NOTREACHED*/
4947             }
4948           LogSenseHeader = (LogSenseHeader_T *)buffer;
4949           length = V2(LogSenseHeader->PageLength);
4950           LogParameter = (LogParameter_T *)(buffer + SIZEOF(LogSenseHeader_T));
4951           /*
4952            * Decode the log pages
4953            */
4954           p = (struct LogPageDecode *)&DecodePages;
4955           found = 0;
4956
4957           dump_hex((u_char *)LogParameter, 64, DEBUG_INFO, SECTION_SCSI);
4958
4959           while(p->ident != NULL) {
4960             if ((strcmp(pDev[INDEX_TAPECTL].ident, p->ident) == 0 ||strcmp("*", p->ident) == 0)  && p->LogPage == logpages[count]) {
4961               p->decode(LogParameter, length);
4962               found = 1;
4963               fprintf(StatFile, "\n");
4964               break;
4965             }
4966             p++;
4967           }
4968
4969           if (!found) {
4970             fprintf(StatFile, "Logpage No %d = %x\n", count ,logpages[count]);
4971
4972             while ((u_char *)LogParameter < (buffer + length)) {
4973               i = LogParameter->ParameterLength;
4974               ParameterCode = V2(LogParameter->ParameterCode);
4975               switch (i) {
4976               case 1:
4977                 value = V1((u_char *)LogParameter + SIZEOF(LogParameter_T));
4978                 fprintf(StatFile, "ParameterCode %02X = %u(%d)\n", ParameterCode, value, i);
4979                 break;
4980               case 2:
4981                 value = V2((u_char *)LogParameter + SIZEOF(LogParameter_T));
4982                 fprintf(StatFile, "ParameterCode %02X = %u(%d)\n", ParameterCode, value, i);
4983                 break;
4984               case 3:
4985                 value = V3((u_char *)LogParameter + SIZEOF(LogParameter_T));
4986                 fprintf(StatFile, "ParameterCode %02X = %u(%d)\n", ParameterCode, value, i);
4987                 break;
4988               case 4:
4989                 value = V4((u_char *)LogParameter + SIZEOF(LogParameter_T));
4990                 fprintf(StatFile, "ParameterCode %02X = %u(%d)\n", ParameterCode, value, i);
4991                 break;
4992               case 5:
4993                 value = V5((u_char *)LogParameter + SIZEOF(LogParameter_T));
4994                 fprintf(StatFile, "ParameterCode %02X = %u(%d)\n", ParameterCode, value, i);
4995                 break;
4996               default:
4997                 fprintf(StatFile, "ParameterCode %02X size %d\n", ParameterCode, i);
4998               }
4999               LogParameter = (LogParameter_T *)((u_char *)LogParameter +  SIZEOF(LogParameter_T) + i);
5000             }
5001             fprintf(StatFile, "\n");
5002           }
5003         }
5004       }
5005
5006       /*
5007        * Test only !!!!
5008        * Reset the cumulative counters
5009        */
5010       CDB[0] = SC_COM_LOG_SELECT;
5011       CDB[1] = 2;
5012       CDB[2] = 0xc0;
5013       CDB[3] = 0;
5014       CDB[4] = 0;
5015       CDB[5] = 0;
5016       CDB[6] = 0;
5017       CDB[7] = 0;
5018       CDB[8] = 0;
5019       CDB[9] = 0;
5020
5021       if (SCSI_Run(INDEX_TAPECTL, Input, CDB, 10,
5022                               buffer,
5023                               size,
5024                               pRequestSense,
5025                               SIZEOF(RequestSense_T)) != 0)
5026         {
5027           DecodeSense(pRequestSense, "LogSense : ",debug_file);
5028           free(pRequestSense);
5029           free(logpages);
5030           /*@ignore@*/
5031           free(buffer);
5032           /*@end@*/
5033           fclose(StatFile);
5034           return(0);
5035           /*NOTREACHED*/
5036         }
5037
5038       free(pRequestSense);
5039       free(logpages);
5040       /*@ignore@*/
5041       free(buffer);
5042       /*@end@*/
5043       fclose(StatFile);
5044     }
5045   DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### STOP LogSense\n");
5046   return(0);
5047 }
5048
5049 void
5050 WriteErrorCountersPage(
5051     LogParameter_T *    buffer,
5052     size_t              length)
5053 {
5054   int i;
5055   unsigned value;
5056   LogParameter_T *LogParameter;
5057   unsigned ParameterCode;
5058   LogParameter = buffer;
5059
5060   fprintf(StatFile, "\tWrite Error Counters Page\n");
5061
5062   while ((u_char *)LogParameter < ((u_char *)buffer + length)) {
5063     i = LogParameter->ParameterLength;
5064     ParameterCode = V2(LogParameter->ParameterCode);
5065
5066     value = 0;
5067     if (Decode(LogParameter, &value) == 0) {
5068       switch (ParameterCode) {
5069       case 2:
5070         fprintf(StatFile, "%-30s = %u\n",
5071                 "Total Rewrites",
5072                 value);
5073         break;
5074       case 3:
5075         fprintf(StatFile, "%-30s = %u\n",
5076                 "Total Errors Corrected",
5077                 value);
5078         break;
5079       case 4:
5080         fprintf(StatFile, "%-30s = %u\n",
5081                 "Total Times E. Processed",
5082                 value);
5083         break;
5084       case 5:
5085         fprintf(StatFile, "%-30s = %u\n",
5086                 "Total Bytes Processed",
5087                 value);
5088         break;
5089       case 6:
5090         fprintf(StatFile, "%-30s = %u\n",
5091                 "Total Unrecoverable Errors",
5092                 value);
5093         break;
5094       default:
5095         fprintf(StatFile, "Unknown ParameterCode %02X = %u(%d)\n",
5096                 ParameterCode,
5097                 value, i);
5098         break;
5099       }
5100     } else {
5101       fprintf(StatFile, "Error decoding Result\n");
5102     }
5103     LogParameter = (LogParameter_T *)((u_char *)LogParameter +  SIZEOF(LogParameter_T) + i);
5104   }
5105 }
5106
5107 void
5108 ReadErrorCountersPage(
5109     LogParameter_T *    buffer,
5110     size_t              length)
5111 {
5112   int i;
5113   unsigned value;
5114   LogParameter_T *LogParameter;
5115   unsigned ParameterCode;
5116   LogParameter = buffer;
5117
5118   fprintf(StatFile, "\tRead Error Counters Page\n");
5119
5120   while ((u_char *)LogParameter < ((u_char *)buffer + length)) {
5121     i = LogParameter->ParameterLength;
5122     ParameterCode = V2(LogParameter->ParameterCode);
5123
5124     value = 0;
5125     if (Decode(LogParameter, &value) == 0) {
5126       switch (ParameterCode) {
5127       case 2:
5128         fprintf(StatFile, "%-30s = %u\n",
5129                 "Total Rereads",
5130                 value);
5131         break;
5132       case 3:
5133         fprintf(StatFile, "%-30s = %u\n",
5134                 "Total Errors Corrected",
5135                 value);
5136         break;
5137       case 4:
5138         fprintf(StatFile, "%-30s = %u\n",
5139                 "Total Times E. Processed",
5140                 value);
5141         break;
5142       case 5:
5143         fprintf(StatFile, "%-30s = %u\n",
5144                 "Total Bytes Processed",
5145                 value);
5146         break;
5147       case 6:
5148         fprintf(StatFile, "%-30s = %u\n",
5149                 "Total Unrecoverable Errors",
5150                 value);
5151         break;
5152       default:
5153         fprintf(StatFile, "Unknown ParameterCode %02X = %u(%d)\n",
5154                 ParameterCode,
5155                 value, i);
5156         break;
5157       }
5158     } else {
5159       fprintf(StatFile, "Error decoding Result\n");
5160     }
5161     LogParameter = (LogParameter_T *)((u_char *)LogParameter +  SIZEOF(LogParameter_T) + i);
5162   }
5163 }
5164
5165 void
5166 C1553APage30(
5167     LogParameter_T *    buffer,
5168     size_t              length)
5169 {
5170   int i;
5171   unsigned value;
5172   LogParameter_T *LogParameter;
5173   unsigned ParameterCode;
5174   LogParameter = buffer;
5175
5176   fprintf(StatFile, "\tData compression transfer Page\n");
5177
5178   while ((u_char *)LogParameter < ((u_char *)buffer + length)) {
5179     i = LogParameter->ParameterLength;
5180     ParameterCode = V2(LogParameter->ParameterCode);
5181
5182     value = 0;
5183     if (Decode(LogParameter, &value) == 0) {
5184       switch (ParameterCode) {
5185       default:
5186         fprintf(StatFile, "Unknown ParameterCode %02X = %u(%d)\n",
5187                 ParameterCode,
5188                 value, i);
5189         break;
5190       }
5191     }
5192     LogParameter = (LogParameter_T *)((u_char *)LogParameter +  SIZEOF(LogParameter_T) + i);
5193   }
5194 }
5195
5196 void
5197 C1553APage37(
5198     LogParameter_T *    buffer,
5199     size_t              length)
5200 {
5201   int i;
5202   unsigned value;
5203   LogParameter_T *LogParameter;
5204   unsigned ParameterCode;
5205   LogParameter = buffer;
5206
5207   fprintf(StatFile, "\tDrive Counters Page\n");
5208
5209   while ((u_char *)LogParameter < ((unsigned char *)buffer + length)) {
5210     i = LogParameter->ParameterLength;
5211     ParameterCode = V2(LogParameter->ParameterCode);
5212
5213     value = 0;
5214     if (Decode(LogParameter, &value) == 0) {
5215       switch (ParameterCode) {
5216       case 1:
5217         fprintf(StatFile, "%-30s = %u\n",
5218                 "Total loads",
5219                 value);
5220         break;
5221       case 2:
5222         fprintf(StatFile, "%-30s = %u\n",
5223                 "Total write drive errors",
5224                 value);
5225         break;
5226       case 3:
5227         fprintf(StatFile, "%-30s = %u\n",
5228                 "Total read drive errors",
5229                 value);
5230         break;
5231       default:
5232         fprintf(StatFile, "Unknown ParameterCode %02X = %u(%d)\n",
5233                 ParameterCode,
5234                 value, i);
5235         break;
5236       }
5237     }
5238     LogParameter = (LogParameter_T *)((u_char *)LogParameter +  SIZEOF(LogParameter_T) + i);
5239   }
5240 }
5241
5242 void
5243 EXB85058HEPage39(
5244     LogParameter_T *    buffer,
5245     size_t              length)
5246 {
5247   int i;
5248   unsigned value;
5249   LogParameter_T *LogParameter;
5250   unsigned ParameterCode;
5251   LogParameter = buffer;
5252
5253   fprintf(StatFile, "\tData Compression Page\n");
5254
5255   while ((u_char *)LogParameter < ((unsigned char *)buffer + length)) {
5256     i = LogParameter->ParameterLength;
5257     ParameterCode = V2(LogParameter->ParameterCode);
5258
5259     value = 0;
5260     if (Decode(LogParameter, &value) == 0) {
5261       switch (ParameterCode) {
5262       case 5:
5263         fprintf(StatFile, "%-30s = %u\n",
5264                 "KB to Compressor",
5265                 value);
5266         break;
5267       case 7:
5268         fprintf(StatFile, "%-30s = %u\n",
5269                 "KB to tape",
5270                 value);
5271         break;
5272       default:
5273         fprintf(StatFile, "Unknown ParameterCode %02X = %u(%d)\n",
5274                 ParameterCode,
5275                 value, i);
5276         break;
5277       }
5278     }
5279     LogParameter = (LogParameter_T *)((u_char *)LogParameter +  SIZEOF(LogParameter_T) + i);
5280   }
5281 }
5282
5283 void
5284 EXB85058HEPage3c(
5285     LogParameter_T *    buffer,
5286     size_t              length)
5287 {
5288   int i;
5289   unsigned value;
5290   LogParameter_T *LogParameter;
5291   unsigned ParameterCode;
5292   LogParameter = buffer;
5293
5294   fprintf(StatFile, "\tDrive Usage Information Page\n");
5295
5296   while ((u_char *)LogParameter < ((unsigned char *)buffer + length)) {
5297     i = LogParameter->ParameterLength;
5298     ParameterCode = V2(LogParameter->ParameterCode);
5299
5300     value = 0;
5301     if (Decode(LogParameter, &value) == 0) {
5302       switch (ParameterCode) {
5303       case 1:
5304       case 2:
5305       case 3:
5306       case 4:
5307       case 5:
5308         break;
5309       case 6:
5310         fprintf(StatFile, "%-30s = %u\n",
5311                 "Total Load Count",
5312                 value);
5313         break;
5314       case 7:
5315         fprintf(StatFile, "%-30s = %u\n",
5316                 "MinutesSince Last Clean",
5317                 value);
5318         break;
5319       case 8:
5320       case 9:
5321         break;
5322       case 0xa:
5323         fprintf(StatFile, "%-30s = %u\n",
5324                 "Cleaning Count",
5325                 value);
5326         break;
5327       case 0xb:
5328       case 0xc:
5329       case 0xd:
5330       case 0xe:
5331       case 0xf:
5332       case 0x10:
5333         break;
5334       case 0x11:
5335         fprintf(StatFile, "%-30s = %u\n",
5336                 "Time to clean",
5337                 value);
5338         break;
5339       case 0x12:
5340       case 0x13:
5341       case 0x14:
5342         break;
5343       default:
5344         fprintf(StatFile, "Unknown ParameterCode %02X = %u(%d)\n",
5345                 ParameterCode,
5346                 value, i);
5347         break;
5348       }
5349     }
5350     LogParameter = (LogParameter_T *)((u_char *)LogParameter +  SIZEOF(LogParameter_T) + i);
5351   }
5352 }
5353
5354 int
5355 Decode(
5356     LogParameter_T *    LogParameter,
5357     unsigned *          value)
5358 {
5359
5360   DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### START Decode\n");
5361   DebugPrint(DEBUG_INFO, SECTION_SCSI,"Decode Parameter with length %d\n", LogParameter->ParameterLength);
5362
5363   *value = 0;
5364   switch (LogParameter->ParameterLength) {
5365   case 1:
5366     *value = V1((u_char *)LogParameter + SIZEOF(LogParameter_T));
5367     break;
5368   case 2:
5369     *value = V2((u_char *)LogParameter + SIZEOF(LogParameter_T));
5370     break;
5371   case 3:
5372     *value = V3((u_char *)LogParameter + SIZEOF(LogParameter_T));
5373     break;
5374   case 4:
5375     *value = V4((u_char *)LogParameter + SIZEOF(LogParameter_T));
5376     break;
5377   case 5:
5378     *value = V5((u_char *)LogParameter + SIZEOF(LogParameter_T));
5379     break;
5380   case 6:
5381     *value = V6((u_char *)LogParameter + SIZEOF(LogParameter_T));
5382     break;
5383   default:
5384     fprintf(StatFile, "Can't decode ParameterCode %02X size %d\n",
5385             V2(LogParameter->ParameterCode), LogParameter->ParameterLength);
5386     DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP Decode (1)\n");
5387     return(1);
5388     /*NOTREACHED*/
5389   }
5390   DebugPrint(DEBUG_INFO, SECTION_SCSI,"Result = %d\n", *value);
5391   DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP Decode(0)\n");
5392   return(0);
5393 }
5394
5395 void
5396 DumpDev(
5397     OpenFiles_T *       p,
5398     char *              device)
5399 {
5400         if (p != NULL)
5401         {
5402                 printf("%s Devicefd   %d\n", device, p->fd);
5403                 printf("%s Can SCSI   %d\n", device, p->SCSI);
5404                 printf("%s Device     %s\n", device, (p->dev != NULL)? p->dev:"No set");
5405                 printf("%s ConfigName %s\n", device, (p->ConfigName != NULL) ? p->ConfigName:"Not ser");
5406         } else {
5407                 printf("%s Null Pointer ....\n", device);
5408         }
5409         printf("\n");
5410 }
5411
5412 void
5413 ChangerReplay(
5414     char *      option)
5415 {
5416     u_char buffer[1024];
5417     FILE *ip;
5418     int x;
5419     unsigned bufferx;
5420
5421     (void)option;       /* Quiet unused parameter warning */
5422
5423     if ((ip=fopen("/tmp/chg-scsi-trace", "r")) == NULL)
5424       {
5425         exit(1);
5426       }
5427
5428     for (x = 0; x < 1024; x++)
5429       {
5430         if (fscanf(ip, "%2x", &bufferx) == EOF) 
5431           {
5432             break;
5433             /*NOTREACHED*/
5434           }
5435         buffer[x] = (u_char)bufferx;
5436         x++;
5437       }
5438
5439     DecodeModeSense(&buffer[0], 12, "DLT448ElementStatus :", 0, debug_file);
5440     fclose(ip);
5441 }
5442
5443 /*
5444  * Display all Information we can get about the library....
5445  */
5446 void
5447 ChangerStatus(
5448     char *      option,
5449     char *      labelfile,
5450     int         HasBarCode,
5451     char *      changer_file,
5452     char *      changer_dev,
5453     char *      tape_device)
5454 {
5455   extern OpenFiles_T *pDev;
5456   size_t x;
5457   FILE *out;
5458   ExtendedRequestSense_T ExtRequestSense;
5459   MBC_T *pbarcoderes;
5460
5461   ChangerCMD_T *p = (ChangerCMD_T *)&ChangerIO;
5462   pbarcoderes = alloc(SIZEOF(MBC_T));
5463   memset(pbarcoderes, 0, SIZEOF(MBC_T));
5464
5465   if (pModePage == NULL) {
5466          pModePage = alloc(0xff);
5467   }
5468
5469   if ((out = fdopen(1 , "w")) == NULL)
5470     {
5471       printf("Error fdopen stdout\n");
5472       free(pbarcoderes);
5473       return;
5474       /*NOTREACHED*/
5475     }
5476
5477   if (strcmp("types", option) == 0 || strcmp("all", option) == 0)
5478   {
5479     while(p->ident != NULL)
5480       {
5481          printf ("Ident = %s, type = %s\n",p->ident, p->type);
5482          p++;
5483       }
5484     DumpSense();
5485   }
5486
5487   if (strcmp("robot", option) == 0 || strcmp("all", option) == 0)
5488       {
5489         if (ElementStatusValid == 0)
5490           {
5491             if (pDev[INDEX_CHANGER].functions->function_status(pDev[INDEX_CHANGER].fd, 1) != 0)
5492               {
5493                 printf("Can not initialize changer status\n");
5494                 free(pbarcoderes);
5495                 fclose(out);
5496                 return;
5497                 /*NOTREACHED*/
5498               }
5499           }
5500         /*      0123456789012345678901234567890123456789012 */
5501         if (HasBarCode)
5502         {
5503                 printf("Address Type Status From Barcode Label\n");
5504         } else {
5505                 printf("Address Type Status From\n");
5506         }
5507         printf("-------------------------------------------\n");
5508
5509
5510         for ( x = 0; x < MTE; x++)
5511         if (HasBarCode)
5512         {
5513           printf("%07d MTE  %s  %04d %s ",pMTE[x].address,
5514                  (pMTE[x].full ? "Full " :"Empty"),
5515                  pMTE[x].from, pMTE[x].VolTag);
5516
5517           if (pMTE[x].full == 1)
5518             {
5519               pbarcoderes->action = BARCODE_BARCODE;
5520               strncpy(pbarcoderes->data.barcode, pMTE[x].VolTag,
5521                       SIZEOF(pbarcoderes->data.barcode));
5522
5523               if (MapBarCode(labelfile, pbarcoderes) == 0 )
5524                 {
5525                   printf("No mapping\n");
5526                 } else {
5527                   printf("%s \n",pbarcoderes->data.voltag);
5528                 }
5529             } else {
5530               printf("\n");
5531             }
5532         } else {
5533           printf("%07d MTE  %s  %04d \n",pMTE[x].address,
5534                  (pMTE[x].full ? "Full " :"Empty"),
5535                  pMTE[x].from);
5536         }
5537
5538
5539         for ( x = 0; x < STE; x++)
5540         if (HasBarCode)
5541         {
5542           printf("%07d STE  %s  %04d %s ",pSTE[x].address,
5543                  (pSTE[x].full ? "Full ":"Empty"),
5544                  pSTE[x].from, pSTE[x].VolTag);
5545
5546           if (pSTE[x].full == 1)
5547             {
5548               pbarcoderes->action = BARCODE_BARCODE;
5549               strncpy(pbarcoderes->data.barcode, pSTE[x].VolTag,
5550                       SIZEOF(pbarcoderes->data.barcode));
5551
5552               if (MapBarCode(labelfile, pbarcoderes) == 0 )
5553                 {
5554                   printf("No mapping\n");
5555                 } else {
5556                   printf("%s \n",pbarcoderes->data.voltag);
5557                 }
5558             } else {
5559               printf("\n");
5560             }
5561         } else {
5562           printf("%07d STE  %s  %04d %s\n",pSTE[x].address,
5563                  (pSTE[x].full ? "Full ":"Empty"),
5564                  pSTE[x].from, pSTE[x].VolTag);
5565         }
5566
5567
5568         for ( x = 0; x < DTE; x++)
5569         if (HasBarCode)
5570         {
5571           printf("%07d DTE  %s  %04d %s ",pDTE[x].address,
5572                  (pDTE[x].full ? "Full " : "Empty"),
5573                  pDTE[x].from, pDTE[x].VolTag);
5574
5575           if (pDTE[x].full == 1)
5576             {
5577               pbarcoderes->action = BARCODE_BARCODE;
5578               strncpy(pbarcoderes->data.barcode, pDTE[x].VolTag,
5579                       SIZEOF(pbarcoderes->data.barcode));
5580
5581               if (MapBarCode(labelfile, pbarcoderes) == 0 )
5582                 {
5583                   printf("No mapping\n");
5584                 } else {
5585                   printf("%s \n",pbarcoderes->data.voltag);
5586                 }
5587             } else {
5588               printf("\n");
5589             }
5590
5591         } else {
5592           printf("%07d DTE  %s  %04d %s\n",pDTE[x].address,
5593                  (pDTE[x].full ? "Full " : "Empty"),
5594                  pDTE[x].from, pDTE[x].VolTag);
5595         }
5596
5597         for ( x = 0; x < IEE; x++)
5598         if (HasBarCode)
5599         {
5600           printf("%07d IEE  %s  %04d %s ",pIEE[x].address,
5601                  (pIEE[x].full ? "Full " : "Empty"),
5602                  pIEE[x].from, pIEE[x].VolTag);
5603
5604           if (pIEE[x].full == 1)
5605             {
5606               pbarcoderes->action = BARCODE_BARCODE;
5607               strncpy(pbarcoderes->data.barcode, pIEE[x].VolTag,
5608                       SIZEOF(pbarcoderes->data.barcode));
5609
5610               if (MapBarCode(labelfile, pbarcoderes) == 0 )
5611                 {
5612                   printf("No mapping\n");
5613                 } else {
5614                   printf("%s \n",pbarcoderes->data.voltag);
5615                 }
5616             } else {
5617               printf("\n");
5618             }
5619
5620         } else {
5621           printf("%07d IEE  %s  %04d %s\n",pIEE[x].address,
5622                  (pIEE[x].full ? "Full " : "Empty"),
5623                  pIEE[x].from, pIEE[x].VolTag);
5624         }
5625
5626       }
5627
5628   if (strcmp("sense", option) == 0 || strcmp("all", option) == 0)
5629     {
5630       if (pDev[INDEX_CHANGER].SCSI == 1)
5631         {
5632            printf("\nSense Status from robot:\n");
5633            RequestSense(INDEX_CHANGER , &ExtRequestSense, 0);
5634            DecodeExtSense(&ExtRequestSense, "", out);
5635         }
5636
5637       if (pDev[INDEX_TAPE].SCSI == 1)
5638         {
5639           printf("\n");
5640           printf("Sense Status from tape (tapectl):\n");
5641           RequestSense(INDEX_TAPE, &ExtRequestSense, 0);
5642           DecodeExtSense(&ExtRequestSense, "", out);
5643         }
5644
5645       if (pDev[INDEX_TAPECTL].SCSI == 1)
5646         {
5647           printf("\n");
5648           printf("Sense Status from tape (tapectl):\n");
5649           RequestSense(INDEX_TAPECTL, &ExtRequestSense, 0);
5650           DecodeExtSense(&ExtRequestSense, "", out);
5651         }
5652     }
5653
5654     if (strcmp("ModeSenseRobot", option) == 0 || strcmp("all", option) == 0)
5655       {
5656         printf("\n");
5657         if (SCSI_ModeSense(INDEX_CHANGER, pModePage, 0xff, 0x08, 0x3f) == 0)
5658           {
5659             DecodeModeSense(pModePage, 0, "Changer :" , 0, out);
5660           }
5661       }
5662
5663     if (strcmp("ModeSenseTape", option) == 0 || strcmp("all", option) == 0)
5664       {
5665         if (pDev[INDEX_TAPECTL].SCSI == 1)
5666         {
5667           printf("\n");
5668           if (SCSI_ModeSense(INDEX_TAPECTL, pModePage, 0xff, 0x0, 0x3f) == 0)
5669             {
5670               DecodeModeSense(pModePage, 0, "Tape :" , 1, out);
5671             }
5672         }
5673       }
5674
5675     if (strcmp("fd", option) == 0 || strcmp("all", option) == 0)
5676     {
5677       printf("changer_dev  %s\n",changer_dev);
5678       printf("changer_file %s\n", changer_file);
5679       printf("tape_device  %s\n\n", tape_device);
5680       DumpDev(&pDev[INDEX_TAPE], "pTapeDev");
5681       DumpDev(&pDev[INDEX_TAPECTL], "pTapeDevCtl");
5682       DumpDev(&pDev[INDEX_CHANGER], "pChangerDev");
5683     }
5684
5685   if (GenericClean("") == 1)
5686     printf("Tape needs cleaning\n");
5687
5688   free(pbarcoderes);
5689   fclose(out);
5690 }
5691
5692 void
5693 dump_hex(
5694     u_char *    p,
5695     size_t      size,
5696     int         level,
5697     int         section)
5698 {
5699     size_t row_count = 0;
5700     int x;
5701
5702     while (row_count < size)
5703     {
5704         DebugPrint(level, section,"%02X ", (u_char)p[row_count]);
5705         if (((row_count + 1) % 16) == 0)
5706           {
5707             dbprintf(("   "));
5708             for (x = 16; x > 0; x--)
5709               {
5710                 if (isalnum((u_char)p[row_count - x + 1 ]))
5711                   DebugPrint(level, section,"%c",(u_char)p[row_count - x + 1]);
5712                 else
5713                   DebugPrint(level, section,".");
5714               }
5715             DebugPrint(level, section,"\n");
5716           }
5717         row_count++;
5718     }
5719     DebugPrint(level, section,"\n");
5720 }
5721
5722 void
5723 TerminateString(
5724     char *      string,
5725     size_t      length)
5726 {
5727   ssize_t x;
5728
5729   for (x = (ssize_t)length; x >= 0 && !isalnum((int)string[x]); x--)
5730     string[x] = '\0';
5731 }
5732
5733 void
5734 ChgExit(
5735     char *      where,
5736     char *      reason,
5737     int level)
5738 {
5739     (void)level;        /* Quiet unused parameter warning */
5740
5741    dbprintf(("ChgExit in %s, reason %s\n", where, reason));
5742    fprintf(stderr,"%s\n",reason);
5743    exit(2);
5744 }
5745
5746 /* OK here starts a new set of functions.
5747  * Every function is for one SCSI command.
5748  * Prefix is SCSI_ and then the SCSI command name
5749 */
5750
5751 /*
5752  * SCSI_Run is an wrapper arround SCSI_ExecuteCommand
5753  * It seems to be an good idea to check first if the device
5754  * is ready for accepting commands, and if this is true send
5755  * the command
5756  */
5757 int
5758 SCSI_Run(
5759     int                 DeviceFD,
5760     Direction_T         Direction,
5761     CDB_T               CDB,
5762     size_t              CDB_Length,
5763     void *              DataBuffer,
5764     size_t              DataBufferLength,
5765     RequestSense_T *    pRequestSense,
5766     size_t              RequestSenseLength)
5767 {
5768   int ret = 0;
5769   int ok = 0;
5770   int maxtries = 0;
5771   RequestSense_T *pRqS;
5772
5773   /* Basic sanity checks */
5774   assert(CDB_Length <= UCHAR_MAX);
5775   assert(RequestSenseLength <= UCHAR_MAX);
5776
5777   pRqS = (RequestSense_T *)pRequestSense;
5778
5779   DebugPrint(DEBUG_INFO, SECTION_SCSI, "SCSI_Run TestUnitReady\n");
5780   while (!ok && maxtries < MAXTRIES)
5781     {
5782       ret = SCSI_TestUnitReady(DeviceFD, (RequestSense_T *)pRequestSense );
5783       DebugPrint(DEBUG_INFO, SECTION_SCSI, "SCSI_Run TestUnitReady ret %d\n",ret);
5784       switch (ret)
5785         {
5786         case SCSI_OK:
5787           ok=1;
5788           break;
5789         case SCSI_SENSE:
5790           switch (SenseHandler(DeviceFD, 0, pRqS->SenseKey, pRqS->AdditionalSenseCode, pRqS->AdditionalSenseCodeQualifier, pRqS))
5791             {
5792             case SENSE_NO:
5793               DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run (TestUnitReady) SENSE_NO\n");
5794               ok=1;
5795               break;
5796             case SENSE_TAPE_NOT_ONLINE:
5797               DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run (TestUnitReady) SENSE_TAPE_NOT_ONLINE\n");
5798               ok=1;
5799               break;
5800             case SENSE_IGNORE:
5801               DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run (TestUnitReady) SENSE_IGNORE\n");
5802               ok=1;
5803               break;
5804             case SENSE_ABORT:
5805               DebugPrint(DEBUG_ERROR, SECTION_SCSI,"SCSI_Run (TestUnitReady) SENSE_ABORT\n");
5806               return(-1);
5807               /*NOTREACHED*/
5808             case SENSE_RETRY:
5809               DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run (TestUnitReady) SENSE_RETRY\n");
5810               break;
5811             default:
5812               DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run (TestUnitReady) default (SENSE)\n");
5813               ok=1;
5814               break;
5815             }
5816           break;
5817         case SCSI_ERROR:
5818           DebugPrint(DEBUG_ERROR, SECTION_SCSI,"SCSI_Run (TestUnitReady) SCSI_ERROR\n");
5819           return(-1);
5820           /*NOTREACHED*/
5821         case SCSI_BUSY:
5822           DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run (TestUnitReady) SCSI_BUSY\n");
5823           break;
5824         case SCSI_CHECK:
5825           DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run (TestUnitReady) SCSI_CHECK\n");
5826           break;
5827         default:
5828           DebugPrint(DEBUG_ERROR, SECTION_SCSI,"SCSI_Run (TestUnitReady) unknown (%d)\n",ret);
5829           break;
5830         }
5831       if (!ok)
5832       {
5833         sleep(1);
5834         maxtries++;
5835       }
5836     }
5837
5838   DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run TestUnitReady after %d sec:\n",maxtries);
5839
5840   if (ok != 1)
5841     {
5842       DebugPrint(DEBUG_ERROR, SECTION_SCSI,"SCSI_Run Exit %d\n",ret);
5843       return(-1);
5844       /*NOTREACHED*/
5845     }
5846
5847   ok = 0;
5848   maxtries = 0;
5849   while (!ok && maxtries < MAXTRIES)
5850     {
5851       ret = SCSI_ExecuteCommand(DeviceFD,
5852                                 Direction,
5853                                 CDB,
5854                                 CDB_Length,
5855                                 DataBuffer,
5856                                 DataBufferLength,
5857                                 pRequestSense,
5858                                 RequestSenseLength);
5859
5860       DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run Exit %d\n",ret);
5861       switch (ret)
5862         {
5863         case SCSI_OK:
5864           ok=1;
5865           break;
5866         case SCSI_SENSE:
5867           switch (SenseHandler(DeviceFD, 0, pRqS->SenseKey, pRqS->AdditionalSenseCode, pRqS->AdditionalSenseCodeQualifier, pRqS))
5868             {
5869             case SENSE_NO:
5870               DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run SENSE_NO\n");
5871               ok=1;
5872               break;
5873             case SENSE_TAPE_NOT_ONLINE:
5874               DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run SENSE_TAPE_NOT_ONLINE\n");
5875               ok=1;
5876               break;
5877             case SENSE_IGNORE:
5878               DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run SENSE_IGNORE\n");
5879               ok=1;
5880               break;
5881             case SENSE_ABORT:
5882               DebugPrint(DEBUG_ERROR, SECTION_SCSI,"SCSI_Run SENSE_ABORT\n");
5883               return(-1);
5884               /*NOTREACHED*/
5885             case SENSE_RETRY:
5886               DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run SENSE_RETRY\n");
5887               break;
5888             default:
5889               DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run default (SENSE)\n");
5890               ok=1;
5891               break;
5892             }
5893           break;
5894         case SCSI_ERROR:
5895           DebugPrint(DEBUG_ERROR, SECTION_SCSI,"SCSI_Run SCSI_ERROR\n");
5896           return(-1);
5897           /*NOTREACHED*/
5898         case SCSI_BUSY:
5899           DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run SCSI_BUSY\n");
5900           break;
5901         case SCSI_CHECK:
5902           DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run (TestUnitReady) SCSI_CHECK\n");
5903           break;
5904         default:
5905           DebugPrint(DEBUG_ERROR, SECTION_SCSI,"SCSI_Run (TestUnitReady) unknown (%d)\n",ret);
5906           break;
5907         }
5908       maxtries++;
5909       sleep(1);
5910     }
5911
5912   if (ok == 1)
5913     {
5914       return(0);
5915       /*NOTREACHED*/
5916     }
5917   return(-1);
5918 }
5919
5920 /*
5921  * This a vendor specific command !!!!!!
5922  * First seen at AIT :-)
5923  */
5924 int
5925 SCSI_AlignElements(
5926     int         DeviceFD,
5927     size_t      AE_MTE,
5928     size_t      AE_DTE,
5929     size_t      AE_STE)
5930 {
5931   RequestSense_T *pRequestSense;
5932   int retry;
5933   CDB_T CDB;
5934   int ret;
5935   int i;
5936
5937   DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### START SCSI_AlignElements\n");
5938
5939   pRequestSense = alloc(SIZEOF(RequestSense_T));
5940
5941   for (retry = 0; retry < MAX_RETRIES; retry++)
5942     {
5943       CDB[0]  = 0xE5;
5944       CDB[1]  = 0;
5945       MSB2(&CDB[2],AE_MTE);     /* Which MTE to use, default 0 */
5946       MSB2(&CDB[4],AE_DTE);     /* Which DTE to use, no range check !! */
5947       MSB2(&CDB[6],AE_STE);     /* Which STE to use, no range check !! */
5948       CDB[8]  = 0;
5949       CDB[9]  = 0;
5950       CDB[10] = 0;
5951       CDB[11] = 0;
5952
5953       ret = SCSI_Run(DeviceFD, Input, CDB, 12,
5954                                 NULL, 0, pRequestSense, SIZEOF(RequestSense_T));
5955
5956       DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_AlignElements : SCSI_Run = %d\n", ret);
5957       DecodeSense(pRequestSense, "SCSI_AlignElements :",debug_file);
5958
5959       if (ret < 0)
5960         {
5961           DebugPrint(DEBUG_ERROR, SECTION_SCSI,"%s: Request Sense[Inquiry]: %02X",
5962                     "chs", ((u_char *) &pRequestSense)[0]);
5963           for (i = 1; i < (int)sizeof(RequestSense_T); i++)
5964             DebugPrint(DEBUG_ERROR, SECTION_SCSI," %02X", ((u_char *) &pRequestSense)[i]);
5965           DebugPrint(DEBUG_ERROR, SECTION_SCSI,"\n");
5966           return(ret);
5967           /*NOTREACHED*/
5968         }
5969       if ( ret > 0)
5970         {
5971           switch(SenseHandler(DeviceFD, 0 , pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
5972             {
5973             case SENSE_IGNORE:
5974               DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_AlignElements : SENSE_IGNORE\n");
5975               return(0);
5976               /*NOTREACHED*/
5977             case SENSE_RETRY:
5978               DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_AlignElements : SENSE_RETRY no %d\n", retry);
5979               break;
5980             case SENSE_ABORT:
5981               DebugPrint(DEBUG_ERROR, SECTION_SCSI,"SCSI_AlignElements : SENSE_ABORT\n");
5982               return(-1);
5983               /*NOTREACHED*/
5984             case SENSE_TAPE_NOT_UNLOADED:
5985               DebugPrint(DEBUG_ERROR, SECTION_SCSI,"SCSI_AlignElements : Tape still loaded, eject failed\n");
5986               return(-1);
5987               /*NOTREACHED*/
5988             default:
5989               DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_AlignElements : end %d\n", pRequestSense->SenseKey);
5990               return(pRequestSense->SenseKey);
5991               /*NOTREACHED*/
5992             }
5993         }
5994       if (ret == 0)
5995         {
5996           DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_AlignElements : end %d\n", ret);
5997           return(ret);
5998           /*NOTREACHED*/
5999         }
6000     }
6001   DebugPrint(DEBUG_ERROR, SECTION_SCSI,"SCSI_AlignElements :"
6002              "Retries exceeded = %d\n", retry);
6003   return(-1);
6004 }
6005
6006
6007 int
6008 SCSI_Move(
6009     int         DeviceFD,
6010     u_char      chm,
6011     int         from,
6012     int         to)
6013 {
6014   RequestSense_T *pRequestSense;
6015   int retry;
6016   CDB_T CDB;
6017   int ret = -1;
6018   int i;
6019
6020   DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### START SCSI_Move\n");
6021
6022   pRequestSense = alloc(SIZEOF(RequestSense_T));
6023
6024   for (retry = 0; (ret != 0) && (retry < MAX_RETRIES); retry++)
6025     {
6026       CDB[0]  = SC_MOVE_MEDIUM;
6027       CDB[1]  = 0;
6028       CDB[2]  = 0;
6029       CDB[3]  = chm;     /* Address of CHM */
6030       MSB2(&CDB[4],from);
6031       MSB2(&CDB[6],to);
6032       CDB[8]  = 0;
6033       CDB[9]  = 0;
6034       CDB[10] = 0;
6035       CDB[11] = 0;
6036
6037       ret = SCSI_Run(DeviceFD, Input, CDB, 12,
6038                                 NULL, 0, pRequestSense, SIZEOF(RequestSense_T));
6039
6040       DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Move : SCSI_Run = %d\n", ret);
6041       DecodeSense(pRequestSense, "SCSI_Move :",debug_file);
6042
6043       if (ret < 0)
6044         {
6045           DebugPrint(DEBUG_ERROR, SECTION_SCSI,"%s: Request Sense[Inquiry]: %02X",
6046                     "chs", ((u_char *) &pRequestSense)[0]);
6047           for (i = 1; i < (int)sizeof(RequestSense_T); i++)
6048             DebugPrint(DEBUG_ERROR, SECTION_SCSI," %02X", ((u_char *) &pRequestSense)[i]);
6049           DebugPrint(DEBUG_INFO, SECTION_SCSI,"\n");
6050           return(ret);
6051           /*NOTREACHED*/
6052         }
6053       if ( ret > 0)
6054         {
6055           switch(SenseHandler(DeviceFD,  0 , pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
6056             {
6057             case SENSE_IGNORE:
6058               dbprintf(("SCSI_Move : SENSE_IGNORE\n"));
6059               return(0);
6060               /*NOTREACHED*/
6061             case SENSE_RETRY:
6062               dbprintf(("SCSI_Move : SENSE_RETRY no %d\n", retry));
6063               break;
6064             case SENSE_ABORT:
6065               dbprintf(("SCSI_Move : SENSE_ABORT\n"));
6066               return(-1);
6067               /*NOTREACHED*/
6068             case SENSE_TAPE_NOT_UNLOADED:
6069               dbprintf(("SCSI_Move : Tape still loaded, eject failed\n"));
6070               return(-1);
6071               /*NOTREACHED*/
6072             default:
6073               dbprintf(("SCSI_Move : end %d\n", pRequestSense->SenseKey));
6074               return(pRequestSense->SenseKey);
6075               /*NOTREACHED*/
6076             }
6077         }
6078     }
6079   dbprintf(("SCSI_Move : end %d\n", ret));
6080   return(ret);
6081 }
6082
6083 int
6084 SCSI_LoadUnload(
6085     int                 DeviceFD,
6086     RequestSense_T *    pRequestSense,
6087     u_char              byte1,
6088     u_char              load)
6089 {
6090   CDB_T CDB;
6091   int ret;
6092
6093   dbprintf(("##### START SCSI_LoadUnload\n"));
6094
6095   CDB[0] = SC_COM_UNLOAD;
6096   CDB[1] = byte1;
6097   CDB[2] = 0;
6098   CDB[3] = 0;
6099   CDB[4] = load;
6100   CDB[5] = 0;
6101
6102
6103   ret = SCSI_Run(DeviceFD, Input, CDB, 6,
6104                             NULL, 0,
6105                             pRequestSense,
6106                             SIZEOF(RequestSense_T));
6107
6108   if (ret < 0)
6109     {
6110       dbprintf(("SCSI_Unload : failed %d\n", ret));
6111       return(-1);
6112       /*NOTREACHED*/
6113     }
6114
6115   dbprintf(("##### STOP SCSI_LoadUnload\n"));
6116   return(ret);
6117 }
6118
6119 int
6120 SCSI_TestUnitReady(
6121     int                 DeviceFD,
6122     RequestSense_T *    pRequestSense)
6123 {
6124   CDB_T CDB;
6125   int ret;
6126
6127   DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### START SCSI_TestUnitReady\n");
6128
6129   CDB[0] = SC_COM_TEST_UNIT_READY;
6130   CDB[1] = 0;
6131   CDB[2] = 0;
6132   CDB[3] = 0;
6133   CDB[4] = 0;
6134   CDB[5] = 0;
6135
6136   ret = SCSI_ExecuteCommand(DeviceFD, Input, CDB, 6,
6137                       NULL, (size_t)0,
6138                       pRequestSense,
6139                       SIZEOF(RequestSense_T));
6140
6141   /*
6142    * We got an error, so let the calling function handle this
6143    */
6144   if (ret > 0)
6145     {
6146       DebugPrint(DEBUG_INFO, SECTION_SCSI,"###### STOP SCSI_TestUnitReady (1)\n");
6147       return(ret);
6148       /*NOTREACHED*/
6149     }
6150
6151   /*
6152    * OK, no error condition
6153    * If no sense is set, the Unit is ready
6154    */
6155   if (pRequestSense->ErrorCode == 0 && pRequestSense->SenseKey == 0)
6156     {
6157       DebugPrint(DEBUG_INFO, SECTION_SCSI,"###### STOP SCSI_TestUnitReady (1)\n");
6158       return(0);
6159       /*NOTREACHED*/
6160     }
6161
6162   /*
6163    * Some sense is set
6164    */
6165   if (pRequestSense->ErrorCode != 0){
6166     DebugPrint(DEBUG_INFO, SECTION_SCSI,"###### STOP SCSI_TestUnitReady ErrorCode set\n");
6167   }
6168   if (pRequestSense->SenseKey != 0) {
6169     DebugPrint(DEBUG_INFO, SECTION_SCSI,"###### STOP SCSI_TestUnitReady Sense Key set\n");
6170   }
6171   DebugPrint(DEBUG_INFO, SECTION_SCSI,"###### STOP SCSI_TestUnitReady (0)\n");
6172   return(SCSI_SENSE);
6173 }
6174
6175
6176 int
6177 SCSI_ModeSelect(
6178     int         DeviceFD,
6179     u_char *    buffer,
6180     u_char      length,
6181     u_char      save,
6182     u_char      mode,
6183     u_char      lun)
6184 {
6185   CDB_T CDB;
6186   RequestSense_T *pRequestSense;
6187   int ret = -1;
6188   int retry;
6189   u_char *sendbuf;
6190
6191   dbprintf(("##### START SCSI_ModeSelect\n"));
6192
6193   dbprintf(("SCSI_ModeSelect start length = %u:\n", (unsigned)length));
6194   pRequestSense = alloc(SIZEOF(RequestSense_T));
6195   sendbuf = alloc((size_t)length + 4);
6196   memset(sendbuf, 0 , (size_t)length + 4);
6197
6198   memcpy(&sendbuf[4], buffer, (size_t)length);
6199   dump_hex(sendbuf, (size_t)length+4, DEBUG_INFO, SECTION_SCSI);
6200
6201   for (retry = 0; (ret != 0) && (retry < MAX_RETRIES); retry++)
6202     {
6203       memset(pRequestSense, 0, SIZEOF(RequestSense_T));
6204
6205       CDB[0] = SC_COM_MODE_SELECT;
6206       CDB[1] = (u_char)(((lun << 5) & 0xF0) | ((mode << 4) & 0x10) | (save & 1));
6207       CDB[2] = 0;
6208       CDB[3] = 0;
6209       CDB[4] = (u_char)(length + 4);
6210       CDB[5] = 0;
6211       ret = SCSI_Run(DeviceFD, Output, CDB, 6,
6212                                 sendbuf,
6213                                 (size_t)length + 4,
6214                                 pRequestSense,
6215                                 SIZEOF(RequestSense_T));
6216       if (ret < 0)
6217         {
6218           dbprintf(("SCSI_ModeSelect : ret %d\n", ret));
6219           goto done;
6220           /*NOTREACHED*/
6221         }
6222
6223       if ( ret > 0)
6224         {
6225           switch(SenseHandler(DeviceFD, 0, pRequestSense->SenseKey,
6226                               pRequestSense->AdditionalSenseCode,
6227                               pRequestSense->AdditionalSenseCodeQualifier,
6228                               pRequestSense))
6229             {
6230             case SENSE_IGNORE:
6231               dbprintf(("SCSI_ModeSelect : SENSE_IGNORE\n"));
6232               goto done;
6233               /*NOTREACHED*/
6234
6235             case SENSE_RETRY:
6236               dbprintf(("SCSI_ModeSelect : SENSE_RETRY no %d\n", retry));
6237               break;
6238
6239             default:
6240               ret = pRequestSense->SenseKey;
6241               goto end;
6242             }
6243         }
6244     }
6245 end:
6246   dbprintf(("SCSI_ModeSelect end: %d\n", ret));
6247
6248 done:
6249   free(pRequestSense);
6250   free(sendbuf);
6251   return(ret);
6252 }
6253
6254
6255
6256 int
6257 SCSI_ModeSense(
6258     int         DeviceFD,
6259     u_char *    buffer,
6260     u_char      size,
6261     u_char      byte1,
6262     u_char      byte2)
6263 {
6264   CDB_T CDB;
6265   RequestSense_T *pRequestSense;
6266   int ret = 1;
6267   int retry = 1;
6268
6269   DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### START SCSI_ModeSense\n");
6270
6271   DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ModeSense start length = %d:\n", size);
6272   pRequestSense = alloc(SIZEOF(RequestSense_T));
6273
6274   while (ret && retry < MAX_RETRIES)
6275     {
6276       memset(pRequestSense, 0, SIZEOF(RequestSense_T));
6277       memset(buffer, 0, size);
6278
6279       CDB[0] = SC_COM_MODE_SENSE;
6280       CDB[1] = byte1;
6281       CDB[2] = byte2;
6282       CDB[3] = 0;
6283       CDB[4] = size;
6284       CDB[5] = 0;
6285       ret = SCSI_Run(DeviceFD, Input, CDB, 6,
6286                                 buffer,
6287                                 size,
6288                                 pRequestSense,
6289                                 SIZEOF(RequestSense_T));
6290       if (ret < 0)
6291         {
6292           return(ret);
6293           /*NOTREACHED*/
6294         }
6295
6296       if ( ret > 0)
6297         {
6298           switch(SenseHandler(DeviceFD, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
6299             {
6300             case SENSE_IGNORE:
6301               DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ModeSense : SENSE_IGNORE\n");
6302               return(0);
6303               /*NOTREACHED*/
6304             case SENSE_RETRY:
6305               DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ModeSense : SENSE_RETRY no %d\n", retry);
6306               break;
6307             default:
6308               DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ModeSense : end %d\n", pRequestSense->SenseKey);
6309               return(pRequestSense->SenseKey);
6310               /*NOTREACHED*/
6311             }
6312         }
6313       retry++;
6314     }
6315
6316   DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ModeSense end: %d\n", ret);
6317   return(ret);
6318 }
6319
6320 int
6321 SCSI_Inquiry(
6322     int                 DeviceFD,
6323     SCSIInquiry_T *     buffer,
6324     size_t              size)
6325 {
6326   CDB_T CDB;
6327   RequestSense_T *pRequestSense;
6328   int i;
6329   int ret = -1;
6330   int retry = 1;
6331
6332   assert(size <= UCHAR_MAX);
6333
6334   DebugPrint(DEBUG_INFO, SECTION_SCSI, "##### START SCSI_Inquiry\n");
6335
6336   DebugPrint(DEBUG_INFO, SECTION_SCSI, "SCSI_Inquiry start length = %d:\n", size);
6337
6338   pRequestSense = alloc((size_t)size);
6339
6340   while (retry > 0 && retry < MAX_RETRIES)
6341     {
6342       memset(buffer, 0, size);
6343       CDB[0] = SC_COM_INQUIRY;
6344       CDB[1] = 0;
6345       CDB[2] = 0;
6346       CDB[3] = 0;
6347       CDB[4] = (u_char)size;
6348       CDB[5] = 0;
6349
6350       ret = SCSI_ExecuteCommand(DeviceFD, Input, CDB, 6,
6351                                 buffer,
6352                                 size,
6353                                 pRequestSense,
6354                                 SIZEOF(RequestSense_T));
6355       if (ret < 0)
6356         {
6357           DebugPrint(DEBUG_ERROR, SECTION_SCSI,"%s: Request Sense[Inquiry]: %02X",
6358                     "chs", ((u_char *) pRequestSense)[0]);
6359           for (i = 1; i < (int)sizeof(RequestSense_T); i++)
6360             DebugPrint(DEBUG_ERROR, SECTION_SCSI," %02X", ((u_char *) pRequestSense)[i]);
6361           DebugPrint(DEBUG_ERROR, SECTION_SCSI, "\n");
6362           DebugPrint(DEBUG_ERROR, SECTION_SCSI, "Inquiry end: %d\n", ret);
6363           return(ret);
6364           /*NOTRACHED*/
6365         }
6366       if ( ret > 0)
6367         {
6368           switch(SenseHandler(DeviceFD, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
6369             {
6370             case SENSE_IGNORE:
6371               DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Inquiry : SENSE_IGNORE\n");
6372               return(0);
6373               /*NOTREACHED*/
6374             case SENSE_RETRY:
6375               DebugPrint(DEBUG_INFO, SECTION_SCSI, "SCSI_Inquiry : SENSE_RETRY no %d\n", retry);
6376               break;
6377             default:
6378               DebugPrint(DEBUG_ERROR, SECTION_SCSI, "SCSI_Inquiry : end %d\n", pRequestSense->SenseKey);
6379               return(pRequestSense->SenseKey);
6380               /*NOTREACHED*/
6381             }
6382         }
6383       retry++;
6384       if (ret == 0)
6385         {
6386           dump_hex((u_char *)buffer, size, DEBUG_INFO, SECTION_SCSI);
6387           DebugPrint(DEBUG_INFO, SECTION_SCSI, "SCSI_Inquiry : end %d\n", ret);
6388           return(ret);
6389           /*NOTRACHED*/
6390         }
6391     }
6392
6393   DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Inquiry end: %d\n", ret);
6394   return(ret);
6395 }
6396
6397 /*
6398  * Read the Element Status. If DescriptorSize  != 0 then
6399  * allocate DescriptorSize * NoOfElements for the result from the
6400  * Read Element Status command.
6401  * If DescriptorSize == 0 than try to figure out how much space is needed
6402  * by
6403  * 1. do an read with an allocation size of 8
6404  * 2. from the result take the 'Byte Count of Descriptor Available'
6405  * 3. do again an Read Element Status with the result from 2.
6406  *
6407  */
6408 int
6409 SCSI_ReadElementStatus(
6410     int         DeviceFD,
6411     u_char      type,
6412     u_char      lun,
6413     u_char      VolTag,
6414     int         StartAddress,
6415     size_t      NoOfElements,
6416     size_t      DescriptorSize,
6417     u_char **   data)
6418 {
6419   CDB_T CDB;
6420   size_t DataBufferLength;
6421   ElementStatusData_T *ElementStatusData;
6422   RequestSense_T *pRequestSense;
6423   int retry = 1;
6424   int ret = -1;
6425
6426   DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### START SCSI_ReadElementStatus\n");
6427
6428   pRequestSense = alloc(SIZEOF(RequestSense_T));
6429
6430   /*
6431    * How many elements, if <= 0 than exit with an fatal error
6432    */
6433   if (NoOfElements == 0)
6434     {
6435       ChgExit("SCSI_ReadElementStatus","No of Elements passed are le 0",FATAL);
6436       /*NOTREACHED*/
6437     }
6438
6439   VolTag = (u_char)((VolTag << 4) & 0x10);
6440   type = (u_char)(type & 0xf);
6441   lun = (u_char)((lun << 5) & 0xe0);
6442
6443   /* if  DescriptorSize == 0
6444    * try to get the allocation length for the second call
6445    */
6446   if (DescriptorSize == 0)
6447     {
6448       *data = newalloc(*data, 8);
6449       memset(*data, 0, 8);
6450
6451       while (retry > 0 && retry < MAX_RETRIES)
6452         {
6453           memset(pRequestSense, 0, SIZEOF(RequestSense_T) );
6454
6455           CDB[0] = SC_COM_RES;          /* READ ELEMENT STATUS */
6456           CDB[1] = (u_char)(VolTag | type | lun); /* Element Type Code , VolTag, LUN */
6457           MSB2(&CDB[2], StartAddress);  /* Starting Element Address */
6458           MSB2(&CDB[4], NoOfElements);  /* Number Of Element */
6459           CDB[6] = 0;                             /* Reserved */
6460           MSB3(&CDB[7],8);                   /* Allocation Length */
6461           CDB[10] = 0;                           /* Reserved */
6462           CDB[11] = 0;                           /* Control */
6463
6464           ret = SCSI_Run(DeviceFD, Input, CDB, 12,
6465                          *data, 8,
6466                          pRequestSense, SIZEOF(RequestSense_T));
6467
6468           DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ReadElementStatus : (1) SCSI_Run %d\n", ret);
6469           if (ret < 0)
6470             {
6471               DecodeSense(pRequestSense, "SCSI_ReadElementStatus :",debug_file);
6472               DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP SCSI_ReadElementStatus (%d)\n",ret);
6473               return(ret);
6474               /*NOTRACHED*/
6475             }
6476           if ( ret > 0)
6477             {
6478               switch(SenseHandler(DeviceFD, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
6479                 {
6480                 case SENSE_IGNORE:
6481                   DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ModeSense : SENSE_IGNORE\n");
6482                   retry = 0;
6483                   break;
6484                 case SENSE_RETRY:
6485                   DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ModeSense : SENSE_RETRY no %d\n", retry);
6486                   sleep(2);
6487                   break;
6488                 default:
6489                   DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ModeSense : end %d\n", pRequestSense->SenseKey);
6490                   return(pRequestSense->SenseKey);
6491                   /*NOTREACHED*/
6492                 }
6493             }
6494           retry++;
6495           if (ret == 0)
6496             {
6497               retry=0;
6498             }
6499         }
6500       if (retry > 0)
6501         {
6502           DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP SCSI_ReadElementStatus (%d)\n",ret);
6503           return(ret);
6504           /*NOTRACHED*/
6505         }
6506
6507       ElementStatusData = (ElementStatusData_T *)*data;
6508       DataBufferLength = V3(ElementStatusData->count);
6509
6510       DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ReadElementStatus: DataBufferLength %X, ret %d\n",DataBufferLength, ret);
6511
6512       dump_hex(*data, 8, DEBUG_INFO, SECTION_ELEMENT);
6513     } else { /* DescriptorSize != 0 */
6514       DataBufferLength = NoOfElements * DescriptorSize;
6515     }
6516
6517   DataBufferLength = DataBufferLength + 8;
6518   *data = newalloc(*data, DataBufferLength);
6519   memset(*data, 0, DataBufferLength);
6520   retry = 1;
6521
6522   while (retry > 0 && retry < MAX_RETRIES)
6523     {
6524       memset(pRequestSense, 0, SIZEOF(RequestSense_T) );
6525
6526       CDB[0] = SC_COM_RES;           /* READ ELEMENT STATUS */
6527       CDB[1] = (u_char)(VolTag | type | lun);  /* Element Type Code, VolTag, LUN */
6528       MSB2(&CDB[2], StartAddress);   /* Starting Element Address */
6529       MSB2(&CDB[4], NoOfElements);   /* Number Of Element */
6530       CDB[6] = 0;                              /* Reserved */
6531       MSB3(&CDB[7],DataBufferLength);  /* Allocation Length */
6532       CDB[10] = 0;                                 /* Reserved */
6533       CDB[11] = 0;                                 /* Control */
6534
6535       ret = SCSI_Run(DeviceFD, Input, CDB, 12,
6536                                 *data, DataBufferLength,
6537                                 pRequestSense, SIZEOF(RequestSense_T));
6538
6539
6540       DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ReadElementStatus : (2) SCSI_Run %d\n", ret);
6541       if (ret < 0)
6542         {
6543           DecodeSense(pRequestSense, "SCSI_ReadElementStatus :",debug_file);
6544           DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP SCSI_ReadElementStatus (%d)\n",ret);
6545           return(ret);
6546           /*NOTRACHED*/
6547         }
6548       if ( ret > 0)
6549         {
6550           switch(SenseHandler(DeviceFD, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
6551             {
6552             case SENSE_IGNORE:
6553               DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ModeSense : SENSE_IGNORE\n");
6554               retry = 0;
6555               break;
6556             case SENSE_RETRY:
6557               DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ModeSense : SENSE_RETRY no %d\n", retry);
6558               sleep(2);
6559               break;
6560             default:
6561               DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ModeSense : end %d\n", pRequestSense->SenseKey);
6562               return(pRequestSense->SenseKey);
6563               /*NOTREACHED*/
6564             }
6565         }
6566       retry++;
6567       if (ret == 0)
6568         {
6569           retry=0;
6570         }
6571     }
6572
6573   if (retry > 0)
6574     {
6575       DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP SCSI_ReadElementStatus (%d)\n",ret);
6576       return(ret);
6577       /*NOTRACHED*/
6578     }
6579
6580   dump_hex(*data, DataBufferLength, DEBUG_INFO, SECTION_SCSI);
6581   DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP SCSI_ReadElementStatus (%d)\n",ret);
6582   return(ret);
6583 }
6584
6585 printf_arglist_function2(void DebugPrint, int, level, int, section, char *, fmt)
6586 {
6587   va_list argp;
6588   char buf[1024];
6589   int dlevel;
6590   int dsection = -1;
6591   time_t ti = time(NULL);
6592
6593   if (changer->debuglevel)
6594     {
6595       if (sscanf(changer->debuglevel,"%d:%d", &dlevel, &dsection) != 2) {
6596         dbprintf(("Parse error: line is '%s' expected [0-9]*:[0-9]*\n",
6597                   changer->debuglevel));
6598         dlevel=1;
6599         dsection=1;
6600       }
6601     } else {
6602       dlevel=1;
6603       dsection=1;
6604     }
6605
6606   arglist_start(argp, fmt);
6607   vsnprintf(buf, SIZEOF(buf), fmt, argp);
6608   if (dlevel >= level)
6609     {
6610       if (section == dsection || dsection == 0)
6611         {
6612           if (index(buf, '\n') != NULL && strlen(buf) > 1)
6613           {
6614              dbprintf(("%ld:%s", (long)ti, buf));
6615           } else {
6616              dbprintf(("%s", buf));
6617           }
6618         }
6619     }
6620   arglist_end(argp);
6621 }