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