Sfoglia il codice sorgente

[fcoe] Add support for the FCoE Initialization Protocol (FIP)

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 13 anni fa
parent
commit
0f4fd09180
3 ha cambiato i file con 1139 aggiunte e 44 eliminazioni
  1. 13
    0
      src/include/ipxe/fcoe.h
  2. 450
    0
      src/include/ipxe/fip.h
  3. 676
    44
      src/net/fcoe.c

+ 13
- 0
src/include/ipxe/fcoe.h Vedi File

@@ -33,6 +33,19 @@ union fcoe_name {
33 33
 /** IEEE extended */
34 34
 #define FCOE_AUTHORITY_IEEE_EXTENDED 0x2000
35 35
 
36
+/** An FCoE MAC address prefix (FC-MAP) */
37
+struct fcoe_map {
38
+	uint8_t bytes[3];
39
+} __attribute__ (( packed ));
40
+
41
+/** An FCoE (fabric-assigned) MAC address */
42
+struct fcoe_mac {
43
+	/** MAC address prefix */
44
+	struct fcoe_map map;
45
+	/** Port ID */
46
+	struct fc_port_id port_id;
47
+} __attribute__ (( packed ));
48
+
36 49
 /** An FCoE header */
37 50
 struct fcoe_header {
38 51
 	/** FCoE frame version */

+ 450
- 0
src/include/ipxe/fip.h Vedi File

@@ -0,0 +1,450 @@
1
+#ifndef _IPXE_FIP_H
2
+#define _IPXE_FIP_H
3
+
4
+/*
5
+ * Copyright (C) 2010 Michael Brown <mbrown@fensystems.co.uk>.
6
+ *
7
+ * This program is free software; you can redistribute it and/or
8
+ * modify it under the terms of the GNU General Public License as
9
+ * published by the Free Software Foundation; either version 2 of the
10
+ * License, or any later version.
11
+ *
12
+ * This program is distributed in the hope that it will be useful, but
13
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
+ * General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU General Public License
18
+ * along with this program; if not, write to the Free Software
19
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
+ */
21
+
22
+#include <stdint.h>
23
+#include <ipxe/fc.h>
24
+#include <ipxe/fcels.h>
25
+#include <ipxe/fcoe.h>
26
+
27
+/** A FIP frame header */
28
+struct fip_header {
29
+	/** Frame version */
30
+	uint8_t version;
31
+	/** Reserved */
32
+	uint8_t reserved_a;
33
+	/** Protocol code */
34
+	uint16_t code;
35
+	/** Reserved */
36
+	uint8_t reserved_b;
37
+	/** Subcode */
38
+	uint8_t subcode;
39
+	/** Descriptor list length in 32-bit words */
40
+	uint16_t len;
41
+	/** Flags */
42
+	uint16_t flags;
43
+} __attribute__ (( packed ));
44
+
45
+/** FIP frame version */
46
+#define FIP_VERSION 0x10
47
+
48
+/** FIP protocol code */
49
+enum fip_code {
50
+	FIP_CODE_DISCOVERY = 0x0001,	/**< Discovery */
51
+	FIP_CODE_ELS = 0x0002,		/**< Extended link services */
52
+	FIP_CODE_MAINTAIN = 0x0003,	/**< Maintain virtual links */
53
+	FIP_CODE_VLAN = 0x0004,		/**< VLAN */
54
+};
55
+
56
+/** FIP protocol subcode for discovery */
57
+enum fip_discovery_subcode {
58
+	FIP_DISCOVERY_SOLICIT = 0x01,	/**< Discovery solicitation */
59
+	FIP_DISCOVERY_ADVERTISE = 0x02,	/**< Discovery advertisement */
60
+};
61
+
62
+/** FIP protocol subcode for extended link services */
63
+enum fip_els_subcode {
64
+	FIP_ELS_REQUEST = 0x01,		/**< ELS request */
65
+	FIP_ELS_RESPONSE = 0x02,	/**< ELS response */
66
+};
67
+
68
+/** FIP protocol subcode for keep alive / clear links */
69
+enum fip_vitality_subcode {
70
+	FIP_MAINTAIN_KEEP_ALIVE = 0x01,	/**< Keep alive */
71
+	FIP_MAINTAIN_CLEAR_LINKS = 0x02,/**< Clear virtual links */
72
+};
73
+
74
+/** FIP protocol subcode for VLAN */
75
+enum fip_vlan_subcode {
76
+	FIP_VLAN_REQUEST = 0x01,	/**< VLAN request */
77
+	FIP_VLAN_NOTIFY = 0x02,		/**< VLAN notification */
78
+};
79
+
80
+/** FIP flags */
81
+enum fip_flags {
82
+	FIP_FP	= 0x8000,		/**< Fabric-provided MAC address */
83
+	FIP_SP	= 0x4000,		/**< Server-provided MAC address */
84
+	FIP_A	= 0x0004,		/**< Available for login */
85
+	FIP_S	= 0x0002,		/**< Solicited */
86
+	FIP_F	= 0x0001,		/**< Forwarder */
87
+};
88
+
89
+/** FIP descriptor common fields */
90
+struct fip_common {
91
+	/** Type */
92
+	uint8_t type;
93
+	/** Length in 32-bit words */
94
+	uint8_t len;
95
+	/** Reserved */
96
+	uint8_t reserved[2];
97
+} __attribute__ (( packed ));
98
+
99
+/** FIP descriptor types */
100
+enum fip_type {
101
+	FIP_RESERVED = 0x00,		/**< Reserved */
102
+	FIP_PRIORITY = 0x01,		/**< Priority */
103
+	FIP_MAC_ADDRESS = 0x02,		/**< MAC address */
104
+	FIP_FC_MAP = 0x03,		/**< FC-MAP */
105
+	FIP_NAME_ID = 0x04,		/**< Name identifier */
106
+	FIP_FABRIC = 0x05,		/**< Fabric */
107
+	FIP_MAX_FCOE_SIZE = 0x06,	/**< Max FCoE size */
108
+	FIP_FLOGI = 0x07,		/**< FLOGI */
109
+	FIP_NPIV_FDISC = 0x08,		/**< NPIV FDISC */
110
+	FIP_LOGO = 0x09,		/**< LOGO */
111
+	FIP_ELP = 0x0a,			/**< ELP */
112
+	FIP_VX_PORT_ID = 0x0b,		/**< Vx port identification */
113
+	FIP_FKA_ADV_P = 0x0c,		/**< FKA ADV period */
114
+	FIP_VENDOR_ID = 0x0d,		/**< Vendor ID */
115
+	FIP_VLAN = 0x0e,		/**< VLAN */
116
+	FIP_NUM_DESCRIPTOR_TYPES
117
+};
118
+
119
+/** FIP descriptor type is critical */
120
+#define FIP_IS_CRITICAL( type ) ( (type) <= 0x7f )
121
+
122
+/** A FIP priority descriptor */
123
+struct fip_priority {
124
+	/** Type */
125
+	uint8_t type;
126
+	/** Length in 32-bit words */
127
+	uint8_t len;
128
+	/** Reserved */
129
+	uint8_t reserved;
130
+	/** Priority
131
+	 *
132
+	 * A higher value indicates a lower priority.
133
+	 */
134
+	uint8_t priority;
135
+} __attribute__ (( packed ));
136
+
137
+/** Default FIP priority */
138
+#define FIP_DEFAULT_PRIORITY 128
139
+
140
+/** Lowest FIP priority */
141
+#define FIP_LOWEST_PRIORITY 255
142
+
143
+/** A FIP MAC address descriptor */
144
+struct fip_mac_address {
145
+	/** Type */
146
+	uint8_t type;
147
+	/** Length in 32-bit words */
148
+	uint8_t len;
149
+	/** MAC address */
150
+	uint8_t mac[ETH_ALEN];
151
+} __attribute__ (( packed ));
152
+
153
+/** A FIP FC-MAP descriptor */
154
+struct fip_fc_map {
155
+	/** Type */
156
+	uint8_t type;
157
+	/** Length in 32-bit words */
158
+	uint8_t len;
159
+	/** Reserved */
160
+	uint8_t reserved[3];
161
+	/** FC-MAP */
162
+	struct fcoe_map map;
163
+} __attribute__ (( packed ));
164
+
165
+/** A FIP name identifier descriptor */
166
+struct fip_name_id {
167
+	/** Type */
168
+	uint8_t type;
169
+	/** Length in 32-bit words */
170
+	uint8_t len;
171
+	/** Reserved */
172
+	uint8_t reserved[2];
173
+	/** Name identifier */
174
+	struct fc_name name;
175
+} __attribute__ (( packed ));
176
+
177
+/** A FIP fabric descriptor */
178
+struct fip_fabric {
179
+	/** Type */
180
+	uint8_t type;
181
+	/** Length in 32-bit words */
182
+	uint8_t len;
183
+	/** Virtual Fabric ID, if any */
184
+	uint16_t vf_id;
185
+	/** Reserved */
186
+	uint8_t reserved;
187
+	/** FC-MAP */
188
+	struct fcoe_map map;
189
+	/** Fabric name */
190
+	struct fc_name name;
191
+} __attribute__ (( packed ));
192
+
193
+/** A FIP max FCoE size descriptor */
194
+struct fip_max_fcoe_size {
195
+	/** Type */
196
+	uint8_t type;
197
+	/** Length in 32-bit words */
198
+	uint8_t len;
199
+	/** Maximum FCoE size */
200
+	uint16_t mtu;
201
+} __attribute__ (( packed ));
202
+
203
+/** A FIP descriptor containing an encapsulated ELS frame */
204
+struct fip_els {
205
+	/** Type */
206
+	uint8_t type;
207
+	/** Length in 32-bit words */
208
+	uint8_t len;
209
+	/** Reserved */
210
+	uint8_t reserved[2];
211
+	/** Fibre Channel frame header */
212
+	struct fc_frame_header fc;
213
+	/** ELS frame */
214
+	struct fc_els_frame_common els;
215
+} __attribute__ (( packed ));
216
+
217
+/** A FIP descriptor containing an encapsulated login frame */
218
+struct fip_login {
219
+	/** Type */
220
+	uint8_t type;
221
+	/** Length in 32-bit words */
222
+	uint8_t len;
223
+	/** Reserved */
224
+	uint8_t reserved[2];
225
+	/** Fibre Channel frame header */
226
+	struct fc_frame_header fc;
227
+	/** ELS frame */
228
+	struct fc_login_frame els;
229
+} __attribute__ (( packed ));
230
+
231
+/** A FIP descriptor containing an encapsulated LOGO request frame */
232
+struct fip_logo_request {
233
+	/** Type */
234
+	uint8_t type;
235
+	/** Length in 32-bit words */
236
+	uint8_t len;
237
+	/** Reserved */
238
+	uint8_t reserved[2];
239
+	/** Fibre Channel frame header */
240
+	struct fc_frame_header fc;
241
+	/** ELS frame */
242
+	struct fc_logout_request_frame els;
243
+} __attribute__ (( packed ));
244
+
245
+/** A FIP descriptor containing an encapsulated LOGO response frame */
246
+struct fip_logo_response {
247
+	/** Type */
248
+	uint8_t type;
249
+	/** Length in 32-bit words */
250
+	uint8_t len;
251
+	/** Reserved */
252
+	uint8_t reserved[2];
253
+	/** Fibre Channel frame header */
254
+	struct fc_frame_header fc;
255
+	/** ELS frame */
256
+	struct fc_logout_response_frame els;
257
+} __attribute__ (( packed ));
258
+
259
+/** A FIP descriptor containing an encapsulated ELP frame */
260
+struct fip_elp {
261
+	/** Type */
262
+	uint8_t type;
263
+	/** Length in 32-bit words */
264
+	uint8_t len;
265
+	/** Reserved */
266
+	uint8_t reserved[2];
267
+	/** Fibre Channel frame header */
268
+	struct fc_frame_header fc;
269
+	/** ELS frame */
270
+	struct fc_els_frame_common els;
271
+	/** Uninteresting content */
272
+	uint32_t dull[25];
273
+} __attribute__ (( packed ));
274
+
275
+/** A FIP descriptor containing an encapsulated LS_RJT frame */
276
+struct fip_ls_rjt {
277
+	/** Type */
278
+	uint8_t type;
279
+	/** Length in 32-bit words */
280
+	uint8_t len;
281
+	/** Reserved */
282
+	uint8_t reserved[2];
283
+	/** Fibre Channel frame header */
284
+	struct fc_frame_header fc;
285
+	/** ELS frame */
286
+	struct fc_ls_rjt_frame els;
287
+} __attribute__ (( packed ));
288
+
289
+/** A FIP Vx port identification descriptor */
290
+struct fip_vx_port_id {
291
+	/** Type */
292
+	uint8_t type;
293
+	/** Length in 32-bit words */
294
+	uint8_t len;
295
+	/** MAC address */
296
+	uint8_t mac[ETH_ALEN];
297
+	/** Reserved */
298
+	uint8_t reserved;
299
+	/** Address identifier */
300
+	struct fc_port_id id;
301
+	/** Port name */
302
+	struct fc_name name;
303
+} __attribute__ (( packed ));
304
+
305
+/** A FIP FKA ADV period descriptor */
306
+struct fip_fka_adv_p {
307
+	/** Type */
308
+	uint8_t type;
309
+	/** Length in 32-bit words */
310
+	uint8_t len;
311
+	/** Reserved */
312
+	uint8_t reserved;
313
+	/** Flags */
314
+	uint8_t flags;
315
+	/** Keep alive advertisement period in milliseconds */
316
+	uint32_t period;
317
+} __attribute__ (( packed ));
318
+
319
+/** FIP FKA ADV period flags */
320
+enum fip_fka_adv_p_flags {
321
+	FIP_NO_KEEPALIVE = 0x01,	/**< Do not send keepalives */
322
+};
323
+
324
+/** A FIP vendor ID descriptor */
325
+struct fip_vendor_id {
326
+	/** Type */
327
+	uint8_t type;
328
+	/** Length in 32-bit words */
329
+	uint8_t len;
330
+	/** Reserved */
331
+	uint8_t reserved[2];
332
+	/** Vendor ID */
333
+	uint8_t vendor[8];
334
+} __attribute__ (( packed ));
335
+
336
+/** A FIP VLAN descriptor */
337
+struct fip_vlan {
338
+	/** Type */
339
+	uint8_t type;
340
+	/** Length in 32-bit words */
341
+	uint8_t len;
342
+	/** VLAN ID */
343
+	uint16_t vlan;
344
+} __attribute__ (( packed ));
345
+
346
+/** A FIP descriptor */
347
+union fip_descriptor {
348
+	/** Common fields */
349
+	struct fip_common common;
350
+	/** Priority descriptor */
351
+	struct fip_priority priority;
352
+	/** MAC address descriptor */
353
+	struct fip_mac_address mac_address;
354
+	/** FC-MAP descriptor */
355
+	struct fip_fc_map fc_map;
356
+	/** Name identifier descriptor */
357
+	struct fip_name_id name_id;
358
+	/** Fabric descriptor */
359
+	struct fip_fabric fabric;
360
+	/** Max FCoE size descriptor */
361
+	struct fip_max_fcoe_size max_fcoe_size;
362
+	/** FLOGI descriptor */
363
+	struct fip_els flogi;
364
+	/** FLOGI request descriptor */
365
+	struct fip_login flogi_request;
366
+	/** FLOGI LS_ACC descriptor */
367
+	struct fip_login flogi_ls_acc;
368
+	/** FLOGI LS_RJT descriptor */
369
+	struct fip_ls_rjt flogi_ls_rjt;
370
+	/** NPIV FDISC descriptor */
371
+	struct fip_els npiv_fdisc;
372
+	/** NPIV FDISC request descriptor */
373
+	struct fip_login npiv_fdisc_request;
374
+	/** NPIV FDISC LS_ACC descriptor */
375
+	struct fip_login npiv_fdisc_ls_acc;
376
+	/** NPIV FDISC LS_RJT descriptor */
377
+	struct fip_ls_rjt npiv_fdisc_ls_rjt;
378
+	/** LOGO descriptor */
379
+	struct fip_els logo;
380
+	/** LOGO request descriptor */
381
+	struct fip_logo_request logo_request;
382
+	/** LOGO LS_ACC descriptor */
383
+	struct fip_logo_response logo_ls_acc;
384
+	/** LOGO LS_RJT descriptor */
385
+	struct fip_ls_rjt logo_ls_rjt;
386
+	/** ELS descriptor */
387
+	struct fip_els elp;
388
+	/** ELP request descriptor */
389
+	struct fip_elp elp_request;
390
+	/** ELP LS_ACC descriptor */
391
+	struct fip_elp elp_ls_acc;
392
+	/** ELP LS_RJT descriptor */
393
+	struct fip_ls_rjt elp_ls_rjt;
394
+	/** Vx port identification descriptor */
395
+	struct fip_vx_port_id vx_port_id;
396
+	/** FKA ADV period descriptor */
397
+	struct fip_fka_adv_p fka_adv_p;
398
+	/** Vendor ID descriptor */
399
+	struct fip_vendor_id vendor_id;
400
+	/** VLAN descriptor */
401
+	struct fip_vlan vlan;
402
+} __attribute__ (( packed ));
403
+
404
+/** A FIP descriptor set */
405
+struct fip_descriptors {
406
+	/** Descriptors, indexed by type */
407
+	union fip_descriptor *desc[FIP_NUM_DESCRIPTOR_TYPES];
408
+};
409
+
410
+/**
411
+ * Define a function to extract a specific FIP descriptor type from a list
412
+ *
413
+ * @v type		Descriptor type
414
+ * @v name		Descriptor name
415
+ * @v finder		Descriptor finder
416
+ */
417
+#define FIP_DESCRIPTOR( type, name )					\
418
+	static inline __attribute__ (( always_inline ))			\
419
+	typeof ( ( ( union fip_descriptor * ) NULL )->name ) *		\
420
+	fip_ ## name ( struct fip_descriptors *descs ) {		\
421
+		return &(descs->desc[type]->name);			\
422
+	}
423
+FIP_DESCRIPTOR ( FIP_PRIORITY, priority );
424
+FIP_DESCRIPTOR ( FIP_MAC_ADDRESS, mac_address );
425
+FIP_DESCRIPTOR ( FIP_FC_MAP, fc_map );
426
+FIP_DESCRIPTOR ( FIP_NAME_ID, name_id );
427
+FIP_DESCRIPTOR ( FIP_FABRIC, fabric );
428
+FIP_DESCRIPTOR ( FIP_MAX_FCOE_SIZE, max_fcoe_size );
429
+FIP_DESCRIPTOR ( FIP_FLOGI, flogi );
430
+FIP_DESCRIPTOR ( FIP_FLOGI, flogi_request );
431
+FIP_DESCRIPTOR ( FIP_FLOGI, flogi_ls_acc );
432
+FIP_DESCRIPTOR ( FIP_FLOGI, flogi_ls_rjt );
433
+FIP_DESCRIPTOR ( FIP_NPIV_FDISC, npiv_fdisc );
434
+FIP_DESCRIPTOR ( FIP_NPIV_FDISC, npiv_fdisc_request );
435
+FIP_DESCRIPTOR ( FIP_NPIV_FDISC, npiv_fdisc_ls_acc );
436
+FIP_DESCRIPTOR ( FIP_NPIV_FDISC, npiv_fdisc_ls_rjt );
437
+FIP_DESCRIPTOR ( FIP_LOGO, logo );
438
+FIP_DESCRIPTOR ( FIP_LOGO, logo_request );
439
+FIP_DESCRIPTOR ( FIP_LOGO, logo_ls_acc );
440
+FIP_DESCRIPTOR ( FIP_LOGO, logo_ls_rjt );
441
+FIP_DESCRIPTOR ( FIP_ELP, elp );
442
+FIP_DESCRIPTOR ( FIP_ELP, elp_request );
443
+FIP_DESCRIPTOR ( FIP_ELP, elp_ls_acc );
444
+FIP_DESCRIPTOR ( FIP_ELP, elp_ls_rjt );
445
+FIP_DESCRIPTOR ( FIP_VX_PORT_ID, vx_port_id );
446
+FIP_DESCRIPTOR ( FIP_FKA_ADV_P, fka_adv_p );
447
+FIP_DESCRIPTOR ( FIP_VENDOR_ID, vendor_id );
448
+FIP_DESCRIPTOR ( FIP_VLAN, vlan );
449
+
450
+#endif /* _IPXE_FIP_H */

+ 676
- 44
src/net/fcoe.c Vedi File

@@ -28,11 +28,15 @@ FILE_LICENCE ( GPL2_OR_LATER );
28 28
 #include <ipxe/interface.h>
29 29
 #include <ipxe/xfer.h>
30 30
 #include <ipxe/netdevice.h>
31
+#include <ipxe/ethernet.h>
31 32
 #include <ipxe/features.h>
32 33
 #include <ipxe/errortab.h>
33 34
 #include <ipxe/device.h>
34 35
 #include <ipxe/crc32.h>
36
+#include <ipxe/retry.h>
37
+#include <ipxe/timer.h>
35 38
 #include <ipxe/fc.h>
39
+#include <ipxe/fip.h>
36 40
 #include <ipxe/fcoe.h>
37 41
 
38 42
 /** @file
@@ -67,19 +71,76 @@ struct fcoe_port {
67 71
 	struct interface transport;
68 72
 	/** Network device */
69 73
 	struct net_device *netdev;
74
+
75
+	/** Node WWN */
76
+	union fcoe_name node_wwn;
77
+	/** Port WWN */
78
+	union fcoe_name port_wwn;
79
+
80
+	/** FIP retransmission timer */
81
+	struct retry_timer timer;
82
+	/** FIP timeout counter */
83
+	unsigned int timeouts;
84
+	/** Flags */
85
+	unsigned int flags;
86
+	/** FCoE forwarder priority */
87
+	unsigned int priority;
88
+	/** Keepalive delay (in ms) */
89
+	unsigned int keepalive;
70 90
 	/** FCoE forwarder MAC address */
71
-	uint8_t fcf_ll_addr[ETH_ALEN];
91
+	uint8_t fcf_mac[ETH_ALEN];
92
+	/** Local MAC address */
93
+	uint8_t local_mac[ETH_ALEN];
72 94
 };
