File:  [WindowsNT SDKs] / ntddk / src / scsi / qic117 / ioctl.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Thu Aug 9 18:31:12 2018 UTC (7 years, 9 months ago) by root
Branches: msft, MAIN
CVS tags: ntddk-nov-1993, HEAD
Microsoft Windows NT Build 511 (DDK SDK) 11-01-1993

/*++

Copyright (c) 1993 - Colorado Memory Systems,  Inc.
All Rights Reserved

Module Name:

    ioctl.c

Abstract:

    Tape IOCTL support for NT Backup aplication.

Revision History:




--*/

//
// Includes
//

#include <ntddk.h>
#include <ntddtape.h>   // tape device driver I/O control codes
#include "common.h"
#include "q117.h"
#include "protos.h"
#include "cms.h"


NTSTATUS
q117IoCtlGetPosition (
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )
/*++

Routine Description:



Arguments:

    DeviceObject


Return Value:

    NT Status

--*/

{
    PQ117_CONTEXT       context;
    PTAPE_GET_POSITION  currentPosition;
    PLARGE_INTEGER      offset;

    context = DeviceObject->DeviceExtension;
    currentPosition = Irp->AssociatedIrp.SystemBuffer;

    Irp->IoStatus.Information = sizeof(TAPE_GET_POSITION);

    //
    // signal no partition support
    //
    currentPosition->Partition = 0;

    //
    // Fill in the CurrentOperation.Position based on the mode
    //
    offset = &currentPosition->Offset;

    offset->HighPart = (LONG)0;


    switch (context->CurrentOperation.Type) {

        case BackupInProgress:
            offset->LowPart = context->CurrentOperation.BytesOnTape;
            break;

        case RestoreInProgress:
            offset->LowPart = context->CurrentOperation.BytesRead;
            break;

        case NoOperation:
            offset->LowPart = context->CurrentOperation.BytesRead;
            break;

    }
    offset->LowPart /= BLOCK_SIZE;

    CheckedDump(QIC117SHOWTD,("%d=GetPosition()",currentPosition->Offset.LowPart));

    return STATUS_SUCCESS;
}

NTSTATUS
q117IoCtlGetMediaParameters (
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )
/*++

Routine Description:



Arguments:

    DeviceObject


Return Value:

    NT Status

--*/

{
    PQ117_CONTEXT   context;
    NTSTATUS        ntStatus;

    context = DeviceObject->DeviceExtension;

    //
    // Make sure there is a tape in the drive and that the tape information
    // has been loaded
    //
    if (context->CurrentOperation.Type == NoOperation) {

        ntStatus = q117ConvertStatus(DeviceObject, q117CheckNewTape(context));

    } else {

        ntStatus = STATUS_SUCCESS;

    }


    if ( NT_SUCCESS( ntStatus ) ) {
        //
        // Copy already formed (by q117CheckNewTape) information into callers buffer
        //
        Irp->IoStatus.Information = sizeof(TAPE_GET_MEDIA_PARAMETERS);

        *(PTAPE_GET_MEDIA_PARAMETERS)Irp->AssociatedIrp.SystemBuffer =
            *context->CurrentTape.MediaInfo;

    }

    return ntStatus;
}

NTSTATUS
q117IoCtlSetMediaParameters (
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )
/*++

Routine Description:



Arguments:

    DeviceObject


Return Value:

    NT Status

--*/

{
    PQ117_CONTEXT                context;
    PTAPE_SET_MEDIA_PARAMETERS   setMedia;

    context = DeviceObject->DeviceExtension;

    setMedia = (PTAPE_SET_MEDIA_PARAMETERS)Irp->AssociatedIrp.SystemBuffer;

    CheckedDump((QIC117SHOWTD | QIC117WARN),("SetDriveParameters not implemented yet\n"));
    CheckedDump(QIC117SHOWTD,("BlockSize: %x",setMedia->BlockSize));

    if (setMedia->BlockSize != BLOCK_SIZE)
        return STATUS_INVALID_PARAMETER;
    else
        return STATUS_SUCCESS;
}

NTSTATUS
q117IoCtlGetDriveParameters (
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )
/*++

Routine Description:



Arguments:

    DeviceObject


Return Value:

    NT Status

--*/

