Browse Source

[fc] Add support for Fibre Channel name server lookups

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 14 years ago
parent
commit
8e718df5e1
5 changed files with 585 additions and 38 deletions
  1. 1
    0
      src/include/ipxe/errfile.h
  2. 7
    0
      src/include/ipxe/fc.h
  3. 217
    0
      src/include/ipxe/fcns.h
  4. 120
    38
      src/net/fc.c
  5. 240
    0
      src/net/fcns.c

+ 1
- 0
src/include/ipxe/errfile.h View File

@@ -189,6 +189,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
189 189
 #define ERRFILE_fcels			( ERRFILE_NET | 0x002c0000 )
190 190
 #define ERRFILE_fcp			( ERRFILE_NET | 0x002d0000 )
191 191
 #define ERRFILE_fcoe			( ERRFILE_NET | 0x002e0000 )
192
+#define ERRFILE_fcns			( ERRFILE_NET | 0x002f0000 )
192 193
 
193 194
 #define ERRFILE_image		      ( ERRFILE_IMAGE | 0x00000000 )
194 195
 #define ERRFILE_elf		      ( ERRFILE_IMAGE | 0x00010000 )

+ 7
- 0
src/include/ipxe/fc.h View File

@@ -64,6 +64,7 @@ struct sockaddr_fc {
64 64
 
65 65
 extern struct fc_port_id fc_empty_port_id;
66 66
 extern struct fc_port_id fc_f_port_id;
67
+extern struct fc_port_id fc_gs_port_id;
67 68
 extern struct fc_port_id fc_ptp_low_port_id;
68 69
 extern struct fc_port_id fc_ptp_high_port_id;
69 70
 
@@ -190,6 +191,7 @@ enum fc_type {
190 191
 	FC_TYPE_BLS = 0x00,		/**< Basic Link Service */
191 192
 	FC_TYPE_ELS = 0x01,		/**< Extended Link Service */
192 193
 	FC_TYPE_FCP = 0x08,		/**< Fibre Channel Protocol */
194
+	FC_TYPE_CT  = 0x20,		/**< Common Transport */
193 195
 };
194 196
 
195 197
 /** Fibre Channel Frame Control - Exchange and Sequence */
@@ -277,6 +279,9 @@ struct fc_port {
277 279
 	/** Link port ID (for point-to-point links only) */
278 280
 	struct fc_port_id ptp_link_port_id;
279 281
 
282
+	/** Name server PLOGI interface */
283
+	struct interface ns_plogi;
284
+
280 285
 	/** List of active exchanges */
281 286
 	struct list_head xchgs;
282 287
 };
@@ -285,6 +290,8 @@ struct fc_port {
285 290
 enum fc_port_flags {
286 291
 	/** Port is attached to a fabric */
287 292
 	FC_PORT_HAS_FABRIC = 0x0001,
293
+	/** Port is logged in to a name server */
294
+	FC_PORT_HAS_NS = 0x0002,
288 295
 };
289 296
 
290 297
 /**

+ 217
- 0
src/include/ipxe/fcns.h View File

@@ -0,0 +1,217 @@
1
+#ifndef _IPXE_FCNS_H
2
+#define _IPXE_FCNS_H
3
+
4
+/**
5
+ * @file
6
+ *
7
+ * Fibre Channel name server lookups
8
+ *
9
+ */
10
+
11
+FILE_LICENCE ( GPL2_OR_LATER );
12
+
13
+#include <stdint.h>
14
+#include <ipxe/fc.h>
15
+
16
+/** A Fibre Channel Common Transport header */
17
+struct fc_ct_header {
18
+	/** Revision */
19
+	uint8_t revision;
20
+	/** Original requestor ID */
21
+	struct fc_port_id in_id;
22
+	/** Generic service type */
23
+	uint8_t type;
24
+	/** Generic service subtype */
25
+	uint8_t subtype;
26
+	/** Options */
27
+	uint8_t options;
28
+	/** Reserved */
29
+	uint8_t reserved;
30
+	/** Command/response code */
31
+	uint16_t code;
32
+	/** Maximum/residual size */
33
+	uint16_t size;
34
+	/** Fragment ID */
35
+	uint8_t fragment;
36
+	/** Reason code */
37
+	uint8_t reason;
38
+	/** Reason code explanation */
39
+	uint8_t explanation;
40
+	/** Vendor specific */
41
+	uint8_t vendor;
42
+} __attribute__ (( packed ));
43
+
44
+/** Fibre Channel Common Transport revision */
45
+#define FC_CT_REVISION 1
46
+
47
+/** Fibre Channel generic service type */
48
+enum fc_gs_type {
49
+	/** Directory service */
50
+	FC_GS_TYPE_DS = 0xfc,
51
+};
52
+
53
+/** Fibre Channel generic service response codes */
54
+enum fc_gs_response_code {
55
+	/** Accepted */
56
+	FC_GS_ACCEPT = 0x8002,
57
+	/** Rejected */
58
+	FC_GS_REJECT = 0x8001,
59
+};
60
+
61
+/** Fibre Channel generic service rejection reason codes */
62
+enum fc_gs_reason_code {
63
+	/** Invalid command code */
64
+	FC_GS_BAD_COMMAND = 0x01,
65
+	/** Invalid version level */
66
+	FC_GS_BAD_VERSION = 0x02,
67
+	/** Logical error */
68
+	FC_GS_ERROR = 0x03,
69
+	/** Invalid CT_IU size */
70
+	FC_GS_BAD_SIZE = 0x04,
71
+	/** Logical busy */
72
+	FC_GS_BUSY = 0x05,
73
+	/** Protocol error */
74
+	FC_GS_EPROTO = 0x07,
75
+	/** Unable to perform command request */
76
+	FC_GS_UNABLE = 0x09,
77
+	/** Command not supported */
78
+	FC_GS_ENOTSUP = 0x0b,
79
+	/** Server not available */
80
+	FC_GS_UNAVAILABLE = 0x0d,
81
+	/** Session could not be established */
82
+	FC_GS_SESSION = 0x0e,
83
+};
84
+
85
+/** Fibre Channel directory service subtype */
86
+enum fc_ds_subtype {
87
+	/** Name server */
88
+	FC_DS_SUBTYPE_NAME = 0x02,
89
+};
90
+
91
+/** Fibre Channel name server commands */
92
+enum fc_ns_command_nibble {
93
+	/** Get */
94
+	FC_NS_GET = 0x1,
95
+	/** Register */
96
+	FC_NS_REGISTER = 0x2,
97
+	/** De-register */
98
+	FC_NS_DEREGISTER = 0x3,
99
+};
100
+
101
+/** Fibre Channel name server objects */
102
+enum fc_ns_object_nibble {
103
+	/** Port ID */
104
+	FC_NS_PORT_ID = 0x1,
105
+	/** Port name */
106
+	FC_NS_PORT_NAME = 0x2,
107
+	/** Node name */
108
+	FC_NS_NODE_NAME = 0x3,
109
+	/** FC-4 types */
110
+	FC_NS_FC4_TYPES = 0x7,
111
+	/** Symbolic port name */
112
+	FC_NS_SYM_PORT_NAME = 0x8,
113
+	/** Symbolic node name */
114
+	FC_NS_SYM_NODE_NAME = 0x9,
115
+	/** FC-4 features */
116
+	FC_NS_FC4_FEATURES = 0xf,
117
+};
118
+
119
+/** Construct Fibre Channel name server command code
120
+ *
121
+ * @v command		Name server command
122
+ * @v key		Name server key
123
+ * @v value		Name server value
124
+ * @ret code		Name server command code
125
+ */
126
+#define FC_NS_CODE( command, key, value )				\
127
+	( ( (command) << 8 ) | ( (key) << 4 ) | ( (value) << 0 ) )
128
+
129
+/** Construct Fibre Channel name server "get" command code
130
+ *
131
+ * @v key		Name server key
132
+ * @v value		Name server value to get
133
+ * @ret code		Name server command code
134
+ */
135
+#define FC_NS_GET( key, value ) FC_NS_CODE ( FC_NS_GET, key, value )
136
+
137
+/** Construct Fibre Channel name server "register" command code
138
+ *
139
+ * @v key		Name server key
140
+ * @v value		Name server value to register
141
+ * @ret code		Name server command code
142
+ */
143
+#define FC_NS_REGISTER( key, value ) FC_NS_CODE ( FC_NS_REGISTER, key, value )
144
+
145
+/** Extract Fibre Channel name server command
146
+ *
147
+ * @v code		Name server command code
148
+ * @ret command		Name server command
149
+ */
150
+#define FC_NS_COMMAND( code ) ( ( (code) >> 8 ) & 0xf )
151
+
152
+/** Extract Fibre Channel name server key
153
+ *
154
+ * @v code		Name server command code
155
+ * @ret key		Name server key
156
+ */
157
+#define FC_NS_KEY( code ) ( ( (code) >> 4 ) & 0xf )
158
+
159
+/** Extract Fibre Channel name server value
160
+ *
161
+ * @v code		Name server command code
162
+ * @ret value		NAme server value
163
+ */
164
+#define FC_NS_VALUE( code ) ( ( (code) >> 0 ) & 0xf )
165
+
166
+/** A Fibre Channel name server port ID */
167
+struct fc_ns_port_id {
168
+	/** Reserved */
169
+	uint8_t reserved;
170
+	/** Port ID */
171
+	struct fc_port_id port_id;
172
+} __attribute__ (( packed ));
173
+
174
+/** A Fibre Channel name server GID_PN request */
175
+struct fc_ns_gid_pn_request {
176
+	/** Common Transport header */
177
+	struct fc_ct_header ct;
178
+	/** Port name */
179
+	struct fc_name port_wwn;
180
+} __attribute__ (( packed ));
181
+
182
+/** A Fibre Channel name server request */
183
+union fc_ns_request {
184
+	/** Get ID by port name */
185
+	struct fc_ns_gid_pn_request gid_pn;
186
+};
187
+
188
+/** A Fibre Channel name server rejection response */
189
+struct fc_ns_reject_response {
190
+	/** Common Transport header */
191
+	struct fc_ct_header ct;
192
+} __attribute__ (( packed ));
193
+
194
+/** A Fibre Channel name server GID_PN response */
195
+struct fc_ns_gid_pn_response {
196
+	/** Common Transport header */
197
+	struct fc_ct_header ct;
198
+	/** Port ID */
199
+	struct fc_ns_port_id port_id;
200
+} __attribute__ (( packed ));
201
+
202
+/** A Fibre Channel name server response */
203
+union fc_ns_response {
204
+	/** Common Transport header */
205
+	struct fc_ct_header ct;
206
+	/** Rejection */
207
+	struct fc_ns_reject_response reject;
208
+	/** Get ID by port name */
209
+	struct fc_ns_gid_pn_response gid_pn;
210
+};
211
+
212
+extern int fc_ns_query ( struct fc_peer *peer, struct fc_port *port,
213
+			 int ( * done ) ( struct fc_peer *peer,
214
+					  struct fc_port *port,
215
+					  struct fc_port_id *peer_port_id ) );
216
+
217
+#endif /* _IPXE_FCNS_H */

+ 120
- 38
src/net/fc.c View File

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

+ 240
- 0
src/net/fcns.c View File

@@ -0,0 +1,240 @@
1
+/*
2
+ * Copyright (C) 2010 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
+ */
18
+
19
+FILE_LICENCE ( GPL2_OR_LATER );
20
+
21
+#include <stddef.h>
22
+#include <stdlib.h>
23
+#include <string.h>
24
+#include <errno.h>
25
+#include <byteswap.h>
26
+#include <ipxe/interface.h>
27
+#include <ipxe/iobuf.h>
28
+#include <ipxe/process.h>
29
+#include <ipxe/xfer.h>
30
+#include <ipxe/fc.h>
31
+#include <ipxe/fcns.h>
32
+
33
+/** @file
34
+ *
35
+ * Fibre Channel name server lookups
36
+ *
37
+ */
38
+
39
+/** A Fibre Channel name server query */
40
+struct fc_ns_query {
41
+	/** Reference count */
42
+	struct refcnt refcnt;
43
+	/** Fibre Channel exchange */
44
+	struct interface xchg;
45
+
46
+	/** Fibre Channel peer */
47
+	struct fc_peer *peer;
48
+	/** Fibre Channel port */
49
+	struct fc_port *port;
50
+
51
+	/** Process */
52
+	struct process process;
53
+	/** Success handler
54
+	 *
55
+	 * @v peer		Fibre Channel peer
56
+	 * @v port		Fibre Channel port
57
+	 * @v peer_port_id	Peer port ID
58
+	 * @ret rc		Return status code
59
+	 */
60
+	int ( * done ) ( struct fc_peer *peer, struct fc_port *port,
61
+			 struct fc_port_id *peer_port_id );
62
+};
63
+
64
+/**
65
+ * Free name server query
66
+ *
67
+ * @v refcnt		Reference count
68
+ */
69
+static void fc_ns_query_free ( struct refcnt *refcnt ) {
70
+	struct fc_ns_query *query =
71
+		container_of ( refcnt, struct fc_ns_query, refcnt );
72
+
73
+	fc_peer_put ( query->peer );
74
+	fc_port_put ( query->port );
75
+	free ( query );
76
+}
77
+
78
+/**
79
+ * Close name server query
80
+ *
81
+ * @v query		Name server query
82
+ * @v rc		Reason for close
83
+ */
84
+static void fc_ns_query_close ( struct fc_ns_query *query, int rc ) {
85
+
86
+	/* Stop process */
87
+	process_del ( &query->process );
88
+
89
+	/* Shut down interfaces */
90
+	intf_shutdown ( &query->xchg, rc );
91
+}
92
+
93
+/**
94
+ * Receive name server query response
95
+ *
96
+ * @v query		Name server query
97
+ * @v iobuf		I/O buffer
98
+ * @v meta		Data transfer metadata
99
+ * @ret rc		Return status code
100
+ */
101
+static int fc_ns_query_deliver ( struct fc_ns_query *query,
102
+				 struct io_buffer *iobuf,
103
+				 struct xfer_metadata *meta __unused ) {
104
+	union fc_ns_response *resp = iobuf->data;
105
+	struct fc_port_id *peer_port_id;
106
+	int rc;
107
+
108
+	/* Sanity check */
109
+	if ( iob_len ( iobuf ) < sizeof ( resp->ct ) ) {
110
+		DBGC ( query, "FCNS %p received underlength response (%zd "
111
+		       "bytes)\n", query, iob_len ( iobuf ) );
112
+		rc = -EINVAL;
113
+		goto done;
114
+	}
115
+
116
+	/* Handle response */
117
+	switch ( ntohs ( resp->ct.code ) ) {
118
+	case FC_GS_ACCEPT:
119
+		if ( iob_len ( iobuf ) < sizeof ( resp->gid_pn ) ) {
120
+			DBGC ( query, "FCNS %p received underlength accept "
121
+			       "response (%zd bytes)\n",
122
+			       query, iob_len ( iobuf ) );
123
+			rc = -EINVAL;
124
+			goto done;
125
+		}
126
+		peer_port_id = &resp->gid_pn.port_id.port_id;
127
+		DBGC ( query, "FCNS %p resolved %s to %s via %s\n",
128
+		       query, fc_ntoa ( &query->peer->port_wwn ),
129
+		       fc_id_ntoa ( peer_port_id ), query->port->name );
130
+		if ( ( rc = query->done ( query->peer, query->port,
131
+					  peer_port_id ) ) != 0 )
132
+			goto done;
133
+		break;
134
+	case FC_GS_REJECT:
135
+		DBGC ( query, "FCNS %p rejected (reason %02x explanation "
136
+		       "%02x)\n", query, resp->reject.ct.reason,
137
+		       resp->reject.ct.explanation );
138
+		break;
139
+	default:
140
+		DBGC ( query, "FCNS %p received invalid response code %04x\n",
141
+		       query, ntohs ( resp->ct.code ) );
142
+		rc = -ENOTSUP;
143
+		goto done;
144
+	}
145
+
146
+	rc = 0;
147
+ done:
148
+	free_iob ( iobuf );
149
+	fc_ns_query_close ( query, rc );
150
+	return rc;
151
+}
152
+
153
+/**
154
+ * Name server query process
155
+ *
156
+ * @v process		Process
157
+ */
158
+static void fc_ns_query_step ( struct process *process ) {
159
+	struct fc_ns_query *query =
160
+		container_of ( process, struct fc_ns_query, process );
161
+	struct xfer_metadata meta;
162
+	struct fc_ns_gid_pn_request gid_pn;
163
+	int xchg_id;
164
+	int rc;
165
+
166
+	/* Stop process */
167
+	process_del ( &query->process );
168
+
169
+	/* Create exchange */
170
+	if ( ( xchg_id = fc_xchg_originate ( &query->xchg, query->port,
171
+					     &fc_gs_port_id,
172
+					     FC_TYPE_CT ) ) < 0 ) {
173
+		rc = xchg_id;
174
+		DBGC ( query, "FCNS %p could not create exchange: %s\n",
175
+		       query, strerror ( rc ) );
176
+		fc_ns_query_close ( query, rc );
177
+		return;
178
+	}
179
+
180
+	/* Construct query request */
181
+	memset ( &gid_pn, 0, sizeof ( gid_pn ) );
182
+	gid_pn.ct.revision = FC_CT_REVISION;
183
+	gid_pn.ct.type = FC_GS_TYPE_DS;
184
+	gid_pn.ct.subtype = FC_DS_SUBTYPE_NAME;
185
+	gid_pn.ct.code = htons ( FC_NS_GET ( FC_NS_PORT_NAME, FC_NS_PORT_ID ));
186
+	memcpy ( &gid_pn.port_wwn, &query->peer->port_wwn,
187
+		 sizeof ( gid_pn.port_wwn ) );
188
+	memset ( &meta, 0, sizeof ( meta ) );
189
+	meta.flags = XFER_FL_OVER;
190
+
191
+	/* Send query */
192
+	if ( ( rc = xfer_deliver_raw_meta ( &query->xchg, &gid_pn,
193
+					    sizeof ( gid_pn ), &meta ) ) != 0){
194
+		DBGC ( query, "FCNS %p could not deliver query: %s\n",
195
+		       query, strerror ( rc ) );
196
+		fc_ns_query_close ( query, rc );
197
+		return;
198
+	}
199
+}
200
+
201
+/** Name server exchange interface operations */
202
+static struct interface_operation fc_ns_query_xchg_op[] = {
203
+	INTF_OP ( xfer_deliver, struct fc_ns_query *, fc_ns_query_deliver ),
204
+	INTF_OP ( intf_close, struct fc_ns_query *, fc_ns_query_close ),
205
+};
206
+
207
+/** Name server exchange interface descriptor */
208
+static struct interface_descriptor fc_ns_query_xchg_desc =
209
+	INTF_DESC ( struct fc_ns_query, xchg, fc_ns_query_xchg_op );
210
+
211
+/**
212
+ * Issue Fibre Channel name server query
213
+ *
214
+ * @v peer		Fibre Channel peer
215
+ * @v port		Fibre Channel port
216
+ * @ret rc		Return status code
217
+ */
218
+int fc_ns_query ( struct fc_peer *peer, struct fc_port *port,
219
+		  int ( * done ) ( struct fc_peer *peer, struct fc_port *port,
220
+				   struct fc_port_id *peer_port_id ) ) {
221
+	struct fc_ns_query *query;
222
+
223
+	/* Allocate and initialise structure */
224
+	query = zalloc ( sizeof ( *query ) );
225
+	if ( ! query )
226
+		return -ENOMEM;
227
+	ref_init ( &query->refcnt, fc_ns_query_free );
228
+	intf_init ( &query->xchg, &fc_ns_query_xchg_desc, &query->refcnt );
229
+	process_init ( &query->process, fc_ns_query_step, &query->refcnt );
230
+	query->peer = fc_peer_get ( peer );
231
+	query->port = fc_port_get ( port );
232
+	query->done = done;
233
+
234
+	DBGC ( query, "FCNS %p querying %s via %s\n",
235
+	       query, fc_ntoa ( &query->peer->port_wwn ), port->name );
236
+
237
+	/* Mortalise self and return */
238
+	ref_put ( &query->refcnt );
239
+	return 0;
240
+}

Loading…
Cancel
Save