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
19union 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
27union 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
35static inline void
36nvme_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(sizeof(struct fcnvme_lsdesc_rqst));
45	acc->rqst.w0.ls_cmd = rqst_ls_cmd;
46}
47
48static inline int
49nvme_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, FCNVME_LSDESC_RQST,
55			fcnvme_lsdesc_len(sizeof(struct fcnvme_ls_rjt)),
56			ls_cmd);
57	rjt->rjt.desc_tag = cpu_to_be32(FCNVME_LSDESC_RJT);
58	rjt->rjt.desc_len = fcnvme_lsdesc_len(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 */
67enum {
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
108static 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
151static 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
161static inline void
162nvmefc_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				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				sizeof(struct fcnvme_lsdesc_disconn_cmd));
190}
191
192static inline int
193nvmefc_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				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				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				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