I am sponsoring the following fasttrack for myself.  Micro/patch
binding is requested. The timer is set to expire on Dec. 17 2008.

-Chris


1. Introduction
    1.1. Project/Component Working Name:
         ddi_ssoft_state(9F) and ddi_isoft_state(9F)
    1.2. Name of Document Author/Supplier:
         Author: Chris Horne
    1.3. Date of This Document:
         Tue Nov 11 18:10:01 MST 2008

4. Technical Description

4.1 Background:

    ddi_soft_state(9F) provides utility interfaces to help device
    drivers manage different context. When small integer values, like
    ddi_get_instance(9F) return values, are directly related to
    context, the current "indexed" soft_state interfaces work well.

4.2 Problem:

    Two IEEE-1275 '@unit-address' issues can make the current
    ddi_soft_state(9F) support ineffective:

      o Compression: Some IEEE-1275 bindings, like the SCSI
        '@<target-port>,<lun>' notation, compress multiple addressing
        levels into a single 'unit-address' string. If a driver needs
        to maintain soft state at intermediate levels, like the
        <target-port> level, there is no instance number to use with
        ddi_soft_state(9F), and no dev_info node to allow use of
        ddi_[gs]et_driver_private(9F) or ddi_[gs]et_parent_data).

      o Complexity: An addressing level may be complex: both
        non-numeric, sparse, and large.

    This situation has forced drivers to maintain soft state context in
    ways that no longer fit the ddi_soft_state(9F) model.

    An example is SCSA HBA <target-port> unit-address context. For the
    initial SCSI Parallel Interconnect transport the <target-port> was
    as an integer limited to the [0-15] range, and ddi_soft_state(9F)
    worked well. On modern transports the complexity of the
    <target-port> space has mushroomed, as shown below, and the <lun>
    space is now 64-bits and sparse.

      SPI:   disk at 0,0
      WWN:   disk at w216000c0ff8047dd,0
      GUID:  disk at g600c0ff0000000000047dd270fdf0901   (lun identity: MPxIO)
      ISCSI: disk at 
0000iqn.1986-03.com.sun%3A02%3Ac8a82272-b354-c913-80f9-db9cb378a6f60001,0

4.3 Proposal:

    The proposal is to extend the ddi_soft_state(9F) programming model
    by providing "string" based peers to todays "indexed" soft_state
    interfaces. In addition to "string" support, "indexed" interfaces
    with stronger typing are proposed.

    Implementation of proposed ddi_ssoft_state(9F) interfaces is built
    on top of the 'modhash' interfaces introduced by [1].

4.4 Proposed Interfaces:

    ------------------------------------------------------------------
    Interface Name              Comm.Lev.       Comments
    ------------------------------------------------------------------

    ddi_isoft_state             Private         "indexed" soft_state

    ddi_ssoft_state             "               "string" soft_state


    ddi_isoft_state_init        "               typed equivalent of
                                                ddi_soft_state_init(9F)
    ddi_ssoft_state_init        "               string peer of
                                                ddi_isoft_state_init(9F)


    ddi_isoft_state_zalloc      "               typed equivalent of
                                                ddi_soft_state_zalloc(9F)
    ddi_ssoft_state_zalloc      "               string peer of
                                                ddi_isoft_state_zalloc(9F)

    ddi_isoft_state_get         "               typed equivalent of
                                                ddi_soft_state_get(9F)
    ddi_ssoft_state_get         "               string peer of
                                                ddi_isoft_state_get(9F)

    ddi_isoft_state_free        "               typed equivalent of
                                                ddi_soft_state_free(9F)
    ddi_ssoft_state_free        "               string peer of
                                                ddi_isoft_state_free(9F)

    ddi_isoft_state_fini        "               typed equivalent of
                                                ddi_soft_state_fini(9F)
    ddi_ssoft_state_fini        "               string peer of
                                                ddi_isoft_state_fini(9F)

    ddi_isoft_state_unassigned  "               return first unassigned
                                                item of an ddi_isoft_state.