{
    PQ117_CONTEXT             context;
    PTAPE_GET_DRIVE_PARAMETERS driveInfo;

    context = DeviceObject->DeviceExtension;

    //
    // Copy already formed (by q117CheckNewTape) information into callers buffer
    //
    //
    driveInfo = (PTAPE_GET_DRIVE_PARAMETERS)Irp->AssociatedIrp.SystemBuffer;
    Irp->IoStatus.Information = sizeof(TAPE_GET_DRIVE_PARAMETERS);

    driveInfo->ECC = TRUE;
    driveInfo->Compression = FALSE;
    driveInfo->DataPadding = FALSE;
    driveInfo->ReportSetmarks = TRUE;
    driveInfo->DefaultBlockSize = BLOCK_SIZE;
    driveInfo->MaximumBlockSize = BLOCK_SIZE;
    driveInfo->MinimumBlockSize = BLOCK_SIZE;
    driveInfo->MaximumPartitionCount = 0;
    driveInfo->FeaturesLow =
        TAPE_DRIVE_ERASE_SHORT |
        TAPE_DRIVE_ERASE_BOP_ONLY |
        TAPE_DRIVE_TAPE_CAPACITY |
        TAPE_DRIVE_TAPE_REMAINING |
        TAPE_DRIVE_FIXED_BLOCK |
        TAPE_DRIVE_WRITE_PROTECT |
        TAPE_DRIVE_ECC |
        TAPE_DRIVE_COMPRESSION |
        TAPE_DRIVE_REPORT_SMKS |
        TAPE_DRIVE_GET_ABSOLUTE_BLK |
        TAPE_DRIVE_GET_LOGICAL_BLK;
    driveInfo->FeaturesHigh =
        TAPE_DRIVE_LOAD_UNLOAD |
        TAPE_DRIVE_TENSION |
        TAPE_DRIVE_LOCK_UNLOCK |
        TAPE_DRIVE_ABSOLUTE_BLK |
        TAPE_DRIVE_LOGICAL_BLK |
        TAPE_DRIVE_END_OF_DATA |
        TAPE_DRIVE_RELATIVE_BLKS |
        TAPE_DRIVE_FILEMARKS |
        TAPE_DRIVE_SEQUENTIAL_FMKS |
        TAPE_DRIVE_SETMARKS |
        TAPE_DRIVE_SEQUENTIAL_SMKS |
        TAPE_DRIVE_REVERSE_POSITION |
        TAPE_DRIVE_WRITE_SETMARKS |
        TAPE_DRIVE_WRITE_FILEMARKS |
        TAPE_DRIVE_FORMAT;

    driveInfo->FeaturesHigh &= ~TAPE_DRIVE_HIGH_FEATURES;

    return STATUS_SUCCESS;
}

NTSTATUS
q117IoCtlSetDriveParameters (
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )
/*++

Routine Description:



Arguments:

    DeviceObject


Return Value:

    NT Status

--*/

{
    PQ117_CONTEXT             context;
    PTAPE_SET_DRIVE_PARAMETERS driveInfo;
    NTSTATUS            ntStatus;

    context = DeviceObject->DeviceExtension;

    //
    // Copy already formed (by q117CheckNewTape) information into callers buffer
    //
    //
    driveInfo = (PTAPE_SET_DRIVE_PARAMETERS)Irp->AssociatedIrp.SystemBuffer;

    CheckedDump((QIC117SHOWTD | QIC117WARN),("SetDriveParameters not implemented yet\n"));
    CheckedDump(QIC117SHOWTD,("ECC: %x",driveInfo->ECC));
    CheckedDump(QIC117SHOWTD,("Compression: %x",driveInfo->Compression));
    CheckedDump(QIC117SHOWTD,("DataPadding: %x",driveInfo->DataPadding));
    CheckedDump(QIC117SHOWTD,("ReportSetmarks: %x",driveInfo->ReportSetmarks));
    ntStatus = STATUS_SUCCESS;
    if (!driveInfo->ECC ||
        driveInfo->Compression ||
        driveInfo->DataPadding ||
        !driveInfo->ReportSetmarks) {

        ntStatus = STATUS_INVALID_DEVICE_REQUEST;
    }

    return ntStatus;
}

NTSTATUS
q117IoCtlWriteMarks (
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )
/*++

Routine Description:

    Handle user request to write tape mark

Arguments:

    DeviceObject


Return Value:

    NT Status

--*/

