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 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 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 * 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 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 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 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 * 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 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 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 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 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 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 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