]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/ocs_fc/ocs_vpd.h
MFV r360158:
[FreeBSD/FreeBSD.git] / sys / dev / ocs_fc / ocs_vpd.h
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
178                                         /* Read the checksum */
179                                         for (i = 0; i < sublen; i++) {
180                                                 vpdnext(&vpdbuf);
181                                         }
182
183                                         /* The accumulated checksum should be zero here */
184                                         if (vpdbuf.checksum != 0) {
185                                                 ocs_log_test(NULL, "checksum error\n");
186                                                 return NULL;
187                                         }
188                                 }
189                                 else
190                                         for (i = 0; i < sublen; i++) {
191                                                 vpdnext(&vpdbuf);
192                                         }
193                         }
194                 }
195
196                 for (i = 0; i < len; i++) {
197                         vpdnext(&vpdbuf);
198                 }
199         }
200
201         return pret;
202 }
203 #endif