Designing a Miniport Driver Callback Routine that Handles WMI Classes with Methods

This section uses example WMI classes that contain WMI methods and describes what the corresponding miniport driver callback routine should look like. For more information about the miniport driver callback routine that executes WMI methods, see HwScsiWmiExecuteMethod.

The following example WMI classes contain WMI methods:

class MSFC_HBAAdapterMethods
{
    [key] 
    string InstanceName;
    boolean Active;
    [
     Implemented,
     WmiMethodId(1)
    ]
    void GetDiscoveredPortAttributes(
            [in ] uint32 PortIndex,
            [in ] uint32 DiscoveredPortIndex,
            [out, HBA_STATUS_QUALIFIERS ] HBA_STATUS HBAStatus,
            [out, HBAType("HBA_PORTATTRIBUTES") ] 
                MSFC_HBAPortAttributesResults PortAttributes
            );
    [
     Implemented,
     WmiMethodId(2)
    ]
    void GetPortAttributesByWWN(
            [in, HBAType("HBA_WWN")] uint8 wwn[8],
            [out, HBA_STATUS_QUALIFIERS ] HBA_STATUS HBAStatus,
          [out, HBAType("HBA_PORTATTRIBUTES") ] 
                MSFC_HBAPortAttributesResults PortAttributes
            );
};
class MSFC_HBAFCPInfo
{
    [key] 
    string InstanceName;
    boolean Active;
    [
     Implemented,
     WmiMethodId(1)
    ]
    void GetFcpTargetMapping(
            [in, HBAType("HBA_WWN")] uint8 HbaPortWWN[8],
            [in ] uint32 InEntryCount,
            [out, HBA_STATUS_QUALIFIERS ] HBA_STATUS HBAStatus,
            [out] uint32 TotalEntryCount,
            [out] uint32 OutEntryCount,
            [out, WmiSizeIs("OutEntryCount")] HBAFCPScsiEntry  
                 Entry[]
            );
};

The MSFC_HBAAdapterMethods class contains two methods, GetDiscoveredPortAttributes and GetPortAttributesByWWN. The MSFC_HBAFCPInfo class contains one method, GetFcpTargetMapping.

When the SCSI Port WMI library dispatch routine calls your miniport driver's execute method callback routine, it passes in a GuidIndex value that identifies the WMI class, a MethodId value that identifies the method within the class, and an InstanceIndex value that identifies which of the potential multiple instances of the class to process. The callback routine should take the appropriate action for any given combination of class, method, and class instance.

The following example shows how the execute method callback routine might handle the methods in the previous example.

HwScsiWmiExecuteMethod (
    IN PVOID Context,
    IN PSCSIWMI_REQUEST_CONTEXT DispatchContext,
    IN ULONG GuidIndex,
    IN ULONG InstanceIndex,
    IN ULONG MethodId,
    IN ULONG InBufferSize,
    IN ULONG OutBufferSize,
    IN OUT PUCHAR Buffer
    )

  switch(GuidIndex) { 
    case MSFC_HBAAdapterMethodsGuidIndex:
    {
      switch(MethodId) {
      case GetDiscoveredPortAttributes:
        // handle method here 
        Switch(InstanceIndex) {
        case 1:
          // handle instance 1
          PGetDiscoveredPortAttributes_IN In;
          PGetDiscoveredPortAttributes_OUT Out;
          // note: input and output parameters use the same buffer
          In = (PGetDiscoveredPortAttributes_IN)Buffer;
          Out = (PGetDiscoveredPortAttributes_OUT)Buffer;
          // put code for method here
          break;
        case 2:
       // handle instance 2
        default:
          break;
        }
      case GetPortAttributesByWWN:
        // handle method here 
      default:
        break;
    }
    case MSFC_HBAFCPInfoGuidIndex:
    {
      switch(MethodId) {
      case GetFcpTargetMapping:
        // handle method here 
      default:
        break;
      }
    }

The WMI tool suite (mofcomp and wmimofck) simplifies the task of writing this routine by automatically generating a binary type library and a header file that defines a symbolic constant for each WMI class GUID index and each method identifier. For more information about how to use these tools, see Compiling a Driver's MOF File and Using wmimofck.exe.

The wmimofck tool generates a .h file from the .bmf binary file generated by mofcomp. It forms the name of the symbolic constant for the class index by concatenating a suffix of "GuidIndex" to the name of the WMI class. For instance, with the MSFC_FibrePortHBAMethods class, the tool will create a symbolic constant called MSFC_FibrePortHBAMethodsGuidIndex that represents the GUID index for that class. In a similar manner, the tool will use the method name to form a symbolic constant that represents the method, but without adding any suffixes. The name of the symbolic constant for the method is simply the name of the method. In the example, the switch statement tests the value of the method identifier. Each case in the switch statement corresponds to a method name.

The MOF syntax used to define a WMI class method resembles a routine; however, a WMI method is not a routine. When the mofcomp and wmimofck tools process a method definition in the MOF file, they generate two separate C language structure declarations for the method. One structure is for the parameters that are identified in the MOF file as input parameters by an "[in]" prefix, and another structure for the parameters that are identified as output parameters by an "[out]" prefix.

The wmimofck tool forms the name of the structure that contains the method's input parameters by concatenating a suffix of "_IN" to the name of the method. For instance, if the name of the method is GetDiscoveredPortAttributes, wmimofck will automatically generate a declaration for a structure named GetDiscoveredPortAttributes_IN. Likewise, wmimofck generates a declaration for a structure named GetDiscoveredPortAttributes_OUT that holds the output parameters of the method.

The following code snippet shows how an execute method callback routine could validate the size of the input and output buffers for a method called GetDiscoveredPortAttributes in a class called MSFC_HBAPortMethods:

case MSFC_HBAPortMethodsGuidIndex:
  switch(MethodId) {
    case GetDiscoveredPortAttributes:
  {
      BOOLEAN bInputBigEnough = (InBufferSize >= 
              sizeof(GetDiscoveredPortAttributes_IN))
      BOOLEAN bOutputBigEnough = (OutBufferSize >= 
              sizeof(GetDiscoveredPortAttributes_OUT))
      if (bInputBigEnough && bOutputBigEngough) {
        PGetDiscoveredPortAttributes_IN In;
        PGetDiscoveredPortAttributes_OUT Out;

        In = (PGetDiscoveredPortAttributes_IN)Buffer;
         Out = (PGetDiscoveredPortAttributes_OUT)Buffer;
        // 
        // process method here
      //
        status = SRB_STATUS_SUCCESS;
      } else {
        status = SRB_STATUS_DATA_OVERRUN;
      }
    }

Before returning, your callback routine should call ScsiPortWmiPostProcess. This SCSI Port WMI library routine updates the request context with information, such as the status of the request and the size of the return data. For more information about the information that is stored in the request context, see SCSIWMI_REQUEST_CONTEXT.