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