* Sync to trunk HEAD (r53298).
[reactos.git] / drivers / storage / classpnp / power.c
1 /*++
2
3 Copyright (C) Microsoft Corporation, 1991 - 1999
4
5 Module Name:
6
7 class.c
8
9 Abstract:
10
11 SCSI class driver routines
12
13 Environment:
14
15 kernel mode only
16
17 Notes:
18
19
20 Revision History:
21
22 --*/
23
24 #include "classp.h"
25
26 #define CLASS_TAG_POWER 'WLcS'
27
28 NTSTATUS
29 ClasspPowerHandler(
30 IN PDEVICE_OBJECT DeviceObject,
31 IN PIRP Irp,
32 IN CLASS_POWER_OPTIONS Options
33 );
34
35 NTSTATUS
36 ClasspPowerDownCompletion(
37 IN PDEVICE_OBJECT DeviceObject,
38 IN PIRP Irp,
39 IN PCLASS_POWER_CONTEXT Context
40 );
41
42 NTSTATUS
43 ClasspPowerUpCompletion(
44 IN PDEVICE_OBJECT DeviceObject,
45 IN PIRP Irp,
46 IN PCLASS_POWER_CONTEXT Context
47 );
48
49 VOID
50 RetryPowerRequest(
51 PDEVICE_OBJECT DeviceObject,
52 PIRP Irp,
53 PCLASS_POWER_CONTEXT Context
54 );
55
56 NTSTATUS
57 ClasspStartNextPowerIrpCompletion(
58 IN PDEVICE_OBJECT DeviceObject,
59 IN PIRP Irp,
60 IN PVOID Context
61 );
62
63 \f
64 /*++////////////////////////////////////////////////////////////////////////////
65
66 ClassDispatchPower()
67
68 Routine Description:
69
70 This routine acquires the removelock for the irp and then calls the
71 appropriate power callback.
72
73 Arguments:
74
75 DeviceObject -
76 Irp -
77
78 Return Value:
79
80 --*/
81 NTSTATUS
82 ClassDispatchPower(
83 IN PDEVICE_OBJECT DeviceObject,
84 IN PIRP Irp
85 )
86 {
87 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
88 ULONG isRemoved;
89 PCLASS_POWER_DEVICE powerRoutine = NULL;
90
91 //
92 // NOTE: This code may be called at PASSIVE or DISPATCH, depending
93 // upon the device object it is being called for.
94 // don't do anything that would break under either circumstance.
95 //
96
97 NTSTATUS status;
98
99 isRemoved = ClassAcquireRemoveLock(DeviceObject, Irp);
100
101 if(isRemoved) {
102 ClassReleaseRemoveLock(DeviceObject, Irp);
103 Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
104 PoStartNextPowerIrp(Irp);
105 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
106 return STATUS_DEVICE_DOES_NOT_EXIST;
107 }
108
109 return commonExtension->DevInfo->ClassPowerDevice(DeviceObject, Irp);
110 } // end ClassDispatchPower()
111 \f
112 /*++////////////////////////////////////////////////////////////////////////////
113
114 ClasspPowerUpCompletion()
115
116 Routine Description:
117
118 This routine is used for intermediate completion of a power up request.
119 PowerUp requires four requests to be sent to the lower driver in sequence.
120
121 * The queue is "power locked" to ensure that the class driver power-up
122 work can be done before request processing resumes.
123
124 * The power irp is sent down the stack for any filter drivers and the
125 port driver to return power and resume command processing for the
126 device. Since the queue is locked, no queued irps will be sent
127 immediately.
128
129 * A start unit command is issued to the device with appropriate flags
130 to override the "power locked" queue.
131
132 * The queue is "power unlocked" to start processing requests again.
133
134 This routine uses the function in the srb which just completed to determine
135 which state it is in.
136
137 Arguments:
138
139 DeviceObject - the device object being powered up
140
141 Irp - the IO_REQUEST_PACKET containing the power request
142
143 Srb - the SRB used to perform port/class operations.
144
145 Return Value:
146
147 STATUS_MORE_PROCESSING_REQUIRED or
148 STATUS_SUCCESS
149
150 --*/
151 NTSTATUS
152 ClasspPowerUpCompletion(
153 IN PDEVICE_OBJECT DeviceObject,
154 IN PIRP Irp,
155 IN PCLASS_POWER_CONTEXT Context
156 )
157 {
158 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
159 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
160
161 PIO_STACK_LOCATION currentStack = IoGetCurrentIrpStackLocation(Irp);
162 PIO_STACK_LOCATION nextStack = IoGetNextIrpStackLocation(Irp);
163
164
165 NTSTATUS status = STATUS_MORE_PROCESSING_REQUIRED;
166
167 DebugPrint((1, "ClasspPowerUpCompletion: Device Object %p, Irp %p, "
168 "Context %p\n",
169 DeviceObject, Irp, Context));
170
171 ASSERT(!TEST_FLAG(Context->Srb.SrbFlags, SRB_FLAGS_FREE_SENSE_BUFFER));
172 ASSERT(!TEST_FLAG(Context->Srb.SrbFlags, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE));
173 ASSERT(Context->Options.PowerDown == FALSE);
174 ASSERT(Context->Options.HandleSpinUp);
175
176 if(Irp->PendingReturned) {
177 IoMarkIrpPending(Irp);
178 }
179
180 Context->PowerChangeState.PowerUp++;
181
182 switch(Context->PowerChangeState.PowerUp) {
183
184 case PowerUpDeviceLocked: {
185
186 DebugPrint((1, "(%p)\tPreviously sent power lock\n", Irp));
187
188 //
189 // Issue the actual power request to the lower driver.
190 //
191
192 IoCopyCurrentIrpStackLocationToNext(Irp);
193
194 //
195 // If the lock wasn't successful then just bail out on the power
196 // request unless we can ignore failed locks
197 //
198
199 if((Context->Options.LockQueue == TRUE) &&
200 (!NT_SUCCESS(Irp->IoStatus.Status))) {
201
202 DebugPrint((1, "(%p)\tIrp status was %lx\n",
203 Irp, Irp->IoStatus.Status));
204 DebugPrint((1, "(%p)\tSrb status was %lx\n",
205 Irp, Context->Srb.SrbStatus));
206
207 //
208 // Lock was not successful - throw down the power IRP
209 // by itself and don't try to spin up the drive or unlock
210 // the queue.
211 //
212
213 Context->InUse = FALSE;
214 Context = NULL;
215
216 //
217 // Set the new power state
218 //
219
220 fdoExtension->DevicePowerState =
221 currentStack->Parameters.Power.State.DeviceState;
222
223 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
224
225 IoCopyCurrentIrpStackLocationToNext(Irp);
226
227 IoSetCompletionRoutine(Irp,
228 ClasspStartNextPowerIrpCompletion,
229 NULL,
230 TRUE,
231 TRUE,
232 TRUE);
233
234 //
235 // Indicate to Po that we've been successfully powered up so
236 // it can do it's notification stuff.
237 //
238
239 PoSetPowerState(DeviceObject,
240 currentStack->Parameters.Power.Type,
241 currentStack->Parameters.Power.State);
242
243 PoCallDriver(commonExtension->LowerDeviceObject, Irp);
244
245 ClassReleaseRemoveLock(commonExtension->DeviceObject,
246 Irp);
247
248 return STATUS_MORE_PROCESSING_REQUIRED;
249
250 } else {
251 Context->QueueLocked = (UCHAR) Context->Options.LockQueue;
252 }
253
254 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
255
256 Context->PowerChangeState.PowerUp = PowerUpDeviceLocked;
257
258 IoSetCompletionRoutine(Irp,
259 ClasspPowerUpCompletion,
260 Context,
261 TRUE,
262 TRUE,
263 TRUE);
264
265 status = PoCallDriver(commonExtension->LowerDeviceObject, Irp);
266
267 DebugPrint((2, "(%p)\tPoCallDriver returned %lx\n", Irp, status));
268 break;
269 }
270
271 case PowerUpDeviceOn: {
272
273 PCDB cdb;
274
275 if(NT_SUCCESS(Irp->IoStatus.Status)) {
276
277 DebugPrint((1, "(%p)\tSending start unit to device\n", Irp));
278
279 //
280 // Issue the start unit command to the device.
281 //
282
283 Context->Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
284 Context->Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
285
286 Context->Srb.SrbStatus = Context->Srb.ScsiStatus = 0;
287 Context->Srb.DataTransferLength = 0;
288
289 Context->Srb.TimeOutValue = START_UNIT_TIMEOUT;
290
291 Context->Srb.SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER |
292 SRB_FLAGS_DISABLE_AUTOSENSE |
293 SRB_FLAGS_DISABLE_SYNCH_TRANSFER |
294 SRB_FLAGS_NO_QUEUE_FREEZE;
295
296 if(Context->Options.LockQueue) {
297 SET_FLAG(Context->Srb.SrbFlags, SRB_FLAGS_BYPASS_LOCKED_QUEUE);
298 }
299
300 Context->Srb.CdbLength = 6;
301
302 cdb = (PCDB) (Context->Srb.Cdb);
303 RtlZeroMemory(cdb, sizeof(CDB));
304
305
306 cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
307 cdb->START_STOP.Start = 1;
308
309 Context->PowerChangeState.PowerUp = PowerUpDeviceOn;
310
311 IoSetCompletionRoutine(Irp,
312 ClasspPowerUpCompletion,
313 Context,
314 TRUE,
315 TRUE,
316 TRUE);
317
318 nextStack->Parameters.Scsi.Srb = &(Context->Srb);
319 nextStack->MajorFunction = IRP_MJ_SCSI;
320
321 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
322
323 DebugPrint((2, "(%p)\tIoCallDriver returned %lx\n", Irp, status));
324
325 } else {
326
327 //
328 // we're done.
329 //
330
331 Context->FinalStatus = Irp->IoStatus.Status;
332 goto ClasspPowerUpCompletionFailure;
333 }
334
335 break;
336 }
337
338 case PowerUpDeviceStarted: { // 3
339
340 //
341 // First deal with an error if one occurred.
342 //
343
344 if(SRB_STATUS(Context->Srb.SrbStatus) != SRB_STATUS_SUCCESS) {
345
346 BOOLEAN retry;
347
348 DebugPrint((1, "%p\tError occured when issuing START_UNIT "
349 "command to device. Srb %p, Status %x\n",
350 Irp,
351 &Context->Srb,
352 Context->Srb.SrbStatus));
353
354 ASSERT(!(TEST_FLAG(Context->Srb.SrbStatus,
355 SRB_STATUS_QUEUE_FROZEN)));
356 ASSERT(Context->Srb.Function == SRB_FUNCTION_EXECUTE_SCSI);
357
358 Context->RetryInterval = 0;
359
360 retry = ClassInterpretSenseInfo(
361 commonExtension->DeviceObject,
362 &Context->Srb,
363 IRP_MJ_SCSI,
364 IRP_MJ_POWER,
365 MAXIMUM_RETRIES - Context->RetryCount,
366 &status,
367 &Context->RetryInterval);
368
369 if((retry == TRUE) && (Context->RetryCount-- != 0)) {
370
371 DebugPrint((1, "(%p)\tRetrying failed request\n", Irp));
372
373 //
374 // Decrement the state so we come back through here the
375 // next time.
376 //
377
378 Context->PowerChangeState.PowerUp--;
379
380 RetryPowerRequest(commonExtension->DeviceObject,
381 Irp,
382 Context);
383
384 break;
385
386 }
387
388 // reset retries
389 Context->RetryCount = MAXIMUM_RETRIES;
390
391 }
392
393 ClasspPowerUpCompletionFailure:
394
395 DebugPrint((1, "(%p)\tPreviously spun device up\n", Irp));
396
397 if (Context->QueueLocked) {
398 DebugPrint((1, "(%p)\tUnlocking queue\n", Irp));
399
400 Context->Srb.Function = SRB_FUNCTION_UNLOCK_QUEUE;
401 Context->Srb.SrbFlags = SRB_FLAGS_BYPASS_LOCKED_QUEUE;
402 Context->Srb.SrbStatus = Context->Srb.ScsiStatus = 0;
403 Context->Srb.DataTransferLength = 0;
404
405 nextStack->Parameters.Scsi.Srb = &(Context->Srb);
406 nextStack->MajorFunction = IRP_MJ_SCSI;
407
408 Context->PowerChangeState.PowerUp = PowerUpDeviceStarted;
409
410 IoSetCompletionRoutine(Irp,
411 ClasspPowerUpCompletion,
412 Context,
413 TRUE,
414 TRUE,
415 TRUE);
416
417 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
418 DebugPrint((1, "(%p)\tIoCallDriver returned %lx\n",
419 Irp, status));
420 break;
421 }
422
423 // Fall-through to next case...
424
425 }
426
427 case PowerUpDeviceUnlocked: {
428
429 //
430 // This is the end of the dance. Free the srb and complete the
431 // request finally. We're ignoring possible intermediate
432 // error conditions ....
433 //
434
435 if (Context->QueueLocked) {
436 DebugPrint((1, "(%p)\tPreviously unlocked queue\n", Irp));
437 ASSERT(NT_SUCCESS(Irp->IoStatus.Status));
438 ASSERT(Context->Srb.SrbStatus == SRB_STATUS_SUCCESS);
439 } else {
440 DebugPrint((1, "(%p)\tFall-through (queue not locked)\n", Irp));
441 }
442
443 DebugPrint((1, "(%p)\tFreeing srb and completing\n", Irp));
444 Context->InUse = FALSE;
445
446 status = Context->FinalStatus;
447 Irp->IoStatus.Status = status;
448
449 Context = NULL;
450
451 //
452 // Set the new power state
453 //
454
455 if(NT_SUCCESS(status)) {
456 fdoExtension->DevicePowerState =
457 currentStack->Parameters.Power.State.DeviceState;
458 }
459
460 //
461 // Indicate to Po that we've been successfully powered up so
462 // it can do it's notification stuff.
463 //
464
465 PoSetPowerState(DeviceObject,
466 currentStack->Parameters.Power.Type,
467 currentStack->Parameters.Power.State);
468
469 DebugPrint((1, "(%p)\tStarting next power irp\n", Irp));
470 ClassReleaseRemoveLock(DeviceObject, Irp);
471 PoStartNextPowerIrp(Irp);
472
473 return status;
474 }
475 }
476
477 return STATUS_MORE_PROCESSING_REQUIRED;
478 } // end ClasspPowerUpCompletion()
479 \f
480 /*++////////////////////////////////////////////////////////////////////////////
481
482 ClasspPowerDownCompletion()
483
484 Routine Description:
485
486 This routine is used for intermediate completion of a power up request.
487 PowerUp requires four requests to be sent to the lower driver in sequence.
488
489 * The queue is "power locked" to ensure that the class driver power-up
490 work can be done before request processing resumes.
491
492 * The power irp is sent down the stack for any filter drivers and the
493 port driver to return power and resume command processing for the
494 device. Since the queue is locked, no queued irps will be sent
495 immediately.
496
497 * A start unit command is issued to the device with appropriate flags
498 to override the "power locked" queue.
499
500 * The queue is "power unlocked" to start processing requests again.
501
502 This routine uses the function in the srb which just completed to determine
503 which state it is in.
504
505 Arguments:
506
507 DeviceObject - the device object being powered up
508
509 Irp - the IO_REQUEST_PACKET containing the power request
510
511 Srb - the SRB used to perform port/class operations.
512
513 Return Value:
514
515 STATUS_MORE_PROCESSING_REQUIRED or
516 STATUS_SUCCESS
517
518 --*/
519 NTSTATUS
520 ClasspPowerDownCompletion(
521 IN PDEVICE_OBJECT DeviceObject,
522 IN PIRP Irp,
523 IN PCLASS_POWER_CONTEXT Context
524 )
525 {
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
975 return STATUS_MORE_PROCESSING_REQUIRED;
976 } // end ClasspPowerDownCompletion()
977 \f
978 /*++////////////////////////////////////////////////////////////////////////////
979
980 ClasspPowerHandler()
981
982 Routine Description:
983
984 This routine reduces the number of useless spinups and spindown requests
985 sent to a given device by ignoring transitions to power states we are
986 currently in.
987
988 ISSUE-2000/02/20-henrygab - by ignoring spin-up requests, we may be
989 allowing the drive
990
991 Arguments:
992
993 DeviceObject - the device object which is transitioning power states
994 Irp - the power irp
995 Options - a set of flags indicating what the device handles
996
997 Return Value:
998
999 --*/
1000 NTSTATUS
1001 ClasspPowerHandler(
1002 IN PDEVICE_OBJECT DeviceObject,
1003 IN PIRP Irp,
1004 IN CLASS_POWER_OPTIONS Options // ISSUE-2000/02/20-henrygab - pass pointer, not whole struct
1005 )
1006 {
1007 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
1008 PDEVICE_OBJECT lowerDevice = commonExtension->LowerDeviceObject;
1009 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
1010 PIO_STACK_LOCATION nextIrpStack;
1011 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
1012 PCLASS_POWER_CONTEXT context;
1013
1014 if (!commonExtension->IsFdo) {
1015
1016 //
1017 // certain assumptions are made here,
1018 // particularly: having the fdoExtension
1019 //
1020
1021 DebugPrint((0, "ClasspPowerHandler: Called for PDO %p???\n",
1022 DeviceObject));
1023 ASSERT(!"PDO using ClasspPowerHandler");
1024 return STATUS_NOT_SUPPORTED;
1025 }
1026
1027 DebugPrint((1, "ClasspPowerHandler: Power irp %p to %s %p\n",
1028 Irp, (commonExtension->IsFdo ? "fdo" : "pdo"), DeviceObject));
1029
1030 switch(irpStack->MinorFunction) {
1031
1032 case IRP_MN_SET_POWER: {
1033 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData;
1034
1035 DebugPrint((1, "(%p)\tIRP_MN_SET_POWER\n", Irp));
1036
1037 DebugPrint((1, "(%p)\tSetting %s state to %d\n",
1038 Irp,
1039 (irpStack->Parameters.Power.Type == SystemPowerState ?
1040 "System" : "Device"),
1041 irpStack->Parameters.Power.State.SystemState));
1042
1043 switch (irpStack->Parameters.Power.ShutdownType){
1044
1045 case PowerActionSleep:
1046 case PowerActionHibernate:
1047 if (fdoData->HotplugInfo.MediaRemovable || fdoData->HotplugInfo.MediaHotplug){
1048 /*
1049 * We are suspending and this drive is either hot-pluggable
1050 * or contains removeable media.
1051 * Set the media dirty bit, since the media may change while
1052 * we are suspended.
1053 */
1054 SET_FLAG(DeviceObject->Flags, DO_VERIFY_VOLUME);
1055 }
1056 break;
1057 }
1058
1059 break;
1060 }
1061
1062 default: {
1063
1064 DebugPrint((1, "(%p)\tIrp minor code = %#x\n",
1065 Irp, irpStack->MinorFunction));
1066 break;
1067 }
1068 }
1069
1070 if (irpStack->Parameters.Power.Type != DevicePowerState ||
1071 irpStack->MinorFunction != IRP_MN_SET_POWER) {
1072
1073 DebugPrint((1, "(%p)\tSending to lower device\n", Irp));
1074
1075 goto ClasspPowerHandlerCleanup;
1076
1077 }
1078
1079 nextIrpStack = IoGetNextIrpStackLocation(Irp);
1080
1081 //
1082 // already in exact same state, don't work to transition to it.
1083 //
1084
1085 if(irpStack->Parameters.Power.State.DeviceState ==
1086 fdoExtension->DevicePowerState) {
1087
1088 DebugPrint((1, "(%p)\tAlready in device state %x\n",
1089 Irp, fdoExtension->DevicePowerState));
1090 goto ClasspPowerHandlerCleanup;
1091
1092 }
1093
1094 //
1095 // or powering down from non-d0 state (device already stopped)
1096 // NOTE -- we're not sure whether this case can exist or not (the
1097 // power system may never send this sort of request) but it's trivial
1098 // to deal with.
1099 //
1100
1101 if ((irpStack->Parameters.Power.State.DeviceState != PowerDeviceD0) &&
1102 (fdoExtension->DevicePowerState != PowerDeviceD0)) {
1103 DebugPrint((1, "(%p)\tAlready powered down to %x???\n",
1104 Irp, fdoExtension->DevicePowerState));
1105 fdoExtension->DevicePowerState =
1106 irpStack->Parameters.Power.State.DeviceState;
1107 goto ClasspPowerHandlerCleanup;
1108 }
1109
1110 //
1111 // or going into a hibernation state when we're in the hibernation path.
1112 // If the device is spinning then we should leave it spinning - if it's not
1113 // then the dump driver will start it up for us.
1114 //
1115
1116 if((irpStack->Parameters.Power.State.DeviceState == PowerDeviceD3) &&
1117 (irpStack->Parameters.Power.ShutdownType == PowerActionHibernate) &&
1118 (commonExtension->HibernationPathCount != 0)) {
1119
1120 DebugPrint((1, "(%p)\tdoing nothing for hibernation request for "
1121 "state %x???\n",
1122 Irp, fdoExtension->DevicePowerState));
1123 fdoExtension->DevicePowerState =
1124 irpStack->Parameters.Power.State.DeviceState;
1125 goto ClasspPowerHandlerCleanup;
1126 }
1127 //
1128 // or when not handling powering up and are powering up
1129 //
1130
1131 if ((!Options.HandleSpinUp) &&
1132 (irpStack->Parameters.Power.State.DeviceState == PowerDeviceD0)) {
1133
1134 DebugPrint((2, "(%p)\tNot handling spinup to state %x\n",
1135 Irp, fdoExtension->DevicePowerState));
1136 fdoExtension->DevicePowerState =
1137 irpStack->Parameters.Power.State.DeviceState;
1138 goto ClasspPowerHandlerCleanup;
1139
1140 }
1141
1142 //
1143 // or when not handling powering down and are powering down
1144 //
1145
1146 if ((!Options.HandleSpinDown) &&
1147 (irpStack->Parameters.Power.State.DeviceState != PowerDeviceD0)) {
1148
1149 DebugPrint((2, "(%p)\tNot handling spindown to state %x\n",
1150 Irp, fdoExtension->DevicePowerState));
1151 fdoExtension->DevicePowerState =
1152 irpStack->Parameters.Power.State.DeviceState;
1153 goto ClasspPowerHandlerCleanup;
1154
1155 }
1156
1157 context = &(fdoExtension->PowerContext);
1158
1159 #if DBG
1160 //
1161 // Mark the context as in use. We should be synchronizing this but
1162 // since it's just for debugging purposes we don't worry too much.
1163 //
1164
1165 ASSERT(context->InUse == FALSE);
1166 #endif
1167
1168 RtlZeroMemory(context, sizeof(CLASS_POWER_CONTEXT));
1169 context->InUse = TRUE;
1170
1171 nextIrpStack->Parameters.Scsi.Srb = &(context->Srb);
1172 nextIrpStack->MajorFunction = IRP_MJ_SCSI;
1173
1174 context->FinalStatus = STATUS_SUCCESS;
1175
1176 context->Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
1177 context->Srb.OriginalRequest = Irp;
1178 context->Srb.SrbFlags |= SRB_FLAGS_BYPASS_LOCKED_QUEUE
1179 | SRB_FLAGS_NO_QUEUE_FREEZE;
1180 context->Srb.Function = SRB_FUNCTION_LOCK_QUEUE;
1181
1182 context->Srb.SenseInfoBuffer =
1183 commonExtension->PartitionZeroExtension->SenseData;
1184 context->Srb.SenseInfoBufferLength = SENSE_BUFFER_SIZE;
1185 context->RetryCount = MAXIMUM_RETRIES;
1186
1187 context->Options = Options;
1188 context->DeviceObject = DeviceObject;
1189 context->Irp = Irp;
1190
1191 if(irpStack->Parameters.Power.State.DeviceState == PowerDeviceD0) {
1192
1193 ASSERT(Options.HandleSpinUp);
1194
1195 DebugPrint((2, "(%p)\tpower up - locking queue\n", Irp));
1196
1197 //
1198 // We need to issue a queue lock request so that we
1199 // can spin the drive back up after the power is restored
1200 // but before any requests are processed.
1201 //
1202
1203 context->Options.PowerDown = FALSE;
1204 context->PowerChangeState.PowerUp = PowerUpDeviceInitial;
1205 context->CompletionRoutine = ClasspPowerUpCompletion;
1206
1207 } else {
1208
1209 ASSERT(Options.HandleSpinDown);
1210
1211 fdoExtension->PowerDownInProgress = TRUE;
1212
1213 DebugPrint((2, "(%p)\tPowering down - locking queue\n", Irp));
1214
1215 PoSetPowerState(DeviceObject,
1216 irpStack->Parameters.Power.Type,
1217 irpStack->Parameters.Power.State);
1218
1219 context->Options.PowerDown = TRUE;
1220 context->PowerChangeState.PowerDown2 = PowerDownDeviceInitial2;
1221 context->CompletionRoutine = ClasspPowerDownCompletion;
1222
1223 }
1224
1225 //
1226 // we are not dealing with port-allocated sense in these routines.
1227 //
1228
1229 ASSERT(!TEST_FLAG(context->Srb.SrbFlags, SRB_FLAGS_FREE_SENSE_BUFFER));
1230 ASSERT(!TEST_FLAG(context->Srb.SrbFlags, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE));
1231
1232 //
1233 // we are always returning STATUS_PENDING, so we need to always
1234 // set the irp as pending.
1235 //
1236
1237 IoMarkIrpPending(Irp);
1238
1239 if(Options.LockQueue) {
1240
1241 //
1242 // Send the lock irp down.
1243 //
1244
1245 IoSetCompletionRoutine(Irp,
1246 context->CompletionRoutine,
1247 context,
1248 TRUE,
1249 TRUE,
1250 TRUE);
1251
1252 IoCallDriver(lowerDevice, Irp);
1253
1254 } else {
1255
1256 //
1257 // Call the completion routine directly. It won't care what the
1258 // status of the "lock" was - it will just go and do the next
1259 // step of the operation.
1260 //
1261
1262 context->CompletionRoutine(DeviceObject, Irp, context);
1263 }
1264
1265 return STATUS_PENDING;
1266
1267 ClasspPowerHandlerCleanup:
1268
1269 ClassReleaseRemoveLock(DeviceObject, Irp);
1270
1271 DebugPrint((1, "(%p)\tStarting next power irp\n", Irp));
1272 IoCopyCurrentIrpStackLocationToNext(Irp);
1273 IoSetCompletionRoutine(Irp,
1274 ClasspStartNextPowerIrpCompletion,
1275 NULL,
1276 TRUE,
1277 TRUE,
1278 TRUE);
1279 return PoCallDriver(lowerDevice, Irp);
1280 } // end ClasspPowerHandler()
1281 \f
1282 /*++////////////////////////////////////////////////////////////////////////////
1283
1284 ClassMinimalPowerHandler()
1285
1286 Routine Description:
1287
1288 This routine is the minimum power handler for a storage driver. It does
1289 the least amount of work possible.
1290
1291 --*/
1292 NTSTATUS
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 \f
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 ClassSpinDownPowerHandler(
1387 IN PDEVICE_OBJECT DeviceObject,
1388 IN PIRP Irp
1389 )
1390 {
1391 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
1392 CLASS_POWER_OPTIONS options;
1393
1394 fdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1395
1396 //
1397 // this will set all options to FALSE
1398 //
1399
1400 RtlZeroMemory(&options, sizeof(CLASS_POWER_OPTIONS));
1401
1402 //
1403 // check the flags to see what options we need to worry about
1404 //
1405
1406 if (!TEST_FLAG(fdoExtension->ScanForSpecialFlags,
1407 CLASS_SPECIAL_DISABLE_SPIN_DOWN)) {
1408 options.HandleSpinDown = TRUE;
1409 }
1410
1411 if (!TEST_FLAG(fdoExtension->ScanForSpecialFlags,
1412 CLASS_SPECIAL_DISABLE_SPIN_UP)) {
1413 options.HandleSpinUp = TRUE;
1414 }
1415
1416 if (!TEST_FLAG(fdoExtension->ScanForSpecialFlags,
1417 CLASS_SPECIAL_NO_QUEUE_LOCK)) {
1418 options.LockQueue = TRUE;
1419 }
1420
1421 DebugPrint((3, "ClasspPowerHandler: Devobj %p\n"
1422 "\t%shandling spin down\n"
1423 "\t%shandling spin up\n"
1424 "\t%slocking queue\n",
1425 DeviceObject,
1426 (options.HandleSpinDown ? "" : "not "),
1427 (options.HandleSpinUp ? "" : "not "),
1428 (options.LockQueue ? "" : "not ")
1429 ));
1430
1431 //
1432 // do all the dirty work
1433 //
1434
1435 return ClasspPowerHandler(DeviceObject, Irp, options);
1436 } // end ClassSpinDownPowerHandler()
1437 \f
1438 /*++////////////////////////////////////////////////////////////////////////////
1439
1440 ClassStopUnitPowerHandler()
1441
1442 Routine Description:
1443
1444 This routine is an outdated call. To achieve equivalent functionality,
1445 the driver should set the following flags in ScanForSpecialFlags in the
1446 FdoExtension:
1447
1448 CLASS_SPECIAL_DISABLE_SPIN_UP
1449 CLASS_SPECIAL_NO_QUEUE_LOCK
1450
1451 --*/
1452 NTSTATUS
1453 ClassStopUnitPowerHandler(
1454 IN PDEVICE_OBJECT DeviceObject,
1455 IN PIRP Irp
1456 )
1457 {
1458 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
1459
1460 DebugPrint((0, "ClassStopUnitPowerHandler - Devobj %p using outdated call\n"
1461 "Drivers should set the following flags in ScanForSpecialFlags "
1462 " in the FDO extension:\n"
1463 "\tCLASS_SPECIAL_DISABLE_SPIN_UP\n"
1464 "\tCLASS_SPECIAL_NO_QUEUE_LOCK\n"
1465 "This will provide equivalent functionality if the power "
1466 "routine is then set to ClassSpinDownPowerHandler\n\n",
1467 DeviceObject));
1468
1469 fdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1470
1471 SET_FLAG(fdoExtension->ScanForSpecialFlags,
1472 CLASS_SPECIAL_DISABLE_SPIN_UP);
1473 SET_FLAG(fdoExtension->ScanForSpecialFlags,
1474 CLASS_SPECIAL_NO_QUEUE_LOCK);
1475
1476 return ClassSpinDownPowerHandler(DeviceObject, Irp);
1477 } // end ClassStopUnitPowerHandler()
1478 \f
1479 /*++////////////////////////////////////////////////////////////////////////////
1480
1481 RetryPowerRequest()
1482
1483 Routine Description:
1484
1485 This routine reinitalizes the necessary fields, and sends the request
1486 to the lower driver.
1487
1488 Arguments:
1489
1490 DeviceObject - Supplies the device object associated with this request.
1491
1492 Irp - Supplies the request to be retried.
1493
1494 Context - Supplies a pointer to the power up context for this request.
1495
1496 Return Value:
1497
1498 None
1499
1500 --*/
1501 VOID
1502 RetryPowerRequest(
1503 PDEVICE_OBJECT DeviceObject,
1504 PIRP Irp,
1505 PCLASS_POWER_CONTEXT Context
1506 )
1507 {
1508 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
1509 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
1510 PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
1511 PSCSI_REQUEST_BLOCK srb = &(Context->Srb);
1512 LARGE_INTEGER dueTime;
1513
1514 DebugPrint((1, "(%p)\tDelaying retry by queueing DPC\n", Irp));
1515
1516 ASSERT(Context->Irp == Irp);
1517 ASSERT(Context->DeviceObject == DeviceObject);
1518 ASSERT(!TEST_FLAG(Context->Srb.SrbFlags, SRB_FLAGS_FREE_SENSE_BUFFER));
1519 ASSERT(!TEST_FLAG(Context->Srb.SrbFlags, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE));
1520
1521 //
1522 // reset the retry interval
1523 //
1524
1525 Context->RetryInterval = 0;
1526
1527 //
1528 // Reset byte count of transfer in SRB Extension.
1529 //
1530
1531 srb->DataTransferLength = 0;
1532
1533 //
1534 // Zero SRB statuses.
1535 //
1536
1537 srb->SrbStatus = srb->ScsiStatus = 0;
1538
1539 //
1540 // Set up major SCSI function.
1541 //
1542
1543 nextIrpStack->MajorFunction = IRP_MJ_SCSI;
1544
1545 //
1546 // Save SRB address in next stack for port driver.
1547 //
1548
1549 nextIrpStack->Parameters.Scsi.Srb = srb;
1550
1551 //
1552 // Set the completion routine up again.
1553 //
1554
1555 IoSetCompletionRoutine(Irp, Context->CompletionRoutine, Context,
1556 TRUE, TRUE, TRUE);
1557
1558
1559 if (Context->RetryInterval == 0) {
1560
1561 DebugPrint((2, "(%p)\tDelaying minimum time (.2 sec)\n", Irp));
1562 dueTime.QuadPart = (LONGLONG)1000000 * 2;
1563
1564 } else {
1565
1566 DebugPrint((2, "(%p)\tDelaying %x seconds\n",
1567 Irp, Context->RetryInterval));
1568 dueTime.QuadPart = (LONGLONG)1000000 * 10 * Context->RetryInterval;
1569
1570 }
1571
1572 ClassRetryRequest(DeviceObject, Irp, dueTime);
1573
1574 return;
1575
1576 } // end RetryRequest()
1577 \f
1578 /*++////////////////////////////////////////////////////////////////////////////
1579
1580 ClasspStartNextPowerIrpCompletion()
1581
1582 Routine Description:
1583
1584 This routine guarantees that the next power irp (power up or down) is not
1585 sent until the previous one has fully completed.
1586
1587 --*/
1588 NTSTATUS
1589 ClasspStartNextPowerIrpCompletion(
1590 IN PDEVICE_OBJECT DeviceObject,
1591 IN PIRP Irp,
1592 IN PVOID Context
1593 )
1594 {
1595 if(Irp->PendingReturned) {
1596 IoMarkIrpPending(Irp);
1597 }
1598
1599 PoStartNextPowerIrp(Irp);
1600 return STATUS_SUCCESS;
1601 } // end ClasspStartNextPowerIrpCompletion()
1602