summaryrefslogtreecommitdiff
path: root/usr/src/lib/fm/libldom/sparc/ldmsvcs_utils.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/fm/libldom/sparc/ldmsvcs_utils.c')
-rw-r--r--usr/src/lib/fm/libldom/sparc/ldmsvcs_utils.c1747
1 files changed, 0 insertions, 1747 deletions
diff --git a/usr/src/lib/fm/libldom/sparc/ldmsvcs_utils.c b/usr/src/lib/fm/libldom/sparc/ldmsvcs_utils.c
deleted file mode 100644
index be9e78cc3e..0000000000
--- a/usr/src/lib/fm/libldom/sparc/ldmsvcs_utils.c
+++ /dev/null
@@ -1,1747 +0,0 @@
-/*
- * 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
- * or http://www.opensolaris.org/os/licensing.
- * 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 (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-
-#include <strings.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <time.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <errno.h>
-#include <assert.h>
-#include <umem.h>
-#include <alloca.h>
-#include <sys/processor.h>
-#include <poll.h>
-#include <pthread.h>
-#include <signal.h>
-#include <values.h>
-#include <libscf.h>
-
-#include <ctype.h>
-
-#include "ldmsvcs_utils.h"
-#include "ldom_alloc.h"
-#include "ldom_utils.h"
-
-#define ASSERT(cnd) \
- ((void) ((cnd) || ((void) fprintf(stderr, \
- "assertion failure in %s:%d: %s\n", \
- __FILE__, __LINE__, #cnd), 0)))
-
-#define FDS_VLDC \
- "/devices/virtual-devices@100/channel-devices@200/" \
- "/virtual-channel-client@1:ldmfma"
-
-/* allow timeouts in sec that are nearly forever but small enough for an int */
-#define LDM_TIMEOUT_CEILING (MAXINT / 2)
-
-#define MIN(x, y) ((x) < (y) ? (x) : (y))
-
-/*
- * functions in this file are for version 1.0 of FMA domain services
- */
-static ds_ver_t ds_vers[] = {
- { 1, 0 }
-};
-
-#define DS_NUM_VER (sizeof (ds_vers) / sizeof (ds_ver_t))
-
-/*
- * information for each channel
- */
-struct ldmsvcs_info {
- pthread_mutex_t mt;
- pthread_cond_t cv;
- fds_channel_t fds_chan;
- fds_reg_svcs_t fmas_svcs;
- int cv_twait;
-};
-
-/*
- * struct listdata_s and struct poller_s are used to maintain the state of
- * the poller thread. this thread is used to manage incoming messages and
- * pass those messages onto the correct requesting thread. see the "poller
- * functions" section for more details.
- */
-struct listdata_s {
- enum {
- UNUSED,
- PENDING,
- ARRIVED
- } status;
- uint64_t req_num;
- int fd;
- size_t datalen;
-};
-
-static struct poller_s {
- pthread_mutex_t mt;
- pthread_cond_t cv;
- pthread_t polling_tid;
- int notify_pipe[2];
- int doreset;
- int doexit;
- int nclients;
- struct listdata_s **list;
- int list_len;
- int pending_count;
-} pollbase = {
- PTHREAD_MUTEX_INITIALIZER,
- PTHREAD_COND_INITIALIZER,
- 0,
- {-1, -1},
- 1,
- 0,
- 0,
- NULL,
- 0,
- 0
-};
-
-
-static struct ldmsvcs_info *channel_init(struct ldom_hdl *lhp);
-static int channel_openreset(struct ldmsvcs_info *lsp);
-static int read_msg(struct ldmsvcs_info *lsp);
-
-static int
-get_smf_int_val(char *prop_nm, int min, int max, int default_val)
-{
- scf_simple_prop_t *prop; /* SMF property */
- int64_t *valp; /* prop value ptr */
- int64_t val; /* prop value to return */
-
- val = default_val;
- if ((prop = scf_simple_prop_get(NULL, LDM_SVC_NM, LDM_PROP_GROUP_NM,
- prop_nm)) != NULL) {
- if ((valp = scf_simple_prop_next_integer(prop)) != NULL) {
- val = *valp;
- if (val < min)
- val = min;
- else if (val > max)
- val = max;
- }
- scf_simple_prop_free(prop);
- }
- return ((int)val);
-}
-
-static void
-channel_close(struct ldmsvcs_info *lsp)
-{
- (void) pthread_mutex_lock(&lsp->mt);
-
- if (lsp->fds_chan.state == CHANNEL_OPEN ||
- lsp->fds_chan.state == CHANNEL_READY) {
- (void) close(lsp->fds_chan.fd);
- lsp->cv_twait = get_smf_int_val(LDM_INIT_TO_PROP_NM,
- 0, LDM_TIMEOUT_CEILING, LDM_INIT_WAIT_TIME);
- lsp->fds_chan.state = CHANNEL_CLOSED;
- }
-
- (void) pthread_mutex_unlock(&lsp->mt);
-}
-
-/*
- * read size bytes of data from a streaming fd into buf
- */
-static int
-read_stream(int fd, void *buf, size_t size)
-{
- pollfd_t pollfd;
- ssize_t rv;
- size_t data_left;
- ptrdiff_t currentp;
-
- pollfd.events = POLLIN;
- pollfd.revents = 0;
- pollfd.fd = fd;
-
- currentp = (ptrdiff_t)buf;
- data_left = size;
-
- /*
- * data may come in bits and pieces
- */
- do {
- if ((rv = read(fd, (void *)currentp, data_left)) < 0) {
- if (errno == EAGAIN && poll(&pollfd, 1, 3000) > 0)
- continue; /* retry */
- else
- return (1);
- }
-
- data_left -= rv;
- currentp += rv;
- } while (data_left > 0);
-
- return (0);
-}
-
-
-/*
- * poller functions
- *
- * at init time, a thread is created for the purpose of monitoring incoming
- * messages and doing one of the following:
- *
- * 1. doing the initial handshake and version negotiation
- *
- * 2. handing incoming data off to the requesting thread (which is an fmd
- * module or scheme thread)
- */
-static int
-poller_handle_data(int fd, size_t payloadsize)
-{
- uint64_t *req_num;
- void *pr;
- size_t prlen;
- int i;
-
- prlen = sizeof (ds_data_handle_t) + sizeof (uint64_t);
-
- if (payloadsize < prlen)
- return (1);
-
- pr = alloca(prlen);
-
- if (read_stream(fd, pr, prlen) != 0)
- return (1);
-
- req_num = (uint64_t *)((ptrdiff_t)pr + sizeof (ds_data_handle_t));
-
- (void) pthread_mutex_lock(&pollbase.mt);
-
- for (i = 0; i < pollbase.list_len; i++) {
- if (pollbase.list[i]->req_num == *req_num) {
- ASSERT(pollbase.list[i]->status == PENDING);
-
- pollbase.list[i]->status = ARRIVED;
- pollbase.list[i]->fd = fd;
- pollbase.list[i]->datalen = payloadsize - prlen;
-
- pollbase.pending_count--;
- (void) pthread_cond_broadcast(&pollbase.cv);
- break;
- }
- }
-
- /*
- * now wait for receiving thread to read in the data
- */
- if (i < pollbase.list_len) {
- while (pollbase.list[i]->status == ARRIVED)
- (void) pthread_cond_wait(&pollbase.cv, &pollbase.mt);
- }
-
- (void) pthread_mutex_unlock(&pollbase.mt);
-
- return (0);
-}
-
-
-/*
- * note that this function is meant to handle only DS_DATA messages
- */
-static int
-poller_recv_data(struct ldom_hdl *lhp, uint64_t req_num, int index,
- void **resp, size_t *resplen)
-{
- struct timespec twait;
- int ier;
-
- ier = 0;
- twait.tv_sec = time(NULL) + lhp->lsinfo->cv_twait;
- twait.tv_nsec = 0;
-
- (void) pthread_mutex_lock(&pollbase.mt);
-
- ASSERT(pollbase.list[index]->req_num == req_num);
-
- while (pollbase.list[index]->status == PENDING &&
- pollbase.doreset == 0 && ier == 0)
- ier = pthread_cond_timedwait(&pollbase.cv, &pollbase.mt,
- &twait);
-
- if (ier == 0) {
- if (pollbase.doreset == 0) {
- ASSERT(pollbase.list[index]->status == ARRIVED);
-
- /*
- * need to add req_num to beginning of resp
- */
- *resplen = pollbase.list[index]->datalen +
- sizeof (uint64_t);
- *resp = lhp->allocp(*resplen);
- *((uint64_t *)*resp) = req_num;
-
- if (read_stream(pollbase.list[index]->fd,
- (void *)((ptrdiff_t)*resp + sizeof (uint64_t)),
- *resplen - sizeof (uint64_t)) != 0)
- ier = ETIMEDOUT;
-
- pollbase.list[index]->status = UNUSED;
- pollbase.list[index]->req_num = 0;
- (void) pthread_cond_broadcast(&pollbase.cv);
- } else {
- if (--(pollbase.pending_count) == 0)
- (void) pthread_cond_broadcast(&pollbase.cv);
- }
- }
-
- (void) pthread_mutex_unlock(&pollbase.mt);
-
- ASSERT(ier == 0 || ier == ETIMEDOUT);
-
- return (ier);
-}
-
-
-static void
-poller_add_client(void)
-{
- (void) pthread_mutex_lock(&pollbase.mt);
- pollbase.nclients++;
- (void) pthread_mutex_unlock(&pollbase.mt);
-}
-
-
-static void
-poller_remove_client(void)
-{
- (void) pthread_mutex_lock(&pollbase.mt);
- pollbase.nclients--;
- ASSERT(pollbase.nclients >= 0);
- (void) pthread_mutex_unlock(&pollbase.mt);
-}
-
-
-static int
-poller_add_pending(uint64_t req_num)
-{
- int newlen, index, i, j;
-
- (void) pthread_mutex_lock(&pollbase.mt);
- pollbase.pending_count++;
-
- for (j = 0, index = -1; j < 2 && index == -1; j++) {
- for (i = 0; i < pollbase.list_len; i++) {
- if (pollbase.list[i]->status == UNUSED) {
- pollbase.list[i]->status = PENDING;
- pollbase.list[i]->req_num = req_num;
- pollbase.list[i]->datalen = 0;
- index = i;
- break;
- }
- }
-
- if (index == -1) {
- struct listdata_s **newlist, **oldlist;
-
- /*
- * get to this point if list is not long enough.
- * check for a runaway list. since requests are
- * synchronous (clients send a request and need to
- * wait for the result before returning) the size
- * of the list cannot be much more than the number
- * of clients.
- */
- ASSERT(pollbase.list_len < pollbase.nclients + 1);
-
- newlen = pollbase.list_len + 5;
- newlist = ldom_alloc(newlen *
- sizeof (struct listdata_s *));
-
- for (i = 0; i < pollbase.list_len; i++)
- newlist[i] = pollbase.list[i];
-
- oldlist = pollbase.list;
- pollbase.list = newlist;
- ldom_free(oldlist, pollbase.list_len *
- sizeof (struct listdata_s *));
-
- for (i = pollbase.list_len; i < newlen; i++) {
- pollbase.list[i] =
- ldom_alloc(sizeof (struct listdata_s));
- pollbase.list[i]->status = UNUSED;
- }
-
- pollbase.list_len = newlen;
- }
- }
-
- (void) pthread_mutex_unlock(&pollbase.mt);
- ASSERT(index != -1);
-
- return (index);
-}
-
-
-static void
-poller_delete_pending(uint64_t req_num, int index)
-{
- (void) pthread_mutex_lock(&pollbase.mt);
-
- ASSERT(pollbase.list[index]->req_num == req_num);
- pollbase.list[index]->status = UNUSED;
-
- if (--(pollbase.pending_count) == 0 && pollbase.doreset == 1)
- (void) pthread_cond_broadcast(&pollbase.cv);
-
- (void) pthread_mutex_unlock(&pollbase.mt);
-}
-
-
-static void
-poller_shutdown(boolean_t wait)
-{
- (void) pthread_mutex_lock(&pollbase.mt);
-
- pollbase.doexit = 1;
-
- (void) pthread_mutex_unlock(&pollbase.mt);
-
- if (wait == B_TRUE) {
- /*
- * Write a byte to the pipe to notify the poller thread to exit.
- * Then wait for it to exit.
- */
- (void) write(pollbase.notify_pipe[0], "1", 1);
- (void) pthread_join(pollbase.polling_tid, NULL);
- }
-}
-
-
-/*
- * perform the polling of incoming messages. manage any resets (usually
- * due to one end of the connection being closed) as well as exit
- * conditions.
- */
-static void *
-poller_loop(void *arg)
-{
- struct ldmsvcs_info *lsp;
- pollfd_t pollfd[2];
- struct pollfd *pipe_fd = &pollfd[0];
- struct pollfd *recv_fd = &pollfd[1];
- int ier;
-
- lsp = (struct ldmsvcs_info *)arg;
-
- for (;;) {
- (void) pthread_mutex_lock(&pollbase.mt);
-
- if (pollbase.doexit) {
- (void) pthread_mutex_unlock(&pollbase.mt);
- break;
- }
-
- if (pollbase.doreset) {
- int i;
-
- while (pollbase.pending_count > 0)
- (void) pthread_cond_wait(&pollbase.cv,
- &pollbase.mt);
-
- ASSERT(pollbase.pending_count == 0);
- for (i = 0; i < pollbase.list_len; i++)
- pollbase.list[i]->status = UNUSED;
-
- pollbase.doreset = 0;
- }
-
- (void) pthread_mutex_unlock(&pollbase.mt);
-
- if ((ier = channel_openreset(lsp)) == 1) {
- continue;
- } else if (ier == 2) {
- /*
- * start exit preparations
- */
- poller_shutdown(B_FALSE);
- continue;
- }
-
- pipe_fd->fd = pollbase.notify_pipe[1]; /* notification pipe */
- pipe_fd->events = POLLIN;
- pipe_fd->revents = 0;
- recv_fd->fd = lsp->fds_chan.fd; /* FMA LDC */
- recv_fd->events = POLLIN;
- recv_fd->revents = 0;
-
- if (poll(pollfd, 2, -1) <= 0) {
- /* fd got closed */
- (void) pthread_mutex_lock(&pollbase.mt);
- pollbase.doreset = 1;
- (void) pthread_mutex_unlock(&pollbase.mt);
- channel_close(lsp);
- } else if (pipe_fd->revents & POLLIN) {
- /* Receive a notification to exit */
- channel_close(lsp);
- pthread_exit((void *)NULL);
- } else if (read_msg(lsp) != 0) {
- /* fail to read a message from the LDOM manager */
- (void) pthread_mutex_lock(&pollbase.mt);
- pollbase.doreset = 1;
- (void) pthread_mutex_unlock(&pollbase.mt);
- channel_close(lsp);
- }
- }
-
- return (NULL);
-}
-
-
-/*
- * create the polling thread
- */
-static int
-poller_init(struct ldmsvcs_info *lsp)
-{
- int rc = 0;
-
- (void) pthread_mutex_lock(&pollbase.mt);
-
- if (pollbase.polling_tid == 0) {
- pthread_attr_t *attr = NULL;
-
- /*
- * create a joinable polling thread for receiving messages
- * The notify pipe is for stopping the thread
- */
- (void) notify_setup(pollbase.notify_pipe);
- if (pthread_create(&pollbase.polling_tid, attr,
- poller_loop, lsp) != 0)
- rc = 1;
- }
-
- (void) pthread_mutex_unlock(&pollbase.mt);
-
- return (rc);
-}
-
-/*
- * Cleanup the polling thread
- */
-static void
-poller_fini(void)
-{
- int i;
-
- /* stop the poller thread */
- poller_shutdown(B_TRUE);
-
- (void) pthread_mutex_lock(&pollbase.mt);
-
- /* Free up the list of outstanding requests */
- if (pollbase.list != NULL) {
- for (i = 0; i < pollbase.list_len; i++) {
- if (pollbase.list[i]) {
- ldom_free(pollbase.list[i],
- sizeof (struct listdata_s));
- }
- }
- ldom_free(pollbase.list, pollbase.list_len *
- sizeof (struct listdata_s *));
- pollbase.list = NULL;
- pollbase.list_len = 0;
- }
-
- (void) pthread_mutex_unlock(&pollbase.mt);
-}
-
-/*
- * utilities for message handlers
- */
-static int
-fds_send(struct ldmsvcs_info *lsp, void *msg, size_t msglen)
-{
- static pthread_mutex_t mt = PTHREAD_MUTEX_INITIALIZER;
-
- (void) pthread_mutex_lock(&mt);
-
- if (write(lsp->fds_chan.fd, msg, msglen) != msglen) {
- channel_close(lsp);
- (void) pthread_mutex_unlock(&mt);
- return (ETIMEDOUT);
- }
-
- (void) pthread_mutex_unlock(&mt);
- return (0);
-}
-
-
-/*
- * Find the max and min version supported
- */
-static void
-fds_min_max_versions(uint16_t *min_major, uint16_t *max_major)
-{
- int i;
-
- *min_major = ds_vers[0].major;
- *max_major = *min_major;
-
- for (i = 1; i < DS_NUM_VER; i++) {
- if (ds_vers[i].major < *min_major)
- *min_major = ds_vers[i].major;
-
- if (ds_vers[i].major > *max_major)
- *max_major = ds_vers[i].major;
- }
-}
-
-/*
- * check whether the major and minor numbers requested by remote ds client
- * can be satisfied. if the requested major is supported, true is
- * returned, and the agreed minor is returned in new_minor. if the
- * requested major is not supported, the routine returns false, and the
- * closest major is returned in *new_major, upon which the ds client should
- * renegotiate. the closest major is the just lower that the requested
- * major number.
- */
-static boolean_t
-fds_negotiate_version(uint16_t req_major, uint16_t *new_majorp,
- uint16_t *new_minorp)
-{
- int i = 0;
- uint16_t major, lower_major;
- uint16_t min_major, max_major;
- boolean_t found_match = B_FALSE;
-
- fds_min_max_versions(&min_major, &max_major);
-
- /*
- * if the minimum version supported is greater than the version
- * requested, return the lowest version supported
- */
- if (min_major > req_major) {
- *new_majorp = min_major;
- return (B_FALSE);
- }
-
- /*
- * if the largest version supported is lower than the version
- * requested, return the largest version supported
- */
- if (max_major < req_major) {
- *new_majorp = max_major;
- return (B_FALSE);
- }
-
- /*
- * now we know that the requested version lies between the min and
- * max versions supported. check if the requested major can be
- * found in supported versions.
- */
- lower_major = min_major;
- for (i = 0; i < DS_NUM_VER; i++) {
- major = ds_vers[i].major;
- if (major == req_major) {
- found_match = B_TRUE;
- *new_minorp = ds_vers[i].minor;
- *new_majorp = major;
- break;
- } else if ((major < req_major) && (major > lower_major))
- lower_major = major;
- }
-
- /*
- * If no match is found, return the closest available number
- */
- if (!found_match)
- *new_majorp = lower_major;
-
- return (found_match);
-}
-
-
-/*
- * return 0 if service is added; 1 if service is a duplicate
- */
-static int
-fds_svc_add(struct ldmsvcs_info *lsp, ds_reg_req_t *req, int minor)
-{
- fds_svc_t *svc;
- int i, rc;
-
- svc = NULL;
- for (i = 0; i < lsp->fmas_svcs.nsvcs; i++) {
- if (strcmp(lsp->fmas_svcs.tbl[i]->name, req->svc_id) == 0) {
- svc = lsp->fmas_svcs.tbl[i];
- break;
- }
- }
-
- if (svc == NULL)
- return (0); /* we don't need this service */
-
- (void) pthread_mutex_lock(&lsp->fmas_svcs.mt);
-
- /*
- * duplicate registration is OK --- we retain the previous entry
- * (which has not been unregistered anyway)
- */
- if (svc->state == DS_SVC_ACTIVE) {
- rc = 1;
- } else {
- svc->state = DS_SVC_ACTIVE;
- svc->hdl = req->svc_handle;
- svc->ver.major = req->major_vers;
- svc->ver.minor = minor;
-
- rc = 0;
- (void) pthread_cond_broadcast(&lsp->fmas_svcs.cv);
- }
-
- (void) pthread_mutex_unlock(&lsp->fmas_svcs.mt);
-
- return (rc);
-}
-
-
-static void
-fds_svc_reset(struct ldmsvcs_info *lsp, int index)
-{
- int i, start, end;
-
- if (index >= 0) {
- start = index;
- end = index + 1;
- } else {
- start = 0;
- end = lsp->fmas_svcs.nsvcs;
- }
-
- (void) pthread_mutex_lock(&lsp->fmas_svcs.mt);
-
- for (i = start; i < end; i++) {
- lsp->fmas_svcs.tbl[i]->hdl = 0;
- lsp->fmas_svcs.tbl[i]->state = DS_SVC_INVAL;
- lsp->fmas_svcs.tbl[i]->ver.major =
- ds_vers[DS_NUM_VER - 1].major;
- lsp->fmas_svcs.tbl[i]->ver.minor =
- ds_vers[DS_NUM_VER - 1].minor;
- }
-
- (void) pthread_mutex_unlock(&lsp->fmas_svcs.mt);
-}
-
-
-static int
-fds_svc_remove(struct ldmsvcs_info *lsp, ds_svc_hdl_t svc_handle)
-{
- int i;
-
- for (i = 0; i < lsp->fmas_svcs.nsvcs; i++) {
- if (lsp->fmas_svcs.tbl[i]->hdl == svc_handle) {
- fds_svc_reset(lsp, i);
- return (0);
- }
- }
-
- return (1);
-}
-
-
-/*
- * message handlers
- */
-/*ARGSUSED*/
-static void
-ds_handle_msg_noop(struct ldmsvcs_info *lsp, void *buf, size_t len)
-{
-}
-
-static void
-ds_handle_init_req(struct ldmsvcs_info *lsp, void *buf, size_t len)
-{
- ds_init_req_t *req;
- uint16_t new_major, new_minor;
- size_t msglen;
-
- req = (ds_init_req_t *)buf;
-
- /* sanity check the incoming message */
- if (len != sizeof (ds_init_req_t)) {
- channel_close(lsp);
- return;
- }
-
- /*
- * Check version info. ACK only if the major numbers exactly
- * match. The service entity can retry with a new minor
- * based on the response sent as part of the NACK.
- */
- if (fds_negotiate_version(req->major_vers, &new_major, &new_minor)) {
- ds_hdr_t *H;
- ds_init_ack_t *R;
-
- msglen = sizeof (ds_hdr_t) + sizeof (ds_init_ack_t);
- H = alloca(msglen);
- R = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t));
-
- H->msg_type = DS_INIT_ACK;
- H->payload_len = sizeof (ds_init_ack_t);
- R->minor_vers = MIN(new_minor, req->minor_vers);
-
- if (fds_send(lsp, H, msglen) != 0)
- return;
-
- (void) pthread_mutex_lock(&lsp->mt);
- ASSERT(lsp->fds_chan.state == CHANNEL_OPEN);
- lsp->fds_chan.state = CHANNEL_READY;
-
- /*
- * Now the channel is ready after the handshake completes.
- * Reset the timeout to a smaller value for receiving messages
- * from the domain services.
- */
- lsp->cv_twait = get_smf_int_val(LDM_RUNNING_TO_PROP_NM,
- 0, LDM_TIMEOUT_CEILING, LDM_RUNNING_WAIT_TIME);
-
- (void) pthread_mutex_unlock(&lsp->mt);
- } else {
- ds_hdr_t *H;
- ds_init_nack_t *R;
-
- msglen = sizeof (ds_hdr_t) + sizeof (ds_init_nack_t);
- H = alloca(msglen);
- R = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t));
-
- H->msg_type = DS_INIT_NACK;
- H->payload_len = sizeof (ds_init_nack_t);
- R->major_vers = new_major;
-
- (void) fds_send(lsp, H, msglen);
- /*
- * do not update state; remote end may attempt to initiate
- * connection with a different version
- */
- }
-}
-
-
-/*ARGSUSED*/
-static void
-ds_handle_reg_req(struct ldmsvcs_info *lsp, void *buf, size_t len)
-{
- ds_reg_req_t *req;
- char *msg;
- uint16_t new_major, new_minor;
- size_t msglen;
- int dup_svcreg = 0;
-
- req = (ds_reg_req_t *)buf;
- msg = (char *)req->svc_id;
-
- /*
- * Service must be NULL terminated
- */
- if (req->svc_id == NULL || strlen(req->svc_id) == 0 ||
- msg[strlen(req->svc_id)] != '\0') {
- channel_close(lsp);
- return;
- }
-
- if (fds_negotiate_version(req->major_vers, &new_major, &new_minor) &&
- (dup_svcreg = fds_svc_add(lsp, req,
- MIN(new_minor, req->minor_vers))) == 0) {
-
- /*
- * Check version info. ACK only if the major numbers
- * exactly match. The service entity can retry with a new
- * minor based on the response sent as part of the NACK.
- */
- ds_hdr_t *H;
- ds_reg_ack_t *R;
-
- msglen = sizeof (ds_hdr_t) + sizeof (ds_reg_ack_t);
- H = alloca(msglen);
- bzero(H, msglen);
- R = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t));
-
- H->msg_type = DS_REG_ACK;
- H->payload_len = sizeof (ds_reg_ack_t);
- R->svc_handle = req->svc_handle;
- R->minor_vers = MIN(new_minor, req->minor_vers);
-
- (void) fds_send(lsp, H, msglen);
- } else {
- ds_hdr_t *H;
- ds_reg_nack_t *R;
-
- msglen = sizeof (ds_hdr_t) + sizeof (ds_reg_nack_t);
- H = alloca(msglen);
- bzero(H, msglen);
- R = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t));
-
- H->msg_type = DS_REG_NACK;
- H->payload_len = sizeof (ds_reg_nack_t);
- R->svc_handle = req->svc_handle;
- R->major_vers = new_major;
-
- if (dup_svcreg)
- R->result = DS_REG_DUP;
- else
- R->result = DS_REG_VER_NACK;
-
- (void) fds_send(lsp, H, msglen);
- }
-}
-
-
-/*ARGSUSED*/
-static void
-ds_handle_unreg(struct ldmsvcs_info *lsp, void *buf, size_t len)
-{
- ds_unreg_req_t *req;
- size_t msglen;
-
- req = (ds_unreg_req_t *)buf;
-
- if (fds_svc_remove(lsp, req->svc_handle) == 0) {
- ds_hdr_t *H;
- ds_unreg_ack_t *R;
-
- msglen = sizeof (ds_hdr_t) + sizeof (ds_unreg_ack_t);
- H = alloca(msglen);
- R = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t));
-
- H->msg_type = DS_REG_ACK;
- H->payload_len = sizeof (ds_unreg_ack_t);
- R->svc_handle = req->svc_handle;
-
- (void) fds_send(lsp, H, msglen);
- } else {
- ds_hdr_t *H;
- ds_unreg_nack_t *R;
-
- msglen = sizeof (ds_hdr_t) + sizeof (ds_unreg_nack_t);
- H = alloca(msglen);
- R = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t));
-
- H->msg_type = DS_REG_NACK;
- H->payload_len = sizeof (ds_unreg_nack_t);
- R->svc_handle = req->svc_handle;
-
- (void) fds_send(lsp, H, msglen);
- }
-}
-
-
-/*
- * Message handler lookup table (v1.0 only for now) Future
- * versions can add their own lookup table.
- */
-typedef void (*ds_msg_handler_t)(struct ldmsvcs_info *lsp,
- void *buf, size_t len);
-
-static const ds_msg_handler_t ds_msg_handlers[] = {
- ds_handle_init_req, /* DS_INIT_REQ */
- ds_handle_msg_noop, /* DS_INIT_ACK */
- ds_handle_msg_noop, /* DS_INIT_NACK */
- ds_handle_reg_req, /* DS_REG_REQ */
- ds_handle_msg_noop, /* DS_REG_ACK */
- ds_handle_msg_noop, /* DS_REG_NACK */
- ds_handle_unreg, /* DS_UNREG */
- ds_handle_msg_noop, /* DS_UNREG_ACK */
- ds_handle_msg_noop, /* DS_UNREG_NACK */
- ds_handle_msg_noop, /* DS_DATA */
- ds_handle_msg_noop /* DS_NACK */
-};
-
-
-/*
- * message and service internal functions
- */
-static void
-fds_svc_alloc(struct ldmsvcs_info *lsp)
-{
- int i;
- static char *name[] = { LDM_DS_NAME_CPU, LDM_DS_NAME_MEM,
- LDM_DS_NAME_PRI, LDM_DS_NAME_IOD, NULL };
-
- (void) pthread_mutex_init(&lsp->fmas_svcs.mt, NULL);
- (void) pthread_cond_init(&lsp->fmas_svcs.cv, NULL);
-
- for (lsp->fmas_svcs.nsvcs = 0; name[lsp->fmas_svcs.nsvcs] != NULL;
- lsp->fmas_svcs.nsvcs++)
- ;
-
- lsp->fmas_svcs.tbl = (fds_svc_t **)ldom_alloc(sizeof (fds_svc_t *) *
- lsp->fmas_svcs.nsvcs);
-
- for (i = 0; i < lsp->fmas_svcs.nsvcs; i++) {
- lsp->fmas_svcs.tbl[i] =
- (fds_svc_t *)ldom_alloc(sizeof (fds_svc_t));
- bzero(lsp->fmas_svcs.tbl[i], sizeof (fds_svc_t));
- lsp->fmas_svcs.tbl[i]->name = name[i];
- }
-}
-
-
-static fds_svc_t *
-fds_svc_lookup(struct ldmsvcs_info *lsp, char *name)
-{
- struct timespec twait;
- fds_svc_t *svc;
- int i, ier;
-
- if (pthread_mutex_lock(&lsp->fmas_svcs.mt) == EINVAL)
- return (NULL); /* uninitialized or destroyed mutex */
-
- svc = NULL;
- for (i = 0; i < lsp->fmas_svcs.nsvcs; i++) {
- if (strcmp(lsp->fmas_svcs.tbl[i]->name, name) == 0) {
- svc = lsp->fmas_svcs.tbl[i];
- break;
- }
- }
-
- ASSERT(svc != NULL);
-
- if (svc->state == DS_SVC_INACTIVE) {
- /* service is not registered */
- ier = ETIMEDOUT;
- } else {
- ier = 0;
- twait.tv_sec = time(NULL) + lsp->cv_twait;
- twait.tv_nsec = 0;
-
- while (svc->state != DS_SVC_ACTIVE && ier == 0 &&
- lsp->fds_chan.state != CHANNEL_UNUSABLE)
- ier = pthread_cond_timedwait(&lsp->fmas_svcs.cv,
- &lsp->fmas_svcs.mt, &twait);
-
- /*
- * By now, the ds service should have registered already.
- * If it does not, ldmd probably does not support this service.
- * Then mark the service state as inactive.
- */
- if (ier == ETIMEDOUT) {
- svc->state = DS_SVC_INACTIVE;
- }
- }
-
- (void) pthread_mutex_unlock(&lsp->fmas_svcs.mt);
-
- if (ier == 0)
- return (svc);
- else
- return (NULL);
-}
-
-
-static uint64_t
-fds_svc_req_num(void)
-{
- static uint64_t req_num = 1;
-
- return (req_num++);
-}
-
-
-/*
- * return 0 if successful, 1 if otherwise
- */
-static int
-read_msg(struct ldmsvcs_info *lsp)
-{
- ds_hdr_t header;
- void *msg_buf;
-
- /*
- * read the header
- */
- if (read_stream(lsp->fds_chan.fd, &header, sizeof (ds_hdr_t)) != 0)
- return (1);
-
- if (header.msg_type >=
- sizeof (ds_msg_handlers) / sizeof (ds_msg_handler_t))
- return (1);
-
- /*
- * handle data as a special case
- */
- if (header.msg_type == 9)
- return (poller_handle_data(lsp->fds_chan.fd,
- header.payload_len));
-
- /*
- * all other types of messages should be small
- */
- ASSERT(header.payload_len < 1024);
- msg_buf = alloca(header.payload_len);
-
- /*
- * read the payload
- */
- if (read_stream(lsp->fds_chan.fd, msg_buf, header.payload_len) != 0)
- return (1);
-
- (*ds_msg_handlers[header.msg_type])(lsp, msg_buf, header.payload_len);
-
- return (0);
-}
-
-
-/*
- * return values:
- * 0 - success
- * 1 - problem with opening the channel
- * 2 - channed not opened; request to exit has been detected
- */
-static int
-channel_openreset(struct ldmsvcs_info *lsp)
-{
- int ier;
-
- ier = pthread_mutex_lock(&lsp->mt);
-
- if (ier == EINVAL || lsp->fds_chan.state == CHANNEL_EXIT ||
- lsp->fds_chan.state == CHANNEL_UNUSABLE) {
- (void) pthread_mutex_unlock(&lsp->mt);
- return (2);
- }
-
- if (lsp->fds_chan.state == CHANNEL_UNINITIALIZED ||
- lsp->fds_chan.state == CHANNEL_CLOSED) {
- (void) pthread_cond_broadcast(&lsp->cv);
-
- if ((lsp->fds_chan.fd = open(FDS_VLDC, O_RDWR)) < 0) {
- lsp->fds_chan.state = CHANNEL_UNUSABLE;
- lsp->cv_twait = get_smf_int_val(LDM_RUNNING_TO_PROP_NM,
- 0, LDM_TIMEOUT_CEILING, LDM_RUNNING_WAIT_TIME);
- (void) pthread_mutex_unlock(&lsp->mt);
- (void) pthread_cond_broadcast(&lsp->fmas_svcs.cv);
-
- return (2);
- } else {
- vldc_opt_op_t op;
-
- op.op_sel = VLDC_OP_SET;
- op.opt_sel = VLDC_OPT_MODE;
- op.opt_val = LDC_MODE_RELIABLE;
-
- if (ioctl(lsp->fds_chan.fd, VLDC_IOCTL_OPT_OP,
- &op) != 0) {
- (void) close(lsp->fds_chan.fd);
- (void) pthread_mutex_unlock(&lsp->mt);
- return (1);
- }
- }
- lsp->fds_chan.state = CHANNEL_OPEN;
- }
-
- if (lsp->fds_chan.state == CHANNEL_OPEN) {
- /*
- * reset various channel parameters
- */
- lsp->fds_chan.ver.major = 0;
- lsp->fds_chan.ver.minor = 0;
- fds_svc_reset(lsp, -1);
- }
- (void) pthread_mutex_unlock(&lsp->mt);
-
- return (0);
-}
-
-
-static void
-channel_fini(void)
-{
- int i;
- struct ldmsvcs_info *lsp;
-
- /*
- * End the poller thread
- */
- poller_fini();
-
- if ((lsp = channel_init(NULL)) == NULL)
- return;
-
- (void) pthread_mutex_lock(&lsp->mt);
-
- lsp->fds_chan.state = CHANNEL_EXIT;
- (void) close(lsp->fds_chan.fd);
-
- (void) pthread_mutex_unlock(&lsp->mt);
-
- /* Free the ldom service structure */
- for (i = 0; i < lsp->fmas_svcs.nsvcs; i++) {
- ldom_free(lsp->fmas_svcs.tbl[i], sizeof (fds_svc_t));
- }
- ldom_free(lsp->fmas_svcs.tbl,
- lsp->fmas_svcs.nsvcs * sizeof (fds_svc_t *));
- ldom_free(lsp, sizeof (struct ldmsvcs_info));
-}
-
-
-static struct ldmsvcs_info *
-channel_init(struct ldom_hdl *lhp)
-{
- static pthread_mutex_t mt = PTHREAD_MUTEX_INITIALIZER;
- static pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
- static struct ldmsvcs_info *root = NULL;
- static int busy_init = 0;
-
- struct timespec twait;
- int expired;
-
- (void) pthread_mutex_lock(&mt);
-
- while (busy_init == 1)
- (void) pthread_cond_wait(&cv, &mt);
-
- if (root != NULL || (lhp == NULL && root == NULL)) {
- (void) pthread_mutex_unlock(&mt);
- return (root);
- }
-
- /*
- * get to this point if we need to open the channel
- */
- busy_init = 1;
- (void) pthread_mutex_unlock(&mt);
-
- root = (struct ldmsvcs_info *)
- ldom_alloc(sizeof (struct ldmsvcs_info));
- bzero(root, sizeof (struct ldmsvcs_info));
-
- root->fds_chan.state = CHANNEL_UNINITIALIZED;
- root->cv_twait = get_smf_int_val(LDM_INIT_TO_PROP_NM,
- 0, LDM_TIMEOUT_CEILING, LDM_INIT_WAIT_TIME);
-
- if (pthread_mutex_init(&root->mt, NULL) != 0 ||
- pthread_cond_init(&root->cv, NULL) != 0) {
- ldom_free(root, sizeof (struct ldmsvcs_info));
- return (NULL);
- }
-
- fds_svc_alloc(root);
- fds_svc_reset(root, -1);
-
- (void) poller_init(root);
-
- expired = 0;
- twait.tv_sec = time(NULL) + 10;
- twait.tv_nsec = 0;
-
- (void) pthread_mutex_lock(&root->mt);
-
- /*
- * wait for channel to become uninitialized. this should be quick.
- */
- while (root->fds_chan.state == CHANNEL_UNINITIALIZED && expired == 0)
- expired = pthread_cond_timedwait(&root->cv, &root->mt, &twait);
-
- if (root->fds_chan.state == CHANNEL_UNUSABLE)
- expired = 1;
-
- (void) pthread_mutex_unlock(&root->mt);
-
- (void) pthread_mutex_lock(&mt);
- busy_init = 0;
- (void) pthread_mutex_unlock(&mt);
- (void) pthread_cond_broadcast(&cv);
-
- (void) atexit(channel_fini);
-
- if (expired == 0)
- return (root);
- else
- return (NULL);
-}
-
-
-static int
-sendrecv(struct ldom_hdl *lhp, uint64_t req_num,
- void *msg, size_t msglen, ds_svc_hdl_t *svc_hdl, char *svcname,
- void **resp, size_t *resplen)
-{
- struct ldmsvcs_info *lsp;
- fds_svc_t *svc;
- int maxretries, index, i, ier;
-
- lsp = lhp->lsinfo;
- i = 0;
- maxretries = 1;
-
- do {
- /*
- * if any of the calls in this loop fail, retry some number
- * of times before giving up.
- */
- if ((svc = fds_svc_lookup(lsp, svcname)) == NULL) {
- (void) pthread_mutex_lock(&lsp->mt);
-
- if (lsp->fds_chan.state != CHANNEL_READY)
- ier = ETIMEDOUT; /* channel not ready */
- else
- ier = ENOTSUP; /* service not ready */
-
- (void) pthread_mutex_unlock(&lsp->mt);
-
- continue;
- } else {
- ier = 0;
- *svc_hdl = svc->hdl;
- }
-
- index = poller_add_pending(req_num);
-
- if ((ier = fds_send(lsp, msg, msglen)) != 0 ||
- (ier = poller_recv_data(lhp, req_num, index, resp,
- resplen)) != 0)
- poller_delete_pending(req_num, index);
-
- } while (i++ < maxretries && ier != 0);
-
- ASSERT(ier == 0 || ier == ETIMEDOUT || ier == ENOTSUP);
-
- return (ier);
-}
-
-
-/*
- * input:
- * msg_type - requested operation: FMA_CPU_REQ_STATUS or FMA_CPU_REQ_OFFLINE
- * cpuid - physical cpu id
- *
- * normal return values:
- * P_OFFLINE - cpu is offline
- * P_ONLINE - cpu is online
- *
- * abnormal return values:
- * ETIMEDOUT - LDOM manager is not responding
- * ENOTSUP - LDOM service for cpu offlining/status is not available
- * ENOMSG - got an unexpected response from the LDOM cpu service
- */
-static int
-cpu_request(struct ldom_hdl *lhp, uint32_t msg_type, uint32_t cpuid)
-{
- ds_hdr_t *H;
- ds_data_handle_t *D;
- fma_cpu_service_req_t *R;
-
- char *svcname = LDM_DS_NAME_CPU;
- fma_cpu_resp_t *respmsg;
- void *resp;
- size_t resplen, reqmsglen;
- int rc;
-
- if (lhp->lsinfo == NULL)
- return (ENOMSG);
-
- reqmsglen = sizeof (ds_hdr_t) + sizeof (ds_data_handle_t) +
- sizeof (fma_cpu_service_req_t);
-
- H = lhp->allocp(reqmsglen);
- D = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t));
- R = (void *)((ptrdiff_t)D + sizeof (ds_data_handle_t));
-
- H->msg_type = DS_DATA;
- H->payload_len = sizeof (ds_data_handle_t) +
- sizeof (fma_cpu_service_req_t);
-
- R->req_num = fds_svc_req_num();
- R->msg_type = msg_type;
- R->cpu_id = cpuid;
-
- if ((rc = sendrecv(lhp, R->req_num, H, reqmsglen,
- &D->svc_handle, svcname, &resp, &resplen)) != 0) {
- lhp->freep(H, reqmsglen);
- return (rc);
- }
-
- lhp->freep(H, reqmsglen);
-
- ASSERT(resplen == sizeof (fma_cpu_resp_t));
- respmsg = (fma_cpu_resp_t *)resp;
-
- rc = ENOMSG;
- if (respmsg->result == FMA_CPU_RESP_OK) {
- if (respmsg->status == FMA_CPU_STAT_ONLINE)
- rc = P_ONLINE;
- else if (respmsg->status == FMA_CPU_STAT_OFFLINE)
- rc = P_OFFLINE;
- } else {
- if (msg_type == FMA_CPU_REQ_OFFLINE &&
- respmsg->status == FMA_CPU_STAT_OFFLINE)
- rc = P_OFFLINE;
- }
-
- lhp->freep(resp, resplen);
-
- return (rc);
-}
-
-
-/*
- * input:
- * msg_type - requested operation: FMA_MEM_REQ_STATUS or FMA_MEM_REQ_RETIRE
- * pa - starting address of memory page
- * pgsize - memory page size in bytes
- *
- * normal return values for msg_type == FMA_MEM_REQ_STATUS:
- * 0 - page is retired
- * EAGAIN - page is scheduled for retirement
- * EIO - page not scheduled for retirement
- * EINVAL - error
- *
- * normal return values for msg_type == FMA_MEM_REQ_RETIRE:
- * 0 - success in retiring page
- * EIO - page is already retired
- * EAGAIN - page is scheduled for retirement
- * EINVAL - error
- *
- * abnormal return values (regardless of msg_type)
- * ETIMEDOUT - LDOM manager is not responding
- * ENOTSUP - LDOM service for cpu offlining/status is not available
- * ENOMSG - got an unexpected response from the LDOM cpu service
- */
-static int
-mem_request(struct ldom_hdl *lhp, uint32_t msg_type, uint64_t pa,
- uint64_t pgsize)
-{
- ds_hdr_t *H;
- ds_data_handle_t *D;
- fma_mem_service_req_t *R;
-
- char *svcname = LDM_DS_NAME_MEM;
- fma_mem_resp_t *respmsg;
- void *resp;
- size_t resplen, reqmsglen;
- int rc;
-
- if (lhp->lsinfo == NULL)
- return (ENOMSG);
-
- reqmsglen = sizeof (ds_hdr_t) + sizeof (ds_data_handle_t) +
- sizeof (fma_mem_service_req_t);
-
- H = lhp->allocp(reqmsglen);
- bzero(H, reqmsglen);
- D = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t));
- R = (void *)((ptrdiff_t)D + sizeof (ds_data_handle_t));
-
- H->msg_type = DS_DATA;
- H->payload_len = sizeof (ds_data_handle_t) +
- sizeof (fma_mem_service_req_t);
-
- R->req_num = fds_svc_req_num();
- R->msg_type = msg_type;
- R->real_addr = pa;
- R->length = pgsize;
-
- if ((rc = sendrecv(lhp, R->req_num, H, reqmsglen,
- &D->svc_handle, svcname, &resp, &resplen)) != 0) {
- lhp->freep(H, reqmsglen);
- return (rc);
- }
-
- lhp->freep(H, reqmsglen);
-
- ASSERT(resplen == sizeof (fma_mem_resp_t));
- respmsg = (fma_mem_resp_t *)resp;
-
- rc = ENOMSG;
- if (msg_type == FMA_MEM_REQ_STATUS) {
- if (respmsg->result == FMA_MEM_RESP_OK) {
- if (respmsg->status == FMA_MEM_STAT_RETIRED)
- rc = 0; /* page is retired */
- else if (respmsg->status == FMA_MEM_STAT_NOTRETIRED)
- rc = EIO; /* page is not scheduled */
- } else if (respmsg->result == FMA_MEM_RESP_FAILURE) {
- if (respmsg->status == FMA_MEM_STAT_NOTRETIRED)
- rc = EAGAIN; /* page is scheduled */
- else if (respmsg->status == FMA_MEM_STAT_ILLEGAL)
- rc = EINVAL;
- }
- } else if (msg_type == FMA_MEM_REQ_RETIRE) {
- if (respmsg->result == FMA_MEM_RESP_OK) {
- if (respmsg->status == FMA_MEM_STAT_RETIRED)
- rc = 0; /* is successfully retired */
- } else if (respmsg->result == FMA_MEM_RESP_FAILURE) {
- if (respmsg->status == FMA_MEM_STAT_RETIRED)
- rc = EIO; /* is already retired */
- else if (respmsg->status == FMA_MEM_STAT_NOTRETIRED)
- rc = EAGAIN; /* is scheduled to retire */
- else if (respmsg->status == FMA_MEM_STAT_ILLEGAL)
- rc = EINVAL;
- }
- } else if (msg_type == FMA_MEM_REQ_RESURRECT) {
- if (respmsg->result == FMA_MEM_RESP_OK) {
- if (respmsg->status == FMA_MEM_STAT_NOTRETIRED)
- rc = 0; /* is successfully unretired */
- } if (respmsg->result == FMA_MEM_RESP_FAILURE) {
- if (respmsg->status == FMA_MEM_STAT_RETIRED)
- rc = EAGAIN; /* page couldn't be locked */
- else if (respmsg->status == FMA_MEM_STAT_NOTRETIRED)
- rc = EIO; /* page isn't retired already */
- else if (respmsg->status == FMA_MEM_STAT_ILLEGAL)
- rc = EINVAL;
- }
- }
-
- lhp->freep(resp, resplen);
-
- return (rc);
-}
-
-
-/*
- * APIs
- */
-int
-ldmsvcs_check_channel(void)
-{
- struct stat buf;
-
- if (stat(FDS_VLDC, &buf) == 0)
- return (0); /* vldc exists */
- else if (errno == ENOENT || errno == ENOTDIR)
- return (1); /* vldc does not exist */
- else
- return (-1); /* miscellaneous error */
-}
-
-
-/*ARGSUSED*/
-void
-ldmsvcs_init(struct ldom_hdl *lhp)
-{
- if (ldmsvcs_check_channel() != 0)
- return;
-
- lhp->lsinfo = channel_init(lhp);
- poller_add_client();
-}
-
-
-/*ARGSUSED*/
-void
-ldmsvcs_fini(struct ldom_hdl *lhp)
-{
- if (ldmsvcs_check_channel() != 0)
- return;
-
- poller_remove_client();
-}
-
-
-/*ARGSUSED*/
-ssize_t
-ldmsvcs_get_core_md(struct ldom_hdl *lhp, uint64_t **buf)
-{
- ds_hdr_t *H;
- ds_data_handle_t *D;
- fma_req_pri_t *R;
-
- char *svcname = LDM_DS_NAME_PRI;
- void *resp;
- size_t resplen, reqmsglen;
- ssize_t buflen;
- int rc;
-
- if (lhp->lsinfo == NULL)
- return (-1);
-
- reqmsglen = sizeof (ds_hdr_t) + sizeof (ds_data_handle_t) +
- sizeof (fma_req_pri_t);
-
- H = lhp->allocp(reqmsglen);
- D = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t));
- R = (void *)((ptrdiff_t)D + sizeof (ds_data_handle_t));
-
- H->msg_type = DS_DATA;
- H->payload_len = sizeof (ds_data_handle_t) +
- sizeof (fma_req_pri_t);
-
- R->req_num = fds_svc_req_num();
-
- if ((rc = sendrecv(lhp, R->req_num, H, reqmsglen,
- &D->svc_handle, svcname, &resp, &resplen)) != 0) {
- lhp->freep(H, reqmsglen);
- errno = rc;
- return (-1);
- }
-
- lhp->freep(H, reqmsglen);
-
- /*
- * resp should contain the req_num immediately followed by the PRI
- * (the latter may or may not be present). unfortunately, the
- * current compiler flags cause a warning for the following
- * definition
- *
- * typedef struct {
- * uint64_t req_num;
- * uint8_t pri[];
- * } fma_pri_resp_t;
- *
- * so we do not use the struct here.
- */
- if (resplen <= sizeof (uint64_t)) {
- lhp->freep(resp, resplen);
- if (resplen == sizeof (uint64_t))
- return (0);
- else
- return (-1);
- }
-
- buflen = resplen - sizeof (uint64_t);
- *buf = lhp->allocp(buflen);
-
- bcopy((void *)((ptrdiff_t)resp + sizeof (uint64_t)), *buf, buflen);
- lhp->freep(resp, resplen);
-
- return (buflen);
-}
-
-
-/*
- * see cpu_request() for a description of return values
- */
-int
-ldmsvcs_cpu_req_status(struct ldom_hdl *lhp, uint32_t cpuid)
-{
- return (cpu_request(lhp, FMA_CPU_REQ_STATUS, cpuid));
-}
-
-
-int
-ldmsvcs_cpu_req_offline(struct ldom_hdl *lhp, uint32_t cpuid)
-{
- return (cpu_request(lhp, FMA_CPU_REQ_OFFLINE, cpuid));
-}
-
-int
-ldmsvcs_cpu_req_online(struct ldom_hdl *lhp, uint32_t cpuid)
-{
- return (cpu_request(lhp, FMA_CPU_REQ_ONLINE, cpuid));
-}
-
-/*
- * see mem_request() for a description of return values
- */
-int
-ldmsvcs_mem_req_status(struct ldom_hdl *lhp, uint64_t pa)
-{
- return (mem_request(lhp, FMA_MEM_REQ_STATUS, pa, getpagesize()));
-}
-
-int
-ldmsvcs_mem_req_retire(struct ldom_hdl *lhp, uint64_t pa)
-{
- return (mem_request(lhp, FMA_MEM_REQ_RETIRE, pa, getpagesize()));
-}
-
-int
-ldmsvcs_mem_req_unretire(struct ldom_hdl *lhp, uint64_t pa)
-{
- return (mem_request(lhp, FMA_MEM_REQ_RESURRECT, pa, getpagesize()));
-}
-
-int
-ldmsvcs_io_req_id(struct ldom_hdl *lhp, uint64_t addr, uint_t type,
- uint64_t *virt_addr, char *name, int name_len, uint64_t *did)
-{
-
- ds_hdr_t *H;
- ds_data_handle_t *D;
- fma_io_req_t *R;
-
- char *svcname = LDM_DS_NAME_IOD;
- void *resp;
- fma_io_resp_t *iop;
- size_t resplen, reqmsglen;
- int offset;
- int rc;
-
- if (lhp->lsinfo == NULL)
- return (-1);
-
- reqmsglen = sizeof (ds_hdr_t) + sizeof (ds_data_handle_t) +
- sizeof (fma_io_req_t);
-
- H = lhp->allocp(reqmsglen);
- D = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t));
- R = (void *)((ptrdiff_t)D + sizeof (ds_data_handle_t));
-
- H->msg_type = DS_DATA;
- H->payload_len = sizeof (ds_data_handle_t) + sizeof (fma_io_req_t);
-
- R->req_num = fds_svc_req_num();
- R->msg_type = type;
- R->rsrc_address = addr;
-
- rc = ENOMSG;
- if ((rc = sendrecv(lhp, R->req_num, H, reqmsglen,
- &D->svc_handle, svcname, &resp, &resplen)) != 0) {
- lhp->freep(H, reqmsglen);
- return (rc);
- }
- lhp->freep(H, reqmsglen);
-
- /*
- * resp should contain the req_num, status, virtual addr, domain id
- * and the domain name. The domain name may or may not be present.
- */
- offset = sizeof (fma_io_resp_t);
- if (resplen < offset) {
- lhp->freep(resp, resplen);
- return (-1);
- }
-
- iop = (fma_io_resp_t *)resp;
- switch (iop->result) {
- case FMA_IO_RESP_OK:
- /* success */
- rc = 0;
- *virt_addr = iop->virt_rsrc_address;
- *did = iop->domain_id;
- if (name == NULL || name_len <= 0)
- break;
- *name = '\0';
- if (resplen > offset) {
- (void) strncpy(name, (char *)((ptrdiff_t)resp + offset),
- name_len);
- }
- break;
- default:
- rc = -1;
- break;
- }
-
- lhp->freep(resp, resplen);
- return (rc);
-}
-
-/* end file */