⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tape.c

📁 This sample is a working example of Exabyte2 Tape Minidriver. This module contains device-specific r
💻 C
📖 第 1 页 / 共 5 页
字号:
    size.

    The number of IRPs required to process this
    request is written in the current stack of
    the original IRP. Then as each new IRP completes
    the count in the original IRP is decremented.
    When the count goes to zero, the original IRP
    is completed.

Arguments:

    DeviceObject - Pointer to the device object
    Irp - Pointer to Irp

Return Value:

    None.

--*/

{
    PFUNCTIONAL_DEVICE_EXTENSION   fdoExtension = Fdo->DeviceExtension;
    PIO_STACK_LOCATION  currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
    PIO_STACK_LOCATION  nextIrpStack = IoGetNextIrpStackLocation(Irp);
    ULONG               irpCount;
    ULONG               transferByteCount = currentIrpStack->Parameters.Read.Length;
    PSCSI_REQUEST_BLOCK srb;
    LARGE_INTEGER       startingOffset = currentIrpStack->Parameters.Read.ByteOffset;
    ULONG               dataLength = MaximumBytes;
    PVOID               dataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
    LONG                remainingIrps;
    BOOLEAN             completeOriginalIrp = FALSE;
    NTSTATUS            status;
    ULONG               i;

    PAGED_CODE();

    //
    // Caluculate number of requests to break this IRP into.
    //

    irpCount = (transferByteCount + MaximumBytes - 1) / MaximumBytes;

    DebugPrint((2,
                "SplitTapeRequest: Requires %d IRPs\n", irpCount));
    DebugPrint((2,
                "SplitTapeRequest: Original IRP %p\n", Irp));

    //
    // If all partial transfers complete successfully then
    // the status is already set up.
    // Failing partial transfer IRP will set status to
    // error and bytes transferred to 0 during IoCompletion.
    //

    Irp->IoStatus.Status = STATUS_SUCCESS;
    //CEP Irp->IoStatus.Information = transferByteCount;
    Irp->IoStatus.Information = 0;

    //
    // Save number of IRPs to complete count on current stack
    // of original IRP.
    //

    nextIrpStack->Parameters.Others.Argument1 = ULongToPtr( irpCount );

    for (i = 0; i < irpCount; i++) {

        PIRP newIrp;
        PIO_STACK_LOCATION newIrpStack;

        //
        // Allocate new IRP.
        //

        newIrp = IoAllocateIrp(Fdo->StackSize, FALSE);

        if (newIrp == NULL) {

            DebugPrint((1,
                       "SplitTapeRequest: Can't allocate Irp\n"));

            //
            // Decrement count of outstanding partial requests.
            //

            remainingIrps = InterlockedDecrement((PLONG)&nextIrpStack->Parameters.Others.Argument1);

            //
            // Check if any outstanding IRPs.
            //

            if (remainingIrps == 0) {
                completeOriginalIrp = TRUE;
            }

            //
            // Update original IRP with failing status.
            //

            Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
            Irp->IoStatus.Information = 0;

            //
            // Keep going with this request as outstanding partials
            // may be in progress.
            //

            goto KeepGoing;
        }

        DebugPrint((2,
                    "SplitTapeRequest: New IRP %p\n", newIrp));

        //
        // Write MDL address to new IRP.
        // In the port driver the SRB data length
        // field is used as an offset into the MDL,
        // so the same MDL can be used for each partial
        // transfer. This saves having to build a new
        // MDL for each partial transfer.
        //

        newIrp->MdlAddress = Irp->MdlAddress;

        //
        // At this point there is no current stack.
        // IoSetNextIrpStackLocation will make the
        // first stack location the current stack
        // so that the SRB address can be written
        // there.
        //

        IoSetNextIrpStackLocation(newIrp);

        newIrpStack = IoGetCurrentIrpStackLocation(newIrp);

        newIrpStack->MajorFunction = currentIrpStack->MajorFunction;

        newIrpStack->Parameters.Read.Length = dataLength;
        newIrpStack->Parameters.Read.ByteOffset = startingOffset;

        newIrpStack->DeviceObject = Fdo;

        //
        // Build SRB and CDB.
        //

        TapeReadWrite(Fdo, newIrp);

        //
        // Adjust SRB for this partial transfer.
        //

        newIrpStack = IoGetNextIrpStackLocation(newIrp);

        srb = newIrpStack->Parameters.Others.Argument1;

        srb->DataBuffer = dataBuffer;

        //
        // Write original IRP address to new IRP.
        //

        newIrp->AssociatedIrp.MasterIrp = Irp;

        //
        // Set the completion routine to TapeIoCompleteAssociated.
        //

        IoSetCompletionRoutine(newIrp,
                               TapeIoCompleteAssociated,
                               srb,
                               TRUE,
                               TRUE,
                               TRUE);

        //
        // Call port driver with new request.
        //

        status = IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, newIrp);

        if (!NT_SUCCESS(status)) {

            DebugPrint((1,
                       "SplitTapeRequest: IoCallDriver returned error\n"));

            //
            // Decrement count of outstanding partial requests.
            //

            remainingIrps = InterlockedDecrement((PLONG)&nextIrpStack->Parameters.Others.Argument1);

            //
            // Check if any outstanding IRPs.
            //

            if (remainingIrps == 0) {
                completeOriginalIrp = TRUE;
            }

            //
            // Update original IRP with failing status.
            //

            Irp->IoStatus.Status = status;
            Irp->IoStatus.Information = 0;

            //
            // Deallocate this partial IRP.
            //

            IoFreeIrp(newIrp);
        }

KeepGoing:

        //
        // Set up for next request.
        //

        dataBuffer = (PCHAR)dataBuffer + MaximumBytes;

        transferByteCount -= MaximumBytes;

        if (transferByteCount > MaximumBytes) {

            dataLength = MaximumBytes;

        } else {

            dataLength = transferByteCount;
        }

        //
        // Adjust disk byte offset.
        //

        startingOffset.QuadPart += MaximumBytes;
    }

    //
    // Check if original IRP should be completed.
    //

    if (completeOriginalIrp) {

        ClassReleaseRemoveLock(Fdo, Irp);
        ClassCompleteRequest(Fdo, Irp, 0);
    }

    return;

} // end SplitTapeRequest()



