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