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
rscp_init(void)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
rscp_send_recv(rscp_msg_t * req,rscp_msg_t * resp,struct timespec * timeout)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 *
rsc_lookup_rr_table(req_resp_table_t * rr_table,int cnt,rsci8 type)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
rsc_check_unsupported_cmd(rsci8 type)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
rsc_cmd_response_guaranteed(rsci8 type)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
rsc_nmi(void)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
rscp_register_bpmsg_cb(rscp_bpmsg_cb_t * cb)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
rscp_unregister_bpmsg_cb(rscp_bpmsg_cb_t * cb)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
rscp_send_bpmsg(bp_msg_t * bpmsg)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
rsc_raw_write(char * buf,int nbytes)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
rscp_start(void)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
rscp_send(rscp_msg_t * msgp)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
rscp_recv(rscp_msg_t * msgp,struct timespec * timeout)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
rscp_free_msg(rscp_msg_t * msgp)705 rscp_free_msg(rscp_msg_t *msgp)
706 {
707 if (rsc_fd < 0)
708 return (EBADF);
709
710 return (0);
711 }
712