summaryrefslogtreecommitdiff
path: root/usr/src/uts/sun4/sys/fcode.h
blob: 30d83bee1aa3ba83ad4f554c628ec4ef4ef32061 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#ifndef	_SYS_FCODE_H
#define	_SYS_FCODE_H

#pragma ident	"%Z%%M%	%I%	%E% SMI"

#include <sys/sysmacros.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/fc_plat.h>
#include <sys/pci.h>

#ifdef	__cplusplus
extern "C" {
#endif

/*
 * The FCode driver presents a private interface to the fcode
 * user level interpreter.  This interface is subject to change
 * at any time and is only provided for use by the fcode interpreter.
 *
 * The user program opens the device, causing a new instance of
 * the driver to be cloned.  This instance is specific to a specific
 * instance of a new device managed by the kernel and driver framework.
 *
 * The interpreter does an FC_GET_PARAMETERS ioctl to get the fcode
 * length, which can be mmap-ed (at offset 0) to provide access to a copy
 * of the device's fcode.
 *
 * The interpreter uses the FC_RUN_PRIV ioctl to request privileged
 * operations to be run by the driver.
 *
 * The interpreter sends an FC_VALIDATE ioctl to notify the
 * driver that it's done interpreting FCode to signify a normal
 * ending sequence when the interpreter later closes the device.
 * This way the driver can easily distinguish between the user
 * level interpreter failing and finishing normally, thus validating
 * the interpreters actions and the state it downloads to the driver.
 * The 'arg' value in the FC_VALIDATE ioctl is ignored, there
 * are no arguments to this ioctl.
 */

#define	FCIOC			(0xfc<<8)
#define	FC_GET_PARAMETERS	(FCIOC | 1)
#define	FC_RUN_PRIV		(FCIOC | 2)
#define	FC_VALIDATE		(FCIOC | 3)
#define	FC_GET_MY_ARGS		(FCIOC | 4)
#define	FC_GET_FCODE_DATA	(FCIOC | 5)

#define	FC_GET_MY_ARGS_BUFLEN	256	/* Max my-args length */

/*
 * FC_GET_PARAMETERS: Expected as the first ioctl after a successful
 * open and blocking read (the read returns 0 when there's something
 * to interpret).  The ioctl arg is a pointer to an fc_parameters
 * data structure which is filled in by the driver with the fcode
 * len (if any) and unit address of the new device.
 * Offset 0 .. fcode len may be used as the offset to an mmap call to
 * provide access to a copy of the device fcode. The unit address is
 * returned as a NULL terminated string.
 */

struct fc_parameters {
	int32_t	fcode_size;
	char	unit_address[OBP_MAXPATHLEN];
	int	config_address;
};



/*
 * FC_RUN_PRIV: The ioctl 'arg' is a pointer to an array of fc_cell_t's
 * in the following format:
 *
 * fc_cell_t[0]: Pointer to a NULL terminated string: service name
 * fc_cell_t[1]: Number of input arguments (Call this value 'A')
 * fc_cell_t[2]: Number of output result cells allocated (Call this val 'R')
 * fc_cell_t[3]: Error Cell (See below)
 * fc_cell_t[4]: Priv Violation Cell (non-zero if priv. violation)
 * fc_cell_t[5]: Argument cell[0] (Possibly none)
 * fc_cell_t[5 + 'A']: Result cell[0] (Possibly none)
 *
 * The array is variable sized, and must contain a minimum of 5 fc_cell_t's.
 * The size (in fc_cell_t's) is 5 + 'A' + 'R'.
 *
 * The argument cells are filled in by the caller.  The result cells
 * (if any) and error cell are returned to the caller by the driver.
 * The error cell and priv violation cell are filled in and returned
 * to the caller by the driver.
 *
 * Error Cell Values:
 *
 *	-1:	The call itself failed (the service name was unknown).
 *
 *	0:	No error (though the result cells may indicate results
 *		that signify an error consistent with the service request.)
 *
 * Priv Violation Cell Values:
 *
 *	0:	No priv violation
 *
 *	-1:	Executing the request caused a priv. violation.
 *		For example, an rl@ from an address not mapped in
 *		by the interpreter.
 */

#define	FC_ERR_NONE	fc_int2cell(0)
#define	FC_ERR_SVC_NAME	fc_int2cell(-1)

#define	FC_PRIV_OK	fc_intcell(0)
#define	FC_PRIV_ERROR	fc_int2cell(-1)

/*
 * Client interface template:
 * The actual number of arguments is nargs.
 * The actual number of results is nresults.
 * The variable array 'v' contains 'nargs + nresults' elements
 */
struct fc_client_interface {
	fc_cell_t	svc_name;
	fc_cell_t	nargs;
	fc_cell_t	nresults;
	fc_cell_t	error;
	fc_cell_t	priv_error;
	fc_cell_t	v[1];	/* variable array of args and results */
};

typedef	struct fc_client_interface fc_ci_t;

#define	fc_arg(cp, i)		(cp->v[(i)])
#define	fc_result(cp, i)	(cp->v[fc_cell2int(cp->nargs) + (i)])

#define	FCC_FIXED_CELLS			5

/*
 * FC_GET_FCODE_DATA: This ioctl allows userland portion of the fcode
 * interpreter to get the fcode into a local buffer without having
 * to use mmap() interface (which calls hat_getkpfnum() routine).
 * This allows DR kernel cage memory to be relocated while this
 * fcode buffer is allocated.
 *
 * The ioctl arg is a pointer to an fc_fcode_info structure which
 * has the fcode_size field set with the expected fcode length.
 * The driver uses this field to validate correct size before using
 * copyout() to fill in the fcode_ptr buffer with fcode data.
 */
typedef struct fc_fcode_info {
	int32_t	fcode_size;
	char	*fcode_ptr;
} fc_fcode_info_t;

/*
 * The service name len (max) is limited by the size of a method name
 */
#define	FC_SVC_NAME_LEN		OBP_MAXPROPNAME

/*
 * "Internally" generated service names ...
 */
#define	FC_SVC_VALIDATE		"sunos,validate"
#define	FC_SVC_INVALIDATE	"sunos,invalidate"
#define	FC_SVC_EXIT		"sunos,exit"

#define	FC_OPEN_METHOD		"open"
#define	FC_CLOSE_METHOD		"close"
#define	FC_FIND_FCODE		"$find"

/*
 * Property related group:
 *
 * sunos,get*proplen ( propname-cstr phandle -- proplen )
 * sunos,get*prop ( propname-cstr buf phandle -- proplen )
 *
 * sunos,property ( propname-cstr buf len phandle -- )
 */

#define	FC_GET_MY_PROPLEN	"sunos,get-my-proplen"
#define	FC_GET_MY_PROP		"sunos,get-my-prop"

#define	FC_GET_IN_PROPLEN	"sunos,get-inherited-proplen"
#define	FC_GET_IN_PROP		"sunos,get-inherited-prop"

#define	FC_GET_PKG_PROPLEN	"sunos,get-package-proplen"
#define	FC_GET_PKG_PROP		"sunos,get-package-prop"

#define	FC_CREATE_PROPERTY	"sunos,property"

/*
 * Register access and dma ... same as 1275
 *
 * dma-map-in maps in a suitable aligned user address.
 */
#define	FC_RL_FETCH		"rl@"
#define	FC_RW_FETCH		"rw@"
#define	FC_RB_FETCH		"rb@"

#define	FC_RL_STORE		"rl!"
#define	FC_RW_STORE		"rw!"
#define	FC_RB_STORE		"rb!"

#define	FC_MAP_IN		"map-in"
#define	FC_MAP_OUT		"map-out"
#define	FC_DMA_MAP_IN		"dma-map-in"
#define	FC_DMA_MAP_OUT		"dma-map-out"

/*
 * PCI configuration space access methods ... same as pci binding
 */
#define	FC_PCI_CFG_L_FETCH	"config-l@"
#define	FC_PCI_CFG_W_FETCH	"config-w@"
#define	FC_PCI_CFG_B_FETCH	"config-b@"

#define	FC_PCI_CFG_L_STORE	"config-l!"
#define	FC_PCI_CFG_W_STORE	"config-w!"
#define	FC_PCI_CFG_B_STORE	"config-b!"

/*
 * Device node creation ...
 *
 * Create a new device with the given name, unit-address, parent.phandle
 * with a phandle that must have been previously allocated using
 * sunos,alloc-phandle.  finish-device marks the device creation and
 * the creation of its properties as complete. (It's a signal to the
 * the OS that the node is now reasonably complete.)
 *
 * sunos,new-device ( name-cstr unit-addr-cstr parent.phandle phandle -- )
 * finish-device ( phandle  -- )
 */
#define	FC_NEW_DEVICE		"sunos,new-device"
#define	FC_FINISH_DEVICE	"sunos,finish-device"

/*
 * Navigation and configuration:
 *
 * sunos,probe-address ( -- phys.lo ... )
 * sunos,probe-space ( -- phys.hi )
 *
 * sunos,ap-phandle ( -- ap.phandle )
 *	Return attachment point phandle
 *
 * sunos,parent ( child.phandle -- parent.phandle )
 *
 * child ( parent.phandle -- child.phandle )
 * peer ( phandle -- phandle.sibling )
 *
 * sunos,alloc-phandle ( -- phandle )
 * Allocates a unique phandle, not associated with the device tree
 *
 * sunos,config-child ( -- child.phandle )
 * Return the phandle of the child being configured.
 */

#define	FC_PROBE_ADDRESS	"sunos,probe-address"
#define	FC_PROBE_SPACE		"sunos,probe-space"
#define	FC_AP_PHANDLE		"sunos,ap-phandle"
#define	FC_PARENT		"sunos,parent"
#define	FC_CHILD_FCODE		"child"
#define	FC_PEER_FCODE		"peer"
#define	FC_ALLOC_PHANDLE	"sunos,alloc-phandle"
#define	FC_CONFIG_CHILD		"sunos,config-child"

/*
 * Fcode Drop In Routines:
 * sunos,get_fcode_size ( cstr -- len )
 * Returns the size in bytes of the Fcode for a given drop in.
 * sunos,get_fcode (cstr buf len -- status? )
 * Returns the Fcode image for a given drop in.
 */
#define	FC_GET_FCODE_SIZE	"sunos,get-fcode-size"
#define	FC_GET_FCODE		"sunos,get-fcode"

/*
 * kernel internal data structures and interfaces
 * for the fcode interpreter.
 */
#if defined(_KERNEL)

/*
 * PCI bus-specific arguments.
 *
 * We can't get the physical config address of the child from the
 * unit address, so we supply it here, along with the child's dip
 * as the bus specific argument to pci_ops_alloc_handle.
 */

struct pci_ops_bus_args {
	int32_t config_address;		/* phys.hi config addr component */
};

/*
 * Define data structures for resource lists and handle management
 *
 * 'untyped' resources are managed by the provider.
 */
struct fc_dma_resource {
	void *virt;
	size_t len;
	ddi_dma_handle_t h;
	uint32_t devaddr;
	struct buf *bp;
};

struct fc_map_resource {
	void *virt;
	size_t len;
	ddi_acc_handle_t h;
	void *regspec;
};

struct fc_nodeid_resource {
	int nodeid;		/* An allocated nodeid */
};

struct fc_contigious_resource {
	void *virt;
	size_t len;
};
struct fc_untyped_resource {
	int utype;		/* providers private type field */
	void (*free)(void *);	/* function to free the resource */
	void *resource;		/* Pointer to the resource */
};

typedef enum {
	RT_DMA = 0,
	RT_MAP,
	RT_NODEID,
	RT_CONTIGIOUS,
	RT_UNTYPED
} fc_resource_type_t;

struct fc_resource {
	struct fc_resource *next;
	fc_resource_type_t type;
	union {
		struct fc_dma_resource d;
		struct fc_map_resource m;
		struct fc_nodeid_resource n;
		struct fc_contigious_resource c;
		struct fc_untyped_resource r;
	} un;
};

#define	fc_dma_virt	un.d.virt
#define	fc_dma_len	un.d.len
#define	fc_dma_handle	un.d.h
#define	fc_dma_devaddr	un.d.devaddr
#define	fc_dma_bp	un.d.bp

#define	fc_map_virt	un.m.virt
#define	fc_map_len	un.m.len
#define	fc_map_handle	un.m.h
#define	fc_regspec	un.m.regspec

#define	fc_nodeid_r	un.n.nodeid

#define	fc_contig_virt	un.c.virt
#define	fc_contig_len	un.c.len

#define	fc_untyped_type	un.r.utype
#define	fc_untyped_free	un.r.free
#define	fc_untyped_r	un.r.resource

struct fc_phandle_entry {
	struct fc_phandle_entry *next;
	dev_info_t	*dip;
	fc_phandle_t	h;
};

extern void fc_phandle_table_alloc(struct fc_phandle_entry **);
extern void fc_phandle_table_free(struct fc_phandle_entry **);
extern dev_info_t *fc_phandle_to_dip(struct fc_phandle_entry **, fc_phandle_t);
extern fc_phandle_t fc_dip_to_phandle(struct fc_phandle_entry **, dev_info_t *);
extern void fc_add_dip_to_phandle(struct fc_phandle_entry **, dev_info_t *,
    fc_phandle_t);

/*
 * Structures and functions for managing our own subtree rooted
 * at the attachment point. The parent linkage is established
 * at node creation time.  The 'downwards' linkage isn't established
 * until the node is bound.
 */
struct fc_device_tree {
	dev_info_t *dip;
	struct fc_device_tree *child;
	struct fc_device_tree *peer;
};

void fc_add_child(dev_info_t *child, dev_info_t *parent,
    struct fc_device_tree *head);

void fc_remove_child(dev_info_t *child, struct fc_device_tree *head);

dev_info_t *fc_child_node(dev_info_t *parent, struct fc_device_tree *head);
dev_info_t *fc_peer_node(dev_info_t *devi, struct fc_device_tree *head);
struct fc_device_tree *fc_find_node(dev_info_t *, struct fc_device_tree *);

void fc_create_device_tree(dev_info_t *ap, struct fc_device_tree **head);
void fc_remove_device_tree(struct fc_device_tree **head);

/*
 * Our handles represent a list of resources associated with an
 * attachment point.  The handles chain, just as the ops functions
 * do, with the ops caller responsible for remembering the handle
 * of the ops function below it. NB: Externally, this data structure
 * is opaque. (Not all members may be present in each chained cookie.)
 * For example, the dtree head is valid in only a single instance
 * of a set of chained cookies, so use the access function to find it.)
 */
struct fc_resource_list {
	struct fc_resource *head;
	void *next_handle;		/* next handle in chain */
	dev_info_t *ap;			/* Attachment point dip */
	dev_info_t *child;		/* Child being configured, if any */
	dev_info_t *cdip;		/* Current node, if any */
	int cdip_state;			/* node creation state - see below */
	void *fcode;			/* fcode kernel address */
	size_t fcode_size;		/* fcode size or zero */
	char *unit_address;		/* childs unit address */
	char *my_args;			/* initial setting for my-args */
	void *bus_args;			/* bus dependent arguments */
	struct fc_phandle_entry *ptable; /* devinfo/phandle table */
	struct fc_device_tree *dtree;	/* Our subtree (leaf cookie only) */
};

typedef struct fc_resource_list *fco_handle_t;

/*
 * Values for cdip_state:
 */
#define	FC_CDIP_NOSTATE		0x00	/* No state - no nodes created */
#define	FC_CDIP_STARTED		0x01	/* Node started - dip in cdip */
#define	FC_CDIP_DONE		0x02	/* Node finished - last dip in cdip */
#define	FC_CDIP_CONFIG		0x10	/* subtree configured */

/*
 * Functions to allocate handles for the fcode_interpreter.
 *
 * This function allocates a handle, used to store resources
 * associated with this fcode request including the address of
 * the mapped in and copied in fcode and it's size or NULL, 0
 * if there is no fcode (the interpreter may look for a drop-in
 * driver if there is no fcode), the unit address of child and
 * bus specific arguments.  For PCI, the bus specific arguments
 * include the child's prototype dip and the config address of
 * the child, which can't be derived from the unit address.
 *
 * The 'handle' returned also contains resource information
 * about any allocations of kernel resources that the fcode
 * may have created.  Thus, the handle's life is the life
 * of the plug-in card and can't be released until the card
 * is removed.  Upon release, the resources are released.
 */
extern fco_handle_t
fc_ops_alloc_handle(dev_info_t *ap, dev_info_t *config_child,
    void *fcode, size_t fcode_size, char *unit_address, void *bus_args);

extern fco_handle_t
pci_fc_ops_alloc_handle(dev_info_t *ap, dev_info_t *config_child,
    void *fcode, size_t fcode_size, char *unit_address,
    struct pci_ops_bus_args *bus_args);

extern fco_handle_t
gp2_fc_ops_alloc_handle(dev_info_t *ap, dev_info_t *config_child,
    void *fcode, size_t fcode_size, char *unit_address,
    char *my_args);

extern void pci_fc_ops_free_handle(fco_handle_t handle);
extern void gp2_fc_ops_free_handle(fco_handle_t handle);
extern void fc_ops_free_handle(fco_handle_t handle);

extern struct fc_phandle_entry **fc_handle_to_phandle_head(fco_handle_t rp);

struct fc_device_tree **fc_handle_to_dtree_head(fco_handle_t);
struct fc_device_tree *fc_handle_to_dtree(fco_handle_t);

/*
 * fc_ops_t is the main glue back to the framework and attachment point driver
 * for privileged driver operations.  The framework/driver provides a pointer
 * to the fc_ops function to handle the request given in the args.  The dip
 * and handle are passed back to the framework/driver to distinguish
 * requests, if necessary.  The argument array is an array of fc_cell_t's
 * and is defined in fcode.h
 *
 * The ops function should return -1 to indicate that the service name is
 * unknown and return the value 0 to indicate that the service name was known
 * and processed (even if it failed).  ops functions may chain, using the
 * return code to communicate if the current function handled the service
 * request. Using this technique, the driver can provide certain ops functions
 * and allow a framework ops function to handle standardized ops functions,
 * or work hand in hand with a framework function so both can handle an op.
 * If an ops function is not handled, thus returning -1 to the driver, the
 * driver will log an error noting the name of the service and return the
 * error to the caller.
 */
typedef int (fc_ops_t)(dev_info_t *, fco_handle_t, fc_ci_t *);

extern fc_ops_t fc_ops;
extern fc_ops_t pci_fc_ops;
extern fc_ops_t gp2_fc_ops;

/*
 * Internal structure used to enque an fcode request
 * The 'next' and 'busy' fields are protected by a mutex.
 * Thread synchronization is accomplished via use of the 'busy' field.
 */
struct fc_request {
	struct fc_request *next;	/* Next in chain (private) */
	int		busy;		/* Waiters flag (private; see below) */
	int		error;		/* Interpreter return code (private) */
	dev_info_t	*ap_dip;	/* Attachment point. ie: pci nexus */
	fc_ops_t	*ap_ops;	/* driver's fcode ops function */
	fco_handle_t	handle;		/* Caller's private identifier */
	timeout_id_t	timeout;	/* Timeout identifier */
};

/*
 * Values for 'busy'.  The requester initializes the field to FC_R_INIT (0),
 * then waits for it be set to FC_R_DONE.  The framework sets it to
 * FC_R_BUSY while working on the request so it can distinguish between
 * an inactive and an active request.
 */
#define	FC_R_INIT	0		/* initialized, on queue */
#define	FC_R_BUSY	1		/* request is active, busy */
#define	FC_R_DONE	2		/* request is done and may be deq'd */

/*
 * Values for 'error'.
 */
#define	FC_SUCCESS	0		/* FCode interpreted successfully */
#define	FC_TIMEOUT	1		/* Timer expired */
#define	FC_ERROR	-1		/* Interpreter error */

/*
 * Function to call to invoke the fcode interpreter.
 *
 * This function will wait and return when the interpreter either
 * completes successfully or fails, returning pass/fail status as
 * the return code.  Interim calls to the driver's ops function will
 * be made for both priv. ops and to create device nodes and properties.
 *
 * Calling this function will log a message to userland to request the
 * eventd to start the userland fcode interpreter process. The interpreter
 * opens /dev/fcode, which clones an instance of the driver, and then
 * waits in a 'read' until there's an active request.
 * XXX: For the prototype, we can start it manually or use an init.d script.
 *
 * 'ap' is the attachment point dip: that is, the driving parent's dev_info_t
 * ie: for pci devices, this will be the dip of the pci nexus.
 *
 * The 'handle' is provided for the caller, and can be used to
 * identify the request along with the attachment point dip, both
 * of which will be passed back to the driver's ops function.
 * The handle is allocated first by calling a bus-specific
 * <bus>_ops_handle_alloc function.
 *
 * ops functions may chain; an ops function should return -1 if
 * the call was not recognized, or 0 if the call was recognized.
 */
extern int fcode_interpreter(dev_info_t *, fc_ops_t *, fco_handle_t);

/*
 * The fcode implementation uses this function to wait for and 'de-queue'
 * an fcode request.  It's triggered by a 'read' request from the
 * userland interpreter. It uses a 'sig' form of waiting (cv_wait_sig),
 * so the interpreter can interrupt the read.
 */
extern struct fc_request *fc_get_request(void);

/*
 * When the fcode implementation is finished servicing a request, it calls this
 * function to mark the request as done and to signal the originating thread
 * (now waiting in fcode_interpreter) that the request is done.
 */
extern void fc_finish_request(struct fc_request *);

/*
 * The fcode implementation uses these functions to manage
 * resource items and resource lists ...
 */
extern void fc_add_resource(fco_handle_t, struct fc_resource *);
extern void fc_rem_resource(fco_handle_t, struct fc_resource *);
extern void fc_lock_resource_list(fco_handle_t);
extern void fc_unlock_resource_list(fco_handle_t);

/*
 * ops common and helper functions
 */
extern int fc_fail_op(dev_info_t *, fco_handle_t, fc_ci_t *);
extern int fc_success_op(dev_info_t *, fco_handle_t, fc_ci_t *);

extern int fc_syntax_error(fc_ci_t *, char *);
extern int fc_priv_error(fc_ci_t *, char *);

/*
 * Recharacterized ddi functions we need to define ...
 *
 * The only difference is we call through the attachment point driver,
 * as a proxy for the child that isn't yet attached. The ddi functions
 * optimize these functions by not necessarily calling through the
 * attachment point driver.
 */
int fc_ddi_dma_htoc(dev_info_t *, ddi_dma_handle_t, off_t, ddi_dma_cookie_t *);
int fc_ddi_dma_free(dev_info_t *ap, ddi_dma_handle_t h);
int fc_ddi_dma_sync(ddi_dma_handle_t h, off_t o, size_t l, uint_t whom);

/*
 * The ndi prop functions aren't appropriate for the interpreter.
 * We create byte-array, untyped properties.
 */

int fc_ndi_prop_update(dev_t, dev_info_t *, char *, uchar_t *, uint_t);

/*
 * The setup and teardown parts of physio()
 */
int fc_physio_setup(struct buf **bpp, void *io_base, size_t io_len);
void fc_physio_free(struct buf **bpp, void *io_base, size_t io_len);

/*
 * debugging macros
 */
extern int fcode_debug;
#define	dcmn_err(level, args) if (fcode_debug >= level) cmn_err args

#ifdef DEBUG

void fc_debug(char *, uintptr_t, uintptr_t,
    uintptr_t, uintptr_t, uintptr_t);

#define	FC_DEBUG0(level, flag, s) if (fcode_debug >= level) \
    fc_debug(s, 0, 0, 0, 0, 0)
#define	FC_DEBUG1(level, flag, fmt, a1) if (fcode_debug >= level) \
    fc_debug(fmt, (uintptr_t)(a1), 0, 0, 0, 0);
#define	FC_DEBUG2(level, flag, fmt, a1, a2) if (fcode_debug >= level) \
    fc_debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2), 0, 0, 0);
#define	FC_DEBUG3(level, flag, fmt, a1, a2, a3) \
    if (fcode_debug >= level) \
    fc_debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2), (uintptr_t)(a3), 0, 0);
#else
#define	FC_DEBUG0(level, flag, s)
#define	FC_DEBUG1(level, flag, fmt, a1)
#define	FC_DEBUG2(level, flag, fmt, a1, a2)
#define	FC_DEBUG3(level, flag, fmt, a1, a2, a3)
#endif


#endif	/* defined(_KERNEL) */

#ifdef	__cplusplus
}
#endif

#endif	/* _SYS_FCODE_H */