1 /*++ 2 3 Copyright (C) Microsoft Corporation, 1991 - 2010 4 5 Module Name: 6 7 xferpkt.c 8 9 Abstract: 10 11 Packet routines for CLASSPNP 12 13 Environment: 14 15 kernel mode only 16 17 Notes: 18 19 20 Revision History: 21 22 --*/ 23 24 #include "classp.h" 25 #include "debug.h" 26 27 #ifdef DEBUG_USE_WPP 28 #include "xferpkt.tmh" 29 #endif 30 31 #ifdef ALLOC_PRAGMA 32 #pragma alloc_text(PAGE, InitializeTransferPackets) 33 #pragma alloc_text(PAGE, DestroyAllTransferPackets) 34 #pragma alloc_text(PAGE, SetupEjectionTransferPacket) 35 #pragma alloc_text(PAGE, SetupModeSenseTransferPacket) 36 #pragma alloc_text(PAGE, CleanupTransferPacketToWorkingSetSizeWorker) 37 #pragma alloc_text(PAGE, ClasspSetupPopulateTokenTransferPacket) 38 #endif 39 40 /* 41 * InitializeTransferPackets 42 * 43 * Allocate/initialize TRANSFER_PACKETs and related resources. 44 */ 45 NTSTATUS InitializeTransferPackets(PDEVICE_OBJECT Fdo) 46 { 47 PCOMMON_DEVICE_EXTENSION commonExt = Fdo->DeviceExtension; 48 PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension; 49 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData; 50 PSTORAGE_ADAPTER_DESCRIPTOR adapterDesc = commonExt->PartitionZeroExtension->AdapterDescriptor; 51 PSTORAGE_DEVICE_IO_CAPABILITY_DESCRIPTOR devIoCapabilityDesc = NULL; 52 STORAGE_PROPERTY_ID propertyId; 53 OSVERSIONINFOEXW osVersionInfo; 54 ULONG hwMaxPages; 55 ULONG arraySize; 56 ULONG index; 57 ULONG maxOutstandingIOPerLUN; 58 ULONG minWorkingSetTransferPackets; 59 ULONG maxWorkingSetTransferPackets; 60 61 NTSTATUS status = STATUS_SUCCESS; 62 63 PAGED_CODE(); 64 65 // 66 // Precompute the maximum transfer length 67 // 68 NT_ASSERT(adapterDesc->MaximumTransferLength); 69 70 hwMaxPages = adapterDesc->MaximumPhysicalPages ? adapterDesc->MaximumPhysicalPages-1 : 0; 71 72 fdoData->HwMaxXferLen = MIN(adapterDesc->MaximumTransferLength, hwMaxPages << PAGE_SHIFT); 73 fdoData->HwMaxXferLen = MAX(fdoData->HwMaxXferLen, PAGE_SIZE); 74 75 // 76 // Allocate per-node free packet lists 77 // 78 arraySize = KeQueryHighestNodeNumber() + 1; 79 fdoData->FreeTransferPacketsLists = 80 ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned, 81 sizeof(PNL_SLIST_HEADER) * arraySize, 82 CLASS_TAG_PRIVATE_DATA); 83 84 if (fdoData->FreeTransferPacketsLists == NULL) { 85 status = STATUS_INSUFFICIENT_RESOURCES; 86 return status; 87 } 88 89 for (index = 0; index < arraySize; index++) { 90 InitializeSListHead(&(fdoData->FreeTransferPacketsLists[index].SListHeader)); 91 fdoData->FreeTransferPacketsLists[index].NumTotalTransferPackets = 0; 92 fdoData->FreeTransferPacketsLists[index].NumFreeTransferPackets = 0; 93 } 94 95 InitializeListHead(&fdoData->AllTransferPacketsList); 96 97 // 98 // Set the packet threshold numbers based on the Windows Client or Server SKU. 99 // 100 101 osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW); 102 status = RtlGetVersion((POSVERSIONINFOW) &osVersionInfo); 103 104 NT_ASSERT( NT_SUCCESS(status)); 105 106 // 107 // Retrieve info on IO capability supported by port drivers 108 // 109 110 propertyId = StorageDeviceIoCapabilityProperty; 111 status = ClassGetDescriptor(fdoExt->CommonExtension.LowerDeviceObject, 112 &propertyId, 113 (PVOID *)&devIoCapabilityDesc); 114 115 if (NT_SUCCESS(status) && (devIoCapabilityDesc != NULL)) { 116 maxOutstandingIOPerLUN = devIoCapabilityDesc->LunMaxIoCount; 117 FREE_POOL(devIoCapabilityDesc); 118 119 #if DBG 120 fdoData->MaxOutstandingIOPerLUN = maxOutstandingIOPerLUN; 121 #endif 122 123 } else { 124 maxOutstandingIOPerLUN = MAX_OUTSTANDING_IO_PER_LUN_DEFAULT; 125 126 #if DBG 127 fdoData->MaxOutstandingIOPerLUN = 0; 128 #endif 129 130 } 131 132 // 133 // StorageDeviceIoCapabilityProperty support is optional so 134 // ignore any failures. 135 // 136 137 status = STATUS_SUCCESS; 138 139 140 if ((osVersionInfo.wProductType != VER_NT_DOMAIN_CONTROLLER) && 141 (osVersionInfo.wProductType != VER_NT_SERVER)) { 142 143 // this is Client SKU 144 145 minWorkingSetTransferPackets = MIN_WORKINGSET_TRANSFER_PACKETS_Client; 146 147 // Note: the reason we use max here is to guarantee a reasonable large max number 148 // in the case where the port driver may return a very small supported outstanding 149 // IOs. For example, even EMMC drive only reports 1 outstanding IO supported, we 150 // may still want to set this value to be at least 151 // MAX_WORKINGSET_TRANSFER_PACKETS_Client. 152 maxWorkingSetTransferPackets = max(MAX_WORKINGSET_TRANSFER_PACKETS_Client, 153 2 * maxOutstandingIOPerLUN); 154 155 } else { 156 157 // this is Server SKU 158 // Note: the addition max here to make sure we set the min to be at least 159 // MIN_WORKINGSET_TRANSFER_PACKETS_Server_LowerBound no matter what maxOutstandingIOPerLUN 160 // reported. We shouldn't set this value to be smaller than client system. 161 // In other words, the minWorkingSetTransferPackets for server will always between 162 // MIN_WORKINGSET_TRANSFER_PACKETS_Server_LowerBound and MIN_WORKINGSET_TRANSFER_PACKETS_Server_UpperBound 163 164 minWorkingSetTransferPackets = 165 max(MIN_WORKINGSET_TRANSFER_PACKETS_Server_LowerBound, 166 min(MIN_WORKINGSET_TRANSFER_PACKETS_Server_UpperBound, 167 maxOutstandingIOPerLUN)); 168 169 maxWorkingSetTransferPackets = max(MAX_WORKINGSET_TRANSFER_PACKETS_Server, 170 2 * maxOutstandingIOPerLUN); 171 } 172 173 174 fdoData->LocalMinWorkingSetTransferPackets = minWorkingSetTransferPackets; 175 fdoData->LocalMaxWorkingSetTransferPackets = maxWorkingSetTransferPackets; 176 177 // 178 // Allow class driver to override the settings 179 // 180 if (commonExt->DriverExtension->WorkingSet != NULL) { 181 PCLASS_WORKING_SET workingSet = commonExt->DriverExtension->WorkingSet; 182 183 // override only if non-zero 184 if (workingSet->XferPacketsWorkingSetMinimum != 0) 185 { 186 fdoData->LocalMinWorkingSetTransferPackets = workingSet->XferPacketsWorkingSetMinimum; 187 // adjust maximum upwards if needed 188 if (fdoData->LocalMaxWorkingSetTransferPackets < fdoData->LocalMinWorkingSetTransferPackets) 189 { 190 fdoData->LocalMaxWorkingSetTransferPackets = fdoData->LocalMinWorkingSetTransferPackets; 191 } 192 } 193 // override only if non-zero 194 if (workingSet->XferPacketsWorkingSetMaximum != 0) 195 { 196 fdoData->LocalMaxWorkingSetTransferPackets = workingSet->XferPacketsWorkingSetMaximum; 197 // adjust minimum downwards if needed 198 if (fdoData->LocalMinWorkingSetTransferPackets > fdoData->LocalMaxWorkingSetTransferPackets) 199 { 200 fdoData->LocalMinWorkingSetTransferPackets = fdoData->LocalMaxWorkingSetTransferPackets; 201 } 202 } 203 // that's all the adjustments required/allowed 204 } // end working set size special code 205 206 for (index = 0; index < arraySize; index++) { 207 while (fdoData->FreeTransferPacketsLists[index].NumFreeTransferPackets < MIN_INITIAL_TRANSFER_PACKETS){ 208 PTRANSFER_PACKET pkt = NewTransferPacket(Fdo); 209 if (pkt) { 210 InterlockedIncrement((volatile LONG *)&(fdoData->FreeTransferPacketsLists[index].NumTotalTransferPackets)); 211 pkt->AllocateNode = index; 212 EnqueueFreeTransferPacket(Fdo, pkt); 213 } else { 214 status = STATUS_INSUFFICIENT_RESOURCES; 215 break; 216 } 217 } 218 fdoData->FreeTransferPacketsLists[index].DbgPeakNumTransferPackets = fdoData->FreeTransferPacketsLists[index].NumTotalTransferPackets; 219 } 220 221 // 222 // Pre-initialize our SCSI_REQUEST_BLOCK template with all 223 // the constant fields. This will save a little time for each xfer. 224 // NOTE: a CdbLength field of 10 may not always be appropriate 225 // 226 227 if (NT_SUCCESS(status)) { 228 if (fdoExt->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { 229 ULONG ByteSize = 0; 230 231 #if (NTDDI_VERSION >= NTDDI_WINBLUE) 232 if ((fdoExt->MiniportDescriptor != NULL) && 233 (fdoExt->MiniportDescriptor->Size >= RTL_SIZEOF_THROUGH_FIELD(STORAGE_MINIPORT_DESCRIPTOR, ExtraIoInfoSupported)) && 234 (fdoExt->MiniportDescriptor->ExtraIoInfoSupported == TRUE)) { 235 status = CreateStorageRequestBlock((PSTORAGE_REQUEST_BLOCK *)&fdoData->SrbTemplate, 236 fdoExt->AdapterDescriptor->AddressType, 237 DefaultStorageRequestBlockAllocateRoutine, 238 &ByteSize, 239 2, 240 SrbExDataTypeScsiCdb16, 241 SrbExDataTypeIoInfo 242 ); 243 } else { 244 status = CreateStorageRequestBlock((PSTORAGE_REQUEST_BLOCK *)&fdoData->SrbTemplate, 245 fdoExt->AdapterDescriptor->AddressType, 246 DefaultStorageRequestBlockAllocateRoutine, 247 &ByteSize, 248 1, 249 SrbExDataTypeScsiCdb16 250 ); 251 } 252 #else 253 status = CreateStorageRequestBlock((PSTORAGE_REQUEST_BLOCK *)&fdoData->SrbTemplate, 254 fdoExt->AdapterDescriptor->AddressType, 255 DefaultStorageRequestBlockAllocateRoutine, 256 &ByteSize, 257 1, 258 SrbExDataTypeScsiCdb16 259 ); 260 #endif 261 if (NT_SUCCESS(status)) { 262 ((PSTORAGE_REQUEST_BLOCK) fdoData->SrbTemplate)->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI; 263 } else { 264 NT_ASSERT(FALSE); 265 } 266 } else { 267 fdoData->SrbTemplate = ExAllocatePoolWithTag(NonPagedPoolNx, sizeof(SCSI_REQUEST_BLOCK), '-brs'); 268 if (fdoData->SrbTemplate == NULL) { 269 status = STATUS_INSUFFICIENT_RESOURCES; 270 } else { 271 RtlZeroMemory(fdoData->SrbTemplate, sizeof(SCSI_REQUEST_BLOCK)); 272 fdoData->SrbTemplate->Length = sizeof(SCSI_REQUEST_BLOCK); 273 fdoData->SrbTemplate->Function = SRB_FUNCTION_EXECUTE_SCSI; 274 } 275 } 276 } 277 278 if (status == STATUS_SUCCESS) { 279 SrbSetRequestAttribute(fdoData->SrbTemplate, SRB_SIMPLE_TAG_REQUEST); 280 SrbSetSenseInfoBufferLength(fdoData->SrbTemplate, SENSE_BUFFER_SIZE_EX); 281 SrbSetCdbLength(fdoData->SrbTemplate, 10); 282 } 283 284 return status; 285 } 286 287 288 VOID DestroyAllTransferPackets(PDEVICE_OBJECT Fdo) 289 { 290 PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension; 291 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData; 292 TRANSFER_PACKET *pkt; 293 ULONG index; 294 ULONG arraySize; 295 296 PAGED_CODE(); 297 298 // 299 // fdoData->FreeTransferPacketsLists could be NULL if 300 // there was an error during start device. 301 // 302 if (fdoData->FreeTransferPacketsLists != NULL) { 303 304 NT_ASSERT(IsListEmpty(&fdoData->DeferredClientIrpList)); 305 306 arraySize = KeQueryHighestNodeNumber() + 1; 307 for (index = 0; index < arraySize; index++) { 308 pkt = DequeueFreeTransferPacketEx(Fdo, FALSE, index); 309 while (pkt) { 310 DestroyTransferPacket(pkt); 311 InterlockedDecrement((volatile LONG *)&(fdoData->FreeTransferPacketsLists[index].NumTotalTransferPackets)); 312 pkt = DequeueFreeTransferPacketEx(Fdo, FALSE, index); 313 } 314 315 NT_ASSERT(fdoData->FreeTransferPacketsLists[index].NumTotalTransferPackets == 0); 316 } 317 } 318 319 FREE_POOL(fdoData->SrbTemplate); 320 } 321 322 __drv_allocatesMem(Mem) 323 #ifdef _MSC_VER 324 #pragma warning(suppress:28195) // This function may not allocate memory in some error cases. 325 #endif 326 PTRANSFER_PACKET NewTransferPacket(PDEVICE_OBJECT Fdo) 327 { 328 PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension; 329 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData; 330 PTRANSFER_PACKET newPkt = NULL; 331 ULONG transferLength = (ULONG)-1; 332 NTSTATUS status = STATUS_SUCCESS; 333 334 if (NT_SUCCESS(status)) { 335 status = RtlULongAdd(fdoData->HwMaxXferLen, PAGE_SIZE, &transferLength); 336 if (!NT_SUCCESS(status)) { 337 338 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "Integer overflow in calculating transfer packet size.")); 339 status = STATUS_INTEGER_OVERFLOW; 340 } 341 } 342 343 /* 344 * Allocate the actual packet. 345 */ 346 if (NT_SUCCESS(status)) { 347 newPkt = ExAllocatePoolWithTag(NonPagedPoolNx, sizeof(TRANSFER_PACKET), 'pnPC'); 348 if (newPkt == NULL) { 349 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_RW, "Failed to allocate transfer packet.")); 350 status = STATUS_INSUFFICIENT_RESOURCES; 351 } else { 352 RtlZeroMemory(newPkt, sizeof(TRANSFER_PACKET)); 353 newPkt->AllocateNode = KeGetCurrentNodeNumber(); 354 if (fdoExt->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { 355 #if (NTDDI_VERSION >= NTDDI_WINBLUE) 356 if ((fdoExt->MiniportDescriptor != NULL) && 357 (fdoExt->MiniportDescriptor->Size >= RTL_SIZEOF_THROUGH_FIELD(STORAGE_MINIPORT_DESCRIPTOR, ExtraIoInfoSupported)) && 358 (fdoExt->MiniportDescriptor->ExtraIoInfoSupported == TRUE)) { 359 status = CreateStorageRequestBlock((PSTORAGE_REQUEST_BLOCK *)&newPkt->Srb, 360 fdoExt->AdapterDescriptor->AddressType, 361 DefaultStorageRequestBlockAllocateRoutine, 362 NULL, 363 2, 364 SrbExDataTypeScsiCdb16, 365 SrbExDataTypeIoInfo 366 ); 367 } else { 368 status = CreateStorageRequestBlock((PSTORAGE_REQUEST_BLOCK *)&newPkt->Srb, 369 fdoExt->AdapterDescriptor->AddressType, 370 DefaultStorageRequestBlockAllocateRoutine, 371 NULL, 372 1, 373 SrbExDataTypeScsiCdb16 374 ); 375 } 376 #else 377 status = CreateStorageRequestBlock((PSTORAGE_REQUEST_BLOCK *)&newPkt->Srb, 378 fdoExt->AdapterDescriptor->AddressType, 379 DefaultStorageRequestBlockAllocateRoutine, 380 NULL, 381 1, 382 SrbExDataTypeScsiCdb16 383 ); 384 #endif 385 } else { 386 #ifdef _MSC_VER 387 #pragma prefast(suppress:6014, "The allocated memory that Pkt->Srb points to will be freed in DestroyTransferPacket().") 388 #endif 389 newPkt->Srb = ExAllocatePoolWithTag(NonPagedPoolNx, sizeof(SCSI_REQUEST_BLOCK), '-brs'); 390 if (newPkt->Srb == NULL) { 391 status = STATUS_INSUFFICIENT_RESOURCES; 392 } 393 394 } 395 396 if (status != STATUS_SUCCESS) 397 { 398 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_RW, "Failed to allocate SRB.")); 399 FREE_POOL(newPkt); 400 } 401 } 402 } 403 404 /* 405 * Allocate Irp for the packet. 406 */ 407 if (NT_SUCCESS(status) && newPkt != NULL) { 408 newPkt->Irp = IoAllocateIrp(Fdo->StackSize, FALSE); 409 if (newPkt->Irp == NULL) { 410 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_RW, "Failed to allocate IRP for transfer packet.")); 411 status = STATUS_INSUFFICIENT_RESOURCES; 412 } 413 } 414 415 /* 416 * Allocate a MDL. Add one page to the length to insure an extra page 417 * entry is allocated if the buffer does not start on page boundaries. 418 */ 419 if (NT_SUCCESS(status) && newPkt != NULL) { 420 421 NT_ASSERT(transferLength != (ULONG)-1); 422 423 newPkt->PartialMdl = IoAllocateMdl(NULL, 424 transferLength, 425 FALSE, 426 FALSE, 427 NULL); 428 if (newPkt->PartialMdl == NULL) { 429 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_RW, "Failed to allocate MDL for transfer packet.")); 430 status = STATUS_INSUFFICIENT_RESOURCES; 431 } else { 432 NT_ASSERT(newPkt->PartialMdl->Size >= (CSHORT)(sizeof(MDL) + BYTES_TO_PAGES(fdoData->HwMaxXferLen) * sizeof(PFN_NUMBER))); 433 } 434 435 } 436 437 /* 438 * Allocate per-packet retry history, if required 439 */ 440 if (NT_SUCCESS(status) && 441 (fdoData->InterpretSenseInfo != NULL) && 442 (newPkt != NULL) 443 ) { 444 // attempt to allocate also the history 445 ULONG historyByteCount = 0; 446 447 // SAL annotation and ClassInitializeEx() should both catch this case 448 NT_ASSERT(fdoData->InterpretSenseInfo->HistoryCount != 0); 449 _Analysis_assume_(fdoData->InterpretSenseInfo->HistoryCount != 0); 450 451 historyByteCount = sizeof(SRB_HISTORY_ITEM) * fdoData->InterpretSenseInfo->HistoryCount; 452 historyByteCount += sizeof(SRB_HISTORY) - sizeof(SRB_HISTORY_ITEM); 453 454 newPkt->RetryHistory = (PSRB_HISTORY)ExAllocatePoolWithTag(NonPagedPoolNx, historyByteCount, 'hrPC'); 455 456 if (newPkt->RetryHistory == NULL) { 457 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_RW, "Failed to allocate MDL for transfer packet.")); 458 status = STATUS_INSUFFICIENT_RESOURCES; 459 } else { 460 // call this routine directly once since it's the first initialization of 461 // the structure and the internal maximum count field is not yet setup. 462 HistoryInitializeRetryLogs(newPkt->RetryHistory, fdoData->InterpretSenseInfo->HistoryCount); 463 } 464 } 465 466 /* 467 * Enqueue the packet in our static AllTransferPacketsList 468 * (just so we can find it during debugging if its stuck somewhere). 469 */ 470 if (NT_SUCCESS(status) && newPkt != NULL) 471 { 472 KIRQL oldIrql; 473 newPkt->Fdo = Fdo; 474 #if DBG 475 newPkt->DbgPktId = InterlockedIncrement((volatile LONG *)&fdoData->DbgMaxPktId); 476 #endif 477 KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql); 478 InsertTailList(&fdoData->AllTransferPacketsList, &newPkt->AllPktsListEntry); 479 KeReleaseSpinLock(&fdoData->SpinLock, oldIrql); 480 481 } else { 482 // free any resources acquired above (in reverse order) 483 if (newPkt != NULL) { 484 FREE_POOL(newPkt->RetryHistory); 485 if (newPkt->PartialMdl != NULL) { IoFreeMdl(newPkt->PartialMdl); } 486 if (newPkt->Irp != NULL) { IoFreeIrp(newPkt->Irp); } 487 if (newPkt->Srb != NULL) { FREE_POOL(newPkt->Srb); } 488 FREE_POOL(newPkt); 489 } 490 } 491 492 return newPkt; 493 } 494 495 496 /* 497 * DestroyTransferPacket 498 * 499 */ 500 VOID DestroyTransferPacket(_In_ __drv_freesMem(mem) PTRANSFER_PACKET Pkt) 501 { 502 PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Pkt->Fdo->DeviceExtension; 503 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData; 504 KIRQL oldIrql; 505 506 NT_ASSERT(!Pkt->SlistEntry.Next); 507 // NT_ASSERT(!Pkt->OriginalIrp); 508 509 KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql); 510 511 /* 512 * Delete the packet from our all-packets queue. 513 */ 514 NT_ASSERT(!IsListEmpty(&Pkt->AllPktsListEntry)); 515 NT_ASSERT(!IsListEmpty(&fdoData->AllTransferPacketsList)); 516 RemoveEntryList(&Pkt->AllPktsListEntry); 517 InitializeListHead(&Pkt->AllPktsListEntry); 518 519 KeReleaseSpinLock(&fdoData->SpinLock, oldIrql); 520 521 IoFreeMdl(Pkt->PartialMdl); 522 IoFreeIrp(Pkt->Irp); 523 FREE_POOL(Pkt->RetryHistory); 524 FREE_POOL(Pkt->Srb); 525 FREE_POOL(Pkt); 526 } 527 528 529 VOID EnqueueFreeTransferPacket(PDEVICE_OBJECT Fdo, __drv_aliasesMem PTRANSFER_PACKET Pkt) 530 { 531 PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension; 532 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData; 533 ULONG allocateNode; 534 KIRQL oldIrql; 535 536 NT_ASSERT(!Pkt->SlistEntry.Next); 537 538 allocateNode = Pkt->AllocateNode; 539 InterlockedPushEntrySList(&(fdoData->FreeTransferPacketsLists[allocateNode].SListHeader), &Pkt->SlistEntry); 540 InterlockedIncrement((volatile LONG *)&(fdoData->FreeTransferPacketsLists[allocateNode].NumFreeTransferPackets)); 541 542 /* 543 * If the total number of packets is larger than LocalMinWorkingSetTransferPackets, 544 * that means that we've been in stress. If all those packets are now 545 * free, then we are now out of stress and can free the extra packets. 546 * Attempt to free down to LocalMaxWorkingSetTransferPackets immediately, and 547 * down to LocalMinWorkingSetTransferPackets lazily (one at a time). 548 * However, since we're at DPC, do this is a work item. If the device is removed 549 * or we are unable to allocate the work item, do NOT free more than 550 * MAX_CLEANUP_TRANSFER_PACKETS_AT_ONCE. Subsequent IO completions will end up freeing 551 * up the rest, even if it is MAX_CLEANUP_TRANSFER_PACKETS_AT_ONCE at a time. 552 */ 553 if (fdoData->FreeTransferPacketsLists[allocateNode].NumFreeTransferPackets >= 554 fdoData->FreeTransferPacketsLists[allocateNode].NumTotalTransferPackets) { 555 556 /* 557 * 1. Immediately snap down to our UPPER threshold. 558 */ 559 if (fdoData->FreeTransferPacketsLists[allocateNode].NumTotalTransferPackets > 560 fdoData->LocalMaxWorkingSetTransferPackets) { 561 562 ULONG isRemoved; 563 PIO_WORKITEM workItem = NULL; 564 565 workItem = IoAllocateWorkItem(Fdo); 566 567 // 568 // Acquire a remove lock in order to make sure the device object and its 569 // private data structures will exist when the workitem fires. 570 // The remove lock will be released by the workitem (CleanupTransferPacketToWorkingSetSize). 571 // 572 isRemoved = ClassAcquireRemoveLock(Fdo, (PIRP)workItem); 573 574 if (workItem && !isRemoved) { 575 576 TracePrint((TRACE_LEVEL_INFORMATION, 577 TRACE_FLAG_GENERAL, 578 "EnqueueFreeTransferPacket: Device (%p), queuing work item to clean up free transfer packets.\n", 579 Fdo)); 580 581 // 582 // Queue a work item to trim down the total number of transfer packets to with the 583 // working size. 584 // 585 IoQueueWorkItemEx(workItem, CleanupTransferPacketToWorkingSetSizeWorker, DelayedWorkQueue, (PVOID)(ULONG_PTR)allocateNode); 586 587 } else { 588 589 if (workItem) { 590 IoFreeWorkItem(workItem); 591 } 592 593 if (isRemoved != REMOVE_COMPLETE) { 594 ClassReleaseRemoveLock(Fdo, (PIRP)workItem); 595 } 596 597 TracePrint((TRACE_LEVEL_ERROR, 598 TRACE_FLAG_GENERAL, 599 "EnqueueFreeTransferPacket: Device (%p), Failed to allocate memory for the work item.\n", 600 Fdo)); 601 602 CleanupTransferPacketToWorkingSetSize(Fdo, TRUE, allocateNode); 603 } 604 } 605 606 /* 607 * 2. Lazily work down to our LOWER threshold (by only freeing one packet at a time). 608 */ 609 if (fdoData->FreeTransferPacketsLists[allocateNode].NumTotalTransferPackets > 610 fdoData->LocalMinWorkingSetTransferPackets){ 611 /* 612 * Check the counter again with lock held. This eliminates a race condition 613 * while still allowing us to not grab the spinlock in the common codepath. 614 * 615 * Note that the spinlock does not synchronize with threads dequeuing free 616 * packets to send (DequeueFreeTransferPacket does that with a lightweight 617 * interlocked exchange); the spinlock prevents multiple threads in this function 618 * from deciding to free too many extra packets at once. 619 */ 620 PTRANSFER_PACKET pktToDelete = NULL; 621 622 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_RW, "Exiting stress, lazily freeing one of %d/%d packets from node %d.", 623 fdoData->FreeTransferPacketsLists[allocateNode].NumTotalTransferPackets, 624 fdoData->LocalMinWorkingSetTransferPackets, 625 allocateNode)); 626 627 KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql); 628 if ((fdoData->FreeTransferPacketsLists[allocateNode].NumFreeTransferPackets >= 629 fdoData->FreeTransferPacketsLists[allocateNode].NumTotalTransferPackets) && 630 (fdoData->FreeTransferPacketsLists[allocateNode].NumTotalTransferPackets > 631 fdoData->LocalMinWorkingSetTransferPackets)){ 632 633 pktToDelete = DequeueFreeTransferPacketEx(Fdo, FALSE, allocateNode); 634 if (pktToDelete) { 635 InterlockedDecrement((volatile LONG *)&(fdoData->FreeTransferPacketsLists[allocateNode].NumTotalTransferPackets)); 636 } else { 637 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_RW, 638 "Extremely unlikely condition (non-fatal): %d packets dequeued at once for Fdo %p. NumTotalTransferPackets=%d (2). Node=%d", 639 fdoData->LocalMinWorkingSetTransferPackets, 640 Fdo, 641 fdoData->FreeTransferPacketsLists[allocateNode].NumTotalTransferPackets, 642 allocateNode)); 643 } 644 } 645 KeReleaseSpinLock(&fdoData->SpinLock, oldIrql); 646 647 if (pktToDelete) { 648 DestroyTransferPacket(pktToDelete); 649 } 650 } 651 652 } 653 654 } 655 656 PTRANSFER_PACKET DequeueFreeTransferPacket(PDEVICE_OBJECT Fdo, BOOLEAN AllocIfNeeded) 657 { 658 return DequeueFreeTransferPacketEx(Fdo, AllocIfNeeded, KeGetCurrentNodeNumber()); 659 } 660 661 PTRANSFER_PACKET DequeueFreeTransferPacketEx( 662 _In_ PDEVICE_OBJECT Fdo, 663 _In_ BOOLEAN AllocIfNeeded, 664 _In_ ULONG Node) 665 { 666 PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension; 667 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData; 668 PTRANSFER_PACKET pkt; 669 PSLIST_ENTRY slistEntry; 670 671 slistEntry = InterlockedPopEntrySList(&(fdoData->FreeTransferPacketsLists[Node].SListHeader)); 672 673 if (slistEntry) { 674 slistEntry->Next = NULL; 675 pkt = CONTAINING_RECORD(slistEntry, TRANSFER_PACKET, SlistEntry); 676 InterlockedDecrement((volatile LONG *)&(fdoData->FreeTransferPacketsLists[Node].NumFreeTransferPackets)); 677 678 // when dequeuing the packet, also reset the history data 679 HISTORYINITIALIZERETRYLOGS(pkt); 680 681 } else { 682 if (AllocIfNeeded) { 683 /* 684 * We are in stress and have run out of lookaside packets. 685 * In order to service the current transfer, 686 * allocate an extra packet. 687 * We will free it lazily when we are out of stress. 688 */ 689 pkt = NewTransferPacket(Fdo); 690 if (pkt) { 691 InterlockedIncrement((volatile LONG *)&fdoData->FreeTransferPacketsLists[Node].NumTotalTransferPackets); 692 fdoData->FreeTransferPacketsLists[Node].DbgPeakNumTransferPackets = 693 max(fdoData->FreeTransferPacketsLists[Node].DbgPeakNumTransferPackets, 694 fdoData->FreeTransferPacketsLists[Node].NumTotalTransferPackets); 695 } else { 696 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_RW, "DequeueFreeTransferPacket: packet allocation failed")); 697 } 698 } else { 699 pkt = NULL; 700 } 701 } 702 703 return pkt; 704 } 705 706 707 708 /* 709 * SetupReadWriteTransferPacket 710 * 711 * This function is called once to set up the first attempt to send a packet. 712 * It is not called before a retry, as SRB fields may be modified for the retry. 713 * 714 * Set up the Srb of the TRANSFER_PACKET for the transfer. 715 * The Irp is set up in SubmitTransferPacket because it must be reset 716 * for each packet submission. 717 */ 718 VOID SetupReadWriteTransferPacket( PTRANSFER_PACKET Pkt, 719 PVOID Buf, 720 ULONG Len, 721 LARGE_INTEGER DiskLocation, 722 PIRP OriginalIrp) 723 { 724 PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Pkt->Fdo->DeviceExtension; 725 PCOMMON_DEVICE_EXTENSION commonExtension = Pkt->Fdo->DeviceExtension; 726 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData; 727 PIO_STACK_LOCATION origCurSp = IoGetCurrentIrpStackLocation(OriginalIrp); 728 UCHAR majorFunc = origCurSp->MajorFunction; 729 LARGE_INTEGER logicalBlockAddr; 730 ULONG numTransferBlocks; 731 PCDB pCdb; 732 ULONG srbLength; 733 ULONG timeoutValue = fdoExt->TimeOutValue; 734 735 logicalBlockAddr.QuadPart = Int64ShrlMod32(DiskLocation.QuadPart, fdoExt->SectorShift); 736 numTransferBlocks = Len >> fdoExt->SectorShift; 737 738 /* 739 * This field is useful when debugging, since low-memory conditions are 740 * handled differently for CDROM (which is the only driver using StartIO) 741 */ 742 Pkt->DriverUsesStartIO = (commonExtension->DriverExtension->InitData.ClassStartIo != NULL); 743 744 /* 745 * Slap the constant SRB fields in from our pre-initialized template. 746 * We'll then only have to fill in the unique fields for this transfer. 747 * Tell lower drivers to sort the SRBs by the logical block address 748 * so that disk seeks are minimized. 749 */ 750 if (fdoExt->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { 751 srbLength = ((PSTORAGE_REQUEST_BLOCK) fdoData->SrbTemplate)->SrbLength; 752 NT_ASSERT(((PSTORAGE_REQUEST_BLOCK) Pkt->Srb)->SrbLength >= srbLength); 753 } else { 754 srbLength = fdoData->SrbTemplate->Length; 755 } 756 RtlCopyMemory(Pkt->Srb, fdoData->SrbTemplate, srbLength); // copies _contents_ of SRB blocks 757 SrbSetDataBuffer(Pkt->Srb, Buf); 758 SrbSetDataTransferLength(Pkt->Srb, Len); 759 SrbSetQueueSortKey(Pkt->Srb, logicalBlockAddr.LowPart); 760 if (logicalBlockAddr.QuadPart > 0xFFFFFFFF) { 761 // 762 // If the requested LBA is more than max ULONG set the 763 // QueueSortKey to the maximum value, so that these 764 // requests can be added towards the end of the queue. 765 // 766 767 SrbSetQueueSortKey(Pkt->Srb, 0xFFFFFFFF); 768 } 769 SrbSetOriginalRequest(Pkt->Srb, Pkt->Irp); 770 SrbSetSenseInfoBuffer(Pkt->Srb, &Pkt->SrbErrorSenseData); 771 772 773 SrbSetTimeOutValue(Pkt->Srb, timeoutValue); 774 775 /* 776 * Arrange values in CDB in big-endian format. 777 */ 778 pCdb = SrbGetCdb(Pkt->Srb); 779 if (pCdb) { 780 if (TEST_FLAG(fdoExt->DeviceFlags, DEV_USE_16BYTE_CDB)) { 781 REVERSE_BYTES_QUAD(&pCdb->CDB16.LogicalBlock, &logicalBlockAddr); 782 REVERSE_BYTES(&pCdb->CDB16.TransferLength, &numTransferBlocks); 783 pCdb->CDB16.OperationCode = (majorFunc==IRP_MJ_READ) ? SCSIOP_READ16 : SCSIOP_WRITE16; 784 SrbSetCdbLength(Pkt->Srb, 16); 785 } else { 786 pCdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&logicalBlockAddr.LowPart)->Byte3; 787 pCdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&logicalBlockAddr.LowPart)->Byte2; 788 pCdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&logicalBlockAddr.LowPart)->Byte1; 789 pCdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&logicalBlockAddr.LowPart)->Byte0; 790 pCdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&numTransferBlocks)->Byte1; 791 pCdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&numTransferBlocks)->Byte0; 792 pCdb->CDB10.OperationCode = (majorFunc==IRP_MJ_READ) ? SCSIOP_READ : SCSIOP_WRITE; 793 } 794 } 795 796 /* 797 * Set SRB and IRP flags 798 */ 799 SrbAssignSrbFlags(Pkt->Srb, fdoExt->SrbFlags); 800 if (TEST_FLAG(OriginalIrp->Flags, IRP_PAGING_IO) || 801 TEST_FLAG(OriginalIrp->Flags, IRP_SYNCHRONOUS_PAGING_IO)){ 802 SrbSetSrbFlags(Pkt->Srb, SRB_CLASS_FLAGS_PAGING); 803 } 804 SrbSetSrbFlags(Pkt->Srb, (majorFunc==IRP_MJ_READ) ? SRB_FLAGS_DATA_IN : SRB_FLAGS_DATA_OUT); 805 806 /* 807 * Allow caching only if this is not a write-through request. 808 * If write-through and caching is enabled on the device, force 809 * media access. 810 * Ignore SL_WRITE_THROUGH for reads; it's only set because the file handle was opened with WRITE_THROUGH. 811 */ 812 if ((majorFunc == IRP_MJ_WRITE) && TEST_FLAG(origCurSp->Flags, SL_WRITE_THROUGH) && pCdb) { 813 pCdb->CDB10.ForceUnitAccess = fdoExt->CdbForceUnitAccess; 814 } else { 815 SrbSetSrbFlags(Pkt->Srb, SRB_FLAGS_ADAPTER_CACHE_ENABLE); 816 } 817 818 /* 819 * Remember the buf and len in the SRB because miniports 820 * can overwrite SRB.DataTransferLength and we may need it again 821 * for the retry. 822 */ 823 Pkt->BufPtrCopy = Buf; 824 Pkt->BufLenCopy = Len; 825 Pkt->TargetLocationCopy = DiskLocation; 826 827 Pkt->OriginalIrp = OriginalIrp; 828 Pkt->NumRetries = fdoData->MaxNumberOfIoRetries; 829 Pkt->SyncEventPtr = NULL; 830 Pkt->CompleteOriginalIrpWhenLastPacketCompletes = TRUE; 831 #if !defined(__REACTOS__) && NTDDI_VERSION >= NTDDI_WINBLUE 832 Pkt->NumIoTimeoutRetries = fdoData->MaxNumberOfIoRetries; 833 Pkt->NumThinProvisioningRetries = 0; 834 #endif 835 836 837 if (pCdb) { 838 DBGLOGFLUSHINFO(fdoData, TRUE, (BOOLEAN)(pCdb->CDB10.ForceUnitAccess), FALSE); 839 } else { 840 DBGLOGFLUSHINFO(fdoData, TRUE, FALSE, FALSE); 841 } 842 } 843 844 845 /* 846 * SubmitTransferPacket 847 * 848 * Set up the IRP for the TRANSFER_PACKET submission and send it down. 849 */ 850 NTSTATUS SubmitTransferPacket(PTRANSFER_PACKET Pkt) 851 { 852 PCOMMON_DEVICE_EXTENSION commonExtension = Pkt->Fdo->DeviceExtension; 853 PDEVICE_OBJECT nextDevObj = commonExtension->LowerDeviceObject; 854 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Pkt->Fdo->DeviceExtension; 855 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData; 856 BOOLEAN idleRequest = FALSE; 857 PIO_STACK_LOCATION nextSp; 858 859 NT_ASSERT(Pkt->Irp->CurrentLocation == Pkt->Irp->StackCount+1); 860 861 /* 862 * Attach the SRB to the IRP. 863 * The reused IRP's stack location has to be rewritten for each retry 864 * call because IoCompleteRequest clears the stack locations. 865 */ 866 IoReuseIrp(Pkt->Irp, STATUS_NOT_SUPPORTED); 867 868 869 nextSp = IoGetNextIrpStackLocation(Pkt->Irp); 870 nextSp->MajorFunction = IRP_MJ_SCSI; 871 nextSp->Parameters.Scsi.Srb = (PSCSI_REQUEST_BLOCK)Pkt->Srb; 872 873 SrbSetScsiStatus(Pkt->Srb, 0); 874 Pkt->Srb->SrbStatus = 0; 875 SrbSetSenseInfoBufferLength(Pkt->Srb, SENSE_BUFFER_SIZE_EX); 876 877 if (Pkt->CompleteOriginalIrpWhenLastPacketCompletes) { 878 /* 879 * Only dereference the "original IRP"'s stack location 880 * if its a real client irp (as opposed to a static irp 881 * we're using just for result status for one of the non-IO scsi commands). 882 * 883 * For read/write, propagate the storage-specific IRP stack location flags 884 * (e.g. SL_OVERRIDE_VERIFY_VOLUME, SL_WRITE_THROUGH). 885 */ 886 PIO_STACK_LOCATION origCurSp = IoGetCurrentIrpStackLocation(Pkt->OriginalIrp); 887 nextSp->Flags = origCurSp->Flags; 888 } 889 890 // 891 // If the request is not split, we can use the original IRP MDL. If the 892 // request needs to be split, we need to use a partial MDL. The partial MDL 893 // is needed because more than one driver might be mapping the same MDL 894 // and this causes problems. 895 // 896 if (Pkt->UsePartialMdl == FALSE) { 897 Pkt->Irp->MdlAddress = Pkt->OriginalIrp->MdlAddress; 898 } else { 899 IoBuildPartialMdl(Pkt->OriginalIrp->MdlAddress, Pkt->PartialMdl, SrbGetDataBuffer(Pkt->Srb), SrbGetDataTransferLength(Pkt->Srb)); 900 Pkt->Irp->MdlAddress = Pkt->PartialMdl; 901 } 902 903 904 DBGLOGSENDPACKET(Pkt); 905 HISTORYLOGSENDPACKET(Pkt); 906 907 // 908 // Set the original irp here for SFIO. 909 // 910 ClasspSrbSetOriginalIrp(Pkt->Srb, (PVOID) (Pkt->OriginalIrp)); 911 912 // 913 // No need to lock for IdlePrioritySupported, since it will 914 // be modified only at initialization time. 915 // 916 if (fdoData->IdlePrioritySupported == TRUE) { 917 idleRequest = ClasspIsIdleRequest(Pkt->OriginalIrp); 918 if (idleRequest) { 919 InterlockedIncrement(&fdoData->ActiveIdleIoCount); 920 } else { 921 InterlockedIncrement(&fdoData->ActiveIoCount); 922 } 923 } 924 925 IoSetCompletionRoutine(Pkt->Irp, TransferPktComplete, Pkt, TRUE, TRUE, TRUE); 926 return IoCallDriver(nextDevObj, Pkt->Irp); 927 } 928 929 930 NTSTATUS 931 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 932 TransferPktComplete(IN PDEVICE_OBJECT NullFdo, IN PIRP Irp, IN PVOID Context) 933 { 934 PTRANSFER_PACKET pkt = (PTRANSFER_PACKET)Context; 935 PFUNCTIONAL_DEVICE_EXTENSION fdoExt = pkt->Fdo->DeviceExtension; 936 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData; 937 BOOLEAN packetDone = FALSE; 938 BOOLEAN idleRequest = FALSE; 939 ULONG transferLength; 940 LARGE_INTEGER completionTime; 941 ULONGLONG lastIoCompletionTime; 942 943 UNREFERENCED_PARAMETER(NullFdo); 944 945 /* 946 * Put all the assertions and spew in here so we don't have to look at them. 947 */ 948 DBGLOGRETURNPACKET(pkt); 949 DBGCHECKRETURNEDPKT(pkt); 950 HISTORYLOGRETURNEDPACKET(pkt); 951 952 953 completionTime = ClasspGetCurrentTime(); 954 955 // 956 // Record the time at which the last IO completed while snapping the old 957 // value to be used later. This can occur on multiple threads and hence 958 // could be overwritten with an older value. This is OK because this value 959 // is maintained as a heuristic. 960 // 961 962 #ifdef _WIN64 963 #ifndef __REACTOS__ 964 lastIoCompletionTime = ReadULong64NoFence((volatile ULONG64*)&fdoData->LastIoCompletionTime.QuadPart); 965 WriteULong64NoFence((volatile ULONG64*)&fdoData->LastIoCompletionTime.QuadPart, 966 completionTime.QuadPart); 967 #else 968 lastIoCompletionTime = *(volatile ULONG64*)&fdoData->LastIoCompletionTime.QuadPart; 969 *((volatile ULONG64*)&fdoData->LastIoCompletionTime.QuadPart) = completionTime.QuadPart; 970 #endif 971 #else 972 lastIoCompletionTime = InterlockedExchangeNoFence64((volatile LONG64*)&fdoData->LastIoCompletionTime.QuadPart, 973 completionTime.QuadPart); 974 #endif 975 976 if (fdoData->IdlePrioritySupported == TRUE) { 977 idleRequest = ClasspIsIdleRequest(pkt->OriginalIrp); 978 if (idleRequest) { 979 InterlockedDecrement(&fdoData->ActiveIdleIoCount); 980 NT_ASSERT(fdoData->ActiveIdleIoCount >= 0); 981 } else { 982 fdoData->LastNonIdleIoTime = completionTime; 983 InterlockedDecrement(&fdoData->ActiveIoCount); 984 NT_ASSERT(fdoData->ActiveIoCount >= 0); 985 } 986 } 987 988 // 989 // If partial MDL was used, unmap the pages. When the packet is retried, the 990 // MDL will be recreated. If the packet is done, the MDL will be ready to be reused. 991 // 992 if (pkt->UsePartialMdl) { 993 MmPrepareMdlForReuse(pkt->PartialMdl); 994 } 995 996 if (SRB_STATUS(pkt->Srb->SrbStatus) == SRB_STATUS_SUCCESS) { 997 998 NT_ASSERT(NT_SUCCESS(Irp->IoStatus.Status)); 999 1000 transferLength = SrbGetDataTransferLength(pkt->Srb); 1001 1002 fdoData->LoggedTURFailureSinceLastIO = FALSE; 1003 1004 /* 1005 * The port driver should not have allocated a sense buffer 1006 * if the SRB succeeded. 1007 */ 1008 NT_ASSERT(!PORT_ALLOCATED_SENSE_EX(fdoExt, pkt->Srb)); 1009 1010 /* 1011 * Add this packet's transferred length to the original IRP's. 1012 */ 1013 InterlockedExchangeAdd((PLONG)&pkt->OriginalIrp->IoStatus.Information, 1014 (LONG)transferLength); 1015 1016 1017 if ((pkt->InLowMemRetry) || 1018 (pkt->DriverUsesStartIO && pkt->LowMemRetry_remainingBufLen > 0)) { 1019 packetDone = StepLowMemRetry(pkt); 1020 } else { 1021 packetDone = TRUE; 1022 } 1023 1024 } 1025 else { 1026 /* 1027 * The packet failed. We may retry it if possible. 1028 */ 1029 BOOLEAN shouldRetry; 1030 1031 /* 1032 * Make sure IRP status matches SRB error status (since we propagate it). 1033 */ 1034 if (NT_SUCCESS(Irp->IoStatus.Status)){ 1035 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; 1036 } 1037 1038 /* 1039 * The packet failed. 1040 * So when sending the packet down we either saw either an error or STATUS_PENDING, 1041 * and so we returned STATUS_PENDING for the original IRP. 1042 * So now we must mark the original irp pending to match that, _regardless_ of 1043 * whether we actually switch threads here by retrying. 1044 * (We also have to mark the irp pending if the lower driver marked the irp pending; 1045 * that is dealt with farther down). 1046 */ 1047 if (pkt->CompleteOriginalIrpWhenLastPacketCompletes){ 1048 IoMarkIrpPending(pkt->OriginalIrp); 1049 } 1050 1051 /* 1052 * Interpret the SRB error (to a meaningful IRP status) 1053 * and determine if we should retry this packet. 1054 * This call looks at the returned SENSE info to figure out what to do. 1055 */ 1056 shouldRetry = InterpretTransferPacketError(pkt); 1057 1058 /* 1059 * If the SRB queue is locked-up, release it. 1060 * Do this after calling the error handler. 1061 */ 1062 if (pkt->Srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN){ 1063 ClassReleaseQueue(pkt->Fdo); 1064 } 1065 1066 1067 if (NT_SUCCESS(Irp->IoStatus.Status)){ 1068 /* 1069 * The error was recovered above in the InterpretTransferPacketError() call. 1070 */ 1071 1072 NT_ASSERT(!shouldRetry); 1073 1074 /* 1075 * In the case of a recovered error, 1076 * add the transfer length to the original Irp as we would in the success case. 1077 */ 1078 InterlockedExchangeAdd((PLONG)&pkt->OriginalIrp->IoStatus.Information, 1079 (LONG)SrbGetDataTransferLength(pkt->Srb)); 1080 1081 if ((pkt->InLowMemRetry) || 1082 (pkt->DriverUsesStartIO && pkt->LowMemRetry_remainingBufLen > 0)) { 1083 packetDone = StepLowMemRetry(pkt); 1084 } else { 1085 packetDone = TRUE; 1086 } 1087 } else { 1088 if (shouldRetry && (pkt->NumRetries > 0)){ 1089 packetDone = RetryTransferPacket(pkt); 1090 } else if (shouldRetry && (pkt->RetryHistory != NULL)){ 1091 // don't limit retries if class driver has custom interpretation routines 1092 packetDone = RetryTransferPacket(pkt); 1093 } else { 1094 packetDone = TRUE; 1095 } 1096 } 1097 } 1098 1099 /* 1100 * If the packet is completed, put it back in the free list. 1101 * If it is the last packet servicing the original request, complete the original irp. 1102 */ 1103 if (packetDone){ 1104 LONG numPacketsRemaining; 1105 PIRP deferredIrp; 1106 PDEVICE_OBJECT Fdo = pkt->Fdo; 1107 UCHAR uniqueAddr = 0; 1108 1109 /* 1110 * In case a remove is pending, bump the lock count so we don't get freed 1111 * right after we complete the original irp. 1112 */ 1113 ClassAcquireRemoveLock(Fdo, (PVOID)&uniqueAddr); 1114 1115 1116 /* 1117 * Sometimes the port driver can allocates a new 'sense' buffer 1118 * to report transfer errors, e.g. when the default sense buffer 1119 * is too small. If so, it is up to us to free it. 1120 * Now that we're done using the sense info, free it if appropriate. 1121 * Then clear the sense buffer so it doesn't pollute future errors returned in this packet. 1122 */ 1123 if (PORT_ALLOCATED_SENSE_EX(fdoExt, pkt->Srb)) { 1124 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_RW, "Freeing port-allocated sense buffer for pkt %ph.", pkt)); 1125 FREE_PORT_ALLOCATED_SENSE_BUFFER_EX(fdoExt, pkt->Srb); 1126 SrbSetSenseInfoBuffer(pkt->Srb, &pkt->SrbErrorSenseData); 1127 SrbSetSenseInfoBufferLength(pkt->Srb, sizeof(pkt->SrbErrorSenseData)); 1128 } else { 1129 NT_ASSERT(SrbGetSenseInfoBuffer(pkt->Srb) == &pkt->SrbErrorSenseData); 1130 NT_ASSERT(SrbGetSenseInfoBufferLength(pkt->Srb) <= sizeof(pkt->SrbErrorSenseData)); 1131 } 1132 1133 RtlZeroMemory(&pkt->SrbErrorSenseData, sizeof(pkt->SrbErrorSenseData)); 1134 1135 /* 1136 * Call IoSetMasterIrpStatus to set appropriate status 1137 * for the Master IRP. 1138 */ 1139 IoSetMasterIrpStatus(pkt->OriginalIrp, Irp->IoStatus.Status); 1140 1141 if (!NT_SUCCESS(Irp->IoStatus.Status)){ 1142 /* 1143 * If the original I/O originated in user space (i.e. it is thread-queued), 1144 * and the error is user-correctable (e.g. media is missing, for removable media), 1145 * alert the user. 1146 * Since this is only one of possibly several packets completing for the original IRP, 1147 * we may do this more than once for a single request. That's ok; this allows 1148 * us to test each returned status with IoIsErrorUserInduced(). 1149 */ 1150 if (IoIsErrorUserInduced(Irp->IoStatus.Status) && 1151 pkt->CompleteOriginalIrpWhenLastPacketCompletes && 1152 pkt->OriginalIrp->Tail.Overlay.Thread){ 1153 1154 IoSetHardErrorOrVerifyDevice(pkt->OriginalIrp, Fdo); 1155 } 1156 } 1157 1158 /* 1159 * We use a field in the original IRP to count 1160 * down the transfer pieces as they complete. 1161 */ 1162 numPacketsRemaining = InterlockedDecrement( 1163 (PLONG)&pkt->OriginalIrp->Tail.Overlay.DriverContext[0]); 1164 1165 if (numPacketsRemaining > 0){ 1166 /* 1167 * More transfer pieces remain for the original request. 1168 * Wait for them to complete before completing the original irp. 1169 */ 1170 } else { 1171 1172 /* 1173 * All the transfer pieces are done. 1174 * Complete the original irp if appropriate. 1175 */ 1176 NT_ASSERT(numPacketsRemaining == 0); 1177 if (pkt->CompleteOriginalIrpWhenLastPacketCompletes){ 1178 1179 IO_PAGING_PRIORITY priority = (TEST_FLAG(pkt->OriginalIrp->Flags, IRP_PAGING_IO)) ? IoGetPagingIoPriority(pkt->OriginalIrp) : IoPagingPriorityInvalid; 1180 KIRQL oldIrql; 1181 1182 if (NT_SUCCESS(pkt->OriginalIrp->IoStatus.Status)){ 1183 NT_ASSERT((ULONG)pkt->OriginalIrp->IoStatus.Information == IoGetCurrentIrpStackLocation(pkt->OriginalIrp)->Parameters.Read.Length); 1184 ClasspPerfIncrementSuccessfulIo(fdoExt); 1185 } 1186 ClassReleaseRemoveLock(Fdo, pkt->OriginalIrp); 1187 1188 /* 1189 * We submitted all the downward irps, including this last one, on the thread 1190 * that the OriginalIrp came in on. So the OriginalIrp is completing on a 1191 * different thread iff this last downward irp is completing on a different thread. 1192 * If BlkCache is loaded, for example, it will often complete 1193 * requests out of the cache on the same thread, therefore not marking the downward 1194 * irp pending and not requiring us to do so here. If the downward request is completing 1195 * on the same thread, then by not marking the OriginalIrp pending we can save an APC 1196 * and get extra perf benefit out of BlkCache. 1197 * Note that if the packet ever cycled due to retry or LowMemRetry, 1198 * we set the pending bit in those codepaths. 1199 */ 1200 if (pkt->Irp->PendingReturned){ 1201 IoMarkIrpPending(pkt->OriginalIrp); 1202 } 1203 1204 1205 ClassCompleteRequest(Fdo, pkt->OriginalIrp, IO_DISK_INCREMENT); 1206 1207 // 1208 // Drop the count only after completing the request, to give 1209 // Mm some amount of time to issue its next critical request 1210 // 1211 1212 if (priority == IoPagingPriorityHigh) 1213 { 1214 KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql); 1215 1216 if (fdoData->MaxInterleavedNormalIo < ClassMaxInterleavePerCriticalIo) 1217 { 1218 fdoData->MaxInterleavedNormalIo = 0; 1219 } else { 1220 fdoData->MaxInterleavedNormalIo -= ClassMaxInterleavePerCriticalIo; 1221 } 1222 1223 fdoData->NumHighPriorityPagingIo--; 1224 1225 if (fdoData->NumHighPriorityPagingIo == 0) 1226 { 1227 LARGE_INTEGER period; 1228 1229 // 1230 // Exiting throttle mode 1231 // 1232 1233 KeQuerySystemTime(&fdoData->ThrottleStopTime); 1234 1235 period.QuadPart = fdoData->ThrottleStopTime.QuadPart - fdoData->ThrottleStartTime.QuadPart; 1236 fdoData->LongestThrottlePeriod.QuadPart = max(fdoData->LongestThrottlePeriod.QuadPart, period.QuadPart); 1237 } 1238 1239 KeReleaseSpinLock(&fdoData->SpinLock, oldIrql); 1240 } 1241 1242 if (idleRequest) { 1243 ClasspCompleteIdleRequest(fdoExt); 1244 } 1245 1246 /* 1247 * We may have been called by one of the class drivers (e.g. cdrom) 1248 * via the legacy API ClassSplitRequest. 1249 * This is the only case for which the packet engine is called for an FDO 1250 * with a StartIo routine; in that case, we have to call IoStartNextPacket 1251 * now that the original irp has been completed. 1252 */ 1253 if (fdoExt->CommonExtension.DriverExtension->InitData.ClassStartIo) { 1254 if (TEST_FLAG(SrbGetSrbFlags(pkt->Srb), SRB_FLAGS_DONT_START_NEXT_PACKET)){ 1255 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_RW, "SRB_FLAGS_DONT_START_NEXT_PACKET should never be set here (?)")); 1256 } else { 1257 KeRaiseIrql(DISPATCH_LEVEL, &oldIrql); 1258 IoStartNextPacket(Fdo, TRUE); // yes, some IO is now cancellable 1259 KeLowerIrql(oldIrql); 1260 } 1261 } 1262 } 1263 } 1264 1265 /* 1266 * If the packet was synchronous, write the final result back to the issuer's status buffer 1267 * and signal his event. 1268 */ 1269 if (pkt->SyncEventPtr){ 1270 KeSetEvent(pkt->SyncEventPtr, 0, FALSE); 1271 pkt->SyncEventPtr = NULL; 1272 } 1273 1274 /* 1275 * If the operation isn't a normal read/write, but needs to do more 1276 * operation-specific processing, call the operation's continuation 1277 * routine. The operation may create and queue another transfer packet 1278 * within this routine, but pkt is still freed after returning from the 1279 * continuation routine. 1280 */ 1281 if (pkt->ContinuationRoutine != NULL){ 1282 pkt->ContinuationRoutine(pkt->ContinuationContext); 1283 pkt->ContinuationRoutine = NULL; 1284 } 1285 1286 /* 1287 * Free the completed packet. 1288 */ 1289 pkt->UsePartialMdl = FALSE; 1290 // pkt->OriginalIrp = NULL; 1291 pkt->InLowMemRetry = FALSE; 1292 EnqueueFreeTransferPacket(Fdo, pkt); 1293 1294 /* 1295 * Now that we have freed some resources, 1296 * try again to send one of the previously deferred irps. 1297 */ 1298 deferredIrp = DequeueDeferredClientIrp(Fdo); 1299 if (deferredIrp){ 1300 ServiceTransferRequest(Fdo, deferredIrp, TRUE); 1301 } 1302 1303 ClassReleaseRemoveLock(Fdo, (PVOID)&uniqueAddr); 1304 } 1305 1306 return STATUS_MORE_PROCESSING_REQUIRED; 1307 } 1308 1309 1310 /* 1311 * SetupEjectionTransferPacket 1312 * 1313 * Set up a transferPacket for a synchronous Ejection Control transfer. 1314 */ 1315 VOID SetupEjectionTransferPacket( TRANSFER_PACKET *Pkt, 1316 BOOLEAN PreventMediaRemoval, 1317 PKEVENT SyncEventPtr, 1318 PIRP OriginalIrp) 1319 { 1320 PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Pkt->Fdo->DeviceExtension; 1321 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData; 1322 PCDB pCdb; 1323 ULONG srbLength; 1324 1325 PAGED_CODE(); 1326 1327 if (fdoExt->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { 1328 srbLength = ((PSTORAGE_REQUEST_BLOCK) fdoData->SrbTemplate)->SrbLength; 1329 NT_ASSERT(((PSTORAGE_REQUEST_BLOCK) Pkt->Srb)->SrbLength >= srbLength); 1330 } else { 1331 srbLength = fdoData->SrbTemplate->Length; 1332 } 1333 RtlCopyMemory(Pkt->Srb, fdoData->SrbTemplate, srbLength); // copies _contents_ of SRB blocks 1334 1335 SrbSetRequestAttribute(Pkt->Srb, SRB_SIMPLE_TAG_REQUEST); 1336 SrbSetCdbLength(Pkt->Srb, 6); 1337 SrbSetOriginalRequest(Pkt->Srb, Pkt->Irp); 1338 SrbSetSenseInfoBuffer(Pkt->Srb, &Pkt->SrbErrorSenseData); 1339 SrbSetSenseInfoBufferLength(Pkt->Srb, sizeof(Pkt->SrbErrorSenseData)); 1340 SrbSetTimeOutValue(Pkt->Srb, fdoExt->TimeOutValue); 1341 1342 SrbAssignSrbFlags(Pkt->Srb, fdoExt->SrbFlags | SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_QUEUE_FREEZE); 1343 1344 pCdb = SrbGetCdb(Pkt->Srb); 1345 if (pCdb) { 1346 pCdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL; 1347 pCdb->MEDIA_REMOVAL.Prevent = PreventMediaRemoval; 1348 } 1349 1350 Pkt->BufPtrCopy = NULL; 1351 Pkt->BufLenCopy = 0; 1352 1353 Pkt->OriginalIrp = OriginalIrp; 1354 Pkt->NumRetries = NUM_LOCKMEDIAREMOVAL_RETRIES; 1355 Pkt->SyncEventPtr = SyncEventPtr; 1356 Pkt->CompleteOriginalIrpWhenLastPacketCompletes = FALSE; 1357 } 1358 1359 1360 /* 1361 * SetupModeSenseTransferPacket 1362 * 1363 * Set up a transferPacket for a synchronous Mode Sense transfer. 1364 */ 1365 VOID SetupModeSenseTransferPacket(TRANSFER_PACKET *Pkt, 1366 PKEVENT SyncEventPtr, 1367 PVOID ModeSenseBuffer, 1368 UCHAR ModeSenseBufferLen, 1369 UCHAR PageMode, 1370 UCHAR SubPage, 1371 PIRP OriginalIrp, 1372 UCHAR PageControl) 1373 1374 { 1375 PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Pkt->Fdo->DeviceExtension; 1376 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData; 1377 PCDB pCdb; 1378 ULONG srbLength; 1379 1380 PAGED_CODE(); 1381 1382 if (fdoExt->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { 1383 srbLength = ((PSTORAGE_REQUEST_BLOCK) fdoData->SrbTemplate)->SrbLength; 1384 NT_ASSERT(((PSTORAGE_REQUEST_BLOCK) Pkt->Srb)->SrbLength >= srbLength); 1385 } else { 1386 srbLength = fdoData->SrbTemplate->Length; 1387 } 1388 RtlCopyMemory(Pkt->Srb, fdoData->SrbTemplate, srbLength); // copies _contents_ of SRB blocks 1389 1390 SrbSetRequestAttribute(Pkt->Srb, SRB_SIMPLE_TAG_REQUEST); 1391 SrbSetCdbLength(Pkt->Srb, 6); 1392 SrbSetOriginalRequest(Pkt->Srb, Pkt->Irp); 1393 SrbSetSenseInfoBuffer(Pkt->Srb, &Pkt->SrbErrorSenseData); 1394 SrbSetSenseInfoBufferLength(Pkt->Srb, sizeof(Pkt->SrbErrorSenseData)); 1395 SrbSetTimeOutValue(Pkt->Srb, fdoExt->TimeOutValue); 1396 SrbSetDataBuffer(Pkt->Srb, ModeSenseBuffer); 1397 SrbSetDataTransferLength(Pkt->Srb, ModeSenseBufferLen); 1398 1399 1400 SrbAssignSrbFlags(Pkt->Srb, fdoExt->SrbFlags | SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_QUEUE_FREEZE); 1401 1402 pCdb = SrbGetCdb(Pkt->Srb); 1403 if (pCdb) { 1404 pCdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE; 1405 pCdb->MODE_SENSE.PageCode = PageMode; 1406 pCdb->MODE_SENSE.SubPageCode = SubPage; 1407 pCdb->MODE_SENSE.Pc = PageControl; 1408 pCdb->MODE_SENSE.AllocationLength = (UCHAR)ModeSenseBufferLen; 1409 } 1410 1411 Pkt->BufPtrCopy = ModeSenseBuffer; 1412 Pkt->BufLenCopy = ModeSenseBufferLen; 1413 1414 Pkt->OriginalIrp = OriginalIrp; 1415 Pkt->NumRetries = NUM_MODESENSE_RETRIES; 1416 Pkt->SyncEventPtr = SyncEventPtr; 1417 Pkt->CompleteOriginalIrpWhenLastPacketCompletes = FALSE; 1418 } 1419 1420 /* 1421 * SetupModeSelectTransferPacket 1422 * 1423 * Set up a transferPacket for a synchronous Mode Select transfer. 1424 */ 1425 VOID SetupModeSelectTransferPacket(TRANSFER_PACKET *Pkt, 1426 PKEVENT SyncEventPtr, 1427 PVOID ModeSelectBuffer, 1428 UCHAR ModeSelectBufferLen, 1429 BOOLEAN SavePages, 1430 PIRP OriginalIrp) 1431 1432 { 1433 PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Pkt->Fdo->DeviceExtension; 1434 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData; 1435 PCDB pCdb; 1436 ULONG srbLength; 1437 1438 if (fdoExt->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { 1439 srbLength = ((PSTORAGE_REQUEST_BLOCK) fdoData->SrbTemplate)->SrbLength; 1440 NT_ASSERT(((PSTORAGE_REQUEST_BLOCK) Pkt->Srb)->SrbLength >= srbLength); 1441 } else { 1442 srbLength = fdoData->SrbTemplate->Length; 1443 } 1444 RtlCopyMemory(Pkt->Srb, fdoData->SrbTemplate, srbLength); // copies _contents_ of SRB blocks 1445 1446 SrbSetRequestAttribute(Pkt->Srb, SRB_SIMPLE_TAG_REQUEST); 1447 SrbSetCdbLength(Pkt->Srb, 6); 1448 SrbSetOriginalRequest(Pkt->Srb, Pkt->Irp); 1449 SrbSetSenseInfoBuffer(Pkt->Srb, &Pkt->SrbErrorSenseData); 1450 SrbSetSenseInfoBufferLength(Pkt->Srb, sizeof(Pkt->SrbErrorSenseData)); 1451 SrbSetTimeOutValue(Pkt->Srb, fdoExt->TimeOutValue); 1452 SrbSetDataBuffer(Pkt->Srb, ModeSelectBuffer); 1453 SrbSetDataTransferLength(Pkt->Srb, ModeSelectBufferLen); 1454 1455 SrbAssignSrbFlags(Pkt->Srb, fdoExt->SrbFlags | SRB_FLAGS_DATA_OUT | SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_QUEUE_FREEZE); 1456 1457 pCdb = SrbGetCdb(Pkt->Srb); 1458 if (pCdb) { 1459 pCdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT; 1460 pCdb->MODE_SELECT.SPBit = SavePages; 1461 pCdb->MODE_SELECT.PFBit = 1; 1462 pCdb->MODE_SELECT.ParameterListLength = (UCHAR)ModeSelectBufferLen; 1463 } 1464 1465 Pkt->BufPtrCopy = ModeSelectBuffer; 1466 Pkt->BufLenCopy = ModeSelectBufferLen; 1467 1468 Pkt->OriginalIrp = OriginalIrp; 1469 Pkt->NumRetries = NUM_MODESELECT_RETRIES; 1470 Pkt->SyncEventPtr = SyncEventPtr; 1471 Pkt->CompleteOriginalIrpWhenLastPacketCompletes = FALSE; 1472 } 1473 1474 1475 /* 1476 * SetupDriveCapacityTransferPacket 1477 * 1478 * Set up a transferPacket for a synchronous Drive Capacity transfer. 1479 */ 1480 VOID SetupDriveCapacityTransferPacket( TRANSFER_PACKET *Pkt, 1481 PVOID ReadCapacityBuffer, 1482 ULONG ReadCapacityBufferLen, 1483 PKEVENT SyncEventPtr, 1484 PIRP OriginalIrp, 1485 BOOLEAN Use16ByteCdb) 1486 { 1487 PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Pkt->Fdo->DeviceExtension; 1488 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData; 1489 PCDB pCdb; 1490 ULONG srbLength; 1491 ULONG timeoutValue = fdoExt->TimeOutValue; 1492 1493 if (fdoExt->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { 1494 srbLength = ((PSTORAGE_REQUEST_BLOCK) fdoData->SrbTemplate)->SrbLength; 1495 NT_ASSERT(((PSTORAGE_REQUEST_BLOCK) Pkt->Srb)->SrbLength >= srbLength); 1496 } else { 1497 srbLength = fdoData->SrbTemplate->Length; 1498 } 1499 RtlCopyMemory(Pkt->Srb, fdoData->SrbTemplate, srbLength); // copies _contents_ of SRB blocks 1500 1501 SrbSetRequestAttribute(Pkt->Srb, SRB_SIMPLE_TAG_REQUEST); 1502 SrbSetOriginalRequest(Pkt->Srb, Pkt->Irp); 1503 SrbSetSenseInfoBuffer(Pkt->Srb, &Pkt->SrbErrorSenseData); 1504 SrbSetSenseInfoBufferLength(Pkt->Srb, sizeof(Pkt->SrbErrorSenseData)); 1505 1506 1507 SrbSetTimeOutValue(Pkt->Srb, timeoutValue); 1508 SrbSetDataBuffer(Pkt->Srb, ReadCapacityBuffer); 1509 SrbSetDataTransferLength(Pkt->Srb, ReadCapacityBufferLen); 1510 1511 SrbAssignSrbFlags(Pkt->Srb, fdoExt->SrbFlags | SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_QUEUE_FREEZE); 1512 1513 pCdb = SrbGetCdb(Pkt->Srb); 1514 if (pCdb) { 1515 if (Use16ByteCdb == TRUE) { 1516 NT_ASSERT(ReadCapacityBufferLen >= sizeof(READ_CAPACITY_DATA_EX)); 1517 SrbSetCdbLength(Pkt->Srb, 16); 1518 pCdb->CDB16.OperationCode = SCSIOP_READ_CAPACITY16; 1519 REVERSE_BYTES(&pCdb->CDB16.TransferLength, &ReadCapacityBufferLen); 1520 pCdb->AsByte[1] = 0x10; // Service Action 1521 } else { 1522 SrbSetCdbLength(Pkt->Srb, 10); 1523 pCdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY; 1524 } 1525 } 1526 1527 Pkt->BufPtrCopy = ReadCapacityBuffer; 1528 Pkt->BufLenCopy = ReadCapacityBufferLen; 1529 1530 Pkt->OriginalIrp = OriginalIrp; 1531 Pkt->NumRetries = NUM_DRIVECAPACITY_RETRIES; 1532 #if !defined(__REACTOS__) && NTDDI_VERSION >= NTDDI_WINBLUE 1533 Pkt->NumIoTimeoutRetries = NUM_DRIVECAPACITY_RETRIES; 1534 #endif 1535 1536 Pkt->SyncEventPtr = SyncEventPtr; 1537 Pkt->CompleteOriginalIrpWhenLastPacketCompletes = FALSE; 1538 } 1539 1540 1541 #if 0 1542 /* 1543 * SetupSendStartUnitTransferPacket 1544 * 1545 * Set up a transferPacket for a synchronous Send Start Unit transfer. 1546 */ 1547 VOID SetupSendStartUnitTransferPacket( TRANSFER_PACKET *Pkt, 1548 PIRP OriginalIrp) 1549 { 1550 PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Pkt->Fdo->DeviceExtension; 1551 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData; 1552 PCDB pCdb; 1553 1554 PAGED_CODE(); 1555 1556 RtlZeroMemory(&Pkt->Srb, sizeof(SCSI_REQUEST_BLOCK)); 1557 1558 /* 1559 * Initialize the SRB. 1560 * Use a very long timeout value to give the drive time to spin up. 1561 */ 1562 Pkt->Srb->Length = sizeof(SCSI_REQUEST_BLOCK); 1563 Pkt->Srb->Function = SRB_FUNCTION_EXECUTE_SCSI; 1564 Pkt->Srb->TimeOutValue = START_UNIT_TIMEOUT; 1565 Pkt->Srb->CdbLength = 6; 1566 Pkt->Srb->OriginalRequest = Pkt->Irp; 1567 Pkt->Srb->SenseInfoBuffer = &Pkt->SrbErrorSenseData; 1568 Pkt->Srb->SenseInfoBufferLength = sizeof(Pkt->SrbErrorSenseData); 1569 Pkt->Srb->Lun = 0; 1570 1571 SET_FLAG(Pkt->Srb->SrbFlags, SRB_FLAGS_NO_DATA_TRANSFER); 1572 SET_FLAG(Pkt->Srb->SrbFlags, SRB_FLAGS_DISABLE_AUTOSENSE); 1573 SET_FLAG(Pkt->Srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER); 1574 1575 pCdb = (PCDB)Pkt->Srb->Cdb; 1576 pCdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT; 1577 pCdb->START_STOP.Start = 1; 1578 pCdb->START_STOP.Immediate = 0; 1579 pCdb->START_STOP.LogicalUnitNumber = 0; 1580 1581 Pkt->OriginalIrp = OriginalIrp; 1582 Pkt->NumRetries = 0; 1583 Pkt->SyncEventPtr = NULL; 1584 Pkt->CompleteOriginalIrpWhenLastPacketCompletes = FALSE; 1585 } 1586 #endif 1587 1588 1589 VOID 1590 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 1591 CleanupTransferPacketToWorkingSetSizeWorker( 1592 _In_ PVOID Fdo, 1593 _In_opt_ PVOID Context, 1594 _In_ PIO_WORKITEM IoWorkItem 1595 ) 1596 { 1597 ULONG node = (ULONG) (ULONG_PTR)Context; 1598 1599 PAGED_CODE(); 1600 1601 CleanupTransferPacketToWorkingSetSize((PDEVICE_OBJECT)Fdo, FALSE, node); 1602 1603 // 1604 // Release the remove lock acquired in EnqueueFreeTransferPacket 1605 // 1606 ClassReleaseRemoveLock((PDEVICE_OBJECT)Fdo, (PIRP)IoWorkItem); 1607 1608 if (IoWorkItem != NULL) { 1609 IoFreeWorkItem(IoWorkItem); 1610 } 1611 } 1612 1613 1614 VOID 1615 CleanupTransferPacketToWorkingSetSize( 1616 _In_ PDEVICE_OBJECT Fdo, 1617 _In_ BOOLEAN LimitNumPktToDelete, 1618 _In_ ULONG Node 1619 ) 1620 1621 /* 1622 Routine Description: 1623 1624 This function frees the resources for the free transfer packets attempting 1625 to bring them down within the working set size. 1626 1627 Arguments: 1628 Fdo: The FDO that represents the device whose transfer packet size needs to be trimmed. 1629 LimitNumPktToDelete: Flag to indicate if the number of packets freed in one call should be capped. 1630 Node: NUMA node transfer packet is associated with. 1631 1632 --*/ 1633 1634 { 1635 PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension; 1636 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData; 1637 KIRQL oldIrql; 1638 SINGLE_LIST_ENTRY pktList; 1639 PSINGLE_LIST_ENTRY slistEntry; 1640 PTRANSFER_PACKET pktToDelete; 1641 ULONG requiredNumPktToDelete = fdoData->FreeTransferPacketsLists[Node].NumTotalTransferPackets - 1642 fdoData->LocalMaxWorkingSetTransferPackets; 1643 1644 if (LimitNumPktToDelete) { 1645 requiredNumPktToDelete = MIN(requiredNumPktToDelete, MAX_CLEANUP_TRANSFER_PACKETS_AT_ONCE); 1646 } 1647 1648 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_RW, "CleanupTransferPacketToWorkingSetSize (%p): Exiting stress, block freeing %d packets.", Fdo, requiredNumPktToDelete)); 1649 1650 /* 1651 * Check the counter again with lock held. This eliminates a race condition 1652 * while still allowing us to not grab the spinlock in the common codepath. 1653 * 1654 * Note that the spinlock does not synchronize with threads dequeuing free 1655 * packets to send (DequeueFreeTransferPacket does that with a lightweight 1656 * interlocked exchange); the spinlock prevents multiple threads in this function 1657 * from deciding to free too many extra packets at once. 1658 */ 1659 SimpleInitSlistHdr(&pktList); 1660 KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql); 1661 while ((fdoData->FreeTransferPacketsLists[Node].NumFreeTransferPackets >= fdoData->FreeTransferPacketsLists[Node].NumTotalTransferPackets) && 1662 (fdoData->FreeTransferPacketsLists[Node].NumTotalTransferPackets > fdoData->LocalMaxWorkingSetTransferPackets) && 1663 (requiredNumPktToDelete--)){ 1664 1665 pktToDelete = DequeueFreeTransferPacketEx(Fdo, FALSE, Node); 1666 if (pktToDelete){ 1667 SimplePushSlist(&pktList, 1668 (PSINGLE_LIST_ENTRY)&pktToDelete->SlistEntry); 1669 InterlockedDecrement((volatile LONG *)&fdoData->FreeTransferPacketsLists[Node].NumTotalTransferPackets); 1670 } else { 1671 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_RW, 1672 "Extremely unlikely condition (non-fatal): %d packets dequeued at once for Fdo %p. NumTotalTransferPackets=%d (1). Node=%d", 1673 fdoData->LocalMaxWorkingSetTransferPackets, 1674 Fdo, 1675 fdoData->FreeTransferPacketsLists[Node].NumTotalTransferPackets, 1676 Node)); 1677 break; 1678 } 1679 } 1680 KeReleaseSpinLock(&fdoData->SpinLock, oldIrql); 1681 1682 slistEntry = SimplePopSlist(&pktList); 1683 while (slistEntry) { 1684 pktToDelete = CONTAINING_RECORD(slistEntry, TRANSFER_PACKET, SlistEntry); 1685 DestroyTransferPacket(pktToDelete); 1686 slistEntry = SimplePopSlist(&pktList); 1687 } 1688 1689 return; 1690 } 1691 1692 1693 _IRQL_requires_max_(APC_LEVEL) 1694 _IRQL_requires_min_(PASSIVE_LEVEL) 1695 _IRQL_requires_same_ 1696 VOID 1697 ClasspSetupPopulateTokenTransferPacket( 1698 _In_ __drv_aliasesMem POFFLOAD_READ_CONTEXT OffloadReadContext, 1699 _In_ PTRANSFER_PACKET Pkt, 1700 _In_ ULONG Length, 1701 _In_reads_bytes_(Length) PUCHAR PopulateTokenBuffer, 1702 _In_ PIRP OriginalIrp, 1703 _In_ ULONG ListIdentifier 1704 ) 1705 1706 /*++ 1707 1708 Routine description: 1709 1710 This routine is called once to set up a packet for PopulateToken. 1711 It builds up the SRB by setting the appropriate fields. 1712 1713 Arguments: 1714 1715 Pkt - The transfer packet to be sent down to the lower driver 1716 SyncEventPtr - The event that gets signaled once the IRP contained in the packet completes 1717 Length - Length of the buffer being sent as part of the command 1718 PopulateTokenBuffer - The buffer that contains the LBA ranges information for the PopulateToken operation 1719 OriginalIrp - The Io request to be processed 1720 ListIdentifier - The identifier that will be used to correlate a subsequent command to retrieve the token 1721 1722 Return Value: 1723 1724 Nothing 1725 1726 --*/ 1727 1728 { 1729 PFUNCTIONAL_DEVICE_EXTENSION fdoExt; 1730 PCLASS_PRIVATE_FDO_DATA fdoData; 1731 PCDB pCdb; 1732 ULONG srbLength; 1733 1734 PAGED_CODE(); 1735 1736 TracePrint((TRACE_LEVEL_VERBOSE, 1737 TRACE_FLAG_IOCTL, 1738 "ClasspSetupPopulateTokenTransferPacket (%p): Entering function. Irp %p\n", 1739 Pkt->Fdo, 1740 OriginalIrp)); 1741 1742 fdoExt = Pkt->Fdo->DeviceExtension; 1743 fdoData = fdoExt->PrivateFdoData; 1744 1745 if (fdoExt->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { 1746 srbLength = ((PSTORAGE_REQUEST_BLOCK) fdoData->SrbTemplate)->SrbLength; 1747 NT_ASSERT(((PSTORAGE_REQUEST_BLOCK) Pkt->Srb)->SrbLength >= srbLength); 1748 } else { 1749 srbLength = fdoData->SrbTemplate->Length; 1750 } 1751 RtlCopyMemory(Pkt->Srb, fdoData->SrbTemplate, srbLength); // copies _contents_ of SRB blocks 1752 1753 SrbSetRequestAttribute(Pkt->Srb, SRB_SIMPLE_TAG_REQUEST); 1754 SrbSetCdbLength(Pkt->Srb, 16); 1755 SrbSetOriginalRequest(Pkt->Srb, Pkt->Irp); 1756 SrbSetSenseInfoBuffer(Pkt->Srb, &Pkt->SrbErrorSenseData); 1757 SrbSetSenseInfoBufferLength(Pkt->Srb, sizeof(Pkt->SrbErrorSenseData)); 1758 SrbSetTimeOutValue(Pkt->Srb, fdoExt->TimeOutValue); 1759 SrbSetDataBuffer(Pkt->Srb, PopulateTokenBuffer); 1760 SrbSetDataTransferLength(Pkt->Srb, Length); 1761 1762 SrbAssignSrbFlags(Pkt->Srb, fdoExt->SrbFlags | SRB_FLAGS_DATA_OUT | SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_QUEUE_FREEZE); 1763 1764 pCdb = SrbGetCdb(Pkt->Srb); 1765 if (pCdb) { 1766 pCdb->TOKEN_OPERATION.OperationCode = SCSIOP_POPULATE_TOKEN; 1767 pCdb->TOKEN_OPERATION.ServiceAction = SERVICE_ACTION_POPULATE_TOKEN; 1768 1769 REVERSE_BYTES(&pCdb->TOKEN_OPERATION.ListIdentifier, &ListIdentifier); 1770 REVERSE_BYTES(&pCdb->TOKEN_OPERATION.ParameterListLength, &Length); 1771 } 1772 1773 Pkt->BufPtrCopy = PopulateTokenBuffer; 1774 Pkt->BufLenCopy = Length; 1775 1776 Pkt->OriginalIrp = OriginalIrp; 1777 Pkt->NumRetries = NUM_POPULATE_TOKEN_RETRIES; 1778 Pkt->CompleteOriginalIrpWhenLastPacketCompletes = FALSE; 1779 1780 Pkt->ContinuationRoutine = ClasspPopulateTokenTransferPacketDone; 1781 Pkt->ContinuationContext = OffloadReadContext; 1782 1783 TracePrint((TRACE_LEVEL_VERBOSE, 1784 TRACE_FLAG_IOCTL, 1785 "ClasspSetupPopulateTokenTransferPacket (%p): Exiting function with Irp %p\n", 1786 Pkt->Fdo, 1787 OriginalIrp)); 1788 1789 return; 1790 } 1791 1792 1793 _IRQL_requires_max_(APC_LEVEL) 1794 _IRQL_requires_min_(PASSIVE_LEVEL) 1795 _IRQL_requires_same_ 1796 VOID 1797 ClasspSetupReceivePopulateTokenInformationTransferPacket( 1798 _In_ POFFLOAD_READ_CONTEXT OffloadReadContext, 1799 _In_ PTRANSFER_PACKET Pkt, 1800 _In_ ULONG Length, 1801 _In_reads_bytes_(Length) PUCHAR ReceivePopulateTokenInformationBuffer, 1802 _In_ PIRP OriginalIrp, 1803 _In_ ULONG ListIdentifier 1804 ) 1805 1806 /*++ 1807 1808 Routine description: 1809 1810 This routine is called once to set up a packet for read token retrieval. 1811 It builds up the SRB by setting the appropriate fields. 1812 1813 Arguments: 1814 1815 Pkt - The transfer packet to be sent down to the lower driver 1816 Length - Length of the buffer being sent as part of the command 1817 ReceivePopulateTokenInformationBuffer - The buffer into which the target will pass back the token 1818 OriginalIrp - The Io request to be processed 1819 ListIdentifier - The identifier that will be used to correlate this command with its corresponding previous populate token operation 1820 1821 Return Value: 1822 1823 Nothing 1824 1825 --*/ 1826 1827 { 1828 PFUNCTIONAL_DEVICE_EXTENSION fdoExt; 1829 PCLASS_PRIVATE_FDO_DATA fdoData; 1830 PCDB pCdb; 1831 ULONG srbLength; 1832 1833 TracePrint((TRACE_LEVEL_VERBOSE, 1834 TRACE_FLAG_IOCTL, 1835 "ClasspSetupReceivePopulateTokenInformationTransferPacket (%p): Entering function. Irp %p\n", 1836 Pkt->Fdo, 1837 OriginalIrp)); 1838 1839 fdoExt = Pkt->Fdo->DeviceExtension; 1840 fdoData = fdoExt->PrivateFdoData; 1841 1842 if (fdoExt->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { 1843 srbLength = ((PSTORAGE_REQUEST_BLOCK) fdoData->SrbTemplate)->SrbLength; 1844 NT_ASSERT(((PSTORAGE_REQUEST_BLOCK) Pkt->Srb)->SrbLength >= srbLength); 1845 } else { 1846 srbLength = fdoData->SrbTemplate->Length; 1847 } 1848 RtlCopyMemory(Pkt->Srb, fdoData->SrbTemplate, srbLength); // copies _contents_ of SRB blocks 1849 1850 SrbSetRequestAttribute(Pkt->Srb, SRB_SIMPLE_TAG_REQUEST); 1851 SrbSetCdbLength(Pkt->Srb, 16); 1852 SrbSetOriginalRequest(Pkt->Srb, Pkt->Irp); 1853 SrbSetSenseInfoBuffer(Pkt->Srb, &Pkt->SrbErrorSenseData); 1854 SrbSetSenseInfoBufferLength(Pkt->Srb, sizeof(Pkt->SrbErrorSenseData)); 1855 SrbSetTimeOutValue(Pkt->Srb, fdoExt->TimeOutValue); 1856 SrbSetDataBuffer(Pkt->Srb, ReceivePopulateTokenInformationBuffer); 1857 SrbSetDataTransferLength(Pkt->Srb, Length); 1858 1859 SrbAssignSrbFlags(Pkt->Srb, fdoExt->SrbFlags | SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_QUEUE_FREEZE); 1860 1861 pCdb = SrbGetCdb(Pkt->Srb); 1862 if (pCdb) { 1863 pCdb->RECEIVE_TOKEN_INFORMATION.OperationCode = SCSIOP_RECEIVE_ROD_TOKEN_INFORMATION; 1864 pCdb->RECEIVE_TOKEN_INFORMATION.ServiceAction = SERVICE_ACTION_RECEIVE_TOKEN_INFORMATION; 1865 1866 REVERSE_BYTES(&pCdb->RECEIVE_TOKEN_INFORMATION.ListIdentifier, &ListIdentifier); 1867 REVERSE_BYTES(&pCdb->RECEIVE_TOKEN_INFORMATION.AllocationLength, &Length); 1868 } 1869 1870 Pkt->BufPtrCopy = ReceivePopulateTokenInformationBuffer; 1871 Pkt->BufLenCopy = Length; 1872 1873 Pkt->OriginalIrp = OriginalIrp; 1874 Pkt->NumRetries = NUM_POPULATE_TOKEN_RETRIES; 1875 Pkt->CompleteOriginalIrpWhenLastPacketCompletes = FALSE; 1876 1877 Pkt->ContinuationRoutine = ClasspReceivePopulateTokenInformationTransferPacketDone; 1878 Pkt->ContinuationContext = OffloadReadContext; 1879 1880 TracePrint((TRACE_LEVEL_VERBOSE, 1881 TRACE_FLAG_IOCTL, 1882 "ClasspSetupReceivePopulateTokenInformationTransferPacket (%p): Exiting function with Irp %p\n", 1883 Pkt->Fdo, 1884 OriginalIrp)); 1885 1886 return; 1887 } 1888 1889 1890 _IRQL_requires_max_(APC_LEVEL) 1891 _IRQL_requires_min_(PASSIVE_LEVEL) 1892 _IRQL_requires_same_ 1893 VOID 1894 ClasspSetupWriteUsingTokenTransferPacket( 1895 _In_ __drv_aliasesMem POFFLOAD_WRITE_CONTEXT OffloadWriteContext, 1896 _In_ PTRANSFER_PACKET Pkt, 1897 _In_ ULONG Length, 1898 _In_reads_bytes_ (Length) PUCHAR WriteUsingTokenBuffer, 1899 _In_ PIRP OriginalIrp, 1900 _In_ ULONG ListIdentifier 1901 ) 1902 1903 /*++ 1904 1905 Routine description: 1906 1907 This routine is called once to set up a packet for WriteUsingToken. 1908 It builds up the SRB by setting the appropriate fields. It is not called 1909 before a retry as the SRB fields may be modified for the retry. 1910 1911 The IRP is set up in SubmitTransferPacket because it must be reset for 1912 each packet submission. 1913 1914 Arguments: 1915 1916 Pkt - The transfer packet to be sent down to the lower driver 1917 Length - Length of the buffer being sent as part of the command 1918 WriteUsingTokenBuffer - The buffer that contains the read token and the write LBA ranges information for the WriteUsingToken operation 1919 OriginalIrp - The Io request to be processed 1920 ListIdentifier - The identifier that will be used to correlate a subsequent command to retrieve extended results in case of command failure 1921 1922 Return Value: 1923 1924 Nothing 1925 1926 --*/ 1927 1928 { 1929 PFUNCTIONAL_DEVICE_EXTENSION fdoExt; 1930 PCLASS_PRIVATE_FDO_DATA fdoData; 1931 PCDB pCdb; 1932 ULONG srbLength; 1933 1934 TracePrint((TRACE_LEVEL_VERBOSE, 1935 TRACE_FLAG_IOCTL, 1936 "ClasspSetupWriteUsingTokenTransferPacket (%p): Entering function. Irp %p\n", 1937 Pkt->Fdo, 1938 OriginalIrp)); 1939 1940 fdoExt = Pkt->Fdo->DeviceExtension; 1941 fdoData = fdoExt->PrivateFdoData; 1942 1943 if (fdoExt->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { 1944 srbLength = ((PSTORAGE_REQUEST_BLOCK) fdoData->SrbTemplate)->SrbLength; 1945 NT_ASSERT(((PSTORAGE_REQUEST_BLOCK) Pkt->Srb)->SrbLength >= srbLength); 1946 } else { 1947 srbLength = fdoData->SrbTemplate->Length; 1948 } 1949 RtlCopyMemory(Pkt->Srb, fdoData->SrbTemplate, srbLength); // copies _contents_ of SRB blocks 1950 1951 SrbSetRequestAttribute(Pkt->Srb, SRB_SIMPLE_TAG_REQUEST); 1952 SrbSetCdbLength(Pkt->Srb, 16); 1953 SrbSetOriginalRequest(Pkt->Srb, Pkt->Irp); 1954 SrbSetSenseInfoBuffer(Pkt->Srb, &Pkt->SrbErrorSenseData); 1955 SrbSetSenseInfoBufferLength(Pkt->Srb, sizeof(Pkt->SrbErrorSenseData)); 1956 SrbSetTimeOutValue(Pkt->Srb, fdoExt->TimeOutValue); 1957 SrbSetDataBuffer(Pkt->Srb, WriteUsingTokenBuffer); 1958 SrbSetDataTransferLength(Pkt->Srb, Length); 1959 1960 SrbAssignSrbFlags(Pkt->Srb, fdoExt->SrbFlags | SRB_FLAGS_DATA_OUT | SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_QUEUE_FREEZE); 1961 1962 pCdb = SrbGetCdb(Pkt->Srb); 1963 if (pCdb) { 1964 pCdb->TOKEN_OPERATION.OperationCode = SCSIOP_WRITE_USING_TOKEN; 1965 pCdb->TOKEN_OPERATION.ServiceAction = SERVICE_ACTION_WRITE_USING_TOKEN; 1966 1967 REVERSE_BYTES(&pCdb->TOKEN_OPERATION.ParameterListLength, &Length); 1968 REVERSE_BYTES(&pCdb->TOKEN_OPERATION.ListIdentifier, &ListIdentifier); 1969 } 1970 1971 Pkt->BufPtrCopy = WriteUsingTokenBuffer; 1972 Pkt->BufLenCopy = Length; 1973 1974 Pkt->OriginalIrp = OriginalIrp; 1975 Pkt->NumRetries = NUM_WRITE_USING_TOKEN_RETRIES; 1976 Pkt->CompleteOriginalIrpWhenLastPacketCompletes = FALSE; 1977 1978 Pkt->ContinuationRoutine = ClasspWriteUsingTokenTransferPacketDone; 1979 Pkt->ContinuationContext = OffloadWriteContext; 1980 1981 TracePrint((TRACE_LEVEL_VERBOSE, 1982 TRACE_FLAG_IOCTL, 1983 "ClasspSetupWriteUsingTokenTransferPacket (%p): Exiting function with Irp %p\n", 1984 Pkt->Fdo, 1985 OriginalIrp)); 1986 1987 return; 1988 } 1989 1990 1991 _IRQL_requires_max_(APC_LEVEL) 1992 _IRQL_requires_min_(PASSIVE_LEVEL) 1993 _IRQL_requires_same_ 1994 VOID 1995 ClasspSetupReceiveWriteUsingTokenInformationTransferPacket( 1996 _In_ POFFLOAD_WRITE_CONTEXT OffloadWriteContext, 1997 _In_ PTRANSFER_PACKET Pkt, 1998 _In_ ULONG Length, 1999 _In_reads_bytes_ (Length) PUCHAR ReceiveWriteUsingTokenInformationBuffer, 2000 _In_ PIRP OriginalIrp, 2001 _In_ ULONG ListIdentifier 2002 ) 2003 2004 /*++ 2005 2006 Routine description: 2007 2008 This routine is called once to set up a packet for extended results for 2009 WriteUsingToken operation. It builds up the SRB by setting the appropriate fields. 2010 2011 Arguments: 2012 2013 Pkt - The transfer packet to be sent down to the lower driver 2014 SyncEventPtr - The event that gets signaled once the IRP contained in the packet completes 2015 Length - Length of the buffer being sent as part of the command 2016 ReceiveWriteUsingTokenInformationBuffer - The buffer into which the target will pass back the extended results 2017 OriginalIrp - The Io request to be processed 2018 ListIdentifier - The identifier that will be used to correlate this command with its corresponding previous write using token operation 2019 2020 Return Value: 2021 2022 Nothing 2023 2024 --*/ 2025 2026 { 2027 PFUNCTIONAL_DEVICE_EXTENSION fdoExt; 2028 PCLASS_PRIVATE_FDO_DATA fdoData; 2029 PCDB pCdb; 2030 ULONG srbLength; 2031 2032 TracePrint((TRACE_LEVEL_VERBOSE, 2033 TRACE_FLAG_IOCTL, 2034 "ClasspSetupReceiveWriteUsingTokenInformationTransferPacket (%p): Entering function. Irp %p\n", 2035 Pkt->Fdo, 2036 OriginalIrp)); 2037 2038 fdoExt = Pkt->Fdo->DeviceExtension; 2039 fdoData = fdoExt->PrivateFdoData; 2040 2041 if (fdoExt->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { 2042 srbLength = ((PSTORAGE_REQUEST_BLOCK) fdoData->SrbTemplate)->SrbLength; 2043 NT_ASSERT(((PSTORAGE_REQUEST_BLOCK) Pkt->Srb)->SrbLength >= srbLength); 2044 } else { 2045 srbLength = fdoData->SrbTemplate->Length; 2046 } 2047 RtlCopyMemory(Pkt->Srb, fdoData->SrbTemplate, srbLength); // copies _contents_ of SRB blocks 2048 2049 SrbSetRequestAttribute(Pkt->Srb, SRB_SIMPLE_TAG_REQUEST); 2050 SrbSetCdbLength(Pkt->Srb, 16); 2051 SrbSetOriginalRequest(Pkt->Srb, Pkt->Irp); 2052 SrbSetSenseInfoBuffer(Pkt->Srb, &Pkt->SrbErrorSenseData); 2053 SrbSetSenseInfoBufferLength(Pkt->Srb, sizeof(Pkt->SrbErrorSenseData)); 2054 SrbSetTimeOutValue(Pkt->Srb, fdoExt->TimeOutValue); 2055 SrbSetDataBuffer(Pkt->Srb, ReceiveWriteUsingTokenInformationBuffer); 2056 SrbSetDataTransferLength(Pkt->Srb, Length); 2057 2058 SrbAssignSrbFlags(Pkt->Srb, fdoExt->SrbFlags | SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_QUEUE_FREEZE); 2059 2060 pCdb = SrbGetCdb(Pkt->Srb); 2061 if (pCdb) { 2062 pCdb->RECEIVE_TOKEN_INFORMATION.OperationCode = SCSIOP_RECEIVE_ROD_TOKEN_INFORMATION; 2063 pCdb->RECEIVE_TOKEN_INFORMATION.ServiceAction = SERVICE_ACTION_RECEIVE_TOKEN_INFORMATION; 2064 2065 REVERSE_BYTES(&pCdb->RECEIVE_TOKEN_INFORMATION.AllocationLength, &Length); 2066 REVERSE_BYTES(&pCdb->RECEIVE_TOKEN_INFORMATION.ListIdentifier, &ListIdentifier); 2067 } 2068 2069 Pkt->BufPtrCopy = ReceiveWriteUsingTokenInformationBuffer; 2070 Pkt->BufLenCopy = Length; 2071 2072 Pkt->OriginalIrp = OriginalIrp; 2073 Pkt->NumRetries = NUM_WRITE_USING_TOKEN_RETRIES; 2074 Pkt->CompleteOriginalIrpWhenLastPacketCompletes = FALSE; 2075 2076 Pkt->ContinuationRoutine = (PCONTINUATION_ROUTINE) ClasspReceiveWriteUsingTokenInformationTransferPacketDone; 2077 Pkt->ContinuationContext = OffloadWriteContext; 2078 2079 TracePrint((TRACE_LEVEL_VERBOSE, 2080 TRACE_FLAG_IOCTL, 2081 "ClasspSetupReceiveWriteUsingTokenInformationTransferPacket (%p): Exiting function with Irp %p\n", 2082 Pkt->Fdo, 2083 OriginalIrp)); 2084 2085 return; 2086 } 2087 2088 2089