2 static char rcsid[] = "$Id: scsi-changer-driver.c,v 1.49 2006/03/16 00:20:53 paddy_s Exp $";
5 * Interface to control a tape robot/library connected to the SCSI bus
7 * Copyright (c) Thomas Hepper th@ant.han.de
46 #include "scsi-defs.h"
50 extern int TapeEject(int DeviceFD);
52 extern FILE *debug_file;
54 int PrintInquiry(SCSIInquiry_T *);
55 int GenericElementStatus(int DeviceFD, int InitStatus);
56 int SDXElementStatus(int DeviceFD, int InitStatus);
57 int DLT448ElementStatus(int DeviceFD, int InitStatus);
58 ElementInfo_T *LookupElement(int addr);
59 int GenericResetStatus(int DeviceFD);
60 int RequestSense(int, ExtendedRequestSense_T *, int );
61 void dump_hex(char *, int, int, int);
62 void TerminateString(char *string, int length);
63 void ChgExit(char *, char *, int);
66 int SenseHandler(int fd, unsigned char flag, unsigned char SenseKey, unsigned char AdditionalSenseCode, unsigned char AdditionalSenseCodeQualifier, char *buffer);
68 int SCSI_AlignElements(int DeviceFD, int MTE, int DTE, int STE);
71 int GenericMove(int, int, int);
72 int SDXMove(int, int, int);
73 int CheckMove(ElementInfo_T *from, ElementInfo_T *to);
74 int GenericRewind(int);
75 /* int GenericStatus(); */
77 int TapeStatus(); /* Is the tape loaded ? */
78 int DLT4000Eject(char *Device, int type);
79 int GenericEject(char *Device, int type);
80 int GenericClean(char *Device); /* Does the tape need a clean */
81 int GenericBarCode(int DeviceFD); /* Do we have Barcode reader support */
82 int NoBarCode(int DeviceFD);
85 void Inventory(char *labelfile, int drive, int eject, int start, int stop, int clean);
87 int TreeFrogBarCode(int DeviceFD);
88 int EXB_BarCode(int DeviceFD);
89 int GenericSenseHandler(int fd, int flags, unsigned char SenseKey, unsigned char AdditionalSenseCode, unsigned char AdditionalSenseCodeQualifier, char *);
91 ElementInfo_T *LookupElement(int address);
92 int eject_tape(char *tapedev, int type);
93 int unload(int fd, int drive, int slot);
94 int load(int fd, int drive, int slot);
95 int GetElementStatus(int DeviceFD);
100 void WriteErrorCountersPage(LogParameter_T *, int);
101 void ReadErrorCountersPage(LogParameter_T *, int);
102 void C1553APage30(LogParameter_T *, int);
103 void C1553APage37(LogParameter_T *, int);
104 void EXB85058HEPage39(LogParameter_T *, int);
105 void EXB85058HEPage3c(LogParameter_T *, int);
106 int Decode(LogParameter_T *, int *);
107 int DecodeModeSense(char *buffer, int offset, char *pstring, char block, FILE *out);
109 int SCSI_Run(int DeviceFD,
110 Direction_T Direction,
114 int DataBufferLength,
116 int RequestSenseLength);
118 int SCSI_Move(int DeviceFD, unsigned char chm, int from, int to);
119 int SCSI_LoadUnload(int DeviceFD, RequestSense_T *pRequestSense, unsigned char byte1, unsigned char load);
120 int SCSI_TestUnitReady(int, RequestSense_T *);
121 int SCSI_ModeSense(int DeviceFD, char *buffer, u_char size, u_char byte1, u_char byte2);
122 int SCSI_ModeSelect(int DeviceFD,
124 unsigned char length,
129 int SCSI_ReadElementStatus(int DeviceFD,
132 unsigned char VolTag,
140 SC_COM_T SCSICommand[] = {
152 "INITIALIZE ELEMENT STATUS"},
179 "READ ELEMENT STATUS"},
183 ChangerCMD_T ChangerIO[] = {
185 "Generic driver changer [generic_changer]",
187 GenericElementStatus,
195 GenericSenseHandler},
198 "HP Auto Loader [C1553A]",
200 GenericElementStatus,
208 GenericSenseHandler},
209 /* Exabyte Devices */
211 "Exabyte Robot [EXB-10e]",
213 GenericElementStatus,
221 GenericSenseHandler},
223 "Exabyte Robot [EXB-120]",
225 GenericElementStatus,
233 GenericSenseHandler},
235 "Exabyte Robot [EXB-210]",
237 GenericElementStatus,
245 GenericSenseHandler},
247 "Exabyte Tape [EXB-85058HE-0000]",
257 GenericSenseHandler},
258 /* Tandberg Devices */
260 "Tandberg Robot (TDS 1420)",
262 GenericElementStatus,
270 GenericSenseHandler},
273 "ADIC VLS DLT Library [VLS DLT]",
275 GenericElementStatus,
283 GenericSenseHandler},
285 "ADIC VLS DLT Library [VLS SDX]",
295 GenericSenseHandler},
297 "ADIC FastStor DLT Library [FastStor DLT]",
307 GenericSenseHandler},
309 "ADIC DLT 448 [Scalar DLT 448]",
319 GenericSenseHandler},
320 /* Sepctra Logic Devices */
322 "Spectra Logic TreeFrog[215]",
324 GenericElementStatus,
332 GenericSenseHandler},
335 "Breece Hill Quad 7",
337 GenericElementStatus,
345 GenericSenseHandler},
346 /* Quantum Devices */
350 GenericElementStatus,
358 GenericSenseHandler},
360 * And now the tape devices
362 /* The generic handler if nothing matches */
364 "Generic driver tape [generic_tape]",
366 GenericElementStatus,
374 GenericSenseHandler},
376 "DLT Tape [DLT8000]",
386 GenericSenseHandler},
388 "DLT Tape [DLT7000]",
398 GenericSenseHandler},
400 "DLT Tape [DLT4000]",
410 GenericSenseHandler},
411 {NULL, NULL, NULL,NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}
415 LogPageDecode_T DecodePages[] = {
418 WriteErrorCountersPage},
421 ReadErrorCountersPage},
430 WriteErrorCountersPage},
433 ReadErrorCountersPage},
444 int ElementStatusValid = 0; /* Set if the READ ELEMENT STATUS was OK, an no error is pending */
445 int LibModeSenseValid = 0; /* Set if we did an scussefull MODE SENSE */
448 /* Pointer to MODE SENSE Pages */
449 char *pModePage = NULL;
450 EAAPage_T *pEAAPage = NULL;
451 DeviceCapabilitiesPage_T *pDeviceCapabilitiesPage = NULL;
452 char *pVendorUnique = NULL;
455 * New way, every element type has its on array
456 * which is dynamic allocated by the ElementStatus function,
458 ElementInfo_T *pMTE = NULL; /*Medium Transport Element */
459 ElementInfo_T *pSTE = NULL; /*Storage Element */
460 ElementInfo_T *pIEE = NULL; /*Import Export Element */
461 ElementInfo_T *pDTE = NULL; /*Data Transfer Element */
462 int MTE = 0; /*Counter for the above element types */
467 char *chgscsi_datestamp = NULL; /* Result pointer for tape_rdlabel */
468 char *chgscsi_label = NULL; /* Result pointer for tape_rdlabel */
469 char *chgscsi_result = NULL; /* Needed for the result string of MapBarCode */
472 * First all functions which are called from extern
477 * Print the scsi-changer-driver version
480 void ChangerDriverVersion()
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
492 extern OpenFiles_T *pDev;
496 printf("# Please replace every ??? with the correct parameter. It is not possible\n");
497 printf("# to guess everything :-)\n");
498 printf("# If the option is not needed, cleanmax for example if you have no cleaning\n");
499 printf("# tape remove the line.\n");
501 printf("number_configs 1 # Number of configs, you can have more than 1 config\n");
502 printf(" # if you have for example more than one drive, or you\n");
503 printf(" # to split your lib to use different dump levels\n");
505 printf("emubarcode 1 # If you drive has no barcode reader this will try\n");
506 printf(" # keep an inventory of your tapes to find them faster\n");
508 printf("havebarcode 0 # Set this to 1 if you have an library with an installed\n");
509 printf(" # barcode reader\n");
511 printf("debuglevel 0:0 # For debuging, see the docs /docs/TAPE-CHANGER\n");
513 printf("eject ??? # set this to 1 if your drive needs an eject before move\n");
515 printf("sleep ??? # How long to wait after an eject command before moving\n");
516 printf(" # the tape\n");
519 for (count = 0; count < CHG_MAXDEV ; count++)
523 if (pDev[count].inquiry != NULL && pDev[count].inquiry->type == TYPE_CHANGER)
525 printf("changerdev %s # This is the device to communicate with the robot\n", pDev[count].dev);
532 * Did we reach the end of the list ?
533 * If no we found an changer and now we try to
534 * get the element status for the count of slots
536 if (count < CHG_MAXDEV)
538 pDev[count].functions->function_status(count, 1);
540 printf("changerdev ??? # Ups nothing found. Please check the docs\n");
544 printf(" # Here now comes the config for the first tape\n");
545 printf("config 0 # This value is the one which is used in the amanda\n");
546 printf(" # config file to tell the chg-scsi programm which tape\n");
547 printf(" # and which slots to use\n");
549 printf("cleancart ??? # The slot where the cleaning tape is located\n");
550 printf(" # remove it if you have no cleaning tape\n");
552 printf("drivenum 0 # Which tape drive to use if there are more than one drive\n");
554 printf("dev ??? # Which is the raw device to read/write data from the tape\n");
555 printf(" # It is important to use the non rewinding tape, like\n");
556 printf(" # /dev/nrst0 on linux, /dev/nrsa0 on BSD ....\n");
560 * OK now lets see if we have an direct SCSI channel
562 * If not thats not a problem
564 for (count = 0; count < CHG_MAXDEV; count++)
568 if (pDev[count].inquiry != NULL && pDev[count].inquiry->type == TYPE_TAPE)
570 printf("scsitapedev %s # This is the device to communicate with the tape\n", pDev[count].dev);
571 printf(" # to get some device stats, not so importatn, and\n");
572 printf(" # if you run in problems delete it complete\n");
582 printf("startuse 0 # Which is the first slot to use\n");
584 printf("enduse %d # Which is the last slot to use\n", STE);
586 printf("startuse ??? # Which is the first slot to use\n");
588 printf("enduse ??? # Which is the last slot to use\n");
590 printf(" # decrement this value by 1 if you have an\n");
591 printf(" # cleaning tape in the last slot\n");
594 cwd = getcwd(NULL, 0);
596 printf("statfile %s/tape0-slot #\n",cwd);
597 printf("cleanfile %s/tape0-clean #\n", cwd);
598 printf("usagecount %s/tape0-totaltime #\n", cwd);
599 printf("tapestatus %s/tape0-tapestatus #\n", cwd);
600 printf("labelfile %s/labelfile #\n", cwd);
606 * Try to create a list of tapes and labels which are in the current
607 * magazin. The drive must be empty !!
609 * labelfile -> file name of the db
610 * drive -> which drive should we use
611 * eject -> the tape device needs an eject before move
612 * start -> start at slot start
613 * stop -> stop at slot stop
614 * clean -> if we have an cleaning tape than this is the slot number of it
621 * Check if the tape/changer is ready for the next move
622 * If an tape is loaded unload it and do initialize element status to
623 * get all labels if an bar code reader is installed
625 void Inventory(char *labelfile, int drive, int eject, int start, int stop, int clean)
627 extern OpenFiles_T *pDev;
629 char *result; /* Used to store the result of MapBarCode */
630 int barcode; /* cache the result from the BarCode function */
631 static int inv_done = 0; /* Inventory function called ?, marker to disable recursion */
632 MBC_T *pbarcoderes; /* Here we will pass the parameter to MapBarCode and get the result */
634 DebugPrint(DEBUG_INFO,SECTION_MAP_BARCODE, "##### START Inventory\n");
635 if ((pbarcoderes = malloc(sizeof(MBC_T))) == NULL)
637 DebugPrint(DEBUG_ERROR, SECTION_MAP_BARCODE,"##### malloc failed (-1)\n");
640 memset(pbarcoderes, 0 , sizeof(MBC_T));
644 DebugPrint(DEBUG_INFO,SECTION_MAP_BARCODE, "##### STOP inv_done -> %d Inventory\n",inv_done);
649 barcode = BarCode(INDEX_CHANGER);
651 pbarcoderes->action = RESET_VALID;
653 MapBarCode(labelfile,pbarcoderes);
656 * Check if an tape is loaded, if yes unload it
657 * and do an INIT ELEMENT STATUS
660 if (pDTE[0].status == 'F')
664 eject_tape("", eject);
666 (void)unload(INDEX_TAPE, 0, 0);
669 GenericResetStatus(INDEX_CHANGER);
671 for (x = 0; x < STE; x++)
679 * Load the tape, on error try the next
680 * error could be an empty slot for example
682 if (load(INDEX_CHANGER, drive, x ) != 0)
684 DebugPrint(DEBUG_ERROR,SECTION_MAP_BARCODE, "Load drive(%d) from(%d) failed\n", drive, x);
689 * Wait until the tape is ready
691 Tape_Ready(INDEX_TAPECTL, 60);
693 SCSI_CloseDevice(INDEX_TAPE);
695 if ((result = (char *)tape_rdlabel(pDev[INDEX_TAPE].dev, &chgscsi_datestamp, &chgscsi_label)) == NULL)
697 pbarcoderes->action = UPDATE_SLOT;
698 strcpy(pbarcoderes->data.voltag, chgscsi_label);
699 pbarcoderes->data.slot = x;
700 pbarcoderes->data.from = 0;
701 pbarcoderes->data.LoadCount = 1;
702 if (BarCode(INDEX_CHANGER) == 1)
704 strcpy(pbarcoderes->data.barcode, pDTE[drive].VolTag);
705 MapBarCode(labelfile, pbarcoderes);
707 MapBarCode(labelfile, pbarcoderes);
710 DebugPrint(DEBUG_ERROR,SECTION_MAP_BARCODE, "Read label failed\n");
715 eject_tape("", eject);
718 (void)unload(INDEX_TAPE, drive, x);
720 DebugPrint(DEBUG_INFO,SECTION_MAP_BARCODE, "##### STOP Inventory\n");
725 * Check if the slot ist empty
726 * slot -> slot number to check
728 int isempty(int fd, int slot)
730 extern OpenFiles_T *pDev;
731 DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### START isempty\n");
733 if (ElementStatusValid == 0)
735 if ( pDev[fd].functions->function_status(fd, 1) != 0)
737 DebugPrint(DEBUG_ERROR,SECTION_TAPE,"##### STOP isempty [-1]\n");
742 if (pSTE[slot].status == 'E')
744 DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### STOP isempty [1]\n");
747 DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### STOP isempty [0]\n");
751 int get_clean_state(char *tapedev)
753 extern OpenFiles_T *pDev;
754 /* Return 1 if cleaning is needed */
757 DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### START get_clean_state\n");
759 if (pDev[INDEX_TAPECTL].SCSI == 0)
761 DebugPrint(DEBUG_ERROR,SECTION_TAPE,"##### STOP get_clean_state [-1]\n");
764 ret=pDev[INDEX_TAPECTL].functions->function_clean(tapedev);
765 DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### STOP get_clean_state [%d]\n", ret);
771 * The parameter tapedev is not used.
772 * Type describes if we should force the SCSI eject if available
773 * normal eject is done with the ioctl
775 int eject_tape(char *tapedev, int type)
776 /* This function ejects the tape from the drive */
778 extern OpenFiles_T *pDev;
780 extern changer_t chg; /* Needed for the infos about emubarcode and labelfile */
782 DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### START eject_tape\n");
785 * Try to read the label
787 if (pDev[INDEX_TAPE].avail == 1 && (chg.emubarcode == 1 || BarCode(INDEX_CHANGER)))
790 if (pDev[INDEX_TAPECTL].SCSI == 1 && pDev[INDEX_TAPECTL].avail) {
791 pDev[INDEX_TAPECTL].functions->function_rewind(INDEX_TAPECTL);
793 pDev[INDEX_TAPE].functions->function_rewind(INDEX_TAPE);
796 if (pDev[INDEX_TAPE].devopen == 1)
798 SCSI_CloseDevice(INDEX_TAPE);
801 chgscsi_result = (char *)tape_rdlabel(pDev[INDEX_TAPE].dev, &chgscsi_datestamp, &chgscsi_label);
804 if (pDev[INDEX_TAPECTL].SCSI == 1 && pDev[INDEX_TAPECTL].avail == 1 && type == 1)
806 ret=pDev[INDEX_TAPECTL].functions->function_eject(tapedev, type);
807 DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### STOP (SCSI)eject_tape [%d]\n", ret);
811 if (pDev[INDEX_TAPE].avail == 1)
813 ret=Tape_Ioctl(INDEX_TAPE, IOCTL_EJECT);
814 DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### STOP (ioctl)eject_tape [%d]\n", ret);
818 DebugPrint(DEBUG_INFO,SECTION_TAPE,"##### STOP eject_tape [-1]\n");
823 /* Find an empty slot, starting at start, ending at start+count */
824 int find_empty(int fd, int start, int count)
826 extern OpenFiles_T *pDev;
830 DebugPrint(DEBUG_INFO,SECTION_ELEMENT,"###### START find_empty\n");
832 if (ElementStatusValid == 0)
834 if ( pDev[fd].functions->function_status(fd , 1) != 0)
836 DebugPrint(DEBUG_ERROR,SECTION_ELEMENT,"###### END find_empty [%d]\n", -1);
853 DebugPrint(DEBUG_INFO,SECTION_ELEMENT,"start at %d, end at %d\n", start, end);
855 for (x = start; x < end; x++)
857 if (pSTE[x].status == 'E')
859 DebugPrint(DEBUG_INFO,SECTION_ELEMENT,"###### END find_empty [%d]\n", x);
863 DebugPrint(DEBUG_ERROR,SECTION_ELEMENT,"###### END find_empty [%d]\n", -1);
868 * See if the tape is loaded based on the information we
869 * got back from the ReadElementStatus
871 * -1 -> Error (Fatal)
872 * 0 -> drive is empty
873 * 1 -> drive is loaded
875 int drive_loaded(int fd, int drivenum)
877 extern OpenFiles_T *pDev;
879 DebugPrint(DEBUG_INFO,SECTION_TAPE,"###### START drive_loaded\n");
880 DebugPrint(DEBUG_INFO,SECTION_TAPE,"%-20s : fd %d drivenum %d \n", "drive_loaded", fd, drivenum);
883 if (ElementStatusValid == 0)
885 if (pDev[INDEX_CHANGER].functions->function_status(INDEX_CHANGER, 1) != 0)
887 DebugPrint(DEBUG_ERROR,SECTION_TAPE,"Fatal error\n");
892 if (pDTE[drivenum].status == 'E') {
893 DebugPrint(DEBUG_INFO,SECTION_TAPE,"###### STOP drive_loaded (empty)\n");
896 DebugPrint(DEBUG_INFO,SECTION_TAPE,"###### STOP drive_loaded (not empty)\n");
903 * unload the specified drive into the specified slot
907 * Check if the MTE is empty
909 int unload(int fd, int drive, int slot)
911 extern OpenFiles_T *pDev;
913 extern changer_t chg; /* Needed for the infos about emubarcode and labelfile */
914 extern int do_inventory;
917 DebugPrint(DEBUG_INFO, SECTION_TAPE,"###### START unload\n");
918 DebugPrint(DEBUG_INFO, SECTION_TAPE,"%-20s : fd %d, slot %d, drive %d \n", "unload", fd, slot, drive);
919 if ((pbarcoderes = malloc(sizeof(MBC_T))) == NULL)
921 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"##### malloc failed (-1)\n");
924 memset(pbarcoderes, 0, sizeof(MBC_T));
927 * If the Element Status is not valid try to
930 if (ElementStatusValid == 0)
932 if (pDev[INDEX_CHANGER].functions->function_status(INDEX_CHANGER , 1) != 0)
934 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"Element Status not valid, reset failed\n");
935 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"##### STOP unload (-1)\n");
941 DebugPrint(DEBUG_INFO, SECTION_TAPE,"%-20s : unload drive %d[%d] slot %d[%d]\n", "unload",
948 * Unloading an empty tape unit makes no sense
949 * so return with an error
951 if (pDTE[drive].status == 'E')
953 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"unload : Drive %d address %d is empty\n", drive, pDTE[drive].address);
954 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"##### STOP unload (-1)\n");
960 * If the destination slot is full
961 * try to find an enpty slot
963 if (pSTE[slot].status == 'F')
965 DebugPrint(DEBUG_INFO, SECTION_TAPE,"unload : Slot %d address %d is full\n", drive, pSTE[slot].address);
966 if ( ElementStatusValid == 0)
968 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "unload: Element Status not valid, can't find an empty slot\n");
973 slot = find_empty(fd, 0, 0);
976 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "unload: No Empty slot found\n");
980 DebugPrint(DEBUG_INFO, SECTION_TAPE,"unload : found empty one, try to unload to slot %d\n", slot);
986 * If eject is not set we must read the label info
991 if (pDev[INDEX_TAPE].avail == 1 && (chg.emubarcode == 1 || BarCode(INDEX_CHANGER)))
994 if (pDev[INDEX_TAPECTL].SCSI == 1 && pDev[INDEX_TAPECTL].avail) {
995 pDev[INDEX_TAPECTL].functions->function_rewind(INDEX_TAPECTL);
997 pDev[INDEX_TAPE].functions->function_rewind(INDEX_TAPE);
1000 if (pDev[INDEX_TAPE].devopen == 1)
1002 SCSI_CloseDevice(INDEX_TAPE);
1005 chgscsi_result = (char *)tape_rdlabel(pDev[INDEX_TAPE].dev, &chgscsi_datestamp, &chgscsi_label);
1010 * Do the unload/move
1012 ret = pDev[INDEX_CHANGER].functions->function_move(INDEX_CHANGER , pDTE[drive].address, pSTE[slot].address);
1017 if (pDev[INDEX_CHANGER].functions->function_status(INDEX_CHANGER , 1) != 0)
1019 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"##### STOP unload (-1 update status failed)\n");
1025 * Did we get an error from tape_rdlabel
1026 * if no update the vol/label mapping
1027 * If chgscsi_label is NULL don't do it
1029 if (chgscsi_result == NULL && chgscsi_label != NULL && chg.labelfile != NULL)
1032 * OK this is only needed if we have emubarcode set
1033 * There we need an exact inventory to get the search function working
1034 * and returning correct results
1036 if (BarCode(INDEX_CHANGER) == 0 && chg.emubarcode == 1)
1039 * We got something, update the db
1040 * but before check if the db has as entry the slot
1041 * to where we placed the tape, if no force an inventory
1043 pbarcoderes->action = FIND_SLOT;
1044 strcpy(pbarcoderes->data.voltag, chgscsi_label);
1045 strcpy(pbarcoderes->data.barcode, pSTE[slot].VolTag );
1046 pbarcoderes->data.slot = 0;
1047 pbarcoderes->data.from = 0;
1048 pbarcoderes->data.LoadCount = 0;
1051 if ( MapBarCode(chg.labelfile, pbarcoderes) == 0) /* Nothing known about this, do an Inventory */
1055 if (slot != pbarcoderes->data.slot)
1057 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"Slot DB out of sync, slot %d != map %d",slot, pbarcoderes->data.slot);
1064 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### STOP unload(0)\n");
1071 * load the media from the specified element (slot) into the
1072 * specified data transfer unit (drive)
1073 * fd -> pointer to the internal device structure pDev
1074 * driver -> which drive in the library
1075 * slot -> the slot number from where to load
1077 * return -> 0 = success
1080 int load(int fd, int drive, int slot)
1082 extern changer_t chg; /* Needed for the infos about emubarcode and labelfile */
1083 char *result = NULL; /* Needed for the result of tape_rdlabel */
1085 extern OpenFiles_T *pDev;
1086 extern int do_inventory;
1089 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"###### START load\n");
1090 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"%-20s : fd %d, drive %d, slot %d \n", "load", fd, drive, slot);
1091 if ((pbarcoderes = malloc(sizeof(MBC_T))) == NULL)
1093 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"##### malloc failed (-1)\n");
1096 memset(pbarcoderes, 0 , sizeof(MBC_T));
1098 if (ElementStatusValid == 0)
1100 if (pDev[fd].functions->function_status(fd, 1) != 0)
1102 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"##### STOP load (-1)\n");
1103 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"##### STOP load (-1 update status failed)\n");
1110 * Check if the requested slot is in the range of available slots
1111 * The library starts counting at 1, we start at 0, so if the request slot
1112 * is ge than the value we got from the ModeSense fail with an return value
1117 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"load : slot %d ge STE %d\n",slot, STE);
1118 ChgExit("load", "slot >= STE", FATAL);
1122 * And the same for the tape drives
1126 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"load : drive %d ge DTE %d\n",drive, DTE);
1127 ChgExit("load", "drive >= DTE", FATAL);
1130 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"load : load drive %d[%d] slot %d[%d]\n",drive,
1131 pDTE[drive].address,
1133 pSTE[slot].address);
1135 if (pDTE[drive].status == 'F')
1137 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"load : Drive %d address %d is full\n", drive, pDTE[drive].address);
1138 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"##### STOP load (-1 update status failed)\n");
1143 if (pSTE[slot].status == 'E')
1145 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"load : Slot %d address %d is empty\n", drive, pSTE[slot].address);
1146 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"##### STOP load (-1 update status failed)\n");
1151 ret = pDev[fd].functions->function_move(fd, pSTE[slot].address, pDTE[drive].address);
1156 if (pDev[fd].functions->function_status(fd, 1) != 0)
1158 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"##### STOP load (-1 update status failed)\n");
1164 * Try to read the label
1165 * and update the label/slot database
1167 if (pDev[INDEX_TAPE].avail == 1 && (chg.emubarcode == 1 || BarCode(INDEX_CHANGER)))
1170 if (pDev[INDEX_TAPECTL].SCSI == 1 && pDev[INDEX_TAPECTL].avail) {
1171 pDev[INDEX_TAPECTL].functions->function_rewind(INDEX_TAPECTL);
1173 pDev[INDEX_TAPE].functions->function_rewind(INDEX_TAPE);
1176 if (pDev[INDEX_TAPE].devopen == 1)
1178 SCSI_CloseDevice(INDEX_TAPE);
1181 result = (char *)tape_rdlabel(pDev[INDEX_TAPE].dev, &chgscsi_datestamp, &chgscsi_label);
1185 * Did we get an error from tape_rdlabel
1186 * if no update the vol/label mapping
1188 if (result == NULL && chg.labelfile != NULL && chgscsi_label != NULL )
1191 * We got something, update the db
1192 * but before check if the db has as entry the slot
1193 * to where we placed the tape, if no force an inventory
1195 strcpy(pbarcoderes->data.voltag, chgscsi_label);
1196 pbarcoderes->data.slot = 0;
1197 pbarcoderes->data.from = 0;
1198 pbarcoderes->data.LoadCount = 0;
1202 * If we have an barcode reader we only do an update
1203 * If emubarcode is set we check if the
1204 * info in the DB is up to date, if no we set the do_inventory flag
1207 if (BarCode(INDEX_CHANGER) == 1 && chg.emubarcode == 0)
1209 pbarcoderes->action = UPDATE_SLOT;
1210 strcpy(pbarcoderes->data.barcode, pDTE[drive].VolTag);
1211 pbarcoderes->data.LoadCount = 1;
1212 pbarcoderes->data.slot = slot;
1213 MapBarCode(chg.labelfile, pbarcoderes);
1216 if (BarCode(INDEX_CHANGER) == 0 && chg.emubarcode == 1)
1218 pbarcoderes->action = FIND_SLOT;
1219 if (MapBarCode(chg.labelfile, pbarcoderes) == 0) /* Nothing found, do an inventory */
1222 } else { /* We got something, is it correct ? */
1223 if (slot != pbarcoderes->data.slot && do_inventory == 0)
1225 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"Slot DB out of sync, slot %d != map %d",slot, pbarcoderes->data.slot);
1226 ChgExit("Load", "Label DB out of sync", FATAL);
1227 } else { /* OK, so increment the load count */
1228 pbarcoderes->action = UPDATE_SLOT;
1229 pbarcoderes->data.LoadCount = 1;
1230 pbarcoderes->data.slot = slot;
1231 MapBarCode(chg.labelfile, pbarcoderes);
1236 if (BarCode(INDEX_CHANGER) == 1 && chg.emubarcode == 1)
1238 ChgExit("Load", "BarCode == 1 and emubarcode == 1", FATAL);
1241 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"##### STOP load (%d)\n",ret);
1245 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"##### STOP load (%d)\n",ret);
1251 * Returns the number of Storage Slots which the library has
1252 * fd -> pointer to the internal devie structure pDev
1253 * return -> Number of slots
1255 int get_slot_count(int fd)
1257 extern OpenFiles_T *pDev;
1259 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"###### START get_slot_count\n");
1260 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"%-20s : fd %d\n", "get_slot_count", fd);
1262 if (ElementStatusValid == 0)
1264 pDev[fd].functions->function_status(fd, 1);
1266 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"##### STOP get_slot_count (%d)\n",STE);
1269 * return the number of slots in the robot
1277 * retreive the number of data-transfer devices /Tape drives)
1278 * fd -> pointer to the internal devie structure pDev
1279 * return -> -1 on failure
1281 int get_drive_count(int fd)
1284 extern OpenFiles_T *pDev;
1286 DebugPrint(DEBUG_INFO, SECTION_SCSI,"###### START get_drive_count\n");
1287 DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-20s : fd %d\n", "get_drive_count", fd);
1290 if (ElementStatusValid == 0)
1292 if ( pDev[fd].functions->function_status(fd, 1) != 0)
1294 DebugPrint(DEBUG_ERROR, SECTION_SCSI, "Error getting drive count\n");
1295 DebugPrint(DEBUG_ERROR, SECTION_SCSI, "##### STOP get_drive_count (-1)\n");
1299 DebugPrint(DEBUG_INFO, SECTION_SCSI,"###### STOP get_drive_count (%d drives)\n",DTE);
1304 * Now the internal functions
1308 * Open the device and placeit in the list of open files
1309 * The OS has to decide if it is an SCSI Commands capable device
1312 int OpenDevice(int ip , char *DeviceName, char *ConfigName, char *ident)
1314 extern OpenFiles_T *pDev;
1316 ChangerCMD_T *p = (ChangerCMD_T *)&ChangerIO;
1318 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### START OpenDevice\n");
1319 DebugPrint(DEBUG_INFO, SECTION_SCSI,"OpenDevice : %s\n", DeviceName);
1321 pDev[ip].ConfigName = strdup(ConfigName);
1322 pDev[ip].dev = strdup(DeviceName);
1324 if (SCSI_OpenDevice(ip) != 0 )
1326 if (ident != NULL) /* Override by config */
1328 while(p->ident != NULL)
1330 if (strcmp(ident, p->ident) == 0)
1332 pDev[ip].functions = p;
1333 strncpy(pDev[ip].ident, ident, 17);
1334 DebugPrint(DEBUG_INFO, SECTION_SCSI,"override using ident = %s, type = %s\n",p->ident, p->type);
1335 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP OpenDevice\n");
1340 ChgExit("OpenDevice", "ident not found", FATAL);
1342 while(p->ident != NULL)
1344 if (strcmp(pDev[ip].ident, p->ident) == 0)
1346 pDev[ip].functions = p;
1347 DebugPrint(DEBUG_INFO, SECTION_SCSI,"using ident = %s, type = %s\n",p->ident, p->type);
1348 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP OpenDevice\n");
1354 /* Nothing matching found, try generic */
1355 /* divide generic in generic_type, where type is the */
1356 /* num returned by the inquiry command */
1357 p = (ChangerCMD_T *)&ChangerIO;
1358 sprintf(&tmpstr[0],"%s_%s","generic",pDev[0].type);
1359 while(p->ident != NULL)
1361 if (strcmp(tmpstr, p->ident) == 0)
1363 pDev[ip].functions = p;
1364 DebugPrint(DEBUG_INFO, SECTION_SCSI,"using ident = %s, type = %s\n",p->ident, p->type);
1365 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP OpenDevice\n");
1370 } else { /* Something failed, lets see what */
1371 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"##### STOP OpenDevice failed\n");
1373 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP OpenDevice (nothing found) !!\n");
1379 * This functions checks if the library has an barcode reader.
1380 * fd -> pointer to the internal devie structure pDev
1385 extern OpenFiles_T *pDev;
1387 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"##### START BarCode\n");
1388 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"%-20s : fd %d\n", "BarCode", fd);
1390 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"Ident = [%s], function = [%s]\n", pDev[fd].ident,
1391 pDev[fd].functions->ident);
1392 ret = pDev[fd].functions->function_barcode(fd);
1393 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"##### STOP BarCode (%d)\n",ret);
1399 * This functions check if the tape drive is ready
1401 * fd -> pointer to the internal devie structure pDev
1402 * wait -> time to wait for the ready status
1405 int Tape_Ready(int fd, int wait_time)
1407 extern OpenFiles_T *pDev;
1412 RequestSense_T *pRequestSense;
1413 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### START Tape_Ready\n");
1416 * Which device should we use to get the
1421 * First the ioctl tapedevice
1423 if (pDev[INDEX_TAPE].avail == 1)
1429 * But if available and can do SCSI
1432 if (pDev[INDEX_TAPECTL].avail == 1 && pDev[INDEX_TAPECTL].SCSI == 1)
1437 if (pDev[fd].avail == 1 && pDev[fd].SCSI == 0)
1439 DebugPrint(DEBUG_INFO, SECTION_TAPE,"Tape_Ready : Can't send SCSI commands, try ioctl\n");
1441 * Do we get an non negative result.
1442 * If yes this function is available
1443 * and we can use it to get the status
1446 ret = Tape_Status(fd);
1449 while (cnt < wait_time)
1451 if ( ret & TAPE_ONLINE)
1453 DebugPrint(DEBUG_INFO, SECTION_TAPE,"Tape_Ready : Ready after %d seconds\n",cnt);
1454 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### STOP Tape_Ready\n");
1459 ret = Tape_Status(fd);
1462 DebugPrint(DEBUG_INFO, SECTION_TAPE,"Tape_Ready : not ready, stop after %d seconds\n",cnt);
1463 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### STOP Tape_Ready\n");
1467 DebugPrint(DEBUG_INFO, SECTION_TAPE,"Tape_Ready : no ioctl interface, will sleep for %d seconds\n", wait_time);
1469 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### STOP Tape_Ready\n");
1474 if ((pRequestSense = (RequestSense_T *)malloc(sizeof(RequestSense_T))) == NULL)
1476 DebugPrint(DEBUG_INFO, SECTION_TAPE,"Tape_Ready : malloc failed\n");
1477 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### STOP Tape_Ready\n");
1482 * Ignore errors at this point
1487 * Wait until we get an ready condition
1490 while (true && cnt < wait_time)
1492 ret = SCSI_TestUnitReady(fd, pRequestSense );
1499 switch (SenseHandler(fd, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, (char *)pRequestSense))
1502 DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeReady (TestUnitReady) SENSE_NO\n");
1505 case SENSE_TAPE_NOT_ONLINE:
1506 DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeReady (TestUnitReady) SENSE_TAPE_NOT_ONLINE\n");
1509 DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeReady (TestUnitReady) SENSE_IGNORE\n");
1513 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"TapeReady (TestUnitReady) SENSE_ABORT\n");
1514 free(pRequestSense);
1518 DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeReady (TestUnitReady) SENSE_RETRY\n");
1521 DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeReady (TestUnitReady) default (SENSE)\n");
1527 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"TapeReady (TestUnitReady) SCSI_ERROR\n");
1528 free(pRequestSense);
1532 DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeReady (TestUnitReady) SCSI_BUSY\n");
1535 DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeReady (TestUnitReady) SCSI_CHECK\n");
1538 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"TapeReady (TestUnitReady) unknown (%d)\n",ret);
1545 DebugPrint(DEBUG_INFO, SECTION_TAPE,"Tape_Ready after %d sec\n", cnt);
1546 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### STOP Tape_Ready\n");
1547 free(pRequestSense);
1552 int DecodeSCSI(CDB_T CDB, char *string)
1554 SC_COM_T *pSCSICommand;
1557 DebugPrint(DEBUG_INFO, SECTION_SCSI, "##### START DecodeSCSI\n");
1558 pSCSICommand = (SC_COM_T *)&SCSICommand;
1560 while (pSCSICommand->name != NULL)
1562 if (CDB[0] == pSCSICommand->command)
1564 DebugPrint(DEBUG_INFO, SECTION_SCSI,"%s %s", string, pSCSICommand->name);
1565 for (x=0; x < pSCSICommand->length; x++)
1567 DebugPrint(DEBUG_INFO, SECTION_SCSI," %02X", CDB[x]);
1569 DebugPrint(DEBUG_INFO, SECTION_SCSI,"\n");
1570 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP DecodeSCSI\n");
1575 DebugPrint(DEBUG_INFO, SECTION_SCSI,"Not found %X\n", CDB[0]);
1576 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP DecodeSCSI\n");
1580 int DecodeModeSense(char *buffer, int offset, char *pstring, char block, FILE *out)
1582 ReadWriteErrorRecoveryPage_T *prp;
1583 DisconnectReconnectPage_T *pdrp;
1584 int length = (unsigned char)*buffer - 4 - offset;
1586 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### START DecodeModeSense\n");
1588 dump_hex(buffer, 255, DEBUG_INFO, SECTION_SCSI);
1590 /* Jump over the Parameter List header and an offset if we have something
1591 * Unknown at the start (ADIC-218) at the moment
1594 buffer = buffer + 4 + offset;
1596 DebugPrint(DEBUG_INFO, SECTION_SCSI,"buffer length = %d\n", length);
1598 if (block) /* Do we have an block descriptor page ?*/
1601 fprintf(out, "DecodeModeSense : Density Code %x\n", buffer[0]);
1605 fprintf(out, "DecodeModeSense : Number of Blocks %d\n", V3(buffer));
1606 buffer = buffer + 4;
1609 fprintf(out, "DecodeModeSense : Block Length %d\n", V3(buffer));
1610 buffer = buffer + 3;
1615 switch (*buffer & 0x3f)
1618 pVendorUnique = buffer;
1622 prp = (ReadWriteErrorRecoveryPage_T *)buffer;
1625 fprintf(out, "DecodeModeSense : Read/Write Error Recovery Page\n");
1626 fprintf(out,"\tTransfer Block %d\n", prp->tb);
1627 fprintf(out,"\tEnable Early Recovery %d\n", prp->eer);
1628 fprintf(out,"\tPost Error %d\n", prp->per);
1629 fprintf(out,"\tDisable Transfer on Error %d\n", prp->dte);
1630 fprintf(out,"\tDisable ECC Correction %d\n", prp->dcr);
1631 fprintf(out,"\tRead Retry Count %d\n", prp->ReadRetryCount);
1632 fprintf(out,"\tWrite Retry Count %d\n", prp->WriteRetryCount);
1637 pdrp = (DisconnectReconnectPage_T *)buffer;
1640 fprintf(out, "DecodeModeSense : Disconnect/Reconnect Page\n");
1641 fprintf(out,"\tBuffer Full Ratio %d\n", pdrp->BufferFullRatio);
1642 fprintf(out,"\tBuffer Empty Ratio %d\n", pdrp->BufferEmptyRatio);
1643 fprintf(out,"\tBus Inactivity Limit %d\n",
1644 V2(pdrp->BusInactivityLimit));
1645 fprintf(out,"\tDisconnect Time Limit %d\n",
1646 V2(pdrp->DisconnectTimeLimit));
1647 fprintf(out,"\tConnect Time Limit %d\n",
1648 V2(pdrp->ConnectTimeLimit));
1649 fprintf(out,"\tMaximum Burst Size %d\n",
1650 V2(pdrp->MaximumBurstSize));
1651 fprintf(out,"\tDTDC %d\n", pdrp->DTDC);
1656 pEAAPage = (EAAPage_T *)buffer;
1659 fprintf(out,"DecodeModeSense : Element Address Assignment Page\n");
1660 fprintf(out,"\tMedium Transport Element Address %d\n",
1661 V2(pEAAPage->MediumTransportElementAddress));
1662 fprintf(out,"\tNumber of Medium Transport Elements %d\n",
1663 V2(pEAAPage->NoMediumTransportElements));
1664 fprintf(out, "\tFirst Storage Element Address %d\n",
1665 V2(pEAAPage->FirstStorageElementAddress));
1666 fprintf(out, "\tNumber of Storage Elements %d\n",
1667 V2(pEAAPage->NoStorageElements));
1668 fprintf(out, "\tFirst Import/Export Element Address %d\n",
1669 V2(pEAAPage->FirstImportExportElementAddress));
1670 fprintf(out, "\tNumber of ImportExport Elements %d\n",
1671 V2(pEAAPage->NoImportExportElements));
1672 fprintf(out, "\tFirst Data Transfer Element Address %d\n",
1673 V2(pEAAPage->FirstDataTransferElementAddress));
1674 fprintf(out, "\tNumber of Data Transfer Elements %d\n",
1675 V2(pEAAPage->NoDataTransferElements));
1680 pDeviceCapabilitiesPage = (DeviceCapabilitiesPage_T *)buffer;
1683 fprintf(out, "DecodeModeSense : MT can store data cartridges %d\n",
1684 pDeviceCapabilitiesPage->MT);
1685 fprintf(out, "DecodeModeSense : ST can store data cartridges %d\n",
1686 pDeviceCapabilitiesPage->ST);
1687 fprintf(out, "DecodeModeSense : IE can store data cartridges %d\n",
1688 pDeviceCapabilitiesPage->IE);
1689 fprintf(out, "DecodeModeSense : DT can store data cartridges %d\n",
1690 pDeviceCapabilitiesPage->DT);
1691 fprintf(out, "DecodeModeSense : MT to MT %d\n",
1692 pDeviceCapabilitiesPage->MT2MT);
1693 fprintf(out, "DecodeModeSense : MT to ST %d\n",
1694 pDeviceCapabilitiesPage->MT2ST);
1695 fprintf(out, "DecodeModeSense : MT to IE %d\n",
1696 pDeviceCapabilitiesPage->MT2IE);
1697 fprintf(out, "DecodeModeSense : MT to DT %d\n",
1698 pDeviceCapabilitiesPage->MT2DT);
1699 fprintf(out, "DecodeModeSense : ST to MT %d\n",
1700 pDeviceCapabilitiesPage->ST2ST);
1701 fprintf(out, "DecodeModeSense : ST to MT %d\n",
1702 pDeviceCapabilitiesPage->ST2ST);
1703 fprintf(out, "DecodeModeSense : ST to DT %d\n",
1704 pDeviceCapabilitiesPage->ST2DT);
1705 fprintf(out, "DecodeModeSense : IE to MT %d\n",
1706 pDeviceCapabilitiesPage->IE2MT);
1707 fprintf(out, "DecodeModeSense : IE to ST %d\n",
1708 pDeviceCapabilitiesPage->IE2IE);
1709 fprintf(out, "DecodeModeSense : IE to ST %d\n",
1710 pDeviceCapabilitiesPage->IE2DT);
1711 fprintf(out, "DecodeModeSense : IE to ST %d\n",
1712 pDeviceCapabilitiesPage->IE2DT);
1713 fprintf(out, "DecodeModeSense : DT to MT %d\n",
1714 pDeviceCapabilitiesPage->DT2MT);
1715 fprintf(out, "DecodeModeSense : DT to ST %d\n",
1716 pDeviceCapabilitiesPage->DT2ST);
1717 fprintf(out, "DecodeModeSense : DT to IE %d\n",
1718 pDeviceCapabilitiesPage->DT2IE);
1719 fprintf(out, "DecodeModeSense : DT to DT %d\n",
1720 pDeviceCapabilitiesPage->DT2DT);
1725 buffer++; /* set pointer to the length information */
1728 /* Error if *buffer (length) is 0 */
1731 /* EAAPage = NULL; */
1732 /* DeviceCapabilitiesPage = NULL; */
1735 length = length - *buffer - 2;
1736 buffer = buffer + *buffer + 1;
1741 int DecodeSense(RequestSense_T *sense, char *pstring, FILE *out)
1747 fprintf(out,"##### START DecodeSense\n");
1748 fprintf(out,"%sSense Keys\n", pstring);
1749 if (sense->ErrorCode == 0x70)
1751 fprintf(out,"\tExtended Sense \n");
1753 fprintf(out,"\tErrorCode %02x\n", sense->ErrorCode);
1754 fprintf(out,"\tValid %d\n", sense->Valid);
1756 fprintf(out,"\tASC %02X\n", sense->AdditionalSenseCode);
1757 fprintf(out,"\tASCQ %02X\n", sense->AdditionalSenseCodeQualifier);
1758 fprintf(out,"\tSense key %02X\n", sense->SenseKey);
1759 switch (sense->SenseKey)
1762 fprintf(out,"\t\tNo Sense\n");
1765 fprintf(out,"\t\tRecoverd Error\n");
1768 fprintf(out,"\t\tNot Ready\n");
1771 fprintf(out,"\t\tMedium Error\n");
1774 fprintf(out,"\t\tHardware Error\n");
1777 fprintf(out,"\t\tIllegal Request\n");
1780 fprintf(out,"\t\tUnit Attention\n");
1783 fprintf(out,"\t\tData Protect\n");
1786 fprintf(out,"\t\tBlank Check\n");
1789 fprintf(out,"\t\tVendor uniq\n");
1792 fprintf(out,"\t\tCopy Aborted\n");
1795 fprintf(out,"\t\tAborted Command\n");
1798 fprintf(out,"\t\tEqual\n");
1801 fprintf(out,"\t\tVolume Overflow\n");
1804 fprintf(out,"\t\tMiscompare\n");
1807 fprintf(out,"\t\tReserved\n");
1813 int DecodeExtSense(ExtendedRequestSense_T *sense, char *pstring, FILE *out)
1815 ExtendedRequestSense_T *p;
1817 fprintf(out,"##### START DecodeExtSense\n");
1820 fprintf(out,"%sExtended Sense\n", pstring);
1821 DecodeSense((RequestSense_T *)p, pstring, out);
1822 fprintf(out,"\tLog Parameter Page Code %02X\n", sense->LogParameterPageCode);
1823 fprintf(out,"\tLog Parameter Code %02X\n", sense->LogParameterCode);
1824 fprintf(out,"\tUnderrun/Overrun Counter %02X\n", sense->UnderrunOverrunCounter);
1825 fprintf(out,"\tRead/Write Error Counter %d\n", V3((char *)sense->ReadWriteDataErrorCounter));
1826 if (sense->AdditionalSenseLength > sizeof(RequestSense_T))
1829 fprintf(out,"\tPower Fail\n");
1831 fprintf(out,"\tSCSI Bus Parity Error\n");
1833 fprintf(out,"\tFormatted Buffer parity Error\n");
1835 fprintf(out,"\tMedia Error\n");
1837 fprintf(out,"\tError Counter Overflow\n");
1839 fprintf(out,"\tTapeMotion Error\n");
1841 fprintf(out,"\tTape Not Present\n");
1843 fprintf(out,"\tLogical Beginning of tape\n");
1845 fprintf(out,"\tTape Mark Detect Error\n");
1847 fprintf(out,"\tWrite Protect\n");
1849 fprintf(out,"\tFilemark Error\n");
1851 fprintf(out,"\tUnder Run Error\n");
1853 fprintf(out,"\tWrite Error 1\n");
1855 fprintf(out,"\tServo System Error\n");
1857 fprintf(out,"\tFormatter Error\n");
1859 fprintf(out,"\tCleaning Cartridge is empty\n");
1861 fprintf(out,"\tReverse Retries Required\n");
1863 fprintf(out,"\tTape Drive has been cleaned\n");
1865 fprintf(out,"\tTape Drive needs to be cleaned\n");
1867 fprintf(out,"\tPhysical End of Tape\n");
1869 fprintf(out,"\tWrite Splice Error\n");
1871 fprintf(out,"\tWrite Splice Error\n");
1872 fprintf(out,"\tRemaing 1024 byte tape blocks %d\n", V3((char *)sense->RemainingTape));
1873 fprintf(out,"\tTracking Retry Counter %02X\n", sense->TrackingRetryCounter);
1874 fprintf(out,"\tRead/Write Retry Counter %02X\n", sense->ReadWriteRetryCounter);
1875 fprintf(out,"\tFault Sympton Code %02X\n", sense->FaultSymptomCode);
1880 int PrintInquiry(SCSIInquiry_T *SCSIInquiry)
1882 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### START PrintInquiry\n");
1883 DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-15s %x\n", "qualifier", SCSIInquiry->qualifier);
1884 DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-15s %x\n", "type", SCSIInquiry->type);
1885 DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-15s %x\n", "data_format", SCSIInquiry->data_format);
1886 DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-15s %X\n", "ansi_version", SCSIInquiry->ansi_version);
1887 DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-15s %X\n", "ecma_version", SCSIInquiry->ecma_version);
1888 DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-15s %X\n", "iso_version", SCSIInquiry->iso_version);
1889 DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-15s %X\n", "type_modifier", SCSIInquiry->type_modifier);
1890 DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-15s %x\n", "removable", SCSIInquiry->removable);
1891 DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-15s %.8s\n", "vendor_info", SCSIInquiry->vendor_info);
1892 DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-15s %.16s\n", "prod_ident", SCSIInquiry->prod_ident);
1893 DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-15s %.4s\n", "prod_version", SCSIInquiry->prod_version);
1894 DebugPrint(DEBUG_INFO, SECTION_SCSI,"%-15s %.19s\n", "vendor_specific", SCSIInquiry->vendor_specific);
1901 dbprintf(("##### START DoNothing\n"));
1907 dbprintf(("##### START GenericFree\n"));
1913 dbprintf(("##### START GenericSearch\n"));
1917 int TreeFrogBarCode(int DeviceFD)
1919 extern OpenFiles_T *pDev;
1921 ModePageTreeFrogVendorUnique_T *pVendor;
1923 dbprintf(("##### START TreeFrogBarCode\n"));
1924 if (pModePage == NULL)
1926 if ((pModePage = malloc(0xff)) == NULL)
1928 dbprintf(("TreeFrogBarCode : malloc failed\n"));
1933 if (SCSI_ModeSense(DeviceFD, pModePage, 0xff, 0x0, 0x3f) == 0)
1935 DecodeModeSense(pModePage, 0, "TreeFrogBarCode :", 0, debug_file);
1937 if (pVendorUnique == NULL)
1939 dbprintf(("TreeFrogBarCode : no pVendorUnique\n"));
1942 pVendor = ( ModePageTreeFrogVendorUnique_T *)pVendorUnique;
1944 dbprintf(("TreeFrogBarCode : EBARCO %d\n", pVendor->EBARCO));
1945 dbprintf(("TreeFrogCheckSum : CHKSUM %d\n", pVendor->CHKSUM));
1947 dump_hex((char *)pDev[INDEX_CHANGER].inquiry, INQUIRY_SIZE, DEBUG_INFO, SECTION_ELEMENT);
1948 return(pVendor->EBARCO);
1953 int EXB_BarCode(int DeviceFD)
1955 extern OpenFiles_T *pDev;
1957 ModePageEXB120VendorUnique_T *pVendor;
1958 ModePageEXB120VendorUnique_T *pVendorWork = NULL;
1960 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"##### START EXB_BarCode\n");
1961 if (pModePage == NULL && LibModeSenseValid == 0)
1963 if ((pModePage = malloc(0xff)) == NULL)
1965 DebugPrint(DEBUG_ERROR, SECTION_BARCODE,"EXB_BarCode : malloc failed\n");
1968 if (SCSI_ModeSense(DeviceFD, pModePage, 0xff, 0x8, 0x3f) == 0)
1970 DecodeModeSense(pModePage, 0, "EXB_BarCode :", 0, debug_file);
1971 LibModeSenseValid = 1;
1973 LibModeSenseValid = -1;
1977 if (LibModeSenseValid == 1)
1979 if (pVendorUnique == NULL)
1981 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"EXB_BarCode : no pVendorUnique\n");
1984 pVendor = ( ModePageEXB120VendorUnique_T *)pVendorUnique;
1986 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"EXB_BarCode : NBL %d\n", pVendor->NBL);
1987 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"EXB_BarCode : PS %d\n", pVendor->PS);
1988 if (pVendor->NBL == 1 && pVendor->PS == 1 )
1990 if ((pVendorWork = ( ModePageEXB120VendorUnique_T *)malloc(pVendor->ParameterListLength + 2)) == NULL)
1992 DebugPrint(DEBUG_ERROR, SECTION_BARCODE,"EXB_BarCode : malloc failed\n");
1995 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"EXB_BarCode : setting NBL to 1\n");
1996 memcpy(pVendorWork, pVendor, pVendor->ParameterListLength + 2);
1997 pVendorWork->NBL = 0;
1998 pVendorWork->PS = 0;
1999 pVendorWork->RSVD0 = 0;
2000 if (SCSI_ModeSelect(DeviceFD, (char *)pVendorWork, pVendorWork->ParameterListLength + 2, 0, 1, 0) == 0)
2002 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"EXB_BarCode : SCSI_ModeSelect OK\n");
2007 /* And now again !!!
2009 GenericResetStatus(DeviceFD);
2011 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"EXB_BarCode : SCSI_ModeSelect failed\n");
2013 amfree(pVendorWork);
2015 dump_hex((char *)pDev[INDEX_CHANGER].inquiry, INQUIRY_SIZE, DEBUG_INFO, SECTION_BARCODE);
2016 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"EXB_BarCode : vendor_specific[19] %x\n",
2017 pDev[INDEX_CHANGER].inquiry->vendor_specific[19]);
2023 int NoBarCode(int DeviceFD)
2025 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"##### START NoBarCode\n");
2026 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"##### STOP NoBarCode\n");
2030 int GenericBarCode(int DeviceFD)
2032 extern changer_t chg;
2034 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"##### START GenericBarCode\n");
2035 if ( chg.havebarcode >= 1)
2037 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"##### STOP GenericBarCode (havebarcode) => %d\n",chg.havebarcode);
2040 DebugPrint(DEBUG_INFO, SECTION_BARCODE,"##### STOP GenericBarCode => 0\n");
2044 int SenseHandler(int DeviceFD, unsigned char flag, unsigned char SenseKey, unsigned char AdditionalSenseCode, unsigned char AdditionalSenseCodeQualifier, char *buffer)
2046 extern OpenFiles_T *pDev;
2048 dbprintf(("##### START SenseHandler\n"));
2049 if (pDev[DeviceFD].inqdone == 1)
2051 dbprintf(("Ident = [%s], function = [%s]\n", pDev[DeviceFD].ident,
2052 pDev[DeviceFD].functions->ident));
2053 ret = pDev[DeviceFD].functions->function_error(DeviceFD, flag, SenseKey, AdditionalSenseCode, AdditionalSenseCodeQualifier, buffer);
2055 dbprintf((" Ups no sense\n"));
2057 dbprintf(("#### STOP SenseHandler\n"));
2062 * Try to get information about the tape,
2063 * Tape loaded ? Online etc
2064 * Use the mtio ioctl to get the information if no SCSI Path
2065 * to the tape drive is available.
2068 * Pass an parameter to identify which unit to use
2069 * if there are more than one
2070 * Implement the SCSI path if available
2074 extern OpenFiles_T *pDev;
2078 RequestSense_T *pRequestSense = NULL;
2080 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### START TapeStatus\n");
2083 * If it is an device which understand SCSI commands the
2084 * normal ioctl (MTIOCGET for example) may fail
2087 if (pDev[INDEX_TAPECTL].SCSI == 1)
2089 if ((pRequestSense = malloc(sizeof(RequestSense_T))) == NULL)
2091 dbprintf(("%-20s : malloc failed\n","TapeStatus"));
2095 while (true && cnt < 60)
2097 ret = SCSI_TestUnitReady(INDEX_TAPECTL, pRequestSense);
2098 DebugPrint(DEBUG_INFO, SECTION_SCSI, "TapeStatus TestUnitReady ret %d\n",ret);
2103 switch (SenseHandler(INDEX_TAPECTL, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, (char *)pRequestSense))
2107 DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeStatus (TestUnitReady) SENSE_NO\n");
2108 pDTE[0].status = 'F';
2109 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### FULL\n");
2112 case SENSE_TAPE_NOT_ONLINE:
2113 DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeStatus (TestUnitReady) SENSE_TAPE_NOT_ONLINE\n");
2114 pDTE[0].status = 'E';
2115 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### EMPTY\n");
2119 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"TapeStatus (TestUnitReady) SENSE_ABORT\n");
2123 DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeStatus (TestUnitReady) SENSE_RETRY\n");
2126 DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeStatus (TestUnitReady) default (SENSE)\n");
2131 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"TapeStatus (TestUnitReady) SCSI_ERROR\n");
2135 DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeStatus (TestUnitReady) SCSI_BUSY\n");
2138 DebugPrint(DEBUG_INFO, SECTION_SCSI,"TapeStatus (TestUnitReady) SCSI_CHECK\n");
2141 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"TapeStatus (TestUnitReady) unknown (%d)\n",ret);
2147 amfree(pRequestSense);
2149 ret = Tape_Status(INDEX_TAPE);
2150 if ( ret & TAPE_ONLINE)
2152 pDTE[0].status ='F';
2153 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### FULL\n");
2155 pDTE[0].status = 'E';
2156 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### EMPTY\n");
2158 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### STOP TapeStatus\n");
2163 int DLT4000Eject(char *Device, int type)
2165 extern OpenFiles_T *pDev;
2167 RequestSense_T *pRequestSense;
2168 ExtendedRequestSense_T *pExtendedRequestSense;
2173 dbprintf(("##### START DLT4000Eject\n"));
2175 if ((pRequestSense = malloc(sizeof(RequestSense_T))) == NULL)
2177 dbprintf(("%-20s : malloc failed\n","DLT4000Eject"));
2181 if ((pExtendedRequestSense = malloc(sizeof(ExtendedRequestSense_T))) == NULL)
2183 dbprintf(("%-20s : malloc failed\n","DLT4000Eject"));
2184 free(pRequestSense);
2190 dbprintf(("DLT4000Eject : use mtio ioctl for eject on %s\n", pDev[INDEX_TAPE].dev));
2191 free(pExtendedRequestSense);
2192 free(pRequestSense);
2193 return(Tape_Ioctl(INDEX_TAPE, IOCTL_EJECT));
2198 if (pDev[INDEX_TAPECTL].SCSI == 0)
2200 dbprintf(("DLT4000Eject : Device %s not able to receive SCSI commands\n", pDev[INDEX_TAPE].dev));
2201 free(pExtendedRequestSense);
2202 free(pRequestSense);
2203 return(Tape_Ioctl(INDEX_TAPE, IOCTL_EJECT));
2207 dbprintf(("DLT4000Eject : SCSI eject on %s = %s\n", pDev[INDEX_TAPECTL].dev, pDev[INDEX_TAPECTL].ConfigName));
2209 RequestSense(INDEX_TAPECTL, pExtendedRequestSense, 0);
2210 DecodeExtSense(pExtendedRequestSense, "DLT4000Eject : ", debug_file);
2211 /* Unload the tape, 0 == wait for success
2214 ret = SCSI_LoadUnload(INDEX_TAPECTL, pRequestSense, 0, 0);
2216 RequestSense(INDEX_TAPECTL, pExtendedRequestSense, 0);
2217 DecodeExtSense(pExtendedRequestSense, "DLT4000Eject : ", debug_file);
2221 free(pExtendedRequestSense);
2222 free(pRequestSense);
2227 while (true && cnt < 300)
2229 ret = SCSI_TestUnitReady(INDEX_TAPECTL, pRequestSense);
2230 DebugPrint(DEBUG_INFO, SECTION_SCSI, "DLT4000Eject TestUnitReady ret %d\n",ret);
2237 switch (SenseHandler(INDEX_TAPECTL, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, (char *)pRequestSense))
2240 DebugPrint(DEBUG_INFO, SECTION_SCSI,"DLT4000Eject (TestUnitReady) SENSE_NO\n");
2243 case SENSE_TAPE_NOT_ONLINE:
2244 DebugPrint(DEBUG_INFO, SECTION_SCSI,"DLT4000Eject (TestUnitReady) SENSE_TAPE_NOT_ONLINE\n");
2248 DebugPrint(DEBUG_INFO, SECTION_SCSI,"DLT4000Eject (TestUnitReady) SENSE_IGNORE\n");
2252 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"DLT4000Eject (TestUnitReady) SENSE_ABORT\n");
2253 free(pExtendedRequestSense);
2254 free(pRequestSense);
2257 DebugPrint(DEBUG_INFO, SECTION_SCSI,"DLT4000Eject (TestUnitReady) SENSE_RETRY\n");
2260 DebugPrint(DEBUG_INFO, SECTION_SCSI,"DLT4000Eject (TestUnitReady) default (SENSE)\n");
2266 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"DLT4000Eject (TestUnitReady) SCSI_ERROR\n");
2267 free(pExtendedRequestSense);
2268 free(pRequestSense);
2271 DebugPrint(DEBUG_INFO, SECTION_SCSI,"DLT4000Eject (TestUnitReady) SCSI_BUSY\n");
2274 DebugPrint(DEBUG_INFO, SECTION_SCSI,"DLT4000Eject (TestUnitReady) SCSI_CHECK\n");
2277 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"DLT4000Eject (TestUnitReady) unknown (%d)\n",ret);
2285 dbprintf(("DLT4000Eject : Ready after %d sec, true = %d\n", cnt * 2, true));
2287 free(pExtendedRequestSense);
2288 free(pRequestSense);
2294 * Ejects an tape either with the ioctl interface
2295 * or by using the SCSI interface if available.
2298 * Before unload check if there is an tape in the drive
2301 int GenericEject(char *Device, int type)
2303 extern OpenFiles_T *pDev;
2304 RequestSense_T *pRequestSense;
2309 DebugPrint(DEBUG_INFO, SECTION_TAPE, "##### START GenericEject\n");
2311 if ((pRequestSense = malloc(sizeof(RequestSense_T))) == NULL)
2313 DebugPrint(DEBUG_ERROR, SECTION_TAPE, "%-20s : malloc failed\n","GenericEject");
2317 DebugPrint(DEBUG_INFO, SECTION_TAPE,"GenericEject : SCSI eject on %s = %s\n",
2318 pDev[INDEX_TAPECTL].dev, pDev[INDEX_TAPECTL].ConfigName);
2321 * Can we use SCSI commands ?
2323 if (pDev[INDEX_TAPECTL].SCSI == 1)
2325 LogSense(INDEX_TAPECTL);
2327 * Unload the tape, 1 == don't wait for success
2330 ret = SCSI_LoadUnload(INDEX_TAPECTL, pRequestSense, 1, 0);
2334 free(pRequestSense);
2339 while (true && cnt < 300)
2341 ret = SCSI_TestUnitReady(INDEX_TAPECTL, pRequestSense);
2342 DebugPrint(DEBUG_INFO, SECTION_SCSI, "GenericEject TestUnitReady ret %d\n",ret);
2347 switch (SenseHandler(INDEX_TAPECTL, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, (char *)pRequestSense))
2350 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericEject (TestUnitReady) SENSE_NO\n");
2352 case SENSE_TAPE_NOT_ONLINE:
2353 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericEject (TestUnitReady) SENSE_TAPE_NOT_ONLINE\n");
2357 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericEject (TestUnitReady) SENSE_IGNORE\n");
2360 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"GenericEject (TestUnitReady) SENSE_ABORT\n");
2361 free(pRequestSense);
2364 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericEject (TestUnitReady) SENSE_RETRY\n");
2367 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericEject (TestUnitReady) default (SENSE)\n");
2372 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"GenericEject (TestUnitReady) SCSI_ERROR\n");
2373 free(pRequestSense);
2376 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericEject (TestUnitReady) SCSI_BUSY\n");
2379 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericEject (TestUnitReady) SCSI_CHECK\n");
2382 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"GenericEject (TestUnitReady) unknown (%d)\n",ret);
2389 DebugPrint(DEBUG_INFO, SECTION_TAPE,"GenericEject : Device can't understand SCSI try ioctl\n");
2390 Tape_Ioctl(INDEX_TAPECTL, IOCTL_EJECT);
2392 DebugPrint(DEBUG_INFO, SECTION_TAPE,"GenericEject : Ready after %d sec, true = %d\n", cnt * 2, true);
2393 free(pRequestSense);
2401 * Make the retry counter an config option,
2407 int GenericRewind(int DeviceFD)
2410 extern OpenFiles_T *pDev;
2411 RequestSense_T *pRequestSense = NULL;
2412 char *errstr; /* Used by tape_rewind */
2417 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### START GenericRewind pDEV -> %d\n",DeviceFD);
2421 * If we can use the SCSI device than use it, else use the ioctl
2424 if (pDev[DeviceFD].SCSI == 1)
2426 if ((pRequestSense = (RequestSense_T *)malloc(sizeof(RequestSense_T))) == NULL)
2428 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"GenericRewind : malloc failed\n");
2432 * Before doing the rewind check if the tape is ready to accept commands
2437 ret = SCSI_TestUnitReady(DeviceFD, (RequestSense_T *)pRequestSense );
2438 DebugPrint(DEBUG_INFO, SECTION_TAPE, "GenericRewind (TestUnitReady) ret %d\n",ret);
2445 switch (SenseHandler(DeviceFD, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, (char *)pRequestSense))
2448 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) SENSE_NO\n");
2451 case SENSE_TAPE_NOT_ONLINE:
2452 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) SENSE_TAPE_NOT_ONLINE\n");
2453 free(pRequestSense);
2457 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) SENSE_IGNORE\n");
2461 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"GenericRewind (TestUnitReady) SENSE_ABORT\n");
2462 free(pRequestSense);
2466 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) SENSE_RETRY\n");
2469 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) default (SENSE)\n");
2472 } /* switch (SenseHandler(DeviceFD, 0, pRequestSense->SenseKey.... */
2476 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"GenericRewind (TestUnitReady) SCSI_ERROR\n");
2477 free(pRequestSense);
2481 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) SCSI_BUSY\n");
2484 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) SCSI_CHECK\n");
2487 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"GenericRewind (TestUnitReady) unknown (%d)\n",ret);
2492 DebugPrint(DEBUG_INFO, SECTION_TAPE," Wait .... (%d)\n",cnt);
2495 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"##### STOP GenericRewind (-1)\n");
2496 free(pRequestSense);
2499 } /* while true == 1 */
2504 CDB[0] = SC_COM_REWIND;
2513 ret = SCSI_Run(DeviceFD, Input, CDB, 6,
2515 (char *) pRequestSense,
2516 sizeof(RequestSense_T));
2518 DecodeSense(pRequestSense, "GenericRewind : ", debug_file);
2522 if (pRequestSense->SenseKey != UNIT_ATTENTION)
2533 DebugPrint(DEBUG_INFO, SECTION_TAPE,"GenericRewind : failed %d\n", ret);
2540 while (true && cnt < 300)
2542 ret = SCSI_TestUnitReady(DeviceFD, pRequestSense);
2543 DebugPrint(DEBUG_INFO, SECTION_SCSI, "GenericRewind TestUnitReady ret %d\n",ret);
2550 switch (SenseHandler(DeviceFD, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, (char *)pRequestSense))
2553 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) SENSE_NO\n");
2556 case SENSE_TAPE_NOT_ONLINE:
2557 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) SENSE_TAPE_NOT_ONLINE\n");
2558 free(pRequestSense);
2562 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) SENSE_IGNORE\n");
2566 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"GenericRewind (TestUnitReady) SENSE_ABORT\n");
2567 free(pRequestSense);
2571 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) SENSE_RETRY\n");
2574 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) default (SENSE)\n");
2580 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"GenericRewind (TestUnitReady) SCSI_ERROR\n");
2581 free(pRequestSense);
2585 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) SCSI_BUSY\n");
2588 DebugPrint(DEBUG_INFO, SECTION_SCSI,"GenericRewind (TestUnitReady) SCSI_CHECK\n");
2591 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"GenericRewind (TestUnitReady) unknown (%d)\n",ret);
2599 amfree(pRequestSense);
2601 DebugPrint(DEBUG_INFO, SECTION_TAPE,"GenericRewind : Ready after %d sec, true = %d\n", cnt * 2, true);
2602 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### STOP GenericRewind (0)\n");
2604 DebugPrint(DEBUG_INFO, SECTION_TAPE,"GenericRewind : use ioctl rewind\n");
2605 if (pDev[DeviceFD].devopen == 1)
2607 DebugPrint(DEBUG_INFO, SECTION_TAPE,"Close Device\n");
2608 SCSI_CloseDevice(DeviceFD);
2610 /* We don't retry if it fails; that is left to the vtape driver. */
2611 if ((errstr = tape_rewind(pDev[DeviceFD].dev)) == NULL) {
2613 DebugPrint(DEBUG_INFO, SECTION_TAPE,"Rewind OK,\n", cnt);
2615 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"Rewind failed %s\n",errstr);
2616 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### STOP GenericRewind (-1)\n");
2617 amfree(pRequestSense);
2620 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### STOP GenericRewind (0)\n");
2623 amfree(pRequestSense);
2629 * Check if the tape has the tape clean
2630 * bit set in the return of an request sense
2633 int GenericClean(char * Device)
2635 extern OpenFiles_T *pDev;
2636 ExtendedRequestSense_T ExtRequestSense;
2639 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### START GenericClean\n");
2640 if (pDev[INDEX_TAPECTL].SCSI == 0)
2642 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"GenericClean : can't send SCSI commands\n");
2643 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"##### STOP GenericClean\n");
2648 * Request Sense Data, reset the counter
2650 if ( RequestSense(INDEX_TAPECTL, &ExtRequestSense, 1) == 0)
2653 DecodeExtSense(&ExtRequestSense, "GenericClean : ", debug_file);
2654 if(ExtRequestSense.CLN) {
2660 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"Got error from RequestSense\n");
2662 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### STOP GenericClean (%d)\n",ret);
2666 int GenericResetStatus(int DeviceFD)
2669 RequestSense_T *pRequestSense;
2673 DebugPrint(DEBUG_INFO, SECTION_ELEMENT, "##### START GenericResetStatus\n");
2675 if ((pRequestSense = (RequestSense_T *)malloc(sizeof(RequestSense_T))) == NULL)
2677 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "GenericResetStatus : malloc failed\n");
2683 CDB[0] = SC_COM_IES; /* */
2691 ret = SCSI_Run(DeviceFD, Input, CDB, 6,
2693 (char *) pRequestSense,
2694 sizeof(RequestSense_T));
2698 /* fprintf(stderr, "%s: Request Sense[Inquiry]: %02X", */
2699 /* "chs", ((unsigned char *) &pRequestSense)[0]); */
2700 /* for (i = 1; i < sizeof(RequestSense_T); i++) */
2701 /* fprintf(stderr, " %02X", ((unsigned char *) &pRequestSense)[i]); */
2702 /* fprintf(stderr, "\n"); */
2703 free(pRequestSense);
2708 switch (SenseHandler(DeviceFD, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, (char *)pRequestSense))
2711 free(pRequestSense);
2715 free(pRequestSense);
2720 if (retry < MAX_RETRIES )
2722 DebugPrint(DEBUG_INFO, SECTION_ELEMENT, "GenericResetStatus : retry %d\n", retry);
2725 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "GenericResetStatus : return (-1)\n");
2726 free(pRequestSense);
2731 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "GenericResetStatus : (default) return (-1)\n");
2732 free(pRequestSense);
2740 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "##### STOP GenericResetStatus (%d)\n",ret);
2741 free(pRequestSense);
2745 /* GenericSenseHandler
2746 * Handles the conditions/sense wich is returned by an SCSI command
2747 * pwork is an pointer to the structure OpenFiles_T, which is filled with information
2748 * about the device to which we talk. Information are for example
2749 * The vendor, the ident, which fd, etc. This strucure is filled when we open the
2751 * flag tells how to handle the information passed in the buffer,
2752 * 0 -> Sense Key available
2753 * 1 -> No Sense key available
2754 * buffer is a pointer to the data from the request sense result.
2757 * Limit recursion, may run in an infinite loop
2759 int GenericSenseHandler(int ip, int flag, unsigned char SenseKey, unsigned char AdditionalSenseCode, unsigned char AdditionalSenseCodeQualifier, char *buffer)
2761 extern OpenFiles_T *pDev;
2762 RequestSense_T *pRequestSense = (RequestSense_T *)buffer;
2764 unsigned char *info = NULL;
2766 dbprintf(("##### START GenericSenseHandler\n"));
2768 DecodeSense(pRequestSense, "GenericSenseHandler : ", debug_file);
2770 ret = Sense2Action(pDev[ip].ident,
2771 pDev[ip].inquiry->type,
2773 AdditionalSenseCode,
2774 AdditionalSenseCodeQualifier,
2777 dbprintf(("##### STOP GenericSenseHandler\n"));
2782 * Do the move. We don't address the MTE element (the gripper)
2783 * here. We assume that the library use the right MTE.
2784 * The difference to GenericMove is that we do an align element
2789 * != 0 -> error either from the SCSI command or from
2790 * the element handling
2793 int SDXMove(int DeviceFD, int from, int to)
2795 extern OpenFiles_T *pDev;
2796 ElementInfo_T *pfrom;
2801 int SDX_MTE = 0; /* This are parameters passed */
2802 int SDX_STE = -1; /* to */
2803 int SDX_DTE = -1; /* AlignElements */
2805 DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### START SDXMove\n");
2807 DebugPrint(DEBUG_INFO, SECTION_MOVE,"%-20s : from = %d, to = %d\n", "SDXMove", from, to);
2810 if ((pfrom = LookupElement(from)) == NULL)
2812 DebugPrint(DEBUG_INFO, SECTION_MOVE,"SDXMove : ElementInfo for %d not found\n", from);
2813 DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP SDXMove\n");
2817 if ((pto = LookupElement(to)) == NULL)
2819 DebugPrint(DEBUG_INFO, SECTION_MOVE,"SDXMove : ElementInfo for %d not found\n", to);
2820 DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP SDXMove\n");
2824 if (pfrom->status == 'E')
2826 DebugPrint(DEBUG_INFO, SECTION_MOVE,"SDXMove : from %d is empty\n", from);
2827 DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP SDXMove\n");
2831 if (pto->status == 'F')
2833 switch (pto->status)
2838 DebugPrint(DEBUG_INFO, SECTION_MOVE,"SDXMove : Destination Element %d Type %d is full\n",
2839 pto->address, pto->type);
2840 to = find_empty(DeviceFD, 0, 0);
2843 DebugPrint(DEBUG_ERROR, SECTION_MOVE,"SDXMove : no empty slot found for unload\n");
2846 DebugPrint(DEBUG_INFO, SECTION_MOVE,"SDXMove : Unload to %d\n", to);
2847 if ((pto = LookupElement(to)) == NULL)
2849 DebugPrint(DEBUG_INFO, SECTION_MOVE, "SDXMove : ElementInfo for %d not found\n", to);
2850 DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP SDXMove\n");
2861 moveok = CheckMove(pfrom, pto);
2866 SDX_DTE = pto->address;
2869 SDX_STE = pto->address;
2872 SDX_STE = pto->address;
2876 switch (pfrom->type)
2879 SDX_DTE = pfrom->address;
2882 SDX_STE = pfrom->address;
2885 SDX_STE = pfrom->address;
2889 if (SDX_DTE >= 0 && SDX_STE >= 0)
2891 ret = SCSI_AlignElements(DeviceFD, SDX_MTE, SDX_DTE, SDX_STE);
2892 DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### SCSI_AlignElemnts ret = %d\n",ret);
2895 DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP SDXMove\n");
2899 DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### Error setting STE/DTE %d/%d\n", SDX_STE, SDX_DTE);
2900 DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP SDXMove\n");
2905 * If from is a tape we must check if it is loaded
2906 * and if yes we have to eject it
2908 if (pfrom->type == TAPETYPE)
2910 tapestat = Tape_Status(INDEX_TAPE);
2911 if ( tapestat & TAPE_ONLINE)
2913 if (pDev[INDEX_TAPECTL].SCSI == 1)
2915 ret = eject_tape(pDev[INDEX_TAPECTL].dev,1);
2917 ret = eject_tape(pDev[INDEX_TAPE].dev,2);
2924 ret = SCSI_Move(DeviceFD, 0, from, to);
2926 DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP SDXMove\n");
2929 DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP SDXMove\n");
2934 * Do the move. We don't address the MTE element (the gripper)
2935 * here. We assume that the library use the right MTE
2939 * != 0 -> error either from the SCSI command or from
2940 * the element handling
2943 int GenericMove(int DeviceFD, int from, int to)
2945 ElementInfo_T *pfrom;
2949 DebugPrint(DEBUG_INFO, SECTION_MOVE, "##### START GenericMove\n");
2951 DebugPrint(DEBUG_INFO, SECTION_MOVE, "%-20s : from = %d, to = %d\n", "GenericMove", from, to);
2954 if ((pfrom = LookupElement(from)) == NULL)
2956 DebugPrint(DEBUG_INFO, SECTION_MOVE, "GenericMove : ElementInfo for %d not found\n", from);
2957 DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP GenericMove\n");
2961 if ((pto = LookupElement(to)) == NULL)
2963 DebugPrint(DEBUG_INFO, SECTION_MOVE, "GenericMove : ElementInfo for %d not found\n", to);
2964 DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP GenericMove\n");
2968 if (pfrom->status == 'E')
2970 DebugPrint(DEBUG_INFO, SECTION_MOVE, "GenericMove : from %d is empty\n", from);
2971 DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP GenericMove\n");
2975 if (pto->status == 'F')
2977 DebugPrint(DEBUG_INFO, SECTION_MOVE, "GenericMove : Destination Element %d Type %d is full\n",
2978 pto->address, pto->type);
2979 to = find_empty(DeviceFD, 0, 0);
2982 DebugPrint(DEBUG_ERROR, SECTION_MOVE, "GenericMove : no empty slot found\n");
2985 DebugPrint(DEBUG_INFO, SECTION_MOVE, "GenericMove : Unload to %d\n", to);
2986 if ((pto = LookupElement(to)) == NULL)
2988 DebugPrint(DEBUG_ERROR, SECTION_MOVE, " Ups should not happen\n");
2989 DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP GenericMove\n");
2994 if (CheckMove(pfrom, pto))
2996 ret = SCSI_Move(DeviceFD, 0, from, to);
2999 DebugPrint(DEBUG_INFO, SECTION_MOVE, "GenericMove : SCSI_Move return (%d)\n", ret);
3000 DebugPrint(DEBUG_INFO, SECTION_MOVE,"##### STOP GenericMove\n");
3005 * Check if a move based on the information we got from the Mode Sense command
3012 int CheckMove(ElementInfo_T *from, ElementInfo_T *to)
3016 DebugPrint(DEBUG_INFO, SECTION_MOVE, "##### START CheckMove\n");
3017 if (pDeviceCapabilitiesPage != NULL )
3019 DebugPrint(DEBUG_INFO, SECTION_MOVE, "CheckMove : checking if move from %d to %d is legal\n", from->address, to->address);
3023 DebugPrint(DEBUG_INFO, SECTION_MOVE, "CheckMove : MT2");
3027 if (pDeviceCapabilitiesPage->MT2MT == 1)
3029 DebugPrint(DEBUG_INFO, SECTION_MOVE, "MT\n");
3034 if (pDeviceCapabilitiesPage->MT2ST == 1)
3036 DebugPrint(DEBUG_INFO, SECTION_MOVE, "ST\n");
3041 if (pDeviceCapabilitiesPage->MT2IE == 1)
3043 DebugPrint(DEBUG_INFO, SECTION_MOVE, "IE\n");
3048 if (pDeviceCapabilitiesPage->MT2DT == 1)
3050 DebugPrint(DEBUG_INFO, SECTION_MOVE, "DT\n");
3059 DebugPrint(DEBUG_INFO, SECTION_MOVE, "CheckMove : ST2");
3063 if (pDeviceCapabilitiesPage->ST2MT == 1)
3065 DebugPrint(DEBUG_INFO, SECTION_MOVE, "MT\n");
3070 if (pDeviceCapabilitiesPage->ST2ST == 1)
3072 DebugPrint(DEBUG_INFO, SECTION_MOVE, "ST\n");
3077 if (pDeviceCapabilitiesPage->ST2IE == 1)
3079 DebugPrint(DEBUG_INFO, SECTION_MOVE, "IE\n");
3084 if (pDeviceCapabilitiesPage->ST2DT == 1)
3086 DebugPrint(DEBUG_INFO, SECTION_MOVE, "DT\n");
3095 DebugPrint(DEBUG_INFO, SECTION_MOVE, "CheckMove : IE2");
3099 if (pDeviceCapabilitiesPage->IE2MT == 1)
3101 DebugPrint(DEBUG_INFO, SECTION_MOVE, "MT\n");
3106 if (pDeviceCapabilitiesPage->IE2ST == 1)
3108 DebugPrint(DEBUG_INFO, SECTION_MOVE, "ST\n");
3113 if (pDeviceCapabilitiesPage->IE2IE == 1)
3115 DebugPrint(DEBUG_INFO, SECTION_MOVE, "IE\n");
3120 if (pDeviceCapabilitiesPage->IE2DT == 1)
3122 DebugPrint(DEBUG_INFO, SECTION_MOVE, "DT\n");
3131 DebugPrint(DEBUG_INFO, SECTION_MOVE, "CheckMove : DT2");
3135 if (pDeviceCapabilitiesPage->DT2MT == 1)
3137 DebugPrint(DEBUG_INFO, SECTION_MOVE, "MT\n");
3142 if (pDeviceCapabilitiesPage->DT2ST == 1)
3144 DebugPrint(DEBUG_INFO, SECTION_MOVE, "ST\n");
3149 if (pDeviceCapabilitiesPage->DT2IE == 1)
3151 DebugPrint(DEBUG_INFO, SECTION_MOVE, "IE\n");
3156 if (pDeviceCapabilitiesPage->DT2DT == 1)
3158 DebugPrint(DEBUG_INFO, SECTION_MOVE, "DT\n");
3170 DebugPrint(DEBUG_INFO, SECTION_MOVE, "CheckMove : pDeviceCapabilitiesPage == NULL");
3172 ChgExit("CheckMove", "DeviceCapabilitiesPage == NULL", FATAL);
3177 DebugPrint(DEBUG_INFO, SECTION_MOVE, "###### STOP CheckMove\n");
3184 int GetCurrentSlot(int fd, int drive)
3186 extern OpenFiles_T *pDev;
3188 dbprintf(("##### START GetCurrentSlot\n"));
3190 if (pDev[0].SCSI == 0)
3192 dbprintf(("GetCurrentSlot : can't send SCSI commands\n"));
3196 if (ElementStatusValid == 0)
3198 if (pDev[0].functions->function_status(0, 1) != 0)
3204 /* If the from address is the as the same as the tape address skip it */
3205 if (pDTE[drive].from >= 0 && pDTE[drive].from != pDTE[drive].address)
3207 for (x = 0; x < STE;x++)
3209 if (pSTE[x].address == pDTE[drive].from)
3215 for (x = 0; x < STE;x++)
3217 if (pSTE[x].status == 'E')
3221 /* Ups nothing loaded */
3228 * Reworked function to get the ElementStatus
3229 * This function will first call the GetElementStatus
3230 * function to get the Element status,
3231 * and than check if there are abnormal conditions.
3233 * If there are error conditions try to fix them
3236 int GenericElementStatus(int DeviceFD, int InitStatus)
3244 extern OpenFiles_T *pDev;
3246 int error = 0; /* If set do an INIT ELEMENT STATUS */
3247 int x; /* The standard loop counter :-) */
3248 int loop = 2; /* Redo it if an error has been reset */
3250 DebugPrint(DEBUG_INFO, SECTION_ELEMENT, "##### START GenericElementStatus\n");
3252 if (pEAAPage == NULL)
3255 * If this pointer is null
3256 * then try to read the parameter with MODE SENSE
3259 if (pModePage == NULL && LibModeSenseValid == 0)
3261 if ((pModePage = malloc(0xff)) == NULL)
3263 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"GenericElementStatus : malloc failed\n");
3266 if (SCSI_ModeSense(DeviceFD, pModePage, 0xff, 0x8, 0x3f) == 0)
3268 LibModeSenseValid = 1;
3269 DecodeModeSense(pModePage, 0, "GenericElementStatus :", 0, debug_file);
3271 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"GetElementStatus : failed SCSI_ModeSense\n");
3272 LibModeSenseValid = -1;
3277 if (GetElementStatus(DeviceFD) == 0 && loop > 0)
3280 for (x = 0; x < MTE; x++)
3282 if (pMTE[x].ASC > 0)
3284 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pMTE[x].ASC, pMTE[x].ASCQ, (char *)&pMTE[x]))
3291 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "GenericElementStatus : Abort on MTE\n");
3298 for (x = 0; x < IEE; x++)
3300 if (pIEE[x].ASC > 0)
3302 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pIEE[x].ASC, pIEE[x].ASCQ, (char *)&pIEE[x]))
3309 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "GenericElementStatus : Abort on IEE\n");
3317 for (x = 0; x < STE; x++)
3320 * Needed for the hack to guess the tape status if an error
3321 * for the tape is pending
3323 if (pSTE[x].status == 'E')
3328 if (pSTE[x].ASC > 0)
3330 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pSTE[x].ASC, pSTE[x].ASCQ, (char *)&pSTE[x]))
3337 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "GenericElementStatus : Abort on IES\n");
3344 for (x = 0; x < DTE; x++)
3346 if (pDTE[x].ASC > 0)
3348 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pDTE[x].ASC, pDTE[x].ASCQ, (char *)&pDTE[x]))
3355 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "GenericElementStatus : Abort on DTE\n");
3363 * OK, we have an error, do an INIT ELMENT
3364 * For the tape if not handled by the robot we have
3365 * to do some extra checks
3369 if (GenericResetStatus(DeviceFD) != 0)
3371 ElementStatusValid = 0;
3372 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "GenericElementStatus : Can't init status STEError(%d) MTEError(%d) DTEError(%d) IEEError(%d)\n", STEError, MTEError, DTEError, IEEError);
3382 * If the status is empty to an move from tape to tape
3383 * This is if the tape is ejected, but not unloaded
3385 if (pDTE[0].status == 'E')
3387 DebugPrint(DEBUG_INFO, SECTION_ELEMENT, "GenericElementStatus : try to move tape to tape drive\n");
3388 pDev[DeviceFD].functions->function_move(DeviceFD, pDTE[0].address, pDTE[0].address);
3391 /* Done GetElementStatus */
3396 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "GenericElementStatus : Can't init status (after loop)\n");
3400 ElementStatusValid = 1;
3401 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "#### STOP GenericElementStatus\n");
3407 * This is for the ADIC changer, it seems that they have an diferent
3408 * offset in the mode sense data before the first mode page (+12)
3410 int DLT448ElementStatus(int DeviceFD, int InitStatus)
3418 extern OpenFiles_T *pDev;
3420 int error = 0; /* If set do an INIT ELEMENT STATUS */
3421 int x; /* The standard loop counter :-) */
3422 int loop = 2; /* Redo it if an error has been reset */
3424 DebugPrint(DEBUG_INFO, SECTION_ELEMENT, "##### START DLT448ElementStatus\n");
3426 if (pEAAPage == NULL)
3429 * If this pointer is null
3430 * then try to read the parameter with MODE SENSE
3433 if (pModePage == NULL && LibModeSenseValid == 0)
3435 if ((pModePage = malloc(0xff)) == NULL)
3437 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"DLT448ElementStatus : malloc failed\n");
3440 if (SCSI_ModeSense(DeviceFD, pModePage, 0xff, 0x8, 0x3f) == 0)
3442 LibModeSenseValid = 1;
3443 DecodeModeSense(pModePage, 12, "DLT448ElementStatus :", 0, debug_file);
3445 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"DLT448ElementStatus : failed SCSI_ModeSense\n");
3446 LibModeSenseValid = -1;
3451 if (GetElementStatus(DeviceFD) == 0 && loop > 0)
3454 for (x = 0; x < MTE; x++)
3456 if (pMTE[x].ASC > 0)
3458 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pMTE[x].ASC, pMTE[x].ASCQ, (char *)&pMTE[x]))
3465 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "DLT448ElementStatus : Abort on MTE\n");
3472 for (x = 0; x < IEE; x++)
3474 if (pIEE[x].ASC > 0)
3476 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pIEE[x].ASC, pIEE[x].ASCQ, (char *)&pIEE[x]))
3483 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "DLT448ElementStatus : Abort on IEE\n");
3491 for (x = 0; x < STE; x++)
3494 * Needed for the hack to guess the tape status if an error
3495 * for the tape is pending
3497 if (pSTE[x].status == 'E')
3502 if (pSTE[x].ASC > 0)
3504 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pSTE[x].ASC, pSTE[x].ASCQ, (char *)&pSTE[x]))
3511 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "DLT448ElementStatus : Abort on IES\n");
3518 for (x = 0; x < DTE; x++)
3520 if (pDTE[x].ASC > 0)
3522 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pDTE[x].ASC, pDTE[x].ASCQ, (char *)&pDTE[x]))
3529 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "DLT448ElementStatus : Abort on DTE\n");
3537 * OK, we have an error, do an INIT ELMENT
3538 * For the tape if not handled by the robot we have
3539 * to do some extra checks
3543 if (GenericResetStatus(DeviceFD) != 0)
3545 ElementStatusValid = 0;
3546 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "DLT448ElementStatus : Can't init status\n");
3556 * If the status is empty to an move from tape to tape
3557 * This is if the tape is ejected, but not unloaded
3559 if (pDTE[0].status == 'E')
3561 DebugPrint(DEBUG_INFO, SECTION_ELEMENT, "DLT448ElementStatus : try to move tape to tape drive\n");
3562 pDev[DeviceFD].functions->function_move(DeviceFD, pDTE[0].address, pDTE[0].address);
3565 /* Done GetElementStatus */
3570 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "DLT448ElementStatus : Can't init status (after loop)\n");
3574 ElementStatusValid = 1;
3575 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "#### STOP DLT448ElementStatus\n");
3581 * Much the same like GenericElementStatus but
3582 * it seemes that for the STE Elements ASC/ASCQ is not set
3583 * on an error, only the except bit is set
3585 int SDXElementStatus(int DeviceFD, int InitStatus)
3592 int error = 0; /* If set do an INIT ELEMENT STATUS */
3593 int x; /* The standard loop counter :-) */
3594 int loop = 2; /* Redo it if an error has been reset */
3596 DebugPrint(DEBUG_INFO, SECTION_ELEMENT, "##### START SDXElementStatus\n");
3598 if (pEAAPage == NULL)
3601 * If this pointer is null
3602 * then try to read the parameter with MODE SENSE
3605 if (pModePage == NULL && LibModeSenseValid == 0)
3607 if ((pModePage = malloc(0xff)) == NULL)
3609 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"SDXElementStatus : malloc failed\n");
3612 if (SCSI_ModeSense(DeviceFD, pModePage, 0xff, 0x8, 0x3f) == 0)
3614 LibModeSenseValid = 1;
3615 DecodeModeSense(pModePage, 0, "SDXElementStatus :", 0, debug_file);
3617 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"SDXElementStatus : failed SCSI_ModeSense\n");
3618 LibModeSenseValid = -1;
3623 if (GetElementStatus(DeviceFD) == 0 && loop)
3627 for (x = 0; x < MTE; x++)
3629 if (pMTE[x].ASC > 0)
3631 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pMTE[x].ASC, pMTE[x].ASCQ, (char *)&pMTE[x]))
3638 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "SDXElementStatus : Abort on MTE\n");
3645 for (x = 0; x < IEE; x++)
3647 if (pIEE[x].ASC > 0)
3649 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pIEE[x].ASC, pIEE[x].ASCQ, (char *)&pIEE[x]))
3656 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "SDXElementStatus : Abort on IEE\n");
3664 for (x = 0; x < STE; x++)
3666 if (pSTE[x].except != 0)
3671 if (pSTE[x].ASC > 0)
3673 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pSTE[x].ASC, pSTE[x].ASCQ, (char *)&pSTE[x]))
3680 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "SDXElementStatus : Abort on IES\n");
3687 for (x = 0; x < DTE; x++)
3689 if (pDTE[x].ASC > 0)
3691 switch(SenseHandler(DeviceFD, 0, SENSE_CHG_ELEMENT_STATUS, pDTE[x].ASC, pDTE[x].ASCQ, (char *)&pDTE[x]))
3700 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "SDXElementStatus : Abort on DTE\n");
3708 * OK, we have an error, do an INIT ELMENT
3709 * For the tape if not handled by the robot we have
3710 * to do some extra checks
3714 if (GenericResetStatus(DeviceFD) != 0)
3716 ElementStatusValid = 0;
3717 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "SDXElementStatus : Can't init status\n");
3722 /* Done GetElementStatus */
3727 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "SDXElementStatus : Can't init status\n");
3731 ElementStatusValid = 1;
3733 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT, "#### STOP SDXElementStatus\n");
3739 * Reads the element information from the library. There are 2 ways to do this.
3740 * Either check the result from the mode sense page to see which types of elements
3741 * are available (STE/DTE/MTE....), or do an read element status with the option give
3742 * me all and than check what is available.
3744 * Only do the read, error handling is done by the calling function
3752 int GetElementStatus(int DeviceFD)
3754 unsigned char *DataBuffer = NULL;
3755 int DataBufferLength;
3756 ElementStatusData_T *ElementStatusData;
3757 ElementStatusPage_T *ElementStatusPage;
3758 MediumTransportElementDescriptor_T *MediumTransportElementDescriptor;
3759 StorageElementDescriptor_T *StorageElementDescriptor;
3760 DataTransferElementDescriptor_T *DataTransferElementDescriptor;
3761 ImportExportElementDescriptor_T *ImportExportElementDescriptor;
3764 int length = 0; /* Length of an Element */
3765 int barcode = 0; /* To store the result of the BarCode function */
3768 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"##### START GetElementStatus\n");
3770 barcode = BarCode(DeviceFD);
3773 * If the MODE_SENSE was successfull we use this Information to read the Elelement Info
3775 if (pEAAPage != NULL)
3777 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Reading Element Status with the info from mode sense\n");
3778 /* First the Medim Transport*/
3779 if (V2(pEAAPage->NoMediumTransportElements) > 0)
3782 MTE = V2(pEAAPage->NoMediumTransportElements) ;
3783 if ((pMTE = (ElementInfo_T *)malloc(sizeof(ElementInfo_T) * MTE)) == NULL)
3785 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"GenericElementStatus : malloc failed\n");
3788 memset(pMTE, 0, sizeof(ElementInfo_T) * MTE);
3790 if (SCSI_ReadElementStatus(DeviceFD,
3794 V2(pEAAPage->MediumTransportElementAddress),
3796 sizeof(MediumTransportElementDescriptor_T),
3797 (char **)&DataBuffer) != 0)
3801 ChgExit("genericElementStatus","Can't read MTE status", FATAL);
3803 ElementStatusData = (ElementStatusData_T *)DataBuffer;
3804 offset = sizeof(ElementStatusData_T);
3806 ElementStatusPage = (ElementStatusPage_T *)&DataBuffer[offset];
3807 offset = offset + sizeof(ElementStatusPage_T);
3808 length = V2(ElementStatusPage->length);
3809 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"MTE Length %d(%d)\n",length,sizeof(MediumTransportElementDescriptor_T));
3811 for (x = 0; x < MTE; x++)
3813 MediumTransportElementDescriptor = (MediumTransportElementDescriptor_T *)&DataBuffer[offset];
3815 if (ElementStatusPage->pvoltag == 1)
3817 strncpy((char *)pMTE[x].VolTag,
3818 (char *)MediumTransportElementDescriptor->pvoltag,
3820 TerminateString(pMTE[x].VolTag, TAG_SIZE+1);
3823 pMTE[x].type = ElementStatusPage->type;
3824 pMTE[x].address = V2(MediumTransportElementDescriptor->address);
3825 pMTE[x].except = MediumTransportElementDescriptor->except;
3826 pMTE[x].status = (MediumTransportElementDescriptor->full > 0) ? 'F':'E';
3827 pMTE[x].full = MediumTransportElementDescriptor->full;
3831 pMTE[x].ASC = MediumTransportElementDescriptor->asc;
3833 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASC MTE\n");
3838 pMTE[x].ASCQ = MediumTransportElementDescriptor->ascq;
3840 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASCQ MTE\n");
3845 if (MediumTransportElementDescriptor->svalid == 1)
3847 pMTE[x].from = V2(MediumTransportElementDescriptor->source);
3852 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip source MTE\n");
3854 offset = offset + length;
3860 if ( V2(pEAAPage->NoStorageElements) > 0)
3863 STE = V2(pEAAPage->NoStorageElements);
3864 if ((pSTE = (ElementInfo_T *)malloc(sizeof(ElementInfo_T) * STE)) == NULL)
3866 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"GenericElementStatus : malloc failed\n");
3870 memset(pSTE, 0, sizeof(ElementInfo_T) * STE);
3872 if (SCSI_ReadElementStatus(DeviceFD,
3876 V2(pEAAPage->FirstStorageElementAddress),
3878 sizeof(StorageElementDescriptor_T),
3879 (char **)&DataBuffer) != 0)
3882 ChgExit("GetElementStatus", "Can't read STE status", FATAL);
3885 ElementStatusData = (ElementStatusData_T *)DataBuffer;
3886 offset = sizeof(ElementStatusData_T);
3888 ElementStatusPage = (ElementStatusPage_T *)&DataBuffer[offset];
3889 offset = offset + sizeof(ElementStatusPage_T);
3890 length = V2(ElementStatusPage->length);
3891 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"STE Length %d\n",length);
3893 for (x = 0; x < STE; x++)
3895 StorageElementDescriptor = (StorageElementDescriptor_T *)&DataBuffer[offset];
3896 if (ElementStatusPage->pvoltag == 1)
3898 strncpy(pSTE[x].VolTag,
3899 (char *)StorageElementDescriptor->pvoltag,
3901 TerminateString(pSTE[x].VolTag, TAG_SIZE+1);
3905 pSTE[x].type = ElementStatusPage->type;
3906 pSTE[x].address = V2(StorageElementDescriptor->address);
3907 pSTE[x].except = StorageElementDescriptor->except;
3908 pSTE[x].status = (StorageElementDescriptor->full > 0) ? 'F':'E';
3909 pSTE[x].full = StorageElementDescriptor->full;
3913 pSTE[x].ASC = StorageElementDescriptor->asc;
3915 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASC STE\n");
3920 pSTE[x].ASCQ = StorageElementDescriptor->ascq;
3922 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASCQ STE\n");
3927 if (StorageElementDescriptor->svalid == 1)
3929 pSTE[x].from = V2(StorageElementDescriptor->source);
3934 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip source STE\n");
3937 offset = offset + length;
3942 * Import/Export Elements
3944 if ( V2(pEAAPage->NoImportExportElements) > 0)
3947 IEE = V2(pEAAPage->NoImportExportElements);
3948 if ((pIEE = (ElementInfo_T *)malloc(sizeof(ElementInfo_T) * IEE)) == NULL)
3950 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"GenericElementStatus : malloc failed\n");
3954 memset(pIEE, 0, sizeof(ElementInfo_T) * IEE);
3956 if (SCSI_ReadElementStatus(DeviceFD,
3960 V2(pEAAPage->FirstImportExportElementAddress),
3962 sizeof(ImportExportElementDescriptor_T),
3963 (char **)&DataBuffer) != 0)
3965 if (DataBuffer != 0)
3969 ChgExit("GetElementStatus", "Can't read IEE status", FATAL);
3972 ElementStatusData = (ElementStatusData_T *)DataBuffer;
3973 offset = sizeof(ElementStatusData_T);
3975 ElementStatusPage = (ElementStatusPage_T *)&DataBuffer[offset];
3976 offset = offset + sizeof(ElementStatusPage_T);
3977 length = V2(ElementStatusPage->length);
3978 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"IEE Length %d\n",length);
3980 for (x = 0; x < IEE; x++)
3982 ImportExportElementDescriptor = (ImportExportElementDescriptor_T *)&DataBuffer[offset];
3983 if (ElementStatusPage->pvoltag == 1)
3985 strncpy(pIEE[x].VolTag,
3986 (char *)ImportExportElementDescriptor->pvoltag,
3988 TerminateString(pIEE[x].VolTag, TAG_SIZE+1);
3990 pIEE[x].type = ElementStatusPage->type;
3991 pIEE[x].address = V2(ImportExportElementDescriptor->address);
3992 pIEE[x].except = ImportExportElementDescriptor->except;
3993 pIEE[x].status = (ImportExportElementDescriptor->full > 0) ? 'F':'E';
3994 pIEE[x].full = ImportExportElementDescriptor->full;
3998 pIEE[x].ASC = ImportExportElementDescriptor->asc;
4000 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASC IEE\n");
4005 pIEE[x].ASCQ = ImportExportElementDescriptor->ascq;
4007 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASCQ IEE\n");
4012 if (ImportExportElementDescriptor->svalid == 1)
4014 pIEE[x].from = V2(ImportExportElementDescriptor->source);
4019 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip source IEE\n");
4022 offset = offset + length;
4027 * Data Transfer Elements
4029 if (V2(pEAAPage->NoDataTransferElements) >0)
4032 DTE = V2(pEAAPage->NoDataTransferElements) ;
4033 if ((pDTE = (ElementInfo_T *)malloc(sizeof(ElementInfo_T) * DTE)) == NULL)
4035 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"GenericElementStatus : malloc failed\n");
4039 memset(pDTE, 0, sizeof(ElementInfo_T) * DTE);
4041 if (SCSI_ReadElementStatus(DeviceFD,
4045 V2(pEAAPage->FirstDataTransferElementAddress),
4047 sizeof(DataTransferElementDescriptor_T),
4048 (char **)&DataBuffer) != 0)
4051 ChgExit("GenericElementStatus", "Can't read DTE status", FATAL);
4054 ElementStatusData = (ElementStatusData_T *)DataBuffer;
4055 offset = sizeof(ElementStatusData_T);
4057 ElementStatusPage = (ElementStatusPage_T *)&DataBuffer[offset];
4058 offset = offset + sizeof(ElementStatusPage_T);
4059 length = V2(ElementStatusPage->length);
4060 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"DTE Length %d\n",length);
4062 for (x = 0; x < DTE; x++)
4064 DataTransferElementDescriptor = (DataTransferElementDescriptor_T *)&DataBuffer[offset];
4065 if (ElementStatusPage->pvoltag == 1)
4067 strncpy(pDTE[x].VolTag,
4068 (char *)DataTransferElementDescriptor->pvoltag,
4070 TerminateString(pDTE[x].VolTag, TAG_SIZE+1);
4072 pDTE[x].type = ElementStatusPage->type;
4073 pDTE[x].address = V2(DataTransferElementDescriptor->address);
4074 pDTE[x].except = DataTransferElementDescriptor->except;
4075 pDTE[x].scsi = DataTransferElementDescriptor->scsi;
4076 pDTE[x].status = (DataTransferElementDescriptor->full > 0) ? 'F':'E';
4077 pDTE[x].full = DataTransferElementDescriptor->full;
4081 pDTE[x].ASC = DataTransferElementDescriptor->asc;
4083 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASC DTE\n");
4088 pDTE[x].ASCQ = DataTransferElementDescriptor->ascq;
4090 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASCQ DTE\n");
4095 if (DataTransferElementDescriptor->svalid == 1)
4097 pDTE[x].from = V2(DataTransferElementDescriptor->source);
4102 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip source STE\n");
4105 offset = offset + length;
4110 * And now the old way, when we get here the read mode sense page has failed ...
4112 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Reading Element Status the old way .... (max 255 elements)\n");
4113 if (SCSI_ReadElementStatus(DeviceFD,
4120 (char **)&DataBuffer) != 0)
4122 if (DataBuffer != 0)
4126 ChgExit("GenericElementStatus","Can't get ElementStatus", FATAL);
4129 ElementStatusData = (ElementStatusData_T *)DataBuffer;
4130 DataBufferLength = V3(ElementStatusData->count);
4132 offset = sizeof(ElementStatusData_T);
4134 if (DataBufferLength <= 0)
4136 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"DataBufferLength %d\n",DataBufferLength);
4141 while (offset < DataBufferLength)
4143 ElementStatusPage = (ElementStatusPage_T *)&DataBuffer[offset];
4144 NoOfElements = V3(ElementStatusPage->count) / V2(ElementStatusPage->length);
4145 offset = offset + sizeof(ElementStatusPage_T);
4146 length = V2(ElementStatusPage->length);
4148 switch (ElementStatusPage->type)
4153 if ((pMTE = (ElementInfo_T *)malloc(sizeof(ElementInfo_T) * MTE)) == NULL)
4155 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"GenericElementStatus : malloc failed\n");
4159 memset(pMTE, 0, sizeof(ElementInfo_T) * MTE);
4161 for (x = 0; x < NoOfElements; x++)
4163 MediumTransportElementDescriptor = (MediumTransportElementDescriptor_T *)&DataBuffer[offset];
4164 if (ElementStatusPage->pvoltag == 1)
4166 strncpy(pMTE[x].VolTag,
4167 (char *)MediumTransportElementDescriptor->pvoltag,
4169 TerminateString(pMTE[x].VolTag, TAG_SIZE+1);
4171 pMTE[x].type = ElementStatusPage->type;
4172 pMTE[x].address = V2(MediumTransportElementDescriptor->address);
4173 pMTE[x].except = MediumTransportElementDescriptor->except;
4174 pMTE[x].status = (MediumTransportElementDescriptor->full > 0) ? 'F':'E';
4175 pMTE[x].full = MediumTransportElementDescriptor->full;
4180 pMTE[x].ASC = MediumTransportElementDescriptor->asc;
4182 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASC MTE\n");
4187 pMTE[x].ASCQ = MediumTransportElementDescriptor->ascq;
4189 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASCQ MTE\n");
4194 if (MediumTransportElementDescriptor->svalid == 1)
4196 pMTE[x].from = V2(MediumTransportElementDescriptor->source);
4201 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip source MTE\n");
4204 offset = offset + length;
4210 if ((pSTE = (ElementInfo_T *)malloc(sizeof(ElementInfo_T) * STE)) == NULL)
4212 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"GenericElementStatus : malloc failed\n");
4216 memset(pSTE, 0, sizeof(ElementInfo_T) * STE);
4218 for (x = 0; x < NoOfElements; x++)
4220 StorageElementDescriptor = (StorageElementDescriptor_T *)&DataBuffer[offset];
4221 if (ElementStatusPage->pvoltag == 1)
4223 strncpy(pSTE[x].VolTag,
4224 (char *)StorageElementDescriptor->pvoltag,
4226 TerminateString(pSTE[x].VolTag, TAG_SIZE+1);
4229 pSTE[x].type = ElementStatusPage->type;
4230 pSTE[x].address = V2(StorageElementDescriptor->address);
4231 pSTE[x].except = StorageElementDescriptor->except;
4232 pSTE[x].status = (StorageElementDescriptor->full > 0) ? 'F':'E';
4233 pSTE[x].full = StorageElementDescriptor->full;
4237 pSTE[x].ASC = StorageElementDescriptor->asc;
4239 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASC STE\n");
4244 pSTE[x].ASCQ = StorageElementDescriptor->ascq;
4246 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASCQ STE\n");
4251 if (StorageElementDescriptor->svalid == 1)
4253 pSTE[x].from = V2(StorageElementDescriptor->source);
4258 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip source STE\n");
4261 offset = offset + length;
4267 if ((pIEE = (ElementInfo_T *)malloc(sizeof(ElementInfo_T) * IEE)) == NULL)
4269 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"GenericElementStatus : malloc failed\n");
4273 memset(pIEE, 0, sizeof(ElementInfo_T) * IEE);
4275 for (x = 0; x < NoOfElements; x++)
4277 ImportExportElementDescriptor = (ImportExportElementDescriptor_T *)&DataBuffer[offset];
4278 if (ElementStatusPage->pvoltag == 1)
4280 strncpy(pIEE[x].VolTag,
4281 (char *)ImportExportElementDescriptor->pvoltag,
4283 TerminateString(pIEE[x].VolTag, TAG_SIZE+1);
4285 ImportExportElementDescriptor = (ImportExportElementDescriptor_T *)&DataBuffer[offset];
4286 pIEE[x].type = ElementStatusPage->type;
4287 pIEE[x].address = V2(ImportExportElementDescriptor->address);
4288 pIEE[x].except = ImportExportElementDescriptor->except;
4289 pIEE[x].status = (ImportExportElementDescriptor->full > 0) ? 'F':'E';
4290 pIEE[x].full = ImportExportElementDescriptor->full;
4294 pIEE[x].ASC = ImportExportElementDescriptor->asc;
4296 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASC IEE\n");
4301 pIEE[x].ASCQ = ImportExportElementDescriptor->ascq;
4303 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASCQ IEE\n");
4308 if (ImportExportElementDescriptor->svalid == 1)
4310 pIEE[x].from = V2(ImportExportElementDescriptor->source);
4315 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip source IEE\n");
4318 offset = offset + length;
4324 if ((pDTE = (ElementInfo_T *)malloc(sizeof(ElementInfo_T) * DTE)) == NULL)
4326 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"GenericElementStatus : malloc failed\n");
4330 memset(pDTE, 0, sizeof(ElementInfo_T) * DTE);
4332 for (x = 0; x < NoOfElements; x++)
4334 DataTransferElementDescriptor = (DataTransferElementDescriptor_T *)&DataBuffer[offset];
4335 if (ElementStatusPage->pvoltag == 1)
4337 strncpy(pSTE[x].VolTag,
4338 (char *)DataTransferElementDescriptor->pvoltag,
4340 TerminateString(pSTE[x].VolTag, TAG_SIZE+1);
4342 pDTE[x].type = ElementStatusPage->type;
4343 pDTE[x].address = V2(DataTransferElementDescriptor->address);
4344 pDTE[x].except = DataTransferElementDescriptor->except;
4345 pDTE[x].scsi = DataTransferElementDescriptor->scsi;
4346 pDTE[x].status = (DataTransferElementDescriptor->full > 0) ? 'F':'E';
4347 pDTE[x].full = DataTransferElementDescriptor->full;
4351 pDTE[x].ASC = DataTransferElementDescriptor->asc;
4353 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASC DTE\n");
4358 pDTE[x].ASCQ = DataTransferElementDescriptor->ascq;
4360 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip ASCQ DTE\n");
4365 if (DataTransferElementDescriptor->svalid == 1)
4367 pDTE[x].from = V2(DataTransferElementDescriptor->source);
4372 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"Skip source STE\n");
4375 offset = offset + length;
4379 offset = offset + length;
4380 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"GetElementStatus : UnGknown Type %d\n",ElementStatusPage->type);
4386 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"\n\n\tMedia Transport Elements (robot arms) :\n");
4388 for ( x = 0; x < MTE; x++)
4389 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",
4390 pMTE[x].address, pMTE[x].status, pMTE[x].except, pMTE[x].ASC,
4391 pMTE[x].ASCQ, pMTE[x].type, pMTE[x].from, pMTE[x].VolTag);
4393 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"\n\n\tStorage Elements (Media slots) :\n");
4395 for ( x = 0; x < STE; x++)
4396 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",
4397 pSTE[x].address, pSTE[x].status, pSTE[x].except, pSTE[x].ASC,
4398 pSTE[x].ASCQ, pSTE[x].type, pSTE[x].from, pSTE[x].VolTag);
4400 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"\n\n\tData Transfer Elements (tape drives) :\n");
4402 for ( x = 0; x < DTE; x++)
4403 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",
4404 pDTE[x].address, pDTE[x].status, pDTE[x].except, pDTE[x].ASC,
4405 pDTE[x].ASCQ, pDTE[x].type, pDTE[x].from, pDTE[x].VolTag,pDTE[x].scsi);
4407 DebugPrint(DEBUG_INFO, SECTION_ELEMENT,"\n\n\tImport/Export Elements :\n");
4409 for ( x = 0; x < IEE; x++)
4410 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",
4411 pIEE[x].address, pIEE[x].status, pIEE[x].except, pIEE[x].ASC,
4412 pIEE[x].ASCQ, pIEE[x].type, pIEE[x].from, pIEE[x].VolTag);
4422 * If ClearErrorCounters is set the counters will be reset.
4423 * Used by GenericClean for example
4427 int RequestSense(int DeviceFD, ExtendedRequestSense_T *ExtendedRequestSense, int ClearErrorCounters )
4432 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### START RequestSense\n");
4434 CDB[0] = SC_COM_REQUEST_SENSE; /* REQUEST SENSE */
4435 CDB[1] = 0; /* Logical Unit Number = 0, Reserved */
4436 CDB[2] = 0; /* Reserved */
4437 CDB[3] = 0; /* Reserved */
4438 CDB[4] = sizeof(ExtendedRequestSense_T); /* Allocation Length */
4439 CDB[5] = (ClearErrorCounters << 7) & 0x80; /* */
4441 memset(ExtendedRequestSense, 0, sizeof(ExtendedRequestSense_T));
4443 ret = SCSI_Run(DeviceFD, Input, CDB, 6,
4444 (char *) ExtendedRequestSense,
4445 sizeof(ExtendedRequestSense_T),
4446 (char *) ExtendedRequestSense, sizeof(ExtendedRequestSense_T));
4451 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP RequestSense (%d)\n",ret);
4457 DecodeExtSense(ExtendedRequestSense, "RequestSense : ",debug_file);
4458 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP RequestSense (%d)\n", ExtendedRequestSense->SenseKey);
4459 return(ExtendedRequestSense->SenseKey);
4462 dump_hex((char *)ExtendedRequestSense , sizeof(ExtendedRequestSense_T) , DEBUG_INFO, SECTION_SCSI);
4463 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP RequestSense (0)\n");
4469 * Lookup function pointer for device ....
4473 ElementInfo_T *LookupElement(int address)
4477 dbprintf(("##### START LookupElement\n"));
4481 for (x = 0; x < DTE; x++)
4483 if (pDTE[x].address == address)
4485 dbprintf(("##### STOP LookupElement (DTE)\n"));
4493 for (x = 0; x < MTE; x++)
4495 if (pMTE[x].address == address)
4497 dbprintf(("##### STOP LookupElement (MTE)\n"));
4505 for (x = 0; x < STE; x++)
4507 if (pSTE[x].address == address)
4509 dbprintf(("##### STOP LookupElement (STE)\n"));
4517 for ( x = 0; x < IEE; x++)
4519 if (pIEE[x].address == address)
4521 dbprintf(("##### STOP LookupElement (IEE)\n"));
4529 * Here comes everything what decode the log Pages
4532 * Fix the result handling from TestUnitReady
4535 int LogSense(DeviceFD)
4537 extern OpenFiles_T *pDev;
4539 RequestSense_T *pRequestSense;
4540 LogSenseHeader_T *LogSenseHeader;
4541 LogParameter_T *LogParameter;
4542 struct LogPageDecode *p;
4544 extern char *tapestatfile;
4555 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### START LogSense\n");
4557 if ((tapestatfile != NULL) && (pDev[INDEX_TAPECTL].SCSI == 1) &&
4558 ((StatFile = fopen(tapestatfile,"a")) != NULL))
4560 if ((pRequestSense = (RequestSense_T *)malloc(sizeof(RequestSense_T))) == NULL)
4562 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"LogSense : malloc failed\n");
4567 if (GenericRewind(INDEX_TAPECTL) < 0)
4569 DebugPrint(DEBUG_INFO, SECTION_TAPE,"LogSense : Rewind failed\n");
4570 free(pRequestSense);
4575 * Try to read the tape label
4577 if (pDev[INDEX_TAPE].inqdone == 1)
4579 if (pDev[INDEX_TAPE].devopen == 1)
4581 SCSI_CloseDevice(INDEX_TAPE);
4584 if ((chgscsi_result = (char *)tape_rdlabel(pDev[INDEX_TAPE].dev, &chgscsi_datestamp, &chgscsi_label)) == NULL)
4586 fprintf(StatFile, "==== %s ==== %s ====\n", chgscsi_datestamp, chgscsi_label);
4588 fprintf(StatFile, "%s\n", chgscsi_result);
4592 if ((buffer = (char *)malloc(size)) == NULL)
4594 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"LogSense : malloc failed\n");
4595 free(pRequestSense);
4599 memset(buffer, 0, size);
4601 * Get the known log pages
4604 CDB[0] = SC_COM_LOG_SENSE;
4606 CDB[2] = 0x40; /* 0x40 for current values */
4611 MSB2(&CDB[7], size);
4614 if (SCSI_Run(INDEX_TAPECTL, Input, CDB, 10,
4617 (char *)pRequestSense,
4618 sizeof(RequestSense_T)) != 0)
4620 DecodeSense(pRequestSense, "LogSense : ",debug_file);
4621 free(pRequestSense);
4627 LogSenseHeader = (LogSenseHeader_T *)buffer;
4628 nologpages = V2(LogSenseHeader->PageLength);
4629 if ((logpages = (char *)malloc(nologpages)) == NULL)
4631 DebugPrint(DEBUG_ERROR, SECTION_TAPE,"LogSense : malloc failed\n");
4632 free(pRequestSense);
4638 memcpy(logpages, buffer + sizeof(LogSenseHeader_T), nologpages);
4640 for (count = 0; count < nologpages; count++) {
4641 if (logpages[count] != 0 ) {
4642 memset(buffer, 0, size);
4643 CDB[0] = SC_COM_LOG_SENSE;
4645 CDB[2] = 0x40 | logpages[count]; /* 0x40 for current values */
4650 MSB2(&CDB[7], size);
4653 if (SCSI_Run(INDEX_TAPECTL, Input, CDB, 10,
4656 (char *)pRequestSense,
4657 sizeof(RequestSense_T)) != 0)
4659 DecodeSense(pRequestSense, "LogSense : ",debug_file);
4660 free(pRequestSense);
4666 LogSenseHeader = (LogSenseHeader_T *)buffer;
4667 length = V2(LogSenseHeader->PageLength);
4668 LogParameter = (LogParameter_T *)(buffer + sizeof(LogSenseHeader_T));
4670 * Decode the log pages
4672 p = (struct LogPageDecode *)&DecodePages;
4675 dump_hex((char *)LogParameter, 64, DEBUG_INFO, SECTION_SCSI);
4677 while(p->ident != NULL) {
4678 if ((strcmp(pDev[INDEX_TAPECTL].ident, p->ident) == 0 ||strcmp("*", p->ident) == 0) && p->LogPage == logpages[count]) {
4679 p->decode(LogParameter, length);
4681 fprintf(StatFile, "\n");
4688 fprintf(StatFile, "Logpage No %d = %x\n", count ,logpages[count]);
4690 while ((char *)LogParameter < (buffer + length)) {
4691 i = LogParameter->ParameterLength;
4692 ParameterCode = V2(LogParameter->ParameterCode);
4695 value = V1((char *)LogParameter + sizeof(LogParameter_T));
4696 fprintf(StatFile, "ParameterCode %02X = %u(%d)\n", ParameterCode, value, i);
4699 value = V2((char *)LogParameter + sizeof(LogParameter_T));
4700 fprintf(StatFile, "ParameterCode %02X = %u(%d)\n", ParameterCode, value, i);
4703 value = V3((char *)LogParameter + sizeof(LogParameter_T));
4704 fprintf(StatFile, "ParameterCode %02X = %u(%d)\n", ParameterCode, value, i);
4707 value = V4((char *)LogParameter + sizeof(LogParameter_T));
4708 fprintf(StatFile, "ParameterCode %02X = %u(%d)\n", ParameterCode, value, i);
4711 value = V5((char *)LogParameter + sizeof(LogParameter_T));
4712 fprintf(StatFile, "ParameterCode %02X = %u(%d)\n", ParameterCode, value, i);
4715 fprintf(StatFile, "ParameterCode %02X size %d\n", ParameterCode, i);
4717 LogParameter = (LogParameter_T *)((char *)LogParameter + sizeof(LogParameter_T) + i);
4719 fprintf(StatFile, "\n");
4726 * Reset the cumulative counters
4728 CDB[0] = SC_COM_LOG_SELECT;
4739 if (SCSI_Run(INDEX_TAPECTL, Input, CDB, 10,
4742 (char *)pRequestSense,
4743 sizeof(RequestSense_T)) != 0)
4745 DecodeSense(pRequestSense, "LogSense : ",debug_file);
4746 free(pRequestSense);
4753 free(pRequestSense);
4758 DebugPrint(DEBUG_INFO, SECTION_TAPE,"##### STOP LogSense\n");
4762 void WriteErrorCountersPage(LogParameter_T *buffer, int length)
4766 LogParameter_T *LogParameter;
4768 LogParameter = buffer;
4770 fprintf(StatFile, "\tWrite Error Counters Page\n");
4772 while ((char *)LogParameter < ((char *)buffer + length)) {
4773 i = LogParameter->ParameterLength;
4774 ParameterCode = V2(LogParameter->ParameterCode);
4777 if (Decode(LogParameter, &value) == 0) {
4778 switch (ParameterCode) {
4780 fprintf(StatFile, "%-30s = %u\n",
4785 fprintf(StatFile, "%-30s = %u\n",
4786 "Total Errors Corrected",
4790 fprintf(StatFile, "%-30s = %u\n",
4791 "Total Times E. Processed",
4795 fprintf(StatFile, "%-30s = %u\n",
4796 "Total Bytes Processed",
4800 fprintf(StatFile, "%-30s = %u\n",
4801 "Total Unrecoverable Errors",
4805 fprintf(StatFile, "Unknown ParameterCode %02X = %u(%d)\n",
4811 fprintf(StatFile, "Error decoding Result\n");
4813 LogParameter = (LogParameter_T *)((char *)LogParameter + sizeof(LogParameter_T) + i);
4817 void ReadErrorCountersPage(LogParameter_T *buffer, int length)
4821 LogParameter_T *LogParameter;
4823 LogParameter = buffer;
4825 fprintf(StatFile, "\tRead Error Counters Page\n");
4827 while ((char *)LogParameter < ((char *)buffer + length)) {
4828 i = LogParameter->ParameterLength;
4829 ParameterCode = V2(LogParameter->ParameterCode);
4831 if (Decode(LogParameter, &value) == 0) {
4832 switch (ParameterCode) {
4834 fprintf(StatFile, "%-30s = %u\n",
4839 fprintf(StatFile, "%-30s = %u\n",
4840 "Total Errors Corrected",
4844 fprintf(StatFile, "%-30s = %u\n",
4845 "Total Times E. Processed",
4849 fprintf(StatFile, "%-30s = %u\n",
4850 "Total Bytes Processed",
4854 fprintf(StatFile, "%-30s = %u\n",
4855 "Total Unrecoverable Errors",
4859 fprintf(StatFile, "Unknown ParameterCode %02X = %u(%d)\n",
4865 fprintf(StatFile, "Error decoding Result\n");
4867 LogParameter = (LogParameter_T *)((char *)LogParameter + sizeof(LogParameter_T) + i);
4871 void C1553APage30(LogParameter_T *buffer, int length)
4875 LogParameter_T *LogParameter;
4877 LogParameter = buffer;
4879 fprintf(StatFile, "\tData compression transfer Page\n");
4881 while ((char *)LogParameter < ((char *)buffer + length)) {
4882 i = LogParameter->ParameterLength;
4883 ParameterCode = V2(LogParameter->ParameterCode);
4885 if (Decode(LogParameter, &value) == 0) {
4886 switch (ParameterCode) {
4888 fprintf(StatFile, "Unknown ParameterCode %02X = %u(%d)\n",
4894 LogParameter = (LogParameter_T *)((char *)LogParameter + sizeof(LogParameter_T) + i);
4898 void C1553APage37(LogParameter_T *buffer, int length)
4902 LogParameter_T *LogParameter;
4904 LogParameter = buffer;
4906 fprintf(StatFile, "\tDrive Counters Page\n");
4908 while ((char *)LogParameter < ((char *)buffer + length)) {
4909 i = LogParameter->ParameterLength;
4910 ParameterCode = V2(LogParameter->ParameterCode);
4912 if (Decode(LogParameter, &value) == 0) {
4913 switch (ParameterCode) {
4915 fprintf(StatFile, "%-30s = %u\n",
4920 fprintf(StatFile, "%-30s = %u\n",
4921 "Total write drive errors",
4925 fprintf(StatFile, "%-30s = %u\n",
4926 "Total read drive errors",
4930 fprintf(StatFile, "Unknown ParameterCode %02X = %u(%d)\n",
4936 LogParameter = (LogParameter_T *)((char *)LogParameter + sizeof(LogParameter_T) + i);
4940 void EXB85058HEPage39(LogParameter_T *buffer, int length)
4944 LogParameter_T *LogParameter;
4946 LogParameter = buffer;
4948 fprintf(StatFile, "\tData Compression Page\n");
4950 while ((char *)LogParameter < ((char *)buffer + length)) {
4951 i = LogParameter->ParameterLength;
4952 ParameterCode = V2(LogParameter->ParameterCode);
4954 if (Decode(LogParameter, &value) == 0) {
4955 switch (ParameterCode) {
4957 fprintf(StatFile, "%-30s = %u\n",
4962 fprintf(StatFile, "%-30s = %u\n",
4967 fprintf(StatFile, "Unknown ParameterCode %02X = %u(%d)\n",
4973 LogParameter = (LogParameter_T *)((char *)LogParameter + sizeof(LogParameter_T) + i);
4977 void EXB85058HEPage3c(LogParameter_T *buffer, int length)
4981 LogParameter_T *LogParameter;
4983 LogParameter = buffer;
4985 fprintf(StatFile, "\tDrive Usage Information Page\n");
4987 while ((char *)LogParameter < ((char *)buffer + length)) {
4988 i = LogParameter->ParameterLength;
4989 ParameterCode = V2(LogParameter->ParameterCode);
4991 if (Decode(LogParameter, &value) == 0) {
4992 switch (ParameterCode) {
5000 fprintf(StatFile, "%-30s = %u\n",
5005 fprintf(StatFile, "%-30s = %u\n",
5006 "MinutesSince Last Clean",
5013 fprintf(StatFile, "%-30s = %u\n",
5025 fprintf(StatFile, "%-30s = %u\n",
5034 fprintf(StatFile, "Unknown ParameterCode %02X = %u(%d)\n",
5040 LogParameter = (LogParameter_T *)((char *)LogParameter + sizeof(LogParameter_T) + i);
5044 int Decode(LogParameter_T *LogParameter, int *value)
5047 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### START Decode\n");
5048 DebugPrint(DEBUG_INFO, SECTION_SCSI,"Decode Parameter with length %d\n", LogParameter->ParameterLength);
5049 switch (LogParameter->ParameterLength) {
5051 *value = V1((char *)LogParameter + sizeof(LogParameter_T));
5054 *value = V2((char *)LogParameter + sizeof(LogParameter_T));
5057 *value = V3((char *)LogParameter + sizeof(LogParameter_T));
5060 *value = V4((char *)LogParameter + sizeof(LogParameter_T));
5063 *value = V5((char *)LogParameter + sizeof(LogParameter_T));
5066 *value = V6((char *)LogParameter + sizeof(LogParameter_T));
5069 fprintf(StatFile, "Can't decode ParameterCode %02X size %d\n",
5070 V2(LogParameter->ParameterCode), LogParameter->ParameterLength);
5071 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP Decode (1)\n");
5074 DebugPrint(DEBUG_INFO, SECTION_SCSI,"Result = %d\n", *value);
5075 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP Decode(0)\n");
5079 void DumpDev(OpenFiles_T *p, char *device)
5083 printf("%s Devicefd %d\n", device, p->fd);
5084 printf("%s Can SCSI %d\n", device, p->SCSI);
5085 printf("%s Device %s\n", device, (p->dev != NULL)? p->dev:"No set");
5086 printf("%s ConfigName %s\n", device, (p->ConfigName != NULL) ? p->ConfigName:"Not ser");
5088 printf("%s Null Pointer ....\n", device);
5093 void ChangerReplay(char *option)
5099 if ((ip=fopen("/tmp/chg-scsi-trace", "r")) == NULL)
5104 while (fscanf(ip, "%2x", &bufferx) != EOF)
5106 buffer[x] = bufferx;
5110 DecodeModeSense(&buffer[0], 12, "DLT448ElementStatus :", 0, debug_file);
5115 * Display all Information we can get about the library....
5117 void ChangerStatus(char *option, char * labelfile, int HasBarCode, char *changer_file, char *changer_dev, char *tape_device)
5119 extern OpenFiles_T *pDev;
5122 ExtendedRequestSense_T ExtRequestSense;
5125 ChangerCMD_T *p = (ChangerCMD_T *)&ChangerIO;
5126 if ((pbarcoderes = malloc(sizeof(MBC_T))) == NULL)
5128 printf("malloc failed \n");
5131 memset(pbarcoderes, 0, sizeof(MBC_T));
5133 if ((pModePage == NULL) && ((pModePage = (char *)malloc(0xff)) == NULL))
5135 DebugPrint(DEBUG_ERROR, SECTION_ELEMENT,"##### malloc failed (-1)\n");
5136 printf("malloc failed \n");
5141 if ((out = fdopen(1 , "w")) == NULL)
5143 printf("Error fdopen stdout\n");
5148 if (strcmp("types", option) == 0 || strcmp("all", option) == 0)
5150 while(p->ident != NULL)
5152 printf ("Ident = %s, type = %s\n",p->ident, p->type);
5158 if (strcmp("robot", option) == 0 || strcmp("all", option) == 0)
5160 if (ElementStatusValid == 0)
5162 if (pDev[INDEX_CHANGER].functions->function_status(pDev[INDEX_CHANGER].fd, 1) != 0)
5164 printf("Can not initialize changer status\n");
5170 /* 0123456789012345678901234567890123456789012 */
5173 printf("Address Type Status From Barcode Label\n");
5175 printf("Address Type Status From\n");
5177 printf("-------------------------------------------\n");
5180 for ( x = 0; x < MTE; x++)
5183 printf("%07d MTE %s %04d %s ",pMTE[x].address,
5184 (pMTE[x].full ? "Full " :"Empty"),
5185 pMTE[x].from, pMTE[x].VolTag);
5187 if (pMTE[x].full == 1)
5189 pbarcoderes->action = BARCODE_BARCODE;
5190 strcpy(pbarcoderes->data.barcode, pMTE[x].VolTag);
5192 if (MapBarCode(labelfile, pbarcoderes) == 0 )
5194 printf("No mapping\n");
5196 printf("%s \n",pbarcoderes->data.voltag);
5202 printf("%07d MTE %s %04d \n",pMTE[x].address,
5203 (pMTE[x].full ? "Full " :"Empty"),
5208 for ( x = 0; x < STE; x++)
5211 printf("%07d STE %s %04d %s ",pSTE[x].address,
5212 (pSTE[x].full ? "Full ":"Empty"),
5213 pSTE[x].from, pSTE[x].VolTag);
5215 if (pSTE[x].full == 1)
5217 pbarcoderes->action = BARCODE_BARCODE;
5218 strcpy(pbarcoderes->data.barcode, pSTE[x].VolTag);
5220 if (MapBarCode(labelfile, pbarcoderes) == 0 )
5222 printf("No mapping\n");
5224 printf("%s \n",pbarcoderes->data.voltag);
5230 printf("%07d STE %s %04d %s\n",pSTE[x].address,
5231 (pSTE[x].full ? "Full ":"Empty"),
5232 pSTE[x].from, pSTE[x].VolTag);
5236 for ( x = 0; x < DTE; x++)
5239 printf("%07d DTE %s %04d %s ",pDTE[x].address,
5240 (pDTE[x].full ? "Full " : "Empty"),
5241 pDTE[x].from, pDTE[x].VolTag);
5243 if (pDTE[x].full == 1)
5245 pbarcoderes->action = BARCODE_BARCODE;
5246 strcpy(pbarcoderes->data.barcode, pDTE[x].VolTag);
5248 if (MapBarCode(labelfile, pbarcoderes) == 0 )
5250 printf("No mapping\n");
5252 printf("%s \n",pbarcoderes->data.voltag);
5259 printf("%07d DTE %s %04d %s\n",pDTE[x].address,
5260 (pDTE[x].full ? "Full " : "Empty"),
5261 pDTE[x].from, pDTE[x].VolTag);
5264 for ( x = 0; x < IEE; x++)
5267 printf("%07d IEE %s %04d %s ",pIEE[x].address,
5268 (pIEE[x].full ? "Full " : "Empty"),
5269 pIEE[x].from, pIEE[x].VolTag);
5271 if (pIEE[x].full == 1)
5273 pbarcoderes->action = BARCODE_BARCODE;
5274 strcpy(pbarcoderes->data.barcode, pIEE[x].VolTag);
5276 if (MapBarCode(labelfile, pbarcoderes) == 0 )
5278 printf("No mapping\n");
5280 printf("%s \n",pbarcoderes->data.voltag);
5287 printf("%07d IEE %s %04d %s\n",pIEE[x].address,
5288 (pIEE[x].full ? "Full " : "Empty"),
5289 pIEE[x].from, pIEE[x].VolTag);
5294 if (strcmp("sense", option) == 0 || strcmp("all", option) == 0)
5296 if (pDev[INDEX_CHANGER].SCSI == 1)
5298 printf("\nSense Status from robot:\n");
5299 RequestSense(INDEX_CHANGER , &ExtRequestSense, 0);
5300 DecodeExtSense(&ExtRequestSense, "", out);
5303 if (pDev[INDEX_TAPE].SCSI == 1)
5306 printf("Sense Status from tape (tapectl):\n");
5307 RequestSense(INDEX_TAPE, &ExtRequestSense, 0);
5308 DecodeExtSense(&ExtRequestSense, "", out);
5311 if (pDev[INDEX_TAPECTL].SCSI == 1)
5314 printf("Sense Status from tape (tapectl):\n");
5315 RequestSense(INDEX_TAPECTL, &ExtRequestSense, 0);
5316 DecodeExtSense(&ExtRequestSense, "", out);
5320 if (strcmp("ModeSenseRobot", option) == 0 || strcmp("all", option) == 0)
5323 if (SCSI_ModeSense(INDEX_CHANGER, pModePage, 0xff, 0x08, 0x3f) == 0)
5325 DecodeModeSense(pModePage, 0, "Changer :" , 0, out);
5329 if (strcmp("ModeSenseTape", option) == 0 || strcmp("all", option) == 0)
5331 if (pDev[INDEX_TAPECTL].SCSI == 1)
5334 if (SCSI_ModeSense(INDEX_TAPECTL, pModePage, 0xff, 0x0, 0x3f) == 0)
5336 DecodeModeSense(pModePage, 0, "Tape :" , 1, out);
5341 if (strcmp("fd", option) == 0 || strcmp("all", option) == 0)
5343 printf("changer_dev %s\n",changer_dev);
5344 printf("changer_file %s\n", changer_file);
5345 printf("tape_device %s\n\n", tape_device);
5346 DumpDev(&pDev[INDEX_TAPE], "pTapeDev");
5347 DumpDev(&pDev[INDEX_TAPECTL], "pTapeDevCtl");
5348 DumpDev(&pDev[INDEX_CHANGER], "pChangerDev");
5351 if (GenericClean("") == 1)
5352 printf("Tape needs cleaning\n");
5358 void dump_hex(char *p, int size, int level, int section)
5363 while (row_count < size)
5365 DebugPrint(level, section,"%02X ", (unsigned char)p[row_count]);
5366 if (((row_count + 1) % 16) == 0 )
5369 for (x = 16; x>0;x--)
5371 if (isalnum((unsigned char)p[row_count - x + 1 ]))
5372 DebugPrint(level, section,"%c",(unsigned char)p[row_count - x + 1]);
5374 DebugPrint(level, section,".");
5376 DebugPrint(level, section,"\n");
5380 DebugPrint(level, section,"\n");
5383 void TerminateString(char *string, int length)
5387 for (x = length; x >= 0 && !isalnum((int)string[x]); x--)
5391 void ChgExit(char *where, char *reason, int level)
5393 dbprintf(("ChgExit in %s, reason %s\n", where, reason));
5394 fprintf(stderr,"%s\n",reason);
5398 /* OK here starts a new set of functions.
5399 * Every function is for one SCSI command.
5400 * Prefix is SCSI_ and then the SCSI command name
5404 * SCSI_Run is an wrapper arround SCSI_ExecuteCommand
5405 * It seems to be an good idea to check first if the device
5406 * is ready for accepting commands, and if this is true send
5409 int SCSI_Run(int DeviceFD,
5410 Direction_T Direction,
5414 int DataBufferLength,
5415 char *pRequestSense,
5416 int RequestSenseLength)
5421 RequestSense_T *pRqS;
5423 pRqS = (RequestSense_T *)pRequestSense;
5425 DebugPrint(DEBUG_INFO, SECTION_SCSI, "SCSI_Run TestUnitReady\n");
5426 while (!ok && maxtries < MAXTRIES)
5428 ret = SCSI_TestUnitReady(DeviceFD, (RequestSense_T *)pRequestSense );
5429 DebugPrint(DEBUG_INFO, SECTION_SCSI, "SCSI_Run TestUnitReady ret %d\n",ret);
5436 switch (SenseHandler(DeviceFD, 0, pRqS->SenseKey, pRqS->AdditionalSenseCode, pRqS->AdditionalSenseCodeQualifier, pRequestSense))
5439 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run (TestUnitReady) SENSE_NO\n");
5442 case SENSE_TAPE_NOT_ONLINE:
5443 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run (TestUnitReady) SENSE_TAPE_NOT_ONLINE\n");
5447 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run (TestUnitReady) SENSE_IGNORE\n");
5451 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"SCSI_Run (TestUnitReady) SENSE_ABORT\n");
5455 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run (TestUnitReady) SENSE_RETRY\n");
5458 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run (TestUnitReady) default (SENSE)\n");
5464 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"SCSI_Run (TestUnitReady) SCSI_ERROR\n");
5468 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run (TestUnitReady) SCSI_BUSY\n");
5471 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run (TestUnitReady) SCSI_CHECK\n");
5474 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"SCSI_Run (TestUnitReady) unknown (%d)\n",ret);
5484 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run TestUnitReady after %d sec:\n",maxtries);
5488 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"SCSI_Run Exit %d\n",ret);
5494 while (!ok && maxtries < MAXTRIES)
5496 ret = SCSI_ExecuteCommand(DeviceFD,
5503 RequestSenseLength);
5505 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run Exit %d\n",ret);
5512 switch (SenseHandler(DeviceFD, 0, pRqS->SenseKey, pRqS->AdditionalSenseCode, pRqS->AdditionalSenseCodeQualifier, pRequestSense))
5515 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run SENSE_NO\n");
5518 case SENSE_TAPE_NOT_ONLINE:
5519 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run SENSE_TAPE_NOT_ONLINE\n");
5523 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run SENSE_IGNORE\n");
5527 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"SCSI_Run SENSE_ABORT\n");
5531 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run SENSE_RETRY\n");
5534 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run default (SENSE)\n");
5540 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"SCSI_Run SCSI_ERROR\n");
5544 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run SCSI_BUSY\n");
5547 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Run (TestUnitReady) SCSI_CHECK\n");
5550 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"SCSI_Run (TestUnitReady) unknown (%d)\n",ret);
5566 * This a vendor specific command !!!!!!
5567 * First seen at AIT :-)
5569 int SCSI_AlignElements(int DeviceFD, int AE_MTE, int AE_DTE, int AE_STE)
5571 RequestSense_T *pRequestSense;
5577 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### START SCSI_AlignElements\n");
5579 if ((pRequestSense = (RequestSense_T *)malloc(sizeof(RequestSense_T))) == NULL)
5581 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_AlignElements : malloc failed\n");
5585 for (retry = 0; retry < MAX_RETRIES; retry++)
5589 MSB2(&CDB[2],AE_MTE); /* Which MTE to use, default 0 */
5590 MSB2(&CDB[4],AE_DTE); /* Which DTE to use, no range check !! */
5591 MSB2(&CDB[6],AE_STE); /* Which STE to use, no range check !! */
5597 ret = SCSI_Run(DeviceFD, Input, CDB, 12,
5598 NULL, 0, (char *)pRequestSense, sizeof(RequestSense_T));
5600 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_AlignElements : SCSI_Run = %d\n", ret);
5601 DecodeSense(pRequestSense, "SCSI_AlignElements :",debug_file);
5605 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"%s: Request Sense[Inquiry]: %02X",
5606 "chs", ((unsigned char *) &pRequestSense)[0]);
5607 for (i = 1; i < sizeof(RequestSense_T); i++)
5608 DebugPrint(DEBUG_ERROR, SECTION_SCSI," %02X", ((unsigned char *) &pRequestSense)[i]);
5609 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"\n");
5614 switch(SenseHandler(DeviceFD, 0 , pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, (char *)pRequestSense))
5617 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_AlignElements : SENSE_IGNORE\n");
5621 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_AlignElements : SENSE_RETRY no %d\n", retry);
5624 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"SCSI_AlignElements : SENSE_ABORT\n");
5627 case SENSE_TAPE_NOT_UNLOADED:
5628 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"SCSI_AlignElements : Tape still loaded, eject failed\n");
5632 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_AlignElements : end %d\n", pRequestSense->SenseKey);
5633 return(pRequestSense->SenseKey);
5639 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_AlignElements : end %d\n", ret);
5643 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"SCSI_AlignElements :"
5644 "Retries exceeded = %d\n", retry);
5649 int SCSI_Move(int DeviceFD, unsigned char chm, int from, int to)
5651 RequestSense_T *pRequestSense;
5657 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### START SCSI_Move\n");
5659 if ((pRequestSense = (RequestSense_T *)malloc(sizeof(RequestSense_T))) == NULL)
5661 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"SCSI_Move : malloc failed\n");
5665 for (retry = 0; (ret != 0) && (retry < MAX_RETRIES); retry++)
5667 CDB[0] = SC_MOVE_MEDIUM;
5670 CDB[3] = chm; /* Address of CHM */
5678 ret = SCSI_Run(DeviceFD, Input, CDB, 12,
5679 NULL, 0, (char *)pRequestSense, sizeof(RequestSense_T));
5681 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Move : SCSI_Run = %d\n", ret);
5682 DecodeSense(pRequestSense, "SCSI_Move :",debug_file);
5686 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"%s: Request Sense[Inquiry]: %02X",
5687 "chs", ((unsigned char *) &pRequestSense)[0]);
5688 for (i = 1; i < sizeof(RequestSense_T); i++)
5689 DebugPrint(DEBUG_ERROR, SECTION_SCSI," %02X", ((unsigned char *) &pRequestSense)[i]);
5690 DebugPrint(DEBUG_INFO, SECTION_SCSI,"\n");
5695 switch(SenseHandler(DeviceFD, 0 , pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, (char *)pRequestSense))
5698 dbprintf(("SCSI_Move : SENSE_IGNORE\n"));
5702 dbprintf(("SCSI_Move : SENSE_RETRY no %d\n", retry));
5705 dbprintf(("SCSI_Move : SENSE_ABORT\n"));
5708 case SENSE_TAPE_NOT_UNLOADED:
5709 dbprintf(("SCSI_Move : Tape still loaded, eject failed\n"));
5713 dbprintf(("SCSI_Move : end %d\n", pRequestSense->SenseKey));
5714 return(pRequestSense->SenseKey);
5719 dbprintf(("SCSI_Move : end %d\n", ret));
5723 int SCSI_LoadUnload(int DeviceFD, RequestSense_T *pRequestSense, unsigned char byte1, unsigned char load)
5728 dbprintf(("##### START SCSI_LoadUnload\n"));
5730 CDB[0] = SC_COM_UNLOAD;
5738 ret = SCSI_Run(DeviceFD, Input, CDB, 6,
5740 (char *) pRequestSense,
5741 sizeof(RequestSense_T));
5745 dbprintf(("SCSI_Unload : failed %d\n", ret));
5752 int SCSI_TestUnitReady(int DeviceFD, RequestSense_T *pRequestSense)
5757 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### START SCSI_TestUnitReady\n");
5759 CDB[0] = SC_COM_TEST_UNIT_READY;
5766 ret = SCSI_ExecuteCommand(DeviceFD, Input, CDB, 6,
5768 (char *) pRequestSense,
5769 sizeof(RequestSense_T));
5772 * We got an error, so let the calling function handle this
5776 DebugPrint(DEBUG_INFO, SECTION_SCSI,"###### STOP SCSI_TestUnitReady (1)\n");
5781 * OK, no error condition
5782 * If no sense is set, the Unit is ready
5784 if (pRequestSense->ErrorCode == 0 && pRequestSense->SenseKey == 0)
5786 DebugPrint(DEBUG_INFO, SECTION_SCSI,"###### STOP SCSI_TestUnitReady (1)\n");
5793 DebugPrint(DEBUG_INFO, SECTION_SCSI,"###### STOP SCSI_TestUnitReady (0)\n");
5798 int SCSI_ModeSelect(int DeviceFD, char *buffer, unsigned char length, unsigned char save, unsigned char mode, unsigned char lun)
5801 RequestSense_T *pRequestSense;
5806 dbprintf(("##### START SCSI_ModeSelect\n"));
5808 dbprintf(("SCSI_ModeSelect start length = %d:\n", length));
5809 if ((pRequestSense = (RequestSense_T *)malloc(sizeof(RequestSense_T))) == NULL)
5811 dbprintf(("SCSI_ModeSelect : malloc failed\n"));
5816 if ((sendbuf = (char *)malloc(length + 4)) == NULL)
5818 dbprintf(("SCSI_ModeSelect : malloc failed\n"));
5819 free(pRequestSense);
5823 memset(sendbuf, 0 , length + 4);
5825 memcpy(&sendbuf[4], buffer, length);
5826 dump_hex(sendbuf, length+4, DEBUG_INFO, SECTION_SCSI);
5828 for (retry = 0; (ret != 0) && (retry < MAX_RETRIES); retry++)
5830 memset(pRequestSense, 0, sizeof(RequestSense_T));
5832 CDB[0] = SC_COM_MODE_SELECT;
5833 CDB[1] = ((lun << 5) & 0xF0) | ((mode << 4) & 0x10) | (save & 1);
5836 CDB[4] = length + 4;
5838 ret = SCSI_Run(DeviceFD, Output, CDB, 6,
5841 (char *) pRequestSense,
5842 sizeof(RequestSense_T));
5845 dbprintf(("SCSI_ModeSelect : ret %d\n", ret));
5846 free(pRequestSense);
5853 switch(SenseHandler(DeviceFD, 0, pRequestSense->SenseKey,
5854 pRequestSense->AdditionalSenseCode,
5855 pRequestSense->AdditionalSenseCodeQualifier,
5856 (char *)pRequestSense))
5859 dbprintf(("SCSI_ModeSelect : SENSE_IGNORE\n"));
5860 free(pRequestSense);
5865 dbprintf(("SCSI_ModeSelect : SENSE_RETRY no %d\n", retry));
5868 dbprintf(("SCSI_ModeSelect : end %d\n", pRequestSense->SenseKey));
5869 free(pRequestSense);
5871 return(pRequestSense->SenseKey);
5876 dbprintf(("SCSI_ModeSelect end: %d\n", ret));
5877 free(pRequestSense);
5884 int SCSI_ModeSense(int DeviceFD, char *buffer, u_char size, u_char byte1, u_char byte2)
5887 RequestSense_T *pRequestSense;
5891 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### START SCSI_ModeSense\n");
5893 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ModeSense start length = %d:\n", size);
5894 if ((pRequestSense = (RequestSense_T *)malloc(sizeof(RequestSense_T))) == NULL)
5896 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"SCSI_ModeSense : malloc failed\n");
5900 while (ret && retry < MAX_RETRIES)
5902 memset(pRequestSense, 0, sizeof(RequestSense_T));
5903 memset(buffer, 0, size);
5905 CDB[0] = SC_COM_MODE_SENSE;
5911 ret = SCSI_Run(DeviceFD, Input, CDB, 6,
5914 (char *) pRequestSense,
5915 sizeof(RequestSense_T));
5923 switch(SenseHandler(DeviceFD, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, (char *)pRequestSense))
5926 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ModeSense : SENSE_IGNORE\n");
5930 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ModeSense : SENSE_RETRY no %d\n", retry);
5933 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ModeSense : end %d\n", pRequestSense->SenseKey);
5934 return(pRequestSense->SenseKey);
5941 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ModeSense end: %d\n", ret);
5945 int SCSI_Inquiry(int DeviceFD, SCSIInquiry_T *buffer, u_char size)
5948 RequestSense_T *pRequestSense;
5953 DebugPrint(DEBUG_INFO, SECTION_SCSI, "##### START SCSI_Inquiry\n");
5955 DebugPrint(DEBUG_INFO, SECTION_SCSI, "SCSI_Inquiry start length = %d:\n", size);
5957 if ((pRequestSense = (RequestSense_T *)malloc(size)) == NULL)
5959 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"SCSI_Inquiry : malloc failed\n");
5963 while (retry > 0 && retry < MAX_RETRIES)
5965 memset(buffer, 0, size);
5966 CDB[0] = SC_COM_INQUIRY;
5973 ret = SCSI_ExecuteCommand(DeviceFD, Input, CDB, 6,
5976 (char *) pRequestSense,
5977 sizeof(RequestSense_T));
5980 DebugPrint(DEBUG_ERROR, SECTION_SCSI,"%s: Request Sense[Inquiry]: %02X",
5981 "chs", ((unsigned char *) pRequestSense)[0]);
5982 for (i = 1; i < sizeof(RequestSense_T); i++)
5983 DebugPrint(DEBUG_ERROR, SECTION_SCSI," %02X", ((unsigned char *) pRequestSense)[i]);
5984 DebugPrint(DEBUG_ERROR, SECTION_SCSI, "\n");
5985 DebugPrint(DEBUG_ERROR, SECTION_SCSI, "Inquiry end: %d\n", ret);
5990 switch(SenseHandler(DeviceFD, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, (char *)pRequestSense))
5993 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Inquiry : SENSE_IGNORE\n");
5997 DebugPrint(DEBUG_INFO, SECTION_SCSI, "SCSI_Inquiry : SENSE_RETRY no %d\n", retry);
6000 DebugPrint(DEBUG_ERROR, SECTION_SCSI, "SCSI_Inquiry : end %d\n", pRequestSense->SenseKey);
6001 return(pRequestSense->SenseKey);
6008 dump_hex((char *)buffer, size, DEBUG_INFO, SECTION_SCSI);
6009 DebugPrint(DEBUG_INFO, SECTION_SCSI, "SCSI_Inquiry : end %d\n", ret);
6014 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_Inquiry end: %d\n", ret);
6019 * Read the Element Status. If DescriptorSize != 0 then
6020 * allocate DescriptorSize * NoOfElements for the result from the
6021 * Read Element Status command.
6022 * If DescriptorSize == 0 than try to figure out how much space is needed
6024 * 1. do an read with an allocation size of 8
6025 * 2. from the result take the 'Byte Count of Descriptor Available'
6026 * 3. do again an Read Element Status with the result from 2.
6029 int SCSI_ReadElementStatus(int DeviceFD,
6032 unsigned char VolTag,
6039 int DataBufferLength;
6040 ElementStatusData_T *ElementStatusData;
6041 RequestSense_T *pRequestSense;
6045 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### START SCSI_ReadElementStatus\n");
6047 if ((pRequestSense = (RequestSense_T *)malloc(sizeof(RequestSense_T))) == NULL)
6049 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ReadElementStatus : malloc failed\n");
6050 ChgExit("SCSI_ReadElementStatus","malloc failed", FATAL);
6054 * How many elements, if <= 0 than exit with an fatal error
6056 if (NoOfElements <= 0)
6058 ChgExit("SCSI_ReadElementStatus","No of Elements passed are le 0",FATAL);
6061 VolTag = (VolTag << 4) & 0x10;
6063 lun = (lun << 5) & 0xe0;
6066 /* if DescriptorSize == 0
6067 * try to get the allocation length for the second call
6069 if (DescriptorSize == 0)
6073 *data = realloc(*data, 8);
6078 memset(*data, 0, 8);
6082 while (retry > 0 && retry < MAX_RETRIES)
6084 memset(pRequestSense, 0, sizeof(RequestSense_T) );
6086 CDB[0] = SC_COM_RES; /* READ ELEMENT STATUS */
6087 CDB[1] = VolTag | type | lun; /* Element Type Code , VolTag, LUN */
6088 MSB2(&CDB[2], StartAddress); /* Starting Element Address */
6089 MSB2(&CDB[4], NoOfElements); /* Number Of Element */
6090 CDB[6] = 0; /* Reserved */
6091 MSB3(&CDB[7],8); /* Allocation Length */
6092 CDB[10] = 0; /* Reserved */
6093 CDB[11] = 0; /* Control */
6095 ret = SCSI_Run(DeviceFD, Input, CDB, 12,
6097 (char *)pRequestSense, sizeof(RequestSense_T));
6100 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ReadElementStatus : (1) SCSI_Run %d\n", ret);
6103 DecodeSense(pRequestSense, "SCSI_ReadElementStatus :",debug_file);
6104 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP SCSI_ReadElementStatus (%d)\n",ret);
6109 switch(SenseHandler(DeviceFD, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, (char *)pRequestSense))
6112 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ModeSense : SENSE_IGNORE\n");
6116 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ModeSense : SENSE_RETRY no %d\n", retry);
6120 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ModeSense : end %d\n", pRequestSense->SenseKey);
6121 return(pRequestSense->SenseKey);
6133 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP SCSI_ReadElementStatus (%d)\n",ret);
6137 ElementStatusData = (ElementStatusData_T *)*data;
6138 DataBufferLength = V3(ElementStatusData->count);
6140 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ReadElementStatus: DataBufferLength %X, ret %d\n",DataBufferLength, ret);
6142 dump_hex(*data, 8, DEBUG_INFO, SECTION_ELEMENT);
6143 } else { /* DescriptorSize != 0 */
6144 DataBufferLength = NoOfElements * DescriptorSize;
6147 DataBufferLength = DataBufferLength + 8;
6148 *data = realloc(*data, DataBufferLength);
6149 memset(*data, 0, DataBufferLength);
6152 while (retry > 0 && retry < MAX_RETRIES)
6154 memset(pRequestSense, 0, sizeof(RequestSense_T) );
6156 CDB[0] = SC_COM_RES; /* READ ELEMENT STATUS */
6157 CDB[1] = VolTag | type | lun; /* Element Type Code, VolTag, LUN */
6158 MSB2(&CDB[2], StartAddress); /* Starting Element Address */
6159 MSB2(&CDB[4], NoOfElements); /* Number Of Element */
6160 CDB[6] = 0; /* Reserved */
6161 MSB3(&CDB[7],DataBufferLength); /* Allocation Length */
6162 CDB[10] = 0; /* Reserved */
6163 CDB[11] = 0; /* Control */
6165 ret = SCSI_Run(DeviceFD, Input, CDB, 12,
6166 *data, DataBufferLength,
6167 (char *)pRequestSense, sizeof(RequestSense_T));
6170 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ReadElementStatus : (2) SCSI_Run %d\n", ret);
6173 DecodeSense(pRequestSense, "SCSI_ReadElementStatus :",debug_file);
6174 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP SCSI_ReadElementStatus (%d)\n",ret);
6179 switch(SenseHandler(DeviceFD, 0, pRequestSense->SenseKey, pRequestSense->AdditionalSenseCode, pRequestSense->AdditionalSenseCodeQualifier, (char *)pRequestSense))
6182 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ModeSense : SENSE_IGNORE\n");
6186 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ModeSense : SENSE_RETRY no %d\n", retry);
6190 DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_ModeSense : end %d\n", pRequestSense->SenseKey);
6191 return(pRequestSense->SenseKey);
6204 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP SCSI_ReadElementStatus (%d)\n",ret);
6208 dump_hex(*data, DataBufferLength, DEBUG_INFO, SECTION_SCSI);
6209 DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP SCSI_ReadElementStatus (%d)\n",ret);
6213 printf_arglist_function2(void DebugPrint, int, level, int, section, char *, fmt)
6217 extern changer_t chg;
6218 int dlevel,dsection;
6225 sscanf(chg.debuglevel,"%d:%d", &dlevel, &dsection);
6231 arglist_start(argp, fmt);
6232 vsnprintf(buf, sizeof(buf), fmt, argp);
6233 if (dlevel >= level)
6235 if (section == dsection || dsection == 0)
6237 if (index(buf, '\n') != NULL && strlen(buf) > 1)
6239 dbprintf(("%ld:%s", (long)ti, buf));
6241 dbprintf(("%s", buf));