1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | /* |
3 | * Copyright (c) 2016, Avago Technologies |
4 | */ |
5 | |
6 | #ifndef _NVME_FC_TRANSPORT_H |
7 | #define _NVME_FC_TRANSPORT_H 1 |
8 | |
9 | |
10 | /* |
11 | * Common definitions between the nvme_fc (host) transport and |
12 | * nvmet_fc (target) transport implementation. |
13 | */ |
14 | |
15 | /* |
16 | * ****************** FC-NVME LS HANDLING ****************** |
17 | */ |
18 | |
19 | union nvmefc_ls_requests { |
20 | struct fcnvme_ls_rqst_w0 w0; |
21 | struct fcnvme_ls_cr_assoc_rqst rq_cr_assoc; |
22 | struct fcnvme_ls_cr_conn_rqst rq_cr_conn; |
23 | struct fcnvme_ls_disconnect_assoc_rqst rq_dis_assoc; |
24 | struct fcnvme_ls_disconnect_conn_rqst rq_dis_conn; |
25 | } __aligned(128); /* alignment for other things alloc'd with */ |
26 | |
27 | union nvmefc_ls_responses { |
28 | struct fcnvme_ls_rjt rsp_rjt; |
29 | struct fcnvme_ls_cr_assoc_acc rsp_cr_assoc; |
30 | struct fcnvme_ls_cr_conn_acc rsp_cr_conn; |
31 | struct fcnvme_ls_disconnect_assoc_acc rsp_dis_assoc; |
32 | struct fcnvme_ls_disconnect_conn_acc rsp_dis_conn; |
33 | } __aligned(128); /* alignment for other things alloc'd with */ |
34 | |
35 | static inline void |
36 | nvme_fc_format_rsp_hdr(void *buf, u8 ls_cmd, __be32 desc_len, u8 rqst_ls_cmd) |
37 | { |
38 | struct fcnvme_ls_acc_hdr *acc = buf; |
39 | |
40 | acc->w0.ls_cmd = ls_cmd; |
41 | acc->desc_list_len = desc_len; |
42 | acc->rqst.desc_tag = cpu_to_be32(FCNVME_LSDESC_RQST); |
43 | acc->rqst.desc_len = |
44 | fcnvme_lsdesc_len(sz: sizeof(struct fcnvme_lsdesc_rqst)); |
45 | acc->rqst.w0.ls_cmd = rqst_ls_cmd; |
46 | } |
47 | |
48 | static inline int |
49 | nvme_fc_format_rjt(void *buf, u16 buflen, u8 ls_cmd, |
50 | u8 reason, u8 explanation, u8 vendor) |
51 | { |
52 | struct fcnvme_ls_rjt *rjt = buf; |
53 | |
54 | nvme_fc_format_rsp_hdr(buf, ls_cmd: FCNVME_LSDESC_RQST, |
55 | desc_len: fcnvme_lsdesc_len(sz: sizeof(struct fcnvme_ls_rjt)), |
56 | rqst_ls_cmd: ls_cmd); |
57 | rjt->rjt.desc_tag = cpu_to_be32(FCNVME_LSDESC_RJT); |
58 | rjt->rjt.desc_len = fcnvme_lsdesc_len(sz: sizeof(struct fcnvme_lsdesc_rjt)); |
59 | rjt->rjt.reason_code = reason; |
60 | rjt->rjt.reason_explanation = explanation; |
61 | rjt->rjt.vendor = vendor; |
62 | |
63 | return sizeof(struct fcnvme_ls_rjt); |
64 | } |
65 | |
66 | /* Validation Error indexes into the string table below */ |
67 | enum { |
68 | VERR_NO_ERROR = 0, |
69 | VERR_CR_ASSOC_LEN = 1, |
70 | VERR_CR_ASSOC_RQST_LEN = 2, |
71 | VERR_CR_ASSOC_CMD = 3, |
72 | VERR_CR_ASSOC_CMD_LEN = 4, |
73 | VERR_ERSP_RATIO = 5, |
74 | VERR_ASSOC_ALLOC_FAIL = 6, |
75 | VERR_QUEUE_ALLOC_FAIL = 7, |
76 | VERR_CR_CONN_LEN = 8, |
77 | VERR_CR_CONN_RQST_LEN = 9, |
78 | VERR_ASSOC_ID = 10, |
79 | VERR_ASSOC_ID_LEN = 11, |
80 | VERR_NO_ASSOC = 12, |
81 | VERR_CONN_ID = 13, |
82 | VERR_CONN_ID_LEN = 14, |
83 | VERR_INVAL_CONN = 15, |
84 | VERR_CR_CONN_CMD = 16, |
85 | VERR_CR_CONN_CMD_LEN = 17, |
86 | VERR_DISCONN_LEN = 18, |
87 | VERR_DISCONN_RQST_LEN = 19, |
88 | VERR_DISCONN_CMD = 20, |
89 | VERR_DISCONN_CMD_LEN = 21, |
90 | VERR_DISCONN_SCOPE = 22, |
91 | VERR_RS_LEN = 23, |
92 | VERR_RS_RQST_LEN = 24, |
93 | VERR_RS_CMD = 25, |
94 | VERR_RS_CMD_LEN = 26, |
95 | VERR_RS_RCTL = 27, |
96 | VERR_RS_RO = 28, |
97 | VERR_LSACC = 29, |
98 | VERR_LSDESC_RQST = 30, |
99 | VERR_LSDESC_RQST_LEN = 31, |
100 | VERR_CR_ASSOC = 32, |
101 | VERR_CR_ASSOC_ACC_LEN = 33, |
102 | VERR_CR_CONN = 34, |
103 | VERR_CR_CONN_ACC_LEN = 35, |
104 | VERR_DISCONN = 36, |
105 | VERR_DISCONN_ACC_LEN = 37, |
106 | }; |
107 | |
108 | static char *validation_errors[] = { |
109 | "OK" , |
110 | "Bad CR_ASSOC Length" , |
111 | "Bad CR_ASSOC Rqst Length" , |
112 | "Not CR_ASSOC Cmd" , |
113 | "Bad CR_ASSOC Cmd Length" , |
114 | "Bad Ersp Ratio" , |
115 | "Association Allocation Failed" , |
116 | "Queue Allocation Failed" , |
117 | "Bad CR_CONN Length" , |
118 | "Bad CR_CONN Rqst Length" , |
119 | "Not Association ID" , |
120 | "Bad Association ID Length" , |
121 | "No Association" , |
122 | "Not Connection ID" , |
123 | "Bad Connection ID Length" , |
124 | "Invalid Connection ID" , |
125 | "Not CR_CONN Cmd" , |
126 | "Bad CR_CONN Cmd Length" , |
127 | "Bad DISCONN Length" , |
128 | "Bad DISCONN Rqst Length" , |
129 | "Not DISCONN Cmd" , |
130 | "Bad DISCONN Cmd Length" , |
131 | "Bad Disconnect Scope" , |
132 | "Bad RS Length" , |
133 | "Bad RS Rqst Length" , |
134 | "Not RS Cmd" , |
135 | "Bad RS Cmd Length" , |
136 | "Bad RS R_CTL" , |
137 | "Bad RS Relative Offset" , |
138 | "Not LS_ACC" , |
139 | "Not LSDESC_RQST" , |
140 | "Bad LSDESC_RQST Length" , |
141 | "Not CR_ASSOC Rqst" , |
142 | "Bad CR_ASSOC ACC Length" , |
143 | "Not CR_CONN Rqst" , |
144 | "Bad CR_CONN ACC Length" , |
145 | "Not Disconnect Rqst" , |
146 | "Bad Disconnect ACC Length" , |
147 | }; |
148 | |
149 | #define NVME_FC_LAST_LS_CMD_VALUE FCNVME_LS_DISCONNECT_CONN |
150 | |
151 | static char *nvmefc_ls_names[] = { |
152 | "Reserved (0)" , |
153 | "RJT (1)" , |
154 | "ACC (2)" , |
155 | "Create Association" , |
156 | "Create Connection" , |
157 | "Disconnect Association" , |
158 | "Disconnect Connection" , |
159 | }; |
160 | |
161 | static inline void |
162 | nvmefc_fmt_lsreq_discon_assoc(struct nvmefc_ls_req *lsreq, |
163 | struct fcnvme_ls_disconnect_assoc_rqst *discon_rqst, |
164 | struct fcnvme_ls_disconnect_assoc_acc *discon_acc, |
165 | u64 association_id) |
166 | { |
167 | lsreq->rqstaddr = discon_rqst; |
168 | lsreq->rqstlen = sizeof(*discon_rqst); |
169 | lsreq->rspaddr = discon_acc; |
170 | lsreq->rsplen = sizeof(*discon_acc); |
171 | lsreq->timeout = NVME_FC_LS_TIMEOUT_SEC; |
172 | |
173 | discon_rqst->w0.ls_cmd = FCNVME_LS_DISCONNECT_ASSOC; |
174 | discon_rqst->desc_list_len = cpu_to_be32( |
175 | sizeof(struct fcnvme_lsdesc_assoc_id) + |
176 | sizeof(struct fcnvme_lsdesc_disconn_cmd)); |
177 | |
178 | discon_rqst->associd.desc_tag = cpu_to_be32(FCNVME_LSDESC_ASSOC_ID); |
179 | discon_rqst->associd.desc_len = |
180 | fcnvme_lsdesc_len( |
181 | sz: sizeof(struct fcnvme_lsdesc_assoc_id)); |
182 | |
183 | discon_rqst->associd.association_id = cpu_to_be64(association_id); |
184 | |
185 | discon_rqst->discon_cmd.desc_tag = cpu_to_be32( |
186 | FCNVME_LSDESC_DISCONN_CMD); |
187 | discon_rqst->discon_cmd.desc_len = |
188 | fcnvme_lsdesc_len( |
189 | sz: sizeof(struct fcnvme_lsdesc_disconn_cmd)); |
190 | } |
191 | |
192 | static inline int |
193 | nvmefc_vldt_lsreq_discon_assoc(u32 rqstlen, |
194 | struct fcnvme_ls_disconnect_assoc_rqst *rqst) |
195 | { |
196 | int ret = 0; |
197 | |
198 | if (rqstlen < sizeof(struct fcnvme_ls_disconnect_assoc_rqst)) |
199 | ret = VERR_DISCONN_LEN; |
200 | else if (rqst->desc_list_len != |
201 | fcnvme_lsdesc_len( |
202 | sz: sizeof(struct fcnvme_ls_disconnect_assoc_rqst))) |
203 | ret = VERR_DISCONN_RQST_LEN; |
204 | else if (rqst->associd.desc_tag != cpu_to_be32(FCNVME_LSDESC_ASSOC_ID)) |
205 | ret = VERR_ASSOC_ID; |
206 | else if (rqst->associd.desc_len != |
207 | fcnvme_lsdesc_len( |
208 | sz: sizeof(struct fcnvme_lsdesc_assoc_id))) |
209 | ret = VERR_ASSOC_ID_LEN; |
210 | else if (rqst->discon_cmd.desc_tag != |
211 | cpu_to_be32(FCNVME_LSDESC_DISCONN_CMD)) |
212 | ret = VERR_DISCONN_CMD; |
213 | else if (rqst->discon_cmd.desc_len != |
214 | fcnvme_lsdesc_len( |
215 | sz: sizeof(struct fcnvme_lsdesc_disconn_cmd))) |
216 | ret = VERR_DISCONN_CMD_LEN; |
217 | /* |
218 | * As the standard changed on the LS, check if old format and scope |
219 | * something other than Association (e.g. 0). |
220 | */ |
221 | else if (rqst->discon_cmd.rsvd8[0]) |
222 | ret = VERR_DISCONN_SCOPE; |
223 | |
224 | return ret; |
225 | } |
226 | |
227 | #endif /* _NVME_FC_TRANSPORT_H */ |
228 | |