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