+/* reject CT_IU reason codes acc. to FC-GS-4 */
+static const struct zfcp_rc_entry zfcp_ct_rc[] = {
+ {0x01, "invalid command code"},
+ {0x02, "invalid version level"},
+ {0x03, "logical error"},
+ {0x04, "invalid CT_IU size"},
+ {0x05, "logical busy"},
+ {0x07, "protocol error"},
+ {0x09, "unable to perform command request"},
+ {0x0b, "command not supported"},
+ {0x0d, "server not available"},
+ {0x0e, "session could not be established"},
+ {0xff, "vendor specific error"},
+ {0, NULL},
+};
+
+/* LS_RJT reason codes acc. to FC-FS */
+static const struct zfcp_rc_entry zfcp_ls_rjt_rc[] = {
+ {0x01, "invalid LS_Command code"},
+ {0x03, "logical error"},
+ {0x05, "logical busy"},
+ {0x07, "protocol error"},
+ {0x09, "unable to perform command request"},
+ {0x0b, "command not supported"},
+ {0x0e, "command already in progress"},
+ {0xff, "vendor specific error"},
+ {0, NULL},
+};
+
+/* reject reason codes according to FC-PH/FC-FS */
+static const struct zfcp_rc_entry zfcp_p_rjt_rc[] = {
+ {0x01, "invalid D_ID"},
+ {0x02, "invalid S_ID"},
+ {0x03, "Nx_Port not available, temporary"},
+ {0x04, "Nx_Port not available, permament"},
+ {0x05, "class not supported"},
+ {0x06, "delimiter usage error"},
+ {0x07, "TYPE not supported"},
+ {0x08, "invalid Link_Control"},
+ {0x09, "invalid R_CTL field"},
+ {0x0a, "invalid F_CTL field"},
+ {0x0b, "invalid OX_ID"},
+ {0x0c, "invalid RX_ID"},
+ {0x0d, "invalid SEQ_ID"},
+ {0x0e, "invalid DF_CTL"},
+ {0x0f, "invalid SEQ_CNT"},
+ {0x10, "invalid parameter field"},
+ {0x11, "exchange error"},
+ {0x12, "protocol error"},
+ {0x13, "incorrect length"},
+ {0x14, "unsupported ACK"},
+ {0x15, "class of service not supported by entity at FFFFFE"},
+ {0x16, "login required"},
+ {0x17, "excessive sequences attempted"},
+ {0x18, "unable to establish exchange"},
+ {0x1a, "fabric path not available"},
+ {0x1b, "invalid VC_ID (class 4)"},
+ {0x1c, "invalid CS_CTL field"},
+ {0x1d, "insufficient resources for VC (class 4)"},
+ {0x1f, "invalid class of service"},
+ {0x20, "preemption request rejected"},
+ {0x21, "preemption not enabled"},
+ {0x22, "multicast error"},
+ {0x23, "multicast error terminate"},
+ {0x24, "process login required"},
+ {0xff, "vendor specific reject"},
+ {0, NULL},
+};
+
+/**
+ * zfcp_rc_description - return description for given reaon code
+ * @code: reason code
+ * @rc_table: table of reason codes and descriptions
+ */
+static inline const char *
+zfcp_rc_description(u8 code, const struct zfcp_rc_entry *rc_table)
+{
+ const char *descr = "unknown reason code";
+
+ do {
+ if (code == rc_table->code) {
+ descr = rc_table->description;
+ break;
+ }
+ rc_table++;
+ } while (rc_table->code && rc_table->description);
+
+ return descr;
+}
+
+/**
+ * zfcp_check_ct_response - evaluate reason code for CT_IU
+ * @rjt: response payload to an CT_IU request
+ * Return: 0 for accept CT_IU, 1 for reject CT_IU or invlid response code
+ */
+int
+zfcp_check_ct_response(struct ct_hdr *rjt)
+{
+ if (rjt->cmd_rsp_code == ZFCP_CT_ACCEPT)
+ return 0;
+
+ if (rjt->cmd_rsp_code != ZFCP_CT_REJECT) {
+ ZFCP_LOG_NORMAL("error: invalid Generic Service command/"
+ "response code (0x%04hx)\n",
+ rjt->cmd_rsp_code);
+ return 1;
+ }
+
+ ZFCP_LOG_INFO("Generic Service command rejected\n");
+ ZFCP_LOG_INFO("%s (0x%02x, 0x%02x, 0x%02x)\n",
+ zfcp_rc_description(rjt->reason_code, zfcp_ct_rc),
+ (u32) rjt->reason_code, (u32) rjt->reason_code_expl,
+ (u32) rjt->vendor_unique);
+
+ return 1;
+}
+
+/**
+ * zfcp_print_els_rjt - print reject parameter and description for ELS reject
+ * @rjt_par: reject parameter acc. to FC-PH/FC-FS
+ * @rc_table: table of reason codes and descriptions
+ */
+static inline void
+zfcp_print_els_rjt(struct zfcp_ls_rjt_par *rjt_par,
+ const struct zfcp_rc_entry *rc_table)
+{
+ ZFCP_LOG_INFO("%s (%02x %02x %02x %02x)\n",
+ zfcp_rc_description(rjt_par->reason_code, rc_table),
+ (u32) rjt_par->action, (u32) rjt_par->reason_code,
+ (u32) rjt_par->reason_expl, (u32) rjt_par->vendor_unique);
+}
+
+/**
+ * zfcp_fsf_handle_els_rjt - evaluate status qualifier/reason code on ELS reject
+ * @sq: status qualifier word
+ * @rjt_par: reject parameter as described in FC-PH and FC-FS
+ * Return: -EROMTEIO for LS_RJT, -EREMCHG for invalid D_ID, -EIO else
+ */
+int
+zfcp_handle_els_rjt(u32 sq, struct zfcp_ls_rjt_par *rjt_par)
+{
+ int ret = -EIO;
+
+ if (sq == FSF_IOSTAT_NPORT_RJT) {
+ ZFCP_LOG_INFO("ELS rejected (P_RJT)\n");
+ zfcp_print_els_rjt(rjt_par, zfcp_p_rjt_rc);
+ /* invalid d_id */
+ if (rjt_par->reason_code == 0x01)
+ ret = -EREMCHG;
+ } else if (sq == FSF_IOSTAT_FABRIC_RJT) {
+ ZFCP_LOG_INFO("ELS rejected (F_RJT)\n");
+ zfcp_print_els_rjt(rjt_par, zfcp_p_rjt_rc);
+ /* invalid d_id */
+ if (rjt_par->reason_code == 0x01)
+ ret = -EREMCHG;
+ } else if (sq == FSF_IOSTAT_LS_RJT) {
+ ZFCP_LOG_INFO("ELS rejected (LS_RJT)\n");
+ zfcp_print_els_rjt(rjt_par, zfcp_ls_rjt_rc);
+ ret = -EREMOTEIO;
+ } else
+ ZFCP_LOG_INFO("unexpected SQ: 0x%02x\n", sq);
+
+ return ret;
+}
+
+/**
+ * zfcp_plogi_evaluate - evaluate PLOGI playload and copy important fields
+ * into zfcp_port structure
+ * @port: zfcp_port structure
+ * @plogi: plogi payload
+ */
+void
+zfcp_plogi_evaluate(struct zfcp_port *port, struct fsf_plogi *plogi)
+{
+ port->maxframe_size = plogi->serv_param.common_serv_param[7] |
+ ((plogi->serv_param.common_serv_param[6] & 0x0F) << 8);
+ if (plogi->serv_param.class1_serv_param[0] & 0x80)
+ port->supported_classes |= FC_COS_CLASS1;
+ if (plogi->serv_param.class2_serv_param[0] & 0x80)
+ port->supported_classes |= FC_COS_CLASS2;
+ if (plogi->serv_param.class3_serv_param[0] & 0x80)
+ port->supported_classes |= FC_COS_CLASS3;
+ if (plogi->serv_param.class4_serv_param[0] & 0x80)
+ port->supported_classes |= FC_COS_CLASS4;
+}
+