summaryrefslogtreecommitdiffstats
path: root/qemu/roms/ipxe/src/include/ipxe/fc.h
blob: 840d11f62520f79d2cbe5b6e5edfbc0e8f3d9dc6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
#ifndef _IPXE_FC_H
#define _IPXE_FC_H

/**
 * @file
 *
 * Fibre Channel
 *
 */

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );

#include <stdint.h>
#include <ipxe/refcnt.h>
#include <ipxe/list.h>
#include <ipxe/tables.h>
#include <ipxe/interface.h>
#include <ipxe/retry.h>
#include <ipxe/socket.h>

/******************************************************************************
 *
 * Fibre Channel Names and identifiers
 *
 ******************************************************************************
 */

/** A Fibre Channel name */
struct fc_name {
	uint8_t bytes[8];
} __attribute__ (( packed ));

/** Length of Fibre Channel name text */
#define FC_NAME_STRLEN 23 /* "xx:xx:xx:xx:xx:xx:xx:xx" */

/** A Fibre Channel port identifier */
struct fc_port_id {
	uint8_t bytes[3];
} __attribute__ (( packed ));

/** Length of Fibre Channel port identifier next */
#define FC_PORT_ID_STRLEN 9 /* "xx.xx.xx" */

/**
 * Fibre Channel socket address
 */
struct sockaddr_fc {
	/** Socket address family (part of struct @c sockaddr)
	 *
	 * Always set to @c AF_FC for Fibre Channel addresses
	 */
	sa_family_t sfc_family;
	/** Port ID */
	struct fc_port_id sfc_port_id;
	/** Padding
	 *
	 * This ensures that a struct @c sockaddr_tcpip is large
	 * enough to hold a socket address for any TCP/IP address
	 * family.
	 */
	char pad[ sizeof ( struct sockaddr ) - sizeof ( sa_family_t )
					     - sizeof ( struct fc_port_id ) ];
} __attribute__ (( packed, may_alias ));

extern struct fc_port_id fc_empty_port_id;
extern struct fc_port_id fc_f_port_id;
extern struct fc_port_id fc_gs_port_id;
extern struct fc_port_id fc_ptp_low_port_id;
extern struct fc_port_id fc_ptp_high_port_id;

extern const char * fc_id_ntoa ( const struct fc_port_id *id );
extern int fc_id_aton ( const char *id_text, struct fc_port_id *id );
extern const char * fc_ntoa ( const struct fc_name *wwn );
extern int fc_aton ( const char *wwn_text, struct fc_name *wwn );
extern struct sockaddr * fc_fill_sockaddr ( struct sockaddr_fc *sa_fc,
					    struct fc_port_id *id );

/******************************************************************************
 *
 * Fibre Channel link state
 *
 ******************************************************************************
 */

/** Delay between failed link-up attempts */
#define FC_LINK_RETRY_DELAY ( 2 * TICKS_PER_SEC )

/** A Fibre Channel link state nonitor */
struct fc_link_state {
	/** Retry timer */
	struct retry_timer timer;
	/** Link state */
	int rc;
	/** Examine link state
	 *
	 * @v link		Fibre Channel link state monitor
	 */
	void ( * examine ) ( struct fc_link_state *link );
};

/**
 * Check Fibre Channel link state
 *
 * @v link		Fibre Channel link state monitor
 * @ret link_up		Link is up
 */
static inline __attribute__ (( always_inline )) int
fc_link_ok ( struct fc_link_state *link ) {
	return ( link->rc == 0 );
}

/******************************************************************************
 *
 * Fibre Channel packet formats and exchanges
 *
 ******************************************************************************
 */

/** A Fibre Channel Frame Header */
struct fc_frame_header {
	/** Routing control
	 *
	 * This is the bitwise OR of one @c fc_r_ctl_routing value and
	 * one @c fc_r_ctl_info value.
	 */
	uint8_t r_ctl;
	/** Destination ID */
	struct fc_port_id d_id;
	/** Class-specific control / Priority */
	uint8_t cs_ctl_prio;
	/** Source ID */
	struct fc_port_id s_id;
	/** Data structure type */
	uint8_t type;
	/** Frame control - exchange and sequence */
	uint8_t f_ctl_es;
	/** Frame control - acknowledgements  */
	uint8_t f_ctl_ack;
	/** Frame control - miscellaneous */
	uint8_t f_ctl_misc;
	/** Sequence ID */
	uint8_t seq_id;
	/** Data field control */
	uint8_t df_ctl;
	/** Sequence count */
	uint16_t seq_cnt;
	/** Originator exchange ID */
	uint16_t ox_id;
	/** Responder exchange ID */
	uint16_t rx_id;
	/** Parameter
	 *
	 * Contains the relative offset when @c FC_F_CTL_MISC_REL_OFF
	 * is set.
	 */
	uint32_t parameter;
} __attribute__ (( packed ));

