4.2 Operational Overview

This section describes a CDM's major functional procedures and their main flow of events in the following topics:

4.2.1 Load-Time Initialization and Registration

Figure 4-1 CDM Initialization and Registration

Loading the CDM can be initiated in multiple ways: by the systems operator at the server console, by a startup file, or by INSTALL. The following steps show the sequence of events for initializing and registering a CDM at load-time.

  1. When a CDM is loaded, the OS calls the CDM's CDM_Load entry point passing it loadHandle, screenID, and commandLine as input parameters. CDM_Load is responsible to perform the following:
    1. Register the CDM module.

      The CDM registers its module by calling NPA_Register_CDM_Module. This API sets up the general environment necessary for the CDM to become operational and makes it possible for the CDM to allocate and register any resources it may need. It is within the context of NPA_Register_CDM_Module that the CDM's npaHandle is assigned a value, and that the following CDM entry points get registered with NWPA:

      CDM_Check_Option (Optional)

      CDM_Execute_CDMMessage

      CDM_Inquiry

      If a reentrant CDM supports a device under different operational states according to options specified on the command line, it should call NPA_Register_CDM_Module for each load-instance of itself.

      NPA_Register_CDM_Module accepts a CDM-generated instance number as an input parameter. The CDM should use this instance number to associate a group of command line options with its corresponding load-instance, so the CDM can distinguish which operational states go with which load-instance.

    2. (Optional: Implement if applicable) Create a select-list of desired command line options to be used with NWPA's command line parser.

      If the CDM does not support command line options or it plans to do its own command line parsing, it should ignore this step.

      Options are command line keywords that set operational states for the CDM.

      The CDM creates an options list by filling out an instance of an NPAOptionStructand calling NPA_Add_Option. During the context of NPA_Add_Option, NWPA copies the option information and constructs a select-list of valid options for the CDM. To completely build the option list, the CDM should iteratively fill out the NPAOptionStruct instance and call NPA_Add_Option for each option type it desires. Because NWPA maintains its own copy of option information in constructing the select-list, the CDM can reuse the same NPAOptionStruct instance for each call to NPA_Add_Option.

      Because the CDM does not interface directly with the hardware, it should not try to reserve hardware options such as interrupts, ports, DMA channels, etc. CDM command line options should set only operational states for the program module.

    3. (Optional: Implement if applicable) Parse the load command line for specified options.

      The CDM can either do its own parsing or use NWPA's parser. NWPA's parser is invoked by calling NPA_Parse_Options. This support routine causes NWPA to match options specified on the command line with those in the CDM's select-list. In turn, NPA_Parse_Options iteratively calls the CDM's CDM_Check_Option entry point for each match it finds. CDM_Check_Option either accepts or rejects the selected option. Each time CDM_Check_Option accepts an option, NWPA places it in a use-list. If there is an option on the command line that does not match anything in the CDM's select-list, it is ignored. However, if after parsing the command line NWPA finds residual options in the CDM's select-list, it either prompts the user for the options or discards them depending on the bits set in the flags field of each option's NPAOptionStruct.

      NOTE:Steps 1.b - 1.c describe the general paradigm for registering configuration options. For more detailed information and actual registration examples, refer to the NPAOptionStruct.

    4. Allocate memory resources.

      The CDM allocates any memory buffers it may need by calling NPA_Allocate_Memory.

    5. Prepare the CDM to accept I/O.

      The CDM must ensure that it is operational and ready to accept CDM messages before going to Step f.

    6. Activate the CDM.

      The CDM calls CDI_Register_CDM to activate itself. This API requires an exchange of handles that identify the CDM. The CDM passes a unique handle (cdmHandle) it generates to identify itself as an input parameter. Then, NWPA returns its own unique handle (cdmOSHandle) to identify the CDM as an output parameter.

    7. Return load status.

      If the CDM loaded successfully, CDM_Load should return zero. If the load was unsuccessful, it should do the following:

      Return all allocated memory by calling NPA_Return_Memory.

      Unregister all command line options by calling NPA_Unregister_Options.

      Unregister the module by calling NPA_Unregister_Module if the CDM failed its initial load instance.

      WARNING:NPA_Unregister_Module should not be called if the CDM is erroring out of the registration of only a single instance of itself, but it intends to continue supporting other instances. If it is called, all pending I/O for this CDM will be aborted. Use Instance Unload to unload a single instance (see Instance Unload for HAMs).

      Return -1.

      If at any time during initialization and registration an uncorrectable error occurs, the CDM must return its resources and back out from the point it reached. For example, if the CDM progressed as far as Step 1d in the preceding sequence, the CDM would need to return memory, unregister options if implemented, and then unregister the module.

