1 package org.metricshub.ipmi.core.coding.commands.fru;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 import org.metricshub.ipmi.core.coding.commands.CommandCodes;
26 import org.metricshub.ipmi.core.coding.commands.IpmiCommandCoder;
27 import org.metricshub.ipmi.core.coding.commands.IpmiVersion;
28 import org.metricshub.ipmi.core.coding.commands.ResponseData;
29 import org.metricshub.ipmi.core.coding.commands.fru.record.BoardInfo;
30 import org.metricshub.ipmi.core.coding.commands.fru.record.ChassisInfo;
31 import org.metricshub.ipmi.core.coding.commands.fru.record.FruRecord;
32 import org.metricshub.ipmi.core.coding.commands.fru.record.MultiRecordInfo;
33 import org.metricshub.ipmi.core.coding.commands.fru.record.ProductInfo;
34 import org.metricshub.ipmi.core.coding.commands.sdr.GetSdr;
35 import org.metricshub.ipmi.core.coding.commands.sdr.record.FruDeviceLocatorRecord;
36 import org.metricshub.ipmi.core.coding.payload.CompletionCode;
37 import org.metricshub.ipmi.core.coding.payload.IpmiPayload;
38 import org.metricshub.ipmi.core.coding.payload.lan.IPMIException;
39 import org.metricshub.ipmi.core.coding.payload.lan.IpmiLanRequest;
40 import org.metricshub.ipmi.core.coding.payload.lan.IpmiLanResponse;
41 import org.metricshub.ipmi.core.coding.payload.lan.NetworkFunction;
42 import org.metricshub.ipmi.core.coding.protocol.AuthenticationType;
43 import org.metricshub.ipmi.core.coding.protocol.IpmiMessage;
44 import org.metricshub.ipmi.core.coding.security.CipherSuite;
45 import org.metricshub.ipmi.core.common.TypeConverter;
46
47 import java.security.InvalidKeyException;
48 import java.security.NoSuchAlgorithmException;
49 import java.util.ArrayList;
50 import java.util.List;
51
52
53
54
55
56 public class ReadFruData extends IpmiCommandCoder {
57
58 private int offset;
59
60 private int size;
61
62 private int fruId;
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82 public ReadFruData(int fruId, BaseUnit unit, int offset, int countToRead) {
83 super();
84
85 if (countToRead > 255) {
86 throw new IllegalArgumentException(
87 "Count to read cannot exceed 255");
88 }
89
90 if (fruId > 255) {
91 throw new IllegalArgumentException("FRU ID cannot exceed 255");
92 }
93
94 this.offset = offset * unit.getSize();
95
96 size = countToRead * unit.getSize();
97
98 this.fruId = fruId;
99
100
101 }
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125 public ReadFruData(IpmiVersion version, CipherSuite cipherSuite,
126 AuthenticationType authenticationType, int fruId, BaseUnit unit,
127 int offset, int countToRead) {
128 super(version, cipherSuite, authenticationType);
129
130 if (countToRead > 255) {
131 throw new IllegalArgumentException(
132 "Count to read cannot exceed 255");
133 }
134
135 if (fruId > 255) {
136 throw new IllegalArgumentException("FRU ID cannot exceed 255");
137 }
138
139 this.offset = offset * unit.getSize();
140
141 size = countToRead * unit.getSize();
142
143 this.fruId = fruId;
144
145
146 }
147
148 @Override
149 public byte getCommandCode() {
150 return CommandCodes.READ_FRU_DATA;
151 }
152
153 @Override
154 public NetworkFunction getNetworkFunction() {
155 return NetworkFunction.StorageRequest;
156 }
157
158 @Override
159 protected IpmiPayload preparePayload(int sequenceNumber)
160 throws NoSuchAlgorithmException, InvalidKeyException {
161 byte[] payload = new byte[4];
162 payload[0] = TypeConverter.intToByte(fruId);
163 byte[] buffer = TypeConverter.intToLittleEndianByteArray(offset);
164 payload[1] = buffer[0];
165 payload[2] = buffer[1];
166 payload[3] = TypeConverter.intToByte(size);
167
168 return new IpmiLanRequest(getNetworkFunction(), getCommandCode(),
169 payload, TypeConverter.intToByte(sequenceNumber));
170 }
171
172 @Override
173 public ResponseData getResponseData(IpmiMessage message) throws IPMIException, NoSuchAlgorithmException, InvalidKeyException {
174
175 if (!isCommandResponse(message)) {
176 throw new IllegalArgumentException(
177 "This is not a response for Get SDR Repository Info command");
178 }
179 if (!(message.getPayload() instanceof IpmiLanResponse)) {
180 throw new IllegalArgumentException("Invalid response payload");
181 }
182 if (((IpmiLanResponse) message.getPayload()).getCompletionCode() != CompletionCode.Ok) {
183 throw new IPMIException(
184 ((IpmiLanResponse) message.getPayload())
185 .getCompletionCode());
186 }
187
188 byte[] raw = message.getPayload().getIpmiCommandData();
189
190 if (raw == null || raw.length < 2) {
191 throw new IllegalArgumentException(
192 "Invalid response payload length");
193 }
194
195 ReadFruDataResponseData responseData = new ReadFruDataResponseData();
196
197 int sizeFromResponse = TypeConverter.byteToInt(raw[0]);
198
199 byte[] fruData = new byte[sizeFromResponse];
200
201 System.arraycopy(raw, 1, fruData, 0, sizeFromResponse);
202
203 responseData.setFruData(fruData);
204
205 return responseData;
206 }
207
208
209
210
211
212
213
214
215
216
217
218 @SuppressWarnings("unused")
219 public static List<FruRecord> decodeFruData(
220 List<ReadFruDataResponseData> fruData) {
221
222 int size = 0;
223
224 ArrayList<FruRecord> list = new ArrayList<FruRecord>();
225
226 for (ReadFruDataResponseData responseData : fruData) {
227 size += responseData.getFruData().length;
228 }
229
230 byte[] data = new byte[size];
231
232 int offset = 0;
233
234 for (ReadFruDataResponseData responseData : fruData) {
235 int length = responseData.getFruData().length;
236 System.arraycopy(responseData.getFruData(), 0, data, offset, length);
237 offset += length;
238 }
239
240 if (data[0] == 0x1) {
241
242 int chassisOffset = TypeConverter.byteToInt(data[2]) * 8;
243 int boardOffset = TypeConverter.byteToInt(data[3]) * 8;
244 int productInfoOffset = TypeConverter.byteToInt(data[4]) * 8;
245 int multiRecordOffset = TypeConverter.byteToInt(data[5]) * 8;
246
247 if (chassisOffset != 0) {
248 list.add(new ChassisInfo(data, chassisOffset));
249 }
250 if (boardOffset != 0) {
251 list.add(new BoardInfo(data, boardOffset));
252 }
253 if (productInfoOffset != 0) {
254 list.add(new ProductInfo(data, productInfoOffset));
255 }
256 if (multiRecordOffset != 0) {
257 addMultirecords(list, data, multiRecordOffset);
258 }
259 } else if (false) {
260
261 } else {
262 throw new IllegalArgumentException("Invalid format version: " + data[0]);
263 }
264
265 return list;
266 }
267
268 private static void addMultirecords(ArrayList<FruRecord> list, byte[] data, int multiRecordOffset) {
269 int currentMultirecordOffset = multiRecordOffset;
270
271 while ((TypeConverter.byteToInt(data[currentMultirecordOffset + 1]) & 0x80) == 0) {
272 list.add(MultiRecordInfo.populateMultiRecord(data, currentMultirecordOffset));
273 currentMultirecordOffset += TypeConverter.byteToInt(data[currentMultirecordOffset + 2]) + 5;
274 }
275 }
276
277 }