1 /*++ 2 3 Copyright (C) Microsoft Corporation, 1991 - 2010 4 5 Module Name: 6 7 power.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 #ifndef __REACTOS__ 25 #include "stddef.h" 26 #include "ntddk.h" 27 #include "scsi.h" 28 #endif 29 #include "classp.h" 30 31 // #include <stdarg.h> __REACTOS__ 32 33 #ifdef DEBUG_USE_WPP 34 #include "power.tmh" 35 #endif 36 37 #define CLASS_TAG_POWER 'WLcS' 38 39 // constants for power transition process. (UNIT: seconds) 40 #define DEFAULT_POWER_IRP_TIMEOUT_VALUE 10*60 41 #define TIME_LEFT_FOR_LOWER_DRIVERS 30 42 #define TIME_LEFT_FOR_UPPER_DRIVERS 5 43 #define DEFAULT_IO_TIMEOUT_VALUE 10 44 #define MINIMUM_STOP_UNIT_TIMEOUT_VALUE 2 45 46 // 47 // MINIMAL value is one that has some slack and is the value to use 48 // if there is a shortened POWER IRP timeout value. If time remaining 49 // is less than MINIMAL, we will use the MINIMUM value. Both values 50 // are in the same unit as above (seconds). 51 // 52 #define MINIMAL_START_UNIT_TIMEOUT_VALUE 60 53 #define MINIMUM_START_UNIT_TIMEOUT_VALUE 30 54 55 // PoQueryWatchdogTime was introduced in Windows 7. 56 // Returns TRUE if a watchdog-enabled power IRP is found, otherwise FALSE. 57 #if (NTDDI_VERSION < NTDDI_WIN7) 58 #define PoQueryWatchdogTime(A, B) FALSE 59 #endif 60 61 IO_COMPLETION_ROUTINE ClasspPowerDownCompletion; 62 63 IO_COMPLETION_ROUTINE ClasspPowerUpCompletion; 64 65 IO_COMPLETION_ROUTINE ClasspStartNextPowerIrpCompletion; 66 IO_COMPLETION_ROUTINE ClasspDeviceLockFailurePowerIrpCompletion; 67 68 NTSTATUS 69 ClasspPowerHandler( 70 IN PDEVICE_OBJECT DeviceObject, 71 IN PIRP Irp, 72 IN CLASS_POWER_OPTIONS Options 73 ); 74 75 VOID 76 RetryPowerRequest( 77 PDEVICE_OBJECT DeviceObject, 78 PIRP Irp, 79 PCLASS_POWER_CONTEXT Context 80 ); 81 82 #ifdef ALLOC_PRAGMA 83 #pragma alloc_text(PAGE, ClasspPowerSettingCallback) 84 #endif 85 86 /*++//////////////////////////////////////////////////////////////////////////// 87 88 ClassDispatchPower() 89 90 Routine Description: 91 92 This routine acquires the removelock for the irp and then calls the 93 appropriate power callback. 94 95 Arguments: 96 97 DeviceObject - 98 Irp - 99 100 Return Value: 101 102 --*/ 103 NTSTATUS 104 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 105 ClassDispatchPower( 106 IN PDEVICE_OBJECT DeviceObject, 107 IN PIRP Irp 108 ) 109 { 110 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 111 ULONG isRemoved; 112 113 // 114 // NOTE: This code may be called at PASSIVE or DISPATCH, depending 115 // upon the device object it is being called for. 116 // don't do anything that would break under either circumstance. 117 // 118 119 // 120 // If device is added but not yet started, we need to send the Power 121 // request down the stack. If device is started and then stopped, 122 // we have enough state to process the power request. 123 // 124 125 if (!commonExtension->IsInitialized) { 126 127 PoStartNextPowerIrp(Irp); 128 IoSkipCurrentIrpStackLocation(Irp); 129 return PoCallDriver(commonExtension->LowerDeviceObject, Irp); 130 } 131 132 isRemoved = ClassAcquireRemoveLock(DeviceObject, Irp); 133 134 if (isRemoved) { 135 ClassReleaseRemoveLock(DeviceObject, Irp); 136 Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST; 137 PoStartNextPowerIrp(Irp); 138 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 139 return STATUS_DEVICE_DOES_NOT_EXIST; 140 } 141 142 return commonExtension->DevInfo->ClassPowerDevice(DeviceObject, Irp); 143 } // end ClassDispatchPower() 144 145 /*++//////////////////////////////////////////////////////////////////////////// 146 147 ClasspPowerUpCompletion() 148 149 Routine Description: 150 151 This routine is used for intermediate completion of a power up request. 152 PowerUp requires four requests to be sent to the lower driver in sequence. 153 154 * The queue is "power locked" to ensure that the class driver power-up 155 work can be done before request processing resumes. 156 157 * The power irp is sent down the stack for any filter drivers and the 158 port driver to return power and resume command processing for the 159 device. Since the queue is locked, no queued irps will be sent 160 immediately. 161 162 * A start unit command is issued to the device with appropriate flags 163 to override the "power locked" queue. 164 165 * The queue is "power unlocked" to start processing requests again. 166 167 This routine uses the function in the srb which just completed to determine 168 which state it is in. 169 170 Arguments: 171 172 DeviceObject - the device object being powered up 173 174 Irp - Context->Irp: original power irp; fdoExtension->PrivateFdoData->PowerProcessIrp: power process irp 175 176 Context - Class power context used to perform port/class operations. 177 178 Return Value: 179 180 STATUS_MORE_PROCESSING_REQUIRED or 181 STATUS_SUCCESS 182 183 --*/ 184 NTSTATUS 185 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 186 ClasspPowerUpCompletion( 187 IN PDEVICE_OBJECT DeviceObject, 188 IN PIRP Irp, 189 IN PVOID Context 190 ) 191 { 192 PCLASS_POWER_CONTEXT PowerContext = (PCLASS_POWER_CONTEXT)Context; 193 PCOMMON_DEVICE_EXTENSION commonExtension; 194 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension; 195 PIRP OriginalIrp; 196 PIO_STACK_LOCATION currentStack; 197 PIO_STACK_LOCATION nextStack; 198 199 NTSTATUS status = STATUS_MORE_PROCESSING_REQUIRED; 200 PSTORAGE_REQUEST_BLOCK_HEADER srbHeader; 201 ULONG srbFlags; 202 BOOLEAN FailurePredictionEnabled = FALSE; 203 204 UNREFERENCED_PARAMETER(DeviceObject); 205 206 if (PowerContext == NULL) { 207 NT_ASSERT(PowerContext != NULL); 208 return STATUS_INVALID_PARAMETER; 209 } 210 211 commonExtension = PowerContext->DeviceObject->DeviceExtension; 212 fdoExtension = PowerContext->DeviceObject->DeviceExtension; 213 OriginalIrp = PowerContext->Irp; 214 215 // currentStack - from original power irp 216 // nextStack - from power process irp 217 currentStack = IoGetCurrentIrpStackLocation(OriginalIrp); 218 nextStack = IoGetNextIrpStackLocation(fdoExtension->PrivateFdoData->PowerProcessIrp); 219 220 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "ClasspPowerUpCompletion: Device Object %p, Irp %p, " 221 "Context %p\n", 222 PowerContext->DeviceObject, Irp, Context)); 223 224 if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { 225 srbHeader = (PSTORAGE_REQUEST_BLOCK_HEADER)&(fdoExtension->PrivateFdoData->PowerSrb.SrbEx); 226 227 // 228 // Check if reverted to using legacy SRB. 229 // 230 if (PowerContext->Srb.Length == sizeof(SCSI_REQUEST_BLOCK)) { 231 srbHeader = (PSTORAGE_REQUEST_BLOCK_HEADER)&(PowerContext->Srb); 232 } 233 } else { 234 srbHeader = (PSTORAGE_REQUEST_BLOCK_HEADER)&(PowerContext->Srb); 235 } 236 237 srbFlags = SrbGetSrbFlags(srbHeader); 238 NT_ASSERT(!TEST_FLAG(srbFlags, SRB_FLAGS_FREE_SENSE_BUFFER)); 239 NT_ASSERT(!TEST_FLAG(srbFlags, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE)); 240 NT_ASSERT(PowerContext->Options.PowerDown == FALSE); 241 NT_ASSERT(PowerContext->Options.HandleSpinUp); 242 243 if ((Irp == OriginalIrp) && (Irp->PendingReturned)) { 244 // only for original power irp 245 IoMarkIrpPending(Irp); 246 } 247 248 PowerContext->PowerChangeState.PowerUp++; 249 250 switch (PowerContext->PowerChangeState.PowerUp) { 251 252 case PowerUpDeviceLocked: { 253 254 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tPreviously sent power lock\n", Irp)); 255 256 // 257 // Lock Queue operation has been sent. 258 // Now, send the original power irp down to get lower driver and device ready. 259 // 260 261 IoCopyCurrentIrpStackLocationToNext(OriginalIrp); 262 263 if ((PowerContext->Options.LockQueue == TRUE) && 264 (!NT_SUCCESS(Irp->IoStatus.Status))) { 265 266 // 267 // Lock was not successful: 268 // Issue the original power request to the lower driver and next power irp will be started in completion routine. 269 // 270 271 272 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tIrp status was %lx\n", 273 Irp, Irp->IoStatus.Status)); 274 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tSrb status was %lx\n", 275 Irp, srbHeader->SrbStatus)); 276 277 IoSetCompletionRoutine(OriginalIrp, 278 ClasspDeviceLockFailurePowerIrpCompletion, 279 PowerContext, 280 TRUE, 281 TRUE, 282 TRUE); 283 284 PoCallDriver(commonExtension->LowerDeviceObject, OriginalIrp); 285 286 return STATUS_MORE_PROCESSING_REQUIRED; 287 288 } else { 289 PowerContext->QueueLocked = (UCHAR)PowerContext->Options.LockQueue; 290 } 291 292 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; 293 294 PowerContext->PowerChangeState.PowerUp = PowerUpDeviceLocked; 295 296 IoSetCompletionRoutine(OriginalIrp, 297 ClasspPowerUpCompletion, 298 PowerContext, 299 TRUE, 300 TRUE, 301 TRUE); 302 303 status = PoCallDriver(commonExtension->LowerDeviceObject, OriginalIrp); 304 305 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tIoCallDriver returned %lx\n", OriginalIrp, status)); 306 break; 307 } 308 309 case PowerUpDeviceOn: { 310 311 // 312 // Original power irp has been completed by lower driver. 313 // 314 315 if (NT_SUCCESS(Irp->IoStatus.Status)) { 316 // 317 // If power irp succeeded, START UNIT command will be sent. 318 // 319 PCDB cdb; 320 ULONG secondsRemaining = 0; 321 ULONG timeoutValue = 0; 322 ULONG startUnitTimeout; 323 324 if (PoQueryWatchdogTime(fdoExtension->LowerPdo, &secondsRemaining)) { 325 326 // do not exceed DEFAULT_POWER_IRP_TIMEOUT_VALUE. 327 secondsRemaining = min(secondsRemaining, DEFAULT_POWER_IRP_TIMEOUT_VALUE); 328 329 // 330 // It's possible for POWER IRP timeout value to be smaller than default of 331 // START_UNIT_TIMEOUT. If this is the case, use a smaller timeout value. 332 // 333 if (secondsRemaining >= START_UNIT_TIMEOUT) { 334 startUnitTimeout = START_UNIT_TIMEOUT; 335 } else { 336 startUnitTimeout = MINIMAL_START_UNIT_TIMEOUT_VALUE; 337 } 338 339 // plan to leave (TIME_LEFT_FOR_UPPER_DRIVERS) seconds to upper level drivers 340 // for processing original power irp. 341 if (secondsRemaining >= (TIME_LEFT_FOR_UPPER_DRIVERS + startUnitTimeout)) { 342 fdoExtension->PrivateFdoData->MaxPowerOperationRetryCount = 343 (secondsRemaining - TIME_LEFT_FOR_UPPER_DRIVERS) / startUnitTimeout; 344 345 // * No 'short' timeouts 346 // 347 // 348 // timeoutValue = (secondsRemaining - TIME_LEFT_FOR_UPPER_DRIVERS) % 349 // startUnitTimeout; 350 // 351 352 if (--fdoExtension->PrivateFdoData->MaxPowerOperationRetryCount) 353 { 354 timeoutValue = startUnitTimeout; 355 } else { 356 timeoutValue = secondsRemaining - TIME_LEFT_FOR_UPPER_DRIVERS; 357 } 358 } else { 359 // issue the command with minimum timeout value and do not retry on it. 360 // case of (secondsRemaining < DEFAULT_IO_TIMEOUT_VALUE) is ignored as it should not happen. 361 NT_ASSERT(secondsRemaining >= DEFAULT_IO_TIMEOUT_VALUE); 362 363 fdoExtension->PrivateFdoData->MaxPowerOperationRetryCount = 0; 364 timeoutValue = MINIMUM_START_UNIT_TIMEOUT_VALUE; // use the minimum value for this corner case. 365 } 366 367 } else { 368 // don't know how long left, do not exceed DEFAULT_POWER_IRP_TIMEOUT_VALUE. 369 fdoExtension->PrivateFdoData->MaxPowerOperationRetryCount = 370 DEFAULT_POWER_IRP_TIMEOUT_VALUE / START_UNIT_TIMEOUT - 1; 371 timeoutValue = START_UNIT_TIMEOUT; 372 } 373 374 375 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tSending start unit to device\n", Irp)); 376 377 // 378 // Issue the start unit command to the device. 379 // 380 381 PowerContext->RetryCount = fdoExtension->PrivateFdoData->MaxPowerOperationRetryCount; 382 383 if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { 384 status = InitializeStorageRequestBlock((PSTORAGE_REQUEST_BLOCK)srbHeader, 385 STORAGE_ADDRESS_TYPE_BTL8, 386 CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE, 387 1, 388 SrbExDataTypeScsiCdb16); 389 if (NT_SUCCESS(status)) { 390 ((PSTORAGE_REQUEST_BLOCK)srbHeader)->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI; 391 392 // 393 // Set length field in Power Context SRB so we know legacy SRB is not being used. 394 // 395 PowerContext->Srb.Length = 0; 396 397 } else { 398 // 399 // Should not happen. Revert to legacy SRB. 400 // 401 NT_ASSERT(FALSE); 402 srbHeader = (PSTORAGE_REQUEST_BLOCK_HEADER)&(PowerContext->Srb); 403 RtlZeroMemory(srbHeader, sizeof(SCSI_REQUEST_BLOCK)); 404 srbHeader->Length = sizeof(SCSI_REQUEST_BLOCK); 405 srbHeader->Function = SRB_FUNCTION_EXECUTE_SCSI; 406 } 407 408 } else { 409 RtlZeroMemory(srbHeader, sizeof(SCSI_REQUEST_BLOCK)); 410 srbHeader->Length = sizeof(SCSI_REQUEST_BLOCK); 411 srbHeader->Function = SRB_FUNCTION_EXECUTE_SCSI; 412 } 413 414 SrbSetOriginalRequest(srbHeader, fdoExtension->PrivateFdoData->PowerProcessIrp); 415 SrbSetSenseInfoBuffer(srbHeader, commonExtension->PartitionZeroExtension->SenseData); 416 SrbSetSenseInfoBufferLength(srbHeader, GET_FDO_EXTENSON_SENSE_DATA_LENGTH(commonExtension->PartitionZeroExtension)); 417 418 SrbSetTimeOutValue(srbHeader, timeoutValue); 419 SrbAssignSrbFlags(srbHeader, 420 (SRB_FLAGS_NO_DATA_TRANSFER | 421 SRB_FLAGS_DISABLE_AUTOSENSE | 422 SRB_FLAGS_DISABLE_SYNCH_TRANSFER | 423 SRB_FLAGS_NO_QUEUE_FREEZE)); 424 425 if (PowerContext->Options.LockQueue) { 426 SrbSetSrbFlags(srbHeader, SRB_FLAGS_BYPASS_LOCKED_QUEUE); 427 } 428 429 SrbSetCdbLength(srbHeader, 6); 430 431 cdb = SrbGetCdb(srbHeader); 432 RtlZeroMemory(cdb, sizeof(CDB)); 433 434 cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT; 435 cdb->START_STOP.Start = 1; 436 437 PowerContext->PowerChangeState.PowerUp = PowerUpDeviceOn; 438 439 IoSetCompletionRoutine(fdoExtension->PrivateFdoData->PowerProcessIrp, 440 ClasspPowerUpCompletion, 441 PowerContext, 442 TRUE, 443 TRUE, 444 TRUE); 445 446 nextStack->Parameters.Scsi.Srb = (PSCSI_REQUEST_BLOCK)srbHeader; 447 nextStack->MajorFunction = IRP_MJ_SCSI; 448 449 status = IoCallDriver(commonExtension->LowerDeviceObject, fdoExtension->PrivateFdoData->PowerProcessIrp); 450 451 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tIoCallDriver returned %lx\n", fdoExtension->PrivateFdoData->PowerProcessIrp, status)); 452 453 } else { 454 455 // 456 // power irp is failed by lower driver. we're done. 457 // 458 459 PowerContext->FinalStatus = Irp->IoStatus.Status; 460 goto ClasspPowerUpCompletionFailure; 461 } 462 463 break; 464 } 465 466 case PowerUpDeviceStarted: { // 3 467 468 // 469 // First deal with an error if one occurred. 470 // 471 472 if (SRB_STATUS(srbHeader->SrbStatus) != SRB_STATUS_SUCCESS) { 473 474 BOOLEAN retry; 475 LONGLONG delta100nsUnits = 0; 476 ULONG secondsRemaining = 0; 477 ULONG startUnitTimeout = START_UNIT_TIMEOUT; 478 479 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_POWER, "%p\tError occured when issuing START_UNIT " 480 "command to device. Srb %p, Status %x\n", 481 Irp, 482 srbHeader, 483 srbHeader->SrbStatus)); 484 485 NT_ASSERT(!(TEST_FLAG(srbHeader->SrbStatus, SRB_STATUS_QUEUE_FROZEN))); 486 NT_ASSERT((srbHeader->Function == SRB_FUNCTION_EXECUTE_SCSI) || 487 (((PSTORAGE_REQUEST_BLOCK)srbHeader)->SrbFunction == SRB_FUNCTION_EXECUTE_SCSI)); 488 489 PowerContext->RetryInterval = 0; 490 retry = InterpretSenseInfoWithoutHistory( 491 fdoExtension->DeviceObject, 492 Irp, 493 (PSCSI_REQUEST_BLOCK)srbHeader, 494 IRP_MJ_SCSI, 495 IRP_MJ_POWER, 496 fdoExtension->PrivateFdoData->MaxPowerOperationRetryCount - PowerContext->RetryCount, 497 &status, 498 &delta100nsUnits); 499 500 // NOTE: Power context is a public structure, and thus cannot be 501 // updated to use 100ns units. Therefore, must store the 502 // one-second equivalent. Round up to ensure minimum delay 503 // requirements have been met. 504 delta100nsUnits += (10*1000*1000) - 1; 505 delta100nsUnits /= (10*1000*1000); 506 // guaranteed not to have high bits set per SAL annotations 507 PowerContext->RetryInterval = (ULONG)(delta100nsUnits); 508 509 510 if ((retry == TRUE) && (PowerContext->RetryCount-- != 0)) { 511 512 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tRetrying failed request\n", Irp)); 513 514 // 515 // Decrement the state so we come back through here the 516 // next time. 517 // 518 519 PowerContext->PowerChangeState.PowerUp--; 520 521 // 522 // Adjust start unit timeout based on remaining time if needed. 523 // 524 if (PoQueryWatchdogTime(fdoExtension->LowerPdo, &secondsRemaining)) { 525 526 if (secondsRemaining >= TIME_LEFT_FOR_UPPER_DRIVERS) { 527 secondsRemaining -= TIME_LEFT_FOR_UPPER_DRIVERS; 528 } 529 530 if (secondsRemaining < MINIMAL_START_UNIT_TIMEOUT_VALUE) { 531 startUnitTimeout = MINIMUM_START_UNIT_TIMEOUT_VALUE; 532 } else if (secondsRemaining < START_UNIT_TIMEOUT) { 533 startUnitTimeout = MINIMAL_START_UNIT_TIMEOUT_VALUE; 534 } 535 } 536 537 SrbSetTimeOutValue(srbHeader, startUnitTimeout); 538 539 RetryPowerRequest(commonExtension->DeviceObject, 540 Irp, 541 PowerContext); 542 543 break; 544 545 } 546 547 // reset retry count for UNLOCK command. 548 fdoExtension->PrivateFdoData->MaxPowerOperationRetryCount = MAXIMUM_RETRIES; 549 PowerContext->RetryCount = MAXIMUM_RETRIES; 550 } 551 552 ClasspPowerUpCompletionFailure: 553 554 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tPreviously spun device up\n", Irp)); 555 556 if (PowerContext->QueueLocked) { 557 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tUnlocking queue\n", Irp)); 558 559 if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { 560 // 561 // Will reuse SRB for a non-SCSI SRB. 562 // 563 status = InitializeStorageRequestBlock((PSTORAGE_REQUEST_BLOCK)srbHeader, 564 STORAGE_ADDRESS_TYPE_BTL8, 565 CLASS_SRBEX_NO_SRBEX_DATA_BUFFER_SIZE, 566 0); 567 if (NT_SUCCESS(status)) { 568 ((PSTORAGE_REQUEST_BLOCK)srbHeader)->SrbFunction = SRB_FUNCTION_UNLOCK_QUEUE; 569 570 // 571 // Set length field in Power Context SRB so we know legacy SRB is not being used. 572 // 573 PowerContext->Srb.Length = 0; 574 575 } else { 576 // 577 // Should not occur. Revert to legacy SRB. 578 NT_ASSERT(FALSE); 579 srbHeader = (PSTORAGE_REQUEST_BLOCK_HEADER)&(PowerContext->Srb); 580 RtlZeroMemory(srbHeader, sizeof(SCSI_REQUEST_BLOCK)); 581 srbHeader->Length = sizeof(SCSI_REQUEST_BLOCK); 582 srbHeader->Function = SRB_FUNCTION_UNLOCK_QUEUE; 583 } 584 } else { 585 RtlZeroMemory(srbHeader, sizeof(SCSI_REQUEST_BLOCK)); 586 srbHeader->Length = sizeof(SCSI_REQUEST_BLOCK); 587 srbHeader->Function = SRB_FUNCTION_UNLOCK_QUEUE; 588 } 589 SrbAssignSrbFlags(srbHeader, SRB_FLAGS_BYPASS_LOCKED_QUEUE); 590 SrbSetOriginalRequest(srbHeader, fdoExtension->PrivateFdoData->PowerProcessIrp); 591 592 nextStack->Parameters.Scsi.Srb = (PSCSI_REQUEST_BLOCK)srbHeader; 593 nextStack->MajorFunction = IRP_MJ_SCSI; 594 595 PowerContext->PowerChangeState.PowerUp = PowerUpDeviceStarted; 596 597 IoSetCompletionRoutine(fdoExtension->PrivateFdoData->PowerProcessIrp, 598 ClasspPowerUpCompletion, 599 PowerContext, 600 TRUE, 601 TRUE, 602 TRUE); 603 604 status = IoCallDriver(commonExtension->LowerDeviceObject, fdoExtension->PrivateFdoData->PowerProcessIrp); 605 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tIoCallDriver returned %lx\n", 606 fdoExtension->PrivateFdoData->PowerProcessIrp, status)); 607 break; 608 } 609 610 // Fall-through to next case... 611 612 } 613 614 case PowerUpDeviceUnlocked: { 615 616 // 617 // This is the end of the dance. 618 // We're ignoring possible intermediate error conditions .... 619 // 620 621 if (PowerContext->QueueLocked) { 622 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tPreviously unlocked queue\n", OriginalIrp)); 623 624 // 625 // If the lower device is being removed, the IRP's status may be STATUS_DELETE_PENDING or 626 // STATUS_DEVICE_DOES_NOT_EXIST. 627 // 628 if((NT_SUCCESS(Irp->IoStatus.Status) == FALSE) && 629 (Irp->IoStatus.Status != STATUS_DELETE_PENDING) && 630 (Irp->IoStatus.Status != STATUS_DEVICE_DOES_NOT_EXIST)) { 631 632 633 NT_ASSERT(FALSE); 634 } 635 636 } else { 637 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tFall-through (queue not locked)\n", OriginalIrp)); 638 } 639 640 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tFreeing srb and completing\n", OriginalIrp)); 641 642 status = PowerContext->FinalStatus; 643 OriginalIrp->IoStatus.Status = status; 644 645 // 646 // Set the new power state 647 // 648 649 if (NT_SUCCESS(status)) { 650 fdoExtension->DevicePowerState = currentStack->Parameters.Power.State.DeviceState; 651 } 652 653 // 654 // Check whether failure detection is enabled 655 // 656 657 if ((fdoExtension->FailurePredictionInfo != NULL) && 658 (fdoExtension->FailurePredictionInfo->Method != FailurePredictionNone)) { 659 FailurePredictionEnabled = TRUE; 660 } 661 662 // 663 // Enable tick timer at end of D0 processing if it was previously enabled. 664 // 665 666 if ((commonExtension->DriverExtension->InitData.ClassTick != NULL) || 667 ((fdoExtension->MediaChangeDetectionInfo != NULL) && 668 (fdoExtension->FunctionSupportInfo != NULL) && 669 (fdoExtension->FunctionSupportInfo->AsynchronousNotificationSupported == FALSE)) || 670 (FailurePredictionEnabled)) { 671 672 673 // 674 // If failure prediction is turned on and we've been powered 675 // off longer than the failure prediction query period then 676 // force the query on the next timer tick. 677 // 678 679 if ((FailurePredictionEnabled) && (ClasspFailurePredictionPeriodMissed(fdoExtension))) { 680 fdoExtension->FailurePredictionInfo->CountDown = 1; 681 } 682 683 // 684 // Finally, enable the timer. 685 // 686 687 ClasspEnableTimer(fdoExtension); 688 } 689 690 // 691 // Indicate to Po that we've been successfully powered up so 692 // it can do it's notification stuff. 693 // 694 695 PoSetPowerState(PowerContext->DeviceObject, 696 currentStack->Parameters.Power.Type, 697 currentStack->Parameters.Power.State); 698 699 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tStarting next power irp\n", OriginalIrp)); 700 701 ClassReleaseRemoveLock(PowerContext->DeviceObject, OriginalIrp); 702 703 PowerContext->InUse = FALSE; 704 705 PoStartNextPowerIrp(OriginalIrp); 706 707 // prevent from completing the irp allocated by ourselves 708 if ((fdoExtension->PrivateFdoData) && (Irp == fdoExtension->PrivateFdoData->PowerProcessIrp)) { 709 // complete original irp if we are processing powerprocess irp, 710 // otherwise, by returning status other than STATUS_MORE_PROCESSING_REQUIRED, IO manager will complete it. 711 ClassCompleteRequest(commonExtension->DeviceObject, OriginalIrp, IO_NO_INCREMENT); 712 status = STATUS_MORE_PROCESSING_REQUIRED; 713 } 714 715 return status; 716 } 717 } 718 719 return STATUS_MORE_PROCESSING_REQUIRED; 720 } // end ClasspPowerUpCompletion() 721 722 /*++//////////////////////////////////////////////////////////////////////////// 723 724 ClasspPowerDownCompletion() 725 726 Routine Description: 727 728 This routine is used for intermediate completion of a power down request. 729 PowerDown performs the following sequence to power down the device. 730 731 1. The queue(s) in the lower stack is/are "power locked" to ensure new 732 requests are held until the power-down process is complete. 733 734 2. A request to the lower layers to wait for all outstanding IO to 735 complete ("quiescence") is sent. This ensures we don't power down 736 the device while it's in the middle of handling IO. 737 738 3. A request to flush the device's cache is sent. The device may lose 739 power when we forward the D-IRP so any data in volatile storage must 740 be committed to non-volatile storage first. 741 742 4. A "stop unit" request is sent to the device to notify it that it 743 is about to be powered down. 744 745 5. The D-IRP is forwarded down the stack. If D3Cold is supported and 746 enabled via ACPI, the ACPI filter driver may power off the device. 747 748 6. Once the D-IRP is completed by the lower stack, we will "power 749 unlock" the queue(s). (It is the lower stack's responsibility to 750 continue to queue any IO that requires hardware access until the 751 device is powered up again.) 752 753 Arguments: 754 755 DeviceObject - the device object being powered down 756 757 Irp - the IO_REQUEST_PACKET containing the power request 758 759 Context - the class power context used to perform port/class operations. 760 761 Return Value: 762 763 STATUS_MORE_PROCESSING_REQUIRED or 764 STATUS_SUCCESS 765 766 --*/ 767 NTSTATUS 768 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 769 ClasspPowerDownCompletion( 770 IN PDEVICE_OBJECT DeviceObject, 771 IN PIRP Irp, 772 IN PVOID Context 773 ) 774 { 775 PCLASS_POWER_CONTEXT PowerContext = (PCLASS_POWER_CONTEXT)Context; 776 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = PowerContext->DeviceObject->DeviceExtension; 777 PCOMMON_DEVICE_EXTENSION commonExtension = PowerContext->DeviceObject->DeviceExtension; 778 PIRP OriginalIrp = PowerContext->Irp; 779 780 // currentStack is for original power irp 781 // nextStack is for power process irp 782 PIO_STACK_LOCATION currentStack = IoGetCurrentIrpStackLocation(OriginalIrp); 783 PIO_STACK_LOCATION nextStack = IoGetNextIrpStackLocation(fdoExtension->PrivateFdoData->PowerProcessIrp); 784 785 NTSTATUS status = STATUS_MORE_PROCESSING_REQUIRED; 786 PSTORAGE_REQUEST_BLOCK_HEADER srbHeader; 787 ULONG srbFlags; 788 789 UNREFERENCED_PARAMETER(DeviceObject); 790 791 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "ClasspPowerDownCompletion: Device Object %p, " 792 "Irp %p, Context %p\n", 793 PowerContext->DeviceObject, Irp, Context)); 794 795 if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { 796 srbHeader = (PSTORAGE_REQUEST_BLOCK_HEADER)&(fdoExtension->PrivateFdoData->PowerSrb.SrbEx); 797 798 // 799 // Check if reverted to using legacy SRB. 800 // 801 if (PowerContext->Srb.Length == sizeof(SCSI_REQUEST_BLOCK)) { 802 srbHeader = (PSTORAGE_REQUEST_BLOCK_HEADER)&(PowerContext->Srb); 803 } 804 } else { 805 srbHeader = (PSTORAGE_REQUEST_BLOCK_HEADER)&(PowerContext->Srb); 806 } 807 808 srbFlags = SrbGetSrbFlags(srbHeader); 809 NT_ASSERT(!TEST_FLAG(srbFlags, SRB_FLAGS_FREE_SENSE_BUFFER)); 810 NT_ASSERT(!TEST_FLAG(srbFlags, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE)); 811 NT_ASSERT(PowerContext->Options.PowerDown == TRUE); 812 NT_ASSERT(PowerContext->Options.HandleSpinDown); 813 814 if ((Irp == OriginalIrp) && (Irp->PendingReturned)) { 815 // only for original power irp 816 IoMarkIrpPending(Irp); 817 } 818 819 PowerContext->PowerChangeState.PowerDown3++; 820 821 switch(PowerContext->PowerChangeState.PowerDown3) { 822 823 case PowerDownDeviceLocked3: { 824 825 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tPreviously sent power lock\n", Irp)); 826 827 if ((PowerContext->Options.LockQueue == TRUE) && 828 (!NT_SUCCESS(Irp->IoStatus.Status))) { 829 830 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tIrp status was %lx\n", 831 Irp, 832 Irp->IoStatus.Status)); 833 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tSrb status was %lx\n", 834 Irp, 835 srbHeader->SrbStatus)); 836 837 838 839 // 840 // Lock was not successful - throw down the power IRP 841 // by itself and don't try to spin down the drive or unlock 842 // the queue. 843 // 844 845 // 846 // Set the new power state 847 // 848 849 fdoExtension->DevicePowerState = 850 currentStack->Parameters.Power.State.DeviceState; 851 852 // 853 // Indicate to Po that we've been successfully powered down 854 // so it can do it's notification stuff. 855 // 856 857 IoCopyCurrentIrpStackLocationToNext(OriginalIrp); 858 IoSetCompletionRoutine(OriginalIrp, 859 ClasspStartNextPowerIrpCompletion, 860 PowerContext, 861 TRUE, 862 TRUE, 863 TRUE); 864 865 PoSetPowerState(PowerContext->DeviceObject, 866 currentStack->Parameters.Power.Type, 867 currentStack->Parameters.Power.State); 868 869 fdoExtension->PowerDownInProgress = FALSE; 870 871 ClassReleaseRemoveLock(commonExtension->DeviceObject, 872 OriginalIrp); 873 874 PoCallDriver(commonExtension->LowerDeviceObject, OriginalIrp); 875 876 return STATUS_MORE_PROCESSING_REQUIRED; 877 878 } else { 879 // 880 // Lock the device queue succeeded. Now wait for all outstanding IO to complete. 881 // To do this, Srb with SRB_FUNCTION_QUIESCE_DEVICE will be sent down with default timeout value. 882 // We need to tolerant failure of this request, no retry will be made. 883 // 884 PowerContext->QueueLocked = (UCHAR) PowerContext->Options.LockQueue; 885 886 // 887 // No retry on device quiescence reqeust 888 // 889 fdoExtension->PrivateFdoData->MaxPowerOperationRetryCount = 0; 890 PowerContext->RetryCount = 0; 891 892 if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { 893 srbHeader = (PSTORAGE_REQUEST_BLOCK_HEADER)&(fdoExtension->PrivateFdoData->PowerSrb.SrbEx); 894 895 // 896 // Initialize extended SRB for a SRB_FUNCTION_LOCK_QUEUE 897 // 898 status = InitializeStorageRequestBlock((PSTORAGE_REQUEST_BLOCK)srbHeader, 899 STORAGE_ADDRESS_TYPE_BTL8, 900 CLASS_SRBEX_NO_SRBEX_DATA_BUFFER_SIZE, 901 0); 902 if (NT_SUCCESS(status)) { 903 ((PSTORAGE_REQUEST_BLOCK)srbHeader)->SrbFunction = SRB_FUNCTION_QUIESCE_DEVICE; 904 } else { 905 // 906 // Should not happen. Revert to legacy SRB. 907 // 908 NT_ASSERT(FALSE); 909 srbHeader = (PSTORAGE_REQUEST_BLOCK_HEADER)&(PowerContext->Srb); 910 srbHeader->Length = sizeof(SCSI_REQUEST_BLOCK); 911 srbHeader->Function = SRB_FUNCTION_QUIESCE_DEVICE; 912 } 913 } else { 914 srbHeader = (PSTORAGE_REQUEST_BLOCK_HEADER)&(PowerContext->Srb); 915 srbHeader->Length = sizeof(SCSI_REQUEST_BLOCK); 916 srbHeader->Function = SRB_FUNCTION_QUIESCE_DEVICE; 917 } 918 919 SrbSetOriginalRequest(srbHeader, fdoExtension->PrivateFdoData->PowerProcessIrp); 920 SrbSetTimeOutValue(srbHeader, fdoExtension->TimeOutValue); 921 922 SrbAssignSrbFlags(srbHeader, 923 (SRB_FLAGS_NO_DATA_TRANSFER | 924 SRB_FLAGS_DISABLE_AUTOSENSE | 925 SRB_FLAGS_DISABLE_SYNCH_TRANSFER | 926 SRB_FLAGS_NO_QUEUE_FREEZE | 927 SRB_FLAGS_BYPASS_LOCKED_QUEUE | 928 SRB_FLAGS_D3_PROCESSING)); 929 930 IoSetCompletionRoutine(fdoExtension->PrivateFdoData->PowerProcessIrp, 931 ClasspPowerDownCompletion, 932 PowerContext, 933 TRUE, 934 TRUE, 935 TRUE); 936 937 nextStack->Parameters.Scsi.Srb = (PSCSI_REQUEST_BLOCK)srbHeader; 938 nextStack->MajorFunction = IRP_MJ_SCSI; 939 940 status = IoCallDriver(commonExtension->LowerDeviceObject, fdoExtension->PrivateFdoData->PowerProcessIrp); 941 942 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tIoCallDriver returned %lx\n", fdoExtension->PrivateFdoData->PowerProcessIrp, status)); 943 break; 944 } 945 946 } 947 948 case PowerDownDeviceQuiesced3: { 949 950 PCDB cdb; 951 952 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tPreviously sent device quiesce\n", Irp)); 953 954 // 955 // don't care the result of device quiesce, we've made the effort. 956 // continue on sending other SCSI commands anyway. 957 // 958 959 960 if (!TEST_FLAG(fdoExtension->PrivateFdoData->HackFlags, 961 FDO_HACK_NO_SYNC_CACHE)) { 962 963 // 964 // send SCSIOP_SYNCHRONIZE_CACHE 965 // 966 967 fdoExtension->PrivateFdoData->MaxPowerOperationRetryCount = MAXIMUM_RETRIES; 968 PowerContext->RetryCount = MAXIMUM_RETRIES; 969 970 if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { 971 status = InitializeStorageRequestBlock((PSTORAGE_REQUEST_BLOCK)srbHeader, 972 STORAGE_ADDRESS_TYPE_BTL8, 973 CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE, 974 1, 975 SrbExDataTypeScsiCdb16); 976 if (NT_SUCCESS(status)) { 977 ((PSTORAGE_REQUEST_BLOCK)srbHeader)->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI; 978 979 // 980 // Set length field in Power Context SRB so we know legacy SRB is not being used. 981 // 982 PowerContext->Srb.Length = 0; 983 984 } else { 985 // 986 // Should not occur. Revert to legacy SRB. 987 NT_ASSERT(FALSE); 988 srbHeader = (PSTORAGE_REQUEST_BLOCK_HEADER)&(PowerContext->Srb); 989 RtlZeroMemory(srbHeader, sizeof(SCSI_REQUEST_BLOCK)); 990 srbHeader->Length = sizeof(SCSI_REQUEST_BLOCK); 991 srbHeader->Function = SRB_FUNCTION_EXECUTE_SCSI; 992 } 993 994 } else { 995 RtlZeroMemory(srbHeader, sizeof(SCSI_REQUEST_BLOCK)); 996 srbHeader->Length = sizeof(SCSI_REQUEST_BLOCK); 997 srbHeader->Function = SRB_FUNCTION_EXECUTE_SCSI; 998 } 999 1000 1001 SrbSetOriginalRequest(srbHeader, fdoExtension->PrivateFdoData->PowerProcessIrp); 1002 SrbSetSenseInfoBuffer(srbHeader, commonExtension->PartitionZeroExtension->SenseData); 1003 SrbSetSenseInfoBufferLength(srbHeader, GET_FDO_EXTENSON_SENSE_DATA_LENGTH(commonExtension->PartitionZeroExtension)); 1004 SrbSetTimeOutValue(srbHeader, fdoExtension->TimeOutValue); 1005 1006 SrbAssignSrbFlags(srbHeader, 1007 (SRB_FLAGS_NO_DATA_TRANSFER | 1008 SRB_FLAGS_DISABLE_AUTOSENSE | 1009 SRB_FLAGS_DISABLE_SYNCH_TRANSFER | 1010 SRB_FLAGS_NO_QUEUE_FREEZE | 1011 SRB_FLAGS_BYPASS_LOCKED_QUEUE | 1012 SRB_FLAGS_D3_PROCESSING)); 1013 1014 SrbSetCdbLength(srbHeader, 10); 1015 1016 cdb = SrbGetCdb(srbHeader); 1017 1018 RtlZeroMemory(cdb, sizeof(CDB)); 1019 cdb->SYNCHRONIZE_CACHE10.OperationCode = SCSIOP_SYNCHRONIZE_CACHE; 1020 1021 IoSetCompletionRoutine(fdoExtension->PrivateFdoData->PowerProcessIrp, 1022 ClasspPowerDownCompletion, 1023 PowerContext, 1024 TRUE, 1025 TRUE, 1026 TRUE); 1027 1028 nextStack->Parameters.Scsi.Srb = (PSCSI_REQUEST_BLOCK)srbHeader; 1029 nextStack->MajorFunction = IRP_MJ_SCSI; 1030 1031 status = IoCallDriver(commonExtension->LowerDeviceObject, fdoExtension->PrivateFdoData->PowerProcessIrp); 1032 1033 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tIoCallDriver returned %lx\n", fdoExtension->PrivateFdoData->PowerProcessIrp, status)); 1034 break; 1035 1036 } else { 1037 1038 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_POWER, "(%p)\tPower Down: not sending SYNCH_CACHE\n", 1039 PowerContext->DeviceObject)); 1040 PowerContext->PowerChangeState.PowerDown3++; 1041 srbHeader->SrbStatus = SRB_STATUS_SUCCESS; 1042 // and fall through.... 1043 } 1044 // no break in case the device doesn't like synch_cache commands 1045 1046 } 1047 1048 case PowerDownDeviceFlushed3: { 1049 1050 PCDB cdb; 1051 1052 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tPreviously send SCSIOP_SYNCHRONIZE_CACHE\n", 1053 Irp)); 1054 1055 // 1056 // SCSIOP_SYNCHRONIZE_CACHE was sent 1057 // 1058 1059 if (SRB_STATUS(srbHeader->SrbStatus) != SRB_STATUS_SUCCESS) { 1060 1061 BOOLEAN retry; 1062 LONGLONG delta100nsUnits = 0; 1063 1064 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_POWER, "(%p)\tError occured when issuing " 1065 "SYNCHRONIZE_CACHE command to device. " 1066 "Srb %p, Status %lx\n", 1067 Irp, 1068 srbHeader, 1069 srbHeader->SrbStatus)); 1070 1071 NT_ASSERT(!(TEST_FLAG(srbHeader->SrbStatus, SRB_STATUS_QUEUE_FROZEN))); 1072 NT_ASSERT((srbHeader->Function == SRB_FUNCTION_EXECUTE_SCSI) || 1073 (((PSTORAGE_REQUEST_BLOCK)srbHeader)->SrbFunction == SRB_FUNCTION_EXECUTE_SCSI)); 1074 1075 PowerContext->RetryInterval = 0; 1076 retry = InterpretSenseInfoWithoutHistory( 1077 fdoExtension->DeviceObject, 1078 Irp, 1079 (PSCSI_REQUEST_BLOCK)srbHeader, 1080 IRP_MJ_SCSI, 1081 IRP_MJ_POWER, 1082 fdoExtension->PrivateFdoData->MaxPowerOperationRetryCount - PowerContext->RetryCount, 1083 &status, 1084 &delta100nsUnits); 1085 1086 // NOTE: Power context is a public structure, and thus cannot be 1087 // updated to use 100ns units. Therefore, must store the 1088 // one-second equivalent. Round up to ensure minimum delay 1089 // requirements have been met. 1090 delta100nsUnits += (10*1000*1000) - 1; 1091 delta100nsUnits /= (10*1000*1000); 1092 // guaranteed not to have high bits set per SAL annotations 1093 PowerContext->RetryInterval = (ULONG)(delta100nsUnits); 1094 1095 1096 if ((retry == TRUE) && (PowerContext->RetryCount-- != 0)) { 1097 1098 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tRetrying failed request\n", Irp)); 1099 1100 // 1101 // decrement the state so we come back through here 1102 // the next time. 1103 // 1104 1105 PowerContext->PowerChangeState.PowerDown3--; 1106 RetryPowerRequest(commonExtension->DeviceObject, 1107 Irp, 1108 PowerContext); 1109 break; 1110 } 1111 1112 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tSYNCHRONIZE_CACHE not retried\n", Irp)); 1113 fdoExtension->PrivateFdoData->MaxPowerOperationRetryCount = MAXIMUM_RETRIES; 1114 PowerContext->RetryCount = MAXIMUM_RETRIES; 1115 } // end !SRB_STATUS_SUCCESS 1116 1117 // 1118 // note: we are purposefully ignoring any errors. if the drive 1119 // doesn't support a synch_cache, then we're up a creek 1120 // anyways. 1121 // 1122 1123 if ((currentStack->Parameters.Power.State.DeviceState == PowerDeviceD3) && 1124 (currentStack->Parameters.Power.ShutdownType == PowerActionHibernate) && 1125 (commonExtension->HibernationPathCount != 0)) { 1126 1127 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tPower Down: not sending SPIN DOWN due to hibernation path\n", 1128 PowerContext->DeviceObject)); 1129 1130 PowerContext->PowerChangeState.PowerDown3++; 1131 srbHeader->SrbStatus = SRB_STATUS_SUCCESS; 1132 status = STATUS_SUCCESS; 1133 1134 // Fall through to next case... 1135 1136 } else { 1137 // Send STOP UNIT command. As "Imme" bit is set to '1', this command should be completed in short time. 1138 // This command is at low importance, failure of this command has very small impact. 1139 1140 ULONG secondsRemaining; 1141 ULONG timeoutValue; 1142 1143 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tSending stop unit to device\n", Irp)); 1144 1145 if (PoQueryWatchdogTime(fdoExtension->LowerPdo, &secondsRemaining)) { 1146 // plan to leave some time (TIME_LEFT_FOR_LOWER_DRIVERS) to lower level drivers 1147 // for processing the original power irp. 1148 if (secondsRemaining >= (TIME_LEFT_FOR_LOWER_DRIVERS + DEFAULT_IO_TIMEOUT_VALUE)) { 1149 fdoExtension->PrivateFdoData->MaxPowerOperationRetryCount = 1150 (secondsRemaining - TIME_LEFT_FOR_LOWER_DRIVERS) / DEFAULT_IO_TIMEOUT_VALUE; 1151 1152 // * No 'short' timeouts 1153 // 1154 // timeoutValue = (secondsRemaining - TIME_LEFT_FOR_LOWER_DRIVERS) % 1155 // DEFAULT_IO_TIMEOUT_VALUE; 1156 // if (timeoutValue < MINIMUM_STOP_UNIT_TIMEOUT_VALUE) 1157 // { 1158 if (--fdoExtension->PrivateFdoData->MaxPowerOperationRetryCount) 1159 { 1160 timeoutValue = DEFAULT_IO_TIMEOUT_VALUE; 1161 } else { 1162 timeoutValue = secondsRemaining - TIME_LEFT_FOR_LOWER_DRIVERS; 1163 } 1164 // } 1165 1166 // Limit to maximum retry count. 1167 if (fdoExtension->PrivateFdoData->MaxPowerOperationRetryCount > MAXIMUM_RETRIES) { 1168 fdoExtension->PrivateFdoData->MaxPowerOperationRetryCount = MAXIMUM_RETRIES; 1169 } 1170 } else { 1171 // issue the command with minimum timeout value and do not retry on it. 1172 fdoExtension->PrivateFdoData->MaxPowerOperationRetryCount = 0; 1173 1174 // minimum as MINIMUM_STOP_UNIT_TIMEOUT_VALUE. 1175 if (secondsRemaining > 2 * MINIMUM_STOP_UNIT_TIMEOUT_VALUE) { 1176 timeoutValue = secondsRemaining - MINIMUM_STOP_UNIT_TIMEOUT_VALUE; 1177 } else { 1178 timeoutValue = MINIMUM_STOP_UNIT_TIMEOUT_VALUE; 1179 } 1180 1181 } 1182 1183 } else { 1184 // do not know how long, use default values. 1185 fdoExtension->PrivateFdoData->MaxPowerOperationRetryCount = MAXIMUM_RETRIES; 1186 timeoutValue = DEFAULT_IO_TIMEOUT_VALUE; 1187 } 1188 1189 // 1190 // Issue STOP UNIT command to the device. 1191 // 1192 1193 PowerContext->RetryCount = fdoExtension->PrivateFdoData->MaxPowerOperationRetryCount; 1194 1195 if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { 1196 status = InitializeStorageRequestBlock((PSTORAGE_REQUEST_BLOCK)srbHeader, 1197 STORAGE_ADDRESS_TYPE_BTL8, 1198 CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE, 1199 1, 1200 SrbExDataTypeScsiCdb16); 1201 if (NT_SUCCESS(status)) { 1202 ((PSTORAGE_REQUEST_BLOCK)srbHeader)->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI; 1203 1204 // 1205 // Set length field in Power Context SRB so we know legacy SRB is not being used. 1206 // 1207 PowerContext->Srb.Length = 0; 1208 1209 } else { 1210 // 1211 // Should not occur. Revert to legacy SRB. 1212 // 1213 NT_ASSERT(FALSE); 1214 srbHeader = (PSTORAGE_REQUEST_BLOCK_HEADER)&(PowerContext->Srb); 1215 RtlZeroMemory(srbHeader, sizeof(SCSI_REQUEST_BLOCK)); 1216 srbHeader->Length = sizeof(SCSI_REQUEST_BLOCK); 1217 srbHeader->Function = SRB_FUNCTION_EXECUTE_SCSI; 1218 } 1219 1220 } else { 1221 RtlZeroMemory(srbHeader, sizeof(SCSI_REQUEST_BLOCK)); 1222 srbHeader->Length = sizeof(SCSI_REQUEST_BLOCK); 1223 srbHeader->Function = SRB_FUNCTION_EXECUTE_SCSI; 1224 } 1225 1226 SrbSetOriginalRequest(srbHeader, fdoExtension->PrivateFdoData->PowerProcessIrp); 1227 SrbSetSenseInfoBuffer(srbHeader, commonExtension->PartitionZeroExtension->SenseData); 1228 SrbSetSenseInfoBufferLength(srbHeader, GET_FDO_EXTENSON_SENSE_DATA_LENGTH(commonExtension->PartitionZeroExtension)); 1229 SrbSetTimeOutValue(srbHeader, timeoutValue); 1230 1231 1232 SrbAssignSrbFlags(srbHeader, 1233 (SRB_FLAGS_NO_DATA_TRANSFER | 1234 SRB_FLAGS_DISABLE_AUTOSENSE | 1235 SRB_FLAGS_DISABLE_SYNCH_TRANSFER | 1236 SRB_FLAGS_NO_QUEUE_FREEZE | 1237 SRB_FLAGS_BYPASS_LOCKED_QUEUE | 1238 SRB_FLAGS_D3_PROCESSING)); 1239 1240 SrbSetCdbLength(srbHeader, 6); 1241 1242 cdb = SrbGetCdb(srbHeader); 1243 RtlZeroMemory(cdb, sizeof(CDB)); 1244 1245 cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT; 1246 cdb->START_STOP.Start = 0; 1247 cdb->START_STOP.Immediate = 1; 1248 1249 IoSetCompletionRoutine(fdoExtension->PrivateFdoData->PowerProcessIrp, 1250 ClasspPowerDownCompletion, 1251 PowerContext, 1252 TRUE, 1253 TRUE, 1254 TRUE); 1255 1256 nextStack->Parameters.Scsi.Srb = (PSCSI_REQUEST_BLOCK)srbHeader; 1257 nextStack->MajorFunction = IRP_MJ_SCSI; 1258 1259 status = IoCallDriver(commonExtension->LowerDeviceObject, fdoExtension->PrivateFdoData->PowerProcessIrp); 1260 1261 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tIoCallDriver returned %lx\n", fdoExtension->PrivateFdoData->PowerProcessIrp, status)); 1262 break; 1263 } 1264 } 1265 1266 case PowerDownDeviceStopped3: { 1267 1268 BOOLEAN ignoreError = TRUE; 1269 1270 // 1271 // stop was sent 1272 // 1273 1274 if (SRB_STATUS(srbHeader->SrbStatus) != SRB_STATUS_SUCCESS) { 1275 1276 BOOLEAN retry; 1277 LONGLONG delta100nsUnits = 0; 1278 1279 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_POWER, "(%p)\tError occured when issueing STOP_UNIT " 1280 "command to device. Srb %p, Status %lx\n", 1281 Irp, 1282 srbHeader, 1283 srbHeader->SrbStatus)); 1284 1285 NT_ASSERT(!(TEST_FLAG(srbHeader->SrbStatus, SRB_STATUS_QUEUE_FROZEN))); 1286 NT_ASSERT((srbHeader->Function == SRB_FUNCTION_EXECUTE_SCSI) || 1287 (((PSTORAGE_REQUEST_BLOCK)srbHeader)->SrbFunction == SRB_FUNCTION_EXECUTE_SCSI)); 1288 1289 PowerContext->RetryInterval = 0; 1290 retry = InterpretSenseInfoWithoutHistory( 1291 fdoExtension->DeviceObject, 1292 Irp, 1293 (PSCSI_REQUEST_BLOCK)srbHeader, 1294 IRP_MJ_SCSI, 1295 IRP_MJ_POWER, 1296 fdoExtension->PrivateFdoData->MaxPowerOperationRetryCount - PowerContext->RetryCount, 1297 &status, 1298 &delta100nsUnits); 1299 1300 // NOTE: Power context is a public structure, and thus cannot be 1301 // updated to use 100ns units. Therefore, must store the 1302 // one-second equivalent. Round up to ensure minimum delay 1303 // requirements have been met. 1304 delta100nsUnits += (10*1000*1000) - 1; 1305 delta100nsUnits /= (10*1000*1000); 1306 // guaranteed not to have high bits set per SAL annotations 1307 PowerContext->RetryInterval = (ULONG)(delta100nsUnits); 1308 1309 1310 if ((retry == TRUE) && (PowerContext->RetryCount-- != 0)) { 1311 1312 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tRetrying failed request\n", Irp)); 1313 1314 // 1315 // decrement the state so we come back through here 1316 // the next time. 1317 // 1318 1319 PowerContext->PowerChangeState.PowerDown3--; 1320 1321 SrbSetTimeOutValue(srbHeader, DEFAULT_IO_TIMEOUT_VALUE); 1322 1323 RetryPowerRequest(commonExtension->DeviceObject, 1324 Irp, 1325 PowerContext); 1326 break; 1327 } 1328 1329 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tSTOP_UNIT not retried\n", Irp)); 1330 fdoExtension->PrivateFdoData->MaxPowerOperationRetryCount = MAXIMUM_RETRIES; 1331 PowerContext->RetryCount = MAXIMUM_RETRIES; 1332 1333 } // end !SRB_STATUS_SUCCESS 1334 1335 1336 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tPreviously sent stop unit\n", Irp)); 1337 1338 // 1339 // some operations, such as a physical format in progress, 1340 // should not be ignored and should fail the power operation. 1341 // 1342 1343 if (!NT_SUCCESS(status)) { 1344 1345 PVOID senseBuffer = SrbGetSenseInfoBuffer(srbHeader); 1346 1347 if (TEST_FLAG(srbHeader->SrbStatus, SRB_STATUS_AUTOSENSE_VALID) && 1348 (senseBuffer != NULL)) { 1349 1350 BOOLEAN validSense = FALSE; 1351 UCHAR senseKey = 0; 1352 UCHAR additionalSenseCode = 0; 1353 UCHAR additionalSenseCodeQualifier = 0; 1354 1355 validSense = ScsiGetSenseKeyAndCodes(senseBuffer, 1356 SrbGetSenseInfoBufferLength(srbHeader), 1357 SCSI_SENSE_OPTIONS_FIXED_FORMAT_IF_UNKNOWN_FORMAT_INDICATED, 1358 &senseKey, 1359 &additionalSenseCode, 1360 &additionalSenseCodeQualifier); 1361 1362 if (validSense) { 1363 if ((senseKey == SCSI_SENSE_NOT_READY) && 1364 (additionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY) && 1365 (additionalSenseCodeQualifier == SCSI_SENSEQ_FORMAT_IN_PROGRESS)) { 1366 1367 ignoreError = FALSE; 1368 PowerContext->FinalStatus = STATUS_DEVICE_BUSY; 1369 status = PowerContext->FinalStatus; 1370 } 1371 } 1372 } 1373 } 1374 1375 if (NT_SUCCESS(status) || ignoreError) { 1376 1377 // 1378 // Issue the original power request to the lower driver. 1379 // 1380 1381 IoCopyCurrentIrpStackLocationToNext(OriginalIrp); 1382 1383 IoSetCompletionRoutine(OriginalIrp, 1384 ClasspPowerDownCompletion, 1385 PowerContext, 1386 TRUE, 1387 TRUE, 1388 TRUE); 1389 1390 status = PoCallDriver(commonExtension->LowerDeviceObject, OriginalIrp); 1391 1392 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tPoCallDriver returned %lx\n", OriginalIrp, status)); 1393 break; 1394 } 1395 1396 // else fall through w/o sending the power irp, since the device 1397 // is reporting an error that would be "really bad" to power down 1398 // during. 1399 1400 } 1401 1402 case PowerDownDeviceOff3: { 1403 1404 // 1405 // SpinDown request completed ... whether it succeeded or not is 1406 // another matter entirely. 1407 // 1408 1409 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tPreviously sent power irp\n", OriginalIrp)); 1410 1411 if (PowerContext->QueueLocked) { 1412 1413 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tUnlocking queue\n", OriginalIrp)); 1414 1415 if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { 1416 // 1417 // Will reuse SRB for a non-SCSI SRB. 1418 // 1419 status = InitializeStorageRequestBlock((PSTORAGE_REQUEST_BLOCK)srbHeader, 1420 STORAGE_ADDRESS_TYPE_BTL8, 1421 CLASS_SRBEX_NO_SRBEX_DATA_BUFFER_SIZE, 1422 0); 1423 if (NT_SUCCESS(status)) { 1424 ((PSTORAGE_REQUEST_BLOCK)srbHeader)->SrbFunction = SRB_FUNCTION_UNLOCK_QUEUE; 1425 1426 // 1427 // Set length field in Power Context SRB so we know legacy SRB is not being used. 1428 // 1429 PowerContext->Srb.Length = 0; 1430 1431 } else { 1432 // 1433 // Should not occur. Revert to legacy SRB. 1434 // 1435 NT_ASSERT(FALSE); 1436 srbHeader = (PSTORAGE_REQUEST_BLOCK_HEADER)&(PowerContext->Srb); 1437 RtlZeroMemory(srbHeader, sizeof(SCSI_REQUEST_BLOCK)); 1438 srbHeader->Length = sizeof(SCSI_REQUEST_BLOCK); 1439 srbHeader->Function = SRB_FUNCTION_UNLOCK_QUEUE; 1440 } 1441 } else { 1442 RtlZeroMemory(srbHeader, sizeof(SCSI_REQUEST_BLOCK)); 1443 srbHeader->Length = sizeof(SCSI_REQUEST_BLOCK); 1444 srbHeader->Function = SRB_FUNCTION_UNLOCK_QUEUE; 1445 } 1446 1447 SrbSetOriginalRequest(srbHeader, fdoExtension->PrivateFdoData->PowerProcessIrp); 1448 SrbAssignSrbFlags(srbHeader, (SRB_FLAGS_BYPASS_LOCKED_QUEUE | 1449 SRB_FLAGS_D3_PROCESSING)); 1450 1451 nextStack->Parameters.Scsi.Srb = (PSCSI_REQUEST_BLOCK)srbHeader; 1452 nextStack->MajorFunction = IRP_MJ_SCSI; 1453 1454 IoSetCompletionRoutine(fdoExtension->PrivateFdoData->PowerProcessIrp, 1455 ClasspPowerDownCompletion, 1456 PowerContext, 1457 TRUE, 1458 TRUE, 1459 TRUE); 1460 1461 status = IoCallDriver(commonExtension->LowerDeviceObject, fdoExtension->PrivateFdoData->PowerProcessIrp); 1462 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tIoCallDriver returned %lx\n", 1463 fdoExtension->PrivateFdoData->PowerProcessIrp, 1464 status)); 1465 break; 1466 } 1467 1468 } 1469 1470 case PowerDownDeviceUnlocked3: { 1471 1472 // 1473 // This is the end of the dance. 1474 // We're ignoring possible intermediate error conditions .... 1475 // 1476 1477 if (PowerContext->QueueLocked == FALSE) { 1478 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tFall through (queue not locked)\n", OriginalIrp)); 1479 } else { 1480 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tPreviously unlocked queue\n", OriginalIrp)); 1481 NT_ASSERT(NT_SUCCESS(Irp->IoStatus.Status)); 1482 NT_ASSERT(srbHeader->SrbStatus == SRB_STATUS_SUCCESS); 1483 1484 if (NT_SUCCESS(Irp->IoStatus.Status)) { 1485 PowerContext->QueueLocked = FALSE; 1486 } 1487 } 1488 1489 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tFreeing srb and completing\n", OriginalIrp)); 1490 status = PowerContext->FinalStatus; // allow failure to propogate 1491 1492 OriginalIrp->IoStatus.Status = status; 1493 OriginalIrp->IoStatus.Information = 0; 1494 1495 if (NT_SUCCESS(status)) { 1496 1497 // 1498 // Set the new power state 1499 // 1500 1501 fdoExtension->DevicePowerState = 1502 currentStack->Parameters.Power.State.DeviceState; 1503 1504 } 1505 1506 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tStarting next power irp\n", OriginalIrp)); 1507 1508 ClassReleaseRemoveLock(PowerContext->DeviceObject, OriginalIrp); 1509 1510 PowerContext->InUse = FALSE; 1511 1512 PoStartNextPowerIrp(OriginalIrp); 1513 1514 fdoExtension->PowerDownInProgress = FALSE; 1515 1516 // prevent from completing the irp allocated by ourselves 1517 if (Irp == fdoExtension->PrivateFdoData->PowerProcessIrp) { 1518 // complete original irp if we are processing powerprocess irp, 1519 // otherwise, by returning status other than STATUS_MORE_PROCESSING_REQUIRED, IO manager will complete it. 1520 ClassCompleteRequest(commonExtension->DeviceObject, OriginalIrp, IO_NO_INCREMENT); 1521 status = STATUS_MORE_PROCESSING_REQUIRED; 1522 } 1523 1524 return status; 1525 } 1526 } 1527 1528 return STATUS_MORE_PROCESSING_REQUIRED; 1529 } // end ClasspPowerDownCompletion() 1530 1531 /*++//////////////////////////////////////////////////////////////////////////// 1532 1533 ClasspPowerHandler() 1534 1535 Routine Description: 1536 1537 This routine reduces the number of useless spinups and spindown requests 1538 sent to a given device by ignoring transitions to power states we are 1539 currently in. 1540 1541 ISSUE-2000/02/20-henrygab - by ignoring spin-up requests, we may be 1542 allowing the drive 1543 1544 Arguments: 1545 1546 DeviceObject - the device object which is transitioning power states 1547 Irp - the power irp 1548 Options - a set of flags indicating what the device handles 1549 1550 Return Value: 1551 1552 --*/ 1553 NTSTATUS 1554 ClasspPowerHandler( 1555 IN PDEVICE_OBJECT DeviceObject, 1556 IN PIRP Irp, 1557 IN CLASS_POWER_OPTIONS Options // ISSUE-2000/02/20-henrygab - pass pointer, not whole struct 1558 ) 1559 { 1560 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 1561 PDEVICE_OBJECT lowerDevice = commonExtension->LowerDeviceObject; 1562 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); 1563 PIO_STACK_LOCATION nextIrpStack; 1564 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; 1565 PCLASS_POWER_CONTEXT context; 1566 PSTORAGE_REQUEST_BLOCK_HEADER srbHeader; 1567 ULONG srbFlags; 1568 NTSTATUS status; 1569 1570 _Analysis_assume_(fdoExtension); 1571 _Analysis_assume_(fdoExtension->PrivateFdoData); 1572 1573 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "ClasspPowerHandler: Power irp %p to %s %p\n", 1574 Irp, (commonExtension->IsFdo ? "fdo" : "pdo"), DeviceObject)); 1575 1576 if (!commonExtension->IsFdo) { 1577 1578 // 1579 // certain assumptions are made here, 1580 // particularly: having the fdoExtension 1581 // 1582 1583 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_POWER, "ClasspPowerHandler: Called for PDO %p???\n", 1584 DeviceObject)); 1585 NT_ASSERT(!"PDO using ClasspPowerHandler"); 1586 1587 ClassReleaseRemoveLock(DeviceObject, Irp); 1588 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; 1589 PoStartNextPowerIrp(Irp); 1590 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 1591 return STATUS_NOT_SUPPORTED; 1592 } 1593 1594 switch (irpStack->MinorFunction) { 1595 1596 case IRP_MN_SET_POWER: { 1597 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData; 1598 1599 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tIRP_MN_SET_POWER\n", Irp)); 1600 1601 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tSetting %s state to %d\n", 1602 Irp, 1603 (irpStack->Parameters.Power.Type == SystemPowerState ? 1604 "System" : "Device"), 1605 irpStack->Parameters.Power.State.SystemState)); 1606 1607 switch (irpStack->Parameters.Power.ShutdownType){ 1608 1609 case PowerActionNone: 1610 1611 // 1612 // Skip if device doesn't need volume verification during idle power 1613 // transitions. 1614 // 1615 if ((fdoExtension->FunctionSupportInfo) && 1616 (fdoExtension->FunctionSupportInfo->IdlePower.NoVerifyDuringIdlePower)) { 1617 break; 1618 } 1619 1620 case PowerActionSleep: 1621 case PowerActionHibernate: 1622 if (fdoData->HotplugInfo.MediaRemovable || fdoData->HotplugInfo.MediaHotplug) { 1623 /* 1624 * We are suspending device and this drive is either hot-pluggable 1625 * or contains removeable media. 1626 * Set the media dirty bit, since the media may change while 1627 * we are suspended. 1628 */ 1629 SET_FLAG(DeviceObject->Flags, DO_VERIFY_VOLUME); 1630 1631 // 1632 // Bumping the media change count will force the 1633 // file system to verify the volume when we resume 1634 // 1635 1636 InterlockedIncrement((volatile LONG *)&fdoExtension->MediaChangeCount); 1637 } 1638 1639 break; 1640 } 1641 1642 break; 1643 } 1644 1645 default: { 1646 1647 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tIrp minor code = %#x\n", 1648 Irp, irpStack->MinorFunction)); 1649 break; 1650 } 1651 } 1652 1653 if (irpStack->Parameters.Power.Type != DevicePowerState || 1654 irpStack->MinorFunction != IRP_MN_SET_POWER) { 1655 1656 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tSending to lower device\n", Irp)); 1657 1658 goto ClasspPowerHandlerCleanup; 1659 1660 } 1661 1662 // 1663 // already in exact same state, don't work to transition to it. 1664 // 1665 1666 if (irpStack->Parameters.Power.State.DeviceState == 1667 fdoExtension->DevicePowerState) { 1668 1669 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tAlready in device state %x\n", 1670 Irp, fdoExtension->DevicePowerState)); 1671 goto ClasspPowerHandlerCleanup; 1672 1673 } 1674 1675 // 1676 // or powering down from non-d0 state (device already stopped) 1677 // NOTE -- we're not sure whether this case can exist or not (the 1678 // power system may never send this sort of request) but it's trivial 1679 // to deal with. 1680 // 1681 1682 if ((irpStack->Parameters.Power.State.DeviceState != PowerDeviceD0) && 1683 (fdoExtension->DevicePowerState != PowerDeviceD0)) { 1684 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tAlready powered down to %x???\n", 1685 Irp, fdoExtension->DevicePowerState)); 1686 fdoExtension->DevicePowerState = 1687 irpStack->Parameters.Power.State.DeviceState; 1688 goto ClasspPowerHandlerCleanup; 1689 } 1690 1691 // 1692 // or when not handling powering up and are powering up 1693 // 1694 1695 if ((!Options.HandleSpinUp) && 1696 (irpStack->Parameters.Power.State.DeviceState == PowerDeviceD0)) { 1697 1698 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tNot handling spinup to state %x\n", 1699 Irp, fdoExtension->DevicePowerState)); 1700 fdoExtension->DevicePowerState = 1701 irpStack->Parameters.Power.State.DeviceState; 1702 goto ClasspPowerHandlerCleanup; 1703 1704 } 1705 1706 // 1707 // or when not handling powering down and are powering down 1708 // 1709 1710 if ((!Options.HandleSpinDown) && 1711 (irpStack->Parameters.Power.State.DeviceState != PowerDeviceD0)) { 1712 1713 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tNot handling spindown to state %x\n", 1714 Irp, fdoExtension->DevicePowerState)); 1715 fdoExtension->DevicePowerState = 1716 irpStack->Parameters.Power.State.DeviceState; 1717 goto ClasspPowerHandlerCleanup; 1718 1719 } 1720 1721 // 1722 // validation completed, start the real work. 1723 // 1724 1725 IoReuseIrp(fdoExtension->PrivateFdoData->PowerProcessIrp, STATUS_SUCCESS); 1726 IoSetNextIrpStackLocation(fdoExtension->PrivateFdoData->PowerProcessIrp); 1727 nextIrpStack = IoGetNextIrpStackLocation(fdoExtension->PrivateFdoData->PowerProcessIrp); 1728 1729 context = &(fdoExtension->PowerContext); 1730 1731 NT_ASSERT(context->InUse == FALSE); 1732 1733 RtlZeroMemory(context, sizeof(CLASS_POWER_CONTEXT)); 1734 context->InUse = TRUE; 1735 1736 if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { 1737 srbHeader = (PSTORAGE_REQUEST_BLOCK_HEADER)&(fdoExtension->PrivateFdoData->PowerSrb.SrbEx); 1738 1739 // 1740 // Initialize extended SRB for a SRB_FUNCTION_LOCK_QUEUE 1741 // 1742 status = InitializeStorageRequestBlock((PSTORAGE_REQUEST_BLOCK)srbHeader, 1743 STORAGE_ADDRESS_TYPE_BTL8, 1744 CLASS_SRBEX_NO_SRBEX_DATA_BUFFER_SIZE, 1745 0); 1746 if (NT_SUCCESS(status)) { 1747 ((PSTORAGE_REQUEST_BLOCK)srbHeader)->SrbFunction = SRB_FUNCTION_LOCK_QUEUE; 1748 } else { 1749 // 1750 // Should not happen. Revert to legacy SRB. 1751 // 1752 NT_ASSERT(FALSE); 1753 srbHeader = (PSTORAGE_REQUEST_BLOCK_HEADER)&(context->Srb); 1754 srbHeader->Length = sizeof(SCSI_REQUEST_BLOCK); 1755 srbHeader->Function = SRB_FUNCTION_LOCK_QUEUE; 1756 } 1757 } else { 1758 srbHeader = (PSTORAGE_REQUEST_BLOCK_HEADER)&(context->Srb); 1759 srbHeader->Length = sizeof(SCSI_REQUEST_BLOCK); 1760 srbHeader->Function = SRB_FUNCTION_LOCK_QUEUE; 1761 } 1762 nextIrpStack->Parameters.Scsi.Srb = (PSCSI_REQUEST_BLOCK)srbHeader; 1763 nextIrpStack->MajorFunction = IRP_MJ_SCSI; 1764 1765 context->FinalStatus = STATUS_SUCCESS; 1766 1767 SrbSetOriginalRequest(srbHeader, fdoExtension->PrivateFdoData->PowerProcessIrp); 1768 SrbSetSrbFlags(srbHeader, (SRB_FLAGS_BYPASS_LOCKED_QUEUE | SRB_FLAGS_NO_QUEUE_FREEZE)); 1769 1770 fdoExtension->PrivateFdoData->MaxPowerOperationRetryCount = MAXIMUM_RETRIES; 1771 context->RetryCount = MAXIMUM_RETRIES; 1772 1773 context->Options = Options; 1774 context->DeviceObject = DeviceObject; 1775 context->Irp = Irp; 1776 1777 if (irpStack->Parameters.Power.State.DeviceState == PowerDeviceD0) { 1778 1779 NT_ASSERT(Options.HandleSpinUp); 1780 1781 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tpower up - locking queue\n", Irp)); 1782 1783 // 1784 // We need to issue a queue lock request so that we 1785 // can spin the drive back up after the power is restored 1786 // but before any requests are processed. 1787 // 1788 1789 context->Options.PowerDown = FALSE; 1790 context->PowerChangeState.PowerUp = PowerUpDeviceInitial; 1791 context->CompletionRoutine = ClasspPowerUpCompletion; 1792 1793 } else { 1794 1795 NT_ASSERT(Options.HandleSpinDown); 1796 1797 fdoExtension->PowerDownInProgress = TRUE; 1798 1799 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tPowering down - locking queue\n", Irp)); 1800 1801 // 1802 // Disable tick timer at beginning of D3 processing if running. 1803 // 1804 if ((fdoExtension->PrivateFdoData->TickTimerEnabled)) { 1805 ClasspDisableTimer(fdoExtension); 1806 } 1807 1808 PoSetPowerState(DeviceObject, 1809 irpStack->Parameters.Power.Type, 1810 irpStack->Parameters.Power.State); 1811 1812 context->Options.PowerDown = TRUE; 1813 context->PowerChangeState.PowerDown3 = PowerDownDeviceInitial3; 1814 context->CompletionRoutine = ClasspPowerDownCompletion; 1815 1816 } 1817 1818 // 1819 // we are not dealing with port-allocated sense in these routines. 1820 // 1821 1822 srbFlags = SrbGetSrbFlags(srbHeader); 1823 NT_ASSERT(!TEST_FLAG(srbFlags, SRB_FLAGS_FREE_SENSE_BUFFER)); 1824 NT_ASSERT(!TEST_FLAG(srbFlags, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE)); 1825 1826 // 1827 // Mark the original power irp pending. 1828 // 1829 1830 IoMarkIrpPending(Irp); 1831 1832 if (Options.LockQueue) { 1833 1834 // 1835 // Send the lock irp down. 1836 // 1837 1838 IoSetCompletionRoutine(fdoExtension->PrivateFdoData->PowerProcessIrp, 1839 context->CompletionRoutine, 1840 context, 1841 TRUE, 1842 TRUE, 1843 TRUE); 1844 1845 IoCallDriver(lowerDevice, fdoExtension->PrivateFdoData->PowerProcessIrp); 1846 1847 } else { 1848 1849 // 1850 // Call the completion routine directly. It won't care what the 1851 // status of the "lock" was - it will just go and do the next 1852 // step of the operation. 1853 // 1854 1855 context->CompletionRoutine(DeviceObject, fdoExtension->PrivateFdoData->PowerProcessIrp, context); 1856 } 1857 1858 return STATUS_PENDING; 1859 1860 ClasspPowerHandlerCleanup: 1861 1862 // 1863 // Send the original power irp down, we will start the next power irp in completion routine. 1864 // 1865 ClassReleaseRemoveLock(DeviceObject, Irp); 1866 1867 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tStarting next power irp\n", Irp)); 1868 IoCopyCurrentIrpStackLocationToNext(Irp); 1869 IoSetCompletionRoutine(Irp, 1870 ClasspStartNextPowerIrpCompletion, 1871 NULL, 1872 TRUE, 1873 TRUE, 1874 TRUE); 1875 return PoCallDriver(lowerDevice, Irp); 1876 } // end ClasspPowerHandler() 1877 1878 /*++//////////////////////////////////////////////////////////////////////////// 1879 1880 ClassMinimalPowerHandler() 1881 1882 Routine Description: 1883 1884 This routine is the minimum power handler for a storage driver. It does 1885 the least amount of work possible. 1886 1887 --*/ 1888 NTSTATUS 1889 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 1890 ClassMinimalPowerHandler( 1891 IN PDEVICE_OBJECT DeviceObject, 1892 IN PIRP Irp 1893 ) 1894 { 1895 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 1896 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); 1897 NTSTATUS status; 1898 1899 ClassReleaseRemoveLock(DeviceObject, Irp); 1900 PoStartNextPowerIrp(Irp); 1901 1902 switch (irpStack->MinorFunction) 1903 { 1904 case IRP_MN_SET_POWER: 1905 { 1906 switch (irpStack->Parameters.Power.ShutdownType) 1907 { 1908 case PowerActionNone: 1909 case PowerActionSleep: 1910 case PowerActionHibernate: 1911 { 1912 if (TEST_FLAG(DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA)) 1913 { 1914 if ((ClassGetVpb(DeviceObject) != NULL) && (ClassGetVpb(DeviceObject)->Flags & VPB_MOUNTED)) 1915 { 1916 // 1917 // This flag will cause the filesystem to verify the 1918 // volume when coming out of hibernation or standby or runtime power 1919 // 1920 SET_FLAG(DeviceObject->Flags, DO_VERIFY_VOLUME); 1921 } 1922 } 1923 } 1924 break; 1925 } 1926 } 1927 1928 // 1929 // Fall through 1930 // 1931 1932 case IRP_MN_QUERY_POWER: 1933 { 1934 if (!commonExtension->IsFdo) 1935 { 1936 Irp->IoStatus.Status = STATUS_SUCCESS; 1937 Irp->IoStatus.Information = 0; 1938 } 1939 } 1940 break; 1941 } 1942 1943 if (commonExtension->IsFdo) 1944 { 1945 IoCopyCurrentIrpStackLocationToNext(Irp); 1946 status = PoCallDriver(commonExtension->LowerDeviceObject, Irp); 1947 } 1948 else 1949 { 1950 status = Irp->IoStatus.Status; 1951 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 1952 } 1953 1954 return status; 1955 } // end ClassMinimalPowerHandler() 1956 1957 /*++//////////////////////////////////////////////////////////////////////////// 1958 1959 ClassSpinDownPowerHandler() 1960 1961 Routine Description: 1962 1963 This routine is a callback for disks and other things which require both 1964 a start and a stop to be sent to the device. (actually the starts are 1965 almost always optional, since most device power themselves on to process 1966 commands, but i digress). 1967 1968 Determines proper use of spinup, spindown, and queue locking based upon 1969 ScanForSpecialFlags in the FdoExtension. This is the most common power 1970 handler passed into classpnp.sys 1971 1972 Arguments: 1973 1974 DeviceObject - Supplies the functional device object 1975 1976 Irp - Supplies the request to be retried. 1977 1978 Return Value: 1979 1980 None 1981 1982 --*/ 1983 __control_entrypoint(DeviceDriver) 1984 NTSTATUS 1985 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 1986 ClassSpinDownPowerHandler( 1987 _In_ PDEVICE_OBJECT DeviceObject, 1988 _In_ PIRP Irp 1989 ) 1990 { 1991 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension; 1992 CLASS_POWER_OPTIONS options = {0}; 1993 1994 fdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 1995 1996 // 1997 // check the flags to see what options we need to worry about 1998 // 1999 2000 if (!TEST_FLAG(fdoExtension->ScanForSpecialFlags, 2001 CLASS_SPECIAL_DISABLE_SPIN_DOWN)) { 2002 options.HandleSpinDown = TRUE; 2003 } 2004 2005 if (!TEST_FLAG(fdoExtension->ScanForSpecialFlags, 2006 CLASS_SPECIAL_DISABLE_SPIN_UP)) { 2007 options.HandleSpinUp = TRUE; 2008 } 2009 2010 if (!TEST_FLAG(fdoExtension->ScanForSpecialFlags, 2011 CLASS_SPECIAL_NO_QUEUE_LOCK)) { 2012 options.LockQueue = TRUE; 2013 } 2014 2015 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "ClasspPowerHandler: Devobj %p\n" 2016 "\t%shandling spin down\n" 2017 "\t%shandling spin up\n" 2018 "\t%slocking queue\n", 2019 DeviceObject, 2020 (options.HandleSpinDown ? "" : "not "), 2021 (options.HandleSpinUp ? "" : "not "), 2022 (options.LockQueue ? "" : "not ") 2023 )); 2024 2025 // 2026 // do all the dirty work 2027 // 2028 2029 return ClasspPowerHandler(DeviceObject, Irp, options); 2030 } // end ClassSpinDownPowerHandler() 2031 2032 /*++//////////////////////////////////////////////////////////////////////////// 2033 2034 ClassStopUnitPowerHandler() 2035 2036 Routine Description: 2037 2038 This routine is an outdated call. To achieve equivalent functionality, 2039 the driver should set the following flags in ScanForSpecialFlags in the 2040 FdoExtension: 2041 2042 CLASS_SPECIAL_DISABLE_SPIN_UP 2043 CLASS_SPECIAL_NO_QUEUE_LOCK 2044 2045 --*/ 2046 NTSTATUS 2047 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 2048 ClassStopUnitPowerHandler( 2049 _In_ PDEVICE_OBJECT DeviceObject, 2050 _In_ PIRP Irp 2051 ) 2052 { 2053 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension; 2054 2055 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_POWER, "ClassStopUnitPowerHandler - Devobj %p using outdated call\n" 2056 "Drivers should set the following flags in ScanForSpecialFlags " 2057 " in the FDO extension:\n" 2058 "\tCLASS_SPECIAL_DISABLE_SPIN_UP\n" 2059 "\tCLASS_SPECIAL_NO_QUEUE_LOCK\n" 2060 "This will provide equivalent functionality if the power " 2061 "routine is then set to ClassSpinDownPowerHandler\n\n", 2062 DeviceObject)); 2063 2064 fdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 2065 2066 SET_FLAG(fdoExtension->ScanForSpecialFlags, 2067 CLASS_SPECIAL_DISABLE_SPIN_UP); 2068 SET_FLAG(fdoExtension->ScanForSpecialFlags, 2069 CLASS_SPECIAL_NO_QUEUE_LOCK); 2070 2071 return ClassSpinDownPowerHandler(DeviceObject, Irp); 2072 } // end ClassStopUnitPowerHandler() 2073 2074 /*++//////////////////////////////////////////////////////////////////////////// 2075 2076 RetryPowerRequest() 2077 2078 Routine Description: 2079 2080 This routine reinitalizes the necessary fields, and sends the request 2081 to the lower driver. 2082 2083 Arguments: 2084 2085 DeviceObject - Supplies the device object associated with this request. 2086 2087 Irp - Supplies the request to be retried. 2088 2089 Context - Supplies a pointer to the power up context for this request. 2090 2091 Return Value: 2092 2093 None 2094 2095 --*/ 2096 VOID 2097 RetryPowerRequest( 2098 PDEVICE_OBJECT DeviceObject, 2099 PIRP Irp, 2100 PCLASS_POWER_CONTEXT Context 2101 ) 2102 { 2103 PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp); 2104 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = 2105 (PFUNCTIONAL_DEVICE_EXTENSION)Context->DeviceObject->DeviceExtension; 2106 PSTORAGE_REQUEST_BLOCK_HEADER srb; 2107 LONGLONG dueTime; 2108 ULONG srbFlags; 2109 ULONG srbFunction; 2110 2111 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tDelaying retry by queueing DPC\n", Irp)); 2112 2113 //NT_ASSERT(Context->Irp == Irp); 2114 if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { 2115 srb = (PSTORAGE_REQUEST_BLOCK_HEADER)&(fdoExtension->PrivateFdoData->PowerSrb.SrbEx); 2116 2117 // 2118 // Check if reverted to using legacy SRB. 2119 // 2120 if (Context->Srb.Length == sizeof(SCSI_REQUEST_BLOCK)) { 2121 srb = (PSTORAGE_REQUEST_BLOCK_HEADER)&(Context->Srb); 2122 srbFunction = srb->Function; 2123 } else { 2124 srbFunction = ((PSTORAGE_REQUEST_BLOCK)srb)->SrbFunction; 2125 } 2126 } else { 2127 srb = (PSTORAGE_REQUEST_BLOCK_HEADER)&(Context->Srb); 2128 srbFunction = srb->Function; 2129 } 2130 2131 NT_ASSERT(Context->DeviceObject == DeviceObject); 2132 srbFlags = SrbGetSrbFlags(srb); 2133 NT_ASSERT(!TEST_FLAG(srbFlags, SRB_FLAGS_FREE_SENSE_BUFFER)); 2134 NT_ASSERT(!TEST_FLAG(srbFlags, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE)); 2135 2136 if (Context->RetryInterval == 0) { 2137 2138 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tDelaying minimum time (.2 sec)\n", Irp)); 2139 dueTime = (LONGLONG)1000000 * 2; 2140 2141 } else { 2142 2143 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tDelaying %x seconds\n", 2144 Irp, Context->RetryInterval)); 2145 dueTime = (LONGLONG)1000000 * 10 * Context->RetryInterval; 2146 2147 } 2148 2149 // 2150 // reset the retry interval 2151 // 2152 2153 Context->RetryInterval = 0; 2154 2155 // 2156 // Reset byte count of transfer in SRB Extension. 2157 // 2158 2159 SrbSetDataTransferLength(srb, 0); 2160 2161 // 2162 // Zero SRB statuses. 2163 // 2164 2165 srb->SrbStatus = 0; 2166 if (srbFunction == SRB_FUNCTION_EXECUTE_SCSI) { 2167 SrbSetScsiStatus(srb, 0); 2168 } 2169 2170 // 2171 // Set up major SCSI function. 2172 // 2173 2174 nextIrpStack->MajorFunction = IRP_MJ_SCSI; 2175 2176 // 2177 // Save SRB address in next stack for port driver. 2178 // 2179 2180 nextIrpStack->Parameters.Scsi.Srb = (PSCSI_REQUEST_BLOCK)srb; 2181 2182 // 2183 // Set the completion routine up again. 2184 // 2185 2186 IoSetCompletionRoutine(Irp, Context->CompletionRoutine, Context, 2187 TRUE, TRUE, TRUE); 2188 2189 ClassRetryRequest(DeviceObject, Irp, dueTime); 2190 2191 return; 2192 2193 } // end RetryRequest() 2194 2195 /*++//////////////////////////////////////////////////////////////////////////// 2196 2197 ClasspStartNextPowerIrpCompletion() 2198 2199 Routine Description: 2200 2201 This routine guarantees that the next power irp (power up or down) is not 2202 sent until the previous one has fully completed. 2203 2204 --*/ 2205 NTSTATUS 2206 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 2207 ClasspStartNextPowerIrpCompletion( 2208 IN PDEVICE_OBJECT DeviceObject, 2209 IN PIRP Irp, 2210 IN PVOID Context 2211 ) 2212 { 2213 PCLASS_POWER_CONTEXT PowerContext = (PCLASS_POWER_CONTEXT)Context; 2214 2215 UNREFERENCED_PARAMETER(DeviceObject); 2216 2217 if (Irp->PendingReturned) { 2218 IoMarkIrpPending(Irp); 2219 } 2220 2221 if (PowerContext != NULL) 2222 { 2223 PowerContext->InUse = FALSE; 2224 } 2225 2226 2227 PoStartNextPowerIrp(Irp); 2228 return STATUS_SUCCESS; 2229 } // end ClasspStartNextPowerIrpCompletion() 2230 2231 NTSTATUS 2232 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 2233 ClasspDeviceLockFailurePowerIrpCompletion( 2234 IN PDEVICE_OBJECT DeviceObject, 2235 IN PIRP Irp, 2236 IN PVOID Context 2237 ) 2238 { 2239 PCLASS_POWER_CONTEXT PowerContext = (PCLASS_POWER_CONTEXT)Context; 2240 PCOMMON_DEVICE_EXTENSION commonExtension; 2241 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension; 2242 PIO_STACK_LOCATION currentStack; 2243 BOOLEAN FailurePredictionEnabled = FALSE; 2244 2245 UNREFERENCED_PARAMETER(DeviceObject); 2246 2247 commonExtension = PowerContext->DeviceObject->DeviceExtension; 2248 fdoExtension = PowerContext->DeviceObject->DeviceExtension; 2249 2250 currentStack = IoGetCurrentIrpStackLocation(Irp); 2251 2252 // 2253 // Set the new power state 2254 // 2255 2256 fdoExtension->DevicePowerState = currentStack->Parameters.Power.State.DeviceState; 2257 2258 // 2259 // We reach here becasue LockQueue operation was not successful. 2260 // However, media change detection would not happen in case of resume becasue we 2261 // had disabled the timer while going into lower power state. 2262 // So, if the device goes into D0 then enable the tick timer. 2263 // 2264 2265 if (fdoExtension->DevicePowerState == PowerDeviceD0) { 2266 // 2267 // Check whether failure detection is enabled 2268 // 2269 2270 if ((fdoExtension->FailurePredictionInfo != NULL) && 2271 (fdoExtension->FailurePredictionInfo->Method != FailurePredictionNone)) { 2272 FailurePredictionEnabled = TRUE; 2273 } 2274 2275 // 2276 // Enable tick timer at end of D0 processing if it was previously enabled. 2277 // 2278 2279 if ((commonExtension->DriverExtension->InitData.ClassTick != NULL) || 2280 ((fdoExtension->MediaChangeDetectionInfo != NULL) && 2281 (fdoExtension->FunctionSupportInfo != NULL) && 2282 (fdoExtension->FunctionSupportInfo->AsynchronousNotificationSupported == FALSE)) || 2283 (FailurePredictionEnabled)) { 2284 2285 // 2286 // If failure prediction is turned on and we've been powered 2287 // off longer than the failure prediction query period then 2288 // force the query on the next timer tick. 2289 // 2290 2291 if ((FailurePredictionEnabled) && (ClasspFailurePredictionPeriodMissed(fdoExtension))) { 2292 fdoExtension->FailurePredictionInfo->CountDown = 1; 2293 } 2294 2295 // 2296 // Finally, enable the timer. 2297 // 2298 2299 ClasspEnableTimer(fdoExtension); 2300 } 2301 } 2302 2303 // 2304 // Indicate to Po that we've been successfully powered up so 2305 // it can do it's notification stuff. 2306 // 2307 2308 PoSetPowerState(PowerContext->DeviceObject, 2309 currentStack->Parameters.Power.Type, 2310 currentStack->Parameters.Power.State); 2311 2312 PowerContext->InUse = FALSE; 2313 2314 2315 ClassReleaseRemoveLock(commonExtension->DeviceObject, Irp); 2316 2317 // 2318 // Start the next power IRP 2319 // 2320 2321 if (Irp->PendingReturned) { 2322 IoMarkIrpPending(Irp); 2323 } 2324 2325 PoStartNextPowerIrp(Irp); 2326 2327 return STATUS_SUCCESS; 2328 } 2329 2330 2331 _IRQL_requires_same_ 2332 NTSTATUS 2333 ClasspSendEnableIdlePowerIoctl( 2334 _In_ PDEVICE_OBJECT DeviceObject 2335 ) 2336 /*++ 2337 Description: 2338 2339 This function is used to send IOCTL_STORAGE_ENABLE_IDLE_POWER to the port 2340 driver. It pulls the relevant idle power management properties from the 2341 FDO's device extension. 2342 2343 Arguments: 2344 2345 DeviceObject - The class FDO. 2346 2347 Return Value: 2348 2349 The NTSTATUS code returned from the port driver. STATUS_SUCCESS indicates 2350 this device is now enabled for idle (runtime) power management. 2351 2352 --*/ 2353 { 2354 NTSTATUS status; 2355 STORAGE_IDLE_POWER idlePower = {0}; 2356 IO_STATUS_BLOCK ioStatus = {0}; 2357 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 2358 PCOMMON_DEVICE_EXTENSION commonExtension = &(fdoExtension->CommonExtension); 2359 2360 idlePower.Version = 1; 2361 idlePower.Size = sizeof(STORAGE_IDLE_POWER); 2362 idlePower.WakeCapableHint = fdoExtension->FunctionSupportInfo->IdlePower.DeviceWakeable; 2363 idlePower.D3ColdSupported = fdoExtension->FunctionSupportInfo->IdlePower.D3ColdSupported; 2364 idlePower.D3IdleTimeout = fdoExtension->FunctionSupportInfo->IdlePower.D3IdleTimeout; 2365 2366 ClassSendDeviceIoControlSynchronous( 2367 IOCTL_STORAGE_ENABLE_IDLE_POWER, 2368 commonExtension->LowerDeviceObject, 2369 &idlePower, 2370 sizeof(STORAGE_IDLE_POWER), 2371 0, 2372 FALSE, 2373 &ioStatus 2374 ); 2375 2376 status = ioStatus.Status; 2377 2378 TracePrint((TRACE_LEVEL_INFORMATION, 2379 TRACE_FLAG_POWER, 2380 "ClasspSendEnableIdlePowerIoctl: Port driver returned status (%x) for FDO (%p)\n" 2381 "\tWakeCapableHint: %u\n" 2382 "\tD3ColdSupported: %u\n" 2383 "\tD3IdleTimeout: %u (ms)", 2384 status, 2385 DeviceObject, 2386 idlePower.WakeCapableHint, 2387 idlePower.D3ColdSupported, 2388 idlePower.D3IdleTimeout)); 2389 2390 return status; 2391 } 2392 2393 _Function_class_(POWER_SETTING_CALLBACK) 2394 _IRQL_requires_same_ 2395 NTSTATUS 2396 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 2397 ClasspPowerSettingCallback( 2398 _In_ LPCGUID SettingGuid, 2399 _In_reads_bytes_(ValueLength) PVOID Value, 2400 _In_ ULONG ValueLength, 2401 _Inout_opt_ PVOID Context 2402 ) 2403 /*++ 2404 Description: 2405 2406 This function is the callback for power setting notifications (registered 2407 when ClasspGetD3IdleTimeout() is called for the first time). 2408 2409 Currently, this function is used to get the disk idle timeout value from 2410 the system power settings. 2411 2412 This function is guaranteed to be called at PASSIVE_LEVEL. 2413 2414 Arguments: 2415 2416 SettingGuid - The power setting GUID. 2417 Value - Pointer to the power setting value. 2418 ValueLength - Size of the Value buffer. 2419 Context - The FDO's device extension. 2420 2421 Return Value: 2422 2423 STATUS_SUCCESS 2424 2425 --*/ 2426 { 2427 PIDLE_POWER_FDO_LIST_ENTRY fdoEntry = NULL; 2428 2429 #ifdef _MSC_VER 2430 #pragma warning(suppress:4054) // okay to type cast function pointer to PIRP for this use case 2431 #endif 2432 PIRP removeLockTag = (PIRP)&ClasspPowerSettingCallback; 2433 2434 UNREFERENCED_PARAMETER(Context); 2435 2436 PAGED_CODE(); 2437 2438 if (IsEqualGUID(SettingGuid, &GUID_DISK_IDLE_TIMEOUT)) { 2439 if (ValueLength != sizeof(ULONG) || Value == NULL) { 2440 return STATUS_INVALID_PARAMETER; 2441 } 2442 2443 // 2444 // The value supplied by this GUID is already in milliseconds. 2445 // 2446 DiskIdleTimeoutInMS = *((PULONG)Value); 2447 2448 // 2449 // For each FDO on the idle power list, grab the remove lock and send 2450 // IOCTL_STORAGE_ENABLE_IDLE_POWER to the port driver to update the 2451 // idle timeout value. 2452 // 2453 KeAcquireGuardedMutex(&IdlePowerFDOListMutex); 2454 fdoEntry = (PIDLE_POWER_FDO_LIST_ENTRY)IdlePowerFDOList.Flink; 2455 while ((PLIST_ENTRY)fdoEntry != &IdlePowerFDOList) { 2456 2457 ULONG isRemoved = ClassAcquireRemoveLock(fdoEntry->Fdo, removeLockTag); 2458 2459 if (!isRemoved) { 2460 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION)fdoEntry->Fdo->DeviceExtension; 2461 2462 // 2463 // Apply the new timeout if the user hasn't overridden it via the registry. 2464 // 2465 if (!fdoExtension->FunctionSupportInfo->IdlePower.D3IdleTimeoutOverridden) { 2466 fdoExtension->FunctionSupportInfo->IdlePower.D3IdleTimeout = DiskIdleTimeoutInMS; 2467 ClasspSendEnableIdlePowerIoctl(fdoEntry->Fdo); 2468 } 2469 } 2470 2471 ClassReleaseRemoveLock(fdoEntry->Fdo, removeLockTag); 2472 2473 fdoEntry = (PIDLE_POWER_FDO_LIST_ENTRY)fdoEntry->ListEntry.Flink; 2474 } 2475 KeReleaseGuardedMutex(&IdlePowerFDOListMutex); 2476 2477 } else if (IsEqualGUID(SettingGuid, &GUID_CONSOLE_DISPLAY_STATE)) { 2478 2479 // 2480 // If monitor is off, change media change requests to not 2481 // keep device active. This allows removable media devices to 2482 // go to sleep if there are no other active requests. Otherwise, 2483 // let media change requests keep the device active. 2484 // 2485 if ((ValueLength == sizeof(ULONG)) && (Value != NULL)) { 2486 if (*((PULONG)Value) == PowerMonitorOff) { 2487 ClasspScreenOff = TRUE; 2488 } else { 2489 ClasspScreenOff = FALSE; 2490 } 2491 2492 KeAcquireGuardedMutex(&IdlePowerFDOListMutex); 2493 fdoEntry = (PIDLE_POWER_FDO_LIST_ENTRY)IdlePowerFDOList.Flink; 2494 while ((PLIST_ENTRY)fdoEntry != &IdlePowerFDOList) { 2495 2496 ULONG isRemoved = ClassAcquireRemoveLock(fdoEntry->Fdo, removeLockTag); 2497 if (!isRemoved) { 2498 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION)fdoEntry->Fdo->DeviceExtension; 2499 2500 if (ClasspScreenOff == FALSE) { 2501 // 2502 // Now that the screen is on, we may need to check for media 2503 // for devices that are not in D0 and may have removable media. 2504 // This is because the media change polling has been disabled 2505 // for devices in D3 and now that the screen is on the user may 2506 // have inserted some media that they want to interact with. 2507 // 2508 if ((fdoExtension->DevicePowerState != PowerDeviceD0) && 2509 (fdoExtension->MediaChangeDetectionInfo != NULL) && 2510 (fdoExtension->FunctionSupportInfo->AsynchronousNotificationSupported == FALSE)) { 2511 ClassCheckMediaState(fdoExtension); 2512 } 2513 2514 // 2515 // We disabled failure prediction polling during screen-off 2516 // so now check to see if we missed a failure prediction 2517 // period and if so, force the IOCTL to be sent now. 2518 // 2519 if ((fdoExtension->FailurePredictionInfo != NULL) && 2520 (fdoExtension->FailurePredictionInfo->Method != FailurePredictionNone)) { 2521 if (ClasspFailurePredictionPeriodMissed(fdoExtension)) { 2522 fdoExtension->FailurePredictionInfo->CountDown = 1; 2523 } 2524 } 2525 } 2526 2527 #if (NTDDI_VERSION >= NTDDI_WINBLUE) 2528 // 2529 // Screen state has changed so attempt to update the tick 2530 // timer's no-wake tolerance accordingly. 2531 // 2532 ClasspUpdateTimerNoWakeTolerance(fdoExtension); 2533 #endif 2534 } 2535 ClassReleaseRemoveLock(fdoEntry->Fdo, removeLockTag); 2536 2537 fdoEntry = (PIDLE_POWER_FDO_LIST_ENTRY)fdoEntry->ListEntry.Flink; 2538 } 2539 KeReleaseGuardedMutex(&IdlePowerFDOListMutex); 2540 } 2541 2542 } 2543 2544 return STATUS_SUCCESS; 2545 } 2546 2547 2548 _IRQL_requires_same_ 2549 NTSTATUS 2550 ClasspEnableIdlePower( 2551 _In_ PDEVICE_OBJECT DeviceObject 2552 ) 2553 /*++ 2554 Description: 2555 2556 This function is used to enable idle (runtime) power management for the 2557 device. It will do the work to determine D3Cold support, idle timeout, 2558 etc. and then notify the port driver that it wants to enable idle power 2559 management. 2560 2561 This function may modify some of the idle power fields in the FDO's device 2562 extension. 2563 2564 Arguments: 2565 2566 DeviceObject - The class FDO. 2567 2568 Return Value: 2569 2570 An NTSTATUS code indicating the status of the operation. 2571 2572 --*/ 2573 { 2574 NTSTATUS status = STATUS_SUCCESS; 2575 ULONG d3ColdDisabledByUser = FALSE; 2576 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 2577 ULONG idleTimeoutOverrideInSeconds = 0; 2578 2579 // 2580 // This function should only be called once. 2581 // 2582 NT_ASSERT(fdoExtension->FunctionSupportInfo->IdlePower.IdlePowerEnabled == FALSE); 2583 2584 ClassGetDeviceParameter(fdoExtension, 2585 CLASSP_REG_SUBKEY_NAME, 2586 CLASSP_REG_DISABLE_D3COLD, 2587 &d3ColdDisabledByUser); 2588 2589 // 2590 // If the device is hot-pluggable or the user has explicitly 2591 // disabled D3Cold, do not enable D3Cold for this device. 2592 // 2593 if (d3ColdDisabledByUser || fdoExtension->PrivateFdoData->HotplugInfo.DeviceHotplug) { 2594 fdoExtension->FunctionSupportInfo->IdlePower.D3ColdSupported = 0; 2595 } 2596 2597 ClassGetDeviceParameter(fdoExtension, 2598 CLASSP_REG_SUBKEY_NAME, 2599 CLASSP_REG_IDLE_TIMEOUT_IN_SECONDS, 2600 &idleTimeoutOverrideInSeconds); 2601 2602 // 2603 // Set the idle timeout. If the user has not specified an override value, 2604 // this will either be a default value or will have been updated by the 2605 // power setting notification callback. 2606 // 2607 if (idleTimeoutOverrideInSeconds != 0) { 2608 fdoExtension->FunctionSupportInfo->IdlePower.D3IdleTimeout = (idleTimeoutOverrideInSeconds * 1000); 2609 fdoExtension->FunctionSupportInfo->IdlePower.D3IdleTimeoutOverridden = TRUE; 2610 } else { 2611 fdoExtension->FunctionSupportInfo->IdlePower.D3IdleTimeout = DiskIdleTimeoutInMS; 2612 } 2613 2614 // 2615 // We don't allow disks to be wakeable. 2616 // 2617 fdoExtension->FunctionSupportInfo->IdlePower.DeviceWakeable = FALSE; 2618 2619 // 2620 // Send IOCTL_STORAGE_ENABLE_IDLE_POWER to the port driver to enable idle 2621 // power management by the port driver. 2622 // 2623 status = ClasspSendEnableIdlePowerIoctl(DeviceObject); 2624 2625 if (NT_SUCCESS(status)) { 2626 PIDLE_POWER_FDO_LIST_ENTRY fdoEntry = NULL; 2627 2628 // 2629 // Put this FDO on the list of devices that are idle power managed. 2630 // 2631 fdoEntry = ExAllocatePoolWithTag(NonPagedPoolNx, sizeof(IDLE_POWER_FDO_LIST_ENTRY), CLASS_TAG_POWER); 2632 if (fdoEntry) { 2633 2634 fdoExtension->FunctionSupportInfo->IdlePower.IdlePowerEnabled = TRUE; 2635 2636 fdoEntry->Fdo = DeviceObject; 2637 2638 KeAcquireGuardedMutex(&IdlePowerFDOListMutex); 2639 InsertHeadList(&IdlePowerFDOList, &(fdoEntry->ListEntry)); 2640 KeReleaseGuardedMutex(&IdlePowerFDOListMutex); 2641 2642 // 2643 // If not registered already, register for disk idle timeout power 2644 // setting notifications. The power manager will call our power 2645 // setting callback very soon to set the idle timeout to the actual 2646 // value. 2647 // 2648 if (PowerSettingNotificationHandle == NULL) { 2649 PoRegisterPowerSettingCallback(DeviceObject, 2650 &GUID_DISK_IDLE_TIMEOUT, 2651 &ClasspPowerSettingCallback, 2652 NULL, 2653 &(PowerSettingNotificationHandle)); 2654 } 2655 } else { 2656 fdoExtension->FunctionSupportInfo->IdlePower.IdlePowerEnabled = FALSE; 2657 status = STATUS_UNSUCCESSFUL; 2658 } 2659 } 2660 2661 return status; 2662 } 2663 2664