/*
* 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.
*/
#include <sys/ddi_impldefs.h>
#include <sys/autoconf.h>
#include <sys/instance.h>
#include <sys/cpc_pcbe.h>
#include <sys/socketvar.h>
extern int moddebug;
extern struct dev_ops mod_nodev_ops;
extern int findmodbyname(char *);
extern int mod_getsysnum(char *);
/*
* Define dev_ops for unused devopsp entry.
*/
DEVO_REV, /* devo_rev */
0, /* refcnt */
ddi_no_info, /* info */
nulldev, /* identify */
nulldev, /* probe */
ddifail, /* attach */
nodev, /* detach */
nulldev, /* reset */
(struct bus_ops *)0 /* bus operations for nexus drivers */
};
/*
* Define mod_ops for each supported module type
*/
/*
* Null operations; used for uninitialized and "misc" modules.
*/
static int mod_infonull(void *, struct modlinkage *, int *);
};
/* CPU Modules */
};
/*
* Cryptographic Modules
*/
};
/*
* IP Policy Modules
*/
};
/*
* Device drivers
*/
};
/*
* System calls (new interface)
*/
};
#ifdef _SYSCALL32_IMPL
/*
* 32-bit system calls in 64-bit kernel
*/
};
#endif /* _SYSCALL32_IMPL */
/*
* Filesystems
*/
};
/*
* Streams modules.
*/
};
/*
* Socket modules.
*/
};
/*
* Scheduling classes.
*/
};
/*
* Exec file type (like ELF, ...).
*/
};
/*
* Dacf (Dynamic Autoconfiguration) modules.
*/
};
/*
* PCBE (Performance Counter BackEnd) modules.
*/
};
/*
* Brand modules.
*/
};
/*
* kiconv modules.
*/
};
/*
* Debugging support
*/
/*PRINTFLIKE2*/
static void
{
}
}
/*
* Install a module.
*/
int
{
printf("mod_install: modlinkage structure is not MODREV_1\n");
return (EINVAL);
}
linkpp1++;
}
break;
}
linkpp++;
}
return (retval);
}
static char *reins_err =
"Could not reinstall %s\nReboot to correct the problem";
/*
* Remove a module. This is called by the module wrapper routine.
*/
int
{
int retval = 0;
last_linkp = *linkpp;
while (*linkpp != last_linkp) {
(*linkpp)->misc_linkinfo);
break;
}
linkpp++;
}
break;
}
linkpp++;
}
return (retval);
}
/*
* Get module status.
*/
int
{
int i;
int retval = 0;
for (i = 0; i < MODMAXLINK; i++) {
} else {
if (retval != 0)
break;
linkpp++;
}
msip++;
}
/*
* Slight kludge used to extract the address of the
* modlinkage structure from the module (just after
* loading a module for the very first time)
*/
}
if (retval == 0)
return (1);
return (0);
}
/*
* Get module name.
*/
const char *
{
return (NULL);
return (mcp->mod_modname);
}
/*
* Null operation; return 0.
*/
/*ARGSUSED*/
static int
{
return (0);
}
/*
* Status for User modules.
*/
/*ARGSUSED*/
static int
{
return (0);
}
/*
* Driver status info
*/
/*ARGSUSED*/
static int
{
char *mod_name;
*p0 = -1;
return (0); /* driver is not yet installed */
}
return (0);
}
/*
* Manage dacf (device autoconfiguration) modules
*/
/*ARGSUSED*/
static int
{
*p0 = -1;
return (0); /* module is not yet installed */
}
*p0 = 0;
return (0);
}
static int
{
return (EINVAL);
}
/*ARGSUSED*/
static int
{
return (EINVAL);
}
/*
* Manage PCBE (Performance Counter BackEnd) modules.
*/
/*ARGSUSED*/
static int
{
return (EINVAL);
}
return (0);
}
/*
* PCBEs may not be unloaded. It would make CPC locking too complex, and since
* PCBEs are loaded once and used for life, there is no harm done in leaving
* them in the system.
*/
/*ARGSUSED*/
static int
{
return (EBUSY);
}
/*
* Manage BrandZ modules.
*/
/*ARGSUSED*/
static int
{
}
/*ARGSUSED*/
static int
{
}
/*
* Install a new driver
*/
static int
{
char *modname;
int err = 0;
/* sanity check module */
goto done;
}
/* Sanity check modname */
#ifdef DEBUG
"mod_installdrv: no major number for %s", modname);
#endif
goto done;
}
/* Verify MP safety flag */
"mod_installdrv: MT-unsafe driver '%s' rejected", modname);
goto done;
}
/* Is bus_map_fault signature correct (version 8 and higher)? */
"mod_installdrv: busops' revision of '%s' is too low"
" (must be at least 8)", modname);
goto done;
}
/* Make sure the driver is uninstalled */
#ifdef DEBUG
"mod_installdrv: driver %s not installed", modname);
#endif
goto unlock;
}
"mod_installdrv: driver already installed %s", modname);
goto unlock;
}
goto unlock;
}
done:
return (err);
}
static int
{
char *modname;
extern kthread_id_t mod_aul_thread;
int err = 0;
/* Don't auto unload modules on if moddebug flag is set */
goto done;
}
/* Verify modname has a driver major */
goto done;
}
modname);
goto unlock;
}
/*
* A driver is not unloadable if its dev_ops are held
*/
if (!DRV_UNLOADABLE(dp)) {
goto unlock;
}
/*
* OK to unload.
*/
/* check for reference to per-dev syncq */
}
}
done:
return (err);
}
/*
* System call subroutines
*/
/*
* Compute system call number for given sysent and sysent table
*/
static int
{
return (-1);
}
/*
* Put a loadable system call entry into a sysent table.
*/
static int
struct modlinkage *modlp,
{
#ifdef DEBUG
/*
* Before we even play with the sysent table, sanity check the
* incoming flags to make sure the entry is valid
*/
case SE_32RVAL1:
/* only r_val1 returned */
case SE_32RVAL1 | SE_32RVAL2:
/* r_val1 and r_val2 returned */
case SE_64RVAL:
/* 64-bit rval returned */
break;
default:
return (ENOSYS);
}
#endif
return (ENOSPC);
/*
* We should only block here until the reader in syscall gives
* up the lock. Multiple writers are prevented in the mod layer.
*/
/*
* clear the old call method flag, and get the new one from the module.
*/
/*
* If the syscall doesn't need or want unloading, it can avoid
* the locking overhead on each entry. Convert the sysent to a
* normal non-loadable entry in that case.
*/
} else {
}
}
return (0);
}
/*
* Remove a loadable system call entry from a sysent table.
*/
static int
struct modlinkage *modlp,
{
return (EINVAL);
}
/* If we can't get the write lock, we can't unlink from the system */
if (!(moddebug & MODDEBUG_NOAUL_SYS) &&
/*
* Check the flags to be sure the syscall is still
* (un)loadable.
* If SE_NOUNLOAD is set, SE_LOADABLE will not be.
*/
(SE_LOADED | SE_LOADABLE)) {
return (0);
}
}
return (EBUSY);
}
/*
* System call status info
*/
/*ARGSUSED*/
static int
{
return (0);
}
/*
* Link a system call into the system by setting the proper sysent entry.
* Called from the module's _init routine.
*/
static int
{
}
/*
* Unlink a system call from the system.
* Called from a modules _fini routine.
*/
static int
{
}
#ifdef _SYSCALL32_IMPL
/*
* 32-bit system call status info
*/
/*ARGSUSED*/
static int
{
return (0);
}
/*
* Link the 32-bit syscall into the system by setting the proper sysent entry.
* Also called from the module's _init routine.
*/
static int
{
}
/*
* Unlink the 32-bit flavor of a system call from the system.
* Also called from a module's _fini routine.
*/
static int
{
}
#endif /* _SYSCALL32_IMPL */
/*
* Filesystem status info
*/
/*ARGSUSED*/
static int
{
RLOCK_VFSSW();
*p0 = -1;
else {
}
return (0);
}
/*
* Install a filesystem.
*/
/*ARGSUSED1*/
static int
{
char *fsname;
int allocated;
int err;
int vsw_stats_enabled;
/* Not for public consumption so these aren't in a header file */
extern int vopstats_enabled;
extern vopstats_t **vopstats_fstype;
extern void initialize_vopstats(vopstats_t *);
/* Version matched */
} else {
/* Older VFSDEF_VERSION */
/* Pre-VFSDEF_VERSION */
} else {
/* If all else fails... */
fsname = "<unknown file system type>";
}
return (ENXIO);
}
allocated = 0;
WLOCK_VFSSW();
/*
* See 1095689. If this message appears, then
* we either need to make the vfssw table bigger
* statically, or make it grow dynamically.
*/
return (ENXIO);
}
allocated = 1;
}
/* Turn on everything by default *except* VSW_STATS */
&vswp->vsw_optproto);
} else {
}
/*
* This obviously implies VSW_CANREMOUNT.
*/
}
/*
* If stats are enabled system wide and for this fstype, then
* set the VSW_STATS flag in the proper vfssw[] table entry.
*/
}
else
if (err != 0) {
if (allocated) {
}
}
/* We don't want to hold the vfssw[] write lock over a kmem_alloc() */
/* If everything is on, set up the per-fstype vopstats */
if (vsw_stats_enabled && vopstats_enabled &&
}
return (err);
}
/*
* Remove a filesystem
*/
static int
{
char *modname;
if (moddebug & MODDEBUG_NOAUL_FS)
return (EBUSY);
WLOCK_VFSSW();
return (EINVAL);
}
return (EBUSY);
}
/*
* A mounted filesystem could still have vsw_count = 0
* so we must check whether anyone is actually using our ops
*/
return (EBUSY);
}
return (0);
}
/*
* Get status of a streams module.
*/
/*ARGSUSED*/
static int
{
return (0);
}
/*
* Install a streams module.
*/
/*ARGSUSED*/
static int
{
return (ENXIO);
}
}
/*
* Remove a streams module.
*/
/*ARGSUSED*/
static int
{
if (moddebug & MODDEBUG_NOAUL_STR)
return (EBUSY);
}
/*
* Get status of a socket module.
*/
/*ARGSUSED*/
static int
{
return (0);
}
/*
* Install a socket module.
*/
/*ARGSUSED*/
static int
{
char *mod_name;
#ifdef DEBUG
" %s != %s \n", mod_name,
#endif
return (EINVAL);
}
/*
* Register module.
*/
}
/*
* Remove a socket module.
*/
/*ARGSUSED*/
static int
{
/*
* unregister from the global socket creation table
* check the refcnt in the lookup table
*/
}
/*
* Get status of a scheduling class module.
*/
/*ARGSUSED1*/
static int
{
int status;
if (status != 0)
*p0 = -1;
else
return (0);
}
/*
* Install a scheduling class module.
*/
/*ARGSUSED1*/
static int
{
int status;
/*
* See if module is already installed.
*/
if (SCHED_INSTALLED(clp)) {
printf("scheduling class %s is already installed\n",
return (EBUSY); /* it's already there */
}
loaded_classes++; /* for priocntl system call */
return (0);
}
/*
* Remove a scheduling class module.
*
* we only null out the init func and the class functions because
* once a class has been loaded it has that slot in the class
* array until the next reboot. We don't decrement loaded_classes
* because this keeps count of the number of classes that have
* been loaded for this session. It will have to be this way until
* we implement the class array as a linked list and do true
* dynamic allocation.
*/
static int
{
int status;
char *modname;
if (status != 0) {
return (EINVAL);
}
if (moddebug & MODDEBUG_NOAUL_SCHED ||
return (EBUSY);
return (0);
}
/*
* Get status of an exec module.
*/
/*ARGSUSED1*/
static int
{
*p0 = -1;
else
return (0);
}
/*
* Install an exec module.
*/
static int
{
char *modname;
char *magic;
/*
* See if execsw entry is already allocated. Can't use findexectype()
* because we may get a recursive call to here.
*/
NULL) {
printf("no unused entries in 'execsw'\n");
return (ENOSPC);
}
}
printf("exec type %x is already installed\n",
*eswp->exec_magic);
return (EBUSY); /* it's already there! */
}
return (0);
}
/*
* Remove an exec module.
*/
static int
{
char *modname;
return (EINVAL);
}
if (moddebug & MODDEBUG_NOAUL_EXEC ||
return (EBUSY);
return (0);
}
/*
* Find a free sysent entry or check if the specified one is free.
*/
static struct sysent *
{
int sysnum;
char *mod_name;
/*
* This happens when we're looking up the module
* pointer as part of a stub installation. So
* there's no need to whine at this point.
*/
return (NULL);
}
return (NULL);
}
return (NULL);
}
/*
* IP Policy Modules.
*/
/*ARGSUSED*/
static int
{
*p0 = -1;
return (0); /* module is not yet installed */
}
return (0);
}
static int
{
}
/*ARGSUSED*/
static int
{
extern kthread_id_t mod_aul_thread;
return (EBUSY);
return (ipp_mod_unregister(mid));
}
/*
* Manage kiconv modules.
*/
/*ARGSUSED*/
static int
{
}
/*ARGSUSED*/
static int
{
}