4.5 Interface Prototypes: (defined in sunddi.h):

    typedef     struct __ddi_isoft_state        ddi_isoft_state;
    typedef     struct __ddi_ssoft_state        ddi_ssoft_state;

    int
    ddi_isoft_state_init(ddi_isoft_state **state_p,
        size_t size, size_t n_items);
    int
    ddi_ssoft_state_init(ddi_ssoft_state **state_p,
        size_t size, int hash_sz);

    int
    ddi_isoft_state_zalloc(ddi_isoft_state *state, int index);
    int
    ddi_ssoft_state_zalloc(ddi_ssoft_state *state, const char *stringkey);

    void *
    ddi_isoft_state_get(ddi_isoft_state *state, int index);
    void *
    ddi_ssoft_state_get(ddi_ssoft_state *state, const char *stringkey);

    void
    ddi_isoft_state_free(ddi_isoft_state *state, int index);
    void
    ddi_ssoft_state_free(ddi_ssoft_state *state, const char *stringkey);

    void
    ddi_isoft_state_fini(ddi_isoft_state **state_p);
    void
    ddi_ssoft_state_fini(ddi_ssoft_state **state_p);

    int
    ddi_isoft_state_unassigned(ddi_isoft_state **state_p);

4.4 Example:

    Assuming that 'tpaddr' is the <target-port> portion SCSI
    'unit-address' string, A SCSA HBA driver can use the following to
    access its private <target-port> specific context.

        ss = ddi_isoft_state_get(xx_state, ddi_get_instance(devi));
        tpss = ddi_ssoft_state_get(ss->ss_tpstate, tpaddr);

    Where xx_state would be setup in _init(9E) via
    ddi_isoft_state_init(9F), and ss_tpstate would be setup in
    xxattach(9E) via ddi_ssoft_state_init(9F).

4.5 Alternatives:

    An alternative 'compound' approach was considered and prototyped.
    The 'compound' approach implemented a set of 'ddi_strid_*(9E)'
    string-to-id mapping interfaces, and then used the existing
    "indexed" ddi_soft_state(9F) to get from an 'id' to the soft state.
    The 'ddi_strid_(9E)' interfaces, while a good fit for some
    applications, was found to increase SCSI host adapter driver
    complexity compared to the proposed ddi_ssoft_state(9F) interfaces.
    The proposed ddi_ssoft_state(9F) interfaces also present a familiar
    API: they are based on the well-established ddi_soft_state(9F) API
    structure.

4.6 Man Pages

    See Appendix A. Some of the examples are TBS at this point, more
    meaningful examples should be provided before these interfaces are
    promoted.

4.7 Release Binding

    Micro/patch binding is requested.

4.8 References

    [1] PSARC case that introduced modhash interfaces
        PSARC/1998/212 Extensions to Device Autoconfiguration [John Danielson]
        http://sac.sfbay/PSARC/1998/212
        http://www.opensolaris.org/os/community/arc/caselog/PSARC/1998/212


Appendix A:

A.1: New ddi_ssoft_state(9F)
=========================================
    :r ddi_ssoft_state.9f

Kernel Functions for Drivers                   ddi_ssoft_state(9F)

NAME
     ddi_ssoft_state, ddi_ssoft_state_get, ddi_ssoft_state_fini,
     ddi_ssoft_state_free, ddi_ssoft_state_init, ddi_ssoft_state_zalloc -
     driver string soft state utility routines

SYNOPSIS
     #include <sys/ddi.h>
     #include <sys/sunddi.h>

     typedef struct __ddi_ssoft_state   ddi_ssoft_state;

     int ddi_ssoft_state_init(ddi_ssoft_state **state_p,
                size_t size, size_t hash_sz);

     int ddi_ssoft_state_zalloc(ddi_ssoft_state *state, int stringkey);

     void *ddi_ssoft_state_get(ddi_ssoft_state *state, int stringkey);

     void ddi_ssoft_state_free(ddi_ssoft_state *state, int stringkey);

     void ddi_ssoft_state_fini(ddi_ssoft_state **state_p);

