📄 mtxl.c
字号:
#endif dest++; } dest=0; /* null-terminate, sigh. */ }/* This #%!@# routine has more parameters than I can count! */unsigned char *SendElementStatusRequest(DEVICE_TYPE MediumChangerFD, RequestSense_T *RequestSense, Inquiry_T *inquiry_info, SCSI_Flags_T *flags, int ElementStart, int NumElements, int NumBytes ) { CDB_T CDB; boolean is_attached = false; unsigned char *DataBuffer; /* size of data... */#ifdef HAVE_GET_ID_LUN scsi_id_t *scsi_id;#endif if ((inquiry_info->MChngr) && (inquiry_info->PeripheralDeviceType != MEDIUM_CHANGER_TYPE)) { is_attached=true; } if (flags->no_attached) { /* override, sigh */ is_attached=false; } DataBuffer=(unsigned char *) xmalloc(NumBytes+1); slow_bzero((char *)RequestSense,sizeof(RequestSense_T));#ifdef HAVE_GET_ID_LUN scsi_id = SCSI_GetIDLun(MediumChangerFD);#endif CDB[0] = 0xB8; /* READ ELEMENT STATUS */ if (is_attached) { CDB[0] = 0xB4; /* whoops, READ_ELEMENT_STATUS_ATTACHED! */ }#ifdef HAVE_GET_ID_LUN CDB[1] = (scsi_id->lun << 5) | ((flags->no_barcodes) ? 0 : 0x10) | flags->elementtype; /* Lun + VolTag + Type code */ free(scsi_id);#else CDB[1] = ((flags->no_barcodes) ? 0 : 0x10) | flags->elementtype; /* Element Type Code = 0, VolTag = 1 */#endif CDB[2] = (ElementStart >> 8) & 0xff; /* Starting Element Address MSB */ CDB[3] = ElementStart & 0xff; /* Starting Element Address LSB */ CDB[4]= (NumElements >> 8) & 0xff; /* Number Of Elements MSB */ CDB[5]= NumElements & 0xff ; /* Number of elements LSB */ /* CDB[5]=127; */ /* test */#ifdef DEBUG fprintf(stderr,"CDB[5]=%d\n" , CDB[5]);#endif CDB[6] = 0; /* Reserved */ CDB[7]= (NumBytes >> 16) & 0xff; /* allocation length MSB */ CDB[8]= (NumBytes >> 8) & 0xff; CDB[9]= NumBytes & 0xff; /* allocation length LSB */ CDB[10] = 0; /* Reserved */ CDB[11] = 0; /* Control */#ifdef DEBUG_BARCODE { int i; fprintf(stderr,"CDB= "); for (i=0;i<12;i++) { fprintf(stderr,"%x ",CDB[i]); } fprintf(stderr,"\n"); fflush(stderr); }#endif if (SCSI_ExecuteCommand(MediumChangerFD, Input, &CDB, 12, DataBuffer,NumBytes, RequestSense) != 0){ /* okay, first see if we have sense key of 'illegal request', additional sense code of '24', additional sense qualfier of '0', and field in error of '4'. This means that we issued a request w/bar code reader and did not have one, thus must re-issue the request w/out barcode :-(. */ /* Okay, most autochangers and tape libraries set a sense key here if * they do not have a bar code reader. For some reason, the ADIC DAT * uses a different sense key? Let's retry w/o bar codes for *ALL* * sense keys, sigh sigh sigh. */ if ( RequestSense->SenseKey > 1 ) { /* we issued a code requesting bar codes, there is no bar code reader? */ /* clear out our sense buffer first... */ slow_bzero((char *)RequestSense,sizeof(RequestSense_T)); CDB[1] &= ~0x10; /* clear bar code flag! */#ifdef DEBUG_BARCODE { int i; fprintf(stderr,"CDB= "); for (i=0;i<12;i++) { fprintf(stderr,"%x ",CDB[i]); } fprintf(stderr,"\n"); fflush(stderr); }#endif if (SCSI_ExecuteCommand(MediumChangerFD, Input, &CDB, 12, DataBuffer, NumBytes, RequestSense) != 0){ free(DataBuffer); return NULL; } } else { free(DataBuffer); return NULL; } }#ifdef DEBUG_BARCODE /* print a bunch of extra debug data :-(. */ PrintRequestSense(RequestSense); /* see what it sez :-(. */ { int i; fprintf(stderr,"Data:"); for (i=0;i<40;i++) { fprint(stderr,"%02x ",DataBuffer[i]); } fprintf(stderr,"\n"); }#endif return DataBuffer; /* we succeeded! */}/******************* ParseElementStatus ***********************************//* This does the actual grunt work of parsing element status data. It fills * in appropriate pieces of its input data. It may be called multiple times * while we are gathering element status. */static void ParseElementStatus(int *EmptyStorageElementAddress, int *EmptyStorageElementCount, unsigned char *DataBuffer, ElementStatus_T *ElementStatus, ElementModeSense_T *mode_sense ) { unsigned char *DataPointer=DataBuffer; TransportElementDescriptor_T TEBuf; TransportElementDescriptor_T *TransportElementDescriptor; ElementStatusDataHeader_T *ElementStatusDataHeader; Element2StatusPage_T *ElementStatusPage; Element2StatusPage_T ESBuf; int ElementCount; int TransportElementDescriptorLength; int BytesAvailable; ElementStatusDataHeader = (ElementStatusDataHeader_T *) DataBuffer; ElementStatusDataHeader = (ElementStatusDataHeader_T *) DataPointer; DataPointer += sizeof(ElementStatusDataHeader_T); ElementCount = BigEndian16(ElementStatusDataHeader->NumberOfElementsAvailable);#ifdef DEBUG fprintf(stderr,"ElementCount=%d\n",ElementCount); fflush(stderr);#endif while (ElementCount > 0) {#ifdef DEBUG int got_element_num=0; fprintf(stderr,"Working on element # %d Element Count %d\n",got_element_num,ElementCount); got_element_num++;#endif memcpy(&ESBuf, DataPointer, sizeof(ElementStatusPage_T)); ElementStatusPage = &ESBuf; DataPointer += sizeof(ElementStatusPage_T); TransportElementDescriptorLength = BigEndian16(ElementStatusPage->ElementDescriptorLength); if (TransportElementDescriptorLength < sizeof(TransportElementDescriptorShort_T)) { /* Foo, Storage Element Descriptors can be 4 bytes?! */ if ( (ElementStatusPage->ElementTypeCode != MediumTransportElement && ElementStatusPage->ElementTypeCode != StorageElement && ElementStatusPage->ElementTypeCode != ImportExportElement ) || TransportElementDescriptorLength < 4) {#ifdef DEBUG fprintf(stderr,"boom! ElementTypeCode=%d\n",ElementStatusPage->ElementTypeCode);#endif FatalError("Transport Element Descriptor Length too short: %d\n",TransportElementDescriptorLength); } }#ifdef DEBUG fprintf(stderr,"Transport Element Descriptor Length=%d\n",TransportElementDescriptorLength);#endif BytesAvailable = BigEndian24(ElementStatusPage->ByteCountOfDescriptorDataAvailable); if (BytesAvailable <= 0) { ElementCount--; } while (BytesAvailable > 0) { /* TransportElementDescriptor = (TransportElementDescriptor_T *) DataPointer; */ memcpy(&TEBuf, DataPointer, (TransportElementDescriptorLength <= sizeof(TEBuf)) ? TransportElementDescriptorLength : sizeof(TEBuf)); TransportElementDescriptor = &TEBuf; DataPointer += TransportElementDescriptorLength; BytesAvailable -= TransportElementDescriptorLength; ElementCount--; switch (ElementStatusPage->ElementTypeCode) { case MediumTransportElement: ElementStatus->TransportElementAddress = BigEndian16(TransportElementDescriptor->ElementAddress);#ifdef DEBUG fprintf(stderr,"TransportElementAddress=%d\n",ElementStatus->TransportElementAddress); #endif break; /* we treat ImportExport elements as if they were normal * storage elements now, sigh... */ case ImportExportElement: ElementStatus->ImportExportCount++;#ifdef DEBUG fprintf(stderr,"ImportExportElement=%d\n",ElementStatus->StorageElementCount);#endif ElementStatus->StorageElementIsImportExport[ElementStatus->StorageElementCount] = 1; /* WARNING: DO *NOT* PUT A 'break' STATEMENT HERE, it is supposed * to run on into the case for a Storage Element! */ case StorageElement:#ifdef DEBUG fprintf(stderr,"StorageElementCount=%d ElementAddress = %d ",ElementStatus->StorageElementCount,BigEndian16(TransportElementDescriptor->ElementAddress));#endif ElementStatus->StorageElementAddress[ElementStatus->StorageElementCount] = BigEndian16(TransportElementDescriptor->ElementAddress); ElementStatus->StorageElementFull[ElementStatus->StorageElementCount] = TransportElementDescriptor->Full;#ifdef DEBUG fprintf(stderr,"TransportElement->Full = %d\n",TransportElementDescriptor->Full);#endif if (!TransportElementDescriptor->Full) { EmptyStorageElementAddress[(*EmptyStorageElementCount)++] = ElementStatus->StorageElementCount; /* slot idx. */ /* ElementStatus->StorageElementAddress[ElementStatus->StorageElementCount]; */ } if ( (TransportElementDescriptorLength > 11) && (ElementStatusPage->VolBits & E2_AVOLTAG)) { copy_barcode(TransportElementDescriptor->AlternateVolumeTag, ElementStatus->AlternateVolumeTag[ElementStatus->StorageElementCount]); } else { ElementStatus->AlternateVolumeTag[ElementStatus->StorageElementCount][0]=0; /* null string. */; } if ( (TransportElementDescriptorLength > 11) && (ElementStatusPage->VolBits & E2_PVOLTAG)) { copy_barcode(TransportElementDescriptor->PrimaryVolumeTag, ElementStatus->PrimaryVolumeTag[ElementStatus->StorageElementCount]); } else { ElementStatus->PrimaryVolumeTag[ElementStatus->StorageElementCount][0]=0; /* null string. */ } ElementStatus->StorageElementCount++; /* Note that the original mtx had no check here for buffer overflow, though some drives might mistakingly do one... */ if (ElementStatus->StorageElementCount > mode_sense->NumStorage) { fprintf(stderr,"Warning:Too Many Storage Elements Reported (expected %d, now have %d\n", mode_sense->NumStorage, ElementStatus->StorageElementCount); fflush(stderr); return; /* we're done :-(. */ } break; case DataTransferElement: /* tape drive not installed, go back to top of loop */ /* if (TransportElementDescriptor->Except) continue ; */ /* Note: This is for Exabyte tape libraries that improperly report that they have a 2nd tape drive when they don't. We could generalize this in an ideal world, but my attempt to do so failed with dual-drive Exabyte tape libraries that *DID* have the second drive. Sigh. */ /* No longer need this test due to code restructuring? */ /* if (TransportElementDescriptor->AdditionalSenseCode==0x83 && TransportElementDescriptor->AdditionalSenseCodeQualifier==0x04) continue; */ /* generalize it. Does it work? Let's try it! */ /* No, dammit, following does not work on dual-drive Exabyte 'cause if a tape is in the drive, it sets the AdditionalSense code to something (sigh). */ /* if (TransportElementDescriptor->AdditionalSenseCode!=0) continue; */ ElementStatus->DataTransferElementAddress[ElementStatus->DataTransferElementCount] = BigEndian16(TransportElementDescriptor->ElementAddress); ElementStatus->DataTransferElementFull[ElementStatus->DataTransferElementCount] = TransportElementDescriptor->Full; ElementStatus->DataTransferElementSourceStorageElementNumber[ElementStatus->DataTransferElementCount] = BigEndian16(TransportElementDescriptor ->SourceStorageElementAddress); if (ElementStatus->DataTransferElementCount >= mode_sense->NumDataTransfer) { FatalError("Too many Data Transfer Elements Reported\n"); } if (ElementStatusPage->VolBits & E2_PVOLTAG) { copy_barcode(TransportElementDescriptor->PrimaryVolumeTag, ElementStatus->DataTransferPrimaryVolumeTag[ElementStatus->DataTransferElementCount]); } else { ElementStatus->DataTransferPrimaryVolumeTag[ElementStatus->DataTransferElementCount][0]=0; /* null string */ } if (ElementStatusPage->VolBits & E2_AVOLTAG) { copy_barcode(TransportElementDescriptor->AlternateVolumeTag, ElementStatus->DataTransferAlternateVolumeTag[ElementStatus->DataTransferElementCount]); } else { ElementStatus->DataTransferAlternateVolumeTag[ElementStatus->DataTransferElementCount][0]=0; /* null string */ } ElementStatus->DataTransferElementCount++; /* 0 actually is a usable element address */ /* if (DataTransferElementAddress == 0) */ /* FatalError( */ /* "illegal Data Transfer Element Address %d reported\n", */ /* DataTransferElementAddress); */ break; default: FatalError("illegal Element Type Code %d reported\n", ElementStatusPage->ElementTypeCode); } } }}/********************* Real ReadElementStatus ********************* *//* * We no longer do the funky trick to figure out ALLOCATION_LENGTH. * Instead, we use the SCSI Generic command rather than SEND_SCSI_COMMAND * under Linux, which gets around the @#%@ 4k buffer size in Linux. * We still have the restriction that Linux cuts off the last two * bytes of the SENSE DATA (Q#@$%@#$^ Linux!). Which means that the * verbose widget won't work :-(. * We now look for that "attached" bit in the inquiry_info to see whether * to use READ_ELEMENT_ATTACHED or plain old READ_ELEMENT. In addition, we * look at the device type in the inquiry_info to see whether it is a media * changer or tape device, and if it's a media changer device, we ignore the * attached bit (one beta tester found an old 4-tape DAT changer that set * the attached bit for both the tape device AND the media changer device). */ElementStatus_T *ReadElementStatus(DEVICE_TYPE MediumChangerFD, RequestSense_T *RequestSense, Inquiry_T *inquiry_info, SCSI_Flags_T *flags) { ElementStatus_T *ElementStatus; unsigned char *DataBuffer; /* size of data... */ int EmptyStorageElementCount=0; int *EmptyStorageElementAddress; /* [MAX_STORAGE_ELEMENTS]; */ int empty_idx=0; int invalid_sources=0; boolean is_attached = false; int i,j; ElementModeSense_T *mode_sense = NULL; if ((inquiry_info->MChngr) && (inquiry_info->PeripheralDeviceType != MEDIUM_CHANGER_TYPE)) { is_attached=true; } if (flags->no_attached) { /* override, sigh */ is_attached=false; } if (!is_attached) { mode_sense=ReadAssignmentPage(MediumChangerFD); } if (!mode_sense) { mode_sense=(ElementModeSense_T *) xmalloc(sizeof(ElementModeSense_T)); mode_sense->NumMediumTransport=MAX_TRANSPORT_ELEMENTS; mode_sense->NumStorage=MAX_STORAGE_ELEMENTS; mode_sense->NumDataTransfer=MAX_TRANSFER_ELEMENTS; mode_sense->MaxReadElementStatusData= (sizeof(ElementStatusDataHeader_T) + 3 * sizeof(ElementStatusPage_T) + (MAX_STORAGE_ELEMENTS+MAX_TRANSFER_ELEMENTS+MAX_TRANSPORT_ELEMENTS) * sizeof(TransportElementDescriptor_T)); /* don't care about the others anyhow at the moment... */ } ElementStatus=AllocateElementData(mode_sense); /* Now to initialize it (sigh). */ ElementStatus->StorageElementCount = 0; ElementStatus->DataTransferElementCount=0; /* first, allocate some empty storage stuff: Note that we pass this * down to ParseElementStatus (sigh!) */ EmptyStorageElementAddress=(int *)xzmalloc((mode_sense->NumStorage+1)*sizeof(int)); for (i=0;i<mode_sense->NumStorage;i++) { EmptyStorageElementAddress[i]=-1; } /* Okay, now to send some requests for the various types of stuff: */ /* -----------STORAGE ELEMENTS---------------- */ /* Let's start with storage elements: */ for (i=0;i<mode_sense->NumDataTransfer;i++) { /* initialize them to an illegal # so that we can fix later... */ ElementStatus->DataTransferElementSourceStorageElementNumber[i] = -1; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -