/*++ Copyright (c) 1990 Microsoft Corporation Module Name: tapeapi.c Abstract: This module implements Win32 Tape APIs Author: Steve Wood (stevewo) 26-Mar-1992 Lori Brown (Maynard) Revision History: --*/ #include "basedll.h" #pragma hdrstop #include DWORD BasepDoTapeOperation( IN HANDLE TapeDevice, IN ULONG IoControlCode, IN PVOID InputBuffer, IN ULONG InputBufferLength, OUT PVOID OutputBuffer, IN ULONG OutputBufferLength ); DWORD BasepDoTapeOperation( IN HANDLE TapeDevice, IN ULONG IoControlCode, IN PVOID InputBuffer, IN ULONG InputBufferLength, OUT PVOID OutputBuffer, IN ULONG OutputBufferLength ) { HANDLE NotificationEvent; NTSTATUS Status; IO_STATUS_BLOCK IoStatus; PIO_STATUS_BLOCK IoStatusBlock; IoStatusBlock = &IoStatus; NotificationEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if (NotificationEvent == NULL) { return GetLastError(); } Status = NtDeviceIoControlFile( TapeDevice, NotificationEvent, NULL, NULL, IoStatusBlock, IoControlCode, InputBuffer, InputBufferLength, OutputBuffer, OutputBufferLength ); if (Status == STATUS_PENDING) { WaitForSingleObject(NotificationEvent, INFINITE); Status = IoStatus.Status; } CloseHandle(NotificationEvent); if (!NT_SUCCESS( Status )) { return BaseSetLastNTError( Status ); } else { return NO_ERROR; } } DWORD WINAPI SetTapePosition( HANDLE hDevice, DWORD dwPositionMethod, DWORD dwPartition, DWORD dwOffsetLow, DWORD dwOffsetHigh, BOOL bImmediate ) /*++ Routine Description: This API is used to set the tape position. Arguments: hDevice - Handle to the device on which to set the tape position. dwPositionMethod - Type of positioning to perform. This parameter can have one of the following values: TAPE_REWIND - Position the tape to beginning-of-tape or to beginning-of-partition if a multiple partition mode is in effect (ref: CreateTapePartition API). The parameters dwPartition, dwOffsetHigh, and dwOffsetLow are ignored. TAPE_ABSOLUTE_BLOCK - Position the tape to the device specific block address specified by dwOffsetHigh/dwOffsetLow. The dwPartition parameter is ignored. TAPE_LOGICAL_BLOCK - Position the tape to the logical block address specified by dwOffsetHigh/dwOffsetLow. If a multiple partition mode is in effect (ref: CreateTapePartition API), then the tape is positioned to the specified logical block address in the partition specified by dwPartition; otherwise, the dwPartition parameter value must be 0. TAPE_SPACE_END_OF_DATA - Position the tape to the end-of-data on tape or to the end-of-data in the current partition if a multiple partition mode is in effect (ref: CreateTapePartition API). The parameters dwPartition, dwOffsetHigh, and dwOffsetLow are ignored. TAPE_SPACE_RELATIVE_BLOCKS - Position forward or reverse the number of blocks specified by dwOffsetHigh/dwOffsetLow. The dwPartition parameter is ignored. TAPE_SPACE_FILEMARKS - Position forward or reverse the number of filemarks specified by dwOffsetHigh/dwOffsetLow. The dwPartition parameter is ignored. TAPE_SPACE_SEQUENTIAL_FMKS - Position forward or reverse to the next occurrence, if any, of the consecutive number of filemarks specified by dwOffsetHigh/dwOffsetLow. The dwPartition parameter is ignored. TAPE_SPACE_SETMARKS - Position forward or reverse the number of setmarks specified by dwOffsetHigh/dwOffsetLow. The dwPartition parameter is ignored. TAPE_SPACE_SEQUENTIAL_SMKS - Position forward or reverse to the next occurrence, if any, of the consecutive number of setmarks specified by dwOffsetHigh/dwOffsetLow. The dwPartition parameter is ignored. Note that a drive/tape may not support all dwPositionMethod values: an "unsupported" error indication is returned if the dwPositionMethod is one that is not flagged as supported in the drive's features bits (ref: GetTapeParameters API). dwPartition - The partition number for the position operation specified by dwPositionMethod (if not ignored). A partition number value of 0 selects the current partition for the position operation. Partitions are numbered logically from 1 to N: the first partition of the tape is partition number 1, the next is partition number 2, etc. However, a partition number does not imply a physical/linear position on tape -- partition number 1 on tape may not be at BOT. This parameter must be set to 0 if a multiple partition mode is not in effect (ref: CreateTapePartition API). dwOffsetHigh/dwOffsetLow - The block address or count for the position operation specified by dwPositionMethod. When the offset specifies the number of blocks, filemarks, or setmarks to position over, a positive value N in the offset shall cause forward positioning over N blocks, filemarks, or setmarks, ending on the end-of-partition/tape side of a block, filemark, or setmark. A zero value in the offset shall cause no change of position. A negative value N in the offset shall cause reverse positioning (toward beginning-of-partition/tape) over N blocks, filemarks, or setmarks, ending on the beginning-of-partition side of a block, filemark, or setmark. bImmediate - Return immediately without waiting for the operation to complete. Note that a drive/tape may not support the bImmediate option for either some or all dwPositionMethod values: an "unsupported" error indication is returned if the bImmediate dwPositionMethod is one that is not flagged as supported in the drive's features bits (ref: GetTapeParameters API). Return Value: If the function is successful, the return value is NO_ERROR. Otherwise, it is a Win32 API error code. --*/ { TAPE_SET_POSITION TapeSetPosition; TapeSetPosition.Method = dwPositionMethod; TapeSetPosition.Partition = dwPartition; TapeSetPosition.Offset.LowPart = dwOffsetLow; TapeSetPosition.Offset.HighPart = dwOffsetHigh; TapeSetPosition.Immediate = (BOOLEAN)bImmediate; return BasepDoTapeOperation( hDevice, IOCTL_TAPE_SET_POSITION, &TapeSetPosition, sizeof( TapeSetPosition ), NULL, 0 ); } DWORD WINAPI GetTapePosition( HANDLE hDevice, DWORD dwPositionType, LPDWORD lpdwPartition, LPDWORD lpdwOffsetLow, LPDWORD lpdwOffsetHigh ) /*++ Routine Description: This API is used to get the tape position. Arguments: hDevice - Handle to the device on which to get the tape position. dwPositionType - Type of position to return. This parameter can have one of the following values: TAPE_ABSOLUTE_POSITION - Return a device specific block address to the LARGE_INTEGER pointed to by lpliOffset. The DWORD pointed to by the lpdwPartition parameter is set to 0. TAPE_LOGICAL_POSITION - Return a logical block address to the LARGE_INTEGER pointed to by lpliOffset. The DWORD pointed to by the lpdwPartition parameter is set to 0 if a multiple partition mode is not in effect; otherwise, it is set to the partition number of the currently selected partition (ref: CreateTapePartition API). Logical block addresses are 0 based -- 0 is a valid logical block address. A logical block address is a relative reference point (ref: logical positioning whitepaper). lpdwPartition - Pointer to a DWORD that receives the appropriate return value for the dwPositionType values explained above. lpliOffset - Pointer to a LARGE_INTEGER that receives the appropriate return value for the dwPositionType values explained above. Return Value: If the function is successful, the return value is NO_ERROR. Otherwise, it is a Win32 API error code. --*/ { TAPE_GET_POSITION TapeGetPosition; DWORD rc; TapeGetPosition.Type = dwPositionType; rc = BasepDoTapeOperation( hDevice, IOCTL_TAPE_GET_POSITION, &TapeGetPosition, sizeof( TapeGetPosition ), &TapeGetPosition, sizeof( TapeGetPosition ) ); if (rc == NO_ERROR) { *lpdwPartition = TapeGetPosition.Partition; *lpdwOffsetLow = TapeGetPosition.Offset.LowPart; *lpdwOffsetHigh = TapeGetPosition.Offset.HighPart; } else { *lpdwPartition = 0; *lpdwOffsetLow = 0; *lpdwOffsetHigh = 0; } return rc; } DWORD WINAPI PrepareTape( HANDLE hDevice, DWORD dwOperation, BOOL bImmediate ) /*++ Routine Description: This API is used to prepare the tape. Arguments: hDevice - Handle to the device on which to prepare the tape. dwOperation - Type of tape preparation to perform. This parameter can have one of the following values: TAPE_LOAD - Load the tape and position the tape to beginning-of-medium. TAPE_UNLOAD - Position the tape to beginning-of-medium for removal from the device. Following a successful unload operation, the device shall return an error for all subsequent medium-access commands until a load operation is successfully completed. TAPE_TENSION - Tension the tape in the device as required. The implementation of this operation is device specific. TAPE_LOCK - Disable the removal of the tape from the device. TAPE_UNLOCK - Enable the removal of the tape from the device. TAPE_FORMAT - Format media in tape device. bImmediate - Return immediately without waiting for operation to complete. Return Value: If the function is successful, the return value is NO_ERROR. Otherwise, it is a Win32 API error code. --*/ { TAPE_PREPARE TapePrepare; TapePrepare.Operation = dwOperation; TapePrepare.Immediate = (BOOLEAN)bImmediate; return BasepDoTapeOperation( hDevice, IOCTL_TAPE_PREPARE, &TapePrepare, sizeof( TapePrepare ), NULL, 0 ); } DWORD WINAPI EraseTape( HANDLE hDevice, DWORD dwEraseType, BOOL bImmediate ) /*++ Routine Description: This API is used to erase the tape partition. Arguments: hDevice - Handle to the device on which to erase the tape partition. dwEraseType - Type of erase to perform. This parameter can have one of the following values: TAPE_ERASE_SHORT - Write an erase gap or end-of-recorded data marker beginning at the current position. TAPE_ERASE_LONG - Erase all remaining media in the current partition beginning at the current position. bImmediate - Return immediately without waiting for operation to complete. Return Value: If the function is successful, the return value is NO_ERROR. Otherwise, it is a Win32 API error code. --*/ { TAPE_ERASE TapeErase; TapeErase.Type = dwEraseType; TapeErase.Immediate = (BOOLEAN)bImmediate; return BasepDoTapeOperation( hDevice, IOCTL_TAPE_ERASE, &TapeErase, sizeof( TapeErase ), NULL, 0 ); } DWORD WINAPI CreateTapePartition( HANDLE hDevice, DWORD dwPartitionMethod, DWORD dwCount, DWORD dwSize ) /*++ Routine Description: This API is used to create partitions. Arguments: hDevice - Handle to the device on which to create partitions. dwPartitionMethod - Type of partitioning to perform. Creating partitions causes the tape to be reformatted. All previous information recorded on the tape is destroyed. This parameter can have one of the following values: TAPE_FIXED_PARTITIONS - Partition the tape based on the device's fixed definition of partitions. The dwCount and dwSize parameters are ignored. TAPE_SELECT_PARTITIONS - Partition the tape into the number of partitions specified by dwCount using the partition sizes defined by the device. The dwSize parameter is ignored. TAPE_INITIATOR_PARTITIONS - Partition the tape into the number of partitions specified by dwCount using the partition size specified by dwSize for all but the last partition. The size of the last partition is the remainder of the tape. dwCount - Number of partitions to create. The maximum number of partitions a device can create is returned by GetTapeParameters. dwSize - Partition size in megabytes. The maximum capacity of a tape is returned by GetTapeParameters. Return Value: If the function is successful, the return value is NO_ERROR. Otherwise, it is a Win32 API error code. --*/ { TAPE_CREATE_PARTITION TapeCreatePartition; TapeCreatePartition.Method = dwPartitionMethod; TapeCreatePartition.Count = dwCount; TapeCreatePartition.Size = dwSize; return BasepDoTapeOperation( hDevice, IOCTL_TAPE_CREATE_PARTITION, &TapeCreatePartition, sizeof( TapeCreatePartition ), NULL, 0 ); } DWORD WINAPI WriteTapemark( HANDLE hDevice, DWORD dwTapemarkType, DWORD dwTapemarkCount, BOOL bImmediate ) /*++ Routine Description: This API is used to write tapemarks. Arguments: hDevice - Handle to the device on which to write the tapemarks. dwTapemarkType - Type of tapemarks to write. This parameter can have one of the following values: TAPE_SETMARKS - Write the number of setmarks specified by dwTapemarkCount to the tape. A setmark is a special recorded element containing no user data. A setmark provides a segmentation scheme hierarchically superior to filemarks. TAPE_FILEMARKS - Write the number of filemarks specified by dwTapemarkCount to the tape. A filemark is a special recorded element containing no user data. TAPE_SHORT_FILEMARKS - Write the number of short filemarks specified by dwTapemarkCount to the tape. A short filemark contains a short erase gap that does not allow a write operation to be performed. The short filemark cannot be overwritten except when the write operation is performed from the beginning-of-partition or from a previous long filemark. TAPE_LONG_FILEMARKS - Write the number of long filemarks specified by dwTapemarkCount to the tape. A long filemark includes a long erase gap. This gap allows the initiator to position on the beginning-of-partition side of the filemark, in the erase gap, and append data with the write operation. This causes the long filemark and any data following the long filemark to be erased. dwTapemarkCount - The number of tapemarks to write. bImmediate - Return immediately without waiting for operation to complete. Return Value: If the function is successful, the return value is NO_ERROR. Otherwise, it is a Win32 API error code. --*/ { TAPE_WRITE_MARKS TapeWriteMarks; TapeWriteMarks.Type = dwTapemarkType; TapeWriteMarks.Count = dwTapemarkCount; TapeWriteMarks.Immediate = (BOOLEAN)bImmediate; return BasepDoTapeOperation( hDevice, IOCTL_TAPE_WRITE_MARKS, &TapeWriteMarks, sizeof( TapeWriteMarks ), NULL, 0 ); } DWORD WINAPI GetTapeParameters( HANDLE hDevice, DWORD dwOperation, LPDWORD lpdwSize, LPVOID lpTapeInformation ) /*++ Routine Description: This API is used to get information about a tape device. Arguments: hDevice - Handle to the device on which to get the information. dwOperation - Type of information to get. This parameter can have one of the following values: GET_TAPE_MEDIA_INFORMATION - Return the media specific information in lpTapeInformation. GET_TAPE_DRIVE_INFORMATION - Return the device specific information in lpTapeInformation. lpdwSize - Pointer to a DWORD containing the size of the buffer pointed to by lpTapeInformation. If the buffer is too small, this parameter returns with the required size in bytes. lpTapeInformation - Pointer to a buffer to receive the information. The structure returned in the buffer is determined by dwOperation. For GET_TAPE_MEDIA_INFORMATION, lpTapeInformation returns the following structure: LARGE_INTEGER Capacity - The maximum tape capacity in bytes. LARGE_INTEGER Remaining - The remaining tape capacity in bytes. DWORD BlockSize - The size of a fixed-length logical block in bytes. A block size of 0 indicates variable-length block mode, where the length of a block is set by the write operation. The default fixed-block size and the range of valid block sizes are returned by GetTapeParameters. DWORD PartitionCount - Number of partitions on the tape. If only one partition is supported by the device, this parameter is set to 0. BOOLEAN WriteProtected - Indicates if the tape is write protected: 0 is write enabled, 1 is write protected. For GET_TAPE_DRIVE_INFORMATION, lpTapeInformation returns the following structure: BOOLEAN ECC - Indicates if hardware error correction is enabled or disabled: 0 is disabled, 1 is enabled. BOOLEAN Compression - Indicates if hardware data compression is enabled or disabled: 0 is disabled, 1 is enabled. BOOLEAN DataPadding - Indicates if data padding is disabled or enabled: 0 is disabled, 1 is enabled. BOOLEAN ReportSetmarks - Indicates if reporting setmarks is enabled or disabled: 0 is disabled, 1 is enabled. DWORD DefaultBlockSize - Returns the default fixed-block size for the device. DWORD MaximumBlockSize - Returns the maximum block size for the device. DWORD MinimumBlockSize - Returns the minimum block size for the device. DWORD MaximumPartitionCount - Returns the maximum number of partitions the device can create. DWORD FeaturesLow - The lower 32 bits of the device features flag. DWORD FeaturesHigh - The upper 32 bits of the device features flag. The device features flag represents the operations a device supports by returning a value of 1 in the appropriate bit for each feature supported. This parameter can have one or more of the following bit values set in the lower 32 bits: TAPE_DRIVE_FIXED - Supports creating fixed data partitions. TAPE_DRIVE_SELECT - Supports creating select data partitions. TAPE_DRIVE_INITIATOR - Supports creating initiator-defined partitions. TAPE_DRIVE_ERASE_SHORT - Supports short erase operation. TAPE_DRIVE_ERASE_LONG - Supports long erase operation. TAPE_DRIVE_ERASE_BOP_ONLY - Supports erase operation from the beginning-of-partition only. TAPE_DRIVE_TAPE_CAPACITY - Supports returning the maximum capacity of the tape. TAPE_DRIVE_TAPE_REMAINING - Supports returning the remaining capacity of the tape. TAPE_DRIVE_FIXED_BLOCK - Supports fixed-length block mode. TAPE_DRIVE_VARIABLE_BLOCK - Supports variable-length block mode. TAPE_DRIVE_WRITE_PROTECT - Supports returning if the tape is write enabled or write protected. TAPE_DRIVE_ECC - Supports hardware error correction. TAPE_DRIVE_COMPRESSION - Supports hardware data compression. TAPE_DRIVE_PADDING - Supports data padding. TAPE_DRIVE_REPORT_SMKS - Supports reporting setmarks. TAPE_DRIVE_GET_ABSOLUTE_BLK - Supports returning the current device specific block address. TAPE_DRIVE_GET_LOGICAL_BLK - Supports returning the current logical block address (and logical tape partition). This parameter can have one or more of the following bit values set in the upper 32 bits: TAPE_DRIVE_LOAD_UNLOAD - Supports enabling and disabling the device for further operations. TAPE_DRIVE_TENSION - Supports tensioning the tape. TAPE_DRIVE_LOCK_UNLOCK - Supports enabling and disabling removal of the tape from the device. TAPE_DRIVE_SET_BLOCK_SIZE - Supports setting the size of a fixed-length logical block or setting variable-length block mode. TAPE_DRIVE_SET_ECC - Supports enabling and disabling hardware error correction. TAPE_DRIVE_SET_COMPRESSION - Supports enabling and disabling hardware data compression. TAPE_DRIVE_SET_PADDING - Supports enabling and disabling data padding. TAPE_DRIVE_SET_REPORT_SMKS - Supports enabling and disabling reporting of setmarks. TAPE_DRIVE_ABSOLUTE_BLK - Supports positioning to a device specific block address. TAPE_DRIVE_ABS_BLK_IMMED - Supports immediate positioning to a device specific block address. TAPE_DRIVE_LOGICAL_BLK - Supports positioning to a logical block address in a partition. TAPE_DRIVE_LOG_BLK_IMMED - Supports immediate positioning to a logical block address in a partition. TAPE_DRIVE_END_OF_DATA - Supports positioning to the end-of-data in a partition. TAPE_DRIVE_RELATIVE_BLKS - Supports positioning forward (or reverse) a specified number of blocks. TAPE_DRIVE_FILEMARKS - Supports positioning forward (or reverse) a specified number of filemarks. TAPE_DRIVE_SEQUENTIAL_FMKS - Supports positioning forward (or reverse) to the first occurrence of a specified number of consecutive filemarks. TAPE_DRIVE_SETMARKS - Supports positioning forward (or reverse) a specified number of setmarks. TAPE_DRIVE_SEQUENTIAL_SMKS - Supports positioning forward (or reverse) to the first occurrence of a specified number of consecutive setmarks. TAPE_DRIVE_REVERSE_POSITION - Supports positioning over blocks, filemarks, or setmarks in the reverse direction. TAPE_DRIVE_WRITE_SETMARKS - Supports writing setmarks. TAPE_DRIVE_WRITE_FILEMARKS - Supports writing filemarks. TAPE_DRIVE_WRITE_SHORT_FMKS - Supports writing short filemarks. TAPE_DRIVE_WRITE_LONG_FMKS - Supports writing long filemarks. Return Value: If the function is successful, the return value is NO_ERROR. Otherwise, it is a Win32 API error code. --*/ { DWORD rc; switch (dwOperation) { case GET_TAPE_MEDIA_INFORMATION: if (*lpdwSize < sizeof(TAPE_GET_MEDIA_PARAMETERS)) { *lpdwSize = sizeof(TAPE_GET_MEDIA_PARAMETERS); rc = ERROR_MORE_DATA ; } else { rc = BasepDoTapeOperation( hDevice, IOCTL_TAPE_GET_MEDIA_PARAMS, NULL, 0, lpTapeInformation, sizeof( TAPE_GET_MEDIA_PARAMETERS ) ); } break; case GET_TAPE_DRIVE_INFORMATION: if (*lpdwSize < sizeof(TAPE_GET_DRIVE_PARAMETERS)) { *lpdwSize = sizeof(TAPE_GET_DRIVE_PARAMETERS); rc = ERROR_MORE_DATA ; } else { rc = BasepDoTapeOperation( hDevice, IOCTL_TAPE_GET_DRIVE_PARAMS, NULL, 0, lpTapeInformation, sizeof( TAPE_GET_DRIVE_PARAMETERS ) ); } break; default: rc = ERROR_INVALID_FUNCTION; break; } return rc; } DWORD WINAPI SetTapeParameters( HANDLE hDevice, DWORD dwOperation, LPVOID lpTapeInformation ) /*++ Routine Description: This API is used to set information about a tape device. Arguments: hDevice - Handle to the device on which to set the information. dwOperation - Type of information to set. This parameter can have one of the following values: SET_TAPE_MEDIA_INFORMATION - Set the media specific information specified in lpTapeInformation. SET_TAPE_DRIVE_INFORMATION - Set the device specific information specified in lpTapeInformation. lpTapeInformation - Pointer to a buffer containing the information to set. The structure returned in the buffer is determined by dwOperation. For SET_TAPE_MEDIA_INFORMATION, lpTapeInformation contains the following structure: DWORD BlockSize - The size of a fixed-length logical block in bytes. A block size of 0 indicates variable-length block mode, where the length of a block is set by the write operation. The default fixed-block size and the range of valid block sizes are returned by GetTapeParameters. For SET_TAPE_DRIVE_INFORMATION, lpTapeInformation contains the following structure: BOOLEAN ECC - Enables or disables hardware error correction: 0 is disabled, 1 is enabled. BOOLEAN Compression - Enables or disables hardware data compression: 0 is disabled, 1 is enabled. BOOLEAN DataPadding - Enables or disables data padding: 0 is disabled, 1 is enabled. BOOLEAN ReportSetmarks - Enables or disables reporting of setmarks: 0 is disabled, 1 is enabled. Return Value: If the function is successful, the return value is NO_ERROR. Otherwise, it is a Win32 API error code. --*/ { DWORD rc; switch (dwOperation) { case SET_TAPE_MEDIA_INFORMATION: rc = BasepDoTapeOperation( hDevice, IOCTL_TAPE_SET_MEDIA_PARAMS, lpTapeInformation, sizeof( TAPE_SET_MEDIA_PARAMETERS ), NULL, 0 ); break; case SET_TAPE_DRIVE_INFORMATION: rc = BasepDoTapeOperation( hDevice, IOCTL_TAPE_SET_DRIVE_PARAMS, lpTapeInformation, sizeof( TAPE_SET_DRIVE_PARAMETERS ), NULL, 0 ); break; default: rc = ERROR_INVALID_FUNCTION; break; } return rc; } DWORD WINAPI GetTapeStatus( HANDLE hDevice ) /*++ Routine Description: This API is used to get the status of a tape device. Arguments: hDevice - Handle to the device on which to get the status. Return Value: If the device is ready to accept an appropriate medium-access command without returning an error, the return value is NO_ERROR. Otherwise, it is a Win32 API error code. --*/ { return BasepDoTapeOperation( hDevice, IOCTL_TAPE_GET_STATUS, NULL, 0, NULL, 0 ); }