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