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 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * ENXS platform-specific functions 31 */ 32 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <unistd.h> 36 #include <string.h> 37 #include <assert.h> 38 #include <fcntl.h> 39 #include <errno.h> 40 #include <sys/types.h> 41 #include <sys/stat.h> 42 43 #include "librsc.h" 44 45 /* rmcadm driver file descriptor */ 46 static int rsc_fd = -1; 47 48 /* 49 * librsc receive buffer - it is used as temporary buffer to store replies 50 * from the remote side 51 */ 52 53 static uchar_t rsc_rx_buffer[RSC_MAX_RX_BUFFER]; 54 static int rsc_rx_resp_len = 0; 55 static int rsc_rx_error = 0; 56 static rsci8 rsc_rx_resp_type = 0; 57 58 /* 59 * Registered boot-protocol message callback routine. This routine will be 60 * called whenever a boot protocol message is received. 61 */ 62 static rscp_bpmsg_cb_t *bpmsg_cb; 63 64 65 66 /* lookup table to match request and response . This is in order to support */ 67 /* obsolete functions (rscp_send, rscp_recv) */ 68 69 static req_resp_table_t rr_table[] = { 70 71 { DP_GET_DATE_TIME, DP_GET_DATE_TIME_R, 72 sizeof (dp_get_date_time_r_t), RR_TIMEOUT }, 73 { DP_SET_DATE_TIME, DP_SET_DATE_TIME_R, 74 sizeof (dp_set_date_time_r_t), RR_TIMEOUT }, 75 { DP_GET_EVENT_LOG, DP_GET_EVENT_LOG_R, 76 sizeof (dp_get_event_log_r_t), RR_TIMEOUT }, 77 { DP_MODEM_CONNECT, DP_MODEM_CONNECT_R, 78 sizeof (dp_modem_connect_r_t), RR_TIMEOUT }, 79 { DP_MODEM_DISCONNECT, DP_MODEM_DISCONNECT_R, 80 sizeof (dp_modem_disconnect_r_t), RR_TIMEOUT }, 81 { DP_SEND_ALERT, DP_SEND_ALERT_R, 82 sizeof (dp_send_alert_r_t), RR_TIMEOUT }, 83 { DP_SET_CFGVAR, DP_SET_CFGVAR_R, 84 sizeof (dp_set_cfgvar_r_t), RR_TIMEOUT }, 85 { DP_GET_CFGVAR, DP_GET_CFGVAR_R, 86 sizeof (dp_get_cfgvar_r_t), RR_TIMEOUT }, 87 { DP_GET_CFGVAR_NAME, DP_GET_CFGVAR_NAME_R, 88 sizeof (dp_get_cfgvar_name_r_t), RR_TIMEOUT }, 89 { DP_GET_NETWORK_CFG, DP_GET_NETWORK_CFG_R, 90 sizeof (dp_get_network_cfg_r_t), RR_TIMEOUT }, 91 { DP_RSC_STATUS, DP_RSC_STATUS_R, 92 sizeof (dp_rsc_status_r_t), RR_TIMEOUT }, 93 { DP_USER_ADM, DP_USER_ADM_R, 94 sizeof (dp_user_adm_r_t), RR_SEPROM_TIMEOUT}, 95 { DP_RESET_RSC, DP_NULL_MSG, 96 0, 1 }, 97 { DP_GET_CONSOLE_LOG, DP_GET_CONSOLE_LOG_R, 98 sizeof (dp_get_console_log_r_t), RR_TIMEOUT }, 99 { DP_GET_CONFIG_LOG, DP_GET_CONFIG_LOG_R, 100 sizeof (dp_get_config_log_r_t), RR_TIMEOUT }, 101 { DP_GET_EVENT_LOG2, DP_GET_EVENT_LOG2_R, 102 sizeof (dp_get_event_log2_r_t), RR_TIMEOUT }, 103 }; 104 105 static const int rr_table_cnt = sizeof (rr_table) / sizeof (rr_table[0]); 106 107 108 /* lookup table to get timeout value for BP cmd reply. This is in order to */ 109 /* support obsolete functions (rscp_send_bpmsg, rsc_raw_write) */ 110 111 static req_resp_table_t rr_bp_table[] = { 112 113 { BP_OBP_BOOTINIT, NULL, sizeof (bp_msg_t), 114 RR_BOOT_INIT_TIMEOUT }, 115 { BP_OBP_RESET, NULL, sizeof (bp_msg_t), 116 RR_BOOT_RESET_TIMEOUT } 117 }; 118 119 static const int rr_bp_table_cnt = 120 sizeof (rr_bp_table) / sizeof (rr_bp_table[0]); 121 122 static rsci8 unsupported_cmds[] = { DP_SET_DATE_TIME }; 123 124 static int unsupported_cmds_cnt = sizeof (unsupported_cmds) / 125 sizeof (unsupported_cmds[0]); 126 127 /* 128 * Protocol version number, used to determine whether ALOM will 129 * time out on unknown commands. 130 */ 131 static int sdp_version = -1; 132 133 /* function prototypes */ 134 135 static req_resp_table_t *rsc_lookup_rr_table(req_resp_table_t *, int, rsci8); 136 137 static int rsc_check_unsupported_cmd(rsci8); 138 139 static int rsc_cmd_response_guaranteed(rsci8); 140 141 /* 142 * Initialize the generic librsc data protocol routines. basically, it 143 * open the rmcadm (pseudo) device and initialize data 144 */ 145 int 146 rscp_init(void) 147 { 148 rscp_msg_t request, response; 149 dp_get_sdp_version_r_t version_msg; 150 151 /* 152 * 'erase' the rx buffer 153 */ 154 (void) memset(rsc_rx_buffer, 0, sizeof (RSC_MAX_RX_BUFFER)); 155 rsc_rx_resp_len = 0; 156 rsc_rx_error = 0; 157 rsc_rx_resp_type = DP_NULL_MSG; 158 159 /* 160 * open rmcadm driver 161 */ 162 if ((rsc_fd = open(RSC_RMCADM_DRV, O_RDWR)) < 0) { 163 #ifdef DEBUG 164 printf("rscp_init: Error opening %s, error code = %d\n", 165 RSC_RMCADM_DRV, errno); 166 #endif 167 return (errno); 168 } 169 170 /* 171 * Fetch the protocol version number in use between the host 172 * and ALOM. 173 */ 174 request.type = DP_GET_SDP_VERSION; 175 request.len = 0; 176 request.data = 0; 177 178 response.type = DP_GET_SDP_VERSION_R; 179 response.len = sizeof (version_msg); 180 response.data = (caddr_t)&version_msg; 181 182 if ((errno = rscp_send_recv(&request, &response, 0)) != 0) 183 return (errno); 184 185 sdp_version = version_msg.version; 186 187 #ifdef DEBUG 188 printf("rscp_init: sdp version number is %d\n", sdp_version); 189 #endif 190 191 return (0); 192 } 193 194 /* 195 * send/receive interface: this is the new interface where application 196 * (currently scadm, SunVTS) send a request and wait for a reply in a 197 * single call. If a response is not required (resp=NULL), the function 198 * will only return the status of the request (whether it has been successfully 199 * or not). 200 */ 201 int 202 rscp_send_recv(rscp_msg_t *req, rscp_msg_t *resp, struct timespec *timeout) 203 { 204 rmcadm_request_response_t rr; 205 rmcadm_msg_t *rr_req = &rr.req; 206 rmcadm_msg_t *rr_resp = &rr.resp; 207 208 if (rsc_fd < 0) 209 return (EBADF); 210 211 /* 212 * the request is required, it should not be NULL! 213 */ 214 if (req == NULL) 215 return (EINVAL); 216 217 /* 218 * Check if the command is actually supported 219 * if not, return an error 220 */ 221 if (rsc_check_unsupported_cmd(req->type) != 0) 222 return (ENOTSUP); 223 224 /* 225 * Check if this command will generate a response and if it will not, 226 * return an error. 227 */ 228 if (!rsc_cmd_response_guaranteed(req->type)) 229 return (ENOTSUP); 230 231 rr_req->msg_type = req->type; 232 rr_req->msg_len = req->len; 233 rr_req->msg_buf = (caddr_t)req->data; 234 235 if (resp != NULL) { 236 rr_resp->msg_type = resp->type; 237 rr_resp->msg_len = resp->len; 238 rr_resp->msg_buf = (caddr_t)resp->data; 239 rr_resp->msg_bytes = 0; 240 } else { 241 rr_resp->msg_type = DP_NULL_MSG; 242 rr_resp->msg_buf = (caddr_t)NULL; 243 rr_resp->msg_len = 0; 244 rr_resp->msg_bytes = 0; 245 } 246 247 if (timeout == NULL) { 248 rr.wait_time = RR_TIMEOUT; 249 } else { 250 rr.wait_time = timeout->tv_sec * 1000 + 251 timeout->tv_nsec / 1000000; 252 } 253 rr.status = 0; 254 255 if (ioctl(rsc_fd, RMCADM_REQUEST_RESPONSE, &rr) < 0) { 256 #ifdef DEBUG 257 printf("rscp_send_recv: req. failed, status=%d errno=%d\n", 258 rr_req->msg_type, rr.status, errno); 259 #endif 260 return (errno); 261 } 262 263 return (0); 264 } 265 266 /* 267 * function used to look up at the request/response table. Given a request 268 * type, will return a record which provides the following information: 269 * response expected and a timeout value 270 */ 271 static req_resp_table_t * 272 rsc_lookup_rr_table(req_resp_table_t *rr_table, int cnt, rsci8 type) 273 { 274 int i; 275 276 #ifdef DEBUG 277 printf("lookup for type %x, count %d\n", type, cnt); 278 #endif 279 280 for (i = 0; i < cnt; i++) 281 if (rr_table[i].req_type == type) { 282 return (rr_table + i); 283 } 284 285 return (NULL); 286 } 287 288 /* 289 * function to check if a message type is in the list of unsupported commands 290 * If so, will return 1. 291 */ 292 static int 293 rsc_check_unsupported_cmd(rsci8 type) 294 { 295 int i; 296 297 for (i = 0; i < unsupported_cmds_cnt; i++) 298 if (unsupported_cmds[i] == type) { 299 return (1); 300 } 301 302 return (0); 303 } 304 305 /* 306 * Returns 1 if ALOM will generate a response to the given command code, 307 * otherwise it returns 0. If a command is not in the following list, 308 * and the protocol version is 2 or less, then ALOM will not generate 309 * a response to the command. This causes the driver to time out, 310 * and we want to avoid that situation. 311 */ 312 static int 313 rsc_cmd_response_guaranteed(rsci8 type) 314 { 315 switch (type) { 316 case DP_GET_ALARM_STATE: 317 case DP_GET_CFGVAR: 318 case DP_GET_CFGVAR_NAME: 319 case DP_GET_CIRCUIT_BRKS: 320 case DP_GET_DATE_TIME: 321 case DP_GET_DEVICE: 322 case DP_GET_EVENT_LOG: 323 case DP_GET_FAN_STATUS: 324 case DP_GET_FRU_STATUS: 325 case DP_GET_HANDLE: 326 case DP_GET_HANDLE_NAME: 327 case DP_GET_LED_STATE: 328 case DP_GET_NETWORK_CFG: 329 case DP_GET_PCMCIA_INFO: 330 case DP_GET_PSU_STATUS: 331 case DP_GET_SDP_VERSION: 332 case DP_GET_SYSINFO: 333 case DP_GET_TEMP: 334 case DP_GET_TEMPERATURES: 335 case DP_GET_TICKCNT: 336 case DP_GET_TOD_CLOCK: 337 case DP_GET_USER_WATCHDOG: 338 case DP_GET_VOLTS: 339 case DP_MODEM_CONNECT: 340 case DP_MODEM_DATA: 341 case DP_MODEM_DISCONNECT: 342 case DP_RESET_RSC: 343 case DP_RMC_EVENTS: 344 case DP_RSC_STATUS: 345 case DP_RUN_TEST: 346 case DP_SEND_ALERT: 347 case DP_SET_ALARM_STATE: 348 case DP_SET_CFGVAR: 349 case DP_SET_CPU_SIGNATURE: 350 case DP_SET_DATE_TIME: 351 case DP_SET_DEFAULT_CFG: 352 case DP_SET_HOST_WATCHDOG: 353 case DP_SET_LED_STATE: 354 case DP_SET_USER_WATCHDOG: 355 case DP_UPDATE_FLASH: 356 case DP_USER_ADM: 357 return (1); 358 default: 359 return (sdp_version >= SDP_RESPONDS_TO_ALL_CMDS); 360 } 361 } 362 363 /* 364 * RSC hard reset. Returns 0 on success, non-zero on error. 365 */ 366 int 367 rsc_nmi(void) 368 { 369 if (rsc_fd < 0) 370 return (EBADF); 371 372 if (ioctl(rsc_fd, RMCADM_RESET_SP, NULL) < 0) 373 return (errno); 374 375 return (0); 376 } 377 378 /* 379 * functions used (exclusively) for the firmware download 380 */ 381 382 /* 383 * Call this routine to register a callback that will be called by the 384 * generic data protocol routines when a boot protocol message is 385 * received. Only one of these routines may be registered at a time. 386 * Note that receiving a boot protocol message has the effect of 387 * re-initializing the data protocol. Returns 0 on success, or non- 388 * zero on failure. 389 */ 390 int 391 rscp_register_bpmsg_cb(rscp_bpmsg_cb_t *cb) 392 { 393 if (rsc_fd < 0) 394 return (EBADF); 395 396 if (bpmsg_cb == NULL) { 397 bpmsg_cb = cb; 398 return (0); 399 } else { 400 return (EALREADY); 401 } 402 } 403 404 /* 405 * This routine un-registers a boot protocol message callback. 406 */ 407 int 408 rscp_unregister_bpmsg_cb(rscp_bpmsg_cb_t *cb) 409 { 410 if (rsc_fd < 0) 411 return (EBADF); 412 413 if (bpmsg_cb == cb) { 414 bpmsg_cb = NULL; 415 return (0); 416 } else { 417 return (EINPROGRESS); 418 } 419 } 420 421 /* 422 * Call this routine to send a boot protocol message. 423 */ 424 void 425 rscp_send_bpmsg(bp_msg_t *bpmsg) 426 { 427 rmcadm_request_response_t rr_bp; 428 rmcadm_msg_t *req_bp = &rr_bp.req; 429 rmcadm_msg_t *resp_bp = &rr_bp.resp; 430 req_resp_table_t *rr_bp_item; 431 bp_msg_t bpmsg_reply; 432 433 if (rsc_fd < 0 || bpmsg == NULL) 434 return; 435 436 /* 437 * get the timeout value 438 */ 439 if ((rr_bp_item = rsc_lookup_rr_table(rr_bp_table, rr_bp_table_cnt, 440 bpmsg->cmd)) != NULL) { 441 442 rr_bp.wait_time = rr_bp_item->timeout; 443 444 } else { 445 446 rr_bp.wait_time = RR_BP_TIMEOUT; 447 } 448 449 rr_bp.status = 0; 450 451 req_bp->msg_len = sizeof (bp_msg_t); 452 req_bp->msg_buf = (caddr_t)bpmsg; 453 454 if (rr_bp.wait_time == 0) { 455 resp_bp->msg_buf = (caddr_t)NULL; 456 } else { 457 resp_bp->msg_len = sizeof (bp_msg_t); 458 resp_bp->msg_buf = (caddr_t)&bpmsg_reply; 459 } 460 461 #ifdef DEBUG 462 printf("send BP cmd %x, expect reply %x/%d\n", 463 bpmsg->cmd, resp_bp->msg_buf, resp_bp->msg_len); 464 #endif 465 if (ioctl(rsc_fd, RMCADM_REQUEST_RESPONSE_BP, &rr_bp) < 0) { 466 #ifdef DEBUG 467 printf("rscp_send_bpmsg: BP cmd %x failed status=%d " 468 "errno=%d\n", bpmsg->cmd, rr_bp.status, errno); 469 #endif 470 return; 471 } 472 473 #ifdef DEBUG 474 printf("got BP reply type=%x,%x,%x\n", 475 bpmsg_reply.cmd, bpmsg_reply.dat1, bpmsg_reply.dat2); 476 #endif 477 478 /* 479 * reply received. call the registered callback (if any) 480 */ 481 if (bpmsg_cb != NULL && resp_bp->msg_buf != NULL) 482 bpmsg_cb(&bpmsg_reply); 483 } 484 485 /* 486 * Write raw characters to the RSC control device. Returns 0 on success, 487 * non-zero on error. 488 */ 489 int 490 rsc_raw_write(char *buf, int nbytes) 491 { 492 rmcadm_send_srecord_bp_t srec_bp; 493 bp_msg_t bpmsg_reply; 494 495 if (rsc_fd < 0) 496 return (EBADF); 497 498 srec_bp.data_len = (uint_t)nbytes; 499 srec_bp.data_buf = (caddr_t)buf; 500 srec_bp.resp_bp.msg_len = sizeof (bp_msg_t); 501 srec_bp.resp_bp.msg_buf = (caddr_t)&bpmsg_reply; 502 srec_bp.wait_time = RR_BOOT_LOAD_TIMEOUT; 503 srec_bp.status = 0; 504 505 #ifdef DEBUG 506 printf("send srecord BP len=%d\n", nbytes); 507 #endif 508 if (ioctl(rsc_fd, RMCADM_SEND_SRECORD_BP, &srec_bp) < 0) { 509 #ifdef DEBUG 510 printf("rsc_raw_write: failed. status=%d ioctl error=%d\n", 511 srec_bp.status, errno); 512 #endif 513 return (errno); 514 } 515 516 #ifdef DEBUG 517 printf("got BP reply type=%x\n", bpmsg_reply.cmd); 518 #endif 519 520 /* 521 * reply received. call the registered callback (if any) 522 */ 523 if (bpmsg_cb != NULL) 524 bpmsg_cb(&bpmsg_reply); 525 526 return (0); 527 } 528 529 /* 530 * obsolete functions provided for backward compatibility 531 */ 532 533 /* 534 * This function is obsolete and it is provided for backward compatibility. 535 * (no-op function). It was used to start up the data protocol. low-level 536 * protocol has moved to the kernel and the rmc_comm driver is responsible 537 * for setting up the data protocol. 538 * (obsolete) 539 */ 540 int 541 rscp_start(void) 542 { 543 if (rsc_fd < 0) 544 return (EBADF); 545 546 return (0); 547 } 548 549 /* 550 * This function is obsolete and it is provided for backward compatibility. 551 * Previously, rscp_send() and rscp_recv() where used to send a request and 552 * read a reply respectively. Now, rscp_send_recv() should be used instead 553 * (request/response in one call). 554 * 555 * This is used to send a message by making an RMCADM_REQUEST_RESPONSE ioctl 556 * call. A lookup table (rr_table) is used to find out the expected reply 557 * (if any) and the timeout value for a message to be sent. The reply is then 558 * stored in a buffer (rsc_rx_buffer) to be returned by calling rscp_recv() 559 */ 560 int 561 rscp_send(rscp_msg_t *msgp) 562 { 563 rmcadm_request_response_t rr; 564 rmcadm_msg_t *req = &rr.req; 565 rmcadm_msg_t *resp = &rr.resp; 566 req_resp_table_t *rr_item; 567 568 if (rsc_fd < 0) 569 return (EBADF); 570 571 /* 572 * sanity check 573 */ 574 if (msgp == NULL) 575 return (EINVAL); 576 577 /* 578 * Check if the command is actually supported 579 * if not, return an error 580 */ 581 if (rsc_check_unsupported_cmd(msgp->type) != 0) 582 return (ENOTSUP); 583 584 /* 585 * Check if this command will generate a response and if it will not, 586 * return an error. 587 */ 588 if (!rsc_cmd_response_guaranteed(msgp->type)) 589 return (ENOTSUP); 590 591 /* 592 * init rx buffer 593 */ 594 rsc_rx_resp_len = 0; 595 rsc_rx_error = 0; 596 597 req->msg_type = msgp->type; 598 req->msg_len = msgp->len; 599 req->msg_buf = msgp->data; 600 601 if ((rr_item = rsc_lookup_rr_table(rr_table, rr_table_cnt, 602 msgp->type)) != NULL) { 603 resp->msg_type = rr_item->resp_type; 604 if (rr_item->resp_type == DP_NULL_MSG) { 605 /* 606 * no reply expected. so, no reply buffer needed 607 * (set to NULL) 608 */ 609 resp->msg_len = 0; 610 resp->msg_buf = (caddr_t)NULL; 611 } else { 612 resp->msg_len = RSC_MAX_RX_BUFFER; 613 resp->msg_buf = (caddr_t)rsc_rx_buffer; 614 } 615 616 rr.wait_time = rr_item->timeout; 617 rsc_rx_resp_type = rr_item->resp_type; 618 } else { 619 return (ENOTSUP); 620 } 621 rr.status = 0; 622 623 #ifdef DEBUG 624 printf("request/response %x/%x\n", req->msg_type, resp->msg_type); 625 #endif 626 if (ioctl(rsc_fd, RMCADM_REQUEST_RESPONSE, &rr) < 0) { 627 #ifdef DEBUG 628 printf("rscp_send: req %x failed, status=%d errno=%d\n", 629 rr.req.msg_type, rr.status, errno); 630 #endif 631 rsc_rx_error = errno; 632 633 return (errno); 634 } 635 636 /* 637 * reply received. get the number of bytes effectively returned 638 */ 639 rsc_rx_resp_len = resp->msg_bytes; 640 rsc_rx_resp_type = resp->msg_type; 641 642 #ifdef DEBUG 643 printf("got reply type=%x len=%d\n", rsc_rx_resp_type, rsc_rx_resp_len); 644 #endif 645 646 return (0); 647 } 648 649 /* 650 * This function is obsolete and it is provided for backward compatibility 651 * Previously, rscp_send() and rscp_recv() where used to send a request and 652 * read a reply repectively. Now, rscp_send_recv() should be used instead 653 * (request/response in one call). 654 * 655 * This function returns the reply received when a request was previously sent 656 * using the rscp_send() function (stored in the rsc_rx_buffer buffer). If a 657 * reply was not received, then an error is returned. 658 * 659 * timeout parameter is declared for backward compatibility but it is not used. 660 */ 661 /*ARGSUSED*/ 662 int 663 rscp_recv(rscp_msg_t *msgp, struct timespec *timeout) 664 { 665 int err = 0; 666 667 if (rsc_fd < 0) 668 return (EBADF); 669 670 /* 671 * sanity check 672 */ 673 if (msgp == NULL) 674 return (EINVAL); 675 676 if (rsc_rx_error < 0) { 677 msgp->type = DP_NULL_MSG; 678 msgp->len = 0; 679 msgp->data = NULL; 680 681 err = rsc_rx_error; 682 683 } else { 684 msgp->type = rsc_rx_resp_type; 685 msgp->len = rsc_rx_resp_len; 686 msgp->data = rsc_rx_buffer; 687 } 688 689 #ifdef DEBUG 690 printf("read reply. type=%x, err=%d\n", msgp->type, err); 691 #endif 692 693 rsc_rx_resp_len = 0; 694 rsc_rx_error = 0; 695 rsc_rx_resp_type = DP_NULL_MSG; 696 697 return (err); 698 } 699 700 /* 701 * used to free up a (received) message. no-op function 702 */ 703 /*ARGSUSED*/ 704 int 705 rscp_free_msg(rscp_msg_t *msgp) 706 { 707 if (rsc_fd < 0) 708 return (EBADF); 709 710 return (0); 711 } 712