73 95
 
74
-/** List of FCoE ports */
75
-static LIST_HEAD ( fcoe_ports );
96
+/** FCoE flags */
97
+enum fcoe_flags {
98
+	/** Underlying network device is available */
99
+	FCOE_HAVE_NETWORK = 0x0001,
100
+	/** We have selected an FCoE forwarder to use */
101
+	FCOE_HAVE_FCF = 0x0002,
102
+	/** We have a FIP-capable FCoE forwarder available to be used */
103
+	FCOE_HAVE_FIP_FCF = 0x0004,
104
+};
76 105
 
77 106
 struct net_protocol fcoe_protocol __net_protocol;
107
+struct net_protocol fip_protocol __net_protocol;
108
+
109
+/** FCoE All-FCoE-MACs address */
110
+static uint8_t all_fcoe_macs[ETH_ALEN] =
111
+	{ 0x01, 0x10, 0x18, 0x01, 0x00, 0x00 };
112
+
113
+/** FCoE All-ENode-MACs address */
114
+static uint8_t all_enode_macs[ETH_ALEN] =
115
+	{ 0x01, 0x10, 0x18, 0x01, 0x00, 0x01 };
116
+
117
+/** FCoE All-FCF-MACs address */
118
+static uint8_t all_fcf_macs[ETH_ALEN] =
119
+	{ 0x01, 0x10, 0x18, 0x01, 0x00, 0x02 };
78 120
 
