NT4/private/ntos/dd/qic117/mtaccess.c
2020-09-30 17:12:29 +02:00

943 lines
26 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1993 - Colorado Memory Systems, Inc.
All Rights Reserved
Module Name:
mtaccess.c
Abstract:
interface functions to lower level driver.
Revision History:
--*/
//
// include files
//
#include <ntddk.h>
#include <ntddtape.h>
#include "common.h"
#include "q117.h"
#include "protos.h"
#define FCT_ID 0x010e
#define PAGES_TO_SECTORS(pages) (((pages)*PAGE_SIZE)/BYTES_PER_SECTOR)
#define MIN(a,b) ((a)>(b)?(b):(a))
char *q117GetErrorString(dStatus stat);
dStatus
q117ReqIO(
IN PIO_REQUEST IoRequest,
IN PSEGMENT_BUFFER BufferInfo,
IN PIO_COMPLETION_ROUTINE CompletionRoutine,
IN PVOID CompletionContext,
IN PQ117_CONTEXT Context
)
/*++
Routine Description:
Form an IRP to send to the lower level driver, and send it.
For MIPS, allocate sub-requests and break the request into
smaller chunks to allow for the 4K DMA limitation of the MIPS
box.
Arguments:
IoRequest - Original request
BufferInfo - If a DMA is involved, this contains information about the
associated memory for DMA.
Context - Context of the driver.
Return Value:
--*/
{
PIO_STACK_LOCATION irpStack;
PIRP irp;
#ifdef BUFFER_SPLIT
BOOLEAN secondary = FALSE;
PVOID address;
PIO_REQUEST subRequest;
IO_REQUEST requestCopy;
PKEVENT pevent;
ULONG mask;
ULONG bufferSize;
ULONG numberOfPagesInTransfer;
BOOLEAN needToSplit;
ULONG sectorsToTransfer;
ULONG maxSplits;
#endif
CheckedDump(QIC117SHOWKDI,("ReqIO called (%x)\n", IoRequest->x.adi_hdr.driver_cmd));
IoRequest->BufferInfo = BufferInfo;
#ifdef BUFFER_SPLIT
needToSplit = FALSE;
if (BufferInfo) {
if (IoRequest->x.adi_hdr.driver_cmd != CMD_FORMAT) {
bufferSize = IoRequest->x.ioDeviceIO.number * BYTES_PER_SECTOR;
} else {
//
// use 4K until frb defines something else
//
bufferSize = 4 * BYTES_PER_SECTOR;
}
numberOfPagesInTransfer = ADDRESS_AND_SIZE_TO_SPAN_PAGES(
IoRequest->x.adi_hdr.cmd_buffer_ptr,
bufferSize);
if ( numberOfPagesInTransfer >
Context->AdapterInfo->NumberOfMapRegisters ) {
needToSplit = TRUE;
maxSplits =
(numberOfPagesInTransfer /
Context->AdapterInfo->NumberOfMapRegisters) + 1;
}
}
#endif
#if DBG
if (BufferInfo) {
//
// Check to make sure the buffer information is for the data pointer
// we recieved.
// If not, then there is a real problem with the calling function.
// We need to check this so we don't page fault the system when a bug
// occurs.
//
if ((ULONG)IoRequest->x.adi_hdr.cmd_buffer_ptr < (ULONG)BufferInfo->logical ||
((ULONG)IoRequest->x.adi_hdr.cmd_buffer_ptr + bufferSize) >
((ULONG)BufferInfo->logical + BYTES_PER_SEGMENT) ) {
CheckedDump(QIC117DBGP,("Buffer pointer out of range\n"));
return ERROR_ENCODE(ERR_PROGRAM_FAILURE, FCT_ID, 1);
}
}
#endif
#ifdef BUFFER_SPLIT
//
// For MIPS we must split the request into 4K DMA requests because
// the MIPS will not transfer more than 4K at a time.
//
if (BufferInfo && IoRequest->x.adi_hdr.driver_cmd != CMD_FORMAT && needToSplit) {
address = IoRequest->x.adi_hdr.cmd_buffer_ptr;
//
// Split request into chunks
//
subRequest = ExAllocatePool(NonPagedPool,
sizeof(*IoRequest)*maxSplits);
CheckedDump(QIC117SHOWKDI,("q117ReqIO: Allocating %d subreqs\n", maxSplits));
IoRequest->Next = subRequest;
IoRequest->x.adi_hdr.status = ERROR_ENCODE(ERR_SPLIT_REQUESTS, FCT_ID, 1);
requestCopy = *IoRequest;
#if DBG
CheckedDump(QIC117SHOWTD,("*************************", requestCopy.x.ioDeviceIO.starting_sector ));
CheckedDump(QIC117SHOWTD,("IoRequest->x.ioDeviceIO.starting_sector %x\n", requestCopy.x.ioDeviceIO.starting_sector ));
CheckedDump(QIC117SHOWTD,("IoRequest->x.ioDeviceIO.number %x\n", requestCopy.x.ioDeviceIO.number ));
CheckedDump(QIC117SHOWTD,("IoRequest->x.adi_hdr.cmd_buffer_ptr %x\n", requestCopy.x.adi_hdr.cmd_buffer_ptr ));
CheckedDump(QIC117SHOWTD,("IoRequest->x.ioDeviceIO.bsm %x\n", requestCopy.x.ioDeviceIO.bsm ));
CheckedDump(QIC117SHOWTD,("IoRequest->x.ioDeviceIO.crc %x\n", requestCopy.x.ioDeviceIO.crc ));
CheckedDump(QIC117SHOWTD,("IoRequest->x.ioDeviceIO.retrys %x\n", requestCopy.x.ioDeviceIO.retrys ));
CheckedDump(QIC117SHOWTD,("IoRequest->x.adi_hdr.driver_cmd %x\n\n", requestCopy.x.adi_hdr.driver_cmd ));
#endif
while (requestCopy.x.ioDeviceIO.number) {
//
// Make a copy of the current request
//
*subRequest = requestCopy;
//
// there aren't enough map registers to handle the whole
// transfer so cap the transfer at the number of map registers
// we have
//
sectorsToTransfer =
PAGES_TO_SECTORS(Context->AdapterInfo->NumberOfMapRegisters);
//
// Perform the lesser of the two for this request
//
subRequest->x.ioDeviceIO.number = (UCHAR)
MIN(sectorsToTransfer, (ULONG)subRequest->x.ioDeviceIO.number);
CheckedDump(QIC117SHOWTD,("Split at %d sectors\n", subRequest->x.ioDeviceIO.number));
//
// Adjust the current request to be the remainder of request
//
(PCHAR)requestCopy.x.adi_hdr.cmd_buffer_ptr += subRequest->x.ioDeviceIO.number * BYTES_PER_SECTOR;
requestCopy.x.ioDeviceIO.starting_sector += subRequest->x.ioDeviceIO.number;
requestCopy.x.ioDeviceIO.number -= subRequest->x.ioDeviceIO.number;
requestCopy.x.ioDeviceIO.bsm >>= subRequest->x.ioDeviceIO.number;
requestCopy.x.ioDeviceIO.crc >>= subRequest->x.ioDeviceIO.number;
requestCopy.x.ioDeviceIO.retrys >>= subRequest->x.ioDeviceIO.number;
mask = ~(0xffffffff << subRequest->x.ioDeviceIO.number);
requestCopy.x.ioDeviceIO.bsm &= mask;
requestCopy.x.ioDeviceIO.crc &= mask;
requestCopy.x.ioDeviceIO.retrys &= mask;
//
// use IoRequest.DoneEvent on last request so that all requests
// up to the last one are done before event is set
//
pevent = requestCopy.x.ioDeviceIO.number ?
&subRequest->DoneEvent : &IoRequest->DoneEvent;
KeInitializeEvent(
pevent,
NotificationEvent,
FALSE);
irp = IoBuildDeviceIoControlRequest(
IOCTL_QIC117_DRIVE_REQUEST,
Context->q117iDeviceObject,
NULL,
0,
NULL,
0,
TRUE,
pevent,
&subRequest->IoStatus
);
if (irp == NULL) {
CheckedDump(QIC117DBGP,("q117ReqIO: Can't allocate Irp\n"));
//
// If an Irp can't be allocated, then this call will
// simply return. This will leave the queue frozen for
// this device, which means it can no longer be accessed.
//
return ERROR_ENCODE(ERR_PROGRAM_FAILURE, FCT_ID, 2);
}
//
// Build mdl
//
irp->MdlAddress = IoAllocateMdl(
address,
IoRequest->x.ioDeviceIO.number * BYTES_PER_SECTOR,
secondary,
FALSE, // no charge of quota
NULL // no irp
);
(PCHAR)address += subRequest->x.ioDeviceIO.number * BYTES_PER_SECTOR;
secondary = TRUE;
if (irp->MdlAddress == NULL) {
CheckedDump(QIC117DBGP,("q117ReqIO: Can't allocate MDL\n"));
//
// If a MDL can't be allocated, then this call will
// simply return. This will leave the queue frozen for
// this device, which means it can no longer be accessed.
//
IoFreeIrp(irp);
return ERROR_ENCODE(ERR_PROGRAM_FAILURE, FCT_ID, 3);
}
MmBuildMdlForNonPagedPool(irp->MdlAddress);
//
// Get Q117I's stack location and store IoRequest for it's use
//
irpStack = IoGetNextIrpStackLocation(irp);
irpStack->Parameters.DeviceIoControl.Type3InputBuffer = subRequest;
#if DBG
CheckedDump(QIC117SHOWTD,("subRequest->x.ioDeviceIO.starting_sector %x\n", subRequest->x.ioDeviceIO.starting_sector ));
CheckedDump(QIC117SHOWTD,("subRequest->x.ioDeviceIO.number %x\n", subRequest->x.ioDeviceIO.number ));
CheckedDump(QIC117SHOWTD,("subRequest->x.adi_hdr.cmd_buffer_ptr %x\n", subRequest->x.adi_hdr.cmd_buffer_ptr ));
CheckedDump(QIC117SHOWTD,("subRequest->x.ioDeviceIO.bsm %x\n", subRequest->x.ioDeviceIO.bsm ));
CheckedDump(QIC117SHOWTD,("subRequest->x.ioDeviceIO.crc %x\n", subRequest->x.ioDeviceIO.crc ));
CheckedDump(QIC117SHOWTD,("subRequest->x.ioDeviceIO.retrys %x\n", subRequest->x.ioDeviceIO.retrys ));
CheckedDump(QIC117SHOWTD,("subRequest->x.adi_hdr.driver_cmd %x\n\n", subRequest->x.adi_hdr.driver_cmd ));
#endif
//
// Set IO completion routine only on the last entry
//
if (CompletionRoutine && requestCopy.x.ioDeviceIO.number == 0) {
IoSetCompletionRoutine(irp, CompletionRoutine, CompletionContext, TRUE, TRUE, TRUE);
}
(VOID)IoCallDriver(Context->q117iDeviceObject, irp);
CheckedDump(QIC117SHOWKDI,("q117ReqIO: Sending subreq\n"));
//
// point to the next sub-request to make
//
++subRequest;
}
} else {
#endif // BUFFER_SPLIT
IoRequest->x.adi_hdr.status = ERROR_ENCODE(ERR_PROGRAM_FAILURE, FCT_ID, 4);
KeInitializeEvent(
&IoRequest->DoneEvent,
NotificationEvent,
FALSE);
irp = IoBuildDeviceIoControlRequest(
IOCTL_QIC117_DRIVE_REQUEST,
Context->q117iDeviceObject,
NULL,
0,
NULL,
0,
TRUE,
&IoRequest->DoneEvent,
&IoRequest->IoStatus
);
if (irp == NULL) {
CheckedDump(QIC117DBGP,("q117ReqIO: Can't allocate Irp\n"));
//
// If an Irp can't be allocated, then this call will
// simply return. This will leave the queue frozen for
// this device, which means it can no longer be accessed.
//
return ERROR_ENCODE(ERR_PROGRAM_FAILURE, FCT_ID, 5);
}
//
// If we have buffer information
//
if (BufferInfo) {
irp->MdlAddress = IoAllocateMdl(
IoRequest->x.adi_hdr.cmd_buffer_ptr,
bufferSize,
FALSE, // not a secondary buffer
FALSE, // no charge of quota
NULL // no irp
);
if (irp->MdlAddress == NULL) {
CheckedDump(QIC117DBGP,("q117ReqIO: Can't allocate MDL\n"));
//
// If a MDL can't be allocated, then this call will
// simply return. This will leave the queue frozen for
// this device, which means it can no longer be accessed.
//
IoFreeIrp(irp);
return ERROR_ENCODE(ERR_PROGRAM_FAILURE, FCT_ID, 6);
}
MmBuildMdlForNonPagedPool(irp->MdlAddress);
}
//
// Get Q117I's stack location and store IoRequest for it's use
//
irpStack = IoGetNextIrpStackLocation(irp);
irpStack->Parameters.DeviceIoControl.Type3InputBuffer = IoRequest;
if (CompletionRoutine) {
IoSetCompletionRoutine(irp, CompletionRoutine, CompletionContext, TRUE, TRUE, TRUE);
}
IoCallDriver(Context->q117iDeviceObject, irp);
#ifdef BUFFER_SPLIT
}
#endif // BUFFER_SPLIT
return ERR_NO_ERR;
}
dStatus
q117WaitIO(
IN PIO_REQUEST IoRequest,
IN BOOLEAN Wait,
IN PQ117_CONTEXT Context
)
/*++
Routine Description:
Wait for an I/O request to complete. If a MIPS machine,
coalesce the sub-requests into the original request.
Arguments:
IoRequest - original request to lower level driver (has event to wait on)
Wait - Set if processing an FRB from cms_IoCtl. This disables waiting
on the event (as this routine is called from IoCompletion
routine) and disables translation of the bad block errors.
Return Value:
--*/
{
CheckedDump(QIC117SHOWKDI,("WaitIO(%x,%x,%x) ... ", IoRequest->x.adi_hdr.driver_cmd,IoRequest->x.ioDeviceIO.starting_sector,IoRequest->x.adi_hdr.status));
if (Wait) {
KeWaitForSingleObject(
&IoRequest->DoneEvent,
Suspended,
KernelMode,
FALSE,
NULL);
}
#ifdef BUFFER_SPLIT
if (ERROR_DECODE(IoRequest->x.adi_hdr.status) == ERR_SPLIT_REQUESTS) {
PIO_REQUEST subRequest;
ULONG blocksLeft,mask,slot;
CheckedDump(QIC117SHOWKDI,("Got split request\n"));
subRequest = IoRequest->Next;
blocksLeft = IoRequest->x.ioDeviceIO.number;
//
// Zero accumulating fields
//
IoRequest->x.ioDeviceIO.bsm = IoRequest->x.ioDeviceIO.retrys = 0;
IoRequest->x.ioDeviceIO.crc = 0;
IoRequest->x.adi_hdr.status = ERR_NO_ERR;
//
// Loop through all sub-requests and build the resultant request
//
while (blocksLeft) {
#if DBG
CheckedDump(QIC117SHOWTD,("subRequest(%x)\n",subRequest));
CheckedDump(QIC117SHOWTD,("subRequest->x.ioDeviceIO.starting_sector %x\n", subRequest->x.ioDeviceIO.starting_sector ));
CheckedDump(QIC117SHOWTD,("subRequest->x.ioDeviceIO.number %x\n", subRequest->x.ioDeviceIO.number ));
CheckedDump(QIC117SHOWTD,("subRequest->x.adi_hdr.cmd_buffer_ptr %x\n", subRequest->x.adi_hdr.cmd_buffer_ptr ));
CheckedDump(QIC117SHOWTD,("subRequest->x.ioDeviceIO.bsm %x\n", subRequest->x.ioDeviceIO.bsm ));
CheckedDump(QIC117SHOWTD,("subRequest->x.ioDeviceIO.crc %x\n", subRequest->x.ioDeviceIO.crc ));
CheckedDump(QIC117SHOWTD,("subRequest->x.ioDeviceIO.retrys %x\n", subRequest->x.ioDeviceIO.retrys ));
CheckedDump(QIC117SHOWTD,("subRequest->x.adi_hdr.driver_cmd %x\n", subRequest->x.adi_hdr.driver_cmd ));
CheckedDump(QIC117SHOWTD,("subRequest->x.adi_hdr.status %x\n", subRequest->x.adi_hdr.status ));
#endif
//
// Create mask and calculate bit shift (slot) for each
// sub-request
//
mask = ~(0xffffffff << subRequest->x.ioDeviceIO.number);
slot = subRequest->x.ioDeviceIO.starting_sector - IoRequest->x.ioDeviceIO.starting_sector;
CheckedDump(QIC117SHOWTD,("mask=%08lx slot=%x\n",mask,slot));
//
// Coalesce the bad sector and retry bitfields
//
IoRequest->x.ioDeviceIO.bsm |= (subRequest->x.ioDeviceIO.bsm & mask) << slot;
IoRequest->x.ioDeviceIO.crc |= (subRequest->x.ioDeviceIO.crc & mask) << slot;
IoRequest->x.ioDeviceIO.retrys |= (subRequest->x.ioDeviceIO.retrys & mask) << slot;
if (ERROR_DECODE(subRequest->x.adi_hdr.status) == ERR_NEW_TAPE) {
//
// Saw new cart, so set need loaded flag
//
Context->CurrentTape.State = NeedInfoLoaded;
CheckedDump(QIC117INFO,("mtaccess: New Cart Detected\n"));
}
//
// Ignore BadBlk errors (but report them)
//
if (
ERROR_DECODE(subRequest->x.adi_hdr.status) == ERR_BAD_BLOCK_FDC_FAULT ||
ERROR_DECODE(subRequest->x.adi_hdr.status) == ERR_BAD_BLOCK_NO_DATA ||
ERROR_DECODE(subRequest->x.adi_hdr.status) == ERR_BAD_BLOCK_HARD_ERR
) {
IoRequest->x.adi_hdr.status = subRequest->x.adi_hdr.status;
subRequest->x.adi_hdr.status = ERR_NO_ERR;
}
if (subRequest->x.adi_hdr.status != ERR_NO_ERR) {
blocksLeft = 0;
IoRequest->x.adi_hdr.status = subRequest->x.adi_hdr.status;
} else {
blocksLeft -= subRequest->x.ioDeviceIO.number;
}
//
// point to the next sub-request to process
//
++subRequest;
}
//
// Free the sub-requests for this I/O request
//
ExFreePool(IoRequest->Next);
#if DBG
CheckedDump(QIC117SHOWTD,("IoRequest->x.adi_hdr.status %x\n", IoRequest->x.adi_hdr.status ));
CheckedDump(QIC117SHOWTD,("IoRequest->x.ioDeviceIO.starting_sector %x\n", IoRequest->x.ioDeviceIO.starting_sector ));
CheckedDump(QIC117SHOWTD,("IoRequest->x.ioDeviceIO.number %x\n", IoRequest->x.ioDeviceIO.number ));
CheckedDump(QIC117SHOWTD,("IoRequest->x.adi_hdr.cmd_buffer_ptr %x\n", IoRequest->x.adi_hdr.cmd_buffer_ptr ));
CheckedDump(QIC117SHOWTD,("IoRequest->x.ioDeviceIO.bsm %x\n", IoRequest->x.ioDeviceIO.bsm ));
CheckedDump(QIC117SHOWTD,("IoRequest->x.ioDeviceIO.crc %x\n", IoRequest->x.ioDeviceIO.crc ));
CheckedDump(QIC117SHOWTD,("IoRequest->x.ioDeviceIO.retrys %x\n", IoRequest->x.ioDeviceIO.retrys ));
CheckedDump(QIC117SHOWTD,("IoRequest->x.adi_hdr.driver_cmd %x\n", IoRequest->x.adi_hdr.driver_cmd ));
#endif
}
if (ERROR_DECODE(IoRequest->x.adi_hdr.status) == ERR_NEW_TAPE) {
//
// Saw new cart, so set need loaded flag
//
Context->CurrentTape.State = NeedInfoLoaded;
CheckedDump(QIC117SHOWTD,("New Cart Detected\n"));
}
#endif // BUFFER_SPLIT
#if DBG
switch(IoRequest->x.adi_hdr.driver_cmd) {
case CMD_READ:
case CMD_READ_RAW:
case CMD_READ_HEROIC:
case CMD_READ_VERIFY:
case CMD_WRITE:
case CMD_WRITE_DELETED_MARK:
if ((IoRequest->x.ioDeviceIO.crc || IoRequest->x.ioDeviceIO.bsm) && IoRequest->x.adi_hdr.driver_cmd) {
CheckedDump(QIC117SHOWKDI|QIC117SHOWBSM,("sect:%x bbm: %x crc: %x\n",IoRequest->x.ioDeviceIO.starting_sector ,IoRequest->x.ioDeviceIO.bsm, IoRequest->x.ioDeviceIO.crc));
}
break;
}
#endif
if ((
ERROR_DECODE(IoRequest->x.adi_hdr.status) == ERR_BAD_BLOCK_FDC_FAULT ||
ERROR_DECODE(IoRequest->x.adi_hdr.status) == ERR_BAD_BLOCK_NO_DATA ||
ERROR_DECODE(IoRequest->x.adi_hdr.status) == ERR_BAD_BLOCK_HARD_ERR) &&
Wait) {
IoRequest->x.adi_hdr.status = ERROR_ENCODE(ERR_BAD_BLOCK_DETECTED, FCT_ID, 1);
}
#if DBG
if (1) {
char *str;
str = q117GetErrorString(IoRequest->x.adi_hdr.status);
CheckedDump(QIC117SHOWKDI,(" >>>> waitio status %x:%s\n", IoRequest->x.adi_hdr.status, str));
}
#endif
return ERR_NO_ERR;
}
dStatus
q117DoIO(
IN PIO_REQUEST IoRequest,
IN PSEGMENT_BUFFER BufferInfo,
IN PQ117_CONTEXT Context
)
/*++
Routine Description:
Arguments:
IoRequest -
BufferInfo -
Context -
Return Value:
--*/
{
dStatus ret;
CheckedDump(QIC117SHOWKDI,("DoIO called (%x)\n", IoRequest->x.adi_hdr.driver_cmd));
ret = q117ReqIO(IoRequest, BufferInfo, NULL, NULL, Context);
if (!ret) {
ret = q117WaitIO(IoRequest, TRUE, Context);
}
return ret;
}
dStatus
q117AbortIo(
IN PQ117_CONTEXT Context,
IN PKEVENT DoneEvent,
IN PIO_STATUS_BLOCK IoStatus
)
/*++
Routine Description:
Arguments:
Context -
DoneEvent -
IoStatus -
Return Value:
--*/
{
PIRP irp;
CheckedDump(QIC117SHOWKDI,("ClearIO Called\n"));
KeInitializeEvent(
DoneEvent,
NotificationEvent,
FALSE);
irp = IoBuildDeviceIoControlRequest(
IOCTL_QIC117_CLEAR_QUEUE,
Context->q117iDeviceObject,
NULL,
0,
NULL,
0,
TRUE,
DoneEvent,
IoStatus
);
if (irp == NULL) {
CheckedDump(QIC117DBGP,("q117ClearIO: Can't allocate Irp\n"));
//
// If an Irp can't be allocated, then this call will
// simply return. This will leave the queue frozen for
// this device, which means it can no longer be accessed.
//
return ERROR_ENCODE(ERR_PROGRAM_FAILURE, FCT_ID, 7);
}
(VOID)IoCallDriver(Context->q117iDeviceObject, irp);
return ERR_NO_ERR;
}
dStatus
q117AbortIoDone(
IN PQ117_CONTEXT Context,
IN PKEVENT DoneEvent
)
/*++
Routine Description:
Arguments:
Context -
DoneEvent -
Return Value:
--*/
{
//
// wait for the driver to complete request
//
KeWaitForSingleObject(
DoneEvent,
Suspended,
KernelMode,
FALSE,
NULL);
return ERR_NO_ERR;
}
#if DBG
char *q117GetErrorString(dStatus stat)
{
char *str;
switch(ERROR_DECODE(stat)) {
case ERR_BAD_TAPE:
str = "ERR_BAD_TAPE";
break;
case ERR_BAD_SIGNATURE:
str = "ERR_BAD_SIGNATURE";
break;
case ERR_UNKNOWN_FORMAT_CODE:
str = "ERR_UNKNOWN_FORMAT_CODE";
break;
case ERR_CORRECTION_FAILED:
str = "ERR_CORRECTION_FAILED";
break;
case ERR_PROGRAM_FAILURE:
str = "ERR_PROGRAM_FAILURE";
break;
case ERR_WRITE_PROTECTED:
str = "ERR_WRITE_PROTECTED";
break;
case ERR_TAPE_NOT_FORMATED:
str = "ERR_TAPE_NOT_FORMATED";
break;
case ERR_UNRECOGNIZED_FORMAT:
str = "ERR_UNRECOGNIZED_FORMAT";
break;
case ERR_END_OF_VOLUME:
str = "ERR_END_OF_VOLUME";
break;
case ERR_UNUSABLE_TAPE:
str = "ERR_UNUSABLE_TAPE";
break;
case ERR_SPLIT_REQUESTS:
str = "ERR_SPLIT_REQUESTS";
break;
case ERR_EARLY_WARNING:
str = "ERR_EARLY_WARNING";
break;
case ERR_SET_MARK:
str = "ERR_SET_MARK";
break;
case ERR_FILE_MARK:
str = "ERR_FILE_MARK";
break;
case ERR_LONG_FILE_MARK:
str = "ERR_LONG_FILE_MARK";
break;
case ERR_SHORT_FILE_MARK:
str = "ERR_SHORT_FILE_MARK";
break;
case ERR_NO_VOLUMES:
str = "ERR_NO_VOLUMES";
break;
case ERR_NO_MEMORY:
str = "ERR_NO_MEMORY";
break;
case ERR_ECC_FAILED:
str = "ERR_ECC_FAILED";
break;
case ERR_END_OF_TAPE:
str = "ERR_END_OF_TAPE";
break;
case ERR_TAPE_FULL:
str = "ERR_TAPE_FULL";
break;
case ERR_WRITE_FAILURE:
str = "ERR_WRITE_FAILURE";
break;
case ERR_BAD_BLOCK_DETECTED:
str = "ERR_BAD_BLOCK_DETECTED";
break;
case ERR_NO_ERR:
str="ERR_NO_ERR";
break;
case ERR_ABORT:
str = "ERR_ABORT";
break;
case ERR_BAD_BLOCK_FDC_FAULT:
str = "ERR_BAD_BLOCK_FDC_FAULT";
break;
case ERR_BAD_BLOCK_HARD_ERR:
str = "ERR_BAD_BLOCK_HARD_ERR";
break;
case ERR_BAD_BLOCK_NO_DATA:
str = "ERR_BAD_BLOCK_NO_DATA";
break;
case ERR_BAD_FORMAT:
str = "ERR_BAD_FORMAT";
break;
case ERR_BAD_MARK_DETECTED:
str = "ERR_BAD_MARK_DETECTED";
break;
case ERR_BAD_REQUEST:
str = "ERR_BAD_REQUEST";
break;
case ERR_CMD_FAULT:
str = "ERR_CMD_FAULT";
break;
case ERR_CMD_OVERRUN:
str = "ERR_CMD_OVERRUN";
break;
case ERR_DEVICE_NOT_CONFIGURED:
str = "ERR_DEVICE_NOT_CONFIGURED";
break;
case ERR_DEVICE_NOT_SELECTED:
str = "ERR_DEVICE_NOT_SELECTED";
break;
case ERR_DRIVE_FAULT:
str = "ERR_DRIVE_FAULT";
break;
case ERR_DRV_NOT_READY:
str = "ERR_DRV_NOT_READY";
break;
case ERR_FDC_FAULT:
str = "ERR_FDC_FAULT";
break;
case ERR_FMT_MOTION_TIMEOUT:
str = "ERR_FMT_MOTION_TIMEOUT";
break;
case ERR_FORMAT_TIMED_OUT:
str = "ERR_FORMAT_TIMED_OUT";
break;
case ERR_INCOMPATIBLE_MEDIA:
str = "ERR_INCOMPATIBLE_MEDIA";
break;
case ERR_INCOMPATIBLE_PARTIAL_FMT:
str = "ERR_INCOMPATIBLE_PARTIAL_FMT";
break;
case ERR_INVALID_COMMAND:
str = "ERR_INVALID_COMMAND";
break;
case ERR_INVALID_FDC_STATUS:
str = "ERR_INVALID_FDC_STATUS";
break;
case ERR_NEW_TAPE:
str = "ERR_NEW_TAPE";
break;
case ERR_NO_DRIVE:
str = "ERR_NO_DRIVE";
break;
case ERR_NO_FDC:
str = "ERR_NO_FDC";
break;
case ERR_NO_TAPE:
str = "ERR_NO_TAPE";
break;
case ERR_SEEK_FAILED:
str = "ERR_SEEK_FAILED";
break;
case ERR_SPEED_UNAVAILBLE:
str = "ERR_SPEED_UNAVAILBLE";
break;
case ERR_TAPE_STOPPED:
str = "ERR_TAPE_STOPPED";
break;
case ERR_UNKNOWN_TAPE_FORMAT:
str = "ERR_UNKNOWN_TAPE_FORMAT";
break;
case ERR_UNKNOWN_TAPE_LENGTH:
str = "ERR_UNKNOWN_TAPE_LENGTH";
break;
case ERR_UNSUPPORTED_FORMAT:
str = "ERR_UNSUPPORTED_FORMAT";
break;
case ERR_UNSUPPORTED_RATE:
str = "ERR_UNSUPPORTED_RATE";
break;
case ERR_WRITE_BURST_FAILURE:
str = "ERR_WRITE_BURST_FAILURE";
break;
default:
str = "not decoded";
}
return str;
}
#endif