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.

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