INTERFACE LEVEL
     Solaris DDI specific (Solaris DDI).

PARAMETERS
     state_p    Address of the opaque state pointer which will be
                initialized by ddi_ssoft_state_init() to point to
                implementation dependent data.

     state      An opaque pointer to implementation-dependent data that
                describes the soft state.

     size       Size of the soft state which will be allocated by subsequent
                calls to ddi_ssoft_state_zalloc(); zero is illegal.

     hash_sz    The number of hashed lists which will be allocated;
                zero is not allowed. There is a performance
                .vs. space tradeoff in the selection of a hash_sz
                value: for 'n' soft state structures, on average each
                ddi_ssoft_state_get will need to traverse 'n'/hash_sz/2
                entries to locate the requested soft state structure.

     stringkey  The string key for the soft state structure; usually
                associated with some sub-portion of the device's
                'unit-address'.

DESCRIPTION

     Some drivers must maintain state information at a granularity
     unrelated to ddi_get_instance(9F) instance numbers or dev_info
     node ddi_get_driver_private(9F) data.

     When the needed soft state granularity can be associated with a
     string, such as a sub-portion of a 'unit-address' string, the
     ddi_ssoft_state(9F) utility routines can be used to help device
     drivers manage the space used by the driver to hold such state
     information.

     For example, if a SCSI HBA driver maintains state for each
     target-port address in a separate state structure, for transports
     with complex target-port address representations these routines
     can be used to dynamically allocate and deallocate a separate
     structure for each target-port as scsi_device(9S) associated with
     the target-port are initialized by tran_tgt_init(9E) and and freed
     by tran_tgt_free(9E).

     To use the routines, the driver writer needs to declare a state
     pointer, state_p, which the implementation uses as a place to hang
     a set of per-driver structures; everything else is managed by
     these routines.

     The routine ddi_ssoft_state_init() is usually called in the
     driver's attach(9E) routine to initialize the state pointer, and set
     the size of the soft state structure.

     The routine ddi_ssoft_state_zalloc() is called to allocate a soft
     state.  The routine is passed a string key, which is used to refer
     to the structure in subsequent calls to ddi_ssoft_state_get() and
     ddi_ssoft_state_free(). The string key is usually some sub-portion
     of a 'unit-address'.  The routine attempts to allocate space for
     the new structure, and if the space allocation was successful,
     DDI_SUCCESS is returned to the caller. Returned memory is zeroed.

     A pointer to the space previously allocated for a soft state
     structure can be obtained by calling ddi_ssoft_state_get() with the
     appropriate string key.

     The space used by a given soft state structure can be returned to
     the system using ddi_ssoft_state_free().

     The space used by all the soft state structures allocated on a
     given state pointer, together with the housekeeping information
     used by the implementation can be returned to the system using
     ddi_ssoft_state_fini(). This routine is typically called from the
     driver's detach(9E) routine.

     The ddi_ssoft_state_zalloc(), ddi_ssoft_state_free() and
     ddi_ssoft_state_get() routines coordinate access to the underlying
     data structures in an MT-safe fashion, thus no additional locks
     should be necessary.

RETURN VALUES

     ddi_ssoft_state_get()

     NULL               The requested soft state structure was not
                        allocated at the time of the call.

     pointer            The pointer to the soft state structure.



     ddi_ssoft_state_init()

     0                  The allocation was successful.

     EINVAL             Either the size parameter was zero, or the
                        state_p parameter was invalid.


     ddi_ssoft_state_zalloc()

     DDI_SUCCESS        The allocation was successful.

     DDI_FAILURE        The routine failed to allocate the storage
                        required; either the state parameter was
                        invalid, the string key was NULL, or an attempt
                        was made to allocate using a string key that
                        was already allocated.


