1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright(c) 2008 Intel Corporation. All rights reserved. 4 * 5 * Maintained at www.Open-FCoE.org 6 */ 7 8 /* 9 * Provide interface to send ELS/CT FC frames 10 */ 11 12 #include <linux/export.h> 13 #include <linux/unaligned.h> 14 #include <scsi/fc/fc_gs.h> 15 #include <scsi/fc/fc_ns.h> 16 #include <scsi/fc/fc_els.h> 17 #include <scsi/libfc.h> 18 #include "fc_encode.h" 19 #include "fc_libfc.h" 20 21 /** 22 * fc_elsct_send() - Send an ELS or CT frame 23 * @lport: The local port to send the frame on 24 * @did: The destination ID for the frame 25 * @fp: The frame to be sent 26 * @op: The operational code 27 * @resp: The callback routine when the response is received 28 * @arg: The argument to pass to the response callback routine 29 * @timer_msec: The timeout period for the frame (in msecs) 30 */ 31 struct fc_seq *fc_elsct_send(struct fc_lport *lport, u32 did, 32 struct fc_frame *fp, unsigned int op, 33 void (*resp)(struct fc_seq *, 34 struct fc_frame *, 35 void *), 36 void *arg, u32 timer_msec) 37 { 38 enum fc_rctl r_ctl; 39 enum fc_fh_type fh_type; 40 int rc; 41 42 /* ELS requests */ 43 if ((op >= ELS_LS_RJT) && (op <= ELS_AUTH_ELS)) 44 rc = fc_els_fill(lport, did, fp, op, &r_ctl, &fh_type); 45 else { 46 /* CT requests */ 47 rc = fc_ct_fill(lport, did, fp, op, &r_ctl, &fh_type, &did); 48 } 49 50 if (rc) { 51 fc_frame_free(fp); 52 return NULL; 53 } 54 55 fc_fill_fc_hdr(fp, r_ctl, did, lport->port_id, fh_type, 56 FC_FCTL_REQ, 0); 57 58 return fc_exch_seq_send(lport, fp, resp, NULL, arg, timer_msec); 59 } 60 EXPORT_SYMBOL(fc_elsct_send); 61 62 /** 63 * fc_elsct_init() - Initialize the ELS/CT layer 64 * @lport: The local port to initialize the ELS/CT layer for 65 */ 66 int fc_elsct_init(struct fc_lport *lport) 67 { 68 if (!lport->tt.elsct_send) 69 lport->tt.elsct_send = fc_elsct_send; 70 71 return 0; 72 } 73 EXPORT_SYMBOL(fc_elsct_init); 74 75 /** 76 * fc_els_resp_type() - Return a string describing the ELS response 77 * @fp: The frame pointer or possible error code 78 */ 79 const char *fc_els_resp_type(struct fc_frame *fp) 80 { 81 const char *msg; 82 struct fc_frame_header *fh; 83 struct fc_ct_hdr *ct; 84 85 if (IS_ERR(fp)) { 86 switch (-PTR_ERR(fp)) { 87 case FC_NO_ERR: 88 msg = "response no error"; 89 break; 90 case FC_EX_TIMEOUT: 91 msg = "response timeout"; 92 break; 93 case FC_EX_CLOSED: 94 msg = "response closed"; 95 break; 96 default: 97 msg = "response unknown error"; 98 break; 99 } 100 } else { 101 fh = fc_frame_header_get(fp); 102 switch (fh->fh_type) { 103 case FC_TYPE_ELS: 104 switch (fc_frame_payload_op(fp)) { 105 case ELS_LS_ACC: 106 msg = "accept"; 107 break; 108 case ELS_LS_RJT: 109 msg = "reject"; 110 break; 111 default: 112 msg = "response unknown ELS"; 113 break; 114 } 115 break; 116 case FC_TYPE_CT: 117 ct = fc_frame_payload_get(fp, sizeof(*ct)); 118 if (ct) { 119 switch (ntohs(ct->ct_cmd)) { 120 case FC_FS_ACC: 121 msg = "CT accept"; 122 break; 123 case FC_FS_RJT: 124 msg = "CT reject"; 125 break; 126 default: 127 msg = "response unknown CT"; 128 break; 129 } 130 } else { 131 msg = "short CT response"; 132 } 133 break; 134 default: 135 msg = "response not ELS or CT"; 136 break; 137 } 138 } 139 return msg; 140 } 141