File:  [WindowsNT SDKs] / ntddk / src / scsi / qic117 / mtaccess.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:

    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 PAGES_TO_SECTORS(pages)  (((pages)*PAGE_SIZE)/BYTES_PER_SECTOR)

#define MIN(a,b) ((a)>(b)?(b):(a))

STATUS
q117ReqIO(
    IN PIO_REQUEST IoRequest,
    IN PSEGMENT_BUFFER BufferInfo,
    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 numberOfPagesInTransfer;
    BOOLEAN needToSplit;
    ULONG sectorsToTransfer;
    ULONG maxSplits;
#endif


    IoRequest->BufferInfo = BufferInfo;

#ifdef BUFFER_SPLIT

    needToSplit = FALSE;

    if (BufferInfo) {
        numberOfPagesInTransfer = ADDRESS_AND_SIZE_TO_SPAN_PAGES(
            IoRequest->Data,
            IoRequest->Number * BYTES_PER_SECTOR );

        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 (BufferInfo->logical < IoRequest->Data ||
            ((PUCHAR)(IoRequest->Data) + (IoRequest->Number * BYTES_PER_SECTOR)) >
            ((PUCHAR)(BufferInfo->logical) + BYTES_PER_SEGMENT) ) {

            CheckedDump(QIC117DBGP,("Buffer pointer out of range\n"));

            return FCodeErr;

        }
    }
#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->Command != DFmt && needToSplit) {

        address = IoRequest->Data;

        //
        // Split request into chunks
        //
        subRequest = ExAllocatePool(NonPagedPool,
                         sizeof(*IoRequest)*maxSplits);

        CheckedDump(QIC117INFO,("q117ReqIO: Allocating %d subreqs\n", maxSplits));

        IoRequest->Next = subRequest;
        IoRequest->Status = SplitRequests;

        requestCopy = *IoRequest;

#if DBG
        CheckedDump(QIC117SHOWTD,("*************************", requestCopy.Block ));
        CheckedDump(QIC117SHOWTD,("IoRequest->Block     %x\n", requestCopy.Block ));
        CheckedDump(QIC117SHOWTD,("IoRequest->Number    %x\n", requestCopy.Number ));
        CheckedDump(QIC117SHOWTD,("IoRequest->Data      %x\n", requestCopy.Data ));
        CheckedDump(QIC117SHOWTD,("IoRequest->BadList   %x\n", requestCopy.BadList ));
        CheckedDump(QIC117SHOWTD,("IoRequest->RetryList %x\n", requestCopy.RetryList ));
        CheckedDump(QIC117SHOWTD,("IoRequest->Command   %x\n\n", requestCopy.Command ));
#endif

        while (requestCopy.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->Number = (UCHAR)
                MIN(sectorsToTransfer, (ULONG)subRequest->Number);

            CheckedDump(QIC117SHOWTD,("Split at %d sectors\n", subRequest->Number));

            //
            // Adjust the current request to be the remainder of request
            //
            (PCHAR)requestCopy.Data += subRequest->Number * BYTES_PER_SECTOR;
            requestCopy.Block += subRequest->Number;
            requestCopy.Number -= subRequest->Number;
            requestCopy.BadList >>= subRequest->Number;
            requestCopy.RetryList >>= subRequest->Number;

            mask = ~(0xffffffff << subRequest->Number);
            requestCopy.BadList &=  mask;
            requestCopy.RetryList &= mask;


            //
            // use IoRequest.DoneEvent on last request so that all requests
            //  up to the last one are done before event is set
            //
            pevent = requestCopy.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 FCodeErr;
            }



            //
            // Build mdl
            //
            irp->MdlAddress = IoAllocateMdl(
                    address,
                    subRequest->Number * BYTES_PER_SECTOR,
                    secondary,
                    FALSE,  // no charge of quota
                    NULL    // no irp
                );

            (PCHAR)address += subRequest->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 FCodeErr;
            }

            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->Block     %x\n", subRequest->Block ));
            CheckedDump(QIC117SHOWTD,("subRequest->Number    %x\n", subRequest->Number ));
            CheckedDump(QIC117SHOWTD,("subRequest->Data      %x\n", subRequest->Data ));
            CheckedDump(QIC117SHOWTD,("subRequest->BadList   %x\n", subRequest->BadList ));
            CheckedDump(QIC117SHOWTD,("subRequest->RetryList %x\n", subRequest->RetryList ));
            CheckedDump(QIC117SHOWTD,("subRequest->Command   %x\n\n", subRequest->Command ));
#endif
            (VOID)IoCallDriver(Context->q117iDeviceObject, irp);

            CheckedDump(QIC117INFO,("q117ReqIO: Sending subreq\n"));

            //
            // point to the next sub-request to make
            //
            ++subRequest;
        }

    } else {

#endif // BUFFER_SPLIT

    IoRequest->Status = InQue;

    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 FCodeErr;
    }



    //
    // If we have buffer information
    //
    if (BufferInfo) {

        irp->MdlAddress = IoAllocateMdl(
                IoRequest->Data,
                IoRequest->Number * BYTES_PER_SECTOR,
                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 FCodeErr;
        }
        MmBuildMdlForNonPagedPool(irp->MdlAddress);
    }



    //
    // Get Q117I's stack location and store IoRequest for it's use
    //

    irpStack = IoGetNextIrpStackLocation(irp);
    irpStack->Parameters.DeviceIoControl.Type3InputBuffer = IoRequest;

    IoCallDriver(Context->q117iDeviceObject, irp);

#ifdef BUFFER_SPLIT
    }
#endif // BUFFER_SPLIT

    return NoErr;

}

