Blame view
include/scsi/libfc.h
31.7 KB
42e9a92fe
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
/* * Copyright(c) 2007 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. * * Maintained at www.Open-FCoE.org */ #ifndef _LIBFC_H_ #define _LIBFC_H_ #include <linux/timer.h> #include <linux/if.h> |
582b45bc5
|
25 |
#include <linux/percpu.h> |
22c70d1a9
|
26 |
#include <linux/refcount.h> |
42e9a92fe
|
27 28 29 |
#include <scsi/scsi_transport.h> #include <scsi/scsi_transport_fc.h> |
a51ab3960
|
30 |
#include <scsi/scsi_bsg_fc.h> |
42e9a92fe
|
31 32 33 |
#include <scsi/fc/fc_fcp.h> #include <scsi/fc/fc_ns.h> |
d78c317f6
|
34 |
#include <scsi/fc/fc_ms.h> |
42e9a92fe
|
35 36 37 38 |
#include <scsi/fc/fc_els.h> #include <scsi/fc/fc_gs.h> #include <scsi/fc_frame.h> |
96ad84644
|
39 |
#define FC_FC4_PROV_SIZE (FC_TYPE_FCP + 1) /* size of tables */ |
42e9a92fe
|
40 41 42 43 44 45 |
/* * libfc error codes */ #define FC_NO_ERR 0 /* no error */ #define FC_EX_TIMEOUT 1 /* Exchange timeout */ #define FC_EX_CLOSED 2 /* Exchange closed */ |
9f9504a7c
|
46 47 48 49 50 |
#define FC_EX_ALLOC_ERR 3 /* Exchange allocation failed */ #define FC_EX_XMIT_ERR 4 /* Exchange transmit failed */ #define FC_EX_ELS_RJT 5 /* ELS rejected */ #define FC_EX_INV_LOGIN 6 /* Login not completed */ #define FC_EX_SEQ_ERR 6 /* Exchange sequence error */ |
42e9a92fe
|
51 |
|
3a3b42bf8
|
52 53 54 55 56 57 58 |
/** * enum fc_lport_state - Local port states * @LPORT_ST_DISABLED: Disabled * @LPORT_ST_FLOGI: Fabric login (FLOGI) sent * @LPORT_ST_DNS: Waiting for name server remote port to become ready * @LPORT_ST_RPN_ID: Register port name by ID (RPN_ID) sent * @LPORT_ST_RFT_ID: Register Fibre Channel types by ID (RFT_ID) sent |
ab593b187
|
59 |
* @LPORT_ST_RFF_ID: Register FC-4 Features by ID (RFF_ID) sent |
d78c317f6
|
60 61 |
* @LPORT_ST_FDMI: Waiting for mgmt server rport to become ready * @LPORT_ST_RHBA: |
3a3b42bf8
|
62 63 64 65 |
* @LPORT_ST_SCR: State Change Register (SCR) sent * @LPORT_ST_READY: Ready for use * @LPORT_ST_LOGO: Local port logout (LOGO) sent * @LPORT_ST_RESET: Local port reset |
42e9a92fe
|
66 |
*/ |
42e9a92fe
|
67 |
enum fc_lport_state { |
b1d9fd557
|
68 |
LPORT_ST_DISABLED = 0, |
42e9a92fe
|
69 70 |
LPORT_ST_FLOGI, LPORT_ST_DNS, |
c9c7bd7a5
|
71 |
LPORT_ST_RNN_ID, |
5baa17c3e
|
72 |
LPORT_ST_RSNN_NN, |
c9866a548
|
73 |
LPORT_ST_RSPN_ID, |
42e9a92fe
|
74 |
LPORT_ST_RFT_ID, |
ab593b187
|
75 |
LPORT_ST_RFF_ID, |
d78c317f6
|
76 77 78 79 80 |
LPORT_ST_FDMI, LPORT_ST_RHBA, LPORT_ST_RPA, LPORT_ST_DHBA, LPORT_ST_DPRT, |
42e9a92fe
|
81 82 83 84 85 86 87 88 89 90 91 |
LPORT_ST_SCR, LPORT_ST_READY, LPORT_ST_LOGO, LPORT_ST_RESET }; enum fc_disc_event { DISC_EV_NONE = 0, DISC_EV_SUCCESS, DISC_EV_FAILED }; |
3a3b42bf8
|
92 93 94 |
/** * enum fc_rport_state - Remote port states * @RPORT_ST_INIT: Initialized |
a7b12a279
|
95 96 |
* @RPORT_ST_FLOGI: Waiting for FLOGI completion for point-to-multipoint * @RPORT_ST_PLOGI_WAIT: Waiting for peer to login for point-to-multipoint |
3a3b42bf8
|
97 98 99 100 |
* @RPORT_ST_PLOGI: Waiting for PLOGI completion * @RPORT_ST_PRLI: Waiting for PRLI completion * @RPORT_ST_RTV: Waiting for RTV completion * @RPORT_ST_READY: Ready for use |
3a3b42bf8
|
101 102 |
* @RPORT_ST_ADISC: Discover Address sent * @RPORT_ST_DELETE: Remote port being deleted |
3a3b42bf8
|
103 |
*/ |
42e9a92fe
|
104 |
enum fc_rport_state { |
3a3b42bf8
|
105 |
RPORT_ST_INIT, |
a7b12a279
|
106 107 |
RPORT_ST_FLOGI, RPORT_ST_PLOGI_WAIT, |
3a3b42bf8
|
108 109 110 111 |
RPORT_ST_PLOGI, RPORT_ST_PRLI, RPORT_ST_RTV, RPORT_ST_READY, |
3a3b42bf8
|
112 113 |
RPORT_ST_ADISC, RPORT_ST_DELETE, |
42e9a92fe
|
114 |
}; |
42e9a92fe
|
115 116 |
/** * struct fc_disc_port - temporary discovery port to hold rport identifiers |
9737e6a7b
|
117 118 119 120 |
* @lp: Fibre Channel host port instance * @peers: Node for list management during discovery and RSCN processing * @rport_work: Work struct for starting the rport state machine * @port_id: Port ID of the discovered port |
42e9a92fe
|
121 122 |
*/ struct fc_disc_port { |
3a3b42bf8
|
123 124 125 126 |
struct fc_lport *lp; struct list_head peers; struct work_struct rport_work; u32 port_id; |
42e9a92fe
|
127 |
}; |
3a3b42bf8
|
128 129 130 131 132 133 134 135 |
/** * enum fc_rport_event - Remote port events * @RPORT_EV_NONE: No event * @RPORT_EV_READY: Remote port is ready for use * @RPORT_EV_FAILED: State machine failed, remote port is not ready * @RPORT_EV_STOP: Remote port has been stopped * @RPORT_EV_LOGO: Remote port logout (LOGO) sent */ |
42e9a92fe
|
136 137 |
enum fc_rport_event { RPORT_EV_NONE = 0, |
4c0f62b56
|
138 |
RPORT_EV_READY, |
42e9a92fe
|
139 140 141 142 |
RPORT_EV_FAILED, RPORT_EV_STOP, RPORT_EV_LOGO }; |
9fb9d3283
|
143 |
struct fc_rport_priv; |
3a3b42bf8
|
144 145 146 147 |
/** * struct fc_rport_operations - Operations for a remote port * @event_callback: Function to be called for remote port events */ |
42e9a92fe
|
148 |
struct fc_rport_operations { |
9fb9d3283
|
149 |
void (*event_callback)(struct fc_lport *, struct fc_rport_priv *, |
42e9a92fe
|
150 151 152 153 154 |
enum fc_rport_event); }; /** * struct fc_rport_libfc_priv - libfc internal information about a remote port |
3a3b42bf8
|
155 156 157 158 159 |
* @local_port: The associated local port * @rp_state: Indicates READY for I/O or DELETE when blocked * @flags: REC and RETRY supported flags * @e_d_tov: Error detect timeout value (in msec) * @r_a_tov: Resource allocation timeout value (in msec) |
9e9d0452f
|
160 161 162 163 164 165 166 |
*/ struct fc_rport_libfc_priv { struct fc_lport *local_port; enum fc_rport_state rp_state; u16 flags; #define FC_RP_FLAGS_REC_SUPPORTED (1 << 0) #define FC_RP_FLAGS_RETRY (1 << 1) |
4b2164d4d
|
167 |
#define FC_RP_STARTED (1 << 2) |
75a2792df
|
168 |
#define FC_RP_FLAGS_CONF_REQ (1 << 3) |
9e9d0452f
|
169 170 171 172 173 |
unsigned int e_d_tov; unsigned int r_a_tov; }; /** |
3a3b42bf8
|
174 175 176 177 178 179 180 |
* struct fc_rport_priv - libfc remote port and discovery info * @local_port: The associated local port * @rport: The FC transport remote port * @kref: Reference counter * @rp_state: Enumeration that tracks progress of PLOGI, PRLI, * and RTV exchanges * @ids: The remote port identifiers and roles |
4b2164d4d
|
181 |
* @flags: STARTED, REC and RETRY_SUPPORTED flags |
3a3b42bf8
|
182 183 184 185 |
* @max_seq: Maximum number of concurrent sequences * @disc_id: The discovery identifier * @maxframe_size: The maximum frame size * @retries: The retry count for the current state |
f034260db
|
186 |
* @major_retries: The retry count for the entire PLOGI/PRLI state machine |
3a3b42bf8
|
187 188 189 190 191 |
* @e_d_tov: Error detect timeout value (in msec) * @r_a_tov: Resource allocation timeout value (in msec) * @rp_mutex: The mutex that protects the remote port * @retry_work: Handle for retries * @event_callback: Callback when READY, FAILED or LOGO states complete |
96ad84644
|
192 |
* @prli_count: Count of open PRLI sessions in providers |
42e904146
|
193 |
* @rcu: Structure used for freeing in an RCU-safe manner |
42e9a92fe
|
194 |
*/ |
9e9d0452f
|
195 |
struct fc_rport_priv { |
3a3b42bf8
|
196 197 198 199 |
struct fc_lport *local_port; struct fc_rport *rport; struct kref kref; enum fc_rport_state rp_state; |
f211fa514
|
200 |
struct fc_rport_identifiers ids; |
3a3b42bf8
|
201 202 203 204 205 |
u16 flags; u16 max_seq; u16 disc_id; u16 maxframe_size; unsigned int retries; |
f034260db
|
206 |
unsigned int major_retries; |
3a3b42bf8
|
207 208 209 210 211 212 213 214 215 |
unsigned int e_d_tov; unsigned int r_a_tov; struct mutex rp_mutex; struct delayed_work retry_work; enum fc_rport_event event; struct fc_rport_operations *ops; struct list_head peers; struct work_struct event_work; u32 supported_classes; |
96ad84644
|
216 |
u16 prli_count; |
42e904146
|
217 |
struct rcu_head rcu; |
75a2792df
|
218 219 220 221 222 |
u16 sp_features; u8 spp_type; void (*lld_event_callback)(struct fc_lport *, struct fc_rport_priv *, enum fc_rport_event); |
42e9a92fe
|
223 |
}; |
3a3b42bf8
|
224 |
/** |
1bd49b482
|
225 |
* struct fc_stats - fc stats structure |
3a3b42bf8
|
226 227 228 229 230 231 232 |
* @SecondsSinceLastReset: Seconds since the last reset * @TxFrames: Number of transmitted frames * @TxWords: Number of transmitted words * @RxFrames: Number of received frames * @RxWords: Number of received words * @ErrorFrames: Number of received error frames * @DumpedFrames: Number of dumped frames |
0f02a6652
|
233 234 235 |
* @FcpPktAllocFails: Number of fcp packet allocation failures * @FcpPktAborts: Number of fcp packet aborts * @FcpFrameAllocFails: Number of fcp frame allocation failures |
3a3b42bf8
|
236 237 238 239 240 241 242 |
* @LinkFailureCount: Number of link failures * @LossOfSignalCount: Number for signal losses * @InvalidTxWordCount: Number of invalid transmitted words * @InvalidCRCCount: Number of invalid CRCs * @InputRequests: Number of input requests * @OutputRequests: Number of output requests * @ControlRequests: Number of control requests |
5f0e385fd
|
243 244 |
* @InputBytes: Number of received bytes * @OutputBytes: Number of transmitted bytes |
6580bbd0a
|
245 246 |
* @VLinkFailureCount: Number of virtual link failures * @MissDiscAdvCount: Number of missing FIP discovery advertisement |
42e9a92fe
|
247 |
*/ |
1bd49b482
|
248 |
struct fc_stats { |
42e9a92fe
|
249 250 251 252 253 254 255 |
u64 SecondsSinceLastReset; u64 TxFrames; u64 TxWords; u64 RxFrames; u64 RxWords; u64 ErrorFrames; u64 DumpedFrames; |
0f02a6652
|
256 257 258 |
u64 FcpPktAllocFails; u64 FcpPktAborts; u64 FcpFrameAllocFails; |
42e9a92fe
|
259 260 261 262 263 264 265 |
u64 LinkFailureCount; u64 LossOfSignalCount; u64 InvalidTxWordCount; u64 InvalidCRCCount; u64 InputRequests; u64 OutputRequests; u64 ControlRequests; |
5f0e385fd
|
266 267 |
u64 InputBytes; u64 OutputBytes; |
6580bbd0a
|
268 269 |
u64 VLinkFailureCount; u64 MissDiscAdvCount; |
42e9a92fe
|
270 |
}; |
3a3b42bf8
|
271 272 |
/** * struct fc_seq_els_data - ELS data used for passing ELS specific responses |
3a3b42bf8
|
273 |
* @reason: The reason for rejection |
25985edce
|
274 |
* @explan: The explanation of the rejection |
3a3b42bf8
|
275 276 |
* * Mainly used by the exchange manager layer. |
42e9a92fe
|
277 278 |
*/ struct fc_seq_els_data { |
42e9a92fe
|
279 280 281 |
enum fc_els_rjt_reason reason; enum fc_els_rjt_explan explan; }; |
3a3b42bf8
|
282 283 284 285 |
/** * struct fc_fcp_pkt - FCP request structure (one for each scsi_cmnd request) * @lp: The associated local port * @state: The state of the I/O |
3a3b42bf8
|
286 287 288 289 290 291 292 293 |
* @ref_cnt: Reference count * @scsi_pkt_lock: Lock to protect the SCSI packet (must be taken before the * host_lock if both are to be held at the same time) * @cmd: The SCSI command (set and clear with the host_lock held) * @list: Tracks queued commands (accessed with the host_lock held) * @timer: The command timer * @tm_done: Completion indicator * @wait_for_comp: Indicator to wait for completion of the I/O (in jiffies) |
3a3b42bf8
|
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 |
* @data_len: The length of the data * @cdb_cmd: The CDB command * @xfer_len: The transfer length * @xfer_ddp: Indicates if this transfer used DDP (XID of the exchange * will be set here if DDP was setup) * @xfer_contig_end: The offset into the buffer if the buffer is contiguous * (Tx and Rx) * @max_payload: The maximum payload size (in bytes) * @io_status: SCSI result (upper 24 bits) * @cdb_status: CDB status * @status_code: FCP I/O status * @scsi_comp_flags: Completion flags (bit 3 Underrun bit 2: overrun) * @req_flags: Request flags (bit 0: read bit:1 write) * @scsi_resid: SCSI residule length * @rport: The remote port that the SCSI command is targeted at * @seq_ptr: The sequence that will carry the SCSI command * @recov_retry: Number of recovery retries * @recov_seq: The sequence for REC or SRR |
42e9a92fe
|
312 313 |
*/ struct fc_fcp_pkt { |
3a3b42bf8
|
314 |
spinlock_t scsi_pkt_lock; |
22c70d1a9
|
315 |
refcount_t ref_cnt; |
ed26cfece
|
316 317 318 |
/* SCSI command and data transfer information */ u32 data_len; |
3a3b42bf8
|
319 320 321 322 |
/* SCSI I/O related information */ struct scsi_cmnd *cmd; struct list_head list; |
ed26cfece
|
323 324 325 |
/* Housekeeping information */ struct fc_lport *lp; u8 state; |
3a3b42bf8
|
326 327 |
/* SCSI/FCP return status */ |
3a3b42bf8
|
328 329 330 |
u8 cdb_status; u8 status_code; u8 scsi_comp_flags; |
ed26cfece
|
331 |
u32 io_status; |
3a3b42bf8
|
332 333 |
u32 req_flags; u32 scsi_resid; |
ed26cfece
|
334 335 336 337 338 339 |
/* Transport related veriables */ size_t xfer_len; struct fcp_cmnd cdb_cmd; u32 xfer_contig_end; u16 max_payload; u16 xfer_ddp; |
3a3b42bf8
|
340 341 342 |
/* Associated structures */ struct fc_rport *rport; struct fc_seq *seq_ptr; |
ed26cfece
|
343 344 |
/* Timeout/error related information */ struct timer_list timer; |
ad3120cfe
|
345 346 |
int wait_for_comp; int timer_delay; |
ed26cfece
|
347 |
u32 recov_retry; |
3a3b42bf8
|
348 |
struct fc_seq *recov_seq; |
ed26cfece
|
349 350 |
struct completion tm_done; } ____cacheline_aligned_in_smp; |
42e9a92fe
|
351 352 353 354 355 356 357 358 359 360 361 |
/* * Structure and function definitions for managing Fibre Channel Exchanges * and Sequences * * fc_exch holds state for one exchange and links to its active sequence. * * fc_seq holds the state for an individual sequence. */ struct fc_exch_mgr; |
96316099a
|
362 |
struct fc_exch_mgr_anchor; |
3a3b42bf8
|
363 |
extern u16 fc_cpu_mask; /* cpu mask for possible cpus */ |
42e9a92fe
|
364 |
|
3a3b42bf8
|
365 366 367 368 369 370 |
/** * struct fc_seq - FC sequence * @id: The sequence ID * @ssb_stat: Status flags for the sequence status block (SSB) * @cnt: Number of frames sent so far * @rec_data: FC-4 value for REC |
42e9a92fe
|
371 372 |
*/ struct fc_seq { |
3a3b42bf8
|
373 374 375 376 |
u8 id; u16 ssb_stat; u16 cnt; u32 rec_data; |
42e9a92fe
|
377 378 379 380 |
}; #define FC_EX_DONE (1 << 0) /* ep is completed */ #define FC_EX_RST_CLEANUP (1 << 1) /* reset is forcing completion */ |
9ca1e182b
|
381 |
#define FC_EX_QUARANTINE (1 << 2) /* exch is quarantined */ |
42e9a92fe
|
382 |
|
3a3b42bf8
|
383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 |
/** * struct fc_exch - Fibre Channel Exchange * @em: Exchange manager * @pool: Exchange pool * @state: The exchange's state * @xid: The exchange ID * @ex_list: Handle used by the EM to track free exchanges * @ex_lock: Lock that protects the exchange * @ex_refcnt: Reference count * @timeout_work: Handle for timeout handler * @lp: The local port that this exchange is on * @oxid: Originator's exchange ID * @rxid: Responder's exchange ID * @oid: Originator's FCID * @sid: Source FCID * @did: Destination FCID * @esb_stat: ESB exchange status * @r_a_tov: Resouce allocation time out value (in msecs) * @seq_id: The next sequence ID to use |
f60e12e9c
|
402 |
* @encaps: encapsulation information for lower-level driver |
3a3b42bf8
|
403 404 405 406 |
* @f_ctl: F_CTL flags for the sequence * @fh_type: The frame type * @class: The class of service * @seq: The sequence in use on this exchange |
7030fd626
|
407 408 409 410 411 412 |
* @resp_active: Number of tasks that are concurrently executing @resp(). * @resp_task: If @resp_active > 0, either the task executing @resp(), the * task that has been interrupted to execute the soft-IRQ * executing @resp() or NULL if more than one task is executing * @resp concurrently. * @resp_wq: Waitqueue for the tasks waiting on @resp_active. |
3a3b42bf8
|
413 414 415 |
* @resp: Callback for responses on this exchange * @destructor: Called when destroying the exchange * @arg: Passed as a void pointer to the resp() callback |
42e9a92fe
|
416 417 418 419 420 421 422 |
* * Locking notes: The ex_lock protects following items: * state, esb_stat, f_ctl, seq.ssb_stat * seq_id * sequence allocation */ struct fc_exch { |
49a198898
|
423 424 425 |
spinlock_t ex_lock; atomic_t ex_refcnt; enum fc_class class; |
3a3b42bf8
|
426 427 |
struct fc_exch_mgr *em; struct fc_exch_pool *pool; |
3a3b42bf8
|
428 |
struct list_head ex_list; |
3a3b42bf8
|
429 |
struct fc_lport *lp; |
49a198898
|
430 431 432 433 434 435 |
u32 esb_stat; u8 state; u8 fh_type; u8 seq_id; u8 encaps; u16 xid; |
3a3b42bf8
|
436 437 438 439 440 |
u16 oxid; u16 rxid; u32 oid; u32 sid; u32 did; |
3a3b42bf8
|
441 |
u32 r_a_tov; |
3a3b42bf8
|
442 |
u32 f_ctl; |
49a198898
|
443 |
struct fc_seq seq; |
7030fd626
|
444 445 446 |
int resp_active; struct task_struct *resp_task; wait_queue_head_t resp_wq; |
3a3b42bf8
|
447 448 |
void (*resp)(struct fc_seq *, struct fc_frame *, void *); void *arg; |
3a3b42bf8
|
449 |
void (*destructor)(struct fc_seq *, void *); |
49a198898
|
450 451 |
struct delayed_work timeout_work; } ____cacheline_aligned_in_smp; |
42e9a92fe
|
452 |
#define fc_seq_exch(sp) container_of(sp, struct fc_exch, seq) |
42e9a92fe
|
453 |
|
3a3b42bf8
|
454 |
struct libfc_function_template { |
42e9a92fe
|
455 456 |
/* * Interface to send a FC frame |
42e9a92fe
|
457 |
* |
0ae4d4ae4
|
458 |
* STATUS: REQUIRED |
42e9a92fe
|
459 |
*/ |
3a3b42bf8
|
460 |
int (*frame_send)(struct fc_lport *, struct fc_frame *); |
42e9a92fe
|
461 462 |
/* |
0ae4d4ae4
|
463 464 465 |
* Interface to send ELS/CT frames * * STATUS: OPTIONAL |
42e9a92fe
|
466 |
*/ |
3a3b42bf8
|
467 468 |
struct fc_seq *(*elsct_send)(struct fc_lport *, u32 did, struct fc_frame *, unsigned int op, |
42e9a92fe
|
469 |
void (*resp)(struct fc_seq *, |
3a3b42bf8
|
470 |
struct fc_frame *, void *arg), |
42e9a92fe
|
471 |
void *arg, u32 timer_msec); |
42e9a92fe
|
472 473 |
/* |
b277d2aa9
|
474 475 476 477 478 |
* Sets up the DDP context for a given exchange id on the given * scatterlist if LLD supports DDP for large receive. * * STATUS: OPTIONAL */ |
3a3b42bf8
|
479 480 |
int (*ddp_setup)(struct fc_lport *, u16, struct scatterlist *, unsigned int); |
b277d2aa9
|
481 482 483 484 485 486 |
/* * Completes the DDP transfer and returns the length of data DDPed * for the given exchange id. * * STATUS: OPTIONAL */ |
3a3b42bf8
|
487 |
int (*ddp_done)(struct fc_lport *, u16); |
b277d2aa9
|
488 |
/* |
33dc362b7
|
489 |
* Sets up the DDP context for a given exchange id on the given |
1bd49b482
|
490 |
* scatterlist if LLD supports DDP for target. |
33dc362b7
|
491 492 493 494 495 496 |
* * STATUS: OPTIONAL */ int (*ddp_target)(struct fc_lport *, u16, struct scatterlist *, unsigned int); /* |
b84056bf6
|
497 498 499 500 501 |
* Allow LLD to fill its own Link Error Status Block * * STATUS: OPTIONAL */ void (*get_lesb)(struct fc_lport *, struct fc_els_lesb *lesb); |
42e9a92fe
|
502 503 |
/* |
42e9a92fe
|
504 505 506 |
* Reset an exchange manager, completing all sequences and exchanges. * If s_id is non-zero, reset only exchanges originating from that FID. * If d_id is non-zero, reset only exchanges sending to that FID. |
0ae4d4ae4
|
507 508 |
* * STATUS: OPTIONAL |
42e9a92fe
|
509 |
*/ |
3a3b42bf8
|
510 |
void (*exch_mgr_reset)(struct fc_lport *, u32 s_id, u32 d_id); |
42e9a92fe
|
511 |
|
0ae4d4ae4
|
512 |
/* |
093bb6a2d
|
513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 |
* Set the local port FC_ID. * * This may be provided by the LLD to allow it to be * notified when the local port is assigned a FC-ID. * * The frame, if non-NULL, is the incoming frame with the * FLOGI LS_ACC or FLOGI, and may contain the granted MAC * address for the LLD. The frame pointer may be NULL if * no MAC is associated with this assignment (LOGO or PLOGI). * * If FC_ID is non-zero, r_a_tov and e_d_tov must be valid. * * Note: this is called with the local port mutex held. * * STATUS: OPTIONAL */ void (*lport_set_port_id)(struct fc_lport *, u32 port_id, struct fc_frame *); /* |
75a2792df
|
533 534 535 536 537 538 539 540 541 |
* Callback routine after the remote port is logged in * * STATUS: OPTIONAL */ void (*rport_event_callback)(struct fc_lport *, struct fc_rport_priv *, enum fc_rport_event); /* |
42e9a92fe
|
542 543 544 545 546 |
* Send a fcp cmd from fsp pkt. * Called with the SCSI host lock unlocked and irqs disabled. * * The resp handler is called when FCP_RSP received. * |
0ae4d4ae4
|
547 |
* STATUS: OPTIONAL |
42e9a92fe
|
548 |
*/ |
3a3b42bf8
|
549 550 551 |
int (*fcp_cmd_send)(struct fc_lport *, struct fc_fcp_pkt *, void (*resp)(struct fc_seq *, struct fc_frame *, void *)); |
42e9a92fe
|
552 553 |
/* |
25985edce
|
554 |
* Cleanup the FCP layer, used during link down and reset |
0ae4d4ae4
|
555 556 |
* * STATUS: OPTIONAL |
42e9a92fe
|
557 |
*/ |
3a3b42bf8
|
558 |
void (*fcp_cleanup)(struct fc_lport *); |
42e9a92fe
|
559 560 561 |
/* * Abort all I/O on a local port |
0ae4d4ae4
|
562 563 |
* * STATUS: OPTIONAL |
42e9a92fe
|
564 |
*/ |
3a3b42bf8
|
565 |
void (*fcp_abort_io)(struct fc_lport *); |
42e9a92fe
|
566 |
|
0ae4d4ae4
|
567 568 569 570 |
/* * Receive a request for the discovery layer. * * STATUS: OPTIONAL |
42e9a92fe
|
571 |
*/ |
922611569
|
572 |
void (*disc_recv_req)(struct fc_lport *, struct fc_frame *); |
42e9a92fe
|
573 574 575 |
/* * Start discovery for a local port. |
0ae4d4ae4
|
576 577 |
* * STATUS: OPTIONAL |
42e9a92fe
|
578 579 580 581 582 583 584 585 |
*/ void (*disc_start)(void (*disc_callback)(struct fc_lport *, enum fc_disc_event), struct fc_lport *); /* * Stop discovery for a given lport. This will remove * all discovered rports |
0ae4d4ae4
|
586 587 |
* * STATUS: OPTIONAL |
42e9a92fe
|
588 589 590 591 592 593 594 |
*/ void (*disc_stop) (struct fc_lport *); /* * Stop discovery for a given lport. This will block * until all discovered rports are deleted from the * FC transport class |
0ae4d4ae4
|
595 596 |
* * STATUS: OPTIONAL |
42e9a92fe
|
597 598 599 |
*/ void (*disc_stop_final) (struct fc_lport *); }; |
3a3b42bf8
|
600 601 602 603 |
/** * struct fc_disc - Discovery context * @retry_count: Number of retries * @pending: 1 if discovery is pending, 0 if not |
c531b9b49
|
604 |
* @requested: 1 if discovery has been requested, 0 if not |
3a3b42bf8
|
605 606 607 608 |
* @seq_count: Number of sequences used for discovery * @buf_len: Length of the discovery buffer * @disc_id: Discovery ID * @rports: List of discovered remote ports |
0685230c5
|
609 |
* @priv: Private pointer for use by discovery code |
3a3b42bf8
|
610 611 612 613 614 615 |
* @disc_mutex: Mutex that protects the discovery context * @partial_buf: Partial name buffer (if names are returned * in multiple frames) * @disc_work: handle for delayed work context * @disc_callback: Callback routine called when discovery completes */ |
42e9a92fe
|
616 |
struct fc_disc { |
3a3b42bf8
|
617 618 619 620 621 622 623 624 |
unsigned char retry_count; unsigned char pending; unsigned char requested; unsigned short seq_count; unsigned char buf_len; u16 disc_id; struct list_head rports; |
0685230c5
|
625 |
void *priv; |
3a3b42bf8
|
626 627 628 |
struct mutex disc_mutex; struct fc_gpn_ft_resp partial_buf; struct delayed_work disc_work; |
42e9a92fe
|
629 630 631 |
void (*disc_callback)(struct fc_lport *, enum fc_disc_event); |
42e9a92fe
|
632 |
}; |
70d53b046
|
633 634 635 636 637 638 639 640 |
/* * Local port notifier and events. */ extern struct blocking_notifier_head fc_lport_notifier_head; enum fc_lport_event { FC_LPORT_EV_ADD, FC_LPORT_EV_DEL, }; |
3a3b42bf8
|
641 642 643 644 645 |
/** * struct fc_lport - Local port * @host: The SCSI host associated with a local port * @ema_list: Exchange manager anchor list * @dns_rdata: The directory server remote port |
d78c317f6
|
646 |
* @ms_rdata: The management server remote port |
3a3b42bf8
|
647 648 649 650 651 652 653 654 655 656 657 |
* @ptp_rdata: Point to point remote port * @scsi_priv: FCP layer internal data * @disc: Discovery context * @vports: Child vports if N_Port * @vport: Parent vport if VN_Port * @tt: Libfc function template * @link_up: Link state (1 = link up, 0 = link down) * @qfull: Queue state (1 queue is full, 0 queue is not full) * @state: Identifies the state * @boot_time: Timestamp indicating when the local port came online * @host_stats: SCSI host statistics |
1bd49b482
|
658 |
* @stats: FC local port stats (TODO separate libfc LLD stats) |
3a3b42bf8
|
659 |
* @retry_count: Number of retries in the current state |
7b2787ec1
|
660 |
* @port_id: FC Port ID |
3a3b42bf8
|
661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 |
* @wwpn: World Wide Port Name * @wwnn: World Wide Node Name * @service_params: Common service parameters * @e_d_tov: Error detection timeout value * @r_a_tov: Resouce allocation timeout value * @rnid_gen: RNID information * @sg_supp: Indicates if scatter gather is supported * @seq_offload: Indicates if sequence offload is supported * @crc_offload: Indicates if CRC offload is supported * @lro_enabled: Indicates if large receive offload is supported * @does_npiv: Supports multiple vports * @npiv_enabled: Switch/fabric allows NPIV * @mfs: The maximum Fibre Channel payload size * @max_retry_count: The maximum retry attempts * @max_rport_retry_count: The maximum remote port retry attempts |
f90377abc
|
676 |
* @rport_priv_size: Size needed by driver after struct fc_rport_priv |
3a3b42bf8
|
677 678 679 680 |
* @lro_xid: The maximum XID for LRO * @lso_max: The maximum large offload send size * @fcts: FC-4 type mask * @lp_mutex: Mutex to protect the local port |
70d53b046
|
681 |
* @list: Linkage on list of vport peers |
3a3b42bf8
|
682 |
* @retry_work: Handle to local port for delayed retry context |
baf9fdf07
|
683 |
* @prov: Pointers available for use by passive FC-4 providers |
70d53b046
|
684 |
* @lport_list: Linkage on module-wide list of local ports |
3a3b42bf8
|
685 |
*/ |
42e9a92fe
|
686 |
struct fc_lport { |
42e9a92fe
|
687 |
/* Associations */ |
3a3b42bf8
|
688 689 690 |
struct Scsi_Host *host; struct list_head ema_list; struct fc_rport_priv *dns_rdata; |
d78c317f6
|
691 |
struct fc_rport_priv *ms_rdata; |
3a3b42bf8
|
692 693 694 695 696 697 698 |
struct fc_rport_priv *ptp_rdata; void *scsi_priv; struct fc_disc disc; /* Virtual port information */ struct list_head vports; struct fc_vport *vport; |
42e9a92fe
|
699 700 701 |
/* Operational Information */ struct libfc_function_template tt; |
3a3b42bf8
|
702 703 |
u8 link_up; u8 qfull; |
9a6cf881d
|
704 |
u16 vlan; |
3a3b42bf8
|
705 706 707 |
enum fc_lport_state state; unsigned long boot_time; struct fc_host_statistics host_stats; |
1bd49b482
|
708 |
struct fc_stats __percpu *stats; |
3a3b42bf8
|
709 710 711 |
u8 retry_count; /* Fabric information */ |
7b2787ec1
|
712 |
u32 port_id; |
3a3b42bf8
|
713 714 715 716 717 718 |
u64 wwpn; u64 wwnn; unsigned int service_params; unsigned int e_d_tov; unsigned int r_a_tov; struct fc_els_rnid_gen rnid_gen; |
42e9a92fe
|
719 720 |
/* Capabilities */ |
3a3b42bf8
|
721 722 723 724 725 726 |
u32 sg_supp:1; u32 seq_offload:1; u32 crc_offload:1; u32 lro_enabled:1; u32 does_npiv:1; u32 npiv_enabled:1; |
3726f3584
|
727 |
u32 point_to_multipoint:1; |
d78c317f6
|
728 |
u32 fdmi_enabled:1; |
3a3b42bf8
|
729 730 731 |
u32 mfs; u8 max_retry_count; u8 max_rport_retry_count; |
f90377abc
|
732 |
u16 rport_priv_size; |
3a3b42bf8
|
733 734 735 736 737 |
u16 link_speed; u16 link_supported_speeds; u16 lro_xid; unsigned int lso_max; struct fc_ns_fts fcts; |
42e9a92fe
|
738 739 |
/* Miscellaneous */ |
3a3b42bf8
|
740 741 742 |
struct mutex lp_mutex; struct list_head list; struct delayed_work retry_work; |
baf9fdf07
|
743 |
void *prov[FC_FC4_PROV_SIZE]; |
70d53b046
|
744 |
struct list_head lport_list; |
42e9a92fe
|
745 |
}; |
96ad84644
|
746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 |
/** * struct fc4_prov - FC-4 provider registration * @prli: Handler for incoming PRLI * @prlo: Handler for session reset * @recv: Handler for incoming request * @module: Pointer to module. May be NULL. */ struct fc4_prov { int (*prli)(struct fc_rport_priv *, u32 spp_len, const struct fc_els_spp *spp_in, struct fc_els_spp *spp_out); void (*prlo)(struct fc_rport_priv *); void (*recv)(struct fc_lport *, struct fc_frame *); struct module *module; }; /* * Register FC-4 provider with libfc. */ int fc_fc4_register_provider(enum fc_fh_type type, struct fc4_prov *); void fc_fc4_deregister_provider(enum fc_fh_type type, struct fc4_prov *); |
34f42a070
|
767 |
/* |
42e9a92fe
|
768 769 |
* FC_LPORT HELPER FUNCTIONS *****************************/ |
3a3b42bf8
|
770 771 772 773 774 775 |
/** * fc_lport_test_ready() - Determine if a local port is in the READY state * @lport: The local port to test */ static inline int fc_lport_test_ready(struct fc_lport *lport) |
42e9a92fe
|
776 |
{ |
3a3b42bf8
|
777 |
return lport->state == LPORT_ST_READY; |
42e9a92fe
|
778 |
} |
3a3b42bf8
|
779 780 781 782 783 784 |
/** * fc_set_wwnn() - Set the World Wide Node Name of a local port * @lport: The local port whose WWNN is to be set * @wwnn: The new WWNN */ static inline void fc_set_wwnn(struct fc_lport *lport, u64 wwnn) |
42e9a92fe
|
785 |
{ |
3a3b42bf8
|
786 |
lport->wwnn = wwnn; |
42e9a92fe
|
787 |
} |
3a3b42bf8
|
788 789 790 |
/** * fc_set_wwpn() - Set the World Wide Port Name of a local port * @lport: The local port whose WWPN is to be set |
67d35e70a
|
791 |
* @wwpn: The new WWPN |
3a3b42bf8
|
792 |
*/ |
67d35e70a
|
793 |
static inline void fc_set_wwpn(struct fc_lport *lport, u64 wwpn) |
42e9a92fe
|
794 |
{ |
67d35e70a
|
795 |
lport->wwpn = wwpn; |
42e9a92fe
|
796 |
} |
3a3b42bf8
|
797 798 799 800 801 802 |
/** * fc_lport_state_enter() - Change a local port's state * @lport: The local port whose state is to change * @state: The new state */ static inline void fc_lport_state_enter(struct fc_lport *lport, |
42e9a92fe
|
803 804 |
enum fc_lport_state state) { |
3a3b42bf8
|
805 806 807 |
if (state != lport->state) lport->retry_count = 0; lport->state = state; |
42e9a92fe
|
808 |
} |
3a3b42bf8
|
809 810 811 812 813 |
/** * fc_lport_init_stats() - Allocate per-CPU statistics for a local port * @lport: The local port whose statistics are to be initialized */ static inline int fc_lport_init_stats(struct fc_lport *lport) |
582b45bc5
|
814 |
{ |
1bd49b482
|
815 816 |
lport->stats = alloc_percpu(struct fc_stats); if (!lport->stats) |
582b45bc5
|
817 818 819 |
return -ENOMEM; return 0; } |
3a3b42bf8
|
820 821 822 823 824 |
/** * fc_lport_free_stats() - Free memory for a local port's statistics * @lport: The local port whose statistics are to be freed */ static inline void fc_lport_free_stats(struct fc_lport *lport) |
582b45bc5
|
825 |
{ |
1bd49b482
|
826 |
free_percpu(lport->stats); |
582b45bc5
|
827 |
} |
3a3b42bf8
|
828 829 830 831 832 |
/** * lport_priv() - Return the private data from a local port * @lport: The local port whose private data is to be retreived */ static inline void *lport_priv(const struct fc_lport *lport) |
a0a25da2a
|
833 |
{ |
3a3b42bf8
|
834 |
return (void *)(lport + 1); |
a0a25da2a
|
835 836 837 |
} /** |
3a3b42bf8
|
838 839 840 841 |
* libfc_host_alloc() - Allocate a Scsi_Host with room for a local port and * LLD private data * @sht: The SCSI host template * @priv_size: Size of private data |
a0a25da2a
|
842 |
* |
86221969e
|
843 |
* Returns: libfc lport |
a0a25da2a
|
844 |
*/ |
86221969e
|
845 |
static inline struct fc_lport * |
a0a25da2a
|
846 847 |
libfc_host_alloc(struct scsi_host_template *sht, int priv_size) { |
86221969e
|
848 849 850 851 852 853 854 855 856 |
struct fc_lport *lport; struct Scsi_Host *shost; shost = scsi_host_alloc(sht, sizeof(*lport) + priv_size); if (!shost) return NULL; lport = shost_priv(shost); lport->host = shost; INIT_LIST_HEAD(&lport->ema_list); |
174e1ebff
|
857 |
INIT_LIST_HEAD(&lport->vports); |
86221969e
|
858 |
return lport; |
a0a25da2a
|
859 |
} |
42e9a92fe
|
860 |
|
34f42a070
|
861 |
/* |
3a3b42bf8
|
862 |
* FC_FCP HELPER FUNCTIONS |
42e9a92fe
|
863 |
*****************************/ |
3a3b42bf8
|
864 865 866 867 868 869 |
static inline bool fc_fcp_is_read(const struct fc_fcp_pkt *fsp) { if (fsp && fsp->cmd) return fsp->cmd->sc_data_direction == DMA_FROM_DEVICE; return false; } |
42e9a92fe
|
870 871 |
/* |
3a3b42bf8
|
872 873 874 875 876 877 |
* LOCAL PORT LAYER *****************************/ int fc_lport_init(struct fc_lport *); int fc_lport_destroy(struct fc_lport *); int fc_fabric_logoff(struct fc_lport *); int fc_fabric_login(struct fc_lport *); |
8faecddb2
|
878 |
void __fc_linkup(struct fc_lport *); |
42e9a92fe
|
879 |
void fc_linkup(struct fc_lport *); |
8faecddb2
|
880 |
void __fc_linkdown(struct fc_lport *); |
42e9a92fe
|
881 |
void fc_linkdown(struct fc_lport *); |
3a3b42bf8
|
882 883 |
void fc_vport_setlink(struct fc_lport *); void fc_vports_linkchange(struct fc_lport *); |
42e9a92fe
|
884 |
int fc_lport_config(struct fc_lport *); |
42e9a92fe
|
885 |
int fc_lport_reset(struct fc_lport *); |
c5cb444c3
|
886 |
void fc_lport_recv(struct fc_lport *lport, struct fc_frame *fp); |
3a3b42bf8
|
887 888 889 |
int fc_set_mfs(struct fc_lport *, u32 mfs); struct fc_lport *libfc_vport_create(struct fc_vport *, int privsize); struct fc_lport *fc_vport_id_lookup(struct fc_lport *, u32 port_id); |
75cc8cfc6
|
890 |
int fc_lport_bsg_request(struct bsg_job *); |
3726f3584
|
891 |
void fc_lport_set_local_id(struct fc_lport *, u32 port_id); |
70d53b046
|
892 |
void fc_lport_iterate(void (*func)(struct fc_lport *, void *), void *); |
a51ab3960
|
893 894 |
/* |
42e9a92fe
|
895 896 |
* REMOTE PORT LAYER *****************************/ |
3a3b42bf8
|
897 |
void fc_rport_terminate_io(struct fc_rport *); |
e87b77779
|
898 899 |
struct fc_rport_priv *fc_rport_lookup(const struct fc_lport *lport, u32 port_id); |
2580064b5
|
900 |
struct fc_rport_priv *fc_rport_create(struct fc_lport *, u32); |
944ef9689
|
901 |
void fc_rport_destroy(struct kref *kref); |
05d7d3b0b
|
902 |
int fc_rport_login(struct fc_rport_priv *rdata); |
c96c792ae
|
903 |
int fc_rport_logoff(struct fc_rport_priv *rdata); |
e76ee65fa
|
904 |
void fc_rport_recv_req(struct fc_lport *lport, struct fc_frame *fp); |
5922a9574
|
905 |
void fc_rport_flush_queue(void); |
42e9a92fe
|
906 |
|
34f42a070
|
907 |
/* |
42e9a92fe
|
908 909 |
* DISCOVERY LAYER *****************************/ |
0807619d3
|
910 911 |
void fc_disc_init(struct fc_lport *); void fc_disc_config(struct fc_lport *, void *); |
42e9a92fe
|
912 |
|
0685230c5
|
913 914 915 916 |
static inline struct fc_lport *fc_disc_lport(struct fc_disc *disc) { return container_of(disc, struct fc_lport, disc); } |
34f42a070
|
917 |
/* |
3a3b42bf8
|
918 |
* FCP LAYER |
42e9a92fe
|
919 |
*****************************/ |
42e9a92fe
|
920 |
int fc_fcp_init(struct fc_lport *); |
3a3b42bf8
|
921 |
void fc_fcp_destroy(struct fc_lport *); |
42e9a92fe
|
922 923 |
/* |
3a3b42bf8
|
924 925 |
* SCSI INTERACTION LAYER *****************************/ |
f281233d3
|
926 |
int fc_queuecommand(struct Scsi_Host *, struct scsi_cmnd *); |
3a3b42bf8
|
927 928 929 930 |
int fc_eh_abort(struct scsi_cmnd *); int fc_eh_device_reset(struct scsi_cmnd *); int fc_eh_host_reset(struct scsi_cmnd *); int fc_slave_alloc(struct scsi_device *); |
42e9a92fe
|
931 |
|
34f42a070
|
932 |
/* |
42e9a92fe
|
933 934 |
* ELS/CT interface *****************************/ |
3a3b42bf8
|
935 936 937 |
int fc_elsct_init(struct fc_lport *); struct fc_seq *fc_elsct_send(struct fc_lport *, u32 did, struct fc_frame *, |
11b561886
|
938 939 |
unsigned int op, void (*resp)(struct fc_seq *, |
3a3b42bf8
|
940 |
struct fc_frame *, |
11b561886
|
941 942 943 944 |
void *arg), void *arg, u32 timer_msec); void fc_lport_flogi_resp(struct fc_seq *, struct fc_frame *, void *); void fc_lport_logo_resp(struct fc_seq *, struct fc_frame *, void *); |
24f089e2f
|
945 946 947 948 |
void fc_fill_reply_hdr(struct fc_frame *, const struct fc_frame *, enum fc_rctl, u32 parm_offset); void fc_fill_hdr(struct fc_frame *, const struct fc_frame *, enum fc_rctl, u32 f_ctl, u16 seq_cnt, u32 parm_offset); |
42e9a92fe
|
949 |
|
34f42a070
|
950 |
/* |
42e9a92fe
|
951 952 |
* EXCHANGE MANAGER LAYER *****************************/ |
3a3b42bf8
|
953 |
int fc_exch_init(struct fc_lport *); |
4e5fae7ad
|
954 |
void fc_exch_update_stats(struct fc_lport *lport); |
3afd2d152
|
955 956 957 958 959 960 961 |
struct fc_seq *fc_exch_seq_send(struct fc_lport *lport, struct fc_frame *fp, void (*resp)(struct fc_seq *, struct fc_frame *fp, void *arg), void (*destructor)(struct fc_seq *, void *), void *arg, u32 timer_msec); |
7ab24dd16
|
962 963 |
void fc_seq_els_rsp_send(struct fc_frame *, enum fc_els_cmd, struct fc_seq_els_data *); |
c6865b30b
|
964 |
struct fc_seq *fc_seq_start_next(struct fc_seq *sp); |
f1d61e6e6
|
965 966 967 |
void fc_seq_set_resp(struct fc_seq *sp, void (*resp)(struct fc_seq *, struct fc_frame *, void *), void *arg); |
96d564e24
|
968 |
struct fc_seq *fc_seq_assign(struct fc_lport *lport, struct fc_frame *fp); |
9625cc483
|
969 |
void fc_seq_release(struct fc_seq *sp); |
3a3b42bf8
|
970 971 |
struct fc_exch_mgr_anchor *fc_exch_mgr_add(struct fc_lport *, struct fc_exch_mgr *, |
96316099a
|
972 |
bool (*match)(struct fc_frame *)); |
3a3b42bf8
|
973 |
void fc_exch_mgr_del(struct fc_exch_mgr_anchor *); |
174e1ebff
|
974 |
int fc_exch_mgr_list_clone(struct fc_lport *src, struct fc_lport *dst); |
3a3b42bf8
|
975 976 |
struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *, enum fc_class class, u16 min_xid, u16 max_xid, |
52ff878c9
|
977 |
bool (*match)(struct fc_frame *)); |
3a3b42bf8
|
978 979 |
void fc_exch_mgr_free(struct fc_lport *); void fc_exch_recv(struct fc_lport *, struct fc_frame *); |
1f6ff364c
|
980 |
void fc_exch_mgr_reset(struct fc_lport *, u32 s_id, u32 d_id); |
0cac937da
|
981 |
int fc_seq_send(struct fc_lport *lport, struct fc_seq *sp, struct fc_frame *fp); |
0ebaed17f
|
982 |
int fc_seq_exch_abort(const struct fc_seq *, unsigned int timer_msec); |
768c72cc3
|
983 |
void fc_exch_done(struct fc_seq *sp); |
42e9a92fe
|
984 985 986 987 |
/* * Functions for fc_functions_template */ |
3a3b42bf8
|
988 |
void fc_get_host_speed(struct Scsi_Host *); |
3a3b42bf8
|
989 990 |
void fc_get_host_port_state(struct Scsi_Host *); void fc_set_rport_loss_tmo(struct fc_rport *, u32 timeout); |
42e9a92fe
|
991 |
struct fc_host_statistics *fc_get_host_stats(struct Scsi_Host *); |
42e9a92fe
|
992 |
#endif /* _LIBFC_H_ */ |