1 /*
2  * Copyright 2021 Google LLC
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef PLATFORMS_NEMORA_PORTABLE_NCSI_H_
18 #define PLATFORMS_NEMORA_PORTABLE_NCSI_H_
19 
20 /*
21  * Module for interacting with NC-SI capable network cards.
22  *
23  * DMTF v1.0.0 NC-SI specification:
24  * http://www.dmtf.org/sites/default/files/standards/documents/DSP0222_1.0.0.pdf
25  */
26 
27 #include <stdbool.h>
28 #include <stdint.h>
29 
30 #include "platforms/nemora/portable/net_types.h"
31 
32 #ifdef __cplusplus
33 extern "C" {
34 #endif
35 
36 #ifndef __packed
37 #define __packed __attribute__((packed))
38 #endif
39 
40 // Define states for our NC-SI connection to the NIC.
41 // There is no mapping to the NC-SI specification for these states, but they
42 // reflect the outcome of NC-SI commands used in our configuration state
43 // machine.
44 //
45 // 'DOWN' - while in this state, periodically restart the configuration state
46 //   machine until it succeeds.
47 // 'LOOPBACK' - the response to the first NC-SI command of the configuration
48 //   state machine was identical to the command: from this we infer we are in
49 //   loopback. While in this state, periodically restart the configuration state
50 //   machine.
51 // 'UP' - all commands were responded successfully, but need DHCP configuration
52 //   to go to the next state. While in this state, the connection is tested
53 //   periodically for failures, which can bring back to 'DOWN'.
54 // 'UP_AND_CONFIGURED' - NC-SI OEM commands for L3/L4 configuration (which
55 //   depend on DHCP configuration) were responded successfully. While in this
56 //   state, the connection and configuration are tested periodically for
57 //   failures, which can bring back to 'DOWN'.
58 // 'DISABLED' - reset default state. As soon as network is enabled (which
59 //   noticeably means that ProdID must be disabled), the state goes to DOWN.
60 // TODO: connection state has nothing to do with ncsi protocol and needs
61 // to be moved to ncsi_fsm.h. The main problem with the move is that
62 // ncsi_client.h defines an extern function with this return type, that is used
63 // in a lot of places that have no business including ncsi_fsm.h
64 typedef enum {
65   NCSI_CONNECTION_DOWN,
66   NCSI_CONNECTION_LOOPBACK,
67   NCSI_CONNECTION_UP,
68   NCSI_CONNECTION_UP_AND_CONFIGURED,
69   NCSI_CONNECTION_DISABLED,
70 } ncsi_connection_state_t;
71 
72 typedef enum {
73   NCSI_RESPONSE_NONE,
74   NCSI_RESPONSE_ACK,
75   NCSI_RESPONSE_NACK,
76   NCSI_RESPONSE_UNDERSIZED,
77   NCSI_RESPONSE_UNEXPECTED_TYPE,
78   NCSI_RESPONSE_UNEXPECTED_SIZE,
79   NCSI_RESPONSE_OEM_FORMAT_ERROR,
80   NCSI_RESPONSE_TIMEOUT,
81   NCSI_RESPONSE_UNEXPECTED_PARAMS,
82 } ncsi_response_type_t;
83 
84 // For NC-SI Rev 1.0.0, the management controller ID (mc_id) is 0.
85 #define NCSI_MC_ID 0
86 // For NC-SI Rev 1.0.0, the header revision is 0x01.
87 #define NCSI_HEADER_REV 1
88 #define NCSI_ETHERTYPE 0x88F8
89 #define NCSI_RESPONSE 0x80
90 
91 // Command IDs
92 enum {
93   NCSI_CLEAR_INITIAL_STATE,
94   NCSI_SELECT_PACKAGE,
95   NCSI_DESELECT_PACKAGE,
96   NCSI_ENABLE_CHANNEL,
97   NCSI_DISABLE_CHANNEL,
98   NCSI_RESET_CHANNEL,
99   NCSI_ENABLE_CHANNEL_NETWORK_TX,
100   NCSI_DISABLE_CHANNEL_NETWORK_TX,
101   NCSI_AEN_ENABLE,
102   NCSI_SET_LINK,
103   NCSI_GET_LINK_STATUS,
104   NCSI_SET_VLAN_FILTER,
105   NCSI_ENABLE_VLAN,
106   NCSI_DISABLE_VLAN,
107   NCSI_SET_MAC_ADDRESS,
108   // 0x0F is not a valid command
109   NCSI_ENABLE_BROADCAST_FILTER = 0x10,
110   NCSI_DISABLE_BROADCAST_FILTER,
111   NCSI_ENABLE_GLOBAL_MULTICAST_FILTER,
112   NCSI_DISABLE_GLOBAL_MULTICAST_FILTER,
113   NCSI_SET_NCSI_FLOW_CONTROL,
114   NCSI_GET_VERSION_ID,
115   NCSI_GET_CAPABILITIES,
116   NCSI_GET_PARAMETERS,
117   NCSI_GET_CONTROLLER_PACKET_STATISTICS,
118   NCSI_GET_NCSI_STATISTICS,
119   NCSI_GET_PASSTHROUGH_STATISTICS,
120   // 0x1B-0x4F are not valid commands
121   NCSI_OEM_COMMAND = 0x50,
122 };
123 // OEM Command IDs (subtypes of NCSI_OEM_COMMAND)
124 #define NCSI_OEM_COMMAND_GET_HOST_MAC 0x00
125 #define NCSI_OEM_COMMAND_SET_FILTER 0x01
126 #define NCSI_OEM_COMMAND_GET_FILTER 0x02
127 #define NCSI_OEM_COMMAND_ECHO 0x03
128 
129 #define NCSI_OEM_MANUFACTURER_ID 11129  // IANA Enterprise Number for Google.
130 #define NCSI_OEM_ECHO_PATTERN_SIZE 64
131 
132 /*
133  * NCSI command frame with packet header as described in section 8.2.1.
134  * Prepended with an ethernet header.
135  */
136 typedef struct __packed {
137   eth_hdr_t ethhdr;
138   uint8_t mc_id;
139   uint8_t header_revision;
140   uint8_t reserved_00;
141   uint8_t instance_id;          // Destinguish retried commands from new ones.
142   uint8_t control_packet_type;  // See section 8.3, and Table 17.
143   uint8_t channel_id;
144   uint16_t payload_length;  // In Bytes. Excludes header, checksum, padding.
145   uint16_t reserved_01[4];
146 } ncsi_header_t;
147 
148 /*
149  * Simple NCSI response packet.
150  */
151 typedef struct __packed {
152   ncsi_header_t hdr;
153   uint16_t response_code;
154   uint16_t reason_code;
155 } ncsi_simple_response_t;
156 
157 /*
158  * Simple NCSI command packet.
159  */
160 typedef struct {
161   ncsi_header_t hdr;
162 } ncsi_simple_command_t;
163 
164 /*
165  * Get Link Status Response. 8.4.24
166  */
167 typedef struct __packed {
168   uint32_t link_status;
169   uint32_t other_indications;
170   uint32_t oem_link_status;
171 } ncsi_link_status_t;
172 
173 typedef struct __packed {
174   ncsi_header_t hdr;
175   uint16_t response_code;
176   uint16_t reason_code;
177   ncsi_link_status_t link_status;
178 } ncsi_link_status_response_t;
179 
180 #define NCSI_LINK_STATUS_UP (1 << 0)
181 
182 /*
183  * Set MAC Address packet. 8.4.31
184  */
185 typedef struct __packed {
186   ncsi_header_t hdr;
187   mac_addr_t mac_addr;
188   uint8_t mac_addr_num;
189   uint8_t misc;
190 } ncsi_set_mac_command_t;
191 
192 /*
193  * Enable Broadcast Filter packet. 8.4.33
194  */
195 typedef struct __packed {
196   ncsi_header_t hdr;
197   uint32_t filter_settings;
198 } ncsi_enable_broadcast_filter_command_t;
199 
200 #define NCSI_BROADCAST_FILTER_MASK_ARP         (1 << 0)
201 #define NCSI_BROADCAST_FILTER_MASK_DHCP_CLIENT (1 << 1)
202 #define NCSI_BROADCAST_FILTER_MASK_DHCP_SERVER (1 << 2)
203 #define NCSI_BROADCAST_FILTER_MASK_NETBIOS     (1 << 3)
204 
205 /*
206  * Get Version ID Response. 8.4.44
207  */
208 typedef struct __packed {
209   struct {
210     uint8_t major;
211     uint8_t minor;
212     uint8_t update;
213     uint8_t alpha1;
214     uint8_t reserved[3];
215     uint8_t alpha2;
216   } ncsi_version;
217   uint8_t firmware_name_string[12];
218   uint32_t firmware_version;
219   uint16_t pci_did;
220   uint16_t pci_vid;
221   uint16_t pci_ssid;
222   uint16_t pci_svid;
223   uint32_t manufacturer_id;
224 } ncsi_version_id_t;
225 
226 typedef struct __packed {
227   ncsi_header_t hdr;
228   uint16_t response_code;
229   uint16_t reason_code;
230   ncsi_version_id_t version;
231 } ncsi_version_id_response_t;
232 
233 /*
234  * Get Capabilities Response 8.4.46
235  */
236 typedef struct __packed {
237   ncsi_header_t hdr;
238   uint16_t response_code;
239   uint16_t reason_code;
240   uint32_t capabilities_flags;
241   uint32_t broadcast_packet_filter_capabilties;
242   uint32_t multicast_packet_filter_capabilties;
243   uint32_t buffering_capability;
244   uint32_t aen_control_support;
245   uint8_t vlan_filter_count;
246   uint8_t mixed_filter_count;
247   uint8_t multicast_filter_count;
248   uint8_t unicast_filter_count;
249   uint16_t reserved;
250   uint8_t vlan_mode_support;
251   uint8_t channel_count;
252 } ncsi_capabilities_response_t;
253 
254 /*
255  * Get Parameters Response 8.4.48
256  */
257 typedef struct __packed {
258   ncsi_header_t hdr;
259   uint16_t response_code;
260   uint16_t reason_code;
261   // TODO: Note: Mellanox 1.4 FW has mac count swapped with mac flags.
262   uint8_t mac_address_count;
263   uint16_t reserved_01;
264   uint8_t mac_address_flags;
265   uint8_t vlan_tag_count;
266   uint8_t reserved_02;
267   uint16_t vlan_tag_flags;
268   uint32_t link_settings;
269   uint32_t broadcast_settings;
270   uint32_t configuration_flags;
271   uint8_t vlan_mode;
272   uint8_t flow_control_enable;
273   uint16_t reserved_03;
274   uint32_t aen_control;
275   mac_addr_t mac_address[2];
276   // TODO: Variable number of mac address filters (max 8. See 8.4.48)
277   uint16_t vlan_tags[2];
278   // TODO: Variable of vlan filters (up to 15 based on 8.4.48)
279 } ncsi_parameters_response_t;
280 
281 /*
282  * Get Passthrough statistics response. 8.4.54
283  *
284  * The legacy data structure matches MLX implementation up to vX
285  * (Google vX), however the standard requires the first field to be
286  * 64bits and MLX fixed it in vX (Google vX).
287  *
288  */
289 typedef struct __packed {
290   uint32_t tx_packets_received;  // EC -> NIC
291   uint32_t tx_packets_dropped;
292   uint32_t tx_channel_errors;
293   uint32_t tx_undersized_errors;
294   uint32_t tx_oversized_errors;
295   uint32_t rx_packets_received;  // Network -> NIC
296   uint32_t rx_packets_dropped;
297   uint32_t rx_channel_errors;
298   uint32_t rx_undersized_errors;
299   uint32_t rx_oversized_errors;
300 } ncsi_passthrough_stats_legacy_t;
301 
302 typedef struct __packed {
303   uint32_t tx_packets_received_hi;  // EC -> NIC (higher 32bit)
304   uint32_t tx_packets_received_lo;  // EC -> NIC (lower 32bit)
305   uint32_t tx_packets_dropped;
306   uint32_t tx_channel_errors;
307   uint32_t tx_undersized_errors;
308   uint32_t tx_oversized_errors;
309   uint32_t rx_packets_received;  // Network -> NIC
310   uint32_t rx_packets_dropped;
311   uint32_t rx_channel_errors;
312   uint32_t rx_undersized_errors;
313   uint32_t rx_oversized_errors;
314 } ncsi_passthrough_stats_t;
315 
316 typedef struct __packed {
317   ncsi_header_t hdr;
318   uint16_t response_code;
319   uint16_t reason_code;
320   ncsi_passthrough_stats_legacy_t stats;
321 } ncsi_passthrough_stats_legacy_response_t;
322 
323 typedef struct __packed {
324   ncsi_header_t hdr;
325   uint16_t response_code;
326   uint16_t reason_code;
327   ncsi_passthrough_stats_t stats;
328 } ncsi_passthrough_stats_response_t;
329 
330 /*
331  * OEM extension header for custom commands.
332  */
333 typedef struct __packed {
334   uint32_t manufacturer_id;
335   uint8_t reserved[3];
336   uint8_t oem_cmd;
337 } ncsi_oem_extension_header_t;
338 
339 /*
340  * Response format for simple OEM command.
341  */
342 typedef struct __packed {
343   ncsi_header_t hdr;
344   uint16_t response_code;
345   uint16_t reason_code;
346   ncsi_oem_extension_header_t oem_header;
347 } ncsi_oem_simple_response_t;
348 
349 /*
350  * Response format for OEM get MAC command.
351  */
352 typedef struct __packed {
353   ncsi_header_t hdr;
354   uint16_t response_code;
355   uint16_t reason_code;
356   ncsi_oem_extension_header_t oem_header;
357   uint16_t reserved0;
358   uint8_t mac[6];
359 } ncsi_host_mac_response_t;
360 
361 /*
362  * Format for OEM filter.
363  */
364 typedef struct __packed {
365   uint16_t reserved0;
366   uint8_t mac[6];
367   // If ip is set to zero, the filter will match any IP address, including any
368   // IPv6 address.
369   uint32_t ip;  // Network order
370   uint16_t port;  // Network order
371   uint8_t reserved1;
372   uint8_t flags;
373   uint8_t regid[8];
374 } ncsi_oem_filter_t;
375 
376 // Set flags
377 #define NCSI_OEM_FILTER_FLAGS_ENABLE      (0x01)
378 
379 // Get flags
380 #define NCSI_OEM_FILTER_FLAGS_ENABLED     (0x01)
381 #define NCSI_OEM_FILTER_FLAGS_REGISTERED  (0x02)
382 #define NCSI_OEM_FILTER_FLAGS_HOSTLESS    (0x04)
383 
384 /*
385  * Command format for simple OEM command.
386  */
387 typedef struct __packed {
388   ncsi_header_t hdr;
389   ncsi_oem_extension_header_t oem_header;
390 } ncsi_oem_simple_cmd_t;
391 
392 /*
393  * Response format for OEM get filter command.
394  */
395 typedef struct __packed {
396   ncsi_header_t hdr;
397   uint16_t response_code;
398   uint16_t reason_code;
399   ncsi_oem_extension_header_t oem_header;
400   ncsi_oem_filter_t filter;
401 } ncsi_oem_get_filter_response_t;
402 
403 /*
404  * Command format for OEM set filter command.
405  */
406 typedef struct __packed {
407   ncsi_header_t hdr;
408   ncsi_oem_extension_header_t oem_header;
409   ncsi_oem_filter_t filter;
410 } ncsi_oem_set_filter_cmd_t;
411 
412 /*
413  * Command format for OEM echo command.
414  */
415 typedef struct __packed {
416   ncsi_header_t hdr;
417   ncsi_oem_extension_header_t oem_header;
418   uint8_t pattern[NCSI_OEM_ECHO_PATTERN_SIZE];
419 } ncsi_oem_echo_cmd_t;
420 
421 /*
422  * Response format for OEM echo command.
423  */
424 typedef struct __packed {
425   ncsi_header_t hdr;
426   uint16_t response_code;
427   uint16_t reason_code;
428   ncsi_oem_extension_header_t oem_header;
429   uint8_t pattern[NCSI_OEM_ECHO_PATTERN_SIZE];
430 } ncsi_oem_echo_response_t;
431 
432 #ifdef __cplusplus
433 }  /* extern "C" */
434 #endif
435 
436 #endif  // PLATFORMS_NEMORA_PORTABLE_NCSI_H_
437