/** Fibre Channel Routing Control Routing */
enum fc_r_ctl_routing {
	FC_R_CTL_DATA = 0x00,		/**< Device Data */
	FC_R_CTL_ELS = 0x20,		/**< Extended Link Services */
	FC_R_CTL_FC4_LINK = 0x30,	/**< FC-4 Link Data */
	FC_R_CTL_VIDEO = 0x40,		/**< Video Data */
	FC_R_CTL_EH = 0x50,		/**< Extended Headers */
	FC_R_CTL_BLS = 0x80,		/**< Basic Link Services */
	FC_R_CTL_LINK_CTRL = 0xc0,	/**< Link Control */
	FC_R_CTL_EXT_ROUTE = 0xf0,	/**< Extended Routing */
};

/** Fibre Channel Routing Control Routing mask */
#define FC_R_CTL_ROUTING_MASK 0xf0

/** Fibre Channel Routing Control Information */
enum fc_r_ctl_info {
	FC_R_CTL_UNCAT = 0x00,		/**< Uncategorized */
	FC_R_CTL_SOL_DATA = 0x01,	/**< Solicited Data */
	FC_R_CTL_UNSOL_CTRL = 0x02,	/**< Unsolicited Control */
	FC_R_CTL_SOL_CTRL = 0x03,	/**< Solicited Control */
	FC_R_CTL_UNSOL_DATA = 0x04,	/**< Unsolicited Data */
	FC_R_CTL_DATA_DESC = 0x05,	/**< Data Descriptor */
	FC_R_CTL_UNSOL_CMD = 0x06,	/**< Unsolicited Command */
	FC_R_CTL_CMD_STAT = 0x07,	/**< Command Status */
};

/** Fibre Channel Routing Control Information mask */
#define FC_R_CTL_INFO_MASK 0x07

/** Fibre Channel Data Structure Type */
enum fc_type {
	FC_TYPE_BLS = 0x00,		/**< Basic Link Service */
	FC_TYPE_ELS = 0x01,		/**< Extended Link Service */
	FC_TYPE_FCP = 0x08,		/**< Fibre Channel Protocol */
	FC_TYPE_CT  = 0x20,		/**< Common Transport */
};

/** Fibre Channel Frame Control - Exchange and Sequence */
enum fc_f_ctl_es {
	FC_F_CTL_ES_RESPONDER = 0x80,	/**< Responder of Exchange */
	FC_F_CTL_ES_RECIPIENT = 0x40,	/**< Sequence Recipient */
	FC_F_CTL_ES_FIRST = 0x20,	/**< First Sequence of Exchange */
	FC_F_CTL_ES_LAST = 0x10,	/**< Last Sequence of Exchange */
	FC_F_CTL_ES_END = 0x08,		/**< Last Data Frame of Sequence */
	FC_F_CTL_ES_TRANSFER = 0x01,	/**< Transfer Sequence Initiative */
};

/** Fibre Channel Frame Control - Miscellaneous */
enum fc_f_ctl_misc {
	FC_F_CTL_MISC_REL_OFF = 0x08,	/**< Relative Offset Present */
};

/** Responder exchange identifier used before first response */
#define FC_RX_ID_UNKNOWN 0xffff

struct fc_port;

extern int fc_xchg_originate ( struct interface *parent, struct fc_port *port,
			       struct fc_port_id *peer_port_id,
			       unsigned int type );

/** A Fibre Channel responder */
struct fc_responder {
	/** Type */
	unsigned int type;
	/** Respond to exchange
	 *
	 * @v xchg		Exchange interface
	 * @v port		Fibre Channel port
	 * @v port_id		Local port ID
	 * @v peer_port_id	Peer port ID
	 * @ret rc		Return status code
	 */
	int ( * respond ) ( struct interface *xchg, struct fc_port *port,
			    struct fc_port_id *port_id,
			    struct fc_port_id *peer_port_id );
};

/** Fibre Channel responder table */
#define FC_RESPONDERS __table ( struct fc_responder, "fc_responders" )

