mirror of https://github.com/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.
140 lines
3.0 KiB
140 lines
3.0 KiB
// SPDX-License-Identifier: GPL-2.0-only |
|
/* |
|
* Copyright(c) 2008 Intel Corporation. All rights reserved. |
|
* |
|
* Maintained at www.Open-FCoE.org |
|
*/ |
|
|
|
/* |
|
* Provide interface to send ELS/CT FC frames |
|
*/ |
|
|
|
#include <linux/export.h> |
|
#include <asm/unaligned.h> |
|
#include <scsi/fc/fc_gs.h> |
|
#include <scsi/fc/fc_ns.h> |
|
#include <scsi/fc/fc_els.h> |
|
#include <scsi/libfc.h> |
|
#include "fc_encode.h" |
|
#include "fc_libfc.h" |
|
|
|
/** |
|
* fc_elsct_send() - Send an ELS or CT frame |
|
* @lport: The local port to send the frame on |
|
* @did: The destination ID for the frame |
|
* @fp: The frame to be sent |
|
* @op: The operational code |
|
* @resp: The callback routine when the response is received |
|
* @arg: The argument to pass to the response callback routine |
|
* @timer_msec: The timeout period for the frame (in msecs) |
|
*/ |
|
struct fc_seq *fc_elsct_send(struct fc_lport *lport, u32 did, |
|
struct fc_frame *fp, unsigned int op, |
|
void (*resp)(struct fc_seq *, |
|
struct fc_frame *, |
|
void *), |
|
void *arg, u32 timer_msec) |
|
{ |
|
enum fc_rctl r_ctl; |
|
enum fc_fh_type fh_type; |
|
int rc; |
|
|
|
/* ELS requests */ |
|
if ((op >= ELS_LS_RJT) && (op <= ELS_AUTH_ELS)) |
|
rc = fc_els_fill(lport, did, fp, op, &r_ctl, &fh_type); |
|
else { |
|
/* CT requests */ |
|
rc = fc_ct_fill(lport, did, fp, op, &r_ctl, &fh_type, &did); |
|
} |
|
|
|
if (rc) { |
|
fc_frame_free(fp); |
|
return NULL; |
|
} |
|
|
|
fc_fill_fc_hdr(fp, r_ctl, did, lport->port_id, fh_type, |
|
FC_FCTL_REQ, 0); |
|
|
|
return fc_exch_seq_send(lport, fp, resp, NULL, arg, timer_msec); |
|
} |
|
EXPORT_SYMBOL(fc_elsct_send); |
|
|
|
/** |
|
* fc_elsct_init() - Initialize the ELS/CT layer |
|
* @lport: The local port to initialize the ELS/CT layer for |
|
*/ |
|
int fc_elsct_init(struct fc_lport *lport) |
|
{ |
|
if (!lport->tt.elsct_send) |
|
lport->tt.elsct_send = fc_elsct_send; |
|
|
|
return 0; |
|
} |
|
EXPORT_SYMBOL(fc_elsct_init); |
|
|
|
/** |
|
* fc_els_resp_type() - Return a string describing the ELS response |
|
* @fp: The frame pointer or possible error code |
|
*/ |
|
const char *fc_els_resp_type(struct fc_frame *fp) |
|
{ |
|
const char *msg; |
|
struct fc_frame_header *fh; |
|
struct fc_ct_hdr *ct; |
|
|
|
if (IS_ERR(fp)) { |
|
switch (-PTR_ERR(fp)) { |
|
case FC_NO_ERR: |
|
msg = "response no error"; |
|
break; |
|
case FC_EX_TIMEOUT: |
|
msg = "response timeout"; |
|
break; |
|
case FC_EX_CLOSED: |
|
msg = "response closed"; |
|
break; |
|
default: |
|
msg = "response unknown error"; |
|
break; |
|
} |
|
} else { |
|
fh = fc_frame_header_get(fp); |
|
switch (fh->fh_type) { |
|
case FC_TYPE_ELS: |
|
switch (fc_frame_payload_op(fp)) { |
|
case ELS_LS_ACC: |
|
msg = "accept"; |
|
break; |
|
case ELS_LS_RJT: |
|
msg = "reject"; |
|
break; |
|
default: |
|
msg = "response unknown ELS"; |
|
break; |
|
} |
|
break; |
|
case FC_TYPE_CT: |
|
ct = fc_frame_payload_get(fp, sizeof(*ct)); |
|
if (ct) { |
|
switch (ntohs(ct->ct_cmd)) { |
|
case FC_FS_ACC: |
|
msg = "CT accept"; |
|
break; |
|
case FC_FS_RJT: |
|
msg = "CT reject"; |
|
break; |
|
default: |
|
msg = "response unknown CT"; |
|
break; |
|
} |
|
} else { |
|
msg = "short CT response"; |
|
} |
|
break; |
|
default: |
|
msg = "response not ELS or CT"; |
|
break; |
|
} |
|
} |
|
return msg; |
|
}
|
|
|