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