VOID
TapeReadWrite(
    IN PDEVICE_OBJECT Fdo,
    IN PIRP Irp
    )

/*++

Routine Description:

    This routine builds up the given irp for a read or write request.

Arguments:

    DeviceObject - Supplies the device object.

    Irp - Supplies the I/O request packet.

Return Value:

    None.

--*/

{
    PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
    PTAPE_DATA         tapeData = (PTAPE_DATA)(fdoExtension->CommonExtension.DriverData);
    PTAPE_INIT_DATA_EX tapeInitData = &tapeData->TapeInitData;
    PVOID minitapeExtension = (tapeData + 1);
    PIO_STACK_LOCATION       irpSp, nextSp;
    PSCSI_REQUEST_BLOCK      srb;
    PCDB                     cdb;
    ULONG                    transferBlocks;

    PAGED_CODE();

    //
    // Allocate an Srb.
    //

    srb = ExAllocateFromNPagedLookasideList(&(fdoExtension->CommonExtension.SrbLookasideList));

    srb->SrbFlags = 0;

    irpSp = IoGetCurrentIrpStackLocation(Irp);

    if (irpSp->MajorFunction == IRP_MJ_READ) {
        srb->SrbFlags |= SRB_FLAGS_DATA_IN;
    } else {
        srb->SrbFlags |= SRB_FLAGS_DATA_OUT;
    }

    srb->Length = SCSI_REQUEST_BLOCK_SIZE;
    srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
    srb->SrbStatus = 0;
    srb->ScsiStatus = 0;
    srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
    srb->SrbFlags |= fdoExtension->SrbFlags;
    srb->DataTransferLength = irpSp->Parameters.Read.Length;
    srb->TimeOutValue = fdoExtension->TimeOutValue;
    srb->DataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
    srb->SenseInfoBuffer = fdoExtension->SenseData;
    srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
    srb->NextSrb = NULL;
    srb->OriginalRequest = Irp;
    srb->SrbExtension = NULL;
    srb->QueueSortKey = 0;

    //
    // Indicate that 6-byte CDB's will be used.
    //

    srb->CdbLength = CDB6GENERIC_LENGTH;

    //
    // Fill in CDB fields.
    //

    cdb = (PCDB)srb->Cdb;

    //
    // Zero CDB in SRB.
    //

    RtlZeroMemory(cdb, MAXIMUM_CDB_SIZE);

    if (fdoExtension->DiskGeometry.BytesPerSector) {

        //
        // Since we are writing fixed block mode, normalize transfer count
        // to number of blocks.
        //

        transferBlocks = irpSp->Parameters.Read.Length / fdoExtension->DiskGeometry.BytesPerSector;

        //
        // Tell the device that we are in fixed block mode.
        //

        cdb->CDB6READWRITETAPE.VendorSpecific = 1;
    } else {

        //
        // Variable block mode transfer.
        //

        transferBlocks = irpSp->Parameters.Read.Length;
        cdb->CDB6READWRITETAPE.VendorSpecific = 0;
    }

    //
    // Set up transfer length
    //

    cdb->CDB6READWRITETAPE.TransferLenMSB = (UCHAR)((transferBlocks >> 16) & 0xff);
    cdb->CDB6READWRITETAPE.TransferLen    = (UCHAR)((transferBlocks >> 8) & 0xff);
    cdb->CDB6READWRITETAPE.TransferLenLSB = (UCHAR)(transferBlocks & 0xff);

    //
    // Set transfer direction.
    //

    if (srb->SrbFlags & SRB_FLAGS_DATA_IN) {

         DebugPrint((3,
                    "TapeReadWrite: Read Command\n"));

         cdb->CDB6READWRITETAPE.OperationCode = SCSIOP_READ6;

    } else {

         DebugPrint((3,
                     "TapeReadWrite: Write Command\n"));

         cdb->CDB6READWRITETAPE.OperationCode = SCSIOP_WRITE6;
    }

    nextSp = IoGetNextIrpStackLocation(Irp);

    nextSp->MajorFunction = IRP_MJ_SCSI;
    nextSp->Parameters.Scsi.Srb = srb;
    irpSp->Parameters.Others.Argument4 = (PVOID) MAXIMUM_RETRIES;

    IoSetCompletionRoutine(Irp,
                           ClassIoComplete,
                           srb,
                           TRUE,
                           TRUE,
                           FALSE);

    if (tapeInitData->PreProcessReadWrite) {

        //
        // If the routine exists, call it. The miniclass driver will
        // do whatever it needs to.
        //

        tapeInitData->PreProcessReadWrite(minitapeExtension,
                                          NULL,
                                          NULL,
                                          srb,
                                          0,
                                          0,
                                          NULL);
    }
}