4.2.2 Inquiring and Binding to a Device

This section covers the following topics:

The following figure shows the process and binding a CDM to a device:

Figure 4-2 Inquiring and Binding a CDM to a Device

Once the CDM is initialized and registered, NWPA calls CDM_Inquiry. This routine is blocking, and it is registered with NWPA during NPA_Register_CDM_Module. NWPA passes four arguments to CDM_Inquiry: npaDeviceID, npaBusID, a pointer to a DeviceInfoStruct instance, and flag.

The parameters npaDeviceID and npaBusID are the object IDs of the device and bus as entered in NWPA's object database. DeviceInfoStruct is a pointer to an interface-specific structure that describes the device in enough detail so that the CDM can determine the device type. The HAM is responsible for supplying this information to NWPA.

The parameter flag is an indicator telling the CDM the type of function to perform during CDM_Inquiry. It is within the context of this routine that a CDM binds to a device. Binding is where the CDM tells NWPA to route I/O for a particular device through it, and the CDM also registers the control and I/O functions that it will support for the device.

CDM_Inquiry is responsible to perform the following:

  1. Build and maintain a linked list of device objects to which the CDM is bound.
  2. Generate a unique handle (cdmBindHandle) of type LONG for each object to which the CDM is bound.
  3. Check the DeviceInfoStruct for the device information and/or perform any necessary device tests for more information necessary to determine if the CDM should bind to the device.
    1. If the CDM decides to bind to the device, create an instance of an UpdateInfoStruct structure, fill in its fields with the appropriate information found from DeviceInfoStruct, and call CDI_Bind_CDM_To_Object passing the appropriate arguments. Add the device along with its UpdateInfoStruct structure to the CDM's object list, and return zero. cdmBindHandle is used by the CDM to identify device objects in the list and to map to the object's device information. The cdmBindHandle parameter is necessary in CDI_Bind_CDM_To_Object.

      At the minimum, the following fields of a device object's UpdateInfoStruct structure must be filled in so that NWPA has enough information to be able to use the device:

      functionMask, controlMask, unitSize, blockSize, capacity, preferredUnitSize, and activateFlag

      A description of each of these fields can be found in UpdateInfoStruct.

    2. If the CDM decides not to bind to the device, it does not call CDI_Bind_CDM_To_Object, does not add the device to the linked list, and returns -1.

