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