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 GenericClean(char *Device); /* Does the tape need a clean */
78 int GenericBarCode(int DeviceFD); /* Do we have Barcode reader support */
79 int NoBarCode(int DeviceFD);
81 int GenericSearch(void);
82 void Inventory(char *labelfile, int drive, int eject, int start, int stop, int clean);
84 int TreeFrogBarCode(int DeviceFD);
85 int EXB_BarCode(int DeviceFD);
86 int GenericSenseHandler(int fd, u_char flags, u_char SenseKey, u_char AdditionalSenseCode, u_char AdditionalSenseCodeQualifier, RequestSense_T *);
88 ElementInfo_T *LookupElement(int address);
89 int eject_tape(char *tapedev, int type);
90 int unload(int fd, int drive, int slot);
91 int load(int fd, int drive, int slot);
92 int GetElementStatus(int DeviceFD);
93 int drive_loaded(int fd, int drivenum);
98 void WriteErrorCountersPage(LogParameter_T *, size_t);
99 void ReadErrorCountersPage(LogParameter_T *, size_t);
100 void C1553APage30(LogParameter_T *, size_t);
101 void C1553APage37(LogParameter_T *, size_t);
102 void EXB85058HEPage39(LogParameter_T *, size_t);
103 void EXB85058HEPage3c(LogParameter_T *, size_t);
104 int Decode(LogParameter_T *, unsigned *);
105 int DecodeModeSense(u_char *buffer, size_t offset, char *pstring, char block, FILE *out);
107 int SCSI_Run(int DeviceFD,
108 Direction_T Direction,
112 size_t DataBufferLength,
113 RequestSense_T *pRequestSense,
114 size_t RequestSenseLength);
116 int SCSI_Move(int DeviceFD, u_char chm, int from, int to);
117 int SCSI_LoadUnload(int DeviceFD, RequestSense_T *pRequestSense, u_char byte1, u_char load);
118 int SCSI_TestUnitReady(int, RequestSense_T *);
119 int SCSI_ModeSense(int DeviceFD, u_char *buffer, u_char size, u_char byte1, u_char byte2);
120 int SCSI_ModeSelect(int DeviceFD,
127 int SCSI_ReadElementStatus(int DeviceFD,
133 size_t DescriptorSize,
137 static int barcode; /* cache the result from the BarCode function */
139 SC_COM_T SCSICommand[] = {
151 "INITIALIZE ELEMENT STATUS"},
178 "READ ELEMENT STATUS"},
182 ChangerCMD_T ChangerIO[] = {
184 "Generic driver changer [generic_changer]",
186 GenericElementStatus,
194 GenericSenseHandler},
197 "HP Auto Loader [C1553A]",
199 GenericElementStatus,
207 GenericSenseHandler},
208 /* Exabyte Devices */
210 "Exabyte Robot [EXB-10e]",
212 GenericElementStatus,
220 GenericSenseHandler},
222 "Exabyte Robot [EXB-120]",
224 GenericElementStatus,
232 GenericSenseHandler},
234 "Exabyte Robot [EXB-210]",
236 GenericElementStatus,
244 GenericSenseHandler},
246 "Exabyte Tape [EXB-85058HE-0000]",
256 GenericSenseHandler},
257 /* Tandberg Devices */
259 "Tandberg Robot (TDS 1420)",
261 GenericElementStatus,
269 GenericSenseHandler},
272 "ADIC VLS DLT Library [VLS DLT]",
274 GenericElementStatus,
282 GenericSenseHandler},
284 "ADIC VLS DLT Library [VLS SDX]",
294 GenericSenseHandler},
296 "ADIC FastStor DLT Library [FastStor DLT]",
306 GenericSenseHandler},
308 "ADIC DLT 448 [Scalar DLT 448]",
318 GenericSenseHandler},
319 /* Sepctra Logic Devices */
321 "Spectra Logic TreeFrog[215]",
323 GenericElementStatus,
331 GenericSenseHandler},
334 "Breece Hill Quad 7",
336 GenericElementStatus,
344 GenericSenseHandler},
345 /* Quantum Devices */
349 GenericElementStatus,
357 GenericSenseHandler},
359 * And now the tape devices
361 /* The generic handler if nothing matches */
363 "Generic driver tape [generic_tape]",
365 GenericElementStatus,
373 GenericSenseHandler},
375 "DLT Tape [DLT8000]",
385 GenericSenseHandler},
387 "DLT Tape [DLT7000]",
397 GenericSenseHandler},
399 "DLT Tape [DLT4000]",
409 GenericSenseHandler},
410 {NULL, NULL, NULL,NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}
414 LogPageDecode_T DecodePages[] = {
417 WriteErrorCountersPage},
420 ReadErrorCountersPage},
429 WriteErrorCountersPage},
432 ReadErrorCountersPage},
443 int ElementStatusValid = 0; /* Set if the READ ELEMENT STATUS was OK, an no error is pending */
444 int LibModeSenseValid = 0; /* Set if we did an scussefull MODE SENSE */
447 /* Pointer to MODE SENSE Pages */
448 u_char *pModePage = NULL;
449 EAAPage_T *pEAAPage = NULL;
450 DeviceCapabilitiesPage_T *pDeviceCapabilitiesPage = NULL;
451 u_char *pVendorUnique = NULL;
454 * New way, every element type has its on array
455 * which is dynamic allocated by the ElementStatus function,
457 ElementInfo_T *pMTE = NULL; /*Medium Transport Element */
458 ElementInfo_T *pSTE = NULL; /*Storage Element */
459 ElementInfo_T *pIEE = NULL; /*Import Export Element */
460 ElementInfo_T *pDTE = NULL; /*Data Transfer Element */
461 size_t MTE = 0; /*Counter for the above element types */
466 char *chgscsi_datestamp = NULL; /* Result pointer for tape_rdlabel */
467 char *chgscsi_label = NULL; /* Result pointer for tape_rdlabel */
468 char *chgscsi_result = NULL; /* Needed for the result string of MapBarCode */
471 * First all functions which are called from extern
476 * Print the scsi-changer-driver version
480 ChangerDriverVersion(void)
482 DebugPrint(DEBUG_ERROR, SECTION_INFO, "scsi-changer-driver: %s\n",rcsid);
487 * Try to generate an template which can be used as an example for the config file
493 extern OpenFiles_T *pDev;
497 printf("# Please replace every ??? with the correct parameter. It is not possible\n");
498 printf("# to guess everything :-)\n");
499 printf("# If the option is not needed, cleanmax for example if you have no cleaning\n");
500 printf("# tape remove the line.\n");
502 printf("number_configs 1 # Number of configs, you can have more than 1 config\n");
503 printf(" # if you have for example more than one drive, or you\n");
504 printf(" # to split your lib to use different dump levels\n");
506 printf("emubarcode 1 # If you drive has no barcode reader this will try\n");
507 printf(" # keep an inventory of your tapes to find them faster\n");
509 printf("havebarcode 0 # Set this to 1 if you have an library with an installed\n");
510 printf(" # barcode reader\n");
512 printf("debuglevel 0:0 # For debuging, see the docs /docs/TAPE-CHANGER\n");
514 printf("eject ??? # set this to 1 if your drive needs an eject before move\n");
516 printf("sleep ??? # How long to wait after an eject command before moving\n");
517 printf(" # the tape\n");
520 for (count = 0; count < CHG_MAXDEV ; count++)
524 if (pDev[count].inquiry != NULL && pDev[count].inquiry->type == TYPE_CHANGER)
526 printf("changerdev %s # This is the device to communicate with the robot\n", pDev[count].dev);
533 * Did we reach the end of the list ?
534 * If no we found an changer and now we try to
535 * get the element status for the count of slots
537 if (count < CHG_MAXDEV)
539 pDev[count].functions->function_status(count, 1);
541 printf("changerdev ??? # Ups nothing found. Please check the docs\n");
545 printf(" # Here now comes the config for the first tape\n");
546 printf("config 0 # This value is the one which is used in the amanda\n");
547 printf(" # config file to tell the chg-scsi programm which tape\n");
548 printf(" # and which slots to use\n");
550 printf("cleancart ??? # The slot where the cleaning tape is located\n");
551 printf(" # remove it if you have no cleaning tape\n");
553 printf("drivenum 0 # Which tape drive to use if there are more than one drive\n");
555 printf("dev ??? # Which is the raw device to read/write data from the tape\n");
556 printf(" # It is important to use the non rewinding tape, like\n");
557 printf(" # /dev/nrst0 on linux, /dev/nrsa0 on BSD ....\n");
561 * OK now lets see if we have an direct SCSI channel
563 * If not thats not a problem
565 for (count = 0; count < CHG_MAXDEV; count++)
569 if (pDev[count].inquiry != NULL && pDev[count].inquiry->type == TYPE_TAPE)
571 printf("scsitapedev %s # This is the device to communicate with the tape\n", pDev[count].dev);
572 printf(" # to get some device stats, not so importatn, and\n");
573 printf(" # if you run in problems delete it complete\n");
583 printf("startuse 0 # Which is the first slot to use\n");
585 printf("enduse " SIZE_T_FMT " # Which is the last slot to use\n", STE);
587 printf("startuse ??? # Which is the first slot to use\n");
589 printf("enduse ??? # Which is the last slot to use\n");
591 printf(" # decrement this value by 1 if you have an\n");
592 printf(" # cleaning tape in the last slot\n");
595 if ((cwd = getcwd(NULL, 0)) == NULL) {
599 printf("statfile %s/tape0-slot #\n",cwd);
600 printf("cleanfile %s/tape0-clean #\n", cwd);
601 printf("usagecount %s/tape0-totaltime #\n", cwd);
602 printf("tapestatus %s/tape0-tapestatus #\n", cwd);
603 printf("labelfile %s/labelfile #\n", cwd);
609 * Try to create a list of tapes and labels which are in the current
610 * magazin. The drive must be empty !!
612 * labelfile -> file name of the db
613 * drive -> which drive should we use
614 * eject -> the tape device needs an eject before move
615 * start -> start at slot start
616 * stop -> stop at slot stop
617 * clean -> if we have an cleaning tape than this is the slot number of it
624 * Check if the tape/changer is ready for the next move
625 * If an tape is loaded unload it and do initialize element status to
626 * get all labels if an bar code reader is installed
637 extern OpenFiles_T *pDev;
639 static int inv_done = 0; /* Inventory function called ?, marker to disable recursion */
640 MBC_T *pbarcoderes; /* Here we will pass the parameter to MapBarCode and get the result */
642 (void)start; /* Quiet unused parameter warning */
643 (void)stop; /* Quiet unused parameter warning */
645 DebugPrint(DEBUG_INFO,SECTION_MAP_BARCODE, "##### START Inventory\n");
646 pbarcoderes = alloc(SIZEOF(MBC_T));
647 memset(pbarcoderes, 0 , SIZEOF(MBC_T));
651 DebugPrint(DEBUG_INFO,SECTION_MAP_BARCODE, "##### STOP inv_done -> %d Inventory\n",inv_done);
657 barcode = BarCode(INDEX_CHANGER);
659 pbarcoderes->action = RESET_VALID;
661 MapBarCode(labelfile,pbarcoderes);
664 * Check if an tape is loaded, if yes unload it
665 * and do an INIT ELEMENT STATUS
668 if (pDTE[0].status == 'F')
672 (void)eject_tape("", eject);
674 (void)unload(INDEX_TAPE, 0, 0);
677 GenericResetStatus(INDEX_CHANGER);
679 for (x = 0; x < STE; x++)
681 if (x == (size_t)clean)
687 * Load the tape, on error try the next
688 * error could be an empty slot for example
690 if (load(INDEX_CHANGER, drive, x ) != 0)
692 DebugPrint(DEBUG_ERROR,SECTION_MAP_BARCODE, "Load drive(%d) from(%d) failed\n", drive, x);
697 * Wait until the tape is ready
699 Tape_Ready(INDEX_TAPECTL, 60);
701 SCSI_CloseDevice(INDEX_TAPE);
703 if ((chgscsi_result = (char *)tape_rdlabel(pDev[INDEX_TAPE].dev, &chgscsi_datestamp, &chgscsi_label)) == NULL)
705 pbarcoderes->action = UPDATE_SLOT;
706 strncpy(pbarcoderes->data.voltag, chgscsi_label,
707 SIZEOF(pbarcoderes->data.voltag));
708 pbarcoderes->data.slot = x;
709 pbarcoderes->data.from = 0;
710 pbarcoderes->data.LoadCount = 1;
711 if (BarCode(INDEX_CHANGER) == 1)
713 strncpy(pbarcoderes->data.barcode, pDTE[drive].VolTag,
714 SIZEOF(pbarcoderes->data.barcode));
715 MapBarCode(labelfile, pbarcoderes);
717 MapBarCode(labelfile, pbarcoderes);
720 DebugPrint(DEBUG_ERROR,SECTION_MAP_BARCODE, "Read label failed\n");
725 (void)eject_tape("", eject);
728 (void)unload(INDEX_TAPE, drive, x);
730 DebugPrint(DEBUG_INFO,SECTION_MAP_BARCODE, "##### STOP Inventory\n");
735 * Check if the slot ist empty
736 * slot -> slot number to check
743 extern OpenFiles_T *pDev;
744 DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### START isempty\n");
746 if (ElementStatusValid == 0)
748 if ( pDev[fd].functions->function_status(fd, 1) != 0)
750 DebugPrint(DEBUG_ERROR,SECTION_TAPE,"##### STOP isempty [-1]\n");
756 if (pSTE[slot].status == 'E')
758 DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### STOP isempty [1]\n");
762 DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### STOP isempty [0]\n");
770 extern OpenFiles_T *pDev;
771 /* Return 1 if cleaning is needed */
774 DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### START get_clean_state\n");
776 if (pDev[INDEX_TAPECTL].SCSI == 0)
778 DebugPrint(DEBUG_ERROR,SECTION_TAPE,"##### STOP get_clean_state [-1]\n");
782 ret=pDev[INDEX_TAPECTL].functions->function_clean(tapedev);
783 DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### STOP get_clean_state [%d]\n", ret);
789 * The parameter tapedev is not used.
790 * Type describes if we should force the SCSI eject if available
791 * normal eject is done with the ioctl
793 /* This function ejects the tape from the drive */
800 extern OpenFiles_T *pDev;
803 DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### START eject_tape\n");
806 * Try to read the label
808 if (pDev[INDEX_TAPE].avail == 1 && (changer->emubarcode == 1 || BarCode(INDEX_CHANGER)))
811 if (pDev[INDEX_TAPECTL].SCSI == 1 && pDev[INDEX_TAPECTL].avail) {
812 pDev[INDEX_TAPECTL].functions->function_rewind(INDEX_TAPECTL);
814 pDev[INDEX_TAPE].functions->function_rewind(INDEX_TAPE);
817 if (pDev[INDEX_TAPE].devopen == 1)
819 SCSI_CloseDevice(INDEX_TAPE);
822 chgscsi_result = (char *)tape_rdlabel(pDev[INDEX_TAPE].dev, &chgscsi_datestamp, &chgscsi_label);
825 if (pDev[INDEX_TAPECTL].SCSI == 1 && pDev[INDEX_TAPECTL].avail == 1 && type == 1)
827 ret=pDev[INDEX_TAPECTL].functions->function_eject(tapedev, type);
828 DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### STOP (SCSI)eject_tape [%d]\n", ret);
833 if (pDev[INDEX_TAPE].avail == 1)
835 ret=Tape_Ioctl(INDEX_TAPE, IOCTL_EJECT);
836 DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### STOP (ioctl)eject_tape [%d]\n", ret);
841 DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### STOP eject_tape [-1]\n");
846 /* Find an empty slot, starting at start, ending at start+count */
853 extern OpenFiles_T *pDev;
857 DebugPrint(DEBUG_INFO,SECTION_ELEMENT,"###### START find_empty\n");
859 if (ElementStatusValid == 0)
861 if ( pDev[fd].functions->function_status(fd , 1) != 0)
863 DebugPrint(DEBUG_ERROR,SECTION_ELEMENT,
864 "###### END find_empty [-1]\n");
882 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,
883 "start at " SIZE_T_FMT ", end at " SIZE_T_FMT "\n",
884 (SIZE_T_FMT_TYPE)start,
885 (SIZE_T_FMT_TYPE)end);
887 for (x = start; x < end; x++)
889 if (pSTE[x].status == 'E')
891 DebugPrint(DEBUG_INFO,SECTION_ELEMENT,
892 "###### END find_empty [" SIZE_T_FMT "]\n", x);
897 DebugPrint(DEBUG_ERROR,SECTION_ELEMENT,"###### END find_empty [-1]\n");
902 * See if the tape is loaded based on the information we
903 * got back from the ReadElementStatus
905 * -1 -> Error (Fatal)
906 * 0 -> drive is empty
907 * 1 -> drive is loaded
914 extern OpenFiles_T *pDev;
916 DebugPrint(DEBUG_INFO,SECTION_TAPE,"###### START drive_loaded\n");
917 DebugPrint(DEBUG_INFO,SECTION_TAPE,"%-20s : fd %d drivenum %d \n", "drive_loaded", fd, drivenum);
920 if (ElementStatusValid == 0)
922 if (pDev[INDEX_CHANGER].functions->function_status(INDEX_CHANGER, 1) != 0)
924 DebugPrint(DEBUG_ERROR,SECTION_TAPE,"Fatal error\n");
930 if (pDTE[drivenum].status == 'E') {
931 DebugPrint(DEBUG_INFO,SECTION_TAPE,"###### STOP drive_loaded (empty)\n");
935 DebugPrint(DEBUG_INFO,SECTION_TAPE,"###### STOP drive_loaded (not empty)\n");
941 * unload the specified drive into the specified slot
945 * Check if the MTE is empty
953 extern OpenFiles_T *pDev;
954 extern int do_inventory;
957 DebugPrint(DEBUG_INFO, SECTION_TAPE,"###### START unload\n");
958 DebugPrint(DEBUG_INFO, SECTION_TAPE,"%-20s : fd %d, slot %d, drive %d \n", "unload", fd, slot, drive);
959 pbarcoderes = alloc(SIZEOF(MBC_T));
960 memset(pbarcoderes, 0, SIZEOF(MBC_T));
963 * If the Element Status is not valid try to
966 if (ElementStatusValid == 0)
968 if (pDev[INDEX_CHANGER].functions->function_status(INDEX_CHANGER , 1) != 0)
970 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"Element Status not valid, reset failed\n");
971 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"##### STOP unload (-1)\n");
978 DebugPrint(DEBUG_INFO, SECTION_TAPE,"%-20s : unload drive %d[%d] slot %d[%d]\n", "unload",
985 * Unloading an empty tape unit makes no sense
986 * so return with an error
988 if (pDTE[drive].status == 'E')
990 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"unload : Drive %d address %d is empty\n", drive, pDTE[drive].address);
991 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"##### STOP unload (-1)\n");
998 * If the destination slot is full
999 * try to find an enpty slot
1001 if (pSTE[slot].status == 'F')
1003 DebugPrint(DEBUG_INFO, SECTION_TAPE,"unload : Slot %d address %d is full\n", drive, pSTE[slot].address);
1004 if ( ElementStatusValid == 0)
1006 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "unload: Element Status not valid, can't find an empty slot\n");
1012 slot = find_empty(fd, 0, 0);
1015 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "unload: No Empty slot found\n");
1020 DebugPrint(DEBUG_INFO, SECTION_TAPE,"unload : found empty one, try to unload to slot %d\n", slot);
1026 * If eject is not set we must read the label info
1029 if (changer->eject == 0)
1031 if (pDev[INDEX_TAPE].avail == 1 && (changer->emubarcode == 1 || BarCode(INDEX_CHANGER)))
1034 if (pDev[INDEX_TAPECTL].SCSI == 1 && pDev[INDEX_TAPECTL].avail) {
1035 pDev[INDEX_TAPECTL].functions->function_rewind(INDEX_TAPECTL);
1037 pDev[INDEX_TAPE].functions->function_rewind(INDEX_TAPE);
1040 if (pDev[INDEX_TAPE].devopen == 1)
1042 SCSI_CloseDevice(INDEX_TAPE);
1045 chgscsi_result = (char *)tape_rdlabel(pDev[INDEX_TAPE].dev, &chgscsi_datestamp, &chgscsi_label);
1050 * Do the unload/move
1052 if (pDev[INDEX_CHANGER].functions->function_move(INDEX_CHANGER,
1053 pDTE[drive].address, pSTE[slot].address) != 0) {
1054 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"##### STOP unload (-1 move failed)\n");
1064 if (pDev[INDEX_CHANGER].functions->function_status(INDEX_CHANGER , 1) != 0)
1066 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"##### STOP unload (-1 update status failed)\n");
1073 * Did we get an error from tape_rdlabel
1074 * if no update the vol/label mapping
1075 * If chgscsi_label is NULL don't do it
1077 if (chgscsi_result == NULL && chgscsi_label != NULL && changer->labelfile != NULL)
1080 * OK this is only needed if we have emubarcode set
1081 * There we need an exact inventory to get the search function working
1082 * and returning correct results
1084 if (BarCode(INDEX_CHANGER) == 0 && changer->emubarcode == 1)
1087 * We got something, update the db
1088 * but before check if the db has as entry the slot
1089 * to where we placed the tape, if no force an inventory
1091 pbarcoderes->action = FIND_SLOT;
1092 strncpy(pbarcoderes->data.voltag, chgscsi_label,
1093 SIZEOF(pbarcoderes->data.voltag));
1094 strncpy(pbarcoderes->data.barcode, pSTE[slot].VolTag,
1095 SIZEOF(pbarcoderes->data.barcode));
1096 pbarcoderes->data.slot = 0;
1097 pbarcoderes->data.from = 0;
1098 pbarcoderes->data.LoadCount = 0;
1101 if ( MapBarCode(changer->labelfile, pbarcoderes) == 0) /* Nothing known about this, do an Inventory */
1105 if (slot != pbarcoderes->data.slot)
1107 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"Slot DB out of sync, slot %d != map %d",slot, pbarcoderes->data.slot);
1114 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### STOP unload(0)\n");
1121 * load the media from the specified element (slot) into the
1122 * specified data transfer unit (drive)
1123 * fd -> pointer to the internal device structure pDev
1124 * driver -> which drive in the library
1125 * slot -> the slot number from where to load
1127 * return -> 0 = success
1136 char *result = NULL; /* Needed for the result of tape_rdlabel */
1138 extern OpenFiles_T *pDev;
1139 extern int do_inventory;
1142 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"###### START load\n");
1143 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"%-20s : fd %d, drive %d, slot %d \n", "load", fd, drive, slot);
1144 pbarcoderes = alloc(SIZEOF(MBC_T));
1145 memset(pbarcoderes, 0 , SIZEOF(MBC_T));
1147 if (ElementStatusValid == 0)
1149 if (pDev[fd].functions->function_status(fd, 1) != 0)
1151 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"##### STOP load (-1)\n");
1152 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"##### STOP load (-1 update status failed)\n");
1160 * Check if the requested slot is in the range of available slots
1161 * The library starts counting at 1, we start at 0, so if the request slot
1162 * is ge than the value we got from the ModeSense fail with an return value
1165 if ((size_t)slot >= STE)
1167 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"load : slot %d ge STE %d\n",slot, STE);
1168 ChgExit("load", "slot >= STE", FATAL);
1173 * And the same for the tape drives
1175 if (drive >= (int)DTE)
1177 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"load : drive %d ge DTE %d\n",drive, DTE);
1178 ChgExit("load", "drive >= DTE", FATAL);
1182 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"load : load drive %d[%d] slot %d[%d]\n",drive,
1183 pDTE[drive].address,
1185 pSTE[slot].address);
1187 if (pDTE[drive].status == 'F')
1189 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"load : Drive %d address %d is full\n", drive, pDTE[drive].address);
1190 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"##### STOP load (-1 update status failed)\n");
1196 if (pSTE[slot].status == 'E')
1198 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"load : Slot %d address %d is empty\n", drive, pSTE[slot].address);
1199 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"##### STOP load (-1 update status failed)\n");
1205 ret = pDev[fd].functions->function_move(fd, pSTE[slot].address, pDTE[drive].address);
1210 if (pDev[fd].functions->function_status(fd, 1) != 0)
1212 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"##### STOP load (-1 update status failed)\n");
1219 * Try to read the label
1220 * and update the label/slot database
1222 if (pDev[INDEX_TAPE].avail == 1 && (changer->emubarcode == 1 || BarCode(INDEX_CHANGER)))
1225 if (pDev[INDEX_TAPECTL].SCSI == 1 && pDev[INDEX_TAPECTL].avail) {
1226 pDev[INDEX_TAPECTL].functions->function_rewind(INDEX_TAPECTL);
1228 pDev[INDEX_TAPE].functions->function_rewind(INDEX_TAPE);
1231 if (pDev[INDEX_TAPE].devopen == 1)
1233 SCSI_CloseDevice(INDEX_TAPE);
1236 result = (char *)tape_rdlabel(pDev[INDEX_TAPE].dev, &chgscsi_datestamp, &chgscsi_label);
1240 * Did we get an error from tape_rdlabel
1241 * if no update the vol/label mapping
1243 if (result == NULL && changer->labelfile != NULL && chgscsi_label != NULL )
1246 * We got something, update the db
1247 * but before check if the db has as entry the slot
1248 * to where we placed the tape, if no force an inventory
1250 strncpy(pbarcoderes->data.voltag, chgscsi_label,
1251 SIZEOF(pbarcoderes->data.voltag));
1252 pbarcoderes->data.slot = 0;
1253 pbarcoderes->data.from = 0;
1254 pbarcoderes->data.LoadCount = 0;
1258 * If we have an barcode reader we only do an update
1259 * If emubarcode is set we check if the
1260 * info in the DB is up to date, if no we set the do_inventory flag
1263 if (BarCode(INDEX_CHANGER) == 1 && changer->emubarcode == 0)
1265 pbarcoderes->action = UPDATE_SLOT;
1266 strncpy(pbarcoderes->data.barcode, pDTE[drive].VolTag,
1267 SIZEOF(pbarcoderes->data.barcode));
1268 pbarcoderes->data.LoadCount = 1;
1269 pbarcoderes->data.slot = slot;
1270 MapBarCode(changer->labelfile, pbarcoderes);
1273 if (BarCode(INDEX_CHANGER) == 0 && changer->emubarcode == 1)
1275 pbarcoderes->action = FIND_SLOT;
1276 if (MapBarCode(changer->labelfile, pbarcoderes) == 0) /* Nothing found, do an inventory */
1279 } else { /* We got something, is it correct ? */
1280 if (slot != pbarcoderes->data.slot && do_inventory == 0)
1282 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"Slot DB out of sync, slot %d != map %d",slot, pbarcoderes->data.slot);
1283 ChgExit("Load", "Label DB out of sync", FATAL);
1285 } else { /* OK, so increment the load count */
1286 pbarcoderes->action = UPDATE_SLOT;
1287 pbarcoderes->data.LoadCount = 1;
1288 pbarcoderes->data.slot = slot;
1289 MapBarCode(changer->labelfile, pbarcoderes);
1294 if (BarCode(INDEX_CHANGER) == 1 && changer->emubarcode == 1)
1296 ChgExit("Load", "BarCode == 1 and emubarcode == 1", FATAL);
1300 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"##### STOP load (%d)\n",ret);
1305 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"##### STOP load (%d)\n",ret);
1311 * Returns the number of Storage Slots which the library has
1312 * fd -> pointer to the internal devie structure pDev
1313 * return -> Number of slots
1319 extern OpenFiles_T *pDev;
1321 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"###### START get_slot_count\n");
1322 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"%-20s : fd %d\n", "get_slot_count", fd);
1324 if (ElementStatusValid == 0)
1326 pDev[fd].functions->function_status(fd, 1);
1328 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,
1329 "##### STOP get_slot_count (" SIZE_T_FMT ")\n",
1330 (SIZE_T_FMT_TYPE)STE);
1331 return((ssize_t)STE);
1333 * return the number of slots in the robot
1340 * retreive the number of data-transfer devices /Tape drives)
1341 * fd -> pointer to the internal devie structure pDev
1342 * return -> -1 on failure
1349 extern OpenFiles_T *pDev;
1351 DebugPrint(DEBUG_INFO, SECTION_SCSI,"###### START get_drive_count\n");
1352 DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-20s : fd %d\n", "get_drive_count", fd);
1354 if (ElementStatusValid == 0)
1356 if ( pDev[fd].functions->function_status(fd, 1) != 0)
1358 DebugPrint(DEBUG_ERROR, SECTION_SCSI, "Error getting drive count\n");
1359 DebugPrint(DEBUG_ERROR, SECTION_SCSI, "##### STOP get_drive_count (-1)\n");
1364 DebugPrint(DEBUG_INFO, SECTION_SCSI,
1365 "###### STOP get_drive_count (" SIZE_T_FMT " drives)\n",
1366 (SIZE_T_FMT_TYPE)DTE);
1367 return((ssize_t)DTE);
1371 * Now the internal functions
1375 * Open the device and placeit in the list of open files
1376 * The OS has to decide if it is an SCSI Commands capable device
1386 extern OpenFiles_T *pDev;
1388 ChangerCMD_T *p = (ChangerCMD_T *)&ChangerIO;
1395 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### START OpenDevice\n");
1396 DebugPrint(DEBUG_INFO, SECTION_SCSI,"OpenDevice : %s\n", DeviceName);
1398 pDev[ip].ConfigName = strdup(ConfigName);
1399 pDev[ip].dev = strdup(DeviceName);
1401 if (SCSI_OpenDevice(ip) != 0 )
1403 if (ident != NULL) /* Override by config */
1405 while(p->ident != NULL)
1407 if (strcmp(ident, p->ident) == 0)
1409 pDev[ip].functions = p;
1410 strncpy(pDev[ip].ident, ident, 17);
1411 DebugPrint(DEBUG_INFO, SECTION_SCSI,"override using ident = %s, type = %s\n",p->ident, p->type);
1412 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP OpenDevice\n");
1418 ChgExit("OpenDevice", "ident not found", FATAL);
1421 while(p->ident != NULL)
1423 if (strcmp(pDev[ip].ident, p->ident) == 0)
1425 pDev[ip].functions = p;
1426 DebugPrint(DEBUG_INFO, SECTION_SCSI,"using ident = %s, type = %s\n",p->ident, p->type);
1427 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP OpenDevice\n");
1434 /* Nothing matching found, try generic */
1435 /* divide generic in generic_type, where type is the */
1436 /* num returned by the inquiry command */
1437 p = (ChangerCMD_T *)&ChangerIO;
1438 snprintf(&tmpstr[0], SIZEOF(tmpstr), "%s_%s","generic",pDev[0].type);
1439 while(p->ident != NULL)
1441 if (strcmp(tmpstr, p->ident) == 0)
1443 pDev[ip].functions = p;
1444 DebugPrint(DEBUG_INFO, SECTION_SCSI,"using ident = %s, type = %s\n",p->ident, p->type);
1445 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP OpenDevice\n");
1451 } else { /* Something failed, lets see what */
1452 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"##### STOP OpenDevice failed\n");
1454 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP OpenDevice (nothing found) !!\n");
1460 * This functions checks if the library has an barcode reader.
1461 * fd -> pointer to the internal devie structure pDev
1468 extern OpenFiles_T *pDev;
1470 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"##### START BarCode\n");
1471 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"%-20s : fd %d\n", "BarCode", fd);
1473 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"Ident = [%s], function = [%s]\n", pDev[fd].ident,
1474 pDev[fd].functions->ident);
1475 ret = pDev[fd].functions->function_barcode(fd);
1476 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"##### STOP BarCode (%d)\n",ret);
1482 * This functions check if the tape drive is ready
1484 * fd -> pointer to the internal devie structure pDev
1485 * wait -> time to wait for the ready status
1493 extern OpenFiles_T *pDev;
1498 RequestSense_T *pRequestSense;
1499 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### START Tape_Ready\n");
1502 * Which device should we use to get the
1507 * First the ioctl tapedevice
1509 if (pDev[INDEX_TAPE].avail == 1)
1515 * But if available and can do SCSI
1518 if (pDev[INDEX_TAPECTL].avail == 1 && pDev[INDEX_TAPECTL].SCSI == 1)
1523 if (pDev[fd].avail == 1 && pDev[fd].SCSI == 0)
1525 DebugPrint(DEBUG_INFO, SECTION_TAPE,"Tape_Ready : Can't send SCSI commands, try ioctl\n");
1527 * Do we get an non negative result.
1528 * If yes this function is available
1529 * and we can use it to get the status
1532 ret = Tape_Status(fd);
1535 while (cnt < wait_time)
1537 if ( ret & TAPE_ONLINE)
1539 DebugPrint(DEBUG_INFO, SECTION_TAPE,"Tape_Ready : Ready after %d seconds\n",cnt);
1540 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### STOP Tape_Ready\n");
1546 ret = Tape_Status(fd);
1549 DebugPrint(DEBUG_INFO, SECTION_TAPE,"Tape_Ready : not ready, stop after %d seconds\n",cnt);
1550 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### STOP Tape_Ready\n");
1555 DebugPrint(DEBUG_INFO, SECTION_TAPE,"Tape_Ready : no ioctl interface, will sleep for %d seconds\n", wait_time);
1557 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### STOP Tape_Ready\n");
1562 pRequestSense = alloc(SIZEOF(RequestSense_T));
1565 * Ignore errors at this point
1570 * Wait until we get an ready condition
1574 while (!done && (cnt < wait_time))
1576 ret = SCSI_TestUnitReady(fd, pRequestSense );
1583 switch (SenseHandler(fd, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
1586 DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeReady (TestUnitReady) SENSE_NO\n");
1589 case SENSE_TAPE_NOT_ONLINE:
1590 DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeReady (TestUnitReady) SENSE_TAPE_NOT_ONLINE\n");
1593 DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeReady (TestUnitReady) SENSE_IGNORE\n");
1597 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"TapeReady (TestUnitReady) SENSE_ABORT\n");
1598 amfree(pRequestSense);
1602 DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeReady (TestUnitReady) SENSE_RETRY\n");
1605 DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeReady (TestUnitReady) default (SENSE)\n");
1611 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"TapeReady (TestUnitReady) SCSI_ERROR\n");
1612 free(pRequestSense);
1616 DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeReady (TestUnitReady) SCSI_BUSY\n");
1619 DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeReady (TestUnitReady) SCSI_CHECK\n");
1622 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"TapeReady (TestUnitReady) unknown (%d)\n",ret);
1629 amfree(pRequestSense);
1630 DebugPrint(DEBUG_INFO, SECTION_TAPE,"Tape_Ready after %d sec\n", cnt);
1631 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### STOP Tape_Ready\n");
1641 SC_COM_T *pSCSICommand;
1644 DebugPrint(DEBUG_INFO, SECTION_SCSI, "##### START DecodeSCSI\n");
1645 pSCSICommand = (SC_COM_T *)&SCSICommand;
1647 while (pSCSICommand->name != NULL)
1649 if (CDB[0] == pSCSICommand->command)
1651 DebugPrint(DEBUG_INFO, SECTION_SCSI,"%s %s", string, pSCSICommand->name);
1652 for (x=0; x < pSCSICommand->length; x++)
1654 DebugPrint(DEBUG_INFO, SECTION_SCSI," %02X", CDB[x]);
1656 DebugPrint(DEBUG_INFO, SECTION_SCSI,"\n");
1657 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP DecodeSCSI\n");
1663 DebugPrint(DEBUG_INFO, SECTION_SCSI,"Not found %X\n", CDB[0]);
1664 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP DecodeSCSI\n");
1676 ReadWriteErrorRecoveryPage_T *prp;
1677 DisconnectReconnectPage_T *pdrp;
1678 size_t length = (size_t)buffer[0] - 4 - offset;
1680 (void)pstring; /* Quiet unused parameter warning */
1682 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### START DecodeModeSense\n");
1684 dump_hex(buffer, 255, DEBUG_INFO, SECTION_SCSI);
1686 /* Jump over the Parameter List header and an offset if we have something
1687 * Unknown at the start (ADIC-218) at the moment
1690 buffer = buffer + 4 + offset;
1692 DebugPrint(DEBUG_INFO, SECTION_SCSI,"buffer length = %d\n", length);
1694 if (block) /* Do we have an block descriptor page ?*/
1697 fprintf(out, "DecodeModeSense : Density Code %x\n", (unsigned)buffer[0]);
1701 fprintf(out, "DecodeModeSense : Number of Blocks %d\n", V3(buffer));
1702 buffer = buffer + 4;
1705 fprintf(out, "DecodeModeSense : Block Length %d\n", V3(buffer));
1706 buffer = buffer + 3;
1711 switch (*buffer & 0x3f)
1714 pVendorUnique = buffer;
1718 prp = (ReadWriteErrorRecoveryPage_T *)buffer;
1721 fprintf(out, "DecodeModeSense : Read/Write Error Recovery Page\n");
1722 fprintf(out,"\tTransfer Block %d\n", prp->tb);
1723 fprintf(out,"\tEnable Early Recovery %d\n", prp->eer);
1724 fprintf(out,"\tPost Error %d\n", prp->per);
1725 fprintf(out,"\tDisable Transfer on Error %d\n", prp->dte);
1726 fprintf(out,"\tDisable ECC Correction %d\n", prp->dcr);
1727 fprintf(out,"\tRead Retry Count %d\n", prp->ReadRetryCount);
1728 fprintf(out,"\tWrite Retry Count %d\n", prp->WriteRetryCount);
1733 pdrp = (DisconnectReconnectPage_T *)buffer;
1736 fprintf(out, "DecodeModeSense : Disconnect/Reconnect Page\n");
1737 fprintf(out,"\tBuffer Full Ratio %d\n", pdrp->BufferFullRatio);
1738 fprintf(out,"\tBuffer Empty Ratio %d\n", pdrp->BufferEmptyRatio);
1739 fprintf(out,"\tBus Inactivity Limit %d\n",
1740 V2(pdrp->BusInactivityLimit));
1741 fprintf(out,"\tDisconnect Time Limit %d\n",
1742 V2(pdrp->DisconnectTimeLimit));
1743 fprintf(out,"\tConnect Time Limit %d\n",
1744 V2(pdrp->ConnectTimeLimit));
1745 fprintf(out,"\tMaximum Burst Size %d\n",
1746 V2(pdrp->MaximumBurstSize));
1747 fprintf(out,"\tDTDC %d\n", pdrp->DTDC);
1752 pEAAPage = (EAAPage_T *)buffer;
1755 fprintf(out,"DecodeModeSense : Element Address Assignment Page\n");
1756 fprintf(out,"\tMedium Transport Element Address %d\n",
1757 V2(pEAAPage->MediumTransportElementAddress));
1758 fprintf(out,"\tNumber of Medium Transport Elements %d\n",
1759 V2(pEAAPage->NoMediumTransportElements));
1760 fprintf(out, "\tFirst Storage Element Address %d\n",
1761 V2(pEAAPage->FirstStorageElementAddress));
1762 fprintf(out, "\tNumber of Storage Elements %d\n",
1763 V2(pEAAPage->NoStorageElements));
1764 fprintf(out, "\tFirst Import/Export Element Address %d\n",
1765 V2(pEAAPage->FirstImportExportElementAddress));
1766 fprintf(out, "\tNumber of ImportExport Elements %d\n",
1767 V2(pEAAPage->NoImportExportElements));
1768 fprintf(out, "\tFirst Data Transfer Element Address %d\n",
1769 V2(pEAAPage->FirstDataTransferElementAddress));
1770 fprintf(out, "\tNumber of Data Transfer Elements %d\n",
1771 V2(pEAAPage->NoDataTransferElements));
1776 pDeviceCapabilitiesPage = (DeviceCapabilitiesPage_T *)buffer;
1779 fprintf(out, "DecodeModeSense : MT can store data cartridges %d\n",
1780 pDeviceCapabilitiesPage->MT);
1781 fprintf(out, "DecodeModeSense : ST can store data cartridges %d\n",
1782 pDeviceCapabilitiesPage->ST);
1783 fprintf(out, "DecodeModeSense : IE can store data cartridges %d\n",
1784 pDeviceCapabilitiesPage->IE);
1785 fprintf(out, "DecodeModeSense : DT can store data cartridges %d\n",
1786 pDeviceCapabilitiesPage->DT);
1787 fprintf(out, "DecodeModeSense : MT to MT %d\n",
1788 pDeviceCapabilitiesPage->MT2MT);
1789 fprintf(out, "DecodeModeSense : MT to ST %d\n",
1790 pDeviceCapabilitiesPage->MT2ST);
1791 fprintf(out, "DecodeModeSense : MT to IE %d\n",
1792 pDeviceCapabilitiesPage->MT2IE);
1793 fprintf(out, "DecodeModeSense : MT to DT %d\n",
1794 pDeviceCapabilitiesPage->MT2DT);
1795 fprintf(out, "DecodeModeSense : ST to MT %d\n",
1796 pDeviceCapabilitiesPage->ST2ST);
1797 fprintf(out, "DecodeModeSense : ST to MT %d\n",
1798 pDeviceCapabilitiesPage->ST2ST);
1799 fprintf(out, "DecodeModeSense : ST to DT %d\n",
1800 pDeviceCapabilitiesPage->ST2DT);
1801 fprintf(out, "DecodeModeSense : IE to MT %d\n",
1802 pDeviceCapabilitiesPage->IE2MT);
1803 fprintf(out, "DecodeModeSense : IE to ST %d\n",
1804 pDeviceCapabilitiesPage->IE2IE);
1805 fprintf(out, "DecodeModeSense : IE to ST %d\n",
1806 pDeviceCapabilitiesPage->IE2DT);
1807 fprintf(out, "DecodeModeSense : IE to ST %d\n",
1808 pDeviceCapabilitiesPage->IE2DT);
1809 fprintf(out, "DecodeModeSense : DT to MT %d\n",
1810 pDeviceCapabilitiesPage->DT2MT);
1811 fprintf(out, "DecodeModeSense : DT to ST %d\n",
1812 pDeviceCapabilitiesPage->DT2ST);
1813 fprintf(out, "DecodeModeSense : DT to IE %d\n",
1814 pDeviceCapabilitiesPage->DT2IE);
1815 fprintf(out, "DecodeModeSense : DT to DT %d\n",
1816 pDeviceCapabilitiesPage->DT2DT);
1821 buffer++; /* set pointer to the length information */
1824 /* Error if *buffer (length) is 0 */
1827 /* EAAPage = NULL; */
1828 /* DeviceCapabilitiesPage = NULL; */
1832 length = length - (size_t)*buffer - 2;
1833 buffer = buffer + (size_t)*buffer + 1;
1840 RequestSense_T * sense,
1849 fprintf(out,"##### START DecodeSense\n");
1850 fprintf(out,"%sSense Keys\n", pstring);
1851 if (sense->ErrorCode == 0x70)
1853 fprintf(out,"\tExtended Sense \n");
1855 fprintf(out,"\tErrorCode %02x\n", sense->ErrorCode);
1856 fprintf(out,"\tValid %d\n", sense->Valid);
1858 fprintf(out,"\tASC %02X\n", sense->AdditionalSenseCode);
1859 fprintf(out,"\tASCQ %02X\n", sense->AdditionalSenseCodeQualifier);
1860 fprintf(out,"\tSense key %02X\n", sense->SenseKey);
1861 switch (sense->SenseKey)
1864 fprintf(out,"\t\tNo Sense\n");
1867 fprintf(out,"\t\tRecoverd Error\n");
1870 fprintf(out,"\t\tNot Ready\n");
1873 fprintf(out,"\t\tMedium Error\n");
1876 fprintf(out,"\t\tHardware Error\n");
1879 fprintf(out,"\t\tIllegal Request\n");
1882 fprintf(out,"\t\tUnit Attention\n");
1885 fprintf(out,"\t\tData Protect\n");
1888 fprintf(out,"\t\tBlank Check\n");
1891 fprintf(out,"\t\tVendor uniq\n");
1894 fprintf(out,"\t\tCopy Aborted\n");
1897 fprintf(out,"\t\tAborted Command\n");
1900 fprintf(out,"\t\tEqual\n");
1903 fprintf(out,"\t\tVolume Overflow\n");
1906 fprintf(out,"\t\tMiscompare\n");
1909 fprintf(out,"\t\tReserved\n");
1917 ExtendedRequestSense_T * sense,
1921 ExtendedRequestSense_T *p;
1923 fprintf(out,"##### START DecodeExtSense\n");
1926 fprintf(out,"%sExtended Sense\n", pstring);
1927 DecodeSense((RequestSense_T *)p, pstring, out);
1928 fprintf(out,"\tLog Parameter Page Code %02X\n", sense->LogParameterPageCode);
1929 fprintf(out,"\tLog Parameter Code %02X\n", sense->LogParameterCode);
1930 fprintf(out,"\tUnderrun/Overrun Counter %02X\n", sense->UnderrunOverrunCounter);
1931 fprintf(out,"\tRead/Write Error Counter %d\n", V3((char *)sense->ReadWriteDataErrorCounter));
1932 if (sense->AdditionalSenseLength > (u_char)sizeof(RequestSense_T))
1935 fprintf(out,"\tPower Fail\n");
1937 fprintf(out,"\tSCSI Bus Parity Error\n");
1939 fprintf(out,"\tFormatted Buffer parity Error\n");
1941 fprintf(out,"\tMedia Error\n");
1943 fprintf(out,"\tError Counter Overflow\n");
1945 fprintf(out,"\tTapeMotion Error\n");
1947 fprintf(out,"\tTape Not Present\n");
1949 fprintf(out,"\tLogical Beginning of tape\n");
1951 fprintf(out,"\tTape Mark Detect Error\n");
1953 fprintf(out,"\tWrite Protect\n");
1955 fprintf(out,"\tFilemark Error\n");
1957 fprintf(out,"\tUnder Run Error\n");
1959 fprintf(out,"\tWrite Error 1\n");
1961 fprintf(out,"\tServo System Error\n");
1963 fprintf(out,"\tFormatter Error\n");
1965 fprintf(out,"\tCleaning Cartridge is empty\n");
1967 fprintf(out,"\tReverse Retries Required\n");
1969 fprintf(out,"\tTape Drive has been cleaned\n");
1971 fprintf(out,"\tTape Drive needs to be cleaned\n");
1973 fprintf(out,"\tPhysical End of Tape\n");
1975 fprintf(out,"\tWrite Splice Error\n");
1977 fprintf(out,"\tWrite Splice Error\n");
1978 fprintf(out,"\tRemaing 1024 byte tape blocks %d\n", V3((char *)sense->RemainingTape));
1979 fprintf(out,"\tTracking Retry Counter %02X\n", sense->TrackingRetryCounter);
1980 fprintf(out,"\tRead/Write Retry Counter %02X\n", sense->ReadWriteRetryCounter);
1981 fprintf(out,"\tFault Sympton Code %02X\n", sense->FaultSymptomCode);
1988 SCSIInquiry_T * SCSIInquiry)
1990 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### START PrintInquiry\n");
1991 DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-15s %x\n", "qualifier", SCSIInquiry->qualifier);
1992 DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-15s %x\n", "type", SCSIInquiry->type);
1993 DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-15s %x\n", "data_format", SCSIInquiry->data_format);
1994 DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-15s %X\n", "ansi_version", SCSIInquiry->ansi_version);
1995 DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-15s %X\n", "ecma_version", SCSIInquiry->ecma_version);
1996 DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-15s %X\n", "iso_version", SCSIInquiry->iso_version);
1997 DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-15s %X\n", "type_modifier", SCSIInquiry->type_modifier);
1998 DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-15s %x\n", "removable", SCSIInquiry->removable);
1999 DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-15s %.8s\n", "vendor_info", SCSIInquiry->vendor_info);
2000 DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-15s %.16s\n", "prod_ident", SCSIInquiry->prod_ident);
2001 DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-15s %.4s\n", "prod_version", SCSIInquiry->prod_version);
2002 DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-15s %.19s\n", "vendor_specific", SCSIInquiry->vendor_specific);
2010 dbprintf(("##### START DoNothing\n"));
2018 (void)unused1; /* Quiet unused parameter warning */
2020 dbprintf(("##### START DoNothing\n"));
2029 (void)unused1; /* Quiet unused parameter warning */
2030 (void)unused2; /* Quiet unused parameter warning */
2032 dbprintf(("##### START DoNothing\n"));
2042 (void)unused1; /* Quiet unused parameter warning */
2043 (void)unused2; /* Quiet unused parameter warning */
2044 (void)unused3; /* Quiet unused parameter warning */
2046 dbprintf(("##### START DoNothing\n"));
2053 dbprintf(("##### START GenericFree\n"));
2060 dbprintf(("##### START GenericSearch\n"));
2068 extern OpenFiles_T *pDev;
2070 ModePageTreeFrogVendorUnique_T *pVendor;
2072 dbprintf(("##### START TreeFrogBarCode\n"));
2073 if (pModePage == NULL)
2075 pModePage = alloc(0xff);
2078 if (SCSI_ModeSense(DeviceFD, pModePage, 0xff, 0x0, 0x3f) == 0)
2080 DecodeModeSense(pModePage, 0, "TreeFrogBarCode :", 0, debug_file);
2082 if (pVendorUnique == NULL)
2084 dbprintf(("TreeFrogBarCode : no pVendorUnique\n"));
2088 pVendor = ( ModePageTreeFrogVendorUnique_T *)pVendorUnique;
2090 dbprintf(("TreeFrogBarCode : EBARCO %d\n", pVendor->EBARCO));
2091 dbprintf(("TreeFrogCheckSum : CHKSUM %d\n", pVendor->CHKSUM));
2093 dump_hex((u_char *)pDev[INDEX_CHANGER].inquiry, INQUIRY_SIZE, DEBUG_INFO, SECTION_ELEMENT);
2094 return(pVendor->EBARCO);
2104 extern OpenFiles_T *pDev;
2106 ModePageEXB120VendorUnique_T *pVendor;
2107 ModePageEXB120VendorUnique_T *pVendorWork;
2109 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"##### START EXB_BarCode\n");
2110 if (pModePage == NULL && LibModeSenseValid == 0)
2112 pModePage = alloc(0xff);
2114 if (SCSI_ModeSense(DeviceFD, pModePage, 0xff, 0x8, 0x3f) == 0)
2116 DecodeModeSense(pModePage, 0, "EXB_BarCode :", 0, debug_file);
2117 LibModeSenseValid = 1;
2119 LibModeSenseValid = -1;
2123 if (LibModeSenseValid == 1)
2125 if (pVendorUnique == NULL)
2127 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"EXB_BarCode : no pVendorUnique\n");
2131 pVendor = ( ModePageEXB120VendorUnique_T *)pVendorUnique;
2133 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"EXB_BarCode : NBL %d\n", pVendor->NBL);
2134 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"EXB_BarCode : PS %d\n", pVendor->PS);
2135 if (pVendor->NBL == 1 && pVendor->PS == 1 )
2137 pVendorWork = alloc((size_t)pVendor->ParameterListLength + 2);
2138 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"EXB_BarCode : setting NBL to 1\n");
2139 memcpy(pVendorWork, pVendor, (size_t)pVendor->ParameterListLength + 2);
2140 pVendorWork->NBL = 0;
2141 pVendorWork->PS = 0;
2142 pVendorWork->RSVD0 = 0;
2143 if (SCSI_ModeSelect(DeviceFD, (u_char *)pVendorWork, (u_char)(pVendorWork->ParameterListLength + 2), 0, 1, 0) == 0)
2145 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"EXB_BarCode : SCSI_ModeSelect OK\n");
2150 /* And now again !!!
2152 GenericResetStatus(DeviceFD);
2154 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"EXB_BarCode : SCSI_ModeSelect failed\n");
2156 amfree(pVendorWork);
2158 dump_hex((u_char *)pDev[INDEX_CHANGER].inquiry, INQUIRY_SIZE, DEBUG_INFO, SECTION_BARCODE);
2159 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"EXB_BarCode : vendor_specific[19] %x\n",
2160 pDev[INDEX_CHANGER].inquiry->vendor_specific[19]);
2169 (void)DeviceFD; /* Quiet unused parameter warning */
2171 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"##### START NoBarCode\n");
2172 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"##### STOP NoBarCode\n");
2180 (void)DeviceFD; /* Quiet unused parameter warning */
2182 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"##### START GenericBarCode\n");
2183 if ( changer->havebarcode >= 1)
2185 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"##### STOP GenericBarCode (havebarcode) => %d\n",changer->havebarcode);
2189 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"##### STOP GenericBarCode => 0\n");
2198 u_char AdditionalSenseCode,
2199 u_char AdditionalSenseCodeQualifier,
2200 RequestSense_T * buffer)
2202 extern OpenFiles_T *pDev;
2204 dbprintf(("##### START SenseHandler\n"));
2205 if (pDev[DeviceFD].inqdone == 1)
2207 dbprintf(("Ident = [%s], function = [%s]\n", pDev[DeviceFD].ident,
2208 pDev[DeviceFD].functions->ident));
2209 ret = pDev[DeviceFD].functions->function_error(DeviceFD, flag, SenseKey, AdditionalSenseCode, AdditionalSenseCodeQualifier, buffer);
2211 dbprintf((" Ups no sense\n"));
2213 dbprintf(("#### STOP SenseHandler\n"));
2218 * Try to get information about the tape,
2219 * Tape loaded ? Online etc
2220 * Use the mtio ioctl to get the information if no SCSI Path
2221 * to the tape drive is available.
2224 * Pass an parameter to identify which unit to use
2225 * if there are more than one
2226 * Implement the SCSI path if available
2231 extern OpenFiles_T *pDev;
2235 RequestSense_T *pRequestSense;
2237 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### START TapeStatus\n");
2240 * If it is an device which understand SCSI commands the
2241 * normal ioctl (MTIOCGET for example) may fail
2244 if (pDev[INDEX_TAPECTL].SCSI == 1)
2246 pRequestSense = alloc(SIZEOF(RequestSense_T));
2247 memset(pRequestSense, 0, SIZEOF(RequestSense_T));
2249 for (done = 0, cnt = 0; !done && (cnt < 60); cnt++)
2251 ret = SCSI_TestUnitReady(INDEX_TAPECTL, pRequestSense);
2252 DebugPrint(DEBUG_INFO, SECTION_SCSI, "TapeStatus TestUnitReady ret %d\n",ret);
2257 switch (SenseHandler(INDEX_TAPECTL, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
2261 DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeStatus (TestUnitReady) SENSE_NO\n");
2262 pDTE[0].status = 'F';
2263 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### FULL\n");
2267 case SENSE_TAPE_NOT_ONLINE:
2268 DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeStatus (TestUnitReady) SENSE_TAPE_NOT_ONLINE\n");
2269 pDTE[0].status = 'E';
2270 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### EMPTY\n");
2275 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"TapeStatus (TestUnitReady) SENSE_ABORT\n");
2280 DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeStatus (TestUnitReady) SENSE_RETRY\n");
2284 DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeStatus (TestUnitReady) default (SENSE)\n");
2290 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"TapeStatus (TestUnitReady) SCSI_ERROR\n");
2295 DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeStatus (TestUnitReady) SCSI_BUSY\n");
2299 DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeStatus (TestUnitReady) SCSI_CHECK\n");
2303 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"TapeStatus (TestUnitReady) unknown (%d)\n",ret);
2310 amfree(pRequestSense);
2312 ret = Tape_Status(INDEX_TAPE);
2313 if ( ret & TAPE_ONLINE)
2315 pDTE[0].status ='F';
2316 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### FULL\n");
2318 pDTE[0].status = 'E';
2319 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### EMPTY\n");
2321 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### STOP TapeStatus\n");
2331 extern OpenFiles_T *pDev;
2333 RequestSense_T *pRequestSense;
2334 ExtendedRequestSense_T *pExtendedRequestSense;
2339 (void)Device; /* Quiet unused parameter warning */
2341 dbprintf(("##### START DLT4000Eject\n"));
2343 pRequestSense = alloc(SIZEOF(RequestSense_T));
2344 pExtendedRequestSense = alloc(SIZEOF(ExtendedRequestSense_T));
2348 dbprintf(("DLT4000Eject : use mtio ioctl for eject on %s\n", pDev[INDEX_TAPE].dev));
2349 free(pExtendedRequestSense);
2350 free(pRequestSense);
2351 return(Tape_Ioctl(INDEX_TAPE, IOCTL_EJECT));
2357 if (pDev[INDEX_TAPECTL].SCSI == 0)
2359 dbprintf(("DLT4000Eject : Device %s not able to receive SCSI commands\n", pDev[INDEX_TAPE].dev));
2360 free(pExtendedRequestSense);
2361 free(pRequestSense);
2362 return(Tape_Ioctl(INDEX_TAPE, IOCTL_EJECT));
2367 dbprintf(("DLT4000Eject : SCSI eject on %s = %s\n", pDev[INDEX_TAPECTL].dev, pDev[INDEX_TAPECTL].ConfigName));
2369 RequestSense(INDEX_TAPECTL, pExtendedRequestSense, 0);
2370 DecodeExtSense(pExtendedRequestSense, "DLT4000Eject : ", debug_file);
2371 /* Unload the tape, 0 == wait for success
2374 ret = SCSI_LoadUnload(INDEX_TAPECTL, pRequestSense, 0, 0);
2376 RequestSense(INDEX_TAPECTL, pExtendedRequestSense, 0);
2377 DecodeExtSense(pExtendedRequestSense, "DLT4000Eject : ", debug_file);
2381 free(pExtendedRequestSense);
2382 free(pRequestSense);
2388 while (!done && cnt < 300)
2390 ret = SCSI_TestUnitReady(INDEX_TAPECTL, pRequestSense);
2391 DebugPrint(DEBUG_INFO, SECTION_SCSI, "DLT4000Eject TestUnitReady ret %d\n",ret);
2398 switch (SenseHandler(INDEX_TAPECTL, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
2401 DebugPrint(DEBUG_INFO, SECTION_SCSI,"DLT4000Eject (TestUnitReady) SENSE_NO\n");
2404 case SENSE_TAPE_NOT_ONLINE:
2405 DebugPrint(DEBUG_INFO, SECTION_SCSI,"DLT4000Eject (TestUnitReady) SENSE_TAPE_NOT_ONLINE\n");
2409 DebugPrint(DEBUG_INFO, SECTION_SCSI,"DLT4000Eject (TestUnitReady) SENSE_IGNORE\n");
2413 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"DLT4000Eject (TestUnitReady) SENSE_ABORT\n");
2414 free(pExtendedRequestSense);
2415 free(pRequestSense);
2419 DebugPrint(DEBUG_INFO, SECTION_SCSI,"DLT4000Eject (TestUnitReady) SENSE_RETRY\n");
2422 DebugPrint(DEBUG_INFO, SECTION_SCSI,"DLT4000Eject (TestUnitReady) default (SENSE)\n");
2428 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"DLT4000Eject (TestUnitReady) SCSI_ERROR\n");
2429 free(pExtendedRequestSense);
2430 free(pRequestSense);
2434 DebugPrint(DEBUG_INFO, SECTION_SCSI,"DLT4000Eject (TestUnitReady) SCSI_BUSY\n");
2437 DebugPrint(DEBUG_INFO, SECTION_SCSI,"DLT4000Eject (TestUnitReady) SCSI_CHECK\n");
2440 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"DLT4000Eject (TestUnitReady) unknown (%d)\n",ret);
2448 dbprintf(("DLT4000Eject : Ready after %d sec, done = %d\n", cnt * 2, done));
2450 free(pExtendedRequestSense);
2451 free(pRequestSense);
2457 * Ejects an tape either with the ioctl interface
2458 * or by using the SCSI interface if available.
2461 * Before unload check if there is an tape in the drive
2469 extern OpenFiles_T *pDev;
2470 RequestSense_T *pRequestSense;
2475 (void)Device; /* Quiet unused parameter warning */
2476 (void)type; /* Quiet unused parameter warning */
2478 DebugPrint(DEBUG_INFO, SECTION_TAPE, "##### START GenericEject\n");
2480 pRequestSense = alloc(SIZEOF(RequestSense_T));
2482 DebugPrint(DEBUG_INFO, SECTION_TAPE,"GenericEject : SCSI eject on %s = %s\n",
2483 pDev[INDEX_TAPECTL].dev, pDev[INDEX_TAPECTL].ConfigName);
2486 * Can we use SCSI commands ?
2488 if (pDev[INDEX_TAPECTL].SCSI == 1)
2490 LogSense(INDEX_TAPECTL);
2492 * Unload the tape, 1 == don't wait for success
2495 ret = SCSI_LoadUnload(INDEX_TAPECTL, pRequestSense, 1, 0);
2499 free(pRequestSense);
2505 while (!done && cnt < 300)
2507 ret = SCSI_TestUnitReady(INDEX_TAPECTL, pRequestSense);
2508 DebugPrint(DEBUG_INFO, SECTION_SCSI, "GenericEject TestUnitReady ret %d\n",ret);
2513 switch (SenseHandler(INDEX_TAPECTL, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
2516 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericEject (TestUnitReady) SENSE_NO\n");
2518 case SENSE_TAPE_NOT_ONLINE:
2519 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericEject (TestUnitReady) SENSE_TAPE_NOT_ONLINE\n");
2523 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericEject (TestUnitReady) SENSE_IGNORE\n");
2526 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"GenericEject (TestUnitReady) SENSE_ABORT\n");
2527 free(pRequestSense);
2531 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericEject (TestUnitReady) SENSE_RETRY\n");
2534 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericEject (TestUnitReady) default (SENSE)\n");
2539 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"GenericEject (TestUnitReady) SCSI_ERROR\n");
2540 free(pRequestSense);
2544 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericEject (TestUnitReady) SCSI_BUSY\n");
2547 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericEject (TestUnitReady) SCSI_CHECK\n");
2550 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"GenericEject (TestUnitReady) unknown (%d)\n",ret);
2557 DebugPrint(DEBUG_INFO, SECTION_TAPE,"GenericEject : Device can't understand SCSI try ioctl\n");
2558 Tape_Ioctl(INDEX_TAPECTL, IOCTL_EJECT);
2560 DebugPrint(DEBUG_INFO, SECTION_TAPE,
2561 "GenericEject : Ready after %d sec\n", cnt * 2);
2562 free(pRequestSense);
2570 * Make the retry counter an config option,
2581 extern OpenFiles_T *pDev;
2582 RequestSense_T *pRequestSense;
2583 char *errstr; /* Used by tape_rewind */
2588 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### START GenericRewind pDEV -> %d\n",DeviceFD);
2592 * If we can use the SCSI device than use it, else use the ioctl
2595 if (pDev[DeviceFD].SCSI == 1)
2597 pRequestSense = alloc(SIZEOF(RequestSense_T));
2600 * Before doing the rewind check if the tape is ready to accept commands
2606 ret = SCSI_TestUnitReady(DeviceFD, (RequestSense_T *)pRequestSense );
2607 DebugPrint(DEBUG_INFO, SECTION_TAPE, "GenericRewind (TestUnitReady) ret %d\n",ret);
2614 switch (SenseHandler(DeviceFD, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
2617 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) SENSE_NO\n");
2620 case SENSE_TAPE_NOT_ONLINE:
2621 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) SENSE_TAPE_NOT_ONLINE\n");
2622 free(pRequestSense);
2626 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) SENSE_IGNORE\n");
2630 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"GenericRewind (TestUnitReady) SENSE_ABORT\n");
2631 free(pRequestSense);
2635 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) SENSE_RETRY\n");
2638 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) default (SENSE)\n");
2641 } /* switch (SenseHandler(DeviceFD, 0, pRequestSense->SenseKey.... */
2645 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"GenericRewind (TestUnitReady) SCSI_ERROR\n");
2646 free(pRequestSense);
2651 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) SCSI_BUSY\n");
2654 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) SCSI_CHECK\n");
2657 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"GenericRewind (TestUnitReady) unknown (%d)\n",ret);
2662 DebugPrint(DEBUG_INFO, SECTION_TAPE," Wait .... (%d)\n",cnt);
2665 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"##### STOP GenericRewind (-1)\n");
2666 free(pRequestSense);
2674 CDB[0] = SC_COM_REWIND;
2684 ret = SCSI_Run(DeviceFD, Input, CDB, 6,
2687 SIZEOF(RequestSense_T));
2689 DecodeSense(pRequestSense, "GenericRewind : ", debug_file);
2693 if (pRequestSense->SenseKey != UNIT_ATTENTION)
2704 DebugPrint(DEBUG_INFO, SECTION_TAPE,"GenericRewind : failed %d\n", ret);
2710 while (!done && (cnt < 300))
2712 ret = SCSI_TestUnitReady(DeviceFD, pRequestSense);
2713 DebugPrint(DEBUG_INFO, SECTION_SCSI, "GenericRewind TestUnitReady ret %d\n",ret);
2720 switch (SenseHandler(DeviceFD, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
2723 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) SENSE_NO\n");
2726 case SENSE_TAPE_NOT_ONLINE:
2727 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) SENSE_TAPE_NOT_ONLINE\n");
2728 free(pRequestSense);
2732 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) SENSE_IGNORE\n");
2736 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"GenericRewind (TestUnitReady) SENSE_ABORT\n");
2737 free(pRequestSense);
2741 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) SENSE_RETRY\n");
2744 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) default (SENSE)\n");
2750 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"GenericRewind (TestUnitReady) SCSI_ERROR\n");
2755 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) SCSI_BUSY\n");
2758 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) SCSI_CHECK\n");
2761 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"GenericRewind (TestUnitReady) unknown (%d)\n",ret);
2769 amfree(pRequestSense);
2771 DebugPrint(DEBUG_INFO, SECTION_TAPE,"GenericRewind : Ready after %d sec, "
2772 "done = %d\n", cnt * 2, done);
2773 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### STOP GenericRewind (0)\n");
2775 DebugPrint(DEBUG_INFO, SECTION_TAPE,"GenericRewind : use ioctl rewind\n");
2776 if (pDev[DeviceFD].devopen == 1)
2778 DebugPrint(DEBUG_INFO, SECTION_TAPE,"Close Device\n");
2779 SCSI_CloseDevice(DeviceFD);
2781 /* We don't retry if it fails; that is left to the vtape driver. */
2782 if ((errstr = tape_rewind(pDev[DeviceFD].dev)) == NULL) {
2783 DebugPrint(DEBUG_INFO, SECTION_TAPE,"Rewind OK,\n", cnt);
2785 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"Rewind failed %s\n",errstr);
2786 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### STOP GenericRewind (-1)\n");
2790 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### STOP GenericRewind (0)\n");
2798 * Check if the tape has the tape clean
2799 * bit set in the return of an request sense
2806 extern OpenFiles_T *pDev;
2807 ExtendedRequestSense_T ExtRequestSense;
2810 (void)Device; /* Quiet unused parameter warning */
2812 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### START GenericClean\n");
2813 if (pDev[INDEX_TAPECTL].SCSI == 0)
2815 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"GenericClean : can't send SCSI commands\n");
2816 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"##### STOP GenericClean\n");
2822 * Request Sense Data, reset the counter
2824 if ( RequestSense(INDEX_TAPECTL, &ExtRequestSense, 1) == 0)
2827 DecodeExtSense(&ExtRequestSense, "GenericClean : ", debug_file);
2828 if(ExtRequestSense.CLN) {
2834 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"Got error from RequestSense\n");
2836 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### STOP GenericClean (%d)\n",ret);
2845 RequestSense_T *pRequestSense;
2849 DebugPrint(DEBUG_INFO, SECTION_ELEMENT, "##### START GenericResetStatus\n");
2851 pRequestSense = alloc(SIZEOF(RequestSense_T));
2855 CDB[0] = SC_COM_IES; /* */
2863 ret = SCSI_Run(DeviceFD, Input, CDB, 6,
2866 SIZEOF(RequestSense_T));
2870 /* fprintf(stderr, "%s: Request Sense[Inquiry]: %02X", */
2871 /* "chs", ((u_char *) &pRequestSense)[0]); */
2872 /* for (i = 1; i < SIZEOF(RequestSense_T); i++) */
2873 /* fprintf(stderr, " %02X", ((u_char *) &pRequestSense)[i]); */
2874 /* fprintf(stderr, "\n"); */
2875 free(pRequestSense);
2881 switch (SenseHandler(DeviceFD, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
2884 free(pRequestSense);
2888 free(pRequestSense);
2893 if (retry < MAX_RETRIES )
2895 DebugPrint(DEBUG_INFO, SECTION_ELEMENT, "GenericResetStatus : retry %d\n", retry);
2898 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "GenericResetStatus : return (-1)\n");
2899 free(pRequestSense);
2905 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "GenericResetStatus : (default) return (-1)\n");
2906 free(pRequestSense);
2914 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "##### STOP GenericResetStatus (%d)\n",ret);
2915 free(pRequestSense);
2919 /* GenericSenseHandler
2920 * Handles the conditions/sense wich is returned by an SCSI command
2921 * pwork is an pointer to the structure OpenFiles_T, which is filled with information
2922 * about the device to which we talk. Information are for example
2923 * The vendor, the ident, which fd, etc. This strucure is filled when we open the
2925 * flag tells how to handle the information passed in the buffer,
2926 * 0 -> Sense Key available
2927 * 1 -> No Sense key available
2928 * buffer is a pointer to the data from the request sense result.
2931 * Limit recursion, may run in an infinite loop
2934 GenericSenseHandler(
2938 u_char AdditionalSenseCode,
2939 u_char AdditionalSenseCodeQualifier,
2940 RequestSense_T * pRequestSense)
2942 extern OpenFiles_T *pDev;
2946 dbprintf(("##### START GenericSenseHandler\n"));
2948 DecodeSense(pRequestSense, "GenericSenseHandler : ", debug_file);
2950 ret = Sense2Action(pDev[ip].ident,
2951 pDev[ip].inquiry->type,
2953 AdditionalSenseCode,
2954 AdditionalSenseCodeQualifier,
2957 dbprintf(("##### STOP GenericSenseHandler\n"));
2962 * Do the move. We don't address the MTE element (the gripper)
2963 * here. We assume that the library use the right MTE.
2964 * The difference to GenericMove is that we do an align element
2969 * != 0 -> error either from the SCSI command or from
2970 * the element handling
2979 extern OpenFiles_T *pDev;
2980 ElementInfo_T *pfrom;
2985 int SDX_MTE = 0; /* This are parameters passed */
2986 int SDX_STE = -1; /* to */
2987 int SDX_DTE = -1; /* AlignElements */
2989 DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### START SDXMove\n");
2991 DebugPrint(DEBUG_INFO, SECTION_MOVE,"%-20s : from = %d, to = %d\n", "SDXMove", from, to);
2994 if ((pfrom = LookupElement(from)) == NULL)
2996 DebugPrint(DEBUG_INFO, SECTION_MOVE,"SDXMove : ElementInfo for %d not found\n", from);
2997 DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP SDXMove\n");
3002 if ((pto = LookupElement(to)) == NULL)
3004 DebugPrint(DEBUG_INFO, SECTION_MOVE,"SDXMove : ElementInfo for %d not found\n", to);
3005 DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP SDXMove\n");
3010 if (pfrom->status == 'E')
3012 DebugPrint(DEBUG_INFO, SECTION_MOVE,"SDXMove : from %d is empty\n", from);
3013 DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP SDXMove\n");
3018 if (pto->status == 'F')
3020 switch (pto->status)
3025 DebugPrint(DEBUG_INFO, SECTION_MOVE,"SDXMove : Destination Element %d Type %d is full\n",
3026 pto->address, pto->type);
3027 to = find_empty(DeviceFD, 0, 0);
3030 DebugPrint(DEBUG_ERROR, SECTION_MOVE,"SDXMove : no empty slot found for unload\n");
3034 DebugPrint(DEBUG_INFO, SECTION_MOVE,"SDXMove : Unload to %d\n", to);
3035 if ((pto = LookupElement(to)) == NULL)
3037 DebugPrint(DEBUG_INFO, SECTION_MOVE, "SDXMove : ElementInfo for %d not found\n", to);
3038 DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP SDXMove\n");
3050 moveok = CheckMove(pfrom, pto);
3055 SDX_DTE = pto->address;
3058 SDX_STE = pto->address;
3061 SDX_STE = pto->address;
3065 switch (pfrom->type)
3068 SDX_DTE = pfrom->address;
3071 SDX_STE = pfrom->address;
3074 SDX_STE = pfrom->address;
3078 if (SDX_DTE >= 0 && SDX_STE >= 0)
3080 ret = SCSI_AlignElements(DeviceFD, SDX_MTE, SDX_DTE, SDX_STE);
3081 DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### SCSI_AlignElemnts ret = %d\n",ret);
3084 DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP SDXMove\n");
3089 DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### Error setting STE/DTE %d/%d\n", SDX_STE, SDX_DTE);
3090 DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP SDXMove\n");
3096 * If from is a tape we must check if it is loaded
3097 * and if yes we have to eject it
3099 if (pfrom->type == TAPETYPE)
3101 tapestat = Tape_Status(INDEX_TAPE);
3102 if ( tapestat & TAPE_ONLINE)
3104 if (pDev[INDEX_TAPECTL].SCSI == 1)
3106 ret = eject_tape(pDev[INDEX_TAPECTL].dev,1);
3108 ret = eject_tape(pDev[INDEX_TAPE].dev,2);
3113 if ((ret == 0) && moveok)
3115 ret = SCSI_Move(DeviceFD, 0, from, to);
3117 DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP SDXMove\n");
3121 DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP SDXMove\n");
3126 * Do the move. We don't address the MTE element (the gripper)
3127 * here. We assume that the library use the right MTE
3131 * != 0 -> error either from the SCSI command or from
3132 * the element handling
3141 ElementInfo_T *pfrom;
3145 DebugPrint(DEBUG_INFO, SECTION_MOVE, "##### START GenericMove\n");
3147 DebugPrint(DEBUG_INFO, SECTION_MOVE, "%-20s : from = %d, to = %d\n", "GenericMove", from, to);
3150 if ((pfrom = LookupElement(from)) == NULL)
3152 DebugPrint(DEBUG_INFO, SECTION_MOVE, "GenericMove : ElementInfo for %d not found\n", from);
3153 DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP GenericMove\n");
3158 if ((pto = LookupElement(to)) == NULL)
3160 DebugPrint(DEBUG_INFO, SECTION_MOVE, "GenericMove : ElementInfo for %d not found\n", to);
3161 DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP GenericMove\n");
3166 if (pfrom->status == 'E')
3168 DebugPrint(DEBUG_INFO, SECTION_MOVE, "GenericMove : from %d is empty\n", from);
3169 DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP GenericMove\n");
3174 if (pto->status == 'F')
3176 DebugPrint(DEBUG_INFO, SECTION_MOVE, "GenericMove : Destination Element %d Type %d is full\n",
3177 pto->address, pto->type);
3178 to = find_empty(DeviceFD, 0, 0);
3181 DebugPrint(DEBUG_ERROR, SECTION_MOVE, "GenericMove : no empty slot found\n");
3185 DebugPrint(DEBUG_INFO, SECTION_MOVE, "GenericMove : Unload to %d\n", to);
3186 if ((pto = LookupElement(to)) == NULL)
3188 DebugPrint(DEBUG_ERROR, SECTION_MOVE, " Ups should not happen\n");
3189 DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP GenericMove\n");
3195 if (CheckMove(pfrom, pto))
3197 ret = SCSI_Move(DeviceFD, 0, from, to);
3200 DebugPrint(DEBUG_INFO, SECTION_MOVE, "GenericMove : SCSI_Move return (%d)\n", ret);
3201 DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP GenericMove\n");
3206 * Check if a move based on the information we got from the Mode Sense command
3215 ElementInfo_T * from,
3220 DebugPrint(DEBUG_INFO, SECTION_MOVE, "##### START CheckMove\n");
3221 if (pDeviceCapabilitiesPage != NULL )
3223 DebugPrint(DEBUG_INFO, SECTION_MOVE, "CheckMove : checking if move from %d to %d is legal\n", from->address, to->address);
3227 DebugPrint(DEBUG_INFO, SECTION_MOVE, "CheckMove : MT2");
3231 if (pDeviceCapabilitiesPage->MT2MT == 1)
3233 DebugPrint(DEBUG_INFO, SECTION_MOVE, "MT\n");
3238 if (pDeviceCapabilitiesPage->MT2ST == 1)
3240 DebugPrint(DEBUG_INFO, SECTION_MOVE, "ST\n");
3245 if (pDeviceCapabilitiesPage->MT2IE == 1)
3247 DebugPrint(DEBUG_INFO, SECTION_MOVE, "IE\n");
3252 if (pDeviceCapabilitiesPage->MT2DT == 1)
3254 DebugPrint(DEBUG_INFO, SECTION_MOVE, "DT\n");
3263 DebugPrint(DEBUG_INFO, SECTION_MOVE, "CheckMove : ST2");
3267 if (pDeviceCapabilitiesPage->ST2MT == 1)
3269 DebugPrint(DEBUG_INFO, SECTION_MOVE, "MT\n");
3274 if (pDeviceCapabilitiesPage->ST2ST == 1)
3276 DebugPrint(DEBUG_INFO, SECTION_MOVE, "ST\n");
3281 if (pDeviceCapabilitiesPage->ST2IE == 1)
3283 DebugPrint(DEBUG_INFO, SECTION_MOVE, "IE\n");
3288 if (pDeviceCapabilitiesPage->ST2DT == 1)
3290 DebugPrint(DEBUG_INFO, SECTION_MOVE, "DT\n");
3299 DebugPrint(DEBUG_INFO, SECTION_MOVE, "CheckMove : IE2");
3303 if (pDeviceCapabilitiesPage->IE2MT == 1)
3305 DebugPrint(DEBUG_INFO, SECTION_MOVE, "MT\n");
3310 if (pDeviceCapabilitiesPage->IE2ST == 1)
3312 DebugPrint(DEBUG_INFO, SECTION_MOVE, "ST\n");
3317 if (pDeviceCapabilitiesPage->IE2IE == 1)
3319 DebugPrint(DEBUG_INFO, SECTION_MOVE, "IE\n");
3324 if (pDeviceCapabilitiesPage->IE2DT == 1)
3326 DebugPrint(DEBUG_INFO, SECTION_MOVE, "DT\n");
3335 DebugPrint(DEBUG_INFO, SECTION_MOVE, "CheckMove : DT2");
3339 if (pDeviceCapabilitiesPage->DT2MT == 1)
3341 DebugPrint(DEBUG_INFO, SECTION_MOVE, "MT\n");
3346 if (pDeviceCapabilitiesPage->DT2ST == 1)
3348 DebugPrint(DEBUG_INFO, SECTION_MOVE, "ST\n");
3353 if (pDeviceCapabilitiesPage->DT2IE == 1)
3355 DebugPrint(DEBUG_INFO, SECTION_MOVE, "IE\n");
3360 if (pDeviceCapabilitiesPage->DT2DT == 1)
3362 DebugPrint(DEBUG_INFO, SECTION_MOVE, "DT\n");
3374 DebugPrint(DEBUG_INFO, SECTION_MOVE, "CheckMove : pDeviceCapabilitiesPage == NULL");
3376 ChgExit("CheckMove", "DeviceCapabilitiesPage == NULL", FATAL);
3381 DebugPrint(DEBUG_INFO, SECTION_MOVE, "###### STOP CheckMove\n");
3393 extern OpenFiles_T *pDev;
3395 dbprintf(("##### START GetCurrentSlot\n"));
3397 (void)fd; /* Quiet unused parameter warning */
3399 if (pDev[0].SCSI == 0)
3401 dbprintf(("GetCurrentSlot : can't send SCSI commands\n"));
3406 if (ElementStatusValid == 0)
3408 if (pDev[0].functions->function_status(0, 1) != 0)
3415 /* If the from address is the as the same as the tape address skip it */
3416 if (pDTE[drive].from >= 0 && pDTE[drive].from != pDTE[drive].address)
3418 for (x = 0; x < STE;x++)
3420 if (pSTE[x].address == pDTE[drive].from)
3428 for (x = 0; x < STE;x++)
3430 if (pSTE[x].status == 'E') {
3436 /* Ups nothing loaded */
3443 * Reworked function to get the ElementStatus
3444 * This function will first call the GetElementStatus
3445 * function to get the Element status,
3446 * and than check if there are abnormal conditions.
3448 * If there are error conditions try to fix them
3452 GenericElementStatus(
3461 extern OpenFiles_T *pDev;
3463 int error = 0; /* If set do an INIT ELEMENT STATUS */
3464 size_t x; /* The standard loop counter :-) */
3465 int retry = 2; /* Redo it if an error has been reset */
3467 (void)InitStatus; /* Quiet unused parameter warning */
3469 DebugPrint(DEBUG_INFO, SECTION_ELEMENT, "##### START GenericElementStatus\n");
3471 if (pEAAPage == NULL)
3474 * If this pointer is null
3475 * then try to read the parameter with MODE SENSE
3478 if (pModePage == NULL && LibModeSenseValid == 0)
3480 pModePage = alloc(0xff);
3482 if (SCSI_ModeSense(DeviceFD, pModePage, 0xff, 0x8, 0x3f) == 0)
3484 LibModeSenseValid = 1;
3485 DecodeModeSense(pModePage, 0, "GenericElementStatus :", 0, debug_file);
3487 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"GetElementStatus : failed SCSI_ModeSense\n");
3488 LibModeSenseValid = -1;
3493 while ((GetElementStatus(DeviceFD) == 0) && (retry-- > 0))
3495 for (x = 0; x < MTE; x++)
3497 if (pMTE[x].ASC > 0)
3499 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pMTE[x].ASC, pMTE[x].ASCQ, (RequestSense_T *)&pMTE[x]))
3506 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "GenericElementStatus : Abort on MTE\n");
3513 for (x = 0; x < IEE; x++)
3515 if (pIEE[x].ASC > 0)
3517 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pIEE[x].ASC, pIEE[x].ASCQ, (RequestSense_T *)&pIEE[x]))
3524 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "GenericElementStatus : Abort on IEE\n");
3532 for (x = 0; x < STE; x++)
3534 if (pSTE[x].ASC > 0)
3536 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pSTE[x].ASC, pSTE[x].ASCQ, (RequestSense_T *)&pSTE[x]))
3543 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "GenericElementStatus : Abort on IES\n");
3550 for (x = 0; x < DTE; x++)
3552 if (pDTE[x].ASC > 0)
3554 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pDTE[x].ASC, pDTE[x].ASCQ, (RequestSense_T *)&pDTE[x]))
3561 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "GenericElementStatus : Abort on DTE\n");
3569 * OK, we have an error, do an INIT ELMENT
3570 * For the tape if not handled by the robot we have
3571 * to do some extra checks
3575 if (GenericResetStatus(DeviceFD) != 0)
3577 ElementStatusValid = 0;
3578 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "GenericElementStatus : Can't init status STEError(%d) MTEError(%d) DTEError(%d) IEEError(%d)\n", STEError, MTEError, DTEError, IEEError);
3589 * If the status is empty to an move from tape to tape
3590 * This is if the tape is ejected, but not unloaded
3592 if (pDTE[0].status == 'E')
3594 DebugPrint(DEBUG_INFO, SECTION_ELEMENT, "GenericElementStatus : try to move tape to tape drive\n");
3595 pDev[DeviceFD].functions->function_move(DeviceFD, pDTE[0].address, pDTE[0].address);
3598 /* Done GetElementStatus */
3603 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "GenericElementStatus : Can't init status (after loop)\n");
3608 ElementStatusValid = 1;
3609 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "#### STOP GenericElementStatus\n");
3615 * This is for the ADIC changer, it seems that they have an diferent
3616 * offset in the mode sense data before the first mode page (+12)
3619 DLT448ElementStatus(
3625 extern OpenFiles_T *pDev;
3627 int error = 0; /* If set do an INIT ELEMENT STATUS */
3628 size_t x; /* The standard loop counter :-) */
3629 int loop = 2; /* Redo it if an error has been reset */
3631 (void)InitStatus; /* Quiet unused parameter warning */
3633 DebugPrint(DEBUG_INFO, SECTION_ELEMENT, "##### START DLT448ElementStatus\n");
3635 if (pEAAPage == NULL)
3638 * If this pointer is null
3639 * then try to read the parameter with MODE SENSE
3642 if (pModePage == NULL && LibModeSenseValid == 0)
3644 pModePage = alloc(0xff);
3646 if (SCSI_ModeSense(DeviceFD, pModePage, 0xff, 0x8, 0x3f) == 0)
3648 LibModeSenseValid = 1;
3649 DecodeModeSense(pModePage, 12, "DLT448ElementStatus :", 0, debug_file);
3651 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"DLT448ElementStatus : failed SCSI_ModeSense\n");
3652 LibModeSenseValid = -1;
3657 while (GetElementStatus(DeviceFD) == 0 && loop-- > 0)
3659 for (x = 0; x < MTE; x++)
3661 if (pMTE[x].ASC > 0)
3663 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pMTE[x].ASC, pMTE[x].ASCQ, (RequestSense_T *)&pMTE[x]))
3669 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "DLT448ElementStatus : Abort on MTE\n");
3676 for (x = 0; x < IEE; x++)
3678 if (pIEE[x].ASC > 0)
3680 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pIEE[x].ASC, pIEE[x].ASCQ, (RequestSense_T *)&pIEE[x]))
3686 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "DLT448ElementStatus : Abort on IEE\n");
3694 for (x = 0; x < STE; x++)
3697 * Needed for the hack to guess the tape status if an error
3698 * for the tape is pending
3700 if (pSTE[x].ASC > 0)
3702 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pSTE[x].ASC, pSTE[x].ASCQ, (RequestSense_T *)&pSTE[x]))
3708 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "DLT448ElementStatus : Abort on IES\n");
3715 for (x = 0; x < DTE; x++)
3717 if (pDTE[x].ASC > 0)
3719 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pDTE[x].ASC, pDTE[x].ASCQ, (RequestSense_T *)&pDTE[x]))
3726 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "DLT448ElementStatus : Abort on DTE\n");
3734 * OK, we have an error, do an INIT ELMENT
3735 * For the tape if not handled by the robot we have
3736 * to do some extra checks
3740 if (GenericResetStatus(DeviceFD) != 0)
3742 ElementStatusValid = 0;
3743 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "DLT448ElementStatus : Can't init status\n");
3754 * If the status is empty to an move from tape to tape
3755 * This is if the tape is ejected, but not unloaded
3757 if (pDTE[0].status == 'E')
3759 DebugPrint(DEBUG_INFO, SECTION_ELEMENT, "DLT448ElementStatus : try to move tape to tape drive\n");
3760 pDev[DeviceFD].functions->function_move(DeviceFD, pDTE[0].address, pDTE[0].address);
3763 /* Done GetElementStatus */
3768 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "DLT448ElementStatus : Can't init status (after loop)\n");
3773 ElementStatusValid = 1;
3774 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "#### STOP DLT448ElementStatus\n");
3780 * Much the same like GenericElementStatus but
3781 * it seemes that for the STE Elements ASC/ASCQ is not set
3782 * on an error, only the except bit is set
3789 int error = 0; /* If set do an INIT ELEMENT STATUS */
3790 size_t x; /* The standard loop counter :-) */
3791 int loop = 2; /* Redo it if an error has been reset */
3793 (void)InitStatus; /* Quiet unused parameter warning */
3795 DebugPrint(DEBUG_INFO, SECTION_ELEMENT, "##### START SDXElementStatus\n");
3797 if (pEAAPage == NULL)
3800 * If this pointer is null
3801 * then try to read the parameter with MODE SENSE
3804 if (pModePage == NULL && LibModeSenseValid == 0)
3806 pModePage = alloc(0xff);
3808 if (SCSI_ModeSense(DeviceFD, pModePage, 0xff, 0x8, 0x3f) == 0)
3810 LibModeSenseValid = 1;
3811 DecodeModeSense(pModePage, 0, "SDXElementStatus :", 0, debug_file);
3813 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"SDXElementStatus : failed SCSI_ModeSense\n");
3814 LibModeSenseValid = -1;
3819 while (GetElementStatus(DeviceFD) == 0 && loop--)
3822 for (x = 0; x < MTE; x++)
3824 if (pMTE[x].ASC > 0)
3826 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pMTE[x].ASC, pMTE[x].ASCQ, (RequestSense_T *)&pMTE[x]))
3832 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "SDXElementStatus : Abort on MTE\n");
3839 for (x = 0; x < IEE; x++)
3841 if (pIEE[x].ASC > 0)
3843 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pIEE[x].ASC, pIEE[x].ASCQ, (RequestSense_T *)&pIEE[x]))
3849 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "SDXElementStatus : Abort on IEE\n");
3857 for (x = 0; x < STE; x++)
3859 if (pSTE[x].ASC > 0)
3861 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pSTE[x].ASC, pSTE[x].ASCQ, (RequestSense_T *)&pSTE[x]))
3867 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "SDXElementStatus : Abort on IES\n");
3874 for (x = 0; x < DTE; x++)
3876 if (pDTE[x].ASC > 0)
3878 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pDTE[x].ASC, pDTE[x].ASCQ, (RequestSense_T *)&pDTE[x]))
3886 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "SDXElementStatus : Abort on DTE\n");
3894 * OK, we have an error, do an INIT ELMENT
3895 * For the tape if not handled by the robot we have
3896 * to do some extra checks
3900 if (GenericResetStatus(DeviceFD) != 0)
3902 ElementStatusValid = 0;
3903 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "SDXElementStatus : Can't init status\n");
3909 /* Done GetElementStatus */
3914 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "SDXElementStatus : Can't init status\n");
3919 ElementStatusValid = 1;
3921 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "#### STOP SDXElementStatus\n");
3927 * Reads the element information from the library. There are 2 ways to do this.
3928 * Either check the result from the mode sense page to see which types of elements
3929 * are available (STE/DTE/MTE....), or do an read element status with the option give
3930 * me all and than check what is available.
3932 * Only do the read, error handling is done by the calling function
3944 u_char *DataBuffer = NULL;
3945 size_t DataBufferLength;
3946 ElementStatusData_T *ElementStatusData;
3947 ElementStatusPage_T *ElementStatusPage;
3948 MediumTransportElementDescriptor_T *MediumTransportElementDescriptor;
3949 StorageElementDescriptor_T *StorageElementDescriptor;
3950 DataTransferElementDescriptor_T *DataTransferElementDescriptor;
3951 ImportExportElementDescriptor_T *ImportExportElementDescriptor;
3954 size_t length; /* Length of an Element */
3955 size_t NoOfElements;
3957 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"##### START GetElementStatus\n");
3959 barcode = BarCode(DeviceFD);
3962 * If the MODE_SENSE was successfull we use this Information to read the Elelement Info
3964 if (pEAAPage != NULL)
3966 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Reading Element Status with the info from mode sense\n");
3967 /* First the Medim Transport*/
3968 if (V2(pEAAPage->NoMediumTransportElements) > 0)
3970 MTE = V2(pEAAPage->NoMediumTransportElements) ;
3971 pMTE = alloc(SIZEOF(ElementInfo_T) * MTE);
3972 memset(pMTE, 0, SIZEOF(ElementInfo_T) * MTE);
3974 if (SCSI_ReadElementStatus(DeviceFD,
3978 V2(pEAAPage->MediumTransportElementAddress),
3980 SIZEOF(MediumTransportElementDescriptor_T),
3983 ChgExit("genericElementStatus","Can't read MTE status", FATAL);
3986 // ElementStatusData = (ElementStatusData_T *)DataBuffer;
3987 offset = SIZEOF(ElementStatusData_T);
3989 ElementStatusPage = (ElementStatusPage_T *)&DataBuffer[offset];
3990 offset = offset + SIZEOF(ElementStatusPage_T);
3991 length = V2(ElementStatusPage->length);
3993 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"MTE Length %d(%d)\n", length,
3994 SIZEOF(MediumTransportElementDescriptor_T));
3996 for (x = 0; x < MTE; x++)
3998 MediumTransportElementDescriptor = (MediumTransportElementDescriptor_T *)&DataBuffer[offset];
4000 if (ElementStatusPage->pvoltag == 1)
4002 strncpy((char *)pMTE[x].VolTag,
4003 (char *)MediumTransportElementDescriptor->pvoltag,
4005 TerminateString(pMTE[x].VolTag, TAG_SIZE+1);
4008 pMTE[x].type = ElementStatusPage->type;
4009 pMTE[x].address = V2(MediumTransportElementDescriptor->address);
4010 pMTE[x].except = MediumTransportElementDescriptor->except;
4011 pMTE[x].full = MediumTransportElementDescriptor->full;
4012 if (MediumTransportElementDescriptor->full > 0)
4014 pMTE[x].status = 'F';
4016 pMTE[x].status = 'E';
4021 pMTE[x].ASC = MediumTransportElementDescriptor->asc;
4023 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASC MTE\n");
4028 pMTE[x].ASCQ = MediumTransportElementDescriptor->ascq;
4030 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASCQ MTE\n");
4035 if (MediumTransportElementDescriptor->svalid == 1)
4037 pMTE[x].from = V2(MediumTransportElementDescriptor->source);
4042 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip source MTE\n");
4044 offset = offset + length;
4052 if ( V2(pEAAPage->NoStorageElements) > 0)
4055 STE = V2(pEAAPage->NoStorageElements);
4056 pSTE = alloc(SIZEOF(ElementInfo_T) * STE);
4057 memset(pSTE, 0, SIZEOF(ElementInfo_T) * STE);
4059 if (SCSI_ReadElementStatus(DeviceFD,
4063 V2(pEAAPage->FirstStorageElementAddress),
4065 SIZEOF(StorageElementDescriptor_T),
4068 ChgExit("GetElementStatus", "Can't read STE status", FATAL);
4071 assert(DataBuffer != NULL);
4073 // ElementStatusData = (ElementStatusData_T *)DataBuffer;
4074 offset = SIZEOF(ElementStatusData_T);
4076 ElementStatusPage = (ElementStatusPage_T *)&DataBuffer[offset];
4077 offset = offset + SIZEOF(ElementStatusPage_T);
4078 length = V2(ElementStatusPage->length);
4079 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"STE Length %d\n",length);
4081 for (x = 0; x < STE; x++)
4083 StorageElementDescriptor = (StorageElementDescriptor_T *)&DataBuffer[offset];
4084 if (ElementStatusPage->pvoltag == 1)
4086 strncpy(pSTE[x].VolTag,
4087 (char *)StorageElementDescriptor->pvoltag,
4089 TerminateString(pSTE[x].VolTag, TAG_SIZE+1);
4093 pSTE[x].type = ElementStatusPage->type;
4094 pSTE[x].address = V2(StorageElementDescriptor->address);
4095 pSTE[x].except = StorageElementDescriptor->except;
4096 pSTE[x].full = StorageElementDescriptor->full;
4097 if (StorageElementDescriptor->full > 0)
4099 pSTE[x].status = 'F';
4101 pSTE[x].status = 'E';
4106 pSTE[x].ASC = StorageElementDescriptor->asc;
4108 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASC STE\n");
4113 pSTE[x].ASCQ = StorageElementDescriptor->ascq;
4115 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASCQ STE\n");
4120 if (StorageElementDescriptor->svalid == 1)
4122 pSTE[x].from = V2(StorageElementDescriptor->source);
4127 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip source STE\n");
4130 offset = offset + length;
4136 * Import/Export Elements
4138 if ( V2(pEAAPage->NoImportExportElements) > 0)
4141 IEE = V2(pEAAPage->NoImportExportElements);
4142 pIEE = alloc(SIZEOF(ElementInfo_T) * IEE);
4143 memset(pIEE, 0, SIZEOF(ElementInfo_T) * IEE);
4145 if (SCSI_ReadElementStatus(DeviceFD,
4149 V2(pEAAPage->FirstImportExportElementAddress),
4151 SIZEOF(ImportExportElementDescriptor_T),
4154 ChgExit("GetElementStatus", "Can't read IEE status", FATAL);
4157 assert(DataBuffer != NULL);
4159 // ElementStatusData = (ElementStatusData_T *)DataBuffer;
4160 offset = SIZEOF(ElementStatusData_T);
4162 ElementStatusPage = (ElementStatusPage_T *)&DataBuffer[offset];
4163 offset = offset + SIZEOF(ElementStatusPage_T);
4164 length = V2(ElementStatusPage->length);
4165 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"IEE Length %d\n",length);
4167 for (x = 0; x < IEE; x++)
4169 ImportExportElementDescriptor = (ImportExportElementDescriptor_T *)&DataBuffer[offset];
4170 if (ElementStatusPage->pvoltag == 1)
4172 strncpy(pIEE[x].VolTag,
4173 (char *)ImportExportElementDescriptor->pvoltag,
4175 TerminateString(pIEE[x].VolTag, TAG_SIZE+1);
4177 pIEE[x].type = ElementStatusPage->type;
4178 pIEE[x].address = V2(ImportExportElementDescriptor->address);
4179 pIEE[x].except = ImportExportElementDescriptor->except;
4180 pIEE[x].full = ImportExportElementDescriptor->full;
4181 if (ImportExportElementDescriptor->full > 0)
4183 pIEE[x].status = 'F';
4185 pIEE[x].status = 'E';
4190 pIEE[x].ASC = ImportExportElementDescriptor->asc;
4192 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASC IEE\n");
4197 pIEE[x].ASCQ = ImportExportElementDescriptor->ascq;
4199 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASCQ IEE\n");
4204 if (ImportExportElementDescriptor->svalid == 1)
4206 pIEE[x].from = V2(ImportExportElementDescriptor->source);
4211 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip source IEE\n");
4214 offset = offset + length;
4220 * Data Transfer Elements
4222 if (V2(pEAAPage->NoDataTransferElements) >0)
4225 DTE = V2(pEAAPage->NoDataTransferElements) ;
4226 pDTE = alloc(SIZEOF(ElementInfo_T) * DTE);
4227 memset(pDTE, 0, SIZEOF(ElementInfo_T) * DTE);
4229 if (SCSI_ReadElementStatus(DeviceFD,
4233 V2(pEAAPage->FirstDataTransferElementAddress),
4235 SIZEOF(DataTransferElementDescriptor_T),
4238 ChgExit("GenericElementStatus", "Can't read DTE status", FATAL);
4241 assert(DataBuffer != NULL);
4243 // ElementStatusData = (ElementStatusData_T *)DataBuffer;
4244 offset = SIZEOF(ElementStatusData_T);
4246 ElementStatusPage = (ElementStatusPage_T *)&DataBuffer[offset];
4247 offset = offset + SIZEOF(ElementStatusPage_T);
4248 length = V2(ElementStatusPage->length);
4249 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"DTE Length %d\n",length);
4251 for (x = 0; x < DTE; x++)
4253 DataTransferElementDescriptor = (DataTransferElementDescriptor_T *)&DataBuffer[offset];
4254 if (ElementStatusPage->pvoltag == 1)
4256 strncpy(pDTE[x].VolTag,
4257 (char *)DataTransferElementDescriptor->pvoltag,
4259 TerminateString(pDTE[x].VolTag, TAG_SIZE+1);
4261 pDTE[x].type = ElementStatusPage->type;
4262 pDTE[x].address = V2(DataTransferElementDescriptor->address);
4263 pDTE[x].except = DataTransferElementDescriptor->except;
4264 pDTE[x].scsi = DataTransferElementDescriptor->scsi;
4265 pDTE[x].full = DataTransferElementDescriptor->full;
4266 if (DataTransferElementDescriptor->full > 0)
4268 pDTE[x].status = 'F';
4270 pDTE[x].status = 'E';
4275 pDTE[x].ASC = DataTransferElementDescriptor->asc;
4277 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASC DTE\n");
4282 pDTE[x].ASCQ = DataTransferElementDescriptor->ascq;
4284 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASCQ DTE\n");
4289 if (DataTransferElementDescriptor->svalid == 1)
4291 pDTE[x].from = V2(DataTransferElementDescriptor->source);
4296 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip source STE\n");
4299 offset = offset + length;
4306 * And now the old way, when we get here the read mode sense page has failed ...
4308 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Reading Element Status the old way .... (max 255 elements)\n");
4309 if (SCSI_ReadElementStatus(DeviceFD,
4318 ChgExit("GenericElementStatus","Can't get ElementStatus", FATAL);
4321 assert(DataBuffer != NULL);
4323 ElementStatusData = (ElementStatusData_T *)DataBuffer;
4324 DataBufferLength = V3(ElementStatusData->count);
4326 offset = SIZEOF(ElementStatusData_T);
4328 while (offset < DataBufferLength)
4330 ElementStatusPage = (ElementStatusPage_T *)&DataBuffer[offset];
4331 NoOfElements = V3(ElementStatusPage->count) / V2(ElementStatusPage->length);
4332 offset = offset + SIZEOF(ElementStatusPage_T);
4333 length = V2(ElementStatusPage->length);
4335 switch (ElementStatusPage->type)
4340 pMTE = alloc(SIZEOF(ElementInfo_T) * MTE);
4341 memset(pMTE, 0, SIZEOF(ElementInfo_T) * MTE);
4343 for (x = 0; x < NoOfElements; x++)
4345 MediumTransportElementDescriptor = (MediumTransportElementDescriptor_T *)&DataBuffer[offset];
4346 if (ElementStatusPage->pvoltag == 1)
4348 strncpy(pMTE[x].VolTag,
4349 (char *)MediumTransportElementDescriptor->pvoltag,
4351 TerminateString(pMTE[x].VolTag, TAG_SIZE+1);
4353 pMTE[x].type = ElementStatusPage->type;
4354 pMTE[x].address = V2(MediumTransportElementDescriptor->address);
4355 pMTE[x].except = MediumTransportElementDescriptor->except;
4356 pMTE[x].full = MediumTransportElementDescriptor->full;
4357 if (MediumTransportElementDescriptor->full > 0)
4359 pMTE[x].status = 'F';
4361 pMTE[x].status = 'E';
4366 pMTE[x].ASC = MediumTransportElementDescriptor->asc;
4368 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASC MTE\n");
4373 pMTE[x].ASCQ = MediumTransportElementDescriptor->ascq;
4375 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASCQ MTE\n");
4380 if (MediumTransportElementDescriptor->svalid == 1)
4382 pMTE[x].from = V2(MediumTransportElementDescriptor->source);
4387 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip source MTE\n");
4390 offset = offset + length;
4396 pSTE = alloc(SIZEOF(ElementInfo_T) * STE);
4397 memset(pSTE, 0, SIZEOF(ElementInfo_T) * STE);
4399 for (x = 0; x < NoOfElements; x++)
4401 StorageElementDescriptor = (StorageElementDescriptor_T *)&DataBuffer[offset];
4402 if (ElementStatusPage->pvoltag == 1)
4404 strncpy(pSTE[x].VolTag,
4405 (char *)StorageElementDescriptor->pvoltag,
4407 TerminateString(pSTE[x].VolTag, TAG_SIZE+1);
4410 pSTE[x].type = ElementStatusPage->type;
4411 pSTE[x].address = V2(StorageElementDescriptor->address);
4412 pSTE[x].except = StorageElementDescriptor->except;
4413 pSTE[x].full = StorageElementDescriptor->full;
4414 if (StorageElementDescriptor->full > 0)
4416 pSTE[x].status = 'F';
4418 pSTE[x].status = 'E';
4423 pSTE[x].ASC = StorageElementDescriptor->asc;
4425 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASC STE\n");
4430 pSTE[x].ASCQ = StorageElementDescriptor->ascq;
4432 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASCQ STE\n");
4437 if (StorageElementDescriptor->svalid == 1)
4439 pSTE[x].from = V2(StorageElementDescriptor->source);
4444 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip source STE\n");
4447 offset = offset + length;
4453 pIEE = alloc(SIZEOF(ElementInfo_T) * IEE);
4454 memset(pIEE, 0, SIZEOF(ElementInfo_T) * IEE);
4456 for (x = 0; x < NoOfElements; x++)
4458 ImportExportElementDescriptor = (ImportExportElementDescriptor_T *)&DataBuffer[offset];
4459 if (ElementStatusPage->pvoltag == 1)
4461 strncpy(pIEE[x].VolTag,
4462 (char *)ImportExportElementDescriptor->pvoltag,
4464 TerminateString(pIEE[x].VolTag, TAG_SIZE+1);
4466 ImportExportElementDescriptor = (ImportExportElementDescriptor_T *)&DataBuffer[offset];
4467 pIEE[x].type = ElementStatusPage->type;
4468 pIEE[x].address = V2(ImportExportElementDescriptor->address);
4469 pIEE[x].except = ImportExportElementDescriptor->except;
4470 pIEE[x].full = ImportExportElementDescriptor->full;
4471 if (ImportExportElementDescriptor->full > 0)
4473 pIEE[x].status = 'F';
4475 pIEE[x].status = 'E';
4480 pIEE[x].ASC = ImportExportElementDescriptor->asc;
4482 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASC IEE\n");
4487 pIEE[x].ASCQ = ImportExportElementDescriptor->ascq;
4489 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASCQ IEE\n");
4494 if (ImportExportElementDescriptor->svalid == 1)
4496 pIEE[x].from = V2(ImportExportElementDescriptor->source);
4501 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip source IEE\n");
4504 offset = offset + length;
4510 pDTE = alloc(SIZEOF(ElementInfo_T) * DTE);
4511 memset(pDTE, 0, SIZEOF(ElementInfo_T) * DTE);
4513 for (x = 0; x < NoOfElements; x++)
4515 DataTransferElementDescriptor = (DataTransferElementDescriptor_T *)&DataBuffer[offset];
4516 if (ElementStatusPage->pvoltag == 1)
4518 strncpy(pSTE[x].VolTag,
4519 (char *)DataTransferElementDescriptor->pvoltag,
4521 TerminateString(pSTE[x].VolTag, TAG_SIZE+1);
4523 pDTE[x].type = ElementStatusPage->type;
4524 pDTE[x].address = V2(DataTransferElementDescriptor->address);
4525 pDTE[x].except = DataTransferElementDescriptor->except;
4526 pDTE[x].scsi = DataTransferElementDescriptor->scsi;
4527 pDTE[x].full = DataTransferElementDescriptor->full;
4528 if (DataTransferElementDescriptor->full > 0)
4530 pDTE[x].status = 'F';
4532 pDTE[x].status = 'E';
4537 pDTE[x].ASC = DataTransferElementDescriptor->asc;
4539 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASC DTE\n");
4544 pDTE[x].ASCQ = DataTransferElementDescriptor->ascq;
4546 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASCQ DTE\n");
4551 if (DataTransferElementDescriptor->svalid == 1)
4553 pDTE[x].from = V2(DataTransferElementDescriptor->source);
4558 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip source STE\n");
4561 offset = offset + length;
4565 offset = offset + length;
4566 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"GetElementStatus : UnGknown Type %d\n",ElementStatusPage->type);
4573 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"\n\n\tMedia Transport Elements (robot arms) :\n");
4575 for ( x = 0; x < MTE; x++)
4576 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",
4577 pMTE[x].address, pMTE[x].status, pMTE[x].except, pMTE[x].ASC,
4578 pMTE[x].ASCQ, pMTE[x].type, pMTE[x].from, pMTE[x].VolTag);
4580 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"\n\n\tStorage Elements (Media slots) :\n");
4582 for ( x = 0; x < STE; x++)
4583 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",
4584 pSTE[x].address, pSTE[x].status, pSTE[x].except, pSTE[x].ASC,
4585 pSTE[x].ASCQ, pSTE[x].type, pSTE[x].from, pSTE[x].VolTag);
4587 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"\n\n\tData Transfer Elements (tape drives) :\n");
4589 for ( x = 0; x < DTE; x++)
4590 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",
4591 pDTE[x].address, pDTE[x].status, pDTE[x].except, pDTE[x].ASC,
4592 pDTE[x].ASCQ, pDTE[x].type, pDTE[x].from, pDTE[x].VolTag,pDTE[x].scsi);
4594 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"\n\n\tImport/Export Elements :\n");
4596 for ( x = 0; x < IEE; x++)
4597 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",
4598 pIEE[x].address, pIEE[x].status, pIEE[x].except, pIEE[x].ASC,
4599 pIEE[x].ASCQ, pIEE[x].type, pIEE[x].from, pIEE[x].VolTag);
4608 * If ClearErrorCounters is set the counters will be reset.
4609 * Used by GenericClean for example
4616 ExtendedRequestSense_T * ExtendedRequestSense,
4617 int ClearErrorCounters)
4622 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### START RequestSense\n");
4624 CDB[0] = SC_COM_REQUEST_SENSE; /* REQUEST SENSE */
4625 CDB[1] = 0; /* Logical Unit Number = 0, Reserved */
4626 CDB[2] = 0; /* Reserved */
4627 CDB[3] = 0; /* Reserved */
4628 CDB[4] = (u_char)sizeof(ExtendedRequestSense_T); /* Allocation Length */
4629 CDB[5] = (u_char)((ClearErrorCounters << 7) & 0x80); /* */
4631 memset(ExtendedRequestSense, 0, SIZEOF(ExtendedRequestSense_T));
4633 ret = SCSI_Run(DeviceFD, Input, CDB, 6,
4634 (char *) ExtendedRequestSense,
4635 SIZEOF(ExtendedRequestSense_T),
4636 (RequestSense_T *) ExtendedRequestSense,
4637 SIZEOF(ExtendedRequestSense_T));
4642 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP RequestSense (%d)\n",ret);
4649 DecodeExtSense(ExtendedRequestSense, "RequestSense : ",debug_file);
4650 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP RequestSense (%d)\n", ExtendedRequestSense->SenseKey);
4651 return(ExtendedRequestSense->SenseKey);
4655 dump_hex((u_char *)ExtendedRequestSense ,
4656 SIZEOF(ExtendedRequestSense_T),
4657 DEBUG_INFO, SECTION_SCSI);
4658 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP RequestSense (0)\n");
4664 * Lookup function pointer for device ....
4674 dbprintf(("##### START LookupElement\n"));
4678 for (x = 0; x < DTE; x++)
4680 if (pDTE[x].address == address)
4682 dbprintf(("##### STOP LookupElement (DTE)\n"));
4691 for (x = 0; x < MTE; x++)
4693 if (pMTE[x].address == address)
4695 dbprintf(("##### STOP LookupElement (MTE)\n"));
4704 for (x = 0; x < STE; x++)
4706 if (pSTE[x].address == address)
4708 dbprintf(("##### STOP LookupElement (STE)\n"));
4717 for ( x = 0; x < IEE; x++)
4719 if (pIEE[x].address == address)
4721 dbprintf(("##### STOP LookupElement (IEE)\n"));
4731 * Here comes everything what decode the log Pages
4734 * Fix the result handling from TestUnitReady
4741 extern OpenFiles_T *pDev;
4743 RequestSense_T *pRequestSense;
4744 LogSenseHeader_T *LogSenseHeader;
4745 LogParameter_T *LogParameter;
4746 struct LogPageDecode *p;
4748 extern char *tapestatfile;
4750 unsigned ParameterCode;
4759 (void)DeviceFD; /* Quiet unused parameter warning */
4761 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### START LogSense\n");
4763 if ((tapestatfile != NULL) && (pDev[INDEX_TAPECTL].SCSI == 1) &&
4764 ((StatFile = fopen(tapestatfile,"a")) != NULL))
4766 pRequestSense = alloc(SIZEOF(RequestSense_T));
4768 if (GenericRewind(INDEX_TAPECTL) < 0)
4770 DebugPrint(DEBUG_INFO, SECTION_TAPE,"LogSense : Rewind failed\n");
4771 free(pRequestSense);
4777 * Try to read the tape label
4779 if (pDev[INDEX_TAPE].inqdone == 1)
4781 if (pDev[INDEX_TAPE].devopen == 1)
4783 SCSI_CloseDevice(INDEX_TAPE);
4786 if ((chgscsi_result = (char *)tape_rdlabel(pDev[INDEX_TAPE].dev, &chgscsi_datestamp, &chgscsi_label)) == NULL)
4788 fprintf(StatFile, "==== %s ==== %s ====\n", chgscsi_datestamp, chgscsi_label);
4790 fprintf(StatFile, "%s\n", chgscsi_result);
4794 buffer = alloc(size);
4795 memset(buffer, 0, size);
4797 * Get the known log pages
4800 CDB[0] = SC_COM_LOG_SENSE;
4802 CDB[2] = 0x40; /* 0x40 for current values */
4807 MSB2(&CDB[7], size);
4810 if (SCSI_Run(INDEX_TAPECTL, Input, CDB, 10,
4814 SIZEOF(RequestSense_T)) != 0)
4816 DecodeSense(pRequestSense, "LogSense : ",debug_file);
4817 free(pRequestSense);
4824 LogSenseHeader = (LogSenseHeader_T *)buffer;
4825 nologpages = V2(LogSenseHeader->PageLength);
4826 logpages = alloc(nologpages);
4828 memcpy(logpages, buffer + SIZEOF(LogSenseHeader_T), nologpages);
4830 for (count = 0; count < (int)nologpages; count++) {
4831 if (logpages[count] != 0 ) {
4832 memset(buffer, 0, size);
4833 CDB[0] = SC_COM_LOG_SENSE;
4835 CDB[2] = (u_char)(0x40 | logpages[count]);/* 0x40 for current values */
4840 MSB2(&CDB[7], size);
4843 if (SCSI_Run(INDEX_TAPECTL, Input, CDB, 10,
4847 SIZEOF(RequestSense_T)) != 0)
4849 DecodeSense(pRequestSense, "LogSense : ",debug_file);
4850 free(pRequestSense);
4857 LogSenseHeader = (LogSenseHeader_T *)buffer;
4858 length = V2(LogSenseHeader->PageLength);
4859 LogParameter = (LogParameter_T *)(buffer + SIZEOF(LogSenseHeader_T));
4861 * Decode the log pages
4863 p = (struct LogPageDecode *)&DecodePages;
4866 dump_hex((u_char *)LogParameter, 64, DEBUG_INFO, SECTION_SCSI);
4868 while(p->ident != NULL) {
4869 if ((strcmp(pDev[INDEX_TAPECTL].ident, p->ident) == 0 ||strcmp("*", p->ident) == 0) && p->LogPage == logpages[count]) {
4870 p->decode(LogParameter, length);
4872 fprintf(StatFile, "\n");
4879 fprintf(StatFile, "Logpage No %d = %x\n", count ,logpages[count]);
4881 while ((u_char *)LogParameter < (buffer + length)) {
4882 i = LogParameter->ParameterLength;
4883 ParameterCode = V2(LogParameter->ParameterCode);
4886 value = V1((u_char *)LogParameter + SIZEOF(LogParameter_T));
4887 fprintf(StatFile, "ParameterCode %02X = %u(%d)\n", ParameterCode, value, i);
4890 value = V2((u_char *)LogParameter + SIZEOF(LogParameter_T));
4891 fprintf(StatFile, "ParameterCode %02X = %u(%d)\n", ParameterCode, value, i);
4894 value = V3((u_char *)LogParameter + SIZEOF(LogParameter_T));
4895 fprintf(StatFile, "ParameterCode %02X = %u(%d)\n", ParameterCode, value, i);
4898 value = V4((u_char *)LogParameter + SIZEOF(LogParameter_T));
4899 fprintf(StatFile, "ParameterCode %02X = %u(%d)\n", ParameterCode, value, i);
4902 value = V5((u_char *)LogParameter + SIZEOF(LogParameter_T));
4903 fprintf(StatFile, "ParameterCode %02X = %u(%d)\n", ParameterCode, value, i);
4906 fprintf(StatFile, "ParameterCode %02X size %d\n", ParameterCode, i);
4908 LogParameter = (LogParameter_T *)((u_char *)LogParameter + SIZEOF(LogParameter_T) + i);
4910 fprintf(StatFile, "\n");
4917 * Reset the cumulative counters
4919 CDB[0] = SC_COM_LOG_SELECT;
4930 if (SCSI_Run(INDEX_TAPECTL, Input, CDB, 10,
4934 SIZEOF(RequestSense_T)) != 0)
4936 DecodeSense(pRequestSense, "LogSense : ",debug_file);
4937 free(pRequestSense);
4947 free(pRequestSense);
4954 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### STOP LogSense\n");
4959 WriteErrorCountersPage(
4960 LogParameter_T * buffer,
4965 LogParameter_T *LogParameter;
4966 unsigned ParameterCode;
4967 LogParameter = buffer;
4969 fprintf(StatFile, "\tWrite Error Counters Page\n");
4971 while ((u_char *)LogParameter < ((u_char *)buffer + length)) {
4972 i = LogParameter->ParameterLength;
4973 ParameterCode = V2(LogParameter->ParameterCode);
4976 if (Decode(LogParameter, &value) == 0) {
4977 switch (ParameterCode) {
4979 fprintf(StatFile, "%-30s = %u\n",
4984 fprintf(StatFile, "%-30s = %u\n",
4985 "Total Errors Corrected",
4989 fprintf(StatFile, "%-30s = %u\n",
4990 "Total Times E. Processed",
4994 fprintf(StatFile, "%-30s = %u\n",
4995 "Total Bytes Processed",
4999 fprintf(StatFile, "%-30s = %u\n",
5000 "Total Unrecoverable Errors",
5004 fprintf(StatFile, "Unknown ParameterCode %02X = %u(%d)\n",
5010 fprintf(StatFile, "Error decoding Result\n");
5012 LogParameter = (LogParameter_T *)((u_char *)LogParameter + SIZEOF(LogParameter_T) + i);
5017 ReadErrorCountersPage(
5018 LogParameter_T * buffer,
5023 LogParameter_T *LogParameter;
5024 unsigned ParameterCode;
5025 LogParameter = buffer;
5027 fprintf(StatFile, "\tRead Error Counters Page\n");
5029 while ((u_char *)LogParameter < ((u_char *)buffer + length)) {
5030 i = LogParameter->ParameterLength;
5031 ParameterCode = V2(LogParameter->ParameterCode);
5034 if (Decode(LogParameter, &value) == 0) {
5035 switch (ParameterCode) {
5037 fprintf(StatFile, "%-30s = %u\n",
5042 fprintf(StatFile, "%-30s = %u\n",
5043 "Total Errors Corrected",
5047 fprintf(StatFile, "%-30s = %u\n",
5048 "Total Times E. Processed",
5052 fprintf(StatFile, "%-30s = %u\n",
5053 "Total Bytes Processed",
5057 fprintf(StatFile, "%-30s = %u\n",
5058 "Total Unrecoverable Errors",
5062 fprintf(StatFile, "Unknown ParameterCode %02X = %u(%d)\n",
5068 fprintf(StatFile, "Error decoding Result\n");
5070 LogParameter = (LogParameter_T *)((u_char *)LogParameter + SIZEOF(LogParameter_T) + i);
5076 LogParameter_T * buffer,
5081 LogParameter_T *LogParameter;
5082 unsigned ParameterCode;
5083 LogParameter = buffer;
5085 fprintf(StatFile, "\tData compression transfer Page\n");
5087 while ((u_char *)LogParameter < ((u_char *)buffer + length)) {
5088 i = LogParameter->ParameterLength;
5089 ParameterCode = V2(LogParameter->ParameterCode);
5092 if (Decode(LogParameter, &value) == 0) {
5093 switch (ParameterCode) {
5095 fprintf(StatFile, "Unknown ParameterCode %02X = %u(%d)\n",
5101 LogParameter = (LogParameter_T *)((u_char *)LogParameter + SIZEOF(LogParameter_T) + i);
5107 LogParameter_T * buffer,
5112 LogParameter_T *LogParameter;
5113 unsigned ParameterCode;
5114 LogParameter = buffer;
5116 fprintf(StatFile, "\tDrive Counters Page\n");
5118 while ((u_char *)LogParameter < ((unsigned char *)buffer + length)) {
5119 i = LogParameter->ParameterLength;
5120 ParameterCode = V2(LogParameter->ParameterCode);
5123 if (Decode(LogParameter, &value) == 0) {
5124 switch (ParameterCode) {
5126 fprintf(StatFile, "%-30s = %u\n",
5131 fprintf(StatFile, "%-30s = %u\n",
5132 "Total write drive errors",
5136 fprintf(StatFile, "%-30s = %u\n",
5137 "Total read drive errors",
5141 fprintf(StatFile, "Unknown ParameterCode %02X = %u(%d)\n",
5147 LogParameter = (LogParameter_T *)((u_char *)LogParameter + SIZEOF(LogParameter_T) + i);
5153 LogParameter_T * buffer,
5158 LogParameter_T *LogParameter;
5159 unsigned ParameterCode;
5160 LogParameter = buffer;
5162 fprintf(StatFile, "\tData Compression Page\n");
5164 while ((u_char *)LogParameter < ((unsigned char *)buffer + length)) {
5165 i = LogParameter->ParameterLength;
5166 ParameterCode = V2(LogParameter->ParameterCode);
5169 if (Decode(LogParameter, &value) == 0) {
5170 switch (ParameterCode) {
5172 fprintf(StatFile, "%-30s = %u\n",
5177 fprintf(StatFile, "%-30s = %u\n",
5182 fprintf(StatFile, "Unknown ParameterCode %02X = %u(%d)\n",
5188 LogParameter = (LogParameter_T *)((u_char *)LogParameter + SIZEOF(LogParameter_T) + i);
5194 LogParameter_T * buffer,
5199 LogParameter_T *LogParameter;
5200 unsigned ParameterCode;
5201 LogParameter = buffer;
5203 fprintf(StatFile, "\tDrive Usage Information Page\n");
5205 while ((u_char *)LogParameter < ((unsigned char *)buffer + length)) {
5206 i = LogParameter->ParameterLength;
5207 ParameterCode = V2(LogParameter->ParameterCode);
5210 if (Decode(LogParameter, &value) == 0) {
5211 switch (ParameterCode) {
5219 fprintf(StatFile, "%-30s = %u\n",
5224 fprintf(StatFile, "%-30s = %u\n",
5225 "MinutesSince Last Clean",
5232 fprintf(StatFile, "%-30s = %u\n",
5244 fprintf(StatFile, "%-30s = %u\n",
5253 fprintf(StatFile, "Unknown ParameterCode %02X = %u(%d)\n",
5259 LogParameter = (LogParameter_T *)((u_char *)LogParameter + SIZEOF(LogParameter_T) + i);
5265 LogParameter_T * LogParameter,
5269 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### START Decode\n");
5270 DebugPrint(DEBUG_INFO, SECTION_SCSI,"Decode Parameter with length %d\n", LogParameter->ParameterLength);
5273 switch (LogParameter->ParameterLength) {
5275 *value = V1((u_char *)LogParameter + SIZEOF(LogParameter_T));
5278 *value = V2((u_char *)LogParameter + SIZEOF(LogParameter_T));
5281 *value = V3((u_char *)LogParameter + SIZEOF(LogParameter_T));
5284 *value = V4((u_char *)LogParameter + SIZEOF(LogParameter_T));
5287 *value = V5((u_char *)LogParameter + SIZEOF(LogParameter_T));
5290 *value = V6((u_char *)LogParameter + SIZEOF(LogParameter_T));
5293 fprintf(StatFile, "Can't decode ParameterCode %02X size %d\n",
5294 V2(LogParameter->ParameterCode), LogParameter->ParameterLength);
5295 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP Decode (1)\n");
5299 DebugPrint(DEBUG_INFO, SECTION_SCSI,"Result = %d\n", *value);
5300 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP Decode(0)\n");
5311 printf("%s Devicefd %d\n", device, p->fd);
5312 printf("%s Can SCSI %d\n", device, p->SCSI);
5313 printf("%s Device %s\n", device, (p->dev != NULL)? p->dev:"No set");
5314 printf("%s ConfigName %s\n", device, (p->ConfigName != NULL) ? p->ConfigName:"Not ser");
5316 printf("%s Null Pointer ....\n", device);
5325 u_char buffer[1024];
5330 (void)option; /* Quiet unused parameter warning */
5332 if ((ip=fopen("/tmp/chg-scsi-trace", "r")) == NULL)
5337 for (x = 0; x < 1024; x++)
5339 if (fscanf(ip, "%2x", &bufferx) == EOF)
5344 buffer[x] = (u_char)bufferx;
5348 DecodeModeSense(&buffer[0], 12, "DLT448ElementStatus :", 0, debug_file);
5353 * Display all Information we can get about the library....
5360 char * changer_file,
5364 extern OpenFiles_T *pDev;
5367 ExtendedRequestSense_T ExtRequestSense;
5370 ChangerCMD_T *p = (ChangerCMD_T *)&ChangerIO;
5371 pbarcoderes = alloc(SIZEOF(MBC_T));
5372 memset(pbarcoderes, 0, SIZEOF(MBC_T));
5374 if (pModePage == NULL) {
5375 pModePage = alloc(0xff);
5378 if ((out = fdopen(1 , "w")) == NULL)
5380 printf("Error fdopen stdout\n");
5386 if (strcmp("types", option) == 0 || strcmp("all", option) == 0)
5388 while(p->ident != NULL)
5390 printf ("Ident = %s, type = %s\n",p->ident, p->type);
5396 if (strcmp("robot", option) == 0 || strcmp("all", option) == 0)
5398 if (ElementStatusValid == 0)
5400 if (pDev[INDEX_CHANGER].functions->function_status(pDev[INDEX_CHANGER].fd, 1) != 0)
5402 printf("Can not initialize changer status\n");
5409 /* 0123456789012345678901234567890123456789012 */
5412 printf("Address Type Status From Barcode Label\n");
5414 printf("Address Type Status From\n");
5416 printf("-------------------------------------------\n");
5419 for ( x = 0; x < MTE; x++)
5422 printf("%07d MTE %s %04d %s ",pMTE[x].address,
5423 (pMTE[x].full ? "Full " :"Empty"),
5424 pMTE[x].from, pMTE[x].VolTag);
5426 if (pMTE[x].full == 1)
5428 pbarcoderes->action = BARCODE_BARCODE;
5429 strncpy(pbarcoderes->data.barcode, pMTE[x].VolTag,
5430 SIZEOF(pbarcoderes->data.barcode));
5432 if (MapBarCode(labelfile, pbarcoderes) == 0 )
5434 printf("No mapping\n");
5436 printf("%s \n",pbarcoderes->data.voltag);
5442 printf("%07d MTE %s %04d \n",pMTE[x].address,
5443 (pMTE[x].full ? "Full " :"Empty"),
5448 for ( x = 0; x < STE; x++)
5451 printf("%07d STE %s %04d %s ",pSTE[x].address,
5452 (pSTE[x].full ? "Full ":"Empty"),
5453 pSTE[x].from, pSTE[x].VolTag);
5455 if (pSTE[x].full == 1)
5457 pbarcoderes->action = BARCODE_BARCODE;
5458 strncpy(pbarcoderes->data.barcode, pSTE[x].VolTag,
5459 SIZEOF(pbarcoderes->data.barcode));
5461 if (MapBarCode(labelfile, pbarcoderes) == 0 )
5463 printf("No mapping\n");
5465 printf("%s \n",pbarcoderes->data.voltag);
5471 printf("%07d STE %s %04d %s\n",pSTE[x].address,
5472 (pSTE[x].full ? "Full ":"Empty"),
5473 pSTE[x].from, pSTE[x].VolTag);
5477 for ( x = 0; x < DTE; x++)
5480 printf("%07d DTE %s %04d %s ",pDTE[x].address,
5481 (pDTE[x].full ? "Full " : "Empty"),
5482 pDTE[x].from, pDTE[x].VolTag);
5484 if (pDTE[x].full == 1)
5486 pbarcoderes->action = BARCODE_BARCODE;
5487 strncpy(pbarcoderes->data.barcode, pDTE[x].VolTag,
5488 SIZEOF(pbarcoderes->data.barcode));
5490 if (MapBarCode(labelfile, pbarcoderes) == 0 )
5492 printf("No mapping\n");
5494 printf("%s \n",pbarcoderes->data.voltag);
5501 printf("%07d DTE %s %04d %s\n",pDTE[x].address,
5502 (pDTE[x].full ? "Full " : "Empty"),
5503 pDTE[x].from, pDTE[x].VolTag);
5506 for ( x = 0; x < IEE; x++)
5509 printf("%07d IEE %s %04d %s ",pIEE[x].address,
5510 (pIEE[x].full ? "Full " : "Empty"),
5511 pIEE[x].from, pIEE[x].VolTag);
5513 if (pIEE[x].full == 1)
5515 pbarcoderes->action = BARCODE_BARCODE;
5516 strncpy(pbarcoderes->data.barcode, pIEE[x].VolTag,
5517 SIZEOF(pbarcoderes->data.barcode));
5519 if (MapBarCode(labelfile, pbarcoderes) == 0 )
5521 printf("No mapping\n");
5523 printf("%s \n",pbarcoderes->data.voltag);
5530 printf("%07d IEE %s %04d %s\n",pIEE[x].address,
5531 (pIEE[x].full ? "Full " : "Empty"),
5532 pIEE[x].from, pIEE[x].VolTag);
5537 if (strcmp("sense", option) == 0 || strcmp("all", option) == 0)
5539 if (pDev[INDEX_CHANGER].SCSI == 1)
5541 printf("\nSense Status from robot:\n");
5542 RequestSense(INDEX_CHANGER , &ExtRequestSense, 0);
5543 DecodeExtSense(&ExtRequestSense, "", out);
5546 if (pDev[INDEX_TAPE].SCSI == 1)
5549 printf("Sense Status from tape (tapectl):\n");
5550 RequestSense(INDEX_TAPE, &ExtRequestSense, 0);
5551 DecodeExtSense(&ExtRequestSense, "", out);
5554 if (pDev[INDEX_TAPECTL].SCSI == 1)
5557 printf("Sense Status from tape (tapectl):\n");
5558 RequestSense(INDEX_TAPECTL, &ExtRequestSense, 0);
5559 DecodeExtSense(&ExtRequestSense, "", out);
5563 if (strcmp("ModeSenseRobot", option) == 0 || strcmp("all", option) == 0)
5566 if (SCSI_ModeSense(INDEX_CHANGER, pModePage, 0xff, 0x08, 0x3f) == 0)
5568 DecodeModeSense(pModePage, 0, "Changer :" , 0, out);
5572 if (strcmp("ModeSenseTape", option) == 0 || strcmp("all", option) == 0)
5574 if (pDev[INDEX_TAPECTL].SCSI == 1)
5577 if (SCSI_ModeSense(INDEX_TAPECTL, pModePage, 0xff, 0x0, 0x3f) == 0)
5579 DecodeModeSense(pModePage, 0, "Tape :" , 1, out);
5584 if (strcmp("fd", option) == 0 || strcmp("all", option) == 0)
5586 printf("changer_dev %s\n",changer_dev);
5587 printf("changer_file %s\n", changer_file);
5588 printf("tape_device %s\n\n", tape_device);
5589 DumpDev(&pDev[INDEX_TAPE], "pTapeDev");
5590 DumpDev(&pDev[INDEX_TAPECTL], "pTapeDevCtl");
5591 DumpDev(&pDev[INDEX_CHANGER], "pChangerDev");
5594 if (GenericClean("") == 1)
5595 printf("Tape needs cleaning\n");
5608 size_t row_count = 0;
5611 while (row_count < size)
5613 DebugPrint(level, section,"%02X ", (u_char)p[row_count]);
5614 if (((row_count + 1) % 16) == 0)
5617 for (x = 16; x > 0; x--)
5619 if (isalnum((u_char)p[row_count - x + 1 ]))
5620 DebugPrint(level, section,"%c",(u_char)p[row_count - x + 1]);
5622 DebugPrint(level, section,".");
5624 DebugPrint(level, section,"\n");
5628 DebugPrint(level, section,"\n");
5638 for (x = (ssize_t)length; x >= 0 && !isalnum((int)string[x]); x--)
5648 (void)level; /* Quiet unused parameter warning */
5650 dbprintf(("ChgExit in %s, reason %s\n", where, reason));
5651 fprintf(stderr,"%s\n",reason);
5655 /* OK here starts a new set of functions.
5656 * Every function is for one SCSI command.
5657 * Prefix is SCSI_ and then the SCSI command name
5661 * SCSI_Run is an wrapper arround SCSI_ExecuteCommand
5662 * It seems to be an good idea to check first if the device
5663 * is ready for accepting commands, and if this is true send
5669 Direction_T Direction,
5673 size_t DataBufferLength,
5674 RequestSense_T * pRequestSense,
5675 size_t RequestSenseLength)
5680 RequestSense_T *pRqS;
5682 /* Basic sanity checks */
5683 assert(CDB_Length <= UCHAR_MAX);
5684 assert(RequestSenseLength <= UCHAR_MAX);
5686 pRqS = (RequestSense_T *)pRequestSense;
5688 DebugPrint(DEBUG_INFO, SECTION_SCSI, "SCSI_Run TestUnitReady\n");
5689 while (!ok && maxtries < MAXTRIES)
5691 ret = SCSI_TestUnitReady(DeviceFD, (RequestSense_T *)pRequestSense );
5692 DebugPrint(DEBUG_INFO, SECTION_SCSI, "SCSI_Run TestUnitReady ret %d\n",ret);
5699 switch (SenseHandler(DeviceFD, 0, pRqS->SenseKey, pRqS->AdditionalSenseCode, pRqS->AdditionalSenseCodeQualifier, pRqS))
5702 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run (TestUnitReady) SENSE_NO\n");
5705 case SENSE_TAPE_NOT_ONLINE:
5706 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run (TestUnitReady) SENSE_TAPE_NOT_ONLINE\n");
5710 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run (TestUnitReady) SENSE_IGNORE\n");
5714 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"SCSI_Run (TestUnitReady) SENSE_ABORT\n");
5718 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run (TestUnitReady) SENSE_RETRY\n");
5721 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run (TestUnitReady) default (SENSE)\n");
5727 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"SCSI_Run (TestUnitReady) SCSI_ERROR\n");
5731 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run (TestUnitReady) SCSI_BUSY\n");
5734 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run (TestUnitReady) SCSI_CHECK\n");
5737 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"SCSI_Run (TestUnitReady) unknown (%d)\n",ret);
5747 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run TestUnitReady after %d sec:\n",maxtries);
5751 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"SCSI_Run Exit %d\n",ret);
5758 while (!ok && maxtries < MAXTRIES)
5760 ret = SCSI_ExecuteCommand(DeviceFD,
5767 RequestSenseLength);
5769 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run Exit %d\n",ret);
5776 switch (SenseHandler(DeviceFD, 0, pRqS->SenseKey, pRqS->AdditionalSenseCode, pRqS->AdditionalSenseCodeQualifier, pRqS))
5779 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run SENSE_NO\n");
5782 case SENSE_TAPE_NOT_ONLINE:
5783 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run SENSE_TAPE_NOT_ONLINE\n");
5787 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run SENSE_IGNORE\n");
5791 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"SCSI_Run SENSE_ABORT\n");
5795 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run SENSE_RETRY\n");
5798 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run default (SENSE)\n");
5804 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"SCSI_Run SCSI_ERROR\n");
5808 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run SCSI_BUSY\n");
5811 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run (TestUnitReady) SCSI_CHECK\n");
5814 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"SCSI_Run (TestUnitReady) unknown (%d)\n",ret);
5830 * This a vendor specific command !!!!!!
5831 * First seen at AIT :-)
5840 RequestSense_T *pRequestSense;
5846 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### START SCSI_AlignElements\n");
5848 pRequestSense = alloc(SIZEOF(RequestSense_T));
5850 for (retry = 0; retry < MAX_RETRIES; retry++)
5854 MSB2(&CDB[2],AE_MTE); /* Which MTE to use, default 0 */
5855 MSB2(&CDB[4],AE_DTE); /* Which DTE to use, no range check !! */
5856 MSB2(&CDB[6],AE_STE); /* Which STE to use, no range check !! */
5862 ret = SCSI_Run(DeviceFD, Input, CDB, 12,
5863 NULL, 0, pRequestSense, SIZEOF(RequestSense_T));
5865 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_AlignElements : SCSI_Run = %d\n", ret);
5866 DecodeSense(pRequestSense, "SCSI_AlignElements :",debug_file);
5870 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"%s: Request Sense[Inquiry]: %02X",
5871 "chs", ((u_char *) &pRequestSense)[0]);
5872 for (i = 1; i < (int)sizeof(RequestSense_T); i++)
5873 DebugPrint(DEBUG_ERROR, SECTION_SCSI," %02X", ((u_char *) &pRequestSense)[i]);
5874 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"\n");
5880 switch(SenseHandler(DeviceFD, 0 , pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
5883 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_AlignElements : SENSE_IGNORE\n");
5887 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_AlignElements : SENSE_RETRY no %d\n", retry);
5890 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"SCSI_AlignElements : SENSE_ABORT\n");
5893 case SENSE_TAPE_NOT_UNLOADED:
5894 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"SCSI_AlignElements : Tape still loaded, eject failed\n");
5898 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_AlignElements : end %d\n", pRequestSense->SenseKey);
5899 return(pRequestSense->SenseKey);
5905 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_AlignElements : end %d\n", ret);
5910 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"SCSI_AlignElements :"
5911 "Retries exceeded = %d\n", retry);
5923 RequestSense_T *pRequestSense;
5929 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### START SCSI_Move\n");
5931 pRequestSense = alloc(SIZEOF(RequestSense_T));
5933 for (retry = 0; (ret != 0) && (retry < MAX_RETRIES); retry++)
5935 CDB[0] = SC_MOVE_MEDIUM;
5938 CDB[3] = chm; /* Address of CHM */
5946 ret = SCSI_Run(DeviceFD, Input, CDB, 12,
5947 NULL, 0, pRequestSense, SIZEOF(RequestSense_T));
5949 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Move : SCSI_Run = %d\n", ret);
5950 DecodeSense(pRequestSense, "SCSI_Move :",debug_file);
5954 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"%s: Request Sense[Inquiry]: %02X",
5955 "chs", ((u_char *) &pRequestSense)[0]);
5956 for (i = 1; i < (int)sizeof(RequestSense_T); i++)
5957 DebugPrint(DEBUG_ERROR, SECTION_SCSI," %02X", ((u_char *) &pRequestSense)[i]);
5958 DebugPrint(DEBUG_INFO, SECTION_SCSI,"\n");
5964 switch(SenseHandler(DeviceFD, 0 , pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
5967 dbprintf(("SCSI_Move : SENSE_IGNORE\n"));
5971 dbprintf(("SCSI_Move : SENSE_RETRY no %d\n", retry));
5974 dbprintf(("SCSI_Move : SENSE_ABORT\n"));
5977 case SENSE_TAPE_NOT_UNLOADED:
5978 dbprintf(("SCSI_Move : Tape still loaded, eject failed\n"));
5982 dbprintf(("SCSI_Move : end %d\n", pRequestSense->SenseKey));
5983 return(pRequestSense->SenseKey);
5988 dbprintf(("SCSI_Move : end %d\n", ret));
5995 RequestSense_T * pRequestSense,
6002 dbprintf(("##### START SCSI_LoadUnload\n"));
6004 CDB[0] = SC_COM_UNLOAD;
6012 ret = SCSI_Run(DeviceFD, Input, CDB, 6,
6015 SIZEOF(RequestSense_T));
6019 dbprintf(("SCSI_Unload : failed %d\n", ret));
6030 RequestSense_T * pRequestSense)
6035 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### START SCSI_TestUnitReady\n");
6037 CDB[0] = SC_COM_TEST_UNIT_READY;
6044 ret = SCSI_ExecuteCommand(DeviceFD, Input, CDB, 6,
6047 SIZEOF(RequestSense_T));
6050 * We got an error, so let the calling function handle this
6054 DebugPrint(DEBUG_INFO, SECTION_SCSI,"###### STOP SCSI_TestUnitReady (1)\n");
6060 * OK, no error condition
6061 * If no sense is set, the Unit is ready
6063 if (pRequestSense->ErrorCode == 0 && pRequestSense->SenseKey == 0)
6065 DebugPrint(DEBUG_INFO, SECTION_SCSI,"###### STOP SCSI_TestUnitReady (1)\n");
6073 DebugPrint(DEBUG_INFO, SECTION_SCSI,"###### STOP SCSI_TestUnitReady (0)\n");
6088 RequestSense_T *pRequestSense;
6093 dbprintf(("##### START SCSI_ModeSelect\n"));
6095 dbprintf(("SCSI_ModeSelect start length = %u:\n", (unsigned)length));
6096 pRequestSense = alloc(SIZEOF(RequestSense_T));
6097 sendbuf = alloc((size_t)length + 4);
6098 memset(sendbuf, 0 , (size_t)length + 4);
6100 memcpy(&sendbuf[4], buffer, (size_t)length);
6101 dump_hex(sendbuf, (size_t)length+4, DEBUG_INFO, SECTION_SCSI);
6103 for (retry = 0; (ret != 0) && (retry < MAX_RETRIES); retry++)
6105 memset(pRequestSense, 0, SIZEOF(RequestSense_T));
6107 CDB[0] = SC_COM_MODE_SELECT;
6108 CDB[1] = (u_char)(((lun << 5) & 0xF0) | ((mode << 4) & 0x10) | (save & 1));
6111 CDB[4] = (u_char)(length + 4);
6113 ret = SCSI_Run(DeviceFD, Output, CDB, 6,
6117 SIZEOF(RequestSense_T));
6120 dbprintf(("SCSI_ModeSelect : ret %d\n", ret));
6127 switch(SenseHandler(DeviceFD, 0, pRequestSense->SenseKey,
6128 pRequestSense->AdditionalSenseCode,
6129 pRequestSense->AdditionalSenseCodeQualifier,
6133 dbprintf(("SCSI_ModeSelect : SENSE_IGNORE\n"));
6138 dbprintf(("SCSI_ModeSelect : SENSE_RETRY no %d\n", retry));
6142 ret = pRequestSense->SenseKey;
6148 dbprintf(("SCSI_ModeSelect end: %d\n", ret));
6151 free(pRequestSense);
6167 RequestSense_T *pRequestSense;
6171 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### START SCSI_ModeSense\n");
6173 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ModeSense start length = %d:\n", size);
6174 pRequestSense = alloc(SIZEOF(RequestSense_T));
6176 while (ret && retry < MAX_RETRIES)
6178 memset(pRequestSense, 0, SIZEOF(RequestSense_T));
6179 memset(buffer, 0, size);
6181 CDB[0] = SC_COM_MODE_SENSE;
6187 ret = SCSI_Run(DeviceFD, Input, CDB, 6,
6191 SIZEOF(RequestSense_T));
6200 switch(SenseHandler(DeviceFD, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
6203 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ModeSense : SENSE_IGNORE\n");
6207 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ModeSense : SENSE_RETRY no %d\n", retry);
6210 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ModeSense : end %d\n", pRequestSense->SenseKey);
6211 return(pRequestSense->SenseKey);
6218 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ModeSense end: %d\n", ret);
6225 SCSIInquiry_T * buffer,
6229 RequestSense_T *pRequestSense;
6234 assert(size <= UCHAR_MAX);
6236 DebugPrint(DEBUG_INFO, SECTION_SCSI, "##### START SCSI_Inquiry\n");
6238 DebugPrint(DEBUG_INFO, SECTION_SCSI, "SCSI_Inquiry start length = %d:\n", size);
6240 pRequestSense = alloc((size_t)size);
6242 while (retry > 0 && retry < MAX_RETRIES)
6244 memset(buffer, 0, size);
6245 CDB[0] = SC_COM_INQUIRY;
6249 CDB[4] = (u_char)size;
6252 ret = SCSI_ExecuteCommand(DeviceFD, Input, CDB, 6,
6256 SIZEOF(RequestSense_T));
6259 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"%s: Request Sense[Inquiry]: %02X",
6260 "chs", ((u_char *) pRequestSense)[0]);
6261 for (i = 1; i < (int)sizeof(RequestSense_T); i++)
6262 DebugPrint(DEBUG_ERROR, SECTION_SCSI," %02X", ((u_char *) pRequestSense)[i]);
6263 DebugPrint(DEBUG_ERROR, SECTION_SCSI, "\n");
6264 DebugPrint(DEBUG_ERROR, SECTION_SCSI, "Inquiry end: %d\n", ret);
6270 switch(SenseHandler(DeviceFD, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
6273 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Inquiry : SENSE_IGNORE\n");
6277 DebugPrint(DEBUG_INFO, SECTION_SCSI, "SCSI_Inquiry : SENSE_RETRY no %d\n", retry);
6280 DebugPrint(DEBUG_ERROR, SECTION_SCSI, "SCSI_Inquiry : end %d\n", pRequestSense->SenseKey);
6281 return(pRequestSense->SenseKey);
6288 dump_hex((u_char *)buffer, size, DEBUG_INFO, SECTION_SCSI);
6289 DebugPrint(DEBUG_INFO, SECTION_SCSI, "SCSI_Inquiry : end %d\n", ret);
6295 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Inquiry end: %d\n", ret);
6300 * Read the Element Status. If DescriptorSize != 0 then
6301 * allocate DescriptorSize * NoOfElements for the result from the
6302 * Read Element Status command.
6303 * If DescriptorSize == 0 than try to figure out how much space is needed
6305 * 1. do an read with an allocation size of 8
6306 * 2. from the result take the 'Byte Count of Descriptor Available'
6307 * 3. do again an Read Element Status with the result from 2.
6311 SCSI_ReadElementStatus(
6317 size_t NoOfElements,
6318 size_t DescriptorSize,
6322 size_t DataBufferLength;
6323 ElementStatusData_T *ElementStatusData;
6324 RequestSense_T *pRequestSense;
6328 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### START SCSI_ReadElementStatus\n");
6330 pRequestSense = alloc(SIZEOF(RequestSense_T));
6333 * How many elements, if <= 0 than exit with an fatal error
6335 if (NoOfElements == 0)
6337 ChgExit("SCSI_ReadElementStatus","No of Elements passed are le 0",FATAL);
6341 VolTag = (u_char)((VolTag << 4) & 0x10);
6342 type = (u_char)(type & 0xf);
6343 lun = (u_char)((lun << 5) & 0xe0);
6345 /* if DescriptorSize == 0
6346 * try to get the allocation length for the second call
6348 if (DescriptorSize == 0)
6350 *data = newalloc(*data, 8);
6351 memset(*data, 0, 8);
6353 while (retry > 0 && retry < MAX_RETRIES)
6355 memset(pRequestSense, 0, SIZEOF(RequestSense_T) );
6357 CDB[0] = SC_COM_RES; /* READ ELEMENT STATUS */
6358 CDB[1] = (u_char)(VolTag | type | lun); /* Element Type Code , VolTag, LUN */
6359 MSB2(&CDB[2], StartAddress); /* Starting Element Address */
6360 MSB2(&CDB[4], NoOfElements); /* Number Of Element */
6361 CDB[6] = 0; /* Reserved */
6362 MSB3(&CDB[7],8); /* Allocation Length */
6363 CDB[10] = 0; /* Reserved */
6364 CDB[11] = 0; /* Control */
6366 ret = SCSI_Run(DeviceFD, Input, CDB, 12,
6368 pRequestSense, SIZEOF(RequestSense_T));
6370 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ReadElementStatus : (1) SCSI_Run %d\n", ret);
6373 DecodeSense(pRequestSense, "SCSI_ReadElementStatus :",debug_file);
6374 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP SCSI_ReadElementStatus (%d)\n",ret);
6380 switch(SenseHandler(DeviceFD, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
6383 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ModeSense : SENSE_IGNORE\n");
6387 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ModeSense : SENSE_RETRY no %d\n", retry);
6391 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ModeSense : end %d\n", pRequestSense->SenseKey);
6392 return(pRequestSense->SenseKey);
6404 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP SCSI_ReadElementStatus (%d)\n",ret);
6409 ElementStatusData = (ElementStatusData_T *)*data;
6410 DataBufferLength = V3(ElementStatusData->count);
6412 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ReadElementStatus: DataBufferLength %X, ret %d\n",DataBufferLength, ret);
6414 dump_hex(*data, 8, DEBUG_INFO, SECTION_ELEMENT);
6415 } else { /* DescriptorSize != 0 */
6416 DataBufferLength = NoOfElements * DescriptorSize;
6419 DataBufferLength = DataBufferLength + 8;
6420 *data = newalloc(*data, DataBufferLength);
6421 memset(*data, 0, DataBufferLength);
6424 while (retry > 0 && retry < MAX_RETRIES)
6426 memset(pRequestSense, 0, SIZEOF(RequestSense_T) );
6428 CDB[0] = SC_COM_RES; /* READ ELEMENT STATUS */
6429 CDB[1] = (u_char)(VolTag | type | lun); /* Element Type Code, VolTag, LUN */
6430 MSB2(&CDB[2], StartAddress); /* Starting Element Address */
6431 MSB2(&CDB[4], NoOfElements); /* Number Of Element */
6432 CDB[6] = 0; /* Reserved */
6433 MSB3(&CDB[7],DataBufferLength); /* Allocation Length */
6434 CDB[10] = 0; /* Reserved */
6435 CDB[11] = 0; /* Control */
6437 ret = SCSI_Run(DeviceFD, Input, CDB, 12,
6438 *data, DataBufferLength,
6439 pRequestSense, SIZEOF(RequestSense_T));
6442 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ReadElementStatus : (2) SCSI_Run %d\n", ret);
6445 DecodeSense(pRequestSense, "SCSI_ReadElementStatus :",debug_file);
6446 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP SCSI_ReadElementStatus (%d)\n",ret);
6452 switch(SenseHandler(DeviceFD, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, pRequestSense))
6455 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ModeSense : SENSE_IGNORE\n");
6459 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ModeSense : SENSE_RETRY no %d\n", retry);
6463 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ModeSense : end %d\n", pRequestSense->SenseKey);
6464 return(pRequestSense->SenseKey);
6477 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP SCSI_ReadElementStatus (%d)\n",ret);
6482 dump_hex(*data, DataBufferLength, DEBUG_INFO, SECTION_SCSI);
6483 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP SCSI_ReadElementStatus (%d)\n",ret);
6487 printf_arglist_function2(void DebugPrint, int, level, int, section, char *, fmt)
6493 time_t ti = time(NULL);
6495 if (changer->debuglevel)
6497 if (sscanf(changer->debuglevel,"%d:%d", &dlevel, &dsection) != 2) {
6498 dbprintf(("Parse error: line is '%s' expected [0-9]*:[0-9]*\n",
6499 changer->debuglevel));
6508 arglist_start(argp, fmt);
6509 vsnprintf(buf, SIZEOF(buf), fmt, argp);
6510 if (dlevel >= level)
6512 if (section == dsection || dsection == 0)
6514 if (index(buf, '\n') != NULL && strlen(buf) > 1)
6516 dbprintf(("%ld:%s", (long)ti, buf));
6518 dbprintf(("%s", buf));