1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright(c) 2008 Intel Corporation. All rights reserved. |
4 | * |
5 | * Maintained at www.Open-FCoE.org |
6 | */ |
7 | |
8 | /* |
9 | * Provide interface to send ELS/CT FC frames |
10 | */ |
11 | |
12 | #include <linux/export.h> |
13 | #include <asm/unaligned.h> |
14 | #include <scsi/fc/fc_gs.h> |
15 | #include <scsi/fc/fc_ns.h> |
16 | #include <scsi/fc/fc_els.h> |
17 | #include <scsi/libfc.h> |
18 | #include "fc_encode.h" |
19 | #include "fc_libfc.h" |
20 | |
21 | /** |
22 | * fc_elsct_send() - Send an ELS or CT frame |
23 | * @lport: The local port to send the frame on |
24 | * @did: The destination ID for the frame |
25 | * @fp: The frame to be sent |
26 | * @op: The operational code |
27 | * @resp: The callback routine when the response is received |
28 | * @arg: The argument to pass to the response callback routine |
29 | * @timer_msec: The timeout period for the frame (in msecs) |
30 | */ |
31 | struct fc_seq *fc_elsct_send(struct fc_lport *lport, u32 did, |
32 | struct fc_frame *fp, unsigned int op, |
33 | void (*resp)(struct fc_seq *, |
34 | struct fc_frame *, |
35 | void *), |
36 | void *arg, u32 timer_msec) |
37 | { |
38 | enum fc_rctl r_ctl; |
39 | enum fc_fh_type fh_type; |
40 | int rc; |
41 | |
42 | /* ELS requests */ |
43 | if ((op >= ELS_LS_RJT) && (op <= ELS_AUTH_ELS)) |
44 | rc = fc_els_fill(lport, did, fp, op, r_ctl: &r_ctl, fh_type: &fh_type); |
45 | else { |
46 | /* CT requests */ |
47 | rc = fc_ct_fill(lport, fc_id: did, fp, op, r_ctl: &r_ctl, fh_type: &fh_type, did: &did); |
48 | } |
49 | |
50 | if (rc) { |
51 | fc_frame_free(fp); |
52 | return NULL; |
53 | } |
54 | |
55 | fc_fill_fc_hdr(fp, r_ctl, did, sid: lport->port_id, type: fh_type, |
56 | FC_FCTL_REQ, parm_offset: 0); |
57 | |
58 | return fc_exch_seq_send(lport, fp, resp, NULL, arg, timer_msec); |
59 | } |
60 | EXPORT_SYMBOL(fc_elsct_send); |
61 | |
62 | /** |
63 | * fc_elsct_init() - Initialize the ELS/CT layer |
64 | * @lport: The local port to initialize the ELS/CT layer for |
65 | */ |
66 | int fc_elsct_init(struct fc_lport *lport) |
67 | { |
68 | if (!lport->tt.elsct_send) |
69 | lport->tt.elsct_send = fc_elsct_send; |
70 | |
71 | return 0; |
72 | } |
73 | EXPORT_SYMBOL(fc_elsct_init); |
74 | |
75 | /** |
76 | * fc_els_resp_type() - Return a string describing the ELS response |
77 | * @fp: The frame pointer or possible error code |
78 | */ |
79 | const char *fc_els_resp_type(struct fc_frame *fp) |
80 | { |
81 | const char *msg; |
82 | struct fc_frame_header *fh; |
83 | struct fc_ct_hdr *ct; |
84 | |
85 | if (IS_ERR(ptr: fp)) { |
86 | switch (-PTR_ERR(ptr: fp)) { |
87 | case FC_NO_ERR: |
88 | msg = "response no error" ; |
89 | break; |
90 | case FC_EX_TIMEOUT: |
91 | msg = "response timeout" ; |
92 | break; |
93 | case FC_EX_CLOSED: |
94 | msg = "response closed" ; |
95 | break; |
96 | default: |
97 | msg = "response unknown error" ; |
98 | break; |
99 | } |
100 | } else { |
101 | fh = fc_frame_header_get(fp); |
102 | switch (fh->fh_type) { |
103 | case FC_TYPE_ELS: |
104 | switch (fc_frame_payload_op(fp)) { |
105 | case ELS_LS_ACC: |
106 | msg = "accept" ; |
107 | break; |
108 | case ELS_LS_RJT: |
109 | msg = "reject" ; |
110 | break; |
111 | default: |
112 | msg = "response unknown ELS" ; |
113 | break; |
114 | } |
115 | break; |
116 | case FC_TYPE_CT: |
117 | ct = fc_frame_payload_get(fp, len: sizeof(*ct)); |
118 | if (ct) { |
119 | switch (ntohs(ct->ct_cmd)) { |
120 | case FC_FS_ACC: |
121 | msg = "CT accept" ; |
122 | break; |
123 | case FC_FS_RJT: |
124 | msg = "CT reject" ; |
125 | break; |
126 | default: |
127 | msg = "response unknown CT" ; |
128 | break; |
129 | } |
130 | } else { |
131 | msg = "short CT response" ; |
132 | } |
133 | break; |
134 | default: |
135 | msg = "response not ELS or CT" ; |
136 | break; |
137 | } |
138 | } |
139 | return msg; |
140 | } |
141 | |