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