linux/drivers/scsi/libfc/fc_elsct.c
<<
>>
Prefs
   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 <asm/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 */
  31struct 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}
  60EXPORT_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 */
  66int 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}
  73EXPORT_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 */
  79const 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