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