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