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