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 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 28 * Use is subject to license terms. 29 */ 30 31 #pragma ident "%Z%%M% %I% %E% SMI" 32 33 #include <sys/types.h> 34 #include <stddef.h> 35 #include <stdio.h> 36 #include <string.h> 37 #include <strings.h> 38 #include <libnvpair.h> 39 40 #include <scsi/libses.h> 41 #include "ses2_impl.h" 42 43 #define SES_UCODE_CHUNK_SIZE (32 * 1024) 44 45 /*ARGSUSED*/ 46 static int 47 enc_do_ucode(ses_plugin_t *sp, ses_node_t *np, nvlist_t *nvl) 48 { 49 nvlist_t *props = ses_node_props(np); 50 uint64_t maxlen, bufid = 0; 51 uint8_t *data; 52 ses2_ucode_ctl_page_impl_t *uip; 53 size_t offset, len, pagelen; 54 uint_t datalen; 55 uint64_t mode; 56 57 /* 58 * Get the data and check the length. 59 */ 60 if (nvlist_lookup_byte_array(nvl, SES_CTL_PROP_UCODE_DATA, 61 &data, &datalen) != 0) 62 return (ses_error(ESES_INVALID_PROP, 63 "missing or invalid %s property", SES_CTL_PROP_UCODE_DATA)); 64 65 if (nvlist_lookup_uint64(nvl, SES_CTL_PROP_UCODE_MODE, 66 &mode) != 0) 67 return (ses_error(ESES_INVALID_PROP, 68 "missing or invalid %s property", SES_CTL_PROP_UCODE_MODE)); 69 70 if (nvlist_lookup_uint64(props, SES_EN_PROP_UCODE_SZ, 71 &maxlen) != 0 || datalen > maxlen) 72 return (ses_error(ESES_RANGE, 73 "microcode image length (%u) exceeds maximum length (%llu)", 74 datalen, maxlen)); 75 76 /* 77 * Get the expected buffer ID, but allow the user to override it. 78 */ 79 (void) nvlist_lookup_uint64(props, SES_EN_PROP_UCODE_BUF, 80 &bufid); 81 82 if (bufid == 0xFF) 83 bufid = 0; 84 85 (void) nvlist_lookup_uint64(nvl, SES_CTL_PROP_UCODE_BUFID, &bufid); 86 87 for (offset = 0; offset < datalen; offset += SES_UCODE_CHUNK_SIZE) { 88 89 len = MIN(datalen - offset, SES_UCODE_CHUNK_SIZE); 90 if (len & 0x3) 91 pagelen = (len + 4) & 0x3; 92 else 93 pagelen = len; 94 95 if ((uip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np), 96 SES2_DIAGPAGE_DL_MICROCODE_CTL_STATUS, pagelen, 97 np, B_TRUE)) == NULL) 98 return (-1); 99 100 uip->sucpi_buffer_id = (uint8_t)bufid; 101 uip->sucpi_dl_ucode_mode = mode; 102 SCSI_WRITE32(&uip->sucpi_buffer_offset, offset); 103 SCSI_WRITE32(&uip->sucpi_ucode_image_length, datalen); 104 SCSI_WRITE32(&uip->sucpi_ucode_data_length, len); 105 106 bcopy(data + offset, &uip->sucpi_ucode_data[0], 107 len); 108 109 if (len != pagelen) 110 bzero(&uip->sucpi_ucode_data[0] + len, 111 pagelen - len); 112 } 113 114 (void) nvlist_remove_all(nvl, SES_CTL_PROP_UCODE_DATA); 115 (void) nvlist_remove_all(nvl, SES_CTL_PROP_UCODE_MODE); 116 (void) nvlist_remove_all(nvl, SES_CTL_PROP_UCODE_BUFID); 117 118 return (0); 119 } 120 121 static int 122 enc_ctl_common(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page, 123 nvpair_t *nvp) 124 { 125 ses2_enclosure_ctl_impl_t *tp; 126 const char *name; 127 boolean_t boolval; 128 uint64_t intval; 129 130 ASSERT(page == SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS); 131 132 if ((tp = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np), 133 page, 0, np, B_FALSE)) == NULL) 134 return (-1); 135 136 name = nvpair_name(nvp); 137 (void) nvpair_value_boolean_value(nvp, &boolval); 138 (void) nvpair_value_uint64(nvp, &intval); 139 140 if (strcmp(name, SES_PROP_IDENT) == 0) 141 tp->seci_rqst_ident = boolval; 142 else if (strcmp(name, SES_PROP_WARN_REQ) == 0) 143 tp->seci_request_warning = boolval; 144 else if (strcmp(name, SES_PROP_FAIL_REQ) == 0) 145 tp->seci_request_failure = boolval; 146 else if (strcmp(name, SES_EN_PROP_POWER_DELAY) == 0) 147 tp->seci_power_cycle_delay = intval; 148 else if (strcmp(name, SES_EN_PROP_POWER_REQUEST) == 0) 149 tp->seci_power_cycle_request = intval; 150 else if (strcmp(name, SES_EN_PROP_POWER_DURATION) == 0) 151 tp->seci_power_off_duration = intval; 152 else 153 ses_panic("bad property %s", name); 154 155 return (0); 156 } 157 158 /*ARGSUSED*/ 159 static int 160 enc_ctl_string(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page, 161 nvpair_t *nvp) 162 { 163 ses2_substring_out_page_impl_t *spip; 164 ses2_string_out_page_impl_t *pip; 165 const uint8_t *data; 166 size_t datalen; 167 uint_t nvlen; 168 nvlist_t *props = ses_node_props(np); 169 uint64_t eid; 170 171 ASSERT(strcmp(nvpair_name(nvp), SES_EN_PROP_STRING) == 0); 172 173 VERIFY(nvlist_lookup_uint64(props, SES_EN_PROP_EID, &eid) == 0); 174 175 (void) nvpair_value_byte_array(nvp, (uint8_t **)&data, &nvlen); 176 datalen = (size_t)nvlen; 177 178 if ((spip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np), 179 SES2_DIAGPAGE_SUBENCLOSURE_STRING_IO, datalen, np, 180 B_FALSE)) != NULL) { 181 spip->ssopi_subenclosure_identifier = eid; 182 bcopy(data, spip->ssopi_data, datalen); 183 } else { 184 if (eid != 0) 185 return (ses_error(ESES_NOTSUP, "target does not " 186 "support string data for secondary subenclosures")); 187 188 if ((pip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np), 189 SES2_DIAGPAGE_STRING_IO, datalen, np, B_FALSE)) == NULL) 190 return (-1); 191 192 bcopy(data, pip->ssopi_data, datalen); 193 } 194 195 return (0); 196 } 197 198 static int 199 enc_ctl_nick(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page, 200 nvpair_t *nvp) 201 { 202 /* LINTED - dummy variable for sizeof */ 203 ses2_subnick_ctl_page_impl_t *pip, dummy; 204 const char *nick; 205 size_t len, max; 206 nvlist_t *props = ses_node_props(np); 207 uint64_t eid; 208 209 ASSERT(strcmp(nvpair_name(nvp), SES_EN_PROP_NICK) == 0); 210 ASSERT(page == SES2_DIAGPAGE_SUBENCLOSURE_NICKNAME_CTL_STATUS); 211 212 (void) nvpair_value_string(nvp, (char **)&nick); 213 len = strlen(nick); 214 215 VERIFY(nvlist_lookup_uint64(props, SES_EN_PROP_EID, &eid) == 0); 216 217 max = sizeof (dummy.sspci_subenclosure_nickname); 218 if (len > max) 219 return (ses_error(ESES_RANGE, "nickname '%s' exceeds " 220 "maximum length %lu", nick, max)); 221 222 if ((pip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np), 223 page, len, np, B_FALSE)) == NULL) 224 return (-1); 225 226 pip->sspci_subenclosure_identifier = eid; 227 bcopy(nick, pip->sspci_subenclosure_nickname, len); 228 229 return (0); 230 } 231 232 static const ses2_ctl_prop_t enc_props[] = { 233 SES_COMMON_CTL_PROPS, 234 { 235 .scp_name = SES_PROP_IDENT, 236 .scp_type = DATA_TYPE_BOOLEAN_VALUE, 237 .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, 238 .scp_setprop = enc_ctl_common 239 }, 240 { 241 .scp_name = SES_PROP_WARN_REQ, 242 .scp_type = DATA_TYPE_BOOLEAN_VALUE, 243 .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, 244 .scp_setprop = enc_ctl_common 245 }, 246 { 247 .scp_name = SES_PROP_FAIL_REQ, 248 .scp_type = DATA_TYPE_BOOLEAN_VALUE, 249 .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, 250 .scp_setprop = enc_ctl_common 251 }, 252 { 253 .scp_name = SES_EN_PROP_POWER_DELAY, 254 .scp_type = DATA_TYPE_UINT64, 255 .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, 256 .scp_setprop = enc_ctl_common 257 }, 258 { 259 .scp_name = SES_EN_PROP_POWER_DURATION, 260 .scp_type = DATA_TYPE_UINT64, 261 .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, 262 .scp_setprop = enc_ctl_common 263 }, 264 { 265 .scp_name = SES_EN_PROP_POWER_REQUEST, 266 .scp_type = DATA_TYPE_UINT64, 267 .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, 268 .scp_setprop = enc_ctl_common 269 }, 270 { 271 .scp_name = SES_EN_PROP_STRING, 272 .scp_type = DATA_TYPE_BYTE_ARRAY, 273 .scp_num = -1, 274 .scp_setprop = enc_ctl_string 275 }, 276 { 277 .scp_name = SES_EN_PROP_NICK, 278 .scp_type = DATA_TYPE_STRING, 279 .scp_num = SES2_DIAGPAGE_SUBENCLOSURE_NICKNAME_CTL_STATUS, 280 .scp_setprop = enc_ctl_nick 281 }, 282 { 283 NULL 284 } 285 }; 286 287 static int 288 enc_setdef_one(ses_node_t *np, ses2_diag_page_t page, void *data) 289 { 290 ses2_enclosure_ctl_impl_t *tp = data; 291 nvlist_t *props = ses_node_props(np); 292 293 if (page != SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS) 294 return (0); 295 296 SES_NV_CTLBOOL(props, SES_PROP_IDENT, tp->seci_rqst_ident); 297 SES_NV_CTLBOOL(props, SES_PROP_WARN_REQ, 298 tp->seci_request_warning); 299 SES_NV_CTLBOOL(props, SES_PROP_FAIL_REQ, 300 tp->seci_request_failure); 301 302 return (0); 303 } 304 305 int 306 ses2_enclosure_ctl(ses_plugin_t *sp, ses_node_t *np, const char *op, 307 nvlist_t *nvl) 308 { 309 if (strcmp(op, SES_CTL_OP_SETPROP) == 0) 310 return (ses2_setprop(sp, np, enc_props, nvl)); 311 else if (strcmp(op, SES_CTL_OP_DL_UCODE) == 0) 312 return (enc_do_ucode(sp, np, nvl)); 313 314 return (0); 315 } 316 317 int 318 ses2_enclosure_setdef(ses_node_t *np, ses2_diag_page_t page, void *data) 319 { 320 nvlist_t *props = ses_node_props(np); 321 uint64_t type; 322 323 VERIFY(nvlist_lookup_uint64(props, SES_PROP_ELEMENT_TYPE, &type) == 0); 324 325 if (type == SES_ET_ENCLOSURE && 326 enc_setdef_one(np, page, data) != 0) 327 return (-1); 328 329 return (0); 330 } 331