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