diff options
| author | Dave Wilson <[email protected]> | 2015-03-17 19:50:07 -0700 |
|---|---|---|
| committer | Dave Wilson <[email protected]> | 2015-03-17 19:50:07 -0700 |
| commit | 97cf5197cf5b882b2c689d8dc2b555f2edf8f418 (patch) | |
| tree | 46f3701832d70b420eb0fc0eb93261f9da45db3f /storage/class/classpnp/src/obsolete.c | |
| parent | ef1905bf1e8825bb31120dfb27e0daf3154d859a (diff) | |
Initial publish
Diffstat (limited to 'storage/class/classpnp/src/obsolete.c')
| -rw-r--r-- | storage/class/classpnp/src/obsolete.c | 1125 |
1 files changed, 1125 insertions, 0 deletions
diff --git a/storage/class/classpnp/src/obsolete.c b/storage/class/classpnp/src/obsolete.c new file mode 100644 index 00000000..aeeef81d --- /dev/null +++ b/storage/class/classpnp/src/obsolete.c @@ -0,0 +1,1125 @@ +/*++ + +Copyright (C) Microsoft Corporation, 1991 - 2010 + +Module Name: + + obsolete.c + +Abstract: + + THESE ARE EXPORTED CLASSPNP FUNCTIONS (and their subroutines) + WHICH ARE NOW OBSOLETE. + BUT WE NEED TO KEEP THEM AROUND FOR LEGACY REASONS. + +Environment: + + kernel mode only + +Notes: + + +Revision History: + +--*/ + +#include "classp.h" +#include "debug.h" + +#ifdef DEBUG_USE_WPP +#include "obsolete.tmh" +#endif + +PIRP ClassRemoveCScanList(IN PCSCAN_LIST List); +VOID ClasspInitializeCScanList(IN PCSCAN_LIST List); + +#ifdef ALLOC_PRAGMA + #pragma alloc_text(PAGE, ClassDeleteSrbLookasideList) + #pragma alloc_text(PAGE, ClassInitializeSrbLookasideList) + #pragma alloc_text(PAGE, ClasspInitializeCScanList) +#endif + +typedef struct _CSCAN_LIST_ENTRY { + LIST_ENTRY Entry; + ULONGLONG BlockNumber; +} CSCAN_LIST_ENTRY, *PCSCAN_LIST_ENTRY; + + + + + +/* + * ClassSplitRequest + * + * This is a legacy exported function. + * It is called by storage miniport driver that have their own + * StartIo routine when the transfer size is too large for the hardware. + * We map it to our new read/write handler. + */ +VOID ClassSplitRequest(_In_ PDEVICE_OBJECT Fdo, _In_ PIRP Irp, _In_ ULONG MaximumBytes) +{ + PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension; + PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData; + + if (MaximumBytes > fdoData->HwMaxXferLen) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "ClassSplitRequest - driver requesting split to size that " + "hardware is unable to handle!\n")); + } + + if (MaximumBytes < fdoData->HwMaxXferLen){ + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_RW, "ClassSplitRequest - driver requesting smaller HwMaxXferLen " + "than required")); + fdoData->HwMaxXferLen = MAX(MaximumBytes, PAGE_SIZE); + } + + ServiceTransferRequest(Fdo, Irp, FALSE); +} + + +/*++//////////////////////////////////////////////////////////////////////////// + +ClassIoCompleteAssociated() + +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: + + Fdo - Supplies the functional device object which represents the target. + + Irp - Supplies the Irp which has completed. + + Context - Supplies a pointer to the SRB. + +Return Value: + + NT status + +--*/ +NTSTATUS +ClassIoCompleteAssociated( + IN PDEVICE_OBJECT Fdo, + IN PIRP Irp, + IN PVOID Context + ) +{ + PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; + + PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); + PSCSI_REQUEST_BLOCK srb = Context; + + PIRP originalIrp = Irp->AssociatedIrp.MasterIrp; + LONG irpCount; + + NTSTATUS status; + BOOLEAN retry; + + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "ClassIoCompleteAssociated is OBSOLETE !")); + + // + // Check SRB status for success of completing request. + // + if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) { + + LONGLONG retryInterval; + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "ClassIoCompleteAssociated: IRP %p, SRB %p", Irp, srb)); + + // + // Release the queue if it is frozen. + // + + if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) { + ClassReleaseQueue(Fdo); + } + + retry = InterpretSenseInfoWithoutHistory( + Fdo, + Irp, + srb, + irpStack->MajorFunction, + irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL ? + irpStack->Parameters.DeviceIoControl.IoControlCode : + 0, + MAXIMUM_RETRIES - + ((ULONG)(ULONG_PTR)irpStack->Parameters.Others.Argument4), + &status, + &retryInterval); + + // + // If the status is verified required and the this request + // should bypass verify required then retry the request. + // + + if (irpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME && + status == STATUS_VERIFY_REQUIRED) { + + status = STATUS_IO_DEVICE_ERROR; + retry = TRUE; + } + +#pragma warning(suppress:4213) // okay to cast Arg4 as a ulong for this use case + if (retry && ((ULONG)(ULONG_PTR)irpStack->Parameters.Others.Argument4)--) { + + // + // Retry request. If the class driver has supplied a StartIo, + // call it directly for retries. + // + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "Retry request %p\n", Irp)); + + if (PORT_ALLOCATED_SENSE(fdoExtension, srb)) { + FREE_PORT_ALLOCATED_SENSE_BUFFER(fdoExtension, srb); + } + + RetryRequest(Fdo, Irp, srb, TRUE, retryInterval); + + return STATUS_MORE_PROCESSING_REQUIRED; + } + + } else { + + // + // Set status for successful request. + // + + status = STATUS_SUCCESS; + + } // end if (SRB_STATUS(srb->SrbStatus) ... + + // + // Return SRB to list. + // + + if (PORT_ALLOCATED_SENSE(fdoExtension, srb)) { + FREE_PORT_ALLOCATED_SENSE_BUFFER(fdoExtension, srb); + } + + ClassFreeOrReuseSrb(fdoExtension, srb); + + // + // Set status in completing IRP. + // + + Irp->IoStatus.Status = status; + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "ClassIoCompleteAssociated: Partial xfer IRP %p\n", Irp)); + + // + // Get next stack location. This original request is unused + // except to keep track of the completing partial IRPs so the + // stack location is valid. + // + + irpStack = IoGetNextIrpStackLocation(originalIrp); + + // + // Update status only if error so that if any partial transfer + // completes with error, then the original IRP will return with + // error. If any of the asynchronous partial transfer IRPs fail, + // with an error then the original IRP will return 0 bytes transfered. + // This is an optimization for successful transfers. + // + + if (!NT_SUCCESS(status)) { + + originalIrp->IoStatus.Status = status; + originalIrp->IoStatus.Information = 0; + + // + // Set the hard error if necessary. + // + + if (IoIsErrorUserInduced(status) && + (originalIrp->Tail.Overlay.Thread != NULL)) { + + // + // Store DeviceObject for filesystem. + // + + IoSetHardErrorOrVerifyDevice(originalIrp, Fdo); + } + } + + // + // Decrement and get the count of remaining IRPs. + // + + irpCount = InterlockedDecrement( + (PLONG)&irpStack->Parameters.Others.Argument1); + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "ClassIoCompleteAssociated: Partial IRPs left %d\n", + irpCount)); + + // + // Ensure that the irpCount doesn't go negative. This was happening once + // because classpnp would get confused if it ran out of resources when + // splitting the request. + // + + NT_ASSERT(irpCount >= 0); + + if (irpCount == 0) { + + // + // All partial IRPs have completed. + // + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, + "ClassIoCompleteAssociated: All partial IRPs complete %p\n", + originalIrp)); + + if (fdoExtension->CommonExtension.DriverExtension->InitData.ClassStartIo) { + + // + // Acquire a separate copy of the remove lock so the debugging code + // works okay and we don't have to hold up the completion of this + // irp until after we start the next packet(s). + // + + KIRQL oldIrql; + UCHAR uniqueAddress = 0; + ClassAcquireRemoveLock(Fdo, (PIRP)&uniqueAddress); + ClassReleaseRemoveLock(Fdo, originalIrp); + ClassCompleteRequest(Fdo, originalIrp, IO_DISK_INCREMENT); + + KeRaiseIrql(DISPATCH_LEVEL, &oldIrql); + IoStartNextPacket(Fdo, TRUE); // yes, some IO is now cancellable + KeLowerIrql(oldIrql); + + ClassReleaseRemoveLock(Fdo, (PIRP)&uniqueAddress); + + } else { + + // + // just complete this request + // + + ClassReleaseRemoveLock(Fdo, originalIrp); + ClassCompleteRequest(Fdo, originalIrp, IO_DISK_INCREMENT); + + } + + } + + // + // Deallocate IRP and indicate the I/O system should not attempt any more + // processing. + // + + IoFreeIrp(Irp); + return STATUS_MORE_PROCESSING_REQUIRED; + +} // end ClassIoCompleteAssociated() + + +/*++//////////////////////////////////////////////////////////////////////////// + +RetryRequest() + +Routine Description: + + This is a wrapper around the delayed retry DPC routine, RetryRequestDPC. + This reinitalizes the necessary fields, queues the request, and sets + a timer to call the DPC if someone hasn't already done so. + +Arguments: + + DeviceObject - Supplies the device object associated with this request. + + Irp - Supplies the request to be retried. + + Srb - Supplies a Pointer to the SCSI request block to be retied. + + Assocaiated - Indicates this is an assocatied Irp created by split request. + + TimeDelta100ns - How long, in 100ns units, before retrying the request. + +Return Value: + + None + +--*/ +VOID +RetryRequest( + PDEVICE_OBJECT DeviceObject, + PIRP Irp, + PSCSI_REQUEST_BLOCK Srb, + BOOLEAN Associated, + LONGLONG TimeDelta100ns + ) +{ + PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp); + PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp); + ULONG transferByteCount; + ULONG dataTransferLength; + PSTORAGE_REQUEST_BLOCK_HEADER srbHeader = (PSTORAGE_REQUEST_BLOCK_HEADER)Srb; + + // This function is obsolete but is still used by some of our class drivers. + // TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "RetryRequest is OBSOLETE !")); + + // + // Determine the transfer count of the request. If this is a read or a + // write then the transfer count is in the Irp stack. Otherwise assume + // the MDL contains the correct length. If there is no MDL then the + // transfer length must be zero. + // + + dataTransferLength = SrbGetDataTransferLength(srbHeader); + if (currentIrpStack->MajorFunction == IRP_MJ_READ || + currentIrpStack->MajorFunction == IRP_MJ_WRITE) { + + _Analysis_assume_(currentIrpStack->Parameters.Read.Length <= dataTransferLength); + transferByteCount = currentIrpStack->Parameters.Read.Length; + + } else if (Irp->MdlAddress != NULL) { + + // + // Note this assumes that only read and write requests are spilt and + // other request do not need to be. If the data buffer address in + // the MDL and the SRB don't match then transfer length is most + // likely incorrect. + // + + NT_ASSERT(SrbGetDataBuffer(srbHeader) == MmGetMdlVirtualAddress(Irp->MdlAddress)); + _Analysis_assume_(Irp->MdlAddress->ByteCount <= dataTransferLength); + transferByteCount = Irp->MdlAddress->ByteCount; + + } else { + + transferByteCount = 0; + } + + // + // this is a safety net. this should not normally be hit, since we are + // not guaranteed to be an fdoExtension + // + + NT_ASSERT(!TEST_FLAG(SrbGetSrbFlags(srbHeader), SRB_FLAGS_FREE_SENSE_BUFFER)); + + // + // Reset byte count of transfer in SRB Extension. + // + + SrbSetDataTransferLength(srbHeader, transferByteCount); + + // + // Zero SRB statuses. + // + + srbHeader->SrbStatus = 0; + SrbSetScsiStatus(srbHeader, 0); + + // + // If this is the last retry, then disable all the special flags. + // + + if ( 0 == (ULONG)(ULONG_PTR)currentIrpStack->Parameters.Others.Argument4 ) { + // + // Set the no disconnect flag, disable synchronous data transfers and + // disable tagged queuing. This fixes some errors. + // NOTE: Cannot clear these flags, just add to them + // + + SrbSetSrbFlags(srbHeader, + SRB_FLAGS_DISABLE_DISCONNECT | SRB_FLAGS_DISABLE_SYNCH_TRANSFER); + SrbClearSrbFlags(srbHeader, SRB_FLAGS_QUEUE_ACTION_ENABLE); + + SrbSetQueueTag(srbHeader, SP_UNTAGGED); + } + + + // + // Set up major SCSI function. + // + + nextIrpStack->MajorFunction = IRP_MJ_SCSI; + + // + // Save SRB address in next stack for port driver. + // + + nextIrpStack->Parameters.Scsi.Srb = Srb; + + if (Associated){ + IoSetCompletionRoutine(Irp, ClassIoCompleteAssociated, Srb, TRUE, TRUE, TRUE); + } + else { + IoSetCompletionRoutine(Irp, ClassIoComplete, Srb, TRUE, TRUE, TRUE); + } + + ClassRetryRequest(DeviceObject, Irp, TimeDelta100ns); + return; +} // end RetryRequest() + + +/*++ + +ClassBuildRequest() + +Routine Description: + + This routine allocates an SRB for the specified request then calls + ClasspBuildRequestEx to create a SCSI operation to read or write the device. + + If no SRB is available then the request will be queued to be issued later + when requests are available. Drivers which do not want the queueing + behavior should allocate the SRB themselves and call ClasspBuildRequestEx + to issue it. + +Arguments: + + Fdo - Supplies the functional device object associated with this request. + + Irp - Supplies the request to be retried. + +Note: + + If the IRP is for a disk transfer, the byteoffset field + will already have been adjusted to make it relative to + the beginning of the disk. + + +Return Value: + + NT Status + +--*/ +NTSTATUS +ClassBuildRequest( + _In_ PDEVICE_OBJECT Fdo, + _In_ PIRP Irp + ) +{ + PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; + + PSCSI_REQUEST_BLOCK srb; + + // This function is obsolete, but still called by CDROM.SYS . + // TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "ClassBuildRequest is OBSOLETE !")); + + // + // Allocate an Srb. + // + + srb = ClasspAllocateSrb(fdoExtension); + + if (srb == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + ClasspBuildRequestEx(fdoExtension, Irp, srb); + return STATUS_SUCCESS; + +} // end ClassBuildRequest() + + +VOID +#pragma prefast(suppress:28194) // Srb may not be aliased if it is NULL +ClasspBuildRequestEx( + _In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, + _In_ PIRP Irp, + _In_ __drv_aliasesMem PSCSI_REQUEST_BLOCK Srb + ) + +/*++ + +ClasspBuildRequestEx() + +Routine Description: + + This routine allocates and builds an Srb for a read or write request. + The block address and length are supplied by the Irp. The retry count + is stored in the current stack for use by ClassIoComplete which + processes these requests when they complete. The Irp is ready to be + passed to the port driver when this routine returns. + +Arguments: + + FdoExtension - Supplies the device extension associated with this request. + + Irp - Supplies the request to be issued. + + Srb - Supplies an SRB to be used for the request. + +Note: + + If the IRP is for a disk transfer, the byteoffset field + will already have been adjusted to make it relative to + the beginning of the disk. + + +Return Value: + + NT Status + +--*/ +{ + PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp); + PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp); + + LARGE_INTEGER startingOffset = currentIrpStack->Parameters.Read.ByteOffset; + + PCDB cdb; + ULONG logicalBlockAddress; + USHORT transferBlocks; + NTSTATUS status; + PSTORAGE_REQUEST_BLOCK_HEADER srbHeader = (PSTORAGE_REQUEST_BLOCK_HEADER)Srb; + + // This function is obsolete, but still called by CDROM.SYS . + // TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "ClasspBuildRequestEx is OBSOLETE !")); + + if (Srb == NULL) { + NT_ASSERT(FALSE); + return; + } + + // + // Calculate relative sector address. + // + + logicalBlockAddress = + (ULONG)(Int64ShrlMod32(startingOffset.QuadPart, + FdoExtension->SectorShift)); + + // + // Prepare the SRB. + // NOTE - for extended SRB, size used is based on allocation in ClasspAllocateSrb. + // + + if (FdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { + status = InitializeStorageRequestBlock((PSTORAGE_REQUEST_BLOCK)Srb, + STORAGE_ADDRESS_TYPE_BTL8, + CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE, + 1, + SrbExDataTypeScsiCdb16); + if (!NT_SUCCESS(status)) { + NT_ASSERT(FALSE); + return; + } + + ((PSTORAGE_REQUEST_BLOCK)Srb)->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI; + } else { + RtlZeroMemory(Srb, sizeof(SCSI_REQUEST_BLOCK)); + + // + // Write length to SRB. + // + + Srb->Length = sizeof(SCSI_REQUEST_BLOCK); + + Srb->Function = SRB_FUNCTION_EXECUTE_SCSI; + } + + + // + // Set up IRP Address. + // + + SrbSetOriginalRequest(srbHeader, Irp); + + // + // Set up data buffer + // + + SrbSetDataBuffer(srbHeader, + MmGetMdlVirtualAddress(Irp->MdlAddress)); + + // + // Save byte count of transfer in SRB Extension. + // + + SrbSetDataTransferLength(srbHeader, + currentIrpStack->Parameters.Read.Length); + + // + // Initialize the queue actions field. + // + + SrbSetRequestAttribute(srbHeader, SRB_SIMPLE_TAG_REQUEST); + + // + // Queue sort key is Relative Block Address. + // + + SrbSetQueueSortKey(srbHeader, logicalBlockAddress); + + // + // Indicate auto request sense by specifying buffer and size. + // + + SrbSetSenseInfoBuffer(srbHeader, FdoExtension->SenseData); + SrbSetSenseInfoBufferLength(srbHeader, GET_FDO_EXTENSON_SENSE_DATA_LENGTH(FdoExtension)); + + // + // Set timeout value of one unit per 64k bytes of data. + // + + SrbSetTimeOutValue(srbHeader, + ((SrbGetDataTransferLength(srbHeader) + 0xFFFF) >> 16) * + FdoExtension->TimeOutValue); + + // + // Indicate that 10-byte CDB's will be used. + // + + SrbSetCdbLength(srbHeader, 10); + + // + // Fill in CDB fields. + // + + cdb = SrbGetCdb(srbHeader); + NT_ASSERT(cdb != NULL); + + transferBlocks = (USHORT)(currentIrpStack->Parameters.Read.Length >> + FdoExtension->SectorShift); + + // + // Move little endian values into CDB in big endian format. + // + + cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&logicalBlockAddress)->Byte3; + cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&logicalBlockAddress)->Byte2; + cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&logicalBlockAddress)->Byte1; + cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&logicalBlockAddress)->Byte0; + + cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&transferBlocks)->Byte1; + cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&transferBlocks)->Byte0; + + // + // Set transfer direction flag and Cdb command. + // + + if (currentIrpStack->MajorFunction == IRP_MJ_READ) { + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_RW, "ClassBuildRequest: Read Command\n")); + + SrbSetSrbFlags(srbHeader, SRB_FLAGS_DATA_IN); + cdb->CDB10.OperationCode = SCSIOP_READ; + + } else { + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_RW, "ClassBuildRequest: Write Command\n")); + + SrbSetSrbFlags(srbHeader, SRB_FLAGS_DATA_OUT); + cdb->CDB10.OperationCode = SCSIOP_WRITE; + + } + + // + // If this is not a write-through request, then allow caching. + // + + if (!(currentIrpStack->Flags & SL_WRITE_THROUGH)) { + + SrbSetSrbFlags(srbHeader, SRB_FLAGS_ADAPTER_CACHE_ENABLE); + + } else { + + // + // If write caching is enable then force media access in the + // cdb. + // + + cdb->CDB10.ForceUnitAccess = FdoExtension->CdbForceUnitAccess; + } + + if (TEST_FLAG(Irp->Flags, (IRP_PAGING_IO | IRP_SYNCHRONOUS_PAGING_IO))) { + SrbSetSrbFlags(srbHeader, SRB_CLASS_FLAGS_PAGING); + } + + // + // OR in the default flags from the device object. + // + + SrbSetSrbFlags(srbHeader, FdoExtension->SrbFlags); + + // + // Set up major SCSI function. + // + + nextIrpStack->MajorFunction = IRP_MJ_SCSI; + + // + // Save SRB address in next stack for port driver. + // + + nextIrpStack->Parameters.Scsi.Srb = Srb; + + // + // Save retry count in current IRP stack. + // + + currentIrpStack->Parameters.Others.Argument4 = (PVOID)MAXIMUM_RETRIES; + + // + // Set up IoCompletion routine address. + // + + IoSetCompletionRoutine(Irp, ClassIoComplete, Srb, TRUE, TRUE, TRUE); + +} + + +VOID ClasspInsertCScanList(IN PLIST_ENTRY ListHead, IN PCSCAN_LIST_ENTRY Entry) +{ + PCSCAN_LIST_ENTRY t; + + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "ClasspInsertCScanList is OBSOLETE !")); + + // + // Iterate through the list. Insert this entry in the sorted list in + // order (after other requests for the same block). At each stop if + // blockNumber(Entry) >= blockNumber(t) then move on. + // + + for(t = (PCSCAN_LIST_ENTRY) ListHead->Flink; + t != (PCSCAN_LIST_ENTRY) ListHead; + t = (PCSCAN_LIST_ENTRY) t->Entry.Flink) { + + if(Entry->BlockNumber < t->BlockNumber) { + + // + // Set the pointers in entry to the right location. + // + + Entry->Entry.Flink = &(t->Entry); + Entry->Entry.Blink = t->Entry.Blink; + + // + // Set the pointers in the surrounding elements to refer to us. + // + + t->Entry.Blink->Flink = &(Entry->Entry); + t->Entry.Blink = &(Entry->Entry); + return; + } + } + + // + // Insert this entry at the tail of the list. If the list was empty this + // will also be the head of the list. + // + + InsertTailList(ListHead, &(Entry->Entry)); + +} + + +VOID ClassInsertCScanList(IN PCSCAN_LIST List, IN PIRP Irp, IN ULONGLONG BlockNumber, IN BOOLEAN LowPriority) +/*++ + +Routine Description: + + This routine inserts an entry into the CScan list based on it's block number + and priority. It is assumed that the caller is providing synchronization + to the access of the list. + + Low priority requests are always scheduled to run on the next sweep across + the disk. Normal priority requests will be inserted into the current or + next sweep based on the standard C-SCAN algorithm. + +Arguments: + + List - the list to insert into + + Irp - the irp to be inserted. + + BlockNumber - the block number for this request. + + LowPriority - indicates that the request is lower priority and should be + done on the next sweep across the disk. + +Return Value: + + none + +--*/ +{ + PCSCAN_LIST_ENTRY entry = (PCSCAN_LIST_ENTRY)Irp->Tail.Overlay.DriverContext; + + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "ClassInsertCScanList is OBSOLETE !")); + + // + // Set the block number in the entry. We need this to keep the list sorted. + // + entry->BlockNumber = BlockNumber; + + // + // If it's a normal priority request and further down the disk than our + // current position then insert this entry into the current sweep. + // + + if((LowPriority != TRUE) && (BlockNumber > List->BlockNumber)) { + ClasspInsertCScanList(&(List->CurrentSweep), entry); + } else { + ClasspInsertCScanList(&(List->NextSweep), entry); + } + return; +} + + + +VOID ClassFreeOrReuseSrb( IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, + IN __drv_freesMem(mem) PSCSI_REQUEST_BLOCK Srb) +/*++ + +Routine Description: + + This routine will attempt to reuse the provided SRB to start a blocked + read/write request. + If there is no need to reuse the request it will be returned + to the SRB lookaside list. + +Arguments: + + Fdo - the device extension + + Srb - the SRB which is to be reused or freed. + +Return Value: + + none. + +--*/ + +{ + PCOMMON_DEVICE_EXTENSION commonExt = &FdoExtension->CommonExtension; + + // This function is obsolete, but still called by DISK.SYS . + // TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "ClassFreeOrReuseSrb is OBSOLETE !")); + + // + // safety net. this should never occur. if it does, it's a potential + // memory leak. + // + NT_ASSERT(!TEST_FLAG(SrbGetSrbFlags(Srb), SRB_FLAGS_FREE_SENSE_BUFFER)); + + if (commonExt->IsSrbLookasideListInitialized){ + /* + * Put the SRB back in our lookaside list. + * + * Note: Some class drivers use ClassIoComplete + * to complete SRBs that they themselves allocated. + * So we may be putting a "foreign" SRB + * (e.g. with a different pool tag) into our lookaside list. + */ + ClasspFreeSrb(FdoExtension, Srb); + } + else { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,"ClassFreeOrReuseSrb: someone is trying to use an uninitialized SrbLookasideList !!!")); + FREE_POOL(Srb); + } +} + + +/*++//////////////////////////////////////////////////////////////////////////// + +ClassDeleteSrbLookasideList() + +Routine Description: + + This routine deletes a lookaside listhead for srbs, and should be called + only during the final removal. + + If called at other times, the caller is responsible for + synchronization and removal issues. + +Arguments: + + CommonExtension - Pointer to the CommonExtension containing the listhead. + +Return Value: + + None + +--*/ +_IRQL_requires_max_(PASSIVE_LEVEL) +VOID ClassDeleteSrbLookasideList(_Inout_ PCOMMON_DEVICE_EXTENSION CommonExtension) +{ + PAGED_CODE(); + + // This function is obsolete, but is still called by some of our code. + // TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "ClassDeleteSrbLookasideList is OBSOLETE !")); + + if (CommonExtension->IsSrbLookasideListInitialized){ + CommonExtension->IsSrbLookasideListInitialized = FALSE; + ExDeleteNPagedLookasideList(&CommonExtension->SrbLookasideList); + } + else { + TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "ClassDeleteSrbLookasideList: attempt to delete uninitialized or freed srblookasidelist")); + } +} + + +/*++//////////////////////////////////////////////////////////////////////////// + +ClassInitializeSrbLookasideList() + +Routine Description: + + This routine sets up a lookaside listhead for srbs, and should be called + only from the ClassInitDevice() routine to prevent race conditions. + + If called from other locations, the caller is responsible for + synchronization and removal issues. + +Arguments: + + CommonExtension - Pointer to the CommonExtension containing the listhead. + + NumberElements - Supplies the maximum depth of the lookaside list. + + +Note: + + The Windows 2000 version of classpnp did not return any status value from + this call. + +--*/ + +_IRQL_requires_max_(PASSIVE_LEVEL) +VOID ClassInitializeSrbLookasideList( _Inout_ PCOMMON_DEVICE_EXTENSION CommonExtension, + _In_ ULONG NumberElements) +{ + size_t sizeNeeded; + PFUNCTIONAL_DEVICE_EXTENSION fdo; + + PAGED_CODE(); + + // This function is obsolete, but still called by DISK.SYS . + // TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "ClassInitializeSrbLookasideList is OBSOLETE !")); + + NT_ASSERT(!CommonExtension->IsSrbLookasideListInitialized); + if (!CommonExtension->IsSrbLookasideListInitialized){ + + if (CommonExtension->IsFdo == TRUE) { + fdo = (PFUNCTIONAL_DEVICE_EXTENSION)CommonExtension; + + // + // Check FDO extension on the SRB type supported + // + if (fdo->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { + + // + // It's 16 byte CDBs for now. Need to change when classpnp uses >16 + // byte CDBs or support new address types. + // + sizeNeeded = CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE; + + } else { + sizeNeeded = sizeof(SCSI_REQUEST_BLOCK); + } + + } else { + + // + // For PDO, use the max of old and new SRB as can't guarantee we can get + // corresponding FDO to determine SRB support. + // + sizeNeeded = max(sizeof(SCSI_REQUEST_BLOCK), CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE); + } + + ExInitializeNPagedLookasideList(&CommonExtension->SrbLookasideList, + NULL, + NULL, + POOL_NX_ALLOCATION, + sizeNeeded, + '$scS', + (USHORT)NumberElements); + + CommonExtension->IsSrbLookasideListInitialized = TRUE; + } + +} + + + + +VOID ClasspInitializeCScanList(IN PCSCAN_LIST List) +{ + PAGED_CODE(); + RtlZeroMemory(List, sizeof(CSCAN_LIST)); + InitializeListHead(&(List->CurrentSweep)); + InitializeListHead(&(List->NextSweep)); +} + + + +VOID ClasspStartNextSweep(PCSCAN_LIST List) +{ + NT_ASSERT(IsListEmpty(&(List->CurrentSweep)) == TRUE); + + // + // If the next sweep is empty then there's nothing to do. + // + + if(IsListEmpty(&(List->NextSweep))) { + return; + } + + // + // Copy the next sweep list head into the current sweep list head. + // + + List->CurrentSweep = List->NextSweep; + + // + // Unlink the next sweep list from the list head now that we have a copy + // of it. + // + + InitializeListHead(&(List->NextSweep)); + + // + // Update the next sweep list to point back to the current sweep list head. + // + + List->CurrentSweep.Flink->Blink = &(List->CurrentSweep); + List->CurrentSweep.Blink->Flink = &(List->CurrentSweep); + + return; +} + + + +PIRP ClassRemoveCScanList(IN PCSCAN_LIST List) +{ + PCSCAN_LIST_ENTRY entry; + + // + // If the current sweep is empty then promote the next sweep. + // + + if(IsListEmpty(&(List->CurrentSweep))) { + ClasspStartNextSweep(List); + } + + // + // If the current sweep is still empty then we're done. + // + + if(IsListEmpty(&(List->CurrentSweep))) { + return NULL; + } + + // + // Remove the head entry from the current sweep. Record it's block number + // so that nothing before it on the disk gets into the current sweep. + // + + entry = (PCSCAN_LIST_ENTRY) RemoveHeadList(&(List->CurrentSweep)); + + List->BlockNumber = entry->BlockNumber; + + return CONTAINING_RECORD(entry, IRP, Tail.Overlay.DriverContext); +} |