STATUS
q117WaitIO(
    IN PIO_REQUEST IoRequest,
    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 -

Return Value:

--*/

{
    CheckedDump(QIC117INFO,("WaitIO(%x,%x,%x) ... ", IoRequest->Command,IoRequest->Block,IoRequest->Status));

    KeWaitForSingleObject(
        &IoRequest->DoneEvent,
        Suspended,
        KernelMode,
        FALSE,
        NULL);

#ifdef BUFFER_SPLIT

    if (IoRequest->Status == SplitRequests) {
        PIO_REQUEST subRequest;
        ULONG blocksLeft,mask,slot;

        CheckedDump(QIC117INFO,("Got split request\n"));

        subRequest = IoRequest->Next;
        blocksLeft = IoRequest->Number;

        //
        // Zero accumulating fields
        //

        IoRequest->BadList = IoRequest->RetryList = 0;
        IoRequest->Status = NoErr;

        //
        // Loop through all sub-requests and build the resultant request
        //
        while (blocksLeft) {

#if DBG
        CheckedDump(QIC117SHOWTD,("subRequest(%x)\n",subRequest));
        CheckedDump(QIC117SHOWTD,("subRequest->Block     %x\n", subRequest->Block ));
        CheckedDump(QIC117SHOWTD,("subRequest->Number    %x\n", subRequest->Number ));
        CheckedDump(QIC117SHOWTD,("subRequest->Data      %x\n", subRequest->Data ));
        CheckedDump(QIC117SHOWTD,("subRequest->BadList   %x\n", subRequest->BadList ));
        CheckedDump(QIC117SHOWTD,("subRequest->RetryList %x\n", subRequest->RetryList ));
        CheckedDump(QIC117SHOWTD,("subRequest->Command   %x\n", subRequest->Command ));
        CheckedDump(QIC117SHOWTD,("subRequest->Status    %x\n", subRequest->Status ));
#endif

            //
            // Create mask and calculate bit shift (slot) for each
            // sub-request
            //
            mask = ~(0xffffffff << subRequest->Number);
            slot = subRequest->Block - IoRequest->Block;

            CheckedDump(QIC117SHOWTD,("mask=%08lx slot=%x\n",mask,slot));

            //
            // Coalesce the bad sector and retry bitfields
            //
            IoRequest->BadList |= (subRequest->BadList & mask) << slot;
            IoRequest->RetryList |= (subRequest->RetryList & mask) << slot;

            if (subRequest->Status == NewCart) {
                //
                // Saw new cart,  so set need loaded flag
                //
                Context->CurrentTape.State = NeedInfoLoaded;
                CheckedDump(QIC117SHOWTD,("New Cart Detected\n"));

            }

            //
            // Ignore BadBlk errors (but report them)
            //
            if (subRequest->Status == BadBlk) {

                IoRequest->Status = subRequest->Status;
                subRequest->Status = NoErr;

            }

            if (subRequest->Status != NoErr) {

                blocksLeft = 0;
                IoRequest->Status = subRequest->Status;

            } else {

                blocksLeft -= subRequest->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->Status    %x\n", IoRequest->Status ));
        CheckedDump(QIC117SHOWTD,("IoRequest->Block     %x\n", IoRequest->Block ));
        CheckedDump(QIC117SHOWTD,("IoRequest->Number    %x\n", IoRequest->Number ));
        CheckedDump(QIC117SHOWTD,("IoRequest->Data      %x\n", IoRequest->Data ));
        CheckedDump(QIC117SHOWTD,("IoRequest->BadList   %x\n", IoRequest->BadList ));
        CheckedDump(QIC117SHOWTD,("IoRequest->RetryList %x\n", IoRequest->RetryList ));
        CheckedDump(QIC117SHOWTD,("IoRequest->Command   %x\n", IoRequest->Command ));
#endif
    }

    if (IoRequest->Status == NewCart) {
        //
        // Saw new cart,  so set need loaded flag
        //
        Context->CurrentTape.State = NeedInfoLoaded;
        CheckedDump(QIC117SHOWTD,("New Cart Detected\n"));

    }

#endif // BUFFER_SPLIT

#if DBG
    if (IoRequest->Status == BadBlk) {
        CheckedDump(QIC117INFO,("bbm: %x ", IoRequest->BadList));
    }
#endif
    CheckedDump(QIC117INFO,("waitio status %x\n", IoRequest->Status));

    return NoErr;
}

STATUS
q117DoIO(
    IN PIO_REQUEST IoRequest,
    IN PSEGMENT_BUFFER BufferInfo,
    IN PQ117_CONTEXT Context
    )

/*++

Routine Description:


Arguments:

    IoRequest -

    BufferInfo -

    Context -

Return Value:

--*/

{
    STATUS ret;

    CheckedDump(QIC117INFO,("DoIO called (%x)\n", IoRequest->Command));

    ret = q117ReqIO(IoRequest, BufferInfo, Context);
    if (!ret) {
        ret = q117WaitIO(IoRequest, Context);
    }
    return ret;
}

STATUS
q117AbortIo(
    IN PQ117_CONTEXT Context,
    IN PKEVENT DoneEvent,
    IN PIO_STATUS_BLOCK IoStatus
    )

/*++

Routine Description:


Arguments:

    Context -

    DoneEvent -

    IoStatus -

Return Value:

--*/

{
    PIRP irp;


    CheckedDump(QIC117INFO,("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 FCodeErr;
    }


    (VOID)IoCallDriver(Context->q117iDeviceObject, irp);

    return NoErr;
}

STATUS
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 NoErr;
}

unix.superglobalmegacorp.com

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