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