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