|
@@ -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
|