NTSTATUS
TapeIoCompleteAssociated(
    IN PDEVICE_OBJECT Fdo,
    IN PIRP Irp,
    IN PVOID Context
    )

/*++

Routine Description:

    This routine executes when the port driver has completed a request.
    It looks at the SRB status in the completing SRB and if not success
    it checks for valid request sense buffer information. If valid, the
    info is used to update status with more precise message of type of
    error. This routine deallocates the SRB.  This routine is used for
    requests which were build by split request.  After it has processed
    the request it decrements the Irp count in the master Irp.  If the
    count goes to zero then the master Irp is completed.

Arguments:

    DeviceObject - Supplies the device object which represents the logical
        unit.

    Irp - Supplies the Irp which has completed.

    Context - Supplies a pointer to the SRB.

Return Value:

    NT status

--*/

{
    PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
    PSCSI_REQUEST_BLOCK srb = Context;
    PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
    PTAPE_DATA tapeData = (PTAPE_DATA)(fdoExtension->CommonExtension.DriverData);
    LONG irpCount;
    PIRP originalIrp = Irp->AssociatedIrp.MasterIrp;
    NTSTATUS status;

    //
    // Check SRB status for success of completing request.
    //

    if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {

        DebugPrint((2,
                    "TapeIoCompleteAssociated: IRP %p, SRB %p", Irp, srb));

        //
        // Release the queue if it is frozen.
        //

        if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
            ClassReleaseQueue(Fdo);
        }

      

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -