1 static char rcsid[] = "$Id: scsi-changer-driver.c,v 1.52 2006/07/21 00:25:50 martinea Exp $";
3 * Interface to control a tape robot/library connected to the SCSI bus
5 * Copyright (c) Thomas Hepper th@ant.han.de
12 #include "scsi-defs.h"
16 extern FILE *debug_file;
17 extern changer_t *changer; /* Needed for the infos about emubarcode and labelfile */
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);
31 int SenseHandler(int fd, u_char flag, u_char SenseKey, u_char AdditionalSenseCode, u_char AdditionalSenseCodeQualifier, RequestSense_T *buffer);
33 int SCSI_AlignElements(int DeviceFD, size_t MTE, size_t DTE, size_t STE);
37 int DoNothing2(int, int);
38 int DoNothing3(int, int, int);
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);
54 int GenericSearch(void);
55 void Inventory(char *labelfile, int drive, int eject, int start, int stop, int clean);
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 *);
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);
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);
80 int SCSI_Run(int DeviceFD,
81 Direction_T Direction,
85 size_t DataBufferLength,
86 RequestSense_T *pRequestSense,
87 size_t RequestSenseLength);
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,
100 int SCSI_ReadElementStatus(int DeviceFD,
106 size_t DescriptorSize,
110 static int barcode; /* cache the result from the BarCode function */
112 SC_COM_T SCSICommand[] = {
124 "INITIALIZE ELEMENT STATUS"},
151 "READ ELEMENT STATUS"},
155 ChangerCMD_T ChangerIO[] = {
157 "Generic driver changer [generic_changer]",
159 GenericElementStatus,
167 GenericSenseHandler},
170 "HP Auto Loader [C1553A]",
172 GenericElementStatus,
180 GenericSenseHandler},
181 /* Exabyte Devices */
183 "Exabyte Robot [EXB-10e]",
185 GenericElementStatus,
193 GenericSenseHandler},
195 "Exabyte Robot [EXB-120]",
197 GenericElementStatus,
205 GenericSenseHandler},
207 "Exabyte Robot [EXB-210]",
209 GenericElementStatus,
217 GenericSenseHandler},
219 "Exabyte Tape [EXB-85058HE-0000]",
229 GenericSenseHandler},
230 /* Tandberg Devices */
232 "Tandberg Robot (TDS 1420)",
234 GenericElementStatus,
242 GenericSenseHandler},
245 "ADIC VLS DLT Library [VLS DLT]",
247 GenericElementStatus,
255 GenericSenseHandler},
257 "ADIC VLS DLT Library [VLS SDX]",
267 GenericSenseHandler},
269 "ADIC FastStor DLT Library [FastStor DLT]",
279 GenericSenseHandler},
281 "ADIC DLT 448 [Scalar DLT 448]",
291 GenericSenseHandler},
292 /* Sepctra Logic Devices */
294 "Spectra Logic TreeFrog[215]",
296 GenericElementStatus,
304 GenericSenseHandler},
307 "Breece Hill Quad 7",
309 GenericElementStatus,
317 GenericSenseHandler},
318 /* Quantum Devices */
322 GenericElementStatus,
330 GenericSenseHandler},
332 * And now the tape devices
334 /* The generic handler if nothing matches */
336 "Generic driver tape [generic_tape]",
338 GenericElementStatus,
346 GenericSenseHandler},
348 "DLT Tape [DLT8000]",
358 GenericSenseHandler},
360 "DLT Tape [DLT7000]",
370 GenericSenseHandler},
372 "DLT Tape [DLT4000]",
382 GenericSenseHandler},
386 GenericElementStatus,
394 GenericSenseHandler},
395 {NULL, NULL, NULL,NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}
399 LogPageDecode_T DecodePages[] = {
402 WriteErrorCountersPage},
405 ReadErrorCountersPage},
414 WriteErrorCountersPage},
417 ReadErrorCountersPage},
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 */
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;
439 * New way, every element type has its on array
440 * which is dynamic allocated by the ElementStatus function,
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 */
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 */
456 * First all functions which are called from extern
461 * Print the scsi-changer-driver version
465 ChangerDriverVersion(void)
467 DebugPrint(DEBUG_ERROR, SECTION_INFO, "scsi-changer-driver: %s\n",rcsid);
472 * Try to generate an template which can be used as an example for the config file
478 extern OpenFiles_T *pDev;
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"));
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"
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"
497 "havebarcode 0 # Set this to 1 if you have a library with a\n"
498 " # barcode reader\n"
501 "debuglevel 0:0 # For debuging, see the docs /docs/TAPE-CHANGER\n"
504 "eject ??? # set this to 1 if your drive needs an eject before move\n"
507 "sleep ??? # How long to wait after an eject command before moving\n"
511 for (count = 0; count < CHG_MAXDEV ; count++)
515 if (pDev[count].inquiry != NULL && pDev[count].inquiry->type == TYPE_CHANGER)
517 g_printf(_("changerdev %s # This is the device to communicate with the robot\n"), pDev[count].dev);
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
528 if (count < CHG_MAXDEV)
530 pDev[count].functions->function_status(count, 1);
532 g_printf(_("changerdev ??? # Ups nothing found. Please check the docs\n"));
538 " # Here now comes the config for the first tape\n"));
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"
545 "cleancart ??? # The slot where the cleaning tape is located\n"
546 " # remove it if you have no cleaning tape\n"
549 "drivenum 0 # Which tape drive to use if there are more than one drive\n"
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"
558 * OK now lets see if we have an direct SCSI channel
560 * If not thats not a problem
562 for (count = 0; count < CHG_MAXDEV; count++)
566 if (pDev[count].inquiry != NULL && pDev[count].inquiry->type == TYPE_TAPE)
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);
582 "startuse 0 # Which is the first slot to use\n"
585 "enduse %zu # Which is the last slot to use.\n"), STE);
588 "startuse ??? # Which is the first slot to use\n"
591 "enduse ??? # Which is the last slot to use.\n"));
594 " # Decrement this value by 1 if you have a\n"
595 " # cleaning tape in the last slot\n"
598 if ((cwd = getcwd(NULL, 0)) == NULL) {
599 cwd = _("<unknown>");
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);
612 * Try to create a list of tapes and labels which are in the current
613 * magazin. The drive must be empty !!
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
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
640 extern OpenFiles_T *pDev;
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 */
645 (void)start; /* Quiet unused parameter warning */
646 (void)stop; /* Quiet unused parameter warning */
648 DebugPrint(DEBUG_INFO,SECTION_MAP_BARCODE, _("##### START Inventory\n"));
649 pbarcoderes = alloc(SIZEOF(MBC_T));
650 memset(pbarcoderes, 0 , SIZEOF(MBC_T));
654 DebugPrint(DEBUG_INFO,SECTION_MAP_BARCODE, _("##### STOP inv_done -> %d Inventory\n"),inv_done);
660 barcode = BarCode(INDEX_CHANGER);
662 pbarcoderes->action = RESET_VALID;
664 MapBarCode(labelfile,pbarcoderes);
667 * Check if an tape is loaded, if yes unload it
668 * and do an INIT ELEMENT STATUS
671 if (pDTE[0].status == 'F')
675 (void)eject_tape("", eject);
677 (void)unload(INDEX_TAPE, 0, 0);
680 GenericResetStatus(INDEX_CHANGER);
682 for (x = 0; x < STE; x++)
684 if (x == (size_t)clean)
690 * Load the tape, on error try the next
691 * error could be an empty slot for example
693 if (load(INDEX_CHANGER, drive, x ) != 0)
695 DebugPrint(DEBUG_ERROR,SECTION_MAP_BARCODE, _("Load drive(%d) from(%d) failed\n"), drive, x);
700 * Wait until the tape is ready
702 Tape_Ready(INDEX_TAPECTL, 60);
704 SCSI_CloseDevice(INDEX_TAPE);
706 if ((chgscsi_result = (char *)tape_rdlabel(pDev[INDEX_TAPE].dev, &chgscsi_datestamp, &chgscsi_label)) == NULL)
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)
716 strncpy(pbarcoderes->data.barcode, pDTE[drive].VolTag,
717 SIZEOF(pbarcoderes->data.barcode));
718 MapBarCode(labelfile, pbarcoderes);
720 MapBarCode(labelfile, pbarcoderes);
723 DebugPrint(DEBUG_ERROR,SECTION_MAP_BARCODE, _("Read label failed\n"));
728 (void)eject_tape("", eject);
731 (void)unload(INDEX_TAPE, drive, x);
733 DebugPrint(DEBUG_INFO,SECTION_MAP_BARCODE, _("##### STOP Inventory\n"));
738 * Check if the slot ist empty
739 * slot -> slot number to check
746 extern OpenFiles_T *pDev;
747 DebugPrint(DEBUG_INFO,SECTION_TAPE,_("##### START isempty\n"));
749 if (ElementStatusValid == 0)
751 if ( pDev[fd].functions->function_status(fd, 1) != 0)
753 DebugPrint(DEBUG_ERROR,SECTION_TAPE,_("##### STOP isempty [-1]\n"));
759 if (pSTE[slot].status == 'E')
761 DebugPrint(DEBUG_INFO,SECTION_TAPE,_("##### STOP isempty [1]\n"));
765 DebugPrint(DEBUG_INFO,SECTION_TAPE,_("##### STOP isempty [0]\n"));
773 extern OpenFiles_T *pDev;
774 /* Return 1 if cleaning is needed */
777 DebugPrint(DEBUG_INFO,SECTION_TAPE,_("##### START get_clean_state\n"));
779 if (pDev[INDEX_TAPECTL].SCSI == 0)
781 DebugPrint(DEBUG_ERROR,SECTION_TAPE,_("##### STOP get_clean_state [-1]\n"));
785 ret=pDev[INDEX_TAPECTL].functions->function_clean(tapedev);
786 DebugPrint(DEBUG_INFO,SECTION_TAPE,_("##### STOP get_clean_state [%d]\n"), ret);
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
796 /* This function ejects the tape from the drive */
803 extern OpenFiles_T *pDev;
806 DebugPrint(DEBUG_INFO,SECTION_TAPE,_("##### START eject_tape %s\n"),tapedev);
807 if (pDev[INDEX_TAPECTL].functions == NULL)
811 * Try to read the label
813 if (pDev[INDEX_TAPE].avail == 1 && (changer->emubarcode == 1 || BarCode(INDEX_CHANGER)))
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);
820 DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### eject_tape rewind2\n");
821 pDev[INDEX_TAPE].functions->function_rewind(INDEX_TAPE);
824 if (pDev[INDEX_TAPE].devopen == 1)
826 DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### eject_tape close\n");
827 SCSI_CloseDevice(INDEX_TAPE);
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);
834 if (pDev[INDEX_TAPECTL].SCSI == 1 && pDev[INDEX_TAPECTL].avail == 1 && type == 1)
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);
843 if (pDev[INDEX_TAPE].avail == 1)
845 ret=Tape_Ioctl(INDEX_TAPE, IOCTL_EJECT);
846 DebugPrint(DEBUG_INFO,SECTION_TAPE,_("##### STOP (ioctl)eject_tape [%d]\n"), ret);
851 DebugPrint(DEBUG_INFO,SECTION_TAPE,_("##### STOP eject_tape [-1]\n"));
856 /* Find an empty slot, starting at start, ending at start+count */
863 extern OpenFiles_T *pDev;
867 DebugPrint(DEBUG_INFO,SECTION_ELEMENT,_("###### START find_empty\n"));
869 if (ElementStatusValid == 0)
871 if ( pDev[fd].functions->function_status(fd , 1) != 0)
873 DebugPrint(DEBUG_ERROR,SECTION_ELEMENT,
874 _("###### END find_empty [-1]\n"));
892 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,
893 _("start at %zu, end at %zu\n"),
897 for (x = start; x < end; x++)
899 if (pSTE[x].status == 'E')
901 DebugPrint(DEBUG_INFO,SECTION_ELEMENT,
902 _("###### END find_empty [%lu]\n"), x);
907 DebugPrint(DEBUG_ERROR,SECTION_ELEMENT,_("###### END find_empty [-1]\n"));
912 * See if the tape is loaded based on the information we
913 * got back from the ReadElementStatus
915 * -1 -> Error (Fatal)
916 * 0 -> drive is empty
917 * 1 -> drive is loaded
924 extern OpenFiles_T *pDev;
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);
931 if (ElementStatusValid == 0)
933 if (pDev[INDEX_CHANGER].functions->function_status(INDEX_CHANGER, 1) != 0)
935 DebugPrint(DEBUG_ERROR,SECTION_TAPE,_("Fatal error\n"));
941 if (pDTE[drivenum].status == 'E') {
942 DebugPrint(DEBUG_INFO,SECTION_TAPE,_("###### STOP drive_loaded (empty)\n"));
946 DebugPrint(DEBUG_INFO,SECTION_TAPE,_("###### STOP drive_loaded (not empty)\n"));
952 * unload the specified drive into the specified slot
956 * Check if the MTE is empty
964 extern OpenFiles_T *pDev;
965 extern int do_inventory;
968 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("###### START unload\n"));
969 DebugPrint(DEBUG_INFO, SECTION_TAPE,
970 _(" unload : fd %d, slot %d, drive %d \n"),
972 pbarcoderes = alloc(SIZEOF(MBC_T));
973 memset(pbarcoderes, 0, SIZEOF(MBC_T));
976 * If the Element Status is not valid try to
979 if (ElementStatusValid == 0)
981 if (pDev[INDEX_CHANGER].functions->function_status(INDEX_CHANGER , 1) != 0)
983 DebugPrint(DEBUG_ERROR, SECTION_TAPE,_("Element Status not valid, reset failed\n"));
984 DebugPrint(DEBUG_ERROR, SECTION_TAPE,_("##### STOP unload (-1)\n"));
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);
996 * Unloading an empty tape unit makes no sense
997 * so return with an error
999 if (pDTE[drive].status == 'E')
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"));
1009 * If the destination slot is full
1010 * try to find an enpty slot
1012 if (pSTE[slot].status == 'F')
1014 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("unload : Slot %d address %d is full\n"), drive, pSTE[slot].address);
1015 if ( ElementStatusValid == 0)
1017 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("unload: Element Status not valid, can't find an empty slot\n"));
1023 slot = find_empty(fd, 0, 0);
1026 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("unload: No Empty slot found\n"));
1031 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("unload : found empty one, try to unload to slot %d\n"), slot);
1037 * If eject is not set we must read the label info
1040 if (changer->eject == 0)
1042 if (pDev[INDEX_TAPE].avail == 1 && (changer->emubarcode == 1 || BarCode(INDEX_CHANGER)))
1045 if (pDev[INDEX_TAPECTL].SCSI == 1 && pDev[INDEX_TAPECTL].avail) {
1046 pDev[INDEX_TAPECTL].functions->function_rewind(INDEX_TAPECTL);
1048 pDev[INDEX_TAPE].functions->function_rewind(INDEX_TAPE);
1051 if (pDev[INDEX_TAPE].devopen == 1)
1053 SCSI_CloseDevice(INDEX_TAPE);
1056 chgscsi_result = (char *)tape_rdlabel(pDev[INDEX_TAPE].dev, &chgscsi_datestamp, &chgscsi_label);
1061 * Do the unload/move
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"));
1075 if (pDev[INDEX_CHANGER].functions->function_status(INDEX_CHANGER , 1) != 0)
1077 DebugPrint(DEBUG_ERROR, SECTION_TAPE,_("##### STOP unload (-1 update status failed)\n"));
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
1088 if (chgscsi_result == NULL && chgscsi_label != NULL && changer->labelfile != NULL)
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
1095 if (BarCode(INDEX_CHANGER) == 0 && changer->emubarcode == 1)
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
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;
1112 if ( MapBarCode(changer->labelfile, pbarcoderes) == 0) /* Nothing known about this, do an Inventory */
1116 if (slot != pbarcoderes->data.slot)
1118 DebugPrint(DEBUG_ERROR, SECTION_TAPE,_("Slot DB out of sync, slot %d != map %d"),slot, pbarcoderes->data.slot);
1125 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("##### STOP unload(0)\n"));
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
1138 * return -> 0 = success
1147 char *result = NULL; /* Needed for the result of tape_rdlabel */
1149 extern OpenFiles_T *pDev;
1150 extern int do_inventory;
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));
1158 if (ElementStatusValid == 0)
1160 if (pDev[fd].functions->function_status(fd, 1) != 0)
1162 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,_("##### STOP load (-1)\n"));
1163 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,_("##### STOP load (-1 update status failed)\n"));
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
1176 if ((size_t)slot >= STE)
1178 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,_("load : slot %d ge STE %d\n"),slot, STE);
1179 ChgExit("load", _("slot >= STE"), FATAL);
1184 * And the same for the tape drives
1186 if (drive >= (int)DTE)
1188 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,_("load : drive %d ge DTE %d\n"),drive, DTE);
1189 ChgExit("load", _("drive >= DTE"), FATAL);
1193 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("load : load drive %d[%d] slot %d[%d]\n"),drive,
1194 pDTE[drive].address,
1196 pSTE[slot].address);
1198 if (pDTE[drive].status == 'F')
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"));
1207 if (pSTE[slot].status == 'E')
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"));
1216 ret = pDev[fd].functions->function_move(fd, pSTE[slot].address, pDTE[drive].address);
1221 if (pDev[fd].functions->function_status(fd, 1) != 0)
1223 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,_("##### STOP load (-1 update status failed)\n"));
1230 * Try to read the label
1231 * and update the label/slot database
1233 if (pDev[INDEX_TAPE].avail == 1 && (changer->emubarcode == 1 || BarCode(INDEX_CHANGER)))
1236 if (pDev[INDEX_TAPECTL].SCSI == 1 && pDev[INDEX_TAPECTL].avail) {
1237 pDev[INDEX_TAPECTL].functions->function_rewind(INDEX_TAPECTL);
1239 pDev[INDEX_TAPE].functions->function_rewind(INDEX_TAPE);
1242 if (pDev[INDEX_TAPE].devopen == 1)
1244 SCSI_CloseDevice(INDEX_TAPE);
1247 result = (char *)tape_rdlabel(pDev[INDEX_TAPE].dev, &chgscsi_datestamp, &chgscsi_label);
1251 * Did we get an error from tape_rdlabel
1252 * if no update the vol/label mapping
1254 if (result == NULL && changer->labelfile != NULL && chgscsi_label != NULL )
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
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;
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
1274 if (BarCode(INDEX_CHANGER) == 1 && changer->emubarcode == 0)
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);
1284 if (BarCode(INDEX_CHANGER) == 0 && changer->emubarcode == 1)
1286 pbarcoderes->action = FIND_SLOT;
1287 if (MapBarCode(changer->labelfile, pbarcoderes) == 0) /* Nothing found, do an inventory */
1290 } else { /* We got something, is it correct ? */
1291 if (slot != pbarcoderes->data.slot && do_inventory == 0)
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);
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);
1305 if (BarCode(INDEX_CHANGER) == 1 && changer->emubarcode == 1)
1307 ChgExit("Load", _("BarCode == 1 and emubarcode == 1"), FATAL);
1311 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("##### STOP load (%d)\n"),ret);
1316 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("##### STOP load (%d)\n"),ret);
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
1330 extern OpenFiles_T *pDev;
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);
1335 if (ElementStatusValid == 0)
1337 pDev[fd].functions->function_status(fd, 1);
1339 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,
1340 _("##### STOP get_slot_count (%zu)\n"), STE);
1341 return((ssize_t)STE);
1343 * return the number of slots in the robot
1350 * retreive the number of data-transfer devices /Tape drives)
1351 * fd -> pointer to the internal devie structure pDev
1352 * return -> -1 on failure
1359 extern OpenFiles_T *pDev;
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);
1364 if (ElementStatusValid == 0)
1366 if ( pDev[fd].functions->function_status(fd, 1) != 0)
1368 DebugPrint(DEBUG_ERROR, SECTION_SCSI, _("Error getting drive count\n"));
1369 DebugPrint(DEBUG_ERROR, SECTION_SCSI, _("##### STOP get_drive_count (-1)\n"));
1374 DebugPrint(DEBUG_INFO, SECTION_SCSI,
1375 _("###### STOP get_drive_count (%zu drives)\n"), DTE);
1376 return((ssize_t)DTE);
1380 * Now the internal functions
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
1395 extern OpenFiles_T *pDev;
1397 ChangerCMD_T *p = (ChangerCMD_T *)&ChangerIO;
1404 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("##### START OpenDevice\n"));
1405 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("OpenDevice : %s\n"), DeviceName);
1407 pDev[ip].ConfigName = strdup(ConfigName);
1408 pDev[ip].dev = strdup(DeviceName);
1410 if (SCSI_OpenDevice(ip) != 0 )
1412 if (ident != NULL) /* Override by config */
1414 while(p->ident != NULL)
1416 if (strcmp(ident, p->ident) == 0)
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"));
1427 ChgExit("OpenDevice", _("ident not found"), FATAL);
1430 while(p->ident != NULL)
1432 if (strcmp(pDev[ip].ident, p->ident) == 0)
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"));
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)
1451 if (strcmp(tmpstr, p->ident) == 0)
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"));
1461 } else { /* Something failed, lets see what */
1462 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("##### STOP OpenDevice failed\n"));
1464 pDev[ip].functions = NULL;
1465 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("##### STOP OpenDevice (nothing found) !!\n"));
1471 * This functions checks if the library has an barcode reader.
1472 * fd -> pointer to the internal devie structure pDev
1479 extern OpenFiles_T *pDev;
1481 DebugPrint(DEBUG_INFO, SECTION_BARCODE,_("##### START BarCode\n"));
1482 DebugPrint(DEBUG_INFO, SECTION_BARCODE,_("%-20s : fd %d\n"), "BarCode", fd);
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);
1493 * This functions check if the tape drive is ready
1495 * fd -> pointer to the internal devie structure pDev
1496 * wait -> time to wait for the ready status
1504 extern OpenFiles_T *pDev;
1509 RequestSense_T *pRequestSense;
1510 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("##### START Tape_Ready\n"));
1513 * Which device should we use to get the
1518 * First the ioctl tapedevice
1520 if (pDev[INDEX_TAPE].avail == 1)
1526 * But if available and can do SCSI
1529 if (pDev[INDEX_TAPECTL].avail == 1 && pDev[INDEX_TAPECTL].SCSI == 1)
1534 if (pDev[fd].avail == 1 && pDev[fd].SCSI == 0)
1536 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("Tape_Ready : Can't send SCSI commands, try ioctl\n"));
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
1543 ret = Tape_Status(fd);
1546 while (cnt < wait_time)
1548 if ( ret & TAPE_ONLINE)
1550 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("Tape_Ready : Ready after %d seconds\n"),cnt);
1551 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("##### STOP Tape_Ready\n"));
1557 ret = Tape_Status(fd);
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"));
1566 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("Tape_Ready : no ioctl interface, will sleep for %d seconds\n"), wait_time);
1568 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("##### STOP Tape_Ready\n"));
1573 pRequestSense = alloc(SIZEOF(RequestSense_T));
1576 * Ignore errors at this point
1581 * Wait until we get an ready condition
1585 while (!done && (cnt < wait_time))
1587 ret = SCSI_TestUnitReady(fd, pRequestSense );
1594 switch (SenseHandler(fd, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
1597 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("TapeReady (TestUnitReady) SENSE_NO\n"));
1600 case SENSE_TAPE_NOT_ONLINE:
1601 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("TapeReady (TestUnitReady) SENSE_TAPE_NOT_ONLINE\n"));
1604 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("TapeReady (TestUnitReady) SENSE_IGNORE\n"));
1608 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("TapeReady (TestUnitReady) SENSE_ABORT\n"));
1609 amfree(pRequestSense);
1613 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("TapeReady (TestUnitReady) SENSE_RETRY\n"));
1616 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("TapeReady (TestUnitReady) default (SENSE)\n"));
1622 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("TapeReady (TestUnitReady) SCSI_ERROR\n"));
1623 free(pRequestSense);
1627 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("TapeReady (TestUnitReady) SCSI_BUSY\n"));
1630 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("TapeReady (TestUnitReady) SCSI_CHECK\n"));
1633 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("TapeReady (TestUnitReady) unknown (%d)\n"),ret);
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"));
1652 SC_COM_T *pSCSICommand;
1655 DebugPrint(DEBUG_INFO, SECTION_SCSI, _("##### START DecodeSCSI\n"));
1656 pSCSICommand = (SC_COM_T *)&SCSICommand;
1658 while (pSCSICommand->name != NULL)
1660 if (CDB[0] == pSCSICommand->command)
1662 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("%s %s"), string, pSCSICommand->name);
1663 for (x=0; x < pSCSICommand->length; x++)
1665 DebugPrint(DEBUG_INFO, SECTION_SCSI," %02X", CDB[x]);
1667 DebugPrint(DEBUG_INFO, SECTION_SCSI,"\n");
1668 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("##### STOP DecodeSCSI\n"));
1674 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("Not found %X\n"), CDB[0]);
1675 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("##### STOP DecodeSCSI\n"));
1687 ReadWriteErrorRecoveryPage_T *prp;
1688 DisconnectReconnectPage_T *pdrp;
1689 size_t length = (size_t)buffer[0] - 4 - offset;
1691 (void)pstring; /* Quiet unused parameter warning */
1693 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("##### START DecodeModeSense\n"));
1695 dump_hex(buffer, 255, DEBUG_INFO, SECTION_SCSI);
1697 /* Jump over the Parameter List header and an offset if we have something
1698 * Unknown at the start (ADIC-218) at the moment
1701 buffer = buffer + 4 + offset;
1703 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("buffer length = %d\n"), length);
1705 if (block) /* Do we have an block descriptor page ?*/
1708 g_fprintf(out, _("DecodeModeSense : Density Code %x\n"), (unsigned)buffer[0]);
1712 g_fprintf(out, _("DecodeModeSense : Number of Blocks %d\n"), V3(buffer));
1713 buffer = buffer + 4;
1716 g_fprintf(out, _("DecodeModeSense : Block Length %d\n"), V3(buffer));
1717 buffer = buffer + 3;
1722 switch (*buffer & 0x3f)
1725 pVendorUnique = buffer;
1729 prp = (ReadWriteErrorRecoveryPage_T *)buffer;
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);
1744 pdrp = (DisconnectReconnectPage_T *)buffer;
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);
1763 pEAAPage = (EAAPage_T *)buffer;
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));
1787 pDeviceCapabilitiesPage = (DeviceCapabilitiesPage_T *)buffer;
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);
1832 buffer++; /* set pointer to the length information */
1835 /* Error if *buffer (length) is 0 */
1838 /* EAAPage = NULL; */
1839 /* DeviceCapabilitiesPage = NULL; */
1843 length = length - (size_t)*buffer - 2;
1844 buffer = buffer + (size_t)*buffer + 1;
1851 RequestSense_T * sense,
1860 g_fprintf(out,_("##### START DecodeSense\n"));
1861 g_fprintf(out,_("%sSense Keys\n"), pstring);
1862 if (sense->ErrorCode == 0x70)
1864 g_fprintf(out,_("\tExtended Sense \n"));
1866 g_fprintf(out,_("\tErrorCode %02x\n"), sense->ErrorCode);
1867 g_fprintf(out,_("\tValid %d\n"), sense->Valid);
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)
1875 g_fprintf(out,_("\t\tNo Sense\n"));
1878 g_fprintf(out,_("\t\tRecoverd Error\n"));
1881 g_fprintf(out,_("\t\tNot Ready\n"));
1884 g_fprintf(out,_("\t\tMedium Error\n"));
1887 g_fprintf(out,_("\t\tHardware Error\n"));
1890 g_fprintf(out,_("\t\tIllegal Request\n"));
1893 g_fprintf(out,_("\t\tUnit Attention\n"));
1896 g_fprintf(out,_("\t\tData Protect\n"));
1899 g_fprintf(out,_("\t\tBlank Check\n"));
1902 g_fprintf(out,_("\t\tVendor uniq\n"));
1905 g_fprintf(out,_("\t\tCopy Aborted\n"));
1908 g_fprintf(out,_("\t\tAborted Command\n"));
1911 g_fprintf(out,_("\t\tEqual\n"));
1914 g_fprintf(out,_("\t\tVolume Overflow\n"));
1917 g_fprintf(out,_("\t\tMiscompare\n"));
1920 g_fprintf(out,_("\t\tReserved\n"));
1928 ExtendedRequestSense_T * sense,
1932 ExtendedRequestSense_T *p;
1934 g_fprintf(out,_("##### START DecodeExtSense\n"));
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))
1946 g_fprintf(out,_("\tPower Fail\n"));
1948 g_fprintf(out,_("\tSCSI Bus Parity Error\n"));
1950 g_fprintf(out,_("\tFormatted Buffer parity Error\n"));
1952 g_fprintf(out,_("\tMedia Error\n"));
1954 g_fprintf(out,_("\tError Counter Overflow\n"));
1956 g_fprintf(out,_("\tTapeMotion Error\n"));
1958 g_fprintf(out,_("\tTape Not Present\n"));
1960 g_fprintf(out,_("\tLogical Beginning of tape\n"));
1962 g_fprintf(out,_("\tTape Mark Detect Error\n"));
1964 g_fprintf(out,_("\tWrite Protect\n"));
1966 g_fprintf(out,_("\tFilemark Error\n"));
1968 g_fprintf(out,_("\tUnder Run Error\n"));
1970 g_fprintf(out,_("\tWrite Error 1\n"));
1972 g_fprintf(out,_("\tServo System Error\n"));
1974 g_fprintf(out,_("\tFormatter Error\n"));
1976 g_fprintf(out,_("\tCleaning Cartridge is empty\n"));
1978 g_fprintf(out,_("\tReverse Retries Required\n"));
1980 g_fprintf(out,_("\tTape Drive has been cleaned\n"));
1982 g_fprintf(out,_("\tTape Drive needs to be cleaned\n"));
1984 g_fprintf(out,_("\tPhysical End of Tape\n"));
1986 g_fprintf(out,_("\tWrite Splice Error\n"));
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);
1999 SCSIInquiry_T * SCSIInquiry)
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);
2021 dbprintf(_("##### START DoNothing\n"));
2029 (void)unused1; /* Quiet unused parameter warning */
2031 dbprintf(_("##### START DoNothing\n"));
2040 (void)unused1; /* Quiet unused parameter warning */
2041 (void)unused2; /* Quiet unused parameter warning */
2043 dbprintf(_("##### START DoNothing\n"));
2053 (void)unused1; /* Quiet unused parameter warning */
2054 (void)unused2; /* Quiet unused parameter warning */
2055 (void)unused3; /* Quiet unused parameter warning */
2057 dbprintf(_("##### START DoNothing\n"));
2064 dbprintf(_("##### START GenericFree\n"));
2071 dbprintf(_("##### START GenericSearch\n"));
2079 extern OpenFiles_T *pDev;
2081 ModePageTreeFrogVendorUnique_T *pVendor;
2083 dbprintf(_("##### START TreeFrogBarCode\n"));
2084 if (pModePage == NULL)
2086 pModePage = alloc(0xff);
2089 if (SCSI_ModeSense(DeviceFD, pModePage, 0xff, 0x0, 0x3f) == 0)
2091 DecodeModeSense(pModePage, 0, _("TreeFrogBarCode :"), 0, debug_file);
2093 if (pVendorUnique == NULL)
2095 dbprintf(_("TreeFrogBarCode : no pVendorUnique\n"));
2099 pVendor = ( ModePageTreeFrogVendorUnique_T *)pVendorUnique;
2101 dbprintf(_("TreeFrogBarCode : EBARCO %d\n"), pVendor->EBARCO);
2102 dbprintf(_("TreeFrogCheckSum : CHKSUM %d\n"), pVendor->CHKSUM);
2104 dump_hex((u_char *)pDev[INDEX_CHANGER].inquiry, INQUIRY_SIZE, DEBUG_INFO, SECTION_ELEMENT);
2105 return(pVendor->EBARCO);
2115 extern OpenFiles_T *pDev;
2117 ModePageEXB120VendorUnique_T *pVendor;
2118 ModePageEXB120VendorUnique_T *pVendorWork;
2120 DebugPrint(DEBUG_INFO, SECTION_BARCODE,_("##### START EXB_BarCode\n"));
2121 if (pModePage == NULL && LibModeSenseValid == 0)
2123 pModePage = alloc(0xff);
2125 if (SCSI_ModeSense(DeviceFD, pModePage, 0xff, 0x8, 0x3f) == 0)
2127 DecodeModeSense(pModePage, 0, _("EXB_BarCode :"), 0, debug_file);
2128 LibModeSenseValid = 1;
2130 LibModeSenseValid = -1;
2134 if (LibModeSenseValid == 1)
2136 if (pVendorUnique == NULL)
2138 DebugPrint(DEBUG_INFO, SECTION_BARCODE,_("EXB_BarCode : no pVendorUnique\n"));
2142 pVendor = ( ModePageEXB120VendorUnique_T *)pVendorUnique;
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 )
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)
2156 DebugPrint(DEBUG_INFO, SECTION_BARCODE,_("EXB_BarCode : SCSI_ModeSelect OK\n"));
2161 /* And now again !!!
2163 GenericResetStatus(DeviceFD);
2165 DebugPrint(DEBUG_INFO, SECTION_BARCODE,_("EXB_BarCode : SCSI_ModeSelect failed\n"));
2167 amfree(pVendorWork);
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]);
2180 (void)DeviceFD; /* Quiet unused parameter warning */
2182 DebugPrint(DEBUG_INFO, SECTION_BARCODE,_("##### START NoBarCode\n"));
2183 DebugPrint(DEBUG_INFO, SECTION_BARCODE,_("##### STOP NoBarCode\n"));
2191 (void)DeviceFD; /* Quiet unused parameter warning */
2193 DebugPrint(DEBUG_INFO, SECTION_BARCODE,_("##### START GenericBarCode\n"));
2194 if ( changer->havebarcode >= 1)
2196 DebugPrint(DEBUG_INFO, SECTION_BARCODE,_("##### STOP GenericBarCode (havebarcode) => %d\n"),changer->havebarcode);
2200 DebugPrint(DEBUG_INFO, SECTION_BARCODE,_("##### STOP GenericBarCode => 0\n"));
2209 u_char AdditionalSenseCode,
2210 u_char AdditionalSenseCodeQualifier,
2211 RequestSense_T * buffer)
2213 extern OpenFiles_T *pDev;
2215 dbprintf(_("##### START SenseHandler\n"));
2216 if (pDev[DeviceFD].inqdone == 1)
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);
2222 dbprintf(_(" Ups no sense\n"));
2224 dbprintf(_("#### STOP SenseHandler\n"));
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.
2235 * Pass an parameter to identify which unit to use
2236 * if there are more than one
2237 * Implement the SCSI path if available
2242 extern OpenFiles_T *pDev;
2246 RequestSense_T *pRequestSense;
2248 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("##### START TapeStatus\n"));
2251 * If it is an device which understand SCSI commands the
2252 * normal ioctl (MTIOCGET for example) may fail
2255 if (pDev[INDEX_TAPECTL].SCSI == 1)
2257 pRequestSense = alloc(SIZEOF(RequestSense_T));
2258 memset(pRequestSense, 0, SIZEOF(RequestSense_T));
2260 for (done = 0, cnt = 0; !done && (cnt < 60); cnt++)
2262 ret = SCSI_TestUnitReady(INDEX_TAPECTL, pRequestSense);
2263 DebugPrint(DEBUG_INFO, SECTION_SCSI, _("TapeStatus TestUnitReady ret %d\n"),ret);
2268 switch (SenseHandler(INDEX_TAPECTL, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
2272 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("TapeStatus (TestUnitReady) SENSE_NO\n"));
2273 pDTE[0].status = 'F';
2274 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("##### FULL\n"));
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"));
2286 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("TapeStatus (TestUnitReady) SENSE_ABORT\n"));
2291 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("TapeStatus (TestUnitReady) SENSE_RETRY\n"));
2295 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("TapeStatus (TestUnitReady) default (SENSE)\n"));
2301 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("TapeStatus (TestUnitReady) SCSI_ERROR\n"));
2306 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("TapeStatus (TestUnitReady) SCSI_BUSY\n"));
2310 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("TapeStatus (TestUnitReady) SCSI_CHECK\n"));
2314 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("TapeStatus (TestUnitReady) unknown (%d)\n"),ret);
2321 amfree(pRequestSense);
2323 ret = Tape_Status(INDEX_TAPE);
2324 if ( ret & TAPE_ONLINE)
2326 pDTE[0].status ='F';
2327 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("##### FULL\n"));
2329 pDTE[0].status = 'E';
2330 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("##### EMPTY\n"));
2332 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("##### STOP TapeStatus\n"));
2342 extern OpenFiles_T *pDev;
2344 RequestSense_T *pRequestSense;
2345 ExtendedRequestSense_T *pExtendedRequestSense;
2350 (void)Device; /* Quiet unused parameter warning */
2352 dbprintf(_("##### START DLT4000Eject\n"));
2354 pRequestSense = alloc(SIZEOF(RequestSense_T));
2355 pExtendedRequestSense = alloc(SIZEOF(ExtendedRequestSense_T));
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));
2368 if (pDev[INDEX_TAPECTL].SCSI == 0)
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));
2378 dbprintf(_("DLT4000Eject : SCSI eject on %s = %s\n"), pDev[INDEX_TAPECTL].dev, pDev[INDEX_TAPECTL].ConfigName);
2380 RequestSense(INDEX_TAPECTL, pExtendedRequestSense, 0);
2381 DecodeExtSense(pExtendedRequestSense, _("DLT4000Eject : "), debug_file);
2382 /* Unload the tape, 0 == wait for success
2385 ret = SCSI_LoadUnload(INDEX_TAPECTL, pRequestSense, 0, 0);
2387 RequestSense(INDEX_TAPECTL, pExtendedRequestSense, 0);
2388 DecodeExtSense(pExtendedRequestSense, _("DLT4000Eject : "), debug_file);
2392 free(pExtendedRequestSense);
2393 free(pRequestSense);
2399 while (!done && cnt < 300)
2401 ret = SCSI_TestUnitReady(INDEX_TAPECTL, pRequestSense);
2402 DebugPrint(DEBUG_INFO, SECTION_SCSI, _("DLT4000Eject TestUnitReady ret %d\n"),ret);
2409 switch (SenseHandler(INDEX_TAPECTL, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
2412 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("DLT4000Eject (TestUnitReady) SENSE_NO\n"));
2415 case SENSE_TAPE_NOT_ONLINE:
2416 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("DLT4000Eject (TestUnitReady) SENSE_TAPE_NOT_ONLINE\n"));
2420 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("DLT4000Eject (TestUnitReady) SENSE_IGNORE\n"));
2424 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("DLT4000Eject (TestUnitReady) SENSE_ABORT\n"));
2425 free(pExtendedRequestSense);
2426 free(pRequestSense);
2430 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("DLT4000Eject (TestUnitReady) SENSE_RETRY\n"));
2433 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("DLT4000Eject (TestUnitReady) default (SENSE)\n"));
2439 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("DLT4000Eject (TestUnitReady) SCSI_ERROR\n"));
2440 free(pExtendedRequestSense);
2441 free(pRequestSense);
2445 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("DLT4000Eject (TestUnitReady) SCSI_BUSY\n"));
2448 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("DLT4000Eject (TestUnitReady) SCSI_CHECK\n"));
2451 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("DLT4000Eject (TestUnitReady) unknown (%d)\n"),ret);
2459 dbprintf(_("DLT4000Eject : Ready after %d sec, done = %d\n"), cnt * 2, done);
2461 free(pExtendedRequestSense);
2462 free(pRequestSense);
2468 * Ejects an tape either with the ioctl interface
2469 * or by using the SCSI interface if available.
2472 * Before unload check if there is an tape in the drive
2480 extern OpenFiles_T *pDev;
2481 RequestSense_T *pRequestSense;
2486 (void)Device; /* Quiet unused parameter warning */
2487 (void)type; /* Quiet unused parameter warning */
2489 DebugPrint(DEBUG_INFO, SECTION_TAPE, _("##### START GenericEject\n"));
2491 pRequestSense = alloc(SIZEOF(RequestSense_T));
2493 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("GenericEject : SCSI eject on %s = %s\n"),
2494 pDev[INDEX_TAPECTL].dev, pDev[INDEX_TAPECTL].ConfigName);
2497 * Can we use SCSI commands ?
2499 if (pDev[INDEX_TAPECTL].SCSI == 1)
2501 LogSense(INDEX_TAPECTL);
2503 * Unload the tape, 1 == don't wait for success
2506 ret = SCSI_LoadUnload(INDEX_TAPECTL, pRequestSense, 1, 0);
2510 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericEject SCSI_LoadUnload failed\n");
2511 free(pRequestSense);
2517 while (!done && cnt < 300)
2519 ret = SCSI_TestUnitReady(INDEX_TAPECTL, pRequestSense);
2520 DebugPrint(DEBUG_INFO, SECTION_SCSI, _("GenericEject TestUnitReady ret %d\n"),ret);
2525 switch (SenseHandler(INDEX_TAPECTL, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
2528 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("GenericEject (TestUnitReady) SENSE_NO\n"));
2530 case SENSE_TAPE_NOT_ONLINE:
2531 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("GenericEject (TestUnitReady) SENSE_TAPE_NOT_ONLINE\n"));
2535 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("GenericEject (TestUnitReady) SENSE_IGNORE\n"));
2538 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("GenericEject (TestUnitReady) SENSE_ABORT\n"));
2539 free(pRequestSense);
2543 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("GenericEject (TestUnitReady) SENSE_RETRY\n"));
2546 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("GenericEject (TestUnitReady) default (SENSE)\n"));
2551 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("GenericEject (TestUnitReady) SCSI_ERROR\n"));
2552 free(pRequestSense);
2556 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("GenericEject (TestUnitReady) SCSI_BUSY\n"));
2559 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("GenericEject (TestUnitReady) SCSI_CHECK\n"));
2562 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("GenericEject (TestUnitReady) unknown (%d)\n"),ret);
2569 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("GenericEject : Device can't understand SCSI try ioctl\n"));
2570 Tape_Ioctl(INDEX_TAPECTL, IOCTL_EJECT);
2572 DebugPrint(DEBUG_INFO, SECTION_TAPE,
2573 _("GenericEject : Ready after %d sec\n"), cnt * 2);
2574 free(pRequestSense);
2582 * Make the retry counter an config option,
2593 extern OpenFiles_T *pDev;
2594 RequestSense_T *pRequestSense;
2595 char *errstr; /* Used by tape_rewind */
2600 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("##### START GenericRewind pDEV -> %d\n"),DeviceFD);
2604 * If we can use the SCSI device than use it, else use the ioctl
2607 if (pDev[DeviceFD].SCSI == 1)
2609 pRequestSense = alloc(SIZEOF(RequestSense_T));
2612 * Before doing the rewind check if the tape is ready to accept commands
2618 ret = SCSI_TestUnitReady(DeviceFD, (RequestSense_T *)pRequestSense );
2619 DebugPrint(DEBUG_INFO, SECTION_TAPE, _("GenericRewind (TestUnitReady) ret %d\n"),ret);
2626 switch (SenseHandler(DeviceFD, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
2629 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("GenericRewind (TestUnitReady) SENSE_NO\n"));
2632 case SENSE_TAPE_NOT_ONLINE:
2633 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("GenericRewind (TestUnitReady) SENSE_TAPE_NOT_ONLINE\n"));
2634 free(pRequestSense);
2638 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("GenericRewind (TestUnitReady) SENSE_IGNORE\n"));
2642 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("GenericRewind (TestUnitReady) SENSE_ABORT\n"));
2643 free(pRequestSense);
2647 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("GenericRewind (TestUnitReady) SENSE_RETRY\n"));
2650 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("GenericRewind (TestUnitReady) default (SENSE)\n"));
2653 } /* switch (SenseHandler(DeviceFD, 0, pRequestSense->SenseKey.... */
2657 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("GenericRewind (TestUnitReady) SCSI_ERROR\n"));
2658 free(pRequestSense);
2663 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("GenericRewind (TestUnitReady) SCSI_BUSY\n"));
2666 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("GenericRewind (TestUnitReady) SCSI_CHECK\n"));
2669 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("GenericRewind (TestUnitReady) unknown (%d)\n"),ret);
2674 DebugPrint(DEBUG_INFO, SECTION_TAPE,_(" Wait .... (%d)\n"),cnt);
2677 DebugPrint(DEBUG_ERROR, SECTION_TAPE,_("##### STOP GenericRewind (-1)\n"));
2678 free(pRequestSense);
2686 CDB[0] = SC_COM_REWIND;
2696 ret = SCSI_Run(DeviceFD, Input, CDB, 6,
2699 SIZEOF(RequestSense_T));
2701 DecodeSense(pRequestSense, _("GenericRewind : "), debug_file);
2705 if (pRequestSense->SenseKey != UNIT_ATTENTION)
2716 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("GenericRewind : failed %d\n"), ret);
2722 while (!done && (cnt < 300))
2724 ret = SCSI_TestUnitReady(DeviceFD, pRequestSense);
2725 DebugPrint(DEBUG_INFO, SECTION_SCSI, _("GenericRewind TestUnitReady ret %d\n"),ret);
2732 switch (SenseHandler(DeviceFD, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
2735 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("GenericRewind (TestUnitReady) SENSE_NO\n"));
2738 case SENSE_TAPE_NOT_ONLINE:
2739 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("GenericRewind (TestUnitReady) SENSE_TAPE_NOT_ONLINE\n"));
2740 free(pRequestSense);
2744 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("GenericRewind (TestUnitReady) SENSE_IGNORE\n"));
2748 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("GenericRewind (TestUnitReady) SENSE_ABORT\n"));
2749 free(pRequestSense);
2753 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("GenericRewind (TestUnitReady) SENSE_RETRY\n"));
2756 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("GenericRewind (TestUnitReady) default (SENSE)\n"));
2762 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("GenericRewind (TestUnitReady) SCSI_ERROR\n"));
2767 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("GenericRewind (TestUnitReady) SCSI_BUSY\n"));
2770 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("GenericRewind (TestUnitReady) SCSI_CHECK\n"));
2773 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("GenericRewind (TestUnitReady) unknown (%d)\n"),ret);
2781 amfree(pRequestSense);
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"));
2787 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("GenericRewind : use ioctl rewind\n"));
2788 if (pDev[DeviceFD].devopen == 1)
2790 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("Close Device\n"));
2791 SCSI_CloseDevice(DeviceFD);
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);
2797 DebugPrint(DEBUG_ERROR, SECTION_TAPE,_("Rewind failed %s\n"),errstr);
2798 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("##### STOP GenericRewind (-1)\n"));
2802 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("##### STOP GenericRewind (0)\n"));
2810 * Check if the tape has the tape clean
2811 * bit set in the return of an request sense
2818 extern OpenFiles_T *pDev;
2819 ExtendedRequestSense_T ExtRequestSense;
2822 (void)Device; /* Quiet unused parameter warning */
2824 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("##### START GenericClean\n"));
2825 if (pDev[INDEX_TAPECTL].SCSI == 0)
2827 DebugPrint(DEBUG_ERROR, SECTION_TAPE,_("GenericClean : can't send SCSI commands\n"));
2828 DebugPrint(DEBUG_ERROR, SECTION_TAPE,_("##### STOP GenericClean\n"));
2834 * Request Sense Data, reset the counter
2836 if ( RequestSense(INDEX_TAPECTL, &ExtRequestSense, 1) == 0)
2839 DecodeExtSense(&ExtRequestSense, _("GenericClean : "), debug_file);
2840 if(ExtRequestSense.CLN) {
2846 DebugPrint(DEBUG_ERROR, SECTION_TAPE,_("Got error from RequestSense\n"));
2848 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("##### STOP GenericClean (%d)\n"),ret);
2856 extern OpenFiles_T *pDev;
2858 RequestSense_T *pRequestSense;
2863 (void)Device; /* Quiet unused parameter warning */
2864 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### START SCSI_LogSenseClean\n");
2865 if (pDev[INDEX_TAPECTL].SCSI == 0)
2867 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"SCSILogSenseClean : can't send SCSI commands\n");
2868 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"##### STOP SCSI_LogSenseClean\n");
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");
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");
2884 memset(buffer, 0, size);
2885 CDB[0] = SC_COM_LOG_SENSE;
2887 CDB[2] = (u_char)(0x40 | 0x33);/* 0x40 for current values 0x33 Head Cleaning Page*/
2892 MSB2(&CDB[7], size);
2895 if (SCSI_Run(INDEX_TAPECTL, Input, CDB, 10,
2899 SIZEOF(RequestSense_T)) != 0)
2901 DecodeSense(pRequestSense, "SCSI_LogSenseClean : ",debug_file);
2902 free(pRequestSense);
2904 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"##### STOP SCSI_LogSenseClean (0) Page could not be read.\n");
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 */
2914 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### STOP SCSI_LogSenseClean (%d)\n",ret);
2915 free(pRequestSense);
2925 RequestSense_T *pRequestSense;
2929 DebugPrint(DEBUG_INFO, SECTION_ELEMENT, _("##### START GenericResetStatus\n"));
2931 pRequestSense = alloc(SIZEOF(RequestSense_T));
2935 CDB[0] = SC_COM_IES; /* */
2943 ret = SCSI_Run(DeviceFD, Input, CDB, 6,
2946 SIZEOF(RequestSense_T));
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);
2961 switch (SenseHandler(DeviceFD, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
2964 free(pRequestSense);
2968 free(pRequestSense);
2973 if (retry < MAX_RETRIES )
2975 DebugPrint(DEBUG_INFO, SECTION_ELEMENT, _("GenericResetStatus : retry %d\n"), retry);
2978 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("GenericResetStatus : return (-1)\n"));
2979 free(pRequestSense);
2985 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("GenericResetStatus : (default) return (-1)\n"));
2986 free(pRequestSense);
2994 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("##### STOP GenericResetStatus (%d)\n"),ret);
2995 free(pRequestSense);
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
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.
3011 * Limit recursion, may run in an infinite loop
3014 GenericSenseHandler(
3018 u_char AdditionalSenseCode,
3019 u_char AdditionalSenseCodeQualifier,
3020 RequestSense_T * pRequestSense)
3022 extern OpenFiles_T *pDev;
3026 dbprintf(_("##### START GenericSenseHandler\n"));
3028 DecodeSense(pRequestSense, _("GenericSenseHandler : "), debug_file);
3030 ret = Sense2Action(pDev[ip].ident,
3031 pDev[ip].inquiry->type,
3033 AdditionalSenseCode,
3034 AdditionalSenseCodeQualifier,
3037 dbprintf(_("##### STOP GenericSenseHandler: %s\n"), _(info));
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
3049 * != 0 -> error either from the SCSI command or from
3050 * the element handling
3059 extern OpenFiles_T *pDev;
3060 ElementInfo_T *pfrom;
3065 int SDX_MTE = 0; /* This are parameters passed */
3066 int SDX_STE = -1; /* to */
3067 int SDX_DTE = -1; /* AlignElements */
3069 DebugPrint(DEBUG_INFO, SECTION_MOVE,_("##### START SDXMove\n"));
3071 DebugPrint(DEBUG_INFO, SECTION_MOVE,_("%-20s : from = %d, to = %d\n"), "SDXMove", from, to);
3074 if ((pfrom = LookupElement(from)) == NULL)
3076 DebugPrint(DEBUG_INFO, SECTION_MOVE,_("SDXMove : ElementInfo for %d not found\n"), from);
3077 DebugPrint(DEBUG_INFO, SECTION_MOVE,_("##### STOP SDXMove\n"));
3082 if ((pto = LookupElement(to)) == NULL)
3084 DebugPrint(DEBUG_INFO, SECTION_MOVE,_("SDXMove : ElementInfo for %d not found\n"), to);
3085 DebugPrint(DEBUG_INFO, SECTION_MOVE,_("##### STOP SDXMove\n"));
3090 if (pfrom->status == 'E')
3092 DebugPrint(DEBUG_INFO, SECTION_MOVE,_("SDXMove : from %d is empty\n"), from);
3093 DebugPrint(DEBUG_INFO, SECTION_MOVE,_("##### STOP SDXMove\n"));
3098 if (pto->status == 'F')
3100 switch (pto->status)
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);
3110 DebugPrint(DEBUG_ERROR, SECTION_MOVE,_("SDXMove : no empty slot found for unload\n"));
3114 DebugPrint(DEBUG_INFO, SECTION_MOVE,_("SDXMove : Unload to %d\n"), to);
3115 if ((pto = LookupElement(to)) == NULL)
3117 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("SDXMove : ElementInfo for %d not found\n"), to);
3118 DebugPrint(DEBUG_INFO, SECTION_MOVE,_("##### STOP SDXMove\n"));
3130 moveok = CheckMove(pfrom, pto);
3135 SDX_DTE = pto->address;
3138 SDX_STE = pto->address;
3141 SDX_STE = pto->address;
3145 switch (pfrom->type)
3148 SDX_DTE = pfrom->address;
3151 SDX_STE = pfrom->address;
3154 SDX_STE = pfrom->address;
3158 if (SDX_DTE >= 0 && SDX_STE >= 0)
3160 ret = SCSI_AlignElements(DeviceFD, SDX_MTE, SDX_DTE, SDX_STE);
3161 DebugPrint(DEBUG_INFO, SECTION_MOVE,_("##### SCSI_AlignElemnts ret = %d\n"),ret);
3164 DebugPrint(DEBUG_INFO, SECTION_MOVE,_("##### STOP SDXMove\n"));
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"));
3176 * If from is a tape we must check if it is loaded
3177 * and if yes we have to eject it
3179 if (pfrom->type == TAPETYPE)
3181 tapestat = Tape_Status(INDEX_TAPE);
3182 if ( tapestat & TAPE_ONLINE)
3184 if (pDev[INDEX_TAPECTL].SCSI == 1)
3186 ret = eject_tape(pDev[INDEX_TAPECTL].dev,1);
3188 ret = eject_tape(pDev[INDEX_TAPE].dev,2);
3193 if ((ret == 0) && moveok)
3195 ret = SCSI_Move(DeviceFD, 0, from, to);
3197 DebugPrint(DEBUG_INFO, SECTION_MOVE,_("##### STOP SDXMove\n"));
3201 DebugPrint(DEBUG_INFO, SECTION_MOVE,_("##### STOP SDXMove\n"));
3206 * Do the move. We don't address the MTE element (the gripper)
3207 * here. We assume that the library use the right MTE
3211 * != 0 -> error either from the SCSI command or from
3212 * the element handling
3221 ElementInfo_T *pfrom;
3225 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("##### START GenericMove\n"));
3227 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("%-20s : from = %d, to = %d\n"), "GenericMove", from, to);
3230 if ((pfrom = LookupElement(from)) == NULL)
3232 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("GenericMove : ElementInfo for %d not found\n"), from);
3233 DebugPrint(DEBUG_INFO, SECTION_MOVE,_("##### STOP GenericMove\n"));
3238 if ((pto = LookupElement(to)) == NULL)
3240 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("GenericMove : ElementInfo for %d not found\n"), to);
3241 DebugPrint(DEBUG_INFO, SECTION_MOVE,_("##### STOP GenericMove\n"));
3246 if (pfrom->status == 'E')
3248 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("GenericMove : from %d is empty\n"), from);
3249 DebugPrint(DEBUG_INFO, SECTION_MOVE,_("##### STOP GenericMove\n"));
3254 if (pto->status == 'F')
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);
3261 DebugPrint(DEBUG_ERROR, SECTION_MOVE, _("GenericMove : no empty slot found\n"));
3265 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("GenericMove : Unload to %d\n"), to);
3266 if ((pto = LookupElement(to)) == NULL)
3268 DebugPrint(DEBUG_ERROR, SECTION_MOVE, _(" Ups should not happen\n"));
3269 DebugPrint(DEBUG_INFO, SECTION_MOVE,_("##### STOP GenericMove\n"));
3275 if (CheckMove(pfrom, pto))
3277 ret = SCSI_Move(DeviceFD, 0, from, to);
3280 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("GenericMove : SCSI_Move return (%d)\n"), ret);
3281 DebugPrint(DEBUG_INFO, SECTION_MOVE,_("##### STOP GenericMove\n"));
3286 * Check if a move based on the information we got from the Mode Sense command
3295 ElementInfo_T * from,
3300 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("##### START CheckMove\n"));
3301 if (pDeviceCapabilitiesPage != NULL )
3303 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("CheckMove : checking if move from %d to %d is legal\n"), from->address, to->address);
3307 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("CheckMove : MT2"));
3311 if (pDeviceCapabilitiesPage->MT2MT == 1)
3313 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("MT\n"));
3318 if (pDeviceCapabilitiesPage->MT2ST == 1)
3320 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("ST\n"));
3325 if (pDeviceCapabilitiesPage->MT2IE == 1)
3327 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("IE\n"));
3332 if (pDeviceCapabilitiesPage->MT2DT == 1)
3334 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("DT\n"));
3343 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("CheckMove : ST2"));
3347 if (pDeviceCapabilitiesPage->ST2MT == 1)
3349 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("MT\n"));
3354 if (pDeviceCapabilitiesPage->ST2ST == 1)
3356 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("ST\n"));
3361 if (pDeviceCapabilitiesPage->ST2IE == 1)
3363 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("IE\n"));
3368 if (pDeviceCapabilitiesPage->ST2DT == 1)
3370 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("DT\n"));
3379 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("CheckMove : IE2"));
3383 if (pDeviceCapabilitiesPage->IE2MT == 1)
3385 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("MT\n"));
3390 if (pDeviceCapabilitiesPage->IE2ST == 1)
3392 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("ST\n"));
3397 if (pDeviceCapabilitiesPage->IE2IE == 1)
3399 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("IE\n"));
3404 if (pDeviceCapabilitiesPage->IE2DT == 1)
3406 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("DT\n"));
3415 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("CheckMove : DT2"));
3419 if (pDeviceCapabilitiesPage->DT2MT == 1)
3421 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("MT\n"));
3426 if (pDeviceCapabilitiesPage->DT2ST == 1)
3428 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("ST\n"));
3433 if (pDeviceCapabilitiesPage->DT2IE == 1)
3435 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("IE\n"));
3440 if (pDeviceCapabilitiesPage->DT2DT == 1)
3442 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("DT\n"));
3454 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("CheckMove : pDeviceCapabilitiesPage == NULL"));
3456 ChgExit("CheckMove", _("DeviceCapabilitiesPage == NULL"), FATAL);
3461 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("###### STOP CheckMove\n"));
3473 extern OpenFiles_T *pDev;
3475 dbprintf(_("##### START GetCurrentSlot\n"));
3477 (void)fd; /* Quiet unused parameter warning */
3479 if (pDev[0].SCSI == 0)
3481 dbprintf(_("GetCurrentSlot : can't send SCSI commands\n"));
3486 if (ElementStatusValid == 0)
3488 if (pDev[0].functions->function_status(0, 1) != 0)
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)
3498 for (x = 0; x < STE;x++)
3500 if (pSTE[x].address == pDTE[drive].from)
3508 for (x = 0; x < STE;x++)
3510 if (pSTE[x].status == 'E') {
3516 /* Ups nothing loaded */
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.
3528 * If there are error conditions try to fix them
3532 GenericElementStatus(
3541 extern OpenFiles_T *pDev;
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 */
3547 (void)InitStatus; /* Quiet unused parameter warning */
3549 DebugPrint(DEBUG_INFO, SECTION_ELEMENT, _("##### START GenericElementStatus\n"));
3551 if (pEAAPage == NULL)
3554 * If this pointer is null
3555 * then try to read the parameter with MODE SENSE
3558 if (pModePage == NULL && LibModeSenseValid == 0)
3560 pModePage = alloc(0xff);
3562 if (SCSI_ModeSense(DeviceFD, pModePage, 0xff, 0x8, 0x3f) == 0)
3564 LibModeSenseValid = 1;
3565 DecodeModeSense(pModePage, 0, _("GenericElementStatus :"), 0, debug_file);
3567 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,_("GetElementStatus : failed SCSI_ModeSense\n"));
3568 LibModeSenseValid = -1;
3573 while ((GetElementStatus(DeviceFD) == 0) && (retry-- > 0))
3575 for (x = 0; x < MTE; x++)
3577 if (pMTE[x].ASC > 0)
3579 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pMTE[x].ASC, pMTE[x].ASCQ, (RequestSense_T *)&pMTE[x]))
3586 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("GenericElementStatus : Abort on MTE\n"));
3593 for (x = 0; x < IEE; x++)
3595 if (pIEE[x].ASC > 0)
3597 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pIEE[x].ASC, pIEE[x].ASCQ, (RequestSense_T *)&pIEE[x]))
3604 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("GenericElementStatus : Abort on IEE\n"));
3612 for (x = 0; x < STE; x++)
3614 if (pSTE[x].ASC > 0)
3616 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pSTE[x].ASC, pSTE[x].ASCQ, (RequestSense_T *)&pSTE[x]))
3623 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("GenericElementStatus : Abort on IES\n"));
3630 for (x = 0; x < DTE; x++)
3632 if (pDTE[x].ASC > 0)
3634 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pDTE[x].ASC, pDTE[x].ASCQ, (RequestSense_T *)&pDTE[x]))
3641 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("GenericElementStatus : Abort on DTE\n"));
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
3655 if (GenericResetStatus(DeviceFD) != 0)
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);
3669 * If the status is empty to an move from tape to tape
3670 * This is if the tape is ejected, but not unloaded
3672 if (pDTE[0].status == 'E')
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);
3678 /* Done GetElementStatus */
3683 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("GenericElementStatus : Can't init status (after loop)\n"));
3688 ElementStatusValid = 1;
3689 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("#### STOP GenericElementStatus\n"));
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)
3699 DLT448ElementStatus(
3705 extern OpenFiles_T *pDev;
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 */
3711 (void)InitStatus; /* Quiet unused parameter warning */
3713 DebugPrint(DEBUG_INFO, SECTION_ELEMENT, _("##### START DLT448ElementStatus\n"));
3715 if (pEAAPage == NULL)
3718 * If this pointer is null
3719 * then try to read the parameter with MODE SENSE
3722 if (pModePage == NULL && LibModeSenseValid == 0)
3724 pModePage = alloc(0xff);
3726 if (SCSI_ModeSense(DeviceFD, pModePage, 0xff, 0x8, 0x3f) == 0)
3728 LibModeSenseValid = 1;
3729 DecodeModeSense(pModePage, 12, _("DLT448ElementStatus :"), 0, debug_file);
3731 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,_("DLT448ElementStatus : failed SCSI_ModeSense\n"));
3732 LibModeSenseValid = -1;
3737 while (GetElementStatus(DeviceFD) == 0 && loop-- > 0)
3739 for (x = 0; x < MTE; x++)
3741 if (pMTE[x].ASC > 0)
3743 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pMTE[x].ASC, pMTE[x].ASCQ, (RequestSense_T *)&pMTE[x]))
3749 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("DLT448ElementStatus : Abort on MTE\n"));
3756 for (x = 0; x < IEE; x++)
3758 if (pIEE[x].ASC > 0)
3760 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pIEE[x].ASC, pIEE[x].ASCQ, (RequestSense_T *)&pIEE[x]))
3766 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("DLT448ElementStatus : Abort on IEE\n"));
3774 for (x = 0; x < STE; x++)
3777 * Needed for the hack to guess the tape status if an error
3778 * for the tape is pending
3780 if (pSTE[x].ASC > 0)
3782 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pSTE[x].ASC, pSTE[x].ASCQ, (RequestSense_T *)&pSTE[x]))
3788 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("DLT448ElementStatus : Abort on IES\n"));
3795 for (x = 0; x < DTE; x++)
3797 if (pDTE[x].ASC > 0)
3799 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pDTE[x].ASC, pDTE[x].ASCQ, (RequestSense_T *)&pDTE[x]))
3806 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("DLT448ElementStatus : Abort on DTE\n"));
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
3820 if (GenericResetStatus(DeviceFD) != 0)
3822 ElementStatusValid = 0;
3823 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("DLT448ElementStatus : Can't init status\n"));
3834 * If the status is empty to an move from tape to tape
3835 * This is if the tape is ejected, but not unloaded
3837 if (pDTE[0].status == 'E')
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);
3843 /* Done GetElementStatus */
3848 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("DLT448ElementStatus : Can't init status (after loop)\n"));
3853 ElementStatusValid = 1;
3854 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("#### STOP DLT448ElementStatus\n"));
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
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 */
3873 (void)InitStatus; /* Quiet unused parameter warning */
3875 DebugPrint(DEBUG_INFO, SECTION_ELEMENT, _("##### START SDXElementStatus\n"));
3877 if (pEAAPage == NULL)
3880 * If this pointer is null
3881 * then try to read the parameter with MODE SENSE
3884 if (pModePage == NULL && LibModeSenseValid == 0)
3886 pModePage = alloc(0xff);
3888 if (SCSI_ModeSense(DeviceFD, pModePage, 0xff, 0x8, 0x3f) == 0)
3890 LibModeSenseValid = 1;
3891 DecodeModeSense(pModePage, 0, _("SDXElementStatus :"), 0, debug_file);
3893 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,_("SDXElementStatus : failed SCSI_ModeSense\n"));
3894 LibModeSenseValid = -1;
3899 while (GetElementStatus(DeviceFD) == 0 && loop--)
3902 for (x = 0; x < MTE; x++)
3904 if (pMTE[x].ASC > 0)
3906 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pMTE[x].ASC, pMTE[x].ASCQ, (RequestSense_T *)&pMTE[x]))
3912 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("SDXElementStatus : Abort on MTE\n"));
3919 for (x = 0; x < IEE; x++)
3921 if (pIEE[x].ASC > 0)
3923 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pIEE[x].ASC, pIEE[x].ASCQ, (RequestSense_T *)&pIEE[x]))
3929 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("SDXElementStatus : Abort on IEE\n"));
3937 for (x = 0; x < STE; x++)
3939 if (pSTE[x].ASC > 0)
3941 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pSTE[x].ASC, pSTE[x].ASCQ, (RequestSense_T *)&pSTE[x]))
3947 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("SDXElementStatus : Abort on IES\n"));
3954 for (x = 0; x < DTE; x++)
3956 if (pDTE[x].ASC > 0)
3958 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pDTE[x].ASC, pDTE[x].ASCQ, (RequestSense_T *)&pDTE[x]))
3966 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("SDXElementStatus : Abort on DTE\n"));
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
3980 if (GenericResetStatus(DeviceFD) != 0)
3982 ElementStatusValid = 0;
3983 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("SDXElementStatus : Can't init status\n"));
3989 /* Done GetElementStatus */
3994 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("SDXElementStatus : Can't init status\n"));
3999 ElementStatusValid = 1;
4001 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("#### STOP SDXElementStatus\n"));
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.
4012 * Only do the read, error handling is done by the calling function
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;
4034 size_t length; /* Length of an Element */
4035 size_t NoOfElements;
4037 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("##### START GetElementStatus\n"));
4039 barcode = BarCode(DeviceFD);
4042 * If the MODE_SENSE was successfull we use this Information to read the Elelement Info
4044 if (pEAAPage != NULL)
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)
4050 MTE = V2(pEAAPage->NoMediumTransportElements) ;
4051 pMTE = alloc(SIZEOF(ElementInfo_T) * MTE);
4052 memset(pMTE, 0, SIZEOF(ElementInfo_T) * MTE);
4054 if (SCSI_ReadElementStatus(DeviceFD,
4058 V2(pEAAPage->MediumTransportElementAddress),
4060 SIZEOF(MediumTransportElementDescriptor_T),
4063 ChgExit("genericElementStatus",_("Can't read MTE status"), FATAL);
4066 // ElementStatusData = (ElementStatusData_T *)DataBuffer;
4067 offset = SIZEOF(ElementStatusData_T);
4069 ElementStatusPage = (ElementStatusPage_T *)&DataBuffer[offset];
4070 offset = offset + SIZEOF(ElementStatusPage_T);
4071 length = V2(ElementStatusPage->length);
4073 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("MTE Length %d(%d)\n"), length,
4074 SIZEOF(MediumTransportElementDescriptor_T));
4076 for (x = 0; x < MTE; x++)
4078 MediumTransportElementDescriptor = (MediumTransportElementDescriptor_T *)&DataBuffer[offset];
4080 if (ElementStatusPage->pvoltag == 1)
4082 strncpy((char *)pMTE[x].VolTag,
4083 (char *)MediumTransportElementDescriptor->pvoltag,
4085 TerminateString(pMTE[x].VolTag, TAG_SIZE+1);
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)
4094 pMTE[x].status = 'F';
4096 pMTE[x].status = 'E';
4101 pMTE[x].ASC = MediumTransportElementDescriptor->asc;
4103 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Skip ASC MTE\n"));
4108 pMTE[x].ASCQ = MediumTransportElementDescriptor->ascq;
4110 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Skip ASCQ MTE\n"));
4115 if (MediumTransportElementDescriptor->svalid == 1)
4117 pMTE[x].from = V2(MediumTransportElementDescriptor->source);
4122 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Skip source MTE\n"));
4124 offset = offset + length;
4132 if ( V2(pEAAPage->NoStorageElements) > 0)
4135 STE = V2(pEAAPage->NoStorageElements);
4136 pSTE = alloc(SIZEOF(ElementInfo_T) * STE);
4137 memset(pSTE, 0, SIZEOF(ElementInfo_T) * STE);
4139 if (SCSI_ReadElementStatus(DeviceFD,
4143 V2(pEAAPage->FirstStorageElementAddress),
4145 SIZEOF(StorageElementDescriptor_T),
4148 ChgExit("GetElementStatus", _("Can't read STE status"), FATAL);
4151 assert(DataBuffer != NULL);
4153 // ElementStatusData = (ElementStatusData_T *)DataBuffer;
4154 offset = SIZEOF(ElementStatusData_T);
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);
4161 for (x = 0; x < STE; x++)
4163 StorageElementDescriptor = (StorageElementDescriptor_T *)&DataBuffer[offset];
4164 if (ElementStatusPage->pvoltag == 1)
4166 strncpy(pSTE[x].VolTag,
4167 (char *)StorageElementDescriptor->pvoltag,
4169 TerminateString(pSTE[x].VolTag, TAG_SIZE+1);
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)
4179 pSTE[x].status = 'F';
4181 pSTE[x].status = 'E';
4186 pSTE[x].ASC = StorageElementDescriptor->asc;
4188 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Skip ASC STE\n"));
4193 pSTE[x].ASCQ = StorageElementDescriptor->ascq;
4195 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Skip ASCQ STE\n"));
4200 if (StorageElementDescriptor->svalid == 1)
4202 pSTE[x].from = V2(StorageElementDescriptor->source);
4207 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Skip source STE\n"));
4210 offset = offset + length;
4216 * Import/Export Elements
4218 if ( V2(pEAAPage->NoImportExportElements) > 0)
4221 IEE = V2(pEAAPage->NoImportExportElements);
4222 pIEE = alloc(SIZEOF(ElementInfo_T) * IEE);
4223 memset(pIEE, 0, SIZEOF(ElementInfo_T) * IEE);
4225 if (SCSI_ReadElementStatus(DeviceFD,
4229 V2(pEAAPage->FirstImportExportElementAddress),
4231 SIZEOF(ImportExportElementDescriptor_T),
4234 ChgExit("GetElementStatus", _("Can't read IEE status"), FATAL);
4237 assert(DataBuffer != NULL);
4239 // ElementStatusData = (ElementStatusData_T *)DataBuffer;
4240 offset = SIZEOF(ElementStatusData_T);
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);
4247 for (x = 0; x < IEE; x++)
4249 ImportExportElementDescriptor = (ImportExportElementDescriptor_T *)&DataBuffer[offset];
4250 if (ElementStatusPage->pvoltag == 1)
4252 strncpy(pIEE[x].VolTag,
4253 (char *)ImportExportElementDescriptor->pvoltag,
4255 TerminateString(pIEE[x].VolTag, TAG_SIZE+1);
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)
4263 pIEE[x].status = 'F';
4265 pIEE[x].status = 'E';
4270 pIEE[x].ASC = ImportExportElementDescriptor->asc;
4272 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Skip ASC IEE\n"));
4277 pIEE[x].ASCQ = ImportExportElementDescriptor->ascq;
4279 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Skip ASCQ IEE\n"));
4284 if (ImportExportElementDescriptor->svalid == 1)
4286 pIEE[x].from = V2(ImportExportElementDescriptor->source);
4291 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Skip source IEE\n"));
4294 offset = offset + length;
4300 * Data Transfer Elements
4302 if (V2(pEAAPage->NoDataTransferElements) >0)
4305 DTE = V2(pEAAPage->NoDataTransferElements) ;
4306 pDTE = alloc(SIZEOF(ElementInfo_T) * DTE);
4307 memset(pDTE, 0, SIZEOF(ElementInfo_T) * DTE);
4309 if (SCSI_ReadElementStatus(DeviceFD,
4313 V2(pEAAPage->FirstDataTransferElementAddress),
4315 SIZEOF(DataTransferElementDescriptor_T),
4318 ChgExit("GenericElementStatus", _("Can't read DTE status"), FATAL);
4321 assert(DataBuffer != NULL);
4323 // ElementStatusData = (ElementStatusData_T *)DataBuffer;
4324 offset = SIZEOF(ElementStatusData_T);
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);
4331 for (x = 0; x < DTE; x++)
4333 DataTransferElementDescriptor = (DataTransferElementDescriptor_T *)&DataBuffer[offset];
4334 if (ElementStatusPage->pvoltag == 1)
4336 strncpy(pDTE[x].VolTag,
4337 (char *)DataTransferElementDescriptor->pvoltag,
4339 TerminateString(pDTE[x].VolTag, TAG_SIZE+1);
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)
4348 pDTE[x].status = 'F';
4350 pDTE[x].status = 'E';
4355 pDTE[x].ASC = DataTransferElementDescriptor->asc;
4357 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Skip ASC DTE\n"));
4362 pDTE[x].ASCQ = DataTransferElementDescriptor->ascq;
4364 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Skip ASCQ DTE\n"));
4369 if (DataTransferElementDescriptor->svalid == 1)
4371 pDTE[x].from = V2(DataTransferElementDescriptor->source);
4376 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Skip source STE\n"));
4379 offset = offset + length;
4386 * And now the old way, when we get here the read mode sense page has failed ...
4388 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Reading Element Status the old way .... (max 255 elements)\n"));
4389 if (SCSI_ReadElementStatus(DeviceFD,
4398 ChgExit("GenericElementStatus",_("Can't get ElementStatus"), FATAL);
4401 assert(DataBuffer != NULL);
4403 ElementStatusData = (ElementStatusData_T *)DataBuffer;
4404 DataBufferLength = V3(ElementStatusData->count);
4406 offset = SIZEOF(ElementStatusData_T);
4408 while (offset < DataBufferLength)
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);
4415 switch (ElementStatusPage->type)
4420 pMTE = alloc(SIZEOF(ElementInfo_T) * MTE);
4421 memset(pMTE, 0, SIZEOF(ElementInfo_T) * MTE);
4423 for (x = 0; x < NoOfElements; x++)
4425 MediumTransportElementDescriptor = (MediumTransportElementDescriptor_T *)&DataBuffer[offset];
4426 if (ElementStatusPage->pvoltag == 1)
4428 strncpy(pMTE[x].VolTag,
4429 (char *)MediumTransportElementDescriptor->pvoltag,
4431 TerminateString(pMTE[x].VolTag, TAG_SIZE+1);
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)
4439 pMTE[x].status = 'F';
4441 pMTE[x].status = 'E';
4446 pMTE[x].ASC = MediumTransportElementDescriptor->asc;
4448 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Skip ASC MTE\n"));
4453 pMTE[x].ASCQ = MediumTransportElementDescriptor->ascq;
4455 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Skip ASCQ MTE\n"));
4460 if (MediumTransportElementDescriptor->svalid == 1)
4462 pMTE[x].from = V2(MediumTransportElementDescriptor->source);
4467 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Skip source MTE\n"));
4470 offset = offset + length;
4476 pSTE = alloc(SIZEOF(ElementInfo_T) * STE);
4477 memset(pSTE, 0, SIZEOF(ElementInfo_T) * STE);
4479 for (x = 0; x < NoOfElements; x++)
4481 StorageElementDescriptor = (StorageElementDescriptor_T *)&DataBuffer[offset];
4482 if (ElementStatusPage->pvoltag == 1)
4484 strncpy(pSTE[x].VolTag,
4485 (char *)StorageElementDescriptor->pvoltag,
4487 TerminateString(pSTE[x].VolTag, TAG_SIZE+1);
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)
4496 pSTE[x].status = 'F';
4498 pSTE[x].status = 'E';
4503 pSTE[x].ASC = StorageElementDescriptor->asc;
4505 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Skip ASC STE\n"));
4510 pSTE[x].ASCQ = StorageElementDescriptor->ascq;
4512 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Skip ASCQ STE\n"));
4517 if (StorageElementDescriptor->svalid == 1)
4519 pSTE[x].from = V2(StorageElementDescriptor->source);
4524 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Skip source STE\n"));
4527 offset = offset + length;
4533 pIEE = alloc(SIZEOF(ElementInfo_T) * IEE);
4534 memset(pIEE, 0, SIZEOF(ElementInfo_T) * IEE);
4536 for (x = 0; x < NoOfElements; x++)
4538 ImportExportElementDescriptor = (ImportExportElementDescriptor_T *)&DataBuffer[offset];
4539 if (ElementStatusPage->pvoltag == 1)
4541 strncpy(pIEE[x].VolTag,
4542 (char *)ImportExportElementDescriptor->pvoltag,
4544 TerminateString(pIEE[x].VolTag, TAG_SIZE+1);
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)
4553 pIEE[x].status = 'F';
4555 pIEE[x].status = 'E';
4560 pIEE[x].ASC = ImportExportElementDescriptor->asc;
4562 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Skip ASC IEE\n"));
4567 pIEE[x].ASCQ = ImportExportElementDescriptor->ascq;
4569 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Skip ASCQ IEE\n"));
4574 if (ImportExportElementDescriptor->svalid == 1)
4576 pIEE[x].from = V2(ImportExportElementDescriptor->source);
4581 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Skip source IEE\n"));
4584 offset = offset + length;
4590 pDTE = alloc(SIZEOF(ElementInfo_T) * DTE);
4591 memset(pDTE, 0, SIZEOF(ElementInfo_T) * DTE);
4593 for (x = 0; x < NoOfElements; x++)
4595 DataTransferElementDescriptor = (DataTransferElementDescriptor_T *)&DataBuffer[offset];
4596 if (ElementStatusPage->pvoltag == 1)
4598 strncpy(pSTE[x].VolTag,
4599 (char *)DataTransferElementDescriptor->pvoltag,
4601 TerminateString(pSTE[x].VolTag, TAG_SIZE+1);
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)
4610 pDTE[x].status = 'F';
4612 pDTE[x].status = 'E';
4617 pDTE[x].ASC = DataTransferElementDescriptor->asc;
4619 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Skip ASC DTE\n"));
4624 pDTE[x].ASCQ = DataTransferElementDescriptor->ascq;
4626 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Skip ASCQ DTE\n"));
4631 if (DataTransferElementDescriptor->svalid == 1)
4633 pDTE[x].from = V2(DataTransferElementDescriptor->source);
4638 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Skip source STE\n"));
4641 offset = offset + length;
4645 offset = offset + length;
4646 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,_("GetElementStatus : UnGknown Type %d\n"),ElementStatusPage->type);
4653 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("\n\n\tMedia Transport Elements (robot arms) :\n"));
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);
4660 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("\n\n\tStorage Elements (Media slots) :\n"));
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);
4667 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("\n\n\tData Transfer Elements (tape drives) :\n"));
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);
4674 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("\n\n\tImport/Export Elements :\n"));
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);
4688 * If ClearErrorCounters is set the counters will be reset.
4689 * Used by GenericClean for example
4696 ExtendedRequestSense_T * ExtendedRequestSense,
4697 int ClearErrorCounters)
4702 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("##### START RequestSense\n"));
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); /* */
4711 memset(ExtendedRequestSense, 0, SIZEOF(ExtendedRequestSense_T));
4713 ret = SCSI_Run(DeviceFD, Input, CDB, 6,
4714 (char *) ExtendedRequestSense,
4715 SIZEOF(ExtendedRequestSense_T),
4716 (RequestSense_T *) ExtendedRequestSense,
4717 SIZEOF(ExtendedRequestSense_T));
4722 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("##### STOP RequestSense (%d)\n"),ret);
4729 DecodeExtSense(ExtendedRequestSense, "RequestSense : ",debug_file);
4730 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("##### STOP RequestSense (%d)\n"), ExtendedRequestSense->SenseKey);
4731 return(ExtendedRequestSense->SenseKey);
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"));
4744 * Lookup function pointer for device ....
4754 dbprintf(_("##### START LookupElement\n"));
4758 for (x = 0; x < DTE; x++)
4760 if (pDTE[x].address == address)
4762 dbprintf(_("##### STOP LookupElement (DTE)\n"));
4771 for (x = 0; x < MTE; x++)
4773 if (pMTE[x].address == address)
4775 dbprintf(_("##### STOP LookupElement (MTE)\n"));
4784 for (x = 0; x < STE; x++)
4786 if (pSTE[x].address == address)
4788 dbprintf(_("##### STOP LookupElement (STE)\n"));
4797 for ( x = 0; x < IEE; x++)
4799 if (pIEE[x].address == address)
4801 dbprintf(_("##### STOP LookupElement (IEE)\n"));
4811 * Here comes everything what decode the log Pages
4814 * Fix the result handling from TestUnitReady
4821 extern OpenFiles_T *pDev;
4823 RequestSense_T *pRequestSense;
4824 LogSenseHeader_T *LogSenseHeader;
4825 LogParameter_T *LogParameter;
4826 struct LogPageDecode *p;
4828 extern char *tapestatfile;
4830 unsigned ParameterCode;
4839 (void)DeviceFD; /* Quiet unused parameter warning */
4841 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("##### START LogSense\n"));
4843 if ((tapestatfile != NULL) && (pDev[INDEX_TAPECTL].SCSI == 1) &&
4844 ((StatFile = fopen(tapestatfile,"a")) != NULL))
4846 pRequestSense = alloc(SIZEOF(RequestSense_T));
4848 if (GenericRewind(INDEX_TAPECTL) < 0)
4850 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("LogSense : Rewind failed\n"));
4851 free(pRequestSense);
4857 * Try to read the tape label
4859 if (pDev[INDEX_TAPE].inqdone == 1)
4861 if (pDev[INDEX_TAPE].devopen == 1)
4863 SCSI_CloseDevice(INDEX_TAPE);
4866 if ((chgscsi_result = (char *)tape_rdlabel(pDev[INDEX_TAPE].dev, &chgscsi_datestamp, &chgscsi_label)) == NULL)
4868 g_fprintf(StatFile, _("==== %s ==== %s ====\n"), chgscsi_datestamp, chgscsi_label);
4870 g_fprintf(StatFile, "%s\n", chgscsi_result);
4874 buffer = alloc(size);
4875 memset(buffer, 0, size);
4877 * Get the known log pages
4880 CDB[0] = SC_COM_LOG_SENSE;
4882 CDB[2] = 0x40; /* 0x40 for current values */
4887 MSB2(&CDB[7], size);
4890 if (SCSI_Run(INDEX_TAPECTL, Input, CDB, 10,
4894 SIZEOF(RequestSense_T)) != 0)
4896 DecodeSense(pRequestSense, "LogSense : ",debug_file);
4897 free(pRequestSense);
4904 LogSenseHeader = (LogSenseHeader_T *)buffer;
4905 nologpages = V2(LogSenseHeader->PageLength);
4906 logpages = alloc(nologpages);
4908 memcpy(logpages, buffer + SIZEOF(LogSenseHeader_T), nologpages);
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;
4915 CDB[2] = (u_char)(0x40 | logpages[count]);/* 0x40 for current values */
4920 MSB2(&CDB[7], size);
4923 if (SCSI_Run(INDEX_TAPECTL, Input, CDB, 10,
4927 SIZEOF(RequestSense_T)) != 0)
4929 DecodeSense(pRequestSense, "LogSense : ",debug_file);
4930 free(pRequestSense);
4937 LogSenseHeader = (LogSenseHeader_T *)buffer;
4938 length = V2(LogSenseHeader->PageLength);
4939 LogParameter = (LogParameter_T *)(buffer + SIZEOF(LogSenseHeader_T));
4941 * Decode the log pages
4943 p = (struct LogPageDecode *)&DecodePages;
4946 dump_hex((u_char *)LogParameter, 64, DEBUG_INFO, SECTION_SCSI);
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);
4952 g_fprintf(StatFile, "\n");
4959 g_fprintf(StatFile, _("Logpage No %d = %x\n"), count ,logpages[count]);
4961 while ((u_char *)LogParameter < (buffer + length)) {
4962 i = LogParameter->ParameterLength;
4963 ParameterCode = V2(LogParameter->ParameterCode);
4966 value = V1((u_char *)LogParameter + SIZEOF(LogParameter_T));
4967 g_fprintf(StatFile, _("ParameterCode %02X = %u(%d)\n"), ParameterCode, value, i);
4970 value = V2((u_char *)LogParameter + SIZEOF(LogParameter_T));
4971 g_fprintf(StatFile, _("ParameterCode %02X = %u(%d)\n"), ParameterCode, value, i);
4974 value = V3((u_char *)LogParameter + SIZEOF(LogParameter_T));
4975 g_fprintf(StatFile, _("ParameterCode %02X = %u(%d)\n"), ParameterCode, value, i);
4978 value = V4((u_char *)LogParameter + SIZEOF(LogParameter_T));
4979 g_fprintf(StatFile, _("ParameterCode %02X = %u(%d)\n"), ParameterCode, value, i);
4982 value = V5((u_char *)LogParameter + SIZEOF(LogParameter_T));
4983 g_fprintf(StatFile, _("ParameterCode %02X = %u(%d)\n"), ParameterCode, value, i);
4986 g_fprintf(StatFile, _("ParameterCode %02X size %d\n"), ParameterCode, i);
4988 LogParameter = (LogParameter_T *)((u_char *)LogParameter + SIZEOF(LogParameter_T) + i);
4990 g_fprintf(StatFile, "\n");
4997 * Reset the cumulative counters
4999 CDB[0] = SC_COM_LOG_SELECT;
5010 if (SCSI_Run(INDEX_TAPECTL, Input, CDB, 10,
5014 SIZEOF(RequestSense_T)) != 0)
5016 DecodeSense(pRequestSense, "LogSense : ",debug_file);
5017 free(pRequestSense);
5027 free(pRequestSense);
5034 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("##### STOP LogSense\n"));
5039 WriteErrorCountersPage(
5040 LogParameter_T * buffer,
5045 LogParameter_T *LogParameter;
5046 unsigned ParameterCode;
5047 LogParameter = buffer;
5049 g_fprintf(StatFile, _("\tWrite Error Counters Page\n"));
5051 while ((u_char *)LogParameter < ((u_char *)buffer + length)) {
5052 i = LogParameter->ParameterLength;
5053 ParameterCode = V2(LogParameter->ParameterCode);
5056 if (Decode(LogParameter, &value) == 0) {
5057 switch (ParameterCode) {
5059 g_fprintf(StatFile, _("%-30s = %u\n"),
5060 _("Total Rewrites"),
5064 g_fprintf(StatFile, _("%-30s = %u\n"),
5065 _("Total Errors Corrected"),
5069 g_fprintf(StatFile, _("%-30s = %u\n"),
5070 _("Total Times E. Processed"),
5074 g_fprintf(StatFile, _("%-30s = %u\n"),
5075 _("Total Bytes Processed"),
5079 g_fprintf(StatFile, _("%-30s = %u\n"),
5080 _("Total Unrecoverable Errors"),
5084 g_fprintf(StatFile, _("Unknown ParameterCode %02X = %u(%d)\n"),
5090 g_fprintf(StatFile, _("Error decoding Result\n"));
5092 LogParameter = (LogParameter_T *)((u_char *)LogParameter + SIZEOF(LogParameter_T) + i);
5097 ReadErrorCountersPage(
5098 LogParameter_T * buffer,
5103 LogParameter_T *LogParameter;
5104 unsigned ParameterCode;
5105 LogParameter = buffer;
5107 g_fprintf(StatFile, _("\tRead Error Counters Page\n"));
5109 while ((u_char *)LogParameter < ((u_char *)buffer + length)) {
5110 i = LogParameter->ParameterLength;
5111 ParameterCode = V2(LogParameter->ParameterCode);
5114 if (Decode(LogParameter, &value) == 0) {
5115 switch (ParameterCode) {
5117 g_fprintf(StatFile, _("%-30s = %u\n"),
5122 g_fprintf(StatFile, _("%-30s = %u\n"),
5123 _("Total Errors Corrected"),
5127 g_fprintf(StatFile, _("%-30s = %u\n"),
5128 _("Total Times E. Processed"),
5132 g_fprintf(StatFile, _("%-30s = %u\n"),
5133 _("Total Bytes Processed"),
5137 g_fprintf(StatFile, _("%-30s = %u\n"),
5138 _("Total Unrecoverable Errors"),
5142 g_fprintf(StatFile, _("Unknown ParameterCode %02X = %u(%d)\n"),
5148 g_fprintf(StatFile, _("Error decoding Result\n"));
5150 LogParameter = (LogParameter_T *)((u_char *)LogParameter + SIZEOF(LogParameter_T) + i);
5156 LogParameter_T * buffer,
5161 LogParameter_T *LogParameter;
5162 unsigned ParameterCode;
5163 LogParameter = buffer;
5165 g_fprintf(StatFile, _("\tData compression transfer Page\n"));
5167 while ((u_char *)LogParameter < ((u_char *)buffer + length)) {
5168 i = LogParameter->ParameterLength;
5169 ParameterCode = V2(LogParameter->ParameterCode);
5172 if (Decode(LogParameter, &value) == 0) {
5173 switch (ParameterCode) {
5175 g_fprintf(StatFile, _("Unknown ParameterCode %02X = %u(%d)\n"),
5181 LogParameter = (LogParameter_T *)((u_char *)LogParameter + SIZEOF(LogParameter_T) + i);
5187 LogParameter_T * buffer,
5192 LogParameter_T *LogParameter;
5193 unsigned ParameterCode;
5194 LogParameter = buffer;
5196 g_fprintf(StatFile, _("\tDrive Counters Page\n"));
5198 while ((u_char *)LogParameter < ((unsigned char *)buffer + length)) {
5199 i = LogParameter->ParameterLength;
5200 ParameterCode = V2(LogParameter->ParameterCode);
5203 if (Decode(LogParameter, &value) == 0) {
5204 switch (ParameterCode) {
5206 g_fprintf(StatFile, _("%-30s = %u\n"),
5211 g_fprintf(StatFile, _("%-30s = %u\n"),
5212 _("Total write drive errors"),
5216 g_fprintf(StatFile, _("%-30s = %u\n"),
5217 _("Total read drive errors"),
5221 g_fprintf(StatFile, _("Unknown ParameterCode %02X = %u(%d)\n"),
5227 LogParameter = (LogParameter_T *)((u_char *)LogParameter + SIZEOF(LogParameter_T) + i);
5233 LogParameter_T * buffer,
5238 LogParameter_T *LogParameter;
5239 unsigned ParameterCode;
5240 LogParameter = buffer;
5242 g_fprintf(StatFile, _("\tData Compression Page\n"));
5244 while ((u_char *)LogParameter < ((unsigned char *)buffer + length)) {
5245 i = LogParameter->ParameterLength;
5246 ParameterCode = V2(LogParameter->ParameterCode);
5249 if (Decode(LogParameter, &value) == 0) {
5250 switch (ParameterCode) {
5252 g_fprintf(StatFile, _("%-30s = %u\n"),
5253 _("KB to Compressor"),
5257 g_fprintf(StatFile, _("%-30s = %u\n"),
5262 g_fprintf(StatFile, _("Unknown ParameterCode %02X = %u(%d)\n"),
5268 LogParameter = (LogParameter_T *)((u_char *)LogParameter + SIZEOF(LogParameter_T) + i);
5274 LogParameter_T * buffer,
5279 LogParameter_T *LogParameter;
5280 unsigned ParameterCode;
5281 LogParameter = buffer;
5283 g_fprintf(StatFile, _("\tDrive Usage Information Page\n"));
5285 while ((u_char *)LogParameter < ((unsigned char *)buffer + length)) {
5286 i = LogParameter->ParameterLength;
5287 ParameterCode = V2(LogParameter->ParameterCode);
5290 if (Decode(LogParameter, &value) == 0) {
5291 switch (ParameterCode) {
5299 g_fprintf(StatFile, _("%-30s = %u\n"),
5300 _("Total Load Count"),
5304 g_fprintf(StatFile, _("%-30s = %u\n"),
5305 _("MinutesSince Last Clean"),
5312 g_fprintf(StatFile, _("%-30s = %u\n"),
5313 _("Cleaning Count"),
5324 g_fprintf(StatFile, _("%-30s = %u\n"),
5333 g_fprintf(StatFile, _("Unknown ParameterCode %02X = %u(%d)\n"),
5339 LogParameter = (LogParameter_T *)((u_char *)LogParameter + SIZEOF(LogParameter_T) + i);
5345 LogParameter_T * LogParameter,
5349 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("##### START Decode\n"));
5350 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("Decode Parameter with length %d\n"), LogParameter->ParameterLength);
5353 switch (LogParameter->ParameterLength) {
5355 *value = V1((u_char *)LogParameter + SIZEOF(LogParameter_T));
5358 *value = V2((u_char *)LogParameter + SIZEOF(LogParameter_T));
5361 *value = V3((u_char *)LogParameter + SIZEOF(LogParameter_T));
5364 *value = V4((u_char *)LogParameter + SIZEOF(LogParameter_T));
5367 *value = V5((u_char *)LogParameter + SIZEOF(LogParameter_T));
5370 *value = V6((u_char *)LogParameter + SIZEOF(LogParameter_T));
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"));
5379 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("Result = %d\n"), *value);
5380 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("##### STOP Decode(0)\n"));
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"));
5396 g_printf(_("%s Null Pointer ....\n"), device);
5405 u_char buffer[1024];
5410 (void)option; /* Quiet unused parameter warning */
5412 if ((ip=fopen("/tmp/chg-scsi-trace", "r")) == NULL)
5417 for (x = 0; x < 1024; x++)
5419 if (fscanf(ip, "%2x", &bufferx) == EOF)
5424 buffer[x] = (u_char)bufferx;
5428 DecodeModeSense(&buffer[0], 12, "DLT448ElementStatus :", 0, debug_file);
5433 * Display all Information we can get about the library....
5440 char * changer_file,
5444 extern OpenFiles_T *pDev;
5447 ExtendedRequestSense_T ExtRequestSense;
5450 ChangerCMD_T *p = (ChangerCMD_T *)&ChangerIO;
5451 pbarcoderes = alloc(SIZEOF(MBC_T));
5452 memset(pbarcoderes, 0, SIZEOF(MBC_T));
5454 if (pModePage == NULL) {
5455 pModePage = alloc(0xff);
5458 if ((out = fdopen(1 , "w")) == NULL)
5460 g_printf(_("Error fdopen stdout\n"));
5466 if (strcmp("types", option) == 0 || strcmp("all", option) == 0)
5468 while(p->ident != NULL)
5470 g_printf (_("Ident = %s, type = %s\n"),p->ident, p->type);
5476 if (strcmp("robot", option) == 0 || strcmp("all", option) == 0)
5478 if (ElementStatusValid == 0)
5480 if (pDev[INDEX_CHANGER].functions->function_status(pDev[INDEX_CHANGER].fd, 1) != 0)
5482 g_printf(_("Can not initialize changer status\n"));
5489 /* 0123456789012345678901234567890123456789012 */
5492 g_printf(_("Address Type Status From Barcode Label\n"));
5494 g_printf(_("Address Type Status From\n"));
5496 g_printf(_("-------------------------------------------\n"));
5499 for ( x = 0; x < MTE; x++)
5502 g_printf(_("%07d MTE %s %04d %s "),pMTE[x].address,
5503 (pMTE[x].full ? _("Full ") :_("Empty")),
5504 pMTE[x].from, pMTE[x].VolTag);
5506 if (pMTE[x].full == 1)
5508 pbarcoderes->action = BARCODE_BARCODE;
5509 strncpy(pbarcoderes->data.barcode, pMTE[x].VolTag,
5510 SIZEOF(pbarcoderes->data.barcode));
5512 if (MapBarCode(labelfile, pbarcoderes) == 0 )
5514 g_printf(_("No mapping\n"));
5516 g_printf(_("%s \n"),pbarcoderes->data.voltag);
5522 g_printf(_("%07d MTE %s %04d \n"),pMTE[x].address,
5523 (pMTE[x].full ? _("Full ") :_("Empty")),
5528 for ( x = 0; x < STE; x++)
5531 g_printf(_("%07d STE %s %04d %s "),pSTE[x].address,
5532 (pSTE[x].full ? _("Full "):_("Empty")),
5533 pSTE[x].from, pSTE[x].VolTag);
5535 if (pSTE[x].full == 1)
5537 pbarcoderes->action = BARCODE_BARCODE;
5538 strncpy(pbarcoderes->data.barcode, pSTE[x].VolTag,
5539 SIZEOF(pbarcoderes->data.barcode));
5541 if (MapBarCode(labelfile, pbarcoderes) == 0 )
5543 g_printf(_("No mapping\n"));
5545 g_printf(_("%s \n"),pbarcoderes->data.voltag);
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);
5557 for ( x = 0; x < DTE; x++)
5560 g_printf(_("%07d DTE %s %04d %s "),pDTE[x].address,
5561 (pDTE[x].full ? _("Full") : _("Empty")),
5562 pDTE[x].from, pDTE[x].VolTag);
5564 if (pDTE[x].full == 1)
5566 pbarcoderes->action = BARCODE_BARCODE;
5567 strncpy(pbarcoderes->data.barcode, pDTE[x].VolTag,
5568 SIZEOF(pbarcoderes->data.barcode));
5570 if (MapBarCode(labelfile, pbarcoderes) == 0 )
5572 g_printf(_("No mapping\n"));
5574 g_printf("%s \n",pbarcoderes->data.voltag);
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);
5586 for ( x = 0; x < IEE; x++)
5589 g_printf(_("%07d IEE %s %04d %s "),pIEE[x].address,
5590 (pIEE[x].full ? _("Full ") : _("Empty")),
5591 pIEE[x].from, pIEE[x].VolTag);
5593 if (pIEE[x].full == 1)
5595 pbarcoderes->action = BARCODE_BARCODE;
5596 strncpy(pbarcoderes->data.barcode, pIEE[x].VolTag,
5597 SIZEOF(pbarcoderes->data.barcode));
5599 if (MapBarCode(labelfile, pbarcoderes) == 0 )
5601 g_printf(_("No mapping\n"));
5603 g_printf(_("%s \n"),pbarcoderes->data.voltag);
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);
5617 if (strcmp("sense", option) == 0 || strcmp("all", option) == 0)
5619 if (pDev[INDEX_CHANGER].SCSI == 1)
5621 g_printf(_("\nSense Status from robot:\n"));
5622 RequestSense(INDEX_CHANGER , &ExtRequestSense, 0);
5623 DecodeExtSense(&ExtRequestSense, "", out);
5626 if (pDev[INDEX_TAPE].SCSI == 1)
5629 g_printf(_("Sense Status from tape (tapectl):\n"));
5630 RequestSense(INDEX_TAPE, &ExtRequestSense, 0);
5631 DecodeExtSense(&ExtRequestSense, "", out);
5634 if (pDev[INDEX_TAPECTL].SCSI == 1)
5637 g_printf(_("Sense Status from tape (tapectl):\n"));
5638 RequestSense(INDEX_TAPECTL, &ExtRequestSense, 0);
5639 DecodeExtSense(&ExtRequestSense, "", out);
5643 if (strcmp("ModeSenseRobot", option) == 0 || strcmp("all", option) == 0)
5646 if (SCSI_ModeSense(INDEX_CHANGER, pModePage, 0xff, 0x08, 0x3f) == 0)
5648 DecodeModeSense(pModePage, 0, "Changer :" , 0, out);
5652 if (strcmp("ModeSenseTape", option) == 0 || strcmp("all", option) == 0)
5654 if (pDev[INDEX_TAPECTL].SCSI == 1)
5657 if (SCSI_ModeSense(INDEX_TAPECTL, pModePage, 0xff, 0x0, 0x3f) == 0)
5659 DecodeModeSense(pModePage, 0, "Tape :" , 1, out);
5664 if (strcmp("fd", option) == 0 || strcmp("all", option) == 0)
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");
5674 if (GenericClean("") == 1)
5675 g_printf(_("Tape needs cleaning\n"));
5688 size_t row_count = 0;
5691 while (row_count < size)
5693 DebugPrint(level, section,"%02X ", (u_char)p[row_count]);
5694 if (((row_count + 1) % 16) == 0)
5697 for (x = 16; x > 0; x--)
5699 if (isalnum((u_char)p[row_count - x + 1 ]))
5700 DebugPrint(level, section,"%c",(u_char)p[row_count - x + 1]);
5702 DebugPrint(level, section,".");
5704 DebugPrint(level, section,"\n");
5708 DebugPrint(level, section,"\n");
5718 for (x = (ssize_t)length; x >= 0 && !isalnum((int)string[x]); x--)
5728 (void)level; /* Quiet unused parameter warning */
5730 dbprintf(_("ChgExit in %s, reason %s\n"), where, reason);
5731 g_fprintf(stderr,"%s\n",reason);
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
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
5749 Direction_T Direction,
5753 size_t DataBufferLength,
5754 RequestSense_T * pRequestSense,
5755 size_t RequestSenseLength)
5760 RequestSense_T *pRqS;
5762 /* Basic sanity checks */
5763 assert(CDB_Length <= UCHAR_MAX);
5764 assert(RequestSenseLength <= UCHAR_MAX);
5766 pRqS = (RequestSense_T *)pRequestSense;
5768 DebugPrint(DEBUG_INFO, SECTION_SCSI, _("SCSI_Run TestUnitReady\n"));
5769 while (!ok && maxtries < MAXTRIES)
5771 ret = SCSI_TestUnitReady(DeviceFD, (RequestSense_T *)pRequestSense );
5772 DebugPrint(DEBUG_INFO, SECTION_SCSI, _("SCSI_Run TestUnitReady ret %d\n"),ret);
5779 switch (SenseHandler(DeviceFD, 0, pRqS->SenseKey, pRqS->AdditionalSenseCode, pRqS->AdditionalSenseCodeQualifier, pRqS))
5782 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_Run (TestUnitReady) SENSE_NO\n"));
5785 case SENSE_TAPE_NOT_ONLINE:
5786 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_Run (TestUnitReady) SENSE_TAPE_NOT_ONLINE\n"));
5790 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_Run (TestUnitReady) SENSE_IGNORE\n"));
5794 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("SCSI_Run (TestUnitReady) SENSE_ABORT\n"));
5798 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_Run (TestUnitReady) SENSE_RETRY\n"));
5801 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_Run (TestUnitReady) default (SENSE)\n"));
5807 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("SCSI_Run (TestUnitReady) SCSI_ERROR\n"));
5811 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_Run (TestUnitReady) SCSI_BUSY\n"));
5814 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_Run (TestUnitReady) SCSI_CHECK\n"));
5817 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("SCSI_Run (TestUnitReady) unknown (%d)\n"),ret);
5827 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_Run TestUnitReady after %d sec:\n"),maxtries);
5831 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("SCSI_Run Exit %d\n"),ret);
5838 while (!ok && maxtries < MAXTRIES)
5840 ret = SCSI_ExecuteCommand(DeviceFD,
5847 RequestSenseLength);
5849 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_Run Exit %d\n"),ret);
5856 switch (SenseHandler(DeviceFD, 0, pRqS->SenseKey, pRqS->AdditionalSenseCode, pRqS->AdditionalSenseCodeQualifier, pRqS))
5859 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_Run SENSE_NO\n"));
5862 case SENSE_TAPE_NOT_ONLINE:
5863 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_Run SENSE_TAPE_NOT_ONLINE\n"));
5867 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_Run SENSE_IGNORE\n"));
5871 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("SCSI_Run SENSE_ABORT\n"));
5875 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_Run SENSE_RETRY\n"));
5878 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_Run default (SENSE)\n"));
5884 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("SCSI_Run SCSI_ERROR\n"));
5888 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_Run SCSI_BUSY\n"));
5891 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_Run (TestUnitReady) SCSI_CHECK\n"));
5894 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("SCSI_Run (TestUnitReady) unknown (%d)\n"),ret);
5910 * This a vendor specific command !!!!!!
5911 * First seen at AIT :-)
5920 RequestSense_T *pRequestSense;
5926 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("##### START SCSI_AlignElements\n"));
5928 pRequestSense = alloc(SIZEOF(RequestSense_T));
5930 for (retry = 0; retry < MAX_RETRIES; retry++)
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 !! */
5942 ret = SCSI_Run(DeviceFD, Input, CDB, 12,
5943 NULL, 0, pRequestSense, SIZEOF(RequestSense_T));
5945 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_AlignElements : SCSI_Run = %d\n"), ret);
5946 DecodeSense(pRequestSense, _("SCSI_AlignElements :"),debug_file);
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");
5960 switch(SenseHandler(DeviceFD, 0 , pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
5963 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_AlignElements : SENSE_IGNORE\n"));
5967 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_AlignElements : SENSE_RETRY no %d\n"), retry);
5970 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("SCSI_AlignElements : SENSE_ABORT\n"));
5973 case SENSE_TAPE_NOT_UNLOADED:
5974 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("SCSI_AlignElements : Tape still loaded, eject failed\n"));
5978 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_AlignElements : end %d\n"), pRequestSense->SenseKey);
5979 return(pRequestSense->SenseKey);
5985 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_AlignElements : end %d\n"), ret);
5990 DebugPrint(DEBUG_ERROR, SECTION_SCSI,
5991 _("SCSI_AlignElements: Retries exceeded = %d\n"), retry);
6003 RequestSense_T *pRequestSense;
6009 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("##### START SCSI_Move\n"));
6011 pRequestSense = alloc(SIZEOF(RequestSense_T));
6013 for (retry = 0; (ret != 0) && (retry < MAX_RETRIES); retry++)
6015 CDB[0] = SC_MOVE_MEDIUM;
6018 CDB[3] = chm; /* Address of CHM */
6026 ret = SCSI_Run(DeviceFD, Input, CDB, 12,
6027 NULL, 0, pRequestSense, SIZEOF(RequestSense_T));
6029 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_Move : SCSI_Run = %d\n"), ret);
6030 DecodeSense(pRequestSense, _("SCSI_Move :"),debug_file);
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");
6044 switch(SenseHandler(DeviceFD, 0 , pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
6047 dbprintf(_("SCSI_Move : SENSE_IGNORE\n"));
6051 dbprintf(_("SCSI_Move : SENSE_RETRY no %d\n"), retry);
6054 dbprintf(_("SCSI_Move : SENSE_ABORT\n"));
6057 case SENSE_TAPE_NOT_UNLOADED:
6058 dbprintf(_("SCSI_Move : Tape still loaded, eject failed\n"));
6062 dbprintf(_("SCSI_Move : end %d\n"), pRequestSense->SenseKey);
6063 return(pRequestSense->SenseKey);
6068 dbprintf(_("SCSI_Move : end %d\n"), ret);
6075 RequestSense_T * pRequestSense,
6082 dbprintf(_("##### START SCSI_LoadUnload\n"));
6084 CDB[0] = SC_COM_UNLOAD;
6092 ret = SCSI_Run(DeviceFD, Input, CDB, 6,
6095 SIZEOF(RequestSense_T));
6099 dbprintf(_("SCSI_Unload : failed %d\n"), ret);
6104 dbprintf(_("##### STOP SCSI_LoadUnload\n"));
6111 RequestSense_T * pRequestSense)
6116 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("##### START SCSI_TestUnitReady\n"));
6118 CDB[0] = SC_COM_TEST_UNIT_READY;
6125 ret = SCSI_ExecuteCommand(DeviceFD, Input, CDB, 6,
6128 SIZEOF(RequestSense_T));
6131 * We got an error, so let the calling function handle this
6135 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("###### STOP SCSI_TestUnitReady (1)\n"));
6141 * OK, no error condition
6142 * If no sense is set, the Unit is ready
6144 if (pRequestSense->ErrorCode == 0 && pRequestSense->SenseKey == 0)
6146 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("###### STOP SCSI_TestUnitReady (1)\n"));
6154 if (pRequestSense->ErrorCode != 0){
6155 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("###### STOP SCSI_TestUnitReady ErrorCode set\n"));
6157 if (pRequestSense->SenseKey != 0) {
6158 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("###### STOP SCSI_TestUnitReady Sense Key set\n"));
6160 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("###### STOP SCSI_TestUnitReady (0)\n"));
6175 RequestSense_T *pRequestSense;
6180 dbprintf(_("##### START SCSI_ModeSelect\n"));
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);
6187 memcpy(&sendbuf[4], buffer, (size_t)length);
6188 dump_hex(sendbuf, (size_t)length+4, DEBUG_INFO, SECTION_SCSI);
6190 for (retry = 0; (ret != 0) && (retry < MAX_RETRIES); retry++)
6192 memset(pRequestSense, 0, SIZEOF(RequestSense_T));
6194 CDB[0] = SC_COM_MODE_SELECT;
6195 CDB[1] = (u_char)(((lun << 5) & 0xF0) | ((mode << 4) & 0x10) | (save & 1));
6198 CDB[4] = (u_char)(length + 4);
6200 ret = SCSI_Run(DeviceFD, Output, CDB, 6,
6204 SIZEOF(RequestSense_T));
6207 dbprintf(_("SCSI_ModeSelect : ret %d\n"), ret);
6214 switch(SenseHandler(DeviceFD, 0, pRequestSense->SenseKey,
6215 pRequestSense->AdditionalSenseCode,
6216 pRequestSense->AdditionalSenseCodeQualifier,
6220 dbprintf(_("SCSI_ModeSelect : SENSE_IGNORE\n"));
6225 dbprintf(_("SCSI_ModeSelect : SENSE_RETRY no %d\n"), retry);
6229 ret = pRequestSense->SenseKey;
6235 dbprintf(_("SCSI_ModeSelect end: %d\n"), ret);
6238 free(pRequestSense);
6254 RequestSense_T *pRequestSense;
6258 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("##### START SCSI_ModeSense\n"));
6260 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_ModeSense start length = %d:\n"), size);
6261 pRequestSense = alloc(SIZEOF(RequestSense_T));
6263 while (ret && retry < MAX_RETRIES)
6265 memset(pRequestSense, 0, SIZEOF(RequestSense_T));
6266 memset(buffer, 0, size);
6268 CDB[0] = SC_COM_MODE_SENSE;
6274 ret = SCSI_Run(DeviceFD, Input, CDB, 6,
6278 SIZEOF(RequestSense_T));
6287 switch(SenseHandler(DeviceFD, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
6290 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_ModeSense : SENSE_IGNORE\n"));
6294 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_ModeSense : SENSE_RETRY no %d\n"), retry);
6297 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_ModeSense : end %d\n"), pRequestSense->SenseKey);
6298 return(pRequestSense->SenseKey);
6305 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_ModeSense end: %d\n"), ret);
6312 SCSIInquiry_T * buffer,
6316 RequestSense_T *pRequestSense;
6321 assert(size <= UCHAR_MAX);
6323 DebugPrint(DEBUG_INFO, SECTION_SCSI, _("##### START SCSI_Inquiry\n"));
6325 DebugPrint(DEBUG_INFO, SECTION_SCSI, _("SCSI_Inquiry start length = %d:\n"), size);
6327 pRequestSense = alloc((size_t)size);
6329 while (retry > 0 && retry < MAX_RETRIES)
6331 memset(buffer, 0, size);
6332 CDB[0] = SC_COM_INQUIRY;
6336 CDB[4] = (u_char)size;
6339 ret = SCSI_ExecuteCommand(DeviceFD, Input, CDB, 6,
6343 SIZEOF(RequestSense_T));
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);
6357 switch(SenseHandler(DeviceFD, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
6360 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_Inquiry : SENSE_IGNORE\n"));
6364 DebugPrint(DEBUG_INFO, SECTION_SCSI, _("SCSI_Inquiry : SENSE_RETRY no %d\n"), retry);
6367 DebugPrint(DEBUG_ERROR, SECTION_SCSI, _("SCSI_Inquiry : end %d\n"), pRequestSense->SenseKey);
6368 return(pRequestSense->SenseKey);
6375 dump_hex((u_char *)buffer, size, DEBUG_INFO, SECTION_SCSI);
6376 DebugPrint(DEBUG_INFO, SECTION_SCSI, _("SCSI_Inquiry : end %d\n"), ret);
6382 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_Inquiry end: %d\n"), ret);
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
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.
6398 SCSI_ReadElementStatus(
6404 size_t NoOfElements,
6405 size_t DescriptorSize,
6409 size_t DataBufferLength;
6410 ElementStatusData_T *ElementStatusData;
6411 RequestSense_T *pRequestSense;
6415 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("##### START SCSI_ReadElementStatus\n"));
6417 pRequestSense = alloc(SIZEOF(RequestSense_T));
6420 * How many elements, if <= 0 than exit with an fatal error
6422 if (NoOfElements == 0)
6424 ChgExit("SCSI_ReadElementStatus",_("No of Elements passed are le 0"),FATAL);
6428 VolTag = (u_char)((VolTag << 4) & 0x10);
6429 type = (u_char)(type & 0xf);
6430 lun = (u_char)((lun << 5) & 0xe0);
6432 /* if DescriptorSize == 0
6433 * try to get the allocation length for the second call
6435 if (DescriptorSize == 0)
6437 *data = newalloc(*data, 8);
6438 memset(*data, 0, 8);
6440 while (retry > 0 && retry < MAX_RETRIES)
6442 memset(pRequestSense, 0, SIZEOF(RequestSense_T) );
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 */
6453 ret = SCSI_Run(DeviceFD, Input, CDB, 12,
6455 pRequestSense, SIZEOF(RequestSense_T));
6457 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_ReadElementStatus : (1) SCSI_Run %d\n"), ret);
6460 DecodeSense(pRequestSense, "SCSI_ReadElementStatus :",debug_file);
6461 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("##### STOP SCSI_ReadElementStatus (%d)\n"),ret);
6467 switch(SenseHandler(DeviceFD, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
6470 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_ModeSense : SENSE_IGNORE\n"));
6474 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_ModeSense : SENSE_RETRY no %d\n"), retry);
6478 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_ModeSense : end %d\n"), pRequestSense->SenseKey);
6479 return(pRequestSense->SenseKey);
6491 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("##### STOP SCSI_ReadElementStatus (%d)\n"),ret);
6496 ElementStatusData = (ElementStatusData_T *)*data;
6497 DataBufferLength = V3(ElementStatusData->count);
6499 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_ReadElementStatus: DataBufferLength %X, ret %d\n"),DataBufferLength, ret);
6501 dump_hex(*data, 8, DEBUG_INFO, SECTION_ELEMENT);
6502 } else { /* DescriptorSize != 0 */
6503 DataBufferLength = NoOfElements * DescriptorSize;
6506 DataBufferLength = DataBufferLength + 8;
6507 *data = newalloc(*data, DataBufferLength);
6508 memset(*data, 0, DataBufferLength);
6511 while (retry > 0 && retry < MAX_RETRIES)
6513 memset(pRequestSense, 0, SIZEOF(RequestSense_T) );
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 */
6524 ret = SCSI_Run(DeviceFD, Input, CDB, 12,
6525 *data, DataBufferLength,
6526 pRequestSense, SIZEOF(RequestSense_T));
6529 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_ReadElementStatus : (2) SCSI_Run %d\n"), ret);
6532 DecodeSense(pRequestSense, _("SCSI_ReadElementStatus :"),debug_file);
6533 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("##### STOP SCSI_ReadElementStatus (%d)\n"),ret);
6539 switch(SenseHandler(DeviceFD, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
6542 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_ModeSense : SENSE_IGNORE\n"));
6546 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_ModeSense : SENSE_RETRY no %d\n"), retry);
6550 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_ModeSense : end %d\n"), pRequestSense->SenseKey);
6551 return(pRequestSense->SenseKey);
6564 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("##### STOP SCSI_ReadElementStatus (%d)\n"),ret);
6569 dump_hex(*data, DataBufferLength, DEBUG_INFO, SECTION_SCSI);
6570 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("##### STOP SCSI_ReadElementStatus (%d)\n"),ret);
6574 printf_arglist_function2(void DebugPrint, int, level, int, section, char *, fmt)
6580 time_t ti = time(NULL);
6582 if (changer->debuglevel)
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);
6595 arglist_start(argp, fmt);
6596 g_vsnprintf(buf, SIZEOF(buf), fmt, argp);
6597 if (dlevel >= level)
6599 if (section == dsection || dsection == 0)
6601 if (index(buf, '\n') != NULL && strlen(buf) > 1)
6603 dbprintf(_("%ld:%s"), (long)ti, buf);
6605 dbprintf("%s", buf);