{
#ifndef NO_MARKS

    PQ117_CONTEXT       context;
    PTAPE_WRITE_MARKS   tapeMarks = Irp->AssociatedIrp.SystemBuffer;
    ULONG               numMarks;
    NTSTATUS            ntStatus;
    ULONG               type;

    context = DeviceObject->DeviceExtension;

    //
    // Make sure we are in write mode
    //
    ntStatus = q117ConvertStatus(DeviceObject, q117OpenForWrite(context));

    numMarks = tapeMarks->Count;
    type = tapeMarks->Type;

    //
    // Don't allow long/short filemarks
    //
    switch(type) {
        case TAPE_LONG_FILEMARKS:
        case TAPE_SHORT_FILEMARKS:
            ntStatus = STATUS_INVALID_DEVICE_REQUEST;
    }

    //
    // Put as many marks as the user asked for,  in the mark array
    //
    while (numMarks && NT_SUCCESS( ntStatus )) {

        context->MarkArray.MarkEntry[
            context->MarkArray.TotalMarks].Type = tapeMarks->Type;

        context->MarkArray.MarkEntry[
            context->MarkArray.TotalMarks].Offset =
            context->CurrentOperation.BytesOnTape;

        --numMarks;

        ++context->MarkArray.TotalMarks;
        ++context->CurrentMark;

        //
        // Always make the (last mark) huge so we don't have to check
        // for the end of the table in the rest of the code.
        //
        context->MarkArray.MarkEntry[
            context->MarkArray.TotalMarks].Offset = 0xffffffff;

        //
        // For each mark, write a "fake" block on the tape.  This
        // is due to the ntBackup program assuming that a filemark
        // takes a block
        //

        ntStatus = q117ConvertStatus(
            DeviceObject,
            q117WriteTape(NULL,BLOCK_SIZE,context)
            );
    }

    return ntStatus;

#else

    return STATUS_INVALID_DEVICE_REQUEST;

#endif
}

NTSTATUS
q117IoCtlSetPosition (
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )
/*++

Routine Description:



Arguments:

    DeviceObject


Return Value:

    NT Status

--*/

{
    PQ117_CONTEXT             context;
    PTAPE_SET_POSITION tapePosition = Irp->AssociatedIrp.SystemBuffer;
    STATUS status;
    NTSTATUS ntStatus;
    IO_REQUEST ioreq;
    ULONG offset;
#ifndef NO_MARKS
    int x = 0;
#endif

    context = DeviceObject->DeviceExtension;

    status = NoErr;
    ntStatus = STATUS_SUCCESS;

    if (context->CurrentOperation.Type != NoOperation) {
        switch(context->CurrentOperation.Type) {

            case BackupInProgress:
                status = q117EndWriteOperation(context);
                break;

            case RestoreInProgress:
                if (
                    tapePosition->Method == TAPE_REWIND
                    ) {
                    status = q117EndReadOperation(context);
                }

                break;
        }
    }

    context->CurrentOperation.Position = tapePosition->Method;
    switch(tapePosition->Method) {

        case TAPE_REWIND:

            CheckedDump(QIC117INFO,("Rewind()\n"));
            status = q117DoCmd(&ioreq, DEject, NULL, context);

//            context->TapeStatus.Status |= TAPE_STATUS_BEGINNING_OF_MEDIA;
//            context->TapeStatus.Status &= ~TAPE_STATUS_END_OF_MEDIA;

            context->CurrentOperation.BytesRead = 0;

#ifndef NO_MARKS
            context->CurrentMark = 0;
#endif
            break;

        case TAPE_LOGICAL_BLOCK:
        case TAPE_ABSOLUTE_BLOCK:

            CheckedDump(QIC117SHOWTD,(
                "%s SeekBlock(%d)\n",
                tapePosition->Method==TAPE_LOGICAL_BLOCK?"Logical":"Absolute",
                tapePosition->Offset.LowPart
                ));

            offset = (tapePosition->Offset.LowPart)*BLOCK_SIZE;

            ntStatus = q117SeekToOffset(offset, context, DeviceObject);

            break;

        case TAPE_SPACE_END_OF_DATA:
            //
            // This will be taken care of when backup starts
            //  by using the context->CurrentOperation.Position
            //
            // It is assumed that this function will only be called prior
            //  to a backup operation only.

            CheckedDump(QIC117SHOWTD,("SeekEOD()\n"));
            context->CurrentOperation.BytesRead =
                context->ActiveVolume.DataSize;

#ifndef NO_MARKS
            context->CurrentMark = context->MarkArray.TotalMarks;
#endif

//            context->TapeStatus.Status |= TAPE_STATUS_END_OF_MEDIA;
//            context->TapeStatus.Status &= ~TAPE_STATUS_BEGINNING_OF_MEDIA;
            break;


        case TAPE_SPACE_RELATIVE_BLOCKS:


            CheckedDump(QIC117SHOWTD,("SeekRelBlock(%d)\n",tapePosition->Offset.LowPart));
            //
            // Convert relative offset into absolute
            //
            offset = (LONG)context->CurrentOperation.BytesRead +
                    ((LONG)tapePosition->Offset.LowPart*BLOCK_SIZE);

            //
            // Perform absolute seek.
            //
            ntStatus = q117SeekToOffset(offset,context, DeviceObject);

            break;

#ifndef NO_MARKS
        case TAPE_SPACE_SETMARKS:
            ++x;
        case TAPE_SPACE_FILEMARKS:
            ++x;
        case TAPE_SPACE_SEQUENTIAL_FMKS:
            ++x;
        case TAPE_SPACE_SEQUENTIAL_SMKS:
            if (1) {
                static char *type[4] = {"SequentialSet","SequentialFile","File","Set"};

                CheckedDump(QIC117SHOWTD,("Seek%sMark(%d)\n",type[x],tapePosition->Offset.LowPart));
            }
            ntStatus = q117FindMark(tapePosition->Method,
                         tapePosition->Offset.LowPart, context, DeviceObject);
            break;
#else
        case TAPE_SPACE_SETMARKS:
        case TAPE_SPACE_FILEMARKS:
        case TAPE_SPACE_SEQUENTIAL_FMKS:
        case TAPE_SPACE_SEQUENTIAL_SMKS:
#endif
        default:
            CheckedDump(QIC117DBGP,("TAPE: Position: Invalid Position Code (%x)\n",
                tapePosition->Method));

            ntStatus = STATUS_INVALID_DEVICE_REQUEST;
            break;

    } // end switch(tapePosition->Method)

    if (status)
        ntStatus = q117ConvertStatus(DeviceObject, status);

    return ntStatus;

}

