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
40 #include "scsi-defs.h"
44 extern FILE *debug_file;
45 extern changer_t *changer; /* Needed for the infos about emubarcode and labelfile */
47 int PrintInquiry(SCSIInquiry_T *);
48 int GenericElementStatus(int DeviceFD, int InitStatus);
49 int SDXElementStatus(int DeviceFD, int InitStatus);
50 int DLT448ElementStatus(int DeviceFD, int InitStatus);
51 ElementInfo_T *LookupElement(int addr);
52 int GenericResetStatus(int DeviceFD);
53 int RequestSense(int, ExtendedRequestSense_T *, int );
54 void dump_hex(u_char *, size_t, int, int);
55 void TerminateString(char *string, size_t length);
56 void ChgExit(char *, char *, int);
59 int SenseHandler(int fd, u_char flag, u_char SenseKey, u_char AdditionalSenseCode, u_char AdditionalSenseCodeQualifier, RequestSense_T *buffer);
61 int SCSI_AlignElements(int DeviceFD, size_t MTE, size_t DTE, size_t STE);
65 int DoNothing2(int, int);
66 int DoNothing3(int, int, int);
68 int GenericMove(int, int, int);
69 int SDXMove(int, int, int);
70 int CheckMove(ElementInfo_T *from, ElementInfo_T *to);
71 int GenericRewind(int);
72 /* int GenericStatus(void); */
73 int GenericFree(void);
74 int TapeStatus(void); /* Is the tape loaded ? */
75 int DLT4000Eject(char *Device, int type);
76 int GenericEject(char *Device, int type);
77 int SCSI_LogSenseClean(char *Device); /* Does the tape need a clean */
78 int GenericClean(char *Device); /* Does the tape need a clean */
79 int GenericBarCode(int DeviceFD); /* Do we have Barcode reader support */
80 int NoBarCode(int DeviceFD);
82 int GenericSearch(void);
83 void Inventory(char *labelfile, int drive, int eject, int start, int stop, int clean);
85 int TreeFrogBarCode(int DeviceFD);
86 int EXB_BarCode(int DeviceFD);
87 int GenericSenseHandler(int fd, u_char flags, u_char SenseKey, u_char AdditionalSenseCode, u_char AdditionalSenseCodeQualifier, RequestSense_T *);
89 ElementInfo_T *LookupElement(int address);
90 int eject_tape(char *tapedev, int type);
91 int unload(int fd, int drive, int slot);
92 int load(int fd, int drive, int slot);
93 int GetElementStatus(int DeviceFD);
94 int drive_loaded(int fd, int drivenum);
99 void WriteErrorCountersPage(LogParameter_T *, size_t);
100 void ReadErrorCountersPage(LogParameter_T *, size_t);
101 void C1553APage30(LogParameter_T *, size_t);
102 void C1553APage37(LogParameter_T *, size_t);
103 void EXB85058HEPage39(LogParameter_T *, size_t);
104 void EXB85058HEPage3c(LogParameter_T *, size_t);
105 int Decode(LogParameter_T *, unsigned *);
106 int DecodeModeSense(u_char *buffer, size_t offset, char *pstring, char block, FILE *out);
108 int SCSI_Run(int DeviceFD,
109 Direction_T Direction,
113 size_t DataBufferLength,
114 RequestSense_T *pRequestSense,
115 size_t RequestSenseLength);
117 int SCSI_Move(int DeviceFD, u_char chm, int from, int to);
118 int SCSI_LoadUnload(int DeviceFD, RequestSense_T *pRequestSense, u_char byte1, u_char load);
119 int SCSI_TestUnitReady(int, RequestSense_T *);
120 int SCSI_ModeSense(int DeviceFD, u_char *buffer, u_char size, u_char byte1, u_char byte2);
121 int SCSI_ModeSelect(int DeviceFD,
128 int SCSI_ReadElementStatus(int DeviceFD,
134 size_t DescriptorSize,
138 static int barcode; /* cache the result from the BarCode function */
140 SC_COM_T SCSICommand[] = {
152 "INITIALIZE ELEMENT STATUS"},
179 "READ ELEMENT STATUS"},
183 ChangerCMD_T ChangerIO[] = {
185 "Generic driver changer [generic_changer]",
187 GenericElementStatus,
195 GenericSenseHandler},
198 "HP Auto Loader [C1553A]",
200 GenericElementStatus,
208 GenericSenseHandler},
209 /* Exabyte Devices */
211 "Exabyte Robot [EXB-10e]",
213 GenericElementStatus,
221 GenericSenseHandler},
223 "Exabyte Robot [EXB-120]",
225 GenericElementStatus,
233 GenericSenseHandler},
235 "Exabyte Robot [EXB-210]",
237 GenericElementStatus,
245 GenericSenseHandler},
247 "Exabyte Tape [EXB-85058HE-0000]",
257 GenericSenseHandler},
258 /* Tandberg Devices */
260 "Tandberg Robot (TDS 1420)",
262 GenericElementStatus,
270 GenericSenseHandler},
273 "ADIC VLS DLT Library [VLS DLT]",
275 GenericElementStatus,
283 GenericSenseHandler},
285 "ADIC VLS DLT Library [VLS SDX]",
295 GenericSenseHandler},
297 "ADIC FastStor DLT Library [FastStor DLT]",
307 GenericSenseHandler},
309 "ADIC DLT 448 [Scalar DLT 448]",
319 GenericSenseHandler},
320 /* Sepctra Logic Devices */
322 "Spectra Logic TreeFrog[215]",
324 GenericElementStatus,
332 GenericSenseHandler},
335 "Breece Hill Quad 7",
337 GenericElementStatus,
345 GenericSenseHandler},
346 /* Quantum Devices */
350 GenericElementStatus,
358 GenericSenseHandler},
360 * And now the tape devices
362 /* The generic handler if nothing matches */
364 "Generic driver tape [generic_tape]",
366 GenericElementStatus,
374 GenericSenseHandler},
376 "DLT Tape [DLT8000]",
386 GenericSenseHandler},
388 "DLT Tape [DLT7000]",
398 GenericSenseHandler},
400 "DLT Tape [DLT4000]",
410 GenericSenseHandler},
414 GenericElementStatus,
422 GenericSenseHandler},
423 {NULL, NULL, NULL,NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}
427 LogPageDecode_T DecodePages[] = {
430 WriteErrorCountersPage},
433 ReadErrorCountersPage},
442 WriteErrorCountersPage},
445 ReadErrorCountersPage},
456 int ElementStatusValid = 0; /* Set if the READ ELEMENT STATUS was OK, an no error is pending */
457 int LibModeSenseValid = 0; /* Set if we did an scussefull MODE SENSE */
460 /* Pointer to MODE SENSE Pages */
461 u_char *pModePage = NULL;
462 EAAPage_T *pEAAPage = NULL;
463 DeviceCapabilitiesPage_T *pDeviceCapabilitiesPage = NULL;
464 u_char *pVendorUnique = NULL;
467 * New way, every element type has its on array
468 * which is dynamic allocated by the ElementStatus function,
470 ElementInfo_T *pMTE = NULL; /*Medium Transport Element */
471 ElementInfo_T *pSTE = NULL; /*Storage Element */
472 ElementInfo_T *pIEE = NULL; /*Import Export Element */
473 ElementInfo_T *pDTE = NULL; /*Data Transfer Element */
474 size_t MTE = 0; /*Counter for the above element types */
479 char *chgscsi_datestamp = NULL; /* Result pointer for tape_rdlabel */
480 char *chgscsi_label = NULL; /* Result pointer for tape_rdlabel */
481 char *chgscsi_result = NULL; /* Needed for the result string of MapBarCode */
484 * First all functions which are called from extern
489 * Print the scsi-changer-driver version
493 ChangerDriverVersion(void)
495 DebugPrint(DEBUG_ERROR, SECTION_INFO, "scsi-changer-driver: %s\n",rcsid);
500 * Try to generate an template which can be used as an example for the config file
506 extern OpenFiles_T *pDev;
510 printf("# Please replace every ??? with the correct parameter. It is not possible\n");
511 printf("# to guess everything :-)\n");
512 printf("# If the option is not needed, cleanmax for example if you have no cleaning\n");
513 printf("# tape remove the line.\n");
515 printf("number_configs 1 # Number of configs, you can have more than 1 config\n");
516 printf(" # if you have for example more than one drive, or you\n");
517 printf(" # to split your lib to use different dump levels\n");
519 printf("emubarcode 1 # If you drive has no barcode reader this will try\n");
520 printf(" # keep an inventory of your tapes to find them faster\n");
522 printf("havebarcode 0 # Set this to 1 if you have an library with an installed\n");
523 printf(" # barcode reader\n");
525 printf("debuglevel 0:0 # For debuging, see the docs /docs/TAPE-CHANGER\n");
527 printf("eject ??? # set this to 1 if your drive needs an eject before move\n");
529 printf("sleep ??? # How long to wait after an eject command before moving\n");
530 printf(" # the tape\n");
533 for (count = 0; count < CHG_MAXDEV ; count++)
537 if (pDev[count].inquiry != NULL && pDev[count].inquiry->type == TYPE_CHANGER)
539 printf("changerdev %s # This is the device to communicate with the robot\n", pDev[count].dev);
546 * Did we reach the end of the list ?
547 * If no we found an changer and now we try to
548 * get the element status for the count of slots
550 if (count < CHG_MAXDEV)
552 pDev[count].functions->function_status(count, 1);
554 printf("changerdev ??? # Ups nothing found. Please check the docs\n");
558 printf(" # Here now comes the config for the first tape\n");
559 printf("config 0 # This value is the one which is used in the amanda\n");
560 printf(" # config file to tell the chg-scsi programm which tape\n");
561 printf(" # and which slots to use\n");
563 printf("cleancart ??? # The slot where the cleaning tape is located\n");
564 printf(" # remove it if you have no cleaning tape\n");
566 printf("drivenum 0 # Which tape drive to use if there are more than one drive\n");
568 printf("dev ??? # Which is the raw device to read/write data from the tape\n");
569 printf(" # It is important to use the non rewinding tape, like\n");
570 printf(" # /dev/nrst0 on linux, /dev/nrsa0 on BSD ....\n");
574 * OK now lets see if we have an direct SCSI channel
576 * If not thats not a problem
578 for (count = 0; count < CHG_MAXDEV; count++)
582 if (pDev[count].inquiry != NULL && pDev[count].inquiry->type == TYPE_TAPE)
584 printf("scsitapedev %s # This is the device to communicate with the tape\n", pDev[count].dev);
585 printf(" # to get some device stats, not so importatn, and\n");
586 printf(" # if you run in problems delete it complete\n");
596 printf("startuse 0 # Which is the first slot to use\n");
598 printf("enduse " SIZE_T_FMT " # Which is the last slot to use\n", STE);
600 printf("startuse ??? # Which is the first slot to use\n");
602 printf("enduse ??? # Which is the last slot to use\n");
604 printf(" # decrement this value by 1 if you have an\n");
605 printf(" # cleaning tape in the last slot\n");
608 if ((cwd = getcwd(NULL, 0)) == NULL) {
612 printf("statfile %s/tape0-slot #\n",cwd);
613 printf("cleanfile %s/tape0-clean #\n", cwd);
614 printf("usagecount %s/tape0-totaltime #\n", cwd);
615 printf("tapestatus %s/tape0-tapestatus #\n", cwd);
616 printf("labelfile %s/labelfile #\n", cwd);
622 * Try to create a list of tapes and labels which are in the current
623 * magazin. The drive must be empty !!
625 * labelfile -> file name of the db
626 * drive -> which drive should we use
627 * eject -> the tape device needs an eject before move
628 * start -> start at slot start
629 * stop -> stop at slot stop
630 * clean -> if we have an cleaning tape than this is the slot number of it
637 * Check if the tape/changer is ready for the next move
638 * If an tape is loaded unload it and do initialize element status to
639 * get all labels if an bar code reader is installed
650 extern OpenFiles_T *pDev;
652 static int inv_done = 0; /* Inventory function called ?, marker to disable recursion */
653 MBC_T *pbarcoderes; /* Here we will pass the parameter to MapBarCode and get the result */
655 (void)start; /* Quiet unused parameter warning */
656 (void)stop; /* Quiet unused parameter warning */
658 DebugPrint(DEBUG_INFO,SECTION_MAP_BARCODE, "##### START Inventory\n");
659 pbarcoderes = alloc(SIZEOF(MBC_T));
660 memset(pbarcoderes, 0 , SIZEOF(MBC_T));
664 DebugPrint(DEBUG_INFO,SECTION_MAP_BARCODE, "##### STOP inv_done -> %d Inventory\n",inv_done);
670 barcode = BarCode(INDEX_CHANGER);
672 pbarcoderes->action = RESET_VALID;
674 MapBarCode(labelfile,pbarcoderes);
677 * Check if an tape is loaded, if yes unload it
678 * and do an INIT ELEMENT STATUS
681 if (pDTE[0].status == 'F')
685 (void)eject_tape("", eject);
687 (void)unload(INDEX_TAPE, 0, 0);
690 GenericResetStatus(INDEX_CHANGER);
692 for (x = 0; x < STE; x++)
694 if (x == (size_t)clean)
700 * Load the tape, on error try the next
701 * error could be an empty slot for example
703 if (load(INDEX_CHANGER, drive, x ) != 0)
705 DebugPrint(DEBUG_ERROR,SECTION_MAP_BARCODE, "Load drive(%d) from(%d) failed\n", drive, x);
710 * Wait until the tape is ready
712 Tape_Ready(INDEX_TAPECTL, 60);
714 SCSI_CloseDevice(INDEX_TAPE);
716 if ((chgscsi_result = (char *)tape_rdlabel(pDev[INDEX_TAPE].dev, &chgscsi_datestamp, &chgscsi_label)) == NULL)
718 pbarcoderes->action = UPDATE_SLOT;
719 strncpy(pbarcoderes->data.voltag, chgscsi_label,
720 SIZEOF(pbarcoderes->data.voltag));
721 pbarcoderes->data.slot = x;
722 pbarcoderes->data.from = 0;
723 pbarcoderes->data.LoadCount = 1;
724 if (BarCode(INDEX_CHANGER) == 1)
726 strncpy(pbarcoderes->data.barcode, pDTE[drive].VolTag,
727 SIZEOF(pbarcoderes->data.barcode));
728 MapBarCode(labelfile, pbarcoderes);
730 MapBarCode(labelfile, pbarcoderes);
733 DebugPrint(DEBUG_ERROR,SECTION_MAP_BARCODE, "Read label failed\n");
738 (void)eject_tape("", eject);
741 (void)unload(INDEX_TAPE, drive, x);
743 DebugPrint(DEBUG_INFO,SECTION_MAP_BARCODE, "##### STOP Inventory\n");
748 * Check if the slot ist empty
749 * slot -> slot number to check
756 extern OpenFiles_T *pDev;
757 DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### START isempty\n");
759 if (ElementStatusValid == 0)
761 if ( pDev[fd].functions->function_status(fd, 1) != 0)
763 DebugPrint(DEBUG_ERROR,SECTION_TAPE,"##### STOP isempty [-1]\n");
769 if (pSTE[slot].status == 'E')
771 DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### STOP isempty [1]\n");
775 DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### STOP isempty [0]\n");
783 extern OpenFiles_T *pDev;
784 /* Return 1 if cleaning is needed */
787 DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### START get_clean_state\n");
789 if (pDev[INDEX_TAPECTL].SCSI == 0)
791 DebugPrint(DEBUG_ERROR,SECTION_TAPE,"##### STOP get_clean_state [-1]\n");
795 ret=pDev[INDEX_TAPECTL].functions->function_clean(tapedev);
796 DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### STOP get_clean_state [%d]\n", ret);
802 * The parameter tapedev is not used.
803 * Type describes if we should force the SCSI eject if available
804 * normal eject is done with the ioctl
806 /* This function ejects the tape from the drive */
813 extern OpenFiles_T *pDev;
816 DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### START eject_tape %s\n",tapedev);
817 if (pDev[INDEX_TAPECTL].functions == NULL)
821 * Try to read the label
823 if (pDev[INDEX_TAPE].avail == 1 && (changer->emubarcode == 1 || BarCode(INDEX_CHANGER)))
826 if (pDev[INDEX_TAPECTL].SCSI == 1 && pDev[INDEX_TAPECTL].avail) {
827 DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### eject_tape rewind\n");
828 pDev[INDEX_TAPECTL].functions->function_rewind(INDEX_TAPECTL);
830 DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### eject_tape rewind2\n");
831 pDev[INDEX_TAPE].functions->function_rewind(INDEX_TAPE);
834 if (pDev[INDEX_TAPE].devopen == 1)
836 DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### eject_tape close\n");
837 SCSI_CloseDevice(INDEX_TAPE);
840 DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### tape_eject tape_rdlabel\n");
841 chgscsi_result = (char *)tape_rdlabel(pDev[INDEX_TAPE].dev, &chgscsi_datestamp, &chgscsi_label);
844 if (pDev[INDEX_TAPECTL].SCSI == 1 && pDev[INDEX_TAPECTL].avail == 1 && type == 1)
846 DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### tape_eject eject\n");
847 ret=pDev[INDEX_TAPECTL].functions->function_eject(tapedev, type);
848 DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### STOP (SCSI)eject_tape [%d]\n", ret);
853 if (pDev[INDEX_TAPE].avail == 1)
855 ret=Tape_Ioctl(INDEX_TAPE, IOCTL_EJECT);
856 DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### STOP (ioctl)eject_tape [%d]\n", ret);
861 DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### STOP eject_tape [-1]\n");
866 /* Find an empty slot, starting at start, ending at start+count */
873 extern OpenFiles_T *pDev;
877 DebugPrint(DEBUG_INFO,SECTION_ELEMENT,"###### START find_empty\n");
879 if (ElementStatusValid == 0)
881 if ( pDev[fd].functions->function_status(fd , 1) != 0)
883 DebugPrint(DEBUG_ERROR,SECTION_ELEMENT,
884 "###### END find_empty [-1]\n");
902 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,
903 "start at " SIZE_T_FMT ", end at " SIZE_T_FMT "\n",
904 (SIZE_T_FMT_TYPE)start,
905 (SIZE_T_FMT_TYPE)end);
907 for (x = start; x < end; x++)
909 if (pSTE[x].status == 'E')
911 DebugPrint(DEBUG_INFO,SECTION_ELEMENT,
912 "###### END find_empty [" SIZE_T_FMT "]\n", x);
917 DebugPrint(DEBUG_ERROR,SECTION_ELEMENT,"###### END find_empty [-1]\n");
922 * See if the tape is loaded based on the information we
923 * got back from the ReadElementStatus
925 * -1 -> Error (Fatal)
926 * 0 -> drive is empty
927 * 1 -> drive is loaded
934 extern OpenFiles_T *pDev;
936 DebugPrint(DEBUG_INFO,SECTION_TAPE,"###### START drive_loaded\n");
937 DebugPrint(DEBUG_INFO,SECTION_TAPE,"%-20s : fd %d drivenum %d \n", "drive_loaded", fd, drivenum);
940 if (ElementStatusValid == 0)
942 if (pDev[INDEX_CHANGER].functions->function_status(INDEX_CHANGER, 1) != 0)
944 DebugPrint(DEBUG_ERROR,SECTION_TAPE,"Fatal error\n");
950 if (pDTE[drivenum].status == 'E') {
951 DebugPrint(DEBUG_INFO,SECTION_TAPE,"###### STOP drive_loaded (empty)\n");
955 DebugPrint(DEBUG_INFO,SECTION_TAPE,"###### STOP drive_loaded (not empty)\n");
961 * unload the specified drive into the specified slot
965 * Check if the MTE is empty
973 extern OpenFiles_T *pDev;
974 extern int do_inventory;
977 DebugPrint(DEBUG_INFO, SECTION_TAPE,"###### START unload\n");
978 DebugPrint(DEBUG_INFO, SECTION_TAPE,"%-20s : fd %d, slot %d, drive %d \n", "unload", fd, slot, drive);
979 pbarcoderes = alloc(SIZEOF(MBC_T));
980 memset(pbarcoderes, 0, SIZEOF(MBC_T));
983 * If the Element Status is not valid try to
986 if (ElementStatusValid == 0)
988 if (pDev[INDEX_CHANGER].functions->function_status(INDEX_CHANGER , 1) != 0)
990 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"Element Status not valid, reset failed\n");
991 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"##### STOP unload (-1)\n");
998 DebugPrint(DEBUG_INFO, SECTION_TAPE,"%-20s : unload drive %d[%d] slot %d[%d]\n", "unload",
1000 pDTE[drive].address,
1002 pSTE[slot].address);
1005 * Unloading an empty tape unit makes no sense
1006 * so return with an error
1008 if (pDTE[drive].status == 'E')
1010 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"unload : Drive %d address %d is empty\n", drive, pDTE[drive].address);
1011 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"##### STOP unload (-1)\n");
1018 * If the destination slot is full
1019 * try to find an enpty slot
1021 if (pSTE[slot].status == 'F')
1023 DebugPrint(DEBUG_INFO, SECTION_TAPE,"unload : Slot %d address %d is full\n", drive, pSTE[slot].address);
1024 if ( ElementStatusValid == 0)
1026 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "unload: Element Status not valid, can't find an empty slot\n");
1032 slot = find_empty(fd, 0, 0);
1035 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "unload: No Empty slot found\n");
1040 DebugPrint(DEBUG_INFO, SECTION_TAPE,"unload : found empty one, try to unload to slot %d\n", slot);
1046 * If eject is not set we must read the label info
1049 if (changer->eject == 0)
1051 if (pDev[INDEX_TAPE].avail == 1 && (changer->emubarcode == 1 || BarCode(INDEX_CHANGER)))
1054 if (pDev[INDEX_TAPECTL].SCSI == 1 && pDev[INDEX_TAPECTL].avail) {
1055 pDev[INDEX_TAPECTL].functions->function_rewind(INDEX_TAPECTL);
1057 pDev[INDEX_TAPE].functions->function_rewind(INDEX_TAPE);
1060 if (pDev[INDEX_TAPE].devopen == 1)
1062 SCSI_CloseDevice(INDEX_TAPE);
1065 chgscsi_result = (char *)tape_rdlabel(pDev[INDEX_TAPE].dev, &chgscsi_datestamp, &chgscsi_label);
1070 * Do the unload/move
1072 if (pDev[INDEX_CHANGER].functions->function_move(INDEX_CHANGER,
1073 pDTE[drive].address, pSTE[slot].address) != 0) {
1074 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"##### STOP unload (-1 move failed)\n");
1084 if (pDev[INDEX_CHANGER].functions->function_status(INDEX_CHANGER , 1) != 0)
1086 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"##### STOP unload (-1 update status failed)\n");
1093 * Did we get an error from tape_rdlabel
1094 * if no update the vol/label mapping
1095 * If chgscsi_label is NULL don't do it
1097 if (chgscsi_result == NULL && chgscsi_label != NULL && changer->labelfile != NULL)
1100 * OK this is only needed if we have emubarcode set
1101 * There we need an exact inventory to get the search function working
1102 * and returning correct results
1104 if (BarCode(INDEX_CHANGER) == 0 && changer->emubarcode == 1)
1107 * We got something, update the db
1108 * but before check if the db has as entry the slot
1109 * to where we placed the tape, if no force an inventory
1111 pbarcoderes->action = FIND_SLOT;
1112 strncpy(pbarcoderes->data.voltag, chgscsi_label,
1113 SIZEOF(pbarcoderes->data.voltag));
1114 strncpy(pbarcoderes->data.barcode, pSTE[slot].VolTag,
1115 SIZEOF(pbarcoderes->data.barcode));
1116 pbarcoderes->data.slot = 0;
1117 pbarcoderes->data.from = 0;
1118 pbarcoderes->data.LoadCount = 0;
1121 if ( MapBarCode(changer->labelfile, pbarcoderes) == 0) /* Nothing known about this, do an Inventory */
1125 if (slot != pbarcoderes->data.slot)
1127 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"Slot DB out of sync, slot %d != map %d",slot, pbarcoderes->data.slot);
1134 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### STOP unload(0)\n");
1141 * load the media from the specified element (slot) into the
1142 * specified data transfer unit (drive)
1143 * fd -> pointer to the internal device structure pDev
1144 * driver -> which drive in the library
1145 * slot -> the slot number from where to load
1147 * return -> 0 = success
1156 char *result = NULL; /* Needed for the result of tape_rdlabel */
1158 extern OpenFiles_T *pDev;
1159 extern int do_inventory;
1162 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"###### START load\n");
1163 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"%-20s : fd %d, drive %d, slot %d \n", "load", fd, drive, slot);
1164 pbarcoderes = alloc(SIZEOF(MBC_T));
1165 memset(pbarcoderes, 0 , SIZEOF(MBC_T));
1167 if (ElementStatusValid == 0)
1169 if (pDev[fd].functions->function_status(fd, 1) != 0)
1171 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"##### STOP load (-1)\n");
1172 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"##### STOP load (-1 update status failed)\n");
1180 * Check if the requested slot is in the range of available slots
1181 * The library starts counting at 1, we start at 0, so if the request slot
1182 * is ge than the value we got from the ModeSense fail with an return value
1185 if ((size_t)slot >= STE)
1187 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"load : slot %d ge STE %d\n",slot, STE);
1188 ChgExit("load", "slot >= STE", FATAL);
1193 * And the same for the tape drives
1195 if (drive >= (int)DTE)
1197 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"load : drive %d ge DTE %d\n",drive, DTE);
1198 ChgExit("load", "drive >= DTE", FATAL);
1202 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"load : load drive %d[%d] slot %d[%d]\n",drive,
1203 pDTE[drive].address,
1205 pSTE[slot].address);
1207 if (pDTE[drive].status == 'F')
1209 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"load : Drive %d address %d is full\n", drive, pDTE[drive].address);
1210 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"##### STOP load (-1 update status failed)\n");
1216 if (pSTE[slot].status == 'E')
1218 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"load : Slot %d address %d is empty\n", drive, pSTE[slot].address);
1219 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"##### STOP load (-1 update status failed)\n");
1225 ret = pDev[fd].functions->function_move(fd, pSTE[slot].address, pDTE[drive].address);
1230 if (pDev[fd].functions->function_status(fd, 1) != 0)
1232 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"##### STOP load (-1 update status failed)\n");
1239 * Try to read the label
1240 * and update the label/slot database
1242 if (pDev[INDEX_TAPE].avail == 1 && (changer->emubarcode == 1 || BarCode(INDEX_CHANGER)))
1245 if (pDev[INDEX_TAPECTL].SCSI == 1 && pDev[INDEX_TAPECTL].avail) {
1246 pDev[INDEX_TAPECTL].functions->function_rewind(INDEX_TAPECTL);
1248 pDev[INDEX_TAPE].functions->function_rewind(INDEX_TAPE);
1251 if (pDev[INDEX_TAPE].devopen == 1)
1253 SCSI_CloseDevice(INDEX_TAPE);
1256 result = (char *)tape_rdlabel(pDev[INDEX_TAPE].dev, &chgscsi_datestamp, &chgscsi_label);
1260 * Did we get an error from tape_rdlabel
1261 * if no update the vol/label mapping
1263 if (result == NULL && changer->labelfile != NULL && chgscsi_label != NULL )
1266 * We got something, update the db
1267 * but before check if the db has as entry the slot
1268 * to where we placed the tape, if no force an inventory
1270 strncpy(pbarcoderes->data.voltag, chgscsi_label,
1271 SIZEOF(pbarcoderes->data.voltag));
1272 pbarcoderes->data.slot = 0;
1273 pbarcoderes->data.from = 0;
1274 pbarcoderes->data.LoadCount = 0;
1278 * If we have an barcode reader we only do an update
1279 * If emubarcode is set we check if the
1280 * info in the DB is up to date, if no we set the do_inventory flag
1283 if (BarCode(INDEX_CHANGER) == 1 && changer->emubarcode == 0)
1285 pbarcoderes->action = UPDATE_SLOT;
1286 strncpy(pbarcoderes->data.barcode, pDTE[drive].VolTag,
1287 SIZEOF(pbarcoderes->data.barcode));
1288 pbarcoderes->data.LoadCount = 1;
1289 pbarcoderes->data.slot = slot;
1290 MapBarCode(changer->labelfile, pbarcoderes);
1293 if (BarCode(INDEX_CHANGER) == 0 && changer->emubarcode == 1)
1295 pbarcoderes->action = FIND_SLOT;
1296 if (MapBarCode(changer->labelfile, pbarcoderes) == 0) /* Nothing found, do an inventory */
1299 } else { /* We got something, is it correct ? */
1300 if (slot != pbarcoderes->data.slot && do_inventory == 0)
1302 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"Slot DB out of sync, slot %d != map %d",slot, pbarcoderes->data.slot);
1303 ChgExit("Load", "Label DB out of sync", FATAL);
1305 } else { /* OK, so increment the load count */
1306 pbarcoderes->action = UPDATE_SLOT;
1307 pbarcoderes->data.LoadCount = 1;
1308 pbarcoderes->data.slot = slot;
1309 MapBarCode(changer->labelfile, pbarcoderes);
1314 if (BarCode(INDEX_CHANGER) == 1 && changer->emubarcode == 1)
1316 ChgExit("Load", "BarCode == 1 and emubarcode == 1", FATAL);
1320 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"##### STOP load (%d)\n",ret);
1325 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"##### STOP load (%d)\n",ret);
1331 * Returns the number of Storage Slots which the library has
1332 * fd -> pointer to the internal devie structure pDev
1333 * return -> Number of slots
1339 extern OpenFiles_T *pDev;
1341 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"###### START get_slot_count\n");
1342 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"%-20s : fd %d\n", "get_slot_count", fd);
1344 if (ElementStatusValid == 0)
1346 pDev[fd].functions->function_status(fd, 1);
1348 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,
1349 "##### STOP get_slot_count (" SIZE_T_FMT ")\n",
1350 (SIZE_T_FMT_TYPE)STE);
1351 return((ssize_t)STE);
1353 * return the number of slots in the robot
1360 * retreive the number of data-transfer devices /Tape drives)
1361 * fd -> pointer to the internal devie structure pDev
1362 * return -> -1 on failure
1369 extern OpenFiles_T *pDev;
1371 DebugPrint(DEBUG_INFO, SECTION_SCSI,"###### START get_drive_count\n");
1372 DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-20s : fd %d\n", "get_drive_count", fd);
1374 if (ElementStatusValid == 0)
1376 if ( pDev[fd].functions->function_status(fd, 1) != 0)
1378 DebugPrint(DEBUG_ERROR, SECTION_SCSI, "Error getting drive count\n");
1379 DebugPrint(DEBUG_ERROR, SECTION_SCSI, "##### STOP get_drive_count (-1)\n");
1384 DebugPrint(DEBUG_INFO, SECTION_SCSI,
1385 "###### STOP get_drive_count (" SIZE_T_FMT " drives)\n",
1386 (SIZE_T_FMT_TYPE)DTE);
1387 return((ssize_t)DTE);
1391 * Now the internal functions
1395 * Open the device and placeit in the list of open files
1396 * The OS has to decide if it is an SCSI Commands capable device
1406 extern OpenFiles_T *pDev;
1408 ChangerCMD_T *p = (ChangerCMD_T *)&ChangerIO;
1415 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### START OpenDevice\n");
1416 DebugPrint(DEBUG_INFO, SECTION_SCSI,"OpenDevice : %s\n", DeviceName);
1418 pDev[ip].ConfigName = strdup(ConfigName);
1419 pDev[ip].dev = strdup(DeviceName);
1421 if (SCSI_OpenDevice(ip) != 0 )
1423 if (ident != NULL) /* Override by config */
1425 while(p->ident != NULL)
1427 if (strcmp(ident, p->ident) == 0)
1429 pDev[ip].functions = p;
1430 strncpy(pDev[ip].ident, ident, 17);
1431 DebugPrint(DEBUG_INFO, SECTION_SCSI,"override using ident = %s, type = %s\n",p->ident, p->type);
1432 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP OpenDevice\n");
1438 ChgExit("OpenDevice", "ident not found", FATAL);
1441 while(p->ident != NULL)
1443 if (strcmp(pDev[ip].ident, p->ident) == 0)
1445 pDev[ip].functions = p;
1446 DebugPrint(DEBUG_INFO, SECTION_SCSI,"using ident = %s, type = %s\n",p->ident, p->type);
1447 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP OpenDevice\n");
1454 /* Nothing matching found, try generic */
1455 /* divide generic in generic_type, where type is the */
1456 /* num returned by the inquiry command */
1457 p = (ChangerCMD_T *)&ChangerIO;
1458 snprintf(&tmpstr[0], SIZEOF(tmpstr), "%s_%s","generic",pDev[0].type);
1459 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### OpenDevice trying GENERIC Device %s\n",tmpstr);
1460 while(p->ident != NULL)
1462 if (strcmp(tmpstr, p->ident) == 0)
1464 pDev[ip].functions = p;
1465 DebugPrint(DEBUG_INFO, SECTION_SCSI,"using ident = %s, type = %s\n",p->ident, p->type);
1466 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP OpenDevice\n");
1472 } else { /* Something failed, lets see what */
1473 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"##### STOP OpenDevice failed\n");
1475 pDev[ip].functions = NULL;
1476 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP OpenDevice (nothing found) !!\n");
1482 * This functions checks if the library has an barcode reader.
1483 * fd -> pointer to the internal devie structure pDev
1490 extern OpenFiles_T *pDev;
1492 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"##### START BarCode\n");
1493 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"%-20s : fd %d\n", "BarCode", fd);
1495 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"Ident = [%s], function = [%s]\n", pDev[fd].ident,
1496 pDev[fd].functions->ident);
1497 ret = pDev[fd].functions->function_barcode(fd);
1498 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"##### STOP BarCode (%d)\n",ret);
1504 * This functions check if the tape drive is ready
1506 * fd -> pointer to the internal devie structure pDev
1507 * wait -> time to wait for the ready status
1515 extern OpenFiles_T *pDev;
1520 RequestSense_T *pRequestSense;
1521 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### START Tape_Ready\n");
1524 * Which device should we use to get the
1529 * First the ioctl tapedevice
1531 if (pDev[INDEX_TAPE].avail == 1)
1537 * But if available and can do SCSI
1540 if (pDev[INDEX_TAPECTL].avail == 1 && pDev[INDEX_TAPECTL].SCSI == 1)
1545 if (pDev[fd].avail == 1 && pDev[fd].SCSI == 0)
1547 DebugPrint(DEBUG_INFO, SECTION_TAPE,"Tape_Ready : Can't send SCSI commands, try ioctl\n");
1549 * Do we get an non negative result.
1550 * If yes this function is available
1551 * and we can use it to get the status
1554 ret = Tape_Status(fd);
1557 while (cnt < wait_time)
1559 if ( ret & TAPE_ONLINE)
1561 DebugPrint(DEBUG_INFO, SECTION_TAPE,"Tape_Ready : Ready after %d seconds\n",cnt);
1562 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### STOP Tape_Ready\n");
1568 ret = Tape_Status(fd);
1571 DebugPrint(DEBUG_INFO, SECTION_TAPE,"Tape_Ready : not ready, stop after %d seconds\n",cnt);
1572 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### STOP Tape_Ready\n");
1577 DebugPrint(DEBUG_INFO, SECTION_TAPE,"Tape_Ready : no ioctl interface, will sleep for %d seconds\n", wait_time);
1579 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### STOP Tape_Ready\n");
1584 pRequestSense = alloc(SIZEOF(RequestSense_T));
1587 * Ignore errors at this point
1592 * Wait until we get an ready condition
1596 while (!done && (cnt < wait_time))
1598 ret = SCSI_TestUnitReady(fd, pRequestSense );
1605 switch (SenseHandler(fd, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
1608 DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeReady (TestUnitReady) SENSE_NO\n");
1611 case SENSE_TAPE_NOT_ONLINE:
1612 DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeReady (TestUnitReady) SENSE_TAPE_NOT_ONLINE\n");
1615 DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeReady (TestUnitReady) SENSE_IGNORE\n");
1619 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"TapeReady (TestUnitReady) SENSE_ABORT\n");
1620 amfree(pRequestSense);
1624 DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeReady (TestUnitReady) SENSE_RETRY\n");
1627 DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeReady (TestUnitReady) default (SENSE)\n");
1633 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"TapeReady (TestUnitReady) SCSI_ERROR\n");
1634 free(pRequestSense);
1638 DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeReady (TestUnitReady) SCSI_BUSY\n");
1641 DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeReady (TestUnitReady) SCSI_CHECK\n");
1644 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"TapeReady (TestUnitReady) unknown (%d)\n",ret);
1651 amfree(pRequestSense);
1652 DebugPrint(DEBUG_INFO, SECTION_TAPE,"Tape_Ready after %d sec\n", cnt);
1653 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### STOP Tape_Ready\n");
1663 SC_COM_T *pSCSICommand;
1666 DebugPrint(DEBUG_INFO, SECTION_SCSI, "##### START DecodeSCSI\n");
1667 pSCSICommand = (SC_COM_T *)&SCSICommand;
1669 while (pSCSICommand->name != NULL)
1671 if (CDB[0] == pSCSICommand->command)
1673 DebugPrint(DEBUG_INFO, SECTION_SCSI,"%s %s", string, pSCSICommand->name);
1674 for (x=0; x < pSCSICommand->length; x++)
1676 DebugPrint(DEBUG_INFO, SECTION_SCSI," %02X", CDB[x]);
1678 DebugPrint(DEBUG_INFO, SECTION_SCSI,"\n");
1679 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP DecodeSCSI\n");
1685 DebugPrint(DEBUG_INFO, SECTION_SCSI,"Not found %X\n", CDB[0]);
1686 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP DecodeSCSI\n");
1698 ReadWriteErrorRecoveryPage_T *prp;
1699 DisconnectReconnectPage_T *pdrp;
1700 size_t length = (size_t)buffer[0] - 4 - offset;
1702 (void)pstring; /* Quiet unused parameter warning */
1704 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### START DecodeModeSense\n");
1706 dump_hex(buffer, 255, DEBUG_INFO, SECTION_SCSI);
1708 /* Jump over the Parameter List header and an offset if we have something
1709 * Unknown at the start (ADIC-218) at the moment
1712 buffer = buffer + 4 + offset;
1714 DebugPrint(DEBUG_INFO, SECTION_SCSI,"buffer length = %d\n", length);
1716 if (block) /* Do we have an block descriptor page ?*/
1719 fprintf(out, "DecodeModeSense : Density Code %x\n", (unsigned)buffer[0]);
1723 fprintf(out, "DecodeModeSense : Number of Blocks %d\n", V3(buffer));
1724 buffer = buffer + 4;
1727 fprintf(out, "DecodeModeSense : Block Length %d\n", V3(buffer));
1728 buffer = buffer + 3;
1733 switch (*buffer & 0x3f)
1736 pVendorUnique = buffer;
1740 prp = (ReadWriteErrorRecoveryPage_T *)buffer;
1743 fprintf(out, "DecodeModeSense : Read/Write Error Recovery Page\n");
1744 fprintf(out,"\tTransfer Block %d\n", prp->tb);
1745 fprintf(out,"\tEnable Early Recovery %d\n", prp->eer);
1746 fprintf(out,"\tPost Error %d\n", prp->per);
1747 fprintf(out,"\tDisable Transfer on Error %d\n", prp->dte);
1748 fprintf(out,"\tDisable ECC Correction %d\n", prp->dcr);
1749 fprintf(out,"\tRead Retry Count %d\n", prp->ReadRetryCount);
1750 fprintf(out,"\tWrite Retry Count %d\n", prp->WriteRetryCount);
1755 pdrp = (DisconnectReconnectPage_T *)buffer;
1758 fprintf(out, "DecodeModeSense : Disconnect/Reconnect Page\n");
1759 fprintf(out,"\tBuffer Full Ratio %d\n", pdrp->BufferFullRatio);
1760 fprintf(out,"\tBuffer Empty Ratio %d\n", pdrp->BufferEmptyRatio);
1761 fprintf(out,"\tBus Inactivity Limit %d\n",
1762 V2(pdrp->BusInactivityLimit));
1763 fprintf(out,"\tDisconnect Time Limit %d\n",
1764 V2(pdrp->DisconnectTimeLimit));
1765 fprintf(out,"\tConnect Time Limit %d\n",
1766 V2(pdrp->ConnectTimeLimit));
1767 fprintf(out,"\tMaximum Burst Size %d\n",
1768 V2(pdrp->MaximumBurstSize));
1769 fprintf(out,"\tDTDC %d\n", pdrp->DTDC);
1774 pEAAPage = (EAAPage_T *)buffer;
1777 fprintf(out,"DecodeModeSense : Element Address Assignment Page\n");
1778 fprintf(out,"\tMedium Transport Element Address %d\n",
1779 V2(pEAAPage->MediumTransportElementAddress));
1780 fprintf(out,"\tNumber of Medium Transport Elements %d\n",
1781 V2(pEAAPage->NoMediumTransportElements));
1782 fprintf(out, "\tFirst Storage Element Address %d\n",
1783 V2(pEAAPage->FirstStorageElementAddress));
1784 fprintf(out, "\tNumber of Storage Elements %d\n",
1785 V2(pEAAPage->NoStorageElements));
1786 fprintf(out, "\tFirst Import/Export Element Address %d\n",
1787 V2(pEAAPage->FirstImportExportElementAddress));
1788 fprintf(out, "\tNumber of ImportExport Elements %d\n",
1789 V2(pEAAPage->NoImportExportElements));
1790 fprintf(out, "\tFirst Data Transfer Element Address %d\n",
1791 V2(pEAAPage->FirstDataTransferElementAddress));
1792 fprintf(out, "\tNumber of Data Transfer Elements %d\n",
1793 V2(pEAAPage->NoDataTransferElements));
1798 pDeviceCapabilitiesPage = (DeviceCapabilitiesPage_T *)buffer;
1801 fprintf(out, "DecodeModeSense : MT can store data cartridges %d\n",
1802 pDeviceCapabilitiesPage->MT);
1803 fprintf(out, "DecodeModeSense : ST can store data cartridges %d\n",
1804 pDeviceCapabilitiesPage->ST);
1805 fprintf(out, "DecodeModeSense : IE can store data cartridges %d\n",
1806 pDeviceCapabilitiesPage->IE);
1807 fprintf(out, "DecodeModeSense : DT can store data cartridges %d\n",
1808 pDeviceCapabilitiesPage->DT);
1809 fprintf(out, "DecodeModeSense : MT to MT %d\n",
1810 pDeviceCapabilitiesPage->MT2MT);
1811 fprintf(out, "DecodeModeSense : MT to ST %d\n",
1812 pDeviceCapabilitiesPage->MT2ST);
1813 fprintf(out, "DecodeModeSense : MT to IE %d\n",
1814 pDeviceCapabilitiesPage->MT2IE);
1815 fprintf(out, "DecodeModeSense : MT to DT %d\n",
1816 pDeviceCapabilitiesPage->MT2DT);
1817 fprintf(out, "DecodeModeSense : ST to MT %d\n",
1818 pDeviceCapabilitiesPage->ST2ST);
1819 fprintf(out, "DecodeModeSense : ST to MT %d\n",
1820 pDeviceCapabilitiesPage->ST2ST);
1821 fprintf(out, "DecodeModeSense : ST to DT %d\n",
1822 pDeviceCapabilitiesPage->ST2DT);
1823 fprintf(out, "DecodeModeSense : IE to MT %d\n",
1824 pDeviceCapabilitiesPage->IE2MT);
1825 fprintf(out, "DecodeModeSense : IE to ST %d\n",
1826 pDeviceCapabilitiesPage->IE2IE);
1827 fprintf(out, "DecodeModeSense : IE to ST %d\n",
1828 pDeviceCapabilitiesPage->IE2DT);
1829 fprintf(out, "DecodeModeSense : IE to ST %d\n",
1830 pDeviceCapabilitiesPage->IE2DT);
1831 fprintf(out, "DecodeModeSense : DT to MT %d\n",
1832 pDeviceCapabilitiesPage->DT2MT);
1833 fprintf(out, "DecodeModeSense : DT to ST %d\n",
1834 pDeviceCapabilitiesPage->DT2ST);
1835 fprintf(out, "DecodeModeSense : DT to IE %d\n",
1836 pDeviceCapabilitiesPage->DT2IE);
1837 fprintf(out, "DecodeModeSense : DT to DT %d\n",
1838 pDeviceCapabilitiesPage->DT2DT);
1843 buffer++; /* set pointer to the length information */
1846 /* Error if *buffer (length) is 0 */
1849 /* EAAPage = NULL; */
1850 /* DeviceCapabilitiesPage = NULL; */
1854 length = length - (size_t)*buffer - 2;
1855 buffer = buffer + (size_t)*buffer + 1;
1862 RequestSense_T * sense,
1871 fprintf(out,"##### START DecodeSense\n");
1872 fprintf(out,"%sSense Keys\n", pstring);
1873 if (sense->ErrorCode == 0x70)
1875 fprintf(out,"\tExtended Sense \n");
1877 fprintf(out,"\tErrorCode %02x\n", sense->ErrorCode);
1878 fprintf(out,"\tValid %d\n", sense->Valid);
1880 fprintf(out,"\tASC %02X\n", sense->AdditionalSenseCode);
1881 fprintf(out,"\tASCQ %02X\n", sense->AdditionalSenseCodeQualifier);
1882 fprintf(out,"\tSense key %02X\n", sense->SenseKey);
1883 switch (sense->SenseKey)
1886 fprintf(out,"\t\tNo Sense\n");
1889 fprintf(out,"\t\tRecoverd Error\n");
1892 fprintf(out,"\t\tNot Ready\n");
1895 fprintf(out,"\t\tMedium Error\n");
1898 fprintf(out,"\t\tHardware Error\n");
1901 fprintf(out,"\t\tIllegal Request\n");
1904 fprintf(out,"\t\tUnit Attention\n");
1907 fprintf(out,"\t\tData Protect\n");
1910 fprintf(out,"\t\tBlank Check\n");
1913 fprintf(out,"\t\tVendor uniq\n");
1916 fprintf(out,"\t\tCopy Aborted\n");
1919 fprintf(out,"\t\tAborted Command\n");
1922 fprintf(out,"\t\tEqual\n");
1925 fprintf(out,"\t\tVolume Overflow\n");
1928 fprintf(out,"\t\tMiscompare\n");
1931 fprintf(out,"\t\tReserved\n");
1939 ExtendedRequestSense_T * sense,
1943 ExtendedRequestSense_T *p;
1945 fprintf(out,"##### START DecodeExtSense\n");
1948 fprintf(out,"%sExtended Sense\n", pstring);
1949 DecodeSense((RequestSense_T *)p, pstring, out);
1950 fprintf(out,"\tLog Parameter Page Code %02X\n", sense->LogParameterPageCode);
1951 fprintf(out,"\tLog Parameter Code %02X\n", sense->LogParameterCode);
1952 fprintf(out,"\tUnderrun/Overrun Counter %02X\n", sense->UnderrunOverrunCounter);
1953 fprintf(out,"\tRead/Write Error Counter %d\n", V3((char *)sense->ReadWriteDataErrorCounter));
1954 if (sense->AdditionalSenseLength > (u_char)sizeof(RequestSense_T))
1957 fprintf(out,"\tPower Fail\n");
1959 fprintf(out,"\tSCSI Bus Parity Error\n");
1961 fprintf(out,"\tFormatted Buffer parity Error\n");
1963 fprintf(out,"\tMedia Error\n");
1965 fprintf(out,"\tError Counter Overflow\n");
1967 fprintf(out,"\tTapeMotion Error\n");
1969 fprintf(out,"\tTape Not Present\n");
1971 fprintf(out,"\tLogical Beginning of tape\n");
1973 fprintf(out,"\tTape Mark Detect Error\n");
1975 fprintf(out,"\tWrite Protect\n");
1977 fprintf(out,"\tFilemark Error\n");
1979 fprintf(out,"\tUnder Run Error\n");
1981 fprintf(out,"\tWrite Error 1\n");
1983 fprintf(out,"\tServo System Error\n");
1985 fprintf(out,"\tFormatter Error\n");
1987 fprintf(out,"\tCleaning Cartridge is empty\n");
1989 fprintf(out,"\tReverse Retries Required\n");
1991 fprintf(out,"\tTape Drive has been cleaned\n");
1993 fprintf(out,"\tTape Drive needs to be cleaned\n");
1995 fprintf(out,"\tPhysical End of Tape\n");
1997 fprintf(out,"\tWrite Splice Error\n");
1999 fprintf(out,"\tWrite Splice Error\n");
2000 fprintf(out,"\tRemaing 1024 byte tape blocks %d\n", V3((char *)sense->RemainingTape));
2001 fprintf(out,"\tTracking Retry Counter %02X\n", sense->TrackingRetryCounter);
2002 fprintf(out,"\tRead/Write Retry Counter %02X\n", sense->ReadWriteRetryCounter);
2003 fprintf(out,"\tFault Sympton Code %02X\n", sense->FaultSymptomCode);
2010 SCSIInquiry_T * SCSIInquiry)
2012 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### START PrintInquiry\n");
2013 DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-15s %x\n", "qualifier", SCSIInquiry->qualifier);
2014 DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-15s %x\n", "type", SCSIInquiry->type);
2015 DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-15s %x\n", "data_format", SCSIInquiry->data_format);
2016 DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-15s %X\n", "ansi_version", SCSIInquiry->ansi_version);
2017 DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-15s %X\n", "ecma_version", SCSIInquiry->ecma_version);
2018 DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-15s %X\n", "iso_version", SCSIInquiry->iso_version);
2019 DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-15s %X\n", "type_modifier", SCSIInquiry->type_modifier);
2020 DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-15s %x\n", "removable", SCSIInquiry->removable);
2021 DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-15s %.8s\n", "vendor_info", SCSIInquiry->vendor_info);
2022 DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-15s %.16s\n", "prod_ident", SCSIInquiry->prod_ident);
2023 DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-15s %.4s\n", "prod_version", SCSIInquiry->prod_version);
2024 DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-15s %.19s\n", "vendor_specific", SCSIInquiry->vendor_specific);
2032 dbprintf(("##### START DoNothing\n"));
2040 (void)unused1; /* Quiet unused parameter warning */
2042 dbprintf(("##### START DoNothing\n"));
2051 (void)unused1; /* Quiet unused parameter warning */
2052 (void)unused2; /* Quiet unused parameter warning */
2054 dbprintf(("##### START DoNothing\n"));
2064 (void)unused1; /* Quiet unused parameter warning */
2065 (void)unused2; /* Quiet unused parameter warning */
2066 (void)unused3; /* Quiet unused parameter warning */
2068 dbprintf(("##### START DoNothing\n"));
2075 dbprintf(("##### START GenericFree\n"));
2082 dbprintf(("##### START GenericSearch\n"));
2090 extern OpenFiles_T *pDev;
2092 ModePageTreeFrogVendorUnique_T *pVendor;
2094 dbprintf(("##### START TreeFrogBarCode\n"));
2095 if (pModePage == NULL)
2097 pModePage = alloc(0xff);
2100 if (SCSI_ModeSense(DeviceFD, pModePage, 0xff, 0x0, 0x3f) == 0)
2102 DecodeModeSense(pModePage, 0, "TreeFrogBarCode :", 0, debug_file);
2104 if (pVendorUnique == NULL)
2106 dbprintf(("TreeFrogBarCode : no pVendorUnique\n"));
2110 pVendor = ( ModePageTreeFrogVendorUnique_T *)pVendorUnique;
2112 dbprintf(("TreeFrogBarCode : EBARCO %d\n", pVendor->EBARCO));
2113 dbprintf(("TreeFrogCheckSum : CHKSUM %d\n", pVendor->CHKSUM));
2115 dump_hex((u_char *)pDev[INDEX_CHANGER].inquiry, INQUIRY_SIZE, DEBUG_INFO, SECTION_ELEMENT);
2116 return(pVendor->EBARCO);
2126 extern OpenFiles_T *pDev;
2128 ModePageEXB120VendorUnique_T *pVendor;
2129 ModePageEXB120VendorUnique_T *pVendorWork;
2131 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"##### START EXB_BarCode\n");
2132 if (pModePage == NULL && LibModeSenseValid == 0)
2134 pModePage = alloc(0xff);
2136 if (SCSI_ModeSense(DeviceFD, pModePage, 0xff, 0x8, 0x3f) == 0)
2138 DecodeModeSense(pModePage, 0, "EXB_BarCode :", 0, debug_file);
2139 LibModeSenseValid = 1;
2141 LibModeSenseValid = -1;
2145 if (LibModeSenseValid == 1)
2147 if (pVendorUnique == NULL)
2149 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"EXB_BarCode : no pVendorUnique\n");
2153 pVendor = ( ModePageEXB120VendorUnique_T *)pVendorUnique;
2155 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"EXB_BarCode : NBL %d\n", pVendor->NBL);
2156 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"EXB_BarCode : PS %d\n", pVendor->PS);
2157 if (pVendor->NBL == 1 && pVendor->PS == 1 )
2159 pVendorWork = alloc((size_t)pVendor->ParameterListLength + 2);
2160 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"EXB_BarCode : setting NBL to 1\n");
2161 memcpy(pVendorWork, pVendor, (size_t)pVendor->ParameterListLength + 2);
2162 pVendorWork->NBL = 0;
2163 pVendorWork->PS = 0;
2164 pVendorWork->RSVD0 = 0;
2165 if (SCSI_ModeSelect(DeviceFD, (u_char *)pVendorWork, (u_char)(pVendorWork->ParameterListLength + 2), 0, 1, 0) == 0)
2167 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"EXB_BarCode : SCSI_ModeSelect OK\n");
2172 /* And now again !!!
2174 GenericResetStatus(DeviceFD);
2176 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"EXB_BarCode : SCSI_ModeSelect failed\n");
2178 amfree(pVendorWork);
2180 dump_hex((u_char *)pDev[INDEX_CHANGER].inquiry, INQUIRY_SIZE, DEBUG_INFO, SECTION_BARCODE);
2181 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"EXB_BarCode : vendor_specific[19] %x\n",
2182 pDev[INDEX_CHANGER].inquiry->vendor_specific[19]);
2191 (void)DeviceFD; /* Quiet unused parameter warning */
2193 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"##### START NoBarCode\n");
2194 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"##### STOP NoBarCode\n");
2202 (void)DeviceFD; /* Quiet unused parameter warning */
2204 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"##### START GenericBarCode\n");
2205 if ( changer->havebarcode >= 1)
2207 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"##### STOP GenericBarCode (havebarcode) => %d\n",changer->havebarcode);
2211 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"##### STOP GenericBarCode => 0\n");
2220 u_char AdditionalSenseCode,
2221 u_char AdditionalSenseCodeQualifier,
2222 RequestSense_T * buffer)
2224 extern OpenFiles_T *pDev;
2226 dbprintf(("##### START SenseHandler\n"));
2227 if (pDev[DeviceFD].inqdone == 1)
2229 dbprintf(("Ident = [%s], function = [%s]\n", pDev[DeviceFD].ident,
2230 pDev[DeviceFD].functions->ident));
2231 ret = pDev[DeviceFD].functions->function_error(DeviceFD, flag, SenseKey, AdditionalSenseCode, AdditionalSenseCodeQualifier, buffer);
2233 dbprintf((" Ups no sense\n"));
2235 dbprintf(("#### STOP SenseHandler\n"));
2240 * Try to get information about the tape,
2241 * Tape loaded ? Online etc
2242 * Use the mtio ioctl to get the information if no SCSI Path
2243 * to the tape drive is available.
2246 * Pass an parameter to identify which unit to use
2247 * if there are more than one
2248 * Implement the SCSI path if available
2253 extern OpenFiles_T *pDev;
2257 RequestSense_T *pRequestSense;
2259 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### START TapeStatus\n");
2262 * If it is an device which understand SCSI commands the
2263 * normal ioctl (MTIOCGET for example) may fail
2266 if (pDev[INDEX_TAPECTL].SCSI == 1)
2268 pRequestSense = alloc(SIZEOF(RequestSense_T));
2269 memset(pRequestSense, 0, SIZEOF(RequestSense_T));
2271 for (done = 0, cnt = 0; !done && (cnt < 60); cnt++)
2273 ret = SCSI_TestUnitReady(INDEX_TAPECTL, pRequestSense);
2274 DebugPrint(DEBUG_INFO, SECTION_SCSI, "TapeStatus TestUnitReady ret %d\n",ret);
2279 switch (SenseHandler(INDEX_TAPECTL, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
2283 DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeStatus (TestUnitReady) SENSE_NO\n");
2284 pDTE[0].status = 'F';
2285 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### FULL\n");
2289 case SENSE_TAPE_NOT_ONLINE:
2290 DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeStatus (TestUnitReady) SENSE_TAPE_NOT_ONLINE\n");
2291 pDTE[0].status = 'E';
2292 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### EMPTY\n");
2297 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"TapeStatus (TestUnitReady) SENSE_ABORT\n");
2302 DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeStatus (TestUnitReady) SENSE_RETRY\n");
2306 DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeStatus (TestUnitReady) default (SENSE)\n");
2312 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"TapeStatus (TestUnitReady) SCSI_ERROR\n");
2317 DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeStatus (TestUnitReady) SCSI_BUSY\n");
2321 DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeStatus (TestUnitReady) SCSI_CHECK\n");
2325 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"TapeStatus (TestUnitReady) unknown (%d)\n",ret);
2332 amfree(pRequestSense);
2334 ret = Tape_Status(INDEX_TAPE);
2335 if ( ret & TAPE_ONLINE)
2337 pDTE[0].status ='F';
2338 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### FULL\n");
2340 pDTE[0].status = 'E';
2341 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### EMPTY\n");
2343 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### STOP TapeStatus\n");
2353 extern OpenFiles_T *pDev;
2355 RequestSense_T *pRequestSense;
2356 ExtendedRequestSense_T *pExtendedRequestSense;
2361 (void)Device; /* Quiet unused parameter warning */
2363 dbprintf(("##### START DLT4000Eject\n"));
2365 pRequestSense = alloc(SIZEOF(RequestSense_T));
2366 pExtendedRequestSense = alloc(SIZEOF(ExtendedRequestSense_T));
2370 dbprintf(("DLT4000Eject : use mtio ioctl for eject on %s\n", pDev[INDEX_TAPE].dev));
2371 free(pExtendedRequestSense);
2372 free(pRequestSense);
2373 return(Tape_Ioctl(INDEX_TAPE, IOCTL_EJECT));
2379 if (pDev[INDEX_TAPECTL].SCSI == 0)
2381 dbprintf(("DLT4000Eject : Device %s not able to receive SCSI commands\n", pDev[INDEX_TAPE].dev));
2382 free(pExtendedRequestSense);
2383 free(pRequestSense);
2384 return(Tape_Ioctl(INDEX_TAPE, IOCTL_EJECT));
2389 dbprintf(("DLT4000Eject : SCSI eject on %s = %s\n", pDev[INDEX_TAPECTL].dev, pDev[INDEX_TAPECTL].ConfigName));
2391 RequestSense(INDEX_TAPECTL, pExtendedRequestSense, 0);
2392 DecodeExtSense(pExtendedRequestSense, "DLT4000Eject : ", debug_file);
2393 /* Unload the tape, 0 == wait for success
2396 ret = SCSI_LoadUnload(INDEX_TAPECTL, pRequestSense, 0, 0);
2398 RequestSense(INDEX_TAPECTL, pExtendedRequestSense, 0);
2399 DecodeExtSense(pExtendedRequestSense, "DLT4000Eject : ", debug_file);
2403 free(pExtendedRequestSense);
2404 free(pRequestSense);
2410 while (!done && cnt < 300)
2412 ret = SCSI_TestUnitReady(INDEX_TAPECTL, pRequestSense);
2413 DebugPrint(DEBUG_INFO, SECTION_SCSI, "DLT4000Eject TestUnitReady ret %d\n",ret);
2420 switch (SenseHandler(INDEX_TAPECTL, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
2423 DebugPrint(DEBUG_INFO, SECTION_SCSI,"DLT4000Eject (TestUnitReady) SENSE_NO\n");
2426 case SENSE_TAPE_NOT_ONLINE:
2427 DebugPrint(DEBUG_INFO, SECTION_SCSI,"DLT4000Eject (TestUnitReady) SENSE_TAPE_NOT_ONLINE\n");
2431 DebugPrint(DEBUG_INFO, SECTION_SCSI,"DLT4000Eject (TestUnitReady) SENSE_IGNORE\n");
2435 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"DLT4000Eject (TestUnitReady) SENSE_ABORT\n");
2436 free(pExtendedRequestSense);
2437 free(pRequestSense);
2441 DebugPrint(DEBUG_INFO, SECTION_SCSI,"DLT4000Eject (TestUnitReady) SENSE_RETRY\n");
2444 DebugPrint(DEBUG_INFO, SECTION_SCSI,"DLT4000Eject (TestUnitReady) default (SENSE)\n");
2450 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"DLT4000Eject (TestUnitReady) SCSI_ERROR\n");
2451 free(pExtendedRequestSense);
2452 free(pRequestSense);
2456 DebugPrint(DEBUG_INFO, SECTION_SCSI,"DLT4000Eject (TestUnitReady) SCSI_BUSY\n");
2459 DebugPrint(DEBUG_INFO, SECTION_SCSI,"DLT4000Eject (TestUnitReady) SCSI_CHECK\n");
2462 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"DLT4000Eject (TestUnitReady) unknown (%d)\n",ret);
2470 dbprintf(("DLT4000Eject : Ready after %d sec, done = %d\n", cnt * 2, done));
2472 free(pExtendedRequestSense);
2473 free(pRequestSense);
2479 * Ejects an tape either with the ioctl interface
2480 * or by using the SCSI interface if available.
2483 * Before unload check if there is an tape in the drive
2491 extern OpenFiles_T *pDev;
2492 RequestSense_T *pRequestSense;
2497 (void)Device; /* Quiet unused parameter warning */
2498 (void)type; /* Quiet unused parameter warning */
2500 DebugPrint(DEBUG_INFO, SECTION_TAPE, "##### START GenericEject\n");
2502 pRequestSense = alloc(SIZEOF(RequestSense_T));
2504 DebugPrint(DEBUG_INFO, SECTION_TAPE,"GenericEject : SCSI eject on %s = %s\n",
2505 pDev[INDEX_TAPECTL].dev, pDev[INDEX_TAPECTL].ConfigName);
2508 * Can we use SCSI commands ?
2510 if (pDev[INDEX_TAPECTL].SCSI == 1)
2512 LogSense(INDEX_TAPECTL);
2514 * Unload the tape, 1 == don't wait for success
2517 ret = SCSI_LoadUnload(INDEX_TAPECTL, pRequestSense, 1, 0);
2521 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericEject SCSI_LoadUnload failed\n");
2522 free(pRequestSense);
2528 while (!done && cnt < 300)
2530 ret = SCSI_TestUnitReady(INDEX_TAPECTL, pRequestSense);
2531 DebugPrint(DEBUG_INFO, SECTION_SCSI, "GenericEject TestUnitReady ret %d\n",ret);
2536 switch (SenseHandler(INDEX_TAPECTL, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
2539 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericEject (TestUnitReady) SENSE_NO\n");
2541 case SENSE_TAPE_NOT_ONLINE:
2542 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericEject (TestUnitReady) SENSE_TAPE_NOT_ONLINE\n");
2546 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericEject (TestUnitReady) SENSE_IGNORE\n");
2549 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"GenericEject (TestUnitReady) SENSE_ABORT\n");
2550 free(pRequestSense);
2554 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericEject (TestUnitReady) SENSE_RETRY\n");
2557 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericEject (TestUnitReady) default (SENSE)\n");
2562 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"GenericEject (TestUnitReady) SCSI_ERROR\n");
2563 free(pRequestSense);
2567 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericEject (TestUnitReady) SCSI_BUSY\n");
2570 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericEject (TestUnitReady) SCSI_CHECK\n");
2573 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"GenericEject (TestUnitReady) unknown (%d)\n",ret);
2580 DebugPrint(DEBUG_INFO, SECTION_TAPE,"GenericEject : Device can't understand SCSI try ioctl\n");
2581 Tape_Ioctl(INDEX_TAPECTL, IOCTL_EJECT);
2583 DebugPrint(DEBUG_INFO, SECTION_TAPE,
2584 "GenericEject : Ready after %d sec\n", cnt * 2);
2585 free(pRequestSense);
2593 * Make the retry counter an config option,
2604 extern OpenFiles_T *pDev;
2605 RequestSense_T *pRequestSense;
2606 char *errstr; /* Used by tape_rewind */
2611 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### START GenericRewind pDEV -> %d\n",DeviceFD);
2615 * If we can use the SCSI device than use it, else use the ioctl
2618 if (pDev[DeviceFD].SCSI == 1)
2620 pRequestSense = alloc(SIZEOF(RequestSense_T));
2623 * Before doing the rewind check if the tape is ready to accept commands
2629 ret = SCSI_TestUnitReady(DeviceFD, (RequestSense_T *)pRequestSense );
2630 DebugPrint(DEBUG_INFO, SECTION_TAPE, "GenericRewind (TestUnitReady) ret %d\n",ret);
2637 switch (SenseHandler(DeviceFD, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
2640 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) SENSE_NO\n");
2643 case SENSE_TAPE_NOT_ONLINE:
2644 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) SENSE_TAPE_NOT_ONLINE\n");
2645 free(pRequestSense);
2649 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) SENSE_IGNORE\n");
2653 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"GenericRewind (TestUnitReady) SENSE_ABORT\n");
2654 free(pRequestSense);
2658 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) SENSE_RETRY\n");
2661 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) default (SENSE)\n");
2664 } /* switch (SenseHandler(DeviceFD, 0, pRequestSense->SenseKey.... */
2668 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"GenericRewind (TestUnitReady) SCSI_ERROR\n");
2669 free(pRequestSense);
2674 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) SCSI_BUSY\n");
2677 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) SCSI_CHECK\n");
2680 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"GenericRewind (TestUnitReady) unknown (%d)\n",ret);
2685 DebugPrint(DEBUG_INFO, SECTION_TAPE," Wait .... (%d)\n",cnt);
2688 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"##### STOP GenericRewind (-1)\n");
2689 free(pRequestSense);
2697 CDB[0] = SC_COM_REWIND;
2707 ret = SCSI_Run(DeviceFD, Input, CDB, 6,
2710 SIZEOF(RequestSense_T));
2712 DecodeSense(pRequestSense, "GenericRewind : ", debug_file);
2716 if (pRequestSense->SenseKey != UNIT_ATTENTION)
2727 DebugPrint(DEBUG_INFO, SECTION_TAPE,"GenericRewind : failed %d\n", ret);
2733 while (!done && (cnt < 300))
2735 ret = SCSI_TestUnitReady(DeviceFD, pRequestSense);
2736 DebugPrint(DEBUG_INFO, SECTION_SCSI, "GenericRewind TestUnitReady ret %d\n",ret);
2743 switch (SenseHandler(DeviceFD, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
2746 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) SENSE_NO\n");
2749 case SENSE_TAPE_NOT_ONLINE:
2750 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) SENSE_TAPE_NOT_ONLINE\n");
2751 free(pRequestSense);
2755 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) SENSE_IGNORE\n");
2759 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"GenericRewind (TestUnitReady) SENSE_ABORT\n");
2760 free(pRequestSense);
2764 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) SENSE_RETRY\n");
2767 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) default (SENSE)\n");
2773 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"GenericRewind (TestUnitReady) SCSI_ERROR\n");
2778 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) SCSI_BUSY\n");
2781 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) SCSI_CHECK\n");
2784 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"GenericRewind (TestUnitReady) unknown (%d)\n",ret);
2792 amfree(pRequestSense);
2794 DebugPrint(DEBUG_INFO, SECTION_TAPE,"GenericRewind : Ready after %d sec, "
2795 "done = %d\n", cnt * 2, done);
2796 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### STOP GenericRewind (0)\n");
2798 DebugPrint(DEBUG_INFO, SECTION_TAPE,"GenericRewind : use ioctl rewind\n");
2799 if (pDev[DeviceFD].devopen == 1)
2801 DebugPrint(DEBUG_INFO, SECTION_TAPE,"Close Device\n");
2802 SCSI_CloseDevice(DeviceFD);
2804 /* We don't retry if it fails; that is left to the vtape driver. */
2805 if ((errstr = tape_rewind(pDev[DeviceFD].dev)) == NULL) {
2806 DebugPrint(DEBUG_INFO, SECTION_TAPE,"Rewind OK,\n", cnt);
2808 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"Rewind failed %s\n",errstr);
2809 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### STOP GenericRewind (-1)\n");
2813 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### STOP GenericRewind (0)\n");
2821 * Check if the tape has the tape clean
2822 * bit set in the return of an request sense
2829 extern OpenFiles_T *pDev;
2830 ExtendedRequestSense_T ExtRequestSense;
2833 (void)Device; /* Quiet unused parameter warning */
2835 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### START GenericClean\n");
2836 if (pDev[INDEX_TAPECTL].SCSI == 0)
2838 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"GenericClean : can't send SCSI commands\n");
2839 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"##### STOP GenericClean\n");
2845 * Request Sense Data, reset the counter
2847 if ( RequestSense(INDEX_TAPECTL, &ExtRequestSense, 1) == 0)
2850 DecodeExtSense(&ExtRequestSense, "GenericClean : ", debug_file);
2851 if(ExtRequestSense.CLN) {
2857 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"Got error from RequestSense\n");
2859 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### STOP GenericClean (%d)\n",ret);
2867 extern OpenFiles_T *pDev;
2869 RequestSense_T *pRequestSense;
2874 (void)Device; /* Quiet unused parameter warning */
2875 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### START SCSI_LogSenseClean\n");
2876 if (pDev[INDEX_TAPECTL].SCSI == 0)
2878 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"SCSILogSenseClean : can't send SCSI commands\n");
2879 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"##### STOP SCSI_LogSenseClean\n");
2884 if (NULL == (buffer = alloc(size))){
2885 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"SCSI_LogSenseClean : can't alloc buffer\n");
2886 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"##### STOP SCSI_LogSenseClean\n");
2889 if (NULL == (pRequestSense = alloc(SIZEOF(RequestSense_T)))){
2890 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"SCSI_LogSenseClean : can't alloc memory\n");
2891 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"##### STOP SCSI_LogSenseClean\n");
2895 memset(buffer, 0, size);
2896 CDB[0] = SC_COM_LOG_SENSE;
2898 CDB[2] = (u_char)(0x40 | 0x33);/* 0x40 for current values 0x33 Head Cleaning Page*/
2903 MSB2(&CDB[7], size);
2906 if (SCSI_Run(INDEX_TAPECTL, Input, CDB, 10,
2910 SIZEOF(RequestSense_T)) != 0)
2912 DecodeSense(pRequestSense, "SCSI_LogSenseClean : ",debug_file);
2913 free(pRequestSense);
2915 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"##### STOP SCSI_LogSenseClean (0) Page could not be read.\n");
2919 if (1==(0x1 & buffer[8])){ /* Bit 0 of the 4th byte in the Clean Head Log Parameter, which are the bytes */
2920 /* 4 to 8 on the Log Sense Page 0x33 */
2925 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### STOP SCSI_LogSenseClean (%d)\n",ret);
2926 free(pRequestSense);
2936 RequestSense_T *pRequestSense;
2940 DebugPrint(DEBUG_INFO, SECTION_ELEMENT, "##### START GenericResetStatus\n");
2942 pRequestSense = alloc(SIZEOF(RequestSense_T));
2946 CDB[0] = SC_COM_IES; /* */
2954 ret = SCSI_Run(DeviceFD, Input, CDB, 6,
2957 SIZEOF(RequestSense_T));
2961 /* fprintf(stderr, "%s: Request Sense[Inquiry]: %02X", */
2962 /* "chs", ((u_char *) &pRequestSense)[0]); */
2963 /* for (i = 1; i < SIZEOF(RequestSense_T); i++) */
2964 /* fprintf(stderr, " %02X", ((u_char *) &pRequestSense)[i]); */
2965 /* fprintf(stderr, "\n"); */
2966 free(pRequestSense);
2972 switch (SenseHandler(DeviceFD, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
2975 free(pRequestSense);
2979 free(pRequestSense);
2984 if (retry < MAX_RETRIES )
2986 DebugPrint(DEBUG_INFO, SECTION_ELEMENT, "GenericResetStatus : retry %d\n", retry);
2989 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "GenericResetStatus : return (-1)\n");
2990 free(pRequestSense);
2996 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "GenericResetStatus : (default) return (-1)\n");
2997 free(pRequestSense);
3005 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "##### STOP GenericResetStatus (%d)\n",ret);
3006 free(pRequestSense);
3010 /* GenericSenseHandler
3011 * Handles the conditions/sense wich is returned by an SCSI command
3012 * pwork is an pointer to the structure OpenFiles_T, which is filled with information
3013 * about the device to which we talk. Information are for example
3014 * The vendor, the ident, which fd, etc. This strucure is filled when we open the
3016 * flag tells how to handle the information passed in the buffer,
3017 * 0 -> Sense Key available
3018 * 1 -> No Sense key available
3019 * buffer is a pointer to the data from the request sense result.
3022 * Limit recursion, may run in an infinite loop
3025 GenericSenseHandler(
3029 u_char AdditionalSenseCode,
3030 u_char AdditionalSenseCodeQualifier,
3031 RequestSense_T * pRequestSense)
3033 extern OpenFiles_T *pDev;
3037 dbprintf(("##### START GenericSenseHandler\n"));
3039 DecodeSense(pRequestSense, "GenericSenseHandler : ", debug_file);
3041 ret = Sense2Action(pDev[ip].ident,
3042 pDev[ip].inquiry->type,
3044 AdditionalSenseCode,
3045 AdditionalSenseCodeQualifier,
3048 dbprintf(("##### STOP GenericSenseHandler\n"));
3053 * Do the move. We don't address the MTE element (the gripper)
3054 * here. We assume that the library use the right MTE.
3055 * The difference to GenericMove is that we do an align element
3060 * != 0 -> error either from the SCSI command or from
3061 * the element handling
3070 extern OpenFiles_T *pDev;
3071 ElementInfo_T *pfrom;
3076 int SDX_MTE = 0; /* This are parameters passed */
3077 int SDX_STE = -1; /* to */
3078 int SDX_DTE = -1; /* AlignElements */
3080 DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### START SDXMove\n");
3082 DebugPrint(DEBUG_INFO, SECTION_MOVE,"%-20s : from = %d, to = %d\n", "SDXMove", from, to);
3085 if ((pfrom = LookupElement(from)) == NULL)
3087 DebugPrint(DEBUG_INFO, SECTION_MOVE,"SDXMove : ElementInfo for %d not found\n", from);
3088 DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP SDXMove\n");
3093 if ((pto = LookupElement(to)) == NULL)
3095 DebugPrint(DEBUG_INFO, SECTION_MOVE,"SDXMove : ElementInfo for %d not found\n", to);
3096 DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP SDXMove\n");
3101 if (pfrom->status == 'E')
3103 DebugPrint(DEBUG_INFO, SECTION_MOVE,"SDXMove : from %d is empty\n", from);
3104 DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP SDXMove\n");
3109 if (pto->status == 'F')
3111 switch (pto->status)
3116 DebugPrint(DEBUG_INFO, SECTION_MOVE,"SDXMove : Destination Element %d Type %d is full\n",
3117 pto->address, pto->type);
3118 to = find_empty(DeviceFD, 0, 0);
3121 DebugPrint(DEBUG_ERROR, SECTION_MOVE,"SDXMove : no empty slot found for unload\n");
3125 DebugPrint(DEBUG_INFO, SECTION_MOVE,"SDXMove : Unload to %d\n", to);
3126 if ((pto = LookupElement(to)) == NULL)
3128 DebugPrint(DEBUG_INFO, SECTION_MOVE, "SDXMove : ElementInfo for %d not found\n", to);
3129 DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP SDXMove\n");
3141 moveok = CheckMove(pfrom, pto);
3146 SDX_DTE = pto->address;
3149 SDX_STE = pto->address;
3152 SDX_STE = pto->address;
3156 switch (pfrom->type)
3159 SDX_DTE = pfrom->address;
3162 SDX_STE = pfrom->address;
3165 SDX_STE = pfrom->address;
3169 if (SDX_DTE >= 0 && SDX_STE >= 0)
3171 ret = SCSI_AlignElements(DeviceFD, SDX_MTE, SDX_DTE, SDX_STE);
3172 DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### SCSI_AlignElemnts ret = %d\n",ret);
3175 DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP SDXMove\n");
3180 DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### Error setting STE/DTE %d/%d\n", SDX_STE, SDX_DTE);
3181 DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP SDXMove\n");
3187 * If from is a tape we must check if it is loaded
3188 * and if yes we have to eject it
3190 if (pfrom->type == TAPETYPE)
3192 tapestat = Tape_Status(INDEX_TAPE);
3193 if ( tapestat & TAPE_ONLINE)
3195 if (pDev[INDEX_TAPECTL].SCSI == 1)
3197 ret = eject_tape(pDev[INDEX_TAPECTL].dev,1);
3199 ret = eject_tape(pDev[INDEX_TAPE].dev,2);
3204 if ((ret == 0) && moveok)
3206 ret = SCSI_Move(DeviceFD, 0, from, to);
3208 DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP SDXMove\n");
3212 DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP SDXMove\n");
3217 * Do the move. We don't address the MTE element (the gripper)
3218 * here. We assume that the library use the right MTE
3222 * != 0 -> error either from the SCSI command or from
3223 * the element handling
3232 ElementInfo_T *pfrom;
3236 DebugPrint(DEBUG_INFO, SECTION_MOVE, "##### START GenericMove\n");
3238 DebugPrint(DEBUG_INFO, SECTION_MOVE, "%-20s : from = %d, to = %d\n", "GenericMove", from, to);
3241 if ((pfrom = LookupElement(from)) == NULL)
3243 DebugPrint(DEBUG_INFO, SECTION_MOVE, "GenericMove : ElementInfo for %d not found\n", from);
3244 DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP GenericMove\n");
3249 if ((pto = LookupElement(to)) == NULL)
3251 DebugPrint(DEBUG_INFO, SECTION_MOVE, "GenericMove : ElementInfo for %d not found\n", to);
3252 DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP GenericMove\n");
3257 if (pfrom->status == 'E')
3259 DebugPrint(DEBUG_INFO, SECTION_MOVE, "GenericMove : from %d is empty\n", from);
3260 DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP GenericMove\n");
3265 if (pto->status == 'F')
3267 DebugPrint(DEBUG_INFO, SECTION_MOVE, "GenericMove : Destination Element %d Type %d is full\n",
3268 pto->address, pto->type);
3269 to = find_empty(DeviceFD, 0, 0);
3272 DebugPrint(DEBUG_ERROR, SECTION_MOVE, "GenericMove : no empty slot found\n");
3276 DebugPrint(DEBUG_INFO, SECTION_MOVE, "GenericMove : Unload to %d\n", to);
3277 if ((pto = LookupElement(to)) == NULL)
3279 DebugPrint(DEBUG_ERROR, SECTION_MOVE, " Ups should not happen\n");
3280 DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP GenericMove\n");
3286 if (CheckMove(pfrom, pto))
3288 ret = SCSI_Move(DeviceFD, 0, from, to);
3291 DebugPrint(DEBUG_INFO, SECTION_MOVE, "GenericMove : SCSI_Move return (%d)\n", ret);
3292 DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP GenericMove\n");
3297 * Check if a move based on the information we got from the Mode Sense command
3306 ElementInfo_T * from,
3311 DebugPrint(DEBUG_INFO, SECTION_MOVE, "##### START CheckMove\n");
3312 if (pDeviceCapabilitiesPage != NULL )
3314 DebugPrint(DEBUG_INFO, SECTION_MOVE, "CheckMove : checking if move from %d to %d is legal\n", from->address, to->address);
3318 DebugPrint(DEBUG_INFO, SECTION_MOVE, "CheckMove : MT2");
3322 if (pDeviceCapabilitiesPage->MT2MT == 1)
3324 DebugPrint(DEBUG_INFO, SECTION_MOVE, "MT\n");
3329 if (pDeviceCapabilitiesPage->MT2ST == 1)
3331 DebugPrint(DEBUG_INFO, SECTION_MOVE, "ST\n");
3336 if (pDeviceCapabilitiesPage->MT2IE == 1)
3338 DebugPrint(DEBUG_INFO, SECTION_MOVE, "IE\n");
3343 if (pDeviceCapabilitiesPage->MT2DT == 1)
3345 DebugPrint(DEBUG_INFO, SECTION_MOVE, "DT\n");
3354 DebugPrint(DEBUG_INFO, SECTION_MOVE, "CheckMove : ST2");
3358 if (pDeviceCapabilitiesPage->ST2MT == 1)
3360 DebugPrint(DEBUG_INFO, SECTION_MOVE, "MT\n");
3365 if (pDeviceCapabilitiesPage->ST2ST == 1)
3367 DebugPrint(DEBUG_INFO, SECTION_MOVE, "ST\n");
3372 if (pDeviceCapabilitiesPage->ST2IE == 1)
3374 DebugPrint(DEBUG_INFO, SECTION_MOVE, "IE\n");
3379 if (pDeviceCapabilitiesPage->ST2DT == 1)
3381 DebugPrint(DEBUG_INFO, SECTION_MOVE, "DT\n");
3390 DebugPrint(DEBUG_INFO, SECTION_MOVE, "CheckMove : IE2");
3394 if (pDeviceCapabilitiesPage->IE2MT == 1)
3396 DebugPrint(DEBUG_INFO, SECTION_MOVE, "MT\n");
3401 if (pDeviceCapabilitiesPage->IE2ST == 1)
3403 DebugPrint(DEBUG_INFO, SECTION_MOVE, "ST\n");
3408 if (pDeviceCapabilitiesPage->IE2IE == 1)
3410 DebugPrint(DEBUG_INFO, SECTION_MOVE, "IE\n");
3415 if (pDeviceCapabilitiesPage->IE2DT == 1)
3417 DebugPrint(DEBUG_INFO, SECTION_MOVE, "DT\n");
3426 DebugPrint(DEBUG_INFO, SECTION_MOVE, "CheckMove : DT2");
3430 if (pDeviceCapabilitiesPage->DT2MT == 1)
3432 DebugPrint(DEBUG_INFO, SECTION_MOVE, "MT\n");
3437 if (pDeviceCapabilitiesPage->DT2ST == 1)
3439 DebugPrint(DEBUG_INFO, SECTION_MOVE, "ST\n");
3444 if (pDeviceCapabilitiesPage->DT2IE == 1)
3446 DebugPrint(DEBUG_INFO, SECTION_MOVE, "IE\n");
3451 if (pDeviceCapabilitiesPage->DT2DT == 1)
3453 DebugPrint(DEBUG_INFO, SECTION_MOVE, "DT\n");
3465 DebugPrint(DEBUG_INFO, SECTION_MOVE, "CheckMove : pDeviceCapabilitiesPage == NULL");
3467 ChgExit("CheckMove", "DeviceCapabilitiesPage == NULL", FATAL);
3472 DebugPrint(DEBUG_INFO, SECTION_MOVE, "###### STOP CheckMove\n");
3484 extern OpenFiles_T *pDev;
3486 dbprintf(("##### START GetCurrentSlot\n"));
3488 (void)fd; /* Quiet unused parameter warning */
3490 if (pDev[0].SCSI == 0)
3492 dbprintf(("GetCurrentSlot : can't send SCSI commands\n"));
3497 if (ElementStatusValid == 0)
3499 if (pDev[0].functions->function_status(0, 1) != 0)
3506 /* If the from address is the as the same as the tape address skip it */
3507 if (pDTE[drive].from >= 0 && pDTE[drive].from != pDTE[drive].address)
3509 for (x = 0; x < STE;x++)
3511 if (pSTE[x].address == pDTE[drive].from)
3519 for (x = 0; x < STE;x++)
3521 if (pSTE[x].status == 'E') {
3527 /* Ups nothing loaded */
3534 * Reworked function to get the ElementStatus
3535 * This function will first call the GetElementStatus
3536 * function to get the Element status,
3537 * and than check if there are abnormal conditions.
3539 * If there are error conditions try to fix them
3543 GenericElementStatus(
3552 extern OpenFiles_T *pDev;
3554 int error = 0; /* If set do an INIT ELEMENT STATUS */
3555 size_t x; /* The standard loop counter :-) */
3556 int retry = 2; /* Redo it if an error has been reset */
3558 (void)InitStatus; /* Quiet unused parameter warning */
3560 DebugPrint(DEBUG_INFO, SECTION_ELEMENT, "##### START GenericElementStatus\n");
3562 if (pEAAPage == NULL)
3565 * If this pointer is null
3566 * then try to read the parameter with MODE SENSE
3569 if (pModePage == NULL && LibModeSenseValid == 0)
3571 pModePage = alloc(0xff);
3573 if (SCSI_ModeSense(DeviceFD, pModePage, 0xff, 0x8, 0x3f) == 0)
3575 LibModeSenseValid = 1;
3576 DecodeModeSense(pModePage, 0, "GenericElementStatus :", 0, debug_file);
3578 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"GetElementStatus : failed SCSI_ModeSense\n");
3579 LibModeSenseValid = -1;
3584 while ((GetElementStatus(DeviceFD) == 0) && (retry-- > 0))
3586 for (x = 0; x < MTE; x++)
3588 if (pMTE[x].ASC > 0)
3590 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pMTE[x].ASC, pMTE[x].ASCQ, (RequestSense_T *)&pMTE[x]))
3597 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "GenericElementStatus : Abort on MTE\n");
3604 for (x = 0; x < IEE; x++)
3606 if (pIEE[x].ASC > 0)
3608 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pIEE[x].ASC, pIEE[x].ASCQ, (RequestSense_T *)&pIEE[x]))
3615 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "GenericElementStatus : Abort on IEE\n");
3623 for (x = 0; x < STE; x++)
3625 if (pSTE[x].ASC > 0)
3627 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pSTE[x].ASC, pSTE[x].ASCQ, (RequestSense_T *)&pSTE[x]))
3634 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "GenericElementStatus : Abort on IES\n");
3641 for (x = 0; x < DTE; x++)
3643 if (pDTE[x].ASC > 0)
3645 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pDTE[x].ASC, pDTE[x].ASCQ, (RequestSense_T *)&pDTE[x]))
3652 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "GenericElementStatus : Abort on DTE\n");
3660 * OK, we have an error, do an INIT ELMENT
3661 * For the tape if not handled by the robot we have
3662 * to do some extra checks
3666 if (GenericResetStatus(DeviceFD) != 0)
3668 ElementStatusValid = 0;
3669 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "GenericElementStatus : Can't init status STEError(%d) MTEError(%d) DTEError(%d) IEEError(%d)\n", STEError, MTEError, DTEError, IEEError);
3680 * If the status is empty to an move from tape to tape
3681 * This is if the tape is ejected, but not unloaded
3683 if (pDTE[0].status == 'E')
3685 DebugPrint(DEBUG_INFO, SECTION_ELEMENT, "GenericElementStatus : try to move tape to tape drive\n");
3686 pDev[DeviceFD].functions->function_move(DeviceFD, pDTE[0].address, pDTE[0].address);
3689 /* Done GetElementStatus */
3694 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "GenericElementStatus : Can't init status (after loop)\n");
3699 ElementStatusValid = 1;
3700 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "#### STOP GenericElementStatus\n");
3706 * This is for the ADIC changer, it seems that they have an diferent
3707 * offset in the mode sense data before the first mode page (+12)
3710 DLT448ElementStatus(
3716 extern OpenFiles_T *pDev;
3718 int error = 0; /* If set do an INIT ELEMENT STATUS */
3719 size_t x; /* The standard loop counter :-) */
3720 int loop = 2; /* Redo it if an error has been reset */
3722 (void)InitStatus; /* Quiet unused parameter warning */
3724 DebugPrint(DEBUG_INFO, SECTION_ELEMENT, "##### START DLT448ElementStatus\n");
3726 if (pEAAPage == NULL)
3729 * If this pointer is null
3730 * then try to read the parameter with MODE SENSE
3733 if (pModePage == NULL && LibModeSenseValid == 0)
3735 pModePage = alloc(0xff);
3737 if (SCSI_ModeSense(DeviceFD, pModePage, 0xff, 0x8, 0x3f) == 0)
3739 LibModeSenseValid = 1;
3740 DecodeModeSense(pModePage, 12, "DLT448ElementStatus :", 0, debug_file);
3742 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"DLT448ElementStatus : failed SCSI_ModeSense\n");
3743 LibModeSenseValid = -1;
3748 while (GetElementStatus(DeviceFD) == 0 && loop-- > 0)
3750 for (x = 0; x < MTE; x++)
3752 if (pMTE[x].ASC > 0)
3754 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pMTE[x].ASC, pMTE[x].ASCQ, (RequestSense_T *)&pMTE[x]))
3760 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "DLT448ElementStatus : Abort on MTE\n");
3767 for (x = 0; x < IEE; x++)
3769 if (pIEE[x].ASC > 0)
3771 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pIEE[x].ASC, pIEE[x].ASCQ, (RequestSense_T *)&pIEE[x]))
3777 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "DLT448ElementStatus : Abort on IEE\n");
3785 for (x = 0; x < STE; x++)
3788 * Needed for the hack to guess the tape status if an error
3789 * for the tape is pending
3791 if (pSTE[x].ASC > 0)
3793 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pSTE[x].ASC, pSTE[x].ASCQ, (RequestSense_T *)&pSTE[x]))
3799 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "DLT448ElementStatus : Abort on IES\n");
3806 for (x = 0; x < DTE; x++)
3808 if (pDTE[x].ASC > 0)
3810 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pDTE[x].ASC, pDTE[x].ASCQ, (RequestSense_T *)&pDTE[x]))
3817 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "DLT448ElementStatus : Abort on DTE\n");
3825 * OK, we have an error, do an INIT ELMENT
3826 * For the tape if not handled by the robot we have
3827 * to do some extra checks
3831 if (GenericResetStatus(DeviceFD) != 0)
3833 ElementStatusValid = 0;
3834 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "DLT448ElementStatus : Can't init status\n");
3845 * If the status is empty to an move from tape to tape
3846 * This is if the tape is ejected, but not unloaded
3848 if (pDTE[0].status == 'E')
3850 DebugPrint(DEBUG_INFO, SECTION_ELEMENT, "DLT448ElementStatus : try to move tape to tape drive\n");
3851 pDev[DeviceFD].functions->function_move(DeviceFD, pDTE[0].address, pDTE[0].address);
3854 /* Done GetElementStatus */
3859 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "DLT448ElementStatus : Can't init status (after loop)\n");
3864 ElementStatusValid = 1;
3865 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "#### STOP DLT448ElementStatus\n");
3871 * Much the same like GenericElementStatus but
3872 * it seemes that for the STE Elements ASC/ASCQ is not set
3873 * on an error, only the except bit is set
3880 int error = 0; /* If set do an INIT ELEMENT STATUS */
3881 size_t x; /* The standard loop counter :-) */
3882 int loop = 2; /* Redo it if an error has been reset */
3884 (void)InitStatus; /* Quiet unused parameter warning */
3886 DebugPrint(DEBUG_INFO, SECTION_ELEMENT, "##### START SDXElementStatus\n");
3888 if (pEAAPage == NULL)
3891 * If this pointer is null
3892 * then try to read the parameter with MODE SENSE
3895 if (pModePage == NULL && LibModeSenseValid == 0)
3897 pModePage = alloc(0xff);
3899 if (SCSI_ModeSense(DeviceFD, pModePage, 0xff, 0x8, 0x3f) == 0)
3901 LibModeSenseValid = 1;
3902 DecodeModeSense(pModePage, 0, "SDXElementStatus :", 0, debug_file);
3904 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"SDXElementStatus : failed SCSI_ModeSense\n");
3905 LibModeSenseValid = -1;
3910 while (GetElementStatus(DeviceFD) == 0 && loop--)
3913 for (x = 0; x < MTE; x++)
3915 if (pMTE[x].ASC > 0)
3917 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pMTE[x].ASC, pMTE[x].ASCQ, (RequestSense_T *)&pMTE[x]))
3923 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "SDXElementStatus : Abort on MTE\n");
3930 for (x = 0; x < IEE; x++)
3932 if (pIEE[x].ASC > 0)
3934 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pIEE[x].ASC, pIEE[x].ASCQ, (RequestSense_T *)&pIEE[x]))
3940 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "SDXElementStatus : Abort on IEE\n");
3948 for (x = 0; x < STE; x++)
3950 if (pSTE[x].ASC > 0)
3952 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pSTE[x].ASC, pSTE[x].ASCQ, (RequestSense_T *)&pSTE[x]))
3958 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "SDXElementStatus : Abort on IES\n");
3965 for (x = 0; x < DTE; x++)
3967 if (pDTE[x].ASC > 0)
3969 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pDTE[x].ASC, pDTE[x].ASCQ, (RequestSense_T *)&pDTE[x]))
3977 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "SDXElementStatus : Abort on DTE\n");
3985 * OK, we have an error, do an INIT ELMENT
3986 * For the tape if not handled by the robot we have
3987 * to do some extra checks
3991 if (GenericResetStatus(DeviceFD) != 0)
3993 ElementStatusValid = 0;
3994 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "SDXElementStatus : Can't init status\n");
4000 /* Done GetElementStatus */
4005 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "SDXElementStatus : Can't init status\n");
4010 ElementStatusValid = 1;
4012 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "#### STOP SDXElementStatus\n");
4018 * Reads the element information from the library. There are 2 ways to do this.
4019 * Either check the result from the mode sense page to see which types of elements
4020 * are available (STE/DTE/MTE....), or do an read element status with the option give
4021 * me all and than check what is available.
4023 * Only do the read, error handling is done by the calling function
4035 u_char *DataBuffer = NULL;
4036 size_t DataBufferLength;
4037 ElementStatusData_T *ElementStatusData;
4038 ElementStatusPage_T *ElementStatusPage;
4039 MediumTransportElementDescriptor_T *MediumTransportElementDescriptor;
4040 StorageElementDescriptor_T *StorageElementDescriptor;
4041 DataTransferElementDescriptor_T *DataTransferElementDescriptor;
4042 ImportExportElementDescriptor_T *ImportExportElementDescriptor;
4045 size_t length; /* Length of an Element */
4046 size_t NoOfElements;
4048 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"##### START GetElementStatus\n");
4050 barcode = BarCode(DeviceFD);
4053 * If the MODE_SENSE was successfull we use this Information to read the Elelement Info
4055 if (pEAAPage != NULL)
4057 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Reading Element Status with the info from mode sense\n");
4058 /* First the Medim Transport*/
4059 if (V2(pEAAPage->NoMediumTransportElements) > 0)
4061 MTE = V2(pEAAPage->NoMediumTransportElements) ;
4062 pMTE = alloc(SIZEOF(ElementInfo_T) * MTE);
4063 memset(pMTE, 0, SIZEOF(ElementInfo_T) * MTE);
4065 if (SCSI_ReadElementStatus(DeviceFD,
4069 V2(pEAAPage->MediumTransportElementAddress),
4071 SIZEOF(MediumTransportElementDescriptor_T),
4074 ChgExit("genericElementStatus","Can't read MTE status", FATAL);
4077 // ElementStatusData = (ElementStatusData_T *)DataBuffer;
4078 offset = SIZEOF(ElementStatusData_T);
4080 ElementStatusPage = (ElementStatusPage_T *)&DataBuffer[offset];
4081 offset = offset + SIZEOF(ElementStatusPage_T);
4082 length = V2(ElementStatusPage->length);
4084 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"MTE Length %d(%d)\n", length,
4085 SIZEOF(MediumTransportElementDescriptor_T));
4087 for (x = 0; x < MTE; x++)
4089 MediumTransportElementDescriptor = (MediumTransportElementDescriptor_T *)&DataBuffer[offset];
4091 if (ElementStatusPage->pvoltag == 1)
4093 strncpy((char *)pMTE[x].VolTag,
4094 (char *)MediumTransportElementDescriptor->pvoltag,
4096 TerminateString(pMTE[x].VolTag, TAG_SIZE+1);
4099 pMTE[x].type = ElementStatusPage->type;
4100 pMTE[x].address = V2(MediumTransportElementDescriptor->address);
4101 pMTE[x].except = MediumTransportElementDescriptor->except;
4102 pMTE[x].full = MediumTransportElementDescriptor->full;
4103 if (MediumTransportElementDescriptor->full > 0)
4105 pMTE[x].status = 'F';
4107 pMTE[x].status = 'E';
4112 pMTE[x].ASC = MediumTransportElementDescriptor->asc;
4114 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASC MTE\n");
4119 pMTE[x].ASCQ = MediumTransportElementDescriptor->ascq;
4121 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASCQ MTE\n");
4126 if (MediumTransportElementDescriptor->svalid == 1)
4128 pMTE[x].from = V2(MediumTransportElementDescriptor->source);
4133 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip source MTE\n");
4135 offset = offset + length;
4143 if ( V2(pEAAPage->NoStorageElements) > 0)
4146 STE = V2(pEAAPage->NoStorageElements);
4147 pSTE = alloc(SIZEOF(ElementInfo_T) * STE);
4148 memset(pSTE, 0, SIZEOF(ElementInfo_T) * STE);
4150 if (SCSI_ReadElementStatus(DeviceFD,
4154 V2(pEAAPage->FirstStorageElementAddress),
4156 SIZEOF(StorageElementDescriptor_T),
4159 ChgExit("GetElementStatus", "Can't read STE status", FATAL);
4162 assert(DataBuffer != NULL);
4164 // ElementStatusData = (ElementStatusData_T *)DataBuffer;
4165 offset = SIZEOF(ElementStatusData_T);
4167 ElementStatusPage = (ElementStatusPage_T *)&DataBuffer[offset];
4168 offset = offset + SIZEOF(ElementStatusPage_T);
4169 length = V2(ElementStatusPage->length);
4170 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"STE Length %d\n",length);
4172 for (x = 0; x < STE; x++)
4174 StorageElementDescriptor = (StorageElementDescriptor_T *)&DataBuffer[offset];
4175 if (ElementStatusPage->pvoltag == 1)
4177 strncpy(pSTE[x].VolTag,
4178 (char *)StorageElementDescriptor->pvoltag,
4180 TerminateString(pSTE[x].VolTag, TAG_SIZE+1);
4184 pSTE[x].type = ElementStatusPage->type;
4185 pSTE[x].address = V2(StorageElementDescriptor->address);
4186 pSTE[x].except = StorageElementDescriptor->except;
4187 pSTE[x].full = StorageElementDescriptor->full;
4188 if (StorageElementDescriptor->full > 0)
4190 pSTE[x].status = 'F';
4192 pSTE[x].status = 'E';
4197 pSTE[x].ASC = StorageElementDescriptor->asc;
4199 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASC STE\n");
4204 pSTE[x].ASCQ = StorageElementDescriptor->ascq;
4206 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASCQ STE\n");
4211 if (StorageElementDescriptor->svalid == 1)
4213 pSTE[x].from = V2(StorageElementDescriptor->source);
4218 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip source STE\n");
4221 offset = offset + length;
4227 * Import/Export Elements
4229 if ( V2(pEAAPage->NoImportExportElements) > 0)
4232 IEE = V2(pEAAPage->NoImportExportElements);
4233 pIEE = alloc(SIZEOF(ElementInfo_T) * IEE);
4234 memset(pIEE, 0, SIZEOF(ElementInfo_T) * IEE);
4236 if (SCSI_ReadElementStatus(DeviceFD,
4240 V2(pEAAPage->FirstImportExportElementAddress),
4242 SIZEOF(ImportExportElementDescriptor_T),
4245 ChgExit("GetElementStatus", "Can't read IEE status", FATAL);
4248 assert(DataBuffer != NULL);
4250 // ElementStatusData = (ElementStatusData_T *)DataBuffer;
4251 offset = SIZEOF(ElementStatusData_T);
4253 ElementStatusPage = (ElementStatusPage_T *)&DataBuffer[offset];
4254 offset = offset + SIZEOF(ElementStatusPage_T);
4255 length = V2(ElementStatusPage->length);
4256 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"IEE Length %d\n",length);
4258 for (x = 0; x < IEE; x++)
4260 ImportExportElementDescriptor = (ImportExportElementDescriptor_T *)&DataBuffer[offset];
4261 if (ElementStatusPage->pvoltag == 1)
4263 strncpy(pIEE[x].VolTag,
4264 (char *)ImportExportElementDescriptor->pvoltag,
4266 TerminateString(pIEE[x].VolTag, TAG_SIZE+1);
4268 pIEE[x].type = ElementStatusPage->type;
4269 pIEE[x].address = V2(ImportExportElementDescriptor->address);
4270 pIEE[x].except = ImportExportElementDescriptor->except;
4271 pIEE[x].full = ImportExportElementDescriptor->full;
4272 if (ImportExportElementDescriptor->full > 0)
4274 pIEE[x].status = 'F';
4276 pIEE[x].status = 'E';
4281 pIEE[x].ASC = ImportExportElementDescriptor->asc;
4283 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASC IEE\n");
4288 pIEE[x].ASCQ = ImportExportElementDescriptor->ascq;
4290 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASCQ IEE\n");
4295 if (ImportExportElementDescriptor->svalid == 1)
4297 pIEE[x].from = V2(ImportExportElementDescriptor->source);
4302 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip source IEE\n");
4305 offset = offset + length;
4311 * Data Transfer Elements
4313 if (V2(pEAAPage->NoDataTransferElements) >0)
4316 DTE = V2(pEAAPage->NoDataTransferElements) ;
4317 pDTE = alloc(SIZEOF(ElementInfo_T) * DTE);
4318 memset(pDTE, 0, SIZEOF(ElementInfo_T) * DTE);
4320 if (SCSI_ReadElementStatus(DeviceFD,
4324 V2(pEAAPage->FirstDataTransferElementAddress),
4326 SIZEOF(DataTransferElementDescriptor_T),
4329 ChgExit("GenericElementStatus", "Can't read DTE status", FATAL);
4332 assert(DataBuffer != NULL);
4334 // ElementStatusData = (ElementStatusData_T *)DataBuffer;
4335 offset = SIZEOF(ElementStatusData_T);
4337 ElementStatusPage = (ElementStatusPage_T *)&DataBuffer[offset];
4338 offset = offset + SIZEOF(ElementStatusPage_T);
4339 length = V2(ElementStatusPage->length);
4340 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"DTE Length %d\n",length);
4342 for (x = 0; x < DTE; x++)
4344 DataTransferElementDescriptor = (DataTransferElementDescriptor_T *)&DataBuffer[offset];
4345 if (ElementStatusPage->pvoltag == 1)
4347 strncpy(pDTE[x].VolTag,
4348 (char *)DataTransferElementDescriptor->pvoltag,
4350 TerminateString(pDTE[x].VolTag, TAG_SIZE+1);
4352 pDTE[x].type = ElementStatusPage->type;
4353 pDTE[x].address = V2(DataTransferElementDescriptor->address);
4354 pDTE[x].except = DataTransferElementDescriptor->except;
4355 pDTE[x].scsi = DataTransferElementDescriptor->scsi;
4356 pDTE[x].full = DataTransferElementDescriptor->full;
4357 if (DataTransferElementDescriptor->full > 0)
4359 pDTE[x].status = 'F';
4361 pDTE[x].status = 'E';
4366 pDTE[x].ASC = DataTransferElementDescriptor->asc;
4368 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASC DTE\n");
4373 pDTE[x].ASCQ = DataTransferElementDescriptor->ascq;
4375 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASCQ DTE\n");
4380 if (DataTransferElementDescriptor->svalid == 1)
4382 pDTE[x].from = V2(DataTransferElementDescriptor->source);
4387 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip source STE\n");
4390 offset = offset + length;
4397 * And now the old way, when we get here the read mode sense page has failed ...
4399 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Reading Element Status the old way .... (max 255 elements)\n");
4400 if (SCSI_ReadElementStatus(DeviceFD,
4409 ChgExit("GenericElementStatus","Can't get ElementStatus", FATAL);
4412 assert(DataBuffer != NULL);
4414 ElementStatusData = (ElementStatusData_T *)DataBuffer;
4415 DataBufferLength = V3(ElementStatusData->count);
4417 offset = SIZEOF(ElementStatusData_T);
4419 while (offset < DataBufferLength)
4421 ElementStatusPage = (ElementStatusPage_T *)&DataBuffer[offset];
4422 NoOfElements = V3(ElementStatusPage->count) / V2(ElementStatusPage->length);
4423 offset = offset + SIZEOF(ElementStatusPage_T);
4424 length = V2(ElementStatusPage->length);
4426 switch (ElementStatusPage->type)
4431 pMTE = alloc(SIZEOF(ElementInfo_T) * MTE);
4432 memset(pMTE, 0, SIZEOF(ElementInfo_T) * MTE);
4434 for (x = 0; x < NoOfElements; x++)
4436 MediumTransportElementDescriptor = (MediumTransportElementDescriptor_T *)&DataBuffer[offset];
4437 if (ElementStatusPage->pvoltag == 1)
4439 strncpy(pMTE[x].VolTag,
4440 (char *)MediumTransportElementDescriptor->pvoltag,
4442 TerminateString(pMTE[x].VolTag, TAG_SIZE+1);
4444 pMTE[x].type = ElementStatusPage->type;
4445 pMTE[x].address = V2(MediumTransportElementDescriptor->address);
4446 pMTE[x].except = MediumTransportElementDescriptor->except;
4447 pMTE[x].full = MediumTransportElementDescriptor->full;
4448 if (MediumTransportElementDescriptor->full > 0)
4450 pMTE[x].status = 'F';
4452 pMTE[x].status = 'E';
4457 pMTE[x].ASC = MediumTransportElementDescriptor->asc;
4459 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASC MTE\n");
4464 pMTE[x].ASCQ = MediumTransportElementDescriptor->ascq;
4466 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASCQ MTE\n");
4471 if (MediumTransportElementDescriptor->svalid == 1)
4473 pMTE[x].from = V2(MediumTransportElementDescriptor->source);
4478 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip source MTE\n");
4481 offset = offset + length;
4487 pSTE = alloc(SIZEOF(ElementInfo_T) * STE);
4488 memset(pSTE, 0, SIZEOF(ElementInfo_T) * STE);
4490 for (x = 0; x < NoOfElements; x++)
4492 StorageElementDescriptor = (StorageElementDescriptor_T *)&DataBuffer[offset];
4493 if (ElementStatusPage->pvoltag == 1)
4495 strncpy(pSTE[x].VolTag,
4496 (char *)StorageElementDescriptor->pvoltag,
4498 TerminateString(pSTE[x].VolTag, TAG_SIZE+1);
4501 pSTE[x].type = ElementStatusPage->type;
4502 pSTE[x].address = V2(StorageElementDescriptor->address);
4503 pSTE[x].except = StorageElementDescriptor->except;
4504 pSTE[x].full = StorageElementDescriptor->full;
4505 if (StorageElementDescriptor->full > 0)
4507 pSTE[x].status = 'F';
4509 pSTE[x].status = 'E';
4514 pSTE[x].ASC = StorageElementDescriptor->asc;
4516 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASC STE\n");
4521 pSTE[x].ASCQ = StorageElementDescriptor->ascq;
4523 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASCQ STE\n");
4528 if (StorageElementDescriptor->svalid == 1)
4530 pSTE[x].from = V2(StorageElementDescriptor->source);
4535 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip source STE\n");
4538 offset = offset + length;
4544 pIEE = alloc(SIZEOF(ElementInfo_T) * IEE);
4545 memset(pIEE, 0, SIZEOF(ElementInfo_T) * IEE);
4547 for (x = 0; x < NoOfElements; x++)
4549 ImportExportElementDescriptor = (ImportExportElementDescriptor_T *)&DataBuffer[offset];
4550 if (ElementStatusPage->pvoltag == 1)
4552 strncpy(pIEE[x].VolTag,
4553 (char *)ImportExportElementDescriptor->pvoltag,
4555 TerminateString(pIEE[x].VolTag, TAG_SIZE+1);
4557 ImportExportElementDescriptor = (ImportExportElementDescriptor_T *)&DataBuffer[offset];
4558 pIEE[x].type = ElementStatusPage->type;
4559 pIEE[x].address = V2(ImportExportElementDescriptor->address);
4560 pIEE[x].except = ImportExportElementDescriptor->except;
4561 pIEE[x].full = ImportExportElementDescriptor->full;
4562 if (ImportExportElementDescriptor->full > 0)
4564 pIEE[x].status = 'F';
4566 pIEE[x].status = 'E';
4571 pIEE[x].ASC = ImportExportElementDescriptor->asc;
4573 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASC IEE\n");
4578 pIEE[x].ASCQ = ImportExportElementDescriptor->ascq;
4580 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASCQ IEE\n");
4585 if (ImportExportElementDescriptor->svalid == 1)
4587 pIEE[x].from = V2(ImportExportElementDescriptor->source);
4592 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip source IEE\n");
4595 offset = offset + length;
4601 pDTE = alloc(SIZEOF(ElementInfo_T) * DTE);
4602 memset(pDTE, 0, SIZEOF(ElementInfo_T) * DTE);
4604 for (x = 0; x < NoOfElements; x++)
4606 DataTransferElementDescriptor = (DataTransferElementDescriptor_T *)&DataBuffer[offset];
4607 if (ElementStatusPage->pvoltag == 1)
4609 strncpy(pSTE[x].VolTag,
4610 (char *)DataTransferElementDescriptor->pvoltag,
4612 TerminateString(pSTE[x].VolTag, TAG_SIZE+1);
4614 pDTE[x].type = ElementStatusPage->type;
4615 pDTE[x].address = V2(DataTransferElementDescriptor->address);
4616 pDTE[x].except = DataTransferElementDescriptor->except;
4617 pDTE[x].scsi = DataTransferElementDescriptor->scsi;
4618 pDTE[x].full = DataTransferElementDescriptor->full;
4619 if (DataTransferElementDescriptor->full > 0)
4621 pDTE[x].status = 'F';
4623 pDTE[x].status = 'E';
4628 pDTE[x].ASC = DataTransferElementDescriptor->asc;
4630 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASC DTE\n");
4635 pDTE[x].ASCQ = DataTransferElementDescriptor->ascq;
4637 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASCQ DTE\n");
4642 if (DataTransferElementDescriptor->svalid == 1)
4644 pDTE[x].from = V2(DataTransferElementDescriptor->source);
4649 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip source STE\n");
4652 offset = offset + length;
4656 offset = offset + length;
4657 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"GetElementStatus : UnGknown Type %d\n",ElementStatusPage->type);
4664 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"\n\n\tMedia Transport Elements (robot arms) :\n");
4666 for ( x = 0; x < MTE; x++)
4667 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",
4668 pMTE[x].address, pMTE[x].status, pMTE[x].except, pMTE[x].ASC,
4669 pMTE[x].ASCQ, pMTE[x].type, pMTE[x].from, pMTE[x].VolTag);
4671 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"\n\n\tStorage Elements (Media slots) :\n");
4673 for ( x = 0; x < STE; x++)
4674 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",
4675 pSTE[x].address, pSTE[x].status, pSTE[x].except, pSTE[x].ASC,
4676 pSTE[x].ASCQ, pSTE[x].type, pSTE[x].from, pSTE[x].VolTag);
4678 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"\n\n\tData Transfer Elements (tape drives) :\n");
4680 for ( x = 0; x < DTE; x++)
4681 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",
4682 pDTE[x].address, pDTE[x].status, pDTE[x].except, pDTE[x].ASC,
4683 pDTE[x].ASCQ, pDTE[x].type, pDTE[x].from, pDTE[x].VolTag,pDTE[x].scsi);
4685 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"\n\n\tImport/Export Elements :\n");
4687 for ( x = 0; x < IEE; x++)
4688 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",
4689 pIEE[x].address, pIEE[x].status, pIEE[x].except, pIEE[x].ASC,
4690 pIEE[x].ASCQ, pIEE[x].type, pIEE[x].from, pIEE[x].VolTag);
4699 * If ClearErrorCounters is set the counters will be reset.
4700 * Used by GenericClean for example
4707 ExtendedRequestSense_T * ExtendedRequestSense,
4708 int ClearErrorCounters)
4713 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### START RequestSense\n");
4715 CDB[0] = SC_COM_REQUEST_SENSE; /* REQUEST SENSE */
4716 CDB[1] = 0; /* Logical Unit Number = 0, Reserved */
4717 CDB[2] = 0; /* Reserved */
4718 CDB[3] = 0; /* Reserved */
4719 CDB[4] = (u_char)sizeof(ExtendedRequestSense_T); /* Allocation Length */
4720 CDB[5] = (u_char)((ClearErrorCounters << 7) & 0x80); /* */
4722 memset(ExtendedRequestSense, 0, SIZEOF(ExtendedRequestSense_T));
4724 ret = SCSI_Run(DeviceFD, Input, CDB, 6,
4725 (char *) ExtendedRequestSense,
4726 SIZEOF(ExtendedRequestSense_T),
4727 (RequestSense_T *) ExtendedRequestSense,
4728 SIZEOF(ExtendedRequestSense_T));
4733 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP RequestSense (%d)\n",ret);
4740 DecodeExtSense(ExtendedRequestSense, "RequestSense : ",debug_file);
4741 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP RequestSense (%d)\n", ExtendedRequestSense->SenseKey);
4742 return(ExtendedRequestSense->SenseKey);
4746 dump_hex((u_char *)ExtendedRequestSense ,
4747 SIZEOF(ExtendedRequestSense_T),
4748 DEBUG_INFO, SECTION_SCSI);
4749 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP RequestSense (0)\n");
4755 * Lookup function pointer for device ....
4765 dbprintf(("##### START LookupElement\n"));
4769 for (x = 0; x < DTE; x++)
4771 if (pDTE[x].address == address)
4773 dbprintf(("##### STOP LookupElement (DTE)\n"));
4782 for (x = 0; x < MTE; x++)
4784 if (pMTE[x].address == address)
4786 dbprintf(("##### STOP LookupElement (MTE)\n"));
4795 for (x = 0; x < STE; x++)
4797 if (pSTE[x].address == address)
4799 dbprintf(("##### STOP LookupElement (STE)\n"));
4808 for ( x = 0; x < IEE; x++)
4810 if (pIEE[x].address == address)
4812 dbprintf(("##### STOP LookupElement (IEE)\n"));
4822 * Here comes everything what decode the log Pages
4825 * Fix the result handling from TestUnitReady
4832 extern OpenFiles_T *pDev;
4834 RequestSense_T *pRequestSense;
4835 LogSenseHeader_T *LogSenseHeader;
4836 LogParameter_T *LogParameter;
4837 struct LogPageDecode *p;
4839 extern char *tapestatfile;
4841 unsigned ParameterCode;
4850 (void)DeviceFD; /* Quiet unused parameter warning */
4852 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### START LogSense\n");
4854 if ((tapestatfile != NULL) && (pDev[INDEX_TAPECTL].SCSI == 1) &&
4855 ((StatFile = fopen(tapestatfile,"a")) != NULL))
4857 pRequestSense = alloc(SIZEOF(RequestSense_T));
4859 if (GenericRewind(INDEX_TAPECTL) < 0)
4861 DebugPrint(DEBUG_INFO, SECTION_TAPE,"LogSense : Rewind failed\n");
4862 free(pRequestSense);
4868 * Try to read the tape label
4870 if (pDev[INDEX_TAPE].inqdone == 1)
4872 if (pDev[INDEX_TAPE].devopen == 1)
4874 SCSI_CloseDevice(INDEX_TAPE);
4877 if ((chgscsi_result = (char *)tape_rdlabel(pDev[INDEX_TAPE].dev, &chgscsi_datestamp, &chgscsi_label)) == NULL)
4879 fprintf(StatFile, "==== %s ==== %s ====\n", chgscsi_datestamp, chgscsi_label);
4881 fprintf(StatFile, "%s\n", chgscsi_result);
4885 buffer = alloc(size);
4886 memset(buffer, 0, size);
4888 * Get the known log pages
4891 CDB[0] = SC_COM_LOG_SENSE;
4893 CDB[2] = 0x40; /* 0x40 for current values */
4898 MSB2(&CDB[7], size);
4901 if (SCSI_Run(INDEX_TAPECTL, Input, CDB, 10,
4905 SIZEOF(RequestSense_T)) != 0)
4907 DecodeSense(pRequestSense, "LogSense : ",debug_file);
4908 free(pRequestSense);
4915 LogSenseHeader = (LogSenseHeader_T *)buffer;
4916 nologpages = V2(LogSenseHeader->PageLength);
4917 logpages = alloc(nologpages);
4919 memcpy(logpages, buffer + SIZEOF(LogSenseHeader_T), nologpages);
4921 for (count = 0; count < (int)nologpages; count++) {
4922 if (logpages[count] != 0 ) {
4923 memset(buffer, 0, size);
4924 CDB[0] = SC_COM_LOG_SENSE;
4926 CDB[2] = (u_char)(0x40 | logpages[count]);/* 0x40 for current values */
4931 MSB2(&CDB[7], size);
4934 if (SCSI_Run(INDEX_TAPECTL, Input, CDB, 10,
4938 SIZEOF(RequestSense_T)) != 0)
4940 DecodeSense(pRequestSense, "LogSense : ",debug_file);
4941 free(pRequestSense);
4948 LogSenseHeader = (LogSenseHeader_T *)buffer;
4949 length = V2(LogSenseHeader->PageLength);
4950 LogParameter = (LogParameter_T *)(buffer + SIZEOF(LogSenseHeader_T));
4952 * Decode the log pages
4954 p = (struct LogPageDecode *)&DecodePages;
4957 dump_hex((u_char *)LogParameter, 64, DEBUG_INFO, SECTION_SCSI);
4959 while(p->ident != NULL) {
4960 if ((strcmp(pDev[INDEX_TAPECTL].ident, p->ident) == 0 ||strcmp("*", p->ident) == 0) && p->LogPage == logpages[count]) {
4961 p->decode(LogParameter, length);
4963 fprintf(StatFile, "\n");
4970 fprintf(StatFile, "Logpage No %d = %x\n", count ,logpages[count]);
4972 while ((u_char *)LogParameter < (buffer + length)) {
4973 i = LogParameter->ParameterLength;
4974 ParameterCode = V2(LogParameter->ParameterCode);
4977 value = V1((u_char *)LogParameter + SIZEOF(LogParameter_T));
4978 fprintf(StatFile, "ParameterCode %02X = %u(%d)\n", ParameterCode, value, i);
4981 value = V2((u_char *)LogParameter + SIZEOF(LogParameter_T));
4982 fprintf(StatFile, "ParameterCode %02X = %u(%d)\n", ParameterCode, value, i);
4985 value = V3((u_char *)LogParameter + SIZEOF(LogParameter_T));
4986 fprintf(StatFile, "ParameterCode %02X = %u(%d)\n", ParameterCode, value, i);
4989 value = V4((u_char *)LogParameter + SIZEOF(LogParameter_T));
4990 fprintf(StatFile, "ParameterCode %02X = %u(%d)\n", ParameterCode, value, i);
4993 value = V5((u_char *)LogParameter + SIZEOF(LogParameter_T));
4994 fprintf(StatFile, "ParameterCode %02X = %u(%d)\n", ParameterCode, value, i);
4997 fprintf(StatFile, "ParameterCode %02X size %d\n", ParameterCode, i);
4999 LogParameter = (LogParameter_T *)((u_char *)LogParameter + SIZEOF(LogParameter_T) + i);
5001 fprintf(StatFile, "\n");
5008 * Reset the cumulative counters
5010 CDB[0] = SC_COM_LOG_SELECT;
5021 if (SCSI_Run(INDEX_TAPECTL, Input, CDB, 10,
5025 SIZEOF(RequestSense_T)) != 0)
5027 DecodeSense(pRequestSense, "LogSense : ",debug_file);
5028 free(pRequestSense);
5038 free(pRequestSense);
5045 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### STOP LogSense\n");
5050 WriteErrorCountersPage(
5051 LogParameter_T * buffer,
5056 LogParameter_T *LogParameter;
5057 unsigned ParameterCode;
5058 LogParameter = buffer;
5060 fprintf(StatFile, "\tWrite Error Counters Page\n");
5062 while ((u_char *)LogParameter < ((u_char *)buffer + length)) {
5063 i = LogParameter->ParameterLength;
5064 ParameterCode = V2(LogParameter->ParameterCode);
5067 if (Decode(LogParameter, &value) == 0) {
5068 switch (ParameterCode) {
5070 fprintf(StatFile, "%-30s = %u\n",
5075 fprintf(StatFile, "%-30s = %u\n",
5076 "Total Errors Corrected",
5080 fprintf(StatFile, "%-30s = %u\n",
5081 "Total Times E. Processed",
5085 fprintf(StatFile, "%-30s = %u\n",
5086 "Total Bytes Processed",
5090 fprintf(StatFile, "%-30s = %u\n",
5091 "Total Unrecoverable Errors",
5095 fprintf(StatFile, "Unknown ParameterCode %02X = %u(%d)\n",
5101 fprintf(StatFile, "Error decoding Result\n");
5103 LogParameter = (LogParameter_T *)((u_char *)LogParameter + SIZEOF(LogParameter_T) + i);
5108 ReadErrorCountersPage(
5109 LogParameter_T * buffer,
5114 LogParameter_T *LogParameter;
5115 unsigned ParameterCode;
5116 LogParameter = buffer;
5118 fprintf(StatFile, "\tRead Error Counters Page\n");
5120 while ((u_char *)LogParameter < ((u_char *)buffer + length)) {
5121 i = LogParameter->ParameterLength;
5122 ParameterCode = V2(LogParameter->ParameterCode);
5125 if (Decode(LogParameter, &value) == 0) {
5126 switch (ParameterCode) {
5128 fprintf(StatFile, "%-30s = %u\n",
5133 fprintf(StatFile, "%-30s = %u\n",
5134 "Total Errors Corrected",
5138 fprintf(StatFile, "%-30s = %u\n",
5139 "Total Times E. Processed",
5143 fprintf(StatFile, "%-30s = %u\n",
5144 "Total Bytes Processed",
5148 fprintf(StatFile, "%-30s = %u\n",
5149 "Total Unrecoverable Errors",
5153 fprintf(StatFile, "Unknown ParameterCode %02X = %u(%d)\n",
5159 fprintf(StatFile, "Error decoding Result\n");
5161 LogParameter = (LogParameter_T *)((u_char *)LogParameter + SIZEOF(LogParameter_T) + i);
5167 LogParameter_T * buffer,
5172 LogParameter_T *LogParameter;
5173 unsigned ParameterCode;
5174 LogParameter = buffer;
5176 fprintf(StatFile, "\tData compression transfer Page\n");
5178 while ((u_char *)LogParameter < ((u_char *)buffer + length)) {
5179 i = LogParameter->ParameterLength;
5180 ParameterCode = V2(LogParameter->ParameterCode);
5183 if (Decode(LogParameter, &value) == 0) {
5184 switch (ParameterCode) {
5186 fprintf(StatFile, "Unknown ParameterCode %02X = %u(%d)\n",
5192 LogParameter = (LogParameter_T *)((u_char *)LogParameter + SIZEOF(LogParameter_T) + i);
5198 LogParameter_T * buffer,
5203 LogParameter_T *LogParameter;
5204 unsigned ParameterCode;
5205 LogParameter = buffer;
5207 fprintf(StatFile, "\tDrive Counters Page\n");
5209 while ((u_char *)LogParameter < ((unsigned char *)buffer + length)) {
5210 i = LogParameter->ParameterLength;
5211 ParameterCode = V2(LogParameter->ParameterCode);
5214 if (Decode(LogParameter, &value) == 0) {
5215 switch (ParameterCode) {
5217 fprintf(StatFile, "%-30s = %u\n",
5222 fprintf(StatFile, "%-30s = %u\n",
5223 "Total write drive errors",
5227 fprintf(StatFile, "%-30s = %u\n",
5228 "Total read drive errors",
5232 fprintf(StatFile, "Unknown ParameterCode %02X = %u(%d)\n",
5238 LogParameter = (LogParameter_T *)((u_char *)LogParameter + SIZEOF(LogParameter_T) + i);
5244 LogParameter_T * buffer,
5249 LogParameter_T *LogParameter;
5250 unsigned ParameterCode;
5251 LogParameter = buffer;
5253 fprintf(StatFile, "\tData Compression Page\n");
5255 while ((u_char *)LogParameter < ((unsigned char *)buffer + length)) {
5256 i = LogParameter->ParameterLength;
5257 ParameterCode = V2(LogParameter->ParameterCode);
5260 if (Decode(LogParameter, &value) == 0) {
5261 switch (ParameterCode) {
5263 fprintf(StatFile, "%-30s = %u\n",
5268 fprintf(StatFile, "%-30s = %u\n",
5273 fprintf(StatFile, "Unknown ParameterCode %02X = %u(%d)\n",
5279 LogParameter = (LogParameter_T *)((u_char *)LogParameter + SIZEOF(LogParameter_T) + i);
5285 LogParameter_T * buffer,
5290 LogParameter_T *LogParameter;
5291 unsigned ParameterCode;
5292 LogParameter = buffer;
5294 fprintf(StatFile, "\tDrive Usage Information Page\n");
5296 while ((u_char *)LogParameter < ((unsigned char *)buffer + length)) {
5297 i = LogParameter->ParameterLength;
5298 ParameterCode = V2(LogParameter->ParameterCode);
5301 if (Decode(LogParameter, &value) == 0) {
5302 switch (ParameterCode) {
5310 fprintf(StatFile, "%-30s = %u\n",
5315 fprintf(StatFile, "%-30s = %u\n",
5316 "MinutesSince Last Clean",
5323 fprintf(StatFile, "%-30s = %u\n",
5335 fprintf(StatFile, "%-30s = %u\n",
5344 fprintf(StatFile, "Unknown ParameterCode %02X = %u(%d)\n",
5350 LogParameter = (LogParameter_T *)((u_char *)LogParameter + SIZEOF(LogParameter_T) + i);
5356 LogParameter_T * LogParameter,
5360 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### START Decode\n");
5361 DebugPrint(DEBUG_INFO, SECTION_SCSI,"Decode Parameter with length %d\n", LogParameter->ParameterLength);
5364 switch (LogParameter->ParameterLength) {
5366 *value = V1((u_char *)LogParameter + SIZEOF(LogParameter_T));
5369 *value = V2((u_char *)LogParameter + SIZEOF(LogParameter_T));
5372 *value = V3((u_char *)LogParameter + SIZEOF(LogParameter_T));
5375 *value = V4((u_char *)LogParameter + SIZEOF(LogParameter_T));
5378 *value = V5((u_char *)LogParameter + SIZEOF(LogParameter_T));
5381 *value = V6((u_char *)LogParameter + SIZEOF(LogParameter_T));
5384 fprintf(StatFile, "Can't decode ParameterCode %02X size %d\n",
5385 V2(LogParameter->ParameterCode), LogParameter->ParameterLength);
5386 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP Decode (1)\n");
5390 DebugPrint(DEBUG_INFO, SECTION_SCSI,"Result = %d\n", *value);
5391 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP Decode(0)\n");
5402 printf("%s Devicefd %d\n", device, p->fd);
5403 printf("%s Can SCSI %d\n", device, p->SCSI);
5404 printf("%s Device %s\n", device, (p->dev != NULL)? p->dev:"No set");
5405 printf("%s ConfigName %s\n", device, (p->ConfigName != NULL) ? p->ConfigName:"Not ser");
5407 printf("%s Null Pointer ....\n", device);
5416 u_char buffer[1024];
5421 (void)option; /* Quiet unused parameter warning */
5423 if ((ip=fopen("/tmp/chg-scsi-trace", "r")) == NULL)
5428 for (x = 0; x < 1024; x++)
5430 if (fscanf(ip, "%2x", &bufferx) == EOF)
5435 buffer[x] = (u_char)bufferx;
5439 DecodeModeSense(&buffer[0], 12, "DLT448ElementStatus :", 0, debug_file);
5444 * Display all Information we can get about the library....
5451 char * changer_file,
5455 extern OpenFiles_T *pDev;
5458 ExtendedRequestSense_T ExtRequestSense;
5461 ChangerCMD_T *p = (ChangerCMD_T *)&ChangerIO;
5462 pbarcoderes = alloc(SIZEOF(MBC_T));
5463 memset(pbarcoderes, 0, SIZEOF(MBC_T));
5465 if (pModePage == NULL) {
5466 pModePage = alloc(0xff);
5469 if ((out = fdopen(1 , "w")) == NULL)
5471 printf("Error fdopen stdout\n");
5477 if (strcmp("types", option) == 0 || strcmp("all", option) == 0)
5479 while(p->ident != NULL)
5481 printf ("Ident = %s, type = %s\n",p->ident, p->type);
5487 if (strcmp("robot", option) == 0 || strcmp("all", option) == 0)
5489 if (ElementStatusValid == 0)
5491 if (pDev[INDEX_CHANGER].functions->function_status(pDev[INDEX_CHANGER].fd, 1) != 0)
5493 printf("Can not initialize changer status\n");
5500 /* 0123456789012345678901234567890123456789012 */
5503 printf("Address Type Status From Barcode Label\n");
5505 printf("Address Type Status From\n");
5507 printf("-------------------------------------------\n");
5510 for ( x = 0; x < MTE; x++)
5513 printf("%07d MTE %s %04d %s ",pMTE[x].address,
5514 (pMTE[x].full ? "Full " :"Empty"),
5515 pMTE[x].from, pMTE[x].VolTag);
5517 if (pMTE[x].full == 1)
5519 pbarcoderes->action = BARCODE_BARCODE;
5520 strncpy(pbarcoderes->data.barcode, pMTE[x].VolTag,
5521 SIZEOF(pbarcoderes->data.barcode));
5523 if (MapBarCode(labelfile, pbarcoderes) == 0 )
5525 printf("No mapping\n");
5527 printf("%s \n",pbarcoderes->data.voltag);
5533 printf("%07d MTE %s %04d \n",pMTE[x].address,
5534 (pMTE[x].full ? "Full " :"Empty"),
5539 for ( x = 0; x < STE; x++)
5542 printf("%07d STE %s %04d %s ",pSTE[x].address,
5543 (pSTE[x].full ? "Full ":"Empty"),
5544 pSTE[x].from, pSTE[x].VolTag);
5546 if (pSTE[x].full == 1)
5548 pbarcoderes->action = BARCODE_BARCODE;
5549 strncpy(pbarcoderes->data.barcode, pSTE[x].VolTag,
5550 SIZEOF(pbarcoderes->data.barcode));
5552 if (MapBarCode(labelfile, pbarcoderes) == 0 )
5554 printf("No mapping\n");
5556 printf("%s \n",pbarcoderes->data.voltag);
5562 printf("%07d STE %s %04d %s\n",pSTE[x].address,
5563 (pSTE[x].full ? "Full ":"Empty"),
5564 pSTE[x].from, pSTE[x].VolTag);
5568 for ( x = 0; x < DTE; x++)
5571 printf("%07d DTE %s %04d %s ",pDTE[x].address,
5572 (pDTE[x].full ? "Full " : "Empty"),
5573 pDTE[x].from, pDTE[x].VolTag);
5575 if (pDTE[x].full == 1)
5577 pbarcoderes->action = BARCODE_BARCODE;
5578 strncpy(pbarcoderes->data.barcode, pDTE[x].VolTag,
5579 SIZEOF(pbarcoderes->data.barcode));
5581 if (MapBarCode(labelfile, pbarcoderes) == 0 )
5583 printf("No mapping\n");
5585 printf("%s \n",pbarcoderes->data.voltag);
5592 printf("%07d DTE %s %04d %s\n",pDTE[x].address,
5593 (pDTE[x].full ? "Full " : "Empty"),
5594 pDTE[x].from, pDTE[x].VolTag);
5597 for ( x = 0; x < IEE; x++)
5600 printf("%07d IEE %s %04d %s ",pIEE[x].address,
5601 (pIEE[x].full ? "Full " : "Empty"),
5602 pIEE[x].from, pIEE[x].VolTag);
5604 if (pIEE[x].full == 1)
5606 pbarcoderes->action = BARCODE_BARCODE;
5607 strncpy(pbarcoderes->data.barcode, pIEE[x].VolTag,
5608 SIZEOF(pbarcoderes->data.barcode));
5610 if (MapBarCode(labelfile, pbarcoderes) == 0 )
5612 printf("No mapping\n");
5614 printf("%s \n",pbarcoderes->data.voltag);
5621 printf("%07d IEE %s %04d %s\n",pIEE[x].address,
5622 (pIEE[x].full ? "Full " : "Empty"),
5623 pIEE[x].from, pIEE[x].VolTag);
5628 if (strcmp("sense", option) == 0 || strcmp("all", option) == 0)
5630 if (pDev[INDEX_CHANGER].SCSI == 1)
5632 printf("\nSense Status from robot:\n");
5633 RequestSense(INDEX_CHANGER , &ExtRequestSense, 0);
5634 DecodeExtSense(&ExtRequestSense, "", out);
5637 if (pDev[INDEX_TAPE].SCSI == 1)
5640 printf("Sense Status from tape (tapectl):\n");
5641 RequestSense(INDEX_TAPE, &ExtRequestSense, 0);
5642 DecodeExtSense(&ExtRequestSense, "", out);
5645 if (pDev[INDEX_TAPECTL].SCSI == 1)
5648 printf("Sense Status from tape (tapectl):\n");
5649 RequestSense(INDEX_TAPECTL, &ExtRequestSense, 0);
5650 DecodeExtSense(&ExtRequestSense, "", out);
5654 if (strcmp("ModeSenseRobot", option) == 0 || strcmp("all", option) == 0)
5657 if (SCSI_ModeSense(INDEX_CHANGER, pModePage, 0xff, 0x08, 0x3f) == 0)
5659 DecodeModeSense(pModePage, 0, "Changer :" , 0, out);
5663 if (strcmp("ModeSenseTape", option) == 0 || strcmp("all", option) == 0)
5665 if (pDev[INDEX_TAPECTL].SCSI == 1)
5668 if (SCSI_ModeSense(INDEX_TAPECTL, pModePage, 0xff, 0x0, 0x3f) == 0)
5670 DecodeModeSense(pModePage, 0, "Tape :" , 1, out);
5675 if (strcmp("fd", option) == 0 || strcmp("all", option) == 0)
5677 printf("changer_dev %s\n",changer_dev);
5678 printf("changer_file %s\n", changer_file);
5679 printf("tape_device %s\n\n", tape_device);
5680 DumpDev(&pDev[INDEX_TAPE], "pTapeDev");
5681 DumpDev(&pDev[INDEX_TAPECTL], "pTapeDevCtl");
5682 DumpDev(&pDev[INDEX_CHANGER], "pChangerDev");
5685 if (GenericClean("") == 1)
5686 printf("Tape needs cleaning\n");
5699 size_t row_count = 0;
5702 while (row_count < size)
5704 DebugPrint(level, section,"%02X ", (u_char)p[row_count]);
5705 if (((row_count + 1) % 16) == 0)
5708 for (x = 16; x > 0; x--)
5710 if (isalnum((u_char)p[row_count - x + 1 ]))
5711 DebugPrint(level, section,"%c",(u_char)p[row_count - x + 1]);
5713 DebugPrint(level, section,".");
5715 DebugPrint(level, section,"\n");
5719 DebugPrint(level, section,"\n");
5729 for (x = (ssize_t)length; x >= 0 && !isalnum((int)string[x]); x--)
5739 (void)level; /* Quiet unused parameter warning */
5741 dbprintf(("ChgExit in %s, reason %s\n", where, reason));
5742 fprintf(stderr,"%s\n",reason);
5746 /* OK here starts a new set of functions.
5747 * Every function is for one SCSI command.
5748 * Prefix is SCSI_ and then the SCSI command name
5752 * SCSI_Run is an wrapper arround SCSI_ExecuteCommand
5753 * It seems to be an good idea to check first if the device
5754 * is ready for accepting commands, and if this is true send
5760 Direction_T Direction,
5764 size_t DataBufferLength,
5765 RequestSense_T * pRequestSense,
5766 size_t RequestSenseLength)
5771 RequestSense_T *pRqS;
5773 /* Basic sanity checks */
5774 assert(CDB_Length <= UCHAR_MAX);
5775 assert(RequestSenseLength <= UCHAR_MAX);
5777 pRqS = (RequestSense_T *)pRequestSense;
5779 DebugPrint(DEBUG_INFO, SECTION_SCSI, "SCSI_Run TestUnitReady\n");
5780 while (!ok && maxtries < MAXTRIES)
5782 ret = SCSI_TestUnitReady(DeviceFD, (RequestSense_T *)pRequestSense );
5783 DebugPrint(DEBUG_INFO, SECTION_SCSI, "SCSI_Run TestUnitReady ret %d\n",ret);
5790 switch (SenseHandler(DeviceFD, 0, pRqS->SenseKey, pRqS->AdditionalSenseCode, pRqS->AdditionalSenseCodeQualifier, pRqS))
5793 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run (TestUnitReady) SENSE_NO\n");
5796 case SENSE_TAPE_NOT_ONLINE:
5797 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run (TestUnitReady) SENSE_TAPE_NOT_ONLINE\n");
5801 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run (TestUnitReady) SENSE_IGNORE\n");
5805 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"SCSI_Run (TestUnitReady) SENSE_ABORT\n");
5809 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run (TestUnitReady) SENSE_RETRY\n");
5812 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run (TestUnitReady) default (SENSE)\n");
5818 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"SCSI_Run (TestUnitReady) SCSI_ERROR\n");
5822 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run (TestUnitReady) SCSI_BUSY\n");
5825 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run (TestUnitReady) SCSI_CHECK\n");
5828 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"SCSI_Run (TestUnitReady) unknown (%d)\n",ret);
5838 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run TestUnitReady after %d sec:\n",maxtries);
5842 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"SCSI_Run Exit %d\n",ret);
5849 while (!ok && maxtries < MAXTRIES)
5851 ret = SCSI_ExecuteCommand(DeviceFD,
5858 RequestSenseLength);
5860 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run Exit %d\n",ret);
5867 switch (SenseHandler(DeviceFD, 0, pRqS->SenseKey, pRqS->AdditionalSenseCode, pRqS->AdditionalSenseCodeQualifier, pRqS))
5870 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run SENSE_NO\n");
5873 case SENSE_TAPE_NOT_ONLINE:
5874 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run SENSE_TAPE_NOT_ONLINE\n");
5878 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run SENSE_IGNORE\n");
5882 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"SCSI_Run SENSE_ABORT\n");
5886 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run SENSE_RETRY\n");
5889 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run default (SENSE)\n");
5895 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"SCSI_Run SCSI_ERROR\n");
5899 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run SCSI_BUSY\n");
5902 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run (TestUnitReady) SCSI_CHECK\n");
5905 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"SCSI_Run (TestUnitReady) unknown (%d)\n",ret);
5921 * This a vendor specific command !!!!!!
5922 * First seen at AIT :-)
5931 RequestSense_T *pRequestSense;
5937 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### START SCSI_AlignElements\n");
5939 pRequestSense = alloc(SIZEOF(RequestSense_T));
5941 for (retry = 0; retry < MAX_RETRIES; retry++)
5945 MSB2(&CDB[2],AE_MTE); /* Which MTE to use, default 0 */
5946 MSB2(&CDB[4],AE_DTE); /* Which DTE to use, no range check !! */
5947 MSB2(&CDB[6],AE_STE); /* Which STE to use, no range check !! */
5953 ret = SCSI_Run(DeviceFD, Input, CDB, 12,
5954 NULL, 0, pRequestSense, SIZEOF(RequestSense_T));
5956 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_AlignElements : SCSI_Run = %d\n", ret);
5957 DecodeSense(pRequestSense, "SCSI_AlignElements :",debug_file);
5961 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"%s: Request Sense[Inquiry]: %02X",
5962 "chs", ((u_char *) &pRequestSense)[0]);
5963 for (i = 1; i < (int)sizeof(RequestSense_T); i++)
5964 DebugPrint(DEBUG_ERROR, SECTION_SCSI," %02X", ((u_char *) &pRequestSense)[i]);
5965 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"\n");
5971 switch(SenseHandler(DeviceFD, 0 , pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
5974 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_AlignElements : SENSE_IGNORE\n");
5978 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_AlignElements : SENSE_RETRY no %d\n", retry);
5981 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"SCSI_AlignElements : SENSE_ABORT\n");
5984 case SENSE_TAPE_NOT_UNLOADED:
5985 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"SCSI_AlignElements : Tape still loaded, eject failed\n");
5989 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_AlignElements : end %d\n", pRequestSense->SenseKey);
5990 return(pRequestSense->SenseKey);
5996 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_AlignElements : end %d\n", ret);
6001 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"SCSI_AlignElements :"
6002 "Retries exceeded = %d\n", retry);
6014 RequestSense_T *pRequestSense;
6020 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### START SCSI_Move\n");
6022 pRequestSense = alloc(SIZEOF(RequestSense_T));
6024 for (retry = 0; (ret != 0) && (retry < MAX_RETRIES); retry++)
6026 CDB[0] = SC_MOVE_MEDIUM;
6029 CDB[3] = chm; /* Address of CHM */
6037 ret = SCSI_Run(DeviceFD, Input, CDB, 12,
6038 NULL, 0, pRequestSense, SIZEOF(RequestSense_T));
6040 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Move : SCSI_Run = %d\n", ret);
6041 DecodeSense(pRequestSense, "SCSI_Move :",debug_file);
6045 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"%s: Request Sense[Inquiry]: %02X",
6046 "chs", ((u_char *) &pRequestSense)[0]);
6047 for (i = 1; i < (int)sizeof(RequestSense_T); i++)
6048 DebugPrint(DEBUG_ERROR, SECTION_SCSI," %02X", ((u_char *) &pRequestSense)[i]);
6049 DebugPrint(DEBUG_INFO, SECTION_SCSI,"\n");
6055 switch(SenseHandler(DeviceFD, 0 , pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
6058 dbprintf(("SCSI_Move : SENSE_IGNORE\n"));
6062 dbprintf(("SCSI_Move : SENSE_RETRY no %d\n", retry));
6065 dbprintf(("SCSI_Move : SENSE_ABORT\n"));
6068 case SENSE_TAPE_NOT_UNLOADED:
6069 dbprintf(("SCSI_Move : Tape still loaded, eject failed\n"));
6073 dbprintf(("SCSI_Move : end %d\n", pRequestSense->SenseKey));
6074 return(pRequestSense->SenseKey);
6079 dbprintf(("SCSI_Move : end %d\n", ret));
6086 RequestSense_T * pRequestSense,
6093 dbprintf(("##### START SCSI_LoadUnload\n"));
6095 CDB[0] = SC_COM_UNLOAD;
6103 ret = SCSI_Run(DeviceFD, Input, CDB, 6,
6106 SIZEOF(RequestSense_T));
6110 dbprintf(("SCSI_Unload : failed %d\n", ret));
6115 dbprintf(("##### STOP SCSI_LoadUnload\n"));
6122 RequestSense_T * pRequestSense)
6127 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### START SCSI_TestUnitReady\n");
6129 CDB[0] = SC_COM_TEST_UNIT_READY;
6136 ret = SCSI_ExecuteCommand(DeviceFD, Input, CDB, 6,
6139 SIZEOF(RequestSense_T));
6142 * We got an error, so let the calling function handle this
6146 DebugPrint(DEBUG_INFO, SECTION_SCSI,"###### STOP SCSI_TestUnitReady (1)\n");
6152 * OK, no error condition
6153 * If no sense is set, the Unit is ready
6155 if (pRequestSense->ErrorCode == 0 && pRequestSense->SenseKey == 0)
6157 DebugPrint(DEBUG_INFO, SECTION_SCSI,"###### STOP SCSI_TestUnitReady (1)\n");
6165 if (pRequestSense->ErrorCode != 0){
6166 DebugPrint(DEBUG_INFO, SECTION_SCSI,"###### STOP SCSI_TestUnitReady ErrorCode set\n");
6168 if (pRequestSense->SenseKey != 0) {
6169 DebugPrint(DEBUG_INFO, SECTION_SCSI,"###### STOP SCSI_TestUnitReady Sense Key set\n");
6171 DebugPrint(DEBUG_INFO, SECTION_SCSI,"###### STOP SCSI_TestUnitReady (0)\n");
6186 RequestSense_T *pRequestSense;
6191 dbprintf(("##### START SCSI_ModeSelect\n"));
6193 dbprintf(("SCSI_ModeSelect start length = %u:\n", (unsigned)length));
6194 pRequestSense = alloc(SIZEOF(RequestSense_T));
6195 sendbuf = alloc((size_t)length + 4);
6196 memset(sendbuf, 0 , (size_t)length + 4);
6198 memcpy(&sendbuf[4], buffer, (size_t)length);
6199 dump_hex(sendbuf, (size_t)length+4, DEBUG_INFO, SECTION_SCSI);
6201 for (retry = 0; (ret != 0) && (retry < MAX_RETRIES); retry++)
6203 memset(pRequestSense, 0, SIZEOF(RequestSense_T));
6205 CDB[0] = SC_COM_MODE_SELECT;
6206 CDB[1] = (u_char)(((lun << 5) & 0xF0) | ((mode << 4) & 0x10) | (save & 1));
6209 CDB[4] = (u_char)(length + 4);
6211 ret = SCSI_Run(DeviceFD, Output, CDB, 6,
6215 SIZEOF(RequestSense_T));
6218 dbprintf(("SCSI_ModeSelect : ret %d\n", ret));
6225 switch(SenseHandler(DeviceFD, 0, pRequestSense->SenseKey,
6226 pRequestSense->AdditionalSenseCode,
6227 pRequestSense->AdditionalSenseCodeQualifier,
6231 dbprintf(("SCSI_ModeSelect : SENSE_IGNORE\n"));
6236 dbprintf(("SCSI_ModeSelect : SENSE_RETRY no %d\n", retry));
6240 ret = pRequestSense->SenseKey;
6246 dbprintf(("SCSI_ModeSelect end: %d\n", ret));
6249 free(pRequestSense);
6265 RequestSense_T *pRequestSense;
6269 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### START SCSI_ModeSense\n");
6271 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ModeSense start length = %d:\n", size);
6272 pRequestSense = alloc(SIZEOF(RequestSense_T));
6274 while (ret && retry < MAX_RETRIES)
6276 memset(pRequestSense, 0, SIZEOF(RequestSense_T));
6277 memset(buffer, 0, size);
6279 CDB[0] = SC_COM_MODE_SENSE;
6285 ret = SCSI_Run(DeviceFD, Input, CDB, 6,
6289 SIZEOF(RequestSense_T));
6298 switch(SenseHandler(DeviceFD, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
6301 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ModeSense : SENSE_IGNORE\n");
6305 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ModeSense : SENSE_RETRY no %d\n", retry);
6308 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ModeSense : end %d\n", pRequestSense->SenseKey);
6309 return(pRequestSense->SenseKey);
6316 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ModeSense end: %d\n", ret);
6323 SCSIInquiry_T * buffer,
6327 RequestSense_T *pRequestSense;
6332 assert(size <= UCHAR_MAX);
6334 DebugPrint(DEBUG_INFO, SECTION_SCSI, "##### START SCSI_Inquiry\n");
6336 DebugPrint(DEBUG_INFO, SECTION_SCSI, "SCSI_Inquiry start length = %d:\n", size);
6338 pRequestSense = alloc((size_t)size);
6340 while (retry > 0 && retry < MAX_RETRIES)
6342 memset(buffer, 0, size);
6343 CDB[0] = SC_COM_INQUIRY;
6347 CDB[4] = (u_char)size;
6350 ret = SCSI_ExecuteCommand(DeviceFD, Input, CDB, 6,
6354 SIZEOF(RequestSense_T));
6357 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"%s: Request Sense[Inquiry]: %02X",
6358 "chs", ((u_char *) pRequestSense)[0]);
6359 for (i = 1; i < (int)sizeof(RequestSense_T); i++)
6360 DebugPrint(DEBUG_ERROR, SECTION_SCSI," %02X", ((u_char *) pRequestSense)[i]);
6361 DebugPrint(DEBUG_ERROR, SECTION_SCSI, "\n");
6362 DebugPrint(DEBUG_ERROR, SECTION_SCSI, "Inquiry end: %d\n", ret);
6368 switch(SenseHandler(DeviceFD, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
6371 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Inquiry : SENSE_IGNORE\n");
6375 DebugPrint(DEBUG_INFO, SECTION_SCSI, "SCSI_Inquiry : SENSE_RETRY no %d\n", retry);
6378 DebugPrint(DEBUG_ERROR, SECTION_SCSI, "SCSI_Inquiry : end %d\n", pRequestSense->SenseKey);
6379 return(pRequestSense->SenseKey);
6386 dump_hex((u_char *)buffer, size, DEBUG_INFO, SECTION_SCSI);
6387 DebugPrint(DEBUG_INFO, SECTION_SCSI, "SCSI_Inquiry : end %d\n", ret);
6393 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Inquiry end: %d\n", ret);
6398 * Read the Element Status. If DescriptorSize != 0 then
6399 * allocate DescriptorSize * NoOfElements for the result from the
6400 * Read Element Status command.
6401 * If DescriptorSize == 0 than try to figure out how much space is needed
6403 * 1. do an read with an allocation size of 8
6404 * 2. from the result take the 'Byte Count of Descriptor Available'
6405 * 3. do again an Read Element Status with the result from 2.
6409 SCSI_ReadElementStatus(
6415 size_t NoOfElements,
6416 size_t DescriptorSize,
6420 size_t DataBufferLength;
6421 ElementStatusData_T *ElementStatusData;
6422 RequestSense_T *pRequestSense;
6426 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### START SCSI_ReadElementStatus\n");
6428 pRequestSense = alloc(SIZEOF(RequestSense_T));
6431 * How many elements, if <= 0 than exit with an fatal error
6433 if (NoOfElements == 0)
6435 ChgExit("SCSI_ReadElementStatus","No of Elements passed are le 0",FATAL);
6439 VolTag = (u_char)((VolTag << 4) & 0x10);
6440 type = (u_char)(type & 0xf);
6441 lun = (u_char)((lun << 5) & 0xe0);
6443 /* if DescriptorSize == 0
6444 * try to get the allocation length for the second call
6446 if (DescriptorSize == 0)
6448 *data = newalloc(*data, 8);
6449 memset(*data, 0, 8);
6451 while (retry > 0 && retry < MAX_RETRIES)
6453 memset(pRequestSense, 0, SIZEOF(RequestSense_T) );
6455 CDB[0] = SC_COM_RES; /* READ ELEMENT STATUS */
6456 CDB[1] = (u_char)(VolTag | type | lun); /* Element Type Code , VolTag, LUN */
6457 MSB2(&CDB[2], StartAddress); /* Starting Element Address */
6458 MSB2(&CDB[4], NoOfElements); /* Number Of Element */
6459 CDB[6] = 0; /* Reserved */
6460 MSB3(&CDB[7],8); /* Allocation Length */
6461 CDB[10] = 0; /* Reserved */
6462 CDB[11] = 0; /* Control */
6464 ret = SCSI_Run(DeviceFD, Input, CDB, 12,
6466 pRequestSense, SIZEOF(RequestSense_T));
6468 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ReadElementStatus : (1) SCSI_Run %d\n", ret);
6471 DecodeSense(pRequestSense, "SCSI_ReadElementStatus :",debug_file);
6472 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP SCSI_ReadElementStatus (%d)\n",ret);
6478 switch(SenseHandler(DeviceFD, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
6481 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ModeSense : SENSE_IGNORE\n");
6485 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ModeSense : SENSE_RETRY no %d\n", retry);
6489 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ModeSense : end %d\n", pRequestSense->SenseKey);
6490 return(pRequestSense->SenseKey);
6502 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP SCSI_ReadElementStatus (%d)\n",ret);
6507 ElementStatusData = (ElementStatusData_T *)*data;
6508 DataBufferLength = V3(ElementStatusData->count);
6510 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ReadElementStatus: DataBufferLength %X, ret %d\n",DataBufferLength, ret);
6512 dump_hex(*data, 8, DEBUG_INFO, SECTION_ELEMENT);
6513 } else { /* DescriptorSize != 0 */
6514 DataBufferLength = NoOfElements * DescriptorSize;
6517 DataBufferLength = DataBufferLength + 8;
6518 *data = newalloc(*data, DataBufferLength);
6519 memset(*data, 0, DataBufferLength);
6522 while (retry > 0 && retry < MAX_RETRIES)
6524 memset(pRequestSense, 0, SIZEOF(RequestSense_T) );
6526 CDB[0] = SC_COM_RES; /* READ ELEMENT STATUS */
6527 CDB[1] = (u_char)(VolTag | type | lun); /* Element Type Code, VolTag, LUN */
6528 MSB2(&CDB[2], StartAddress); /* Starting Element Address */
6529 MSB2(&CDB[4], NoOfElements); /* Number Of Element */
6530 CDB[6] = 0; /* Reserved */
6531 MSB3(&CDB[7],DataBufferLength); /* Allocation Length */
6532 CDB[10] = 0; /* Reserved */
6533 CDB[11] = 0; /* Control */
6535 ret = SCSI_Run(DeviceFD, Input, CDB, 12,
6536 *data, DataBufferLength,
6537 pRequestSense, SIZEOF(RequestSense_T));
6540 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ReadElementStatus : (2) SCSI_Run %d\n", ret);
6543 DecodeSense(pRequestSense, "SCSI_ReadElementStatus :",debug_file);
6544 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP SCSI_ReadElementStatus (%d)\n",ret);
6550 switch(SenseHandler(DeviceFD, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
6553 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ModeSense : SENSE_IGNORE\n");
6557 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ModeSense : SENSE_RETRY no %d\n", retry);
6561 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ModeSense : end %d\n", pRequestSense->SenseKey);
6562 return(pRequestSense->SenseKey);
6575 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP SCSI_ReadElementStatus (%d)\n",ret);
6580 dump_hex(*data, DataBufferLength, DEBUG_INFO, SECTION_SCSI);
6581 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP SCSI_ReadElementStatus (%d)\n",ret);
6585 printf_arglist_function2(void DebugPrint, int, level, int, section, char *, fmt)
6591 time_t ti = time(NULL);
6593 if (changer->debuglevel)
6595 if (sscanf(changer->debuglevel,"%d:%d", &dlevel, &dsection) != 2) {
6596 dbprintf(("Parse error: line is '%s' expected [0-9]*:[0-9]*\n",
6597 changer->debuglevel));
6606 arglist_start(argp, fmt);
6607 vsnprintf(buf, SIZEOF(buf), fmt, argp);
6608 if (dlevel >= level)
6610 if (section == dsection || dsection == 0)
6612 if (index(buf, '\n') != NULL && strlen(buf) > 1)
6614 dbprintf(("%ld:%s", (long)ti, buf));
6616 dbprintf(("%s", buf));