1 /*++ 2 3 Copyright (C) Microsoft Corporation, 1991 - 1999 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 #include "classp.h" 25 26 #define CLASS_TAG_POWER 'WLcS' 27 28 NTSTATUS 29 NTAPI 30 ClasspPowerHandler( 31 IN PDEVICE_OBJECT DeviceObject, 32 IN PIRP Irp, 33 IN CLASS_POWER_OPTIONS Options 34 ); 35 36 IO_COMPLETION_ROUTINE ClasspPowerDownCompletion; 37 38 IO_COMPLETION_ROUTINE ClasspPowerUpCompletion; 39 40 VOID 41 NTAPI 42 RetryPowerRequest( 43 PDEVICE_OBJECT DeviceObject, 44 PIRP Irp, 45 PCLASS_POWER_CONTEXT Context 46 ); 47 48 NTSTATUS 49 NTAPI 50 ClasspStartNextPowerIrpCompletion( 51 IN PDEVICE_OBJECT DeviceObject, 52 IN PIRP Irp, 53 IN PVOID Context 54 ); 55 56 57 /*++//////////////////////////////////////////////////////////////////////////// 58 59 ClassDispatchPower() 60 61 Routine Description: 62 63 This routine acquires the removelock for the irp and then calls the 64 appropriate power callback. 65 66 Arguments: 67 68 DeviceObject - 69 Irp - 70 71 Return Value: 72 73 --*/ 74 NTSTATUS 75 NTAPI 76 ClassDispatchPower( 77 IN PDEVICE_OBJECT DeviceObject, 78 IN PIRP Irp 79 ) 80 { 81 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 82 ULONG isRemoved; 83 84 // 85 // NOTE: This code may be called at PASSIVE or DISPATCH, depending 86 // upon the device object it is being called for. 87 // don't do anything that would break under either circumstance. 88 // 89 90 isRemoved = ClassAcquireRemoveLock(DeviceObject, Irp); 91 92 if(isRemoved) { 93 ClassReleaseRemoveLock(DeviceObject, Irp); 94 Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST; 95 PoStartNextPowerIrp(Irp); 96 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 97 return STATUS_DEVICE_DOES_NOT_EXIST; 98 } 99 100 return commonExtension->DevInfo->ClassPowerDevice(DeviceObject, Irp); 101 } // end ClassDispatchPower() 102 103 /*++//////////////////////////////////////////////////////////////////////////// 104 105 ClasspPowerUpCompletion() 106 107 Routine Description: 108 109 This routine is used for intermediate completion of a power up request. 110 PowerUp requires four requests to be sent to the lower driver in sequence. 111 112 * The queue is "power locked" to ensure that the class driver power-up 113 work can be done before request processing resumes. 114 115 * The power irp is sent down the stack for any filter drivers and the 116 port driver to return power and resume command processing for the 117 device. Since the queue is locked, no queued irps will be sent 118 immediately. 119 120 * A start unit command is issued to the device with appropriate flags 121 to override the "power locked" queue. 122 123 * The queue is "power unlocked" to start processing requests again. 124 125 This routine uses the function in the srb which just completed to determine 126 which state it is in. 127 128 Arguments: 129 130 DeviceObject - the device object being powered up 131 132 Irp - the IO_REQUEST_PACKET containing the power request 133 134 Srb - the SRB used to perform port/class operations. 135 136 Return Value: 137 138 STATUS_MORE_PROCESSING_REQUIRED or 139 STATUS_SUCCESS 140 141 --*/ 142 NTSTATUS 143 NTAPI 144 ClasspPowerUpCompletion( 145 IN PDEVICE_OBJECT DeviceObject, 146 IN PIRP Irp, 147 IN PVOID CompletionContext 148 ) 149 { 150 PCLASS_POWER_CONTEXT context = CompletionContext; 151 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 152 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; 153 154 PIO_STACK_LOCATION currentStack = IoGetCurrentIrpStackLocation(Irp); 155 PIO_STACK_LOCATION nextStack = IoGetNextIrpStackLocation(Irp); 156 157 158 NTSTATUS status = STATUS_MORE_PROCESSING_REQUIRED; 159 160 DebugPrint((1, "ClasspPowerUpCompletion: Device Object %p, Irp %p, " 161 "Context %p\n", 162 DeviceObject, Irp, context)); 163 164 ASSERT(!TEST_FLAG(context->Srb.SrbFlags, SRB_FLAGS_FREE_SENSE_BUFFER)); 165 ASSERT(!TEST_FLAG(context->Srb.SrbFlags, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE)); 166 ASSERT(context->Options.PowerDown == FALSE); 167 ASSERT(context->Options.HandleSpinUp); 168 169 if(Irp->PendingReturned) { 170 IoMarkIrpPending(Irp); 171 } 172 173 context->PowerChangeState.PowerUp++; 174 175 switch(context->PowerChangeState.PowerUp) { 176 177 case PowerUpDeviceLocked: { 178 179 DebugPrint((1, "(%p)\tPreviously sent power lock\n", Irp)); 180 181 // 182 // Issue the actual power request to the lower driver. 183 // 184 185 IoCopyCurrentIrpStackLocationToNext(Irp); 186 187 // 188 // If the lock wasn't successful then just bail out on the power 189 // request unless we can ignore failed locks 190 // 191 192 if ((context->Options.LockQueue != FALSE) && 193 (!NT_SUCCESS(Irp->IoStatus.Status))) { 194 195 DebugPrint((1, "(%p)\tIrp status was %lx\n", 196 Irp, Irp->IoStatus.Status)); 197 DebugPrint((1, "(%p)\tSrb status was %lx\n", 198 Irp, context->Srb.SrbStatus)); 199 200 // 201 // Lock was not successful - throw down the power IRP 202 // by itself and don't try to spin up the drive or unlock 203 // the queue. 204 // 205 206 context->InUse = FALSE; 207 context = NULL; 208 209 // 210 // Set the new power state 211 // 212 213 fdoExtension->DevicePowerState = 214 currentStack->Parameters.Power.State.DeviceState; 215 216 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; 217 218 IoCopyCurrentIrpStackLocationToNext(Irp); 219 220 IoSetCompletionRoutine(Irp, 221 ClasspStartNextPowerIrpCompletion, 222 NULL, 223 TRUE, 224 TRUE, 225 TRUE); 226 227 // 228 // Indicate to Po that we've been successfully powered up so 229 // it can do it's notification stuff. 230 // 231 232 PoSetPowerState(DeviceObject, 233 currentStack->Parameters.Power.Type, 234 currentStack->Parameters.Power.State); 235 236 PoCallDriver(commonExtension->LowerDeviceObject, Irp); 237 238 ClassReleaseRemoveLock(commonExtension->DeviceObject, 239 Irp); 240 241 return STATUS_MORE_PROCESSING_REQUIRED; 242 243 } else { 244 context->QueueLocked = (UCHAR) context->Options.LockQueue; 245 } 246 247 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; 248 249 context->PowerChangeState.PowerUp = PowerUpDeviceLocked; 250 251 IoSetCompletionRoutine(Irp, 252 ClasspPowerUpCompletion, 253 context, 254 TRUE, 255 TRUE, 256 TRUE); 257 258 status = PoCallDriver(commonExtension->LowerDeviceObject, Irp); 259 260 DebugPrint((2, "(%p)\tPoCallDriver returned %lx\n", Irp, status)); 261 break; 262 } 263 264 case PowerUpDeviceOn: { 265 266 PCDB cdb; 267 268 if(NT_SUCCESS(Irp->IoStatus.Status)) { 269 270 DebugPrint((1, "(%p)\tSending start unit to device\n", Irp)); 271 272 // 273 // Issue the start unit command to the device. 274 // 275 276 context->Srb.Length = sizeof(SCSI_REQUEST_BLOCK); 277 context->Srb.Function = SRB_FUNCTION_EXECUTE_SCSI; 278 279 context->Srb.SrbStatus = context->Srb.ScsiStatus = 0; 280 context->Srb.DataTransferLength = 0; 281 282 context->Srb.TimeOutValue = START_UNIT_TIMEOUT; 283 284 context->Srb.SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER | 285 SRB_FLAGS_DISABLE_AUTOSENSE | 286 SRB_FLAGS_DISABLE_SYNCH_TRANSFER | 287 SRB_FLAGS_NO_QUEUE_FREEZE; 288 289 if(context->Options.LockQueue) { 290 SET_FLAG(context->Srb.SrbFlags, SRB_FLAGS_BYPASS_LOCKED_QUEUE); 291 } 292 293 context->Srb.CdbLength = 6; 294 295 cdb = (PCDB) (context->Srb.Cdb); 296 RtlZeroMemory(cdb, sizeof(CDB)); 297 298 299 cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT; 300 cdb->START_STOP.Start = 1; 301 302 context->PowerChangeState.PowerUp = PowerUpDeviceOn; 303 304 IoSetCompletionRoutine(Irp, 305 ClasspPowerUpCompletion, 306 context, 307 TRUE, 308 TRUE, 309 TRUE); 310 311 nextStack->Parameters.Scsi.Srb = &(context->Srb); 312 nextStack->MajorFunction = IRP_MJ_SCSI; 313 314 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 315 316 DebugPrint((2, "(%p)\tIoCallDriver returned %lx\n", Irp, status)); 317 318 } else { 319 320 // 321 // we're done. 322 // 323 324 context->FinalStatus = Irp->IoStatus.Status; 325 goto ClasspPowerUpCompletionFailure; 326 } 327 328 break; 329 } 330 331 case PowerUpDeviceStarted: { // 3 332 333 // 334 // First deal with an error if one occurred. 335 // 336 337 if(SRB_STATUS(context->Srb.SrbStatus) != SRB_STATUS_SUCCESS) { 338 339 BOOLEAN retry; 340 341 DebugPrint((1, "%p\tError occured when issuing START_UNIT " 342 "command to device. Srb %p, Status %x\n", 343 Irp, 344 &context->Srb, 345 context->Srb.SrbStatus)); 346 347 ASSERT(!(TEST_FLAG(context->Srb.SrbStatus, 348 SRB_STATUS_QUEUE_FROZEN))); 349 ASSERT(context->Srb.Function == SRB_FUNCTION_EXECUTE_SCSI); 350 351 context->RetryInterval = 0; 352 353 retry = ClassInterpretSenseInfo( 354 commonExtension->DeviceObject, 355 &context->Srb, 356 IRP_MJ_SCSI, 357 IRP_MJ_POWER, 358 MAXIMUM_RETRIES - context->RetryCount, 359 &status, 360 &context->RetryInterval); 361 362 if ((retry != FALSE) && (context->RetryCount-- != 0)) { 363 364 DebugPrint((1, "(%p)\tRetrying failed request\n", Irp)); 365 366 // 367 // Decrement the state so we come back through here the 368 // next time. 369 // 370 371 context->PowerChangeState.PowerUp--; 372 373 RetryPowerRequest(commonExtension->DeviceObject, 374 Irp, 375 context); 376 377 break; 378 379 } 380 381 // reset retries 382 context->RetryCount = MAXIMUM_RETRIES; 383 384 } 385 386 ClasspPowerUpCompletionFailure: 387 388 DebugPrint((1, "(%p)\tPreviously spun device up\n", Irp)); 389 390 if (context->QueueLocked) { 391 DebugPrint((1, "(%p)\tUnlocking queue\n", Irp)); 392 393 context->Srb.Function = SRB_FUNCTION_UNLOCK_QUEUE; 394 context->Srb.SrbFlags = SRB_FLAGS_BYPASS_LOCKED_QUEUE; 395 context->Srb.SrbStatus = context->Srb.ScsiStatus = 0; 396 context->Srb.DataTransferLength = 0; 397 398 nextStack->Parameters.Scsi.Srb = &(context->Srb); 399 nextStack->MajorFunction = IRP_MJ_SCSI; 400 401 context->PowerChangeState.PowerUp = PowerUpDeviceStarted; 402 403 IoSetCompletionRoutine(Irp, 404 ClasspPowerUpCompletion, 405 context, 406 TRUE, 407 TRUE, 408 TRUE); 409 410 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 411 DebugPrint((1, "(%p)\tIoCallDriver returned %lx\n", 412 Irp, status)); 413 break; 414 } 415 416 // Fall-through to next case... 417 418 } 419 420 case PowerUpDeviceUnlocked: { 421 422 // 423 // This is the end of the dance. Free the srb and complete the 424 // request finally. We're ignoring possible intermediate 425 // error conditions .... 426 // 427 428 if (context->QueueLocked) { 429 DebugPrint((1, "(%p)\tPreviously unlocked queue\n", Irp)); 430 ASSERT(NT_SUCCESS(Irp->IoStatus.Status)); 431 ASSERT(context->Srb.SrbStatus == SRB_STATUS_SUCCESS); 432 } else { 433 DebugPrint((1, "(%p)\tFall-through (queue not locked)\n", Irp)); 434 } 435 436 DebugPrint((1, "(%p)\tFreeing srb and completing\n", Irp)); 437 context->InUse = FALSE; 438 439 status = context->FinalStatus; 440 Irp->IoStatus.Status = status; 441 442 context = NULL; 443 444 // 445 // Set the new power state 446 // 447 448 if(NT_SUCCESS(status)) { 449 fdoExtension->DevicePowerState = 450 currentStack->Parameters.Power.State.DeviceState; 451 } 452 453 // 454 // Indicate to Po that we've been successfully powered up so 455 // it can do it's notification stuff. 456 // 457 458 PoSetPowerState(DeviceObject, 459 currentStack->Parameters.Power.Type, 460 currentStack->Parameters.Power.State); 461 462 DebugPrint((1, "(%p)\tStarting next power irp\n", Irp)); 463 ClassReleaseRemoveLock(DeviceObject, Irp); 464 PoStartNextPowerIrp(Irp); 465 466 return status; 467 } 468 469 case PowerUpDeviceInitial: { 470 NT_ASSERT(context->PowerChangeState.PowerUp != PowerUpDeviceInitial); 471 break; 472 } 473 } 474 475 return STATUS_MORE_PROCESSING_REQUIRED; 476 } // end ClasspPowerUpCompletion() 477 478 /*++//////////////////////////////////////////////////////////////////////////// 479 480 ClasspPowerDownCompletion() 481 482 Routine Description: 483 484 This routine is used for intermediate completion of a power up request. 485 PowerUp requires four requests to be sent to the lower driver in sequence. 486 487 * The queue is "power locked" to ensure that the class driver power-up 488 work can be done before request processing resumes. 489 490 * The power irp is sent down the stack for any filter drivers and the 491 port driver to return power and resume command processing for the 492 device. Since the queue is locked, no queued irps will be sent 493 immediately. 494 495 * A start unit command is issued to the device with appropriate flags 496 to override the "power locked" queue. 497 498 * The queue is "power unlocked" to start processing requests again. 499 500 This routine uses the function in the srb which just completed to determine 501 which state it is in. 502 503 Arguments: 504 505 DeviceObject - the device object being powered up 506 507 Irp - the IO_REQUEST_PACKET containing the power request 508 509 Srb - the SRB used to perform port/class operations. 510 511 Return Value: 512 513 STATUS_MORE_PROCESSING_REQUIRED or 514 STATUS_SUCCESS 515 516 --*/ 517 NTSTATUS 518 NTAPI 519 ClasspPowerDownCompletion( 520 IN PDEVICE_OBJECT DeviceObject, 521 IN PIRP Irp, 522 IN PVOID CompletionContext 523 ) 524 { 525 PCLASS_POWER_CONTEXT context = CompletionContext; 526 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; 527 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 528 529 PIO_STACK_LOCATION currentStack = IoGetCurrentIrpStackLocation(Irp); 530 PIO_STACK_LOCATION nextStack = IoGetNextIrpStackLocation(Irp); 531 532 NTSTATUS status = STATUS_MORE_PROCESSING_REQUIRED; 533 534 DebugPrint((1, "ClasspPowerDownCompletion: Device Object %p, " 535 "Irp %p, Context %p\n", 536 DeviceObject, Irp, context)); 537 538 ASSERT(!TEST_FLAG(context->Srb.SrbFlags, SRB_FLAGS_FREE_SENSE_BUFFER)); 539 ASSERT(!TEST_FLAG(context->Srb.SrbFlags, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE)); 540 ASSERT(context->Options.PowerDown == TRUE); 541 ASSERT(context->Options.HandleSpinDown); 542 543 if(Irp->PendingReturned) { 544 IoMarkIrpPending(Irp); 545 } 546 547 context->PowerChangeState.PowerDown2++; 548 549 switch(context->PowerChangeState.PowerDown2) { 550 551 case PowerDownDeviceLocked2: { 552 553 PCDB cdb; 554 555 DebugPrint((1, "(%p)\tPreviously sent power lock\n", Irp)); 556 557 if ((context->Options.LockQueue != FALSE) && 558 (!NT_SUCCESS(Irp->IoStatus.Status))) { 559 560 DebugPrint((1, "(%p)\tIrp status was %lx\n", 561 Irp, 562 Irp->IoStatus.Status)); 563 DebugPrint((1, "(%p)\tSrb status was %lx\n", 564 Irp, 565 context->Srb.SrbStatus)); 566 567 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; 568 569 // 570 // Lock was not successful - throw down the power IRP 571 // by itself and don't try to spin down the drive or unlock 572 // the queue. 573 // 574 575 context->InUse = FALSE; 576 context = NULL; 577 578 // 579 // Set the new power state 580 // 581 582 fdoExtension->DevicePowerState = 583 currentStack->Parameters.Power.State.DeviceState; 584 585 // 586 // Indicate to Po that we've been successfully powered down 587 // so it can do it's notification stuff. 588 // 589 590 IoCopyCurrentIrpStackLocationToNext(Irp); 591 IoSetCompletionRoutine(Irp, 592 ClasspStartNextPowerIrpCompletion, 593 NULL, 594 TRUE, 595 TRUE, 596 TRUE); 597 598 PoSetPowerState(DeviceObject, 599 currentStack->Parameters.Power.Type, 600 currentStack->Parameters.Power.State); 601 602 fdoExtension->PowerDownInProgress = FALSE; 603 604 PoCallDriver(commonExtension->LowerDeviceObject, Irp); 605 606 ClassReleaseRemoveLock(commonExtension->DeviceObject, 607 Irp); 608 609 return STATUS_MORE_PROCESSING_REQUIRED; 610 611 } else { 612 context->QueueLocked = (UCHAR) context->Options.LockQueue; 613 } 614 615 if (!TEST_FLAG(fdoExtension->PrivateFdoData->HackFlags, 616 FDO_HACK_NO_SYNC_CACHE)) { 617 618 // 619 // send SCSIOP_SYNCHRONIZE_CACHE 620 // 621 622 context->Srb.Length = sizeof(SCSI_REQUEST_BLOCK); 623 context->Srb.Function = SRB_FUNCTION_EXECUTE_SCSI; 624 625 context->Srb.TimeOutValue = fdoExtension->TimeOutValue; 626 627 context->Srb.SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER | 628 SRB_FLAGS_DISABLE_AUTOSENSE | 629 SRB_FLAGS_DISABLE_SYNCH_TRANSFER | 630 SRB_FLAGS_NO_QUEUE_FREEZE | 631 SRB_FLAGS_BYPASS_LOCKED_QUEUE; 632 633 context->Srb.SrbStatus = context->Srb.ScsiStatus = 0; 634 context->Srb.DataTransferLength = 0; 635 636 context->Srb.CdbLength = 10; 637 638 cdb = (PCDB) context->Srb.Cdb; 639 640 RtlZeroMemory(cdb, sizeof(CDB)); 641 cdb->SYNCHRONIZE_CACHE10.OperationCode = SCSIOP_SYNCHRONIZE_CACHE; 642 643 IoSetCompletionRoutine(Irp, 644 ClasspPowerDownCompletion, 645 context, 646 TRUE, 647 TRUE, 648 TRUE); 649 650 nextStack->Parameters.Scsi.Srb = &(context->Srb); 651 nextStack->MajorFunction = IRP_MJ_SCSI; 652 653 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 654 655 DebugPrint((1, "(%p)\tIoCallDriver returned %lx\n", Irp, status)); 656 break; 657 658 } else { 659 660 DebugPrint((1, "(%p)\tPower Down: not sending SYNCH_CACHE\n", 661 DeviceObject)); 662 context->PowerChangeState.PowerDown2++; 663 context->Srb.SrbStatus = SRB_STATUS_SUCCESS; 664 // and fall through.... 665 } 666 // no break in case the device doesn't like synch_cache commands 667 668 } 669 670 case PowerDownDeviceFlushed2: { 671 672 PCDB cdb; 673 674 DebugPrint((1, "(%p)\tPreviously send SCSIOP_SYNCHRONIZE_CACHE\n", 675 Irp)); 676 677 // 678 // SCSIOP_SYNCHRONIZE_CACHE was sent 679 // 680 681 if(SRB_STATUS(context->Srb.SrbStatus) != SRB_STATUS_SUCCESS) { 682 683 BOOLEAN retry; 684 685 DebugPrint((1, "(%p)\tError occured when issuing " 686 "SYNCHRONIZE_CACHE command to device. " 687 "Srb %p, Status %lx\n", 688 Irp, 689 &context->Srb, 690 context->Srb.SrbStatus)); 691 692 ASSERT(!(TEST_FLAG(context->Srb.SrbStatus, 693 SRB_STATUS_QUEUE_FROZEN))); 694 ASSERT(context->Srb.Function == SRB_FUNCTION_EXECUTE_SCSI); 695 696 context->RetryInterval = 0; 697 retry = ClassInterpretSenseInfo( 698 commonExtension->DeviceObject, 699 &context->Srb, 700 IRP_MJ_SCSI, 701 IRP_MJ_POWER, 702 MAXIMUM_RETRIES - context->RetryCount, 703 &status, 704 &context->RetryInterval); 705 706 if ((retry != FALSE) && (context->RetryCount-- != 0)) { 707 708 DebugPrint((1, "(%p)\tRetrying failed request\n", Irp)); 709 710 // 711 // decrement the state so we come back through here 712 // the next time. 713 // 714 715 context->PowerChangeState.PowerDown2--; 716 RetryPowerRequest(commonExtension->DeviceObject, 717 Irp, 718 context); 719 break; 720 } 721 722 DebugPrint((1, "(%p)\tSYNCHRONIZE_CACHE not retried\n", Irp)); 723 context->RetryCount = MAXIMUM_RETRIES; 724 725 } // end !SRB_STATUS_SUCCESS 726 727 // 728 // note: we are purposefully ignoring any errors. if the drive 729 // doesn't support a synch_cache, then we're up a creek 730 // anyways. 731 // 732 733 DebugPrint((1, "(%p)\tSending stop unit to device\n", Irp)); 734 735 // 736 // Issue the start unit command to the device. 737 // 738 739 context->Srb.Length = sizeof(SCSI_REQUEST_BLOCK); 740 context->Srb.Function = SRB_FUNCTION_EXECUTE_SCSI; 741 742 context->Srb.TimeOutValue = START_UNIT_TIMEOUT; 743 744 context->Srb.SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER | 745 SRB_FLAGS_DISABLE_AUTOSENSE | 746 SRB_FLAGS_DISABLE_SYNCH_TRANSFER | 747 SRB_FLAGS_NO_QUEUE_FREEZE | 748 SRB_FLAGS_BYPASS_LOCKED_QUEUE; 749 750 context->Srb.SrbStatus = context->Srb.ScsiStatus = 0; 751 context->Srb.DataTransferLength = 0; 752 753 context->Srb.CdbLength = 6; 754 755 cdb = (PCDB) context->Srb.Cdb; 756 RtlZeroMemory(cdb, sizeof(CDB)); 757 758 cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT; 759 cdb->START_STOP.Start = 0; 760 cdb->START_STOP.Immediate = 1; 761 762 IoSetCompletionRoutine(Irp, 763 ClasspPowerDownCompletion, 764 context, 765 TRUE, 766 TRUE, 767 TRUE); 768 769 nextStack->Parameters.Scsi.Srb = &(context->Srb); 770 nextStack->MajorFunction = IRP_MJ_SCSI; 771 772 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 773 774 DebugPrint((1, "(%p)\tIoCallDriver returned %lx\n", Irp, status)); 775 break; 776 777 } 778 779 case PowerDownDeviceStopped2: { 780 781 BOOLEAN ignoreError = TRUE; 782 783 // 784 // stop was sent 785 // 786 787 if(SRB_STATUS(context->Srb.SrbStatus) != SRB_STATUS_SUCCESS) { 788 789 BOOLEAN retry; 790 791 DebugPrint((1, "(%p)\tError occured when issuing STOP_UNIT " 792 "command to device. Srb %p, Status %lx\n", 793 Irp, 794 &context->Srb, 795 context->Srb.SrbStatus)); 796 797 ASSERT(!(TEST_FLAG(context->Srb.SrbStatus, 798 SRB_STATUS_QUEUE_FROZEN))); 799 ASSERT(context->Srb.Function == SRB_FUNCTION_EXECUTE_SCSI); 800 801 context->RetryInterval = 0; 802 retry = ClassInterpretSenseInfo( 803 commonExtension->DeviceObject, 804 &context->Srb, 805 IRP_MJ_SCSI, 806 IRP_MJ_POWER, 807 MAXIMUM_RETRIES - context->RetryCount, 808 &status, 809 &context->RetryInterval); 810 811 if ((retry != FALSE) && (context->RetryCount-- != 0)) { 812 813 DebugPrint((1, "(%p)\tRetrying failed request\n", Irp)); 814 815 // 816 // decrement the state so we come back through here 817 // the next time. 818 // 819 820 context->PowerChangeState.PowerDown2--; 821 RetryPowerRequest(commonExtension->DeviceObject, 822 Irp, 823 context); 824 break; 825 } 826 827 DebugPrint((1, "(%p)\tSTOP_UNIT not retried\n", Irp)); 828 context->RetryCount = MAXIMUM_RETRIES; 829 830 } // end !SRB_STATUS_SUCCESS 831 832 833 DebugPrint((1, "(%p)\tPreviously sent stop unit\n", Irp)); 834 835 // 836 // some operations, such as a physical format in progress, 837 // should not be ignored and should fail the power operation. 838 // 839 840 if (!NT_SUCCESS(status)) { 841 842 PSENSE_DATA senseBuffer = context->Srb.SenseInfoBuffer; 843 844 if (TEST_FLAG(context->Srb.SrbStatus, 845 SRB_STATUS_AUTOSENSE_VALID) && 846 ((senseBuffer->SenseKey & 0xf) == SCSI_SENSE_NOT_READY) && 847 (senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY) && 848 (senseBuffer->AdditionalSenseCodeQualifier == SCSI_SENSEQ_FORMAT_IN_PROGRESS) 849 ) { 850 ignoreError = FALSE; 851 context->FinalStatus = STATUS_DEVICE_BUSY; 852 status = context->FinalStatus; 853 } 854 855 } 856 857 if (NT_SUCCESS(status) || ignoreError) { 858 859 // 860 // Issue the actual power request to the lower driver. 861 // 862 863 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; 864 865 IoCopyCurrentIrpStackLocationToNext(Irp); 866 867 IoSetCompletionRoutine(Irp, 868 ClasspPowerDownCompletion, 869 context, 870 TRUE, 871 TRUE, 872 TRUE); 873 874 status = PoCallDriver(commonExtension->LowerDeviceObject, Irp); 875 876 DebugPrint((1, "(%p)\tPoCallDriver returned %lx\n", Irp, status)); 877 break; 878 } 879 880 // else fall through w/o sending the power irp, since the device 881 // is reporting an error that would be "really bad" to power down 882 // during. 883 884 } 885 886 case PowerDownDeviceOff2: { 887 888 // 889 // SpinDown request completed ... whether it succeeded or not is 890 // another matter entirely. 891 // 892 893 DebugPrint((1, "(%p)\tPreviously sent power irp\n", Irp)); 894 895 if (context->QueueLocked) { 896 897 DebugPrint((1, "(%p)\tUnlocking queue\n", Irp)); 898 899 context->Srb.Length = sizeof(SCSI_REQUEST_BLOCK); 900 901 context->Srb.SrbStatus = context->Srb.ScsiStatus = 0; 902 context->Srb.DataTransferLength = 0; 903 904 context->Srb.Function = SRB_FUNCTION_UNLOCK_QUEUE; 905 context->Srb.SrbFlags = SRB_FLAGS_BYPASS_LOCKED_QUEUE; 906 nextStack->Parameters.Scsi.Srb = &(context->Srb); 907 nextStack->MajorFunction = IRP_MJ_SCSI; 908 909 IoSetCompletionRoutine(Irp, 910 ClasspPowerDownCompletion, 911 context, 912 TRUE, 913 TRUE, 914 TRUE); 915 916 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 917 DebugPrint((1, "(%p)\tIoCallDriver returned %lx\n", 918 Irp, 919 status)); 920 break; 921 } 922 923 } 924 925 case PowerDownDeviceUnlocked2: { 926 927 // 928 // This is the end of the dance. Free the srb and complete the 929 // request finally. We're ignoring possible intermediate 930 // error conditions .... 931 // 932 933 if (context->QueueLocked == FALSE) { 934 DebugPrint((1, "(%p)\tFall through (queue not locked)\n", Irp)); 935 } else { 936 DebugPrint((1, "(%p)\tPreviously unlocked queue\n", Irp)); 937 ASSERT(NT_SUCCESS(Irp->IoStatus.Status)); 938 ASSERT(context->Srb.SrbStatus == SRB_STATUS_SUCCESS); 939 } 940 941 DebugPrint((1, "(%p)\tFreeing srb and completing\n", Irp)); 942 context->InUse = FALSE; 943 status = context->FinalStatus; // allow failure to propagate 944 context = NULL; 945 946 if(Irp->PendingReturned) { 947 IoMarkIrpPending(Irp); 948 } 949 950 Irp->IoStatus.Status = status; 951 Irp->IoStatus.Information = 0; 952 953 if (NT_SUCCESS(status)) { 954 955 // 956 // Set the new power state 957 // 958 959 fdoExtension->DevicePowerState = 960 currentStack->Parameters.Power.State.DeviceState; 961 962 } 963 964 965 DebugPrint((1, "(%p)\tStarting next power irp\n", Irp)); 966 967 ClassReleaseRemoveLock(DeviceObject, Irp); 968 PoStartNextPowerIrp(Irp); 969 fdoExtension->PowerDownInProgress = FALSE; 970 971 return status; 972 } 973 974 case PowerDownDeviceInitial2: { 975 NT_ASSERT(context->PowerChangeState.PowerDown2 != PowerDownDeviceInitial2); 976 break; 977 } 978 } 979 980 return STATUS_MORE_PROCESSING_REQUIRED; 981 } // end ClasspPowerDownCompletion() 982 983 /*++//////////////////////////////////////////////////////////////////////////// 984 985 ClasspPowerHandler() 986 987 Routine Description: 988 989 This routine reduces the number of useless spinups and spindown requests 990 sent to a given device by ignoring transitions to power states we are 991 currently in. 992 993 ISSUE-2000/02/20-henrygab - by ignoring spin-up requests, we may be 994 allowing the drive 995 996 Arguments: 997 998 DeviceObject - the device object which is transitioning power states 999 Irp - the power irp 1000 Options - a set of flags indicating what the device handles 1001 1002 Return Value: 1003 1004 --*/ 1005 NTSTATUS 1006 NTAPI 1007 ClasspPowerHandler( 1008 IN PDEVICE_OBJECT DeviceObject, 1009 IN PIRP Irp, 1010 IN CLASS_POWER_OPTIONS Options // ISSUE-2000/02/20-henrygab - pass pointer, not whole struct 1011 ) 1012 { 1013 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 1014 PDEVICE_OBJECT lowerDevice = commonExtension->LowerDeviceObject; 1015 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); 1016 PIO_STACK_LOCATION nextIrpStack; 1017 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; 1018 PCLASS_POWER_CONTEXT context; 1019 1020 if (!commonExtension->IsFdo) { 1021 1022 // 1023 // certain assumptions are made here, 1024 // particularly: having the fdoExtension 1025 // 1026 1027 DebugPrint((0, "ClasspPowerHandler: Called for PDO %p???\n", 1028 DeviceObject)); 1029 ASSERT(!"PDO using ClasspPowerHandler"); 1030 return STATUS_NOT_SUPPORTED; 1031 } 1032 1033 DebugPrint((1, "ClasspPowerHandler: Power irp %p to %s %p\n", 1034 Irp, (commonExtension->IsFdo ? "fdo" : "pdo"), DeviceObject)); 1035 1036 switch(irpStack->MinorFunction) { 1037 1038 case IRP_MN_SET_POWER: { 1039 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData; 1040 1041 DebugPrint((1, "(%p)\tIRP_MN_SET_POWER\n", Irp)); 1042 1043 DebugPrint((1, "(%p)\tSetting %s state to %d\n", 1044 Irp, 1045 (irpStack->Parameters.Power.Type == SystemPowerState ? 1046 "System" : "Device"), 1047 irpStack->Parameters.Power.State.SystemState)); 1048 1049 switch (irpStack->Parameters.Power.ShutdownType){ 1050 1051 case PowerActionSleep: 1052 case PowerActionHibernate: 1053 if (fdoData->HotplugInfo.MediaRemovable || fdoData->HotplugInfo.MediaHotplug){ 1054 /* 1055 * We are suspending and this drive is either hot-pluggable 1056 * or contains removeable media. 1057 * Set the media dirty bit, since the media may change while 1058 * we are suspended. 1059 */ 1060 SET_FLAG(DeviceObject->Flags, DO_VERIFY_VOLUME); 1061 } 1062 break; 1063 default: 1064 break; 1065 } 1066 1067 break; 1068 } 1069 1070 default: { 1071 1072 DebugPrint((1, "(%p)\tIrp minor code = %#x\n", 1073 Irp, irpStack->MinorFunction)); 1074 break; 1075 } 1076 } 1077 1078 if (irpStack->Parameters.Power.Type != DevicePowerState || 1079 irpStack->MinorFunction != IRP_MN_SET_POWER) { 1080 1081 DebugPrint((1, "(%p)\tSending to lower device\n", Irp)); 1082 1083 goto ClasspPowerHandlerCleanup; 1084 1085 } 1086 1087 nextIrpStack = IoGetNextIrpStackLocation(Irp); 1088 1089 // 1090 // already in exact same state, don't work to transition to it. 1091 // 1092 1093 if(irpStack->Parameters.Power.State.DeviceState == 1094 fdoExtension->DevicePowerState) { 1095 1096 DebugPrint((1, "(%p)\tAlready in device state %x\n", 1097 Irp, fdoExtension->DevicePowerState)); 1098 goto ClasspPowerHandlerCleanup; 1099 1100 } 1101 1102 // 1103 // or powering down from non-d0 state (device already stopped) 1104 // NOTE -- we're not sure whether this case can exist or not (the 1105 // power system may never send this sort of request) but it's trivial 1106 // to deal with. 1107 // 1108 1109 if ((irpStack->Parameters.Power.State.DeviceState != PowerDeviceD0) && 1110 (fdoExtension->DevicePowerState != PowerDeviceD0)) { 1111 DebugPrint((1, "(%p)\tAlready powered down to %x???\n", 1112 Irp, fdoExtension->DevicePowerState)); 1113 fdoExtension->DevicePowerState = 1114 irpStack->Parameters.Power.State.DeviceState; 1115 goto ClasspPowerHandlerCleanup; 1116 } 1117 1118 // 1119 // or going into a hibernation state when we're in the hibernation path. 1120 // If the device is spinning then we should leave it spinning - if it's not 1121 // then the dump driver will start it up for us. 1122 // 1123 1124 if((irpStack->Parameters.Power.State.DeviceState == PowerDeviceD3) && 1125 (irpStack->Parameters.Power.ShutdownType == PowerActionHibernate) && 1126 (commonExtension->HibernationPathCount != 0)) { 1127 1128 DebugPrint((1, "(%p)\tdoing nothing for hibernation request for " 1129 "state %x???\n", 1130 Irp, fdoExtension->DevicePowerState)); 1131 fdoExtension->DevicePowerState = 1132 irpStack->Parameters.Power.State.DeviceState; 1133 goto ClasspPowerHandlerCleanup; 1134 } 1135 // 1136 // or when not handling powering up and are powering up 1137 // 1138 1139 if ((!Options.HandleSpinUp) && 1140 (irpStack->Parameters.Power.State.DeviceState == PowerDeviceD0)) { 1141 1142 DebugPrint((2, "(%p)\tNot handling spinup to state %x\n", 1143 Irp, fdoExtension->DevicePowerState)); 1144 fdoExtension->DevicePowerState = 1145 irpStack->Parameters.Power.State.DeviceState; 1146 goto ClasspPowerHandlerCleanup; 1147 1148 } 1149 1150 // 1151 // or when not handling powering down and are powering down 1152 // 1153 1154 if ((!Options.HandleSpinDown) && 1155 (irpStack->Parameters.Power.State.DeviceState != PowerDeviceD0)) { 1156 1157 DebugPrint((2, "(%p)\tNot handling spindown to state %x\n", 1158 Irp, fdoExtension->DevicePowerState)); 1159 fdoExtension->DevicePowerState = 1160 irpStack->Parameters.Power.State.DeviceState; 1161 goto ClasspPowerHandlerCleanup; 1162 1163 } 1164 1165 context = &(fdoExtension->PowerContext); 1166 1167 #if DBG 1168 // 1169 // Mark the context as in use. We should be synchronizing this but 1170 // since it's just for debugging purposes we don't worry too much. 1171 // 1172 1173 ASSERT(context->InUse == FALSE); 1174 #endif 1175 1176 RtlZeroMemory(context, sizeof(CLASS_POWER_CONTEXT)); 1177 context->InUse = TRUE; 1178 1179 nextIrpStack->Parameters.Scsi.Srb = &(context->Srb); 1180 nextIrpStack->MajorFunction = IRP_MJ_SCSI; 1181 1182 context->FinalStatus = STATUS_SUCCESS; 1183 1184 context->Srb.Length = sizeof(SCSI_REQUEST_BLOCK); 1185 context->Srb.OriginalRequest = Irp; 1186 context->Srb.SrbFlags |= SRB_FLAGS_BYPASS_LOCKED_QUEUE 1187 | SRB_FLAGS_NO_QUEUE_FREEZE; 1188 context->Srb.Function = SRB_FUNCTION_LOCK_QUEUE; 1189 1190 context->Srb.SenseInfoBuffer = 1191 commonExtension->PartitionZeroExtension->SenseData; 1192 context->Srb.SenseInfoBufferLength = SENSE_BUFFER_SIZE; 1193 context->RetryCount = MAXIMUM_RETRIES; 1194 1195 context->Options = Options; 1196 context->DeviceObject = DeviceObject; 1197 context->Irp = Irp; 1198 1199 if(irpStack->Parameters.Power.State.DeviceState == PowerDeviceD0) { 1200 1201 ASSERT(Options.HandleSpinUp); 1202 1203 DebugPrint((2, "(%p)\tpower up - locking queue\n", Irp)); 1204 1205 // 1206 // We need to issue a queue lock request so that we 1207 // can spin the drive back up after the power is restored 1208 // but before any requests are processed. 1209 // 1210 1211 context->Options.PowerDown = FALSE; 1212 context->PowerChangeState.PowerUp = PowerUpDeviceInitial; 1213 context->CompletionRoutine = ClasspPowerUpCompletion; 1214 1215 } else { 1216 1217 ASSERT(Options.HandleSpinDown); 1218 1219 fdoExtension->PowerDownInProgress = TRUE; 1220 1221 DebugPrint((2, "(%p)\tPowering down - locking queue\n", Irp)); 1222 1223 PoSetPowerState(DeviceObject, 1224 irpStack->Parameters.Power.Type, 1225 irpStack->Parameters.Power.State); 1226 1227 context->Options.PowerDown = TRUE; 1228 context->PowerChangeState.PowerDown2 = PowerDownDeviceInitial2; 1229 context->CompletionRoutine = ClasspPowerDownCompletion; 1230 1231 } 1232 1233 // 1234 // we are not dealing with port-allocated sense in these routines. 1235 // 1236 1237 ASSERT(!TEST_FLAG(context->Srb.SrbFlags, SRB_FLAGS_FREE_SENSE_BUFFER)); 1238 ASSERT(!TEST_FLAG(context->Srb.SrbFlags, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE)); 1239 1240 // 1241 // we are always returning STATUS_PENDING, so we need to always 1242 // set the irp as pending. 1243 // 1244 1245 IoMarkIrpPending(Irp); 1246 1247 if(Options.LockQueue) { 1248 1249 // 1250 // Send the lock irp down. 1251 // 1252 1253 IoSetCompletionRoutine(Irp, 1254 context->CompletionRoutine, 1255 context, 1256 TRUE, 1257 TRUE, 1258 TRUE); 1259 1260 IoCallDriver(lowerDevice, Irp); 1261 1262 } else { 1263 1264 // 1265 // Call the completion routine directly. It won't care what the 1266 // status of the "lock" was - it will just go and do the next 1267 // step of the operation. 1268 // 1269 1270 context->CompletionRoutine(DeviceObject, Irp, context); 1271 } 1272 1273 return STATUS_PENDING; 1274 1275 ClasspPowerHandlerCleanup: 1276 1277 ClassReleaseRemoveLock(DeviceObject, Irp); 1278 1279 DebugPrint((1, "(%p)\tStarting next power irp\n", Irp)); 1280 IoCopyCurrentIrpStackLocationToNext(Irp); 1281 IoSetCompletionRoutine(Irp, 1282 ClasspStartNextPowerIrpCompletion, 1283 NULL, 1284 TRUE, 1285 TRUE, 1286 TRUE); 1287 return PoCallDriver(lowerDevice, Irp); 1288 } // end ClasspPowerHandler() 1289 1290 /*++//////////////////////////////////////////////////////////////////////////// 1291 1292 ClassMinimalPowerHandler() 1293 1294 Routine Description: 1295 1296 This routine is the minimum power handler for a storage driver. It does 1297 the least amount of work possible. 1298 1299 --*/ 1300 NTSTATUS 1301 NTAPI 1302 ClassMinimalPowerHandler( 1303 IN PDEVICE_OBJECT DeviceObject, 1304 IN PIRP Irp 1305 ) 1306 { 1307 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 1308 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); 1309 NTSTATUS status; 1310 1311 ClassReleaseRemoveLock(DeviceObject, Irp); 1312 PoStartNextPowerIrp(Irp); 1313 1314 if(commonExtension->IsFdo) { 1315 1316 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) { 1317 1318 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = 1319 DeviceObject->DeviceExtension; 1320 1321 // 1322 // Check if the system is going to hibernate or standby. 1323 // 1324 if (irpStack->MinorFunction == IRP_MN_SET_POWER){ 1325 PVPB vpb; 1326 1327 switch (irpStack->Parameters.Power.ShutdownType){ 1328 1329 case PowerActionSleep: 1330 case PowerActionHibernate: 1331 // 1332 // If the volume is mounted, set the verify bit so that 1333 // the filesystem will be forced re-read the media 1334 // after coming out of hibernation or standby. 1335 // 1336 vpb = ClassGetVpb(fdoExtension->DeviceObject); 1337 if (vpb && (vpb->Flags & VPB_MOUNTED)){ 1338 SET_FLAG(fdoExtension->DeviceObject->Flags, DO_VERIFY_VOLUME); 1339 } 1340 break; 1341 default: 1342 break; 1343 } 1344 } 1345 } 1346 1347 IoCopyCurrentIrpStackLocationToNext(Irp); 1348 return PoCallDriver(commonExtension->LowerDeviceObject, Irp); 1349 1350 } else { 1351 1352 if (irpStack->MinorFunction != IRP_MN_SET_POWER && 1353 irpStack->MinorFunction != IRP_MN_QUERY_POWER) { 1354 1355 NOTHING; 1356 1357 } else { 1358 1359 Irp->IoStatus.Status = STATUS_SUCCESS; 1360 Irp->IoStatus.Information = 0; 1361 1362 } 1363 status = Irp->IoStatus.Status; 1364 1365 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 1366 return status; 1367 } 1368 } // end ClassMinimalPowerHandler() 1369 1370 /*++//////////////////////////////////////////////////////////////////////////// 1371 1372 ClassSpinDownPowerHandler() 1373 1374 Routine Description: 1375 1376 This routine is a callback for disks and other things which require both 1377 a start and a stop to be sent to the device. (actually the starts are 1378 almost always optional, since most device power themselves on to process 1379 commands, but i digress). 1380 1381 Determines proper use of spinup, spindown, and queue locking based upon 1382 ScanForSpecialFlags in the FdoExtension. This is the most common power 1383 handler passed into classpnp.sys 1384 1385 Arguments: 1386 1387 DeviceObject - Supplies the functional device object 1388 1389 Irp - Supplies the request to be retried. 1390 1391 Return Value: 1392 1393 None 1394 1395 --*/ 1396 NTSTATUS 1397 NTAPI 1398 ClassSpinDownPowerHandler( 1399 IN PDEVICE_OBJECT DeviceObject, 1400 IN PIRP Irp 1401 ) 1402 { 1403 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension; 1404 CLASS_POWER_OPTIONS options; 1405 1406 fdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 1407 1408 // 1409 // this will set all options to FALSE 1410 // 1411 1412 RtlZeroMemory(&options, sizeof(CLASS_POWER_OPTIONS)); 1413 1414 // 1415 // check the flags to see what options we need to worry about 1416 // 1417 1418 if (!TEST_FLAG(fdoExtension->ScanForSpecialFlags, 1419 CLASS_SPECIAL_DISABLE_SPIN_DOWN)) { 1420 options.HandleSpinDown = TRUE; 1421 } 1422 1423 if (!TEST_FLAG(fdoExtension->ScanForSpecialFlags, 1424 CLASS_SPECIAL_DISABLE_SPIN_UP)) { 1425 options.HandleSpinUp = TRUE; 1426 } 1427 1428 if (!TEST_FLAG(fdoExtension->ScanForSpecialFlags, 1429 CLASS_SPECIAL_NO_QUEUE_LOCK)) { 1430 options.LockQueue = TRUE; 1431 } 1432 1433 DebugPrint((3, "ClasspPowerHandler: Devobj %p\n" 1434 "\t%shandling spin down\n" 1435 "\t%shandling spin up\n" 1436 "\t%slocking queue\n", 1437 DeviceObject, 1438 (options.HandleSpinDown ? "" : "not "), 1439 (options.HandleSpinUp ? "" : "not "), 1440 (options.LockQueue ? "" : "not ") 1441 )); 1442 1443 // 1444 // do all the dirty work 1445 // 1446 1447 return ClasspPowerHandler(DeviceObject, Irp, options); 1448 } // end ClassSpinDownPowerHandler() 1449 1450 /*++//////////////////////////////////////////////////////////////////////////// 1451 1452 ClassStopUnitPowerHandler() 1453 1454 Routine Description: 1455 1456 This routine is an outdated call. To achieve equivalent functionality, 1457 the driver should set the following flags in ScanForSpecialFlags in the 1458 FdoExtension: 1459 1460 CLASS_SPECIAL_DISABLE_SPIN_UP 1461 CLASS_SPECIAL_NO_QUEUE_LOCK 1462 1463 --*/ 1464 NTSTATUS 1465 NTAPI 1466 ClassStopUnitPowerHandler( 1467 IN PDEVICE_OBJECT DeviceObject, 1468 IN PIRP Irp 1469 ) 1470 { 1471 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension; 1472 1473 DebugPrint((0, "ClassStopUnitPowerHandler - Devobj %p using outdated call\n" 1474 "Drivers should set the following flags in ScanForSpecialFlags " 1475 " in the FDO extension:\n" 1476 "\tCLASS_SPECIAL_DISABLE_SPIN_UP\n" 1477 "\tCLASS_SPECIAL_NO_QUEUE_LOCK\n" 1478 "This will provide equivalent functionality if the power " 1479 "routine is then set to ClassSpinDownPowerHandler\n\n", 1480 DeviceObject)); 1481 1482 fdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 1483 1484 SET_FLAG(fdoExtension->ScanForSpecialFlags, 1485 CLASS_SPECIAL_DISABLE_SPIN_UP); 1486 SET_FLAG(fdoExtension->ScanForSpecialFlags, 1487 CLASS_SPECIAL_NO_QUEUE_LOCK); 1488 1489 return ClassSpinDownPowerHandler(DeviceObject, Irp); 1490 } // end ClassStopUnitPowerHandler() 1491 1492 /*++//////////////////////////////////////////////////////////////////////////// 1493 1494 RetryPowerRequest() 1495 1496 Routine Description: 1497 1498 This routine reinitializes the necessary fields, and sends the request 1499 to the lower driver. 1500 1501 Arguments: 1502 1503 DeviceObject - Supplies the device object associated with this request. 1504 1505 Irp - Supplies the request to be retried. 1506 1507 Context - Supplies a pointer to the power up context for this request. 1508 1509 Return Value: 1510 1511 None 1512 1513 --*/ 1514 VOID 1515 NTAPI 1516 RetryPowerRequest( 1517 PDEVICE_OBJECT DeviceObject, 1518 PIRP Irp, 1519 PCLASS_POWER_CONTEXT Context 1520 ) 1521 { 1522 PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp); 1523 PSCSI_REQUEST_BLOCK srb = &(Context->Srb); 1524 LARGE_INTEGER dueTime; 1525 1526 DebugPrint((1, "(%p)\tDelaying retry by queueing DPC\n", Irp)); 1527 1528 ASSERT(Context->Irp == Irp); 1529 ASSERT(Context->DeviceObject == DeviceObject); 1530 ASSERT(!TEST_FLAG(Context->Srb.SrbFlags, SRB_FLAGS_FREE_SENSE_BUFFER)); 1531 ASSERT(!TEST_FLAG(Context->Srb.SrbFlags, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE)); 1532 1533 // 1534 // reset the retry interval 1535 // 1536 1537 Context->RetryInterval = 0; 1538 1539 // 1540 // Reset byte count of transfer in SRB Extension. 1541 // 1542 1543 srb->DataTransferLength = 0; 1544 1545 // 1546 // Zero SRB statuses. 1547 // 1548 1549 srb->SrbStatus = srb->ScsiStatus = 0; 1550 1551 // 1552 // Set up major SCSI function. 1553 // 1554 1555 nextIrpStack->MajorFunction = IRP_MJ_SCSI; 1556 1557 // 1558 // Save SRB address in next stack for port driver. 1559 // 1560 1561 nextIrpStack->Parameters.Scsi.Srb = srb; 1562 1563 // 1564 // Set the completion routine up again. 1565 // 1566 1567 IoSetCompletionRoutine(Irp, Context->CompletionRoutine, Context, 1568 TRUE, TRUE, TRUE); 1569 1570 1571 if (Context->RetryInterval == 0) { 1572 1573 DebugPrint((2, "(%p)\tDelaying minimum time (.2 sec)\n", Irp)); 1574 dueTime.QuadPart = (LONGLONG)1000000 * 2; 1575 1576 } else { 1577 1578 DebugPrint((2, "(%p)\tDelaying %x seconds\n", 1579 Irp, Context->RetryInterval)); 1580 dueTime.QuadPart = (LONGLONG)1000000 * 10 * Context->RetryInterval; 1581 1582 } 1583 1584 ClassRetryRequest(DeviceObject, Irp, dueTime); 1585 1586 return; 1587 1588 } // end RetryRequest() 1589 1590 /*++//////////////////////////////////////////////////////////////////////////// 1591 1592 ClasspStartNextPowerIrpCompletion() 1593 1594 Routine Description: 1595 1596 This routine guarantees that the next power irp (power up or down) is not 1597 sent until the previous one has fully completed. 1598 1599 --*/ 1600 NTSTATUS 1601 NTAPI 1602 ClasspStartNextPowerIrpCompletion( 1603 IN PDEVICE_OBJECT DeviceObject, 1604 IN PIRP Irp, 1605 IN PVOID Context 1606 ) 1607 { 1608 if(Irp->PendingReturned) { 1609 IoMarkIrpPending(Irp); 1610 } 1611 1612 PoStartNextPowerIrp(Irp); 1613 return STATUS_SUCCESS; 1614 } // end ClasspStartNextPowerIrpCompletion() 1615