Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1613 lines
49 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1991 - 1999
  3. Module Name:
  4. class.c
  5. Abstract:
  6. SCSI class driver routines
  7. Environment:
  8. kernel mode only
  9. Notes:
  10. Revision History:
  11. --*/
  12. #include "stddef.h"
  13. #include "ntddk.h"
  14. #include "scsi.h"
  15. #include "classp.h"
  16. #include <stdarg.h>
  17. #define CLASS_TAG_POWER 'WLcS'
  18. NTSTATUS
  19. ClasspPowerHandler(
  20. IN PDEVICE_OBJECT DeviceObject,
  21. IN PIRP Irp,
  22. IN CLASS_POWER_OPTIONS Options
  23. );
  24. NTSTATUS
  25. ClasspPowerDownCompletion(
  26. IN PDEVICE_OBJECT DeviceObject,
  27. IN PIRP Irp,
  28. IN PCLASS_POWER_CONTEXT Context
  29. );
  30. NTSTATUS
  31. ClasspPowerUpCompletion(
  32. IN PDEVICE_OBJECT DeviceObject,
  33. IN PIRP Irp,
  34. IN PCLASS_POWER_CONTEXT Context
  35. );
  36. VOID
  37. RetryPowerRequest(
  38. PDEVICE_OBJECT DeviceObject,
  39. PIRP Irp,
  40. PCLASS_POWER_CONTEXT Context
  41. );
  42. NTSTATUS
  43. ClasspStartNextPowerIrpCompletion(
  44. IN PDEVICE_OBJECT DeviceObject,
  45. IN PIRP Irp,
  46. IN PVOID Context
  47. );
  48. /*++////////////////////////////////////////////////////////////////////////////
  49. ClassDispatchPower()
  50. Routine Description:
  51. This routine acquires the removelock for the irp and then calls the
  52. appropriate power callback.
  53. Arguments:
  54. DeviceObject -
  55. Irp -
  56. Return Value:
  57. --*/
  58. NTSTATUS
  59. ClassDispatchPower(
  60. IN PDEVICE_OBJECT DeviceObject,
  61. IN PIRP Irp
  62. )
  63. {
  64. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  65. ULONG isRemoved;
  66. PCLASS_POWER_DEVICE powerRoutine = NULL;
  67. //
  68. // NOTE: This code may be called at PASSIVE or DISPATCH, depending
  69. // upon the device object it is being called for.
  70. // don't do anything that would break under either circumstance.
  71. //
  72. NTSTATUS status;
  73. isRemoved = ClassAcquireRemoveLock(DeviceObject, Irp);
  74. if(isRemoved) {
  75. ClassReleaseRemoveLock(DeviceObject, Irp);
  76. Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
  77. PoStartNextPowerIrp(Irp);
  78. ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
  79. return STATUS_DEVICE_DOES_NOT_EXIST;
  80. }
  81. return commonExtension->DevInfo->ClassPowerDevice(DeviceObject, Irp);
  82. } // end ClassDispatchPower()
  83. /*++////////////////////////////////////////////////////////////////////////////
  84. ClasspPowerUpCompletion()
  85. Routine Description:
  86. This routine is used for intermediate completion of a power up request.
  87. PowerUp requires four requests to be sent to the lower driver in sequence.
  88. * The queue is "power locked" to ensure that the class driver power-up
  89. work can be done before request processing resumes.
  90. * The power irp is sent down the stack for any filter drivers and the
  91. port driver to return power and resume command processing for the
  92. device. Since the queue is locked, no queued irps will be sent
  93. immediately.
  94. * A start unit command is issued to the device with appropriate flags
  95. to override the "power locked" queue.
  96. * The queue is "power unlocked" to start processing requests again.
  97. This routine uses the function in the srb which just completed to determine
  98. which state it is in.
  99. Arguments:
  100. DeviceObject - the device object being powered up
  101. Irp - the IO_REQUEST_PACKET containing the power request
  102. Srb - the SRB used to perform port/class operations.
  103. Return Value:
  104. STATUS_MORE_PROCESSING_REQUIRED or
  105. STATUS_SUCCESS
  106. --*/
  107. NTSTATUS
  108. ClasspPowerUpCompletion(
  109. IN PDEVICE_OBJECT DeviceObject,
  110. IN PIRP Irp,
  111. IN PCLASS_POWER_CONTEXT Context
  112. )
  113. {
  114. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  115. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  116. PIO_STACK_LOCATION currentStack = IoGetCurrentIrpStackLocation(Irp);
  117. PIO_STACK_LOCATION nextStack = IoGetNextIrpStackLocation(Irp);
  118. NTSTATUS status = STATUS_MORE_PROCESSING_REQUIRED;
  119. DebugPrint((1, "ClasspPowerUpCompletion: Device Object %p, Irp %p, "
  120. "Context %p\n",
  121. DeviceObject, Irp, Context));
  122. ASSERT(!TEST_FLAG(Context->Srb.SrbFlags, SRB_FLAGS_FREE_SENSE_BUFFER));
  123. ASSERT(!TEST_FLAG(Context->Srb.SrbFlags, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE));
  124. ASSERT(Context->Options.PowerDown == FALSE);
  125. ASSERT(Context->Options.HandleSpinUp);
  126. if(Irp->PendingReturned) {
  127. IoMarkIrpPending(Irp);
  128. }
  129. Context->PowerChangeState.PowerUp++;
  130. switch(Context->PowerChangeState.PowerUp) {
  131. case PowerUpDeviceLocked: {
  132. DebugPrint((1, "(%p)\tPreviously sent power lock\n", Irp));
  133. //
  134. // Issue the actual power request to the lower driver.
  135. //
  136. IoCopyCurrentIrpStackLocationToNext(Irp);
  137. //
  138. // If the lock wasn't successful then just bail out on the power
  139. // request unless we can ignore failed locks
  140. //
  141. if((Context->Options.LockQueue == TRUE) &&
  142. (!NT_SUCCESS(Irp->IoStatus.Status))) {
  143. DebugPrint((1, "(%p)\tIrp status was %lx\n",
  144. Irp, Irp->IoStatus.Status));
  145. DebugPrint((1, "(%p)\tSrb status was %lx\n",
  146. Irp, Context->Srb.SrbStatus));
  147. //
  148. // Lock was not successful - throw down the power IRP
  149. // by itself and don't try to spin up the drive or unlock
  150. // the queue.
  151. //
  152. Context->InUse = FALSE;
  153. Context = NULL;
  154. //
  155. // Set the new power state
  156. //
  157. fdoExtension->DevicePowerState =
  158. currentStack->Parameters.Power.State.DeviceState;
  159. Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  160. IoCopyCurrentIrpStackLocationToNext(Irp);
  161. IoSetCompletionRoutine(Irp,
  162. ClasspStartNextPowerIrpCompletion,
  163. NULL,
  164. TRUE,
  165. TRUE,
  166. TRUE);
  167. //
  168. // Indicate to Po that we've been successfully powered up so
  169. // it can do it's notification stuff.
  170. //
  171. PoSetPowerState(DeviceObject,
  172. currentStack->Parameters.Power.Type,
  173. currentStack->Parameters.Power.State);
  174. PoCallDriver(commonExtension->LowerDeviceObject, Irp);
  175. ClassReleaseRemoveLock(commonExtension->DeviceObject,
  176. Irp);
  177. return STATUS_MORE_PROCESSING_REQUIRED;
  178. } else {
  179. Context->QueueLocked = (UCHAR) Context->Options.LockQueue;
  180. }
  181. Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  182. Context->PowerChangeState.PowerUp = PowerUpDeviceLocked;
  183. IoSetCompletionRoutine(Irp,
  184. ClasspPowerUpCompletion,
  185. Context,
  186. TRUE,
  187. TRUE,
  188. TRUE);
  189. status = PoCallDriver(commonExtension->LowerDeviceObject, Irp);
  190. DebugPrint((2, "(%p)\tPoCallDriver returned %lx\n", Irp, status));
  191. break;
  192. }
  193. case PowerUpDeviceOn: {
  194. PCDB cdb;
  195. if(NT_SUCCESS(Irp->IoStatus.Status)) {
  196. DebugPrint((1, "(%p)\tSending start unit to device\n", Irp));
  197. //
  198. // Issue the start unit command to the device.
  199. //
  200. Context->Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
  201. Context->Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
  202. Context->Srb.SrbStatus = Context->Srb.ScsiStatus = 0;
  203. Context->Srb.DataTransferLength = 0;
  204. Context->Srb.TimeOutValue = START_UNIT_TIMEOUT;
  205. Context->Srb.SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER |
  206. SRB_FLAGS_DISABLE_AUTOSENSE |
  207. SRB_FLAGS_DISABLE_SYNCH_TRANSFER |
  208. SRB_FLAGS_NO_QUEUE_FREEZE;
  209. if(Context->Options.LockQueue) {
  210. SET_FLAG(Context->Srb.SrbFlags, SRB_FLAGS_BYPASS_LOCKED_QUEUE);
  211. }
  212. Context->Srb.CdbLength = 6;
  213. cdb = (PCDB) (Context->Srb.Cdb);
  214. RtlZeroMemory(cdb, sizeof(CDB));
  215. cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
  216. cdb->START_STOP.Start = 1;
  217. Context->PowerChangeState.PowerUp = PowerUpDeviceOn;
  218. IoSetCompletionRoutine(Irp,
  219. ClasspPowerUpCompletion,
  220. Context,
  221. TRUE,
  222. TRUE,
  223. TRUE);
  224. nextStack->Parameters.Scsi.Srb = &(Context->Srb);
  225. nextStack->MajorFunction = IRP_MJ_SCSI;
  226. status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
  227. DebugPrint((2, "(%p)\tIoCallDriver returned %lx\n", Irp, status));
  228. } else {
  229. //
  230. // we're done.
  231. //
  232. Context->FinalStatus = Irp->IoStatus.Status;
  233. goto ClasspPowerUpCompletionFailure;
  234. }
  235. break;
  236. }
  237. case PowerUpDeviceStarted: { // 3
  238. //
  239. // First deal with an error if one occurred.
  240. //
  241. if(SRB_STATUS(Context->Srb.SrbStatus) != SRB_STATUS_SUCCESS) {
  242. BOOLEAN retry;
  243. DebugPrint((1, "%p\tError occured when issuing START_UNIT "
  244. "command to device. Srb %p, Status %x\n",
  245. Irp,
  246. &Context->Srb,
  247. Context->Srb.SrbStatus));
  248. ASSERT(!(TEST_FLAG(Context->Srb.SrbStatus,
  249. SRB_STATUS_QUEUE_FROZEN)));
  250. ASSERT(Context->Srb.Function == SRB_FUNCTION_EXECUTE_SCSI);
  251. Context->RetryInterval = 0;
  252. retry = ClassInterpretSenseInfo(
  253. commonExtension->DeviceObject,
  254. &Context->Srb,
  255. IRP_MJ_SCSI,
  256. IRP_MJ_POWER,
  257. MAXIMUM_RETRIES - Context->RetryCount,
  258. &status,
  259. &Context->RetryInterval);
  260. if((retry == TRUE) && (Context->RetryCount-- != 0)) {
  261. DebugPrint((1, "(%p)\tRetrying failed request\n", Irp));
  262. //
  263. // Decrement the state so we come back through here the
  264. // next time.
  265. //
  266. Context->PowerChangeState.PowerUp--;
  267. RetryPowerRequest(commonExtension->DeviceObject,
  268. Irp,
  269. Context);
  270. break;
  271. }
  272. // reset retries
  273. Context->RetryCount = MAXIMUM_RETRIES;
  274. }
  275. ClasspPowerUpCompletionFailure:
  276. DebugPrint((1, "(%p)\tPreviously spun device up\n", Irp));
  277. if (Context->QueueLocked) {
  278. DebugPrint((1, "(%p)\tUnlocking queue\n", Irp));
  279. Context->Srb.Function = SRB_FUNCTION_UNLOCK_QUEUE;
  280. Context->Srb.SrbFlags = SRB_FLAGS_BYPASS_LOCKED_QUEUE;
  281. Context->Srb.SrbStatus = Context->Srb.ScsiStatus = 0;
  282. Context->Srb.DataTransferLength = 0;
  283. nextStack->Parameters.Scsi.Srb = &(Context->Srb);
  284. nextStack->MajorFunction = IRP_MJ_SCSI;
  285. Context->PowerChangeState.PowerUp = PowerUpDeviceStarted;
  286. IoSetCompletionRoutine(Irp,
  287. ClasspPowerUpCompletion,
  288. Context,
  289. TRUE,
  290. TRUE,
  291. TRUE);
  292. status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
  293. DebugPrint((1, "(%p)\tIoCallDriver returned %lx\n",
  294. Irp, status));
  295. break;
  296. }
  297. // Fall-through to next case...
  298. }
  299. case PowerUpDeviceUnlocked: {
  300. //
  301. // This is the end of the dance. Free the srb and complete the
  302. // request finally. We're ignoring possible intermediate
  303. // error conditions ....
  304. //
  305. if (Context->QueueLocked) {
  306. DebugPrint((1, "(%p)\tPreviously unlocked queue\n", Irp));
  307. ASSERT(NT_SUCCESS(Irp->IoStatus.Status));
  308. ASSERT(Context->Srb.SrbStatus == SRB_STATUS_SUCCESS);
  309. } else {
  310. DebugPrint((1, "(%p)\tFall-through (queue not locked)\n", Irp));
  311. }
  312. DebugPrint((1, "(%p)\tFreeing srb and completing\n", Irp));
  313. Context->InUse = FALSE;
  314. status = Context->FinalStatus;
  315. Irp->IoStatus.Status = status;
  316. Context = NULL;
  317. //
  318. // Set the new power state
  319. //
  320. if(NT_SUCCESS(status)) {
  321. fdoExtension->DevicePowerState =
  322. currentStack->Parameters.Power.State.DeviceState;
  323. }
  324. //
  325. // Indicate to Po that we've been successfully powered up so
  326. // it can do it's notification stuff.
  327. //
  328. PoSetPowerState(DeviceObject,
  329. currentStack->Parameters.Power.Type,
  330. currentStack->Parameters.Power.State);
  331. DebugPrint((1, "(%p)\tStarting next power irp\n", Irp));
  332. ClassReleaseRemoveLock(DeviceObject, Irp);
  333. PoStartNextPowerIrp(Irp);
  334. return status;
  335. }
  336. }
  337. return STATUS_MORE_PROCESSING_REQUIRED;
  338. } // end ClasspPowerUpCompletion()
  339. /*++////////////////////////////////////////////////////////////////////////////
  340. ClasspPowerDownCompletion()
  341. Routine Description:
  342. This routine is used for intermediate completion of a power up request.
  343. PowerUp requires four requests to be sent to the lower driver in sequence.
  344. * The queue is "power locked" to ensure that the class driver power-up
  345. work can be done before request processing resumes.
  346. * The power irp is sent down the stack for any filter drivers and the
  347. port driver to return power and resume command processing for the
  348. device. Since the queue is locked, no queued irps will be sent
  349. immediately.
  350. * A start unit command is issued to the device with appropriate flags
  351. to override the "power locked" queue.
  352. * The queue is "power unlocked" to start processing requests again.
  353. This routine uses the function in the srb which just completed to determine
  354. which state it is in.
  355. Arguments:
  356. DeviceObject - the device object being powered up
  357. Irp - the IO_REQUEST_PACKET containing the power request
  358. Srb - the SRB used to perform port/class operations.
  359. Return Value:
  360. STATUS_MORE_PROCESSING_REQUIRED or
  361. STATUS_SUCCESS
  362. --*/
  363. NTSTATUS
  364. ClasspPowerDownCompletion(
  365. IN PDEVICE_OBJECT DeviceObject,
  366. IN PIRP Irp,
  367. IN PCLASS_POWER_CONTEXT Context
  368. )
  369. {
  370. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  371. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  372. PIO_STACK_LOCATION currentStack = IoGetCurrentIrpStackLocation(Irp);
  373. PIO_STACK_LOCATION nextStack = IoGetNextIrpStackLocation(Irp);
  374. NTSTATUS status = STATUS_MORE_PROCESSING_REQUIRED;
  375. DebugPrint((1, "ClasspPowerDownCompletion: Device Object %p, "
  376. "Irp %p, Context %p\n",
  377. DeviceObject, Irp, Context));
  378. ASSERT(!TEST_FLAG(Context->Srb.SrbFlags, SRB_FLAGS_FREE_SENSE_BUFFER));
  379. ASSERT(!TEST_FLAG(Context->Srb.SrbFlags, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE));
  380. ASSERT(Context->Options.PowerDown == TRUE);
  381. ASSERT(Context->Options.HandleSpinDown);
  382. if(Irp->PendingReturned) {
  383. IoMarkIrpPending(Irp);
  384. }
  385. Context->PowerChangeState.PowerDown2++;
  386. switch(Context->PowerChangeState.PowerDown2) {
  387. case PowerDownDeviceLocked2: {
  388. PCDB cdb;
  389. DebugPrint((1, "(%p)\tPreviously sent power lock\n", Irp));
  390. if((Context->Options.LockQueue == TRUE) &&
  391. (!NT_SUCCESS(Irp->IoStatus.Status))) {
  392. DebugPrint((1, "(%p)\tIrp status was %lx\n",
  393. Irp,
  394. Irp->IoStatus.Status));
  395. DebugPrint((1, "(%p)\tSrb status was %lx\n",
  396. Irp,
  397. Context->Srb.SrbStatus));
  398. Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  399. //
  400. // Lock was not successful - throw down the power IRP
  401. // by itself and don't try to spin down the drive or unlock
  402. // the queue.
  403. //
  404. Context->InUse = FALSE;
  405. Context = NULL;
  406. //
  407. // Set the new power state
  408. //
  409. fdoExtension->DevicePowerState =
  410. currentStack->Parameters.Power.State.DeviceState;
  411. //
  412. // Indicate to Po that we've been successfully powered down
  413. // so it can do it's notification stuff.
  414. //
  415. IoCopyCurrentIrpStackLocationToNext(Irp);
  416. IoSetCompletionRoutine(Irp,
  417. ClasspStartNextPowerIrpCompletion,
  418. NULL,
  419. TRUE,
  420. TRUE,
  421. TRUE);
  422. PoSetPowerState(DeviceObject,
  423. currentStack->Parameters.Power.Type,
  424. currentStack->Parameters.Power.State);
  425. fdoExtension->PowerDownInProgress = FALSE;
  426. PoCallDriver(commonExtension->LowerDeviceObject, Irp);
  427. ClassReleaseRemoveLock(commonExtension->DeviceObject,
  428. Irp);
  429. return STATUS_MORE_PROCESSING_REQUIRED;
  430. } else {
  431. Context->QueueLocked = (UCHAR) Context->Options.LockQueue;
  432. }
  433. if (!TEST_FLAG(fdoExtension->PrivateFdoData->HackFlags,
  434. FDO_HACK_NO_SYNC_CACHE)) {
  435. //
  436. // send SCSIOP_SYNCHRONIZE_CACHE
  437. //
  438. Context->Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
  439. Context->Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
  440. Context->Srb.TimeOutValue = fdoExtension->TimeOutValue;
  441. Context->Srb.SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER |
  442. SRB_FLAGS_DISABLE_AUTOSENSE |
  443. SRB_FLAGS_DISABLE_SYNCH_TRANSFER |
  444. SRB_FLAGS_NO_QUEUE_FREEZE |
  445. SRB_FLAGS_BYPASS_LOCKED_QUEUE;
  446. Context->Srb.SrbStatus = Context->Srb.ScsiStatus = 0;
  447. Context->Srb.DataTransferLength = 0;
  448. Context->Srb.CdbLength = 10;
  449. cdb = (PCDB) Context->Srb.Cdb;
  450. RtlZeroMemory(cdb, sizeof(CDB));
  451. cdb->SYNCHRONIZE_CACHE10.OperationCode = SCSIOP_SYNCHRONIZE_CACHE;
  452. IoSetCompletionRoutine(Irp,
  453. ClasspPowerDownCompletion,
  454. Context,
  455. TRUE,
  456. TRUE,
  457. TRUE);
  458. nextStack->Parameters.Scsi.Srb = &(Context->Srb);
  459. nextStack->MajorFunction = IRP_MJ_SCSI;
  460. status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
  461. DebugPrint((1, "(%p)\tIoCallDriver returned %lx\n", Irp, status));
  462. break;
  463. } else {
  464. DebugPrint((1, "(%p)\tPower Down: not sending SYNCH_CACHE\n",
  465. DeviceObject));
  466. Context->PowerChangeState.PowerDown2++;
  467. Context->Srb.SrbStatus = SRB_STATUS_SUCCESS;
  468. // and fall through....
  469. }
  470. // no break in case the device doesn't like synch_cache commands
  471. }
  472. case PowerDownDeviceFlushed2: {
  473. PCDB cdb;
  474. DebugPrint((1, "(%p)\tPreviously send SCSIOP_SYNCHRONIZE_CACHE\n",
  475. Irp));
  476. //
  477. // SCSIOP_SYNCHRONIZE_CACHE was sent
  478. //
  479. if(SRB_STATUS(Context->Srb.SrbStatus) != SRB_STATUS_SUCCESS) {
  480. BOOLEAN retry;
  481. DebugPrint((1, "(%p)\tError occured when issuing "
  482. "SYNCHRONIZE_CACHE command to device. "
  483. "Srb %p, Status %lx\n",
  484. Irp,
  485. &Context->Srb,
  486. Context->Srb.SrbStatus));
  487. ASSERT(!(TEST_FLAG(Context->Srb.SrbStatus,
  488. SRB_STATUS_QUEUE_FROZEN)));
  489. ASSERT(Context->Srb.Function == SRB_FUNCTION_EXECUTE_SCSI);
  490. Context->RetryInterval = 0;
  491. retry = ClassInterpretSenseInfo(
  492. commonExtension->DeviceObject,
  493. &Context->Srb,
  494. IRP_MJ_SCSI,
  495. IRP_MJ_POWER,
  496. MAXIMUM_RETRIES - Context->RetryCount,
  497. &status,
  498. &Context->RetryInterval);
  499. if((retry == TRUE) && (Context->RetryCount-- != 0)) {
  500. DebugPrint((1, "(%p)\tRetrying failed request\n", Irp));
  501. //
  502. // decrement the state so we come back through here
  503. // the next time.
  504. //
  505. Context->PowerChangeState.PowerDown2--;
  506. RetryPowerRequest(commonExtension->DeviceObject,
  507. Irp,
  508. Context);
  509. break;
  510. }
  511. DebugPrint((1, "(%p)\tSYNCHRONIZE_CACHE not retried\n", Irp));
  512. Context->RetryCount = MAXIMUM_RETRIES;
  513. } // end !SRB_STATUS_SUCCESS
  514. //
  515. // note: we are purposefully ignoring any errors. if the drive
  516. // doesn't support a synch_cache, then we're up a creek
  517. // anyways.
  518. //
  519. DebugPrint((1, "(%p)\tSending stop unit to device\n", Irp));
  520. //
  521. // Issue the start unit command to the device.
  522. //
  523. Context->Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
  524. Context->Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
  525. Context->Srb.TimeOutValue = START_UNIT_TIMEOUT;
  526. Context->Srb.SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER |
  527. SRB_FLAGS_DISABLE_AUTOSENSE |
  528. SRB_FLAGS_DISABLE_SYNCH_TRANSFER |
  529. SRB_FLAGS_NO_QUEUE_FREEZE |
  530. SRB_FLAGS_BYPASS_LOCKED_QUEUE;
  531. Context->Srb.SrbStatus = Context->Srb.ScsiStatus = 0;
  532. Context->Srb.DataTransferLength = 0;
  533. Context->Srb.CdbLength = 6;
  534. cdb = (PCDB) Context->Srb.Cdb;
  535. RtlZeroMemory(cdb, sizeof(CDB));
  536. cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
  537. cdb->START_STOP.Start = 0;
  538. cdb->START_STOP.Immediate = 1;
  539. IoSetCompletionRoutine(Irp,
  540. ClasspPowerDownCompletion,
  541. Context,
  542. TRUE,
  543. TRUE,
  544. TRUE);
  545. nextStack->Parameters.Scsi.Srb = &(Context->Srb);
  546. nextStack->MajorFunction = IRP_MJ_SCSI;
  547. status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
  548. DebugPrint((1, "(%p)\tIoCallDriver returned %lx\n", Irp, status));
  549. break;
  550. }
  551. case PowerDownDeviceStopped2: {
  552. BOOLEAN ignoreError = TRUE;
  553. //
  554. // stop was sent
  555. //
  556. if(SRB_STATUS(Context->Srb.SrbStatus) != SRB_STATUS_SUCCESS) {
  557. BOOLEAN retry;
  558. DebugPrint((1, "(%p)\tError occured when issueing STOP_UNIT "
  559. "command to device. Srb %p, Status %lx\n",
  560. Irp,
  561. &Context->Srb,
  562. Context->Srb.SrbStatus));
  563. ASSERT(!(TEST_FLAG(Context->Srb.SrbStatus,
  564. SRB_STATUS_QUEUE_FROZEN)));
  565. ASSERT(Context->Srb.Function == SRB_FUNCTION_EXECUTE_SCSI);
  566. Context->RetryInterval = 0;
  567. retry = ClassInterpretSenseInfo(
  568. commonExtension->DeviceObject,
  569. &Context->Srb,
  570. IRP_MJ_SCSI,
  571. IRP_MJ_POWER,
  572. MAXIMUM_RETRIES - Context->RetryCount,
  573. &status,
  574. &Context->RetryInterval);
  575. if((retry == TRUE) && (Context->RetryCount-- != 0)) {
  576. DebugPrint((1, "(%p)\tRetrying failed request\n", Irp));
  577. //
  578. // decrement the state so we come back through here
  579. // the next time.
  580. //
  581. Context->PowerChangeState.PowerDown2--;
  582. RetryPowerRequest(commonExtension->DeviceObject,
  583. Irp,
  584. Context);
  585. break;
  586. }
  587. DebugPrint((1, "(%p)\tSTOP_UNIT not retried\n", Irp));
  588. Context->RetryCount = MAXIMUM_RETRIES;
  589. } // end !SRB_STATUS_SUCCESS
  590. DebugPrint((1, "(%p)\tPreviously sent stop unit\n", Irp));
  591. //
  592. // some operations, such as a physical format in progress,
  593. // should not be ignored and should fail the power operation.
  594. //
  595. if (!NT_SUCCESS(status)) {
  596. PSENSE_DATA senseBuffer = Context->Srb.SenseInfoBuffer;
  597. if (TEST_FLAG(Context->Srb.SrbStatus,
  598. SRB_STATUS_AUTOSENSE_VALID) &&
  599. ((senseBuffer->SenseKey & 0xf) == SCSI_SENSE_NOT_READY) &&
  600. (senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY) &&
  601. (senseBuffer->AdditionalSenseCodeQualifier == SCSI_SENSEQ_FORMAT_IN_PROGRESS)
  602. ) {
  603. ignoreError = FALSE;
  604. Context->FinalStatus = STATUS_DEVICE_BUSY;
  605. status = Context->FinalStatus;
  606. }
  607. }
  608. if (NT_SUCCESS(status) || ignoreError) {
  609. //
  610. // Issue the actual power request to the lower driver.
  611. //
  612. Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  613. IoCopyCurrentIrpStackLocationToNext(Irp);
  614. IoSetCompletionRoutine(Irp,
  615. ClasspPowerDownCompletion,
  616. Context,
  617. TRUE,
  618. TRUE,
  619. TRUE);
  620. status = PoCallDriver(commonExtension->LowerDeviceObject, Irp);
  621. DebugPrint((1, "(%p)\tPoCallDriver returned %lx\n", Irp, status));
  622. break;
  623. }
  624. // else fall through w/o sending the power irp, since the device
  625. // is reporting an error that would be "really bad" to power down
  626. // during.
  627. }
  628. case PowerDownDeviceOff2: {
  629. //
  630. // SpinDown request completed ... whether it succeeded or not is
  631. // another matter entirely.
  632. //
  633. DebugPrint((1, "(%p)\tPreviously sent power irp\n", Irp));
  634. if (Context->QueueLocked) {
  635. DebugPrint((1, "(%p)\tUnlocking queue\n", Irp));
  636. Context->Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
  637. Context->Srb.SrbStatus = Context->Srb.ScsiStatus = 0;
  638. Context->Srb.DataTransferLength = 0;
  639. Context->Srb.Function = SRB_FUNCTION_UNLOCK_QUEUE;
  640. Context->Srb.SrbFlags = SRB_FLAGS_BYPASS_LOCKED_QUEUE;
  641. nextStack->Parameters.Scsi.Srb = &(Context->Srb);
  642. nextStack->MajorFunction = IRP_MJ_SCSI;
  643. IoSetCompletionRoutine(Irp,
  644. ClasspPowerDownCompletion,
  645. Context,
  646. TRUE,
  647. TRUE,
  648. TRUE);
  649. status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
  650. DebugPrint((1, "(%p)\tIoCallDriver returned %lx\n",
  651. Irp,
  652. status));
  653. break;
  654. }
  655. }
  656. case PowerDownDeviceUnlocked2: {
  657. //
  658. // This is the end of the dance. Free the srb and complete the
  659. // request finally. We're ignoring possible intermediate
  660. // error conditions ....
  661. //
  662. if (Context->QueueLocked == FALSE) {
  663. DebugPrint((1, "(%p)\tFall through (queue not locked)\n", Irp));
  664. } else {
  665. DebugPrint((1, "(%p)\tPreviously unlocked queue\n", Irp));
  666. ASSERT(NT_SUCCESS(Irp->IoStatus.Status));
  667. ASSERT(Context->Srb.SrbStatus == SRB_STATUS_SUCCESS);
  668. }
  669. DebugPrint((1, "(%p)\tFreeing srb and completing\n", Irp));
  670. Context->InUse = FALSE;
  671. status = Context->FinalStatus; // allow failure to propogate
  672. Context = NULL;
  673. if(Irp->PendingReturned) {
  674. IoMarkIrpPending(Irp);
  675. }
  676. Irp->IoStatus.Status = status;
  677. Irp->IoStatus.Information = 0;
  678. if (NT_SUCCESS(status)) {
  679. //
  680. // Set the new power state
  681. //
  682. fdoExtension->DevicePowerState =
  683. currentStack->Parameters.Power.State.DeviceState;
  684. }
  685. DebugPrint((1, "(%p)\tStarting next power irp\n", Irp));
  686. ClassReleaseRemoveLock(DeviceObject, Irp);
  687. PoStartNextPowerIrp(Irp);
  688. fdoExtension->PowerDownInProgress = FALSE;
  689. return status;
  690. }
  691. }
  692. return STATUS_MORE_PROCESSING_REQUIRED;
  693. } // end ClasspPowerDownCompletion()
  694. /*++////////////////////////////////////////////////////////////////////////////
  695. ClasspPowerHandler()
  696. Routine Description:
  697. This routine reduces the number of useless spinups and spindown requests
  698. sent to a given device by ignoring transitions to power states we are
  699. currently in.
  700. ISSUE-2000/02/20-henrygab - by ignoring spin-up requests, we may be
  701. allowing the drive
  702. Arguments:
  703. DeviceObject - the device object which is transitioning power states
  704. Irp - the power irp
  705. Options - a set of flags indicating what the device handles
  706. Return Value:
  707. --*/
  708. NTSTATUS
  709. ClasspPowerHandler(
  710. IN PDEVICE_OBJECT DeviceObject,
  711. IN PIRP Irp,
  712. IN CLASS_POWER_OPTIONS Options // ISSUE-2000/02/20-henrygab - pass pointer, not whole struct
  713. )
  714. {
  715. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  716. PDEVICE_OBJECT lowerDevice = commonExtension->LowerDeviceObject;
  717. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  718. PIO_STACK_LOCATION nextIrpStack;
  719. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  720. PCLASS_POWER_CONTEXT context;
  721. if (!commonExtension->IsFdo) {
  722. //
  723. // certain assumptions are made here,
  724. // particularly: having the fdoExtension
  725. //
  726. DebugPrint((0, "ClasspPowerHandler: Called for PDO %p???\n",
  727. DeviceObject));
  728. ASSERT(!"PDO using ClasspPowerHandler");
  729. return STATUS_NOT_SUPPORTED;
  730. }
  731. DebugPrint((1, "ClasspPowerHandler: Power irp %p to %s %p\n",
  732. Irp, (commonExtension->IsFdo ? "fdo" : "pdo"), DeviceObject));
  733. switch(irpStack->MinorFunction) {
  734. case IRP_MN_SET_POWER: {
  735. PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData;
  736. DebugPrint((1, "(%p)\tIRP_MN_SET_POWER\n", Irp));
  737. DebugPrint((1, "(%p)\tSetting %s state to %d\n",
  738. Irp,
  739. (irpStack->Parameters.Power.Type == SystemPowerState ?
  740. "System" : "Device"),
  741. irpStack->Parameters.Power.State.SystemState));
  742. switch (irpStack->Parameters.Power.ShutdownType){
  743. case PowerActionSleep:
  744. case PowerActionHibernate:
  745. if (fdoData->HotplugInfo.MediaRemovable || fdoData->HotplugInfo.MediaHotplug){
  746. /*
  747. * We are suspending and this drive is either hot-pluggable
  748. * or contains removeable media.
  749. * Set the media dirty bit, since the media may change while
  750. * we are suspended.
  751. */
  752. SET_FLAG(DeviceObject->Flags, DO_VERIFY_VOLUME);
  753. //
  754. // Bumping the media change count will force the
  755. // file system to verify the volume when we resume
  756. //
  757. InterlockedIncrement(&fdoExtension->MediaChangeCount);
  758. }
  759. break;
  760. }
  761. break;
  762. }
  763. default: {
  764. DebugPrint((1, "(%p)\tIrp minor code = %#x\n",
  765. Irp, irpStack->MinorFunction));
  766. break;
  767. }
  768. }
  769. if (irpStack->Parameters.Power.Type != DevicePowerState ||
  770. irpStack->MinorFunction != IRP_MN_SET_POWER) {
  771. DebugPrint((1, "(%p)\tSending to lower device\n", Irp));
  772. goto ClasspPowerHandlerCleanup;
  773. }
  774. nextIrpStack = IoGetNextIrpStackLocation(Irp);
  775. //
  776. // already in exact same state, don't work to transition to it.
  777. //
  778. if(irpStack->Parameters.Power.State.DeviceState ==
  779. fdoExtension->DevicePowerState) {
  780. DebugPrint((1, "(%p)\tAlready in device state %x\n",
  781. Irp, fdoExtension->DevicePowerState));
  782. goto ClasspPowerHandlerCleanup;
  783. }
  784. //
  785. // or powering down from non-d0 state (device already stopped)
  786. // NOTE -- we're not sure whether this case can exist or not (the
  787. // power system may never send this sort of request) but it's trivial
  788. // to deal with.
  789. //
  790. if ((irpStack->Parameters.Power.State.DeviceState != PowerDeviceD0) &&
  791. (fdoExtension->DevicePowerState != PowerDeviceD0)) {
  792. DebugPrint((1, "(%p)\tAlready powered down to %x???\n",
  793. Irp, fdoExtension->DevicePowerState));
  794. fdoExtension->DevicePowerState =
  795. irpStack->Parameters.Power.State.DeviceState;
  796. goto ClasspPowerHandlerCleanup;
  797. }
  798. //
  799. // or going into a hibernation state when we're in the hibernation path.
  800. // If the device is spinning then we should leave it spinning - if it's not
  801. // then the dump driver will start it up for us.
  802. //
  803. if((irpStack->Parameters.Power.State.DeviceState == PowerDeviceD3) &&
  804. (irpStack->Parameters.Power.ShutdownType == PowerActionHibernate) &&
  805. (commonExtension->HibernationPathCount != 0)) {
  806. DebugPrint((1, "(%p)\tdoing nothing for hibernation request for "
  807. "state %x???\n",
  808. Irp, fdoExtension->DevicePowerState));
  809. fdoExtension->DevicePowerState =
  810. irpStack->Parameters.Power.State.DeviceState;
  811. goto ClasspPowerHandlerCleanup;
  812. }
  813. //
  814. // or when not handling powering up and are powering up
  815. //
  816. if ((!Options.HandleSpinUp) &&
  817. (irpStack->Parameters.Power.State.DeviceState == PowerDeviceD0)) {
  818. DebugPrint((2, "(%p)\tNot handling spinup to state %x\n",
  819. Irp, fdoExtension->DevicePowerState));
  820. fdoExtension->DevicePowerState =
  821. irpStack->Parameters.Power.State.DeviceState;
  822. goto ClasspPowerHandlerCleanup;
  823. }
  824. //
  825. // or when not handling powering down and are powering down
  826. //
  827. if ((!Options.HandleSpinDown) &&
  828. (irpStack->Parameters.Power.State.DeviceState != PowerDeviceD0)) {
  829. DebugPrint((2, "(%p)\tNot handling spindown to state %x\n",
  830. Irp, fdoExtension->DevicePowerState));
  831. fdoExtension->DevicePowerState =
  832. irpStack->Parameters.Power.State.DeviceState;
  833. goto ClasspPowerHandlerCleanup;
  834. }
  835. context = &(fdoExtension->PowerContext);
  836. #if DBG
  837. //
  838. // Mark the context as in use. We should be synchronizing this but
  839. // since it's just for debugging purposes we don't worry too much.
  840. //
  841. ASSERT(context->InUse == FALSE);
  842. #endif
  843. RtlZeroMemory(context, sizeof(CLASS_POWER_CONTEXT));
  844. context->InUse = TRUE;
  845. nextIrpStack->Parameters.Scsi.Srb = &(context->Srb);
  846. nextIrpStack->MajorFunction = IRP_MJ_SCSI;
  847. context->FinalStatus = STATUS_SUCCESS;
  848. context->Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
  849. context->Srb.OriginalRequest = Irp;
  850. context->Srb.SrbFlags |= SRB_FLAGS_BYPASS_LOCKED_QUEUE
  851. | SRB_FLAGS_NO_QUEUE_FREEZE;
  852. context->Srb.Function = SRB_FUNCTION_LOCK_QUEUE;
  853. context->Srb.SenseInfoBuffer =
  854. commonExtension->PartitionZeroExtension->SenseData;
  855. context->Srb.SenseInfoBufferLength = SENSE_BUFFER_SIZE;
  856. context->RetryCount = MAXIMUM_RETRIES;
  857. context->Options = Options;
  858. context->DeviceObject = DeviceObject;
  859. context->Irp = Irp;
  860. if(irpStack->Parameters.Power.State.DeviceState == PowerDeviceD0) {
  861. ASSERT(Options.HandleSpinUp);
  862. DebugPrint((2, "(%p)\tpower up - locking queue\n", Irp));
  863. //
  864. // We need to issue a queue lock request so that we
  865. // can spin the drive back up after the power is restored
  866. // but before any requests are processed.
  867. //
  868. context->Options.PowerDown = FALSE;
  869. context->PowerChangeState.PowerUp = PowerUpDeviceInitial;
  870. context->CompletionRoutine = ClasspPowerUpCompletion;
  871. } else {
  872. ASSERT(Options.HandleSpinDown);
  873. fdoExtension->PowerDownInProgress = TRUE;
  874. DebugPrint((2, "(%p)\tPowering down - locking queue\n", Irp));
  875. PoSetPowerState(DeviceObject,
  876. irpStack->Parameters.Power.Type,
  877. irpStack->Parameters.Power.State);
  878. context->Options.PowerDown = TRUE;
  879. context->PowerChangeState.PowerDown2 = PowerDownDeviceInitial2;
  880. context->CompletionRoutine = ClasspPowerDownCompletion;
  881. }
  882. //
  883. // we are not dealing with port-allocated sense in these routines.
  884. //
  885. ASSERT(!TEST_FLAG(context->Srb.SrbFlags, SRB_FLAGS_FREE_SENSE_BUFFER));
  886. ASSERT(!TEST_FLAG(context->Srb.SrbFlags, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE));
  887. //
  888. // we are always returning STATUS_PENDING, so we need to always
  889. // set the irp as pending.
  890. //
  891. IoMarkIrpPending(Irp);
  892. if(Options.LockQueue) {
  893. //
  894. // Send the lock irp down.
  895. //
  896. IoSetCompletionRoutine(Irp,
  897. context->CompletionRoutine,
  898. context,
  899. TRUE,
  900. TRUE,
  901. TRUE);
  902. IoCallDriver(lowerDevice, Irp);
  903. } else {
  904. //
  905. // Call the completion routine directly. It won't care what the
  906. // status of the "lock" was - it will just go and do the next
  907. // step of the operation.
  908. //
  909. context->CompletionRoutine(DeviceObject, Irp, context);
  910. }
  911. return STATUS_PENDING;
  912. ClasspPowerHandlerCleanup:
  913. ClassReleaseRemoveLock(DeviceObject, Irp);
  914. DebugPrint((1, "(%p)\tStarting next power irp\n", Irp));
  915. IoCopyCurrentIrpStackLocationToNext(Irp);
  916. IoSetCompletionRoutine(Irp,
  917. ClasspStartNextPowerIrpCompletion,
  918. NULL,
  919. TRUE,
  920. TRUE,
  921. TRUE);
  922. return PoCallDriver(lowerDevice, Irp);
  923. } // end ClasspPowerHandler()
  924. /*++////////////////////////////////////////////////////////////////////////////
  925. ClassMinimalPowerHandler()
  926. Routine Description:
  927. This routine is the minimum power handler for a storage driver. It does
  928. the least amount of work possible.
  929. --*/
  930. NTSTATUS
  931. ClassMinimalPowerHandler(
  932. IN PDEVICE_OBJECT DeviceObject,
  933. IN PIRP Irp
  934. )
  935. {
  936. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  937. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  938. NTSTATUS status;
  939. ClassReleaseRemoveLock(DeviceObject, Irp);
  940. PoStartNextPowerIrp(Irp);
  941. switch (irpStack->MinorFunction)
  942. {
  943. case IRP_MN_SET_POWER:
  944. {
  945. switch (irpStack->Parameters.Power.ShutdownType)
  946. {
  947. case PowerActionSleep:
  948. case PowerActionHibernate:
  949. {
  950. if (TEST_FLAG(DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA))
  951. {
  952. if ((ClassGetVpb(DeviceObject) != NULL) && (ClassGetVpb(DeviceObject)->Flags & VPB_MOUNTED))
  953. {
  954. //
  955. // This flag will cause the filesystem to verify the
  956. // volume when coming out of hibernation or standby
  957. //
  958. SET_FLAG(DeviceObject->Flags, DO_VERIFY_VOLUME);
  959. }
  960. }
  961. }
  962. break;
  963. }
  964. }
  965. //
  966. // Fall through
  967. //
  968. case IRP_MN_QUERY_POWER:
  969. {
  970. if (!commonExtension->IsFdo)
  971. {
  972. Irp->IoStatus.Status = STATUS_SUCCESS;
  973. Irp->IoStatus.Information = 0;
  974. }
  975. }
  976. break;
  977. }
  978. if (commonExtension->IsFdo)
  979. {
  980. IoCopyCurrentIrpStackLocationToNext(Irp);
  981. status = PoCallDriver(commonExtension->LowerDeviceObject, Irp);
  982. }
  983. else
  984. {
  985. status = Irp->IoStatus.Status;
  986. ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
  987. }
  988. return status;
  989. } // end ClassMinimalPowerHandler()
  990. /*++////////////////////////////////////////////////////////////////////////////
  991. ClassSpinDownPowerHandler()
  992. Routine Description:
  993. This routine is a callback for disks and other things which require both
  994. a start and a stop to be sent to the device. (actually the starts are
  995. almost always optional, since most device power themselves on to process
  996. commands, but i digress).
  997. Determines proper use of spinup, spindown, and queue locking based upon
  998. ScanForSpecialFlags in the FdoExtension. This is the most common power
  999. handler passed into classpnp.sys
  1000. Arguments:
  1001. DeviceObject - Supplies the functional device object
  1002. Irp - Supplies the request to be retried.
  1003. Return Value:
  1004. None
  1005. --*/
  1006. NTSTATUS
  1007. ClassSpinDownPowerHandler(
  1008. IN PDEVICE_OBJECT DeviceObject,
  1009. IN PIRP Irp
  1010. )
  1011. {
  1012. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
  1013. CLASS_POWER_OPTIONS options;
  1014. fdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
  1015. //
  1016. // this will set all options to FALSE
  1017. //
  1018. RtlZeroMemory(&options, sizeof(CLASS_POWER_OPTIONS));
  1019. //
  1020. // check the flags to see what options we need to worry about
  1021. //
  1022. if (!TEST_FLAG(fdoExtension->ScanForSpecialFlags,
  1023. CLASS_SPECIAL_DISABLE_SPIN_DOWN)) {
  1024. options.HandleSpinDown = TRUE;
  1025. }
  1026. if (!TEST_FLAG(fdoExtension->ScanForSpecialFlags,
  1027. CLASS_SPECIAL_DISABLE_SPIN_UP)) {
  1028. options.HandleSpinUp = TRUE;
  1029. }
  1030. if (!TEST_FLAG(fdoExtension->ScanForSpecialFlags,
  1031. CLASS_SPECIAL_NO_QUEUE_LOCK)) {
  1032. options.LockQueue = TRUE;
  1033. }
  1034. DebugPrint((3, "ClasspPowerHandler: Devobj %p\n"
  1035. "\t%shandling spin down\n"
  1036. "\t%shandling spin up\n"
  1037. "\t%slocking queue\n",
  1038. DeviceObject,
  1039. (options.HandleSpinDown ? "" : "not "),
  1040. (options.HandleSpinUp ? "" : "not "),
  1041. (options.LockQueue ? "" : "not ")
  1042. ));
  1043. //
  1044. // do all the dirty work
  1045. //
  1046. return ClasspPowerHandler(DeviceObject, Irp, options);
  1047. } // end ClassSpinDownPowerHandler()
  1048. /*++////////////////////////////////////////////////////////////////////////////
  1049. ClassStopUnitPowerHandler()
  1050. Routine Description:
  1051. This routine is an outdated call. To achieve equivalent functionality,
  1052. the driver should set the following flags in ScanForSpecialFlags in the
  1053. FdoExtension:
  1054. CLASS_SPECIAL_DISABLE_SPIN_UP
  1055. CLASS_SPECIAL_NO_QUEUE_LOCK
  1056. --*/
  1057. NTSTATUS
  1058. ClassStopUnitPowerHandler(
  1059. IN PDEVICE_OBJECT DeviceObject,
  1060. IN PIRP Irp
  1061. )
  1062. {
  1063. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
  1064. DebugPrint((0, "ClassStopUnitPowerHandler - Devobj %p using outdated call\n"
  1065. "Drivers should set the following flags in ScanForSpecialFlags "
  1066. " in the FDO extension:\n"
  1067. "\tCLASS_SPECIAL_DISABLE_SPIN_UP\n"
  1068. "\tCLASS_SPECIAL_NO_QUEUE_LOCK\n"
  1069. "This will provide equivalent functionality if the power "
  1070. "routine is then set to ClassSpinDownPowerHandler\n\n",
  1071. DeviceObject));
  1072. fdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
  1073. SET_FLAG(fdoExtension->ScanForSpecialFlags,
  1074. CLASS_SPECIAL_DISABLE_SPIN_UP);
  1075. SET_FLAG(fdoExtension->ScanForSpecialFlags,
  1076. CLASS_SPECIAL_NO_QUEUE_LOCK);
  1077. return ClassSpinDownPowerHandler(DeviceObject, Irp);
  1078. } // end ClassStopUnitPowerHandler()
  1079. /*++////////////////////////////////////////////////////////////////////////////
  1080. RetryPowerRequest()
  1081. Routine Description:
  1082. This routine reinitalizes the necessary fields, and sends the request
  1083. to the lower driver.
  1084. Arguments:
  1085. DeviceObject - Supplies the device object associated with this request.
  1086. Irp - Supplies the request to be retried.
  1087. Context - Supplies a pointer to the power up context for this request.
  1088. Return Value:
  1089. None
  1090. --*/
  1091. VOID
  1092. RetryPowerRequest(
  1093. PDEVICE_OBJECT DeviceObject,
  1094. PIRP Irp,
  1095. PCLASS_POWER_CONTEXT Context
  1096. )
  1097. {
  1098. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  1099. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  1100. PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
  1101. PSCSI_REQUEST_BLOCK srb = &(Context->Srb);
  1102. LARGE_INTEGER dueTime;
  1103. DebugPrint((1, "(%p)\tDelaying retry by queueing DPC\n", Irp));
  1104. ASSERT(Context->Irp == Irp);
  1105. ASSERT(Context->DeviceObject == DeviceObject);
  1106. ASSERT(!TEST_FLAG(Context->Srb.SrbFlags, SRB_FLAGS_FREE_SENSE_BUFFER));
  1107. ASSERT(!TEST_FLAG(Context->Srb.SrbFlags, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE));
  1108. //
  1109. // reset the retry interval
  1110. //
  1111. Context->RetryInterval = 0;
  1112. //
  1113. // Reset byte count of transfer in SRB Extension.
  1114. //
  1115. srb->DataTransferLength = 0;
  1116. //
  1117. // Zero SRB statuses.
  1118. //
  1119. srb->SrbStatus = srb->ScsiStatus = 0;
  1120. //
  1121. // Set up major SCSI function.
  1122. //
  1123. nextIrpStack->MajorFunction = IRP_MJ_SCSI;
  1124. //
  1125. // Save SRB address in next stack for port driver.
  1126. //
  1127. nextIrpStack->Parameters.Scsi.Srb = srb;
  1128. //
  1129. // Set the completion routine up again.
  1130. //
  1131. IoSetCompletionRoutine(Irp, Context->CompletionRoutine, Context,
  1132. TRUE, TRUE, TRUE);
  1133. if (Context->RetryInterval == 0) {
  1134. DebugPrint((2, "(%p)\tDelaying minimum time (.2 sec)\n", Irp));
  1135. dueTime.QuadPart = (LONGLONG)1000000 * 2;
  1136. } else {
  1137. DebugPrint((2, "(%p)\tDelaying %x seconds\n",
  1138. Irp, Context->RetryInterval));
  1139. dueTime.QuadPart = (LONGLONG)1000000 * 10 * Context->RetryInterval;
  1140. }
  1141. ClassRetryRequest(DeviceObject, Irp, dueTime);
  1142. return;
  1143. } // end RetryRequest()
  1144. /*++////////////////////////////////////////////////////////////////////////////
  1145. ClasspStartNextPowerIrpCompletion()
  1146. Routine Description:
  1147. This routine guarantees that the next power irp (power up or down) is not
  1148. sent until the previous one has fully completed.
  1149. --*/
  1150. NTSTATUS
  1151. ClasspStartNextPowerIrpCompletion(
  1152. IN PDEVICE_OBJECT DeviceObject,
  1153. IN PIRP Irp,
  1154. IN PVOID Context
  1155. )
  1156. {
  1157. if(Irp->PendingReturned) {
  1158. IoMarkIrpPending(Irp);
  1159. }
  1160. PoStartNextPowerIrp(Irp);
  1161. return STATUS_SUCCESS;
  1162. } // end ClasspStartNextPowerIrpCompletion()