/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#define __NSC_GEN__
#include "nsc_dev.h"
#ifdef DS_DDICT
#include "../contract.h"
#endif
#include "../nsctl.h"
0, 0, 0
};
0, 0, 0
};
extern nsc_def_t _nsc_disk_def[];
extern nsc_def_t _nsc_cache_def[];
extern nsc_mem_t *_nsc_local_mem;
extern nsc_rmmap_t *_nsc_global_map;
static nsc_io_t *_nsc_find_io(char *, int, int *);
nsc_io_t *_nsc_reserve_io(char *, int);
static nsc_io_t *_nsc_alloc_io(int, char *, int);
static int _nsc_open_fn(nsc_fd_t *, int);
static int _nsc_close_fn(nsc_fd_t *);
static int _nsc_alloc_fd(char *, int, int, nsc_fd_t **);
static int _nsc_alloc_dev(char *, nsc_dev_t **);
static int _nsc_reopen_io(char *, int);
static int _nsc_reopen_dev(nsc_dev_t *, int);
static int _nsc_reopen_fd(nsc_fd_t *, int);
void _nsc_release_io(nsc_io_t *);
static void _nsc_free_fd(nsc_fd_t *);
static void _nsc_free_iodev(nsc_iodev_t *);
static void _nsc_free_dev(nsc_dev_t *);
static void _nsc_free_io(nsc_io_t *);
static int _nsc_setval(nsc_dev_t *, char *, char *, int, int);
static void r_nsc_setval(ncall_t *, int *);
static void r_nsc_setval_all(ncall_t *, int *);
extern void _nsc_add_disk(nsc_io_t *);
extern void _nsc_add_cache(nsc_io_t *);
/*
* void
* _nsc_init_dev (void)
* Initialise device subsystem.
*
* Called at driver initialisation time to allocate necessary
* data structures.
*/
void
{
if (!_nsc_null_io)
}
void
{
}
}
}
/*
* nsc_io_t *
* nsc_register_io (char *name, int type, nsc_def_t *def)
* Register an I/O module.
*
* Returns a token for use in future calls to nsc_unregister_io.
* The ID and flags for the module are specified by 'type' and
* the appropriate entry points are defined using 'def'. If
* registration fails NULL is returned.
*
* Description:
* Registers an I/O module for use by subsequent calls to
* nsc_open.
*/
nsc_io_t *
char *name;
int type;
{
return (NULL);
return (NULL);
return (NULL);
}
return (NULL);
}
}
break;
_nsc_io_lbolt = nsc_lbolt();
break;
return (io);
}
/*
* static int
* _nsc_decode_io (nsc_def_t *def, nsc_io_t *io)
* Decode I/O module definition.
*
* Returns TRUE if the definition contains an adequate
* description of an I/O module.
*
* Description:
* Decode the definition of an I/O module and supply
* translation routines where possible for operations
* that are not defined.
*/
static int
{
return (1);
}
/*
* int
* nsc_unregister_io (nsc_io_t *io, int flag)
* Un-register an I/O module.
*
* Returns 0 on success, otherwise returns an error code.
*
* Description:
* The specified I/O module is un-registered if possible.
* All open file descriptors using the module will be closed
* in preparation for a subsequent re-open.
*
* If NSC_PCATCH is specified and a signal is received,
* the unregister will be terminated and EINTR returned.
*/
int
{
int rc = 0;
if (io == _nsc_null_io)
return (EINVAL);
break;
}
lp:
return (rc);
}
goto lp;
}
_nsc_io_lbolt = nsc_lbolt();
break;
break;
}
/*
* We have tried to get rid of all the IO provider's clients.
* If there are still anonymous buffers outstanding, then fail
* the unregister.
*/
if (rc)
if (!rc)
return (rc);
}
/*
* nsc_path_t *
* nsc_register_path (char *path, int type, nsc_io_t *io)
* Register interest in pathname.
*
* Returns a token for use in future calls to
* nsc_unregister_path. The 'path' argument can contain
* wild characters. If registration fails NULL is returned.
* May not be called for io providers that support NSC_ANON.
*
* Description:
* Registers an interest in any pathnames matching 'path'
* which are opened with the specified type.
*/
{
int rc;
return (NULL);
break;
_nsc_io_lbolt = nsc_lbolt();
break;
return (sp);
}
/*
* int
* nsc_unregister_path (nsc_path_t *sp, int flag)
* Un-register interest in pathname.
*
* Returns 0 on success, otherwise returns an error code.
*
* Description:
* Interest in the specified pathname is un-registered
* if possible. All appropriate file descriptors will be
* closed in preparation for a subsequent re-open.
*
* If NSC_PCATCH is specified and a signal is received,
* the unregister will be terminated and EINTR returned.
*/
int
nsc_path_t *sp;
int flag;
{
int rc;
break;
}
_nsc_io_lbolt = nsc_lbolt();
return (rc);
}
break;
if (*spp)
return (0);
}
/*
* static int
* _nsc_reopen_io (char *path, int flag)
* Force re-open of all file descriptors.
*
* The _nsc_io_lock must be held across calls to
* this function.
*
* Returns 0 if the force succeeds without releasing
* _nsc_io_lock, otherwise returns an error code.
*
* Description:
* A re-open is forced for all file descriptors as
* appropriate. For performance reasons available
* devices are re-opened before those that would block.
*/
static int
char *path;
int flag;
{
continue;
continue;
break;
if (!dp)
return (ERESTART);
run = 1;
}
}
return (errno);
}
/*
* static int
* _nsc_reopen_dev (nsc_dev_t *dev, int flag)
* Force re-open of entire device.
*
* The _nsc_io_lock must be held across calls to
* this function.
*
* Returns 0 if the force succeeds without releasing
* _nsc_io_lock, otherwise returns an error code.
*
* Description:
* A re-open is forced for all file descriptors for the
* device as appropriate.
*/
static int
int flag;
{
continue;
return (ERESTART);
return (ERESTART);
run = 1;
}
}
continue;
return (ERESTART);
return (ERESTART);
run = 1;
}
return (errno);
}
/*
* static int
* _nsc_relock_dev (nsc_dev_t *dev, nsc_fd_t *fd, nsc_iodev_t *iodev)
* Relock device structure if possible.
*
* The _nsc_io_lock must be held across calls to
* this function.
*
* Checks whether the file descriptor is still part
* of the specified device and I/O device. If so the
* device lock is taken. Otherwise FALSE is returned.
*/
static int
{
break;
if (!dp)
return (0);
if (iodev)
break;
break;
}
if (!fp) {
return (0);
}
return (1);
}
/*
* static int
* _nsc_reopen_fd (nsc_fd_t *dev, int flag)
* Force re-open of file descriptor.
*
* Both _nsc_io_lock and the device lock must be held
* across calls to this function.
*
* Returns 0 if the force succeeds without releasing
* any locks, otherwise returns an error code. If an
* error code is returned the device lock is released.
*
* Description:
* If appropriate the file descriptor is closed in order
* to force a subsequent open using the currently available
* resources.
*/
static int
int flag;
{
int changed = 0;
int rc;
return (0);
return (0);
if (iodev &&
!changed)
return (0);
if (iodev)
dev->nsc_reopen = 0;
}
/*
* nsc_fd_t *
* nsc_open (char *path, int type, nsc_def_t *def, blind_t arg, int *sts)
* Open file descriptor for pathname.
*
* Returns file descriptor if open succeeds, otherwise
* returns 0 and puts error code in the location pointed
* to by sts.
*
* Description:
* Open the specified pathname using an appropriate access
* method.
*/
nsc_fd_t *
char *path;
int type;
int *sts;
{
if (sts)
return (NULL);
}
break;
if (rc) {
if (sts)
return (NULL);
}
return (fd);
}
/*
* int
* _nsc_open_fd (nsc_fd_t *fd, int flag)
* Open file descriptor.
*
* The device lock must be held across calls to
* this function.
*
* Returns 0 if the open succeeds, otherwise
* returns an error code.
*
* Description:
* Open the specified file descriptor.
*/
int
int flag;
{
int rc;
return (0);
if (flag & NSC_NOBLOCK)
return (EAGAIN);
if (!rc)
}
/*
* static int
* _nsc_open_fn (nsc_fd_t *fd, int flag)
* Allocate I/O device and open file descriptor.
*
* No locks may be held across this function.
*
* If the open succeeds an I/O device will be
* attached to the file descriptor, marked as
* pending and 0 returned. Otherwise, returns
* an error code.
*
* Description:
* Allocate an I/O device and open the specified
* file descriptor.
*/
static int
int flag;
{
int rc;
return (rc);
return (rc);
}
if (rc) {
return (rc);
}
/* save away the DevMaj and DevMin values */
#ifdef DEBUG
if (rc != 1) {
}
#endif
#ifdef DEBUG
if (rc != 1) {
}
#endif
}
return (0);
}
/*
* int
* nsc_close (nsc_fd_t *fd)
* Close file descriptor for pathname.
*
* Returns 0 if close succeeds, otherwise returns error
* code.
*
* Description:
* Close the specified file descriptor. It is assumed
* that all other users of this file descriptor have
* finished. Any reserve will be discarded before the
* close is performed.
*/
int
{
int rc;
if (!fd)
return (0);
while (fd->sf_reserve)
break;
if (!rc)
return (rc);
}
/*
* int
* _nsc_close_fd (nsc_fd_t *fd, int flag)
* Close file descriptor.
*
* The device lock must be held across calls to
* this function.
*
* Returns 0 if the close succeeds, otherwise
* returns an error code.
*
* Description:
* Close the specified file descriptor.
*/
int
int flag;
{
int rc;
return (-ERESTART);
}
if (!iodev)
return (0);
return (rc);
return (rc);
return (rc);
}
if (flag & NSC_NOBLOCK)
return (EAGAIN);
if (rc)
}
/*
* static int
* _nsc_close_fn (nsc_fd_t *fd)
* Close file descriptor and free I/O device.
*
* No locks may be held across this function.
*
* Returns 0 if the close succeeds, otherwise
* returns an error code.
*
* If the close succeeds the I/O device will be
* detached from the file descriptor, released
* and 0 returned. Otherwise, returns an error
* code.
*
* Description:
* Close the specified file descriptor and free
* the I/O device.
*/
static int
{
return (rc);
return (0);
}
/*
* void
* nsc_set_owner (nsc_fd_t *fd, nsc_iodev_t *iodev)
* Set owner associated with file descriptor.
*
* Sets the owner field in the file descriptor.
*/
void
{
if (fd) {
}
}
/*
* char *
* nsc_pathname (nsc_fd_t *fd)
* Pathname associated with file descriptor.
*
* Returns a pointer to the pathname associated
* with the given file descriptor.
*/
char *
{
}
/*
* int
* nsc_fdpathcmp(nsc_fd_t *fd, uint64_t phash, char *path)
* Compare fd to pathname and hash
*
* Returns comparison value like strcmp(3C).
*
* Description:
* Does an optimised comparison of the pathname and associated hash
* value (as returned from nsc_strhash()) against the pathname of
* the filedescriptor, fd.
*/
int
{
return (rc);
}
static int
{
char *pp;
int rc;
#ifdef DEBUG
}
#endif
#ifdef DEBUG
#endif
return (0);
}
else {
/* found dv for device */
break;
}
}
return (0);
}
}
break;
}
}
}
}
/*
* phoenix: ncall the new value to the other node now.
*/
/* CONSTCOND */
goto out;
}
if (rc == 0) {
if (rc == 0) {
/*
* Send synchronously and read a reply
* so that we know that the remote
* setval has completed before this
* function returns and hence whilst
* the device is still reserved on this
* node.
*/
}
}
}
out:
return (vp ? 1 : 0);
}
/* ARGSUSED */
static void
{
int rc;
return;
}
if (rc != 0) {
return;
}
rc = 0;
else
}
/* ARGSUSED */
static void
{
int rc;
/* CONSTCOND */
}
}
}
if (rc != 0) {
return;
}
if (rc != 0) {
return;
}
break;
}
if (dv) {
continue;
}
if (rc == 0) {
/*
* Send synchronously and read a reply
* so that we know that the remote
* setval has completed before this
* function returns.
*/
}
}
ncall_free(np);
rc = 0;
} else {
}
}
/*
* int
* nsc_setval (nsc_fd_t *fd, char *name, int val)
* Set value for device.
*
* Returns 1 if the value has been set, otherwise 0.
* Must be called with the fd reserved.
*
* Description:
* Sets the specified global variable for the device
* to the value provided.
*/
int
{
if (!fd)
return (0);
return (0);
}
/*
* int
* nsc_getval (nsc_fd_t *fd, char *name, int *vp)
* Get value from device.
*
* Returns 1 if the value has been found, otherwise 0.
* Must be called with the fd reserved, except for "DevMaj" / "DevMin".
*
* Description:
* Finds the value of the specified device variable for
* the device and returns it in the location pointed to
* by vp.
*/
int
{
if (!fd)
return (0);
/*
* Don't check for nsc_held() for the device number values
* since these are magically created and cannot change when
* the fd is not reserved.
*/
return (0);
break;
}
}
}
return (val ? 1 : 0);
}
/*
* char *
* nsc_shared (nsc_fd_t *fd)
* Device is currently shared.
*
* The device lock must be held across calls to this
* this function.
*
* Returns an indication of whether the device accessed
* by the file descriptor is currently referenced by more
* than one user.
*
* This is only intended for use in performance critical
* situations.
*/
int
{
int cnt = 0;
if (!fd)
return (0);
return (1);
return (1);
return (0);
}
/*
* kmutex_t *
* nsc_lock_addr (nsc_fd_t *fd)
* Address of device lock.
*
* Returns a pointer to the spin lock associated with the
* device.
*
* Description:
* This is only intended for use in performance critical
* situations in conjunction with nsc_reserve_lk.
*/
kmutex_t *
{
}
/*
* int
* _nsc_call_io (long f, blind_t a, blind_t b, blind_t c)
* Call information function.
*
* Returns result from function or 0 if not available.
* f represents the offset into the I/O structure at which
* the required function can be found and a, b, c are the
* desired arguments.
*
* Description:
* Calls the requested function for the first available
* cache interface.
*/
int
{
int (*fn)();
int rc;
if (!io)
return (rc);
}
/*
* nsc_io_t *
* _nsc_reserve_io (char *, int type)
* Reserve I/O module.
*
* Returns address of I/O structure matching specified
* type, or NULL.
*
* Description:
* Searches for an appropriate I/O module and increments
* the reference count to prevent it being unregistered.
*/
nsc_io_t *
char *path;
int type;
{
return (io);
}
/*
* static nsc_io_t *
* _nsc_find_io (char *path, int type, int *changed)
* Find I/O module.
*
* The _nsc_io_lock must be held across calls to
* this function.
*
* Returns address of I/O structure matching specified
* type, or NULL.
*
* 'changed' will be set to non-zero if there is a pending
* nsc_path_t that matches the criteria for the requested type.
* This allows nsctl to distinguish between multiple
* nsc_register_path's done by the same I/O provider.
*
* Description:
* Searches for an appropriate I/O module.
*
* 1. If <type> is a single module id find the specified I/O
* module by module id.
*
* 2. Find the highest module that provides any of the I/O types
* included in <type>, taking into account any modules
* registered via the nsc_register_path() interface if <path>
* is non-NULL.
*
* 3. Find an I/O module following the rules in (2), but whose
* module id is less than the id OR'd into <type>.
*
* If no module is found by the above algorithms and NSC_NULL was
* included in <type>, return the _nsc_null_io module. Otherwise
* return NULL.
*/
static nsc_io_t *
{
if (path) {
continue;
continue;
break;
}
if (sp) {
/* look for matching pending paths */
break;
}
}
}
}
continue;
break;
continue;
}
continue;
}
break;
}
/*
* Mark this as a path change.
*/
if (changed) {
*changed = 1;
}
}
return (NULL);
if (!io)
io = _nsc_null_io;
return (io);
}
/*
* void
* _nsc_release_io (nsc_io_t *)
* Release I/O module.
*
* Description:
* Releases reference to I/O structure and wakes up
* anybody waiting on it.
*/
void
{
}
/*
* static int
* _nsc_alloc_fd (char *path, int type, int flag, nsc_fd_t **fdp)
* Allocate file descriptor structure.
*
* Stores address of file descriptor through fdp and
* returns 0 on success, otherwise returns error code.
*
* Description:
* A new file descriptor is allocated and linked in to
* the file descriptor chain which is protected by the
* device lock.
*
* On return the file descriptor must contain all the
* information necessary to perform an open. Details
* specific to user callbacks are not required yet.
*/
static int
char *path;
{
int rc;
return (ENOMEM);
return (rc);
}
return (0);
}
/*
* static int
* _nsc_free_fd (nsc_fd_t *)
* Free file descriptor.
*
* Description:
* The file descriptor is removed from the chain and free'd
* once pending activity has completed.
*/
static void
{
if (!fd)
return;
break;
}
(void) _nsc_wait_dev(dev, 0);
}
/*
* static void
* _nsc_relink_fd (nsc_fd_t *fd, nsc_fd_t **from,
* nsc_fd_t **to, nsc_iodev_t *iodev)
* Relink file descriptor.
*
* Description:
* Remove the file descriptor from the 'from' chain and
* add it to the 'to' chain. The busy flag in iodev is
* used to prevent modifications to the chain whilst a
* callback is in progress.
*/
static void
{
(void) _nsc_wait_dev(dev, 0);
break;
}
}
/*
* static int
* _nsc_alloc_iodev (nsc_dev_t *dev, int type, nsc_iodev_t **iodevp)
* Allocate I/O device structure.
*
* Stores address of I/O device structure through iodevp
* and returns 0 on success, otherwise returns error code.
*
* Description:
* If an entry for the I/O device already exists increment
* the reference count and return the address, otherwise
* allocate a new structure.
*
* A new structure is allocated before scanning the chain
* to avoid calling the memory allocator with a spin lock
* held. If an entry is found the new structure is free'd.
*
* The I/O device chain is protected by the device lock.
*/
static int
int type;
{
return (ENOMEM);
return (ENXIO);
}
dev->nsc_refcnt++;
break;
}
if (!ip) {
}
if (ip) {
}
return (0);
}
/*
* static int
* _nsc_free_iodev (nsc_iodev_t *iodev)
* Free I/O device structure.
*
* Description:
* Decrements the reference count of a previously allocated
* I/O device structure. If this is the last reference it
* is removed from the device chain and free'd once pending
* activity has completed.
*/
static void
{
if (!iodev)
return;
return;
}
break;
}
(void) _nsc_wait_dev(dev, 0);
}
/*
* static int
* _nsc_alloc_dev (char *path, nsc_dev_t **devp)
* Allocate device structure.
*
* Stores address of device structure through devp
* and returns 0 on success, otherwise returns error
* code.
*
* Description:
* If an entry for the device already exists increment
* the reference count and return the address, otherwise
* allocate a new structure.
*
* A new structure is allocated before scanning the device
* chain to avoid calling the memory allocator with a spin
* lock held. If the device is found the new structure is
* free'd.
*
* The device chain is protected by _nsc_io_lock.
*/
static int
{
int rc;
return (ENOMEM);
dev->nsc_refcnt++;
_nsc_dev_pend = dev;
dp->nsc_refcnt++;
break;
}
if (!dp) {
break;
}
_nsc_dev_top = dev;
}
if (dp) {
}
/*
* and link it back to the device structure.
*/
break;
}
}
}
/*
*/
goto out;
}
if (rc == 0) {
if (rc == 0) {
/*
* Send synchronously and read a reply
* so that we know that the updates
* have completed before this
* function returns.
*/
}
}
out:
return (0);
}
/*
* static void
* _nsc_free_dev (nsc_dev_t *dev)
* Free device structure.
*
* Description:
* Decrements the reference count of a previously allocated
* device structure. If this is the last reference it is
* removed from the device chain and free'd once pending
* activity has completed.
*
* Whilst waiting for pending activity to cease the device is
* relinked onto the pending chain.
*/
static void
{
if (!dev)
return;
if (--dev->nsc_refcnt > 0) {
return;
}
_nsc_dev_pend = dev;
break;
}
}
break;
}
}
/*
* static nsc_io_t *
* _nsc_alloc_io (int id, char *name, int flag)
* Allocate an I/O structure.
*
* Returns the address of the I/O structure, or NULL.
*/
static nsc_io_t *
int id;
char *name;
int flag;
{
return (NULL);
return (io);
}
/*
* static void
* _nsc_free_io (int id, char *name, int flag)
* Free an I/O structure.
*
* Free the I/O structure and remove it from the chain.
*/
static void
{
break;
if (*iop)
}