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
;
83 PCLASS_POWER_DEVICE powerRoutine
= NULL
;
86 // NOTE: This code may be called at PASSIVE or DISPATCH, depending
87 // upon the device object it is being called for.
88 // don't do anything that would break under either circumstance.
93 isRemoved
= ClassAcquireRemoveLock(DeviceObject
, Irp
);
96 ClassReleaseRemoveLock(DeviceObject
, Irp
);
97 Irp
->IoStatus
.Status
= STATUS_DEVICE_DOES_NOT_EXIST
;
98 PoStartNextPowerIrp(Irp
);
99 ClassCompleteRequest(DeviceObject
, Irp
, IO_NO_INCREMENT
);
100 return STATUS_DEVICE_DOES_NOT_EXIST
;
103 return commonExtension
->DevInfo
->ClassPowerDevice(DeviceObject
, Irp
);
104 } // end ClassDispatchPower()
106 /*++////////////////////////////////////////////////////////////////////////////
108 ClasspPowerUpCompletion()
112 This routine is used for intermediate completion of a power up request.
113 PowerUp requires four requests to be sent to the lower driver in sequence.
115 * The queue is "power locked" to ensure that the class driver power-up
116 work can be done before request processing resumes.
118 * The power irp is sent down the stack for any filter drivers and the
119 port driver to return power and resume command processing for the
120 device. Since the queue is locked, no queued irps will be sent
123 * A start unit command is issued to the device with appropriate flags
124 to override the "power locked" queue.
126 * The queue is "power unlocked" to start processing requests again.
128 This routine uses the function in the srb which just completed to determine
129 which state it is in.
133 DeviceObject - the device object being powered up
135 Irp - the IO_REQUEST_PACKET containing the power request
137 Srb - the SRB used to perform port/class operations.
141 STATUS_MORE_PROCESSING_REQUIRED or
147 ClasspPowerUpCompletion(
148 IN PDEVICE_OBJECT DeviceObject
,
150 IN PVOID CompletionContext
153 PCLASS_POWER_CONTEXT context
= CompletionContext
;
154 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
155 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
157 PIO_STACK_LOCATION currentStack
= IoGetCurrentIrpStackLocation(Irp
);
158 PIO_STACK_LOCATION nextStack
= IoGetNextIrpStackLocation(Irp
);
161 NTSTATUS status
= STATUS_MORE_PROCESSING_REQUIRED
;
163 DebugPrint((1, "ClasspPowerUpCompletion: Device Object %p, Irp %p, "
165 DeviceObject
, Irp
, context
));
167 ASSERT(!TEST_FLAG(context
->Srb
.SrbFlags
, SRB_FLAGS_FREE_SENSE_BUFFER
));
168 ASSERT(!TEST_FLAG(context
->Srb
.SrbFlags
, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE
));
169 ASSERT(context
->Options
.PowerDown
== FALSE
);
170 ASSERT(context
->Options
.HandleSpinUp
);
172 if(Irp
->PendingReturned
) {
173 IoMarkIrpPending(Irp
);
176 context
->PowerChangeState
.PowerUp
++;
178 switch(context
->PowerChangeState
.PowerUp
) {
180 case PowerUpDeviceLocked
: {
182 DebugPrint((1, "(%p)\tPreviously sent power lock\n", Irp
));
185 // Issue the actual power request to the lower driver.
188 IoCopyCurrentIrpStackLocationToNext(Irp
);
191 // If the lock wasn't successful then just bail out on the power
192 // request unless we can ignore failed locks
195 if((context
->Options
.LockQueue
== TRUE
) &&
196 (!NT_SUCCESS(Irp
->IoStatus
.Status
))) {
198 DebugPrint((1, "(%p)\tIrp status was %lx\n",
199 Irp
, Irp
->IoStatus
.Status
));
200 DebugPrint((1, "(%p)\tSrb status was %lx\n",
201 Irp
, context
->Srb
.SrbStatus
));
204 // Lock was not successful - throw down the power IRP
205 // by itself and don't try to spin up the drive or unlock
209 context
->InUse
= FALSE
;
213 // Set the new power state
216 fdoExtension
->DevicePowerState
=
217 currentStack
->Parameters
.Power
.State
.DeviceState
;
219 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
221 IoCopyCurrentIrpStackLocationToNext(Irp
);
223 IoSetCompletionRoutine(Irp
,
224 ClasspStartNextPowerIrpCompletion
,
231 // Indicate to Po that we've been successfully powered up so
232 // it can do it's notification stuff.
235 PoSetPowerState(DeviceObject
,
236 currentStack
->Parameters
.Power
.Type
,
237 currentStack
->Parameters
.Power
.State
);
239 PoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
241 ClassReleaseRemoveLock(commonExtension
->DeviceObject
,
244 return STATUS_MORE_PROCESSING_REQUIRED
;
247 context
->QueueLocked
= (UCHAR
) context
->Options
.LockQueue
;
250 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
252 context
->PowerChangeState
.PowerUp
= PowerUpDeviceLocked
;
254 IoSetCompletionRoutine(Irp
,
255 ClasspPowerUpCompletion
,
261 status
= PoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
263 DebugPrint((2, "(%p)\tPoCallDriver returned %lx\n", Irp
, status
));
267 case PowerUpDeviceOn
: {
271 if(NT_SUCCESS(Irp
->IoStatus
.Status
)) {
273 DebugPrint((1, "(%p)\tSending start unit to device\n", Irp
));
276 // Issue the start unit command to the device.
279 context
->Srb
.Length
= sizeof(SCSI_REQUEST_BLOCK
);
280 context
->Srb
.Function
= SRB_FUNCTION_EXECUTE_SCSI
;
282 context
->Srb
.SrbStatus
= context
->Srb
.ScsiStatus
= 0;
283 context
->Srb
.DataTransferLength
= 0;
285 context
->Srb
.TimeOutValue
= START_UNIT_TIMEOUT
;
287 context
->Srb
.SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
|
288 SRB_FLAGS_DISABLE_AUTOSENSE
|
289 SRB_FLAGS_DISABLE_SYNCH_TRANSFER
|
290 SRB_FLAGS_NO_QUEUE_FREEZE
;
292 if(context
->Options
.LockQueue
) {
293 SET_FLAG(context
->Srb
.SrbFlags
, SRB_FLAGS_BYPASS_LOCKED_QUEUE
);
296 context
->Srb
.CdbLength
= 6;
298 cdb
= (PCDB
) (context
->Srb
.Cdb
);
299 RtlZeroMemory(cdb
, sizeof(CDB
));
302 cdb
->START_STOP
.OperationCode
= SCSIOP_START_STOP_UNIT
;
303 cdb
->START_STOP
.Start
= 1;
305 context
->PowerChangeState
.PowerUp
= PowerUpDeviceOn
;
307 IoSetCompletionRoutine(Irp
,
308 ClasspPowerUpCompletion
,
314 nextStack
->Parameters
.Scsi
.Srb
= &(context
->Srb
);
315 nextStack
->MajorFunction
= IRP_MJ_SCSI
;
317 status
= IoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
319 DebugPrint((2, "(%p)\tIoCallDriver returned %lx\n", Irp
, status
));
327 context
->FinalStatus
= Irp
->IoStatus
.Status
;
328 goto ClasspPowerUpCompletionFailure
;
334 case PowerUpDeviceStarted
: { // 3
337 // First deal with an error if one occurred.
340 if(SRB_STATUS(context
->Srb
.SrbStatus
) != SRB_STATUS_SUCCESS
) {
344 DebugPrint((1, "%p\tError occured when issuing START_UNIT "
345 "command to device. Srb %p, Status %x\n",
348 context
->Srb
.SrbStatus
));
350 ASSERT(!(TEST_FLAG(context
->Srb
.SrbStatus
,
351 SRB_STATUS_QUEUE_FROZEN
)));
352 ASSERT(context
->Srb
.Function
== SRB_FUNCTION_EXECUTE_SCSI
);
354 context
->RetryInterval
= 0;
356 retry
= ClassInterpretSenseInfo(
357 commonExtension
->DeviceObject
,
361 MAXIMUM_RETRIES
- context
->RetryCount
,
363 &context
->RetryInterval
);
365 if((retry
== TRUE
) && (context
->RetryCount
-- != 0)) {
367 DebugPrint((1, "(%p)\tRetrying failed request\n", Irp
));
370 // Decrement the state so we come back through here the
374 context
->PowerChangeState
.PowerUp
--;
376 RetryPowerRequest(commonExtension
->DeviceObject
,
385 context
->RetryCount
= MAXIMUM_RETRIES
;
389 ClasspPowerUpCompletionFailure
:
391 DebugPrint((1, "(%p)\tPreviously spun device up\n", Irp
));
393 if (context
->QueueLocked
) {
394 DebugPrint((1, "(%p)\tUnlocking queue\n", Irp
));
396 context
->Srb
.Function
= SRB_FUNCTION_UNLOCK_QUEUE
;
397 context
->Srb
.SrbFlags
= SRB_FLAGS_BYPASS_LOCKED_QUEUE
;
398 context
->Srb
.SrbStatus
= context
->Srb
.ScsiStatus
= 0;
399 context
->Srb
.DataTransferLength
= 0;
401 nextStack
->Parameters
.Scsi
.Srb
= &(context
->Srb
);
402 nextStack
->MajorFunction
= IRP_MJ_SCSI
;
404 context
->PowerChangeState
.PowerUp
= PowerUpDeviceStarted
;
406 IoSetCompletionRoutine(Irp
,
407 ClasspPowerUpCompletion
,
413 status
= IoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
414 DebugPrint((1, "(%p)\tIoCallDriver returned %lx\n",
419 // Fall-through to next case...
423 case PowerUpDeviceUnlocked
: {
426 // This is the end of the dance. Free the srb and complete the
427 // request finally. We're ignoring possible intermediate
428 // error conditions ....
431 if (context
->QueueLocked
) {
432 DebugPrint((1, "(%p)\tPreviously unlocked queue\n", Irp
));
433 ASSERT(NT_SUCCESS(Irp
->IoStatus
.Status
));
434 ASSERT(context
->Srb
.SrbStatus
== SRB_STATUS_SUCCESS
);
436 DebugPrint((1, "(%p)\tFall-through (queue not locked)\n", Irp
));
439 DebugPrint((1, "(%p)\tFreeing srb and completing\n", Irp
));
440 context
->InUse
= FALSE
;
442 status
= context
->FinalStatus
;
443 Irp
->IoStatus
.Status
= status
;
448 // Set the new power state
451 if(NT_SUCCESS(status
)) {
452 fdoExtension
->DevicePowerState
=
453 currentStack
->Parameters
.Power
.State
.DeviceState
;
457 // Indicate to Po that we've been successfully powered up so
458 // it can do it's notification stuff.
461 PoSetPowerState(DeviceObject
,
462 currentStack
->Parameters
.Power
.Type
,
463 currentStack
->Parameters
.Power
.State
);
465 DebugPrint((1, "(%p)\tStarting next power irp\n", Irp
));
466 ClassReleaseRemoveLock(DeviceObject
, Irp
);
467 PoStartNextPowerIrp(Irp
);
473 return STATUS_MORE_PROCESSING_REQUIRED
;
474 } // end ClasspPowerUpCompletion()
476 /*++////////////////////////////////////////////////////////////////////////////
478 ClasspPowerDownCompletion()
482 This routine is used for intermediate completion of a power up request.
483 PowerUp requires four requests to be sent to the lower driver in sequence.
485 * The queue is "power locked" to ensure that the class driver power-up
486 work can be done before request processing resumes.
488 * The power irp is sent down the stack for any filter drivers and the
489 port driver to return power and resume command processing for the
490 device. Since the queue is locked, no queued irps will be sent
493 * A start unit command is issued to the device with appropriate flags
494 to override the "power locked" queue.
496 * The queue is "power unlocked" to start processing requests again.
498 This routine uses the function in the srb which just completed to determine
499 which state it is in.
503 DeviceObject - the device object being powered up
505 Irp - the IO_REQUEST_PACKET containing the power request
507 Srb - the SRB used to perform port/class operations.
511 STATUS_MORE_PROCESSING_REQUIRED or
517 ClasspPowerDownCompletion(
518 IN PDEVICE_OBJECT DeviceObject
,
520 IN PVOID CompletionContext
523 PCLASS_POWER_CONTEXT context
= CompletionContext
;
524 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
525 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
527 PIO_STACK_LOCATION currentStack
= IoGetCurrentIrpStackLocation(Irp
);
528 PIO_STACK_LOCATION nextStack
= IoGetNextIrpStackLocation(Irp
);
530 NTSTATUS status
= STATUS_MORE_PROCESSING_REQUIRED
;
532 DebugPrint((1, "ClasspPowerDownCompletion: Device Object %p, "
533 "Irp %p, Context %p\n",
534 DeviceObject
, Irp
, context
));
536 ASSERT(!TEST_FLAG(context
->Srb
.SrbFlags
, SRB_FLAGS_FREE_SENSE_BUFFER
));
537 ASSERT(!TEST_FLAG(context
->Srb
.SrbFlags
, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE
));
538 ASSERT(context
->Options
.PowerDown
== TRUE
);
539 ASSERT(context
->Options
.HandleSpinDown
);
541 if(Irp
->PendingReturned
) {
542 IoMarkIrpPending(Irp
);
545 context
->PowerChangeState
.PowerDown2
++;
547 switch(context
->PowerChangeState
.PowerDown2
) {
549 case PowerDownDeviceLocked2
: {
553 DebugPrint((1, "(%p)\tPreviously sent power lock\n", Irp
));
555 if((context
->Options
.LockQueue
== TRUE
) &&
556 (!NT_SUCCESS(Irp
->IoStatus
.Status
))) {
558 DebugPrint((1, "(%p)\tIrp status was %lx\n",
560 Irp
->IoStatus
.Status
));
561 DebugPrint((1, "(%p)\tSrb status was %lx\n",
563 context
->Srb
.SrbStatus
));
565 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
568 // Lock was not successful - throw down the power IRP
569 // by itself and don't try to spin down the drive or unlock
573 context
->InUse
= FALSE
;
577 // Set the new power state
580 fdoExtension
->DevicePowerState
=
581 currentStack
->Parameters
.Power
.State
.DeviceState
;
584 // Indicate to Po that we've been successfully powered down
585 // so it can do it's notification stuff.
588 IoCopyCurrentIrpStackLocationToNext(Irp
);
589 IoSetCompletionRoutine(Irp
,
590 ClasspStartNextPowerIrpCompletion
,
596 PoSetPowerState(DeviceObject
,
597 currentStack
->Parameters
.Power
.Type
,
598 currentStack
->Parameters
.Power
.State
);
600 fdoExtension
->PowerDownInProgress
= FALSE
;
602 PoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
604 ClassReleaseRemoveLock(commonExtension
->DeviceObject
,
607 return STATUS_MORE_PROCESSING_REQUIRED
;
610 context
->QueueLocked
= (UCHAR
) context
->Options
.LockQueue
;
613 if (!TEST_FLAG(fdoExtension
->PrivateFdoData
->HackFlags
,
614 FDO_HACK_NO_SYNC_CACHE
)) {
617 // send SCSIOP_SYNCHRONIZE_CACHE
620 context
->Srb
.Length
= sizeof(SCSI_REQUEST_BLOCK
);
621 context
->Srb
.Function
= SRB_FUNCTION_EXECUTE_SCSI
;
623 context
->Srb
.TimeOutValue
= fdoExtension
->TimeOutValue
;
625 context
->Srb
.SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
|
626 SRB_FLAGS_DISABLE_AUTOSENSE
|
627 SRB_FLAGS_DISABLE_SYNCH_TRANSFER
|
628 SRB_FLAGS_NO_QUEUE_FREEZE
|
629 SRB_FLAGS_BYPASS_LOCKED_QUEUE
;
631 context
->Srb
.SrbStatus
= context
->Srb
.ScsiStatus
= 0;
632 context
->Srb
.DataTransferLength
= 0;
634 context
->Srb
.CdbLength
= 10;
636 cdb
= (PCDB
) context
->Srb
.Cdb
;
638 RtlZeroMemory(cdb
, sizeof(CDB
));
639 cdb
->SYNCHRONIZE_CACHE10
.OperationCode
= SCSIOP_SYNCHRONIZE_CACHE
;
641 IoSetCompletionRoutine(Irp
,
642 ClasspPowerDownCompletion
,
648 nextStack
->Parameters
.Scsi
.Srb
= &(context
->Srb
);
649 nextStack
->MajorFunction
= IRP_MJ_SCSI
;
651 status
= IoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
653 DebugPrint((1, "(%p)\tIoCallDriver returned %lx\n", Irp
, status
));
658 DebugPrint((1, "(%p)\tPower Down: not sending SYNCH_CACHE\n",
660 context
->PowerChangeState
.PowerDown2
++;
661 context
->Srb
.SrbStatus
= SRB_STATUS_SUCCESS
;
662 // and fall through....
664 // no break in case the device doesn't like synch_cache commands
668 case PowerDownDeviceFlushed2
: {
672 DebugPrint((1, "(%p)\tPreviously send SCSIOP_SYNCHRONIZE_CACHE\n",
676 // SCSIOP_SYNCHRONIZE_CACHE was sent
679 if(SRB_STATUS(context
->Srb
.SrbStatus
) != SRB_STATUS_SUCCESS
) {
683 DebugPrint((1, "(%p)\tError occured when issuing "
684 "SYNCHRONIZE_CACHE command to device. "
685 "Srb %p, Status %lx\n",
688 context
->Srb
.SrbStatus
));
690 ASSERT(!(TEST_FLAG(context
->Srb
.SrbStatus
,
691 SRB_STATUS_QUEUE_FROZEN
)));
692 ASSERT(context
->Srb
.Function
== SRB_FUNCTION_EXECUTE_SCSI
);
694 context
->RetryInterval
= 0;
695 retry
= ClassInterpretSenseInfo(
696 commonExtension
->DeviceObject
,
700 MAXIMUM_RETRIES
- context
->RetryCount
,
702 &context
->RetryInterval
);
704 if((retry
== TRUE
) && (context
->RetryCount
-- != 0)) {
706 DebugPrint((1, "(%p)\tRetrying failed request\n", Irp
));
709 // decrement the state so we come back through here
713 context
->PowerChangeState
.PowerDown2
--;
714 RetryPowerRequest(commonExtension
->DeviceObject
,
720 DebugPrint((1, "(%p)\tSYNCHRONIZE_CACHE not retried\n", Irp
));
721 context
->RetryCount
= MAXIMUM_RETRIES
;
723 } // end !SRB_STATUS_SUCCESS
726 // note: we are purposefully ignoring any errors. if the drive
727 // doesn't support a synch_cache, then we're up a creek
731 DebugPrint((1, "(%p)\tSending stop unit to device\n", Irp
));
734 // Issue the start unit command to the device.
737 context
->Srb
.Length
= sizeof(SCSI_REQUEST_BLOCK
);
738 context
->Srb
.Function
= SRB_FUNCTION_EXECUTE_SCSI
;
740 context
->Srb
.TimeOutValue
= START_UNIT_TIMEOUT
;
742 context
->Srb
.SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
|
743 SRB_FLAGS_DISABLE_AUTOSENSE
|
744 SRB_FLAGS_DISABLE_SYNCH_TRANSFER
|
745 SRB_FLAGS_NO_QUEUE_FREEZE
|
746 SRB_FLAGS_BYPASS_LOCKED_QUEUE
;
748 context
->Srb
.SrbStatus
= context
->Srb
.ScsiStatus
= 0;
749 context
->Srb
.DataTransferLength
= 0;
751 context
->Srb
.CdbLength
= 6;
753 cdb
= (PCDB
) context
->Srb
.Cdb
;
754 RtlZeroMemory(cdb
, sizeof(CDB
));
756 cdb
->START_STOP
.OperationCode
= SCSIOP_START_STOP_UNIT
;
757 cdb
->START_STOP
.Start
= 0;
758 cdb
->START_STOP
.Immediate
= 1;
760 IoSetCompletionRoutine(Irp
,
761 ClasspPowerDownCompletion
,
767 nextStack
->Parameters
.Scsi
.Srb
= &(context
->Srb
);
768 nextStack
->MajorFunction
= IRP_MJ_SCSI
;
770 status
= IoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
772 DebugPrint((1, "(%p)\tIoCallDriver returned %lx\n", Irp
, status
));
777 case PowerDownDeviceStopped2
: {
779 BOOLEAN ignoreError
= TRUE
;
785 if(SRB_STATUS(context
->Srb
.SrbStatus
) != SRB_STATUS_SUCCESS
) {
789 DebugPrint((1, "(%p)\tError occured when issueing STOP_UNIT "
790 "command to device. Srb %p, Status %lx\n",
793 context
->Srb
.SrbStatus
));
795 ASSERT(!(TEST_FLAG(context
->Srb
.SrbStatus
,
796 SRB_STATUS_QUEUE_FROZEN
)));
797 ASSERT(context
->Srb
.Function
== SRB_FUNCTION_EXECUTE_SCSI
);
799 context
->RetryInterval
= 0;
800 retry
= ClassInterpretSenseInfo(
801 commonExtension
->DeviceObject
,
805 MAXIMUM_RETRIES
- context
->RetryCount
,
807 &context
->RetryInterval
);
809 if((retry
== TRUE
) && (context
->RetryCount
-- != 0)) {
811 DebugPrint((1, "(%p)\tRetrying failed request\n", Irp
));
814 // decrement the state so we come back through here
818 context
->PowerChangeState
.PowerDown2
--;
819 RetryPowerRequest(commonExtension
->DeviceObject
,
825 DebugPrint((1, "(%p)\tSTOP_UNIT not retried\n", Irp
));
826 context
->RetryCount
= MAXIMUM_RETRIES
;
828 } // end !SRB_STATUS_SUCCESS
831 DebugPrint((1, "(%p)\tPreviously sent stop unit\n", Irp
));
834 // some operations, such as a physical format in progress,
835 // should not be ignored and should fail the power operation.
838 if (!NT_SUCCESS(status
)) {
840 PSENSE_DATA senseBuffer
= context
->Srb
.SenseInfoBuffer
;
842 if (TEST_FLAG(context
->Srb
.SrbStatus
,
843 SRB_STATUS_AUTOSENSE_VALID
) &&
844 ((senseBuffer
->SenseKey
& 0xf) == SCSI_SENSE_NOT_READY
) &&
845 (senseBuffer
->AdditionalSenseCode
== SCSI_ADSENSE_LUN_NOT_READY
) &&
846 (senseBuffer
->AdditionalSenseCodeQualifier
== SCSI_SENSEQ_FORMAT_IN_PROGRESS
)
849 context
->FinalStatus
= STATUS_DEVICE_BUSY
;
850 status
= context
->FinalStatus
;
855 if (NT_SUCCESS(status
) || ignoreError
) {
858 // Issue the actual power request to the lower driver.
861 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
863 IoCopyCurrentIrpStackLocationToNext(Irp
);
865 IoSetCompletionRoutine(Irp
,
866 ClasspPowerDownCompletion
,
872 status
= PoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
874 DebugPrint((1, "(%p)\tPoCallDriver returned %lx\n", Irp
, status
));
878 // else fall through w/o sending the power irp, since the device
879 // is reporting an error that would be "really bad" to power down
884 case PowerDownDeviceOff2
: {
887 // SpinDown request completed ... whether it succeeded or not is
888 // another matter entirely.
891 DebugPrint((1, "(%p)\tPreviously sent power irp\n", Irp
));
893 if (context
->QueueLocked
) {
895 DebugPrint((1, "(%p)\tUnlocking queue\n", Irp
));
897 context
->Srb
.Length
= sizeof(SCSI_REQUEST_BLOCK
);
899 context
->Srb
.SrbStatus
= context
->Srb
.ScsiStatus
= 0;
900 context
->Srb
.DataTransferLength
= 0;
902 context
->Srb
.Function
= SRB_FUNCTION_UNLOCK_QUEUE
;
903 context
->Srb
.SrbFlags
= SRB_FLAGS_BYPASS_LOCKED_QUEUE
;
904 nextStack
->Parameters
.Scsi
.Srb
= &(context
->Srb
);
905 nextStack
->MajorFunction
= IRP_MJ_SCSI
;
907 IoSetCompletionRoutine(Irp
,
908 ClasspPowerDownCompletion
,
914 status
= IoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
915 DebugPrint((1, "(%p)\tIoCallDriver returned %lx\n",
923 case PowerDownDeviceUnlocked2
: {
926 // This is the end of the dance. Free the srb and complete the
927 // request finally. We're ignoring possible intermediate
928 // error conditions ....
931 if (context
->QueueLocked
== FALSE
) {
932 DebugPrint((1, "(%p)\tFall through (queue not locked)\n", Irp
));
934 DebugPrint((1, "(%p)\tPreviously unlocked queue\n", Irp
));
935 ASSERT(NT_SUCCESS(Irp
->IoStatus
.Status
));
936 ASSERT(context
->Srb
.SrbStatus
== SRB_STATUS_SUCCESS
);
939 DebugPrint((1, "(%p)\tFreeing srb and completing\n", Irp
));
940 context
->InUse
= FALSE
;
941 status
= context
->FinalStatus
; // allow failure to propogate
944 if(Irp
->PendingReturned
) {
945 IoMarkIrpPending(Irp
);
948 Irp
->IoStatus
.Status
= status
;
949 Irp
->IoStatus
.Information
= 0;
951 if (NT_SUCCESS(status
)) {
954 // Set the new power state
957 fdoExtension
->DevicePowerState
=
958 currentStack
->Parameters
.Power
.State
.DeviceState
;
963 DebugPrint((1, "(%p)\tStarting next power irp\n", Irp
));
965 ClassReleaseRemoveLock(DeviceObject
, Irp
);
966 PoStartNextPowerIrp(Irp
);
967 fdoExtension
->PowerDownInProgress
= FALSE
;
973 return STATUS_MORE_PROCESSING_REQUIRED
;
974 } // end ClasspPowerDownCompletion()
976 /*++////////////////////////////////////////////////////////////////////////////
982 This routine reduces the number of useless spinups and spindown requests
983 sent to a given device by ignoring transitions to power states we are
986 ISSUE-2000/02/20-henrygab - by ignoring spin-up requests, we may be
991 DeviceObject - the device object which is transitioning power states
993 Options - a set of flags indicating what the device handles
1001 IN PDEVICE_OBJECT DeviceObject
,
1003 IN CLASS_POWER_OPTIONS Options
// ISSUE-2000/02/20-henrygab - pass pointer, not whole struct
1006 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
1007 PDEVICE_OBJECT lowerDevice
= commonExtension
->LowerDeviceObject
;
1008 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
1009 PIO_STACK_LOCATION nextIrpStack
;
1010 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
1011 PCLASS_POWER_CONTEXT context
;
1013 if (!commonExtension
->IsFdo
) {
1016 // certain assumptions are made here,
1017 // particularly: having the fdoExtension
1020 DebugPrint((0, "ClasspPowerHandler: Called for PDO %p???\n",
1022 ASSERT(!"PDO using ClasspPowerHandler");
1023 return STATUS_NOT_SUPPORTED
;
1026 DebugPrint((1, "ClasspPowerHandler: Power irp %p to %s %p\n",
1027 Irp
, (commonExtension
->IsFdo
? "fdo" : "pdo"), DeviceObject
));
1029 switch(irpStack
->MinorFunction
) {
1031 case IRP_MN_SET_POWER
: {
1032 PCLASS_PRIVATE_FDO_DATA fdoData
= fdoExtension
->PrivateFdoData
;
1034 DebugPrint((1, "(%p)\tIRP_MN_SET_POWER\n", Irp
));
1036 DebugPrint((1, "(%p)\tSetting %s state to %d\n",
1038 (irpStack
->Parameters
.Power
.Type
== SystemPowerState
?
1039 "System" : "Device"),
1040 irpStack
->Parameters
.Power
.State
.SystemState
));
1042 switch (irpStack
->Parameters
.Power
.ShutdownType
){
1044 case PowerActionSleep
:
1045 case PowerActionHibernate
:
1046 if (fdoData
->HotplugInfo
.MediaRemovable
|| fdoData
->HotplugInfo
.MediaHotplug
){
1048 * We are suspending and this drive is either hot-pluggable
1049 * or contains removeable media.
1050 * Set the media dirty bit, since the media may change while
1053 SET_FLAG(DeviceObject
->Flags
, DO_VERIFY_VOLUME
);
1063 DebugPrint((1, "(%p)\tIrp minor code = %#x\n",
1064 Irp
, irpStack
->MinorFunction
));
1069 if (irpStack
->Parameters
.Power
.Type
!= DevicePowerState
||
1070 irpStack
->MinorFunction
!= IRP_MN_SET_POWER
) {
1072 DebugPrint((1, "(%p)\tSending to lower device\n", Irp
));
1074 goto ClasspPowerHandlerCleanup
;
1078 nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
1081 // already in exact same state, don't work to transition to it.
1084 if(irpStack
->Parameters
.Power
.State
.DeviceState
==
1085 fdoExtension
->DevicePowerState
) {
1087 DebugPrint((1, "(%p)\tAlready in device state %x\n",
1088 Irp
, fdoExtension
->DevicePowerState
));
1089 goto ClasspPowerHandlerCleanup
;
1094 // or powering down from non-d0 state (device already stopped)
1095 // NOTE -- we're not sure whether this case can exist or not (the
1096 // power system may never send this sort of request) but it's trivial
1100 if ((irpStack
->Parameters
.Power
.State
.DeviceState
!= PowerDeviceD0
) &&
1101 (fdoExtension
->DevicePowerState
!= PowerDeviceD0
)) {
1102 DebugPrint((1, "(%p)\tAlready powered down to %x???\n",
1103 Irp
, fdoExtension
->DevicePowerState
));
1104 fdoExtension
->DevicePowerState
=
1105 irpStack
->Parameters
.Power
.State
.DeviceState
;
1106 goto ClasspPowerHandlerCleanup
;
1110 // or going into a hibernation state when we're in the hibernation path.
1111 // If the device is spinning then we should leave it spinning - if it's not
1112 // then the dump driver will start it up for us.
1115 if((irpStack
->Parameters
.Power
.State
.DeviceState
== PowerDeviceD3
) &&
1116 (irpStack
->Parameters
.Power
.ShutdownType
== PowerActionHibernate
) &&
1117 (commonExtension
->HibernationPathCount
!= 0)) {
1119 DebugPrint((1, "(%p)\tdoing nothing for hibernation request for "
1121 Irp
, fdoExtension
->DevicePowerState
));
1122 fdoExtension
->DevicePowerState
=
1123 irpStack
->Parameters
.Power
.State
.DeviceState
;
1124 goto ClasspPowerHandlerCleanup
;
1127 // or when not handling powering up and are powering up
1130 if ((!Options
.HandleSpinUp
) &&
1131 (irpStack
->Parameters
.Power
.State
.DeviceState
== PowerDeviceD0
)) {
1133 DebugPrint((2, "(%p)\tNot handling spinup to state %x\n",
1134 Irp
, fdoExtension
->DevicePowerState
));
1135 fdoExtension
->DevicePowerState
=
1136 irpStack
->Parameters
.Power
.State
.DeviceState
;
1137 goto ClasspPowerHandlerCleanup
;
1142 // or when not handling powering down and are powering down
1145 if ((!Options
.HandleSpinDown
) &&
1146 (irpStack
->Parameters
.Power
.State
.DeviceState
!= PowerDeviceD0
)) {
1148 DebugPrint((2, "(%p)\tNot handling spindown to state %x\n",
1149 Irp
, fdoExtension
->DevicePowerState
));
1150 fdoExtension
->DevicePowerState
=
1151 irpStack
->Parameters
.Power
.State
.DeviceState
;
1152 goto ClasspPowerHandlerCleanup
;
1156 context
= &(fdoExtension
->PowerContext
);
1160 // Mark the context as in use. We should be synchronizing this but
1161 // since it's just for debugging purposes we don't worry too much.
1164 ASSERT(context
->InUse
== FALSE
);
1167 RtlZeroMemory(context
, sizeof(CLASS_POWER_CONTEXT
));
1168 context
->InUse
= TRUE
;
1170 nextIrpStack
->Parameters
.Scsi
.Srb
= &(context
->Srb
);
1171 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
1173 context
->FinalStatus
= STATUS_SUCCESS
;
1175 context
->Srb
.Length
= sizeof(SCSI_REQUEST_BLOCK
);
1176 context
->Srb
.OriginalRequest
= Irp
;
1177 context
->Srb
.SrbFlags
|= SRB_FLAGS_BYPASS_LOCKED_QUEUE
1178 | SRB_FLAGS_NO_QUEUE_FREEZE
;
1179 context
->Srb
.Function
= SRB_FUNCTION_LOCK_QUEUE
;
1181 context
->Srb
.SenseInfoBuffer
=
1182 commonExtension
->PartitionZeroExtension
->SenseData
;
1183 context
->Srb
.SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
1184 context
->RetryCount
= MAXIMUM_RETRIES
;
1186 context
->Options
= Options
;
1187 context
->DeviceObject
= DeviceObject
;
1190 if(irpStack
->Parameters
.Power
.State
.DeviceState
== PowerDeviceD0
) {
1192 ASSERT(Options
.HandleSpinUp
);
1194 DebugPrint((2, "(%p)\tpower up - locking queue\n", Irp
));
1197 // We need to issue a queue lock request so that we
1198 // can spin the drive back up after the power is restored
1199 // but before any requests are processed.
1202 context
->Options
.PowerDown
= FALSE
;
1203 context
->PowerChangeState
.PowerUp
= PowerUpDeviceInitial
;
1204 context
->CompletionRoutine
= ClasspPowerUpCompletion
;
1208 ASSERT(Options
.HandleSpinDown
);
1210 fdoExtension
->PowerDownInProgress
= TRUE
;
1212 DebugPrint((2, "(%p)\tPowering down - locking queue\n", Irp
));
1214 PoSetPowerState(DeviceObject
,
1215 irpStack
->Parameters
.Power
.Type
,
1216 irpStack
->Parameters
.Power
.State
);
1218 context
->Options
.PowerDown
= TRUE
;
1219 context
->PowerChangeState
.PowerDown2
= PowerDownDeviceInitial2
;
1220 context
->CompletionRoutine
= ClasspPowerDownCompletion
;
1225 // we are not dealing with port-allocated sense in these routines.
1228 ASSERT(!TEST_FLAG(context
->Srb
.SrbFlags
, SRB_FLAGS_FREE_SENSE_BUFFER
));
1229 ASSERT(!TEST_FLAG(context
->Srb
.SrbFlags
, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE
));
1232 // we are always returning STATUS_PENDING, so we need to always
1233 // set the irp as pending.
1236 IoMarkIrpPending(Irp
);
1238 if(Options
.LockQueue
) {
1241 // Send the lock irp down.
1244 IoSetCompletionRoutine(Irp
,
1245 context
->CompletionRoutine
,
1251 IoCallDriver(lowerDevice
, Irp
);
1256 // Call the completion routine directly. It won't care what the
1257 // status of the "lock" was - it will just go and do the next
1258 // step of the operation.
1261 context
->CompletionRoutine(DeviceObject
, Irp
, context
);
1264 return STATUS_PENDING
;
1266 ClasspPowerHandlerCleanup
:
1268 ClassReleaseRemoveLock(DeviceObject
, Irp
);
1270 DebugPrint((1, "(%p)\tStarting next power irp\n", Irp
));
1271 IoCopyCurrentIrpStackLocationToNext(Irp
);
1272 IoSetCompletionRoutine(Irp
,
1273 ClasspStartNextPowerIrpCompletion
,
1278 return PoCallDriver(lowerDevice
, Irp
);
1279 } // end ClasspPowerHandler()
1281 /*++////////////////////////////////////////////////////////////////////////////
1283 ClassMinimalPowerHandler()
1285 Routine Description:
1287 This routine is the minimum power handler for a storage driver. It does
1288 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.
1387 ClassSpinDownPowerHandler(
1388 IN PDEVICE_OBJECT DeviceObject
,
1392 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
;
1393 CLASS_POWER_OPTIONS options
;
1395 fdoExtension
= (PFUNCTIONAL_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
1398 // this will set all options to FALSE
1401 RtlZeroMemory(&options
, sizeof(CLASS_POWER_OPTIONS
));
1404 // check the flags to see what options we need to worry about
1407 if (!TEST_FLAG(fdoExtension
->ScanForSpecialFlags
,
1408 CLASS_SPECIAL_DISABLE_SPIN_DOWN
)) {
1409 options
.HandleSpinDown
= TRUE
;
1412 if (!TEST_FLAG(fdoExtension
->ScanForSpecialFlags
,
1413 CLASS_SPECIAL_DISABLE_SPIN_UP
)) {
1414 options
.HandleSpinUp
= TRUE
;
1417 if (!TEST_FLAG(fdoExtension
->ScanForSpecialFlags
,
1418 CLASS_SPECIAL_NO_QUEUE_LOCK
)) {
1419 options
.LockQueue
= TRUE
;
1422 DebugPrint((3, "ClasspPowerHandler: Devobj %p\n"
1423 "\t%shandling spin down\n"
1424 "\t%shandling spin up\n"
1425 "\t%slocking queue\n",
1427 (options
.HandleSpinDown
? "" : "not "),
1428 (options
.HandleSpinUp
? "" : "not "),
1429 (options
.LockQueue
? "" : "not ")
1433 // do all the dirty work
1436 return ClasspPowerHandler(DeviceObject
, Irp
, options
);
1437 } // end ClassSpinDownPowerHandler()
1439 /*++////////////////////////////////////////////////////////////////////////////
1441 ClassStopUnitPowerHandler()
1443 Routine Description:
1445 This routine is an outdated call. To achieve equivalent functionality,
1446 the driver should set the following flags in ScanForSpecialFlags in the
1449 CLASS_SPECIAL_DISABLE_SPIN_UP
1450 CLASS_SPECIAL_NO_QUEUE_LOCK
1455 ClassStopUnitPowerHandler(
1456 IN PDEVICE_OBJECT DeviceObject
,
1460 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
;
1462 DebugPrint((0, "ClassStopUnitPowerHandler - Devobj %p using outdated call\n"
1463 "Drivers should set the following flags in ScanForSpecialFlags "
1464 " in the FDO extension:\n"
1465 "\tCLASS_SPECIAL_DISABLE_SPIN_UP\n"
1466 "\tCLASS_SPECIAL_NO_QUEUE_LOCK\n"
1467 "This will provide equivalent functionality if the power "
1468 "routine is then set to ClassSpinDownPowerHandler\n\n",
1471 fdoExtension
= (PFUNCTIONAL_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
1473 SET_FLAG(fdoExtension
->ScanForSpecialFlags
,
1474 CLASS_SPECIAL_DISABLE_SPIN_UP
);
1475 SET_FLAG(fdoExtension
->ScanForSpecialFlags
,
1476 CLASS_SPECIAL_NO_QUEUE_LOCK
);
1478 return ClassSpinDownPowerHandler(DeviceObject
, Irp
);
1479 } // end ClassStopUnitPowerHandler()
1481 /*++////////////////////////////////////////////////////////////////////////////
1485 Routine Description:
1487 This routine reinitializes the necessary fields, and sends the request
1488 to the lower driver.
1492 DeviceObject - Supplies the device object associated with this request.
1494 Irp - Supplies the request to be retried.
1496 Context - Supplies a pointer to the power up context for this request.
1506 PDEVICE_OBJECT DeviceObject
,
1508 PCLASS_POWER_CONTEXT Context
1511 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
1512 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
1513 PIO_STACK_LOCATION nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
1514 PSCSI_REQUEST_BLOCK srb
= &(Context
->Srb
);
1515 LARGE_INTEGER dueTime
;
1517 DebugPrint((1, "(%p)\tDelaying retry by queueing DPC\n", Irp
));
1519 ASSERT(Context
->Irp
== Irp
);
1520 ASSERT(Context
->DeviceObject
== DeviceObject
);
1521 ASSERT(!TEST_FLAG(Context
->Srb
.SrbFlags
, SRB_FLAGS_FREE_SENSE_BUFFER
));
1522 ASSERT(!TEST_FLAG(Context
->Srb
.SrbFlags
, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE
));
1525 // reset the retry interval
1528 Context
->RetryInterval
= 0;
1531 // Reset byte count of transfer in SRB Extension.
1534 srb
->DataTransferLength
= 0;
1537 // Zero SRB statuses.
1540 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
1543 // Set up major SCSI function.
1546 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
1549 // Save SRB address in next stack for port driver.
1552 nextIrpStack
->Parameters
.Scsi
.Srb
= srb
;
1555 // Set the completion routine up again.
1558 IoSetCompletionRoutine(Irp
, Context
->CompletionRoutine
, Context
,
1562 if (Context
->RetryInterval
== 0) {
1564 DebugPrint((2, "(%p)\tDelaying minimum time (.2 sec)\n", Irp
));
1565 dueTime
.QuadPart
= (LONGLONG
)1000000 * 2;
1569 DebugPrint((2, "(%p)\tDelaying %x seconds\n",
1570 Irp
, Context
->RetryInterval
));
1571 dueTime
.QuadPart
= (LONGLONG
)1000000 * 10 * Context
->RetryInterval
;
1575 ClassRetryRequest(DeviceObject
, Irp
, dueTime
);
1579 } // end RetryRequest()
1581 /*++////////////////////////////////////////////////////////////////////////////
1583 ClasspStartNextPowerIrpCompletion()
1585 Routine Description:
1587 This routine guarantees that the next power irp (power up or down) is not
1588 sent until the previous one has fully completed.
1593 ClasspStartNextPowerIrpCompletion(
1594 IN PDEVICE_OBJECT DeviceObject
,
1599 if(Irp
->PendingReturned
) {
1600 IoMarkIrpPending(Irp
);
1603 PoStartNextPowerIrp(Irp
);
1604 return STATUS_SUCCESS
;
1605 } // end ClasspStartNextPowerIrpCompletion()