PTRANSFER_PACKET DequeueFreeTransferPacket(PDEVICE_OBJECT Fdo, BOOLEAN AllocIfNeeded) { PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension; PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData; PTRANSFER_PACKET pkt; PSLIST_ENTRY slistEntry; slistEntry = InterlockedPopEntrySList(&fdoData->FreeTransferPacketsList); if (slistEntry){ slistEntry->Next = NULL; pkt = CONTAINING_RECORD(slistEntry, TRANSFER_PACKET, SlistEntry); InterlockedDecrement(&fdoData->NumFreeTransferPackets); // when dequeue'ing the packet, also reset the history data HISTORYINITIALIZERETRYLOGS(pkt); } else { if (AllocIfNeeded){ /* * We are in stress and have run out of lookaside packets. * In order to service the current transfer, * allocate an extra packet. * We will free it lazily when we are out of stress. */ pkt = NewTransferPacket(Fdo); if (pkt){ InterlockedIncrement(&fdoData->NumTotalTransferPackets); fdoData->DbgPeakNumTransferPackets = max(fdoData->DbgPeakNumTransferPackets, fdoData->NumTotalTransferPackets); } else { TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_RW, "DequeueFreeTransferPacket: packet allocation failed")); } } else { pkt = NULL; } } return pkt; }
PTRANSFER_PACKET DequeueFreeTransferPacket(PDEVICE_OBJECT Fdo, BOOLEAN AllocIfNeeded) { PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension; PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData; PTRANSFER_PACKET pkt; PSINGLE_LIST_ENTRY slistEntry; KIRQL oldIrql; slistEntry = InterlockedPopEntrySList(&fdoData->FreeTransferPacketsList); if (slistEntry){ slistEntry->Next = NULL; pkt = CONTAINING_RECORD(slistEntry, TRANSFER_PACKET, SlistEntry); ASSERT(fdoData->NumFreeTransferPackets > 0); InterlockedDecrement(&fdoData->NumFreeTransferPackets); } else { if (AllocIfNeeded){ /* * We are in stress and have run out of lookaside packets. * In order to service the current transfer, * allocate an extra packet. * We will free it lazily when we are out of stress. */ pkt = NewTransferPacket(Fdo); if (pkt){ InterlockedIncrement(&fdoData->NumTotalTransferPackets); fdoData->DbgPeakNumTransferPackets = max(fdoData->DbgPeakNumTransferPackets, fdoData->NumTotalTransferPackets); } else { DBGWARN(("DequeueFreeTransferPacket: packet allocation failed")); } } else { pkt = NULL; } } return pkt; }
/* * InitializeTransferPackets * * Allocate/initialize TRANSFER_PACKETs and related resources. */ NTSTATUS InitializeTransferPackets(PDEVICE_OBJECT Fdo) { PCOMMON_DEVICE_EXTENSION commonExt = Fdo->DeviceExtension; PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension; PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData; PSTORAGE_ADAPTER_DESCRIPTOR adapterDesc = commonExt->PartitionZeroExtension->AdapterDescriptor; ULONG hwMaxPages; NTSTATUS status = STATUS_SUCCESS; PAGED_CODE(); /* * Precompute the maximum transfer length */ ASSERT(adapterDesc->MaximumTransferLength); ASSERT(adapterDesc->MaximumPhysicalPages); hwMaxPages = adapterDesc->MaximumPhysicalPages ? adapterDesc->MaximumPhysicalPages-1 : 0; #if defined(_AMD64_SIMULATOR_) // // The simulator appears to have a problem with large transfers. // if (hwMaxPages > 4) { hwMaxPages = 4; } #endif fdoData->HwMaxXferLen = MIN(adapterDesc->MaximumTransferLength, hwMaxPages << PAGE_SHIFT); fdoData->HwMaxXferLen = MAX(fdoData->HwMaxXferLen, PAGE_SIZE); fdoData->NumTotalTransferPackets = 0; fdoData->NumFreeTransferPackets = 0; InitializeSListHead(&fdoData->FreeTransferPacketsList); InitializeListHead(&fdoData->AllTransferPacketsList); InitializeListHead(&fdoData->DeferredClientIrpList); /* * Set the packet threshold numbers based on the Windows SKU. */ if (ExVerifySuite(Personal)){ // this is Windows Personal MinWorkingSetTransferPackets = MIN_WORKINGSET_TRANSFER_PACKETS_Consumer; MaxWorkingSetTransferPackets = MAX_WORKINGSET_TRANSFER_PACKETS_Consumer; } else if (ExVerifySuite(Enterprise) || ExVerifySuite(DataCenter)){ // this is Advanced Server or Datacenter MinWorkingSetTransferPackets = MIN_WORKINGSET_TRANSFER_PACKETS_Enterprise; MaxWorkingSetTransferPackets = MAX_WORKINGSET_TRANSFER_PACKETS_Enterprise; } else if (ExVerifySuite(TerminalServer)){ // this is standard Server or Pro with terminal server MinWorkingSetTransferPackets = MIN_WORKINGSET_TRANSFER_PACKETS_Server; MaxWorkingSetTransferPackets = MAX_WORKINGSET_TRANSFER_PACKETS_Server; } else { // this is Professional without terminal server MinWorkingSetTransferPackets = MIN_WORKINGSET_TRANSFER_PACKETS_Consumer; MaxWorkingSetTransferPackets = MAX_WORKINGSET_TRANSFER_PACKETS_Consumer; } while (fdoData->NumFreeTransferPackets < MIN_INITIAL_TRANSFER_PACKETS){ PTRANSFER_PACKET pkt = NewTransferPacket(Fdo); if (pkt){ InterlockedIncrement(&fdoData->NumTotalTransferPackets); EnqueueFreeTransferPacket(Fdo, pkt); } else { status = STATUS_INSUFFICIENT_RESOURCES; break; } } fdoData->DbgPeakNumTransferPackets = fdoData->NumTotalTransferPackets; /* * Pre-initialize our SCSI_REQUEST_BLOCK template with all * the constant fields. This will save a little time for each xfer. * NOTE: a CdbLength field of 10 may not always be appropriate */ RtlZeroMemory(&fdoData->SrbTemplate, sizeof(SCSI_REQUEST_BLOCK)); fdoData->SrbTemplate.Length = sizeof(SCSI_REQUEST_BLOCK); fdoData->SrbTemplate.Function = SRB_FUNCTION_EXECUTE_SCSI; fdoData->SrbTemplate.QueueAction = SRB_SIMPLE_TAG_REQUEST; fdoData->SrbTemplate.SenseInfoBufferLength = sizeof(SENSE_DATA); fdoData->SrbTemplate.CdbLength = 10; return status; }
/* * InitializeTransferPackets * * Allocate/initialize TRANSFER_PACKETs and related resources. */ NTSTATUS InitializeTransferPackets(PDEVICE_OBJECT Fdo) { PCOMMON_DEVICE_EXTENSION commonExt = Fdo->DeviceExtension; PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension; PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData; PSTORAGE_ADAPTER_DESCRIPTOR adapterDesc = commonExt->PartitionZeroExtension->AdapterDescriptor; ULONG hwMaxPages; NTSTATUS status = STATUS_SUCCESS; PAGED_CODE(); /* * Precompute the maximum transfer length */ ASSERT(adapterDesc->MaximumTransferLength); hwMaxPages = adapterDesc->MaximumPhysicalPages ? adapterDesc->MaximumPhysicalPages-1 : 0; fdoData->HwMaxXferLen = MIN(adapterDesc->MaximumTransferLength, hwMaxPages << PAGE_SHIFT); fdoData->HwMaxXferLen = MAX(fdoData->HwMaxXferLen, PAGE_SIZE); fdoData->NumTotalTransferPackets = 0; fdoData->NumFreeTransferPackets = 0; InitializeSListHead(&fdoData->FreeTransferPacketsList); InitializeListHead(&fdoData->AllTransferPacketsList); InitializeListHead(&fdoData->DeferredClientIrpList); /* * Set the packet threshold numbers based on the Windows SKU. */ if (ExVerifySuite(Personal)){ // this is Windows Personal MinWorkingSetTransferPackets = MIN_WORKINGSET_TRANSFER_PACKETS_Consumer; MaxWorkingSetTransferPackets = MAX_WORKINGSET_TRANSFER_PACKETS_Consumer; } else if (ExVerifySuite(Enterprise) || ExVerifySuite(DataCenter)){ // this is Advanced Server or Datacenter MinWorkingSetTransferPackets = MIN_WORKINGSET_TRANSFER_PACKETS_Enterprise; MaxWorkingSetTransferPackets = MAX_WORKINGSET_TRANSFER_PACKETS_Enterprise; } else if (ExVerifySuite(TerminalServer)){ // this is standard Server or Pro with terminal server MinWorkingSetTransferPackets = MIN_WORKINGSET_TRANSFER_PACKETS_Server; MaxWorkingSetTransferPackets = MAX_WORKINGSET_TRANSFER_PACKETS_Server; } else { // this is Professional without terminal server MinWorkingSetTransferPackets = MIN_WORKINGSET_TRANSFER_PACKETS_Consumer; MaxWorkingSetTransferPackets = MAX_WORKINGSET_TRANSFER_PACKETS_Consumer; } fdoData->LocalMinWorkingSetTransferPackets = MinWorkingSetTransferPackets; fdoData->LocalMaxWorkingSetTransferPackets = MaxWorkingSetTransferPackets; /* * Allow class driver to override the settings */ if (commonExt->DriverExtension->WorkingSet != NULL) { PCLASS_WORKING_SET workingSet = commonExt->DriverExtension->WorkingSet; // override only if non-zero if (workingSet->XferPacketsWorkingSetMinimum != 0) { fdoData->LocalMinWorkingSetTransferPackets = workingSet->XferPacketsWorkingSetMinimum; // adjust maximum upwards if needed if (fdoData->LocalMaxWorkingSetTransferPackets < fdoData->LocalMinWorkingSetTransferPackets) { fdoData->LocalMaxWorkingSetTransferPackets = fdoData->LocalMinWorkingSetTransferPackets; } } // override only if non-zero if (workingSet->XferPacketsWorkingSetMaximum != 0) { fdoData->LocalMaxWorkingSetTransferPackets = workingSet->XferPacketsWorkingSetMaximum; // adjust minimum downwards if needed if (fdoData->LocalMinWorkingSetTransferPackets > fdoData->LocalMaxWorkingSetTransferPackets) { fdoData->LocalMinWorkingSetTransferPackets = fdoData->LocalMaxWorkingSetTransferPackets; } } // that's all the adjustments required/allowed } // end working set size special code while (fdoData->NumFreeTransferPackets < MIN_INITIAL_TRANSFER_PACKETS){ PTRANSFER_PACKET pkt = NewTransferPacket(Fdo); if (pkt){ InterlockedIncrement(&fdoData->NumTotalTransferPackets); EnqueueFreeTransferPacket(Fdo, pkt); } else { status = STATUS_INSUFFICIENT_RESOURCES; break; } } fdoData->DbgPeakNumTransferPackets = fdoData->NumTotalTransferPackets; /* * Pre-initialize our SCSI_REQUEST_BLOCK template with all * the constant fields. This will save a little time for each xfer. * NOTE: a CdbLength field of 10 may not always be appropriate */ RtlZeroMemory(&fdoData->SrbTemplate, sizeof(SCSI_REQUEST_BLOCK)); fdoData->SrbTemplate.Length = sizeof(SCSI_REQUEST_BLOCK); fdoData->SrbTemplate.Function = SRB_FUNCTION_EXECUTE_SCSI; fdoData->SrbTemplate.QueueAction = SRB_SIMPLE_TAG_REQUEST; fdoData->SrbTemplate.SenseInfoBufferLength = sizeof(SENSE_DATA); fdoData->SrbTemplate.CdbLength = 10; return status; }