CDI_Bind_CDM_To_Object updates device object information and registers the functions the CDM supports for the device with NWPA. Besides being called at CDM load time, CDM_Inquiry can be called again if any of the following events occur: (For details, see the description of CDM_Inquiry.

  • A HAM registers a new device with NWPA that matches the Host Adapter Type and Device Type reported by the CDM in the types parameter of CDI_Register_CDM.
  • A HAM updates information in the DeviceInfoStruct.
  • (For Filter CDMs) A base CDM updates information about a device to which a filter CDM is also bound.
  • A device is no longer valid, and the CDM must remove the device and all of the local structures associated with this device from its list.
  • An End of Bus condition occurred during a scan for new devices. This means there are no more public devices on this bus. The CDM can then scan for specific devices not found during the normal scan. The specific devices can become public or private devices depending on the Scan function case used. For details, refer to HACB Type Zero Functions under Function 1- HAM_Scan_For_Devices (Function 0x01)
  • An End of Bus condition occurred when the bus is being deactivated (that is, when the HAM associated with the bus is being unloaded). The CDM must remove any private devices on this bus and all of the local structures associated with these devices from its list.

Updating Device Object Information

Figure 4-3 Updating Device Information

A CDM can update device information, such as the functions it will support for a device, by doing the following:

  1. Instantiate a new UpdateInfoStruct structure initialized with -1 in each field.

    This indicates that the field does not get updated, thereby maintaining its previous state from either the last update event or when the CDM originally bound to the device.

  2. Change the appropriate UpdateInfoStruct fields to the new values.
  3. Call CDI_Object_Update including the structure address and CDIBindHandle as arguments.

Function Masking

As previously mentioned, a CDM must register the functions it supports for a given device with NWPA. This section describes how this is done.

NLM applications assume a certain functionality set, and NWPA encompasses these by providing a general set of I/O and control messages that it can issue for devices. The CDM is expected to implement routines that translate these messages into actual commands recognized by a device. The way in which NWPA recognizes the I/O and control routines that a CDM supports for a device are through the respective values set in the functionMask and controlMask fields of the device object's UpdateInfoStruct. Each field is 32 bits wide, and each bit position within a field corresponds to an NWPA function. When bits within a field are set, it indicates to NWPA that the CDM supports that function. Inversely, a CDM can remove supported I/O or control functions by clearing the appropriate bits within these fields and updating the device object information. Refer to Structures for more information about the UpdateInfoStruct and its fields.

4.2.3 Processing CDM Messages

When NWPA receives an NLM application I/O request, it converts the request into a CDMMessageStruct (CDM message) data structure. The fields in this structure contain all the necessary information that a CDM needs to build a device command. NWPA routes a CDM message to the CDM that has

  1. Bound to the device NWPA wants to access.
  2. Registered the desired support function that NWPA wants to call.

After a CDM receives a CDM message, it generally performs one of the following actions:

  • Creates a SuperHACB request and executes it.
  • Places the CDM message in a process queue.
  • Chains the CDM message down to another CDM. This action only applies to filter CDMs.

The following subsections address each of these actions.

Creating and Executing a SuperHACB Request

Since most NLM application requests to NWPA are either control or I/O requests, creating and executing SuperHACB requests is the most frequent action. The following is a list of the phases involved:

  • Receiving the request and mapping to a CDM function
  • Building and executing a SuperHACB request

Figure 4-4 Processing a CDM Message

Receiving a Request and Function Mapping

A NWPA control or I/O request is first packaged into a CDMMessageStruct and then passed to a CDM. CDM_Execute_CDMMessage is the CDM's entry point for receiving a CDMMessageStruct. The main purpose of CDM_Execute_CDMMessage is to map a general NWPA control or I/O request (in the form of a CDM message) into a specific CDM function call. NWPA calls this function passing it CDMBindHandle and a pointer to a CDMMessageStruct structure. CDMBindHandle identifies the desired device and its specific information. The CDMMessageStruct structure contains the information describing the request.

NWPA control and I/O requests are equated to unique hexadecimal function codes (0x0000 - 0x003F). When NWPA makes a request, it places the appropriate function code in the function field of the CDMMessageStruct. The CDM uses this code to determine what function it is to perform. The functions are in CDM Message Control Functions and CDM Message I/O Functions.

Building and Executing a SuperHACB Request

After a NWPA request is mapped to a CDM function, the CDM function has the responsibility to build a SuperHACB and execute it. The control and I/O routines discussed in CDM Entry Points are the functions that do the building and executing. Each function accepts a CDMBindHandle and a pointer to a CDMMessageStruct as arguments.

The Control and I/O routines are responsible to perform the following:

  1. Allocate a SuperHACBStruct using CDI_Allocate_HACB.
  2. Fill in the SuperHACB fields with the appropriate information relative to the request. See Host Adapter Control Block for details on what is expected to be placed in the SuperHACB structure.
  3. Call CDI_Execute_HACB passing the appropriate arguments. One argument that is necessary is a pointer to CDM_Callback. By passing this address, NWPA ensures that the CDM is notified of the request completion by calling CDM_Callback.

4.2.4 Error Handling

This section describes the CDM's general error handling paradigm and how this paradigm is affected by auto error sense. It covers the following topics:

Auto error sense is a generic phrase describing the way in which error sense information is automatically returned with an I/O request for a given bus protocol. As an example, for SCSI and ATAPI this phrase refers to REQUEST SENSE.

Some adapter boards support this feature and others do not. The HAM, during its load-time initialization, is responsible for determining whether or not the adapter supports the feature and whether or not it is to be used. The CDM, on the other hand, must be ready to support either case. There are three fields in HACBStruct and one in the DeviceInfoStruct that provide NWPA support for auto error sense. The following is a list of these fields:

Fields in the HACBStruct:

    LONG   errorSenseBufferLength; 
    void  *vErrorSenseBufferPtr; 
    void  *pErrorSenseBufferPtr; 
    
    

Field in the DeviceInfoStruct:

    LONG attributeFlags;
    

The CDM discovers if a device is set up for auto error sense by checking the Auto_Error_Sense_Flag (0x00000040) bit in the attributeFlags field of the device's DeviceInfoStruct. If the flag is set, the device does auto error sense. If the flag is not set, the device does not do auto error sense. The CDM receives a pointer to this structure as an input parameter to its CDM_Inquiry routine. Thus, at bind-time the CDM knows the error sense mode of the device.

The following subsections describe the CDM's error handling paradigm.

Without Auto Error Sense

Error handling without auto error sense is probably the simplest case for CDMs. The paradigm is as follows:

  • For the no-auto-error-sense case, the CDM should zero out the errorSenseBufferLen and vErrorSenseBufferPtr fields of the HACB.
  • When a device error occurs, the HAM freezes that device's queue, unless the no_freeze bit is set, posts the appropriate completion code to the HACB, and then completes the HACB.

    For SCSI, a device error generates a check condition, and the appropriate completion code is 0x80010002. For IDE-ATA and SATA, the appropriate completion code is 0x80010001. Refer to HACB Completion Codes for more information.

  • The CDM receives the HACB through its callback routine, checks the completion code, and realizes that the I/O request generated a device error.
  • The CDM then spawns a blocking, error-recovery thread that issues another HACB request for error sense information. The CDM can request as much error sense information as the device and transport protocol can provide. The error sense data is retrieved under the normal HACB I/O channel, meaning that the CDM and HAM use the HACB's data buffer.
  • The CDM uses the error sense information to determine what it will attempt to do to recover from the error condition.
  • When the error condition is remedied, the CDM completes the I/O request's corresponding CDM message with a successful completion code and allows normal I/O to the device to continue. If the CDM determines that the error condition cannot be remedied, it completes the corresponding CDM message with an appropriate error code.

With Auto Error Sense

The information presented in this subsection is tightly coupled to the reference information for the ErrorSenseInfoStruct structure.

For the auto error sense case, the CDM is expected to do these additional steps in building the HACB I/O request:

  • Allocate an I/O contiguous, auto error sense buffer and assign its address to the HACB's vErrorSenseBufferPtr field.

This buffer is where the return sense information is to be placed, and its structure is defined by NWPA's ErrorSenseInfoStruct. The size of this buffer is the size of NWPA's ErrorSenseInfoStruct plus however many BYTES of auto error sense data the CDM wants returned. For more details refer to ErrorSenseInfoStruct.

Because the CDM may need a number of these error sense buffers, we suggest you allocate a pool and reuse them as needed. Also, the CDM should not be concerned with assigning anything to the HACB's pErrorSenseBufferPtr field. NWPA calculates the sense buffer's physical address and place it in this field at execute-time.

  • Place a value in the auto error sense buffer's numberBytesRequested field to indicate the desired number of sense bytes it wants the device to return.
  • Place a value in the HACB's errorSenseBufferLen field indicating the byte size of the HACB's auto error sense buffer.

At callback time [CDM_Callback], if the CDM detects a device error on the HACB request, the CDM attempts error recovery as prescribed in the previous subsection. Prior to reading the error information, the CDM should check the value in the numberBytesReturned field of the buffer, which indicates the actual number of sense bytes the device provided. Instead of issuing another HACB to request error sense, the CDM looks in the HACB's sense buffer to get the error information.

4.2.5 Registering Device Attributes

Attributes are parameters associated with a device such as unit size, block size, capacity, preferred unit size, tape read/write formats, etc. Device attributes should be registered during the context of CDM_Inquiry after the CDM has had a chance to query the device and bind to it. The CDM informs an NLM application of a device's attributes by registering them with NWPA. Also, if the device supports it, a CDM can allow an NLM application to set attributes. The following steps outline the procedure for registering device attributes.

  1. The CDM fills out an instance of an AttributeInfoStruct for each attribute it intends to register.
  2. The CDM then calls CDI_Register_Object_Attribute for each attribute in step 1. CDI_Register_Object_Attribute accepts a pointer to the AttributeInfoStruct instance associated with the attribute and pointers to the attribute's CDM_Get_Attribute and CDM_Set_Attribute routines as input parameters.

    If the attribute is not settable, then the input parameter corresponding to CDM_Set_Attribute should be set to zero.

    NWPA informs an NLM application of the data type associated with the infoBuffer parameter of these routines by the value the CDM specified in the attributeType field of the attribute's AttributeInfoStruct.

  3. Through a set of NWPA APIs, the NLM application can then get and set attributes. The following code example shows how to register a minimum block size attribute:
    /*- Prototypes of get and set routines for this attribute -*/ 
    LONG CDM_Get_Attribute( 
       LONG cdmBindHandle, 
       LONG *infoBuffer, 
       LONG infoBufferLength, 
       LONG attributeID); 
     
    LONG CDM_Set_Attribute( 
       LONG cdmBindHandle, 
       LONG *infoBuffer, 
       LONG infoBufferLength 
       LONG attributeID); 
     
    /*- Data type, AttributeID, Buffer Length definitions -*/ 
    #define MM_BYTE 0x02 
    #define MM_LONG 0x04 
    #define MIN_BLOCKSIZE 0x4E494D12 
    #define MM_BUFFERLEN 0x04 
     
    /*- Attribute Information -*/ 
    struct AttributeInfoStruct MinimumBlocksize = { 
       MIN_BLOCKSIZE,MM_LONG, 
       MM_BUFFERLEN, 
       "\x17MINIMUM_BLOCKSIZE"}; 
     
    /*- Register Attribute -*/ 
    cCode = CDI_Register_Object_Attribute( 
       NWPAHandle, 
       CDMBindHandle, 
       &MinimumBlocksize, 
       CDM_Get_Attribute, 
       CDM_Set_Attribute); 
     
    

4.2.6 Unload-Time Deregistration

The following figure shows the process of deregistering at unload time.

Figure 4-5 Deregistering at Unload Time

Unloading the CDM is initiated by the systems operator at the server console. The following steps show the sequence of events at unload-time.

  1. When a CDM is unloaded, the OS first calls the CDM's CDM_Unload_Check entry point, passing it screenID as an input parameter. CDM_Unload_Check has blocking context, and it does the following:
    1. Determines if any NLM applications are using any of the devices managed by the CDM.

      CDM_Unload_Check calls NPA_Unload_Module_Check, which checks NWPA's database and returns the status of each device attached to the adapter. CDM_Unload_Check returns the use-status returned by NPA_Unload_Module_Check.

      NPA_Unload_Module_Check issues a warning message to the console for each device that is locked. Current I/O to these devices halts if the CDM is unloaded, and the devices are deactivated.

    2. Returns the composite device status to the calling process. A return value of zero indicates that none of the CDM's devices are in use. A return value greater than zero indicates that one or more of the CDM's devices are in use.
  2. If CDM_Unload_Check returns zero, the OS calls the CDMs CDM_Unload entry point. If CDM_Unload_Check returns non-zero, the OS issues a message to the console, giving the operator a chance to either cancel or continue the unload. If the operator chooses to continue the unload, the OS calls the CDM's CDM_Unload entry point. The OS calls the CDM's CDM_Unload entry point with blocking context, and it does the following:
    1. Causes NWPA to terminate I/O to the CDM.

      CDM_Unload terminates I/O to the CDM by calling CDI_Unregister_CDM immediately upon entry. It is during the context of this API that the NLM application is notified that its link to the device is about to be severed. Therefore, the CDM must remain operational and process requests until CDI_Unregister_CDM returns control. After CDI_Unregister_CDM returns control to CDM_Unload, the CDM is guaranteed not to receive any more I/O requests for that device.

    2. Returns resources back to the system.

      Abort all outstanding AEN HACBs using CDI_Abort_HACB. If the CDM does not abort all of its outstanding AEN HACBs, it might result in a server abend.

      If the CDM is controlling any private devices, they must either be made public using Case 2 of the Scan function, or be removed using Case 3 of the Scan function. For more details, refer to HAM_Scan_For_Devices (Function 0x01)

      Cancel all asynchronous events, such as timeout handlers, and timers by calling NPA_Cancel_Thread.

      Return memory to the system pool by calling NPA_Return_Memory.

      Unregister the module using NPA_Unregister_Module.

    3. Return 0.