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 (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 #include <stddef.h> 27 #include <string.h> 28 #include <strings.h> 29 #include <libnvpair.h> 30 31 #include <scsi/libses.h> 32 #include <scsi/plugins/ses/framework/ses2_impl.h> 33 34 static int 35 enc_parse_sd(ses2_elem_status_impl_t *esip, nvlist_t *nvl) 36 { 37 ses2_enclosure_status_impl_t *sdp; 38 int nverr; 39 40 sdp = (ses2_enclosure_status_impl_t *)esip; 41 42 SES_NV_ADD(uint64, nverr, nvl, SES_PROP_STATUS_CODE, 43 sdp->sesi_common.sesi_status_code); 44 SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_SWAP, 45 sdp->sesi_common.sesi_swap); 46 SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_DISABLED, 47 sdp->sesi_common.sesi_disabled); 48 SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_PRDFAIL, 49 sdp->sesi_common.sesi_prdfail); 50 51 SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_IDENT, sdp->sesi_ident); 52 SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_WARN, 53 sdp->sesi_warning_indication); 54 SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_FAIL, 55 sdp->sesi_failure_indication); 56 SES_NV_ADD(uint64, nverr, nvl, SES_EN_PROP_POWER_DELAY, 57 sdp->sesi_power_delay); 58 SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_WARN_REQ, 59 sdp->sesi_warning_requested); 60 SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_FAIL_REQ, 61 sdp->sesi_warning_requested); 62 SES_NV_ADD(uint64, nverr, nvl, SES_EN_PROP_POWER_DURATION, 63 sdp->sesi_power_duration); 64 65 return (0); 66 } 67 68 static int 69 enc_parse_help(ses_plugin_t *sp, ses_node_t *np) 70 { 71 ses_snap_t *snap = ses_node_snapshot(np); 72 ses2_help_page_impl_t *hpip; 73 ses2_subhelp_page_impl_t *shpip; 74 ses2_subhelp_text_impl_t *tip; 75 nvlist_t *nvl = ses_node_props(np); 76 uint64_t eid; 77 size_t len, textlen; 78 off_t pos; 79 int nverr; 80 81 if (nvlist_lookup_uint64(nvl, SES_EN_PROP_EID, &eid) != 0) 82 return (0); 83 84 if ((shpip = ses_plugin_page_lookup(sp, snap, 85 SES2_DIAGPAGE_SUBENCLOSURE_HELP_TEXT, np, &len)) != NULL) { 86 pos = 0; 87 for (tip = (ses2_subhelp_text_impl_t *)shpip->sspi_data; 88 pos < SCSI_READ16(&shpip->sspi_page_length); 89 pos += SES2_SUBHELP_LEN(tip), 90 tip = (ses2_subhelp_text_impl_t *)((uint8_t *)tip + pos)) { 91 if (!SES_WITHIN_PAGE_STRUCT(tip, shpip, len)) 92 break; 93 94 if (tip->ssti_subenclosure_identifier != eid) 95 continue; 96 97 textlen = SCSI_READ16( 98 &tip->ssti_subenclosure_help_text_length); 99 100 if (!SES_WITHIN_PAGE(tip->ssti_subenclosure_help_text, 101 textlen, shpip, len)) 102 break; 103 104 SES_NV_ADD(fixed_string, nverr, nvl, SES_EN_PROP_HELP, 105 tip->ssti_subenclosure_help_text, textlen); 106 return (0); 107 } 108 } 109 110 if (eid == 0 && (hpip = ses_plugin_page_lookup(sp, snap, 111 SES2_DIAGPAGE_HELP_TEXT, np, &len)) != NULL) { 112 if (!SES_WITHIN_PAGE_STRUCT(hpip, hpip, len)) 113 return (0); 114 115 if (!SES_WITHIN_PAGE(hpip->shpi_help_text, 116 SCSI_READ16(&hpip->shpi_page_length), hpip, len)) 117 return (0); 118 119 SES_NV_ADD(fixed_string, nverr, nvl, SES_EN_PROP_HELP, 120 hpip->shpi_help_text, SCSI_READ16(&hpip->shpi_page_length)); 121 } 122 123 return (0); 124 } 125 126 static int 127 enc_parse_string_in(ses_plugin_t *sp, ses_node_t *np) 128 { 129 ses_snap_t *snap = ses_node_snapshot(np); 130 ses2_string_in_page_impl_t *sip; 131 ses2_substring_in_page_impl_t *ssip; 132 ses2_substring_in_data_impl_t *dip; 133 nvlist_t *nvl = ses_node_props(np); 134 uint64_t eid; 135 off_t pos; 136 size_t len, textlen; 137 int nverr; 138 139 if (nvlist_lookup_uint64(nvl, SES_EN_PROP_EID, &eid) != 0) 140 return (0); 141 142 if ((ssip = ses_plugin_page_lookup(sp, snap, 143 SES2_DIAGPAGE_SUBENCLOSURE_STRING_IO, np, &len)) != NULL) { 144 pos = 0; 145 for (dip = (ses2_substring_in_data_impl_t *)ssip->ssipi_data; 146 pos < SCSI_READ16(&ssip->ssipi_page_length); 147 pos += SES2_SUBSTR_LEN(dip), 148 dip = (ses2_substring_in_data_impl_t *) 149 ((uint8_t *)dip + pos)) { 150 if (!SES_WITHIN_PAGE_STRUCT(dip, ssip, len)) 151 break; 152 153 if (dip->ssidi_subenclosure_identifier != eid) 154 continue; 155 156 textlen = 157 SCSI_READ16(&dip->ssidi_substring_data_length); 158 159 if (!SES_WITHIN_PAGE(dip->ssidi_data, textlen, 160 ssip, len)) 161 break; 162 163 SES_NV_ADD(fixed_string, nverr, nvl, SES_EN_PROP_STRING, 164 (char *)dip->ssidi_data, textlen); 165 return (0); 166 } 167 } 168 169 if (eid == 0 && (sip = ses_plugin_page_lookup(sp, snap, 170 SES2_DIAGPAGE_STRING_IO, np, &len)) != NULL) { 171 if (!SES_WITHIN_PAGE_STRUCT(sip, sip, len)) 172 return (0); 173 174 textlen = SCSI_READ16(&sip->ssipi_page_length); 175 176 if (!SES_WITHIN_PAGE(sip->ssipi_data, textlen, sip, len)) 177 return (0); 178 179 SES_NV_ADD(byte_array, nverr, nvl, SES_EN_PROP_STRING, 180 sip->ssipi_data, textlen); 181 } 182 183 return (0); 184 } 185 186 static int 187 enc_parse_descr(ses_plugin_t *sp, ses_node_t *np) 188 { 189 char *desc; 190 nvlist_t *props = ses_node_props(np); 191 int nverr; 192 size_t len; 193 194 if ((desc = ses_plugin_page_lookup(sp, ses_node_snapshot(np), 195 SES2_DIAGPAGE_ELEMENT_DESC, np, &len)) == NULL) 196 return (0); 197 198 SES_NV_ADD(fixed_string, nverr, props, SES_PROP_DESCRIPTION, 199 desc, len); 200 201 return (0); 202 } 203 204 static int 205 enc_parse_dlucode(ses_plugin_t *sp, ses_node_t *np) 206 { 207 ses_snap_t *snap = ses_node_snapshot(np); 208 ses2_ucode_status_page_impl_t *upip; 209 ses2_ucode_status_descr_impl_t *dip; 210 nvlist_t *nvl = ses_node_props(np); 211 int nverr, i; 212 size_t len; 213 uint64_t eid; 214 215 if ((upip = ses_plugin_page_lookup(sp, snap, 216 SES2_DIAGPAGE_DL_MICROCODE_CTL_STATUS, np, &len)) == NULL) 217 return (0); 218 219 if (nvlist_lookup_uint64(nvl, SES_EN_PROP_EID, &eid) != 0) 220 return (0); 221 222 if (!SES_WITHIN_PAGE_STRUCT(upip, upip, len)) 223 return (0); 224 225 /* 226 * The number of subenclosures excludes the primary subenclosure, which 227 * is always part of the response. 228 */ 229 for (dip = &upip->suspi_descriptors[0], i = 0; 230 i <= upip->suspi_n_subenclosures; 231 i++, dip++) { 232 if (!SES_WITHIN_PAGE_STRUCT(dip, upip, len)) 233 break; 234 235 if (dip->susdi_subenclosure_identifier != eid) 236 continue; 237 SES_NV_ADD(uint64, nverr, nvl, SES_EN_PROP_UCODE, 238 dip->susdi_subenclosure_dl_status); 239 SES_NV_ADD(uint64, nverr, nvl, SES_EN_PROP_UCODE_A, 240 dip->susdi_subenclosure_dl_addl_status); 241 SES_NV_ADD(uint64, nverr, nvl, SES_EN_PROP_UCODE_SZ, 242 SCSI_READ32(&dip->susdi_subenclosure_dl_max_size)); 243 SES_NV_ADD(uint64, nverr, nvl, SES_EN_PROP_UCODE_BUF, 244 dip->susdi_subenclosure_dl_buffer_id); 245 SES_NV_ADD(uint64, nverr, nvl, SES_EN_PROP_UCODE_OFF, 246 dip->susdi_subenclosure_dl_buffer_offset); 247 break; 248 } 249 250 return (0); 251 } 252 253 static int 254 enc_parse_subnick(ses_plugin_t *sp, ses_node_t *np) 255 { 256 ses_snap_t *snap = ses_node_snapshot(np); 257 ses2_subnick_status_page_impl_t *spip; 258 ses2_subnick_descr_impl_t *dip; 259 nvlist_t *nvl = ses_node_props(np); 260 int nverr, i; 261 size_t len; 262 uint64_t eid; 263 264 if (nvlist_lookup_uint64(nvl, SES_EN_PROP_EID, &eid) != 0) 265 return (0); 266 267 if ((spip = ses_plugin_page_lookup(sp, snap, 268 SES2_DIAGPAGE_SUBENCLOSURE_NICKNAME_CTL_STATUS, 269 np, &len)) == NULL) 270 return (0); 271 272 if (!SES_WITHIN_PAGE_STRUCT(spip, spip, len)) 273 return (0); 274 275 for (dip = &spip->sspci_subnicks[0], i = 0; 276 i <= spip->sspci_n_subenclosures; 277 i++, dip++) { 278 if (!SES_WITHIN_PAGE_STRUCT(dip, spip, len)) 279 break; 280 281 if (dip->ssdi_subenclosure_identifier != eid) 282 continue; 283 SES_NV_ADD(uint64, nverr, nvl, SES_EN_PROP_NICK_STATUS, 284 dip->ssdi_subenclosure_nick_status); 285 SES_NV_ADD(uint64, nverr, nvl, SES_EN_PROP_NICK_ADDL_STATUS, 286 dip->ssdi_subenclosure_nick_addl_status); 287 SES_NV_ADD_FS(nverr, nvl, SES_EN_PROP_NICK, 288 dip->ssdi_subenclosure_nickname); 289 SES_NV_ADD(uint64, nverr, nvl, SES_EN_PROP_NICK_LANG, 290 dip->ssdi_subenclosure_nick_lang_code); 291 break; 292 } 293 294 return (0); 295 } 296 297 int 298 ses2_fill_enclosure_node(ses_plugin_t *sp, ses_node_t *np) 299 { 300 ses_snap_t *snap = ses_node_snapshot(np); 301 nvlist_t *props = ses_node_props(np); 302 ses2_elem_status_impl_t *esip; 303 int err; 304 size_t len; 305 306 if ((esip = ses_plugin_page_lookup(sp, snap, 307 SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, np, &len)) != NULL) { 308 if ((err = enc_parse_sd(esip, props)) != 0) 309 return (err); 310 } 311 312 if ((err = enc_parse_help(sp, np)) != 0) 313 return (err); 314 315 if ((err = enc_parse_string_in(sp, np)) != 0) 316 return (err); 317 318 if ((err = enc_parse_descr(sp, np)) != 0) 319 return (err); 320 321 if ((err = enc_parse_dlucode(sp, np)) != 0) 322 return (err); 323 324 if ((err = enc_parse_subnick(sp, np)) != 0) 325 return (err); 326 327 return (0); 328 } 329