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