ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

power.c
Go to the documentation of this file.
00001 /*++
00002 
00003 Copyright (C) Microsoft Corporation, 1991 - 1999
00004 
00005 Module Name:
00006 
00007     class.c
00008 
00009 Abstract:
00010 
00011     SCSI class driver routines
00012 
00013 Environment:
00014 
00015     kernel mode only
00016 
00017 Notes:
00018 
00019 
00020 Revision History:
00021 
00022 --*/
00023 
00024 #include "classp.h"
00025 
00026 #define CLASS_TAG_POWER     'WLcS'
00027 
00028 NTSTATUS
00029 ClasspPowerHandler(
00030     IN PDEVICE_OBJECT DeviceObject,
00031     IN PIRP Irp,
00032     IN CLASS_POWER_OPTIONS Options
00033     );
00034 
00035 NTSTATUS
00036 ClasspPowerDownCompletion(
00037     IN PDEVICE_OBJECT DeviceObject,
00038     IN PIRP Irp,
00039     IN PCLASS_POWER_CONTEXT Context
00040     );
00041 
00042 NTSTATUS
00043 ClasspPowerUpCompletion(
00044     IN PDEVICE_OBJECT DeviceObject,
00045     IN PIRP Irp,
00046     IN PCLASS_POWER_CONTEXT Context
00047     );
00048 
00049 VOID
00050 RetryPowerRequest(
00051     PDEVICE_OBJECT DeviceObject,
00052     PIRP Irp,
00053     PCLASS_POWER_CONTEXT Context
00054     );
00055 
00056 NTSTATUS
00057 ClasspStartNextPowerIrpCompletion(
00058     IN PDEVICE_OBJECT DeviceObject,
00059     IN PIRP Irp,
00060     IN PVOID Context
00061     );
00062 
00063 
00064 /*++////////////////////////////////////////////////////////////////////////////
00065 
00066 ClassDispatchPower()
00067 
00068 Routine Description:
00069 
00070     This routine acquires the removelock for the irp and then calls the
00071     appropriate power callback.
00072 
00073 Arguments:
00074 
00075     DeviceObject - 
00076     Irp - 
00077 
00078 Return Value:
00079 
00080 --*/
00081 NTSTATUS
00082 ClassDispatchPower(
00083     IN PDEVICE_OBJECT DeviceObject,
00084     IN PIRP Irp
00085     )
00086 {
00087     PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
00088     ULONG isRemoved;
00089     PCLASS_POWER_DEVICE powerRoutine = NULL;
00090 
00091     //
00092     // NOTE: This code may be called at PASSIVE or DISPATCH, depending
00093     //       upon the device object it is being called for.
00094     //       don't do anything that would break under either circumstance.
00095     //
00096 
00097     NTSTATUS status;
00098 
00099     isRemoved = ClassAcquireRemoveLock(DeviceObject, Irp);
00100 
00101     if(isRemoved) {
00102         ClassReleaseRemoveLock(DeviceObject, Irp);
00103         Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
00104         PoStartNextPowerIrp(Irp);
00105         ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
00106         return STATUS_DEVICE_DOES_NOT_EXIST;
00107     }
00108 
00109     return commonExtension->DevInfo->ClassPowerDevice(DeviceObject, Irp);
00110 } // end ClassDispatchPower()
00111 
00112 /*++////////////////////////////////////////////////////////////////////////////
00113 
00114 ClasspPowerUpCompletion()
00115 
00116 Routine Description:
00117 
00118     This routine is used for intermediate completion of a power up request.
00119     PowerUp requires four requests to be sent to the lower driver in sequence.
00120 
00121         * The queue is "power locked" to ensure that the class driver power-up
00122           work can be done before request processing resumes.
00123 
00124         * The power irp is sent down the stack for any filter drivers and the
00125           port driver to return power and resume command processing for the
00126           device.  Since the queue is locked, no queued irps will be sent
00127           immediately.
00128 
00129         * A start unit command is issued to the device with appropriate flags
00130           to override the "power locked" queue.
00131 
00132         * The queue is "power unlocked" to start processing requests again.
00133 
00134     This routine uses the function in the srb which just completed to determine
00135     which state it is in.
00136 
00137 Arguments:
00138 
00139     DeviceObject - the device object being powered up
00140 
00141     Irp - the IO_REQUEST_PACKET containing the power request
00142 
00143     Srb - the SRB used to perform port/class operations.
00144 
00145 Return Value:
00146 
00147     STATUS_MORE_PROCESSING_REQUIRED or
00148     STATUS_SUCCESS
00149     
00150 --*/
00151 NTSTATUS
00152 ClasspPowerUpCompletion(
00153     IN PDEVICE_OBJECT DeviceObject,
00154     IN PIRP Irp,
00155     IN PCLASS_POWER_CONTEXT Context
00156     )
00157 {
00158     PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
00159     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
00160 
00161     PIO_STACK_LOCATION currentStack = IoGetCurrentIrpStackLocation(Irp);
00162     PIO_STACK_LOCATION nextStack = IoGetNextIrpStackLocation(Irp);
00163 
00164 
00165     NTSTATUS status = STATUS_MORE_PROCESSING_REQUIRED;
00166 
00167     DebugPrint((1, "ClasspPowerUpCompletion: Device Object %p, Irp %p, "
00168                    "Context %p\n",
00169                 DeviceObject, Irp, Context));
00170 
00171     ASSERT(!TEST_FLAG(Context->Srb.SrbFlags, SRB_FLAGS_FREE_SENSE_BUFFER));
00172     ASSERT(!TEST_FLAG(Context->Srb.SrbFlags, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE));
00173     ASSERT(Context->Options.PowerDown == FALSE);
00174     ASSERT(Context->Options.HandleSpinUp);
00175 
00176     if(Irp->PendingReturned) {
00177         IoMarkIrpPending(Irp);
00178     }
00179 
00180     Context->PowerChangeState.PowerUp++;
00181 
00182     switch(Context->PowerChangeState.PowerUp) {
00183 
00184         case PowerUpDeviceLocked: {
00185 
00186             DebugPrint((1, "(%p)\tPreviously sent power lock\n", Irp));
00187 
00188             //
00189             // Issue the actual power request to the lower driver.
00190             //
00191 
00192             IoCopyCurrentIrpStackLocationToNext(Irp);
00193 
00194             //
00195             // If the lock wasn't successful then just bail out on the power
00196             // request unless we can ignore failed locks
00197             //
00198 
00199             if((Context->Options.LockQueue == TRUE) &&
00200                (!NT_SUCCESS(Irp->IoStatus.Status))) {
00201 
00202                 DebugPrint((1, "(%p)\tIrp status was %lx\n",
00203                             Irp, Irp->IoStatus.Status));
00204                 DebugPrint((1, "(%p)\tSrb status was %lx\n",
00205                             Irp, Context->Srb.SrbStatus));
00206 
00207                 //
00208                 // Lock was not successful - throw down the power IRP
00209                 // by itself and don't try to spin up the drive or unlock
00210                 // the queue.
00211                 //
00212 
00213                 Context->InUse = FALSE;
00214                 Context = NULL;
00215 
00216                 //
00217                 // Set the new power state
00218                 //
00219 
00220                 fdoExtension->DevicePowerState =
00221                     currentStack->Parameters.Power.State.DeviceState;
00222 
00223                 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
00224 
00225                 IoCopyCurrentIrpStackLocationToNext(Irp);
00226 
00227                 IoSetCompletionRoutine(Irp,
00228                                        ClasspStartNextPowerIrpCompletion,
00229                                        NULL,
00230                                        TRUE,
00231                                        TRUE,
00232                                        TRUE);
00233 
00234                 //
00235                 // Indicate to Po that we've been successfully powered up so
00236                 // it can do it's notification stuff.
00237                 //
00238 
00239                 PoSetPowerState(DeviceObject,
00240                                 currentStack->Parameters.Power.Type,
00241                                 currentStack->Parameters.Power.State);
00242 
00243                 PoCallDriver(commonExtension->LowerDeviceObject, Irp);
00244 
00245                 ClassReleaseRemoveLock(commonExtension->DeviceObject,
00246                                        Irp);
00247 
00248                 return STATUS_MORE_PROCESSING_REQUIRED;
00249 
00250             } else {
00251                 Context->QueueLocked = (UCHAR) Context->Options.LockQueue;
00252             }
00253 
00254             Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
00255 
00256             Context->PowerChangeState.PowerUp = PowerUpDeviceLocked;
00257 
00258             IoSetCompletionRoutine(Irp,
00259                                    ClasspPowerUpCompletion,
00260                                    Context,
00261                                    TRUE,
00262                                    TRUE,
00263                                    TRUE);
00264 
00265             status = PoCallDriver(commonExtension->LowerDeviceObject, Irp);
00266 
00267             DebugPrint((2, "(%p)\tPoCallDriver returned %lx\n", Irp, status));
00268             break;
00269         }
00270 
00271         case PowerUpDeviceOn: {
00272 
00273             PCDB cdb;
00274 
00275             if(NT_SUCCESS(Irp->IoStatus.Status)) {
00276 
00277                 DebugPrint((1, "(%p)\tSending start unit to device\n", Irp));
00278 
00279                 //
00280                 // Issue the start unit command to the device.
00281                 //
00282 
00283                 Context->Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
00284                 Context->Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
00285 
00286                 Context->Srb.SrbStatus = Context->Srb.ScsiStatus = 0;
00287                 Context->Srb.DataTransferLength = 0;
00288 
00289                 Context->Srb.TimeOutValue = START_UNIT_TIMEOUT;
00290 
00291                 Context->Srb.SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER |
00292                                         SRB_FLAGS_DISABLE_AUTOSENSE |
00293                                         SRB_FLAGS_DISABLE_SYNCH_TRANSFER |
00294                                         SRB_FLAGS_NO_QUEUE_FREEZE;
00295 
00296                 if(Context->Options.LockQueue) {
00297                     SET_FLAG(Context->Srb.SrbFlags, SRB_FLAGS_BYPASS_LOCKED_QUEUE);
00298                 }
00299 
00300                 Context->Srb.CdbLength = 6;
00301 
00302                 cdb = (PCDB) (Context->Srb.Cdb);
00303                 RtlZeroMemory(cdb, sizeof(CDB));
00304 
00305 
00306                 cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
00307                 cdb->START_STOP.Start = 1;
00308 
00309                 Context->PowerChangeState.PowerUp = PowerUpDeviceOn;
00310 
00311                 IoSetCompletionRoutine(Irp,
00312                                        ClasspPowerUpCompletion,
00313                                        Context,
00314                                        TRUE,
00315                                        TRUE,
00316                                        TRUE);
00317 
00318                 nextStack->Parameters.Scsi.Srb = &(Context->Srb);
00319                 nextStack->MajorFunction = IRP_MJ_SCSI;
00320 
00321                 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
00322 
00323                 DebugPrint((2, "(%p)\tIoCallDriver returned %lx\n", Irp, status));
00324 
00325             } else {
00326 
00327                 //
00328                 // we're done.
00329                 //
00330 
00331                 Context->FinalStatus = Irp->IoStatus.Status;
00332                 goto ClasspPowerUpCompletionFailure;
00333             }
00334 
00335             break;
00336         }
00337 
00338         case PowerUpDeviceStarted: { // 3
00339 
00340             //
00341             // First deal with an error if one occurred.
00342             //
00343 
00344             if(SRB_STATUS(Context->Srb.SrbStatus) != SRB_STATUS_SUCCESS) {
00345 
00346                 BOOLEAN retry;
00347 
00348                 DebugPrint((1, "%p\tError occured when issuing START_UNIT "
00349                             "command to device. Srb %p, Status %x\n",
00350                             Irp,
00351                             &Context->Srb,
00352                             Context->Srb.SrbStatus));
00353 
00354                 ASSERT(!(TEST_FLAG(Context->Srb.SrbStatus,
00355                                    SRB_STATUS_QUEUE_FROZEN)));
00356                 ASSERT(Context->Srb.Function == SRB_FUNCTION_EXECUTE_SCSI);
00357 
00358                 Context->RetryInterval = 0;
00359 
00360                 retry = ClassInterpretSenseInfo(
00361                             commonExtension->DeviceObject,
00362                             &Context->Srb,
00363                             IRP_MJ_SCSI,
00364                             IRP_MJ_POWER,
00365                             MAXIMUM_RETRIES - Context->RetryCount,
00366                             &status,
00367                             &Context->RetryInterval);
00368 
00369                 if((retry == TRUE) && (Context->RetryCount-- != 0)) {
00370 
00371                     DebugPrint((1, "(%p)\tRetrying failed request\n", Irp));
00372 
00373                     //
00374                     // Decrement the state so we come back through here the
00375                     // next time.
00376                     //
00377 
00378                     Context->PowerChangeState.PowerUp--;
00379 
00380                     RetryPowerRequest(commonExtension->DeviceObject,
00381                                       Irp,
00382                                       Context);
00383 
00384                     break;
00385 
00386                 }
00387                 
00388                 // reset retries
00389                 Context->RetryCount = MAXIMUM_RETRIES;
00390 
00391             }
00392 
00393 ClasspPowerUpCompletionFailure:
00394 
00395             DebugPrint((1, "(%p)\tPreviously spun device up\n", Irp));
00396 
00397             if (Context->QueueLocked) {
00398                 DebugPrint((1, "(%p)\tUnlocking queue\n", Irp));
00399 
00400                 Context->Srb.Function = SRB_FUNCTION_UNLOCK_QUEUE;
00401                 Context->Srb.SrbFlags = SRB_FLAGS_BYPASS_LOCKED_QUEUE;
00402                 Context->Srb.SrbStatus = Context->Srb.ScsiStatus = 0;
00403                 Context->Srb.DataTransferLength = 0;
00404                 
00405                 nextStack->Parameters.Scsi.Srb = &(Context->Srb);
00406                 nextStack->MajorFunction = IRP_MJ_SCSI;
00407 
00408                 Context->PowerChangeState.PowerUp = PowerUpDeviceStarted;
00409 
00410                 IoSetCompletionRoutine(Irp,
00411                                        ClasspPowerUpCompletion,
00412                                        Context,
00413                                        TRUE,
00414                                        TRUE,
00415                                        TRUE);
00416 
00417                 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
00418                 DebugPrint((1, "(%p)\tIoCallDriver returned %lx\n",
00419                             Irp, status));
00420                 break;
00421             }
00422 
00423             // Fall-through to next case...
00424 
00425         }
00426 
00427         case PowerUpDeviceUnlocked: {
00428 
00429             //
00430             // This is the end of the dance.  Free the srb and complete the
00431             // request finally.  We're ignoring possible intermediate
00432             // error conditions ....
00433             //
00434 
00435             if (Context->QueueLocked) {
00436                 DebugPrint((1, "(%p)\tPreviously unlocked queue\n", Irp));
00437                 ASSERT(NT_SUCCESS(Irp->IoStatus.Status));
00438                 ASSERT(Context->Srb.SrbStatus == SRB_STATUS_SUCCESS);
00439             } else {
00440                 DebugPrint((1, "(%p)\tFall-through (queue not locked)\n", Irp));
00441             }
00442 
00443             DebugPrint((1, "(%p)\tFreeing srb and completing\n", Irp));
00444             Context->InUse = FALSE;
00445 
00446             status = Context->FinalStatus;
00447             Irp->IoStatus.Status = status;
00448 
00449             Context = NULL;
00450 
00451             //
00452             // Set the new power state
00453             //
00454 
00455             if(NT_SUCCESS(status)) {
00456                 fdoExtension->DevicePowerState =
00457                     currentStack->Parameters.Power.State.DeviceState;
00458             }
00459 
00460             //
00461             // Indicate to Po that we've been successfully powered up so
00462             // it can do it's notification stuff.
00463             //
00464             
00465             PoSetPowerState(DeviceObject,
00466                             currentStack->Parameters.Power.Type,
00467                             currentStack->Parameters.Power.State);
00468 
00469             DebugPrint((1, "(%p)\tStarting next power irp\n", Irp));
00470             ClassReleaseRemoveLock(DeviceObject, Irp);
00471             PoStartNextPowerIrp(Irp);
00472 
00473             return status;
00474         }
00475     }
00476 
00477     return STATUS_MORE_PROCESSING_REQUIRED;
00478 } // end ClasspPowerUpCompletion()
00479 
00480 /*++////////////////////////////////////////////////////////////////////////////
00481 
00482 ClasspPowerDownCompletion()
00483 
00484 Routine Description:
00485 
00486     This routine is used for intermediate completion of a power up request.
00487     PowerUp requires four requests to be sent to the lower driver in sequence.
00488 
00489         * The queue is "power locked" to ensure that the class driver power-up
00490           work can be done before request processing resumes.
00491 
00492         * The power irp is sent down the stack for any filter drivers and the
00493           port driver to return power and resume command processing for the
00494           device.  Since the queue is locked, no queued irps will be sent
00495           immediately.
00496 
00497         * A start unit command is issued to the device with appropriate flags
00498           to override the "power locked" queue.
00499 
00500         * The queue is "power unlocked" to start processing requests again.
00501 
00502     This routine uses the function in the srb which just completed to determine
00503     which state it is in.
00504 
00505 Arguments:
00506 
00507     DeviceObject - the device object being powered up
00508 
00509     Irp - the IO_REQUEST_PACKET containing the power request
00510 
00511     Srb - the SRB used to perform port/class operations.
00512 
00513 Return Value:
00514 
00515     STATUS_MORE_PROCESSING_REQUIRED or
00516     STATUS_SUCCESS
00517 
00518 --*/
00519 NTSTATUS
00520 ClasspPowerDownCompletion(
00521     IN PDEVICE_OBJECT DeviceObject,
00522     IN PIRP Irp,
00523     IN PCLASS_POWER_CONTEXT Context
00524     )
00525 {
00526     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
00527     PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
00528 
00529     PIO_STACK_LOCATION currentStack = IoGetCurrentIrpStackLocation(Irp);
00530     PIO_STACK_LOCATION nextStack = IoGetNextIrpStackLocation(Irp);
00531 
00532     NTSTATUS status = STATUS_MORE_PROCESSING_REQUIRED;
00533 
00534     DebugPrint((1, "ClasspPowerDownCompletion: Device Object %p, "
00535                    "Irp %p, Context %p\n",
00536                 DeviceObject, Irp, Context));
00537 
00538     ASSERT(!TEST_FLAG(Context->Srb.SrbFlags, SRB_FLAGS_FREE_SENSE_BUFFER));
00539     ASSERT(!TEST_FLAG(Context->Srb.SrbFlags, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE));
00540     ASSERT(Context->Options.PowerDown == TRUE);
00541     ASSERT(Context->Options.HandleSpinDown);
00542 
00543     if(Irp->PendingReturned) {
00544         IoMarkIrpPending(Irp);
00545     }
00546 
00547     Context->PowerChangeState.PowerDown2++;
00548 
00549     switch(Context->PowerChangeState.PowerDown2) {
00550 
00551         case PowerDownDeviceLocked2: {
00552 
00553             PCDB cdb;
00554 
00555             DebugPrint((1, "(%p)\tPreviously sent power lock\n", Irp));
00556 
00557             if((Context->Options.LockQueue == TRUE) &&
00558                (!NT_SUCCESS(Irp->IoStatus.Status))) {
00559 
00560                 DebugPrint((1, "(%p)\tIrp status was %lx\n",
00561                             Irp,
00562                             Irp->IoStatus.Status));
00563                 DebugPrint((1, "(%p)\tSrb status was %lx\n",
00564                             Irp,
00565                             Context->Srb.SrbStatus));
00566 
00567                 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
00568 
00569                 //
00570                 // Lock was not successful - throw down the power IRP
00571                 // by itself and don't try to spin down the drive or unlock
00572                 // the queue.
00573                 //
00574 
00575                 Context->InUse = FALSE;
00576                 Context = NULL;
00577 
00578                 //
00579                 // Set the new power state
00580                 //
00581 
00582                 fdoExtension->DevicePowerState =
00583                     currentStack->Parameters.Power.State.DeviceState;
00584 
00585                 //
00586                 // Indicate to Po that we've been successfully powered down
00587                 // so it can do it's notification stuff.
00588                 //
00589 
00590                 IoCopyCurrentIrpStackLocationToNext(Irp);
00591                 IoSetCompletionRoutine(Irp,
00592                                        ClasspStartNextPowerIrpCompletion,
00593                                        NULL,
00594                                        TRUE,
00595                                        TRUE,
00596                                        TRUE);
00597 
00598                 PoSetPowerState(DeviceObject,
00599                                 currentStack->Parameters.Power.Type,
00600                                 currentStack->Parameters.Power.State);
00601 
00602                 fdoExtension->PowerDownInProgress = FALSE;
00603 
00604                 PoCallDriver(commonExtension->LowerDeviceObject, Irp);
00605 
00606                 ClassReleaseRemoveLock(commonExtension->DeviceObject,
00607                                        Irp);
00608 
00609                 return STATUS_MORE_PROCESSING_REQUIRED;
00610 
00611             } else {
00612                 Context->QueueLocked = (UCHAR) Context->Options.LockQueue;
00613             }
00614 
00615             if (!TEST_FLAG(fdoExtension->PrivateFdoData->HackFlags,
00616                            FDO_HACK_NO_SYNC_CACHE)) {
00617 
00618                 //
00619                 // send SCSIOP_SYNCHRONIZE_CACHE
00620                 //
00621     
00622                 Context->Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
00623                 Context->Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
00624     
00625                 Context->Srb.TimeOutValue = fdoExtension->TimeOutValue;
00626     
00627                 Context->Srb.SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER |
00628                                         SRB_FLAGS_DISABLE_AUTOSENSE |
00629                                         SRB_FLAGS_DISABLE_SYNCH_TRANSFER |
00630                                         SRB_FLAGS_NO_QUEUE_FREEZE |
00631                                         SRB_FLAGS_BYPASS_LOCKED_QUEUE;
00632     
00633                 Context->Srb.SrbStatus = Context->Srb.ScsiStatus = 0;
00634                 Context->Srb.DataTransferLength = 0;
00635     
00636                 Context->Srb.CdbLength = 10;
00637     
00638                 cdb = (PCDB) Context->Srb.Cdb;
00639                 
00640                 RtlZeroMemory(cdb, sizeof(CDB));
00641                 cdb->SYNCHRONIZE_CACHE10.OperationCode = SCSIOP_SYNCHRONIZE_CACHE;
00642     
00643                 IoSetCompletionRoutine(Irp,
00644                                        ClasspPowerDownCompletion,
00645                                        Context,
00646                                        TRUE,
00647                                        TRUE,
00648                                        TRUE);
00649     
00650                 nextStack->Parameters.Scsi.Srb = &(Context->Srb);
00651                 nextStack->MajorFunction = IRP_MJ_SCSI;
00652     
00653                 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
00654     
00655                 DebugPrint((1, "(%p)\tIoCallDriver returned %lx\n", Irp, status));
00656                 break;
00657             
00658             } else {
00659                
00660                 DebugPrint((1, "(%p)\tPower Down: not sending SYNCH_CACHE\n",
00661                             DeviceObject));
00662                 Context->PowerChangeState.PowerDown2++;
00663                 Context->Srb.SrbStatus = SRB_STATUS_SUCCESS;
00664                 // and fall through....
00665             }
00666             // no break in case the device doesn't like synch_cache commands
00667 
00668         }
00669          
00670         case PowerDownDeviceFlushed2: {
00671 
00672             PCDB cdb;
00673 
00674             DebugPrint((1, "(%p)\tPreviously send SCSIOP_SYNCHRONIZE_CACHE\n",
00675                         Irp));
00676 
00677             //
00678             // SCSIOP_SYNCHRONIZE_CACHE was sent
00679             //
00680 
00681             if(SRB_STATUS(Context->Srb.SrbStatus) != SRB_STATUS_SUCCESS) {
00682 
00683                 BOOLEAN retry;
00684 
00685                 DebugPrint((1, "(%p)\tError occured when issuing "
00686                             "SYNCHRONIZE_CACHE command to device. "
00687                             "Srb %p, Status %lx\n",
00688                             Irp,
00689                             &Context->Srb,
00690                             Context->Srb.SrbStatus));
00691 
00692                 ASSERT(!(TEST_FLAG(Context->Srb.SrbStatus,
00693                                    SRB_STATUS_QUEUE_FROZEN)));
00694                 ASSERT(Context->Srb.Function == SRB_FUNCTION_EXECUTE_SCSI);
00695 
00696                 Context->RetryInterval = 0;
00697                 retry = ClassInterpretSenseInfo(
00698                             commonExtension->DeviceObject,
00699                             &Context->Srb,
00700                             IRP_MJ_SCSI,
00701                             IRP_MJ_POWER,
00702                             MAXIMUM_RETRIES - Context->RetryCount,
00703                             &status,
00704                             &Context->RetryInterval);
00705 
00706                 if((retry == TRUE) && (Context->RetryCount-- != 0)) {
00707 
00708                         DebugPrint((1, "(%p)\tRetrying failed request\n", Irp));
00709 
00710                         //
00711                         // decrement the state so we come back through here
00712                         // the next time.
00713                         //
00714 
00715                         Context->PowerChangeState.PowerDown2--;
00716                         RetryPowerRequest(commonExtension->DeviceObject,
00717                                           Irp,
00718                                           Context);
00719                         break;
00720                 }
00721 
00722                 DebugPrint((1, "(%p)\tSYNCHRONIZE_CACHE not retried\n", Irp));
00723                 Context->RetryCount = MAXIMUM_RETRIES;
00724 
00725             } // end !SRB_STATUS_SUCCESS
00726 
00727             //
00728             // note: we are purposefully ignoring any errors.  if the drive
00729             //       doesn't support a synch_cache, then we're up a creek
00730             //       anyways.
00731             //
00732 
00733             DebugPrint((1, "(%p)\tSending stop unit to device\n", Irp));
00734 
00735             //
00736             // Issue the start unit command to the device.
00737             //
00738 
00739             Context->Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
00740             Context->Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
00741 
00742             Context->Srb.TimeOutValue = START_UNIT_TIMEOUT;
00743 
00744             Context->Srb.SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER |
00745                                     SRB_FLAGS_DISABLE_AUTOSENSE |
00746                                     SRB_FLAGS_DISABLE_SYNCH_TRANSFER |
00747                                     SRB_FLAGS_NO_QUEUE_FREEZE |
00748                                     SRB_FLAGS_BYPASS_LOCKED_QUEUE;
00749 
00750             Context->Srb.SrbStatus = Context->Srb.ScsiStatus = 0;
00751             Context->Srb.DataTransferLength = 0;
00752 
00753             Context->Srb.CdbLength = 6;
00754 
00755             cdb = (PCDB) Context->Srb.Cdb;
00756             RtlZeroMemory(cdb, sizeof(CDB));
00757 
00758             cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
00759             cdb->START_STOP.Start = 0;
00760             cdb->START_STOP.Immediate = 1;
00761 
00762             IoSetCompletionRoutine(Irp,
00763                                    ClasspPowerDownCompletion,
00764                                    Context,
00765                                    TRUE,
00766                                    TRUE,
00767                                    TRUE);
00768 
00769             nextStack->Parameters.Scsi.Srb = &(Context->Srb);
00770             nextStack->MajorFunction = IRP_MJ_SCSI;
00771 
00772             status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
00773 
00774             DebugPrint((1, "(%p)\tIoCallDriver returned %lx\n", Irp, status));
00775             break;
00776 
00777         }
00778 
00779         case PowerDownDeviceStopped2: {
00780 
00781             BOOLEAN ignoreError = TRUE;
00782 
00783             //
00784             // stop was sent
00785             //
00786 
00787             if(SRB_STATUS(Context->Srb.SrbStatus) != SRB_STATUS_SUCCESS) {
00788 
00789                 BOOLEAN retry;
00790 
00791                 DebugPrint((1, "(%p)\tError occured when issueing STOP_UNIT "
00792                             "command to device. Srb %p, Status %lx\n",
00793                             Irp,
00794                             &Context->Srb,
00795                             Context->Srb.SrbStatus));
00796 
00797                 ASSERT(!(TEST_FLAG(Context->Srb.SrbStatus,
00798                                    SRB_STATUS_QUEUE_FROZEN)));
00799                 ASSERT(Context->Srb.Function == SRB_FUNCTION_EXECUTE_SCSI);
00800 
00801                 Context->RetryInterval = 0;
00802                 retry = ClassInterpretSenseInfo(
00803                             commonExtension->DeviceObject,
00804                             &Context->Srb,
00805                             IRP_MJ_SCSI,
00806                             IRP_MJ_POWER,
00807                             MAXIMUM_RETRIES - Context->RetryCount,
00808                             &status,
00809                             &Context->RetryInterval);
00810 
00811                 if((retry == TRUE) && (Context->RetryCount-- != 0)) {
00812 
00813                         DebugPrint((1, "(%p)\tRetrying failed request\n", Irp));
00814 
00815                         //
00816                         // decrement the state so we come back through here
00817                         // the next time.
00818                         //
00819 
00820                         Context->PowerChangeState.PowerDown2--;
00821                         RetryPowerRequest(commonExtension->DeviceObject,
00822                                           Irp,
00823                                           Context);
00824                         break;
00825                 }
00826 
00827                 DebugPrint((1, "(%p)\tSTOP_UNIT not retried\n", Irp));
00828                 Context->RetryCount = MAXIMUM_RETRIES;
00829 
00830             } // end !SRB_STATUS_SUCCESS
00831 
00832 
00833             DebugPrint((1, "(%p)\tPreviously sent stop unit\n", Irp));
00834 
00835             //
00836             // some operations, such as a physical format in progress,
00837             // should not be ignored and should fail the power operation.
00838             //
00839 
00840             if (!NT_SUCCESS(status)) {
00841                 
00842                 PSENSE_DATA senseBuffer = Context->Srb.SenseInfoBuffer;
00843                 
00844                 if (TEST_FLAG(Context->Srb.SrbStatus,
00845                               SRB_STATUS_AUTOSENSE_VALID) &&
00846                     ((senseBuffer->SenseKey & 0xf) == SCSI_SENSE_NOT_READY) &&
00847                     (senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY) &&
00848                     (senseBuffer->AdditionalSenseCodeQualifier == SCSI_SENSEQ_FORMAT_IN_PROGRESS)
00849                     ) {
00850                     ignoreError = FALSE;
00851                     Context->FinalStatus = STATUS_DEVICE_BUSY;
00852                     status = Context->FinalStatus;
00853                 }
00854 
00855             }
00856 
00857             if (NT_SUCCESS(status) || ignoreError) {
00858 
00859                 //
00860                 // Issue the actual power request to the lower driver.
00861                 //
00862 
00863                 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
00864 
00865                 IoCopyCurrentIrpStackLocationToNext(Irp);
00866 
00867                 IoSetCompletionRoutine(Irp,
00868                                        ClasspPowerDownCompletion,
00869                                        Context,
00870                                        TRUE,
00871                                        TRUE,
00872                                        TRUE);
00873 
00874                 status = PoCallDriver(commonExtension->LowerDeviceObject, Irp);
00875 
00876                 DebugPrint((1, "(%p)\tPoCallDriver returned %lx\n", Irp, status));
00877                 break;
00878             }
00879             
00880             // else fall through w/o sending the power irp, since the device
00881             // is reporting an error that would be "really bad" to power down
00882             // during.
00883 
00884         }
00885 
00886         case PowerDownDeviceOff2: {
00887 
00888             //
00889             // SpinDown request completed ... whether it succeeded or not is
00890             // another matter entirely.
00891             //
00892 
00893             DebugPrint((1, "(%p)\tPreviously sent power irp\n", Irp));
00894 
00895             if (Context->QueueLocked) {
00896 
00897                 DebugPrint((1, "(%p)\tUnlocking queue\n", Irp));
00898                 
00899                 Context->Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
00900 
00901                 Context->Srb.SrbStatus = Context->Srb.ScsiStatus = 0;
00902                 Context->Srb.DataTransferLength = 0;
00903 
00904                 Context->Srb.Function = SRB_FUNCTION_UNLOCK_QUEUE;
00905                 Context->Srb.SrbFlags = SRB_FLAGS_BYPASS_LOCKED_QUEUE;
00906                 nextStack->Parameters.Scsi.Srb = &(Context->Srb);
00907                 nextStack->MajorFunction = IRP_MJ_SCSI;
00908 
00909                 IoSetCompletionRoutine(Irp,
00910                                        ClasspPowerDownCompletion,
00911                                        Context,
00912                                        TRUE,
00913                                        TRUE,
00914                                        TRUE);
00915 
00916                 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
00917                 DebugPrint((1, "(%p)\tIoCallDriver returned %lx\n",
00918                             Irp,
00919                             status));
00920                 break;
00921             }
00922 
00923         }
00924 
00925         case PowerDownDeviceUnlocked2: {
00926 
00927             //
00928             // This is the end of the dance.  Free the srb and complete the
00929             // request finally.  We're ignoring possible intermediate
00930             // error conditions ....
00931             //
00932 
00933             if (Context->QueueLocked == FALSE) {
00934                 DebugPrint((1, "(%p)\tFall through (queue not locked)\n", Irp));
00935             } else {
00936                 DebugPrint((1, "(%p)\tPreviously unlocked queue\n", Irp));
00937                 ASSERT(NT_SUCCESS(Irp->IoStatus.Status));
00938                 ASSERT(Context->Srb.SrbStatus == SRB_STATUS_SUCCESS);
00939             }
00940 
00941             DebugPrint((1, "(%p)\tFreeing srb and completing\n", Irp));
00942             Context->InUse = FALSE;
00943             status = Context->FinalStatus; // allow failure to propogate
00944             Context = NULL;
00945 
00946             if(Irp->PendingReturned) {
00947                 IoMarkIrpPending(Irp);
00948             }
00949 
00950             Irp->IoStatus.Status = status;
00951             Irp->IoStatus.Information = 0;
00952 
00953             if (NT_SUCCESS(status)) {
00954                 
00955                 //
00956                 // Set the new power state
00957                 //
00958 
00959                 fdoExtension->DevicePowerState =
00960                     currentStack->Parameters.Power.State.DeviceState;
00961 
00962             }
00963 
00964 
00965             DebugPrint((1, "(%p)\tStarting next power irp\n", Irp));
00966 
00967             ClassReleaseRemoveLock(DeviceObject, Irp);
00968             PoStartNextPowerIrp(Irp);
00969             fdoExtension->PowerDownInProgress = FALSE;
00970 
00971             return status;
00972         }
00973     }
00974 
00975     return STATUS_MORE_PROCESSING_REQUIRED;
00976 } // end ClasspPowerDownCompletion()
00977 
00978 /*++////////////////////////////////////////////////////////////////////////////
00979 
00980 ClasspPowerHandler()
00981 
00982 Routine Description:
00983 
00984     This routine reduces the number of useless spinups and spindown requests
00985     sent to a given device by ignoring transitions to power states we are
00986     currently in.
00987     
00988     ISSUE-2000/02/20-henrygab - by ignoring spin-up requests, we may be
00989           allowing the drive
00990 
00991 Arguments:
00992 
00993     DeviceObject - the device object which is transitioning power states
00994     Irp - the power irp
00995     Options - a set of flags indicating what the device handles
00996 
00997 Return Value:
00998 
00999 --*/
01000 NTSTATUS
01001 ClasspPowerHandler(
01002     IN PDEVICE_OBJECT DeviceObject,
01003     IN PIRP Irp,
01004     IN CLASS_POWER_OPTIONS Options  // ISSUE-2000/02/20-henrygab - pass pointer, not whole struct
01005     )
01006 {
01007     PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
01008     PDEVICE_OBJECT lowerDevice = commonExtension->LowerDeviceObject;
01009     PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
01010     PIO_STACK_LOCATION nextIrpStack;
01011     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
01012     PCLASS_POWER_CONTEXT context;
01013 
01014     if (!commonExtension->IsFdo) {
01015 
01016         //
01017         // certain assumptions are made here,
01018         // particularly: having the fdoExtension
01019         //
01020 
01021         DebugPrint((0, "ClasspPowerHandler: Called for PDO %p???\n",
01022                     DeviceObject));
01023         ASSERT(!"PDO using ClasspPowerHandler");
01024         return STATUS_NOT_SUPPORTED;
01025     }
01026 
01027     DebugPrint((1, "ClasspPowerHandler: Power irp %p to %s %p\n",
01028                 Irp, (commonExtension->IsFdo ? "fdo" : "pdo"), DeviceObject));
01029 
01030     switch(irpStack->MinorFunction) {
01031 
01032         case IRP_MN_SET_POWER: {
01033             PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData;
01034 
01035             DebugPrint((1, "(%p)\tIRP_MN_SET_POWER\n", Irp));
01036 
01037             DebugPrint((1, "(%p)\tSetting %s state to %d\n",
01038                         Irp,
01039                         (irpStack->Parameters.Power.Type == SystemPowerState ?
01040                             "System" : "Device"),
01041                         irpStack->Parameters.Power.State.SystemState));
01042 
01043                 switch (irpStack->Parameters.Power.ShutdownType){
01044                     
01045                     case PowerActionSleep:
01046                     case PowerActionHibernate:
01047                         if (fdoData->HotplugInfo.MediaRemovable || fdoData->HotplugInfo.MediaHotplug){
01048                             /*
01049                              *  We are suspending and this drive is either hot-pluggable
01050                              *  or contains removeable media.
01051                              *  Set the media dirty bit, since the media may change while
01052                              *  we are suspended.
01053                              */
01054                             SET_FLAG(DeviceObject->Flags, DO_VERIFY_VOLUME);
01055                         }
01056                         break;
01057                 }
01058             
01059             break;
01060         }
01061 
01062         default: {
01063 
01064             DebugPrint((1, "(%p)\tIrp minor code = %#x\n",
01065                         Irp, irpStack->MinorFunction));
01066             break;
01067         }
01068     }
01069 
01070     if (irpStack->Parameters.Power.Type != DevicePowerState ||
01071         irpStack->MinorFunction != IRP_MN_SET_POWER) {
01072 
01073         DebugPrint((1, "(%p)\tSending to lower device\n", Irp));
01074 
01075         goto ClasspPowerHandlerCleanup;
01076 
01077     }
01078 
01079     nextIrpStack = IoGetNextIrpStackLocation(Irp);
01080 
01081     //
01082     // already in exact same state, don't work to transition to it.
01083     //
01084 
01085     if(irpStack->Parameters.Power.State.DeviceState ==
01086        fdoExtension->DevicePowerState) {
01087 
01088         DebugPrint((1, "(%p)\tAlready in device state %x\n",
01089                     Irp, fdoExtension->DevicePowerState));
01090         goto ClasspPowerHandlerCleanup;
01091 
01092     }
01093 
01094     //
01095     // or powering down from non-d0 state (device already stopped)
01096     // NOTE -- we're not sure whether this case can exist or not (the
01097     // power system may never send this sort of request) but it's trivial
01098     // to deal with.
01099     //
01100 
01101     if ((irpStack->Parameters.Power.State.DeviceState != PowerDeviceD0) &&
01102         (fdoExtension->DevicePowerState != PowerDeviceD0)) {
01103         DebugPrint((1, "(%p)\tAlready powered down to %x???\n",
01104                     Irp, fdoExtension->DevicePowerState));
01105         fdoExtension->DevicePowerState =
01106             irpStack->Parameters.Power.State.DeviceState;
01107         goto ClasspPowerHandlerCleanup;
01108     }
01109 
01110     //
01111     // or going into a hibernation state when we're in the hibernation path.
01112     // If the device is spinning then we should leave it spinning - if it's not
01113     // then the dump driver will start it up for us.
01114     //
01115 
01116     if((irpStack->Parameters.Power.State.DeviceState == PowerDeviceD3) &&
01117        (irpStack->Parameters.Power.ShutdownType == PowerActionHibernate) &&
01118        (commonExtension->HibernationPathCount != 0)) {
01119 
01120         DebugPrint((1, "(%p)\tdoing nothing for hibernation request for "
01121                        "state %x???\n",
01122                     Irp, fdoExtension->DevicePowerState));
01123         fdoExtension->DevicePowerState =
01124             irpStack->Parameters.Power.State.DeviceState;
01125         goto ClasspPowerHandlerCleanup;
01126     }
01127     //
01128     // or when not handling powering up and are powering up
01129     //
01130 
01131     if ((!Options.HandleSpinUp) &&
01132         (irpStack->Parameters.Power.State.DeviceState == PowerDeviceD0)) {
01133 
01134         DebugPrint((2, "(%p)\tNot handling spinup to state %x\n",
01135                     Irp, fdoExtension->DevicePowerState));
01136         fdoExtension->DevicePowerState =
01137             irpStack->Parameters.Power.State.DeviceState;
01138         goto ClasspPowerHandlerCleanup;
01139 
01140     }
01141 
01142     //
01143     // or when not handling powering down and are powering down
01144     //
01145 
01146     if ((!Options.HandleSpinDown) &&
01147         (irpStack->Parameters.Power.State.DeviceState != PowerDeviceD0)) {
01148 
01149         DebugPrint((2, "(%p)\tNot handling spindown to state %x\n",
01150                     Irp, fdoExtension->DevicePowerState));
01151         fdoExtension->DevicePowerState =
01152             irpStack->Parameters.Power.State.DeviceState;
01153         goto ClasspPowerHandlerCleanup;
01154 
01155     }
01156 
01157     context = &(fdoExtension->PowerContext);
01158 
01159 #if DBG
01160     //
01161     // Mark the context as in use.  We should be synchronizing this but
01162     // since it's just for debugging purposes we don't worry too much.
01163     //
01164 
01165     ASSERT(context->InUse == FALSE);
01166 #endif
01167 
01168     RtlZeroMemory(context, sizeof(CLASS_POWER_CONTEXT));
01169     context->InUse = TRUE;
01170 
01171     nextIrpStack->Parameters.Scsi.Srb = &(context->Srb);
01172     nextIrpStack->MajorFunction = IRP_MJ_SCSI;
01173 
01174     context->FinalStatus = STATUS_SUCCESS;
01175 
01176     context->Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
01177     context->Srb.OriginalRequest = Irp;
01178     context->Srb.SrbFlags |= SRB_FLAGS_BYPASS_LOCKED_QUEUE
01179                           |  SRB_FLAGS_NO_QUEUE_FREEZE;
01180     context->Srb.Function = SRB_FUNCTION_LOCK_QUEUE;
01181 
01182     context->Srb.SenseInfoBuffer =
01183         commonExtension->PartitionZeroExtension->SenseData;
01184     context->Srb.SenseInfoBufferLength = SENSE_BUFFER_SIZE;
01185     context->RetryCount = MAXIMUM_RETRIES;
01186 
01187     context->Options = Options;
01188     context->DeviceObject = DeviceObject;
01189     context->Irp = Irp;
01190 
01191     if(irpStack->Parameters.Power.State.DeviceState == PowerDeviceD0) {
01192 
01193         ASSERT(Options.HandleSpinUp);
01194 
01195         DebugPrint((2, "(%p)\tpower up - locking queue\n", Irp));
01196 
01197         //
01198         // We need to issue a queue lock request so that we
01199         // can spin the drive back up after the power is restored
01200         // but before any requests are processed.
01201         //
01202 
01203         context->Options.PowerDown = FALSE;
01204         context->PowerChangeState.PowerUp = PowerUpDeviceInitial;
01205         context->CompletionRoutine = ClasspPowerUpCompletion;
01206 
01207     } else {
01208 
01209         ASSERT(Options.HandleSpinDown);
01210 
01211         fdoExtension->PowerDownInProgress = TRUE;
01212 
01213         DebugPrint((2, "(%p)\tPowering down - locking queue\n", Irp));
01214 
01215         PoSetPowerState(DeviceObject,
01216                         irpStack->Parameters.Power.Type,
01217                         irpStack->Parameters.Power.State);
01218 
01219         context->Options.PowerDown = TRUE;
01220         context->PowerChangeState.PowerDown2 = PowerDownDeviceInitial2;
01221         context->CompletionRoutine = ClasspPowerDownCompletion;
01222 
01223     }
01224 
01225     //
01226     // we are not dealing with port-allocated sense in these routines.
01227     //
01228 
01229     ASSERT(!TEST_FLAG(context->Srb.SrbFlags, SRB_FLAGS_FREE_SENSE_BUFFER));
01230     ASSERT(!TEST_FLAG(context->Srb.SrbFlags, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE));
01231 
01232     //
01233     // we are always returning STATUS_PENDING, so we need to always
01234     // set the irp as pending.
01235     //
01236 
01237     IoMarkIrpPending(Irp);
01238 
01239     if(Options.LockQueue) {
01240 
01241         //
01242         // Send the lock irp down.
01243         //
01244 
01245         IoSetCompletionRoutine(Irp,
01246                                context->CompletionRoutine,
01247                                context,
01248                                TRUE,
01249                                TRUE,
01250                                TRUE);
01251 
01252         IoCallDriver(lowerDevice, Irp);
01253 
01254     } else {
01255 
01256         //
01257         // Call the completion routine directly.  It won't care what the
01258         // status of the "lock" was - it will just go and do the next
01259         // step of the operation.
01260         //
01261 
01262         context->CompletionRoutine(DeviceObject, Irp, context);
01263     }
01264 
01265     return STATUS_PENDING;
01266 
01267 ClasspPowerHandlerCleanup:
01268 
01269     ClassReleaseRemoveLock(DeviceObject, Irp);
01270 
01271     DebugPrint((1, "(%p)\tStarting next power irp\n", Irp));
01272     IoCopyCurrentIrpStackLocationToNext(Irp);
01273     IoSetCompletionRoutine(Irp,
01274                            ClasspStartNextPowerIrpCompletion,
01275                            NULL,
01276                            TRUE,
01277                            TRUE,
01278                            TRUE);
01279     return PoCallDriver(lowerDevice, Irp);
01280 } // end ClasspPowerHandler()
01281 
01282 /*++////////////////////////////////////////////////////////////////////////////
01283 
01284 ClassMinimalPowerHandler()
01285 
01286 Routine Description:
01287 
01288     This routine is the minimum power handler for a storage driver.  It does
01289     the least amount of work possible.
01290 
01291 --*/
01292 NTSTATUS
01293 ClassMinimalPowerHandler(
01294     IN PDEVICE_OBJECT DeviceObject,
01295     IN PIRP Irp
01296     )
01297 {
01298     PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
01299     PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
01300     NTSTATUS status;
01301 
01302     ClassReleaseRemoveLock(DeviceObject, Irp);
01303     PoStartNextPowerIrp(Irp);
01304 
01305     if(commonExtension->IsFdo) {
01306 
01307         if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
01308 
01309             PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = 
01310                 DeviceObject->DeviceExtension;
01311 
01312             //
01313             // Check if the system is going to hibernate or standby.
01314             //
01315             if (irpStack->MinorFunction == IRP_MN_SET_POWER){
01316                 PVPB vpb;
01317                 
01318                 switch (irpStack->Parameters.Power.ShutdownType){
01319                     
01320                     case PowerActionSleep:
01321                     case PowerActionHibernate:
01322                         //
01323                         // If the volume is mounted, set the verify bit so that
01324                         // the filesystem will be forced re-read the media
01325                         // after coming out of hibernation or standby.
01326                         //
01327                         vpb = ClassGetVpb(fdoExtension->DeviceObject);
01328                         if (vpb && (vpb->Flags & VPB_MOUNTED)){
01329                             SET_FLAG(fdoExtension->DeviceObject->Flags, DO_VERIFY_VOLUME);  
01330                         } 
01331                         break;
01332                 }
01333             } 
01334         }
01335 
01336         IoCopyCurrentIrpStackLocationToNext(Irp);
01337         return PoCallDriver(commonExtension->LowerDeviceObject, Irp);
01338 
01339     } else {
01340 
01341         if (irpStack->MinorFunction != IRP_MN_SET_POWER &&
01342             irpStack->MinorFunction != IRP_MN_QUERY_POWER) {
01343            
01344             NOTHING;
01345 
01346         } else {
01347 
01348             Irp->IoStatus.Status = STATUS_SUCCESS;
01349             Irp->IoStatus.Information = 0;
01350 
01351         }
01352         status = Irp->IoStatus.Status;
01353 
01354         ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
01355         return status;
01356     }
01357 } // end ClassMinimalPowerHandler()
01358 
01359 /*++////////////////////////////////////////////////////////////////////////////
01360 
01361 ClassSpinDownPowerHandler()
01362 
01363 Routine Description:
01364 
01365     This routine is a callback for disks and other things which require both
01366     a start and a stop to be sent to the device.  (actually the starts are
01367     almost always optional, since most device power themselves on to process
01368     commands, but i digress).
01369     
01370     Determines proper use of spinup, spindown, and queue locking based upon
01371     ScanForSpecialFlags in the FdoExtension.  This is the most common power
01372     handler passed into classpnp.sys
01373 
01374 Arguments:
01375 
01376     DeviceObject - Supplies the functional device object
01377 
01378     Irp - Supplies the request to be retried.
01379 
01380 Return Value:
01381 
01382     None
01383 
01384 --*/
01385 NTSTATUS
01386 ClassSpinDownPowerHandler(
01387     IN PDEVICE_OBJECT DeviceObject,
01388     IN PIRP Irp
01389     )
01390 {
01391     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
01392     CLASS_POWER_OPTIONS options;
01393 
01394     fdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
01395 
01396     //
01397     // this will set all options to FALSE
01398     //
01399 
01400     RtlZeroMemory(&options, sizeof(CLASS_POWER_OPTIONS));
01401 
01402     //
01403     // check the flags to see what options we need to worry about
01404     //
01405 
01406     if (!TEST_FLAG(fdoExtension->ScanForSpecialFlags,
01407                   CLASS_SPECIAL_DISABLE_SPIN_DOWN)) {
01408         options.HandleSpinDown = TRUE;
01409     }
01410 
01411     if (!TEST_FLAG(fdoExtension->ScanForSpecialFlags,
01412                   CLASS_SPECIAL_DISABLE_SPIN_UP)) {
01413         options.HandleSpinUp = TRUE;
01414     }
01415 
01416     if (!TEST_FLAG(fdoExtension->ScanForSpecialFlags,
01417                   CLASS_SPECIAL_NO_QUEUE_LOCK)) {
01418         options.LockQueue = TRUE;
01419     }
01420 
01421     DebugPrint((3, "ClasspPowerHandler: Devobj %p\n"
01422                 "\t%shandling spin down\n"
01423                 "\t%shandling spin up\n"
01424                 "\t%slocking queue\n",
01425                 DeviceObject,
01426                 (options.HandleSpinDown ? "" : "not "),
01427                 (options.HandleSpinUp   ? "" : "not "),
01428                 (options.LockQueue      ? "" : "not ")
01429                 ));
01430 
01431     //
01432     // do all the dirty work
01433     //
01434 
01435     return ClasspPowerHandler(DeviceObject, Irp, options);
01436 } // end ClassSpinDownPowerHandler()
01437 
01438 /*++////////////////////////////////////////////////////////////////////////////
01439 
01440 ClassStopUnitPowerHandler()
01441 
01442 Routine Description:
01443 
01444     This routine is an outdated call.  To achieve equivalent functionality,
01445     the driver should set the following flags in ScanForSpecialFlags in the
01446     FdoExtension:
01447         
01448         CLASS_SPECIAL_DISABLE_SPIN_UP
01449         CLASS_SPECIAL_NO_QUEUE_LOCK
01450 
01451 --*/
01452 NTSTATUS
01453 ClassStopUnitPowerHandler(
01454     IN PDEVICE_OBJECT DeviceObject,
01455     IN PIRP Irp
01456     )
01457 {
01458     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
01459 
01460     DebugPrint((0, "ClassStopUnitPowerHandler - Devobj %p using outdated call\n"
01461                 "Drivers should set the following flags in ScanForSpecialFlags "
01462                 " in the FDO extension:\n"
01463                 "\tCLASS_SPECIAL_DISABLE_SPIN_UP\n"
01464                 "\tCLASS_SPECIAL_NO_QUEUE_LOCK\n"
01465                 "This will provide equivalent functionality if the power "
01466                 "routine is then set to ClassSpinDownPowerHandler\n\n",
01467                 DeviceObject));
01468 
01469     fdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
01470 
01471     SET_FLAG(fdoExtension->ScanForSpecialFlags,
01472              CLASS_SPECIAL_DISABLE_SPIN_UP);
01473     SET_FLAG(fdoExtension->ScanForSpecialFlags,
01474              CLASS_SPECIAL_NO_QUEUE_LOCK);
01475 
01476     return ClassSpinDownPowerHandler(DeviceObject, Irp);
01477 } // end ClassStopUnitPowerHandler()
01478 
01479 /*++////////////////////////////////////////////////////////////////////////////
01480 
01481 RetryPowerRequest()
01482 
01483 Routine Description:
01484 
01485     This routine reinitalizes the necessary fields, and sends the request
01486     to the lower driver.
01487 
01488 Arguments:
01489 
01490     DeviceObject - Supplies the device object associated with this request.
01491 
01492     Irp - Supplies the request to be retried.
01493 
01494     Context - Supplies a pointer to the power up context for this request.
01495 
01496 Return Value:
01497 
01498     None
01499 
01500 --*/
01501 VOID
01502 RetryPowerRequest(
01503     PDEVICE_OBJECT DeviceObject,
01504     PIRP Irp,
01505     PCLASS_POWER_CONTEXT Context
01506     )
01507 {
01508     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
01509     PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
01510     PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
01511     PSCSI_REQUEST_BLOCK srb = &(Context->Srb);
01512     LARGE_INTEGER dueTime;
01513 
01514     DebugPrint((1, "(%p)\tDelaying retry by queueing DPC\n", Irp));
01515 
01516     ASSERT(Context->Irp == Irp);
01517     ASSERT(Context->DeviceObject == DeviceObject);
01518     ASSERT(!TEST_FLAG(Context->Srb.SrbFlags, SRB_FLAGS_FREE_SENSE_BUFFER));
01519     ASSERT(!TEST_FLAG(Context->Srb.SrbFlags, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE));
01520 
01521     //
01522     // reset the retry interval
01523     //
01524 
01525     Context->RetryInterval = 0;
01526 
01527     //
01528     // Reset byte count of transfer in SRB Extension.
01529     //
01530 
01531     srb->DataTransferLength = 0;
01532 
01533     //
01534     // Zero SRB statuses.
01535     //
01536 
01537     srb->SrbStatus = srb->ScsiStatus = 0;
01538 
01539     //
01540     // Set up major SCSI function.
01541     //
01542 
01543     nextIrpStack->MajorFunction = IRP_MJ_SCSI;
01544 
01545     //
01546     // Save SRB address in next stack for port driver.
01547     //
01548 
01549     nextIrpStack->Parameters.Scsi.Srb = srb;
01550 
01551     //
01552     // Set the completion routine up again.
01553     //
01554 
01555     IoSetCompletionRoutine(Irp, Context->CompletionRoutine, Context,
01556                            TRUE, TRUE, TRUE);
01557 
01558 
01559     if (Context->RetryInterval == 0) {
01560 
01561         DebugPrint((2, "(%p)\tDelaying minimum time (.2 sec)\n", Irp));
01562         dueTime.QuadPart = (LONGLONG)1000000 * 2;
01563 
01564     } else {
01565 
01566         DebugPrint((2, "(%p)\tDelaying %x seconds\n",
01567                     Irp, Context->RetryInterval));
01568         dueTime.QuadPart = (LONGLONG)1000000 * 10 * Context->RetryInterval;
01569 
01570     }
01571 
01572     ClassRetryRequest(DeviceObject, Irp, dueTime);
01573 
01574     return;
01575 
01576 } // end RetryRequest()
01577 
01578 /*++////////////////////////////////////////////////////////////////////////////
01579 
01580 ClasspStartNextPowerIrpCompletion()
01581 
01582 Routine Description:
01583 
01584     This routine guarantees that the next power irp (power up or down) is not
01585     sent until the previous one has fully completed.
01586 
01587 --*/
01588 NTSTATUS
01589 ClasspStartNextPowerIrpCompletion(
01590     IN PDEVICE_OBJECT DeviceObject,
01591     IN PIRP Irp,
01592     IN PVOID Context
01593     )
01594 {
01595     if(Irp->PendingReturned) {
01596         IoMarkIrpPending(Irp);
01597     }
01598 
01599     PoStartNextPowerIrp(Irp);
01600     return STATUS_SUCCESS;
01601 } // end ClasspStartNextPowerIrpCompletion()
01602 

Generated on Mon May 28 2012 04:24:07 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.