diff options
| author | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
|---|---|---|
| committer | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
| commit | 7c478bd95313f5f23a4c958a745db2134aa03244 (patch) | |
| tree | c871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/lib/libpcp | |
| download | illumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz | |
OpenSolaris Launch
Diffstat (limited to 'usr/src/lib/libpcp')
| -rw-r--r-- | usr/src/lib/libpcp/Makefile | 46 | ||||
| -rw-r--r-- | usr/src/lib/libpcp/Makefile.com | 75 | ||||
| -rw-r--r-- | usr/src/lib/libpcp/common/libpcp.c | 1157 | ||||
| -rw-r--r-- | usr/src/lib/libpcp/common/libpcp.h | 100 | ||||
| -rw-r--r-- | usr/src/lib/libpcp/common/mapfile-vers | 37 | ||||
| -rw-r--r-- | usr/src/lib/libpcp/common/pcp_common.h | 110 | ||||
| -rw-r--r-- | usr/src/lib/libpcp/sparc/Makefile | 78 |
7 files changed, 1603 insertions, 0 deletions
diff --git a/usr/src/lib/libpcp/Makefile b/usr/src/lib/libpcp/Makefile new file mode 100644 index 0000000000..3c086c2988 --- /dev/null +++ b/usr/src/lib/libpcp/Makefile @@ -0,0 +1,46 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (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 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" +# +# lib/libpcp/Makefile + + +SUBDIRS= $(MACH) + +all := TARGET= all +clean := TARGET= clean +clobber := TARGET= clobber +install := TARGET= install +lint := TARGET= lint + +.KEEP_STATE: + +all clean clobber install lint : $(SUBDIRS) + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: diff --git a/usr/src/lib/libpcp/Makefile.com b/usr/src/lib/libpcp/Makefile.com new file mode 100644 index 0000000000..359f66a973 --- /dev/null +++ b/usr/src/lib/libpcp/Makefile.com @@ -0,0 +1,75 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (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 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# lib/libpcp/Makefile.com +# + +LIBRARY= libpcp.a +VERS= .1 + +# PLATFORM_OBJECTS is defined in platform Makefile +OBJECTS= $(PLATFORM_OBJECTS) + +include $(SRC)/lib/Makefile.lib +include $(SRC)/Makefile.psm + +MAPFILE = ../common/mapfile-vers + +DYNFLAGS += -M $(MAPFILE) + +CPPFLAGS += $(PLATINCS) -DPCP_CKSUM_ENABLE + +LINKED_DIRS = $(LINKED_PLATFORMS:%=$(USR_PLAT_DIR)/%) +LINKED_LIB_DIRS = $(LINKED_PLATFORMS:%=$(USR_PLAT_DIR)/%/lib) +LINKED_LIBPCP_DIR = \ + $(LINKED_PLATFORMS:%=$(USR_PLAT_DIR)/%/lib/libpcp.so) +LINKED_LIBPCP1_DIR = \ + $(LINKED_PLATFORMS:%=$(USR_PLAT_DIR)/%/lib/libpcp.so.1) +LINKED_LLIBLPCP_DIR = \ + $(LINKED_PLATFORMS:%=$(USR_PLAT_DIR)/%/lib/llib-lpcp.ln) + +SRCDIR = ../common +LIBS = $(DYNLIB) $(LINTLIB) +CFLAGS += $(CCVERBOSE) +LDLIBS += -lc -lumem +PLATLIBS = $(USR_PLAT_DIR)/$(PLATFORM)/lib/ +INS.slink6= $(RM) -r $@; $(SYMLINK) ../../$(PLATFORM)/lib/libpcp.so.1 $@ $(CHOWNLINK) $(CHGRPLINK) +INS.slink7= $(RM) -r $@; $(SYMLINK) ../../$(PLATFORM)/lib/libpcp.so $@ $(CHOWNLINK) $(CHGRPLINK) +INS.slink8= $(RM) -r $@; $(SYMLINK) ../../$(PLATFORM)/lib/llib-lpcp.ln $@ $(CHOWNLINK) $(CHGRPLINK) + +.KEEP_STATE: + +# +# build/lint rules +# +all: $(LIBS) + +lint: lintcheck + +$(DYNLIB): $(MAPFILE) + +include $(SRC)/lib/Makefile.targ diff --git a/usr/src/lib/libpcp/common/libpcp.c b/usr/src/lib/libpcp/common/libpcp.c new file mode 100644 index 0000000000..e7877a7cdb --- /dev/null +++ b/usr/src/lib/libpcp/common/libpcp.c @@ -0,0 +1,1157 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (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 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * Platform Channel Protocol Library functions on Nigara platforms + * (Ontario, Erie, etc..) Solaris applications use these interfaces + * to communicate with entities that reside on service processor. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <errno.h> +#include <signal.h> +#include <setjmp.h> +#include <inttypes.h> +#include <umem.h> +#include <strings.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/glvc.h> +#include <netinet/in.h> + +#include "libpcp.h" +#include "pcp_common.h" + +/* + * Following libpcp interfaces are exposed to user applications. + * + * int pcp_init(char *channel_dev_path); + * int pcp_send_recv(pcp_msg_t *req_msg, pcp_msg_t *resp_msg, uint32_t timeout); + * int pcp_close(void); + * + */ + +/* + * Forward declarations. + */ +static int pcp_send_req_msg_hdr(pcp_req_msg_hdr_t *req_hdr); +static int pcp_recv_resp_msg_hdr(pcp_resp_msg_hdr_t *resp_hdr); +static int pcp_io_op(void *buf, int byte_cnt, int io_op); +static int pcp_get_xid(void); +static int pcp_get_prop(int prop, unsigned int *val); +static int pcp_read(uint8_t *buf, int buf_len); +static int pcp_write(uint8_t *buf, int buf_len); +static int pcp_peek(uint8_t *buf, int buf_len); +static int pcp_peek_read(uint8_t *buf, int buf_len); +static int pcp_frame_error_handle(void); +static int check_magic_byte_presence(int byte_cnt, uint8_t *byte_val, + int *ispresent); +static uint16_t checksum(uint16_t *addr, int32_t count); +static int pcp_cleanup(void); + +/* + * glvc driver file descriptor + */ +static int chnl_fd = -1; + +/* + * Message Transaction ID + */ +static uint32_t msg_xid = 0; + +/* + * Channel MTU size. + */ +static unsigned int mtu_size = PCPL_DEF_MTU_SZ; + +/* + * timeout field is supplied by user. timeout field is used to decide + * how long to block on glvc driver calls before we return timeout error + * to user applications. + * + * Note: In the current implementation of glvc driver, all glvc calls are + * blocking. + */ +static uint32_t glvc_timeout = 0; + +/* + * variables used by setsetjmp/siglongjmp. + */ +static volatile sig_atomic_t jumpok = 0; +static sigjmp_buf jmpbuf; + +/* + * To unblock SIGALRM signal incase if it's blocked in libpcp user apps. + * Restore it to old state during pcp_close. + */ +static sigset_t blkset; + +/* + * Buffers used for stream reading channel data. When data is read in + * stream fashion, first data is copied from channel (glvc) buffers to + * these local buffers from which the read requests are serviced. + */ +#define READ_AREA_SIZE (2*mtu_size) +static uint8_t *read_head = NULL; +static uint8_t *read_tail = NULL; +static uint8_t *read_area = NULL; + +/* + * Buffer used for peeking new data available in channel (glvc) buffers. + */ +#define PEEK_AREA_SIZE (mtu_size) +static uint8_t *peek_area = NULL; + +/* + * Buffers used for peeking data available either in local buffers or + * new data available in channel (glvc) buffers. + */ +#define PEEK_READ_AREA_SIZE (2*mtu_size) +static uint8_t *peek_read_head = NULL; +static uint8_t *peek_read_tail = NULL; +static uint8_t *peek_read_area = NULL; + +static pcp_req_msg_hdr_t *req_msg_hdr = NULL; +static pcp_resp_msg_hdr_t *resp_msg_hdr = NULL; +static int req_msg_hdr_sz = 0; +static int resp_msg_hdr_sz = 0; + +/* + * signal handling variables to handle glvc blocking calls. + */ +static struct sigaction glvc_act; + +/* To restore old SIGALRM signal handler */ +static struct sigaction old_act; + +static void +glvc_timeout_handler(void) +{ + if (jumpok == 0) + return; + siglongjmp(jmpbuf, 1); +} + +/* + * Initialize the virtual channel. It basically opens the virtual channel + * provided by the host application. + * + */ + +int +pcp_init(char *channel_dev_path) +{ + sigset_t oldset; + + if (channel_dev_path == NULL) + return (PCPL_INVALID_ARGS); + /* + * Open virtual channel device node. + */ + if ((chnl_fd = open(channel_dev_path, O_RDWR|O_EXCL)) < 0) { + return (PCPL_GLVC_ERROR); + } + + /* + * Initialize Message Transaction ID. + */ + msg_xid = PCPL_INIT_XID; + + /* + * Get the Channel MTU size + */ + + if (pcp_get_prop(GLVC_XPORT_OPT_MTU_SZ, &mtu_size) != 0) { + (void) close(chnl_fd); + chnl_fd = -1; + return (PCPL_GLVC_ERROR); + } + + /* + * Get current signal mask. If SIGALRM is blocked + * unblock it. + */ + (void) sigprocmask(0, NULL, &oldset); + + (void) sigemptyset(&blkset); + + if (sigismember(&oldset, SIGALRM)) { + (void) sigaddset(&blkset, SIGALRM); + (void) sigprocmask(SIG_UNBLOCK, &blkset, NULL); + } + /* + * signal handler initialization to handle glvc call timeouts. + */ + glvc_act.sa_handler = glvc_timeout_handler; + (void) sigemptyset(&glvc_act.sa_mask); + glvc_act.sa_flags = SA_NODEFER; + + if (sigaction(SIGALRM, &glvc_act, &old_act) < 0) { + (void) close(chnl_fd); + chnl_fd = -1; + return (PCPL_ERROR); + } + + return (PCPL_OK); +} + +/* + * Function: Close platform channel. + * Arguments: None + * Returns: + * always returns PCPL_OK for now. + */ +int +pcp_close(void) +{ + + if (chnl_fd >= 0) { + (void) pcp_cleanup(); + (void) close(chnl_fd); + chnl_fd = -1; + } + + /* + * free global buffers + */ + if (read_area != NULL) { + umem_free(read_area, READ_AREA_SIZE); + read_area = NULL; + } + if (peek_area != NULL) { + umem_free(peek_area, PEEK_AREA_SIZE); + peek_area = NULL; + } + if (peek_read_area != NULL) { + umem_free(peek_read_area, PEEK_READ_AREA_SIZE); + peek_read_area = NULL; + } + if (req_msg_hdr != NULL) { + umem_free(req_msg_hdr, req_msg_hdr_sz); + req_msg_hdr = NULL; + } + if (resp_msg_hdr != NULL) { + umem_free(resp_msg_hdr, resp_msg_hdr_sz); + resp_msg_hdr = NULL; + } + + /* + * Restore SIGALRM signal mask incase if we unblocked + * it during pcp_init. + */ + if (sigismember(&blkset, SIGALRM)) { + (void) sigprocmask(SIG_BLOCK, &blkset, NULL); + } + + /* Restore SIGALRM signal handler */ + (void) sigaction(SIGALRM, &old_act, NULL); + + return (PCPL_OK); +} + +/* + * Function: Send and Receive messages on platform channel. + * Arguments: + * pcp_msg_t *req_msg - Request Message to send to other end of channel. + * pcp_msg_t *resp_msg - Response Message to be received. + * uint32_t timeout - timeout field when waiting for data from channel. + * Returns: + * 0 - success (PCPL_OK). + * (-ve) - failure: + * PCPL_INVALID_ARGS - invalid args. + * PCPL_GLVC_TIMEOUT - glvc call timeout. + * PCPL_XPORT_ERROR - transport error in request message + * noticed by receiver. + * PCPL_MALLOC_FAIL - malloc failure. + * PCPL_CKSUM_ERROR - checksum error. + */ +int +pcp_send_recv(pcp_msg_t *req_msg, pcp_msg_t *resp_msg, uint32_t timeout) +{ + void *datap; + void *resp_msg_data = NULL; + uint32_t status; + uint16_t cksum = 0; + int ret; + int resp_hdr_ok; +#ifdef PCP_CKSUM_ENABLE + uint16_t bkup_resp_hdr_cksum; +#endif + if (chnl_fd < 0) { + return (PCPL_ERROR); + } + + if (req_msg == NULL) { + return (PCPL_INVALID_ARGS); + } + + if (timeout > 0) + glvc_timeout = timeout; + else + glvc_timeout = 0; + + if ((datap = req_msg->msg_data) == NULL) + return (PCPL_INVALID_ARGS); + + if (req_msg_hdr == NULL) { + req_msg_hdr_sz = sizeof (pcp_req_msg_hdr_t); + req_msg_hdr = (pcp_req_msg_hdr_t *)umem_zalloc(req_msg_hdr_sz, + UMEM_DEFAULT); + if (req_msg_hdr == NULL) + return (PCPL_MALLOC_FAIL); + } + + /* calculate request msg_cksum */ + cksum = checksum((uint16_t *)datap, req_msg->msg_len); + + /* + * Fill in the message header for the request packet + */ + req_msg_hdr->magic_num = PCP_MAGIC_NUM; + req_msg_hdr->proto_ver = PCP_PROT_VER_1; + req_msg_hdr->msg_type = req_msg->msg_type; + req_msg_hdr->sub_type = req_msg->sub_type; + req_msg_hdr->rsvd_pad = 0; + req_msg_hdr->xid = pcp_get_xid(); + req_msg_hdr->msg_len = req_msg->msg_len; + req_msg_hdr->timeout = timeout; + req_msg_hdr->msg_cksum = cksum; + req_msg_hdr->hdr_cksum = 0; + + /* fill request header checksum */ + req_msg_hdr->hdr_cksum = checksum((uint16_t *)req_msg_hdr, + req_msg_hdr_sz); + /* + * set sig jmp location + */ + if (sigsetjmp(jmpbuf, 1)) { + return (PCPL_GLVC_TIMEOUT); + } + jumpok = 1; /* monitor sigalrm from now on */ + + /* + * send request message header + */ + if ((ret = pcp_send_req_msg_hdr(req_msg_hdr))) { + + return (ret); + } + + /* + * send request message + */ + if ((ret = pcp_io_op(datap, req_msg->msg_len, + PCPL_IO_OP_WRITE))) { + return (ret); + } + if (timeout == (uint32_t)PCP_TO_NO_RESPONSE) + return (PCPL_OK); + + if (resp_msg_hdr == NULL) { + resp_msg_hdr_sz = sizeof (pcp_resp_msg_hdr_t); + resp_msg_hdr = (pcp_resp_msg_hdr_t *)umem_alloc(resp_msg_hdr_sz, + UMEM_DEFAULT); + if (resp_msg_hdr == NULL) + return (PCPL_MALLOC_FAIL); + } + + resp_hdr_ok = 0; + while (!resp_hdr_ok) { + + /* + * Receive response message header + * Note: frame error handling is done in + * 'pcp_recv_resp_msg_hdr()'. + */ + if ((ret = pcp_recv_resp_msg_hdr(resp_msg_hdr))) { + return (ret); + } + + /* + * Check header checksum if it matches with the received hdr + * checksum. + */ +#ifdef PCP_CKSUM_ENABLE + bkup_resp_hdr_cksum = resp_msg_hdr->hdr_cksum; + resp_msg_hdr->hdr_cksum = 0; + cksum = checksum((uint16_t *)resp_msg_hdr, resp_msg_hdr_sz); + + if (cksum != bkup_resp_hdr_cksum) { + return (PCPL_CKSUM_ERROR); + } +#endif + /* + * Check for matching request and response messages + */ + if (resp_msg_hdr->xid != req_msg_hdr->xid) { + + continue; /* continue reading response header */ + } + resp_hdr_ok = 1; + } + + /* + * check status field for any channel protocol errrors + * This field signifies something happend during request + * message trasmission. This field is set by the receiver. + */ + status = resp_msg_hdr->status; + if (status != PCP_OK) { + return (PCPL_XPORT_ERROR); + } + + + /* libpcp users should free this memory */ + if ((resp_msg_data = (uint8_t *)malloc(resp_msg_hdr->msg_len)) == NULL) + return (PCPL_MALLOC_FAIL); + bzero(resp_msg_data, resp_msg_hdr->msg_len); + /* + * Receive response message. + */ + if ((ret = pcp_io_op(resp_msg_data, resp_msg_hdr->msg_len, + PCPL_IO_OP_READ))) { + free(resp_msg_data); + return (ret); + } + +#ifdef PCP_CKSUM_ENABLE + /* verify response message data checksum */ + cksum = checksum((uint16_t *)resp_msg_data, + resp_msg_hdr->msg_len); + if (cksum != resp_msg_hdr->msg_cksum) { + free(resp_msg_data); + return (PCPL_CKSUM_ERROR); + } +#endif + + /* Everything is okay put the received data into user */ + /* application's resp_msg struct */ + resp_msg->msg_len = resp_msg_hdr->msg_len; + resp_msg->msg_type = resp_msg_hdr->msg_type; + resp_msg->sub_type = resp_msg_hdr->sub_type; + resp_msg->msg_data = (uint8_t *)resp_msg_data; + + return (PCPL_OK); + +} + +/* + * Function: Get channel property values. + * Arguments: + * int prop - property id. + * unsigned int *val - property value tobe copied. + * Returns: + * 0 - success + * (-ve) - failure: + * PCPL_ERR_GLVC - glvc ioctl failure. + */ + +static int +pcp_get_prop(int prop, unsigned int *val) +{ + glvc_xport_opt_op_t channel_op; + int ret; + + channel_op.op_sel = GLVC_XPORT_OPT_GET; + channel_op.opt_sel = prop; + channel_op.opt_val = 0; + + (void) alarm(glvc_timeout); + + if ((ret = ioctl(chnl_fd, GLVC_XPORT_IOCTL_OPT_OP, &channel_op)) < 0) { + (void) alarm(0); + return (ret); + } + (void) alarm(0); + + *val = channel_op.opt_val; + + return (0); +} + +/* + * Function: wrapper for handling glvc calls (read/write/peek). + */ +static int +pcp_io_op(void *buf, int byte_cnt, int io_op) +{ + int rv; + int n; + uint8_t *datap; + int (*func_ptr)(uint8_t *, int); + int io_sz; + int try_cnt; + + + if ((buf == NULL) || (byte_cnt < 0)) { + return (PCPL_INVALID_ARGS); + } + + switch (io_op) { + case PCPL_IO_OP_READ: + func_ptr = pcp_read; + break; + case PCPL_IO_OP_WRITE: + func_ptr = pcp_write; + break; + case PCPL_IO_OP_PEEK: + func_ptr = pcp_peek; + break; + default: + return (PCPL_INVALID_ARGS); + } + + /* + * loop until all I/O done, try limit exceded, or real failure + */ + + rv = 0; + datap = buf; + while (rv < byte_cnt) { + io_sz = MIN((byte_cnt - rv), mtu_size); + try_cnt = 0; + while ((n = (*func_ptr)(datap, io_sz)) < 0) { + try_cnt++; + if (try_cnt > PCPL_MAX_TRY_CNT) { + rv = n; + goto done; + } + (void) sleep(PCPL_GLVC_SLEEP); + } /* while trying the io operation */ + + if (n < 0) { + rv = n; + goto done; + } + rv += n; + datap += n; + } /* while still have more data */ + +done: + if (rv == byte_cnt) + return (0); + else + return (PCPL_GLVC_ERROR); +} + +/* + * For peeking 'bytes_cnt' bytes in channel (glvc) buffers. + * If data is available, the data is copied into 'buf'. + */ +static int +pcp_peek(uint8_t *buf, int bytes_cnt) +{ + int ret; + glvc_xport_msg_peek_t peek_ctrl; + int n, m; + + if (bytes_cnt < 0 || bytes_cnt > mtu_size) { + return (PCPL_INVALID_ARGS); + } + + /* + * initialization of buffers used for peeking data in channel buffers. + */ + if (peek_area == NULL) { + peek_area = (uint8_t *)umem_zalloc(PEEK_AREA_SIZE, + UMEM_DEFAULT); + if (peek_area == NULL) { + return (PCPL_MALLOC_FAIL); + } + } + + /* + * peek max MTU size bytes + */ + peek_ctrl.buf = (caddr_t)peek_area; + peek_ctrl.buflen = mtu_size; + peek_ctrl.flags = 0; + + (void) alarm(glvc_timeout); + + if ((ret = ioctl(chnl_fd, GLVC_XPORT_IOCTL_DATA_PEEK, &peek_ctrl)) + < 0) { + (void) alarm(0); + return (ret); + } + (void) alarm(0); + + n = peek_ctrl.buflen; + + if (n < 0) + return (PCPL_GLVC_ERROR); + + /* + * satisfy request as best as we can + */ + m = MIN(bytes_cnt, n); + (void) memcpy(buf, peek_area, m); + + return (m); + +} + +/* + * Function: write 'byte_cnt' bytes from 'buf' to channel. + */ +static int +pcp_write(uint8_t *buf, int byte_cnt) +{ + + int ret; + + /* check for valid arguments */ + if (buf == NULL || byte_cnt < 0 || byte_cnt > mtu_size) { + return (PCPL_INVALID_ARGS); + } + + (void) alarm(glvc_timeout); + + if ((ret = write(chnl_fd, buf, byte_cnt)) < 0) { + (void) alarm(0); + return (ret); + } + (void) alarm(0); + + return (ret); +} + +/* + * In current implementaion of glvc driver, streams reads are not supported. + * pcp_read mimics stream reads by first reading all the bytes present in the + * channel buffer into a local buffer and from then on read requests + * are serviced from local buffer. When read requests are not serviceble + * from local buffer, it repeates by first reading data from channel buffers. + * + * This call may need to be enhanced when glvc supports buffered (stream) + * reads - TBD + */ + +static int +pcp_read(uint8_t *buf, int byte_cnt) +{ + int ret; + int n, m, i; + + if (byte_cnt < 0 || byte_cnt > mtu_size) { + return (PCPL_INVALID_ARGS); + } + + /* + * initialization of local read buffer + * from which the stream read requests are serviced. + */ + if (read_area == NULL) { + read_area = (uint8_t *)umem_zalloc(READ_AREA_SIZE, + UMEM_DEFAULT); + if (read_area == NULL) { + return (PCPL_MALLOC_FAIL); + } + read_head = read_area; + read_tail = read_area; + } + + /* + * if we already read this data then copy from local buffer it self + * without calling new read. + */ + if (byte_cnt <= (read_tail - read_head)) { + (void) memcpy(buf, read_head, byte_cnt); + read_head += byte_cnt; + return (byte_cnt); + } + + /* + * if the request is not satisfied from the buffered data, then move the + * remaining data to front of the buffer and read new data. + */ + for (i = 0; i < (read_tail - read_head); ++i) { + read_area[i] = read_head[i]; + } + read_head = read_area; + read_tail = read_head + i; + + /* + * do a peek to see how much data is available and read complete data. + */ + + if ((m = pcp_peek(read_tail, mtu_size)) < 0) { + return (m); + } + + (void) alarm(glvc_timeout); + if ((ret = read(chnl_fd, read_tail, m)) < 0) { + (void) alarm(0); + return (ret); + } + + (void) alarm(0); + read_tail += ret; + + /* + * copy the requested bytes. + */ + n = MIN(byte_cnt, (read_tail - read_head)); + (void) memcpy(buf, read_head, n); + + read_head += n; + + return (n); +} + +/* + * This function is slight different from pcp_peek. The peek requests are first + * serviced from local read buffer, if data is available. If the peek request + * is not serviceble from local read buffer, then the data is peeked from + * channel buffer. This function is mainly used for proper protocol framing + * error handling. + */ +static int +pcp_peek_read(uint8_t *buf, int byte_cnt) +{ + int n, m, i; + + if (byte_cnt < 0 || byte_cnt > mtu_size) { + return (PCPL_INVALID_ARGS); + } + + /* + * initialization of peek_read buffer. + */ + if (peek_read_area == NULL) { + peek_read_area = (uint8_t *)umem_zalloc(PEEK_READ_AREA_SIZE, + UMEM_DEFAULT); + if (peek_read_area == NULL) { + return (PCPL_MALLOC_FAIL); + } + peek_read_head = peek_read_area; + peek_read_tail = peek_read_area; + } + + /* + * if we already have the data in local read buffer then copy + * from local buffer it self w/out calling new peek + */ + if (byte_cnt <= (read_tail - read_head)) { + (void) memcpy(buf, read_head, byte_cnt); + return (byte_cnt); + } + + /* + * if the request is not satisfied from local read buffer, then first + * copy the remaining data in local read buffer to peek_read_area and + * then issue new peek. + */ + for (i = 0; i < (read_tail - read_head); ++i) { + peek_read_area[i] = read_head[i]; + } + peek_read_head = peek_read_area; + peek_read_tail = peek_read_head + i; + + /* + * do a peek to see how much data is available and read complete data. + */ + + if ((m = pcp_peek(peek_read_tail, mtu_size)) < 0) { + return (m); + } + + peek_read_tail += m; + + /* + * copy the requested bytes + */ + n = MIN(byte_cnt, (peek_read_tail - peek_read_head)); + (void) memcpy(buf, peek_read_head, n); + + return (n); +} + +/* + * Send Request Message Header. + */ +static int +pcp_send_req_msg_hdr(pcp_req_msg_hdr_t *req_hdr) +{ + pcp_req_msg_hdr_t *hdrp; + int hdr_sz; + int ret; + + hdr_sz = sizeof (pcp_req_msg_hdr_t); + if ((hdrp = (pcp_req_msg_hdr_t *)umem_zalloc(hdr_sz, + UMEM_DEFAULT)) == NULL) { + return (PCPL_MALLOC_FAIL); + } + + hdrp->magic_num = htonl(req_hdr->magic_num); + hdrp->proto_ver = req_hdr->proto_ver; + hdrp->msg_type = req_hdr->msg_type; + hdrp->sub_type = req_hdr->sub_type; + hdrp->rsvd_pad = htons(req_hdr->rsvd_pad); + hdrp->xid = htonl(req_hdr->xid); + hdrp->timeout = htonl(req_hdr->timeout); + hdrp->msg_len = htonl(req_hdr->msg_len); + hdrp->msg_cksum = htons(req_hdr->msg_cksum); + hdrp->hdr_cksum = htons(req_hdr->hdr_cksum); + + if ((ret = pcp_io_op((char *)hdrp, hdr_sz, PCPL_IO_OP_WRITE)) != 0) { + umem_free(hdrp, hdr_sz); + return (ret); + } + umem_free(hdrp, hdr_sz); + return (PCP_OK); +} + +/* + * Receive Response message header. + */ +static int +pcp_recv_resp_msg_hdr(pcp_resp_msg_hdr_t *resp_hdr) +{ + uint32_t magic_num; + uint8_t proto_ver; + uint8_t msg_type; + uint8_t sub_type; + uint8_t rsvd_pad; + uint32_t xid; + uint32_t timeout; + uint32_t msg_len; + uint32_t status; + uint16_t msg_cksum; + uint16_t hdr_cksum; + int ret; + + if (resp_hdr == NULL) { + return (PCPL_INVALID_ARGS); + } + + /* + * handle protocol framing errors. + * pcp_frame_error_handle() returns when proper frame arrived + * (magic seq) or if an error happens while reading data from + * channel. + */ + if ((ret = pcp_frame_error_handle()) != 0) + return (PCPL_FRAME_ERROR); + + /* read magic number first */ + if ((ret = pcp_io_op(&magic_num, sizeof (magic_num), + PCPL_IO_OP_READ)) != 0) { + return (ret); + } + + magic_num = ntohl(magic_num); + + if (magic_num != PCP_MAGIC_NUM) { + return (PCPL_FRAME_ERROR); + } + + /* read version field */ + if ((ret = pcp_io_op(&proto_ver, sizeof (proto_ver), + PCPL_IO_OP_READ)) != 0) { + return (ret); + } + + /* check protocol version */ + if (proto_ver != PCP_PROT_VER_1) { + return (PCPL_PROT_ERROR); + } + + /* Read message type */ + if ((ret = pcp_io_op(&msg_type, sizeof (msg_type), + PCPL_IO_OP_READ)) != 0) { + return (ret); + } + + /* Read message sub type */ + if ((ret = pcp_io_op(&sub_type, sizeof (sub_type), + PCPL_IO_OP_READ)) != 0) { + return (ret); + } + + /* Read rcvd_pad bits */ + if ((ret = pcp_io_op(&rsvd_pad, sizeof (rsvd_pad), + PCPL_IO_OP_READ)) != 0) { + return (ret); + } + + /* receive transaction id */ + if ((ret = pcp_io_op(&xid, sizeof (xid), + PCPL_IO_OP_READ)) != 0) { + return (ret); + } + + xid = ntohl(xid); + + /* receive timeout value */ + if ((ret = pcp_io_op(&timeout, sizeof (timeout), + PCPL_IO_OP_READ)) != 0) { + return (ret); + } + + timeout = ntohl(timeout); + + /* receive message length */ + if ((ret = pcp_io_op(&msg_len, sizeof (msg_len), + PCPL_IO_OP_READ)) != 0) { + return (ret); + } + + msg_len = ntohl(msg_len); + + /* receive status field */ + if ((ret = pcp_io_op(&status, sizeof (status), + PCPL_IO_OP_READ)) != 0) { + return (ret); + } + + status = ntohl(status); + + /* receive message checksum */ + if ((ret = pcp_io_op(&msg_cksum, sizeof (msg_cksum), + PCPL_IO_OP_READ)) != 0) { + return (ret); + } + + msg_cksum = ntohs(msg_cksum); + + /* receive header checksum */ + if ((ret = pcp_io_op(&hdr_cksum, sizeof (hdr_cksum), + PCPL_IO_OP_READ)) != 0) { + return (ret); + } + + hdr_cksum = ntohs(hdr_cksum); + + /* copy to resp_hdr */ + + resp_hdr->magic_num = magic_num; + resp_hdr->proto_ver = proto_ver; + resp_hdr->msg_type = msg_type; + resp_hdr->sub_type = sub_type; + resp_hdr->rsvd_pad = rsvd_pad; + resp_hdr->xid = xid; + resp_hdr->timeout = timeout; + resp_hdr->msg_len = msg_len; + resp_hdr->status = status; + resp_hdr->msg_cksum = msg_cksum; + resp_hdr->hdr_cksum = hdr_cksum; + + return (PCP_OK); +} + +/* + * Get next xid for including in request message. + * Every request and response message are matched + * for same xid. + */ +static int pcp_get_xid(void) +{ + uint32_t ret; + + ret = msg_xid; + if (msg_xid == PCPL_MAX_XID) + msg_xid = PCPL_MIN_XID; + else + ++msg_xid; + return (ret); +} + +/* + * This function handles channel framing errors. It waits until proper + * frame with starting sequence as magic numder (0xAFBCAFA0) + * is arrived. It removes unexpected data (before the magic number sequence) + * on the channel. It returns when proper magic number sequence is seen + * or when any failure happens while reading/peeking the channel. + */ +static int +pcp_frame_error_handle(void) +{ + uint8_t magic_num_buf[4]; + int ispresent = 0; + uint32_t net_magic_num; /* magic byte in network byte order */ + uint32_t host_magic_num = PCP_MAGIC_NUM; + uint8_t buf[2]; + + net_magic_num = htonl(host_magic_num); + (void) memcpy(magic_num_buf, (uint8_t *)&net_magic_num, 4); + + while (!ispresent) { + /* + * Check if next four bytes matches pcp magic number. + * if mathing not found, discard 1 byte and continue checking. + */ + if (!check_magic_byte_presence(4, &magic_num_buf[0], + &ispresent)) { + if (!ispresent) { + /* remove 1 byte */ + (void) pcp_io_op(buf, 1, PCPL_IO_OP_READ); + } + } else { + return (-1); + } + } + + return (0); +} + +/* + * checks whether certain byte sequence is present in the data stream. + */ +static int +check_magic_byte_presence(int byte_cnt, uint8_t *byte_seq, int *ispresent) +{ + int ret, i; + uint8_t buf[4]; + + if ((ret = pcp_peek_read(buf, byte_cnt)) < 0) { + return (ret); + } + + /* 'byte_cnt' bytes not present */ + if (ret != byte_cnt) { + *ispresent = 0; + return (0); + } + + for (i = 0; i < byte_cnt; ++i) { + if (buf[i] != byte_seq[i]) { + *ispresent = 0; + return (0); + } + } + *ispresent = 1; + + return (0); +} + +/* + * 16-bit simple internet checksum + */ +static uint16_t +checksum(uint16_t *addr, int32_t count) +{ + /* + * Compute Internet Checksum for "count" bytes + * beginning at location "addr". + */ + + register uint32_t sum = 0; + + while (count > 1) { + /* This is the inner loop */ + sum += *(unsigned short *)addr++; + count -= 2; + } + + /* Add left-over byte, if any */ + if (count > 0) + sum += * (unsigned char *)addr; + + /* Fold 32-bit sum to 16 bits */ + while (sum >> 16) + sum = (sum & 0xffff) + (sum >> 16); + + sum = (~sum) & 0xffff; + if (sum == 0) + sum = 0xffff; + + return (sum); +} + +/* + * cleanup the channel if any data is hanging in + * channel buffers. + */ +static int +pcp_cleanup(void) +{ + int ret; + glvc_xport_msg_peek_t peek_ctrl; + int n, done; + uint8_t *buf = NULL; + int retry = 0; + + + buf = (uint8_t *)umem_zalloc((mtu_size), UMEM_DEFAULT); + if (buf == NULL) { + return (PCPL_MALLOC_FAIL); + } + + peek_ctrl.buf = (caddr_t)buf; + peek_ctrl.buflen = mtu_size; + peek_ctrl.flags = 0; + + /* + * set sig jmp location + */ + if (sigsetjmp(jmpbuf, 1)) { + umem_free(buf, mtu_size); + return (PCPL_GLVC_TIMEOUT); + } + + done = 0; + while (!done) { + + (void) alarm(PCP_CLEANUP_TIMEOUT); + if ((ret = ioctl(chnl_fd, GLVC_XPORT_IOCTL_DATA_PEEK, + &peek_ctrl)) < 0) { + (void) alarm(0); + done = 1; + continue; + } + (void) alarm(0); + + n = peek_ctrl.buflen; + + if (n <= 0 && retry > 2) { + done = 1; + continue; + } else if (n <= 0) { + ++retry; + continue; + } + + /* remove data from channel */ + (void) alarm(PCP_CLEANUP_TIMEOUT); + if ((ret = read(chnl_fd, buf, n)) < 0) { + (void) alarm(0); + done = 1; + continue; + } + (void) alarm(0); + } + + umem_free(buf, mtu_size); + return (ret); +} diff --git a/usr/src/lib/libpcp/common/libpcp.h b/usr/src/lib/libpcp/common/libpcp.h new file mode 100644 index 0000000000..ca73d96551 --- /dev/null +++ b/usr/src/lib/libpcp/common/libpcp.h @@ -0,0 +1,100 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (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 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _LIBPCP_H +#define _LIBPCP_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#define PCPL_MIN_XID (0xFF) +#define PCPL_MAX_XID (0xFFFFFFFF) +#define PCPL_INIT_XID (0xFF) + +#define PCPL_MAX_TRY_CNT 5 +#define PCP_CLEANUP_TIMEOUT 3 + +#define PCPL_DEF_MTU_SZ 100 + + +#define PCPL_IO_OP_READ (1) +#define PCPL_IO_OP_WRITE (2) +#define PCPL_IO_OP_PEEK (3) + +/* + * sleep (seconds) for glvc call failures before + * retrying. + */ +#define PCPL_GLVC_SLEEP (5) + +/* + * Error codes for pcp library that are + * returned to users applications. + */ +#define PCPL_OK 0 +#define PCPL_ERROR (-1) +#define PCPL_INVALID_ARGS (-2) +#define PCPL_GLVC_ERROR (-3) +#define PCPL_XPORT_ERROR (-4) +#define PCPL_MALLOC_FAIL (-5) +#define PCPL_GLVC_TIMEOUT (-6) +#define PCPL_FRAME_ERROR (-7) +#define PCPL_CKSUM_ERROR (-8) +#define PCPL_PROT_ERROR (-9) + +/* common defines */ +#ifndef MIN +#define MIN(x, y) ((x) < (y) ? (x) : (y)) +#endif +#ifndef MAX +#define MAX(x, y) ((x) > (y) ? (x) : (y)) +#endif +#ifndef ABS +#define ABS(x) ((x) < (0) ? (-(x)) : (x)) +#endif + +/* + * PCP user apps message format + */ +typedef struct pcp_msg { + uint8_t msg_type; + uint8_t sub_type; + uint32_t msg_len; + void *msg_data; +} pcp_msg_t; + +int pcp_init(char *channel_dev_path); +int pcp_send_recv(pcp_msg_t *req_msg, pcp_msg_t *resp_msg, uint32_t timeout); +int pcp_close(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _LIBPCP_H */ diff --git a/usr/src/lib/libpcp/common/mapfile-vers b/usr/src/lib/libpcp/common/mapfile-vers new file mode 100644 index 0000000000..7474707747 --- /dev/null +++ b/usr/src/lib/libpcp/common/mapfile-vers @@ -0,0 +1,37 @@ +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (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 +# +# ident "%Z%%M% %I% %E% SMI" +# +# Interface definition for usr/src/lib/libpcp +# + +SUNWprivate_1.1 { + global: + pcp_init; + pcp_send_recv; + pcp_close; + local: + *; +}; diff --git a/usr/src/lib/libpcp/common/pcp_common.h b/usr/src/lib/libpcp/common/pcp_common.h new file mode 100644 index 0000000000..fe8559f89f --- /dev/null +++ b/usr/src/lib/libpcp/common/pcp_common.h @@ -0,0 +1,110 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (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 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _PCP_COMMON_H +#define _PCP_COMMON_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This file is shared by both ALOM and Solaris sides of + * Platform Channel Protocol users. So this file should + * include only common shared things. + */ + +/* + * Platform Channel Request Message Header. + */ +typedef struct pcp_req_msg_hdr { + uint32_t magic_num; /* magic number */ + uint8_t proto_ver; /* version info for */ + /* backward compatibility */ + uint8_t msg_type; /* provided by user apps */ + uint8_t sub_type; /* provided by user apps */ + uint8_t rsvd_pad; /* padding bits */ + uint32_t xid; /* transaction id */ + uint32_t timeout; /* timeout in seconds */ + uint32_t msg_len; /* length of request or response data */ + uint16_t msg_cksum; /* 16-bit checksum of req msg data */ + uint16_t hdr_cksum; /* 16-bit checksum of req hdr */ +} pcp_req_msg_hdr_t; + + +/* + * Platform Channel Response Message Header. + */ +typedef struct pcp_resp_msg_hdr { + uint32_t magic_num; /* magic number */ + uint8_t proto_ver; /* version info for */ + /* backward compatibility */ + uint8_t msg_type; /* passed to user apps */ + uint8_t sub_type; /* passed to user apps */ + uint8_t rsvd_pad; /* for padding */ + uint32_t xid; /* transaction id */ + uint32_t timeout; /* timeout in seconds */ + uint32_t msg_len; /* length of request or response data */ + uint32_t status; /* response status */ + uint16_t msg_cksum; /* 16-bit checksum of resp msg data */ + uint16_t hdr_cksum; /* 16-bit checksum of resp hdr */ +} pcp_resp_msg_hdr_t; + +/* + * magic number for Platform Channel Protocol (PCP) + * ~(rot13("PCP_") = 0xAFBCAFA0 + * rot13 is a simple Caesar-cypher encryption that replaces each English letter + * with the one 13 places forward or back along the alphabet. + */ +#define PCP_MAGIC_NUM (0xAFBCAFA0) + + +/* Platform channel protocol versions. */ +#define PCP_PROT_VER_1 1 + + +/* Error codes for 'status' field in response message header */ + +#define PCP_OK (0) /* message received okay */ +#define PCP_ERROR (1) /* generic error */ +#define PCP_HDR_CKSUM_ERROR (2) /* header checksum error */ +#define PCP_MSG_CKSUM_ERROR (3) /* message checksum error */ +#define PCP_XPORT_ERROR (4) /* message in complete error */ + +/* defines for 'timeout' */ +#define PCP_TO_NO_RESPONSE (-1) /* no response required */ +#define PCP_TO_WAIT_FOREVER (0) /* wait forever..(in reality, */ + /* it waits until glvc driver */ + /* call returns; curently glvc */ + /* calls are blocking calls. */ + +#ifdef __cplusplus +} +#endif + +#endif /* _PCP_COMMON_H */ diff --git a/usr/src/lib/libpcp/sparc/Makefile b/usr/src/lib/libpcp/sparc/Makefile new file mode 100644 index 0000000000..9bdc7c258b --- /dev/null +++ b/usr/src/lib/libpcp/sparc/Makefile @@ -0,0 +1,78 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (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 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" +# +# lib/libpcp/sparc/Makefile + +UTSBASE= ../../../uts + +PLATINCS += -I$(USR_PLAT_DIR)/sun4v/include -I$(UTSBASE)/sun4v + +PLATFORM_OBJECTS= libpcp.o + +# +# platform library directory (/usr/platform/SUNW,Sun-Fire-T200/lib) +# +PLATFORM=SUNW,Sun-Fire-T200 +LINKED_PLATFORMS = + +include ../Makefile.com + +# +# install rules +# + +$(PLATLIBS): + $(INS.dir) + +$(PLATLIBS)/libpcp.so: + $(RM) -r $@; $(SYMLINK) libpcp.so.1 $@ $(CHOWNLINK) $(CHGRPLINK) + +$(USR_PSM_LIB_DIR)/%: % $(USR_PSM_LIB_DIR) + $(INS.file) + +$(USR_PSM_LIB_DIR): + cd $(UTSBASE)/sun4v; pwd; $(MAKE) $(USR_PSM_LIB_DIR) + +$(LINKED_DIRS): $(USR_PLAT_DIR) + -$(INS.dir.root.sys) + +$(LINKED_LIB_DIRS): $(LINKED_DIRS) + -$(INS.dir.root.sys) + +$(LINKED_LIBPCP_DIR): $(USR_PLAT_DIR) + -$(INS.slink7) + +$(LINKED_LIBPCP1_DIR): $(USR_PLAT_DIR) + -$(INS.slink6) + +$(LINKED_LLIBLPCP_DIR): $(USR_PLAT_DIR) + -$(INS.slink8) + +install: all $(PLATLIBS) $(USR_PSM_LIBS) $(PLATLIBS)/libpcp.so \ + $(LINKED_DIRS) $(LINKED_LIB_DIRS) \ + $(LINKED_LIBPCP_DIR) $(LINKED_LIBPCP1_DIR) \ + $(LINKED_LLIBLPCP_DIR) |
