Leaked source code of windows server 2003
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.

569 lines
14 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1996 - 1999
  3. Module Name:
  4. power.c
  5. Abstract:
  6. This module contains the routines for port driver power support
  7. Authors:
  8. Peter Wieland
  9. Environment:
  10. Kernel mode only
  11. Notes:
  12. Revision History:
  13. --*/
  14. #include "port.h"
  15. #define __FILE_ID__ 'enab'
  16. typedef struct _REINIT_CONTEXT {
  17. IN PADAPTER_EXTENSION Adapter;
  18. IN BOOLEAN UseAdapterControl;
  19. OUT NTSTATUS Status;
  20. } REINIT_CONTEXT, *PREINIT_CONTEXT;
  21. NTSTATUS
  22. SpReinitializeAdapter(
  23. IN PADAPTER_EXTENSION Adapter
  24. );
  25. BOOLEAN
  26. SpReinitializeAdapterSynchronized(
  27. IN PREINIT_CONTEXT Context
  28. );
  29. NTSTATUS
  30. SpShutdownAdapter(
  31. IN PADAPTER_EXTENSION Adapter
  32. );
  33. BOOLEAN
  34. SpShutdownAdapterSynchronized(
  35. IN PADAPTER_EXTENSION Adapter
  36. );
  37. NTSTATUS
  38. SpEnableDisableCompletionRoutine(
  39. IN PDEVICE_OBJECT DeviceObject,
  40. IN PIRP Irp,
  41. IN PVOID Context
  42. );
  43. NTSTATUS
  44. SpEnableDisableAdapter(
  45. IN PADAPTER_EXTENSION Adapter,
  46. IN BOOLEAN Enable
  47. )
  48. /*++
  49. Routine Description:
  50. This routine will synchronously enable or disable the specified adapter.
  51. It should be called from the adapter's StartIo routine when a power
  52. irp is processed for the controller.
  53. When the adapter is disabled the state of the adapter will be saved and
  54. the miniport will be shut-down. When the adapter is re-enabled the
  55. miniport will be reinitialized.
  56. Arguments:
  57. Adapter - the adapter to be [en|dis]abled.
  58. Enable - whether to enable or disable the adapter.
  59. Return Value:
  60. status of the adapter enable/disable action.
  61. --*/
  62. {
  63. ULONG count;
  64. KIRQL oldIrql;
  65. NTSTATUS status = STATUS_SUCCESS;
  66. KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
  67. DebugPrint((1, "SpEnableDisableAdapter: Adapter %#p %s\n",
  68. Adapter, Enable ? "enable":"disable"));
  69. if(Enable) {
  70. count = --Adapter->DisableCount;
  71. DebugPrint((1, "SpEnableDisableAdapter: DisableCount is %d\n",
  72. count));
  73. if(count == 0) {
  74. //
  75. // Re-initialize the adapter.
  76. //
  77. status = SpReinitializeAdapter(Adapter);
  78. }
  79. } else {
  80. count = Adapter->DisableCount++;
  81. DebugPrint((1, "SpEnableDisableAdapter: DisableCount was %d\n",
  82. count));
  83. if(count == 0) {
  84. //
  85. // Shut-down the adapter.
  86. //
  87. status = SpShutdownAdapter(Adapter);
  88. }
  89. }
  90. KeLowerIrql(oldIrql);
  91. return status;
  92. }
  93. NTSTATUS
  94. SpEnableDisableLogicalUnit(
  95. IN PLOGICAL_UNIT_EXTENSION LogicalUnit,
  96. IN BOOLEAN Enable,
  97. IN PSP_ENABLE_DISABLE_COMPLETION_ROUTINE CompletionRoutine,
  98. IN PVOID Context
  99. )
  100. /*++
  101. Routine Description:
  102. This routine will enable the specified logical unit. An unlock queue
  103. request will be issued to the logical unit - if the lock count drops
  104. to zero then the device will be re-enabled and i/o processing can be
  105. restarted.
  106. If STATUS_PENDING is returned then the completion routine will be run
  107. when the unlock has been processed. The routine will be called with
  108. the status of the unlock request (note that STATUS_SUCCESS does not
  109. necessarily indicate that the device is ready for use - just that the
  110. lock count has been decremented) and the specified context.
  111. Arguments:
  112. LogicalUnit - the logical unit to be enabled.
  113. Enable - whether the routine should enable or disable the logical unit
  114. CompletionRoutine - the completion routine to be run when the unlock
  115. request has succeeded.
  116. Context - arbitrary context value/pointer which will be passed into the
  117. enable completion routine.
  118. Return Value:
  119. STATUS_PENDING if the request to send an unlock succeeds and the
  120. completion routine will be called.
  121. error if the attempt to send the irp fails. In this case the completion
  122. routine will not be called.
  123. --*/
  124. {
  125. USHORT srbSize;
  126. USHORT size;
  127. PIRP irp;
  128. PSCSI_REQUEST_BLOCK srb;
  129. PIO_STACK_LOCATION nextStack;
  130. NTSTATUS status;
  131. DebugPrint((4, "SpEnableDisableLun: Lun %#p %s context %#p\n",
  132. LogicalUnit, Enable ? "enable":"disable", Context));
  133. srbSize = sizeof(SCSI_REQUEST_BLOCK);
  134. srbSize += sizeof(ULONG) - 1;
  135. srbSize &= ~(sizeof(ULONG) - 1);
  136. size = srbSize + IoSizeOfIrp(LogicalUnit->DeviceObject->StackSize + 1);
  137. srb = SpAllocatePool(NonPagedPool,
  138. size,
  139. SCSIPORT_TAG_ENABLE,
  140. LogicalUnit->DeviceObject->DriverObject);
  141. if(srb == NULL) {
  142. //
  143. // Already failed. Call the completion routine will the failure status
  144. // and let it clean up the request.
  145. //
  146. DebugPrint((1, "SpEnableDisableLogicalUnit: failed to allocate SRB\n"));
  147. if(CompletionRoutine != NULL) {
  148. CompletionRoutine(LogicalUnit->DeviceObject,
  149. STATUS_INSUFFICIENT_RESOURCES,
  150. Context);
  151. }
  152. return STATUS_INSUFFICIENT_RESOURCES;
  153. }
  154. irp = (PIRP) (srb + 1);
  155. IoInitializeIrp(irp,
  156. (USHORT) (size - srbSize),
  157. (CCHAR)(LogicalUnit->DeviceObject->StackSize + 1));
  158. nextStack = IoGetNextIrpStackLocation(irp);
  159. nextStack->Parameters.Others.Argument1 = LogicalUnit->DeviceObject;
  160. nextStack->Parameters.Others.Argument2 = CompletionRoutine;
  161. nextStack->Parameters.Others.Argument3 = Context;
  162. nextStack->Parameters.Others.Argument4 = 0; // retry count
  163. IoSetNextIrpStackLocation(irp);
  164. IoSetCompletionRoutine(irp,
  165. SpEnableDisableCompletionRoutine,
  166. srb,
  167. TRUE,
  168. TRUE,
  169. TRUE);
  170. nextStack = IoGetNextIrpStackLocation(irp);
  171. nextStack->MajorFunction = IRP_MJ_SCSI;
  172. nextStack->MinorFunction = 1;
  173. nextStack->Parameters.Scsi.Srb = srb;
  174. RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
  175. srb->Length = sizeof(SCSI_REQUEST_BLOCK);
  176. srb->OriginalRequest = irp;
  177. srb->SrbFlags = SRB_FLAGS_BYPASS_LOCKED_QUEUE;
  178. srb->Function = Enable ? SRB_FUNCTION_UNLOCK_QUEUE :
  179. SRB_FUNCTION_LOCK_QUEUE;
  180. status = IoCallDriver(LogicalUnit->DeviceObject, irp);
  181. return status;
  182. }
  183. NTSTATUS
  184. SpEnableDisableCompletionRoutine(
  185. IN PDEVICE_OBJECT DeviceObject,
  186. IN PIRP Irp,
  187. IN PSCSI_REQUEST_BLOCK Srb
  188. )
  189. {
  190. PIO_STACK_LOCATION irpStack;
  191. PSP_ENABLE_DISABLE_COMPLETION_ROUTINE routine;
  192. PVOID context;
  193. NTSTATUS status;
  194. DebugPrint((4, "SpEnableDisableCompletionRoutine: irp %#p completed "
  195. "with status %#08lx\n",
  196. Irp, Irp->IoStatus.Status));
  197. irpStack = IoGetCurrentIrpStackLocation(Irp);
  198. routine = irpStack->Parameters.Others.Argument2;
  199. context = irpStack->Parameters.Others.Argument3;
  200. DeviceObject = irpStack->Parameters.Others.Argument1;
  201. status = Irp->IoStatus.Status;
  202. //
  203. // Free the srb which will also release the irp.
  204. //
  205. ExFreePool(Srb);
  206. if(routine != NULL) {
  207. routine(DeviceObject, status, context);
  208. }
  209. return STATUS_MORE_PROCESSING_REQUIRED;
  210. }
  211. NTSTATUS
  212. SpReinitializeAdapter(
  213. IN PADAPTER_EXTENSION Adapter
  214. )
  215. /*++
  216. Routine Description:
  217. This routine will allow the miniport to restore any state or configuration
  218. information and then to restart it's adapter. Adapter interrupts will
  219. be re-enabled at the return of this routine and scsiport may begin issuing
  220. new requests to the miniport.
  221. Arguments:
  222. Adapter - the adapter to be re-initialized.
  223. Return Value:
  224. status
  225. --*/
  226. {
  227. ULONG oldDebug;
  228. KIRQL oldIrql;
  229. ULONG result;
  230. BOOLEAN again;
  231. BOOLEAN useAdapterControl;
  232. NTSTATUS status;
  233. UCHAR string[] = {'W', 'A', 'K', 'E', 'U', 'P', '\0'};
  234. //
  235. // Give the miniport a chance to restore it's bus-data to a state which
  236. // allows the miniport to operate.
  237. //
  238. if(SpIsAdapterControlTypeSupported(Adapter, ScsiRestartAdapter) == TRUE) {
  239. DebugPrint((1, "SpReinitializeAdapter: using AdapterControl\n"));
  240. useAdapterControl = TRUE;
  241. } else {
  242. DebugPrint((1, "SpReinitializeAdapter: using init routines\n"));
  243. useAdapterControl = FALSE;
  244. }
  245. oldIrql = KeRaiseIrqlToDpcLevel();
  246. KeAcquireSpinLockAtDpcLevel(&(Adapter->SpinLock));
  247. //
  248. // Since we may be reinitializing the miniport at DISPATCH_LEVEL we need
  249. // to set the miniport reinitializing flag for some of the SCSIPORT api's
  250. // to modify their behavior.
  251. //
  252. SET_FLAG(Adapter->Flags, PD_MINIPORT_REINITIALIZING);
  253. result = SP_RETURN_FOUND;
  254. if(useAdapterControl == FALSE) {
  255. result = Adapter->HwFindAdapter(Adapter->HwDeviceExtension,
  256. NULL,
  257. NULL,
  258. string,
  259. Adapter->PortConfig,
  260. &again);
  261. } else if(SpIsAdapterControlTypeSupported(Adapter,
  262. ScsiSetRunningConfig) == TRUE) {
  263. SCSI_ADAPTER_CONTROL_STATUS b;
  264. b = SpCallAdapterControl(Adapter, ScsiSetRunningConfig, NULL);
  265. ASSERT(b == ScsiAdapterControlSuccess);
  266. }
  267. if(result == SP_RETURN_FOUND) {
  268. REINIT_CONTEXT context;
  269. context.Adapter = Adapter;
  270. context.UseAdapterControl = useAdapterControl;
  271. Adapter->SynchronizeExecution(Adapter->InterruptObject,
  272. SpReinitializeAdapterSynchronized,
  273. &context);
  274. status = context.Status;
  275. } else {
  276. status = STATUS_DRIVER_INTERNAL_ERROR;
  277. }
  278. if(NT_SUCCESS(status)) {
  279. //
  280. // We had better be ready for another request by now.
  281. //
  282. ScsiPortNotification(NextRequest,
  283. Adapter->HwDeviceExtension);
  284. if (Adapter->InterruptData.InterruptFlags & PD_NOTIFICATION_REQUIRED) {
  285. //
  286. // Request a completion DPC so that we clear out any existing
  287. // attempts to do things like reset the bus.
  288. //
  289. SpRequestCompletionDpc(Adapter->DeviceObject);
  290. }
  291. }
  292. KeReleaseSpinLockFromDpcLevel(&(Adapter->SpinLock));
  293. ASSERT(NT_SUCCESS(status));
  294. KeLowerIrql(oldIrql);
  295. return status;
  296. }
  297. BOOLEAN
  298. SpReinitializeAdapterSynchronized(
  299. IN PREINIT_CONTEXT Context
  300. )
  301. {
  302. PADAPTER_EXTENSION adapter = Context->Adapter;
  303. BOOLEAN result;
  304. DebugPrint((1, "SpReinitializeAdapterSynchronized: calling "
  305. "HwFindAdapter\n"));
  306. if(Context->UseAdapterControl) {
  307. SCSI_ADAPTER_CONTROL_TYPE status;
  308. status = SpCallAdapterControl(adapter, ScsiRestartAdapter, NULL);
  309. result = (status == ScsiAdapterControlSuccess);
  310. } else {
  311. result = adapter->HwInitialize(adapter->HwDeviceExtension);
  312. }
  313. if(result == TRUE) {
  314. Context->Status = STATUS_SUCCESS;
  315. } else {
  316. Context->Status = STATUS_ADAPTER_HARDWARE_ERROR;
  317. }
  318. DebugPrint((1, "SpReinitializeAdapterSynchronized: enabling interrupts\n"));
  319. adapter->InterruptData.InterruptFlags &= ~PD_DISABLE_INTERRUPTS;
  320. CLEAR_FLAG(adapter->Flags, PD_MINIPORT_REINITIALIZING);
  321. CLEAR_FLAG(adapter->Flags, PD_UNCACHED_EXTENSION_RETURNED);
  322. return TRUE;
  323. }
  324. NTSTATUS
  325. SpShutdownAdapter(
  326. IN PADAPTER_EXTENSION Adapter
  327. )
  328. /*++
  329. Routine Description:
  330. This routine will shutdown the miniport and save away any state information
  331. necessary to restart it. Adapter interrupts will be disabled at the
  332. return of this routine - scsiport will not issue any new requests to the
  333. miniport until it has been reinitialized.
  334. Arguments:
  335. Adapter - the adapter to be shut down.
  336. Return Value:
  337. status
  338. --*/
  339. {
  340. //
  341. // Acquire the adapter spinlock and set state to indicate that a
  342. // shutdown is in progress. This will prevent us from starting
  343. // operations that shouldn't be started while shutting down.
  344. //
  345. KeAcquireSpinLockAtDpcLevel(&Adapter->SpinLock);
  346. SET_FLAG(Adapter->Flags, PD_SHUTDOWN_IN_PROGRESS);
  347. KeReleaseSpinLockFromDpcLevel(&Adapter->SpinLock);
  348. //
  349. // Cancel the miniport timer so that we don't call into it after we've
  350. // shut down.
  351. //
  352. KeCancelTimer(&(Adapter->MiniPortTimer));
  353. //
  354. // Currently we don't give the miniport any chance to save any sort of
  355. // state information. We just stop any i/o going into it and then do
  356. // a shutdown.
  357. //
  358. Adapter->SynchronizeExecution(Adapter->InterruptObject,
  359. SpShutdownAdapterSynchronized,
  360. Adapter);
  361. if(SpIsAdapterControlTypeSupported(Adapter, ScsiSetBootConfig)) {
  362. //
  363. // Allow the miniport a chance to reset its PCI bus data before we
  364. // power it off.
  365. //
  366. SpCallAdapterControl(Adapter, ScsiSetBootConfig, NULL);
  367. }
  368. return STATUS_SUCCESS;
  369. }
  370. BOOLEAN
  371. SpShutdownAdapterSynchronized(
  372. IN PADAPTER_EXTENSION Adapter
  373. )
  374. /*++
  375. Routine Description:
  376. This routine performs the ISR synchronized part of shutting down the
  377. miniport. This includes disabling the interrupt and request a shutdown
  378. of the miniport.
  379. Arguments:
  380. Adapter - the adapter to shut down.
  381. Return Value:
  382. TRUE
  383. --*/
  384. {
  385. SpCallAdapterControl(Adapter, ScsiStopAdapter, NULL);
  386. DebugPrint((1, "SpShutdownAdapterSynchronized: Disabling interrupts\n"));
  387. Adapter->InterruptData.InterruptFlags |= PD_DISABLE_INTERRUPTS;
  388. CLEAR_FLAG(Adapter->Flags, PD_SHUTDOWN_IN_PROGRESS);
  389. return TRUE;
  390. }