1 /*++ 2 3 Copyright (C) Microsoft Corporation, 1991 - 2010 4 5 Module Name: 6 7 class.c 8 9 Abstract: 10 11 SCSI class driver routines 12 13 Environment: 14 15 kernel mode only 16 17 Notes: 18 19 20 Revision History: 21 22 --*/ 23 24 #define CLASS_INIT_GUID 1 25 #define DEBUG_MAIN_SOURCE 1 26 27 #include "classp.h" 28 #include "debug.h" 29 #include <process.h> 30 #include <devpkey.h> 31 #include <ntiologc.h> 32 33 34 #ifdef DEBUG_USE_WPP 35 #include "class.tmh" 36 #endif 37 38 #ifdef ALLOC_PRAGMA 39 #pragma alloc_text(INIT, DriverEntry) 40 #pragma alloc_text(PAGE, ClassAddDevice) 41 #pragma alloc_text(PAGE, ClassClaimDevice) 42 #pragma alloc_text(PAGE, ClassCreateDeviceObject) 43 #pragma alloc_text(PAGE, ClassDispatchPnp) 44 #pragma alloc_text(PAGE, ClassGetDescriptor) 45 #pragma alloc_text(PAGE, ClassGetPdoId) 46 #pragma alloc_text(PAGE, ClassInitialize) 47 #pragma alloc_text(PAGE, ClassInitializeEx) 48 #pragma alloc_text(PAGE, ClassInvalidateBusRelations) 49 #pragma alloc_text(PAGE, ClassMarkChildMissing) 50 #pragma alloc_text(PAGE, ClassMarkChildrenMissing) 51 #pragma alloc_text(PAGE, ClassModeSense) 52 #pragma alloc_text(PAGE, ClassPnpQueryFdoRelations) 53 #pragma alloc_text(PAGE, ClassPnpStartDevice) 54 #pragma alloc_text(PAGE, ClassQueryPnpCapabilities) 55 #pragma alloc_text(PAGE, ClassQueryTimeOutRegistryValue) 56 #pragma alloc_text(PAGE, ClassRemoveDevice) 57 #pragma alloc_text(PAGE, ClassRetrieveDeviceRelations) 58 #pragma alloc_text(PAGE, ClassUpdateInformationInRegistry) 59 #pragma alloc_text(PAGE, ClassSendDeviceIoControlSynchronous) 60 #pragma alloc_text(PAGE, ClassUnload) 61 #pragma alloc_text(PAGE, ClasspAllocateReleaseRequest) 62 #pragma alloc_text(PAGE, ClasspFreeReleaseRequest) 63 #pragma alloc_text(PAGE, ClasspInitializeHotplugInfo) 64 #pragma alloc_text(PAGE, ClasspRegisterMountedDeviceInterface) 65 #pragma alloc_text(PAGE, ClasspScanForClassHacks) 66 #pragma alloc_text(PAGE, ClasspScanForSpecialInRegistry) 67 #pragma alloc_text(PAGE, ClasspModeSense) 68 #pragma alloc_text(PAGE, ClasspIsPortable) 69 #pragma alloc_text(PAGE, ClassAcquireChildLock) 70 #pragma alloc_text(PAGE, ClassDetermineTokenOperationCommandSupport) 71 #pragma alloc_text(PAGE, ClassDeviceProcessOffloadRead) 72 #pragma alloc_text(PAGE, ClassDeviceProcessOffloadWrite) 73 #pragma alloc_text(PAGE, ClasspServicePopulateTokenTransferRequest) 74 #pragma alloc_text(PAGE, ClasspServiceWriteUsingTokenTransferRequest) 75 #if (NTDDI_VERSION >= NTDDI_WINBLUE) 76 #pragma alloc_text(PAGE, ClassModeSenseEx) 77 #endif 78 #endif 79 80 #ifdef _MSC_VER 81 #pragma prefast(disable:28159, "There are certain cases when we have to bugcheck...") 82 #endif 83 84 IO_COMPLETION_ROUTINE ClassCheckVerifyComplete; 85 86 87 ULONG ClassPnpAllowUnload = TRUE; 88 ULONG ClassMaxInterleavePerCriticalIo = CLASS_MAX_INTERLEAVE_PER_CRITICAL_IO; 89 CONST LARGE_INTEGER Magic10000 = {{0xe219652c, 0xd1b71758}}; 90 GUID StoragePredictFailureDPSGuid = WDI_STORAGE_PREDICT_FAILURE_DPS_GUID; 91 92 #define FirstDriveLetter 'C' 93 #define LastDriveLetter 'Z' 94 95 BOOLEAN UseQPCTime = FALSE; 96 97 // 98 // Keep track of whether security cookie is initialized or not. This is 99 // required by SDL. 100 // 101 102 BOOLEAN InitSecurityCookie = FALSE; 103 104 // 105 // List Identifier for offload data transfer operations 106 // 107 ULONG MaxTokenOperationListIdentifier = MAX_TOKEN_LIST_IDENTIFIERS; 108 volatile ULONG TokenOperationListIdentifier = (ULONG)-1; 109 110 // 111 // List of FDOs that have enabled idle power management. 112 // 113 LIST_ENTRY IdlePowerFDOList = {0}; 114 KGUARDED_MUTEX IdlePowerFDOListMutex; 115 116 // 117 // Handle used to register for power setting notifications. 118 // 119 PVOID PowerSettingNotificationHandle; 120 121 // 122 // Handle used to register for screen state setting notifications. 123 // 124 PVOID ScreenStateNotificationHandle; 125 126 // 127 // Disk idle timeout in milliseconds. 128 // We default this to 0xFFFFFFFF as this is what the power manager considers 129 // "never" and ensures we do not set a disk idle timeout until the power 130 // manager calls us back with a different value. 131 // 132 ULONG DiskIdleTimeoutInMS = 0xFFFFFFFF; 133 134 135 NTSTATUS DllUnload(VOID) 136 { 137 DbgPrintEx(DPFLTR_CLASSPNP_ID, DPFLTR_INFO_LEVEL, "classpnp.sys is now unloading\n"); 138 139 if (PowerSettingNotificationHandle) { 140 PoUnregisterPowerSettingCallback(PowerSettingNotificationHandle); 141 PowerSettingNotificationHandle = NULL; 142 } 143 144 if (ScreenStateNotificationHandle) { 145 PoUnregisterPowerSettingCallback(ScreenStateNotificationHandle); 146 ScreenStateNotificationHandle = NULL; 147 } 148 149 150 return STATUS_SUCCESS; 151 } 152 153 154 /*++//////////////////////////////////////////////////////////////////////////// 155 156 DriverEntry() 157 158 Routine Description: 159 160 Temporary entry point needed to initialize the class system dll. 161 It doesn't do anything. 162 163 Arguments: 164 165 DriverObject - Pointer to the driver object created by the system. 166 167 Return Value: 168 169 STATUS_SUCCESS 170 171 --*/ 172 NTSTATUS 173 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 174 DriverEntry( 175 IN PDRIVER_OBJECT DriverObject, 176 IN PUNICODE_STRING RegistryPath 177 ) 178 { 179 UNREFERENCED_PARAMETER(DriverObject); 180 UNREFERENCED_PARAMETER(RegistryPath); 181 182 return STATUS_SUCCESS; 183 } 184 185 186 187 /*++//////////////////////////////////////////////////////////////////////////// 188 189 ClassInitialize() 190 191 Routine Description: 192 193 This routine is called by a class driver during its 194 DriverEntry routine to initialize the driver. 195 196 Arguments: 197 198 Argument1 - Driver Object. 199 Argument2 - Registry Path. 200 InitializationData - Device-specific driver's initialization data. 201 202 Return Value: 203 204 A valid return code for a DriverEntry routine. 205 206 --*/ 207 _IRQL_requires_max_(PASSIVE_LEVEL) 208 _Must_inspect_result_ 209 ULONG 210 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 211 ClassInitialize( 212 _In_ PVOID Argument1, 213 _In_ PVOID Argument2, 214 _In_ PCLASS_INIT_DATA InitializationData 215 ) 216 { 217 PDRIVER_OBJECT DriverObject = Argument1; 218 PUNICODE_STRING RegistryPath = Argument2; 219 220 PCLASS_DRIVER_EXTENSION driverExtension; 221 222 NTSTATUS status; 223 224 225 226 PAGED_CODE(); 227 228 // 229 // Initialize the security cookie if needed. 230 // 231 #ifndef __REACTOS__ 232 if (InitSecurityCookie == FALSE) { 233 __security_init_cookie(); 234 InitSecurityCookie = TRUE; 235 } 236 #endif 237 238 239 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, "\n\nSCSI Class Driver\n")); 240 241 ClasspInitializeDebugGlobals(); 242 243 // 244 // Validate the length of this structure. This is effectively a 245 // version check. 246 // 247 248 if (InitializationData->InitializationDataSize != sizeof(CLASS_INIT_DATA)) { 249 250 // 251 // This DebugPrint is to help third-party driver writers 252 // 253 254 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT, "ClassInitialize: Class driver wrong version\n")); 255 return (ULONG) STATUS_REVISION_MISMATCH; 256 } 257 258 // 259 // Check that each required entry is not NULL. Note that Shutdown, Flush and Error 260 // are not required entry points. 261 // 262 263 if ((!InitializationData->FdoData.ClassDeviceControl) || 264 (!((InitializationData->FdoData.ClassReadWriteVerification) || 265 (InitializationData->ClassStartIo))) || 266 (!InitializationData->ClassAddDevice) || 267 (!InitializationData->FdoData.ClassStartDevice)) { 268 269 // 270 // This DebugPrint is to help third-party driver writers 271 // 272 273 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT, 274 "ClassInitialize: Class device-specific driver missing required " 275 "FDO entry\n")); 276 277 return (ULONG) STATUS_REVISION_MISMATCH; 278 } 279 280 if ((InitializationData->ClassEnumerateDevice) && 281 ((!InitializationData->PdoData.ClassDeviceControl) || 282 (!InitializationData->PdoData.ClassStartDevice) || 283 (!((InitializationData->PdoData.ClassReadWriteVerification) || 284 (InitializationData->ClassStartIo))))) { 285 286 // 287 // This DebugPrint is to help third-party driver writers 288 // 289 290 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT, "ClassInitialize: Class device-specific missing " 291 "required PDO entry\n")); 292 293 return (ULONG) STATUS_REVISION_MISMATCH; 294 } 295 296 if((InitializationData->FdoData.ClassStopDevice == NULL) || 297 ((InitializationData->ClassEnumerateDevice != NULL) && 298 (InitializationData->PdoData.ClassStopDevice == NULL))) { 299 300 // 301 // This DebugPrint is to help third-party driver writers 302 // 303 304 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT, "ClassInitialize: Class device-specific missing " 305 "required PDO entry\n")); 306 NT_ASSERT(FALSE); 307 return (ULONG) STATUS_REVISION_MISMATCH; 308 } 309 310 // 311 // Setup the default power handlers if the class driver didn't provide 312 // any. 313 // 314 315 if(InitializationData->FdoData.ClassPowerDevice == NULL) { 316 InitializationData->FdoData.ClassPowerDevice = ClassMinimalPowerHandler; 317 } 318 319 if((InitializationData->ClassEnumerateDevice != NULL) && 320 (InitializationData->PdoData.ClassPowerDevice == NULL)) { 321 InitializationData->PdoData.ClassPowerDevice = ClassMinimalPowerHandler; 322 } 323 324 // 325 // warn that unload is not supported 326 // 327 // ISSUE-2000/02/03-peterwie 328 // We should think about making this a fatal error. 329 // 330 331 if(InitializationData->ClassUnload == NULL) { 332 333 // 334 // This DebugPrint is to help third-party driver writers 335 // 336 337 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, "ClassInitialize: driver does not support unload %wZ\n", 338 RegistryPath)); 339 } 340 341 // 342 // Create an extension for the driver object 343 // 344 #ifdef _MSC_VER 345 #pragma warning(suppress:4054) // okay to type cast function pointer as data pointer for this use case 346 #endif 347 status = IoAllocateDriverObjectExtension(DriverObject, CLASS_DRIVER_EXTENSION_KEY, sizeof(CLASS_DRIVER_EXTENSION), (PVOID *)&driverExtension); 348 349 if(NT_SUCCESS(status)) { 350 351 // 352 // Copy the registry path into the driver extension so we can use it later 353 // 354 355 driverExtension->RegistryPath.Length = RegistryPath->Length; 356 driverExtension->RegistryPath.MaximumLength = RegistryPath->MaximumLength; 357 358 driverExtension->RegistryPath.Buffer = 359 ExAllocatePoolWithTag(PagedPool, 360 RegistryPath->MaximumLength, 361 '1CcS'); 362 363 if(driverExtension->RegistryPath.Buffer == NULL) { 364 365 status = STATUS_INSUFFICIENT_RESOURCES; 366 return status; 367 } 368 369 RtlCopyUnicodeString( 370 &(driverExtension->RegistryPath), 371 RegistryPath); 372 373 // 374 // Copy the initialization data into the driver extension so we can reuse 375 // it during our add device routine 376 // 377 378 RtlCopyMemory( 379 &(driverExtension->InitData), 380 InitializationData, 381 sizeof(CLASS_INIT_DATA)); 382 383 driverExtension->DeviceCount = 0; 384 385 ClassInitializeDispatchTables(driverExtension); 386 387 } else if (status == STATUS_OBJECT_NAME_COLLISION) { 388 389 // 390 // The extension already exists - get a pointer to it 391 // 392 #ifdef _MSC_VER 393 #pragma warning(suppress:4054) // okay to type cast function pointer as data pointer for this use case 394 #endif 395 driverExtension = IoGetDriverObjectExtension(DriverObject, CLASS_DRIVER_EXTENSION_KEY); 396 397 NT_ASSERT(driverExtension != NULL); 398 399 } else { 400 401 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT, "ClassInitialize: Class driver extension could not be " 402 "allocated %lx\n", status)); 403 return status; 404 } 405 406 407 // 408 // Update driver object with entry points. 409 // 410 411 #ifdef _MSC_VER 412 #pragma prefast(push) 413 #pragma prefast(disable:28175, "Accessing DRIVER_OBJECT fileds is OK here since this function " \ 414 "is supposed to be invoked from DriverEntry only") 415 #endif 416 DriverObject->MajorFunction[IRP_MJ_CREATE] = ClassGlobalDispatch; 417 DriverObject->MajorFunction[IRP_MJ_CLOSE] = ClassGlobalDispatch; 418 DriverObject->MajorFunction[IRP_MJ_READ] = ClassGlobalDispatch; 419 DriverObject->MajorFunction[IRP_MJ_WRITE] = ClassGlobalDispatch; 420 DriverObject->MajorFunction[IRP_MJ_SCSI] = ClassGlobalDispatch; 421 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ClassGlobalDispatch; 422 DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = ClassGlobalDispatch; 423 DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = ClassGlobalDispatch; 424 DriverObject->MajorFunction[IRP_MJ_PNP] = ClassGlobalDispatch; 425 DriverObject->MajorFunction[IRP_MJ_POWER] = ClassGlobalDispatch; 426 DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = ClassGlobalDispatch; 427 428 if (InitializationData->ClassStartIo) { 429 DriverObject->DriverStartIo = ClasspStartIo; 430 } 431 432 if ((InitializationData->ClassUnload) && (ClassPnpAllowUnload == TRUE)) { 433 DriverObject->DriverUnload = ClassUnload; 434 } else { 435 DriverObject->DriverUnload = NULL; 436 } 437 438 DriverObject->DriverExtension->AddDevice = ClassAddDevice; 439 #ifdef _MSC_VER 440 #pragma prefast(pop) 441 #endif 442 443 444 // 445 // Register for event tracing 446 // 447 if (driverExtension->EtwHandle == 0) { 448 status = EtwRegister(&StoragePredictFailureDPSGuid, 449 NULL, 450 NULL, 451 &driverExtension->EtwHandle); 452 if (!NT_SUCCESS(status)) { 453 driverExtension->EtwHandle = 0; 454 } 455 WPP_INIT_TRACING(DriverObject, RegistryPath); 456 } 457 458 459 // 460 // Ensure these are only initialized once. 461 // 462 if (IdlePowerFDOList.Flink == NULL) { 463 InitializeListHead(&IdlePowerFDOList); 464 KeInitializeGuardedMutex(&IdlePowerFDOListMutex); 465 } 466 467 status = STATUS_SUCCESS; 468 return status; 469 } // end ClassInitialize() 470 471 /*++//////////////////////////////////////////////////////////////////////////// 472 473 ClassInitializeEx() 474 475 Routine Description: 476 477 This routine is allows the caller to do any extra initialization or 478 setup that is not done in ClassInitialize. The operation is 479 controlled by the GUID that is passed and the contents of the Data 480 parameter is dependent upon the GUID. 481 482 This is the list of supported operations: 483 484 GUID_CLASSPNP_QUERY_REGINFOEX == CLASS_QUERY_WMI_REGINFO_EX_LIST 485 486 Initialized classpnp to callback a PCLASS_QUERY_WMI_REGINFO_EX 487 callback instead of a PCLASS_QUERY_WMI_REGINFO callback. The 488 former callback allows the driver to specify the name of the 489 mof resource. 490 491 GUID_CLASSPNP_SENSEINFO2 == CLASS_INTERPRET_SENSE_INFO2 492 493 Initialize classpnp to callback into class drive for interpretation 494 of all sense info, and to indicate the count of "history" to keep 495 for each packet. 496 497 GUID_CLASSPNP_WORKING_SET == CLASS_WORKING_SET 498 499 Allow class driver to override the min and max working set transfer 500 packet value used in classpnp. 501 502 GUID_CLASSPNP_SRB_SUPPORT == ULONG 503 504 Allow class driver to provide supported SRB types. 505 506 Arguments: 507 508 DriverObject 509 Guid 510 Data 511 512 Return Value: 513 514 Status Code 515 516 --*/ 517 _IRQL_requires_max_(PASSIVE_LEVEL) 518 _Must_inspect_result_ 519 ULONG 520 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 521 ClassInitializeEx( 522 _In_ PDRIVER_OBJECT DriverObject, 523 _In_ LPGUID Guid, 524 _In_ PVOID Data 525 ) 526 { 527 PCLASS_DRIVER_EXTENSION driverExtension; 528 529 NTSTATUS status; 530 531 PAGED_CODE(); 532 533 #ifdef _MSC_VER 534 #pragma warning(suppress:4054) // okay to type cast function pointer as data pointer for this use case 535 #endif 536 driverExtension = IoGetDriverObjectExtension( DriverObject, CLASS_DRIVER_EXTENSION_KEY ); 537 538 if (driverExtension == NULL) 539 { 540 NT_ASSERT(FALSE); 541 return (ULONG)STATUS_UNSUCCESSFUL; 542 } 543 544 if (IsEqualGUID(Guid, &ClassGuidQueryRegInfoEx)) 545 { 546 PCLASS_QUERY_WMI_REGINFO_EX_LIST List; 547 548 // 549 // Indicate the device supports PCLASS_QUERY_REGINFO_EX 550 // callback instead of PCLASS_QUERY_REGINFO callback. 551 // 552 List = (PCLASS_QUERY_WMI_REGINFO_EX_LIST)Data; 553 554 if (List->Size == sizeof(CLASS_QUERY_WMI_REGINFO_EX_LIST)) 555 { 556 driverExtension->ClassFdoQueryWmiRegInfoEx = List->ClassFdoQueryWmiRegInfoEx; 557 driverExtension->ClassPdoQueryWmiRegInfoEx = List->ClassPdoQueryWmiRegInfoEx; 558 status = STATUS_SUCCESS; 559 } else { 560 status = STATUS_INVALID_PARAMETER; 561 } 562 } 563 else if (IsEqualGUID(Guid, &ClassGuidWorkingSet)) 564 { 565 PCLASS_WORKING_SET infoOriginal = (PCLASS_WORKING_SET)Data; 566 PCLASS_WORKING_SET info = NULL; 567 568 // only try to allocate memory for cached copy if size is correct 569 if (infoOriginal->Size != sizeof(CLASS_WORKING_SET)) 570 { 571 // incorrect size -- client programming error 572 status = STATUS_INVALID_PARAMETER; 573 } 574 else 575 { 576 info = ExAllocatePoolWithTag(NonPagedPoolNx, 577 sizeof(CLASS_WORKING_SET), 578 CLASS_TAG_WORKING_SET 579 ); 580 if (info == NULL) 581 { 582 status = STATUS_INSUFFICIENT_RESOURCES; 583 } 584 else 585 { 586 // cache the structure internally 587 RtlCopyMemory(info, infoOriginal, sizeof(CLASS_WORKING_SET)); 588 status = STATUS_SUCCESS; 589 } 590 } 591 // if we successfully cached a copy, validate all the data within 592 if (NT_SUCCESS(status)) 593 { 594 if (info->Size != sizeof(CLASS_WORKING_SET)) 595 { 596 // incorrect size -- client programming error 597 status = STATUS_INVALID_PARAMETER; 598 } 599 else if (info->XferPacketsWorkingSetMaximum > CLASS_WORKING_SET_MAXIMUM) 600 { 601 // too many requested in the working set 602 status = STATUS_INVALID_PARAMETER; 603 } 604 else if (info->XferPacketsWorkingSetMinimum > CLASS_WORKING_SET_MAXIMUM) 605 { 606 // too many requested in the working set 607 status = STATUS_INVALID_PARAMETER; 608 } 609 else if (driverExtension->InitData.FdoData.DeviceType != FILE_DEVICE_CD_ROM) 610 { 611 // classpnp developer wants to restrict this code path 612 // for now to CDROM devices only. 613 status = STATUS_INVALID_DEVICE_REQUEST; 614 } 615 else if (driverExtension->WorkingSet != NULL) 616 { 617 // not allowed to change it once it is set for a driver 618 status = STATUS_INVALID_PARAMETER; 619 NT_ASSERT(FALSE); 620 } 621 } 622 // save results or cleanup 623 if (NT_SUCCESS(status)) 624 { 625 driverExtension->WorkingSet = info; info = NULL; 626 } 627 else 628 { 629 FREE_POOL( info ); 630 } 631 } 632 else if (IsEqualGUID(Guid, &ClassGuidSenseInfo2)) 633 { 634 PCLASS_INTERPRET_SENSE_INFO2 infoOriginal = (PCLASS_INTERPRET_SENSE_INFO2)Data; 635 PCLASS_INTERPRET_SENSE_INFO2 info = NULL; 636 637 // only try to allocate memory for cached copy if size is correct 638 if (infoOriginal->Size != sizeof(CLASS_INTERPRET_SENSE_INFO2)) 639 { 640 // incorrect size -- client programming error 641 status = STATUS_INVALID_PARAMETER; 642 } 643 else 644 { 645 info = ExAllocatePoolWithTag(NonPagedPoolNx, 646 sizeof(CLASS_INTERPRET_SENSE_INFO2), 647 CLASS_TAG_SENSE2 648 ); 649 if (info == NULL) 650 { 651 status = STATUS_INSUFFICIENT_RESOURCES; 652 } 653 else 654 { 655 // cache the structure internally 656 RtlCopyMemory(info, infoOriginal, sizeof(CLASS_INTERPRET_SENSE_INFO2)); 657 status = STATUS_SUCCESS; 658 } 659 } 660 661 // if we successfully cached a copy, validate all the data within 662 if (NT_SUCCESS(status)) 663 { 664 if (info->Size != sizeof(CLASS_INTERPRET_SENSE_INFO2)) 665 { 666 // incorrect size -- client programming error 667 status = STATUS_INVALID_PARAMETER; 668 } 669 else if (info->HistoryCount > CLASS_INTERPRET_SENSE_INFO2_MAXIMUM_HISTORY_COUNT) 670 { 671 // incorrect count -- client programming error 672 status = STATUS_INVALID_PARAMETER; 673 } 674 else if (info->Compress == NULL) 675 { 676 // Compression of the history is required to be supported 677 status = STATUS_INVALID_PARAMETER; 678 } 679 else if (info->HistoryCount == 0) 680 { 681 // History count cannot be zero 682 status = STATUS_INVALID_PARAMETER; 683 } 684 else if (info->Interpret == NULL) 685 { 686 // Updated interpret sense info function is required 687 status = STATUS_INVALID_PARAMETER; 688 } 689 else if (driverExtension->InitData.FdoData.DeviceType != FILE_DEVICE_CD_ROM) 690 { 691 // classpnp developer wants to restrict this code path 692 // for now to CDROM devices only. 693 status = STATUS_INVALID_DEVICE_REQUEST; 694 } 695 else if (driverExtension->InterpretSenseInfo != NULL) 696 { 697 // not allowed to change it once it is set for a driver 698 status = STATUS_INVALID_PARAMETER; 699 NT_ASSERT(FALSE); 700 } 701 } 702 703 // save results or cleanup 704 if (NT_SUCCESS(status)) 705 { 706 driverExtension->InterpretSenseInfo = info; info = NULL; 707 } 708 else 709 { 710 FREE_POOL( info ); 711 } 712 } 713 else if (IsEqualGUID(Guid, &ClassGuidSrbSupport)) 714 { 715 ULONG srbSupport = *((PULONG)Data); 716 717 // 718 // Validate that at least one of the supported bit flags is set. Assume 719 // all class drivers support SCSI_REQUEST_BLOCK as a class driver that 720 // supports only extended SRB is not feasible. 721 // 722 if ((srbSupport & 723 (CLASS_SRB_SCSI_REQUEST_BLOCK | CLASS_SRB_STORAGE_REQUEST_BLOCK)) != 0) { 724 driverExtension->SrbSupport = srbSupport; 725 status = STATUS_SUCCESS; 726 727 // 728 // Catch cases of a class driver reporting only extended SRB support 729 // 730 if ((driverExtension->SrbSupport & CLASS_SRB_SCSI_REQUEST_BLOCK) == 0) { 731 NT_ASSERT(FALSE); 732 } 733 } else { 734 status = STATUS_INVALID_PARAMETER; 735 } 736 } 737 else 738 { 739 status = STATUS_NOT_SUPPORTED; 740 } 741 742 return status; 743 744 } // end ClassInitializeEx() 745 746 /*++//////////////////////////////////////////////////////////////////////////// 747 748 ClassUnload() 749 750 Routine Description: 751 752 called when there are no more references to the driver. this allows 753 drivers to be updated without rebooting. 754 755 Arguments: 756 757 DriverObject - a pointer to the driver object that is being unloaded 758 759 Status: 760 761 --*/ 762 VOID 763 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 764 ClassUnload( 765 IN PDRIVER_OBJECT DriverObject 766 ) 767 { 768 PCLASS_DRIVER_EXTENSION driverExtension; 769 770 PAGED_CODE(); 771 772 NT_ASSERT( DriverObject->DeviceObject == NULL ); 773 774 #ifdef _MSC_VER 775 #pragma warning(suppress:4054) // okay to type cast function pointer as data pointer for this use case 776 #endif 777 driverExtension = IoGetDriverObjectExtension( DriverObject, CLASS_DRIVER_EXTENSION_KEY ); 778 779 780 if (driverExtension == NULL) 781 { 782 NT_ASSERT(FALSE); 783 return; 784 } 785 786 NT_ASSERT(driverExtension->RegistryPath.Buffer != NULL); 787 NT_ASSERT(driverExtension->InitData.ClassUnload != NULL); 788 789 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, "ClassUnload: driver unloading %wZ\n", 790 &driverExtension->RegistryPath)); 791 792 // 793 // attempt to process the driver's unload routine first. 794 // 795 796 driverExtension->InitData.ClassUnload(DriverObject); 797 798 // 799 // free own allocated resources and return 800 // 801 802 FREE_POOL( driverExtension->WorkingSet ); 803 FREE_POOL( driverExtension->InterpretSenseInfo ); 804 FREE_POOL( driverExtension->RegistryPath.Buffer ); 805 driverExtension->RegistryPath.Length = 0; 806 driverExtension->RegistryPath.MaximumLength = 0; 807 808 809 // 810 // Unregister ETW 811 // 812 if (driverExtension->EtwHandle != 0) { 813 EtwUnregister(driverExtension->EtwHandle); 814 driverExtension->EtwHandle = 0; 815 816 WPP_CLEANUP(DriverObject); 817 } 818 819 820 return; 821 } // end ClassUnload() 822 823 /*++//////////////////////////////////////////////////////////////////////////// 824 825 ClassAddDevice() 826 827 Routine Description: 828 829 SCSI class driver add device routine. This is called by pnp when a new 830 physical device come into being. 831 832 This routine will call out to the class driver to verify that it should 833 own this device then will create and attach a device object and then hand 834 it to the driver to initialize and create symbolic links 835 836 Arguments: 837 838 DriverObject - a pointer to the driver object that this is being created for 839 PhysicalDeviceObject - a pointer to the physical device object 840 841 Status: STATUS_NO_SUCH_DEVICE if the class driver did not want this device 842 STATUS_SUCCESS if the creation and attachment was successful 843 status of device creation and initialization 844 845 --*/ 846 NTSTATUS 847 #ifdef _MSC_VER 848 #pragma prefast(suppress:28152, "We expect the class driver to clear the DO_DEVICE_INITIALIZING flag in its AddDevice routine.") 849 #endif 850 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 851 ClassAddDevice( 852 IN PDRIVER_OBJECT DriverObject, 853 IN PDEVICE_OBJECT PhysicalDeviceObject 854 ) 855 { 856 #ifdef _MSC_VER 857 #pragma warning(suppress:4054) // okay to type cast function pointer as data pointer for this use case 858 #endif 859 PCLASS_DRIVER_EXTENSION driverExtension = IoGetDriverObjectExtension(DriverObject, CLASS_DRIVER_EXTENSION_KEY); 860 861 NTSTATUS status; 862 863 PAGED_CODE(); 864 865 866 status = driverExtension->InitData.ClassAddDevice(DriverObject, 867 PhysicalDeviceObject); 868 869 return status; 870 } // end ClassAddDevice() 871 872 /*++//////////////////////////////////////////////////////////////////////////// 873 874 ClassDispatchPnp() 875 876 Routine Description: 877 878 Storage class driver pnp routine. This is called by the io system when 879 a PNP request is sent to the device. 880 881 Arguments: 882 883 DeviceObject - pointer to the device object 884 885 Irp - pointer to the io request packet 886 887 Return Value: 888 889 status 890 891 --*/ 892 NTSTATUS 893 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 894 ClassDispatchPnp( 895 IN PDEVICE_OBJECT DeviceObject, 896 IN PIRP Irp 897 ) 898 { 899 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 900 BOOLEAN isFdo = commonExtension->IsFdo; 901 902 PCLASS_DRIVER_EXTENSION driverExtension; 903 PCLASS_INIT_DATA initData; 904 PCLASS_DEV_INFO devInfo; 905 906 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); 907 908 NTSTATUS status = Irp->IoStatus.Status; 909 BOOLEAN completeRequest = TRUE; 910 BOOLEAN lockReleased = FALSE; 911 912 913 PAGED_CODE(); 914 915 // 916 // Extract all the useful information out of the driver object 917 // extension 918 // 919 920 #ifdef _MSC_VER 921 #pragma warning(suppress:4054) // okay to type cast function pointer as data pointer for this use case 922 #endif 923 driverExtension = IoGetDriverObjectExtension(DeviceObject->DriverObject, CLASS_DRIVER_EXTENSION_KEY); 924 925 if (driverExtension){ 926 927 initData = &(driverExtension->InitData); 928 929 if(isFdo) { 930 devInfo = &(initData->FdoData); 931 } else { 932 devInfo = &(initData->PdoData); 933 } 934 935 ClassAcquireRemoveLock(DeviceObject, Irp); 936 937 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "ClassDispatchPnp (%p,%p): minor code %#x for %s %p\n", 938 DeviceObject, Irp, 939 irpStack->MinorFunction, 940 isFdo ? "fdo" : "pdo", 941 DeviceObject)); 942 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "ClassDispatchPnp (%p,%p): previous %#x, current %#x\n", 943 DeviceObject, Irp, 944 commonExtension->PreviousState, 945 commonExtension->CurrentState)); 946 947 948 switch(irpStack->MinorFunction) { 949 950 case IRP_MN_START_DEVICE: { 951 952 // 953 // if this is sent to the FDO we should forward it down the 954 // attachment chain before we start the FDO. 955 // 956 957 if (isFdo) { 958 status = ClassForwardIrpSynchronous(commonExtension, Irp); 959 } 960 else { 961 status = STATUS_SUCCESS; 962 } 963 964 if (NT_SUCCESS(status)){ 965 status = Irp->IoStatus.Status = ClassPnpStartDevice(DeviceObject); 966 } 967 968 break; 969 } 970 971 972 case IRP_MN_QUERY_DEVICE_RELATIONS: { 973 974 DEVICE_RELATION_TYPE type = 975 irpStack->Parameters.QueryDeviceRelations.Type; 976 977 PDEVICE_RELATIONS deviceRelations = NULL; 978 979 980 if(!isFdo) { 981 982 if(type == TargetDeviceRelation) { 983 984 // 985 // Device relations has one entry built in to it's size. 986 // 987 988 status = STATUS_INSUFFICIENT_RESOURCES; 989 990 deviceRelations = ExAllocatePoolWithTag(PagedPool, 991 sizeof(DEVICE_RELATIONS), 992 '2CcS'); 993 994 if(deviceRelations != NULL) { 995 996 RtlZeroMemory(deviceRelations, 997 sizeof(DEVICE_RELATIONS)); 998 999 Irp->IoStatus.Information = (ULONG_PTR) deviceRelations; 1000 1001 deviceRelations->Count = 1; 1002 deviceRelations->Objects[0] = DeviceObject; 1003 ObReferenceObject(deviceRelations->Objects[0]); 1004 1005 status = STATUS_SUCCESS; 1006 } 1007 1008 } else { 1009 // 1010 // PDO's just complete enumeration requests without altering 1011 // the status. 1012 // 1013 1014 status = Irp->IoStatus.Status; 1015 } 1016 1017 break; 1018 1019 } else if (type == BusRelations) { 1020 1021 NT_ASSERT(commonExtension->IsInitialized); 1022 1023 // 1024 // Make sure we support enumeration 1025 // 1026 1027 if(initData->ClassEnumerateDevice == NULL) { 1028 1029 // 1030 // Just send the request down to the lower driver. Perhaps 1031 // It can enumerate children. 1032 // 1033 1034 } else { 1035 1036 // 1037 // Re-enumerate the device 1038 // 1039 1040 status = ClassPnpQueryFdoRelations(DeviceObject, Irp); 1041 1042 if(!NT_SUCCESS(status)) { 1043 completeRequest = TRUE; 1044 break; 1045 } 1046 } 1047 } 1048 1049 1050 IoCopyCurrentIrpStackLocationToNext(Irp); 1051 ClassReleaseRemoveLock(DeviceObject, Irp); 1052 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 1053 completeRequest = FALSE; 1054 1055 break; 1056 } 1057 1058 case IRP_MN_QUERY_ID: { 1059 1060 BUS_QUERY_ID_TYPE idType = irpStack->Parameters.QueryId.IdType; 1061 UNICODE_STRING unicodeString; 1062 1063 1064 if(isFdo) { 1065 1066 1067 // 1068 // FDO's should just forward the query down to the lower 1069 // device objects 1070 // 1071 1072 IoCopyCurrentIrpStackLocationToNext(Irp); 1073 ClassReleaseRemoveLock(DeviceObject, Irp); 1074 1075 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 1076 completeRequest = FALSE; 1077 break; 1078 } 1079 1080 // 1081 // PDO's need to give an answer - this is easy for now 1082 // 1083 1084 RtlInitUnicodeString(&unicodeString, NULL); 1085 1086 status = ClassGetPdoId(DeviceObject, 1087 idType, 1088 &unicodeString); 1089 1090 if(status == STATUS_NOT_IMPLEMENTED) { 1091 // 1092 // The driver doesn't implement this ID (whatever it is). 1093 // Use the status out of the IRP so that we don't mangle a 1094 // response from someone else. 1095 // 1096 1097 status = Irp->IoStatus.Status; 1098 } else if(NT_SUCCESS(status)) { 1099 Irp->IoStatus.Information = (ULONG_PTR) unicodeString.Buffer; 1100 } else { 1101 Irp->IoStatus.Information = (ULONG_PTR) NULL; 1102 } 1103 1104 break; 1105 } 1106 1107 case IRP_MN_QUERY_STOP_DEVICE: 1108 case IRP_MN_QUERY_REMOVE_DEVICE: { 1109 1110 1111 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "ClassDispatchPnp (%p,%p): Processing QUERY_%s irp\n", 1112 DeviceObject, Irp, 1113 ((irpStack->MinorFunction == IRP_MN_QUERY_STOP_DEVICE) ? 1114 "STOP" : "REMOVE"))); 1115 1116 // 1117 // If this device is in use for some reason (paging, etc...) 1118 // then we need to fail the request. 1119 // 1120 1121 if(commonExtension->PagingPathCount != 0) { 1122 1123 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP, "ClassDispatchPnp (%p,%p): device is in paging " 1124 "path and cannot be removed\n", 1125 DeviceObject, Irp)); 1126 status = STATUS_DEVICE_BUSY; 1127 break; 1128 } 1129 1130 1131 // 1132 // Check with the class driver to see if the query operation 1133 // can succeed. 1134 // 1135 1136 if(irpStack->MinorFunction == IRP_MN_QUERY_STOP_DEVICE) { 1137 status = devInfo->ClassStopDevice(DeviceObject, 1138 irpStack->MinorFunction); 1139 } else { 1140 status = devInfo->ClassRemoveDevice(DeviceObject, 1141 irpStack->MinorFunction); 1142 } 1143 1144 if(NT_SUCCESS(status)) { 1145 1146 // 1147 // ASSERT that we never get two queries in a row, as 1148 // this will severly mess up the state machine 1149 // 1150 NT_ASSERT(commonExtension->CurrentState != irpStack->MinorFunction); 1151 commonExtension->PreviousState = commonExtension->CurrentState; 1152 commonExtension->CurrentState = irpStack->MinorFunction; 1153 1154 if(isFdo) { 1155 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "ClassDispatchPnp (%p,%p): Forwarding QUERY_" 1156 "%s irp\n", DeviceObject, Irp, 1157 ((irpStack->MinorFunction == IRP_MN_QUERY_STOP_DEVICE) ? 1158 "STOP" : "REMOVE"))); 1159 status = ClassForwardIrpSynchronous(commonExtension, Irp); 1160 } 1161 } 1162 1163 1164 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "ClassDispatchPnp (%p,%p): Final status == %x\n", 1165 DeviceObject, Irp, status)); 1166 1167 break; 1168 } 1169 1170 case IRP_MN_CANCEL_STOP_DEVICE: 1171 case IRP_MN_CANCEL_REMOVE_DEVICE: { 1172 1173 1174 // 1175 // Check with the class driver to see if the query or cancel 1176 // operation can succeed. 1177 // 1178 1179 if(irpStack->MinorFunction == IRP_MN_CANCEL_STOP_DEVICE) { 1180 status = devInfo->ClassStopDevice(DeviceObject, 1181 irpStack->MinorFunction); 1182 NT_ASSERTMSG("ClassDispatchPnp !! CANCEL_STOP_DEVICE should never be failed\n", NT_SUCCESS(status)); 1183 } else { 1184 status = devInfo->ClassRemoveDevice(DeviceObject, 1185 irpStack->MinorFunction); 1186 NT_ASSERTMSG("ClassDispatchPnp !! CANCEL_REMOVE_DEVICE should never be failed\n", NT_SUCCESS(status)); 1187 } 1188 1189 Irp->IoStatus.Status = status; 1190 1191 // 1192 // We got a CANCEL - roll back to the previous state only 1193 // if the current state is the respective QUERY state. 1194 // 1195 1196 if(((irpStack->MinorFunction == IRP_MN_CANCEL_STOP_DEVICE) && 1197 (commonExtension->CurrentState == IRP_MN_QUERY_STOP_DEVICE) 1198 ) || 1199 ((irpStack->MinorFunction == IRP_MN_CANCEL_REMOVE_DEVICE) && 1200 (commonExtension->CurrentState == IRP_MN_QUERY_REMOVE_DEVICE) 1201 ) 1202 ) { 1203 1204 commonExtension->CurrentState = 1205 commonExtension->PreviousState; 1206 commonExtension->PreviousState = 0xff; 1207 1208 } 1209 1210 1211 if(isFdo) { 1212 1213 1214 IoCopyCurrentIrpStackLocationToNext(Irp); 1215 ClassReleaseRemoveLock(DeviceObject, Irp); 1216 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 1217 completeRequest = FALSE; 1218 } else { 1219 status = STATUS_SUCCESS; 1220 } 1221 1222 break; 1223 } 1224 1225 case IRP_MN_STOP_DEVICE: { 1226 1227 1228 // 1229 // These all mean nothing to the class driver currently. The 1230 // port driver will handle all queueing when necessary. 1231 // 1232 1233 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "ClassDispatchPnp (%p,%p): got stop request for %s\n", 1234 DeviceObject, Irp, 1235 (isFdo ? "fdo" : "pdo") 1236 )); 1237 1238 NT_ASSERT(commonExtension->PagingPathCount == 0); 1239 1240 // 1241 // ISSUE-2000/02/03-peterwie 1242 // if we stop the timer here then it means no class driver can 1243 // do i/o in its ClassStopDevice routine. This is because the 1244 // retry (among other things) is tied into the tick handler 1245 // and disabling retries could cause the class driver to deadlock. 1246 // Currently no class driver we're aware of issues i/o in its 1247 // Stop routine but this is a case we may want to defend ourself 1248 // against. 1249 // 1250 1251 ClasspDisableTimer((PFUNCTIONAL_DEVICE_EXTENSION)commonExtension); 1252 1253 1254 status = devInfo->ClassStopDevice(DeviceObject, IRP_MN_STOP_DEVICE); 1255 1256 NT_ASSERTMSG("ClassDispatchPnp !! STOP_DEVICE should never be failed\n", NT_SUCCESS(status)); 1257 1258 if(isFdo) { 1259 status = ClassForwardIrpSynchronous(commonExtension, Irp); 1260 } 1261 1262 if(NT_SUCCESS(status)) { 1263 commonExtension->CurrentState = irpStack->MinorFunction; 1264 commonExtension->PreviousState = 0xff; 1265 } 1266 1267 1268 break; 1269 } 1270 1271 case IRP_MN_REMOVE_DEVICE: 1272 case IRP_MN_SURPRISE_REMOVAL: { 1273 UCHAR removeType = irpStack->MinorFunction; 1274 1275 // 1276 // Log a sytem event when non-removable disks are surprise-removed. 1277 // 1278 if (isFdo && 1279 (removeType == IRP_MN_SURPRISE_REMOVAL)) { 1280 1281 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; 1282 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData; 1283 BOOLEAN logSurpriseRemove = TRUE; 1284 STORAGE_BUS_TYPE busType = fdoExtension->DeviceDescriptor->BusType; 1285 1286 // 1287 // Don't log an event for VHDs 1288 // 1289 if (busType == BusTypeFileBackedVirtual) { 1290 logSurpriseRemove = FALSE; 1291 1292 } else if (fdoData->HotplugInfo.MediaRemovable) { 1293 logSurpriseRemove = FALSE; 1294 1295 } else if (fdoData->HotplugInfo.DeviceHotplug && ( busType == BusTypeUsb || busType == BusType1394)) { 1296 1297 /* 1298 This device is reported as DeviceHotplug but since the busType is Usb or 1394, don't log an event 1299 Note that some storage arrays may report DeviceHotplug and we would like to log an event in those cases 1300 */ 1301 1302 logSurpriseRemove = FALSE; 1303 } 1304 1305 if (logSurpriseRemove) { 1306 1307 ClasspLogSystemEventWithDeviceNumber(DeviceObject, IO_WARNING_DISK_SURPRISE_REMOVED); 1308 } 1309 1310 } 1311 1312 if (commonExtension->PagingPathCount != 0) { 1313 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP, "ClassDispatchPnp (%p,%p): paging device is getting removed!", DeviceObject, Irp)); 1314 } 1315 1316 // 1317 // Release the lock for this IRP before calling in. 1318 // 1319 ClassReleaseRemoveLock(DeviceObject, Irp); 1320 lockReleased = TRUE; 1321 1322 /* 1323 * Set IsRemoved before propagating the REMOVE down the stack. 1324 * This keeps class-initiated I/O (e.g. the MCN irp) from getting sent 1325 * after we propagate the remove. 1326 */ 1327 commonExtension->IsRemoved = REMOVE_PENDING; 1328 1329 /* 1330 * If a timer was started on the device, stop it. 1331 */ 1332 ClasspDisableTimer((PFUNCTIONAL_DEVICE_EXTENSION)commonExtension); 1333 1334 /* 1335 * "Fire-and-forget" the remove irp to the lower stack. 1336 * Don't touch the irp (or the irp stack!) after this. 1337 */ 1338 if (isFdo) { 1339 1340 1341 IoCopyCurrentIrpStackLocationToNext(Irp); 1342 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 1343 NT_ASSERT(NT_SUCCESS(status)); 1344 completeRequest = FALSE; 1345 } 1346 else { 1347 status = STATUS_SUCCESS; 1348 } 1349 1350 /* 1351 * Do our own cleanup and call the class driver's remove 1352 * cleanup routine. 1353 * For IRP_MN_REMOVE_DEVICE, this also deletes our device object, 1354 * so don't touch the extension after this. 1355 */ 1356 commonExtension->PreviousState = commonExtension->CurrentState; 1357 commonExtension->CurrentState = removeType; 1358 ClassRemoveDevice(DeviceObject, removeType); 1359 1360 break; 1361 } 1362 1363 case IRP_MN_DEVICE_USAGE_NOTIFICATION: { 1364 1365 DEVICE_USAGE_NOTIFICATION_TYPE type = irpStack->Parameters.UsageNotification.Type; 1366 BOOLEAN setPagable; 1367 1368 1369 switch(type) { 1370 1371 case DeviceUsageTypePaging: { 1372 1373 if ((irpStack->Parameters.UsageNotification.InPath) && 1374 (commonExtension->CurrentState != IRP_MN_START_DEVICE)) { 1375 1376 // 1377 // Device isn't started. Don't allow adding a 1378 // paging file, but allow a removal of one. 1379 // 1380 1381 status = STATUS_DEVICE_NOT_READY; 1382 break; 1383 } 1384 1385 NT_ASSERT(commonExtension->IsInitialized); 1386 1387 /* 1388 * Ensure that this user thread is not suspended while we are holding the PathCountEvent. 1389 */ 1390 KeEnterCriticalRegion(); 1391 1392 (VOID)KeWaitForSingleObject(&commonExtension->PathCountEvent, 1393 Executive, KernelMode, 1394 FALSE, NULL); 1395 status = STATUS_SUCCESS; 1396 1397 // 1398 // If the volume is removable we should try to lock it in 1399 // place or unlock it once per paging path count 1400 // 1401 1402 if (commonExtension->IsFdo){ 1403 status = ClasspEjectionControl( 1404 DeviceObject, 1405 Irp, 1406 InternalMediaLock, 1407 (BOOLEAN)irpStack->Parameters.UsageNotification.InPath); 1408 } 1409 1410 if (!NT_SUCCESS(status)){ 1411 KeSetEvent(&commonExtension->PathCountEvent, IO_NO_INCREMENT, FALSE); 1412 KeLeaveCriticalRegion(); 1413 break; 1414 } 1415 1416 // 1417 // if removing last paging device, need to set DO_POWER_PAGABLE 1418 // bit here, and possible re-set it below on failure. 1419 // 1420 1421 setPagable = FALSE; 1422 1423 if ((!irpStack->Parameters.UsageNotification.InPath) && 1424 (commonExtension->PagingPathCount == 1)) { 1425 1426 // 1427 // removing last paging file 1428 // must have DO_POWER_PAGABLE bits set, but only 1429 // if none set the DO_POWER_INRUSH bit and no other special files 1430 // 1431 1432 if (TEST_FLAG(DeviceObject->Flags, DO_POWER_INRUSH)) { 1433 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "ClassDispatchPnp (%p,%p): Last " 1434 "paging file removed, but " 1435 "DO_POWER_INRUSH was set, so NOT " 1436 "setting DO_POWER_PAGABLE\n", 1437 DeviceObject, Irp)); 1438 } else if ((commonExtension->HibernationPathCount == 0) && 1439 (commonExtension->DumpPathCount == 0)) { 1440 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "ClassDispatchPnp (%p,%p): Last " 1441 "paging file removed, " 1442 "setting DO_POWER_PAGABLE\n", 1443 DeviceObject, Irp)); 1444 SET_FLAG(DeviceObject->Flags, DO_POWER_PAGABLE); 1445 setPagable = TRUE; 1446 } 1447 1448 } 1449 1450 // 1451 // forward the irp before finishing handling the 1452 // special cases 1453 // 1454 1455 status = ClassForwardIrpSynchronous(commonExtension, Irp); 1456 1457 // 1458 // now deal with the failure and success cases. 1459 // note that we are not allowed to fail the irp 1460 // once it is sent to the lower drivers. 1461 // 1462 1463 if (NT_SUCCESS(status)) { 1464 1465 IoAdjustPagingPathCount( 1466 (volatile LONG *)&commonExtension->PagingPathCount, 1467 irpStack->Parameters.UsageNotification.InPath); 1468 1469 if (irpStack->Parameters.UsageNotification.InPath) { 1470 if (commonExtension->PagingPathCount == 1) { 1471 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "ClassDispatchPnp (%p,%p): " 1472 "Clearing PAGABLE bit\n", 1473 DeviceObject, Irp)); 1474 CLEAR_FLAG(DeviceObject->Flags, DO_POWER_PAGABLE); 1475 1476 1477 } 1478 1479 } 1480 1481 } else { 1482 1483 // 1484 // cleanup the changes done above 1485 // 1486 1487 if (setPagable == TRUE) { 1488 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "ClassDispatchPnp (%p,%p): Unsetting " 1489 "PAGABLE bit due to irp failure\n", 1490 DeviceObject, Irp)); 1491 CLEAR_FLAG(DeviceObject->Flags, DO_POWER_PAGABLE); 1492 setPagable = FALSE; 1493 } 1494 1495 // 1496 // relock or unlock the media if needed. 1497 // 1498 1499 if (commonExtension->IsFdo) { 1500 1501 ClasspEjectionControl( 1502 DeviceObject, 1503 Irp, 1504 InternalMediaLock, 1505 (BOOLEAN)!irpStack->Parameters.UsageNotification.InPath); 1506 } 1507 } 1508 1509 // 1510 // set the event so the next one can occur. 1511 // 1512 1513 KeSetEvent(&commonExtension->PathCountEvent, 1514 IO_NO_INCREMENT, FALSE); 1515 KeLeaveCriticalRegion(); 1516 break; 1517 } 1518 1519 case DeviceUsageTypeHibernation: { 1520 1521 // 1522 // if removing last hiber device, need to set DO_POWER_PAGABLE 1523 // bit here, and possible re-set it below on failure. 1524 // 1525 1526 setPagable = FALSE; 1527 1528 if ((!irpStack->Parameters.UsageNotification.InPath) && 1529 (commonExtension->HibernationPathCount == 1)) { 1530 1531 // 1532 // removing last hiber file 1533 // must have DO_POWER_PAGABLE bits set, but only 1534 // if none set the DO_POWER_INRUSH bit and no other special files 1535 // 1536 1537 if (TEST_FLAG(DeviceObject->Flags, DO_POWER_INRUSH)) { 1538 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "ClassDispatchPnp (%p,%p): Last " 1539 "hiber file removed, but " 1540 "DO_POWER_INRUSH was set, so NOT " 1541 "setting DO_POWER_PAGABLE\n", 1542 DeviceObject, Irp)); 1543 } else if ((commonExtension->PagingPathCount == 0) && 1544 (commonExtension->DumpPathCount == 0)) { 1545 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "ClassDispatchPnp (%p,%p): Last " 1546 "hiber file removed, " 1547 "setting DO_POWER_PAGABLE\n", 1548 DeviceObject, Irp)); 1549 SET_FLAG(DeviceObject->Flags, DO_POWER_PAGABLE); 1550 setPagable = TRUE; 1551 } 1552 1553 } 1554 1555 status = ClassForwardIrpSynchronous(commonExtension, Irp); 1556 if (!NT_SUCCESS(status)) { 1557 1558 if (setPagable == TRUE) { 1559 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "ClassDispatchPnp (%p,%p): Unsetting " 1560 "PAGABLE bit due to irp failure\n", 1561 DeviceObject, Irp)); 1562 CLEAR_FLAG(DeviceObject->Flags, DO_POWER_PAGABLE); 1563 setPagable = FALSE; 1564 } 1565 1566 } else { 1567 1568 IoAdjustPagingPathCount( 1569 (volatile LONG *)&commonExtension->HibernationPathCount, 1570 irpStack->Parameters.UsageNotification.InPath 1571 ); 1572 1573 if ((irpStack->Parameters.UsageNotification.InPath) && 1574 (commonExtension->HibernationPathCount == 1)) { 1575 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "ClassDispatchPnp (%p,%p): " 1576 "Clearing PAGABLE bit\n", 1577 DeviceObject, Irp)); 1578 CLEAR_FLAG(DeviceObject->Flags, DO_POWER_PAGABLE); 1579 } 1580 } 1581 1582 break; 1583 } 1584 1585 case DeviceUsageTypeDumpFile: { 1586 1587 // 1588 // if removing last dump device, need to set DO_POWER_PAGABLE 1589 // bit here, and possible re-set it below on failure. 1590 // 1591 1592 setPagable = FALSE; 1593 1594 if ((!irpStack->Parameters.UsageNotification.InPath) && 1595 (commonExtension->DumpPathCount == 1)) { 1596 1597 // 1598 // removing last dump file 1599 // must have DO_POWER_PAGABLE bits set, but only 1600 // if none set the DO_POWER_INRUSH bit and no other special files 1601 // 1602 1603 if (TEST_FLAG(DeviceObject->Flags, DO_POWER_INRUSH)) { 1604 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "ClassDispatchPnp (%p,%p): Last " 1605 "dump file removed, but " 1606 "DO_POWER_INRUSH was set, so NOT " 1607 "setting DO_POWER_PAGABLE\n", 1608 DeviceObject, Irp)); 1609 } else if ((commonExtension->PagingPathCount == 0) && 1610 (commonExtension->HibernationPathCount == 0)) { 1611 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "ClassDispatchPnp (%p,%p): Last " 1612 "dump file removed, " 1613 "setting DO_POWER_PAGABLE\n", 1614 DeviceObject, Irp)); 1615 SET_FLAG(DeviceObject->Flags, DO_POWER_PAGABLE); 1616 setPagable = TRUE; 1617 } 1618 1619 } 1620 1621 status = ClassForwardIrpSynchronous(commonExtension, Irp); 1622 if (!NT_SUCCESS(status)) { 1623 1624 if (setPagable == TRUE) { 1625 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "ClassDispatchPnp (%p,%p): Unsetting " 1626 "PAGABLE bit due to irp failure\n", 1627 DeviceObject, Irp)); 1628 CLEAR_FLAG(DeviceObject->Flags, DO_POWER_PAGABLE); 1629 setPagable = FALSE; 1630 } 1631 1632 } else { 1633 1634 IoAdjustPagingPathCount( 1635 (volatile LONG *)&commonExtension->DumpPathCount, 1636 irpStack->Parameters.UsageNotification.InPath 1637 ); 1638 1639 if ((irpStack->Parameters.UsageNotification.InPath) && 1640 (commonExtension->DumpPathCount == 1)) { 1641 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "ClassDispatchPnp (%p,%p): " 1642 "Clearing PAGABLE bit\n", 1643 DeviceObject, Irp)); 1644 CLEAR_FLAG(DeviceObject->Flags, DO_POWER_PAGABLE); 1645 } 1646 } 1647 1648 break; 1649 } 1650 1651 case DeviceUsageTypeBoot: { 1652 1653 if (isFdo) { 1654 PCLASS_PRIVATE_FDO_DATA fdoData; 1655 1656 fdoData = ((PFUNCTIONAL_DEVICE_EXTENSION)(DeviceObject->DeviceExtension))->PrivateFdoData; 1657 1658 1659 // 1660 // If boot disk has removal policy as RemovalPolicyExpectSurpriseRemoval (e.g. disk is hotplug-able), 1661 // change the removal policy to RemovalPolicyExpectOrderlyRemoval. 1662 // This will cause the write cache of disk to be enabled on subsequent start Fdo (next boot). 1663 // 1664 if ((fdoData != NULL) && 1665 fdoData->HotplugInfo.DeviceHotplug) { 1666 1667 fdoData->HotplugInfo.DeviceHotplug = FALSE; 1668 fdoData->HotplugInfo.MediaRemovable = FALSE; 1669 1670 ClassSetDeviceParameter((PFUNCTIONAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension, 1671 CLASSP_REG_SUBKEY_NAME, 1672 CLASSP_REG_REMOVAL_POLICY_VALUE_NAME, 1673 RemovalPolicyExpectOrderlyRemoval); 1674 } 1675 } 1676 1677 status = ClassForwardIrpSynchronous(commonExtension, Irp); 1678 break; 1679 } 1680 1681 default: { 1682 status = STATUS_INVALID_PARAMETER; 1683 break; 1684 } 1685 } 1686 break; 1687 } 1688 1689 case IRP_MN_QUERY_CAPABILITIES: { 1690 1691 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "ClassDispatchPnp (%p,%p): QueryCapabilities\n", 1692 DeviceObject, Irp)); 1693 1694 if(!isFdo) { 1695 1696 status = ClassQueryPnpCapabilities( 1697 DeviceObject, 1698 irpStack->Parameters.DeviceCapabilities.Capabilities 1699 ); 1700 1701 break; 1702 1703 } else { 1704 1705 PDEVICE_CAPABILITIES deviceCapabilities; 1706 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension; 1707 PCLASS_PRIVATE_FDO_DATA fdoData; 1708 1709 fdoExtension = DeviceObject->DeviceExtension; 1710 fdoData = fdoExtension->PrivateFdoData; 1711 deviceCapabilities = 1712 irpStack->Parameters.DeviceCapabilities.Capabilities; 1713 1714 // 1715 // forward the irp before handling the special cases 1716 // 1717 1718 status = ClassForwardIrpSynchronous(commonExtension, Irp); 1719 if (!NT_SUCCESS(status)) { 1720 break; 1721 } 1722 1723 // 1724 // we generally want to remove the device from the hotplug 1725 // applet, which requires the SR-OK bit to be set. 1726 // only when the user specifies that they are capable of 1727 // safely removing things do we want to clear this bit 1728 // (saved in WriteCacheEnableOverride) 1729 // 1730 // setting of this bit is done either above, or by the 1731 // lower driver. 1732 // 1733 // note: may not be started, so check we have FDO data first. 1734 // 1735 1736 if (fdoData && 1737 fdoData->HotplugInfo.WriteCacheEnableOverride) { 1738 if (deviceCapabilities->SurpriseRemovalOK) { 1739 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "Classpnp: Clearing SR-OK bit in " 1740 "device capabilities due to hotplug " 1741 "device or media\n")); 1742 } 1743 deviceCapabilities->SurpriseRemovalOK = FALSE; 1744 } 1745 break; 1746 1747 } // end QUERY_CAPABILITIES for FDOs 1748 1749 break; 1750 1751 1752 } // end QUERY_CAPABILITIES 1753 1754 default: { 1755 1756 if (isFdo){ 1757 1758 1759 IoCopyCurrentIrpStackLocationToNext(Irp); 1760 1761 ClassReleaseRemoveLock(DeviceObject, Irp); 1762 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 1763 1764 completeRequest = FALSE; 1765 } 1766 1767 break; 1768 } 1769 } 1770 } 1771 else { 1772 NT_ASSERT(driverExtension); 1773 status = STATUS_INTERNAL_ERROR; 1774 } 1775 1776 if (completeRequest){ 1777 Irp->IoStatus.Status = status; 1778 1779 if (!lockReleased){ 1780 ClassReleaseRemoveLock(DeviceObject, Irp); 1781 } 1782 1783 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 1784 1785 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "ClassDispatchPnp (%p,%p): leaving with previous %#x, current %#x.", DeviceObject, Irp, commonExtension->PreviousState, commonExtension->CurrentState)); 1786 } 1787 else { 1788 /* 1789 * The irp is already completed so don't touch it. 1790 * This may be a remove so don't touch the device extension. 1791 */ 1792 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "ClassDispatchPnp (%p,%p): leaving.", DeviceObject, Irp)); 1793 } 1794 1795 return status; 1796 } // end ClassDispatchPnp() 1797 1798 1799 /*++//////////////////////////////////////////////////////////////////////////// 1800 1801 ClassPnpStartDevice() 1802 1803 Routine Description: 1804 1805 Storage class driver routine for IRP_MN_START_DEVICE requests. 1806 This routine kicks off any device specific initialization 1807 1808 Arguments: 1809 1810 DeviceObject - a pointer to the device object 1811 1812 Irp - a pointer to the io request packet 1813 1814 Return Value: 1815 1816 none 1817 1818 --*/ 1819 NTSTATUS ClassPnpStartDevice(IN PDEVICE_OBJECT DeviceObject) 1820 { 1821 PCLASS_DRIVER_EXTENSION driverExtension; 1822 PCLASS_INIT_DATA initData; 1823 1824 PCLASS_DEV_INFO devInfo; 1825 1826 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 1827 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; 1828 BOOLEAN isFdo = commonExtension->IsFdo; 1829 1830 BOOLEAN isMountedDevice = TRUE; 1831 BOOLEAN isPortable = FALSE; 1832 1833 NTSTATUS status = STATUS_SUCCESS; 1834 PDEVICE_POWER_DESCRIPTOR powerDescriptor = NULL; 1835 1836 1837 PAGED_CODE(); 1838 1839 #ifdef _MSC_VER 1840 #pragma warning(suppress:4054) // okay to type cast function pointer as data pointer for this use case 1841 #endif 1842 driverExtension = IoGetDriverObjectExtension(DeviceObject->DriverObject, CLASS_DRIVER_EXTENSION_KEY); 1843 1844 initData = &(driverExtension->InitData); 1845 if(isFdo) { 1846 devInfo = &(initData->FdoData); 1847 } else { 1848 devInfo = &(initData->PdoData); 1849 } 1850 1851 NT_ASSERT(devInfo->ClassInitDevice != NULL); 1852 NT_ASSERT(devInfo->ClassStartDevice != NULL); 1853 1854 if (!commonExtension->IsInitialized){ 1855 1856 // 1857 // perform FDO/PDO specific initialization 1858 // 1859 1860 if (isFdo){ 1861 STORAGE_PROPERTY_ID propertyId; 1862 1863 // 1864 // allocate a private extension for class data 1865 // 1866 1867 if (fdoExtension->PrivateFdoData == NULL) { 1868 fdoExtension->PrivateFdoData = ExAllocatePoolWithTag(NonPagedPoolNx, 1869 sizeof(CLASS_PRIVATE_FDO_DATA), 1870 CLASS_TAG_PRIVATE_DATA 1871 ); 1872 } 1873 1874 if (fdoExtension->PrivateFdoData == NULL) { 1875 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "ClassPnpStartDevice: Cannot allocate for private fdo data\n")); 1876 return STATUS_INSUFFICIENT_RESOURCES; 1877 } 1878 1879 RtlZeroMemory(fdoExtension->PrivateFdoData, sizeof(CLASS_PRIVATE_FDO_DATA)); 1880 1881 1882 #if (NTDDI_VERSION >= NTDDI_WINTHRESHOLD) 1883 // 1884 // Allocate a structure to hold more data than what we can put in FUNCTIONAL_DEVICE_EXTENSION. 1885 // This structure's memory is managed by classpnp, so it is more extensible. 1886 // 1887 if (fdoExtension->AdditionalFdoData == NULL) { 1888 fdoExtension->AdditionalFdoData = ExAllocatePoolWithTag(NonPagedPoolNx, 1889 sizeof(ADDITIONAL_FDO_DATA), 1890 CLASSPNP_POOL_TAG_ADDITIONAL_DATA 1891 ); 1892 } 1893 1894 if (fdoExtension->AdditionalFdoData == NULL) { 1895 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "ClassPnpStartDevice: Cannot allocate memory for the additional data structure.\n")); 1896 return STATUS_INSUFFICIENT_RESOURCES; 1897 } 1898 1899 RtlZeroMemory(fdoExtension->AdditionalFdoData, sizeof(ADDITIONAL_FDO_DATA)); 1900 #endif 1901 1902 status = ClasspInitializeTimer(fdoExtension); 1903 if (NT_SUCCESS(status) == FALSE) { 1904 FREE_POOL(fdoExtension->PrivateFdoData); 1905 #if (NTDDI_VERSION >= NTDDI_WINTHRESHOLD) 1906 FREE_POOL(fdoExtension->AdditionalFdoData); 1907 #endif 1908 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "ClassPnpStartDevice: Failed to initialize tick timer\n")); 1909 return STATUS_INSUFFICIENT_RESOURCES; 1910 } 1911 1912 // 1913 // allocate LowerLayerSupport for class data 1914 // 1915 1916 if (fdoExtension->FunctionSupportInfo == NULL) { 1917 fdoExtension->FunctionSupportInfo = (PCLASS_FUNCTION_SUPPORT_INFO)ExAllocatePoolWithTag(NonPagedPoolNx, 1918 sizeof(CLASS_FUNCTION_SUPPORT_INFO), 1919 '3BcS' 1920 ); 1921 } 1922 1923 if (fdoExtension->FunctionSupportInfo == NULL) { 1924 ClasspDeleteTimer(fdoExtension); 1925 FREE_POOL(fdoExtension->PrivateFdoData); 1926 #if (NTDDI_VERSION >= NTDDI_WINTHRESHOLD) 1927 FREE_POOL(fdoExtension->AdditionalFdoData); 1928 #endif 1929 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "ClassPnpStartDevice: Cannot allocate for FunctionSupportInfo\n")); 1930 return STATUS_INSUFFICIENT_RESOURCES; 1931 } 1932 1933 // 1934 // initialize the struct's various fields. 1935 // 1936 RtlZeroMemory(fdoExtension->FunctionSupportInfo, sizeof(CLASS_FUNCTION_SUPPORT_INFO)); 1937 KeInitializeSpinLock(&fdoExtension->FunctionSupportInfo->SyncLock); 1938 1939 // 1940 // intialize the CommandStatus to -1 indicates that no effort made yet to retrieve the info. 1941 // Possible values of CommandStatus (data type: NTSTATUS): 1942 // -1: It's not attempted yet to retrieve the information. 1943 // success: Command sent and succeeded, information cached in FdoExtension. 1944 // failed/warning: Command is either not supported or failed by device or lower level driver. 1945 // The command should not be attempted again. 1946 // 1947 fdoExtension->FunctionSupportInfo->BlockLimitsData.CommandStatus = -1; 1948 fdoExtension->FunctionSupportInfo->DeviceCharacteristicsData.CommandStatus = -1; 1949 fdoExtension->FunctionSupportInfo->LBProvisioningData.CommandStatus = -1; 1950 fdoExtension->FunctionSupportInfo->ReadCapacity16Data.CommandStatus = -1; 1951 fdoExtension->FunctionSupportInfo->BlockDeviceRODLimitsData.CommandStatus = -1; 1952 1953 1954 KeInitializeTimer(&fdoExtension->PrivateFdoData->Retry.Timer); 1955 KeInitializeDpc(&fdoExtension->PrivateFdoData->Retry.Dpc, 1956 ClasspRetryRequestDpc, 1957 DeviceObject); 1958 KeInitializeSpinLock(&fdoExtension->PrivateFdoData->Retry.Lock); 1959 fdoExtension->PrivateFdoData->Retry.Granularity = KeQueryTimeIncrement(); 1960 commonExtension->Reserved4 = (ULONG_PTR)(' GPH'); // debug aid 1961 InitializeListHead(&fdoExtension->PrivateFdoData->DeferredClientIrpList); 1962 1963 KeInitializeSpinLock(&fdoExtension->PrivateFdoData->SpinLock); 1964 1965 // 1966 // keep a pointer to the senseinfo2 stuff locally also (used in every read/write). 1967 // 1968 fdoExtension->PrivateFdoData->InterpretSenseInfo = driverExtension->InterpretSenseInfo; 1969 1970 fdoExtension->PrivateFdoData->MaxNumberOfIoRetries = NUM_IO_RETRIES; 1971 1972 // 1973 // Initialize release queue extended SRB 1974 // 1975 status = InitializeStorageRequestBlock(&(fdoExtension->PrivateFdoData->ReleaseQueueSrb.SrbEx), 1976 STORAGE_ADDRESS_TYPE_BTL8, 1977 sizeof(fdoExtension->PrivateFdoData->ReleaseQueueSrb.ReleaseQueueSrbBuffer), 1978 0); 1979 if (!NT_SUCCESS(status)) { 1980 NT_ASSERT(FALSE); 1981 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, 1982 "ClassPnpStartDevice: fail to initialize release queue extended SRB 0x%x\n", status)); 1983 return status; 1984 } 1985 1986 1987 /* 1988 * Anchor the FDO in our static list. 1989 * Pnp is synchronized, so we shouldn't need any synchronization here. 1990 */ 1991 InsertTailList(&AllFdosList, &fdoExtension->PrivateFdoData->AllFdosListEntry); 1992 1993 // 1994 // NOTE: the old interface allowed the class driver to allocate 1995 // this. this was unsafe for low-memory conditions. allocate one 1996 // unconditionally now, and modify our internal functions to use 1997 // our own exclusively as it is the only safe way to do this. 1998 // 1999 2000 status = ClasspAllocateReleaseQueueIrp(fdoExtension); 2001 if (!NT_SUCCESS(status)) { 2002 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "ClassPnpStartDevice: Cannot allocate the private release queue irp\n")); 2003 return status; 2004 } 2005 2006 status = ClasspAllocatePowerProcessIrp(fdoExtension); 2007 if (!NT_SUCCESS(status)) { 2008 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "ClassPnpStartDevice: Cannot allocate the power process irp\n")); 2009 return status; 2010 } 2011 2012 // 2013 // Call port driver to get miniport properties for disk devices 2014 // It's ok for this call to fail 2015 // 2016 2017 if ((DeviceObject->DeviceType == FILE_DEVICE_DISK) && 2018 (!TEST_FLAG(DeviceObject->Characteristics, FILE_FLOPPY_DISKETTE))) { 2019 2020 propertyId = StorageMiniportProperty; 2021 2022 status = ClassGetDescriptor(fdoExtension->CommonExtension.LowerDeviceObject, 2023 &propertyId, 2024 (PVOID *)&fdoExtension->MiniportDescriptor); 2025 2026 // 2027 // function ClassGetDescriptor returns succeed with buffer "fdoExtension->MiniportDescriptor" allocated. 2028 // 2029 if ( NT_SUCCESS(status) && 2030 (fdoExtension->MiniportDescriptor->Portdriver != StoragePortCodeSetStorport && 2031 fdoExtension->MiniportDescriptor->Portdriver != StoragePortCodeSetUSBport) ) { 2032 // 2033 // field "IoTimeoutValue" supported for either Storport or USBStor 2034 // 2035 fdoExtension->MiniportDescriptor->IoTimeoutValue = 0; 2036 } 2037 2038 2039 2040 } 2041 2042 // 2043 // Call port driver to get adapter capabilities. 2044 // 2045 2046 propertyId = StorageAdapterProperty; 2047 2048 status = ClassGetDescriptor( 2049 commonExtension->LowerDeviceObject, 2050 &propertyId, 2051 (PVOID *)&fdoExtension->AdapterDescriptor); 2052 if (!NT_SUCCESS(status)) { 2053 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "ClassPnpStartDevice: ClassGetDescriptor [ADAPTER] failed %lx\n", status)); 2054 return status; 2055 } 2056 2057 // 2058 // Call port driver to get device descriptor. 2059 // 2060 2061 propertyId = StorageDeviceProperty; 2062 2063 status = ClassGetDescriptor( 2064 commonExtension->LowerDeviceObject, 2065 &propertyId, 2066 (PVOID *)&fdoExtension->DeviceDescriptor); 2067 if (NT_SUCCESS(status)){ 2068 2069 ClasspScanForSpecialInRegistry(fdoExtension); 2070 ClassScanForSpecial(fdoExtension, ClassBadItems, ClasspScanForClassHacks); 2071 2072 // 2073 // allow perf to be re-enabled after a given number of failed IOs 2074 // require this number to be at least CLASS_PERF_RESTORE_MINIMUM 2075 // 2076 2077 { 2078 ULONG t = CLASS_PERF_RESTORE_MINIMUM; 2079 2080 ClassGetDeviceParameter(fdoExtension, 2081 CLASSP_REG_SUBKEY_NAME, 2082 CLASSP_REG_PERF_RESTORE_VALUE_NAME, 2083 &t); 2084 if (t >= CLASS_PERF_RESTORE_MINIMUM) { 2085 fdoExtension->PrivateFdoData->Perf.ReEnableThreshhold = t; 2086 } 2087 } 2088 2089 // 2090 // compatibility comes first. writable cd media will not 2091 // get a SYNCH_CACHE on power down. 2092 // 2093 if (fdoExtension->DeviceObject->DeviceType != FILE_DEVICE_DISK) { 2094 SET_FLAG(fdoExtension->PrivateFdoData->HackFlags, FDO_HACK_NO_SYNC_CACHE); 2095 } 2096 2097 2098 // 2099 // Test if the device is portable and updated the characteristics if so 2100 // 2101 status = ClasspIsPortable(fdoExtension, 2102 &isPortable); 2103 2104 if (NT_SUCCESS(status) && (isPortable == TRUE)) { 2105 DeviceObject->Characteristics |= FILE_PORTABLE_DEVICE; 2106 } 2107 2108 // 2109 // initialize the hotplug information only after the ScanForSpecial 2110 // routines, as it relies upon the hack flags. 2111 // 2112 status = ClasspInitializeHotplugInfo(fdoExtension); 2113 if (NT_SUCCESS(status)){ 2114 /* 2115 * Allocate/initialize TRANSFER_PACKETs and related resources. 2116 */ 2117 status = InitializeTransferPackets(DeviceObject); 2118 } 2119 else { 2120 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP, "ClassPnpStartDevice: Could not initialize hotplug information %lx\n", status)); 2121 } 2122 } 2123 else { 2124 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "ClassPnpStartDevice: ClassGetDescriptor [DEVICE] failed %lx\n", status)); 2125 return status; 2126 } 2127 2128 2129 if (NT_SUCCESS(status)) { 2130 2131 // 2132 // Retrieve info on whether async notification is supported by port drivers 2133 // 2134 propertyId = StorageDevicePowerProperty; 2135 2136 status = ClassGetDescriptor(fdoExtension->CommonExtension.LowerDeviceObject, 2137 &propertyId, 2138 (PVOID *)&powerDescriptor); 2139 if (NT_SUCCESS(status) && (powerDescriptor != NULL)) { 2140 fdoExtension->FunctionSupportInfo->AsynchronousNotificationSupported = powerDescriptor->AsynchronousNotificationSupported; 2141 fdoExtension->FunctionSupportInfo->IdlePower.D3ColdSupported = powerDescriptor->D3ColdSupported; 2142 fdoExtension->FunctionSupportInfo->IdlePower.NoVerifyDuringIdlePower = powerDescriptor->NoVerifyDuringIdlePower; 2143 FREE_POOL(powerDescriptor); 2144 } else { 2145 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "ClassPnpStartDevice: ClassGetDescriptor [DevicePower] failed %lx\n", status)); 2146 2147 // 2148 // Ignore error as device power property is optional 2149 // 2150 status = STATUS_SUCCESS; 2151 } 2152 } 2153 } 2154 2155 // 2156 // ISSUE - drivers need to disable write caching on the media 2157 // if hotplug and !useroverride. perhaps we should 2158 // allow registration of a callback to enable/disable 2159 // write cache instead. 2160 // 2161 2162 if (NT_SUCCESS(status)){ 2163 status = devInfo->ClassInitDevice(DeviceObject); 2164 } 2165 2166 if (commonExtension->IsFdo) { 2167 fdoExtension->PrivateFdoData->Perf.OriginalSrbFlags = fdoExtension->SrbFlags; 2168 2169 // 2170 // initialization for disk device 2171 // 2172 if ((DeviceObject->DeviceType == FILE_DEVICE_DISK) && 2173 (!TEST_FLAG(DeviceObject->Characteristics, FILE_FLOPPY_DISKETTE))) { 2174 2175 ULONG accessAlignmentNotSupported = 0; 2176 ULONG qerrOverrideMode = QERR_SET_ZERO_ODX_OR_TP_ONLY; 2177 ULONG legacyErrorHandling = FALSE; 2178 2179 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, 2180 "ClassPnpStartDevice: Enabling idle timer for %p\n", DeviceObject)); 2181 // Initialize idle timer for disk devices 2182 ClasspInitializeIdleTimer(fdoExtension); 2183 2184 if (ClasspIsObsoletePortDriver(fdoExtension) == FALSE) { 2185 // get INQUIRY VPD support information. It's safe to send command as everything is ready in ClassInitDevice(). 2186 ClasspGetInquiryVpdSupportInfo(fdoExtension); 2187 2188 // Query and cache away Logical Block Provisioning info in the FDO extension. 2189 // The cached information will be used in responding to some IOCTLs 2190 ClasspGetLBProvisioningInfo(fdoExtension); 2191 2192 // 2193 // Query and cache away Block Device ROD Limits info in the FDO extension. 2194 // 2195 if (fdoExtension->FunctionSupportInfo->ValidInquiryPages.BlockDeviceRODLimits) { 2196 ClassDetermineTokenOperationCommandSupport(DeviceObject); 2197 } 2198 2199 // 2200 // See if the user has specified a particular QERR override 2201 // mode. "Override" meaning setting QERR = 0 via Mode Select. 2202 // 0 = Only when ODX or Thin Provisioning are supported (default) 2203 // 1 = Always 2204 // 2 = Never (or any value >= 2) 2205 // 2206 ClassGetDeviceParameter(fdoExtension, 2207 CLASSP_REG_SUBKEY_NAME, 2208 CLASSP_REG_QERR_OVERRIDE_MODE, 2209 &qerrOverrideMode); 2210 2211 // 2212 // If this device is thinly provisioned or supports ODX, we 2213 // may need to force QERR to zero. The user may have also 2214 // specified that we should always or never do this. 2215 // 2216 if (qerrOverrideMode == QERR_SET_ZERO_ALWAYS || 2217 (qerrOverrideMode == QERR_SET_ZERO_ODX_OR_TP_ONLY && 2218 (ClasspIsThinProvisioned(fdoExtension->FunctionSupportInfo) || 2219 NT_SUCCESS(ClasspValidateOffloadSupported(DeviceObject, NULL))))) { 2220 2221 ClasspZeroQERR(DeviceObject); 2222 } 2223 2224 } else { 2225 2226 // 2227 // Since this device has been exposed by a legacy miniport (e.g. SCSIPort miniport) 2228 // set its LB Provisioning command status to an error status that will be surfaced 2229 // up to the caller of a TRIM/Unmap command. 2230 // 2231 fdoExtension->FunctionSupportInfo->LBProvisioningData.CommandStatus = STATUS_UNSUCCESSFUL; 2232 fdoExtension->FunctionSupportInfo->BlockLimitsData.CommandStatus = STATUS_UNSUCCESSFUL; 2233 fdoExtension->FunctionSupportInfo->BlockDeviceRODLimitsData.CommandStatus = STATUS_UNSUCCESSFUL; 2234 } 2235 2236 // Get registry setting of failing the IOCTL for AccessAlignment Property. 2237 ClassGetDeviceParameter(fdoExtension, 2238 CLASSP_REG_SUBKEY_NAME, 2239 CLASSP_REG_ACCESS_ALIGNMENT_NOT_SUPPORTED, 2240 &accessAlignmentNotSupported); 2241 2242 if (accessAlignmentNotSupported > 0) { 2243 fdoExtension->FunctionSupportInfo->RegAccessAlignmentQueryNotSupported = TRUE; 2244 } 2245 2246 #if (NTDDI_VERSION >= NTDDI_WINBLUE) 2247 2248 2249 // 2250 // See if the user has specified legacy error handling. 2251 // 2252 ClassGetDeviceParameter(fdoExtension, 2253 CLASSP_REG_SUBKEY_NAME, 2254 CLASSP_REG_LEGACY_ERROR_HANDLING, 2255 &legacyErrorHandling); 2256 2257 if (legacyErrorHandling) { 2258 // 2259 // Legacy error handling means that the maximum number of 2260 // retries allowd for an IO request is 8 instead of 4. 2261 // 2262 fdoExtension->PrivateFdoData->MaxNumberOfIoRetries = LEGACY_NUM_IO_RETRIES; 2263 fdoExtension->PrivateFdoData->LegacyErrorHandling = TRUE; 2264 } 2265 #else 2266 UNREFERENCED_PARAMETER(legacyErrorHandling); 2267 #endif 2268 2269 2270 // 2271 // Get the copy offload max target duration value. 2272 // This function will set the default value if one hasn't been 2273 // specified in the registry. 2274 // 2275 ClasspGetCopyOffloadMaxDuration(DeviceObject, 2276 REG_DISK_CLASS_CONTROL, 2277 &(fdoExtension->PrivateFdoData->CopyOffloadMaxTargetDuration)); 2278 2279 } 2280 2281 } 2282 } 2283 2284 if (!NT_SUCCESS(status)){ 2285 2286 // 2287 // Just bail out - the remove that comes down will clean up the 2288 // initialized scraps. 2289 // 2290 2291 return status; 2292 } else { 2293 commonExtension->IsInitialized = TRUE; 2294 } 2295 2296 // 2297 // If device requests autorun functionality or a once a second callback 2298 // then enable the once per second timer. Exception is if media change 2299 // detection is desired but device supports async notification. 2300 // 2301 // NOTE: This assumes that ClassInitializeMediaChangeDetection is always 2302 // called in the context of the ClassInitDevice callback. If called 2303 // after then this check will have already been made and the 2304 // once a second timer will not have been enabled. 2305 // 2306 if ((isFdo) && 2307 ((initData->ClassTick != NULL) || 2308 ((fdoExtension->MediaChangeDetectionInfo != NULL) && 2309 (fdoExtension->FunctionSupportInfo != NULL) && 2310 (fdoExtension->FunctionSupportInfo->AsynchronousNotificationSupported == FALSE)) || 2311 ((fdoExtension->FailurePredictionInfo != NULL) && 2312 (fdoExtension->FailurePredictionInfo->Method != FailurePredictionNone)))) 2313 { 2314 ClasspEnableTimer(fdoExtension); 2315 2316 // 2317 // In addition, we may change our polling behavior when the screen is 2318 // off so register for screen state notification if we haven't already 2319 // done so. 2320 // 2321 if (ScreenStateNotificationHandle == NULL) { 2322 PoRegisterPowerSettingCallback(DeviceObject, 2323 &GUID_CONSOLE_DISPLAY_STATE, 2324 &ClasspPowerSettingCallback, 2325 NULL, 2326 &ScreenStateNotificationHandle); 2327 } 2328 } 2329 2330 // 2331 // NOTE: the timer looks at commonExtension->CurrentState now 2332 // to prevent Media Change Notification code from running 2333 // until the device is started, but allows the device 2334 // specific tick handler to run. therefore it is imperative 2335 // that commonExtension->CurrentState not be updated until 2336 // the device specific startdevice handler has finished. 2337 // 2338 2339 status = devInfo->ClassStartDevice(DeviceObject); 2340 2341 if (NT_SUCCESS(status)){ 2342 commonExtension->CurrentState = IRP_MN_START_DEVICE; 2343 2344 if((isFdo) && (initData->ClassEnumerateDevice != NULL)) { 2345 isMountedDevice = FALSE; 2346 } 2347 2348 if (DeviceObject->DeviceType != FILE_DEVICE_CD_ROM) { 2349 2350 isMountedDevice = FALSE; 2351 } 2352 2353 // 2354 // Register for mounted device interface if this is a 2355 // sfloppy device. 2356 // 2357 if ((DeviceObject->DeviceType == FILE_DEVICE_DISK) && 2358 (TEST_FLAG(DeviceObject->Characteristics, FILE_FLOPPY_DISKETTE))) { 2359 2360 isMountedDevice = TRUE; 2361 } 2362 2363 if(isMountedDevice) { 2364 ClasspRegisterMountedDeviceInterface(DeviceObject); 2365 } 2366 2367 if(commonExtension->IsFdo) { 2368 IoWMIRegistrationControl(DeviceObject, WMIREG_ACTION_REGISTER); 2369 2370 // 2371 // Tell Storport (Usbstor or SD) to enable idle power management for this 2372 // device, assuming the user hasn't turned it off in the registry. 2373 // 2374 if (fdoExtension->FunctionSupportInfo != NULL && 2375 fdoExtension->FunctionSupportInfo->IdlePower.IdlePowerEnabled == FALSE && 2376 fdoExtension->MiniportDescriptor != NULL && 2377 (fdoExtension->MiniportDescriptor->Portdriver == StoragePortCodeSetStorport || 2378 fdoExtension->MiniportDescriptor->Portdriver == StoragePortCodeSetSDport || 2379 fdoExtension->MiniportDescriptor->Portdriver == StoragePortCodeSetUSBport)) { 2380 ULONG disableIdlePower= 0; 2381 ClassGetDeviceParameter(fdoExtension, 2382 CLASSP_REG_SUBKEY_NAME, 2383 CLASSP_REG_DISBALE_IDLE_POWER_NAME, 2384 &disableIdlePower); 2385 2386 if (!disableIdlePower) { 2387 ClasspEnableIdlePower(DeviceObject); 2388 } 2389 } 2390 } 2391 } 2392 else { 2393 ClasspDisableTimer(fdoExtension); 2394 } 2395 2396 2397 return status; 2398 } 2399 2400 2401 /*++//////////////////////////////////////////////////////////////////////////// 2402 2403 ClassReadWrite() 2404 2405 Routine Description: 2406 2407 This is the system entry point for read and write requests. The 2408 device-specific handler is invoked to perform any validation necessary. 2409 2410 If the device object is a PDO (partition object) then the request will 2411 simply be adjusted for Partition0 and issued to the lower device driver. 2412 2413 IF the device object is an FDO (paritition 0 object), the number of bytes 2414 in the request are checked against the maximum byte counts that the adapter 2415 supports and requests are broken up into 2416 smaller sizes if necessary. 2417 2418 Arguments: 2419 2420 DeviceObject - a pointer to the device object for this request 2421 2422 Irp - IO request 2423 2424 Return Value: 2425 2426 NT Status 2427 2428 --*/ 2429 NTSTATUS 2430 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 2431 ClassReadWrite(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) 2432 { 2433 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 2434 PDEVICE_OBJECT lowerDeviceObject = commonExtension->LowerDeviceObject; 2435 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp); 2436 ULONG transferByteCount = currentIrpStack->Parameters.Read.Length; 2437 ULONG isRemoved; 2438 NTSTATUS status; 2439 2440 /* 2441 * Grab the remove lock. If we can't acquire it, bail out. 2442 */ 2443 isRemoved = ClassAcquireRemoveLock(DeviceObject, Irp); 2444 if (isRemoved) { 2445 Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST; 2446 Irp->IoStatus.Information = 0; 2447 ClassReleaseRemoveLock(DeviceObject, Irp); 2448 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 2449 status = STATUS_DEVICE_DOES_NOT_EXIST; 2450 } 2451 else if (TEST_FLAG(DeviceObject->Flags, DO_VERIFY_VOLUME) && 2452 (currentIrpStack->MinorFunction != CLASSP_VOLUME_VERIFY_CHECKED) && 2453 !TEST_FLAG(currentIrpStack->Flags, SL_OVERRIDE_VERIFY_VOLUME)){ 2454 2455 /* 2456 * DO_VERIFY_VOLUME is set for the device object, 2457 * but this request is not itself a verify request. 2458 * So fail this request. 2459 */ 2460 if (Irp->Tail.Overlay.Thread != NULL) { 2461 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject); 2462 } 2463 Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED; 2464 Irp->IoStatus.Information = 0; 2465 ClassReleaseRemoveLock(DeviceObject, Irp); 2466 ClassCompleteRequest(DeviceObject, Irp, 0); 2467 status = STATUS_VERIFY_REQUIRED; 2468 } 2469 else { 2470 2471 /* 2472 * Since we've bypassed the verify-required tests we don't need to repeat 2473 * them with this IRP - in particular we don't want to worry about 2474 * hitting them at the partition 0 level if the request has come through 2475 * a non-zero partition. 2476 */ 2477 currentIrpStack->MinorFunction = CLASSP_VOLUME_VERIFY_CHECKED; 2478 2479 /* 2480 * Call the miniport driver's pre-pass filter to check if we 2481 * should continue with this transfer. 2482 */ 2483 NT_ASSERT(commonExtension->DevInfo->ClassReadWriteVerification); 2484 status = commonExtension->DevInfo->ClassReadWriteVerification(DeviceObject, Irp); 2485 // Code Analysis cannot analyze the code paths specific to clients. 2486 _Analysis_assume_(status != STATUS_PENDING); 2487 if (!NT_SUCCESS(status)){ 2488 NT_ASSERT(Irp->IoStatus.Status == status); 2489 Irp->IoStatus.Information = 0; 2490 ClassReleaseRemoveLock(DeviceObject, Irp); 2491 ClassCompleteRequest (DeviceObject, Irp, IO_NO_INCREMENT); 2492 } 2493 else if (status == STATUS_PENDING){ 2494 /* 2495 * ClassReadWriteVerification queued this request. 2496 * So don't touch the irp anymore. 2497 */ 2498 } 2499 else { 2500 2501 if (transferByteCount == 0) { 2502 /* 2503 * Several parts of the code turn 0 into 0xffffffff, 2504 * so don't process a zero-length request any further. 2505 */ 2506 Irp->IoStatus.Status = STATUS_SUCCESS; 2507 Irp->IoStatus.Information = 0; 2508 ClassReleaseRemoveLock(DeviceObject, Irp); 2509 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 2510 status = STATUS_SUCCESS; 2511 } 2512 else { 2513 /* 2514 * If the driver has its own StartIo routine, call it. 2515 */ 2516 if (commonExtension->DriverExtension->InitData.ClassStartIo) { 2517 IoMarkIrpPending(Irp); 2518 IoStartPacket(DeviceObject, Irp, NULL, NULL); 2519 status = STATUS_PENDING; 2520 } 2521 else { 2522 /* 2523 * The driver does not have its own StartIo routine. 2524 * So process this request ourselves. 2525 */ 2526 2527 /* 2528 * Add partition byte offset to make starting byte relative to 2529 * beginning of disk. 2530 */ 2531 currentIrpStack->Parameters.Read.ByteOffset.QuadPart += 2532 commonExtension->StartingOffset.QuadPart; 2533 2534 if (commonExtension->IsFdo){ 2535 2536 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; 2537 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData; 2538 2539 /* 2540 * Add in any skew for the disk manager software. 2541 */ 2542 currentIrpStack->Parameters.Read.ByteOffset.QuadPart += 2543 commonExtension->PartitionZeroExtension->DMByteSkew; 2544 2545 // 2546 // In case DEV_USE_16BYTE_CDB flag is not set, R/W request will be translated into READ/WRITE 10 SCSI command. 2547 // These SCSI commands have 4 bytes in "Starting LBA" field. 2548 // Requests cannot be represented in these SCSI commands should be failed. 2549 // 2550 if (!TEST_FLAG(fdoExtension->DeviceFlags, DEV_USE_16BYTE_CDB)) { 2551 LARGE_INTEGER startingLba; 2552 2553 startingLba.QuadPart = currentIrpStack->Parameters.Read.ByteOffset.QuadPart >> fdoExtension->SectorShift; 2554 2555 if (startingLba.QuadPart > MAXULONG) { 2556 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; 2557 Irp->IoStatus.Information = 0; 2558 ClassReleaseRemoveLock(DeviceObject, Irp); 2559 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 2560 status = STATUS_INVALID_PARAMETER; 2561 goto Exit; 2562 } 2563 } 2564 2565 #if DBG 2566 // 2567 // Record the caller if: 2568 // 1. the disk is currently off 2569 // 2. the operation is a read, (likely resulting in disk spinnage) 2570 // 3. the operation is marked WT (likely resulting in disk spinnage) 2571 // 2572 if((fdoExtension->DevicePowerState == PowerDeviceD3) && // disk is off 2573 ((currentIrpStack->MajorFunction == IRP_MJ_READ) || // It's a read. 2574 (TEST_FLAG(currentIrpStack->Flags, SL_WRITE_THROUGH))) ) { // they *really* want it to go to disk. 2575 2576 SnapDiskStartup(); 2577 } 2578 #endif 2579 2580 /* 2581 * Perform the actual transfer(s) on the hardware 2582 * to service this request. 2583 */ 2584 if (ClasspIsIdleRequestSupported(fdoData, Irp)) { 2585 ClasspMarkIrpAsIdle(Irp, TRUE); 2586 status = ClasspEnqueueIdleRequest(DeviceObject, Irp); 2587 } else { 2588 UCHAR uniqueAddr = 0; 2589 2590 // 2591 // Since we're touching fdoData after servicing the transfer packet, this opens us up to 2592 // a potential window, where the device may be removed between the time that 2593 // ServiceTransferPacket completes and we've had a chance to access fdoData. In order 2594 // to guard against this, we acquire the removelock an additional time here. This 2595 // acquire is guaranteed to succeed otherwise we wouldn't be here (because of the 2596 // outer acquire). 2597 // The sequence of events we're guarding against with this remLock acquire is: 2598 // 1. This UL IRP acquired the lock. 2599 // 2. Device gets surprised removed, then gets IRP_MN_REMOVE_DEVICE; ClassRemoveDevice 2600 // waits for the above RemoveLock. 2601 // 3. ServiceTransferRequest breaks the UL IRP into DL IRPs. 2602 // 4. DL IRPs complete with STATUS_NO_SUCH_DEVICE and TransferPktComplete completes the UL 2603 // IRP with STATUS_NO_SUCH_DEVICE; releases the RemoveLock. 2604 // 5. ClassRemoveDevice is now unblocked, continues running and frees resources (including 2605 // fdoData). 2606 // 6. Finally ClassReadWrite gets to run again and accesses a freed fdoData when trying to 2607 // check/update idle-related fields. 2608 // 2609 ClassAcquireRemoveLock(DeviceObject, (PVOID)&uniqueAddr); 2610 2611 ClasspMarkIrpAsIdle(Irp, FALSE); 2612 status = ServiceTransferRequest(DeviceObject, Irp, FALSE); 2613 if (fdoData->IdlePrioritySupported == TRUE) { 2614 fdoData->LastNonIdleIoTime = ClasspGetCurrentTime(); 2615 } 2616 2617 ClassReleaseRemoveLock(DeviceObject, (PVOID)&uniqueAddr); 2618 } 2619 } 2620 else { 2621 /* 2622 * This is a child PDO enumerated for our FDO by e.g. disk.sys 2623 * and owned by e.g. partmgr. Send it down to the next device 2624 * and the same irp will come back to us for the FDO. 2625 */ 2626 IoCopyCurrentIrpStackLocationToNext(Irp); 2627 ClassReleaseRemoveLock(DeviceObject, Irp); 2628 status = IoCallDriver(lowerDeviceObject, Irp); 2629 } 2630 } 2631 } 2632 } 2633 } 2634 2635 Exit: 2636 return status; 2637 } 2638 2639 2640 VOID InterpretCapacityData(PDEVICE_OBJECT Fdo, PREAD_CAPACITY_DATA_EX ReadCapacityData) 2641 { 2642 PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension; 2643 ULONG cylinderSize; 2644 ULONG bytesPerSector; 2645 LARGE_INTEGER lastSector; 2646 LARGE_INTEGER largeInt; 2647 2648 bytesPerSector = ClasspCalculateLogicalSectorSize(Fdo, ReadCapacityData->BytesPerBlock); 2649 2650 fdoExt->DiskGeometry.BytesPerSector = bytesPerSector; 2651 WHICH_BIT(fdoExt->DiskGeometry.BytesPerSector, fdoExt->SectorShift); 2652 2653 /* 2654 * LogicalBlockAddress is the last sector of the logical drive, in big-endian. 2655 * It tells us the size of the drive (#sectors is lastSector+1). 2656 */ 2657 2658 largeInt = ReadCapacityData->LogicalBlockAddress; 2659 REVERSE_BYTES_QUAD(&lastSector, &largeInt); 2660 2661 if (fdoExt->DMActive){ 2662 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, "ClassReadDriveCapacity: reducing number of sectors by %d\n", fdoExt->DMSkew)); 2663 lastSector.QuadPart -= fdoExt->DMSkew; 2664 } 2665 2666 /* 2667 * Check to see if we have a geometry we should be using already. 2668 * If not, we set part of the disk geometry to garbage values that will be filled in by the caller (e.g. disk.sys). 2669 * 2670 * So the first call to ClassReadDriveCapacity always sets a meaningless geometry. 2671 * TracksPerCylinder and SectorsPerTrack are kind of meaningless anyway wrt I/O, 2672 * because I/O is always targeted to a logical sector number. 2673 * All that really matters is BytesPerSector and the number of sectors. 2674 */ 2675 cylinderSize = fdoExt->DiskGeometry.TracksPerCylinder * fdoExt->DiskGeometry.SectorsPerTrack; 2676 if (cylinderSize == 0){ 2677 fdoExt->DiskGeometry.TracksPerCylinder = 0xff; 2678 fdoExt->DiskGeometry.SectorsPerTrack = 0x3f; 2679 cylinderSize = fdoExt->DiskGeometry.TracksPerCylinder * fdoExt->DiskGeometry.SectorsPerTrack; 2680 } 2681 2682 /* 2683 * Calculate number of cylinders. 2684 * If there are zero cylinders, then the device lied AND it's 2685 * smaller than 0xff*0x3f (about 16k sectors, usually 8 meg) 2686 * this can fit into a single LONGLONG, so create another usable 2687 * geometry, even if it's unusual looking. 2688 * This allows small, non-standard devices, such as Sony's Memory Stick, to show up as having a partition. 2689 */ 2690 fdoExt->DiskGeometry.Cylinders.QuadPart = (LONGLONG)((lastSector.QuadPart + 1)/cylinderSize); 2691 if (fdoExt->DiskGeometry.Cylinders.QuadPart == (LONGLONG)0) { 2692 fdoExt->DiskGeometry.SectorsPerTrack = 1; 2693 fdoExt->DiskGeometry.TracksPerCylinder = 1; 2694 fdoExt->DiskGeometry.Cylinders.QuadPart = lastSector.QuadPart + 1; 2695 } 2696 2697 /* 2698 * Calculate media capacity in bytes. 2699 * For this purpose we treat the entire LUN as is if it is one partition. Disk will deal with actual partitioning. 2700 */ 2701 fdoExt->CommonExtension.PartitionLength.QuadPart = 2702 ((LONGLONG)(lastSector.QuadPart + 1)) << fdoExt->SectorShift; 2703 2704 /* 2705 * Is this removable or fixed media 2706 */ 2707 if (TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)){ 2708 fdoExt->DiskGeometry.MediaType = RemovableMedia; 2709 } 2710 else { 2711 fdoExt->DiskGeometry.MediaType = FixedMedia; 2712 } 2713 2714 } 2715 2716 /*++//////////////////////////////////////////////////////////////////////////// 2717 2718 ClassReadDriveCapacity() 2719 2720 Routine Description: 2721 2722 This routine sends a READ CAPACITY to the requested device, updates 2723 the geometry information in the device object and returns 2724 when it is complete. This routine is synchronous. 2725 2726 This routine must be called with the remove lock held or some other 2727 assurance that the Fdo will not be removed while processing. 2728 2729 Arguments: 2730 2731 DeviceObject - Supplies a pointer to the device object that represents 2732 the device whose capacity is to be read. 2733 2734 Return Value: 2735 2736 Status is returned. 2737 2738 --*/ 2739 _Must_inspect_result_ 2740 NTSTATUS 2741 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 2742 ClassReadDriveCapacity(_In_ PDEVICE_OBJECT Fdo) 2743 { 2744 PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension; 2745 PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension; 2746 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData; 2747 READ_CAPACITY_DATA_EX PTRALIGN readCapacityData = {0}; 2748 PTRANSFER_PACKET pkt; 2749 NTSTATUS status; 2750 PMDL driveCapMdl = NULL; 2751 KEVENT event; 2752 IRP pseudoIrp = {0}; 2753 ULONG readCapacityDataSize; 2754 BOOLEAN use16ByteCdb; 2755 BOOLEAN match = TRUE; 2756 2757 use16ByteCdb = TEST_FLAG(fdoExt->DeviceFlags, DEV_USE_16BYTE_CDB); 2758 2759 RetryRequest: 2760 2761 if (use16ByteCdb) { 2762 readCapacityDataSize = sizeof(READ_CAPACITY_DATA_EX); 2763 } else { 2764 readCapacityDataSize = sizeof(READ_CAPACITY_DATA); 2765 } 2766 2767 if (driveCapMdl != NULL) { 2768 FreeDeviceInputMdl(driveCapMdl); 2769 driveCapMdl = NULL; 2770 } 2771 2772 // 2773 // Allocate the MDL based on the Read Capacity command. 2774 // 2775 driveCapMdl = BuildDeviceInputMdl(&readCapacityData, readCapacityDataSize); 2776 if (driveCapMdl == NULL) { 2777 status = STATUS_INSUFFICIENT_RESOURCES; 2778 goto SafeExit; 2779 } 2780 2781 pkt = DequeueFreeTransferPacket(Fdo, TRUE); 2782 if (pkt == NULL) { 2783 status = STATUS_INSUFFICIENT_RESOURCES; 2784 goto SafeExit; 2785 } 2786 2787 // 2788 // Our engine needs an "original irp" to write the status back to 2789 // and to count down packets (one in this case). 2790 // Just use a pretend irp for this. 2791 // 2792 2793 pseudoIrp.Tail.Overlay.DriverContext[0] = LongToPtr(1); 2794 pseudoIrp.IoStatus.Status = STATUS_SUCCESS; 2795 pseudoIrp.IoStatus.Information = 0; 2796 pseudoIrp.MdlAddress = driveCapMdl; 2797 2798 // 2799 // Set this up as a SYNCHRONOUS transfer, submit it, 2800 // and wait for the packet to complete. The result 2801 // status will be written to the original irp. 2802 // 2803 2804 KeInitializeEvent(&event, SynchronizationEvent, FALSE); 2805 SetupDriveCapacityTransferPacket(pkt, 2806 &readCapacityData, 2807 readCapacityDataSize, 2808 &event, 2809 &pseudoIrp, 2810 use16ByteCdb); 2811 SubmitTransferPacket(pkt); 2812 (VOID)KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); 2813 2814 status = pseudoIrp.IoStatus.Status; 2815 2816 // 2817 // If we got an UNDERRUN, retry exactly once. 2818 // (The transfer_packet engine didn't retry because the result 2819 // status was success). 2820 // 2821 2822 if (NT_SUCCESS(status) && 2823 (pseudoIrp.IoStatus.Information < readCapacityDataSize)) { 2824 2825 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT, "ClassReadDriveCapacity: read len (%xh) < %xh, retrying ...", 2826 (ULONG)pseudoIrp.IoStatus.Information, readCapacityDataSize)); 2827 2828 pkt = DequeueFreeTransferPacket(Fdo, TRUE); 2829 if (pkt) { 2830 pseudoIrp.Tail.Overlay.DriverContext[0] = LongToPtr(1); 2831 pseudoIrp.IoStatus.Status = STATUS_SUCCESS; 2832 pseudoIrp.IoStatus.Information = 0; 2833 KeInitializeEvent(&event, SynchronizationEvent, FALSE); 2834 SetupDriveCapacityTransferPacket(pkt, 2835 &readCapacityData, 2836 readCapacityDataSize, 2837 &event, 2838 &pseudoIrp, 2839 use16ByteCdb); 2840 SubmitTransferPacket(pkt); 2841 (VOID)KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); 2842 status = pseudoIrp.IoStatus.Status; 2843 if (pseudoIrp.IoStatus.Information < readCapacityDataSize){ 2844 status = STATUS_DEVICE_BUSY; 2845 } 2846 } else { 2847 status = STATUS_INSUFFICIENT_RESOURCES; 2848 } 2849 } 2850 2851 if (NT_SUCCESS(status)) { 2852 // 2853 // The request succeeded. Check for 8 byte LBA support. 2854 // 2855 2856 if (use16ByteCdb == FALSE) { 2857 2858 PREAD_CAPACITY_DATA readCapacity; 2859 2860 // 2861 // Check whether the device supports 8 byte LBA. If the device supports 2862 // it then retry the request using 16 byte CDB. 2863 // 2864 2865 readCapacity = (PREAD_CAPACITY_DATA) &readCapacityData; 2866 2867 if (readCapacity->LogicalBlockAddress == 0xFFFFFFFF) { 2868 // 2869 // Device returned max size for last LBA. Need to send 2870 // 16 byte request to get the size. 2871 // 2872 use16ByteCdb = TRUE; 2873 goto RetryRequest; 2874 2875 } else { 2876 // 2877 // Convert the 4 byte LBA (READ_CAPACITY_DATA) to 8 byte LBA (READ_CAPACITY_DATA_EX) 2878 // format for ease of use. This is the only format stored in the device extension. 2879 // 2880 2881 RtlMoveMemory((PUCHAR)(&readCapacityData) + sizeof(ULONG), readCapacity, sizeof(READ_CAPACITY_DATA)); 2882 RtlZeroMemory((PUCHAR)(&readCapacityData), sizeof(ULONG)); 2883 2884 } 2885 } else { 2886 // 2887 // Device completed 16 byte command successfully, it supports 8-byte LBA. 2888 // 2889 2890 SET_FLAG(fdoExt->DeviceFlags, DEV_USE_16BYTE_CDB); 2891 } 2892 2893 // 2894 // Read out and store the drive information. 2895 // 2896 2897 InterpretCapacityData(Fdo, &readCapacityData); 2898 2899 // 2900 // Before caching the new drive capacity, compare it with the 2901 // cached capacity for any change. 2902 // 2903 2904 if (fdoData->IsCachedDriveCapDataValid == TRUE) { 2905 2906 match = (BOOLEAN) RtlEqualMemory(&fdoData->LastKnownDriveCapacityData, 2907 &readCapacityData, sizeof(READ_CAPACITY_DATA_EX)); 2908 } 2909 2910 // 2911 // Store the readCapacityData in private FDO data. 2912 // This is so that runtime memory failures don't cause disk.sys to put 2913 // the paging disk in an error state. Also this is used in 2914 // IOCTL_STORAGE_READ_CAPACITY. 2915 // 2916 fdoData->LastKnownDriveCapacityData = readCapacityData; 2917 fdoData->IsCachedDriveCapDataValid = TRUE; 2918 2919 if (match == FALSE) { 2920 if (commonExtension->CurrentState != IRP_MN_START_DEVICE) 2921 { 2922 // 2923 // This can happen if a disk reports Parameters Changed / Capacity Data Changed sense data. 2924 // NT_ASSERT(!"Drive capacity has changed while the device wasn't started!"); 2925 // 2926 } else { 2927 // 2928 // state of (commonExtension->CurrentState == IRP_MN_START_DEVICE) indicates that the device has been started. 2929 // UpdateDiskPropertiesWorkItemActive is used as a flag to ensure we only have one work item updating the disk 2930 // properties at a time. 2931 // 2932 if (InterlockedCompareExchange((volatile LONG *)&fdoData->UpdateDiskPropertiesWorkItemActive, 1, 0) == 0) 2933 { 2934 PIO_WORKITEM workItem; 2935 2936 workItem = IoAllocateWorkItem(Fdo); 2937 2938 if (workItem) { 2939 // 2940 // The disk capacity has changed, send notification to the disk driver. 2941 // Start a work item to notify the disk class driver asynchronously. 2942 // 2943 IoQueueWorkItem(workItem, ClasspUpdateDiskProperties, DelayedWorkQueue, workItem); 2944 } else { 2945 InterlockedExchange((volatile LONG *)&fdoData->UpdateDiskPropertiesWorkItemActive, 0); 2946 } 2947 } 2948 } 2949 } 2950 2951 } else { 2952 // 2953 // The request failed. 2954 // 2955 2956 // 2957 // ISSUE - 2000/02/04 - henrygab - non-512-byte sector sizes and failed geometry update 2958 // what happens when the disk's sector size is bigger than 2959 // 512 bytes and we hit this code path? this is untested. 2960 // 2961 // If the read capacity fails, set the geometry to reasonable parameter 2962 // so things don't fail at unexpected places. Zero the geometry 2963 // except for the bytes per sector and sector shift. 2964 // 2965 2966 // 2967 // This request can sometimes fail legitimately 2968 // (e.g. when a SCSI device is attached but turned off) 2969 // so this is not necessarily a device/driver bug. 2970 // 2971 2972 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, "ClassReadDriveCapacity on Fdo %p failed with status %ul.", Fdo, status)); 2973 2974 // 2975 // Write in a default disk geometry which we HOPE is right (??). 2976 // 2977 2978 RtlZeroMemory(&fdoExt->DiskGeometry, sizeof(DISK_GEOMETRY)); 2979 fdoExt->DiskGeometry.BytesPerSector = 512; 2980 fdoExt->SectorShift = 9; 2981 fdoExt->CommonExtension.PartitionLength.QuadPart = (LONGLONG) 0; 2982 2983 // 2984 // Is this removable or fixed media 2985 // 2986 2987 if (TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)){ 2988 fdoExt->DiskGeometry.MediaType = RemovableMedia; 2989 } else { 2990 fdoExt->DiskGeometry.MediaType = FixedMedia; 2991 } 2992 } 2993 2994 SafeExit: 2995 2996 2997 // 2998 // In case DEV_USE_16BYTE_CDB flag is not set, classpnp translates R/W request into READ/WRITE 10 SCSI command. 2999 // These SCSI commands have 2 bytes in "Transfer Blocks" field. 3000 // Make sure this max length (0xFFFF * sector size) is respected during request split. 3001 // 3002 if (!TEST_FLAG(fdoExt->DeviceFlags, DEV_USE_16BYTE_CDB)) { 3003 ULONG cdb10MaxBlocks = ((ULONG)USHORT_MAX) << fdoExt->SectorShift; 3004 3005 fdoData->HwMaxXferLen = min(cdb10MaxBlocks, fdoData->HwMaxXferLen); 3006 } 3007 3008 if (driveCapMdl != NULL) { 3009 FreeDeviceInputMdl(driveCapMdl); 3010 } 3011 3012 // 3013 // If the request failed for some reason then invalidate the cached 3014 // capacity data for removable devices. So that we won't return 3015 // wrong capacity in IOCTL_STORAGE_READ_CAPACITY 3016 // 3017 3018 if (!NT_SUCCESS(status) && (fdoExt->DiskGeometry.MediaType == RemovableMedia)) { 3019 fdoData->IsCachedDriveCapDataValid = FALSE; 3020 } 3021 3022 // 3023 // Don't let memory failures (either here or in the port driver) in the ReadDriveCapacity call 3024 // put the paging disk in an error state such that paging fails. 3025 // Return the last known drive capacity (which may possibly be slightly out of date, even on 3026 // fixed media, e.g. for storage cabinets that can grow a logical disk). 3027 // 3028 if ((status == STATUS_INSUFFICIENT_RESOURCES) && 3029 (fdoData->IsCachedDriveCapDataValid) && 3030 (fdoExt->DiskGeometry.MediaType == FixedMedia)) { 3031 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, "ClassReadDriveCapacity: defaulting to cached DriveCapacity data")); 3032 InterpretCapacityData(Fdo, &fdoData->LastKnownDriveCapacityData); 3033 status = STATUS_SUCCESS; 3034 } 3035 3036 return status; 3037 } 3038 3039 3040 /*++//////////////////////////////////////////////////////////////////////////// 3041 3042 ClassSendStartUnit() 3043 3044 Routine Description: 3045 3046 Send command to SCSI unit to start or power up. 3047 Because this command is issued asynchronounsly, that is, without 3048 waiting on it to complete, the IMMEDIATE flag is not set. This 3049 means that the CDB will not return until the drive has powered up. 3050 This should keep subsequent requests from being submitted to the 3051 device before it has completely spun up. 3052 3053 This routine is called from the InterpretSense routine, when a 3054 request sense returns data indicating that a drive must be 3055 powered up. 3056 3057 This routine may also be called from a class driver's error handler, 3058 or anytime a non-critical start device should be sent to the device. 3059 3060 Arguments: 3061 3062 Fdo - The functional device object for the stopped device. 3063 3064 Return Value: 3065 3066 None. 3067 3068 --*/ 3069 VOID 3070 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 3071 ClassSendStartUnit( 3072 _In_ PDEVICE_OBJECT Fdo 3073 ) 3074 { 3075 PIO_STACK_LOCATION irpStack; 3076 PIRP irp; 3077 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; 3078 PSCSI_REQUEST_BLOCK srb; 3079 PCOMPLETION_CONTEXT context; 3080 PCDB cdb; 3081 NTSTATUS status; 3082 PSTORAGE_REQUEST_BLOCK srbEx; 3083 3084 // 3085 // Allocate Srb from nonpaged pool. 3086 // 3087 3088 context = ExAllocatePoolWithTag(NonPagedPoolNx, 3089 sizeof(COMPLETION_CONTEXT), 3090 '6CcS'); 3091 3092 if (context == NULL) { 3093 3094 // 3095 // ISSUE-2000/02/03-peterwie 3096 // This code path was inheritted from the NT 4.0 class2.sys driver. 3097 // It needs to be changed to survive low-memory conditions. 3098 // 3099 3100 KeBugCheck(SCSI_DISK_DRIVER_INTERNAL); 3101 } 3102 3103 // 3104 // Save the device object in the context for use by the completion 3105 // routine. 3106 // 3107 3108 context->DeviceObject = Fdo; 3109 3110 srb = &context->Srb.Srb; 3111 if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { 3112 srbEx = &context->Srb.SrbEx; 3113 status = InitializeStorageRequestBlock(srbEx, 3114 STORAGE_ADDRESS_TYPE_BTL8, 3115 sizeof(context->Srb.SrbExBuffer), 3116 1, 3117 SrbExDataTypeScsiCdb16); 3118 if (!NT_SUCCESS(status)) { 3119 FREE_POOL(context); 3120 NT_ASSERT(FALSE); 3121 return; 3122 } 3123 3124 srbEx->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI; 3125 3126 } else { 3127 3128 // 3129 // Zero out srb. 3130 // 3131 3132 RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK)); 3133 3134 // 3135 // Write length to SRB. 3136 // 3137 3138 srb->Length = sizeof(SCSI_REQUEST_BLOCK); 3139 3140 srb->Function = SRB_FUNCTION_EXECUTE_SCSI; 3141 } 3142 3143 // 3144 // Set timeout value large enough for drive to spin up. 3145 // 3146 3147 SrbSetTimeOutValue(srb, START_UNIT_TIMEOUT); 3148 3149 // 3150 // Set the transfer length. 3151 // 3152 3153 SrbAssignSrbFlags(srb, 3154 (SRB_FLAGS_NO_DATA_TRANSFER | 3155 SRB_FLAGS_DISABLE_AUTOSENSE | 3156 SRB_FLAGS_DISABLE_SYNCH_TRANSFER)); 3157 3158 // 3159 // Build the start unit CDB. 3160 // 3161 3162 SrbSetCdbLength(srb, 6); 3163 cdb = SrbGetCdb(srb); 3164 3165 cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT; 3166 cdb->START_STOP.Start = 1; 3167 cdb->START_STOP.Immediate = 0; 3168 cdb->START_STOP.LogicalUnitNumber = srb->Lun; 3169 3170 // 3171 // Build the asynchronous request to be sent to the port driver. 3172 // Since this routine is called from a DPC the IRP should always be 3173 // available. 3174 // 3175 3176 irp = IoAllocateIrp(Fdo->StackSize, FALSE); 3177 3178 if (irp == NULL) { 3179 3180 // 3181 // ISSUE-2000/02/03-peterwie 3182 // This code path was inheritted from the NT 4.0 class2.sys driver. 3183 // It needs to be changed to survive low-memory conditions. 3184 // 3185 3186 KeBugCheck(SCSI_DISK_DRIVER_INTERNAL); 3187 3188 } 3189 3190 ClassAcquireRemoveLock(Fdo, irp); 3191 3192 IoSetCompletionRoutine(irp, 3193 (PIO_COMPLETION_ROUTINE)ClassAsynchronousCompletion, 3194 context, 3195 TRUE, 3196 TRUE, 3197 TRUE); 3198 3199 irpStack = IoGetNextIrpStackLocation(irp); 3200 irpStack->MajorFunction = IRP_MJ_SCSI; 3201 SrbSetOriginalRequest(srb, irp); 3202 3203 // 3204 // Store the SRB address in next stack for port driver. 3205 // 3206 3207 irpStack->Parameters.Scsi.Srb = srb; 3208 3209 // 3210 // Call the port driver with the IRP. 3211 // 3212 3213 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp); 3214 3215 return; 3216 3217 } // end StartUnit() 3218 3219 /*++//////////////////////////////////////////////////////////////////////////// 3220 3221 ClassAsynchronousCompletion() ISSUE-2000/02/18-henrygab - why public?! 3222 3223 Routine Description: 3224 3225 This routine is called when an asynchronous I/O request 3226 which was issused by the class driver completes. Examples of such requests 3227 are release queue or START UNIT. This routine releases the queue if 3228 necessary. It then frees the context and the IRP. 3229 3230 Arguments: 3231 3232 DeviceObject - The device object for the logical unit; however since this 3233 is the top stack location the value is NULL. 3234 3235 Irp - Supplies a pointer to the Irp to be processed. 3236 3237 Context - Supplies the context to be used to process this request. 3238 3239 Return Value: 3240 3241 None. 3242 3243 --*/ 3244 NTSTATUS 3245 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 3246 ClassAsynchronousCompletion( 3247 PDEVICE_OBJECT DeviceObject, 3248 PIRP Irp, 3249 PVOID Context 3250 ) 3251 { 3252 PCOMPLETION_CONTEXT context = Context; 3253 PSCSI_REQUEST_BLOCK srb; 3254 ULONG srbFunction; 3255 ULONG srbFlags; 3256 3257 if (context == NULL) { 3258 return STATUS_INVALID_PARAMETER; 3259 } 3260 3261 if (DeviceObject == NULL) { 3262 3263 DeviceObject = context->DeviceObject; 3264 } 3265 3266 srb = &context->Srb.Srb; 3267 3268 if (srb->Function == SRB_FUNCTION_STORAGE_REQUEST_BLOCK) { 3269 srbFunction = ((PSTORAGE_REQUEST_BLOCK)srb)->SrbFunction; 3270 srbFlags = ((PSTORAGE_REQUEST_BLOCK)srb)->SrbFlags; 3271 } else { 3272 srbFunction = srb->Function; 3273 srbFlags = srb->SrbFlags; 3274 } 3275 3276 // 3277 // If this is an execute srb, then check the return status and make sure. 3278 // the queue is not frozen. 3279 // 3280 3281 if (srbFunction == SRB_FUNCTION_EXECUTE_SCSI) { 3282 3283 // 3284 // Check for a frozen queue. 3285 // 3286 3287 if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) { 3288 3289 // 3290 // Unfreeze the queue getting the device object from the context. 3291 // 3292 3293 ClassReleaseQueue(context->DeviceObject); 3294 } 3295 } 3296 3297 { // free port-allocated sense buffer if we can detect 3298 3299 if (((PCOMMON_DEVICE_EXTENSION)(DeviceObject->DeviceExtension))->IsFdo) { 3300 3301 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; 3302 if (PORT_ALLOCATED_SENSE(fdoExtension, srb)) { 3303 FREE_PORT_ALLOCATED_SENSE_BUFFER(fdoExtension, srb); 3304 } 3305 3306 } else { 3307 3308 NT_ASSERT(!TEST_FLAG(srbFlags, SRB_FLAGS_FREE_SENSE_BUFFER)); 3309 3310 } 3311 } 3312 3313 3314 // 3315 // Free the context and the Irp. 3316 // 3317 3318 if (Irp->MdlAddress != NULL) { 3319 MmUnlockPages(Irp->MdlAddress); 3320 IoFreeMdl(Irp->MdlAddress); 3321 3322 Irp->MdlAddress = NULL; 3323 } 3324 3325 ClassReleaseRemoveLock(DeviceObject, Irp); 3326 3327 FREE_POOL(context); 3328 3329 IoFreeIrp(Irp); 3330 3331 // 3332 // Indicate the I/O system should stop processing the Irp completion. 3333 // 3334 3335 return STATUS_MORE_PROCESSING_REQUIRED; 3336 3337 } // end ClassAsynchronousCompletion() 3338 3339 3340 NTSTATUS 3341 ServiceTransferRequest( 3342 PDEVICE_OBJECT Fdo, 3343 PIRP Irp, 3344 BOOLEAN PostToDpc 3345 ) 3346 3347 /*++ 3348 3349 Routine description: 3350 3351 This routine processes Io requests, splitting them if they 3352 are larger than what the hardware can handle at a time. If 3353 there isn't enough memory available, the request is placed 3354 in a queue, to be processed at a later time 3355 3356 If this is a high priority paging request, all regular Io 3357 are throttled to provide Mm with better thoroughput 3358 3359 Arguments: 3360 3361 Fdo - The functional device object processing the request 3362 Irp - The Io request to be processed 3363 PostToDpc - Flag that indicates that this IRP must be posted to a DPC 3364 3365 Return Value: 3366 3367 STATUS_SUCCESS if successful, an error code otherwise 3368 3369 --*/ 3370 3371 { 3372 PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension; 3373 PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension; 3374 PSTORAGE_ADAPTER_DESCRIPTOR adapterDesc = commonExtension->PartitionZeroExtension->AdapterDescriptor; 3375 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData; 3376 IO_PAGING_PRIORITY priority = (TEST_FLAG(Irp->Flags, IRP_PAGING_IO)) ? IoGetPagingIoPriority(Irp) : IoPagingPriorityInvalid; 3377 BOOLEAN deferClientIrp = FALSE; 3378 BOOLEAN driverUsesStartIO = (commonExtension->DriverExtension->InitData.ClassStartIo != NULL); 3379 KIRQL oldIrql; 3380 NTSTATUS status = STATUS_UNSUCCESSFUL; 3381 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp); 3382 3383 /* 3384 * Initialize IRP status for the master IRP to 3385 * - STATUS_FT_READ_FROM_COPY if it's a copy-specific read 3386 * - STATUS_SUCCESS otherwise. 3387 * 3388 * This is required. When Classpnp determines the status for the master IRP 3389 * when completing child IRPs, the call to IoSetMasterIrpStatus 3390 * will be functioning properly (See TransferPktComplete function) 3391 * 3392 * Note: 3393 * If the IRP is a copy-specific read, File System already initialized the IRP status 3394 * to be STATUS_FT_READ_FROM_COPY. However, this can be changed when the IRP arrives 3395 * at Classpnp. It's possible that other drivers in the stack may initialize the 3396 * IRP status field to other values before forwarding the IRP down the stack. 3397 * To be defensive, we initialize the IRP status to either STATUS_FT_READ_FROM_COPY 3398 * if it's a copy-specific read, or STATUS_SUCCESS otherwise. 3399 */ 3400 if (currentIrpStack->MajorFunction == IRP_MJ_READ && 3401 TEST_FLAG(currentIrpStack->Flags, SL_KEY_SPECIFIED) && 3402 IsKeyReadCopyNumber(currentIrpStack->Parameters.Read.Key)) { 3403 Irp->IoStatus.Status = STATUS_FT_READ_FROM_COPY; 3404 } else { 3405 Irp->IoStatus.Status = STATUS_SUCCESS; 3406 } 3407 3408 // 3409 // If this is a high priority request, hold off all other Io requests 3410 // 3411 3412 if (priority == IoPagingPriorityHigh) 3413 { 3414 KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql); 3415 3416 if (fdoData->NumHighPriorityPagingIo == 0) 3417 { 3418 // 3419 // Entering throttle mode 3420 // 3421 3422 KeQuerySystemTime(&fdoData->ThrottleStartTime); 3423 } 3424 3425 fdoData->NumHighPriorityPagingIo++; 3426 fdoData->MaxInterleavedNormalIo += ClassMaxInterleavePerCriticalIo; 3427 3428 KeReleaseSpinLock(&fdoData->SpinLock, oldIrql); 3429 } 3430 else 3431 { 3432 if (fdoData->NumHighPriorityPagingIo != 0) 3433 { 3434 // 3435 // This request wasn't flagged as critical and atleast one critical request 3436 // is currently outstanding. Queue this request until all of those are done 3437 // but only if the interleave threshold has been reached 3438 // 3439 3440 KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql); 3441 3442 if (fdoData->NumHighPriorityPagingIo != 0) 3443 { 3444 if (fdoData->MaxInterleavedNormalIo == 0) 3445 { 3446 deferClientIrp = TRUE; 3447 } 3448 else 3449 { 3450 fdoData->MaxInterleavedNormalIo--; 3451 } 3452 } 3453 3454 KeReleaseSpinLock(&fdoData->SpinLock, oldIrql); 3455 } 3456 } 3457 3458 if (!deferClientIrp) 3459 { 3460 PIO_STACK_LOCATION currentSp = IoGetCurrentIrpStackLocation(Irp); 3461 ULONG entireXferLen = currentSp->Parameters.Read.Length; 3462 PUCHAR bufPtr = MmGetMdlVirtualAddress(Irp->MdlAddress); 3463 LARGE_INTEGER targetLocation = currentSp->Parameters.Read.ByteOffset; 3464 PTRANSFER_PACKET pkt; 3465 SINGLE_LIST_ENTRY pktList; 3466 PSINGLE_LIST_ENTRY slistEntry; 3467 ULONG hwMaxXferLen; 3468 ULONG numPackets; 3469 ULONG i; 3470 3471 3472 /* 3473 * We precomputed fdoData->HwMaxXferLen using (MaximumPhysicalPages-1). 3474 * If the buffer is page-aligned, that's one less page crossing so we can add the page back in. 3475 * Note: adapters that return MaximumPhysicalPages=0x10 depend on this to 3476 * transfer aligned 64K requests in one piece. 3477 * Also note: make sure adding PAGE_SIZE back in doesn't wrap to zero. 3478 */ 3479 if (((ULONG_PTR)bufPtr & (PAGE_SIZE-1)) || (fdoData->HwMaxXferLen > 0xffffffff-PAGE_SIZE)){ 3480 hwMaxXferLen = fdoData->HwMaxXferLen; 3481 } 3482 else { 3483 NT_ASSERT((PAGE_SIZE%fdoExt->DiskGeometry.BytesPerSector) == 0); 3484 hwMaxXferLen = min(fdoData->HwMaxXferLen+PAGE_SIZE, adapterDesc->MaximumTransferLength); 3485 } 3486 3487 /* 3488 * Compute the number of hw xfers we'll have to do. 3489 * Calculate this without allowing for an overflow condition. 3490 */ 3491 NT_ASSERT(hwMaxXferLen >= PAGE_SIZE); 3492 numPackets = entireXferLen/hwMaxXferLen; 3493 if (entireXferLen % hwMaxXferLen){ 3494 numPackets++; 3495 } 3496 3497 /* 3498 * Use our 'simple' slist functions since we don't need interlocked. 3499 */ 3500 SimpleInitSlistHdr(&pktList); 3501 3502 if (driverUsesStartIO) { 3503 /* 3504 * special case: StartIO-based writing must stay serialized, so just 3505 * re-use one packet. 3506 */ 3507 pkt = DequeueFreeTransferPacket(Fdo, TRUE); 3508 if (pkt) { 3509 SimplePushSlist(&pktList, (PSINGLE_LIST_ENTRY)&pkt->SlistEntry); 3510 i = 1; 3511 } else { 3512 i = 0; 3513 } 3514 } else { 3515 /* 3516 * First get all the TRANSFER_PACKETs that we'll need at once. 3517 */ 3518 for (i = 0; i < numPackets; i++){ 3519 pkt = DequeueFreeTransferPacket(Fdo, TRUE); 3520 if (pkt){ 3521 SimplePushSlist(&pktList, (PSINGLE_LIST_ENTRY)&pkt->SlistEntry); 3522 } 3523 else { 3524 break; 3525 } 3526 } 3527 } 3528 3529 3530 if ((i == numPackets) && 3531 (!driverUsesStartIO)) { 3532 NTSTATUS pktStat; 3533 3534 /* 3535 * The IoStatus.Information field will be incremented to the 3536 * transfer length as the pieces complete. 3537 */ 3538 Irp->IoStatus.Information = 0; 3539 3540 /* 3541 * Store the number of transfer pieces inside the original IRP. 3542 * It will be used to count down the pieces as they complete. 3543 */ 3544 Irp->Tail.Overlay.DriverContext[0] = LongToPtr(numPackets); 3545 3546 /* 3547 * For the common 1-packet case, we want to allow for an optimization by BlkCache 3548 * (and also potentially synchronous storage drivers) which may complete the 3549 * downward request synchronously. 3550 * In that synchronous completion case, we want to _not_ mark the original irp pending 3551 * and thereby save on the top-level APC. 3552 * It's critical to coordinate this with the completion routine so that we mark the original irp 3553 * pending if-and-only-if we return STATUS_PENDING for it. 3554 */ 3555 if (numPackets > 1){ 3556 IoMarkIrpPending(Irp); 3557 status = STATUS_PENDING; 3558 } 3559 else { 3560 status = STATUS_SUCCESS; 3561 } 3562 3563 /* 3564 * Transmit the pieces of the transfer. 3565 */ 3566 while (entireXferLen > 0){ 3567 ULONG thisPieceLen = MIN(hwMaxXferLen, entireXferLen); 3568 3569 /* 3570 * Set up a TRANSFER_PACKET for this piece and send it. 3571 */ 3572 slistEntry = SimplePopSlist(&pktList); 3573 NT_ASSERT(slistEntry); 3574 pkt = CONTAINING_RECORD(slistEntry, TRANSFER_PACKET, SlistEntry); 3575 SetupReadWriteTransferPacket( pkt, 3576 bufPtr, 3577 thisPieceLen, 3578 targetLocation, 3579 Irp); 3580 3581 // 3582 // If the IRP needs to be split, then we need to use a partial MDL. 3583 // This prevents problems if the same MDL is mapped multiple times. 3584 // 3585 if (numPackets > 1) { 3586 pkt->UsePartialMdl = TRUE; 3587 } 3588 3589 /* 3590 * When an IRP is completed, the completion routine checks to see if there 3591 * is a deferred IRP ready to sent down (assuming that there are no non-idle 3592 * requests waiting to be serviced). If such a deferred IRP is available, it 3593 * is sent down using this routine. However, if the lower driver completes 3594 * the request inline, there is a potential for multiple deferred IRPs being 3595 * sent down in the context of the same completion thread, thus exhausting 3596 * the call stack. 3597 * In order to prevent this from happening, we need to ensure that deferred 3598 * IRPs that are dequeued in the context of a request's completion routine 3599 * get posted to a DPC. 3600 */ 3601 if (PostToDpc) { 3602 3603 pkt->RetryIn100nsUnits = 0; 3604 TransferPacketQueueRetryDpc(pkt); 3605 status = STATUS_PENDING; 3606 3607 } else { 3608 3609 pktStat = SubmitTransferPacket(pkt); 3610 3611 /* 3612 * If any of the packets completes with pending, we MUST return pending. 3613 * Also, if a packet completes with an error, return pending; this is because 3614 * in the completion routine we mark the original irp pending if the packet failed 3615 * (since we may retry, thereby switching threads). 3616 */ 3617 if (pktStat != STATUS_SUCCESS){ 3618 status = STATUS_PENDING; 3619 } 3620 } 3621 3622 entireXferLen -= thisPieceLen; 3623 bufPtr += thisPieceLen; 3624 targetLocation.QuadPart += thisPieceLen; 3625 } 3626 NT_ASSERT(SimpleIsSlistEmpty(&pktList)); 3627 } 3628 else if (i >= 1){ 3629 /* 3630 * We were unable to get all the TRANSFER_PACKETs we need, 3631 * but we did get at least one. 3632 * That means that we are in extreme low-memory stress. 3633 * We'll try doing this transfer using a single packet. 3634 * The port driver is certainly also in stress, so use one-page 3635 * transfers. 3636 */ 3637 3638 /* 3639 * Free all but one of the TRANSFER_PACKETs. 3640 */ 3641 while (i-- > 1){ 3642 slistEntry = SimplePopSlist(&pktList); 3643 NT_ASSERT(slistEntry); 3644 pkt = CONTAINING_RECORD(slistEntry, TRANSFER_PACKET, SlistEntry); 3645 EnqueueFreeTransferPacket(Fdo, pkt); 3646 } 3647 3648 /* 3649 * Get the single TRANSFER_PACKET that we'll be using. 3650 */ 3651 slistEntry = SimplePopSlist(&pktList); 3652 NT_ASSERT(slistEntry); 3653 NT_ASSERT(SimpleIsSlistEmpty(&pktList)); 3654 pkt = CONTAINING_RECORD(slistEntry, TRANSFER_PACKET, SlistEntry); 3655 3656 if (!driverUsesStartIO) { 3657 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_RW, "Insufficient packets available in ServiceTransferRequest - entering lowMemRetry with pkt=%p.", pkt)); 3658 } 3659 3660 /* 3661 * Set the number of transfer packets (one) 3662 * inside the original irp. 3663 */ 3664 Irp->IoStatus.Information = 0; 3665 Irp->Tail.Overlay.DriverContext[0] = LongToPtr(1); 3666 IoMarkIrpPending(Irp); 3667 3668 /* 3669 * Set up the TRANSFER_PACKET for a lowMem transfer and launch. 3670 */ 3671 SetupReadWriteTransferPacket( pkt, 3672 bufPtr, 3673 entireXferLen, 3674 targetLocation, 3675 Irp); 3676 3677 InitLowMemRetry(pkt, bufPtr, entireXferLen, targetLocation); 3678 StepLowMemRetry(pkt); 3679 status = STATUS_PENDING; 3680 } 3681 else { 3682 /* 3683 * We were unable to get ANY TRANSFER_PACKETs. 3684 * Defer this client irp until some TRANSFER_PACKETs free up. 3685 */ 3686 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_RW, "No packets available in ServiceTransferRequest - deferring transfer (Irp=%p)...", Irp)); 3687 3688 if (priority == IoPagingPriorityHigh) 3689 { 3690 KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql); 3691 3692 if (fdoData->MaxInterleavedNormalIo < ClassMaxInterleavePerCriticalIo) 3693 { 3694 fdoData->MaxInterleavedNormalIo = 0; 3695 } 3696 else 3697 { 3698 fdoData->MaxInterleavedNormalIo -= ClassMaxInterleavePerCriticalIo; 3699 } 3700 3701 fdoData->NumHighPriorityPagingIo--; 3702 3703 if (fdoData->NumHighPriorityPagingIo == 0) 3704 { 3705 LARGE_INTEGER period; 3706 3707 // 3708 // Exiting throttle mode 3709 // 3710 3711 KeQuerySystemTime(&fdoData->ThrottleStopTime); 3712 3713 period.QuadPart = fdoData->ThrottleStopTime.QuadPart - fdoData->ThrottleStartTime.QuadPart; 3714 fdoData->LongestThrottlePeriod.QuadPart = max(fdoData->LongestThrottlePeriod.QuadPart, period.QuadPart); 3715 } 3716 3717 KeReleaseSpinLock(&fdoData->SpinLock, oldIrql); 3718 } 3719 3720 deferClientIrp = TRUE; 3721 } 3722 } 3723 _Analysis_assume_(deferClientIrp); 3724 if (deferClientIrp) 3725 { 3726 IoMarkIrpPending(Irp); 3727 EnqueueDeferredClientIrp(Fdo, Irp); 3728 status = STATUS_PENDING; 3729 } 3730 3731 NT_ASSERT(status != STATUS_UNSUCCESSFUL); 3732 3733 return status; 3734 } 3735 3736 3737 /*++//////////////////////////////////////////////////////////////////////////// 3738 3739 ClassIoComplete() 3740 3741 Routine Description: 3742 3743 This routine executes when the port driver has completed a request. 3744 It looks at the SRB status in the completing SRB and if not success 3745 it checks for valid request sense buffer information. If valid, the 3746 info is used to update status with more precise message of type of 3747 error. This routine deallocates the SRB. 3748 3749 This routine should only be placed on the stack location for a class 3750 driver FDO. 3751 3752 Arguments: 3753 3754 Fdo - Supplies the device object which represents the logical 3755 unit. 3756 3757 Irp - Supplies the Irp which has completed. 3758 3759 Context - Supplies a pointer to the SRB. 3760 3761 Return Value: 3762 3763 NT status 3764 3765 --*/ 3766 NTSTATUS 3767 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 3768 ClassIoComplete( 3769 IN PDEVICE_OBJECT Fdo, 3770 IN PIRP Irp, 3771 IN PVOID Context 3772 ) 3773 { 3774 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); 3775 PSCSI_REQUEST_BLOCK srb = Context; 3776 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; 3777 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData; 3778 NTSTATUS status; 3779 BOOLEAN retry; 3780 BOOLEAN callStartNextPacket; 3781 ULONG srbFlags; 3782 ULONG srbFunction; 3783 3784 NT_ASSERT(fdoExtension->CommonExtension.IsFdo); 3785 3786 if (srb->Function == SRB_FUNCTION_STORAGE_REQUEST_BLOCK) { 3787 srbFlags = ((PSTORAGE_REQUEST_BLOCK)srb)->SrbFlags; 3788 srbFunction = ((PSTORAGE_REQUEST_BLOCK)srb)->SrbFunction; 3789 } else { 3790 srbFlags = srb->SrbFlags; 3791 srbFunction = srb->Function; 3792 } 3793 3794 #if DBG 3795 if (srbFunction == SRB_FUNCTION_FLUSH) { 3796 DBGLOGFLUSHINFO(fdoData, FALSE, FALSE, TRUE); 3797 } 3798 #endif 3799 3800 // 3801 // Check SRB status for success of completing request. 3802 // 3803 3804 if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) { 3805 LONGLONG retryInterval; 3806 3807 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "ClassIoComplete: IRP %p, SRB %p\n", Irp, srb)); 3808 3809 // 3810 // Release the queue if it is frozen. 3811 // 3812 3813 if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) { 3814 ClassReleaseQueue(Fdo); 3815 } 3816 retry = InterpretSenseInfoWithoutHistory( 3817 Fdo, 3818 Irp, 3819 srb, 3820 irpStack->MajorFunction, 3821 ((irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) ? 3822 irpStack->Parameters.DeviceIoControl.IoControlCode : 3823 0), 3824 MAXIMUM_RETRIES - 3825 ((ULONG)(ULONG_PTR)irpStack->Parameters.Others.Argument4), 3826 &status, 3827 &retryInterval); 3828 3829 // 3830 // For Persistent Reserve requests, make sure user gets back partial data. 3831 // 3832 3833 if (irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL && 3834 (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_STORAGE_PERSISTENT_RESERVE_IN || 3835 irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_STORAGE_PERSISTENT_RESERVE_OUT) && 3836 status == STATUS_DATA_OVERRUN) { 3837 3838 status = STATUS_SUCCESS; 3839 retry = FALSE; 3840 } 3841 3842 // 3843 // If the status is verified required and the this request 3844 // should bypass verify required then retry the request. 3845 // 3846 3847 if (TEST_FLAG(irpStack->Flags, SL_OVERRIDE_VERIFY_VOLUME) && 3848 status == STATUS_VERIFY_REQUIRED) { 3849 3850 status = STATUS_IO_DEVICE_ERROR; 3851 retry = TRUE; 3852 } 3853 3854 #ifndef __REACTOS__ 3855 #pragma warning(suppress:4213) // okay to cast Arg4 as a ulong for this use case 3856 if (retry && ((ULONG)(ULONG_PTR)irpStack->Parameters.Others.Argument4)--) { 3857 #else 3858 if (retry && (*(ULONG *)&irpStack->Parameters.Others.Argument4)--) { 3859 #endif 3860 3861 3862 // 3863 // Retry request. 3864 // 3865 3866 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "Retry request %p\n", Irp)); 3867 3868 if (PORT_ALLOCATED_SENSE(fdoExtension, srb)) { 3869 FREE_PORT_ALLOCATED_SENSE_BUFFER(fdoExtension, srb); 3870 } 3871 3872 RetryRequest(Fdo, Irp, srb, FALSE, retryInterval); 3873 return STATUS_MORE_PROCESSING_REQUIRED; 3874 } 3875 3876 } else { 3877 3878 // 3879 // Set status for successful request 3880 // 3881 fdoData->LoggedTURFailureSinceLastIO = FALSE; 3882 ClasspPerfIncrementSuccessfulIo(fdoExtension); 3883 status = STATUS_SUCCESS; 3884 } // end if (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_SUCCESS) 3885 3886 3887 // 3888 // ensure we have returned some info, and it matches what the 3889 // original request wanted for PAGING operations only 3890 // 3891 3892 if ((NT_SUCCESS(status)) && TEST_FLAG(Irp->Flags, IRP_PAGING_IO)) { 3893 NT_ASSERT(Irp->IoStatus.Information != 0); 3894 NT_ASSERT(irpStack->Parameters.Read.Length == Irp->IoStatus.Information); 3895 } 3896 3897 // 3898 // remember if the caller wanted to skip calling IoStartNextPacket. 3899 // for legacy reasons, we cannot call IoStartNextPacket for IoDeviceControl 3900 // calls. this setting only affects device objects with StartIo routines. 3901 // 3902 3903 callStartNextPacket = !TEST_FLAG(srbFlags, SRB_FLAGS_DONT_START_NEXT_PACKET); 3904 if (irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) { 3905 callStartNextPacket = FALSE; 3906 } 3907 3908 // 3909 // Free MDL if allocated. 3910 // 3911 3912 if (TEST_FLAG(srbFlags, SRB_CLASS_FLAGS_FREE_MDL)) { 3913 SrbClearSrbFlags(srb, SRB_CLASS_FLAGS_FREE_MDL); 3914 IoFreeMdl(Irp->MdlAddress); 3915 Irp->MdlAddress = NULL; 3916 } 3917 3918 3919 // 3920 // Free the srb 3921 // 3922 3923 if (!TEST_FLAG(srbFlags, SRB_CLASS_FLAGS_PERSISTANT)) { 3924 3925 if (PORT_ALLOCATED_SENSE(fdoExtension, srb)) { 3926 FREE_PORT_ALLOCATED_SENSE_BUFFER(fdoExtension, srb); 3927 } 3928 3929 if (fdoExtension->CommonExtension.IsSrbLookasideListInitialized){ 3930 ClassFreeOrReuseSrb(fdoExtension, srb); 3931 } 3932 else { 3933 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "ClassIoComplete is freeing an SRB (possibly) on behalf of another driver.")); 3934 FREE_POOL(srb); 3935 } 3936 3937 } else { 3938 3939 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "ClassIoComplete: Not Freeing srb @ %p because " 3940 "SRB_CLASS_FLAGS_PERSISTANT set\n", srb)); 3941 if (PORT_ALLOCATED_SENSE(fdoExtension, srb)) { 3942 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "ClassIoComplete: Not Freeing sensebuffer @ %p " 3943 " because SRB_CLASS_FLAGS_PERSISTANT set\n", 3944 srb->SenseInfoBuffer)); 3945 } 3946 3947 } 3948 3949 // 3950 // Set status in completing IRP. 3951 // 3952 3953 Irp->IoStatus.Status = status; 3954 3955 // 3956 // Set the hard error if necessary. 3957 // 3958 3959 if (!NT_SUCCESS(status) && 3960 IoIsErrorUserInduced(status) && 3961 (Irp->Tail.Overlay.Thread != NULL) 3962 ) { 3963 3964 // 3965 // Store DeviceObject for filesystem, and clear 3966 // in IoStatus.Information field. 3967 // 3968 3969 IoSetHardErrorOrVerifyDevice(Irp, Fdo); 3970 Irp->IoStatus.Information = 0; 3971 } 3972 3973 // 3974 // If disk firmware update succeeded, log a system event. 3975 // 3976 3977 if (NT_SUCCESS(status) && 3978 (irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) && 3979 (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_STORAGE_FIRMWARE_ACTIVATE)) { 3980 3981 ClasspLogSystemEventWithDeviceNumber(Fdo, IO_WARNING_DISK_FIRMWARE_UPDATED); 3982 } 3983 3984 // 3985 // If pending has be returned for this irp then mark the current stack as 3986 // pending. 3987 // 3988 3989 if (Irp->PendingReturned) { 3990 IoMarkIrpPending(Irp); 3991 } 3992 3993 if (fdoExtension->CommonExtension.DriverExtension->InitData.ClassStartIo) { 3994 if (callStartNextPacket) { 3995 KIRQL oldIrql; 3996 KeRaiseIrql(DISPATCH_LEVEL, &oldIrql); 3997 IoStartNextPacket(Fdo, TRUE); // Yes, some IO must now be cancellable. 3998 KeLowerIrql(oldIrql); 3999 } 4000 } 4001 4002 ClassReleaseRemoveLock(Fdo, Irp); 4003 4004 return status; 4005 4006 } // end ClassIoComplete() 4007 4008 4009 /*++//////////////////////////////////////////////////////////////////////////// 4010 4011 ClassSendSrbSynchronous() 4012 4013 Routine Description: 4014 4015 This routine is called by SCSI device controls to complete an 4016 SRB and send it to the port driver synchronously (ie wait for 4017 completion). The CDB is already completed along with the SRB CDB 4018 size and request timeout value. 4019 4020 Arguments: 4021 4022 Fdo - Supplies the functional device object which represents the target. 4023 4024 Srb - Supplies a partially initialized SRB. The SRB cannot come from zone. 4025 4026 BufferAddress - Supplies the address of the buffer. 4027 4028 BufferLength - Supplies the length in bytes of the buffer. 4029 4030 WriteToDevice - Indicates the data should be transfer to the device. 4031 4032 Return Value: 4033 4034 NTSTATUS indicating the final results of the operation. 4035 4036 If NT_SUCCESS(), then the amount of usable data is contained in the field 4037 Srb->DataTransferLength 4038 4039 --*/ 4040 NTSTATUS 4041 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 4042 ClassSendSrbSynchronous( 4043 _In_ PDEVICE_OBJECT Fdo, 4044 _Inout_ PSCSI_REQUEST_BLOCK _Srb, 4045 _In_reads_bytes_opt_(BufferLength) PVOID BufferAddress, 4046 _In_ ULONG BufferLength, 4047 _In_ BOOLEAN WriteToDevice 4048 ) 4049 { 4050 4051 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; 4052 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData; 4053 IO_STATUS_BLOCK ioStatus = {0}; 4054 PIRP irp; 4055 PIO_STACK_LOCATION irpStack; 4056 KEVENT event; 4057 PVOID senseInfoBuffer = NULL; 4058 ULONG senseInfoBufferLength = SENSE_BUFFER_SIZE_EX; 4059 ULONG retryCount = MAXIMUM_RETRIES; 4060 NTSTATUS status; 4061 BOOLEAN retry; 4062 PSTORAGE_REQUEST_BLOCK_HEADER Srb = (PSTORAGE_REQUEST_BLOCK_HEADER)_Srb; 4063 4064 // 4065 // NOTE: This code is only pagable because we are not freezing 4066 // the queue. Allowing the queue to be frozen from a pagable 4067 // routine could leave the queue frozen as we try to page in 4068 // the code to unfreeze the queue. The result would be a nice 4069 // case of deadlock. Therefore, since we are unfreezing the 4070 // queue regardless of the result, just set the NO_FREEZE_QUEUE 4071 // flag in the SRB. 4072 // 4073 4074 NT_ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); 4075 NT_ASSERT(fdoExtension->CommonExtension.IsFdo); 4076 4077 if (Srb->Function != SRB_FUNCTION_STORAGE_REQUEST_BLOCK) { 4078 // 4079 // Write length to SRB. 4080 // 4081 4082 Srb->Length = sizeof(SCSI_REQUEST_BLOCK); 4083 4084 // 4085 // Set SCSI bus address. 4086 // 4087 4088 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI; 4089 } 4090 4091 // 4092 // The Srb->Function should have been set corresponding to SrbType. 4093 // 4094 4095 NT_ASSERT( ((fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_SCSI_REQUEST_BLOCK) && (Srb->Function == SRB_FUNCTION_EXECUTE_SCSI)) || 4096 ((fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) && (Srb->Function == SRB_FUNCTION_STORAGE_REQUEST_BLOCK)) ); 4097 4098 4099 // 4100 // Sense buffer is in aligned nonpaged pool. 4101 // 4102 4103 #if defined(_ARM_) || defined(_ARM64_) 4104 4105 // 4106 // ARM has specific alignment requirements, although this will not have a functional impact on x86 or amd64 4107 // based platforms. We are taking the conservative approach here. 4108 // 4109 senseInfoBufferLength = ALIGN_UP_BY(senseInfoBufferLength,KeGetRecommendedSharedDataAlignment()); 4110 4111 #endif 4112 4113 senseInfoBuffer = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned, 4114 senseInfoBufferLength, 4115 '7CcS'); 4116 4117 if (senseInfoBuffer == NULL) { 4118 4119 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "ClassSendSrbSynchronous: Can't allocate request sense " 4120 "buffer\n")); 4121 return(STATUS_INSUFFICIENT_RESOURCES); 4122 } 4123 4124 4125 // 4126 // Enable auto request sense. 4127 // 4128 SrbSetSenseInfoBufferLength(Srb, SENSE_BUFFER_SIZE_EX); 4129 SrbSetSenseInfoBuffer(Srb, senseInfoBuffer); 4130 4131 SrbSetDataBuffer(Srb, BufferAddress); 4132 4133 4134 // 4135 // Start retries here. 4136 // 4137 4138 retry: 4139 4140 // 4141 // use fdoextension's flags by default. 4142 // do not move out of loop, as the flag may change due to errors 4143 // sending this command. 4144 // 4145 4146 SrbAssignSrbFlags(Srb, fdoExtension->SrbFlags); 4147 4148 if (BufferAddress != NULL) { 4149 if (WriteToDevice) { 4150 SrbSetSrbFlags(Srb, SRB_FLAGS_DATA_OUT); 4151 } else { 4152 SrbSetSrbFlags(Srb, SRB_FLAGS_DATA_IN); 4153 } 4154 } 4155 4156 4157 // 4158 // Initialize the QueueAction field. 4159 // 4160 4161 SrbSetRequestAttribute(Srb, SRB_SIMPLE_TAG_REQUEST); 4162 4163 // 4164 // Disable synchronous transfer for these requests. 4165 // 4166 SrbSetSrbFlags(Srb, SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_QUEUE_FREEZE); 4167 4168 // 4169 // Set the event object to the unsignaled state. 4170 // It will be used to signal request completion. 4171 // 4172 4173 KeInitializeEvent(&event, NotificationEvent, FALSE); 4174 4175 // 4176 // Build device I/O control request with METHOD_NEITHER data transfer. 4177 // We'll queue a completion routine to cleanup the MDL's and such ourself. 4178 // 4179 4180 irp = IoAllocateIrp( 4181 (CCHAR) (fdoExtension->CommonExtension.LowerDeviceObject->StackSize + 1), 4182 FALSE); 4183 4184 if (irp == NULL) { 4185 FREE_POOL(senseInfoBuffer); 4186 SrbSetSenseInfoBuffer(Srb, NULL); 4187 SrbSetSenseInfoBufferLength(Srb, 0); 4188 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "ClassSendSrbSynchronous: Can't allocate Irp\n")); 4189 return(STATUS_INSUFFICIENT_RESOURCES); 4190 } 4191 4192 // 4193 // Get next stack location. 4194 // 4195 4196 irpStack = IoGetNextIrpStackLocation(irp); 4197 4198 // 4199 // Set up SRB for execute scsi request. Save SRB address in next stack 4200 // for the port driver. 4201 // 4202 4203 irpStack->MajorFunction = IRP_MJ_SCSI; 4204 irpStack->Parameters.Scsi.Srb = (PSCSI_REQUEST_BLOCK)Srb; 4205 4206 IoSetCompletionRoutine(irp, 4207 ClasspSendSynchronousCompletion, 4208 Srb, 4209 TRUE, 4210 TRUE, 4211 TRUE); 4212 4213 irp->UserIosb = &ioStatus; 4214 irp->UserEvent = &event; 4215 4216 if (BufferAddress) { 4217 // 4218 // Build an MDL for the data buffer and stick it into the irp. The 4219 // completion routine will unlock the pages and free the MDL. 4220 // 4221 4222 irp->MdlAddress = IoAllocateMdl( BufferAddress, 4223 BufferLength, 4224 FALSE, 4225 FALSE, 4226 irp ); 4227 if (irp->MdlAddress == NULL) { 4228 FREE_POOL(senseInfoBuffer); 4229 SrbSetSenseInfoBuffer(Srb, NULL); 4230 SrbSetSenseInfoBufferLength(Srb, 0); 4231 IoFreeIrp( irp ); 4232 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "ClassSendSrbSynchronous: Can't allocate MDL\n")); 4233 return STATUS_INSUFFICIENT_RESOURCES; 4234 } 4235 4236 _SEH2_TRY { 4237 4238 // 4239 // the io manager unlocks these pages upon completion 4240 // 4241 4242 MmProbeAndLockPages( irp->MdlAddress, 4243 KernelMode, 4244 (WriteToDevice ? IoReadAccess : 4245 IoWriteAccess)); 4246 4247 #ifdef _MSC_VER 4248 #pragma warning(suppress: 6320) // We want to handle any exception that MmProbeAndLockPages might throw 4249 #endif 4250 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { 4251 status = _SEH2_GetExceptionCode(); 4252 4253 FREE_POOL(senseInfoBuffer); 4254 SrbSetSenseInfoBuffer(Srb, NULL); 4255 SrbSetSenseInfoBufferLength(Srb, 0); 4256 IoFreeMdl(irp->MdlAddress); 4257 IoFreeIrp(irp); 4258 4259 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "ClassSendSrbSynchronous: Exception %lx " 4260 "locking buffer\n", status)); 4261 _SEH2_YIELD(return status); 4262 } _SEH2_END; 4263 } 4264 4265 // 4266 // Set the transfer length. 4267 // 4268 4269 SrbSetDataTransferLength(Srb, BufferLength); 4270 4271 // 4272 // Zero out status. 4273 // 4274 4275 SrbSetScsiStatus(Srb, 0); 4276 Srb->SrbStatus = 0; 4277 SrbSetNextSrb(Srb, NULL); 4278 4279 // 4280 // Set up IRP Address. 4281 // 4282 4283 SrbSetOriginalRequest(Srb, irp); 4284 4285 // 4286 // Call the port driver with the request and wait for it to complete. 4287 // 4288 4289 status = IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp); 4290 4291 if (status == STATUS_PENDING) { 4292 (VOID)KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); 4293 status = ioStatus.Status; 4294 } 4295 4296 // NT_ASSERT(SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_PENDING); 4297 NT_ASSERT(status != STATUS_PENDING); 4298 NT_ASSERT(!(Srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN)); 4299 4300 // 4301 // Clear the IRP address in SRB as IRP has been freed at this time 4302 // and don't want to leave any references that may be accessed. 4303 // 4304 4305 SrbSetOriginalRequest(Srb, NULL); 4306 4307 // 4308 // Check that request completed without error. 4309 // 4310 4311 if (SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS) { 4312 4313 LONGLONG retryInterval; 4314 4315 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "ClassSendSrbSynchronous - srb %ph failed (op=%s srbstat=%s(%xh), irpstat=%xh, sense=%s/%s/%s)", Srb, 4316 DBGGETSCSIOPSTR(Srb), 4317 DBGGETSRBSTATUSSTR(Srb), (ULONG)Srb->SrbStatus, status, 4318 DBGGETSENSECODESTR(Srb), 4319 DBGGETADSENSECODESTR(Srb), 4320 DBGGETADSENSEQUALIFIERSTR(Srb))); 4321 4322 // 4323 // assert that the queue is not frozen 4324 // 4325 4326 NT_ASSERT(!TEST_FLAG(Srb->SrbStatus, SRB_STATUS_QUEUE_FROZEN)); 4327 4328 // 4329 // Update status and determine if request should be retried. 4330 // 4331 4332 retry = InterpretSenseInfoWithoutHistory(Fdo, 4333 NULL, // no valid irp exists 4334 (PSCSI_REQUEST_BLOCK)Srb, 4335 IRP_MJ_SCSI, 4336 0, 4337 MAXIMUM_RETRIES - retryCount, 4338 &status, 4339 &retryInterval); 4340 4341 if (retry) { 4342 4343 BOOLEAN validSense = FALSE; 4344 UCHAR additionalSenseCode = 0; 4345 4346 if (status == STATUS_DEVICE_NOT_READY) { 4347 4348 validSense = ScsiGetSenseKeyAndCodes(senseInfoBuffer, 4349 SrbGetSenseInfoBufferLength(Srb), 4350 SCSI_SENSE_OPTIONS_FIXED_FORMAT_IF_UNKNOWN_FORMAT_INDICATED, 4351 NULL, 4352 &additionalSenseCode, 4353 NULL); 4354 } 4355 4356 if ((validSense && additionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY) || 4357 (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SELECTION_TIMEOUT)) { 4358 4359 LARGE_INTEGER delay; 4360 4361 // 4362 // Delay for at least 2 seconds. 4363 // 4364 4365 if (retryInterval < 2*1000*1000*10) { 4366 retryInterval = 2*1000*1000*10; 4367 } 4368 4369 delay.QuadPart = -retryInterval; 4370 4371 // 4372 // Stall for a while to let the device become ready 4373 // 4374 4375 KeDelayExecutionThread(KernelMode, FALSE, &delay); 4376 4377 } 4378 4379 4380 // 4381 // If retries are not exhausted then retry this operation. 4382 // 4383 4384 if (retryCount--) { 4385 4386 if (PORT_ALLOCATED_SENSE_EX(fdoExtension, Srb)) { 4387 FREE_PORT_ALLOCATED_SENSE_BUFFER_EX(fdoExtension, Srb); 4388 } 4389 4390 goto retry; 4391 } 4392 } 4393 4394 4395 } else { 4396 fdoData->LoggedTURFailureSinceLastIO = FALSE; 4397 status = STATUS_SUCCESS; 4398 } 4399 4400 // 4401 // required even though we allocated our own, since the port driver may 4402 // have allocated one also 4403 // 4404 4405 if (PORT_ALLOCATED_SENSE_EX(fdoExtension, Srb)) { 4406 FREE_PORT_ALLOCATED_SENSE_BUFFER_EX(fdoExtension, Srb); 4407 } 4408 4409 FREE_POOL(senseInfoBuffer); 4410 SrbSetSenseInfoBuffer(Srb, NULL); 4411 SrbSetSenseInfoBufferLength(Srb, 0); 4412 4413 return status; 4414 } 4415 4416 4417 /*++//////////////////////////////////////////////////////////////////////////// 4418 4419 ClassInterpretSenseInfo() 4420 4421 Routine Description: 4422 4423 This routine interprets the data returned from the SCSI 4424 request sense. It determines the status to return in the 4425 IRP and whether this request can be retried. 4426 4427 Arguments: 4428 4429 Fdo - Supplies the device object associated with this request. 4430 4431 Srb - Supplies the scsi request block which failed. 4432 4433 MajorFunctionCode - Supplies the function code to be used for logging. 4434 4435 IoDeviceCode - Supplies the device code to be used for logging. 4436 4437 RetryCount - Number of times that the request has been retried. 4438 4439 Status - Returns the status for the request. 4440 4441 RetryInterval - Number of seconds before the request should be retried. 4442 Zero indicates the request should be immediately retried. 4443 4444 Return Value: 4445 4446 BOOLEAN TRUE: Drivers should retry this request. 4447 FALSE: Drivers should not retry this request. 4448 4449 --*/ 4450 BOOLEAN 4451 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 4452 ClassInterpretSenseInfo( 4453 _In_ PDEVICE_OBJECT Fdo, 4454 _In_ PSCSI_REQUEST_BLOCK _Srb, 4455 _In_ UCHAR MajorFunctionCode, 4456 _In_ ULONG IoDeviceCode, 4457 _In_ ULONG RetryCount, 4458 _Out_ NTSTATUS *Status, 4459 _Out_opt_ _Deref_out_range_(0,100) ULONG *RetryInterval 4460 ) 4461 { 4462 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; 4463 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData; 4464 PSTORAGE_REQUEST_BLOCK_HEADER Srb = (PSTORAGE_REQUEST_BLOCK_HEADER)_Srb; 4465 PVOID senseBuffer = SrbGetSenseInfoBuffer(Srb); 4466 BOOLEAN retry = TRUE; 4467 BOOLEAN logError = FALSE; 4468 BOOLEAN unhandledError = FALSE; 4469 BOOLEAN incrementErrorCount = FALSE; 4470 4471 // 4472 // NOTE: This flag must be used only for read/write requests that 4473 // fail with a unexpected retryable error. 4474 // 4475 BOOLEAN logRetryableError = TRUE; 4476 4477 // 4478 // Indicates if we should log this error in our internal log. 4479 // 4480 BOOLEAN logErrorInternal = TRUE; 4481 4482 ULONGLONG badSector = 0; 4483 ULONG uniqueId = 0; 4484 4485 NTSTATUS logStatus; 4486 4487 ULONGLONG readSector; 4488 ULONG index; 4489 4490 ULONG retryInterval = 0; 4491 KIRQL oldIrql; 4492 PCDB cdb = SrbGetCdb(Srb); 4493 UCHAR cdbOpcode = 0; 4494 ULONG cdbLength = SrbGetCdbLength(Srb); 4495 4496 #if DBG 4497 BOOLEAN isReservationConflict = FALSE; 4498 #endif 4499 4500 if (cdb) { 4501 cdbOpcode = cdb->CDB6GENERIC.OperationCode; 4502 } 4503 4504 *Status = STATUS_IO_DEVICE_ERROR; 4505 logStatus = -1; 4506 4507 if (TEST_FLAG(SrbGetSrbFlags(Srb), SRB_CLASS_FLAGS_PAGING)) { 4508 4509 // 4510 // Log anything remotely incorrect about paging i/o 4511 // 4512 4513 logError = TRUE; 4514 uniqueId = 301; 4515 logStatus = IO_WARNING_PAGING_FAILURE; 4516 } 4517 4518 // 4519 // Check that request sense buffer is valid. 4520 // 4521 4522 NT_ASSERT(fdoExtension->CommonExtension.IsFdo); 4523 4524 4525 // 4526 // must handle the SRB_STATUS_INTERNAL_ERROR case first, 4527 // as it has all the flags set. 4528 // 4529 4530 if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_INTERNAL_ERROR) { 4531 4532 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, 4533 "ClassInterpretSenseInfo: Internal Error code is %x\n", 4534 SrbGetSystemStatus(Srb))); 4535 4536 retry = FALSE; 4537 *Status = SrbGetSystemStatus(Srb); 4538 4539 } else if (SrbGetScsiStatus(Srb) == SCSISTAT_RESERVATION_CONFLICT) { 4540 4541 // 4542 // Need to reserve STATUS_DEVICE_BUSY to convey reservation conflict 4543 // for read/write requests as there are upper level components that 4544 // have built-in assumptions that STATUS_DEVICE_BUSY implies reservation 4545 // conflict. 4546 // 4547 *Status = STATUS_DEVICE_BUSY; 4548 retry = FALSE; 4549 logError = FALSE; 4550 #if DBG 4551 isReservationConflict = TRUE; 4552 #endif 4553 4554 } else { 4555 4556 BOOLEAN validSense = FALSE; 4557 4558 if ((Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) && senseBuffer) { 4559 4560 UCHAR errorCode = 0; 4561 UCHAR senseKey = 0; 4562 UCHAR addlSenseCode = 0; 4563 UCHAR addlSenseCodeQual = 0; 4564 BOOLEAN isIncorrectLengthValid = FALSE; 4565 BOOLEAN incorrectLength = FALSE; 4566 BOOLEAN isInformationValid = FALSE; 4567 ULONGLONG information = 0; 4568 4569 4570 validSense = ScsiGetSenseKeyAndCodes(senseBuffer, 4571 SrbGetSenseInfoBufferLength(Srb), 4572 SCSI_SENSE_OPTIONS_NONE, 4573 &senseKey, 4574 &addlSenseCode, 4575 &addlSenseCodeQual); 4576 4577 if (!validSense && !IsSenseDataFormatValueValid(senseBuffer)) { 4578 4579 NT_ASSERT(FALSE); 4580 4581 validSense = ScsiGetFixedSenseKeyAndCodes(senseBuffer, 4582 SrbGetSenseInfoBufferLength(Srb), 4583 &senseKey, 4584 &addlSenseCode, 4585 &addlSenseCodeQual); 4586 } 4587 4588 if (!validSense) { 4589 goto __ClassInterpretSenseInfo_ProcessingInvalidSenseBuffer; 4590 } 4591 4592 errorCode = ScsiGetSenseErrorCode(senseBuffer); 4593 4594 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: Error code is %x\n", errorCode)); 4595 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: Sense key is %x\n", senseKey)); 4596 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: Additional sense code is %x\n", addlSenseCode)); 4597 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: Additional sense code qualifier is %x\n", addlSenseCodeQual)); 4598 4599 if (IsDescriptorSenseDataFormat(senseBuffer)) { 4600 4601 // 4602 // Sense data in Descriptor format 4603 // 4604 4605 PVOID startBuffer = NULL; 4606 UCHAR startBufferLength = 0; 4607 4608 4609 if (ScsiGetSenseDescriptor(senseBuffer, 4610 SrbGetSenseInfoBufferLength(Srb), 4611 &startBuffer, 4612 &startBufferLength)) { 4613 UCHAR outType; 4614 PVOID outBuffer = NULL; 4615 UCHAR outBufferLength = 0; 4616 BOOLEAN foundBlockCommandType = FALSE; 4617 BOOLEAN foundInformationType = FALSE; 4618 UCHAR descriptorLength = 0; 4619 4620 UCHAR typeList[2] = {SCSI_SENSE_DESCRIPTOR_TYPE_INFORMATION, 4621 SCSI_SENSE_DESCRIPTOR_TYPE_BLOCK_COMMAND}; 4622 4623 while ((!foundBlockCommandType || !foundInformationType) && 4624 ScsiGetNextSenseDescriptorByType(startBuffer, 4625 startBufferLength, 4626 typeList, 4627 ARRAYSIZE(typeList), 4628 &outType, 4629 &outBuffer, 4630 &outBufferLength)) { 4631 4632 descriptorLength = ScsiGetSenseDescriptorLength(outBuffer); 4633 4634 if (outBufferLength < descriptorLength) { 4635 4636 // Descriptor data is truncated. 4637 // Complete searching descriptors. Exit the loop now. 4638 break; 4639 } 4640 4641 if (outType == SCSI_SENSE_DESCRIPTOR_TYPE_BLOCK_COMMAND) { 4642 4643 // 4644 // Block Command type 4645 // 4646 4647 if (!foundBlockCommandType) { 4648 4649 foundBlockCommandType = TRUE; 4650 4651 if (ScsiValidateBlockCommandSenseDescriptor(outBuffer, outBufferLength)) { 4652 incorrectLength = ((PSCSI_SENSE_DESCRIPTOR_BLOCK_COMMAND)outBuffer)->IncorrectLength; 4653 isIncorrectLengthValid = TRUE; 4654 } 4655 } else { 4656 4657 // 4658 // A Block Command descriptor is already found earlier. 4659 // 4660 // T10 SPC specification only allows one descriptor for Block Command Descriptor type. 4661 // Assert here to catch devices that violate this rule. Ignore this descriptor. 4662 // 4663 NT_ASSERT(FALSE); 4664 } 4665 4666 } else if (outType == SCSI_SENSE_DESCRIPTOR_TYPE_INFORMATION) { 4667 4668 // 4669 // Information type 4670 // 4671 4672 if (!foundInformationType) { 4673 4674 foundInformationType = TRUE; 4675 4676 if (ScsiValidateInformationSenseDescriptor(outBuffer, outBufferLength)) { 4677 REVERSE_BYTES_QUAD(&information, &(((PSCSI_SENSE_DESCRIPTOR_INFORMATION)outBuffer)->Information)); 4678 isInformationValid = TRUE; 4679 } 4680 } else { 4681 4682 // 4683 // A Information descriptor is already found earlier. 4684 // 4685 // T10 SPC specification only allows one descriptor for Information Descriptor type. 4686 // Assert here to catch devices that violate this rule. Ignore this descriptor. 4687 // 4688 NT_ASSERT(FALSE); 4689 } 4690 4691 } else { 4692 4693 // 4694 // ScsiGetNextDescriptorByType should only return a type that is specified by us. 4695 // 4696 NT_ASSERT(FALSE); 4697 break; 4698 } 4699 4700 // 4701 // Advance to start address of next descriptor 4702 // 4703 startBuffer = (PUCHAR)outBuffer + descriptorLength; 4704 startBufferLength = outBufferLength - descriptorLength; 4705 } 4706 } 4707 } else { 4708 4709 // 4710 // Sense data in Fixed format 4711 // 4712 4713 incorrectLength = ((PFIXED_SENSE_DATA)(senseBuffer))->IncorrectLength; 4714 REVERSE_BYTES(&information, &(((PFIXED_SENSE_DATA)senseBuffer)->Information)); 4715 isInformationValid = TRUE; 4716 isIncorrectLengthValid = TRUE; 4717 } 4718 4719 4720 switch (senseKey) { 4721 4722 case SCSI_SENSE_NO_SENSE: { 4723 4724 // 4725 // Check other indicators. 4726 // 4727 4728 if (isIncorrectLengthValid && incorrectLength) { 4729 4730 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: " 4731 "Incorrect length detected.\n")); 4732 *Status = STATUS_INVALID_BLOCK_LENGTH ; 4733 retry = FALSE; 4734 4735 } else { 4736 4737 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: " 4738 "No specific sense key\n")); 4739 *Status = STATUS_IO_DEVICE_ERROR; 4740 retry = TRUE; 4741 } 4742 4743 break; 4744 } // end SCSI_SENSE_NO_SENSE 4745 4746 case SCSI_SENSE_RECOVERED_ERROR: { 4747 4748 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: " 4749 "Recovered error\n")); 4750 *Status = STATUS_SUCCESS; 4751 retry = FALSE; 4752 logError = TRUE; 4753 uniqueId = 258; 4754 4755 switch(addlSenseCode) { 4756 case SCSI_ADSENSE_TRACK_ERROR: 4757 case SCSI_ADSENSE_SEEK_ERROR: { 4758 logStatus = IO_ERR_SEEK_ERROR; 4759 break; 4760 } 4761 4762 case SCSI_ADSENSE_REC_DATA_NOECC: 4763 case SCSI_ADSENSE_REC_DATA_ECC: { 4764 logStatus = IO_RECOVERED_VIA_ECC; 4765 break; 4766 } 4767 4768 case SCSI_ADSENSE_FAILURE_PREDICTION_THRESHOLD_EXCEEDED: { 4769 4770 UCHAR wmiEventData[sizeof(ULONG)+sizeof(UCHAR)] = {0}; 4771 4772 *((PULONG)wmiEventData) = sizeof(UCHAR); 4773 wmiEventData[sizeof(ULONG)] = addlSenseCodeQual; 4774 4775 // 4776 // Don't log another eventlog if we have already logged once 4777 // NOTE: this should have been interlocked, but the structure 4778 // was publicly defined to use a BOOLEAN (char). Since 4779 // media only reports these errors once per X minutes, 4780 // the potential race condition is nearly non-existant. 4781 // the worst case is duplicate log entries, so ignore. 4782 // 4783 4784 logError = FALSE; 4785 if (fdoExtension->FailurePredicted == 0) { 4786 logError = TRUE; 4787 } 4788 fdoExtension->FailureReason = addlSenseCodeQual; 4789 logStatus = IO_WRN_FAILURE_PREDICTED; 4790 4791 ClassNotifyFailurePredicted(fdoExtension, 4792 (PUCHAR)wmiEventData, 4793 sizeof(wmiEventData), 4794 FALSE, // do not log error 4795 4, // unique error value 4796 SrbGetPathId(Srb), 4797 SrbGetTargetId(Srb), 4798 SrbGetLun(Srb)); 4799 4800 fdoExtension->FailurePredicted = TRUE; 4801 break; 4802 } 4803 4804 default: { 4805 logStatus = IO_ERR_CONTROLLER_ERROR; 4806 break; 4807 } 4808 4809 } // end switch(addlSenseCode) 4810 4811 if (isIncorrectLengthValid && incorrectLength) { 4812 4813 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: " 4814 "Incorrect length detected.\n")); 4815 *Status = STATUS_INVALID_BLOCK_LENGTH ; 4816 } 4817 4818 4819 break; 4820 } // end SCSI_SENSE_RECOVERED_ERROR 4821 4822 case SCSI_SENSE_NOT_READY: { 4823 4824 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: " 4825 "Device not ready\n")); 4826 *Status = STATUS_DEVICE_NOT_READY; 4827 4828 switch (addlSenseCode) { 4829 4830 case SCSI_ADSENSE_LUN_NOT_READY: { 4831 4832 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: " 4833 "Lun not ready\n")); 4834 4835 retryInterval = NOT_READY_RETRY_INTERVAL; 4836 4837 switch (addlSenseCodeQual) { 4838 4839 case SCSI_SENSEQ_BECOMING_READY: { 4840 DEVICE_EVENT_BECOMING_READY notReady = {0}; 4841 4842 logRetryableError = FALSE; 4843 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: " 4844 "In process of becoming ready\n")); 4845 4846 notReady.Version = 1; 4847 notReady.Reason = 1; 4848 notReady.Estimated100msToReady = retryInterval * 10; 4849 ClassSendNotification(fdoExtension, 4850 &GUID_IO_DEVICE_BECOMING_READY, 4851 sizeof(DEVICE_EVENT_BECOMING_READY), 4852 ¬Ready); 4853 break; 4854 } 4855 4856 case SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED: { 4857 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: " 4858 "Manual intervention required\n")); 4859 *Status = STATUS_NO_MEDIA_IN_DEVICE; 4860 retry = FALSE; 4861 break; 4862 } 4863 4864 case SCSI_SENSEQ_FORMAT_IN_PROGRESS: { 4865 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: " 4866 "Format in progress\n")); 4867 retry = FALSE; 4868 break; 4869 } 4870 4871 case SCSI_SENSEQ_OPERATION_IN_PROGRESS: { 4872 DEVICE_EVENT_BECOMING_READY notReady = {0}; 4873 4874 logRetryableError = FALSE; 4875 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: " 4876 "Operation In Progress\n")); 4877 4878 notReady.Version = 1; 4879 notReady.Reason = 2; 4880 notReady.Estimated100msToReady = retryInterval * 10; 4881 ClassSendNotification(fdoExtension, 4882 &GUID_IO_DEVICE_BECOMING_READY, 4883 sizeof(DEVICE_EVENT_BECOMING_READY), 4884 ¬Ready); 4885 4886 break; 4887 } 4888 4889 case SCSI_SENSEQ_LONG_WRITE_IN_PROGRESS: { 4890 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: " 4891 "Long write in progress\n")); 4892 // 4893 // This has been seen as a transcient failure on some cdrom 4894 // drives. The cdrom class driver is going to override this 4895 // setting but has no way of dropping the retry interval 4896 // 4897 retry = FALSE; 4898 retryInterval = 1; 4899 break; 4900 } 4901 4902 case SCSI_SENSEQ_SPACE_ALLOC_IN_PROGRESS: { 4903 logRetryableError = FALSE; 4904 TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: " 4905 "The device (%p) is busy allocating space.\n", 4906 Fdo)); 4907 4908 // 4909 // This indicates that a thinly-provisioned device has hit 4910 // a temporary resource exhaustion and is busy allocating 4911 // more space. We need to retry the request as the device 4912 // will eventually be able to service it. 4913 // 4914 *Status = STATUS_RETRY; 4915 retry = TRUE; 4916 4917 break; 4918 } 4919 4920 case SCSI_SENSEQ_CAUSE_NOT_REPORTABLE: { 4921 4922 if (!TEST_FLAG(fdoExtension->ScanForSpecialFlags, 4923 CLASS_SPECIAL_CAUSE_NOT_REPORTABLE_HACK)) { 4924 4925 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, 4926 "ClassInterpretSenseInfo: " 4927 "not ready, cause unknown\n")); 4928 /* 4929 Many non-WHQL certified drives (mostly CD-RW) return 4930 this when they have no media instead of the obvious 4931 choice of: 4932 4933 SCSI_SENSE_NOT_READY/SCSI_ADSENSE_NO_MEDIA_IN_DEVICE 4934 4935 These drives should not pass WHQL certification due 4936 to this discrepency. 4937 4938 */ 4939 retry = FALSE; 4940 break; 4941 4942 } else { 4943 4944 // 4945 // Treat this as init command required and fall through. 4946 // 4947 } 4948 } 4949 4950 case SCSI_SENSEQ_INIT_COMMAND_REQUIRED: 4951 default: { 4952 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: " 4953 "Initializing command required\n")); 4954 retryInterval = 0; // go back to default 4955 logRetryableError = FALSE; 4956 4957 // 4958 // This sense code/additional sense code 4959 // combination may indicate that the device 4960 // needs to be started. Send an start unit if this 4961 // is a disk device. 4962 // 4963 if (TEST_FLAG(fdoExtension->DeviceFlags, DEV_SAFE_START_UNIT) && 4964 !TEST_FLAG(SrbGetSrbFlags(Srb), SRB_CLASS_FLAGS_LOW_PRIORITY)){ 4965 4966 ClassSendStartUnit(Fdo); 4967 } 4968 break; 4969 } 4970 4971 } // end switch (addlSenseCodeQual) 4972 break; 4973 } 4974 4975 case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE: { 4976 TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: " 4977 "No Media in device.\n")); 4978 *Status = STATUS_NO_MEDIA_IN_DEVICE; 4979 retry = FALSE; 4980 4981 // 4982 // signal MCN that there isn't any media in the device 4983 // 4984 if (!TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) { 4985 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: " 4986 "No Media in a non-removable device %p\n", 4987 Fdo)); 4988 } 4989 4990 if (addlSenseCodeQual == 0xCC){ 4991 /* 4992 * The IMAPI filter returns this ASCQ value when it is burning CD-R media. 4993 * We want to indicate that the media is not present to most applications; 4994 * but RSM has to know that the media is still in the drive (i.e. the drive is not free). 4995 */ 4996 ClassSetMediaChangeState(fdoExtension, MediaUnavailable, FALSE); 4997 } 4998 else { 4999 ClassSetMediaChangeState(fdoExtension, MediaNotPresent, FALSE); 5000 } 5001 5002 break; 5003 } 5004 } // end switch (addlSenseCode) 5005 5006 break; 5007 } // end SCSI_SENSE_NOT_READY 5008 5009 case SCSI_SENSE_MEDIUM_ERROR: { 5010 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: " 5011 "Medium Error (bad block)\n")); 5012 *Status = STATUS_DEVICE_DATA_ERROR; 5013 5014 retry = FALSE; 5015 logError = TRUE; 5016 uniqueId = 256; 5017 logStatus = IO_ERR_BAD_BLOCK; 5018 5019 // 5020 // Check if this error is due to unknown format 5021 // 5022 if (addlSenseCode == SCSI_ADSENSE_INVALID_MEDIA) { 5023 5024 switch (addlSenseCodeQual) { 5025 5026 case SCSI_SENSEQ_UNKNOWN_FORMAT: { 5027 5028 *Status = STATUS_UNRECOGNIZED_MEDIA; 5029 5030 // 5031 // Log error only if this is a paging request 5032 // 5033 if (!TEST_FLAG(SrbGetSrbFlags(Srb), SRB_CLASS_FLAGS_PAGING)) { 5034 logError = FALSE; 5035 } 5036 break; 5037 } 5038 5039 case SCSI_SENSEQ_CLEANING_CARTRIDGE_INSTALLED: { 5040 5041 *Status = STATUS_CLEANER_CARTRIDGE_INSTALLED; 5042 logError = FALSE; 5043 break; 5044 5045 } 5046 default: { 5047 break; 5048 } 5049 } // end switch addlSenseCodeQual 5050 5051 } // end SCSI_ADSENSE_INVALID_MEDIA 5052 5053 break; 5054 5055 } // end SCSI_SENSE_MEDIUM_ERROR 5056 5057 case SCSI_SENSE_HARDWARE_ERROR: { 5058 BOOLEAN logHardwareError = TRUE; 5059 5060 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: " 5061 "Hardware error\n")); 5062 5063 if (fdoData->LegacyErrorHandling == FALSE) { 5064 // 5065 // Hardware errors indicate something has seriously gone 5066 // wrong with the device and retries are very unlikely to 5067 // succeed so fail this request back immediately. 5068 // 5069 retry = FALSE; 5070 *Status = STATUS_DEVICE_HARDWARE_ERROR; 5071 logError = FALSE; 5072 5073 } else { 5074 // 5075 // Revert to legacy behavior. That is, retry everything by default. 5076 // 5077 retry = TRUE; 5078 *Status = STATUS_IO_DEVICE_ERROR; 5079 logError = TRUE; 5080 uniqueId = 257; 5081 logStatus = IO_ERR_CONTROLLER_ERROR; 5082 logHardwareError = FALSE; 5083 5084 // 5085 // This indicates the possibility of a dropped FC packet. 5086 // 5087 if ((addlSenseCode == SCSI_ADSENSE_LOGICAL_UNIT_ERROR && addlSenseCodeQual == SCSI_SENSEQ_TIMEOUT_ON_LOGICAL_UNIT) || 5088 (addlSenseCode == SCSI_ADSENSE_DATA_TRANSFER_ERROR && addlSenseCodeQual == SCSI_SENSEQ_INITIATOR_RESPONSE_TIMEOUT)) { 5089 // 5090 // Fail requests that report this error back to the application. 5091 // 5092 retry = FALSE; 5093 5094 // 5095 // Log a more descriptive error and avoid a second 5096 // error message (IO_ERR_CONTROLLER_ERROR) being logged. 5097 // 5098 logHardwareError = TRUE; 5099 logError = FALSE; 5100 } 5101 } 5102 5103 // 5104 // If CRC error was returned, retry after a slight delay. 5105 // 5106 if (addlSenseCode == SCSI_ADSENSE_LUN_COMMUNICATION && 5107 addlSenseCodeQual == SCSI_SESNEQ_COMM_CRC_ERROR) { 5108 retry = TRUE; 5109 retryInterval = 1; 5110 logHardwareError = FALSE; 5111 logError = FALSE; 5112 } 5113 5114 // 5115 // Hardware errors warrant a more descriptive error. 5116 // Specifically, we need to ensure this disk is easily 5117 // identifiable. 5118 // 5119 if (logHardwareError) { 5120 UCHAR senseInfoBufferLength = SrbGetSenseInfoBufferLength(Srb); 5121 UCHAR senseBufferSize = 0; 5122 5123 if (ScsiGetTotalSenseByteCountIndicated(senseBuffer, 5124 senseInfoBufferLength, 5125 &senseBufferSize)) { 5126 5127 senseBufferSize = min(senseBufferSize, senseInfoBufferLength); 5128 5129 } else { 5130 // 5131 // it's smaller than required to read the total number of 5132 // valid bytes, so just use the SenseInfoBufferLength field. 5133 // 5134 senseBufferSize = senseInfoBufferLength; 5135 } 5136 5137 ClasspQueueLogIOEventWithContextWorker(Fdo, 5138 senseBufferSize, 5139 senseBuffer, 5140 SRB_STATUS(Srb->SrbStatus), 5141 SrbGetScsiStatus(Srb), 5142 (ULONG)IO_ERROR_IO_HARDWARE_ERROR, 5143 cdbLength, 5144 cdb, 5145 NULL); 5146 } 5147 5148 break; 5149 } // end SCSI_SENSE_HARDWARE_ERROR 5150 5151 case SCSI_SENSE_ILLEGAL_REQUEST: { 5152 5153 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: " 5154 "Illegal SCSI request\n")); 5155 *Status = STATUS_INVALID_DEVICE_REQUEST; 5156 retry = FALSE; 5157 5158 switch (addlSenseCode) { 5159 5160 case SCSI_ADSENSE_NO_SENSE: { 5161 5162 switch (addlSenseCodeQual) { 5163 5164 // 5165 // 1. Duplicate List Identifier 5166 // 5167 case SCSI_SENSEQ_OPERATION_IS_IN_PROGRESS: { 5168 5169 // 5170 // XCOPY, READ BUFFER and CHANGE ALIASES return this sense combination under 5171 // certain conditions. Since these commands aren't sent down natively by the 5172 // Windows OS, return the default error for them and only handle this sense 5173 // combination for offload data transfer commands. 5174 // 5175 if (ClasspIsOffloadDataTransferCommand(cdb)) { 5176 5177 TracePrint((TRACE_LEVEL_ERROR, 5178 TRACE_FLAG_IOCTL, 5179 "ClassInterpretSenseInfo (%p): Duplicate List Identifier (command %x, parameter field offset 0x%016llx)\n", 5180 Fdo, 5181 cdbOpcode, 5182 information)); 5183 5184 NT_ASSERTMSG("Duplicate list identifier specified", FALSE); 5185 5186 // 5187 // The host should ensure that it uses unique list id for each TokenOperation request. 5188 // 5189 *Status = STATUS_OPERATION_IN_PROGRESS; 5190 } 5191 break; 5192 } 5193 } 5194 break; 5195 } 5196 5197 case SCSI_ADSENSE_LUN_COMMUNICATION: { 5198 5199 switch (addlSenseCodeQual) { 5200 5201 // 5202 // 1. Source/Destination pairing can't communicate with each other or the copy manager. 5203 // 5204 case SCSI_SENSEQ_UNREACHABLE_TARGET: { 5205 5206 TracePrint((TRACE_LEVEL_ERROR, 5207 TRACE_FLAG_IOCTL, 5208 "ClassInterpretSenseInfo (%p): Source-Destination LUNs can't communicate (command %x)\n", 5209 Fdo, 5210 cdbOpcode)); 5211 5212 *Status = STATUS_DEVICE_UNREACHABLE; 5213 break; 5214 } 5215 } 5216 break; 5217 } 5218 5219 case SCSI_ADSENSE_COPY_TARGET_DEVICE_ERROR: { 5220 5221 switch (addlSenseCodeQual) { 5222 5223 // 5224 // 1. Sum of logical block fields in all block device range descriptors is greater than number 5225 // of logical blocks in the ROD minus block offset into ROD 5226 // 5227 case SCSI_SENSEQ_DATA_UNDERRUN: { 5228 5229 TracePrint((TRACE_LEVEL_ERROR, 5230 TRACE_FLAG_IOCTL, 5231 "ClassInterpretSenseInfo (%p): Host specified a transfer length greater than what is represented by the token (considering the offset) [command %x]\n", 5232 Fdo, 5233 cdbOpcode)); 5234 5235 NT_ASSERTMSG("Host specified blocks to write beyond what is represented by the token", FALSE); 5236 5237 *Status = STATUS_DATA_OVERRUN; 5238 break; 5239 } 5240 } 5241 break; 5242 } 5243 5244 // 5245 // 1. Parameter data truncation (e.g. last descriptor was not fully specified) 5246 // 5247 case SCSI_ADSENSE_PARAMETER_LIST_LENGTH: { 5248 5249 TracePrint((TRACE_LEVEL_ERROR, 5250 TRACE_FLAG_IOCTL, 5251 "ClassInterpretSenseInfo (%p): Target truncated the block device range descriptors in the parameter list (command %x)\n", 5252 Fdo, 5253 cdbOpcode)); 5254 5255 NT_ASSERTMSG("Parameter data truncation", FALSE); 5256 5257 *Status = STATUS_DATA_OVERRUN; 5258 break; 5259 } 5260 5261 case SCSI_ADSENSE_ILLEGAL_COMMAND: { 5262 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: " 5263 "Illegal command\n")); 5264 break; 5265 } 5266 5267 case SCSI_ADSENSE_ILLEGAL_BLOCK: { 5268 5269 LARGE_INTEGER logicalBlockAddr; 5270 LARGE_INTEGER lastLBA; 5271 ULONG numTransferBlocks = 0; 5272 5273 logicalBlockAddr.QuadPart = 0; 5274 5275 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: Illegal block address\n")); 5276 5277 *Status = STATUS_NONEXISTENT_SECTOR; 5278 5279 if (Fdo->DeviceType == FILE_DEVICE_DISK) { 5280 5281 if (IS_SCSIOP_READWRITE(cdbOpcode) && cdb) { 5282 5283 if (TEST_FLAG(fdoExtension->DeviceFlags, DEV_USE_16BYTE_CDB)) { 5284 REVERSE_BYTES_QUAD(&logicalBlockAddr, &cdb->CDB16.LogicalBlock); 5285 REVERSE_BYTES(&numTransferBlocks, &cdb->CDB16.TransferLength); 5286 } else { 5287 REVERSE_BYTES(&logicalBlockAddr.LowPart, &cdb->CDB10.LogicalBlockByte0); 5288 REVERSE_BYTES_SHORT((PUSHORT)&numTransferBlocks, &cdb->CDB10.TransferBlocksMsb); 5289 } 5290 5291 REVERSE_BYTES_QUAD(&lastLBA, &fdoData->LastKnownDriveCapacityData.LogicalBlockAddress); 5292 5293 if ((logicalBlockAddr.QuadPart > lastLBA.QuadPart) || 5294 ((logicalBlockAddr.QuadPart + numTransferBlocks - 1) > lastLBA.QuadPart)) { 5295 5296 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: " 5297 "Request beyond boundary. Last LBA: 0x%I64X Read LBA: 0x%I64X Length: 0x%X\n", 5298 (__int64) lastLBA.QuadPart, (__int64) logicalBlockAddr.QuadPart, numTransferBlocks)); 5299 } else { 5300 // 5301 // Should only retry these if the request was 5302 // truly within our expected size. 5303 // 5304 // Fujitsu IDE drives have been observed to 5305 // return this error transiently for a legal LBA; 5306 // manual retry in the debugger then works, so 5307 // there is a good chance that a programmed retry 5308 // will also work. 5309 // 5310 5311 retry = TRUE; 5312 retryInterval = 5; 5313 } 5314 } else if (ClasspIsOffloadDataTransferCommand(cdb)) { 5315 5316 // 5317 // 1. Number of logical blocks of block device range descriptor exceeds capacity of the medium 5318 // 5319 TracePrint((TRACE_LEVEL_ERROR, 5320 TRACE_FLAG_IOCTL, 5321 "ClassInterpretSenseInfo (%p): LBA out of range (command %x, parameter field offset 0x%016llx)\n", 5322 Fdo, 5323 cdbOpcode, 5324 information)); 5325 5326 NT_ASSERTMSG("Number of blocks specified exceeds LUN capacity", FALSE); 5327 } 5328 } 5329 break; 5330 } 5331 5332 // 5333 // 1. Generic error - cause not reportable 5334 // 2. Insufficient resources to create ROD 5335 // 3. Insufficient resources to create Token 5336 // 4. Max number of tokens exceeded 5337 // 5. Remote Token creation not supported 5338 // 6. Token expired 5339 // 7. Token unknown 5340 // 8. Unsupported Token type 5341 // 9. Token corrupt 5342 // 10. Token revoked 5343 // 11. Token cancelled 5344 // 12. Remote Token usage not supported 5345 // 5346 case SCSI_ADSENSE_INVALID_TOKEN: { 5347 5348 TracePrint((TRACE_LEVEL_ERROR, 5349 TRACE_FLAG_IOCTL, 5350 "ClassInterpretSenseInfo (%p): Invalid/Expired/Modified token specified (command %x, parameter field offset 0x%016llx)\n", 5351 Fdo, 5352 cdbOpcode, 5353 information)); 5354 5355 *Status = STATUS_INVALID_TOKEN; 5356 break; 5357 } 5358 5359 case SCSI_ADSENSE_INVALID_CDB: { 5360 if (ClasspIsOffloadDataTransferCommand(cdb)) { 5361 5362 // 5363 // 1. Mismatched I_T nexus and list identifier 5364 // 5365 TracePrint((TRACE_LEVEL_ERROR, 5366 TRACE_FLAG_IOCTL, 5367 "ClassInterpretSenseInfo (%p): Incorrect I_T nexus likely used (command %x)\n", 5368 Fdo, 5369 cdbOpcode)); 5370 5371 // 5372 // The host should ensure that it sends TokenOperation and ReceiveTokenInformation for the same 5373 // list Id using the same I_T nexus. 5374 // 5375 *Status = STATUS_INVALID_INITIATOR_TARGET_PATH; 5376 5377 } else { 5378 5379 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: " 5380 "Invalid CDB\n")); 5381 5382 // 5383 // Note: the retry interval is not typically used. 5384 // it is set here only because a ClassErrorHandler 5385 // cannot set the retryInterval, and the error may 5386 // require a few commands to be sent to clear whatever 5387 // caused this condition (i.e. disk clears the write 5388 // cache, requiring at least two commands) 5389 // 5390 // hopefully, this shortcoming can be changed for 5391 // blackcomb. 5392 // 5393 5394 retryInterval = 3; 5395 } 5396 break; 5397 } 5398 5399 case SCSI_ADSENSE_INVALID_LUN: { 5400 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: " 5401 "Invalid LUN\n")); 5402 *Status = STATUS_NO_SUCH_DEVICE; 5403 break; 5404 } 5405 5406 case SCSI_ADSENSE_INVALID_FIELD_PARAMETER_LIST: { 5407 5408 switch (addlSenseCodeQual) { 5409 5410 // 5411 // 1. Alignment violation (e.g. copy manager is unable to copy because destination offset is NOT aligned to LUN's granularity/alignment) 5412 // 5413 case SCSI_SENSEQ_INVALID_RELEASE_OF_PERSISTENT_RESERVATION: { 5414 5415 TracePrint((TRACE_LEVEL_ERROR, 5416 TRACE_FLAG_IOCTL, 5417 "ClassInterpretSenseInfo (%p): Alignment violation for command %x.\n", 5418 Fdo, 5419 cdbOpcode)); 5420 5421 NT_ASSERTMSG("Specified offset is not aligned to LUN's granularity", FALSE); 5422 5423 *Status = STATUS_INVALID_OFFSET_ALIGNMENT; 5424 break; 5425 } 5426 5427 // 5428 // 1. Number of block device range descriptors is greater than maximum range descriptors 5429 // 5430 case SCSI_SENSEQ_TOO_MANY_SEGMENT_DESCRIPTORS: { 5431 5432 TracePrint((TRACE_LEVEL_ERROR, 5433 TRACE_FLAG_IOCTL, 5434 "ClassInterpretSenseInfo (%p): Too many descriptors in parameter list for command %x (parameter field offset 0x%016llx)\n", 5435 Fdo, 5436 cdbOpcode, 5437 information)); 5438 5439 NT_ASSERTMSG("Too many descriptors specified", FALSE); 5440 5441 *Status = STATUS_TOO_MANY_SEGMENT_DESCRIPTORS; 5442 break; 5443 } 5444 5445 default: { 5446 5447 if (ClasspIsOffloadDataTransferCommand(cdb)) { 5448 5449 // 5450 // 1. (Various) Invalid parameter length 5451 // 2. Requested inactivity timeout is greater than maximum inactivity timeout 5452 // 3. Same LBA is included in more than one block device range descriptor (overlapping LBAs) 5453 // 4. Total number of logical blocks of all block range descriptors is greater than the maximum transfer size 5454 // 5. Total number of logical blocks of all block range descriptors is greater than maximum token transfer size 5455 // (e.g. WriteUsingToken descriptors specify a cumulative total block count that exceeds the PopulateToken that created the token) 5456 // 6. Block offset into ROD specified an offset that is greater than or equal to the number of logical blocks in the ROD 5457 // 7. Number of logical blocks in a block device range descriptor is greater than maximum transfer length in blocks 5458 // 5459 TracePrint((TRACE_LEVEL_ERROR, 5460 TRACE_FLAG_IOCTL, 5461 "ClassInterpretSenseInfo (%p): Illegal field in parameter list for command %x (parameter field offset 0x%016llx) [AddSense %x, AddSenseQ %x]\n", 5462 Fdo, 5463 cdbOpcode, 5464 information, 5465 addlSenseCode, 5466 addlSenseCodeQual)); 5467 5468 NT_ASSERTMSG("Invalid field in parameter list", FALSE); 5469 5470 *Status = STATUS_INVALID_FIELD_IN_PARAMETER_LIST; 5471 } 5472 5473 break; 5474 } 5475 } 5476 break; 5477 } 5478 5479 case SCSI_ADSENSE_COPY_PROTECTION_FAILURE: { 5480 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: " 5481 "Copy protection failure\n")); 5482 5483 *Status = STATUS_COPY_PROTECTION_FAILURE; 5484 5485 switch (addlSenseCodeQual) { 5486 case SCSI_SENSEQ_AUTHENTICATION_FAILURE: 5487 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, 5488 "ClassInterpretSenseInfo: " 5489 "Authentication failure\n")); 5490 *Status = STATUS_CSS_AUTHENTICATION_FAILURE; 5491 break; 5492 case SCSI_SENSEQ_KEY_NOT_PRESENT: 5493 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, 5494 "ClassInterpretSenseInfo: " 5495 "Key not present\n")); 5496 *Status = STATUS_CSS_KEY_NOT_PRESENT; 5497 break; 5498 case SCSI_SENSEQ_KEY_NOT_ESTABLISHED: 5499 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, 5500 "ClassInterpretSenseInfo: " 5501 "Key not established\n")); 5502 *Status = STATUS_CSS_KEY_NOT_ESTABLISHED; 5503 break; 5504 case SCSI_SENSEQ_READ_OF_SCRAMBLED_SECTOR_WITHOUT_AUTHENTICATION: 5505 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, 5506 "ClassInterpretSenseInfo: " 5507 "Read of scrambled sector w/o " 5508 "authentication\n")); 5509 *Status = STATUS_CSS_SCRAMBLED_SECTOR; 5510 break; 5511 case SCSI_SENSEQ_MEDIA_CODE_MISMATCHED_TO_LOGICAL_UNIT: 5512 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, 5513 "ClassInterpretSenseInfo: " 5514 "Media region does not logical unit " 5515 "region\n")); 5516 *Status = STATUS_CSS_REGION_MISMATCH; 5517 break; 5518 case SCSI_SENSEQ_LOGICAL_UNIT_RESET_COUNT_ERROR: 5519 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, 5520 "ClassInterpretSenseInfo: " 5521 "Region set error -- region may " 5522 "be permanent\n")); 5523 *Status = STATUS_CSS_RESETS_EXHAUSTED; 5524 break; 5525 } // end switch of ASCQ for COPY_PROTECTION_FAILURE 5526 5527 break; 5528 } 5529 5530 case SCSI_ADSENSE_MUSIC_AREA: { 5531 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: " 5532 "Music area\n")); 5533 break; 5534 } 5535 5536 case SCSI_ADSENSE_DATA_AREA: { 5537 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: " 5538 "Data area\n")); 5539 break; 5540 } 5541 5542 case SCSI_ADSENSE_VOLUME_OVERFLOW: { 5543 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: " 5544 "Volume overflow\n")); 5545 break; 5546 } 5547 5548 } // end switch (addlSenseCode) 5549 5550 break; 5551 } // end SCSI_SENSE_ILLEGAL_REQUEST 5552 5553 case SCSI_SENSE_UNIT_ATTENTION: { 5554 5555 ULONG count; 5556 5557 // 5558 // A media change may have occured so increment the change 5559 // count for the physical device 5560 // 5561 5562 count = InterlockedIncrement((volatile LONG *)&fdoExtension->MediaChangeCount); 5563 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, "ClassInterpretSenseInfo: " 5564 "Media change count for device %d incremented to %#lx\n", 5565 fdoExtension->DeviceNumber, count)); 5566 5567 5568 switch (addlSenseCode) { 5569 case SCSI_ADSENSE_MEDIUM_CHANGED: { 5570 logRetryableError = FALSE; 5571 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, "ClassInterpretSenseInfo: " 5572 "Media changed\n")); 5573 5574 if (!TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) { 5575 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_MCN, "ClassInterpretSenseInfo: " 5576 "Media Changed on non-removable device %p\n", 5577 Fdo)); 5578 } 5579 ClassSetMediaChangeState(fdoExtension, MediaPresent, FALSE); 5580 break; 5581 } 5582 5583 case SCSI_ADSENSE_BUS_RESET: { 5584 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: " 5585 "Bus reset\n")); 5586 break; 5587 } 5588 5589 case SCSI_ADSENSE_PARAMETERS_CHANGED: { 5590 logRetryableError = FALSE; 5591 if (addlSenseCodeQual == SCSI_SENSEQ_CAPACITY_DATA_CHANGED) { 5592 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: " 5593 "Device capacity changed (e.g. thinly provisioned LUN). Retry the request.\n")); 5594 5595 ClassQueueCapacityChangedEventWorker(Fdo); 5596 5597 // 5598 // Retry with 1 second delay as ClassQueueCapacityChangedEventWorker may trigger a couple of commands sent to disk. 5599 // 5600 retryInterval = 1; 5601 retry = TRUE; 5602 } 5603 break; 5604 } 5605 5606 case SCSI_ADSENSE_LB_PROVISIONING: { 5607 5608 switch (addlSenseCodeQual) { 5609 5610 case SCSI_SENSEQ_SOFT_THRESHOLD_REACHED: { 5611 5612 logRetryableError = FALSE; 5613 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: " 5614 "Device (%p) has hit a soft threshold.\n", 5615 Fdo)); 5616 5617 // 5618 // This indicates that a resource provisioned or thinly 5619 // provisioned device has hit a soft threshold. Queue a 5620 // worker thread to log a system event and then retry the 5621 // original request. 5622 // 5623 ClassQueueThresholdEventWorker(Fdo); 5624 break; 5625 } 5626 default: { 5627 retry = FALSE; 5628 break; 5629 } 5630 5631 } // end switch (addlSenseCodeQual) 5632 break; 5633 } 5634 5635 case SCSI_ADSENSE_OPERATING_CONDITIONS_CHANGED: { 5636 5637 if (addlSenseCodeQual == SCSI_SENSEQ_MICROCODE_CHANGED) { 5638 // 5639 // Device firmware has been changed. Retry the request. 5640 // 5641 logRetryableError = TRUE; 5642 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: " 5643 "Device firmware has been changed.\n")); 5644 5645 retryInterval = 1; 5646 retry = TRUE; 5647 } else { 5648 // 5649 // Device information has changed, we need to rescan the 5650 // bus for changed information such as the capacity. 5651 // 5652 logRetryableError = FALSE; 5653 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: " 5654 "Device information changed. Invalidate the bus\n")); 5655 5656 if (addlSenseCodeQual == SCSI_SENSEQ_INQUIRY_DATA_CHANGED) { 5657 5658 ClassQueueProvisioningTypeChangedEventWorker(Fdo); 5659 } 5660 5661 if (addlSenseCodeQual == SCSI_SENSEQ_INQUIRY_DATA_CHANGED || 5662 addlSenseCodeQual == SCSI_SENSEQ_OPERATING_DEFINITION_CHANGED) { 5663 5664 // 5665 // Since either the LB provisioning type changed, or the block/slab size 5666 // changed, next time anyone trying to query the FunctionSupportInfo, we 5667 // will requery the device. 5668 // 5669 InterlockedIncrement((volatile LONG *)&fdoExtension->FunctionSupportInfo->ChangeRequestCount); 5670 } 5671 5672 IoInvalidateDeviceRelations(fdoExtension->LowerPdo, BusRelations); 5673 retryInterval = 5; 5674 } 5675 break; 5676 } 5677 5678 case SCSI_ADSENSE_OPERATOR_REQUEST: { 5679 switch (addlSenseCodeQual) { 5680 5681 case SCSI_SENSEQ_MEDIUM_REMOVAL: { 5682 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: " 5683 "Ejection request received!\n")); 5684 ClassSendEjectionNotification(fdoExtension); 5685 break; 5686 } 5687 5688 case SCSI_SENSEQ_WRITE_PROTECT_ENABLE: { 5689 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: " 5690 "Operator selected write permit?! " 5691 "(unsupported!)\n")); 5692 break; 5693 } 5694 5695 case SCSI_SENSEQ_WRITE_PROTECT_DISABLE: { 5696 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: " 5697 "Operator selected write protect?! " 5698 "(unsupported!)\n")); 5699 break; 5700 } 5701 } 5702 } 5703 5704 case SCSI_ADSENSE_FAILURE_PREDICTION_THRESHOLD_EXCEEDED: { 5705 5706 UCHAR wmiEventData[sizeof(ULONG)+sizeof(UCHAR)] = {0}; 5707 5708 *((PULONG)wmiEventData) = sizeof(UCHAR); 5709 wmiEventData[sizeof(ULONG)] = addlSenseCodeQual; 5710 5711 // 5712 // Don't log another eventlog if we have already logged once 5713 // NOTE: this should have been interlocked, but the structure 5714 // was publicly defined to use a BOOLEAN (char). Since 5715 // media only reports these errors once per X minutes, 5716 // the potential race condition is nearly non-existant. 5717 // the worst case is duplicate log entries, so ignore. 5718 // 5719 5720 logError = FALSE; 5721 if (fdoExtension->FailurePredicted == 0) { 5722 logError = TRUE; 5723 } 5724 fdoExtension->FailureReason = addlSenseCodeQual; 5725 logStatus = IO_WRN_FAILURE_PREDICTED; 5726 5727 ClassNotifyFailurePredicted(fdoExtension, 5728 (PUCHAR)wmiEventData, 5729 sizeof(wmiEventData), 5730 FALSE, // do not log error 5731 4, // unique error value 5732 SrbGetPathId(Srb), 5733 SrbGetTargetId(Srb), 5734 SrbGetLun(Srb)); 5735 5736 fdoExtension->FailurePredicted = TRUE; 5737 5738 // 5739 // Since this is a Unit Attention we need to make 5740 // sure we retry this request. 5741 // 5742 retry = TRUE; 5743 5744 break; 5745 } 5746 5747 default: { 5748 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: " 5749 "Unit attention\n")); 5750 break; 5751 } 5752 5753 } // end switch (addlSenseCode) 5754 5755 if (TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) 5756 { 5757 5758 if ((ClassGetVpb(Fdo) != NULL) && (ClassGetVpb(Fdo)->Flags & VPB_MOUNTED)) 5759 { 5760 // 5761 // Set bit to indicate that media may have changed 5762 // and volume needs verification. 5763 // 5764 5765 SET_FLAG(Fdo->Flags, DO_VERIFY_VOLUME); 5766 5767 *Status = STATUS_VERIFY_REQUIRED; 5768 retry = FALSE; 5769 } 5770 else { 5771 *Status = STATUS_IO_DEVICE_ERROR; 5772 } 5773 } 5774 else 5775 { 5776 *Status = STATUS_IO_DEVICE_ERROR; 5777 } 5778 5779 break; 5780 5781 } // end SCSI_SENSE_UNIT_ATTENTION 5782 5783 case SCSI_SENSE_DATA_PROTECT: { 5784 5785 retry = FALSE; 5786 5787 if (addlSenseCode == SCSI_ADSENSE_WRITE_PROTECT) 5788 { 5789 switch (addlSenseCodeQual) { 5790 5791 case SCSI_SENSEQ_SPACE_ALLOC_FAILED_WRITE_PROTECT: { 5792 5793 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: " 5794 "Device's (%p) resources are exhausted.\n", 5795 Fdo)); 5796 5797 ClassQueueResourceExhaustionEventWorker(Fdo); 5798 5799 // 5800 // This indicates that a thinly-provisioned device has 5801 // hit a permanent resource exhaustion. We need to 5802 // return this status code so that patmgr can take the 5803 // disk offline. 5804 // 5805 *Status = STATUS_DISK_RESOURCES_EXHAUSTED; 5806 break; 5807 } 5808 default: 5809 { 5810 break; 5811 } 5812 5813 } // end switch addlSenseCodeQual 5814 } 5815 else 5816 { 5817 if (IS_SCSIOP_WRITE(cdbOpcode)) { 5818 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: " 5819 "Media write protected\n")); 5820 *Status = STATUS_MEDIA_WRITE_PROTECTED; 5821 } else { 5822 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: " 5823 "Access denied\n")); 5824 *Status = STATUS_ACCESS_DENIED; 5825 } 5826 } 5827 break; 5828 } // end SCSI_SENSE_DATA_PROTECT 5829 5830 case SCSI_SENSE_BLANK_CHECK: { 5831 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: " 5832 "Media blank check\n")); 5833 retry = FALSE; 5834 *Status = STATUS_NO_DATA_DETECTED; 5835 break; 5836 } // end SCSI_SENSE_BLANK_CHECK 5837 5838 case SCSI_SENSE_COPY_ABORTED: { 5839 5840 switch (addlSenseCode) { 5841 5842 case SCSI_ADSENSE_COPY_TARGET_DEVICE_ERROR: { 5843 5844 switch (addlSenseCodeQual) { 5845 5846 // 5847 // 1. Target truncated the data transfer. 5848 // 5849 case SCSI_SENSEQ_DATA_UNDERRUN: { 5850 5851 TracePrint((TRACE_LEVEL_WARNING, 5852 TRACE_FLAG_IOCTL, 5853 "ClassInterpretSenseInfo (%p): Data transfer was truncated (command %x)\n", 5854 Fdo, 5855 cdbOpcode)); 5856 5857 *Status = STATUS_SUCCESS; 5858 retry = FALSE; 5859 break; 5860 } 5861 } 5862 break; 5863 } 5864 } 5865 break; 5866 } 5867 5868 case SCSI_SENSE_ABORTED_COMMAND: { 5869 if (ClasspIsOffloadDataTransferCommand(cdb)) { 5870 5871 switch (addlSenseCode) { 5872 5873 case SCSI_ADSENSE_COPY_TARGET_DEVICE_ERROR: { 5874 5875 switch (addlSenseCodeQual) { 5876 5877 // 5878 // 1. Target truncated the data transfer. 5879 // 5880 case SCSI_SENSEQ_DATA_UNDERRUN: { 5881 5882 TracePrint((TRACE_LEVEL_WARNING, 5883 TRACE_FLAG_IOCTL, 5884 "ClassInterpretSenseInfo (%p): Target has truncated the data transfer (command %x)\n", 5885 Fdo, 5886 cdbOpcode)); 5887 5888 *Status = STATUS_SUCCESS; 5889 retry = FALSE; 5890 break; 5891 } 5892 } 5893 break; 5894 } 5895 5896 case SCSI_ADSENSE_RESOURCE_FAILURE: { 5897 5898 switch (addlSenseCodeQual) { 5899 5900 // 5901 // 1. Copy manager wasn't able to finish the operation because of insuffient resources 5902 // (e.g. microsnapshot failure on read, no space on write, etc.) 5903 // 5904 case SCSI_SENSEQ_INSUFFICIENT_RESOURCES: { 5905 5906 TracePrint((TRACE_LEVEL_ERROR, 5907 TRACE_FLAG_IOCTL, 5908 "ClassInterpretSenseInfo (%p): Target has insufficient resources (command %x)\n", 5909 Fdo, 5910 cdb->CDB6GENERIC.OperationCode)); 5911 5912 *Status = STATUS_INSUFFICIENT_RESOURCES; 5913 retry = FALSE; 5914 break; 5915 } 5916 } 5917 break; 5918 } 5919 } 5920 } else { 5921 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: " 5922 "Command aborted\n")); 5923 *Status = STATUS_IO_DEVICE_ERROR; 5924 retryInterval = 1; 5925 } 5926 break; 5927 } // end SCSI_SENSE_ABORTED_COMMAND 5928 5929 default: { 5930 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: " 5931 "Unrecognized sense code\n")); 5932 *Status = STATUS_IO_DEVICE_ERROR; 5933 break; 5934 } 5935 5936 } // end switch (senseKey) 5937 5938 5939 5940 // 5941 // Try to determine bad sector information from sense data 5942 // 5943 5944 if (((IS_SCSIOP_READWRITE(cdbOpcode)) || 5945 (cdbOpcode == SCSIOP_VERIFY) || 5946 (cdbOpcode == SCSIOP_VERIFY16)) && cdb) { 5947 5948 if (isInformationValid) 5949 { 5950 readSector = 0; 5951 badSector = information; 5952 5953 if (cdbOpcode == SCSIOP_READ16 || cdbOpcode == SCSIOP_WRITE16 || cdbOpcode == SCSIOP_VERIFY16) { 5954 REVERSE_BYTES_QUAD(&readSector, &(cdb->AsByte[2])); 5955 } else { 5956 REVERSE_BYTES(&readSector, &(cdb->AsByte[2])); 5957 } 5958 5959 if (cdbOpcode == SCSIOP_READ || cdbOpcode == SCSIOP_WRITE || cdbOpcode == SCSIOP_VERIFY) { 5960 REVERSE_BYTES_SHORT(&index, &(cdb->CDB10.TransferBlocksMsb)); 5961 } else if (cdbOpcode == SCSIOP_READ6 || cdbOpcode == SCSIOP_WRITE6) { 5962 index = cdb->CDB6READWRITE.TransferBlocks; 5963 } else if(cdbOpcode == SCSIOP_READ12 || cdbOpcode == SCSIOP_WRITE12) { 5964 REVERSE_BYTES(&index, &(cdb->CDB12.TransferLength)); 5965 } else { 5966 REVERSE_BYTES(&index, &(cdb->CDB16.TransferLength)); 5967 } 5968 5969 // 5970 // Make sure the bad sector is within the read sectors. 5971 // 5972 5973 if (!(badSector >= readSector && badSector < readSector + index)) { 5974 badSector = readSector; 5975 } 5976 } 5977 } 5978 } 5979 5980 __ClassInterpretSenseInfo_ProcessingInvalidSenseBuffer: 5981 5982 if (!validSense) { 5983 5984 // 5985 // Request sense buffer not valid. No sense information 5986 // to pinpoint the error. Return general request fail. 5987 // 5988 5989 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: " 5990 "Request sense info not valid. SrbStatus %2x\n", 5991 SRB_STATUS(Srb->SrbStatus))); 5992 retry = TRUE; 5993 5994 5995 switch (SRB_STATUS(Srb->SrbStatus)) { 5996 case SRB_STATUS_ABORTED: { 5997 5998 // 5999 // Update the error count for the device. 6000 // 6001 6002 incrementErrorCount = TRUE; 6003 *Status = STATUS_IO_TIMEOUT; 6004 retryInterval = 1; 6005 retry = TRUE; 6006 break; 6007 } 6008 6009 case SRB_STATUS_ERROR: { 6010 6011 *Status = STATUS_IO_DEVICE_ERROR; 6012 if (SrbGetScsiStatus(Srb) == SCSISTAT_GOOD) { 6013 6014 // 6015 // This is some strange return code. Update the error 6016 // count for the device. 6017 // 6018 6019 incrementErrorCount = TRUE; 6020 6021 } else if (SrbGetScsiStatus(Srb) == SCSISTAT_BUSY) { 6022 6023 *Status = STATUS_DEVICE_NOT_READY; 6024 logRetryableError = FALSE; 6025 } 6026 6027 break; 6028 } 6029 6030 case SRB_STATUS_INVALID_REQUEST: { 6031 *Status = STATUS_INVALID_DEVICE_REQUEST; 6032 retry = FALSE; 6033 break; 6034 } 6035 6036 case SRB_STATUS_INVALID_PATH_ID: 6037 case SRB_STATUS_NO_DEVICE: 6038 case SRB_STATUS_NO_HBA: 6039 case SRB_STATUS_INVALID_LUN: 6040 case SRB_STATUS_INVALID_TARGET_ID: { 6041 *Status = STATUS_NO_SUCH_DEVICE; 6042 retry = FALSE; 6043 break; 6044 } 6045 6046 case SRB_STATUS_SELECTION_TIMEOUT: { 6047 logError = TRUE; 6048 logStatus = IO_ERR_NOT_READY; 6049 uniqueId = 260; 6050 *Status = STATUS_DEVICE_NOT_CONNECTED; 6051 retry = FALSE; 6052 break; 6053 } 6054 6055 case SRB_STATUS_TIMEOUT: 6056 case SRB_STATUS_COMMAND_TIMEOUT: { 6057 6058 // 6059 // Update the error count for the device. 6060 // 6061 incrementErrorCount = TRUE; 6062 *Status = STATUS_IO_TIMEOUT; 6063 break; 6064 } 6065 6066 case SRB_STATUS_PARITY_ERROR: 6067 case SRB_STATUS_UNEXPECTED_BUS_FREE: 6068 6069 // 6070 // Update the error count for the device 6071 // and fall through to below 6072 // 6073 incrementErrorCount = TRUE; 6074 6075 case SRB_STATUS_BUS_RESET: { 6076 6077 *Status = STATUS_IO_DEVICE_ERROR; 6078 logRetryableError = FALSE; 6079 break; 6080 } 6081 6082 case SRB_STATUS_DATA_OVERRUN: { 6083 6084 *Status = STATUS_DATA_OVERRUN; 6085 retry = FALSE; 6086 6087 // 6088 // For some commands, we allocate a buffer that may be 6089 // larger than necessary. In these cases, the SRB may be 6090 // returned with SRB_STATUS_DATA_OVERRUN to indicate a 6091 // buffer *underrun*. However, the command was still 6092 // successful so we ensure STATUS_SUCCESS is returned. 6093 // We will also prevent these errors from causing noise in 6094 // the error logs. 6095 // 6096 if ((cdbOpcode == SCSIOP_MODE_SENSE && SrbGetDataTransferLength(Srb) <= cdb->MODE_SENSE.AllocationLength) || 6097 (cdbOpcode == SCSIOP_INQUIRY && SrbGetDataTransferLength(Srb) <= cdb->CDB6INQUIRY.AllocationLength)) { 6098 *Status = STATUS_SUCCESS; 6099 logErrorInternal = FALSE; 6100 logError = FALSE; 6101 } else if (cdbOpcode == SCSIOP_MODE_SENSE10) { 6102 USHORT allocationLength; 6103 REVERSE_BYTES_SHORT(&(cdb->MODE_SENSE10.AllocationLength), &allocationLength); 6104 if (SrbGetDataTransferLength(Srb) <= allocationLength) { 6105 *Status = STATUS_SUCCESS; 6106 logErrorInternal = FALSE; 6107 logError = FALSE; 6108 } 6109 } else if (ClasspIsReceiveTokenInformation(cdb)) { 6110 ULONG allocationLength; 6111 REVERSE_BYTES(&(cdb->RECEIVE_TOKEN_INFORMATION.AllocationLength), &allocationLength); 6112 if (SrbGetDataTransferLength(Srb) <= allocationLength) { 6113 *Status = STATUS_SUCCESS; 6114 logErrorInternal = FALSE; 6115 logError = FALSE; 6116 } 6117 } 6118 6119 break; 6120 } 6121 6122 case SRB_STATUS_PHASE_SEQUENCE_FAILURE: { 6123 6124 // 6125 // Update the error count for the device. 6126 // 6127 6128 incrementErrorCount = TRUE; 6129 *Status = STATUS_IO_DEVICE_ERROR; 6130 6131 // 6132 // If there was phase sequence error then limit the number of 6133 // retries. 6134 // 6135 6136 if (RetryCount > 1 ) { 6137 retry = FALSE; 6138 } 6139 6140 break; 6141 } 6142 6143 case SRB_STATUS_REQUEST_FLUSHED: { 6144 6145 // 6146 // If the status needs verification bit is set. Then set 6147 // the status to need verification and no retry; otherwise, 6148 // just retry the request. 6149 // 6150 6151 if (TEST_FLAG(Fdo->Flags, DO_VERIFY_VOLUME)) { 6152 6153 *Status = STATUS_VERIFY_REQUIRED; 6154 retry = FALSE; 6155 6156 } else { 6157 *Status = STATUS_IO_DEVICE_ERROR; 6158 logRetryableError = FALSE; 6159 } 6160 6161 break; 6162 } 6163 6164 6165 default: { 6166 logError = TRUE; 6167 logStatus = IO_ERR_CONTROLLER_ERROR; 6168 uniqueId = 259; 6169 *Status = STATUS_IO_DEVICE_ERROR; 6170 unhandledError = TRUE; 6171 logRetryableError = FALSE; 6172 break; 6173 } 6174 } 6175 6176 6177 // 6178 // NTRAID #183546 - if we support GESN subtype NOT_READY events, and 6179 // we know from a previous poll when the device will be ready (ETA) 6180 // we should delay the retry more appropriately than just guessing. 6181 // 6182 /* 6183 if (fdoExtension->MediaChangeDetectionInfo && 6184 fdoExtension->MediaChangeDetectionInfo->Gesn.Supported && 6185 TEST_FLAG(fdoExtension->MediaChangeDetectionInfo->Gesn.EventMask, 6186 NOTIFICATION_DEVICE_BUSY_CLASS_MASK) 6187 ) { 6188 // check if Gesn.ReadyTime if greater than current tick count 6189 // if so, delay that long (from 1 to 30 seconds max?) 6190 // else, leave the guess of time alone. 6191 } 6192 */ 6193 6194 } 6195 6196 } 6197 6198 if (incrementErrorCount) { 6199 6200 // 6201 // if any error count occurred, delay the retry of this io by 6202 // at least one second, if caller supports it. 6203 // 6204 6205 if (retryInterval == 0) { 6206 retryInterval = 1; 6207 } 6208 ClasspPerfIncrementErrorCount(fdoExtension); 6209 } 6210 6211 // 6212 // If there is a class specific error handler call it. 6213 // 6214 6215 if (fdoExtension->CommonExtension.DevInfo->ClassError != NULL) { 6216 6217 SCSI_REQUEST_BLOCK tempSrb = {0}; 6218 PSCSI_REQUEST_BLOCK srbPtr = (PSCSI_REQUEST_BLOCK)Srb; 6219 6220 // 6221 // If class driver does not support extended SRB and this is 6222 // an extended SRB, convert to legacy SRB and pass to class 6223 // driver. 6224 // 6225 if ((Srb->Function == SRB_FUNCTION_STORAGE_REQUEST_BLOCK) && 6226 ((fdoExtension->CommonExtension.DriverExtension->SrbSupport & 6227 CLASS_SRB_STORAGE_REQUEST_BLOCK) == 0)) { 6228 ClasspConvertToScsiRequestBlock(&tempSrb, (PSTORAGE_REQUEST_BLOCK)Srb); 6229 srbPtr = &tempSrb; 6230 } 6231 6232 fdoExtension->CommonExtension.DevInfo->ClassError(Fdo, 6233 srbPtr, 6234 Status, 6235 &retry); 6236 } 6237 6238 // 6239 // If the caller wants to know the suggested retry interval tell them. 6240 // 6241 6242 if (ARGUMENT_PRESENT(RetryInterval)) { 6243 *RetryInterval = retryInterval; 6244 } 6245 6246 // 6247 // The RESERVE(6) / RELEASE(6) commands are optional. So 6248 // if they aren't supported, try the 10-byte equivalents 6249 // 6250 6251 cdb = SrbGetCdb(Srb); 6252 if (cdb) { 6253 cdbOpcode = cdb->CDB6GENERIC.OperationCode; 6254 } 6255 6256 if ((cdbOpcode == SCSIOP_RESERVE_UNIT || 6257 cdbOpcode == SCSIOP_RELEASE_UNIT) && cdb) 6258 { 6259 if (*Status == STATUS_INVALID_DEVICE_REQUEST) 6260 { 6261 SrbSetCdbLength(Srb, 10); 6262 cdb->CDB10.OperationCode = (cdb->CDB6GENERIC.OperationCode == SCSIOP_RESERVE_UNIT) ? SCSIOP_RESERVE_UNIT10 : SCSIOP_RELEASE_UNIT10; 6263 6264 SET_FLAG(fdoExtension->PrivateFdoData->HackFlags, FDO_HACK_NO_RESERVE6); 6265 retry = TRUE; 6266 } 6267 } 6268 6269 #if DBG 6270 6271 // 6272 // Ensure that for read/write requests, only return STATUS_DEVICE_BUSY if 6273 // reservation conflict. 6274 // 6275 if (IS_SCSIOP_READWRITE(cdbOpcode) && (*Status == STATUS_DEVICE_BUSY)) { 6276 NT_ASSERT(isReservationConflict == TRUE); 6277 } 6278 6279 #endif 6280 6281 /* 6282 * LOG the error: 6283 * If logErrorInternal is set, log the error in our internal log. 6284 * If logError is set, also log the error in the system log. 6285 */ 6286 if (logErrorInternal || logError) { 6287 ULONG totalSize; 6288 ULONG senseBufferSize = 0; 6289 IO_ERROR_LOG_PACKET staticErrLogEntry = {0}; 6290 CLASS_ERROR_LOG_DATA staticErrLogData = {0}; 6291 SENSE_DATA convertedSenseBuffer = {0}; 6292 UCHAR convertedSenseBufferLength = 0; 6293 BOOLEAN senseDataConverted = FALSE; 6294 6295 // 6296 // Logic below assumes that IO_ERROR_LOG_PACKET + CLASS_ERROR_LOG_DATA 6297 // is less than ERROR_LOG_MAXIMUM_SIZE which is not true for extended SRB. 6298 // Given that classpnp currently does not use >16 byte CDB, we'll convert 6299 // an extended SRB to SCSI_REQUEST_BLOCK instead of changing this code. 6300 // More changes will need to be made when classpnp starts using >16 byte 6301 // CDBs. 6302 // 6303 6304 // 6305 // Calculate the total size of the error log entry. 6306 // add to totalSize in the order that they are used. 6307 // the advantage to calculating all the sizes here is 6308 // that we don't have to do a bunch of extraneous checks 6309 // later on in this code path. 6310 // 6311 totalSize = sizeof(IO_ERROR_LOG_PACKET) // required 6312 + sizeof(CLASS_ERROR_LOG_DATA);// struct for ease 6313 6314 // 6315 // also save any available extra sense data, up to the maximum errlog 6316 // packet size . WMI should be used for real-time analysis. 6317 // the event log should only be used for post-mortem debugging. 6318 // 6319 if ((TEST_FLAG(Srb->SrbStatus, SRB_STATUS_AUTOSENSE_VALID)) && senseBuffer) { 6320 6321 UCHAR validSenseBytes = 0; 6322 UCHAR senseInfoBufferLength = 0; 6323 6324 senseInfoBufferLength = SrbGetSenseInfoBufferLength(Srb); 6325 6326 // 6327 // If sense data is in Descriptor format, convert it to Fixed format 6328 // for the private log. 6329 // 6330 6331 if (IsDescriptorSenseDataFormat(senseBuffer)) { 6332 6333 convertedSenseBufferLength = sizeof(convertedSenseBuffer); 6334 6335 senseDataConverted = ScsiConvertToFixedSenseFormat(senseBuffer, 6336 senseInfoBufferLength, 6337 (PVOID)&convertedSenseBuffer, 6338 convertedSenseBufferLength); 6339 } 6340 6341 // 6342 // For System Log, copy the maximum amount of available sense data 6343 // 6344 6345 if (ScsiGetTotalSenseByteCountIndicated(senseBuffer, 6346 senseInfoBufferLength, 6347 &validSenseBytes)) { 6348 6349 // 6350 // If it is able to determine number of valid bytes, 6351 // copy the maximum amount of available 6352 // sense data that can be saved into the the errlog. 6353 // 6354 6355 // 6356 // set to save the most sense buffer possible 6357 // 6358 6359 senseBufferSize = max(validSenseBytes, sizeof(staticErrLogData.SenseData)); 6360 senseBufferSize = min(senseBufferSize, senseInfoBufferLength); 6361 6362 } else { 6363 // 6364 // it's smaller than required to read the total number of 6365 // valid bytes, so just use the SenseInfoBufferLength field. 6366 // 6367 senseBufferSize = senseInfoBufferLength; 6368 } 6369 6370 /* 6371 * Bump totalSize by the number of extra senseBuffer bytes 6372 * (beyond the default sense buffer within CLASS_ERROR_LOG_DATA). 6373 * Make sure to never allocate more than ERROR_LOG_MAXIMUM_SIZE. 6374 */ 6375 if (senseBufferSize > sizeof(staticErrLogData.SenseData)){ 6376 totalSize += senseBufferSize-sizeof(staticErrLogData.SenseData); 6377 if (totalSize > ERROR_LOG_MAXIMUM_SIZE){ 6378 senseBufferSize -= totalSize-ERROR_LOG_MAXIMUM_SIZE; 6379 totalSize = ERROR_LOG_MAXIMUM_SIZE; 6380 } 6381 } 6382 } 6383 6384 // 6385 // If we've used up all of our retry attempts, set the final status to 6386 // reflect the appropriate result. 6387 // 6388 // ISSUE: the test below should also check RetryCount to determine if we will actually retry, 6389 // but there is no easy test because we'd have to consider the original retry count 6390 // for the op; besides, InterpretTransferPacketError sometimes ignores the retry 6391 // decision returned by this function. So just ErrorRetried to be true in the majority case. 6392 // 6393 if (retry){ 6394 staticErrLogEntry.FinalStatus = STATUS_SUCCESS; 6395 staticErrLogData.ErrorRetried = TRUE; 6396 } else { 6397 staticErrLogEntry.FinalStatus = *Status; 6398 } 6399 6400 // 6401 // Don't log generic IO_WARNING_PAGING_FAILURE message if either the 6402 // I/O is retried, or it completed successfully. 6403 // 6404 if (logStatus == IO_WARNING_PAGING_FAILURE && 6405 (retry || NT_SUCCESS(*Status)) ) { 6406 logError = FALSE; 6407 } 6408 6409 if (TEST_FLAG(SrbGetSrbFlags(Srb), SRB_CLASS_FLAGS_PAGING)) { 6410 staticErrLogData.ErrorPaging = TRUE; 6411 } 6412 if (unhandledError) { 6413 staticErrLogData.ErrorUnhandled = TRUE; 6414 } 6415 6416 // 6417 // Calculate the device offset if there is a geometry. 6418 // 6419 staticErrLogEntry.DeviceOffset.QuadPart = (LONGLONG)badSector; 6420 staticErrLogEntry.DeviceOffset.QuadPart *= (LONGLONG)fdoExtension->DiskGeometry.BytesPerSector; 6421 if (logStatus == -1){ 6422 staticErrLogEntry.ErrorCode = STATUS_IO_DEVICE_ERROR; 6423 } else { 6424 staticErrLogEntry.ErrorCode = logStatus; 6425 } 6426 6427 /* 6428 * The dump data follows the IO_ERROR_LOG_PACKET 6429 */ 6430 staticErrLogEntry.DumpDataSize = (USHORT)totalSize - sizeof(IO_ERROR_LOG_PACKET); 6431 6432 staticErrLogEntry.SequenceNumber = 0; 6433 staticErrLogEntry.MajorFunctionCode = MajorFunctionCode; 6434 staticErrLogEntry.IoControlCode = IoDeviceCode; 6435 staticErrLogEntry.RetryCount = (UCHAR) RetryCount; 6436 staticErrLogEntry.UniqueErrorValue = uniqueId; 6437 6438 KeQueryTickCount(&staticErrLogData.TickCount); 6439 staticErrLogData.PortNumber = (ULONG)-1; 6440 6441 /* 6442 * Save the entire contents of the SRB. 6443 */ 6444 if (Srb->Function == SRB_FUNCTION_STORAGE_REQUEST_BLOCK) { 6445 ClasspConvertToScsiRequestBlock(&staticErrLogData.Srb, (PSTORAGE_REQUEST_BLOCK)Srb); 6446 } else { 6447 staticErrLogData.Srb = *(PSCSI_REQUEST_BLOCK)Srb; 6448 } 6449 6450 /* 6451 * For our private log, save just the default length of the SENSE_DATA. 6452 */ 6453 6454 if ((senseBufferSize != 0) && senseBuffer) { 6455 6456 // 6457 // If sense buffer is in Fixed format, put it in the private log 6458 // 6459 // If sense buffer is in Descriptor format, put it in the private log if conversion to Fixed format 6460 // succeeded. Otherwise, do not put it in the private log. 6461 // 6462 // If sense buffer is in unknown format, the device or the driver probably does not populate 6463 // the first byte of sense data, we probably still want to log error in this case assuming 6464 // it's fixed format, so that its sense key, its additional sense code, and its additional sense code 6465 // qualifier would be shown in the debugger extension output. By doing so, it minimizes any potential 6466 // negative impacts to our ability to diagnose issue. 6467 // 6468 if (IsDescriptorSenseDataFormat(senseBuffer)) { 6469 if (senseDataConverted) { 6470 RtlCopyMemory(&staticErrLogData.SenseData, &convertedSenseBuffer, min(convertedSenseBufferLength, sizeof(staticErrLogData.SenseData))); 6471 } 6472 } else { 6473 RtlCopyMemory(&staticErrLogData.SenseData, senseBuffer, min(senseBufferSize, sizeof(staticErrLogData.SenseData))); 6474 } 6475 } 6476 6477 /* 6478 * Save the error log in our context. 6479 * We only save the default sense buffer length. 6480 */ 6481 if (logErrorInternal) { 6482 KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql); 6483 fdoData->ErrorLogs[fdoData->ErrorLogNextIndex] = staticErrLogData; 6484 fdoData->ErrorLogNextIndex++; 6485 fdoData->ErrorLogNextIndex %= NUM_ERROR_LOG_ENTRIES; 6486 KeReleaseSpinLock(&fdoData->SpinLock, oldIrql); 6487 } 6488 6489 /* 6490 * Log an event if an IO is being retried for reasons that may indicate 6491 * a transient/permanent problem with the I_T_L nexus. But log the event 6492 * only once per retried IO. 6493 */ 6494 if (!IS_SCSIOP_READWRITE(cdbOpcode) || 6495 !retry || 6496 (RetryCount != 0)) { 6497 6498 logRetryableError = FALSE; 6499 } 6500 6501 if (logRetryableError) { 6502 6503 logError = TRUE; 6504 } 6505 6506 /* 6507 * If logError is set, also save this log in the system's error log. 6508 * But make sure we don't log TUR failures over and over 6509 * (e.g. if an external drive was switched off and we're still sending TUR's to it every second). 6510 */ 6511 6512 if (logError) 6513 { 6514 // 6515 // We do not want to log certain system events repetitively 6516 // 6517 6518 cdb = SrbGetCdb(Srb); 6519 if (cdb) { 6520 switch (cdb->CDB10.OperationCode) 6521 { 6522 case SCSIOP_TEST_UNIT_READY: 6523 { 6524 if (fdoData->LoggedTURFailureSinceLastIO) 6525 { 6526 logError = FALSE; 6527 } 6528 else 6529 { 6530 fdoData->LoggedTURFailureSinceLastIO = TRUE; 6531 } 6532 6533 break; 6534 } 6535 6536 case SCSIOP_SYNCHRONIZE_CACHE: 6537 { 6538 if (fdoData->LoggedSYNCFailure) 6539 { 6540 logError = FALSE; 6541 } 6542 else 6543 { 6544 fdoData->LoggedSYNCFailure = TRUE; 6545 } 6546 6547 break; 6548 } 6549 } 6550 } 6551 } 6552 6553 if (logError){ 6554 6555 if (logRetryableError) { 6556 6557 NT_ASSERT(IS_SCSIOP_READWRITE(cdbOpcode)); 6558 6559 // 6560 // A large Disk TimeOutValue (like 60 seconds) results in giving a command a 6561 // large window to complete in. However, if the target returns a retryable error 6562 // just prior to the command timing out, and if multiple retries kick in, it may 6563 // take a significantly long time for the request to complete back to the 6564 // application, leading to a user perception of a hung system. So log an event 6565 // for retried IO so that an admin can help explain the reason for this behavior. 6566 // 6567 ClasspQueueLogIOEventWithContextWorker(Fdo, 6568 senseBufferSize, 6569 senseBuffer, 6570 SRB_STATUS(Srb->SrbStatus), 6571 SrbGetScsiStatus(Srb), 6572 (ULONG)IO_WARNING_IO_OPERATION_RETRIED, 6573 cdbLength, 6574 cdb, 6575 NULL); 6576 6577 } else { 6578 6579 PIO_ERROR_LOG_PACKET errorLogEntry; 6580 PCLASS_ERROR_LOG_DATA errlogData; 6581 6582 errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(Fdo, (UCHAR)totalSize); 6583 if (errorLogEntry){ 6584 errlogData = (PCLASS_ERROR_LOG_DATA)errorLogEntry->DumpData; 6585 6586 *errorLogEntry = staticErrLogEntry; 6587 *errlogData = staticErrLogData; 6588 6589 /* 6590 * For the system log, copy as much of the sense buffer as possible. 6591 */ 6592 if ((senseBufferSize != 0) && senseBuffer) { 6593 RtlCopyMemory(&errlogData->SenseData, senseBuffer, senseBufferSize); 6594 } 6595 6596 /* 6597 * Write the error log packet to the system error logging thread. 6598 * It will be freed by the kernel. 6599 */ 6600 IoWriteErrorLogEntry(errorLogEntry); 6601 } 6602 } 6603 } 6604 } 6605 6606 return retry; 6607 6608 } // end ClassInterpretSenseInfo() 6609 6610 6611 /*++//////////////////////////////////////////////////////////////////////////// 6612 6613 ClassModeSense() 6614 6615 Routine Description: 6616 6617 This routine sends a mode sense command to a target ID and returns 6618 when it is complete. 6619 6620 Arguments: 6621 6622 Fdo - Supplies the functional device object associated with this request. 6623 6624 ModeSenseBuffer - Supplies a buffer to store the sense data. 6625 6626 Length - Supplies the length in bytes of the mode sense buffer. 6627 6628 PageMode - Supplies the page or pages of mode sense data to be retrived. 6629 6630 Return Value: 6631 6632 Length of the transferred data is returned. 6633 6634 --*/ 6635 ULONG 6636 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 6637 ClassModeSense( 6638 _In_ PDEVICE_OBJECT Fdo, 6639 _In_reads_bytes_(Length) PCHAR ModeSenseBuffer, 6640 _In_ ULONG Length, 6641 _In_ UCHAR PageMode 6642 ) 6643 { 6644 PAGED_CODE(); 6645 6646 return ClasspModeSense(Fdo, 6647 ModeSenseBuffer, 6648 Length, 6649 PageMode, 6650 MODE_SENSE_CURRENT_VALUES); 6651 } 6652 6653 6654 ULONG 6655 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 6656 ClassModeSenseEx( 6657 _In_ PDEVICE_OBJECT Fdo, 6658 _In_reads_bytes_(Length) PCHAR ModeSenseBuffer, 6659 _In_ ULONG Length, 6660 _In_ UCHAR PageMode, 6661 _In_ UCHAR PageControl 6662 ) 6663 { 6664 PAGED_CODE(); 6665 #if (NTDDI_VERSION >= NTDDI_WINBLUE) 6666 return ClasspModeSense(Fdo, 6667 ModeSenseBuffer, 6668 Length, 6669 PageMode, 6670 PageControl); 6671 #else 6672 UNREFERENCED_PARAMETER(Fdo); 6673 UNREFERENCED_PARAMETER(ModeSenseBuffer); 6674 UNREFERENCED_PARAMETER(Length); 6675 UNREFERENCED_PARAMETER(PageMode); 6676 UNREFERENCED_PARAMETER(PageControl); 6677 return 0; 6678 #endif 6679 } 6680 6681 ULONG ClasspModeSense( 6682 _In_ PDEVICE_OBJECT Fdo, 6683 _In_reads_bytes_(Length) PCHAR ModeSenseBuffer, 6684 _In_ ULONG Length, 6685 _In_ UCHAR PageMode, 6686 _In_ UCHAR PageControl 6687 ) 6688 /* 6689 Routine Description: 6690 6691 This routine sends a mode sense command to a target ID and returns 6692 when it is complete. 6693 6694 Arguments: 6695 6696 Fdo - Supplies the functional device object associated with this request. 6697 6698 ModeSenseBuffer - Supplies a buffer to store the sense data. 6699 6700 Length - Supplies the length in bytes of the mode sense buffer. 6701 6702 PageMode - Supplies the page or pages of mode sense data to be retrived. 6703 6704 PageControl - Supplies the page control value of the request, which is 6705 one of the following: 6706 MODE_SENSE_CURRENT_VALUES 6707 MODE_SENSE_CHANGEABLE_VALUES 6708 MODE_SENSE_DEFAULT_VAULES 6709 MODE_SENSE_SAVED_VALUES 6710 6711 Return Value: 6712 6713 Length of the transferred data is returned. 6714 6715 --*/ 6716 { 6717 ULONG lengthTransferred = 0; 6718 PMDL senseBufferMdl; 6719 6720 PAGED_CODE(); 6721 6722 senseBufferMdl = BuildDeviceInputMdl(ModeSenseBuffer, Length); 6723 if (senseBufferMdl){ 6724 6725 TRANSFER_PACKET *pkt = DequeueFreeTransferPacket(Fdo, TRUE); 6726 if (pkt){ 6727 KEVENT event; 6728 IRP pseudoIrp = {0}; 6729 6730 /* 6731 * Store the number of packets servicing the irp (one) 6732 * inside the original IRP. It will be used to counted down 6733 * to zero when the packet completes. 6734 * Initialize the original IRP's status to success. 6735 * If the packet fails, we will set it to the error status. 6736 */ 6737 pseudoIrp.Tail.Overlay.DriverContext[0] = LongToPtr(1); 6738 pseudoIrp.IoStatus.Status = STATUS_SUCCESS; 6739 pseudoIrp.IoStatus.Information = 0; 6740 pseudoIrp.MdlAddress = senseBufferMdl; 6741 6742 /* 6743 * Set this up as a SYNCHRONOUS transfer, submit it, 6744 * and wait for the packet to complete. The result 6745 * status will be written to the original irp. 6746 */ 6747 NT_ASSERT(Length <= 0x0ff); 6748 KeInitializeEvent(&event, SynchronizationEvent, FALSE); 6749 SetupModeSenseTransferPacket(pkt, &event, ModeSenseBuffer, (UCHAR)Length, PageMode, 0, &pseudoIrp, PageControl); 6750 SubmitTransferPacket(pkt); 6751 (VOID)KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); 6752 6753 if (NT_SUCCESS(pseudoIrp.IoStatus.Status)){ 6754 lengthTransferred = (ULONG)pseudoIrp.IoStatus.Information; 6755 } 6756 else { 6757 /* 6758 * This request can sometimes fail legitimately 6759 * (e.g. when a SCSI device is attached but turned off) 6760 * so this is not necessarily a device/driver bug. 6761 */ 6762 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "ClasspModeSense on Fdo %ph failed with status %xh.", Fdo, pseudoIrp.IoStatus.Status)); 6763 } 6764 } 6765 6766 FreeDeviceInputMdl(senseBufferMdl); 6767 } 6768 6769 return lengthTransferred; 6770 } 6771 6772 /*++//////////////////////////////////////////////////////////////////////////// 6773 6774 ClassFindModePage() 6775 6776 Routine Description: 6777 6778 This routine scans through the mode sense data and finds the requested 6779 mode sense page code. 6780 6781 Arguments: 6782 ModeSenseBuffer - Supplies a pointer to the mode sense data. 6783 6784 Length - Indicates the length of valid data. 6785 6786 PageMode - Supplies the page mode to be searched for. 6787 6788 Use6Byte - Indicates whether 6 or 10 byte mode sense was used. 6789 6790 Return Value: 6791 6792 A pointer to the the requested mode page. If the mode page was not found 6793 then NULL is return. 6794 6795 --*/ 6796 PVOID 6797 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 6798 ClassFindModePage( 6799 _In_reads_bytes_(Length) PCHAR ModeSenseBuffer, 6800 _In_ ULONG Length, 6801 _In_ UCHAR PageMode, 6802 _In_ BOOLEAN Use6Byte 6803 ) 6804 { 6805 PUCHAR limit; 6806 ULONG parameterHeaderLength; 6807 PVOID result = NULL; 6808 6809 limit = (PUCHAR)ModeSenseBuffer + Length; 6810 parameterHeaderLength = (Use6Byte) ? sizeof(MODE_PARAMETER_HEADER) : sizeof(MODE_PARAMETER_HEADER10); 6811 6812 if (Length >= parameterHeaderLength) { 6813 6814 PMODE_PARAMETER_HEADER10 modeParam10; 6815 ULONG blockDescriptorLength; 6816 6817 /* 6818 * Skip the mode select header and block descriptors. 6819 */ 6820 if (Use6Byte){ 6821 blockDescriptorLength = ((PMODE_PARAMETER_HEADER) ModeSenseBuffer)->BlockDescriptorLength; 6822 } 6823 else { 6824 modeParam10 = (PMODE_PARAMETER_HEADER10) ModeSenseBuffer; 6825 blockDescriptorLength = modeParam10->BlockDescriptorLength[1]; 6826 } 6827 6828 ModeSenseBuffer += parameterHeaderLength + blockDescriptorLength; 6829 6830 // 6831 // ModeSenseBuffer now points at pages. Walk the pages looking for the 6832 // requested page until the limit is reached. 6833 // 6834 6835 while (ModeSenseBuffer + 6836 RTL_SIZEOF_THROUGH_FIELD(MODE_DISCONNECT_PAGE, PageLength) < (PCHAR)limit) { 6837 6838 if (((PMODE_DISCONNECT_PAGE) ModeSenseBuffer)->PageCode == PageMode) { 6839 6840 /* 6841 * found the mode page. make sure it's safe to touch it all 6842 * before returning the pointer to caller 6843 */ 6844 6845 if (ModeSenseBuffer + ((PMODE_DISCONNECT_PAGE)ModeSenseBuffer)->PageLength > (PCHAR)limit) { 6846 /* 6847 * Return NULL since the page is not safe to access in full 6848 */ 6849 result = NULL; 6850 } 6851 else { 6852 result = ModeSenseBuffer; 6853 } 6854 break; 6855 } 6856 6857 // 6858 // Advance to the next page which is 4-byte-aligned offset after this page. 6859 // 6860 ModeSenseBuffer += 6861 ((PMODE_DISCONNECT_PAGE) ModeSenseBuffer)->PageLength + 6862 RTL_SIZEOF_THROUGH_FIELD(MODE_DISCONNECT_PAGE, PageLength); 6863 6864 } 6865 } 6866 6867 return result; 6868 } // end ClassFindModePage() 6869 6870 6871 NTSTATUS 6872 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 6873 ClassModeSelect( 6874 _In_ PDEVICE_OBJECT Fdo, 6875 _In_reads_bytes_(Length) PCHAR ModeSelectBuffer, 6876 _In_ ULONG Length, 6877 _In_ BOOLEAN SavePages 6878 ) 6879 { 6880 #if (NTDDI_VERSION >= NTDDI_WINBLUE) 6881 return ClasspModeSelect(Fdo, 6882 ModeSelectBuffer, 6883 Length, 6884 SavePages); 6885 #else 6886 UNREFERENCED_PARAMETER(Fdo); 6887 UNREFERENCED_PARAMETER(ModeSelectBuffer); 6888 UNREFERENCED_PARAMETER(Length); 6889 UNREFERENCED_PARAMETER(SavePages); 6890 return STATUS_NOT_SUPPORTED; 6891 #endif 6892 } 6893 6894 /*++ 6895 ClasspModeSelect() 6896 6897 Routine Description: 6898 6899 This routine sends a mode select command to a target ID and returns 6900 when it is complete. 6901 6902 Arguments: 6903 6904 Fdo - Supplies the functional device object associated with this request. 6905 6906 ModeSelectBuffer - Supplies a buffer to the select data. 6907 6908 Length - Supplies the length in bytes of the mode select buffer. 6909 6910 SavePages - Specifies the value of the save pages (SP) bit in the mode 6911 select command. 6912 6913 Return Value: 6914 6915 NTSTATUS code of the request. 6916 6917 --*/ 6918 NTSTATUS 6919 ClasspModeSelect( 6920 _In_ PDEVICE_OBJECT Fdo, 6921 _In_reads_bytes_(Length) PCHAR ModeSelectBuffer, 6922 _In_ ULONG Length, 6923 _In_ BOOLEAN SavePages 6924 ) 6925 { 6926 6927 PMDL senseBufferMdl; 6928 NTSTATUS status = STATUS_UNSUCCESSFUL; 6929 6930 senseBufferMdl = BuildDeviceInputMdl(ModeSelectBuffer, Length); 6931 if (senseBufferMdl) { 6932 6933 TRANSFER_PACKET *pkt = DequeueFreeTransferPacket(Fdo, TRUE); 6934 if (pkt){ 6935 KEVENT event; 6936 IRP pseudoIrp = {0}; 6937 6938 /* 6939 * Store the number of packets servicing the irp (one) 6940 * inside the original IRP. It will be used to counted down 6941 * to zero when the packet completes. 6942 * Initialize the original IRP's status to success. 6943 * If the packet fails, we will set it to the error status. 6944 */ 6945 pseudoIrp.Tail.Overlay.DriverContext[0] = LongToPtr(1); 6946 pseudoIrp.IoStatus.Status = STATUS_SUCCESS; 6947 pseudoIrp.IoStatus.Information = 0; 6948 pseudoIrp.MdlAddress = senseBufferMdl; 6949 6950 /* 6951 * Set this up as a SYNCHRONOUS transfer, submit it, 6952 * and wait for the packet to complete. The result 6953 * status will be written to the original irp. 6954 */ 6955 NT_ASSERT(Length <= 0x0ff); 6956 KeInitializeEvent(&event, SynchronizationEvent, FALSE); 6957 SetupModeSelectTransferPacket(pkt, &event, ModeSelectBuffer, (UCHAR)Length, SavePages, &pseudoIrp); 6958 SubmitTransferPacket(pkt); 6959 (VOID)KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); 6960 6961 if (!NT_SUCCESS(pseudoIrp.IoStatus.Status)){ 6962 /* 6963 * This request can sometimes fail legitimately 6964 * (e.g. when a SCSI device is attached but turned off) 6965 * so this is not necessarily a device/driver bug. 6966 */ 6967 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "ClassModeSelect on Fdo %ph failed with status %xh.", Fdo, pseudoIrp.IoStatus.Status)); 6968 } 6969 6970 status = pseudoIrp.IoStatus.Status; 6971 } 6972 6973 FreeDeviceInputMdl(senseBufferMdl); 6974 } else { 6975 status = STATUS_INSUFFICIENT_RESOURCES; 6976 } 6977 6978 return status; 6979 } 6980 6981 /*++//////////////////////////////////////////////////////////////////////////// 6982 6983 ClassSendSrbAsynchronous() 6984 6985 Routine Description: 6986 6987 This routine takes a partially built Srb and an Irp and sends it down to 6988 the port driver. 6989 6990 This routine must be called with the remove lock held for the specified 6991 Irp. 6992 6993 Arguments: 6994 6995 Fdo - Supplies the functional device object for the orginal request. 6996 6997 Srb - Supplies a paritally build ScsiRequestBlock. In particular, the 6998 CDB and the SRB timeout value must be filled in. The SRB must not be 6999 allocated from zone. 7000 7001 Irp - Supplies the requesting Irp. 7002 7003 BufferAddress - Supplies a pointer to the buffer to be transfered. 7004 7005 BufferLength - Supplies the length of data transfer. 7006 7007 WriteToDevice - Indicates the data transfer will be from system memory to 7008 device. 7009 7010 Return Value: 7011 7012 Returns STATUS_PENDING if the request is dispatched (since the 7013 completion routine may change the irp's status value we cannot simply 7014 return the value of the dispatch) 7015 7016 or returns a status value to indicate why it failed. 7017 7018 --*/ 7019 _Success_(return == STATUS_PENDING) 7020 NTSTATUS 7021 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 7022 ClassSendSrbAsynchronous( 7023 _In_ PDEVICE_OBJECT Fdo, 7024 _Inout_ __on_failure(__drv_freesMem(Mem)) __drv_aliasesMem PSCSI_REQUEST_BLOCK _Srb, 7025 _In_ PIRP Irp, 7026 _In_reads_bytes_opt_(BufferLength) __drv_aliasesMem PVOID BufferAddress, 7027 _In_ ULONG BufferLength, 7028 _In_ BOOLEAN WriteToDevice 7029 ) 7030 { 7031 7032 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; 7033 PIO_STACK_LOCATION irpStack; 7034 PSTORAGE_REQUEST_BLOCK_HEADER Srb = (PSTORAGE_REQUEST_BLOCK_HEADER)_Srb; 7035 7036 ULONG savedFlags; 7037 7038 if (Srb->Function != SRB_FUNCTION_STORAGE_REQUEST_BLOCK) { 7039 // 7040 // Write length to SRB. 7041 // 7042 7043 Srb->Length = sizeof(SCSI_REQUEST_BLOCK); 7044 7045 // 7046 // Set SCSI bus address. 7047 // 7048 7049 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI; 7050 } 7051 7052 // 7053 // This is a violation of the SCSI spec but it is required for 7054 // some targets. 7055 // 7056 7057 // Srb->Cdb[1] |= deviceExtension->Lun << 5; 7058 7059 // 7060 // Indicate auto request sense by specifying buffer and size. 7061 // 7062 7063 SrbSetSenseInfoBuffer(Srb, fdoExtension->SenseData); 7064 SrbSetSenseInfoBufferLength(Srb, GET_FDO_EXTENSON_SENSE_DATA_LENGTH(fdoExtension)); 7065 7066 SrbSetDataBuffer(Srb, BufferAddress); 7067 7068 // 7069 // Set the transfer length. 7070 // 7071 SrbSetDataTransferLength(Srb, BufferLength); 7072 7073 // 7074 // Save the class driver specific flags away. 7075 // 7076 7077 savedFlags = SrbGetSrbFlags(Srb) & SRB_FLAGS_CLASS_DRIVER_RESERVED; 7078 7079 // 7080 // Allow the caller to specify that they do not wish 7081 // IoStartNextPacket() to be called in the completion routine. 7082 // 7083 7084 SET_FLAG(savedFlags, (SrbGetSrbFlags(Srb) & SRB_FLAGS_DONT_START_NEXT_PACKET)); 7085 7086 // 7087 // If caller wants to this request to be tagged, save this fact. 7088 // 7089 7090 if ( TEST_FLAG(SrbGetSrbFlags(Srb), SRB_FLAGS_QUEUE_ACTION_ENABLE) && 7091 ( SRB_SIMPLE_TAG_REQUEST == SrbGetRequestAttribute(Srb) || 7092 SRB_HEAD_OF_QUEUE_TAG_REQUEST == SrbGetRequestAttribute(Srb) || 7093 SRB_ORDERED_QUEUE_TAG_REQUEST == SrbGetRequestAttribute(Srb) ) ) { 7094 7095 SET_FLAG(savedFlags, SRB_FLAGS_QUEUE_ACTION_ENABLE); 7096 if (TEST_FLAG(SrbGetSrbFlags(Srb), SRB_FLAGS_NO_QUEUE_FREEZE)) { 7097 SET_FLAG(savedFlags, SRB_FLAGS_NO_QUEUE_FREEZE); 7098 } 7099 } 7100 7101 if (BufferAddress != NULL) { 7102 7103 // 7104 // Build Mdl if necessary. 7105 // 7106 7107 if (Irp->MdlAddress == NULL) { 7108 7109 PMDL mdl; 7110 7111 mdl = IoAllocateMdl(BufferAddress, 7112 BufferLength, 7113 FALSE, 7114 FALSE, 7115 Irp); 7116 7117 if ((mdl == NULL) || (Irp->MdlAddress == NULL)) { 7118 7119 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 7120 7121 // 7122 // ClassIoComplete() would have free'd the srb 7123 // 7124 7125 if (PORT_ALLOCATED_SENSE_EX(fdoExtension, Srb)) { 7126 FREE_PORT_ALLOCATED_SENSE_BUFFER_EX(fdoExtension, Srb); 7127 } 7128 ClassFreeOrReuseSrb(fdoExtension, (PSCSI_REQUEST_BLOCK)Srb); 7129 ClassReleaseRemoveLock(Fdo, Irp); 7130 ClassCompleteRequest(Fdo, Irp, IO_NO_INCREMENT); 7131 7132 return STATUS_INSUFFICIENT_RESOURCES; 7133 } 7134 7135 SET_FLAG(savedFlags, SRB_CLASS_FLAGS_FREE_MDL); 7136 7137 MmBuildMdlForNonPagedPool(Irp->MdlAddress); 7138 7139 } else { 7140 7141 // 7142 // Make sure the buffer requested matches the MDL. 7143 // 7144 7145 NT_ASSERT(BufferAddress == MmGetMdlVirtualAddress(Irp->MdlAddress)); 7146 } 7147 7148 // 7149 // Set read flag. 7150 // 7151 7152 SrbAssignSrbFlags(Srb, WriteToDevice ? SRB_FLAGS_DATA_OUT : SRB_FLAGS_DATA_IN); 7153 7154 } else { 7155 7156 // 7157 // Clear flags. 7158 // 7159 7160 SrbAssignSrbFlags(Srb, SRB_FLAGS_NO_DATA_TRANSFER); 7161 } 7162 7163 // 7164 // Restore saved flags. 7165 // 7166 7167 SrbSetSrbFlags(Srb, savedFlags); 7168 7169 // 7170 // Disable synchronous transfer for these requests. 7171 // 7172 7173 SrbSetSrbFlags(Srb, SRB_FLAGS_DISABLE_SYNCH_TRANSFER); 7174 7175 // 7176 // Zero out status. 7177 // 7178 7179 SrbSetScsiStatus(Srb, 0); 7180 Srb->SrbStatus = 0; 7181 7182 SrbSetNextSrb(Srb, NULL); 7183 7184 // 7185 // Save a few parameters in the current stack location. 7186 // 7187 7188 irpStack = IoGetCurrentIrpStackLocation(Irp); 7189 7190 // 7191 // Save retry count in current Irp stack. 7192 // 7193 7194 irpStack->Parameters.Others.Argument4 = (PVOID)MAXIMUM_RETRIES; 7195 7196 // 7197 // Set up IoCompletion routine address. 7198 // 7199 7200 IoSetCompletionRoutine(Irp, ClassIoComplete, Srb, TRUE, TRUE, TRUE); 7201 7202 // 7203 // Get next stack location and 7204 // set major function code. 7205 // 7206 7207 irpStack = IoGetNextIrpStackLocation(Irp); 7208 7209 irpStack->MajorFunction = IRP_MJ_SCSI; 7210 7211 // 7212 // Save SRB address in next stack for port driver. 7213 // 7214 7215 irpStack->Parameters.Scsi.Srb = (PSCSI_REQUEST_BLOCK)Srb; 7216 7217 // 7218 // Set up Irp Address. 7219 // 7220 7221 SrbSetOriginalRequest(Srb, Irp); 7222 7223 // 7224 // Call the port driver to process the request. 7225 // 7226 7227 IoMarkIrpPending(Irp); 7228 7229 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, Irp); 7230 7231 return STATUS_PENDING; 7232 7233 } // end ClassSendSrbAsynchronous() 7234 7235 /*++//////////////////////////////////////////////////////////////////////////// 7236 7237 ClassDeviceControlDispatch() 7238 7239 Routine Description: 7240 7241 The routine is the common class driver device control dispatch entry point. 7242 This routine is invokes the device-specific drivers DeviceControl routine, 7243 (which may call the Class driver's common DeviceControl routine). 7244 7245 Arguments: 7246 7247 DeviceObject - Supplies a pointer to the device object for this request. 7248 7249 Irp - Supplies the Irp making the request. 7250 7251 Return Value: 7252 7253 Returns the status returned from the device-specific driver. 7254 7255 --*/ 7256 NTSTATUS 7257 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 7258 ClassDeviceControlDispatch( 7259 PDEVICE_OBJECT DeviceObject, 7260 PIRP Irp 7261 ) 7262 { 7263 7264 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 7265 ULONG isRemoved; 7266 7267 isRemoved = ClassAcquireRemoveLock(DeviceObject, Irp); 7268 _Analysis_assume_(isRemoved); 7269 if(isRemoved) { 7270 7271 ClassReleaseRemoveLock(DeviceObject, Irp); 7272 7273 Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST; 7274 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 7275 return STATUS_DEVICE_DOES_NOT_EXIST; 7276 } 7277 7278 // 7279 // Call the class specific driver DeviceControl routine. 7280 // If it doesn't handle it, it will call back into ClassDeviceControl. 7281 // 7282 7283 NT_ASSERT(commonExtension->DevInfo->ClassDeviceControl); 7284 7285 return commonExtension->DevInfo->ClassDeviceControl(DeviceObject,Irp); 7286 } // end ClassDeviceControlDispatch() 7287 7288 7289 /*++//////////////////////////////////////////////////////////////////////////// 7290 7291 ClassDeviceControl() 7292 7293 Routine Description: 7294 7295 The routine is the common class driver device control dispatch function. 7296 This routine is called by a class driver when it get an unrecognized 7297 device control request. This routine will perform the correct action for 7298 common requests such as lock media. If the device request is unknown it 7299 passed down to the next level. 7300 7301 This routine must be called with the remove lock held for the specified 7302 irp. 7303 7304 Arguments: 7305 7306 DeviceObject - Supplies a pointer to the device object for this request. 7307 7308 Irp - Supplies the Irp making the request. 7309 7310 Return Value: 7311 7312 Returns back a STATUS_PENDING or a completion status. 7313 7314 --*/ 7315 NTSTATUS 7316 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 7317 ClassDeviceControl( 7318 _In_ PDEVICE_OBJECT DeviceObject, 7319 _Inout_ PIRP Irp 7320 ) 7321 { 7322 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 7323 7324 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); 7325 PIO_STACK_LOCATION nextStack = NULL; 7326 7327 ULONG controlCode = irpStack->Parameters.DeviceIoControl.IoControlCode; 7328 7329 PSCSI_REQUEST_BLOCK srb = NULL; 7330 PCDB cdb = NULL; 7331 7332 NTSTATUS status; 7333 ULONG modifiedIoControlCode = 0; 7334 GUID activityId = {0}; 7335 7336 7337 // 7338 // If this is a pass through I/O control, set the minor function code 7339 // and device address and pass it to the port driver. 7340 // 7341 7342 if ( (controlCode == IOCTL_SCSI_PASS_THROUGH) || 7343 (controlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT) || 7344 (controlCode == IOCTL_SCSI_PASS_THROUGH_EX) || 7345 (controlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT_EX) ) { 7346 7347 7348 7349 // 7350 // Validiate the user buffer for SCSI pass through. 7351 // For pass through EX: as the handler will validate the size anyway, 7352 // do not apply the similar check and leave the work to the handler. 7353 // 7354 if ( (controlCode == IOCTL_SCSI_PASS_THROUGH) || 7355 (controlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT) ) { 7356 7357 #if BUILD_WOW64_ENABLED && defined(_WIN64) 7358 7359 if (IoIs32bitProcess(Irp)) { 7360 7361 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SCSI_PASS_THROUGH32)){ 7362 7363 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; 7364 7365 ClassReleaseRemoveLock(DeviceObject, Irp); 7366 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 7367 7368 status = STATUS_INVALID_PARAMETER; 7369 goto SetStatusAndReturn; 7370 } 7371 } 7372 else 7373 7374 #endif 7375 7376 { 7377 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < 7378 sizeof(SCSI_PASS_THROUGH)) { 7379 7380 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; 7381 7382 ClassReleaseRemoveLock(DeviceObject, Irp); 7383 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 7384 7385 status = STATUS_INVALID_PARAMETER; 7386 goto SetStatusAndReturn; 7387 } 7388 } 7389 } 7390 7391 7392 IoCopyCurrentIrpStackLocationToNext(Irp); 7393 7394 nextStack = IoGetNextIrpStackLocation(Irp); 7395 nextStack->MinorFunction = 1; 7396 7397 ClassReleaseRemoveLock(DeviceObject, Irp); 7398 7399 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 7400 goto SetStatusAndReturn; 7401 7402 } 7403 7404 Irp->IoStatus.Information = 0; 7405 7406 7407 switch (controlCode) { 7408 7409 case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID: { 7410 7411 PMOUNTDEV_UNIQUE_ID uniqueId; 7412 7413 if (!commonExtension->MountedDeviceInterfaceName.Buffer) { 7414 status = STATUS_INVALID_PARAMETER; 7415 break; 7416 } 7417 7418 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 7419 sizeof(MOUNTDEV_UNIQUE_ID)) { 7420 7421 status = STATUS_BUFFER_TOO_SMALL; 7422 Irp->IoStatus.Information = sizeof(MOUNTDEV_UNIQUE_ID); 7423 break; 7424 } 7425 7426 uniqueId = Irp->AssociatedIrp.SystemBuffer; 7427 RtlZeroMemory(uniqueId, sizeof(MOUNTDEV_UNIQUE_ID)); 7428 uniqueId->UniqueIdLength = 7429 commonExtension->MountedDeviceInterfaceName.Length; 7430 7431 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 7432 sizeof(USHORT) + uniqueId->UniqueIdLength) { 7433 7434 status = STATUS_BUFFER_OVERFLOW; 7435 Irp->IoStatus.Information = sizeof(MOUNTDEV_UNIQUE_ID); 7436 break; 7437 } 7438 7439 RtlCopyMemory(uniqueId->UniqueId, 7440 commonExtension->MountedDeviceInterfaceName.Buffer, 7441 uniqueId->UniqueIdLength); 7442 7443 status = STATUS_SUCCESS; 7444 Irp->IoStatus.Information = sizeof(USHORT) + 7445 uniqueId->UniqueIdLength; 7446 break; 7447 } 7448 7449 case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME: { 7450 7451 PMOUNTDEV_NAME name; 7452 7453 NT_ASSERT(commonExtension->DeviceName.Buffer); 7454 7455 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 7456 sizeof(MOUNTDEV_NAME)) { 7457 7458 status = STATUS_BUFFER_TOO_SMALL; 7459 Irp->IoStatus.Information = sizeof(MOUNTDEV_NAME); 7460 break; 7461 } 7462 7463 name = Irp->AssociatedIrp.SystemBuffer; 7464 RtlZeroMemory(name, sizeof(MOUNTDEV_NAME)); 7465 name->NameLength = commonExtension->DeviceName.Length; 7466 7467 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 7468 sizeof(USHORT) + name->NameLength) { 7469 7470 status = STATUS_BUFFER_OVERFLOW; 7471 Irp->IoStatus.Information = sizeof(MOUNTDEV_NAME); 7472 break; 7473 } 7474 7475 RtlCopyMemory(name->Name, commonExtension->DeviceName.Buffer, 7476 name->NameLength); 7477 7478 status = STATUS_SUCCESS; 7479 Irp->IoStatus.Information = sizeof(USHORT) + name->NameLength; 7480 break; 7481 } 7482 7483 case IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME: { 7484 7485 PMOUNTDEV_SUGGESTED_LINK_NAME suggestedName; 7486 WCHAR driveLetterNameBuffer[10] = {0}; 7487 RTL_QUERY_REGISTRY_TABLE queryTable[2] = {0}; 7488 PWSTR valueName; 7489 UNICODE_STRING driveLetterName; 7490 7491 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 7492 sizeof(MOUNTDEV_SUGGESTED_LINK_NAME)) { 7493 7494 status = STATUS_BUFFER_TOO_SMALL; 7495 Irp->IoStatus.Information = sizeof(MOUNTDEV_SUGGESTED_LINK_NAME); 7496 break; 7497 } 7498 7499 valueName = ExAllocatePoolWithTag( 7500 PagedPool, 7501 commonExtension->DeviceName.Length + sizeof(WCHAR), 7502 '8CcS'); 7503 7504 if (!valueName) { 7505 status = STATUS_INSUFFICIENT_RESOURCES; 7506 break; 7507 } 7508 7509 RtlCopyMemory(valueName, commonExtension->DeviceName.Buffer, 7510 commonExtension->DeviceName.Length); 7511 valueName[commonExtension->DeviceName.Length/sizeof(WCHAR)] = 0; 7512 7513 driveLetterName.Buffer = driveLetterNameBuffer; 7514 driveLetterName.MaximumLength = sizeof(driveLetterNameBuffer); 7515 driveLetterName.Length = 0; 7516 7517 queryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | 7518 RTL_QUERY_REGISTRY_DIRECT | 7519 RTL_QUERY_REGISTRY_TYPECHECK; 7520 queryTable[0].Name = valueName; 7521 queryTable[0].EntryContext = &driveLetterName; 7522 queryTable->DefaultType = (REG_SZ << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_NONE; 7523 7524 status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, 7525 L"\\Registry\\Machine\\System\\DISK", 7526 queryTable, NULL, NULL); 7527 7528 if (!NT_SUCCESS(status)) { 7529 FREE_POOL(valueName); 7530 break; 7531 } 7532 7533 if (driveLetterName.Length == 4 && 7534 driveLetterName.Buffer[0] == '%' && 7535 driveLetterName.Buffer[1] == ':') { 7536 7537 driveLetterName.Buffer[0] = 0xFF; 7538 7539 } else if (driveLetterName.Length != 4 || 7540 driveLetterName.Buffer[0] < FirstDriveLetter || 7541 driveLetterName.Buffer[0] > LastDriveLetter || 7542 driveLetterName.Buffer[1] != ':') { 7543 7544 status = STATUS_NOT_FOUND; 7545 FREE_POOL(valueName); 7546 break; 7547 } 7548 7549 suggestedName = Irp->AssociatedIrp.SystemBuffer; 7550 RtlZeroMemory(suggestedName, sizeof(MOUNTDEV_SUGGESTED_LINK_NAME)); 7551 suggestedName->UseOnlyIfThereAreNoOtherLinks = TRUE; 7552 suggestedName->NameLength = 28; 7553 7554 Irp->IoStatus.Information = 7555 FIELD_OFFSET(MOUNTDEV_SUGGESTED_LINK_NAME, Name) + 28; 7556 7557 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 7558 Irp->IoStatus.Information) { 7559 7560 Irp->IoStatus.Information = 7561 sizeof(MOUNTDEV_SUGGESTED_LINK_NAME); 7562 status = STATUS_BUFFER_OVERFLOW; 7563 FREE_POOL(valueName); 7564 break; 7565 } 7566 7567 RtlDeleteRegistryValue(RTL_REGISTRY_ABSOLUTE, 7568 L"\\Registry\\Machine\\System\\DISK", 7569 valueName); 7570 7571 FREE_POOL(valueName); 7572 7573 RtlCopyMemory(suggestedName->Name, L"\\DosDevices\\", 24); 7574 suggestedName->Name[12] = driveLetterName.Buffer[0]; 7575 suggestedName->Name[13] = ':'; 7576 7577 // 7578 // NT_SUCCESS(status) based on RtlQueryRegistryValues 7579 // 7580 status = STATUS_SUCCESS; 7581 7582 break; 7583 } 7584 7585 default: 7586 status = STATUS_PENDING; 7587 break; 7588 } 7589 7590 if (status != STATUS_PENDING) { 7591 ClassReleaseRemoveLock(DeviceObject, Irp); 7592 Irp->IoStatus.Status = status; 7593 7594 7595 IoCompleteRequest(Irp, IO_NO_INCREMENT); 7596 return status; 7597 } 7598 7599 if (commonExtension->IsFdo){ 7600 7601 PULONG_PTR function; 7602 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION)commonExtension; 7603 size_t sizeNeeded; 7604 7605 // 7606 // Allocate a SCSI SRB for handling various IOCTLs. 7607 // NOTE - there is a case where an IOCTL is sent to classpnp before AdapterDescriptor 7608 // is initialized. In this case, default to legacy SRB. 7609 // 7610 if ((fdoExtension->AdapterDescriptor != NULL) && 7611 (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK)) { 7612 sizeNeeded = CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE; 7613 } else { 7614 sizeNeeded = sizeof(SCSI_REQUEST_BLOCK); 7615 } 7616 7617 srb = ExAllocatePoolWithTag(NonPagedPoolNx, 7618 sizeNeeded + 7619 (sizeof(ULONG_PTR) * 2), 7620 '9CcS'); 7621 7622 if (srb == NULL) { 7623 7624 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 7625 ClassReleaseRemoveLock(DeviceObject, Irp); 7626 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 7627 status = STATUS_INSUFFICIENT_RESOURCES; 7628 goto SetStatusAndReturn; 7629 } 7630 7631 if ((fdoExtension->AdapterDescriptor != NULL) && 7632 (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK)) { 7633 status = InitializeStorageRequestBlock((PSTORAGE_REQUEST_BLOCK)srb, 7634 STORAGE_ADDRESS_TYPE_BTL8, 7635 CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE, 7636 1, 7637 SrbExDataTypeScsiCdb16); 7638 if (NT_SUCCESS(status)) { 7639 ((PSTORAGE_REQUEST_BLOCK)srb)->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI; 7640 function = (PULONG_PTR)((PCHAR)srb + sizeNeeded); 7641 } else { 7642 // 7643 // Should not occur. 7644 // 7645 NT_ASSERT(FALSE); 7646 goto SetStatusAndReturn; 7647 } 7648 } else { 7649 RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK)); 7650 srb->Length = sizeof(SCSI_REQUEST_BLOCK); 7651 srb->Function = SRB_FUNCTION_EXECUTE_SCSI; 7652 function = (PULONG_PTR) ((PSCSI_REQUEST_BLOCK) (srb + 1)); 7653 } 7654 7655 // 7656 // Save the function code and the device object in the memory after 7657 // the SRB. 7658 // 7659 7660 *function = (ULONG_PTR) DeviceObject; 7661 function++; 7662 *function = (ULONG_PTR) controlCode; 7663 7664 } else { 7665 srb = NULL; 7666 } 7667 7668 // 7669 // Change the device type to storage for the switch statement, but only 7670 // if from a legacy device type 7671 // 7672 7673 if (((controlCode & 0xffff0000) == (IOCTL_DISK_BASE << 16)) || 7674 ((controlCode & 0xffff0000) == (IOCTL_TAPE_BASE << 16)) || 7675 ((controlCode & 0xffff0000) == (IOCTL_CDROM_BASE << 16)) 7676 ) { 7677 7678 modifiedIoControlCode = (controlCode & ~0xffff0000); 7679 modifiedIoControlCode |= (IOCTL_STORAGE_BASE << 16); 7680 7681 } else { 7682 7683 modifiedIoControlCode = controlCode; 7684 7685 } 7686 7687 TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "> ioctl %xh (%s)", modifiedIoControlCode, DBGGETIOCTLSTR(modifiedIoControlCode))); 7688 7689 7690 switch (modifiedIoControlCode) { 7691 7692 case IOCTL_STORAGE_GET_HOTPLUG_INFO: { 7693 7694 FREE_POOL(srb); 7695 7696 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 7697 sizeof(STORAGE_HOTPLUG_INFO)) { 7698 7699 // 7700 // Indicate unsuccessful status and no data transferred. 7701 // 7702 7703 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL; 7704 Irp->IoStatus.Information = sizeof(STORAGE_HOTPLUG_INFO); 7705 7706 ClassReleaseRemoveLock(DeviceObject, Irp); 7707 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 7708 status = STATUS_BUFFER_TOO_SMALL; 7709 7710 } else if (!commonExtension->IsFdo) { 7711 7712 7713 // 7714 // Just forward this down and return 7715 // 7716 7717 IoCopyCurrentIrpStackLocationToNext(Irp); 7718 7719 ClassReleaseRemoveLock(DeviceObject, Irp); 7720 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 7721 7722 } else { 7723 7724 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension; 7725 PSTORAGE_HOTPLUG_INFO info; 7726 7727 fdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION)commonExtension; 7728 info = Irp->AssociatedIrp.SystemBuffer; 7729 7730 *info = fdoExtension->PrivateFdoData->HotplugInfo; 7731 Irp->IoStatus.Status = STATUS_SUCCESS; 7732 Irp->IoStatus.Information = sizeof(STORAGE_HOTPLUG_INFO); 7733 ClassReleaseRemoveLock(DeviceObject, Irp); 7734 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 7735 status = STATUS_SUCCESS; 7736 } 7737 break; 7738 } 7739 7740 case IOCTL_STORAGE_SET_HOTPLUG_INFO: { 7741 7742 FREE_POOL(srb); 7743 7744 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < 7745 sizeof(STORAGE_HOTPLUG_INFO)) { 7746 7747 // 7748 // Indicate unsuccessful status and no data transferred. 7749 // 7750 7751 Irp->IoStatus.Status = STATUS_INFO_LENGTH_MISMATCH; 7752 7753 ClassReleaseRemoveLock(DeviceObject, Irp); 7754 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 7755 status = STATUS_INFO_LENGTH_MISMATCH; 7756 goto SetStatusAndReturn; 7757 7758 } 7759 7760 if (!commonExtension->IsFdo) { 7761 7762 7763 // 7764 // Just forward this down and return 7765 // 7766 7767 IoCopyCurrentIrpStackLocationToNext(Irp); 7768 7769 ClassReleaseRemoveLock(DeviceObject, Irp); 7770 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 7771 7772 } else { 7773 7774 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION)commonExtension; 7775 PSTORAGE_HOTPLUG_INFO info = Irp->AssociatedIrp.SystemBuffer; 7776 7777 status = STATUS_SUCCESS; 7778 7779 if (info->Size != fdoExtension->PrivateFdoData->HotplugInfo.Size) 7780 { 7781 status = STATUS_INVALID_PARAMETER_1; 7782 } 7783 7784 if (info->MediaRemovable != fdoExtension->PrivateFdoData->HotplugInfo.MediaRemovable) 7785 { 7786 status = STATUS_INVALID_PARAMETER_2; 7787 } 7788 7789 if (info->MediaHotplug != fdoExtension->PrivateFdoData->HotplugInfo.MediaHotplug) 7790 { 7791 status = STATUS_INVALID_PARAMETER_3; 7792 } 7793 7794 if (NT_SUCCESS(status)) 7795 { 7796 if (info->WriteCacheEnableOverride != fdoExtension->PrivateFdoData->HotplugInfo.WriteCacheEnableOverride) 7797 { 7798 fdoExtension->PrivateFdoData->HotplugInfo.WriteCacheEnableOverride = info->WriteCacheEnableOverride; 7799 7800 // 7801 // Store the user-defined override in the registry 7802 // 7803 7804 ClassSetDeviceParameter(fdoExtension, 7805 CLASSP_REG_SUBKEY_NAME, 7806 CLASSP_REG_WRITE_CACHE_VALUE_NAME, 7807 info->WriteCacheEnableOverride); 7808 } 7809 7810 fdoExtension->PrivateFdoData->HotplugInfo.DeviceHotplug = info->DeviceHotplug; 7811 7812 // 7813 // Store the user-defined override in the registry 7814 // 7815 7816 ClassSetDeviceParameter(fdoExtension, 7817 CLASSP_REG_SUBKEY_NAME, 7818 CLASSP_REG_REMOVAL_POLICY_VALUE_NAME, 7819 (info->DeviceHotplug) ? RemovalPolicyExpectSurpriseRemoval : RemovalPolicyExpectOrderlyRemoval); 7820 } 7821 7822 Irp->IoStatus.Status = status; 7823 7824 ClassReleaseRemoveLock(DeviceObject, Irp); 7825 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 7826 } 7827 7828 break; 7829 } 7830 7831 case IOCTL_STORAGE_CHECK_VERIFY: 7832 case IOCTL_STORAGE_CHECK_VERIFY2: { 7833 7834 PIRP irp2 = NULL; 7835 PIO_STACK_LOCATION newStack; 7836 7837 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = NULL; 7838 7839 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DeviceIoControl: Check verify\n")); 7840 7841 // 7842 // If a buffer for a media change count was provided, make sure it's 7843 // big enough to hold the result 7844 // 7845 7846 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength) { 7847 7848 // 7849 // If the buffer is too small to hold the media change count 7850 // then return an error to the caller 7851 // 7852 7853 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 7854 sizeof(ULONG)) { 7855 7856 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, "DeviceIoControl: media count " 7857 "buffer too small\n")); 7858 7859 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL; 7860 Irp->IoStatus.Information = sizeof(ULONG); 7861 7862 FREE_POOL(srb); 7863 7864 ClassReleaseRemoveLock(DeviceObject, Irp); 7865 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 7866 7867 status = STATUS_BUFFER_TOO_SMALL; 7868 goto SetStatusAndReturn; 7869 } 7870 } 7871 7872 if (!commonExtension->IsFdo) { 7873 7874 7875 // 7876 // If this is a PDO then we should just forward the request down 7877 // 7878 NT_ASSERT(!srb); 7879 7880 IoCopyCurrentIrpStackLocationToNext(Irp); 7881 7882 ClassReleaseRemoveLock(DeviceObject, Irp); 7883 7884 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 7885 7886 goto SetStatusAndReturn; 7887 7888 } else { 7889 7890 fdoExtension = DeviceObject->DeviceExtension; 7891 7892 } 7893 7894 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength) { 7895 7896 // 7897 // The caller has provided a valid buffer. Allocate an additional 7898 // irp and stick the CheckVerify completion routine on it. We will 7899 // then send this down to the port driver instead of the irp the 7900 // caller sent in 7901 // 7902 7903 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DeviceIoControl: Check verify wants " 7904 "media count\n")); 7905 7906 // 7907 // Allocate a new irp to send the TestUnitReady to the port driver 7908 // 7909 7910 irp2 = IoAllocateIrp((CCHAR) (DeviceObject->StackSize + 3), FALSE); 7911 7912 if (irp2 == NULL) { 7913 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 7914 Irp->IoStatus.Information = 0; 7915 FREE_POOL(srb); 7916 ClassReleaseRemoveLock(DeviceObject, Irp); 7917 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 7918 status = STATUS_INSUFFICIENT_RESOURCES; 7919 goto SetStatusAndReturn; 7920 7921 break; 7922 } 7923 7924 // 7925 // Make sure to acquire the lock for the new irp. 7926 // 7927 7928 ClassAcquireRemoveLock(DeviceObject, irp2); 7929 7930 irp2->Tail.Overlay.Thread = Irp->Tail.Overlay.Thread; 7931 IoSetNextIrpStackLocation(irp2); 7932 7933 // 7934 // Set the top stack location and shove the master Irp into the 7935 // top location 7936 // 7937 7938 newStack = IoGetCurrentIrpStackLocation(irp2); 7939 newStack->Parameters.Others.Argument1 = Irp; 7940 newStack->DeviceObject = DeviceObject; 7941 7942 // 7943 // Stick the check verify completion routine onto the stack 7944 // and prepare the irp for the port driver 7945 // 7946 7947 IoSetCompletionRoutine(irp2, 7948 ClassCheckVerifyComplete, 7949 NULL, 7950 TRUE, 7951 TRUE, 7952 TRUE); 7953 7954 IoSetNextIrpStackLocation(irp2); 7955 newStack = IoGetCurrentIrpStackLocation(irp2); 7956 newStack->DeviceObject = DeviceObject; 7957 newStack->MajorFunction = irpStack->MajorFunction; 7958 newStack->MinorFunction = irpStack->MinorFunction; 7959 newStack->Flags = irpStack->Flags; 7960 7961 7962 // 7963 // Mark the master irp as pending - whether the lower level 7964 // driver completes it immediately or not this should allow it 7965 // to go all the way back up. 7966 // 7967 7968 IoMarkIrpPending(Irp); 7969 7970 Irp = irp2; 7971 7972 } 7973 7974 // 7975 // Test Unit Ready 7976 // 7977 7978 SrbSetCdbLength(srb, 6); 7979 cdb = SrbGetCdb(srb); 7980 cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY; 7981 7982 // 7983 // Set timeout value. 7984 // 7985 7986 SrbSetTimeOutValue(srb, fdoExtension->TimeOutValue); 7987 7988 // 7989 // If this was a CV2 then mark the request as low-priority so we don't 7990 // spin up the drive just to satisfy it. 7991 // 7992 7993 if (controlCode == IOCTL_STORAGE_CHECK_VERIFY2) { 7994 SrbSetSrbFlags(srb, SRB_CLASS_FLAGS_LOW_PRIORITY); 7995 } 7996 7997 // 7998 // Since this routine will always hand the request to the 7999 // port driver if there isn't a data transfer to be done 8000 // we don't have to worry about completing the request here 8001 // on an error 8002 // 8003 8004 // 8005 // This routine uses a completion routine so we don't want to release 8006 // the remove lock until then. 8007 // 8008 8009 status = ClassSendSrbAsynchronous(DeviceObject, 8010 srb, 8011 Irp, 8012 NULL, 8013 0, 8014 FALSE); 8015 8016 break; 8017 } 8018 8019 case IOCTL_STORAGE_MEDIA_REMOVAL: 8020 case IOCTL_STORAGE_EJECTION_CONTROL: { 8021 8022 PPREVENT_MEDIA_REMOVAL mediaRemoval = Irp->AssociatedIrp.SystemBuffer; 8023 8024 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoControl: ejection control\n")); 8025 8026 FREE_POOL(srb); 8027 8028 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < 8029 sizeof(PREVENT_MEDIA_REMOVAL)) { 8030 8031 // 8032 // Indicate unsuccessful status and no data transferred. 8033 // 8034 8035 Irp->IoStatus.Status = STATUS_INFO_LENGTH_MISMATCH; 8036 8037 ClassReleaseRemoveLock(DeviceObject, Irp); 8038 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 8039 status = STATUS_INFO_LENGTH_MISMATCH; 8040 goto SetStatusAndReturn; 8041 } 8042 8043 if (!commonExtension->IsFdo) { 8044 8045 8046 // 8047 // Just forward this down and return 8048 // 8049 8050 IoCopyCurrentIrpStackLocationToNext(Irp); 8051 8052 ClassReleaseRemoveLock(DeviceObject, Irp); 8053 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 8054 } 8055 else { 8056 8057 // i don't believe this assertion is valid. this is a request 8058 // from user-mode, so they could request this for any device 8059 // they want? also, we handle it properly. 8060 // NT_ASSERT(TEST_FLAG(DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA)); 8061 status = ClasspEjectionControl( 8062 DeviceObject, 8063 Irp, 8064 ((modifiedIoControlCode == 8065 IOCTL_STORAGE_EJECTION_CONTROL) ? SecureMediaLock : 8066 SimpleMediaLock), 8067 mediaRemoval->PreventMediaRemoval); 8068 8069 Irp->IoStatus.Status = status; 8070 ClassReleaseRemoveLock(DeviceObject, Irp); 8071 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 8072 } 8073 8074 break; 8075 } 8076 8077 case IOCTL_STORAGE_MCN_CONTROL: { 8078 8079 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoControl: MCN control\n")); 8080 8081 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < 8082 sizeof(PREVENT_MEDIA_REMOVAL)) { 8083 8084 // 8085 // Indicate unsuccessful status and no data transferred. 8086 // 8087 8088 Irp->IoStatus.Status = STATUS_INFO_LENGTH_MISMATCH; 8089 Irp->IoStatus.Information = 0; 8090 8091 FREE_POOL(srb); 8092 8093 ClassReleaseRemoveLock(DeviceObject, Irp); 8094 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 8095 status = STATUS_INFO_LENGTH_MISMATCH; 8096 goto SetStatusAndReturn; 8097 } 8098 8099 if (!commonExtension->IsFdo) { 8100 8101 8102 // 8103 // Just forward this down and return 8104 // 8105 8106 FREE_POOL(srb); 8107 8108 IoCopyCurrentIrpStackLocationToNext(Irp); 8109 8110 ClassReleaseRemoveLock(DeviceObject, Irp); 8111 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 8112 8113 } else { 8114 8115 // 8116 // Call to the FDO - handle the ejection control. 8117 // 8118 8119 status = ClasspMcnControl(DeviceObject->DeviceExtension, 8120 Irp, 8121 srb); 8122 } 8123 goto SetStatusAndReturn; 8124 } 8125 8126 case IOCTL_STORAGE_RESERVE: 8127 case IOCTL_STORAGE_RELEASE: { 8128 8129 // 8130 // Reserve logical unit. 8131 // 8132 8133 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = NULL; 8134 8135 if (!commonExtension->IsFdo) { 8136 8137 8138 IoCopyCurrentIrpStackLocationToNext(Irp); 8139 8140 ClassReleaseRemoveLock(DeviceObject, Irp); 8141 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 8142 goto SetStatusAndReturn; 8143 8144 } else { 8145 fdoExtension = DeviceObject->DeviceExtension; 8146 } 8147 8148 if (TEST_FLAG(fdoExtension->PrivateFdoData->HackFlags, FDO_HACK_NO_RESERVE6)) 8149 { 8150 SrbSetCdbLength(srb, 10); 8151 cdb = SrbGetCdb(srb); 8152 cdb->CDB10.OperationCode = (modifiedIoControlCode == IOCTL_STORAGE_RESERVE) ? SCSIOP_RESERVE_UNIT10 : SCSIOP_RELEASE_UNIT10; 8153 } 8154 else 8155 { 8156 SrbSetCdbLength(srb, 6); 8157 cdb = SrbGetCdb(srb); 8158 cdb->CDB6GENERIC.OperationCode = (modifiedIoControlCode == IOCTL_STORAGE_RESERVE) ? SCSIOP_RESERVE_UNIT : SCSIOP_RELEASE_UNIT; 8159 } 8160 8161 // 8162 // Set timeout value. 8163 // 8164 8165 SrbSetTimeOutValue(srb, fdoExtension->TimeOutValue); 8166 8167 // 8168 // Send reserves as tagged requests. 8169 // 8170 8171 if ( IOCTL_STORAGE_RESERVE == modifiedIoControlCode ) { 8172 SrbSetSrbFlags(srb, SRB_FLAGS_QUEUE_ACTION_ENABLE); 8173 SrbSetRequestAttribute(srb, SRB_SIMPLE_TAG_REQUEST); 8174 } 8175 8176 status = ClassSendSrbAsynchronous(DeviceObject, 8177 srb, 8178 Irp, 8179 NULL, 8180 0, 8181 FALSE); 8182 8183 break; 8184 } 8185 8186 case IOCTL_STORAGE_PERSISTENT_RESERVE_IN: 8187 case IOCTL_STORAGE_PERSISTENT_RESERVE_OUT: { 8188 8189 if (!commonExtension->IsFdo) { 8190 8191 IoCopyCurrentIrpStackLocationToNext(Irp); 8192 8193 ClassReleaseRemoveLock(DeviceObject, Irp); 8194 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 8195 goto SetStatusAndReturn; 8196 } 8197 8198 // 8199 // Process Persistent Reserve 8200 // 8201 8202 status = ClasspPersistentReserve(DeviceObject, Irp, srb); 8203 8204 break; 8205 8206 } 8207 8208 case IOCTL_STORAGE_EJECT_MEDIA: 8209 case IOCTL_STORAGE_LOAD_MEDIA: 8210 case IOCTL_STORAGE_LOAD_MEDIA2:{ 8211 8212 // 8213 // Eject media. 8214 // 8215 8216 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = NULL; 8217 8218 if (!commonExtension->IsFdo) { 8219 8220 8221 IoCopyCurrentIrpStackLocationToNext(Irp); 8222 8223 ClassReleaseRemoveLock(DeviceObject, Irp); 8224 8225 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 8226 goto SetStatusAndReturn; 8227 } else { 8228 fdoExtension = DeviceObject->DeviceExtension; 8229 } 8230 8231 if (commonExtension->PagingPathCount != 0) { 8232 8233 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, "ClassDeviceControl: call to eject paging device - " 8234 "failure\n")); 8235 8236 status = STATUS_FILES_OPEN; 8237 Irp->IoStatus.Status = status; 8238 8239 Irp->IoStatus.Information = 0; 8240 8241 FREE_POOL(srb); 8242 8243 ClassReleaseRemoveLock(DeviceObject, Irp); 8244 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 8245 goto SetStatusAndReturn; 8246 } 8247 8248 // 8249 // Synchronize with ejection control and ejection cleanup code as 8250 // well as other eject/load requests. 8251 // 8252 8253 KeEnterCriticalRegion(); 8254 (VOID)KeWaitForSingleObject(&(fdoExtension->EjectSynchronizationEvent), 8255 UserRequest, 8256 KernelMode, 8257 FALSE, 8258 NULL); 8259 8260 if (fdoExtension->ProtectedLockCount != 0) { 8261 8262 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, "ClassDeviceControl: call to eject protected locked " 8263 "device - failure\n")); 8264 8265 status = STATUS_DEVICE_BUSY; 8266 Irp->IoStatus.Status = status; 8267 Irp->IoStatus.Information = 0; 8268 8269 FREE_POOL(srb); 8270 8271 ClassReleaseRemoveLock(DeviceObject, Irp); 8272 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 8273 8274 KeSetEvent(&fdoExtension->EjectSynchronizationEvent, 8275 IO_NO_INCREMENT, 8276 FALSE); 8277 KeLeaveCriticalRegion(); 8278 8279 goto SetStatusAndReturn; 8280 } 8281 8282 SrbSetCdbLength(srb, 6); 8283 cdb = SrbGetCdb(srb); 8284 8285 cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT; 8286 cdb->START_STOP.LoadEject = 1; 8287 8288 if (modifiedIoControlCode == IOCTL_STORAGE_EJECT_MEDIA) { 8289 cdb->START_STOP.Start = 0; 8290 } else { 8291 cdb->START_STOP.Start = 1; 8292 } 8293 8294 // 8295 // Set timeout value. 8296 // 8297 8298 SrbSetTimeOutValue(srb, fdoExtension->TimeOutValue); 8299 status = ClassSendSrbAsynchronous(DeviceObject, 8300 srb, 8301 Irp, 8302 NULL, 8303 0, 8304 FALSE); 8305 8306 KeSetEvent(&fdoExtension->EjectSynchronizationEvent, IO_NO_INCREMENT, FALSE); 8307 KeLeaveCriticalRegion(); 8308 8309 break; 8310 } 8311 8312 case IOCTL_STORAGE_FIND_NEW_DEVICES: { 8313 8314 FREE_POOL(srb); 8315 8316 if (commonExtension->IsFdo) { 8317 8318 IoInvalidateDeviceRelations( 8319 ((PFUNCTIONAL_DEVICE_EXTENSION) commonExtension)->LowerPdo, 8320 BusRelations); 8321 8322 status = STATUS_SUCCESS; 8323 Irp->IoStatus.Status = status; 8324 8325 ClassReleaseRemoveLock(DeviceObject, Irp); 8326 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 8327 } 8328 else { 8329 8330 8331 IoCopyCurrentIrpStackLocationToNext(Irp); 8332 8333 ClassReleaseRemoveLock(DeviceObject, Irp); 8334 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 8335 } 8336 break; 8337 } 8338 8339 case IOCTL_STORAGE_GET_DEVICE_NUMBER: { 8340 8341 FREE_POOL(srb); 8342 8343 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength >= 8344 sizeof(STORAGE_DEVICE_NUMBER)) { 8345 8346 PSTORAGE_DEVICE_NUMBER deviceNumber = 8347 Irp->AssociatedIrp.SystemBuffer; 8348 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = 8349 commonExtension->PartitionZeroExtension; 8350 8351 deviceNumber->DeviceType = fdoExtension->CommonExtension.DeviceObject->DeviceType; 8352 deviceNumber->DeviceNumber = fdoExtension->DeviceNumber; 8353 deviceNumber->PartitionNumber = commonExtension->PartitionNumber; 8354 8355 status = STATUS_SUCCESS; 8356 Irp->IoStatus.Information = sizeof(STORAGE_DEVICE_NUMBER); 8357 8358 } else { 8359 status = STATUS_BUFFER_TOO_SMALL; 8360 Irp->IoStatus.Information = sizeof(STORAGE_DEVICE_NUMBER); 8361 } 8362 8363 Irp->IoStatus.Status = status; 8364 ClassReleaseRemoveLock(DeviceObject, Irp); 8365 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 8366 8367 break; 8368 } 8369 8370 8371 case IOCTL_STORAGE_READ_CAPACITY: { 8372 8373 FREE_POOL(srb); 8374 8375 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 8376 sizeof(STORAGE_READ_CAPACITY)) { 8377 8378 // 8379 // Indicate unsuccessful status and no data transferred. 8380 // 8381 8382 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL; 8383 Irp->IoStatus.Information = sizeof(STORAGE_READ_CAPACITY); 8384 8385 ClassReleaseRemoveLock(DeviceObject, Irp); 8386 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 8387 status = STATUS_BUFFER_TOO_SMALL; 8388 break; 8389 } 8390 8391 if (!commonExtension->IsFdo) { 8392 8393 8394 // 8395 // Just forward this down and return 8396 // 8397 8398 IoCopyCurrentIrpStackLocationToNext(Irp); 8399 8400 ClassReleaseRemoveLock(DeviceObject, Irp); 8401 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 8402 } 8403 else { 8404 8405 PFUNCTIONAL_DEVICE_EXTENSION fdoExt = DeviceObject->DeviceExtension; 8406 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData; 8407 PSTORAGE_READ_CAPACITY readCapacity = Irp->AssociatedIrp.SystemBuffer; 8408 LARGE_INTEGER diskLength; 8409 8410 status = ClassReadDriveCapacity(DeviceObject); 8411 if (NT_SUCCESS(status) && fdoData->IsCachedDriveCapDataValid) { 8412 8413 readCapacity->Version = sizeof(STORAGE_READ_CAPACITY); 8414 readCapacity->Size = sizeof(STORAGE_READ_CAPACITY); 8415 8416 REVERSE_BYTES(&readCapacity->BlockLength, 8417 &fdoData->LastKnownDriveCapacityData.BytesPerBlock); 8418 REVERSE_BYTES_QUAD(&readCapacity->NumberOfBlocks, 8419 &fdoData->LastKnownDriveCapacityData.LogicalBlockAddress); 8420 readCapacity->NumberOfBlocks.QuadPart++; 8421 8422 readCapacity->DiskLength = fdoExt->CommonExtension.PartitionLength; 8423 8424 // 8425 // Make sure the lengths are equal. 8426 // Remove this after testing. 8427 // 8428 diskLength.QuadPart = readCapacity->NumberOfBlocks.QuadPart * 8429 readCapacity->BlockLength; 8430 8431 Irp->IoStatus.Status = STATUS_SUCCESS; 8432 Irp->IoStatus.Information = sizeof(STORAGE_READ_CAPACITY); 8433 8434 } else { 8435 // 8436 // Read capacity request failed. 8437 // 8438 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, "ClassDeviceControl: ClassReadDriveCapacity failed: 0x%X IsCachedDriveCapDataValid: %d\n", 8439 status, fdoData->IsCachedDriveCapDataValid)); 8440 Irp->IoStatus.Status = status; 8441 Irp->IoStatus.Information = 0; 8442 } 8443 ClassReleaseRemoveLock(DeviceObject, Irp); 8444 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 8445 } 8446 8447 break; 8448 } 8449 8450 case IOCTL_STORAGE_QUERY_PROPERTY: { 8451 8452 PSTORAGE_PROPERTY_QUERY query = Irp->AssociatedIrp.SystemBuffer; 8453 8454 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(STORAGE_PROPERTY_QUERY)) { 8455 8456 status = STATUS_INFO_LENGTH_MISMATCH; 8457 Irp->IoStatus.Status = status; 8458 ClassReleaseRemoveLock(DeviceObject, Irp); 8459 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 8460 FREE_POOL(srb); 8461 break; 8462 } 8463 8464 if (!commonExtension->IsFdo) { 8465 8466 8467 IoCopyCurrentIrpStackLocationToNext(Irp); 8468 8469 ClassReleaseRemoveLock(DeviceObject, Irp); 8470 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 8471 FREE_POOL(srb); 8472 break; 8473 } 8474 8475 // 8476 // Determine PropertyId type and either call appropriate routine 8477 // or pass request to lower drivers. 8478 // 8479 8480 switch ( query->PropertyId ) { 8481 8482 case StorageDeviceUniqueIdProperty: { 8483 8484 status = ClasspDuidQueryProperty(DeviceObject, Irp); 8485 break; 8486 } 8487 8488 case StorageDeviceWriteCacheProperty: { 8489 8490 status = ClasspWriteCacheProperty(DeviceObject, Irp, srb); 8491 break; 8492 } 8493 8494 // these propertyId has been implemented in some port driver and filter drivers. 8495 // to keep the backwards compatibility, classpnp will send the request down if it's supported by lower layer. 8496 // otherwise, classpnp sends SCSI command and then interprets the result. 8497 case StorageAccessAlignmentProperty: { 8498 8499 status = ClasspAccessAlignmentProperty(DeviceObject, Irp, srb); 8500 break; 8501 } 8502 8503 case StorageDeviceSeekPenaltyProperty: { 8504 8505 status = ClasspDeviceSeekPenaltyProperty(DeviceObject, Irp, srb); 8506 break; 8507 } 8508 8509 case StorageDeviceTrimProperty: { 8510 8511 status = ClasspDeviceTrimProperty(DeviceObject, Irp, srb); 8512 break; 8513 } 8514 8515 case StorageDeviceLBProvisioningProperty: { 8516 8517 status = ClasspDeviceLBProvisioningProperty(DeviceObject, Irp, srb); 8518 break; 8519 } 8520 8521 case StorageDeviceCopyOffloadProperty: { 8522 8523 status = ClasspDeviceCopyOffloadProperty(DeviceObject, Irp, srb); 8524 break; 8525 } 8526 8527 case StorageDeviceMediumProductType: { 8528 8529 status = ClasspDeviceMediaTypeProperty(DeviceObject, Irp, srb); 8530 break; 8531 } 8532 8533 default: { 8534 8535 // 8536 // Copy the Irp stack parameters to the next stack location. 8537 // 8538 8539 IoCopyCurrentIrpStackLocationToNext(Irp); 8540 8541 ClassReleaseRemoveLock(DeviceObject, Irp); 8542 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 8543 break; 8544 } 8545 } // end switch 8546 8547 FREE_POOL(srb); 8548 break; 8549 } 8550 8551 case IOCTL_STORAGE_CHECK_PRIORITY_HINT_SUPPORT: { 8552 8553 FREE_POOL(srb); 8554 8555 if (!commonExtension->IsFdo) { 8556 8557 8558 IoCopyCurrentIrpStackLocationToNext(Irp); 8559 8560 ClassReleaseRemoveLock(DeviceObject, Irp); 8561 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 8562 break; 8563 } 8564 8565 // 8566 // Process priority hit request 8567 // 8568 8569 status = ClasspPriorityHint(DeviceObject, Irp); 8570 break; 8571 } 8572 8573 case IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES: { 8574 8575 PDEVICE_MANAGE_DATA_SET_ATTRIBUTES dsmAttributes = Irp->AssociatedIrp.SystemBuffer; 8576 8577 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(DEVICE_MANAGE_DATA_SET_ATTRIBUTES)) { 8578 8579 status = STATUS_INVALID_PARAMETER; 8580 Irp->IoStatus.Status = status; 8581 ClassReleaseRemoveLock(DeviceObject, Irp); 8582 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 8583 FREE_POOL(srb); 8584 break; 8585 } 8586 8587 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < 8588 (sizeof(DEVICE_MANAGE_DATA_SET_ATTRIBUTES) + dsmAttributes->ParameterBlockLength + dsmAttributes->DataSetRangesLength)) { 8589 8590 status = STATUS_INVALID_PARAMETER; 8591 Irp->IoStatus.Status = status; 8592 ClassReleaseRemoveLock(DeviceObject, Irp); 8593 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 8594 FREE_POOL(srb); 8595 break; 8596 } 8597 8598 if (!commonExtension->IsFdo) { 8599 8600 8601 IoCopyCurrentIrpStackLocationToNext(Irp); 8602 8603 ClassReleaseRemoveLock(DeviceObject, Irp); 8604 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 8605 FREE_POOL(srb); 8606 break; 8607 } 8608 8609 switch(dsmAttributes->Action) { 8610 8611 // only process Trim action in class layer if possible. 8612 case DeviceDsmAction_Trim: { 8613 status = ClasspDeviceTrimProcess(DeviceObject, Irp, &activityId, srb); 8614 break; 8615 } 8616 8617 case DeviceDsmAction_OffloadRead: { 8618 status = ClassDeviceProcessOffloadRead(DeviceObject, Irp, srb); 8619 break; 8620 } 8621 8622 case DeviceDsmAction_OffloadWrite: { 8623 status = ClassDeviceProcessOffloadWrite(DeviceObject, Irp, srb); 8624 break; 8625 } 8626 8627 case DeviceDsmAction_Allocation: { 8628 status = ClasspDeviceGetLBAStatus(DeviceObject, Irp, srb); 8629 break; 8630 } 8631 8632 8633 default: { 8634 8635 8636 // 8637 // Copy the Irp stack parameters to the next stack location. 8638 // 8639 8640 IoCopyCurrentIrpStackLocationToNext(Irp); 8641 8642 ClassReleaseRemoveLock(DeviceObject, Irp); 8643 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 8644 break; 8645 } 8646 } // end switch 8647 8648 FREE_POOL(srb); 8649 break; 8650 } 8651 8652 case IOCTL_STORAGE_GET_LB_PROVISIONING_MAP_RESOURCES: { 8653 8654 if (commonExtension->IsFdo) { 8655 8656 status = ClassDeviceGetLBProvisioningResources(DeviceObject, Irp, srb); 8657 8658 } else { 8659 8660 IoCopyCurrentIrpStackLocationToNext(Irp); 8661 8662 ClassReleaseRemoveLock(DeviceObject, Irp); 8663 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 8664 } 8665 8666 FREE_POOL(srb); 8667 8668 break; 8669 } 8670 8671 case IOCTL_STORAGE_EVENT_NOTIFICATION: { 8672 8673 FREE_POOL(srb); 8674 8675 status = ClasspStorageEventNotification(DeviceObject, Irp); 8676 break; 8677 } 8678 8679 #if (NTDDI_VERSION >= NTDDI_WINTRHESHOLD) 8680 case IOCTL_STORAGE_FIRMWARE_GET_INFO: { 8681 FREE_POOL(srb); 8682 8683 status = ClassDeviceHwFirmwareGetInfoProcess(DeviceObject, Irp); 8684 break; 8685 } 8686 8687 case IOCTL_STORAGE_FIRMWARE_DOWNLOAD: { 8688 if (!commonExtension->IsFdo) { 8689 8690 IoCopyCurrentIrpStackLocationToNext(Irp); 8691 8692 ClassReleaseRemoveLock(DeviceObject, Irp); 8693 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 8694 goto SetStatusAndReturn; 8695 } 8696 8697 status = ClassDeviceHwFirmwareDownloadProcess(DeviceObject, Irp, srb); 8698 break; 8699 } 8700 8701 case IOCTL_STORAGE_FIRMWARE_ACTIVATE: { 8702 if (!commonExtension->IsFdo) { 8703 8704 IoCopyCurrentIrpStackLocationToNext(Irp); 8705 8706 ClassReleaseRemoveLock(DeviceObject, Irp); 8707 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 8708 goto SetStatusAndReturn; 8709 } 8710 8711 status = ClassDeviceHwFirmwareActivateProcess(DeviceObject, Irp, srb); 8712 break; 8713 } 8714 #endif 8715 8716 8717 default: { 8718 8719 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "IoDeviceControl: Unsupported device IOCTL %x for %p\n", 8720 controlCode, DeviceObject)); 8721 8722 8723 // 8724 // Pass the device control to the next driver. 8725 // 8726 8727 FREE_POOL(srb); 8728 8729 // 8730 // Copy the Irp stack parameters to the next stack location. 8731 // 8732 8733 IoCopyCurrentIrpStackLocationToNext(Irp); 8734 8735 ClassReleaseRemoveLock(DeviceObject, Irp); 8736 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 8737 break; 8738 } 8739 8740 } // end switch( ... 8741 8742 SetStatusAndReturn: 8743 8744 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "< ioctl %xh (%s): status %xh.", modifiedIoControlCode, DBGGETIOCTLSTR(modifiedIoControlCode), status)); 8745 8746 return status; 8747 } // end ClassDeviceControl() 8748 8749 /*++//////////////////////////////////////////////////////////////////////////// 8750 8751 ClassShutdownFlush() 8752 8753 Routine Description: 8754 8755 This routine is called for a shutdown and flush IRPs. These are sent by the 8756 system before it actually shuts down or when the file system does a flush. 8757 If it exists, the device-specific driver's routine will be invoked. If there 8758 wasn't one specified, the Irp will be completed with an Invalid device request. 8759 8760 Arguments: 8761 8762 DriverObject - Pointer to device object to being shutdown by system. 8763 8764 Irp - IRP involved. 8765 8766 Return Value: 8767 8768 NT Status 8769 8770 --*/ 8771 NTSTATUS 8772 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 8773 ClassShutdownFlush( 8774 IN PDEVICE_OBJECT DeviceObject, 8775 IN PIRP Irp 8776 ) 8777 { 8778 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 8779 8780 ULONG isRemoved; 8781 8782 isRemoved = ClassAcquireRemoveLock(DeviceObject, Irp); 8783 _Analysis_assume_(isRemoved); 8784 if(isRemoved) { 8785 8786 ClassReleaseRemoveLock(DeviceObject, Irp); 8787 8788 Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST; 8789 8790 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 8791 8792 return STATUS_DEVICE_DOES_NOT_EXIST; 8793 } 8794 8795 if (commonExtension->DevInfo->ClassShutdownFlush) { 8796 8797 // 8798 // Call the device-specific driver's routine. 8799 // 8800 8801 return commonExtension->DevInfo->ClassShutdownFlush(DeviceObject, Irp); 8802 } 8803 8804 // 8805 // Device-specific driver doesn't support this. 8806 // 8807 8808 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; 8809 8810 ClassReleaseRemoveLock(DeviceObject, Irp); 8811 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 8812 8813 return STATUS_INVALID_DEVICE_REQUEST; 8814 } // end ClassShutdownFlush() 8815 8816 /*++//////////////////////////////////////////////////////////////////////////// 8817 8818 ClasspIsPortable() 8819 8820 Routine Description: 8821 8822 This routine is called during start device to determine whether the PDO 8823 for a stack reports itself as portable. 8824 8825 Arguments: 8826 8827 FdoExtension - Pointer to FDO whose PDO we check for portability. 8828 8829 IsPortable - Boolean pointer in which to store result. 8830 8831 Return Value: 8832 8833 NT Status 8834 8835 --*/ 8836 NTSTATUS 8837 ClasspIsPortable( 8838 _In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, 8839 _Out_ PBOOLEAN IsPortable 8840 ) 8841 { 8842 DEVPROP_BOOLEAN isInternal = DEVPROP_FALSE; 8843 BOOLEAN isPortable = FALSE; 8844 ULONG size = 0; 8845 NTSTATUS status = STATUS_SUCCESS; 8846 DEVPROPTYPE type = DEVPROP_TYPE_EMPTY; 8847 8848 PAGED_CODE(); 8849 8850 *IsPortable = FALSE; 8851 8852 // 8853 // Check to see if the underlying device 8854 // object is in local machine container 8855 // 8856 8857 status = IoGetDevicePropertyData(FdoExtension->LowerPdo, 8858 &DEVPKEY_Device_InLocalMachineContainer, 8859 0, 8860 0, 8861 sizeof(isInternal), 8862 &isInternal, 8863 &size, 8864 &type); 8865 8866 if (!NT_SUCCESS(status)) { 8867 goto cleanup; 8868 } 8869 8870 NT_ASSERT(size == sizeof(isInternal)); 8871 NT_ASSERT(type == DEVPROP_TYPE_BOOLEAN); 8872 8873 // 8874 // Volume is hot-pluggable if the disk pdo 8875 // container id differs from that of root device 8876 // 8877 8878 if (isInternal == DEVPROP_TRUE) { 8879 goto cleanup; 8880 } 8881 8882 isPortable = TRUE; 8883 8884 // 8885 // Examine the bus type to ensure 8886 // that this really is a fixed disk 8887 // 8888 8889 if (FdoExtension->DeviceDescriptor->BusType == BusTypeFibre || 8890 FdoExtension->DeviceDescriptor->BusType == BusTypeiScsi || 8891 FdoExtension->DeviceDescriptor->BusType == BusTypeRAID) { 8892 8893 isPortable = FALSE; 8894 } 8895 8896 *IsPortable = isPortable; 8897 8898 cleanup: 8899 8900 return status; 8901 } 8902 8903 /*++//////////////////////////////////////////////////////////////////////////// 8904 8905 ClassCreateDeviceObject() 8906 8907 Routine Description: 8908 8909 This routine creates an object for the physical device specified and 8910 sets up the deviceExtension's function pointers for each entry point 8911 in the device-specific driver. 8912 8913 Arguments: 8914 8915 DriverObject - Pointer to driver object created by system. 8916 8917 ObjectNameBuffer - Dir. name of the object to create. 8918 8919 LowerDeviceObject - Pointer to the lower device object 8920 8921 IsFdo - should this be an fdo or a pdo 8922 8923 DeviceObject - Pointer to the device object pointer we will return. 8924 8925 Return Value: 8926 8927 NTSTATUS 8928 8929 --*/ 8930 8931 _IRQL_requires_max_(PASSIVE_LEVEL) 8932 _Must_inspect_result_ 8933 _Post_satisfies_(return <= 0) 8934 SCSIPORT_API 8935 NTSTATUS 8936 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 8937 ClassCreateDeviceObject( 8938 _In_ PDRIVER_OBJECT DriverObject, 8939 _In_z_ PCCHAR ObjectNameBuffer, 8940 _In_ PDEVICE_OBJECT LowerDevice, 8941 _In_ BOOLEAN IsFdo, 8942 _Outptr_result_nullonfailure_ 8943 _At_(*DeviceObject, __drv_allocatesMem(Mem) __drv_aliasesMem) 8944 PDEVICE_OBJECT *DeviceObject 8945 ) 8946 { 8947 BOOLEAN isPartitionable; 8948 STRING ntNameString; 8949 UNICODE_STRING ntUnicodeString; 8950 NTSTATUS status; 8951 PDEVICE_OBJECT deviceObject = NULL; 8952 8953 ULONG characteristics; 8954 SIZE_T rundownSize = ExSizeOfRundownProtectionCacheAware(); 8955 PCHAR rundownAddr = NULL; 8956 ULONG devExtSize; 8957 8958 #ifdef _MSC_VER 8959 #pragma warning(suppress:4054) // okay to type cast function pointer as data pointer for this use case 8960 #endif 8961 PCLASS_DRIVER_EXTENSION driverExtension = IoGetDriverObjectExtension(DriverObject, CLASS_DRIVER_EXTENSION_KEY); 8962 8963 PCLASS_DEV_INFO devInfo; 8964 8965 PAGED_CODE(); 8966 8967 _Analysis_assume_(driverExtension != NULL); 8968 8969 *DeviceObject = NULL; 8970 RtlInitUnicodeString(&ntUnicodeString, NULL); 8971 8972 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, "ClassCreateFdo: Create device object\n")); 8973 8974 NT_ASSERT(LowerDevice); 8975 8976 // 8977 // Make sure that if we're making PDO's we have an enumeration routine 8978 // 8979 8980 isPartitionable = (driverExtension->InitData.ClassEnumerateDevice != NULL); 8981 8982 NT_ASSERT(IsFdo || isPartitionable); 8983 8984 // 8985 // Grab the correct dev-info structure out of the init data 8986 // 8987 8988 if (IsFdo) { 8989 devInfo = &(driverExtension->InitData.FdoData); 8990 } else { 8991 devInfo = &(driverExtension->InitData.PdoData); 8992 } 8993 8994 characteristics = devInfo->DeviceCharacteristics; 8995 8996 if (ARGUMENT_PRESENT(ObjectNameBuffer)) { 8997 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, "ClassCreateFdo: Name is %s\n", ObjectNameBuffer)); 8998 8999 RtlInitString(&ntNameString, ObjectNameBuffer); 9000 9001 status = RtlAnsiStringToUnicodeString(&ntUnicodeString, &ntNameString, TRUE); 9002 9003 if (!NT_SUCCESS(status)) { 9004 9005 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, 9006 "ClassCreateFdo: Cannot convert string %s\n", 9007 ObjectNameBuffer)); 9008 9009 ntUnicodeString.Buffer = NULL; 9010 return status; 9011 } 9012 } else { 9013 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, "ClassCreateFdo: Object will be unnamed\n")); 9014 9015 if (IsFdo == FALSE) { 9016 9017 // 9018 // PDO's have to have some sort of name. 9019 // 9020 9021 SET_FLAG(characteristics, FILE_AUTOGENERATED_DEVICE_NAME); 9022 } 9023 9024 RtlInitUnicodeString(&ntUnicodeString, NULL); 9025 } 9026 9027 devExtSize = devInfo->DeviceExtensionSize + 9028 (ULONG)sizeof(CLASS_PRIVATE_COMMON_DATA) + (ULONG)rundownSize; 9029 status = IoCreateDevice(DriverObject, 9030 devExtSize, 9031 &ntUnicodeString, 9032 devInfo->DeviceType, 9033 characteristics, 9034 FALSE, 9035 &deviceObject); 9036 9037 if (!NT_SUCCESS(status)) { 9038 9039 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT, "ClassCreateFdo: Can not create device object %lx\n", 9040 status)); 9041 NT_ASSERT(deviceObject == NULL); 9042 9043 // 9044 // buffer is not used any longer here. 9045 // 9046 9047 if (ntUnicodeString.Buffer != NULL) { 9048 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, "ClassCreateFdo: Freeing unicode name buffer\n")); 9049 FREE_POOL(ntUnicodeString.Buffer); 9050 RtlInitUnicodeString(&ntUnicodeString, NULL); 9051 } 9052 9053 } else { 9054 9055 PCOMMON_DEVICE_EXTENSION commonExtension = deviceObject->DeviceExtension; 9056 9057 RtlZeroMemory( 9058 deviceObject->DeviceExtension, 9059 devExtSize); 9060 9061 // 9062 // Setup version code 9063 // 9064 9065 commonExtension->Version = 0x03; 9066 9067 // 9068 // Setup the remove lock and event 9069 // 9070 9071 commonExtension->IsRemoved = NO_REMOVE; 9072 9073 #if DBG 9074 9075 commonExtension->RemoveLock = 0; 9076 9077 #endif 9078 9079 KeInitializeEvent(&commonExtension->RemoveEvent, 9080 SynchronizationEvent, 9081 FALSE); 9082 9083 9084 ClasspInitializeRemoveTracking(deviceObject); 9085 9086 // 9087 // Initialize the PrivateCommonData 9088 // 9089 9090 commonExtension->PrivateCommonData = (PCLASS_PRIVATE_COMMON_DATA) 9091 ((PCHAR)deviceObject->DeviceExtension + devInfo->DeviceExtensionSize); 9092 rundownAddr = (PCHAR)commonExtension->PrivateCommonData + sizeof(CLASS_PRIVATE_COMMON_DATA); 9093 ExInitializeRundownProtectionCacheAware((PEX_RUNDOWN_REF_CACHE_AWARE)rundownAddr, rundownSize); 9094 commonExtension->PrivateCommonData->RemoveLockFailAcquire = 0; 9095 9096 // 9097 // Acquire the lock once. This reference will be released when the 9098 // remove IRP has been received. 9099 // 9100 9101 ClassAcquireRemoveLock(deviceObject, (PIRP) deviceObject); 9102 9103 // 9104 // Store a pointer to the driver extension so we don't have to do 9105 // lookups to get it. 9106 // 9107 9108 commonExtension->DriverExtension = driverExtension; 9109 9110 // 9111 // Fill in entry points 9112 // 9113 9114 commonExtension->DevInfo = devInfo; 9115 9116 // 9117 // Initialize some of the common values in the structure 9118 // 9119 9120 commonExtension->DeviceObject = deviceObject; 9121 9122 commonExtension->LowerDeviceObject = NULL; 9123 9124 commonExtension->DispatchTable = driverExtension->DeviceMajorFunctionTable; 9125 9126 if(IsFdo) { 9127 9128 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = (PVOID) commonExtension; 9129 9130 commonExtension->PartitionZeroExtension = deviceObject->DeviceExtension; 9131 9132 // 9133 // Set the initial device object flags. 9134 // 9135 9136 SET_FLAG(deviceObject->Flags, DO_POWER_PAGABLE); 9137 // 9138 // Clear the PDO list 9139 // 9140 9141 commonExtension->ChildList = NULL; 9142 9143 commonExtension->DriverData = 9144 ((PFUNCTIONAL_DEVICE_EXTENSION) deviceObject->DeviceExtension + 1); 9145 9146 // 9147 // The disk class driver creates only FDO. The partition number 9148 // for the FDO must be 0. 9149 // 9150 9151 if ((isPartitionable == TRUE) || 9152 (devInfo->DeviceType == FILE_DEVICE_DISK)) { 9153 9154 commonExtension->PartitionNumber = 0; 9155 } else { 9156 commonExtension->PartitionNumber = (ULONG) (-1L); 9157 } 9158 9159 fdoExtension->DevicePowerState = PowerDeviceD0; 9160 9161 KeInitializeEvent(&fdoExtension->EjectSynchronizationEvent, 9162 SynchronizationEvent, 9163 TRUE); 9164 9165 KeInitializeEvent(&fdoExtension->ChildLock, 9166 SynchronizationEvent, 9167 TRUE); 9168 9169 status = ClasspAllocateReleaseRequest(deviceObject); 9170 9171 if(!NT_SUCCESS(status)) { 9172 IoDeleteDevice(deviceObject); 9173 *DeviceObject = NULL; 9174 9175 if (ntUnicodeString.Buffer != NULL) { 9176 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, "ClassCreateFdo: Freeing unicode name buffer\n")); 9177 FREE_POOL(ntUnicodeString.Buffer); 9178 RtlInitUnicodeString(&ntUnicodeString, NULL); 9179 } 9180 9181 return status; 9182 } 9183 9184 } else { 9185 9186 PPHYSICAL_DEVICE_EXTENSION pdoExtension = 9187 deviceObject->DeviceExtension; 9188 9189 PFUNCTIONAL_DEVICE_EXTENSION p0Extension = 9190 LowerDevice->DeviceExtension; 9191 9192 SET_FLAG(deviceObject->Flags, DO_POWER_PAGABLE); 9193 9194 commonExtension->PartitionZeroExtension = p0Extension; 9195 9196 // 9197 // Stick this onto the PDO list 9198 // 9199 9200 ClassAddChild(p0Extension, pdoExtension, TRUE); 9201 9202 commonExtension->DriverData = (PVOID) (pdoExtension + 1); 9203 9204 // 9205 // Get the top of stack for the lower device - this allows 9206 // filters to get stuck in between the partitions and the 9207 // physical disk. 9208 // 9209 9210 commonExtension->LowerDeviceObject = 9211 IoGetAttachedDeviceReference(LowerDevice); 9212 9213 // 9214 // Pnp will keep a reference to the lower device object long 9215 // after this partition has been deleted. Dereference now so 9216 // we don't have to deal with it later. 9217 // 9218 9219 ObDereferenceObject(commonExtension->LowerDeviceObject); 9220 } 9221 9222 KeInitializeEvent(&commonExtension->PathCountEvent, SynchronizationEvent, TRUE); 9223 9224 commonExtension->IsFdo = IsFdo; 9225 9226 commonExtension->DeviceName = ntUnicodeString; 9227 9228 commonExtension->PreviousState = 0xff; 9229 9230 InitializeDictionary(&(commonExtension->FileObjectDictionary)); 9231 9232 commonExtension->CurrentState = IRP_MN_STOP_DEVICE; 9233 9234 if (commonExtension->DriverExtension->InitData.ClassStartIo) { 9235 IoSetStartIoAttributes(deviceObject, TRUE, TRUE); 9236 } 9237 } 9238 9239 *DeviceObject = deviceObject; 9240 9241 return status; 9242 } // end ClassCreateDeviceObject() 9243 9244 /*++//////////////////////////////////////////////////////////////////////////// 9245 9246 ClassClaimDevice() 9247 9248 Routine Description: 9249 9250 This function claims a device in the port driver. The port driver object 9251 is updated with the correct driver object if the device is successfully 9252 claimed. 9253 9254 Arguments: 9255 9256 LowerDeviceObject - Supplies the base port device object. 9257 9258 Release - Indicates the logical unit should be released rather than claimed. 9259 9260 Return Value: 9261 9262 Returns a status indicating success or failure of the operation. 9263 9264 --*/ 9265 _IRQL_requires_max_(PASSIVE_LEVEL) 9266 NTSTATUS 9267 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 9268 ClassClaimDevice( 9269 _In_ PDEVICE_OBJECT LowerDeviceObject, 9270 _In_ BOOLEAN Release 9271 ) 9272 { 9273 IO_STATUS_BLOCK ioStatus; 9274 PIRP irp; 9275 PIO_STACK_LOCATION irpStack; 9276 KEVENT event; 9277 NTSTATUS status; 9278 SCSI_REQUEST_BLOCK srb = {0}; 9279 9280 PAGED_CODE(); 9281 9282 // 9283 // WORK ITEM - MPIO related. Need to think about how to handle. 9284 // 9285 9286 srb.Length = sizeof(SCSI_REQUEST_BLOCK); 9287 9288 srb.Function = Release ? SRB_FUNCTION_RELEASE_DEVICE : 9289 SRB_FUNCTION_CLAIM_DEVICE; 9290 9291 // 9292 // Set the event object to the unsignaled state. 9293 // It will be used to signal request completion 9294 // 9295 9296 KeInitializeEvent(&event, SynchronizationEvent, FALSE); 9297 9298 // 9299 // Build synchronous request with no transfer. 9300 // 9301 9302 irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_NONE, 9303 LowerDeviceObject, 9304 NULL, 9305 0, 9306 NULL, 9307 0, 9308 TRUE, 9309 &event, 9310 &ioStatus); 9311 9312 if (irp == NULL) { 9313 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, "ClassClaimDevice: Can't allocate Irp\n")); 9314 return STATUS_INSUFFICIENT_RESOURCES; 9315 } 9316 9317 irpStack = IoGetNextIrpStackLocation(irp); 9318 9319 // 9320 // Save SRB address in next stack for port driver. 9321 // 9322 9323 irpStack->Parameters.Scsi.Srb = &srb; 9324 9325 // 9326 // Set up IRP Address. 9327 // 9328 9329 srb.OriginalRequest = irp; 9330 9331 // 9332 // Call the port driver with the request and wait for it to complete. 9333 // 9334 9335 status = IoCallDriver(LowerDeviceObject, irp); 9336 if (status == STATUS_PENDING) { 9337 9338 (VOID)KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); 9339 status = ioStatus.Status; 9340 } 9341 9342 // 9343 // If this is a release request, then just decrement the reference count 9344 // and return. The status does not matter. 9345 // 9346 9347 if (Release) { 9348 9349 // ObDereferenceObject(LowerDeviceObject); 9350 return STATUS_SUCCESS; 9351 } 9352 9353 if (!NT_SUCCESS(status)) { 9354 return status; 9355 } 9356 9357 NT_ASSERT(srb.DataBuffer != NULL); 9358 NT_ASSERT(!TEST_FLAG(srb.SrbFlags, SRB_FLAGS_FREE_SENSE_BUFFER)); 9359 9360 return status; 9361 } // end ClassClaimDevice() 9362 9363 /*++//////////////////////////////////////////////////////////////////////////// 9364 9365 ClassInternalIoControl() 9366 9367 Routine Description: 9368 9369 This routine passes internal device controls to the port driver. 9370 Internal device controls are used by higher level drivers both for ioctls 9371 and to pass through scsi requests. 9372 9373 If the IoControlCode does not match any of the handled ioctls and is 9374 a valid system address then the request will be treated as an SRB and 9375 passed down to the lower driver. If the IoControlCode is not a valid 9376 system address the ioctl will be failed. 9377 9378 Callers must therefore be extremely cautious to pass correct, initialized 9379 values to this function. 9380 9381 Arguments: 9382 9383 DeviceObject - Supplies a pointer to the device object for this request. 9384 9385 Irp - Supplies the Irp making the request. 9386 9387 Return Value: 9388 9389 Returns back a STATUS_PENDING or a completion status. 9390 9391 --*/ 9392 NTSTATUS 9393 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 9394 ClassInternalIoControl( 9395 IN PDEVICE_OBJECT DeviceObject, 9396 IN PIRP Irp 9397 ) 9398 { 9399 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 9400 9401 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); 9402 PIO_STACK_LOCATION nextStack = IoGetNextIrpStackLocation(Irp); 9403 9404 ULONG isRemoved; 9405 9406 PSCSI_REQUEST_BLOCK srb; 9407 9408 isRemoved = ClassAcquireRemoveLock(DeviceObject, Irp); 9409 _Analysis_assume_(isRemoved); 9410 if(isRemoved) { 9411 9412 Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST; 9413 9414 ClassReleaseRemoveLock(DeviceObject, Irp); 9415 9416 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 9417 9418 return STATUS_DEVICE_DOES_NOT_EXIST; 9419 } 9420 9421 // 9422 // Get a pointer to the SRB. 9423 // 9424 9425 srb = irpStack->Parameters.Scsi.Srb; 9426 9427 // 9428 // Set the parameters in the next stack location. 9429 // 9430 9431 if(commonExtension->IsFdo) { 9432 nextStack->Parameters.Scsi.Srb = srb; 9433 nextStack->MajorFunction = IRP_MJ_SCSI; 9434 nextStack->MinorFunction = IRP_MN_SCSI_CLASS; 9435 9436 } else { 9437 9438 IoCopyCurrentIrpStackLocationToNext(Irp); 9439 } 9440 9441 ClassReleaseRemoveLock(DeviceObject, Irp); 9442 9443 return IoCallDriver(commonExtension->LowerDeviceObject, Irp); 9444 } // end ClassInternalIoControl() 9445 9446 /*++//////////////////////////////////////////////////////////////////////////// 9447 9448 ClassQueryTimeOutRegistryValue() 9449 9450 Routine Description: 9451 9452 This routine determines whether a reg key for a user-specified timeout 9453 value exists. This should be called at initialization time. 9454 9455 Arguments: 9456 9457 DeviceObject - Pointer to the device object we are retrieving the timeout 9458 value for 9459 9460 Return Value: 9461 9462 None, but it sets a new default timeout for a class of devices. 9463 9464 --*/ 9465 _IRQL_requires_max_(PASSIVE_LEVEL) 9466 ULONG 9467 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 9468 ClassQueryTimeOutRegistryValue( 9469 _In_ PDEVICE_OBJECT DeviceObject 9470 ) 9471 { 9472 // 9473 // Find the appropriate reg. key 9474 // 9475 9476 #ifdef _MSC_VER 9477 #pragma warning(suppress:4054) // okay to type cast function pointer as data pointer for this use case 9478 #endif 9479 PCLASS_DRIVER_EXTENSION driverExtension = IoGetDriverObjectExtension(DeviceObject->DriverObject, CLASS_DRIVER_EXTENSION_KEY); 9480 9481 PUNICODE_STRING registryPath = &(driverExtension->RegistryPath); 9482 9483 PRTL_QUERY_REGISTRY_TABLE parameters = NULL; 9484 PWSTR path; 9485 NTSTATUS status; 9486 LONG timeOut = 0; 9487 ULONG zero = 0; 9488 ULONG size; 9489 9490 PAGED_CODE(); 9491 9492 if (!registryPath) { 9493 return 0; 9494 } 9495 9496 parameters = ExAllocatePoolWithTag(NonPagedPoolNx, 9497 sizeof(RTL_QUERY_REGISTRY_TABLE)*2, 9498 '1BcS'); 9499 9500 if (!parameters) { 9501 return 0; 9502 } 9503 9504 size = registryPath->MaximumLength + sizeof(WCHAR); 9505 path = ExAllocatePoolWithTag(NonPagedPoolNx, size, '2BcS'); 9506 9507 if (!path) { 9508 FREE_POOL(parameters); 9509 return 0; 9510 } 9511 9512 RtlZeroMemory(path,size); 9513 RtlCopyMemory(path, registryPath->Buffer, size - sizeof(WCHAR)); 9514 9515 9516 // 9517 // Check for the Timeout value. 9518 // 9519 9520 RtlZeroMemory(parameters, 9521 (sizeof(RTL_QUERY_REGISTRY_TABLE)*2)); 9522 9523 parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_TYPECHECK; 9524 parameters[0].Name = L"TimeOutValue"; 9525 parameters[0].EntryContext = &timeOut; 9526 parameters[0].DefaultType = (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_DWORD; 9527 parameters[0].DefaultData = &zero; 9528 parameters[0].DefaultLength = sizeof(ULONG); 9529 9530 status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL, 9531 path, 9532 parameters, 9533 NULL, 9534 NULL); 9535 9536 if (!(NT_SUCCESS(status))) { 9537 timeOut = 0; 9538 } 9539 9540 FREE_POOL(parameters); 9541 FREE_POOL(path); 9542 9543 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, 9544 "ClassQueryTimeOutRegistryValue: Timeout value %d\n", 9545 timeOut)); 9546 9547 9548 return timeOut; 9549 9550 } // end ClassQueryTimeOutRegistryValue() 9551 9552 9553 /*++//////////////////////////////////////////////////////////////////////////// 9554 9555 ClassCheckVerifyComplete() ISSUE-2000/02/18-henrygab - why public?! 9556 9557 Routine Description: 9558 9559 This routine executes when the port driver has completed a check verify 9560 ioctl. It will set the status of the master Irp, copy the media change 9561 count and complete the request. 9562 9563 Arguments: 9564 9565 Fdo - Supplies the functional device object which represents the logical unit. 9566 9567 Irp - Supplies the Irp which has completed. 9568 9569 Context - NULL 9570 9571 Return Value: 9572 9573 NT status 9574 9575 --*/ 9576 NTSTATUS 9577 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 9578 ClassCheckVerifyComplete( 9579 IN PDEVICE_OBJECT Fdo, 9580 IN PIRP Irp, 9581 IN PVOID Context 9582 ) 9583 { 9584 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); 9585 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; 9586 9587 PIRP originalIrp; 9588 9589 UNREFERENCED_PARAMETER(Context); 9590 9591 ASSERT_FDO(Fdo); 9592 9593 originalIrp = irpStack->Parameters.Others.Argument1; 9594 9595 // 9596 // Copy the media change count and status 9597 // 9598 9599 *((PULONG) (originalIrp->AssociatedIrp.SystemBuffer)) = 9600 fdoExtension->MediaChangeCount; 9601 9602 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "ClassCheckVerifyComplete - Media change count for" 9603 "device %d is %lx - saved as %lx\n", 9604 fdoExtension->DeviceNumber, 9605 fdoExtension->MediaChangeCount, 9606 *((PULONG) originalIrp->AssociatedIrp.SystemBuffer))); 9607 9608 originalIrp->IoStatus.Status = Irp->IoStatus.Status; 9609 originalIrp->IoStatus.Information = sizeof(ULONG); 9610 9611 ClassReleaseRemoveLock(Fdo, originalIrp); 9612 ClassCompleteRequest(Fdo, originalIrp, IO_DISK_INCREMENT); 9613 9614 IoFreeIrp(Irp); 9615 9616 return STATUS_MORE_PROCESSING_REQUIRED; 9617 9618 } // end ClassCheckVerifyComplete() 9619 9620 9621 /*++//////////////////////////////////////////////////////////////////////////// 9622 9623 ClassGetDescriptor() 9624 9625 Routine Description: 9626 9627 This routine will perform a query for the specified property id and will 9628 allocate a non-paged buffer to store the data in. It is the responsibility 9629 of the caller to ensure that this buffer is freed. 9630 9631 This routine must be run at IRQL_PASSIVE_LEVEL 9632 9633 Arguments: 9634 9635 DeviceObject - the device to query 9636 DeviceInfo - a location to store a pointer to the buffer we allocate 9637 9638 Return Value: 9639 9640 status 9641 if status is unsuccessful *DeviceInfo will be set to NULL, else the 9642 buffer allocated on behalf of the caller. 9643 9644 --*/ 9645 _IRQL_requires_max_(PASSIVE_LEVEL) 9646 NTSTATUS 9647 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 9648 ClassGetDescriptor( 9649 _In_ PDEVICE_OBJECT DeviceObject, 9650 _In_ PSTORAGE_PROPERTY_ID PropertyId, 9651 _Outptr_ PVOID *Descriptor 9652 ) 9653 { 9654 STORAGE_PROPERTY_QUERY query = {0}; 9655 IO_STATUS_BLOCK ioStatus; 9656 9657 PSTORAGE_DESCRIPTOR_HEADER descriptor = NULL; 9658 ULONG length; 9659 9660 PAGED_CODE(); 9661 9662 // 9663 // Set the passed-in descriptor pointer to NULL as default 9664 // 9665 9666 *Descriptor = NULL; 9667 9668 query.PropertyId = *PropertyId; 9669 query.QueryType = PropertyStandardQuery; 9670 9671 // 9672 // On the first pass we just want to get the first few 9673 // bytes of the descriptor so we can read it's size 9674 // 9675 9676 descriptor = (PVOID)&query; 9677 9678 NT_ASSERT(sizeof(STORAGE_PROPERTY_QUERY) >= (sizeof(ULONG)*2)); 9679 9680 ClassSendDeviceIoControlSynchronous( 9681 IOCTL_STORAGE_QUERY_PROPERTY, 9682 DeviceObject, 9683 &query, 9684 sizeof(STORAGE_PROPERTY_QUERY), 9685 sizeof(ULONG) * 2, 9686 FALSE, 9687 &ioStatus 9688 ); 9689 9690 if(!NT_SUCCESS(ioStatus.Status)) { 9691 9692 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT, "ClassGetDescriptor: error %lx trying to " 9693 "query properties #1\n", ioStatus.Status)); 9694 return ioStatus.Status; 9695 } 9696 9697 if (descriptor->Size == 0) { 9698 9699 // 9700 // This DebugPrint is to help third-party driver writers 9701 // 9702 9703 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT, "ClassGetDescriptor: size returned was zero?! (status " 9704 "%x\n", ioStatus.Status)); 9705 return STATUS_UNSUCCESSFUL; 9706 9707 } 9708 9709 // 9710 // This time we know how much data there is so we can 9711 // allocate a buffer of the correct size 9712 // 9713 9714 length = descriptor->Size; 9715 NT_ASSERT(length >= sizeof(STORAGE_PROPERTY_QUERY)); 9716 length = max(length, sizeof(STORAGE_PROPERTY_QUERY)); 9717 9718 descriptor = ExAllocatePoolWithTag(NonPagedPoolNx, length, '4BcS'); 9719 9720 if(descriptor == NULL) { 9721 9722 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT, "ClassGetDescriptor: unable to memory for descriptor " 9723 "(%d bytes)\n", length)); 9724 return STATUS_INSUFFICIENT_RESOURCES; 9725 } 9726 9727 // 9728 // setup the query again, as it was overwritten above 9729 // 9730 9731 RtlZeroMemory(&query, sizeof(STORAGE_PROPERTY_QUERY)); 9732 query.PropertyId = *PropertyId; 9733 query.QueryType = PropertyStandardQuery; 9734 9735 // 9736 // copy the input to the new outputbuffer 9737 // 9738 9739 RtlZeroMemory(descriptor, length); 9740 9741 RtlCopyMemory(descriptor, 9742 &query, 9743 sizeof(STORAGE_PROPERTY_QUERY) 9744 ); 9745 9746 ClassSendDeviceIoControlSynchronous( 9747 IOCTL_STORAGE_QUERY_PROPERTY, 9748 DeviceObject, 9749 descriptor, 9750 sizeof(STORAGE_PROPERTY_QUERY), 9751 length, 9752 FALSE, 9753 &ioStatus 9754 ); 9755 9756 if(!NT_SUCCESS(ioStatus.Status)) { 9757 9758 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT, "ClassGetDescriptor: error %lx trying to " 9759 "query properties #1\n", ioStatus.Status)); 9760 FREE_POOL(descriptor); 9761 return ioStatus.Status; 9762 } 9763 9764 // 9765 // return the memory we've allocated to the caller 9766 // 9767 9768 *Descriptor = descriptor; 9769 return ioStatus.Status; 9770 } // end ClassGetDescriptor() 9771 9772 9773 /*++//////////////////////////////////////////////////////////////////////////// 9774 9775 ClassSignalCompletion() 9776 9777 Routine Description: 9778 9779 This completion routine will signal the event given as context and then 9780 return STATUS_MORE_PROCESSING_REQUIRED to stop event completion. It is 9781 the responsibility of the routine waiting on the event to complete the 9782 request and free the event. 9783 9784 Arguments: 9785 9786 DeviceObject - a pointer to the device object 9787 9788 Irp - a pointer to the irp 9789 9790 Event - a pointer to the event to signal 9791 9792 Return Value: 9793 9794 STATUS_MORE_PROCESSING_REQUIRED 9795 9796 --*/ 9797 NTSTATUS 9798 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 9799 ClassSignalCompletion( 9800 IN PDEVICE_OBJECT DeviceObject, 9801 IN PIRP Irp, 9802 IN PVOID Context 9803 ) 9804 { 9805 PKEVENT Event = (PKEVENT)Context; 9806 9807 UNREFERENCED_PARAMETER(DeviceObject); 9808 UNREFERENCED_PARAMETER(Irp); 9809 9810 if (Context == NULL) { 9811 NT_ASSERT(Context != NULL); 9812 return STATUS_INVALID_PARAMETER; 9813 } 9814 9815 KeSetEvent(Event, IO_NO_INCREMENT, FALSE); 9816 9817 return STATUS_MORE_PROCESSING_REQUIRED; 9818 } // end ClassSignalCompletion() 9819 9820 /*++//////////////////////////////////////////////////////////////////////////// 9821 9822 ClassPnpQueryFdoRelations() 9823 9824 Routine Description: 9825 9826 This routine will call the driver's enumeration routine to update the 9827 list of PDO's. It will then build a response to the 9828 IRP_MN_QUERY_DEVICE_RELATIONS and place it into the information field in 9829 the irp. 9830 9831 Arguments: 9832 9833 Fdo - a pointer to the functional device object we are enumerating 9834 9835 Irp - a pointer to the enumeration request 9836 9837 Return Value: 9838 9839 status 9840 9841 --*/ 9842 NTSTATUS 9843 ClassPnpQueryFdoRelations( 9844 IN PDEVICE_OBJECT Fdo, 9845 IN PIRP Irp 9846 ) 9847 { 9848 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; 9849 #ifdef _MSC_VER 9850 #pragma warning(suppress:4054) // okay to type cast function pointer as data pointer for this use case 9851 #endif 9852 PCLASS_DRIVER_EXTENSION driverExtension = IoGetDriverObjectExtension(Fdo->DriverObject, CLASS_DRIVER_EXTENSION_KEY); 9853 9854 PAGED_CODE(); 9855 9856 _Analysis_assume_(driverExtension != NULL); 9857 9858 // 9859 // If there's already an enumeration in progress then don't start another 9860 // one. 9861 // 9862 9863 if(InterlockedIncrement((volatile LONG *)&(fdoExtension->EnumerationInterlock)) == 1) { 9864 driverExtension->InitData.ClassEnumerateDevice(Fdo); 9865 } 9866 9867 Irp->IoStatus.Status = ClassRetrieveDeviceRelations( 9868 Fdo, 9869 BusRelations, 9870 (PDEVICE_RELATIONS *) &Irp->IoStatus.Information); 9871 InterlockedDecrement((volatile LONG *)&(fdoExtension->EnumerationInterlock)); 9872 9873 return Irp->IoStatus.Status; 9874 } // end ClassPnpQueryFdoRelations() 9875 9876 /*++//////////////////////////////////////////////////////////////////////////// 9877 9878 ClassMarkChildrenMissing() 9879 9880 Routine Description: 9881 9882 This routine will call ClassMarkChildMissing() for all children. 9883 It acquires the ChildLock before calling ClassMarkChildMissing(). 9884 9885 Arguments: 9886 9887 Fdo - the "bus's" device object, such as the disk FDO for non-removable 9888 disks with multiple partitions. 9889 9890 Return Value: 9891 9892 None 9893 9894 --*/ 9895 _IRQL_requires_max_(PASSIVE_LEVEL) 9896 VOID 9897 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 9898 ClassMarkChildrenMissing( 9899 _In_ PFUNCTIONAL_DEVICE_EXTENSION Fdo 9900 ) 9901 { 9902 PCOMMON_DEVICE_EXTENSION commonExtension = &(Fdo->CommonExtension); 9903 PPHYSICAL_DEVICE_EXTENSION nextChild = commonExtension->ChildList; 9904 9905 PAGED_CODE(); 9906 9907 ClassAcquireChildLock(Fdo); 9908 9909 while (nextChild){ 9910 PPHYSICAL_DEVICE_EXTENSION tmpChild; 9911 9912 /* 9913 * ClassMarkChildMissing will also dequeue the child extension. 9914 * So get the next pointer before calling ClassMarkChildMissing. 9915 */ 9916 tmpChild = nextChild; 9917 nextChild = tmpChild->CommonExtension.ChildList; 9918 ClassMarkChildMissing(tmpChild, FALSE); 9919 } 9920 ClassReleaseChildLock(Fdo); 9921 return; 9922 } // end ClassMarkChildrenMissing() 9923 9924 /*++//////////////////////////////////////////////////////////////////////////// 9925 9926 ClassMarkChildMissing() 9927 9928 Routine Description: 9929 9930 This routine will make an active child "missing." If the device has never 9931 been enumerated then it will be deleted on the spot. If the device has 9932 not been enumerated then it will be marked as missing so that we can 9933 not report it in the next device enumeration. 9934 9935 Arguments: 9936 9937 Child - the child device to be marked as missing. 9938 9939 AcquireChildLock - TRUE if the child lock should be acquired before removing 9940 the missing child. FALSE if the child lock is already 9941 acquired by this thread. 9942 9943 Return Value: 9944 9945 returns whether or not the child device object has previously been reported 9946 to PNP. 9947 9948 --*/ 9949 _IRQL_requires_max_(PASSIVE_LEVEL) 9950 BOOLEAN 9951 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 9952 ClassMarkChildMissing( 9953 _In_ PPHYSICAL_DEVICE_EXTENSION Child, 9954 _In_ BOOLEAN AcquireChildLock 9955 ) 9956 { 9957 BOOLEAN returnValue = Child->IsEnumerated; 9958 9959 PAGED_CODE(); 9960 ASSERT_PDO(Child->DeviceObject); 9961 9962 Child->IsMissing = TRUE; 9963 9964 // 9965 // Make sure this child is not in the active list. 9966 // 9967 9968 ClassRemoveChild(Child->CommonExtension.PartitionZeroExtension, 9969 Child, 9970 AcquireChildLock); 9971 9972 if(Child->IsEnumerated == FALSE) { 9973 PCOMMON_DEVICE_EXTENSION commonExtension = Child->DeviceObject->DeviceExtension; 9974 commonExtension->IsRemoved = REMOVE_PENDING; 9975 ClassRemoveDevice(Child->DeviceObject, IRP_MN_REMOVE_DEVICE); 9976 } 9977 9978 return returnValue; 9979 } // end ClassMarkChildMissing() 9980 9981 /*++//////////////////////////////////////////////////////////////////////////// 9982 9983 ClassRetrieveDeviceRelations() 9984 9985 Routine Description: 9986 9987 This routine will allocate a buffer to hold the specified list of 9988 relations. It will then fill in the list with referenced device pointers 9989 and will return the request. 9990 9991 Arguments: 9992 9993 Fdo - pointer to the FDO being queried 9994 9995 RelationType - what type of relations are being queried 9996 9997 DeviceRelations - a location to store a pointer to the response 9998 9999 Return Value: 10000 10001 status 10002 10003 --*/ 10004 NTSTATUS 10005 ClassRetrieveDeviceRelations( 10006 IN PDEVICE_OBJECT Fdo, 10007 IN DEVICE_RELATION_TYPE RelationType, 10008 OUT PDEVICE_RELATIONS *DeviceRelations 10009 ) 10010 { 10011 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; 10012 10013 ULONG count = 0; 10014 ULONG i; 10015 10016 PPHYSICAL_DEVICE_EXTENSION nextChild; 10017 10018 ULONG relationsSize; 10019 PDEVICE_RELATIONS deviceRelations = NULL; 10020 PDEVICE_RELATIONS oldRelations = *DeviceRelations; 10021 10022 NTSTATUS status; 10023 10024 UNREFERENCED_PARAMETER(RelationType); 10025 10026 PAGED_CODE(); 10027 10028 ClassAcquireChildLock(fdoExtension); 10029 10030 nextChild = fdoExtension->CommonExtension.ChildList; 10031 10032 // 10033 // Count the number of PDO's attached to this disk 10034 // 10035 10036 while (nextChild != NULL) { 10037 PCOMMON_DEVICE_EXTENSION commonExtension; 10038 10039 commonExtension = &(nextChild->CommonExtension); 10040 10041 NT_ASSERTMSG("ClassPnp internal error: missing child on active list\n", 10042 (nextChild->IsMissing == FALSE)); 10043 10044 nextChild = commonExtension->ChildList; 10045 10046 count++; 10047 }; 10048 10049 // 10050 // If relations already exist in the QDR, adjust the current count 10051 // to include the previous list. 10052 // 10053 10054 if (oldRelations) { 10055 count += oldRelations->Count; 10056 } 10057 10058 relationsSize = (sizeof(DEVICE_RELATIONS) + 10059 (count * sizeof(PDEVICE_OBJECT))); 10060 10061 deviceRelations = ExAllocatePoolWithTag(PagedPool, relationsSize, '5BcS'); 10062 10063 if (deviceRelations == NULL) { 10064 10065 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_ENUM, "ClassRetrieveDeviceRelations: unable to allocate " 10066 "%d bytes for device relations\n", relationsSize)); 10067 10068 ClassReleaseChildLock(fdoExtension); 10069 10070 return STATUS_INSUFFICIENT_RESOURCES; 10071 } 10072 10073 RtlZeroMemory(deviceRelations, relationsSize); 10074 10075 if (oldRelations) { 10076 10077 // 10078 // Copy the old relations to the new list and free the old list. 10079 // 10080 10081 for (i = 0; i < oldRelations->Count; i++) { 10082 deviceRelations->Objects[i] = oldRelations->Objects[i]; 10083 } 10084 10085 FREE_POOL(oldRelations); 10086 } 10087 10088 nextChild = fdoExtension->CommonExtension.ChildList; 10089 i = count; 10090 10091 while (nextChild != NULL) { 10092 PCOMMON_DEVICE_EXTENSION commonExtension; 10093 10094 commonExtension = &(nextChild->CommonExtension); 10095 10096 NT_ASSERTMSG("ClassPnp internal error: missing child on active list\n", 10097 (nextChild->IsMissing == FALSE)); 10098 10099 _Analysis_assume_(i >= 1); 10100 deviceRelations->Objects[--i] = nextChild->DeviceObject; 10101 10102 status = ObReferenceObjectByPointer( 10103 nextChild->DeviceObject, 10104 0, 10105 NULL, 10106 KernelMode); 10107 if (!NT_SUCCESS(status)) { 10108 NT_ASSERT(!"Error referencing child device by pointer"); 10109 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_ENUM, 10110 "ClassRetrieveDeviceRelations: Error referencing child " 10111 "device %p by pointer\n", nextChild->DeviceObject)); 10112 10113 } 10114 nextChild->IsEnumerated = TRUE; 10115 nextChild = commonExtension->ChildList; 10116 } 10117 10118 NT_ASSERTMSG("Child list has changed: ", i == 0); 10119 10120 deviceRelations->Count = count; 10121 *DeviceRelations = deviceRelations; 10122 10123 ClassReleaseChildLock(fdoExtension); 10124 return STATUS_SUCCESS; 10125 } // end ClassRetrieveDeviceRelations() 10126 10127 /*++//////////////////////////////////////////////////////////////////////////// 10128 10129 ClassGetPdoId() 10130 10131 Routine Description: 10132 10133 This routine will call into the driver to retrieve a copy of one of it's 10134 id strings. 10135 10136 Arguments: 10137 10138 Pdo - a pointer to the pdo being queried 10139 10140 IdType - which type of id string is being queried 10141 10142 IdString - an allocated unicode string structure which the driver 10143 can fill in. 10144 10145 Return Value: 10146 10147 status 10148 10149 --*/ 10150 NTSTATUS 10151 ClassGetPdoId( 10152 IN PDEVICE_OBJECT Pdo, 10153 IN BUS_QUERY_ID_TYPE IdType, 10154 IN PUNICODE_STRING IdString 10155 ) 10156 { 10157 #ifdef _MSC_VER 10158 #pragma warning(suppress:4054) // okay to type cast function pointer as data pointer for this use case 10159 #endif 10160 PCLASS_DRIVER_EXTENSION driverExtension = IoGetDriverObjectExtension(Pdo->DriverObject, CLASS_DRIVER_EXTENSION_KEY); 10161 10162 _Analysis_assume_(driverExtension != NULL); 10163 10164 ASSERT_PDO(Pdo); 10165 NT_ASSERT(driverExtension->InitData.ClassQueryId); 10166 10167 PAGED_CODE(); 10168 10169 return driverExtension->InitData.ClassQueryId( Pdo, IdType, IdString); 10170 } // end ClassGetPdoId() 10171 10172 /*++//////////////////////////////////////////////////////////////////////////// 10173 10174 ClassQueryPnpCapabilities() 10175 10176 Routine Description: 10177 10178 This routine will call into the class driver to retrieve it's pnp 10179 capabilities. 10180 10181 Arguments: 10182 10183 PhysicalDeviceObject - The physical device object to retrieve properties 10184 for. 10185 10186 Return Value: 10187 10188 status 10189 10190 --*/ 10191 NTSTATUS 10192 ClassQueryPnpCapabilities( 10193 IN PDEVICE_OBJECT DeviceObject, 10194 IN PDEVICE_CAPABILITIES Capabilities 10195 ) 10196 { 10197 PCLASS_DRIVER_EXTENSION driverExtension = 10198 ClassGetDriverExtension(DeviceObject->DriverObject); 10199 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 10200 10201 PCLASS_QUERY_PNP_CAPABILITIES queryRoutine = NULL; 10202 10203 PAGED_CODE(); 10204 10205 NT_ASSERT(DeviceObject); 10206 NT_ASSERT(Capabilities); 10207 10208 if(commonExtension->IsFdo) { 10209 queryRoutine = driverExtension->InitData.FdoData.ClassQueryPnpCapabilities; 10210 } else { 10211 queryRoutine = driverExtension->InitData.PdoData.ClassQueryPnpCapabilities; 10212 } 10213 10214 if(queryRoutine) { 10215 return queryRoutine(DeviceObject, 10216 Capabilities); 10217 } else { 10218 return STATUS_NOT_IMPLEMENTED; 10219 } 10220 } // end ClassQueryPnpCapabilities() 10221 10222 /*++//////////////////////////////////////////////////////////////////////////// 10223 10224 ClassInvalidateBusRelations() 10225 10226 Routine Description: 10227 10228 This routine re-enumerates the devices on the "bus". It will call into 10229 the driver's ClassEnumerate routine to update the device objects 10230 immediately. It will then schedule a bus re-enumeration for pnp by calling 10231 IoInvalidateDeviceRelations. 10232 10233 Arguments: 10234 10235 Fdo - a pointer to the functional device object for this bus 10236 10237 Return Value: 10238 10239 none 10240 10241 --*/ 10242 _IRQL_requires_max_(PASSIVE_LEVEL) 10243 VOID 10244 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 10245 ClassInvalidateBusRelations( 10246 _In_ PDEVICE_OBJECT Fdo 10247 ) 10248 { 10249 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; 10250 #ifdef _MSC_VER 10251 #pragma warning(suppress:4054) // okay to type cast function pointer as data pointer for this use case 10252 #endif 10253 PCLASS_DRIVER_EXTENSION driverExtension = IoGetDriverObjectExtension(Fdo->DriverObject, CLASS_DRIVER_EXTENSION_KEY); 10254 10255 NTSTATUS status = STATUS_SUCCESS; 10256 10257 PAGED_CODE(); 10258 10259 _Analysis_assume_(driverExtension != NULL); 10260 10261 ASSERT_FDO(Fdo); 10262 NT_ASSERT(driverExtension->InitData.ClassEnumerateDevice != NULL); 10263 10264 if(InterlockedIncrement((volatile LONG *)&(fdoExtension->EnumerationInterlock)) == 1) { 10265 status = driverExtension->InitData.ClassEnumerateDevice(Fdo); 10266 } 10267 InterlockedDecrement((volatile LONG *)&(fdoExtension->EnumerationInterlock)); 10268 10269 if(!NT_SUCCESS(status)) { 10270 10271 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_ENUM, "ClassInvalidateBusRelations: EnumerateDevice routine " 10272 "returned %lx\n", status)); 10273 } 10274 10275 IoInvalidateDeviceRelations(fdoExtension->LowerPdo, BusRelations); 10276 10277 return; 10278 } // end ClassInvalidateBusRelations() 10279 10280 /*++//////////////////////////////////////////////////////////////////////////// 10281 10282 ClassRemoveDevice() ISSUE-2000/02/18-henrygab - why public?! 10283 10284 Routine Description: 10285 10286 This routine is called to handle the "removal" of a device. It will 10287 forward the request downwards if necesssary, call into the driver 10288 to release any necessary resources (memory, events, etc) and then 10289 will delete the device object. 10290 10291 Arguments: 10292 10293 DeviceObject - a pointer to the device object being removed 10294 10295 RemoveType - indicates what type of remove this is (regular or surprise). 10296 10297 Return Value: 10298 10299 status 10300 10301 --*/ 10302 _IRQL_requires_max_(PASSIVE_LEVEL) 10303 NTSTATUS 10304 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 10305 ClassRemoveDevice( 10306 _In_ PDEVICE_OBJECT DeviceObject, 10307 _In_ UCHAR RemoveType 10308 ) 10309 { 10310 #ifdef _MSC_VER 10311 #pragma warning(suppress:4054) // okay to type cast function pointer as data pointer for this use case 10312 #endif 10313 PCLASS_DRIVER_EXTENSION driverExtension = IoGetDriverObjectExtension(DeviceObject->DriverObject, CLASS_DRIVER_EXTENSION_KEY); 10314 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 10315 PDEVICE_OBJECT lowerDeviceObject = commonExtension->LowerDeviceObject; 10316 BOOLEAN proceedWithRemove = TRUE; 10317 NTSTATUS status; 10318 PEX_RUNDOWN_REF_CACHE_AWARE removeLockRundown = NULL; 10319 10320 10321 PAGED_CODE(); 10322 10323 _Analysis_assume_(driverExtension != NULL); 10324 10325 /* 10326 * Deregister from WMI. 10327 */ 10328 if (commonExtension->IsFdo || 10329 driverExtension->InitData.PdoData.ClassWmiInfo.GuidRegInfo) { 10330 status = IoWMIRegistrationControl(DeviceObject, WMIREG_ACTION_DEREGISTER); 10331 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "ClassRemoveDevice: IoWMIRegistrationControl(%p, WMI_ACTION_DEREGISTER) --> %lx", DeviceObject, status)); 10332 } 10333 10334 /* 10335 * If we exposed a "shingle" (a named device interface openable by CreateFile) 10336 * then delete it now. 10337 */ 10338 if (commonExtension->MountedDeviceInterfaceName.Buffer){ 10339 (VOID)IoSetDeviceInterfaceState(&commonExtension->MountedDeviceInterfaceName, FALSE); 10340 RtlFreeUnicodeString(&commonExtension->MountedDeviceInterfaceName); 10341 RtlInitUnicodeString(&commonExtension->MountedDeviceInterfaceName, NULL); 10342 } 10343 10344 // 10345 // If this is a surprise removal we leave the device around - which means 10346 // we don't have to (or want to) drop the remove lock and wait for pending 10347 // requests to complete. 10348 // 10349 10350 if (RemoveType == IRP_MN_REMOVE_DEVICE) { 10351 10352 // 10353 // Release the lock we acquired when the device object was created. 10354 // 10355 10356 ClassReleaseRemoveLock(DeviceObject, (PIRP) DeviceObject); 10357 10358 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP, "ClasspRemoveDevice - Reference count is now %d\n", 10359 commonExtension->RemoveLock)); 10360 10361 // 10362 // The RemoveLockRundown allows fast protection of the device object 10363 // structure that is torn down by a single thread. While in the rundown process (the call to 10364 // ExWaitForRundownProtectionReleaseCacheAware returns), the rundown object becomes 10365 // invalid and the subsequent calls to ExAcquireRundownProtectionCacheAware will return FALSE. 10366 // ExReInitializeRundownProtectionCacheAware needs to be called to re-initialize the 10367 // RemoveLockRundown protection. 10368 // 10369 10370 removeLockRundown = (PEX_RUNDOWN_REF_CACHE_AWARE) 10371 ((PCHAR)commonExtension->PrivateCommonData + 10372 sizeof(CLASS_PRIVATE_COMMON_DATA)); 10373 ExWaitForRundownProtectionReleaseCacheAware(removeLockRundown); 10374 10375 KeSetEvent(&commonExtension->RemoveEvent, 10376 IO_NO_INCREMENT, 10377 FALSE); 10378 10379 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP, "ClasspRemoveDevice - removing device %p\n", DeviceObject)); 10380 10381 if (commonExtension->IsFdo) { 10382 10383 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP, "ClasspRemoveDevice - FDO %p has received a " 10384 "remove request.\n", DeviceObject)); 10385 10386 } else { 10387 PPHYSICAL_DEVICE_EXTENSION pdoExtension = DeviceObject->DeviceExtension; 10388 10389 if (pdoExtension->IsMissing) { 10390 /* 10391 * The child partition PDO is missing, so we are going to go ahead 10392 * and delete it for the remove. 10393 */ 10394 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP, "ClasspRemoveDevice - PDO %p is missing and will be removed", DeviceObject)); 10395 } else { 10396 /* 10397 * We got a remove for a child partition PDO which is not actually missing. 10398 * So we will NOT actually delete it. 10399 */ 10400 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP, "ClasspRemoveDevice - PDO %p still exists and will be removed when it disappears", DeviceObject)); 10401 10402 ExReInitializeRundownProtectionCacheAware(removeLockRundown); 10403 10404 // 10405 // Reacquire the remove lock for the next time this comes around. 10406 // 10407 10408 ClassAcquireRemoveLock(DeviceObject, (PIRP) DeviceObject); 10409 10410 // 10411 // the device wasn't missing so it's not really been removed. 10412 // 10413 10414 commonExtension->IsRemoved = NO_REMOVE; 10415 10416 IoInvalidateDeviceRelations( 10417 commonExtension->PartitionZeroExtension->LowerPdo, 10418 BusRelations); 10419 10420 proceedWithRemove = FALSE; 10421 } 10422 } 10423 } 10424 10425 10426 if (proceedWithRemove) { 10427 10428 /* 10429 * Call the class driver's remove handler. 10430 * All this is supposed to do is clean up its data and device interfaces. 10431 */ 10432 NT_ASSERT(commonExtension->DevInfo->ClassRemoveDevice); 10433 status = commonExtension->DevInfo->ClassRemoveDevice(DeviceObject, RemoveType); 10434 NT_ASSERT(NT_SUCCESS(status)); 10435 status = STATUS_SUCCESS; 10436 UNREFERENCED_PARAMETER(status); // disables prefast warning; defensive coding... 10437 10438 if (commonExtension->IsFdo) { 10439 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; 10440 10441 ClasspDisableTimer(fdoExtension); 10442 10443 if (RemoveType == IRP_MN_REMOVE_DEVICE) { 10444 10445 PPHYSICAL_DEVICE_EXTENSION child; 10446 10447 // 10448 // If this FDO is idle power managed, remove it from the 10449 // list of idle power managed FDOs. 10450 // 10451 if (fdoExtension->FunctionSupportInfo && 10452 fdoExtension->FunctionSupportInfo->IdlePower.IdlePowerEnabled) { 10453 PIDLE_POWER_FDO_LIST_ENTRY fdoEntry; 10454 10455 KeAcquireGuardedMutex(&IdlePowerFDOListMutex); 10456 fdoEntry = (PIDLE_POWER_FDO_LIST_ENTRY)IdlePowerFDOList.Flink; 10457 while ((PLIST_ENTRY)fdoEntry != &IdlePowerFDOList) { 10458 PIDLE_POWER_FDO_LIST_ENTRY nextEntry = (PIDLE_POWER_FDO_LIST_ENTRY)fdoEntry->ListEntry.Flink; 10459 if (fdoEntry->Fdo == DeviceObject) { 10460 RemoveEntryList(&(fdoEntry->ListEntry)); 10461 ExFreePool(fdoEntry); 10462 break; 10463 } 10464 fdoEntry = nextEntry; 10465 } 10466 KeReleaseGuardedMutex(&IdlePowerFDOListMutex); 10467 } 10468 10469 // 10470 // Cleanup the media detection resources now that the class driver 10471 // has stopped it's timer (if any) and we can be sure they won't 10472 // call us to do detection again. 10473 // 10474 10475 ClassCleanupMediaChangeDetection(fdoExtension); 10476 10477 // 10478 // Cleanup any Failure Prediction stuff 10479 // 10480 FREE_POOL(fdoExtension->FailurePredictionInfo); 10481 10482 /* 10483 * Ordinarily all child PDOs will be removed by the time 10484 * that the parent gets the REMOVE_DEVICE. 10485 * However, if a child PDO has been created but has not 10486 * been announced in a QueryDeviceRelations, then it is 10487 * just a private data structure unknown to pnp, and we have 10488 * to delete it ourselves. 10489 */ 10490 ClassAcquireChildLock(fdoExtension); 10491 child = ClassRemoveChild(fdoExtension, NULL, FALSE); 10492 while (child) { 10493 PCOMMON_DEVICE_EXTENSION childCommonExtension = child->DeviceObject->DeviceExtension; 10494 10495 // 10496 // Yank the pdo. This routine will unlink the device from the 10497 // pdo list so NextPdo will point to the next one when it's 10498 // complete. 10499 // 10500 child->IsMissing = TRUE; 10501 childCommonExtension->IsRemoved = REMOVE_PENDING; 10502 ClassRemoveDevice(child->DeviceObject, IRP_MN_REMOVE_DEVICE); 10503 child = ClassRemoveChild(fdoExtension, NULL, FALSE); 10504 } 10505 ClassReleaseChildLock(fdoExtension); 10506 } 10507 else if (RemoveType == IRP_MN_SURPRISE_REMOVAL){ 10508 /* 10509 * This is a surprise-remove on the parent FDO. 10510 * We will mark the child PDOs as missing so that they 10511 * will actually get deleted when they get a REMOVE_DEVICE. 10512 */ 10513 ClassMarkChildrenMissing(fdoExtension); 10514 } 10515 10516 if (RemoveType == IRP_MN_REMOVE_DEVICE) { 10517 10518 ClasspFreeReleaseRequest(DeviceObject); 10519 10520 // 10521 // Free FDO-specific data structs 10522 // 10523 if (fdoExtension->PrivateFdoData) { 10524 // 10525 // Only remove the entry if the list has been initialized, or 10526 // else we will access invalid memory. 10527 // 10528 PLIST_ENTRY allFdosListEntry = &fdoExtension->PrivateFdoData->AllFdosListEntry; 10529 if (allFdosListEntry->Flink && allFdosListEntry->Blink) { 10530 // 10531 // Remove the FDO from the static list. 10532 // Pnp is synchronized so this shouldn't need any synchronization. 10533 // 10534 RemoveEntryList(allFdosListEntry); 10535 } 10536 InitializeListHead(allFdosListEntry); 10537 10538 DestroyAllTransferPackets(DeviceObject); 10539 10540 // 10541 // Delete the tick timer now. 10542 // 10543 ClasspDeleteTimer(fdoExtension); 10544 10545 10546 FREE_POOL(fdoExtension->PrivateFdoData->PowerProcessIrp); 10547 FREE_POOL(fdoExtension->PrivateFdoData->FreeTransferPacketsLists); 10548 FREE_POOL(fdoExtension->PrivateFdoData); 10549 } 10550 10551 #if (NTDDI_VERSION >= NTDDI_WINTHRESHOLD) 10552 FREE_POOL(fdoExtension->AdditionalFdoData); 10553 #endif 10554 10555 if (commonExtension->DeviceName.Buffer) { 10556 FREE_POOL(commonExtension->DeviceName.Buffer); 10557 RtlInitUnicodeString(&commonExtension->DeviceName, NULL); 10558 } 10559 10560 #if (NTDDI_VERSION >= NTDDI_WINTHRESHOLD) 10561 if (fdoExtension->FunctionSupportInfo != NULL) { 10562 FREE_POOL(fdoExtension->FunctionSupportInfo->HwFirmwareInfo); 10563 } 10564 #endif 10565 FREE_POOL(fdoExtension->FunctionSupportInfo); 10566 10567 FREE_POOL(fdoExtension->MiniportDescriptor); 10568 10569 FREE_POOL(fdoExtension->AdapterDescriptor); 10570 10571 FREE_POOL(fdoExtension->DeviceDescriptor); 10572 10573 // 10574 // Detach our device object from the stack - there's no reason 10575 // to hold off our cleanup any longer. 10576 // 10577 10578 IoDetachDevice(lowerDeviceObject); 10579 } 10580 } 10581 else { 10582 /* 10583 * This is a child partition PDO. 10584 * We have already determined that it was previously marked 10585 * as missing. So if this is a REMOVE_DEVICE, we will actually 10586 * delete it. 10587 */ 10588 if (RemoveType == IRP_MN_REMOVE_DEVICE) { 10589 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = commonExtension->PartitionZeroExtension; 10590 PPHYSICAL_DEVICE_EXTENSION pdoExtension = (PPHYSICAL_DEVICE_EXTENSION)commonExtension; 10591 10592 // 10593 // See if this device is in the child list (if this was a suprise 10594 // removal it might be) and remove it. 10595 // 10596 ClassRemoveChild(fdoExtension, pdoExtension, TRUE); 10597 } 10598 } 10599 10600 commonExtension->PartitionLength.QuadPart = 0; 10601 10602 if (RemoveType == IRP_MN_REMOVE_DEVICE) { 10603 10604 ClasspUninitializeRemoveTracking(DeviceObject); 10605 10606 IoDeleteDevice(DeviceObject); 10607 } 10608 } 10609 10610 return STATUS_SUCCESS; 10611 } // end ClassRemoveDevice() 10612 10613 /*++//////////////////////////////////////////////////////////////////////////// 10614 10615 ClassGetDriverExtension() 10616 10617 Routine Description: 10618 10619 This routine will return the classpnp's driver extension. 10620 10621 Arguments: 10622 10623 DriverObject - the driver object for which to get classpnp's extension 10624 10625 Return Value: 10626 10627 Either NULL if none, or a pointer to the driver extension 10628 10629 --*/ 10630 __drv_aliasesMem 10631 _IRQL_requires_max_(DISPATCH_LEVEL) 10632 PCLASS_DRIVER_EXTENSION 10633 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 10634 ClassGetDriverExtension( 10635 _In_ PDRIVER_OBJECT DriverObject 10636 ) 10637 { 10638 #ifdef _MSC_VER 10639 #pragma warning(suppress:4054) // okay to type cast function pointer as data pointer for this use case 10640 #endif 10641 return IoGetDriverObjectExtension(DriverObject, CLASS_DRIVER_EXTENSION_KEY); 10642 } // end ClassGetDriverExtension() 10643 10644 /*++//////////////////////////////////////////////////////////////////////////// 10645 10646 ClasspStartIo() 10647 10648 Routine Description: 10649 10650 This routine wraps the class driver's start io routine. If the device 10651 is being removed it will complete any requests with 10652 STATUS_DEVICE_DOES_NOT_EXIST and fire up the next packet. 10653 10654 Arguments: 10655 10656 Return Value: 10657 10658 none 10659 10660 --*/ 10661 VOID 10662 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 10663 ClasspStartIo( 10664 IN PDEVICE_OBJECT DeviceObject, 10665 IN PIRP Irp 10666 ) 10667 { 10668 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 10669 10670 // 10671 // We're already holding the remove lock so just check the variable and 10672 // see what's going on. 10673 // 10674 10675 if(commonExtension->IsRemoved) { 10676 10677 Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST; 10678 10679 #ifdef _MSC_VER 10680 #pragma warning(suppress:4054) // okay to type cast function pointer to PIRP for this use case 10681 #endif 10682 ClassAcquireRemoveLock(DeviceObject, (PIRP) ClasspStartIo); 10683 10684 ClassReleaseRemoveLock(DeviceObject, Irp); 10685 ClassCompleteRequest(DeviceObject, Irp, IO_DISK_INCREMENT); 10686 IoStartNextPacket(DeviceObject, TRUE); // Some IO is cancellable 10687 10688 #ifdef _MSC_VER 10689 #pragma warning(suppress:4054) // okay to type cast function pointer to PIRP for this use case 10690 #endif 10691 ClassReleaseRemoveLock(DeviceObject, (PIRP) ClasspStartIo); 10692 10693 return; 10694 } 10695 10696 commonExtension->DriverExtension->InitData.ClassStartIo( 10697 DeviceObject, 10698 Irp); 10699 10700 return; 10701 } // ClasspStartIo() 10702 10703 /*++//////////////////////////////////////////////////////////////////////////// 10704 10705 ClassUpdateInformationInRegistry() 10706 10707 Routine Description: 10708 10709 This routine has knowledge about the layout of the device map information 10710 in the registry. It will update this information to include a value 10711 entry specifying the dos device name that is assumed to get assigned 10712 to this NT device name. For more information on this assigning of the 10713 dos device name look in the drive support routine in the hal that assigns 10714 all dos names. 10715 10716 Since some versions of some device's firmware did not work and some 10717 vendors did not bother to follow the specification, the entire inquiry 10718 information must also be stored in the registry so than someone can 10719 figure out the firmware version. 10720 10721 Arguments: 10722 10723 DeviceObject - A pointer to the device object for the tape device. 10724 10725 Return Value: 10726 10727 None 10728 10729 --*/ 10730 _IRQL_requires_max_(PASSIVE_LEVEL) 10731 VOID 10732 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 10733 ClassUpdateInformationInRegistry( 10734 _In_ PDEVICE_OBJECT Fdo, 10735 _In_ PCHAR DeviceName, 10736 _In_ ULONG DeviceNumber, 10737 _In_reads_bytes_opt_(InquiryDataLength) PINQUIRYDATA InquiryData, 10738 _In_ ULONG InquiryDataLength 10739 ) 10740 { 10741 NTSTATUS status; 10742 SCSI_ADDRESS scsiAddress = {0}; 10743 OBJECT_ATTRIBUTES objectAttributes = {0}; 10744 STRING string; 10745 UNICODE_STRING unicodeName = {0}; 10746 UNICODE_STRING unicodeRegistryPath = {0}; 10747 UNICODE_STRING unicodeData = {0}; 10748 HANDLE targetKey; 10749 IO_STATUS_BLOCK ioStatus; 10750 UCHAR buffer[256] = {0}; 10751 10752 PAGED_CODE(); 10753 10754 NT_ASSERT(DeviceName); 10755 targetKey = NULL; 10756 10757 _SEH2_TRY { 10758 10759 // 10760 // Issue GET_ADDRESS Ioctl to determine path, target, and lun information. 10761 // 10762 10763 ClassSendDeviceIoControlSynchronous( 10764 IOCTL_SCSI_GET_ADDRESS, 10765 Fdo, 10766 &scsiAddress, 10767 0, 10768 sizeof(SCSI_ADDRESS), 10769 FALSE, 10770 &ioStatus 10771 ); 10772 10773 if (!NT_SUCCESS(ioStatus.Status)) { 10774 10775 status = ioStatus.Status; 10776 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, 10777 "UpdateInformationInRegistry: Get Address failed %lx\n", 10778 status)); 10779 _SEH2_LEAVE; 10780 10781 } else { 10782 10783 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, 10784 "GetAddress: Port %x, Path %x, Target %x, Lun %x\n", 10785 scsiAddress.PortNumber, 10786 scsiAddress.PathId, 10787 scsiAddress.TargetId, 10788 scsiAddress.Lun)); 10789 10790 } 10791 10792 status = RtlStringCchPrintfA((NTSTRSAFE_PSTR)buffer, 10793 sizeof(buffer)-1, 10794 "\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi\\Scsi Port %d\\Scsi Bus %d\\Target Id %d\\Logical Unit Id %d", 10795 scsiAddress.PortNumber, 10796 scsiAddress.PathId, 10797 scsiAddress.TargetId, 10798 scsiAddress.Lun); 10799 10800 if (!NT_SUCCESS(status)) { 10801 _SEH2_LEAVE; 10802 } 10803 10804 RtlInitString(&string, (PCSZ)buffer); 10805 10806 status = RtlAnsiStringToUnicodeString(&unicodeRegistryPath, 10807 &string, 10808 TRUE); 10809 10810 if (!NT_SUCCESS(status)) { 10811 _SEH2_LEAVE; 10812 } 10813 10814 // 10815 // Open the registry key for the scsi information for this 10816 // scsibus, target, lun. 10817 // 10818 10819 InitializeObjectAttributes(&objectAttributes, 10820 &unicodeRegistryPath, 10821 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 10822 NULL, 10823 NULL); 10824 10825 status = ZwOpenKey(&targetKey, 10826 KEY_READ | KEY_WRITE, 10827 &objectAttributes); 10828 10829 if (!NT_SUCCESS(status)) { 10830 _SEH2_LEAVE; 10831 } 10832 10833 // 10834 // Now construct and attempt to create the registry value 10835 // specifying the device name in the appropriate place in the 10836 // device map. 10837 // 10838 10839 RtlInitUnicodeString(&unicodeName, L"DeviceName"); 10840 10841 status = RtlStringCchPrintfA((NTSTRSAFE_PSTR)buffer, sizeof(buffer)-1, "%s%d", DeviceName, DeviceNumber); 10842 if (!NT_SUCCESS(status)) { 10843 _SEH2_LEAVE; 10844 } 10845 10846 RtlInitString(&string, (PCSZ)buffer); 10847 status = RtlAnsiStringToUnicodeString(&unicodeData, 10848 &string, 10849 TRUE); 10850 if (NT_SUCCESS(status)) { 10851 status = ZwSetValueKey(targetKey, 10852 &unicodeName, 10853 0, 10854 REG_SZ, 10855 unicodeData.Buffer, 10856 unicodeData.Length); 10857 } 10858 10859 // 10860 // if they sent in data, update the registry 10861 // 10862 10863 if (NT_SUCCESS(status) && InquiryDataLength) { 10864 10865 NT_ASSERT(InquiryData); 10866 10867 RtlInitUnicodeString(&unicodeName, L"InquiryData"); 10868 status = ZwSetValueKey(targetKey, 10869 &unicodeName, 10870 0, 10871 REG_BINARY, 10872 InquiryData, 10873 InquiryDataLength); 10874 } 10875 10876 // that's all, except to clean up. 10877 10878 } _SEH2_FINALLY { 10879 10880 if (!NT_SUCCESS(status)) { 10881 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, 10882 "Failure to update information in registry: %08x\n", 10883 status 10884 )); 10885 } 10886 10887 if (unicodeData.Buffer) { 10888 RtlFreeUnicodeString(&unicodeData); 10889 } 10890 if (unicodeRegistryPath.Buffer) { 10891 RtlFreeUnicodeString(&unicodeRegistryPath); 10892 } 10893 if (targetKey) { 10894 ZwClose(targetKey); 10895 } 10896 10897 } _SEH2_END; 10898 10899 } // end ClassUpdateInformationInRegistry() 10900 10901 /*++//////////////////////////////////////////////////////////////////////////// 10902 10903 ClasspSendSynchronousCompletion() 10904 10905 Routine Description: 10906 10907 This completion routine will set the user event in the irp after 10908 freeing the irp and the associated MDL (if any). 10909 10910 Arguments: 10911 10912 DeviceObject - the device object which requested the completion routine 10913 10914 Irp - the irp being completed 10915 10916 Context - unused 10917 10918 Return Value: 10919 10920 STATUS_MORE_PROCESSING_REQUIRED 10921 10922 --*/ 10923 NTSTATUS 10924 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 10925 ClasspSendSynchronousCompletion( 10926 IN PDEVICE_OBJECT DeviceObject, 10927 IN PIRP Irp, 10928 IN PVOID Context 10929 ) 10930 { 10931 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "ClasspSendSynchronousCompletion: %p %p %p\n", 10932 DeviceObject, Irp, Context)); 10933 // 10934 // First set the status and information fields in the io status block 10935 // provided by the caller. 10936 // 10937 10938 *(Irp->UserIosb) = Irp->IoStatus; 10939 10940 // 10941 // Unlock the pages for the data buffer. 10942 // 10943 10944 if(Irp->MdlAddress) { 10945 MmUnlockPages(Irp->MdlAddress); 10946 IoFreeMdl(Irp->MdlAddress); 10947 } 10948 10949 // 10950 // Signal the caller's event. 10951 // 10952 10953 KeSetEvent(Irp->UserEvent, IO_NO_INCREMENT, FALSE); 10954 10955 // 10956 // Free the MDL and the IRP. 10957 // 10958 10959 IoFreeIrp(Irp); 10960 10961 return STATUS_MORE_PROCESSING_REQUIRED; 10962 } // end ClasspSendSynchronousCompletion() 10963 10964 /*++ 10965 10966 ISSUE-2000/02/20-henrygab Not documented ClasspRegisterMountedDeviceInterface 10967 10968 --*/ 10969 VOID 10970 ClasspRegisterMountedDeviceInterface( 10971 IN PDEVICE_OBJECT DeviceObject 10972 ) 10973 { 10974 10975 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 10976 BOOLEAN isFdo = commonExtension->IsFdo; 10977 PDEVICE_OBJECT pdo; 10978 UNICODE_STRING interfaceName; 10979 10980 NTSTATUS status; 10981 10982 PAGED_CODE(); 10983 10984 if(isFdo) { 10985 10986 PFUNCTIONAL_DEVICE_EXTENSION functionalExtension; 10987 10988 functionalExtension = 10989 (PFUNCTIONAL_DEVICE_EXTENSION) commonExtension; 10990 pdo = functionalExtension->LowerPdo; 10991 } else { 10992 pdo = DeviceObject; 10993 } 10994 10995 #ifdef _MSC_VER 10996 #pragma prefast(suppress:6014, "The allocated memory that interfaceName points to will be freed in ClassRemoveDevice().") 10997 #endif 10998 status = IoRegisterDeviceInterface( 10999 pdo, 11000 &MOUNTDEV_MOUNTED_DEVICE_GUID, 11001 NULL, 11002 &interfaceName 11003 ); 11004 11005 if(NT_SUCCESS(status)) { 11006 11007 // 11008 // Copy the interface name before setting the interface state - the 11009 // name is needed by the components we notify. 11010 // 11011 11012 commonExtension->MountedDeviceInterfaceName = interfaceName; 11013 status = IoSetDeviceInterfaceState(&interfaceName, TRUE); 11014 11015 if(!NT_SUCCESS(status)) { 11016 RtlFreeUnicodeString(&interfaceName); 11017 } 11018 } 11019 11020 if(!NT_SUCCESS(status)) { 11021 RtlInitUnicodeString(&(commonExtension->MountedDeviceInterfaceName), 11022 NULL); 11023 } 11024 return; 11025 } // end ClasspRegisterMountedDeviceInterface() 11026 11027 /*++//////////////////////////////////////////////////////////////////////////// 11028 11029 ClassSendDeviceIoControlSynchronous() 11030 11031 Routine Description: 11032 11033 This routine is based upon IoBuildDeviceIoControlRequest(). It has been 11034 modified to reduce code and memory by not double-buffering the io, using 11035 the same buffer for both input and output, allocating and deallocating 11036 the mdl on behalf of the caller, and waiting for the io to complete. 11037 11038 This routine also works around the rare cases in which APC's are disabled. 11039 Since IoBuildDeviceIoControl() used APC's to signal completion, this had 11040 led to a number of difficult-to-detect hangs, where the irp was completed, 11041 but the event passed to IoBuild..() was still being waited upon by the 11042 caller. 11043 11044 Arguments: 11045 11046 IoControlCode - the IOCTL to send 11047 11048 TargetDeviceObject - the device object that should handle the ioctl 11049 11050 Buffer - the input and output buffer, or NULL if no input/output 11051 11052 InputBufferLength - the number of bytes prepared for the IOCTL in Buffer 11053 11054 OutputBufferLength - the number of bytes to be filled in upon success 11055 11056 InternalDeviceIoControl - if TRUE, uses IRP_MJ_INTERNAL_DEVICE_CONTROL 11057 11058 IoStatus - the status block that contains the results of the operation 11059 11060 Return Value: 11061 11062 --*/ 11063 VOID 11064 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 11065 ClassSendDeviceIoControlSynchronous( 11066 _In_ ULONG IoControlCode, 11067 _In_ PDEVICE_OBJECT TargetDeviceObject, 11068 _Inout_updates_opt_(_Inexpressible_(max(InputBufferLength, OutputBufferLength))) PVOID Buffer, 11069 _In_ ULONG InputBufferLength, 11070 _In_ ULONG OutputBufferLength, 11071 _In_ BOOLEAN InternalDeviceIoControl, 11072 _Out_ PIO_STATUS_BLOCK IoStatus 11073 ) 11074 { 11075 PIRP irp; 11076 PIO_STACK_LOCATION irpSp; 11077 ULONG method; 11078 11079 PAGED_CODE(); 11080 11081 irp = NULL; 11082 method = IoControlCode & 3; 11083 11084 #if DBG // Begin Argument Checking (nop in fre version) 11085 11086 NT_ASSERT(ARGUMENT_PRESENT(IoStatus)); 11087 11088 if ((InputBufferLength != 0) || (OutputBufferLength != 0)) { 11089 NT_ASSERT(ARGUMENT_PRESENT(Buffer)); 11090 } 11091 else { 11092 NT_ASSERT(!ARGUMENT_PRESENT(Buffer)); 11093 } 11094 #endif 11095 11096 // 11097 // Begin by allocating the IRP for this request. Do not charge quota to 11098 // the current process for this IRP. 11099 // 11100 11101 irp = IoAllocateIrp(TargetDeviceObject->StackSize, FALSE); 11102 if (!irp) { 11103 IoStatus->Information = 0; 11104 IoStatus->Status = STATUS_INSUFFICIENT_RESOURCES; 11105 return; 11106 } 11107 11108 // 11109 // Get a pointer to the stack location of the first driver which will be 11110 // invoked. This is where the function codes and the parameters are set. 11111 // 11112 11113 irpSp = IoGetNextIrpStackLocation(irp); 11114 11115 // 11116 // Set the major function code based on the type of device I/O control 11117 // function the caller has specified. 11118 // 11119 11120 if (InternalDeviceIoControl) { 11121 irpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; 11122 } else { 11123 irpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL; 11124 } 11125 11126 // 11127 // Copy the caller's parameters to the service-specific portion of the 11128 // IRP for those parameters that are the same for all four methods. 11129 // 11130 11131 irpSp->Parameters.DeviceIoControl.OutputBufferLength = OutputBufferLength; 11132 irpSp->Parameters.DeviceIoControl.InputBufferLength = InputBufferLength; 11133 irpSp->Parameters.DeviceIoControl.IoControlCode = IoControlCode; 11134 11135 // 11136 // Get the method bits from the I/O control code to determine how the 11137 // buffers are to be passed to the driver. 11138 // 11139 11140 switch (method) 11141 { 11142 // 11143 // case 0 11144 // 11145 case METHOD_BUFFERED: 11146 { 11147 if ((InputBufferLength != 0) || (OutputBufferLength != 0)) 11148 { 11149 irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned, 11150 max(InputBufferLength, OutputBufferLength), 11151 CLASS_TAG_DEVICE_CONTROL); 11152 if (irp->AssociatedIrp.SystemBuffer == NULL) 11153 { 11154 IoFreeIrp(irp); 11155 11156 IoStatus->Information = 0; 11157 IoStatus->Status = STATUS_INSUFFICIENT_RESOURCES; 11158 return; 11159 } 11160 11161 if (InputBufferLength != 0) 11162 { 11163 RtlCopyMemory(irp->AssociatedIrp.SystemBuffer, Buffer, InputBufferLength); 11164 } 11165 } 11166 11167 irp->UserBuffer = Buffer; 11168 11169 break; 11170 } 11171 11172 // 11173 // case 1, case 2 11174 // 11175 case METHOD_IN_DIRECT: 11176 case METHOD_OUT_DIRECT: 11177 { 11178 if (InputBufferLength != 0) 11179 { 11180 irp->AssociatedIrp.SystemBuffer = Buffer; 11181 } 11182 11183 if (OutputBufferLength != 0) 11184 { 11185 irp->MdlAddress = IoAllocateMdl(Buffer, 11186 OutputBufferLength, 11187 FALSE, 11188 FALSE, 11189 (PIRP) NULL); 11190 if (irp->MdlAddress == NULL) 11191 { 11192 IoFreeIrp(irp); 11193 11194 IoStatus->Information = 0; 11195 IoStatus->Status = STATUS_INSUFFICIENT_RESOURCES; 11196 return; 11197 } 11198 11199 _SEH2_TRY 11200 { 11201 MmProbeAndLockPages(irp->MdlAddress, 11202 KernelMode, 11203 (method == METHOD_IN_DIRECT) ? IoReadAccess : IoWriteAccess); 11204 } 11205 #ifdef _MSC_VER 11206 #pragma warning(suppress: 6320) // We want to handle any exception that MmProbeAndLockPages might throw 11207 #endif 11208 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 11209 { 11210 IoFreeMdl(irp->MdlAddress); 11211 IoFreeIrp(irp); 11212 11213 IoStatus->Information = 0; 11214 IoStatus->Status = _SEH2_GetExceptionCode(); 11215 _SEH2_YIELD(return); 11216 } _SEH2_END; 11217 } 11218 11219 break; 11220 } 11221 11222 // 11223 // case 3 11224 // 11225 case METHOD_NEITHER: 11226 { 11227 NT_ASSERT(!"ClassSendDeviceIoControlSynchronous does not support METHOD_NEITHER Ioctls"); 11228 11229 IoFreeIrp(irp); 11230 11231 IoStatus->Information = 0; 11232 IoStatus->Status = STATUS_NOT_SUPPORTED; 11233 return; 11234 } 11235 } 11236 11237 irp->Tail.Overlay.Thread = PsGetCurrentThread(); 11238 11239 // 11240 // send the irp synchronously 11241 // 11242 11243 ClassSendIrpSynchronous(TargetDeviceObject, irp); 11244 11245 // 11246 // copy the iostatus block for the caller 11247 // 11248 11249 *IoStatus = irp->IoStatus; 11250 11251 // 11252 // free any allocated resources 11253 // 11254 11255 switch (method) { 11256 case METHOD_BUFFERED: { 11257 11258 NT_ASSERT(irp->UserBuffer == Buffer); 11259 11260 // 11261 // first copy the buffered result, if any 11262 // Note that there are no security implications in 11263 // not checking for success since only drivers can 11264 // call into this routine anyways... 11265 // 11266 11267 if (OutputBufferLength != 0) { 11268 #ifdef _MSC_VER 11269 #pragma warning(suppress: 6386) // Buffer's size is max(InputBufferLength, OutputBufferLength) 11270 #endif 11271 RtlCopyMemory(Buffer, // irp->UserBuffer 11272 irp->AssociatedIrp.SystemBuffer, 11273 OutputBufferLength 11274 ); 11275 } 11276 11277 // 11278 // then free the memory allocated to buffer the io 11279 // 11280 11281 if ((InputBufferLength !=0) || (OutputBufferLength != 0)) { 11282 FREE_POOL(irp->AssociatedIrp.SystemBuffer); 11283 } 11284 break; 11285 } 11286 11287 case METHOD_IN_DIRECT: 11288 case METHOD_OUT_DIRECT: { 11289 11290 // 11291 // we alloc a mdl if there is an output buffer specified 11292 // free it here after unlocking the pages 11293 // 11294 11295 if (OutputBufferLength != 0) { 11296 NT_ASSERT(irp->MdlAddress != NULL); 11297 MmUnlockPages(irp->MdlAddress); 11298 IoFreeMdl(irp->MdlAddress); 11299 irp->MdlAddress = (PMDL) NULL; 11300 } 11301 break; 11302 } 11303 11304 case METHOD_NEITHER: { 11305 NT_ASSERT(!"Code is out of date"); 11306 break; 11307 } 11308 } 11309 11310 // 11311 // we always have allocated an irp. free it here. 11312 // 11313 11314 IoFreeIrp(irp); 11315 irp = (PIRP) NULL; 11316 11317 // 11318 // return the io status block's status to the caller 11319 // 11320 11321 return; 11322 } // end ClassSendDeviceIoControlSynchronous() 11323 11324 /*++//////////////////////////////////////////////////////////////////////////// 11325 11326 ClassForwardIrpSynchronous() 11327 11328 Routine Description: 11329 11330 Forwards a given irp to the next lower device object. 11331 11332 Arguments: 11333 11334 CommonExtension - the common class extension 11335 11336 Irp - the request to forward down the stack 11337 11338 Return Value: 11339 11340 --*/ 11341 NTSTATUS 11342 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 11343 ClassForwardIrpSynchronous( 11344 _In_ PCOMMON_DEVICE_EXTENSION CommonExtension, 11345 _In_ PIRP Irp 11346 ) 11347 { 11348 IoCopyCurrentIrpStackLocationToNext(Irp); 11349 return ClassSendIrpSynchronous(CommonExtension->LowerDeviceObject, Irp); 11350 } // end ClassForwardIrpSynchronous() 11351 11352 /*++//////////////////////////////////////////////////////////////////////////// 11353 11354 ClassSendIrpSynchronous() 11355 11356 Routine Description: 11357 11358 This routine sends the given irp to the given device object, and waits for 11359 it to complete. On debug versions, will print out a debug message and 11360 optionally assert for "lost" irps based upon classpnp's globals 11361 11362 Arguments: 11363 11364 TargetDeviceObject - the device object to handle this irp 11365 11366 Irp - the request to be sent 11367 11368 Return Value: 11369 11370 --*/ 11371 NTSTATUS 11372 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 11373 ClassSendIrpSynchronous( 11374 _In_ PDEVICE_OBJECT TargetDeviceObject, 11375 _In_ PIRP Irp 11376 ) 11377 { 11378 KEVENT event; 11379 NTSTATUS status; 11380 11381 NT_ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); 11382 NT_ASSERT(TargetDeviceObject != NULL); 11383 NT_ASSERT(Irp != NULL); 11384 NT_ASSERT(Irp->StackCount >= TargetDeviceObject->StackSize); 11385 11386 // 11387 // ISSUE-2000/02/20-henrygab What if APCs are disabled? 11388 // May need to enter critical section before IoCallDriver() 11389 // until the event is hit? 11390 // 11391 11392 KeInitializeEvent(&event, SynchronizationEvent, FALSE); 11393 IoSetCompletionRoutine(Irp, ClassSignalCompletion, &event, 11394 TRUE, TRUE, TRUE); 11395 11396 status = IoCallDriver(TargetDeviceObject, Irp); 11397 _Analysis_assume_(status!=STATUS_PENDING); 11398 if (status == STATUS_PENDING) { 11399 11400 #if DBG 11401 LARGE_INTEGER timeout; 11402 11403 timeout.QuadPart = (LONGLONG)(-1 * 10 * 1000 * (LONGLONG)1000 * 11404 ClasspnpGlobals.SecondsToWaitForIrps); 11405 11406 do { 11407 status = KeWaitForSingleObject(&event, 11408 Executive, 11409 KernelMode, 11410 FALSE, 11411 &timeout); 11412 11413 11414 if (status == STATUS_TIMEOUT) { 11415 11416 // 11417 // This DebugPrint should almost always be investigated by the 11418 // party who sent the irp and/or the current owner of the irp. 11419 // Synchronous Irps should not take this long (currently 30 11420 // seconds) without good reason. This points to a potentially 11421 // serious problem in the underlying device stack. 11422 // 11423 11424 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "ClassSendIrpSynchronous: (%p) irp %p did not " 11425 "complete within %x seconds\n", 11426 TargetDeviceObject, Irp, 11427 ClasspnpGlobals.SecondsToWaitForIrps 11428 )); 11429 11430 if (ClasspnpGlobals.BreakOnLostIrps != 0) { 11431 NT_ASSERT(!" - Irp failed to complete within 30 seconds - "); 11432 } 11433 } 11434 11435 11436 } while (status==STATUS_TIMEOUT); 11437 #else 11438 (VOID)KeWaitForSingleObject(&event, 11439 Executive, 11440 KernelMode, 11441 FALSE, 11442 NULL); 11443 #endif 11444 11445 status = Irp->IoStatus.Status; 11446 } 11447 11448 return status; 11449 } // end ClassSendIrpSynchronous() 11450 11451 /*++//////////////////////////////////////////////////////////////////////////// 11452 11453 ClassGetVpb() 11454 11455 Routine Description: 11456 11457 This routine returns the current VPB (Volume Parameter Block) for the 11458 given device object. 11459 The Vpb field is only visible in the ntddk.h (not the wdm.h) definition 11460 of DEVICE_OBJECT; hence this exported function. 11461 11462 Arguments: 11463 11464 DeviceObject - the device to get the VPB for 11465 11466 Return Value: 11467 11468 the VPB, or NULL if none. 11469 11470 --*/ 11471 PVPB 11472 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 11473 ClassGetVpb( 11474 _In_ PDEVICE_OBJECT DeviceObject 11475 ) 11476 { 11477 #ifdef _MSC_VER 11478 #pragma prefast(suppress:28175) 11479 #endif 11480 return DeviceObject->Vpb; 11481 } // end ClassGetVpb() 11482 11483 /*++ 11484 11485 ISSUE-2000/02/20-henrygab Not documented ClasspAllocateReleaseRequest 11486 11487 --*/ 11488 NTSTATUS 11489 ClasspAllocateReleaseRequest( 11490 IN PDEVICE_OBJECT Fdo 11491 ) 11492 { 11493 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; 11494 11495 PAGED_CODE(); 11496 11497 KeInitializeSpinLock(&(fdoExtension->ReleaseQueueSpinLock)); 11498 11499 fdoExtension->ReleaseQueueNeeded = FALSE; 11500 fdoExtension->ReleaseQueueInProgress = FALSE; 11501 fdoExtension->ReleaseQueueIrpFromPool = FALSE; 11502 11503 // 11504 // The class driver is responsible for allocating a properly sized irp, 11505 // or ClassReleaseQueue will attempt to do it on the first error. 11506 // 11507 11508 fdoExtension->ReleaseQueueIrp = NULL; 11509 11510 // 11511 // Write length to SRB. 11512 // 11513 11514 fdoExtension->ReleaseQueueSrb.Length = sizeof(SCSI_REQUEST_BLOCK); 11515 11516 return STATUS_SUCCESS; 11517 } // end ClasspAllocateReleaseRequest() 11518 11519 /*++ 11520 11521 ISSUE-2000/02/20-henrygab Not documented ClasspFreeReleaseRequest 11522 11523 --*/ 11524 VOID 11525 ClasspFreeReleaseRequest( 11526 IN PDEVICE_OBJECT Fdo 11527 ) 11528 { 11529 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; 11530 11531 PAGED_CODE(); 11532 11533 //KIRQL oldIrql; 11534 11535 NT_ASSERT(fdoExtension->CommonExtension.IsRemoved != NO_REMOVE); 11536 11537 // 11538 // free anything the driver allocated 11539 // 11540 11541 if (fdoExtension->ReleaseQueueIrp) { 11542 if (fdoExtension->ReleaseQueueIrpFromPool) { 11543 FREE_POOL(fdoExtension->ReleaseQueueIrp); 11544 } else { 11545 IoFreeIrp(fdoExtension->ReleaseQueueIrp); 11546 } 11547 fdoExtension->ReleaseQueueIrp = NULL; 11548 } 11549 11550 // 11551 // free anything that we allocated 11552 // 11553 11554 if ((fdoExtension->PrivateFdoData) && 11555 (fdoExtension->PrivateFdoData->ReleaseQueueIrpAllocated)) { 11556 11557 FREE_POOL(fdoExtension->PrivateFdoData->ReleaseQueueIrp); 11558 fdoExtension->PrivateFdoData->ReleaseQueueIrpAllocated = FALSE; 11559 } 11560 11561 return; 11562 } // end ClasspFreeReleaseRequest() 11563 11564 /*++//////////////////////////////////////////////////////////////////////////// 11565 11566 ClassReleaseQueue() 11567 11568 Routine Description: 11569 11570 This routine issues an internal device control command 11571 to the port driver to release a frozen queue. The call 11572 is issued asynchronously as ClassReleaseQueue will be invoked 11573 from the IO completion DPC (and will have no context to 11574 wait for a synchronous call to complete). 11575 11576 This routine must be called with the remove lock held. 11577 11578 Arguments: 11579 11580 Fdo - The functional device object for the device with the frozen queue. 11581 11582 Return Value: 11583 11584 None. 11585 11586 --*/ 11587 VOID 11588 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 11589 ClassReleaseQueue( 11590 _In_ PDEVICE_OBJECT Fdo 11591 ) 11592 { 11593 ClasspReleaseQueue(Fdo, NULL); 11594 return; 11595 } // end ClassReleaseQueue() 11596 11597 /*++//////////////////////////////////////////////////////////////////////////// 11598 11599 ClasspAllocateReleaseQueueIrp() 11600 11601 Routine Description: 11602 11603 This routine allocates the release queue irp held in classpnp's private 11604 extension. This was added to allow no-memory conditions to be more 11605 survivable. 11606 11607 Return Value: 11608 11609 NT_SUCCESS value. 11610 11611 Notes: 11612 11613 Does not grab the spinlock. Should only be called from StartDevice() 11614 routine. May be called elsewhere for poorly-behaved drivers that cause 11615 the queue to lockup before the device is started. This should *never* 11616 occur, since it's illegal to send a request to a non-started PDO. This 11617 condition is checked for in ClasspReleaseQueue(). 11618 11619 --*/ 11620 NTSTATUS 11621 ClasspAllocateReleaseQueueIrp( 11622 PFUNCTIONAL_DEVICE_EXTENSION FdoExtension 11623 ) 11624 { 11625 UCHAR lowerStackSize; 11626 11627 // 11628 // do an initial check w/o the spinlock 11629 // 11630 11631 if (FdoExtension->PrivateFdoData->ReleaseQueueIrpAllocated) { 11632 return STATUS_SUCCESS; 11633 } 11634 11635 11636 lowerStackSize = FdoExtension->CommonExtension.LowerDeviceObject->StackSize; 11637 11638 // 11639 // don't allocate one if one is in progress! this means whoever called 11640 // this routine didn't check if one was in progress. 11641 // 11642 11643 NT_ASSERT(!(FdoExtension->ReleaseQueueInProgress)); 11644 11645 FdoExtension->PrivateFdoData->ReleaseQueueIrp = 11646 ExAllocatePoolWithTag(NonPagedPoolNx, 11647 IoSizeOfIrp(lowerStackSize), 11648 CLASS_TAG_RELEASE_QUEUE 11649 ); 11650 11651 if (FdoExtension->PrivateFdoData->ReleaseQueueIrp == NULL) { 11652 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "ClassPnpStartDevice: Cannot allocate for " 11653 "release queue irp\n")); 11654 return STATUS_INSUFFICIENT_RESOURCES; 11655 } 11656 IoInitializeIrp(FdoExtension->PrivateFdoData->ReleaseQueueIrp, 11657 IoSizeOfIrp(lowerStackSize), 11658 lowerStackSize); 11659 FdoExtension->PrivateFdoData->ReleaseQueueIrpAllocated = TRUE; 11660 11661 return STATUS_SUCCESS; 11662 } 11663 11664 /*++//////////////////////////////////////////////////////////////////////////// 11665 11666 ClasspAllocatePowerProcessIrp() 11667 11668 Routine Description: 11669 11670 This routine allocates the power process irp. 11671 This routine should be called after PrivateFdoData is allocated. 11672 11673 Return Value: 11674 11675 NTSTATUS value. 11676 11677 Notes: 11678 11679 Should only be called from StartDevice() 11680 11681 --*/ 11682 NTSTATUS 11683 ClasspAllocatePowerProcessIrp( 11684 PFUNCTIONAL_DEVICE_EXTENSION FdoExtension 11685 ) 11686 { 11687 UCHAR stackSize; 11688 11689 NT_ASSERT(FdoExtension->PrivateFdoData != NULL); 11690 11691 stackSize = FdoExtension->CommonExtension.LowerDeviceObject->StackSize + 1; 11692 11693 FdoExtension->PrivateFdoData->PowerProcessIrp = ExAllocatePoolWithTag(NonPagedPoolNx, 11694 IoSizeOfIrp(stackSize), 11695 CLASS_TAG_POWER 11696 ); 11697 11698 if (FdoExtension->PrivateFdoData->PowerProcessIrp == NULL) { 11699 11700 return STATUS_INSUFFICIENT_RESOURCES; 11701 } else { 11702 11703 IoInitializeIrp(FdoExtension->PrivateFdoData->PowerProcessIrp, 11704 IoSizeOfIrp(stackSize), 11705 stackSize); 11706 11707 return STATUS_SUCCESS; 11708 } 11709 } 11710 11711 11712 /*++//////////////////////////////////////////////////////////////////////////// 11713 11714 ClasspReleaseQueue() 11715 11716 Routine Description: 11717 11718 This routine issues an internal device control command 11719 to the port driver to release a frozen queue. The call 11720 is issued asynchronously as ClassReleaseQueue will be invoked 11721 from the IO completion DPC (and will have no context to 11722 wait for a synchronous call to complete). 11723 11724 This routine must be called with the remove lock held. 11725 11726 Arguments: 11727 11728 Fdo - The functional device object for the device with the frozen queue. 11729 11730 ReleaseQueueIrp - If this irp is supplied then the test to determine whether 11731 a release queue request is in progress will be ignored. 11732 The irp provided must be the IRP originally allocated 11733 for release queue requests (so this parameter can only 11734 really be provided by the release queue completion 11735 routine.) 11736 11737 Return Value: 11738 11739 None. 11740 11741 --*/ 11742 VOID 11743 ClasspReleaseQueue( 11744 IN PDEVICE_OBJECT Fdo, 11745 IN PIRP ReleaseQueueIrp OPTIONAL 11746 ) 11747 { 11748 PIO_STACK_LOCATION irpStack; 11749 PIRP irp; 11750 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; 11751 PDEVICE_OBJECT lowerDevice; 11752 PSTORAGE_REQUEST_BLOCK_HEADER srb; 11753 KIRQL currentIrql; 11754 ULONG function; 11755 11756 lowerDevice = fdoExtension->CommonExtension.LowerDeviceObject; 11757 11758 // 11759 // we raise irql seperately so we're not swapped out or suspended 11760 // while holding the release queue irp in this routine. this lets 11761 // us release the spin lock before lowering irql. 11762 // 11763 11764 KeRaiseIrql(DISPATCH_LEVEL, ¤tIrql); 11765 11766 KeAcquireSpinLockAtDpcLevel(&(fdoExtension->ReleaseQueueSpinLock)); 11767 11768 // 11769 // make sure that if they passed us an irp, it matches our allocated irp. 11770 // 11771 11772 NT_ASSERT((ReleaseQueueIrp == NULL) || 11773 (ReleaseQueueIrp == fdoExtension->PrivateFdoData->ReleaseQueueIrp)); 11774 11775 // 11776 // ASSERT that we've already allocated this. (should not occur) 11777 // try to allocate it anyways, then finally bugcheck if 11778 // there's still no memory... 11779 // 11780 11781 NT_ASSERT(fdoExtension->PrivateFdoData->ReleaseQueueIrpAllocated); 11782 if (!fdoExtension->PrivateFdoData->ReleaseQueueIrpAllocated) { 11783 ClasspAllocateReleaseQueueIrp(fdoExtension); 11784 } 11785 if (!fdoExtension->PrivateFdoData->ReleaseQueueIrpAllocated) { 11786 KeBugCheckEx(SCSI_DISK_DRIVER_INTERNAL, 0x12, (ULONG_PTR)Fdo, 0x0, 0x0); 11787 } 11788 11789 if ((fdoExtension->ReleaseQueueInProgress) && (ReleaseQueueIrp == NULL)) { 11790 11791 // 11792 // Someone is already using the irp - just set the flag to indicate that 11793 // we need to release the queue again. 11794 // 11795 11796 fdoExtension->ReleaseQueueNeeded = TRUE; 11797 KeReleaseSpinLockFromDpcLevel(&(fdoExtension->ReleaseQueueSpinLock)); 11798 KeLowerIrql(currentIrql); 11799 return; 11800 11801 } 11802 11803 // 11804 // Mark that there is a release queue in progress and drop the spinlock. 11805 // 11806 11807 fdoExtension->ReleaseQueueInProgress = TRUE; 11808 if (ReleaseQueueIrp) { 11809 irp = ReleaseQueueIrp; 11810 } else { 11811 irp = fdoExtension->PrivateFdoData->ReleaseQueueIrp; 11812 } 11813 11814 if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { 11815 srb = (PSTORAGE_REQUEST_BLOCK_HEADER)&(fdoExtension->PrivateFdoData->ReleaseQueueSrb.SrbEx); 11816 } else { 11817 srb = (PSTORAGE_REQUEST_BLOCK_HEADER)&(fdoExtension->ReleaseQueueSrb); 11818 } 11819 11820 KeReleaseSpinLockFromDpcLevel(&(fdoExtension->ReleaseQueueSpinLock)); 11821 11822 NT_ASSERT(irp != NULL); 11823 11824 irpStack = IoGetNextIrpStackLocation(irp); 11825 11826 irpStack->MajorFunction = IRP_MJ_SCSI; 11827 11828 SrbSetOriginalRequest(srb, irp); 11829 11830 // 11831 // Store the SRB address in next stack for port driver. 11832 // 11833 11834 irpStack->Parameters.Scsi.Srb = (PSCSI_REQUEST_BLOCK)srb; 11835 11836 // 11837 // If this device is removable then flush the queue. This will also 11838 // release it. 11839 // 11840 11841 if (TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)){ 11842 function = SRB_FUNCTION_FLUSH_QUEUE; 11843 } 11844 else { 11845 function = SRB_FUNCTION_RELEASE_QUEUE; 11846 } 11847 11848 if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { 11849 ((PSTORAGE_REQUEST_BLOCK)srb)->SrbFunction = function; 11850 } else { 11851 srb->Function = (UCHAR)function; 11852 } 11853 11854 ClassAcquireRemoveLock(Fdo, irp); 11855 11856 IoSetCompletionRoutine(irp, 11857 ClassReleaseQueueCompletion, 11858 Fdo, 11859 TRUE, 11860 TRUE, 11861 TRUE); 11862 11863 IoCallDriver(lowerDevice, irp); 11864 11865 KeLowerIrql(currentIrql); 11866 11867 return; 11868 11869 } // end ClassReleaseQueue() 11870 11871 /*++//////////////////////////////////////////////////////////////////////////// 11872 11873 ClassReleaseQueueCompletion() 11874 11875 Routine Description: 11876 11877 This routine is called when an asynchronous I/O request 11878 which was issused by the class driver completes. Examples of such requests 11879 are release queue or START UNIT. This routine releases the queue if 11880 necessary. It then frees the context and the IRP. 11881 11882 Arguments: 11883 11884 DeviceObject - The device object for the logical unit; however since this 11885 is the top stack location the value is NULL. 11886 11887 Irp - Supplies a pointer to the Irp to be processed. 11888 11889 Context - Supplies the context to be used to process this request. 11890 11891 Return Value: 11892 11893 None. 11894 11895 --*/ 11896 NTSTATUS 11897 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 11898 ClassReleaseQueueCompletion( 11899 PDEVICE_OBJECT DeviceObject, 11900 PIRP Irp, 11901 PVOID Context 11902 ) 11903 { 11904 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension; 11905 KIRQL oldIrql; 11906 11907 BOOLEAN releaseQueueNeeded; 11908 11909 if (Context == NULL) { 11910 NT_ASSERT(Context != NULL); 11911 return STATUS_INVALID_PARAMETER; 11912 } 11913 11914 DeviceObject = Context; 11915 11916 fdoExtension = DeviceObject->DeviceExtension; 11917 11918 ClassReleaseRemoveLock(DeviceObject, Irp); 11919 11920 // 11921 // Grab the spinlock and clear the release queue in progress flag so others 11922 // can run. Save (and clear) the state of the release queue needed flag 11923 // so that we can issue a new release queue outside the spinlock. 11924 // 11925 11926 KeAcquireSpinLock(&(fdoExtension->ReleaseQueueSpinLock), &oldIrql); 11927 11928 releaseQueueNeeded = fdoExtension->ReleaseQueueNeeded; 11929 11930 fdoExtension->ReleaseQueueNeeded = FALSE; 11931 fdoExtension->ReleaseQueueInProgress = FALSE; 11932 11933 KeReleaseSpinLock(&(fdoExtension->ReleaseQueueSpinLock), oldIrql); 11934 11935 // 11936 // If we need a release queue then issue one now. Another processor may 11937 // have already started one in which case we'll try to issue this one after 11938 // it is done - but we should never recurse more than one deep. 11939 // 11940 11941 if(releaseQueueNeeded) { 11942 ClasspReleaseQueue(DeviceObject, Irp); 11943 } 11944 11945 // 11946 // Indicate the I/O system should stop processing the Irp completion. 11947 // 11948 11949 return STATUS_MORE_PROCESSING_REQUIRED; 11950 11951 } // ClassAsynchronousCompletion() 11952 11953 11954 /*++//////////////////////////////////////////////////////////////////////////// 11955 11956 ClassAcquireChildLock() 11957 11958 Routine Description: 11959 11960 This routine acquires the lock protecting children PDOs. It may be 11961 acquired recursively by the same thread, but must be release by the 11962 thread once for each acquisition. 11963 11964 Arguments: 11965 11966 FdoExtension - the device whose child list is protected. 11967 11968 Return Value: 11969 11970 None 11971 11972 --*/ 11973 _IRQL_requires_max_(PASSIVE_LEVEL) 11974 VOID 11975 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 11976 ClassAcquireChildLock( 11977 _In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension 11978 ) 11979 { 11980 PAGED_CODE(); 11981 11982 if(FdoExtension->ChildLockOwner != KeGetCurrentThread()) { 11983 (VOID)KeWaitForSingleObject(&FdoExtension->ChildLock, 11984 Executive, KernelMode, 11985 FALSE, NULL); 11986 11987 NT_ASSERT(FdoExtension->ChildLockOwner == NULL); 11988 NT_ASSERT(FdoExtension->ChildLockAcquisitionCount == 0); 11989 11990 FdoExtension->ChildLockOwner = KeGetCurrentThread(); 11991 } else { 11992 NT_ASSERT(FdoExtension->ChildLockAcquisitionCount != 0); 11993 } 11994 11995 FdoExtension->ChildLockAcquisitionCount++; 11996 return; 11997 } 11998 11999 /*++//////////////////////////////////////////////////////////////////////////// 12000 12001 ClassReleaseChildLock() ISSUE-2000/02/18-henrygab - not documented 12002 12003 Routine Description: 12004 12005 This routine releases the lock protecting children PDOs. It must be 12006 called once for each time ClassAcquireChildLock was called. 12007 12008 Arguments: 12009 12010 FdoExtension - the device whose child list is protected 12011 12012 Return Value: 12013 12014 None. 12015 12016 --*/ 12017 VOID 12018 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 12019 ClassReleaseChildLock( 12020 _In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension 12021 ) 12022 { 12023 NT_ASSERT(FdoExtension->ChildLockOwner == KeGetCurrentThread()); 12024 NT_ASSERT(FdoExtension->ChildLockAcquisitionCount != 0); 12025 12026 FdoExtension->ChildLockAcquisitionCount -= 1; 12027 12028 if(FdoExtension->ChildLockAcquisitionCount == 0) { 12029 FdoExtension->ChildLockOwner = NULL; 12030 KeSetEvent(&FdoExtension->ChildLock, IO_NO_INCREMENT, FALSE); 12031 } 12032 12033 return; 12034 } // end ClassReleaseChildLock( 12035 12036 /*++//////////////////////////////////////////////////////////////////////////// 12037 12038 ClassAddChild() 12039 12040 Routine Description: 12041 12042 This routine will insert a new child into the head of the child list. 12043 12044 Arguments: 12045 12046 Parent - the child's parent (contains the head of the list) 12047 Child - the child to be inserted. 12048 AcquireLock - whether the child lock should be acquired (TRUE) or whether 12049 it's already been acquired by or on behalf of the caller 12050 (FALSE). 12051 12052 Return Value: 12053 12054 None. 12055 12056 --*/ 12057 VOID 12058 ClassAddChild( 12059 _In_ PFUNCTIONAL_DEVICE_EXTENSION Parent, 12060 _In_ PPHYSICAL_DEVICE_EXTENSION Child, 12061 _In_ BOOLEAN AcquireLock 12062 ) 12063 { 12064 if(AcquireLock) { 12065 ClassAcquireChildLock(Parent); 12066 } 12067 12068 #if DBG 12069 // 12070 // Make sure this child's not already in the list. 12071 // 12072 { 12073 PPHYSICAL_DEVICE_EXTENSION testChild; 12074 12075 for (testChild = Parent->CommonExtension.ChildList; 12076 testChild != NULL; 12077 testChild = testChild->CommonExtension.ChildList) { 12078 12079 NT_ASSERT(testChild != Child); 12080 } 12081 } 12082 #endif 12083 12084 Child->CommonExtension.ChildList = Parent->CommonExtension.ChildList; 12085 Parent->CommonExtension.ChildList = Child; 12086 12087 if(AcquireLock) { 12088 ClassReleaseChildLock(Parent); 12089 } 12090 return; 12091 } // end ClassAddChild() 12092 12093 /*++//////////////////////////////////////////////////////////////////////////// 12094 12095 ClassRemoveChild() 12096 12097 Routine Description: 12098 12099 This routine will remove a child from the child list. 12100 12101 Arguments: 12102 12103 Parent - the parent to be removed from. 12104 12105 Child - the child to be removed or NULL if the first child should be 12106 removed. 12107 12108 AcquireLock - whether the child lock should be acquired (TRUE) or whether 12109 it's already been acquired by or on behalf of the caller 12110 (FALSE). 12111 12112 Return Value: 12113 12114 A pointer to the child which was removed or NULL if no such child could 12115 be found in the list (or if Child was NULL but the list is empty). 12116 12117 --*/ 12118 PPHYSICAL_DEVICE_EXTENSION 12119 ClassRemoveChild( 12120 IN PFUNCTIONAL_DEVICE_EXTENSION Parent, 12121 IN PPHYSICAL_DEVICE_EXTENSION Child, 12122 IN BOOLEAN AcquireLock 12123 ) 12124 { 12125 if(AcquireLock) { 12126 ClassAcquireChildLock(Parent); 12127 } 12128 12129 TRY { 12130 PCOMMON_DEVICE_EXTENSION previousChild = &Parent->CommonExtension; 12131 12132 // 12133 // If the list is empty then bail out now. 12134 // 12135 12136 if(Parent->CommonExtension.ChildList == NULL) { 12137 Child = NULL; 12138 LEAVE; 12139 } 12140 12141 // 12142 // If the caller specified a child then find the child object before 12143 // it. If none was specified then the FDO is the child object before 12144 // the one we want to remove. 12145 // 12146 12147 if(Child != NULL) { 12148 12149 // 12150 // Scan through the child list to find the entry which points to 12151 // this one. 12152 // 12153 12154 do { 12155 NT_ASSERT(previousChild != &Child->CommonExtension); 12156 12157 if(previousChild->ChildList == Child) { 12158 break; 12159 } 12160 12161 previousChild = &previousChild->ChildList->CommonExtension; 12162 } while(previousChild != NULL); 12163 12164 if(previousChild == NULL) { 12165 Child = NULL; 12166 LEAVE; 12167 } 12168 } 12169 12170 // 12171 // Save the next child away then unlink it from the list. 12172 // 12173 12174 Child = previousChild->ChildList; 12175 previousChild->ChildList = Child->CommonExtension.ChildList; 12176 Child->CommonExtension.ChildList = NULL; 12177 12178 } FINALLY { 12179 if(AcquireLock) { 12180 ClassReleaseChildLock(Parent); 12181 } 12182 } 12183 return Child; 12184 } // end ClassRemoveChild() 12185 12186 12187 /*++ 12188 12189 ISSUE-2000/02/20-henrygab Not documented ClasspRetryRequestDpc 12190 12191 --*/ 12192 VOID 12193 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 12194 ClasspRetryRequestDpc( 12195 IN PKDPC Dpc, 12196 IN PVOID DeferredContext, 12197 IN PVOID Arg1, 12198 IN PVOID Arg2 12199 ) 12200 { 12201 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension; 12202 PCOMMON_DEVICE_EXTENSION commonExtension; 12203 PCLASS_PRIVATE_FDO_DATA fdoData; 12204 PCLASS_RETRY_INFO retryList; 12205 KIRQL irql; 12206 PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)DeferredContext; 12207 12208 UNREFERENCED_PARAMETER(Dpc); 12209 UNREFERENCED_PARAMETER(Arg1); 12210 UNREFERENCED_PARAMETER(Arg2); 12211 12212 if (DeferredContext == NULL) { 12213 NT_ASSERT(DeferredContext != NULL); 12214 return; 12215 } 12216 12217 commonExtension = DeviceObject->DeviceExtension; 12218 NT_ASSERT(commonExtension->IsFdo); 12219 fdoExtension = DeviceObject->DeviceExtension; 12220 fdoData = fdoExtension->PrivateFdoData; 12221 12222 12223 KeAcquireSpinLock(&fdoData->Retry.Lock, &irql); 12224 { 12225 LARGE_INTEGER now; 12226 KeQueryTickCount(&now); 12227 12228 // 12229 // if CurrentTick is less than now 12230 // fire another DPC 12231 // else 12232 // retry entire list 12233 // endif 12234 // 12235 12236 if (now.QuadPart < fdoData->Retry.Tick.QuadPart) { 12237 12238 ClasspRetryDpcTimer(fdoData); 12239 retryList = NULL; 12240 12241 } else { 12242 12243 retryList = fdoData->Retry.ListHead; 12244 fdoData->Retry.ListHead = NULL; 12245 fdoData->Retry.Delta.QuadPart = (LONGLONG)0; 12246 fdoData->Retry.Tick.QuadPart = (LONGLONG)0; 12247 12248 } 12249 } 12250 KeReleaseSpinLock(&fdoData->Retry.Lock, irql); 12251 12252 while (retryList != NULL) { 12253 12254 PIRP irp; 12255 12256 12257 irp = CONTAINING_RECORD(retryList, IRP, Tail.Overlay.DriverContext[0]); 12258 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "ClassRetry: -- %p\n", irp)); 12259 retryList = retryList->Next; 12260 #if DBG 12261 irp->Tail.Overlay.DriverContext[0] = ULongToPtr(0xdddddddd); // invalidate data 12262 irp->Tail.Overlay.DriverContext[1] = ULongToPtr(0xdddddddd); // invalidate data 12263 irp->Tail.Overlay.DriverContext[2] = ULongToPtr(0xdddddddd); // invalidate data 12264 irp->Tail.Overlay.DriverContext[3] = ULongToPtr(0xdddddddd); // invalidate data 12265 #endif 12266 12267 12268 if (NO_REMOVE == InterlockedCompareExchange((volatile LONG *)&commonExtension->IsRemoved, REMOVE_PENDING, REMOVE_PENDING)) { 12269 12270 IoCallDriver(commonExtension->LowerDeviceObject, irp); 12271 12272 } else { 12273 12274 PIO_STACK_LOCATION irpStack; 12275 12276 // 12277 // Ensure that we don't skip a completion routine (equivalent of sending down a request 12278 // to a device after it has received a remove and it completes the request. We need to 12279 // mimic that behavior here). 12280 // 12281 IoSetNextIrpStackLocation(irp); 12282 12283 irpStack = IoGetCurrentIrpStackLocation(irp); 12284 12285 if (irpStack->MajorFunction == IRP_MJ_SCSI) { 12286 12287 PSCSI_REQUEST_BLOCK srb = irpStack->Parameters.Scsi.Srb; 12288 12289 if (srb) { 12290 srb->SrbStatus = SRB_STATUS_NO_DEVICE; 12291 } 12292 } 12293 12294 // 12295 // Ensure that no retries will take place. This takes care of requests that are either 12296 // not IRP_MJ_SCSI or for ones where the SRB was passed in to the completion routine 12297 // as a context as opposed to an argument on the IRP stack location. 12298 // 12299 irpStack->Parameters.Others.Argument4 = (PVOID)0; 12300 12301 irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE; 12302 irp->IoStatus.Information = 0; 12303 IoCompleteRequest(irp, IO_NO_INCREMENT); 12304 } 12305 12306 } 12307 return; 12308 12309 } // end ClasspRetryRequestDpc() 12310 12311 /*++ 12312 12313 ISSUE-2000/02/20-henrygab Not documented ClassRetryRequest 12314 12315 --*/ 12316 VOID 12317 ClassRetryRequest( 12318 IN PDEVICE_OBJECT SelfDeviceObject, 12319 IN PIRP Irp, 12320 _In_ _In_range_(0,MAXIMUM_RETRY_FOR_SINGLE_IO_IN_100NS_UNITS) // 100 seconds; already an assert on this... 12321 IN LONGLONG TimeDelta100ns // in 100ns units 12322 ) 12323 { 12324 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension; 12325 PCLASS_PRIVATE_FDO_DATA fdoData; 12326 PCLASS_RETRY_INFO retryInfo; 12327 LARGE_INTEGER delta; 12328 KIRQL irql; 12329 12330 // 12331 // this checks we aren't destroying irps 12332 // 12333 NT_ASSERT(sizeof(CLASS_RETRY_INFO) <= (4*sizeof(PVOID))); 12334 12335 fdoExtension = SelfDeviceObject->DeviceExtension; 12336 12337 if (!fdoExtension->CommonExtension.IsFdo) { 12338 12339 // 12340 // this debug print/assertion should ALWAYS be investigated. 12341 // ClassRetryRequest can currently only be used by FDO's 12342 // 12343 12344 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "ClassRetryRequestEx: LOST IRP %p\n", Irp)); 12345 NT_ASSERT(!"ClassRetryRequestEx Called From PDO? LOST IRP"); 12346 return; 12347 12348 } 12349 12350 fdoData = fdoExtension->PrivateFdoData; 12351 12352 if (TimeDelta100ns < 0) { 12353 NT_ASSERT(!"ClassRetryRequest - must use positive delay"); 12354 TimeDelta100ns *= -1; 12355 } 12356 12357 /* 12358 * We are going to queue the irp and send it down in a timer DPC. 12359 * This means that we may be causing the irp to complete on a different thread than the issuing thread. 12360 * So mark the irp pending. 12361 */ 12362 IoMarkIrpPending(Irp); 12363 12364 // 12365 // prepare what we can out of the loop 12366 // 12367 12368 retryInfo = (PCLASS_RETRY_INFO)(&Irp->Tail.Overlay.DriverContext[0]); 12369 RtlZeroMemory(retryInfo, sizeof(CLASS_RETRY_INFO)); 12370 12371 delta.QuadPart = (TimeDelta100ns / fdoData->Retry.Granularity); 12372 if (TimeDelta100ns % fdoData->Retry.Granularity) { 12373 delta.QuadPart ++; // round up to next tick 12374 } 12375 if (delta.QuadPart == (LONGLONG)0) { 12376 delta.QuadPart = MINIMUM_RETRY_UNITS; 12377 } 12378 12379 // 12380 // now determine if we should fire another DPC or not 12381 // 12382 12383 KeAcquireSpinLock(&fdoData->Retry.Lock, &irql); 12384 12385 // 12386 // always add request to the list 12387 // 12388 12389 retryInfo->Next = fdoData->Retry.ListHead; 12390 fdoData->Retry.ListHead = retryInfo; 12391 12392 if (fdoData->Retry.Delta.QuadPart == (LONGLONG)0) { 12393 12394 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "ClassRetry: +++ %p\n", Irp)); 12395 12396 // 12397 // must be exactly one item on list 12398 // 12399 12400 NT_ASSERT(fdoData->Retry.ListHead != NULL); 12401 NT_ASSERT(fdoData->Retry.ListHead->Next == NULL); 12402 12403 // 12404 // if currentDelta is zero, always fire a DPC 12405 // 12406 12407 KeQueryTickCount(&fdoData->Retry.Tick); 12408 fdoData->Retry.Tick.QuadPart += delta.QuadPart; 12409 fdoData->Retry.Delta.QuadPart = delta.QuadPart; 12410 ClasspRetryDpcTimer(fdoData); 12411 12412 } else if (delta.QuadPart > fdoData->Retry.Delta.QuadPart) { 12413 12414 // 12415 // if delta is greater than the list's current delta, 12416 // increase the DPC handling time by difference 12417 // and update the delta to new larger value 12418 // allow the DPC to re-fire itself if needed 12419 // 12420 12421 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "ClassRetry: ++ %p\n", Irp)); 12422 12423 // 12424 // must be at least two items on list 12425 // 12426 12427 NT_ASSERT(fdoData->Retry.ListHead != NULL); 12428 NT_ASSERT(fdoData->Retry.ListHead->Next != NULL); 12429 12430 fdoData->Retry.Tick.QuadPart -= fdoData->Retry.Delta.QuadPart; 12431 fdoData->Retry.Tick.QuadPart += delta.QuadPart; 12432 12433 fdoData->Retry.Delta.QuadPart = delta.QuadPart; 12434 12435 } else { 12436 12437 // 12438 // just inserting it on the list was enough 12439 // 12440 12441 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "ClassRetry: ++ %p\n", Irp)); 12442 12443 } 12444 12445 12446 KeReleaseSpinLock(&fdoData->Retry.Lock, irql); 12447 12448 12449 } // end ClassRetryRequest() 12450 12451 /*++ 12452 12453 ISSUE-2000/02/20-henrygab Not documented ClasspRetryDpcTimer 12454 12455 --*/ 12456 VOID 12457 ClasspRetryDpcTimer( 12458 IN PCLASS_PRIVATE_FDO_DATA FdoData 12459 ) 12460 { 12461 LARGE_INTEGER fire; 12462 12463 NT_ASSERT(FdoData->Retry.Tick.QuadPart != (LONGLONG)0); 12464 NT_ASSERT(FdoData->Retry.ListHead != NULL); // never fire an empty list 12465 12466 // 12467 // fire == (CurrentTick - now) * (100ns per tick) 12468 // 12469 // NOTE: Overflow is nearly impossible and is ignored here 12470 // 12471 12472 KeQueryTickCount(&fire); 12473 fire.QuadPart = FdoData->Retry.Tick.QuadPart - fire.QuadPart; 12474 fire.QuadPart *= FdoData->Retry.Granularity; 12475 12476 // 12477 // fire is now multiples of 100ns until should fire the timer. 12478 // if timer should already have expired, or would fire too quickly, 12479 // fire it in some arbitrary number of ticks to prevent infinitely 12480 // recursing. 12481 // 12482 12483 if (fire.QuadPart < MINIMUM_RETRY_UNITS) { 12484 fire.QuadPart = MINIMUM_RETRY_UNITS; 12485 } 12486 12487 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, 12488 "ClassRetry: ======= %I64x ticks\n", 12489 fire.QuadPart)); 12490 12491 // 12492 // must use negative to specify relative time to fire 12493 // 12494 12495 fire.QuadPart = fire.QuadPart * ((LONGLONG)-1); 12496 12497 // 12498 // set the timer, since this is the first addition 12499 // 12500 12501 KeSetTimerEx(&FdoData->Retry.Timer, fire, 0, &FdoData->Retry.Dpc); 12502 12503 return; 12504 } // end ClasspRetryDpcTimer() 12505 12506 NTSTATUS 12507 ClasspInitializeHotplugInfo( 12508 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension 12509 ) 12510 { 12511 PCLASS_PRIVATE_FDO_DATA fdoData = FdoExtension->PrivateFdoData; 12512 DEVICE_REMOVAL_POLICY deviceRemovalPolicy = 0; 12513 NTSTATUS status; 12514 ULONG resultLength = 0; 12515 ULONG writeCacheOverride; 12516 12517 PAGED_CODE(); 12518 12519 // 12520 // start with some default settings 12521 // 12522 RtlZeroMemory(&(fdoData->HotplugInfo), sizeof(STORAGE_HOTPLUG_INFO)); 12523 12524 // 12525 // set the size (aka version) 12526 // 12527 12528 fdoData->HotplugInfo.Size = sizeof(STORAGE_HOTPLUG_INFO); 12529 12530 // 12531 // set if the device has removable media 12532 // 12533 12534 if (FdoExtension->DeviceDescriptor->RemovableMedia) { 12535 fdoData->HotplugInfo.MediaRemovable = TRUE; 12536 } else { 12537 fdoData->HotplugInfo.MediaRemovable = FALSE; 12538 } 12539 12540 // 12541 // this refers to devices which, for reasons not yet understood, 12542 // do not fail PREVENT_MEDIA_REMOVAL requests even though they 12543 // have no way to lock the media into the drive. this allows 12544 // the filesystems to turn off delayed-write caching for these 12545 // devices as well. 12546 // 12547 12548 if (TEST_FLAG(FdoExtension->PrivateFdoData->HackFlags, 12549 FDO_HACK_CANNOT_LOCK_MEDIA)) { 12550 fdoData->HotplugInfo.MediaHotplug = TRUE; 12551 } else { 12552 fdoData->HotplugInfo.MediaHotplug = FALSE; 12553 } 12554 12555 // 12556 // Query the default removal policy from the kernel 12557 // 12558 12559 status = IoGetDeviceProperty(FdoExtension->LowerPdo, 12560 DevicePropertyRemovalPolicy, 12561 sizeof(DEVICE_REMOVAL_POLICY), 12562 (PVOID)&deviceRemovalPolicy, 12563 &resultLength); 12564 if (!NT_SUCCESS(status)) { 12565 return status; 12566 } 12567 12568 if (resultLength != sizeof(DEVICE_REMOVAL_POLICY)) { 12569 return STATUS_UNSUCCESSFUL; 12570 } 12571 12572 // 12573 // Look into the registry to see if the user has chosen 12574 // to override the default setting for the removal policy. 12575 // User can override only if the default removal policy is 12576 // orderly or suprise removal. 12577 12578 if ((deviceRemovalPolicy == RemovalPolicyExpectOrderlyRemoval) || 12579 (deviceRemovalPolicy == RemovalPolicyExpectSurpriseRemoval)) { 12580 12581 DEVICE_REMOVAL_POLICY userRemovalPolicy = 0; 12582 12583 ClassGetDeviceParameter(FdoExtension, 12584 CLASSP_REG_SUBKEY_NAME, 12585 CLASSP_REG_REMOVAL_POLICY_VALUE_NAME, 12586 (PULONG)&userRemovalPolicy); 12587 12588 // 12589 // Validate the override value and use it only if it is an 12590 // allowed value. 12591 // 12592 if ((userRemovalPolicy == RemovalPolicyExpectOrderlyRemoval) || 12593 (userRemovalPolicy == RemovalPolicyExpectSurpriseRemoval)) { 12594 deviceRemovalPolicy = userRemovalPolicy; 12595 } 12596 } 12597 12598 // 12599 // use this info to set the DeviceHotplug setting 12600 // don't rely on DeviceCapabilities, since it can't properly 12601 // determine device relations, etc. let the kernel figure this 12602 // stuff out instead. 12603 // 12604 12605 if (deviceRemovalPolicy == RemovalPolicyExpectSurpriseRemoval) { 12606 fdoData->HotplugInfo.DeviceHotplug = TRUE; 12607 } else { 12608 fdoData->HotplugInfo.DeviceHotplug = FALSE; 12609 } 12610 12611 // 12612 // this refers to the *filesystem* caching, but has to be included 12613 // here since it's a per-device setting. this may change to be 12614 // stored by the system in the future. 12615 // 12616 12617 writeCacheOverride = FALSE; 12618 ClassGetDeviceParameter(FdoExtension, 12619 CLASSP_REG_SUBKEY_NAME, 12620 CLASSP_REG_WRITE_CACHE_VALUE_NAME, 12621 &writeCacheOverride); 12622 12623 if (writeCacheOverride) { 12624 fdoData->HotplugInfo.WriteCacheEnableOverride = TRUE; 12625 } else { 12626 fdoData->HotplugInfo.WriteCacheEnableOverride = FALSE; 12627 } 12628 12629 return STATUS_SUCCESS; 12630 } 12631 12632 VOID 12633 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 12634 ClasspScanForClassHacks( 12635 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, 12636 IN ULONG_PTR Data 12637 ) 12638 { 12639 PAGED_CODE(); 12640 12641 // 12642 // remove invalid flags and save 12643 // 12644 12645 CLEAR_FLAG(Data, FDO_HACK_INVALID_FLAGS); 12646 SET_FLAG(FdoExtension->PrivateFdoData->HackFlags, Data); 12647 return; 12648 } 12649 12650 VOID 12651 ClasspScanForSpecialInRegistry( 12652 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension 12653 ) 12654 { 12655 HANDLE deviceParameterHandle; // device instance key 12656 HANDLE classParameterHandle; // classpnp subkey 12657 OBJECT_ATTRIBUTES objectAttributes = {0}; 12658 UNICODE_STRING subkeyName; 12659 NTSTATUS status; 12660 12661 // 12662 // seeded in the ENUM tree by ClassInstaller 12663 // 12664 ULONG deviceHacks; 12665 RTL_QUERY_REGISTRY_TABLE queryTable[2] = {0}; // null terminated array 12666 12667 PAGED_CODE(); 12668 12669 deviceParameterHandle = NULL; 12670 classParameterHandle = NULL; 12671 deviceHacks = 0; 12672 12673 status = IoOpenDeviceRegistryKey(FdoExtension->LowerPdo, 12674 PLUGPLAY_REGKEY_DEVICE, 12675 KEY_WRITE, 12676 &deviceParameterHandle 12677 ); 12678 12679 if (!NT_SUCCESS(status)) { 12680 goto cleanupScanForSpecial; 12681 } 12682 12683 RtlInitUnicodeString(&subkeyName, CLASSP_REG_SUBKEY_NAME); 12684 InitializeObjectAttributes(&objectAttributes, 12685 &subkeyName, 12686 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 12687 deviceParameterHandle, 12688 NULL 12689 ); 12690 12691 status = ZwOpenKey( &classParameterHandle, 12692 KEY_READ, 12693 &objectAttributes 12694 ); 12695 12696 if (!NT_SUCCESS(status)) { 12697 goto cleanupScanForSpecial; 12698 } 12699 12700 // 12701 // Setup the structure to read 12702 // 12703 12704 queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_TYPECHECK; 12705 queryTable[0].Name = CLASSP_REG_HACK_VALUE_NAME; 12706 queryTable[0].EntryContext = &deviceHacks; 12707 queryTable[0].DefaultType = (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_DWORD; 12708 queryTable[0].DefaultData = &deviceHacks; 12709 queryTable[0].DefaultLength = 0; 12710 12711 // 12712 // read values 12713 // 12714 12715 status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, 12716 (PWSTR)classParameterHandle, 12717 &queryTable[0], 12718 NULL, 12719 NULL 12720 ); 12721 if (!NT_SUCCESS(status)) { 12722 goto cleanupScanForSpecial; 12723 } 12724 12725 // 12726 // remove unknown values and save... 12727 // 12728 12729 CLEAR_FLAG(deviceHacks, FDO_HACK_INVALID_FLAGS); 12730 SET_FLAG(FdoExtension->PrivateFdoData->HackFlags, deviceHacks); 12731 12732 12733 cleanupScanForSpecial: 12734 12735 if (deviceParameterHandle) { 12736 ZwClose(deviceParameterHandle); 12737 } 12738 12739 if (classParameterHandle) { 12740 ZwClose(classParameterHandle); 12741 } 12742 12743 // 12744 // we should modify the system hive to include another key for us to grab 12745 // settings from. in this case: Classpnp\HackFlags 12746 // 12747 // the use of a DWORD value for the HackFlags allows 32 hacks w/o 12748 // significant use of the registry, and also reduces OEM exposure. 12749 // 12750 // definition of bit flags: 12751 // 0x00000001 -- Device succeeds PREVENT_MEDIUM_REMOVAL, but 12752 // cannot actually prevent removal. 12753 // 0x00000002 -- Device hard-hangs or times out for GESN requests. 12754 // 0xfffffffc -- Currently reserved, may be used later. 12755 // 12756 12757 return; 12758 } 12759 12760 /*++//////////////////////////////////////////////////////////////////////////// 12761 12762 ClasspUpdateDiskProperties() 12763 12764 Routine Description: 12765 12766 This routine will send IOCTL_DISK_UPDATE_PROPERTIES to top of stack - Partition Manager 12767 to invalidate the cached geometry. 12768 12769 Arguments: 12770 12771 Fdo - The device object whose capacity needs to be verified. 12772 12773 Return Value: 12774 12775 NTSTATUS 12776 12777 --*/ 12778 12779 VOID 12780 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 12781 ClasspUpdateDiskProperties( 12782 IN PDEVICE_OBJECT Fdo, 12783 IN PVOID Context 12784 ) 12785 { 12786 PDEVICE_OBJECT topOfStack; 12787 IO_STATUS_BLOCK ioStatus; 12788 NTSTATUS status = STATUS_SUCCESS; 12789 KEVENT event; 12790 PIRP irp = NULL; 12791 PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension; 12792 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData; 12793 PIO_WORKITEM WorkItem = (PIO_WORKITEM)Context; 12794 12795 KeInitializeEvent(&event, SynchronizationEvent, FALSE); 12796 12797 topOfStack = IoGetAttachedDeviceReference(Fdo); 12798 12799 // 12800 // Send down irp to update properties 12801 // 12802 12803 irp = IoBuildDeviceIoControlRequest( 12804 IOCTL_DISK_UPDATE_PROPERTIES, 12805 topOfStack, 12806 NULL, 12807 0, 12808 NULL, 12809 0, 12810 FALSE, 12811 &event, 12812 &ioStatus); 12813 12814 if (irp != NULL) { 12815 12816 12817 status = IoCallDriver(topOfStack, irp); 12818 if (status == STATUS_PENDING) { 12819 (VOID)KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); 12820 status = ioStatus.Status; 12821 } 12822 12823 } else { 12824 status = STATUS_INSUFFICIENT_RESOURCES; 12825 } 12826 12827 InterlockedExchange((volatile LONG *)&fdoData->UpdateDiskPropertiesWorkItemActive, 0); 12828 12829 if (!NT_SUCCESS(status)) { 12830 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, "ClasspUpdateDiskProperties: Disk property update for fdo %p failed with status 0x%X.\n", Fdo, status)); 12831 } else { 12832 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, "ClasspUpdateDiskProperties: Drive capacity has changed for %p.\n", Fdo)); 12833 } 12834 ObDereferenceObject(topOfStack); 12835 12836 if (WorkItem != NULL) { 12837 IoFreeWorkItem(WorkItem); 12838 } 12839 12840 return; 12841 } 12842 12843 BOOLEAN 12844 InterpretSenseInfoWithoutHistory( 12845 _In_ PDEVICE_OBJECT Fdo, 12846 _In_opt_ PIRP OriginalRequest, 12847 _In_ PSCSI_REQUEST_BLOCK Srb, 12848 UCHAR MajorFunctionCode, 12849 ULONG IoDeviceCode, 12850 ULONG PreviousRetryCount, 12851 _Out_ NTSTATUS * Status, 12852 _Out_opt_ _Deref_out_range_(0,MAXIMUM_RETRY_FOR_SINGLE_IO_IN_100NS_UNITS) 12853 LONGLONG * RetryIn100nsUnits 12854 ) 12855 { 12856 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; 12857 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData; 12858 LONGLONG tmpRetry = 0; 12859 BOOLEAN retry = FALSE; 12860 12861 if (fdoData->InterpretSenseInfo != NULL) 12862 { 12863 SCSI_REQUEST_BLOCK tempSrb = {0}; 12864 PSCSI_REQUEST_BLOCK srbPtr = Srb; 12865 12866 // SAL annotations and ClassInitializeEx() both validate this 12867 NT_ASSERT(fdoData->InterpretSenseInfo->Interpret != NULL); 12868 12869 // 12870 // If class driver does not support extended SRB and this is 12871 // an extended SRB, convert to legacy SRB and pass to class 12872 // driver. 12873 // 12874 if ((Srb->Function == SRB_FUNCTION_STORAGE_REQUEST_BLOCK) && 12875 ((fdoExtension->CommonExtension.DriverExtension->SrbSupport & 12876 CLASS_SRB_STORAGE_REQUEST_BLOCK) == 0)) { 12877 ClasspConvertToScsiRequestBlock(&tempSrb, (PSTORAGE_REQUEST_BLOCK)Srb); 12878 srbPtr = &tempSrb; 12879 } 12880 12881 retry = fdoData->InterpretSenseInfo->Interpret(Fdo, 12882 OriginalRequest, 12883 srbPtr, 12884 MajorFunctionCode, 12885 IoDeviceCode, 12886 PreviousRetryCount, 12887 NULL, 12888 Status, 12889 &tmpRetry); 12890 } 12891 else 12892 { 12893 ULONG seconds = 0; 12894 12895 retry = ClassInterpretSenseInfo(Fdo, 12896 Srb, 12897 MajorFunctionCode, 12898 IoDeviceCode, 12899 PreviousRetryCount, 12900 Status, 12901 &seconds); 12902 tmpRetry = ((LONGLONG)seconds) * 1000 * 1000 * 10; 12903 } 12904 12905 12906 if (RetryIn100nsUnits != NULL) 12907 { 12908 *RetryIn100nsUnits = tmpRetry; 12909 } 12910 return retry; 12911 } 12912 12913 VOID 12914 ClasspGetInquiryVpdSupportInfo( 12915 _Inout_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension 12916 ) 12917 { 12918 NTSTATUS status; 12919 PCOMMON_DEVICE_EXTENSION commonExtension = (PCOMMON_DEVICE_EXTENSION)FdoExtension; 12920 SCSI_REQUEST_BLOCK srb = {0}; 12921 PCDB cdb; 12922 PVPD_SUPPORTED_PAGES_PAGE supportedPages = NULL; 12923 UCHAR bufferLength = VPD_MAX_BUFFER_SIZE; 12924 ULONG allocationBufferLength = bufferLength; 12925 UCHAR srbExBuffer[CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE] = {0}; 12926 PSTORAGE_REQUEST_BLOCK_HEADER srbHeader; 12927 12928 #if defined(_ARM_) || defined(_ARM64_) 12929 // 12930 // ARM has specific alignment requirements, although this will not have a functional impact on x86 or amd64 12931 // based platforms. We are taking the conservative approach here. 12932 // 12933 allocationBufferLength = ALIGN_UP_BY(allocationBufferLength,KeGetRecommendedSharedDataAlignment()); 12934 supportedPages = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned, 12935 allocationBufferLength, 12936 '3CcS' 12937 ); 12938 12939 #else 12940 supportedPages = ExAllocatePoolWithTag(NonPagedPoolNx, 12941 bufferLength, 12942 '3CcS' 12943 ); 12944 #endif 12945 12946 if (supportedPages == NULL) { 12947 // memory allocation failure. 12948 return; 12949 } 12950 12951 RtlZeroMemory(supportedPages, allocationBufferLength); 12952 12953 // prepare the Srb 12954 if (FdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { 12955 12956 #ifdef _MSC_VER 12957 #pragma prefast(suppress:26015, "InitializeStorageRequestBlock ensures buffer access is bounded") 12958 #endif 12959 status = InitializeStorageRequestBlock((PSTORAGE_REQUEST_BLOCK)srbExBuffer, 12960 STORAGE_ADDRESS_TYPE_BTL8, 12961 sizeof(srbExBuffer), 12962 1, 12963 SrbExDataTypeScsiCdb16); 12964 12965 if (!NT_SUCCESS(status)) { 12966 // 12967 // Should not happen. Revert to legacy SRB. 12968 NT_ASSERT(FALSE); 12969 srb.Length = SCSI_REQUEST_BLOCK_SIZE; 12970 srb.Function = SRB_FUNCTION_EXECUTE_SCSI; 12971 srbHeader = (PSTORAGE_REQUEST_BLOCK_HEADER)&srb; 12972 } else { 12973 ((PSTORAGE_REQUEST_BLOCK)srbExBuffer)->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI; 12974 srbHeader = (PSTORAGE_REQUEST_BLOCK_HEADER)srbExBuffer; 12975 } 12976 12977 } else { 12978 srb.Length = SCSI_REQUEST_BLOCK_SIZE; 12979 srb.Function = SRB_FUNCTION_EXECUTE_SCSI; 12980 srbHeader = (PSTORAGE_REQUEST_BLOCK_HEADER)&srb; 12981 } 12982 12983 SrbSetTimeOutValue(srbHeader, FdoExtension->TimeOutValue); 12984 SrbSetRequestTag(srbHeader, SP_UNTAGGED); 12985 SrbSetRequestAttribute(srbHeader, SRB_SIMPLE_TAG_REQUEST); 12986 SrbAssignSrbFlags(srbHeader, FdoExtension->SrbFlags); 12987 SrbSetCdbLength(srbHeader, 6); 12988 12989 cdb = SrbGetCdb(srbHeader); 12990 cdb->CDB6INQUIRY3.OperationCode = SCSIOP_INQUIRY; 12991 cdb->CDB6INQUIRY3.EnableVitalProductData = 1; //EVPD bit 12992 cdb->CDB6INQUIRY3.PageCode = VPD_SUPPORTED_PAGES; 12993 cdb->CDB6INQUIRY3.AllocationLength = bufferLength; //AllocationLength field in CDB6INQUIRY3 is only one byte. 12994 12995 status = ClassSendSrbSynchronous(commonExtension->DeviceObject, 12996 (PSCSI_REQUEST_BLOCK)srbHeader, 12997 supportedPages, 12998 allocationBufferLength, 12999 FALSE); 13000 13001 // 13002 // Handle the case where we get back STATUS_DATA_OVERRUN b/c the input 13003 // buffer was larger than necessary. 13004 // 13005 if (status == STATUS_DATA_OVERRUN && SrbGetDataTransferLength(srbHeader) < bufferLength) 13006 { 13007 status = STATUS_SUCCESS; 13008 } 13009 13010 if ( NT_SUCCESS(status) && 13011 (supportedPages->PageLength > 0) && 13012 (supportedPages->SupportedPageList[0] > 0) ) { 13013 // ataport treats all INQUIRY command as standard INQUIRY command, thus fills invalid info 13014 // If VPD INQUIRY is supported, the first page reported (additional length field for standard INQUIRY data) should be '00' 13015 status = STATUS_NOT_SUPPORTED; 13016 } 13017 13018 if (NT_SUCCESS(status)) { 13019 int i; 13020 13021 for (i = 0; i < supportedPages->PageLength; i++) { 13022 if ( (i > 0) && (supportedPages->SupportedPageList[i] <= supportedPages->SupportedPageList[i - 1]) ) { 13023 // shall be in ascending order beginning with page code 00h. 13024 FdoExtension->FunctionSupportInfo->ValidInquiryPages.BlockDeviceRODLimits = FALSE; 13025 FdoExtension->FunctionSupportInfo->ValidInquiryPages.BlockLimits = FALSE; 13026 FdoExtension->FunctionSupportInfo->ValidInquiryPages.BlockDeviceCharacteristics = FALSE; 13027 FdoExtension->FunctionSupportInfo->ValidInquiryPages.LBProvisioning = FALSE; 13028 13029 13030 break; 13031 } 13032 switch (supportedPages->SupportedPageList[i]) { 13033 case VPD_THIRD_PARTY_COPY: 13034 FdoExtension->FunctionSupportInfo->ValidInquiryPages.BlockDeviceRODLimits = TRUE; 13035 break; 13036 13037 case VPD_BLOCK_LIMITS: 13038 FdoExtension->FunctionSupportInfo->ValidInquiryPages.BlockLimits = TRUE; 13039 break; 13040 13041 case VPD_BLOCK_DEVICE_CHARACTERISTICS: 13042 FdoExtension->FunctionSupportInfo->ValidInquiryPages.BlockDeviceCharacteristics = TRUE; 13043 break; 13044 13045 case VPD_LOGICAL_BLOCK_PROVISIONING: 13046 FdoExtension->FunctionSupportInfo->ValidInquiryPages.LBProvisioning = TRUE; 13047 break; 13048 13049 } 13050 } 13051 } 13052 13053 ExFreePool(supportedPages); 13054 13055 return; 13056 } 13057 13058 // 13059 // ClasspGetLBProvisioningInfo 13060 // 13061 // Description: This function does the work to get Logical Block Provisioning 13062 // (LBP) info for a given LUN, including UNMAP support and parameters. It 13063 // will attempt to get both the Logical Block Provisioning (0xB2) VPD page 13064 // and the Block Limits (0xB0) VPD page and cache the relevant values in 13065 // the given FDO extension. 13066 // 13067 // After calling this function, you can use the ClasspIsThinProvisioned() 13068 // function to determine if the device is thinly provisioned and the 13069 // ClasspSupportsUnmap() function to determine if the device supports the 13070 // UNMAP command. 13071 // 13072 // Arguments: 13073 // - FdoExtension: The FDO extension associated with the LUN for which Thin 13074 // Provisioning info is desired. The Thin Provisioning info is stored 13075 // in the FunctionSupportInfo member of this FDO extension. 13076 // 13077 // Returns: 13078 // - STATUS_INVALID_PARAMETER if the given FDO extension has not been 13079 // allocated properly. 13080 // - STATUS_INSUFFICIENT_RESOURCES if this function was unable to allocate 13081 // an SRB used to get the necessary VPD pages. 13082 // - STATUS_SUCCESS in all other cases. If any of the incidental functions 13083 // don't return STATUS_SUCCESS this function will just assume Thin 13084 // Provisioning is not enabled and return STATUS_SUCCESS. 13085 // 13086 NTSTATUS 13087 ClasspGetLBProvisioningInfo( 13088 _Inout_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension 13089 ) 13090 { 13091 PSCSI_REQUEST_BLOCK srb = NULL; 13092 ULONG srbSize = 0; 13093 13094 // 13095 // Make sure we actually have data structures to work with. 13096 // 13097 if (FdoExtension == NULL || 13098 FdoExtension->FunctionSupportInfo == NULL) { 13099 return STATUS_INVALID_PARAMETER; 13100 } 13101 13102 // 13103 // Allocate an SRB for querying the device for LBP-related info if either 13104 // the Logical Block Provisioning (0xB2) or Block Limits (0xB0) VPD page 13105 // exists. 13106 // 13107 if ((FdoExtension->FunctionSupportInfo->ValidInquiryPages.LBProvisioning == TRUE) || 13108 (FdoExtension->FunctionSupportInfo->ValidInquiryPages.BlockLimits == TRUE)) { 13109 13110 if ((FdoExtension->AdapterDescriptor != NULL) && 13111 (FdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK)) { 13112 srbSize = CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE; 13113 } else { 13114 srbSize = sizeof(SCSI_REQUEST_BLOCK); 13115 } 13116 13117 srb = ExAllocatePoolWithTag(NonPagedPoolNx, srbSize, '0DcS'); 13118 13119 if (srb == NULL) { 13120 return STATUS_INSUFFICIENT_RESOURCES; 13121 } 13122 } 13123 13124 // 13125 // Get the Logical Block Provisioning VPD page (0xB2). This function will 13126 // set some default values if the LBP VPD page is not supported. 13127 // 13128 ClasspDeviceGetLBProvisioningVPDPage(FdoExtension->DeviceObject, srb); 13129 13130 13131 // 13132 // Get the Block Limits VPD page (0xB0), which may override the default 13133 // UNMAP parameter values set above. 13134 // 13135 ClasspDeviceGetBlockLimitsVPDPage(FdoExtension, 13136 srb, 13137 srbSize, 13138 &FdoExtension->FunctionSupportInfo->BlockLimitsData); 13139 13140 FREE_POOL(srb); 13141 13142 return STATUS_SUCCESS; 13143 } 13144 13145 13146 13147 _IRQL_requires_(PASSIVE_LEVEL) 13148 _IRQL_requires_same_ 13149 NTSTATUS 13150 ClassDetermineTokenOperationCommandSupport( 13151 _In_ PDEVICE_OBJECT DeviceObject 13152 ) 13153 13154 /*++ 13155 13156 Routine Description: 13157 13158 This routine determines if Token Operation and Receive ROD Token Information commands 13159 are supported by this device and updates the internal structures to reflect this. 13160 In addition, it also queries the registry to determine the maximum listIdentifier 13161 to use for TokenOperation commands. 13162 13163 This function must be called at IRQL == PASSIVE_LEVEL. 13164 13165 Arguments: 13166 13167 DeviceObject - The device object for which we want to determine command support. 13168 13169 Return Value: 13170 13171 Nothing 13172 13173 --*/ 13174 13175 { 13176 NTSTATUS status = STATUS_SUCCESS; 13177 13178 PAGED_CODE(); 13179 13180 TracePrint((TRACE_LEVEL_VERBOSE, 13181 TRACE_FLAG_PNP, 13182 "ClassDetermineTokenOperationCommandSupport (%p): Entering function.\n", 13183 DeviceObject)); 13184 13185 // 13186 // Send down Inquiry for VPD_THIRD_PARTY_COPY_PAGE and cache away the device parameters 13187 // from WINDOWS_BLOCK_DEVICE_TOKEN_LIMITS_DESCRIPTOR. 13188 // 13189 status = ClasspGetBlockDeviceTokenLimitsInfo(DeviceObject); 13190 13191 if (NT_SUCCESS(status)) { 13192 13193 ULONG maxListIdentifier = MaxTokenOperationListIdentifier; 13194 13195 // 13196 // Query the maximum list identifier to use for TokenOperation commands. 13197 // 13198 if (NT_SUCCESS(ClasspGetMaximumTokenListIdentifier(DeviceObject, REG_DISK_CLASS_CONTROL, &maxListIdentifier))) { 13199 if (maxListIdentifier >= MIN_TOKEN_LIST_IDENTIFIERS) { 13200 13201 NT_ASSERT(maxListIdentifier <= MAX_TOKEN_LIST_IDENTIFIERS); 13202 MaxTokenOperationListIdentifier = maxListIdentifier; 13203 } 13204 } 13205 13206 } 13207 13208 TracePrint((TRACE_LEVEL_VERBOSE, 13209 TRACE_FLAG_PNP, 13210 "ClassDetermineTokenOperationCommandSupport (%p): Exiting function with status %x.\n", 13211 DeviceObject, 13212 status)); 13213 13214 return status; 13215 } 13216 13217 13218 _IRQL_requires_same_ 13219 NTSTATUS 13220 ClasspGetBlockDeviceTokenLimitsInfo( 13221 _Inout_ PDEVICE_OBJECT DeviceObject 13222 ) 13223 13224 /*++ 13225 13226 Routine Description: 13227 13228 This routine does the work to get the Block Device Token Limits info for a given LUN. 13229 This is done by sending Inquiry for the Third Party Copy VPD page. 13230 13231 Arguments: 13232 13233 DeviceObject - The FDO associated with the LUN for which Block Device Token 13234 limits info is desired. 13235 13236 Return Value: 13237 13238 STATUS_DEVICE_FEATURE_NOT_SUPPORTED if either the Inquiry fails or validations fail. 13239 STATUS_SUCCESS otherwise. 13240 13241 --*/ 13242 13243 { 13244 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; 13245 NTSTATUS status; 13246 PSCSI_REQUEST_BLOCK srb = NULL; 13247 ULONG srbSize = 0; 13248 USHORT pageLength = 0; 13249 USHORT descriptorLength = 0; 13250 PVOID dataBuffer = NULL; 13251 UCHAR bufferLength = VPD_MAX_BUFFER_SIZE; 13252 ULONG allocationBufferLength = bufferLength; 13253 PCDB cdb; 13254 ULONG dataTransferLength = 0; 13255 PVPD_THIRD_PARTY_COPY_PAGE operatingParameters = NULL; 13256 PWINDOWS_BLOCK_DEVICE_TOKEN_LIMITS_DESCRIPTOR blockDeviceTokenLimits = NULL; 13257 13258 TracePrint((TRACE_LEVEL_VERBOSE, 13259 TRACE_FLAG_PNP, 13260 "ClasspGetBlockDeviceTokenLimitsInfo (%p): Entering function.\n", 13261 DeviceObject)); 13262 13263 // 13264 // Allocate an SRB for querying the device for LBP-related info. 13265 // 13266 if ((fdoExtension->AdapterDescriptor != NULL) && 13267 (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK)) { 13268 srbSize = CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE; 13269 } else { 13270 srbSize = sizeof(SCSI_REQUEST_BLOCK); 13271 } 13272 13273 srb = ExAllocatePoolWithTag(NonPagedPoolNx, srbSize, CLASSPNP_POOL_TAG_SRB); 13274 13275 if (!srb) { 13276 13277 TracePrint((TRACE_LEVEL_ERROR, 13278 TRACE_FLAG_PNP, 13279 "ClasspGetBlockDeviceTokenLimitsInfo (%p): Couldn't allocate SRB.\n", 13280 DeviceObject)); 13281 13282 status = STATUS_INSUFFICIENT_RESOURCES; 13283 goto __ClasspGetBlockDeviceTokenLimitsInfo_Exit; 13284 } 13285 13286 #if defined(_ARM_) || defined(_ARM64_) 13287 // 13288 // ARM has specific alignment requirements, although this will not have a functional impact on x86 or amd64 13289 // based platforms. We are taking the conservative approach here. 13290 // 13291 allocationBufferLength = ALIGN_UP_BY(allocationBufferLength, KeGetRecommendedSharedDataAlignment()); 13292 dataBuffer = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned, allocationBufferLength, CLASSPNP_POOL_TAG_VPD); 13293 #else 13294 dataBuffer = ExAllocatePoolWithTag(NonPagedPoolNx, bufferLength, CLASSPNP_POOL_TAG_VPD); 13295 #endif 13296 13297 if (!dataBuffer) { 13298 13299 TracePrint((TRACE_LEVEL_ERROR, 13300 TRACE_FLAG_PNP, 13301 "ClasspGetBlockDeviceTokenLimitsInfo (%p): Couldn't allocate dataBuffer.\n", 13302 DeviceObject)); 13303 13304 status = STATUS_INSUFFICIENT_RESOURCES; 13305 goto __ClasspGetBlockDeviceTokenLimitsInfo_Exit; 13306 } 13307 13308 operatingParameters = (PVPD_THIRD_PARTY_COPY_PAGE)dataBuffer; 13309 13310 RtlZeroMemory(dataBuffer, allocationBufferLength); 13311 13312 if ((fdoExtension->AdapterDescriptor != NULL) && 13313 (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK)) { 13314 status = InitializeStorageRequestBlock((PSTORAGE_REQUEST_BLOCK)srb, 13315 STORAGE_ADDRESS_TYPE_BTL8, 13316 CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE, 13317 1, 13318 SrbExDataTypeScsiCdb16); 13319 if (NT_SUCCESS(status)) { 13320 13321 ((PSTORAGE_REQUEST_BLOCK)srb)->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI; 13322 13323 } else { 13324 13325 // 13326 // Should not occur. Revert to legacy SRB. 13327 // 13328 NT_ASSERT(FALSE); 13329 13330 TracePrint((TRACE_LEVEL_WARNING, 13331 TRACE_FLAG_PNP, 13332 "ClasspGetBlockDeviceTokenLimitsInfo (%p): Falling back to using SRB (instead of SRB_EX).\n", 13333 DeviceObject)); 13334 13335 RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK)); 13336 srb->Length = sizeof(SCSI_REQUEST_BLOCK); 13337 srb->Function = SRB_FUNCTION_EXECUTE_SCSI; 13338 } 13339 } else { 13340 13341 RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK)); 13342 srb->Length = sizeof(SCSI_REQUEST_BLOCK); 13343 srb->Function = SRB_FUNCTION_EXECUTE_SCSI; 13344 } 13345 13346 SrbSetTimeOutValue(srb, fdoExtension->TimeOutValue); 13347 SrbSetRequestTag(srb, SP_UNTAGGED); 13348 SrbSetRequestAttribute(srb, SRB_SIMPLE_TAG_REQUEST); 13349 SrbAssignSrbFlags(srb, fdoExtension->SrbFlags); 13350 13351 SrbSetCdbLength(srb, 6); 13352 13353 cdb = SrbGetCdb(srb); 13354 cdb->CDB6INQUIRY3.OperationCode = SCSIOP_INQUIRY; 13355 cdb->CDB6INQUIRY3.EnableVitalProductData = 1; 13356 cdb->CDB6INQUIRY3.PageCode = VPD_THIRD_PARTY_COPY; 13357 cdb->CDB6INQUIRY3.AllocationLength = bufferLength; 13358 13359 status = ClassSendSrbSynchronous(fdoExtension->DeviceObject, 13360 srb, 13361 dataBuffer, 13362 allocationBufferLength, 13363 FALSE); 13364 13365 // 13366 // Handle the case where we get back STATUS_DATA_OVERRUN because the input 13367 // buffer was larger than necessary. 13368 // 13369 dataTransferLength = SrbGetDataTransferLength(srb); 13370 13371 if (status == STATUS_DATA_OVERRUN && dataTransferLength < bufferLength) { 13372 13373 status = STATUS_SUCCESS; 13374 } 13375 13376 if (NT_SUCCESS(status)) { 13377 13378 REVERSE_BYTES_SHORT(&pageLength, &operatingParameters->PageLength); 13379 13380 } else { 13381 TracePrint((TRACE_LEVEL_ERROR, 13382 TRACE_FLAG_PNP, 13383 "ClasspGetBlockDeviceTokenLimitsInfo (%p): Inquiry for TPC VPD failed with %x.\n", 13384 DeviceObject, 13385 status)); 13386 } 13387 13388 if ((NT_SUCCESS(status)) && 13389 (pageLength >= sizeof(WINDOWS_BLOCK_DEVICE_TOKEN_LIMITS_DESCRIPTOR))) { 13390 13391 USHORT descriptorType; 13392 13393 blockDeviceTokenLimits = (PWINDOWS_BLOCK_DEVICE_TOKEN_LIMITS_DESCRIPTOR)operatingParameters->ThirdPartyCopyDescriptors; 13394 REVERSE_BYTES_SHORT(&descriptorType, &blockDeviceTokenLimits->DescriptorType); 13395 REVERSE_BYTES_SHORT(&descriptorLength, &blockDeviceTokenLimits->DescriptorLength); 13396 13397 if ((descriptorType == BLOCK_DEVICE_TOKEN_LIMITS_DESCRIPTOR_TYPE_WINDOWS) && 13398 (VPD_PAGE_HEADER_SIZE + descriptorLength == sizeof(WINDOWS_BLOCK_DEVICE_TOKEN_LIMITS_DESCRIPTOR))) { 13399 13400 fdoExtension->FunctionSupportInfo->ValidInquiryPages.BlockDeviceRODLimits = TRUE; 13401 13402 REVERSE_BYTES_SHORT(&fdoExtension->FunctionSupportInfo->BlockDeviceRODLimitsData.MaximumRangeDescriptors, &blockDeviceTokenLimits->MaximumRangeDescriptors); 13403 REVERSE_BYTES(&fdoExtension->FunctionSupportInfo->BlockDeviceRODLimitsData.MaximumInactivityTimer, &blockDeviceTokenLimits->MaximumInactivityTimer); 13404 REVERSE_BYTES(&fdoExtension->FunctionSupportInfo->BlockDeviceRODLimitsData.DefaultInactivityTimer, &blockDeviceTokenLimits->DefaultInactivityTimer); 13405 REVERSE_BYTES_QUAD(&fdoExtension->FunctionSupportInfo->BlockDeviceRODLimitsData.MaximumTokenTransferSize, &blockDeviceTokenLimits->MaximumTokenTransferSize); 13406 REVERSE_BYTES_QUAD(&fdoExtension->FunctionSupportInfo->BlockDeviceRODLimitsData.OptimalTransferCount, &blockDeviceTokenLimits->OptimalTransferCount); 13407 13408 TracePrint((TRACE_LEVEL_INFORMATION, 13409 TRACE_FLAG_PNP, 13410 "ClasspGetBlockDeviceTokenLimitsInfo (%p): %s %s (rev %s) reported following parameters: \ 13411 \n\t\t\tMaxRangeDescriptors: %u\n\t\t\tMaxIAT: %u\n\t\t\tDefaultIAT: %u \ 13412 \n\t\t\tMaxTokenTransferSize: %I64u\n\t\t\tOptimalTransferCount: %I64u\n\t\t\tOptimalTransferLengthGranularity: %u \ 13413 \n\t\t\tOptimalTransferLength: %u\n\t\t\tMaxTransferLength: %u\n", 13414 DeviceObject, 13415 (PCSZ)(((PUCHAR)fdoExtension->DeviceDescriptor) + fdoExtension->DeviceDescriptor->VendorIdOffset), 13416 (PCSZ)(((PUCHAR)fdoExtension->DeviceDescriptor) + fdoExtension->DeviceDescriptor->ProductIdOffset), 13417 (PCSZ)(((PUCHAR)fdoExtension->DeviceDescriptor) + fdoExtension->DeviceDescriptor->ProductRevisionOffset), 13418 fdoExtension->FunctionSupportInfo->BlockDeviceRODLimitsData.MaximumRangeDescriptors, 13419 fdoExtension->FunctionSupportInfo->BlockDeviceRODLimitsData.MaximumInactivityTimer, 13420 fdoExtension->FunctionSupportInfo->BlockDeviceRODLimitsData.DefaultInactivityTimer, 13421 fdoExtension->FunctionSupportInfo->BlockDeviceRODLimitsData.MaximumTokenTransferSize, 13422 fdoExtension->FunctionSupportInfo->BlockDeviceRODLimitsData.OptimalTransferCount, 13423 fdoExtension->FunctionSupportInfo->BlockLimitsData.OptimalTransferLengthGranularity, 13424 fdoExtension->FunctionSupportInfo->BlockLimitsData.OptimalTransferLength, 13425 fdoExtension->FunctionSupportInfo->BlockLimitsData.MaximumTransferLength)); 13426 } else { 13427 13428 TracePrint((TRACE_LEVEL_WARNING, 13429 TRACE_FLAG_PNP, 13430 "ClasspGetBlockDeviceTokenLimitsInfo (%p): ThirdPartyCopy VPD data doesn't have Windows OffloadDataTransfer descriptor.\n", 13431 DeviceObject)); 13432 13433 fdoExtension->FunctionSupportInfo->ValidInquiryPages.BlockDeviceRODLimits = FALSE; 13434 status = STATUS_DEVICE_FEATURE_NOT_SUPPORTED; 13435 } 13436 } else { 13437 13438 TracePrint((TRACE_LEVEL_WARNING, 13439 TRACE_FLAG_PNP, 13440 "ClasspGetBlockDeviceTokenLimitsInfo (%p): TPC VPD data didn't return TPC descriptors of interest.\n", 13441 DeviceObject)); 13442 13443 fdoExtension->FunctionSupportInfo->ValidInquiryPages.BlockDeviceRODLimits = FALSE; 13444 status = STATUS_DEVICE_FEATURE_NOT_SUPPORTED; 13445 } 13446 13447 __ClasspGetBlockDeviceTokenLimitsInfo_Exit: 13448 13449 FREE_POOL(dataBuffer); 13450 FREE_POOL(srb); 13451 fdoExtension->FunctionSupportInfo->BlockDeviceRODLimitsData.CommandStatus = status; 13452 13453 TracePrint((TRACE_LEVEL_VERBOSE, 13454 TRACE_FLAG_PNP, 13455 "ClasspGetBlockDeviceTokenLimitsInfo (%p): Exiting function with status %x.\n", 13456 DeviceObject, 13457 status)); 13458 13459 return status; 13460 } 13461 13462 13463 _IRQL_requires_max_(APC_LEVEL) 13464 _IRQL_requires_min_(PASSIVE_LEVEL) 13465 _IRQL_requires_same_ 13466 NTSTATUS 13467 ClassDeviceProcessOffloadRead( 13468 _In_ PDEVICE_OBJECT DeviceObject, 13469 _In_ PIRP Irp, 13470 _Inout_ PSCSI_REQUEST_BLOCK Srb 13471 ) 13472 13473 /*++ 13474 13475 Routine Description: 13476 13477 This routine services IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES for CopyOffload 13478 Read. If the device supports copy offload, it performs the translation of the 13479 IOCTL into the appropriate SCSI commands to complete the operation. 13480 13481 This function must be called at IRQL < DISPATCH_LEVEL. 13482 13483 Arguments: 13484 13485 DeviceObject - Supplies the device object associated with this request 13486 Irp - The IRP to be processed 13487 Srb - An SRB that can be optimally used to process this request 13488 13489 Return Value: 13490 13491 NTSTATUS code 13492 13493 --*/ 13494 13495 { 13496 PIO_STACK_LOCATION irpStack; 13497 NTSTATUS status; 13498 PDEVICE_MANAGE_DATA_SET_ATTRIBUTES dsmAttributes; 13499 PDEVICE_DSM_OFFLOAD_READ_PARAMETERS offloadReadParameters; 13500 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension; 13501 13502 UNREFERENCED_PARAMETER(Srb); 13503 13504 // 13505 // This function must be called at less than dispatch level. 13506 // Fail if IRQL >= DISPATCH_LEVEL. 13507 // 13508 PAGED_CODE(); 13509 13510 TracePrint((TRACE_LEVEL_VERBOSE, 13511 TRACE_FLAG_IOCTL, 13512 "ClassDeviceProcessOffloadRead (%p): Entering function. Irp %p\n", 13513 DeviceObject, 13514 Irp)); 13515 13516 13517 irpStack = IoGetCurrentIrpStackLocation (Irp); 13518 13519 // 13520 // Validations 13521 // 13522 status = ClasspValidateOffloadSupported(DeviceObject, Irp); 13523 if (!NT_SUCCESS(status)) { 13524 goto __ClassDeviceProcessOffloadRead_CompleteAndExit; 13525 } 13526 13527 if (KeGetCurrentIrql() >= DISPATCH_LEVEL) { 13528 13529 NT_ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); 13530 TracePrint((TRACE_LEVEL_ERROR, 13531 TRACE_FLAG_IOCTL, 13532 "ClassDeviceProcessOffloadRead (%p): Called at raised IRQL.\n", 13533 DeviceObject)); 13534 13535 status = STATUS_INVALID_LEVEL; 13536 goto __ClassDeviceProcessOffloadRead_CompleteAndExit; 13537 } 13538 13539 // 13540 // Ensure that this DSM IOCTL was generated in kernel 13541 // 13542 if (Irp->RequestorMode != KernelMode) { 13543 13544 TracePrint((TRACE_LEVEL_ERROR, 13545 TRACE_FLAG_IOCTL, 13546 "ClassDeviceProcessOffloadRead (%p): Called from user mode.\n", 13547 DeviceObject)); 13548 13549 status = STATUS_ACCESS_DENIED; 13550 goto __ClassDeviceProcessOffloadRead_CompleteAndExit; 13551 } 13552 13553 status = ClasspValidateOffloadInputParameters(DeviceObject, Irp); 13554 if (!NT_SUCCESS(status)) { 13555 goto __ClassDeviceProcessOffloadRead_CompleteAndExit; 13556 } 13557 13558 dsmAttributes = Irp->AssociatedIrp.SystemBuffer; 13559 13560 // 13561 // Validate that we were passed in correct sized parameter block. 13562 // 13563 if (dsmAttributes->ParameterBlockLength < sizeof(DEVICE_DSM_OFFLOAD_READ_PARAMETERS)) { 13564 13565 TracePrint((TRACE_LEVEL_ERROR, 13566 TRACE_FLAG_IOCTL, 13567 "ClassDeviceProcessOffloadRead (%p): Parameter block size (%u) too small. Required %u.\n", 13568 DeviceObject, 13569 dsmAttributes->ParameterBlockLength, 13570 sizeof(DEVICE_DSM_OFFLOAD_READ_PARAMETERS))); 13571 13572 status = STATUS_INVALID_PARAMETER; 13573 goto __ClassDeviceProcessOffloadRead_CompleteAndExit; 13574 } 13575 13576 offloadReadParameters = Add2Ptr(dsmAttributes, dsmAttributes->ParameterBlockOffset); 13577 13578 fdoExtension = DeviceObject->DeviceExtension; 13579 13580 // 13581 // If the request TTL is greater than the max supported by this storage, the target will 13582 // end up failing this command, so might as well do the check up front. 13583 // 13584 if ((fdoExtension->FunctionSupportInfo->BlockDeviceRODLimitsData.MaximumInactivityTimer > 0) && 13585 (offloadReadParameters->TimeToLive > fdoExtension->FunctionSupportInfo->BlockDeviceRODLimitsData.MaximumInactivityTimer)) { 13586 13587 TracePrint((TRACE_LEVEL_ERROR, 13588 TRACE_FLAG_IOCTL, 13589 "ClassDeviceProcessOffloadRead (%p): Requested TTL (%u) greater than max supported (%u).\n", 13590 DeviceObject, 13591 offloadReadParameters->TimeToLive, 13592 fdoExtension->FunctionSupportInfo->BlockDeviceRODLimitsData.MaximumInactivityTimer)); 13593 13594 status = STATUS_INVALID_PARAMETER; 13595 goto __ClassDeviceProcessOffloadRead_CompleteAndExit; 13596 } 13597 13598 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(STORAGE_OFFLOAD_READ_OUTPUT)) { 13599 13600 TracePrint((TRACE_LEVEL_ERROR, 13601 TRACE_FLAG_IOCTL, 13602 "ClassDeviceProcessOffloadRead (%p): Output buffer size (%u) too small.\n", 13603 DeviceObject, 13604 irpStack->Parameters.DeviceIoControl.OutputBufferLength)); 13605 13606 status = STATUS_BUFFER_TOO_SMALL; 13607 goto __ClassDeviceProcessOffloadRead_CompleteAndExit; 13608 } 13609 13610 13611 13612 status = ClasspServicePopulateTokenTransferRequest(DeviceObject, Irp); 13613 13614 if (status == STATUS_PENDING) { 13615 goto __ClassDeviceProcessOffloadRead_Exit; 13616 } 13617 13618 __ClassDeviceProcessOffloadRead_CompleteAndExit: 13619 ClasspCompleteOffloadRequest(DeviceObject, Irp, status); 13620 __ClassDeviceProcessOffloadRead_Exit: 13621 TracePrint((TRACE_LEVEL_VERBOSE, 13622 TRACE_FLAG_IOCTL, 13623 "ClassDeviceProcessOffloadRead (%p): Exiting function Irp %p with status %x.\n", 13624 DeviceObject, 13625 Irp, 13626 status)); 13627 13628 return status; 13629 } 13630 13631 VOID 13632 ClasspCompleteOffloadRequest( 13633 _In_ PDEVICE_OBJECT DeviceObject, 13634 _In_ PIRP Irp, 13635 _In_ NTSTATUS CompletionStatus) 13636 { 13637 NTSTATUS status = CompletionStatus; 13638 13639 13640 Irp->IoStatus.Status = status; 13641 13642 ClassReleaseRemoveLock(DeviceObject, Irp); 13643 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 13644 13645 return; 13646 } 13647 13648 13649 _IRQL_requires_max_(APC_LEVEL) 13650 _IRQL_requires_min_(PASSIVE_LEVEL) 13651 _IRQL_requires_same_ 13652 NTSTATUS 13653 ClassDeviceProcessOffloadWrite( 13654 _In_ PDEVICE_OBJECT DeviceObject, 13655 _In_ PIRP Irp, 13656 _Inout_ PSCSI_REQUEST_BLOCK Srb 13657 ) 13658 13659 /*++ 13660 13661 Routine Description: 13662 13663 This routine services IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES for CopyOffload 13664 Write. If the device supports copy offload, it performs the translation of the 13665 IOCTL into the appropriate SCSI commands to complete the operation. 13666 13667 This function must be called at IRQL < DISPATCH_LEVEL. 13668 13669 Arguments: 13670 13671 DeviceObject - Supplies the device object associated with this request 13672 Irp - The IRP to be processed 13673 Srb - An SRB that can be optinally used to process this request 13674 13675 Return Value: 13676 13677 NTSTATUS code 13678 13679 --*/ 13680 13681 { 13682 PIO_STACK_LOCATION irpStack; 13683 NTSTATUS status; 13684 PDEVICE_MANAGE_DATA_SET_ATTRIBUTES dsmAttributes; 13685 13686 UNREFERENCED_PARAMETER(Srb); 13687 13688 // 13689 // This function must be called at less than dispatch level. 13690 // 13691 PAGED_CODE(); 13692 13693 TracePrint((TRACE_LEVEL_VERBOSE, 13694 TRACE_FLAG_IOCTL, 13695 "ClassDeviceProcessOffloadWrite (%p): Entering function. Irp %p\n", 13696 DeviceObject, 13697 Irp)); 13698 13699 13700 irpStack = IoGetCurrentIrpStackLocation(Irp); 13701 13702 // 13703 // Validations 13704 // 13705 status = ClasspValidateOffloadSupported(DeviceObject, Irp); 13706 if (!NT_SUCCESS(status)) { 13707 goto __ClassDeviceProcessOffloadWrite_CompleteAndExit; 13708 } 13709 13710 if (KeGetCurrentIrql() >= DISPATCH_LEVEL) { 13711 13712 NT_ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); 13713 TracePrint((TRACE_LEVEL_ERROR, 13714 TRACE_FLAG_IOCTL, 13715 "ClassDeviceProcessOffloadWrite (%p): Called at raised IRQL.\n", 13716 DeviceObject)); 13717 13718 status = STATUS_INVALID_LEVEL; 13719 goto __ClassDeviceProcessOffloadWrite_CompleteAndExit; 13720 } 13721 13722 // 13723 // Ensure that this DSM IOCTL was generated in kernel 13724 // 13725 if (Irp->RequestorMode != KernelMode) { 13726 13727 TracePrint((TRACE_LEVEL_ERROR, 13728 TRACE_FLAG_IOCTL, 13729 "ClassDeviceProcessOffloadWrite (%p): Called from user mode.\n", 13730 DeviceObject)); 13731 13732 status = STATUS_ACCESS_DENIED; 13733 goto __ClassDeviceProcessOffloadWrite_CompleteAndExit; 13734 } 13735 13736 status = ClasspValidateOffloadInputParameters(DeviceObject, Irp); 13737 if (!NT_SUCCESS(status)) { 13738 goto __ClassDeviceProcessOffloadWrite_CompleteAndExit; 13739 } 13740 13741 dsmAttributes = Irp->AssociatedIrp.SystemBuffer; 13742 13743 // 13744 // Validate that we were passed in correct sized parameter block. 13745 // 13746 if (dsmAttributes->ParameterBlockLength < sizeof(DEVICE_DSM_OFFLOAD_WRITE_PARAMETERS)) { 13747 13748 TracePrint((TRACE_LEVEL_ERROR, 13749 TRACE_FLAG_IOCTL, 13750 "ClassDeviceProcessOffloadWrite (%p): Parameter block size (%u) too small. Required %u.\n", 13751 DeviceObject, 13752 dsmAttributes->ParameterBlockLength, 13753 sizeof(DEVICE_DSM_OFFLOAD_WRITE_PARAMETERS))); 13754 13755 status = STATUS_INVALID_PARAMETER; 13756 goto __ClassDeviceProcessOffloadWrite_CompleteAndExit; 13757 } 13758 13759 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(STORAGE_OFFLOAD_WRITE_OUTPUT)) { 13760 13761 TracePrint((TRACE_LEVEL_ERROR, 13762 TRACE_FLAG_IOCTL, 13763 "ClassDeviceProcessOffloadWrite (%p): Output buffer size (%u) too small.\n", 13764 DeviceObject, 13765 irpStack->Parameters.DeviceIoControl.OutputBufferLength)); 13766 13767 status = STATUS_BUFFER_TOO_SMALL; 13768 goto __ClassDeviceProcessOffloadWrite_CompleteAndExit; 13769 } 13770 13771 13772 13773 status = ClasspServiceWriteUsingTokenTransferRequest(DeviceObject, Irp); 13774 13775 if (status == STATUS_PENDING) { 13776 goto __ClassDeviceProcessOffloadWrite_Exit; 13777 } 13778 13779 __ClassDeviceProcessOffloadWrite_CompleteAndExit: 13780 ClasspCompleteOffloadRequest(DeviceObject, Irp, status); 13781 __ClassDeviceProcessOffloadWrite_Exit: 13782 TracePrint((TRACE_LEVEL_VERBOSE, 13783 TRACE_FLAG_IOCTL, 13784 "ClassDeviceProcessOffloadWrite (%p): Exiting function Irp %p with status %x\n", 13785 DeviceObject, 13786 Irp, 13787 status)); 13788 13789 return status; 13790 } 13791 13792 13793 _IRQL_requires_max_(APC_LEVEL) 13794 _IRQL_requires_min_(PASSIVE_LEVEL) 13795 _IRQL_requires_same_ 13796 NTSTATUS 13797 ClasspServicePopulateTokenTransferRequest( 13798 _In_ PDEVICE_OBJECT Fdo, 13799 _In_ PIRP Irp 13800 ) 13801 13802 /*++ 13803 13804 Routine description: 13805 13806 This routine processes offload read requests by building the SRB 13807 for PopulateToken and its result (i.e. token). 13808 13809 Arguments: 13810 13811 Fdo - The functional device object processing the request 13812 Irp - The Io request to be processed 13813 13814 Return Value: 13815 13816 STATUS_SUCCESS if successful, an error code otherwise 13817 13818 --*/ 13819 13820 { 13821 BOOLEAN allDataSetRangeFullyConverted; 13822 UINT32 allocationSize; 13823 ULONG blockDescrIndex; 13824 PBLOCK_DEVICE_RANGE_DESCRIPTOR blockDescrPointer; 13825 PVOID buffer; 13826 ULONG bufferLength; 13827 ULONG dataSetRangeIndex; 13828 PDEVICE_DATA_SET_RANGE dataSetRanges; 13829 ULONG dataSetRangesCount; 13830 PDEVICE_MANAGE_DATA_SET_ATTRIBUTES dsmAttributes; 13831 ULONGLONG entireXferLen; 13832 PFUNCTIONAL_DEVICE_EXTENSION fdoExt; 13833 ULONG i; 13834 ULONG lbaCount; 13835 ULONG listIdentifier; 13836 ULONG maxBlockDescrCount; 13837 ULONGLONG maxLbaCount; 13838 POFFLOAD_READ_CONTEXT offloadReadContext; 13839 PDEVICE_DSM_OFFLOAD_READ_PARAMETERS offloadReadParameters; 13840 PTRANSFER_PACKET pkt; 13841 USHORT populateTokenDataLength; 13842 USHORT populateTokenDescriptorsLength; 13843 PMDL populateTokenMdl; 13844 PIRP pseudoIrp; 13845 ULONG receiveTokenInformationBufferLength; 13846 NTSTATUS status; 13847 DEVICE_DATA_SET_RANGE tempDataSetRange; 13848 BOOLEAN tempDataSetRangeFullyConverted; 13849 PUCHAR token; 13850 ULONG tokenLength; 13851 ULONG tokenOperationBufferLength; 13852 ULONGLONG totalSectorCount; 13853 ULONGLONG totalSectorsToProcess; 13854 ULONG transferSize; 13855 13856 PAGED_CODE(); 13857 13858 TracePrint((TRACE_LEVEL_VERBOSE, 13859 TRACE_FLAG_IOCTL, 13860 "ClasspServicePopulateTokenTransferRequest (%p): Entering function. Irp %p\n", 13861 Fdo, 13862 Irp)); 13863 13864 fdoExt = Fdo->DeviceExtension; 13865 status = STATUS_SUCCESS; 13866 dsmAttributes = Irp->AssociatedIrp.SystemBuffer; 13867 buffer = NULL; 13868 pkt = NULL; 13869 populateTokenMdl = NULL; 13870 offloadReadParameters = Add2Ptr(dsmAttributes, dsmAttributes->ParameterBlockOffset); 13871 dataSetRanges = Add2Ptr(dsmAttributes, dsmAttributes->DataSetRangesOffset); 13872 dataSetRangesCount = dsmAttributes->DataSetRangesLength / sizeof(DEVICE_DATA_SET_RANGE); 13873 totalSectorsToProcess = 0; 13874 token = NULL; 13875 tokenLength = 0; 13876 bufferLength = 0; 13877 offloadReadContext = NULL; 13878 13879 NT_ASSERT(fdoExt->FunctionSupportInfo->ValidInquiryPages.BlockDeviceRODLimits && 13880 NT_SUCCESS(fdoExt->FunctionSupportInfo->BlockDeviceRODLimitsData.CommandStatus)); 13881 13882 13883 for (i = 0, entireXferLen = 0; i < dataSetRangesCount; i++) { 13884 entireXferLen += dataSetRanges[i].LengthInBytes; 13885 } 13886 13887 // 13888 // We need to truncate the read request based on the following hardware limitations: 13889 // 1. The size of the data buffer containing the TokenOperation command's parameters must 13890 // not exceed the MaximumTransferLength (and max physical pages) of the underlying 13891 // adapter. 13892 // 2. The number of descriptors specified in the TokenOperation command must not exceed 13893 // the MaximumRangeDescriptors. 13894 // 3. The cumulative total of the number of transfer blocks in all the descriptors in 13895 // the TokenOperation command must not exceed the MaximumTokenTransferSize. 13896 // 4. If the TTL has been set to the 0 (i.e. indicates the use of the default TLT), 13897 // limit the cumulative total of the number of transfer blocks in all the descriptors 13898 // in the TokenOperation command to the OptimalTransferCount. 13899 // NOTE: only a TTL of 0 has an implicit indication that the initiator of the 13900 // request would like the storage stack to be smart about the amount of data 13901 // transfer. 13902 // 13903 // In addition to the above, we need to ensure that for each of the descriptors in the 13904 // TokenOperation command: 13905 // 1. The number of blocks specified is an exact multiple of the OptimalTransferLengthGranularity. 13906 // 2. The number of blocks specified is limited to the MaximumTransferLength. (We shall 13907 // however, limit the number of blocks specified in each descriptor to be a maximum of 13908 // OptimalTransferLength or MaximumTransferLength, whichever is lesser). 13909 // 13910 // Finally, we shall always send down the PopulateToken command using IMMED = 0 for this 13911 // release. This makes it simpler to handle multi-initiator scenarios since we won't need 13912 // to deal with the PopulateToken (with IMMED = 1) succeeding but ReceiveRODTokenInformation 13913 // failing due to the path/node failing, thus making it impossible to retrieve the token. 13914 // 13915 // The LBA ranges is in DEVICE_DATA_SET_RANGE format, it needs to be converted into 13916 // WINDOWS_RANGE_DESCRIPTOR Block Descriptors. 13917 // 13918 13919 ClasspGetTokenOperationCommandBufferLength(Fdo, 13920 SERVICE_ACTION_POPULATE_TOKEN, 13921 &bufferLength, 13922 &tokenOperationBufferLength, 13923 &receiveTokenInformationBufferLength); 13924 13925 allocationSize = sizeof(OFFLOAD_READ_CONTEXT) + bufferLength; 13926 13927 offloadReadContext = ExAllocatePoolWithTag( 13928 NonPagedPoolNx, 13929 allocationSize, 13930 CLASSPNP_POOL_TAG_TOKEN_OPERATION); 13931 13932 if (!offloadReadContext) { 13933 13934 TracePrint((TRACE_LEVEL_ERROR, 13935 TRACE_FLAG_IOCTL, 13936 "ClasspServicePopulateTokenTransferRequest (%p): Failed to allocate buffer for PopulateToken operations.\n", 13937 Fdo)); 13938 13939 status = STATUS_INSUFFICIENT_RESOURCES; 13940 goto __ClasspServicePopulateTokenTransferRequest_ErrorExit; 13941 } 13942 13943 RtlZeroMemory(offloadReadContext, allocationSize); 13944 13945 offloadReadContext->Fdo = Fdo; 13946 offloadReadContext->OffloadReadDsmIrp = Irp; 13947 13948 // 13949 // The buffer for the commands is after the offloadReadContext. 13950 // 13951 buffer = (offloadReadContext + 1); 13952 13953 // 13954 // No matter how large the offload read request, we'll be sending it down in one shot. 13955 // So we need only one transfer packet. 13956 // 13957 pkt = DequeueFreeTransferPacket(Fdo, TRUE); 13958 if (!pkt){ 13959 13960 TracePrint((TRACE_LEVEL_ERROR, 13961 TRACE_FLAG_IOCTL, 13962 "ClasspServicePopulateTokenTransferRequest (%p): Failed to retrieve transfer packet for TokenOperation (PopulateToken) operation.\n", 13963 Fdo)); 13964 13965 status = STATUS_INSUFFICIENT_RESOURCES; 13966 goto __ClasspServicePopulateTokenTransferRequest_ErrorExit; 13967 } 13968 13969 offloadReadContext->Pkt = pkt; 13970 13971 ClasspGetTokenOperationDescriptorLimits(Fdo, 13972 SERVICE_ACTION_POPULATE_TOKEN, 13973 tokenOperationBufferLength, 13974 &maxBlockDescrCount, 13975 &maxLbaCount); 13976 13977 // 13978 // We will limit the maximum data transfer in an offload read operation to: 13979 // - OTC if TTL was specified as 0 13980 // - MaximumTransferTransferSize if lesser than above, or if TTL was specified was non-zero 13981 // 13982 if ((offloadReadParameters->TimeToLive == 0) && (fdoExt->FunctionSupportInfo->BlockDeviceRODLimitsData.OptimalTransferCount > 0)) { 13983 13984 maxLbaCount = MIN(maxLbaCount, fdoExt->FunctionSupportInfo->BlockDeviceRODLimitsData.OptimalTransferCount); 13985 } 13986 13987 // 13988 // Since we do not want very fragmented files to end up causing the PopulateToken command to take 13989 // too long (and potentially timeout), we will limit the max number of descriptors sent down in a 13990 // command. 13991 // 13992 maxBlockDescrCount = MIN(maxBlockDescrCount, MAX_NUMBER_BLOCK_DEVICE_DESCRIPTORS); 13993 13994 TracePrint((TRACE_LEVEL_INFORMATION, 13995 TRACE_FLAG_IOCTL, 13996 "ClasspServicePopulateTokenTransferRequest (%p): Using MaxBlockDescrCount %u and MaxLbaCount %I64u.\n", 13997 Fdo, 13998 maxBlockDescrCount, 13999 maxLbaCount)); 14000 14001 allDataSetRangeFullyConverted = FALSE; 14002 tempDataSetRangeFullyConverted = TRUE; 14003 dataSetRangeIndex = (ULONG)-1; 14004 14005 blockDescrPointer = (PBLOCK_DEVICE_RANGE_DESCRIPTOR) 14006 &((PPOPULATE_TOKEN_HEADER)buffer)->BlockDeviceRangeDescriptor[0]; 14007 14008 RtlZeroMemory(&tempDataSetRange, sizeof(tempDataSetRange)); 14009 14010 blockDescrIndex = 0; 14011 lbaCount = 0; 14012 14013 // 14014 // Send PopulateToken command when the buffer is full or all input entries are converted. 14015 // 14016 while (!((blockDescrIndex == maxBlockDescrCount) || // buffer full or block descriptor count reached 14017 (lbaCount == maxLbaCount) || // block LBA count reached 14018 (allDataSetRangeFullyConverted))) { // all DataSetRanges have been converted 14019 14020 // 14021 // If the previous entry conversion completed, continue the next one; 14022 // Otherwise, still process the left part of the un-completed entry. 14023 // 14024 if (tempDataSetRangeFullyConverted) { 14025 dataSetRangeIndex++; 14026 tempDataSetRange.StartingOffset = dataSetRanges[dataSetRangeIndex].StartingOffset; 14027 tempDataSetRange.LengthInBytes = dataSetRanges[dataSetRangeIndex].LengthInBytes; 14028 } 14029 14030 totalSectorCount = 0; 14031 14032 ClasspConvertDataSetRangeToBlockDescr(Fdo, 14033 blockDescrPointer, 14034 &blockDescrIndex, 14035 maxBlockDescrCount, 14036 &lbaCount, 14037 maxLbaCount, 14038 &tempDataSetRange, 14039 &totalSectorCount); 14040 14041 tempDataSetRangeFullyConverted = (tempDataSetRange.LengthInBytes == 0) ? TRUE : FALSE; 14042 14043 allDataSetRangeFullyConverted = tempDataSetRangeFullyConverted && ((dataSetRangeIndex + 1) == dataSetRangesCount); 14044 14045 totalSectorsToProcess += totalSectorCount; 14046 } 14047 14048 // 14049 // Calculate transfer size, including the header 14050 // 14051 transferSize = (blockDescrIndex * sizeof(BLOCK_DEVICE_RANGE_DESCRIPTOR)) + FIELD_OFFSET(POPULATE_TOKEN_HEADER, BlockDeviceRangeDescriptor); 14052 14053 NT_ASSERT(transferSize <= MAX_TOKEN_OPERATION_PARAMETER_DATA_LENGTH); 14054 14055 populateTokenDataLength = (USHORT)transferSize - RTL_SIZEOF_THROUGH_FIELD(POPULATE_TOKEN_HEADER, PopulateTokenDataLength); 14056 REVERSE_BYTES_SHORT(((PPOPULATE_TOKEN_HEADER)buffer)->PopulateTokenDataLength, &populateTokenDataLength); 14057 14058 ((PPOPULATE_TOKEN_HEADER)buffer)->Immediate = 0; 14059 14060 REVERSE_BYTES(((PPOPULATE_TOKEN_HEADER)buffer)->InactivityTimeout, &offloadReadParameters->TimeToLive); 14061 14062 populateTokenDescriptorsLength = (USHORT)transferSize - FIELD_OFFSET(POPULATE_TOKEN_HEADER, BlockDeviceRangeDescriptor); 14063 REVERSE_BYTES_SHORT(((PPOPULATE_TOKEN_HEADER)buffer)->BlockDeviceRangeDescriptorListLength, &populateTokenDescriptorsLength); 14064 14065 // 14066 // Reuse a single buffer for both TokenOperation and ReceiveTokenInformation. This has the one disadvantage 14067 // that we'll be marking the page(s) as IoWriteAccess even though we only need read access for token 14068 // operation command. However, the advantage is that we eliminate the possibility of any potential failures 14069 // when trying to allocate an MDL for the ReceiveTokenInformation later on. 14070 // 14071 bufferLength = max(transferSize, receiveTokenInformationBufferLength); 14072 14073 populateTokenMdl = ClasspBuildDeviceMdl(buffer, bufferLength, FALSE); 14074 if (!populateTokenMdl) { 14075 14076 TracePrint((TRACE_LEVEL_ERROR, 14077 TRACE_FLAG_IOCTL, 14078 "ClasspServicePopulateTokenTransferRequest (%p): Failed to allocate MDL for PopulateToken operations.\n", 14079 Fdo)); 14080 14081 status = STATUS_INSUFFICIENT_RESOURCES; 14082 goto __ClasspServicePopulateTokenTransferRequest_ErrorExit; 14083 } 14084 14085 offloadReadContext->PopulateTokenMdl = populateTokenMdl; 14086 14087 pseudoIrp = &offloadReadContext->PseudoIrp; 14088 14089 14090 pseudoIrp->IoStatus.Status = STATUS_SUCCESS; 14091 pseudoIrp->IoStatus.Information = 0; 14092 pseudoIrp->Tail.Overlay.DriverContext[0] = LongToPtr(1); 14093 pseudoIrp->MdlAddress = populateTokenMdl; 14094 14095 InterlockedCompareExchange((volatile LONG *)&TokenOperationListIdentifier, -1, MaxTokenOperationListIdentifier); 14096 listIdentifier = InterlockedIncrement((volatile LONG *)&TokenOperationListIdentifier); 14097 14098 ClasspSetupPopulateTokenTransferPacket( 14099 offloadReadContext, 14100 pkt, 14101 transferSize, 14102 (PUCHAR)buffer, 14103 pseudoIrp, 14104 listIdentifier); 14105 14106 TracePrint((TRACE_LEVEL_INFORMATION, 14107 TRACE_FLAG_IOCTL, 14108 "ClasspServicePopulateTokenTransferRequest (%p): Generate token for %I64u bytes (versus %I64u) [via %u descriptors]. \ 14109 \n\t\t\tDataLength: %u, DescriptorsLength: %u. Pkt %p (list id %x). Requested TTL: %u secs.\n", 14110 Fdo, 14111 totalSectorsToProcess * fdoExt->DiskGeometry.BytesPerSector, 14112 entireXferLen, 14113 blockDescrIndex, 14114 populateTokenDataLength, 14115 populateTokenDescriptorsLength, 14116 pkt, 14117 listIdentifier, 14118 offloadReadParameters->TimeToLive)); 14119 14120 // 14121 // Save (into the offloadReadContext) any remaining things that 14122 // ClasspPopulateTokenTransferPacketDone() will need. 14123 // 14124 14125 offloadReadContext->ListIdentifier = listIdentifier; 14126 offloadReadContext->BufferLength = bufferLength; 14127 offloadReadContext->ReceiveTokenInformationBufferLength = receiveTokenInformationBufferLength; 14128 offloadReadContext->TotalSectorsToProcess = totalSectorsToProcess; // so far 14129 offloadReadContext->EntireXferLen = entireXferLen; 14130 14131 NT_ASSERT(status == STATUS_SUCCESS); // so far. 14132 14133 IoMarkIrpPending(Irp); 14134 SubmitTransferPacket(pkt); 14135 14136 status = STATUS_PENDING; 14137 goto __ClasspServicePopulateTokenTransferRequest_Exit; 14138 14139 // 14140 // Error cleanup label only - not used in success case: 14141 // 14142 14143 __ClasspServicePopulateTokenTransferRequest_ErrorExit: 14144 14145 NT_ASSERT(status != STATUS_PENDING); 14146 14147 if (offloadReadContext != NULL) { 14148 ClasspCleanupOffloadReadContext(offloadReadContext); 14149 offloadReadContext = NULL; 14150 } 14151 14152 __ClasspServicePopulateTokenTransferRequest_Exit: 14153 14154 TracePrint((TRACE_LEVEL_VERBOSE, 14155 TRACE_FLAG_IOCTL, 14156 "ClasspServicePopulateTokenTransferRequest (%p): Exiting function (Irp %p) with status %x.\n", 14157 Fdo, 14158 Irp, 14159 status)); 14160 14161 return status; 14162 } 14163 14164 14165 VOID 14166 ClasspPopulateTokenTransferPacketDone( 14167 _In_ PVOID Context 14168 ) 14169 14170 /*++ 14171 14172 Routine description: 14173 14174 This routine continues an offload read operation on completion of the 14175 populate token transfer packet. 14176 14177 This function is responsible for continuing or completing the offload read 14178 operation. 14179 14180 Arguments: 14181 14182 Context - Pointer to the OFFLOAD_READ_CONTEXT for the offload read 14183 operation. 14184 14185 Return Value: 14186 14187 None. 14188 14189 --*/ 14190 14191 { 14192 PDEVICE_OBJECT fdo; 14193 ULONG listIdentifier; 14194 POFFLOAD_READ_CONTEXT offloadReadContext; 14195 PTRANSFER_PACKET pkt; 14196 PIRP pseudoIrp; 14197 NTSTATUS status; 14198 14199 offloadReadContext = Context; 14200 pseudoIrp = &offloadReadContext->PseudoIrp; 14201 pkt = offloadReadContext->Pkt; 14202 fdo = offloadReadContext->Fdo; 14203 listIdentifier = offloadReadContext->ListIdentifier; 14204 14205 offloadReadContext->Pkt = NULL; 14206 14207 14208 status = pseudoIrp->IoStatus.Status; 14209 NT_ASSERT(status != STATUS_PENDING); 14210 14211 if (!NT_SUCCESS(status)) { 14212 TracePrint((TRACE_LEVEL_ERROR, 14213 TRACE_FLAG_IOCTL, 14214 "ClasspPopulateTokenTransferPacketDone (%p): Generate token for list Id %x failed with %x (Pkt %p).\n", 14215 fdo, 14216 listIdentifier, 14217 status, 14218 pkt)); 14219 goto __ClasspPopulateTokenTransferPacketDone_ErrorExit; 14220 } 14221 14222 // 14223 // If a token was successfully generated, it is now time to retrieve the token. 14224 // The called function is responsible for completing the offload read DSM IRP. 14225 // 14226 ClasspReceivePopulateTokenInformation(offloadReadContext); 14227 14228 // 14229 // ClasspReceivePopulateTokenInformation() takes care of completing the IRP, 14230 // so this function is done regardless of success or failure in 14231 // ClasspReceivePopulateTokenInformation(). 14232 // 14233 14234 return; 14235 14236 // 14237 // Error cleanup label only - not used in success case: 14238 // 14239 14240 __ClasspPopulateTokenTransferPacketDone_ErrorExit: 14241 14242 NT_ASSERT(!NT_SUCCESS(status)); 14243 14244 // 14245 // ClasspCompleteOffloadRead also cleans up offloadReadContext. 14246 // 14247 14248 ClasspCompleteOffloadRead(offloadReadContext, status); 14249 14250 return; 14251 } 14252 14253 14254 VOID 14255 ClasspCompleteOffloadRead( 14256 _In_ POFFLOAD_READ_CONTEXT OffloadReadContext, 14257 _In_ NTSTATUS CompletionStatus 14258 ) 14259 14260 /*++ 14261 14262 Routine description: 14263 14264 This routine completes an offload read operation with given status, and 14265 cleans up the OFFLOAD_READ_CONTEXT. 14266 14267 Arguments: 14268 14269 OffloadReadContext - Pointer to the OFFLOAD_READ_CONTEXT for the offload 14270 read operation. 14271 14272 CompletionStatus - The completion status for the offload read operation. 14273 14274 Return Value: 14275 14276 None. 14277 14278 --*/ 14279 14280 { 14281 PDEVICE_MANAGE_DATA_SET_ATTRIBUTES dsmAttributes; 14282 ULONGLONG entireXferLen; 14283 PDEVICE_OBJECT fdo; 14284 PFUNCTIONAL_DEVICE_EXTENSION fdoExt; 14285 PIRP irp; 14286 NTSTATUS status; 14287 PUCHAR token; 14288 ULONGLONG totalSectorsProcessed; 14289 14290 status = CompletionStatus; 14291 dsmAttributes = OffloadReadContext->OffloadReadDsmIrp->AssociatedIrp.SystemBuffer; 14292 totalSectorsProcessed = OffloadReadContext->TotalSectorsProcessed; 14293 fdoExt = OffloadReadContext->Fdo->DeviceExtension; 14294 entireXferLen = OffloadReadContext->EntireXferLen; 14295 token = OffloadReadContext->Token; 14296 irp = OffloadReadContext->OffloadReadDsmIrp; 14297 fdo = OffloadReadContext->Fdo; 14298 14299 ((PSTORAGE_OFFLOAD_READ_OUTPUT)dsmAttributes)->OffloadReadFlags = 0; 14300 ((PSTORAGE_OFFLOAD_READ_OUTPUT)dsmAttributes)->Reserved = 0; 14301 14302 if (NT_SUCCESS(status)) { 14303 ULONGLONG totalBytesProcessed = totalSectorsProcessed * fdoExt->DiskGeometry.BytesPerSector; 14304 14305 TracePrint((totalBytesProcessed == entireXferLen ? TRACE_LEVEL_INFORMATION : TRACE_LEVEL_WARNING, 14306 TRACE_FLAG_IOCTL, 14307 "ClasspCompleteOffloadRead (%p): Successfully populated token with %I64u (out of %I64u) bytes (list Id %x).\n", 14308 fdo, 14309 totalBytesProcessed, 14310 entireXferLen, 14311 OffloadReadContext->ListIdentifier)); 14312 14313 if (totalBytesProcessed < entireXferLen) { 14314 SET_FLAG(((PSTORAGE_OFFLOAD_READ_OUTPUT)dsmAttributes)->OffloadReadFlags, STORAGE_OFFLOAD_READ_RANGE_TRUNCATED); 14315 } 14316 ((PSTORAGE_OFFLOAD_READ_OUTPUT)dsmAttributes)->LengthProtected = totalBytesProcessed; 14317 ((PSTORAGE_OFFLOAD_READ_OUTPUT)dsmAttributes)->TokenLength = STORAGE_OFFLOAD_MAX_TOKEN_LENGTH; 14318 RtlCopyMemory(&((PSTORAGE_OFFLOAD_READ_OUTPUT)dsmAttributes)->Token, token, STORAGE_OFFLOAD_MAX_TOKEN_LENGTH); 14319 } else { 14320 ((PSTORAGE_OFFLOAD_READ_OUTPUT)dsmAttributes)->LengthProtected = 0; 14321 ((PSTORAGE_OFFLOAD_READ_OUTPUT)dsmAttributes)->TokenLength = 0; 14322 } 14323 14324 irp->IoStatus.Information = sizeof(STORAGE_OFFLOAD_READ_OUTPUT); 14325 14326 ClasspCompleteOffloadRequest(fdo, irp, status); 14327 ClasspCleanupOffloadReadContext(OffloadReadContext); 14328 OffloadReadContext = NULL; 14329 14330 return; 14331 } 14332 14333 14334 VOID 14335 ClasspCleanupOffloadReadContext( 14336 _In_ __drv_freesMem(mem) POFFLOAD_READ_CONTEXT OffloadReadContext 14337 ) 14338 14339 /*++ 14340 14341 Routine description: 14342 14343 This routine cleans up an OFFLOAD_READ_CONTEXT. 14344 14345 Arguments: 14346 14347 OffloadReadContext - Pointer to the OFFLOAD_READ_CONTEXT for the offload 14348 read operation. 14349 14350 Return Value: 14351 14352 None. 14353 14354 --*/ 14355 14356 { 14357 PMDL populateTokenMdl; 14358 14359 populateTokenMdl = OffloadReadContext->PopulateTokenMdl; 14360 14361 NT_ASSERT(OffloadReadContext != NULL); 14362 14363 if (populateTokenMdl) { 14364 ClasspFreeDeviceMdl(populateTokenMdl); 14365 } 14366 FREE_POOL(OffloadReadContext); 14367 14368 return; 14369 } 14370 14371 14372 _IRQL_requires_same_ 14373 VOID 14374 ClasspReceivePopulateTokenInformation( 14375 _In_ POFFLOAD_READ_CONTEXT OffloadReadContext 14376 ) 14377 14378 /*++ 14379 14380 Routine description: 14381 14382 This routine retrieves the token after a PopulateToken command 14383 has been sent down. 14384 14385 Can also be called repeatedly for a single offload op when a previous 14386 RECEIVE ROD TOKEN INFORMATION for that op indicated that the operation was 14387 not yet complete. 14388 14389 This function is responsible for continuing or completing the offload read 14390 operation. 14391 14392 Arguments: 14393 14394 OffloadReadContext - Pointer to the OFFLOAD_READ_CONTEXT for the offload 14395 read operation. 14396 14397 Return Value: 14398 14399 None. 14400 14401 --*/ 14402 14403 { 14404 PVOID buffer; 14405 ULONG bufferLength; 14406 ULONG cdbLength; 14407 PDEVICE_OBJECT fdo; 14408 PIRP irp; 14409 ULONG listIdentifier; 14410 PTRANSFER_PACKET pkt; 14411 PIRP pseudoIrp; 14412 ULONG receiveTokenInformationBufferLength; 14413 PSCSI_REQUEST_BLOCK srb; 14414 NTSTATUS status; 14415 ULONG tempSizeUlong; 14416 PULONGLONG totalSectorsProcessed; 14417 14418 totalSectorsProcessed = &OffloadReadContext->TotalSectorsProcessed; 14419 buffer = OffloadReadContext + 1; 14420 bufferLength = OffloadReadContext->BufferLength; 14421 fdo = OffloadReadContext->Fdo; 14422 irp = OffloadReadContext->OffloadReadDsmIrp; 14423 receiveTokenInformationBufferLength = OffloadReadContext->ReceiveTokenInformationBufferLength; 14424 listIdentifier = OffloadReadContext->ListIdentifier; 14425 14426 TracePrint((TRACE_LEVEL_VERBOSE, 14427 TRACE_FLAG_IOCTL, 14428 "ClasspReceivePopulateTokenInformation (%p): Entering function. Irp %p\n", 14429 fdo, 14430 irp)); 14431 14432 srb = &OffloadReadContext->Srb; 14433 *totalSectorsProcessed = 0; 14434 14435 pkt = DequeueFreeTransferPacket(fdo, TRUE); 14436 if (!pkt){ 14437 14438 TracePrint((TRACE_LEVEL_ERROR, 14439 TRACE_FLAG_IOCTL, 14440 "ClasspReceivePopulateTokenInformation (%p): Failed to retrieve transfer packet for ReceiveTokenInformation (PopulateToken) operation.\n", 14441 fdo)); 14442 14443 status = STATUS_INSUFFICIENT_RESOURCES; 14444 goto __ClasspReceivePopulateTokenInformation_ErrorExit; 14445 } 14446 14447 OffloadReadContext->Pkt = pkt; 14448 14449 RtlZeroMemory(buffer, bufferLength); 14450 14451 tempSizeUlong = receiveTokenInformationBufferLength - 4; 14452 REVERSE_BYTES(((PRECEIVE_TOKEN_INFORMATION_HEADER)buffer)->AvailableData, &tempSizeUlong); 14453 14454 pseudoIrp = &OffloadReadContext->PseudoIrp; 14455 RtlZeroMemory(pseudoIrp, sizeof(IRP)); 14456 14457 14458 pseudoIrp->IoStatus.Status = STATUS_SUCCESS; 14459 pseudoIrp->IoStatus.Information = 0; 14460 pseudoIrp->Tail.Overlay.DriverContext[0] = LongToPtr(1); 14461 pseudoIrp->MdlAddress = OffloadReadContext->PopulateTokenMdl; 14462 14463 ClasspSetupReceivePopulateTokenInformationTransferPacket( 14464 OffloadReadContext, 14465 pkt, 14466 receiveTokenInformationBufferLength, 14467 (PUCHAR)buffer, 14468 pseudoIrp, 14469 listIdentifier); 14470 14471 // 14472 // Cache away the CDB as it may be required for forwarded sense data 14473 // after this command completes. 14474 // 14475 RtlZeroMemory(srb, sizeof(*srb)); 14476 cdbLength = SrbGetCdbLength(pkt->Srb); 14477 if (cdbLength <= 16) { 14478 RtlCopyMemory(&srb->Cdb, SrbGetCdb(pkt->Srb), cdbLength); 14479 } 14480 14481 SubmitTransferPacket(pkt); 14482 14483 return; 14484 14485 // 14486 // Error cleanup label only - not used in success case: 14487 // 14488 14489 __ClasspReceivePopulateTokenInformation_ErrorExit: 14490 14491 NT_ASSERT(!NT_SUCCESS(status)); 14492 14493 // 14494 // ClasspCompleteOffloadRead also cleans up offloadReadContext. 14495 // 14496 14497 ClasspCompleteOffloadRead(OffloadReadContext, status); 14498 14499 return; 14500 } 14501 14502 14503 VOID 14504 ClasspReceivePopulateTokenInformationTransferPacketDone( 14505 _In_ PVOID Context 14506 ) 14507 14508 /*++ 14509 14510 Routine description: 14511 14512 This routine continues an offload read operation on completion of the 14513 RECEIVE ROD TOKEN INFORMATION transfer packet. 14514 14515 This routine is responsible for continuing or completing the offload read 14516 operation. 14517 14518 Arguments: 14519 14520 Context - Pointer to the OFFLOAD_READ_CONTEXT for the offload read 14521 operation. 14522 14523 Return Value: 14524 14525 None. 14526 14527 --*/ 14528 14529 { 14530 ULONG availableData; 14531 PVOID buffer; 14532 UCHAR completionStatus; 14533 ULONG estimatedRetryInterval; 14534 PDEVICE_OBJECT fdo; 14535 PFUNCTIONAL_DEVICE_EXTENSION fdoExt; 14536 PIRP irp; 14537 ULONG listIdentifier; 14538 POFFLOAD_READ_CONTEXT offloadReadContext; 14539 BOOLEAN operationCompleted; 14540 UCHAR operationStatus; 14541 PIRP pseudoIrp; 14542 USHORT segmentsProcessed; 14543 PSENSE_DATA senseData; 14544 ULONG senseDataFieldLength; 14545 UCHAR senseDataLength; 14546 PSCSI_REQUEST_BLOCK srb; 14547 NTSTATUS status; 14548 PUCHAR token; 14549 PVOID tokenAscii; 14550 PBLOCK_DEVICE_TOKEN_DESCRIPTOR tokenDescriptor; 14551 ULONG tokenDescriptorLength; 14552 PRECEIVE_TOKEN_INFORMATION_HEADER tokenInformationResults; 14553 PRECEIVE_TOKEN_INFORMATION_RESPONSE_HEADER tokenInformationResultsResponse; 14554 ULONG tokenLength; 14555 ULONG tokenSize; 14556 PULONGLONG totalSectorsProcessed; 14557 ULONGLONG totalSectorsToProcess; 14558 ULONGLONG transferBlockCount; 14559 14560 offloadReadContext = Context; 14561 fdo = offloadReadContext->Fdo; 14562 fdoExt = fdo->DeviceExtension; 14563 buffer = offloadReadContext + 1; 14564 listIdentifier = offloadReadContext->ListIdentifier; 14565 irp = offloadReadContext->OffloadReadDsmIrp; 14566 totalSectorsToProcess = offloadReadContext->TotalSectorsToProcess; 14567 totalSectorsProcessed = &offloadReadContext->TotalSectorsProcessed; 14568 srb = &offloadReadContext->Srb; 14569 tokenAscii = NULL; 14570 tokenSize = BLOCK_DEVICE_TOKEN_SIZE; 14571 tokenInformationResults = (PRECEIVE_TOKEN_INFORMATION_HEADER)buffer; 14572 senseData = (PSENSE_DATA)((PUCHAR)tokenInformationResults + FIELD_OFFSET(RECEIVE_TOKEN_INFORMATION_HEADER, SenseData)); 14573 transferBlockCount = 0; 14574 tokenInformationResultsResponse = NULL; 14575 tokenDescriptor = NULL; 14576 operationCompleted = FALSE; 14577 tokenDescriptorLength = 0; 14578 tokenLength = 0; 14579 token = NULL; 14580 pseudoIrp = &offloadReadContext->PseudoIrp; 14581 14582 status = pseudoIrp->IoStatus.Status; 14583 NT_ASSERT(status != STATUS_PENDING); 14584 14585 // 14586 // The buffer we hand allows for the max sizes for all the fields whereas the returned 14587 // data may be lesser (e.g. sense data info will almost never be MAX_SENSE_BUFFER_SIZE, etc. 14588 // so handle underrun "error" 14589 // 14590 if (status == STATUS_DATA_OVERRUN) { 14591 14592 status = STATUS_SUCCESS; 14593 } 14594 14595 if (!NT_SUCCESS(status)) { 14596 TracePrint((TRACE_LEVEL_ERROR, 14597 TRACE_FLAG_IOCTL, 14598 "ClasspReceivePopulateTokenInformationTransferPacketDone (%p): Token retrieval failed for list Id %x with %x.\n", 14599 fdo, 14600 listIdentifier, 14601 status)); 14602 goto __ClasspReceivePopulateTokenInformationTransferPacketDone_Exit; 14603 } 14604 14605 REVERSE_BYTES(&availableData, &tokenInformationResults->AvailableData); 14606 14607 NT_ASSERT(availableData <= FIELD_OFFSET(RECEIVE_TOKEN_INFORMATION_HEADER, SenseData) + MAX_SENSE_BUFFER_SIZE + 14608 FIELD_OFFSET(RECEIVE_TOKEN_INFORMATION_RESPONSE_HEADER, TokenDescriptor) + BLOCK_DEVICE_TOKEN_SIZE); 14609 14610 NT_ASSERT(tokenInformationResults->ResponseToServiceAction == SERVICE_ACTION_POPULATE_TOKEN); 14611 14612 operationStatus = tokenInformationResults->OperationStatus; 14613 operationCompleted = ClasspIsTokenOperationComplete(operationStatus); 14614 NT_ASSERT(operationCompleted); 14615 14616 REVERSE_BYTES(&estimatedRetryInterval, &tokenInformationResults->EstimatedStatusUpdateDelay); 14617 14618 completionStatus = tokenInformationResults->CompletionStatus; 14619 14620 NT_ASSERT(tokenInformationResults->TransferCountUnits == TRANSFER_COUNT_UNITS_NUMBER_BLOCKS); 14621 REVERSE_BYTES_QUAD(&transferBlockCount, &tokenInformationResults->TransferCount); 14622 14623 REVERSE_BYTES_SHORT(&segmentsProcessed, &tokenInformationResults->SegmentsProcessed); 14624 NT_ASSERT(segmentsProcessed == 0); 14625 14626 if (operationCompleted) { 14627 14628 if (transferBlockCount > totalSectorsToProcess) { 14629 14630 // 14631 // Buggy or hostile target. Don't let it claim more was procesed 14632 // than was requested. Since this is likely a bug and it's unknown 14633 // how much was actually transferred, assume no data was 14634 // transferred. 14635 // 14636 14637 NT_ASSERT(transferBlockCount <= totalSectorsToProcess); 14638 transferBlockCount = 0; 14639 } 14640 14641 if (operationStatus != OPERATION_COMPLETED_WITH_SUCCESS && 14642 operationStatus != OPERATION_COMPLETED_WITH_RESIDUAL_DATA) { 14643 14644 // 14645 // Assert on buggy response from target, but in any case, make sure not 14646 // to claim that any data was written. 14647 // 14648 14649 NT_ASSERT(transferBlockCount == 0); 14650 transferBlockCount = 0; 14651 } 14652 14653 // 14654 // Since the TokenOperation was sent down synchronously, the operation is complete as soon as the command returns. 14655 // 14656 14657 senseDataFieldLength = tokenInformationResults->SenseDataFieldLength; 14658 senseDataLength = tokenInformationResults->SenseDataLength; 14659 NT_ASSERT(senseDataFieldLength >= senseDataLength); 14660 14661 tokenInformationResultsResponse = (PRECEIVE_TOKEN_INFORMATION_RESPONSE_HEADER)((PUCHAR)tokenInformationResults + 14662 FIELD_OFFSET(RECEIVE_TOKEN_INFORMATION_HEADER, SenseData) + 14663 tokenInformationResults->SenseDataFieldLength); 14664 14665 REVERSE_BYTES(&tokenDescriptorLength, &tokenInformationResultsResponse->TokenDescriptorsLength); 14666 14667 if (tokenDescriptorLength > 0) { 14668 14669 NT_ASSERT(tokenDescriptorLength == sizeof(BLOCK_DEVICE_TOKEN_DESCRIPTOR)); 14670 14671 if (tokenDescriptorLength != sizeof(BLOCK_DEVICE_TOKEN_DESCRIPTOR)) { 14672 14673 TracePrint((TRACE_LEVEL_ERROR, 14674 TRACE_FLAG_IOCTL, 14675 "ClasspReceivePopulateTokenInformationTransferPacketDone (%p): Bad firmware, token descriptor length %u.\n", 14676 fdo, 14677 tokenDescriptorLength)); 14678 14679 NT_ASSERT((*totalSectorsProcessed) == 0); 14680 NT_ASSERT(tokenLength == 0); 14681 14682 } else { 14683 14684 USHORT restrictedId; 14685 14686 tokenDescriptor = (PBLOCK_DEVICE_TOKEN_DESCRIPTOR)tokenInformationResultsResponse->TokenDescriptor; 14687 14688 REVERSE_BYTES_SHORT(&restrictedId, &tokenDescriptor->TokenIdentifier); 14689 NT_ASSERT(restrictedId == 0); 14690 14691 tokenLength = BLOCK_DEVICE_TOKEN_SIZE; 14692 token = tokenDescriptor->Token; 14693 14694 *totalSectorsProcessed = transferBlockCount; 14695 14696 if (transferBlockCount < totalSectorsToProcess) { 14697 14698 NT_ASSERT(operationStatus == OPERATION_COMPLETED_WITH_RESIDUAL_DATA || 14699 operationStatus == OPERATION_COMPLETED_WITH_ERROR || 14700 operationStatus == OPERATION_TERMINATED); 14701 14702 if (transferBlockCount == 0) { 14703 // 14704 // Treat the same as not getting a token. 14705 // 14706 14707 tokenLength = 0; 14708 } 14709 14710 } else { 14711 14712 NT_ASSERT(operationStatus == OPERATION_COMPLETED_WITH_SUCCESS); 14713 NT_ASSERT(transferBlockCount == totalSectorsToProcess); 14714 } 14715 14716 // 14717 // Need to convert to ascii. 14718 // 14719 tokenAscii = ClasspBinaryToAscii((PUCHAR)token, 14720 tokenSize, 14721 &tokenSize); 14722 14723 TracePrint((transferBlockCount == totalSectorsToProcess ? TRACE_LEVEL_INFORMATION : TRACE_LEVEL_WARNING, 14724 TRACE_FLAG_IOCTL, 14725 "ClasspReceivePopulateTokenInformationTransferPacketDone (%p): %wsToken %s generated successfully for list Id %x for data size %I64u bytes.\n", 14726 fdo, 14727 transferBlockCount == totalSectorsToProcess ? L"" : L"Target truncated read. ", 14728 (tokenAscii == NULL) ? "" : tokenAscii, 14729 listIdentifier, 14730 (*totalSectorsProcessed) * fdoExt->DiskGeometry.BytesPerSector)); 14731 14732 FREE_POOL(tokenAscii); 14733 } 14734 } else { 14735 14736 TracePrint((TRACE_LEVEL_ERROR, 14737 TRACE_FLAG_IOCTL, 14738 "ClasspReceivePopulateTokenInformationTransferPacketDone (%p): Target failed to generate a token for list Id %x for data size %I64u bytes (requested %I64u bytes).\n", 14739 fdo, 14740 listIdentifier, 14741 transferBlockCount * fdoExt->DiskGeometry.BytesPerSector, 14742 totalSectorsToProcess * fdoExt->DiskGeometry.BytesPerSector)); 14743 14744 *totalSectorsProcessed = 0; 14745 14746 NT_ASSERT(operationStatus == OPERATION_COMPLETED_WITH_ERROR); 14747 } 14748 14749 // 14750 // Operation that completes with success can have sense data (for target to pass on some extra info) 14751 // but we don't care about such sense info. 14752 // Operation that complete but not with success, may not have sense data associated, but may 14753 // have valid CompletionStatus. 14754 // 14755 // The "status" may be overriden by ClassInterpretSenseInfo(). Final 14756 // status is determined a bit later - this is just the default status 14757 // when ClassInterpretSenseInfo() doesn't get to run here. 14758 // 14759 status = STATUS_SUCCESS; 14760 if (operationStatus == OPERATION_COMPLETED_WITH_ERROR || 14761 operationStatus == OPERATION_COMPLETED_WITH_RESIDUAL_DATA || 14762 operationStatus == OPERATION_TERMINATED) { 14763 14764 SrbSetScsiStatus((PSTORAGE_REQUEST_BLOCK_HEADER)srb, completionStatus); 14765 14766 if (senseDataLength) { 14767 14768 ULONG retryInterval; 14769 14770 NT_ASSERT(senseDataLength <= sizeof(SENSE_DATA)); 14771 14772 srb->Function = SRB_FUNCTION_EXECUTE_SCSI; 14773 14774 srb->SrbStatus = SRB_STATUS_AUTOSENSE_VALID | SRB_STATUS_ERROR; 14775 SrbSetSenseInfoBuffer((PSTORAGE_REQUEST_BLOCK_HEADER)srb, senseData); 14776 SrbSetSenseInfoBufferLength((PSTORAGE_REQUEST_BLOCK_HEADER)srb, senseDataLength); 14777 14778 ClassInterpretSenseInfo(fdo, 14779 srb, 14780 IRP_MJ_SCSI, 14781 0, 14782 0, 14783 &status, 14784 &retryInterval); 14785 14786 TracePrint((TRACE_LEVEL_WARNING, 14787 TRACE_FLAG_IOCTL, 14788 "ClasspReceivePopulateTokenInformationTransferPacketDone (%p): Reason for truncation/failure: %x - for list Id %x for data size %I64u bytes.\n", 14789 fdo, 14790 status, 14791 listIdentifier, 14792 transferBlockCount * fdoExt->DiskGeometry.BytesPerSector)); 14793 } else { 14794 14795 TracePrint((TRACE_LEVEL_WARNING, 14796 TRACE_FLAG_IOCTL, 14797 "ClasspReceivePopulateTokenInformationTransferPacketDone (%p): No sense data available but reason for truncation/failure, possibly: %x - for list Id %x for data size %I64u bytes.\n", 14798 fdo, 14799 completionStatus, 14800 listIdentifier, 14801 transferBlockCount * fdoExt->DiskGeometry.BytesPerSector)); 14802 } 14803 } 14804 14805 if (tokenLength > 0) { 14806 14807 offloadReadContext->Token = token; 14808 14809 // 14810 // Even if target returned an error, from the OS upper layers' perspective, 14811 // it is a success (with truncation) if any data at all was read. 14812 // 14813 status = STATUS_SUCCESS; 14814 14815 } else { 14816 14817 if (NT_SUCCESS(status)) { 14818 // 14819 // Make sure status is a failing status, without throwing away an 14820 // already-failing status obtained from sense data. 14821 // 14822 status = STATUS_UNSUCCESSFUL; 14823 } 14824 } 14825 14826 // 14827 // Done with the operation. 14828 // 14829 14830 NT_ASSERT(status != STATUS_PENDING); 14831 goto __ClasspReceivePopulateTokenInformationTransferPacketDone_Exit; 14832 14833 } else { 14834 14835 status = STATUS_UNSUCCESSFUL; 14836 14837 TracePrint((TRACE_LEVEL_ERROR, 14838 TRACE_FLAG_IOCTL, 14839 "ClasspReceivePopulateTokenInformationTransferPacketDone (%p): Token retrieval failed for list Id %x with %x.\n", 14840 fdo, 14841 listIdentifier, 14842 status)); 14843 14844 NT_ASSERT(*totalSectorsProcessed == 0); 14845 goto __ClasspReceivePopulateTokenInformationTransferPacketDone_Exit; 14846 } 14847 14848 __ClasspReceivePopulateTokenInformationTransferPacketDone_Exit: 14849 14850 if (status != STATUS_PENDING) { 14851 14852 // 14853 // The "status" value can be success or failure at this point, as 14854 // appropriate. 14855 // 14856 14857 ClasspCompleteOffloadRead(offloadReadContext, status); 14858 } 14859 14860 // 14861 // Due to tracing a potentially freed pointer value "Irp", this trace could 14862 // be delayed beyond another offload op picking up the same pointer value 14863 // for its Irp. This function exits after the operation is complete when 14864 // status != STATUS_PENDING. 14865 // 14866 14867 TracePrint((TRACE_LEVEL_VERBOSE, 14868 TRACE_FLAG_IOCTL, 14869 "ClasspReceivePopulateTokenInformationTransferPacketDone (%p): Exiting function (Irp %p) with internal status %x.\n", 14870 fdo, 14871 irp, 14872 status)); 14873 14874 return; 14875 } 14876 14877 14878 _IRQL_requires_max_(APC_LEVEL) 14879 _IRQL_requires_min_(PASSIVE_LEVEL) 14880 _IRQL_requires_same_ 14881 NTSTATUS 14882 ClasspServiceWriteUsingTokenTransferRequest( 14883 _In_ PDEVICE_OBJECT Fdo, 14884 _In_ PIRP Irp 14885 ) 14886 14887 /*++ 14888 14889 Routine description: 14890 14891 This routine processes offload write requests by building the SRB 14892 for WriteUsingToken. 14893 14894 Arguments: 14895 14896 Fdo - The functional device object processing the request 14897 Irp - The Io request to be processed 14898 14899 Return Value: 14900 14901 STATUS_SUCCESS if successful, an error code otherwise 14902 14903 --*/ 14904 14905 { 14906 ULONG allocationSize; 14907 PVOID buffer; 14908 ULONG bufferLength; 14909 PDEVICE_DATA_SET_RANGE dataSetRanges; 14910 ULONG dataSetRangesCount; 14911 PDEVICE_MANAGE_DATA_SET_ATTRIBUTES dsmAttributes; 14912 ULONGLONG entireXferLen; 14913 PFUNCTIONAL_DEVICE_EXTENSION fdoExt; 14914 ULONG i; 14915 ULONGLONG logicalBlockOffset; 14916 ULONG maxBlockDescrCount; 14917 ULONGLONG maxLbaCount; 14918 POFFLOAD_WRITE_CONTEXT offloadWriteContext; 14919 PDEVICE_DSM_OFFLOAD_WRITE_PARAMETERS offloadWriteParameters; 14920 ULONG receiveTokenInformationBufferLength; 14921 NTSTATUS status; 14922 NTSTATUS tempStatus; 14923 BOOLEAN tokenInvalidated; 14924 ULONG tokenOperationBufferLength; 14925 PMDL writeUsingTokenMdl; 14926 14927 PAGED_CODE(); 14928 14929 TracePrint((TRACE_LEVEL_VERBOSE, 14930 TRACE_FLAG_IOCTL, 14931 "ClasspServiceWriteUsingTokenTransferRequest (%p): Entering function. Irp %p.\n", 14932 Fdo, 14933 Irp)); 14934 14935 fdoExt = Fdo->DeviceExtension; 14936 status = STATUS_SUCCESS; 14937 tempStatus = STATUS_SUCCESS; 14938 dsmAttributes = Irp->AssociatedIrp.SystemBuffer; 14939 buffer = NULL; 14940 writeUsingTokenMdl = NULL; 14941 offloadWriteParameters = Add2Ptr(dsmAttributes, dsmAttributes->ParameterBlockOffset); 14942 dataSetRanges = Add2Ptr(dsmAttributes, dsmAttributes->DataSetRangesOffset); 14943 dataSetRangesCount = dsmAttributes->DataSetRangesLength / sizeof(DEVICE_DATA_SET_RANGE); 14944 logicalBlockOffset = offloadWriteParameters->TokenOffset / fdoExt->DiskGeometry.BytesPerSector; 14945 tokenInvalidated = FALSE; 14946 bufferLength = 0; 14947 14948 14949 NT_ASSERT(fdoExt->FunctionSupportInfo->ValidInquiryPages.BlockDeviceRODLimits && 14950 NT_SUCCESS(fdoExt->FunctionSupportInfo->BlockDeviceRODLimitsData.CommandStatus)); 14951 14952 for (i = 0, entireXferLen = 0; i < dataSetRangesCount; i++) { 14953 entireXferLen += dataSetRanges[i].LengthInBytes; 14954 } 14955 14956 // 14957 // We need to split the write request based on the following hardware limitations: 14958 // 1. The size of the data buffer containing the TokenOperation command's parameters must 14959 // not exceed the MaximumTransferLength (and max physical pages) of the underlying 14960 // adapter. 14961 // 2. The number of descriptors specified in the TokenOperation command must not exceed 14962 // the MaximumRangeDescriptors. 14963 // 3. The cumulative total of the number of transfer blocks in all the descriptors in 14964 // the TokenOperation command must not exceed the MaximumTokenTransferSize. 14965 // 14966 // In addition to the above, we need to ensure that for each of the descriptors in the 14967 // TokenOperation command: 14968 // 1. The number of blocks specified is an exact multiple of the OptimalTransferLengthGranularity. 14969 // 2. The number of blocks specified is limited to the MaximumTransferLength. (We shall 14970 // however, limit the number of blocks specified in each descriptor to be a maximum of 14971 // OptimalTransferLength or MaximumTransferLength, whichever is lesser). 14972 // 14973 // Finally, we shall always send down the WriteUsingToken command using IMMED = 0 for this 14974 // release. This makes it simpler to handle multi-initiator scenarios since we won't need 14975 // to deal with the WriteUsingToken (with IMMED = 1) succeeding but ReceiveRODTokenInformation 14976 // failing due to the path/node failing, thus making it impossible to retrieve results of 14977 // the data transfer operation, or to cancel the data transfer via CopyOperationAbort. 14978 // Since a write data transfer of a large amount of data may take a long time when sent 14979 // down IMMED = 0, we shall limit the size to a maximum of 256MB even if it means truncating 14980 // the original requested size to this capped size. The application is expected to deal with 14981 // this truncation. 14982 // (NOTE: the cap of 256MB is chosen to match with the Copy Engine's chunk size). 14983 // 14984 // The LBA ranges is in DEVICE_DATA_SET_RANGE format, it needs to be converted into 14985 // WINDOWS_BLOCK_DEVICE_RANGE_DESCRIPTOR Block Descriptors. 14986 // 14987 14988 ClasspGetTokenOperationCommandBufferLength(Fdo, 14989 SERVICE_ACTION_WRITE_USING_TOKEN, 14990 &bufferLength, 14991 &tokenOperationBufferLength, 14992 &receiveTokenInformationBufferLength); 14993 14994 allocationSize = sizeof(OFFLOAD_WRITE_CONTEXT) + bufferLength; 14995 14996 offloadWriteContext = ExAllocatePoolWithTag( 14997 NonPagedPoolNx, 14998 allocationSize, 14999 CLASSPNP_POOL_TAG_TOKEN_OPERATION); 15000 15001 if (!offloadWriteContext) { 15002 15003 TracePrint((TRACE_LEVEL_ERROR, 15004 TRACE_FLAG_IOCTL, 15005 "ClasspServiceWriteUsingTokenTransferRequest (%p): Failed to allocate buffer for WriteUsingToken operations.\n", 15006 Fdo)); 15007 15008 status = STATUS_INSUFFICIENT_RESOURCES; 15009 goto __ClasspServiceWriteUsingTokenTransferRequest_ErrorExit; 15010 } 15011 15012 // 15013 // Only zero the context portion here. The buffer portion is zeroed for 15014 // each sub-request. 15015 // 15016 RtlZeroMemory(offloadWriteContext, sizeof(OFFLOAD_WRITE_CONTEXT)); 15017 15018 offloadWriteContext->Fdo = Fdo; 15019 offloadWriteContext->OffloadWriteDsmIrp = Irp; 15020 offloadWriteContext->OperationStartTime = KeQueryInterruptTime(); 15021 15022 // 15023 // The buffer for the commands is after the offloadWriteContext. 15024 // 15025 buffer = (offloadWriteContext + 1); 15026 15027 // 15028 // Set up fields that allow iterating through whole request, by issuing sub- 15029 // requests which each do some of the writing. Because of truncation by the 15030 // target, it's not known exactly how many bytes will be written by the 15031 // target in each sub-request (can be less than requested), so the 15032 // progress through the outer request must only commit the move through the 15033 // upper DSM ranges when a lower request is done and the number of written 15034 // sectors is known. 15035 // 15036 15037 NT_ASSERT(offloadWriteContext->TotalSectorsProcessedSuccessfully == 0); 15038 offloadWriteContext->TotalRequestSizeSectors = entireXferLen / fdoExt->DiskGeometry.BytesPerSector; 15039 NT_ASSERT(offloadWriteContext->DataSetRangeIndex == 0); 15040 NT_ASSERT(offloadWriteContext->DataSetRangeByteOffset == 0); 15041 offloadWriteContext->DataSetRangesCount = dataSetRangesCount; 15042 15043 offloadWriteContext->DsmAttributes = dsmAttributes; 15044 offloadWriteContext->OffloadWriteParameters = offloadWriteParameters; 15045 offloadWriteContext->DataSetRanges = dataSetRanges; 15046 offloadWriteContext->LogicalBlockOffset = logicalBlockOffset; 15047 15048 ClasspGetTokenOperationDescriptorLimits(Fdo, 15049 SERVICE_ACTION_WRITE_USING_TOKEN, 15050 tokenOperationBufferLength, 15051 &maxBlockDescrCount, 15052 &maxLbaCount); 15053 15054 if (fdoExt->FunctionSupportInfo->BlockDeviceRODLimitsData.OptimalTransferCount && fdoExt->FunctionSupportInfo->BlockDeviceRODLimitsData.MaximumTokenTransferSize) { 15055 15056 NT_ASSERT(fdoExt->FunctionSupportInfo->BlockDeviceRODLimitsData.OptimalTransferCount <= fdoExt->FunctionSupportInfo->BlockDeviceRODLimitsData.MaximumTokenTransferSize); 15057 } 15058 15059 // 15060 // We will limit the maximum data transfer in an offload write operation to: 15061 // - 64MB if OptimalTransferCount = 0 15062 // - OptimalTransferCount if < 256MB 15063 // - 256MB if OptimalTransferCount >= 256MB 15064 // - MaximumTokenTransferSize if lesser than above chosen size 15065 // 15066 if (0 == fdoExt->FunctionSupportInfo->BlockDeviceRODLimitsData.OptimalTransferCount) { 15067 15068 maxLbaCount = MIN(maxLbaCount, (DEFAULT_MAX_NUMBER_BYTES_PER_SYNC_WRITE_USING_TOKEN / (ULONGLONG)fdoExt->DiskGeometry.BytesPerSector)); 15069 15070 } else if (fdoExt->FunctionSupportInfo->BlockDeviceRODLimitsData.OptimalTransferCount < (MAX_NUMBER_BYTES_PER_SYNC_WRITE_USING_TOKEN / (ULONGLONG)fdoExt->DiskGeometry.BytesPerSector)) { 15071 15072 maxLbaCount = MIN(maxLbaCount, fdoExt->FunctionSupportInfo->BlockDeviceRODLimitsData.OptimalTransferCount); 15073 15074 } else { 15075 15076 maxLbaCount = MIN(maxLbaCount, (MAX_NUMBER_BYTES_PER_SYNC_WRITE_USING_TOKEN / (ULONGLONG)fdoExt->DiskGeometry.BytesPerSector)); 15077 } 15078 15079 // 15080 // Since we do not want very fragmented files to end up causing the WriteUsingToken command to take 15081 // too long (and potentially timeout), we will limit the max number of descriptors sent down in a 15082 // command. 15083 // 15084 maxBlockDescrCount = MIN(maxBlockDescrCount, MAX_NUMBER_BLOCK_DEVICE_DESCRIPTORS); 15085 15086 TracePrint((TRACE_LEVEL_INFORMATION, 15087 TRACE_FLAG_IOCTL, 15088 "ClasspServiceWriteUsingTokenTransferRequest (%p): Using MaxBlockDescrCount %u and MaxLbaCount %I64u.\n", 15089 Fdo, 15090 maxBlockDescrCount, 15091 maxLbaCount)); 15092 15093 offloadWriteContext->MaxBlockDescrCount = maxBlockDescrCount; 15094 offloadWriteContext->MaxLbaCount = maxLbaCount; 15095 15096 // 15097 // Reuse a single buffer for both TokenOperation and ReceiveTokenInformation. This has the one disadvantage 15098 // that we'll be marking the page(s) as IoWriteAccess even though we only need read access for token 15099 // operation command and we may not even need to send down a ReceiveTokenInformation (in case of a successful 15100 // synchronous transfer). However, the advantage is that we eliminate the possibility of any potential 15101 // failures when trying to allocate an MDL for the ReceiveTokenInformation later on if we need to send it. 15102 // 15103 writeUsingTokenMdl = ClasspBuildDeviceMdl(buffer, bufferLength, FALSE); 15104 if (!writeUsingTokenMdl) { 15105 15106 TracePrint((TRACE_LEVEL_ERROR, 15107 TRACE_FLAG_IOCTL, 15108 "ClasspServiceWriteUsingTokenTransferRequest (%p): Failed to allocate MDL for WriteUsingToken operations.\n", 15109 Fdo)); 15110 15111 status = STATUS_INSUFFICIENT_RESOURCES; 15112 goto __ClasspServiceWriteUsingTokenTransferRequest_ErrorExit; 15113 } 15114 15115 offloadWriteContext->WriteUsingTokenMdl = writeUsingTokenMdl; 15116 15117 // 15118 // There are potentially two approaches that we can take: 15119 // 1. Determine how many transfer packets we need (in case we need to split the request), get 15120 // them all up-front and then send down all the split WriteUsingToken commands in parallel. 15121 // The benefit of this approach is that the performance will be improved in the success case. 15122 // But error case handling becomes very complex to handle, since if one of the intermediate 15123 // write fails, there is no way to cancel the remaining writes that were sent. Waiting for 15124 // such requests to complete in geo-distributed source and target cases can be very time 15125 // consuming. The complexity gets worse in the case that the target succeeds only a partial 15126 // amount of data for one the of intermediate split commands. 15127 // [OR] 15128 // 2. Until the entire data set range is processed, build the command for as much of the range as 15129 // possible, send down a packet, and once it completes, repeat sequentially in a loop. 15130 // The advantage of this approach is its simplistic nature. In the success case, it will 15131 // be less performant as compared to the previous approach, but since the gain of offload 15132 // copy is so significant compared to native buffered-copy, the tradeoff is acceptable. 15133 // In the failure case the simplicity offers the following benefit - if any command fails, 15134 // there is no further processing that is needed. And the cumulative total bytes that succeeded 15135 // (until the failing split WriteUsingToken command) is easily tracked. 15136 // 15137 // Given the above, we're going with the second approach. 15138 // 15139 15140 NT_ASSERT(status == STATUS_SUCCESS); // so far 15141 15142 // 15143 // Save (into the offloadReadContext) any remaining things that 15144 // ClasspPopulateTokenTransferPacketDone() will need. 15145 // 15146 15147 offloadWriteContext->BufferLength = bufferLength; 15148 offloadWriteContext->ReceiveTokenInformationBufferLength = receiveTokenInformationBufferLength; 15149 offloadWriteContext->EntireXferLen = entireXferLen; 15150 15151 IoMarkIrpPending(Irp); 15152 ClasspContinueOffloadWrite(offloadWriteContext); 15153 15154 status = STATUS_PENDING; 15155 goto __ClasspServiceWriteUsingTokenTransferRequest_Exit; 15156 15157 // 15158 // Error label only - not used in success case: 15159 // 15160 15161 __ClasspServiceWriteUsingTokenTransferRequest_ErrorExit: 15162 15163 NT_ASSERT(status != STATUS_PENDING); 15164 15165 if (offloadWriteContext != NULL) { 15166 ClasspCleanupOffloadWriteContext(offloadWriteContext); 15167 offloadWriteContext = NULL; 15168 } 15169 15170 __ClasspServiceWriteUsingTokenTransferRequest_Exit: 15171 15172 TracePrint((TRACE_LEVEL_VERBOSE, 15173 TRACE_FLAG_IOCTL, 15174 "ClasspServiceWriteUsingTokenTransferRequest (%p): Exiting function (Irp %p) with status %x.\n", 15175 Fdo, 15176 Irp, 15177 status)); 15178 15179 return status; 15180 } 15181 15182 15183 VOID 15184 #ifdef _MSC_VER 15185 #pragma warning(suppress: 28194) // This function will either alias or free OffloadWriteContext 15186 #endif 15187 ClasspContinueOffloadWrite( 15188 _In_ __drv_aliasesMem POFFLOAD_WRITE_CONTEXT OffloadWriteContext 15189 ) 15190 15191 /*++ 15192 15193 Routine description: 15194 15195 This routine continues an offload write operation. This routine expects the 15196 offload write operation to be set up and ready to start a WRITE USING TOKEN, 15197 but with no WRITE USING TOKEN currently in flight. 15198 15199 This routine is responsible for continuing or completing the offload write 15200 operation. 15201 15202 Arguments: 15203 15204 OffloadWriteContext - Pointer to the OFFLOAD_WRITE_CONTEXT for the offload 15205 write operation. 15206 15207 Return Value: 15208 15209 None. 15210 15211 --*/ 15212 15213 { 15214 BOOLEAN allDataSetRangeFullyConverted; 15215 ULONG blockDescrIndex; 15216 PBLOCK_DEVICE_RANGE_DESCRIPTOR blockDescrPointer; 15217 PVOID buffer; 15218 ULONG bufferLength; 15219 ULONGLONG dataSetRangeByteOffset; 15220 ULONG dataSetRangeIndex; 15221 PDEVICE_DATA_SET_RANGE dataSetRanges; 15222 ULONG dataSetRangesCount; 15223 ULONGLONG entireXferLen; 15224 PDEVICE_OBJECT fdo; 15225 PFUNCTIONAL_DEVICE_EXTENSION fdoExt; 15226 PIRP irp; 15227 ULONG lbaCount; 15228 ULONG listIdentifier; 15229 ULONGLONG logicalBlockOffset; 15230 ULONG maxBlockDescrCount; 15231 ULONGLONG maxLbaCount; 15232 PDEVICE_DSM_OFFLOAD_WRITE_PARAMETERS offloadWriteParameters; 15233 PTRANSFER_PACKET pkt; 15234 PIRP pseudoIrp; 15235 NTSTATUS status; 15236 DEVICE_DATA_SET_RANGE tempDataSetRange; 15237 BOOLEAN tempDataSetRangeFullyConverted; 15238 PVOID tokenAscii; 15239 ULONG tokenSize; 15240 ULONGLONG totalSectorCount; 15241 ULONGLONG totalSectorsProcessedSuccessfully; 15242 ULONGLONG totalSectorsToProcess; 15243 ULONG transferSize; 15244 USHORT writeUsingTokenDataLength; 15245 USHORT writeUsingTokenDescriptorsLength; 15246 PMDL writeUsingTokenMdl; 15247 15248 tokenAscii = NULL; 15249 tokenSize = BLOCK_DEVICE_TOKEN_SIZE; 15250 tempDataSetRangeFullyConverted = FALSE; 15251 allDataSetRangeFullyConverted = FALSE; 15252 fdo = OffloadWriteContext->Fdo; 15253 fdoExt = fdo->DeviceExtension; 15254 irp = OffloadWriteContext->OffloadWriteDsmIrp; 15255 buffer = OffloadWriteContext + 1; 15256 bufferLength = OffloadWriteContext->BufferLength; 15257 dataSetRanges = OffloadWriteContext->DataSetRanges; 15258 offloadWriteParameters = OffloadWriteContext->OffloadWriteParameters; 15259 pseudoIrp = &OffloadWriteContext->PseudoIrp; 15260 writeUsingTokenMdl = OffloadWriteContext->WriteUsingTokenMdl; 15261 entireXferLen = OffloadWriteContext->EntireXferLen; 15262 15263 RtlZeroMemory(buffer, bufferLength); 15264 15265 pkt = DequeueFreeTransferPacket(fdo, TRUE); 15266 if (!pkt){ 15267 15268 TracePrint((TRACE_LEVEL_ERROR, 15269 TRACE_FLAG_IOCTL, 15270 "ClasspContinueOffloadWrite (%p): Failed to retrieve transfer packet for TokenOperation (WriteUsingToken) operation.\n", 15271 fdo)); 15272 15273 status = STATUS_INSUFFICIENT_RESOURCES; 15274 goto __ClasspContinueOffloadWrite_ErrorExit; 15275 } 15276 15277 OffloadWriteContext->Pkt = pkt; 15278 15279 blockDescrPointer = (PBLOCK_DEVICE_RANGE_DESCRIPTOR) 15280 &((PWRITE_USING_TOKEN_HEADER)buffer)->BlockDeviceRangeDescriptor[0]; 15281 15282 blockDescrIndex = 0; 15283 lbaCount = 0; 15284 15285 totalSectorsToProcess = 0; 15286 15287 maxBlockDescrCount = OffloadWriteContext->MaxBlockDescrCount; 15288 maxLbaCount = OffloadWriteContext->MaxLbaCount; 15289 15290 // 15291 // The OffloadWriteContext->DataSetRangeIndex, DataSetRangeByteOffset, and 15292 // TotalSectorsProcessedSuccessfully don't move forward until RRTI has 15293 // reported the actual amount written. 15294 // 15295 // For that reason, this function only updates 15296 // OffloadWriteContext->TotalSectorsProcessed, which tracks the number of 15297 // sectors requested to be written by the current WRITE USING TOKEN command 15298 // (not all will necessarily be written). 15299 // 15300 15301 dataSetRangeIndex = OffloadWriteContext->DataSetRangeIndex; 15302 dataSetRangesCount = OffloadWriteContext->DataSetRangesCount; 15303 dataSetRangeByteOffset = OffloadWriteContext->DataSetRangeByteOffset; 15304 totalSectorsProcessedSuccessfully = OffloadWriteContext->TotalSectorsProcessedSuccessfully; 15305 15306 // 15307 // Send WriteUsingToken commands when the buffer is full or all input entries are converted. 15308 // 15309 while (!((blockDescrIndex == maxBlockDescrCount) || // buffer full or block descriptor count reached 15310 (lbaCount == maxLbaCount) || // block LBA count reached 15311 (allDataSetRangeFullyConverted))) { // all DataSetRanges have been converted 15312 15313 NT_ASSERT(dataSetRangeIndex < dataSetRangesCount); 15314 NT_ASSERT(dataSetRangeByteOffset < dataSetRanges[dataSetRangeIndex].LengthInBytes); 15315 15316 tempDataSetRange.StartingOffset = dataSetRanges[dataSetRangeIndex].StartingOffset + dataSetRangeByteOffset; 15317 tempDataSetRange.LengthInBytes = dataSetRanges[dataSetRangeIndex].LengthInBytes - dataSetRangeByteOffset; 15318 15319 totalSectorCount = 0; 15320 15321 ClasspConvertDataSetRangeToBlockDescr(fdo, 15322 blockDescrPointer, 15323 &blockDescrIndex, 15324 maxBlockDescrCount, 15325 &lbaCount, 15326 maxLbaCount, 15327 &tempDataSetRange, 15328 &totalSectorCount); 15329 15330 tempDataSetRangeFullyConverted = (tempDataSetRange.LengthInBytes == 0) ? TRUE : FALSE; 15331 15332 allDataSetRangeFullyConverted = tempDataSetRangeFullyConverted && ((dataSetRangeIndex + 1) == dataSetRangesCount); 15333 15334 if (tempDataSetRangeFullyConverted) { 15335 dataSetRangeIndex += 1; 15336 dataSetRangeByteOffset = 0; 15337 NT_ASSERT(dataSetRangeIndex <= dataSetRangesCount); 15338 } else { 15339 dataSetRangeByteOffset += totalSectorCount * fdoExt->DiskGeometry.BytesPerSector; 15340 NT_ASSERT(dataSetRangeByteOffset < dataSetRanges[dataSetRangeIndex].LengthInBytes); 15341 } 15342 15343 totalSectorsToProcess += totalSectorCount; 15344 } 15345 15346 // 15347 // Save the number of sectors being attempted in this WRITE USING TOKEN 15348 // command, so that a success return from the command will know how much 15349 // was written, without needing to issue a RECEIVE ROD TOKEN INFORMATION 15350 // command. 15351 // 15352 OffloadWriteContext->TotalSectorsToProcess = totalSectorsToProcess; 15353 OffloadWriteContext->TotalSectorsProcessed = 0; 15354 15355 // 15356 // Calculate transfer size, including the header 15357 // 15358 transferSize = (blockDescrIndex * sizeof(BLOCK_DEVICE_RANGE_DESCRIPTOR)) + FIELD_OFFSET(WRITE_USING_TOKEN_HEADER, BlockDeviceRangeDescriptor); 15359 15360 NT_ASSERT(transferSize <= MAX_TOKEN_OPERATION_PARAMETER_DATA_LENGTH); 15361 15362 writeUsingTokenDataLength = (USHORT)transferSize - RTL_SIZEOF_THROUGH_FIELD(WRITE_USING_TOKEN_HEADER, WriteUsingTokenDataLength); 15363 REVERSE_BYTES_SHORT(((PWRITE_USING_TOKEN_HEADER)buffer)->WriteUsingTokenDataLength, &writeUsingTokenDataLength); 15364 15365 ((PWRITE_USING_TOKEN_HEADER)buffer)->Immediate = 0; 15366 15367 logicalBlockOffset = OffloadWriteContext->LogicalBlockOffset + totalSectorsProcessedSuccessfully; 15368 REVERSE_BYTES_QUAD(((PWRITE_USING_TOKEN_HEADER)buffer)->BlockOffsetIntoToken, &logicalBlockOffset); 15369 15370 RtlCopyMemory(((PWRITE_USING_TOKEN_HEADER)buffer)->Token, 15371 &offloadWriteParameters->Token, 15372 BLOCK_DEVICE_TOKEN_SIZE); 15373 15374 writeUsingTokenDescriptorsLength = (USHORT)transferSize - FIELD_OFFSET(WRITE_USING_TOKEN_HEADER, BlockDeviceRangeDescriptor); 15375 REVERSE_BYTES_SHORT(((PWRITE_USING_TOKEN_HEADER)buffer)->BlockDeviceRangeDescriptorListLength, &writeUsingTokenDescriptorsLength); 15376 15377 RtlZeroMemory(pseudoIrp, sizeof(IRP)); 15378 15379 pseudoIrp->IoStatus.Status = STATUS_SUCCESS; 15380 pseudoIrp->IoStatus.Information = 0; 15381 pseudoIrp->Tail.Overlay.DriverContext[0] = LongToPtr(1); 15382 pseudoIrp->MdlAddress = writeUsingTokenMdl; 15383 15384 InterlockedCompareExchange((volatile LONG *)&TokenOperationListIdentifier, -1, MaxTokenOperationListIdentifier); 15385 listIdentifier = InterlockedIncrement((volatile LONG *)&TokenOperationListIdentifier); 15386 15387 ClasspSetupWriteUsingTokenTransferPacket( 15388 OffloadWriteContext, 15389 pkt, 15390 transferSize, 15391 (PUCHAR)buffer, 15392 pseudoIrp, 15393 listIdentifier); 15394 15395 tokenAscii = ClasspBinaryToAscii((PUCHAR)(((PWRITE_USING_TOKEN_HEADER)buffer)->Token), 15396 tokenSize, 15397 &tokenSize); 15398 15399 TracePrint((TRACE_LEVEL_INFORMATION, 15400 TRACE_FLAG_IOCTL, 15401 "ClasspContinueOffloadWrite (%p): Offloading write for %I64u bytes (versus %I64u) [via %u descriptors]. \ 15402 \n\t\t\tDataLength: %u, DescriptorsLength: %u. Pkt %p (list id %x) [Token: %s]\n", 15403 fdo, 15404 totalSectorsToProcess * fdoExt->DiskGeometry.BytesPerSector, 15405 entireXferLen, 15406 blockDescrIndex, 15407 writeUsingTokenDataLength, 15408 writeUsingTokenDescriptorsLength, 15409 pkt, 15410 listIdentifier, 15411 (tokenAscii == NULL) ? "" : tokenAscii)); 15412 15413 FREE_POOL(tokenAscii); 15414 15415 OffloadWriteContext->ListIdentifier = listIdentifier; 15416 15417 SubmitTransferPacket(pkt); 15418 15419 // 15420 // ClasspWriteUsingTokenTransferPacketDone() takes care of completing the 15421 // IRP, so this function is done. 15422 // 15423 15424 return; 15425 15426 // 15427 // Error cleaup label only - not used in success case: 15428 // 15429 15430 __ClasspContinueOffloadWrite_ErrorExit: 15431 15432 NT_ASSERT(!NT_SUCCESS(status)); 15433 15434 // 15435 // ClasspCompleteOffloadWrite also cleans up offloadWriteContext. 15436 // 15437 15438 ClasspCompleteOffloadWrite(OffloadWriteContext, status); 15439 15440 return; 15441 } 15442 15443 15444 VOID 15445 ClasspAdvanceOffloadWritePosition( 15446 _In_ POFFLOAD_WRITE_CONTEXT OffloadWriteContext, 15447 _In_ ULONGLONG SectorsToAdvance 15448 ) 15449 15450 /*++ 15451 15452 Routine description: 15453 15454 After the target has responded to WRITE USING TOKEN with success, or RRTI 15455 with a specific TRANSFER COUNT, this routine is used to update the relative 15456 position within the overall offload write request. This position includes 15457 the TotalSectorsProcessedSuccessfully, the DataSetRangeIndex, and the 15458 DataSetRangeByteOffset. 15459 15460 The caller is responsible for continuing or completing the offload write 15461 operation (this routine doesn't do that). 15462 15463 Arguments: 15464 15465 OffloadWriteContext - Pointer to the OFFLOAD_WRITE_CONTEXT for the offload 15466 write operation. 15467 15468 SectorsToAdvance - The number of sectors which were just written 15469 successfully (not the total for the offload write operation overall, 15470 just the number done by the most recent WRITE USING TOKEN). 15471 15472 Return Value: 15473 15474 None. 15475 15476 --*/ 15477 15478 { 15479 ULONGLONG bytesToAdvance; 15480 ULONGLONG bytesToDo; 15481 PULONGLONG dataSetRangeByteOffset; 15482 PULONG dataSetRangeIndex; 15483 PDEVICE_DATA_SET_RANGE dataSetRanges; 15484 PDEVICE_OBJECT fdo; 15485 PFUNCTIONAL_DEVICE_EXTENSION fdoExt; 15486 PULONGLONG totalSectorsProcessedSuccessfully; 15487 15488 fdo = OffloadWriteContext->Fdo; 15489 fdoExt = fdo->DeviceExtension; 15490 dataSetRanges = OffloadWriteContext->DataSetRanges; 15491 dataSetRangeByteOffset = &OffloadWriteContext->DataSetRangeByteOffset; 15492 dataSetRangeIndex = &OffloadWriteContext->DataSetRangeIndex; 15493 totalSectorsProcessedSuccessfully = &OffloadWriteContext->TotalSectorsProcessedSuccessfully; 15494 bytesToAdvance = SectorsToAdvance * fdoExt->DiskGeometry.BytesPerSector; 15495 15496 (*totalSectorsProcessedSuccessfully) += SectorsToAdvance; 15497 NT_ASSERT((*totalSectorsProcessedSuccessfully) <= OffloadWriteContext->TotalRequestSizeSectors); 15498 15499 while (bytesToAdvance != 0) { 15500 bytesToDo = dataSetRanges[*dataSetRangeIndex].LengthInBytes - *dataSetRangeByteOffset; 15501 if (bytesToDo > bytesToAdvance) { 15502 bytesToDo = bytesToAdvance; 15503 } 15504 (*dataSetRangeByteOffset) += bytesToDo; 15505 bytesToAdvance -= bytesToDo; 15506 if ((*dataSetRangeByteOffset) == dataSetRanges[*dataSetRangeIndex].LengthInBytes) { 15507 (*dataSetRangeIndex) += 1; 15508 (*dataSetRangeByteOffset) = 0; 15509 } 15510 } 15511 15512 NT_ASSERT((*dataSetRangeIndex) <= OffloadWriteContext->DataSetRangesCount); 15513 15514 return; 15515 } 15516 15517 15518 VOID 15519 ClasspWriteUsingTokenTransferPacketDone( 15520 _In_ PVOID Context 15521 ) 15522 15523 /*++ 15524 15525 Routine description: 15526 15527 This routine continues an offload write operation when the WRITE USING 15528 TOKEN transfer packet completes. 15529 15530 This routine may be able to determine that all requested sectors were 15531 written if the WRITE USING TOKEN completed with success, or may need to 15532 issue a RECEIVE ROD TOKEN INFORMATION if the WRITE USING TOKEN indicated 15533 check condition. 15534 15535 This routine is responsible for continuing or completing the offload write 15536 operation. 15537 15538 Arguments: 15539 15540 Context - Pointer to the OFFLOAD_WRITE_CONTEXT for the offload write 15541 operation. 15542 15543 Return Value: 15544 15545 None. 15546 15547 --*/ 15548 15549 { 15550 ULONGLONG entireXferLen; 15551 PDEVICE_OBJECT fdo; 15552 PFUNCTIONAL_DEVICE_EXTENSION fdoExt; 15553 ULONG listIdentifier; 15554 POFFLOAD_WRITE_CONTEXT offloadWriteContext; 15555 PTRANSFER_PACKET pkt; 15556 PIRP pseudoIrp; 15557 NTSTATUS status; 15558 PBOOLEAN tokenInvalidated; 15559 ULONGLONG totalSectorsToProcess; 15560 15561 offloadWriteContext = Context; 15562 pseudoIrp = &offloadWriteContext->PseudoIrp; 15563 fdo = offloadWriteContext->Fdo; 15564 fdoExt = fdo->DeviceExtension; 15565 listIdentifier = offloadWriteContext->ListIdentifier; 15566 totalSectorsToProcess = offloadWriteContext->TotalSectorsToProcess; 15567 entireXferLen = offloadWriteContext->EntireXferLen; 15568 tokenInvalidated = &offloadWriteContext->TokenInvalidated; 15569 pkt = offloadWriteContext->Pkt; 15570 15571 offloadWriteContext->Pkt = NULL; 15572 15573 15574 status = pseudoIrp->IoStatus.Status; 15575 NT_ASSERT(status != STATUS_PENDING); 15576 15577 // 15578 // If the request failed with any of the following errors, then it is meaningless to send 15579 // down a ReceiveTokenInformation (regardless of whether the transfer was requested as sync 15580 // or async), since the target has no saved information about the command: 15581 // - STATUS_INVALID_TOKEN 15582 // - STATUS_INVALID_PARAMETER 15583 // 15584 if (status == STATUS_INVALID_PARAMETER || 15585 status == STATUS_INVALID_TOKEN) { 15586 15587 TracePrint((TRACE_LEVEL_ERROR, 15588 TRACE_FLAG_IOCTL, 15589 "ClasspWriteUsingTokenTransferPacketDone (%p): Write failed with %x (list id %x).\n", 15590 fdo, 15591 status, 15592 listIdentifier)); 15593 15594 // 15595 // If the token isn't valid any longer, we should let the upper layers know so that 15596 // they don't waste time retrying the write with the same token. 15597 // 15598 if (status == STATUS_INVALID_TOKEN) { 15599 15600 *tokenInvalidated = TRUE; 15601 } 15602 15603 NT_ASSERT(status != STATUS_PENDING && !NT_SUCCESS(status)); 15604 goto __ClasspWriteUsingTokenTransferPacketDone_Exit; 15605 15606 } else if ((NT_SUCCESS(status)) && 15607 (pkt->Srb->SrbStatus == SRB_STATUS_SUCCESS || pkt->TransferCount != 0)) { 15608 15609 // 15610 // If the TokenOperation command was sent to the target requesting synchronous data 15611 // transfer, a success indicates that the command is complete. 15612 // This could either be because of a successful completion of the entire transfer 15613 // or because of a partial transfer due to target truncation. If it is the latter, 15614 // and the information field of the sense data has returned the TransferCount, we 15615 // can avoid sending down an RRTI. 15616 // 15617 if (pkt->Srb->SrbStatus == SRB_STATUS_SUCCESS) { 15618 15619 // 15620 // The entire transfer has completed successfully. 15621 // 15622 offloadWriteContext->TotalSectorsProcessed = totalSectorsToProcess; 15623 TracePrint((TRACE_LEVEL_INFORMATION, 15624 TRACE_FLAG_IOCTL, 15625 "ClasspWriteUsingTokenTransferPacketDone (%p): Successfully wrote using token %I64u (out of %I64u) bytes (list Id %x).\n", 15626 fdo, 15627 totalSectorsToProcess * fdoExt->DiskGeometry.BytesPerSector, 15628 entireXferLen, 15629 listIdentifier)); 15630 } else { 15631 15632 // 15633 // The target has returned how much data it transferred in the response to the 15634 // WUT command itself, allowing us to optimize by removing the necessaity for 15635 // sending down an RRTI to query the TransferCount. 15636 // 15637 NT_ASSERT(pkt->TransferCount); 15638 15639 offloadWriteContext->TotalSectorsProcessed = totalSectorsToProcess = pkt->TransferCount; 15640 TracePrint((TRACE_LEVEL_INFORMATION, 15641 TRACE_FLAG_IOCTL, 15642 "ClasspWriteUsingTokenTransferPacketDone (%p): Target truncated write using token %I64u (out of %I64u) bytes (list Id %x).\n", 15643 fdo, 15644 totalSectorsToProcess * fdoExt->DiskGeometry.BytesPerSector, 15645 entireXferLen, 15646 listIdentifier)); 15647 } 15648 15649 ClasspAdvanceOffloadWritePosition(offloadWriteContext, totalSectorsToProcess); 15650 15651 NT_ASSERT(status != STATUS_PENDING); 15652 15653 // 15654 // ClasspReceiveWriteUsingTokenInformationDone() takes care of 15655 // completing the operation (eventually), so pending from point of view 15656 // of this function. 15657 // 15658 15659 ClasspReceiveWriteUsingTokenInformationDone(offloadWriteContext, status); 15660 status = STATUS_PENDING; 15661 15662 goto __ClasspWriteUsingTokenTransferPacketDone_Exit; 15663 15664 } else { 15665 15666 // 15667 // Since the TokenOperation was failed (or the target truncated the transfer but 15668 // didn't indicate the amount), we need to send down ReceiveTokenInformation. 15669 // 15670 TracePrint((TRACE_LEVEL_ERROR, 15671 TRACE_FLAG_IOCTL, 15672 "ClasspWriteUsingTokenTransferPacketDone (%p): Write failed with status %x, %x (list id %x).\n", 15673 fdo, 15674 status, 15675 pkt->Srb->SrbStatus, 15676 listIdentifier)); 15677 15678 ClasspReceiveWriteUsingTokenInformation(offloadWriteContext); 15679 15680 status = STATUS_PENDING; 15681 goto __ClasspWriteUsingTokenTransferPacketDone_Exit; 15682 } 15683 15684 __ClasspWriteUsingTokenTransferPacketDone_Exit: 15685 15686 if (status != STATUS_PENDING) { 15687 ClasspCompleteOffloadWrite(offloadWriteContext, status); 15688 } 15689 15690 return; 15691 } 15692 15693 15694 VOID 15695 ClasspReceiveWriteUsingTokenInformationDone( 15696 _In_ POFFLOAD_WRITE_CONTEXT OffloadWriteContext, 15697 _In_ NTSTATUS CompletionCausingStatus 15698 ) 15699 15700 /*++ 15701 15702 Routine description: 15703 15704 This routine continues an offload write operation when a WRITE USING TOKEN 15705 and possible associated RECEIVE ROD TOKEN INFORMATION have both fully 15706 completed and the RRTI has indicated completion of the WUT. 15707 15708 This routine checks to see if the total sectors written is already equal to 15709 the overall total requested sector count, and if so, completes the offload 15710 write operation. If not, this routine continues the operation by issuing 15711 another WUT. 15712 15713 This routine is responsible for continuing or completing the offload write 15714 operation. 15715 15716 Arguments: 15717 15718 OffloadWriteContext - Pointer to the OFFLOAD_WRITE_CONTEXT for the offload 15719 write operation. 15720 15721 Return Value: 15722 15723 None. 15724 15725 --*/ 15726 15727 { 15728 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = OffloadWriteContext->Fdo->DeviceExtension; 15729 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData; 15730 15731 // 15732 // Time taken in 100ns units. 15733 // 15734 ULONGLONG durationIn100ns = (KeQueryInterruptTime() - OffloadWriteContext->OperationStartTime); 15735 ULONGLONG maxTargetDuration = fdoData->CopyOffloadMaxTargetDuration * 10ULL * 1000 * 1000; 15736 15737 NT_ASSERT( 15738 OffloadWriteContext->TotalSectorsProcessedSuccessfully <= 15739 OffloadWriteContext->TotalRequestSizeSectors); 15740 15741 15742 if (OffloadWriteContext->TotalSectorsProcessedSuccessfully == OffloadWriteContext->TotalRequestSizeSectors) { 15743 15744 ClasspCompleteOffloadWrite(OffloadWriteContext, CompletionCausingStatus); 15745 15746 goto __ClasspReceiveWriteUsingTokenInformationDone_Exit; 15747 } 15748 15749 // 15750 // Since we don't want a layered timeout mechanism (e.g. guest and parent OS in Hyper-V scenarios) 15751 // to cause a SCSI timeout for the higher layer token operations. 15752 // 15753 if (maxTargetDuration <= durationIn100ns) { 15754 15755 TracePrint((TRACE_LEVEL_WARNING, 15756 TRACE_FLAG_IOCTL, 15757 "ClasspReceiveWriteUsingTokenInformationDone (%p): Truncating write (list id %x) because of max-duration-rule.\n", 15758 OffloadWriteContext->Fdo, 15759 OffloadWriteContext->ListIdentifier)); 15760 15761 // 15762 // We could technically pass in STATUS_IO_OPERATION_TIMEOUT, but ClasspCompleteOffloadWrite 15763 // won't end up doing anything (useful) with this status, since some bytes would already 15764 // have been transferred. 15765 // 15766 ClasspCompleteOffloadWrite(OffloadWriteContext, STATUS_UNSUCCESSFUL); 15767 15768 goto __ClasspReceiveWriteUsingTokenInformationDone_Exit; 15769 } 15770 15771 NT_ASSERT( 15772 OffloadWriteContext->TotalSectorsProcessedSuccessfully < 15773 OffloadWriteContext->TotalRequestSizeSectors); 15774 15775 // 15776 // Keep going with the next sub-request. 15777 // 15778 15779 ClasspContinueOffloadWrite(OffloadWriteContext); 15780 15781 __ClasspReceiveWriteUsingTokenInformationDone_Exit: 15782 15783 return; 15784 } 15785 15786 15787 VOID 15788 ClasspCompleteOffloadWrite( 15789 _In_ __drv_freesMem(Mem) POFFLOAD_WRITE_CONTEXT OffloadWriteContext, 15790 _In_ NTSTATUS CompletionCausingStatus 15791 ) 15792 15793 /*++ 15794 15795 Routine description: 15796 15797 This routine is used to complete an offload write operation. 15798 15799 The input CompletionCausingStatus doesn't necessarily drive the completion 15800 status of the offload write operation overall, if the offload write 15801 operation overall has previously written some sectors successfully. 15802 15803 This routine completes the offload write operation. 15804 15805 Arguments: 15806 15807 OffloadWriteContext - Pointer to the OFFLOAD_WRITE_CONTEXT for the offload 15808 write operation. 15809 15810 CompletionCausingStatus - Status code indicating a reason that the offload 15811 write operation is completing. For success this will be STATUS_SUCCESS, 15812 but for a failure, this status will indicate what failure occurred. 15813 This status doesn't directly propagate to the completion status of the 15814 overall offload write operation if this status is failure and the 15815 overall offload write operation has already previously written some 15816 sectors successfully. 15817 15818 Return Value: 15819 15820 None. 15821 15822 --*/ 15823 15824 { 15825 PDEVICE_OBJECT fdo; 15826 PFUNCTIONAL_DEVICE_EXTENSION fdoExt; 15827 PDEVICE_MANAGE_DATA_SET_ATTRIBUTES dsmAttributes; 15828 PULONGLONG totalSectorsProcessedSuccessfully; 15829 ULONGLONG entireXferLen; 15830 PIRP irp; 15831 PBOOLEAN tokenInvalidated; 15832 ULONG listIdentifier; 15833 ULONGLONG totalSectorsProcessed; 15834 NTSTATUS status; 15835 ULONGLONG totalBytesProcessed; 15836 15837 fdo = OffloadWriteContext->Fdo; 15838 fdoExt = fdo->DeviceExtension; 15839 dsmAttributes = OffloadWriteContext->DsmAttributes; 15840 totalSectorsProcessedSuccessfully = &OffloadWriteContext->TotalSectorsProcessedSuccessfully; 15841 entireXferLen = OffloadWriteContext->EntireXferLen; 15842 irp = OffloadWriteContext->OffloadWriteDsmIrp; 15843 tokenInvalidated = &OffloadWriteContext->TokenInvalidated; 15844 listIdentifier = OffloadWriteContext->ListIdentifier; 15845 totalSectorsProcessed = OffloadWriteContext->TotalSectorsProcessed; 15846 status = CompletionCausingStatus; 15847 15848 ((PSTORAGE_OFFLOAD_WRITE_OUTPUT)dsmAttributes)->OffloadWriteFlags = 0; 15849 ((PSTORAGE_OFFLOAD_WRITE_OUTPUT)dsmAttributes)->Reserved = 0; 15850 15851 totalBytesProcessed = (*totalSectorsProcessedSuccessfully) * fdoExt->DiskGeometry.BytesPerSector; 15852 15853 TracePrint((totalBytesProcessed == entireXferLen ? TRACE_LEVEL_INFORMATION : TRACE_LEVEL_WARNING, 15854 TRACE_FLAG_IOCTL, 15855 "ClasspCompleteOffloadWrite (%p): %ws wrote using token %I64u (out of %I64u) bytes (Irp %p).\n", 15856 fdo, 15857 NT_SUCCESS(status) ? L"Successful" : L"Failed", 15858 totalBytesProcessed, 15859 entireXferLen, 15860 irp)); 15861 15862 if (totalBytesProcessed > 0 && totalBytesProcessed < entireXferLen) { 15863 SET_FLAG(((PSTORAGE_OFFLOAD_WRITE_OUTPUT)dsmAttributes)->OffloadWriteFlags, STORAGE_OFFLOAD_WRITE_RANGE_TRUNCATED); 15864 } 15865 if (*tokenInvalidated) { 15866 SET_FLAG(((PSTORAGE_OFFLOAD_WRITE_OUTPUT)dsmAttributes)->OffloadWriteFlags, STORAGE_OFFLOAD_TOKEN_INVALID); 15867 } 15868 ((PSTORAGE_OFFLOAD_WRITE_OUTPUT)dsmAttributes)->LengthCopied = totalBytesProcessed; 15869 15870 15871 if (!NT_SUCCESS(status)) { 15872 15873 TracePrint((TRACE_LEVEL_WARNING, 15874 TRACE_FLAG_IOCTL, 15875 "ClasspCompleteOffloadWrite (%p): TokenOperation for WriteUsingToken (list Id %u) completed with %x writing %I64u blocks (currentTotal %I64u blocks).\n", 15876 fdo, 15877 listIdentifier, 15878 status, 15879 totalSectorsProcessed, 15880 *totalSectorsProcessedSuccessfully)); 15881 15882 // 15883 // Even if target returned an error, from the OS upper layers' perspective, 15884 // it is a success (with truncation) if any data at all was written. 15885 // 15886 if (*totalSectorsProcessedSuccessfully) { 15887 status = STATUS_SUCCESS; 15888 } 15889 } 15890 15891 irp->IoStatus.Information = sizeof(STORAGE_OFFLOAD_WRITE_OUTPUT); 15892 15893 ClasspCompleteOffloadRequest(fdo, irp, status); 15894 ClasspCleanupOffloadWriteContext(OffloadWriteContext); 15895 OffloadWriteContext = NULL; 15896 15897 return; 15898 } 15899 15900 15901 VOID 15902 ClasspCleanupOffloadWriteContext( 15903 _In_ __drv_freesMem(mem) POFFLOAD_WRITE_CONTEXT OffloadWriteContext 15904 ) 15905 15906 /*++ 15907 15908 Routine description: 15909 15910 This routine cleans up an offload write context. 15911 15912 Arguments: 15913 15914 OffloadWriteContext - Pointer to the OFFLOAD_WRITE_CONTEXT for the offload 15915 write operation. 15916 15917 Return Value: 15918 15919 None. 15920 15921 --*/ 15922 15923 { 15924 PMDL writeUsingTokenMdl = OffloadWriteContext->WriteUsingTokenMdl; 15925 15926 if (writeUsingTokenMdl) { 15927 ClasspFreeDeviceMdl(writeUsingTokenMdl); 15928 } 15929 FREE_POOL(OffloadWriteContext); 15930 15931 return; 15932 } 15933 15934 15935 _IRQL_requires_same_ 15936 VOID 15937 ClasspReceiveWriteUsingTokenInformation( 15938 _In_ POFFLOAD_WRITE_CONTEXT OffloadWriteContext 15939 ) 15940 15941 /*++ 15942 15943 Routine description: 15944 15945 This routine retrieves the token after a WriteUsingToken command 15946 has been sent down in case of an error or if there is a need to 15947 poll for the result. 15948 15949 This routine is responsible for continuing or completing the offload write 15950 operation. 15951 15952 Arguments: 15953 15954 OffloadWriteContext - Pointer to the OFFLOAD_WRITE_CONTEXT for the offload 15955 write operation. 15956 15957 Return Value: 15958 15959 None. 15960 15961 --*/ 15962 15963 { 15964 PVOID buffer; 15965 ULONG bufferLength; 15966 ULONG cdbLength; 15967 PDEVICE_OBJECT fdo; 15968 PIRP irp; 15969 ULONG listIdentifier; 15970 PTRANSFER_PACKET pkt; 15971 PIRP pseudoIrp; 15972 ULONG receiveTokenInformationBufferLength; 15973 PSCSI_REQUEST_BLOCK srb; 15974 NTSTATUS status; 15975 ULONG tempSizeUlong; 15976 PMDL writeUsingTokenMdl; 15977 15978 fdo = OffloadWriteContext->Fdo; 15979 irp = OffloadWriteContext->OffloadWriteDsmIrp; 15980 pseudoIrp = &OffloadWriteContext->PseudoIrp; 15981 buffer = OffloadWriteContext + 1; 15982 bufferLength = OffloadWriteContext->BufferLength; 15983 receiveTokenInformationBufferLength = OffloadWriteContext->ReceiveTokenInformationBufferLength; 15984 writeUsingTokenMdl = OffloadWriteContext->WriteUsingTokenMdl; 15985 listIdentifier = OffloadWriteContext->ListIdentifier; 15986 srb = &OffloadWriteContext->Srb; 15987 status = STATUS_SUCCESS; 15988 15989 TracePrint((TRACE_LEVEL_VERBOSE, 15990 TRACE_FLAG_IOCTL, 15991 "ClasspReceiveWriteUsingTokenInformation (%p): Entering function. Irp %p\n", 15992 fdo, 15993 irp)); 15994 15995 // 15996 // The WRITE USING TOKEN wasn't immediately fully successful, so that means 15997 // the only way to find out how many sectors were processed by the WRITE 15998 // USING TOKEN is to get a successful RECEIVE ROD TOKEN INFORMATION that 15999 // indicates the operation is complete. 16000 // 16001 16002 NT_ASSERT(OffloadWriteContext->TotalSectorsProcessed == 0); 16003 16004 pkt = DequeueFreeTransferPacket(fdo, TRUE); 16005 16006 if (!pkt) { 16007 16008 TracePrint((TRACE_LEVEL_ERROR, 16009 TRACE_FLAG_IOCTL, 16010 "ClasspReceiveWriteUsingTokenInformation (%p): Failed to retrieve transfer packet for ReceiveTokenInformation (WriteUsingToken) operation.\n", 16011 fdo)); 16012 16013 status = STATUS_INSUFFICIENT_RESOURCES; 16014 16015 goto __ClasspReceiveWriteUsingTokenInformation_ErrorExit; 16016 } 16017 16018 RtlZeroMemory(buffer, bufferLength); 16019 16020 tempSizeUlong = receiveTokenInformationBufferLength - 4; 16021 REVERSE_BYTES(((PRECEIVE_TOKEN_INFORMATION_HEADER)buffer)->AvailableData, &tempSizeUlong); 16022 16023 RtlZeroMemory(pseudoIrp, sizeof(IRP)); 16024 16025 pseudoIrp->IoStatus.Status = STATUS_SUCCESS; 16026 pseudoIrp->IoStatus.Information = 0; 16027 pseudoIrp->Tail.Overlay.DriverContext[0] = LongToPtr(1); 16028 pseudoIrp->MdlAddress = writeUsingTokenMdl; 16029 16030 ClasspSetupReceiveWriteUsingTokenInformationTransferPacket( 16031 OffloadWriteContext, 16032 pkt, 16033 bufferLength, 16034 (PUCHAR)buffer, 16035 pseudoIrp, 16036 listIdentifier); 16037 16038 // 16039 // Cache away the CDB as it may be required for forwarded sense data 16040 // after this command completes. 16041 // 16042 RtlZeroMemory(srb, sizeof(*srb)); 16043 cdbLength = SrbGetCdbLength(pkt->Srb); 16044 if (cdbLength <= 16) { 16045 RtlCopyMemory(&srb->Cdb, SrbGetCdb(pkt->Srb), cdbLength); 16046 } 16047 16048 SubmitTransferPacket(pkt); 16049 16050 return; 16051 16052 // 16053 // Error label only - not used by success cases: 16054 // 16055 16056 __ClasspReceiveWriteUsingTokenInformation_ErrorExit: 16057 16058 NT_ASSERT(!NT_SUCCESS(status)); 16059 16060 // 16061 // ClasspCompleteOffloadWrite also cleans up OffloadWriteContext. 16062 // 16063 16064 ClasspCompleteOffloadWrite(OffloadWriteContext, status); 16065 16066 return; 16067 } 16068 16069 16070 VOID 16071 ClasspReceiveWriteUsingTokenInformationTransferPacketDone( 16072 _In_ POFFLOAD_WRITE_CONTEXT OffloadWriteContext 16073 ) 16074 16075 /*++ 16076 16077 Routine description: 16078 16079 This routine continues an offload write operation when a RECEIVE ROD TOKEN 16080 INFORMATION transfer packet is done. 16081 16082 This routine may need to send another RRTI, or it may be able to indicate 16083 that this WUT is done via call to 16084 ClasspReceiveWriteUsingTokenInformationDone(). 16085 16086 This routine is responsible for continuing or completing the offload write 16087 operation. 16088 16089 Arguments: 16090 16091 OffloadWriteContext - Pointer to the OFFLOAD_WRITE_CONTEXT for the offload 16092 write operation. 16093 16094 Return Value: 16095 16096 None. 16097 16098 --*/ 16099 16100 { 16101 ULONG availableData; 16102 PVOID buffer; 16103 UCHAR completionStatus; 16104 ULONG estimatedRetryInterval; 16105 PDEVICE_OBJECT fdo; 16106 PFUNCTIONAL_DEVICE_EXTENSION fdoExt; 16107 PIRP irp; 16108 ULONG listIdentifier; 16109 BOOLEAN operationCompleted; 16110 UCHAR operationStatus; 16111 PIRP pseudoIrp; 16112 USHORT segmentsProcessed; 16113 PSENSE_DATA senseData; 16114 ULONG senseDataFieldLength; 16115 UCHAR senseDataLength; 16116 PSCSI_REQUEST_BLOCK srb; 16117 NTSTATUS status; 16118 ULONG tokenDescriptorLength; 16119 PRECEIVE_TOKEN_INFORMATION_HEADER tokenInformationResults; 16120 PRECEIVE_TOKEN_INFORMATION_RESPONSE_HEADER tokenInformationResponsePadding; 16121 PBOOLEAN tokenInvalidated; 16122 PULONGLONG totalSectorsProcessed; 16123 ULONGLONG totalSectorsToProcess; 16124 ULONGLONG transferBlockCount; 16125 16126 fdo = OffloadWriteContext->Fdo; 16127 fdoExt = fdo->DeviceExtension; 16128 listIdentifier = OffloadWriteContext->ListIdentifier; 16129 totalSectorsProcessed = &OffloadWriteContext->TotalSectorsProcessed; 16130 totalSectorsToProcess = OffloadWriteContext->TotalSectorsToProcess; 16131 irp = OffloadWriteContext->OffloadWriteDsmIrp; 16132 pseudoIrp = &OffloadWriteContext->PseudoIrp; 16133 tokenInvalidated = &OffloadWriteContext->TokenInvalidated; 16134 srb = &OffloadWriteContext->Srb; 16135 operationCompleted = FALSE; 16136 buffer = OffloadWriteContext + 1; 16137 tokenInformationResults = (PRECEIVE_TOKEN_INFORMATION_HEADER)buffer; 16138 senseData = (PSENSE_DATA)((PUCHAR)tokenInformationResults + FIELD_OFFSET(RECEIVE_TOKEN_INFORMATION_HEADER, SenseData)); 16139 transferBlockCount = 0; 16140 tokenInformationResponsePadding = NULL; 16141 tokenDescriptorLength = 0; 16142 16143 NT_ASSERT((*totalSectorsProcessed) == 0); 16144 16145 OffloadWriteContext->Pkt = NULL; 16146 16147 16148 status = pseudoIrp->IoStatus.Status; 16149 NT_ASSERT(status != STATUS_PENDING); 16150 16151 // 16152 // The buffer we hand allows for the max sizes for all the fields whereas the returned 16153 // data may be lesser (e.g. sense data info will almost never be MAX_SENSE_BUFFER_SIZE, etc. 16154 // so handle underrun "error" 16155 // 16156 if (status == STATUS_DATA_OVERRUN) { 16157 16158 status = STATUS_SUCCESS; 16159 } 16160 16161 if (!NT_SUCCESS(status)) { 16162 TracePrint((TRACE_LEVEL_ERROR, 16163 TRACE_FLAG_IOCTL, 16164 "ClasspReceiveWriteUsingTokenInformationTransferPacketDone (%p): Failed with %x to retrieve write results for list Id %x for data size %I64u bytes.\n", 16165 fdo, 16166 status, 16167 listIdentifier, 16168 totalSectorsToProcess * fdoExt->DiskGeometry.BytesPerSector)); 16169 16170 NT_ASSERT((*totalSectorsProcessed) == 0); 16171 16172 goto __ClasspReceiveWriteUsingTokenInformationTransferPacketDone_ErrorExit; 16173 } 16174 16175 REVERSE_BYTES(&availableData, &tokenInformationResults->AvailableData); 16176 16177 NT_ASSERT(availableData <= FIELD_OFFSET(RECEIVE_TOKEN_INFORMATION_HEADER, SenseData) + MAX_SENSE_BUFFER_SIZE); 16178 16179 NT_ASSERT(tokenInformationResults->ResponseToServiceAction == SERVICE_ACTION_WRITE_USING_TOKEN); 16180 16181 operationStatus = tokenInformationResults->OperationStatus; 16182 operationCompleted = ClasspIsTokenOperationComplete(operationStatus); 16183 NT_ASSERT(operationCompleted); 16184 16185 REVERSE_BYTES(&estimatedRetryInterval, &tokenInformationResults->EstimatedStatusUpdateDelay); 16186 16187 completionStatus = tokenInformationResults->CompletionStatus; 16188 16189 senseDataFieldLength = tokenInformationResults->SenseDataFieldLength; 16190 senseDataLength = tokenInformationResults->SenseDataLength; 16191 NT_ASSERT(senseDataFieldLength >= senseDataLength); 16192 16193 tokenInformationResponsePadding = (PRECEIVE_TOKEN_INFORMATION_RESPONSE_HEADER)((PUCHAR)tokenInformationResults + 16194 FIELD_OFFSET(RECEIVE_TOKEN_INFORMATION_HEADER, SenseData) + 16195 tokenInformationResults->SenseDataFieldLength); 16196 16197 REVERSE_BYTES(&tokenDescriptorLength, &tokenInformationResponsePadding->TokenDescriptorsLength); 16198 NT_ASSERT(tokenDescriptorLength == 0); 16199 16200 NT_ASSERT(tokenInformationResults->TransferCountUnits == TRANSFER_COUNT_UNITS_NUMBER_BLOCKS); 16201 REVERSE_BYTES_QUAD(&transferBlockCount, &tokenInformationResults->TransferCount); 16202 16203 REVERSE_BYTES_SHORT(&segmentsProcessed, &tokenInformationResults->SegmentsProcessed); 16204 NT_ASSERT(segmentsProcessed == 0); 16205 16206 if (operationCompleted) { 16207 16208 if (transferBlockCount > totalSectorsToProcess) { 16209 16210 // 16211 // Buggy or hostile target. Don't let it claim more was procesed 16212 // than was requested. Since this is likely a bug and it's unknown 16213 // how much was actually transferred, assume no data was 16214 // transferred. 16215 // 16216 16217 NT_ASSERT(transferBlockCount <= totalSectorsToProcess); 16218 transferBlockCount = 0; 16219 } 16220 16221 if (operationStatus != OPERATION_COMPLETED_WITH_SUCCESS && 16222 operationStatus != OPERATION_COMPLETED_WITH_RESIDUAL_DATA) { 16223 16224 // 16225 // Assert on buggy response from target, but in any case, make sure not 16226 // to claim that any data was written. 16227 // 16228 16229 NT_ASSERT(transferBlockCount == 0); 16230 transferBlockCount = 0; 16231 } 16232 16233 // 16234 // Since the TokenOperation was sent down synchronously but failed, the operation is complete as soon as the 16235 // ReceiveTokenInformation command returns. 16236 // 16237 16238 NT_ASSERT((*totalSectorsProcessed) == 0); 16239 *totalSectorsProcessed = transferBlockCount; 16240 ClasspAdvanceOffloadWritePosition(OffloadWriteContext, transferBlockCount); 16241 16242 if (transferBlockCount < totalSectorsToProcess) { 16243 16244 NT_ASSERT(operationStatus == OPERATION_COMPLETED_WITH_RESIDUAL_DATA || 16245 operationStatus == OPERATION_COMPLETED_WITH_ERROR || 16246 operationStatus == OPERATION_TERMINATED); 16247 16248 } else { 16249 16250 NT_ASSERT(operationStatus == OPERATION_COMPLETED_WITH_SUCCESS); 16251 } 16252 16253 TracePrint((transferBlockCount == totalSectorsToProcess ? TRACE_LEVEL_INFORMATION : TRACE_LEVEL_WARNING, 16254 TRACE_FLAG_IOCTL, 16255 "ClasspReceiveWriteUsingTokenInformationTransferPacketDone (%p): %wsSuccessfully wrote (for list Id %x) for data size %I64u bytes\n", 16256 fdo, 16257 transferBlockCount == totalSectorsToProcess ? L"" : L"Target truncated write. ", 16258 listIdentifier, 16259 (*totalSectorsProcessed) * fdoExt->DiskGeometry.BytesPerSector)); 16260 16261 // 16262 // Operation that completes with success can have sense data (for target to pass on some extra info) 16263 // but we don't care about such sense info. 16264 // Operation that complete but not with success, may not have sense data associated, but may 16265 // have valid CompletionStatus. 16266 // 16267 // The "status" may be overriden by ClassInterpretSenseInfo(). Final 16268 // status is determined a bit later - this is just the default status 16269 // when ClassInterpretSenseInfo() doesn't get to run here. 16270 // 16271 status = STATUS_SUCCESS; 16272 if (operationStatus == OPERATION_COMPLETED_WITH_ERROR || 16273 operationStatus == OPERATION_COMPLETED_WITH_RESIDUAL_DATA || 16274 operationStatus == OPERATION_TERMINATED) { 16275 16276 SrbSetScsiStatus((PSTORAGE_REQUEST_BLOCK_HEADER)srb, completionStatus); 16277 16278 if (senseDataLength) { 16279 16280 ULONG retryInterval; 16281 16282 NT_ASSERT(senseDataLength <= sizeof(SENSE_DATA)); 16283 16284 srb->Function = SRB_FUNCTION_EXECUTE_SCSI; 16285 16286 srb->SrbStatus = SRB_STATUS_AUTOSENSE_VALID | SRB_STATUS_ERROR; 16287 SrbSetSenseInfoBuffer((PSTORAGE_REQUEST_BLOCK_HEADER)srb, senseData); 16288 SrbSetSenseInfoBufferLength((PSTORAGE_REQUEST_BLOCK_HEADER)srb, senseDataLength); 16289 16290 ClassInterpretSenseInfo(fdo, 16291 srb, 16292 IRP_MJ_SCSI, 16293 0, 16294 0, 16295 &status, 16296 &retryInterval); 16297 16298 TracePrint((TRACE_LEVEL_WARNING, 16299 TRACE_FLAG_IOCTL, 16300 "ClasspReceiveWriteUsingTokenInformationTransferPacketDone (%p): Reason for truncation/failure: %x - for list Id %x for data size %I64u bytes.\n", 16301 fdo, 16302 status, 16303 listIdentifier, 16304 transferBlockCount * fdoExt->DiskGeometry.BytesPerSector)); 16305 16306 // 16307 // If the token isn't valid any longer, we should let the upper layers know so that 16308 // they don't waste time retrying the write with the same token. 16309 // 16310 if (status == STATUS_INVALID_TOKEN) { 16311 16312 *tokenInvalidated = TRUE; 16313 } 16314 } else { 16315 16316 TracePrint((TRACE_LEVEL_WARNING, 16317 TRACE_FLAG_IOCTL, 16318 "ClasspReceiveWriteUsingTokenInformationTransferPacketDone (%p): No sense data available but reason for truncation/failure, possibly: %x - for list Id %x for data size %I64u bytes.\n", 16319 fdo, 16320 completionStatus, 16321 listIdentifier, 16322 transferBlockCount * fdoExt->DiskGeometry.BytesPerSector)); 16323 } 16324 } 16325 16326 // 16327 // Initialize status. Upper layer needs to know if command failed because it 16328 // timed out without doing any writing. ClasspCompleteOffloadWrite() will 16329 // force status to success if any data was written, so it's this function's 16330 // job to set the status appropriately based on the outcome of this 16331 // WRITE USING TOKEN command, and then ClasspCompleteOffloadWrite() 16332 // can override with success if previos WRITE USING TOKEN commands 16333 // issued for the same upper request were able to write some data. 16334 // 16335 if (transferBlockCount != 0) { 16336 status = STATUS_SUCCESS; 16337 } else { 16338 16339 if (NT_SUCCESS(status)) { 16340 // 16341 // Make sure status is a failing status, without throwing away an 16342 // already-failing status obtained from sense data. 16343 // 16344 status = STATUS_UNSUCCESSFUL; 16345 } 16346 } 16347 16348 NT_ASSERT(status != STATUS_PENDING); 16349 16350 if (!NT_SUCCESS(status)) { 16351 goto __ClasspReceiveWriteUsingTokenInformationTransferPacketDone_ErrorExit; 16352 } 16353 16354 ClasspReceiveWriteUsingTokenInformationDone(OffloadWriteContext, status); 16355 status = STATUS_PENDING; 16356 goto __ClasspReceiveWriteUsingTokenInformationTransferPacketDone_Exit; 16357 16358 } else { 16359 16360 status = STATUS_UNSUCCESSFUL; 16361 16362 goto __ClasspReceiveWriteUsingTokenInformationTransferPacketDone_ErrorExit; 16363 } 16364 16365 // 16366 // Error label only - not used in success case: 16367 // 16368 16369 __ClasspReceiveWriteUsingTokenInformationTransferPacketDone_ErrorExit: 16370 16371 NT_ASSERT(!NT_SUCCESS(status)); 16372 16373 ClasspCompleteOffloadWrite(OffloadWriteContext, status); 16374 16375 __ClasspReceiveWriteUsingTokenInformationTransferPacketDone_Exit: 16376 16377 // 16378 // Due to tracing a potentially freed pointer value "Irp", this trace could 16379 // be delayed beyond another offload op picking up the same pointer value 16380 // for its Irp. 16381 // 16382 16383 TracePrint((TRACE_LEVEL_VERBOSE, 16384 TRACE_FLAG_IOCTL, 16385 "ClasspReceiveWriteUsingTokenInformationTransferPacketDone (%p): Exiting function (Irp %p) with status %x.\n", 16386 fdo, 16387 irp, 16388 status)); 16389 16390 return; 16391 } 16392 16393 16394 NTSTATUS 16395 ClasspRefreshFunctionSupportInfo( 16396 _Inout_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, 16397 _In_ BOOLEAN ForceQuery 16398 ) 16399 /* 16400 Routine Description: 16401 16402 This function is to update various properties described in FDO extension's 16403 CLASS_FUNCTION_SUPPORT_INFO structure by requerying the device's VPD pages. 16404 Although this function is capable of updating any properties in the 16405 CLASS_FUNCTION_SUPPORT_INFO structure, it will initially support only 16406 a small number of proporties in the block limit data 16407 16408 Arguments: 16409 16410 FdoExtension : FDO extension 16411 16412 ForceQuery : TRUE if the caller wants to force a query of the device's 16413 VPD pages. Otherwise, the function may use cached data. 16414 16415 Return Value: 16416 16417 STATUS_SUCCESS or an error status 16418 16419 --*/ 16420 { 16421 NTSTATUS status; 16422 PSCSI_REQUEST_BLOCK srb = NULL; 16423 ULONG srbSize; 16424 CLASS_VPD_B0_DATA blockLimitsDataNew; 16425 PCLASS_VPD_B0_DATA blockLimitsDataOriginal; 16426 KLOCK_QUEUE_HANDLE lockHandle; 16427 ULONG generationCount; 16428 ULONG changeRequestCount; 16429 16430 // 16431 // ChangeRequestCount is incremented every time we get an unit attention with 16432 // SCSI_ADSENSE_OPERATING_CONDITIONS_CHANGED. GenerationCount will be set to 16433 // ChangeRequestCount after CLASS_FUNCTION_SUPPORT_INFO is refreshed with the latest 16434 // VPD data. i.e. if both values are the same, data in 16435 // CLASS_FUNCTION_SUPPORT_INFO is current 16436 // 16437 16438 generationCount = FdoExtension->FunctionSupportInfo->GenerationCount; 16439 changeRequestCount = FdoExtension->FunctionSupportInfo->ChangeRequestCount; 16440 if (!ForceQuery && generationCount == changeRequestCount) { 16441 return STATUS_SUCCESS; 16442 } 16443 16444 // 16445 // Allocate an SRB for querying the device for LBP-related info if either 16446 // the Logical Block Provisioning (0xB2) or Block Limits (0xB0) VPD page 16447 // exists. 16448 // 16449 if ((FdoExtension->AdapterDescriptor != NULL) && 16450 (FdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK)) { 16451 srbSize = CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE; 16452 } else { 16453 srbSize = sizeof(SCSI_REQUEST_BLOCK); 16454 } 16455 16456 srb = ExAllocatePoolWithTag(NonPagedPoolNx, srbSize, '1DcS'); 16457 if (srb == NULL) { 16458 return STATUS_INSUFFICIENT_RESOURCES; 16459 } 16460 16461 status = ClasspDeviceGetBlockLimitsVPDPage(FdoExtension, 16462 srb, 16463 srbSize, 16464 &blockLimitsDataNew); 16465 16466 if (NT_SUCCESS(status)) { 16467 16468 KeAcquireInStackQueuedSpinLock(&FdoExtension->FunctionSupportInfo->SyncLock, &lockHandle); 16469 16470 // 16471 // If the generationCount didn't change since we looked at it last time, it means 16472 // no one has tried to update the CLASS_FUNCTION_SUPPORT_INFO data; otherwise, someone 16473 // else has beat us to it. 16474 // 16475 if (generationCount == FdoExtension->FunctionSupportInfo->GenerationCount) { 16476 16477 blockLimitsDataOriginal = &FdoExtension->FunctionSupportInfo->BlockLimitsData; 16478 if (blockLimitsDataOriginal->CommandStatus == -1) { 16479 // 16480 // CommandStatus == -1 means this is the first time we have 16481 // gotten the block limits data. 16482 // 16483 *blockLimitsDataOriginal = blockLimitsDataNew; 16484 } else { 16485 // 16486 // We only expect the Optimal Unmap Granularity (and alignment) 16487 // to change, so those are the only parameters we update. 16488 // 16489 blockLimitsDataOriginal->UGAVALID = blockLimitsDataNew.UGAVALID; 16490 blockLimitsDataOriginal->UnmapGranularityAlignment = blockLimitsDataNew.UnmapGranularityAlignment; 16491 blockLimitsDataOriginal->OptimalUnmapGranularity = blockLimitsDataNew.OptimalUnmapGranularity; 16492 } 16493 FdoExtension->FunctionSupportInfo->GenerationCount = changeRequestCount; 16494 } 16495 16496 KeReleaseInStackQueuedSpinLock(&lockHandle); 16497 } 16498 16499 FREE_POOL(srb); 16500 return status; 16501 } 16502 16503 NTSTATUS 16504 ClasspBlockLimitsDataSnapshot( 16505 _In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, 16506 _In_ BOOLEAN ForceQuery, 16507 _Out_ PCLASS_VPD_B0_DATA BlockLimitsData, 16508 _Out_ PULONG GenerationCount 16509 ) 16510 /* 16511 Routine Description: 16512 16513 This function is to get a copy of the latest block limits data. 16514 16515 When this function is called multiple times, GenerationCount can change (value always goes up) 16516 while BlockLimitsData stays the same. In this case, the caller should assume BlockLimitsData 16517 has changed to different values and eventually changed back to the same state when the first 16518 call to this function was made. 16519 16520 Arguments: 16521 16522 FdoExtension : FDO extension 16523 16524 ForceQuery : TRUE if the caller wants to force a query of the device's 16525 VPD pages. Otherwise, the function may use cached data. 16526 16527 BlockLimitsData : pointer to memory that will receive the block limits data 16528 16529 GenerationCount : generation count of the block limit data. 16530 16531 DataIsOutdated: set to TRUE if the BlockLimitsData is old but this function fails to 16532 query the latest data from the device due to insufficient resources 16533 16534 Return Value: 16535 16536 STATUS_SUCCESS or an error status 16537 16538 --*/ 16539 { 16540 NTSTATUS status; 16541 KLOCK_QUEUE_HANDLE lockHandle; 16542 16543 status = ClasspRefreshFunctionSupportInfo(FdoExtension, ForceQuery); 16544 16545 KeAcquireInStackQueuedSpinLock(&FdoExtension->FunctionSupportInfo->SyncLock, &lockHandle); 16546 *BlockLimitsData = FdoExtension->FunctionSupportInfo->BlockLimitsData; 16547 *GenerationCount = FdoExtension->FunctionSupportInfo->GenerationCount; 16548 KeReleaseInStackQueuedSpinLock(&lockHandle); 16549 16550 return status; 16551 } 16552 16553