#ifndef NO_MARKS
NTSTATUS
q117FindMark(
    ULONG Type,
    LONG Number,
    PQ117_CONTEXT Context,
    IN PDEVICE_OBJECT DeviceObject
    )

/*++

Routine Description:



Arguments:


Return Value:

    NT Status

--*/

{
    NTSTATUS ntStatus;
    BOOLEAN forwardSeek;

    ntStatus = STATUS_SUCCESS;

    //
    // Convert the SetPosition commands into WriteMark types
    //
    switch(Type) {

        case TAPE_SPACE_SEQUENTIAL_FMKS:

            //
            // If sequential mark,  then always start from the first mark.
            //
            Context->CurrentMark = 0;

        case TAPE_SPACE_FILEMARKS:

            Type = TAPE_FILEMARKS;
            break;

        case TAPE_SPACE_SEQUENTIAL_SMKS:

            //
            // If sequential mark,  then always start from the first mark.
            //
            Context->CurrentMark = 0;

        case TAPE_SPACE_SETMARKS:

            Type = TAPE_SETMARKS;
            break;

    }

    if (Number > 0) {
        forwardSeek = TRUE;
    } else {
        forwardSeek = FALSE;
    }


    //
    // Now seek the appropriate amount
    //
    while (NT_SUCCESS( ntStatus ) && Number != 0) {

        if (forwardSeek) {

            if (Context->CurrentMark >= Context->MarkArray.TotalMarks) {

                ntStatus = STATUS_END_OF_MEDIA;

            } else {

                if (Context->MarkArray.MarkEntry[Context->CurrentMark].Type ==
                    Type) {

                    //
                    // If we found one,  decrement the count
                    //

                    --Number;


                    //
                    // Don't increment the current mark on the last one we
                    // find.  This is because current mark points to
                    // the mark we are going to hit next.
                    //

                    if (Number) {

                        ++Context->CurrentMark;
                    }

                } else {

                    ++Context->CurrentMark;

                }
            }

        } else {

            if (Context->CurrentMark == 0) {

                ntStatus = STATUS_END_OF_MEDIA;

            } else {

                --Context->CurrentMark;

                if (Context->MarkArray.MarkEntry[Context->CurrentMark].Type ==
                    Type) {

                    ++Number;

                }

            }

        }

    }

    if (NT_SUCCESS( ntStatus )) {

        if (Context->CurrentMark >= Context->MarkArray.TotalMarks) {

            ntStatus = STATUS_END_OF_MEDIA;

        } else {

            //
            // Seek to proper location.  Note:  forward seek
            // seeks to block after file mark (successive read will return
            // block after filemark.
            // A backward seek will position at the filemark.  The next read
            // will return filemark found,  and successive reads will read
            // data after the mark)
            //
            ntStatus = q117SeekToOffset(
                Context->MarkArray.MarkEntry[Context->CurrentMark].Offset+
                    (forwardSeek?BLOCK_SIZE:0),
                Context,
                DeviceObject
                );

        }

    }

    return ntStatus;
}
#endif