CONTEXT
     The ddi_ssoft_state_init() and  ddi_ssoft_state_alloc() functions
     can be called from user or kernel context only, since they may
     internally call kmem_zalloc(9F) with the KM_SLEEP flag.

     The  ddi_ssoft_state_fini(), ddi_ssoft_state_free() and
     ddi_ssoft_state_get() routines can be called from any driver
     context.

EXAMPLES
<<XXX TBS...>>

SEE ALSO
     _fini(9E), _init(9E), attach(9E), detach(9E),
     ddi_get_instance(9F), ddi_soft_state(9E), ddi_isoft_state(9E),
     getminor(9F), kmem_zalloc(9F)

NOTES
     If necessary, a hierarchy of state structures can be constructed
     by embedding state pointers in higher order state structures.

DIAGNOSTICS
<<XXX VERIFY... with final implementation...>>

     All of the messages described below usually indicate bugs in the
     driver and should not appear in normal operation of the system.

       WARNING: ddi_ssoft_state_zalloc: bad handle
       WARNING: ddi_ssoft_state_free: bad handle
       WARNING: ddi_ssoft_state_fini: bad handle

     The implementation-dependent information kept in the state
     variable is corrupt.

       WARNING: ddi_ssoft_state_free: null handle
       WARNING: ddi_ssoft_state_fini: null handle

     The routine has been passed a null or corrupt state pointer.
     Check that ddi_ssoft_state_init() has been called.

       WARNING: ddi_ssoft_state_free: string key '%s' not allocated

     The routine has been asked to free a string key which is not
     allocated. The message prints out the invalid string key.

A.2: New ddi_isoft_state(9F)
=========================================
    :r ddi_isoft_state.9f

Kernel Functions for Drivers                   ddi_isoft_state(9F)

NAME
     ddi_isoft_state, ddi_isoft_state_get, ddi_isoft_state_fini,
     ddi_isoft_state_free, ddi_isoft_state_init, ddi_isoft_state_zalloc -
     driver indexed soft state utility routines

SYNOPSIS
     #include <sys/ddi.h>
     #include <sys/sunddi.h>

     typedef struct __ddi_isoft_state   ddi_isoft_state;

     int ddi_isoft_state_init(ddi_isoft_state **state_p,
                size_t size, size_t n_items);

     int ddi_isoft_state_zalloc(ddi_isoft_state *state, int item);

     void *ddi_isoft_state_get(ddi_isoft_state *state, int item);

     void ddi_isoft_state_free(ddi_isoft_state *state, int item);

     void ddi_isoft_state_fini(ddi_isoft_state **state_p);

INTERFACE LEVEL
     Solaris DDI specific (Solaris DDI).

PARAMETERS
     state_p    Address of the opaque state pointer which will be
                initialized by ddi_isoft_state_init() to point to
                implementation dependent data.

     state      An opaque pointer to implementation-dependent data that
                describes the soft state.

     size       Size of the item which will be allocated by subsequent
                calls to ddi_isoft_state_zalloc().

     n_items    A hint of the number of items which will be
                preallocated; zero is allowed.

     item       The item number for the state structure; usually the
                instance number of the associated devinfo node.