/** Declare a Fibre Channel responder */
#define __fc_responder __table_entry ( FC_RESPONDERS, 01 )

/******************************************************************************
 *
 * Fibre Channel ports
 *
 ******************************************************************************
 */

/** A Fibre Channel port */
struct fc_port {
	/** Reference count */
	struct refcnt refcnt;
	/** List of all ports */
	struct list_head list;
	/** Name of this port */
	char name[8];

	/** Transport interface */
	struct interface transport;
	/** Node name */
	struct fc_name node_wwn;
	/** Port name */
	struct fc_name port_wwn;
	/** Local port ID */
	struct fc_port_id port_id;
	/** Flags */
	unsigned int flags;

	/** Link state monitor */
	struct fc_link_state link;
	/** FLOGI interface */
	struct interface flogi;
	/** Link node name */
	struct fc_name link_node_wwn;
	/** Link port name */
	struct fc_name link_port_wwn;
	/** Link port ID (for point-to-point links only) */
	struct fc_port_id ptp_link_port_id;

	/** Name server PLOGI interface */
	struct interface ns_plogi;

	/** List of active exchanges */
	struct list_head xchgs;
};

/** Fibre Channel port flags */
enum fc_port_flags {
	/** Port is attached to a fabric */
	FC_PORT_HAS_FABRIC = 0x0001,
	/** Port is logged in to a name server */
	FC_PORT_HAS_NS = 0x0002,
};

/**
 * Get reference to Fibre Channel port
 *
 * @v port		Fibre Channel port
 * @ret port		Fibre Channel port
 */
static inline __attribute__ (( always_inline )) struct fc_port *
fc_port_get ( struct fc_port *port ) {
	ref_get ( &port->refcnt );
	return port;
}

/**
 * Drop reference to Fibre Channel port
 *
 * @v port		Fibre Channel port
 */
static inline __attribute__ (( always_inline )) void
fc_port_put ( struct fc_port *port ) {
	ref_put ( &port->refcnt );
}

extern struct list_head fc_ports;

extern int fc_port_login ( struct fc_port *port, struct fc_port_id *port_id,
			   const struct fc_name *link_node_wwn,
			   const struct fc_name *link_port_wwn,
			   int has_fabric );
extern void fc_port_logout ( struct fc_port *port, int rc );
extern int fc_port_open ( struct interface *transport,
			  const struct fc_name *node_wwn,
			  const struct fc_name *port_wwn,
			  const char *name );
extern struct fc_port * fc_port_find ( const char *name );

/******************************************************************************
 *
 * Fibre Channel peers
 *
 ******************************************************************************
 */

/** A Fibre Channel peer */
struct fc_peer {
	/** Reference count */
	struct refcnt refcnt;
	/** List of all peers */
	struct list_head list;

	/** Port name */
	struct fc_name port_wwn;

	/** Link state monitor */
	struct fc_link_state link;
	/** PLOGI interface */
	struct interface plogi;
	/** Fibre Channel port, if known */
	struct fc_port *port;
	/** Peer port ID, if known */
	struct fc_port_id port_id;

	/** List of upper-layer protocols */
	struct list_head ulps;
	/** Active usage count
	 *
	 * A peer (and attached ULPs) may be created in response to
	 * unsolicited login requests received via the fabric.  We
	 * track our own active usage count independently of the
	 * existence of the peer, so that if the peer becomes logged
	 * out (e.g. due to a link failure) then we know whether or
	 * not we should attempt to relogin.
	 */
	unsigned int usage;
};

/**
 * Get reference to Fibre Channel peer
 *
 * @v peer		Fibre Channel peer
 * @ret peer		Fibre Channel peer
 */
static inline __attribute__ (( always_inline )) struct fc_peer *
fc_peer_get ( struct fc_peer *peer ) {
	ref_get ( &peer->refcnt );
	return peer;
}

/**
 * Drop reference to Fibre Channel peer
 *
 * @v peer		Fibre Channel peer
 */
static inline __attribute__ (( always_inline )) void
fc_peer_put ( struct fc_peer *peer ) {
	ref_put ( &peer->refcnt );
}

extern struct list_head fc_peers;

extern struct fc_peer * fc_peer_get_wwn ( const struct fc_name *port_wwn );
extern struct fc_peer *
fc_peer_get_port_id ( struct fc_port *port,
		      const struct fc_port_id *peer_port_id );
extern int fc_peer_login ( struct fc_peer *peer,
			   struct fc_port *port,
			   struct fc_port_id *port_id );
