| /* 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 */ |