smp.c revision 96c4a178a18cd52ee5001195f1552d9cef0c38f0
/*
* 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.
*/
/*
* SMP - Serial Management Protocol Device Driver
*
* The SMP driver provides user programs access to SAS Serial Management
* Protocol devices by providing ioctl interface.
*/
/*
* Standard entrypoints
*/
/*
* Configuration routines
*/
static int smp_do_attach(dev_info_t *);
static int smp_do_detach(dev_info_t *);
/*
* Command handle routing
*/
/*
*/
static void smp_log(smp_state_t *, int, const char *, ...);
static int smp_retry_recovered = 0; /* retry recovery counter */
static int smp_retry_failed = 0; /* retry failed counter */
static int smp_failed = 0;
static struct cb_ops smp_cb_ops = {
smp_open, /* open */
smp_close, /* close */
nodev, /* strategy */
nodev, /* print */
nodev, /* dump */
nodev, /* read */
nodev, /* write */
smp_ioctl, /* ioctl */
nodev, /* devmap */
nodev, /* mmap */
nodev, /* segmap */
nochpoll, /* poll */
ddi_prop_op, /* cb_prop_op */
0, /* streamtab */
};
static struct dev_ops smp_dev_ops = {
DEVO_REV, /* devo_rev, */
0, /* refcnt */
ddi_getinfo_1to1, /* info */
nulldev, /* identify */
NULL, /* probe */
smp_attach, /* attach */
smp_detach, /* detach */
nodev, /* reset */
&smp_cb_ops, /* driver operations */
(struct bus_ops *)0, /* bus operations */
NULL, /* power */
ddi_quiesce_not_needed, /* quiesce */
};
static void *smp_soft_state = NULL;
};
static struct modlinkage modlinkage = {
};
int
_init(void)
{
int err;
sizeof (smp_state_t), SMP_ESTIMATED_NUM_DEVS)) != 0) {
return (err);
}
}
return (err);
}
int
_fini(void)
{
int err;
}
return (err);
}
int
{
}
/*
* smp_attach()
* attach(9e) entrypoint.
*/
static int
{
int err;
switch (cmd) {
case DDI_ATTACH:
break;
case DDI_RESUME:
err = DDI_SUCCESS;
break;
default:
err = DDI_FAILURE;
break;
}
if (err != DDI_SUCCESS) {
"device unit-address @%s failed",
}
return (err);
}
/*
* smp_do_attach()
* handle the nitty details of attach.
*/
static int
{
int instance;
struct smp_device *smp_sd;
/* make sure device is there, and establish srmir identity property */
"!smp_do_attach: failed smp_probe, "
return (DDI_FAILURE);
}
/* if we have not already registered a devid, then do so now */
/* get the srmir identity information for use in devid */
/* Convert smp unit-address and srmir into devid */
/* register the devid */
}
}
/* We don't need the devid for our own operation, so free now. */
if (devid)
/* we are now done with srmir identity property defined by smp_probe */
(void) ndi_prop_remove(DDI_DEV_T_NONE,
"!smp_do_attach: failed to allocate softstate, "
return (DDI_FAILURE);
}
/*
* For simplicity, the minor number == the instance number
*/
"!smp_do_attach: minor node creation failed, "
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/*
* smp_detach()
* detach(9E) entrypoint
*/
static int
{
int instance;
"!smp_detach: failed, no softstate found (%d), "
"device unit-address @%s",
return (DDI_FAILURE);
}
switch (cmd) {
case DDI_DETACH:
return (smp_do_detach(dip));
case DDI_SUSPEND:
return (DDI_SUCCESS);
default:
return (DDI_FAILURE);
}
}
/*
* smp_do_detach()
* detach the driver, tearing down resources.
*/
static int
{
int instance;
return (DDI_SUCCESS);
}
/*ARGSUSED*/
static int
{
int instance;
int rv = 0;
== NULL) {
return (ENXIO);
}
} else {
}
} else {
} else {
}
}
return (rv);
}
/*ARGSUSED*/
static int
{
int instance;
int rv = 0;
== NULL) {
return (ENXIO);
}
} else {
}
return (rv);
}
/*ARGSUSED*/
static int
{
int instance, retrycount;
int rval = 0;
#ifdef _MULTI_DATAMODEL
#endif
/* require PRIV_SYS_DEVICES privilege */
cr = ddi_get_cred();
return (EPERM);
}
== NULL) {
return (ENXIO);
}
#ifdef _MULTI_DATAMODEL
case DDI_MODEL_ILP32:
flag)) {
return (EFAULT);
}
break;
case DDI_MODEL_NONE:
flag)) {
return (EFAULT);
}
break;
}
#else /* ! _MULTI_DATAMODEL */
return (EFAULT);
}
#endif /* _MULTI_DATAMODEL */
goto done;
}
/* allocate memory space for smp request and response frame in kernel */
KM_SLEEP);
KM_SLEEP);
/* copy smp request frame to kernel space */
goto done;
}
if (usmp_cmd->usmp_timeout <= 0) {
} else {
}
/* call smp_transport entry and send smp_pkt to HBA driver */
/*
* To improve transport reliability, only allow one command
* outstanding at a time in smp_transport().
*
* NOTE: Some expanders have issues with heavy smp load.
*/
if (smp_single_command) {
}
/* Let the transport know if more retries are possible. */
smp_pkt->smp_pkt_reason = 0;
if (smp_delay_cmd)
if (smp_single_command) {
}
if (rval == DDI_SUCCESS) {
if (retrycount)
rval = 0;
break;
}
switch (smp_pkt->smp_pkt_reason) {
case EAGAIN:
if (retrycount < smp_retry_times) {
if (smp_retry_delay)
continue;
} else {
"!smp_transport failed, smp_pkt_reason %d",
goto copyout;
}
default:
"!smp_transport failed, smp_pkt_reason %d",
goto copyout;
}
}
/* copy out smp response to user process */
}
done:
if ((cmd_flags & SMP_FLAG_XFER) != 0) {
}
if ((cmd_flags & SMP_FLAG_REQBUF) != 0) {
}
if ((cmd_flags & SMP_FLAG_RSPBUF) != 0) {
}
if (rval)
smp_failed++;
return (rval);
}
/*ARGSUSED*/
static int
{
int rval = 0;
switch (cmd) {
case USMPFUNC:
/*
* The response payload is valid only if return value is 0
* or EOVERFLOW.
*/
break;
default:
}
return (rval);
}
static void
{
char buf[256];
} else {
}
}