Sync with trunk r58151 to bring the latest changes from Amine and Timo.
[reactos.git] / drivers / storage / classpnp / power.c
1 /*++
2
3 Copyright (C) Microsoft Corporation, 1991 - 1999
4
5 Module Name:
6
7 class.c
8
9 Abstract:
10
11 SCSI class driver routines
12
13 Environment:
14
15 kernel mode only
16
17 Notes:
18
19
20 Revision History:
21
22 --*/
23
24 #include "classp.h"
25
26 #define CLASS_TAG_POWER 'WLcS'
27
28 NTSTATUS
29 NTAPI
30 ClasspPowerHandler(
31 IN PDEVICE_OBJECT DeviceObject,
32 IN PIRP Irp,
33 IN CLASS_POWER_OPTIONS Options
34 );
35
36 NTSTATUS
37 NTAPI
38 ClasspPowerDownCompletion(
39 IN PDEVICE_OBJECT DeviceObject,
40 IN PIRP Irp,
41 IN PCLASS_POWER_CONTEXT Context
42 );
43
44 NTSTATUS
45 NTAPI
46 ClasspPowerUpCompletion(
47 IN PDEVICE_OBJECT DeviceObject,
48 IN PIRP Irp,
49 IN PCLASS_POWER_CONTEXT Context
50 );
51
52 VOID
53 NTAPI
54 RetryPowerRequest(
55 PDEVICE_OBJECT DeviceObject,
56 PIRP Irp,
57 PCLASS_POWER_CONTEXT Context
58 );
59
60 NTSTATUS
61 NTAPI
62 ClasspStartNextPowerIrpCompletion(
63 IN PDEVICE_OBJECT DeviceObject,
64 IN PIRP Irp,
65 IN PVOID Context
66 );
67
68
69 /*++////////////////////////////////////////////////////////////////////////////
70
71 ClassDispatchPower()
72
73 Routine Description:
74
75 This routine acquires the removelock for the irp and then calls the
76 appropriate power callback.
77
78 Arguments:
79
80 DeviceObject -
81 Irp -
82
83 Return Value:
84
85 --*/
86 NTSTATUS
87 NTAPI
88 ClassDispatchPower(
89 IN PDEVICE_OBJECT DeviceObject,
90 IN PIRP Irp
91 )
92 {
93 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
94 ULONG isRemoved;
95 PCLASS_POWER_DEVICE powerRoutine = NULL;
96
97 //
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.
101 //
102
103 //NTSTATUS status;
104
105 isRemoved = ClassAcquireRemoveLock(DeviceObject, Irp);
106
107 if(isRemoved) {
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;
113 }
114
115 return commonExtension->DevInfo->ClassPowerDevice(DeviceObject, Irp);
116 } // end ClassDispatchPower()
117
118 /*++////////////////////////////////////////////////////////////////////////////
119
120 ClasspPowerUpCompletion()
121
122 Routine Description:
123
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.
126
127 * The queue is "power locked" to ensure that the class driver power-up
128 work can be done before request processing resumes.
129
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
133 immediately.
134
135 * A start unit command is issued to the device with appropriate flags
136 to override the "power locked" queue.
137
138 * The queue is "power unlocked" to start processing requests again.
139
140 This routine uses the function in the srb which just completed to determine
141 which state it is in.
142
143 Arguments:
144
145 DeviceObject - the device object being powered up
146
147 Irp - the IO_REQUEST_PACKET containing the power request
148
149 Srb - the SRB used to perform port/class operations.
150
151 Return Value:
152
153 STATUS_MORE_PROCESSING_REQUIRED or
154 STATUS_SUCCESS
155
156 --*/
157 NTSTATUS
158 NTAPI
159 ClasspPowerUpCompletion(
160 IN PDEVICE_OBJECT DeviceObject,
161 IN PIRP Irp,
162 IN PCLASS_POWER_CONTEXT Context
163 )
164 {
165 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
166 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
167
168 PIO_STACK_LOCATION currentStack = IoGetCurrentIrpStackLocation(Irp);
169 PIO_STACK_LOCATION nextStack = IoGetNextIrpStackLocation(Irp);
170
171
172 NTSTATUS status = STATUS_MORE_PROCESSING_REQUIRED;
173
174 DebugPrint((1, "ClasspPowerUpCompletion: Device Object %p, Irp %p, "
175 "Context %p\n",
176 DeviceObject, Irp, Context));
177
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);
182
183 if(Irp->PendingReturned) {
184 IoMarkIrpPending(Irp);
185 }
186
187 Context->PowerChangeState.PowerUp++;
188
189 switch(Context->PowerChangeState.PowerUp) {
190
191 case PowerUpDeviceLocked: {
192
193 DebugPrint((1, "(%p)\tPreviously sent power lock\n", Irp));
194
195 //
196 // Issue the actual power request to the lower driver.
197 //
198
199 IoCopyCurrentIrpStackLocationToNext(Irp);
200
201 //
202 // If the lock wasn't successful then just bail out on the power
203 // request unless we can ignore failed locks
204 //
205
206 if((Context->Options.LockQueue == TRUE) &&
207 (!NT_SUCCESS(Irp->IoStatus.Status))) {
208
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));
213
214 //
215 // Lock was not successful - throw down the power IRP
216 // by itself and don't try to spin up the drive or unlock
217 // the queue.
218 //
219
220 Context->InUse = FALSE;
221 Context = NULL;
222
223 //
224 // Set the new power state
225 //
226
227 fdoExtension->DevicePowerState =
228 currentStack->Parameters.Power.State.DeviceState;
229
230 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
231
232 IoCopyCurrentIrpStackLocationToNext(Irp);
233
234 IoSetCompletionRoutine(Irp,
235 ClasspStartNextPowerIrpCompletion,
236 NULL,
237 TRUE,
238 TRUE,
239 TRUE);
240
241 //
242 // Indicate to Po that we've been successfully powered up so
243 // it can do it's notification stuff.
244 //
245
246 PoSetPowerState(DeviceObject,
247 currentStack->Parameters.Power.Type,
248 currentStack->Parameters.Power.State);
249
250 PoCallDriver(commonExtension->LowerDeviceObject, Irp);
251
252 ClassReleaseRemoveLock(commonExtension->DeviceObject,
253 Irp);
254
255 return STATUS_MORE_PROCESSING_REQUIRED;
256
257 } else {
258 Context->QueueLocked = (UCHAR) Context->Options.LockQueue;
259 }
260
261 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
262
263 Context->PowerChangeState.PowerUp = PowerUpDeviceLocked;
264
265 IoSetCompletionRoutine(Irp,
266 ClasspPowerUpCompletion,
267 Context,
268 TRUE,
269 TRUE,
270 TRUE);
271
272 status = PoCallDriver(commonExtension->LowerDeviceObject, Irp);
273
274 DebugPrint((2, "(%p)\tPoCallDriver returned %lx\n", Irp, status));
275 break;
276 }
277
278 case PowerUpDeviceOn: {
279
280 PCDB cdb;
281
282 if(NT_SUCCESS(Irp->IoStatus.Status)) {
283
284 DebugPrint((1, "(%p)\tSending start unit to device\n", Irp));
285
286 //
287 // Issue the start unit command to the device.
288 //
289
290 Context->Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
291 Context->Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
292
293 Context->Srb.SrbStatus = Context->Srb.ScsiStatus = 0;
294 Context->Srb.DataTransferLength = 0;
295
296 Context->Srb.TimeOutValue = START_UNIT_TIMEOUT;
297
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;
302
303 if(Context->Options.LockQueue) {
304 SET_FLAG(Context->Srb.SrbFlags, SRB_FLAGS_BYPASS_LOCKED_QUEUE);
305 }
306
307 Context->Srb.CdbLength = 6;
308
309 cdb = (PCDB) (Context->Srb.Cdb);
310 RtlZeroMemory(cdb, sizeof(CDB));
311
312
313 cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
314 cdb->START_STOP.Start = 1;
315
316 Context->PowerChangeState.PowerUp = PowerUpDeviceOn;
317
318 IoSetCompletionRoutine(Irp,
319 ClasspPowerUpCompletion,
320 Context,
321 TRUE,
322 TRUE,
323 TRUE);
324
325 nextStack->Parameters.Scsi.Srb = &(Context->Srb);
326 nextStack->MajorFunction = IRP_MJ_SCSI;
327
328 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
329
330 DebugPrint((2, "(%p)\tIoCallDriver returned %lx\n", Irp, status));
331
332 } else {
333
334 //
335 // we're done.
336 //
337
338 Context->FinalStatus = Irp->IoStatus.Status;
339 goto ClasspPowerUpCompletionFailure;
340 }
341
342 break;
343 }
344
345 case PowerUpDeviceStarted: { // 3
346
347 //
348 // First deal with an error if one occurred.
349 //
350
351 if(SRB_STATUS(Context->Srb.SrbStatus) != SRB_STATUS_SUCCESS) {
352
353 BOOLEAN retry;
354
355 DebugPrint((1, "%p\tError occured when issuing START_UNIT "
356 "command to device. Srb %p, Status %x\n",
357 Irp,
358 &Context->Srb,
359 Context->Srb.SrbStatus));
360
361 ASSERT(!(TEST_FLAG(Context->Srb.SrbStatus,
362 SRB_STATUS_QUEUE_FROZEN)));
363 ASSERT(Context->Srb.Function == SRB_FUNCTION_EXECUTE_SCSI);
364
365 Context->RetryInterval = 0;
366
367 retry = ClassInterpretSenseInfo(
368 commonExtension->DeviceObject,
369 &Context->Srb,
370 IRP_MJ_SCSI,
371 IRP_MJ_POWER,
372 MAXIMUM_RETRIES - Context->RetryCount,
373 &status,
374 &Context->RetryInterval);
375
376 if((retry == TRUE) && (Context->RetryCount-- != 0)) {
377
378 DebugPrint((1, "(%p)\tRetrying failed request\n", Irp));
379
380 //
381 // Decrement the state so we come back through here the
382 // next time.
383 //
384
385 Context->PowerChangeState.PowerUp--;
386
387 RetryPowerRequest(commonExtension->DeviceObject,
388 Irp,
389 Context);
390
391 break;
392
393 }
394
395 // reset retries
396 Context->RetryCount = MAXIMUM_RETRIES;
397
398 }
399
400 ClasspPowerUpCompletionFailure:
401
402 DebugPrint((1, "(%p)\tPreviously spun device up\n", Irp));
403
404 if (Context->QueueLocked) {
405 DebugPrint((1, "(%p)\tUnlocking queue\n", Irp));
406
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;
411
412 nextStack->Parameters.Scsi.Srb = &(Context->Srb);
413 nextStack->MajorFunction = IRP_MJ_SCSI;
414
415 Context->PowerChangeState.PowerUp = PowerUpDeviceStarted;
416
417 IoSetCompletionRoutine(Irp,
418 ClasspPowerUpCompletion,
419 Context,
420 TRUE,
421 TRUE,
422 TRUE);
423
424 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
425 DebugPrint((1, "(%p)\tIoCallDriver returned %lx\n",
426 Irp, status));
427 break;
428 }
429
430 // Fall-through to next case...
431
432 }
433
434 case PowerUpDeviceUnlocked: {
435
436 //
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 ....
440 //
441
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);
446 } else {
447 DebugPrint((1, "(%p)\tFall-through (queue not locked)\n", Irp));
448 }
449
450 DebugPrint((1, "(%p)\tFreeing srb and completing\n", Irp));
451 Context->InUse = FALSE;
452
453 status = Context->FinalStatus;
454 Irp->IoStatus.Status = status;
455
456 Context = NULL;
457
458 //
459 // Set the new power state
460 //
461
462 if(NT_SUCCESS(status)) {
463 fdoExtension->DevicePowerState =
464 currentStack->Parameters.Power.State.DeviceState;
465 }
466
467 //
468 // Indicate to Po that we've been successfully powered up so
469 // it can do it's notification stuff.
470 //
471
472 PoSetPowerState(DeviceObject,
473 currentStack->Parameters.Power.Type,
474 currentStack->Parameters.Power.State);
475
476 DebugPrint((1, "(%p)\tStarting next power irp\n", Irp));
477 ClassReleaseRemoveLock(DeviceObject, Irp);
478 PoStartNextPowerIrp(Irp);
479
480 return status;
481 }
482 }
483
484 return STATUS_MORE_PROCESSING_REQUIRED;
485 } // end ClasspPowerUpCompletion()
486
487 /*++////////////////////////////////////////////////////////////////////////////
488
489 ClasspPowerDownCompletion()
490
491 Routine Description:
492
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.
495
496 * The queue is "power locked" to ensure that the class driver power-up
497 work can be done before request processing resumes.
498
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
502 immediately.
503
504 * A start unit command is issued to the device with appropriate flags
505 to override the "power locked" queue.
506
507 * The queue is "power unlocked" to start processing requests again.
508
509 This routine uses the function in the srb which just completed to determine
510 which state it is in.
511
512 Arguments:
513
514 DeviceObject - the device object being powered up
515
516 Irp - the IO_REQUEST_PACKET containing the power request
517
518 Srb - the SRB used to perform port/class operations.
519
520 Return Value:
521
522 STATUS_MORE_PROCESSING_REQUIRED or
523 STATUS_SUCCESS
524
525 --*/
526 NTSTATUS
527 NTAPI
528 ClasspPowerDownCompletion(
529 IN PDEVICE_OBJECT DeviceObject,
530 IN PIRP Irp,
531 IN PCLASS_POWER_CONTEXT Context
532 )
533 {
534 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
535 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
536
537 PIO_STACK_LOCATION currentStack = IoGetCurrentIrpStackLocation(Irp);
538 PIO_STACK_LOCATION nextStack = IoGetNextIrpStackLocation(Irp);
539
540 NTSTATUS status = STATUS_MORE_PROCESSING_REQUIRED;
541
542 DebugPrint((1, "ClasspPowerDownCompletion: Device Object %p, "
543 "Irp %p, Context %p\n",
544 DeviceObject, Irp, Context));
545
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);
550
551 if(Irp->PendingReturned) {
552 IoMarkIrpPending(Irp);
553 }
554
555 Context->PowerChangeState.PowerDown2++;
556
557 switch(Context->PowerChangeState.PowerDown2) {
558
559 case PowerDownDeviceLocked2: {
560
561 PCDB cdb;
562
563 DebugPrint((1, "(%p)\tPreviously sent power lock\n", Irp));
564
565 if((Context->Options.LockQueue == TRUE) &&
566 (!NT_SUCCESS(Irp->IoStatus.Status))) {
567
568 DebugPrint((1, "(%p)\tIrp status was %lx\n",
569 Irp,
570 Irp->IoStatus.Status));
571 DebugPrint((1, "(%p)\tSrb status was %lx\n",
572 Irp,
573 Context->Srb.SrbStatus));
574
575 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
576
577 //
578 // Lock was not successful - throw down the power IRP
579 // by itself and don't try to spin down the drive or unlock
580 // the queue.
581 //
582
583 Context->InUse = FALSE;
584 Context = NULL;
585
586 //
587 // Set the new power state
588 //
589
590 fdoExtension->DevicePowerState =
591 currentStack->Parameters.Power.State.DeviceState;
592
593 //
594 // Indicate to Po that we've been successfully powered down
595 // so it can do it's notification stuff.
596 //
597
598 IoCopyCurrentIrpStackLocationToNext(Irp);
599 IoSetCompletionRoutine(Irp,
600 ClasspStartNextPowerIrpCompletion,
601 NULL,
602 TRUE,
603 TRUE,
604 TRUE);
605
606 PoSetPowerState(DeviceObject,
607 currentStack->Parameters.Power.Type,
608 currentStack->Parameters.Power.State);
609
610 fdoExtension->PowerDownInProgress = FALSE;
611
612 PoCallDriver(commonExtension->LowerDeviceObject, Irp);
613
614 ClassReleaseRemoveLock(commonExtension->DeviceObject,
615 Irp);
616
617 return STATUS_MORE_PROCESSING_REQUIRED;
618
619 } else {
620 Context->QueueLocked = (UCHAR) Context->Options.LockQueue;
621 }
622
623 if (!TEST_FLAG(fdoExtension->PrivateFdoData->HackFlags,
624 FDO_HACK_NO_SYNC_CACHE)) {
625
626 //
627 // send SCSIOP_SYNCHRONIZE_CACHE
628 //
629
630 Context->Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
631 Context->Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
632
633 Context->Srb.TimeOutValue = fdoExtension->TimeOutValue;
634
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;
640
641 Context->Srb.SrbStatus = Context->Srb.ScsiStatus = 0;
642 Context->Srb.DataTransferLength = 0;
643
644 Context->Srb.CdbLength = 10;
645
646 cdb = (PCDB) Context->Srb.Cdb;
647
648 RtlZeroMemory(cdb, sizeof(CDB));
649 cdb->SYNCHRONIZE_CACHE10.OperationCode = SCSIOP_SYNCHRONIZE_CACHE;
650
651 IoSetCompletionRoutine(Irp,
652 ClasspPowerDownCompletion,
653 Context,
654 TRUE,
655 TRUE,
656 TRUE);
657
658 nextStack->Parameters.Scsi.Srb = &(Context->Srb);
659 nextStack->MajorFunction = IRP_MJ_SCSI;
660
661 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
662
663 DebugPrint((1, "(%p)\tIoCallDriver returned %lx\n", Irp, status));
664 break;
665
666 } else {
667
668 DebugPrint((1, "(%p)\tPower Down: not sending SYNCH_CACHE\n",
669 DeviceObject));
670 Context->PowerChangeState.PowerDown2++;
671 Context->Srb.SrbStatus = SRB_STATUS_SUCCESS;
672 // and fall through....
673 }
674 // no break in case the device doesn't like synch_cache commands
675
676 }
677
678 case PowerDownDeviceFlushed2: {
679
680 PCDB cdb;
681
682 DebugPrint((1, "(%p)\tPreviously send SCSIOP_SYNCHRONIZE_CACHE\n",
683 Irp));
684
685 //
686 // SCSIOP_SYNCHRONIZE_CACHE was sent
687 //
688
689 if(SRB_STATUS(Context->Srb.SrbStatus) != SRB_STATUS_SUCCESS) {
690
691 BOOLEAN retry;
692
693 DebugPrint((1, "(%p)\tError occured when issuing "
694 "SYNCHRONIZE_CACHE command to device. "
695 "Srb %p, Status %lx\n",
696 Irp,
697 &Context->Srb,
698 Context->Srb.SrbStatus));
699
700 ASSERT(!(TEST_FLAG(Context->Srb.SrbStatus,
701 SRB_STATUS_QUEUE_FROZEN)));
702 ASSERT(Context->Srb.Function == SRB_FUNCTION_EXECUTE_SCSI);
703
704 Context->RetryInterval = 0;
705 retry = ClassInterpretSenseInfo(
706 commonExtension->DeviceObject,
707 &Context->Srb,
708 IRP_MJ_SCSI,
709 IRP_MJ_POWER,
710 MAXIMUM_RETRIES - Context->RetryCount,
711 &status,
712 &Context->RetryInterval);
713
714 if((retry == TRUE) && (Context->RetryCount-- != 0)) {
715
716 DebugPrint((1, "(%p)\tRetrying failed request\n", Irp));
717
718 //
719 // decrement the state so we come back through here
720 // the next time.
721 //
722
723 Context->PowerChangeState.PowerDown2--;
724 RetryPowerRequest(commonExtension->DeviceObject,
725 Irp,
726 Context);
727 break;
728 }
729
730 DebugPrint((1, "(%p)\tSYNCHRONIZE_CACHE not retried\n", Irp));
731 Context->RetryCount = MAXIMUM_RETRIES;
732
733 } // end !SRB_STATUS_SUCCESS
734
735 //
736 // note: we are purposefully ignoring any errors. if the drive
737 // doesn't support a synch_cache, then we're up a creek
738 // anyways.
739 //
740
741 DebugPrint((1, "(%p)\tSending stop unit to device\n", Irp));
742
743 //
744 // Issue the start unit command to the device.
745 //
746
747 Context->Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
748 Context->Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
749
750 Context->Srb.TimeOutValue = START_UNIT_TIMEOUT;
751
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;
757
758 Context->Srb.SrbStatus = Context->Srb.ScsiStatus = 0;
759 Context->Srb.DataTransferLength = 0;
760
761 Context->Srb.CdbLength = 6;
762
763 cdb = (PCDB) Context->Srb.Cdb;
764 RtlZeroMemory(cdb, sizeof(CDB));
765
766 cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
767 cdb->START_STOP.Start = 0;
768 cdb->START_STOP.Immediate = 1;
769
770 IoSetCompletionRoutine(Irp,
771 ClasspPowerDownCompletion,
772 Context,
773 TRUE,
774 TRUE,
775 TRUE);
776
777 nextStack->Parameters.Scsi.Srb = &(Context->Srb);
778 nextStack->MajorFunction = IRP_MJ_SCSI;
779
780 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
781
782 DebugPrint((1, "(%p)\tIoCallDriver returned %lx\n", Irp, status));
783 break;
784
785 }
786
787 case PowerDownDeviceStopped2: {
788
789 BOOLEAN ignoreError = TRUE;
790
791 //
792 // stop was sent
793 //
794
795 if(SRB_STATUS(Context->Srb.SrbStatus) != SRB_STATUS_SUCCESS) {
796
797 BOOLEAN retry;
798
799 DebugPrint((1, "(%p)\tError occured when issueing STOP_UNIT "
800 "command to device. Srb %p, Status %lx\n",
801 Irp,
802 &Context->Srb,
803 Context->Srb.SrbStatus));
804
805 ASSERT(!(TEST_FLAG(Context->Srb.SrbStatus,
806 SRB_STATUS_QUEUE_FROZEN)));
807 ASSERT(Context->Srb.Function == SRB_FUNCTION_EXECUTE_SCSI);
808
809 Context->RetryInterval = 0;
810 retry = ClassInterpretSenseInfo(
811 commonExtension->DeviceObject,
812 &Context->Srb,
813 IRP_MJ_SCSI,
814 IRP_MJ_POWER,
815 MAXIMUM_RETRIES - Context->RetryCount,
816 &status,
817 &Context->RetryInterval);
818
819 if((retry == TRUE) && (Context->RetryCount-- != 0)) {
820
821 DebugPrint((1, "(%p)\tRetrying failed request\n", Irp));
822
823 //
824 // decrement the state so we come back through here
825 // the next time.
826 //
827
828 Context->PowerChangeState.PowerDown2--;
829 RetryPowerRequest(commonExtension->DeviceObject,
830 Irp,
831 Context);
832 break;
833 }
834
835 DebugPrint((1, "(%p)\tSTOP_UNIT not retried\n", Irp));
836 Context->RetryCount = MAXIMUM_RETRIES;
837
838 } // end !SRB_STATUS_SUCCESS
839
840
841 DebugPrint((1, "(%p)\tPreviously sent stop unit\n", Irp));
842
843 //
844 // some operations, such as a physical format in progress,
845 // should not be ignored and should fail the power operation.
846 //
847
848 if (!NT_SUCCESS(status)) {
849
850 PSENSE_DATA senseBuffer = Context->Srb.SenseInfoBuffer;
851
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)
857 ) {
858 ignoreError = FALSE;
859 Context->FinalStatus = STATUS_DEVICE_BUSY;
860 status = Context->FinalStatus;
861 }
862
863 }
864
865 if (NT_SUCCESS(status) || ignoreError) {
866
867 //
868 // Issue the actual power request to the lower driver.
869 //
870
871 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
872
873 IoCopyCurrentIrpStackLocationToNext(Irp);
874
875 IoSetCompletionRoutine(Irp,
876 ClasspPowerDownCompletion,
877 Context,
878 TRUE,
879 TRUE,
880 TRUE);
881
882 status = PoCallDriver(commonExtension->LowerDeviceObject, Irp);
883
884 DebugPrint((1, "(%p)\tPoCallDriver returned %lx\n", Irp, status));
885 break;
886 }
887
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
890 // during.
891
892 }
893
894 case PowerDownDeviceOff2: {
895
896 //
897 // SpinDown request completed ... whether it succeeded or not is
898 // another matter entirely.
899 //
900
901 DebugPrint((1, "(%p)\tPreviously sent power irp\n", Irp));
902
903 if (Context->QueueLocked) {
904
905 DebugPrint((1, "(%p)\tUnlocking queue\n", Irp));
906
907 Context->Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
908
909 Context->Srb.SrbStatus = Context->Srb.ScsiStatus = 0;
910 Context->Srb.DataTransferLength = 0;
911
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;
916
917 IoSetCompletionRoutine(Irp,
918 ClasspPowerDownCompletion,
919 Context,
920 TRUE,
921 TRUE,
922 TRUE);
923
924 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
925 DebugPrint((1, "(%p)\tIoCallDriver returned %lx\n",
926 Irp,
927 status));
928 break;
929 }
930
931 }
932
933 case PowerDownDeviceUnlocked2: {
934
935 //
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 ....
939 //
940
941 if (Context->QueueLocked == FALSE) {
942 DebugPrint((1, "(%p)\tFall through (queue not locked)\n", Irp));
943 } else {
944 DebugPrint((1, "(%p)\tPreviously unlocked queue\n", Irp));
945 ASSERT(NT_SUCCESS(Irp->IoStatus.Status));
946 ASSERT(Context->Srb.SrbStatus == SRB_STATUS_SUCCESS);
947 }
948
949 DebugPrint((1, "(%p)\tFreeing srb and completing\n", Irp));
950 Context->InUse = FALSE;
951 status = Context->FinalStatus; // allow failure to propogate
952 Context = NULL;
953
954 if(Irp->PendingReturned) {
955 IoMarkIrpPending(Irp);
956 }
957
958 Irp->IoStatus.Status = status;
959 Irp->IoStatus.Information = 0;
960
961 if (NT_SUCCESS(status)) {
962
963 //
964 // Set the new power state
965 //
966
967 fdoExtension->DevicePowerState =
968 currentStack->Parameters.Power.State.DeviceState;
969
970 }
971
972
973 DebugPrint((1, "(%p)\tStarting next power irp\n", Irp));
974
975 ClassReleaseRemoveLock(DeviceObject, Irp);
976 PoStartNextPowerIrp(Irp);
977 fdoExtension->PowerDownInProgress = FALSE;
978
979 return status;
980 }
981 }
982
983 return STATUS_MORE_PROCESSING_REQUIRED;
984 } // end ClasspPowerDownCompletion()
985
986 /*++////////////////////////////////////////////////////////////////////////////
987
988 ClasspPowerHandler()
989
990 Routine Description:
991
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
994 currently in.
995
996 ISSUE-2000/02/20-henrygab - by ignoring spin-up requests, we may be
997 allowing the drive
998
999 Arguments:
1000
1001 DeviceObject - the device object which is transitioning power states
1002 Irp - the power irp
1003 Options - a set of flags indicating what the device handles
1004
1005 Return Value:
1006
1007 --*/
1008 NTSTATUS
1009 NTAPI
1010 ClasspPowerHandler(
1011 IN PDEVICE_OBJECT DeviceObject,
1012 IN PIRP Irp,
1013 IN CLASS_POWER_OPTIONS Options // ISSUE-2000/02/20-henrygab - pass pointer, not whole struct
1014 )
1015 {
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;
1022
1023 if (!commonExtension->IsFdo) {
1024
1025 //
1026 // certain assumptions are made here,
1027 // particularly: having the fdoExtension
1028 //
1029
1030 DebugPrint((0, "ClasspPowerHandler: Called for PDO %p???\n",
1031 DeviceObject));
1032 ASSERT(!"PDO using ClasspPowerHandler");
1033 return STATUS_NOT_SUPPORTED;
1034 }
1035
1036 DebugPrint((1, "ClasspPowerHandler: Power irp %p to %s %p\n",
1037 Irp, (commonExtension->IsFdo ? "fdo" : "pdo"), DeviceObject));
1038
1039 switch(irpStack->MinorFunction) {
1040
1041 case IRP_MN_SET_POWER: {
1042 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData;
1043
1044 DebugPrint((1, "(%p)\tIRP_MN_SET_POWER\n", Irp));
1045
1046 DebugPrint((1, "(%p)\tSetting %s state to %d\n",
1047 Irp,
1048 (irpStack->Parameters.Power.Type == SystemPowerState ?
1049 "System" : "Device"),
1050 irpStack->Parameters.Power.State.SystemState));
1051
1052 switch (irpStack->Parameters.Power.ShutdownType){
1053
1054 case PowerActionSleep:
1055 case PowerActionHibernate:
1056 if (fdoData->HotplugInfo.MediaRemovable || fdoData->HotplugInfo.MediaHotplug){
1057 /*
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
1061 * we are suspended.
1062 */
1063 SET_FLAG(DeviceObject->Flags, DO_VERIFY_VOLUME);
1064 }
1065 break;
1066 }
1067
1068 break;
1069 }
1070
1071 default: {
1072
1073 DebugPrint((1, "(%p)\tIrp minor code = %#x\n",
1074 Irp, irpStack->MinorFunction));
1075 break;
1076 }
1077 }
1078
1079 if (irpStack->Parameters.Power.Type != DevicePowerState ||
1080 irpStack->MinorFunction != IRP_MN_SET_POWER) {
1081
1082 DebugPrint((1, "(%p)\tSending to lower device\n", Irp));
1083
1084 goto ClasspPowerHandlerCleanup;
1085
1086 }
1087
1088 nextIrpStack = IoGetNextIrpStackLocation(Irp);
1089
1090 //
1091 // already in exact same state, don't work to transition to it.
1092 //
1093
1094 if(irpStack->Parameters.Power.State.DeviceState ==
1095 fdoExtension->DevicePowerState) {
1096
1097 DebugPrint((1, "(%p)\tAlready in device state %x\n",
1098 Irp, fdoExtension->DevicePowerState));
1099 goto ClasspPowerHandlerCleanup;
1100
1101 }
1102
1103 //
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
1107 // to deal with.
1108 //
1109
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;
1117 }
1118
1119 //
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.
1123 //
1124
1125 if((irpStack->Parameters.Power.State.DeviceState == PowerDeviceD3) &&
1126 (irpStack->Parameters.Power.ShutdownType == PowerActionHibernate) &&
1127 (commonExtension->HibernationPathCount != 0)) {
1128
1129 DebugPrint((1, "(%p)\tdoing nothing for hibernation request for "
1130 "state %x???\n",
1131 Irp, fdoExtension->DevicePowerState));
1132 fdoExtension->DevicePowerState =
1133 irpStack->Parameters.Power.State.DeviceState;
1134 goto ClasspPowerHandlerCleanup;
1135 }
1136 //
1137 // or when not handling powering up and are powering up
1138 //
1139
1140 if ((!Options.HandleSpinUp) &&
1141 (irpStack->Parameters.Power.State.DeviceState == PowerDeviceD0)) {
1142
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;
1148
1149 }
1150
1151 //
1152 // or when not handling powering down and are powering down
1153 //
1154
1155 if ((!Options.HandleSpinDown) &&
1156 (irpStack->Parameters.Power.State.DeviceState != PowerDeviceD0)) {
1157
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;
1163
1164 }
1165
1166 context = &(fdoExtension->PowerContext);
1167
1168 #if DBG
1169 //
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.
1172 //
1173
1174 ASSERT(context->InUse == FALSE);
1175 #endif
1176
1177 RtlZeroMemory(context, sizeof(CLASS_POWER_CONTEXT));
1178 context->InUse = TRUE;
1179
1180 nextIrpStack->Parameters.Scsi.Srb = &(context->Srb);
1181 nextIrpStack->MajorFunction = IRP_MJ_SCSI;
1182
1183 context->FinalStatus = STATUS_SUCCESS;
1184
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;
1190
1191 context->Srb.SenseInfoBuffer =
1192 commonExtension->PartitionZeroExtension->SenseData;
1193 context->Srb.SenseInfoBufferLength = SENSE_BUFFER_SIZE;
1194 context->RetryCount = MAXIMUM_RETRIES;
1195
1196 context->Options = Options;
1197 context->DeviceObject = DeviceObject;
1198 context->Irp = Irp;
1199
1200 if(irpStack->Parameters.Power.State.DeviceState == PowerDeviceD0) {
1201
1202 ASSERT(Options.HandleSpinUp);
1203
1204 DebugPrint((2, "(%p)\tpower up - locking queue\n", Irp));
1205
1206 //
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.
1210 //
1211
1212 context->Options.PowerDown = FALSE;
1213 context->PowerChangeState.PowerUp = PowerUpDeviceInitial;
1214 context->CompletionRoutine = ClasspPowerUpCompletion;
1215
1216 } else {
1217
1218 ASSERT(Options.HandleSpinDown);
1219
1220 fdoExtension->PowerDownInProgress = TRUE;
1221
1222 DebugPrint((2, "(%p)\tPowering down - locking queue\n", Irp));
1223
1224 PoSetPowerState(DeviceObject,
1225 irpStack->Parameters.Power.Type,
1226 irpStack->Parameters.Power.State);
1227
1228 context->Options.PowerDown = TRUE;
1229 context->PowerChangeState.PowerDown2 = PowerDownDeviceInitial2;
1230 context->CompletionRoutine = ClasspPowerDownCompletion;
1231
1232 }
1233
1234 //
1235 // we are not dealing with port-allocated sense in these routines.
1236 //
1237
1238 ASSERT(!TEST_FLAG(context->Srb.SrbFlags, SRB_FLAGS_FREE_SENSE_BUFFER));
1239 ASSERT(!TEST_FLAG(context->Srb.SrbFlags, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE));
1240
1241 //
1242 // we are always returning STATUS_PENDING, so we need to always
1243 // set the irp as pending.
1244 //
1245
1246 IoMarkIrpPending(Irp);
1247
1248 if(Options.LockQueue) {
1249
1250 //
1251 // Send the lock irp down.
1252 //
1253
1254 IoSetCompletionRoutine(Irp,
1255 context->CompletionRoutine,
1256 context,
1257 TRUE,
1258 TRUE,
1259 TRUE);
1260
1261 IoCallDriver(lowerDevice, Irp);
1262
1263 } else {
1264
1265 //
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.
1269 //
1270
1271 context->CompletionRoutine(DeviceObject, Irp, context);
1272 }
1273
1274 return STATUS_PENDING;
1275
1276 ClasspPowerHandlerCleanup:
1277
1278 ClassReleaseRemoveLock(DeviceObject, Irp);
1279
1280 DebugPrint((1, "(%p)\tStarting next power irp\n", Irp));
1281 IoCopyCurrentIrpStackLocationToNext(Irp);
1282 IoSetCompletionRoutine(Irp,
1283 ClasspStartNextPowerIrpCompletion,
1284 NULL,
1285 TRUE,
1286 TRUE,
1287 TRUE);
1288 return PoCallDriver(lowerDevice, Irp);
1289 } // end ClasspPowerHandler()
1290
1291 /*++////////////////////////////////////////////////////////////////////////////
1292
1293 ClassMinimalPowerHandler()
1294
1295 Routine Description:
1296
1297 This routine is the minimum power handler for a storage driver. It does
1298 the least amount of work possible.
1299
1300 --*/
1301 NTSTATUS
1302 NTAPI
1303 ClassMinimalPowerHandler(
1304 IN PDEVICE_OBJECT DeviceObject,
1305 IN PIRP Irp
1306 )
1307 {
1308 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
1309 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
1310 NTSTATUS status;
1311
1312 ClassReleaseRemoveLock(DeviceObject, Irp);
1313 PoStartNextPowerIrp(Irp);
1314
1315 if(commonExtension->IsFdo) {
1316
1317 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
1318
1319 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension =
1320 DeviceObject->DeviceExtension;
1321
1322 //
1323 // Check if the system is going to hibernate or standby.
1324 //
1325 if (irpStack->MinorFunction == IRP_MN_SET_POWER){
1326 PVPB vpb;
1327
1328 switch (irpStack->Parameters.Power.ShutdownType){
1329
1330 case PowerActionSleep:
1331 case PowerActionHibernate:
1332 //
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.
1336 //
1337 vpb = ClassGetVpb(fdoExtension->DeviceObject);
1338 if (vpb && (vpb->Flags & VPB_MOUNTED)){
1339 SET_FLAG(fdoExtension->DeviceObject->Flags, DO_VERIFY_VOLUME);
1340 }
1341 break;
1342 }
1343 }
1344 }
1345
1346 IoCopyCurrentIrpStackLocationToNext(Irp);
1347 return PoCallDriver(commonExtension->LowerDeviceObject, Irp);
1348
1349 } else {
1350
1351 if (irpStack->MinorFunction != IRP_MN_SET_POWER &&
1352 irpStack->MinorFunction != IRP_MN_QUERY_POWER) {
1353
1354 NOTHING;
1355
1356 } else {
1357
1358 Irp->IoStatus.Status = STATUS_SUCCESS;
1359 Irp->IoStatus.Information = 0;
1360
1361 }
1362 status = Irp->IoStatus.Status;
1363
1364 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
1365 return status;
1366 }
1367 } // end ClassMinimalPowerHandler()
1368
1369 /*++////////////////////////////////////////////////////////////////////////////
1370
1371 ClassSpinDownPowerHandler()
1372
1373 Routine Description:
1374
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).
1379
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
1383
1384 Arguments:
1385
1386 DeviceObject - Supplies the functional device object
1387
1388 Irp - Supplies the request to be retried.
1389
1390 Return Value:
1391
1392 None
1393
1394 --*/
1395 NTSTATUS
1396 NTAPI
1397 ClassSpinDownPowerHandler(
1398 IN PDEVICE_OBJECT DeviceObject,
1399 IN PIRP Irp
1400 )
1401 {
1402 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
1403 CLASS_POWER_OPTIONS options;
1404
1405 fdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1406
1407 //
1408 // this will set all options to FALSE
1409 //
1410
1411 RtlZeroMemory(&options, sizeof(CLASS_POWER_OPTIONS));
1412
1413 //
1414 // check the flags to see what options we need to worry about
1415 //
1416
1417 if (!TEST_FLAG(fdoExtension->ScanForSpecialFlags,
1418 CLASS_SPECIAL_DISABLE_SPIN_DOWN)) {
1419 options.HandleSpinDown = TRUE;
1420 }
1421
1422 if (!TEST_FLAG(fdoExtension->ScanForSpecialFlags,
1423 CLASS_SPECIAL_DISABLE_SPIN_UP)) {
1424 options.HandleSpinUp = TRUE;
1425 }
1426
1427 if (!TEST_FLAG(fdoExtension->ScanForSpecialFlags,
1428 CLASS_SPECIAL_NO_QUEUE_LOCK)) {
1429 options.LockQueue = TRUE;
1430 }
1431
1432 DebugPrint((3, "ClasspPowerHandler: Devobj %p\n"
1433 "\t%shandling spin down\n"
1434 "\t%shandling spin up\n"
1435 "\t%slocking queue\n",
1436 DeviceObject,
1437 (options.HandleSpinDown ? "" : "not "),
1438 (options.HandleSpinUp ? "" : "not "),
1439 (options.LockQueue ? "" : "not ")
1440 ));
1441
1442 //
1443 // do all the dirty work
1444 //
1445
1446 return ClasspPowerHandler(DeviceObject, Irp, options);
1447 } // end ClassSpinDownPowerHandler()
1448
1449 /*++////////////////////////////////////////////////////////////////////////////
1450
1451 ClassStopUnitPowerHandler()
1452
1453 Routine Description:
1454
1455 This routine is an outdated call. To achieve equivalent functionality,
1456 the driver should set the following flags in ScanForSpecialFlags in the
1457 FdoExtension:
1458
1459 CLASS_SPECIAL_DISABLE_SPIN_UP
1460 CLASS_SPECIAL_NO_QUEUE_LOCK
1461
1462 --*/
1463 NTSTATUS
1464 NTAPI
1465 ClassStopUnitPowerHandler(
1466 IN PDEVICE_OBJECT DeviceObject,
1467 IN PIRP Irp
1468 )
1469 {
1470 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
1471
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",
1479 DeviceObject));
1480
1481 fdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1482
1483 SET_FLAG(fdoExtension->ScanForSpecialFlags,
1484 CLASS_SPECIAL_DISABLE_SPIN_UP);
1485 SET_FLAG(fdoExtension->ScanForSpecialFlags,
1486 CLASS_SPECIAL_NO_QUEUE_LOCK);
1487
1488 return ClassSpinDownPowerHandler(DeviceObject, Irp);
1489 } // end ClassStopUnitPowerHandler()
1490
1491 /*++////////////////////////////////////////////////////////////////////////////
1492
1493 RetryPowerRequest()
1494
1495 Routine Description:
1496
1497 This routine reinitalizes the necessary fields, and sends the request
1498 to the lower driver.
1499
1500 Arguments:
1501
1502 DeviceObject - Supplies the device object associated with this request.
1503
1504 Irp - Supplies the request to be retried.
1505
1506 Context - Supplies a pointer to the power up context for this request.
1507
1508 Return Value:
1509
1510 None
1511
1512 --*/
1513 VOID
1514 NTAPI
1515 RetryPowerRequest(
1516 PDEVICE_OBJECT DeviceObject,
1517 PIRP Irp,
1518 PCLASS_POWER_CONTEXT Context
1519 )
1520 {
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;
1526
1527 DebugPrint((1, "(%p)\tDelaying retry by queueing DPC\n", Irp));
1528
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));
1533
1534 //
1535 // reset the retry interval
1536 //
1537
1538 Context->RetryInterval = 0;
1539
1540 //
1541 // Reset byte count of transfer in SRB Extension.
1542 //
1543
1544 srb->DataTransferLength = 0;
1545
1546 //
1547 // Zero SRB statuses.
1548 //
1549
1550 srb->SrbStatus = srb->ScsiStatus = 0;
1551
1552 //
1553 // Set up major SCSI function.
1554 //
1555
1556 nextIrpStack->MajorFunction = IRP_MJ_SCSI;
1557
1558 //
1559 // Save SRB address in next stack for port driver.
1560 //
1561
1562 nextIrpStack->Parameters.Scsi.Srb = srb;
1563
1564 //
1565 // Set the completion routine up again.
1566 //
1567
1568 IoSetCompletionRoutine(Irp, Context->CompletionRoutine, Context,
1569 TRUE, TRUE, TRUE);
1570
1571
1572 if (Context->RetryInterval == 0) {
1573
1574 DebugPrint((2, "(%p)\tDelaying minimum time (.2 sec)\n", Irp));
1575 dueTime.QuadPart = (LONGLONG)1000000 * 2;
1576
1577 } else {
1578
1579 DebugPrint((2, "(%p)\tDelaying %x seconds\n",
1580 Irp, Context->RetryInterval));
1581 dueTime.QuadPart = (LONGLONG)1000000 * 10 * Context->RetryInterval;
1582
1583 }
1584
1585 ClassRetryRequest(DeviceObject, Irp, dueTime);
1586
1587 return;
1588
1589 } // end RetryRequest()
1590
1591 /*++////////////////////////////////////////////////////////////////////////////
1592
1593 ClasspStartNextPowerIrpCompletion()
1594
1595 Routine Description:
1596
1597 This routine guarantees that the next power irp (power up or down) is not
1598 sent until the previous one has fully completed.
1599
1600 --*/
1601 NTSTATUS
1602 NTAPI
1603 ClasspStartNextPowerIrpCompletion(
1604 IN PDEVICE_OBJECT DeviceObject,
1605 IN PIRP Irp,
1606 IN PVOID Context
1607 )
1608 {
1609 if(Irp->PendingReturned) {
1610 IoMarkIrpPending(Irp);
1611 }
1612
1613 PoStartNextPowerIrp(Irp);
1614 return STATUS_SUCCESS;
1615 } // end ClasspStartNextPowerIrpCompletion()