DESCRIPTION
     Most device drivers maintain state information with each instance
     of the device they control; for example, a soft copy of a device
     control register, a mutex that must be held while accessing a
     piece of hardware, a partition table, or a unit structure. These
     utility routines are intended to help device drivers manage the
     space used by the driver to hold such state information.

     For example, if the driver holds the state of each instance in a
     single state structure, these routines can be used to dynamically
     allocate and deallocate a separate structure for each instance of
     the driver as the instance is attached and detached.

     To use the routines, the driver writer needs to declare a state
     pointer, state_p, which the implementation uses as a place to hang
     a set of per-driver structures; everything else is managed by
     these routines.

     The routine ddi_isoft_state_init() is usually called in the
     driver's _init(9E) routine to initialize the state pointer, set
     the size of the soft state structure, and to allow the driver to
     pre-allocate a given number of such structures if required.

     The routine ddi_isoft_state_zalloc() is usually called in the
     driver's attach(9E) routine. The routine is passed an item number
     which is used to refer to the structure in subsequent calls to
     ddi_isoft_state_get() and ddi_isoft_state_free(). The item number is
     usually just the instance number of the devinfo node, obtained
     with ddi_get_instance(9F). The routine attempts to allocate space
     for the new structure, and if the space allocation was successful,
     DDI_SUCCESS is returned to the caller. Returned memory is zeroed.

     A pointer to the space previously allocated for a soft state
     structure can be obtained by calling ddi_isoft_state_get() with the
     appropriate item number.

     The space used by a given soft state structure can be returned to
     the system using ddi_isoft_state_free(). This routine is usually
     called from the driver's detach(9E) entry point.

     The space used by all the soft state structures allocated on a
     given state pointer, together with the housekeeping information
     used by the implementation can be returned to the system using
     ddi_isoft_state_fini(). This routine can be called from the
     driver's _fini(9E) routine.

     The ddi_isoft_state_zalloc(), ddi_isoft_state_free() and
     ddi_isoft_state_get() routines coordinate access to the underlying
     data structures in an MT-safe fashion, thus no additional locks
     should be necessary.

RETURN VALUES

     ddi_isoft_state_get()

     NULL               The requested state structure was not allocated
                        at the time of the call.

     pointer            The pointer to the state structure.



     ddi_isoft_state_init()

     0                  The allocation was successful.

     EINVAL             Either the size parameter was zero, or the
                        state_p parameter was invalid.


     ddi_isoft_state_zalloc()

     DDI_SUCCESS        The allocation was successful.

     DDI_FAILURE        The routine failed to allocate the storage
                        required; either the state parameter was
                        invalid, the item number was negative, or an
                        attempt was made to allocate an item number
                        that was already allocated.


CONTEXT
     The ddi_isoft_state_init() and  ddi_isoft_state_alloc() functions
     can be called from user or kernel context only, since they may
     internally call kmem_zalloc(9F) with the KM_SLEEP flag.

     The   ddi_isoft_state_fini(), ddi_isoft_state_free() and
     ddi_isoft_state_get() routines can be called from any driver
     context.

EXAMPLES
     Example 1 Creating and Removing Data Structures

     The following example shows how the routines described above can
     be used in terms of the driver entry points of a character-only
     driver. The example concentrates on the portions of the code that
     deal with creating and removing the driver's data structures.


        typedef struct {
                volatile caddr_t *csr;        /* device registers */
                kmutex_t         csr_mutex;   /* protects 'csr' field */
                unsigned int     state;
                dev_info_t       *dip;        /* back pointer to devinfo */
        } devstate_t;
        static ddi_isoft_state *statep;

        int
        _init(void)
        {
                int error;

                error = ddi_isoft_state_init(&statep, sizeof (devstate_t), 0);
                if (error != 0)
                        return (error);
                if ((error = mod_install(&modlinkage)) != 0)
                        ddi_isoft_state_fini(&statep);
                return (error);
        }

        int
        _fini(void)
        {
                int error;

                if ((error = mod_remove(&modlinkage)) != 0)
                        return (error);
                ddi_isoft_state_fini(&statep);
                return (0);
        }

        static int
        xxattach(dev_info_t *dip, ddi_attach_cmd_t cmd)
        {
                int instance;
                devstate_t *softc;

                switch (cmd) {
                case DDI_ATTACH:
                        instance = ddi_get_instance(dip);
                        if (ddi_isoft_state_zalloc(statep, instance) !=
                            DDI_SUCCESS)
                                return (DDI_FAILURE);
                        softc = ddi_isoft_state_get(statep, instance);
                        softc->dip = dip;
                        ...
                        return (DDI_SUCCESS);
                default:
                        return (DDI_FAILURE);
                }
        }

        static int
        xxdetach(dev_info_t *dip, ddi_detach_cmd_t cmd)
        {
                int instance;

                switch (cmd) {

                case DDI_DETACH:
                        instance = ddi_get_instance(dip);
                        ...
                        ddi_isoft_state_free(statep, instance);
                        return (DDI_SUCCESS);

                default:
                        return (DDI_FAILURE);
                }
        }

        static int
        xxopen(dev_t *devp, int flag, int otyp, cred_t *cred_p)
        {
                devstate_t *softc;
                int   instance;

                instance = getminor(*devp);
                if ((softc = ddi_isoft_state_get(statep, instance)) == NULL)
                        return (ENXIO);
                ...
                softc->state |= XX_IN_USE;
                ...
                return (0);
        }

