1 #include "config.h"
2 
3 #include "reader_impl.hpp"
4 
5 #include "utils.hpp"
6 
7 #include <algorithm>
8 #include <com/ibm/VPD/error.hpp>
9 #include <map>
10 #include <phosphor-logging/elog-errors.hpp>
11 #include <vector>
12 #include <xyz/openbmc_project/Common/error.hpp>
13 
14 #ifdef ManagerTest
15 #include "reader_test.hpp"
16 #endif
17 
18 namespace openpower
19 {
20 namespace vpd
21 {
22 namespace manager
23 {
24 namespace reader
25 {
26 
27 using namespace phosphor::logging;
28 using namespace openpower::vpd::inventory;
29 using namespace openpower::vpd::constants;
30 using namespace openpower::vpd::utils::interface;
31 
32 using InvalidArgument =
33     sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument;
34 using Argument = xyz::openbmc_project::Common::InvalidArgument;
35 using LocationNotFound = sdbusplus::com::ibm::VPD::Error::LocationNotFound;
36 
37 bool ReaderImpl::isValidLocationCode(const LocationCode& locationCode) const
38 {
39     if ((locationCode.length() < UNEXP_LOCATION_CODE_MIN_LENGTH) ||
40         (locationCode[0] != 'U') ||
41         ((locationCode.find("fcs", 1, 3) == std::string::npos) &&
42          (locationCode.find("mts", 1, 3) == std::string::npos)))
43     {
44         return false;
45     }
46 
47     return true;
48 }
49 
50 LocationCode ReaderImpl::getExpandedLocationCode(
51     const LocationCode& locationCode, const NodeNumber& nodeNumber,
52     const LocationCodeMap& frusLocationCode) const
53 {
54     // unused at this moment. Hence to avoid warnings
55     (void)nodeNumber;
56     if (!isValidLocationCode(locationCode))
57     {
58         // argument is not valid
59         elog<InvalidArgument>(Argument::ARGUMENT_NAME("LOCATIONCODE"),
60                               Argument::ARGUMENT_VALUE(locationCode.c_str()));
61     }
62     auto iterator = frusLocationCode.find(locationCode);
63     if (iterator == frusLocationCode.end())
64     {
65         // TODO: Implementation of error logic till then throwing invalid
66         // argument
67         // the location code was not found in the system
68         // elog<LocationNotFound>();
69         elog<InvalidArgument>(Argument::ARGUMENT_NAME("LOCATIONCODE"),
70                               Argument::ARGUMENT_VALUE(locationCode.c_str()));
71     }
72 
73     std::string expandedLocationCode{};
74 #ifndef ManagerTest
75     utility utilObj;
76 #endif
77     expandedLocationCode = utilObj.readBusProperty(
78         iterator->second, LOCATION_CODE_INF, "LocationCode");
79     return expandedLocationCode;
80 }
81 
82 ListOfPaths
83     ReaderImpl::getFrusAtLocation(const LocationCode& locationCode,
84                                   const NodeNumber& nodeNumber,
85                                   const LocationCodeMap& frusLocationCode) const
86 {
87     // unused at this moment, to avoid compilation warning
88     (void)nodeNumber;
89 
90     // TODO:Implementation related to node number
91     if (!isValidLocationCode(locationCode))
92     {
93         // argument is not valid
94         elog<InvalidArgument>(Argument::ARGUMENT_NAME("LOCATIONCODE"),
95                               Argument::ARGUMENT_VALUE(locationCode.c_str()));
96     }
97 
98     auto range = frusLocationCode.equal_range(locationCode);
99 
100     if (range.first == frusLocationCode.end())
101     {
102         // TODO: Implementation of error logic till then throwing invalid
103         // argument
104         // the location code was not found in the system
105         // elog<LocationNotFound>();
106         elog<InvalidArgument>(Argument::ARGUMENT_NAME("LOCATIONCODE"),
107                               Argument::ARGUMENT_VALUE(locationCode.c_str()));
108     }
109 
110     ListOfPaths inventoryPaths;
111 
112     for_each(range.first, range.second,
113              [&inventoryPaths](
114                  const inventory::LocationCodeMap::value_type& mappedItem) {
115                  inventoryPaths.push_back(INVENTORY_PATH + mappedItem.second);
116              });
117     return inventoryPaths;
118 }
119 
120 std::tuple<LocationCode, NodeNumber>
121     ReaderImpl::getCollapsedLocationCode(const LocationCode& locationCode) const
122 {
123     // Location code should always start with U and fulfil minimum length
124     // criteria.
125     if (locationCode[0] != 'U' ||
126         locationCode.length() < EXP_LOCATIN_CODE_MIN_LENGTH)
127     {
128         elog<InvalidArgument>(Argument::ARGUMENT_NAME("LOCATIONCODE"),
129                               Argument::ARGUMENT_VALUE(locationCode.c_str()));
130     }
131 
132     std::string fc{};
133 #ifndef ManagerTest
134     utility utilObj;
135 #endif
136 
137     fc = utilObj.readBusProperty(SYSTEM_OBJECT, "com.ibm.ipzvpd.VCEN", "FC");
138 
139     // get the first part of expanded location code to check for FC or TM
140     std::string firstKeyword = locationCode.substr(1, 4);
141 
142     LocationCode unexpandedLocationCode{};
143     NodeNumber nodeNummber = INVALID_NODE_NUMBER;
144 
145     // check if this value matches the value of FC kwd
146     if (fc.substr(0, 4) ==
147         firstKeyword) // implies this is Ufcs format location code
148     {
149         // period(.) should be there in expanded location code to seggregate FC,
150         // Node number and SE values.
151         size_t nodeStartPos = locationCode.find('.');
152         if (nodeStartPos == std::string::npos)
153         {
154             elog<InvalidArgument>(
155                 Argument::ARGUMENT_NAME("LOCATIONCODE"),
156                 Argument::ARGUMENT_VALUE(locationCode.c_str()));
157         }
158 
159         // second period(.) should be there to end the node details in non
160         // system location code
161         size_t nodeEndPos = locationCode.find('.', nodeStartPos + 1);
162         if (nodeEndPos == std::string::npos)
163         {
164             elog<InvalidArgument>(
165                 Argument::ARGUMENT_NAME("LOCATIONCODE"),
166                 Argument::ARGUMENT_VALUE(locationCode.c_str()));
167         }
168 
169         // skip 3 for '.ND'
170         nodeNummber = std::stoi(locationCode.substr(
171             nodeStartPos + 3, (nodeEndPos - nodeStartPos - 3)));
172 
173         // confirm if there are other details apart FC, Node number and SE in
174         // location code
175         if (locationCode.length() > EXP_LOCATIN_CODE_MIN_LENGTH)
176         {
177             unexpandedLocationCode =
178                 locationCode[0] + (std::string) "fcs" +
179                 locationCode.substr(nodeEndPos + 1 + SE_KWD_LENGTH,
180                                     std::string::npos);
181         }
182         else
183         {
184             unexpandedLocationCode = "Ufcs";
185         }
186     }
187     else
188     {
189         std::string tm{};
190         // read TM kwd value
191         tm =
192             utilObj.readBusProperty(SYSTEM_OBJECT, "com.ibm.ipzvpd.VSYS", "TM");
193         ;
194 
195         // check if the substr matches to TM kwd
196         if (tm.substr(0, 4) ==
197             firstKeyword) // implies this is Umts format of location code
198         {
199             // system location code will not have any other details and node
200             // number
201             unexpandedLocationCode = "Umts";
202         }
203         // it does not belong to either "fcs" or "mts"
204         else
205         {
206             elog<InvalidArgument>(
207                 Argument::ARGUMENT_NAME("LOCATIONCODE"),
208                 Argument::ARGUMENT_VALUE(locationCode.c_str()));
209         }
210     }
211 
212     return std::make_tuple(unexpandedLocationCode, nodeNummber);
213 }
214 
215 ListOfPaths ReaderImpl::getFRUsByExpandedLocationCode(
216     const inventory::LocationCode& locationCode,
217     const inventory::LocationCodeMap& frusLocationCode) const
218 {
219     std::tuple<LocationCode, NodeNumber> locationAndNodePair =
220         getCollapsedLocationCode(locationCode);
221 
222     return getFrusAtLocation(std::get<0>(locationAndNodePair),
223                              std::get<1>(locationAndNodePair),
224                              frusLocationCode);
225 }
226 } // namespace reader
227 } // namespace manager
228 } // namespace vpd
229 } // namespace openpower
230