NTSTATUS
q117SeekToOffset(
    ULONG Offset,
    PQ117_CONTEXT Context,
    IN PDEVICE_OBJECT DeviceObject
    )

/*++

Routine Description:

    Seek to specified offset on the tape (absolute offset from 0) in bytes

Arguments:

    Offset - Bytes from begining of the volume to seek.

Return Value:

    NT Status

--*/

{
    NTSTATUS ntStatus;


    CheckedDump(QIC117SHOWTD,("Absolute seek: %x\n",Offset));

    ntStatus = STATUS_SUCCESS;

    //
    // If not in read mode,  switch into read mode
    //
    if (Context->CurrentOperation.Type == NoOperation) {

        ntStatus = q117OpenForRead(0, Context, DeviceObject);

        //
        // if there is no data on the tape
        //
        if (ntStatus == STATUS_NO_DATA_DETECTED) {
            return ntStatus;
        }

        Context->CurrentOperation.Type = RestoreInProgress;
    }


    if (Offset < Context->CurrentOperation.BytesRead) {

        //
        // Backward seek,  so stop current operation,
        //  rewind to begining of volume,  and drop
        //  through to a forward seek.
        //

        ntStatus = q117ConvertStatus(
            DeviceObject,
            q117EndReadOperation(Context)
            );

        if (NT_SUCCESS(ntStatus)) {

            ntStatus = q117OpenForRead(0, Context, DeviceObject);

            //
            // if there is no data on the tape
            //
            if (ntStatus == STATUS_NO_DATA_DETECTED) {
                return ntStatus;
            }

            Context->CurrentOperation.Type = RestoreInProgress;
        }
    }


    if (NT_SUCCESS(ntStatus)) {
        //
        // Forward seek only (if we were doing a backward seek,  the operation
        // has been re-started this point and BytesRead == 0)
        //
        Offset -= Context->CurrentOperation.BytesRead;

        //
        // Skip to the appropriate place
        //
        ntStatus = q117ConvertStatus(
                        DeviceObject,
                        q117SkipBlock(&Offset, Context)
                        );

    }

    return ntStatus;
}

NTSTATUS
q117IoCtlErase (
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )
/*++

Routine Description:



Arguments:

    DeviceObject


Return Value:

    NT Status

--*/

{
    PQ117_CONTEXT             context;
    NTSTATUS ntStatus;
    STATUS status;

    context = DeviceObject->DeviceExtension;

    //
    // Complete any operation in progress
    //
    switch(context->CurrentOperation.Type) {

        case BackupInProgress:
            status = q117EndWriteOperation(context);
            break;

        case RestoreInProgress:
            status = q117EndReadOperation(context);
            break;
    }

    //
    // Make sure there is a tape in the drive and that the tape information
    // has been loaded
    //
    ntStatus = q117ConvertStatus(
        DeviceObject,
        q117CheckNewTape(context));

    if ( NT_SUCCESS( ntStatus ) ) {
        //
        // Don't allow an erase if write protected
        //
        if (context->CurrentTape.MediaInfo->WriteProtected) {
            return STATUS_MEDIA_WRITE_PROTECTED;
        }

        //
        // Erase the tape
        //
        status = q117EraseQ(context);

        ntStatus = q117ConvertStatus(DeviceObject, status);
    }

    return ntStatus;
}

NTSTATUS
q117IoCtlPrepare (
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )
/*++

Routine Description:



Arguments:

    DeviceObject


Return Value:

    NT Status

--*/

