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.

1233 lines
41 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1998 - 1999
  3. Module Name:
  4. wmilib.c
  5. Abstract:
  6. WMI library utility functions for SCSI miniports
  7. CONSIDER adding the following functionality to the library:
  8. * Different instance names for different guids
  9. Author:
  10. AlanWar
  11. Environment:
  12. kernel mode only
  13. Notes:
  14. Revision History:
  15. --*/
  16. #include "miniport.h"
  17. #include "scsi.h"
  18. #include "wmistr.h"
  19. #include "scsiwmi.h"
  20. typedef enum
  21. {
  22. ScsiProcessed, // Srb was processed and possibly completed
  23. ScsiNotCompleted, // Srb was process and NOT completed
  24. ScsiNotWmi, // Srb is not a WMI irp
  25. ScsiForward // Srb is wmi irp, but targeted at another device object
  26. } SYSCTL_SCSI_DISPOSITION, *PSYSCTL_SCSI_DISPOSITION;
  27. BOOLEAN
  28. ScsiWmipFindGuid(
  29. IN PSCSIWMIGUIDREGINFO GuidList,
  30. IN ULONG GuidCount,
  31. IN LPGUID Guid,
  32. OUT PULONG GuidIndex,
  33. OUT PULONG InstanceCount
  34. );
  35. BOOLEAN
  36. ScsiWmipFindGuid(
  37. IN PSCSIWMIGUIDREGINFO GuidList,
  38. IN ULONG GuidCount,
  39. IN LPGUID Guid,
  40. OUT PULONG GuidIndex,
  41. OUT PULONG InstanceCount
  42. )
  43. /*++
  44. Routine Description:
  45. This routine will search the list of guids registered and return
  46. the index for the one that was registered.
  47. Arguments:
  48. GuidList is the list of guids to search
  49. GuidCount is the count of guids in the list
  50. Guid is the guid being searched for
  51. *GuidIndex returns the index to the guid
  52. *InstanceCount returns the count of instances for the guid
  53. Return Value:
  54. TRUE if guid is found else FALSE
  55. --*/
  56. {
  57. ULONG i;
  58. for (i = 0; i < GuidCount; i++)
  59. {
  60. if (IsEqualGUID(Guid, GuidList[i].Guid))
  61. {
  62. *GuidIndex = i;
  63. *InstanceCount = GuidList[i].InstanceCount;
  64. return(TRUE);
  65. }
  66. }
  67. return(FALSE);
  68. }
  69. UCHAR ScsiWmipPostProcess(
  70. IN UCHAR MinorFunction,
  71. IN PUCHAR Buffer,
  72. IN ULONG BufferSize,
  73. IN ULONG BufferUsed,
  74. IN UCHAR Status,
  75. OUT PULONG ReturnSize
  76. )
  77. {
  78. ULONG retSize;
  79. switch(MinorFunction)
  80. {
  81. case IRP_MN_QUERY_ALL_DATA:
  82. {
  83. PWNODE_ALL_DATA wnode;
  84. PWNODE_TOO_SMALL wnodeTooSmall;
  85. ULONG bufferNeeded;
  86. ULONG instanceCount;
  87. POFFSETINSTANCEDATAANDLENGTH offsetInstanceDataAndLength;
  88. ULONG i;
  89. PULONG instanceLengthArray;
  90. ULONG dataBlockOffset;
  91. wnode = (PWNODE_ALL_DATA)Buffer;
  92. dataBlockOffset = wnode->DataBlockOffset;
  93. instanceCount = wnode->InstanceCount;
  94. bufferNeeded = dataBlockOffset + BufferUsed;
  95. if ((Status == SRB_STATUS_SUCCESS) &&
  96. (bufferNeeded > BufferSize))
  97. {
  98. Status = SRB_STATUS_DATA_OVERRUN;
  99. }
  100. if (Status != SRB_STATUS_SUCCESS)
  101. {
  102. if (Status == SRB_STATUS_DATA_OVERRUN)
  103. {
  104. wnodeTooSmall = (PWNODE_TOO_SMALL)wnode;
  105. wnodeTooSmall->WnodeHeader.BufferSize = sizeof(WNODE_TOO_SMALL);
  106. wnodeTooSmall->WnodeHeader.Flags = WNODE_FLAG_TOO_SMALL;
  107. wnodeTooSmall->SizeNeeded = bufferNeeded;
  108. retSize = sizeof(WNODE_TOO_SMALL);
  109. Status = SRB_STATUS_SUCCESS;
  110. } else {
  111. retSize = 0;
  112. }
  113. break;
  114. }
  115. wnode->WnodeHeader.BufferSize = bufferNeeded;
  116. retSize = bufferNeeded;
  117. if ((wnode->WnodeHeader.Flags & WNODE_FLAG_STATIC_INSTANCE_NAMES) ==
  118. WNODE_FLAG_STATIC_INSTANCE_NAMES)
  119. {
  120. instanceLengthArray = (PULONG)&wnode->OffsetInstanceDataAndLength[0];
  121. offsetInstanceDataAndLength = (POFFSETINSTANCEDATAANDLENGTH)instanceLengthArray;
  122. for (i = instanceCount; i != 0; i--)
  123. {
  124. offsetInstanceDataAndLength[i-1].LengthInstanceData = instanceLengthArray[i-1];
  125. }
  126. for (i = 0; i < instanceCount; i++)
  127. {
  128. offsetInstanceDataAndLength[i].OffsetInstanceData = dataBlockOffset;
  129. dataBlockOffset = (dataBlockOffset + offsetInstanceDataAndLength[i].LengthInstanceData + 7) & ~7;
  130. }
  131. }
  132. break;
  133. }
  134. case IRP_MN_QUERY_SINGLE_INSTANCE:
  135. {
  136. PWNODE_SINGLE_INSTANCE wnode;
  137. PWNODE_TOO_SMALL wnodeTooSmall;
  138. ULONG bufferNeeded;
  139. wnode = (PWNODE_SINGLE_INSTANCE)Buffer;
  140. bufferNeeded = wnode->DataBlockOffset + BufferUsed;
  141. if (Status == SRB_STATUS_SUCCESS)
  142. {
  143. retSize = bufferNeeded;
  144. wnode->WnodeHeader.BufferSize = bufferNeeded;
  145. ASSERT(wnode->SizeDataBlock == BufferUsed);
  146. } else if (Status == SRB_STATUS_DATA_OVERRUN) {
  147. wnodeTooSmall = (PWNODE_TOO_SMALL)wnode;
  148. wnodeTooSmall->WnodeHeader.BufferSize = sizeof(WNODE_TOO_SMALL);
  149. wnodeTooSmall->WnodeHeader.Flags = WNODE_FLAG_TOO_SMALL;
  150. wnodeTooSmall->SizeNeeded = bufferNeeded;
  151. retSize = sizeof(WNODE_TOO_SMALL);
  152. Status = SRB_STATUS_SUCCESS;
  153. } else {
  154. retSize = 0;
  155. }
  156. break;
  157. }
  158. case IRP_MN_EXECUTE_METHOD:
  159. {
  160. PWNODE_METHOD_ITEM wnode;
  161. PWNODE_TOO_SMALL wnodeTooSmall;
  162. ULONG bufferNeeded;
  163. wnode = (PWNODE_METHOD_ITEM)Buffer;
  164. bufferNeeded = wnode->DataBlockOffset + BufferUsed;
  165. if (Status == SRB_STATUS_SUCCESS)
  166. {
  167. retSize = bufferNeeded;
  168. wnode->WnodeHeader.BufferSize = bufferNeeded;
  169. wnode->SizeDataBlock = BufferUsed;
  170. } else if (Status == SRB_STATUS_DATA_OVERRUN) {
  171. wnodeTooSmall = (PWNODE_TOO_SMALL)wnode;
  172. wnodeTooSmall->WnodeHeader.BufferSize = sizeof(WNODE_TOO_SMALL);
  173. wnodeTooSmall->WnodeHeader.Flags = WNODE_FLAG_TOO_SMALL;
  174. wnodeTooSmall->SizeNeeded = bufferNeeded;
  175. retSize = sizeof(WNODE_TOO_SMALL);
  176. Status = SRB_STATUS_SUCCESS;
  177. } else {
  178. retSize = 0;
  179. }
  180. break;
  181. }
  182. default:
  183. {
  184. //
  185. // All other requests don't return any data
  186. retSize = 0;
  187. break;
  188. }
  189. }
  190. *ReturnSize = retSize;
  191. return(Status);
  192. }
  193. VOID
  194. ScsiPortWmiPostProcess(
  195. IN PSCSIWMI_REQUEST_CONTEXT RequestContext,
  196. IN UCHAR Status,
  197. IN ULONG BufferUsed
  198. )
  199. {
  200. ASSERT(RequestContext != NULL);
  201. RequestContext->ReturnStatus = ScsiWmipPostProcess(
  202. RequestContext->MinorFunction,
  203. RequestContext->Buffer,
  204. RequestContext->BufferSize,
  205. BufferUsed,
  206. Status,
  207. &RequestContext->ReturnSize);
  208. }
  209. UCHAR
  210. ScsiWmipProcessRequest(
  211. IN PSCSI_WMILIB_CONTEXT WmiLibInfo,
  212. IN UCHAR MinorFunction,
  213. IN PVOID Context,
  214. IN PSCSIWMI_REQUEST_CONTEXT RequestContext,
  215. IN PVOID DataPath,
  216. IN ULONG BufferSize,
  217. IN PUCHAR Buffer,
  218. OUT PULONG ReturnSize,
  219. OUT PSYSCTL_SCSI_DISPOSITION IrpDisposition
  220. )
  221. {
  222. UCHAR status;
  223. ULONG retSize;
  224. ULONG guidIndex;
  225. ULONG instanceCount;
  226. ULONG instanceIndex;
  227. ASSERT(MinorFunction <= IRP_MN_EXECUTE_METHOD);
  228. *IrpDisposition = ScsiProcessed;
  229. if (MinorFunction != IRP_MN_REGINFO)
  230. {
  231. //
  232. // For all requests other than query registration info we are passed
  233. // a guid. Determine if the guid is one that is supported by the
  234. // device.
  235. ASSERT(WmiLibInfo->GuidList != NULL);
  236. if (ScsiWmipFindGuid(WmiLibInfo->GuidList,
  237. WmiLibInfo->GuidCount,
  238. (LPGUID)DataPath,
  239. &guidIndex,
  240. &instanceCount))
  241. {
  242. status = SRB_STATUS_SUCCESS;
  243. } else {
  244. status = SRB_STATUS_ERROR;
  245. }
  246. if ((status == SRB_STATUS_SUCCESS) &&
  247. ((MinorFunction == IRP_MN_QUERY_SINGLE_INSTANCE) ||
  248. (MinorFunction == IRP_MN_CHANGE_SINGLE_INSTANCE) ||
  249. (MinorFunction == IRP_MN_CHANGE_SINGLE_ITEM) ||
  250. (MinorFunction == IRP_MN_EXECUTE_METHOD)))
  251. {
  252. instanceIndex = ((PWNODE_SINGLE_INSTANCE)Buffer)->InstanceIndex;
  253. if ( (((PWNODE_HEADER)Buffer)->Flags) &
  254. WNODE_FLAG_STATIC_INSTANCE_NAMES)
  255. {
  256. if ( instanceIndex >= instanceCount )
  257. {
  258. status = SRB_STATUS_ERROR;
  259. }
  260. }
  261. }
  262. //
  263. // If we couldn't find the guid or the instance name index is out
  264. // of range then return an error.
  265. if (status != SRB_STATUS_SUCCESS)
  266. {
  267. *ReturnSize = 0;
  268. *IrpDisposition = ScsiNotCompleted;
  269. return(status);
  270. }
  271. }
  272. switch(MinorFunction)
  273. {
  274. case IRP_MN_REGINFO:
  275. {
  276. ULONG guidCount;
  277. PSCSIWMIGUIDREGINFO guidList;
  278. PWMIREGINFOW wmiRegInfo;
  279. PWMIREGGUIDW wmiRegGuid;
  280. PWCHAR mofResourceName;
  281. PWCHAR stringPtr;
  282. ULONG mofResourceOffset;
  283. USHORT mofResourceSize;
  284. ULONG bufferNeeded;
  285. ULONG i;
  286. USHORT nameSize;
  287. ULONG nameOffset, nameFlags;
  288. USHORT mofResourceNameLen;
  289. //
  290. // Make sure that the required parts of the WMILIB_INFO structure
  291. // are filled in.
  292. ASSERT(WmiLibInfo->QueryWmiRegInfo != NULL);
  293. ASSERT(WmiLibInfo->QueryWmiDataBlock != NULL);
  294. status = WmiLibInfo->QueryWmiRegInfo(
  295. Context,
  296. RequestContext,
  297. &mofResourceName);
  298. if (status == SRB_STATUS_SUCCESS)
  299. {
  300. ASSERT(WmiLibInfo->GuidList != NULL);
  301. guidList = WmiLibInfo->GuidList;
  302. guidCount = WmiLibInfo->GuidCount;
  303. nameOffset = sizeof(WMIREGINFO) +
  304. guidCount * sizeof(WMIREGGUIDW);
  305. nameFlags = WMIREG_FLAG_INSTANCE_BASENAME;
  306. nameSize = sizeof(L"ScsiMiniPort");
  307. mofResourceOffset = nameOffset + nameSize + sizeof(USHORT);
  308. if (mofResourceName == NULL)
  309. {
  310. mofResourceSize = 0;
  311. } else {
  312. mofResourceNameLen = 0;
  313. while (mofResourceName[mofResourceNameLen] != 0)
  314. {
  315. mofResourceNameLen++;
  316. }
  317. mofResourceSize = mofResourceNameLen * sizeof(WCHAR);
  318. }
  319. bufferNeeded = mofResourceOffset + mofResourceSize + sizeof(USHORT);
  320. if (bufferNeeded <= BufferSize)
  321. {
  322. retSize = bufferNeeded;
  323. wmiRegInfo = (PWMIREGINFO)Buffer;
  324. wmiRegInfo->BufferSize = bufferNeeded;
  325. wmiRegInfo->NextWmiRegInfo = 0;
  326. wmiRegInfo->MofResourceName = mofResourceOffset;
  327. wmiRegInfo->RegistryPath = 0;
  328. wmiRegInfo->GuidCount = guidCount;
  329. for (i = 0; i < guidCount; i++)
  330. {
  331. wmiRegGuid = &wmiRegInfo->WmiRegGuid[i];
  332. wmiRegGuid->Guid = *guidList[i].Guid;
  333. if (guidList[i].InstanceCount != 0xffffffff)
  334. {
  335. wmiRegGuid->Flags = guidList[i].Flags | nameFlags;
  336. wmiRegGuid->InstanceInfo = nameOffset;
  337. wmiRegGuid->InstanceCount = guidList[i].InstanceCount;
  338. } else {
  339. wmiRegGuid->Flags = guidList[i].Flags;
  340. wmiRegGuid->InstanceInfo = 0;
  341. wmiRegGuid->InstanceCount = 0;
  342. }
  343. }
  344. stringPtr = (PWCHAR)((PUCHAR)Buffer + nameOffset);
  345. *stringPtr++ = nameSize;
  346. ScsiPortMoveMemory(stringPtr,
  347. L"ScsiMiniPort",
  348. nameSize);
  349. stringPtr = (PWCHAR)((PUCHAR)Buffer + mofResourceOffset);
  350. *stringPtr++ = mofResourceSize;
  351. ScsiPortMoveMemory(stringPtr,
  352. mofResourceName,
  353. mofResourceSize);
  354. } else {
  355. *((PULONG)Buffer) = bufferNeeded;
  356. retSize = sizeof(ULONG);
  357. }
  358. } else {
  359. // QueryWmiRegInfo failed
  360. retSize = 0;
  361. }
  362. *ReturnSize = retSize;
  363. *IrpDisposition = ScsiNotCompleted;
  364. return(status);
  365. }
  366. case IRP_MN_QUERY_ALL_DATA:
  367. {
  368. PWNODE_ALL_DATA wnode;
  369. ULONG bufferAvail;
  370. PULONG instanceLengthArray;
  371. PUCHAR dataBuffer;
  372. ULONG instanceLengthArraySize;
  373. ULONG dataBlockOffset;
  374. wnode = (PWNODE_ALL_DATA)Buffer;
  375. if (BufferSize < sizeof(WNODE_ALL_DATA))
  376. {
  377. //
  378. // The buffer should never be smaller than the size of
  379. // WNODE_ALL_DATA, however if it is then return with an
  380. // error requesting the minimum sized buffer.
  381. ASSERT(FALSE);
  382. status = SRB_STATUS_ERROR;
  383. *IrpDisposition = ScsiNotCompleted;
  384. break;
  385. }
  386. wnode->InstanceCount = instanceCount;
  387. wnode->WnodeHeader.Flags &= ~WNODE_FLAG_FIXED_INSTANCE_SIZE;
  388. instanceLengthArraySize = instanceCount * sizeof(OFFSETINSTANCEDATAANDLENGTH);
  389. dataBlockOffset = (FIELD_OFFSET(WNODE_ALL_DATA, OffsetInstanceDataAndLength) + instanceLengthArraySize + 7) & ~7;
  390. wnode->DataBlockOffset = dataBlockOffset;
  391. if (dataBlockOffset <= BufferSize)
  392. {
  393. instanceLengthArray = (PULONG)&wnode->OffsetInstanceDataAndLength[0];
  394. dataBuffer = Buffer + dataBlockOffset;
  395. bufferAvail = BufferSize - dataBlockOffset;
  396. } else {
  397. //
  398. // There is not enough room in the WNODE to complete
  399. // the query
  400. instanceLengthArray = NULL;
  401. dataBuffer = NULL;
  402. bufferAvail = 0;
  403. }
  404. status = WmiLibInfo->QueryWmiDataBlock(
  405. Context,
  406. RequestContext,
  407. guidIndex,
  408. 0,
  409. instanceCount,
  410. instanceLengthArray,
  411. bufferAvail,
  412. dataBuffer);
  413. break;
  414. }
  415. case IRP_MN_QUERY_SINGLE_INSTANCE:
  416. {
  417. PWNODE_SINGLE_INSTANCE wnode;
  418. ULONG dataBlockOffset;
  419. wnode = (PWNODE_SINGLE_INSTANCE)Buffer;
  420. dataBlockOffset = wnode->DataBlockOffset;
  421. status = WmiLibInfo->QueryWmiDataBlock(
  422. Context,
  423. RequestContext,
  424. guidIndex,
  425. instanceIndex,
  426. 1,
  427. &wnode->SizeDataBlock,
  428. BufferSize - dataBlockOffset,
  429. (PUCHAR)wnode + dataBlockOffset);
  430. break;
  431. }
  432. case IRP_MN_CHANGE_SINGLE_INSTANCE:
  433. {
  434. PWNODE_SINGLE_INSTANCE wnode;
  435. if (WmiLibInfo->SetWmiDataBlock != NULL)
  436. {
  437. wnode = (PWNODE_SINGLE_INSTANCE)Buffer;
  438. status = WmiLibInfo->SetWmiDataBlock(
  439. Context,
  440. RequestContext,
  441. guidIndex,
  442. instanceIndex,
  443. wnode->SizeDataBlock,
  444. (PUCHAR)wnode + wnode->DataBlockOffset);
  445. } else {
  446. //
  447. // If set callback is not filled in then it must be readonly
  448. status = SRB_STATUS_ERROR;
  449. *IrpDisposition = ScsiNotCompleted;
  450. }
  451. break;
  452. }
  453. case IRP_MN_CHANGE_SINGLE_ITEM:
  454. {
  455. PWNODE_SINGLE_ITEM wnode;
  456. if (WmiLibInfo->SetWmiDataItem != NULL)
  457. {
  458. wnode = (PWNODE_SINGLE_ITEM)Buffer;
  459. status = WmiLibInfo->SetWmiDataItem(
  460. Context,
  461. RequestContext,
  462. guidIndex,
  463. instanceIndex,
  464. wnode->ItemId,
  465. wnode->SizeDataItem,
  466. (PUCHAR)wnode + wnode->DataBlockOffset);
  467. } else {
  468. //
  469. // If set callback is not filled in then it must be readonly
  470. status = SRB_STATUS_ERROR;
  471. *IrpDisposition = ScsiNotCompleted;
  472. }
  473. break;
  474. }
  475. case IRP_MN_EXECUTE_METHOD:
  476. {
  477. PWNODE_METHOD_ITEM wnode;
  478. if (WmiLibInfo->ExecuteWmiMethod != NULL)
  479. {
  480. wnode = (PWNODE_METHOD_ITEM)Buffer;
  481. status = WmiLibInfo->ExecuteWmiMethod(
  482. Context,
  483. RequestContext,
  484. guidIndex,
  485. instanceIndex,
  486. wnode->MethodId,
  487. wnode->SizeDataBlock,
  488. BufferSize - wnode->DataBlockOffset,
  489. Buffer + wnode->DataBlockOffset);
  490. } else {
  491. //
  492. // If method callback is not filled in then it must be error
  493. status = SRB_STATUS_ERROR;
  494. *IrpDisposition = ScsiNotCompleted;
  495. }
  496. break;
  497. }
  498. case IRP_MN_ENABLE_EVENTS:
  499. {
  500. if (WmiLibInfo->WmiFunctionControl != NULL)
  501. {
  502. status = WmiLibInfo->WmiFunctionControl(
  503. Context,
  504. RequestContext,
  505. guidIndex,
  506. ScsiWmiEventControl,
  507. TRUE);
  508. } else {
  509. //
  510. // If callback is not filled in then just succeed
  511. status = SRB_STATUS_SUCCESS;
  512. *IrpDisposition = ScsiNotCompleted;
  513. }
  514. break;
  515. }
  516. case IRP_MN_DISABLE_EVENTS:
  517. {
  518. if (WmiLibInfo->WmiFunctionControl != NULL)
  519. {
  520. status = WmiLibInfo->WmiFunctionControl(
  521. Context,
  522. RequestContext,
  523. guidIndex,
  524. ScsiWmiEventControl,
  525. FALSE);
  526. } else {
  527. //
  528. // If callback is not filled in then just succeed
  529. status = SRB_STATUS_SUCCESS;
  530. *IrpDisposition = ScsiNotCompleted;
  531. }
  532. break;
  533. }
  534. case IRP_MN_ENABLE_COLLECTION:
  535. {
  536. if (WmiLibInfo->WmiFunctionControl != NULL)
  537. {
  538. status = WmiLibInfo->WmiFunctionControl(
  539. Context,
  540. RequestContext,
  541. guidIndex,
  542. ScsiWmiDataBlockControl,
  543. TRUE);
  544. } else {
  545. //
  546. // If callback is not filled in then just succeed
  547. status = SRB_STATUS_SUCCESS;
  548. *IrpDisposition = ScsiNotCompleted;
  549. }
  550. break;
  551. }
  552. case IRP_MN_DISABLE_COLLECTION:
  553. {
  554. if (WmiLibInfo->WmiFunctionControl != NULL)
  555. {
  556. status = WmiLibInfo->WmiFunctionControl(
  557. Context,
  558. RequestContext,
  559. guidIndex,
  560. ScsiWmiDataBlockControl,
  561. FALSE);
  562. } else {
  563. //
  564. // If callback is not filled in then just succeed
  565. status = SRB_STATUS_SUCCESS;
  566. *IrpDisposition = ScsiNotCompleted;
  567. }
  568. break;
  569. }
  570. default:
  571. {
  572. ASSERT(FALSE);
  573. status = SRB_STATUS_ERROR;
  574. *IrpDisposition = ScsiNotCompleted;
  575. break;
  576. }
  577. }
  578. return(status);
  579. }
  580. BOOLEAN
  581. ScsiPortWmiDispatchFunction(
  582. IN PSCSI_WMILIB_CONTEXT WmiLibInfo,
  583. IN UCHAR MinorFunction,
  584. IN PVOID Context,
  585. IN PSCSIWMI_REQUEST_CONTEXT RequestContext,
  586. IN PVOID DataPath,
  587. IN ULONG BufferSize,
  588. IN PVOID Buffer
  589. )
  590. /*++
  591. Routine Description:
  592. Dispatch helper routine for WMI srb requests. Based on the Minor
  593. function passed the WMI request is processed and this routine
  594. invokes the appropriate callback in the WMILIB structure.
  595. Arguments:
  596. WmiLibInfo has the SCSI WMILIB information control block associated
  597. with the adapter or logical unit
  598. DeviceContext is miniport defined context value passed on to the callbacks
  599. invoked by this api.
  600. RequestContext is a pointer to a context structure that maintains
  601. information about this WMI srb. This request context must remain
  602. valid throughout the entire processing of the srb, at least until
  603. ScsiPortWmiPostProcess returns with the final srb return status and
  604. buffer size. If the srb can pend then memory for this buffer should
  605. be allocated from the SRB extension. If not then the memory can be
  606. allocated from a stack frame that does not go out of scope, perhaps
  607. that of the caller to this api.
  608. DataPath is value passed in wmi request
  609. BufferSize is value passed in wmi request
  610. Buffer is value passed in wmi request
  611. Return Value:
  612. TRUE if request is pending else FALSE
  613. --*/
  614. {
  615. UCHAR status;
  616. SYSCTL_SCSI_DISPOSITION irpDisposition;
  617. ULONG retSize;
  618. ASSERT(RequestContext != NULL);
  619. //
  620. // First ensure that the irp is a WMI irp
  621. if (MinorFunction > IRP_MN_EXECUTE_METHOD)
  622. {
  623. //
  624. // This is not a WMI irp, setup error return
  625. status = SRB_STATUS_ERROR;
  626. RequestContext->ReturnSize = 0;
  627. RequestContext->ReturnStatus = status;
  628. } else {
  629. //
  630. // Let SCSIWMI library have a crack at the SRB
  631. RequestContext->MinorFunction = MinorFunction;
  632. RequestContext->Buffer = Buffer;
  633. RequestContext->BufferSize = BufferSize;
  634. RequestContext->ReturnSize = 0;
  635. status = ScsiWmipProcessRequest(WmiLibInfo,
  636. MinorFunction,
  637. Context,
  638. RequestContext,
  639. DataPath,
  640. BufferSize,
  641. Buffer,
  642. &retSize,
  643. &irpDisposition);
  644. if (irpDisposition == ScsiNotCompleted)
  645. {
  646. //
  647. // Some error occured while processing the SRB, for example
  648. // guid not found. Setup the returned error
  649. RequestContext->ReturnStatus = status;
  650. if (status != SRB_STATUS_SUCCESS)
  651. {
  652. retSize = 0;
  653. }
  654. RequestContext->ReturnSize = retSize;
  655. }
  656. }
  657. return(status == SRB_STATUS_PENDING);
  658. }
  659. VOID
  660. ScsiPortWmiFireLogicalUnitEvent(
  661. IN PVOID HwDeviceExtension,
  662. IN UCHAR PathId,
  663. IN UCHAR TargetId,
  664. IN UCHAR Lun,
  665. IN LPGUID Guid,
  666. IN ULONG InstanceIndex,
  667. IN ULONG EventDataSize,
  668. IN PVOID EventData
  669. )
  670. /*++
  671. Routine Description:
  672. This routine will fire a WMI event using the data buffer passed. This
  673. routine may be called at or below DPC level
  674. Arguments:
  675. HwDeviceExtension is the adapter device extension
  676. PathId identifies the SCSI bus if a logical unit is firing the event
  677. or is 0xff if the adapter is firing the event.
  678. TargetId identifies the target controller or device on the bus
  679. Lun identifies the logical unit number of the target device
  680. Guid is pointer to the GUID that represents the event
  681. InstanceIndex is the index of the instance of the event
  682. EventDataSize is the number of bytes of data that is being fired with
  683. with the event. This size specifies the size of the event data only
  684. and does NOT include the 0x40 bytes of preceeding padding.
  685. EventData is the data that is fired with the events. There must be exactly
  686. 0x40 bytes of padding preceeding the event data.
  687. Return Value:
  688. --*/
  689. {
  690. PWNODE_SINGLE_INSTANCE event;
  691. UCHAR status;
  692. ASSERT(EventData != NULL);
  693. event = (PWNODE_SINGLE_INSTANCE)EventData;
  694. event->WnodeHeader.Guid = *Guid;
  695. event->WnodeHeader.Flags = WNODE_FLAG_SINGLE_INSTANCE |
  696. WNODE_FLAG_EVENT_ITEM |
  697. WNODE_FLAG_STATIC_INSTANCE_NAMES;
  698. event->WnodeHeader.Linkage = 0;
  699. event->InstanceIndex = InstanceIndex;
  700. event->SizeDataBlock = EventDataSize;
  701. event->DataBlockOffset = 0x40;
  702. event->WnodeHeader.BufferSize = event->DataBlockOffset +
  703. event->SizeDataBlock;
  704. if (PathId != 0xff)
  705. {
  706. ScsiPortNotification(WMIEvent,
  707. HwDeviceExtension,
  708. event,
  709. PathId,
  710. TargetId,
  711. Lun);
  712. } else {
  713. ScsiPortNotification(WMIEvent,
  714. HwDeviceExtension,
  715. event,
  716. PathId);
  717. }
  718. }
  719. PWCHAR ScsiPortWmiGetInstanceName(
  720. IN PSCSIWMI_REQUEST_CONTEXT RequestContext
  721. )
  722. /*++
  723. Routine Description:
  724. This routine will return a pointer to the instance name that was
  725. used to pass the request. If the request type is one that does not
  726. use an instance name then NULL is retuened. The instance name is a
  727. counted string.
  728. Arguments:
  729. RequestContext is a pointer to a context structure that maintains
  730. information about this WMI srb. This request context must remain
  731. valid throughout the entire processing of the srb, at least until
  732. ScsiPortWmiPostProcess returns with the final srb return status and
  733. buffer size. If the srb can pend then memory for this buffer should
  734. be allocated from the SRB extension. If not then the memory can be
  735. allocated from a stack frame that does not go out of scope, perhaps
  736. that of the caller to this api.
  737. Return Value:
  738. Pointer to instance name or NULL if no instance name is available
  739. --*/
  740. {
  741. PWCHAR p;
  742. PWNODE_SINGLE_INSTANCE Wnode;
  743. if ((RequestContext->MinorFunction == IRP_MN_QUERY_SINGLE_INSTANCE) ||
  744. (RequestContext->MinorFunction == IRP_MN_CHANGE_SINGLE_INSTANCE) ||
  745. (RequestContext->MinorFunction == IRP_MN_CHANGE_SINGLE_ITEM) ||
  746. (RequestContext->MinorFunction == IRP_MN_EXECUTE_METHOD) )
  747. {
  748. Wnode = (PWNODE_SINGLE_INSTANCE)RequestContext->Buffer;
  749. if ((Wnode->WnodeHeader.Flags & WNODE_FLAG_STATIC_INSTANCE_NAMES) == 0)
  750. {
  751. p = (PWCHAR)((PUCHAR)Wnode + Wnode->OffsetInstanceName);
  752. } else {
  753. p = NULL;
  754. }
  755. } else {
  756. p = NULL;
  757. }
  758. return(p);
  759. }
  760. BOOLEAN ScsiPortWmiSetInstanceCount(
  761. IN PSCSIWMI_REQUEST_CONTEXT RequestContext,
  762. IN ULONG InstanceCount,
  763. OUT PULONG BufferAvail,
  764. OUT PULONG SizeNeeded
  765. )
  766. /*++
  767. Routine Description:
  768. This routine will update the wnode to indicate the number of
  769. instances that will be returned by the driver. Note that the values
  770. for BufferAvail may change after this call. This routine
  771. may only be called for a WNODE_ALL_DATA. This routine must be
  772. called before calling ScsiPortWmiSetInstanceName or
  773. ScsiPortWmiSetData
  774. Arguments:
  775. RequestContext is a pointer to a context structure that maintains
  776. information about this WMI srb. This request context must remain
  777. valid throughout the entire processing of the srb, at least until
  778. ScsiPortWmiPostProcess returns with the final srb return status and
  779. buffer size. If the srb can pend then memory for this buffer should
  780. be allocated from the SRB extension. If not then the memory can be
  781. allocated from a stack frame that does not go out of scope, perhaps
  782. that of the caller to this api.
  783. InstanceCount is the number of instances to be returned by the
  784. driver.
  785. *BufferAvail returns with the number of bytes available for
  786. instance names and data in the buffer. This may be 0 if there
  787. is not enough room for all instances.
  788. *SizeNeeded returns with the number of bytes that are needed so far
  789. to build the output wnode
  790. Return Value:
  791. TRUE if successful else FALSE. If FALSE wnode is not a
  792. WNODE_ALL_DATA or does not have dynamic instance names.
  793. --*/
  794. {
  795. PWNODE_ALL_DATA wnode;
  796. ULONG bufferSize;
  797. ULONG offsetInstanceNameOffsets, dataBlockOffset, instanceLengthArraySize;
  798. ULONG bufferAvail;
  799. BOOLEAN b;
  800. ASSERT(RequestContext->MinorFunction == IRP_MN_QUERY_ALL_DATA);
  801. *SizeNeeded = 0;
  802. if (RequestContext->MinorFunction == IRP_MN_QUERY_ALL_DATA)
  803. {
  804. wnode = (PWNODE_ALL_DATA)RequestContext->Buffer;
  805. ASSERT((wnode->WnodeHeader.Flags & WNODE_FLAG_STATIC_INSTANCE_NAMES) == 0);
  806. if ((wnode->WnodeHeader.Flags & WNODE_FLAG_STATIC_INSTANCE_NAMES) == 0)
  807. {
  808. bufferSize = RequestContext->BufferSize;
  809. wnode->InstanceCount = InstanceCount;
  810. instanceLengthArraySize = InstanceCount * sizeof(OFFSETINSTANCEDATAANDLENGTH);
  811. offsetInstanceNameOffsets = FIELD_OFFSET(WNODE_ALL_DATA,
  812. OffsetInstanceDataAndLength) +
  813. instanceLengthArraySize;
  814. wnode->OffsetInstanceNameOffsets = offsetInstanceNameOffsets;
  815. dataBlockOffset = (offsetInstanceNameOffsets +
  816. (InstanceCount * sizeof(ULONG)) + 7) & ~7;
  817. wnode->DataBlockOffset = dataBlockOffset;
  818. *SizeNeeded = 0;
  819. if (dataBlockOffset <= bufferSize)
  820. {
  821. *BufferAvail = bufferSize - dataBlockOffset;
  822. memset(wnode->OffsetInstanceDataAndLength, 0,
  823. ((UCHAR)dataBlockOffset-(UCHAR)FIELD_OFFSET(WNODE_ALL_DATA,
  824. OffsetInstanceDataAndLength)));
  825. } else {
  826. //
  827. // There is not enough room in the WNODE to complete
  828. // the query
  829. //
  830. *BufferAvail = 0;
  831. }
  832. b = TRUE;
  833. } else {
  834. b = FALSE;
  835. }
  836. } else {
  837. b = FALSE;
  838. }
  839. return(b);
  840. }
  841. PWCHAR ScsiPortWmiSetInstanceName(
  842. IN PSCSIWMI_REQUEST_CONTEXT RequestContext,
  843. IN ULONG InstanceIndex,
  844. IN ULONG InstanceNameLength,
  845. OUT PULONG BufferAvail,
  846. IN OUT PULONG SizeNeeded
  847. )
  848. /*++
  849. Routine Description:
  850. This routine will update the wnode header to include the position where an
  851. instance name is to be written. Note that the values
  852. for BufferAvail may change after this call. This routine
  853. may only be called for a WNODE_ALL_DATA.
  854. Arguments:
  855. RequestContext is a pointer to a context structure that maintains
  856. information about this WMI srb. This request context must remain
  857. valid throughout the entire processing of the srb, at least until
  858. ScsiPortWmiPostProcess returns with the final srb return status and
  859. buffer size. If the srb can pend then memory for this buffer should
  860. be allocated from the SRB extension. If not then the memory can be
  861. allocated from a stack frame that does not go out of scope, perhaps
  862. that of the caller to this api.
  863. InstanceIndex is the index to the instance name being filled in
  864. InstanceNameLength is the number of bytes (including count) needed
  865. to write the instance name.
  866. *BufferAvail returns with the number of bytes available for
  867. instance names and data in the buffer. This may be 0 if there
  868. is not enough room for the instance name.
  869. *SizeNeeded on entry has the number of bytes needed so far to build
  870. the WNODE and on return has the number of bytes needed to build
  871. the wnode after including the instance name
  872. Return Value:
  873. pointer to where the instance name should be filled in. If NULL
  874. then the wnode is not a WNODE_ALL_DATA or does not have dynamic
  875. instance names
  876. --*/
  877. {
  878. PWNODE_ALL_DATA wnode;
  879. ULONG bufferSize;
  880. ULONG bufferAvail;
  881. PULONG offsetInstanceNameOffsets;
  882. ULONG pos, extra;
  883. PWCHAR p;
  884. ASSERT(RequestContext->MinorFunction == IRP_MN_QUERY_ALL_DATA);
  885. if (RequestContext->MinorFunction == IRP_MN_QUERY_ALL_DATA)
  886. {
  887. wnode = (PWNODE_ALL_DATA)RequestContext->Buffer;
  888. ASSERT((wnode->WnodeHeader.Flags & WNODE_FLAG_STATIC_INSTANCE_NAMES) == 0);
  889. if ((wnode->WnodeHeader.Flags & WNODE_FLAG_STATIC_INSTANCE_NAMES) == 0)
  890. {
  891. ASSERT(InstanceIndex < wnode->InstanceCount);
  892. pos = (*SizeNeeded + 1) &~1;
  893. //
  894. // Update the total size needed for the wnode and number of
  895. // bytes available
  896. //
  897. extra = pos - *SizeNeeded;
  898. extra += InstanceNameLength;
  899. *SizeNeeded += extra;
  900. if (*BufferAvail >= extra)
  901. {
  902. *BufferAvail -= extra;
  903. //
  904. // Fill in offset to the instance name in the wnode header
  905. //
  906. offsetInstanceNameOffsets = (PULONG)((PUCHAR)wnode +
  907. wnode->OffsetInstanceNameOffsets);
  908. offsetInstanceNameOffsets[InstanceIndex] = (ULONG)pos +(ULONG)wnode->DataBlockOffset;
  909. p = (PWCHAR)((PUCHAR)wnode + wnode->DataBlockOffset + pos);
  910. } else {
  911. *BufferAvail = 0;
  912. p = NULL;
  913. }
  914. } else {
  915. p = NULL;
  916. }
  917. } else {
  918. p = NULL;
  919. }
  920. return(p);
  921. }
  922. PVOID ScsiPortWmiSetData(
  923. IN PSCSIWMI_REQUEST_CONTEXT RequestContext,
  924. IN ULONG InstanceIndex,
  925. IN ULONG DataLength,
  926. OUT PULONG BufferAvail,
  927. IN OUT PULONG SizeNeeded
  928. )
  929. /*++
  930. Routine Description:
  931. This routine will update the wnode to indicate the position of the
  932. data for an instance that will be returned by the driver. Note that
  933. the values for BufferAvail may change after this call. This routine
  934. may only be called for a WNODE_ALL_DATA.
  935. Arguments:
  936. RequestContext is a pointer to a context structure that maintains
  937. information about this WMI srb. This request context must remain
  938. valid throughout the entire processing of the srb, at least until
  939. ScsiPortWmiPostProcess returns with the final srb return status and
  940. buffer size. If the srb can pend then memory for this buffer should
  941. be allocated from the SRB extension. If not then the memory can be
  942. allocated from a stack frame that does not go out of scope, perhaps
  943. that of the caller to this api.
  944. InstanceIndex is the index to the instance name being filled in
  945. DataLength is the number of bytes needed to write the data.
  946. *BufferAvail returns with the number of bytes available for
  947. instance names and data in the buffer. This may be 0 if there
  948. is not enough room for the data.
  949. *SizeNeeded on entry has the number of bytes needed so far to build
  950. the WNODE and on return has the number of bytes needed to build
  951. the wnode after including the data
  952. Return Value:
  953. pointer to where the data should be filled in. If NULL
  954. then the wnode is not a WNODE_ALL_DATA or does not have dynamic
  955. instance names
  956. --*/
  957. {
  958. PWNODE_ALL_DATA wnode;
  959. ULONG bufferSize;
  960. ULONG bufferAvail;
  961. POFFSETINSTANCEDATAANDLENGTH offsetInstanceDataAndLength;
  962. ULONG pos, extra;
  963. PVOID p;
  964. ASSERT(RequestContext->MinorFunction == IRP_MN_QUERY_ALL_DATA);
  965. if (RequestContext->MinorFunction == IRP_MN_QUERY_ALL_DATA)
  966. {
  967. wnode = (PWNODE_ALL_DATA)RequestContext->Buffer;
  968. ASSERT((wnode->WnodeHeader.Flags & WNODE_FLAG_STATIC_INSTANCE_NAMES) == 0);
  969. if ((wnode->WnodeHeader.Flags & WNODE_FLAG_STATIC_INSTANCE_NAMES) == 0)
  970. {
  971. ASSERT(InstanceIndex < wnode->InstanceCount);
  972. pos = (*SizeNeeded + 7) &~7;
  973. //
  974. // Update the total size needed for the wnode and number of
  975. // bytes available
  976. //
  977. extra = pos - *SizeNeeded;
  978. extra += DataLength;
  979. *SizeNeeded += extra;
  980. if (*BufferAvail >= extra)
  981. {
  982. *BufferAvail -= extra;
  983. //
  984. // Fill in offset and length to the data in the wnode header
  985. //
  986. offsetInstanceDataAndLength = (POFFSETINSTANCEDATAANDLENGTH)((PUCHAR)wnode +
  987. FIELD_OFFSET(WNODE_ALL_DATA,
  988. OffsetInstanceDataAndLength));
  989. offsetInstanceDataAndLength[InstanceIndex].OffsetInstanceData = wnode->DataBlockOffset + pos;
  990. offsetInstanceDataAndLength[InstanceIndex].LengthInstanceData = DataLength;
  991. p = (PVOID)((PUCHAR)wnode + wnode->DataBlockOffset + pos);
  992. } else {
  993. *BufferAvail = 0;
  994. }
  995. } else {
  996. p = NULL;
  997. }
  998. } else {
  999. p = NULL;
  1000. }
  1001. return(p);
  1002. }