extern void fc_peer_logout ( struct fc_peer *peer, int rc );

/******************************************************************************
 *
 * Fibre Channel upper-layer protocols
 *
 ******************************************************************************
 */

/** A Fibre Channel upper-layer protocol */
struct fc_ulp {
	/** Reference count */
	struct refcnt refcnt;
	/** Fibre Channel peer */
	struct fc_peer *peer;
	/** List of upper-layer protocols */
	struct list_head list;

	/** Type */
	unsigned int type;
	/** Flags */
	unsigned int flags;

	/** Link state monitor */
	struct fc_link_state link;
	/** PRLI interface */
	struct interface prli;
	/** Service parameters, if any */
	void *param;
	/** Service parameter length */
	size_t param_len;

	/** Active users of this upper-layer protocol
	 *
	 * As with peers, an upper-layer protocol may be created in
	 * response to an unsolicited login request received via the
	 * fabric.  This list records the number of active users of
	 * the ULP; the number of entries in the list is equivalent to
	 * the peer usage count.
	 */
	struct list_head users;
};

/** Fibre Channel upper-layer protocol flags */
enum fc_ulp_flags {
	/** A login originated by us has succeeded */
	FC_ULP_ORIGINATED_LOGIN_OK = 0x0001,
};

/** A Fibre Channel upper-layer protocol user */
struct fc_ulp_user {
	/** Fibre Channel upper layer protocol */
	struct fc_ulp *ulp;
	/** List of users */
	struct list_head list;
	/** Containing object reference count, or NULL */
	struct refcnt *refcnt;
	/** Examine link state
	 *
	 * @v user		Fibre Channel upper-layer-protocol user
	 */
	void ( * examine ) ( struct fc_ulp_user *user );
};

/**
 * Get reference to Fibre Channel upper-layer protocol
 *
 * @v ulp		Fibre Channel upper-layer protocol
 * @ret ulp		Fibre Channel upper-layer protocol
 */
static inline __attribute__ (( always_inline )) struct fc_ulp *
fc_ulp_get ( struct fc_ulp *ulp ) {
	ref_get ( &ulp->refcnt );
	return ulp;
}

/**
 * Drop reference to Fibre Channel upper-layer protocol
 *
 * @v ulp		Fibre Channel upper-layer protocol
 */
static inline __attribute__ (( always_inline )) void
fc_ulp_put ( struct fc_ulp *ulp ) {
	ref_put ( &ulp->refcnt );
}

/**
 * Get reference to Fibre Channel upper-layer protocol user
 *
 * @v user		Fibre Channel upper-layer protocol user
 * @ret user		Fibre Channel upper-layer protocol user
 */
static inline __attribute__ (( always_inline )) struct fc_ulp_user *
fc_ulp_user_get ( struct fc_ulp_user *user ) {
	ref_get ( user->refcnt );
	return user;
}

/**
 * Drop reference to Fibre Channel upper-layer protocol user
 *
 * @v user		Fibre Channel upper-layer protocol user
 */
static inline __attribute__ (( always_inline )) void
fc_ulp_user_put ( struct fc_ulp_user *user ) {
	ref_put ( user->refcnt );
}

/**
 * Initialise Fibre Channel upper-layer protocol user
 *
 * @v user		Fibre Channel upper-layer protocol user
 * @v examine		Examine link state method
 * @v refcnt		Containing object reference count, or NULL
 */
static inline __attribute__ (( always_inline )) void
fc_ulp_user_init ( struct fc_ulp_user *user,
		   void ( * examine ) ( struct fc_ulp_user *user ),
		   struct refcnt *refcnt ) {
	user->examine = examine;
	user->refcnt = refcnt;
}

extern struct fc_ulp * fc_ulp_get_wwn_type ( const struct fc_name *port_wwn,
					     unsigned int type );
extern struct fc_ulp *
fc_ulp_get_port_id_type ( struct fc_port *port,
			  const struct fc_port_id *peer_port_id,
			  unsigned int type );
extern void fc_ulp_attach ( struct fc_ulp *ulp, struct fc_ulp_user *user );
extern void fc_ulp_detach ( struct fc_ulp_user *user );
extern int fc_ulp_login ( struct fc_ulp *ulp, const void *param,
			  size_t param_len, int originated );
extern void fc_ulp_logout ( struct fc_ulp *ulp, int rc );

#endif /* _IPXE_FC_H */