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, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
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#include <fcntl.h>
30#include <unistd.h>
31#include <stdlib.h>
32#include <stdio.h>
33#include <strings.h>
34#include <errno.h>
35
36#include <sys/mman.h>
37#include <sys/pci.h>
38#include <sys/stat.h>
39#include <sys/wait.h>
40
41#include <fcode/private.h>
42#include <fcode/log.h>
43
44#include <fcdriver/fcdriver.h>
45
46static char *pkg_my_args;
47static char fcode_dev[] = "/dev/fcode";
48
49static void
50dot_request(fcode_env_t *env)
51{
52	common_data_t *cdp = env->private;
53
54	log_message(MSG_INFO, "request: cfgadd: %x fc_size: %x unitadd: %s"
55	    " attach: %x args: '%s'\n", cdp->fc.config_address,
56	    cdp->fc.fcode_size, cdp->fc.unit_address, cdp->attach,
57	    pkg_my_args ? pkg_my_args : "<null>");
58}
59
60/*
61 * Get next request from /dev/fcode.
62 */
63int
64fc_get_request(common_data_t *cdp)
65{
66	char c;
67	int nbytes;
68
69	if (cdp->fcode_fd < 0) {
70		log_message(MSG_FATAL, "fc_get_request: fcode_fd not open\n");
71		return (0);
72	}
73
74	if ((nbytes = read(cdp->fcode_fd, &c, sizeof (c))) < 0) {
75		log_perror(MSG_FATAL, "read(%s) failed", fcode_dev);
76		return (0);
77	}
78
79	if (ioctl(cdp->fcode_fd, FC_GET_PARAMETERS, &cdp->fc) < 0) {
80		log_perror(MSG_FATAL, "ioctl(FC_GET_PARAMETERS) failed");
81		return (0);
82	}
83
84	if ((cdp->attach = fc_get_ap(cdp)) == NULL)
85		return (0);
86
87	return (1);
88}
89
90static void
91get_my_args(fcode_env_t *env)
92{
93	common_data_t *cdp = env->private;
94	char buffer[BUFSIZ];
95
96	/*
97	 * Don't get if already set.
98	 */
99	if (pkg_my_args)
100		return;
101
102	if (ioctl(cdp->fcode_fd, FC_GET_MY_ARGS, buffer) < 0) {
103		return;
104	}
105	pkg_my_args = STRDUP(buffer);
106}
107
108static void
109set_my_args(fcode_env_t *env)
110{
111	if (pkg_my_args)
112		FREE(pkg_my_args);
113
114	parse_word(env);
115	pkg_my_args = pop_a_duped_string(env, NULL);
116}
117
118static void
119dot_my_args(fcode_env_t *env)
120{
121	if (pkg_my_args)
122		log_message(MSG_INFO, "%s\n", pkg_my_args);
123	else
124		log_message(MSG_INFO, "NULL\n");
125}
126
127void
128push_my_args(fcode_env_t *env)
129{
130	push_a_string(env, pkg_my_args);
131}
132
133void
134get_fcode_from_device(fcode_env_t *env)
135{
136	common_data_t *cdp = env->private;
137	char *p, *buf;
138	static char func_name[] = "get_fcode_from_device";
139	fc_fcode_info_t fcode_info;
140
141	if (!cdp->fc.fcode_size) {
142		debug_msg(DEBUG_FIND_FCODE, "%s: Fcode zero length\n",
143		    func_name);
144		push_a_string(env, NULL);
145		return;
146	}
147	fcode_info.fcode_size = cdp->fc.fcode_size;
148	fcode_info.fcode_ptr = MALLOC(cdp->fc.fcode_size);
149	if (ioctl(cdp->fcode_fd, FC_GET_FCODE_DATA, &fcode_info) < 0) {
150		log_perror(MSG_FATAL, "ioctl(FC_GET_FCODE_DATA) failed");
151		push_a_string(env, NULL);
152	} else {
153		debug_msg(DEBUG_FIND_FCODE,
154		    "%s: Fcode from device: len: 0x%x\n", func_name,
155		    (int)cdp->fc.fcode_size);
156		PUSH(DS, (fstack_t)fcode_info.fcode_ptr);
157		PUSH(DS, (fstack_t)cdp->fc.fcode_size);
158	}
159}
160
161static void
162save_fcode_to_file(fcode_env_t *env)
163{
164	char *buf, *fname;
165	int len;
166	FILE *fd;
167
168	CHECK_DEPTH(env, 4, "save-fcode-to-file");
169	if ((fname = pop_a_string(env, NULL)) == NULL) {
170		log_message(MSG_DEBUG, "fname?\n");
171		return;
172	}
173	if ((buf = pop_a_string(env, &len)) == NULL) {
174		log_message(MSG_INFO, "buf?\n");
175		return;
176	}
177	if ((fd = fopen(fname, "w")) == NULL) {
178		log_perror(MSG_DEBUG, "Save_fcode_to_file: Can't open '%s'",
179		    fname);
180		return;
181	}
182	log_message(MSG_INFO, "Fcode %p,%x to file '%s'\n", buf, len, fname);
183	fwrite(buf, len, sizeof (char), fd);
184	fclose(fd);
185}
186
187void
188exec_fcode_builtin_method(fcode_env_t *env)
189{
190	fstack_t d;
191	char *method;
192	extern void exec_parent_method(fcode_env_t *);
193	extern void exec_builtin_driver(fcode_env_t *);
194
195	method = (char *)DS[-1];
196	exec_parent_method(env);
197	d = POP(DS);
198	if (d) {
199		debug_msg(DEBUG_FIND_FCODE, "builtin-driver: %s -> %s found\n",
200		    method, (char *)DS[-1]);
201		exec_builtin_driver(env);
202		debug_msg(DEBUG_FIND_FCODE, "builtin-driver-exec: %p %x\n",
203		    (char *)DS[-1], (int)TOS);
204	} else {
205		debug_msg(DEBUG_FIND_FCODE, "builtin-driver: %s not found\n",
206		    method);
207		PUSH(DS, FALSE);
208	}
209}
210
211void
212get_fcode_from_filesystem(fcode_env_t *env)
213{
214	fstack_t d;
215	char *method, *fc_name, *path;
216	extern void exec_parent_method(fcode_env_t *);
217	static char fname[] = "get-fcode-from-filesystem";
218
219	method = (char *)DS[-1];
220	exec_parent_method(env);
221	d = POP(DS);
222	if (d) {
223		fc_name = pop_a_string(env, NULL);
224		debug_msg(DEBUG_FIND_FCODE, "%s: %s -> %s found\n", fname,
225		    method, fc_name);
226		if ((path = search_for_fcode_file(env, fc_name)) != NULL) {
227			debug_msg(DEBUG_FIND_FCODE, "%s: file: %s FOUND\n",
228			    fname, path);
229			push_a_string(env, path);
230			load_file(env);
231		} else {
232			debug_msg(DEBUG_FIND_FCODE, "%s: file '%s' not found\n",
233			    fname, fc_name);
234			PUSH(DS, FALSE);
235		}
236	} else {
237		debug_msg(DEBUG_FIND_FCODE, "%s: method '%s' not found\n",
238		    fname, method);
239		PUSH(DS, FALSE);
240	}
241}
242
243/*
244 * Looks for "device-id" and "class-id" methods in parent, if there,
245 * executes them to get "builtin drivers" file name or method name, then
246 * executes the builtin-driver method.  If both those fail, try getting the
247 * fcode from the device.  Note that we sleaze resetting the data stack.
248 * This would be cleaner if we had a way to do the equivalent of "catch/throw"
249 * from within C code.
250 */
251void
252find_fcode(fcode_env_t *env)
253{
254	fstack_t *dp = env->ds;
255	common_data_t *cdp = env->private;
256	static char func_name[] = "find_fcode";
257	int error;
258
259	my_unit(env);
260	push_a_string(env, "device-id");
261	get_fcode_from_filesystem(env);
262	if (TOS) {
263		debug_msg(DEBUG_FIND_FCODE, "%s: FS dev-id: len: 0x%x\n",
264		    func_name, TOS);
265		return;
266	}
267
268	env->ds = dp;
269	my_unit(env);
270	push_a_string(env, "class-id");
271	get_fcode_from_filesystem(env);
272	if (TOS) {
273		debug_msg(DEBUG_FIND_FCODE, "%s: FS cls-id len: 0x%x\n",
274		    func_name, TOS);
275		return;
276	}
277
278	env->ds = dp;
279	get_fcode_from_device(env);
280	if (TOS) {
281		debug_msg(DEBUG_FIND_FCODE, "%s: DEV fcode len: 0x%x\n",
282		    func_name, TOS);
283		return;
284	}
285
286	env->ds = dp;
287	my_unit(env);
288	push_a_string(env, "device-id");
289	exec_fcode_builtin_method(env);
290	if (TOS) {
291		debug_msg(DEBUG_FIND_FCODE, "%s: dropin dev-id len: 0x%x\n",
292		    func_name, TOS);
293		return;
294	}
295
296	env->ds = dp;
297	my_unit(env);
298	push_a_string(env, "class-id");
299	exec_fcode_builtin_method(env);
300	if (TOS) {
301		debug_msg(DEBUG_FIND_FCODE, "%s: dropin cls-id len: 0x%x\n",
302		    func_name, TOS);
303		return;
304	}
305
306	debug_msg(DEBUG_FIND_FCODE, "%s: not found\n", func_name);
307	error = FC_NO_FCODE;
308	if (ioctl(cdp->fcode_fd, FC_SET_FCODE_ERROR, &error) < 0) {
309		log_perror(MSG_FATAL, "ioctl(FC_SET_FCODE_ERROR) failed");
310		return;
311	}
312}
313
314int
315open_fcode_dev(fcode_env_t *env)
316{
317	common_data_t *cdp = env->private;
318
319	if ((cdp->fcode_fd = open(fcode_dev, O_RDONLY)) < 0)
320		log_perror(MSG_ERROR, "Can't open '%s'", fcode_dev);
321	return (cdp->fcode_fd >= 0);
322}
323
324static void
325get_request(fcode_env_t *env)
326{
327	common_data_t *cdp = env->private;
328
329	if (cdp->fcode_fd >= 0)
330		close(cdp->fcode_fd);
331	if (!open_fcode_dev(env))
332		exit(1);
333	if (!fc_get_request(cdp)) {
334		log_message(MSG_FATAL, "fc_get_request failed\n");
335		exit(1);
336	}
337
338	get_my_args(env);
339
340	DEBUGF(UPLOAD, dot_request(env));
341}
342
343/*
344 * invoked from efdaemon, /dev/fcode event has been read and /dev/fcode opened
345 * file descriptor is fd 0.
346 */
347static void
348get_efdaemon_request(fcode_env_t *env)
349{
350	common_data_t *cdp = env->private;
351
352	cdp->fcode_fd = 0;
353	if (ioctl(cdp->fcode_fd, FC_GET_PARAMETERS, &cdp->fc) < 0) {
354		log_perror(MSG_FATAL, "ioctl(FC_GET_PARAMETERS) failed");
355		exit(1);
356	}
357
358	if ((cdp->attach = fc_get_ap(cdp)) == NULL)
359		exit(1);
360
361	get_my_args(env);
362
363	DEBUGF(UPLOAD, dot_request(env));
364}
365
366static void
367process_request(fcode_env_t *env)
368{
369	common_data_t *cdp = env->private;
370	fstack_t fcode_len;
371	char *path;
372
373	build_tree(env);
374	install_builtin_nodes(env);
375	push_my_args(env);
376	push_a_string(env, cdp->fc.unit_address);
377	if ((path = get_path(env, env->attachment_pt)) == NULL) {
378		log_message(MSG_FATAL, "Can't get_path of"
379		    " attachment_pt %p\n", env->attachment_pt);
380		exit(1);
381	}
382	debug_msg(DEBUG_UPLOAD, "Attach Point: %s\n", path);
383
384	push_a_string(env, path);
385	begin_package(env);
386	find_fcode(env);
387	fcode_len = POP(DS);
388	if (!fcode_len) {
389		(void) POP(DS);
390		debug_msg(DEBUG_UPLOAD, "Zero length Fcode\n");
391		return;
392	}
393
394	debug_msg(DEBUG_UPLOAD, "byte-load fcode_len: %x\n",
395	    fcode_len);
396
397	PUSH(DS, 1);
398	byte_load(env);
399	end_package(env);
400	upload_nodes(env);
401	validate_nodes(env);
402	debug_msg(DEBUG_UPLOAD, "Upload Done\n");
403}
404
405static void
406finish_request(fcode_env_t *env)
407{
408	common_data_t *cdp = env->private;
409
410	close(cdp->fcode_fd);
411}
412
413/*
414 * Non-daemon "do-request", for debugging
415 */
416static void
417do_request(fcode_env_t *env)
418{
419	get_request(env);
420	process_request(env);
421	finish_request(env);
422}
423
424/*
425 * This process one request from efdaemon, we know that /dev/fcode is already
426 * open and passed in fd0 (stdin).  If it's not, we throw up our hands.
427 */
428void
429run_one_efdaemon_request(fcode_env_t *env)
430{
431	get_efdaemon_request(env);
432	process_request(env);
433	finish_request(env);
434	exit(0);
435}
436
437void
438probe_space(fcode_env_t *env)
439{
440	fc_cell_t cfg = 0;
441	int error;
442
443	error = fc_run_priv(env->private, FC_PROBE_SPACE, 0, 1, &cfg);
444	if (error)
445		throw_from_fclib(env, 1, "FC_PROBE_SPACE failed\n");
446	PUSH(DS, fc_cell2uint32_t(cfg));
447}
448
449#pragma init(_init)
450
451static void
452_init(void)
453{
454	fcode_env_t *env = initial_env;
455
456	ASSERT(env);
457	NOTICE;
458
459	FORTH(0,	"get-fcode-from-device",	get_fcode_from_device);
460	FORTH(0,	"save-fcode-to-file",		save_fcode_to_file);
461	FORTH(0,	"get-my-args",			get_my_args);
462	FORTH(0,	"set-my-args",			set_my_args);
463	FORTH(0,	".my-args",			dot_my_args);
464	FORTH(0,	".request",			dot_request);
465	FORTH(0,	"get-request",			get_request);
466	FORTH(0,	"process-request",		process_request);
467	FORTH(0,	"finish-request",		finish_request);
468	FORTH(0,	"do-request",			do_request);
469	FORTH(0,	"find-fcode",			find_fcode);
470	FORTH(0,	"exec-fcode-builtin-method", exec_fcode_builtin_method);
471	FORTH(0,	"run-one-efdaemon-request",  run_one_efdaemon_request);
472	FORTH(0,	"get-efdaemon-request",		get_efdaemon_request);
473	FORTH(0,	"probe-space",			probe_space);
474}
475