{
    PQ117_CONTEXT       context;
    NTSTATUS            ntStatus;
    STATUS              status;
    PTAPE_PREPARE       tapePrepare;
    IO_REQUEST          ioreq;
    QIC40_VENDOR_UNIQUE vendorUnique;
    LONG                numberBad;

    context = DeviceObject->DeviceExtension;

    status = NoErr;

    //
    // Complete any operation in progress
    //
    switch(context->CurrentOperation.Type) {

        case BackupInProgress:
            status = q117EndWriteOperation(context);
            break;

        case RestoreInProgress:
            status = q117EndReadOperation(context);
            break;
    }

    //
    // All prepare except LOCK and UNLOCK operations rewind the media.
    //
    tapePrepare = Irp->AssociatedIrp.SystemBuffer;

    if ((tapePrepare->Operation != TAPE_LOCK) &&
        (tapePrepare->Operation != TAPE_UNLOCK)) {
        context->CurrentOperation.BytesRead = 0;
        context->CurrentOperation.Position = 0;
#ifndef NO_MARKS
        context->CurrentMark = 0;
#endif
    }


    if (status) {
        return q117ConvertStatus(DeviceObject, status);
    }

    ntStatus = STATUS_SUCCESS;

    switch (tapePrepare->Operation) {

        case TAPE_LOAD:
            CheckedDump(QIC117SHOWTD,("TAPE_LOAD  ... "));
            ntStatus = q117ConvertStatus(DeviceObject, q117CheckNewTape(context));
            break;

        case TAPE_UNLOAD:

            //
            // Just rewind the tape
            //
            CheckedDump(QIC117SHOWTD,("TAPE_UNLOAD  ... "));
            ntStatus = q117ConvertStatus (
                    DeviceObject,
                    q117DoCmd(&ioreq, DEject, NULL, context) );

            break;

        case TAPE_TENSION:

            CheckedDump(QIC117SHOWTD,("TAPE_TENSION  ... "));
            ntStatus = q117ConvertStatus (
                    DeviceObject,
                    q117DoCmd(&ioreq, DReten, NULL, context) );

            break;

        case TAPE_UNLOCK:
            CheckedDump(QIC117SHOWTD,("UN"));
        case TAPE_LOCK:
            CheckedDump(QIC117SHOWTD,("LOCK TAPE ..."));

            //
            // These commands mean nothing for a QIC-40 drive.  However,  the current
            // operation will be flushed allowing user to remove cartridge.
            //
            break;

        case TAPE_FORMAT:
            CheckedDump(QIC117SHOWTD,("TAPE_FORMAT  ... "));

            ntStatus = q117ConvertStatus (
                        DeviceObject,
                        q117Format(
                            &numberBad,
                            TRUE,
                            &vendorUnique,
                            context ) );
            break;

        default:
            CheckedDump(QIC117SHOWTD,("INVALID  ... "));

            ntStatus = STATUS_INVALID_DEVICE_REQUEST;

    } // end switch (tapePrepare->Operation)

    return ntStatus;
}

NTSTATUS
q117IoCtlGetStatus (
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )
/*++

Routine Description:



Arguments:

    DeviceObject


Return Value:

    NT Status

--*/

{
    PQ117_CONTEXT             context;
//    PTAPE_STATUS tapeStatus;
    STATUS status;

    context = DeviceObject->DeviceExtension;


    //
    // Complete any operation in progress
    //
    switch(context->CurrentOperation.Type) {

        case BackupInProgress:
            status = NoErr;
            break;

        case RestoreInProgress:
            status = NoErr;
            break;

        case NoOperation:
            status = q117CheckNewTape(context);
            break;

        default:
            status = FCodeErr;

    }

    //tapeStatus = Irp->UserBuffer;

    //
    // Is this supported in the tape API ?????
    //
//    *tapeStatus = context->TapeStatus;

    //
    // Reset media changed flag.
    //
//    context->TapeStatus.Status &= ~TAPE_STATUS_MEDIA_CHANGED;

    return q117ConvertStatus(DeviceObject, status);
}

NTSTATUS
q117IoCtlReadAbs (
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )
/*++

Routine Description:



Arguments:

    DeviceObject


Return Value:

    NT Status

--*/

