3 Copyright (C) Microsoft Corporation, 1991 - 1999
11 SCSI class driver routines
31 #define CLASS_TAG_POWER 'WLcS'
35 IN PDEVICE_OBJECT DeviceObject
,
37 IN CLASS_POWER_OPTIONS Options
41 ClasspPowerDownCompletion(
42 IN PDEVICE_OBJECT DeviceObject
,
44 IN PCLASS_POWER_CONTEXT Context
48 ClasspPowerUpCompletion(
49 IN PDEVICE_OBJECT DeviceObject
,
51 IN PCLASS_POWER_CONTEXT Context
56 PDEVICE_OBJECT DeviceObject
,
58 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.
88 IN PDEVICE_OBJECT DeviceObject
,
92 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
94 PCLASS_POWER_DEVICE powerRoutine
= NULL
;
97 // NOTE: This code may be called at PASSIVE or DISPATCH, depending
98 // upon the device object it is being called for.
99 // don't do anything that would break under either circumstance.
104 isRemoved
= ClassAcquireRemoveLock(DeviceObject
, Irp
);
107 ClassReleaseRemoveLock(DeviceObject
, Irp
);
108 Irp
->IoStatus
.Status
= STATUS_DEVICE_DOES_NOT_EXIST
;
109 PoStartNextPowerIrp(Irp
);
110 ClassCompleteRequest(DeviceObject
, Irp
, IO_NO_INCREMENT
);
111 return STATUS_DEVICE_DOES_NOT_EXIST
;
114 return commonExtension
->DevInfo
->ClassPowerDevice(DeviceObject
, Irp
);
115 } // end ClassDispatchPower()
117 /*++////////////////////////////////////////////////////////////////////////////
119 ClasspPowerUpCompletion()
123 This routine is used for intermediate completion of a power up request.
124 PowerUp requires four requests to be sent to the lower driver in sequence.
126 * The queue is "power locked" to ensure that the class driver power-up
127 work can be done before request processing resumes.
129 * The power irp is sent down the stack for any filter drivers and the
130 port driver to return power and resume command processing for the
131 device. Since the queue is locked, no queued irps will be sent
134 * A start unit command is issued to the device with appropriate flags
135 to override the "power locked" queue.
137 * The queue is "power unlocked" to start processing requests again.
139 This routine uses the function in the srb which just completed to determine
140 which state it is in.
144 DeviceObject - the device object being powered up
146 Irp - the IO_REQUEST_PACKET containing the power request
148 Srb - the SRB used to perform port/class operations.
152 STATUS_MORE_PROCESSING_REQUIRED or
157 ClasspPowerUpCompletion(
158 IN PDEVICE_OBJECT DeviceObject
,
160 IN PCLASS_POWER_CONTEXT Context
163 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
164 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
166 PIO_STACK_LOCATION currentStack
= IoGetCurrentIrpStackLocation(Irp
);
167 PIO_STACK_LOCATION nextStack
= IoGetNextIrpStackLocation(Irp
);
170 NTSTATUS status
= STATUS_MORE_PROCESSING_REQUIRED
;
172 DebugPrint((1, "ClasspPowerUpCompletion: Device Object %p, Irp %p, "
174 DeviceObject
, Irp
, Context
));
176 ASSERT(!TEST_FLAG(Context
->Srb
.SrbFlags
, SRB_FLAGS_FREE_SENSE_BUFFER
));
177 ASSERT(!TEST_FLAG(Context
->Srb
.SrbFlags
, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE
));
178 ASSERT(Context
->Options
.PowerDown
== FALSE
);
179 ASSERT(Context
->Options
.HandleSpinUp
);
181 if(Irp
->PendingReturned
) {
182 IoMarkIrpPending(Irp
);
185 Context
->PowerChangeState
.PowerUp
++;
187 switch(Context
->PowerChangeState
.PowerUp
) {
189 case PowerUpDeviceLocked
: {
191 DebugPrint((1, "(%p)\tPreviously sent power lock\n", Irp
));
194 // Issue the actual power request to the lower driver.
197 IoCopyCurrentIrpStackLocationToNext(Irp
);
200 // If the lock wasn't successful then just bail out on the power
201 // request unless we can ignore failed locks
204 if((Context
->Options
.LockQueue
== TRUE
) &&
205 (!NT_SUCCESS(Irp
->IoStatus
.Status
))) {
207 DebugPrint((1, "(%p)\tIrp status was %lx\n",
208 Irp
, Irp
->IoStatus
.Status
));
209 DebugPrint((1, "(%p)\tSrb status was %lx\n",
210 Irp
, Context
->Srb
.SrbStatus
));
213 // Lock was not successful - throw down the power IRP
214 // by itself and don't try to spin up the drive or unlock
218 Context
->InUse
= FALSE
;
222 // Set the new power state
225 fdoExtension
->DevicePowerState
=
226 currentStack
->Parameters
.Power
.State
.DeviceState
;
228 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
230 IoCopyCurrentIrpStackLocationToNext(Irp
);
232 IoSetCompletionRoutine(Irp
,
233 ClasspStartNextPowerIrpCompletion
,
240 // Indicate to Po that we've been successfully powered up so
241 // it can do it's notification stuff.
244 PoSetPowerState(DeviceObject
,
245 currentStack
->Parameters
.Power
.Type
,
246 currentStack
->Parameters
.Power
.State
);
248 PoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
250 ClassReleaseRemoveLock(commonExtension
->DeviceObject
,
253 return STATUS_MORE_PROCESSING_REQUIRED
;
256 Context
->QueueLocked
= (UCHAR
) Context
->Options
.LockQueue
;
259 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
261 Context
->PowerChangeState
.PowerUp
= PowerUpDeviceLocked
;
263 IoSetCompletionRoutine(Irp
,
264 ClasspPowerUpCompletion
,
270 status
= PoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
272 DebugPrint((2, "(%p)\tPoCallDriver returned %lx\n", Irp
, status
));
276 case PowerUpDeviceOn
: {
280 if(NT_SUCCESS(Irp
->IoStatus
.Status
)) {
282 DebugPrint((1, "(%p)\tSending start unit to device\n", Irp
));
285 // Issue the start unit command to the device.
288 Context
->Srb
.Length
= sizeof(SCSI_REQUEST_BLOCK
);
289 Context
->Srb
.Function
= SRB_FUNCTION_EXECUTE_SCSI
;
291 Context
->Srb
.SrbStatus
= Context
->Srb
.ScsiStatus
= 0;
292 Context
->Srb
.DataTransferLength
= 0;
294 Context
->Srb
.TimeOutValue
= START_UNIT_TIMEOUT
;
296 Context
->Srb
.SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
|
297 SRB_FLAGS_DISABLE_AUTOSENSE
|
298 SRB_FLAGS_DISABLE_SYNCH_TRANSFER
|
299 SRB_FLAGS_NO_QUEUE_FREEZE
;
301 if(Context
->Options
.LockQueue
) {
302 SET_FLAG(Context
->Srb
.SrbFlags
, SRB_FLAGS_BYPASS_LOCKED_QUEUE
);
305 Context
->Srb
.CdbLength
= 6;
307 cdb
= (PCDB
) (Context
->Srb
.Cdb
);
308 RtlZeroMemory(cdb
, sizeof(CDB
));
311 cdb
->START_STOP
.OperationCode
= SCSIOP_START_STOP_UNIT
;
312 cdb
->START_STOP
.Start
= 1;
314 Context
->PowerChangeState
.PowerUp
= PowerUpDeviceOn
;
316 IoSetCompletionRoutine(Irp
,
317 ClasspPowerUpCompletion
,
323 nextStack
->Parameters
.Scsi
.Srb
= &(Context
->Srb
);
324 nextStack
->MajorFunction
= IRP_MJ_SCSI
;
326 status
= IoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
328 DebugPrint((2, "(%p)\tIoCallDriver returned %lx\n", Irp
, status
));
336 Context
->FinalStatus
= Irp
->IoStatus
.Status
;
337 goto ClasspPowerUpCompletionFailure
;
343 case PowerUpDeviceStarted
: { // 3
346 // First deal with an error if one occurred.
349 if(SRB_STATUS(Context
->Srb
.SrbStatus
) != SRB_STATUS_SUCCESS
) {
353 DebugPrint((1, "%p\tError occured when issuing START_UNIT "
354 "command to device. Srb %p, Status %x\n",
357 Context
->Srb
.SrbStatus
));
359 ASSERT(!(TEST_FLAG(Context
->Srb
.SrbStatus
,
360 SRB_STATUS_QUEUE_FROZEN
)));
361 ASSERT(Context
->Srb
.Function
== SRB_FUNCTION_EXECUTE_SCSI
);
363 Context
->RetryInterval
= 0;
365 retry
= ClassInterpretSenseInfo(
366 commonExtension
->DeviceObject
,
370 MAXIMUM_RETRIES
- Context
->RetryCount
,
372 &Context
->RetryInterval
);
374 if((retry
== TRUE
) && (Context
->RetryCount
-- != 0)) {
376 DebugPrint((1, "(%p)\tRetrying failed request\n", Irp
));
379 // Decrement the state so we come back through here the
383 Context
->PowerChangeState
.PowerUp
--;
385 RetryPowerRequest(commonExtension
->DeviceObject
,
394 Context
->RetryCount
= MAXIMUM_RETRIES
;
398 ClasspPowerUpCompletionFailure
:
400 DebugPrint((1, "(%p)\tPreviously spun device up\n", Irp
));
402 if (Context
->QueueLocked
) {
403 DebugPrint((1, "(%p)\tUnlocking queue\n", Irp
));
405 Context
->Srb
.Function
= SRB_FUNCTION_UNLOCK_QUEUE
;
406 Context
->Srb
.SrbFlags
= SRB_FLAGS_BYPASS_LOCKED_QUEUE
;
407 Context
->Srb
.SrbStatus
= Context
->Srb
.ScsiStatus
= 0;
408 Context
->Srb
.DataTransferLength
= 0;
410 nextStack
->Parameters
.Scsi
.Srb
= &(Context
->Srb
);
411 nextStack
->MajorFunction
= IRP_MJ_SCSI
;
413 Context
->PowerChangeState
.PowerUp
= PowerUpDeviceStarted
;
415 IoSetCompletionRoutine(Irp
,
416 ClasspPowerUpCompletion
,
422 status
= IoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
423 DebugPrint((1, "(%p)\tIoCallDriver returned %lx\n",
428 // Fall-through to next case...
432 case PowerUpDeviceUnlocked
: {
435 // This is the end of the dance. Free the srb and complete the
436 // request finally. We're ignoring possible intermediate
437 // error conditions ....
440 if (Context
->QueueLocked
) {
441 DebugPrint((1, "(%p)\tPreviously unlocked queue\n", Irp
));
442 ASSERT(NT_SUCCESS(Irp
->IoStatus
.Status
));
443 ASSERT(Context
->Srb
.SrbStatus
== SRB_STATUS_SUCCESS
);
445 DebugPrint((1, "(%p)\tFall-through (queue not locked)\n", Irp
));
448 DebugPrint((1, "(%p)\tFreeing srb and completing\n", Irp
));
449 Context
->InUse
= FALSE
;
451 status
= Context
->FinalStatus
;
452 Irp
->IoStatus
.Status
= status
;
457 // Set the new power state
460 if(NT_SUCCESS(status
)) {
461 fdoExtension
->DevicePowerState
=
462 currentStack
->Parameters
.Power
.State
.DeviceState
;
466 // Indicate to Po that we've been successfully powered up so
467 // it can do it's notification stuff.
470 PoSetPowerState(DeviceObject
,
471 currentStack
->Parameters
.Power
.Type
,
472 currentStack
->Parameters
.Power
.State
);
474 DebugPrint((1, "(%p)\tStarting next power irp\n", Irp
));
475 ClassReleaseRemoveLock(DeviceObject
, Irp
);
476 PoStartNextPowerIrp(Irp
);
482 return STATUS_MORE_PROCESSING_REQUIRED
;
483 } // end ClasspPowerUpCompletion()
485 /*++////////////////////////////////////////////////////////////////////////////
487 ClasspPowerDownCompletion()
491 This routine is used for intermediate completion of a power up request.
492 PowerUp requires four requests to be sent to the lower driver in sequence.
494 * The queue is "power locked" to ensure that the class driver power-up
495 work can be done before request processing resumes.
497 * The power irp is sent down the stack for any filter drivers and the
498 port driver to return power and resume command processing for the
499 device. Since the queue is locked, no queued irps will be sent
502 * A start unit command is issued to the device with appropriate flags
503 to override the "power locked" queue.
505 * The queue is "power unlocked" to start processing requests again.
507 This routine uses the function in the srb which just completed to determine
508 which state it is in.
512 DeviceObject - the device object being powered up
514 Irp - the IO_REQUEST_PACKET containing the power request
516 Srb - the SRB used to perform port/class operations.
520 STATUS_MORE_PROCESSING_REQUIRED or
525 ClasspPowerDownCompletion(
526 IN PDEVICE_OBJECT DeviceObject
,
528 IN PCLASS_POWER_CONTEXT Context
531 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
532 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
534 PIO_STACK_LOCATION currentStack
= IoGetCurrentIrpStackLocation(Irp
);
535 PIO_STACK_LOCATION nextStack
= IoGetNextIrpStackLocation(Irp
);
537 NTSTATUS status
= STATUS_MORE_PROCESSING_REQUIRED
;
539 DebugPrint((1, "ClasspPowerDownCompletion: Device Object %p, "
540 "Irp %p, Context %p\n",
541 DeviceObject
, Irp
, Context
));
543 ASSERT(!TEST_FLAG(Context
->Srb
.SrbFlags
, SRB_FLAGS_FREE_SENSE_BUFFER
));
544 ASSERT(!TEST_FLAG(Context
->Srb
.SrbFlags
, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE
));
545 ASSERT(Context
->Options
.PowerDown
== TRUE
);
546 ASSERT(Context
->Options
.HandleSpinDown
);
548 if(Irp
->PendingReturned
) {
549 IoMarkIrpPending(Irp
);
552 Context
->PowerChangeState
.PowerDown2
++;
554 switch(Context
->PowerChangeState
.PowerDown2
) {
556 case PowerDownDeviceLocked2
: {
560 DebugPrint((1, "(%p)\tPreviously sent power lock\n", Irp
));
562 if((Context
->Options
.LockQueue
== TRUE
) &&
563 (!NT_SUCCESS(Irp
->IoStatus
.Status
))) {
565 DebugPrint((1, "(%p)\tIrp status was %lx\n",
567 Irp
->IoStatus
.Status
));
568 DebugPrint((1, "(%p)\tSrb status was %lx\n",
570 Context
->Srb
.SrbStatus
));
572 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
575 // Lock was not successful - throw down the power IRP
576 // by itself and don't try to spin down the drive or unlock
580 Context
->InUse
= FALSE
;
584 // Set the new power state
587 fdoExtension
->DevicePowerState
=
588 currentStack
->Parameters
.Power
.State
.DeviceState
;
591 // Indicate to Po that we've been successfully powered down
592 // so it can do it's notification stuff.
595 IoCopyCurrentIrpStackLocationToNext(Irp
);
596 IoSetCompletionRoutine(Irp
,
597 ClasspStartNextPowerIrpCompletion
,
603 PoSetPowerState(DeviceObject
,
604 currentStack
->Parameters
.Power
.Type
,
605 currentStack
->Parameters
.Power
.State
);
607 fdoExtension
->PowerDownInProgress
= FALSE
;
609 PoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
611 ClassReleaseRemoveLock(commonExtension
->DeviceObject
,
614 return STATUS_MORE_PROCESSING_REQUIRED
;
617 Context
->QueueLocked
= (UCHAR
) Context
->Options
.LockQueue
;
620 if (!TEST_FLAG(fdoExtension
->PrivateFdoData
->HackFlags
,
621 FDO_HACK_NO_SYNC_CACHE
)) {
624 // send SCSIOP_SYNCHRONIZE_CACHE
627 Context
->Srb
.Length
= sizeof(SCSI_REQUEST_BLOCK
);
628 Context
->Srb
.Function
= SRB_FUNCTION_EXECUTE_SCSI
;
630 Context
->Srb
.TimeOutValue
= fdoExtension
->TimeOutValue
;
632 Context
->Srb
.SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
|
633 SRB_FLAGS_DISABLE_AUTOSENSE
|
634 SRB_FLAGS_DISABLE_SYNCH_TRANSFER
|
635 SRB_FLAGS_NO_QUEUE_FREEZE
|
636 SRB_FLAGS_BYPASS_LOCKED_QUEUE
;
638 Context
->Srb
.SrbStatus
= Context
->Srb
.ScsiStatus
= 0;
639 Context
->Srb
.DataTransferLength
= 0;
641 Context
->Srb
.CdbLength
= 10;
643 cdb
= (PCDB
) Context
->Srb
.Cdb
;
645 RtlZeroMemory(cdb
, sizeof(CDB
));
646 cdb
->SYNCHRONIZE_CACHE10
.OperationCode
= SCSIOP_SYNCHRONIZE_CACHE
;
648 IoSetCompletionRoutine(Irp
,
649 ClasspPowerDownCompletion
,
655 nextStack
->Parameters
.Scsi
.Srb
= &(Context
->Srb
);
656 nextStack
->MajorFunction
= IRP_MJ_SCSI
;
658 status
= IoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
660 DebugPrint((1, "(%p)\tIoCallDriver returned %lx\n", Irp
, status
));
665 DebugPrint((1, "(%p)\tPower Down: not sending SYNCH_CACHE\n",
667 Context
->PowerChangeState
.PowerDown2
++;
668 Context
->Srb
.SrbStatus
= SRB_STATUS_SUCCESS
;
669 // and fall through....
671 // no break in case the device doesn't like synch_cache commands
675 case PowerDownDeviceFlushed2
: {
679 DebugPrint((1, "(%p)\tPreviously send SCSIOP_SYNCHRONIZE_CACHE\n",
683 // SCSIOP_SYNCHRONIZE_CACHE was sent
686 if(SRB_STATUS(Context
->Srb
.SrbStatus
) != SRB_STATUS_SUCCESS
) {
690 DebugPrint((1, "(%p)\tError occured when issuing "
691 "SYNCHRONIZE_CACHE command to device. "
692 "Srb %p, Status %lx\n",
695 Context
->Srb
.SrbStatus
));
697 ASSERT(!(TEST_FLAG(Context
->Srb
.SrbStatus
,
698 SRB_STATUS_QUEUE_FROZEN
)));
699 ASSERT(Context
->Srb
.Function
== SRB_FUNCTION_EXECUTE_SCSI
);
701 Context
->RetryInterval
= 0;
702 retry
= ClassInterpretSenseInfo(
703 commonExtension
->DeviceObject
,
707 MAXIMUM_RETRIES
- Context
->RetryCount
,
709 &Context
->RetryInterval
);
711 if((retry
== TRUE
) && (Context
->RetryCount
-- != 0)) {
713 DebugPrint((1, "(%p)\tRetrying failed request\n", Irp
));
716 // decrement the state so we come back through here
720 Context
->PowerChangeState
.PowerDown2
--;
721 RetryPowerRequest(commonExtension
->DeviceObject
,
727 DebugPrint((1, "(%p)\tSYNCHRONIZE_CACHE not retried\n", Irp
));
728 Context
->RetryCount
= MAXIMUM_RETRIES
;
730 } // end !SRB_STATUS_SUCCESS
733 // note: we are purposefully ignoring any errors. if the drive
734 // doesn't support a synch_cache, then we're up a creek
738 DebugPrint((1, "(%p)\tSending stop unit to device\n", Irp
));
741 // Issue the start unit command to the device.
744 Context
->Srb
.Length
= sizeof(SCSI_REQUEST_BLOCK
);
745 Context
->Srb
.Function
= SRB_FUNCTION_EXECUTE_SCSI
;
747 Context
->Srb
.TimeOutValue
= START_UNIT_TIMEOUT
;
749 Context
->Srb
.SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
|
750 SRB_FLAGS_DISABLE_AUTOSENSE
|
751 SRB_FLAGS_DISABLE_SYNCH_TRANSFER
|
752 SRB_FLAGS_NO_QUEUE_FREEZE
|
753 SRB_FLAGS_BYPASS_LOCKED_QUEUE
;
755 Context
->Srb
.SrbStatus
= Context
->Srb
.ScsiStatus
= 0;
756 Context
->Srb
.DataTransferLength
= 0;
758 Context
->Srb
.CdbLength
= 6;
760 cdb
= (PCDB
) Context
->Srb
.Cdb
;
761 RtlZeroMemory(cdb
, sizeof(CDB
));
763 cdb
->START_STOP
.OperationCode
= SCSIOP_START_STOP_UNIT
;
764 cdb
->START_STOP
.Start
= 0;
765 cdb
->START_STOP
.Immediate
= 1;
767 IoSetCompletionRoutine(Irp
,
768 ClasspPowerDownCompletion
,
774 nextStack
->Parameters
.Scsi
.Srb
= &(Context
->Srb
);
775 nextStack
->MajorFunction
= IRP_MJ_SCSI
;
777 status
= IoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
779 DebugPrint((1, "(%p)\tIoCallDriver returned %lx\n", Irp
, status
));
784 case PowerDownDeviceStopped2
: {
786 BOOLEAN ignoreError
= TRUE
;
792 if(SRB_STATUS(Context
->Srb
.SrbStatus
) != SRB_STATUS_SUCCESS
) {
796 DebugPrint((1, "(%p)\tError occured when issueing STOP_UNIT "
797 "command to device. Srb %p, Status %lx\n",
800 Context
->Srb
.SrbStatus
));
802 ASSERT(!(TEST_FLAG(Context
->Srb
.SrbStatus
,
803 SRB_STATUS_QUEUE_FROZEN
)));
804 ASSERT(Context
->Srb
.Function
== SRB_FUNCTION_EXECUTE_SCSI
);
806 Context
->RetryInterval
= 0;
807 retry
= ClassInterpretSenseInfo(
808 commonExtension
->DeviceObject
,
812 MAXIMUM_RETRIES
- Context
->RetryCount
,
814 &Context
->RetryInterval
);
816 if((retry
== TRUE
) && (Context
->RetryCount
-- != 0)) {
818 DebugPrint((1, "(%p)\tRetrying failed request\n", Irp
));
821 // decrement the state so we come back through here
825 Context
->PowerChangeState
.PowerDown2
--;
826 RetryPowerRequest(commonExtension
->DeviceObject
,
832 DebugPrint((1, "(%p)\tSTOP_UNIT not retried\n", Irp
));
833 Context
->RetryCount
= MAXIMUM_RETRIES
;
835 } // end !SRB_STATUS_SUCCESS
838 DebugPrint((1, "(%p)\tPreviously sent stop unit\n", Irp
));
841 // some operations, such as a physical format in progress,
842 // should not be ignored and should fail the power operation.
845 if (!NT_SUCCESS(status
)) {
847 PSENSE_DATA senseBuffer
= Context
->Srb
.SenseInfoBuffer
;
849 if (TEST_FLAG(Context
->Srb
.SrbStatus
,
850 SRB_STATUS_AUTOSENSE_VALID
) &&
851 ((senseBuffer
->SenseKey
& 0xf) == SCSI_SENSE_NOT_READY
) &&
852 (senseBuffer
->AdditionalSenseCode
== SCSI_ADSENSE_LUN_NOT_READY
) &&
853 (senseBuffer
->AdditionalSenseCodeQualifier
== SCSI_SENSEQ_FORMAT_IN_PROGRESS
)
856 Context
->FinalStatus
= STATUS_DEVICE_BUSY
;
857 status
= Context
->FinalStatus
;
862 if (NT_SUCCESS(status
) || ignoreError
) {
865 // Issue the actual power request to the lower driver.
868 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
870 IoCopyCurrentIrpStackLocationToNext(Irp
);
872 IoSetCompletionRoutine(Irp
,
873 ClasspPowerDownCompletion
,
879 status
= PoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
881 DebugPrint((1, "(%p)\tPoCallDriver returned %lx\n", Irp
, status
));
885 // else fall through w/o sending the power irp, since the device
886 // is reporting an error that would be "really bad" to power down
891 case PowerDownDeviceOff2
: {
894 // SpinDown request completed ... whether it succeeded or not is
895 // another matter entirely.
898 DebugPrint((1, "(%p)\tPreviously sent power irp\n", Irp
));
900 if (Context
->QueueLocked
) {
902 DebugPrint((1, "(%p)\tUnlocking queue\n", Irp
));
904 Context
->Srb
.Length
= sizeof(SCSI_REQUEST_BLOCK
);
906 Context
->Srb
.SrbStatus
= Context
->Srb
.ScsiStatus
= 0;
907 Context
->Srb
.DataTransferLength
= 0;
909 Context
->Srb
.Function
= SRB_FUNCTION_UNLOCK_QUEUE
;
910 Context
->Srb
.SrbFlags
= SRB_FLAGS_BYPASS_LOCKED_QUEUE
;
911 nextStack
->Parameters
.Scsi
.Srb
= &(Context
->Srb
);
912 nextStack
->MajorFunction
= IRP_MJ_SCSI
;
914 IoSetCompletionRoutine(Irp
,
915 ClasspPowerDownCompletion
,
921 status
= IoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
922 DebugPrint((1, "(%p)\tIoCallDriver returned %lx\n",
930 case PowerDownDeviceUnlocked2
: {
933 // This is the end of the dance. Free the srb and complete the
934 // request finally. We're ignoring possible intermediate
935 // error conditions ....
938 if (Context
->QueueLocked
== FALSE
) {
939 DebugPrint((1, "(%p)\tFall through (queue not locked)\n", Irp
));
941 DebugPrint((1, "(%p)\tPreviously unlocked queue\n", Irp
));
942 ASSERT(NT_SUCCESS(Irp
->IoStatus
.Status
));
943 ASSERT(Context
->Srb
.SrbStatus
== SRB_STATUS_SUCCESS
);
946 DebugPrint((1, "(%p)\tFreeing srb and completing\n", Irp
));
947 Context
->InUse
= FALSE
;
948 status
= Context
->FinalStatus
; // allow failure to propogate
951 if(Irp
->PendingReturned
) {
952 IoMarkIrpPending(Irp
);
955 Irp
->IoStatus
.Status
= status
;
956 Irp
->IoStatus
.Information
= 0;
958 if (NT_SUCCESS(status
)) {
961 // Set the new power state
964 fdoExtension
->DevicePowerState
=
965 currentStack
->Parameters
.Power
.State
.DeviceState
;
970 DebugPrint((1, "(%p)\tStarting next power irp\n", Irp
));
972 ClassReleaseRemoveLock(DeviceObject
, Irp
);
973 PoStartNextPowerIrp(Irp
);
974 fdoExtension
->PowerDownInProgress
= FALSE
;
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
1007 IN PDEVICE_OBJECT DeviceObject
,
1009 IN CLASS_POWER_OPTIONS Options
// ISSUE-2000/02/20-henrygab - pass pointer, not whole struct
1012 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
1013 PDEVICE_OBJECT lowerDevice
= commonExtension
->LowerDeviceObject
;
1014 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
1015 PIO_STACK_LOCATION nextIrpStack
;
1016 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
1017 PCLASS_POWER_CONTEXT context
;
1019 if (!commonExtension
->IsFdo
) {
1022 // certain assumptions are made here,
1023 // particularly: having the fdoExtension
1026 DebugPrint((0, "ClasspPowerHandler: Called for PDO %p???\n",
1028 ASSERT(!"PDO using ClasspPowerHandler");
1029 return STATUS_NOT_SUPPORTED
;
1032 DebugPrint((1, "ClasspPowerHandler: Power irp %p to %s %p\n",
1033 Irp
, (commonExtension
->IsFdo
? "fdo" : "pdo"), DeviceObject
));
1035 switch(irpStack
->MinorFunction
) {
1037 case IRP_MN_SET_POWER
: {
1038 PCLASS_PRIVATE_FDO_DATA fdoData
= fdoExtension
->PrivateFdoData
;
1040 DebugPrint((1, "(%p)\tIRP_MN_SET_POWER\n", Irp
));
1042 DebugPrint((1, "(%p)\tSetting %s state to %d\n",
1044 (irpStack
->Parameters
.Power
.Type
== SystemPowerState
?
1045 "System" : "Device"),
1046 irpStack
->Parameters
.Power
.State
.SystemState
));
1048 switch (irpStack
->Parameters
.Power
.ShutdownType
){
1050 case PowerActionSleep
:
1051 case PowerActionHibernate
:
1052 if (fdoData
->HotplugInfo
.MediaRemovable
|| fdoData
->HotplugInfo
.MediaHotplug
){
1054 * We are suspending and this drive is either hot-pluggable
1055 * or contains removeable media.
1056 * Set the media dirty bit, since the media may change while
1059 SET_FLAG(DeviceObject
->Flags
, DO_VERIFY_VOLUME
);
1069 DebugPrint((1, "(%p)\tIrp minor code = %#x\n",
1070 Irp
, irpStack
->MinorFunction
));
1075 if (irpStack
->Parameters
.Power
.Type
!= DevicePowerState
||
1076 irpStack
->MinorFunction
!= IRP_MN_SET_POWER
) {
1078 DebugPrint((1, "(%p)\tSending to lower device\n", Irp
));
1080 goto ClasspPowerHandlerCleanup
;
1084 nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
1087 // already in exact same state, don't work to transition to it.
1090 if(irpStack
->Parameters
.Power
.State
.DeviceState
==
1091 fdoExtension
->DevicePowerState
) {
1093 DebugPrint((1, "(%p)\tAlready in device state %x\n",
1094 Irp
, fdoExtension
->DevicePowerState
));
1095 goto ClasspPowerHandlerCleanup
;
1100 // or powering down from non-d0 state (device already stopped)
1101 // NOTE -- we're not sure whether this case can exist or not (the
1102 // power system may never send this sort of request) but it's trivial
1106 if ((irpStack
->Parameters
.Power
.State
.DeviceState
!= PowerDeviceD0
) &&
1107 (fdoExtension
->DevicePowerState
!= PowerDeviceD0
)) {
1108 DebugPrint((1, "(%p)\tAlready powered down to %x???\n",
1109 Irp
, fdoExtension
->DevicePowerState
));
1110 fdoExtension
->DevicePowerState
=
1111 irpStack
->Parameters
.Power
.State
.DeviceState
;
1112 goto ClasspPowerHandlerCleanup
;
1116 // or going into a hibernation state when we're in the hibernation path.
1117 // If the device is spinning then we should leave it spinning - if it's not
1118 // then the dump driver will start it up for us.
1121 if((irpStack
->Parameters
.Power
.State
.DeviceState
== PowerDeviceD3
) &&
1122 (irpStack
->Parameters
.Power
.ShutdownType
== PowerActionHibernate
) &&
1123 (commonExtension
->HibernationPathCount
!= 0)) {
1125 DebugPrint((1, "(%p)\tdoing nothing for hibernation request for "
1127 Irp
, fdoExtension
->DevicePowerState
));
1128 fdoExtension
->DevicePowerState
=
1129 irpStack
->Parameters
.Power
.State
.DeviceState
;
1130 goto ClasspPowerHandlerCleanup
;
1133 // or when not handling powering up and are powering up
1136 if ((!Options
.HandleSpinUp
) &&
1137 (irpStack
->Parameters
.Power
.State
.DeviceState
== PowerDeviceD0
)) {
1139 DebugPrint((2, "(%p)\tNot handling spinup to state %x\n",
1140 Irp
, fdoExtension
->DevicePowerState
));
1141 fdoExtension
->DevicePowerState
=
1142 irpStack
->Parameters
.Power
.State
.DeviceState
;
1143 goto ClasspPowerHandlerCleanup
;
1148 // or when not handling powering down and are powering down
1151 if ((!Options
.HandleSpinDown
) &&
1152 (irpStack
->Parameters
.Power
.State
.DeviceState
!= PowerDeviceD0
)) {
1154 DebugPrint((2, "(%p)\tNot handling spindown to state %x\n",
1155 Irp
, fdoExtension
->DevicePowerState
));
1156 fdoExtension
->DevicePowerState
=
1157 irpStack
->Parameters
.Power
.State
.DeviceState
;
1158 goto ClasspPowerHandlerCleanup
;
1162 context
= &(fdoExtension
->PowerContext
);
1166 // Mark the context as in use. We should be synchronizing this but
1167 // since it's just for debugging purposes we don't worry too much.
1170 ASSERT(context
->InUse
== FALSE
);
1173 RtlZeroMemory(context
, sizeof(CLASS_POWER_CONTEXT
));
1174 context
->InUse
= TRUE
;
1176 nextIrpStack
->Parameters
.Scsi
.Srb
= &(context
->Srb
);
1177 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
1179 context
->FinalStatus
= STATUS_SUCCESS
;
1181 context
->Srb
.Length
= sizeof(SCSI_REQUEST_BLOCK
);
1182 context
->Srb
.OriginalRequest
= Irp
;
1183 context
->Srb
.SrbFlags
|= SRB_FLAGS_BYPASS_LOCKED_QUEUE
1184 | SRB_FLAGS_NO_QUEUE_FREEZE
;
1185 context
->Srb
.Function
= SRB_FUNCTION_LOCK_QUEUE
;
1187 context
->Srb
.SenseInfoBuffer
=
1188 commonExtension
->PartitionZeroExtension
->SenseData
;
1189 context
->Srb
.SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
1190 context
->RetryCount
= MAXIMUM_RETRIES
;
1192 context
->Options
= Options
;
1193 context
->DeviceObject
= DeviceObject
;
1196 if(irpStack
->Parameters
.Power
.State
.DeviceState
== PowerDeviceD0
) {
1198 ASSERT(Options
.HandleSpinUp
);
1200 DebugPrint((2, "(%p)\tpower up - locking queue\n", Irp
));
1203 // We need to issue a queue lock request so that we
1204 // can spin the drive back up after the power is restored
1205 // but before any requests are processed.
1208 context
->Options
.PowerDown
= FALSE
;
1209 context
->PowerChangeState
.PowerUp
= PowerUpDeviceInitial
;
1210 context
->CompletionRoutine
= ClasspPowerUpCompletion
;
1214 ASSERT(Options
.HandleSpinDown
);
1216 fdoExtension
->PowerDownInProgress
= TRUE
;
1218 DebugPrint((2, "(%p)\tPowering down - locking queue\n", Irp
));
1220 PoSetPowerState(DeviceObject
,
1221 irpStack
->Parameters
.Power
.Type
,
1222 irpStack
->Parameters
.Power
.State
);
1224 context
->Options
.PowerDown
= TRUE
;
1225 context
->PowerChangeState
.PowerDown2
= PowerDownDeviceInitial2
;
1226 context
->CompletionRoutine
= ClasspPowerDownCompletion
;
1231 // we are not dealing with port-allocated sense in these routines.
1234 ASSERT(!TEST_FLAG(context
->Srb
.SrbFlags
, SRB_FLAGS_FREE_SENSE_BUFFER
));
1235 ASSERT(!TEST_FLAG(context
->Srb
.SrbFlags
, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE
));
1238 // we are always returning STATUS_PENDING, so we need to always
1239 // set the irp as pending.
1242 IoMarkIrpPending(Irp
);
1244 if(Options
.LockQueue
) {
1247 // Send the lock irp down.
1250 IoSetCompletionRoutine(Irp
,
1251 context
->CompletionRoutine
,
1257 IoCallDriver(lowerDevice
, Irp
);
1262 // Call the completion routine directly. It won't care what the
1263 // status of the "lock" was - it will just go and do the next
1264 // step of the operation.
1267 context
->CompletionRoutine(DeviceObject
, Irp
, context
);
1270 return STATUS_PENDING
;
1272 ClasspPowerHandlerCleanup
:
1274 ClassReleaseRemoveLock(DeviceObject
, Irp
);
1276 DebugPrint((1, "(%p)\tStarting next power irp\n", Irp
));
1277 IoCopyCurrentIrpStackLocationToNext(Irp
);
1278 IoSetCompletionRoutine(Irp
,
1279 ClasspStartNextPowerIrpCompletion
,
1284 return PoCallDriver(lowerDevice
, Irp
);
1285 } // end ClasspPowerHandler()
1287 /*++////////////////////////////////////////////////////////////////////////////
1289 ClassMinimalPowerHandler()
1291 Routine Description:
1293 This routine is the minimum power handler for a storage driver. It does
1294 the least amount of work possible.
1298 ClassMinimalPowerHandler(
1299 IN PDEVICE_OBJECT DeviceObject
,
1303 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
1304 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
1307 ClassReleaseRemoveLock(DeviceObject
, Irp
);
1308 PoStartNextPowerIrp(Irp
);
1310 if(commonExtension
->IsFdo
) {
1312 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
1314 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
=
1315 DeviceObject
->DeviceExtension
;
1318 // Check if the system is going to hibernate or standby.
1320 if (irpStack
->MinorFunction
== IRP_MN_SET_POWER
){
1323 switch (irpStack
->Parameters
.Power
.ShutdownType
){
1325 case PowerActionSleep
:
1326 case PowerActionHibernate
:
1328 // If the volume is mounted, set the verify bit so that
1329 // the filesystem will be forced re-read the media
1330 // after coming out of hibernation or standby.
1332 vpb
= ClassGetVpb(fdoExtension
->DeviceObject
);
1333 if (vpb
&& (vpb
->Flags
& VPB_MOUNTED
)){
1334 SET_FLAG(fdoExtension
->DeviceObject
->Flags
, DO_VERIFY_VOLUME
);
1341 IoCopyCurrentIrpStackLocationToNext(Irp
);
1342 return PoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
1346 if (irpStack
->MinorFunction
!= IRP_MN_SET_POWER
&&
1347 irpStack
->MinorFunction
!= IRP_MN_QUERY_POWER
) {
1353 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1354 Irp
->IoStatus
.Information
= 0;
1357 status
= Irp
->IoStatus
.Status
;
1359 ClassCompleteRequest(DeviceObject
, Irp
, IO_NO_INCREMENT
);
1362 } // end ClassMinimalPowerHandler()
1364 /*++////////////////////////////////////////////////////////////////////////////
1366 ClassSpinDownPowerHandler()
1368 Routine Description:
1370 This routine is a callback for disks and other things which require both
1371 a start and a stop to be sent to the device. (actually the starts are
1372 almost always optional, since most device power themselves on to process
1373 commands, but i digress).
1375 Determines proper use of spinup, spindown, and queue locking based upon
1376 ScanForSpecialFlags in the FdoExtension. This is the most common power
1377 handler passed into classpnp.sys
1381 DeviceObject - Supplies the functional device object
1383 Irp - Supplies the request to be retried.
1393 ClassSpinDownPowerHandler(
1394 IN PDEVICE_OBJECT DeviceObject
,
1398 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
;
1399 CLASS_POWER_OPTIONS options
;
1401 fdoExtension
= (PFUNCTIONAL_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
1404 // this will set all options to FALSE
1407 RtlZeroMemory(&options
, sizeof(CLASS_POWER_OPTIONS
));
1410 // check the flags to see what options we need to worry about
1413 if (!TEST_FLAG(fdoExtension
->ScanForSpecialFlags
,
1414 CLASS_SPECIAL_DISABLE_SPIN_DOWN
)) {
1415 options
.HandleSpinDown
= TRUE
;
1418 if (!TEST_FLAG(fdoExtension
->ScanForSpecialFlags
,
1419 CLASS_SPECIAL_DISABLE_SPIN_UP
)) {
1420 options
.HandleSpinUp
= TRUE
;
1423 if (!TEST_FLAG(fdoExtension
->ScanForSpecialFlags
,
1424 CLASS_SPECIAL_NO_QUEUE_LOCK
)) {
1425 options
.LockQueue
= TRUE
;
1428 DebugPrint((3, "ClasspPowerHandler: Devobj %p\n"
1429 "\t%shandling spin down\n"
1430 "\t%shandling spin up\n"
1431 "\t%slocking queue\n",
1433 (options
.HandleSpinDown
? "" : "not "),
1434 (options
.HandleSpinUp
? "" : "not "),
1435 (options
.LockQueue
? "" : "not ")
1439 // do all the dirty work
1442 return ClasspPowerHandler(DeviceObject
, Irp
, options
);
1443 } // end ClassSpinDownPowerHandler()
1445 /*++////////////////////////////////////////////////////////////////////////////
1447 ClassStopUnitPowerHandler()
1449 Routine Description:
1451 This routine is an outdated call. To achieve equivalent functionality,
1452 the driver should set the following flags in ScanForSpecialFlags in the
1455 CLASS_SPECIAL_DISABLE_SPIN_UP
1456 CLASS_SPECIAL_NO_QUEUE_LOCK
1462 ClassStopUnitPowerHandler(
1463 IN PDEVICE_OBJECT DeviceObject
,
1467 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
;
1469 DebugPrint((0, "ClassStopUnitPowerHandler - Devobj %p using outdated call\n"
1470 "Drivers should set the following flags in ScanForSpecialFlags "
1471 " in the FDO extension:\n"
1472 "\tCLASS_SPECIAL_DISABLE_SPIN_UP\n"
1473 "\tCLASS_SPECIAL_NO_QUEUE_LOCK\n"
1474 "This will provide equivalent functionality if the power "
1475 "routine is then set to ClassSpinDownPowerHandler\n\n",
1478 fdoExtension
= (PFUNCTIONAL_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
1480 SET_FLAG(fdoExtension
->ScanForSpecialFlags
,
1481 CLASS_SPECIAL_DISABLE_SPIN_UP
);
1482 SET_FLAG(fdoExtension
->ScanForSpecialFlags
,
1483 CLASS_SPECIAL_NO_QUEUE_LOCK
);
1485 return ClassSpinDownPowerHandler(DeviceObject
, Irp
);
1486 } // end ClassStopUnitPowerHandler()
1488 /*++////////////////////////////////////////////////////////////////////////////
1492 Routine Description:
1494 This routine reinitalizes the necessary fields, and sends the request
1495 to the lower driver.
1499 DeviceObject - Supplies the device object associated with this request.
1501 Irp - Supplies the request to be retried.
1503 Context - Supplies a pointer to the power up context for this request.
1512 PDEVICE_OBJECT DeviceObject
,
1514 PCLASS_POWER_CONTEXT Context
1517 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
1518 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
1519 PIO_STACK_LOCATION nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
1520 PSCSI_REQUEST_BLOCK srb
= &(Context
->Srb
);
1521 LARGE_INTEGER dueTime
;
1523 DebugPrint((1, "(%p)\tDelaying retry by queueing DPC\n", Irp
));
1525 ASSERT(Context
->Irp
== Irp
);
1526 ASSERT(Context
->DeviceObject
== DeviceObject
);
1527 ASSERT(!TEST_FLAG(Context
->Srb
.SrbFlags
, SRB_FLAGS_FREE_SENSE_BUFFER
));
1528 ASSERT(!TEST_FLAG(Context
->Srb
.SrbFlags
, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE
));
1531 // reset the retry interval
1534 Context
->RetryInterval
= 0;
1537 // Reset byte count of transfer in SRB Extension.
1540 srb
->DataTransferLength
= 0;
1543 // Zero SRB statuses.
1546 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
1549 // Set up major SCSI function.
1552 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
1555 // Save SRB address in next stack for port driver.
1558 nextIrpStack
->Parameters
.Scsi
.Srb
= srb
;
1561 // Set the completion routine up again.
1564 IoSetCompletionRoutine(Irp
, Context
->CompletionRoutine
, Context
,
1568 if (Context
->RetryInterval
== 0) {
1570 DebugPrint((2, "(%p)\tDelaying minimum time (.2 sec)\n", Irp
));
1571 dueTime
.QuadPart
= (LONGLONG
)1000000 * 2;
1575 DebugPrint((2, "(%p)\tDelaying %x seconds\n",
1576 Irp
, Context
->RetryInterval
));
1577 dueTime
.QuadPart
= (LONGLONG
)1000000 * 10 * Context
->RetryInterval
;
1581 ClassRetryRequest(DeviceObject
, Irp
, dueTime
);
1585 } // end RetryRequest()
1587 /*++////////////////////////////////////////////////////////////////////////////
1589 ClasspStartNextPowerIrpCompletion()
1591 Routine Description:
1593 This routine guarantees that the next power irp (power up or down) is not
1594 sent until the previous one has fully completed.
1598 ClasspStartNextPowerIrpCompletion(
1599 IN PDEVICE_OBJECT DeviceObject
,
1604 if(Irp
->PendingReturned
) {
1605 IoMarkIrpPending(Irp
);
1608 PoStartNextPowerIrp(Irp
);
1609 return STATUS_SUCCESS
;
1610 } // end ClasspStartNextPowerIrpCompletion()