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