xref: /titanic_52/usr/src/uts/common/pcmcia/cis/cis.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate /*
30*7c478bd9Sstevel@tonic-gate  * This is a collection of routines that make up the Card Information
31*7c478bd9Sstevel@tonic-gate  *	Structure (CIS) interpreter.  The algorigthms used are based
32*7c478bd9Sstevel@tonic-gate  *	on the Release 2.01 PCMCIA standard.
33*7c478bd9Sstevel@tonic-gate  *
34*7c478bd9Sstevel@tonic-gate  * Note that a bunch of comments are not indented correctly with the
35*7c478bd9Sstevel@tonic-gate  *	code that they are commenting on. This is because cstyle is
36*7c478bd9Sstevel@tonic-gate  *	inflexible concerning 4-column indenting.
37*7c478bd9Sstevel@tonic-gate  */
38*7c478bd9Sstevel@tonic-gate 
39*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/systm.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/user.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/buf.h>
43*7c478bd9Sstevel@tonic-gate #include <sys/file.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/uio.h>
45*7c478bd9Sstevel@tonic-gate #include <sys/conf.h>
46*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
47*7c478bd9Sstevel@tonic-gate #include <sys/autoconf.h>
48*7c478bd9Sstevel@tonic-gate #include <sys/vtoc.h>
49*7c478bd9Sstevel@tonic-gate #include <sys/dkio.h>
50*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
51*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
52*7c478bd9Sstevel@tonic-gate #include <sys/debug.h>
53*7c478bd9Sstevel@tonic-gate #include <sys/kstat.h>
54*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
55*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
56*7c478bd9Sstevel@tonic-gate #include <sys/kobj.h>
57*7c478bd9Sstevel@tonic-gate #include <sys/callb.h>
58*7c478bd9Sstevel@tonic-gate 
59*7c478bd9Sstevel@tonic-gate #include <sys/pctypes.h>
60*7c478bd9Sstevel@tonic-gate #include <pcmcia/sys/cs_types.h>
61*7c478bd9Sstevel@tonic-gate #include <sys/pcmcia.h>
62*7c478bd9Sstevel@tonic-gate #include <sys/sservice.h>
63*7c478bd9Sstevel@tonic-gate #include <pcmcia/sys/cis.h>
64*7c478bd9Sstevel@tonic-gate #include <pcmcia/sys/cis_handlers.h>
65*7c478bd9Sstevel@tonic-gate #include <pcmcia/sys/cs.h>
66*7c478bd9Sstevel@tonic-gate #include <pcmcia/sys/cs_priv.h>
67*7c478bd9Sstevel@tonic-gate #include <pcmcia/sys/cis_protos.h>
68*7c478bd9Sstevel@tonic-gate #include <pcmcia/sys/cs_stubs.h>
69*7c478bd9Sstevel@tonic-gate 
70*7c478bd9Sstevel@tonic-gate /*
71*7c478bd9Sstevel@tonic-gate  * Function declarations
72*7c478bd9Sstevel@tonic-gate  */
73*7c478bd9Sstevel@tonic-gate void *CISParser(int function, ...);
74*7c478bd9Sstevel@tonic-gate static int (*cis_card_services)(int, ...) = NULL;
75*7c478bd9Sstevel@tonic-gate 
76*7c478bd9Sstevel@tonic-gate static int cis_process_longlink(cistpl_callout_t *, cistpl_t *,
77*7c478bd9Sstevel@tonic-gate 						cis_info_t *, cisparse_t *);
78*7c478bd9Sstevel@tonic-gate static int cis_create_cis_chain(cs_socket_t *, cistpl_callout_t *,
79*7c478bd9Sstevel@tonic-gate 					cisptr_t *, cis_info_t *, cisparse_t *);
80*7c478bd9Sstevel@tonic-gate static void cis_store_cis_addr(cistpl_t *, cisptr_t *);
81*7c478bd9Sstevel@tonic-gate 
82*7c478bd9Sstevel@tonic-gate extern cistpl_callout_t cistpl_std_callout[];
83*7c478bd9Sstevel@tonic-gate extern cistpl_devspeed_struct_t cistpl_devspeed_struct;
84*7c478bd9Sstevel@tonic-gate 
85*7c478bd9Sstevel@tonic-gate #ifdef	CIS_DEBUG
86*7c478bd9Sstevel@tonic-gate int	cis_debug = 0;
87*7c478bd9Sstevel@tonic-gate #endif
88*7c478bd9Sstevel@tonic-gate 
89*7c478bd9Sstevel@tonic-gate /*
90*7c478bd9Sstevel@tonic-gate  * cisp_init - initialize the CIS parser
91*7c478bd9Sstevel@tonic-gate  */
92*7c478bd9Sstevel@tonic-gate void
93*7c478bd9Sstevel@tonic-gate cisp_init()
94*7c478bd9Sstevel@tonic-gate {
95*7c478bd9Sstevel@tonic-gate #ifdef	XXX
96*7c478bd9Sstevel@tonic-gate 	csregister_t csr;
97*7c478bd9Sstevel@tonic-gate 
98*7c478bd9Sstevel@tonic-gate 	/*
99*7c478bd9Sstevel@tonic-gate 	 * Fill out the function for CISSetAddress
100*7c478bd9Sstevel@tonic-gate 	 */
101*7c478bd9Sstevel@tonic-gate 	csr.cs_magic = PCCS_MAGIC;
102*7c478bd9Sstevel@tonic-gate 	csr.cs_version = PCCS_VERSION;
103*7c478bd9Sstevel@tonic-gate 	csr.cs_event = (f_t *)CISParser;
104*7c478bd9Sstevel@tonic-gate 
105*7c478bd9Sstevel@tonic-gate 	/*
106*7c478bd9Sstevel@tonic-gate 	 * We have to call SS instead of CS to register because we
107*7c478bd9Sstevel@tonic-gate 	 *	can't do a _depends_on for CS
108*7c478bd9Sstevel@tonic-gate 	 */
109*7c478bd9Sstevel@tonic-gate 	SocketServices(CISSetAddress, &csr);
110*7c478bd9Sstevel@tonic-gate #endif	/* XXX */
111*7c478bd9Sstevel@tonic-gate }
112*7c478bd9Sstevel@tonic-gate 
113*7c478bd9Sstevel@tonic-gate /*
114*7c478bd9Sstevel@tonic-gate  * cis_deinit - deinitialize the CIS parser
115*7c478bd9Sstevel@tonic-gate  */
116*7c478bd9Sstevel@tonic-gate void
117*7c478bd9Sstevel@tonic-gate cis_deinit()
118*7c478bd9Sstevel@tonic-gate {
119*7c478bd9Sstevel@tonic-gate 
120*7c478bd9Sstevel@tonic-gate 	/*
121*7c478bd9Sstevel@tonic-gate 	 * Tell CS that we're gone.
122*7c478bd9Sstevel@tonic-gate 	 */
123*7c478bd9Sstevel@tonic-gate 	if (cis_card_services)
124*7c478bd9Sstevel@tonic-gate 	    CIS_CARD_SERVICES(CISUnregister);
125*7c478bd9Sstevel@tonic-gate 
126*7c478bd9Sstevel@tonic-gate 	return;
127*7c478bd9Sstevel@tonic-gate 
128*7c478bd9Sstevel@tonic-gate }
129*7c478bd9Sstevel@tonic-gate 
130*7c478bd9Sstevel@tonic-gate /*
131*7c478bd9Sstevel@tonic-gate  * CISParser - this is the entrypoint for all of the CIS Interpreter
132*7c478bd9Sstevel@tonic-gate  *		functions
133*7c478bd9Sstevel@tonic-gate  */
134*7c478bd9Sstevel@tonic-gate void *
135*7c478bd9Sstevel@tonic-gate CISParser(int function, ...)
136*7c478bd9Sstevel@tonic-gate {
137*7c478bd9Sstevel@tonic-gate 	va_list arglist;
138*7c478bd9Sstevel@tonic-gate 	void *retcode = (void *)CS_UNSUPPORTED_FUNCTION;
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate #if defined(CIS_DEBUG)
141*7c478bd9Sstevel@tonic-gate 	if (cis_debug > 1) {
142*7c478bd9Sstevel@tonic-gate 	    cmn_err(CE_CONT, "CISParser: called with function 0x%x\n",
143*7c478bd9Sstevel@tonic-gate 				function);
144*7c478bd9Sstevel@tonic-gate 	}
145*7c478bd9Sstevel@tonic-gate #endif
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate 	va_start(arglist, function);
148*7c478bd9Sstevel@tonic-gate 
149*7c478bd9Sstevel@tonic-gate 	/*
150*7c478bd9Sstevel@tonic-gate 	 * ...and here's the CIS Interpreter waterfall
151*7c478bd9Sstevel@tonic-gate 	 */
152*7c478bd9Sstevel@tonic-gate 	switch (function) {
153*7c478bd9Sstevel@tonic-gate 	    case CISP_CIS_SETUP: {
154*7c478bd9Sstevel@tonic-gate 		csregister_t *csr;
155*7c478bd9Sstevel@tonic-gate 		cisregister_t cisr;
156*7c478bd9Sstevel@tonic-gate 
157*7c478bd9Sstevel@tonic-gate 		    csr = va_arg(arglist, csregister_t *);
158*7c478bd9Sstevel@tonic-gate 		    cis_card_services = csr->cs_card_services;
159*7c478bd9Sstevel@tonic-gate 
160*7c478bd9Sstevel@tonic-gate 		    cisr.cis_magic = PCCS_MAGIC;
161*7c478bd9Sstevel@tonic-gate 		    cisr.cis_version = PCCS_VERSION;
162*7c478bd9Sstevel@tonic-gate 		    cisr.cis_parser = NULL;	/* let the framework do this */
163*7c478bd9Sstevel@tonic-gate 		    cisr.cistpl_std_callout = cistpl_std_callout;
164*7c478bd9Sstevel@tonic-gate 
165*7c478bd9Sstevel@tonic-gate 			/*
166*7c478bd9Sstevel@tonic-gate 			 * Tell CS that we're here and what our
167*7c478bd9Sstevel@tonic-gate 			 *	entrypoint address is.
168*7c478bd9Sstevel@tonic-gate 			 */
169*7c478bd9Sstevel@tonic-gate 		    CIS_CARD_SERVICES(CISRegister, &cisr);
170*7c478bd9Sstevel@tonic-gate 		} /* CISP_CIS_SETUP */
171*7c478bd9Sstevel@tonic-gate 		break;
172*7c478bd9Sstevel@tonic-gate 	    case CISP_CIS_LIST_CREATE: {
173*7c478bd9Sstevel@tonic-gate 		cistpl_callout_t *cistpl_callout;
174*7c478bd9Sstevel@tonic-gate 		cs_socket_t *sp;
175*7c478bd9Sstevel@tonic-gate 
176*7c478bd9Sstevel@tonic-gate 		    cistpl_callout = va_arg(arglist, cistpl_callout_t *);
177*7c478bd9Sstevel@tonic-gate 		    sp = va_arg(arglist, cs_socket_t *);
178*7c478bd9Sstevel@tonic-gate 
179*7c478bd9Sstevel@tonic-gate 		    retcode = (void *)
180*7c478bd9Sstevel@tonic-gate 			(uintptr_t)cis_list_create(cistpl_callout, sp);
181*7c478bd9Sstevel@tonic-gate 		}
182*7c478bd9Sstevel@tonic-gate 		break;
183*7c478bd9Sstevel@tonic-gate 	    case CISP_CIS_LIST_DESTROY: {
184*7c478bd9Sstevel@tonic-gate 		cs_socket_t *sp;
185*7c478bd9Sstevel@tonic-gate 
186*7c478bd9Sstevel@tonic-gate 		    sp = va_arg(arglist, cs_socket_t *);
187*7c478bd9Sstevel@tonic-gate 
188*7c478bd9Sstevel@tonic-gate 		    retcode = (void *)(uintptr_t)cis_list_destroy(sp);
189*7c478bd9Sstevel@tonic-gate 		}
190*7c478bd9Sstevel@tonic-gate 		break;
191*7c478bd9Sstevel@tonic-gate 	    case CISP_CIS_GET_LTUPLE: {
192*7c478bd9Sstevel@tonic-gate 		cistpl_t *tp;
193*7c478bd9Sstevel@tonic-gate 		cisdata_t type;
194*7c478bd9Sstevel@tonic-gate 		int flags;
195*7c478bd9Sstevel@tonic-gate 
196*7c478bd9Sstevel@tonic-gate 		    tp = va_arg(arglist, cistpl_t *);
197*7c478bd9Sstevel@tonic-gate 		    type = va_arg(arglist, uint_t);
198*7c478bd9Sstevel@tonic-gate 		    flags = va_arg(arglist, int);
199*7c478bd9Sstevel@tonic-gate 
200*7c478bd9Sstevel@tonic-gate 		    retcode = (void *)cis_get_ltuple(tp, type, flags);
201*7c478bd9Sstevel@tonic-gate 		}
202*7c478bd9Sstevel@tonic-gate 		break;
203*7c478bd9Sstevel@tonic-gate 
204*7c478bd9Sstevel@tonic-gate 	    case CISP_CIS_PARSE_TUPLE: {
205*7c478bd9Sstevel@tonic-gate 		cistpl_callout_t *co;
206*7c478bd9Sstevel@tonic-gate 		cistpl_t *tp;
207*7c478bd9Sstevel@tonic-gate 		int flags;
208*7c478bd9Sstevel@tonic-gate 		void *arg;
209*7c478bd9Sstevel@tonic-gate 		cisdata_t subtype;
210*7c478bd9Sstevel@tonic-gate 
211*7c478bd9Sstevel@tonic-gate 		co = va_arg(arglist, cistpl_callout_t *);
212*7c478bd9Sstevel@tonic-gate 		tp = va_arg(arglist, cistpl_t *);
213*7c478bd9Sstevel@tonic-gate 		flags = va_arg(arglist, int);
214*7c478bd9Sstevel@tonic-gate 		arg = va_arg(arglist, void *);
215*7c478bd9Sstevel@tonic-gate 		subtype = va_arg(arglist, uint_t);
216*7c478bd9Sstevel@tonic-gate 
217*7c478bd9Sstevel@tonic-gate 		retcode = (void *)(uintptr_t)cis_tuple_handler(co, tp,
218*7c478bd9Sstevel@tonic-gate 		    flags, arg, subtype);
219*7c478bd9Sstevel@tonic-gate 		}
220*7c478bd9Sstevel@tonic-gate 		break;
221*7c478bd9Sstevel@tonic-gate 
222*7c478bd9Sstevel@tonic-gate 	    case CISP_CIS_CONV_DEVSPEED:
223*7c478bd9Sstevel@tonic-gate 		retcode = (void *)(uintptr_t)cis_convert_devspeed(
224*7c478bd9Sstevel@tonic-gate 				va_arg(arglist, convert_speed_t *));
225*7c478bd9Sstevel@tonic-gate 		break;
226*7c478bd9Sstevel@tonic-gate 
227*7c478bd9Sstevel@tonic-gate 	    case CISP_CIS_CONV_DEVSIZE:
228*7c478bd9Sstevel@tonic-gate 		retcode = (void *)(uintptr_t)cis_convert_devsize(
229*7c478bd9Sstevel@tonic-gate 				va_arg(arglist, convert_size_t *));
230*7c478bd9Sstevel@tonic-gate 		break;
231*7c478bd9Sstevel@tonic-gate 
232*7c478bd9Sstevel@tonic-gate 	    default:
233*7c478bd9Sstevel@tonic-gate 		break;
234*7c478bd9Sstevel@tonic-gate 	}
235*7c478bd9Sstevel@tonic-gate 
236*7c478bd9Sstevel@tonic-gate 	va_end(arglist);
237*7c478bd9Sstevel@tonic-gate 
238*7c478bd9Sstevel@tonic-gate 	return (retcode);
239*7c478bd9Sstevel@tonic-gate }
240*7c478bd9Sstevel@tonic-gate 
241*7c478bd9Sstevel@tonic-gate /*
242*7c478bd9Sstevel@tonic-gate  * cis_list_lcreate - read a PC card's CIS and create a local linked CIS list
243*7c478bd9Sstevel@tonic-gate  *
244*7c478bd9Sstevel@tonic-gate  *	cistpl_callout_t *cistpl_callout - pointer to callout structure
245*7c478bd9Sstevel@tonic-gate  *				array to use to find tuples.
246*7c478bd9Sstevel@tonic-gate  *	cisptr_t cisptr - pointer to a structure containing the handle and
247*7c478bd9Sstevel@tonic-gate  *				offset from where we should start reading
248*7c478bd9Sstevel@tonic-gate  *				CIS bytes as well as misc flags.
249*7c478bd9Sstevel@tonic-gate  *	cis_info_t *cis_info - pointer to a cis_info_t structure; pass
250*7c478bd9Sstevel@tonic-gate  *				the cis_info->cis member as a NULL pointer
251*7c478bd9Sstevel@tonic-gate  *				if you want to create a new list.
252*7c478bd9Sstevel@tonic-gate  *	cisparse_t *cisparse - pointer to a cisparse_t struture to put
253*7c478bd9Sstevel@tonic-gate  *				parsed longlink tuple data into.
254*7c478bd9Sstevel@tonic-gate  *      cs_socket_t *sp - pointer to a cs_socket_t structure that describes
255*7c478bd9Sstevel@tonic-gate  *				 the socket and card in this socket.
256*7c478bd9Sstevel@tonic-gate  *
257*7c478bd9Sstevel@tonic-gate  * We return the a count of the number of tuples that we saw, not including
258*7c478bd9Sstevel@tonic-gate  *	any CISTPL_END or CISTPL_NULL tuples if there were no problems
259*7c478bd9Sstevel@tonic-gate  *	processing the CIS.  If a tuple handler returns an error, we
260*7c478bd9Sstevel@tonic-gate  *	immediately return with the error code from the handler. An
261*7c478bd9Sstevel@tonic-gate  *	error return code will always have the HANDTPL_ERROR bit set
262*7c478bd9Sstevel@tonic-gate  *	to allow the caller to distinguish an error from a valid tuple
263*7c478bd9Sstevel@tonic-gate  *	count.
264*7c478bd9Sstevel@tonic-gate  *
265*7c478bd9Sstevel@tonic-gate  * The nchains and ntuples counters in  the cis_info_t structure are also
266*7c478bd9Sstevel@tonic-gate  *	updated to reflect the number of chains and number of tuples in
267*7c478bd9Sstevel@tonic-gate  *	this chain.
268*7c478bd9Sstevel@tonic-gate  *
269*7c478bd9Sstevel@tonic-gate  * XXX need to add CISTPL_END and CISTPL_NULL tuples to the list, and need
270*7c478bd9Sstevel@tonic-gate  *	to be sure that the tuple count reflects these tuples
271*7c478bd9Sstevel@tonic-gate  *
272*7c478bd9Sstevel@tonic-gate  * If we attempt to read beyond the end of the mapped in CIS address space,
273*7c478bd9Sstevel@tonic-gate  *	the BAD_CIS_ADDR error code is returned.
274*7c478bd9Sstevel@tonic-gate  *
275*7c478bd9Sstevel@tonic-gate  * This function only interprets the CISTPL_END and CISTPL_NULL tuples as
276*7c478bd9Sstevel@tonic-gate  *	well as any tuple with a link field of CISTPL_END.
277*7c478bd9Sstevel@tonic-gate  *
278*7c478bd9Sstevel@tonic-gate  * Tuples of type CISTPL_END or CISTPL_NULL are not added to the list.
279*7c478bd9Sstevel@tonic-gate  *
280*7c478bd9Sstevel@tonic-gate  * To append tuples to end of a local linked CIS list, pass a pointer to the
281*7c478bd9Sstevel@tonic-gate  *	address of the last element in the list that you want tuples appended
282*7c478bd9Sstevel@tonic-gate  *	to. This pointer should be passed in cis_info->cis.
283*7c478bd9Sstevel@tonic-gate  *
284*7c478bd9Sstevel@tonic-gate  * To process tuple chains with any long link targets, call this routine
285*7c478bd9Sstevel@tonic-gate  *	for each tuple chain you want to process using the list append method
286*7c478bd9Sstevel@tonic-gate  *	described above.  The caller is responsible for vaildating any link
287*7c478bd9Sstevel@tonic-gate  *	target tuples to be sure that they describe a valid CIS chain.
288*7c478bd9Sstevel@tonic-gate  *
289*7c478bd9Sstevel@tonic-gate  * The cis_info->flags member is updated as follows:
290*7c478bd9Sstevel@tonic-gate  *
291*7c478bd9Sstevel@tonic-gate  *		CW_VALID_CIS - if the CIS is valid
292*7c478bd9Sstevel@tonic-gate  *		CW_LONGLINK_MFC_FOUND - if a CISTPL_LONGLINK_MFC tuple
293*7c478bd9Sstevel@tonic-gate  *					was seen
294*7c478bd9Sstevel@tonic-gate  *		CW_LONGLINK_A_FOUND - if a CISTPL_LONGLINK_A tuple was
295*7c478bd9Sstevel@tonic-gate  *					seen
296*7c478bd9Sstevel@tonic-gate  *		CW_LONGLINK_C_FOUND - if a CISTPL_LONGLINK_C tuple was
297*7c478bd9Sstevel@tonic-gate  *					seen
298*7c478bd9Sstevel@tonic-gate  *
299*7c478bd9Sstevel@tonic-gate  *	If a CISTPL_LONGLINK_MFC, CISTPL_LONGLINK_A or CISTPL_LONGLINK_C
300*7c478bd9Sstevel@tonic-gate  *	tuple is seen, the *cisparse argument will return an appropriate
301*7c478bd9Sstevel@tonic-gate  *	parsed longlink structure as follows:
302*7c478bd9Sstevel@tonic-gate  *
303*7c478bd9Sstevel@tonic-gate  *		CW_LONGLINK_MFC_FOUND:
304*7c478bd9Sstevel@tonic-gate  *			*cisparse --> cistpl_longlink_mfc_t *
305*7c478bd9Sstevel@tonic-gate  *		CW_LONGLINK_A_FOUND, CW_LONGLINK_C_FOUND:
306*7c478bd9Sstevel@tonic-gate  *			*cisparse --> cistpl_longlink_ac_t *
307*7c478bd9Sstevel@tonic-gate  *
308*7c478bd9Sstevel@tonic-gate  *	These flags are set and the tuples are parsed so that the caller does
309*7c478bd9Sstevel@tonic-gate  *	not have to traverse the CIS list to find out if any of these tuples
310*7c478bd9Sstevel@tonic-gate  *	have been seen.
311*7c478bd9Sstevel@tonic-gate  *
312*7c478bd9Sstevel@tonic-gate  * For each tuple that we see, the following flags in the tuple_t->flags member
313*7c478bd9Sstevel@tonic-gate  *	are set/cleared:
314*7c478bd9Sstevel@tonic-gate  *
315*7c478bd9Sstevel@tonic-gate  *		CISTPLF_COPYOK - OK to copy tuple data
316*7c478bd9Sstevel@tonic-gate  *		CISTPLF_GLOBAL_CIS - tuple from global CIS
317*7c478bd9Sstevel@tonic-gate  *		CISTPLF_MF_CIS - tuple from MF CIS chain
318*7c478bd9Sstevel@tonic-gate  *		CISTPLF_FROM_AM - tuple read from AM space
319*7c478bd9Sstevel@tonic-gate  *		CISTPLF_FROM_CM - tuple read from CM space
320*7c478bd9Sstevel@tonic-gate  *		CISTPLF_LINK_INVALID - tuple link is invalid
321*7c478bd9Sstevel@tonic-gate  *		CISTPLF_PARAMS_INVALID - tuple body is invalid
322*7c478bd9Sstevel@tonic-gate  *		CISTPLF_AM_SPACE - this tuple is in AM space
323*7c478bd9Sstevel@tonic-gate  *		CISTPLF_CM_SPACE - this tuple is in CM space
324*7c478bd9Sstevel@tonic-gate  *		CISTPLF_LM_SPACE - this tuple is in local memory
325*7c478bd9Sstevel@tonic-gate  */
326*7c478bd9Sstevel@tonic-gate uint32_t
327*7c478bd9Sstevel@tonic-gate cis_list_lcreate(cistpl_callout_t *cistpl_callout, cisptr_t *cisptr,
328*7c478bd9Sstevel@tonic-gate     cis_info_t *cis_info, cisparse_t *cisparse, cs_socket_t *sp)
329*7c478bd9Sstevel@tonic-gate {
330*7c478bd9Sstevel@tonic-gate 	cistpl_t *cp, *tp = NULL;
331*7c478bd9Sstevel@tonic-gate 	cisdata_t tl, td, *dp;
332*7c478bd9Sstevel@tonic-gate 	int done = 0, err;
333*7c478bd9Sstevel@tonic-gate 	get_socket_t get_socket;
334*7c478bd9Sstevel@tonic-gate 
335*7c478bd9Sstevel@tonic-gate 
336*7c478bd9Sstevel@tonic-gate 	/*
337*7c478bd9Sstevel@tonic-gate 	 * If we were passed a non-NULL list base, that means that we should
338*7c478bd9Sstevel@tonic-gate 	 *	parse the CIS and add any tuples we find to the end of the list
339*7c478bd9Sstevel@tonic-gate 	 *	we were handed a pointer to.
340*7c478bd9Sstevel@tonic-gate 	 */
341*7c478bd9Sstevel@tonic-gate 	if (cis_info->cis) {
342*7c478bd9Sstevel@tonic-gate 		tp = cis_info->cis;
343*7c478bd9Sstevel@tonic-gate 	}
344*7c478bd9Sstevel@tonic-gate 
345*7c478bd9Sstevel@tonic-gate 	get_socket.socket = sp->socket_num;
346*7c478bd9Sstevel@tonic-gate 	if (SocketServices(SS_GetSocket, &get_socket) != SUCCESS) {
347*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT,
348*7c478bd9Sstevel@tonic-gate 		    "cis_list_lcreate: socket %d SS_GetSocket failed\n",
349*7c478bd9Sstevel@tonic-gate 		    sp->socket_num);
350*7c478bd9Sstevel@tonic-gate 		return (CS_BAD_SOCKET);
351*7c478bd9Sstevel@tonic-gate 	}
352*7c478bd9Sstevel@tonic-gate 
353*7c478bd9Sstevel@tonic-gate 	/*
354*7c478bd9Sstevel@tonic-gate 	 * If this is primary CIS chain, the first tuple must be one
355*7c478bd9Sstevel@tonic-gate 	 *	from the following list.
356*7c478bd9Sstevel@tonic-gate 	 * Ref. PC Card 95, Metaformat Specification, Page 7.
357*7c478bd9Sstevel@tonic-gate 	 * XXX Need to think this out a bit more to deal with 3.3V
358*7c478bd9Sstevel@tonic-gate 	 *	cards and the description of where a CISTPL_DEVICE
359*7c478bd9Sstevel@tonic-gate 	 *	can show up.
360*7c478bd9Sstevel@tonic-gate 	 */
361*7c478bd9Sstevel@tonic-gate 
362*7c478bd9Sstevel@tonic-gate #if defined(CIS_DEBUG)
363*7c478bd9Sstevel@tonic-gate 	if (cis_debug > 1) {
364*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "cis_list_lcreate: td=0x%x cisptr=%p\n",
365*7c478bd9Sstevel@tonic-gate 		    GET_CIS_DATA(cisptr), (void *)cisptr);
366*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "\t flags=0x%x CW_CHECK_PRIMARY_CHAIN=0x%x\n",
367*7c478bd9Sstevel@tonic-gate 		    cis_info->flags,  CW_CHECK_PRIMARY_CHAIN);
368*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "\t IFType=0x%x IF_MEMORY=0x%x\n",
369*7c478bd9Sstevel@tonic-gate 		    get_socket.IFType, IF_MEMORY);
370*7c478bd9Sstevel@tonic-gate 	}
371*7c478bd9Sstevel@tonic-gate #endif
372*7c478bd9Sstevel@tonic-gate 
373*7c478bd9Sstevel@tonic-gate 	if (cis_info->flags & CW_CHECK_PRIMARY_CHAIN) {
374*7c478bd9Sstevel@tonic-gate 	switch (td = GET_CIS_DATA(cisptr)) {
375*7c478bd9Sstevel@tonic-gate 		case CISTPL_DEVICE:
376*7c478bd9Sstevel@tonic-gate 		case CISTPL_END:
377*7c478bd9Sstevel@tonic-gate 		case CISTPL_LINKTARGET:
378*7c478bd9Sstevel@tonic-gate 		    break;
379*7c478bd9Sstevel@tonic-gate 		case CISTPL_NULL:
380*7c478bd9Sstevel@tonic-gate 		/*
381*7c478bd9Sstevel@tonic-gate 		 * Magicram memory cards without attribute memory
382*7c478bd9Sstevel@tonic-gate 		 * do not have a CIS and return CISTPL_NULL.
383*7c478bd9Sstevel@tonic-gate 		 */
384*7c478bd9Sstevel@tonic-gate 		    if (get_socket.IFType == IF_MEMORY)
385*7c478bd9Sstevel@tonic-gate 			return (0);
386*7c478bd9Sstevel@tonic-gate 		    break;
387*7c478bd9Sstevel@tonic-gate 
388*7c478bd9Sstevel@tonic-gate 		default:
389*7c478bd9Sstevel@tonic-gate 		    return (0);
390*7c478bd9Sstevel@tonic-gate 	    } /* switch */
391*7c478bd9Sstevel@tonic-gate 	} /* CW_CHECK_PRIMARY_CHAIN */
392*7c478bd9Sstevel@tonic-gate 
393*7c478bd9Sstevel@tonic-gate 	/*
394*7c478bd9Sstevel@tonic-gate 	 * Update the number of chains counter
395*7c478bd9Sstevel@tonic-gate 	 */
396*7c478bd9Sstevel@tonic-gate 	cis_info->nchains++;
397*7c478bd9Sstevel@tonic-gate 
398*7c478bd9Sstevel@tonic-gate 	/*
399*7c478bd9Sstevel@tonic-gate 	 * The main tuple processing loop.  We'll exit this loop when either
400*7c478bd9Sstevel@tonic-gate 	 *	a tuple's link field is CISTPL_END or we've seen a tuple type
401*7c478bd9Sstevel@tonic-gate 	 *	field of CISTPL_END.
402*7c478bd9Sstevel@tonic-gate 	 *
403*7c478bd9Sstevel@tonic-gate 	 * Note that we also silently throw away CISTPL_NULL tuples, and don't
404*7c478bd9Sstevel@tonic-gate 	 *	include them in the tuple count that we return.
405*7c478bd9Sstevel@tonic-gate 	 */
406*7c478bd9Sstevel@tonic-gate 	while (!done && ((td = GET_CIS_DATA(cisptr)) !=
407*7c478bd9Sstevel@tonic-gate 						(cisdata_t)CISTPL_END)) {
408*7c478bd9Sstevel@tonic-gate 
409*7c478bd9Sstevel@tonic-gate #if defined(CIS_DEBUG)
410*7c478bd9Sstevel@tonic-gate 		if ((cis_debug > 1) && (td != 0)) {
411*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "cis_list_lcreate: td=0x%x cisptr=%p"
412*7c478bd9Sstevel@tonic-gate 			    "offset=0x%x\n",
413*7c478bd9Sstevel@tonic-gate 			    td, (void *)cisptr, cisptr->offset);
414*7c478bd9Sstevel@tonic-gate 		}
415*7c478bd9Sstevel@tonic-gate #endif
416*7c478bd9Sstevel@tonic-gate 
417*7c478bd9Sstevel@tonic-gate 		/*
418*7c478bd9Sstevel@tonic-gate 		 * Ignore CISTPL_NULL tuples
419*7c478bd9Sstevel@tonic-gate 		 */
420*7c478bd9Sstevel@tonic-gate 		if (td != (cisdata_t)CISTPL_NULL) {
421*7c478bd9Sstevel@tonic-gate 			/*
422*7c478bd9Sstevel@tonic-gate 			 * point to tuple link field and get the link value
423*7c478bd9Sstevel@tonic-gate 			 */
424*7c478bd9Sstevel@tonic-gate 			if (!NEXT_CIS_ADDR(cisptr))
425*7c478bd9Sstevel@tonic-gate 			    return ((uint32_t)BAD_CIS_ADDR);
426*7c478bd9Sstevel@tonic-gate 			tl = GET_CIS_DATA(cisptr);
427*7c478bd9Sstevel@tonic-gate 		/*
428*7c478bd9Sstevel@tonic-gate 		 * This is an ugly PCMCIA hack - ugh! since the standard allows
429*7c478bd9Sstevel@tonic-gate 		 *	a link byte of CISTPL_END to signify that this is the
430*7c478bd9Sstevel@tonic-gate 		 *	last tuple.  The problem is that this tuple might
431*7c478bd9Sstevel@tonic-gate 		 *	actually contain useful information, but we don't know
432*7c478bd9Sstevel@tonic-gate 		 *	the size of it.
433*7c478bd9Sstevel@tonic-gate 		 * We do know that it can't be more than CIS_MAX_TUPLE_DATA_LEN
434*7c478bd9Sstevel@tonic-gate 		 *	bytes in length, however.  So, we pretend that the link
435*7c478bd9Sstevel@tonic-gate 		 *	byte is CIS_MAX_TUPLE_DATA_LEN and also set a flag so
436*7c478bd9Sstevel@tonic-gate 		 *	that when we're done processing this tuple, we will
437*7c478bd9Sstevel@tonic-gate 		 *	break out of the while loop.
438*7c478bd9Sstevel@tonic-gate 		 */
439*7c478bd9Sstevel@tonic-gate 			if (tl == (cisdata_t)CISTPL_END) {
440*7c478bd9Sstevel@tonic-gate 				tl = CIS_MAX_TUPLE_DATA_LEN;
441*7c478bd9Sstevel@tonic-gate 				done = 1;
442*7c478bd9Sstevel@tonic-gate 			}
443*7c478bd9Sstevel@tonic-gate 
444*7c478bd9Sstevel@tonic-gate 		/*
445*7c478bd9Sstevel@tonic-gate 		 * point to first byte of tuple data, allocate a new list
446*7c478bd9Sstevel@tonic-gate 		 *	element and diddle with the list base and list
447*7c478bd9Sstevel@tonic-gate 		 *	control pointers
448*7c478bd9Sstevel@tonic-gate 		 */
449*7c478bd9Sstevel@tonic-gate 			if (!NEXT_CIS_ADDR(cisptr))
450*7c478bd9Sstevel@tonic-gate 			    return ((uint32_t)BAD_CIS_ADDR);
451*7c478bd9Sstevel@tonic-gate 			cp = (cistpl_t *)CIS_MEM_ALLOC(sizeof (cistpl_t));
452*7c478bd9Sstevel@tonic-gate 			cp->next = NULL;
453*7c478bd9Sstevel@tonic-gate 			/*
454*7c478bd9Sstevel@tonic-gate 			 * if we're not the first in the list, point to our
455*7c478bd9Sstevel@tonic-gate 			 *	next
456*7c478bd9Sstevel@tonic-gate 			 */
457*7c478bd9Sstevel@tonic-gate 			if (tp)
458*7c478bd9Sstevel@tonic-gate 				tp->next = cp;
459*7c478bd9Sstevel@tonic-gate 			/*
460*7c478bd9Sstevel@tonic-gate 			 * will be NULL if we're the first element of the
461*7c478bd9Sstevel@tonic-gate 			 *	list
462*7c478bd9Sstevel@tonic-gate 			 */
463*7c478bd9Sstevel@tonic-gate 			cp->prev = tp;
464*7c478bd9Sstevel@tonic-gate 			tp = cp;
465*7c478bd9Sstevel@tonic-gate 			/*
466*7c478bd9Sstevel@tonic-gate 			 * if this is the first element, save it's address
467*7c478bd9Sstevel@tonic-gate 			 */
468*7c478bd9Sstevel@tonic-gate 			if (!cis_info->cis)
469*7c478bd9Sstevel@tonic-gate 				cis_info->cis = tp;
470*7c478bd9Sstevel@tonic-gate 			tp->type = td;
471*7c478bd9Sstevel@tonic-gate 			tp->len = tl;
472*7c478bd9Sstevel@tonic-gate 
473*7c478bd9Sstevel@tonic-gate 			/*
474*7c478bd9Sstevel@tonic-gate 			 * Save the address in CIS space that this tuple
475*7c478bd9Sstevel@tonic-gate 			 *	begins at, as well as set tuple flags.
476*7c478bd9Sstevel@tonic-gate 			 */
477*7c478bd9Sstevel@tonic-gate 			cis_store_cis_addr(tp, cisptr);
478*7c478bd9Sstevel@tonic-gate 
479*7c478bd9Sstevel@tonic-gate 			/*
480*7c478bd9Sstevel@tonic-gate 			 * If this tuple has tuple data, we might need to
481*7c478bd9Sstevel@tonic-gate 			 *	copy it.
482*7c478bd9Sstevel@tonic-gate 			 * Note that the tuple data pointer (tp->data) will
483*7c478bd9Sstevel@tonic-gate 			 *	be set to NULL for a tuple with no data.
484*7c478bd9Sstevel@tonic-gate 			 */
485*7c478bd9Sstevel@tonic-gate #ifdef	XXX
486*7c478bd9Sstevel@tonic-gate 			if (tl) {
487*7c478bd9Sstevel@tonic-gate #endif
488*7c478bd9Sstevel@tonic-gate 			/*
489*7c478bd9Sstevel@tonic-gate 			 * Read the data in the tuple and store it
490*7c478bd9Sstevel@tonic-gate 			 *	away locally if we're allowed to. If
491*7c478bd9Sstevel@tonic-gate 			 *	the CISTPLF_COPYOK flag is set, it means
492*7c478bd9Sstevel@tonic-gate 			 *	that it's OK to touch the data portion
493*7c478bd9Sstevel@tonic-gate 			 *	of the tuple.
494*7c478bd9Sstevel@tonic-gate 			 *
495*7c478bd9Sstevel@tonic-gate 			 * We need to make this check since some
496*7c478bd9Sstevel@tonic-gate 			 *	tuples might contain active registers
497*7c478bd9Sstevel@tonic-gate 			 *	that can alter the device state if they
498*7c478bd9Sstevel@tonic-gate 			 *	are read before the card is correctly
499*7c478bd9Sstevel@tonic-gate 			 *	initialized.  What a stupid thing to
500*7c478bd9Sstevel@tonic-gate 			 *	allow in a standard, BTW.
501*7c478bd9Sstevel@tonic-gate 			 *
502*7c478bd9Sstevel@tonic-gate 			 * We first give the tuple handler a chance
503*7c478bd9Sstevel@tonic-gate 			 *	to set any tuple flags that it wants
504*7c478bd9Sstevel@tonic-gate 			 *	to, then we (optionally) do the data
505*7c478bd9Sstevel@tonic-gate 			 *	copy, and give the tuple handler another
506*7c478bd9Sstevel@tonic-gate 			 *	shot at the tuple.
507*7c478bd9Sstevel@tonic-gate 			 *
508*7c478bd9Sstevel@tonic-gate 			 * ref. PC Card Standard Release 2.01 in the
509*7c478bd9Sstevel@tonic-gate 			 *	Card Metaformat section, section 5.2.6,
510*7c478bd9Sstevel@tonic-gate 			 *	page 5-12.
511*7c478bd9Sstevel@tonic-gate 			 */
512*7c478bd9Sstevel@tonic-gate 			if ((err = cis_tuple_handler(cistpl_callout, tp,
513*7c478bd9Sstevel@tonic-gate 						HANDTPL_SET_FLAGS, NULL, 0)) &
514*7c478bd9Sstevel@tonic-gate 								HANDTPL_ERROR)
515*7c478bd9Sstevel@tonic-gate 			    return (err);
516*7c478bd9Sstevel@tonic-gate 
517*7c478bd9Sstevel@tonic-gate 			if (tl > (unsigned)0) {
518*7c478bd9Sstevel@tonic-gate 
519*7c478bd9Sstevel@tonic-gate 				/*
520*7c478bd9Sstevel@tonic-gate 				 * if we're supposed to make a local copy of
521*7c478bd9Sstevel@tonic-gate 				 *	the tuple data, allocate space for it,
522*7c478bd9Sstevel@tonic-gate 				 *	otherwise just record the PC card
523*7c478bd9Sstevel@tonic-gate 				 *	starting address of this tuple.
524*7c478bd9Sstevel@tonic-gate 				 * The address was saved by cis_store_cis_addr.
525*7c478bd9Sstevel@tonic-gate 				 */
526*7c478bd9Sstevel@tonic-gate 				if (tp->flags & CISTPLF_COPYOK) {
527*7c478bd9Sstevel@tonic-gate 				    tp->data = (cisdata_t *)CIS_MEM_ALLOC(tl);
528*7c478bd9Sstevel@tonic-gate 				    dp = tp->data;
529*7c478bd9Sstevel@tonic-gate 				} else {
530*7c478bd9Sstevel@tonic-gate 				    tp->data = GET_CIS_ADDR(tp);
531*7c478bd9Sstevel@tonic-gate 				}
532*7c478bd9Sstevel@tonic-gate 
533*7c478bd9Sstevel@tonic-gate 				while (tl--) {
534*7c478bd9Sstevel@tonic-gate 				    if (tp->flags & CISTPLF_COPYOK)
535*7c478bd9Sstevel@tonic-gate 					*dp++ = GET_CIS_DATA(cisptr);
536*7c478bd9Sstevel@tonic-gate 				    if (!NEXT_CIS_ADDR(cisptr))
537*7c478bd9Sstevel@tonic-gate 					return ((uint32_t)BAD_CIS_ADDR);
538*7c478bd9Sstevel@tonic-gate 				}
539*7c478bd9Sstevel@tonic-gate 
540*7c478bd9Sstevel@tonic-gate 				/*
541*7c478bd9Sstevel@tonic-gate 				 * If we made a local copy of the tuple data,
542*7c478bd9Sstevel@tonic-gate 				 *	then clear the AM and CM flags; if the
543*7c478bd9Sstevel@tonic-gate 				 *	tuple data is still on the card, then
544*7c478bd9Sstevel@tonic-gate 				 *	leave the flags alone.
545*7c478bd9Sstevel@tonic-gate 				 */
546*7c478bd9Sstevel@tonic-gate 				if (tp->flags & CISTPLF_COPYOK) {
547*7c478bd9Sstevel@tonic-gate 				    tp->flags &= ~CISTPLF_SPACE_MASK;
548*7c478bd9Sstevel@tonic-gate 				    tp->flags |= CISTPLF_LM_SPACE;
549*7c478bd9Sstevel@tonic-gate 				}
550*7c478bd9Sstevel@tonic-gate 
551*7c478bd9Sstevel@tonic-gate 			/*
552*7c478bd9Sstevel@tonic-gate 			 * This is a tuple with no data in it's body, so
553*7c478bd9Sstevel@tonic-gate 			 *	we just set the data pointer to NULL.
554*7c478bd9Sstevel@tonic-gate 			 */
555*7c478bd9Sstevel@tonic-gate 			} else {
556*7c478bd9Sstevel@tonic-gate 
557*7c478bd9Sstevel@tonic-gate 			    tp->data = NULL;
558*7c478bd9Sstevel@tonic-gate 				/*
559*7c478bd9Sstevel@tonic-gate 				 * tp->flags &= ~(CISTPLF_SPACE_MASK |
560*7c478bd9Sstevel@tonic-gate 				 *		CISTPLF_FROM_MASK);
561*7c478bd9Sstevel@tonic-gate 				 */
562*7c478bd9Sstevel@tonic-gate 
563*7c478bd9Sstevel@tonic-gate 			} /* if (tl > 0) */
564*7c478bd9Sstevel@tonic-gate 
565*7c478bd9Sstevel@tonic-gate 			/*
566*7c478bd9Sstevel@tonic-gate 			 * The main idea behind this call is to give
567*7c478bd9Sstevel@tonic-gate 			 *	the handler a chance to validate the
568*7c478bd9Sstevel@tonic-gate 			 *	tuple.
569*7c478bd9Sstevel@tonic-gate 			 */
570*7c478bd9Sstevel@tonic-gate 			if ((err = cis_tuple_handler(cistpl_callout, tp,
571*7c478bd9Sstevel@tonic-gate 						HANDTPL_COPY_DONE, NULL, 0)) &
572*7c478bd9Sstevel@tonic-gate 								HANDTPL_ERROR)
573*7c478bd9Sstevel@tonic-gate 			    return (err);
574*7c478bd9Sstevel@tonic-gate 
575*7c478bd9Sstevel@tonic-gate #ifdef	XXX
576*7c478bd9Sstevel@tonic-gate 			} else { /* if (tl) */
577*7c478bd9Sstevel@tonic-gate 			    tp->data = NULL;
578*7c478bd9Sstevel@tonic-gate 			}
579*7c478bd9Sstevel@tonic-gate #endif
580*7c478bd9Sstevel@tonic-gate 
581*7c478bd9Sstevel@tonic-gate 			/*
582*7c478bd9Sstevel@tonic-gate 			 * Check to see if this is a longlink tuple and if
583*7c478bd9Sstevel@tonic-gate 			 *	so, do the necessary processing.
584*7c478bd9Sstevel@tonic-gate 			 */
585*7c478bd9Sstevel@tonic-gate 			if ((err = cis_process_longlink(cistpl_callout, tp,
586*7c478bd9Sstevel@tonic-gate 								cis_info,
587*7c478bd9Sstevel@tonic-gate 								cisparse)) &
588*7c478bd9Sstevel@tonic-gate 								HANDTPL_ERROR)
589*7c478bd9Sstevel@tonic-gate 			    return (err);
590*7c478bd9Sstevel@tonic-gate 
591*7c478bd9Sstevel@tonic-gate 			cis_info->ntuples++;
592*7c478bd9Sstevel@tonic-gate 		} else { /* if (td == CISTPL_NULL) */
593*7c478bd9Sstevel@tonic-gate 			/*
594*7c478bd9Sstevel@tonic-gate 			 * If we're a CISTPL_NULL we need to skip to
595*7c478bd9Sstevel@tonic-gate 			 *	the beginning of the next tuple.
596*7c478bd9Sstevel@tonic-gate 			 */
597*7c478bd9Sstevel@tonic-gate 			if (!NEXT_CIS_ADDR(cisptr))
598*7c478bd9Sstevel@tonic-gate 			    return ((uint32_t)BAD_CIS_ADDR);
599*7c478bd9Sstevel@tonic-gate 		}
600*7c478bd9Sstevel@tonic-gate 	} /* while (!done && !CISTPL_END) */
601*7c478bd9Sstevel@tonic-gate 
602*7c478bd9Sstevel@tonic-gate #if defined(CIS_DEBUG)
603*7c478bd9Sstevel@tonic-gate 	if (cis_debug > 1) {
604*7c478bd9Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cis_list_lcreate: exit nchains=%x ntuples=%x\n",
605*7c478bd9Sstevel@tonic-gate 		cis_info->nchains, cis_info->ntuples);
606*7c478bd9Sstevel@tonic-gate 	}
607*7c478bd9Sstevel@tonic-gate #endif
608*7c478bd9Sstevel@tonic-gate 
609*7c478bd9Sstevel@tonic-gate 	return (cis_info->ntuples);
610*7c478bd9Sstevel@tonic-gate }
611*7c478bd9Sstevel@tonic-gate 
612*7c478bd9Sstevel@tonic-gate /*
613*7c478bd9Sstevel@tonic-gate  * cis_process_longlink - processes longlink tuples
614*7c478bd9Sstevel@tonic-gate  *
615*7c478bd9Sstevel@tonic-gate  *	This function examines the passed-in tuple type and if it is a
616*7c478bd9Sstevel@tonic-gate  *	longlink tuple, the tuple is parsed and the appropriate flags in
617*7c478bd9Sstevel@tonic-gate  *	cis_info->flags are set.
618*7c478bd9Sstevel@tonic-gate  *
619*7c478bd9Sstevel@tonic-gate  *	If there is an error parsing the tuple, HANDTPL_ERROR is returned
620*7c478bd9Sstevel@tonic-gate  *	and the CW_LONGLINK_FOUND flags in cis_info->flags are cleared.
621*7c478bd9Sstevel@tonic-gate  */
622*7c478bd9Sstevel@tonic-gate static int
623*7c478bd9Sstevel@tonic-gate cis_process_longlink(cistpl_callout_t *cistpl_callout, cistpl_t *tp,
624*7c478bd9Sstevel@tonic-gate 				cis_info_t *cis_info, cisparse_t *cisparse)
625*7c478bd9Sstevel@tonic-gate {
626*7c478bd9Sstevel@tonic-gate 	/*
627*7c478bd9Sstevel@tonic-gate 	 * If this is a CISTPL_LONGLINK_A, CISTPL_LONGLINK_C
628*7c478bd9Sstevel@tonic-gate 	 *	or CISTPL_LONGLINK_MFC tuple, parse the tuple
629*7c478bd9Sstevel@tonic-gate 	 *	and set appropriate CW_LONGLINK_XXX_FOUND flags.
630*7c478bd9Sstevel@tonic-gate 	 * If this is a CISTPL_NO_LINK tuple, or if there is an
631*7c478bd9Sstevel@tonic-gate 	 *	error parsing the tuple, clear all the
632*7c478bd9Sstevel@tonic-gate 	 *	CW_LONGLINK_XXX_FOUND flags.
633*7c478bd9Sstevel@tonic-gate 	 */
634*7c478bd9Sstevel@tonic-gate 	switch (tp->type) {
635*7c478bd9Sstevel@tonic-gate 	    case CISTPL_LONGLINK_A:
636*7c478bd9Sstevel@tonic-gate 	    case CISTPL_LONGLINK_C:
637*7c478bd9Sstevel@tonic-gate 	    case CISTPL_LONGLINK_MFC:
638*7c478bd9Sstevel@tonic-gate 		cis_info->flags &= ~CW_LONGLINK_FOUND;
639*7c478bd9Sstevel@tonic-gate 		if (cis_tuple_handler(cistpl_callout, tp,
640*7c478bd9Sstevel@tonic-gate 						HANDTPL_PARSE_LTUPLE,
641*7c478bd9Sstevel@tonic-gate 						cisparse, NULL) &
642*7c478bd9Sstevel@tonic-gate 							HANDTPL_ERROR)
643*7c478bd9Sstevel@tonic-gate 		    return (HANDTPL_ERROR);
644*7c478bd9Sstevel@tonic-gate 		switch (tp->type) {
645*7c478bd9Sstevel@tonic-gate 		    case CISTPL_LONGLINK_A:
646*7c478bd9Sstevel@tonic-gate 			cis_info->flags |= CW_LONGLINK_A_FOUND;
647*7c478bd9Sstevel@tonic-gate 			break;
648*7c478bd9Sstevel@tonic-gate 		    case CISTPL_LONGLINK_C:
649*7c478bd9Sstevel@tonic-gate 			cis_info->flags |= CW_LONGLINK_C_FOUND;
650*7c478bd9Sstevel@tonic-gate 			break;
651*7c478bd9Sstevel@tonic-gate 		    case CISTPL_LONGLINK_MFC:
652*7c478bd9Sstevel@tonic-gate 			cis_info->flags |= CW_LONGLINK_MFC_FOUND;
653*7c478bd9Sstevel@tonic-gate 			break;
654*7c478bd9Sstevel@tonic-gate 		} /* switch (tp->type) */
655*7c478bd9Sstevel@tonic-gate 		break;
656*7c478bd9Sstevel@tonic-gate 	    case CISTPL_NO_LINK:
657*7c478bd9Sstevel@tonic-gate 		cis_info->flags &= ~CW_LONGLINK_FOUND;
658*7c478bd9Sstevel@tonic-gate 		break;
659*7c478bd9Sstevel@tonic-gate 	} /* switch (tp->type) */
660*7c478bd9Sstevel@tonic-gate 
661*7c478bd9Sstevel@tonic-gate 	return (HANDTPL_NOERROR);
662*7c478bd9Sstevel@tonic-gate }
663*7c478bd9Sstevel@tonic-gate 
664*7c478bd9Sstevel@tonic-gate /*
665*7c478bd9Sstevel@tonic-gate  * cis_list_ldestroy - function to destroy a linked tuple list
666*7c478bd9Sstevel@tonic-gate  *
667*7c478bd9Sstevel@tonic-gate  *	cistpl_t *cistplbase - pointer to a pointer to the base of a
668*7c478bd9Sstevel@tonic-gate  *				local linked CIS list to destroy; the
669*7c478bd9Sstevel@tonic-gate  *				data that this pointer points to is
670*7c478bd9Sstevel@tonic-gate  *				also destroyed
671*7c478bd9Sstevel@tonic-gate  *
672*7c478bd9Sstevel@tonic-gate  * Once this function returns, cistplbase is set to NULL.
673*7c478bd9Sstevel@tonic-gate  */
674*7c478bd9Sstevel@tonic-gate uint32_t
675*7c478bd9Sstevel@tonic-gate cis_list_ldestroy(cistpl_t **cistplbase)
676*7c478bd9Sstevel@tonic-gate {
677*7c478bd9Sstevel@tonic-gate 	cistpl_t *cp, *tp;
678*7c478bd9Sstevel@tonic-gate 	int tpcnt = 0;
679*7c478bd9Sstevel@tonic-gate 
680*7c478bd9Sstevel@tonic-gate 	/*
681*7c478bd9Sstevel@tonic-gate 	 * First, check to see if we've got a
682*7c478bd9Sstevel@tonic-gate 	 *	non-NULL list pointer.
683*7c478bd9Sstevel@tonic-gate 	 */
684*7c478bd9Sstevel@tonic-gate 	if ((tp = *cistplbase) == NULL)
685*7c478bd9Sstevel@tonic-gate 	    return (0);
686*7c478bd9Sstevel@tonic-gate 
687*7c478bd9Sstevel@tonic-gate 	while (tp) {
688*7c478bd9Sstevel@tonic-gate 		/*
689*7c478bd9Sstevel@tonic-gate 		 * Free any data that may be allocated
690*7c478bd9Sstevel@tonic-gate 		 */
691*7c478bd9Sstevel@tonic-gate 	    if ((tp->flags & CISTPLF_COPYOK) &&
692*7c478bd9Sstevel@tonic-gate 			(tp->flags & CISTPLF_LM_SPACE) &&
693*7c478bd9Sstevel@tonic-gate 						(tp->data))
694*7c478bd9Sstevel@tonic-gate 		CIS_MEM_FREE((caddr_t)tp->data);
695*7c478bd9Sstevel@tonic-gate 
696*7c478bd9Sstevel@tonic-gate 	    cp = tp->next;
697*7c478bd9Sstevel@tonic-gate 
698*7c478bd9Sstevel@tonic-gate 		/*
699*7c478bd9Sstevel@tonic-gate 		 * Free this tuple
700*7c478bd9Sstevel@tonic-gate 		 */
701*7c478bd9Sstevel@tonic-gate 	    CIS_MEM_FREE((caddr_t)tp);
702*7c478bd9Sstevel@tonic-gate 
703*7c478bd9Sstevel@tonic-gate 	    tp = cp;
704*7c478bd9Sstevel@tonic-gate 
705*7c478bd9Sstevel@tonic-gate 	    tpcnt++;
706*7c478bd9Sstevel@tonic-gate 	}
707*7c478bd9Sstevel@tonic-gate 
708*7c478bd9Sstevel@tonic-gate 	/*
709*7c478bd9Sstevel@tonic-gate 	 * Now clear the pointer to the non-existant
710*7c478bd9Sstevel@tonic-gate 	 *	linked list.
711*7c478bd9Sstevel@tonic-gate 	 */
712*7c478bd9Sstevel@tonic-gate 	*cistplbase = NULL;
713*7c478bd9Sstevel@tonic-gate 
714*7c478bd9Sstevel@tonic-gate 	return (tpcnt);
715*7c478bd9Sstevel@tonic-gate 
716*7c478bd9Sstevel@tonic-gate }
717*7c478bd9Sstevel@tonic-gate 
718*7c478bd9Sstevel@tonic-gate /*
719*7c478bd9Sstevel@tonic-gate  * cis_get_ltuple - function to walk local linked CIS list and return
720*7c478bd9Sstevel@tonic-gate  *			a tuple based on various criteria
721*7c478bd9Sstevel@tonic-gate  *
722*7c478bd9Sstevel@tonic-gate  *	cistpl_t *tp - pointer to any valid tuple in the list
723*7c478bd9Sstevel@tonic-gate  *	cisdata_t type - type of tuple to search for
724*7c478bd9Sstevel@tonic-gate  *	int flags - type of action to perform (each is mutually exclusive)
725*7c478bd9Sstevel@tonic-gate  *		GET_FIRST_LTUPLEF, GET_LAST_LTUPLEF:
726*7c478bd9Sstevel@tonic-gate  *		    Returns the {first|last} tuple in the list.
727*7c478bd9Sstevel@tonic-gate  *		FIND_LTUPLE_FWDF, FIND_LTUPLE_BACKF:
728*7c478bd9Sstevel@tonic-gate  *		FIND_NEXT_LTUPLEF, FIND_PREV_LTUPLEF:
729*7c478bd9Sstevel@tonic-gate  *		    Returns the first tuple that matches the passed tuple type,
730*7c478bd9Sstevel@tonic-gate  *			searching the list {forward|backward}.
731*7c478bd9Sstevel@tonic-gate  *		GET_NEXT_LTUPLEF, GET_PREV_LTUPLEF:
732*7c478bd9Sstevel@tonic-gate  *		    Returns the {next|previous} tuple in the list.
733*7c478bd9Sstevel@tonic-gate  *
734*7c478bd9Sstevel@tonic-gate  *	    The following bits can be set in the flags parameter:
735*7c478bd9Sstevel@tonic-gate  *		CIS_GET_LTUPLE_IGNORE - return tuples with
736*7c478bd9Sstevel@tonic-gate  *				CISTPLF_IGNORE_TUPLE set in cistpl_t->flags
737*7c478bd9Sstevel@tonic-gate  *
738*7c478bd9Sstevel@tonic-gate  * Note on searching:
739*7c478bd9Sstevel@tonic-gate  *	When using the FIND_LTUPLE_FWDF and FIND_LTUPLE_BACKF flags,
740*7c478bd9Sstevel@tonic-gate  *	the search starts at the passed tuple.  Continually calling this
741*7c478bd9Sstevel@tonic-gate  *	function with a tuple that is the same type as the passed type will
742*7c478bd9Sstevel@tonic-gate  *	continually return the same tuple.
743*7c478bd9Sstevel@tonic-gate  *
744*7c478bd9Sstevel@tonic-gate  *	When using the FIND_NEXT_LTUPLEF and FIND_PREV_LTUPLEF flags,
745*7c478bd9Sstevel@tonic-gate  *	the search starts at the {next|previous} tuple from the passed tuple.
746*7c478bd9Sstevel@tonic-gate  *
747*7c478bd9Sstevel@tonic-gate  * returns:
748*7c478bd9Sstevel@tonic-gate  *	cistpl_t * - pointer to tuple in list
749*7c478bd9Sstevel@tonic-gate  *	NULL - if error while processing list or tuple not found
750*7c478bd9Sstevel@tonic-gate  */
751*7c478bd9Sstevel@tonic-gate #define	GET_NEXT_LTUPLE(tp)	((tp->next)?tp->next:NULL)
752*7c478bd9Sstevel@tonic-gate #define	GET_PREV_LTUPLE(tp)	((tp->prev)?tp->prev:NULL)
753*7c478bd9Sstevel@tonic-gate cistpl_t *
754*7c478bd9Sstevel@tonic-gate cis_get_ltuple(cistpl_t *tp, cisdata_t type, uint32_t flags)
755*7c478bd9Sstevel@tonic-gate {
756*7c478bd9Sstevel@tonic-gate 	cistpl_t *ltp = NULL;
757*7c478bd9Sstevel@tonic-gate 
758*7c478bd9Sstevel@tonic-gate 	if (!tp)
759*7c478bd9Sstevel@tonic-gate 	    return (NULL);
760*7c478bd9Sstevel@tonic-gate 
761*7c478bd9Sstevel@tonic-gate 	switch (flags & CIS_GET_LTUPLE_OPMASK) {
762*7c478bd9Sstevel@tonic-gate 	    case GET_FIRST_LTUPLEF:	/* return first tuple in list */
763*7c478bd9Sstevel@tonic-gate 		do {
764*7c478bd9Sstevel@tonic-gate 			ltp = tp;
765*7c478bd9Sstevel@tonic-gate 		} while ((tp = GET_PREV_LTUPLE(tp)) != NULL);
766*7c478bd9Sstevel@tonic-gate 
767*7c478bd9Sstevel@tonic-gate 		if (!(flags & CIS_GET_LTUPLE_IGNORE))
768*7c478bd9Sstevel@tonic-gate 		    while (ltp && (ltp->flags & CISTPLF_IGNORE_TUPLE))
769*7c478bd9Sstevel@tonic-gate 			ltp = GET_NEXT_LTUPLE(ltp);
770*7c478bd9Sstevel@tonic-gate 		break;
771*7c478bd9Sstevel@tonic-gate 	    case GET_LAST_LTUPLEF:	/* return last tuple in list */
772*7c478bd9Sstevel@tonic-gate 		do {
773*7c478bd9Sstevel@tonic-gate 			ltp = tp;
774*7c478bd9Sstevel@tonic-gate 		} while ((tp = GET_NEXT_LTUPLE(tp)) != NULL);
775*7c478bd9Sstevel@tonic-gate 
776*7c478bd9Sstevel@tonic-gate 		if (!(flags & CIS_GET_LTUPLE_IGNORE))
777*7c478bd9Sstevel@tonic-gate 		    while (ltp && (ltp->flags & CISTPLF_IGNORE_TUPLE))
778*7c478bd9Sstevel@tonic-gate 			ltp = GET_PREV_LTUPLE(ltp);
779*7c478bd9Sstevel@tonic-gate 		break;
780*7c478bd9Sstevel@tonic-gate 	    case FIND_LTUPLE_FWDF:	/* find tuple, fwd search from tp */
781*7c478bd9Sstevel@tonic-gate 		do {
782*7c478bd9Sstevel@tonic-gate 			if (tp->type == type)
783*7c478bd9Sstevel@tonic-gate 			    if ((flags & CIS_GET_LTUPLE_IGNORE) ||
784*7c478bd9Sstevel@tonic-gate 					(!(tp->flags & CISTPLF_IGNORE_TUPLE)))
785*7c478bd9Sstevel@tonic-gate 				return (tp);	/* note return here */
786*7c478bd9Sstevel@tonic-gate 		} while ((tp = GET_NEXT_LTUPLE(tp)) != NULL);
787*7c478bd9Sstevel@tonic-gate 		break;
788*7c478bd9Sstevel@tonic-gate 	    case FIND_LTUPLE_BACKF:
789*7c478bd9Sstevel@tonic-gate 		/* find tuple, backward search from tp */
790*7c478bd9Sstevel@tonic-gate 		do {
791*7c478bd9Sstevel@tonic-gate 			if (tp->type == type)
792*7c478bd9Sstevel@tonic-gate 			    if ((flags & CIS_GET_LTUPLE_IGNORE) ||
793*7c478bd9Sstevel@tonic-gate 					(!(tp->flags & CISTPLF_IGNORE_TUPLE)))
794*7c478bd9Sstevel@tonic-gate 				return (tp);	/* note return here */
795*7c478bd9Sstevel@tonic-gate 		} while ((tp = GET_PREV_LTUPLE(tp)) != NULL);
796*7c478bd9Sstevel@tonic-gate 		break;
797*7c478bd9Sstevel@tonic-gate 	    case FIND_NEXT_LTUPLEF:	/* find tuple, fwd search from tp+1 */
798*7c478bd9Sstevel@tonic-gate 		while ((tp = GET_NEXT_LTUPLE(tp)) != NULL) {
799*7c478bd9Sstevel@tonic-gate 			if (tp->type == type)
800*7c478bd9Sstevel@tonic-gate 			    if ((flags & CIS_GET_LTUPLE_IGNORE) ||
801*7c478bd9Sstevel@tonic-gate 					(!(tp->flags & CISTPLF_IGNORE_TUPLE)))
802*7c478bd9Sstevel@tonic-gate 				return (tp);	/* note return here */
803*7c478bd9Sstevel@tonic-gate 		} /* while */
804*7c478bd9Sstevel@tonic-gate 		break;
805*7c478bd9Sstevel@tonic-gate 	    case FIND_PREV_LTUPLEF:
806*7c478bd9Sstevel@tonic-gate 		/* find tuple, backward search from tp-1 */
807*7c478bd9Sstevel@tonic-gate 		while ((tp = GET_PREV_LTUPLE(tp)) != NULL) {
808*7c478bd9Sstevel@tonic-gate 			if (tp->type == type)
809*7c478bd9Sstevel@tonic-gate 			    if ((flags & CIS_GET_LTUPLE_IGNORE) ||
810*7c478bd9Sstevel@tonic-gate 					(!(tp->flags & CISTPLF_IGNORE_TUPLE)))
811*7c478bd9Sstevel@tonic-gate 				return (tp);	/* note return here */
812*7c478bd9Sstevel@tonic-gate 		} /* while */
813*7c478bd9Sstevel@tonic-gate 		break;
814*7c478bd9Sstevel@tonic-gate 	    case GET_NEXT_LTUPLEF:	/* return next tuple in list */
815*7c478bd9Sstevel@tonic-gate 		ltp = tp;
816*7c478bd9Sstevel@tonic-gate 		while (((ltp = GET_NEXT_LTUPLE(ltp)) != NULL) &&
817*7c478bd9Sstevel@tonic-gate 				(!(flags & CIS_GET_LTUPLE_IGNORE)) &&
818*7c478bd9Sstevel@tonic-gate 					(ltp->flags & CISTPLF_IGNORE_TUPLE))
819*7c478bd9Sstevel@tonic-gate 			;
820*7c478bd9Sstevel@tonic-gate 		break;
821*7c478bd9Sstevel@tonic-gate 	    case GET_PREV_LTUPLEF:	/* return prev tuple in list */
822*7c478bd9Sstevel@tonic-gate 		ltp = tp;
823*7c478bd9Sstevel@tonic-gate 		while (((ltp = GET_PREV_LTUPLE(ltp)) != NULL) &&
824*7c478bd9Sstevel@tonic-gate 				(!(flags & CIS_GET_LTUPLE_IGNORE)) &&
825*7c478bd9Sstevel@tonic-gate 					(ltp->flags & CISTPLF_IGNORE_TUPLE))
826*7c478bd9Sstevel@tonic-gate 			;
827*7c478bd9Sstevel@tonic-gate 		break;
828*7c478bd9Sstevel@tonic-gate 	    default:	/* ltp is already NULL in the initialization */
829*7c478bd9Sstevel@tonic-gate 		break;
830*7c478bd9Sstevel@tonic-gate 	} /* switch */
831*7c478bd9Sstevel@tonic-gate 
832*7c478bd9Sstevel@tonic-gate 	return (ltp);
833*7c478bd9Sstevel@tonic-gate }
834*7c478bd9Sstevel@tonic-gate 
835*7c478bd9Sstevel@tonic-gate /*
836*7c478bd9Sstevel@tonic-gate  * cis_convert_devspeed - converts a devspeed value to nS or nS
837*7c478bd9Sstevel@tonic-gate  *				to a devspeed entry
838*7c478bd9Sstevel@tonic-gate  */
839*7c478bd9Sstevel@tonic-gate uint32_t
840*7c478bd9Sstevel@tonic-gate cis_convert_devspeed(convert_speed_t *cs)
841*7c478bd9Sstevel@tonic-gate {
842*7c478bd9Sstevel@tonic-gate 	cistpl_devspeed_struct_t *cd = &cistpl_devspeed_struct;
843*7c478bd9Sstevel@tonic-gate 	unsigned exponent = 0, mantissa = 0;
844*7c478bd9Sstevel@tonic-gate 
845*7c478bd9Sstevel@tonic-gate 	/*
846*7c478bd9Sstevel@tonic-gate 	 * Convert nS to a devspeed value
847*7c478bd9Sstevel@tonic-gate 	 */
848*7c478bd9Sstevel@tonic-gate 	if (cs->Attributes & CONVERT_NS_TO_DEVSPEED) {
849*7c478bd9Sstevel@tonic-gate 	    unsigned tnS, tmanv = 0, i;
850*7c478bd9Sstevel@tonic-gate 
851*7c478bd9Sstevel@tonic-gate 	/*
852*7c478bd9Sstevel@tonic-gate 	 * There is no device speed code for 0nS
853*7c478bd9Sstevel@tonic-gate 	 */
854*7c478bd9Sstevel@tonic-gate 	    if (!cs->nS)
855*7c478bd9Sstevel@tonic-gate 		return (CS_BAD_SPEED);
856*7c478bd9Sstevel@tonic-gate 
857*7c478bd9Sstevel@tonic-gate 	/*
858*7c478bd9Sstevel@tonic-gate 	 * Handle any nS value below 10nS specially since the code
859*7c478bd9Sstevel@tonic-gate 	 *	below only works for nS values >= 10.  Now, why anyone
860*7c478bd9Sstevel@tonic-gate 	 *	would want to specify a nS value less than 10 is
861*7c478bd9Sstevel@tonic-gate 	 *	certainly questionable, but it is allowed by the spec.
862*7c478bd9Sstevel@tonic-gate 	 */
863*7c478bd9Sstevel@tonic-gate 	    if (cs->nS < 10) {
864*7c478bd9Sstevel@tonic-gate 		tmanv = cs->nS * 10;
865*7c478bd9Sstevel@tonic-gate 		mantissa = CISTPL_DEVSPEED_MAX_MAN;
866*7c478bd9Sstevel@tonic-gate 	    }
867*7c478bd9Sstevel@tonic-gate 
868*7c478bd9Sstevel@tonic-gate 	    /* find the exponent */
869*7c478bd9Sstevel@tonic-gate 	    for (i = 0; i < CISTPL_DEVSPEED_MAX_EXP; i++) {
870*7c478bd9Sstevel@tonic-gate 		if ((!(tnS = ((cs->nS)/10))) ||
871*7c478bd9Sstevel@tonic-gate 				(mantissa == CISTPL_DEVSPEED_MAX_MAN)) {
872*7c478bd9Sstevel@tonic-gate 		    /* find the mantissa */
873*7c478bd9Sstevel@tonic-gate 		    for (mantissa = 0; mantissa < CISTPL_DEVSPEED_MAX_MAN;
874*7c478bd9Sstevel@tonic-gate 								mantissa++) {
875*7c478bd9Sstevel@tonic-gate 			if (cd->mantissa[mantissa] == tmanv) {
876*7c478bd9Sstevel@tonic-gate 			    cs->devspeed = ((((mantissa<<3) |
877*7c478bd9Sstevel@tonic-gate 				(exponent & (CISTPL_DEVSPEED_MAX_EXP - 1)))));
878*7c478bd9Sstevel@tonic-gate 			    return (CS_SUCCESS);
879*7c478bd9Sstevel@tonic-gate 			}
880*7c478bd9Sstevel@tonic-gate 		    } /* for (mantissa<CISTPL_DEVSPEED_MAX_MAN) */
881*7c478bd9Sstevel@tonic-gate 		} else {
882*7c478bd9Sstevel@tonic-gate 		    exponent = i + 1;
883*7c478bd9Sstevel@tonic-gate 		    tmanv = cs->nS;
884*7c478bd9Sstevel@tonic-gate 		    cs->nS = tnS;
885*7c478bd9Sstevel@tonic-gate 		} /* if (!tnS) */
886*7c478bd9Sstevel@tonic-gate 	    } /* for (i<CISTPL_DEVSPEED_MAX_EXP) */
887*7c478bd9Sstevel@tonic-gate 	/*
888*7c478bd9Sstevel@tonic-gate 	 * Convert a devspeed value to nS
889*7c478bd9Sstevel@tonic-gate 	 */
890*7c478bd9Sstevel@tonic-gate 	} else if (cs->Attributes & CONVERT_DEVSPEED_TO_NS) {
891*7c478bd9Sstevel@tonic-gate 	    exponent = (cs->devspeed & (CISTPL_DEVSPEED_MAX_TBL - 1));
892*7c478bd9Sstevel@tonic-gate 	    if ((mantissa = (((cs->devspeed)>>3) &
893*7c478bd9Sstevel@tonic-gate 				(CISTPL_DEVSPEED_MAX_MAN - 1))) == NULL) {
894*7c478bd9Sstevel@tonic-gate 		if ((cs->nS = cd->table[exponent]) == NULL)
895*7c478bd9Sstevel@tonic-gate 		    return (CS_BAD_SPEED);
896*7c478bd9Sstevel@tonic-gate 		return (CS_SUCCESS);
897*7c478bd9Sstevel@tonic-gate 	    } else {
898*7c478bd9Sstevel@tonic-gate 		if ((cs->nS = ((cd->mantissa[mantissa] *
899*7c478bd9Sstevel@tonic-gate 					cd->exponent[exponent]) / 10)) == NULL)
900*7c478bd9Sstevel@tonic-gate 		    return (CS_BAD_SPEED);
901*7c478bd9Sstevel@tonic-gate 		return (CS_SUCCESS);
902*7c478bd9Sstevel@tonic-gate 	    }
903*7c478bd9Sstevel@tonic-gate 	} else {
904*7c478bd9Sstevel@tonic-gate 	    return (CS_BAD_ATTRIBUTE);
905*7c478bd9Sstevel@tonic-gate 	}
906*7c478bd9Sstevel@tonic-gate 
907*7c478bd9Sstevel@tonic-gate 	return (CS_BAD_SPEED);
908*7c478bd9Sstevel@tonic-gate }
909*7c478bd9Sstevel@tonic-gate 
910*7c478bd9Sstevel@tonic-gate /*
911*7c478bd9Sstevel@tonic-gate  * This array is for the cis_convert_devsize function.
912*7c478bd9Sstevel@tonic-gate  */
913*7c478bd9Sstevel@tonic-gate static uint32_t cistpl_device_size[8] =
914*7c478bd9Sstevel@tonic-gate 	{ 512, 2*1024, 8*1024, 32*1024, 128*1024, 512*1024, 2*1024*1024, 0 };
915*7c478bd9Sstevel@tonic-gate 
916*7c478bd9Sstevel@tonic-gate /*
917*7c478bd9Sstevel@tonic-gate  * cis_convert_devsize - converts a devsize value to a size in bytes value
918*7c478bd9Sstevel@tonic-gate  *				or a size in bytes value to a devsize value
919*7c478bd9Sstevel@tonic-gate  */
920*7c478bd9Sstevel@tonic-gate uint32_t
921*7c478bd9Sstevel@tonic-gate cis_convert_devsize(convert_size_t *cs)
922*7c478bd9Sstevel@tonic-gate {
923*7c478bd9Sstevel@tonic-gate 	int i;
924*7c478bd9Sstevel@tonic-gate 
925*7c478bd9Sstevel@tonic-gate 	if (cs->Attributes & CONVERT_BYTES_TO_DEVSIZE) {
926*7c478bd9Sstevel@tonic-gate 	    if ((cs->bytes < cistpl_device_size[0]) ||
927*7c478bd9Sstevel@tonic-gate 				(cs->bytes > (cistpl_device_size[6] * 32)))
928*7c478bd9Sstevel@tonic-gate 	    return (CS_BAD_SIZE);
929*7c478bd9Sstevel@tonic-gate 
930*7c478bd9Sstevel@tonic-gate 	    for (i = 6; i >= 0; i--)
931*7c478bd9Sstevel@tonic-gate 		if (cs->bytes >= cistpl_device_size[i])
932*7c478bd9Sstevel@tonic-gate 		    break;
933*7c478bd9Sstevel@tonic-gate 
934*7c478bd9Sstevel@tonic-gate 	    cs->devsize = ((((cs->bytes/cistpl_device_size[i]) - 1) << 3) |
935*7c478bd9Sstevel@tonic-gate 								(i & 7));
936*7c478bd9Sstevel@tonic-gate 
937*7c478bd9Sstevel@tonic-gate 	} else if (cs->Attributes & CONVERT_DEVSIZE_TO_BYTES) {
938*7c478bd9Sstevel@tonic-gate 	    if ((cs->devsize & 7) == 7)
939*7c478bd9Sstevel@tonic-gate 		return (CS_BAD_SIZE);
940*7c478bd9Sstevel@tonic-gate 	    cs->bytes =
941*7c478bd9Sstevel@tonic-gate 		cistpl_device_size[cs->devsize & 7] * ((cs->devsize >> 3) + 1);
942*7c478bd9Sstevel@tonic-gate 	} else {
943*7c478bd9Sstevel@tonic-gate 	    return (CS_BAD_ATTRIBUTE);
944*7c478bd9Sstevel@tonic-gate 	}
945*7c478bd9Sstevel@tonic-gate 
946*7c478bd9Sstevel@tonic-gate 	return (CS_SUCCESS);
947*7c478bd9Sstevel@tonic-gate }
948*7c478bd9Sstevel@tonic-gate 
949*7c478bd9Sstevel@tonic-gate /*
950*7c478bd9Sstevel@tonic-gate  * cis_list_create - reads the card's CIS and creates local CIS lists for
951*7c478bd9Sstevel@tonic-gate  *			each function on the card
952*7c478bd9Sstevel@tonic-gate  *
953*7c478bd9Sstevel@tonic-gate  * This function will read the CIS on the card, follow all CISTPL_LONGLINK_A,
954*7c478bd9Sstevel@tonic-gate  *	CISTPL_LONGLINK_C and CISTPL_LONGLINK_MFC tuples and create local CIS
955*7c478bd9Sstevel@tonic-gate  *	lists for each major CIS chain on the card.
956*7c478bd9Sstevel@tonic-gate  *
957*7c478bd9Sstevel@tonic-gate  * If there are no errors, the parameters returned are:
958*7c478bd9Sstevel@tonic-gate  *	For a non-multifunction card:
959*7c478bd9Sstevel@tonic-gate  *		sp->cis_flags - CW_VALID_CIS set
960*7c478bd9Sstevel@tonic-gate  *		sp->nfuncs - set to 0x0
961*7c478bd9Sstevel@tonic-gate  *		sp->cis[CS_GLOBAL_CIS] - contains CIS list
962*7c478bd9Sstevel@tonic-gate  *		sp->cis[CS_GLOBAL_CIS].cis_flags - CW_VALID_CIS set
963*7c478bd9Sstevel@tonic-gate  *
964*7c478bd9Sstevel@tonic-gate  *	For a multifunction card:
965*7c478bd9Sstevel@tonic-gate  *	    Global CIS values:
966*7c478bd9Sstevel@tonic-gate  *		sp->cis_flags - CW_VALID_CIS & CW_MULTI_FUNCTION_CIS set
967*7c478bd9Sstevel@tonic-gate  *		sp->nfuncs - set to number of functions specified in
968*7c478bd9Sstevel@tonic-gate  *				the CISTPL_LONGLINK_MFC tuple
969*7c478bd9Sstevel@tonic-gate  *		sp->cis[CS_GLOBAL_CIS] - contains global CIS list
970*7c478bd9Sstevel@tonic-gate  *		sp->cis[CS_GLOBAL_CIS].cis_flags - CW_VALID_CIS set
971*7c478bd9Sstevel@tonic-gate  *	    Function-specific CIS values:
972*7c478bd9Sstevel@tonic-gate  *		sp->cis[0..sp->nfuncs-1] - contains function-specific CIS lists
973*7c478bd9Sstevel@tonic-gate  *		sp->cis[0..sp->nfuncs-1].cis_flags - CW_VALID_CIS &
974*7c478bd9Sstevel@tonic-gate  *						CW_MULTI_FUNCTION_CIS set
975*7c478bd9Sstevel@tonic-gate  *
976*7c478bd9Sstevel@tonic-gate  *	returns:
977*7c478bd9Sstevel@tonic-gate  *		CS_SUCCESS - if no errors
978*7c478bd9Sstevel@tonic-gate  *		CS_NO_CIS - if no CIS on card
979*7c478bd9Sstevel@tonic-gate  *		CS_BAD_WINDOW or CS_GENERAL_FAILURE - if CIS window could
980*7c478bd9Sstevel@tonic-gate  *				not be setup
981*7c478bd9Sstevel@tonic-gate  *		CS_BAD_CIS - if error creating CIS chains
982*7c478bd9Sstevel@tonic-gate  *		CS_BAD_OFFSET - if cis_list_lcreate tried to read past the
983*7c478bd9Sstevel@tonic-gate  *				boundries of the allocated CIS window
984*7c478bd9Sstevel@tonic-gate  */
985*7c478bd9Sstevel@tonic-gate extern cistpl_ignore_list_t cistpl_ignore_list[];
986*7c478bd9Sstevel@tonic-gate uint32_t
987*7c478bd9Sstevel@tonic-gate cis_list_create(cistpl_callout_t *cistpl_callout, cs_socket_t *sp)
988*7c478bd9Sstevel@tonic-gate {
989*7c478bd9Sstevel@tonic-gate 	cisptr_t cisptr;
990*7c478bd9Sstevel@tonic-gate 	cisparse_t cisparse;
991*7c478bd9Sstevel@tonic-gate 	cis_info_t *cis_info;
992*7c478bd9Sstevel@tonic-gate 	cistpl_longlink_ac_t *cistpl_longlink_ac;
993*7c478bd9Sstevel@tonic-gate 	cistpl_longlink_mfc_t cistpl_longlink_mfc, *mfc;
994*7c478bd9Sstevel@tonic-gate 	cistpl_ignore_list_t *cil;
995*7c478bd9Sstevel@tonic-gate 	int fn, ret;
996*7c478bd9Sstevel@tonic-gate 
997*7c478bd9Sstevel@tonic-gate 	/*
998*7c478bd9Sstevel@tonic-gate 	 * Initialize the CIS structures
999*7c478bd9Sstevel@tonic-gate 	 */
1000*7c478bd9Sstevel@tonic-gate 	bzero((caddr_t)&sp->cis, ((sizeof (cis_info_t)) * CS_MAX_CIS));
1001*7c478bd9Sstevel@tonic-gate 
1002*7c478bd9Sstevel@tonic-gate 	/*
1003*7c478bd9Sstevel@tonic-gate 	 * Start reading the primary CIS chain at offset 0x0 of AM. Assume
1004*7c478bd9Sstevel@tonic-gate 	 *	that there is a CISTPL_LONGLINK_C tuple that points to
1005*7c478bd9Sstevel@tonic-gate 	 *	offset 0x0 of CM space.
1006*7c478bd9Sstevel@tonic-gate 	 * Since this is the primary CIS chain, set CW_CHECK_PRIMARY_CHAIN
1007*7c478bd9Sstevel@tonic-gate 	 *	so that we'll check for a valid first tuple.
1008*7c478bd9Sstevel@tonic-gate 	 */
1009*7c478bd9Sstevel@tonic-gate 	cis_info = &sp->cis[CS_GLOBAL_CIS];
1010*7c478bd9Sstevel@tonic-gate 	cis_info->flags = (CW_LONGLINK_C_FOUND | CW_CHECK_PRIMARY_CHAIN);
1011*7c478bd9Sstevel@tonic-gate 	cisptr.flags = (CISTPLF_AM_SPACE | CISTPLF_GLOBAL_CIS);
1012*7c478bd9Sstevel@tonic-gate 	cisptr.size = sp->cis_win_size - 1;
1013*7c478bd9Sstevel@tonic-gate 	cisptr.offset = 0;
1014*7c478bd9Sstevel@tonic-gate 	cistpl_longlink_ac = (cistpl_longlink_ac_t *)&cisparse;
1015*7c478bd9Sstevel@tonic-gate 	cistpl_longlink_ac->flags = CISTPL_LONGLINK_AC_CM;
1016*7c478bd9Sstevel@tonic-gate 	cistpl_longlink_ac->tpll_addr = 0;
1017*7c478bd9Sstevel@tonic-gate 
1018*7c478bd9Sstevel@tonic-gate 	if ((ret = cis_create_cis_chain(sp, cistpl_callout, &cisptr,
1019*7c478bd9Sstevel@tonic-gate 						cis_info, &cisparse)) !=
1020*7c478bd9Sstevel@tonic-gate 								CS_SUCCESS) {
1021*7c478bd9Sstevel@tonic-gate 	    return (ret);
1022*7c478bd9Sstevel@tonic-gate 	} /* cis_create_cis_chain */
1023*7c478bd9Sstevel@tonic-gate 
1024*7c478bd9Sstevel@tonic-gate 	/*
1025*7c478bd9Sstevel@tonic-gate 	 * If there are no tuples in the primary CIS chain, it means that
1026*7c478bd9Sstevel@tonic-gate 	 *	this card doesn't have a CIS on it.
1027*7c478bd9Sstevel@tonic-gate 	 */
1028*7c478bd9Sstevel@tonic-gate 	if (cis_info->ntuples == 0)
1029*7c478bd9Sstevel@tonic-gate 	    return (CS_NO_CIS);
1030*7c478bd9Sstevel@tonic-gate 
1031*7c478bd9Sstevel@tonic-gate 	/*
1032*7c478bd9Sstevel@tonic-gate 	 * Mark this CIS list as being valid.
1033*7c478bd9Sstevel@tonic-gate 	 */
1034*7c478bd9Sstevel@tonic-gate 	cis_info->flags |= CW_VALID_CIS;
1035*7c478bd9Sstevel@tonic-gate 
1036*7c478bd9Sstevel@tonic-gate 	/*
1037*7c478bd9Sstevel@tonic-gate 	 * Mark this socket as having at least one valid CIS chain.
1038*7c478bd9Sstevel@tonic-gate 	 */
1039*7c478bd9Sstevel@tonic-gate 	sp->cis_flags |= CW_VALID_CIS;
1040*7c478bd9Sstevel@tonic-gate 	sp->nfuncs = 0;
1041*7c478bd9Sstevel@tonic-gate 
1042*7c478bd9Sstevel@tonic-gate 	/*
1043*7c478bd9Sstevel@tonic-gate 	 * If the primary CIS chain specified that there are function-specific
1044*7c478bd9Sstevel@tonic-gate 	 *	CIS chains, we need to create each of these chains. If not,
1045*7c478bd9Sstevel@tonic-gate 	 *	then we're all done and we can return.
1046*7c478bd9Sstevel@tonic-gate 	 */
1047*7c478bd9Sstevel@tonic-gate 	if (!(cis_info->flags & CW_LONGLINK_MFC_FOUND))
1048*7c478bd9Sstevel@tonic-gate 	    return (CS_SUCCESS);
1049*7c478bd9Sstevel@tonic-gate 
1050*7c478bd9Sstevel@tonic-gate 	/*
1051*7c478bd9Sstevel@tonic-gate 	 * Mark this socket as having a multi-function CIS.
1052*7c478bd9Sstevel@tonic-gate 	 */
1053*7c478bd9Sstevel@tonic-gate 	sp->cis_flags |= CW_MULTI_FUNCTION_CIS;
1054*7c478bd9Sstevel@tonic-gate 
1055*7c478bd9Sstevel@tonic-gate 	/*
1056*7c478bd9Sstevel@tonic-gate 	 * At this point, cis_create_cis_chain has told us that the primary
1057*7c478bd9Sstevel@tonic-gate 	 *	CIS chain says that there are function-specific CIS chains
1058*7c478bd9Sstevel@tonic-gate 	 *	on the card that we need to follow. The cisparse variable now
1059*7c478bd9Sstevel@tonic-gate 	 *	contains the parsed output of the CISTPL_LONGLINK_MFC
1060*7c478bd9Sstevel@tonic-gate 	 *	tuple. We need to save that information and then process
1061*7c478bd9Sstevel@tonic-gate 	 *	each function-specific CIS chain.
1062*7c478bd9Sstevel@tonic-gate 	 */
1063*7c478bd9Sstevel@tonic-gate 	bcopy((caddr_t)&cisparse, (caddr_t)&cistpl_longlink_mfc,
1064*7c478bd9Sstevel@tonic-gate 					sizeof (cistpl_longlink_mfc_t));
1065*7c478bd9Sstevel@tonic-gate 	mfc = &cistpl_longlink_mfc;
1066*7c478bd9Sstevel@tonic-gate 	sp->nfuncs = mfc->nregs;
1067*7c478bd9Sstevel@tonic-gate 
1068*7c478bd9Sstevel@tonic-gate 	/*
1069*7c478bd9Sstevel@tonic-gate 	 * Go through and create a CIS list for each function-specific
1070*7c478bd9Sstevel@tonic-gate 	 *	CIS chain on the card. Set CW_CHECK_LINKTARGET since all
1071*7c478bd9Sstevel@tonic-gate 	 *	function-specific CIS chains must begin with a valid
1072*7c478bd9Sstevel@tonic-gate 	 *	CISTPL_LINKTARGET tuple. Also set CW_RET_ON_LINKTARGET_ERROR
1073*7c478bd9Sstevel@tonic-gate 	 *	since we want to return an error if the CISTPL_LINKTARGET
1074*7c478bd9Sstevel@tonic-gate 	 *	tuple is invalid or missing.
1075*7c478bd9Sstevel@tonic-gate 	 */
1076*7c478bd9Sstevel@tonic-gate 	for (fn = 0; fn < sp->nfuncs; fn++) {
1077*7c478bd9Sstevel@tonic-gate 	    cis_info = &sp->cis[fn];
1078*7c478bd9Sstevel@tonic-gate 	    cis_info->flags = (CW_CHECK_LINKTARGET |
1079*7c478bd9Sstevel@tonic-gate 					CW_RET_ON_LINKTARGET_ERROR);
1080*7c478bd9Sstevel@tonic-gate 		/*
1081*7c478bd9Sstevel@tonic-gate 		 * If the function-specific CIS chain starts
1082*7c478bd9Sstevel@tonic-gate 		 *	in AM space, then multiply address by
1083*7c478bd9Sstevel@tonic-gate 		 *	2 since only even bytes are counted in
1084*7c478bd9Sstevel@tonic-gate 		 *	the CIS when AM addresses are specified,
1085*7c478bd9Sstevel@tonic-gate 		 *	otherwise use the
1086*7c478bd9Sstevel@tonic-gate 		 *	address as specified.
1087*7c478bd9Sstevel@tonic-gate 		 */
1088*7c478bd9Sstevel@tonic-gate 	    if (mfc->function[fn].tas == CISTPL_LONGLINK_MFC_TAS_AM) {
1089*7c478bd9Sstevel@tonic-gate 		cisptr.flags = (CISTPLF_AM_SPACE | CISTPLF_MF_CIS);
1090*7c478bd9Sstevel@tonic-gate 		cisptr.offset = mfc->function[fn].addr * 2;
1091*7c478bd9Sstevel@tonic-gate 	    } else {
1092*7c478bd9Sstevel@tonic-gate 		cisptr.flags = (CISTPLF_CM_SPACE | CISTPLF_MF_CIS);
1093*7c478bd9Sstevel@tonic-gate 		cisptr.offset = mfc->function[fn].addr;
1094*7c478bd9Sstevel@tonic-gate 	    }
1095*7c478bd9Sstevel@tonic-gate 
1096*7c478bd9Sstevel@tonic-gate 	    if ((ret = cis_create_cis_chain(sp, cistpl_callout, &cisptr,
1097*7c478bd9Sstevel@tonic-gate 						cis_info, &cisparse)) !=
1098*7c478bd9Sstevel@tonic-gate 								CS_SUCCESS) {
1099*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT,
1100*7c478bd9Sstevel@tonic-gate 		    "cis_list_create: socket %d ERROR_MFC = 0x%x\n",
1101*7c478bd9Sstevel@tonic-gate 		    sp->socket_num, ret);
1102*7c478bd9Sstevel@tonic-gate 		return (ret);
1103*7c478bd9Sstevel@tonic-gate 	    } /* cis_create_cis_chain */
1104*7c478bd9Sstevel@tonic-gate 
1105*7c478bd9Sstevel@tonic-gate 		/*
1106*7c478bd9Sstevel@tonic-gate 		 * Mark this CIS list as being valid and as being a
1107*7c478bd9Sstevel@tonic-gate 		 *	function-specific CIS list.
1108*7c478bd9Sstevel@tonic-gate 		 */
1109*7c478bd9Sstevel@tonic-gate 	    cis_info->flags |= (CW_VALID_CIS | CW_MULTI_FUNCTION_CIS);
1110*7c478bd9Sstevel@tonic-gate 
1111*7c478bd9Sstevel@tonic-gate 		/*
1112*7c478bd9Sstevel@tonic-gate 		 * Check for tuples that we want to ignore
1113*7c478bd9Sstevel@tonic-gate 		 *	in the global CIS.  If the tuple exists
1114*7c478bd9Sstevel@tonic-gate 		 *	in the global CIS and in at least one
1115*7c478bd9Sstevel@tonic-gate 		 *	of the function-specific CIS lists, then
1116*7c478bd9Sstevel@tonic-gate 		 *	we flag the tuple
1117*7c478bd9Sstevel@tonic-gate 		 *	in the global CIS to be ignored.
1118*7c478bd9Sstevel@tonic-gate 		 */
1119*7c478bd9Sstevel@tonic-gate 	    cil = &cistpl_ignore_list[0];
1120*7c478bd9Sstevel@tonic-gate 	    while (cil->type != CISTPL_NULL) {
1121*7c478bd9Sstevel@tonic-gate 		if (cis_get_ltuple(sp->cis[fn].cis, cil->type,
1122*7c478bd9Sstevel@tonic-gate 					FIND_LTUPLE_FWDF |
1123*7c478bd9Sstevel@tonic-gate 					CIS_GET_LTUPLE_IGNORE) != NULL) {
1124*7c478bd9Sstevel@tonic-gate 		    cistpl_t *gtp = sp->cis[CS_GLOBAL_CIS].cis;
1125*7c478bd9Sstevel@tonic-gate 		    while ((gtp = cis_get_ltuple(gtp, cil->type,
1126*7c478bd9Sstevel@tonic-gate 					FIND_LTUPLE_FWDF |
1127*7c478bd9Sstevel@tonic-gate 					CIS_GET_LTUPLE_IGNORE)) != NULL) {
1128*7c478bd9Sstevel@tonic-gate 			gtp->flags |= CISTPLF_IGNORE_TUPLE;
1129*7c478bd9Sstevel@tonic-gate 			gtp = cis_get_ltuple(gtp, NULL, GET_NEXT_LTUPLEF |
1130*7c478bd9Sstevel@tonic-gate 							CIS_GET_LTUPLE_IGNORE);
1131*7c478bd9Sstevel@tonic-gate 		    } /* while */
1132*7c478bd9Sstevel@tonic-gate 		} /* if (cis_get_ltuple(cis[fn])) */
1133*7c478bd9Sstevel@tonic-gate 		cil++;
1134*7c478bd9Sstevel@tonic-gate 	    } /* while */
1135*7c478bd9Sstevel@tonic-gate 	} /* for */
1136*7c478bd9Sstevel@tonic-gate 
1137*7c478bd9Sstevel@tonic-gate 	return (CS_SUCCESS);
1138*7c478bd9Sstevel@tonic-gate }
1139*7c478bd9Sstevel@tonic-gate 
1140*7c478bd9Sstevel@tonic-gate /*
1141*7c478bd9Sstevel@tonic-gate  * cis_create_cis_chain - creates a single CIS chain
1142*7c478bd9Sstevel@tonic-gate  *
1143*7c478bd9Sstevel@tonic-gate  * This function reads the CIS on a card and follows any CISTPL_LONGLINK_A
1144*7c478bd9Sstevel@tonic-gate  *	and CISTPL_LONGLINK_C link tuples to create a single CIS chain. We
1145*7c478bd9Sstevel@tonic-gate  *	keep reading the CIS and following any CISTPL_LONGLINK_A and
1146*7c478bd9Sstevel@tonic-gate  *	CISTPL_LONGLINK_C tuples until we don't see anymore. If we see a
1147*7c478bd9Sstevel@tonic-gate  *	CISTPL_LONGLINK_MFC tuple, we return - the caller is responsible
1148*7c478bd9Sstevel@tonic-gate  *	for following CIS chains on a per-function level.
1149*7c478bd9Sstevel@tonic-gate  *
1150*7c478bd9Sstevel@tonic-gate  * The following parameters must be initialized by the caller:
1151*7c478bd9Sstevel@tonic-gate  *
1152*7c478bd9Sstevel@tonic-gate  *	sp - pointer to a cs_socket_t structure that describes the socket
1153*7c478bd9Sstevel@tonic-gate  *			and card in this socket
1154*7c478bd9Sstevel@tonic-gate  *	cistpl_callout - pointer to a cistpl_callout_t array of structures
1155*7c478bd9Sstevel@tonic-gate  *	cisptr->flags - either CISTPLF_AM_SPACE or CISTPLF_CM_SPACE
1156*7c478bd9Sstevel@tonic-gate  *	cisptr->size - size of CIS window
1157*7c478bd9Sstevel@tonic-gate  *	cisptr->offset - offset in AM or CM space on card to start
1158*7c478bd9Sstevel@tonic-gate  *			reading tuples from
1159*7c478bd9Sstevel@tonic-gate  *	cis_info - pointer to a cis_info_t structure where this list will
1160*7c478bd9Sstevel@tonic-gate  *			be anchored on
1161*7c478bd9Sstevel@tonic-gate  *	cisparse - pointer to a cisparse_t structure where the last longlink
1162*7c478bd9Sstevel@tonic-gate  *			parsed tuple data will be returned
1163*7c478bd9Sstevel@tonic-gate  *
1164*7c478bd9Sstevel@tonic-gate  * To check the CISTPL_LINKTARGET tuple at the beginning of the first
1165*7c478bd9Sstevel@tonic-gate  *	CIS chain that this function encounters, set CW_CHECK_LINKTARGET
1166*7c478bd9Sstevel@tonic-gate  *	in cis_info->flags before calling this function.
1167*7c478bd9Sstevel@tonic-gate  *
1168*7c478bd9Sstevel@tonic-gate  * This function returns:
1169*7c478bd9Sstevel@tonic-gate  *
1170*7c478bd9Sstevel@tonic-gate  *	CS_SUCCESS - if CIS chain was created sucessfully or there
1171*7c478bd9Sstevel@tonic-gate  *			were no tuples found on the first CIS chain
1172*7c478bd9Sstevel@tonic-gate  *	CS_BAD_WINDOW or CS_GENERAL_FAILURE - if CIS window could
1173*7c478bd9Sstevel@tonic-gate  *			not be setup
1174*7c478bd9Sstevel@tonic-gate  *	CS_BAD_CIS - if error creating CIS chain
1175*7c478bd9Sstevel@tonic-gate  *	CS_BAD_OFFSET - if cis_list_lcreate tried to read past the
1176*7c478bd9Sstevel@tonic-gate  *			boundries of the allocated CIS window
1177*7c478bd9Sstevel@tonic-gate  *
1178*7c478bd9Sstevel@tonic-gate  * Note that if the first tuple of the target CIS chain is supposed
1179*7c478bd9Sstevel@tonic-gate  *	to contain a CISTPL_LINKTARGET and the target chain does not
1180*7c478bd9Sstevel@tonic-gate  *	contain that tuple (or that tuple is invalid in some way) and
1181*7c478bd9Sstevel@tonic-gate  *	the CW_RET_ON_LINKTARGET_ERROR flag is not set, we don't flag
1182*7c478bd9Sstevel@tonic-gate  *	this as an error, we just return. This is to handle the case
1183*7c478bd9Sstevel@tonic-gate  *	where the target chain is in uninitialized memory and will be
1184*7c478bd9Sstevel@tonic-gate  *	initialized later.
1185*7c478bd9Sstevel@tonic-gate  * To return an error if an invalid CISTPL_LINKTARGET tuple is seen,
1186*7c478bd9Sstevel@tonic-gate  *	set the CW_RET_ON_LINKTARGET_ERROR flag in cis_info->flags
1187*7c478bd9Sstevel@tonic-gate  *	before calling this function.
1188*7c478bd9Sstevel@tonic-gate  */
1189*7c478bd9Sstevel@tonic-gate static int
1190*7c478bd9Sstevel@tonic-gate cis_create_cis_chain(cs_socket_t *sp, cistpl_callout_t *cistpl_callout,
1191*7c478bd9Sstevel@tonic-gate 				cisptr_t *cisptr, cis_info_t *cis_info,
1192*7c478bd9Sstevel@tonic-gate 							cisparse_t *cisparse)
1193*7c478bd9Sstevel@tonic-gate {
1194*7c478bd9Sstevel@tonic-gate 	cistpl_t *tps = NULL;
1195*7c478bd9Sstevel@tonic-gate 	uint32_t ret;
1196*7c478bd9Sstevel@tonic-gate 
1197*7c478bd9Sstevel@tonic-gate 	do {
1198*7c478bd9Sstevel@tonic-gate 	    if ((ret = CIS_CARD_SERVICES(InitCISWindow, sp, &cisptr->offset,
1199*7c478bd9Sstevel@tonic-gate 				&cisptr->handle, cisptr->flags)) != CS_SUCCESS)
1200*7c478bd9Sstevel@tonic-gate 		return (ret);
1201*7c478bd9Sstevel@tonic-gate 
1202*7c478bd9Sstevel@tonic-gate 		/*
1203*7c478bd9Sstevel@tonic-gate 		 * If we're pointing at a CIS chain that
1204*7c478bd9Sstevel@tonic-gate 		 *	is the target of a longlink tuple,
1205*7c478bd9Sstevel@tonic-gate 		 *	we need to validate the target chain
1206*7c478bd9Sstevel@tonic-gate 		 *	before we try to process it. If the
1207*7c478bd9Sstevel@tonic-gate 		 *	CISTPL_LINKTARGET tuple is invalid,
1208*7c478bd9Sstevel@tonic-gate 		 *	and the CW_RET_ON_LINKTARGET_ERROR
1209*7c478bd9Sstevel@tonic-gate 		 *	is not set, don't flag it as an error,
1210*7c478bd9Sstevel@tonic-gate 		 *	just return.
1211*7c478bd9Sstevel@tonic-gate 		 */
1212*7c478bd9Sstevel@tonic-gate 	    if (cis_info->flags & CW_CHECK_LINKTARGET) {
1213*7c478bd9Sstevel@tonic-gate 		cis_info->flags &= ~CW_CHECK_LINKTARGET;
1214*7c478bd9Sstevel@tonic-gate 		if (cis_validate_longlink_acm(cisptr) != CISTPLF_NOERROR) {
1215*7c478bd9Sstevel@tonic-gate 		    if (tps != NULL)
1216*7c478bd9Sstevel@tonic-gate 			cis_info->cis = tps;
1217*7c478bd9Sstevel@tonic-gate 		    if (cis_info->flags & CW_RET_ON_LINKTARGET_ERROR) {
1218*7c478bd9Sstevel@tonic-gate 			cis_info->flags &= ~CW_RET_ON_LINKTARGET_ERROR;
1219*7c478bd9Sstevel@tonic-gate 			return (CS_BAD_CIS);
1220*7c478bd9Sstevel@tonic-gate 		    } else {
1221*7c478bd9Sstevel@tonic-gate 			return (CS_SUCCESS);
1222*7c478bd9Sstevel@tonic-gate 		    } /* CW_RET_ON_LINKTARGET_ERROR */
1223*7c478bd9Sstevel@tonic-gate 		} /* cis_validate_longlink_acm */
1224*7c478bd9Sstevel@tonic-gate 	    } /* CW_CHECK_LINKTARGET */
1225*7c478bd9Sstevel@tonic-gate 
1226*7c478bd9Sstevel@tonic-gate 	    ret = cis_list_lcreate(cistpl_callout, cisptr, cis_info, cisparse,
1227*7c478bd9Sstevel@tonic-gate 		sp);
1228*7c478bd9Sstevel@tonic-gate 
1229*7c478bd9Sstevel@tonic-gate #if defined(CIS_DEBUG)
1230*7c478bd9Sstevel@tonic-gate 	    if (cis_debug > 1) {
1231*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "cis_create_cis_chain: ret=0x%x"
1232*7c478bd9Sstevel@tonic-gate 		    " BAD_CIS_ADDR=0x%x CS_BAD_SOCKET=0x%x\n",
1233*7c478bd9Sstevel@tonic-gate 		    ret, BAD_CIS_ADDR, CS_BAD_SOCKET);
1234*7c478bd9Sstevel@tonic-gate 	    }
1235*7c478bd9Sstevel@tonic-gate #endif
1236*7c478bd9Sstevel@tonic-gate 
1237*7c478bd9Sstevel@tonic-gate 
1238*7c478bd9Sstevel@tonic-gate 	    if ((ret & HANDTPL_ERROR) || (ret == (uint32_t)BAD_CIS_ADDR)) {
1239*7c478bd9Sstevel@tonic-gate 		if (tps != NULL)
1240*7c478bd9Sstevel@tonic-gate 		    cis_info->cis = tps;
1241*7c478bd9Sstevel@tonic-gate 		if (ret == (uint32_t)BAD_CIS_ADDR)
1242*7c478bd9Sstevel@tonic-gate 		    return (CS_BAD_OFFSET);
1243*7c478bd9Sstevel@tonic-gate 		else
1244*7c478bd9Sstevel@tonic-gate 		    return (CS_BAD_CIS);
1245*7c478bd9Sstevel@tonic-gate 	    }
1246*7c478bd9Sstevel@tonic-gate 
1247*7c478bd9Sstevel@tonic-gate 		/*
1248*7c478bd9Sstevel@tonic-gate 		 * If we're creating the primary CIS chain
1249*7c478bd9Sstevel@tonic-gate 		 *	and we haven't seen any tuples,
1250*7c478bd9Sstevel@tonic-gate 		 *	then return CS_SUCCESS. The caller will
1251*7c478bd9Sstevel@tonic-gate 		 *	have to check cis_info->ntuples to find
1252*7c478bd9Sstevel@tonic-gate 		 *	out if any tuples were found.
1253*7c478bd9Sstevel@tonic-gate 		 * If we're processing the target of a longlink
1254*7c478bd9Sstevel@tonic-gate 		 *	tuple, then by now we have already validated
1255*7c478bd9Sstevel@tonic-gate 		 *	the CISTPL_LINKTARGET tuple so that we
1256*7c478bd9Sstevel@tonic-gate 		 *	know we'll have at least one tuple in
1257*7c478bd9Sstevel@tonic-gate 		 *	our list.
1258*7c478bd9Sstevel@tonic-gate 		 */
1259*7c478bd9Sstevel@tonic-gate 	    if (cis_info->ntuples == 0)
1260*7c478bd9Sstevel@tonic-gate 		return (CS_SUCCESS);
1261*7c478bd9Sstevel@tonic-gate 
1262*7c478bd9Sstevel@tonic-gate 		/*
1263*7c478bd9Sstevel@tonic-gate 		 * If we've just created a new list, we need to
1264*7c478bd9Sstevel@tonic-gate 		 *	save the pointer to the start of the list.
1265*7c478bd9Sstevel@tonic-gate 		 */
1266*7c478bd9Sstevel@tonic-gate 	    if (tps == NULL)
1267*7c478bd9Sstevel@tonic-gate 		tps = cis_info->cis;
1268*7c478bd9Sstevel@tonic-gate 
1269*7c478bd9Sstevel@tonic-gate 	    switch (cis_info->flags & CW_LONGLINK_FOUND) {
1270*7c478bd9Sstevel@tonic-gate 		cistpl_longlink_ac_t *cistpl_longlink_ac;
1271*7c478bd9Sstevel@tonic-gate 
1272*7c478bd9Sstevel@tonic-gate 		case CW_LONGLINK_A_FOUND:
1273*7c478bd9Sstevel@tonic-gate 		    cistpl_longlink_ac = (cistpl_longlink_ac_t *)cisparse;
1274*7c478bd9Sstevel@tonic-gate 		    cisptr->flags &= ~(CISTPLF_SPACE_MASK | CISTPLF_FROM_MASK);
1275*7c478bd9Sstevel@tonic-gate 		    cisptr->flags |= CISTPLF_AM_SPACE;
1276*7c478bd9Sstevel@tonic-gate 			/*
1277*7c478bd9Sstevel@tonic-gate 			 * Multiply address by 2 since only
1278*7c478bd9Sstevel@tonic-gate 			 *	even bytes are counted in the CIS
1279*7c478bd9Sstevel@tonic-gate 			 *	when AM addresses are specified.
1280*7c478bd9Sstevel@tonic-gate 			 */
1281*7c478bd9Sstevel@tonic-gate 		    cisptr->offset = cistpl_longlink_ac->tpll_addr * 2;
1282*7c478bd9Sstevel@tonic-gate 		    cis_info->flags |= CW_CHECK_LINKTARGET;
1283*7c478bd9Sstevel@tonic-gate 
1284*7c478bd9Sstevel@tonic-gate 			/*
1285*7c478bd9Sstevel@tonic-gate 			 * Point to the last tuple in the list.
1286*7c478bd9Sstevel@tonic-gate 			 */
1287*7c478bd9Sstevel@tonic-gate 		    cis_info->cis = cis_get_ltuple(cis_info->cis, NULL,
1288*7c478bd9Sstevel@tonic-gate 							GET_LAST_LTUPLEF);
1289*7c478bd9Sstevel@tonic-gate 		    break;
1290*7c478bd9Sstevel@tonic-gate 		case CW_LONGLINK_C_FOUND:
1291*7c478bd9Sstevel@tonic-gate 		    cistpl_longlink_ac = (cistpl_longlink_ac_t *)cisparse;
1292*7c478bd9Sstevel@tonic-gate 		    cisptr->flags &= ~(CISTPLF_SPACE_MASK | CISTPLF_FROM_MASK);
1293*7c478bd9Sstevel@tonic-gate 		    cisptr->flags |= CISTPLF_CM_SPACE;
1294*7c478bd9Sstevel@tonic-gate 		    cisptr->offset = cistpl_longlink_ac->tpll_addr;
1295*7c478bd9Sstevel@tonic-gate 		    cis_info->flags |= CW_CHECK_LINKTARGET;
1296*7c478bd9Sstevel@tonic-gate 
1297*7c478bd9Sstevel@tonic-gate 			/*
1298*7c478bd9Sstevel@tonic-gate 			 * Point to the last tuple in the list.
1299*7c478bd9Sstevel@tonic-gate 			 */
1300*7c478bd9Sstevel@tonic-gate 		    cis_info->cis = cis_get_ltuple(cis_info->cis, NULL,
1301*7c478bd9Sstevel@tonic-gate 							GET_LAST_LTUPLEF);
1302*7c478bd9Sstevel@tonic-gate 		    break;
1303*7c478bd9Sstevel@tonic-gate 		case CW_LONGLINK_MFC_FOUND:
1304*7c478bd9Sstevel@tonic-gate 		    break;
1305*7c478bd9Sstevel@tonic-gate 		default:
1306*7c478bd9Sstevel@tonic-gate 		    break;
1307*7c478bd9Sstevel@tonic-gate 	    } /* switch (cis_info->flags) */
1308*7c478bd9Sstevel@tonic-gate 
1309*7c478bd9Sstevel@tonic-gate 	} while (cis_info->flags & (CW_LONGLINK_A_FOUND | CW_LONGLINK_C_FOUND));
1310*7c478bd9Sstevel@tonic-gate 
1311*7c478bd9Sstevel@tonic-gate 	/*
1312*7c478bd9Sstevel@tonic-gate 	 * If we needed to save a pointer to the start of the list because
1313*7c478bd9Sstevel@tonic-gate 	 *	we saw a longlink tuple, restore the list head pointer now.
1314*7c478bd9Sstevel@tonic-gate 	 */
1315*7c478bd9Sstevel@tonic-gate 	if (tps != NULL)
1316*7c478bd9Sstevel@tonic-gate 	    cis_info->cis = tps;
1317*7c478bd9Sstevel@tonic-gate 
1318*7c478bd9Sstevel@tonic-gate 	return (CS_SUCCESS);
1319*7c478bd9Sstevel@tonic-gate }
1320*7c478bd9Sstevel@tonic-gate 
1321*7c478bd9Sstevel@tonic-gate /*
1322*7c478bd9Sstevel@tonic-gate  * cis_list_destroy - destroys the local CIS list
1323*7c478bd9Sstevel@tonic-gate  */
1324*7c478bd9Sstevel@tonic-gate uint32_t
1325*7c478bd9Sstevel@tonic-gate cis_list_destroy(cs_socket_t *sp)
1326*7c478bd9Sstevel@tonic-gate {
1327*7c478bd9Sstevel@tonic-gate 	int fn;
1328*7c478bd9Sstevel@tonic-gate 
1329*7c478bd9Sstevel@tonic-gate 	/*
1330*7c478bd9Sstevel@tonic-gate 	 * Destroy any CIS list that we may have created. It's OK to pass
1331*7c478bd9Sstevel@tonic-gate 	 *	a non-existant CIS list pointer to cis_list_ldestroy since
1332*7c478bd9Sstevel@tonic-gate 	 *	that function will not do anything if there is nothing in
1333*7c478bd9Sstevel@tonic-gate 	 *	the passed CIS list to cleanup.
1334*7c478bd9Sstevel@tonic-gate 	 */
1335*7c478bd9Sstevel@tonic-gate 	for (fn = 0; fn < CS_MAX_CIS; fn++)
1336*7c478bd9Sstevel@tonic-gate 	    (void) cis_list_ldestroy(&sp->cis[fn].cis);
1337*7c478bd9Sstevel@tonic-gate 
1338*7c478bd9Sstevel@tonic-gate 	/*
1339*7c478bd9Sstevel@tonic-gate 	 * Clear out any remaining state.
1340*7c478bd9Sstevel@tonic-gate 	 */
1341*7c478bd9Sstevel@tonic-gate 	bzero((caddr_t)&sp->cis, ((sizeof (cis_info_t)) * CS_MAX_CIS));
1342*7c478bd9Sstevel@tonic-gate 	sp->cis_flags = 0;
1343*7c478bd9Sstevel@tonic-gate 	sp->nfuncs = 0;
1344*7c478bd9Sstevel@tonic-gate 
1345*7c478bd9Sstevel@tonic-gate 	return (CS_SUCCESS);
1346*7c478bd9Sstevel@tonic-gate }
1347*7c478bd9Sstevel@tonic-gate 
1348*7c478bd9Sstevel@tonic-gate /*
1349*7c478bd9Sstevel@tonic-gate  * cis_store_cis_addr - saves the current CIS address and space type
1350*7c478bd9Sstevel@tonic-gate  *	of the beginning of the tuple into the passed linked list element.
1351*7c478bd9Sstevel@tonic-gate  *	Note that this function will decrement the CIS address by two
1352*7c478bd9Sstevel@tonic-gate  *	elements prior to storing it to the linked list element to point
1353*7c478bd9Sstevel@tonic-gate  *	to the tuple type byte.
1354*7c478bd9Sstevel@tonic-gate  *
1355*7c478bd9Sstevel@tonic-gate  * This function also sets the following flags in tp->flags if they are set
1356*7c478bd9Sstevel@tonic-gate  *	in ptr->flags:
1357*7c478bd9Sstevel@tonic-gate  *
1358*7c478bd9Sstevel@tonic-gate  *		CISTPLF_GLOBAL_CIS - tuple in global CIS
1359*7c478bd9Sstevel@tonic-gate  *		CISTPLF_MF_CIS - tuple in function-specific CIS
1360*7c478bd9Sstevel@tonic-gate  */
1361*7c478bd9Sstevel@tonic-gate static void
1362*7c478bd9Sstevel@tonic-gate cis_store_cis_addr(cistpl_t *tp, cisptr_t *ptr)
1363*7c478bd9Sstevel@tonic-gate {
1364*7c478bd9Sstevel@tonic-gate 
1365*7c478bd9Sstevel@tonic-gate 	if (ptr->flags & CISTPLF_AM_SPACE)
1366*7c478bd9Sstevel@tonic-gate 	    tp->offset = ptr->offset - 4;
1367*7c478bd9Sstevel@tonic-gate 	else
1368*7c478bd9Sstevel@tonic-gate 	    tp->offset = ptr->offset - 2;
1369*7c478bd9Sstevel@tonic-gate 
1370*7c478bd9Sstevel@tonic-gate 	tp->flags &= ~(CISTPLF_SPACE_MASK | CISTPLF_FROM_MASK |
1371*7c478bd9Sstevel@tonic-gate 					CISTPLF_GLOBAL_CIS | CISTPLF_MF_CIS);
1372*7c478bd9Sstevel@tonic-gate 	tp->flags |= (ptr->flags & (CISTPLF_SPACE_MASK |
1373*7c478bd9Sstevel@tonic-gate 					CISTPLF_GLOBAL_CIS | CISTPLF_MF_CIS));
1374*7c478bd9Sstevel@tonic-gate 
1375*7c478bd9Sstevel@tonic-gate 	if (tp->flags & CISTPLF_AM_SPACE)
1376*7c478bd9Sstevel@tonic-gate 	    tp->flags |= CISTPLF_FROM_AM;
1377*7c478bd9Sstevel@tonic-gate 
1378*7c478bd9Sstevel@tonic-gate 	if (tp->flags & CISTPLF_CM_SPACE)
1379*7c478bd9Sstevel@tonic-gate 	    tp->flags |= CISTPLF_FROM_CM;
1380*7c478bd9Sstevel@tonic-gate }
1381