1a6e6969cSeschrock /* 2a6e6969cSeschrock * CDDL HEADER START 3a6e6969cSeschrock * 4a6e6969cSeschrock * The contents of this file are subject to the terms of the 5a6e6969cSeschrock * Common Development and Distribution License (the "License"). 6a6e6969cSeschrock * You may not use this file except in compliance with the License. 7a6e6969cSeschrock * 8a6e6969cSeschrock * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9a6e6969cSeschrock * or http://www.opensolaris.org/os/licensing. 10a6e6969cSeschrock * See the License for the specific language governing permissions 11a6e6969cSeschrock * and limitations under the License. 12a6e6969cSeschrock * 13a6e6969cSeschrock * When distributing Covered Code, include this CDDL HEADER in each 14a6e6969cSeschrock * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15a6e6969cSeschrock * If applicable, add the following below this CDDL HEADER, with the 16a6e6969cSeschrock * fields enclosed by brackets "[]" replaced with your own identifying 17a6e6969cSeschrock * information: Portions Copyright [yyyy] [name of copyright owner] 18a6e6969cSeschrock * 19a6e6969cSeschrock * CDDL HEADER END 20a6e6969cSeschrock */ 21a6e6969cSeschrock 22a6e6969cSeschrock /* 23a6e6969cSeschrock * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24a6e6969cSeschrock * Use is subject to license terms. 25a6e6969cSeschrock */ 26a6e6969cSeschrock 27a6e6969cSeschrock #pragma ident "%Z%%M% %I% %E% SMI" 28a6e6969cSeschrock 29a6e6969cSeschrock #include <string.h> 30a6e6969cSeschrock #include <strings.h> 31a6e6969cSeschrock 32a6e6969cSeschrock #include <scsi/libses.h> 33a6e6969cSeschrock #include <scsi/libses_plugin.h> 34a6e6969cSeschrock 35a6e6969cSeschrock #include <scsi/plugins/ses/framework/ses2_impl.h> 36a6e6969cSeschrock 37a6e6969cSeschrock static int 38a6e6969cSeschrock sun_loki_fix_bay(ses_plugin_t *sp, ses_node_t *np) 39a6e6969cSeschrock { 40a6e6969cSeschrock ses2_aes_descr_eip_impl_t *dep; 41a6e6969cSeschrock ses2_aes_descr_sas0_eip_impl_t *s0ep; 42a6e6969cSeschrock size_t len; 43a6e6969cSeschrock int nverr; 44a6e6969cSeschrock nvlist_t *props = ses_node_props(np); 45a6e6969cSeschrock 46a6e6969cSeschrock /* 47a6e6969cSeschrock * The spec conveniently defines the bay number as part of the 48a6e6969cSeschrock * additional element status descriptor. However, the AES descriptor 49a6e6969cSeschrock * is technically only valid if the device is inserted. This is a 50a6e6969cSeschrock * problem for loki because the bay numbers don't match the element 51a6e6969cSeschrock * class index, so when a device is removed we have no way of knowing 52a6e6969cSeschrock * *which* bay is empty. Thankfully, loki defines this value even if 53a6e6969cSeschrock * the invalid bit is set, so we override this value, even for empty 54a6e6969cSeschrock * bays. 55a6e6969cSeschrock */ 56a6e6969cSeschrock if ((dep = ses_plugin_page_lookup(sp, ses_node_snapshot(np), 57a6e6969cSeschrock SES2_DIAGPAGE_ADDL_ELEM_STATUS, np, &len)) == NULL) 58a6e6969cSeschrock return (0); 59a6e6969cSeschrock 60a6e6969cSeschrock if (dep->sadei_protocol_identifier != SPC4_PROTO_SAS || 61a6e6969cSeschrock !dep->sadei_eip || !dep->sadei_invalid) 62a6e6969cSeschrock return (0); 63a6e6969cSeschrock 64a6e6969cSeschrock s0ep = (ses2_aes_descr_sas0_eip_impl_t *)dep->sadei_protocol_specific; 65a6e6969cSeschrock 66a6e6969cSeschrock SES_NV_ADD(uint64, nverr, props, SES_PROP_BAY_NUMBER, 67a6e6969cSeschrock s0ep->sadsi_bay_number); 68a6e6969cSeschrock 69a6e6969cSeschrock return (0); 70a6e6969cSeschrock } 71a6e6969cSeschrock 72a6e6969cSeschrock static int 73a6e6969cSeschrock sun_loki_parse_node(ses_plugin_t *sp, ses_node_t *np) 74a6e6969cSeschrock { 75a6e6969cSeschrock ses_node_t *encp; 76a6e6969cSeschrock nvlist_t *props = ses_node_props(np); 77a6e6969cSeschrock nvlist_t *encprops; 78a6e6969cSeschrock uint8_t *stringin; 79a6e6969cSeschrock uint_t len; 80a6e6969cSeschrock nvlist_t *lid; 81a6e6969cSeschrock int nverr; 82a6e6969cSeschrock char serial[17]; 83a6e6969cSeschrock uint8_t fieldlen; 84a6e6969cSeschrock char *field; 85a6e6969cSeschrock uint64_t wwn; 86a6e6969cSeschrock uint64_t type, index; 87a6e6969cSeschrock int i; 88a6e6969cSeschrock 89a6e6969cSeschrock if (ses_node_type(np) != SES_NODE_ENCLOSURE && 90a6e6969cSeschrock ses_node_type(np) != SES_NODE_ELEMENT) 91a6e6969cSeschrock return (0); 92a6e6969cSeschrock 93a6e6969cSeschrock if (ses_node_type(np) == SES_NODE_ELEMENT) { 94a6e6969cSeschrock VERIFY(nvlist_lookup_uint64(props, SES_PROP_ELEMENT_TYPE, 95a6e6969cSeschrock &type) == 0); 96a6e6969cSeschrock 97a6e6969cSeschrock if (type == SES_ET_ARRAY_DEVICE) 98a6e6969cSeschrock return (sun_loki_fix_bay(sp, np)); 99a6e6969cSeschrock 100a6e6969cSeschrock if (type != SES_ET_COOLING && 101a6e6969cSeschrock type != SES_ET_POWER_SUPPLY) 102a6e6969cSeschrock return (0); 103a6e6969cSeschrock 104a6e6969cSeschrock VERIFY(nvlist_lookup_uint64(props, SES_PROP_ELEMENT_CLASS_INDEX, 105a6e6969cSeschrock &index) == 0); 106a6e6969cSeschrock } 107a6e6969cSeschrock 108a6e6969cSeschrock /* 109a6e6969cSeschrock * Find the containing enclosure node and extract the STRING IN 110a6e6969cSeschrock * information. 111a6e6969cSeschrock */ 112a6e6969cSeschrock for (encp = np; ses_node_type(encp) != SES_NODE_ENCLOSURE; 113a6e6969cSeschrock encp = ses_node_parent(encp)) 114a6e6969cSeschrock ; 115a6e6969cSeschrock 116a6e6969cSeschrock encprops = ses_node_props(encp); 117a6e6969cSeschrock if (nvlist_lookup_byte_array(encprops, SES_EN_PROP_STRING, 118*bf82a41bSeschrock &stringin, &len) != 0 || len < 4) 119a6e6969cSeschrock return (0); 120a6e6969cSeschrock 121a6e6969cSeschrock /* 122a6e6969cSeschrock * If this is an enclosure, then calculate the chassis WWN by masking 123a6e6969cSeschrock * off the bottom 8 bits of the WWN. 124a6e6969cSeschrock */ 125a6e6969cSeschrock if (ses_node_type(np) == SES_NODE_ENCLOSURE) { 126a6e6969cSeschrock VERIFY(nvlist_lookup_nvlist(props, SES_EN_PROP_LID, &lid) == 0); 127a6e6969cSeschrock VERIFY(nvlist_lookup_uint64(lid, SPC3_NAA_INT, &wwn) == 0); 128a6e6969cSeschrock (void) snprintf(serial, sizeof (serial), "%llx", 129a6e6969cSeschrock wwn & ~0xFFULL); 130a6e6969cSeschrock SES_NV_ADD(string, nverr, props, LIBSES_EN_PROP_CSN, serial); 131a6e6969cSeschrock } 132a6e6969cSeschrock 133a6e6969cSeschrock /* 134a6e6969cSeschrock * The STRING IN data is organized into a series of variable-length 135a6e6969cSeschrock * fields, where each field can be either a key ("Fan PartNUM") or a 136a6e6969cSeschrock * value. If the field length is less than our shortest expected 137a6e6969cSeschrock * identifier, then something has gone awry and we assume that the data 138a6e6969cSeschrock * is corrupt. 139a6e6969cSeschrock */ 140*bf82a41bSeschrock fieldlen = stringin[3]; 141a6e6969cSeschrock if (fieldlen < 11) 142a6e6969cSeschrock return (0); 143a6e6969cSeschrock 144*bf82a41bSeschrock for (field = (char *)stringin + 4; 145a6e6969cSeschrock field + fieldlen <= (char *)stringin + len; field += fieldlen) { 146*bf82a41bSeschrock if (strncmp(field, "Storage J4500", 13) == 0) { 147a6e6969cSeschrock /* 148a6e6969cSeschrock * This is the part number for the enclosure itself. 149a6e6969cSeschrock */ 150a6e6969cSeschrock if (ses_node_type(np) != SES_NODE_ENCLOSURE) 151a6e6969cSeschrock continue; 152a6e6969cSeschrock 153a6e6969cSeschrock field += fieldlen; 154a6e6969cSeschrock if (field + fieldlen > (char *)stringin + len) 155a6e6969cSeschrock break; 156a6e6969cSeschrock 157a6e6969cSeschrock if (ses_node_type(np) == SES_NODE_ENCLOSURE) { 158a6e6969cSeschrock SES_NV_ADD(fixed_string_trunc, nverr, props, 159a6e6969cSeschrock LIBSES_PROP_PART, field, fieldlen); 160a6e6969cSeschrock return (0); 161a6e6969cSeschrock } 162a6e6969cSeschrock 163a6e6969cSeschrock } else if (strncmp(field, "Fan PartNUM", 11) == 0) { 164a6e6969cSeschrock /* 165a6e6969cSeschrock * Part numbers for the fans, of which there are 5. 166a6e6969cSeschrock */ 167a6e6969cSeschrock if (ses_node_type(np) != SES_NODE_ELEMENT || 168*bf82a41bSeschrock type != SES_ET_COOLING) { 169*bf82a41bSeschrock field += fieldlen * 5; 170a6e6969cSeschrock continue; 171*bf82a41bSeschrock } 172a6e6969cSeschrock 173a6e6969cSeschrock field += fieldlen; 174a6e6969cSeschrock 175a6e6969cSeschrock for (i = 0; i < 5 && 176a6e6969cSeschrock field + fieldlen <= (char *)stringin + len; 177*bf82a41bSeschrock i++, field += fieldlen) { 178a6e6969cSeschrock if (index == i && 179a6e6969cSeschrock strncmp(field, "Unknown", 7) != 0 && 180a6e6969cSeschrock strncmp(field, "Not Installed", 13) != 0) { 181a6e6969cSeschrock SES_NV_ADD(fixed_string_trunc, nverr, 182a6e6969cSeschrock props, LIBSES_PROP_PART, 183a6e6969cSeschrock field, fieldlen); 184a6e6969cSeschrock return (0); 185a6e6969cSeschrock } 186a6e6969cSeschrock } 187a6e6969cSeschrock 188a6e6969cSeschrock } else if (strncmp(field, "PS PartNUM", 10) == 0) { 189a6e6969cSeschrock /* 190a6e6969cSeschrock * Part numbers for the power supplies, of which there 191a6e6969cSeschrock * are 2. 192a6e6969cSeschrock */ 193a6e6969cSeschrock if (ses_node_type(np) != SES_NODE_ELEMENT || 194*bf82a41bSeschrock type != SES_ET_POWER_SUPPLY) { 195*bf82a41bSeschrock field += fieldlen * 2; 196a6e6969cSeschrock continue; 197*bf82a41bSeschrock } 198a6e6969cSeschrock 199a6e6969cSeschrock field += fieldlen; 200a6e6969cSeschrock 201a6e6969cSeschrock for (i = 0; i < 2 && 202a6e6969cSeschrock field + fieldlen <= (char *)stringin + len; 203*bf82a41bSeschrock i++, field += fieldlen) { 204a6e6969cSeschrock if (index == i && 205a6e6969cSeschrock strncmp(field, "Unknown", 7) != 0 && 206a6e6969cSeschrock strncmp(field, "Not Installed", 13) != 0) { 207a6e6969cSeschrock SES_NV_ADD(fixed_string_trunc, nverr, 208a6e6969cSeschrock props, LIBSES_PROP_PART, 209a6e6969cSeschrock field, fieldlen); 210a6e6969cSeschrock return (0); 211a6e6969cSeschrock } 212a6e6969cSeschrock } 213a6e6969cSeschrock } 214a6e6969cSeschrock } 215a6e6969cSeschrock 216a6e6969cSeschrock return (0); 217a6e6969cSeschrock } 218a6e6969cSeschrock 219a6e6969cSeschrock int 220a6e6969cSeschrock _ses_init(ses_plugin_t *sp) 221a6e6969cSeschrock { 222a6e6969cSeschrock ses_plugin_config_t config = { 223a6e6969cSeschrock .spc_node_parse = sun_loki_parse_node 224a6e6969cSeschrock }; 225a6e6969cSeschrock 226a6e6969cSeschrock return (ses_plugin_register(sp, LIBSES_PLUGIN_VERSION, 227a6e6969cSeschrock &config) != 0); 228a6e6969cSeschrock } 229