xref: /titanic_52/usr/src/uts/sun4v/ontario/io/tsalarm.c (revision 193974072f41a843678abf5f61979c748687e66b)
1b250187eSsaisai /*
2b250187eSsaisai  * CDDL HEADER START
3b250187eSsaisai  *
4b250187eSsaisai  * The contents of this file are subject to the terms of the
5b250187eSsaisai  * Common Development and Distribution License (the "License").
6b250187eSsaisai  * You may not use this file except in compliance with the License.
7b250187eSsaisai  *
8b250187eSsaisai  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9b250187eSsaisai  * or http://www.opensolaris.org/os/licensing.
10b250187eSsaisai  * See the License for the specific language governing permissions
11b250187eSsaisai  * and limitations under the License.
12b250187eSsaisai  *
13b250187eSsaisai  * When distributing Covered Code, include this CDDL HEADER in each
14b250187eSsaisai  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15b250187eSsaisai  * If applicable, add the following below this CDDL HEADER, with the
16b250187eSsaisai  * fields enclosed by brackets "[]" replaced with your own identifying
17b250187eSsaisai  * information: Portions Copyright [yyyy] [name of copyright owner]
18b250187eSsaisai  *
19b250187eSsaisai  * CDDL HEADER END
20b250187eSsaisai  */
21b250187eSsaisai /*
22*19397407SSherry Moore  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23b250187eSsaisai  * Use is subject to license terms.
24b250187eSsaisai  */
25b250187eSsaisai 
26b250187eSsaisai 
27b250187eSsaisai #include <sys/types.h>
28b250187eSsaisai #include <sys/file.h>
29b250187eSsaisai #include <sys/errno.h>
30b250187eSsaisai #include <sys/open.h>
31b250187eSsaisai #include <sys/cred.h>
32b250187eSsaisai #include <sys/cmn_err.h>
33b250187eSsaisai #include <sys/modctl.h>
34b250187eSsaisai #include <sys/conf.h>
35b250187eSsaisai #include <sys/stat.h>
36b250187eSsaisai 
37b250187eSsaisai #include <sys/callb.h>
38b250187eSsaisai #include <sys/strlog.h>
39b250187eSsaisai #include <sys/lom_io.h>
40b250187eSsaisai #include <sys/time.h>
41b250187eSsaisai #include <sys/glvc.h>
42b250187eSsaisai #include <sys/kmem.h>
43b250187eSsaisai #include <netinet/in.h>
44b250187eSsaisai #include <sys/inttypes.h>
45b250187eSsaisai 
46b250187eSsaisai #include <sys/ddi.h>
47b250187eSsaisai #include <sys/sunddi.h>
48b250187eSsaisai #include <sys/sunldi.h>
49b250187eSsaisai 
50b250187eSsaisai /* common defines */
51b250187eSsaisai #ifndef MIN
52b250187eSsaisai #define	MIN(x, y) ((x) < (y) ? (x) : (y))
53b250187eSsaisai #endif
54b250187eSsaisai #ifndef MAX
55b250187eSsaisai #define	MAX(x, y) ((x) > (y) ? (x) : (y))
56b250187eSsaisai #endif
57b250187eSsaisai #ifndef	ABS
58b250187eSsaisai #define	ABS(x)	((x) < (0) ? (-(x)) : (x))
59b250187eSsaisai #endif
60b250187eSsaisai 
61b250187eSsaisai #define	LOMIOCALCTL_OLD		_IOW('a', 4, ts_aldata_t)
62b250187eSsaisai #define	LOMIOCALSTATE_OLD	_IOWR('a', 5, ts_aldata_t)
63b250187eSsaisai 
64b250187eSsaisai #define	PCP_CKSUM_ENABLE
65b250187eSsaisai #define	PCP_DEF_MTU_SZ	100
66b250187eSsaisai 
67b250187eSsaisai #define	PCP_MAX_TRY_CNT		5
68b250187eSsaisai #define	PCP_GLVC_SLEEP		5
69b250187eSsaisai #define	PCP_COMM_TIMEOUT	0x10
70b250187eSsaisai 
71b250187eSsaisai #define	PCP_IO_OP_READ		(1)
72b250187eSsaisai #define	PCP_IO_OP_WRITE		(2)
73b250187eSsaisai #define	PCP_IO_OP_PEEK		(3)
74b250187eSsaisai 
75b250187eSsaisai 
76b250187eSsaisai /* Error codes for 'status' field in response message header */
77b250187eSsaisai #define	TSAL_PCP_ERROR		(-1)
78b250187eSsaisai #define	TSAL_PCP_OK		(0)	/* message received okay */
79b250187eSsaisai 
80b250187eSsaisai /*
81b250187eSsaisai  * magic number for Platform Channel Protocol (PCP)
82b250187eSsaisai  * ~(rot13("PCP_") = 0xAFBCAFA0
83b250187eSsaisai  * rot13 is a simple Caesar-cypher encryption that replaces each English letter
84b250187eSsaisai  * with the one 13 places forward or back along the alphabet.
85b250187eSsaisai  */
86b250187eSsaisai #define	 PCP_MAGIC_NUM		(0xAFBCAFA0)
87b250187eSsaisai 
88b250187eSsaisai /* Platform channel protocol versions. */
89b250187eSsaisai #define	PCP_PROT_VER_1		1
90b250187eSsaisai 
91b250187eSsaisai /* defines for 'timeout' */
92b250187eSsaisai #define	PCP_TO_NO_RESPONSE	(0xFFFFFFFF)	/* no response required */
93b250187eSsaisai #define	PCP_TO_WAIT_FOREVER	(0)	/* wait forever..(in reality, */
94b250187eSsaisai 					/* it waits until glvc driver */
95b250187eSsaisai 					/* call returns; curently glvc */
96b250187eSsaisai 					/* calls are blocking calls. */
97b250187eSsaisai 
98b250187eSsaisai /* Message Types */
99b250187eSsaisai #define	PCP_ALARM_CONTROL	15
100b250187eSsaisai #define	PCP_ALARM_CONTROL_R	16
101b250187eSsaisai 
102b250187eSsaisai /* alarm_action */
103b250187eSsaisai #define	PCP_ALARM_ENABLE	1
104b250187eSsaisai #define	PCP_ALARM_DISABLE	2
105b250187eSsaisai #define	PCP_ALARM_STATUS	3
106b250187eSsaisai 
107b250187eSsaisai /* alarm_id */
108b250187eSsaisai #define	PCP_ALARM_CRITICAL	0
109b250187eSsaisai #define	PCP_ALARM_MAJOR		1
110b250187eSsaisai #define	PCP_ALARM_MINOR		2
111b250187eSsaisai #define	PCP_ALARM_USER		3
112b250187eSsaisai 
113b250187eSsaisai /* alarm_state */
114b250187eSsaisai #define	ALARM_STATE_ON		1
115b250187eSsaisai #define	ALARM_STATE_OFF		2
116b250187eSsaisai #define	ALARM_STATE_UNKNOWN	3
117b250187eSsaisai 
118b250187eSsaisai /* Status Types */
119b250187eSsaisai #define	PCP_ALARM_OK		(1)
120b250187eSsaisai #define	PCP_ALARM_ERROR		(2)
121b250187eSsaisai 
122b250187eSsaisai /* tsalarm service channel */
123b250187eSsaisai #define	ALARM_CHANNEL	"/devices/virtual-devices@100/telco-alarm@f:glvc"
124b250187eSsaisai 
125b250187eSsaisai /* Driver state  flags */
126b250187eSsaisai #define	TSAL_OPENED		0x1
127b250187eSsaisai #define	TSAL_IDENTED		0x2
128b250187eSsaisai 
129b250187eSsaisai /*
130b250187eSsaisai  * Platform Channel Request Message Header.
131b250187eSsaisai  */
132b250187eSsaisai typedef	struct tsal_pcp_req_msg_hdr {
133b250187eSsaisai 	uint32_t	magic_num;	/* magic number */
134b250187eSsaisai 	uint8_t		proto_ver;	/* version info for */
135b250187eSsaisai 					/* backward compatibility */
136b250187eSsaisai 	uint8_t		msg_type;	/* provided by user apps */
137b250187eSsaisai 	uint8_t		sub_type;	/* provided by user apps */
138b250187eSsaisai 	uint8_t		rsvd_pad;	/* padding bits */
139b250187eSsaisai 	uint32_t	xid;		/* transaction id */
140b250187eSsaisai 	uint32_t	timeout;	/* timeout in seconds */
141b250187eSsaisai 	uint32_t	msg_len;	/* length of request or response data */
142b250187eSsaisai 	uint16_t	msg_cksum;	/* 16-bit checksum of req msg data */
143b250187eSsaisai 	uint16_t	hdr_cksum;	/* 16-bit checksum of req hdr */
144b250187eSsaisai } tsal_pcp_req_msg_hdr_t;
145b250187eSsaisai 
146b250187eSsaisai /*
147b250187eSsaisai  * Platform Channel Response Message Header.
148b250187eSsaisai  */
149b250187eSsaisai typedef struct tsal_pcp_resp_msg_hdr {
150b250187eSsaisai 	uint32_t	magic_num;	/* magic number */
151b250187eSsaisai 	uint8_t		proto_ver;	/* version info for */
152b250187eSsaisai 					/* backward compatibility */
153b250187eSsaisai 	uint8_t		msg_type;	/* passed to user apps */
154b250187eSsaisai 	uint8_t		sub_type;	/* passed to user apps */
155b250187eSsaisai 	uint8_t		rsvd_pad;	/* for padding */
156b250187eSsaisai 	uint32_t	xid;		/* transaction id */
157b250187eSsaisai 	uint32_t	timeout;	/* timeout in seconds */
158b250187eSsaisai 	uint32_t	msg_len;	/* length of request or response data */
159b250187eSsaisai 	uint32_t	status;		/* response status */
160b250187eSsaisai 	uint16_t	msg_cksum;	/* 16-bit checksum of resp msg data */
161b250187eSsaisai 	uint16_t	hdr_cksum;	/* 16-bit checksum of resp hdr */
162b250187eSsaisai } tsal_pcp_resp_msg_hdr_t;
163b250187eSsaisai 
164b250187eSsaisai /*
165b250187eSsaisai  * PCP user apps message format
166b250187eSsaisai  */
167b250187eSsaisai typedef struct tsal_pcp_msg {
168b250187eSsaisai 	uint8_t		msg_type;
169b250187eSsaisai 	uint8_t		sub_type;
170b250187eSsaisai 	uint16_t	rsvd_pad;
171b250187eSsaisai 	uint32_t	msg_len;
172b250187eSsaisai 	void		*msg_data;
173b250187eSsaisai } tsal_pcp_msg_t;
174b250187eSsaisai 
175b250187eSsaisai /*
176b250187eSsaisai  * alarm set/get request message
177b250187eSsaisai  */
178b250187eSsaisai typedef struct tsal_pcp_alarm_req {
179b250187eSsaisai 	uint32_t	alarm_id;
180b250187eSsaisai 	uint32_t	alarm_action;
181b250187eSsaisai } tsal_pcp_alarm_req_t;
182b250187eSsaisai 
183b250187eSsaisai /*
184b250187eSsaisai  * alarm set/get response message
185b250187eSsaisai  */
186b250187eSsaisai typedef struct tsal_pcp_alarm_resp {
187b250187eSsaisai 	uint32_t	status;
188b250187eSsaisai 	uint32_t	alarm_id;
189b250187eSsaisai 	uint32_t	alarm_state;
190b250187eSsaisai } tsal_pcp_alarm_resp_t;
191b250187eSsaisai 
192b250187eSsaisai /*
193b250187eSsaisai  * tsalarm driver soft structure
194b250187eSsaisai  */
195b250187eSsaisai typedef struct tsalarm_softc {
196b250187eSsaisai 	ldi_handle_t	lh;
197b250187eSsaisai 	ldi_ident_t	li;
198b250187eSsaisai 	dev_info_t	*dip;
199b250187eSsaisai 	minor_t		minor;
200b250187eSsaisai 	int		flags;
201b250187eSsaisai 	kmutex_t	mutex;
202b250187eSsaisai 	uint32_t	msg_xid;
203b250187eSsaisai 	uint32_t	mtu_size;
204b250187eSsaisai 	uint8_t		*read_head;
205b250187eSsaisai 	uint8_t		*read_tail;
206b250187eSsaisai 	uint8_t		*read_area;
207b250187eSsaisai 	uint8_t		*peek_area;
208b250187eSsaisai 	uint8_t		*peek_read_area;
209b250187eSsaisai 	tsal_pcp_alarm_req_t	*req_ptr;
210b250187eSsaisai 	tsal_pcp_alarm_resp_t	*resp_ptr;
211b250187eSsaisai 	tsal_pcp_req_msg_hdr_t	*req_msg_hdr;
212b250187eSsaisai 	tsal_pcp_resp_msg_hdr_t	*resp_msg_hdr;
213b250187eSsaisai }tsalarm_softc_t;
214b250187eSsaisai 
215b250187eSsaisai /*
216b250187eSsaisai  * Forward declarations.
217b250187eSsaisai  */
218b250187eSsaisai static int tsal_pcp_send_req_msg_hdr(tsalarm_softc_t *sc,
219b250187eSsaisai 					tsal_pcp_req_msg_hdr_t *req_hdr);
220b250187eSsaisai static int tsal_pcp_recv_resp_msg_hdr(tsalarm_softc_t *sc,
221b250187eSsaisai 					tsal_pcp_resp_msg_hdr_t *resp_hdr);
222b250187eSsaisai static int tsal_pcp_io_op(tsalarm_softc_t *sc, void *buf,
223b250187eSsaisai 					int byte_cnt, int io_op);
224b250187eSsaisai static int tsal_pcp_read(tsalarm_softc_t *sc, uint8_t *buf, int buf_len);
225b250187eSsaisai static int tsal_pcp_write(tsalarm_softc_t *sc, uint8_t *buf, int buf_len);
226b250187eSsaisai static int tsal_pcp_peek(tsalarm_softc_t *sc, uint8_t *buf, int buf_len);
227b250187eSsaisai static int tsal_pcp_peek_read(tsalarm_softc_t *sc, uint8_t *buf, int buf_len);
228b250187eSsaisai static int tsal_pcp_frame_error_handle(tsalarm_softc_t *sc);
229b250187eSsaisai static int check_magic_byte_presence(tsalarm_softc_t *sc, int byte_cnt,
230b250187eSsaisai 					uint8_t *byte_val, int *ispresent);
231b250187eSsaisai static int tsal_pcp_send_recv(tsalarm_softc_t *sc, tsal_pcp_msg_t *req_msg,
232b250187eSsaisai 			tsal_pcp_msg_t *resp_msg, uint32_t timeout);
233b250187eSsaisai static uint32_t tsal_pcp_get_xid(tsalarm_softc_t *sc);
234b250187eSsaisai static uint16_t checksum(uint16_t *addr, int32_t count);
235b250187eSsaisai static int glvc_alarm_get(int alarm_type, int *alarm_state,
236b250187eSsaisai 					tsalarm_softc_t *sc);
237b250187eSsaisai static int glvc_alarm_set(int alarm_type, int new_state,
238b250187eSsaisai 					tsalarm_softc_t *sc);
239b250187eSsaisai 
240b250187eSsaisai #define	getsoftc(minor)	\
241b250187eSsaisai 		((struct tsalarm_softc *)ddi_get_soft_state(statep, (minor)))
242b250187eSsaisai 
243b250187eSsaisai /*
244b250187eSsaisai  * Driver entry points
245b250187eSsaisai  */
246b250187eSsaisai 
247b250187eSsaisai /* dev_ops and cb_ops entry point function declarations */
248b250187eSsaisai 
249b250187eSsaisai static int	tsalarm_attach(dev_info_t *, ddi_attach_cmd_t);
250b250187eSsaisai static int	tsalarm_detach(dev_info_t *, ddi_detach_cmd_t);
251b250187eSsaisai static int	tsalarm_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
252b250187eSsaisai 
253b250187eSsaisai static int	tsalarm_open(dev_t *, int, int, cred_t *);
254b250187eSsaisai static int	tsalarm_close(dev_t, int, int, cred_t *);
255b250187eSsaisai static int	tsalarm_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
256b250187eSsaisai 
257b250187eSsaisai static struct cb_ops tsalarm_cb_ops = {
258b250187eSsaisai 	tsalarm_open,	/* open */
259b250187eSsaisai 	tsalarm_close,	/* close */
260b250187eSsaisai 	nodev,		/* strategy() */
261b250187eSsaisai 	nodev,		/* print() */
262b250187eSsaisai 	nodev,		/* dump() */
263b250187eSsaisai 	nodev,		/* read() */
264b250187eSsaisai 	nodev,		/* write() */
265b250187eSsaisai 	tsalarm_ioctl,	/* ioctl() */
266b250187eSsaisai 	nodev,		/* devmap() */
267b250187eSsaisai 	nodev,		/* mmap() */
268b250187eSsaisai 	ddi_segmap,	/* segmap() */
269b250187eSsaisai 	nochpoll,	/* poll() */
270b250187eSsaisai 	ddi_prop_op,    /* prop_op() */
271b250187eSsaisai 	NULL,		/* cb_str */
272b250187eSsaisai 	D_NEW | D_MP	/* cb_flag */
273b250187eSsaisai };
274b250187eSsaisai 
275b250187eSsaisai 
276b250187eSsaisai static struct dev_ops tsalarm_ops = {
277b250187eSsaisai 	DEVO_REV,
278b250187eSsaisai 	0,			/* ref count */
279b250187eSsaisai 	tsalarm_getinfo,	/* getinfo() */
280b250187eSsaisai 	nulldev,		/* identify() */
281b250187eSsaisai 	nulldev,		/* probe() */
282b250187eSsaisai 	tsalarm_attach,		/* attach() */
283b250187eSsaisai 	tsalarm_detach,		/* detach */
284b250187eSsaisai 	nodev,			/* reset */
285b250187eSsaisai 	&tsalarm_cb_ops,	/* pointer to cb_ops structure */
286b250187eSsaisai 	(struct bus_ops *)NULL,
287*19397407SSherry Moore 	nulldev,		/* power() */
288*19397407SSherry Moore 	ddi_quiesce_not_needed,		/* quiesce() */
289b250187eSsaisai };
290b250187eSsaisai 
291b250187eSsaisai /*
292b250187eSsaisai  * Loadable module support.
293b250187eSsaisai  */
294b250187eSsaisai extern struct mod_ops mod_driverops;
295b250187eSsaisai static void    *statep;
296b250187eSsaisai 
297b250187eSsaisai static struct modldrv modldrv = {
298b250187eSsaisai 	&mod_driverops,			/* Type of module. This is a driver */
299*19397407SSherry Moore 	"tsalarm control driver",	/* Name of the module */
300b250187eSsaisai 	&tsalarm_ops			/* pointer to the dev_ops structure */
301b250187eSsaisai };
302b250187eSsaisai 
303b250187eSsaisai static struct modlinkage modlinkage = {
304b250187eSsaisai 	MODREV_1,
305b250187eSsaisai 	&modldrv,
306b250187eSsaisai 	NULL
307b250187eSsaisai };
308b250187eSsaisai 
309b250187eSsaisai int
310b250187eSsaisai _init(void)
311b250187eSsaisai {
312b250187eSsaisai 	int    e;
313b250187eSsaisai 
314b250187eSsaisai 	if (e = ddi_soft_state_init(&statep,
315b250187eSsaisai 				sizeof (struct tsalarm_softc), 1)) {
316b250187eSsaisai 		return (e);
317b250187eSsaisai 	}
318b250187eSsaisai 
319b250187eSsaisai 	if ((e = mod_install(&modlinkage)) != 0) {
320b250187eSsaisai 		ddi_soft_state_fini(&statep);
321b250187eSsaisai 	}
322b250187eSsaisai 
323b250187eSsaisai 	return (e);
324b250187eSsaisai }
325b250187eSsaisai 
326b250187eSsaisai int
327b250187eSsaisai _fini(void)
328b250187eSsaisai {
329b250187eSsaisai 	int e;
330b250187eSsaisai 
331b250187eSsaisai 	if ((e = mod_remove(&modlinkage)) != 0) {
332b250187eSsaisai 		return (e);
333b250187eSsaisai 	}
334b250187eSsaisai 
335b250187eSsaisai 	ddi_soft_state_fini(&statep);
336b250187eSsaisai 
337b250187eSsaisai 	return (DDI_SUCCESS);
338b250187eSsaisai }
339b250187eSsaisai 
340b250187eSsaisai int
341b250187eSsaisai _info(struct modinfo *modinfop)
342b250187eSsaisai {
343b250187eSsaisai 	return (mod_info(&modlinkage, modinfop));
344b250187eSsaisai }
345b250187eSsaisai 
346b250187eSsaisai 
347b250187eSsaisai /* ARGSUSED */
348b250187eSsaisai static int
349b250187eSsaisai tsalarm_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
350b250187eSsaisai {
351b250187eSsaisai 	int	inst = getminor((dev_t)arg);
352b250187eSsaisai 	int	retval = DDI_SUCCESS;
353b250187eSsaisai 	struct tsalarm_softc *softc;
354b250187eSsaisai 
355b250187eSsaisai 	switch (cmd) {
356b250187eSsaisai 
357b250187eSsaisai 	case DDI_INFO_DEVT2DEVINFO:
358b250187eSsaisai 		if ((softc = getsoftc(inst)) == NULL) {
359b250187eSsaisai 			*result = (void *)NULL;
360b250187eSsaisai 			retval = DDI_FAILURE;
361b250187eSsaisai 		} else {
362b250187eSsaisai 			*result = (void *)softc->dip;
363b250187eSsaisai 		}
364b250187eSsaisai 		break;
365b250187eSsaisai 
366b250187eSsaisai 	case DDI_INFO_DEVT2INSTANCE:
367b250187eSsaisai 		*result = (void *)(uintptr_t)inst;
368b250187eSsaisai 		break;
369b250187eSsaisai 
370b250187eSsaisai 	default:
371b250187eSsaisai 		retval = DDI_FAILURE;
372b250187eSsaisai 	}
373b250187eSsaisai 
374b250187eSsaisai 	return (retval);
375b250187eSsaisai }
376b250187eSsaisai 
377b250187eSsaisai static int
378b250187eSsaisai tsalarm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
379b250187eSsaisai {
380b250187eSsaisai 
381b250187eSsaisai 	int inst;
382b250187eSsaisai 	struct tsalarm_softc *softc = NULL;
383b250187eSsaisai 
384b250187eSsaisai 	switch (cmd) {
385b250187eSsaisai 
386b250187eSsaisai 	case DDI_ATTACH:
387b250187eSsaisai 		inst = ddi_get_instance(dip);
388b250187eSsaisai 		/*
389b250187eSsaisai 		 * Allocate a soft state structure for this instance.
390b250187eSsaisai 		 */
391b250187eSsaisai 		if (ddi_soft_state_zalloc(statep, inst) != DDI_SUCCESS) {
392b250187eSsaisai 			cmn_err(CE_WARN, "Failed to allocate memory");
393b250187eSsaisai 			goto attach_failed;
394b250187eSsaisai 		}
395b250187eSsaisai 
396b250187eSsaisai 		softc = getsoftc(inst);
397b250187eSsaisai 		softc->dip = dip;
398b250187eSsaisai 		softc->mtu_size = PCP_DEF_MTU_SZ;
399b250187eSsaisai 		softc->msg_xid = 0;
400b250187eSsaisai 		softc->read_area = NULL;
401b250187eSsaisai 		softc->read_head = NULL;
402b250187eSsaisai 		softc->read_tail = NULL;
403b250187eSsaisai 		softc->req_ptr = NULL;
404b250187eSsaisai 		softc->resp_ptr = NULL;
405b250187eSsaisai 
406b250187eSsaisai 		mutex_init(&softc->mutex, NULL, MUTEX_DRIVER, NULL);
407b250187eSsaisai 		/*
408b250187eSsaisai 		 * Create minor node.  The minor device number, inst, has no
409b250187eSsaisai 		 * meaning.  The model number above, which will be added to
410b250187eSsaisai 		 * the device's softc, is used to direct peculiar behavior.
411b250187eSsaisai 		 */
412b250187eSsaisai 		if (ddi_create_minor_node(dip, "lom", S_IFCHR, 0,
413b250187eSsaisai 		    DDI_PSEUDO, NULL) == DDI_FAILURE) {
414b250187eSsaisai 			goto attach_failed;
415b250187eSsaisai 		}
416b250187eSsaisai 
417b250187eSsaisai 		ddi_report_dev(dip);
418b250187eSsaisai 		return (DDI_SUCCESS);
419b250187eSsaisai 
420b250187eSsaisai 	case DDI_RESUME:
421b250187eSsaisai 		return (DDI_SUCCESS);
422b250187eSsaisai 
423b250187eSsaisai 	default:
424b250187eSsaisai 		return (DDI_FAILURE);
425b250187eSsaisai 	}
426b250187eSsaisai 
427b250187eSsaisai attach_failed:
428b250187eSsaisai 	/* Free soft state, if allocated. remove minor node if added earlier */
429b250187eSsaisai 	if (softc) {
430b250187eSsaisai 		mutex_destroy(&softc->mutex);
431b250187eSsaisai 		ddi_soft_state_free(statep, inst);
432b250187eSsaisai 	}
433b250187eSsaisai 
434b250187eSsaisai 	ddi_remove_minor_node(dip, NULL);
435b250187eSsaisai 
436b250187eSsaisai 	return (DDI_FAILURE);
437b250187eSsaisai }
438b250187eSsaisai 
439b250187eSsaisai static int
440b250187eSsaisai tsalarm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
441b250187eSsaisai {
442b250187eSsaisai 	int inst;
443b250187eSsaisai 	struct tsalarm_softc *softc;
444b250187eSsaisai 
445b250187eSsaisai 	switch (cmd) {
446b250187eSsaisai 
447b250187eSsaisai 	case DDI_DETACH:
448b250187eSsaisai 		inst = ddi_get_instance(dip);
449b250187eSsaisai 		if ((softc = getsoftc(inst)) == NULL)
450b250187eSsaisai 			return (DDI_FAILURE);
451b250187eSsaisai 		/*
452b250187eSsaisai 		 * Free the soft state and remove minor node added earlier.
453b250187eSsaisai 		 */
454b250187eSsaisai 		ddi_remove_minor_node(dip, NULL);
455b250187eSsaisai 		mutex_destroy(&softc->mutex);
456b250187eSsaisai 		ddi_soft_state_free(statep, inst);
457b250187eSsaisai 		return (DDI_SUCCESS);
458b250187eSsaisai 
459b250187eSsaisai 	case DDI_SUSPEND:
460b250187eSsaisai 		return (DDI_SUCCESS);
461b250187eSsaisai 
462b250187eSsaisai 	default:
463b250187eSsaisai 		return (DDI_FAILURE);
464b250187eSsaisai 
465b250187eSsaisai 	}
466b250187eSsaisai }
467b250187eSsaisai 
468b250187eSsaisai /* ARGSUSED */
469b250187eSsaisai static int
470b250187eSsaisai tsalarm_open(dev_t *devp, int flag, int otyp, cred_t *credp)
471b250187eSsaisai {
472b250187eSsaisai 	int	rv, inst = getminor(*devp);
473b250187eSsaisai 	struct tsalarm_softc *softc;
474b250187eSsaisai 	glvc_xport_opt_op_t	channel_op;
475b250187eSsaisai 	int rval;
476b250187eSsaisai 
477b250187eSsaisai 	softc = (struct tsalarm_softc *)getsoftc(inst);
478b250187eSsaisai 	if (softc == NULL) {
479b250187eSsaisai 		cmn_err(CE_WARN, "getsoftc failed\n");
480b250187eSsaisai 		return (EIO);
481b250187eSsaisai 	}
482b250187eSsaisai 
483b250187eSsaisai 	mutex_enter(&softc->mutex);
484b250187eSsaisai 
485b250187eSsaisai 	rv = ldi_ident_from_dev(*devp, &softc->li);
486b250187eSsaisai 	if (rv != 0) {
487b250187eSsaisai 		cmn_err(CE_WARN, "ldi_ident_from_dev failed\n");
488b250187eSsaisai 		goto FAIL;
489b250187eSsaisai 	}
490b250187eSsaisai 	softc->flags |= TSAL_IDENTED;
491b250187eSsaisai 
492b250187eSsaisai 	rv = ldi_open_by_name(ALARM_CHANNEL, FREAD | FWRITE, kcred, &softc->lh,
493b250187eSsaisai 	    softc->li);
494b250187eSsaisai 	if (rv != 0) {
495b250187eSsaisai 		cmn_err(CE_WARN, "ldi_open_by_name failed\n");
496b250187eSsaisai 		goto FAIL;
497b250187eSsaisai 	}
498b250187eSsaisai 	softc->flags |= TSAL_OPENED;
499b250187eSsaisai 
500b250187eSsaisai 	/* Get the MTU of the target channel */
501b250187eSsaisai 	channel_op.op_sel = GLVC_XPORT_OPT_GET;
502b250187eSsaisai 	channel_op.opt_sel = GLVC_XPORT_OPT_MTU_SZ;
503b250187eSsaisai 	channel_op.opt_val = 0;
504b250187eSsaisai 
505b250187eSsaisai 	if ((rv = ldi_ioctl(softc->lh, GLVC_XPORT_IOCTL_OPT_OP,
506b250187eSsaisai 	    (intptr_t)&channel_op, FKIOCTL, kcred, &rval)) < 0) {
507b250187eSsaisai 		cmn_err(CE_WARN, "ldi_ioctl failed\n");
508b250187eSsaisai 		goto FAIL;
509b250187eSsaisai 	}
510b250187eSsaisai 	softc->mtu_size = channel_op.opt_val;
511b250187eSsaisai 
512b250187eSsaisai 	if ((softc->req_ptr = (tsal_pcp_alarm_req_t *)kmem_zalloc(
513b250187eSsaisai 	    sizeof (tsal_pcp_alarm_req_t),
514b250187eSsaisai 	    KM_NOSLEEP)) == NULL) {
515b250187eSsaisai 		goto FAIL;
516b250187eSsaisai 	}
517b250187eSsaisai 	if ((softc->resp_ptr = (tsal_pcp_alarm_resp_t *)kmem_zalloc(
518b250187eSsaisai 	    sizeof (tsal_pcp_alarm_resp_t),
519b250187eSsaisai 	    KM_NOSLEEP)) == NULL) {
520b250187eSsaisai 		goto FAIL;
521b250187eSsaisai 	}
522b250187eSsaisai 	if ((softc->req_msg_hdr = (tsal_pcp_req_msg_hdr_t *)kmem_zalloc(
523b250187eSsaisai 	    sizeof (tsal_pcp_req_msg_hdr_t),
524b250187eSsaisai 	    KM_NOSLEEP)) == NULL) {
525b250187eSsaisai 		goto FAIL;
526b250187eSsaisai 	}
527b250187eSsaisai 	if ((softc->resp_msg_hdr = (tsal_pcp_resp_msg_hdr_t *)kmem_zalloc(
528b250187eSsaisai 	    sizeof (tsal_pcp_resp_msg_hdr_t),
529b250187eSsaisai 	    KM_NOSLEEP)) == NULL) {
530b250187eSsaisai 		goto FAIL;
531b250187eSsaisai 	}
532b250187eSsaisai 	if ((softc->peek_area = (uint8_t *)kmem_zalloc(softc->mtu_size,
533b250187eSsaisai 	    KM_NOSLEEP)) == NULL) {
534b250187eSsaisai 		goto FAIL;
535b250187eSsaisai 	}
536b250187eSsaisai 	if ((softc->peek_read_area = (uint8_t *)kmem_zalloc(2*softc->mtu_size,
537b250187eSsaisai 	    KM_NOSLEEP)) == NULL) {
538b250187eSsaisai 		goto FAIL;
539b250187eSsaisai 	}
540b250187eSsaisai 
541b250187eSsaisai 	rv = 0;
542b250187eSsaisai 
543b250187eSsaisai FAIL:
544b250187eSsaisai 	if (rv != 0) {
545b250187eSsaisai 		if (softc->flags & TSAL_OPENED)
546b250187eSsaisai 			(void) ldi_close(softc->lh, FREAD|FWRITE, credp);
547b250187eSsaisai 		if (softc->flags * TSAL_IDENTED)
548b250187eSsaisai 			(void) ldi_ident_release(softc->li);
549b250187eSsaisai 		softc->flags &= ~(TSAL_OPENED | TSAL_IDENTED);
550b250187eSsaisai 		if (softc->req_ptr != NULL)
551b250187eSsaisai 			kmem_free(softc->req_ptr,
552b250187eSsaisai 			    sizeof (tsal_pcp_alarm_req_t));
553b250187eSsaisai 		if (softc->resp_ptr != NULL)
554b250187eSsaisai 			kmem_free(softc->resp_ptr,
555b250187eSsaisai 			    sizeof (tsal_pcp_alarm_resp_t));
556b250187eSsaisai 		if (softc->req_msg_hdr != NULL)
557b250187eSsaisai 			kmem_free(softc->req_msg_hdr,
558b250187eSsaisai 			    sizeof (tsal_pcp_req_msg_hdr_t));
559b250187eSsaisai 		if (softc->resp_msg_hdr != NULL)
560b250187eSsaisai 			kmem_free(softc->resp_msg_hdr,
561b250187eSsaisai 			    sizeof (tsal_pcp_resp_msg_hdr_t));
562b250187eSsaisai 		if (softc->peek_area != NULL)
563b250187eSsaisai 			kmem_free(softc->peek_area, softc->mtu_size);
564b250187eSsaisai 		if (softc->peek_read_area != NULL)
565b250187eSsaisai 			kmem_free(softc->peek_read_area, 2*softc->mtu_size);
566b250187eSsaisai 	}
567b250187eSsaisai 	mutex_exit(&softc->mutex);
568b250187eSsaisai 
569b250187eSsaisai 	return (rv);
570b250187eSsaisai }
571b250187eSsaisai 
572b250187eSsaisai 
573b250187eSsaisai /* ARGSUSED */
574b250187eSsaisai static int
575b250187eSsaisai tsalarm_close(dev_t dev, int flag, int otyp, cred_t *credp)
576b250187eSsaisai {
577b250187eSsaisai 	int rv,	inst = getminor(dev);
578b250187eSsaisai 	struct tsalarm_softc *softc;
579b250187eSsaisai 
580b250187eSsaisai 	softc = (struct tsalarm_softc *)getsoftc(inst);
581b250187eSsaisai 
582b250187eSsaisai 	if (softc == NULL) {
583b250187eSsaisai 		return (EIO);
584b250187eSsaisai 	}
585b250187eSsaisai 
586b250187eSsaisai 	mutex_enter(&softc->mutex);
587b250187eSsaisai 
588b250187eSsaisai 	rv = ldi_close(softc->lh, FREAD | FWRITE, kcred);
589b250187eSsaisai 	if (rv != 0) {
590b250187eSsaisai 		cmn_err(CE_WARN, "ldi_close failed \n");
591b250187eSsaisai 	}
592b250187eSsaisai 
593b250187eSsaisai 	ldi_ident_release(softc->li);
594b250187eSsaisai 	softc->flags &= ~(TSAL_OPENED | TSAL_IDENTED);
595b250187eSsaisai 
596b250187eSsaisai 	mutex_exit(&softc->mutex);
597b250187eSsaisai 
598b250187eSsaisai 	/*
599b250187eSsaisai 	 * free global buffers
600b250187eSsaisai 	 */
601b250187eSsaisai 	if (softc->read_area != NULL) {
602b250187eSsaisai 		kmem_free(softc->read_area, 2*softc->mtu_size);
603b250187eSsaisai 		softc->read_area = NULL;
604b250187eSsaisai 	}
605b250187eSsaisai 	if (softc->req_ptr != NULL) {
606b250187eSsaisai 		kmem_free(softc->req_ptr,
607b250187eSsaisai 		    sizeof (tsal_pcp_alarm_req_t));
608b250187eSsaisai 		softc->req_ptr = NULL;
609b250187eSsaisai 	}
610b250187eSsaisai 	if (softc->resp_ptr != NULL) {
611b250187eSsaisai 		kmem_free(softc->resp_ptr,
612b250187eSsaisai 		    sizeof (tsal_pcp_alarm_resp_t));
613b250187eSsaisai 		softc->resp_ptr = NULL;
614b250187eSsaisai 	}
615b250187eSsaisai 	if (softc->req_msg_hdr != NULL) {
616b250187eSsaisai 		kmem_free(softc->req_msg_hdr,
617b250187eSsaisai 		    sizeof (tsal_pcp_req_msg_hdr_t));
618b250187eSsaisai 		softc->req_msg_hdr = NULL;
619b250187eSsaisai 	}
620b250187eSsaisai 	if (softc->resp_msg_hdr != NULL) {
621b250187eSsaisai 		kmem_free(softc->resp_msg_hdr,
622b250187eSsaisai 		    sizeof (tsal_pcp_resp_msg_hdr_t));
623b250187eSsaisai 		softc->resp_msg_hdr = NULL;
624b250187eSsaisai 	}
625b250187eSsaisai 	if (softc->peek_area != NULL) {
626b250187eSsaisai 		kmem_free(softc->peek_area, softc->mtu_size);
627b250187eSsaisai 		softc->peek_area = NULL;
628b250187eSsaisai 	}
629b250187eSsaisai 	if (softc->peek_read_area != NULL) {
630b250187eSsaisai 		kmem_free(softc->peek_read_area, 2*softc->mtu_size);
631b250187eSsaisai 		softc->peek_read_area = NULL;
632b250187eSsaisai 	}
633b250187eSsaisai 
634b250187eSsaisai 	return (rv);
635b250187eSsaisai }
636b250187eSsaisai 
637b250187eSsaisai 
638b250187eSsaisai /* ARGSUSED */
639b250187eSsaisai static int
640b250187eSsaisai tsalarm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
641b250187eSsaisai 		cred_t *credp, int *rvalp)
642b250187eSsaisai {
643b250187eSsaisai 	int		inst = getminor(dev);
644b250187eSsaisai 	struct tsalarm_softc *softc;
645b250187eSsaisai 	int retval = 0;
646b250187eSsaisai 	ts_aldata_t ts_alinfo;
647b250187eSsaisai 	int alarm_type, alarm_state = 0;
648b250187eSsaisai 
649b250187eSsaisai 	if ((softc = getsoftc(inst)) == NULL)
650b250187eSsaisai 		return (ENXIO);
651b250187eSsaisai 
652b250187eSsaisai 	mutex_enter(&softc->mutex);
653b250187eSsaisai 
654b250187eSsaisai 	switch (cmd) {
655b250187eSsaisai 
656b250187eSsaisai 	case LOMIOCALSTATE:
657b250187eSsaisai 	case LOMIOCALSTATE_OLD:
658b250187eSsaisai 		{
659b250187eSsaisai 			if (ddi_copyin((caddr_t)arg, (caddr_t)&ts_alinfo,
660b250187eSsaisai 			    sizeof (ts_aldata_t), mode) != 0) {
661b250187eSsaisai 				retval = EFAULT;
662b250187eSsaisai 				goto end;
663b250187eSsaisai 			}
664b250187eSsaisai 
665b250187eSsaisai 			alarm_type = ts_alinfo.alarm_no;
666b250187eSsaisai 			if ((alarm_type < ALARM_CRITICAL) ||
667b250187eSsaisai 			    (alarm_type > ALARM_USER)) {
668b250187eSsaisai 				retval = EINVAL;
669b250187eSsaisai 				goto end;
670b250187eSsaisai 			}
671b250187eSsaisai 
672b250187eSsaisai 			retval = glvc_alarm_get(alarm_type, &alarm_state,
673b250187eSsaisai 			    softc);
674b250187eSsaisai 
675b250187eSsaisai 			if (retval != 0)
676b250187eSsaisai 				goto end;
677b250187eSsaisai 
678b250187eSsaisai 			if ((alarm_state != 0) && (alarm_state != 1)) {
679b250187eSsaisai 				retval = EIO;
680b250187eSsaisai 				goto end;
681b250187eSsaisai 			}
682b250187eSsaisai 
683b250187eSsaisai 			ts_alinfo.alarm_state = alarm_state;
684b250187eSsaisai 			if (ddi_copyout((caddr_t)&ts_alinfo, (caddr_t)arg,
685b250187eSsaisai 			    sizeof (ts_aldata_t), mode) != 0) {
686b250187eSsaisai 				retval = EFAULT;
687b250187eSsaisai 				goto end;
688b250187eSsaisai 			}
689b250187eSsaisai 		}
690b250187eSsaisai 		break;
691b250187eSsaisai 
692b250187eSsaisai 	case LOMIOCALCTL:
693b250187eSsaisai 	case LOMIOCALCTL_OLD:
694b250187eSsaisai 		{
695b250187eSsaisai 			if (ddi_copyin((caddr_t)arg, (caddr_t)&ts_alinfo,
696b250187eSsaisai 			    sizeof (ts_aldata_t), mode) != 0) {
697b250187eSsaisai 				retval = EFAULT;
698b250187eSsaisai 				goto end;
699b250187eSsaisai 			}
700b250187eSsaisai 
701b250187eSsaisai 			alarm_type = ts_alinfo.alarm_no;
702b250187eSsaisai 			alarm_state = ts_alinfo.alarm_state;
703b250187eSsaisai 
704b250187eSsaisai 			if ((alarm_type < ALARM_CRITICAL) ||
705b250187eSsaisai 			    (alarm_type > ALARM_USER)) {
706b250187eSsaisai 				retval = EINVAL;
707b250187eSsaisai 				goto end;
708b250187eSsaisai 			}
709b250187eSsaisai 			if ((alarm_state < ALARM_OFF) ||
710b250187eSsaisai 			    (alarm_state > ALARM_ON)) {
711b250187eSsaisai 				retval = EINVAL;
712b250187eSsaisai 				goto end;
713b250187eSsaisai 			}
714b250187eSsaisai 
715b250187eSsaisai 			retval = glvc_alarm_set(alarm_type, alarm_state, softc);
716b250187eSsaisai 		}
717b250187eSsaisai 		break;
718b250187eSsaisai 
719b250187eSsaisai 	default:
720b250187eSsaisai 		retval = EINVAL;
721b250187eSsaisai 		break;
722b250187eSsaisai 	}
723b250187eSsaisai 
724b250187eSsaisai end:
725b250187eSsaisai 	mutex_exit(&softc->mutex);
726b250187eSsaisai 
727b250187eSsaisai 	return (retval);
728b250187eSsaisai }
729b250187eSsaisai 
730b250187eSsaisai static int
731b250187eSsaisai glvc_alarm_get(int alarm_type, int *alarm_state, tsalarm_softc_t *sc)
732b250187eSsaisai {
733b250187eSsaisai 	tsal_pcp_alarm_req_t	*req_ptr = NULL;
734b250187eSsaisai 	tsal_pcp_alarm_resp_t	*resp_ptr = NULL;
735b250187eSsaisai 	tsal_pcp_msg_t		send_msg;
736b250187eSsaisai 	tsal_pcp_msg_t		recv_msg;
737b250187eSsaisai 	int			status = -1;
738b250187eSsaisai 
739b250187eSsaisai 	/*
740b250187eSsaisai 	 * setup the request data to attach to the libpcp msg
741b250187eSsaisai 	 */
742b250187eSsaisai 	if (sc->req_ptr == NULL) {
743b250187eSsaisai 		goto alarm_return;
744b250187eSsaisai 	}
745b250187eSsaisai 
746b250187eSsaisai 	req_ptr = sc->req_ptr;
747b250187eSsaisai 
748b250187eSsaisai 	req_ptr->alarm_action = PCP_ALARM_STATUS;
749b250187eSsaisai 	req_ptr->alarm_id = alarm_type;
750b250187eSsaisai 
751b250187eSsaisai 	send_msg.msg_type = PCP_ALARM_CONTROL;
752b250187eSsaisai 	send_msg.sub_type = NULL;
753b250187eSsaisai 	send_msg.msg_len = sizeof (tsal_pcp_alarm_req_t);
754b250187eSsaisai 	send_msg.msg_data = (uint8_t *)req_ptr;
755b250187eSsaisai 
756b250187eSsaisai 	/*
757b250187eSsaisai 	 * send the request, receive the response
758b250187eSsaisai 	 */
759b250187eSsaisai 	if (tsal_pcp_send_recv(sc, &send_msg, &recv_msg,
760b250187eSsaisai 	    PCP_COMM_TIMEOUT) < 0) {
761b250187eSsaisai 		/* we either timed out or erred; either way try again */
762b250187eSsaisai 		(void) delay(PCP_COMM_TIMEOUT * drv_usectohz(1000000));
763b250187eSsaisai 
764b250187eSsaisai 		if (tsal_pcp_send_recv(sc, &send_msg, &recv_msg,
765b250187eSsaisai 		    PCP_COMM_TIMEOUT) < 0) {
766b250187eSsaisai 			cmn_err(CE_WARN, "tsalarm: communication failure");
767b250187eSsaisai 			goto alarm_return;
768b250187eSsaisai 		}
769b250187eSsaisai 	}
770b250187eSsaisai 
771b250187eSsaisai 	/*
772b250187eSsaisai 	 * validate that this data was meant for us
773b250187eSsaisai 	 */
774b250187eSsaisai 	if (recv_msg.msg_type != PCP_ALARM_CONTROL_R) {
775b250187eSsaisai 		cmn_err(CE_WARN, "tsalarm: unbound packet received");
776b250187eSsaisai 		goto alarm_return;
777b250187eSsaisai 	}
778b250187eSsaisai 
779b250187eSsaisai 	/*
780b250187eSsaisai 	 * verify that the Alarm action has taken place
781b250187eSsaisai 	 */
782b250187eSsaisai 	resp_ptr = (tsal_pcp_alarm_resp_t *)recv_msg.msg_data;
783b250187eSsaisai 	if (resp_ptr->status == PCP_ALARM_ERROR) {
784b250187eSsaisai 		cmn_err(CE_WARN, "tsalarm: failed to get alarm status");
785b250187eSsaisai 		goto alarm_return;
786b250187eSsaisai 	}
787b250187eSsaisai 
788b250187eSsaisai 	if (resp_ptr->alarm_state == ALARM_STATE_UNKNOWN)
789b250187eSsaisai 		cmn_err(CE_WARN, "tsalarm: ALARM set to unknown state");
790b250187eSsaisai 
791b250187eSsaisai 	*alarm_state = resp_ptr->alarm_state;
792b250187eSsaisai 	status = TSAL_PCP_OK;
793b250187eSsaisai 
794b250187eSsaisai alarm_return:
795b250187eSsaisai 	return (status);
796b250187eSsaisai }
797b250187eSsaisai 
798b250187eSsaisai static int
799b250187eSsaisai glvc_alarm_set(int alarm_type, int new_state, tsalarm_softc_t *sc)
800b250187eSsaisai {
801b250187eSsaisai 	tsal_pcp_alarm_req_t	*req_ptr = NULL;
802b250187eSsaisai 	tsal_pcp_alarm_resp_t	*resp_ptr = NULL;
803b250187eSsaisai 	tsal_pcp_msg_t		send_msg;
804b250187eSsaisai 	tsal_pcp_msg_t		recv_msg;
805b250187eSsaisai 	int			status = -1;
806b250187eSsaisai 
807b250187eSsaisai 	/*
808b250187eSsaisai 	 * setup the request data to attach to the libpcp msg
809b250187eSsaisai 	 */
810b250187eSsaisai 	if (sc->req_ptr == NULL) {
811b250187eSsaisai 		if ((sc->req_ptr = (tsal_pcp_alarm_req_t *)kmem_zalloc(
812b250187eSsaisai 		    sizeof (tsal_pcp_alarm_req_t),
813b250187eSsaisai 		    KM_NOSLEEP)) == NULL)
814b250187eSsaisai 			goto alarm_return;
815b250187eSsaisai 	}
816b250187eSsaisai 
817b250187eSsaisai 	req_ptr = sc->req_ptr;
818b250187eSsaisai 
819b250187eSsaisai 	if (new_state == ALARM_ON)
820b250187eSsaisai 		req_ptr->alarm_action = PCP_ALARM_ENABLE;
821b250187eSsaisai 	else if (new_state == ALARM_OFF)
822b250187eSsaisai 		req_ptr->alarm_action = PCP_ALARM_DISABLE;
823b250187eSsaisai 
824b250187eSsaisai 	req_ptr->alarm_id = alarm_type;
825b250187eSsaisai 
826b250187eSsaisai 	send_msg.msg_type = PCP_ALARM_CONTROL;
827b250187eSsaisai 	send_msg.sub_type = NULL;
828b250187eSsaisai 	send_msg.msg_len = sizeof (tsal_pcp_alarm_req_t);
829b250187eSsaisai 	send_msg.msg_data = (uint8_t *)req_ptr;
830b250187eSsaisai 
831b250187eSsaisai 	/*
832b250187eSsaisai 	 * send the request, receive the response
833b250187eSsaisai 	 */
834b250187eSsaisai 	if (tsal_pcp_send_recv(sc, &send_msg, &recv_msg,
835b250187eSsaisai 	    PCP_COMM_TIMEOUT) < 0) {
836b250187eSsaisai 		/* we either timed out or erred; either way try again */
837b250187eSsaisai 		(void) delay(PCP_COMM_TIMEOUT * drv_usectohz(1000000));
838b250187eSsaisai 
839b250187eSsaisai 		if (tsal_pcp_send_recv(sc, &send_msg, &recv_msg,
840b250187eSsaisai 		    PCP_COMM_TIMEOUT) < 0) {
841b250187eSsaisai 			goto alarm_return;
842b250187eSsaisai 		}
843b250187eSsaisai 	}
844b250187eSsaisai 
845b250187eSsaisai 	/*
846b250187eSsaisai 	 * validate that this data was meant for us
847b250187eSsaisai 	 */
848b250187eSsaisai 	if (recv_msg.msg_type != PCP_ALARM_CONTROL_R) {
849b250187eSsaisai 		cmn_err(CE_WARN, "tsalarm: unbound packet received");
850b250187eSsaisai 		goto alarm_return;
851b250187eSsaisai 	}
852b250187eSsaisai 
853b250187eSsaisai 	/*
854b250187eSsaisai 	 * verify that the Alarm action has taken place
855b250187eSsaisai 	 */
856b250187eSsaisai 	resp_ptr = (tsal_pcp_alarm_resp_t *)recv_msg.msg_data;
857b250187eSsaisai 	if (resp_ptr->status == PCP_ALARM_ERROR) {
858b250187eSsaisai 		cmn_err(CE_WARN, "tsalarm: failed to set alarm status");
859b250187eSsaisai 		goto alarm_return;
860b250187eSsaisai 	}
861b250187eSsaisai 
862b250187eSsaisai 	/*
863b250187eSsaisai 	 * ensure the Alarm action taken is the one requested
864b250187eSsaisai 	 */
865b250187eSsaisai 	if ((req_ptr->alarm_action == PCP_ALARM_DISABLE) &&
866b250187eSsaisai 	    (resp_ptr->alarm_state != ALARM_STATE_OFF)) {
867b250187eSsaisai 		cmn_err(CE_WARN, "tsalarm: failed to set alarm");
868b250187eSsaisai 		goto alarm_return;
869b250187eSsaisai 	} else if ((req_ptr->alarm_action == PCP_ALARM_ENABLE) &&
870b250187eSsaisai 	    (resp_ptr->alarm_state != ALARM_STATE_ON)) {
871b250187eSsaisai 		cmn_err(CE_WARN, "tsalarm: failed to set alarm");
872b250187eSsaisai 		goto alarm_return;
873b250187eSsaisai 	} else if (resp_ptr->alarm_state == ALARM_STATE_UNKNOWN) {
874b250187eSsaisai 		cmn_err(CE_WARN, "tsalarm: Alarm set to unknown state");
875b250187eSsaisai 		goto alarm_return;
876b250187eSsaisai 	}
877b250187eSsaisai 
878b250187eSsaisai 	status = TSAL_PCP_OK;
879b250187eSsaisai 
880b250187eSsaisai alarm_return:
881b250187eSsaisai 	return (status);
882b250187eSsaisai }
883b250187eSsaisai /*
884b250187eSsaisai  * Function: Send and Receive messages on platform channel.
885b250187eSsaisai  * Arguments:
886b250187eSsaisai  * int channel_fd      - channel file descriptor.
887b250187eSsaisai  * tsal_pcp_msg_t *req_msg  - Request Message to send to other end of channel.
888b250187eSsaisai  * tsal_pcp_msg_t *resp_msg - Response Message to be received.
889b250187eSsaisai  * uint32_t timeout    - timeout field when waiting for data from channel.
890b250187eSsaisai  * Returns:
891b250187eSsaisai  * 	0    - success (TSAL_PCP_OK).
892b250187eSsaisai  * 	(-1) - failure (TSAL_PCP_ERROR).
893b250187eSsaisai  */
894b250187eSsaisai static int
895b250187eSsaisai tsal_pcp_send_recv(tsalarm_softc_t *sc, tsal_pcp_msg_t *req_msg,
896b250187eSsaisai 			tsal_pcp_msg_t *resp_msg, uint32_t timeout)
897b250187eSsaisai {
898b250187eSsaisai 	void		*datap;
899b250187eSsaisai 	void		*resp_msg_data = NULL;
900b250187eSsaisai 	uint32_t	status;
901b250187eSsaisai 	uint16_t	cksum = 0;
902b250187eSsaisai 	int		ret;
903b250187eSsaisai 	int		resp_hdr_ok;
904b250187eSsaisai 	tsal_pcp_req_msg_hdr_t *req_msg_hdr = NULL;
905b250187eSsaisai 	tsal_pcp_resp_msg_hdr_t *resp_msg_hdr = NULL;
906b250187eSsaisai #ifdef PCP_CKSUM_ENABLE
907b250187eSsaisai 	uint16_t	bkup_resp_hdr_cksum;
908b250187eSsaisai #endif
909b250187eSsaisai 
910b250187eSsaisai 
911b250187eSsaisai 	if (req_msg == NULL) {
912b250187eSsaisai 		return (TSAL_PCP_ERROR);
913b250187eSsaisai 	}
914b250187eSsaisai 
915b250187eSsaisai 	if ((req_msg->msg_len != 0) && ((datap = req_msg->msg_data) == NULL))
916b250187eSsaisai 		return (TSAL_PCP_ERROR);
917b250187eSsaisai 
918b250187eSsaisai 	req_msg_hdr = sc->req_msg_hdr;
919b250187eSsaisai 
920b250187eSsaisai 	if (req_msg_hdr == NULL)
921b250187eSsaisai 		return (TSAL_PCP_ERROR);
922b250187eSsaisai 
923b250187eSsaisai 	if (req_msg->msg_len != 0) {
924b250187eSsaisai 		/* calculate request msg_cksum */
925b250187eSsaisai 		cksum = checksum((uint16_t *)datap, req_msg->msg_len);
926b250187eSsaisai 	}
927b250187eSsaisai 
928b250187eSsaisai 	/*
929b250187eSsaisai 	 * Fill in the message header for the request packet
930b250187eSsaisai 	 */
931b250187eSsaisai 	req_msg_hdr->magic_num = PCP_MAGIC_NUM;
932b250187eSsaisai 	req_msg_hdr->proto_ver = PCP_PROT_VER_1;
933b250187eSsaisai 	req_msg_hdr->msg_type = req_msg->msg_type;
934b250187eSsaisai 	req_msg_hdr->sub_type = req_msg->sub_type;
935b250187eSsaisai 	req_msg_hdr->rsvd_pad = 0;
936b250187eSsaisai 	req_msg_hdr->xid = tsal_pcp_get_xid(sc);
937b250187eSsaisai 	req_msg_hdr->msg_len  = req_msg->msg_len;
938b250187eSsaisai 	req_msg_hdr->timeout = timeout;
939b250187eSsaisai 	req_msg_hdr->msg_cksum = cksum;
940b250187eSsaisai 	req_msg_hdr->hdr_cksum = 0;
941b250187eSsaisai 
942b250187eSsaisai 	/* fill request header checksum */
943b250187eSsaisai 	req_msg_hdr->hdr_cksum = checksum((uint16_t *)req_msg_hdr,
944b250187eSsaisai 	    sizeof (tsal_pcp_req_msg_hdr_t));
945b250187eSsaisai 
946b250187eSsaisai 	/*
947b250187eSsaisai 	 * send request message header
948b250187eSsaisai 	 */
949b250187eSsaisai 	if ((ret = tsal_pcp_send_req_msg_hdr(sc, req_msg_hdr))) {
950b250187eSsaisai 		return (ret);
951b250187eSsaisai 	}
952b250187eSsaisai 
953b250187eSsaisai 	/*
954b250187eSsaisai 	 * send request message
955b250187eSsaisai 	 */
956b250187eSsaisai 	if (req_msg->msg_len != 0) {
957b250187eSsaisai 		if ((ret = tsal_pcp_io_op(sc, datap, req_msg->msg_len,
958b250187eSsaisai 		    PCP_IO_OP_WRITE))) {
959b250187eSsaisai 			return (ret);
960b250187eSsaisai 		}
961b250187eSsaisai 	}
962b250187eSsaisai 
963b250187eSsaisai 	if (timeout == (uint32_t)PCP_TO_NO_RESPONSE)
964b250187eSsaisai 		return (TSAL_PCP_OK);
965b250187eSsaisai 
966b250187eSsaisai 	resp_msg_hdr = sc->resp_msg_hdr;
967b250187eSsaisai 
968b250187eSsaisai 	if (resp_msg_hdr == NULL) {
969b250187eSsaisai 		return (TSAL_PCP_ERROR);
970b250187eSsaisai 	}
971b250187eSsaisai 
972b250187eSsaisai 	resp_hdr_ok = 0;
973b250187eSsaisai 	while (!resp_hdr_ok) {
974b250187eSsaisai 		/*
975b250187eSsaisai 		 * Receive response message header
976b250187eSsaisai 		 * Note: frame error handling is done in
977b250187eSsaisai 		 * 'tsal_pcp_recv_resp_msg_hdr()'.
978b250187eSsaisai 		 */
979b250187eSsaisai 		if ((ret = tsal_pcp_recv_resp_msg_hdr(sc, resp_msg_hdr))) {
980b250187eSsaisai 			return (ret);
981b250187eSsaisai 		}
982b250187eSsaisai 
983b250187eSsaisai 		/*
984b250187eSsaisai 		 * Check header checksum if it matches with the received hdr
985b250187eSsaisai 		 * checksum.
986b250187eSsaisai 		 */
987b250187eSsaisai #ifdef PCP_CKSUM_ENABLE
988b250187eSsaisai 		bkup_resp_hdr_cksum = resp_msg_hdr->hdr_cksum;
989b250187eSsaisai 		resp_msg_hdr->hdr_cksum = 0;
990b250187eSsaisai 		cksum = checksum((uint16_t *)resp_msg_hdr,
991b250187eSsaisai 		    sizeof (tsal_pcp_resp_msg_hdr_t));
992b250187eSsaisai 
993b250187eSsaisai 		if (cksum != bkup_resp_hdr_cksum) {
994b250187eSsaisai 			return (TSAL_PCP_ERROR);
995b250187eSsaisai 		}
996b250187eSsaisai #endif
997b250187eSsaisai 		/*
998b250187eSsaisai 		 * Check for matching request and response messages
999b250187eSsaisai 		 */
1000b250187eSsaisai 		if (resp_msg_hdr->xid != req_msg_hdr->xid) {
1001b250187eSsaisai 			continue; /* continue reading response header */
1002b250187eSsaisai 		}
1003b250187eSsaisai 		resp_hdr_ok = 1;
1004b250187eSsaisai 	}
1005b250187eSsaisai 
1006b250187eSsaisai 	/*
1007b250187eSsaisai 	 * check status field for any channel protocol errrors
1008b250187eSsaisai 	 * This field signifies something happend during request
1009b250187eSsaisai 	 * message trasmission. This field is set by the receiver.
1010b250187eSsaisai 	 */
1011b250187eSsaisai 	status = resp_msg_hdr->status;
1012b250187eSsaisai 	if (status != TSAL_PCP_OK) {
1013b250187eSsaisai 		return (TSAL_PCP_ERROR);
1014b250187eSsaisai 	}
1015b250187eSsaisai 
1016b250187eSsaisai 	if (resp_msg_hdr->msg_len != 0) {
1017b250187eSsaisai 		if (sc->resp_ptr == NULL)
1018b250187eSsaisai 			return (TSAL_PCP_ERROR);
1019b250187eSsaisai 
1020b250187eSsaisai 		resp_msg_data = (uint8_t *)sc->resp_ptr;
1021b250187eSsaisai 		/*
1022b250187eSsaisai 		 * Receive response message.
1023b250187eSsaisai 		 */
1024b250187eSsaisai 		if ((ret = tsal_pcp_io_op(sc, resp_msg_data,
1025b250187eSsaisai 		    resp_msg_hdr->msg_len,
1026b250187eSsaisai 		    PCP_IO_OP_READ))) {
1027b250187eSsaisai 			return (ret);
1028b250187eSsaisai 		}
1029b250187eSsaisai 
1030b250187eSsaisai #ifdef PCP_CKSUM_ENABLE
1031b250187eSsaisai 		/* verify response message data checksum */
1032b250187eSsaisai 		cksum = checksum((uint16_t *)resp_msg_data,
1033b250187eSsaisai 		    resp_msg_hdr->msg_len);
1034b250187eSsaisai 		if (cksum != resp_msg_hdr->msg_cksum) {
1035b250187eSsaisai 			return (TSAL_PCP_ERROR);
1036b250187eSsaisai 		}
1037b250187eSsaisai #endif
1038b250187eSsaisai 	}
1039b250187eSsaisai 	/* Everything is okay put the received data into user */
1040b250187eSsaisai 	/* resp_msg struct */
1041b250187eSsaisai 	resp_msg->msg_len = resp_msg_hdr->msg_len;
1042b250187eSsaisai 	resp_msg->msg_type = resp_msg_hdr->msg_type;
1043b250187eSsaisai 	resp_msg->sub_type = resp_msg_hdr->sub_type;
1044b250187eSsaisai 	resp_msg->msg_data = (uint8_t *)resp_msg_data;
1045b250187eSsaisai 
1046b250187eSsaisai 	return (TSAL_PCP_OK);
1047b250187eSsaisai }
1048b250187eSsaisai 
1049b250187eSsaisai /*
1050b250187eSsaisai  * Function: wrapper for handling glvc calls (read/write/peek).
1051b250187eSsaisai  */
1052b250187eSsaisai static int
1053b250187eSsaisai tsal_pcp_io_op(tsalarm_softc_t *sc, void *buf, int byte_cnt, int io_op)
1054b250187eSsaisai {
1055b250187eSsaisai 	int	rv;
1056b250187eSsaisai 	int	n;
1057b250187eSsaisai 	uint8_t	*datap;
1058b250187eSsaisai 	int	(*func_ptr)(tsalarm_softc_t *, uint8_t *, int);
1059b250187eSsaisai 	int	io_sz;
1060b250187eSsaisai 	int	try_cnt;
1061b250187eSsaisai 
1062b250187eSsaisai 	if ((buf == NULL) || (byte_cnt < 0)) {
1063b250187eSsaisai 		return (TSAL_PCP_ERROR);
1064b250187eSsaisai 	}
1065b250187eSsaisai 
1066b250187eSsaisai 	switch (io_op) {
1067b250187eSsaisai 		case PCP_IO_OP_READ:
1068b250187eSsaisai 			func_ptr = tsal_pcp_read;
1069b250187eSsaisai 			break;
1070b250187eSsaisai 		case PCP_IO_OP_WRITE:
1071b250187eSsaisai 			func_ptr = tsal_pcp_write;
1072b250187eSsaisai 			break;
1073b250187eSsaisai 		case PCP_IO_OP_PEEK:
1074b250187eSsaisai 			func_ptr = tsal_pcp_peek;
1075b250187eSsaisai 			break;
1076b250187eSsaisai 		default:
1077b250187eSsaisai 			return (TSAL_PCP_ERROR);
1078b250187eSsaisai 	}
1079b250187eSsaisai 
1080b250187eSsaisai 	/*
1081b250187eSsaisai 	 * loop until all I/O done, try limit exceded, or real failure
1082b250187eSsaisai 	 */
1083b250187eSsaisai 
1084b250187eSsaisai 	rv = 0;
1085b250187eSsaisai 	datap = buf;
1086b250187eSsaisai 	while (rv < byte_cnt) {
1087b250187eSsaisai 		io_sz = MIN((byte_cnt - rv), sc->mtu_size);
1088b250187eSsaisai 		try_cnt = 0;
1089b250187eSsaisai 		while ((n = (*func_ptr)(sc, datap, io_sz)) < 0) {
1090b250187eSsaisai 			try_cnt++;
1091b250187eSsaisai 			if (try_cnt > PCP_MAX_TRY_CNT) {
1092b250187eSsaisai 				rv = n;
1093b250187eSsaisai 				goto done;
1094b250187eSsaisai 			}
1095b250187eSsaisai 			/* waiting 5 secs. Do we need 5 Secs? */
1096b250187eSsaisai 			(void) delay(PCP_GLVC_SLEEP * drv_usectohz(1000000));
1097b250187eSsaisai 		} /* while trying the io operation */
1098b250187eSsaisai 
1099b250187eSsaisai 		if (n < 0) {
1100b250187eSsaisai 			rv = n;
1101b250187eSsaisai 			goto done;
1102b250187eSsaisai 		}
1103b250187eSsaisai 		rv += n;
1104b250187eSsaisai 		datap += n;
1105b250187eSsaisai 	} /* while still have more data */
1106b250187eSsaisai 
1107b250187eSsaisai done:
1108b250187eSsaisai 	if (rv == byte_cnt)
1109b250187eSsaisai 		return (0);
1110b250187eSsaisai 	else
1111b250187eSsaisai 		return (TSAL_PCP_ERROR);
1112b250187eSsaisai }
1113b250187eSsaisai 
1114b250187eSsaisai /*
1115b250187eSsaisai  * For peeking 'bytes_cnt' bytes in channel (glvc) buffers.
1116b250187eSsaisai  * If data is available, the data is copied into 'buf'.
1117b250187eSsaisai  */
1118b250187eSsaisai static int
1119b250187eSsaisai tsal_pcp_peek(tsalarm_softc_t *sc, uint8_t *buf, int bytes_cnt)
1120b250187eSsaisai {
1121b250187eSsaisai 	int			ret, rval;
1122b250187eSsaisai 	glvc_xport_msg_peek_t	peek_ctrl;
1123b250187eSsaisai 	int			n, m;
1124b250187eSsaisai 
1125b250187eSsaisai 	if (bytes_cnt < 0 || bytes_cnt > sc->mtu_size) {
1126b250187eSsaisai 		return (TSAL_PCP_ERROR);
1127b250187eSsaisai 	}
1128b250187eSsaisai 
1129b250187eSsaisai 	/*
1130b250187eSsaisai 	 * initialization of buffers used for peeking data in channel buffers.
1131b250187eSsaisai 	 */
1132b250187eSsaisai 	if (sc->peek_area == NULL) {
1133b250187eSsaisai 		return (TSAL_PCP_ERROR);
1134b250187eSsaisai 	}
1135b250187eSsaisai 
1136b250187eSsaisai 	/*
1137b250187eSsaisai 	 * peek max MTU size bytes
1138b250187eSsaisai 	 */
1139b250187eSsaisai 	peek_ctrl.buf = (caddr_t)sc->peek_area;
1140b250187eSsaisai 	peek_ctrl.buflen = sc->mtu_size;
1141b250187eSsaisai 	peek_ctrl.flags = 0;
1142b250187eSsaisai 
1143b250187eSsaisai 	if ((ret = ldi_ioctl(sc->lh, GLVC_XPORT_IOCTL_DATA_PEEK,
1144b250187eSsaisai 	    (intptr_t)&peek_ctrl, FKIOCTL, kcred, &rval)) < 0) {
1145b250187eSsaisai 		return (ret);
1146b250187eSsaisai 	}
1147b250187eSsaisai 
1148b250187eSsaisai 	n = peek_ctrl.buflen;
1149b250187eSsaisai 
1150b250187eSsaisai 	if (n < 0)
1151b250187eSsaisai 		return (TSAL_PCP_ERROR);
1152b250187eSsaisai 
1153b250187eSsaisai 	/*
1154b250187eSsaisai 	 * satisfy request as best as we can
1155b250187eSsaisai 	 */
1156b250187eSsaisai 	m = MIN(bytes_cnt, n);
1157b250187eSsaisai 	(void) memcpy(buf, sc->peek_area, m);
1158b250187eSsaisai 
1159b250187eSsaisai 	return (m);
1160b250187eSsaisai }
1161b250187eSsaisai 
1162b250187eSsaisai /*
1163b250187eSsaisai  * Function: write 'byte_cnt' bytes from 'buf' to channel.
1164b250187eSsaisai  */
1165b250187eSsaisai static int
1166b250187eSsaisai tsal_pcp_write(tsalarm_softc_t *sc, uint8_t *buf, int byte_cnt)
1167b250187eSsaisai {
1168b250187eSsaisai 	int		ret;
1169b250187eSsaisai 	struct uio	uio;
1170b250187eSsaisai 	struct iovec	iov;
1171b250187eSsaisai 
1172b250187eSsaisai 	/* check for valid arguments */
1173b250187eSsaisai 	if (buf == NULL || byte_cnt < 0 || byte_cnt > sc->mtu_size) {
1174b250187eSsaisai 		return (TSAL_PCP_ERROR);
1175b250187eSsaisai 	}
1176b250187eSsaisai 	bzero(&uio, sizeof (uio));
1177b250187eSsaisai 	bzero(&iov, sizeof (iov));
1178b250187eSsaisai 	iov.iov_base = (int8_t *)buf;
1179b250187eSsaisai 	iov.iov_len = byte_cnt;
1180b250187eSsaisai 	uio.uio_iov = &iov;
1181b250187eSsaisai 	uio.uio_iovcnt = 1;
1182b250187eSsaisai 	uio.uio_loffset = 0;
1183b250187eSsaisai 	uio.uio_segflg = UIO_SYSSPACE;
1184b250187eSsaisai 	uio.uio_resid = byte_cnt;
1185b250187eSsaisai 
1186b250187eSsaisai 	if ((ret = ldi_write(sc->lh, &uio, kcred)) < 0) {
1187b250187eSsaisai 		return (ret);
1188b250187eSsaisai 	}
1189b250187eSsaisai 	return (byte_cnt - iov.iov_len);
1190b250187eSsaisai }
1191b250187eSsaisai 
1192b250187eSsaisai /*
1193b250187eSsaisai  * In current implementaion of glvc driver, streams reads are not supported.
1194b250187eSsaisai  * tsal_pcp_read mimics stream reads by first reading all the bytes present in
1195b250187eSsaisai  * channel buffer into a local buffer and from then on read requests
1196b250187eSsaisai  * are serviced from local buffer. When read requests are not serviceble
1197b250187eSsaisai  * from local buffer, it repeates by first reading data from channel buffers.
1198b250187eSsaisai  */
1199b250187eSsaisai 
1200b250187eSsaisai static int
1201b250187eSsaisai tsal_pcp_read(tsalarm_softc_t *sc, uint8_t *buf, int byte_cnt)
1202b250187eSsaisai {
1203b250187eSsaisai 	int			ret;
1204b250187eSsaisai 	int			n, m, i;
1205b250187eSsaisai 	struct uio		uio;
1206b250187eSsaisai 	struct iovec		iov;
1207b250187eSsaisai 	int			read_area_size = 0;
1208b250187eSsaisai 
1209b250187eSsaisai 	if (byte_cnt < 0 || byte_cnt > sc->mtu_size) {
1210b250187eSsaisai 		return (TSAL_PCP_ERROR);
1211b250187eSsaisai 	}
1212b250187eSsaisai 
1213b250187eSsaisai 	read_area_size = 2*sc->mtu_size;
1214b250187eSsaisai 	/*
1215b250187eSsaisai 	 * initialization of local read buffer
1216b250187eSsaisai 	 * from which the stream read requests are serviced.
1217b250187eSsaisai 	 */
1218b250187eSsaisai 	if (sc->read_area == NULL) {
1219b250187eSsaisai 		sc->read_area = (uint8_t *)kmem_zalloc(read_area_size,
1220b250187eSsaisai 		    KM_NOSLEEP);
1221b250187eSsaisai 		if (sc->read_area == NULL) {
1222b250187eSsaisai 			return (TSAL_PCP_ERROR);
1223b250187eSsaisai 		}
1224b250187eSsaisai 		sc->read_head = sc->read_area;
1225b250187eSsaisai 		sc->read_tail = sc->read_area;
1226b250187eSsaisai 	}
1227b250187eSsaisai 
1228b250187eSsaisai 	/*
1229b250187eSsaisai 	 * if we already read this data then copy from local buffer it self
1230b250187eSsaisai 	 * without calling new read.
1231b250187eSsaisai 	 */
1232b250187eSsaisai 	if (byte_cnt <= (sc->read_tail - sc->read_head)) {
1233b250187eSsaisai 		(void) memcpy(buf, sc->read_head, byte_cnt);
1234b250187eSsaisai 		sc->read_head += byte_cnt;
1235b250187eSsaisai 		return (byte_cnt);
1236b250187eSsaisai 	}
1237b250187eSsaisai 
1238b250187eSsaisai 	/*
1239b250187eSsaisai 	 * if the request is not satisfied from the buffered data, then move
1240b250187eSsaisai 	 * remaining data to front of the buffer and read new data.
1241b250187eSsaisai 	 */
1242b250187eSsaisai 	for (i = 0; i < (sc->read_tail - sc->read_head); ++i) {
1243b250187eSsaisai 		sc->read_area[i] = sc->read_head[i];
1244b250187eSsaisai 	}
1245b250187eSsaisai 	sc->read_head = sc->read_area;
1246b250187eSsaisai 	sc->read_tail = sc->read_head + i;
1247b250187eSsaisai 
1248b250187eSsaisai 	/*
1249b250187eSsaisai 	 * do a peek to see how much data is available and read complete data.
1250b250187eSsaisai 	 */
1251b250187eSsaisai 
1252b250187eSsaisai 	if ((m = tsal_pcp_peek(sc, sc->read_tail, sc->mtu_size)) < 0) {
1253b250187eSsaisai 		return (m);
1254b250187eSsaisai 	}
1255b250187eSsaisai 
1256b250187eSsaisai 	bzero(&uio, sizeof (uio));
1257b250187eSsaisai 	bzero(&iov, sizeof (iov));
1258b250187eSsaisai 	iov.iov_base = (int8_t *)sc->read_tail;
1259b250187eSsaisai 	iov.iov_len = m;
1260b250187eSsaisai 	uio.uio_iov = &iov;
1261b250187eSsaisai 	uio.uio_iovcnt = 1;
1262b250187eSsaisai 	uio.uio_loffset = 0;
1263b250187eSsaisai 	uio.uio_segflg = UIO_SYSSPACE;
1264b250187eSsaisai 	uio.uio_resid = m;
1265b250187eSsaisai 
1266b250187eSsaisai 	if ((ret = ldi_read(sc->lh, &uio, kcred)) != 0) {
1267b250187eSsaisai 		return (ret);
1268b250187eSsaisai 	}
1269b250187eSsaisai 
1270b250187eSsaisai 	sc->read_tail += (m - iov.iov_len);
1271b250187eSsaisai 
1272b250187eSsaisai 	/*
1273b250187eSsaisai 	 * copy the requested bytes.
1274b250187eSsaisai 	 */
1275b250187eSsaisai 	n = MIN(byte_cnt, (sc->read_tail - sc->read_head));
1276b250187eSsaisai 	(void) memcpy(buf, sc->read_head, n);
1277b250187eSsaisai 
1278b250187eSsaisai 	sc->read_head += n;
1279b250187eSsaisai 
1280b250187eSsaisai 	return (n);
1281b250187eSsaisai }
1282b250187eSsaisai /*
1283b250187eSsaisai  * This function is slight different from tsal_pcp_peek. The peek requests are
1284b250187eSsaisai  * serviced from local read buffer, if data is available. If the peek request
1285b250187eSsaisai  * is not serviceble from local read buffer, then the data is peeked from
1286b250187eSsaisai  * channel buffer. This function is mainly used for proper protocol framing
1287b250187eSsaisai  * error handling.
1288b250187eSsaisai  */
1289b250187eSsaisai static int
1290b250187eSsaisai tsal_pcp_peek_read(tsalarm_softc_t *sc, uint8_t *buf, int byte_cnt)
1291b250187eSsaisai {
1292b250187eSsaisai 	int	n, m, i;
1293b250187eSsaisai 	uint8_t	*peek_read_head = NULL;
1294b250187eSsaisai 	uint8_t *peek_read_tail = NULL;
1295b250187eSsaisai 
1296b250187eSsaisai 	if (byte_cnt < 0 || byte_cnt > sc->mtu_size) {
1297b250187eSsaisai 		return (TSAL_PCP_ERROR);
1298b250187eSsaisai 	}
1299b250187eSsaisai 
1300b250187eSsaisai 	/*
1301b250187eSsaisai 	 * if we already have the data in local read buffer then copy
1302b250187eSsaisai 	 * from local buffer it self w/out calling new peek
1303b250187eSsaisai 	 */
1304b250187eSsaisai 	if (byte_cnt <= (sc->read_tail - sc->read_head)) {
1305b250187eSsaisai 		(void) memcpy(buf, sc->read_head, byte_cnt);
1306b250187eSsaisai 		return (byte_cnt);
1307b250187eSsaisai 	}
1308b250187eSsaisai 
1309b250187eSsaisai 
1310b250187eSsaisai 	if (sc->peek_read_area == NULL) {
1311b250187eSsaisai 		return (TSAL_PCP_ERROR);
1312b250187eSsaisai 	}
1313b250187eSsaisai 	peek_read_head = sc->peek_read_area;
1314b250187eSsaisai 	peek_read_tail = sc->peek_read_area;
1315b250187eSsaisai 
1316b250187eSsaisai 	/*
1317b250187eSsaisai 	 * if the request is not satisfied from local read buffer, then first
1318b250187eSsaisai 	 * copy the remaining data in local read buffer to peek_read_area and
1319b250187eSsaisai 	 * then issue new peek.
1320b250187eSsaisai 	 */
1321b250187eSsaisai 	for (i = 0; i < (sc->read_tail - sc->read_head); ++i) {
1322b250187eSsaisai 		sc->peek_read_area[i] = sc->read_head[i];
1323b250187eSsaisai 	}
1324b250187eSsaisai 	peek_read_head = sc->peek_read_area;
1325b250187eSsaisai 	peek_read_tail = peek_read_head + i;
1326b250187eSsaisai 
1327b250187eSsaisai 	/*
1328b250187eSsaisai 	 * do a peek to see how much data is available and read complete data.
1329b250187eSsaisai 	 */
1330b250187eSsaisai 
1331b250187eSsaisai 	if ((m = tsal_pcp_peek(sc, peek_read_tail, sc->mtu_size)) < 0) {
1332b250187eSsaisai 		return (m);
1333b250187eSsaisai 	}
1334b250187eSsaisai 
1335b250187eSsaisai 	peek_read_tail += m;
1336b250187eSsaisai 
1337b250187eSsaisai 	/*
1338b250187eSsaisai 	 * copy the requested bytes
1339b250187eSsaisai 	 */
1340b250187eSsaisai 	n = MIN(byte_cnt, (peek_read_tail - peek_read_head));
1341b250187eSsaisai 	(void) memcpy(buf, peek_read_head, n);
1342b250187eSsaisai 
1343b250187eSsaisai 	return (n);
1344b250187eSsaisai }
1345b250187eSsaisai /*
1346b250187eSsaisai  * Send Request Message Header.
1347b250187eSsaisai  */
1348b250187eSsaisai static int
1349b250187eSsaisai tsal_pcp_send_req_msg_hdr(tsalarm_softc_t *sc, tsal_pcp_req_msg_hdr_t *req_hdr)
1350b250187eSsaisai {
1351b250187eSsaisai 	tsal_pcp_req_msg_hdr_t	*hdrp;
1352b250187eSsaisai 	int			hdr_sz;
1353b250187eSsaisai 	int			ret;
1354b250187eSsaisai 
1355b250187eSsaisai 	hdr_sz = sizeof (tsal_pcp_req_msg_hdr_t);
1356b250187eSsaisai 	if ((hdrp = (tsal_pcp_req_msg_hdr_t *)kmem_zalloc(hdr_sz,
1357b250187eSsaisai 	    KM_NOSLEEP)) == NULL) {
1358b250187eSsaisai 		return (TSAL_PCP_ERROR);
1359b250187eSsaisai 	}
1360b250187eSsaisai 
1361b250187eSsaisai 	hdrp->magic_num = htonl(req_hdr->magic_num);
1362b250187eSsaisai 	hdrp->proto_ver = req_hdr->proto_ver;
1363b250187eSsaisai 	hdrp->msg_type = req_hdr->msg_type;
1364b250187eSsaisai 	hdrp->sub_type = req_hdr->sub_type;
1365b250187eSsaisai 	hdrp->rsvd_pad = htons(req_hdr->rsvd_pad);
1366b250187eSsaisai 	hdrp->xid = htonl(req_hdr->xid);
1367b250187eSsaisai 	hdrp->timeout = htonl(req_hdr->timeout);
1368b250187eSsaisai 	hdrp->msg_len = htonl(req_hdr->msg_len);
1369b250187eSsaisai 	hdrp->msg_cksum = htons(req_hdr->msg_cksum);
1370b250187eSsaisai 	hdrp->hdr_cksum = htons(req_hdr->hdr_cksum);
1371b250187eSsaisai 
1372b250187eSsaisai 	if ((ret = tsal_pcp_io_op(sc, (char *)hdrp, hdr_sz,
1373b250187eSsaisai 	    PCP_IO_OP_WRITE)) != 0) {
1374b250187eSsaisai 		kmem_free(hdrp, hdr_sz);
1375b250187eSsaisai 		return (ret);
1376b250187eSsaisai 	}
1377b250187eSsaisai 	kmem_free(hdrp, hdr_sz);
1378b250187eSsaisai 	return (TSAL_PCP_OK);
1379b250187eSsaisai }
1380b250187eSsaisai /*
1381b250187eSsaisai  * Receive Response message header.
1382b250187eSsaisai  */
1383b250187eSsaisai static int
1384b250187eSsaisai tsal_pcp_recv_resp_msg_hdr(tsalarm_softc_t *sc,
1385b250187eSsaisai 				tsal_pcp_resp_msg_hdr_t *resp_hdr)
1386b250187eSsaisai {
1387b250187eSsaisai 	uint32_t	magic_num;
1388b250187eSsaisai 	uint8_t		proto_ver;
1389b250187eSsaisai 	uint8_t		msg_type;
1390b250187eSsaisai 	uint8_t		sub_type;
1391b250187eSsaisai 	uint8_t		rsvd_pad;
1392b250187eSsaisai 	uint32_t	xid;
1393b250187eSsaisai 	uint32_t	timeout;
1394b250187eSsaisai 	uint32_t	msg_len;
1395b250187eSsaisai 	uint32_t	status;
1396b250187eSsaisai 	uint16_t	msg_cksum;
1397b250187eSsaisai 	uint16_t	hdr_cksum;
1398b250187eSsaisai 	int		ret;
1399b250187eSsaisai 
1400b250187eSsaisai 	if (resp_hdr == NULL) {
1401b250187eSsaisai 		return (TSAL_PCP_ERROR);
1402b250187eSsaisai 	}
1403b250187eSsaisai 
1404b250187eSsaisai 	/*
1405b250187eSsaisai 	 * handle protocol framing errors.
1406b250187eSsaisai 	 * tsal_pcp_frame_error_handle() returns when proper frame arrived
1407b250187eSsaisai 	 * (magic seq) or if an error happens while reading data from
1408b250187eSsaisai 	 * channel.
1409b250187eSsaisai 	 */
1410b250187eSsaisai 	if ((ret = tsal_pcp_frame_error_handle(sc)) != 0) {
1411b250187eSsaisai 		return (TSAL_PCP_ERROR);
1412b250187eSsaisai 	}
1413b250187eSsaisai 
1414b250187eSsaisai 	/* read magic number first */
1415b250187eSsaisai 	if ((ret = tsal_pcp_io_op(sc, &magic_num, sizeof (magic_num),
1416b250187eSsaisai 	    PCP_IO_OP_READ)) != 0) {
1417b250187eSsaisai 		return (ret);
1418b250187eSsaisai 	}
1419b250187eSsaisai 
1420b250187eSsaisai 	magic_num = ntohl(magic_num);
1421b250187eSsaisai 
1422b250187eSsaisai 	if (magic_num != PCP_MAGIC_NUM) {
1423b250187eSsaisai 		return (TSAL_PCP_ERROR);
1424b250187eSsaisai 	}
1425b250187eSsaisai 
1426b250187eSsaisai 	/* read version field */
1427b250187eSsaisai 	if ((ret = tsal_pcp_io_op(sc, &proto_ver, sizeof (proto_ver),
1428b250187eSsaisai 	    PCP_IO_OP_READ)) != 0) {
1429b250187eSsaisai 		return (ret);
1430b250187eSsaisai 	}
1431b250187eSsaisai 
1432b250187eSsaisai 	/* check protocol version */
1433b250187eSsaisai 	if (proto_ver != PCP_PROT_VER_1) {
1434b250187eSsaisai 		return (TSAL_PCP_ERROR);
1435b250187eSsaisai 	}
1436b250187eSsaisai 
1437b250187eSsaisai 	/* Read message type */
1438b250187eSsaisai 	if ((ret = tsal_pcp_io_op(sc, &msg_type, sizeof (msg_type),
1439b250187eSsaisai 	    PCP_IO_OP_READ)) != 0) {
1440b250187eSsaisai 		return (ret);
1441b250187eSsaisai 	}
1442b250187eSsaisai 
1443b250187eSsaisai 	/* Read message sub type */
1444b250187eSsaisai 	if ((ret = tsal_pcp_io_op(sc, &sub_type, sizeof (sub_type),
1445b250187eSsaisai 	    PCP_IO_OP_READ)) != 0) {
1446b250187eSsaisai 		return (ret);
1447b250187eSsaisai 	}
1448b250187eSsaisai 
1449b250187eSsaisai 	/* Read rcvd_pad bits */
1450b250187eSsaisai 	if ((ret = tsal_pcp_io_op(sc, &rsvd_pad, sizeof (rsvd_pad),
1451b250187eSsaisai 	    PCP_IO_OP_READ)) != 0) {
1452b250187eSsaisai 		return (ret);
1453b250187eSsaisai 	}
1454b250187eSsaisai 
1455b250187eSsaisai 	/* receive transaction id */
1456b250187eSsaisai 	if ((ret = tsal_pcp_io_op(sc, &xid, sizeof (xid),
1457b250187eSsaisai 	    PCP_IO_OP_READ)) != 0) {
1458b250187eSsaisai 		return (ret);
1459b250187eSsaisai 	}
1460b250187eSsaisai 
1461b250187eSsaisai 	xid = ntohl(xid);
1462b250187eSsaisai 
1463b250187eSsaisai 	/* receive timeout value */
1464b250187eSsaisai 	if ((ret = tsal_pcp_io_op(sc, &timeout, sizeof (timeout),
1465b250187eSsaisai 	    PCP_IO_OP_READ)) != 0) {
1466b250187eSsaisai 		return (ret);
1467b250187eSsaisai 	}
1468b250187eSsaisai 
1469b250187eSsaisai 	timeout = ntohl(timeout);
1470b250187eSsaisai 
1471b250187eSsaisai 	/* receive message length */
1472b250187eSsaisai 	if ((ret = tsal_pcp_io_op(sc, &msg_len, sizeof (msg_len),
1473b250187eSsaisai 	    PCP_IO_OP_READ)) != 0) {
1474b250187eSsaisai 		return (ret);
1475b250187eSsaisai 	}
1476b250187eSsaisai 
1477b250187eSsaisai 	msg_len = ntohl(msg_len);
1478b250187eSsaisai 
1479b250187eSsaisai 	/* receive status field */
1480b250187eSsaisai 	if ((ret = tsal_pcp_io_op(sc, &status, sizeof (status),
1481b250187eSsaisai 	    PCP_IO_OP_READ)) != 0) {
1482b250187eSsaisai 		return (ret);
1483b250187eSsaisai 	}
1484b250187eSsaisai 
1485b250187eSsaisai 	status = ntohl(status);
1486b250187eSsaisai 
1487b250187eSsaisai 	/* receive message checksum */
1488b250187eSsaisai 	if ((ret = tsal_pcp_io_op(sc, &msg_cksum, sizeof (msg_cksum),
1489b250187eSsaisai 	    PCP_IO_OP_READ)) != 0) {
1490b250187eSsaisai 		return (ret);
1491b250187eSsaisai 	}
1492b250187eSsaisai 
1493b250187eSsaisai 	msg_cksum = ntohs(msg_cksum);
1494b250187eSsaisai 
1495b250187eSsaisai 	/* receive header checksum */
1496b250187eSsaisai 	if ((ret = tsal_pcp_io_op(sc, &hdr_cksum, sizeof (hdr_cksum),
1497b250187eSsaisai 	    PCP_IO_OP_READ)) != 0) {
1498b250187eSsaisai 		return (ret);
1499b250187eSsaisai 	}
1500b250187eSsaisai 
1501b250187eSsaisai 	hdr_cksum = ntohs(hdr_cksum);
1502b250187eSsaisai 
1503b250187eSsaisai 	/* copy to resp_hdr */
1504b250187eSsaisai 
1505b250187eSsaisai 	resp_hdr->magic_num = magic_num;
1506b250187eSsaisai 	resp_hdr->proto_ver = proto_ver;
1507b250187eSsaisai 	resp_hdr->msg_type = msg_type;
1508b250187eSsaisai 	resp_hdr->sub_type = sub_type;
1509b250187eSsaisai 	resp_hdr->rsvd_pad = rsvd_pad;
1510b250187eSsaisai 	resp_hdr->xid = xid;
1511b250187eSsaisai 	resp_hdr->timeout = timeout;
1512b250187eSsaisai 	resp_hdr->msg_len = msg_len;
1513b250187eSsaisai 	resp_hdr->status = status;
1514b250187eSsaisai 	resp_hdr->msg_cksum = msg_cksum;
1515b250187eSsaisai 	resp_hdr->hdr_cksum = hdr_cksum;
1516b250187eSsaisai 
1517b250187eSsaisai 	return (TSAL_PCP_OK);
1518b250187eSsaisai }
1519b250187eSsaisai 
1520b250187eSsaisai /*
1521b250187eSsaisai  * Get next xid for including in request message.
1522b250187eSsaisai  * Every request and response message are matched
1523b250187eSsaisai  * for same xid.
1524b250187eSsaisai  */
1525b250187eSsaisai 
1526b250187eSsaisai static uint32_t
1527b250187eSsaisai tsal_pcp_get_xid(tsalarm_softc_t *sc)
1528b250187eSsaisai {
1529b250187eSsaisai 	uint32_t		ret;
1530b250187eSsaisai 	static boolean_t	xid_initialized = B_FALSE;
1531b250187eSsaisai 
1532b250187eSsaisai 	if (xid_initialized == B_FALSE) {
1533b250187eSsaisai 		xid_initialized = B_TRUE;
1534b250187eSsaisai 		/*
1535b250187eSsaisai 		 * starting xid is initialized to a different value everytime
1536b250187eSsaisai 		 * user application is restarted so that user apps will not
1537b250187eSsaisai 		 * receive previous session's packets.
1538b250187eSsaisai 		 *
1539b250187eSsaisai 		 * Note: The algorithm for generating initial xid is partially
1540b250187eSsaisai 		 * taken from Solaris rpc code.
1541b250187eSsaisai 		 */
1542b250187eSsaisai 		sc->msg_xid = (uint32_t)gethrtime();
1543b250187eSsaisai 	}
1544b250187eSsaisai 
1545b250187eSsaisai 	ret = sc->msg_xid++;
1546b250187eSsaisai 
1547b250187eSsaisai 	/* zero xid is not allowed */
1548b250187eSsaisai 	if (ret == 0)
1549b250187eSsaisai 		ret = sc->msg_xid++;
1550b250187eSsaisai 
1551b250187eSsaisai 	return (ret);
1552b250187eSsaisai }
1553b250187eSsaisai 
1554b250187eSsaisai /*
1555b250187eSsaisai  * This function handles channel framing errors. It waits until proper
1556b250187eSsaisai  * frame with starting sequence as magic numder (0xAFBCAFA0)
1557b250187eSsaisai  * is arrived. It removes unexpected data (before the magic number sequence)
1558b250187eSsaisai  * on the channel. It returns when proper magic number sequence is seen
1559b250187eSsaisai  * or when any failure happens while reading/peeking the channel.
1560b250187eSsaisai  */
1561b250187eSsaisai static int
1562b250187eSsaisai tsal_pcp_frame_error_handle(tsalarm_softc_t *sc)
1563b250187eSsaisai {
1564b250187eSsaisai 	uint8_t		magic_num_buf[4];
1565b250187eSsaisai 	int		ispresent = 0;
1566b250187eSsaisai 	uint32_t	net_magic_num; /* magic byte in network byte order */
1567b250187eSsaisai 	uint32_t	host_magic_num = PCP_MAGIC_NUM;
1568b250187eSsaisai 	uint8_t		buf[2];
1569b250187eSsaisai 
1570b250187eSsaisai 	net_magic_num =	 htonl(host_magic_num);
1571b250187eSsaisai 	(void) memcpy(magic_num_buf, (uint8_t *)&net_magic_num, 4);
1572b250187eSsaisai 
1573b250187eSsaisai 	while (!ispresent) {
1574b250187eSsaisai 		/*
1575b250187eSsaisai 		 * Check if next four bytes matches pcp magic number.
1576b250187eSsaisai 		 * if mathing not found, discard 1 byte and continue checking.
1577b250187eSsaisai 		 */
1578b250187eSsaisai 		if (!check_magic_byte_presence(sc, 4, &magic_num_buf[0],
1579b250187eSsaisai 		    &ispresent)) {
1580b250187eSsaisai 			if (!ispresent) {
1581b250187eSsaisai 				/* remove 1 byte */
1582b250187eSsaisai 				(void) tsal_pcp_io_op(sc, buf, 1,
1583b250187eSsaisai 				    PCP_IO_OP_READ);
1584b250187eSsaisai 			}
1585b250187eSsaisai 		} else {
1586b250187eSsaisai 			return (-1);
1587b250187eSsaisai 		}
1588b250187eSsaisai 	}
1589b250187eSsaisai 
1590b250187eSsaisai 	return (0);
1591b250187eSsaisai }
1592b250187eSsaisai 
1593b250187eSsaisai /*
1594b250187eSsaisai  * checks whether certain byte sequence is present in the data stream.
1595b250187eSsaisai  */
1596b250187eSsaisai static int
1597b250187eSsaisai check_magic_byte_presence(tsalarm_softc_t *sc,
1598b250187eSsaisai 		int byte_cnt, uint8_t *byte_seq, int *ispresent)
1599b250187eSsaisai {
1600b250187eSsaisai 	int		ret, i;
1601b250187eSsaisai 	uint8_t		buf[4];
1602b250187eSsaisai 
1603b250187eSsaisai 	if ((ret = tsal_pcp_peek_read(sc, buf, byte_cnt)) < 0) {
1604b250187eSsaisai 		return (ret);
1605b250187eSsaisai 	}
1606b250187eSsaisai 
1607b250187eSsaisai 	/* 'byte_cnt' bytes not present */
1608b250187eSsaisai 	if (ret != byte_cnt) {
1609b250187eSsaisai 		*ispresent = 0;
1610b250187eSsaisai 		return (0);
1611b250187eSsaisai 	}
1612b250187eSsaisai 
1613b250187eSsaisai 	for (i = 0; i < byte_cnt; ++i) {
1614b250187eSsaisai 		if (buf[i] != byte_seq[i]) {
1615b250187eSsaisai 			*ispresent = 0;
1616b250187eSsaisai 			return (0);
1617b250187eSsaisai 		}
1618b250187eSsaisai 	}
1619b250187eSsaisai 	*ispresent = 1;
1620b250187eSsaisai 
1621b250187eSsaisai 	return (0);
1622b250187eSsaisai }
1623b250187eSsaisai 
1624b250187eSsaisai /*
1625b250187eSsaisai  * 16-bit simple internet checksum
1626b250187eSsaisai  */
1627b250187eSsaisai static uint16_t
1628b250187eSsaisai checksum(uint16_t *addr, int32_t count)
1629b250187eSsaisai {
1630b250187eSsaisai 	/*
1631b250187eSsaisai 	 * Compute Internet Checksum for "count" bytes
1632b250187eSsaisai 	 * beginning at location "addr".
1633b250187eSsaisai 	 */
1634b250187eSsaisai 
1635b250187eSsaisai 	register uint32_t	sum = 0;
1636b250187eSsaisai 
1637b250187eSsaisai 	while (count > 1)  {
1638b250187eSsaisai 		/*  This is the inner loop */
1639b250187eSsaisai 		sum += *(unsigned short *)addr++;
1640b250187eSsaisai 		count -= 2;
1641b250187eSsaisai 	}
1642b250187eSsaisai 
1643b250187eSsaisai 	/*  Add left-over byte, if any */
1644b250187eSsaisai 	if (count > 0)
1645b250187eSsaisai 		sum += * (unsigned char *)addr;
1646b250187eSsaisai 
1647b250187eSsaisai 	/* Fold 32-bit sum to 16 bits */
1648b250187eSsaisai 	while (sum >> 16)
1649b250187eSsaisai 		sum = (sum & 0xffff) + (sum >> 16);
1650b250187eSsaisai 
1651b250187eSsaisai 	sum = (~sum) & 0xffff;
1652b250187eSsaisai 	if (sum == 0)
1653b250187eSsaisai 		sum = 0xffff;
1654b250187eSsaisai 
1655b250187eSsaisai 	return (sum);
1656b250187eSsaisai }
1657