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