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
_init(void)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
_fini(void)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
_info(struct modinfo * modinfop)341b250187eSsaisai _info(struct modinfo *modinfop)
342b250187eSsaisai {
343b250187eSsaisai return (mod_info(&modlinkage, modinfop));
344b250187eSsaisai }
345b250187eSsaisai
346b250187eSsaisai
347b250187eSsaisai /* ARGSUSED */
348b250187eSsaisai static int
tsalarm_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** result)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
tsalarm_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)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
tsalarm_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)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
tsalarm_open(dev_t * devp,int flag,int otyp,cred_t * credp)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
tsalarm_close(dev_t dev,int flag,int otyp,cred_t * credp)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
tsalarm_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)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
glvc_alarm_get(int alarm_type,int * alarm_state,tsalarm_softc_t * sc)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
glvc_alarm_set(int alarm_type,int new_state,tsalarm_softc_t * sc)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
tsal_pcp_send_recv(tsalarm_softc_t * sc,tsal_pcp_msg_t * req_msg,tsal_pcp_msg_t * resp_msg,uint32_t timeout)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
tsal_pcp_io_op(tsalarm_softc_t * sc,void * buf,int byte_cnt,int io_op)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
tsal_pcp_peek(tsalarm_softc_t * sc,uint8_t * buf,int bytes_cnt)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
tsal_pcp_write(tsalarm_softc_t * sc,uint8_t * buf,int byte_cnt)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
tsal_pcp_read(tsalarm_softc_t * sc,uint8_t * buf,int byte_cnt)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
tsal_pcp_peek_read(tsalarm_softc_t * sc,uint8_t * buf,int byte_cnt)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
tsal_pcp_send_req_msg_hdr(tsalarm_softc_t * sc,tsal_pcp_req_msg_hdr_t * req_hdr)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
tsal_pcp_recv_resp_msg_hdr(tsalarm_softc_t * sc,tsal_pcp_resp_msg_hdr_t * resp_hdr)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
tsal_pcp_get_xid(tsalarm_softc_t * sc)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
tsal_pcp_frame_error_handle(tsalarm_softc_t * sc)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
check_magic_byte_presence(tsalarm_softc_t * sc,int byte_cnt,uint8_t * byte_seq,int * ispresent)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
checksum(uint16_t * addr,int32_t count)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