xref: /titanic_44/usr/src/lib/libpcp/common/libpcp.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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