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
38 ClasspPowerDownCompletion(
39 IN PDEVICE_OBJECT DeviceObject
,
41 IN PCLASS_POWER_CONTEXT Context
46 ClasspPowerUpCompletion(
47 IN PDEVICE_OBJECT DeviceObject
,
49 IN PCLASS_POWER_CONTEXT Context
55 PDEVICE_OBJECT DeviceObject
,
57 PCLASS_POWER_CONTEXT Context
62 ClasspStartNextPowerIrpCompletion(
63 IN PDEVICE_OBJECT DeviceObject
,
69 /*++////////////////////////////////////////////////////////////////////////////
75 This routine acquires the removelock for the irp and then calls the
76 appropriate power callback.
89 IN PDEVICE_OBJECT DeviceObject
,
93 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
95 PCLASS_POWER_DEVICE powerRoutine
= NULL
;
98 // NOTE: This code may be called at PASSIVE or DISPATCH, depending
99 // upon the device object it is being called for.
100 // don't do anything that would break under either circumstance.
105 isRemoved
= ClassAcquireRemoveLock(DeviceObject
, Irp
);
108 ClassReleaseRemoveLock(DeviceObject
, Irp
);
109 Irp
->IoStatus
.Status
= STATUS_DEVICE_DOES_NOT_EXIST
;
110 PoStartNextPowerIrp(Irp
);
111 ClassCompleteRequest(DeviceObject
, Irp
, IO_NO_INCREMENT
);
112 return STATUS_DEVICE_DOES_NOT_EXIST
;
115 return commonExtension
->DevInfo
->ClassPowerDevice(DeviceObject
, Irp
);
116 } // end ClassDispatchPower()
118 /*++////////////////////////////////////////////////////////////////////////////
120 ClasspPowerUpCompletion()
124 This routine is used for intermediate completion of a power up request.
125 PowerUp requires four requests to be sent to the lower driver in sequence.
127 * The queue is "power locked" to ensure that the class driver power-up
128 work can be done before request processing resumes.
130 * The power irp is sent down the stack for any filter drivers and the
131 port driver to return power and resume command processing for the
132 device. Since the queue is locked, no queued irps will be sent
135 * A start unit command is issued to the device with appropriate flags
136 to override the "power locked" queue.
138 * The queue is "power unlocked" to start processing requests again.
140 This routine uses the function in the srb which just completed to determine
141 which state it is in.
145 DeviceObject - the device object being powered up
147 Irp - the IO_REQUEST_PACKET containing the power request
149 Srb - the SRB used to perform port/class operations.
153 STATUS_MORE_PROCESSING_REQUIRED or
159 ClasspPowerUpCompletion(
160 IN PDEVICE_OBJECT DeviceObject
,
162 IN PCLASS_POWER_CONTEXT Context
165 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
166 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
168 PIO_STACK_LOCATION currentStack
= IoGetCurrentIrpStackLocation(Irp
);
169 PIO_STACK_LOCATION nextStack
= IoGetNextIrpStackLocation(Irp
);
172 NTSTATUS status
= STATUS_MORE_PROCESSING_REQUIRED
;
174 DebugPrint((1, "ClasspPowerUpCompletion: Device Object %p, Irp %p, "
176 DeviceObject
, Irp
, Context
));
178 ASSERT(!TEST_FLAG(Context
->Srb
.SrbFlags
, SRB_FLAGS_FREE_SENSE_BUFFER
));
179 ASSERT(!TEST_FLAG(Context
->Srb
.SrbFlags
, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE
));
180 ASSERT(Context
->Options
.PowerDown
== FALSE
);
181 ASSERT(Context
->Options
.HandleSpinUp
);
183 if(Irp
->PendingReturned
) {
184 IoMarkIrpPending(Irp
);
187 Context
->PowerChangeState
.PowerUp
++;
189 switch(Context
->PowerChangeState
.PowerUp
) {
191 case PowerUpDeviceLocked
: {
193 DebugPrint((1, "(%p)\tPreviously sent power lock\n", Irp
));
196 // Issue the actual power request to the lower driver.
199 IoCopyCurrentIrpStackLocationToNext(Irp
);
202 // If the lock wasn't successful then just bail out on the power
203 // request unless we can ignore failed locks
206 if((Context
->Options
.LockQueue
== TRUE
) &&
207 (!NT_SUCCESS(Irp
->IoStatus
.Status
))) {
209 DebugPrint((1, "(%p)\tIrp status was %lx\n",
210 Irp
, Irp
->IoStatus
.Status
));
211 DebugPrint((1, "(%p)\tSrb status was %lx\n",
212 Irp
, Context
->Srb
.SrbStatus
));
215 // Lock was not successful - throw down the power IRP
216 // by itself and don't try to spin up the drive or unlock
220 Context
->InUse
= FALSE
;
224 // Set the new power state
227 fdoExtension
->DevicePowerState
=
228 currentStack
->Parameters
.Power
.State
.DeviceState
;
230 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
232 IoCopyCurrentIrpStackLocationToNext(Irp
);
234 IoSetCompletionRoutine(Irp
,
235 ClasspStartNextPowerIrpCompletion
,
242 // Indicate to Po that we've been successfully powered up so
243 // it can do it's notification stuff.
246 PoSetPowerState(DeviceObject
,
247 currentStack
->Parameters
.Power
.Type
,
248 currentStack
->Parameters
.Power
.State
);
250 PoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
252 ClassReleaseRemoveLock(commonExtension
->DeviceObject
,
255 return STATUS_MORE_PROCESSING_REQUIRED
;
258 Context
->QueueLocked
= (UCHAR
) Context
->Options
.LockQueue
;
261 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
263 Context
->PowerChangeState
.PowerUp
= PowerUpDeviceLocked
;
265 IoSetCompletionRoutine(Irp
,
266 ClasspPowerUpCompletion
,
272 status
= PoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
274 DebugPrint((2, "(%p)\tPoCallDriver returned %lx\n", Irp
, status
));
278 case PowerUpDeviceOn
: {
282 if(NT_SUCCESS(Irp
->IoStatus
.Status
)) {
284 DebugPrint((1, "(%p)\tSending start unit to device\n", Irp
));
287 // Issue the start unit command to the device.
290 Context
->Srb
.Length
= sizeof(SCSI_REQUEST_BLOCK
);
291 Context
->Srb
.Function
= SRB_FUNCTION_EXECUTE_SCSI
;
293 Context
->Srb
.SrbStatus
= Context
->Srb
.ScsiStatus
= 0;
294 Context
->Srb
.DataTransferLength
= 0;
296 Context
->Srb
.TimeOutValue
= START_UNIT_TIMEOUT
;
298 Context
->Srb
.SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
|
299 SRB_FLAGS_DISABLE_AUTOSENSE
|
300 SRB_FLAGS_DISABLE_SYNCH_TRANSFER
|
301 SRB_FLAGS_NO_QUEUE_FREEZE
;
303 if(Context
->Options
.LockQueue
) {
304 SET_FLAG(Context
->Srb
.SrbFlags
, SRB_FLAGS_BYPASS_LOCKED_QUEUE
);
307 Context
->Srb
.CdbLength
= 6;
309 cdb
= (PCDB
) (Context
->Srb
.Cdb
);
310 RtlZeroMemory(cdb
, sizeof(CDB
));
313 cdb
->START_STOP
.OperationCode
= SCSIOP_START_STOP_UNIT
;
314 cdb
->START_STOP
.Start
= 1;
316 Context
->PowerChangeState
.PowerUp
= PowerUpDeviceOn
;
318 IoSetCompletionRoutine(Irp
,
319 ClasspPowerUpCompletion
,
325 nextStack
->Parameters
.Scsi
.Srb
= &(Context
->Srb
);
326 nextStack
->MajorFunction
= IRP_MJ_SCSI
;
328 status
= IoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
330 DebugPrint((2, "(%p)\tIoCallDriver returned %lx\n", Irp
, status
));
338 Context
->FinalStatus
= Irp
->IoStatus
.Status
;
339 goto ClasspPowerUpCompletionFailure
;
345 case PowerUpDeviceStarted
: { // 3
348 // First deal with an error if one occurred.
351 if(SRB_STATUS(Context
->Srb
.SrbStatus
) != SRB_STATUS_SUCCESS
) {
355 DebugPrint((1, "%p\tError occured when issuing START_UNIT "
356 "command to device. Srb %p, Status %x\n",
359 Context
->Srb
.SrbStatus
));
361 ASSERT(!(TEST_FLAG(Context
->Srb
.SrbStatus
,
362 SRB_STATUS_QUEUE_FROZEN
)));
363 ASSERT(Context
->Srb
.Function
== SRB_FUNCTION_EXECUTE_SCSI
);
365 Context
->RetryInterval
= 0;
367 retry
= ClassInterpretSenseInfo(
368 commonExtension
->DeviceObject
,
372 MAXIMUM_RETRIES
- Context
->RetryCount
,
374 &Context
->RetryInterval
);
376 if((retry
== TRUE
) && (Context
->RetryCount
-- != 0)) {
378 DebugPrint((1, "(%p)\tRetrying failed request\n", Irp
));
381 // Decrement the state so we come back through here the
385 Context
->PowerChangeState
.PowerUp
--;
387 RetryPowerRequest(commonExtension
->DeviceObject
,
396 Context
->RetryCount
= MAXIMUM_RETRIES
;
400 ClasspPowerUpCompletionFailure
:
402 DebugPrint((1, "(%p)\tPreviously spun device up\n", Irp
));
404 if (Context
->QueueLocked
) {
405 DebugPrint((1, "(%p)\tUnlocking queue\n", Irp
));
407 Context
->Srb
.Function
= SRB_FUNCTION_UNLOCK_QUEUE
;
408 Context
->Srb
.SrbFlags
= SRB_FLAGS_BYPASS_LOCKED_QUEUE
;
409 Context
->Srb
.SrbStatus
= Context
->Srb
.ScsiStatus
= 0;
410 Context
->Srb
.DataTransferLength
= 0;
412 nextStack
->Parameters
.Scsi
.Srb
= &(Context
->Srb
);
413 nextStack
->MajorFunction
= IRP_MJ_SCSI
;
415 Context
->PowerChangeState
.PowerUp
= PowerUpDeviceStarted
;
417 IoSetCompletionRoutine(Irp
,
418 ClasspPowerUpCompletion
,
424 status
= IoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
425 DebugPrint((1, "(%p)\tIoCallDriver returned %lx\n",
430 // Fall-through to next case...
434 case PowerUpDeviceUnlocked
: {
437 // This is the end of the dance. Free the srb and complete the
438 // request finally. We're ignoring possible intermediate
439 // error conditions ....
442 if (Context
->QueueLocked
) {
443 DebugPrint((1, "(%p)\tPreviously unlocked queue\n", Irp
));
444 ASSERT(NT_SUCCESS(Irp
->IoStatus
.Status
));
445 ASSERT(Context
->Srb
.SrbStatus
== SRB_STATUS_SUCCESS
);
447 DebugPrint((1, "(%p)\tFall-through (queue not locked)\n", Irp
));
450 DebugPrint((1, "(%p)\tFreeing srb and completing\n", Irp
));
451 Context
->InUse
= FALSE
;
453 status
= Context
->FinalStatus
;
454 Irp
->IoStatus
.Status
= status
;
459 // Set the new power state
462 if(NT_SUCCESS(status
)) {
463 fdoExtension
->DevicePowerState
=
464 currentStack
->Parameters
.Power
.State
.DeviceState
;
468 // Indicate to Po that we've been successfully powered up so
469 // it can do it's notification stuff.
472 PoSetPowerState(DeviceObject
,
473 currentStack
->Parameters
.Power
.Type
,
474 currentStack
->Parameters
.Power
.State
);
476 DebugPrint((1, "(%p)\tStarting next power irp\n", Irp
));
477 ClassReleaseRemoveLock(DeviceObject
, Irp
);
478 PoStartNextPowerIrp(Irp
);
484 return STATUS_MORE_PROCESSING_REQUIRED
;
485 } // end ClasspPowerUpCompletion()
487 /*++////////////////////////////////////////////////////////////////////////////
489 ClasspPowerDownCompletion()
493 This routine is used for intermediate completion of a power up request.
494 PowerUp requires four requests to be sent to the lower driver in sequence.
496 * The queue is "power locked" to ensure that the class driver power-up
497 work can be done before request processing resumes.
499 * The power irp is sent down the stack for any filter drivers and the
500 port driver to return power and resume command processing for the
501 device. Since the queue is locked, no queued irps will be sent
504 * A start unit command is issued to the device with appropriate flags
505 to override the "power locked" queue.
507 * The queue is "power unlocked" to start processing requests again.
509 This routine uses the function in the srb which just completed to determine
510 which state it is in.
514 DeviceObject - the device object being powered up
516 Irp - the IO_REQUEST_PACKET containing the power request
518 Srb - the SRB used to perform port/class operations.
522 STATUS_MORE_PROCESSING_REQUIRED or
528 ClasspPowerDownCompletion(
529 IN PDEVICE_OBJECT DeviceObject
,
531 IN PCLASS_POWER_CONTEXT Context
534 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
535 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
537 PIO_STACK_LOCATION currentStack
= IoGetCurrentIrpStackLocation(Irp
);
538 PIO_STACK_LOCATION nextStack
= IoGetNextIrpStackLocation(Irp
);
540 NTSTATUS status
= STATUS_MORE_PROCESSING_REQUIRED
;
542 DebugPrint((1, "ClasspPowerDownCompletion: Device Object %p, "
543 "Irp %p, Context %p\n",
544 DeviceObject
, Irp
, Context
));
546 ASSERT(!TEST_FLAG(Context
->Srb
.SrbFlags
, SRB_FLAGS_FREE_SENSE_BUFFER
));
547 ASSERT(!TEST_FLAG(Context
->Srb
.SrbFlags
, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE
));
548 ASSERT(Context
->Options
.PowerDown
== TRUE
);
549 ASSERT(Context
->Options
.HandleSpinDown
);
551 if(Irp
->PendingReturned
) {
552 IoMarkIrpPending(Irp
);
555 Context
->PowerChangeState
.PowerDown2
++;
557 switch(Context
->PowerChangeState
.PowerDown2
) {
559 case PowerDownDeviceLocked2
: {
563 DebugPrint((1, "(%p)\tPreviously sent power lock\n", Irp
));
565 if((Context
->Options
.LockQueue
== TRUE
) &&
566 (!NT_SUCCESS(Irp
->IoStatus
.Status
))) {
568 DebugPrint((1, "(%p)\tIrp status was %lx\n",
570 Irp
->IoStatus
.Status
));
571 DebugPrint((1, "(%p)\tSrb status was %lx\n",
573 Context
->Srb
.SrbStatus
));
575 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
578 // Lock was not successful - throw down the power IRP
579 // by itself and don't try to spin down the drive or unlock
583 Context
->InUse
= FALSE
;
587 // Set the new power state
590 fdoExtension
->DevicePowerState
=
591 currentStack
->Parameters
.Power
.State
.DeviceState
;
594 // Indicate to Po that we've been successfully powered down
595 // so it can do it's notification stuff.
598 IoCopyCurrentIrpStackLocationToNext(Irp
);
599 IoSetCompletionRoutine(Irp
,
600 ClasspStartNextPowerIrpCompletion
,
606 PoSetPowerState(DeviceObject
,
607 currentStack
->Parameters
.Power
.Type
,
608 currentStack
->Parameters
.Power
.State
);
610 fdoExtension
->PowerDownInProgress
= FALSE
;
612 PoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
614 ClassReleaseRemoveLock(commonExtension
->DeviceObject
,
617 return STATUS_MORE_PROCESSING_REQUIRED
;
620 Context
->QueueLocked
= (UCHAR
) Context
->Options
.LockQueue
;
623 if (!TEST_FLAG(fdoExtension
->PrivateFdoData
->HackFlags
,
624 FDO_HACK_NO_SYNC_CACHE
)) {
627 // send SCSIOP_SYNCHRONIZE_CACHE
630 Context
->Srb
.Length
= sizeof(SCSI_REQUEST_BLOCK
);
631 Context
->Srb
.Function
= SRB_FUNCTION_EXECUTE_SCSI
;
633 Context
->Srb
.TimeOutValue
= fdoExtension
->TimeOutValue
;
635 Context
->Srb
.SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
|
636 SRB_FLAGS_DISABLE_AUTOSENSE
|
637 SRB_FLAGS_DISABLE_SYNCH_TRANSFER
|
638 SRB_FLAGS_NO_QUEUE_FREEZE
|
639 SRB_FLAGS_BYPASS_LOCKED_QUEUE
;
641 Context
->Srb
.SrbStatus
= Context
->Srb
.ScsiStatus
= 0;
642 Context
->Srb
.DataTransferLength
= 0;
644 Context
->Srb
.CdbLength
= 10;
646 cdb
= (PCDB
) Context
->Srb
.Cdb
;
648 RtlZeroMemory(cdb
, sizeof(CDB
));
649 cdb
->SYNCHRONIZE_CACHE10
.OperationCode
= SCSIOP_SYNCHRONIZE_CACHE
;
651 IoSetCompletionRoutine(Irp
,
652 ClasspPowerDownCompletion
,
658 nextStack
->Parameters
.Scsi
.Srb
= &(Context
->Srb
);
659 nextStack
->MajorFunction
= IRP_MJ_SCSI
;
661 status
= IoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
663 DebugPrint((1, "(%p)\tIoCallDriver returned %lx\n", Irp
, status
));
668 DebugPrint((1, "(%p)\tPower Down: not sending SYNCH_CACHE\n",
670 Context
->PowerChangeState
.PowerDown2
++;
671 Context
->Srb
.SrbStatus
= SRB_STATUS_SUCCESS
;
672 // and fall through....
674 // no break in case the device doesn't like synch_cache commands
678 case PowerDownDeviceFlushed2
: {
682 DebugPrint((1, "(%p)\tPreviously send SCSIOP_SYNCHRONIZE_CACHE\n",
686 // SCSIOP_SYNCHRONIZE_CACHE was sent
689 if(SRB_STATUS(Context
->Srb
.SrbStatus
) != SRB_STATUS_SUCCESS
) {
693 DebugPrint((1, "(%p)\tError occured when issuing "
694 "SYNCHRONIZE_CACHE command to device. "
695 "Srb %p, Status %lx\n",
698 Context
->Srb
.SrbStatus
));
700 ASSERT(!(TEST_FLAG(Context
->Srb
.SrbStatus
,
701 SRB_STATUS_QUEUE_FROZEN
)));
702 ASSERT(Context
->Srb
.Function
== SRB_FUNCTION_EXECUTE_SCSI
);
704 Context
->RetryInterval
= 0;
705 retry
= ClassInterpretSenseInfo(
706 commonExtension
->DeviceObject
,
710 MAXIMUM_RETRIES
- Context
->RetryCount
,
712 &Context
->RetryInterval
);
714 if((retry
== TRUE
) && (Context
->RetryCount
-- != 0)) {
716 DebugPrint((1, "(%p)\tRetrying failed request\n", Irp
));
719 // decrement the state so we come back through here
723 Context
->PowerChangeState
.PowerDown2
--;
724 RetryPowerRequest(commonExtension
->DeviceObject
,
730 DebugPrint((1, "(%p)\tSYNCHRONIZE_CACHE not retried\n", Irp
));
731 Context
->RetryCount
= MAXIMUM_RETRIES
;
733 } // end !SRB_STATUS_SUCCESS
736 // note: we are purposefully ignoring any errors. if the drive
737 // doesn't support a synch_cache, then we're up a creek
741 DebugPrint((1, "(%p)\tSending stop unit to device\n", Irp
));
744 // Issue the start unit command to the device.
747 Context
->Srb
.Length
= sizeof(SCSI_REQUEST_BLOCK
);
748 Context
->Srb
.Function
= SRB_FUNCTION_EXECUTE_SCSI
;
750 Context
->Srb
.TimeOutValue
= START_UNIT_TIMEOUT
;
752 Context
->Srb
.SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
|
753 SRB_FLAGS_DISABLE_AUTOSENSE
|
754 SRB_FLAGS_DISABLE_SYNCH_TRANSFER
|
755 SRB_FLAGS_NO_QUEUE_FREEZE
|
756 SRB_FLAGS_BYPASS_LOCKED_QUEUE
;
758 Context
->Srb
.SrbStatus
= Context
->Srb
.ScsiStatus
= 0;
759 Context
->Srb
.DataTransferLength
= 0;
761 Context
->Srb
.CdbLength
= 6;
763 cdb
= (PCDB
) Context
->Srb
.Cdb
;
764 RtlZeroMemory(cdb
, sizeof(CDB
));
766 cdb
->START_STOP
.OperationCode
= SCSIOP_START_STOP_UNIT
;
767 cdb
->START_STOP
.Start
= 0;
768 cdb
->START_STOP
.Immediate
= 1;
770 IoSetCompletionRoutine(Irp
,
771 ClasspPowerDownCompletion
,
777 nextStack
->Parameters
.Scsi
.Srb
= &(Context
->Srb
);
778 nextStack
->MajorFunction
= IRP_MJ_SCSI
;
780 status
= IoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
782 DebugPrint((1, "(%p)\tIoCallDriver returned %lx\n", Irp
, status
));
787 case PowerDownDeviceStopped2
: {
789 BOOLEAN ignoreError
= TRUE
;
795 if(SRB_STATUS(Context
->Srb
.SrbStatus
) != SRB_STATUS_SUCCESS
) {
799 DebugPrint((1, "(%p)\tError occured when issueing STOP_UNIT "
800 "command to device. Srb %p, Status %lx\n",
803 Context
->Srb
.SrbStatus
));
805 ASSERT(!(TEST_FLAG(Context
->Srb
.SrbStatus
,
806 SRB_STATUS_QUEUE_FROZEN
)));
807 ASSERT(Context
->Srb
.Function
== SRB_FUNCTION_EXECUTE_SCSI
);
809 Context
->RetryInterval
= 0;
810 retry
= ClassInterpretSenseInfo(
811 commonExtension
->DeviceObject
,
815 MAXIMUM_RETRIES
- Context
->RetryCount
,
817 &Context
->RetryInterval
);
819 if((retry
== TRUE
) && (Context
->RetryCount
-- != 0)) {
821 DebugPrint((1, "(%p)\tRetrying failed request\n", Irp
));
824 // decrement the state so we come back through here
828 Context
->PowerChangeState
.PowerDown2
--;
829 RetryPowerRequest(commonExtension
->DeviceObject
,
835 DebugPrint((1, "(%p)\tSTOP_UNIT not retried\n", Irp
));
836 Context
->RetryCount
= MAXIMUM_RETRIES
;
838 } // end !SRB_STATUS_SUCCESS
841 DebugPrint((1, "(%p)\tPreviously sent stop unit\n", Irp
));
844 // some operations, such as a physical format in progress,
845 // should not be ignored and should fail the power operation.
848 if (!NT_SUCCESS(status
)) {
850 PSENSE_DATA senseBuffer
= Context
->Srb
.SenseInfoBuffer
;
852 if (TEST_FLAG(Context
->Srb
.SrbStatus
,
853 SRB_STATUS_AUTOSENSE_VALID
) &&
854 ((senseBuffer
->SenseKey
& 0xf) == SCSI_SENSE_NOT_READY
) &&
855 (senseBuffer
->AdditionalSenseCode
== SCSI_ADSENSE_LUN_NOT_READY
) &&
856 (senseBuffer
->AdditionalSenseCodeQualifier
== SCSI_SENSEQ_FORMAT_IN_PROGRESS
)
859 Context
->FinalStatus
= STATUS_DEVICE_BUSY
;
860 status
= Context
->FinalStatus
;
865 if (NT_SUCCESS(status
) || ignoreError
) {
868 // Issue the actual power request to the lower driver.
871 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
873 IoCopyCurrentIrpStackLocationToNext(Irp
);
875 IoSetCompletionRoutine(Irp
,
876 ClasspPowerDownCompletion
,
882 status
= PoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
884 DebugPrint((1, "(%p)\tPoCallDriver returned %lx\n", Irp
, status
));
888 // else fall through w/o sending the power irp, since the device
889 // is reporting an error that would be "really bad" to power down
894 case PowerDownDeviceOff2
: {
897 // SpinDown request completed ... whether it succeeded or not is
898 // another matter entirely.
901 DebugPrint((1, "(%p)\tPreviously sent power irp\n", Irp
));
903 if (Context
->QueueLocked
) {
905 DebugPrint((1, "(%p)\tUnlocking queue\n", Irp
));
907 Context
->Srb
.Length
= sizeof(SCSI_REQUEST_BLOCK
);
909 Context
->Srb
.SrbStatus
= Context
->Srb
.ScsiStatus
= 0;
910 Context
->Srb
.DataTransferLength
= 0;
912 Context
->Srb
.Function
= SRB_FUNCTION_UNLOCK_QUEUE
;
913 Context
->Srb
.SrbFlags
= SRB_FLAGS_BYPASS_LOCKED_QUEUE
;
914 nextStack
->Parameters
.Scsi
.Srb
= &(Context
->Srb
);
915 nextStack
->MajorFunction
= IRP_MJ_SCSI
;
917 IoSetCompletionRoutine(Irp
,
918 ClasspPowerDownCompletion
,
924 status
= IoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
925 DebugPrint((1, "(%p)\tIoCallDriver returned %lx\n",
933 case PowerDownDeviceUnlocked2
: {
936 // This is the end of the dance. Free the srb and complete the
937 // request finally. We're ignoring possible intermediate
938 // error conditions ....
941 if (Context
->QueueLocked
== FALSE
) {
942 DebugPrint((1, "(%p)\tFall through (queue not locked)\n", Irp
));
944 DebugPrint((1, "(%p)\tPreviously unlocked queue\n", Irp
));
945 ASSERT(NT_SUCCESS(Irp
->IoStatus
.Status
));
946 ASSERT(Context
->Srb
.SrbStatus
== SRB_STATUS_SUCCESS
);
949 DebugPrint((1, "(%p)\tFreeing srb and completing\n", Irp
));
950 Context
->InUse
= FALSE
;
951 status
= Context
->FinalStatus
; // allow failure to propogate
954 if(Irp
->PendingReturned
) {
955 IoMarkIrpPending(Irp
);
958 Irp
->IoStatus
.Status
= status
;
959 Irp
->IoStatus
.Information
= 0;
961 if (NT_SUCCESS(status
)) {
964 // Set the new power state
967 fdoExtension
->DevicePowerState
=
968 currentStack
->Parameters
.Power
.State
.DeviceState
;
973 DebugPrint((1, "(%p)\tStarting next power irp\n", Irp
));
975 ClassReleaseRemoveLock(DeviceObject
, Irp
);
976 PoStartNextPowerIrp(Irp
);
977 fdoExtension
->PowerDownInProgress
= FALSE
;
983 return STATUS_MORE_PROCESSING_REQUIRED
;
984 } // end ClasspPowerDownCompletion()
986 /*++////////////////////////////////////////////////////////////////////////////
992 This routine reduces the number of useless spinups and spindown requests
993 sent to a given device by ignoring transitions to power states we are
996 ISSUE-2000/02/20-henrygab - by ignoring spin-up requests, we may be
1001 DeviceObject - the device object which is transitioning power states
1003 Options - a set of flags indicating what the device handles
1011 IN PDEVICE_OBJECT DeviceObject
,
1013 IN CLASS_POWER_OPTIONS Options
// ISSUE-2000/02/20-henrygab - pass pointer, not whole struct
1016 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
1017 PDEVICE_OBJECT lowerDevice
= commonExtension
->LowerDeviceObject
;
1018 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
1019 PIO_STACK_LOCATION nextIrpStack
;
1020 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
1021 PCLASS_POWER_CONTEXT context
;
1023 if (!commonExtension
->IsFdo
) {
1026 // certain assumptions are made here,
1027 // particularly: having the fdoExtension
1030 DebugPrint((0, "ClasspPowerHandler: Called for PDO %p???\n",
1032 ASSERT(!"PDO using ClasspPowerHandler");
1033 return STATUS_NOT_SUPPORTED
;
1036 DebugPrint((1, "ClasspPowerHandler: Power irp %p to %s %p\n",
1037 Irp
, (commonExtension
->IsFdo
? "fdo" : "pdo"), DeviceObject
));
1039 switch(irpStack
->MinorFunction
) {
1041 case IRP_MN_SET_POWER
: {
1042 PCLASS_PRIVATE_FDO_DATA fdoData
= fdoExtension
->PrivateFdoData
;
1044 DebugPrint((1, "(%p)\tIRP_MN_SET_POWER\n", Irp
));
1046 DebugPrint((1, "(%p)\tSetting %s state to %d\n",
1048 (irpStack
->Parameters
.Power
.Type
== SystemPowerState
?
1049 "System" : "Device"),
1050 irpStack
->Parameters
.Power
.State
.SystemState
));
1052 switch (irpStack
->Parameters
.Power
.ShutdownType
){
1054 case PowerActionSleep
:
1055 case PowerActionHibernate
:
1056 if (fdoData
->HotplugInfo
.MediaRemovable
|| fdoData
->HotplugInfo
.MediaHotplug
){
1058 * We are suspending and this drive is either hot-pluggable
1059 * or contains removeable media.
1060 * Set the media dirty bit, since the media may change while
1063 SET_FLAG(DeviceObject
->Flags
, DO_VERIFY_VOLUME
);
1073 DebugPrint((1, "(%p)\tIrp minor code = %#x\n",
1074 Irp
, irpStack
->MinorFunction
));
1079 if (irpStack
->Parameters
.Power
.Type
!= DevicePowerState
||
1080 irpStack
->MinorFunction
!= IRP_MN_SET_POWER
) {
1082 DebugPrint((1, "(%p)\tSending to lower device\n", Irp
));
1084 goto ClasspPowerHandlerCleanup
;
1088 nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
1091 // already in exact same state, don't work to transition to it.
1094 if(irpStack
->Parameters
.Power
.State
.DeviceState
==
1095 fdoExtension
->DevicePowerState
) {
1097 DebugPrint((1, "(%p)\tAlready in device state %x\n",
1098 Irp
, fdoExtension
->DevicePowerState
));
1099 goto ClasspPowerHandlerCleanup
;
1104 // or powering down from non-d0 state (device already stopped)
1105 // NOTE -- we're not sure whether this case can exist or not (the
1106 // power system may never send this sort of request) but it's trivial
1110 if ((irpStack
->Parameters
.Power
.State
.DeviceState
!= PowerDeviceD0
) &&
1111 (fdoExtension
->DevicePowerState
!= PowerDeviceD0
)) {
1112 DebugPrint((1, "(%p)\tAlready powered down to %x???\n",
1113 Irp
, fdoExtension
->DevicePowerState
));
1114 fdoExtension
->DevicePowerState
=
1115 irpStack
->Parameters
.Power
.State
.DeviceState
;
1116 goto ClasspPowerHandlerCleanup
;
1120 // or going into a hibernation state when we're in the hibernation path.
1121 // If the device is spinning then we should leave it spinning - if it's not
1122 // then the dump driver will start it up for us.
1125 if((irpStack
->Parameters
.Power
.State
.DeviceState
== PowerDeviceD3
) &&
1126 (irpStack
->Parameters
.Power
.ShutdownType
== PowerActionHibernate
) &&
1127 (commonExtension
->HibernationPathCount
!= 0)) {
1129 DebugPrint((1, "(%p)\tdoing nothing for hibernation request for "
1131 Irp
, fdoExtension
->DevicePowerState
));
1132 fdoExtension
->DevicePowerState
=
1133 irpStack
->Parameters
.Power
.State
.DeviceState
;
1134 goto ClasspPowerHandlerCleanup
;
1137 // or when not handling powering up and are powering up
1140 if ((!Options
.HandleSpinUp
) &&
1141 (irpStack
->Parameters
.Power
.State
.DeviceState
== PowerDeviceD0
)) {
1143 DebugPrint((2, "(%p)\tNot handling spinup to state %x\n",
1144 Irp
, fdoExtension
->DevicePowerState
));
1145 fdoExtension
->DevicePowerState
=
1146 irpStack
->Parameters
.Power
.State
.DeviceState
;
1147 goto ClasspPowerHandlerCleanup
;
1152 // or when not handling powering down and are powering down
1155 if ((!Options
.HandleSpinDown
) &&
1156 (irpStack
->Parameters
.Power
.State
.DeviceState
!= PowerDeviceD0
)) {
1158 DebugPrint((2, "(%p)\tNot handling spindown to state %x\n",
1159 Irp
, fdoExtension
->DevicePowerState
));
1160 fdoExtension
->DevicePowerState
=
1161 irpStack
->Parameters
.Power
.State
.DeviceState
;
1162 goto ClasspPowerHandlerCleanup
;
1166 context
= &(fdoExtension
->PowerContext
);
1170 // Mark the context as in use. We should be synchronizing this but
1171 // since it's just for debugging purposes we don't worry too much.
1174 ASSERT(context
->InUse
== FALSE
);
1177 RtlZeroMemory(context
, sizeof(CLASS_POWER_CONTEXT
));
1178 context
->InUse
= TRUE
;
1180 nextIrpStack
->Parameters
.Scsi
.Srb
= &(context
->Srb
);
1181 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
1183 context
->FinalStatus
= STATUS_SUCCESS
;
1185 context
->Srb
.Length
= sizeof(SCSI_REQUEST_BLOCK
);
1186 context
->Srb
.OriginalRequest
= Irp
;
1187 context
->Srb
.SrbFlags
|= SRB_FLAGS_BYPASS_LOCKED_QUEUE
1188 | SRB_FLAGS_NO_QUEUE_FREEZE
;
1189 context
->Srb
.Function
= SRB_FUNCTION_LOCK_QUEUE
;
1191 context
->Srb
.SenseInfoBuffer
=
1192 commonExtension
->PartitionZeroExtension
->SenseData
;
1193 context
->Srb
.SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
1194 context
->RetryCount
= MAXIMUM_RETRIES
;
1196 context
->Options
= Options
;
1197 context
->DeviceObject
= DeviceObject
;
1200 if(irpStack
->Parameters
.Power
.State
.DeviceState
== PowerDeviceD0
) {
1202 ASSERT(Options
.HandleSpinUp
);
1204 DebugPrint((2, "(%p)\tpower up - locking queue\n", Irp
));
1207 // We need to issue a queue lock request so that we
1208 // can spin the drive back up after the power is restored
1209 // but before any requests are processed.
1212 context
->Options
.PowerDown
= FALSE
;
1213 context
->PowerChangeState
.PowerUp
= PowerUpDeviceInitial
;
1214 context
->CompletionRoutine
= ClasspPowerUpCompletion
;
1218 ASSERT(Options
.HandleSpinDown
);
1220 fdoExtension
->PowerDownInProgress
= TRUE
;
1222 DebugPrint((2, "(%p)\tPowering down - locking queue\n", Irp
));
1224 PoSetPowerState(DeviceObject
,
1225 irpStack
->Parameters
.Power
.Type
,
1226 irpStack
->Parameters
.Power
.State
);
1228 context
->Options
.PowerDown
= TRUE
;
1229 context
->PowerChangeState
.PowerDown2
= PowerDownDeviceInitial2
;
1230 context
->CompletionRoutine
= ClasspPowerDownCompletion
;
1235 // we are not dealing with port-allocated sense in these routines.
1238 ASSERT(!TEST_FLAG(context
->Srb
.SrbFlags
, SRB_FLAGS_FREE_SENSE_BUFFER
));
1239 ASSERT(!TEST_FLAG(context
->Srb
.SrbFlags
, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE
));
1242 // we are always returning STATUS_PENDING, so we need to always
1243 // set the irp as pending.
1246 IoMarkIrpPending(Irp
);
1248 if(Options
.LockQueue
) {
1251 // Send the lock irp down.
1254 IoSetCompletionRoutine(Irp
,
1255 context
->CompletionRoutine
,
1261 IoCallDriver(lowerDevice
, Irp
);
1266 // Call the completion routine directly. It won't care what the
1267 // status of the "lock" was - it will just go and do the next
1268 // step of the operation.
1271 context
->CompletionRoutine(DeviceObject
, Irp
, context
);
1274 return STATUS_PENDING
;
1276 ClasspPowerHandlerCleanup
:
1278 ClassReleaseRemoveLock(DeviceObject
, Irp
);
1280 DebugPrint((1, "(%p)\tStarting next power irp\n", Irp
));
1281 IoCopyCurrentIrpStackLocationToNext(Irp
);
1282 IoSetCompletionRoutine(Irp
,
1283 ClasspStartNextPowerIrpCompletion
,
1288 return PoCallDriver(lowerDevice
, Irp
);
1289 } // end ClasspPowerHandler()
1291 /*++////////////////////////////////////////////////////////////////////////////
1293 ClassMinimalPowerHandler()
1295 Routine Description:
1297 This routine is the minimum power handler for a storage driver. It does
1298 the least amount of work possible.
1303 ClassMinimalPowerHandler(
1304 IN PDEVICE_OBJECT DeviceObject
,
1308 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
1309 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
1312 ClassReleaseRemoveLock(DeviceObject
, Irp
);
1313 PoStartNextPowerIrp(Irp
);
1315 if(commonExtension
->IsFdo
) {
1317 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
1319 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
=
1320 DeviceObject
->DeviceExtension
;
1323 // Check if the system is going to hibernate or standby.
1325 if (irpStack
->MinorFunction
== IRP_MN_SET_POWER
){
1328 switch (irpStack
->Parameters
.Power
.ShutdownType
){
1330 case PowerActionSleep
:
1331 case PowerActionHibernate
:
1333 // If the volume is mounted, set the verify bit so that
1334 // the filesystem will be forced re-read the media
1335 // after coming out of hibernation or standby.
1337 vpb
= ClassGetVpb(fdoExtension
->DeviceObject
);
1338 if (vpb
&& (vpb
->Flags
& VPB_MOUNTED
)){
1339 SET_FLAG(fdoExtension
->DeviceObject
->Flags
, DO_VERIFY_VOLUME
);
1346 IoCopyCurrentIrpStackLocationToNext(Irp
);
1347 return PoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
1351 if (irpStack
->MinorFunction
!= IRP_MN_SET_POWER
&&
1352 irpStack
->MinorFunction
!= IRP_MN_QUERY_POWER
) {
1358 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1359 Irp
->IoStatus
.Information
= 0;
1362 status
= Irp
->IoStatus
.Status
;
1364 ClassCompleteRequest(DeviceObject
, Irp
, IO_NO_INCREMENT
);
1367 } // end ClassMinimalPowerHandler()
1369 /*++////////////////////////////////////////////////////////////////////////////
1371 ClassSpinDownPowerHandler()
1373 Routine Description:
1375 This routine is a callback for disks and other things which require both
1376 a start and a stop to be sent to the device. (actually the starts are
1377 almost always optional, since most device power themselves on to process
1378 commands, but i digress).
1380 Determines proper use of spinup, spindown, and queue locking based upon
1381 ScanForSpecialFlags in the FdoExtension. This is the most common power
1382 handler passed into classpnp.sys
1386 DeviceObject - Supplies the functional device object
1388 Irp - Supplies the request to be retried.
1397 ClassSpinDownPowerHandler(
1398 IN PDEVICE_OBJECT DeviceObject
,
1402 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
;
1403 CLASS_POWER_OPTIONS options
;
1405 fdoExtension
= (PFUNCTIONAL_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
1408 // this will set all options to FALSE
1411 RtlZeroMemory(&options
, sizeof(CLASS_POWER_OPTIONS
));
1414 // check the flags to see what options we need to worry about
1417 if (!TEST_FLAG(fdoExtension
->ScanForSpecialFlags
,
1418 CLASS_SPECIAL_DISABLE_SPIN_DOWN
)) {
1419 options
.HandleSpinDown
= TRUE
;
1422 if (!TEST_FLAG(fdoExtension
->ScanForSpecialFlags
,
1423 CLASS_SPECIAL_DISABLE_SPIN_UP
)) {
1424 options
.HandleSpinUp
= TRUE
;
1427 if (!TEST_FLAG(fdoExtension
->ScanForSpecialFlags
,
1428 CLASS_SPECIAL_NO_QUEUE_LOCK
)) {
1429 options
.LockQueue
= TRUE
;
1432 DebugPrint((3, "ClasspPowerHandler: Devobj %p\n"
1433 "\t%shandling spin down\n"
1434 "\t%shandling spin up\n"
1435 "\t%slocking queue\n",
1437 (options
.HandleSpinDown
? "" : "not "),
1438 (options
.HandleSpinUp
? "" : "not "),
1439 (options
.LockQueue
? "" : "not ")
1443 // do all the dirty work
1446 return ClasspPowerHandler(DeviceObject
, Irp
, options
);
1447 } // end ClassSpinDownPowerHandler()
1449 /*++////////////////////////////////////////////////////////////////////////////
1451 ClassStopUnitPowerHandler()
1453 Routine Description:
1455 This routine is an outdated call. To achieve equivalent functionality,
1456 the driver should set the following flags in ScanForSpecialFlags in the
1459 CLASS_SPECIAL_DISABLE_SPIN_UP
1460 CLASS_SPECIAL_NO_QUEUE_LOCK
1465 ClassStopUnitPowerHandler(
1466 IN PDEVICE_OBJECT DeviceObject
,
1470 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
;
1472 DebugPrint((0, "ClassStopUnitPowerHandler - Devobj %p using outdated call\n"
1473 "Drivers should set the following flags in ScanForSpecialFlags "
1474 " in the FDO extension:\n"
1475 "\tCLASS_SPECIAL_DISABLE_SPIN_UP\n"
1476 "\tCLASS_SPECIAL_NO_QUEUE_LOCK\n"
1477 "This will provide equivalent functionality if the power "
1478 "routine is then set to ClassSpinDownPowerHandler\n\n",
1481 fdoExtension
= (PFUNCTIONAL_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
1483 SET_FLAG(fdoExtension
->ScanForSpecialFlags
,
1484 CLASS_SPECIAL_DISABLE_SPIN_UP
);
1485 SET_FLAG(fdoExtension
->ScanForSpecialFlags
,
1486 CLASS_SPECIAL_NO_QUEUE_LOCK
);
1488 return ClassSpinDownPowerHandler(DeviceObject
, Irp
);
1489 } // end ClassStopUnitPowerHandler()
1491 /*++////////////////////////////////////////////////////////////////////////////
1495 Routine Description:
1497 This routine reinitalizes the necessary fields, and sends the request
1498 to the lower driver.
1502 DeviceObject - Supplies the device object associated with this request.
1504 Irp - Supplies the request to be retried.
1506 Context - Supplies a pointer to the power up context for this request.
1516 PDEVICE_OBJECT DeviceObject
,
1518 PCLASS_POWER_CONTEXT Context
1521 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
1522 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
1523 PIO_STACK_LOCATION nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
1524 PSCSI_REQUEST_BLOCK srb
= &(Context
->Srb
);
1525 LARGE_INTEGER dueTime
;
1527 DebugPrint((1, "(%p)\tDelaying retry by queueing DPC\n", Irp
));
1529 ASSERT(Context
->Irp
== Irp
);
1530 ASSERT(Context
->DeviceObject
== DeviceObject
);
1531 ASSERT(!TEST_FLAG(Context
->Srb
.SrbFlags
, SRB_FLAGS_FREE_SENSE_BUFFER
));
1532 ASSERT(!TEST_FLAG(Context
->Srb
.SrbFlags
, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE
));
1535 // reset the retry interval
1538 Context
->RetryInterval
= 0;
1541 // Reset byte count of transfer in SRB Extension.
1544 srb
->DataTransferLength
= 0;
1547 // Zero SRB statuses.
1550 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
1553 // Set up major SCSI function.
1556 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
1559 // Save SRB address in next stack for port driver.
1562 nextIrpStack
->Parameters
.Scsi
.Srb
= srb
;
1565 // Set the completion routine up again.
1568 IoSetCompletionRoutine(Irp
, Context
->CompletionRoutine
, Context
,
1572 if (Context
->RetryInterval
== 0) {
1574 DebugPrint((2, "(%p)\tDelaying minimum time (.2 sec)\n", Irp
));
1575 dueTime
.QuadPart
= (LONGLONG
)1000000 * 2;
1579 DebugPrint((2, "(%p)\tDelaying %x seconds\n",
1580 Irp
, Context
->RetryInterval
));
1581 dueTime
.QuadPart
= (LONGLONG
)1000000 * 10 * Context
->RetryInterval
;
1585 ClassRetryRequest(DeviceObject
, Irp
, dueTime
);
1589 } // end RetryRequest()
1591 /*++////////////////////////////////////////////////////////////////////////////
1593 ClasspStartNextPowerIrpCompletion()
1595 Routine Description:
1597 This routine guarantees that the next power irp (power up or down) is not
1598 sent until the previous one has fully completed.
1603 ClasspStartNextPowerIrpCompletion(
1604 IN PDEVICE_OBJECT DeviceObject
,
1609 if(Irp
->PendingReturned
) {
1610 IoMarkIrpPending(Irp
);
1613 PoStartNextPowerIrp(Irp
);
1614 return STATUS_SUCCESS
;
1615 } // end ClasspStartNextPowerIrpCompletion()