{
    PQ117_CONTEXT   context;
    PSEGMENT_BUFFER bufferInfo;
    PVOID           scrbuf;
    PIO_REQUEST     ioreq;
    PCMS_RW_ABS     readWrite;
    STATUS          status;
    ULONG           len;
    PIO_STACK_LOCATION  irpStack;

    context = DeviceObject->DeviceExtension;
    readWrite = Irp->AssociatedIrp.SystemBuffer;
    irpStack = IoGetCurrentIrpStackLocation(Irp);

    scrbuf = q117GetFreeBuffer(&bufferInfo,context);

    status=q117IssIOReq(
                scrbuf,
                DRead,
                readWrite->Block,
                bufferInfo,
                context
                );

    if (!status) {

        //
        // Wait for data to be written
        //
        ioreq=q117Dequeue(WaitForItem,context);

        status = ioreq->Status;

    }

    readWrite->Status = status;

    len = BYTES_PER_SECTOR*readWrite->Count;

    if (len > irpStack->Parameters.DeviceIoControl.OutputBufferLength) {

        len = irpStack->Parameters.DeviceIoControl.OutputBufferLength;

    }

    RtlMoveMemory(
        readWrite+1,
        scrbuf,
        len
        );

    Irp->IoStatus.Information = sizeof(CMS_RW_ABS)+len;

    return q117ConvertStatus(DeviceObject, status);


}

NTSTATUS
q117IoCtlWriteAbs (
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )
/*++

Routine Description:



Arguments:

    DeviceObject


Return Value:

    NT Status

--*/

{
    PQ117_CONTEXT   context;
    PSEGMENT_BUFFER bufferInfo;
    PVOID           scrbuf;
    PIO_REQUEST     ioreq;
    PCMS_RW_ABS     readWrite;
    STATUS          status;

    context = DeviceObject->DeviceExtension;
    readWrite = Irp->AssociatedIrp.SystemBuffer;

    scrbuf = q117GetFreeBuffer(&bufferInfo,context);

    RtlMoveMemory(
        scrbuf,
        readWrite+1,
        BYTES_PER_SECTOR*readWrite->Count
        );

    status = q117IssIOReq(
        scrbuf,
        DWrite,
        readWrite->Block,
        bufferInfo,
        context);

    if (!status) {

        //
        // Wait for data to be written
        //
        ioreq=q117Dequeue(WaitForItem,context);

        status = ioreq->Status;

    }

    readWrite->Status = status;

    return q117ConvertStatus(DeviceObject, status);

}

STATUS
q117CheckNewTape (
    PQ117_CONTEXT             Context
    )
/*++

Routine Description:

    This routine checks for new tape and reads header if necessary

Arguments:

    Context - Current context information

Return Value:

    NT Status

--*/

