|
|
@@ -35,6 +35,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
|
35
|
35
|
#include <ipxe/iobuf.h>
|
|
36
|
36
|
#include <ipxe/fc.h>
|
|
37
|
37
|
#include <ipxe/fcels.h>
|
|
|
38
|
+#include <ipxe/fcns.h>
|
|
38
|
39
|
|
|
39
|
40
|
/** @file
|
|
40
|
41
|
*
|
|
|
@@ -61,6 +62,9 @@ struct fc_port_id fc_empty_port_id = { .bytes = { 0x00, 0x00, 0x00 } };
|
|
61
|
62
|
/** F_Port contoller port ID */
|
|
62
|
63
|
struct fc_port_id fc_f_port_id = { .bytes = { 0xff, 0xff, 0xfe } };
|
|
63
|
64
|
|
|
|
65
|
+/** Generic services port ID */
|
|
|
66
|
+struct fc_port_id fc_gs_port_id = { .bytes = { 0xff, 0xff, 0xfc } };
|
|
|
67
|
+
|
|
64
|
68
|
/** Point-to-point low port ID */
|
|
65
|
69
|
struct fc_port_id fc_ptp_low_port_id = { .bytes = { 0x01, 0x01, 0x01 } };
|
|
66
|
70
|
|
|
|
@@ -464,14 +468,24 @@ static int fc_xchg_tx ( struct fc_exchange *xchg, struct io_buffer *iobuf,
|
|
464
|
468
|
}
|
|
465
|
469
|
|
|
466
|
470
|
/* Calculate routing control */
|
|
467
|
|
- if ( xchg->type == FC_TYPE_ELS ) {
|
|
|
471
|
+ switch ( xchg->type ) {
|
|
|
472
|
+ case FC_TYPE_ELS:
|
|
468
|
473
|
r_ctl = FC_R_CTL_ELS;
|
|
469
|
474
|
if ( meta->flags & XFER_FL_RESPONSE ) {
|
|
470
|
475
|
r_ctl |= FC_R_CTL_SOL_CTRL;
|
|
471
|
476
|
} else {
|
|
472
|
477
|
r_ctl |= FC_R_CTL_UNSOL_CTRL;
|
|
473
|
478
|
}
|
|
474
|
|
- } else {
|
|
|
479
|
+ break;
|
|
|
480
|
+ case FC_TYPE_CT:
|
|
|
481
|
+ r_ctl = FC_R_CTL_DATA;
|
|
|
482
|
+ if ( meta->flags & XFER_FL_RESPONSE ) {
|
|
|
483
|
+ r_ctl |= FC_R_CTL_SOL_CTRL;
|
|
|
484
|
+ } else {
|
|
|
485
|
+ r_ctl |= FC_R_CTL_UNSOL_CTRL;
|
|
|
486
|
+ }
|
|
|
487
|
+ break;
|
|
|
488
|
+ default:
|
|
475
|
489
|
r_ctl = FC_R_CTL_DATA;
|
|
476
|
490
|
switch ( meta->flags &
|
|
477
|
491
|
( XFER_FL_CMD_STAT | XFER_FL_RESPONSE ) ) {
|
|
|
@@ -488,6 +502,7 @@ static int fc_xchg_tx ( struct fc_exchange *xchg, struct io_buffer *iobuf,
|
|
488
|
502
|
r_ctl |= FC_R_CTL_UNSOL_DATA;
|
|
489
|
503
|
break;
|
|
490
|
504
|
}
|
|
|
505
|
+ break;
|
|
491
|
506
|
}
|
|
492
|
507
|
|
|
493
|
508
|
/* Calculate exchange and sequence control */
|
|
|
@@ -799,6 +814,7 @@ static void fc_port_close ( struct fc_port *port, int rc ) {
|
|
799
|
814
|
/* Shut down interfaces */
|
|
800
|
815
|
intf_shutdown ( &port->transport, rc );
|
|
801
|
816
|
intf_shutdown ( &port->flogi, rc );
|
|
|
817
|
+ intf_shutdown ( &port->ns_plogi, rc );
|
|
802
|
818
|
|
|
803
|
819
|
/* Shut down any remaining exchanges */
|
|
804
|
820
|
list_for_each_entry_safe ( xchg, tmp, &port->xchgs, list )
|
|
|
@@ -922,6 +938,7 @@ int fc_port_login ( struct fc_port *port, struct fc_port_id *port_id,
|
|
922
|
938
|
const struct fc_name *link_port_wwn, int has_fabric ) {
|
|
923
|
939
|
struct fc_peer *peer;
|
|
924
|
940
|
struct fc_peer *tmp;
|
|
|
941
|
+ int rc;
|
|
925
|
942
|
|
|
926
|
943
|
/* Perform implicit logout if logged in and details differ */
|
|
927
|
944
|
if ( fc_link_ok ( &port->link ) &&
|
|
|
@@ -978,6 +995,23 @@ int fc_port_login ( struct fc_port *port, struct fc_port_id *port_id,
|
|
978
|
995
|
fc_id_ntoa ( &port->port_id ) );
|
|
979
|
996
|
}
|
|
980
|
997
|
|
|
|
998
|
+ /* Log in to name server, if attached to a fabric */
|
|
|
999
|
+ if ( has_fabric && ! ( port->flags & FC_PORT_HAS_NS ) ) {
|
|
|
1000
|
+
|
|
|
1001
|
+ DBGC ( port, "FCPORT %s attempting login to name server\n",
|
|
|
1002
|
+ port->name );
|
|
|
1003
|
+
|
|
|
1004
|
+ intf_restart ( &port->ns_plogi, -ECANCELED );
|
|
|
1005
|
+ if ( ( rc = fc_els_plogi ( &port->ns_plogi, port,
|
|
|
1006
|
+ &fc_gs_port_id ) ) != 0 ) {
|
|
|
1007
|
+ DBGC ( port, "FCPORT %s could not initiate name "
|
|
|
1008
|
+ "server PLOGI: %s\n",
|
|
|
1009
|
+ port->name, strerror ( rc ) );
|
|
|
1010
|
+ fc_port_logout ( port, rc );
|
|
|
1011
|
+ return rc;
|
|
|
1012
|
+ }
|
|
|
1013
|
+ }
|
|
|
1014
|
+
|
|
981
|
1015
|
/* Record login */
|
|
982
|
1016
|
fc_link_up ( &port->link );
|
|
983
|
1017
|
|
|
|
@@ -1006,6 +1040,7 @@ void fc_port_logout ( struct fc_port *port, int rc ) {
|
|
1006
|
1040
|
|
|
1007
|
1041
|
/* Erase port details */
|
|
1008
|
1042
|
memset ( &port->port_id, 0, sizeof ( port->port_id ) );
|
|
|
1043
|
+ port->flags = 0;
|
|
1009
|
1044
|
|
|
1010
|
1045
|
/* Record logout */
|
|
1011
|
1046
|
fc_link_err ( &port->link, rc );
|
|
|
@@ -1032,6 +1067,27 @@ static void fc_port_flogi_done ( struct fc_port *port, int rc ) {
|
|
1032
|
1067
|
fc_port_logout ( port, rc );
|
|
1033
|
1068
|
}
|
|
1034
|
1069
|
|
|
|
1070
|
+/**
|
|
|
1071
|
+ * Handle name server PLOGI completion
|
|
|
1072
|
+ *
|
|
|
1073
|
+ * @v port Fibre Channel port
|
|
|
1074
|
+ * @v rc Reason for completion
|
|
|
1075
|
+ */
|
|
|
1076
|
+static void fc_port_ns_plogi_done ( struct fc_port *port, int rc ) {
|
|
|
1077
|
+
|
|
|
1078
|
+ intf_restart ( &port->ns_plogi, rc );
|
|
|
1079
|
+
|
|
|
1080
|
+ if ( rc == 0 ) {
|
|
|
1081
|
+ port->flags |= FC_PORT_HAS_NS;
|
|
|
1082
|
+ DBGC ( port, "FCPORT %s logged in to name server\n",
|
|
|
1083
|
+ port->name );
|
|
|
1084
|
+ } else {
|
|
|
1085
|
+ DBGC ( port, "FCPORT %s could not log in to name server: %s\n",
|
|
|
1086
|
+ port->name, strerror ( rc ) );
|
|
|
1087
|
+ /* Absence of a name server is not a fatal error */
|
|
|
1088
|
+ }
|
|
|
1089
|
+}
|
|
|
1090
|
+
|
|
1035
|
1091
|
/**
|
|
1036
|
1092
|
* Examine Fibre Channel port link state
|
|
1037
|
1093
|
*
|
|
|
@@ -1107,6 +1163,15 @@ static struct interface_operation fc_port_flogi_op[] = {
|
|
1107
|
1163
|
static struct interface_descriptor fc_port_flogi_desc =
|
|
1108
|
1164
|
INTF_DESC ( struct fc_port, flogi, fc_port_flogi_op );
|
|
1109
|
1165
|
|
|
|
1166
|
+/** Fibre Channel port name server PLOGI interface operations */
|
|
|
1167
|
+static struct interface_operation fc_port_ns_plogi_op[] = {
|
|
|
1168
|
+ INTF_OP ( intf_close, struct fc_port *, fc_port_ns_plogi_done ),
|
|
|
1169
|
+};
|
|
|
1170
|
+
|
|
|
1171
|
+/** Fibre Channel port name server PLOGI interface descriptor */
|
|
|
1172
|
+static struct interface_descriptor fc_port_ns_plogi_desc =
|
|
|
1173
|
+ INTF_DESC ( struct fc_port, ns_plogi, fc_port_ns_plogi_op );
|
|
|
1174
|
+
|
|
1110
|
1175
|
/**
|
|
1111
|
1176
|
* Create Fibre Channel port
|
|
1112
|
1177
|
*
|
|
|
@@ -1128,6 +1193,7 @@ int fc_port_open ( struct interface *transport, const struct fc_name *node_wwn,
|
|
1128
|
1193
|
intf_init ( &port->transport, &fc_port_transport_desc, &port->refcnt );
|
|
1129
|
1194
|
fc_link_init ( &port->link, fc_port_examine, &port->refcnt );
|
|
1130
|
1195
|
intf_init ( &port->flogi, &fc_port_flogi_desc, &port->refcnt );
|
|
|
1196
|
+ intf_init ( &port->ns_plogi, &fc_port_ns_plogi_desc, &port->refcnt );
|
|
1131
|
1197
|
list_add_tail ( &port->list, &fc_ports );
|
|
1132
|
1198
|
INIT_LIST_HEAD ( &port->xchgs );
|
|
1133
|
1199
|
memcpy ( &port->node_wwn, node_wwn, sizeof ( port->node_wwn ) );
|
|
|
@@ -1162,26 +1228,6 @@ struct fc_port * fc_port_find ( const char *name ) {
|
|
1162
|
1228
|
return NULL;
|
|
1163
|
1229
|
}
|
|
1164
|
1230
|
|
|
1165
|
|
-/**
|
|
1166
|
|
- * Find Fibre Channel port by link node name
|
|
1167
|
|
- *
|
|
1168
|
|
- * @v link_port_wwn Link node name
|
|
1169
|
|
- * @ret port Fibre Channel port, or NULL
|
|
1170
|
|
- */
|
|
1171
|
|
-static struct fc_port *
|
|
1172
|
|
-fc_port_find_link_wwn ( struct fc_name *link_port_wwn ) {
|
|
1173
|
|
- struct fc_port *port;
|
|
1174
|
|
-
|
|
1175
|
|
- list_for_each_entry ( port, &fc_ports, list ) {
|
|
1176
|
|
- if ( fc_link_ok ( &port->link ) &&
|
|
1177
|
|
- ( memcmp ( &port->link_port_wwn, link_port_wwn,
|
|
1178
|
|
- sizeof ( port->link_port_wwn ) ) == 0 ) ) {
|
|
1179
|
|
- return port;
|
|
1180
|
|
- }
|
|
1181
|
|
- }
|
|
1182
|
|
- return NULL;
|
|
1183
|
|
-}
|
|
1184
|
|
-
|
|
1185
|
1231
|
/******************************************************************************
|
|
1186
|
1232
|
*
|
|
1187
|
1233
|
* Fibre Channel peers
|
|
|
@@ -1339,6 +1385,30 @@ static void fc_peer_plogi_done ( struct fc_peer *peer, int rc ) {
|
|
1339
|
1385
|
fc_peer_logout ( peer, rc );
|
|
1340
|
1386
|
}
|
|
1341
|
1387
|
|
|
|
1388
|
+/**
|
|
|
1389
|
+ * Initiate PLOGI
|
|
|
1390
|
+ *
|
|
|
1391
|
+ * @v peer Fibre Channel peer
|
|
|
1392
|
+ * @v port Fibre Channel port
|
|
|
1393
|
+ * @v peer_port_id Peer port ID
|
|
|
1394
|
+ * @ret rc Return status code
|
|
|
1395
|
+ */
|
|
|
1396
|
+static int fc_peer_plogi ( struct fc_peer *peer, struct fc_port *port,
|
|
|
1397
|
+ struct fc_port_id *peer_port_id ) {
|
|
|
1398
|
+ int rc;
|
|
|
1399
|
+
|
|
|
1400
|
+ /* Try to create PLOGI ELS */
|
|
|
1401
|
+ intf_restart ( &peer->plogi, -ECANCELED );
|
|
|
1402
|
+ if ( ( rc = fc_els_plogi ( &peer->plogi, port, peer_port_id ) ) != 0 ) {
|
|
|
1403
|
+ DBGC ( peer, "FCPEER %s could not initiate PLOGI: %s\n",
|
|
|
1404
|
+ fc_ntoa ( &peer->port_wwn ), strerror ( rc ) );
|
|
|
1405
|
+ fc_peer_logout ( peer, rc );
|
|
|
1406
|
+ return rc;
|
|
|
1407
|
+ }
|
|
|
1408
|
+
|
|
|
1409
|
+ return 0;
|
|
|
1410
|
+}
|
|
|
1411
|
+
|
|
1342
|
1412
|
/**
|
|
1343
|
1413
|
* Examine Fibre Channel peer link state
|
|
1344
|
1414
|
*
|
|
|
@@ -1347,7 +1417,6 @@ static void fc_peer_plogi_done ( struct fc_peer *peer, int rc ) {
|
|
1347
|
1417
|
static void fc_peer_examine ( struct fc_link_state *link ) {
|
|
1348
|
1418
|
struct fc_peer *peer = container_of ( link, struct fc_peer, link );
|
|
1349
|
1419
|
struct fc_port *port;
|
|
1350
|
|
- struct fc_port_id *peer_port_id;
|
|
1351
|
1420
|
int rc;
|
|
1352
|
1421
|
|
|
1353
|
1422
|
/* Check to see if underlying port link has gone down */
|
|
|
@@ -1366,23 +1435,36 @@ static void fc_peer_examine ( struct fc_link_state *link ) {
|
|
1366
|
1435
|
/* Sanity check */
|
|
1367
|
1436
|
assert ( peer->port == NULL );
|
|
1368
|
1437
|
|
|
1369
|
|
- /* Look for a port with the peer attached via a point-to-point link */
|
|
1370
|
|
- port = fc_port_find_link_wwn ( &peer->port_wwn );
|
|
1371
|
|
- if ( ! port ) {
|
|
1372
|
|
- DBGC ( peer, "FCPEER %s could not find a point-to-point "
|
|
1373
|
|
- "link\n", fc_ntoa ( &peer->port_wwn ) );
|
|
1374
|
|
- fc_peer_logout ( peer, -ENOENT );
|
|
1375
|
|
- return;
|
|
|
1438
|
+ /* First, look for a port with the peer attached via a
|
|
|
1439
|
+ * point-to-point link.
|
|
|
1440
|
+ */
|
|
|
1441
|
+ list_for_each_entry ( port, &fc_ports, list ) {
|
|
|
1442
|
+ if ( fc_link_ok ( &port->link ) &&
|
|
|
1443
|
+ ( ! ( port->flags & FC_PORT_HAS_FABRIC ) ) &&
|
|
|
1444
|
+ ( memcmp ( &peer->port_wwn, &port->link_port_wwn,
|
|
|
1445
|
+ sizeof ( peer->port_wwn ) ) == 0 ) ) {
|
|
|
1446
|
+ /* Use this peer port ID, and stop looking */
|
|
|
1447
|
+ fc_peer_plogi ( peer, port, &port->ptp_link_port_id );
|
|
|
1448
|
+ return;
|
|
|
1449
|
+ }
|
|
1376
|
1450
|
}
|
|
1377
|
|
- peer_port_id = &port->ptp_link_port_id;
|
|
1378
|
1451
|
|
|
1379
|
|
- /* Try to create PLOGI ELS */
|
|
1380
|
|
- intf_restart ( &peer->plogi, -ECANCELED );
|
|
1381
|
|
- if ( ( rc = fc_els_plogi ( &peer->plogi, port, peer_port_id ) ) != 0 ) {
|
|
1382
|
|
- DBGC ( peer, "FCPEER %s could not initiate PLOGI: %s\n",
|
|
1383
|
|
- fc_ntoa ( &peer->port_wwn ), strerror ( rc ) );
|
|
1384
|
|
- fc_peer_logout ( peer, rc );
|
|
1385
|
|
- return;
|
|
|
1452
|
+ /* If the peer is not directly attached, try initiating a name
|
|
|
1453
|
+ * server lookup on any suitable ports.
|
|
|
1454
|
+ */
|
|
|
1455
|
+ list_for_each_entry ( port, &fc_ports, list ) {
|
|
|
1456
|
+ if ( fc_link_ok ( &port->link ) &&
|
|
|
1457
|
+ ( port->flags & FC_PORT_HAS_FABRIC ) &&
|
|
|
1458
|
+ ( port->flags & FC_PORT_HAS_NS ) ) {
|
|
|
1459
|
+ if ( ( rc = fc_ns_query ( peer, port,
|
|
|
1460
|
+ fc_peer_plogi ) ) != 0 ) {
|
|
|
1461
|
+ DBGC ( peer, "FCPEER %s could not attempt "
|
|
|
1462
|
+ "name server lookup on %s: %s\n",
|
|
|
1463
|
+ fc_ntoa ( &peer->port_wwn ), port->name,
|
|
|
1464
|
+ strerror ( rc ) );
|
|
|
1465
|
+ /* Non-fatal */
|
|
|
1466
|
+ }
|
|
|
1467
|
+ }
|
|
1386
|
1468
|
}
|
|
1387
|
1469
|
}
|
|
1388
|
1470
|
|