1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate /* 28*7c478bd9Sstevel@tonic-gate * Platform Channel Protocol Library functions on Nigara platforms 29*7c478bd9Sstevel@tonic-gate * (Ontario, Erie, etc..) Solaris applications use these interfaces 30*7c478bd9Sstevel@tonic-gate * to communicate with entities that reside on service processor. 31*7c478bd9Sstevel@tonic-gate */ 32*7c478bd9Sstevel@tonic-gate 33*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 34*7c478bd9Sstevel@tonic-gate 35*7c478bd9Sstevel@tonic-gate #include <stdio.h> 36*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 37*7c478bd9Sstevel@tonic-gate #include <unistd.h> 38*7c478bd9Sstevel@tonic-gate #include <string.h> 39*7c478bd9Sstevel@tonic-gate #include <assert.h> 40*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 41*7c478bd9Sstevel@tonic-gate #include <errno.h> 42*7c478bd9Sstevel@tonic-gate #include <signal.h> 43*7c478bd9Sstevel@tonic-gate #include <setjmp.h> 44*7c478bd9Sstevel@tonic-gate #include <inttypes.h> 45*7c478bd9Sstevel@tonic-gate #include <umem.h> 46*7c478bd9Sstevel@tonic-gate #include <strings.h> 47*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 48*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 49*7c478bd9Sstevel@tonic-gate #include <sys/glvc.h> 50*7c478bd9Sstevel@tonic-gate #include <netinet/in.h> 51*7c478bd9Sstevel@tonic-gate 52*7c478bd9Sstevel@tonic-gate #include "libpcp.h" 53*7c478bd9Sstevel@tonic-gate #include "pcp_common.h" 54*7c478bd9Sstevel@tonic-gate 55*7c478bd9Sstevel@tonic-gate /* 56*7c478bd9Sstevel@tonic-gate * Following libpcp interfaces are exposed to user applications. 57*7c478bd9Sstevel@tonic-gate * 58*7c478bd9Sstevel@tonic-gate * int pcp_init(char *channel_dev_path); 59*7c478bd9Sstevel@tonic-gate * int pcp_send_recv(pcp_msg_t *req_msg, pcp_msg_t *resp_msg, uint32_t timeout); 60*7c478bd9Sstevel@tonic-gate * int pcp_close(void); 61*7c478bd9Sstevel@tonic-gate * 62*7c478bd9Sstevel@tonic-gate */ 63*7c478bd9Sstevel@tonic-gate 64*7c478bd9Sstevel@tonic-gate /* 65*7c478bd9Sstevel@tonic-gate * Forward declarations. 66*7c478bd9Sstevel@tonic-gate */ 67*7c478bd9Sstevel@tonic-gate static int pcp_send_req_msg_hdr(pcp_req_msg_hdr_t *req_hdr); 68*7c478bd9Sstevel@tonic-gate static int pcp_recv_resp_msg_hdr(pcp_resp_msg_hdr_t *resp_hdr); 69*7c478bd9Sstevel@tonic-gate static int pcp_io_op(void *buf, int byte_cnt, int io_op); 70*7c478bd9Sstevel@tonic-gate static int pcp_get_xid(void); 71*7c478bd9Sstevel@tonic-gate static int pcp_get_prop(int prop, unsigned int *val); 72*7c478bd9Sstevel@tonic-gate static int pcp_read(uint8_t *buf, int buf_len); 73*7c478bd9Sstevel@tonic-gate static int pcp_write(uint8_t *buf, int buf_len); 74*7c478bd9Sstevel@tonic-gate static int pcp_peek(uint8_t *buf, int buf_len); 75*7c478bd9Sstevel@tonic-gate static int pcp_peek_read(uint8_t *buf, int buf_len); 76*7c478bd9Sstevel@tonic-gate static int pcp_frame_error_handle(void); 77*7c478bd9Sstevel@tonic-gate static int check_magic_byte_presence(int byte_cnt, uint8_t *byte_val, 78*7c478bd9Sstevel@tonic-gate int *ispresent); 79*7c478bd9Sstevel@tonic-gate static uint16_t checksum(uint16_t *addr, int32_t count); 80*7c478bd9Sstevel@tonic-gate static int pcp_cleanup(void); 81*7c478bd9Sstevel@tonic-gate 82*7c478bd9Sstevel@tonic-gate /* 83*7c478bd9Sstevel@tonic-gate * glvc driver file descriptor 84*7c478bd9Sstevel@tonic-gate */ 85*7c478bd9Sstevel@tonic-gate static int chnl_fd = -1; 86*7c478bd9Sstevel@tonic-gate 87*7c478bd9Sstevel@tonic-gate /* 88*7c478bd9Sstevel@tonic-gate * Message Transaction ID 89*7c478bd9Sstevel@tonic-gate */ 90*7c478bd9Sstevel@tonic-gate static uint32_t msg_xid = 0; 91*7c478bd9Sstevel@tonic-gate 92*7c478bd9Sstevel@tonic-gate /* 93*7c478bd9Sstevel@tonic-gate * Channel MTU size. 94*7c478bd9Sstevel@tonic-gate */ 95*7c478bd9Sstevel@tonic-gate static unsigned int mtu_size = PCPL_DEF_MTU_SZ; 96*7c478bd9Sstevel@tonic-gate 97*7c478bd9Sstevel@tonic-gate /* 98*7c478bd9Sstevel@tonic-gate * timeout field is supplied by user. timeout field is used to decide 99*7c478bd9Sstevel@tonic-gate * how long to block on glvc driver calls before we return timeout error 100*7c478bd9Sstevel@tonic-gate * to user applications. 101*7c478bd9Sstevel@tonic-gate * 102*7c478bd9Sstevel@tonic-gate * Note: In the current implementation of glvc driver, all glvc calls are 103*7c478bd9Sstevel@tonic-gate * blocking. 104*7c478bd9Sstevel@tonic-gate */ 105*7c478bd9Sstevel@tonic-gate static uint32_t glvc_timeout = 0; 106*7c478bd9Sstevel@tonic-gate 107*7c478bd9Sstevel@tonic-gate /* 108*7c478bd9Sstevel@tonic-gate * variables used by setsetjmp/siglongjmp. 109*7c478bd9Sstevel@tonic-gate */ 110*7c478bd9Sstevel@tonic-gate static volatile sig_atomic_t jumpok = 0; 111*7c478bd9Sstevel@tonic-gate static sigjmp_buf jmpbuf; 112*7c478bd9Sstevel@tonic-gate 113*7c478bd9Sstevel@tonic-gate /* 114*7c478bd9Sstevel@tonic-gate * To unblock SIGALRM signal incase if it's blocked in libpcp user apps. 115*7c478bd9Sstevel@tonic-gate * Restore it to old state during pcp_close. 116*7c478bd9Sstevel@tonic-gate */ 117*7c478bd9Sstevel@tonic-gate static sigset_t blkset; 118*7c478bd9Sstevel@tonic-gate 119*7c478bd9Sstevel@tonic-gate /* 120*7c478bd9Sstevel@tonic-gate * Buffers used for stream reading channel data. When data is read in 121*7c478bd9Sstevel@tonic-gate * stream fashion, first data is copied from channel (glvc) buffers to 122*7c478bd9Sstevel@tonic-gate * these local buffers from which the read requests are serviced. 123*7c478bd9Sstevel@tonic-gate */ 124*7c478bd9Sstevel@tonic-gate #define READ_AREA_SIZE (2*mtu_size) 125*7c478bd9Sstevel@tonic-gate static uint8_t *read_head = NULL; 126*7c478bd9Sstevel@tonic-gate static uint8_t *read_tail = NULL; 127*7c478bd9Sstevel@tonic-gate static uint8_t *read_area = NULL; 128*7c478bd9Sstevel@tonic-gate 129*7c478bd9Sstevel@tonic-gate /* 130*7c478bd9Sstevel@tonic-gate * Buffer used for peeking new data available in channel (glvc) buffers. 131*7c478bd9Sstevel@tonic-gate */ 132*7c478bd9Sstevel@tonic-gate #define PEEK_AREA_SIZE (mtu_size) 133*7c478bd9Sstevel@tonic-gate static uint8_t *peek_area = NULL; 134*7c478bd9Sstevel@tonic-gate 135*7c478bd9Sstevel@tonic-gate /* 136*7c478bd9Sstevel@tonic-gate * Buffers used for peeking data available either in local buffers or 137*7c478bd9Sstevel@tonic-gate * new data available in channel (glvc) buffers. 138*7c478bd9Sstevel@tonic-gate */ 139*7c478bd9Sstevel@tonic-gate #define PEEK_READ_AREA_SIZE (2*mtu_size) 140*7c478bd9Sstevel@tonic-gate static uint8_t *peek_read_head = NULL; 141*7c478bd9Sstevel@tonic-gate static uint8_t *peek_read_tail = NULL; 142*7c478bd9Sstevel@tonic-gate static uint8_t *peek_read_area = NULL; 143*7c478bd9Sstevel@tonic-gate 144*7c478bd9Sstevel@tonic-gate static pcp_req_msg_hdr_t *req_msg_hdr = NULL; 145*7c478bd9Sstevel@tonic-gate static pcp_resp_msg_hdr_t *resp_msg_hdr = NULL; 146*7c478bd9Sstevel@tonic-gate static int req_msg_hdr_sz = 0; 147*7c478bd9Sstevel@tonic-gate static int resp_msg_hdr_sz = 0; 148*7c478bd9Sstevel@tonic-gate 149*7c478bd9Sstevel@tonic-gate /* 150*7c478bd9Sstevel@tonic-gate * signal handling variables to handle glvc blocking calls. 151*7c478bd9Sstevel@tonic-gate */ 152*7c478bd9Sstevel@tonic-gate static struct sigaction glvc_act; 153*7c478bd9Sstevel@tonic-gate 154*7c478bd9Sstevel@tonic-gate /* To restore old SIGALRM signal handler */ 155*7c478bd9Sstevel@tonic-gate static struct sigaction old_act; 156*7c478bd9Sstevel@tonic-gate 157*7c478bd9Sstevel@tonic-gate static void 158*7c478bd9Sstevel@tonic-gate glvc_timeout_handler(void) 159*7c478bd9Sstevel@tonic-gate { 160*7c478bd9Sstevel@tonic-gate if (jumpok == 0) 161*7c478bd9Sstevel@tonic-gate return; 162*7c478bd9Sstevel@tonic-gate siglongjmp(jmpbuf, 1); 163*7c478bd9Sstevel@tonic-gate } 164*7c478bd9Sstevel@tonic-gate 165*7c478bd9Sstevel@tonic-gate /* 166*7c478bd9Sstevel@tonic-gate * Initialize the virtual channel. It basically opens the virtual channel 167*7c478bd9Sstevel@tonic-gate * provided by the host application. 168*7c478bd9Sstevel@tonic-gate * 169*7c478bd9Sstevel@tonic-gate */ 170*7c478bd9Sstevel@tonic-gate 171*7c478bd9Sstevel@tonic-gate int 172*7c478bd9Sstevel@tonic-gate pcp_init(char *channel_dev_path) 173*7c478bd9Sstevel@tonic-gate { 174*7c478bd9Sstevel@tonic-gate sigset_t oldset; 175*7c478bd9Sstevel@tonic-gate 176*7c478bd9Sstevel@tonic-gate if (channel_dev_path == NULL) 177*7c478bd9Sstevel@tonic-gate return (PCPL_INVALID_ARGS); 178*7c478bd9Sstevel@tonic-gate /* 179*7c478bd9Sstevel@tonic-gate * Open virtual channel device node. 180*7c478bd9Sstevel@tonic-gate */ 181*7c478bd9Sstevel@tonic-gate if ((chnl_fd = open(channel_dev_path, O_RDWR|O_EXCL)) < 0) { 182*7c478bd9Sstevel@tonic-gate return (PCPL_GLVC_ERROR); 183*7c478bd9Sstevel@tonic-gate } 184*7c478bd9Sstevel@tonic-gate 185*7c478bd9Sstevel@tonic-gate /* 186*7c478bd9Sstevel@tonic-gate * Initialize Message Transaction ID. 187*7c478bd9Sstevel@tonic-gate */ 188*7c478bd9Sstevel@tonic-gate msg_xid = PCPL_INIT_XID; 189*7c478bd9Sstevel@tonic-gate 190*7c478bd9Sstevel@tonic-gate /* 191*7c478bd9Sstevel@tonic-gate * Get the Channel MTU size 192*7c478bd9Sstevel@tonic-gate */ 193*7c478bd9Sstevel@tonic-gate 194*7c478bd9Sstevel@tonic-gate if (pcp_get_prop(GLVC_XPORT_OPT_MTU_SZ, &mtu_size) != 0) { 195*7c478bd9Sstevel@tonic-gate (void) close(chnl_fd); 196*7c478bd9Sstevel@tonic-gate chnl_fd = -1; 197*7c478bd9Sstevel@tonic-gate return (PCPL_GLVC_ERROR); 198*7c478bd9Sstevel@tonic-gate } 199*7c478bd9Sstevel@tonic-gate 200*7c478bd9Sstevel@tonic-gate /* 201*7c478bd9Sstevel@tonic-gate * Get current signal mask. If SIGALRM is blocked 202*7c478bd9Sstevel@tonic-gate * unblock it. 203*7c478bd9Sstevel@tonic-gate */ 204*7c478bd9Sstevel@tonic-gate (void) sigprocmask(0, NULL, &oldset); 205*7c478bd9Sstevel@tonic-gate 206*7c478bd9Sstevel@tonic-gate (void) sigemptyset(&blkset); 207*7c478bd9Sstevel@tonic-gate 208*7c478bd9Sstevel@tonic-gate if (sigismember(&oldset, SIGALRM)) { 209*7c478bd9Sstevel@tonic-gate (void) sigaddset(&blkset, SIGALRM); 210*7c478bd9Sstevel@tonic-gate (void) sigprocmask(SIG_UNBLOCK, &blkset, NULL); 211*7c478bd9Sstevel@tonic-gate } 212*7c478bd9Sstevel@tonic-gate /* 213*7c478bd9Sstevel@tonic-gate * signal handler initialization to handle glvc call timeouts. 214*7c478bd9Sstevel@tonic-gate */ 215*7c478bd9Sstevel@tonic-gate glvc_act.sa_handler = glvc_timeout_handler; 216*7c478bd9Sstevel@tonic-gate (void) sigemptyset(&glvc_act.sa_mask); 217*7c478bd9Sstevel@tonic-gate glvc_act.sa_flags = SA_NODEFER; 218*7c478bd9Sstevel@tonic-gate 219*7c478bd9Sstevel@tonic-gate if (sigaction(SIGALRM, &glvc_act, &old_act) < 0) { 220*7c478bd9Sstevel@tonic-gate (void) close(chnl_fd); 221*7c478bd9Sstevel@tonic-gate chnl_fd = -1; 222*7c478bd9Sstevel@tonic-gate return (PCPL_ERROR); 223*7c478bd9Sstevel@tonic-gate } 224*7c478bd9Sstevel@tonic-gate 225*7c478bd9Sstevel@tonic-gate return (PCPL_OK); 226*7c478bd9Sstevel@tonic-gate } 227*7c478bd9Sstevel@tonic-gate 228*7c478bd9Sstevel@tonic-gate /* 229*7c478bd9Sstevel@tonic-gate * Function: Close platform channel. 230*7c478bd9Sstevel@tonic-gate * Arguments: None 231*7c478bd9Sstevel@tonic-gate * Returns: 232*7c478bd9Sstevel@tonic-gate * always returns PCPL_OK for now. 233*7c478bd9Sstevel@tonic-gate */ 234*7c478bd9Sstevel@tonic-gate int 235*7c478bd9Sstevel@tonic-gate pcp_close(void) 236*7c478bd9Sstevel@tonic-gate { 237*7c478bd9Sstevel@tonic-gate 238*7c478bd9Sstevel@tonic-gate if (chnl_fd >= 0) { 239*7c478bd9Sstevel@tonic-gate (void) pcp_cleanup(); 240*7c478bd9Sstevel@tonic-gate (void) close(chnl_fd); 241*7c478bd9Sstevel@tonic-gate chnl_fd = -1; 242*7c478bd9Sstevel@tonic-gate } 243*7c478bd9Sstevel@tonic-gate 244*7c478bd9Sstevel@tonic-gate /* 245*7c478bd9Sstevel@tonic-gate * free global buffers 246*7c478bd9Sstevel@tonic-gate */ 247*7c478bd9Sstevel@tonic-gate if (read_area != NULL) { 248*7c478bd9Sstevel@tonic-gate umem_free(read_area, READ_AREA_SIZE); 249*7c478bd9Sstevel@tonic-gate read_area = NULL; 250*7c478bd9Sstevel@tonic-gate } 251*7c478bd9Sstevel@tonic-gate if (peek_area != NULL) { 252*7c478bd9Sstevel@tonic-gate umem_free(peek_area, PEEK_AREA_SIZE); 253*7c478bd9Sstevel@tonic-gate peek_area = NULL; 254*7c478bd9Sstevel@tonic-gate } 255*7c478bd9Sstevel@tonic-gate if (peek_read_area != NULL) { 256*7c478bd9Sstevel@tonic-gate umem_free(peek_read_area, PEEK_READ_AREA_SIZE); 257*7c478bd9Sstevel@tonic-gate peek_read_area = NULL; 258*7c478bd9Sstevel@tonic-gate } 259*7c478bd9Sstevel@tonic-gate if (req_msg_hdr != NULL) { 260*7c478bd9Sstevel@tonic-gate umem_free(req_msg_hdr, req_msg_hdr_sz); 261*7c478bd9Sstevel@tonic-gate req_msg_hdr = NULL; 262*7c478bd9Sstevel@tonic-gate } 263*7c478bd9Sstevel@tonic-gate if (resp_msg_hdr != NULL) { 264*7c478bd9Sstevel@tonic-gate umem_free(resp_msg_hdr, resp_msg_hdr_sz); 265*7c478bd9Sstevel@tonic-gate resp_msg_hdr = NULL; 266*7c478bd9Sstevel@tonic-gate } 267*7c478bd9Sstevel@tonic-gate 268*7c478bd9Sstevel@tonic-gate /* 269*7c478bd9Sstevel@tonic-gate * Restore SIGALRM signal mask incase if we unblocked 270*7c478bd9Sstevel@tonic-gate * it during pcp_init. 271*7c478bd9Sstevel@tonic-gate */ 272*7c478bd9Sstevel@tonic-gate if (sigismember(&blkset, SIGALRM)) { 273*7c478bd9Sstevel@tonic-gate (void) sigprocmask(SIG_BLOCK, &blkset, NULL); 274*7c478bd9Sstevel@tonic-gate } 275*7c478bd9Sstevel@tonic-gate 276*7c478bd9Sstevel@tonic-gate /* Restore SIGALRM signal handler */ 277*7c478bd9Sstevel@tonic-gate (void) sigaction(SIGALRM, &old_act, NULL); 278*7c478bd9Sstevel@tonic-gate 279*7c478bd9Sstevel@tonic-gate return (PCPL_OK); 280*7c478bd9Sstevel@tonic-gate } 281*7c478bd9Sstevel@tonic-gate 282*7c478bd9Sstevel@tonic-gate /* 283*7c478bd9Sstevel@tonic-gate * Function: Send and Receive messages on platform channel. 284*7c478bd9Sstevel@tonic-gate * Arguments: 285*7c478bd9Sstevel@tonic-gate * pcp_msg_t *req_msg - Request Message to send to other end of channel. 286*7c478bd9Sstevel@tonic-gate * pcp_msg_t *resp_msg - Response Message to be received. 287*7c478bd9Sstevel@tonic-gate * uint32_t timeout - timeout field when waiting for data from channel. 288*7c478bd9Sstevel@tonic-gate * Returns: 289*7c478bd9Sstevel@tonic-gate * 0 - success (PCPL_OK). 290*7c478bd9Sstevel@tonic-gate * (-ve) - failure: 291*7c478bd9Sstevel@tonic-gate * PCPL_INVALID_ARGS - invalid args. 292*7c478bd9Sstevel@tonic-gate * PCPL_GLVC_TIMEOUT - glvc call timeout. 293*7c478bd9Sstevel@tonic-gate * PCPL_XPORT_ERROR - transport error in request message 294*7c478bd9Sstevel@tonic-gate * noticed by receiver. 295*7c478bd9Sstevel@tonic-gate * PCPL_MALLOC_FAIL - malloc failure. 296*7c478bd9Sstevel@tonic-gate * PCPL_CKSUM_ERROR - checksum error. 297*7c478bd9Sstevel@tonic-gate */ 298*7c478bd9Sstevel@tonic-gate int 299*7c478bd9Sstevel@tonic-gate pcp_send_recv(pcp_msg_t *req_msg, pcp_msg_t *resp_msg, uint32_t timeout) 300*7c478bd9Sstevel@tonic-gate { 301*7c478bd9Sstevel@tonic-gate void *datap; 302*7c478bd9Sstevel@tonic-gate void *resp_msg_data = NULL; 303*7c478bd9Sstevel@tonic-gate uint32_t status; 304*7c478bd9Sstevel@tonic-gate uint16_t cksum = 0; 305*7c478bd9Sstevel@tonic-gate int ret; 306*7c478bd9Sstevel@tonic-gate int resp_hdr_ok; 307*7c478bd9Sstevel@tonic-gate #ifdef PCP_CKSUM_ENABLE 308*7c478bd9Sstevel@tonic-gate uint16_t bkup_resp_hdr_cksum; 309*7c478bd9Sstevel@tonic-gate #endif 310*7c478bd9Sstevel@tonic-gate if (chnl_fd < 0) { 311*7c478bd9Sstevel@tonic-gate return (PCPL_ERROR); 312*7c478bd9Sstevel@tonic-gate } 313*7c478bd9Sstevel@tonic-gate 314*7c478bd9Sstevel@tonic-gate if (req_msg == NULL) { 315*7c478bd9Sstevel@tonic-gate return (PCPL_INVALID_ARGS); 316*7c478bd9Sstevel@tonic-gate } 317*7c478bd9Sstevel@tonic-gate 318*7c478bd9Sstevel@tonic-gate if (timeout > 0) 319*7c478bd9Sstevel@tonic-gate glvc_timeout = timeout; 320*7c478bd9Sstevel@tonic-gate else 321*7c478bd9Sstevel@tonic-gate glvc_timeout = 0; 322*7c478bd9Sstevel@tonic-gate 323*7c478bd9Sstevel@tonic-gate if ((datap = req_msg->msg_data) == NULL) 324*7c478bd9Sstevel@tonic-gate return (PCPL_INVALID_ARGS); 325*7c478bd9Sstevel@tonic-gate 326*7c478bd9Sstevel@tonic-gate if (req_msg_hdr == NULL) { 327*7c478bd9Sstevel@tonic-gate req_msg_hdr_sz = sizeof (pcp_req_msg_hdr_t); 328*7c478bd9Sstevel@tonic-gate req_msg_hdr = (pcp_req_msg_hdr_t *)umem_zalloc(req_msg_hdr_sz, 329*7c478bd9Sstevel@tonic-gate UMEM_DEFAULT); 330*7c478bd9Sstevel@tonic-gate if (req_msg_hdr == NULL) 331*7c478bd9Sstevel@tonic-gate return (PCPL_MALLOC_FAIL); 332*7c478bd9Sstevel@tonic-gate } 333*7c478bd9Sstevel@tonic-gate 334*7c478bd9Sstevel@tonic-gate /* calculate request msg_cksum */ 335*7c478bd9Sstevel@tonic-gate cksum = checksum((uint16_t *)datap, req_msg->msg_len); 336*7c478bd9Sstevel@tonic-gate 337*7c478bd9Sstevel@tonic-gate /* 338*7c478bd9Sstevel@tonic-gate * Fill in the message header for the request packet 339*7c478bd9Sstevel@tonic-gate */ 340*7c478bd9Sstevel@tonic-gate req_msg_hdr->magic_num = PCP_MAGIC_NUM; 341*7c478bd9Sstevel@tonic-gate req_msg_hdr->proto_ver = PCP_PROT_VER_1; 342*7c478bd9Sstevel@tonic-gate req_msg_hdr->msg_type = req_msg->msg_type; 343*7c478bd9Sstevel@tonic-gate req_msg_hdr->sub_type = req_msg->sub_type; 344*7c478bd9Sstevel@tonic-gate req_msg_hdr->rsvd_pad = 0; 345*7c478bd9Sstevel@tonic-gate req_msg_hdr->xid = pcp_get_xid(); 346*7c478bd9Sstevel@tonic-gate req_msg_hdr->msg_len = req_msg->msg_len; 347*7c478bd9Sstevel@tonic-gate req_msg_hdr->timeout = timeout; 348*7c478bd9Sstevel@tonic-gate req_msg_hdr->msg_cksum = cksum; 349*7c478bd9Sstevel@tonic-gate req_msg_hdr->hdr_cksum = 0; 350*7c478bd9Sstevel@tonic-gate 351*7c478bd9Sstevel@tonic-gate /* fill request header checksum */ 352*7c478bd9Sstevel@tonic-gate req_msg_hdr->hdr_cksum = checksum((uint16_t *)req_msg_hdr, 353*7c478bd9Sstevel@tonic-gate req_msg_hdr_sz); 354*7c478bd9Sstevel@tonic-gate /* 355*7c478bd9Sstevel@tonic-gate * set sig jmp location 356*7c478bd9Sstevel@tonic-gate */ 357*7c478bd9Sstevel@tonic-gate if (sigsetjmp(jmpbuf, 1)) { 358*7c478bd9Sstevel@tonic-gate return (PCPL_GLVC_TIMEOUT); 359*7c478bd9Sstevel@tonic-gate } 360*7c478bd9Sstevel@tonic-gate jumpok = 1; /* monitor sigalrm from now on */ 361*7c478bd9Sstevel@tonic-gate 362*7c478bd9Sstevel@tonic-gate /* 363*7c478bd9Sstevel@tonic-gate * send request message header 364*7c478bd9Sstevel@tonic-gate */ 365*7c478bd9Sstevel@tonic-gate if ((ret = pcp_send_req_msg_hdr(req_msg_hdr))) { 366*7c478bd9Sstevel@tonic-gate 367*7c478bd9Sstevel@tonic-gate return (ret); 368*7c478bd9Sstevel@tonic-gate } 369*7c478bd9Sstevel@tonic-gate 370*7c478bd9Sstevel@tonic-gate /* 371*7c478bd9Sstevel@tonic-gate * send request message 372*7c478bd9Sstevel@tonic-gate */ 373*7c478bd9Sstevel@tonic-gate if ((ret = pcp_io_op(datap, req_msg->msg_len, 374*7c478bd9Sstevel@tonic-gate PCPL_IO_OP_WRITE))) { 375*7c478bd9Sstevel@tonic-gate return (ret); 376*7c478bd9Sstevel@tonic-gate } 377*7c478bd9Sstevel@tonic-gate if (timeout == (uint32_t)PCP_TO_NO_RESPONSE) 378*7c478bd9Sstevel@tonic-gate return (PCPL_OK); 379*7c478bd9Sstevel@tonic-gate 380*7c478bd9Sstevel@tonic-gate if (resp_msg_hdr == NULL) { 381*7c478bd9Sstevel@tonic-gate resp_msg_hdr_sz = sizeof (pcp_resp_msg_hdr_t); 382*7c478bd9Sstevel@tonic-gate resp_msg_hdr = (pcp_resp_msg_hdr_t *)umem_alloc(resp_msg_hdr_sz, 383*7c478bd9Sstevel@tonic-gate UMEM_DEFAULT); 384*7c478bd9Sstevel@tonic-gate if (resp_msg_hdr == NULL) 385*7c478bd9Sstevel@tonic-gate return (PCPL_MALLOC_FAIL); 386*7c478bd9Sstevel@tonic-gate } 387*7c478bd9Sstevel@tonic-gate 388*7c478bd9Sstevel@tonic-gate resp_hdr_ok = 0; 389*7c478bd9Sstevel@tonic-gate while (!resp_hdr_ok) { 390*7c478bd9Sstevel@tonic-gate 391*7c478bd9Sstevel@tonic-gate /* 392*7c478bd9Sstevel@tonic-gate * Receive response message header 393*7c478bd9Sstevel@tonic-gate * Note: frame error handling is done in 394*7c478bd9Sstevel@tonic-gate * 'pcp_recv_resp_msg_hdr()'. 395*7c478bd9Sstevel@tonic-gate */ 396*7c478bd9Sstevel@tonic-gate if ((ret = pcp_recv_resp_msg_hdr(resp_msg_hdr))) { 397*7c478bd9Sstevel@tonic-gate return (ret); 398*7c478bd9Sstevel@tonic-gate } 399*7c478bd9Sstevel@tonic-gate 400*7c478bd9Sstevel@tonic-gate /* 401*7c478bd9Sstevel@tonic-gate * Check header checksum if it matches with the received hdr 402*7c478bd9Sstevel@tonic-gate * checksum. 403*7c478bd9Sstevel@tonic-gate */ 404*7c478bd9Sstevel@tonic-gate #ifdef PCP_CKSUM_ENABLE 405*7c478bd9Sstevel@tonic-gate bkup_resp_hdr_cksum = resp_msg_hdr->hdr_cksum; 406*7c478bd9Sstevel@tonic-gate resp_msg_hdr->hdr_cksum = 0; 407*7c478bd9Sstevel@tonic-gate cksum = checksum((uint16_t *)resp_msg_hdr, resp_msg_hdr_sz); 408*7c478bd9Sstevel@tonic-gate 409*7c478bd9Sstevel@tonic-gate if (cksum != bkup_resp_hdr_cksum) { 410*7c478bd9Sstevel@tonic-gate return (PCPL_CKSUM_ERROR); 411*7c478bd9Sstevel@tonic-gate } 412*7c478bd9Sstevel@tonic-gate #endif 413*7c478bd9Sstevel@tonic-gate /* 414*7c478bd9Sstevel@tonic-gate * Check for matching request and response messages 415*7c478bd9Sstevel@tonic-gate */ 416*7c478bd9Sstevel@tonic-gate if (resp_msg_hdr->xid != req_msg_hdr->xid) { 417*7c478bd9Sstevel@tonic-gate 418*7c478bd9Sstevel@tonic-gate continue; /* continue reading response header */ 419*7c478bd9Sstevel@tonic-gate } 420*7c478bd9Sstevel@tonic-gate resp_hdr_ok = 1; 421*7c478bd9Sstevel@tonic-gate } 422*7c478bd9Sstevel@tonic-gate 423*7c478bd9Sstevel@tonic-gate /* 424*7c478bd9Sstevel@tonic-gate * check status field for any channel protocol errrors 425*7c478bd9Sstevel@tonic-gate * This field signifies something happend during request 426*7c478bd9Sstevel@tonic-gate * message trasmission. This field is set by the receiver. 427*7c478bd9Sstevel@tonic-gate */ 428*7c478bd9Sstevel@tonic-gate status = resp_msg_hdr->status; 429*7c478bd9Sstevel@tonic-gate if (status != PCP_OK) { 430*7c478bd9Sstevel@tonic-gate return (PCPL_XPORT_ERROR); 431*7c478bd9Sstevel@tonic-gate } 432*7c478bd9Sstevel@tonic-gate 433*7c478bd9Sstevel@tonic-gate 434*7c478bd9Sstevel@tonic-gate /* libpcp users should free this memory */ 435*7c478bd9Sstevel@tonic-gate if ((resp_msg_data = (uint8_t *)malloc(resp_msg_hdr->msg_len)) == NULL) 436*7c478bd9Sstevel@tonic-gate return (PCPL_MALLOC_FAIL); 437*7c478bd9Sstevel@tonic-gate bzero(resp_msg_data, resp_msg_hdr->msg_len); 438*7c478bd9Sstevel@tonic-gate /* 439*7c478bd9Sstevel@tonic-gate * Receive response message. 440*7c478bd9Sstevel@tonic-gate */ 441*7c478bd9Sstevel@tonic-gate if ((ret = pcp_io_op(resp_msg_data, resp_msg_hdr->msg_len, 442*7c478bd9Sstevel@tonic-gate PCPL_IO_OP_READ))) { 443*7c478bd9Sstevel@tonic-gate free(resp_msg_data); 444*7c478bd9Sstevel@tonic-gate return (ret); 445*7c478bd9Sstevel@tonic-gate } 446*7c478bd9Sstevel@tonic-gate 447*7c478bd9Sstevel@tonic-gate #ifdef PCP_CKSUM_ENABLE 448*7c478bd9Sstevel@tonic-gate /* verify response message data checksum */ 449*7c478bd9Sstevel@tonic-gate cksum = checksum((uint16_t *)resp_msg_data, 450*7c478bd9Sstevel@tonic-gate resp_msg_hdr->msg_len); 451*7c478bd9Sstevel@tonic-gate if (cksum != resp_msg_hdr->msg_cksum) { 452*7c478bd9Sstevel@tonic-gate free(resp_msg_data); 453*7c478bd9Sstevel@tonic-gate return (PCPL_CKSUM_ERROR); 454*7c478bd9Sstevel@tonic-gate } 455*7c478bd9Sstevel@tonic-gate #endif 456*7c478bd9Sstevel@tonic-gate 457*7c478bd9Sstevel@tonic-gate /* Everything is okay put the received data into user */ 458*7c478bd9Sstevel@tonic-gate /* application's resp_msg struct */ 459*7c478bd9Sstevel@tonic-gate resp_msg->msg_len = resp_msg_hdr->msg_len; 460*7c478bd9Sstevel@tonic-gate resp_msg->msg_type = resp_msg_hdr->msg_type; 461*7c478bd9Sstevel@tonic-gate resp_msg->sub_type = resp_msg_hdr->sub_type; 462*7c478bd9Sstevel@tonic-gate resp_msg->msg_data = (uint8_t *)resp_msg_data; 463*7c478bd9Sstevel@tonic-gate 464*7c478bd9Sstevel@tonic-gate return (PCPL_OK); 465*7c478bd9Sstevel@tonic-gate 466*7c478bd9Sstevel@tonic-gate } 467*7c478bd9Sstevel@tonic-gate 468*7c478bd9Sstevel@tonic-gate /* 469*7c478bd9Sstevel@tonic-gate * Function: Get channel property values. 470*7c478bd9Sstevel@tonic-gate * Arguments: 471*7c478bd9Sstevel@tonic-gate * int prop - property id. 472*7c478bd9Sstevel@tonic-gate * unsigned int *val - property value tobe copied. 473*7c478bd9Sstevel@tonic-gate * Returns: 474*7c478bd9Sstevel@tonic-gate * 0 - success 475*7c478bd9Sstevel@tonic-gate * (-ve) - failure: 476*7c478bd9Sstevel@tonic-gate * PCPL_ERR_GLVC - glvc ioctl failure. 477*7c478bd9Sstevel@tonic-gate */ 478*7c478bd9Sstevel@tonic-gate 479*7c478bd9Sstevel@tonic-gate static int 480*7c478bd9Sstevel@tonic-gate pcp_get_prop(int prop, unsigned int *val) 481*7c478bd9Sstevel@tonic-gate { 482*7c478bd9Sstevel@tonic-gate glvc_xport_opt_op_t channel_op; 483*7c478bd9Sstevel@tonic-gate int ret; 484*7c478bd9Sstevel@tonic-gate 485*7c478bd9Sstevel@tonic-gate channel_op.op_sel = GLVC_XPORT_OPT_GET; 486*7c478bd9Sstevel@tonic-gate channel_op.opt_sel = prop; 487*7c478bd9Sstevel@tonic-gate channel_op.opt_val = 0; 488*7c478bd9Sstevel@tonic-gate 489*7c478bd9Sstevel@tonic-gate (void) alarm(glvc_timeout); 490*7c478bd9Sstevel@tonic-gate 491*7c478bd9Sstevel@tonic-gate if ((ret = ioctl(chnl_fd, GLVC_XPORT_IOCTL_OPT_OP, &channel_op)) < 0) { 492*7c478bd9Sstevel@tonic-gate (void) alarm(0); 493*7c478bd9Sstevel@tonic-gate return (ret); 494*7c478bd9Sstevel@tonic-gate } 495*7c478bd9Sstevel@tonic-gate (void) alarm(0); 496*7c478bd9Sstevel@tonic-gate 497*7c478bd9Sstevel@tonic-gate *val = channel_op.opt_val; 498*7c478bd9Sstevel@tonic-gate 499*7c478bd9Sstevel@tonic-gate return (0); 500*7c478bd9Sstevel@tonic-gate } 501*7c478bd9Sstevel@tonic-gate 502*7c478bd9Sstevel@tonic-gate /* 503*7c478bd9Sstevel@tonic-gate * Function: wrapper for handling glvc calls (read/write/peek). 504*7c478bd9Sstevel@tonic-gate */ 505*7c478bd9Sstevel@tonic-gate static int 506*7c478bd9Sstevel@tonic-gate pcp_io_op(void *buf, int byte_cnt, int io_op) 507*7c478bd9Sstevel@tonic-gate { 508*7c478bd9Sstevel@tonic-gate int rv; 509*7c478bd9Sstevel@tonic-gate int n; 510*7c478bd9Sstevel@tonic-gate uint8_t *datap; 511*7c478bd9Sstevel@tonic-gate int (*func_ptr)(uint8_t *, int); 512*7c478bd9Sstevel@tonic-gate int io_sz; 513*7c478bd9Sstevel@tonic-gate int try_cnt; 514*7c478bd9Sstevel@tonic-gate 515*7c478bd9Sstevel@tonic-gate 516*7c478bd9Sstevel@tonic-gate if ((buf == NULL) || (byte_cnt < 0)) { 517*7c478bd9Sstevel@tonic-gate return (PCPL_INVALID_ARGS); 518*7c478bd9Sstevel@tonic-gate } 519*7c478bd9Sstevel@tonic-gate 520*7c478bd9Sstevel@tonic-gate switch (io_op) { 521*7c478bd9Sstevel@tonic-gate case PCPL_IO_OP_READ: 522*7c478bd9Sstevel@tonic-gate func_ptr = pcp_read; 523*7c478bd9Sstevel@tonic-gate break; 524*7c478bd9Sstevel@tonic-gate case PCPL_IO_OP_WRITE: 525*7c478bd9Sstevel@tonic-gate func_ptr = pcp_write; 526*7c478bd9Sstevel@tonic-gate break; 527*7c478bd9Sstevel@tonic-gate case PCPL_IO_OP_PEEK: 528*7c478bd9Sstevel@tonic-gate func_ptr = pcp_peek; 529*7c478bd9Sstevel@tonic-gate break; 530*7c478bd9Sstevel@tonic-gate default: 531*7c478bd9Sstevel@tonic-gate return (PCPL_INVALID_ARGS); 532*7c478bd9Sstevel@tonic-gate } 533*7c478bd9Sstevel@tonic-gate 534*7c478bd9Sstevel@tonic-gate /* 535*7c478bd9Sstevel@tonic-gate * loop until all I/O done, try limit exceded, or real failure 536*7c478bd9Sstevel@tonic-gate */ 537*7c478bd9Sstevel@tonic-gate 538*7c478bd9Sstevel@tonic-gate rv = 0; 539*7c478bd9Sstevel@tonic-gate datap = buf; 540*7c478bd9Sstevel@tonic-gate while (rv < byte_cnt) { 541*7c478bd9Sstevel@tonic-gate io_sz = MIN((byte_cnt - rv), mtu_size); 542*7c478bd9Sstevel@tonic-gate try_cnt = 0; 543*7c478bd9Sstevel@tonic-gate while ((n = (*func_ptr)(datap, io_sz)) < 0) { 544*7c478bd9Sstevel@tonic-gate try_cnt++; 545*7c478bd9Sstevel@tonic-gate if (try_cnt > PCPL_MAX_TRY_CNT) { 546*7c478bd9Sstevel@tonic-gate rv = n; 547*7c478bd9Sstevel@tonic-gate goto done; 548*7c478bd9Sstevel@tonic-gate } 549*7c478bd9Sstevel@tonic-gate (void) sleep(PCPL_GLVC_SLEEP); 550*7c478bd9Sstevel@tonic-gate } /* while trying the io operation */ 551*7c478bd9Sstevel@tonic-gate 552*7c478bd9Sstevel@tonic-gate if (n < 0) { 553*7c478bd9Sstevel@tonic-gate rv = n; 554*7c478bd9Sstevel@tonic-gate goto done; 555*7c478bd9Sstevel@tonic-gate } 556*7c478bd9Sstevel@tonic-gate rv += n; 557*7c478bd9Sstevel@tonic-gate datap += n; 558*7c478bd9Sstevel@tonic-gate } /* while still have more data */ 559*7c478bd9Sstevel@tonic-gate 560*7c478bd9Sstevel@tonic-gate done: 561*7c478bd9Sstevel@tonic-gate if (rv == byte_cnt) 562*7c478bd9Sstevel@tonic-gate return (0); 563*7c478bd9Sstevel@tonic-gate else 564*7c478bd9Sstevel@tonic-gate return (PCPL_GLVC_ERROR); 565*7c478bd9Sstevel@tonic-gate } 566*7c478bd9Sstevel@tonic-gate 567*7c478bd9Sstevel@tonic-gate /* 568*7c478bd9Sstevel@tonic-gate * For peeking 'bytes_cnt' bytes in channel (glvc) buffers. 569*7c478bd9Sstevel@tonic-gate * If data is available, the data is copied into 'buf'. 570*7c478bd9Sstevel@tonic-gate */ 571*7c478bd9Sstevel@tonic-gate static int 572*7c478bd9Sstevel@tonic-gate pcp_peek(uint8_t *buf, int bytes_cnt) 573*7c478bd9Sstevel@tonic-gate { 574*7c478bd9Sstevel@tonic-gate int ret; 575*7c478bd9Sstevel@tonic-gate glvc_xport_msg_peek_t peek_ctrl; 576*7c478bd9Sstevel@tonic-gate int n, m; 577*7c478bd9Sstevel@tonic-gate 578*7c478bd9Sstevel@tonic-gate if (bytes_cnt < 0 || bytes_cnt > mtu_size) { 579*7c478bd9Sstevel@tonic-gate return (PCPL_INVALID_ARGS); 580*7c478bd9Sstevel@tonic-gate } 581*7c478bd9Sstevel@tonic-gate 582*7c478bd9Sstevel@tonic-gate /* 583*7c478bd9Sstevel@tonic-gate * initialization of buffers used for peeking data in channel buffers. 584*7c478bd9Sstevel@tonic-gate */ 585*7c478bd9Sstevel@tonic-gate if (peek_area == NULL) { 586*7c478bd9Sstevel@tonic-gate peek_area = (uint8_t *)umem_zalloc(PEEK_AREA_SIZE, 587*7c478bd9Sstevel@tonic-gate UMEM_DEFAULT); 588*7c478bd9Sstevel@tonic-gate if (peek_area == NULL) { 589*7c478bd9Sstevel@tonic-gate return (PCPL_MALLOC_FAIL); 590*7c478bd9Sstevel@tonic-gate } 591*7c478bd9Sstevel@tonic-gate } 592*7c478bd9Sstevel@tonic-gate 593*7c478bd9Sstevel@tonic-gate /* 594*7c478bd9Sstevel@tonic-gate * peek max MTU size bytes 595*7c478bd9Sstevel@tonic-gate */ 596*7c478bd9Sstevel@tonic-gate peek_ctrl.buf = (caddr_t)peek_area; 597*7c478bd9Sstevel@tonic-gate peek_ctrl.buflen = mtu_size; 598*7c478bd9Sstevel@tonic-gate peek_ctrl.flags = 0; 599*7c478bd9Sstevel@tonic-gate 600*7c478bd9Sstevel@tonic-gate (void) alarm(glvc_timeout); 601*7c478bd9Sstevel@tonic-gate 602*7c478bd9Sstevel@tonic-gate if ((ret = ioctl(chnl_fd, GLVC_XPORT_IOCTL_DATA_PEEK, &peek_ctrl)) 603*7c478bd9Sstevel@tonic-gate < 0) { 604*7c478bd9Sstevel@tonic-gate (void) alarm(0); 605*7c478bd9Sstevel@tonic-gate return (ret); 606*7c478bd9Sstevel@tonic-gate } 607*7c478bd9Sstevel@tonic-gate (void) alarm(0); 608*7c478bd9Sstevel@tonic-gate 609*7c478bd9Sstevel@tonic-gate n = peek_ctrl.buflen; 610*7c478bd9Sstevel@tonic-gate 611*7c478bd9Sstevel@tonic-gate if (n < 0) 612*7c478bd9Sstevel@tonic-gate return (PCPL_GLVC_ERROR); 613*7c478bd9Sstevel@tonic-gate 614*7c478bd9Sstevel@tonic-gate /* 615*7c478bd9Sstevel@tonic-gate * satisfy request as best as we can 616*7c478bd9Sstevel@tonic-gate */ 617*7c478bd9Sstevel@tonic-gate m = MIN(bytes_cnt, n); 618*7c478bd9Sstevel@tonic-gate (void) memcpy(buf, peek_area, m); 619*7c478bd9Sstevel@tonic-gate 620*7c478bd9Sstevel@tonic-gate return (m); 621*7c478bd9Sstevel@tonic-gate 622*7c478bd9Sstevel@tonic-gate } 623*7c478bd9Sstevel@tonic-gate 624*7c478bd9Sstevel@tonic-gate /* 625*7c478bd9Sstevel@tonic-gate * Function: write 'byte_cnt' bytes from 'buf' to channel. 626*7c478bd9Sstevel@tonic-gate */ 627*7c478bd9Sstevel@tonic-gate static int 628*7c478bd9Sstevel@tonic-gate pcp_write(uint8_t *buf, int byte_cnt) 629*7c478bd9Sstevel@tonic-gate { 630*7c478bd9Sstevel@tonic-gate 631*7c478bd9Sstevel@tonic-gate int ret; 632*7c478bd9Sstevel@tonic-gate 633*7c478bd9Sstevel@tonic-gate /* check for valid arguments */ 634*7c478bd9Sstevel@tonic-gate if (buf == NULL || byte_cnt < 0 || byte_cnt > mtu_size) { 635*7c478bd9Sstevel@tonic-gate return (PCPL_INVALID_ARGS); 636*7c478bd9Sstevel@tonic-gate } 637*7c478bd9Sstevel@tonic-gate 638*7c478bd9Sstevel@tonic-gate (void) alarm(glvc_timeout); 639*7c478bd9Sstevel@tonic-gate 640*7c478bd9Sstevel@tonic-gate if ((ret = write(chnl_fd, buf, byte_cnt)) < 0) { 641*7c478bd9Sstevel@tonic-gate (void) alarm(0); 642*7c478bd9Sstevel@tonic-gate return (ret); 643*7c478bd9Sstevel@tonic-gate } 644*7c478bd9Sstevel@tonic-gate (void) alarm(0); 645*7c478bd9Sstevel@tonic-gate 646*7c478bd9Sstevel@tonic-gate return (ret); 647*7c478bd9Sstevel@tonic-gate } 648*7c478bd9Sstevel@tonic-gate 649*7c478bd9Sstevel@tonic-gate /* 650*7c478bd9Sstevel@tonic-gate * In current implementaion of glvc driver, streams reads are not supported. 651*7c478bd9Sstevel@tonic-gate * pcp_read mimics stream reads by first reading all the bytes present in the 652*7c478bd9Sstevel@tonic-gate * channel buffer into a local buffer and from then on read requests 653*7c478bd9Sstevel@tonic-gate * are serviced from local buffer. When read requests are not serviceble 654*7c478bd9Sstevel@tonic-gate * from local buffer, it repeates by first reading data from channel buffers. 655*7c478bd9Sstevel@tonic-gate * 656*7c478bd9Sstevel@tonic-gate * This call may need to be enhanced when glvc supports buffered (stream) 657*7c478bd9Sstevel@tonic-gate * reads - TBD 658*7c478bd9Sstevel@tonic-gate */ 659*7c478bd9Sstevel@tonic-gate 660*7c478bd9Sstevel@tonic-gate static int 661*7c478bd9Sstevel@tonic-gate pcp_read(uint8_t *buf, int byte_cnt) 662*7c478bd9Sstevel@tonic-gate { 663*7c478bd9Sstevel@tonic-gate int ret; 664*7c478bd9Sstevel@tonic-gate int n, m, i; 665*7c478bd9Sstevel@tonic-gate 666*7c478bd9Sstevel@tonic-gate if (byte_cnt < 0 || byte_cnt > mtu_size) { 667*7c478bd9Sstevel@tonic-gate return (PCPL_INVALID_ARGS); 668*7c478bd9Sstevel@tonic-gate } 669*7c478bd9Sstevel@tonic-gate 670*7c478bd9Sstevel@tonic-gate /* 671*7c478bd9Sstevel@tonic-gate * initialization of local read buffer 672*7c478bd9Sstevel@tonic-gate * from which the stream read requests are serviced. 673*7c478bd9Sstevel@tonic-gate */ 674*7c478bd9Sstevel@tonic-gate if (read_area == NULL) { 675*7c478bd9Sstevel@tonic-gate read_area = (uint8_t *)umem_zalloc(READ_AREA_SIZE, 676*7c478bd9Sstevel@tonic-gate UMEM_DEFAULT); 677*7c478bd9Sstevel@tonic-gate if (read_area == NULL) { 678*7c478bd9Sstevel@tonic-gate return (PCPL_MALLOC_FAIL); 679*7c478bd9Sstevel@tonic-gate } 680*7c478bd9Sstevel@tonic-gate read_head = read_area; 681*7c478bd9Sstevel@tonic-gate read_tail = read_area; 682*7c478bd9Sstevel@tonic-gate } 683*7c478bd9Sstevel@tonic-gate 684*7c478bd9Sstevel@tonic-gate /* 685*7c478bd9Sstevel@tonic-gate * if we already read this data then copy from local buffer it self 686*7c478bd9Sstevel@tonic-gate * without calling new read. 687*7c478bd9Sstevel@tonic-gate */ 688*7c478bd9Sstevel@tonic-gate if (byte_cnt <= (read_tail - read_head)) { 689*7c478bd9Sstevel@tonic-gate (void) memcpy(buf, read_head, byte_cnt); 690*7c478bd9Sstevel@tonic-gate read_head += byte_cnt; 691*7c478bd9Sstevel@tonic-gate return (byte_cnt); 692*7c478bd9Sstevel@tonic-gate } 693*7c478bd9Sstevel@tonic-gate 694*7c478bd9Sstevel@tonic-gate /* 695*7c478bd9Sstevel@tonic-gate * if the request is not satisfied from the buffered data, then move the 696*7c478bd9Sstevel@tonic-gate * remaining data to front of the buffer and read new data. 697*7c478bd9Sstevel@tonic-gate */ 698*7c478bd9Sstevel@tonic-gate for (i = 0; i < (read_tail - read_head); ++i) { 699*7c478bd9Sstevel@tonic-gate read_area[i] = read_head[i]; 700*7c478bd9Sstevel@tonic-gate } 701*7c478bd9Sstevel@tonic-gate read_head = read_area; 702*7c478bd9Sstevel@tonic-gate read_tail = read_head + i; 703*7c478bd9Sstevel@tonic-gate 704*7c478bd9Sstevel@tonic-gate /* 705*7c478bd9Sstevel@tonic-gate * do a peek to see how much data is available and read complete data. 706*7c478bd9Sstevel@tonic-gate */ 707*7c478bd9Sstevel@tonic-gate 708*7c478bd9Sstevel@tonic-gate if ((m = pcp_peek(read_tail, mtu_size)) < 0) { 709*7c478bd9Sstevel@tonic-gate return (m); 710*7c478bd9Sstevel@tonic-gate } 711*7c478bd9Sstevel@tonic-gate 712*7c478bd9Sstevel@tonic-gate (void) alarm(glvc_timeout); 713*7c478bd9Sstevel@tonic-gate if ((ret = read(chnl_fd, read_tail, m)) < 0) { 714*7c478bd9Sstevel@tonic-gate (void) alarm(0); 715*7c478bd9Sstevel@tonic-gate return (ret); 716*7c478bd9Sstevel@tonic-gate } 717*7c478bd9Sstevel@tonic-gate 718*7c478bd9Sstevel@tonic-gate (void) alarm(0); 719*7c478bd9Sstevel@tonic-gate read_tail += ret; 720*7c478bd9Sstevel@tonic-gate 721*7c478bd9Sstevel@tonic-gate /* 722*7c478bd9Sstevel@tonic-gate * copy the requested bytes. 723*7c478bd9Sstevel@tonic-gate */ 724*7c478bd9Sstevel@tonic-gate n = MIN(byte_cnt, (read_tail - read_head)); 725*7c478bd9Sstevel@tonic-gate (void) memcpy(buf, read_head, n); 726*7c478bd9Sstevel@tonic-gate 727*7c478bd9Sstevel@tonic-gate read_head += n; 728*7c478bd9Sstevel@tonic-gate 729*7c478bd9Sstevel@tonic-gate return (n); 730*7c478bd9Sstevel@tonic-gate } 731*7c478bd9Sstevel@tonic-gate 732*7c478bd9Sstevel@tonic-gate /* 733*7c478bd9Sstevel@tonic-gate * This function is slight different from pcp_peek. The peek requests are first 734*7c478bd9Sstevel@tonic-gate * serviced from local read buffer, if data is available. If the peek request 735*7c478bd9Sstevel@tonic-gate * is not serviceble from local read buffer, then the data is peeked from 736*7c478bd9Sstevel@tonic-gate * channel buffer. This function is mainly used for proper protocol framing 737*7c478bd9Sstevel@tonic-gate * error handling. 738*7c478bd9Sstevel@tonic-gate */ 739*7c478bd9Sstevel@tonic-gate static int 740*7c478bd9Sstevel@tonic-gate pcp_peek_read(uint8_t *buf, int byte_cnt) 741*7c478bd9Sstevel@tonic-gate { 742*7c478bd9Sstevel@tonic-gate int n, m, i; 743*7c478bd9Sstevel@tonic-gate 744*7c478bd9Sstevel@tonic-gate if (byte_cnt < 0 || byte_cnt > mtu_size) { 745*7c478bd9Sstevel@tonic-gate return (PCPL_INVALID_ARGS); 746*7c478bd9Sstevel@tonic-gate } 747*7c478bd9Sstevel@tonic-gate 748*7c478bd9Sstevel@tonic-gate /* 749*7c478bd9Sstevel@tonic-gate * initialization of peek_read buffer. 750*7c478bd9Sstevel@tonic-gate */ 751*7c478bd9Sstevel@tonic-gate if (peek_read_area == NULL) { 752*7c478bd9Sstevel@tonic-gate peek_read_area = (uint8_t *)umem_zalloc(PEEK_READ_AREA_SIZE, 753*7c478bd9Sstevel@tonic-gate UMEM_DEFAULT); 754*7c478bd9Sstevel@tonic-gate if (peek_read_area == NULL) { 755*7c478bd9Sstevel@tonic-gate return (PCPL_MALLOC_FAIL); 756*7c478bd9Sstevel@tonic-gate } 757*7c478bd9Sstevel@tonic-gate peek_read_head = peek_read_area; 758*7c478bd9Sstevel@tonic-gate peek_read_tail = peek_read_area; 759*7c478bd9Sstevel@tonic-gate } 760*7c478bd9Sstevel@tonic-gate 761*7c478bd9Sstevel@tonic-gate /* 762*7c478bd9Sstevel@tonic-gate * if we already have the data in local read buffer then copy 763*7c478bd9Sstevel@tonic-gate * from local buffer it self w/out calling new peek 764*7c478bd9Sstevel@tonic-gate */ 765*7c478bd9Sstevel@tonic-gate if (byte_cnt <= (read_tail - read_head)) { 766*7c478bd9Sstevel@tonic-gate (void) memcpy(buf, read_head, byte_cnt); 767*7c478bd9Sstevel@tonic-gate return (byte_cnt); 768*7c478bd9Sstevel@tonic-gate } 769*7c478bd9Sstevel@tonic-gate 770*7c478bd9Sstevel@tonic-gate /* 771*7c478bd9Sstevel@tonic-gate * if the request is not satisfied from local read buffer, then first 772*7c478bd9Sstevel@tonic-gate * copy the remaining data in local read buffer to peek_read_area and 773*7c478bd9Sstevel@tonic-gate * then issue new peek. 774*7c478bd9Sstevel@tonic-gate */ 775*7c478bd9Sstevel@tonic-gate for (i = 0; i < (read_tail - read_head); ++i) { 776*7c478bd9Sstevel@tonic-gate peek_read_area[i] = read_head[i]; 777*7c478bd9Sstevel@tonic-gate } 778*7c478bd9Sstevel@tonic-gate peek_read_head = peek_read_area; 779*7c478bd9Sstevel@tonic-gate peek_read_tail = peek_read_head + i; 780*7c478bd9Sstevel@tonic-gate 781*7c478bd9Sstevel@tonic-gate /* 782*7c478bd9Sstevel@tonic-gate * do a peek to see how much data is available and read complete data. 783*7c478bd9Sstevel@tonic-gate */ 784*7c478bd9Sstevel@tonic-gate 785*7c478bd9Sstevel@tonic-gate if ((m = pcp_peek(peek_read_tail, mtu_size)) < 0) { 786*7c478bd9Sstevel@tonic-gate return (m); 787*7c478bd9Sstevel@tonic-gate } 788*7c478bd9Sstevel@tonic-gate 789*7c478bd9Sstevel@tonic-gate peek_read_tail += m; 790*7c478bd9Sstevel@tonic-gate 791*7c478bd9Sstevel@tonic-gate /* 792*7c478bd9Sstevel@tonic-gate * copy the requested bytes 793*7c478bd9Sstevel@tonic-gate */ 794*7c478bd9Sstevel@tonic-gate n = MIN(byte_cnt, (peek_read_tail - peek_read_head)); 795*7c478bd9Sstevel@tonic-gate (void) memcpy(buf, peek_read_head, n); 796*7c478bd9Sstevel@tonic-gate 797*7c478bd9Sstevel@tonic-gate return (n); 798*7c478bd9Sstevel@tonic-gate } 799*7c478bd9Sstevel@tonic-gate 800*7c478bd9Sstevel@tonic-gate /* 801*7c478bd9Sstevel@tonic-gate * Send Request Message Header. 802*7c478bd9Sstevel@tonic-gate */ 803*7c478bd9Sstevel@tonic-gate static int 804*7c478bd9Sstevel@tonic-gate pcp_send_req_msg_hdr(pcp_req_msg_hdr_t *req_hdr) 805*7c478bd9Sstevel@tonic-gate { 806*7c478bd9Sstevel@tonic-gate pcp_req_msg_hdr_t *hdrp; 807*7c478bd9Sstevel@tonic-gate int hdr_sz; 808*7c478bd9Sstevel@tonic-gate int ret; 809*7c478bd9Sstevel@tonic-gate 810*7c478bd9Sstevel@tonic-gate hdr_sz = sizeof (pcp_req_msg_hdr_t); 811*7c478bd9Sstevel@tonic-gate if ((hdrp = (pcp_req_msg_hdr_t *)umem_zalloc(hdr_sz, 812*7c478bd9Sstevel@tonic-gate UMEM_DEFAULT)) == NULL) { 813*7c478bd9Sstevel@tonic-gate return (PCPL_MALLOC_FAIL); 814*7c478bd9Sstevel@tonic-gate } 815*7c478bd9Sstevel@tonic-gate 816*7c478bd9Sstevel@tonic-gate hdrp->magic_num = htonl(req_hdr->magic_num); 817*7c478bd9Sstevel@tonic-gate hdrp->proto_ver = req_hdr->proto_ver; 818*7c478bd9Sstevel@tonic-gate hdrp->msg_type = req_hdr->msg_type; 819*7c478bd9Sstevel@tonic-gate hdrp->sub_type = req_hdr->sub_type; 820*7c478bd9Sstevel@tonic-gate hdrp->rsvd_pad = htons(req_hdr->rsvd_pad); 821*7c478bd9Sstevel@tonic-gate hdrp->xid = htonl(req_hdr->xid); 822*7c478bd9Sstevel@tonic-gate hdrp->timeout = htonl(req_hdr->timeout); 823*7c478bd9Sstevel@tonic-gate hdrp->msg_len = htonl(req_hdr->msg_len); 824*7c478bd9Sstevel@tonic-gate hdrp->msg_cksum = htons(req_hdr->msg_cksum); 825*7c478bd9Sstevel@tonic-gate hdrp->hdr_cksum = htons(req_hdr->hdr_cksum); 826*7c478bd9Sstevel@tonic-gate 827*7c478bd9Sstevel@tonic-gate if ((ret = pcp_io_op((char *)hdrp, hdr_sz, PCPL_IO_OP_WRITE)) != 0) { 828*7c478bd9Sstevel@tonic-gate umem_free(hdrp, hdr_sz); 829*7c478bd9Sstevel@tonic-gate return (ret); 830*7c478bd9Sstevel@tonic-gate } 831*7c478bd9Sstevel@tonic-gate umem_free(hdrp, hdr_sz); 832*7c478bd9Sstevel@tonic-gate return (PCP_OK); 833*7c478bd9Sstevel@tonic-gate } 834*7c478bd9Sstevel@tonic-gate 835*7c478bd9Sstevel@tonic-gate /* 836*7c478bd9Sstevel@tonic-gate * Receive Response message header. 837*7c478bd9Sstevel@tonic-gate */ 838*7c478bd9Sstevel@tonic-gate static int 839*7c478bd9Sstevel@tonic-gate pcp_recv_resp_msg_hdr(pcp_resp_msg_hdr_t *resp_hdr) 840*7c478bd9Sstevel@tonic-gate { 841*7c478bd9Sstevel@tonic-gate uint32_t magic_num; 842*7c478bd9Sstevel@tonic-gate uint8_t proto_ver; 843*7c478bd9Sstevel@tonic-gate uint8_t msg_type; 844*7c478bd9Sstevel@tonic-gate uint8_t sub_type; 845*7c478bd9Sstevel@tonic-gate uint8_t rsvd_pad; 846*7c478bd9Sstevel@tonic-gate uint32_t xid; 847*7c478bd9Sstevel@tonic-gate uint32_t timeout; 848*7c478bd9Sstevel@tonic-gate uint32_t msg_len; 849*7c478bd9Sstevel@tonic-gate uint32_t status; 850*7c478bd9Sstevel@tonic-gate uint16_t msg_cksum; 851*7c478bd9Sstevel@tonic-gate uint16_t hdr_cksum; 852*7c478bd9Sstevel@tonic-gate int ret; 853*7c478bd9Sstevel@tonic-gate 854*7c478bd9Sstevel@tonic-gate if (resp_hdr == NULL) { 855*7c478bd9Sstevel@tonic-gate return (PCPL_INVALID_ARGS); 856*7c478bd9Sstevel@tonic-gate } 857*7c478bd9Sstevel@tonic-gate 858*7c478bd9Sstevel@tonic-gate /* 859*7c478bd9Sstevel@tonic-gate * handle protocol framing errors. 860*7c478bd9Sstevel@tonic-gate * pcp_frame_error_handle() returns when proper frame arrived 861*7c478bd9Sstevel@tonic-gate * (magic seq) or if an error happens while reading data from 862*7c478bd9Sstevel@tonic-gate * channel. 863*7c478bd9Sstevel@tonic-gate */ 864*7c478bd9Sstevel@tonic-gate if ((ret = pcp_frame_error_handle()) != 0) 865*7c478bd9Sstevel@tonic-gate return (PCPL_FRAME_ERROR); 866*7c478bd9Sstevel@tonic-gate 867*7c478bd9Sstevel@tonic-gate /* read magic number first */ 868*7c478bd9Sstevel@tonic-gate if ((ret = pcp_io_op(&magic_num, sizeof (magic_num), 869*7c478bd9Sstevel@tonic-gate PCPL_IO_OP_READ)) != 0) { 870*7c478bd9Sstevel@tonic-gate return (ret); 871*7c478bd9Sstevel@tonic-gate } 872*7c478bd9Sstevel@tonic-gate 873*7c478bd9Sstevel@tonic-gate magic_num = ntohl(magic_num); 874*7c478bd9Sstevel@tonic-gate 875*7c478bd9Sstevel@tonic-gate if (magic_num != PCP_MAGIC_NUM) { 876*7c478bd9Sstevel@tonic-gate return (PCPL_FRAME_ERROR); 877*7c478bd9Sstevel@tonic-gate } 878*7c478bd9Sstevel@tonic-gate 879*7c478bd9Sstevel@tonic-gate /* read version field */ 880*7c478bd9Sstevel@tonic-gate if ((ret = pcp_io_op(&proto_ver, sizeof (proto_ver), 881*7c478bd9Sstevel@tonic-gate PCPL_IO_OP_READ)) != 0) { 882*7c478bd9Sstevel@tonic-gate return (ret); 883*7c478bd9Sstevel@tonic-gate } 884*7c478bd9Sstevel@tonic-gate 885*7c478bd9Sstevel@tonic-gate /* check protocol version */ 886*7c478bd9Sstevel@tonic-gate if (proto_ver != PCP_PROT_VER_1) { 887*7c478bd9Sstevel@tonic-gate return (PCPL_PROT_ERROR); 888*7c478bd9Sstevel@tonic-gate } 889*7c478bd9Sstevel@tonic-gate 890*7c478bd9Sstevel@tonic-gate /* Read message type */ 891*7c478bd9Sstevel@tonic-gate if ((ret = pcp_io_op(&msg_type, sizeof (msg_type), 892*7c478bd9Sstevel@tonic-gate PCPL_IO_OP_READ)) != 0) { 893*7c478bd9Sstevel@tonic-gate return (ret); 894*7c478bd9Sstevel@tonic-gate } 895*7c478bd9Sstevel@tonic-gate 896*7c478bd9Sstevel@tonic-gate /* Read message sub type */ 897*7c478bd9Sstevel@tonic-gate if ((ret = pcp_io_op(&sub_type, sizeof (sub_type), 898*7c478bd9Sstevel@tonic-gate PCPL_IO_OP_READ)) != 0) { 899*7c478bd9Sstevel@tonic-gate return (ret); 900*7c478bd9Sstevel@tonic-gate } 901*7c478bd9Sstevel@tonic-gate 902*7c478bd9Sstevel@tonic-gate /* Read rcvd_pad bits */ 903*7c478bd9Sstevel@tonic-gate if ((ret = pcp_io_op(&rsvd_pad, sizeof (rsvd_pad), 904*7c478bd9Sstevel@tonic-gate PCPL_IO_OP_READ)) != 0) { 905*7c478bd9Sstevel@tonic-gate return (ret); 906*7c478bd9Sstevel@tonic-gate } 907*7c478bd9Sstevel@tonic-gate 908*7c478bd9Sstevel@tonic-gate /* receive transaction id */ 909*7c478bd9Sstevel@tonic-gate if ((ret = pcp_io_op(&xid, sizeof (xid), 910*7c478bd9Sstevel@tonic-gate PCPL_IO_OP_READ)) != 0) { 911*7c478bd9Sstevel@tonic-gate return (ret); 912*7c478bd9Sstevel@tonic-gate } 913*7c478bd9Sstevel@tonic-gate 914*7c478bd9Sstevel@tonic-gate xid = ntohl(xid); 915*7c478bd9Sstevel@tonic-gate 916*7c478bd9Sstevel@tonic-gate /* receive timeout value */ 917*7c478bd9Sstevel@tonic-gate if ((ret = pcp_io_op(&timeout, sizeof (timeout), 918*7c478bd9Sstevel@tonic-gate PCPL_IO_OP_READ)) != 0) { 919*7c478bd9Sstevel@tonic-gate return (ret); 920*7c478bd9Sstevel@tonic-gate } 921*7c478bd9Sstevel@tonic-gate 922*7c478bd9Sstevel@tonic-gate timeout = ntohl(timeout); 923*7c478bd9Sstevel@tonic-gate 924*7c478bd9Sstevel@tonic-gate /* receive message length */ 925*7c478bd9Sstevel@tonic-gate if ((ret = pcp_io_op(&msg_len, sizeof (msg_len), 926*7c478bd9Sstevel@tonic-gate PCPL_IO_OP_READ)) != 0) { 927*7c478bd9Sstevel@tonic-gate return (ret); 928*7c478bd9Sstevel@tonic-gate } 929*7c478bd9Sstevel@tonic-gate 930*7c478bd9Sstevel@tonic-gate msg_len = ntohl(msg_len); 931*7c478bd9Sstevel@tonic-gate 932*7c478bd9Sstevel@tonic-gate /* receive status field */ 933*7c478bd9Sstevel@tonic-gate if ((ret = pcp_io_op(&status, sizeof (status), 934*7c478bd9Sstevel@tonic-gate PCPL_IO_OP_READ)) != 0) { 935*7c478bd9Sstevel@tonic-gate return (ret); 936*7c478bd9Sstevel@tonic-gate } 937*7c478bd9Sstevel@tonic-gate 938*7c478bd9Sstevel@tonic-gate status = ntohl(status); 939*7c478bd9Sstevel@tonic-gate 940*7c478bd9Sstevel@tonic-gate /* receive message checksum */ 941*7c478bd9Sstevel@tonic-gate if ((ret = pcp_io_op(&msg_cksum, sizeof (msg_cksum), 942*7c478bd9Sstevel@tonic-gate PCPL_IO_OP_READ)) != 0) { 943*7c478bd9Sstevel@tonic-gate return (ret); 944*7c478bd9Sstevel@tonic-gate } 945*7c478bd9Sstevel@tonic-gate 946*7c478bd9Sstevel@tonic-gate msg_cksum = ntohs(msg_cksum); 947*7c478bd9Sstevel@tonic-gate 948*7c478bd9Sstevel@tonic-gate /* receive header checksum */ 949*7c478bd9Sstevel@tonic-gate if ((ret = pcp_io_op(&hdr_cksum, sizeof (hdr_cksum), 950*7c478bd9Sstevel@tonic-gate PCPL_IO_OP_READ)) != 0) { 951*7c478bd9Sstevel@tonic-gate return (ret); 952*7c478bd9Sstevel@tonic-gate } 953*7c478bd9Sstevel@tonic-gate 954*7c478bd9Sstevel@tonic-gate hdr_cksum = ntohs(hdr_cksum); 955*7c478bd9Sstevel@tonic-gate 956*7c478bd9Sstevel@tonic-gate /* copy to resp_hdr */ 957*7c478bd9Sstevel@tonic-gate 958*7c478bd9Sstevel@tonic-gate resp_hdr->magic_num = magic_num; 959*7c478bd9Sstevel@tonic-gate resp_hdr->proto_ver = proto_ver; 960*7c478bd9Sstevel@tonic-gate resp_hdr->msg_type = msg_type; 961*7c478bd9Sstevel@tonic-gate resp_hdr->sub_type = sub_type; 962*7c478bd9Sstevel@tonic-gate resp_hdr->rsvd_pad = rsvd_pad; 963*7c478bd9Sstevel@tonic-gate resp_hdr->xid = xid; 964*7c478bd9Sstevel@tonic-gate resp_hdr->timeout = timeout; 965*7c478bd9Sstevel@tonic-gate resp_hdr->msg_len = msg_len; 966*7c478bd9Sstevel@tonic-gate resp_hdr->status = status; 967*7c478bd9Sstevel@tonic-gate resp_hdr->msg_cksum = msg_cksum; 968*7c478bd9Sstevel@tonic-gate resp_hdr->hdr_cksum = hdr_cksum; 969*7c478bd9Sstevel@tonic-gate 970*7c478bd9Sstevel@tonic-gate return (PCP_OK); 971*7c478bd9Sstevel@tonic-gate } 972*7c478bd9Sstevel@tonic-gate 973*7c478bd9Sstevel@tonic-gate /* 974*7c478bd9Sstevel@tonic-gate * Get next xid for including in request message. 975*7c478bd9Sstevel@tonic-gate * Every request and response message are matched 976*7c478bd9Sstevel@tonic-gate * for same xid. 977*7c478bd9Sstevel@tonic-gate */ 978*7c478bd9Sstevel@tonic-gate static int pcp_get_xid(void) 979*7c478bd9Sstevel@tonic-gate { 980*7c478bd9Sstevel@tonic-gate uint32_t ret; 981*7c478bd9Sstevel@tonic-gate 982*7c478bd9Sstevel@tonic-gate ret = msg_xid; 983*7c478bd9Sstevel@tonic-gate if (msg_xid == PCPL_MAX_XID) 984*7c478bd9Sstevel@tonic-gate msg_xid = PCPL_MIN_XID; 985*7c478bd9Sstevel@tonic-gate else 986*7c478bd9Sstevel@tonic-gate ++msg_xid; 987*7c478bd9Sstevel@tonic-gate return (ret); 988*7c478bd9Sstevel@tonic-gate } 989*7c478bd9Sstevel@tonic-gate 990*7c478bd9Sstevel@tonic-gate /* 991*7c478bd9Sstevel@tonic-gate * This function handles channel framing errors. It waits until proper 992*7c478bd9Sstevel@tonic-gate * frame with starting sequence as magic numder (0xAFBCAFA0) 993*7c478bd9Sstevel@tonic-gate * is arrived. It removes unexpected data (before the magic number sequence) 994*7c478bd9Sstevel@tonic-gate * on the channel. It returns when proper magic number sequence is seen 995*7c478bd9Sstevel@tonic-gate * or when any failure happens while reading/peeking the channel. 996*7c478bd9Sstevel@tonic-gate */ 997*7c478bd9Sstevel@tonic-gate static int 998*7c478bd9Sstevel@tonic-gate pcp_frame_error_handle(void) 999*7c478bd9Sstevel@tonic-gate { 1000*7c478bd9Sstevel@tonic-gate uint8_t magic_num_buf[4]; 1001*7c478bd9Sstevel@tonic-gate int ispresent = 0; 1002*7c478bd9Sstevel@tonic-gate uint32_t net_magic_num; /* magic byte in network byte order */ 1003*7c478bd9Sstevel@tonic-gate uint32_t host_magic_num = PCP_MAGIC_NUM; 1004*7c478bd9Sstevel@tonic-gate uint8_t buf[2]; 1005*7c478bd9Sstevel@tonic-gate 1006*7c478bd9Sstevel@tonic-gate net_magic_num = htonl(host_magic_num); 1007*7c478bd9Sstevel@tonic-gate (void) memcpy(magic_num_buf, (uint8_t *)&net_magic_num, 4); 1008*7c478bd9Sstevel@tonic-gate 1009*7c478bd9Sstevel@tonic-gate while (!ispresent) { 1010*7c478bd9Sstevel@tonic-gate /* 1011*7c478bd9Sstevel@tonic-gate * Check if next four bytes matches pcp magic number. 1012*7c478bd9Sstevel@tonic-gate * if mathing not found, discard 1 byte and continue checking. 1013*7c478bd9Sstevel@tonic-gate */ 1014*7c478bd9Sstevel@tonic-gate if (!check_magic_byte_presence(4, &magic_num_buf[0], 1015*7c478bd9Sstevel@tonic-gate &ispresent)) { 1016*7c478bd9Sstevel@tonic-gate if (!ispresent) { 1017*7c478bd9Sstevel@tonic-gate /* remove 1 byte */ 1018*7c478bd9Sstevel@tonic-gate (void) pcp_io_op(buf, 1, PCPL_IO_OP_READ); 1019*7c478bd9Sstevel@tonic-gate } 1020*7c478bd9Sstevel@tonic-gate } else { 1021*7c478bd9Sstevel@tonic-gate return (-1); 1022*7c478bd9Sstevel@tonic-gate } 1023*7c478bd9Sstevel@tonic-gate } 1024*7c478bd9Sstevel@tonic-gate 1025*7c478bd9Sstevel@tonic-gate return (0); 1026*7c478bd9Sstevel@tonic-gate } 1027*7c478bd9Sstevel@tonic-gate 1028*7c478bd9Sstevel@tonic-gate /* 1029*7c478bd9Sstevel@tonic-gate * checks whether certain byte sequence is present in the data stream. 1030*7c478bd9Sstevel@tonic-gate */ 1031*7c478bd9Sstevel@tonic-gate static int 1032*7c478bd9Sstevel@tonic-gate check_magic_byte_presence(int byte_cnt, uint8_t *byte_seq, int *ispresent) 1033*7c478bd9Sstevel@tonic-gate { 1034*7c478bd9Sstevel@tonic-gate int ret, i; 1035*7c478bd9Sstevel@tonic-gate uint8_t buf[4]; 1036*7c478bd9Sstevel@tonic-gate 1037*7c478bd9Sstevel@tonic-gate if ((ret = pcp_peek_read(buf, byte_cnt)) < 0) { 1038*7c478bd9Sstevel@tonic-gate return (ret); 1039*7c478bd9Sstevel@tonic-gate } 1040*7c478bd9Sstevel@tonic-gate 1041*7c478bd9Sstevel@tonic-gate /* 'byte_cnt' bytes not present */ 1042*7c478bd9Sstevel@tonic-gate if (ret != byte_cnt) { 1043*7c478bd9Sstevel@tonic-gate *ispresent = 0; 1044*7c478bd9Sstevel@tonic-gate return (0); 1045*7c478bd9Sstevel@tonic-gate } 1046*7c478bd9Sstevel@tonic-gate 1047*7c478bd9Sstevel@tonic-gate for (i = 0; i < byte_cnt; ++i) { 1048*7c478bd9Sstevel@tonic-gate if (buf[i] != byte_seq[i]) { 1049*7c478bd9Sstevel@tonic-gate *ispresent = 0; 1050*7c478bd9Sstevel@tonic-gate return (0); 1051*7c478bd9Sstevel@tonic-gate } 1052*7c478bd9Sstevel@tonic-gate } 1053*7c478bd9Sstevel@tonic-gate *ispresent = 1; 1054*7c478bd9Sstevel@tonic-gate 1055*7c478bd9Sstevel@tonic-gate return (0); 1056*7c478bd9Sstevel@tonic-gate } 1057*7c478bd9Sstevel@tonic-gate 1058*7c478bd9Sstevel@tonic-gate /* 1059*7c478bd9Sstevel@tonic-gate * 16-bit simple internet checksum 1060*7c478bd9Sstevel@tonic-gate */ 1061*7c478bd9Sstevel@tonic-gate static uint16_t 1062*7c478bd9Sstevel@tonic-gate checksum(uint16_t *addr, int32_t count) 1063*7c478bd9Sstevel@tonic-gate { 1064*7c478bd9Sstevel@tonic-gate /* 1065*7c478bd9Sstevel@tonic-gate * Compute Internet Checksum for "count" bytes 1066*7c478bd9Sstevel@tonic-gate * beginning at location "addr". 1067*7c478bd9Sstevel@tonic-gate */ 1068*7c478bd9Sstevel@tonic-gate 1069*7c478bd9Sstevel@tonic-gate register uint32_t sum = 0; 1070*7c478bd9Sstevel@tonic-gate 1071*7c478bd9Sstevel@tonic-gate while (count > 1) { 1072*7c478bd9Sstevel@tonic-gate /* This is the inner loop */ 1073*7c478bd9Sstevel@tonic-gate sum += *(unsigned short *)addr++; 1074*7c478bd9Sstevel@tonic-gate count -= 2; 1075*7c478bd9Sstevel@tonic-gate } 1076*7c478bd9Sstevel@tonic-gate 1077*7c478bd9Sstevel@tonic-gate /* Add left-over byte, if any */ 1078*7c478bd9Sstevel@tonic-gate if (count > 0) 1079*7c478bd9Sstevel@tonic-gate sum += * (unsigned char *)addr; 1080*7c478bd9Sstevel@tonic-gate 1081*7c478bd9Sstevel@tonic-gate /* Fold 32-bit sum to 16 bits */ 1082*7c478bd9Sstevel@tonic-gate while (sum >> 16) 1083*7c478bd9Sstevel@tonic-gate sum = (sum & 0xffff) + (sum >> 16); 1084*7c478bd9Sstevel@tonic-gate 1085*7c478bd9Sstevel@tonic-gate sum = (~sum) & 0xffff; 1086*7c478bd9Sstevel@tonic-gate if (sum == 0) 1087*7c478bd9Sstevel@tonic-gate sum = 0xffff; 1088*7c478bd9Sstevel@tonic-gate 1089*7c478bd9Sstevel@tonic-gate return (sum); 1090*7c478bd9Sstevel@tonic-gate } 1091*7c478bd9Sstevel@tonic-gate 1092*7c478bd9Sstevel@tonic-gate /* 1093*7c478bd9Sstevel@tonic-gate * cleanup the channel if any data is hanging in 1094*7c478bd9Sstevel@tonic-gate * channel buffers. 1095*7c478bd9Sstevel@tonic-gate */ 1096*7c478bd9Sstevel@tonic-gate static int 1097*7c478bd9Sstevel@tonic-gate pcp_cleanup(void) 1098*7c478bd9Sstevel@tonic-gate { 1099*7c478bd9Sstevel@tonic-gate int ret; 1100*7c478bd9Sstevel@tonic-gate glvc_xport_msg_peek_t peek_ctrl; 1101*7c478bd9Sstevel@tonic-gate int n, done; 1102*7c478bd9Sstevel@tonic-gate uint8_t *buf = NULL; 1103*7c478bd9Sstevel@tonic-gate int retry = 0; 1104*7c478bd9Sstevel@tonic-gate 1105*7c478bd9Sstevel@tonic-gate 1106*7c478bd9Sstevel@tonic-gate buf = (uint8_t *)umem_zalloc((mtu_size), UMEM_DEFAULT); 1107*7c478bd9Sstevel@tonic-gate if (buf == NULL) { 1108*7c478bd9Sstevel@tonic-gate return (PCPL_MALLOC_FAIL); 1109*7c478bd9Sstevel@tonic-gate } 1110*7c478bd9Sstevel@tonic-gate 1111*7c478bd9Sstevel@tonic-gate peek_ctrl.buf = (caddr_t)buf; 1112*7c478bd9Sstevel@tonic-gate peek_ctrl.buflen = mtu_size; 1113*7c478bd9Sstevel@tonic-gate peek_ctrl.flags = 0; 1114*7c478bd9Sstevel@tonic-gate 1115*7c478bd9Sstevel@tonic-gate /* 1116*7c478bd9Sstevel@tonic-gate * set sig jmp location 1117*7c478bd9Sstevel@tonic-gate */ 1118*7c478bd9Sstevel@tonic-gate if (sigsetjmp(jmpbuf, 1)) { 1119*7c478bd9Sstevel@tonic-gate umem_free(buf, mtu_size); 1120*7c478bd9Sstevel@tonic-gate return (PCPL_GLVC_TIMEOUT); 1121*7c478bd9Sstevel@tonic-gate } 1122*7c478bd9Sstevel@tonic-gate 1123*7c478bd9Sstevel@tonic-gate done = 0; 1124*7c478bd9Sstevel@tonic-gate while (!done) { 1125*7c478bd9Sstevel@tonic-gate 1126*7c478bd9Sstevel@tonic-gate (void) alarm(PCP_CLEANUP_TIMEOUT); 1127*7c478bd9Sstevel@tonic-gate if ((ret = ioctl(chnl_fd, GLVC_XPORT_IOCTL_DATA_PEEK, 1128*7c478bd9Sstevel@tonic-gate &peek_ctrl)) < 0) { 1129*7c478bd9Sstevel@tonic-gate (void) alarm(0); 1130*7c478bd9Sstevel@tonic-gate done = 1; 1131*7c478bd9Sstevel@tonic-gate continue; 1132*7c478bd9Sstevel@tonic-gate } 1133*7c478bd9Sstevel@tonic-gate (void) alarm(0); 1134*7c478bd9Sstevel@tonic-gate 1135*7c478bd9Sstevel@tonic-gate n = peek_ctrl.buflen; 1136*7c478bd9Sstevel@tonic-gate 1137*7c478bd9Sstevel@tonic-gate if (n <= 0 && retry > 2) { 1138*7c478bd9Sstevel@tonic-gate done = 1; 1139*7c478bd9Sstevel@tonic-gate continue; 1140*7c478bd9Sstevel@tonic-gate } else if (n <= 0) { 1141*7c478bd9Sstevel@tonic-gate ++retry; 1142*7c478bd9Sstevel@tonic-gate continue; 1143*7c478bd9Sstevel@tonic-gate } 1144*7c478bd9Sstevel@tonic-gate 1145*7c478bd9Sstevel@tonic-gate /* remove data from channel */ 1146*7c478bd9Sstevel@tonic-gate (void) alarm(PCP_CLEANUP_TIMEOUT); 1147*7c478bd9Sstevel@tonic-gate if ((ret = read(chnl_fd, buf, n)) < 0) { 1148*7c478bd9Sstevel@tonic-gate (void) alarm(0); 1149*7c478bd9Sstevel@tonic-gate done = 1; 1150*7c478bd9Sstevel@tonic-gate continue; 1151*7c478bd9Sstevel@tonic-gate } 1152*7c478bd9Sstevel@tonic-gate (void) alarm(0); 1153*7c478bd9Sstevel@tonic-gate } 1154*7c478bd9Sstevel@tonic-gate 1155*7c478bd9Sstevel@tonic-gate umem_free(buf, mtu_size); 1156*7c478bd9Sstevel@tonic-gate return (ret); 1157*7c478bd9Sstevel@tonic-gate } 1158