1 /*- 2 * Copyright (c) 2017 Broadcom. All rights reserved. 3 * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * 3. Neither the name of the copyright holder nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 * 31 * $FreeBSD$ 32 */ 33 34 /** 35 * @file 36 * OCS VPD parser 37 */ 38 39 #if !defined(__OCS_VPD_H__) 40 #define __OCS_VPD_H__ 41 42 /** 43 * @brief VPD buffer structure 44 */ 45 46 typedef struct { 47 uint8_t *buffer; 48 uint32_t length; 49 uint32_t offset; 50 uint8_t checksum; 51 } vpdbuf_t; 52 53 /** 54 * @brief return next VPD byte 55 * 56 * Returns next VPD byte and updates accumulated checksum 57 * 58 * @param vpd pointer to vpd buffer 59 * 60 * @return returns next byte for success, or a negative error code value for failure. 61 * 62 */ 63 64 static inline int 65 vpdnext(vpdbuf_t *vpd) 66 { 67 int rc = -1; 68 if (vpd->offset < vpd->length) { 69 rc = vpd->buffer[vpd->offset++]; 70 vpd->checksum += rc; 71 } 72 return rc; 73 } 74 75 /** 76 * @brief return true if no more vpd buffer data 77 * 78 * return true if the vpd buffer data has been completely consumed 79 * 80 * @param vpd pointer to vpd buffer 81 * 82 * @return returns true if no more data 83 * 84 */ 85 static inline int 86 vpddone(vpdbuf_t *vpd) 87 { 88 return vpd->offset >= vpd->length; 89 } 90 /** 91 * @brief return pointer to current VPD data location 92 * 93 * Returns a pointer to the current location in the VPD data 94 * 95 * @param vpd pointer to vpd buffer 96 * 97 * @return pointer to current VPD data location 98 */ 99 100 static inline uint8_t * 101 vpdref(vpdbuf_t *vpd) 102 { 103 return &vpd->buffer[vpd->offset]; 104 } 105 106 #define VPD_LARGE_RESOURCE_TYPE_ID_STRING_TAG 0x82 107 #define VPD_LARGE_RESOURCE_TYPE_R_TAG 0x90 108 #define VPD_LARGE_RESOURCE_TYPE_W_TAG 0x91 109 #define VPD_SMALL_RESOURCE_TYPE_END_TAG 0x78 110 111 /** 112 * @brief find a VPD entry 113 * 114 * Finds a VPD entry given the two character code 115 * 116 * @param vpddata pointer to raw vpd data buffer 117 * @param vpddata_length length of vpddata buffer in bytes 118 * @param key key to look up 119 120 * @return returns a pointer to the key location or NULL if not found or checksum error 121 */ 122 123 static inline uint8_t * 124 ocs_find_vpd(uint8_t *vpddata, uint32_t vpddata_length, const char *key) 125 { 126 vpdbuf_t vpdbuf; 127 uint8_t *pret = NULL; 128 uint8_t c0 = key[0]; 129 uint8_t c1 = key[1]; 130 131 vpdbuf.buffer = (uint8_t*) vpddata; 132 vpdbuf.length = vpddata_length; 133 vpdbuf.offset = 0; 134 vpdbuf.checksum = 0; 135 136 while (!vpddone(&vpdbuf)) { 137 int type = vpdnext(&vpdbuf); 138 int len_lo; 139 int len_hi; 140 int len; 141 int i; 142 143 if (type == VPD_SMALL_RESOURCE_TYPE_END_TAG) { 144 break; 145 } 146 147 len_lo = vpdnext(&vpdbuf); 148 len_hi = vpdnext(&vpdbuf); 149 len = len_lo + (len_hi << 8); 150 151 if ((type == VPD_LARGE_RESOURCE_TYPE_R_TAG) || (type == VPD_LARGE_RESOURCE_TYPE_W_TAG)) { 152 while (len > 0) { 153 int rc0; 154 int rc1; 155 int sublen; 156 uint8_t *pstart; 157 158 rc0 = vpdnext(&vpdbuf); 159 rc1 = vpdnext(&vpdbuf); 160 161 /* Mark this location */ 162 pstart = vpdref(&vpdbuf); 163 164 sublen = vpdnext(&vpdbuf); 165 166 /* Adjust remaining len */ 167 len -= (sublen + 3); 168 169 /* check for match with request */ 170 if ((c0 == rc0) && (c1 == rc1)) { 171 pret = pstart; 172 for (i = 0; i < sublen; i++) { 173 vpdnext(&vpdbuf); 174 } 175 /* check for "RV" end */ 176 } else if ('R' == rc0 && 'V' == rc1) { 177 /* Read the checksum */ 178 for (i = 0; i < sublen; i++) { 179 vpdnext(&vpdbuf); 180 } 181 182 /* The accumulated checksum should be zero here */ 183 if (vpdbuf.checksum != 0) { 184 ocs_log_test(NULL, "checksum error\n"); 185 return NULL; 186 } 187 } 188 else 189 for (i = 0; i < sublen; i++) { 190 vpdnext(&vpdbuf); 191 } 192 } 193 } 194 195 for (i = 0; i < len; i++) { 196 vpdnext(&vpdbuf); 197 } 198 } 199 200 return pret; 201 } 202 #endif 203