79 121
 /** Default FCoE forwarded MAC address */
80
-uint8_t fcoe_default_fcf_ll_addr[ETH_ALEN] =
122
+static uint8_t default_fcf_mac[ETH_ALEN] =
81 123
 	{ 0x0e, 0xfc, 0x00, 0xff, 0xff, 0xfe };
82 124
 
125
+/** Maximum number of FIP solicitations before giving up on FIP */
126
+#define FCOE_MAX_FIP_SOLICITATIONS 2
127
+
128
+/** Delay between retrying FIP solicitations */
129
+#define FCOE_FIP_RETRY_DELAY ( TICKS_PER_SEC )
130
+
131
+/** Maximum number of missing discovery advertisements */
132
+#define FCOE_MAX_FIP_MISSING_KEEPALIVES 4
133
+
134
+/** List of FCoE ports */
135
+static LIST_HEAD ( fcoe_ports );
136
+
137
+/******************************************************************************
138
+ *
139
+ * FCoE protocol
140
+ *
141
+ ******************************************************************************
142
+ */
143
+
83 144
 /**
84 145
  * Identify FCoE port by network device
85 146
  *
@@ -96,6 +157,37 @@ static struct fcoe_port * fcoe_demux ( struct net_device *netdev ) {
96 157
 	return NULL;
97 158
 }
98 159
 
160
+/**
161
+ * Reset FCoE port
162
+ *
163
+ * @v fcoe		FCoE port
164
+ */
165
+static void fcoe_reset ( struct fcoe_port *fcoe ) {
166
+
167
+	/* Reset any FIP state */
168
+	stop_timer ( &fcoe->timer );
169
+	fcoe->timeouts = 0;
170
+	fcoe->flags = 0;
171
+	fcoe->priority = ( FIP_LOWEST_PRIORITY + 1 );
172
+	fcoe->keepalive = 0;
173
+	memcpy ( fcoe->fcf_mac, default_fcf_mac,
174
+		 sizeof ( fcoe->fcf_mac ) );
175
+	memcpy ( fcoe->local_mac, fcoe->netdev->ll_addr,
176
+		 sizeof ( fcoe->local_mac ) );
177
+
178
+	/* Start FIP solicitation if network is available */
179
+	if ( netdev_is_open ( fcoe->netdev ) &&
180
+	     netdev_link_ok ( fcoe->netdev ) ) {
181
+		fcoe->flags |= FCOE_HAVE_NETWORK;
182
+		start_timer_nodelay ( &fcoe->timer );
183
+		DBGC ( fcoe, "FCoE %s starting FIP solicitation\n",
184
+		       fcoe->netdev->name );
185
+	}
186
+
187
+	/* Send notification of window change */
188
+	xfer_window_changed ( &fcoe->transport );
189
+}
190
+
99 191
 /**
100 192
  * Transmit FCoE packet
101 193
  *
@@ -108,28 +200,78 @@ static int fcoe_deliver ( struct fcoe_port *fcoe,
108 200
 			  struct io_buffer *iobuf,
109 201
 			  struct xfer_metadata *meta __unused ) {
110 202
 	struct fc_frame_header *fchdr = iobuf->data;
203
+	struct fc_els_frame_common *els = ( iobuf->data + sizeof ( *fchdr ) );
111 204
 	struct fcoe_header *fcoehdr;
112 205
 	struct fcoe_footer *fcoeftr;
206
+	struct fip_header *fiphdr;
207
+	struct fip_login *fipflogi;
208
+	struct fip_mac_address *fipmac;
113 209
 	uint32_t crc;
210
+	struct net_protocol *net_protocol;
211
+	void *ll_source;
114 212
 	int rc;
115 213
 
116
-	/* Calculate CRC */
117
-	crc = crc32_le ( ~((uint32_t)0), iobuf->data, iob_len ( iobuf ) );
214
+	/* Send as FIP or FCoE as appropriate */
215
+	if ( ( fchdr->r_ctl == ( FC_R_CTL_ELS | FC_R_CTL_UNSOL_CTRL ) ) &&
216
+	     ( els->command == FC_ELS_FLOGI ) &&
217
+	     ( fcoe->flags & FCOE_HAVE_FIP_FCF ) ) {
218
+
219
+		/* Create FIP FLOGI descriptor */
220
+		fipflogi = iob_push ( iobuf,
221
+				      offsetof ( typeof ( *fipflogi ), fc ) );
222
+		memset ( fipflogi, 0, offsetof ( typeof ( *fipflogi ), fc ) );
223
+		fipflogi->type = FIP_FLOGI;
224
+		fipflogi->len = ( iob_len ( iobuf ) / 4 );
225
+
226
+		/* Create FIP MAC address descriptor */
227
+		fipmac = iob_put ( iobuf, sizeof ( *fipmac ) );
228
+		memset ( fipmac, 0, sizeof ( *fipmac ) );
229
+		fipmac->type = FIP_MAC_ADDRESS;
230
+		fipmac->len = ( sizeof ( *fipmac ) / 4 );
231
+		memcpy ( fipmac->mac, fcoe->netdev->ll_addr,
232
+			 sizeof ( fipmac->mac ) );
233
+
234
+		/* Create FIP header */
235
+		fiphdr = iob_push ( iobuf, sizeof ( *fiphdr ) );
236
+		memset ( fiphdr, 0, sizeof ( *fiphdr ) );
237
+		fiphdr->version = FIP_VERSION;
238
+		fiphdr->code = htons ( FIP_CODE_ELS );
239
+		fiphdr->subcode = FIP_ELS_REQUEST;
240
+		fiphdr->len =
241
+			htons ( ( iob_len ( iobuf ) - sizeof ( *fiphdr ) ) / 4);
242
+		fiphdr->flags = htons ( FIP_FP | FIP_SP );
243
+
244
+		/* Send as FIP packet from netdev's own MAC address */
245
+		net_protocol = &fip_protocol;
246
+		ll_source = fcoe->netdev->ll_addr;
247
+
248
+	} else {
249
+
250
+		/* Calculate CRC */
251
+		crc = crc32_le ( ~((uint32_t)0), iobuf->data,
252
+				 iob_len ( iobuf ) );
118 253
 
119
-	/* Create FCoE header */
120
-	fcoehdr = iob_push ( iobuf, sizeof ( *fcoehdr ) );
121
-	memset ( fcoehdr, 0, sizeof ( *fcoehdr ) );
122
-	fcoehdr->sof = ( ( fchdr->seq_cnt == ntohs ( 0 ) ) ?
123
-			 FCOE_SOF_I3 : FCOE_SOF_N3 );
124
-	fcoeftr = iob_put ( iobuf, sizeof ( *fcoeftr ) );
125
-	memset ( fcoeftr, 0, sizeof ( *fcoeftr ) );
126
-	fcoeftr->crc = cpu_to_le32 ( crc ^ ~((uint32_t)0) );
127
-	fcoeftr->eof = ( ( fchdr->f_ctl_es & FC_F_CTL_ES_END ) ?
128
-			 FCOE_EOF_T : FCOE_EOF_N );
254
+		/* Create FCoE header */
255
+		fcoehdr = iob_push ( iobuf, sizeof ( *fcoehdr ) );
256
+		memset ( fcoehdr, 0, sizeof ( *fcoehdr ) );
257
+		fcoehdr->sof = ( ( fchdr->seq_cnt == ntohs ( 0 ) ) ?
258
+				 FCOE_SOF_I3 : FCOE_SOF_N3 );
259
+
260
+		/* Create FCoE footer */
261
+		fcoeftr = iob_put ( iobuf, sizeof ( *fcoeftr ) );
262
+		memset ( fcoeftr, 0, sizeof ( *fcoeftr ) );
263
+		fcoeftr->crc = cpu_to_le32 ( crc ^ ~((uint32_t)0) );
264
+		fcoeftr->eof = ( ( fchdr->f_ctl_es & FC_F_CTL_ES_END ) ?
265
+				 FCOE_EOF_T : FCOE_EOF_N );
266
+
267
+		/* Send as FCoE packet from FCoE MAC address */
268
+		net_protocol = &fcoe_protocol;
269
+		ll_source = fcoe->local_mac;
270
+	}
129 271
 
