3 Copyright (C) Microsoft Corporation, 1991 - 1999
11 SCSI class driver routines
26 #define CLASS_TAG_POWER 'WLcS'
30 IN PDEVICE_OBJECT DeviceObject
,
32 IN CLASS_POWER_OPTIONS Options
36 ClasspPowerDownCompletion(
37 IN PDEVICE_OBJECT DeviceObject
,
39 IN PCLASS_POWER_CONTEXT Context
43 ClasspPowerUpCompletion(
44 IN PDEVICE_OBJECT DeviceObject
,
46 IN PCLASS_POWER_CONTEXT Context
51 PDEVICE_OBJECT DeviceObject
,
53 PCLASS_POWER_CONTEXT Context
57 ClasspStartNextPowerIrpCompletion(
58 IN PDEVICE_OBJECT DeviceObject
,
64 /*++////////////////////////////////////////////////////////////////////////////
70 This routine acquires the removelock for the irp and then calls the
71 appropriate power callback.
83 IN PDEVICE_OBJECT DeviceObject
,
87 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
89 PCLASS_POWER_DEVICE powerRoutine
= NULL
;
92 // NOTE: This code may be called at PASSIVE or DISPATCH, depending
93 // upon the device object it is being called for.
94 // don't do anything that would break under either circumstance.
99 isRemoved
= ClassAcquireRemoveLock(DeviceObject
, Irp
);
102 ClassReleaseRemoveLock(DeviceObject
, Irp
);
103 Irp
->IoStatus
.Status
= STATUS_DEVICE_DOES_NOT_EXIST
;
104 PoStartNextPowerIrp(Irp
);
105 ClassCompleteRequest(DeviceObject
, Irp
, IO_NO_INCREMENT
);
106 return STATUS_DEVICE_DOES_NOT_EXIST
;
109 return commonExtension
->DevInfo
->ClassPowerDevice(DeviceObject
, Irp
);
110 } // end ClassDispatchPower()
112 /*++////////////////////////////////////////////////////////////////////////////
114 ClasspPowerUpCompletion()
118 This routine is used for intermediate completion of a power up request.
119 PowerUp requires four requests to be sent to the lower driver in sequence.
121 * The queue is "power locked" to ensure that the class driver power-up
122 work can be done before request processing resumes.
124 * The power irp is sent down the stack for any filter drivers and the
125 port driver to return power and resume command processing for the
126 device. Since the queue is locked, no queued irps will be sent
129 * A start unit command is issued to the device with appropriate flags
130 to override the "power locked" queue.
132 * The queue is "power unlocked" to start processing requests again.
134 This routine uses the function in the srb which just completed to determine
135 which state it is in.
139 DeviceObject - the device object being powered up
141 Irp - the IO_REQUEST_PACKET containing the power request
143 Srb - the SRB used to perform port/class operations.
147 STATUS_MORE_PROCESSING_REQUIRED or
152 ClasspPowerUpCompletion(
153 IN PDEVICE_OBJECT DeviceObject
,
155 IN PCLASS_POWER_CONTEXT Context
158 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
159 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
161 PIO_STACK_LOCATION currentStack
= IoGetCurrentIrpStackLocation(Irp
);
162 PIO_STACK_LOCATION nextStack
= IoGetNextIrpStackLocation(Irp
);
165 NTSTATUS status
= STATUS_MORE_PROCESSING_REQUIRED
;
167 DebugPrint((1, "ClasspPowerUpCompletion: Device Object %p, Irp %p, "
169 DeviceObject
, Irp
, Context
));
171 ASSERT(!TEST_FLAG(Context
->Srb
.SrbFlags
, SRB_FLAGS_FREE_SENSE_BUFFER
));
172 ASSERT(!TEST_FLAG(Context
->Srb
.SrbFlags
, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE
));
173 ASSERT(Context
->Options
.PowerDown
== FALSE
);
174 ASSERT(Context
->Options
.HandleSpinUp
);
176 if(Irp
->PendingReturned
) {
177 IoMarkIrpPending(Irp
);
180 Context
->PowerChangeState
.PowerUp
++;
182 switch(Context
->PowerChangeState
.PowerUp
) {
184 case PowerUpDeviceLocked
: {
186 DebugPrint((1, "(%p)\tPreviously sent power lock\n", Irp
));
189 // Issue the actual power request to the lower driver.
192 IoCopyCurrentIrpStackLocationToNext(Irp
);
195 // If the lock wasn't successful then just bail out on the power
196 // request unless we can ignore failed locks
199 if((Context
->Options
.LockQueue
== TRUE
) &&
200 (!NT_SUCCESS(Irp
->IoStatus
.Status
))) {
202 DebugPrint((1, "(%p)\tIrp status was %lx\n",
203 Irp
, Irp
->IoStatus
.Status
));
204 DebugPrint((1, "(%p)\tSrb status was %lx\n",
205 Irp
, Context
->Srb
.SrbStatus
));
208 // Lock was not successful - throw down the power IRP
209 // by itself and don't try to spin up the drive or unlock
213 Context
->InUse
= FALSE
;
217 // Set the new power state
220 fdoExtension
->DevicePowerState
=
221 currentStack
->Parameters
.Power
.State
.DeviceState
;
223 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
225 IoCopyCurrentIrpStackLocationToNext(Irp
);
227 IoSetCompletionRoutine(Irp
,
228 ClasspStartNextPowerIrpCompletion
,
235 // Indicate to Po that we've been successfully powered up so
236 // it can do it's notification stuff.
239 PoSetPowerState(DeviceObject
,
240 currentStack
->Parameters
.Power
.Type
,
241 currentStack
->Parameters
.Power
.State
);
243 PoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
245 ClassReleaseRemoveLock(commonExtension
->DeviceObject
,
248 return STATUS_MORE_PROCESSING_REQUIRED
;
251 Context
->QueueLocked
= (UCHAR
) Context
->Options
.LockQueue
;
254 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
256 Context
->PowerChangeState
.PowerUp
= PowerUpDeviceLocked
;
258 IoSetCompletionRoutine(Irp
,
259 ClasspPowerUpCompletion
,
265 status
= PoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
267 DebugPrint((2, "(%p)\tPoCallDriver returned %lx\n", Irp
, status
));
271 case PowerUpDeviceOn
: {
275 if(NT_SUCCESS(Irp
->IoStatus
.Status
)) {
277 DebugPrint((1, "(%p)\tSending start unit to device\n", Irp
));
280 // Issue the start unit command to the device.
283 Context
->Srb
.Length
= sizeof(SCSI_REQUEST_BLOCK
);
284 Context
->Srb
.Function
= SRB_FUNCTION_EXECUTE_SCSI
;
286 Context
->Srb
.SrbStatus
= Context
->Srb
.ScsiStatus
= 0;
287 Context
->Srb
.DataTransferLength
= 0;
289 Context
->Srb
.TimeOutValue
= START_UNIT_TIMEOUT
;
291 Context
->Srb
.SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
|
292 SRB_FLAGS_DISABLE_AUTOSENSE
|
293 SRB_FLAGS_DISABLE_SYNCH_TRANSFER
|
294 SRB_FLAGS_NO_QUEUE_FREEZE
;
296 if(Context
->Options
.LockQueue
) {
297 SET_FLAG(Context
->Srb
.SrbFlags
, SRB_FLAGS_BYPASS_LOCKED_QUEUE
);
300 Context
->Srb
.CdbLength
= 6;
302 cdb
= (PCDB
) (Context
->Srb
.Cdb
);
303 RtlZeroMemory(cdb
, sizeof(CDB
));
306 cdb
->START_STOP
.OperationCode
= SCSIOP_START_STOP_UNIT
;
307 cdb
->START_STOP
.Start
= 1;
309 Context
->PowerChangeState
.PowerUp
= PowerUpDeviceOn
;
311 IoSetCompletionRoutine(Irp
,
312 ClasspPowerUpCompletion
,
318 nextStack
->Parameters
.Scsi
.Srb
= &(Context
->Srb
);
319 nextStack
->MajorFunction
= IRP_MJ_SCSI
;
321 status
= IoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
323 DebugPrint((2, "(%p)\tIoCallDriver returned %lx\n", Irp
, status
));
331 Context
->FinalStatus
= Irp
->IoStatus
.Status
;
332 goto ClasspPowerUpCompletionFailure
;
338 case PowerUpDeviceStarted
: { // 3
341 // First deal with an error if one occurred.
344 if(SRB_STATUS(Context
->Srb
.SrbStatus
) != SRB_STATUS_SUCCESS
) {
348 DebugPrint((1, "%p\tError occured when issuing START_UNIT "
349 "command to device. Srb %p, Status %x\n",
352 Context
->Srb
.SrbStatus
));
354 ASSERT(!(TEST_FLAG(Context
->Srb
.SrbStatus
,
355 SRB_STATUS_QUEUE_FROZEN
)));
356 ASSERT(Context
->Srb
.Function
== SRB_FUNCTION_EXECUTE_SCSI
);
358 Context
->RetryInterval
= 0;
360 retry
= ClassInterpretSenseInfo(
361 commonExtension
->DeviceObject
,
365 MAXIMUM_RETRIES
- Context
->RetryCount
,
367 &Context
->RetryInterval
);
369 if((retry
== TRUE
) && (Context
->RetryCount
-- != 0)) {
371 DebugPrint((1, "(%p)\tRetrying failed request\n", Irp
));
374 // Decrement the state so we come back through here the
378 Context
->PowerChangeState
.PowerUp
--;
380 RetryPowerRequest(commonExtension
->DeviceObject
,
389 Context
->RetryCount
= MAXIMUM_RETRIES
;
393 ClasspPowerUpCompletionFailure
:
395 DebugPrint((1, "(%p)\tPreviously spun device up\n", Irp
));
397 if (Context
->QueueLocked
) {
398 DebugPrint((1, "(%p)\tUnlocking queue\n", Irp
));
400 Context
->Srb
.Function
= SRB_FUNCTION_UNLOCK_QUEUE
;
401 Context
->Srb
.SrbFlags
= SRB_FLAGS_BYPASS_LOCKED_QUEUE
;
402 Context
->Srb
.SrbStatus
= Context
->Srb
.ScsiStatus
= 0;
403 Context
->Srb
.DataTransferLength
= 0;
405 nextStack
->Parameters
.Scsi
.Srb
= &(Context
->Srb
);
406 nextStack
->MajorFunction
= IRP_MJ_SCSI
;
408 Context
->PowerChangeState
.PowerUp
= PowerUpDeviceStarted
;
410 IoSetCompletionRoutine(Irp
,
411 ClasspPowerUpCompletion
,
417 status
= IoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
418 DebugPrint((1, "(%p)\tIoCallDriver returned %lx\n",
423 // Fall-through to next case...
427 case PowerUpDeviceUnlocked
: {
430 // This is the end of the dance. Free the srb and complete the
431 // request finally. We're ignoring possible intermediate
432 // error conditions ....
435 if (Context
->QueueLocked
) {
436 DebugPrint((1, "(%p)\tPreviously unlocked queue\n", Irp
));
437 ASSERT(NT_SUCCESS(Irp
->IoStatus
.Status
));
438 ASSERT(Context
->Srb
.SrbStatus
== SRB_STATUS_SUCCESS
);
440 DebugPrint((1, "(%p)\tFall-through (queue not locked)\n", Irp
));
443 DebugPrint((1, "(%p)\tFreeing srb and completing\n", Irp
));
444 Context
->InUse
= FALSE
;
446 status
= Context
->FinalStatus
;
447 Irp
->IoStatus
.Status
= status
;
452 // Set the new power state
455 if(NT_SUCCESS(status
)) {
456 fdoExtension
->DevicePowerState
=
457 currentStack
->Parameters
.Power
.State
.DeviceState
;
461 // Indicate to Po that we've been successfully powered up so
462 // it can do it's notification stuff.
465 PoSetPowerState(DeviceObject
,
466 currentStack
->Parameters
.Power
.Type
,
467 currentStack
->Parameters
.Power
.State
);
469 DebugPrint((1, "(%p)\tStarting next power irp\n", Irp
));
470 ClassReleaseRemoveLock(DeviceObject
, Irp
);
471 PoStartNextPowerIrp(Irp
);
477 return STATUS_MORE_PROCESSING_REQUIRED
;
478 } // end ClasspPowerUpCompletion()
480 /*++////////////////////////////////////////////////////////////////////////////
482 ClasspPowerDownCompletion()
486 This routine is used for intermediate completion of a power up request.
487 PowerUp requires four requests to be sent to the lower driver in sequence.
489 * The queue is "power locked" to ensure that the class driver power-up
490 work can be done before request processing resumes.
492 * The power irp is sent down the stack for any filter drivers and the
493 port driver to return power and resume command processing for the
494 device. Since the queue is locked, no queued irps will be sent
497 * A start unit command is issued to the device with appropriate flags
498 to override the "power locked" queue.
500 * The queue is "power unlocked" to start processing requests again.
502 This routine uses the function in the srb which just completed to determine
503 which state it is in.
507 DeviceObject - the device object being powered up
509 Irp - the IO_REQUEST_PACKET containing the power request
511 Srb - the SRB used to perform port/class operations.
515 STATUS_MORE_PROCESSING_REQUIRED or
520 ClasspPowerDownCompletion(
521 IN PDEVICE_OBJECT DeviceObject
,
523 IN PCLASS_POWER_CONTEXT Context
526 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
527 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
529 PIO_STACK_LOCATION currentStack
= IoGetCurrentIrpStackLocation(Irp
);
530 PIO_STACK_LOCATION nextStack
= IoGetNextIrpStackLocation(Irp
);
532 NTSTATUS status
= STATUS_MORE_PROCESSING_REQUIRED
;
534 DebugPrint((1, "ClasspPowerDownCompletion: Device Object %p, "
535 "Irp %p, Context %p\n",
536 DeviceObject
, Irp
, Context
));
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
);
543 if(Irp
->PendingReturned
) {
544 IoMarkIrpPending(Irp
);
547 Context
->PowerChangeState
.PowerDown2
++;
549 switch(Context
->PowerChangeState
.PowerDown2
) {
551 case PowerDownDeviceLocked2
: {
555 DebugPrint((1, "(%p)\tPreviously sent power lock\n", Irp
));
557 if((Context
->Options
.LockQueue
== TRUE
) &&
558 (!NT_SUCCESS(Irp
->IoStatus
.Status
))) {
560 DebugPrint((1, "(%p)\tIrp status was %lx\n",
562 Irp
->IoStatus
.Status
));
563 DebugPrint((1, "(%p)\tSrb status was %lx\n",
565 Context
->Srb
.SrbStatus
));
567 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
570 // Lock was not successful - throw down the power IRP
571 // by itself and don't try to spin down the drive or unlock
575 Context
->InUse
= FALSE
;
579 // Set the new power state
582 fdoExtension
->DevicePowerState
=
583 currentStack
->Parameters
.Power
.State
.DeviceState
;
586 // Indicate to Po that we've been successfully powered down
587 // so it can do it's notification stuff.
590 IoCopyCurrentIrpStackLocationToNext(Irp
);
591 IoSetCompletionRoutine(Irp
,
592 ClasspStartNextPowerIrpCompletion
,
598 PoSetPowerState(DeviceObject
,
599 currentStack
->Parameters
.Power
.Type
,
600 currentStack
->Parameters
.Power
.State
);
602 fdoExtension
->PowerDownInProgress
= FALSE
;
604 PoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
606 ClassReleaseRemoveLock(commonExtension
->DeviceObject
,
609 return STATUS_MORE_PROCESSING_REQUIRED
;
612 Context
->QueueLocked
= (UCHAR
) Context
->Options
.LockQueue
;
615 if (!TEST_FLAG(fdoExtension
->PrivateFdoData
->HackFlags
,
616 FDO_HACK_NO_SYNC_CACHE
)) {
619 // send SCSIOP_SYNCHRONIZE_CACHE
622 Context
->Srb
.Length
= sizeof(SCSI_REQUEST_BLOCK
);
623 Context
->Srb
.Function
= SRB_FUNCTION_EXECUTE_SCSI
;
625 Context
->Srb
.TimeOutValue
= fdoExtension
->TimeOutValue
;
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
;
633 Context
->Srb
.SrbStatus
= Context
->Srb
.ScsiStatus
= 0;
634 Context
->Srb
.DataTransferLength
= 0;
636 Context
->Srb
.CdbLength
= 10;
638 cdb
= (PCDB
) Context
->Srb
.Cdb
;
640 RtlZeroMemory(cdb
, sizeof(CDB
));
641 cdb
->SYNCHRONIZE_CACHE10
.OperationCode
= SCSIOP_SYNCHRONIZE_CACHE
;
643 IoSetCompletionRoutine(Irp
,
644 ClasspPowerDownCompletion
,
650 nextStack
->Parameters
.Scsi
.Srb
= &(Context
->Srb
);
651 nextStack
->MajorFunction
= IRP_MJ_SCSI
;
653 status
= IoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
655 DebugPrint((1, "(%p)\tIoCallDriver returned %lx\n", Irp
, status
));
660 DebugPrint((1, "(%p)\tPower Down: not sending SYNCH_CACHE\n",
662 Context
->PowerChangeState
.PowerDown2
++;
663 Context
->Srb
.SrbStatus
= SRB_STATUS_SUCCESS
;
664 // and fall through....
666 // no break in case the device doesn't like synch_cache commands
670 case PowerDownDeviceFlushed2
: {
674 DebugPrint((1, "(%p)\tPreviously send SCSIOP_SYNCHRONIZE_CACHE\n",
678 // SCSIOP_SYNCHRONIZE_CACHE was sent
681 if(SRB_STATUS(Context
->Srb
.SrbStatus
) != SRB_STATUS_SUCCESS
) {
685 DebugPrint((1, "(%p)\tError occured when issuing "
686 "SYNCHRONIZE_CACHE command to device. "
687 "Srb %p, Status %lx\n",
690 Context
->Srb
.SrbStatus
));
692 ASSERT(!(TEST_FLAG(Context
->Srb
.SrbStatus
,
693 SRB_STATUS_QUEUE_FROZEN
)));
694 ASSERT(Context
->Srb
.Function
== SRB_FUNCTION_EXECUTE_SCSI
);
696 Context
->RetryInterval
= 0;
697 retry
= ClassInterpretSenseInfo(
698 commonExtension
->DeviceObject
,
702 MAXIMUM_RETRIES
- Context
->RetryCount
,
704 &Context
->RetryInterval
);
706 if((retry
== TRUE
) && (Context
->RetryCount
-- != 0)) {
708 DebugPrint((1, "(%p)\tRetrying failed request\n", Irp
));
711 // decrement the state so we come back through here
715 Context
->PowerChangeState
.PowerDown2
--;
716 RetryPowerRequest(commonExtension
->DeviceObject
,
722 DebugPrint((1, "(%p)\tSYNCHRONIZE_CACHE not retried\n", Irp
));
723 Context
->RetryCount
= MAXIMUM_RETRIES
;
725 } // end !SRB_STATUS_SUCCESS
728 // note: we are purposefully ignoring any errors. if the drive
729 // doesn't support a synch_cache, then we're up a creek
733 DebugPrint((1, "(%p)\tSending stop unit to device\n", Irp
));
736 // Issue the start unit command to the device.
739 Context
->Srb
.Length
= sizeof(SCSI_REQUEST_BLOCK
);
740 Context
->Srb
.Function
= SRB_FUNCTION_EXECUTE_SCSI
;
742 Context
->Srb
.TimeOutValue
= START_UNIT_TIMEOUT
;
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
;
750 Context
->Srb
.SrbStatus
= Context
->Srb
.ScsiStatus
= 0;
751 Context
->Srb
.DataTransferLength
= 0;
753 Context
->Srb
.CdbLength
= 6;
755 cdb
= (PCDB
) Context
->Srb
.Cdb
;
756 RtlZeroMemory(cdb
, sizeof(CDB
));
758 cdb
->START_STOP
.OperationCode
= SCSIOP_START_STOP_UNIT
;
759 cdb
->START_STOP
.Start
= 0;
760 cdb
->START_STOP
.Immediate
= 1;
762 IoSetCompletionRoutine(Irp
,
763 ClasspPowerDownCompletion
,
769 nextStack
->Parameters
.Scsi
.Srb
= &(Context
->Srb
);
770 nextStack
->MajorFunction
= IRP_MJ_SCSI
;
772 status
= IoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
774 DebugPrint((1, "(%p)\tIoCallDriver returned %lx\n", Irp
, status
));
779 case PowerDownDeviceStopped2
: {
781 BOOLEAN ignoreError
= TRUE
;
787 if(SRB_STATUS(Context
->Srb
.SrbStatus
) != SRB_STATUS_SUCCESS
) {
791 DebugPrint((1, "(%p)\tError occured when issueing STOP_UNIT "
792 "command to device. Srb %p, Status %lx\n",
795 Context
->Srb
.SrbStatus
));
797 ASSERT(!(TEST_FLAG(Context
->Srb
.SrbStatus
,
798 SRB_STATUS_QUEUE_FROZEN
)));
799 ASSERT(Context
->Srb
.Function
== SRB_FUNCTION_EXECUTE_SCSI
);
801 Context
->RetryInterval
= 0;
802 retry
= ClassInterpretSenseInfo(
803 commonExtension
->DeviceObject
,
807 MAXIMUM_RETRIES
- Context
->RetryCount
,
809 &Context
->RetryInterval
);
811 if((retry
== TRUE
) && (Context
->RetryCount
-- != 0)) {
813 DebugPrint((1, "(%p)\tRetrying failed request\n", Irp
));
816 // decrement the state so we come back through here
820 Context
->PowerChangeState
.PowerDown2
--;
821 RetryPowerRequest(commonExtension
->DeviceObject
,
827 DebugPrint((1, "(%p)\tSTOP_UNIT not retried\n", Irp
));
828 Context
->RetryCount
= MAXIMUM_RETRIES
;
830 } // end !SRB_STATUS_SUCCESS
833 DebugPrint((1, "(%p)\tPreviously sent stop unit\n", Irp
));
836 // some operations, such as a physical format in progress,
837 // should not be ignored and should fail the power operation.
840 if (!NT_SUCCESS(status
)) {
842 PSENSE_DATA senseBuffer
= Context
->Srb
.SenseInfoBuffer
;
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
)
851 Context
->FinalStatus
= STATUS_DEVICE_BUSY
;
852 status
= Context
->FinalStatus
;
857 if (NT_SUCCESS(status
) || ignoreError
) {
860 // Issue the actual power request to the lower driver.
863 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
865 IoCopyCurrentIrpStackLocationToNext(Irp
);
867 IoSetCompletionRoutine(Irp
,
868 ClasspPowerDownCompletion
,
874 status
= PoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
876 DebugPrint((1, "(%p)\tPoCallDriver returned %lx\n", Irp
, status
));
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
886 case PowerDownDeviceOff2
: {
889 // SpinDown request completed ... whether it succeeded or not is
890 // another matter entirely.
893 DebugPrint((1, "(%p)\tPreviously sent power irp\n", Irp
));
895 if (Context
->QueueLocked
) {
897 DebugPrint((1, "(%p)\tUnlocking queue\n", Irp
));
899 Context
->Srb
.Length
= sizeof(SCSI_REQUEST_BLOCK
);
901 Context
->Srb
.SrbStatus
= Context
->Srb
.ScsiStatus
= 0;
902 Context
->Srb
.DataTransferLength
= 0;
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
;
909 IoSetCompletionRoutine(Irp
,
910 ClasspPowerDownCompletion
,
916 status
= IoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
917 DebugPrint((1, "(%p)\tIoCallDriver returned %lx\n",
925 case PowerDownDeviceUnlocked2
: {
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 ....
933 if (Context
->QueueLocked
== FALSE
) {
934 DebugPrint((1, "(%p)\tFall through (queue not locked)\n", Irp
));
936 DebugPrint((1, "(%p)\tPreviously unlocked queue\n", Irp
));
937 ASSERT(NT_SUCCESS(Irp
->IoStatus
.Status
));
938 ASSERT(Context
->Srb
.SrbStatus
== SRB_STATUS_SUCCESS
);
941 DebugPrint((1, "(%p)\tFreeing srb and completing\n", Irp
));
942 Context
->InUse
= FALSE
;
943 status
= Context
->FinalStatus
; // allow failure to propogate
946 if(Irp
->PendingReturned
) {
947 IoMarkIrpPending(Irp
);
950 Irp
->IoStatus
.Status
= status
;
951 Irp
->IoStatus
.Information
= 0;
953 if (NT_SUCCESS(status
)) {
956 // Set the new power state
959 fdoExtension
->DevicePowerState
=
960 currentStack
->Parameters
.Power
.State
.DeviceState
;
965 DebugPrint((1, "(%p)\tStarting next power irp\n", Irp
));
967 ClassReleaseRemoveLock(DeviceObject
, Irp
);
968 PoStartNextPowerIrp(Irp
);
969 fdoExtension
->PowerDownInProgress
= FALSE
;
975 return STATUS_MORE_PROCESSING_REQUIRED
;
976 } // end ClasspPowerDownCompletion()
978 /*++////////////////////////////////////////////////////////////////////////////
984 This routine reduces the number of useless spinups and spindown requests
985 sent to a given device by ignoring transitions to power states we are
988 ISSUE-2000/02/20-henrygab - by ignoring spin-up requests, we may be
993 DeviceObject - the device object which is transitioning power states
995 Options - a set of flags indicating what the device handles
1002 IN PDEVICE_OBJECT DeviceObject
,
1004 IN CLASS_POWER_OPTIONS Options
// ISSUE-2000/02/20-henrygab - pass pointer, not whole struct
1007 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
1008 PDEVICE_OBJECT lowerDevice
= commonExtension
->LowerDeviceObject
;
1009 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
1010 PIO_STACK_LOCATION nextIrpStack
;
1011 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
1012 PCLASS_POWER_CONTEXT context
;
1014 if (!commonExtension
->IsFdo
) {
1017 // certain assumptions are made here,
1018 // particularly: having the fdoExtension
1021 DebugPrint((0, "ClasspPowerHandler: Called for PDO %p???\n",
1023 ASSERT(!"PDO using ClasspPowerHandler");
1024 return STATUS_NOT_SUPPORTED
;
1027 DebugPrint((1, "ClasspPowerHandler: Power irp %p to %s %p\n",
1028 Irp
, (commonExtension
->IsFdo
? "fdo" : "pdo"), DeviceObject
));
1030 switch(irpStack
->MinorFunction
) {
1032 case IRP_MN_SET_POWER
: {
1033 PCLASS_PRIVATE_FDO_DATA fdoData
= fdoExtension
->PrivateFdoData
;
1035 DebugPrint((1, "(%p)\tIRP_MN_SET_POWER\n", Irp
));
1037 DebugPrint((1, "(%p)\tSetting %s state to %d\n",
1039 (irpStack
->Parameters
.Power
.Type
== SystemPowerState
?
1040 "System" : "Device"),
1041 irpStack
->Parameters
.Power
.State
.SystemState
));
1043 switch (irpStack
->Parameters
.Power
.ShutdownType
){
1045 case PowerActionSleep
:
1046 case PowerActionHibernate
:
1047 if (fdoData
->HotplugInfo
.MediaRemovable
|| fdoData
->HotplugInfo
.MediaHotplug
){
1049 * We are suspending and this drive is either hot-pluggable
1050 * or contains removeable media.
1051 * Set the media dirty bit, since the media may change while
1054 SET_FLAG(DeviceObject
->Flags
, DO_VERIFY_VOLUME
);
1064 DebugPrint((1, "(%p)\tIrp minor code = %#x\n",
1065 Irp
, irpStack
->MinorFunction
));
1070 if (irpStack
->Parameters
.Power
.Type
!= DevicePowerState
||
1071 irpStack
->MinorFunction
!= IRP_MN_SET_POWER
) {
1073 DebugPrint((1, "(%p)\tSending to lower device\n", Irp
));
1075 goto ClasspPowerHandlerCleanup
;
1079 nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
1082 // already in exact same state, don't work to transition to it.
1085 if(irpStack
->Parameters
.Power
.State
.DeviceState
==
1086 fdoExtension
->DevicePowerState
) {
1088 DebugPrint((1, "(%p)\tAlready in device state %x\n",
1089 Irp
, fdoExtension
->DevicePowerState
));
1090 goto ClasspPowerHandlerCleanup
;
1095 // or powering down from non-d0 state (device already stopped)
1096 // NOTE -- we're not sure whether this case can exist or not (the
1097 // power system may never send this sort of request) but it's trivial
1101 if ((irpStack
->Parameters
.Power
.State
.DeviceState
!= PowerDeviceD0
) &&
1102 (fdoExtension
->DevicePowerState
!= PowerDeviceD0
)) {
1103 DebugPrint((1, "(%p)\tAlready powered down to %x???\n",
1104 Irp
, fdoExtension
->DevicePowerState
));
1105 fdoExtension
->DevicePowerState
=
1106 irpStack
->Parameters
.Power
.State
.DeviceState
;
1107 goto ClasspPowerHandlerCleanup
;
1111 // or going into a hibernation state when we're in the hibernation path.
1112 // If the device is spinning then we should leave it spinning - if it's not
1113 // then the dump driver will start it up for us.
1116 if((irpStack
->Parameters
.Power
.State
.DeviceState
== PowerDeviceD3
) &&
1117 (irpStack
->Parameters
.Power
.ShutdownType
== PowerActionHibernate
) &&
1118 (commonExtension
->HibernationPathCount
!= 0)) {
1120 DebugPrint((1, "(%p)\tdoing nothing for hibernation request for "
1122 Irp
, fdoExtension
->DevicePowerState
));
1123 fdoExtension
->DevicePowerState
=
1124 irpStack
->Parameters
.Power
.State
.DeviceState
;
1125 goto ClasspPowerHandlerCleanup
;
1128 // or when not handling powering up and are powering up
1131 if ((!Options
.HandleSpinUp
) &&
1132 (irpStack
->Parameters
.Power
.State
.DeviceState
== PowerDeviceD0
)) {
1134 DebugPrint((2, "(%p)\tNot handling spinup to state %x\n",
1135 Irp
, fdoExtension
->DevicePowerState
));
1136 fdoExtension
->DevicePowerState
=
1137 irpStack
->Parameters
.Power
.State
.DeviceState
;
1138 goto ClasspPowerHandlerCleanup
;
1143 // or when not handling powering down and are powering down
1146 if ((!Options
.HandleSpinDown
) &&
1147 (irpStack
->Parameters
.Power
.State
.DeviceState
!= PowerDeviceD0
)) {
1149 DebugPrint((2, "(%p)\tNot handling spindown to state %x\n",
1150 Irp
, fdoExtension
->DevicePowerState
));
1151 fdoExtension
->DevicePowerState
=
1152 irpStack
->Parameters
.Power
.State
.DeviceState
;
1153 goto ClasspPowerHandlerCleanup
;
1157 context
= &(fdoExtension
->PowerContext
);
1161 // Mark the context as in use. We should be synchronizing this but
1162 // since it's just for debugging purposes we don't worry too much.
1165 ASSERT(context
->InUse
== FALSE
);
1168 RtlZeroMemory(context
, sizeof(CLASS_POWER_CONTEXT
));
1169 context
->InUse
= TRUE
;
1171 nextIrpStack
->Parameters
.Scsi
.Srb
= &(context
->Srb
);
1172 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
1174 context
->FinalStatus
= STATUS_SUCCESS
;
1176 context
->Srb
.Length
= sizeof(SCSI_REQUEST_BLOCK
);
1177 context
->Srb
.OriginalRequest
= Irp
;
1178 context
->Srb
.SrbFlags
|= SRB_FLAGS_BYPASS_LOCKED_QUEUE
1179 | SRB_FLAGS_NO_QUEUE_FREEZE
;
1180 context
->Srb
.Function
= SRB_FUNCTION_LOCK_QUEUE
;
1182 context
->Srb
.SenseInfoBuffer
=
1183 commonExtension
->PartitionZeroExtension
->SenseData
;
1184 context
->Srb
.SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
1185 context
->RetryCount
= MAXIMUM_RETRIES
;
1187 context
->Options
= Options
;
1188 context
->DeviceObject
= DeviceObject
;
1191 if(irpStack
->Parameters
.Power
.State
.DeviceState
== PowerDeviceD0
) {
1193 ASSERT(Options
.HandleSpinUp
);
1195 DebugPrint((2, "(%p)\tpower up - locking queue\n", Irp
));
1198 // We need to issue a queue lock request so that we
1199 // can spin the drive back up after the power is restored
1200 // but before any requests are processed.
1203 context
->Options
.PowerDown
= FALSE
;
1204 context
->PowerChangeState
.PowerUp
= PowerUpDeviceInitial
;
1205 context
->CompletionRoutine
= ClasspPowerUpCompletion
;
1209 ASSERT(Options
.HandleSpinDown
);
1211 fdoExtension
->PowerDownInProgress
= TRUE
;
1213 DebugPrint((2, "(%p)\tPowering down - locking queue\n", Irp
));
1215 PoSetPowerState(DeviceObject
,
1216 irpStack
->Parameters
.Power
.Type
,
1217 irpStack
->Parameters
.Power
.State
);
1219 context
->Options
.PowerDown
= TRUE
;
1220 context
->PowerChangeState
.PowerDown2
= PowerDownDeviceInitial2
;
1221 context
->CompletionRoutine
= ClasspPowerDownCompletion
;
1226 // we are not dealing with port-allocated sense in these routines.
1229 ASSERT(!TEST_FLAG(context
->Srb
.SrbFlags
, SRB_FLAGS_FREE_SENSE_BUFFER
));
1230 ASSERT(!TEST_FLAG(context
->Srb
.SrbFlags
, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE
));
1233 // we are always returning STATUS_PENDING, so we need to always
1234 // set the irp as pending.
1237 IoMarkIrpPending(Irp
);
1239 if(Options
.LockQueue
) {
1242 // Send the lock irp down.
1245 IoSetCompletionRoutine(Irp
,
1246 context
->CompletionRoutine
,
1252 IoCallDriver(lowerDevice
, Irp
);
1257 // Call the completion routine directly. It won't care what the
1258 // status of the "lock" was - it will just go and do the next
1259 // step of the operation.
1262 context
->CompletionRoutine(DeviceObject
, Irp
, context
);
1265 return STATUS_PENDING
;
1267 ClasspPowerHandlerCleanup
:
1269 ClassReleaseRemoveLock(DeviceObject
, Irp
);
1271 DebugPrint((1, "(%p)\tStarting next power irp\n", Irp
));
1272 IoCopyCurrentIrpStackLocationToNext(Irp
);
1273 IoSetCompletionRoutine(Irp
,
1274 ClasspStartNextPowerIrpCompletion
,
1279 return PoCallDriver(lowerDevice
, Irp
);
1280 } // end ClasspPowerHandler()
1282 /*++////////////////////////////////////////////////////////////////////////////
1284 ClassMinimalPowerHandler()
1286 Routine Description:
1288 This routine is the minimum power handler for a storage driver. It does
1289 the least amount of work possible.
1293 ClassMinimalPowerHandler(
1294 IN PDEVICE_OBJECT DeviceObject
,
1298 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
1299 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
1302 ClassReleaseRemoveLock(DeviceObject
, Irp
);
1303 PoStartNextPowerIrp(Irp
);
1305 if(commonExtension
->IsFdo
) {
1307 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
1309 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
=
1310 DeviceObject
->DeviceExtension
;
1313 // Check if the system is going to hibernate or standby.
1315 if (irpStack
->MinorFunction
== IRP_MN_SET_POWER
){
1318 switch (irpStack
->Parameters
.Power
.ShutdownType
){
1320 case PowerActionSleep
:
1321 case PowerActionHibernate
:
1323 // If the volume is mounted, set the verify bit so that
1324 // the filesystem will be forced re-read the media
1325 // after coming out of hibernation or standby.
1327 vpb
= ClassGetVpb(fdoExtension
->DeviceObject
);
1328 if (vpb
&& (vpb
->Flags
& VPB_MOUNTED
)){
1329 SET_FLAG(fdoExtension
->DeviceObject
->Flags
, DO_VERIFY_VOLUME
);
1336 IoCopyCurrentIrpStackLocationToNext(Irp
);
1337 return PoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
1341 if (irpStack
->MinorFunction
!= IRP_MN_SET_POWER
&&
1342 irpStack
->MinorFunction
!= IRP_MN_QUERY_POWER
) {
1348 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1349 Irp
->IoStatus
.Information
= 0;
1352 status
= Irp
->IoStatus
.Status
;
1354 ClassCompleteRequest(DeviceObject
, Irp
, IO_NO_INCREMENT
);
1357 } // end ClassMinimalPowerHandler()
1359 /*++////////////////////////////////////////////////////////////////////////////
1361 ClassSpinDownPowerHandler()
1363 Routine Description:
1365 This routine is a callback for disks and other things which require both
1366 a start and a stop to be sent to the device. (actually the starts are
1367 almost always optional, since most device power themselves on to process
1368 commands, but i digress).
1370 Determines proper use of spinup, spindown, and queue locking based upon
1371 ScanForSpecialFlags in the FdoExtension. This is the most common power
1372 handler passed into classpnp.sys
1376 DeviceObject - Supplies the functional device object
1378 Irp - Supplies the request to be retried.
1386 ClassSpinDownPowerHandler(
1387 IN PDEVICE_OBJECT DeviceObject
,
1391 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
;
1392 CLASS_POWER_OPTIONS options
;
1394 fdoExtension
= (PFUNCTIONAL_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
1397 // this will set all options to FALSE
1400 RtlZeroMemory(&options
, sizeof(CLASS_POWER_OPTIONS
));
1403 // check the flags to see what options we need to worry about
1406 if (!TEST_FLAG(fdoExtension
->ScanForSpecialFlags
,
1407 CLASS_SPECIAL_DISABLE_SPIN_DOWN
)) {
1408 options
.HandleSpinDown
= TRUE
;
1411 if (!TEST_FLAG(fdoExtension
->ScanForSpecialFlags
,
1412 CLASS_SPECIAL_DISABLE_SPIN_UP
)) {
1413 options
.HandleSpinUp
= TRUE
;
1416 if (!TEST_FLAG(fdoExtension
->ScanForSpecialFlags
,
1417 CLASS_SPECIAL_NO_QUEUE_LOCK
)) {
1418 options
.LockQueue
= TRUE
;
1421 DebugPrint((3, "ClasspPowerHandler: Devobj %p\n"
1422 "\t%shandling spin down\n"
1423 "\t%shandling spin up\n"
1424 "\t%slocking queue\n",
1426 (options
.HandleSpinDown
? "" : "not "),
1427 (options
.HandleSpinUp
? "" : "not "),
1428 (options
.LockQueue
? "" : "not ")
1432 // do all the dirty work
1435 return ClasspPowerHandler(DeviceObject
, Irp
, options
);
1436 } // end ClassSpinDownPowerHandler()
1438 /*++////////////////////////////////////////////////////////////////////////////
1440 ClassStopUnitPowerHandler()
1442 Routine Description:
1444 This routine is an outdated call. To achieve equivalent functionality,
1445 the driver should set the following flags in ScanForSpecialFlags in the
1448 CLASS_SPECIAL_DISABLE_SPIN_UP
1449 CLASS_SPECIAL_NO_QUEUE_LOCK
1453 ClassStopUnitPowerHandler(
1454 IN PDEVICE_OBJECT DeviceObject
,
1458 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
;
1460 DebugPrint((0, "ClassStopUnitPowerHandler - Devobj %p using outdated call\n"
1461 "Drivers should set the following flags in ScanForSpecialFlags "
1462 " in the FDO extension:\n"
1463 "\tCLASS_SPECIAL_DISABLE_SPIN_UP\n"
1464 "\tCLASS_SPECIAL_NO_QUEUE_LOCK\n"
1465 "This will provide equivalent functionality if the power "
1466 "routine is then set to ClassSpinDownPowerHandler\n\n",
1469 fdoExtension
= (PFUNCTIONAL_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
1471 SET_FLAG(fdoExtension
->ScanForSpecialFlags
,
1472 CLASS_SPECIAL_DISABLE_SPIN_UP
);
1473 SET_FLAG(fdoExtension
->ScanForSpecialFlags
,
1474 CLASS_SPECIAL_NO_QUEUE_LOCK
);
1476 return ClassSpinDownPowerHandler(DeviceObject
, Irp
);
1477 } // end ClassStopUnitPowerHandler()
1479 /*++////////////////////////////////////////////////////////////////////////////
1483 Routine Description:
1485 This routine reinitalizes the necessary fields, and sends the request
1486 to the lower driver.
1490 DeviceObject - Supplies the device object associated with this request.
1492 Irp - Supplies the request to be retried.
1494 Context - Supplies a pointer to the power up context for this request.
1503 PDEVICE_OBJECT DeviceObject
,
1505 PCLASS_POWER_CONTEXT Context
1508 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
1509 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
1510 PIO_STACK_LOCATION nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
1511 PSCSI_REQUEST_BLOCK srb
= &(Context
->Srb
);
1512 LARGE_INTEGER dueTime
;
1514 DebugPrint((1, "(%p)\tDelaying retry by queueing DPC\n", Irp
));
1516 ASSERT(Context
->Irp
== Irp
);
1517 ASSERT(Context
->DeviceObject
== DeviceObject
);
1518 ASSERT(!TEST_FLAG(Context
->Srb
.SrbFlags
, SRB_FLAGS_FREE_SENSE_BUFFER
));
1519 ASSERT(!TEST_FLAG(Context
->Srb
.SrbFlags
, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE
));
1522 // reset the retry interval
1525 Context
->RetryInterval
= 0;
1528 // Reset byte count of transfer in SRB Extension.
1531 srb
->DataTransferLength
= 0;
1534 // Zero SRB statuses.
1537 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
1540 // Set up major SCSI function.
1543 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
1546 // Save SRB address in next stack for port driver.
1549 nextIrpStack
->Parameters
.Scsi
.Srb
= srb
;
1552 // Set the completion routine up again.
1555 IoSetCompletionRoutine(Irp
, Context
->CompletionRoutine
, Context
,
1559 if (Context
->RetryInterval
== 0) {
1561 DebugPrint((2, "(%p)\tDelaying minimum time (.2 sec)\n", Irp
));
1562 dueTime
.QuadPart
= (LONGLONG
)1000000 * 2;
1566 DebugPrint((2, "(%p)\tDelaying %x seconds\n",
1567 Irp
, Context
->RetryInterval
));
1568 dueTime
.QuadPart
= (LONGLONG
)1000000 * 10 * Context
->RetryInterval
;
1572 ClassRetryRequest(DeviceObject
, Irp
, dueTime
);
1576 } // end RetryRequest()
1578 /*++////////////////////////////////////////////////////////////////////////////
1580 ClasspStartNextPowerIrpCompletion()
1582 Routine Description:
1584 This routine guarantees that the next power irp (power up or down) is not
1585 sent until the previous one has fully completed.
1589 ClasspStartNextPowerIrpCompletion(
1590 IN PDEVICE_OBJECT DeviceObject
,
1595 if(Irp
->PendingReturned
) {
1596 IoMarkIrpPending(Irp
);
1599 PoStartNextPowerIrp(Irp
);
1600 return STATUS_SUCCESS
;
1601 } // end ClasspStartNextPowerIrpCompletion()