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.

1864 lines
55 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1997 - 1999
  3. Module Name:
  4. wmi.c
  5. Abstract:
  6. This module contains the WMI support code for SCSIPORT's functional and
  7. physical device objects.
  8. Authors:
  9. Dan Markarian
  10. Environment:
  11. Kernel mode only.
  12. Notes:
  13. None.
  14. Revision History:
  15. 19-Mar-1997, Original Writing, Dan Markarian
  16. --*/
  17. #include "port.h"
  18. #define __FILE_ID__ 'wmi '
  19. #if DBG
  20. static const char *__file__ = __FILE__;
  21. #endif
  22. #ifdef ALLOC_PRAGMA
  23. #pragma alloc_text(PAGE, ScsiPortSystemControlIrp)
  24. #pragma alloc_text(PAGE, SpWmiIrpNormalRequest)
  25. #pragma alloc_text(PAGE, SpWmiIrpRegisterRequest)
  26. #pragma alloc_text(PAGE, SpWmiHandleOnMiniPortBehalf)
  27. #pragma alloc_text(PAGE, SpWmiPassToMiniPort)
  28. #pragma alloc_text(PAGE, SpWmiDestroySpRegInfo)
  29. #pragma alloc_text(PAGE, SpWmiGetSpRegInfo)
  30. #pragma alloc_text(PAGE, SpWmiInitializeSpRegInfo)
  31. #pragma alloc_text(PAGE, SpWmiInitializeFreeRequestList)
  32. #pragma alloc_text(PAGE, SpAdapterConfiguredForSenseDataEvents)
  33. #pragma alloc_text(PAGE, SpInitAdapterWmiRegInfo)
  34. #endif
  35. #define SP_WMI_EVENT 1
  36. NTSTATUS
  37. ScsiPortSystemControlIrp(
  38. PDEVICE_OBJECT DeviceObject,
  39. PIRP Irp
  40. )
  41. /*++
  42. Routine Description:
  43. Process an IRP_MJ_SYSTEM_CONTROL request packet.
  44. Arguments:
  45. DeviceObject - Pointer to the functional or physical device object.
  46. Irp - Pointer to the request packet.
  47. Return Value:
  48. NTSTATUS result code.
  49. --*/
  50. {
  51. PCOMMON_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  52. PIO_STACK_LOCATION irpSp;
  53. NTSTATUS status = STATUS_SUCCESS;
  54. WMI_PARAMETERS wmiParameters;
  55. ULONG isRemoved;
  56. PAGED_CODE();
  57. isRemoved = SpAcquireRemoveLock(DeviceObject, Irp);
  58. if (isRemoved) {
  59. Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
  60. SpReleaseRemoveLock(DeviceObject, Irp);
  61. SpCompleteRequest(DeviceObject, Irp, NULL, IO_NO_INCREMENT);
  62. return STATUS_DEVICE_DOES_NOT_EXIST;
  63. }
  64. //
  65. // Obtain a pointer to the current IRP stack location.
  66. //
  67. irpSp = IoGetCurrentIrpStackLocation(Irp);
  68. ASSERT(irpSp->MajorFunction == IRP_MJ_SYSTEM_CONTROL);
  69. //
  70. // Determine if this WMI request was destined to us. If not, pass the IRP
  71. // down.
  72. //
  73. if ( (PDEVICE_OBJECT)irpSp->Parameters.WMI.ProviderId == DeviceObject) {
  74. BOOLEAN forwardDown = FALSE;
  75. DebugPrint((SP_WMI_EVENT, "ScsiPortSystemControlIrp: MinorFunction %x\n",
  76. irpSp->MinorFunction));
  77. //
  78. // Copy the WMI parameters into our local WMISRB structure.
  79. //
  80. wmiParameters.ProviderId = irpSp->Parameters.WMI.ProviderId;
  81. wmiParameters.DataPath = irpSp->Parameters.WMI.DataPath;
  82. wmiParameters.Buffer = irpSp->Parameters.WMI.Buffer;
  83. wmiParameters.BufferSize = irpSp->Parameters.WMI.BufferSize;
  84. //
  85. // Determine what the WMI request wants of us.
  86. //
  87. switch (irpSp->MinorFunction) {
  88. case IRP_MN_QUERY_ALL_DATA:
  89. //
  90. // Query for all instances of a data block.
  91. //
  92. case IRP_MN_QUERY_SINGLE_INSTANCE:
  93. //
  94. // Query for a single instance of a data block.
  95. //
  96. case IRP_MN_CHANGE_SINGLE_INSTANCE:
  97. //
  98. // Change all data items in a data block for a single instance.
  99. //
  100. case IRP_MN_CHANGE_SINGLE_ITEM:
  101. //
  102. // Change a single data item in a data block for a single instance.
  103. //
  104. case IRP_MN_ENABLE_EVENTS:
  105. //
  106. // Enable events.
  107. //
  108. case IRP_MN_DISABLE_EVENTS:
  109. //
  110. // Disable events.
  111. //
  112. case IRP_MN_ENABLE_COLLECTION:
  113. //
  114. // Enable data collection for the given GUID.
  115. //
  116. case IRP_MN_DISABLE_COLLECTION:
  117. //
  118. // Disable data collection for the given GUID.
  119. //
  120. status = SpWmiIrpNormalRequest(DeviceObject,
  121. irpSp->MinorFunction,
  122. &wmiParameters);
  123. break;
  124. case IRP_MN_EXECUTE_METHOD:
  125. //
  126. // Execute method
  127. //
  128. status = SpWmiIrpNormalRequest(DeviceObject,
  129. irpSp->MinorFunction,
  130. &wmiParameters);
  131. break;
  132. case IRP_MN_REGINFO:
  133. //
  134. // Query for registration and registration update information.
  135. //
  136. status = SpWmiIrpRegisterRequest(DeviceObject, &wmiParameters);
  137. break;
  138. default:
  139. //
  140. // Unsupported WMI request. According to some rule in the WMI
  141. // spec we're supposed to send unsupported WMI requests down
  142. // the stack even if we're marked as the provider.
  143. //
  144. forwardDown = TRUE;
  145. break;
  146. }
  147. if(forwardDown == FALSE) {
  148. //
  149. // Complete this WMI IRP request.
  150. //
  151. Irp->IoStatus.Status = status;
  152. Irp->IoStatus.Information= (NT_SUCCESS(status) ?
  153. wmiParameters.BufferSize : 0);
  154. SpReleaseRemoveLock(DeviceObject, Irp);
  155. SpCompleteRequest(DeviceObject, Irp, NULL, IO_NO_INCREMENT);
  156. return status;
  157. }
  158. }
  159. //
  160. // Request should be forwarded down the stack. If we're a pdo that means
  161. // we should complete it as is.
  162. //
  163. SpReleaseRemoveLock(DeviceObject, Irp);
  164. if(commonExtension->IsPdo) {
  165. //
  166. // Get the current status out of the irp.
  167. //
  168. status = Irp->IoStatus.Status;
  169. //
  170. // Complete the irp.
  171. //
  172. SpCompleteRequest(DeviceObject, Irp, NULL, IO_NO_INCREMENT);
  173. } else {
  174. //
  175. // Copy parameters from our stack location to the next stack location.
  176. //
  177. IoCopyCurrentIrpStackLocationToNext(Irp);
  178. //
  179. // Pass the IRP on to the next driver.
  180. //
  181. status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
  182. }
  183. return status;
  184. }
  185. NTSTATUS
  186. SpWmiIrpNormalRequest(
  187. IN PDEVICE_OBJECT DeviceObject,
  188. IN UCHAR WmiMinorCode,
  189. IN OUT PWMI_PARAMETERS WmiParameters
  190. )
  191. /*++
  192. Routine Description:
  193. Process an IRP_MJ_SYSTEM_CONTROL request packet (for all requests except registration
  194. IRP_MN_REGINFO requests).
  195. Arguments:
  196. DeviceObject - Pointer to the functional or physical device object.
  197. WmiMinorCode - WMI action to perform.
  198. WmiParameters - Pointer to the WMI request parameters.
  199. Return Value:
  200. NTSTATUS result code to complete the WMI IRP with.
  201. Notes:
  202. If this WMI request is completed with STATUS_SUCCESS, the WmiParameters
  203. BufferSize field will reflect the actual size of the WMI return buffer.
  204. --*/
  205. {
  206. PCOMMON_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  207. NTSTATUS status = STATUS_SUCCESS;
  208. PAGED_CODE();
  209. //
  210. // Determine if SCSIPORT will repond to this WMI request on behalf of
  211. // the miniport driver.
  212. //
  213. status = SpWmiHandleOnMiniPortBehalf(DeviceObject,
  214. WmiMinorCode,
  215. WmiParameters);
  216. //
  217. // If not, pass the request onto the miniport driver, provided the
  218. // miniport driver does support WMI.
  219. //
  220. if (status == STATUS_WMI_GUID_NOT_FOUND &&
  221. commonExtension->WmiMiniPortSupport) {
  222. //
  223. // Send off the WMI request to the miniport.
  224. //
  225. status = SpWmiPassToMiniPort(DeviceObject,
  226. WmiMinorCode,
  227. WmiParameters);
  228. if (NT_SUCCESS(status)) {
  229. //
  230. // Fill in fields miniport cannot fill in for itself.
  231. //
  232. if ( WmiMinorCode == IRP_MN_QUERY_ALL_DATA ||
  233. WmiMinorCode == IRP_MN_QUERY_SINGLE_INSTANCE ) {
  234. PWNODE_HEADER wnodeHeader = WmiParameters->Buffer;
  235. ASSERT( WmiParameters->BufferSize >= sizeof(WNODE_HEADER) );
  236. KeQuerySystemTime(&wnodeHeader->TimeStamp);
  237. }
  238. } else {
  239. //
  240. // Translate SRB status into a meaningful NTSTATUS status.
  241. //
  242. status = STATUS_INVALID_DEVICE_REQUEST;
  243. }
  244. }
  245. return status;
  246. }
  247. NTSTATUS
  248. SpWmiIrpRegisterRequest(
  249. IN PDEVICE_OBJECT DeviceObject,
  250. IN OUT PWMI_PARAMETERS WmiParameters
  251. )
  252. /*++
  253. Routine Description:
  254. Process an IRP_MJ_SYSTEM_CONTROL registration request.
  255. Arguments:
  256. DeviceObject - Pointer to the functional or physical device object.
  257. WmiParameters - Pointer to the WMI request parameters.
  258. Return Value:
  259. NTSTATUS result code to complete the WMI IRP with.
  260. Notes:
  261. If this WMI request is completed with STATUS_SUCCESS, the WmiParameters
  262. BufferSize field will reflect the actual size of the WMI return buffer.
  263. --*/
  264. {
  265. PCOMMON_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  266. PSCSIPORT_DRIVER_EXTENSION driverExtension = NULL;
  267. ULONG countedRegistryPathSize = 0;
  268. ULONG retSz;
  269. PWMIREGINFO spWmiRegInfoBuf;
  270. ULONG spWmiRegInfoBufSize;
  271. NTSTATUS status = STATUS_SUCCESS;
  272. BOOLEAN wmiUpdateRequest;
  273. ULONG i;
  274. PDEVICE_OBJECT pDO;
  275. WMI_PARAMETERS paranoidBackup = *WmiParameters;
  276. PAGED_CODE();
  277. DebugPrint((SP_WMI_EVENT, "SpWmiRegisterRequest: DO %p WMIParams %p\n",
  278. DeviceObject, WmiParameters));
  279. //
  280. // Validate our assumptions for this function's code.
  281. //
  282. ASSERT(WmiParameters->BufferSize >= sizeof(ULONG));
  283. //
  284. // Validate the registration mode.
  285. //
  286. switch ( (ULONG)(ULONG_PTR)WmiParameters->DataPath ) {
  287. case WMIUPDATE:
  288. //
  289. // No SCSIPORT registration information will be piggybacked
  290. // on behalf of the miniport for a WMIUPDATE request.
  291. //
  292. wmiUpdateRequest = TRUE;
  293. break;
  294. case WMIREGISTER:
  295. wmiUpdateRequest = FALSE;
  296. break;
  297. default:
  298. //
  299. // Unsupported registration mode.
  300. //
  301. ASSERT(FALSE);
  302. return STATUS_INVALID_PARAMETER;
  303. }
  304. //
  305. // Obtain the driver extension for this miniport (FDO/PDO).
  306. //
  307. driverExtension = IoGetDriverObjectExtension(DeviceObject->DriverObject,
  308. ScsiPortInitialize);
  309. ASSERT(driverExtension != NULL);
  310. //
  311. // Make Prefix Happy -- we'll quit if
  312. // driverExtension is NULL
  313. //
  314. if (driverExtension == NULL) {
  315. return (STATUS_UNSUCCESSFUL);
  316. }
  317. //
  318. // Obtain a pointer to the SCSIPORT WMI registration information
  319. // buffer, which is registered on behalf of the miniport driver.
  320. //
  321. SpWmiGetSpRegInfo(DeviceObject, &spWmiRegInfoBuf,
  322. &spWmiRegInfoBufSize);
  323. DebugPrint((SP_WMI_EVENT, "SpWmiIrpRegisterRequest: spWmiRegInfoBuf %p SpWmiReginfoBufSize %d\n",
  324. spWmiRegInfoBuf, spWmiRegInfoBufSize));
  325. //
  326. // Pass the WMI registration request to the miniport. This is not
  327. // necessary if we know the miniport driver does not support WMI.
  328. //
  329. if (commonExtension->WmiMiniPortSupport == TRUE &&
  330. (commonExtension->WmiMiniPortInitialized == TRUE ||
  331. commonExtension->IsPdo == TRUE)) {
  332. DebugPrint((SP_WMI_EVENT, "SpWmiIrpRegisterRequest: add miniport data\n"));
  333. //
  334. // Note that we shrink the buffer size by the size necessary
  335. // to hold SCSIPORT's own registration information, which we
  336. // register on behalf of the miniport. This information is
  337. // piggybacked into the WMI return buffer after the call to
  338. // the miniport. We ensure that the BufferSize passed to the
  339. // miniport is no smaller than "sizeof(ULONG)" so that it can
  340. // tell us the required buffer size should the buffer be too
  341. // small [by filling in this ULONG].
  342. //
  343. // Note that we must also make enough room for a copy of the
  344. // miniport registry path in the buffer, since the WMIREGINFO
  345. // structures from the miniport DO NOT set their registry
  346. // path fields.
  347. //
  348. if (WmiParameters->BufferSize < sizeof(ULONG)) {
  349. return STATUS_INVALID_PARAMETER;
  350. }
  351. //
  352. // Calculate size of required miniport registry path.
  353. //
  354. countedRegistryPathSize = driverExtension->RegistryPath.Length
  355. + sizeof(USHORT);
  356. //
  357. // Shrink buffer by the appropriate size. Note that the extra
  358. // 7 bytes (possibly extraneous) is subtracted to ensure that
  359. // the piggybacked data added later on is 8-byte aligned (if
  360. // any).
  361. //
  362. if (spWmiRegInfoBufSize && !wmiUpdateRequest) {
  363. WmiParameters->BufferSize =
  364. (WmiParameters->BufferSize > spWmiRegInfoBufSize + countedRegistryPathSize + 7 + sizeof(ULONG)) ?
  365. WmiParameters->BufferSize - spWmiRegInfoBufSize - countedRegistryPathSize - 7 :
  366. sizeof(ULONG);
  367. } else { // no data to piggyback
  368. WmiParameters->BufferSize =
  369. (WmiParameters->BufferSize > countedRegistryPathSize + sizeof(ULONG)) ?
  370. WmiParameters->BufferSize - countedRegistryPathSize :
  371. sizeof(ULONG);
  372. }
  373. //
  374. // Call the minidriver.
  375. //
  376. status = SpWmiPassToMiniPort(DeviceObject,
  377. IRP_MN_REGINFO,
  378. WmiParameters);
  379. ASSERT(WmiParameters->ProviderId == paranoidBackup.ProviderId);
  380. ASSERT(WmiParameters->DataPath == paranoidBackup.DataPath);
  381. ASSERT(WmiParameters->Buffer == paranoidBackup.Buffer);
  382. ASSERT(WmiParameters->BufferSize <= paranoidBackup.BufferSize);
  383. //
  384. // Assign WmiParameters->BufferSize to retSz temporarily.
  385. //
  386. // Note that on return from the above call, the wmiParameters'
  387. // BufferSize field has been _modified_ to reflect the current
  388. // size of the return buffer.
  389. //
  390. retSz = WmiParameters->BufferSize;
  391. } else if (WmiParameters->BufferSize < spWmiRegInfoBufSize &&
  392. !wmiUpdateRequest) {
  393. //
  394. // Insufficient space to hold SCSIPORT WMI registration information
  395. // alone. Inform WMI appropriately of the required buffer size.
  396. //
  397. *((ULONG*)WmiParameters->Buffer) = spWmiRegInfoBufSize;
  398. WmiParameters->BufferSize = sizeof(ULONG);
  399. return STATUS_SUCCESS;
  400. } else { // no miniport support for WMI, sufficient space for scsiport info
  401. //
  402. // Fake having the miniport return zero WMIREGINFO structures.
  403. //
  404. retSz = 0;
  405. }
  406. //
  407. // Piggyback SCSIPORT's registration information into the WMI
  408. // registration buffer.
  409. //
  410. if ((status == STATUS_BUFFER_TOO_SMALL) ||
  411. (NT_SUCCESS(status) && (retSz == sizeof(ULONG)))) {
  412. //
  413. // Miniport could not fit registration information into the
  414. // pre-shrunk buffer.
  415. //
  416. // Buffer currently contains a ULONG specifying required buffer
  417. // size of miniport registration info, but does not include the
  418. // SCSIPORT registration info's size. Add it in.
  419. //
  420. if (spWmiRegInfoBufSize && !wmiUpdateRequest) {
  421. *((ULONG*)WmiParameters->Buffer) += spWmiRegInfoBufSize;
  422. //
  423. // Add an extra 7 bytes (possibly extraneous) which is used to
  424. // ensure that the piggybacked data structure 8-byte aligned.
  425. //
  426. *((ULONG*)WmiParameters->Buffer) += 7;
  427. }
  428. //
  429. // Add in size of the miniport registry path.
  430. //
  431. *((ULONG*)WmiParameters->Buffer) += countedRegistryPathSize;
  432. //
  433. // Return STATUS_SUCCESS, even though this is a BUFFER TOO
  434. // SMALL failure, while ensuring retSz = sizeof(ULONG), as
  435. // the WMI protocol calls us to do.
  436. //
  437. retSz = sizeof(ULONG);
  438. status = STATUS_SUCCESS;
  439. } else if ( NT_SUCCESS(status) ) {
  440. DebugPrint((SP_WMI_EVENT, "SpWmiIrpRegisterRequest: add scsiport stuff...\n"));
  441. //
  442. // Zero or more WMIREGINFOs exist in buffer from miniport.
  443. //
  444. //
  445. // Piggyback the miniport registry path transparently, if at least one
  446. // WMIREGINFO was returned by the minport.
  447. //
  448. if (retSz) {
  449. ULONG offsetToRegPath = retSz;
  450. PWMIREGINFO wmiRegInfo = WmiParameters->Buffer;
  451. DebugPrint((SP_WMI_EVENT, "SpWmiIrpRegisterRequest: piggybacking...\n"));
  452. //
  453. // Build a counted wide-character string, containing the
  454. // registry path, into the WMI buffer.
  455. //
  456. *( (PUSHORT)( (PUCHAR)WmiParameters->Buffer + retSz ) ) =
  457. driverExtension->RegistryPath.Length,
  458. RtlCopyMemory( (PUCHAR)WmiParameters->Buffer + retSz + sizeof(USHORT),
  459. driverExtension->RegistryPath.Buffer,
  460. driverExtension->RegistryPath.Length);
  461. //
  462. // Traverse the WMIREGINFO structures returned by the mini-
  463. // driver and set the missing RegistryPath fields to point
  464. // to our registry path location. We also jam in the PDO for
  465. // the device stack so that the device instance name is used for
  466. // the wmi instance names.
  467. //
  468. pDO = commonExtension->IsPdo ? DeviceObject :
  469. ((PADAPTER_EXTENSION)commonExtension)->LowerPdo;
  470. while (1) {
  471. wmiRegInfo->RegistryPath = offsetToRegPath;
  472. for (i = 0; i < wmiRegInfo->GuidCount; i++)
  473. {
  474. if ((wmiRegInfo->WmiRegGuid[i].Flags & (WMIREG_FLAG_INSTANCE_BASENAME |
  475. WMIREG_FLAG_INSTANCE_LIST)) != 0)
  476. {
  477. wmiRegInfo->WmiRegGuid[i].InstanceInfo = (ULONG_PTR)pDO;
  478. wmiRegInfo->WmiRegGuid[i].Flags &= ~(WMIREG_FLAG_INSTANCE_BASENAME |
  479. WMIREG_FLAG_INSTANCE_LIST);
  480. wmiRegInfo->WmiRegGuid[i].Flags |= WMIREG_FLAG_INSTANCE_PDO;
  481. }
  482. }
  483. if (wmiRegInfo->NextWmiRegInfo == 0) {
  484. break;
  485. }
  486. offsetToRegPath -= wmiRegInfo->NextWmiRegInfo;
  487. wmiRegInfo = (PWMIREGINFO)( (PUCHAR)wmiRegInfo +
  488. wmiRegInfo->NextWmiRegInfo );
  489. }
  490. //
  491. // Adjust retSz to reflect new size of the WMI buffer.
  492. //
  493. retSz += countedRegistryPathSize;
  494. wmiRegInfo->BufferSize = retSz;
  495. } // else, no WMIREGINFOs registered whatsoever, nothing to piggyback
  496. //
  497. // Do we have any SCSIPORT WMIREGINFOs to piggyback?
  498. //
  499. if (spWmiRegInfoBufSize && !wmiUpdateRequest) {
  500. //
  501. // Adjust retSz so that the data we piggyback is 8-byte aligned
  502. // (safe if retSz = 0).
  503. //
  504. retSz = (retSz + 7) & ~7;
  505. //
  506. // Piggyback SCSIPORT's registration info into the buffer.
  507. //
  508. RtlCopyMemory( (PUCHAR)WmiParameters->Buffer + retSz,
  509. spWmiRegInfoBuf,
  510. spWmiRegInfoBufSize);
  511. //
  512. // Was at least one WMIREGINFO returned by the minidriver?
  513. // Otherwise, we have nothing else to add to the WMI buffer.
  514. //
  515. if (retSz) { // at least one WMIREGINFO returned by minidriver
  516. PWMIREGINFO wmiRegInfo = WmiParameters->Buffer;
  517. //
  518. // Traverse to the end of the WMIREGINFO structures returned
  519. // by the miniport.
  520. //
  521. while (wmiRegInfo->NextWmiRegInfo) {
  522. wmiRegInfo = (PWMIREGINFO)( (PUCHAR)wmiRegInfo +
  523. wmiRegInfo->NextWmiRegInfo );
  524. }
  525. //
  526. // Chain minidriver's WMIREGINFO structures to SCSIPORT's
  527. // WMIREGINFO structures.
  528. //
  529. wmiRegInfo->NextWmiRegInfo = retSz -
  530. (ULONG)((PUCHAR)wmiRegInfo - (PUCHAR)WmiParameters->Buffer);
  531. }
  532. //
  533. // Adjust retSz to reflect new size of the WMI buffer.
  534. //
  535. retSz += spWmiRegInfoBufSize;
  536. } // we had SCSIPORT REGINFO data to piggyback
  537. } // else, unknown error, complete IRP with this error status
  538. //
  539. // Save new buffer size to WmiParameters->BufferSize.
  540. //
  541. WmiParameters->BufferSize = retSz;
  542. DebugPrint((SP_WMI_EVENT, "SpWmiIrpRegisterRequest: done status %08x WMIParams %p\n",
  543. status, WmiParameters));
  544. return status;
  545. }
  546. NTSTATUS
  547. SpWmiHandleOnMiniPortBehalf(
  548. IN PDEVICE_OBJECT DeviceObject,
  549. IN UCHAR WmiMinorCode,
  550. IN OUT PWMI_PARAMETERS WmiParameters
  551. )
  552. /*++
  553. Routine Description:
  554. Handle the WMI request on the miniport's behalf, if possible.
  555. Arguments:
  556. DeviceObject - Pointer to the functional or physical device object.
  557. WmiMinorCode - WMI action to perform.
  558. WmiParameters - WMI parameters.
  559. Return Value:
  560. If STATUS_UNSUCCESSFUL is returned, SCSIPORT did not handle this WMI
  561. request. It must be passed on to the miniport driver for processing.
  562. Otherwise, this function returns an NTSTATUS code describing the result
  563. of handling the WMI request. Complete the IRP with this status.
  564. Notes:
  565. If this WMI request is completed with STATUS_SUCCESS, the WmiParameters
  566. BufferSize field will reflect the actual size of the WMI return buffer.
  567. --*/
  568. {
  569. PCOMMON_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  570. PAGED_CODE();
  571. if (commonExtension->IsPdo) {
  572. //
  573. /// Placeholder for code to check if this is a PDO-relevant GUID which
  574. // SCSIPORT must handle, and handle it if so.
  575. //
  576. } else { // FDO
  577. NTSTATUS status;
  578. GUID guid = *(GUID*)WmiParameters->DataPath;
  579. PADAPTER_EXTENSION Adapter = (PADAPTER_EXTENSION) commonExtension;
  580. SIZE_T size;
  581. DebugPrint((SP_WMI_EVENT, "SpWmiHandleOnMiniPortBehalf: WmiMinorCode:%x guid:"
  582. "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
  583. WmiMinorCode,
  584. guid.Data1,
  585. guid.Data2,
  586. guid.Data3,
  587. guid.Data4[0],
  588. guid.Data4[1],
  589. guid.Data4[2],
  590. guid.Data4[3],
  591. guid.Data4[4],
  592. guid.Data4[5],
  593. guid.Data4[6],
  594. guid.Data4[7]));
  595. //
  596. // Check the guid to verify that it represents a data block supported
  597. // by scsiport. If it does not, we return failure and let the
  598. // miniports have a look at it.
  599. //
  600. size = RtlCompareMemory(&guid,
  601. &Adapter->SenseDataEventClass,
  602. sizeof(GUID));
  603. if (size != sizeof(GUID)) {
  604. //
  605. // WMI spec says to fail the irp w/ STATUS_WMI_GUID_NOT_FOUND if the
  606. // guid does not represent a data block we understand.
  607. //
  608. DebugPrint((SP_WMI_EVENT, "SpWmiHandleOnMiniPortBehalf: not handling data block\n"));
  609. return STATUS_WMI_GUID_NOT_FOUND;
  610. }
  611. //
  612. // Handle the request. At this point, we've decided that the IRP
  613. // is intended for this device and that this is a datablock
  614. // supported by the device. Therefore, the code below returns the
  615. // appropriate result as per the wmi spec.
  616. //
  617. switch (WmiMinorCode) {
  618. case IRP_MN_QUERY_ALL_DATA:
  619. case IRP_MN_QUERY_SINGLE_INSTANCE:
  620. case IRP_MN_CHANGE_SINGLE_INSTANCE:
  621. case IRP_MN_CHANGE_SINGLE_ITEM:
  622. case IRP_MN_ENABLE_COLLECTION:
  623. case IRP_MN_DISABLE_COLLECTION:
  624. case IRP_MN_REGINFO:
  625. case IRP_MN_EXECUTE_METHOD:
  626. status = STATUS_INVALID_DEVICE_REQUEST;
  627. break;
  628. case IRP_MN_ENABLE_EVENTS:
  629. DebugPrint((SP_WMI_EVENT, "SenseData event enabled\n"));
  630. Adapter->EnableSenseDataEvent = TRUE;
  631. WmiParameters->BufferSize = 0;
  632. status = STATUS_SUCCESS;
  633. break;
  634. case IRP_MN_DISABLE_EVENTS:
  635. DebugPrint((SP_WMI_EVENT, "SenseData event disabled\n"));
  636. Adapter->EnableSenseDataEvent = FALSE;
  637. WmiParameters->BufferSize = 0;
  638. status = STATUS_SUCCESS;
  639. break;
  640. default:
  641. status = STATUS_INVALID_DEVICE_REQUEST;
  642. break;
  643. };
  644. return status;
  645. }
  646. return STATUS_WMI_GUID_NOT_FOUND;
  647. }
  648. NTSTATUS
  649. SpWmiPassToMiniPort(
  650. IN PDEVICE_OBJECT DeviceObject,
  651. IN UCHAR WmiMinorCode,
  652. IN OUT PWMI_PARAMETERS WmiParameters
  653. )
  654. /*++
  655. Routine Description:
  656. This function pass a WMI request to the miniport driver for processing.
  657. It creates an SRB which is processed normally by the port driver. This
  658. call is synchronous.
  659. Callers of SpWmiPassToMiniPort must be running at IRQL PASSIVE_LEVEL.
  660. Arguments:
  661. DeviceObject - Pointer to the functional or physical device object.
  662. WmiMinorCode - WMI action to perform.
  663. WmiParameters - WMI parameters.
  664. Return Value:
  665. An NTSTATUS code describing the result of handling the WMI request.
  666. Complete the IRP with this status.
  667. Notes:
  668. If this WMI request is completed with STATUS_SUCCESS, the WmiParameters
  669. BufferSize field will reflect the actual size of the WMI return buffer.
  670. --*/
  671. {
  672. PCOMMON_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  673. PADAPTER_EXTENSION fdoExtension;
  674. SCSI_WMI_REQUEST_BLOCK srb;
  675. LARGE_INTEGER startingOffset;
  676. PLOGICAL_UNIT_EXTENSION logicalUnit;
  677. ULONG commonBufferSize;
  678. PUCHAR commonBuffer;
  679. PHYSICAL_ADDRESS physicalAddress;
  680. PVOID removeTag = (PVOID)((ULONG_PTR)WmiParameters+3);
  681. PWNODE_HEADER wnode;
  682. NTSTATUS status;
  683. PAGED_CODE();
  684. startingOffset.QuadPart = (LONGLONG) 1;
  685. //
  686. // Zero out the SRB.
  687. //
  688. RtlZeroMemory(&srb, sizeof(SCSI_WMI_REQUEST_BLOCK));
  689. //
  690. // Initialize the SRB for a WMI request.
  691. //
  692. if (commonExtension->IsPdo) { // [PDO]
  693. //
  694. // Set the logical unit addressing from this PDO's device extension.
  695. //
  696. logicalUnit = DeviceObject->DeviceExtension;
  697. SpAcquireRemoveLock(DeviceObject, removeTag);
  698. srb.PathId = logicalUnit->PathId;
  699. srb.TargetId = logicalUnit->TargetId;
  700. srb.Lun = logicalUnit->Lun;
  701. fdoExtension = logicalUnit->AdapterExtension;
  702. } else { // [FDO]
  703. //
  704. // Set the logical unit addressing to the first logical unit. This is
  705. // merely used for addressing purposes for adapter requests only.
  706. // NOTE: SpFindSafeLogicalUnit will acquire the remove lock
  707. //
  708. logicalUnit = SpFindSafeLogicalUnit(DeviceObject,
  709. 0xff,
  710. removeTag);
  711. if (logicalUnit == NULL) {
  712. return(STATUS_DEVICE_DOES_NOT_EXIST);
  713. }
  714. fdoExtension = DeviceObject->DeviceExtension;
  715. srb.WMIFlags = SRB_WMI_FLAGS_ADAPTER_REQUEST;
  716. srb.PathId = logicalUnit->PathId;
  717. srb.TargetId = logicalUnit->TargetId;
  718. srb.Lun = logicalUnit->Lun;
  719. }
  720. //
  721. // HACK - allocate a chunk of common buffer for the actual request to
  722. // get processed in. We need to determine the size of buffer to allocate
  723. // this is the larger of the input or output buffers
  724. //
  725. if (WmiMinorCode == IRP_MN_EXECUTE_METHOD)
  726. {
  727. wnode = (PWNODE_HEADER)WmiParameters->Buffer;
  728. commonBufferSize = (WmiParameters->BufferSize > wnode->BufferSize) ?
  729. WmiParameters->BufferSize :
  730. wnode->BufferSize;
  731. } else {
  732. commonBufferSize = WmiParameters->BufferSize;
  733. }
  734. commonBuffer = AllocateCommonBuffer(fdoExtension->DmaAdapterObject,
  735. commonBufferSize,
  736. &physicalAddress,
  737. FALSE);
  738. if(commonBuffer == NULL) {
  739. DebugPrint((SP_WMI_EVENT, "SpWmiPassToMiniPort: Unable to allocate %#x bytes of "
  740. "common buffer\n", commonBufferSize));
  741. SpReleaseRemoveLock(logicalUnit->DeviceObject, removeTag);
  742. return STATUS_INSUFFICIENT_RESOURCES;
  743. }
  744. try {
  745. KEVENT event;
  746. PIRP irp;
  747. PMDL mdl;
  748. PIO_STACK_LOCATION irpStack;
  749. RtlCopyMemory(commonBuffer, WmiParameters->Buffer, commonBufferSize);
  750. srb.DataBuffer = commonBuffer; // [already non-paged]
  751. srb.DataTransferLength = WmiParameters->BufferSize;
  752. srb.Function = SRB_FUNCTION_WMI;
  753. srb.Length = sizeof(SCSI_REQUEST_BLOCK);
  754. srb.WMISubFunction = WmiMinorCode;
  755. srb.DataPath = WmiParameters->DataPath;
  756. srb.SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_NO_QUEUE_FREEZE;
  757. srb.TimeOutValue = 10; // [ten seconds]
  758. //
  759. // Note that the value in DataBuffer may be used regardless of the value
  760. // of the MapBuffers field.
  761. //
  762. //
  763. // Initialize the notification event.
  764. //
  765. KeInitializeEvent(&event, NotificationEvent, FALSE);
  766. //
  767. // Build IRP for this request.
  768. // Note we do this synchronously for two reasons. If it was done
  769. // asynchonously then the completion code would have to make a special
  770. // check to deallocate the buffer. Second if a completion routine were
  771. // used then an additional IRP stack location would be needed.
  772. //
  773. irp = SpAllocateIrp(logicalUnit->DeviceObject->StackSize, FALSE, DeviceObject->DriverObject);
  774. if(irp == NULL) {
  775. status = STATUS_INSUFFICIENT_RESOURCES;
  776. leave;
  777. }
  778. mdl = SpAllocateMdl(commonBuffer,
  779. WmiParameters->BufferSize,
  780. FALSE,
  781. FALSE,
  782. irp,
  783. DeviceObject->DriverObject);
  784. if(mdl == NULL) {
  785. IoFreeIrp(irp);
  786. status = STATUS_INSUFFICIENT_RESOURCES;
  787. leave;
  788. }
  789. MmBuildMdlForNonPagedPool(mdl);
  790. srb.OriginalRequest = irp;
  791. irpStack = IoGetNextIrpStackLocation(irp);
  792. //
  793. // Set major code.
  794. //
  795. irpStack->MajorFunction = IRP_MJ_SCSI;
  796. //
  797. // Set SRB pointer.
  798. //
  799. irpStack->Parameters.Scsi.Srb = (PSCSI_REQUEST_BLOCK)&srb;
  800. //
  801. // Setup a completion routine so we know when the request has completed.
  802. //
  803. IoSetCompletionRoutine(irp,
  804. SpSignalCompletion,
  805. &event,
  806. TRUE,
  807. TRUE,
  808. TRUE);
  809. //
  810. // Flush the data buffer for output. This will insure that the data is
  811. // written back to memory. Since the data-in flag is the the port driver
  812. // will flush the data again for input which will ensure the data is not
  813. // in the cache.
  814. //
  815. KeFlushIoBuffers(irp->MdlAddress, FALSE, TRUE);
  816. //
  817. // Call port driver to handle this request.
  818. //
  819. IoCallDriver(logicalUnit->CommonExtension.DeviceObject, irp);
  820. //
  821. // Wait for request to complete.
  822. //
  823. KeWaitForSingleObject(&event,
  824. Executive,
  825. KernelMode,
  826. FALSE,
  827. NULL);
  828. status = irp->IoStatus.Status;
  829. //
  830. // Relay the return buffer's size to the caller on success.
  831. //
  832. if (NT_SUCCESS(status)) {
  833. WmiParameters->BufferSize = srb.DataTransferLength;
  834. }
  835. //
  836. // Copy back the correct number of bytes into the caller provided buffer.
  837. //
  838. RtlCopyMemory(WmiParameters->Buffer,
  839. commonBuffer,
  840. WmiParameters->BufferSize);
  841. //
  842. // Free the irp and MDL.
  843. //
  844. IoFreeMdl(mdl);
  845. IoFreeIrp(irp);
  846. } finally {
  847. FreeCommonBuffer(fdoExtension->DmaAdapterObject,
  848. commonBufferSize,
  849. physicalAddress,
  850. commonBuffer,
  851. FALSE);
  852. SpReleaseRemoveLock(logicalUnit->CommonExtension.DeviceObject,
  853. removeTag);
  854. }
  855. //
  856. // Return the IRP's status.
  857. //
  858. return status;
  859. }
  860. VOID
  861. SpWmiGetSpRegInfo(
  862. IN PDEVICE_OBJECT DeviceObject,
  863. OUT PWMIREGINFO * SpRegInfoBuf,
  864. OUT ULONG * SpRegInfoBufSize
  865. )
  866. /*++
  867. Routine Description:
  868. This function retrieves a pointer to the WMI registration information
  869. buffer for the given device object.
  870. Arguments:
  871. DeviceObject - Pointer to the functional or physical device object.
  872. Return Values:
  873. SpRegInfoBuf - Pointer to the registration information buffer, which
  874. will point to the WMIREGINFO structures that SCSIPORT
  875. should register on behalf of the miniport driver.
  876. SpRegInfoBufSize - Size of the registration information buffer in bytes.
  877. --*/
  878. {
  879. PCOMMON_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  880. PAGED_CODE();
  881. //
  882. // Retrieve a pointer to the WMI registration information buffer for the
  883. // given device object.
  884. //
  885. if (commonExtension->WmiScsiPortRegInfoBuf == NULL ||
  886. commonExtension->WmiScsiPortRegInfoBufSize == 0) {
  887. *SpRegInfoBuf = NULL;
  888. *SpRegInfoBufSize = 0;
  889. } else {
  890. *SpRegInfoBuf = commonExtension->WmiScsiPortRegInfoBuf;
  891. *SpRegInfoBufSize = commonExtension->WmiScsiPortRegInfoBufSize;
  892. }
  893. return;
  894. }
  895. VOID
  896. SpWmiInitializeSpRegInfo(
  897. IN PDEVICE_OBJECT DeviceObject
  898. )
  899. /*++
  900. Routine Description:
  901. This function allocates space for and builds the WMI registration
  902. information buffer for this device object.
  903. The WMI registration information consists of zero or more WMIREGINFO
  904. structures which are used to register and identify SCSIPORT-handled
  905. WMI GUIDs on behalf of the miniport driver. This information is not
  906. the complete set of WMI GUIDs supported by for device object, only
  907. the ones supported by SCSIPORT. It is actually piggybacked onto the
  908. WMIREGINFO structures provided by the miniport driver during
  909. registration.
  910. The WMI registration information is allocated and stored on a
  911. per-device basis because, concievably, each device may support
  912. differing WMI GUIDs and/or instances during its lifetime.
  913. Arguments:
  914. DeviceObject - Pointer to the functional or physical device object.
  915. Return Value:
  916. None.
  917. --*/
  918. {
  919. PCOMMON_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  920. PAGED_CODE();
  921. ASSERT(commonExtension->WmiScsiPortRegInfoBuf == NULL);
  922. ASSERT(commonExtension->WmiScsiPortRegInfoBufSize == 0);
  923. if (commonExtension->IsPdo) {
  924. //
  925. /// Placeholder for code to build PDO-relevant GUIDs into the
  926. // registration buffer.
  927. //
  928. /// commonExtension->WmiScsiPortRegInfo = ExAllocatePool( PagedPool, <size> );
  929. // commonExtension->WmiScsiPortRegInfoSize = <size>;
  930. // <code to fill in wmireginfo struct(s) into buffer>
  931. //
  932. // * use L"SCSIPORT" as the RegistryPath
  933. } else { // FDO
  934. BOOLEAN DoesSenseEvents;
  935. GUID SenseDataClass;
  936. //
  937. // Determine if the supplied adapter is configured to generate sense
  938. // data events. If it is, copy the guid into the adapter extension
  939. // and initialize the WMIREGINFO structure pointed to by the
  940. // adapter extension.
  941. //
  942. DoesSenseEvents = SpAdapterConfiguredForSenseDataEvents(
  943. DeviceObject,
  944. &SenseDataClass);
  945. if (DoesSenseEvents) {
  946. ((PADAPTER_EXTENSION)commonExtension)->SenseDataEventClass = SenseDataClass;
  947. SpInitAdapterWmiRegInfo(DeviceObject);
  948. }
  949. }
  950. return;
  951. }
  952. VOID
  953. SpWmiDestroySpRegInfo(
  954. IN PDEVICE_OBJECT DeviceObject
  955. )
  956. /*++
  957. Routine Description:
  958. This function de-allocates the space for the WMI registration information
  959. buffer for this device object, if one exists.
  960. Arguments:
  961. DeviceObject - Pointer to the functional or physical device object.
  962. Return Value:
  963. None.
  964. --*/
  965. {
  966. PCOMMON_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  967. PAGED_CODE();
  968. if (commonExtension->WmiScsiPortRegInfoBuf) {
  969. ExFreePool(commonExtension->WmiScsiPortRegInfoBuf);
  970. commonExtension->WmiScsiPortRegInfoBuf = NULL;
  971. }
  972. commonExtension->WmiScsiPortRegInfoBufSize = 0;
  973. return;
  974. }
  975. NTSTATUS
  976. SpWmiInitializeFreeRequestList(
  977. IN PDEVICE_OBJECT DeviceObject,
  978. IN ULONG NumberOfItems
  979. )
  980. /*++
  981. Routine Description:
  982. Call that initializes the WmiFreeMiniPortRequestList, this call MUST
  983. be completed prior to any manipulatio of the WmiFreeMiniPortRequestList
  984. The list will be initialized with at most the number of cells requested.
  985. If the list has already been initialized, we raise the watermark by the number
  986. of Items requested.
  987. Arguments:
  988. DeviceObject - Device Object that this list belongs to
  989. NumberOfItems - requested number of free cells
  990. Return Value:
  991. Return the SUCESS if list was initialized succesfully
  992. STATUS_INSUFFICIENT_REOSOURCES - Indicates that we could not allocate
  993. enough memory for the list header
  994. Notes:
  995. --*/
  996. {
  997. PADAPTER_EXTENSION fdoExtension;
  998. ULONG itemsInserted;
  999. KIRQL oldIrql;
  1000. PAGED_CODE(); // Routine is paged until locked down.
  1001. //
  1002. // Obtain a pointer to the functional device extension (for the adapter).
  1003. //
  1004. if ( ((PCOMMON_EXTENSION)DeviceObject->DeviceExtension)->IsPdo ) {
  1005. fdoExtension = ((PLOGICAL_UNIT_EXTENSION)DeviceObject->DeviceExtension)
  1006. ->AdapterExtension;
  1007. } else {
  1008. fdoExtension = DeviceObject->DeviceExtension;
  1009. }
  1010. // If the list has been initalized increase the watermark
  1011. if (fdoExtension->WmiFreeMiniPortRequestInitialized) {
  1012. DebugPrint((SP_WMI_EVENT, "SpWmiInitializeFreeRequestList:"
  1013. " Increased watermark for : %p\n", fdoExtension));
  1014. InterlockedExchangeAdd
  1015. (&(fdoExtension->WmiFreeMiniPortRequestWatermark),
  1016. NumberOfItems);
  1017. while (fdoExtension->WmiFreeMiniPortRequestCount <
  1018. fdoExtension->WmiFreeMiniPortRequestWatermark) {
  1019. // Add free cells until the count reaches the watermark
  1020. SpWmiPushFreeRequestItem(fdoExtension);
  1021. }
  1022. return (STATUS_SUCCESS);
  1023. }
  1024. // Only FDO's should be calling when the list has not been initialized
  1025. ASSERT_FDO(DeviceObject);
  1026. // Assignt he list we just initialized to the pointer in the
  1027. // fdoExtension (and save the lock pointer also)
  1028. KeInitializeSpinLock(&(fdoExtension->WmiFreeMiniPortRequestLock));
  1029. ExInitializeSListHead(&(fdoExtension->WmiFreeMiniPortRequestList));
  1030. DebugPrint((SP_WMI_EVENT, "SpWmiInitializeFreeRequestList:"
  1031. " Initialized WmiFreeRequestList for: %p\n", fdoExtension));
  1032. // Set the initialized flag
  1033. fdoExtension->WmiFreeMiniPortRequestInitialized = TRUE;
  1034. // Set the watermark, and the count to 0
  1035. fdoExtension->WmiFreeMiniPortRequestWatermark = 0;
  1036. fdoExtension->WmiFreeMiniPortRequestCount = 0;
  1037. // Attempt to add free cells to the free list
  1038. for (itemsInserted = 0; itemsInserted < NumberOfItems;
  1039. itemsInserted++) {
  1040. // Make a request to push a NULL item, so that the
  1041. // allocation will be done by the next function
  1042. //
  1043. // At this point we don't care about the return value
  1044. // because after we set the watermark, scsiport's free-cell
  1045. // repopulation code will try to get the free list cell count
  1046. // back to the watermark. (So if we fail to add all the requested
  1047. // free cells, the repopulation code will attempt again for us
  1048. // at a later time)
  1049. SpWmiPushFreeRequestItem(fdoExtension);
  1050. }
  1051. // Now set the watermark to the correct value
  1052. fdoExtension->WmiFreeMiniPortRequestWatermark = NumberOfItems;
  1053. return(STATUS_SUCCESS);
  1054. }
  1055. VOID
  1056. SpWmiPushExistingFreeRequestItem(
  1057. IN PADAPTER_EXTENSION Adapter,
  1058. IN PWMI_MINIPORT_REQUEST_ITEM WmiRequestItem
  1059. )
  1060. /*++
  1061. Routine Description:
  1062. Inserts the entry into the interlocked list of free request items.
  1063. Arguments:
  1064. WmiRequestItem - Pointer to the request item to insert into the free list.
  1065. Return Value:
  1066. VOID
  1067. --*/
  1068. {
  1069. //
  1070. // The WMI request list must be initialized.
  1071. //
  1072. if (!Adapter->WmiFreeMiniPortRequestInitialized) {
  1073. ASSERT(FALSE);
  1074. return;
  1075. }
  1076. //
  1077. // This request doesn't point to another one.
  1078. //
  1079. WmiRequestItem->NextRequest = NULL;
  1080. //
  1081. // Insert Cell into interlocked list.
  1082. //
  1083. ExInterlockedPushEntrySList(
  1084. &(Adapter->WmiFreeMiniPortRequestList),
  1085. (PSLIST_ENTRY)WmiRequestItem,
  1086. &(Adapter->WmiFreeMiniPortRequestLock));
  1087. //
  1088. // Increment the value of the free count.
  1089. //
  1090. InterlockedIncrement(&(Adapter->WmiFreeMiniPortRequestCount));
  1091. }
  1092. NTSTATUS
  1093. SpWmiPushFreeRequestItem(
  1094. IN PADAPTER_EXTENSION fdoExtension
  1095. )
  1096. /*++
  1097. Routine Description:
  1098. Inserts the Entry into the interlocked SLIST. (Of Free items)
  1099. Arguments:
  1100. fdoExtension - The extension on the adapter
  1101. Return Value:
  1102. STATUS_SUCESS - If succesful
  1103. STATUS_INSUFFICIENT_RESOURCES - If memory allocation fails
  1104. STATUS_UNSUCCESSFUL - Free List not initialized
  1105. Notes:
  1106. This code cannot be marked as pageable since it will be called from
  1107. DPC level
  1108. Theoricatlly this call can fail, but no one should call this function
  1109. before we've been initialized
  1110. --*/
  1111. {
  1112. PWMI_MINIPORT_REQUEST_ITEM Entry = NULL;
  1113. if (!fdoExtension->WmiFreeMiniPortRequestInitialized) {
  1114. return (STATUS_UNSUCCESSFUL);
  1115. }
  1116. Entry = SpAllocatePool(NonPagedPool,
  1117. sizeof(WMI_MINIPORT_REQUEST_ITEM),
  1118. SCSIPORT_TAG_WMI_EVENT,
  1119. fdoExtension->DeviceObject->DriverObject);
  1120. if (!Entry) {
  1121. return(STATUS_INSUFFICIENT_RESOURCES);
  1122. }
  1123. Entry->NextRequest = NULL;
  1124. // Insert Cell into interlocked list
  1125. ExInterlockedPushEntrySList(
  1126. &(fdoExtension->WmiFreeMiniPortRequestList),
  1127. (PSLIST_ENTRY)Entry,
  1128. &(fdoExtension->WmiFreeMiniPortRequestLock));
  1129. // Increment the value of the free count
  1130. InterlockedIncrement(&(fdoExtension->WmiFreeMiniPortRequestCount));
  1131. return(STATUS_SUCCESS);
  1132. }
  1133. PWMI_MINIPORT_REQUEST_ITEM
  1134. SpWmiPopFreeRequestItem(
  1135. IN PADAPTER_EXTENSION fdoExtension
  1136. )
  1137. /*++
  1138. Routine Description:
  1139. Pops an Entry from the interlocked SLIST. (Of Free items)
  1140. Arguments:
  1141. fdoExtension - The extension on the adapter
  1142. Return Value:
  1143. A pointer to a REQUEST_ITEM or NULL if none are available
  1144. Notes:
  1145. This code cannot be paged, it will be called a DIRLQL
  1146. --*/
  1147. {
  1148. PWMI_MINIPORT_REQUEST_ITEM requestItem;
  1149. if (!fdoExtension->WmiFreeMiniPortRequestInitialized) {
  1150. return (NULL);
  1151. }
  1152. // Pop Cell from interlocked list
  1153. requestItem = (PWMI_MINIPORT_REQUEST_ITEM)
  1154. ExInterlockedPopEntrySList(
  1155. &(fdoExtension->WmiFreeMiniPortRequestList),
  1156. &(fdoExtension->WmiFreeMiniPortRequestLock));
  1157. if (requestItem) {
  1158. // Decrement the count of free cells
  1159. InterlockedDecrement(&(fdoExtension->WmiFreeMiniPortRequestCount));
  1160. }
  1161. return (requestItem);
  1162. }
  1163. BOOLEAN
  1164. SpWmiRemoveFreeMiniPortRequestItems(
  1165. IN PADAPTER_EXTENSION fdoExtension
  1166. )
  1167. /*++
  1168. Routine Description:
  1169. This function removes WMI_MINIPORT_REQUEST_ITEM structures from the "free"
  1170. queue of the adapter extension.
  1171. It removed all the free cells.
  1172. Arguments:
  1173. fdoExtension - The device_extension
  1174. Return Value:
  1175. TRUE always.
  1176. --*/
  1177. {
  1178. PWMI_MINIPORT_REQUEST_ITEM tmpRequestItem;
  1179. PWMI_MINIPORT_REQUEST_ITEM wmiRequestItem;
  1180. //
  1181. // Set the watermark to 0
  1182. // No need to grab a lock we're just setting it
  1183. fdoExtension->WmiFreeMiniPortRequestWatermark = 0;
  1184. DebugPrint((SP_WMI_EVENT, "SpWmiRemoveFreeMiniPortRequestItems: Removing %p", fdoExtension));
  1185. //
  1186. // Walk the queue of items and de-allocate as many as we need to.
  1187. //
  1188. for (;;) {
  1189. // Pop
  1190. wmiRequestItem = SpWmiPopFreeRequestItem(fdoExtension);
  1191. if (wmiRequestItem == NULL) {
  1192. break;
  1193. } else {
  1194. ExFreePool(wmiRequestItem);
  1195. }
  1196. }
  1197. return TRUE;
  1198. }
  1199. const GUID GUID_NULL = { 0 };
  1200. BOOLEAN
  1201. SpAdapterConfiguredForSenseDataEvents(
  1202. IN PDEVICE_OBJECT DeviceObject,
  1203. OUT GUID *SenseDataClass
  1204. )
  1205. /*++
  1206. Routine Description:
  1207. This function answers whether a specified device is configured to generate
  1208. sense data events. This is determined by the presense of a string value
  1209. containing the GUID for the event class responsible for generating the
  1210. events.
  1211. Arguments:
  1212. DeviceObject - Points to the device object
  1213. SenseDataClass - Points to a GUID into which the sense data class,
  1214. if found, is copied. If none is found, GUID_NULL is
  1215. copied into the location.
  1216. If the function's return value is FALSE, SenseDataClass
  1217. will be set to GUID_NULL.
  1218. Return Value:
  1219. Answers TRUE if a GUID is registed for the device. Otherwise, returns
  1220. FALSE.
  1221. --*/
  1222. {
  1223. NTSTATUS status;
  1224. PADAPTER_EXTENSION adapterExtension = DeviceObject->DeviceExtension;
  1225. HANDLE instanceHandle = NULL;
  1226. HANDLE handle = NULL;
  1227. RTL_QUERY_REGISTRY_TABLE queryTable[2];
  1228. UNICODE_STRING unicodeString;
  1229. UNICODE_STRING stringValue;
  1230. OBJECT_ATTRIBUTES objectAttributes;
  1231. //
  1232. // Initialize the guid pointed to by SenseDataClass to GUID_NULL.
  1233. //
  1234. *SenseDataClass = GUID_NULL;
  1235. //
  1236. // If this isn't a pnp device, don't attempt to determine
  1237. // if it supports sense data events. Just return FALSE.
  1238. //
  1239. if (!adapterExtension->IsPnp) {
  1240. return FALSE;
  1241. }
  1242. //
  1243. // Open the device registry key.
  1244. //
  1245. status = IoOpenDeviceRegistryKey(adapterExtension->LowerPdo,
  1246. PLUGPLAY_REGKEY_DEVICE,
  1247. KEY_ALL_ACCESS,
  1248. &instanceHandle);
  1249. if (!NT_SUCCESS(status)) {
  1250. return FALSE;
  1251. }
  1252. //
  1253. // Open the scsiport subkey under the device's Device Parameters key.
  1254. //
  1255. RtlInitUnicodeString(&unicodeString, L"Scsiport");
  1256. InitializeObjectAttributes(
  1257. &objectAttributes,
  1258. &unicodeString,
  1259. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  1260. instanceHandle,
  1261. NULL);
  1262. status = ZwOpenKey(&handle,
  1263. KEY_READ,
  1264. &objectAttributes);
  1265. if (!NT_SUCCESS(status)) {
  1266. goto cleanup;
  1267. }
  1268. //
  1269. // Read the device's sense data class guid. We have to initialize the
  1270. // maximum size of the string and init the buffer to NULL so
  1271. // RtlQueryRegistryValues will allocate a buffer for us. If the specified
  1272. // value is not in the registry, the query will fail
  1273. //
  1274. stringValue.MaximumLength = 40;
  1275. stringValue.Buffer = NULL;
  1276. RtlZeroMemory(queryTable, sizeof(queryTable));
  1277. queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
  1278. queryTable[0].Name = L"SenseDataEventClass";
  1279. queryTable[0].EntryContext = &stringValue;
  1280. status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE | RTL_REGISTRY_OPTIONAL,
  1281. (PWSTR) handle,
  1282. queryTable,
  1283. NULL,
  1284. NULL);
  1285. if (!NT_SUCCESS(status)) {
  1286. goto cleanup;
  1287. }
  1288. //
  1289. // Convert the registry string to a GUID.
  1290. //
  1291. ASSERT(stringValue.Buffer);
  1292. status = RtlGUIDFromString(&stringValue, SenseDataClass);
  1293. ExFreePool(stringValue.Buffer);
  1294. cleanup:
  1295. if(handle != NULL) {
  1296. ZwClose(handle);
  1297. }
  1298. ASSERT(instanceHandle != NULL);
  1299. ZwClose(instanceHandle);
  1300. return (NT_SUCCESS(status)) ? TRUE : FALSE;
  1301. }
  1302. NTSTATUS
  1303. SpInitAdapterWmiRegInfo(
  1304. IN PDEVICE_OBJECT DeviceObject
  1305. )
  1306. /*++
  1307. Routine Description:
  1308. This function initializes a the WMIREGINFO structure pointed to by the
  1309. specified device's extension. This structure will be used later
  1310. to register scsiport to handle WMI IRPs on behalf of the device.
  1311. Arguments:
  1312. DeviceObject - The device object
  1313. Return Value:
  1314. STATUS_SUCCESS
  1315. STATUS_INSUFFICIENT_RESOURCES
  1316. --*/
  1317. {
  1318. ULONG TotalSize;
  1319. PWMIREGINFO TempInfo;
  1320. PWCHAR TempString;
  1321. ULONG OffsetToRegPath;
  1322. ULONG OffsetToRsrcName;
  1323. PADAPTER_EXTENSION adapterExtension = DeviceObject->DeviceExtension;
  1324. PCOMMON_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  1325. //
  1326. // The registry path name follows the WMIREGINFO struct and the
  1327. // contiguous array of WMIREGGUIDW structs.
  1328. //
  1329. OffsetToRegPath = sizeof(WMIREGINFO) + sizeof(WMIREGGUIDW);
  1330. //
  1331. // The name of the resource follows the registry path name and
  1332. // its size.
  1333. //
  1334. OffsetToRsrcName = OffsetToRegPath +
  1335. sizeof(WCHAR) +
  1336. sizeof(SPMOFREGISTRYPATH);
  1337. //
  1338. // The total size of the block of memory we need to allocate is the size
  1339. // of the WMIREGINFO struct, plus the size of however many WMIREGGUIDW
  1340. // structs we need, plus the size of the registry path and and resource
  1341. // name strings. The size is aligned on an 8 byte boundary.
  1342. //
  1343. TotalSize = OffsetToRsrcName +
  1344. sizeof(WCHAR) +
  1345. sizeof(SPMOFRESOURCENAME);
  1346. TotalSize = (TotalSize + 7) & ~7;
  1347. //
  1348. // Try to allocate the memory.
  1349. //
  1350. TempInfo = SpAllocatePool(NonPagedPool,
  1351. TotalSize,
  1352. SCSIPORT_TAG_WMI_EVENT,
  1353. DeviceObject->DriverObject);
  1354. if (TempInfo == NULL) {
  1355. return STATUS_INSUFFICIENT_RESOURCES;
  1356. }
  1357. //
  1358. // Initialize the WMIREGINFO struct.
  1359. //
  1360. TempInfo->BufferSize = TotalSize;
  1361. TempInfo->NextWmiRegInfo = 0;
  1362. TempInfo->RegistryPath = OffsetToRegPath;
  1363. TempInfo->MofResourceName = OffsetToRsrcName;
  1364. TempString = (PWCHAR)((ULONG_PTR)TempInfo + OffsetToRegPath);
  1365. *TempString++ = sizeof(SPMOFREGISTRYPATH);
  1366. RtlCopyMemory(TempString,
  1367. SPMOFREGISTRYPATH,
  1368. sizeof(SPMOFREGISTRYPATH));
  1369. TempString = (PWCHAR)((ULONG_PTR)TempInfo + OffsetToRsrcName);
  1370. *TempString++ = sizeof(SPMOFRESOURCENAME);
  1371. RtlCopyMemory(TempString,
  1372. SPMOFRESOURCENAME,
  1373. sizeof(SPMOFRESOURCENAME));
  1374. TempInfo->GuidCount = 1;
  1375. TempInfo->WmiRegGuid[0].Guid = adapterExtension->SenseDataEventClass;
  1376. TempInfo->WmiRegGuid[0].Flags =
  1377. WMIREG_FLAG_INSTANCE_PDO | WMIREG_FLAG_EVENT_ONLY_GUID;
  1378. TempInfo->WmiRegGuid[0].InstanceCount = 1;
  1379. //
  1380. // This must be a physical device object.
  1381. //
  1382. TempInfo->WmiRegGuid[0].Pdo = (ULONG_PTR) adapterExtension->LowerPdo;
  1383. //
  1384. // Update the common extension members.
  1385. //
  1386. commonExtension->WmiScsiPortRegInfoBuf = TempInfo;
  1387. commonExtension->WmiScsiPortRegInfoBufSize = TotalSize;
  1388. DebugPrint((SP_WMI_EVENT, "SpInitAdapterWmiRegInfo: commonExtension %p "
  1389. "WmiScsiPortRegInfoBuf %p WmiScsiPortRegInfoBufSize %x\n",
  1390. commonExtension,
  1391. commonExtension->WmiScsiPortRegInfoBuf,
  1392. commonExtension->WmiScsiPortRegInfoBufSize));
  1393. return STATUS_SUCCESS;
  1394. }