3 Copyright (C) Microsoft Corporation, 1991 - 1999
11 SCSI class driver routines
26 #define CLASS_TAG_POWER 'WLcS'
31 IN PDEVICE_OBJECT DeviceObject
,
33 IN CLASS_POWER_OPTIONS Options
36 IO_COMPLETION_ROUTINE ClasspPowerDownCompletion
;
38 IO_COMPLETION_ROUTINE ClasspPowerUpCompletion
;
43 PDEVICE_OBJECT DeviceObject
,
45 PCLASS_POWER_CONTEXT Context
50 ClasspStartNextPowerIrpCompletion(
51 IN PDEVICE_OBJECT DeviceObject
,
57 /*++////////////////////////////////////////////////////////////////////////////
63 This routine acquires the removelock for the irp and then calls the
64 appropriate power callback.
77 IN PDEVICE_OBJECT DeviceObject
,
81 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
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.
90 isRemoved
= ClassAcquireRemoveLock(DeviceObject
, Irp
);
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
;
100 return commonExtension
->DevInfo
->ClassPowerDevice(DeviceObject
, Irp
);
101 } // end ClassDispatchPower()
103 /*++////////////////////////////////////////////////////////////////////////////
105 ClasspPowerUpCompletion()
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.
112 * The queue is "power locked" to ensure that the class driver power-up
113 work can be done before request processing resumes.
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
120 * A start unit command is issued to the device with appropriate flags
121 to override the "power locked" queue.
123 * The queue is "power unlocked" to start processing requests again.
125 This routine uses the function in the srb which just completed to determine
126 which state it is in.
130 DeviceObject - the device object being powered up
132 Irp - the IO_REQUEST_PACKET containing the power request
134 Srb - the SRB used to perform port/class operations.
138 STATUS_MORE_PROCESSING_REQUIRED or
144 ClasspPowerUpCompletion(
145 IN PDEVICE_OBJECT DeviceObject
,
147 IN PVOID CompletionContext
150 PCLASS_POWER_CONTEXT context
= CompletionContext
;
151 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
152 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
154 PIO_STACK_LOCATION currentStack
= IoGetCurrentIrpStackLocation(Irp
);
155 PIO_STACK_LOCATION nextStack
= IoGetNextIrpStackLocation(Irp
);
158 NTSTATUS status
= STATUS_MORE_PROCESSING_REQUIRED
;
160 DebugPrint((1, "ClasspPowerUpCompletion: Device Object %p, Irp %p, "
162 DeviceObject
, Irp
, context
));
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
);
169 if(Irp
->PendingReturned
) {
170 IoMarkIrpPending(Irp
);
173 context
->PowerChangeState
.PowerUp
++;
175 switch(context
->PowerChangeState
.PowerUp
) {
177 case PowerUpDeviceLocked
: {
179 DebugPrint((1, "(%p)\tPreviously sent power lock\n", Irp
));
182 // Issue the actual power request to the lower driver.
185 IoCopyCurrentIrpStackLocationToNext(Irp
);
188 // If the lock wasn't successful then just bail out on the power
189 // request unless we can ignore failed locks
192 if((context
->Options
.LockQueue
== TRUE
) &&
193 (!NT_SUCCESS(Irp
->IoStatus
.Status
))) {
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
));
201 // Lock was not successful - throw down the power IRP
202 // by itself and don't try to spin up the drive or unlock
206 context
->InUse
= FALSE
;
210 // Set the new power state
213 fdoExtension
->DevicePowerState
=
214 currentStack
->Parameters
.Power
.State
.DeviceState
;
216 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
218 IoCopyCurrentIrpStackLocationToNext(Irp
);
220 IoSetCompletionRoutine(Irp
,
221 ClasspStartNextPowerIrpCompletion
,
228 // Indicate to Po that we've been successfully powered up so
229 // it can do it's notification stuff.
232 PoSetPowerState(DeviceObject
,
233 currentStack
->Parameters
.Power
.Type
,
234 currentStack
->Parameters
.Power
.State
);
236 PoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
238 ClassReleaseRemoveLock(commonExtension
->DeviceObject
,
241 return STATUS_MORE_PROCESSING_REQUIRED
;
244 context
->QueueLocked
= (UCHAR
) context
->Options
.LockQueue
;
247 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
249 context
->PowerChangeState
.PowerUp
= PowerUpDeviceLocked
;
251 IoSetCompletionRoutine(Irp
,
252 ClasspPowerUpCompletion
,
258 status
= PoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
260 DebugPrint((2, "(%p)\tPoCallDriver returned %lx\n", Irp
, status
));
264 case PowerUpDeviceOn
: {
268 if(NT_SUCCESS(Irp
->IoStatus
.Status
)) {
270 DebugPrint((1, "(%p)\tSending start unit to device\n", Irp
));
273 // Issue the start unit command to the device.
276 context
->Srb
.Length
= sizeof(SCSI_REQUEST_BLOCK
);
277 context
->Srb
.Function
= SRB_FUNCTION_EXECUTE_SCSI
;
279 context
->Srb
.SrbStatus
= context
->Srb
.ScsiStatus
= 0;
280 context
->Srb
.DataTransferLength
= 0;
282 context
->Srb
.TimeOutValue
= START_UNIT_TIMEOUT
;
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
;
289 if(context
->Options
.LockQueue
) {
290 SET_FLAG(context
->Srb
.SrbFlags
, SRB_FLAGS_BYPASS_LOCKED_QUEUE
);
293 context
->Srb
.CdbLength
= 6;
295 cdb
= (PCDB
) (context
->Srb
.Cdb
);
296 RtlZeroMemory(cdb
, sizeof(CDB
));
299 cdb
->START_STOP
.OperationCode
= SCSIOP_START_STOP_UNIT
;
300 cdb
->START_STOP
.Start
= 1;
302 context
->PowerChangeState
.PowerUp
= PowerUpDeviceOn
;
304 IoSetCompletionRoutine(Irp
,
305 ClasspPowerUpCompletion
,
311 nextStack
->Parameters
.Scsi
.Srb
= &(context
->Srb
);
312 nextStack
->MajorFunction
= IRP_MJ_SCSI
;
314 status
= IoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
316 DebugPrint((2, "(%p)\tIoCallDriver returned %lx\n", Irp
, status
));
324 context
->FinalStatus
= Irp
->IoStatus
.Status
;
325 goto ClasspPowerUpCompletionFailure
;
331 case PowerUpDeviceStarted
: { // 3
334 // First deal with an error if one occurred.
337 if(SRB_STATUS(context
->Srb
.SrbStatus
) != SRB_STATUS_SUCCESS
) {
341 DebugPrint((1, "%p\tError occured when issuing START_UNIT "
342 "command to device. Srb %p, Status %x\n",
345 context
->Srb
.SrbStatus
));
347 ASSERT(!(TEST_FLAG(context
->Srb
.SrbStatus
,
348 SRB_STATUS_QUEUE_FROZEN
)));
349 ASSERT(context
->Srb
.Function
== SRB_FUNCTION_EXECUTE_SCSI
);
351 context
->RetryInterval
= 0;
353 retry
= ClassInterpretSenseInfo(
354 commonExtension
->DeviceObject
,
358 MAXIMUM_RETRIES
- context
->RetryCount
,
360 &context
->RetryInterval
);
362 if((retry
== TRUE
) && (context
->RetryCount
-- != 0)) {
364 DebugPrint((1, "(%p)\tRetrying failed request\n", Irp
));
367 // Decrement the state so we come back through here the
371 context
->PowerChangeState
.PowerUp
--;
373 RetryPowerRequest(commonExtension
->DeviceObject
,
382 context
->RetryCount
= MAXIMUM_RETRIES
;
386 ClasspPowerUpCompletionFailure
:
388 DebugPrint((1, "(%p)\tPreviously spun device up\n", Irp
));
390 if (context
->QueueLocked
) {
391 DebugPrint((1, "(%p)\tUnlocking queue\n", Irp
));
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;
398 nextStack
->Parameters
.Scsi
.Srb
= &(context
->Srb
);
399 nextStack
->MajorFunction
= IRP_MJ_SCSI
;
401 context
->PowerChangeState
.PowerUp
= PowerUpDeviceStarted
;
403 IoSetCompletionRoutine(Irp
,
404 ClasspPowerUpCompletion
,
410 status
= IoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
411 DebugPrint((1, "(%p)\tIoCallDriver returned %lx\n",
416 // Fall-through to next case...
420 case PowerUpDeviceUnlocked
: {
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 ....
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
);
433 DebugPrint((1, "(%p)\tFall-through (queue not locked)\n", Irp
));
436 DebugPrint((1, "(%p)\tFreeing srb and completing\n", Irp
));
437 context
->InUse
= FALSE
;
439 status
= context
->FinalStatus
;
440 Irp
->IoStatus
.Status
= status
;
445 // Set the new power state
448 if(NT_SUCCESS(status
)) {
449 fdoExtension
->DevicePowerState
=
450 currentStack
->Parameters
.Power
.State
.DeviceState
;
454 // Indicate to Po that we've been successfully powered up so
455 // it can do it's notification stuff.
458 PoSetPowerState(DeviceObject
,
459 currentStack
->Parameters
.Power
.Type
,
460 currentStack
->Parameters
.Power
.State
);
462 DebugPrint((1, "(%p)\tStarting next power irp\n", Irp
));
463 ClassReleaseRemoveLock(DeviceObject
, Irp
);
464 PoStartNextPowerIrp(Irp
);
469 case PowerUpDeviceInitial
: {
470 NT_ASSERT(context
->PowerChangeState
.PowerUp
!= PowerUpDeviceInitial
);
475 return STATUS_MORE_PROCESSING_REQUIRED
;
476 } // end ClasspPowerUpCompletion()
478 /*++////////////////////////////////////////////////////////////////////////////
480 ClasspPowerDownCompletion()
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.
487 * The queue is "power locked" to ensure that the class driver power-up
488 work can be done before request processing resumes.
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
495 * A start unit command is issued to the device with appropriate flags
496 to override the "power locked" queue.
498 * The queue is "power unlocked" to start processing requests again.
500 This routine uses the function in the srb which just completed to determine
501 which state it is in.
505 DeviceObject - the device object being powered up
507 Irp - the IO_REQUEST_PACKET containing the power request
509 Srb - the SRB used to perform port/class operations.
513 STATUS_MORE_PROCESSING_REQUIRED or
519 ClasspPowerDownCompletion(
520 IN PDEVICE_OBJECT DeviceObject
,
522 IN PVOID CompletionContext
525 PCLASS_POWER_CONTEXT context
= CompletionContext
;
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
;
974 case PowerDownDeviceInitial2
: {
975 NT_ASSERT(context
->PowerChangeState
.PowerDown2
!= PowerDownDeviceInitial2
);
980 return STATUS_MORE_PROCESSING_REQUIRED
;
981 } // end ClasspPowerDownCompletion()
983 /*++////////////////////////////////////////////////////////////////////////////
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
993 ISSUE-2000/02/20-henrygab - by ignoring spin-up requests, we may be
998 DeviceObject - the device object which is transitioning power states
1000 Options - a set of flags indicating what the device handles
1008 IN PDEVICE_OBJECT DeviceObject
,
1010 IN CLASS_POWER_OPTIONS Options
// ISSUE-2000/02/20-henrygab - pass pointer, not whole struct
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
;
1020 if (!commonExtension
->IsFdo
) {
1023 // certain assumptions are made here,
1024 // particularly: having the fdoExtension
1027 DebugPrint((0, "ClasspPowerHandler: Called for PDO %p???\n",
1029 ASSERT(!"PDO using ClasspPowerHandler");
1030 return STATUS_NOT_SUPPORTED
;
1033 DebugPrint((1, "ClasspPowerHandler: Power irp %p to %s %p\n",
1034 Irp
, (commonExtension
->IsFdo
? "fdo" : "pdo"), DeviceObject
));
1036 switch(irpStack
->MinorFunction
) {
1038 case IRP_MN_SET_POWER
: {
1039 PCLASS_PRIVATE_FDO_DATA fdoData
= fdoExtension
->PrivateFdoData
;
1041 DebugPrint((1, "(%p)\tIRP_MN_SET_POWER\n", Irp
));
1043 DebugPrint((1, "(%p)\tSetting %s state to %d\n",
1045 (irpStack
->Parameters
.Power
.Type
== SystemPowerState
?
1046 "System" : "Device"),
1047 irpStack
->Parameters
.Power
.State
.SystemState
));
1049 switch (irpStack
->Parameters
.Power
.ShutdownType
){
1051 case PowerActionSleep
:
1052 case PowerActionHibernate
:
1053 if (fdoData
->HotplugInfo
.MediaRemovable
|| fdoData
->HotplugInfo
.MediaHotplug
){
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
1060 SET_FLAG(DeviceObject
->Flags
, DO_VERIFY_VOLUME
);
1072 DebugPrint((1, "(%p)\tIrp minor code = %#x\n",
1073 Irp
, irpStack
->MinorFunction
));
1078 if (irpStack
->Parameters
.Power
.Type
!= DevicePowerState
||
1079 irpStack
->MinorFunction
!= IRP_MN_SET_POWER
) {
1081 DebugPrint((1, "(%p)\tSending to lower device\n", Irp
));
1083 goto ClasspPowerHandlerCleanup
;
1087 nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
1090 // already in exact same state, don't work to transition to it.
1093 if(irpStack
->Parameters
.Power
.State
.DeviceState
==
1094 fdoExtension
->DevicePowerState
) {
1096 DebugPrint((1, "(%p)\tAlready in device state %x\n",
1097 Irp
, fdoExtension
->DevicePowerState
));
1098 goto ClasspPowerHandlerCleanup
;
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
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
;
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.
1124 if((irpStack
->Parameters
.Power
.State
.DeviceState
== PowerDeviceD3
) &&
1125 (irpStack
->Parameters
.Power
.ShutdownType
== PowerActionHibernate
) &&
1126 (commonExtension
->HibernationPathCount
!= 0)) {
1128 DebugPrint((1, "(%p)\tdoing nothing for hibernation request for "
1130 Irp
, fdoExtension
->DevicePowerState
));
1131 fdoExtension
->DevicePowerState
=
1132 irpStack
->Parameters
.Power
.State
.DeviceState
;
1133 goto ClasspPowerHandlerCleanup
;
1136 // or when not handling powering up and are powering up
1139 if ((!Options
.HandleSpinUp
) &&
1140 (irpStack
->Parameters
.Power
.State
.DeviceState
== PowerDeviceD0
)) {
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
;
1151 // or when not handling powering down and are powering down
1154 if ((!Options
.HandleSpinDown
) &&
1155 (irpStack
->Parameters
.Power
.State
.DeviceState
!= PowerDeviceD0
)) {
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
;
1165 context
= &(fdoExtension
->PowerContext
);
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.
1173 ASSERT(context
->InUse
== FALSE
);
1176 RtlZeroMemory(context
, sizeof(CLASS_POWER_CONTEXT
));
1177 context
->InUse
= TRUE
;
1179 nextIrpStack
->Parameters
.Scsi
.Srb
= &(context
->Srb
);
1180 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
1182 context
->FinalStatus
= STATUS_SUCCESS
;
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
;
1190 context
->Srb
.SenseInfoBuffer
=
1191 commonExtension
->PartitionZeroExtension
->SenseData
;
1192 context
->Srb
.SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
1193 context
->RetryCount
= MAXIMUM_RETRIES
;
1195 context
->Options
= Options
;
1196 context
->DeviceObject
= DeviceObject
;
1199 if(irpStack
->Parameters
.Power
.State
.DeviceState
== PowerDeviceD0
) {
1201 ASSERT(Options
.HandleSpinUp
);
1203 DebugPrint((2, "(%p)\tpower up - locking queue\n", Irp
));
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.
1211 context
->Options
.PowerDown
= FALSE
;
1212 context
->PowerChangeState
.PowerUp
= PowerUpDeviceInitial
;
1213 context
->CompletionRoutine
= ClasspPowerUpCompletion
;
1217 ASSERT(Options
.HandleSpinDown
);
1219 fdoExtension
->PowerDownInProgress
= TRUE
;
1221 DebugPrint((2, "(%p)\tPowering down - locking queue\n", Irp
));
1223 PoSetPowerState(DeviceObject
,
1224 irpStack
->Parameters
.Power
.Type
,
1225 irpStack
->Parameters
.Power
.State
);
1227 context
->Options
.PowerDown
= TRUE
;
1228 context
->PowerChangeState
.PowerDown2
= PowerDownDeviceInitial2
;
1229 context
->CompletionRoutine
= ClasspPowerDownCompletion
;
1234 // we are not dealing with port-allocated sense in these routines.
1237 ASSERT(!TEST_FLAG(context
->Srb
.SrbFlags
, SRB_FLAGS_FREE_SENSE_BUFFER
));
1238 ASSERT(!TEST_FLAG(context
->Srb
.SrbFlags
, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE
));
1241 // we are always returning STATUS_PENDING, so we need to always
1242 // set the irp as pending.
1245 IoMarkIrpPending(Irp
);
1247 if(Options
.LockQueue
) {
1250 // Send the lock irp down.
1253 IoSetCompletionRoutine(Irp
,
1254 context
->CompletionRoutine
,
1260 IoCallDriver(lowerDevice
, Irp
);
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.
1270 context
->CompletionRoutine(DeviceObject
, Irp
, context
);
1273 return STATUS_PENDING
;
1275 ClasspPowerHandlerCleanup
:
1277 ClassReleaseRemoveLock(DeviceObject
, Irp
);
1279 DebugPrint((1, "(%p)\tStarting next power irp\n", Irp
));
1280 IoCopyCurrentIrpStackLocationToNext(Irp
);
1281 IoSetCompletionRoutine(Irp
,
1282 ClasspStartNextPowerIrpCompletion
,
1287 return PoCallDriver(lowerDevice
, Irp
);
1288 } // end ClasspPowerHandler()
1290 /*++////////////////////////////////////////////////////////////////////////////
1292 ClassMinimalPowerHandler()
1294 Routine Description:
1296 This routine is the minimum power handler for a storage driver. It does
1297 the least amount of work possible.
1302 ClassMinimalPowerHandler(
1303 IN PDEVICE_OBJECT DeviceObject
,
1307 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
1308 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
1311 ClassReleaseRemoveLock(DeviceObject
, Irp
);
1312 PoStartNextPowerIrp(Irp
);
1314 if(commonExtension
->IsFdo
) {
1316 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
1318 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
=
1319 DeviceObject
->DeviceExtension
;
1322 // Check if the system is going to hibernate or standby.
1324 if (irpStack
->MinorFunction
== IRP_MN_SET_POWER
){
1327 switch (irpStack
->Parameters
.Power
.ShutdownType
){
1329 case PowerActionSleep
:
1330 case PowerActionHibernate
:
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.
1336 vpb
= ClassGetVpb(fdoExtension
->DeviceObject
);
1337 if (vpb
&& (vpb
->Flags
& VPB_MOUNTED
)){
1338 SET_FLAG(fdoExtension
->DeviceObject
->Flags
, DO_VERIFY_VOLUME
);
1347 IoCopyCurrentIrpStackLocationToNext(Irp
);
1348 return PoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
1352 if (irpStack
->MinorFunction
!= IRP_MN_SET_POWER
&&
1353 irpStack
->MinorFunction
!= IRP_MN_QUERY_POWER
) {
1359 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1360 Irp
->IoStatus
.Information
= 0;
1363 status
= Irp
->IoStatus
.Status
;
1365 ClassCompleteRequest(DeviceObject
, Irp
, IO_NO_INCREMENT
);
1368 } // end ClassMinimalPowerHandler()
1370 /*++////////////////////////////////////////////////////////////////////////////
1372 ClassSpinDownPowerHandler()
1374 Routine Description:
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).
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
1387 DeviceObject - Supplies the functional device object
1389 Irp - Supplies the request to be retried.
1398 ClassSpinDownPowerHandler(
1399 IN PDEVICE_OBJECT DeviceObject
,
1403 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
;
1404 CLASS_POWER_OPTIONS options
;
1406 fdoExtension
= (PFUNCTIONAL_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
1409 // this will set all options to FALSE
1412 RtlZeroMemory(&options
, sizeof(CLASS_POWER_OPTIONS
));
1415 // check the flags to see what options we need to worry about
1418 if (!TEST_FLAG(fdoExtension
->ScanForSpecialFlags
,
1419 CLASS_SPECIAL_DISABLE_SPIN_DOWN
)) {
1420 options
.HandleSpinDown
= TRUE
;
1423 if (!TEST_FLAG(fdoExtension
->ScanForSpecialFlags
,
1424 CLASS_SPECIAL_DISABLE_SPIN_UP
)) {
1425 options
.HandleSpinUp
= TRUE
;
1428 if (!TEST_FLAG(fdoExtension
->ScanForSpecialFlags
,
1429 CLASS_SPECIAL_NO_QUEUE_LOCK
)) {
1430 options
.LockQueue
= TRUE
;
1433 DebugPrint((3, "ClasspPowerHandler: Devobj %p\n"
1434 "\t%shandling spin down\n"
1435 "\t%shandling spin up\n"
1436 "\t%slocking queue\n",
1438 (options
.HandleSpinDown
? "" : "not "),
1439 (options
.HandleSpinUp
? "" : "not "),
1440 (options
.LockQueue
? "" : "not ")
1444 // do all the dirty work
1447 return ClasspPowerHandler(DeviceObject
, Irp
, options
);
1448 } // end ClassSpinDownPowerHandler()
1450 /*++////////////////////////////////////////////////////////////////////////////
1452 ClassStopUnitPowerHandler()
1454 Routine Description:
1456 This routine is an outdated call. To achieve equivalent functionality,
1457 the driver should set the following flags in ScanForSpecialFlags in the
1460 CLASS_SPECIAL_DISABLE_SPIN_UP
1461 CLASS_SPECIAL_NO_QUEUE_LOCK
1466 ClassStopUnitPowerHandler(
1467 IN PDEVICE_OBJECT DeviceObject
,
1471 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
;
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",
1482 fdoExtension
= (PFUNCTIONAL_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
1484 SET_FLAG(fdoExtension
->ScanForSpecialFlags
,
1485 CLASS_SPECIAL_DISABLE_SPIN_UP
);
1486 SET_FLAG(fdoExtension
->ScanForSpecialFlags
,
1487 CLASS_SPECIAL_NO_QUEUE_LOCK
);
1489 return ClassSpinDownPowerHandler(DeviceObject
, Irp
);
1490 } // end ClassStopUnitPowerHandler()
1492 /*++////////////////////////////////////////////////////////////////////////////
1496 Routine Description:
1498 This routine reinitializes the necessary fields, and sends the request
1499 to the lower driver.
1503 DeviceObject - Supplies the device object associated with this request.
1505 Irp - Supplies the request to be retried.
1507 Context - Supplies a pointer to the power up context for this request.
1517 PDEVICE_OBJECT DeviceObject
,
1519 PCLASS_POWER_CONTEXT Context
1522 PIO_STACK_LOCATION nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
1523 PSCSI_REQUEST_BLOCK srb
= &(Context
->Srb
);
1524 LARGE_INTEGER dueTime
;
1526 DebugPrint((1, "(%p)\tDelaying retry by queueing DPC\n", Irp
));
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
));
1534 // reset the retry interval
1537 Context
->RetryInterval
= 0;
1540 // Reset byte count of transfer in SRB Extension.
1543 srb
->DataTransferLength
= 0;
1546 // Zero SRB statuses.
1549 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
1552 // Set up major SCSI function.
1555 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
1558 // Save SRB address in next stack for port driver.
1561 nextIrpStack
->Parameters
.Scsi
.Srb
= srb
;
1564 // Set the completion routine up again.
1567 IoSetCompletionRoutine(Irp
, Context
->CompletionRoutine
, Context
,
1571 if (Context
->RetryInterval
== 0) {
1573 DebugPrint((2, "(%p)\tDelaying minimum time (.2 sec)\n", Irp
));
1574 dueTime
.QuadPart
= (LONGLONG
)1000000 * 2;
1578 DebugPrint((2, "(%p)\tDelaying %x seconds\n",
1579 Irp
, Context
->RetryInterval
));
1580 dueTime
.QuadPart
= (LONGLONG
)1000000 * 10 * Context
->RetryInterval
;
1584 ClassRetryRequest(DeviceObject
, Irp
, dueTime
);
1588 } // end RetryRequest()
1590 /*++////////////////////////////////////////////////////////////////////////////
1592 ClasspStartNextPowerIrpCompletion()
1594 Routine Description:
1596 This routine guarantees that the next power irp (power up or down) is not
1597 sent until the previous one has fully completed.
1602 ClasspStartNextPowerIrpCompletion(
1603 IN PDEVICE_OBJECT DeviceObject
,
1608 if(Irp
->PendingReturned
) {
1609 IoMarkIrpPending(Irp
);
1612 PoStartNextPowerIrp(Irp
);
1613 return STATUS_SUCCESS
;
1614 } // end ClasspStartNextPowerIrpCompletion()