SEE ALSO
     _fini(9E), _init(9E), attach(9E), detach(9E),
     ddi_get_instance(9F), getminor(9F), kmem_zalloc(9F)

WARNINGS
     There is no attempt to validate the item parameter given to
     ddi_isoft_state_zalloc() other than it must be a positive signed
     integer. Therefore very large item numbers may cause the driver to
     hang forever waiting for virtual memory resources that can never
     be satisfied.

NOTES
     If necessary, a hierarchy of state structures can be constructed
     by embedding state pointers in higher order state structures.

DIAGNOSTICS
     All of the messages described below usually indicate bugs in the
     driver and should not appear in normal operation of the system.

       WARNING: ddi_isoft_state_zalloc: bad handle
       WARNING: ddi_isoft_state_free: bad handle
       WARNING: ddi_isoft_state_fini: bad handle

     The implementation-dependent information kept in the state
     variable is corrupt.

       WARNING: ddi_isoft_state_free: null handle
       WARNING: ddi_isoft_state_fini: null handle

     The routine has been passed a null or corrupt state pointer.
     Check that ddi_isoft_state_init() has been called.

       WARNING: ddi_isoft_state_free: item %d not in range [0..%d]

     The routine has been asked to free an item which was never
     allocated. The message prints out the invalid item number and the
     acceptable range.


A.3: Changes to existing ddi_soft_state(9F)
=========================================
    :r!diff -U5 ddi_soft_state.9f.orig ddi_soft_state.9f

--- ddi_soft_state.9f.orig      Mon Nov 10 11:45:36 2008
+++ ddi_soft_state.9f   Tue Nov 11 18:08:26 2008
@@ -224,22 +224,29 @@
                return (0);
        }
 
 SEE ALSO
      _fini(9E), _init(9E), attach(9E), detach(9E),
-     ddi_get_instance(9F), getminor(9F), kmem_zalloc(9F)
+     ddi_get_instance(9F), ddi_isoft_state(9E), ddi_ssoft_state(9E),
+     getminor(9F), kmem_zalloc(9F)
 
 WARNINGS
      There is no attempt to validate the item parameter given to
      ddi_soft_state_zalloc() other than it must be a positive signed
      integer. Therefore very large item numbers may cause the driver to
      hang forever waiting for virtual memory resources that can never
      be satisfied.
 
+     Use of the ddi_isoft_state(9E) interfaces is encouraged, it
+     provides stronger typing.
+
 NOTES
      If necessary, a hierarchy of state structures can be constructed
      by embedding state pointers in higher order state structures.
+
+     Equivalent functionality with stronger typing is provided 
+     by the newer ddi_isoft_state(9F) interfaces.
 
 DIAGNOSTICS
      All of the messages described below usually indicate bugs in the
      driver and should not appear in normal operation of the system.

Reply via email to