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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2015 OmniTI Computer Consulting, Inc. All rights reserved. 24 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 /* 29 * SMBIOS Information Routines 30 * 31 * The routines in this file are used to convert from the SMBIOS data format to 32 * a more reasonable and stable set of structures offered as part of our ABI. 33 * These functions take the general form: 34 * 35 * stp = smb_lookup_type(shp, foo); 36 * smb_foo_t foo; 37 * 38 * smb_info_bcopy(stp->smbst_hdr, &foo, sizeof (foo)); 39 * bzero(caller's struct); 40 * 41 * copy/convert foo members into caller's struct 42 * 43 * We copy the internal structure on to an automatic variable so as to avoid 44 * checks everywhere for structures that the BIOS has improperly truncated, and 45 * also to automatically handle the case of a structure that has been extended. 46 * When necessary, this code can use smb_gteq() to determine whether the SMBIOS 47 * data is of a particular revision that is supposed to contain a new field. 48 */ 49 50 #include <sys/smbios_impl.h> 51 52 #ifdef _KERNEL 53 #include <sys/sunddi.h> 54 #else 55 #include <fcntl.h> 56 #include <unistd.h> 57 #include <string.h> 58 #endif 59 60 /* 61 * A large number of SMBIOS structures contain a set of common strings used to 62 * describe a h/w component's serial number, manufacturer, etc. These fields 63 * helpfully have different names and offsets and sometimes aren't consistent. 64 * To simplify life for our clients, we factor these common things out into 65 * smbios_info_t, which can be retrieved for any structure. The following 66 * table describes the mapping from a given structure to the smbios_info_t. 67 * Multiple SMBIOS stuctures' contained objects are also handled here. 68 */ 69 static const struct smb_infospec { 70 uint8_t is_type; /* structure type */ 71 uint8_t is_manu; /* manufacturer offset */ 72 uint8_t is_product; /* product name offset */ 73 uint8_t is_version; /* version offset */ 74 uint8_t is_serial; /* serial number offset */ 75 uint8_t is_asset; /* asset tag offset */ 76 uint8_t is_location; /* location string offset */ 77 uint8_t is_part; /* part number offset */ 78 uint8_t is_contc; /* contained count */ 79 uint8_t is_contsz; /* contained size */ 80 uint8_t is_contv; /* contained objects */ 81 } _smb_infospecs[] = { 82 { SMB_TYPE_SYSTEM, 83 offsetof(smb_system_t, smbsi_manufacturer), 84 offsetof(smb_system_t, smbsi_product), 85 offsetof(smb_system_t, smbsi_version), 86 offsetof(smb_system_t, smbsi_serial), 87 0, 88 0, 89 0, 90 0, 91 0, 92 0 }, 93 { SMB_TYPE_BASEBOARD, 94 offsetof(smb_bboard_t, smbbb_manufacturer), 95 offsetof(smb_bboard_t, smbbb_product), 96 offsetof(smb_bboard_t, smbbb_version), 97 offsetof(smb_bboard_t, smbbb_serial), 98 offsetof(smb_bboard_t, smbbb_asset), 99 offsetof(smb_bboard_t, smbbb_location), 100 0, 101 offsetof(smb_bboard_t, smbbb_cn), 102 SMB_CONT_WORD, 103 offsetof(smb_bboard_t, smbbb_cv) }, 104 { SMB_TYPE_CHASSIS, 105 offsetof(smb_chassis_t, smbch_manufacturer), 106 0, 107 offsetof(smb_chassis_t, smbch_version), 108 offsetof(smb_chassis_t, smbch_serial), 109 offsetof(smb_chassis_t, smbch_asset), 110 0, 111 0, 112 offsetof(smb_chassis_t, smbch_cn), 113 SMB_CONT_BYTE, 114 offsetof(smb_chassis_t, smbch_cv) }, 115 { SMB_TYPE_PROCESSOR, 116 offsetof(smb_processor_t, smbpr_manufacturer), 117 0, 118 offsetof(smb_processor_t, smbpr_version), 119 offsetof(smb_processor_t, smbpr_serial), 120 offsetof(smb_processor_t, smbpr_asset), 121 offsetof(smb_processor_t, smbpr_socket), 122 offsetof(smb_processor_t, smbpr_part), 123 0, 124 0, 125 0 }, 126 { SMB_TYPE_CACHE, 127 0, 128 0, 129 0, 130 0, 131 0, 132 offsetof(smb_cache_t, smbca_socket), 133 0, 134 0, 135 0, 136 0 }, 137 { SMB_TYPE_PORT, 138 0, 139 0, 140 0, 141 0, 142 0, 143 offsetof(smb_port_t, smbpo_iref), 144 0, 145 0, 146 0, 147 0 }, 148 { SMB_TYPE_SLOT, 149 0, 150 0, 151 0, 152 0, 153 0, 154 offsetof(smb_slot_t, smbsl_name), 155 0, 156 0, 157 0, 158 0 }, 159 { SMB_TYPE_MEMDEVICE, 160 offsetof(smb_memdevice_t, smbmdev_manufacturer), 161 0, 162 0, 163 offsetof(smb_memdevice_t, smbmdev_serial), 164 offsetof(smb_memdevice_t, smbmdev_asset), 165 offsetof(smb_memdevice_t, smbmdev_dloc), 166 offsetof(smb_memdevice_t, smbmdev_part), 167 0, 168 0, 169 0 }, 170 { SMB_TYPE_POWERSUP, 171 offsetof(smb_powersup_t, smbpsup_manufacturer), 172 offsetof(smb_powersup_t, smbpsup_devname), 173 offsetof(smb_powersup_t, smbpsup_rev), 174 offsetof(smb_powersup_t, smbpsup_serial), 175 offsetof(smb_powersup_t, smbpsup_asset), 176 offsetof(smb_powersup_t, smbpsup_loc), 177 offsetof(smb_powersup_t, smbpsup_part), 178 0, 179 0, 180 0 }, 181 { SMB_TYPE_EOT } 182 }; 183 184 static const char * 185 smb_info_strptr(const smb_struct_t *stp, uint8_t off, int *n) 186 { 187 const uint8_t *sp = (const uint8_t *)(uintptr_t)stp->smbst_hdr; 188 189 if (off != 0 && sp + off < stp->smbst_end) { 190 (*n)++; /* indicate success for caller */ 191 return (smb_strptr(stp, sp[off])); 192 } 193 194 return (smb_strptr(stp, 0)); 195 } 196 197 static void 198 smb_info_bcopy(const smb_header_t *hp, void *dst, size_t dstlen) 199 { 200 if (dstlen > hp->smbh_len) { 201 bcopy(hp, dst, hp->smbh_len); 202 bzero((char *)dst + hp->smbh_len, dstlen - hp->smbh_len); 203 } else 204 bcopy(hp, dst, dstlen); 205 } 206 207 void 208 smbios_info_smbios(smbios_hdl_t *shp, smbios_entry_t *ep) 209 { 210 bcopy(&shp->sh_ent, ep, sizeof (smbios_entry_t)); 211 } 212 213 #ifndef _KERNEL 214 static char smbios_product_override[256]; 215 static boolean_t smbios_product_checked; 216 #endif 217 218 int 219 smbios_info_common(smbios_hdl_t *shp, id_t id, smbios_info_t *ip) 220 { 221 const smb_struct_t *stp = smb_lookup_id(shp, id); 222 const struct smb_infospec *isp; 223 int n = 0; 224 225 if (stp == NULL) 226 return (-1); /* errno is set for us */ 227 228 for (isp = _smb_infospecs; isp->is_type != SMB_TYPE_EOT; isp++) { 229 if (isp->is_type == stp->smbst_hdr->smbh_type) 230 break; 231 } 232 233 ip->smbi_manufacturer = smb_info_strptr(stp, isp->is_manu, &n); 234 ip->smbi_product = smb_info_strptr(stp, isp->is_product, &n); 235 ip->smbi_version = smb_info_strptr(stp, isp->is_version, &n); 236 ip->smbi_serial = smb_info_strptr(stp, isp->is_serial, &n); 237 ip->smbi_asset = smb_info_strptr(stp, isp->is_asset, &n); 238 ip->smbi_location = smb_info_strptr(stp, isp->is_location, &n); 239 ip->smbi_part = smb_info_strptr(stp, isp->is_part, &n); 240 241 /* 242 * This private file allows developers to experiment with reporting 243 * different platform strings from SMBIOS. It is not a supported 244 * mechanism in the long term, and does not work in the kernel. 245 */ 246 #ifndef _KERNEL 247 if (isp->is_type == SMB_TYPE_SYSTEM) { 248 if (!smbios_product_checked) { 249 int fd = open("/etc/smbios_product", O_RDONLY); 250 if (fd >= 0) { 251 (void) read(fd, smbios_product_override, 252 sizeof (smbios_product_override) - 1); 253 (void) close(fd); 254 } 255 smbios_product_checked = B_TRUE; 256 } 257 258 if (smbios_product_override[0] != '\0') 259 ip->smbi_product = smbios_product_override; 260 } 261 #endif 262 263 /* 264 * If we have a port with an empty internal reference designator string 265 * try using the external reference designator string instead. 266 */ 267 if (isp->is_type == SMB_TYPE_PORT && ip->smbi_location[0] == '\0') { 268 ip->smbi_location = smb_info_strptr(stp, 269 offsetof(smb_port_t, smbpo_eref), &n); 270 } 271 272 return (n ? 0 : smb_set_errno(shp, ESMB_NOINFO)); 273 } 274 275 /* 276 * Returns the actual number of contained objects. 277 * 278 * idc - number of contained objects 279 * idv - returned array of contained objects 280 */ 281 int 282 smbios_info_contains(smbios_hdl_t *shp, id_t id, uint_t idc, id_t *idv) 283 { 284 const smb_struct_t *stp = smb_lookup_id(shp, id); 285 const struct smb_infospec *isp; 286 id_t *cp; 287 uint_t size; 288 uint8_t cnt; 289 int i, n; 290 291 if (stp == NULL) { 292 return (-1); /* errno is set for us */ 293 } 294 295 for (isp = _smb_infospecs; isp->is_type != SMB_TYPE_EOT; isp++) { 296 if (isp->is_type == stp->smbst_hdr->smbh_type) 297 break; 298 } 299 if (isp->is_type == SMB_TYPE_EOT) 300 return (smb_set_errno(shp, ESMB_TYPE)); 301 302 size = isp->is_contsz; 303 cnt = *((uint8_t *)(uintptr_t)stp->smbst_hdr + isp->is_contc); 304 cp = (id_t *)((uintptr_t)stp->smbst_hdr + isp->is_contv); 305 306 n = MIN(cnt, idc); 307 for (i = 0; i < n; i++) { 308 if (size == SMB_CONT_WORD) 309 idv[i] = *((uint8_t *)(uintptr_t)cp + (i * 2)); 310 else if (size == SMB_CONT_BYTE) 311 idv[i] = *((uint8_t *)(uintptr_t)cp + (i * 3)); 312 else 313 return (smb_set_errno(shp, ESMB_INVAL)); 314 } 315 316 return (cnt); 317 } 318 319 id_t 320 smbios_info_bios(smbios_hdl_t *shp, smbios_bios_t *bp) 321 { 322 const smb_struct_t *stp = smb_lookup_type(shp, SMB_TYPE_BIOS); 323 const smb_bios_t *bip; 324 325 if (stp == NULL) 326 return (-1); /* errno is set for us */ 327 328 if (stp->smbst_hdr->smbh_len < sizeof (smb_bios_t) - sizeof (uint8_t)) 329 return (smb_set_errno(shp, ESMB_CORRUPT)); 330 331 bip = (smb_bios_t *)(uintptr_t)stp->smbst_hdr; 332 bzero(bp, sizeof (smbios_bios_t)); 333 334 bp->smbb_vendor = smb_strptr(stp, bip->smbbi_vendor); 335 bp->smbb_version = smb_strptr(stp, bip->smbbi_version); 336 bp->smbb_segment = bip->smbbi_segment; 337 bp->smbb_reldate = smb_strptr(stp, bip->smbbi_reldate); 338 bp->smbb_romsize = 64 * 1024 * ((uint32_t)bip->smbbi_romsize + 1); 339 bp->smbb_runsize = 16 * (0x10000 - (uint32_t)bip->smbbi_segment); 340 bp->smbb_cflags = bip->smbbi_cflags; 341 342 /* 343 * If one or more extension bytes are present, reset smbb_xcflags to 344 * point to them. Otherwise leave this member set to NULL. 345 */ 346 if (stp->smbst_hdr->smbh_len >= sizeof (smb_bios_t)) { 347 bp->smbb_xcflags = bip->smbbi_xcflags; 348 bp->smbb_nxcflags = stp->smbst_hdr->smbh_len - 349 sizeof (smb_bios_t) + 1; 350 351 if (bp->smbb_nxcflags > SMB_BIOSXB_ECFW_MIN && 352 smb_gteq(shp, SMB_VERSION_24)) { 353 bp->smbb_biosv.smbv_major = 354 bip->smbbi_xcflags[SMB_BIOSXB_BIOS_MAJ]; 355 bp->smbb_biosv.smbv_minor = 356 bip->smbbi_xcflags[SMB_BIOSXB_BIOS_MIN]; 357 bp->smbb_ecfwv.smbv_major = 358 bip->smbbi_xcflags[SMB_BIOSXB_ECFW_MAJ]; 359 bp->smbb_ecfwv.smbv_minor = 360 bip->smbbi_xcflags[SMB_BIOSXB_ECFW_MIN]; 361 } 362 } 363 364 return (stp->smbst_hdr->smbh_hdl); 365 } 366 367 id_t 368 smbios_info_system(smbios_hdl_t *shp, smbios_system_t *sip) 369 { 370 const smb_struct_t *stp = smb_lookup_type(shp, SMB_TYPE_SYSTEM); 371 smb_system_t si; 372 373 if (stp == NULL) 374 return (-1); /* errno is set for us */ 375 376 smb_info_bcopy(stp->smbst_hdr, &si, sizeof (si)); 377 bzero(sip, sizeof (smbios_system_t)); 378 379 sip->smbs_uuid = ((smb_system_t *)stp->smbst_hdr)->smbsi_uuid; 380 sip->smbs_uuidlen = sizeof (si.smbsi_uuid); 381 sip->smbs_wakeup = si.smbsi_wakeup; 382 sip->smbs_sku = smb_strptr(stp, si.smbsi_sku); 383 sip->smbs_family = smb_strptr(stp, si.smbsi_family); 384 385 return (stp->smbst_hdr->smbh_hdl); 386 } 387 388 int 389 smbios_info_bboard(smbios_hdl_t *shp, id_t id, smbios_bboard_t *bbp) 390 { 391 const smb_struct_t *stp = smb_lookup_id(shp, id); 392 smb_bboard_t bb; 393 394 if (stp == NULL) 395 return (-1); /* errno is set for us */ 396 397 if (stp->smbst_hdr->smbh_type != SMB_TYPE_BASEBOARD) 398 return (smb_set_errno(shp, ESMB_TYPE)); 399 400 smb_info_bcopy(stp->smbst_hdr, &bb, sizeof (bb)); 401 bzero(bbp, sizeof (smbios_bboard_t)); 402 403 bbp->smbb_chassis = bb.smbbb_chassis; 404 bbp->smbb_flags = bb.smbbb_flags; 405 bbp->smbb_type = bb.smbbb_type; 406 bbp->smbb_contn = bb.smbbb_cn; 407 408 return (0); 409 } 410 411 int 412 smbios_info_chassis(smbios_hdl_t *shp, id_t id, smbios_chassis_t *chp) 413 { 414 const smb_struct_t *stp = smb_lookup_id(shp, id); 415 /* Length is measurable by one byte, so it'll be no more than 255. */ 416 uint8_t buf[256]; 417 smb_chassis_t *ch = (smb_chassis_t *)&buf[0]; 418 419 if (stp == NULL) 420 return (-1); /* errno is set for us */ 421 422 if (stp->smbst_hdr->smbh_type != SMB_TYPE_CHASSIS) 423 return (smb_set_errno(shp, ESMB_TYPE)); 424 425 smb_info_bcopy(stp->smbst_hdr, ch, sizeof (buf)); 426 bzero(chp, sizeof (smbios_chassis_t)); 427 428 chp->smbc_oemdata = ch->smbch_oemdata; 429 chp->smbc_lock = (ch->smbch_type & SMB_CHT_LOCK) != 0; 430 chp->smbc_type = ch->smbch_type & ~SMB_CHT_LOCK; 431 chp->smbc_bustate = ch->smbch_bustate; 432 chp->smbc_psstate = ch->smbch_psstate; 433 chp->smbc_thstate = ch->smbch_thstate; 434 chp->smbc_security = ch->smbch_security; 435 chp->smbc_uheight = ch->smbch_uheight; 436 chp->smbc_cords = ch->smbch_cords; 437 chp->smbc_elems = ch->smbch_cn; 438 chp->smbc_elemlen = ch->smbch_cm; 439 440 if (shp->sh_smbvers >= SMB_VERSION_27) { 441 (void) strlcpy(chp->smbc_sku, SMB_CH_SKU(ch), 442 sizeof (chp->smbc_sku)); 443 } 444 445 return (0); 446 } 447 448 int 449 smbios_info_processor(smbios_hdl_t *shp, id_t id, smbios_processor_t *pp) 450 { 451 const smb_struct_t *stp = smb_lookup_id(shp, id); 452 smb_processor_t p; 453 454 if (stp == NULL) 455 return (-1); /* errno is set for us */ 456 457 if (stp->smbst_hdr->smbh_type != SMB_TYPE_PROCESSOR) 458 return (smb_set_errno(shp, ESMB_TYPE)); 459 460 smb_info_bcopy(stp->smbst_hdr, &p, sizeof (p)); 461 bzero(pp, sizeof (smbios_processor_t)); 462 463 pp->smbp_cpuid = p.smbpr_cpuid; 464 pp->smbp_type = p.smbpr_type; 465 pp->smbp_family = p.smbpr_family; 466 pp->smbp_voltage = p.smbpr_voltage; 467 pp->smbp_maxspeed = p.smbpr_maxspeed; 468 pp->smbp_curspeed = p.smbpr_curspeed; 469 pp->smbp_status = p.smbpr_status; 470 pp->smbp_upgrade = p.smbpr_upgrade; 471 pp->smbp_l1cache = p.smbpr_l1cache; 472 pp->smbp_l2cache = p.smbpr_l2cache; 473 pp->smbp_l3cache = p.smbpr_l3cache; 474 475 if (shp->sh_smbvers >= SMB_VERSION_25) { 476 pp->smbp_corecount = p.smbpr_corecount; 477 pp->smbp_coresenabled = p.smbpr_coresenabled; 478 pp->smbp_threadcount = p.smbpr_threadcount; 479 pp->smbp_cflags = p.smbpr_cflags; 480 } 481 482 if (shp->sh_smbvers >= SMB_VERSION_26) 483 pp->smbp_family2 = p.smbpr_family2; 484 485 return (0); 486 } 487 488 int 489 smbios_info_cache(smbios_hdl_t *shp, id_t id, smbios_cache_t *cap) 490 { 491 const smb_struct_t *stp = smb_lookup_id(shp, id); 492 smb_cache_t c; 493 494 if (stp == NULL) 495 return (-1); /* errno is set for us */ 496 497 if (stp->smbst_hdr->smbh_type != SMB_TYPE_CACHE) 498 return (smb_set_errno(shp, ESMB_TYPE)); 499 500 smb_info_bcopy(stp->smbst_hdr, &c, sizeof (c)); 501 bzero(cap, sizeof (smbios_cache_t)); 502 503 cap->smba_maxsize = SMB_CACHE_SIZE(c.smbca_maxsize); 504 cap->smba_size = SMB_CACHE_SIZE(c.smbca_size); 505 cap->smba_stype = c.smbca_stype; 506 cap->smba_ctype = c.smbca_ctype; 507 cap->smba_speed = c.smbca_speed; 508 cap->smba_etype = c.smbca_etype; 509 cap->smba_ltype = c.smbca_ltype; 510 cap->smba_assoc = c.smbca_assoc; 511 cap->smba_level = SMB_CACHE_CFG_LEVEL(c.smbca_config); 512 cap->smba_mode = SMB_CACHE_CFG_MODE(c.smbca_config); 513 cap->smba_location = SMB_CACHE_CFG_LOCATION(c.smbca_config); 514 515 if (SMB_CACHE_CFG_ENABLED(c.smbca_config)) 516 cap->smba_flags |= SMB_CAF_ENABLED; 517 518 if (SMB_CACHE_CFG_SOCKETED(c.smbca_config)) 519 cap->smba_flags |= SMB_CAF_SOCKETED; 520 521 return (0); 522 } 523 524 int 525 smbios_info_port(smbios_hdl_t *shp, id_t id, smbios_port_t *pop) 526 { 527 const smb_struct_t *stp = smb_lookup_id(shp, id); 528 smb_port_t p; 529 530 if (stp == NULL) 531 return (-1); /* errno is set for us */ 532 533 if (stp->smbst_hdr->smbh_type != SMB_TYPE_PORT) 534 return (smb_set_errno(shp, ESMB_TYPE)); 535 536 smb_info_bcopy(stp->smbst_hdr, &p, sizeof (p)); 537 bzero(pop, sizeof (smbios_port_t)); 538 539 pop->smbo_iref = smb_strptr(stp, p.smbpo_iref); 540 pop->smbo_eref = smb_strptr(stp, p.smbpo_eref); 541 542 pop->smbo_itype = p.smbpo_itype; 543 pop->smbo_etype = p.smbpo_etype; 544 pop->smbo_ptype = p.smbpo_ptype; 545 546 return (0); 547 } 548 549 int 550 smbios_info_slot(smbios_hdl_t *shp, id_t id, smbios_slot_t *sp) 551 { 552 const smb_struct_t *stp = smb_lookup_id(shp, id); 553 smb_slot_t s; 554 555 if (stp == NULL) 556 return (-1); /* errno is set for us */ 557 558 if (stp->smbst_hdr->smbh_type != SMB_TYPE_SLOT) 559 return (smb_set_errno(shp, ESMB_TYPE)); 560 561 smb_info_bcopy(stp->smbst_hdr, &s, sizeof (s)); 562 bzero(sp, sizeof (smbios_slot_t)); 563 564 sp->smbl_name = smb_strptr(stp, s.smbsl_name); 565 sp->smbl_type = s.smbsl_type; 566 sp->smbl_width = s.smbsl_width; 567 sp->smbl_usage = s.smbsl_usage; 568 sp->smbl_length = s.smbsl_length; 569 sp->smbl_id = s.smbsl_id; 570 sp->smbl_ch1 = s.smbsl_ch1; 571 sp->smbl_ch2 = s.smbsl_ch2; 572 sp->smbl_sg = s.smbsl_sg; 573 sp->smbl_bus = s.smbsl_bus; 574 sp->smbl_df = s.smbsl_df; 575 576 return (0); 577 } 578 579 int 580 smbios_info_obdevs_ext(smbios_hdl_t *shp, id_t id, smbios_obdev_ext_t *oep) 581 { 582 const smb_struct_t *stp = smb_lookup_id(shp, id); 583 smb_obdev_ext_t obe; 584 585 if (stp == NULL) 586 return (-1); /* errno is set for us */ 587 588 if (stp->smbst_hdr->smbh_type != SMB_TYPE_OBDEVEXT) 589 return (smb_set_errno(shp, ESMB_TYPE)); 590 591 smb_info_bcopy(stp->smbst_hdr, &obe, sizeof (obe)); 592 bzero(oep, sizeof (smbios_obdev_ext_t)); 593 594 oep->smboe_name = smb_strptr(stp, obe.smbobe_name); 595 oep->smboe_dtype = obe.smbobe_dtype; 596 oep->smboe_dti = obe.smbobe_dti; 597 oep->smboe_sg = obe.smbobe_sg; 598 oep->smboe_bus = obe.smbobe_bus; 599 oep->smboe_df = obe.smbobe_df; 600 601 return (0); 602 } 603 604 int 605 smbios_info_obdevs(smbios_hdl_t *shp, id_t id, int obc, smbios_obdev_t *obp) 606 { 607 const smb_struct_t *stp = smb_lookup_id(shp, id); 608 const smb_obdev_t *op; 609 int i, m, n; 610 611 if (stp == NULL) 612 return (-1); /* errno is set for us */ 613 614 if (stp->smbst_hdr->smbh_type != SMB_TYPE_OBDEVS) 615 return (smb_set_errno(shp, ESMB_TYPE)); 616 617 op = (smb_obdev_t *)((uintptr_t)stp->smbst_hdr + sizeof (smb_header_t)); 618 m = (stp->smbst_hdr->smbh_len - sizeof (smb_header_t)) / sizeof (*op); 619 n = MIN(m, obc); 620 621 for (i = 0; i < n; i++, op++, obp++) { 622 obp->smbd_name = smb_strptr(stp, op->smbob_name); 623 obp->smbd_type = op->smbob_type & ~SMB_OBT_ENABLED; 624 obp->smbd_enabled = (op->smbob_type & SMB_OBT_ENABLED) != 0; 625 } 626 627 return (m); 628 } 629 630 /* 631 * The implementation structures for OEMSTR, SYSCONFSTR, and LANG all use the 632 * first byte to indicate the size of a string table at the end of the record. 633 * Therefore, smbios_info_strtab() can be used to retrieve the table size and 634 * strings for any of these underlying record types. 635 */ 636 int 637 smbios_info_strtab(smbios_hdl_t *shp, id_t id, int argc, const char *argv[]) 638 { 639 const smb_struct_t *stp = smb_lookup_id(shp, id); 640 smb_strtab_t s; 641 int i, n; 642 643 if (stp == NULL) 644 return (-1); /* errno is set for us */ 645 646 if (stp->smbst_hdr->smbh_type != SMB_TYPE_OEMSTR && 647 stp->smbst_hdr->smbh_type != SMB_TYPE_SYSCONFSTR && 648 stp->smbst_hdr->smbh_type != SMB_TYPE_LANG) 649 return (smb_set_errno(shp, ESMB_TYPE)); 650 651 smb_info_bcopy(stp->smbst_hdr, &s, sizeof (s)); 652 n = MIN(s.smbtb_count, argc); 653 654 for (i = 0; i < n; i++) 655 argv[i] = smb_strptr(stp, i + 1); 656 657 return (s.smbtb_count); 658 } 659 660 id_t 661 smbios_info_lang(smbios_hdl_t *shp, smbios_lang_t *lp) 662 { 663 const smb_struct_t *stp = smb_lookup_type(shp, SMB_TYPE_LANG); 664 smb_lang_t l; 665 666 if (stp == NULL) 667 return (-1); /* errno is set for us */ 668 669 smb_info_bcopy(stp->smbst_hdr, &l, sizeof (l)); 670 bzero(lp, sizeof (smbios_lang_t)); 671 672 lp->smbla_cur = smb_strptr(stp, l.smblang_cur); 673 lp->smbla_fmt = l.smblang_flags & 1; 674 lp->smbla_num = l.smblang_num; 675 676 return (stp->smbst_hdr->smbh_hdl); 677 } 678 679 id_t 680 smbios_info_eventlog(smbios_hdl_t *shp, smbios_evlog_t *evp) 681 { 682 const smb_struct_t *stp = smb_lookup_type(shp, SMB_TYPE_EVENTLOG); 683 const smb_sel_t *sel; 684 size_t len; 685 686 if (stp == NULL) 687 return (-1); /* errno is set for us */ 688 689 if (stp->smbst_hdr->smbh_len < sizeof (smb_sel_t) - sizeof (uint8_t)) 690 return (smb_set_errno(shp, ESMB_CORRUPT)); 691 692 sel = (smb_sel_t *)(uintptr_t)stp->smbst_hdr; 693 len = stp->smbst_hdr->smbh_len - sizeof (smb_sel_t) + sizeof (uint8_t); 694 bzero(evp, sizeof (smbios_evlog_t)); 695 696 if (len < sel->smbsel_typec * sel->smbsel_typesz) 697 return (smb_set_errno(shp, ESMB_CORRUPT)); 698 699 evp->smbev_size = sel->smbsel_len; 700 evp->smbev_hdr = sel->smbsel_hdroff; 701 evp->smbev_data = sel->smbsel_dataoff; 702 evp->smbev_method = sel->smbsel_method; 703 evp->smbev_flags = sel->smbsel_status; 704 evp->smbev_format = sel->smbsel_format; 705 evp->smbev_token = sel->smbsel_token; 706 evp->smbev_addr.eva_addr = sel->smbsel_addr; 707 708 if (sel->smbsel_typesz == sizeof (smbios_evtype_t)) { 709 evp->smbev_typec = sel->smbsel_typec; 710 evp->smbev_typev = (void *)(uintptr_t)sel->smbsel_typev; 711 } 712 713 return (stp->smbst_hdr->smbh_hdl); 714 } 715 716 int 717 smbios_info_memarray(smbios_hdl_t *shp, id_t id, smbios_memarray_t *map) 718 { 719 const smb_struct_t *stp = smb_lookup_id(shp, id); 720 smb_memarray_t m; 721 722 if (stp == NULL) 723 return (-1); /* errno is set for us */ 724 725 if (stp->smbst_hdr->smbh_type != SMB_TYPE_MEMARRAY) 726 return (smb_set_errno(shp, ESMB_TYPE)); 727 728 smb_info_bcopy(stp->smbst_hdr, &m, sizeof (m)); 729 bzero(map, sizeof (smbios_memarray_t)); 730 731 map->smbma_location = m.smbmarr_loc; 732 map->smbma_use = m.smbmarr_use; 733 map->smbma_ecc = m.smbmarr_ecc; 734 map->smbma_ndevs = m.smbmarr_ndevs; 735 map->smbma_err = m.smbmarr_err; 736 737 if (m.smbmarr_cap != 0x80000000) 738 map->smbma_size = (uint64_t)m.smbmarr_cap * 1024; 739 else if (m.smbmarr_extcap != 0) 740 map->smbma_size = m.smbmarr_extcap; 741 else 742 map->smbma_size = 0; /* unknown */ 743 744 return (0); 745 } 746 747 int 748 smbios_info_memarrmap(smbios_hdl_t *shp, id_t id, smbios_memarrmap_t *map) 749 { 750 const smb_struct_t *stp = smb_lookup_id(shp, id); 751 smb_memarrmap_t m; 752 753 if (stp == NULL) 754 return (-1); /* errno is set for us */ 755 756 if (stp->smbst_hdr->smbh_type != SMB_TYPE_MEMARRAYMAP) 757 return (smb_set_errno(shp, ESMB_TYPE)); 758 759 smb_info_bcopy(stp->smbst_hdr, &m, sizeof (m)); 760 bzero(map, sizeof (smbios_memarrmap_t)); 761 762 map->smbmam_array = m.smbamap_array; 763 map->smbmam_width = m.smbamap_width; 764 765 if (m.smbamap_start != 0xFFFFFFFF && m.smbamap_end != 0xFFFFFFFF) { 766 map->smbmam_addr = (uint64_t)m.smbamap_start * 1024; 767 map->smbmam_size = (uint64_t) 768 (m.smbamap_end - m.smbamap_start + 1) * 1024; 769 } else if (m.smbamap_extstart != 0 && m.smbamap_extend != 0) { 770 map->smbmam_addr = m.smbamap_extstart; 771 map->smbmam_size = m.smbamap_extend - m.smbamap_extstart + 1; 772 } 773 774 return (0); 775 } 776 777 int 778 smbios_info_memdevice(smbios_hdl_t *shp, id_t id, smbios_memdevice_t *mdp) 779 { 780 const smb_struct_t *stp = smb_lookup_id(shp, id); 781 smb_memdevice_t m; 782 783 if (stp == NULL) 784 return (-1); /* errno is set for us */ 785 786 if (stp->smbst_hdr->smbh_type != SMB_TYPE_MEMDEVICE) 787 return (smb_set_errno(shp, ESMB_TYPE)); 788 789 smb_info_bcopy(stp->smbst_hdr, &m, sizeof (m)); 790 bzero(mdp, sizeof (smbios_memdevice_t)); 791 792 mdp->smbmd_array = m.smbmdev_array; 793 mdp->smbmd_error = m.smbmdev_error; 794 mdp->smbmd_twidth = m.smbmdev_twidth == 0xFFFF ? -1U : m.smbmdev_twidth; 795 mdp->smbmd_dwidth = m.smbmdev_dwidth == 0xFFFF ? -1U : m.smbmdev_dwidth; 796 797 if (m.smbmdev_size == 0x7FFF) { 798 mdp->smbmd_size = (uint64_t)m.smbmdev_extsize; 799 mdp->smbmd_size *= 1024 * 1024; /* convert MB to bytes */ 800 } else if (m.smbmdev_size != 0xFFFF) { 801 mdp->smbmd_size = (uint64_t)(m.smbmdev_size & ~SMB_MDS_KBYTES); 802 if (m.smbmdev_size & SMB_MDS_KBYTES) 803 mdp->smbmd_size *= 1024; 804 else 805 mdp->smbmd_size *= 1024 * 1024; 806 } else 807 mdp->smbmd_size = -1ULL; /* size unknown */ 808 809 mdp->smbmd_form = m.smbmdev_form; 810 mdp->smbmd_set = m.smbmdev_set; 811 mdp->smbmd_type = m.smbmdev_type; 812 mdp->smbmd_speed = m.smbmdev_speed; 813 mdp->smbmd_flags = m.smbmdev_flags; 814 mdp->smbmd_dloc = smb_strptr(stp, m.smbmdev_dloc); 815 mdp->smbmd_bloc = smb_strptr(stp, m.smbmdev_bloc); 816 817 if (shp->sh_smbvers >= SMB_VERSION_26) 818 mdp->smbmd_rank = m.smbmdev_attrs & 0x0F; 819 820 if (shp->sh_smbvers >= SMB_VERSION_27) 821 mdp->smbmd_clkspeed = m.smbmdev_clkspeed; 822 823 if (shp->sh_smbvers >= SMB_VERSION_28) { 824 mdp->smbmd_minvolt = m.smbmdev_minvolt; 825 mdp->smbmd_maxvolt = m.smbmdev_maxvolt; 826 mdp->smbmd_confvolt = m.smbmdev_confvolt; 827 } 828 829 return (0); 830 } 831 832 int 833 smbios_info_memdevmap(smbios_hdl_t *shp, id_t id, smbios_memdevmap_t *mdp) 834 { 835 const smb_struct_t *stp = smb_lookup_id(shp, id); 836 smb_memdevmap_t m; 837 838 if (stp == NULL) 839 return (-1); /* errno is set for us */ 840 841 if (stp->smbst_hdr->smbh_type != SMB_TYPE_MEMDEVICEMAP) 842 return (smb_set_errno(shp, ESMB_TYPE)); 843 844 smb_info_bcopy(stp->smbst_hdr, &m, sizeof (m)); 845 bzero(mdp, sizeof (smbios_memdevmap_t)); 846 847 mdp->smbmdm_device = m.smbdmap_device; 848 mdp->smbmdm_arrmap = m.smbdmap_array; 849 mdp->smbmdm_rpos = m.smbdmap_rpos; 850 mdp->smbmdm_ipos = m.smbdmap_ipos; 851 mdp->smbmdm_idepth = m.smbdmap_idepth; 852 853 if (m.smbdmap_start != 0xFFFFFFFF && m.smbdmap_end != 0xFFFFFFFF) { 854 mdp->smbmdm_addr = (uint64_t)m.smbdmap_start * 1024; 855 mdp->smbmdm_size = (uint64_t) 856 (m.smbdmap_end - m.smbdmap_start + 1) * 1024; 857 } else if (m.smbdmap_extstart != 0 && m.smbdmap_extend != 0) { 858 mdp->smbmdm_addr = m.smbdmap_extstart; 859 mdp->smbmdm_size = m.smbdmap_extend - m.smbdmap_extstart + 1; 860 } 861 862 return (0); 863 } 864 865 id_t 866 smbios_info_hwsec(smbios_hdl_t *shp, smbios_hwsec_t *hsp) 867 { 868 const smb_struct_t *stp = smb_lookup_type(shp, SMB_TYPE_SECURITY); 869 smb_hwsec_t hs; 870 871 if (stp == NULL) 872 return (-1); /* errno is set for us */ 873 874 smb_info_bcopy(stp->smbst_hdr, &hs, sizeof (hs)); 875 bzero(hsp, sizeof (smbios_hwsec_t)); 876 877 hsp->smbh_pwr_ps = SMB_HWS_PWR_PS(hs.smbhs_settings); 878 hsp->smbh_kbd_ps = SMB_HWS_KBD_PS(hs.smbhs_settings); 879 hsp->smbh_adm_ps = SMB_HWS_ADM_PS(hs.smbhs_settings); 880 hsp->smbh_pan_ps = SMB_HWS_PAN_PS(hs.smbhs_settings); 881 882 return (stp->smbst_hdr->smbh_hdl); 883 } 884 885 id_t 886 smbios_info_boot(smbios_hdl_t *shp, smbios_boot_t *bp) 887 { 888 const smb_struct_t *stp = smb_lookup_type(shp, SMB_TYPE_BOOT); 889 const smb_boot_t *b = (smb_boot_t *)(uintptr_t)stp->smbst_hdr; 890 891 if (stp == NULL) 892 return (-1); /* errno is set for us */ 893 894 bzero(bp, sizeof (smbios_boot_t)); 895 896 bp->smbt_status = b->smbbo_status[0]; 897 bp->smbt_size = stp->smbst_hdr->smbh_len - sizeof (smb_boot_t); 898 bp->smbt_data = bp->smbt_size ? &b->smbbo_status[1] : NULL; 899 900 return (stp->smbst_hdr->smbh_hdl); 901 } 902 903 id_t 904 smbios_info_ipmi(smbios_hdl_t *shp, smbios_ipmi_t *ip) 905 { 906 const smb_struct_t *stp = smb_lookup_type(shp, SMB_TYPE_IPMIDEV); 907 smb_ipmi_t i; 908 909 if (stp == NULL) 910 return (-1); /* errno is set for us */ 911 912 smb_info_bcopy(stp->smbst_hdr, &i, sizeof (i)); 913 bzero(ip, sizeof (smbios_ipmi_t)); 914 915 ip->smbip_type = i.smbipm_type; 916 ip->smbip_vers.smbv_major = SMB_IPM_SPEC_MAJOR(i.smbipm_spec); 917 ip->smbip_vers.smbv_minor = SMB_IPM_SPEC_MINOR(i.smbipm_spec); 918 ip->smbip_i2c = i.smbipm_i2c; 919 ip->smbip_addr = i.smbipm_addr & ~SMB_IPM_ADDR_IO; 920 ip->smbip_intr = i.smbipm_intr; 921 922 if (i.smbipm_bus != (uint8_t)-1) 923 ip->smbip_bus = i.smbipm_bus; 924 else 925 ip->smbip_bus = -1u; 926 927 if (SMB_IPM_INFO_LSB(i.smbipm_info)) 928 ip->smbip_addr |= 1; /* turn on least-significant bit of addr */ 929 930 if (i.smbipm_addr & SMB_IPM_ADDR_IO) { 931 switch (SMB_IPM_INFO_REGS(i.smbipm_info)) { 932 case SMB_IPM_REGS_1B: 933 ip->smbip_regspacing = 1; 934 break; 935 case SMB_IPM_REGS_4B: 936 ip->smbip_regspacing = 4; 937 break; 938 case SMB_IPM_REGS_16B: 939 ip->smbip_regspacing = 16; 940 break; 941 default: 942 ip->smbip_regspacing = 1; 943 } 944 ip->smbip_flags |= SMB_IPMI_F_IOADDR; 945 } 946 947 if (SMB_IPM_INFO_ISPEC(i.smbipm_info)) 948 ip->smbip_flags |= SMB_IPMI_F_INTRSPEC; 949 950 if (SMB_IPM_INFO_IPOL(i.smbipm_info) == SMB_IPM_IPOL_HI) 951 ip->smbip_flags |= SMB_IPMI_F_INTRHIGH; 952 953 if (SMB_IPM_INFO_IMODE(i.smbipm_info) == SMB_IPM_IMODE_EDGE) 954 ip->smbip_flags |= SMB_IPMI_F_INTREDGE; 955 956 return (stp->smbst_hdr->smbh_hdl); 957 } 958 959 static boolean_t 960 smbios_has_oemstr(smbios_hdl_t *shp, const char *oemstr) 961 { 962 const smb_struct_t *stp = shp->sh_structs; 963 smb_strtab_t s; 964 int i, j; 965 966 for (i = 0; i < shp->sh_nstructs; i++, stp++) { 967 if (stp->smbst_hdr->smbh_type != SMB_TYPE_OEMSTR) 968 continue; 969 970 smb_info_bcopy(stp->smbst_hdr, &s, sizeof (s)); 971 for (j = 0; j < s.smbtb_count; j++) 972 if (strcmp(smb_strptr(stp, j + 1), oemstr) == 0) 973 return (B_TRUE); 974 } 975 976 return (B_FALSE); 977 } 978 979 static const char * 980 smb_serial_valid(const char *serial) 981 { 982 char buf[MAXNAMELEN]; 983 int i = 0; 984 985 if (serial == NULL) 986 return (NULL); 987 988 (void) strlcpy(buf, serial, sizeof (buf)); 989 990 while (buf[i] != '\0' && buf[i] == ' ') 991 i++; 992 993 if (buf[i] == '\0' || strstr(buf, SMB_DEFAULT1) != NULL || 994 strstr(buf, SMB_DEFAULT2) != NULL) 995 return (NULL); 996 997 return (serial); 998 } 999 1000 /* 1001 * Get chassis SN or product SN 1002 */ 1003 static int 1004 smb_get_sn(smbios_hdl_t *shp, const char **psnp, const char **csnp) 1005 { 1006 const smb_struct_t *stp; 1007 smbios_info_t s1, s3; 1008 1009 if (psnp == NULL || csnp == NULL) 1010 return (smb_set_errno(shp, ESMB_INVAL)); 1011 1012 *psnp = *csnp = NULL; 1013 1014 /* 1015 * If SMBIOS meets Sun's PRMS requirements, retrieve product SN 1016 * from type 1 structure, and chassis SN from type 3 structure. 1017 * Otherwise return SN in type 1 structure as chassis SN. 1018 */ 1019 1020 /* Get type 1 SN */ 1021 if ((stp = smb_lookup_type(shp, SMB_TYPE_SYSTEM)) == NULL || 1022 smbios_info_common(shp, stp->smbst_hdr->smbh_hdl, &s1) == SMB_ERR) 1023 s1.smbi_serial = NULL; 1024 1025 /* Get type 3 SN */ 1026 if ((stp = smb_lookup_type(shp, SMB_TYPE_CHASSIS)) == NULL || 1027 smbios_info_common(shp, stp->smbst_hdr->smbh_hdl, &s3) == SMB_ERR) 1028 s3.smbi_serial = NULL; 1029 1030 if (smbios_has_oemstr(shp, SMB_PRMS1)) { 1031 *psnp = smb_serial_valid(s1.smbi_serial); 1032 *csnp = smb_serial_valid(s3.smbi_serial); 1033 } else { 1034 *csnp = smb_serial_valid(s1.smbi_serial); 1035 } 1036 1037 return (0); 1038 } 1039 1040 const char * 1041 smbios_psn(smbios_hdl_t *shp) 1042 { 1043 const char *psn, *csn; 1044 1045 return (smb_get_sn(shp, &psn, &csn) == SMB_ERR ? NULL : psn); 1046 } 1047 1048 const char * 1049 smbios_csn(smbios_hdl_t *shp) 1050 { 1051 const char *psn, *csn; 1052 1053 return (smb_get_sn(shp, &psn, &csn) == SMB_ERR ? NULL : csn); 1054 } 1055 1056 int 1057 smbios_info_extprocessor(smbios_hdl_t *shp, id_t id, 1058 smbios_processor_ext_t *epp) 1059 { 1060 const smb_struct_t *stp = smb_lookup_id(shp, id); 1061 smb_processor_ext_t *exp; 1062 1063 if (stp == NULL) 1064 return (-1); /* errno is set for us */ 1065 1066 if (stp->smbst_hdr->smbh_type != SUN_OEM_EXT_PROCESSOR) 1067 return (smb_set_errno(shp, ESMB_TYPE)); 1068 1069 exp = (smb_processor_ext_t *)(uintptr_t)stp->smbst_hdr; 1070 bzero(epp, sizeof (smbios_processor_ext_t)); 1071 1072 epp->smbpe_processor = exp->smbpre_processor; 1073 epp->smbpe_fru = exp->smbpre_fru; 1074 epp->smbpe_n = exp->smbpre_n; 1075 epp->smbpe_apicid = exp->smbpre_apicid; 1076 1077 return (0); 1078 } 1079 1080 int 1081 smbios_info_extport(smbios_hdl_t *shp, id_t id, smbios_port_ext_t *eportp) 1082 { 1083 const smb_struct_t *stp = smb_lookup_id(shp, id); 1084 smb_port_ext_t *ep; 1085 1086 if (stp == NULL) 1087 return (-1); /* errno is set for us */ 1088 1089 if (stp->smbst_hdr->smbh_type != SUN_OEM_EXT_PORT) 1090 return (smb_set_errno(shp, ESMB_TYPE)); 1091 1092 ep = (smb_port_ext_t *)(uintptr_t)stp->smbst_hdr; 1093 bzero(eportp, sizeof (smbios_port_ext_t)); 1094 1095 eportp->smbporte_chassis = ep->smbpoe_chassis; 1096 eportp->smbporte_port = ep->smbpoe_port; 1097 eportp->smbporte_dtype = ep->smbpoe_dtype; 1098 eportp->smbporte_devhdl = ep->smbpoe_devhdl; 1099 eportp->smbporte_phy = ep->smbpoe_phy; 1100 1101 return (0); 1102 } 1103 1104 int 1105 smbios_info_pciexrc(smbios_hdl_t *shp, id_t id, 1106 smbios_pciexrc_t *rcp) 1107 { 1108 const smb_struct_t *stp = smb_lookup_id(shp, id); 1109 smb_pciexrc_t rc; 1110 1111 if (stp == NULL) 1112 return (-1); /* errno is set for us */ 1113 1114 if (stp->smbst_hdr->smbh_type != SUN_OEM_PCIEXRC) 1115 return (smb_set_errno(shp, ESMB_TYPE)); 1116 1117 smb_info_bcopy(stp->smbst_hdr, &rc, sizeof (rc)); 1118 bzero(rcp, sizeof (smbios_pciexrc_t)); 1119 1120 rcp->smbpcie_bb = rc.smbpciexrc_bboard; 1121 rcp->smbpcie_bdf = rc.smbpciexrc_bdf; 1122 1123 return (0); 1124 } 1125 1126 int 1127 smbios_info_extmemarray(smbios_hdl_t *shp, id_t id, smbios_memarray_ext_t *emap) 1128 { 1129 const smb_struct_t *stp = smb_lookup_id(shp, id); 1130 smb_memarray_ext_t exma; 1131 1132 if (stp == NULL) 1133 return (-1); /* errno is set for us */ 1134 1135 if (stp->smbst_hdr->smbh_type != SUN_OEM_EXT_MEMARRAY) 1136 return (smb_set_errno(shp, ESMB_TYPE)); 1137 1138 smb_info_bcopy(stp->smbst_hdr, &exma, sizeof (exma)); 1139 bzero(emap, sizeof (smbios_memarray_ext_t)); 1140 1141 emap->smbmae_ma = exma.smbmarre_ma; 1142 emap->smbmae_comp = exma.smbmarre_component; 1143 emap->smbmae_bdf = exma.smbmarre_bdf; 1144 1145 return (0); 1146 } 1147 1148 int 1149 smbios_info_extmemdevice(smbios_hdl_t *shp, id_t id, 1150 smbios_memdevice_ext_t *emdp) 1151 { 1152 const smb_struct_t *stp = smb_lookup_id(shp, id); 1153 smb_memdevice_ext_t exmd; 1154 1155 if (stp == NULL) 1156 return (-1); /* errno is set for us */ 1157 1158 if (stp->smbst_hdr->smbh_type != SUN_OEM_EXT_MEMDEVICE) 1159 return (smb_set_errno(shp, ESMB_TYPE)); 1160 1161 smb_info_bcopy(stp->smbst_hdr, &exmd, sizeof (exmd)); 1162 bzero(emdp, sizeof (smbios_memdevice_ext_t)); 1163 1164 emdp->smbmdeve_md = exmd.smbmdeve_mdev; 1165 emdp->smbmdeve_drch = exmd.smbmdeve_dchan; 1166 emdp->smbmdeve_ncs = exmd.smbmdeve_ncs; 1167 emdp->smbmdeve_cs = exmd.smbmdeve_cs; 1168 1169 return (0); 1170 } 1171