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