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