xref: /freebsd/sys/dev/ocs_fc/ocs_vpd.h (revision 4e579ad047720775ab580b74192c7de8a3386fea)
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 
32 /**
33  * @file
34  * OCS VPD parser
35  */
36 
37 #if !defined(__OCS_VPD_H__)
38 #define __OCS_VPD_H__
39 
40 /**
41  * @brief VPD buffer structure
42  */
43 
44 typedef struct {
45 	uint8_t *buffer;
46 	uint32_t length;
47 	uint32_t offset;
48 	uint8_t checksum;
49 	} vpdbuf_t;
50 
51 /**
52  * @brief return next VPD byte
53  *
54  * Returns next VPD byte and updates accumulated checksum
55  *
56  * @param vpd pointer to vpd buffer
57  *
58  * @return returns next byte for success, or a negative error code value for failure.
59  *
60  */
61 
62 static inline int
63 vpdnext(vpdbuf_t *vpd)
64 {
65 	int rc = -1;
66 	if (vpd->offset < vpd->length) {
67 		rc = vpd->buffer[vpd->offset++];
68 		vpd->checksum += rc;
69 	}
70 	return rc;
71 }
72 
73 /**
74  * @brief return true if no more vpd buffer data
75  *
76  * return true if the vpd buffer data has been completely consumed
77  *
78  * @param vpd pointer to vpd buffer
79  *
80  * @return returns true if no more data
81  *
82  */
83 static inline int
84 vpddone(vpdbuf_t *vpd)
85 {
86 	return vpd->offset >= vpd->length;
87 }
88 /**
89  * @brief return pointer to current VPD data location
90  *
91  * Returns a pointer to the current location in the VPD data
92  *
93  * @param vpd pointer to vpd buffer
94  *
95  * @return pointer to current VPD data location
96  */
97 
98 static inline uint8_t *
99 vpdref(vpdbuf_t *vpd)
100 {
101 	return &vpd->buffer[vpd->offset];
102 }
103 
104 #define VPD_LARGE_RESOURCE_TYPE_ID_STRING_TAG	0x82
105 #define VPD_LARGE_RESOURCE_TYPE_R_TAG		0x90
106 #define VPD_LARGE_RESOURCE_TYPE_W_TAG		0x91
107 #define VPD_SMALL_RESOURCE_TYPE_END_TAG		0x78
108 
109 /**
110  * @brief find a VPD entry
111  *
112  * Finds a VPD entry given the two character code
113  *
114  * @param vpddata pointer to raw vpd data buffer
115  * @param vpddata_length length of vpddata buffer in bytes
116  * @param key key to look up
117 
118  * @return returns a pointer to the key location or NULL if not found or checksum error
119  */
120 
121 static inline uint8_t *
122 ocs_find_vpd(uint8_t *vpddata, uint32_t vpddata_length, const char *key)
123 {
124 	vpdbuf_t vpdbuf;
125 	uint8_t *pret = NULL;
126 	uint8_t c0 = key[0];
127 	uint8_t c1 = key[1];
128 
129 	vpdbuf.buffer = (uint8_t*) vpddata;
130 	vpdbuf.length = vpddata_length;
131 	vpdbuf.offset = 0;
132 	vpdbuf.checksum = 0;
133 
134 	while (!vpddone(&vpdbuf)) {
135 		int type = vpdnext(&vpdbuf);
136 		int len_lo;
137 		int len_hi;
138 		int len;
139 		int i;
140 
141 		if (type == VPD_SMALL_RESOURCE_TYPE_END_TAG) {
142 			break;
143 		}
144 
145 		len_lo = vpdnext(&vpdbuf);
146 		len_hi = vpdnext(&vpdbuf);
147 		len = len_lo + (len_hi << 8);
148 
149 		if ((type == VPD_LARGE_RESOURCE_TYPE_R_TAG) || (type == VPD_LARGE_RESOURCE_TYPE_W_TAG)) {
150 			while (len > 0) {
151 				int rc0;
152 				int rc1;
153 				int sublen;
154 				uint8_t *pstart;
155 
156 				rc0 = vpdnext(&vpdbuf);
157 				rc1 = vpdnext(&vpdbuf);
158 
159 				/* Mark this location */
160 				pstart = vpdref(&vpdbuf);
161 
162 				sublen = vpdnext(&vpdbuf);
163 
164 				/* Adjust remaining len */
165 				len -= (sublen + 3);
166 
167 				/* check for match with request */
168 				if ((c0 == rc0) && (c1 == rc1)) {
169 					pret = pstart;
170 					for (i = 0; i < sublen; i++) {
171 						vpdnext(&vpdbuf);
172 					}
173 				/* check for "RV" end */
174 				} else if ('R' == rc0 && 'V' == rc1) {
175 					/* Read the checksum */
176 					for (i = 0; i < sublen; i++) {
177 						vpdnext(&vpdbuf);
178 					}
179 
180 					/* The accumulated checksum should be zero here */
181 					if (vpdbuf.checksum != 0) {
182 						ocs_log_test(NULL, "checksum error\n");
183 						return NULL;
184 					}
185 				}
186 				else
187 					for (i = 0; i < sublen; i++) {
188 						vpdnext(&vpdbuf);
189 					}
190 			}
191 		}
192 
193 		for (i = 0; i < len; i++) {
194 			vpdnext(&vpdbuf);
195 		}
196 	}
197 
198 	return pret;
199 }
200 #endif
201