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