130 272
 	/* Transmit packet */
131
-	if ( ( rc = net_tx ( iob_disown ( iobuf ), fcoe->netdev, &fcoe_protocol,
132
-			     fcoe->fcf_ll_addr, fcoe->netdev->ll_addr )) != 0){
273
+	if ( ( rc = net_tx ( iob_disown ( iobuf ), fcoe->netdev, net_protocol,
274
+			     fcoe->fcf_mac, ll_source ) ) != 0 ) {
133 275
 		DBGC ( fcoe, "FCoE %s could not transmit: %s\n",
134 276
 		       fcoe->netdev->name, strerror ( rc ) );
135 277
 		goto done;
@@ -169,7 +311,7 @@ static struct io_buffer * fcoe_alloc_iob ( struct fcoe_port *fcoe __unused,
169 311
  * @ret rc		Return status code
170 312
  */
171 313
 static int fcoe_rx ( struct io_buffer *iobuf, struct net_device *netdev,
172
-		     const void *ll_dest __unused, const void *ll_source ) {
314
+		     const void *ll_dest, const void *ll_source ) {
173 315
 	struct fcoe_header *fcoehdr;
174 316
 	struct fcoe_footer *fcoeftr;
175 317
 	struct fcoe_port *fcoe;
@@ -183,6 +325,17 @@ static int fcoe_rx ( struct io_buffer *iobuf, struct net_device *netdev,
183 325
 		goto done;
184 326
 	}
185 327
 
328
+	/* Discard packets not destined for us */
329
+	if ( ( memcmp ( fcoe->local_mac, ll_dest,
330
+			sizeof ( fcoe->local_mac ) ) != 0 ) &&
331
+	     ( memcmp ( default_fcf_mac, ll_dest,
332
+			sizeof ( default_fcf_mac ) ) != 0 ) ) {
333
+		DBGC2 ( fcoe, "FCoE %s ignoring packet for %s\n",
334
+			fcoe->netdev->name, eth_ntoa ( ll_dest ) );
335
+		rc = -ENOTCONN;
336
+		goto done;
337
+	}
338
+
186 339
 	/* Sanity check */
187 340
 	if ( iob_len ( iobuf ) < ( sizeof ( *fcoehdr ) + sizeof ( *fcoeftr ) )){
188 341
 		DBGC ( fcoe, "FCoE %s received under-length frame (%zd "
@@ -226,8 +379,11 @@ static int fcoe_rx ( struct io_buffer *iobuf, struct net_device *netdev,
226 379
 		goto done;
227 380
 	}
228 381
 
229
-	/* Record FCF address */
230
-	memcpy ( &fcoe->fcf_ll_addr, ll_source, sizeof ( fcoe->fcf_ll_addr ) );
382
+	/* Record FCF address if applicable */
383
+	if ( ( fcoe->flags & FCOE_HAVE_FCF ) &&
384
+	     ( ! ( fcoe->flags & FCOE_HAVE_FIP_FCF ) ) ) {
385
+		memcpy ( &fcoe->fcf_mac, ll_source, sizeof ( fcoe->fcf_mac ) );
386
+	}
231 387
 
232 388
 	/* Hand off via transport interface */
233 389
 	if ( ( rc = xfer_deliver_iob ( &fcoe->transport,
@@ -249,10 +405,7 @@ static int fcoe_rx ( struct io_buffer *iobuf, struct net_device *netdev,
249 405
  * @ret len		Length of window
250 406
  */
251 407
 static size_t fcoe_window ( struct fcoe_port *fcoe ) {
252
-	struct net_device *netdev = fcoe->netdev;
253
-
254
-	return ( ( netdev_is_open ( netdev ) && netdev_link_ok ( netdev ) ) ?
255
-		 ~( ( size_t ) 0 ) : 0 );
408
+	return ( ( fcoe->flags & FCOE_HAVE_FCF ) ? ~( ( size_t ) 0 ) : 0 );
256 409
 }
257 410
 
258 411
 /**
@@ -263,6 +416,7 @@ static size_t fcoe_window ( struct fcoe_port *fcoe ) {
263 416
  */
264 417
 static void fcoe_close ( struct fcoe_port *fcoe, int rc ) {
265 418
 
419
+	stop_timer ( &fcoe->timer );
266 420
 	intf_shutdown ( &fcoe->transport, rc );
267 421
 	netdev_put ( fcoe->netdev );
268 422
 	list_del ( &fcoe->list );
@@ -293,6 +447,483 @@ static struct interface_operation fcoe_transport_op[] = {
293 447
 static struct interface_descriptor fcoe_transport_desc =
294 448
 	INTF_DESC ( struct fcoe_port, transport, fcoe_transport_op );
295 449
 
450
+/******************************************************************************
451
+ *
452
+ * FIP protocol
453
+ *
454
+ ******************************************************************************
455
+ */
456
+
457
+/**
458
+ * Parse FIP packet into descriptor set
459
+ *
460
+ * @v fcoe		FCoE port
461
+ * @v fiphdr		FIP header
462
+ * @v len		Length of FIP packet
463
+ * @v descs		Descriptor set to fill in
464
+ * @ret rc		Return status code
465
+ */
466
+static int fcoe_fip_parse ( struct fcoe_port *fcoe, struct fip_header *fiphdr,
467
+			    size_t len, struct fip_descriptors *descs ) {
468
+	union fip_descriptor *desc;
469
+	size_t descs_len;
470
+	size_t desc_len;
471
+	size_t desc_offset;
472
+	unsigned int desc_type;
473
+
474
+	/* Check FIP version */
475
+	if ( fiphdr->version != FIP_VERSION ) {
476
+		DBGC ( fcoe, "FCoE %s received unsupported FIP version %02x\n",
477
+		       fcoe->netdev->name, fiphdr->version );
478
+		return -EINVAL;
479
+	}
480
+
481
+	/* Check length */
482
+	descs_len = ( ntohs ( fiphdr->len ) * 4 );
483
+	if ( ( sizeof ( *fiphdr ) + descs_len ) > len ) {
484
+		DBGC ( fcoe, "FCoE %s received bad descriptor list length\n",
485
+		       fcoe->netdev->name );
486
+		return -EINVAL;
487
+	}
488
+
489
+	/* Parse descriptor list */
490
+	memset ( descs, 0, sizeof ( *descs ) );
491
+	for ( desc_offset = 0 ;
492
+	      desc_offset <= ( descs_len - sizeof ( desc->common ) ) ;
493
+	      desc_offset += desc_len ) {
494
+
495
+		/* Find descriptor and validate length */
496
+		desc = ( ( ( void * ) ( fiphdr + 1 ) ) + desc_offset );
497
+		desc_type = desc->common.type;
498
+		desc_len = ( desc->common.len * 4 );
499
+		if ( desc_len == 0 ) {
500
+			DBGC ( fcoe, "FCoE %s received zero-length "
501
+			       "descriptor\n", fcoe->netdev->name );
502
+			return -EINVAL;
503
+		}
504
+		if ( ( desc_offset + desc_len ) > descs_len ) {
505
+			DBGC ( fcoe, "FCoE %s descriptor overrun\n",
506
+			       fcoe->netdev->name );
507
+			return -EINVAL;
508
+		}
509
+
510
+		/* Handle descriptors that we understand */
511
+		if ( ( desc_type > FIP_RESERVED ) &&
512
+		     ( desc_type < FIP_NUM_DESCRIPTOR_TYPES ) ) {
513
+			descs->desc[desc_type] = desc;
514
+			continue;
515
+		}
516
+
517
+		/* Abort if we cannot understand a critical descriptor */
518
+		if ( FIP_IS_CRITICAL ( desc_type ) ) {
519
+			DBGC ( fcoe, "FCoE %s cannot understand critical "
520
+			       "descriptor type %02x\n",
521
+			       fcoe->netdev->name, desc_type );
522
+			return -ENOTSUP;
523
+		}
524
+
525
+		/* Ignore non-critical descriptors that we cannot understand */
526
+	}
527
+
528
+	return 0;
529
+}
530
+
531
+/**
532
+ * Send FIP discovery solicitation
533
+ *
534
+ * @v fcoe		FCoE port
535
+ * @ret rc		Return status code
536
+ */
537
+static int fcoe_fip_tx_solicitation ( struct fcoe_port *fcoe ) {
538
+	struct io_buffer *iobuf;
539
+	struct {
540
+		struct fip_header hdr;
541
+		struct fip_mac_address mac_address;
542
+		struct fip_name_id name_id;
543
+		struct fip_max_fcoe_size max_fcoe_size;
544
+	} __attribute__ (( packed )) *solicitation;
545
+	int rc;
546
+
547
+	/* Allocate I/O buffer */
548
+	iobuf = alloc_iob ( MAX_LL_HEADER_LEN + sizeof ( *solicitation ) );
549
+	if ( ! iobuf )
550
+		return -ENOMEM;
551
+	iob_reserve ( iobuf, MAX_LL_HEADER_LEN );
552
+
553
+	/* Construct discovery solicitation */
554
+	solicitation = iob_put ( iobuf, sizeof ( *solicitation ) );
555
+	memset ( solicitation, 0, sizeof ( *solicitation ) );
556
+	solicitation->hdr.version = FIP_VERSION;
557
+	solicitation->hdr.code = htons ( FIP_CODE_DISCOVERY );
558
+	solicitation->hdr.subcode = FIP_DISCOVERY_SOLICIT;
559
+	solicitation->hdr.len =	htons ( ( sizeof ( *solicitation ) -
560
+					  sizeof ( solicitation->hdr ) ) / 4 );
561
+	solicitation->hdr.flags = htons ( FIP_FP | FIP_SP );
562
+	solicitation->mac_address.type = FIP_MAC_ADDRESS;
563
+	solicitation->mac_address.len =
564
+		( sizeof ( solicitation->mac_address ) / 4 );
565
+	memcpy ( solicitation->mac_address.mac, fcoe->netdev->ll_addr,
566
+		 sizeof ( solicitation->mac_address.mac ) );
567
+	solicitation->name_id.type = FIP_NAME_ID;
568
+	solicitation->name_id.len = ( sizeof ( solicitation->name_id ) / 4 );
569
+	memcpy ( &solicitation->name_id.name, &fcoe->node_wwn.fc,
570
+		 sizeof ( solicitation->name_id.name ) );
571
+	solicitation->max_fcoe_size.type = FIP_MAX_FCOE_SIZE;
572
+	solicitation->max_fcoe_size.len =
573
+		( sizeof ( solicitation->max_fcoe_size ) / 4 );
574
+	solicitation->max_fcoe_size.mtu =
575
+		htons ( ETH_MAX_MTU - sizeof ( struct fcoe_header ) -
576
+			sizeof ( struct fcoe_footer ) );
577
+
578
+	/* Send discovery solicitation */
579
+	if ( ( rc = net_tx ( iob_disown ( iobuf ), fcoe->netdev,
580
+			     &fip_protocol, all_fcf_macs,
581
+			     fcoe->netdev->ll_addr ) ) != 0 ) {
582
+		DBGC ( fcoe, "FCoE %s could not send discovery solicitation: "
583
+		       "%s\n", fcoe->netdev->name, strerror ( rc ) );
584
+		return rc;
585
+	}
586
+
587
+	return 0;
588
+}
589
+
590
+/**
591
+ * Handle received FIP discovery advertisement
592
+ *
593
+ * @v fcoe		FCoE port
594
+ * @v descs		Descriptor list
595
+ * @v flags		Flags
596
+ * @ret rc		Return status code
597
+ */
598
+static int fcoe_fip_rx_advertisement ( struct fcoe_port *fcoe,
599
+				       struct fip_descriptors *descs,
600
+				       unsigned int flags ) {
601
+	struct fip_priority *priority = fip_priority ( descs );
602
+	struct fip_mac_address *mac_address = fip_mac_address ( descs );
603
+	struct fip_fka_adv_p *fka_adv_p = fip_fka_adv_p ( descs );
604
+
605
+	/* Sanity checks */
606
+	if ( ! priority ) {
607
+		DBGC ( fcoe, "FCoE %s received advertisement missing "
608
+		       "priority\n", fcoe->netdev->name );
609
+		return -EINVAL;
610
+	}
611
+	if ( ! mac_address ) {
612
+		DBGC ( fcoe, "FCoE %s received advertisement missing MAC "
613
+		       "address\n", fcoe->netdev->name );
614
+		return -EINVAL;
615
+	}
616
+	if ( ! fka_adv_p ) {
617
+		DBGC ( fcoe, "FCoE %s received advertisement missing FKA ADV "
618
+		       "period\n", fcoe->netdev->name );
619
+		return -EINVAL;
620
+	}
621
+
622
+	if ( ! ( fcoe->flags & FCOE_HAVE_FCF ) ) {
623
+
624
+		/* We are soliciting for an FCF.  Store the highest
625
+		 * (i.e. lowest-valued) priority solicited
626
+		 * advertisement that we receive.
627
+		 */
628
+		if ( ( ( flags & ( FIP_A | FIP_S | FIP_F ) ) ==
629
+		       ( FIP_A | FIP_S | FIP_F ) ) &&
630
+		     ( priority->priority < fcoe->priority ) ) {
631
+
632
+			fcoe->flags |= FCOE_HAVE_FIP_FCF;
633
+			fcoe->priority = priority->priority;
634
+			if ( fka_adv_p->flags & FIP_NO_KEEPALIVE ) {
635
+				fcoe->keepalive = 0;
636
+			} else {
637
+				fcoe->keepalive = ntohl ( fka_adv_p->period );
638
+			}
639
+			memcpy ( fcoe->fcf_mac, mac_address->mac,
640
+				 sizeof ( fcoe->fcf_mac ) );
641
+			DBGC ( fcoe, "FCoE %s selected FCF %s (priority %d, ",
642
+			       fcoe->netdev->name, eth_ntoa ( fcoe->fcf_mac ),
643
+			       fcoe->priority );
644
+			if ( fcoe->keepalive ) {
645
+				DBGC ( fcoe, "keepalive %dms)\n",
646
+				       fcoe->keepalive );
647
+			} else {
648
+				DBGC ( fcoe, "no keepalive)\n" );
649
+			}
650
+		}
651
+
652
+	} else if ( fcoe->flags & FCOE_HAVE_FIP_FCF ) {
653
+
654
+		/* We are checking that the FCF remains alive.  Reset
655
+		 * the timeout counter if this is an advertisement
656
+		 * from our forwarder.
657
+		 */
658
+		if ( memcmp ( fcoe->fcf_mac, mac_address->mac,
659
+			      sizeof ( fcoe->fcf_mac ) ) == 0 ) {
660
+			fcoe->timeouts = 0;
661
+		}
662
+
663
+	} else {
664
+
665
+		/* We are operating in non-FIP mode and have received
666
+		 * a FIP advertisement.  Reset the link in order to
667
+		 * attempt FIP.
668
+		 */
669
+		fcoe_reset ( fcoe );
670
+
671
+	}
672
+
673
+	return 0;
674
+}
675
+
676
+/**
677
+ * Handle received FIP ELS response
678
+ *
679
+ * @v fcoe		FCoE port
680
+ * @v descs		Descriptor list
681
+ * @v flags		Flags
682
+ * @ret rc		Return status code
683
+ */
684
+static int fcoe_fip_rx_els_response ( struct fcoe_port *fcoe,
685
+				      struct fip_descriptors *descs,
686
+				      unsigned int flags __unused ) {
687
+	struct fip_els *flogi = fip_flogi ( descs );
688
+	struct fip_mac_address *mac_address = fip_mac_address ( descs );
689
+	void *frame;
690
+	size_t frame_len;
691
+	int rc;
692
+
693
+	/* Sanity checks */
694
+	if ( ! flogi ) {
695
+		DBGC ( fcoe, "FCoE %s received ELS response missing FLOGI\n",
696
+		       fcoe->netdev->name );
697
+		return -EINVAL;
698
+	}
699
+	if ( ! mac_address ) {
700
+		DBGC ( fcoe, "FCoE %s received ELS response missing MAC "
701
+		       "address\n", fcoe->netdev->name );
702
+		return -EINVAL;
703
+	}
704
+
705
+	/* Record local MAC address */
706
+	memcpy ( fcoe->local_mac, mac_address->mac, sizeof ( fcoe->local_mac ));
707
+
708
+	/* Hand off via transport interface */
709
+	frame = &flogi->fc;
710
+	frame_len = ( ( flogi->len * 4 ) - offsetof ( typeof ( *flogi ), fc ) );
711
+	if ( ( rc = xfer_deliver_raw ( &fcoe->transport, frame,
712
+				       frame_len ) ) != 0 ) {
713
+		DBGC ( fcoe, "FCoE %s could not deliver FIP FLOGI frame: %s\n",
714
+		       fcoe->netdev->name, strerror ( rc ) );
715
+		return rc;
716
+	}
717
+
718
+	return 0;
719
+}
720
+
721
+/**
722
+ * Send FIP keepalive
723
+ *
724
+ * @v fcoe		FCoE port
725
+ * @ret rc		Return status code
726
+ */
727
+static int fcoe_fip_tx_keepalive ( struct fcoe_port *fcoe ) {
728
+	struct io_buffer *iobuf;
729
+	struct {
730
+		struct fip_header hdr;
731
+		struct fip_mac_address mac_address;
732
+	} __attribute__ (( packed )) *keepalive;
733
+	int rc;
734
+
735
+	/* Allocate I/O buffer */
736
+	iobuf = alloc_iob ( MAX_LL_HEADER_LEN + sizeof ( *keepalive ) );
737
+	if ( ! iobuf )
738
+		return -ENOMEM;
739
+	iob_reserve ( iobuf, MAX_LL_HEADER_LEN );
740
+
741
+	/* Construct keepalive */
742
+	keepalive = iob_put ( iobuf, sizeof ( *keepalive ) );
743
+	memset ( keepalive, 0, sizeof ( *keepalive ) );
744
+	keepalive->hdr.version = FIP_VERSION;
745
+	keepalive->hdr.code = htons ( FIP_CODE_MAINTAIN );
746
+	keepalive->hdr.subcode = FIP_MAINTAIN_KEEP_ALIVE;
747
+	keepalive->hdr.len =	htons ( ( sizeof ( *keepalive ) -
748
+					  sizeof ( keepalive->hdr ) ) / 4 );
749
+	keepalive->mac_address.type = FIP_MAC_ADDRESS;
750
+	keepalive->mac_address.len =
751
+		( sizeof ( keepalive->mac_address ) / 4 );
752
+	memcpy ( keepalive->mac_address.mac, fcoe->netdev->ll_addr,
753
+		 sizeof ( keepalive->mac_address.mac ) );
754
+
755
+	/* Send keepalive */
756
+	if ( ( rc = net_tx ( iob_disown ( iobuf ), fcoe->netdev,
757
+			     &fip_protocol, fcoe->fcf_mac,
758
+			     fcoe->netdev->ll_addr ) ) != 0 ) {
759
+		DBGC ( fcoe, "FCoE %s could not send keepalive: %s\n",
760
+		       fcoe->netdev->name, strerror ( rc ) );
761
+		return rc;
762
+	}
763
+
764
+	return 0;
765
+}
766
+
767
+/** A FIP handler */
768
+struct fip_handler {
769
+	/** Protocol code */
770
+	uint16_t code;
771
+	/** Protocol subcode */
772
+	uint8_t subcode;
773
+	/**
774
+	 * Receive FIP packet
775
+	 *
776
+	 * @v fcoe		FCoE port
777
+	 * @v descs		Descriptor list
778
+	 * @v flags		Flags
779
+	 * @ret rc		Return status code
780
+	 */
781
+	int ( * rx ) ( struct fcoe_port *fcoe, struct fip_descriptors *descs,
782
+		       unsigned int flags );
783
+};
784
+
785
+/** FIP handlers */
786
+static struct fip_handler fip_handlers[] = {
787
+	{ FIP_CODE_DISCOVERY, FIP_DISCOVERY_ADVERTISE,
788
+	  fcoe_fip_rx_advertisement },
789
+	{ FIP_CODE_ELS, FIP_ELS_RESPONSE,
790
+	  fcoe_fip_rx_els_response },
791
+};
792
+
793
+/**
794
+ * Process incoming FIP packets
795
+ *
796
+ * @v iobuf		I/O buffer
797
+ * @v netdev		Network device
798
+ * @v ll_dest		Link-layer destination address
799
+ * @v ll_source		Link-layer source address
800
+ * @ret rc		Return status code
801
+ */
802
+static int fcoe_fip_rx ( struct io_buffer *iobuf,
803
+			 struct net_device *netdev,
804
+			 const void *ll_dest,
805
+			 const void *ll_source __unused ) {
806
+	struct fip_header *fiphdr = iobuf->data;
807
+	struct fip_descriptors descs;
808
+	struct fip_handler *handler;
809
+	struct fcoe_port *fcoe;
810
+	unsigned int i;
811
+	int rc;
812
+
813
+	/* Identify FCoE port */
814
+	if ( ( fcoe = fcoe_demux ( netdev ) ) == NULL ) {
815
+		DBG ( "FCoE received FIP frame for net device %s missing FCoE "
816
+		      "port\n", netdev->name );
817
+		rc = -ENOTCONN;
818
+		goto done;
819
+	}
820
+
821
+	/* Discard packets not destined for us */
822
+	if ( ( memcmp ( fcoe->netdev->ll_addr, ll_dest, ETH_ALEN ) != 0 ) &&
823
+	     ( memcmp ( all_fcoe_macs, ll_dest,
824
+			sizeof ( all_fcoe_macs ) ) != 0 ) &&
825
+	     ( memcmp ( all_enode_macs, ll_dest,
826
+			sizeof ( all_enode_macs ) ) != 0 ) ) {
827
+		DBGC2 ( fcoe, "FCoE %s ignoring FIP packet for %s\n",
828
+			fcoe->netdev->name, eth_ntoa ( ll_dest ) );
829
+		rc = -ENOTCONN;
830
+		goto done;
831
+	}
832
+
833
+	/* Parse FIP packet */
834
+	if ( ( rc = fcoe_fip_parse ( fcoe, fiphdr, iob_len ( iobuf ),
835
+				     &descs ) ) != 0 )
836
+		goto done;
837
+
838
+	/* Find a suitable handler */
839
+	for ( i = 0 ; i < ( sizeof ( fip_handlers ) /
840
+			    sizeof ( fip_handlers[0] ) ) ; i++ ) {
841
+		handler = &fip_handlers[i];
842
+		if ( ( handler->code == ntohs ( fiphdr->code ) ) &&
843
+		     ( handler->subcode == fiphdr->subcode ) ) {
844
+			rc = handler->rx ( fcoe, &descs,
845
+					   ntohs ( fiphdr->flags ) );
846
+			goto done;
847
+		}
848
+	}
849
+	DBGC ( fcoe, "FCoE %s received unsupported FIP code %04x.%02x\n",
850
+	       fcoe->netdev->name, ntohs ( fiphdr->code ), fiphdr->subcode );
851
+	rc = -ENOTSUP;
852
+
853
+ done:
854
+	free_iob ( iobuf );
855
+	return rc;
856
+}
857
+
858
+/******************************************************************************
859
+ *
860
+ * FCoE ports
861
+ *
862
+ ******************************************************************************
863
+ */
864
+
865
+/**
866
+ * Handle FCoE timer expiry
867
+ *
868
+ * @v timer		FIP timer
869
+ * @v over		Timer expired
870
+ */
871
+static void fcoe_expired ( struct retry_timer *timer, int over __unused ) {
872
+	struct fcoe_port *fcoe =
873
+		container_of ( timer, struct fcoe_port, timer );
874
+
875
+	/* Sanity check */
876
+	assert ( fcoe->flags & FCOE_HAVE_NETWORK );
877
+
878
+	/* Increment the timeout counter */
879
+	fcoe->timeouts++;
880
+
881
+	if ( ! ( fcoe->flags & FCOE_HAVE_FCF ) ) {
882
+
883
+		/* If we have not yet found a FIP-capable forwarder,
884
+		 * and we have not yet timed out and given up on
885
+		 * finding one, then send a FIP solicitation and wait.
886
+		 */
887
+		if ( ( ! ( fcoe->flags & FCOE_HAVE_FIP_FCF ) ) &&
888
+		     ( fcoe->timeouts <= FCOE_MAX_FIP_SOLICITATIONS ) ) {
889
+			start_timer_fixed ( &fcoe->timer,
890
+					    FCOE_FIP_RETRY_DELAY );
891
+			fcoe_fip_tx_solicitation ( fcoe );
892
+			return;
893
+		}
894
+
895
+		/* Either we have found a FIP-capable forwarder, or we
896
+		 * have timed out and will fall back to pre-FIP mode.
897
+		 */
898
+		fcoe->flags |= FCOE_HAVE_FCF;
899
+		fcoe->timeouts = 0;
900
+		DBGC ( fcoe, "FCoE %s using %sFIP FCF %s\n", fcoe->netdev->name,
901
+		       ( ( fcoe->flags & FCOE_HAVE_FIP_FCF ) ? "" : "non-" ),
902
+		       eth_ntoa ( fcoe->fcf_mac ) );
903
+
904
+		/* Start sending keepalives if applicable */
905
+		if ( fcoe->keepalive )
906
+			start_timer_nodelay ( &fcoe->timer );
907
+
908
+		/* Send notification of window change */
909
+		xfer_window_changed ( &fcoe->transport );
910
+
911
+	} else {
912
+
913
+		/* Send keepalive */
914
+		start_timer_fixed ( &fcoe->timer,
915
+			      ( ( fcoe->keepalive * TICKS_PER_SEC ) / 1000 ) );
916
+		fcoe_fip_tx_keepalive ( fcoe );
917
+
918
+		/* Abandon FCF if we have not seen its advertisements */
919
+		if ( fcoe->timeouts > FCOE_MAX_FIP_MISSING_KEEPALIVES ) {
920
+			DBGC ( fcoe, "FCoE %s abandoning FCF %s\n",
921
+			       fcoe->netdev->name, eth_ntoa ( fcoe->fcf_mac ));
922
+			fcoe_reset ( fcoe );
923
+		}
924
+	}
925
+}
926
+
296 927
 /**
297 928
  * Create FCoE port
298 929
  *
@@ -302,8 +933,6 @@ static struct interface_descriptor fcoe_transport_desc =
302 933
 static int fcoe_probe ( struct net_device *netdev ) {
303 934
 	struct ll_protocol *ll_protocol = netdev->ll_protocol;
304 935
 	struct fcoe_port *fcoe;
305
-	union fcoe_name node_wwn;
306
-	union fcoe_name port_wwn;
307 936
 	int rc;
308 937
 
309 938
 	/* Sanity check */
@@ -313,7 +942,6 @@ static int fcoe_probe ( struct net_device *netdev ) {
313 942
 		rc = 0;
314 943
 		goto err_non_ethernet;
315 944
 	}
316
-	assert ( ll_protocol->ll_addr_len == sizeof ( fcoe->fcf_ll_addr ) );
317 945
 
318 946
 	/* Allocate and initialise structure */
319 947
 	fcoe = zalloc ( sizeof ( *fcoe ) );
@@ -323,27 +951,24 @@ static int fcoe_probe ( struct net_device *netdev ) {
323 951
 	}
324 952
 	ref_init ( &fcoe->refcnt, NULL );
325 953
 	intf_init ( &fcoe->transport, &fcoe_transport_desc, &fcoe->refcnt );
954
+	timer_init ( &fcoe->timer, fcoe_expired, &fcoe->refcnt );
326 955
 	fcoe->netdev = netdev_get ( netdev );
327 956
 
328 957
 	/* Construct node and port names */
329
-	node_wwn.fcoe.authority = htons ( FCOE_AUTHORITY_IEEE );
330
-	memcpy ( &node_wwn.fcoe.mac, netdev->ll_addr,
331
-		 sizeof ( node_wwn.fcoe.mac ) );
332
-	port_wwn.fcoe.authority = htons ( FCOE_AUTHORITY_IEEE_EXTENDED );
333
-	memcpy ( &port_wwn.fcoe.mac, netdev->ll_addr,
334
-		 sizeof ( port_wwn.fcoe.mac ) );
335
-
336
-	/* Construct initial FCF address */
337
-	memcpy ( &fcoe->fcf_ll_addr, &fcoe_default_fcf_ll_addr,
338
-		 sizeof ( fcoe->fcf_ll_addr ) );
958
+	fcoe->node_wwn.fcoe.authority = htons ( FCOE_AUTHORITY_IEEE );
959
+	memcpy ( &fcoe->node_wwn.fcoe.mac, netdev->ll_addr,
960
+		 sizeof ( fcoe->node_wwn.fcoe.mac ) );
961
+	fcoe->port_wwn.fcoe.authority = htons ( FCOE_AUTHORITY_IEEE_EXTENDED );
962
+	memcpy ( &fcoe->port_wwn.fcoe.mac, netdev->ll_addr,
963
+		 sizeof ( fcoe->port_wwn.fcoe.mac ) );
339 964
 
340 965
 	DBGC ( fcoe, "FCoE %s is %s", fcoe->netdev->name,
341
-	       fc_ntoa ( &node_wwn.fc ) );
342
-	DBGC ( fcoe, " port %s\n", fc_ntoa ( &port_wwn.fc ) );
966
+	       fc_ntoa ( &fcoe->node_wwn.fc ) );
967
+	DBGC ( fcoe, " port %s\n", fc_ntoa ( &fcoe->port_wwn.fc ) );
343 968
 
344 969
 	/* Attach Fibre Channel port */
345
-	if ( ( rc = fc_port_open ( &fcoe->transport, &node_wwn.fc,
346
-				   &port_wwn.fc ) ) != 0 )
970
+	if ( ( rc = fc_port_open ( &fcoe->transport, &fcoe->node_wwn.fc,
971
+				   &fcoe->port_wwn.fc ) ) != 0 )
347 972
 		goto err_fc_create;
348 973
 
349 974
 	/* Transfer reference to port list */
@@ -372,8 +997,8 @@ static void fcoe_notify ( struct net_device *netdev ) {
372 997
 		return;
373 998
 	}
374 999
 
375
-	/* Send notification of potential window change */
376
-	xfer_window_changed ( &fcoe->transport );
1000
+	/* Reset the FCoE link */
1001
+	fcoe_reset ( fcoe );
377 1002
 }
378 1003
 
379 1004
 /**
@@ -410,6 +1035,13 @@ struct net_protocol fcoe_protocol __net_protocol = {
410 1035
 	.rx = fcoe_rx,
411 1036
 };
412 1037
 
1038
+/** FIP protocol */
1039
+struct net_protocol fip_protocol __net_protocol = {
1040
+	.name = "FIP",
1041
+	.net_proto = htons ( ETH_P_FIP ),
1042
+	.rx = fcoe_fip_rx,
1043
+};
1044
+
413 1045
 /** Human-readable message for CRC errors
414 1046
  *
415 1047
  * It seems as though several drivers neglect to strip the Ethernet

Loading…
Annulla
Salva