Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenpower.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
1.7.6.1
|