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.