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 * This used to be in tape-src/tapeio.c; this is the Device API version.
468 dev = device_open(devname);
469 if (dev->status != DEVICE_STATUS_SUCCESS) {
470 r = g_strdup(device_error_or_status(dev));
475 if (!device_configure(dev, TRUE) || !device_read_label(dev)) {
476 r = g_strdup(device_error_or_status(dev));
481 *datestamp = g_strdup(dev->volume_time);
482 *label = g_strdup(dev->volume_label);
488 * First all functions which are called from extern
493 * Print the scsi-changer-driver version
497 ChangerDriverVersion(void)
499 DebugPrint(DEBUG_ERROR, SECTION_INFO, "scsi-changer-driver: %s\n",rcsid);
504 * Try to generate an template which can be used as an example for the config file
510 extern OpenFiles_T *pDev;
514 g_printf(_("# Please replace every ??? with the correct parameter.\n"));
515 g_printf(_("# It is not possible to guess everything :-)\n"));
516 g_printf(_("# Remove the line if the option is not needed."));
517 g_printf(_("# Example: cleanmax if you have no cleaning tape"));
520 "number_configs 1 # Number of configs, you can have more than 1 config\n"
521 " # if you have for example more than one drive, or you\n"
522 " # to split your lib to use different dump levels\n"
525 "emubarcode 1 # If you drive has no barcode reader this will try\n"
526 " # keep an inventory of your tapes to find them faster\n"
529 "havebarcode 0 # Set this to 1 if you have a library with a\n"
530 " # barcode reader\n"
533 "debuglevel 0:0 # For debuging, see the docs /docs/TAPE-CHANGER\n"
536 "eject ??? # set this to 1 if your drive needs an eject before move\n"
539 "sleep ??? # How long to wait after an eject command before moving\n"
543 for (count = 0; count < CHG_MAXDEV ; count++)
547 if (pDev[count].inquiry != NULL && pDev[count].inquiry->type == TYPE_CHANGER)
549 g_printf(_("changerdev %s # This is the device to communicate with the robot\n"), pDev[count].dev);
556 * Did we reach the end of the list ?
557 * If no we found an changer and now we try to
558 * get the element status for the count of slots
560 if (count < CHG_MAXDEV)
562 pDev[count].functions->function_status(count, 1);
564 g_printf(_("changerdev ??? # Ups nothing found. Please check the docs\n"));
570 " # Here now comes the config for the first tape\n"));
572 "config 0 # This value is the one which is used in the amanda\n"
573 " # config file to tell the chg-scsi programm which tape\n"
574 " # and which slots to use\n"
577 "cleancart ??? # The slot where the cleaning tape is located\n"
578 " # remove it if you have no cleaning tape\n"
581 "drivenum 0 # Which tape drive to use if there are more than one drive\n"
584 "dev ??? # Which is the raw device to read/write data from the tape\n"
585 " # It is important to use the non rewinding tape, like\n"
586 " # /dev/nrst0 on linux, /dev/nrsa0 on BSD ....\n"
590 * OK now lets see if we have an direct SCSI channel
592 * If not thats not a problem
594 for (count = 0; count < CHG_MAXDEV; count++)
598 if (pDev[count].inquiry != NULL && pDev[count].inquiry->type == TYPE_TAPE)
601 "scsitapedev %s # This is the device to communicate with the tape\n"
602 " # to get some device stats, not so important, and\n"
603 " # if you run into problems delete it completely\n"
604 " #\n"), pDev[count].dev);
614 "startuse 0 # Which is the first slot to use\n"
617 "enduse %zu # Which is the last slot to use.\n"), STE);
620 "startuse ??? # Which is the first slot to use\n"
623 "enduse ??? # Which is the last slot to use.\n"));
626 " # Decrement this value by 1 if you have a\n"
627 " # cleaning tape in the last slot\n"
630 if ((cwd = getcwd(NULL, 0)) == NULL) {
631 cwd = _("<unknown>");
634 g_printf(_("statfile %s/tape0-slot #\n"),cwd);
635 g_printf(_("cleanfile %s/tape0-clean #\n"), cwd);
636 g_printf(_("usagecount %s/tape0-totaltime #\n"), cwd);
637 g_printf(_("tapestatus %s/tape0-tapestatus #\n"), cwd);
638 g_printf(_("labelfile %s/labelfile #\n"), cwd);
644 * Try to create a list of tapes and labels which are in the current
645 * magazin. The drive must be empty !!
647 * labelfile -> file name of the db
648 * drive -> which drive should we use
649 * eject -> the tape device needs an eject before move
650 * start -> start at slot start
651 * stop -> stop at slot stop
652 * clean -> if we have an cleaning tape than this is the slot number of it
659 * Check if the tape/changer is ready for the next move
660 * If an tape is loaded unload it and do initialize element status to
661 * get all labels if an bar code reader is installed
672 extern OpenFiles_T *pDev;
674 static int inv_done = 0; /* Inventory function called ?, marker to disable recursion */
675 MBC_T *pbarcoderes; /* Here we will pass the parameter to MapBarCode and get the result */
677 (void)start; /* Quiet unused parameter warning */
678 (void)stop; /* Quiet unused parameter warning */
680 DebugPrint(DEBUG_INFO,SECTION_MAP_BARCODE, _("##### START Inventory\n"));
681 pbarcoderes = alloc(SIZEOF(MBC_T));
682 memset(pbarcoderes, 0 , SIZEOF(MBC_T));
686 DebugPrint(DEBUG_INFO,SECTION_MAP_BARCODE, _("##### STOP inv_done -> %d Inventory\n"),inv_done);
692 barcode = BarCode(INDEX_CHANGER);
694 pbarcoderes->action = RESET_VALID;
696 MapBarCode(labelfile,pbarcoderes);
699 * Check if an tape is loaded, if yes unload it
700 * and do an INIT ELEMENT STATUS
703 if (pDTE[0].status == 'F')
707 (void)eject_tape("", eject);
709 (void)unload(INDEX_TAPE, 0, 0);
712 GenericResetStatus(INDEX_CHANGER);
714 for (x = 0; x < STE; x++)
716 if (x == (size_t)clean)
722 * Load the tape, on error try the next
723 * error could be an empty slot for example
725 if (load(INDEX_CHANGER, drive, x ) != 0)
727 DebugPrint(DEBUG_ERROR,SECTION_MAP_BARCODE, _("Load drive(%d) from(%d) failed\n"), drive, x);
732 * Wait until the tape is ready
734 Tape_Ready(INDEX_TAPECTL, 60);
736 SCSI_CloseDevice(INDEX_TAPE);
738 if ((chgscsi_result = (char *)tape_rdlabel(pDev[INDEX_TAPE].dev, &chgscsi_datestamp, &chgscsi_label)) == NULL)
740 pbarcoderes->action = UPDATE_SLOT;
741 strncpy(pbarcoderes->data.voltag, chgscsi_label,
742 SIZEOF(pbarcoderes->data.voltag));
743 pbarcoderes->data.slot = x;
744 pbarcoderes->data.from = 0;
745 pbarcoderes->data.LoadCount = 1;
746 if (BarCode(INDEX_CHANGER) == 1)
748 strncpy(pbarcoderes->data.barcode, pDTE[drive].VolTag,
749 SIZEOF(pbarcoderes->data.barcode));
750 MapBarCode(labelfile, pbarcoderes);
752 MapBarCode(labelfile, pbarcoderes);
755 DebugPrint(DEBUG_ERROR,SECTION_MAP_BARCODE, _("Read label failed\n"));
760 (void)eject_tape("", eject);
763 (void)unload(INDEX_TAPE, drive, x);
765 DebugPrint(DEBUG_INFO,SECTION_MAP_BARCODE, _("##### STOP Inventory\n"));
770 * Check if the slot ist empty
771 * slot -> slot number to check
778 extern OpenFiles_T *pDev;
779 DebugPrint(DEBUG_INFO,SECTION_TAPE,_("##### START isempty\n"));
781 if (ElementStatusValid == 0)
783 if ( pDev[fd].functions->function_status(fd, 1) != 0)
785 DebugPrint(DEBUG_ERROR,SECTION_TAPE,_("##### STOP isempty [-1]\n"));
791 if (pSTE[slot].status == 'E')
793 DebugPrint(DEBUG_INFO,SECTION_TAPE,_("##### STOP isempty [1]\n"));
797 DebugPrint(DEBUG_INFO,SECTION_TAPE,_("##### STOP isempty [0]\n"));
805 extern OpenFiles_T *pDev;
806 /* Return 1 if cleaning is needed */
809 DebugPrint(DEBUG_INFO,SECTION_TAPE,_("##### START get_clean_state\n"));
811 if (pDev[INDEX_TAPECTL].SCSI == 0)
813 DebugPrint(DEBUG_ERROR,SECTION_TAPE,_("##### STOP get_clean_state [-1]\n"));
817 ret=pDev[INDEX_TAPECTL].functions->function_clean(tapedev);
818 DebugPrint(DEBUG_INFO,SECTION_TAPE,_("##### STOP get_clean_state [%d]\n"), ret);
824 * The parameter tapedev is not used.
825 * Type describes if we should force the SCSI eject if available
826 * normal eject is done with the ioctl
828 /* This function ejects the tape from the drive */
835 extern OpenFiles_T *pDev;
838 DebugPrint(DEBUG_INFO,SECTION_TAPE,_("##### START eject_tape %s\n"),tapedev);
839 if (pDev[INDEX_TAPECTL].functions == NULL)
843 * Try to read the label
845 if (pDev[INDEX_TAPE].avail == 1 && (changer->emubarcode == 1 || BarCode(INDEX_CHANGER)))
848 if (pDev[INDEX_TAPECTL].SCSI == 1 && pDev[INDEX_TAPECTL].avail) {
849 DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### eject_tape rewind\n");
850 pDev[INDEX_TAPECTL].functions->function_rewind(INDEX_TAPECTL);
852 DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### eject_tape rewind2\n");
853 pDev[INDEX_TAPE].functions->function_rewind(INDEX_TAPE);
856 if (pDev[INDEX_TAPE].devopen == 1)
858 DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### eject_tape close\n");
859 SCSI_CloseDevice(INDEX_TAPE);
862 DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### tape_eject tape_rdlabel\n");
863 chgscsi_result = (char *)tape_rdlabel(pDev[INDEX_TAPE].dev, &chgscsi_datestamp, &chgscsi_label);
866 if (pDev[INDEX_TAPECTL].SCSI == 1 && pDev[INDEX_TAPECTL].avail == 1 && type == 1)
868 DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### tape_eject eject\n");
869 ret=pDev[INDEX_TAPECTL].functions->function_eject(tapedev, type);
870 DebugPrint(DEBUG_INFO,SECTION_TAPE,_("##### STOP (SCSI)eject_tape [%d]\n"), ret);
875 if (pDev[INDEX_TAPE].avail == 1)
877 ret=Tape_Ioctl(INDEX_TAPE, IOCTL_EJECT);
878 DebugPrint(DEBUG_INFO,SECTION_TAPE,_("##### STOP (ioctl)eject_tape [%d]\n"), ret);
883 DebugPrint(DEBUG_INFO,SECTION_TAPE,_("##### STOP eject_tape [-1]\n"));
888 /* Find an empty slot, starting at start, ending at start+count */
895 extern OpenFiles_T *pDev;
899 DebugPrint(DEBUG_INFO,SECTION_ELEMENT,_("###### START find_empty\n"));
901 if (ElementStatusValid == 0)
903 if ( pDev[fd].functions->function_status(fd , 1) != 0)
905 DebugPrint(DEBUG_ERROR,SECTION_ELEMENT,
906 _("###### END find_empty [-1]\n"));
924 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,
925 _("start at %zu, end at %zu\n"),
929 for (x = start; x < end; x++)
931 if (pSTE[x].status == 'E')
933 DebugPrint(DEBUG_INFO,SECTION_ELEMENT,
934 _("###### END find_empty [%lu]\n"), x);
939 DebugPrint(DEBUG_ERROR,SECTION_ELEMENT,_("###### END find_empty [-1]\n"));
944 * See if the tape is loaded based on the information we
945 * got back from the ReadElementStatus
947 * -1 -> Error (Fatal)
948 * 0 -> drive is empty
949 * 1 -> drive is loaded
956 extern OpenFiles_T *pDev;
958 DebugPrint(DEBUG_INFO,SECTION_TAPE,_("###### START drive_loaded\n"));
959 DebugPrint(DEBUG_INFO,SECTION_TAPE,
960 _(" drive_loaded : fd %d drivenum %d \n"), fd, drivenum);
963 if (ElementStatusValid == 0)
965 if (pDev[INDEX_CHANGER].functions->function_status(INDEX_CHANGER, 1) != 0)
967 DebugPrint(DEBUG_ERROR,SECTION_TAPE,_("Fatal error\n"));
973 if (pDTE[drivenum].status == 'E') {
974 DebugPrint(DEBUG_INFO,SECTION_TAPE,_("###### STOP drive_loaded (empty)\n"));
978 DebugPrint(DEBUG_INFO,SECTION_TAPE,_("###### STOP drive_loaded (not empty)\n"));
984 * unload the specified drive into the specified slot
988 * Check if the MTE is empty
996 extern OpenFiles_T *pDev;
997 extern int do_inventory;
1000 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("###### START unload\n"));
1001 DebugPrint(DEBUG_INFO, SECTION_TAPE,
1002 _(" unload : fd %d, slot %d, drive %d \n"),
1004 pbarcoderes = alloc(SIZEOF(MBC_T));
1005 memset(pbarcoderes, 0, SIZEOF(MBC_T));
1008 * If the Element Status is not valid try to
1011 if (ElementStatusValid == 0)
1013 if (pDev[INDEX_CHANGER].functions->function_status(INDEX_CHANGER , 1) != 0)
1015 DebugPrint(DEBUG_ERROR, SECTION_TAPE,_("Element Status not valid, reset failed\n"));
1016 DebugPrint(DEBUG_ERROR, SECTION_TAPE,_("##### STOP unload (-1)\n"));
1023 DebugPrint(DEBUG_INFO, SECTION_TAPE,
1024 _(" unload : unload drive %d[%d] slot %d[%d]\n"),
1025 drive, pDTE[drive].address, slot, pSTE[slot].address);
1028 * Unloading an empty tape unit makes no sense
1029 * so return with an error
1031 if (pDTE[drive].status == 'E')
1033 DebugPrint(DEBUG_ERROR, SECTION_TAPE,_("unload : Drive %d address %d is empty\n"), drive, pDTE[drive].address);
1034 DebugPrint(DEBUG_ERROR, SECTION_TAPE,_("##### STOP unload (-1)\n"));
1041 * If the destination slot is full
1042 * try to find an enpty slot
1044 if (pSTE[slot].status == 'F')
1046 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("unload : Slot %d address %d is full\n"), drive, pSTE[slot].address);
1047 if ( ElementStatusValid == 0)
1049 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("unload: Element Status not valid, can't find an empty slot\n"));
1055 slot = find_empty(fd, 0, 0);
1058 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("unload: No Empty slot found\n"));
1063 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("unload : found empty one, try to unload to slot %d\n"), slot);
1069 * If eject is not set we must read the label info
1072 if (changer->eject == 0)
1074 if (pDev[INDEX_TAPE].avail == 1 && (changer->emubarcode == 1 || BarCode(INDEX_CHANGER)))
1077 if (pDev[INDEX_TAPECTL].SCSI == 1 && pDev[INDEX_TAPECTL].avail) {
1078 pDev[INDEX_TAPECTL].functions->function_rewind(INDEX_TAPECTL);
1080 pDev[INDEX_TAPE].functions->function_rewind(INDEX_TAPE);
1083 if (pDev[INDEX_TAPE].devopen == 1)
1085 SCSI_CloseDevice(INDEX_TAPE);
1088 chgscsi_result = (char *)tape_rdlabel(pDev[INDEX_TAPE].dev, &chgscsi_datestamp, &chgscsi_label);
1093 * Do the unload/move
1095 if (pDev[INDEX_CHANGER].functions->function_move(INDEX_CHANGER,
1096 pDTE[drive].address, pSTE[slot].address) != 0) {
1097 DebugPrint(DEBUG_ERROR, SECTION_TAPE,_("##### STOP unload (-1 move failed)\n"));
1107 if (pDev[INDEX_CHANGER].functions->function_status(INDEX_CHANGER , 1) != 0)
1109 DebugPrint(DEBUG_ERROR, SECTION_TAPE,_("##### STOP unload (-1 update status failed)\n"));
1116 * Did we get an error from tape_rdlabel
1117 * if no update the vol/label mapping
1118 * If chgscsi_label is NULL don't do it
1120 if (chgscsi_result == NULL && chgscsi_label != NULL && changer->labelfile != NULL)
1123 * OK this is only needed if we have emubarcode set
1124 * There we need an exact inventory to get the search function working
1125 * and returning correct results
1127 if (BarCode(INDEX_CHANGER) == 0 && changer->emubarcode == 1)
1130 * We got something, update the db
1131 * but before check if the db has as entry the slot
1132 * to where we placed the tape, if no force an inventory
1134 pbarcoderes->action = FIND_SLOT;
1135 strncpy(pbarcoderes->data.voltag, chgscsi_label,
1136 SIZEOF(pbarcoderes->data.voltag));
1137 strncpy(pbarcoderes->data.barcode, pSTE[slot].VolTag,
1138 SIZEOF(pbarcoderes->data.barcode));
1139 pbarcoderes->data.slot = 0;
1140 pbarcoderes->data.from = 0;
1141 pbarcoderes->data.LoadCount = 0;
1144 if ( MapBarCode(changer->labelfile, pbarcoderes) == 0) /* Nothing known about this, do an Inventory */
1148 if (slot != pbarcoderes->data.slot)
1150 DebugPrint(DEBUG_ERROR, SECTION_TAPE,_("Slot DB out of sync, slot %d != map %d"),slot, pbarcoderes->data.slot);
1157 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("##### STOP unload(0)\n"));
1164 * load the media from the specified element (slot) into the
1165 * specified data transfer unit (drive)
1166 * fd -> pointer to the internal device structure pDev
1167 * driver -> which drive in the library
1168 * slot -> the slot number from where to load
1170 * return -> 0 = success
1179 char *result = NULL; /* Needed for the result of tape_rdlabel */
1181 extern OpenFiles_T *pDev;
1182 extern int do_inventory;
1185 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("###### START load\n"));
1186 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("%-20s : fd %d, drive %d, slot %d \n"), "load", fd, drive, slot);
1187 pbarcoderes = alloc(SIZEOF(MBC_T));
1188 memset(pbarcoderes, 0 , SIZEOF(MBC_T));
1190 if (ElementStatusValid == 0)
1192 if (pDev[fd].functions->function_status(fd, 1) != 0)
1194 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,_("##### STOP load (-1)\n"));
1195 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,_("##### STOP load (-1 update status failed)\n"));
1203 * Check if the requested slot is in the range of available slots
1204 * The library starts counting at 1, we start at 0, so if the request slot
1205 * is ge than the value we got from the ModeSense fail with an return value
1208 if ((size_t)slot >= STE)
1210 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,_("load : slot %d ge STE %d\n"),slot, STE);
1211 ChgExit("load", _("slot >= STE"), FATAL);
1216 * And the same for the tape drives
1218 if (drive >= (int)DTE)
1220 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,_("load : drive %d ge DTE %d\n"),drive, DTE);
1221 ChgExit("load", _("drive >= DTE"), FATAL);
1225 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("load : load drive %d[%d] slot %d[%d]\n"),drive,
1226 pDTE[drive].address,
1228 pSTE[slot].address);
1230 if (pDTE[drive].status == 'F')
1232 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,_("load : Drive %d address %d is full\n"), drive, pDTE[drive].address);
1233 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,_("##### STOP load (-1 update status failed)\n"));
1239 if (pSTE[slot].status == 'E')
1241 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,_("load : Slot %d address %d is empty\n"), drive, pSTE[slot].address);
1242 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,_("##### STOP load (-1 update status failed)\n"));
1248 ret = pDev[fd].functions->function_move(fd, pSTE[slot].address, pDTE[drive].address);
1253 if (pDev[fd].functions->function_status(fd, 1) != 0)
1255 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,_("##### STOP load (-1 update status failed)\n"));
1262 * Try to read the label
1263 * and update the label/slot database
1265 if (pDev[INDEX_TAPE].avail == 1 && (changer->emubarcode == 1 || BarCode(INDEX_CHANGER)))
1268 if (pDev[INDEX_TAPECTL].SCSI == 1 && pDev[INDEX_TAPECTL].avail) {
1269 pDev[INDEX_TAPECTL].functions->function_rewind(INDEX_TAPECTL);
1271 pDev[INDEX_TAPE].functions->function_rewind(INDEX_TAPE);
1274 if (pDev[INDEX_TAPE].devopen == 1)
1276 SCSI_CloseDevice(INDEX_TAPE);
1279 result = (char *)tape_rdlabel(pDev[INDEX_TAPE].dev, &chgscsi_datestamp, &chgscsi_label);
1283 * Did we get an error from tape_rdlabel
1284 * if no update the vol/label mapping
1286 if (result == NULL && changer->labelfile != NULL && chgscsi_label != NULL )
1289 * We got something, update the db
1290 * but before check if the db has as entry the slot
1291 * to where we placed the tape, if no force an inventory
1293 strncpy(pbarcoderes->data.voltag, chgscsi_label,
1294 SIZEOF(pbarcoderes->data.voltag));
1295 pbarcoderes->data.slot = 0;
1296 pbarcoderes->data.from = 0;
1297 pbarcoderes->data.LoadCount = 0;
1301 * If we have an barcode reader we only do an update
1302 * If emubarcode is set we check if the
1303 * info in the DB is up to date, if no we set the do_inventory flag
1306 if (BarCode(INDEX_CHANGER) == 1 && changer->emubarcode == 0)
1308 pbarcoderes->action = UPDATE_SLOT;
1309 strncpy(pbarcoderes->data.barcode, pDTE[drive].VolTag,
1310 SIZEOF(pbarcoderes->data.barcode));
1311 pbarcoderes->data.LoadCount = 1;
1312 pbarcoderes->data.slot = slot;
1313 MapBarCode(changer->labelfile, pbarcoderes);
1316 if (BarCode(INDEX_CHANGER) == 0 && changer->emubarcode == 1)
1318 pbarcoderes->action = FIND_SLOT;
1319 if (MapBarCode(changer->labelfile, pbarcoderes) == 0) /* Nothing found, do an inventory */
1322 } else { /* We got something, is it correct ? */
1323 if (slot != pbarcoderes->data.slot && do_inventory == 0)
1325 DebugPrint(DEBUG_ERROR, SECTION_TAPE,_("Slot DB out of sync, slot %d != map %d"),slot, pbarcoderes->data.slot);
1326 ChgExit("Load", _("Label DB out of sync"), FATAL);
1328 } else { /* OK, so increment the load count */
1329 pbarcoderes->action = UPDATE_SLOT;
1330 pbarcoderes->data.LoadCount = 1;
1331 pbarcoderes->data.slot = slot;
1332 MapBarCode(changer->labelfile, pbarcoderes);
1337 if (BarCode(INDEX_CHANGER) == 1 && changer->emubarcode == 1)
1339 ChgExit("Load", _("BarCode == 1 and emubarcode == 1"), FATAL);
1343 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("##### STOP load (%d)\n"),ret);
1348 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("##### STOP load (%d)\n"),ret);
1354 * Returns the number of Storage Slots which the library has
1355 * fd -> pointer to the internal devie structure pDev
1356 * return -> Number of slots
1362 extern OpenFiles_T *pDev;
1364 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("###### START get_slot_count\n"));
1365 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("%-20s : fd %d\n"), "get_slot_count", fd);
1367 if (ElementStatusValid == 0)
1369 pDev[fd].functions->function_status(fd, 1);
1371 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,
1372 _("##### STOP get_slot_count (%zu)\n"), STE);
1373 return((ssize_t)STE);
1375 * return the number of slots in the robot
1382 * retreive the number of data-transfer devices /Tape drives)
1383 * fd -> pointer to the internal devie structure pDev
1384 * return -> -1 on failure
1391 extern OpenFiles_T *pDev;
1393 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("###### START get_drive_count\n"));
1394 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("%-20s : fd %d\n"), "get_drive_count", fd);
1396 if (ElementStatusValid == 0)
1398 if ( pDev[fd].functions->function_status(fd, 1) != 0)
1400 DebugPrint(DEBUG_ERROR, SECTION_SCSI, _("Error getting drive count\n"));
1401 DebugPrint(DEBUG_ERROR, SECTION_SCSI, _("##### STOP get_drive_count (-1)\n"));
1406 DebugPrint(DEBUG_INFO, SECTION_SCSI,
1407 _("###### STOP get_drive_count (%zu drives)\n"), DTE);
1408 return((ssize_t)DTE);
1412 * Now the internal functions
1416 * Open the device and placeit in the list of open files
1417 * The OS has to decide if it is an SCSI Commands capable device
1427 extern OpenFiles_T *pDev;
1429 ChangerCMD_T *p = (ChangerCMD_T *)&ChangerIO;
1436 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("##### START OpenDevice\n"));
1437 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("OpenDevice : %s\n"), DeviceName);
1439 pDev[ip].ConfigName = strdup(ConfigName);
1440 pDev[ip].dev = strdup(DeviceName);
1442 if (SCSI_OpenDevice(ip) != 0 )
1444 if (ident != NULL) /* Override by config */
1446 while(p->ident != NULL)
1448 if (strcmp(ident, p->ident) == 0)
1450 pDev[ip].functions = p;
1451 strncpy(pDev[ip].ident, ident, 17);
1452 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("override using ident = %s, type = %s\n"),p->ident, p->type);
1453 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("##### STOP OpenDevice\n"));
1459 ChgExit("OpenDevice", _("ident not found"), FATAL);
1462 while(p->ident != NULL)
1464 if (strcmp(pDev[ip].ident, p->ident) == 0)
1466 pDev[ip].functions = p;
1467 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("using ident = %s, type = %s\n"),p->ident, p->type);
1468 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("##### STOP OpenDevice\n"));
1475 /* Nothing matching found, try generic */
1476 /* divide generic in generic_type, where type is the */
1477 /* num returned by the inquiry command */
1478 p = (ChangerCMD_T *)&ChangerIO;
1479 g_snprintf(&tmpstr[0], SIZEOF(tmpstr), "%s_%s","generic",pDev[0].type);
1480 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### OpenDevice trying GENERIC Device %s\n",tmpstr);
1481 while(p->ident != NULL)
1483 if (strcmp(tmpstr, p->ident) == 0)
1485 pDev[ip].functions = p;
1486 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("using ident = %s, type = %s\n"),p->ident, p->type);
1487 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("##### STOP OpenDevice\n"));
1493 } else { /* Something failed, lets see what */
1494 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("##### STOP OpenDevice failed\n"));
1496 pDev[ip].functions = NULL;
1497 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("##### STOP OpenDevice (nothing found) !!\n"));
1503 * This functions checks if the library has an barcode reader.
1504 * fd -> pointer to the internal devie structure pDev
1511 extern OpenFiles_T *pDev;
1513 DebugPrint(DEBUG_INFO, SECTION_BARCODE,_("##### START BarCode\n"));
1514 DebugPrint(DEBUG_INFO, SECTION_BARCODE,_("%-20s : fd %d\n"), "BarCode", fd);
1516 DebugPrint(DEBUG_INFO, SECTION_BARCODE,_("Ident = [%s], function = [%s]\n"), pDev[fd].ident,
1517 pDev[fd].functions->ident);
1518 ret = pDev[fd].functions->function_barcode(fd);
1519 DebugPrint(DEBUG_INFO, SECTION_BARCODE,_("##### STOP BarCode (%d)\n"),ret);
1525 * This functions check if the tape drive is ready
1527 * fd -> pointer to the internal devie structure pDev
1528 * wait -> time to wait for the ready status
1536 extern OpenFiles_T *pDev;
1541 RequestSense_T *pRequestSense;
1542 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("##### START Tape_Ready\n"));
1545 * Which device should we use to get the
1550 * First the ioctl tapedevice
1552 if (pDev[INDEX_TAPE].avail == 1)
1558 * But if available and can do SCSI
1561 if (pDev[INDEX_TAPECTL].avail == 1 && pDev[INDEX_TAPECTL].SCSI == 1)
1566 if (pDev[fd].avail == 1 && pDev[fd].SCSI == 0)
1568 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("Tape_Ready : Can't send SCSI commands, try ioctl\n"));
1570 * Do we get an non negative result.
1571 * If yes this function is available
1572 * and we can use it to get the status
1575 ret = Tape_Status(fd);
1578 while (cnt < wait_time)
1580 if ( ret & TAPE_ONLINE)
1582 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("Tape_Ready : Ready after %d seconds\n"),cnt);
1583 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("##### STOP Tape_Ready\n"));
1589 ret = Tape_Status(fd);
1592 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("Tape_Ready : not ready, stop after %d seconds\n"),cnt);
1593 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("##### STOP Tape_Ready\n"));
1598 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("Tape_Ready : no ioctl interface, will sleep for %d seconds\n"), wait_time);
1600 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("##### STOP Tape_Ready\n"));
1605 pRequestSense = alloc(SIZEOF(RequestSense_T));
1608 * Ignore errors at this point
1613 * Wait until we get an ready condition
1617 while (!done && (cnt < wait_time))
1619 ret = SCSI_TestUnitReady(fd, pRequestSense );
1626 switch (SenseHandler(fd, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
1629 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("TapeReady (TestUnitReady) SENSE_NO\n"));
1632 case SENSE_TAPE_NOT_ONLINE:
1633 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("TapeReady (TestUnitReady) SENSE_TAPE_NOT_ONLINE\n"));
1636 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("TapeReady (TestUnitReady) SENSE_IGNORE\n"));
1640 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("TapeReady (TestUnitReady) SENSE_ABORT\n"));
1641 amfree(pRequestSense);
1645 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("TapeReady (TestUnitReady) SENSE_RETRY\n"));
1648 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("TapeReady (TestUnitReady) default (SENSE)\n"));
1654 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("TapeReady (TestUnitReady) SCSI_ERROR\n"));
1655 free(pRequestSense);
1659 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("TapeReady (TestUnitReady) SCSI_BUSY\n"));
1662 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("TapeReady (TestUnitReady) SCSI_CHECK\n"));
1665 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("TapeReady (TestUnitReady) unknown (%d)\n"),ret);
1672 amfree(pRequestSense);
1673 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("Tape_Ready after %d sec\n"), cnt);
1674 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("##### STOP Tape_Ready\n"));
1684 SC_COM_T *pSCSICommand;
1687 DebugPrint(DEBUG_INFO, SECTION_SCSI, _("##### START DecodeSCSI\n"));
1688 pSCSICommand = (SC_COM_T *)&SCSICommand;
1690 while (pSCSICommand->name != NULL)
1692 if (CDB[0] == pSCSICommand->command)
1694 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("%s %s"), string, pSCSICommand->name);
1695 for (x=0; x < pSCSICommand->length; x++)
1697 DebugPrint(DEBUG_INFO, SECTION_SCSI," %02X", CDB[x]);
1699 DebugPrint(DEBUG_INFO, SECTION_SCSI,"\n");
1700 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("##### STOP DecodeSCSI\n"));
1706 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("Not found %X\n"), CDB[0]);
1707 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("##### STOP DecodeSCSI\n"));
1719 ReadWriteErrorRecoveryPage_T *prp;
1720 DisconnectReconnectPage_T *pdrp;
1721 size_t length = (size_t)buffer[0] - 4 - offset;
1723 (void)pstring; /* Quiet unused parameter warning */
1725 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("##### START DecodeModeSense\n"));
1727 dump_hex(buffer, 255, DEBUG_INFO, SECTION_SCSI);
1729 /* Jump over the Parameter List header and an offset if we have something
1730 * Unknown at the start (ADIC-218) at the moment
1733 buffer = buffer + 4 + offset;
1735 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("buffer length = %d\n"), length);
1737 if (block) /* Do we have an block descriptor page ?*/
1740 g_fprintf(out, _("DecodeModeSense : Density Code %x\n"), (unsigned)buffer[0]);
1744 g_fprintf(out, _("DecodeModeSense : Number of Blocks %d\n"), V3(buffer));
1745 buffer = buffer + 4;
1748 g_fprintf(out, _("DecodeModeSense : Block Length %d\n"), V3(buffer));
1749 buffer = buffer + 3;
1754 switch (*buffer & 0x3f)
1757 pVendorUnique = buffer;
1761 prp = (ReadWriteErrorRecoveryPage_T *)buffer;
1764 g_fprintf(out, _("DecodeModeSense : Read/Write Error Recovery Page\n"));
1765 g_fprintf(out,_("\tTransfer Block %d\n"), prp->tb);
1766 g_fprintf(out,_("\tEnable Early Recovery %d\n"), prp->eer);
1767 g_fprintf(out,_("\tPost Error %d\n"), prp->per);
1768 g_fprintf(out,_("\tDisable Transfer on Error %d\n"), prp->dte);
1769 g_fprintf(out,_("\tDisable ECC Correction %d\n"), prp->dcr);
1770 g_fprintf(out,_("\tRead Retry Count %d\n"), prp->ReadRetryCount);
1771 g_fprintf(out,_("\tWrite Retry Count %d\n"), prp->WriteRetryCount);
1776 pdrp = (DisconnectReconnectPage_T *)buffer;
1779 g_fprintf(out, _("DecodeModeSense : Disconnect/Reconnect Page\n"));
1780 g_fprintf(out,_("\tBuffer Full Ratio %d\n"), pdrp->BufferFullRatio);
1781 g_fprintf(out,_("\tBuffer Empty Ratio %d\n"), pdrp->BufferEmptyRatio);
1782 g_fprintf(out,_("\tBus Inactivity Limit %d\n"),
1783 V2(pdrp->BusInactivityLimit));
1784 g_fprintf(out,_("\tDisconnect Time Limit %d\n"),
1785 V2(pdrp->DisconnectTimeLimit));
1786 g_fprintf(out,_("\tConnect Time Limit %d\n"),
1787 V2(pdrp->ConnectTimeLimit));
1788 g_fprintf(out,_("\tMaximum Burst Size %d\n"),
1789 V2(pdrp->MaximumBurstSize));
1790 g_fprintf(out,_("\tDTDC %d\n"), pdrp->DTDC);
1795 pEAAPage = (EAAPage_T *)buffer;
1798 g_fprintf(out,_("DecodeModeSense : Element Address Assignment Page\n"));
1799 g_fprintf(out,_("\tMedium Transport Element Address %d\n"),
1800 V2(pEAAPage->MediumTransportElementAddress));
1801 g_fprintf(out,_("\tNumber of Medium Transport Elements %d\n"),
1802 V2(pEAAPage->NoMediumTransportElements));
1803 g_fprintf(out, _("\tFirst Storage Element Address %d\n"),
1804 V2(pEAAPage->FirstStorageElementAddress));
1805 g_fprintf(out, _("\tNumber of Storage Elements %d\n"),
1806 V2(pEAAPage->NoStorageElements));
1807 g_fprintf(out, _("\tFirst Import/Export Element Address %d\n"),
1808 V2(pEAAPage->FirstImportExportElementAddress));
1809 g_fprintf(out, _("\tNumber of ImportExport Elements %d\n"),
1810 V2(pEAAPage->NoImportExportElements));
1811 g_fprintf(out, _("\tFirst Data Transfer Element Address %d\n"),
1812 V2(pEAAPage->FirstDataTransferElementAddress));
1813 g_fprintf(out, _("\tNumber of Data Transfer Elements %d\n"),
1814 V2(pEAAPage->NoDataTransferElements));
1819 pDeviceCapabilitiesPage = (DeviceCapabilitiesPage_T *)buffer;
1822 g_fprintf(out, _("DecodeModeSense : MT can store data cartridges %d\n"),
1823 pDeviceCapabilitiesPage->MT);
1824 g_fprintf(out, _("DecodeModeSense : ST can store data cartridges %d\n"),
1825 pDeviceCapabilitiesPage->ST);
1826 g_fprintf(out, _("DecodeModeSense : IE can store data cartridges %d\n"),
1827 pDeviceCapabilitiesPage->IE);
1828 g_fprintf(out, _("DecodeModeSense : DT can store data cartridges %d\n"),
1829 pDeviceCapabilitiesPage->DT);
1830 g_fprintf(out, _("DecodeModeSense : MT to MT %d\n"),
1831 pDeviceCapabilitiesPage->MT2MT);
1832 g_fprintf(out, _("DecodeModeSense : MT to ST %d\n"),
1833 pDeviceCapabilitiesPage->MT2ST);
1834 g_fprintf(out, _("DecodeModeSense : MT to IE %d\n"),
1835 pDeviceCapabilitiesPage->MT2IE);
1836 g_fprintf(out, _("DecodeModeSense : MT to DT %d\n"),
1837 pDeviceCapabilitiesPage->MT2DT);
1838 g_fprintf(out, _("DecodeModeSense : ST to MT %d\n"),
1839 pDeviceCapabilitiesPage->ST2ST);
1840 g_fprintf(out, _("DecodeModeSense : ST to MT %d\n"),
1841 pDeviceCapabilitiesPage->ST2ST);
1842 g_fprintf(out, _("DecodeModeSense : ST to DT %d\n"),
1843 pDeviceCapabilitiesPage->ST2DT);
1844 g_fprintf(out, _("DecodeModeSense : IE to MT %d\n"),
1845 pDeviceCapabilitiesPage->IE2MT);
1846 g_fprintf(out, _("DecodeModeSense : IE to ST %d\n"),
1847 pDeviceCapabilitiesPage->IE2IE);
1848 g_fprintf(out, _("DecodeModeSense : IE to ST %d\n"),
1849 pDeviceCapabilitiesPage->IE2DT);
1850 g_fprintf(out, _("DecodeModeSense : IE to ST %d\n"),
1851 pDeviceCapabilitiesPage->IE2DT);
1852 g_fprintf(out, _("DecodeModeSense : DT to MT %d\n"),
1853 pDeviceCapabilitiesPage->DT2MT);
1854 g_fprintf(out, _("DecodeModeSense : DT to ST %d\n"),
1855 pDeviceCapabilitiesPage->DT2ST);
1856 g_fprintf(out, _("DecodeModeSense : DT to IE %d\n"),
1857 pDeviceCapabilitiesPage->DT2IE);
1858 g_fprintf(out, _("DecodeModeSense : DT to DT %d\n"),
1859 pDeviceCapabilitiesPage->DT2DT);
1864 buffer++; /* set pointer to the length information */
1867 /* Error if *buffer (length) is 0 */
1870 /* EAAPage = NULL; */
1871 /* DeviceCapabilitiesPage = NULL; */
1875 length = length - (size_t)*buffer - 2;
1876 buffer = buffer + (size_t)*buffer + 1;
1883 RequestSense_T * sense,
1892 g_fprintf(out,_("##### START DecodeSense\n"));
1893 g_fprintf(out,_("%sSense Keys\n"), pstring);
1894 if (sense->ErrorCode == 0x70)
1896 g_fprintf(out,_("\tExtended Sense \n"));
1898 g_fprintf(out,_("\tErrorCode %02x\n"), sense->ErrorCode);
1899 g_fprintf(out,_("\tValid %d\n"), sense->Valid);
1901 g_fprintf(out,_("\tASC %02X\n"), sense->AdditionalSenseCode);
1902 g_fprintf(out,_("\tASCQ %02X\n"), sense->AdditionalSenseCodeQualifier);
1903 g_fprintf(out,_("\tSense key %02X\n"), sense->SenseKey);
1904 switch (sense->SenseKey)
1907 g_fprintf(out,_("\t\tNo Sense\n"));
1910 g_fprintf(out,_("\t\tRecoverd Error\n"));
1913 g_fprintf(out,_("\t\tNot Ready\n"));
1916 g_fprintf(out,_("\t\tMedium Error\n"));
1919 g_fprintf(out,_("\t\tHardware Error\n"));
1922 g_fprintf(out,_("\t\tIllegal Request\n"));
1925 g_fprintf(out,_("\t\tUnit Attention\n"));
1928 g_fprintf(out,_("\t\tData Protect\n"));
1931 g_fprintf(out,_("\t\tBlank Check\n"));
1934 g_fprintf(out,_("\t\tVendor uniq\n"));
1937 g_fprintf(out,_("\t\tCopy Aborted\n"));
1940 g_fprintf(out,_("\t\tAborted Command\n"));
1943 g_fprintf(out,_("\t\tEqual\n"));
1946 g_fprintf(out,_("\t\tVolume Overflow\n"));
1949 g_fprintf(out,_("\t\tMiscompare\n"));
1952 g_fprintf(out,_("\t\tReserved\n"));
1960 ExtendedRequestSense_T * sense,
1964 ExtendedRequestSense_T *p;
1966 g_fprintf(out,_("##### START DecodeExtSense\n"));
1969 g_fprintf(out,_("%sExtended Sense\n"), pstring);
1970 DecodeSense((RequestSense_T *)p, pstring, out);
1971 g_fprintf(out,_("\tLog Parameter Page Code %02X\n"), sense->LogParameterPageCode);
1972 g_fprintf(out,_("\tLog Parameter Code %02X\n"), sense->LogParameterCode);
1973 g_fprintf(out,_("\tUnderrun/Overrun Counter %02X\n"), sense->UnderrunOverrunCounter);
1974 g_fprintf(out,_("\tRead/Write Error Counter %d\n"), V3((char *)sense->ReadWriteDataErrorCounter));
1975 if (sense->AdditionalSenseLength > (u_char)sizeof(RequestSense_T))
1978 g_fprintf(out,_("\tPower Fail\n"));
1980 g_fprintf(out,_("\tSCSI Bus Parity Error\n"));
1982 g_fprintf(out,_("\tFormatted Buffer parity Error\n"));
1984 g_fprintf(out,_("\tMedia Error\n"));
1986 g_fprintf(out,_("\tError Counter Overflow\n"));
1988 g_fprintf(out,_("\tTapeMotion Error\n"));
1990 g_fprintf(out,_("\tTape Not Present\n"));
1992 g_fprintf(out,_("\tLogical Beginning of tape\n"));
1994 g_fprintf(out,_("\tTape Mark Detect Error\n"));
1996 g_fprintf(out,_("\tWrite Protect\n"));
1998 g_fprintf(out,_("\tFilemark Error\n"));
2000 g_fprintf(out,_("\tUnder Run Error\n"));
2002 g_fprintf(out,_("\tWrite Error 1\n"));
2004 g_fprintf(out,_("\tServo System Error\n"));
2006 g_fprintf(out,_("\tFormatter Error\n"));
2008 g_fprintf(out,_("\tCleaning Cartridge is empty\n"));
2010 g_fprintf(out,_("\tReverse Retries Required\n"));
2012 g_fprintf(out,_("\tTape Drive has been cleaned\n"));
2014 g_fprintf(out,_("\tTape Drive needs to be cleaned\n"));
2016 g_fprintf(out,_("\tPhysical End of Tape\n"));
2018 g_fprintf(out,_("\tWrite Splice Error\n"));
2020 g_fprintf(out,_("\tWrite Splice Error\n"));
2021 g_fprintf(out,_("\tRemaing 1024 byte tape blocks %d\n"), V3((char *)sense->RemainingTape));
2022 g_fprintf(out,_("\tTracking Retry Counter %02X\n"), sense->TrackingRetryCounter);
2023 g_fprintf(out,_("\tRead/Write Retry Counter %02X\n"), sense->ReadWriteRetryCounter);
2024 g_fprintf(out,_("\tFault Sympton Code %02X\n"), sense->FaultSymptomCode);
2031 SCSIInquiry_T * SCSIInquiry)
2033 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("##### START PrintInquiry\n"));
2034 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("%-15s %x\n"), "qualifier", SCSIInquiry->qualifier);
2035 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("%-15s %x\n"), "type", SCSIInquiry->type);
2036 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("%-15s %x\n"), "data_format", SCSIInquiry->data_format);
2037 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("%-15s %X\n"), "ansi_version", SCSIInquiry->ansi_version);
2038 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("%-15s %X\n"), "ecma_version", SCSIInquiry->ecma_version);
2039 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("%-15s %X\n"), "iso_version", SCSIInquiry->iso_version);
2040 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("%-15s %X\n"), "type_modifier", SCSIInquiry->type_modifier);
2041 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("%-15s %x\n"), "removable", SCSIInquiry->removable);
2042 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("%-15s %.8s\n"), "vendor_info", SCSIInquiry->vendor_info);
2043 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("%-15s %.16s\n"), "prod_ident", SCSIInquiry->prod_ident);
2044 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("%-15s %.4s\n"), "prod_version", SCSIInquiry->prod_version);
2045 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("%-15s %.19s\n"), "vendor_specific", SCSIInquiry->vendor_specific);
2053 dbprintf(_("##### START DoNothing\n"));
2061 (void)unused1; /* Quiet unused parameter warning */
2063 dbprintf(_("##### START DoNothing\n"));
2072 (void)unused1; /* Quiet unused parameter warning */
2073 (void)unused2; /* Quiet unused parameter warning */
2075 dbprintf(_("##### START DoNothing\n"));
2085 (void)unused1; /* Quiet unused parameter warning */
2086 (void)unused2; /* Quiet unused parameter warning */
2087 (void)unused3; /* Quiet unused parameter warning */
2089 dbprintf(_("##### START DoNothing\n"));
2096 dbprintf(_("##### START GenericFree\n"));
2103 dbprintf(_("##### START GenericSearch\n"));
2111 extern OpenFiles_T *pDev;
2113 ModePageTreeFrogVendorUnique_T *pVendor;
2115 dbprintf(_("##### START TreeFrogBarCode\n"));
2116 if (pModePage == NULL)
2118 pModePage = alloc(0xff);
2121 if (SCSI_ModeSense(DeviceFD, pModePage, 0xff, 0x0, 0x3f) == 0)
2123 DecodeModeSense(pModePage, 0, _("TreeFrogBarCode :"), 0, debug_file);
2125 if (pVendorUnique == NULL)
2127 dbprintf(_("TreeFrogBarCode : no pVendorUnique\n"));
2131 pVendor = ( ModePageTreeFrogVendorUnique_T *)pVendorUnique;
2133 dbprintf(_("TreeFrogBarCode : EBARCO %d\n"), pVendor->EBARCO);
2134 dbprintf(_("TreeFrogCheckSum : CHKSUM %d\n"), pVendor->CHKSUM);
2136 dump_hex((u_char *)pDev[INDEX_CHANGER].inquiry, INQUIRY_SIZE, DEBUG_INFO, SECTION_ELEMENT);
2137 return(pVendor->EBARCO);
2147 extern OpenFiles_T *pDev;
2149 ModePageEXB120VendorUnique_T *pVendor;
2150 ModePageEXB120VendorUnique_T *pVendorWork;
2152 DebugPrint(DEBUG_INFO, SECTION_BARCODE,_("##### START EXB_BarCode\n"));
2153 if (pModePage == NULL && LibModeSenseValid == 0)
2155 pModePage = alloc(0xff);
2157 if (SCSI_ModeSense(DeviceFD, pModePage, 0xff, 0x8, 0x3f) == 0)
2159 DecodeModeSense(pModePage, 0, _("EXB_BarCode :"), 0, debug_file);
2160 LibModeSenseValid = 1;
2162 LibModeSenseValid = -1;
2166 if (LibModeSenseValid == 1)
2168 if (pVendorUnique == NULL)
2170 DebugPrint(DEBUG_INFO, SECTION_BARCODE,_("EXB_BarCode : no pVendorUnique\n"));
2174 pVendor = ( ModePageEXB120VendorUnique_T *)pVendorUnique;
2176 DebugPrint(DEBUG_INFO, SECTION_BARCODE,_("EXB_BarCode : NBL %d\n"), pVendor->NBL);
2177 DebugPrint(DEBUG_INFO, SECTION_BARCODE,_("EXB_BarCode : PS %d\n"), pVendor->PS);
2178 if (pVendor->NBL == 1 && pVendor->PS == 1 )
2180 pVendorWork = alloc((size_t)pVendor->ParameterListLength + 2);
2181 DebugPrint(DEBUG_INFO, SECTION_BARCODE,_("EXB_BarCode : setting NBL to 1\n"));
2182 memcpy(pVendorWork, pVendor, (size_t)pVendor->ParameterListLength + 2);
2183 pVendorWork->NBL = 0;
2184 pVendorWork->PS = 0;
2185 pVendorWork->RSVD0 = 0;
2186 if (SCSI_ModeSelect(DeviceFD, (u_char *)pVendorWork, (u_char)(pVendorWork->ParameterListLength + 2), 0, 1, 0) == 0)
2188 DebugPrint(DEBUG_INFO, SECTION_BARCODE,_("EXB_BarCode : SCSI_ModeSelect OK\n"));
2193 /* And now again !!!
2195 GenericResetStatus(DeviceFD);
2197 DebugPrint(DEBUG_INFO, SECTION_BARCODE,_("EXB_BarCode : SCSI_ModeSelect failed\n"));
2199 amfree(pVendorWork);
2201 dump_hex((u_char *)pDev[INDEX_CHANGER].inquiry, INQUIRY_SIZE, DEBUG_INFO, SECTION_BARCODE);
2202 DebugPrint(DEBUG_INFO, SECTION_BARCODE,_("EXB_BarCode : vendor_specific[19] %x\n"),
2203 pDev[INDEX_CHANGER].inquiry->vendor_specific[19]);
2212 (void)DeviceFD; /* Quiet unused parameter warning */
2214 DebugPrint(DEBUG_INFO, SECTION_BARCODE,_("##### START NoBarCode\n"));
2215 DebugPrint(DEBUG_INFO, SECTION_BARCODE,_("##### STOP NoBarCode\n"));
2223 (void)DeviceFD; /* Quiet unused parameter warning */
2225 DebugPrint(DEBUG_INFO, SECTION_BARCODE,_("##### START GenericBarCode\n"));
2226 if ( changer->havebarcode >= 1)
2228 DebugPrint(DEBUG_INFO, SECTION_BARCODE,_("##### STOP GenericBarCode (havebarcode) => %d\n"),changer->havebarcode);
2232 DebugPrint(DEBUG_INFO, SECTION_BARCODE,_("##### STOP GenericBarCode => 0\n"));
2241 u_char AdditionalSenseCode,
2242 u_char AdditionalSenseCodeQualifier,
2243 RequestSense_T * buffer)
2245 extern OpenFiles_T *pDev;
2247 dbprintf(_("##### START SenseHandler\n"));
2248 if (pDev[DeviceFD].inqdone == 1)
2250 dbprintf(_("Ident = [%s], function = [%s]\n"), pDev[DeviceFD].ident,
2251 pDev[DeviceFD].functions->ident);
2252 ret = pDev[DeviceFD].functions->function_error(DeviceFD, flag, SenseKey, AdditionalSenseCode, AdditionalSenseCodeQualifier, buffer);
2254 dbprintf(_(" Ups no sense\n"));
2256 dbprintf(_("#### STOP SenseHandler\n"));
2261 * Try to get information about the tape,
2262 * Tape loaded ? Online etc
2263 * Use the mtio ioctl to get the information if no SCSI Path
2264 * to the tape drive is available.
2267 * Pass an parameter to identify which unit to use
2268 * if there are more than one
2269 * Implement the SCSI path if available
2274 extern OpenFiles_T *pDev;
2278 RequestSense_T *pRequestSense;
2280 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("##### START TapeStatus\n"));
2283 * If it is an device which understand SCSI commands the
2284 * normal ioctl (MTIOCGET for example) may fail
2287 if (pDev[INDEX_TAPECTL].SCSI == 1)
2289 pRequestSense = alloc(SIZEOF(RequestSense_T));
2290 memset(pRequestSense, 0, SIZEOF(RequestSense_T));
2292 for (done = 0, cnt = 0; !done && (cnt < 60); cnt++)
2294 ret = SCSI_TestUnitReady(INDEX_TAPECTL, pRequestSense);
2295 DebugPrint(DEBUG_INFO, SECTION_SCSI, _("TapeStatus TestUnitReady ret %d\n"),ret);
2300 switch (SenseHandler(INDEX_TAPECTL, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
2304 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("TapeStatus (TestUnitReady) SENSE_NO\n"));
2305 pDTE[0].status = 'F';
2306 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("##### FULL\n"));
2310 case SENSE_TAPE_NOT_ONLINE:
2311 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("TapeStatus (TestUnitReady) SENSE_TAPE_NOT_ONLINE\n"));
2312 pDTE[0].status = 'E';
2313 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("##### EMPTY\n"));
2318 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("TapeStatus (TestUnitReady) SENSE_ABORT\n"));
2323 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("TapeStatus (TestUnitReady) SENSE_RETRY\n"));
2327 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("TapeStatus (TestUnitReady) default (SENSE)\n"));
2333 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("TapeStatus (TestUnitReady) SCSI_ERROR\n"));
2338 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("TapeStatus (TestUnitReady) SCSI_BUSY\n"));
2342 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("TapeStatus (TestUnitReady) SCSI_CHECK\n"));
2346 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("TapeStatus (TestUnitReady) unknown (%d)\n"),ret);
2353 amfree(pRequestSense);
2355 ret = Tape_Status(INDEX_TAPE);
2356 if ( ret & TAPE_ONLINE)
2358 pDTE[0].status ='F';
2359 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("##### FULL\n"));
2361 pDTE[0].status = 'E';
2362 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("##### EMPTY\n"));
2364 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("##### STOP TapeStatus\n"));
2374 extern OpenFiles_T *pDev;
2376 RequestSense_T *pRequestSense;
2377 ExtendedRequestSense_T *pExtendedRequestSense;
2382 (void)Device; /* Quiet unused parameter warning */
2384 dbprintf(_("##### START DLT4000Eject\n"));
2386 pRequestSense = alloc(SIZEOF(RequestSense_T));
2387 pExtendedRequestSense = alloc(SIZEOF(ExtendedRequestSense_T));
2391 dbprintf(_("DLT4000Eject : use mtio ioctl for eject on %s\n"), pDev[INDEX_TAPE].dev);
2392 free(pExtendedRequestSense);
2393 free(pRequestSense);
2394 return(Tape_Ioctl(INDEX_TAPE, IOCTL_EJECT));
2400 if (pDev[INDEX_TAPECTL].SCSI == 0)
2402 dbprintf(_("DLT4000Eject : Device %s not able to receive SCSI commands\n"), pDev[INDEX_TAPE].dev);
2403 free(pExtendedRequestSense);
2404 free(pRequestSense);
2405 return(Tape_Ioctl(INDEX_TAPE, IOCTL_EJECT));
2410 dbprintf(_("DLT4000Eject : SCSI eject on %s = %s\n"), pDev[INDEX_TAPECTL].dev, pDev[INDEX_TAPECTL].ConfigName);
2412 RequestSense(INDEX_TAPECTL, pExtendedRequestSense, 0);
2413 DecodeExtSense(pExtendedRequestSense, _("DLT4000Eject : "), debug_file);
2414 /* Unload the tape, 0 == wait for success
2417 ret = SCSI_LoadUnload(INDEX_TAPECTL, pRequestSense, 0, 0);
2419 RequestSense(INDEX_TAPECTL, pExtendedRequestSense, 0);
2420 DecodeExtSense(pExtendedRequestSense, _("DLT4000Eject : "), debug_file);
2424 free(pExtendedRequestSense);
2425 free(pRequestSense);
2431 while (!done && cnt < 300)
2433 ret = SCSI_TestUnitReady(INDEX_TAPECTL, pRequestSense);
2434 DebugPrint(DEBUG_INFO, SECTION_SCSI, _("DLT4000Eject TestUnitReady ret %d\n"),ret);
2441 switch (SenseHandler(INDEX_TAPECTL, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
2444 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("DLT4000Eject (TestUnitReady) SENSE_NO\n"));
2447 case SENSE_TAPE_NOT_ONLINE:
2448 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("DLT4000Eject (TestUnitReady) SENSE_TAPE_NOT_ONLINE\n"));
2452 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("DLT4000Eject (TestUnitReady) SENSE_IGNORE\n"));
2456 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("DLT4000Eject (TestUnitReady) SENSE_ABORT\n"));
2457 free(pExtendedRequestSense);
2458 free(pRequestSense);
2462 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("DLT4000Eject (TestUnitReady) SENSE_RETRY\n"));
2465 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("DLT4000Eject (TestUnitReady) default (SENSE)\n"));
2471 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("DLT4000Eject (TestUnitReady) SCSI_ERROR\n"));
2472 free(pExtendedRequestSense);
2473 free(pRequestSense);
2477 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("DLT4000Eject (TestUnitReady) SCSI_BUSY\n"));
2480 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("DLT4000Eject (TestUnitReady) SCSI_CHECK\n"));
2483 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("DLT4000Eject (TestUnitReady) unknown (%d)\n"),ret);
2491 dbprintf(_("DLT4000Eject : Ready after %d sec, done = %d\n"), cnt * 2, done);
2493 free(pExtendedRequestSense);
2494 free(pRequestSense);
2500 * Ejects an tape either with the ioctl interface
2501 * or by using the SCSI interface if available.
2504 * Before unload check if there is an tape in the drive
2512 extern OpenFiles_T *pDev;
2513 RequestSense_T *pRequestSense;
2518 (void)Device; /* Quiet unused parameter warning */
2519 (void)type; /* Quiet unused parameter warning */
2521 DebugPrint(DEBUG_INFO, SECTION_TAPE, _("##### START GenericEject\n"));
2523 pRequestSense = alloc(SIZEOF(RequestSense_T));
2525 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("GenericEject : SCSI eject on %s = %s\n"),
2526 pDev[INDEX_TAPECTL].dev, pDev[INDEX_TAPECTL].ConfigName);
2529 * Can we use SCSI commands ?
2531 if (pDev[INDEX_TAPECTL].SCSI == 1)
2533 LogSense(INDEX_TAPECTL);
2535 * Unload the tape, 1 == don't wait for success
2538 ret = SCSI_LoadUnload(INDEX_TAPECTL, pRequestSense, 1, 0);
2542 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericEject SCSI_LoadUnload failed\n");
2543 free(pRequestSense);
2549 while (!done && cnt < 300)
2551 ret = SCSI_TestUnitReady(INDEX_TAPECTL, pRequestSense);
2552 DebugPrint(DEBUG_INFO, SECTION_SCSI, _("GenericEject TestUnitReady ret %d\n"),ret);
2557 switch (SenseHandler(INDEX_TAPECTL, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
2560 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("GenericEject (TestUnitReady) SENSE_NO\n"));
2562 case SENSE_TAPE_NOT_ONLINE:
2563 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("GenericEject (TestUnitReady) SENSE_TAPE_NOT_ONLINE\n"));
2567 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("GenericEject (TestUnitReady) SENSE_IGNORE\n"));
2570 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("GenericEject (TestUnitReady) SENSE_ABORT\n"));
2571 free(pRequestSense);
2575 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("GenericEject (TestUnitReady) SENSE_RETRY\n"));
2578 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("GenericEject (TestUnitReady) default (SENSE)\n"));
2583 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("GenericEject (TestUnitReady) SCSI_ERROR\n"));
2584 free(pRequestSense);
2588 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("GenericEject (TestUnitReady) SCSI_BUSY\n"));
2591 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("GenericEject (TestUnitReady) SCSI_CHECK\n"));
2594 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("GenericEject (TestUnitReady) unknown (%d)\n"),ret);
2601 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("GenericEject : Device can't understand SCSI try ioctl\n"));
2602 Tape_Ioctl(INDEX_TAPECTL, IOCTL_EJECT);
2604 DebugPrint(DEBUG_INFO, SECTION_TAPE,
2605 _("GenericEject : Ready after %d sec\n"), cnt * 2);
2606 free(pRequestSense);
2614 * Make the retry counter an config option,
2625 extern OpenFiles_T *pDev;
2626 RequestSense_T *pRequestSense;
2631 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("##### START GenericRewind pDEV -> %d\n"),DeviceFD);
2635 * If we can use the SCSI device than use it, else use the ioctl
2638 if (pDev[DeviceFD].SCSI == 1)
2640 pRequestSense = alloc(SIZEOF(RequestSense_T));
2643 * Before doing the rewind check if the tape is ready to accept commands
2649 ret = SCSI_TestUnitReady(DeviceFD, (RequestSense_T *)pRequestSense );
2650 DebugPrint(DEBUG_INFO, SECTION_TAPE, _("GenericRewind (TestUnitReady) ret %d\n"),ret);
2657 switch (SenseHandler(DeviceFD, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
2660 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("GenericRewind (TestUnitReady) SENSE_NO\n"));
2663 case SENSE_TAPE_NOT_ONLINE:
2664 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("GenericRewind (TestUnitReady) SENSE_TAPE_NOT_ONLINE\n"));
2665 free(pRequestSense);
2669 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("GenericRewind (TestUnitReady) SENSE_IGNORE\n"));
2673 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("GenericRewind (TestUnitReady) SENSE_ABORT\n"));
2674 free(pRequestSense);
2678 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("GenericRewind (TestUnitReady) SENSE_RETRY\n"));
2681 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("GenericRewind (TestUnitReady) default (SENSE)\n"));
2684 } /* switch (SenseHandler(DeviceFD, 0, pRequestSense->SenseKey.... */
2688 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("GenericRewind (TestUnitReady) SCSI_ERROR\n"));
2689 free(pRequestSense);
2694 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("GenericRewind (TestUnitReady) SCSI_BUSY\n"));
2697 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("GenericRewind (TestUnitReady) SCSI_CHECK\n"));
2700 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("GenericRewind (TestUnitReady) unknown (%d)\n"),ret);
2705 DebugPrint(DEBUG_INFO, SECTION_TAPE,_(" Wait .... (%d)\n"),cnt);
2708 DebugPrint(DEBUG_ERROR, SECTION_TAPE,_("##### STOP GenericRewind (-1)\n"));
2709 free(pRequestSense);
2717 CDB[0] = SC_COM_REWIND;
2727 ret = SCSI_Run(DeviceFD, Input, CDB, 6,
2730 SIZEOF(RequestSense_T));
2732 DecodeSense(pRequestSense, _("GenericRewind : "), debug_file);
2736 if (pRequestSense->SenseKey != UNIT_ATTENTION)
2747 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("GenericRewind : failed %d\n"), ret);
2753 while (!done && (cnt < 300))
2755 ret = SCSI_TestUnitReady(DeviceFD, pRequestSense);
2756 DebugPrint(DEBUG_INFO, SECTION_SCSI, _("GenericRewind TestUnitReady ret %d\n"),ret);
2763 switch (SenseHandler(DeviceFD, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
2766 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("GenericRewind (TestUnitReady) SENSE_NO\n"));
2769 case SENSE_TAPE_NOT_ONLINE:
2770 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("GenericRewind (TestUnitReady) SENSE_TAPE_NOT_ONLINE\n"));
2771 free(pRequestSense);
2775 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("GenericRewind (TestUnitReady) SENSE_IGNORE\n"));
2779 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("GenericRewind (TestUnitReady) SENSE_ABORT\n"));
2780 free(pRequestSense);
2784 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("GenericRewind (TestUnitReady) SENSE_RETRY\n"));
2787 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("GenericRewind (TestUnitReady) default (SENSE)\n"));
2793 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("GenericRewind (TestUnitReady) SCSI_ERROR\n"));
2798 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("GenericRewind (TestUnitReady) SCSI_BUSY\n"));
2801 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("GenericRewind (TestUnitReady) SCSI_CHECK\n"));
2804 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("GenericRewind (TestUnitReady) unknown (%d)\n"),ret);
2812 amfree(pRequestSense);
2814 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("GenericRewind : Ready after %d sec, "
2815 "done = %d\n"), cnt * 2, done);
2816 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("##### STOP GenericRewind (0)\n"));
2818 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("GenericRewind : use ioctl rewind\n"));
2819 if (pDev[DeviceFD].devopen == 1)
2821 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("Close Device\n"));
2822 SCSI_CloseDevice(DeviceFD);
2824 /* no actual rewind operation here -- the device itself will handle that */
2825 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("##### STOP GenericRewind (0)\n"));
2833 * Check if the tape has the tape clean
2834 * bit set in the return of an request sense
2841 extern OpenFiles_T *pDev;
2842 ExtendedRequestSense_T ExtRequestSense;
2845 (void)Device; /* Quiet unused parameter warning */
2847 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("##### START GenericClean\n"));
2848 if (pDev[INDEX_TAPECTL].SCSI == 0)
2850 DebugPrint(DEBUG_ERROR, SECTION_TAPE,_("GenericClean : can't send SCSI commands\n"));
2851 DebugPrint(DEBUG_ERROR, SECTION_TAPE,_("##### STOP GenericClean\n"));
2857 * Request Sense Data, reset the counter
2859 if ( RequestSense(INDEX_TAPECTL, &ExtRequestSense, 1) == 0)
2862 DecodeExtSense(&ExtRequestSense, _("GenericClean : "), debug_file);
2863 if(ExtRequestSense.CLN) {
2869 DebugPrint(DEBUG_ERROR, SECTION_TAPE,_("Got error from RequestSense\n"));
2871 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("##### STOP GenericClean (%d)\n"),ret);
2879 extern OpenFiles_T *pDev;
2881 RequestSense_T *pRequestSense;
2886 (void)Device; /* Quiet unused parameter warning */
2887 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### START SCSI_LogSenseClean\n");
2888 if (pDev[INDEX_TAPECTL].SCSI == 0)
2890 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"SCSILogSenseClean : can't send SCSI commands\n");
2891 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"##### STOP SCSI_LogSenseClean\n");
2896 if (NULL == (buffer = alloc(size))){
2897 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"SCSI_LogSenseClean : can't alloc buffer\n");
2898 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"##### STOP SCSI_LogSenseClean\n");
2901 if (NULL == (pRequestSense = alloc(SIZEOF(RequestSense_T)))){
2902 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"SCSI_LogSenseClean : can't alloc memory\n");
2903 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"##### STOP SCSI_LogSenseClean\n");
2907 memset(buffer, 0, size);
2908 CDB[0] = SC_COM_LOG_SENSE;
2910 CDB[2] = (u_char)(0x40 | 0x33);/* 0x40 for current values 0x33 Head Cleaning Page*/
2915 MSB2(&CDB[7], size);
2918 if (SCSI_Run(INDEX_TAPECTL, Input, CDB, 10,
2922 SIZEOF(RequestSense_T)) != 0)
2924 DecodeSense(pRequestSense, "SCSI_LogSenseClean : ",debug_file);
2925 free(pRequestSense);
2927 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"##### STOP SCSI_LogSenseClean (0) Page could not be read.\n");
2931 if (1==(0x1 & buffer[8])){ /* Bit 0 of the 4th byte in the Clean Head Log Parameter, which are the bytes */
2932 /* 4 to 8 on the Log Sense Page 0x33 */
2937 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### STOP SCSI_LogSenseClean (%d)\n",ret);
2938 free(pRequestSense);
2948 RequestSense_T *pRequestSense;
2952 DebugPrint(DEBUG_INFO, SECTION_ELEMENT, _("##### START GenericResetStatus\n"));
2954 pRequestSense = alloc(SIZEOF(RequestSense_T));
2958 CDB[0] = SC_COM_IES; /* */
2966 ret = SCSI_Run(DeviceFD, Input, CDB, 6,
2969 SIZEOF(RequestSense_T));
2973 /* g_fprintf(stderr, _("%s: Request Sense[Inquiry]: %02X"), */
2974 /* "chs", ((u_char *) &pRequestSense)[0]); */
2975 /* for (i = 1; i < SIZEOF(RequestSense_T); i++) */
2976 /* g_fprintf(stderr, " %02X", ((u_char *) &pRequestSense)[i]); */
2977 /* g_fprintf(stderr, "\n"); */
2978 free(pRequestSense);
2984 switch (SenseHandler(DeviceFD, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
2987 free(pRequestSense);
2991 free(pRequestSense);
2996 if (retry < MAX_RETRIES )
2998 DebugPrint(DEBUG_INFO, SECTION_ELEMENT, _("GenericResetStatus : retry %d\n"), retry);
3001 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("GenericResetStatus : return (-1)\n"));
3002 free(pRequestSense);
3008 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("GenericResetStatus : (default) return (-1)\n"));
3009 free(pRequestSense);
3017 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("##### STOP GenericResetStatus (%d)\n"),ret);
3018 free(pRequestSense);
3022 /* GenericSenseHandler
3023 * Handles the conditions/sense wich is returned by an SCSI command
3024 * pwork is an pointer to the structure OpenFiles_T, which is filled with information
3025 * about the device to which we talk. Information are for example
3026 * The vendor, the ident, which fd, etc. This strucure is filled when we open the
3028 * flag tells how to handle the information passed in the buffer,
3029 * 0 -> Sense Key available
3030 * 1 -> No Sense key available
3031 * buffer is a pointer to the data from the request sense result.
3034 * Limit recursion, may run in an infinite loop
3037 GenericSenseHandler(
3041 u_char AdditionalSenseCode,
3042 u_char AdditionalSenseCodeQualifier,
3043 RequestSense_T * pRequestSense)
3045 extern OpenFiles_T *pDev;
3049 dbprintf(_("##### START GenericSenseHandler\n"));
3051 DecodeSense(pRequestSense, _("GenericSenseHandler : "), debug_file);
3053 ret = Sense2Action(pDev[ip].ident,
3054 pDev[ip].inquiry->type,
3056 AdditionalSenseCode,
3057 AdditionalSenseCodeQualifier,
3060 dbprintf(_("##### STOP GenericSenseHandler: %s\n"), _(info));
3065 * Do the move. We don't address the MTE element (the gripper)
3066 * here. We assume that the library use the right MTE.
3067 * The difference to GenericMove is that we do an align element
3072 * != 0 -> error either from the SCSI command or from
3073 * the element handling
3082 extern OpenFiles_T *pDev;
3083 ElementInfo_T *pfrom;
3088 int SDX_MTE = 0; /* This are parameters passed */
3089 int SDX_STE = -1; /* to */
3090 int SDX_DTE = -1; /* AlignElements */
3092 DebugPrint(DEBUG_INFO, SECTION_MOVE,_("##### START SDXMove\n"));
3094 DebugPrint(DEBUG_INFO, SECTION_MOVE,_("%-20s : from = %d, to = %d\n"), "SDXMove", from, to);
3097 if ((pfrom = LookupElement(from)) == NULL)
3099 DebugPrint(DEBUG_INFO, SECTION_MOVE,_("SDXMove : ElementInfo for %d not found\n"), from);
3100 DebugPrint(DEBUG_INFO, SECTION_MOVE,_("##### STOP SDXMove\n"));
3105 if ((pto = LookupElement(to)) == NULL)
3107 DebugPrint(DEBUG_INFO, SECTION_MOVE,_("SDXMove : ElementInfo for %d not found\n"), to);
3108 DebugPrint(DEBUG_INFO, SECTION_MOVE,_("##### STOP SDXMove\n"));
3113 if (pfrom->status == 'E')
3115 DebugPrint(DEBUG_INFO, SECTION_MOVE,_("SDXMove : from %d is empty\n"), from);
3116 DebugPrint(DEBUG_INFO, SECTION_MOVE,_("##### STOP SDXMove\n"));
3121 if (pto->status == 'F')
3123 switch (pto->status)
3128 DebugPrint(DEBUG_INFO, SECTION_MOVE,_("SDXMove : Destination Element %d Type %d is full\n"),
3129 pto->address, pto->type);
3130 to = find_empty(DeviceFD, 0, 0);
3133 DebugPrint(DEBUG_ERROR, SECTION_MOVE,_("SDXMove : no empty slot found for unload\n"));
3137 DebugPrint(DEBUG_INFO, SECTION_MOVE,_("SDXMove : Unload to %d\n"), to);
3138 if ((pto = LookupElement(to)) == NULL)
3140 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("SDXMove : ElementInfo for %d not found\n"), to);
3141 DebugPrint(DEBUG_INFO, SECTION_MOVE,_("##### STOP SDXMove\n"));
3153 moveok = CheckMove(pfrom, pto);
3158 SDX_DTE = pto->address;
3161 SDX_STE = pto->address;
3164 SDX_STE = pto->address;
3168 switch (pfrom->type)
3171 SDX_DTE = pfrom->address;
3174 SDX_STE = pfrom->address;
3177 SDX_STE = pfrom->address;
3181 if (SDX_DTE >= 0 && SDX_STE >= 0)
3183 ret = SCSI_AlignElements(DeviceFD, SDX_MTE, SDX_DTE, SDX_STE);
3184 DebugPrint(DEBUG_INFO, SECTION_MOVE,_("##### SCSI_AlignElemnts ret = %d\n"),ret);
3187 DebugPrint(DEBUG_INFO, SECTION_MOVE,_("##### STOP SDXMove\n"));
3192 DebugPrint(DEBUG_INFO, SECTION_MOVE,_("##### Error setting STE/DTE %d/%d\n"), SDX_STE, SDX_DTE);
3193 DebugPrint(DEBUG_INFO, SECTION_MOVE,_("##### STOP SDXMove\n"));
3199 * If from is a tape we must check if it is loaded
3200 * and if yes we have to eject it
3202 if (pfrom->type == TAPETYPE)
3204 tapestat = Tape_Status(INDEX_TAPE);
3205 if ( tapestat & TAPE_ONLINE)
3207 if (pDev[INDEX_TAPECTL].SCSI == 1)
3209 ret = eject_tape(pDev[INDEX_TAPECTL].dev,1);
3211 ret = eject_tape(pDev[INDEX_TAPE].dev,2);
3216 if ((ret == 0) && moveok)
3218 ret = SCSI_Move(DeviceFD, 0, from, to);
3220 DebugPrint(DEBUG_INFO, SECTION_MOVE,_("##### STOP SDXMove\n"));
3224 DebugPrint(DEBUG_INFO, SECTION_MOVE,_("##### STOP SDXMove\n"));
3229 * Do the move. We don't address the MTE element (the gripper)
3230 * here. We assume that the library use the right MTE
3234 * != 0 -> error either from the SCSI command or from
3235 * the element handling
3244 ElementInfo_T *pfrom;
3248 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("##### START GenericMove\n"));
3250 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("%-20s : from = %d, to = %d\n"), "GenericMove", from, to);
3253 if ((pfrom = LookupElement(from)) == NULL)
3255 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("GenericMove : ElementInfo for %d not found\n"), from);
3256 DebugPrint(DEBUG_INFO, SECTION_MOVE,_("##### STOP GenericMove\n"));
3261 if ((pto = LookupElement(to)) == NULL)
3263 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("GenericMove : ElementInfo for %d not found\n"), to);
3264 DebugPrint(DEBUG_INFO, SECTION_MOVE,_("##### STOP GenericMove\n"));
3269 if (pfrom->status == 'E')
3271 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("GenericMove : from %d is empty\n"), from);
3272 DebugPrint(DEBUG_INFO, SECTION_MOVE,_("##### STOP GenericMove\n"));
3277 if (pto->status == 'F')
3279 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("GenericMove : Destination Element %d Type %d is full\n"),
3280 pto->address, pto->type);
3281 to = find_empty(DeviceFD, 0, 0);
3284 DebugPrint(DEBUG_ERROR, SECTION_MOVE, _("GenericMove : no empty slot found\n"));
3288 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("GenericMove : Unload to %d\n"), to);
3289 if ((pto = LookupElement(to)) == NULL)
3291 DebugPrint(DEBUG_ERROR, SECTION_MOVE, _(" Ups should not happen\n"));
3292 DebugPrint(DEBUG_INFO, SECTION_MOVE,_("##### STOP GenericMove\n"));
3298 if (CheckMove(pfrom, pto))
3300 ret = SCSI_Move(DeviceFD, 0, from, to);
3303 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("GenericMove : SCSI_Move return (%d)\n"), ret);
3304 DebugPrint(DEBUG_INFO, SECTION_MOVE,_("##### STOP GenericMove\n"));
3309 * Check if a move based on the information we got from the Mode Sense command
3318 ElementInfo_T * from,
3323 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("##### START CheckMove\n"));
3324 if (pDeviceCapabilitiesPage != NULL )
3326 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("CheckMove : checking if move from %d to %d is legal\n"), from->address, to->address);
3330 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("CheckMove : MT2"));
3334 if (pDeviceCapabilitiesPage->MT2MT == 1)
3336 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("MT\n"));
3341 if (pDeviceCapabilitiesPage->MT2ST == 1)
3343 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("ST\n"));
3348 if (pDeviceCapabilitiesPage->MT2IE == 1)
3350 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("IE\n"));
3355 if (pDeviceCapabilitiesPage->MT2DT == 1)
3357 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("DT\n"));
3366 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("CheckMove : ST2"));
3370 if (pDeviceCapabilitiesPage->ST2MT == 1)
3372 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("MT\n"));
3377 if (pDeviceCapabilitiesPage->ST2ST == 1)
3379 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("ST\n"));
3384 if (pDeviceCapabilitiesPage->ST2IE == 1)
3386 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("IE\n"));
3391 if (pDeviceCapabilitiesPage->ST2DT == 1)
3393 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("DT\n"));
3402 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("CheckMove : IE2"));
3406 if (pDeviceCapabilitiesPage->IE2MT == 1)
3408 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("MT\n"));
3413 if (pDeviceCapabilitiesPage->IE2ST == 1)
3415 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("ST\n"));
3420 if (pDeviceCapabilitiesPage->IE2IE == 1)
3422 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("IE\n"));
3427 if (pDeviceCapabilitiesPage->IE2DT == 1)
3429 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("DT\n"));
3438 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("CheckMove : DT2"));
3442 if (pDeviceCapabilitiesPage->DT2MT == 1)
3444 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("MT\n"));
3449 if (pDeviceCapabilitiesPage->DT2ST == 1)
3451 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("ST\n"));
3456 if (pDeviceCapabilitiesPage->DT2IE == 1)
3458 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("IE\n"));
3463 if (pDeviceCapabilitiesPage->DT2DT == 1)
3465 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("DT\n"));
3477 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("CheckMove : pDeviceCapabilitiesPage == NULL"));
3479 ChgExit("CheckMove", _("DeviceCapabilitiesPage == NULL"), FATAL);
3484 DebugPrint(DEBUG_INFO, SECTION_MOVE, _("###### STOP CheckMove\n"));
3496 extern OpenFiles_T *pDev;
3498 dbprintf(_("##### START GetCurrentSlot\n"));
3500 (void)fd; /* Quiet unused parameter warning */
3502 if (pDev[0].SCSI == 0)
3504 dbprintf(_("GetCurrentSlot : can't send SCSI commands\n"));
3509 if (ElementStatusValid == 0)
3511 if (pDev[0].functions->function_status(0, 1) != 0)
3518 /* If the from address is the as the same as the tape address skip it */
3519 if (pDTE[drive].from >= 0 && pDTE[drive].from != pDTE[drive].address)
3521 for (x = 0; x < STE;x++)
3523 if (pSTE[x].address == pDTE[drive].from)
3531 for (x = 0; x < STE;x++)
3533 if (pSTE[x].status == 'E') {
3539 /* Ups nothing loaded */
3546 * Reworked function to get the ElementStatus
3547 * This function will first call the GetElementStatus
3548 * function to get the Element status,
3549 * and than check if there are abnormal conditions.
3551 * If there are error conditions try to fix them
3555 GenericElementStatus(
3564 extern OpenFiles_T *pDev;
3566 int error = 0; /* If set do an INIT ELEMENT STATUS */
3567 size_t x; /* The standard loop counter :-) */
3568 int retry = 2; /* Redo it if an error has been reset */
3570 (void)InitStatus; /* Quiet unused parameter warning */
3572 DebugPrint(DEBUG_INFO, SECTION_ELEMENT, _("##### START GenericElementStatus\n"));
3574 if (pEAAPage == NULL)
3577 * If this pointer is null
3578 * then try to read the parameter with MODE SENSE
3581 if (pModePage == NULL && LibModeSenseValid == 0)
3583 pModePage = alloc(0xff);
3585 if (SCSI_ModeSense(DeviceFD, pModePage, 0xff, 0x8, 0x3f) == 0)
3587 LibModeSenseValid = 1;
3588 DecodeModeSense(pModePage, 0, _("GenericElementStatus :"), 0, debug_file);
3590 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,_("GetElementStatus : failed SCSI_ModeSense\n"));
3591 LibModeSenseValid = -1;
3596 while ((GetElementStatus(DeviceFD) == 0) && (retry-- > 0))
3598 for (x = 0; x < MTE; x++)
3600 if (pMTE[x].ASC > 0)
3602 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pMTE[x].ASC, pMTE[x].ASCQ, (RequestSense_T *)&pMTE[x]))
3609 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("GenericElementStatus : Abort on MTE\n"));
3616 for (x = 0; x < IEE; x++)
3618 if (pIEE[x].ASC > 0)
3620 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pIEE[x].ASC, pIEE[x].ASCQ, (RequestSense_T *)&pIEE[x]))
3627 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("GenericElementStatus : Abort on IEE\n"));
3635 for (x = 0; x < STE; x++)
3637 if (pSTE[x].ASC > 0)
3639 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pSTE[x].ASC, pSTE[x].ASCQ, (RequestSense_T *)&pSTE[x]))
3646 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("GenericElementStatus : Abort on IES\n"));
3653 for (x = 0; x < DTE; x++)
3655 if (pDTE[x].ASC > 0)
3657 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pDTE[x].ASC, pDTE[x].ASCQ, (RequestSense_T *)&pDTE[x]))
3664 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("GenericElementStatus : Abort on DTE\n"));
3672 * OK, we have an error, do an INIT ELMENT
3673 * For the tape if not handled by the robot we have
3674 * to do some extra checks
3678 if (GenericResetStatus(DeviceFD) != 0)
3680 ElementStatusValid = 0;
3681 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("GenericElementStatus : Can't init status STEError(%d) MTEError(%d) DTEError(%d) IEEError(%d)\n"), STEError, MTEError, DTEError, IEEError);
3692 * If the status is empty to an move from tape to tape
3693 * This is if the tape is ejected, but not unloaded
3695 if (pDTE[0].status == 'E')
3697 DebugPrint(DEBUG_INFO, SECTION_ELEMENT, _("GenericElementStatus : try to move tape to tape drive\n"));
3698 pDev[DeviceFD].functions->function_move(DeviceFD, pDTE[0].address, pDTE[0].address);
3701 /* Done GetElementStatus */
3706 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("GenericElementStatus : Can't init status (after loop)\n"));
3711 ElementStatusValid = 1;
3712 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("#### STOP GenericElementStatus\n"));
3718 * This is for the ADIC changer, it seems that they have an diferent
3719 * offset in the mode sense data before the first mode page (+12)
3722 DLT448ElementStatus(
3728 extern OpenFiles_T *pDev;
3730 int error = 0; /* If set do an INIT ELEMENT STATUS */
3731 size_t x; /* The standard loop counter :-) */
3732 int loop = 2; /* Redo it if an error has been reset */
3734 (void)InitStatus; /* Quiet unused parameter warning */
3736 DebugPrint(DEBUG_INFO, SECTION_ELEMENT, _("##### START DLT448ElementStatus\n"));
3738 if (pEAAPage == NULL)
3741 * If this pointer is null
3742 * then try to read the parameter with MODE SENSE
3745 if (pModePage == NULL && LibModeSenseValid == 0)
3747 pModePage = alloc(0xff);
3749 if (SCSI_ModeSense(DeviceFD, pModePage, 0xff, 0x8, 0x3f) == 0)
3751 LibModeSenseValid = 1;
3752 DecodeModeSense(pModePage, 12, _("DLT448ElementStatus :"), 0, debug_file);
3754 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,_("DLT448ElementStatus : failed SCSI_ModeSense\n"));
3755 LibModeSenseValid = -1;
3760 while (GetElementStatus(DeviceFD) == 0 && loop-- > 0)
3762 for (x = 0; x < MTE; x++)
3764 if (pMTE[x].ASC > 0)
3766 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pMTE[x].ASC, pMTE[x].ASCQ, (RequestSense_T *)&pMTE[x]))
3772 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("DLT448ElementStatus : Abort on MTE\n"));
3779 for (x = 0; x < IEE; x++)
3781 if (pIEE[x].ASC > 0)
3783 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pIEE[x].ASC, pIEE[x].ASCQ, (RequestSense_T *)&pIEE[x]))
3789 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("DLT448ElementStatus : Abort on IEE\n"));
3797 for (x = 0; x < STE; x++)
3800 * Needed for the hack to guess the tape status if an error
3801 * for the tape is pending
3803 if (pSTE[x].ASC > 0)
3805 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pSTE[x].ASC, pSTE[x].ASCQ, (RequestSense_T *)&pSTE[x]))
3811 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("DLT448ElementStatus : Abort on IES\n"));
3818 for (x = 0; x < DTE; x++)
3820 if (pDTE[x].ASC > 0)
3822 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pDTE[x].ASC, pDTE[x].ASCQ, (RequestSense_T *)&pDTE[x]))
3829 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("DLT448ElementStatus : Abort on DTE\n"));
3837 * OK, we have an error, do an INIT ELMENT
3838 * For the tape if not handled by the robot we have
3839 * to do some extra checks
3843 if (GenericResetStatus(DeviceFD) != 0)
3845 ElementStatusValid = 0;
3846 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("DLT448ElementStatus : Can't init status\n"));
3857 * If the status is empty to an move from tape to tape
3858 * This is if the tape is ejected, but not unloaded
3860 if (pDTE[0].status == 'E')
3862 DebugPrint(DEBUG_INFO, SECTION_ELEMENT, _("DLT448ElementStatus : try to move tape to tape drive\n"));
3863 pDev[DeviceFD].functions->function_move(DeviceFD, pDTE[0].address, pDTE[0].address);
3866 /* Done GetElementStatus */
3871 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("DLT448ElementStatus : Can't init status (after loop)\n"));
3876 ElementStatusValid = 1;
3877 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("#### STOP DLT448ElementStatus\n"));
3883 * Much the same like GenericElementStatus but
3884 * it seemes that for the STE Elements ASC/ASCQ is not set
3885 * on an error, only the except bit is set
3892 int error = 0; /* If set do an INIT ELEMENT STATUS */
3893 size_t x; /* The standard loop counter :-) */
3894 int loop = 2; /* Redo it if an error has been reset */
3896 (void)InitStatus; /* Quiet unused parameter warning */
3898 DebugPrint(DEBUG_INFO, SECTION_ELEMENT, _("##### START SDXElementStatus\n"));
3900 if (pEAAPage == NULL)
3903 * If this pointer is null
3904 * then try to read the parameter with MODE SENSE
3907 if (pModePage == NULL && LibModeSenseValid == 0)
3909 pModePage = alloc(0xff);
3911 if (SCSI_ModeSense(DeviceFD, pModePage, 0xff, 0x8, 0x3f) == 0)
3913 LibModeSenseValid = 1;
3914 DecodeModeSense(pModePage, 0, _("SDXElementStatus :"), 0, debug_file);
3916 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,_("SDXElementStatus : failed SCSI_ModeSense\n"));
3917 LibModeSenseValid = -1;
3922 while (GetElementStatus(DeviceFD) == 0 && loop--)
3925 for (x = 0; x < MTE; x++)
3927 if (pMTE[x].ASC > 0)
3929 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pMTE[x].ASC, pMTE[x].ASCQ, (RequestSense_T *)&pMTE[x]))
3935 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("SDXElementStatus : Abort on MTE\n"));
3942 for (x = 0; x < IEE; x++)
3944 if (pIEE[x].ASC > 0)
3946 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pIEE[x].ASC, pIEE[x].ASCQ, (RequestSense_T *)&pIEE[x]))
3952 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("SDXElementStatus : Abort on IEE\n"));
3960 for (x = 0; x < STE; x++)
3962 if (pSTE[x].ASC > 0)
3964 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pSTE[x].ASC, pSTE[x].ASCQ, (RequestSense_T *)&pSTE[x]))
3970 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("SDXElementStatus : Abort on IES\n"));
3977 for (x = 0; x < DTE; x++)
3979 if (pDTE[x].ASC > 0)
3981 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pDTE[x].ASC, pDTE[x].ASCQ, (RequestSense_T *)&pDTE[x]))
3989 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("SDXElementStatus : Abort on DTE\n"));
3997 * OK, we have an error, do an INIT ELMENT
3998 * For the tape if not handled by the robot we have
3999 * to do some extra checks
4003 if (GenericResetStatus(DeviceFD) != 0)
4005 ElementStatusValid = 0;
4006 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("SDXElementStatus : Can't init status\n"));
4012 /* Done GetElementStatus */
4017 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("SDXElementStatus : Can't init status\n"));
4022 ElementStatusValid = 1;
4024 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, _("#### STOP SDXElementStatus\n"));
4030 * Reads the element information from the library. There are 2 ways to do this.
4031 * Either check the result from the mode sense page to see which types of elements
4032 * are available (STE/DTE/MTE....), or do an read element status with the option give
4033 * me all and than check what is available.
4035 * Only do the read, error handling is done by the calling function
4047 u_char *DataBuffer = NULL;
4048 size_t DataBufferLength;
4049 ElementStatusData_T *ElementStatusData;
4050 ElementStatusPage_T *ElementStatusPage;
4051 MediumTransportElementDescriptor_T *MediumTransportElementDescriptor;
4052 StorageElementDescriptor_T *StorageElementDescriptor;
4053 DataTransferElementDescriptor_T *DataTransferElementDescriptor;
4054 ImportExportElementDescriptor_T *ImportExportElementDescriptor;
4057 size_t length; /* Length of an Element */
4058 size_t NoOfElements;
4060 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("##### START GetElementStatus\n"));
4062 barcode = BarCode(DeviceFD);
4065 * If the MODE_SENSE was successfull we use this Information to read the Elelement Info
4067 if (pEAAPage != NULL)
4069 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Reading Element Status with the info from mode sense\n"));
4070 /* First the Medim Transport*/
4071 if (V2(pEAAPage->NoMediumTransportElements) > 0)
4073 MTE = V2(pEAAPage->NoMediumTransportElements) ;
4074 pMTE = alloc(SIZEOF(ElementInfo_T) * MTE);
4075 memset(pMTE, 0, SIZEOF(ElementInfo_T) * MTE);
4077 if (SCSI_ReadElementStatus(DeviceFD,
4081 V2(pEAAPage->MediumTransportElementAddress),
4083 SIZEOF(MediumTransportElementDescriptor_T),
4086 ChgExit("genericElementStatus",_("Can't read MTE status"), FATAL);
4089 // ElementStatusData = (ElementStatusData_T *)DataBuffer;
4090 offset = SIZEOF(ElementStatusData_T);
4092 ElementStatusPage = (ElementStatusPage_T *)&DataBuffer[offset];
4093 offset = offset + SIZEOF(ElementStatusPage_T);
4094 length = V2(ElementStatusPage->length);
4096 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("MTE Length %d(%d)\n"), length,
4097 SIZEOF(MediumTransportElementDescriptor_T));
4099 for (x = 0; x < MTE; x++)
4101 MediumTransportElementDescriptor = (MediumTransportElementDescriptor_T *)&DataBuffer[offset];
4103 if (ElementStatusPage->pvoltag == 1)
4105 strncpy((char *)pMTE[x].VolTag,
4106 (char *)MediumTransportElementDescriptor->pvoltag,
4108 TerminateString(pMTE[x].VolTag, TAG_SIZE+1);
4111 pMTE[x].type = ElementStatusPage->type;
4112 pMTE[x].address = V2(MediumTransportElementDescriptor->address);
4113 pMTE[x].except = MediumTransportElementDescriptor->except;
4114 pMTE[x].full = MediumTransportElementDescriptor->full;
4115 if (MediumTransportElementDescriptor->full > 0)
4117 pMTE[x].status = 'F';
4119 pMTE[x].status = 'E';
4124 pMTE[x].ASC = MediumTransportElementDescriptor->asc;
4126 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Skip ASC MTE\n"));
4131 pMTE[x].ASCQ = MediumTransportElementDescriptor->ascq;
4133 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Skip ASCQ MTE\n"));
4138 if (MediumTransportElementDescriptor->svalid == 1)
4140 pMTE[x].from = V2(MediumTransportElementDescriptor->source);
4145 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Skip source MTE\n"));
4147 offset = offset + length;
4155 if ( V2(pEAAPage->NoStorageElements) > 0)
4158 STE = V2(pEAAPage->NoStorageElements);
4159 pSTE = alloc(SIZEOF(ElementInfo_T) * STE);
4160 memset(pSTE, 0, SIZEOF(ElementInfo_T) * STE);
4162 if (SCSI_ReadElementStatus(DeviceFD,
4166 V2(pEAAPage->FirstStorageElementAddress),
4168 SIZEOF(StorageElementDescriptor_T),
4171 ChgExit("GetElementStatus", _("Can't read STE status"), FATAL);
4174 assert(DataBuffer != NULL);
4176 // ElementStatusData = (ElementStatusData_T *)DataBuffer;
4177 offset = SIZEOF(ElementStatusData_T);
4179 ElementStatusPage = (ElementStatusPage_T *)&DataBuffer[offset];
4180 offset = offset + SIZEOF(ElementStatusPage_T);
4181 length = V2(ElementStatusPage->length);
4182 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("STE Length %d\n"),length);
4184 for (x = 0; x < STE; x++)
4186 StorageElementDescriptor = (StorageElementDescriptor_T *)&DataBuffer[offset];
4187 if (ElementStatusPage->pvoltag == 1)
4189 strncpy(pSTE[x].VolTag,
4190 (char *)StorageElementDescriptor->pvoltag,
4192 TerminateString(pSTE[x].VolTag, TAG_SIZE+1);
4196 pSTE[x].type = ElementStatusPage->type;
4197 pSTE[x].address = V2(StorageElementDescriptor->address);
4198 pSTE[x].except = StorageElementDescriptor->except;
4199 pSTE[x].full = StorageElementDescriptor->full;
4200 if (StorageElementDescriptor->full > 0)
4202 pSTE[x].status = 'F';
4204 pSTE[x].status = 'E';
4209 pSTE[x].ASC = StorageElementDescriptor->asc;
4211 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Skip ASC STE\n"));
4216 pSTE[x].ASCQ = StorageElementDescriptor->ascq;
4218 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Skip ASCQ STE\n"));
4223 if (StorageElementDescriptor->svalid == 1)
4225 pSTE[x].from = V2(StorageElementDescriptor->source);
4230 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Skip source STE\n"));
4233 offset = offset + length;
4239 * Import/Export Elements
4241 if ( V2(pEAAPage->NoImportExportElements) > 0)
4244 IEE = V2(pEAAPage->NoImportExportElements);
4245 pIEE = alloc(SIZEOF(ElementInfo_T) * IEE);
4246 memset(pIEE, 0, SIZEOF(ElementInfo_T) * IEE);
4248 if (SCSI_ReadElementStatus(DeviceFD,
4252 V2(pEAAPage->FirstImportExportElementAddress),
4254 SIZEOF(ImportExportElementDescriptor_T),
4257 ChgExit("GetElementStatus", _("Can't read IEE status"), FATAL);
4260 assert(DataBuffer != NULL);
4262 // ElementStatusData = (ElementStatusData_T *)DataBuffer;
4263 offset = SIZEOF(ElementStatusData_T);
4265 ElementStatusPage = (ElementStatusPage_T *)&DataBuffer[offset];
4266 offset = offset + SIZEOF(ElementStatusPage_T);
4267 length = V2(ElementStatusPage->length);
4268 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("IEE Length %d\n"),length);
4270 for (x = 0; x < IEE; x++)
4272 ImportExportElementDescriptor = (ImportExportElementDescriptor_T *)&DataBuffer[offset];
4273 if (ElementStatusPage->pvoltag == 1)
4275 strncpy(pIEE[x].VolTag,
4276 (char *)ImportExportElementDescriptor->pvoltag,
4278 TerminateString(pIEE[x].VolTag, TAG_SIZE+1);
4280 pIEE[x].type = ElementStatusPage->type;
4281 pIEE[x].address = V2(ImportExportElementDescriptor->address);
4282 pIEE[x].except = ImportExportElementDescriptor->except;
4283 pIEE[x].full = ImportExportElementDescriptor->full;
4284 if (ImportExportElementDescriptor->full > 0)
4286 pIEE[x].status = 'F';
4288 pIEE[x].status = 'E';
4293 pIEE[x].ASC = ImportExportElementDescriptor->asc;
4295 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Skip ASC IEE\n"));
4300 pIEE[x].ASCQ = ImportExportElementDescriptor->ascq;
4302 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Skip ASCQ IEE\n"));
4307 if (ImportExportElementDescriptor->svalid == 1)
4309 pIEE[x].from = V2(ImportExportElementDescriptor->source);
4314 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Skip source IEE\n"));
4317 offset = offset + length;
4323 * Data Transfer Elements
4325 if (V2(pEAAPage->NoDataTransferElements) >0)
4328 DTE = V2(pEAAPage->NoDataTransferElements) ;
4329 pDTE = alloc(SIZEOF(ElementInfo_T) * DTE);
4330 memset(pDTE, 0, SIZEOF(ElementInfo_T) * DTE);
4332 if (SCSI_ReadElementStatus(DeviceFD,
4336 V2(pEAAPage->FirstDataTransferElementAddress),
4338 SIZEOF(DataTransferElementDescriptor_T),
4341 ChgExit("GenericElementStatus", _("Can't read DTE status"), FATAL);
4344 assert(DataBuffer != NULL);
4346 // ElementStatusData = (ElementStatusData_T *)DataBuffer;
4347 offset = SIZEOF(ElementStatusData_T);
4349 ElementStatusPage = (ElementStatusPage_T *)&DataBuffer[offset];
4350 offset = offset + SIZEOF(ElementStatusPage_T);
4351 length = V2(ElementStatusPage->length);
4352 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("DTE Length %d\n"),length);
4354 for (x = 0; x < DTE; x++)
4356 DataTransferElementDescriptor = (DataTransferElementDescriptor_T *)&DataBuffer[offset];
4357 if (ElementStatusPage->pvoltag == 1)
4359 strncpy(pDTE[x].VolTag,
4360 (char *)DataTransferElementDescriptor->pvoltag,
4362 TerminateString(pDTE[x].VolTag, TAG_SIZE+1);
4364 pDTE[x].type = ElementStatusPage->type;
4365 pDTE[x].address = V2(DataTransferElementDescriptor->address);
4366 pDTE[x].except = DataTransferElementDescriptor->except;
4367 pDTE[x].scsi = DataTransferElementDescriptor->scsi;
4368 pDTE[x].full = DataTransferElementDescriptor->full;
4369 if (DataTransferElementDescriptor->full > 0)
4371 pDTE[x].status = 'F';
4373 pDTE[x].status = 'E';
4378 pDTE[x].ASC = DataTransferElementDescriptor->asc;
4380 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Skip ASC DTE\n"));
4385 pDTE[x].ASCQ = DataTransferElementDescriptor->ascq;
4387 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Skip ASCQ DTE\n"));
4392 if (DataTransferElementDescriptor->svalid == 1)
4394 pDTE[x].from = V2(DataTransferElementDescriptor->source);
4399 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Skip source STE\n"));
4402 offset = offset + length;
4409 * And now the old way, when we get here the read mode sense page has failed ...
4411 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Reading Element Status the old way .... (max 255 elements)\n"));
4412 if (SCSI_ReadElementStatus(DeviceFD,
4421 ChgExit("GenericElementStatus",_("Can't get ElementStatus"), FATAL);
4424 assert(DataBuffer != NULL);
4426 ElementStatusData = (ElementStatusData_T *)DataBuffer;
4427 DataBufferLength = V3(ElementStatusData->count);
4429 offset = SIZEOF(ElementStatusData_T);
4431 while (offset < DataBufferLength)
4433 ElementStatusPage = (ElementStatusPage_T *)&DataBuffer[offset];
4434 NoOfElements = V3(ElementStatusPage->count) / V2(ElementStatusPage->length);
4435 offset = offset + SIZEOF(ElementStatusPage_T);
4436 length = V2(ElementStatusPage->length);
4438 switch (ElementStatusPage->type)
4443 pMTE = alloc(SIZEOF(ElementInfo_T) * MTE);
4444 memset(pMTE, 0, SIZEOF(ElementInfo_T) * MTE);
4446 for (x = 0; x < NoOfElements; x++)
4448 MediumTransportElementDescriptor = (MediumTransportElementDescriptor_T *)&DataBuffer[offset];
4449 if (ElementStatusPage->pvoltag == 1)
4451 strncpy(pMTE[x].VolTag,
4452 (char *)MediumTransportElementDescriptor->pvoltag,
4454 TerminateString(pMTE[x].VolTag, TAG_SIZE+1);
4456 pMTE[x].type = ElementStatusPage->type;
4457 pMTE[x].address = V2(MediumTransportElementDescriptor->address);
4458 pMTE[x].except = MediumTransportElementDescriptor->except;
4459 pMTE[x].full = MediumTransportElementDescriptor->full;
4460 if (MediumTransportElementDescriptor->full > 0)
4462 pMTE[x].status = 'F';
4464 pMTE[x].status = 'E';
4469 pMTE[x].ASC = MediumTransportElementDescriptor->asc;
4471 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Skip ASC MTE\n"));
4476 pMTE[x].ASCQ = MediumTransportElementDescriptor->ascq;
4478 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Skip ASCQ MTE\n"));
4483 if (MediumTransportElementDescriptor->svalid == 1)
4485 pMTE[x].from = V2(MediumTransportElementDescriptor->source);
4490 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Skip source MTE\n"));
4493 offset = offset + length;
4499 pSTE = alloc(SIZEOF(ElementInfo_T) * STE);
4500 memset(pSTE, 0, SIZEOF(ElementInfo_T) * STE);
4502 for (x = 0; x < NoOfElements; x++)
4504 StorageElementDescriptor = (StorageElementDescriptor_T *)&DataBuffer[offset];
4505 if (ElementStatusPage->pvoltag == 1)
4507 strncpy(pSTE[x].VolTag,
4508 (char *)StorageElementDescriptor->pvoltag,
4510 TerminateString(pSTE[x].VolTag, TAG_SIZE+1);
4513 pSTE[x].type = ElementStatusPage->type;
4514 pSTE[x].address = V2(StorageElementDescriptor->address);
4515 pSTE[x].except = StorageElementDescriptor->except;
4516 pSTE[x].full = StorageElementDescriptor->full;
4517 if (StorageElementDescriptor->full > 0)
4519 pSTE[x].status = 'F';
4521 pSTE[x].status = 'E';
4526 pSTE[x].ASC = StorageElementDescriptor->asc;
4528 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Skip ASC STE\n"));
4533 pSTE[x].ASCQ = StorageElementDescriptor->ascq;
4535 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Skip ASCQ STE\n"));
4540 if (StorageElementDescriptor->svalid == 1)
4542 pSTE[x].from = V2(StorageElementDescriptor->source);
4547 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Skip source STE\n"));
4550 offset = offset + length;
4556 pIEE = alloc(SIZEOF(ElementInfo_T) * IEE);
4557 memset(pIEE, 0, SIZEOF(ElementInfo_T) * IEE);
4559 for (x = 0; x < NoOfElements; x++)
4561 ImportExportElementDescriptor = (ImportExportElementDescriptor_T *)&DataBuffer[offset];
4562 if (ElementStatusPage->pvoltag == 1)
4564 strncpy(pIEE[x].VolTag,
4565 (char *)ImportExportElementDescriptor->pvoltag,
4567 TerminateString(pIEE[x].VolTag, TAG_SIZE+1);
4569 ImportExportElementDescriptor = (ImportExportElementDescriptor_T *)&DataBuffer[offset];
4570 pIEE[x].type = ElementStatusPage->type;
4571 pIEE[x].address = V2(ImportExportElementDescriptor->address);
4572 pIEE[x].except = ImportExportElementDescriptor->except;
4573 pIEE[x].full = ImportExportElementDescriptor->full;
4574 if (ImportExportElementDescriptor->full > 0)
4576 pIEE[x].status = 'F';
4578 pIEE[x].status = 'E';
4583 pIEE[x].ASC = ImportExportElementDescriptor->asc;
4585 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Skip ASC IEE\n"));
4590 pIEE[x].ASCQ = ImportExportElementDescriptor->ascq;
4592 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Skip ASCQ IEE\n"));
4597 if (ImportExportElementDescriptor->svalid == 1)
4599 pIEE[x].from = V2(ImportExportElementDescriptor->source);
4604 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Skip source IEE\n"));
4607 offset = offset + length;
4613 pDTE = alloc(SIZEOF(ElementInfo_T) * DTE);
4614 memset(pDTE, 0, SIZEOF(ElementInfo_T) * DTE);
4616 for (x = 0; x < NoOfElements; x++)
4618 DataTransferElementDescriptor = (DataTransferElementDescriptor_T *)&DataBuffer[offset];
4619 if (ElementStatusPage->pvoltag == 1)
4621 strncpy(pSTE[x].VolTag,
4622 (char *)DataTransferElementDescriptor->pvoltag,
4624 TerminateString(pSTE[x].VolTag, TAG_SIZE+1);
4626 pDTE[x].type = ElementStatusPage->type;
4627 pDTE[x].address = V2(DataTransferElementDescriptor->address);
4628 pDTE[x].except = DataTransferElementDescriptor->except;
4629 pDTE[x].scsi = DataTransferElementDescriptor->scsi;
4630 pDTE[x].full = DataTransferElementDescriptor->full;
4631 if (DataTransferElementDescriptor->full > 0)
4633 pDTE[x].status = 'F';
4635 pDTE[x].status = 'E';
4640 pDTE[x].ASC = DataTransferElementDescriptor->asc;
4642 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Skip ASC DTE\n"));
4647 pDTE[x].ASCQ = DataTransferElementDescriptor->ascq;
4649 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Skip ASCQ DTE\n"));
4654 if (DataTransferElementDescriptor->svalid == 1)
4656 pDTE[x].from = V2(DataTransferElementDescriptor->source);
4661 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("Skip source STE\n"));
4664 offset = offset + length;
4668 offset = offset + length;
4669 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,_("GetElementStatus : UnGknown Type %d\n"),ElementStatusPage->type);
4676 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("\n\n\tMedia Transport Elements (robot arms) :\n"));
4678 for ( x = 0; x < MTE; x++)
4679 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("\t\tElement #%04d %c\n\t\t\tEXCEPT = %02x\n\t\t\tASC = %02X ASCQ = %02X\n\t\t\tType %d From = %04d\n\t\t\tTAG = %s\n"),
4680 pMTE[x].address, pMTE[x].status, pMTE[x].except, pMTE[x].ASC,
4681 pMTE[x].ASCQ, pMTE[x].type, pMTE[x].from, pMTE[x].VolTag);
4683 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("\n\n\tStorage Elements (Media slots) :\n"));
4685 for ( x = 0; x < STE; x++)
4686 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("\t\tElement #%04d %c\n\t\t\tEXCEPT = %02X\n\t\t\tASC = %02X ASCQ = %02X\n\t\t\tType %d From = %04d\n\t\t\tTAG = %s\n"),
4687 pSTE[x].address, pSTE[x].status, pSTE[x].except, pSTE[x].ASC,
4688 pSTE[x].ASCQ, pSTE[x].type, pSTE[x].from, pSTE[x].VolTag);
4690 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("\n\n\tData Transfer Elements (tape drives) :\n"));
4692 for ( x = 0; x < DTE; x++)
4693 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("\t\tElement #%04d %c\n\t\t\tEXCEPT = %02X\n\t\t\tASC = %02X ASCQ = %02X\n\t\t\tType %d From = %04d\n\t\t\tTAG = %s\n\t\t\tSCSI ADDRESS = %d\n"),
4694 pDTE[x].address, pDTE[x].status, pDTE[x].except, pDTE[x].ASC,
4695 pDTE[x].ASCQ, pDTE[x].type, pDTE[x].from, pDTE[x].VolTag,pDTE[x].scsi);
4697 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("\n\n\tImport/Export Elements :\n"));
4699 for ( x = 0; x < IEE; x++)
4700 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,_("\t\tElement #%04d %c\n\t\t\tEXCEPT = %02X\n\t\t\t\tASC = %02X ASCQ = %02X\n\t\t\tType %d From = %04d\n\t\t\tTAG = %s\n"),
4701 pIEE[x].address, pIEE[x].status, pIEE[x].except, pIEE[x].ASC,
4702 pIEE[x].ASCQ, pIEE[x].type, pIEE[x].from, pIEE[x].VolTag);
4711 * If ClearErrorCounters is set the counters will be reset.
4712 * Used by GenericClean for example
4719 ExtendedRequestSense_T * ExtendedRequestSense,
4720 int ClearErrorCounters)
4725 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("##### START RequestSense\n"));
4727 CDB[0] = SC_COM_REQUEST_SENSE; /* REQUEST SENSE */
4728 CDB[1] = 0; /* Logical Unit Number = 0, Reserved */
4729 CDB[2] = 0; /* Reserved */
4730 CDB[3] = 0; /* Reserved */
4731 CDB[4] = (u_char)sizeof(ExtendedRequestSense_T); /* Allocation Length */
4732 CDB[5] = (u_char)((ClearErrorCounters << 7) & 0x80); /* */
4734 memset(ExtendedRequestSense, 0, SIZEOF(ExtendedRequestSense_T));
4736 ret = SCSI_Run(DeviceFD, Input, CDB, 6,
4737 (char *) ExtendedRequestSense,
4738 SIZEOF(ExtendedRequestSense_T),
4739 (RequestSense_T *) ExtendedRequestSense,
4740 SIZEOF(ExtendedRequestSense_T));
4745 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("##### STOP RequestSense (%d)\n"),ret);
4752 DecodeExtSense(ExtendedRequestSense, "RequestSense : ",debug_file);
4753 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("##### STOP RequestSense (%d)\n"), ExtendedRequestSense->SenseKey);
4754 return(ExtendedRequestSense->SenseKey);
4758 dump_hex((u_char *)ExtendedRequestSense ,
4759 SIZEOF(ExtendedRequestSense_T),
4760 DEBUG_INFO, SECTION_SCSI);
4761 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("##### STOP RequestSense (0)\n"));
4767 * Lookup function pointer for device ....
4777 dbprintf(_("##### START LookupElement\n"));
4781 for (x = 0; x < DTE; x++)
4783 if (pDTE[x].address == address)
4785 dbprintf(_("##### STOP LookupElement (DTE)\n"));
4794 for (x = 0; x < MTE; x++)
4796 if (pMTE[x].address == address)
4798 dbprintf(_("##### STOP LookupElement (MTE)\n"));
4807 for (x = 0; x < STE; x++)
4809 if (pSTE[x].address == address)
4811 dbprintf(_("##### STOP LookupElement (STE)\n"));
4820 for ( x = 0; x < IEE; x++)
4822 if (pIEE[x].address == address)
4824 dbprintf(_("##### STOP LookupElement (IEE)\n"));
4834 * Here comes everything what decode the log Pages
4837 * Fix the result handling from TestUnitReady
4844 extern OpenFiles_T *pDev;
4846 RequestSense_T *pRequestSense;
4847 LogSenseHeader_T *LogSenseHeader;
4848 LogParameter_T *LogParameter;
4849 struct LogPageDecode *p;
4851 extern char *tapestatfile;
4853 unsigned ParameterCode;
4862 (void)DeviceFD; /* Quiet unused parameter warning */
4864 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("##### START LogSense\n"));
4866 if ((tapestatfile != NULL) && (pDev[INDEX_TAPECTL].SCSI == 1) &&
4867 ((StatFile = fopen(tapestatfile,"a")) != NULL))
4869 pRequestSense = alloc(SIZEOF(RequestSense_T));
4871 if (GenericRewind(INDEX_TAPECTL) < 0)
4873 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("LogSense : Rewind failed\n"));
4874 free(pRequestSense);
4880 * Try to read the tape label
4882 if (pDev[INDEX_TAPE].inqdone == 1)
4884 if (pDev[INDEX_TAPE].devopen == 1)
4886 SCSI_CloseDevice(INDEX_TAPE);
4889 if ((chgscsi_result = (char *)tape_rdlabel(pDev[INDEX_TAPE].dev, &chgscsi_datestamp, &chgscsi_label)) == NULL)
4891 g_fprintf(StatFile, _("==== %s ==== %s ====\n"), chgscsi_datestamp, chgscsi_label);
4893 g_fprintf(StatFile, "%s\n", chgscsi_result);
4897 buffer = alloc(size);
4898 memset(buffer, 0, size);
4900 * Get the known log pages
4903 CDB[0] = SC_COM_LOG_SENSE;
4905 CDB[2] = 0x40; /* 0x40 for current values */
4910 MSB2(&CDB[7], size);
4913 if (SCSI_Run(INDEX_TAPECTL, Input, CDB, 10,
4917 SIZEOF(RequestSense_T)) != 0)
4919 DecodeSense(pRequestSense, "LogSense : ",debug_file);
4920 free(pRequestSense);
4927 LogSenseHeader = (LogSenseHeader_T *)buffer;
4928 nologpages = V2(LogSenseHeader->PageLength);
4929 logpages = alloc(nologpages);
4931 memcpy(logpages, buffer + SIZEOF(LogSenseHeader_T), nologpages);
4933 for (count = 0; count < (int)nologpages; count++) {
4934 if (logpages[count] != 0 ) {
4935 memset(buffer, 0, size);
4936 CDB[0] = SC_COM_LOG_SENSE;
4938 CDB[2] = (u_char)(0x40 | logpages[count]);/* 0x40 for current values */
4943 MSB2(&CDB[7], size);
4946 if (SCSI_Run(INDEX_TAPECTL, Input, CDB, 10,
4950 SIZEOF(RequestSense_T)) != 0)
4952 DecodeSense(pRequestSense, "LogSense : ",debug_file);
4953 free(pRequestSense);
4960 LogSenseHeader = (LogSenseHeader_T *)buffer;
4961 length = V2(LogSenseHeader->PageLength);
4962 LogParameter = (LogParameter_T *)(buffer + SIZEOF(LogSenseHeader_T));
4964 * Decode the log pages
4966 p = (struct LogPageDecode *)&DecodePages;
4969 dump_hex((u_char *)LogParameter, 64, DEBUG_INFO, SECTION_SCSI);
4971 while(p->ident != NULL) {
4972 if ((strcmp(pDev[INDEX_TAPECTL].ident, p->ident) == 0 ||strcmp("*", p->ident) == 0) && p->LogPage == logpages[count]) {
4973 p->decode(LogParameter, length);
4975 g_fprintf(StatFile, "\n");
4982 g_fprintf(StatFile, _("Logpage No %d = %x\n"), count ,logpages[count]);
4984 while ((u_char *)LogParameter < (buffer + length)) {
4985 i = LogParameter->ParameterLength;
4986 ParameterCode = V2(LogParameter->ParameterCode);
4989 value = V1((u_char *)LogParameter + SIZEOF(LogParameter_T));
4990 g_fprintf(StatFile, _("ParameterCode %02X = %u(%d)\n"), ParameterCode, value, i);
4993 value = V2((u_char *)LogParameter + SIZEOF(LogParameter_T));
4994 g_fprintf(StatFile, _("ParameterCode %02X = %u(%d)\n"), ParameterCode, value, i);
4997 value = V3((u_char *)LogParameter + SIZEOF(LogParameter_T));
4998 g_fprintf(StatFile, _("ParameterCode %02X = %u(%d)\n"), ParameterCode, value, i);
5001 value = V4((u_char *)LogParameter + SIZEOF(LogParameter_T));
5002 g_fprintf(StatFile, _("ParameterCode %02X = %u(%d)\n"), ParameterCode, value, i);
5005 value = V5((u_char *)LogParameter + SIZEOF(LogParameter_T));
5006 g_fprintf(StatFile, _("ParameterCode %02X = %u(%d)\n"), ParameterCode, value, i);
5009 g_fprintf(StatFile, _("ParameterCode %02X size %d\n"), ParameterCode, i);
5011 LogParameter = (LogParameter_T *)((u_char *)LogParameter + SIZEOF(LogParameter_T) + i);
5013 g_fprintf(StatFile, "\n");
5020 * Reset the cumulative counters
5022 CDB[0] = SC_COM_LOG_SELECT;
5033 if (SCSI_Run(INDEX_TAPECTL, Input, CDB, 10,
5037 SIZEOF(RequestSense_T)) != 0)
5039 DecodeSense(pRequestSense, "LogSense : ",debug_file);
5040 free(pRequestSense);
5050 free(pRequestSense);
5057 DebugPrint(DEBUG_INFO, SECTION_TAPE,_("##### STOP LogSense\n"));
5062 WriteErrorCountersPage(
5063 LogParameter_T * buffer,
5068 LogParameter_T *LogParameter;
5069 unsigned ParameterCode;
5070 LogParameter = buffer;
5072 g_fprintf(StatFile, _("\tWrite Error Counters Page\n"));
5074 while ((u_char *)LogParameter < ((u_char *)buffer + length)) {
5075 i = LogParameter->ParameterLength;
5076 ParameterCode = V2(LogParameter->ParameterCode);
5079 if (Decode(LogParameter, &value) == 0) {
5080 switch (ParameterCode) {
5082 g_fprintf(StatFile, _("%-30s = %u\n"),
5083 _("Total Rewrites"),
5087 g_fprintf(StatFile, _("%-30s = %u\n"),
5088 _("Total Errors Corrected"),
5092 g_fprintf(StatFile, _("%-30s = %u\n"),
5093 _("Total Times E. Processed"),
5097 g_fprintf(StatFile, _("%-30s = %u\n"),
5098 _("Total Bytes Processed"),
5102 g_fprintf(StatFile, _("%-30s = %u\n"),
5103 _("Total Unrecoverable Errors"),
5107 g_fprintf(StatFile, _("Unknown ParameterCode %02X = %u(%d)\n"),
5113 g_fprintf(StatFile, _("Error decoding Result\n"));
5115 LogParameter = (LogParameter_T *)((u_char *)LogParameter + SIZEOF(LogParameter_T) + i);
5120 ReadErrorCountersPage(
5121 LogParameter_T * buffer,
5126 LogParameter_T *LogParameter;
5127 unsigned ParameterCode;
5128 LogParameter = buffer;
5130 g_fprintf(StatFile, _("\tRead Error Counters Page\n"));
5132 while ((u_char *)LogParameter < ((u_char *)buffer + length)) {
5133 i = LogParameter->ParameterLength;
5134 ParameterCode = V2(LogParameter->ParameterCode);
5137 if (Decode(LogParameter, &value) == 0) {
5138 switch (ParameterCode) {
5140 g_fprintf(StatFile, _("%-30s = %u\n"),
5145 g_fprintf(StatFile, _("%-30s = %u\n"),
5146 _("Total Errors Corrected"),
5150 g_fprintf(StatFile, _("%-30s = %u\n"),
5151 _("Total Times E. Processed"),
5155 g_fprintf(StatFile, _("%-30s = %u\n"),
5156 _("Total Bytes Processed"),
5160 g_fprintf(StatFile, _("%-30s = %u\n"),
5161 _("Total Unrecoverable Errors"),
5165 g_fprintf(StatFile, _("Unknown ParameterCode %02X = %u(%d)\n"),
5171 g_fprintf(StatFile, _("Error decoding Result\n"));
5173 LogParameter = (LogParameter_T *)((u_char *)LogParameter + SIZEOF(LogParameter_T) + i);
5179 LogParameter_T * buffer,
5184 LogParameter_T *LogParameter;
5185 unsigned ParameterCode;
5186 LogParameter = buffer;
5188 g_fprintf(StatFile, _("\tData compression transfer Page\n"));
5190 while ((u_char *)LogParameter < ((u_char *)buffer + length)) {
5191 i = LogParameter->ParameterLength;
5192 ParameterCode = V2(LogParameter->ParameterCode);
5195 if (Decode(LogParameter, &value) == 0) {
5196 switch (ParameterCode) {
5198 g_fprintf(StatFile, _("Unknown ParameterCode %02X = %u(%d)\n"),
5204 LogParameter = (LogParameter_T *)((u_char *)LogParameter + SIZEOF(LogParameter_T) + i);
5210 LogParameter_T * buffer,
5215 LogParameter_T *LogParameter;
5216 unsigned ParameterCode;
5217 LogParameter = buffer;
5219 g_fprintf(StatFile, _("\tDrive Counters Page\n"));
5221 while ((u_char *)LogParameter < ((unsigned char *)buffer + length)) {
5222 i = LogParameter->ParameterLength;
5223 ParameterCode = V2(LogParameter->ParameterCode);
5226 if (Decode(LogParameter, &value) == 0) {
5227 switch (ParameterCode) {
5229 g_fprintf(StatFile, _("%-30s = %u\n"),
5234 g_fprintf(StatFile, _("%-30s = %u\n"),
5235 _("Total write drive errors"),
5239 g_fprintf(StatFile, _("%-30s = %u\n"),
5240 _("Total read drive errors"),
5244 g_fprintf(StatFile, _("Unknown ParameterCode %02X = %u(%d)\n"),
5250 LogParameter = (LogParameter_T *)((u_char *)LogParameter + SIZEOF(LogParameter_T) + i);
5256 LogParameter_T * buffer,
5261 LogParameter_T *LogParameter;
5262 unsigned ParameterCode;
5263 LogParameter = buffer;
5265 g_fprintf(StatFile, _("\tData Compression Page\n"));
5267 while ((u_char *)LogParameter < ((unsigned char *)buffer + length)) {
5268 i = LogParameter->ParameterLength;
5269 ParameterCode = V2(LogParameter->ParameterCode);
5272 if (Decode(LogParameter, &value) == 0) {
5273 switch (ParameterCode) {
5275 g_fprintf(StatFile, _("%-30s = %u\n"),
5276 _("KB to Compressor"),
5280 g_fprintf(StatFile, _("%-30s = %u\n"),
5285 g_fprintf(StatFile, _("Unknown ParameterCode %02X = %u(%d)\n"),
5291 LogParameter = (LogParameter_T *)((u_char *)LogParameter + SIZEOF(LogParameter_T) + i);
5297 LogParameter_T * buffer,
5302 LogParameter_T *LogParameter;
5303 unsigned ParameterCode;
5304 LogParameter = buffer;
5306 g_fprintf(StatFile, _("\tDrive Usage Information Page\n"));
5308 while ((u_char *)LogParameter < ((unsigned char *)buffer + length)) {
5309 i = LogParameter->ParameterLength;
5310 ParameterCode = V2(LogParameter->ParameterCode);
5313 if (Decode(LogParameter, &value) == 0) {
5314 switch (ParameterCode) {
5322 g_fprintf(StatFile, _("%-30s = %u\n"),
5323 _("Total Load Count"),
5327 g_fprintf(StatFile, _("%-30s = %u\n"),
5328 _("MinutesSince Last Clean"),
5335 g_fprintf(StatFile, _("%-30s = %u\n"),
5336 _("Cleaning Count"),
5347 g_fprintf(StatFile, _("%-30s = %u\n"),
5356 g_fprintf(StatFile, _("Unknown ParameterCode %02X = %u(%d)\n"),
5362 LogParameter = (LogParameter_T *)((u_char *)LogParameter + SIZEOF(LogParameter_T) + i);
5368 LogParameter_T * LogParameter,
5372 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("##### START Decode\n"));
5373 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("Decode Parameter with length %d\n"), LogParameter->ParameterLength);
5376 switch (LogParameter->ParameterLength) {
5378 *value = V1((u_char *)LogParameter + SIZEOF(LogParameter_T));
5381 *value = V2((u_char *)LogParameter + SIZEOF(LogParameter_T));
5384 *value = V3((u_char *)LogParameter + SIZEOF(LogParameter_T));
5387 *value = V4((u_char *)LogParameter + SIZEOF(LogParameter_T));
5390 *value = V5((u_char *)LogParameter + SIZEOF(LogParameter_T));
5393 *value = V6((u_char *)LogParameter + SIZEOF(LogParameter_T));
5396 g_fprintf(StatFile, _("Can't decode ParameterCode %02X size %d\n"),
5397 V2(LogParameter->ParameterCode), LogParameter->ParameterLength);
5398 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("##### STOP Decode (1)\n"));
5402 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("Result = %d\n"), *value);
5403 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("##### STOP Decode(0)\n"));
5414 g_printf(_("%s Devicefd %d\n"), device, p->fd);
5415 g_printf(_("%s Can SCSI %d\n"), device, p->SCSI);
5416 g_printf(_("%s Device %s\n"), device, (p->dev != NULL)? p->dev:_("No set"));
5417 g_printf(_("%s ConfigName %s\n"), device, (p->ConfigName != NULL) ? p->ConfigName:_("Not ser"));
5419 g_printf(_("%s Null Pointer ....\n"), device);
5428 u_char buffer[1024];
5433 (void)option; /* Quiet unused parameter warning */
5435 if ((ip=fopen("/tmp/chg-scsi-trace", "r")) == NULL)
5440 for (x = 0; x < 1024; x++)
5442 if (fscanf(ip, "%2x", &bufferx) == EOF)
5447 buffer[x] = (u_char)bufferx;
5451 DecodeModeSense(&buffer[0], 12, "DLT448ElementStatus :", 0, debug_file);
5456 * Display all Information we can get about the library....
5463 char * changer_file,
5467 extern OpenFiles_T *pDev;
5470 ExtendedRequestSense_T ExtRequestSense;
5473 ChangerCMD_T *p = (ChangerCMD_T *)&ChangerIO;
5474 pbarcoderes = alloc(SIZEOF(MBC_T));
5475 memset(pbarcoderes, 0, SIZEOF(MBC_T));
5477 if (pModePage == NULL) {
5478 pModePage = alloc(0xff);
5481 if ((out = fdopen(1 , "w")) == NULL)
5483 g_printf(_("Error fdopen stdout\n"));
5489 if (strcmp("types", option) == 0 || strcmp("all", option) == 0)
5491 while(p->ident != NULL)
5493 g_printf (_("Ident = %s, type = %s\n"),p->ident, p->type);
5499 if (strcmp("robot", option) == 0 || strcmp("all", option) == 0)
5501 if (ElementStatusValid == 0)
5503 if (pDev[INDEX_CHANGER].functions->function_status(pDev[INDEX_CHANGER].fd, 1) != 0)
5505 g_printf(_("Can not initialize changer status\n"));
5512 /* 0123456789012345678901234567890123456789012 */
5515 g_printf(_("Address Type Status From Barcode Label\n"));
5517 g_printf(_("Address Type Status From\n"));
5519 g_printf(_("-------------------------------------------\n"));
5522 for ( x = 0; x < MTE; x++)
5525 g_printf(_("%07d MTE %s %04d %s "),pMTE[x].address,
5526 (pMTE[x].full ? _("Full ") :_("Empty")),
5527 pMTE[x].from, pMTE[x].VolTag);
5529 if (pMTE[x].full == 1)
5531 pbarcoderes->action = BARCODE_BARCODE;
5532 strncpy(pbarcoderes->data.barcode, pMTE[x].VolTag,
5533 SIZEOF(pbarcoderes->data.barcode));
5535 if (MapBarCode(labelfile, pbarcoderes) == 0 )
5537 g_printf(_("No mapping\n"));
5539 g_printf(_("%s \n"),pbarcoderes->data.voltag);
5545 g_printf(_("%07d MTE %s %04d \n"),pMTE[x].address,
5546 (pMTE[x].full ? _("Full ") :_("Empty")),
5551 for ( x = 0; x < STE; x++)
5554 g_printf(_("%07d STE %s %04d %s "),pSTE[x].address,
5555 (pSTE[x].full ? _("Full "):_("Empty")),
5556 pSTE[x].from, pSTE[x].VolTag);
5558 if (pSTE[x].full == 1)
5560 pbarcoderes->action = BARCODE_BARCODE;
5561 strncpy(pbarcoderes->data.barcode, pSTE[x].VolTag,
5562 SIZEOF(pbarcoderes->data.barcode));
5564 if (MapBarCode(labelfile, pbarcoderes) == 0 )
5566 g_printf(_("No mapping\n"));
5568 g_printf(_("%s \n"),pbarcoderes->data.voltag);
5574 g_printf(_("%07d STE %s %04d %s\n"),pSTE[x].address,
5575 (pSTE[x].full ? _("Full"):_("Empty")),
5576 pSTE[x].from, pSTE[x].VolTag);
5580 for ( x = 0; x < DTE; x++)
5583 g_printf(_("%07d DTE %s %04d %s "),pDTE[x].address,
5584 (pDTE[x].full ? _("Full") : _("Empty")),
5585 pDTE[x].from, pDTE[x].VolTag);
5587 if (pDTE[x].full == 1)
5589 pbarcoderes->action = BARCODE_BARCODE;
5590 strncpy(pbarcoderes->data.barcode, pDTE[x].VolTag,
5591 SIZEOF(pbarcoderes->data.barcode));
5593 if (MapBarCode(labelfile, pbarcoderes) == 0 )
5595 g_printf(_("No mapping\n"));
5597 g_printf("%s \n",pbarcoderes->data.voltag);
5604 g_printf(_("%07d DTE %s %04d %s\n"),pDTE[x].address,
5605 (pDTE[x].full ?_( "Full ") : _("Empty")),
5606 pDTE[x].from, pDTE[x].VolTag);
5609 for ( x = 0; x < IEE; x++)
5612 g_printf(_("%07d IEE %s %04d %s "),pIEE[x].address,
5613 (pIEE[x].full ? _("Full ") : _("Empty")),
5614 pIEE[x].from, pIEE[x].VolTag);
5616 if (pIEE[x].full == 1)
5618 pbarcoderes->action = BARCODE_BARCODE;
5619 strncpy(pbarcoderes->data.barcode, pIEE[x].VolTag,
5620 SIZEOF(pbarcoderes->data.barcode));
5622 if (MapBarCode(labelfile, pbarcoderes) == 0 )
5624 g_printf(_("No mapping\n"));
5626 g_printf(_("%s \n"),pbarcoderes->data.voltag);
5633 g_printf(_("%07d IEE %s %04d %s\n"),pIEE[x].address,
5634 (pIEE[x].full ? _("Full ") : _("Empty")),
5635 pIEE[x].from, pIEE[x].VolTag);
5640 if (strcmp("sense", option) == 0 || strcmp("all", option) == 0)
5642 if (pDev[INDEX_CHANGER].SCSI == 1)
5644 g_printf(_("\nSense Status from robot:\n"));
5645 RequestSense(INDEX_CHANGER , &ExtRequestSense, 0);
5646 DecodeExtSense(&ExtRequestSense, "", out);
5649 if (pDev[INDEX_TAPE].SCSI == 1)
5652 g_printf(_("Sense Status from tape (tapectl):\n"));
5653 RequestSense(INDEX_TAPE, &ExtRequestSense, 0);
5654 DecodeExtSense(&ExtRequestSense, "", out);
5657 if (pDev[INDEX_TAPECTL].SCSI == 1)
5660 g_printf(_("Sense Status from tape (tapectl):\n"));
5661 RequestSense(INDEX_TAPECTL, &ExtRequestSense, 0);
5662 DecodeExtSense(&ExtRequestSense, "", out);
5666 if (strcmp("ModeSenseRobot", option) == 0 || strcmp("all", option) == 0)
5669 if (SCSI_ModeSense(INDEX_CHANGER, pModePage, 0xff, 0x08, 0x3f) == 0)
5671 DecodeModeSense(pModePage, 0, "Changer :" , 0, out);
5675 if (strcmp("ModeSenseTape", option) == 0 || strcmp("all", option) == 0)
5677 if (pDev[INDEX_TAPECTL].SCSI == 1)
5680 if (SCSI_ModeSense(INDEX_TAPECTL, pModePage, 0xff, 0x0, 0x3f) == 0)
5682 DecodeModeSense(pModePage, 0, "Tape :" , 1, out);
5687 if (strcmp("fd", option) == 0 || strcmp("all", option) == 0)
5689 g_printf("changer_dev %s\n",changer_dev);
5690 g_printf("changer_file %s\n", changer_file);
5691 g_printf("tape_device %s\n\n", tape_device);
5692 DumpDev(&pDev[INDEX_TAPE], "pTapeDev");
5693 DumpDev(&pDev[INDEX_TAPECTL], "pTapeDevCtl");
5694 DumpDev(&pDev[INDEX_CHANGER], "pChangerDev");
5697 if (GenericClean("") == 1)
5698 g_printf(_("Tape needs cleaning\n"));
5711 size_t row_count = 0;
5714 while (row_count < size)
5716 DebugPrint(level, section,"%02X ", (u_char)p[row_count]);
5717 if (((row_count + 1) % 16) == 0)
5720 for (x = 16; x > 0; x--)
5722 if (isalnum((u_char)p[row_count - x + 1 ]))
5723 DebugPrint(level, section,"%c",(u_char)p[row_count - x + 1]);
5725 DebugPrint(level, section,".");
5727 DebugPrint(level, section,"\n");
5731 DebugPrint(level, section,"\n");
5741 for (x = (ssize_t)length; x >= 0 && !isalnum((int)string[x]); x--)
5751 (void)level; /* Quiet unused parameter warning */
5753 dbprintf(_("ChgExit in %s, reason %s\n"), where, reason);
5754 g_fprintf(stderr,"%s\n",reason);
5758 /* OK here starts a new set of functions.
5759 * Every function is for one SCSI command.
5760 * Prefix is SCSI_ and then the SCSI command name
5764 * SCSI_Run is an wrapper arround SCSI_ExecuteCommand
5765 * It seems to be an good idea to check first if the device
5766 * is ready for accepting commands, and if this is true send
5772 Direction_T Direction,
5776 size_t DataBufferLength,
5777 RequestSense_T * pRequestSense,
5778 size_t RequestSenseLength)
5783 RequestSense_T *pRqS;
5785 /* Basic sanity checks */
5786 assert(CDB_Length <= UCHAR_MAX);
5787 assert(RequestSenseLength <= UCHAR_MAX);
5789 pRqS = (RequestSense_T *)pRequestSense;
5791 DebugPrint(DEBUG_INFO, SECTION_SCSI, _("SCSI_Run TestUnitReady\n"));
5792 while (!ok && maxtries < MAXTRIES)
5794 ret = SCSI_TestUnitReady(DeviceFD, (RequestSense_T *)pRequestSense );
5795 DebugPrint(DEBUG_INFO, SECTION_SCSI, _("SCSI_Run TestUnitReady ret %d\n"),ret);
5802 switch (SenseHandler(DeviceFD, 0, pRqS->SenseKey, pRqS->AdditionalSenseCode, pRqS->AdditionalSenseCodeQualifier, pRqS))
5805 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_Run (TestUnitReady) SENSE_NO\n"));
5808 case SENSE_TAPE_NOT_ONLINE:
5809 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_Run (TestUnitReady) SENSE_TAPE_NOT_ONLINE\n"));
5813 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_Run (TestUnitReady) SENSE_IGNORE\n"));
5817 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("SCSI_Run (TestUnitReady) SENSE_ABORT\n"));
5821 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_Run (TestUnitReady) SENSE_RETRY\n"));
5824 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_Run (TestUnitReady) default (SENSE)\n"));
5830 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("SCSI_Run (TestUnitReady) SCSI_ERROR\n"));
5834 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_Run (TestUnitReady) SCSI_BUSY\n"));
5837 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_Run (TestUnitReady) SCSI_CHECK\n"));
5840 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("SCSI_Run (TestUnitReady) unknown (%d)\n"),ret);
5850 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_Run TestUnitReady after %d sec:\n"),maxtries);
5854 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("SCSI_Run Exit %d\n"),ret);
5861 while (!ok && maxtries < MAXTRIES)
5863 ret = SCSI_ExecuteCommand(DeviceFD,
5870 RequestSenseLength);
5872 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_Run Exit %d\n"),ret);
5879 switch (SenseHandler(DeviceFD, 0, pRqS->SenseKey, pRqS->AdditionalSenseCode, pRqS->AdditionalSenseCodeQualifier, pRqS))
5882 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_Run SENSE_NO\n"));
5885 case SENSE_TAPE_NOT_ONLINE:
5886 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_Run SENSE_TAPE_NOT_ONLINE\n"));
5890 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_Run SENSE_IGNORE\n"));
5894 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("SCSI_Run SENSE_ABORT\n"));
5898 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_Run SENSE_RETRY\n"));
5901 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_Run default (SENSE)\n"));
5907 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("SCSI_Run SCSI_ERROR\n"));
5911 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_Run SCSI_BUSY\n"));
5914 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_Run (TestUnitReady) SCSI_CHECK\n"));
5917 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("SCSI_Run (TestUnitReady) unknown (%d)\n"),ret);
5933 * This a vendor specific command !!!!!!
5934 * First seen at AIT :-)
5943 RequestSense_T *pRequestSense;
5949 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("##### START SCSI_AlignElements\n"));
5951 pRequestSense = alloc(SIZEOF(RequestSense_T));
5953 for (retry = 0; retry < MAX_RETRIES; retry++)
5957 MSB2(&CDB[2],AE_MTE); /* Which MTE to use, default 0 */
5958 MSB2(&CDB[4],AE_DTE); /* Which DTE to use, no range check !! */
5959 MSB2(&CDB[6],AE_STE); /* Which STE to use, no range check !! */
5965 ret = SCSI_Run(DeviceFD, Input, CDB, 12,
5966 NULL, 0, pRequestSense, SIZEOF(RequestSense_T));
5968 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_AlignElements : SCSI_Run = %d\n"), ret);
5969 DecodeSense(pRequestSense, _("SCSI_AlignElements :"),debug_file);
5973 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("%s: Request Sense[Inquiry]: %02X"),
5974 "chs", ((u_char *) &pRequestSense)[0]);
5975 for (i = 1; i < (int)sizeof(RequestSense_T); i++)
5976 DebugPrint(DEBUG_ERROR, SECTION_SCSI," %02X", ((u_char *) &pRequestSense)[i]);
5977 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"\n");
5983 switch(SenseHandler(DeviceFD, 0 , pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
5986 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_AlignElements : SENSE_IGNORE\n"));
5990 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_AlignElements : SENSE_RETRY no %d\n"), retry);
5993 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("SCSI_AlignElements : SENSE_ABORT\n"));
5996 case SENSE_TAPE_NOT_UNLOADED:
5997 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("SCSI_AlignElements : Tape still loaded, eject failed\n"));
6001 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_AlignElements : end %d\n"), pRequestSense->SenseKey);
6002 return(pRequestSense->SenseKey);
6008 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_AlignElements : end %d\n"), ret);
6013 DebugPrint(DEBUG_ERROR, SECTION_SCSI,
6014 _("SCSI_AlignElements: Retries exceeded = %d\n"), retry);
6026 RequestSense_T *pRequestSense;
6032 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("##### START SCSI_Move\n"));
6034 pRequestSense = alloc(SIZEOF(RequestSense_T));
6036 for (retry = 0; (ret != 0) && (retry < MAX_RETRIES); retry++)
6038 CDB[0] = SC_MOVE_MEDIUM;
6041 CDB[3] = chm; /* Address of CHM */
6049 ret = SCSI_Run(DeviceFD, Input, CDB, 12,
6050 NULL, 0, pRequestSense, SIZEOF(RequestSense_T));
6052 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_Move : SCSI_Run = %d\n"), ret);
6053 DecodeSense(pRequestSense, _("SCSI_Move :"),debug_file);
6057 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("%s: Request Sense[Inquiry]: %02X"),
6058 "chs", ((u_char *) &pRequestSense)[0]);
6059 for (i = 1; i < (int)sizeof(RequestSense_T); i++)
6060 DebugPrint(DEBUG_ERROR, SECTION_SCSI," %02X", ((u_char *) &pRequestSense)[i]);
6061 DebugPrint(DEBUG_INFO, SECTION_SCSI,"\n");
6067 switch(SenseHandler(DeviceFD, 0 , pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
6070 dbprintf(_("SCSI_Move : SENSE_IGNORE\n"));
6074 dbprintf(_("SCSI_Move : SENSE_RETRY no %d\n"), retry);
6077 dbprintf(_("SCSI_Move : SENSE_ABORT\n"));
6080 case SENSE_TAPE_NOT_UNLOADED:
6081 dbprintf(_("SCSI_Move : Tape still loaded, eject failed\n"));
6085 dbprintf(_("SCSI_Move : end %d\n"), pRequestSense->SenseKey);
6086 return(pRequestSense->SenseKey);
6091 dbprintf(_("SCSI_Move : end %d\n"), ret);
6098 RequestSense_T * pRequestSense,
6105 dbprintf(_("##### START SCSI_LoadUnload\n"));
6107 CDB[0] = SC_COM_UNLOAD;
6115 ret = SCSI_Run(DeviceFD, Input, CDB, 6,
6118 SIZEOF(RequestSense_T));
6122 dbprintf(_("SCSI_Unload : failed %d\n"), ret);
6127 dbprintf(_("##### STOP SCSI_LoadUnload\n"));
6134 RequestSense_T * pRequestSense)
6139 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("##### START SCSI_TestUnitReady\n"));
6141 CDB[0] = SC_COM_TEST_UNIT_READY;
6148 ret = SCSI_ExecuteCommand(DeviceFD, Input, CDB, 6,
6151 SIZEOF(RequestSense_T));
6154 * We got an error, so let the calling function handle this
6158 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("###### STOP SCSI_TestUnitReady (1)\n"));
6164 * OK, no error condition
6165 * If no sense is set, the Unit is ready
6167 if (pRequestSense->ErrorCode == 0 && pRequestSense->SenseKey == 0)
6169 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("###### STOP SCSI_TestUnitReady (1)\n"));
6177 if (pRequestSense->ErrorCode != 0){
6178 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("###### STOP SCSI_TestUnitReady ErrorCode set\n"));
6180 if (pRequestSense->SenseKey != 0) {
6181 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("###### STOP SCSI_TestUnitReady Sense Key set\n"));
6183 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("###### STOP SCSI_TestUnitReady (0)\n"));
6198 RequestSense_T *pRequestSense;
6203 dbprintf(_("##### START SCSI_ModeSelect\n"));
6205 dbprintf(_("SCSI_ModeSelect start length = %u:\n"), (unsigned)length);
6206 pRequestSense = alloc(SIZEOF(RequestSense_T));
6207 sendbuf = alloc((size_t)length + 4);
6208 memset(sendbuf, 0 , (size_t)length + 4);
6210 memcpy(&sendbuf[4], buffer, (size_t)length);
6211 dump_hex(sendbuf, (size_t)length+4, DEBUG_INFO, SECTION_SCSI);
6213 for (retry = 0; (ret != 0) && (retry < MAX_RETRIES); retry++)
6215 memset(pRequestSense, 0, SIZEOF(RequestSense_T));
6217 CDB[0] = SC_COM_MODE_SELECT;
6218 CDB[1] = (u_char)(((lun << 5) & 0xF0) | ((mode << 4) & 0x10) | (save & 1));
6221 CDB[4] = (u_char)(length + 4);
6223 ret = SCSI_Run(DeviceFD, Output, CDB, 6,
6227 SIZEOF(RequestSense_T));
6230 dbprintf(_("SCSI_ModeSelect : ret %d\n"), ret);
6237 switch(SenseHandler(DeviceFD, 0, pRequestSense->SenseKey,
6238 pRequestSense->AdditionalSenseCode,
6239 pRequestSense->AdditionalSenseCodeQualifier,
6243 dbprintf(_("SCSI_ModeSelect : SENSE_IGNORE\n"));
6248 dbprintf(_("SCSI_ModeSelect : SENSE_RETRY no %d\n"), retry);
6252 ret = pRequestSense->SenseKey;
6258 dbprintf(_("SCSI_ModeSelect end: %d\n"), ret);
6261 free(pRequestSense);
6277 RequestSense_T *pRequestSense;
6281 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("##### START SCSI_ModeSense\n"));
6283 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_ModeSense start length = %d:\n"), size);
6284 pRequestSense = alloc(SIZEOF(RequestSense_T));
6286 while (ret && retry < MAX_RETRIES)
6288 memset(pRequestSense, 0, SIZEOF(RequestSense_T));
6289 memset(buffer, 0, size);
6291 CDB[0] = SC_COM_MODE_SENSE;
6297 ret = SCSI_Run(DeviceFD, Input, CDB, 6,
6301 SIZEOF(RequestSense_T));
6310 switch(SenseHandler(DeviceFD, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
6313 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_ModeSense : SENSE_IGNORE\n"));
6317 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_ModeSense : SENSE_RETRY no %d\n"), retry);
6320 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_ModeSense : end %d\n"), pRequestSense->SenseKey);
6321 return(pRequestSense->SenseKey);
6328 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_ModeSense end: %d\n"), ret);
6335 SCSIInquiry_T * buffer,
6339 RequestSense_T *pRequestSense;
6344 assert(size <= UCHAR_MAX);
6346 DebugPrint(DEBUG_INFO, SECTION_SCSI, _("##### START SCSI_Inquiry\n"));
6348 DebugPrint(DEBUG_INFO, SECTION_SCSI, _("SCSI_Inquiry start length = %d:\n"), size);
6350 pRequestSense = alloc((size_t)size);
6352 while (retry > 0 && retry < MAX_RETRIES)
6354 memset(buffer, 0, size);
6355 CDB[0] = SC_COM_INQUIRY;
6359 CDB[4] = (u_char)size;
6362 ret = SCSI_ExecuteCommand(DeviceFD, Input, CDB, 6,
6366 SIZEOF(RequestSense_T));
6369 DebugPrint(DEBUG_ERROR, SECTION_SCSI,_("%s: Request Sense[Inquiry]: %02X"),
6370 "chs", ((u_char *) pRequestSense)[0]);
6371 for (i = 1; i < (int)sizeof(RequestSense_T); i++)
6372 DebugPrint(DEBUG_ERROR, SECTION_SCSI," %02X", ((u_char *) pRequestSense)[i]);
6373 DebugPrint(DEBUG_ERROR, SECTION_SCSI, "\n");
6374 DebugPrint(DEBUG_ERROR, SECTION_SCSI, _("Inquiry end: %d\n"), ret);
6380 switch(SenseHandler(DeviceFD, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
6383 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_Inquiry : SENSE_IGNORE\n"));
6387 DebugPrint(DEBUG_INFO, SECTION_SCSI, _("SCSI_Inquiry : SENSE_RETRY no %d\n"), retry);
6390 DebugPrint(DEBUG_ERROR, SECTION_SCSI, _("SCSI_Inquiry : end %d\n"), pRequestSense->SenseKey);
6391 return(pRequestSense->SenseKey);
6398 dump_hex((u_char *)buffer, size, DEBUG_INFO, SECTION_SCSI);
6399 DebugPrint(DEBUG_INFO, SECTION_SCSI, _("SCSI_Inquiry : end %d\n"), ret);
6405 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_Inquiry end: %d\n"), ret);
6410 * Read the Element Status. If DescriptorSize != 0 then
6411 * allocate DescriptorSize * NoOfElements for the result from the
6412 * Read Element Status command.
6413 * If DescriptorSize == 0 than try to figure out how much space is needed
6415 * 1. do an read with an allocation size of 8
6416 * 2. from the result take the 'Byte Count of Descriptor Available'
6417 * 3. do again an Read Element Status with the result from 2.
6421 SCSI_ReadElementStatus(
6427 size_t NoOfElements,
6428 size_t DescriptorSize,
6432 size_t DataBufferLength;
6433 ElementStatusData_T *ElementStatusData;
6434 RequestSense_T *pRequestSense;
6438 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("##### START SCSI_ReadElementStatus\n"));
6440 pRequestSense = alloc(SIZEOF(RequestSense_T));
6443 * How many elements, if <= 0 than exit with an fatal error
6445 if (NoOfElements == 0)
6447 ChgExit("SCSI_ReadElementStatus",_("No of Elements passed are le 0"),FATAL);
6451 VolTag = (u_char)((VolTag << 4) & 0x10);
6452 type = (u_char)(type & 0xf);
6453 lun = (u_char)((lun << 5) & 0xe0);
6455 /* if DescriptorSize == 0
6456 * try to get the allocation length for the second call
6458 if (DescriptorSize == 0)
6460 *data = newalloc(*data, 8);
6461 memset(*data, 0, 8);
6463 while (retry > 0 && retry < MAX_RETRIES)
6465 memset(pRequestSense, 0, SIZEOF(RequestSense_T) );
6467 CDB[0] = SC_COM_RES; /* READ ELEMENT STATUS */
6468 CDB[1] = (u_char)(VolTag | type | lun); /* Element Type Code , VolTag, LUN */
6469 MSB2(&CDB[2], StartAddress); /* Starting Element Address */
6470 MSB2(&CDB[4], NoOfElements); /* Number Of Element */
6471 CDB[6] = 0; /* Reserved */
6472 MSB3(&CDB[7],8); /* Allocation Length */
6473 CDB[10] = 0; /* Reserved */
6474 CDB[11] = 0; /* Control */
6476 ret = SCSI_Run(DeviceFD, Input, CDB, 12,
6478 pRequestSense, SIZEOF(RequestSense_T));
6480 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_ReadElementStatus : (1) SCSI_Run %d\n"), ret);
6483 DecodeSense(pRequestSense, "SCSI_ReadElementStatus :",debug_file);
6484 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("##### STOP SCSI_ReadElementStatus (%d)\n"),ret);
6490 switch(SenseHandler(DeviceFD, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
6493 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_ModeSense : SENSE_IGNORE\n"));
6497 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_ModeSense : SENSE_RETRY no %d\n"), retry);
6501 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_ModeSense : end %d\n"), pRequestSense->SenseKey);
6502 return(pRequestSense->SenseKey);
6514 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("##### STOP SCSI_ReadElementStatus (%d)\n"),ret);
6519 ElementStatusData = (ElementStatusData_T *)*data;
6520 DataBufferLength = V3(ElementStatusData->count);
6522 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_ReadElementStatus: DataBufferLength %X, ret %d\n"),DataBufferLength, ret);
6524 dump_hex(*data, 8, DEBUG_INFO, SECTION_ELEMENT);
6525 } else { /* DescriptorSize != 0 */
6526 DataBufferLength = NoOfElements * DescriptorSize;
6529 DataBufferLength = DataBufferLength + 8;
6530 *data = newalloc(*data, DataBufferLength);
6531 memset(*data, 0, DataBufferLength);
6534 while (retry > 0 && retry < MAX_RETRIES)
6536 memset(pRequestSense, 0, SIZEOF(RequestSense_T) );
6538 CDB[0] = SC_COM_RES; /* READ ELEMENT STATUS */
6539 CDB[1] = (u_char)(VolTag | type | lun); /* Element Type Code, VolTag, LUN */
6540 MSB2(&CDB[2], StartAddress); /* Starting Element Address */
6541 MSB2(&CDB[4], NoOfElements); /* Number Of Element */
6542 CDB[6] = 0; /* Reserved */
6543 MSB3(&CDB[7],DataBufferLength); /* Allocation Length */
6544 CDB[10] = 0; /* Reserved */
6545 CDB[11] = 0; /* Control */
6547 ret = SCSI_Run(DeviceFD, Input, CDB, 12,
6548 *data, DataBufferLength,
6549 pRequestSense, SIZEOF(RequestSense_T));
6552 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_ReadElementStatus : (2) SCSI_Run %d\n"), ret);
6555 DecodeSense(pRequestSense, _("SCSI_ReadElementStatus :"),debug_file);
6556 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("##### STOP SCSI_ReadElementStatus (%d)\n"),ret);
6562 switch(SenseHandler(DeviceFD, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
6565 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_ModeSense : SENSE_IGNORE\n"));
6569 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_ModeSense : SENSE_RETRY no %d\n"), retry);
6573 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("SCSI_ModeSense : end %d\n"), pRequestSense->SenseKey);
6574 return(pRequestSense->SenseKey);
6587 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("##### STOP SCSI_ReadElementStatus (%d)\n"),ret);
6592 dump_hex(*data, DataBufferLength, DEBUG_INFO, SECTION_SCSI);
6593 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("##### STOP SCSI_ReadElementStatus (%d)\n"),ret);
6597 printf_arglist_function2(void DebugPrint, int, level, int, section, char *, fmt)
6603 time_t ti = time(NULL);
6605 if (changer->debuglevel)
6607 if (sscanf(changer->debuglevel,"%d:%d", &dlevel, &dsection) != 2) {
6608 dbprintf(_("Parse error: line is '%s' expected [0-9]*:[0-9]*\n"),
6609 changer->debuglevel);
6618 arglist_start(argp, fmt);
6619 g_vsnprintf(buf, SIZEOF(buf), fmt, argp);
6620 if (dlevel >= level)
6622 if (section == dsection || dsection == 0)
6624 if (strchr(buf, '\n') != NULL && strlen(buf) > 1)
6626 dbprintf(_("%ld:%s"), (long)ti, buf);
6628 dbprintf("%s", buf);