forked from Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
227 lines
6.0 KiB
227 lines
6.0 KiB
/* SPDX-License-Identifier: GPL-2.0 */ |
|
/* |
|
* Copyright (c) 2016, Avago Technologies |
|
*/ |
|
|
|
#ifndef _NVME_FC_TRANSPORT_H |
|
#define _NVME_FC_TRANSPORT_H 1 |
|
|
|
|
|
/* |
|
* Common definitions between the nvme_fc (host) transport and |
|
* nvmet_fc (target) transport implementation. |
|
*/ |
|
|
|
/* |
|
* ****************** FC-NVME LS HANDLING ****************** |
|
*/ |
|
|
|
union nvmefc_ls_requests { |
|
struct fcnvme_ls_rqst_w0 w0; |
|
struct fcnvme_ls_cr_assoc_rqst rq_cr_assoc; |
|
struct fcnvme_ls_cr_conn_rqst rq_cr_conn; |
|
struct fcnvme_ls_disconnect_assoc_rqst rq_dis_assoc; |
|
struct fcnvme_ls_disconnect_conn_rqst rq_dis_conn; |
|
} __aligned(128); /* alignment for other things alloc'd with */ |
|
|
|
union nvmefc_ls_responses { |
|
struct fcnvme_ls_rjt rsp_rjt; |
|
struct fcnvme_ls_cr_assoc_acc rsp_cr_assoc; |
|
struct fcnvme_ls_cr_conn_acc rsp_cr_conn; |
|
struct fcnvme_ls_disconnect_assoc_acc rsp_dis_assoc; |
|
struct fcnvme_ls_disconnect_conn_acc rsp_dis_conn; |
|
} __aligned(128); /* alignment for other things alloc'd with */ |
|
|
|
static inline void |
|
nvme_fc_format_rsp_hdr(void *buf, u8 ls_cmd, __be32 desc_len, u8 rqst_ls_cmd) |
|
{ |
|
struct fcnvme_ls_acc_hdr *acc = buf; |
|
|
|
acc->w0.ls_cmd = ls_cmd; |
|
acc->desc_list_len = desc_len; |
|
acc->rqst.desc_tag = cpu_to_be32(FCNVME_LSDESC_RQST); |
|
acc->rqst.desc_len = |
|
fcnvme_lsdesc_len(sizeof(struct fcnvme_lsdesc_rqst)); |
|
acc->rqst.w0.ls_cmd = rqst_ls_cmd; |
|
} |
|
|
|
static inline int |
|
nvme_fc_format_rjt(void *buf, u16 buflen, u8 ls_cmd, |
|
u8 reason, u8 explanation, u8 vendor) |
|
{ |
|
struct fcnvme_ls_rjt *rjt = buf; |
|
|
|
nvme_fc_format_rsp_hdr(buf, FCNVME_LSDESC_RQST, |
|
fcnvme_lsdesc_len(sizeof(struct fcnvme_ls_rjt)), |
|
ls_cmd); |
|
rjt->rjt.desc_tag = cpu_to_be32(FCNVME_LSDESC_RJT); |
|
rjt->rjt.desc_len = fcnvme_lsdesc_len(sizeof(struct fcnvme_lsdesc_rjt)); |
|
rjt->rjt.reason_code = reason; |
|
rjt->rjt.reason_explanation = explanation; |
|
rjt->rjt.vendor = vendor; |
|
|
|
return sizeof(struct fcnvme_ls_rjt); |
|
} |
|
|
|
/* Validation Error indexes into the string table below */ |
|
enum { |
|
VERR_NO_ERROR = 0, |
|
VERR_CR_ASSOC_LEN = 1, |
|
VERR_CR_ASSOC_RQST_LEN = 2, |
|
VERR_CR_ASSOC_CMD = 3, |
|
VERR_CR_ASSOC_CMD_LEN = 4, |
|
VERR_ERSP_RATIO = 5, |
|
VERR_ASSOC_ALLOC_FAIL = 6, |
|
VERR_QUEUE_ALLOC_FAIL = 7, |
|
VERR_CR_CONN_LEN = 8, |
|
VERR_CR_CONN_RQST_LEN = 9, |
|
VERR_ASSOC_ID = 10, |
|
VERR_ASSOC_ID_LEN = 11, |
|
VERR_NO_ASSOC = 12, |
|
VERR_CONN_ID = 13, |
|
VERR_CONN_ID_LEN = 14, |
|
VERR_INVAL_CONN = 15, |
|
VERR_CR_CONN_CMD = 16, |
|
VERR_CR_CONN_CMD_LEN = 17, |
|
VERR_DISCONN_LEN = 18, |
|
VERR_DISCONN_RQST_LEN = 19, |
|
VERR_DISCONN_CMD = 20, |
|
VERR_DISCONN_CMD_LEN = 21, |
|
VERR_DISCONN_SCOPE = 22, |
|
VERR_RS_LEN = 23, |
|
VERR_RS_RQST_LEN = 24, |
|
VERR_RS_CMD = 25, |
|
VERR_RS_CMD_LEN = 26, |
|
VERR_RS_RCTL = 27, |
|
VERR_RS_RO = 28, |
|
VERR_LSACC = 29, |
|
VERR_LSDESC_RQST = 30, |
|
VERR_LSDESC_RQST_LEN = 31, |
|
VERR_CR_ASSOC = 32, |
|
VERR_CR_ASSOC_ACC_LEN = 33, |
|
VERR_CR_CONN = 34, |
|
VERR_CR_CONN_ACC_LEN = 35, |
|
VERR_DISCONN = 36, |
|
VERR_DISCONN_ACC_LEN = 37, |
|
}; |
|
|
|
static char *validation_errors[] = { |
|
"OK", |
|
"Bad CR_ASSOC Length", |
|
"Bad CR_ASSOC Rqst Length", |
|
"Not CR_ASSOC Cmd", |
|
"Bad CR_ASSOC Cmd Length", |
|
"Bad Ersp Ratio", |
|
"Association Allocation Failed", |
|
"Queue Allocation Failed", |
|
"Bad CR_CONN Length", |
|
"Bad CR_CONN Rqst Length", |
|
"Not Association ID", |
|
"Bad Association ID Length", |
|
"No Association", |
|
"Not Connection ID", |
|
"Bad Connection ID Length", |
|
"Invalid Connection ID", |
|
"Not CR_CONN Cmd", |
|
"Bad CR_CONN Cmd Length", |
|
"Bad DISCONN Length", |
|
"Bad DISCONN Rqst Length", |
|
"Not DISCONN Cmd", |
|
"Bad DISCONN Cmd Length", |
|
"Bad Disconnect Scope", |
|
"Bad RS Length", |
|
"Bad RS Rqst Length", |
|
"Not RS Cmd", |
|
"Bad RS Cmd Length", |
|
"Bad RS R_CTL", |
|
"Bad RS Relative Offset", |
|
"Not LS_ACC", |
|
"Not LSDESC_RQST", |
|
"Bad LSDESC_RQST Length", |
|
"Not CR_ASSOC Rqst", |
|
"Bad CR_ASSOC ACC Length", |
|
"Not CR_CONN Rqst", |
|
"Bad CR_CONN ACC Length", |
|
"Not Disconnect Rqst", |
|
"Bad Disconnect ACC Length", |
|
}; |
|
|
|
#define NVME_FC_LAST_LS_CMD_VALUE FCNVME_LS_DISCONNECT_CONN |
|
|
|
static char *nvmefc_ls_names[] = { |
|
"Reserved (0)", |
|
"RJT (1)", |
|
"ACC (2)", |
|
"Create Association", |
|
"Create Connection", |
|
"Disconnect Association", |
|
"Disconnect Connection", |
|
}; |
|
|
|
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) |
|
{ |
|
lsreq->rqstaddr = discon_rqst; |
|
lsreq->rqstlen = sizeof(*discon_rqst); |
|
lsreq->rspaddr = discon_acc; |
|
lsreq->rsplen = sizeof(*discon_acc); |
|
lsreq->timeout = NVME_FC_LS_TIMEOUT_SEC; |
|
|
|
discon_rqst->w0.ls_cmd = FCNVME_LS_DISCONNECT_ASSOC; |
|
discon_rqst->desc_list_len = cpu_to_be32( |
|
sizeof(struct fcnvme_lsdesc_assoc_id) + |
|
sizeof(struct fcnvme_lsdesc_disconn_cmd)); |
|
|
|
discon_rqst->associd.desc_tag = cpu_to_be32(FCNVME_LSDESC_ASSOC_ID); |
|
discon_rqst->associd.desc_len = |
|
fcnvme_lsdesc_len( |
|
sizeof(struct fcnvme_lsdesc_assoc_id)); |
|
|
|
discon_rqst->associd.association_id = cpu_to_be64(association_id); |
|
|
|
discon_rqst->discon_cmd.desc_tag = cpu_to_be32( |
|
FCNVME_LSDESC_DISCONN_CMD); |
|
discon_rqst->discon_cmd.desc_len = |
|
fcnvme_lsdesc_len( |
|
sizeof(struct fcnvme_lsdesc_disconn_cmd)); |
|
} |
|
|
|
static inline int |
|
nvmefc_vldt_lsreq_discon_assoc(u32 rqstlen, |
|
struct fcnvme_ls_disconnect_assoc_rqst *rqst) |
|
{ |
|
int ret = 0; |
|
|
|
if (rqstlen < sizeof(struct fcnvme_ls_disconnect_assoc_rqst)) |
|
ret = VERR_DISCONN_LEN; |
|
else if (rqst->desc_list_len != |
|
fcnvme_lsdesc_len( |
|
sizeof(struct fcnvme_ls_disconnect_assoc_rqst))) |
|
ret = VERR_DISCONN_RQST_LEN; |
|
else if (rqst->associd.desc_tag != cpu_to_be32(FCNVME_LSDESC_ASSOC_ID)) |
|
ret = VERR_ASSOC_ID; |
|
else if (rqst->associd.desc_len != |
|
fcnvme_lsdesc_len( |
|
sizeof(struct fcnvme_lsdesc_assoc_id))) |
|
ret = VERR_ASSOC_ID_LEN; |
|
else if (rqst->discon_cmd.desc_tag != |
|
cpu_to_be32(FCNVME_LSDESC_DISCONN_CMD)) |
|
ret = VERR_DISCONN_CMD; |
|
else if (rqst->discon_cmd.desc_len != |
|
fcnvme_lsdesc_len( |
|
sizeof(struct fcnvme_lsdesc_disconn_cmd))) |
|
ret = VERR_DISCONN_CMD_LEN; |
|
/* |
|
* As the standard changed on the LS, check if old format and scope |
|
* something other than Association (e.g. 0). |
|
*/ |
|
else if (rqst->discon_cmd.rsvd8[0]) |
|
ret = VERR_DISCONN_SCOPE; |
|
|
|
return ret; |
|
} |
|
|
|
#endif /* _NVME_FC_TRANSPORT_H */
|
|
|