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