James Smart | ca19bcd | 2020-03-31 09:49:48 -0700 | [diff] [blame] | 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 | |
James Smart | 3b8281b | 2020-03-31 09:49:49 -0700 | [diff] [blame] | 19 | union nvmefc_ls_requests { |
James Smart | fd5a5f2 | 2020-03-31 09:49:52 -0700 | [diff] [blame] | 20 | struct fcnvme_ls_rqst_w0 w0; |
James Smart | 3b8281b | 2020-03-31 09:49:49 -0700 | [diff] [blame] | 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 | |
| 27 | union 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 | |
James Smart | ca19bcd | 2020-03-31 09:49:48 -0700 | [diff] [blame] | 35 | static inline void |
| 36 | nvme_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 | |
| 48 | static inline int |
| 49 | nvme_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 */ |
| 67 | enum { |
| 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 | |
| 108 | static 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 | |
James Smart | fd5a5f2 | 2020-03-31 09:49:52 -0700 | [diff] [blame] | 149 | #define NVME_FC_LAST_LS_CMD_VALUE FCNVME_LS_DISCONNECT_CONN |
| 150 | |
| 151 | static 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 | |
| 161 | static inline void |
| 162 | nvmefc_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 | |
| 192 | static inline int |
| 193 | nvmefc_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 | |
James Smart | ca19bcd | 2020-03-31 09:49:48 -0700 | [diff] [blame] | 227 | #endif /* _NVME_FC_TRANSPORT_H */ |