{
    STATUS              stat;
    IO_REQUEST          ioreq;
    PTAPE_HEADER        header;
    VOLUME_TABLE_ENTRY  tempVolume;
    UCHAR               tapeType;
    BOOLEAN             found;
    BOOLEAN             notNt;
    USHORT              volumesRead;
    DRIVE_CAPACITY      driveCapacity;
    SEGMENT             curseg;


    //
    // Check to see if there is a tape in the drive
    //
    stat = q117DoCmd(&ioreq, DGetCart, &tapeType, Context);

    //
    // If we found a tape and need to read the header and volume tables,
    //   do it now.
    //
    if (stat == NewCart) {
//        Context->TapeStatus.Status |= TAPE_STATUS_MEDIA_CHANGED;
    }

    if (stat == NewCart ||
            (stat == NoErr && Context->CurrentTape.State == NeedInfoLoaded) ) {

        CheckedDump(QIC117SHOWTD,("New Cart Detected\n"));

        //
        // Check to see if there is a tape in the drive
        //

        stat = q117DoCmd(&ioreq, DClearNewCart, NULL, Context);

        if (stat) {
            return stat;
        }

        //
        // Saw new cart,  so set need loaded flag
        //
        Context->CurrentTape.State = NeedInfoLoaded;

        // clear no media flag and end of media flag
//        Context->TapeStatus.Status &=
//            ~(TAPE_STATUS_NO_MEDIA|TAPE_STATUS_END_OF_MEDIA);

        // Set bom and device ready.
//        Context->TapeStatus.Status |=
//            TAPE_STATUS_DEVICE_READY|TAPE_STATUS_BEGINNING_OF_MEDIA;

        //
        // Check to see if tape is write protected
        //
        if (stat = q117DoCmd(&ioreq, DSndWPro, NULL, Context)) {

            if (stat != WProt) {
                return stat;
            }

        }

        Context->CurrentTape.MediaInfo->WriteProtected = (stat == WProt);
        if (stat == WProt) {
//            Context->TapeStatus.Status |= TAPE_STATUS_WRITE_PROTECTED;
        }

        //
        // Check to see if drive is formatted
        //
        stat = q117DoCmd(&ioreq, DGetCap, &driveCapacity, Context);

        if (stat) {
            return stat;
        }

        //
        // If tape not referenced.
        //
        if (driveCapacity.referenced == FALSE) {
            return BadFmt;
        }

        //
        // Check to see if tape is correct format
        //
        stat = q117DoCmd(&ioreq, DChkFmt, NULL, Context);

        if (stat) {
            if (stat == WrongFmt) {
                Context->CurrentTape.MediaInfo->WriteProtected =
                    TRUE;
                stat = NoErr;
            } else {
                return stat;
            }
        }

        //
        // Now read the tape header (and bad sector map)
        //
        if (stat = q117LoadTape(&header,Context)) {
            return stat;
        }
        CheckedDump(QIC117SHOWTD,("LoadTape successful\n"));

        //
        // If this capacity not supported by this drive,
        // (i.e..  Pegasus cart in a QIC-40 drive)
        // return invalid format
        //
        if (header->FormatCode != driveCapacity.TapeFormatCode) {
            return BadFmt;
        }

        //
        // Copy over bad sector map, etc.
        //
        RtlMoveMemory(
            Context->CurrentTape.TapeHeader,
            header,
            sizeof(*Context->CurrentTape.TapeHeader) );

        //
        // Now scan volume list and get last volume on tape as well as the
        // NT volume (if one exists
        //

        if (stat = q117SelectTD(Context))
            return stat;

        volumesRead = 0;

        found = FALSE;

        do {
            /* get a volume directory from the tape (if error then)*/
            stat = q117ReadVolumeEntry(&tempVolume,Context);

            if (stat && (stat != EndOfVol))
                return stat;

            if (!stat) {
                volumesRead++;

                //
                // For now,  let the system find ANY volume type and select
                // it.  This will allow NT Backup software to read the
                // volume and detect that it is a non-nt format.
                // To do this,  the if statement is removed,  allowing
                // the first volume found,  be the one that we select.
                //
                if (!(tempVolume.VendorSpecific &&
                    tempVolume.Vendor.cms_QIC40.OpSysType == OP_WINDOWS_NT)) {

                    Context->CurrentOperation.BytesOnTape =
                        Context->CurrentOperation.BytesRead = 0;

                    notNt = TRUE;

#ifndef NO_MARKS
                    Context->MarkArray.TotalMarks = 0;
                    Context->CurrentMark = Context->MarkArray.TotalMarks;
                    Context->MarkArray.MarkEntry[Context->CurrentMark].Offset =
                        0xffffffff;
#endif

                    /* force the data size to be the entire backup */
                    tempVolume.DataSize = 0;
                    curseg = tempVolume.StartSegment;
                    while (curseg <= tempVolume.EndingSegment) {

                        tempVolume.DataSize +=
                            q117GoodDataBytes(
                                curseg,
                                Context);
                        ++curseg;


                    }

                } else {

                    notNt = FALSE;

                }
                found = TRUE;
                Context->ActiveVolume = tempVolume;
            }

        } while (!stat && volumesRead < Context->CurrentTape.MaximumVolumes);

        if (stat = q117EndRest(Context))
            return(stat);

        //
        // If we did not find a volume,  then signal others that
        //  the ActiveVolume information is invalid.
        //
        if (!found)
            Context->ActiveVolumeNumber = 0;

        //
        // Zero out bytes saved (incase user trys to read)
        // Also set CurrentOperation.BytesRead to zero (start of tape)
        //
        Context->CurrentOperation.BytesOnTape =
            Context->CurrentOperation.BytesRead = 0;

        //
        // Flag that we have done everything
        //
        Context->CurrentTape.State = TapeInfoLoaded;

#ifndef NO_MARKS

        //
        // Read the mark list from the active volume
        //
        if (found && !notNt) {

            stat = q117GetMarks(Context);

        }

#endif

        //
        // If no more pressing error,  return NewCart
        // so application can be aware of the new insertion.
        //
        if (stat == NoErr) {
            stat = NewCart;
        }

    } else {

        if (stat == NoTape) {
//            Context->TapeStatus.Status |= TAPE_STATUS_NO_MEDIA;
            Context->ActiveVolumeNumber = 0;
            Context->CurrentOperation.BytesOnTape =
                Context->CurrentOperation.BytesRead = 0;

#ifndef NO_MARKS
            Context->MarkArray.TotalMarks = 0;
            Context->CurrentMark = Context->MarkArray.TotalMarks;
            Context->MarkArray.MarkEntry[Context->CurrentMark].Offset =
                0xffffffff;
#endif

        }

    }

    return stat;
}


unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.