1283514Sarybchik/*- 2301388Sarybchik * Copyright (c) 2012-2016 Solarflare Communications Inc. 3283514Sarybchik * All rights reserved. 4283514Sarybchik * 5283514Sarybchik * Redistribution and use in source and binary forms, with or without 6283514Sarybchik * modification, are permitted provided that the following conditions are met: 7283514Sarybchik * 8283514Sarybchik * 1. Redistributions of source code must retain the above copyright notice, 9283514Sarybchik * this list of conditions and the following disclaimer. 10283514Sarybchik * 2. Redistributions in binary form must reproduce the above copyright notice, 11283514Sarybchik * this list of conditions and the following disclaimer in the documentation 12283514Sarybchik * and/or other materials provided with the distribution. 13283514Sarybchik * 14283514Sarybchik * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15283514Sarybchik * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 16283514Sarybchik * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17283514Sarybchik * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 18283514Sarybchik * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19283514Sarybchik * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20283514Sarybchik * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21283514Sarybchik * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22283514Sarybchik * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23283514Sarybchik * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 24283514Sarybchik * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25283514Sarybchik * 26283514Sarybchik * The views and conclusions contained in the software and documentation are 27283514Sarybchik * those of the authors and should not be interpreted as representing official 28283514Sarybchik * policies, either expressed or implied, of the FreeBSD Project. 29283514Sarybchik */ 30283514Sarybchik 31283514Sarybchik#include <sys/cdefs.h> 32283514Sarybchik__FBSDID("$FreeBSD: stable/10/sys/dev/sfxge/common/ef10_nvram.c 342512 2018-12-26 10:21:40Z arybchik $"); 33283514Sarybchik 34283514Sarybchik#include "efx.h" 35283514Sarybchik#include "efx_impl.h" 36283514Sarybchik 37299602Sarybchik#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD 38283514Sarybchik 39283514Sarybchik#if EFSYS_OPT_VPD || EFSYS_OPT_NVRAM 40283514Sarybchik 41283514Sarybchik#include "ef10_tlv_layout.h" 42283514Sarybchik 43283514Sarybchik/* Cursor for TLV partition format */ 44283514Sarybchiktypedef struct tlv_cursor_s { 45283514Sarybchik uint32_t *block; /* Base of data block */ 46283514Sarybchik uint32_t *current; /* Cursor position */ 47283514Sarybchik uint32_t *end; /* End tag position */ 48283514Sarybchik uint32_t *limit; /* Last dword of data block */ 49283514Sarybchik} tlv_cursor_t; 50283514Sarybchik 51299319Sarybchiktypedef struct nvram_partition_s { 52299319Sarybchik uint16_t type; 53299319Sarybchik uint8_t chip_select; 54299319Sarybchik uint8_t flags; 55299319Sarybchik /* 56299319Sarybchik * The full length of the NVRAM partition. 57299319Sarybchik * This is different from tlv_partition_header.total_length, 58299319Sarybchik * which can be smaller. 59299319Sarybchik */ 60299319Sarybchik uint32_t length; 61299319Sarybchik uint32_t erase_size; 62299319Sarybchik uint32_t *data; 63299319Sarybchik tlv_cursor_t tlv_cursor; 64299319Sarybchik} nvram_partition_t; 65299319Sarybchik 66299319Sarybchik 67291436Sarybchikstatic __checkReturn efx_rc_t 68283514Sarybchiktlv_validate_state( 69299319Sarybchik __inout tlv_cursor_t *cursor); 70283514Sarybchik 71283514Sarybchik 72299319Sarybchikstatic void 73299319Sarybchiktlv_init_block( 74299319Sarybchik __out uint32_t *block) 75299319Sarybchik{ 76299319Sarybchik *block = __CPU_TO_LE_32(TLV_TAG_END); 77299319Sarybchik} 78299319Sarybchik 79283514Sarybchikstatic uint32_t 80283514Sarybchiktlv_tag( 81283514Sarybchik __in tlv_cursor_t *cursor) 82283514Sarybchik{ 83283514Sarybchik uint32_t dword, tag; 84283514Sarybchik 85283514Sarybchik dword = cursor->current[0]; 86283514Sarybchik tag = __LE_TO_CPU_32(dword); 87283514Sarybchik 88283514Sarybchik return (tag); 89283514Sarybchik} 90283514Sarybchik 91283514Sarybchikstatic size_t 92283514Sarybchiktlv_length( 93283514Sarybchik __in tlv_cursor_t *cursor) 94283514Sarybchik{ 95283514Sarybchik uint32_t dword, length; 96283514Sarybchik 97283514Sarybchik if (tlv_tag(cursor) == TLV_TAG_END) 98283514Sarybchik return (0); 99283514Sarybchik 100283514Sarybchik dword = cursor->current[1]; 101283514Sarybchik length = __LE_TO_CPU_32(dword); 102283514Sarybchik 103283514Sarybchik return ((size_t)length); 104283514Sarybchik} 105283514Sarybchik 106283514Sarybchikstatic uint8_t * 107283514Sarybchiktlv_value( 108283514Sarybchik __in tlv_cursor_t *cursor) 109283514Sarybchik{ 110283514Sarybchik if (tlv_tag(cursor) == TLV_TAG_END) 111283514Sarybchik return (NULL); 112283514Sarybchik 113283514Sarybchik return ((uint8_t *)(&cursor->current[2])); 114283514Sarybchik} 115283514Sarybchik 116283514Sarybchikstatic uint8_t * 117283514Sarybchiktlv_item( 118283514Sarybchik __in tlv_cursor_t *cursor) 119283514Sarybchik{ 120283514Sarybchik if (tlv_tag(cursor) == TLV_TAG_END) 121283514Sarybchik return (NULL); 122283514Sarybchik 123283514Sarybchik return ((uint8_t *)cursor->current); 124283514Sarybchik} 125283514Sarybchik 126283514Sarybchik/* 127283514Sarybchik * TLV item DWORD length is tag + length + value (rounded up to DWORD) 128283514Sarybchik * equivalent to tlv_n_words_for_len in mc-comms tlv.c 129283514Sarybchik */ 130283514Sarybchik#define TLV_DWORD_COUNT(length) \ 131283514Sarybchik (1 + 1 + (((length) + sizeof (uint32_t) - 1) / sizeof (uint32_t))) 132283514Sarybchik 133283514Sarybchik 134283514Sarybchikstatic uint32_t * 135283514Sarybchiktlv_next_item_ptr( 136283514Sarybchik __in tlv_cursor_t *cursor) 137283514Sarybchik{ 138283514Sarybchik uint32_t length; 139283514Sarybchik 140283514Sarybchik length = tlv_length(cursor); 141283514Sarybchik 142283514Sarybchik return (cursor->current + TLV_DWORD_COUNT(length)); 143283514Sarybchik} 144283514Sarybchik 145299319Sarybchikstatic __checkReturn efx_rc_t 146283514Sarybchiktlv_advance( 147299319Sarybchik __inout tlv_cursor_t *cursor) 148283514Sarybchik{ 149291436Sarybchik efx_rc_t rc; 150283514Sarybchik 151283514Sarybchik if ((rc = tlv_validate_state(cursor)) != 0) 152283514Sarybchik goto fail1; 153283514Sarybchik 154283514Sarybchik if (cursor->current == cursor->end) { 155283514Sarybchik /* No more tags after END tag */ 156283514Sarybchik cursor->current = NULL; 157283514Sarybchik rc = ENOENT; 158283514Sarybchik goto fail2; 159283514Sarybchik } 160283514Sarybchik 161283514Sarybchik /* Advance to next item and validate */ 162283514Sarybchik cursor->current = tlv_next_item_ptr(cursor); 163283514Sarybchik 164283514Sarybchik if ((rc = tlv_validate_state(cursor)) != 0) 165283514Sarybchik goto fail3; 166283514Sarybchik 167283514Sarybchik return (0); 168283514Sarybchik 169283514Sarybchikfail3: 170283514Sarybchik EFSYS_PROBE(fail3); 171283514Sarybchikfail2: 172283514Sarybchik EFSYS_PROBE(fail2); 173283514Sarybchikfail1: 174291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 175283514Sarybchik 176283514Sarybchik return (rc); 177283514Sarybchik} 178283514Sarybchik 179291436Sarybchikstatic efx_rc_t 180283514Sarybchiktlv_rewind( 181283514Sarybchik __in tlv_cursor_t *cursor) 182283514Sarybchik{ 183291436Sarybchik efx_rc_t rc; 184283514Sarybchik 185283514Sarybchik cursor->current = cursor->block; 186283514Sarybchik 187283514Sarybchik if ((rc = tlv_validate_state(cursor)) != 0) 188283514Sarybchik goto fail1; 189283514Sarybchik 190283514Sarybchik return (0); 191283514Sarybchik 192283514Sarybchikfail1: 193291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 194283514Sarybchik 195283514Sarybchik return (rc); 196283514Sarybchik} 197283514Sarybchik 198291436Sarybchikstatic efx_rc_t 199283514Sarybchiktlv_find( 200299319Sarybchik __inout tlv_cursor_t *cursor, 201283514Sarybchik __in uint32_t tag) 202283514Sarybchik{ 203291436Sarybchik efx_rc_t rc; 204283514Sarybchik 205283514Sarybchik rc = tlv_rewind(cursor); 206283514Sarybchik while (rc == 0) { 207283514Sarybchik if (tlv_tag(cursor) == tag) 208283514Sarybchik break; 209283514Sarybchik 210283514Sarybchik rc = tlv_advance(cursor); 211283514Sarybchik } 212283514Sarybchik return (rc); 213283514Sarybchik} 214283514Sarybchik 215291436Sarybchikstatic __checkReturn efx_rc_t 216283514Sarybchiktlv_validate_state( 217299319Sarybchik __inout tlv_cursor_t *cursor) 218283514Sarybchik{ 219291436Sarybchik efx_rc_t rc; 220283514Sarybchik 221283514Sarybchik /* Check cursor position */ 222283514Sarybchik if (cursor->current < cursor->block) { 223283514Sarybchik rc = EINVAL; 224283514Sarybchik goto fail1; 225283514Sarybchik } 226283514Sarybchik if (cursor->current > cursor->limit) { 227283514Sarybchik rc = EINVAL; 228283514Sarybchik goto fail2; 229283514Sarybchik } 230283514Sarybchik 231283514Sarybchik if (tlv_tag(cursor) != TLV_TAG_END) { 232283514Sarybchik /* Check current item has space for tag and length */ 233283514Sarybchik if (cursor->current > (cursor->limit - 2)) { 234283514Sarybchik cursor->current = NULL; 235283514Sarybchik rc = EFAULT; 236283514Sarybchik goto fail3; 237283514Sarybchik } 238283514Sarybchik 239283514Sarybchik /* Check we have value data for current item and another tag */ 240283514Sarybchik if (tlv_next_item_ptr(cursor) > (cursor->limit - 1)) { 241283514Sarybchik cursor->current = NULL; 242283514Sarybchik rc = EFAULT; 243283514Sarybchik goto fail4; 244283514Sarybchik } 245283514Sarybchik } 246283514Sarybchik 247283514Sarybchik return (0); 248283514Sarybchik 249283514Sarybchikfail4: 250283514Sarybchik EFSYS_PROBE(fail4); 251283514Sarybchikfail3: 252283514Sarybchik EFSYS_PROBE(fail3); 253283514Sarybchikfail2: 254283514Sarybchik EFSYS_PROBE(fail2); 255283514Sarybchikfail1: 256291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 257283514Sarybchik 258283514Sarybchik return (rc); 259283514Sarybchik} 260283514Sarybchik 261291436Sarybchikstatic efx_rc_t 262283514Sarybchiktlv_init_cursor( 263293817Sarybchik __out tlv_cursor_t *cursor, 264283514Sarybchik __in uint32_t *block, 265299319Sarybchik __in uint32_t *limit, 266299319Sarybchik __in uint32_t *current) 267283514Sarybchik{ 268283514Sarybchik cursor->block = block; 269283514Sarybchik cursor->limit = limit; 270283514Sarybchik 271299319Sarybchik cursor->current = current; 272283514Sarybchik cursor->end = NULL; 273283514Sarybchik 274283514Sarybchik return (tlv_validate_state(cursor)); 275283514Sarybchik} 276283514Sarybchik 277299319Sarybchikstatic __checkReturn efx_rc_t 278283514Sarybchiktlv_init_cursor_from_size( 279293817Sarybchik __out tlv_cursor_t *cursor, 280299319Sarybchik __in_bcount(size) 281299319Sarybchik uint8_t *block, 282283514Sarybchik __in size_t size) 283283514Sarybchik{ 284283514Sarybchik uint32_t *limit; 285283514Sarybchik limit = (uint32_t *)(block + size - sizeof (uint32_t)); 286299319Sarybchik return (tlv_init_cursor(cursor, (uint32_t *)block, 287299319Sarybchik limit, (uint32_t *)block)); 288283514Sarybchik} 289283514Sarybchik 290299319Sarybchikstatic __checkReturn efx_rc_t 291299319Sarybchiktlv_init_cursor_at_offset( 292299319Sarybchik __out tlv_cursor_t *cursor, 293299319Sarybchik __in_bcount(size) 294299319Sarybchik uint8_t *block, 295299319Sarybchik __in size_t size, 296299319Sarybchik __in size_t offset) 297299319Sarybchik{ 298299319Sarybchik uint32_t *limit; 299299319Sarybchik uint32_t *current; 300299319Sarybchik limit = (uint32_t *)(block + size - sizeof (uint32_t)); 301299319Sarybchik current = (uint32_t *)(block + offset); 302299319Sarybchik return (tlv_init_cursor(cursor, (uint32_t *)block, limit, current)); 303299319Sarybchik} 304299319Sarybchik 305299319Sarybchikstatic __checkReturn efx_rc_t 306283514Sarybchiktlv_require_end( 307299319Sarybchik __inout tlv_cursor_t *cursor) 308283514Sarybchik{ 309283514Sarybchik uint32_t *pos; 310291436Sarybchik efx_rc_t rc; 311283514Sarybchik 312283514Sarybchik if (cursor->end == NULL) { 313283514Sarybchik pos = cursor->current; 314283514Sarybchik if ((rc = tlv_find(cursor, TLV_TAG_END)) != 0) 315283514Sarybchik goto fail1; 316283514Sarybchik 317283514Sarybchik cursor->end = cursor->current; 318283514Sarybchik cursor->current = pos; 319283514Sarybchik } 320283514Sarybchik 321283514Sarybchik return (0); 322283514Sarybchik 323283514Sarybchikfail1: 324291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 325283514Sarybchik 326283514Sarybchik return (rc); 327283514Sarybchik} 328283514Sarybchik 329283514Sarybchikstatic size_t 330283514Sarybchiktlv_block_length_used( 331299319Sarybchik __inout tlv_cursor_t *cursor) 332283514Sarybchik{ 333291436Sarybchik efx_rc_t rc; 334283514Sarybchik 335283514Sarybchik if ((rc = tlv_validate_state(cursor)) != 0) 336283514Sarybchik goto fail1; 337283514Sarybchik 338283514Sarybchik if ((rc = tlv_require_end(cursor)) != 0) 339283514Sarybchik goto fail2; 340283514Sarybchik 341283514Sarybchik /* Return space used (including the END tag) */ 342283514Sarybchik return (cursor->end + 1 - cursor->block) * sizeof (uint32_t); 343283514Sarybchik 344283514Sarybchikfail2: 345283514Sarybchik EFSYS_PROBE(fail2); 346283514Sarybchikfail1: 347291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 348283514Sarybchik 349283514Sarybchik return (0); 350283514Sarybchik} 351283514Sarybchik 352299319Sarybchikstatic uint32_t * 353299319Sarybchiktlv_last_segment_end( 354299319Sarybchik __in tlv_cursor_t *cursor) 355299319Sarybchik{ 356299319Sarybchik tlv_cursor_t segment_cursor; 357299319Sarybchik uint32_t *last_segment_end = cursor->block; 358299319Sarybchik uint32_t *segment_start = cursor->block; 359283514Sarybchik 360299319Sarybchik /* 361299319Sarybchik * Go through each segment and check that it has an end tag. If there 362299319Sarybchik * is no end tag then the previous segment was the last valid one, 363299319Sarybchik * so return the pointer to its end tag. 364299319Sarybchik */ 365301400Sarybchik for (;;) { 366299319Sarybchik if (tlv_init_cursor(&segment_cursor, segment_start, 367299319Sarybchik cursor->limit, segment_start) != 0) 368299319Sarybchik break; 369299319Sarybchik if (tlv_require_end(&segment_cursor) != 0) 370299319Sarybchik break; 371299319Sarybchik last_segment_end = segment_cursor.end; 372299319Sarybchik segment_start = segment_cursor.end + 1; 373299319Sarybchik } 374299319Sarybchik 375299319Sarybchik return (last_segment_end); 376299319Sarybchik} 377299319Sarybchik 378299319Sarybchik 379299319Sarybchikstatic uint32_t * 380283514Sarybchiktlv_write( 381283514Sarybchik __in tlv_cursor_t *cursor, 382283514Sarybchik __in uint32_t tag, 383283514Sarybchik __in_bcount(size) uint8_t *data, 384283514Sarybchik __in size_t size) 385283514Sarybchik{ 386283514Sarybchik uint32_t len = size; 387283514Sarybchik uint32_t *ptr; 388283514Sarybchik 389283514Sarybchik ptr = cursor->current; 390283514Sarybchik 391283514Sarybchik *ptr++ = __CPU_TO_LE_32(tag); 392283514Sarybchik *ptr++ = __CPU_TO_LE_32(len); 393283514Sarybchik 394283514Sarybchik if (len > 0) { 395283514Sarybchik ptr[(len - 1) / sizeof (uint32_t)] = 0; 396283514Sarybchik memcpy(ptr, data, len); 397283514Sarybchik ptr += P2ROUNDUP(len, sizeof (uint32_t)) / sizeof (*ptr); 398283514Sarybchik } 399283514Sarybchik 400283514Sarybchik return (ptr); 401283514Sarybchik} 402283514Sarybchik 403291436Sarybchikstatic __checkReturn efx_rc_t 404283514Sarybchiktlv_insert( 405299319Sarybchik __inout tlv_cursor_t *cursor, 406283514Sarybchik __in uint32_t tag, 407299319Sarybchik __in_bcount(size) 408299319Sarybchik uint8_t *data, 409283514Sarybchik __in size_t size) 410283514Sarybchik{ 411283514Sarybchik unsigned int delta; 412299319Sarybchik uint32_t *last_segment_end; 413291436Sarybchik efx_rc_t rc; 414283514Sarybchik 415283514Sarybchik if ((rc = tlv_validate_state(cursor)) != 0) 416283514Sarybchik goto fail1; 417283514Sarybchik 418283514Sarybchik if ((rc = tlv_require_end(cursor)) != 0) 419283514Sarybchik goto fail2; 420283514Sarybchik 421283514Sarybchik if (tag == TLV_TAG_END) { 422283514Sarybchik rc = EINVAL; 423283514Sarybchik goto fail3; 424283514Sarybchik } 425283514Sarybchik 426299319Sarybchik last_segment_end = tlv_last_segment_end(cursor); 427299319Sarybchik 428283514Sarybchik delta = TLV_DWORD_COUNT(size); 429299319Sarybchik if (last_segment_end + 1 + delta > cursor->limit) { 430283514Sarybchik rc = ENOSPC; 431283514Sarybchik goto fail4; 432283514Sarybchik } 433283514Sarybchik 434283514Sarybchik /* Move data up: new space at cursor->current */ 435283514Sarybchik memmove(cursor->current + delta, cursor->current, 436299319Sarybchik (last_segment_end + 1 - cursor->current) * sizeof (uint32_t)); 437283514Sarybchik 438283514Sarybchik /* Adjust the end pointer */ 439283514Sarybchik cursor->end += delta; 440283514Sarybchik 441283514Sarybchik /* Write new TLV item */ 442283514Sarybchik tlv_write(cursor, tag, data, size); 443283514Sarybchik 444283514Sarybchik return (0); 445283514Sarybchik 446283514Sarybchikfail4: 447283514Sarybchik EFSYS_PROBE(fail4); 448283514Sarybchikfail3: 449283514Sarybchik EFSYS_PROBE(fail3); 450283514Sarybchikfail2: 451283514Sarybchik EFSYS_PROBE(fail2); 452283514Sarybchikfail1: 453291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 454283514Sarybchik 455283514Sarybchik return (rc); 456283514Sarybchik} 457283514Sarybchik 458291436Sarybchikstatic __checkReturn efx_rc_t 459299319Sarybchiktlv_delete( 460299319Sarybchik __inout tlv_cursor_t *cursor) 461299319Sarybchik{ 462299319Sarybchik unsigned int delta; 463299319Sarybchik uint32_t *last_segment_end; 464299319Sarybchik efx_rc_t rc; 465299319Sarybchik 466299319Sarybchik if ((rc = tlv_validate_state(cursor)) != 0) 467299319Sarybchik goto fail1; 468299319Sarybchik 469299319Sarybchik if (tlv_tag(cursor) == TLV_TAG_END) { 470299319Sarybchik rc = EINVAL; 471299319Sarybchik goto fail2; 472299319Sarybchik } 473299319Sarybchik 474299319Sarybchik delta = TLV_DWORD_COUNT(tlv_length(cursor)); 475299319Sarybchik 476299319Sarybchik if ((rc = tlv_require_end(cursor)) != 0) 477299319Sarybchik goto fail3; 478299319Sarybchik 479299319Sarybchik last_segment_end = tlv_last_segment_end(cursor); 480299319Sarybchik 481299319Sarybchik /* Shuffle things down, destroying the item at cursor->current */ 482299319Sarybchik memmove(cursor->current, cursor->current + delta, 483299319Sarybchik (last_segment_end + 1 - cursor->current) * sizeof (uint32_t)); 484299319Sarybchik /* Zero the new space at the end of the TLV chain */ 485299319Sarybchik memset(last_segment_end + 1 - delta, 0, delta * sizeof (uint32_t)); 486299319Sarybchik /* Adjust the end pointer */ 487299319Sarybchik cursor->end -= delta; 488299319Sarybchik 489299319Sarybchik return (0); 490299319Sarybchik 491299319Sarybchikfail3: 492299319Sarybchik EFSYS_PROBE(fail3); 493299319Sarybchikfail2: 494299319Sarybchik EFSYS_PROBE(fail2); 495299319Sarybchikfail1: 496299319Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 497299319Sarybchik 498299319Sarybchik return (rc); 499299319Sarybchik} 500299319Sarybchik 501299319Sarybchikstatic __checkReturn efx_rc_t 502283514Sarybchiktlv_modify( 503299319Sarybchik __inout tlv_cursor_t *cursor, 504283514Sarybchik __in uint32_t tag, 505299319Sarybchik __in_bcount(size) 506299319Sarybchik uint8_t *data, 507283514Sarybchik __in size_t size) 508283514Sarybchik{ 509283514Sarybchik uint32_t *pos; 510283514Sarybchik unsigned int old_ndwords; 511283514Sarybchik unsigned int new_ndwords; 512283514Sarybchik unsigned int delta; 513299319Sarybchik uint32_t *last_segment_end; 514291436Sarybchik efx_rc_t rc; 515283514Sarybchik 516283514Sarybchik if ((rc = tlv_validate_state(cursor)) != 0) 517283514Sarybchik goto fail1; 518283514Sarybchik 519283514Sarybchik if (tlv_tag(cursor) == TLV_TAG_END) { 520283514Sarybchik rc = EINVAL; 521283514Sarybchik goto fail2; 522283514Sarybchik } 523283514Sarybchik if (tlv_tag(cursor) != tag) { 524283514Sarybchik rc = EINVAL; 525283514Sarybchik goto fail3; 526283514Sarybchik } 527283514Sarybchik 528283514Sarybchik old_ndwords = TLV_DWORD_COUNT(tlv_length(cursor)); 529283514Sarybchik new_ndwords = TLV_DWORD_COUNT(size); 530283514Sarybchik 531283514Sarybchik if ((rc = tlv_require_end(cursor)) != 0) 532283514Sarybchik goto fail4; 533283514Sarybchik 534299319Sarybchik last_segment_end = tlv_last_segment_end(cursor); 535299319Sarybchik 536283514Sarybchik if (new_ndwords > old_ndwords) { 537283514Sarybchik /* Expand space used for TLV item */ 538283514Sarybchik delta = new_ndwords - old_ndwords; 539283514Sarybchik pos = cursor->current + old_ndwords; 540283514Sarybchik 541299319Sarybchik if (last_segment_end + 1 + delta > cursor->limit) { 542283514Sarybchik rc = ENOSPC; 543283514Sarybchik goto fail5; 544283514Sarybchik } 545283514Sarybchik 546283514Sarybchik /* Move up: new space at (cursor->current + old_ndwords) */ 547283514Sarybchik memmove(pos + delta, pos, 548299319Sarybchik (last_segment_end + 1 - pos) * sizeof (uint32_t)); 549283514Sarybchik 550283514Sarybchik /* Adjust the end pointer */ 551283514Sarybchik cursor->end += delta; 552283514Sarybchik 553283514Sarybchik } else if (new_ndwords < old_ndwords) { 554283514Sarybchik /* Shrink space used for TLV item */ 555283514Sarybchik delta = old_ndwords - new_ndwords; 556283514Sarybchik pos = cursor->current + new_ndwords; 557283514Sarybchik 558283514Sarybchik /* Move down: remove words at (cursor->current + new_ndwords) */ 559283514Sarybchik memmove(pos, pos + delta, 560299319Sarybchik (last_segment_end + 1 - pos) * sizeof (uint32_t)); 561283514Sarybchik 562283514Sarybchik /* Zero the new space at the end of the TLV chain */ 563299319Sarybchik memset(last_segment_end + 1 - delta, 0, 564299319Sarybchik delta * sizeof (uint32_t)); 565283514Sarybchik 566283514Sarybchik /* Adjust the end pointer */ 567283514Sarybchik cursor->end -= delta; 568283514Sarybchik } 569283514Sarybchik 570283514Sarybchik /* Write new data */ 571283514Sarybchik tlv_write(cursor, tag, data, size); 572283514Sarybchik 573283514Sarybchik return (0); 574283514Sarybchik 575283514Sarybchikfail5: 576283514Sarybchik EFSYS_PROBE(fail5); 577283514Sarybchikfail4: 578283514Sarybchik EFSYS_PROBE(fail4); 579283514Sarybchikfail3: 580283514Sarybchik EFSYS_PROBE(fail3); 581283514Sarybchikfail2: 582283514Sarybchik EFSYS_PROBE(fail2); 583283514Sarybchikfail1: 584291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 585283514Sarybchik 586283514Sarybchik return (rc); 587283514Sarybchik} 588283514Sarybchik 589299319Sarybchikstatic uint32_t checksum_tlv_partition( 590299319Sarybchik __in nvram_partition_t *partition) 591299319Sarybchik{ 592299319Sarybchik tlv_cursor_t *cursor; 593299319Sarybchik uint32_t *ptr; 594299319Sarybchik uint32_t *end; 595299319Sarybchik uint32_t csum; 596299319Sarybchik size_t len; 597299319Sarybchik 598299319Sarybchik cursor = &partition->tlv_cursor; 599299319Sarybchik len = tlv_block_length_used(cursor); 600299319Sarybchik EFSYS_ASSERT3U((len & 3), ==, 0); 601299319Sarybchik 602299319Sarybchik csum = 0; 603299319Sarybchik ptr = partition->data; 604299319Sarybchik end = &ptr[len >> 2]; 605299319Sarybchik 606299319Sarybchik while (ptr < end) 607299319Sarybchik csum += __LE_TO_CPU_32(*ptr++); 608299319Sarybchik 609299319Sarybchik return (csum); 610299319Sarybchik} 611299319Sarybchik 612299319Sarybchikstatic __checkReturn efx_rc_t 613299319Sarybchiktlv_update_partition_len_and_cks( 614299319Sarybchik __in tlv_cursor_t *cursor) 615299319Sarybchik{ 616299319Sarybchik efx_rc_t rc; 617299319Sarybchik nvram_partition_t partition; 618299319Sarybchik struct tlv_partition_header *header; 619299319Sarybchik struct tlv_partition_trailer *trailer; 620299319Sarybchik size_t new_len; 621299319Sarybchik 622299319Sarybchik /* 623299319Sarybchik * We just modified the partition, so the total length may not be 624299319Sarybchik * valid. Don't use tlv_find(), which performs some sanity checks 625299319Sarybchik * that may fail here. 626299319Sarybchik */ 627299319Sarybchik partition.data = cursor->block; 628299319Sarybchik memcpy(&partition.tlv_cursor, cursor, sizeof (*cursor)); 629299319Sarybchik header = (struct tlv_partition_header *)partition.data; 630299319Sarybchik /* Sanity check. */ 631299319Sarybchik if (__LE_TO_CPU_32(header->tag) != TLV_TAG_PARTITION_HEADER) { 632299319Sarybchik rc = EFAULT; 633299319Sarybchik goto fail1; 634299319Sarybchik } 635299319Sarybchik new_len = tlv_block_length_used(&partition.tlv_cursor); 636299319Sarybchik if (new_len == 0) { 637299319Sarybchik rc = EFAULT; 638299319Sarybchik goto fail2; 639299319Sarybchik } 640299319Sarybchik header->total_length = __CPU_TO_LE_32(new_len); 641299319Sarybchik /* Ensure the modified partition always has a new generation count. */ 642299319Sarybchik header->generation = __CPU_TO_LE_32( 643299319Sarybchik __LE_TO_CPU_32(header->generation) + 1); 644299319Sarybchik 645299319Sarybchik trailer = (struct tlv_partition_trailer *)((uint8_t *)header + 646299319Sarybchik new_len - sizeof (*trailer) - sizeof (uint32_t)); 647299319Sarybchik trailer->generation = header->generation; 648299319Sarybchik trailer->checksum = __CPU_TO_LE_32( 649299319Sarybchik __LE_TO_CPU_32(trailer->checksum) - 650299319Sarybchik checksum_tlv_partition(&partition)); 651299319Sarybchik 652299319Sarybchik return (0); 653299319Sarybchik 654299319Sarybchikfail2: 655299319Sarybchik EFSYS_PROBE(fail2); 656299319Sarybchikfail1: 657299319Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 658299319Sarybchik 659299319Sarybchik return (rc); 660299319Sarybchik} 661299319Sarybchik 662299319Sarybchik/* Validate buffer contents (before writing to flash) */ 663291436Sarybchik __checkReturn efx_rc_t 664299318Sarybchikef10_nvram_buffer_validate( 665283514Sarybchik __in efx_nic_t *enp, 666283514Sarybchik __in uint32_t partn, 667283514Sarybchik __in_bcount(partn_size) caddr_t partn_data, 668283514Sarybchik __in size_t partn_size) 669283514Sarybchik{ 670283514Sarybchik tlv_cursor_t cursor; 671283514Sarybchik struct tlv_partition_header *header; 672283514Sarybchik struct tlv_partition_trailer *trailer; 673283514Sarybchik size_t total_length; 674283514Sarybchik uint32_t cksum; 675283514Sarybchik int pos; 676291436Sarybchik efx_rc_t rc; 677283514Sarybchik 678342501Sarybchik _NOTE(ARGUNUSED(enp, partn)) 679293756Sarybchik EFX_STATIC_ASSERT(sizeof (*header) <= EF10_NVRAM_CHUNK); 680283514Sarybchik 681283514Sarybchik if ((partn_data == NULL) || (partn_size == 0)) { 682283514Sarybchik rc = EINVAL; 683283514Sarybchik goto fail1; 684283514Sarybchik } 685283514Sarybchik 686283514Sarybchik /* The partition header must be the first item (at offset zero) */ 687291926Sarybchik if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)partn_data, 688283514Sarybchik partn_size)) != 0) { 689283514Sarybchik rc = EFAULT; 690283514Sarybchik goto fail2; 691283514Sarybchik } 692283514Sarybchik if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) { 693283514Sarybchik rc = EINVAL; 694283514Sarybchik goto fail3; 695283514Sarybchik } 696283514Sarybchik header = (struct tlv_partition_header *)tlv_item(&cursor); 697283514Sarybchik 698283514Sarybchik /* Check TLV partition length (includes the END tag) */ 699283514Sarybchik total_length = __LE_TO_CPU_32(header->total_length); 700283514Sarybchik if (total_length > partn_size) { 701283514Sarybchik rc = EFBIG; 702283514Sarybchik goto fail4; 703283514Sarybchik } 704283514Sarybchik 705283514Sarybchik /* Check partition ends with PARTITION_TRAILER and END tags */ 706283514Sarybchik if ((rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER)) != 0) { 707283514Sarybchik rc = EINVAL; 708283514Sarybchik goto fail5; 709283514Sarybchik } 710283514Sarybchik trailer = (struct tlv_partition_trailer *)tlv_item(&cursor); 711283514Sarybchik 712283514Sarybchik if ((rc = tlv_advance(&cursor)) != 0) { 713283514Sarybchik rc = EINVAL; 714283514Sarybchik goto fail6; 715283514Sarybchik } 716283514Sarybchik if (tlv_tag(&cursor) != TLV_TAG_END) { 717283514Sarybchik rc = EINVAL; 718283514Sarybchik goto fail7; 719283514Sarybchik } 720283514Sarybchik 721283514Sarybchik /* Check generation counts are consistent */ 722283514Sarybchik if (trailer->generation != header->generation) { 723283514Sarybchik rc = EINVAL; 724283514Sarybchik goto fail8; 725283514Sarybchik } 726283514Sarybchik 727283514Sarybchik /* Verify partition checksum */ 728283514Sarybchik cksum = 0; 729283514Sarybchik for (pos = 0; (size_t)pos < total_length; pos += sizeof (uint32_t)) { 730283514Sarybchik cksum += *((uint32_t *)(partn_data + pos)); 731283514Sarybchik } 732283514Sarybchik if (cksum != 0) { 733283514Sarybchik rc = EINVAL; 734283514Sarybchik goto fail9; 735283514Sarybchik } 736283514Sarybchik 737283514Sarybchik return (0); 738283514Sarybchik 739283514Sarybchikfail9: 740283514Sarybchik EFSYS_PROBE(fail9); 741283514Sarybchikfail8: 742283514Sarybchik EFSYS_PROBE(fail8); 743283514Sarybchikfail7: 744283514Sarybchik EFSYS_PROBE(fail7); 745283514Sarybchikfail6: 746283514Sarybchik EFSYS_PROBE(fail6); 747283514Sarybchikfail5: 748283514Sarybchik EFSYS_PROBE(fail5); 749283514Sarybchikfail4: 750283514Sarybchik EFSYS_PROBE(fail4); 751283514Sarybchikfail3: 752283514Sarybchik EFSYS_PROBE(fail3); 753283514Sarybchikfail2: 754283514Sarybchik EFSYS_PROBE(fail2); 755283514Sarybchikfail1: 756291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 757283514Sarybchik 758283514Sarybchik return (rc); 759283514Sarybchik} 760283514Sarybchik 761299402Sarybchik 762299402Sarybchik 763299402Sarybchik __checkReturn efx_rc_t 764299402Sarybchikef10_nvram_buffer_create( 765299402Sarybchik __in efx_nic_t *enp, 766299402Sarybchik __in uint16_t partn_type, 767299402Sarybchik __in_bcount(partn_size) caddr_t partn_data, 768299402Sarybchik __in size_t partn_size) 769299402Sarybchik{ 770299402Sarybchik uint32_t *buf = (uint32_t *)partn_data; 771299402Sarybchik efx_rc_t rc; 772299402Sarybchik tlv_cursor_t cursor; 773299402Sarybchik struct tlv_partition_header header; 774299402Sarybchik struct tlv_partition_trailer trailer; 775299402Sarybchik 776311062Sarybchik unsigned int min_buf_size = sizeof (struct tlv_partition_header) + 777299402Sarybchik sizeof (struct tlv_partition_trailer); 778299402Sarybchik if (partn_size < min_buf_size) { 779299402Sarybchik rc = EINVAL; 780299402Sarybchik goto fail1; 781299402Sarybchik } 782299402Sarybchik 783299402Sarybchik memset(buf, 0xff, partn_size); 784299402Sarybchik 785299402Sarybchik tlv_init_block(buf); 786299402Sarybchik if ((rc = tlv_init_cursor(&cursor, buf, 787299402Sarybchik (uint32_t *)((uint8_t *)buf + partn_size), 788299402Sarybchik buf)) != 0) { 789299402Sarybchik goto fail2; 790299402Sarybchik } 791299402Sarybchik 792299402Sarybchik header.tag = __CPU_TO_LE_32(TLV_TAG_PARTITION_HEADER); 793299402Sarybchik header.length = __CPU_TO_LE_32(sizeof (header) - 8); 794299402Sarybchik header.type_id = __CPU_TO_LE_16(partn_type); 795299402Sarybchik header.preset = 0; 796299402Sarybchik header.generation = __CPU_TO_LE_32(1); 797299402Sarybchik header.total_length = 0; /* This will be fixed below. */ 798299402Sarybchik if ((rc = tlv_insert( 799299402Sarybchik &cursor, TLV_TAG_PARTITION_HEADER, 800299402Sarybchik (uint8_t *)&header.type_id, sizeof (header) - 8)) != 0) 801299402Sarybchik goto fail3; 802299402Sarybchik if ((rc = tlv_advance(&cursor)) != 0) 803299402Sarybchik goto fail4; 804299402Sarybchik 805299402Sarybchik trailer.tag = __CPU_TO_LE_32(TLV_TAG_PARTITION_TRAILER); 806299402Sarybchik trailer.length = __CPU_TO_LE_32(sizeof (trailer) - 8); 807299402Sarybchik trailer.generation = header.generation; 808299402Sarybchik trailer.checksum = 0; /* This will be fixed below. */ 809299402Sarybchik if ((rc = tlv_insert(&cursor, TLV_TAG_PARTITION_TRAILER, 810299402Sarybchik (uint8_t *)&trailer.generation, sizeof (trailer) - 8)) != 0) 811299402Sarybchik goto fail5; 812299402Sarybchik 813299402Sarybchik if ((rc = tlv_update_partition_len_and_cks(&cursor)) != 0) 814299402Sarybchik goto fail6; 815299402Sarybchik 816299402Sarybchik /* Check that the partition is valid. */ 817299402Sarybchik if ((rc = ef10_nvram_buffer_validate(enp, partn_type, 818299402Sarybchik partn_data, partn_size)) != 0) 819299402Sarybchik goto fail7; 820299402Sarybchik 821299402Sarybchik return (0); 822299402Sarybchik 823299402Sarybchikfail7: 824299402Sarybchik EFSYS_PROBE(fail7); 825299402Sarybchikfail6: 826299402Sarybchik EFSYS_PROBE(fail6); 827299402Sarybchikfail5: 828299402Sarybchik EFSYS_PROBE(fail5); 829299402Sarybchikfail4: 830299402Sarybchik EFSYS_PROBE(fail4); 831299402Sarybchikfail3: 832299402Sarybchik EFSYS_PROBE(fail3); 833299402Sarybchikfail2: 834299402Sarybchik EFSYS_PROBE(fail2); 835299402Sarybchikfail1: 836299402Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 837299402Sarybchik 838299402Sarybchik return (rc); 839299402Sarybchik} 840299402Sarybchik 841299402Sarybchikstatic uint32_t 842299402Sarybchikbyte_offset( 843299402Sarybchik __in uint32_t *position, 844299402Sarybchik __in uint32_t *base) 845299402Sarybchik{ 846299402Sarybchik return (uint32_t)((uint8_t *)position - (uint8_t *)base); 847299402Sarybchik} 848299402Sarybchik 849299402Sarybchik __checkReturn efx_rc_t 850299402Sarybchikef10_nvram_buffer_find_item_start( 851299402Sarybchik __in_bcount(buffer_size) 852299402Sarybchik caddr_t bufferp, 853299402Sarybchik __in size_t buffer_size, 854299402Sarybchik __out uint32_t *startp) 855299402Sarybchik{ 856311050Sarybchik /* Read past partition header to find start address of the first key */ 857299402Sarybchik tlv_cursor_t cursor; 858299402Sarybchik efx_rc_t rc; 859299402Sarybchik 860299402Sarybchik /* A PARTITION_HEADER tag must be the first item (at offset zero) */ 861299402Sarybchik if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)bufferp, 862299402Sarybchik buffer_size)) != 0) { 863299402Sarybchik rc = EFAULT; 864299402Sarybchik goto fail1; 865299402Sarybchik } 866299402Sarybchik if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) { 867299402Sarybchik rc = EINVAL; 868299402Sarybchik goto fail2; 869299402Sarybchik } 870299402Sarybchik 871299402Sarybchik if ((rc = tlv_advance(&cursor)) != 0) { 872299402Sarybchik rc = EINVAL; 873299402Sarybchik goto fail3; 874299402Sarybchik } 875299402Sarybchik *startp = byte_offset(cursor.current, cursor.block); 876299402Sarybchik 877299402Sarybchik if ((rc = tlv_require_end(&cursor)) != 0) 878299402Sarybchik goto fail4; 879299402Sarybchik 880299402Sarybchik return (0); 881299402Sarybchik 882299402Sarybchikfail4: 883299402Sarybchik EFSYS_PROBE(fail4); 884299402Sarybchikfail3: 885299402Sarybchik EFSYS_PROBE(fail3); 886299402Sarybchikfail2: 887299402Sarybchik EFSYS_PROBE(fail2); 888299402Sarybchikfail1: 889299402Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 890299402Sarybchik 891299402Sarybchik return (rc); 892299402Sarybchik} 893299402Sarybchik 894299402Sarybchik __checkReturn efx_rc_t 895299402Sarybchikef10_nvram_buffer_find_end( 896299402Sarybchik __in_bcount(buffer_size) 897299402Sarybchik caddr_t bufferp, 898299402Sarybchik __in size_t buffer_size, 899299402Sarybchik __in uint32_t offset, 900299402Sarybchik __out uint32_t *endp) 901299402Sarybchik{ 902311050Sarybchik /* Read to end of partition */ 903299402Sarybchik tlv_cursor_t cursor; 904299402Sarybchik efx_rc_t rc; 905301364Sarybchik uint32_t *segment_used; 906299402Sarybchik 907301392Sarybchik _NOTE(ARGUNUSED(offset)) 908301392Sarybchik 909299402Sarybchik if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)bufferp, 910299402Sarybchik buffer_size)) != 0) { 911299402Sarybchik rc = EFAULT; 912299402Sarybchik goto fail1; 913299402Sarybchik } 914299402Sarybchik 915301364Sarybchik segment_used = cursor.block; 916299402Sarybchik 917301364Sarybchik /* 918301364Sarybchik * Go through each segment and check that it has an end tag. If there 919301364Sarybchik * is no end tag then the previous segment was the last valid one, 920301364Sarybchik * so return the used space including that end tag. 921301364Sarybchik */ 922301364Sarybchik while (tlv_tag(&cursor) == TLV_TAG_PARTITION_HEADER) { 923301364Sarybchik if (tlv_require_end(&cursor) != 0) { 924301364Sarybchik if (segment_used == cursor.block) { 925301364Sarybchik /* 926301364Sarybchik * First segment is corrupt, so there is 927301364Sarybchik * no valid data in partition. 928301364Sarybchik */ 929301364Sarybchik rc = EINVAL; 930301364Sarybchik goto fail2; 931301364Sarybchik } 932301364Sarybchik break; 933301364Sarybchik } 934301364Sarybchik segment_used = cursor.end + 1; 935299402Sarybchik 936301364Sarybchik cursor.current = segment_used; 937301364Sarybchik } 938301364Sarybchik /* Return space used (including the END tag) */ 939301364Sarybchik *endp = (segment_used - cursor.block) * sizeof (uint32_t); 940301364Sarybchik 941299402Sarybchik return (0); 942299402Sarybchik 943299402Sarybchikfail2: 944299402Sarybchik EFSYS_PROBE(fail2); 945299402Sarybchikfail1: 946299402Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 947299402Sarybchik 948299402Sarybchik return (rc); 949299402Sarybchik} 950299402Sarybchik 951299402Sarybchik __checkReturn __success(return != B_FALSE) boolean_t 952299402Sarybchikef10_nvram_buffer_find_item( 953299402Sarybchik __in_bcount(buffer_size) 954299402Sarybchik caddr_t bufferp, 955299402Sarybchik __in size_t buffer_size, 956299402Sarybchik __in uint32_t offset, 957299402Sarybchik __out uint32_t *startp, 958299402Sarybchik __out uint32_t *lengthp) 959299402Sarybchik{ 960311050Sarybchik /* Find TLV at offset and return key start and length */ 961299402Sarybchik tlv_cursor_t cursor; 962299402Sarybchik uint8_t *key; 963299402Sarybchik uint32_t tag; 964299402Sarybchik 965299402Sarybchik if (tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp, 966299402Sarybchik buffer_size, offset) != 0) { 967299402Sarybchik return (B_FALSE); 968299402Sarybchik } 969299402Sarybchik 970299402Sarybchik while ((key = tlv_item(&cursor)) != NULL) { 971299402Sarybchik tag = tlv_tag(&cursor); 972299402Sarybchik if (tag == TLV_TAG_PARTITION_HEADER || 973299402Sarybchik tag == TLV_TAG_PARTITION_TRAILER) { 974299402Sarybchik if (tlv_advance(&cursor) != 0) { 975299402Sarybchik break; 976299402Sarybchik } 977299402Sarybchik continue; 978299402Sarybchik } 979299402Sarybchik *startp = byte_offset(cursor.current, cursor.block); 980299402Sarybchik *lengthp = byte_offset(tlv_next_item_ptr(&cursor), 981299402Sarybchik cursor.current); 982299402Sarybchik return (B_TRUE); 983299402Sarybchik } 984299402Sarybchik 985299402Sarybchik return (B_FALSE); 986299402Sarybchik} 987299402Sarybchik 988299402Sarybchik __checkReturn efx_rc_t 989299402Sarybchikef10_nvram_buffer_get_item( 990299402Sarybchik __in_bcount(buffer_size) 991299402Sarybchik caddr_t bufferp, 992299402Sarybchik __in size_t buffer_size, 993299402Sarybchik __in uint32_t offset, 994299402Sarybchik __in uint32_t length, 995299402Sarybchik __out_bcount_part(item_max_size, *lengthp) 996299402Sarybchik caddr_t itemp, 997299402Sarybchik __in size_t item_max_size, 998299402Sarybchik __out uint32_t *lengthp) 999299402Sarybchik{ 1000299402Sarybchik efx_rc_t rc; 1001299402Sarybchik tlv_cursor_t cursor; 1002299402Sarybchik uint32_t item_length; 1003299402Sarybchik 1004299402Sarybchik if (item_max_size < length) { 1005299402Sarybchik rc = ENOSPC; 1006299402Sarybchik goto fail1; 1007299402Sarybchik } 1008299402Sarybchik 1009299402Sarybchik if ((rc = tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp, 1010299402Sarybchik buffer_size, offset)) != 0) { 1011299402Sarybchik goto fail2; 1012299402Sarybchik } 1013299402Sarybchik 1014299402Sarybchik item_length = tlv_length(&cursor); 1015299402Sarybchik if (length < item_length) { 1016299402Sarybchik rc = ENOSPC; 1017299402Sarybchik goto fail3; 1018299402Sarybchik } 1019299402Sarybchik memcpy(itemp, tlv_value(&cursor), item_length); 1020299402Sarybchik 1021299402Sarybchik *lengthp = item_length; 1022299402Sarybchik 1023299402Sarybchik return (0); 1024299402Sarybchik 1025299402Sarybchikfail3: 1026299402Sarybchik EFSYS_PROBE(fail3); 1027299402Sarybchikfail2: 1028299402Sarybchik EFSYS_PROBE(fail2); 1029299402Sarybchikfail1: 1030299402Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 1031299402Sarybchik 1032299402Sarybchik return (rc); 1033299402Sarybchik} 1034299402Sarybchik 1035299402Sarybchik __checkReturn efx_rc_t 1036299402Sarybchikef10_nvram_buffer_insert_item( 1037299402Sarybchik __in_bcount(buffer_size) 1038299402Sarybchik caddr_t bufferp, 1039299402Sarybchik __in size_t buffer_size, 1040299402Sarybchik __in uint32_t offset, 1041299402Sarybchik __in_bcount(length) caddr_t keyp, 1042299402Sarybchik __in uint32_t length, 1043299402Sarybchik __out uint32_t *lengthp) 1044299402Sarybchik{ 1045299402Sarybchik efx_rc_t rc; 1046299402Sarybchik tlv_cursor_t cursor; 1047299402Sarybchik 1048299402Sarybchik if ((rc = tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp, 1049299402Sarybchik buffer_size, offset)) != 0) { 1050299402Sarybchik goto fail1; 1051299402Sarybchik } 1052299402Sarybchik 1053301356Sarybchik rc = tlv_insert(&cursor, TLV_TAG_LICENSE, (uint8_t *)keyp, length); 1054299402Sarybchik 1055299402Sarybchik if (rc != 0) { 1056299402Sarybchik goto fail2; 1057299402Sarybchik } 1058299402Sarybchik 1059299402Sarybchik *lengthp = byte_offset(tlv_next_item_ptr(&cursor), 1060299402Sarybchik cursor.current); 1061299402Sarybchik 1062299402Sarybchik return (0); 1063299402Sarybchik 1064299402Sarybchikfail2: 1065299402Sarybchik EFSYS_PROBE(fail2); 1066299402Sarybchikfail1: 1067299402Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 1068299402Sarybchik 1069299402Sarybchik return (rc); 1070299402Sarybchik} 1071299402Sarybchik 1072299402Sarybchik __checkReturn efx_rc_t 1073299402Sarybchikef10_nvram_buffer_delete_item( 1074299402Sarybchik __in_bcount(buffer_size) 1075299402Sarybchik caddr_t bufferp, 1076299402Sarybchik __in size_t buffer_size, 1077299402Sarybchik __in uint32_t offset, 1078299402Sarybchik __in uint32_t length, 1079299402Sarybchik __in uint32_t end) 1080299402Sarybchik{ 1081299402Sarybchik efx_rc_t rc; 1082299402Sarybchik tlv_cursor_t cursor; 1083299402Sarybchik 1084301392Sarybchik _NOTE(ARGUNUSED(length, end)) 1085301392Sarybchik 1086299402Sarybchik if ((rc = tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp, 1087299402Sarybchik buffer_size, offset)) != 0) { 1088299402Sarybchik goto fail1; 1089299402Sarybchik } 1090299402Sarybchik 1091299402Sarybchik if ((rc = tlv_delete(&cursor)) != 0) 1092299402Sarybchik goto fail2; 1093299402Sarybchik 1094299402Sarybchik return (0); 1095299402Sarybchik 1096299402Sarybchikfail2: 1097299402Sarybchik EFSYS_PROBE(fail2); 1098299402Sarybchikfail1: 1099299402Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 1100299402Sarybchik 1101299402Sarybchik return (rc); 1102299402Sarybchik} 1103299402Sarybchik 1104299402Sarybchik __checkReturn efx_rc_t 1105299402Sarybchikef10_nvram_buffer_finish( 1106299402Sarybchik __in_bcount(buffer_size) 1107299402Sarybchik caddr_t bufferp, 1108299402Sarybchik __in size_t buffer_size) 1109299402Sarybchik{ 1110299402Sarybchik efx_rc_t rc; 1111299402Sarybchik tlv_cursor_t cursor; 1112299402Sarybchik 1113299402Sarybchik if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)bufferp, 1114299402Sarybchik buffer_size)) != 0) { 1115299402Sarybchik rc = EFAULT; 1116299402Sarybchik goto fail1; 1117299402Sarybchik } 1118299402Sarybchik 1119299402Sarybchik if ((rc = tlv_require_end(&cursor)) != 0) 1120299402Sarybchik goto fail2; 1121299402Sarybchik 1122299402Sarybchik if ((rc = tlv_update_partition_len_and_cks(&cursor)) != 0) 1123299402Sarybchik goto fail3; 1124299402Sarybchik 1125299402Sarybchik return (0); 1126299402Sarybchik 1127299402Sarybchikfail3: 1128299402Sarybchik EFSYS_PROBE(fail3); 1129299402Sarybchikfail2: 1130299402Sarybchik EFSYS_PROBE(fail2); 1131299402Sarybchikfail1: 1132299402Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 1133299402Sarybchik 1134299402Sarybchik return (rc); 1135299402Sarybchik} 1136299402Sarybchik 1137299402Sarybchik 1138299402Sarybchik 1139291432Sarybchik/* 1140291432Sarybchik * Read and validate a segment from a partition. A segment is a complete 1141291432Sarybchik * tlv chain between PARTITION_HEADER and PARTITION_END tags. There may 1142291432Sarybchik * be multiple segments in a partition, so seg_offset allows segments 1143291432Sarybchik * beyond the first to be read. 1144291432Sarybchik */ 1145291436Sarybchikstatic __checkReturn efx_rc_t 1146293756Sarybchikef10_nvram_read_tlv_segment( 1147291432Sarybchik __in efx_nic_t *enp, 1148291432Sarybchik __in uint32_t partn, 1149291432Sarybchik __in size_t seg_offset, 1150291432Sarybchik __in_bcount(max_seg_size) caddr_t seg_data, 1151291432Sarybchik __in size_t max_seg_size) 1152283514Sarybchik{ 1153283514Sarybchik tlv_cursor_t cursor; 1154283514Sarybchik struct tlv_partition_header *header; 1155283514Sarybchik struct tlv_partition_trailer *trailer; 1156283514Sarybchik size_t total_length; 1157283514Sarybchik uint32_t cksum; 1158283514Sarybchik int pos; 1159291436Sarybchik efx_rc_t rc; 1160283514Sarybchik 1161293756Sarybchik EFX_STATIC_ASSERT(sizeof (*header) <= EF10_NVRAM_CHUNK); 1162283514Sarybchik 1163291432Sarybchik if ((seg_data == NULL) || (max_seg_size == 0)) { 1164283514Sarybchik rc = EINVAL; 1165283514Sarybchik goto fail1; 1166283514Sarybchik } 1167283514Sarybchik 1168291432Sarybchik /* Read initial chunk of the segment, starting at offset */ 1169294309Sarybchik if ((rc = ef10_nvram_partn_read_mode(enp, partn, seg_offset, seg_data, 1170294309Sarybchik EF10_NVRAM_CHUNK, 1171294309Sarybchik MC_CMD_NVRAM_READ_IN_V2_TARGET_CURRENT)) != 0) { 1172283514Sarybchik goto fail2; 1173283514Sarybchik } 1174283514Sarybchik 1175291432Sarybchik /* A PARTITION_HEADER tag must be the first item at the given offset */ 1176291926Sarybchik if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)seg_data, 1177291432Sarybchik max_seg_size)) != 0) { 1178283514Sarybchik rc = EFAULT; 1179283514Sarybchik goto fail3; 1180283514Sarybchik } 1181283514Sarybchik if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) { 1182283514Sarybchik rc = EINVAL; 1183283514Sarybchik goto fail4; 1184283514Sarybchik } 1185283514Sarybchik header = (struct tlv_partition_header *)tlv_item(&cursor); 1186283514Sarybchik 1187291432Sarybchik /* Check TLV segment length (includes the END tag) */ 1188283514Sarybchik total_length = __LE_TO_CPU_32(header->total_length); 1189291432Sarybchik if (total_length > max_seg_size) { 1190283514Sarybchik rc = EFBIG; 1191283514Sarybchik goto fail5; 1192283514Sarybchik } 1193283514Sarybchik 1194291432Sarybchik /* Read the remaining segment content */ 1195293756Sarybchik if (total_length > EF10_NVRAM_CHUNK) { 1196294309Sarybchik if ((rc = ef10_nvram_partn_read_mode(enp, partn, 1197293756Sarybchik seg_offset + EF10_NVRAM_CHUNK, 1198293756Sarybchik seg_data + EF10_NVRAM_CHUNK, 1199294309Sarybchik total_length - EF10_NVRAM_CHUNK, 1200294309Sarybchik MC_CMD_NVRAM_READ_IN_V2_TARGET_CURRENT)) != 0) 1201283514Sarybchik goto fail6; 1202283514Sarybchik } 1203283514Sarybchik 1204291432Sarybchik /* Check segment ends with PARTITION_TRAILER and END tags */ 1205283514Sarybchik if ((rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER)) != 0) { 1206283514Sarybchik rc = EINVAL; 1207283514Sarybchik goto fail7; 1208283514Sarybchik } 1209283514Sarybchik trailer = (struct tlv_partition_trailer *)tlv_item(&cursor); 1210283514Sarybchik 1211283514Sarybchik if ((rc = tlv_advance(&cursor)) != 0) { 1212283514Sarybchik rc = EINVAL; 1213283514Sarybchik goto fail8; 1214283514Sarybchik } 1215283514Sarybchik if (tlv_tag(&cursor) != TLV_TAG_END) { 1216283514Sarybchik rc = EINVAL; 1217283514Sarybchik goto fail9; 1218283514Sarybchik } 1219283514Sarybchik 1220291432Sarybchik /* Check data read from segment is consistent */ 1221283514Sarybchik if (trailer->generation != header->generation) { 1222283514Sarybchik /* 1223283514Sarybchik * The partition data may have been modified between successive 1224283514Sarybchik * MCDI NVRAM_READ requests by the MC or another PCI function. 1225283514Sarybchik * 1226283514Sarybchik * The caller must retry to obtain consistent partition data. 1227283514Sarybchik */ 1228283514Sarybchik rc = EAGAIN; 1229283514Sarybchik goto fail10; 1230283514Sarybchik } 1231283514Sarybchik 1232291432Sarybchik /* Verify segment checksum */ 1233283514Sarybchik cksum = 0; 1234283514Sarybchik for (pos = 0; (size_t)pos < total_length; pos += sizeof (uint32_t)) { 1235291432Sarybchik cksum += *((uint32_t *)(seg_data + pos)); 1236283514Sarybchik } 1237283514Sarybchik if (cksum != 0) { 1238283514Sarybchik rc = EINVAL; 1239283514Sarybchik goto fail11; 1240283514Sarybchik } 1241283514Sarybchik 1242283514Sarybchik return (0); 1243283514Sarybchik 1244283514Sarybchikfail11: 1245283514Sarybchik EFSYS_PROBE(fail11); 1246283514Sarybchikfail10: 1247283514Sarybchik EFSYS_PROBE(fail10); 1248283514Sarybchikfail9: 1249283514Sarybchik EFSYS_PROBE(fail9); 1250283514Sarybchikfail8: 1251283514Sarybchik EFSYS_PROBE(fail8); 1252283514Sarybchikfail7: 1253283514Sarybchik EFSYS_PROBE(fail7); 1254283514Sarybchikfail6: 1255283514Sarybchik EFSYS_PROBE(fail6); 1256283514Sarybchikfail5: 1257283514Sarybchik EFSYS_PROBE(fail5); 1258283514Sarybchikfail4: 1259283514Sarybchik EFSYS_PROBE(fail4); 1260283514Sarybchikfail3: 1261283514Sarybchik EFSYS_PROBE(fail3); 1262283514Sarybchikfail2: 1263283514Sarybchik EFSYS_PROBE(fail2); 1264283514Sarybchikfail1: 1265291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 1266283514Sarybchik 1267283514Sarybchik return (rc); 1268283514Sarybchik} 1269283514Sarybchik 1270283514Sarybchik/* 1271283514Sarybchik * Read a single TLV item from a host memory 1272291432Sarybchik * buffer containing a TLV formatted segment. 1273283514Sarybchik */ 1274291436Sarybchik __checkReturn efx_rc_t 1275293756Sarybchikef10_nvram_buf_read_tlv( 1276283514Sarybchik __in efx_nic_t *enp, 1277291432Sarybchik __in_bcount(max_seg_size) caddr_t seg_data, 1278291432Sarybchik __in size_t max_seg_size, 1279283514Sarybchik __in uint32_t tag, 1280283514Sarybchik __deref_out_bcount_opt(*sizep) caddr_t *datap, 1281283514Sarybchik __out size_t *sizep) 1282283514Sarybchik{ 1283283514Sarybchik tlv_cursor_t cursor; 1284283514Sarybchik caddr_t data; 1285283514Sarybchik size_t length; 1286283514Sarybchik caddr_t value; 1287291436Sarybchik efx_rc_t rc; 1288283514Sarybchik 1289342501Sarybchik _NOTE(ARGUNUSED(enp)) 1290342501Sarybchik 1291291432Sarybchik if ((seg_data == NULL) || (max_seg_size == 0)) { 1292283514Sarybchik rc = EINVAL; 1293283514Sarybchik goto fail1; 1294283514Sarybchik } 1295283514Sarybchik 1296291432Sarybchik /* Find requested TLV tag in segment data */ 1297291926Sarybchik if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)seg_data, 1298291432Sarybchik max_seg_size)) != 0) { 1299283514Sarybchik rc = EFAULT; 1300283514Sarybchik goto fail2; 1301283514Sarybchik } 1302283514Sarybchik if ((rc = tlv_find(&cursor, tag)) != 0) { 1303283514Sarybchik rc = ENOENT; 1304283514Sarybchik goto fail3; 1305283514Sarybchik } 1306291926Sarybchik value = (caddr_t)tlv_value(&cursor); 1307283514Sarybchik length = tlv_length(&cursor); 1308283514Sarybchik 1309283514Sarybchik if (length == 0) 1310283514Sarybchik data = NULL; 1311283514Sarybchik else { 1312283514Sarybchik /* Copy out data from TLV item */ 1313283514Sarybchik EFSYS_KMEM_ALLOC(enp->en_esip, length, data); 1314283514Sarybchik if (data == NULL) { 1315283514Sarybchik rc = ENOMEM; 1316283514Sarybchik goto fail4; 1317283514Sarybchik } 1318283514Sarybchik memcpy(data, value, length); 1319283514Sarybchik } 1320283514Sarybchik 1321283514Sarybchik *datap = data; 1322283514Sarybchik *sizep = length; 1323283514Sarybchik 1324283514Sarybchik return (0); 1325283514Sarybchik 1326283514Sarybchikfail4: 1327283514Sarybchik EFSYS_PROBE(fail4); 1328283514Sarybchikfail3: 1329283514Sarybchik EFSYS_PROBE(fail3); 1330283514Sarybchikfail2: 1331283514Sarybchik EFSYS_PROBE(fail2); 1332283514Sarybchikfail1: 1333291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 1334283514Sarybchik 1335283514Sarybchik return (rc); 1336283514Sarybchik} 1337283514Sarybchik 1338291432Sarybchik/* Read a single TLV item from the first segment in a TLV formatted partition */ 1339291436Sarybchik __checkReturn efx_rc_t 1340293756Sarybchikef10_nvram_partn_read_tlv( 1341291432Sarybchik __in efx_nic_t *enp, 1342291432Sarybchik __in uint32_t partn, 1343291432Sarybchik __in uint32_t tag, 1344291432Sarybchik __deref_out_bcount_opt(*seg_sizep) caddr_t *seg_datap, 1345291432Sarybchik __out size_t *seg_sizep) 1346283514Sarybchik{ 1347291432Sarybchik caddr_t seg_data = NULL; 1348283514Sarybchik size_t partn_size = 0; 1349283514Sarybchik size_t length; 1350283514Sarybchik caddr_t data; 1351283514Sarybchik int retry; 1352291436Sarybchik efx_rc_t rc; 1353283514Sarybchik 1354283514Sarybchik /* Allocate sufficient memory for the entire partition */ 1355293756Sarybchik if ((rc = ef10_nvram_partn_size(enp, partn, &partn_size)) != 0) 1356283514Sarybchik goto fail1; 1357283514Sarybchik 1358283514Sarybchik if (partn_size == 0) { 1359283514Sarybchik rc = ENOENT; 1360283514Sarybchik goto fail2; 1361283514Sarybchik } 1362283514Sarybchik 1363291432Sarybchik EFSYS_KMEM_ALLOC(enp->en_esip, partn_size, seg_data); 1364291432Sarybchik if (seg_data == NULL) { 1365283514Sarybchik rc = ENOMEM; 1366283514Sarybchik goto fail3; 1367283514Sarybchik } 1368283514Sarybchik 1369283514Sarybchik /* 1370291432Sarybchik * Read the first segment in a TLV partition. Retry until consistent 1371291432Sarybchik * segment contents are returned. Inconsistent data may be read if: 1372291432Sarybchik * a) the segment contents are invalid 1373283514Sarybchik * b) the MC has rebooted while we were reading the partition 1374283514Sarybchik * c) the partition has been modified while we were reading it 1375283514Sarybchik * Limit retry attempts to ensure forward progress. 1376283514Sarybchik */ 1377283514Sarybchik retry = 10; 1378283514Sarybchik do { 1379293756Sarybchik rc = ef10_nvram_read_tlv_segment(enp, partn, 0, 1380291432Sarybchik seg_data, partn_size); 1381283514Sarybchik } while ((rc == EAGAIN) && (--retry > 0)); 1382283514Sarybchik 1383283514Sarybchik if (rc != 0) { 1384291432Sarybchik /* Failed to obtain consistent segment data */ 1385283514Sarybchik goto fail4; 1386283514Sarybchik } 1387283514Sarybchik 1388293756Sarybchik if ((rc = ef10_nvram_buf_read_tlv(enp, seg_data, partn_size, 1389283514Sarybchik tag, &data, &length)) != 0) 1390283514Sarybchik goto fail5; 1391283514Sarybchik 1392291432Sarybchik EFSYS_KMEM_FREE(enp->en_esip, partn_size, seg_data); 1393283514Sarybchik 1394291432Sarybchik *seg_datap = data; 1395291432Sarybchik *seg_sizep = length; 1396283514Sarybchik 1397283514Sarybchik return (0); 1398283514Sarybchik 1399283514Sarybchikfail5: 1400283514Sarybchik EFSYS_PROBE(fail5); 1401283514Sarybchikfail4: 1402283514Sarybchik EFSYS_PROBE(fail4); 1403283514Sarybchik 1404291432Sarybchik EFSYS_KMEM_FREE(enp->en_esip, partn_size, seg_data); 1405283514Sarybchikfail3: 1406283514Sarybchik EFSYS_PROBE(fail3); 1407283514Sarybchikfail2: 1408283514Sarybchik EFSYS_PROBE(fail2); 1409283514Sarybchikfail1: 1410291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 1411283514Sarybchik 1412283514Sarybchik return (rc); 1413283514Sarybchik} 1414283514Sarybchik 1415291432Sarybchik/* Compute the size of a segment. */ 1416291436Sarybchik static __checkReturn efx_rc_t 1417293756Sarybchikef10_nvram_buf_segment_size( 1418291432Sarybchik __in caddr_t seg_data, 1419291432Sarybchik __in size_t max_seg_size, 1420291432Sarybchik __out size_t *seg_sizep) 1421291432Sarybchik{ 1422291436Sarybchik efx_rc_t rc; 1423291432Sarybchik tlv_cursor_t cursor; 1424291432Sarybchik struct tlv_partition_header *header; 1425291432Sarybchik uint32_t cksum; 1426291432Sarybchik int pos; 1427291432Sarybchik uint32_t *end_tag_position; 1428291432Sarybchik uint32_t segment_length; 1429291432Sarybchik 1430291432Sarybchik /* A PARTITION_HEADER tag must be the first item at the given offset */ 1431291926Sarybchik if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)seg_data, 1432291432Sarybchik max_seg_size)) != 0) { 1433291432Sarybchik rc = EFAULT; 1434291432Sarybchik goto fail1; 1435291432Sarybchik } 1436291432Sarybchik if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) { 1437291432Sarybchik rc = EINVAL; 1438291432Sarybchik goto fail2; 1439291432Sarybchik } 1440291432Sarybchik header = (struct tlv_partition_header *)tlv_item(&cursor); 1441291432Sarybchik 1442291432Sarybchik /* Check TLV segment length (includes the END tag) */ 1443291432Sarybchik *seg_sizep = __LE_TO_CPU_32(header->total_length); 1444291432Sarybchik if (*seg_sizep > max_seg_size) { 1445291432Sarybchik rc = EFBIG; 1446291432Sarybchik goto fail3; 1447291432Sarybchik } 1448291432Sarybchik 1449291432Sarybchik /* Check segment ends with PARTITION_TRAILER and END tags */ 1450291432Sarybchik if ((rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER)) != 0) { 1451291432Sarybchik rc = EINVAL; 1452291432Sarybchik goto fail4; 1453291432Sarybchik } 1454291432Sarybchik 1455291432Sarybchik if ((rc = tlv_advance(&cursor)) != 0) { 1456291432Sarybchik rc = EINVAL; 1457291432Sarybchik goto fail5; 1458291432Sarybchik } 1459291432Sarybchik if (tlv_tag(&cursor) != TLV_TAG_END) { 1460291432Sarybchik rc = EINVAL; 1461291432Sarybchik goto fail6; 1462291432Sarybchik } 1463291432Sarybchik end_tag_position = cursor.current; 1464291432Sarybchik 1465291432Sarybchik /* Verify segment checksum */ 1466291432Sarybchik cksum = 0; 1467291432Sarybchik for (pos = 0; (size_t)pos < *seg_sizep; pos += sizeof (uint32_t)) { 1468291432Sarybchik cksum += *((uint32_t *)(seg_data + pos)); 1469291432Sarybchik } 1470291432Sarybchik if (cksum != 0) { 1471291432Sarybchik rc = EINVAL; 1472291432Sarybchik goto fail7; 1473291432Sarybchik } 1474291432Sarybchik 1475291432Sarybchik /* 1476291432Sarybchik * Calculate total length from HEADER to END tags and compare to 1477291432Sarybchik * max_seg_size and the total_length field in the HEADER tag. 1478291432Sarybchik */ 1479291432Sarybchik segment_length = tlv_block_length_used(&cursor); 1480291432Sarybchik 1481291432Sarybchik if (segment_length > max_seg_size) { 1482291432Sarybchik rc = EINVAL; 1483291432Sarybchik goto fail8; 1484291432Sarybchik } 1485291432Sarybchik 1486291432Sarybchik if (segment_length != *seg_sizep) { 1487291432Sarybchik rc = EINVAL; 1488291432Sarybchik goto fail9; 1489291432Sarybchik } 1490291432Sarybchik 1491291432Sarybchik /* Skip over the first HEADER tag. */ 1492291432Sarybchik rc = tlv_rewind(&cursor); 1493291432Sarybchik rc = tlv_advance(&cursor); 1494291432Sarybchik 1495291432Sarybchik while (rc == 0) { 1496291432Sarybchik if (tlv_tag(&cursor) == TLV_TAG_END) { 1497291432Sarybchik /* Check that the END tag is the one found earlier. */ 1498291432Sarybchik if (cursor.current != end_tag_position) 1499291432Sarybchik goto fail10; 1500291432Sarybchik break; 1501291432Sarybchik } 1502291432Sarybchik /* Check for duplicate HEADER tags before the END tag. */ 1503291432Sarybchik if (tlv_tag(&cursor) == TLV_TAG_PARTITION_HEADER) { 1504291432Sarybchik rc = EINVAL; 1505291432Sarybchik goto fail11; 1506291432Sarybchik } 1507291432Sarybchik 1508291432Sarybchik rc = tlv_advance(&cursor); 1509291432Sarybchik } 1510291432Sarybchik if (rc != 0) 1511291432Sarybchik goto fail12; 1512291432Sarybchik 1513291432Sarybchik return (0); 1514291432Sarybchik 1515291432Sarybchikfail12: 1516291432Sarybchik EFSYS_PROBE(fail12); 1517291432Sarybchikfail11: 1518291432Sarybchik EFSYS_PROBE(fail11); 1519291432Sarybchikfail10: 1520291432Sarybchik EFSYS_PROBE(fail10); 1521291432Sarybchikfail9: 1522291432Sarybchik EFSYS_PROBE(fail9); 1523291432Sarybchikfail8: 1524291432Sarybchik EFSYS_PROBE(fail8); 1525291432Sarybchikfail7: 1526291432Sarybchik EFSYS_PROBE(fail7); 1527291432Sarybchikfail6: 1528291432Sarybchik EFSYS_PROBE(fail6); 1529291432Sarybchikfail5: 1530291432Sarybchik EFSYS_PROBE(fail5); 1531291432Sarybchikfail4: 1532291432Sarybchik EFSYS_PROBE(fail4); 1533291432Sarybchikfail3: 1534291432Sarybchik EFSYS_PROBE(fail3); 1535291432Sarybchikfail2: 1536291432Sarybchik EFSYS_PROBE(fail2); 1537291432Sarybchikfail1: 1538291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 1539291432Sarybchik 1540291432Sarybchik return (rc); 1541291432Sarybchik} 1542291432Sarybchik 1543283514Sarybchik/* 1544283514Sarybchik * Add or update a single TLV item in a host memory buffer containing a TLV 1545291432Sarybchik * formatted segment. Historically partitions consisted of only one segment. 1546283514Sarybchik */ 1547291436Sarybchik __checkReturn efx_rc_t 1548293756Sarybchikef10_nvram_buf_write_tlv( 1549291432Sarybchik __inout_bcount(max_seg_size) caddr_t seg_data, 1550291432Sarybchik __in size_t max_seg_size, 1551283514Sarybchik __in uint32_t tag, 1552283514Sarybchik __in_bcount(tag_size) caddr_t tag_data, 1553283514Sarybchik __in size_t tag_size, 1554283514Sarybchik __out size_t *total_lengthp) 1555283514Sarybchik{ 1556283514Sarybchik tlv_cursor_t cursor; 1557283514Sarybchik struct tlv_partition_header *header; 1558283514Sarybchik struct tlv_partition_trailer *trailer; 1559283514Sarybchik uint32_t generation; 1560283514Sarybchik uint32_t cksum; 1561283514Sarybchik int pos; 1562291436Sarybchik efx_rc_t rc; 1563283514Sarybchik 1564291432Sarybchik /* A PARTITION_HEADER tag must be the first item (at offset zero) */ 1565291926Sarybchik if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)seg_data, 1566291432Sarybchik max_seg_size)) != 0) { 1567283514Sarybchik rc = EFAULT; 1568283514Sarybchik goto fail1; 1569283514Sarybchik } 1570283514Sarybchik if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) { 1571283514Sarybchik rc = EINVAL; 1572283514Sarybchik goto fail2; 1573283514Sarybchik } 1574283514Sarybchik header = (struct tlv_partition_header *)tlv_item(&cursor); 1575283514Sarybchik 1576283514Sarybchik /* Update the TLV chain to contain the new data */ 1577283514Sarybchik if ((rc = tlv_find(&cursor, tag)) == 0) { 1578283514Sarybchik /* Modify existing TLV item */ 1579283514Sarybchik if ((rc = tlv_modify(&cursor, tag, 1580291926Sarybchik (uint8_t *)tag_data, tag_size)) != 0) 1581283514Sarybchik goto fail3; 1582283514Sarybchik } else { 1583283514Sarybchik /* Insert a new TLV item before the PARTITION_TRAILER */ 1584283514Sarybchik rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER); 1585283514Sarybchik if (rc != 0) { 1586283514Sarybchik rc = EINVAL; 1587283514Sarybchik goto fail4; 1588283514Sarybchik } 1589283514Sarybchik if ((rc = tlv_insert(&cursor, tag, 1590291926Sarybchik (uint8_t *)tag_data, tag_size)) != 0) { 1591283514Sarybchik rc = EINVAL; 1592283514Sarybchik goto fail5; 1593283514Sarybchik } 1594283514Sarybchik } 1595283514Sarybchik 1596283514Sarybchik /* Find the trailer tag */ 1597283514Sarybchik if ((rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER)) != 0) { 1598283514Sarybchik rc = EINVAL; 1599283514Sarybchik goto fail6; 1600283514Sarybchik } 1601283514Sarybchik trailer = (struct tlv_partition_trailer *)tlv_item(&cursor); 1602283514Sarybchik 1603283514Sarybchik /* Update PARTITION_HEADER and PARTITION_TRAILER fields */ 1604283514Sarybchik *total_lengthp = tlv_block_length_used(&cursor); 1605291432Sarybchik if (*total_lengthp > max_seg_size) { 1606291432Sarybchik rc = ENOSPC; 1607291432Sarybchik goto fail7; 1608291432Sarybchik } 1609283514Sarybchik generation = __LE_TO_CPU_32(header->generation) + 1; 1610283514Sarybchik 1611283514Sarybchik header->total_length = __CPU_TO_LE_32(*total_lengthp); 1612283514Sarybchik header->generation = __CPU_TO_LE_32(generation); 1613283514Sarybchik trailer->generation = __CPU_TO_LE_32(generation); 1614283514Sarybchik 1615283514Sarybchik /* Recompute PARTITION_TRAILER checksum */ 1616283514Sarybchik trailer->checksum = 0; 1617283514Sarybchik cksum = 0; 1618283514Sarybchik for (pos = 0; (size_t)pos < *total_lengthp; pos += sizeof (uint32_t)) { 1619291432Sarybchik cksum += *((uint32_t *)(seg_data + pos)); 1620283514Sarybchik } 1621283514Sarybchik trailer->checksum = ~cksum + 1; 1622283514Sarybchik 1623283514Sarybchik return (0); 1624283514Sarybchik 1625291432Sarybchikfail7: 1626291432Sarybchik EFSYS_PROBE(fail7); 1627283514Sarybchikfail6: 1628283514Sarybchik EFSYS_PROBE(fail6); 1629283514Sarybchikfail5: 1630283514Sarybchik EFSYS_PROBE(fail5); 1631283514Sarybchikfail4: 1632283514Sarybchik EFSYS_PROBE(fail4); 1633283514Sarybchikfail3: 1634283514Sarybchik EFSYS_PROBE(fail3); 1635283514Sarybchikfail2: 1636283514Sarybchik EFSYS_PROBE(fail2); 1637283514Sarybchikfail1: 1638291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 1639283514Sarybchik 1640283514Sarybchik return (rc); 1641283514Sarybchik} 1642283514Sarybchik 1643291432Sarybchik/* 1644291432Sarybchik * Add or update a single TLV item in the first segment of a TLV formatted 1645291432Sarybchik * dynamic config partition. The first segment is the current active 1646291432Sarybchik * configuration. 1647291432Sarybchik */ 1648291436Sarybchik __checkReturn efx_rc_t 1649293756Sarybchikef10_nvram_partn_write_tlv( 1650283514Sarybchik __in efx_nic_t *enp, 1651283514Sarybchik __in uint32_t partn, 1652283514Sarybchik __in uint32_t tag, 1653283514Sarybchik __in_bcount(size) caddr_t data, 1654283514Sarybchik __in size_t size) 1655283514Sarybchik{ 1656293756Sarybchik return ef10_nvram_partn_write_segment_tlv(enp, partn, tag, data, 1657291432Sarybchik size, B_FALSE); 1658291432Sarybchik} 1659291432Sarybchik 1660291432Sarybchik/* 1661291432Sarybchik * Read a segment from nvram at the given offset into a buffer (segment_data) 1662291432Sarybchik * and optionally write a new tag to it. 1663291432Sarybchik */ 1664301988Sarybchikstatic __checkReturn efx_rc_t 1665293756Sarybchikef10_nvram_segment_write_tlv( 1666291432Sarybchik __in efx_nic_t *enp, 1667291432Sarybchik __in uint32_t partn, 1668291432Sarybchik __in uint32_t tag, 1669291432Sarybchik __in_bcount(size) caddr_t data, 1670291432Sarybchik __in size_t size, 1671291432Sarybchik __inout caddr_t *seg_datap, 1672291432Sarybchik __inout size_t *partn_offsetp, 1673291432Sarybchik __inout size_t *src_remain_lenp, 1674291432Sarybchik __inout size_t *dest_remain_lenp, 1675291432Sarybchik __in boolean_t write) 1676291432Sarybchik{ 1677291436Sarybchik efx_rc_t rc; 1678293819Sarybchik efx_rc_t status; 1679291432Sarybchik size_t original_segment_size; 1680291432Sarybchik size_t modified_segment_size; 1681291432Sarybchik 1682291432Sarybchik /* 1683291432Sarybchik * Read the segment from NVRAM into the segment_data buffer and validate 1684291432Sarybchik * it, returning if it does not validate. This is not a failure unless 1685291432Sarybchik * this is the first segment in a partition. In this case the caller 1686298955Spfg * must propagate the error. 1687291432Sarybchik */ 1688293756Sarybchik status = ef10_nvram_read_tlv_segment(enp, partn, *partn_offsetp, 1689291432Sarybchik *seg_datap, *src_remain_lenp); 1690301988Sarybchik if (status != 0) { 1691301988Sarybchik rc = EINVAL; 1692301988Sarybchik goto fail1; 1693301988Sarybchik } 1694291432Sarybchik 1695293756Sarybchik status = ef10_nvram_buf_segment_size(*seg_datap, 1696291432Sarybchik *src_remain_lenp, &original_segment_size); 1697301988Sarybchik if (status != 0) { 1698301988Sarybchik rc = EINVAL; 1699301988Sarybchik goto fail2; 1700301988Sarybchik } 1701291432Sarybchik 1702291432Sarybchik if (write) { 1703291432Sarybchik /* Update the contents of the segment in the buffer */ 1704293756Sarybchik if ((rc = ef10_nvram_buf_write_tlv(*seg_datap, 1705291432Sarybchik *dest_remain_lenp, tag, data, size, 1706301988Sarybchik &modified_segment_size)) != 0) { 1707301988Sarybchik goto fail3; 1708301988Sarybchik } 1709291432Sarybchik *dest_remain_lenp -= modified_segment_size; 1710291432Sarybchik *seg_datap += modified_segment_size; 1711291432Sarybchik } else { 1712291432Sarybchik /* 1713291432Sarybchik * We won't modify this segment, but still need to update the 1714291432Sarybchik * remaining lengths and pointers. 1715291432Sarybchik */ 1716291432Sarybchik *dest_remain_lenp -= original_segment_size; 1717291432Sarybchik *seg_datap += original_segment_size; 1718291432Sarybchik } 1719291432Sarybchik 1720291432Sarybchik *partn_offsetp += original_segment_size; 1721291432Sarybchik *src_remain_lenp -= original_segment_size; 1722291432Sarybchik 1723291432Sarybchik return (0); 1724291432Sarybchik 1725301988Sarybchikfail3: 1726301988Sarybchik EFSYS_PROBE(fail3); 1727301988Sarybchikfail2: 1728301988Sarybchik EFSYS_PROBE(fail2); 1729291432Sarybchikfail1: 1730291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 1731291432Sarybchik 1732291432Sarybchik return (rc); 1733291432Sarybchik} 1734291432Sarybchik 1735291432Sarybchik/* 1736291432Sarybchik * Add or update a single TLV item in either the first segment or in all 1737291432Sarybchik * segments in a TLV formatted dynamic config partition. Dynamic config 1738291432Sarybchik * partitions on boards that support RFID are divided into a number of segments, 1739291432Sarybchik * each formatted like a partition, with header, trailer and end tags. The first 1740291432Sarybchik * segment is the current active configuration. 1741291432Sarybchik * 1742291432Sarybchik * The segments are initialised by manftest and each contain a different 1743291432Sarybchik * configuration e.g. firmware variant. The firmware can be instructed 1744291432Sarybchik * via RFID to copy a segment to replace the first segment, hence changing the 1745291432Sarybchik * active configuration. This allows ops to change the configuration of a board 1746291432Sarybchik * prior to shipment using RFID. 1747291432Sarybchik * 1748291432Sarybchik * Changes to the dynamic config may need to be written to all segments (e.g. 1749291432Sarybchik * firmware versions) or just the first segment (changes to the active 1750291432Sarybchik * configuration). See SF-111324-SW "The use of RFID in Solarflare Products". 1751291432Sarybchik * If only the first segment is written the code still needs to be aware of the 1752291432Sarybchik * possible presence of subsequent segments as writing to a segment may cause 1753291432Sarybchik * its size to increase, which would overwrite the subsequent segments and 1754291432Sarybchik * invalidate them. 1755291432Sarybchik */ 1756291436Sarybchik __checkReturn efx_rc_t 1757293756Sarybchikef10_nvram_partn_write_segment_tlv( 1758291432Sarybchik __in efx_nic_t *enp, 1759291432Sarybchik __in uint32_t partn, 1760291432Sarybchik __in uint32_t tag, 1761291432Sarybchik __in_bcount(size) caddr_t data, 1762291432Sarybchik __in size_t size, 1763291432Sarybchik __in boolean_t all_segments) 1764291432Sarybchik{ 1765291432Sarybchik size_t partn_size = 0; 1766283514Sarybchik caddr_t partn_data; 1767291432Sarybchik size_t total_length = 0; 1768291436Sarybchik efx_rc_t rc; 1769291432Sarybchik size_t current_offset = 0; 1770291432Sarybchik size_t remaining_original_length; 1771291432Sarybchik size_t remaining_modified_length; 1772291432Sarybchik caddr_t segment_data; 1773283514Sarybchik 1774283514Sarybchik EFSYS_ASSERT3U(partn, ==, NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG); 1775283514Sarybchik 1776283514Sarybchik /* Allocate sufficient memory for the entire partition */ 1777293756Sarybchik if ((rc = ef10_nvram_partn_size(enp, partn, &partn_size)) != 0) 1778283514Sarybchik goto fail1; 1779283514Sarybchik 1780283514Sarybchik EFSYS_KMEM_ALLOC(enp->en_esip, partn_size, partn_data); 1781283514Sarybchik if (partn_data == NULL) { 1782283514Sarybchik rc = ENOMEM; 1783283514Sarybchik goto fail2; 1784283514Sarybchik } 1785283514Sarybchik 1786291432Sarybchik remaining_original_length = partn_size; 1787291432Sarybchik remaining_modified_length = partn_size; 1788291432Sarybchik segment_data = partn_data; 1789291432Sarybchik 1790283514Sarybchik /* Lock the partition */ 1791293756Sarybchik if ((rc = ef10_nvram_partn_lock(enp, partn)) != 0) 1792283514Sarybchik goto fail3; 1793283514Sarybchik 1794291432Sarybchik /* Iterate over each (potential) segment to update it. */ 1795291432Sarybchik do { 1796291432Sarybchik boolean_t write = all_segments || current_offset == 0; 1797283514Sarybchik 1798293756Sarybchik rc = ef10_nvram_segment_write_tlv(enp, partn, tag, data, size, 1799291432Sarybchik &segment_data, ¤t_offset, &remaining_original_length, 1800291432Sarybchik &remaining_modified_length, write); 1801291432Sarybchik if (rc != 0) { 1802291432Sarybchik if (current_offset == 0) { 1803291432Sarybchik /* 1804291432Sarybchik * If no data has been read then the first 1805291432Sarybchik * segment is invalid, which is an error. 1806291432Sarybchik */ 1807291432Sarybchik goto fail4; 1808291432Sarybchik } 1809291432Sarybchik break; 1810291432Sarybchik } 1811291432Sarybchik } while (current_offset < partn_size); 1812291432Sarybchik 1813291432Sarybchik total_length = segment_data - partn_data; 1814291432Sarybchik 1815291432Sarybchik /* 1816291432Sarybchik * We've run out of space. This should actually be dealt with by 1817293756Sarybchik * ef10_nvram_buf_write_tlv returning ENOSPC. 1818291432Sarybchik */ 1819291432Sarybchik if (total_length > partn_size) { 1820291432Sarybchik rc = ENOSPC; 1821283514Sarybchik goto fail5; 1822291432Sarybchik } 1823283514Sarybchik 1824291432Sarybchik /* Erase the whole partition in NVRAM */ 1825293756Sarybchik if ((rc = ef10_nvram_partn_erase(enp, partn, 0, partn_size)) != 0) 1826283514Sarybchik goto fail6; 1827283514Sarybchik 1828291432Sarybchik /* Write new partition contents from the buffer to NVRAM */ 1829293756Sarybchik if ((rc = ef10_nvram_partn_write(enp, partn, 0, partn_data, 1830283514Sarybchik total_length)) != 0) 1831283514Sarybchik goto fail7; 1832283514Sarybchik 1833283514Sarybchik /* Unlock the partition */ 1834342511Sarybchik (void) ef10_nvram_partn_unlock(enp, partn, NULL); 1835283514Sarybchik 1836283514Sarybchik EFSYS_KMEM_FREE(enp->en_esip, partn_size, partn_data); 1837283514Sarybchik 1838283514Sarybchik return (0); 1839283514Sarybchik 1840283514Sarybchikfail7: 1841283514Sarybchik EFSYS_PROBE(fail7); 1842283514Sarybchikfail6: 1843283514Sarybchik EFSYS_PROBE(fail6); 1844283514Sarybchikfail5: 1845283514Sarybchik EFSYS_PROBE(fail5); 1846283514Sarybchikfail4: 1847283514Sarybchik EFSYS_PROBE(fail4); 1848283514Sarybchik 1849342511Sarybchik (void) ef10_nvram_partn_unlock(enp, partn, NULL); 1850283514Sarybchikfail3: 1851283514Sarybchik EFSYS_PROBE(fail3); 1852283514Sarybchik 1853283514Sarybchik EFSYS_KMEM_FREE(enp->en_esip, partn_size, partn_data); 1854283514Sarybchikfail2: 1855283514Sarybchik EFSYS_PROBE(fail2); 1856283514Sarybchikfail1: 1857291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 1858283514Sarybchik 1859283514Sarybchik return (rc); 1860283514Sarybchik} 1861283514Sarybchik 1862291432Sarybchik/* 1863291432Sarybchik * Get the size of a NVRAM partition. This is the total size allocated in nvram, 1864291432Sarybchik * not the data used by the segments in the partition. 1865291432Sarybchik */ 1866291436Sarybchik __checkReturn efx_rc_t 1867293756Sarybchikef10_nvram_partn_size( 1868283514Sarybchik __in efx_nic_t *enp, 1869293770Sarybchik __in uint32_t partn, 1870283514Sarybchik __out size_t *sizep) 1871283514Sarybchik{ 1872291436Sarybchik efx_rc_t rc; 1873283514Sarybchik 1874291746Sarybchik if ((rc = efx_mcdi_nvram_info(enp, partn, sizep, 1875291746Sarybchik NULL, NULL, NULL)) != 0) 1876283514Sarybchik goto fail1; 1877283514Sarybchik 1878283514Sarybchik return (0); 1879283514Sarybchik 1880283514Sarybchikfail1: 1881291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 1882283514Sarybchik 1883283514Sarybchik return (rc); 1884283514Sarybchik} 1885283514Sarybchik 1886291436Sarybchik __checkReturn efx_rc_t 1887293756Sarybchikef10_nvram_partn_lock( 1888283514Sarybchik __in efx_nic_t *enp, 1889293770Sarybchik __in uint32_t partn) 1890283514Sarybchik{ 1891291436Sarybchik efx_rc_t rc; 1892283514Sarybchik 1893283514Sarybchik if ((rc = efx_mcdi_nvram_update_start(enp, partn)) != 0) 1894283514Sarybchik goto fail1; 1895283514Sarybchik 1896283514Sarybchik return (0); 1897283514Sarybchik 1898283514Sarybchikfail1: 1899291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 1900283514Sarybchik 1901283514Sarybchik return (rc); 1902283514Sarybchik} 1903283514Sarybchik 1904291436Sarybchik __checkReturn efx_rc_t 1905294309Sarybchikef10_nvram_partn_read_mode( 1906283514Sarybchik __in efx_nic_t *enp, 1907293770Sarybchik __in uint32_t partn, 1908283514Sarybchik __in unsigned int offset, 1909283514Sarybchik __out_bcount(size) caddr_t data, 1910294309Sarybchik __in size_t size, 1911294309Sarybchik __in uint32_t mode) 1912283514Sarybchik{ 1913283514Sarybchik size_t chunk; 1914291436Sarybchik efx_rc_t rc; 1915283514Sarybchik 1916283514Sarybchik while (size > 0) { 1917293756Sarybchik chunk = MIN(size, EF10_NVRAM_CHUNK); 1918283514Sarybchik 1919283514Sarybchik if ((rc = efx_mcdi_nvram_read(enp, partn, offset, 1920294309Sarybchik data, chunk, mode)) != 0) { 1921283514Sarybchik goto fail1; 1922283514Sarybchik } 1923283514Sarybchik 1924283514Sarybchik size -= chunk; 1925283514Sarybchik data += chunk; 1926283514Sarybchik offset += chunk; 1927283514Sarybchik } 1928283514Sarybchik 1929283514Sarybchik return (0); 1930283514Sarybchik 1931283514Sarybchikfail1: 1932291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 1933283514Sarybchik 1934283514Sarybchik return (rc); 1935283514Sarybchik} 1936283514Sarybchik 1937291436Sarybchik __checkReturn efx_rc_t 1938294309Sarybchikef10_nvram_partn_read( 1939294309Sarybchik __in efx_nic_t *enp, 1940294309Sarybchik __in uint32_t partn, 1941294309Sarybchik __in unsigned int offset, 1942294309Sarybchik __out_bcount(size) caddr_t data, 1943294309Sarybchik __in size_t size) 1944294309Sarybchik{ 1945294309Sarybchik /* 1946294309Sarybchik * Read requests which come in through the EFX API expect to 1947294309Sarybchik * read the current, active partition. 1948294309Sarybchik */ 1949294309Sarybchik return ef10_nvram_partn_read_mode(enp, partn, offset, data, size, 1950294309Sarybchik MC_CMD_NVRAM_READ_IN_V2_TARGET_CURRENT); 1951294309Sarybchik} 1952294309Sarybchik 1953294309Sarybchik __checkReturn efx_rc_t 1954293756Sarybchikef10_nvram_partn_erase( 1955283514Sarybchik __in efx_nic_t *enp, 1956293770Sarybchik __in uint32_t partn, 1957283514Sarybchik __in unsigned int offset, 1958283514Sarybchik __in size_t size) 1959283514Sarybchik{ 1960291436Sarybchik efx_rc_t rc; 1961291862Sarybchik uint32_t erase_size; 1962283514Sarybchik 1963291862Sarybchik if ((rc = efx_mcdi_nvram_info(enp, partn, NULL, NULL, 1964291862Sarybchik &erase_size, NULL)) != 0) 1965283514Sarybchik goto fail1; 1966283514Sarybchik 1967291862Sarybchik if (erase_size == 0) { 1968291862Sarybchik if ((rc = efx_mcdi_nvram_erase(enp, partn, offset, size)) != 0) 1969291862Sarybchik goto fail2; 1970291862Sarybchik } else { 1971291862Sarybchik if (size % erase_size != 0) { 1972291862Sarybchik rc = EINVAL; 1973291862Sarybchik goto fail3; 1974291862Sarybchik } 1975291862Sarybchik while (size > 0) { 1976291862Sarybchik if ((rc = efx_mcdi_nvram_erase(enp, partn, offset, 1977291862Sarybchik erase_size)) != 0) 1978291862Sarybchik goto fail4; 1979291862Sarybchik offset += erase_size; 1980291862Sarybchik size -= erase_size; 1981291862Sarybchik } 1982291862Sarybchik } 1983291862Sarybchik 1984283514Sarybchik return (0); 1985283514Sarybchik 1986291862Sarybchikfail4: 1987291862Sarybchik EFSYS_PROBE(fail4); 1988291862Sarybchikfail3: 1989291862Sarybchik EFSYS_PROBE(fail3); 1990291862Sarybchikfail2: 1991291862Sarybchik EFSYS_PROBE(fail2); 1992283514Sarybchikfail1: 1993291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 1994283514Sarybchik 1995283514Sarybchik return (rc); 1996283514Sarybchik} 1997283514Sarybchik 1998291436Sarybchik __checkReturn efx_rc_t 1999293756Sarybchikef10_nvram_partn_write( 2000283514Sarybchik __in efx_nic_t *enp, 2001293770Sarybchik __in uint32_t partn, 2002283514Sarybchik __in unsigned int offset, 2003342512Sarybchik __in_bcount(size) caddr_t data, 2004283514Sarybchik __in size_t size) 2005283514Sarybchik{ 2006283514Sarybchik size_t chunk; 2007291923Sarybchik uint32_t write_size; 2008291436Sarybchik efx_rc_t rc; 2009283514Sarybchik 2010291923Sarybchik if ((rc = efx_mcdi_nvram_info(enp, partn, NULL, NULL, 2011291923Sarybchik NULL, &write_size)) != 0) 2012291923Sarybchik goto fail1; 2013291923Sarybchik 2014291923Sarybchik if (write_size != 0) { 2015291923Sarybchik /* 2016291923Sarybchik * Check that the size is a multiple of the write chunk size if 2017291923Sarybchik * the write chunk size is available. 2018291923Sarybchik */ 2019291923Sarybchik if (size % write_size != 0) { 2020291923Sarybchik rc = EINVAL; 2021291923Sarybchik goto fail2; 2022291923Sarybchik } 2023291923Sarybchik } else { 2024293756Sarybchik write_size = EF10_NVRAM_CHUNK; 2025291923Sarybchik } 2026291923Sarybchik 2027283514Sarybchik while (size > 0) { 2028291923Sarybchik chunk = MIN(size, write_size); 2029283514Sarybchik 2030283514Sarybchik if ((rc = efx_mcdi_nvram_write(enp, partn, offset, 2031283514Sarybchik data, chunk)) != 0) { 2032291923Sarybchik goto fail3; 2033283514Sarybchik } 2034283514Sarybchik 2035283514Sarybchik size -= chunk; 2036283514Sarybchik data += chunk; 2037283514Sarybchik offset += chunk; 2038283514Sarybchik } 2039283514Sarybchik 2040283514Sarybchik return (0); 2041283514Sarybchik 2042291923Sarybchikfail3: 2043291923Sarybchik EFSYS_PROBE(fail3); 2044291923Sarybchikfail2: 2045291923Sarybchik EFSYS_PROBE(fail2); 2046283514Sarybchikfail1: 2047291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 2048283514Sarybchik 2049283514Sarybchik return (rc); 2050283514Sarybchik} 2051283514Sarybchik 2052311495Sarybchik __checkReturn efx_rc_t 2053293756Sarybchikef10_nvram_partn_unlock( 2054283514Sarybchik __in efx_nic_t *enp, 2055311498Sarybchik __in uint32_t partn, 2056311498Sarybchik __out_opt uint32_t *resultp) 2057283514Sarybchik{ 2058311495Sarybchik boolean_t reboot = B_FALSE; 2059291436Sarybchik efx_rc_t rc; 2060283514Sarybchik 2061311498Sarybchik if (resultp != NULL) 2062311498Sarybchik *resultp = MC_CMD_NVRAM_VERIFY_RC_UNKNOWN; 2063311498Sarybchik 2064311498Sarybchik rc = efx_mcdi_nvram_update_finish(enp, partn, reboot, resultp); 2065311495Sarybchik if (rc != 0) 2066283514Sarybchik goto fail1; 2067283514Sarybchik 2068311495Sarybchik return (0); 2069283514Sarybchik 2070283514Sarybchikfail1: 2071291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 2072311495Sarybchik 2073311495Sarybchik return (rc); 2074283514Sarybchik} 2075283514Sarybchik 2076291436Sarybchik __checkReturn efx_rc_t 2077293756Sarybchikef10_nvram_partn_set_version( 2078283514Sarybchik __in efx_nic_t *enp, 2079293770Sarybchik __in uint32_t partn, 2080283514Sarybchik __in_ecount(4) uint16_t version[4]) 2081283514Sarybchik{ 2082283514Sarybchik struct tlv_partition_version partn_version; 2083283514Sarybchik size_t size; 2084291436Sarybchik efx_rc_t rc; 2085283514Sarybchik 2086283514Sarybchik /* Add or modify partition version TLV item */ 2087283514Sarybchik partn_version.version_w = __CPU_TO_LE_16(version[0]); 2088283514Sarybchik partn_version.version_x = __CPU_TO_LE_16(version[1]); 2089283514Sarybchik partn_version.version_y = __CPU_TO_LE_16(version[2]); 2090283514Sarybchik partn_version.version_z = __CPU_TO_LE_16(version[3]); 2091283514Sarybchik 2092283514Sarybchik size = sizeof (partn_version) - (2 * sizeof (uint32_t)); 2093283514Sarybchik 2094291432Sarybchik /* Write the version number to all segments in the partition */ 2095293756Sarybchik if ((rc = ef10_nvram_partn_write_segment_tlv(enp, 2096283514Sarybchik NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 2097283514Sarybchik TLV_TAG_PARTITION_VERSION(partn), 2098291432Sarybchik (caddr_t)&partn_version.version_w, size, B_TRUE)) != 0) 2099283514Sarybchik goto fail1; 2100283514Sarybchik 2101283514Sarybchik return (0); 2102283514Sarybchik 2103283514Sarybchikfail1: 2104291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 2105283514Sarybchik 2106283514Sarybchik return (rc); 2107283514Sarybchik} 2108283514Sarybchik 2109283514Sarybchik#endif /* EFSYS_OPT_VPD || EFSYS_OPT_NVRAM */ 2110283514Sarybchik 2111283514Sarybchik#if EFSYS_OPT_NVRAM 2112283514Sarybchik 2113293756Sarybchiktypedef struct ef10_parttbl_entry_s { 2114283514Sarybchik unsigned int partn; 2115283514Sarybchik unsigned int port; 2116283514Sarybchik efx_nvram_type_t nvtype; 2117293756Sarybchik} ef10_parttbl_entry_t; 2118283514Sarybchik 2119283514Sarybchik/* Translate EFX NVRAM types to firmware partition types */ 2120293768Sarybchikstatic ef10_parttbl_entry_t hunt_parttbl[] = { 2121283514Sarybchik {NVRAM_PARTITION_TYPE_MC_FIRMWARE, 1, EFX_NVRAM_MC_FIRMWARE}, 2122283514Sarybchik {NVRAM_PARTITION_TYPE_MC_FIRMWARE, 2, EFX_NVRAM_MC_FIRMWARE}, 2123283514Sarybchik {NVRAM_PARTITION_TYPE_MC_FIRMWARE, 3, EFX_NVRAM_MC_FIRMWARE}, 2124283514Sarybchik {NVRAM_PARTITION_TYPE_MC_FIRMWARE, 4, EFX_NVRAM_MC_FIRMWARE}, 2125283514Sarybchik {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP, 1, EFX_NVRAM_MC_GOLDEN}, 2126283514Sarybchik {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP, 2, EFX_NVRAM_MC_GOLDEN}, 2127283514Sarybchik {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP, 3, EFX_NVRAM_MC_GOLDEN}, 2128283514Sarybchik {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP, 4, EFX_NVRAM_MC_GOLDEN}, 2129283514Sarybchik {NVRAM_PARTITION_TYPE_EXPANSION_ROM, 1, EFX_NVRAM_BOOTROM}, 2130283514Sarybchik {NVRAM_PARTITION_TYPE_EXPANSION_ROM, 2, EFX_NVRAM_BOOTROM}, 2131283514Sarybchik {NVRAM_PARTITION_TYPE_EXPANSION_ROM, 3, EFX_NVRAM_BOOTROM}, 2132283514Sarybchik {NVRAM_PARTITION_TYPE_EXPANSION_ROM, 4, EFX_NVRAM_BOOTROM}, 2133283514Sarybchik {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT0, 1, EFX_NVRAM_BOOTROM_CFG}, 2134283514Sarybchik {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT1, 2, EFX_NVRAM_BOOTROM_CFG}, 2135283514Sarybchik {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT2, 3, EFX_NVRAM_BOOTROM_CFG}, 2136283514Sarybchik {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT3, 4, EFX_NVRAM_BOOTROM_CFG}, 2137283514Sarybchik {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 1, EFX_NVRAM_DYNAMIC_CFG}, 2138283514Sarybchik {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 2, EFX_NVRAM_DYNAMIC_CFG}, 2139283514Sarybchik {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 3, EFX_NVRAM_DYNAMIC_CFG}, 2140291587Sarybchik {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 4, EFX_NVRAM_DYNAMIC_CFG}, 2141291587Sarybchik {NVRAM_PARTITION_TYPE_FPGA, 1, EFX_NVRAM_FPGA}, 2142291587Sarybchik {NVRAM_PARTITION_TYPE_FPGA, 2, EFX_NVRAM_FPGA}, 2143291587Sarybchik {NVRAM_PARTITION_TYPE_FPGA, 3, EFX_NVRAM_FPGA}, 2144291587Sarybchik {NVRAM_PARTITION_TYPE_FPGA, 4, EFX_NVRAM_FPGA}, 2145291587Sarybchik {NVRAM_PARTITION_TYPE_FPGA_BACKUP, 1, EFX_NVRAM_FPGA_BACKUP}, 2146291587Sarybchik {NVRAM_PARTITION_TYPE_FPGA_BACKUP, 2, EFX_NVRAM_FPGA_BACKUP}, 2147291587Sarybchik {NVRAM_PARTITION_TYPE_FPGA_BACKUP, 3, EFX_NVRAM_FPGA_BACKUP}, 2148293900Sarybchik {NVRAM_PARTITION_TYPE_FPGA_BACKUP, 4, EFX_NVRAM_FPGA_BACKUP}, 2149293900Sarybchik {NVRAM_PARTITION_TYPE_LICENSE, 1, EFX_NVRAM_LICENSE}, 2150293900Sarybchik {NVRAM_PARTITION_TYPE_LICENSE, 2, EFX_NVRAM_LICENSE}, 2151293900Sarybchik {NVRAM_PARTITION_TYPE_LICENSE, 3, EFX_NVRAM_LICENSE}, 2152293900Sarybchik {NVRAM_PARTITION_TYPE_LICENSE, 4, EFX_NVRAM_LICENSE} 2153283514Sarybchik}; 2154283514Sarybchik 2155293768Sarybchikstatic ef10_parttbl_entry_t medford_parttbl[] = { 2156293768Sarybchik {NVRAM_PARTITION_TYPE_MC_FIRMWARE, 1, EFX_NVRAM_MC_FIRMWARE}, 2157293768Sarybchik {NVRAM_PARTITION_TYPE_MC_FIRMWARE, 2, EFX_NVRAM_MC_FIRMWARE}, 2158293768Sarybchik {NVRAM_PARTITION_TYPE_MC_FIRMWARE, 3, EFX_NVRAM_MC_FIRMWARE}, 2159293768Sarybchik {NVRAM_PARTITION_TYPE_MC_FIRMWARE, 4, EFX_NVRAM_MC_FIRMWARE}, 2160293768Sarybchik {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP, 1, EFX_NVRAM_MC_GOLDEN}, 2161293768Sarybchik {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP, 2, EFX_NVRAM_MC_GOLDEN}, 2162293768Sarybchik {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP, 3, EFX_NVRAM_MC_GOLDEN}, 2163293768Sarybchik {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP, 4, EFX_NVRAM_MC_GOLDEN}, 2164293768Sarybchik {NVRAM_PARTITION_TYPE_EXPANSION_ROM, 1, EFX_NVRAM_BOOTROM}, 2165293768Sarybchik {NVRAM_PARTITION_TYPE_EXPANSION_ROM, 2, EFX_NVRAM_BOOTROM}, 2166293768Sarybchik {NVRAM_PARTITION_TYPE_EXPANSION_ROM, 3, EFX_NVRAM_BOOTROM}, 2167293768Sarybchik {NVRAM_PARTITION_TYPE_EXPANSION_ROM, 4, EFX_NVRAM_BOOTROM}, 2168293768Sarybchik {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT0, 1, EFX_NVRAM_BOOTROM_CFG}, 2169293768Sarybchik {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT0, 2, EFX_NVRAM_BOOTROM_CFG}, 2170293768Sarybchik {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT0, 3, EFX_NVRAM_BOOTROM_CFG}, 2171293768Sarybchik {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT0, 4, EFX_NVRAM_BOOTROM_CFG}, 2172293768Sarybchik {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 1, EFX_NVRAM_DYNAMIC_CFG}, 2173293768Sarybchik {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 2, EFX_NVRAM_DYNAMIC_CFG}, 2174293768Sarybchik {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 3, EFX_NVRAM_DYNAMIC_CFG}, 2175293768Sarybchik {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 4, EFX_NVRAM_DYNAMIC_CFG}, 2176293768Sarybchik {NVRAM_PARTITION_TYPE_FPGA, 1, EFX_NVRAM_FPGA}, 2177293768Sarybchik {NVRAM_PARTITION_TYPE_FPGA, 2, EFX_NVRAM_FPGA}, 2178293768Sarybchik {NVRAM_PARTITION_TYPE_FPGA, 3, EFX_NVRAM_FPGA}, 2179293768Sarybchik {NVRAM_PARTITION_TYPE_FPGA, 4, EFX_NVRAM_FPGA}, 2180293768Sarybchik {NVRAM_PARTITION_TYPE_FPGA_BACKUP, 1, EFX_NVRAM_FPGA_BACKUP}, 2181293768Sarybchik {NVRAM_PARTITION_TYPE_FPGA_BACKUP, 2, EFX_NVRAM_FPGA_BACKUP}, 2182293768Sarybchik {NVRAM_PARTITION_TYPE_FPGA_BACKUP, 3, EFX_NVRAM_FPGA_BACKUP}, 2183293900Sarybchik {NVRAM_PARTITION_TYPE_FPGA_BACKUP, 4, EFX_NVRAM_FPGA_BACKUP}, 2184293900Sarybchik {NVRAM_PARTITION_TYPE_LICENSE, 1, EFX_NVRAM_LICENSE}, 2185293900Sarybchik {NVRAM_PARTITION_TYPE_LICENSE, 2, EFX_NVRAM_LICENSE}, 2186293900Sarybchik {NVRAM_PARTITION_TYPE_LICENSE, 3, EFX_NVRAM_LICENSE}, 2187311073Sarybchik {NVRAM_PARTITION_TYPE_LICENSE, 4, EFX_NVRAM_LICENSE}, 2188311073Sarybchik {NVRAM_PARTITION_TYPE_EXPANSION_UEFI, 1, EFX_NVRAM_UEFIROM}, 2189311073Sarybchik {NVRAM_PARTITION_TYPE_EXPANSION_UEFI, 2, EFX_NVRAM_UEFIROM}, 2190311073Sarybchik {NVRAM_PARTITION_TYPE_EXPANSION_UEFI, 3, EFX_NVRAM_UEFIROM}, 2191311073Sarybchik {NVRAM_PARTITION_TYPE_EXPANSION_UEFI, 4, EFX_NVRAM_UEFIROM} 2192293768Sarybchik}; 2193293768Sarybchik 2194293810Sarybchikstatic __checkReturn efx_rc_t 2195293810Sarybchikef10_parttbl_get( 2196283514Sarybchik __in efx_nic_t *enp, 2197293810Sarybchik __out ef10_parttbl_entry_t **parttblp, 2198293810Sarybchik __out size_t *parttbl_rowsp) 2199283514Sarybchik{ 2200293768Sarybchik switch (enp->en_family) { 2201293768Sarybchik case EFX_FAMILY_HUNTINGTON: 2202293810Sarybchik *parttblp = hunt_parttbl; 2203293810Sarybchik *parttbl_rowsp = EFX_ARRAY_SIZE(hunt_parttbl); 2204293768Sarybchik break; 2205283514Sarybchik 2206293768Sarybchik case EFX_FAMILY_MEDFORD: 2207293810Sarybchik *parttblp = medford_parttbl; 2208293810Sarybchik *parttbl_rowsp = EFX_ARRAY_SIZE(medford_parttbl); 2209293768Sarybchik break; 2210293768Sarybchik 2211293768Sarybchik default: 2212293768Sarybchik EFSYS_ASSERT(B_FALSE); 2213293810Sarybchik return (EINVAL); 2214283514Sarybchik } 2215293810Sarybchik return (0); 2216293810Sarybchik} 2217283514Sarybchik 2218293810Sarybchik __checkReturn efx_rc_t 2219293810Sarybchikef10_nvram_type_to_partn( 2220293810Sarybchik __in efx_nic_t *enp, 2221293810Sarybchik __in efx_nvram_type_t type, 2222293810Sarybchik __out uint32_t *partnp) 2223293810Sarybchik{ 2224293810Sarybchik efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 2225293810Sarybchik ef10_parttbl_entry_t *parttbl = NULL; 2226293810Sarybchik size_t parttbl_rows = 0; 2227293810Sarybchik unsigned int i; 2228293768Sarybchik 2229293810Sarybchik EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES); 2230293810Sarybchik EFSYS_ASSERT(partnp != NULL); 2231293810Sarybchik 2232293810Sarybchik if (ef10_parttbl_get(enp, &parttbl, &parttbl_rows) == 0) { 2233293810Sarybchik for (i = 0; i < parttbl_rows; i++) { 2234293810Sarybchik ef10_parttbl_entry_t *entry = &parttbl[i]; 2235293810Sarybchik 2236293810Sarybchik if (entry->nvtype == type && 2237293810Sarybchik entry->port == emip->emi_port) { 2238293810Sarybchik *partnp = entry->partn; 2239293810Sarybchik return (0); 2240293768Sarybchik } 2241293768Sarybchik } 2242293768Sarybchik } 2243293810Sarybchik 2244293810Sarybchik return (ENOTSUP); 2245283514Sarybchik} 2246283514Sarybchik 2247294258Sarybchik#if EFSYS_OPT_DIAG 2248283514Sarybchik 2249293810Sarybchikstatic __checkReturn efx_rc_t 2250293810Sarybchikef10_nvram_partn_to_type( 2251293810Sarybchik __in efx_nic_t *enp, 2252293810Sarybchik __in uint32_t partn, 2253293810Sarybchik __out efx_nvram_type_t *typep) 2254293810Sarybchik{ 2255293810Sarybchik efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 2256293810Sarybchik ef10_parttbl_entry_t *parttbl = NULL; 2257293810Sarybchik size_t parttbl_rows = 0; 2258293810Sarybchik unsigned int i; 2259293810Sarybchik 2260293810Sarybchik EFSYS_ASSERT(typep != NULL); 2261293810Sarybchik 2262293810Sarybchik if (ef10_parttbl_get(enp, &parttbl, &parttbl_rows) == 0) { 2263293810Sarybchik for (i = 0; i < parttbl_rows; i++) { 2264293810Sarybchik ef10_parttbl_entry_t *entry = &parttbl[i]; 2265293810Sarybchik 2266293810Sarybchik if (entry->partn == partn && 2267293810Sarybchik entry->port == emip->emi_port) { 2268293810Sarybchik *typep = entry->nvtype; 2269293810Sarybchik return (0); 2270293810Sarybchik } 2271293810Sarybchik } 2272293810Sarybchik } 2273293810Sarybchik 2274293810Sarybchik return (ENOTSUP); 2275293810Sarybchik} 2276293810Sarybchik 2277291436Sarybchik __checkReturn efx_rc_t 2278293756Sarybchikef10_nvram_test( 2279283514Sarybchik __in efx_nic_t *enp) 2280283514Sarybchik{ 2281293810Sarybchik efx_nvram_type_t type; 2282283514Sarybchik unsigned int npartns = 0; 2283283514Sarybchik uint32_t *partns = NULL; 2284283514Sarybchik size_t size; 2285293768Sarybchik unsigned int i; 2286291436Sarybchik efx_rc_t rc; 2287283514Sarybchik 2288293810Sarybchik /* Read available partitions from NVRAM partition map */ 2289283514Sarybchik size = MC_CMD_NVRAM_PARTITIONS_OUT_TYPE_ID_MAXNUM * sizeof (uint32_t); 2290283514Sarybchik EFSYS_KMEM_ALLOC(enp->en_esip, size, partns); 2291283514Sarybchik if (partns == NULL) { 2292283514Sarybchik rc = ENOMEM; 2293283514Sarybchik goto fail1; 2294283514Sarybchik } 2295283514Sarybchik 2296283514Sarybchik if ((rc = efx_mcdi_nvram_partitions(enp, (caddr_t)partns, size, 2297283514Sarybchik &npartns)) != 0) { 2298283514Sarybchik goto fail2; 2299283514Sarybchik } 2300283514Sarybchik 2301293810Sarybchik for (i = 0; i < npartns; i++) { 2302293810Sarybchik /* Check if the partition is supported for this port */ 2303293810Sarybchik if ((rc = ef10_nvram_partn_to_type(enp, partns[i], &type)) != 0) 2304283514Sarybchik continue; 2305283514Sarybchik 2306293810Sarybchik if ((rc = efx_mcdi_nvram_test(enp, partns[i])) != 0) 2307293810Sarybchik goto fail3; 2308283514Sarybchik } 2309283514Sarybchik 2310283514Sarybchik EFSYS_KMEM_FREE(enp->en_esip, size, partns); 2311283514Sarybchik return (0); 2312283514Sarybchik 2313283514Sarybchikfail3: 2314283514Sarybchik EFSYS_PROBE(fail3); 2315283514Sarybchikfail2: 2316283514Sarybchik EFSYS_PROBE(fail2); 2317283514Sarybchik EFSYS_KMEM_FREE(enp->en_esip, size, partns); 2318283514Sarybchikfail1: 2319291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 2320283514Sarybchik return (rc); 2321283514Sarybchik} 2322283514Sarybchik 2323283514Sarybchik#endif /* EFSYS_OPT_DIAG */ 2324283514Sarybchik 2325291436Sarybchik __checkReturn efx_rc_t 2326294251Sarybchikef10_nvram_partn_get_version( 2327283514Sarybchik __in efx_nic_t *enp, 2328294251Sarybchik __in uint32_t partn, 2329283514Sarybchik __out uint32_t *subtypep, 2330283514Sarybchik __out_ecount(4) uint16_t version[4]) 2331283514Sarybchik{ 2332291436Sarybchik efx_rc_t rc; 2333283514Sarybchik 2334283514Sarybchik /* FIXME: get highest partn version from all ports */ 2335283514Sarybchik /* FIXME: return partn description if available */ 2336283514Sarybchik 2337283514Sarybchik if ((rc = efx_mcdi_nvram_metadata(enp, partn, subtypep, 2338283514Sarybchik version, NULL, 0)) != 0) 2339294251Sarybchik goto fail1; 2340283514Sarybchik 2341283514Sarybchik return (0); 2342283514Sarybchik 2343283514Sarybchikfail1: 2344291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 2345283514Sarybchik 2346283514Sarybchik return (rc); 2347283514Sarybchik} 2348283514Sarybchik 2349291436Sarybchik __checkReturn efx_rc_t 2350294080Sarybchikef10_nvram_partn_rw_start( 2351283514Sarybchik __in efx_nic_t *enp, 2352294080Sarybchik __in uint32_t partn, 2353283514Sarybchik __out size_t *chunk_sizep) 2354283514Sarybchik{ 2355291436Sarybchik efx_rc_t rc; 2356283514Sarybchik 2357294080Sarybchik if ((rc = ef10_nvram_partn_lock(enp, partn)) != 0) 2358283514Sarybchik goto fail1; 2359283514Sarybchik 2360283514Sarybchik if (chunk_sizep != NULL) 2361293756Sarybchik *chunk_sizep = EF10_NVRAM_CHUNK; 2362283514Sarybchik 2363283514Sarybchik return (0); 2364283514Sarybchik 2365283514Sarybchikfail1: 2366291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 2367283514Sarybchik 2368283514Sarybchik return (rc); 2369283514Sarybchik} 2370283514Sarybchik 2371311495Sarybchik __checkReturn efx_rc_t 2372294250Sarybchikef10_nvram_partn_rw_finish( 2373283514Sarybchik __in efx_nic_t *enp, 2374294250Sarybchik __in uint32_t partn) 2375283514Sarybchik{ 2376311495Sarybchik efx_rc_t rc; 2377311495Sarybchik 2378311498Sarybchik if ((rc = ef10_nvram_partn_unlock(enp, partn, NULL)) != 0) 2379311495Sarybchik goto fail1; 2380311495Sarybchik 2381311495Sarybchik return (0); 2382311495Sarybchik 2383311495Sarybchikfail1: 2384311495Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 2385311495Sarybchik 2386311495Sarybchik return (rc); 2387283514Sarybchik} 2388283514Sarybchik 2389283514Sarybchik#endif /* EFSYS_OPT_NVRAM */ 2390283514Sarybchik 2391299602Sarybchik#endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ 2392