ds_pri.c revision 193974072f41a843678abf5f61979c748687e66b
/*
* 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 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* sun4v domain services PRI driver
*/
static uint_t ds_pri_debug = 0;
#define DS_PRI_NAME "ds_pri"
#define TEST_HARNESS
#ifdef TEST_HARNESS
#define DSIOC_TEST_REG 97
#define DSIOC_TEST_UNREG 98
#define DSIOC_TEST_DATA 99
struct ds_pri_test_data {
void *data;
};
struct ds_pri_test_data32 {
};
#endif /* TEST_HARNESS */
typedef enum {
DS_PRI_REQUEST = 0,
DS_PRI_DATA = 1,
DS_PRI_UPDATE = 2
typedef struct {
struct {
} hdr;
} ds_pri_msg_t;
/* The following are bit field flags */
/* No service implies no PRI and no outstanding request */
typedef enum {
DS_PRI_NO_SERVICE = 0x0,
DS_PRI_HAS_SERVICE = 0x1,
DS_PRI_REQUESTED = 0x2,
DS_PRI_HAS_PRI = 0x4
struct ds_pri_state {
int instance;
void *ds_pri;
int num_opens;
};
typedef struct ds_pri_state ds_pri_state_t;
static void *ds_pri_statep;
/*
* DS Callbacks
*/
/*
* PRI DS capability registration
*/
static ds_capability_t ds_pri_cap = {
"pri",
1
};
/*
* PRI DS Client callback vector
*/
static ds_clnt_ops_t ds_pri_ops = {
ds_pri_reg_handler, /* ds_reg_cb */
ds_pri_unreg_handler, /* ds_unreg_cb */
ds_pri_data_handler, /* ds_data_cb */
NULL /* cb_arg */
};
/*
* DS PRI driver Ops Vector
*/
static struct cb_ops ds_pri_cb_ops = {
ds_pri_open, /* cb_open */
ds_pri_close, /* cb_close */
nodev, /* cb_strategy */
nodev, /* cb_print */
nodev, /* cb_dump */
ds_pri_read, /* cb_read */
nodev, /* cb_write */
ds_pri_ioctl, /* cb_ioctl */
nodev, /* cb_devmap */
nodev, /* cb_mmap */
nodev, /* cb_segmap */
nochpoll, /* cb_chpoll */
ddi_prop_op, /* cb_prop_op */
CB_REV, /* cb_rev */
nodev, /* cb_aread */
nodev /* cb_awrite */
};
static struct dev_ops ds_pri_dev_ops = {
DEVO_REV, /* devo_rev */
0, /* devo_refcnt */
ds_pri_getinfo, /* devo_getinfo */
nulldev, /* devo_identify */
nulldev, /* devo_probe */
ds_pri_attach, /* devo_attach */
ds_pri_detach, /* devo_detach */
nodev, /* devo_reset */
&ds_pri_cb_ops, /* devo_cb_ops */
nulldev, /* devo_power */
ddi_quiesce_not_needed, /* devo_quiesce */
};
"Domain Services PRI Driver",
};
static struct modlinkage modlinkage = {
(void *)&modldrv,
};
int
_init(void)
{
int retval;
sizeof (ds_pri_state_t), 0);
if (retval != 0)
return (retval);
if (retval != 0) {
return (retval);
}
return (retval);
}
int
{
}
int
_fini(void)
{
int retval;
return (retval);
return (retval);
}
/*ARGSUSED*/
static int
{
int retval = DDI_FAILURE;
switch (cmd) {
case DDI_INFO_DEVT2DEVINFO:
} else
break;
case DDI_INFO_DEVT2INSTANCE:
break;
default:
break;
}
return (retval);
}
static int
{
int instance;
int rv;
switch (cmd) {
case DDI_ATTACH:
break;
case DDI_RESUME:
return (DDI_SUCCESS);
default:
return (DDI_FAILURE);
}
DDI_SUCCESS) {
return (DDI_FAILURE);
}
DDI_PSEUDO, 0) != DDI_SUCCESS) {
goto fail;
}
goto fail;
/* Until the service registers the handle is invalid */
sp->ds_pri_len = 0;
goto fail;
}
return (DDI_SUCCESS);
fail:
return (DDI_FAILURE);
}
/*ARGSUSED*/
static int
{
int instance;
int rv;
switch (cmd) {
case DDI_DETACH:
break;
case DDI_SUSPEND:
return (DDI_SUCCESS);
default:
return (DDI_FAILURE);
}
/* This really shouldn't fail - but check anyway */
}
return (DDI_SUCCESS);
}
/*ARGSUSED*/
static int
{
int instance;
return (EINVAL);
return (ENXIO);
/*
* If we're here and the state is DS_PRI_NO_SERVICE then this
* means that ds hasn't yet called the registration callback.
* A while loop is necessary as we might have been woken up
* prematurely, e.g., due to a debugger or "pstack" etc.
* Wait here and the callback will signal us when it has completed
* its work.
*/
return (EINTR);
}
}
/*
* On open we dont fetch the PRI even if we have a valid service
* handle. PRI fetch is essentially lazy and on-demand.
*/
return (0);
}
/*ARGSUSED*/
static int
{
int instance;
return (EINVAL);
DS_PRI_DBG("ds_pri_close\n");
return (ENXIO);
return (0);
}
return (0);
}
/* If we have an old PRI - remove it */
/*
* remove the old data if we have an
* outstanding request
*/
sp->ds_pri_len = 0;
}
}
return (0);
}
/*ARGSUSED*/
static int
{
int instance;
int retval;
return (ENXIO);
if (len == 0)
return (0);
/* block or bail if there is no current PRI */
DS_PRI_DBG("ds_pri_read: no PRI held\n");
return (EAGAIN);
}
return (EINTR);
}
}
}
return (EINVAL);
}
/* already checked that offset < ds_pri_len above */
if (len == 0) {
return (0);
}
/*
* We're supposed to move the data out to userland, but
* that can suspend because of page faults etc., and meanwhile
* other parts of this driver want to update the PRI buffer ...
* we could hold the data buffer locked with a flag etc.,
* but that's still a lock ... a simpler mechanism - if not quite
* as performance efficient is to simply clone here the part of
* the buffer we care about and then the original can be released
* for further updates while the uiomove continues.
*/
return (retval);
}
/*ARGSUSED*/
static int
int *rvalp)
{
int instance;
return (ENXIO);
switch (cmd) {
case DSPRI_GETINFO: {
struct dspri_info info;
return (EACCES);
/*
* We are not guaranteed that ddi_copyout(9F) will read
* atomically anything larger than a byte. Therefore we
* must duplicate the size before copying it out to the user.
*/
loop:;
/* If we have a PRI simply return the info */
} else
/* If we have no service return a nil response */
} else {
/* wait for something & check again */
return (EINTR);
}
goto loop;
}
DS_PRI_DBG("ds_pri_ioctl: DSPRI_GETINFO sz=0x%lx tok=0x%lx\n",
return (EFAULT);
break;
}
case DSPRI_WAIT: {
mode) != 0)
return (EFAULT);
DS_PRI_DBG("ds_pri_ioctl: DSPRI_WAIT gen=0x%lx sp->gen=0x%lx\n",
return (EINTR);
}
}
break;
}
default:
return (ENOTTY);
}
return (0);
}
/* assumes sp->lock is held when called */
static void
{
/* If a request is already pending we're done */
return;
return;
/* If we have an old PRI - remove it */
/* remove the old data if we have an outstanding request */
sp->ds_pri_len = 0;
} else {
}
/*
* Request consists of header only.
* We don't care about fail status for ds_send;
* if it does fail we will get an unregister callback
* from the DS framework and we handle the state change
* there.
*/
}
/*
* DS Callbacks
*/
/*ARGSUSED*/
static void
{
int instance;
return;
DS_PRI_DBG("ds_pri_reg_handler: registering handle 0x%lx for version "
/* When the domain service comes up automatically req the pri */
/* have service, but no PRI */
/*
* Cannot request a PRI here, because the reg handler cannot
* do a DS send operation - we take care of this later.
*/
/* Wake up anyone waiting in open() */
}
static void
{
int instance;
return;
DS_PRI_DBG("ds_pri_unreg_handler: un-registering ds_pri service\n");
/* Once the service goes - if we have a PRI at hand free it up */
if (sp->ds_pri_len != 0) {
sp->ds_pri_len = 0;
}
}
static void
{
int instance;
void *data;
/* make sure the header is at least valid */
return;
DS_PRI_DBG("ds_pri_data_handler: msg buf len 0x%lx : type 0x%lx, "
return;
case DS_PRI_DATA: /* in response to a request from us */
break;
case DS_PRI_UPDATE: /* aynch notification */
/* our default response to this is to request the PRI */
/* simply issue a request for the new PRI */
goto done;
default: /* ignore garbage or unknown message types */
goto done;
}
/*
* If there is no pending PRI request, then we've received a
* bogus data message ... so ignore it.
*/
goto done;
}
/* response to a request therefore old PRI must be gone */
/* response seq_num should match our request seq_num */
"request");
goto done;
}
done:;
}