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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 /* 26 * This file contains various support routines. 27 */ 28 29 #include <sys/scsi/adapters/pmcs/pmcs.h> 30 31 /* 32 * SAS Topology Configuration 33 */ 34 static int pmcs_flash_chunk(pmcs_hw_t *, uint8_t *); 35 36 /* 37 * Check current firmware version for correctness 38 * and try to flash the correct firmware if what is 39 * running isn't correct. 40 * 41 * Must be called after setup and MPI setup and 42 * interrupts are enabled. 43 */ 44 45 int 46 pmcs_firmware_update(pmcs_hw_t *pwp) 47 { 48 ddi_modhandle_t modhp; 49 char buf[64], *bufp; 50 int errno; 51 uint8_t *cstart, *cend; /* Firmware image file */ 52 uint8_t *istart, *iend; /* ila */ 53 uint8_t *sstart, *send; /* SPCBoot */ 54 uint32_t *fwvp; 55 int defret = 0; 56 int first_pass = 1; 57 long fw_version, ila_version; 58 uint8_t *fw_verp, *ila_verp; 59 60 /* 61 * If updating is disabled, we're done. 62 */ 63 if (pwp->fw_disable_update) { 64 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 65 "Firmware update disabled by conf file"); 66 return (0); 67 } 68 69 /* 70 * If we're already running the right firmware, we're done. 71 */ 72 if (pwp->fw == PMCS_FIRMWARE_VERSION) { 73 if (pwp->fw_force_update == 0) { 74 return (0); 75 } 76 77 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 78 "Firmware version matches, but still forcing update"); 79 } 80 81 modhp = ddi_modopen(PMCS_FIRMWARE_FILENAME, KRTLD_MODE_FIRST, &errno); 82 if (errno) { 83 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 84 "%s: Firmware module not available; will not upgrade", 85 __func__); 86 return (defret); 87 } 88 89 fwvp = ddi_modsym(modhp, PMCS_FIRMWARE_VERSION_NAME, &errno); 90 if (errno) { 91 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 92 "%s: unable to find symbol '%s'", 93 __func__, PMCS_FIRMWARE_VERSION_NAME); 94 (void) ddi_modclose(modhp); 95 return (defret); 96 } 97 98 /* 99 * If the firmware version from the module isn't what we expect, 100 * and force updating is disabled, return the default (for this 101 * mode of operation) value. 102 */ 103 if (*fwvp != PMCS_FIRMWARE_VERSION) { 104 if (pwp->fw_force_update == 0) { 105 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 106 "%s: firmware module version wrong (0x%x)", 107 __func__, *fwvp); 108 (void) ddi_modclose(modhp); 109 return (defret); 110 } 111 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 112 "%s: firmware module version wrong (0x%x) - update forced", 113 __func__, *fwvp); 114 } 115 116 (void) snprintf(buf, sizeof (buf), 117 PMCS_FIRMWARE_CODE_NAME PMCS_FIRMWARE_START_SUF); 118 cstart = ddi_modsym(modhp, buf, &errno); 119 if (errno) { 120 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 121 "%s: unable to find symbol '%s'", __func__, buf); 122 (void) ddi_modclose(modhp); 123 return (defret); 124 } 125 126 (void) snprintf(buf, sizeof (buf), 127 PMCS_FIRMWARE_CODE_NAME PMCS_FIRMWARE_END_SUF); 128 cend = ddi_modsym(modhp, buf, &errno); 129 if (errno) { 130 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 131 "%s: unable to find symbol '%s'", __func__, buf); 132 (void) ddi_modclose(modhp); 133 return (defret); 134 } 135 136 (void) snprintf(buf, sizeof (buf), 137 PMCS_FIRMWARE_ILA_NAME PMCS_FIRMWARE_START_SUF); 138 istart = ddi_modsym(modhp, buf, &errno); 139 if (errno) { 140 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 141 "%s: unable to find symbol '%s'", __func__, buf); 142 (void) ddi_modclose(modhp); 143 return (defret); 144 } 145 146 (void) snprintf(buf, sizeof (buf), 147 PMCS_FIRMWARE_ILA_NAME PMCS_FIRMWARE_END_SUF); 148 iend = ddi_modsym(modhp, buf, &errno); 149 if (errno) { 150 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 151 "%s: unable to find symbol '%s'", __func__, buf); 152 (void) ddi_modclose(modhp); 153 return (defret); 154 } 155 156 (void) snprintf(buf, sizeof (buf), 157 PMCS_FIRMWARE_SPCBOOT_NAME PMCS_FIRMWARE_START_SUF); 158 sstart = ddi_modsym(modhp, buf, &errno); 159 if (errno) { 160 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 161 "%s: unable to find symbol '%s'", __func__, buf); 162 (void) ddi_modclose(modhp); 163 return (defret); 164 } 165 166 (void) snprintf(buf, sizeof (buf), 167 PMCS_FIRMWARE_SPCBOOT_NAME PMCS_FIRMWARE_END_SUF); 168 send = ddi_modsym(modhp, buf, &errno); 169 if (errno) { 170 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 171 "%s: unable to find symbol '%s'", __func__, buf); 172 (void) ddi_modclose(modhp); 173 return (defret); 174 } 175 176 /* 177 * Get the ILA and firmware versions from the modules themselves 178 */ 179 ila_verp = iend - PMCS_ILA_VER_OFFSET; 180 (void) ddi_strtol((const char *)ila_verp, &bufp, 16, &ila_version); 181 fw_verp = cend - PMCS_FW_VER_OFFSET; 182 (void) ddi_strtol((const char *)fw_verp, &bufp, 16, &fw_version); 183 184 /* 185 * If force update is not set, verify that what we're loading is 186 * what we expect. 187 */ 188 if (pwp->fw_force_update == 0) { 189 if (fw_version != PMCS_FIRMWARE_VERSION) { 190 pmcs_prt(pwp, PMCS_PRT_ERR, NULL, NULL, 191 "Expected fw version 0x%x, not 0x%lx: not " 192 "updating", PMCS_FIRMWARE_VERSION, fw_version); 193 (void) ddi_modclose(modhp); 194 return (defret); 195 } 196 } 197 198 pmcs_prt(pwp, PMCS_PRT_WARN, NULL, NULL, 199 "Upgrading firmware on card from 0x%x to 0x%lx (ILA version 0x%lx)", 200 pwp->fw, fw_version, ila_version); 201 202 /* 203 * The SPCBoot image must be updated first, and this is written to 204 * SEEPROM, not flash. 205 */ 206 if (pmcs_set_nvmd(pwp, PMCS_NVMD_SPCBOOT, sstart, 207 (size_t)((size_t)send - (size_t)sstart)) == B_FALSE) { 208 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 209 "%s: unable to flash '%s' segment", 210 __func__, PMCS_FIRMWARE_SPCBOOT_NAME); 211 (void) ddi_modclose(modhp); 212 return (-1); 213 } 214 215 repeat: 216 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 217 "%s: Beginning firmware update of %s image.", 218 __func__, (first_pass ? "first" : "second")); 219 220 if (pmcs_fw_flash(pwp, (void *)istart, 221 (uint32_t)((size_t)iend - (size_t)istart))) { 222 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 223 "%s: unable to flash '%s' segment", 224 __func__, PMCS_FIRMWARE_ILA_NAME); 225 (void) ddi_modclose(modhp); 226 return (-1); 227 } 228 229 if (pmcs_fw_flash(pwp, (void *)cstart, 230 (uint32_t)((size_t)cend - (size_t)cstart))) { 231 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 232 "%s: unable to flash '%s' segment", 233 __func__, PMCS_FIRMWARE_CODE_NAME); 234 (void) ddi_modclose(modhp); 235 return (-1); 236 } 237 238 if (pmcs_soft_reset(pwp, B_FALSE)) { 239 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 240 "%s: soft reset after flash update failed", __func__); 241 (void) ddi_modclose(modhp); 242 return (-1); 243 } else { 244 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 245 "%s: %s image successfully upgraded.", 246 __func__, (first_pass ? "First" : "Second")); 247 pwp->last_reset_reason = PMCS_LAST_RST_FW_UPGRADE; 248 } 249 250 if (first_pass) { 251 first_pass = 0; 252 goto repeat; 253 } 254 255 pmcs_prt(pwp, PMCS_PRT_WARN, NULL, NULL, 256 "%s: Firmware successfully upgraded", __func__); 257 258 (void) ddi_modclose(modhp); 259 return (0); 260 } 261 262 /* 263 * Flash firmware support 264 * Called unlocked. 265 */ 266 int 267 pmcs_fw_flash(pmcs_hw_t *pwp, pmcs_fw_hdr_t *hdr, uint32_t length) 268 { 269 pmcs_fw_hdr_t *hp; 270 uint8_t *wrk, *base; 271 272 /* 273 * Step 1- Validate firmware chunks within passed pointer. 274 */ 275 hp = hdr; 276 wrk = (uint8_t *)hdr; 277 base = wrk; 278 for (;;) { 279 pmcs_prt(pwp, PMCS_PRT_DEBUG1, NULL, NULL, 280 "%s: partition 0x%x, Length 0x%x", __func__, 281 hp->destination_partition, ntohl(hp->firmware_length)); 282 if (ntohl(hp->firmware_length) == 0) { 283 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 284 "%s: bad firmware length 0x%x", 285 __func__, ntohl(hp->firmware_length)); 286 return (EINVAL); 287 } 288 wrk += (sizeof (pmcs_fw_hdr_t) + ntohl(hp->firmware_length)); 289 if (wrk == base + length) { 290 break; 291 } 292 if (wrk > base + length) { 293 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 294 "%s: out of bounds firmware length", __func__); 295 return (EINVAL); 296 } 297 hp = (void *)wrk; 298 } 299 300 /* 301 * Step 2- acquire scratch 302 */ 303 (void) pmcs_acquire_scratch(pwp, B_TRUE); 304 305 /* 306 * Step 3- loop through firmware chunks and send each one 307 * down to be flashed. 308 */ 309 hp = hdr; 310 wrk = (uint8_t *)hdr; 311 base = wrk; 312 for (;;) { 313 if (pmcs_flash_chunk(pwp, wrk)) { 314 pmcs_release_scratch(pwp); 315 return (EIO); 316 } 317 wrk += (sizeof (pmcs_fw_hdr_t) + ntohl(hp->firmware_length)); 318 if (wrk == base + length) { 319 break; 320 } 321 hp = (void *) wrk; 322 } 323 pmcs_release_scratch(pwp); 324 return (0); 325 } 326 327 static int 328 pmcs_flash_chunk(pmcs_hw_t *pwp, uint8_t *chunk) 329 { 330 pmcs_fw_hdr_t *hp; 331 pmcwork_t *pwrk; 332 uint32_t len, seg, off, result, amt, msg[PMCS_MSG_SIZE], *ptr; 333 334 hp = (void *)chunk; 335 len = sizeof (pmcs_fw_hdr_t) + ntohl(hp->firmware_length); 336 337 seg = off = 0; 338 while (off < len) { 339 amt = PMCS_SCRATCH_SIZE; 340 if (off + amt > len) { 341 amt = len - off; 342 } 343 pmcs_prt(pwp, PMCS_PRT_DEBUG1, NULL, NULL, 344 "%s: segment %d offset %u length %u", 345 __func__, seg, off, amt); 346 (void) memcpy(pwp->scratch, &chunk[off], amt); 347 pwrk = pmcs_gwork(pwp, PMCS_TAG_TYPE_WAIT, NULL); 348 if (pwrk == NULL) { 349 return (ENOMEM); 350 } 351 pwrk->arg = msg; 352 msg[0] = LE_32(PMCS_HIPRI(pwp, 353 PMCS_OQ_EVENTS, PMCIN_FW_FLASH_UPDATE)); 354 msg[1] = LE_32(pwrk->htag); 355 msg[2] = LE_32(off); 356 msg[3] = LE_32(amt); 357 if (off == 0) { 358 msg[4] = LE_32(len); 359 } else { 360 msg[4] = 0; 361 } 362 msg[5] = 0; 363 msg[6] = 0; 364 msg[7] = 0; 365 msg[8] = 0; 366 msg[9] = 0; 367 msg[10] = 0; 368 msg[11] = 0; 369 msg[12] = LE_32(DWORD0(pwp->scratch_dma)); 370 msg[13] = LE_32(DWORD1(pwp->scratch_dma)); 371 msg[14] = LE_32(amt); 372 msg[15] = 0; 373 mutex_enter(&pwp->iqp_lock[PMCS_IQ_OTHER]); 374 ptr = GET_IQ_ENTRY(pwp, PMCS_IQ_OTHER); 375 if (ptr == NULL) { 376 mutex_exit(&pwp->iqp_lock[PMCS_IQ_OTHER]); 377 pmcs_pwork(pwp, pwrk); 378 pmcs_prt(pwp, PMCS_PRT_ERR, NULL, NULL, 379 pmcs_nomsg, __func__); 380 return (ENOMEM); 381 } 382 COPY_MESSAGE(ptr, msg, PMCS_MSG_SIZE); 383 (void) memset(msg, 0xaf, sizeof (msg)); 384 pwrk->state = PMCS_WORK_STATE_ONCHIP; 385 INC_IQ_ENTRY(pwp, PMCS_IQ_OTHER); 386 WAIT_FOR(pwrk, PMCS_FLASH_WAIT_TIME, result); 387 pmcs_pwork(pwp, pwrk); 388 if (result) { 389 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 390 pmcs_timeo, __func__); 391 return (EIO); 392 } 393 switch (LE_32(msg[2])) { 394 case FLASH_UPDATE_COMPLETE_PENDING_REBOOT: 395 pmcs_prt(pwp, PMCS_PRT_DEBUG1, NULL, NULL, 396 "%s: segment %d complete pending reboot", 397 __func__, seg); 398 break; 399 case FLASH_UPDATE_IN_PROGRESS: 400 pmcs_prt(pwp, PMCS_PRT_DEBUG1, NULL, NULL, 401 "%s: segment %d downloaded", __func__, seg); 402 break; 403 case FLASH_UPDATE_HDR_ERR: 404 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 405 "%s: segment %d header error", __func__, seg); 406 return (EIO); 407 case FLASH_UPDATE_OFFSET_ERR: 408 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 409 "%s: segment %d offset error", __func__, seg); 410 return (EIO); 411 case FLASH_UPDATE_UPDATE_CRC_ERR: 412 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 413 "%s: segment %d update crc error", __func__, seg); 414 return (EIO); 415 case FLASH_UPDATE_LENGTH_ERR: 416 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 417 "%s: segment %d length error", __func__, seg); 418 return (EIO); 419 case FLASH_UPDATE_HW_ERR: 420 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 421 "%s: segment %d hw error", __func__, seg); 422 return (EIO); 423 case FLASH_UPDATE_DNLD_NOT_SUPPORTED: 424 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 425 "%s: segment %d download not supported error", 426 __func__, seg); 427 return (EIO); 428 case FLASH_UPDATE_DISABLED: 429 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 430 "%s: segment %d update disabled error", 431 __func__, seg); 432 return (EIO); 433 default: 434 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 435 "%s: segment %d unknown error %x", 436 __func__, seg, msg[2]); 437 return (EIO); 438 } 439 off += amt; 440 seg++; 441 } 442 return (0); 443 } 444 445 /* 446 * pmcs_validate_vpd 447 * 448 * Input: softstate pointer and pointer to vpd data buffer 449 * Returns: B_TRUE if VPD data looks OK, B_FALSE otherwise 450 */ 451 static boolean_t 452 pmcs_validate_vpd(pmcs_hw_t *pwp, uint8_t *data) 453 { 454 pmcs_vpd_header_t *vpd_header; 455 uint8_t *bufp, kv_len, *chksump, chksum = 0; 456 char tbuf[80]; 457 char prop[24]; 458 int idx, str_len; 459 uint16_t strid_length, chksum_len; 460 uint64_t wwid; 461 pmcs_vpd_kv_t *vkvp; 462 463 vpd_header = (pmcs_vpd_header_t *)data; 464 465 /* 466 * Make sure we understand the format of this data 467 */ 468 469 /* 470 * Only VPD version 1 is VALID for Thebe-INT cards and 471 * Only VPD version 2 is valid for Thebe-EXT cards 472 */ 473 if ((vpd_header->eeprom_version == PMCS_EEPROM_INT_VERSION && 474 vpd_header->subsys_pid[0] == PMCS_EEPROM_INT_SSID_BYTE1 && 475 vpd_header->subsys_pid[1] == PMCS_EEPROM_INT_SSID_BYTE2) || 476 (vpd_header->eeprom_version == PMCS_EEPROM_EXT_VERSION && 477 vpd_header->subsys_pid[0] == PMCS_EEPROM_EXT_SSID_BYTE1 && 478 vpd_header->subsys_pid[1] == PMCS_EEPROM_EXT_SSID_BYTE2)) { 479 goto valid_version; 480 } else { 481 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 482 "%s: Detected Thebe card with SSID(%02x%02x)", __func__, 483 vpd_header->subsys_pid[0], vpd_header->subsys_pid[1]); 484 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 485 "%s: EEPROM(%d) unsupported; requires %d for INT(%02x%02x) " 486 " and %d for EXT(%02x%02x) cards.", __func__, 487 vpd_header->eeprom_version, 488 PMCS_EEPROM_INT_VERSION, PMCS_EEPROM_INT_SSID_BYTE1, 489 PMCS_EEPROM_INT_SSID_BYTE2, PMCS_EEPROM_EXT_VERSION, 490 PMCS_EEPROM_EXT_SSID_BYTE1, PMCS_EEPROM_EXT_SSID_BYTE2); 491 return (B_FALSE); 492 } 493 494 valid_version: 495 /* 496 * Do we have a valid SAS WWID? 497 */ 498 if (((vpd_header->hba_sas_wwid[0] & 0xf0) >> 4) != NAA_IEEE_REG) { 499 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 500 "%s: SAS WWN has invalid NAA (%d)", __func__, 501 ((vpd_header->hba_sas_wwid[0] & 0xf0) >> 4)); 502 return (B_FALSE); 503 } 504 wwid = pmcs_barray2wwn(vpd_header->hba_sas_wwid); 505 for (idx = 0; idx < PMCS_MAX_PORTS; idx++) { 506 pwp->sas_wwns[idx] = wwid + idx; 507 } 508 509 if (vpd_header->vpd_start_byte != PMCS_VPD_START) { 510 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 511 "%s: Didn't see VPD start byte", __func__); 512 return (B_FALSE); 513 } 514 515 /* 516 * We only checksum the VPD data between (and including) VPD Start byte 517 * and the checksum value byte. The length of this data for CRC is 518 * 15 less than the length indicated in vpd_length field of the header. 519 * 8 (SAS WWN) + 2 (subsystem ID) + 2 (subsystem vendor ID) + 520 * 1 (end tag) + 2 (hex byte CRC, different from this one) = 15 bytes 521 */ 522 /* 523 * VPD length (little endian format) is represented as byte-array field 524 * & read the following way to avoid alignment issues (in SPARC) 525 */ 526 chksum_len = ((vpd_header->vpd_length[1] << 8) | 527 (vpd_header->vpd_length[0])) - 15; 528 /* Validate VPD data checksum */ 529 chksump = (uint8_t *)&vpd_header->vpd_start_byte; 530 ASSERT (*chksump == PMCS_VPD_START); 531 for (idx = 0; idx < chksum_len; idx++, chksump++) { 532 chksum += *chksump; 533 } 534 ASSERT (*chksump == PMCS_VPD_END); 535 if (chksum) { 536 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 537 "%s: VPD checksum failure", __func__); 538 return (B_FALSE); 539 } 540 541 /* 542 * Get length of string ID tag and read it. 543 */ 544 bufp = (uint8_t *)&vpd_header->vpd_start_byte; 545 bufp += 3; /* Skip the start byte and length */ 546 /* 547 * String ID tag length (little endian format) is represented as 548 * byte-array & read the following way to avoid alignment issues 549 * (in SPARC) 550 */ 551 strid_length = (vpd_header->strid_length[1] << 8) | 552 (vpd_header->strid_length[0]); 553 if (strid_length > 79) { 554 strid_length = 79; 555 } 556 bcopy(bufp, tbuf, strid_length); 557 tbuf[strid_length] = 0; 558 559 pmcs_prt(pwp, PMCS_PRT_DEBUG2, NULL, NULL, 560 "%s: Product Name: '%s'", __func__, tbuf); 561 pmcs_smhba_add_hba_prop(pwp, DATA_TYPE_STRING, PMCS_MODEL_NAME, tbuf); 562 563 /* 564 * Skip VPD-R tag and length of read-only tag, then start reading 565 * keyword/value pairs 566 */ 567 bufp += strid_length; /* Skip to VPD-R tag */ 568 bufp += 3; /* Skip VPD-R tag and length of VPD-R data */ 569 570 vkvp = (pmcs_vpd_kv_t *)bufp; 571 572 while (vkvp->keyword[0] != PMCS_VPD_END) { 573 tbuf[0] = 0; 574 str_len = snprintf(tbuf, 80, "VPD: %c%c = <", 575 vkvp->keyword[0], vkvp->keyword[1]); 576 577 kv_len = vkvp->value_length; 578 for (idx = 0; idx < kv_len; idx++) { 579 tbuf[str_len + idx] = vkvp->value[idx]; 580 prop[idx] = vkvp->value[idx]; 581 } 582 prop[idx] = '\0'; 583 str_len += kv_len; 584 tbuf[str_len] = '>'; 585 tbuf[str_len + 1] = 0; 586 pmcs_prt(pwp, PMCS_PRT_DEBUG2, NULL, NULL, "%s (Len: 0x%x)", 587 tbuf, kv_len); 588 589 /* Keyword is Manufacturer */ 590 if ((vkvp->keyword[0] == 'M') && (vkvp->keyword[1] == 'N')) { 591 pmcs_smhba_add_hba_prop(pwp, DATA_TYPE_STRING, 592 PMCS_MANUFACTURER, prop); 593 } 594 /* Keyword is Serial Number */ 595 if ((vkvp->keyword[0] == 'S') && (vkvp->keyword[1] == 'N')) { 596 pmcs_smhba_add_hba_prop(pwp, DATA_TYPE_STRING, 597 PMCS_SERIAL_NUMBER, prop); 598 } 599 600 vkvp = (pmcs_vpd_kv_t *)(bufp + 3 + kv_len); 601 bufp += kv_len + 3; 602 } 603 604 return (B_TRUE); 605 } 606 607 /* 608 * pmcs_get_nvmd 609 * 610 * This function will read the requested data from the non-volatile 611 * storage on the card. This could mean SEEPROM, VPD, or other areas 612 * as defined by the PM8001 programmer's manual. 613 * 614 * nvmd_type: The data type being requested 615 * nvmd: NVM device to access (IOP/AAP1) 616 * offset: Must be 4K alignment 617 * buf: Pointer to memory region for retrieved data 618 * size_left: Total available bytes left in buf 619 * 620 * Returns: non-negative on success, -1 on failure 621 */ 622 623 /*ARGSUSED*/ 624 int 625 pmcs_get_nvmd(pmcs_hw_t *pwp, pmcs_nvmd_type_t nvmd_type, uint8_t nvmd, 626 uint32_t offset, char *buf, uint32_t size_left) 627 { 628 pmcs_get_nvmd_cmd_t iomb; 629 pmcwork_t *workp; 630 uint8_t *chunkp; 631 uint32_t *ptr, ibq, *iombp; 632 uint32_t dlen; 633 uint16_t status; 634 uint8_t tdas_nvmd, ip, tda, tbn_tdps; 635 uint8_t doa[3]; 636 int32_t result = -1, i = 0; 637 638 switch (nvmd_type) { 639 case PMCS_NVMD_VPD: 640 tdas_nvmd = PMCIN_NVMD_TDPS_1 | PMCIN_NVMD_TWI; 641 tda = PMCIN_TDA_PAGE(2); 642 tbn_tdps = PMCIN_NVMD_TBN(0) | PMCIN_NVMD_TDPS_8; 643 ip = PMCIN_NVMD_INDIRECT_PLD; 644 dlen = LE_32(PMCS_SEEPROM_PAGE_SIZE); 645 doa[0] = 0; 646 doa[1] = 0; 647 doa[2] = 0; 648 break; 649 case PMCS_NVMD_REG_DUMP: 650 tdas_nvmd = nvmd; 651 tda = 0; 652 tbn_tdps = 0; 653 ip = PMCIN_NVMD_INDIRECT_PLD; 654 dlen = LE_32(PMCS_REGISTER_DUMP_BLOCK_SIZE); 655 doa[0] = offset & 0xff; 656 doa[1] = (offset >> 8) & 0xff; 657 doa[2] = (offset >> 16) & 0xff; 658 break; 659 case PMCS_NVMD_EVENT_LOG: 660 tdas_nvmd = nvmd; 661 tda = 0; 662 tbn_tdps = 0; 663 ip = PMCIN_NVMD_INDIRECT_PLD; 664 dlen = LE_32(PMCS_REGISTER_DUMP_BLOCK_SIZE); 665 offset = offset + PMCS_NVMD_EVENT_LOG_OFFSET; 666 doa[0] = offset & 0xff; 667 doa[1] = (offset >> 8) & 0xff; 668 doa[2] = (offset >> 16) & 0xff; 669 break; 670 default: 671 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 672 "%s: Invalid nvmd type: %d", __func__, nvmd_type); 673 return (-1); 674 } 675 676 workp = pmcs_gwork(pwp, PMCS_TAG_TYPE_WAIT, NULL); 677 if (workp == NULL) { 678 pmcs_prt(pwp, PMCS_PRT_WARN, NULL, NULL, 679 "%s: Unable to get work struct", __func__); 680 return (-1); 681 } 682 683 ptr = &iomb.header; 684 bzero(ptr, sizeof (pmcs_get_nvmd_cmd_t)); 685 *ptr = LE_32(PMCS_IOMB_IN_SAS(PMCS_OQ_GENERAL, PMCIN_GET_NVMD_DATA)); 686 workp->arg = (void *)&iomb; 687 iomb.htag = LE_32(workp->htag); 688 iomb.ip = ip; 689 iomb.tbn_tdps = tbn_tdps; 690 iomb.tda = tda; 691 iomb.tdas_nvmd = tdas_nvmd; 692 iomb.ipbal = LE_32(DWORD0(pwp->flash_chunk_addr)); 693 iomb.ipbah = LE_32(DWORD1(pwp->flash_chunk_addr)); 694 iomb.ipdl = dlen; 695 iomb.doa[0] = doa[0]; 696 iomb.doa[1] = doa[1]; 697 iomb.doa[2] = doa[2]; 698 699 /* 700 * ptr will now point to the inbound queue message 701 */ 702 GET_IO_IQ_ENTRY(pwp, ptr, 0, ibq); 703 if (ptr == NULL) { 704 pmcs_prt(pwp, PMCS_PRT_ERR, NULL, NULL, 705 "!%s: Unable to get IQ entry", __func__); 706 pmcs_pwork(pwp, workp); 707 return (-1); 708 } 709 710 bzero(ptr, PMCS_MSG_SIZE << 2); /* PMCS_MSG_SIZE is in dwords */ 711 iombp = (uint32_t *)&iomb; 712 COPY_MESSAGE(ptr, iombp, sizeof (pmcs_get_nvmd_cmd_t) >> 2); 713 workp->state = PMCS_WORK_STATE_ONCHIP; 714 INC_IQ_ENTRY(pwp, ibq); 715 716 WAIT_FOR(workp, 1000, result); 717 ptr = workp->arg; 718 if (result) { 719 pmcs_timed_out(pwp, workp->htag, __func__); 720 pmcs_pwork(pwp, workp); 721 return (-1); 722 } 723 status = LE_32(*(ptr + 3)) & 0xffff; 724 if (status != PMCS_NVMD_STAT_SUCCESS) { 725 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 726 "%s: Error, status = 0x%04x", __func__, status); 727 pmcs_pwork(pwp, workp); 728 return (-1); 729 } 730 731 pmcs_pwork(pwp, workp); 732 733 if (ddi_dma_sync(pwp->cip_handles, 0, 0, 734 DDI_DMA_SYNC_FORKERNEL) != DDI_SUCCESS) { 735 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 736 "Condition check failed at %s():%d", __func__, __LINE__); 737 } 738 chunkp = (uint8_t *)pwp->flash_chunkp; 739 740 switch (nvmd) { 741 case PMCIN_NVMD_VPD: 742 if (pmcs_validate_vpd(pwp, chunkp)) { 743 result = 0; 744 } else { 745 result = -1; 746 } 747 break; 748 case PMCIN_NVMD_AAP1: 749 case PMCIN_NVMD_IOP: 750 ASSERT(buf); 751 i = 0; 752 if (nvmd_type == PMCS_NVMD_REG_DUMP) { 753 while ((i < PMCS_FLASH_CHUNK_SIZE) && 754 (chunkp[i] != 0xff) && (chunkp[i] != '\0')) { 755 (void) snprintf(&buf[i], (size_left - i), 756 "%c", chunkp[i]); 757 i++; 758 } 759 } else if (nvmd_type == PMCS_NVMD_EVENT_LOG) { 760 i = pmcs_dump_binary(pwp, pwp->flash_chunkp, 0, 761 (PMCS_FLASH_CHUNK_SIZE >> 2), buf, size_left); 762 } 763 result = i; 764 break; 765 default: 766 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 767 "UNKNOWN NVMD DEVICE"); 768 return (-1); 769 } 770 771 return (result); 772 } 773 774 /* 775 * pmcs_set_nvmd 776 * 777 * This function will write the requested data to non-volatile storage 778 * on the HBA. This could mean SEEPROM, VPD, or other areas as defined by 779 * the PM8001 programmer's manual. 780 * 781 * nvmd_type: The data type to be written 782 * buf: Pointer to memory region for data to write 783 * len: Length of the data buffer 784 * 785 * Returns: B_TRUE on success, B_FALSE on failure 786 */ 787 788 boolean_t 789 pmcs_set_nvmd(pmcs_hw_t *pwp, pmcs_nvmd_type_t nvmd_type, uint8_t *buf, 790 size_t len) 791 { 792 pmcs_set_nvmd_cmd_t iomb; 793 pmcwork_t *workp; 794 uint32_t *ptr, ibq, *iombp; 795 uint32_t dlen; 796 uint16_t status; 797 uint8_t tdas_nvmd, ip; 798 int result; 799 800 switch (nvmd_type) { 801 case PMCS_NVMD_SPCBOOT: 802 tdas_nvmd = PMCIN_NVMD_SEEPROM; 803 ip = PMCIN_NVMD_INDIRECT_PLD; 804 ASSERT((len >= PMCS_SPCBOOT_MIN_SIZE) && 805 (len <= PMCS_SPCBOOT_MAX_SIZE)); 806 dlen = LE_32(len); 807 break; 808 default: 809 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 810 "%s: Invalid nvmd type: %d", __func__, nvmd_type); 811 return (B_FALSE); 812 } 813 814 pmcs_prt(pwp, PMCS_PRT_DEBUG_DEVEL, NULL, NULL, 815 "%s: Request for nvmd type: %d", __func__, nvmd_type); 816 817 workp = pmcs_gwork(pwp, PMCS_TAG_TYPE_WAIT, NULL); 818 if (workp == NULL) { 819 pmcs_prt(pwp, PMCS_PRT_WARN, NULL, NULL, 820 "%s: Unable to get work struct", __func__); 821 return (B_FALSE); 822 } 823 824 ptr = &iomb.header; 825 bzero(ptr, sizeof (pmcs_set_nvmd_cmd_t)); 826 *ptr = LE_32(PMCS_IOMB_IN_SAS(PMCS_OQ_GENERAL, PMCIN_SET_NVMD_DATA)); 827 workp->arg = (void *)&iomb; 828 iomb.htag = LE_32(workp->htag); 829 iomb.ip = ip; 830 iomb.tdas_nvmd = tdas_nvmd; 831 iomb.signature = LE_32(PMCS_SEEPROM_SIGNATURE); 832 iomb.ipbal = LE_32(DWORD0(pwp->flash_chunk_addr)); 833 iomb.ipbah = LE_32(DWORD1(pwp->flash_chunk_addr)); 834 iomb.ipdl = dlen; 835 836 pmcs_print_entry(pwp, PMCS_PRT_DEBUG_DEVEL, 837 "PMCIN_SET_NVMD_DATA iomb", (void *)&iomb); 838 839 bcopy(buf, pwp->flash_chunkp, len); 840 if (ddi_dma_sync(pwp->cip_handles, 0, 0, 841 DDI_DMA_SYNC_FORDEV) != DDI_SUCCESS) { 842 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 843 "Condition check failed at %s():%d", __func__, __LINE__); 844 } 845 846 /* 847 * ptr will now point to the inbound queue message 848 */ 849 GET_IO_IQ_ENTRY(pwp, ptr, 0, ibq); 850 if (ptr == NULL) { 851 pmcs_prt(pwp, PMCS_PRT_ERR, NULL, NULL, 852 "!%s: Unable to get IQ entry", __func__); 853 pmcs_pwork(pwp, workp); 854 return (B_FALSE); 855 } 856 857 bzero(ptr, PMCS_MSG_SIZE << 2); /* PMCS_MSG_SIZE is in dwords */ 858 iombp = (uint32_t *)&iomb; 859 COPY_MESSAGE(ptr, iombp, sizeof (pmcs_set_nvmd_cmd_t) >> 2); 860 workp->state = PMCS_WORK_STATE_ONCHIP; 861 INC_IQ_ENTRY(pwp, ibq); 862 863 WAIT_FOR(workp, 2000, result); 864 865 if (result) { 866 pmcs_timed_out(pwp, workp->htag, __func__); 867 pmcs_pwork(pwp, workp); 868 return (B_FALSE); 869 } 870 871 pmcs_pwork(pwp, workp); 872 873 status = LE_32(*(ptr + 3)) & 0xffff; 874 if (status != PMCS_NVMD_STAT_SUCCESS) { 875 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 876 "%s: Error, status = 0x%04x", __func__, status); 877 return (B_FALSE); 878 } 879 880 return (B_TRUE); 881 } 882