xref: /illumos-gate/usr/src/lib/librsc/sparc/mpxu/common/librsc.c (revision 930176a00b697a09f5256ff3d4b1550f8e73c3a6)
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