18f406ef7SJames Smart // SPDX-License-Identifier: GPL-2.0
28f406ef7SJames Smart /*
38f406ef7SJames Smart * Copyright (C) 2021 Broadcom. All Rights Reserved. The term
48f406ef7SJames Smart * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
58f406ef7SJames Smart */
68f406ef7SJames Smart
78f406ef7SJames Smart /*
88f406ef7SJames Smart * Functions to build and send ELS/CT/BLS commands and responses.
98f406ef7SJames Smart */
108f406ef7SJames Smart
118f406ef7SJames Smart #include "efc.h"
128f406ef7SJames Smart #include "efc_els.h"
138f406ef7SJames Smart #include "../libefc_sli/sli4.h"
148f406ef7SJames Smart
158f406ef7SJames Smart #define EFC_LOG_ENABLE_ELS_TRACE(efc) \
168f406ef7SJames Smart (((efc) != NULL) ? (((efc)->logmask & (1U << 1)) != 0) : 0)
178f406ef7SJames Smart
188f406ef7SJames Smart #define node_els_trace() \
198f406ef7SJames Smart do { \
208f406ef7SJames Smart if (EFC_LOG_ENABLE_ELS_TRACE(efc)) \
218f406ef7SJames Smart efc_log_info(efc, "[%s] %-20s\n", \
228f406ef7SJames Smart node->display_name, __func__); \
238f406ef7SJames Smart } while (0)
248f406ef7SJames Smart
258f406ef7SJames Smart #define els_io_printf(els, fmt, ...) \
268f406ef7SJames Smart efc_log_err((struct efc *)els->node->efc,\
278f406ef7SJames Smart "[%s] %-8s " fmt, \
288f406ef7SJames Smart els->node->display_name,\
298f406ef7SJames Smart els->display_name, ##__VA_ARGS__)
308f406ef7SJames Smart
318f406ef7SJames Smart #define EFC_ELS_RSP_LEN 1024
328f406ef7SJames Smart #define EFC_ELS_GID_PT_RSP_LEN 8096
338f406ef7SJames Smart
348f406ef7SJames Smart struct efc_els_io_req *
efc_els_io_alloc(struct efc_node * node,u32 reqlen)358f406ef7SJames Smart efc_els_io_alloc(struct efc_node *node, u32 reqlen)
368f406ef7SJames Smart {
378f406ef7SJames Smart return efc_els_io_alloc_size(node, reqlen, EFC_ELS_RSP_LEN);
388f406ef7SJames Smart }
398f406ef7SJames Smart
408f406ef7SJames Smart struct efc_els_io_req *
efc_els_io_alloc_size(struct efc_node * node,u32 reqlen,u32 rsplen)418f406ef7SJames Smart efc_els_io_alloc_size(struct efc_node *node, u32 reqlen, u32 rsplen)
428f406ef7SJames Smart {
438f406ef7SJames Smart struct efc *efc;
448f406ef7SJames Smart struct efc_els_io_req *els;
458f406ef7SJames Smart unsigned long flags = 0;
468f406ef7SJames Smart
478f406ef7SJames Smart efc = node->efc;
488f406ef7SJames Smart
498f406ef7SJames Smart if (!node->els_io_enabled) {
508f406ef7SJames Smart efc_log_err(efc, "els io alloc disabled\n");
518f406ef7SJames Smart return NULL;
528f406ef7SJames Smart }
538f406ef7SJames Smart
548f406ef7SJames Smart els = mempool_alloc(efc->els_io_pool, GFP_ATOMIC);
558f406ef7SJames Smart if (!els) {
568f406ef7SJames Smart atomic_add_return(1, &efc->els_io_alloc_failed_count);
578f406ef7SJames Smart return NULL;
588f406ef7SJames Smart }
598f406ef7SJames Smart
608f406ef7SJames Smart /* initialize refcount */
618f406ef7SJames Smart kref_init(&els->ref);
628f406ef7SJames Smart els->release = _efc_els_io_free;
638f406ef7SJames Smart
648f406ef7SJames Smart /* populate generic io fields */
658f406ef7SJames Smart els->node = node;
668f406ef7SJames Smart
678f406ef7SJames Smart /* now allocate DMA for request and response */
688f406ef7SJames Smart els->io.req.size = reqlen;
698f406ef7SJames Smart els->io.req.virt = dma_alloc_coherent(&efc->pci->dev, els->io.req.size,
70efac162aSChristoph Hellwig &els->io.req.phys, GFP_KERNEL);
718f406ef7SJames Smart if (!els->io.req.virt) {
728f406ef7SJames Smart mempool_free(els, efc->els_io_pool);
738f406ef7SJames Smart return NULL;
748f406ef7SJames Smart }
758f406ef7SJames Smart
768f406ef7SJames Smart els->io.rsp.size = rsplen;
778f406ef7SJames Smart els->io.rsp.virt = dma_alloc_coherent(&efc->pci->dev, els->io.rsp.size,
78efac162aSChristoph Hellwig &els->io.rsp.phys, GFP_KERNEL);
798f406ef7SJames Smart if (!els->io.rsp.virt) {
808f406ef7SJames Smart dma_free_coherent(&efc->pci->dev, els->io.req.size,
818f406ef7SJames Smart els->io.req.virt, els->io.req.phys);
828f406ef7SJames Smart mempool_free(els, efc->els_io_pool);
838f406ef7SJames Smart els = NULL;
848f406ef7SJames Smart }
858f406ef7SJames Smart
868f406ef7SJames Smart if (els) {
878f406ef7SJames Smart /* initialize fields */
888f406ef7SJames Smart els->els_retries_remaining = EFC_FC_ELS_DEFAULT_RETRIES;
898f406ef7SJames Smart
908f406ef7SJames Smart /* add els structure to ELS IO list */
918f406ef7SJames Smart INIT_LIST_HEAD(&els->list_entry);
92*61263b3aSYang Yingliang spin_lock_irqsave(&node->els_ios_lock, flags);
938f406ef7SJames Smart list_add_tail(&els->list_entry, &node->els_ios_list);
94*61263b3aSYang Yingliang spin_unlock_irqrestore(&node->els_ios_lock, flags);
958f406ef7SJames Smart }
968f406ef7SJames Smart
978f406ef7SJames Smart return els;
988f406ef7SJames Smart }
998f406ef7SJames Smart
1008f406ef7SJames Smart void
efc_els_io_free(struct efc_els_io_req * els)1018f406ef7SJames Smart efc_els_io_free(struct efc_els_io_req *els)
1028f406ef7SJames Smart {
1038f406ef7SJames Smart kref_put(&els->ref, els->release);
1048f406ef7SJames Smart }
1058f406ef7SJames Smart
1068f406ef7SJames Smart void
_efc_els_io_free(struct kref * arg)1078f406ef7SJames Smart _efc_els_io_free(struct kref *arg)
1088f406ef7SJames Smart {
1098f406ef7SJames Smart struct efc_els_io_req *els =
1108f406ef7SJames Smart container_of(arg, struct efc_els_io_req, ref);
1118f406ef7SJames Smart struct efc *efc;
1128f406ef7SJames Smart struct efc_node *node;
1138f406ef7SJames Smart int send_empty_event = false;
1148f406ef7SJames Smart unsigned long flags = 0;
1158f406ef7SJames Smart
1168f406ef7SJames Smart node = els->node;
1178f406ef7SJames Smart efc = node->efc;
1188f406ef7SJames Smart
1198f406ef7SJames Smart spin_lock_irqsave(&node->els_ios_lock, flags);
1208f406ef7SJames Smart
1218f406ef7SJames Smart list_del(&els->list_entry);
1228f406ef7SJames Smart /* Send list empty event if the IO allocator
1238f406ef7SJames Smart * is disabled, and the list is empty
1248f406ef7SJames Smart * If node->els_io_enabled was not checked,
1258f406ef7SJames Smart * the event would be posted continually
1268f406ef7SJames Smart */
1278f406ef7SJames Smart send_empty_event = (!node->els_io_enabled &&
1288f406ef7SJames Smart list_empty(&node->els_ios_list));
1298f406ef7SJames Smart
1308f406ef7SJames Smart spin_unlock_irqrestore(&node->els_ios_lock, flags);
1318f406ef7SJames Smart
1328f406ef7SJames Smart /* free ELS request and response buffers */
1338f406ef7SJames Smart dma_free_coherent(&efc->pci->dev, els->io.rsp.size,
1348f406ef7SJames Smart els->io.rsp.virt, els->io.rsp.phys);
1358f406ef7SJames Smart dma_free_coherent(&efc->pci->dev, els->io.req.size,
1368f406ef7SJames Smart els->io.req.virt, els->io.req.phys);
1378f406ef7SJames Smart
1388f406ef7SJames Smart mempool_free(els, efc->els_io_pool);
1398f406ef7SJames Smart
1408f406ef7SJames Smart if (send_empty_event)
1418f406ef7SJames Smart efc_scsi_io_list_empty(node->efc, node);
1428f406ef7SJames Smart }
1438f406ef7SJames Smart
1448f406ef7SJames Smart static void
1458f406ef7SJames Smart efc_els_retry(struct efc_els_io_req *els);
1468f406ef7SJames Smart
1478f406ef7SJames Smart static void
efc_els_delay_timer_cb(struct timer_list * t)1488f406ef7SJames Smart efc_els_delay_timer_cb(struct timer_list *t)
1498f406ef7SJames Smart {
1508f406ef7SJames Smart struct efc_els_io_req *els = from_timer(els, t, delay_timer);
1518f406ef7SJames Smart
1528f406ef7SJames Smart /* Retry delay timer expired, retry the ELS request */
1538f406ef7SJames Smart efc_els_retry(els);
1548f406ef7SJames Smart }
1558f406ef7SJames Smart
1568f406ef7SJames Smart static int
efc_els_req_cb(void * arg,u32 length,int status,u32 ext_status)1578f406ef7SJames Smart efc_els_req_cb(void *arg, u32 length, int status, u32 ext_status)
1588f406ef7SJames Smart {
1598f406ef7SJames Smart struct efc_els_io_req *els;
1608f406ef7SJames Smart struct efc_node *node;
1618f406ef7SJames Smart struct efc *efc;
1628f406ef7SJames Smart struct efc_node_cb cbdata;
1638f406ef7SJames Smart u32 reason_code;
1648f406ef7SJames Smart
1658f406ef7SJames Smart els = arg;
1668f406ef7SJames Smart node = els->node;
1678f406ef7SJames Smart efc = node->efc;
1688f406ef7SJames Smart
1698f406ef7SJames Smart if (status)
1708f406ef7SJames Smart els_io_printf(els, "status x%x ext x%x\n", status, ext_status);
1718f406ef7SJames Smart
1728f406ef7SJames Smart /* set the response len element of els->rsp */
1738f406ef7SJames Smart els->io.rsp.len = length;
1748f406ef7SJames Smart
1758f406ef7SJames Smart cbdata.status = status;
1768f406ef7SJames Smart cbdata.ext_status = ext_status;
1778f406ef7SJames Smart cbdata.header = NULL;
1788f406ef7SJames Smart cbdata.els_rsp = els->io.rsp;
1798f406ef7SJames Smart
1808f406ef7SJames Smart /* set the response len element of els->rsp */
1818f406ef7SJames Smart cbdata.rsp_len = length;
1828f406ef7SJames Smart
1838f406ef7SJames Smart /* FW returns the number of bytes received on the link in
1848f406ef7SJames Smart * the WCQE, not the amount placed in the buffer; use this info to
1858f406ef7SJames Smart * check if there was an overrun.
1868f406ef7SJames Smart */
1878f406ef7SJames Smart if (length > els->io.rsp.size) {
1888f406ef7SJames Smart efc_log_warn(efc,
1898f406ef7SJames Smart "ELS response returned len=%d > buflen=%zu\n",
1908f406ef7SJames Smart length, els->io.rsp.size);
1918f406ef7SJames Smart efc_els_io_cleanup(els, EFC_EVT_SRRS_ELS_REQ_FAIL, &cbdata);
1928f406ef7SJames Smart return 0;
1938f406ef7SJames Smart }
1948f406ef7SJames Smart
1958f406ef7SJames Smart /* Post event to ELS IO object */
1968f406ef7SJames Smart switch (status) {
1978f406ef7SJames Smart case SLI4_FC_WCQE_STATUS_SUCCESS:
1988f406ef7SJames Smart efc_els_io_cleanup(els, EFC_EVT_SRRS_ELS_REQ_OK, &cbdata);
1998f406ef7SJames Smart break;
2008f406ef7SJames Smart
2018f406ef7SJames Smart case SLI4_FC_WCQE_STATUS_LS_RJT:
2028f406ef7SJames Smart reason_code = (ext_status >> 16) & 0xff;
2038f406ef7SJames Smart
2048f406ef7SJames Smart /* delay and retry if reason code is Logical Busy */
2058f406ef7SJames Smart switch (reason_code) {
2068f406ef7SJames Smart case ELS_RJT_BUSY:
2078f406ef7SJames Smart els->node->els_req_cnt--;
2088f406ef7SJames Smart els_io_printf(els,
2098f406ef7SJames Smart "LS_RJT Logical Busy, delay and retry\n");
2108f406ef7SJames Smart timer_setup(&els->delay_timer,
2118f406ef7SJames Smart efc_els_delay_timer_cb, 0);
2128f406ef7SJames Smart mod_timer(&els->delay_timer,
2138f406ef7SJames Smart jiffies + msecs_to_jiffies(5000));
2148f406ef7SJames Smart break;
2158f406ef7SJames Smart default:
2168f406ef7SJames Smart efc_els_io_cleanup(els, EFC_EVT_SRRS_ELS_REQ_RJT,
2178f406ef7SJames Smart &cbdata);
2188f406ef7SJames Smart break;
2198f406ef7SJames Smart }
2208f406ef7SJames Smart break;
2218f406ef7SJames Smart
2228f406ef7SJames Smart case SLI4_FC_WCQE_STATUS_LOCAL_REJECT:
2238f406ef7SJames Smart switch (ext_status) {
2248f406ef7SJames Smart case SLI4_FC_LOCAL_REJECT_SEQUENCE_TIMEOUT:
2258f406ef7SJames Smart efc_els_retry(els);
2268f406ef7SJames Smart break;
2278f406ef7SJames Smart default:
2288f406ef7SJames Smart efc_log_err(efc, "LOCAL_REJECT with ext status:%x\n",
2298f406ef7SJames Smart ext_status);
2308f406ef7SJames Smart efc_els_io_cleanup(els, EFC_EVT_SRRS_ELS_REQ_FAIL,
2318f406ef7SJames Smart &cbdata);
2328f406ef7SJames Smart break;
2338f406ef7SJames Smart }
2348f406ef7SJames Smart break;
2358f406ef7SJames Smart default: /* Other error */
2368f406ef7SJames Smart efc_log_warn(efc, "els req failed status x%x, ext_status x%x\n",
2378f406ef7SJames Smart status, ext_status);
2388f406ef7SJames Smart efc_els_io_cleanup(els, EFC_EVT_SRRS_ELS_REQ_FAIL, &cbdata);
2398f406ef7SJames Smart break;
2408f406ef7SJames Smart }
2418f406ef7SJames Smart
2428f406ef7SJames Smart return 0;
2438f406ef7SJames Smart }
2448f406ef7SJames Smart
efc_disc_io_complete(struct efc_disc_io * io,u32 len,u32 status,u32 ext_status)2458f406ef7SJames Smart void efc_disc_io_complete(struct efc_disc_io *io, u32 len, u32 status,
2468f406ef7SJames Smart u32 ext_status)
2478f406ef7SJames Smart {
2488f406ef7SJames Smart struct efc_els_io_req *els =
2498f406ef7SJames Smart container_of(io, struct efc_els_io_req, io);
2508f406ef7SJames Smart
2518f406ef7SJames Smart WARN_ON_ONCE(!els->cb);
2528f406ef7SJames Smart
2538f406ef7SJames Smart ((efc_hw_srrs_cb_t)els->cb) (els, len, status, ext_status);
2548f406ef7SJames Smart }
2558f406ef7SJames Smart
efc_els_send_req(struct efc_node * node,struct efc_els_io_req * els,enum efc_disc_io_type io_type)2568f406ef7SJames Smart static int efc_els_send_req(struct efc_node *node, struct efc_els_io_req *els,
2578f406ef7SJames Smart enum efc_disc_io_type io_type)
2588f406ef7SJames Smart {
2598f406ef7SJames Smart int rc = 0;
2608f406ef7SJames Smart struct efc *efc = node->efc;
2618f406ef7SJames Smart struct efc_node_cb cbdata;
2628f406ef7SJames Smart
2638f406ef7SJames Smart /* update ELS request counter */
2648f406ef7SJames Smart els->node->els_req_cnt++;
2658f406ef7SJames Smart
2668f406ef7SJames Smart /* Prepare the IO request details */
2678f406ef7SJames Smart els->io.io_type = io_type;
2688f406ef7SJames Smart els->io.xmit_len = els->io.req.size;
2698f406ef7SJames Smart els->io.rsp_len = els->io.rsp.size;
2708f406ef7SJames Smart els->io.rpi = node->rnode.indicator;
2718f406ef7SJames Smart els->io.vpi = node->nport->indicator;
2728f406ef7SJames Smart els->io.s_id = node->nport->fc_id;
2738f406ef7SJames Smart els->io.d_id = node->rnode.fc_id;
2748f406ef7SJames Smart
2758f406ef7SJames Smart if (node->rnode.attached)
2768f406ef7SJames Smart els->io.rpi_registered = true;
2778f406ef7SJames Smart
2788f406ef7SJames Smart els->cb = efc_els_req_cb;
2798f406ef7SJames Smart
2808f406ef7SJames Smart rc = efc->tt.send_els(efc, &els->io);
2818f406ef7SJames Smart if (!rc)
2828f406ef7SJames Smart return rc;
2838f406ef7SJames Smart
2848f406ef7SJames Smart cbdata.status = EFC_STATUS_INVALID;
2858f406ef7SJames Smart cbdata.ext_status = EFC_STATUS_INVALID;
2868f406ef7SJames Smart cbdata.els_rsp = els->io.rsp;
2878f406ef7SJames Smart efc_log_err(efc, "efc_els_send failed: %d\n", rc);
2888f406ef7SJames Smart efc_els_io_cleanup(els, EFC_EVT_SRRS_ELS_REQ_FAIL, &cbdata);
2898f406ef7SJames Smart
2908f406ef7SJames Smart return rc;
2918f406ef7SJames Smart }
2928f406ef7SJames Smart
2938f406ef7SJames Smart static void
efc_els_retry(struct efc_els_io_req * els)2948f406ef7SJames Smart efc_els_retry(struct efc_els_io_req *els)
2958f406ef7SJames Smart {
2968f406ef7SJames Smart struct efc *efc;
2978f406ef7SJames Smart struct efc_node_cb cbdata;
2988f406ef7SJames Smart u32 rc;
2998f406ef7SJames Smart
3008f406ef7SJames Smart efc = els->node->efc;
3018f406ef7SJames Smart cbdata.status = EFC_STATUS_INVALID;
3028f406ef7SJames Smart cbdata.ext_status = EFC_STATUS_INVALID;
3038f406ef7SJames Smart cbdata.els_rsp = els->io.rsp;
3048f406ef7SJames Smart
3058f406ef7SJames Smart if (els->els_retries_remaining) {
3068f406ef7SJames Smart els->els_retries_remaining--;
3078f406ef7SJames Smart rc = efc->tt.send_els(efc, &els->io);
3088f406ef7SJames Smart } else {
3098f406ef7SJames Smart rc = -EIO;
3108f406ef7SJames Smart }
3118f406ef7SJames Smart
3128f406ef7SJames Smart if (rc) {
3138f406ef7SJames Smart efc_log_err(efc, "ELS retries exhausted\n");
3148f406ef7SJames Smart efc_els_io_cleanup(els, EFC_EVT_SRRS_ELS_REQ_FAIL, &cbdata);
3158f406ef7SJames Smart }
3168f406ef7SJames Smart }
3178f406ef7SJames Smart
3188f406ef7SJames Smart static int
efc_els_acc_cb(void * arg,u32 length,int status,u32 ext_status)3198f406ef7SJames Smart efc_els_acc_cb(void *arg, u32 length, int status, u32 ext_status)
3208f406ef7SJames Smart {
3218f406ef7SJames Smart struct efc_els_io_req *els;
3228f406ef7SJames Smart struct efc_node *node;
3238f406ef7SJames Smart struct efc *efc;
3248f406ef7SJames Smart struct efc_node_cb cbdata;
3258f406ef7SJames Smart
3268f406ef7SJames Smart els = arg;
3278f406ef7SJames Smart node = els->node;
3288f406ef7SJames Smart efc = node->efc;
3298f406ef7SJames Smart
3308f406ef7SJames Smart cbdata.status = status;
3318f406ef7SJames Smart cbdata.ext_status = ext_status;
3328f406ef7SJames Smart cbdata.header = NULL;
3338f406ef7SJames Smart cbdata.els_rsp = els->io.rsp;
3348f406ef7SJames Smart
3358f406ef7SJames Smart /* Post node event */
3368f406ef7SJames Smart switch (status) {
3378f406ef7SJames Smart case SLI4_FC_WCQE_STATUS_SUCCESS:
3388f406ef7SJames Smart efc_els_io_cleanup(els, EFC_EVT_SRRS_ELS_CMPL_OK, &cbdata);
3398f406ef7SJames Smart break;
3408f406ef7SJames Smart
3418f406ef7SJames Smart default: /* Other error */
3428f406ef7SJames Smart efc_log_warn(efc, "[%s] %-8s failed status x%x, ext x%x\n",
3438f406ef7SJames Smart node->display_name, els->display_name,
3448f406ef7SJames Smart status, ext_status);
3458f406ef7SJames Smart efc_els_io_cleanup(els, EFC_EVT_SRRS_ELS_CMPL_FAIL, &cbdata);
3468f406ef7SJames Smart break;
3478f406ef7SJames Smart }
3488f406ef7SJames Smart
3498f406ef7SJames Smart return 0;
3508f406ef7SJames Smart }
3518f406ef7SJames Smart
3528f406ef7SJames Smart static int
efc_els_send_rsp(struct efc_els_io_req * els,u32 rsplen)3538f406ef7SJames Smart efc_els_send_rsp(struct efc_els_io_req *els, u32 rsplen)
3548f406ef7SJames Smart {
3558f406ef7SJames Smart int rc = 0;
3568f406ef7SJames Smart struct efc_node_cb cbdata;
3578f406ef7SJames Smart struct efc_node *node = els->node;
3588f406ef7SJames Smart struct efc *efc = node->efc;
3598f406ef7SJames Smart
3608f406ef7SJames Smart /* increment ELS completion counter */
3618f406ef7SJames Smart node->els_cmpl_cnt++;
3628f406ef7SJames Smart
3638f406ef7SJames Smart els->io.io_type = EFC_DISC_IO_ELS_RESP;
3648f406ef7SJames Smart els->cb = efc_els_acc_cb;
3658f406ef7SJames Smart
3668f406ef7SJames Smart /* Prepare the IO request details */
3678f406ef7SJames Smart els->io.xmit_len = rsplen;
3688f406ef7SJames Smart els->io.rsp_len = els->io.rsp.size;
3698f406ef7SJames Smart els->io.rpi = node->rnode.indicator;
3708f406ef7SJames Smart els->io.vpi = node->nport->indicator;
3718f406ef7SJames Smart if (node->nport->fc_id != U32_MAX)
3728f406ef7SJames Smart els->io.s_id = node->nport->fc_id;
3738f406ef7SJames Smart else
3748f406ef7SJames Smart els->io.s_id = els->io.iparam.els.s_id;
3758f406ef7SJames Smart els->io.d_id = node->rnode.fc_id;
3768f406ef7SJames Smart
3778f406ef7SJames Smart if (node->attached)
3788f406ef7SJames Smart els->io.rpi_registered = true;
3798f406ef7SJames Smart
3808f406ef7SJames Smart rc = efc->tt.send_els(efc, &els->io);
3818f406ef7SJames Smart if (!rc)
3828f406ef7SJames Smart return rc;
3838f406ef7SJames Smart
3848f406ef7SJames Smart cbdata.status = EFC_STATUS_INVALID;
3858f406ef7SJames Smart cbdata.ext_status = EFC_STATUS_INVALID;
3868f406ef7SJames Smart cbdata.els_rsp = els->io.rsp;
3878f406ef7SJames Smart efc_els_io_cleanup(els, EFC_EVT_SRRS_ELS_CMPL_FAIL, &cbdata);
3888f406ef7SJames Smart
3898f406ef7SJames Smart return rc;
3908f406ef7SJames Smart }
3918f406ef7SJames Smart
3928f406ef7SJames Smart int
efc_send_plogi(struct efc_node * node)3938f406ef7SJames Smart efc_send_plogi(struct efc_node *node)
3948f406ef7SJames Smart {
3958f406ef7SJames Smart struct efc_els_io_req *els;
3968f406ef7SJames Smart struct efc *efc = node->efc;
3978f406ef7SJames Smart struct fc_els_flogi *plogi;
3988f406ef7SJames Smart
3998f406ef7SJames Smart node_els_trace();
4008f406ef7SJames Smart
4018f406ef7SJames Smart els = efc_els_io_alloc(node, sizeof(*plogi));
4028f406ef7SJames Smart if (!els) {
4038f406ef7SJames Smart efc_log_err(efc, "IO alloc failed\n");
4048f406ef7SJames Smart return -EIO;
4058f406ef7SJames Smart }
4068f406ef7SJames Smart els->display_name = "plogi";
4078f406ef7SJames Smart
4088f406ef7SJames Smart /* Build PLOGI request */
4098f406ef7SJames Smart plogi = els->io.req.virt;
4108f406ef7SJames Smart
4118f406ef7SJames Smart memcpy(plogi, node->nport->service_params, sizeof(*plogi));
4128f406ef7SJames Smart
4138f406ef7SJames Smart plogi->fl_cmd = ELS_PLOGI;
4148f406ef7SJames Smart memset(plogi->_fl_resvd, 0, sizeof(plogi->_fl_resvd));
4158f406ef7SJames Smart
4168f406ef7SJames Smart return efc_els_send_req(node, els, EFC_DISC_IO_ELS_REQ);
4178f406ef7SJames Smart }
4188f406ef7SJames Smart
4198f406ef7SJames Smart int
efc_send_flogi(struct efc_node * node)4208f406ef7SJames Smart efc_send_flogi(struct efc_node *node)
4218f406ef7SJames Smart {
4228f406ef7SJames Smart struct efc_els_io_req *els;
4238f406ef7SJames Smart struct efc *efc;
4248f406ef7SJames Smart struct fc_els_flogi *flogi;
4258f406ef7SJames Smart
4268f406ef7SJames Smart efc = node->efc;
4278f406ef7SJames Smart
4288f406ef7SJames Smart node_els_trace();
4298f406ef7SJames Smart
4308f406ef7SJames Smart els = efc_els_io_alloc(node, sizeof(*flogi));
4318f406ef7SJames Smart if (!els) {
4328f406ef7SJames Smart efc_log_err(efc, "IO alloc failed\n");
4338f406ef7SJames Smart return -EIO;
4348f406ef7SJames Smart }
4358f406ef7SJames Smart
4368f406ef7SJames Smart els->display_name = "flogi";
4378f406ef7SJames Smart
4388f406ef7SJames Smart /* Build FLOGI request */
4398f406ef7SJames Smart flogi = els->io.req.virt;
4408f406ef7SJames Smart
4418f406ef7SJames Smart memcpy(flogi, node->nport->service_params, sizeof(*flogi));
4428f406ef7SJames Smart flogi->fl_cmd = ELS_FLOGI;
4438f406ef7SJames Smart memset(flogi->_fl_resvd, 0, sizeof(flogi->_fl_resvd));
4448f406ef7SJames Smart
4458f406ef7SJames Smart return efc_els_send_req(node, els, EFC_DISC_IO_ELS_REQ);
4468f406ef7SJames Smart }
4478f406ef7SJames Smart
4488f406ef7SJames Smart int
efc_send_fdisc(struct efc_node * node)4498f406ef7SJames Smart efc_send_fdisc(struct efc_node *node)
4508f406ef7SJames Smart {
4518f406ef7SJames Smart struct efc_els_io_req *els;
4528f406ef7SJames Smart struct efc *efc;
4538f406ef7SJames Smart struct fc_els_flogi *fdisc;
4548f406ef7SJames Smart
4558f406ef7SJames Smart efc = node->efc;
4568f406ef7SJames Smart
4578f406ef7SJames Smart node_els_trace();
4588f406ef7SJames Smart
4598f406ef7SJames Smart els = efc_els_io_alloc(node, sizeof(*fdisc));
4608f406ef7SJames Smart if (!els) {
4618f406ef7SJames Smart efc_log_err(efc, "IO alloc failed\n");
4628f406ef7SJames Smart return -EIO;
4638f406ef7SJames Smart }
4648f406ef7SJames Smart
4658f406ef7SJames Smart els->display_name = "fdisc";
4668f406ef7SJames Smart
4678f406ef7SJames Smart /* Build FDISC request */
4688f406ef7SJames Smart fdisc = els->io.req.virt;
4698f406ef7SJames Smart
4708f406ef7SJames Smart memcpy(fdisc, node->nport->service_params, sizeof(*fdisc));
4718f406ef7SJames Smart fdisc->fl_cmd = ELS_FDISC;
4728f406ef7SJames Smart memset(fdisc->_fl_resvd, 0, sizeof(fdisc->_fl_resvd));
4738f406ef7SJames Smart
4748f406ef7SJames Smart return efc_els_send_req(node, els, EFC_DISC_IO_ELS_REQ);
4758f406ef7SJames Smart }
4768f406ef7SJames Smart
4778f406ef7SJames Smart int
efc_send_prli(struct efc_node * node)4788f406ef7SJames Smart efc_send_prli(struct efc_node *node)
4798f406ef7SJames Smart {
4808f406ef7SJames Smart struct efc *efc = node->efc;
4818f406ef7SJames Smart struct efc_els_io_req *els;
4828f406ef7SJames Smart struct {
4838f406ef7SJames Smart struct fc_els_prli prli;
4848f406ef7SJames Smart struct fc_els_spp spp;
4858f406ef7SJames Smart } *pp;
4868f406ef7SJames Smart
4878f406ef7SJames Smart node_els_trace();
4888f406ef7SJames Smart
4898f406ef7SJames Smart els = efc_els_io_alloc(node, sizeof(*pp));
4908f406ef7SJames Smart if (!els) {
4918f406ef7SJames Smart efc_log_err(efc, "IO alloc failed\n");
4928f406ef7SJames Smart return -EIO;
4938f406ef7SJames Smart }
4948f406ef7SJames Smart
4958f406ef7SJames Smart els->display_name = "prli";
4968f406ef7SJames Smart
4978f406ef7SJames Smart /* Build PRLI request */
4988f406ef7SJames Smart pp = els->io.req.virt;
4998f406ef7SJames Smart
5008f406ef7SJames Smart memset(pp, 0, sizeof(*pp));
5018f406ef7SJames Smart
5028f406ef7SJames Smart pp->prli.prli_cmd = ELS_PRLI;
5038f406ef7SJames Smart pp->prli.prli_spp_len = 16;
5048f406ef7SJames Smart pp->prli.prli_len = cpu_to_be16(sizeof(*pp));
5058f406ef7SJames Smart pp->spp.spp_type = FC_TYPE_FCP;
5068f406ef7SJames Smart pp->spp.spp_type_ext = 0;
5078f406ef7SJames Smart pp->spp.spp_flags = FC_SPP_EST_IMG_PAIR;
5088f406ef7SJames Smart pp->spp.spp_params = cpu_to_be32(FCP_SPPF_RD_XRDY_DIS |
5098f406ef7SJames Smart (node->nport->enable_ini ?
5108f406ef7SJames Smart FCP_SPPF_INIT_FCN : 0) |
5118f406ef7SJames Smart (node->nport->enable_tgt ?
5128f406ef7SJames Smart FCP_SPPF_TARG_FCN : 0));
5138f406ef7SJames Smart
5148f406ef7SJames Smart return efc_els_send_req(node, els, EFC_DISC_IO_ELS_REQ);
5158f406ef7SJames Smart }
5168f406ef7SJames Smart
5178f406ef7SJames Smart int
efc_send_logo(struct efc_node * node)5188f406ef7SJames Smart efc_send_logo(struct efc_node *node)
5198f406ef7SJames Smart {
5208f406ef7SJames Smart struct efc *efc = node->efc;
5218f406ef7SJames Smart struct efc_els_io_req *els;
5228f406ef7SJames Smart struct fc_els_logo *logo;
5238f406ef7SJames Smart struct fc_els_flogi *sparams;
5248f406ef7SJames Smart
5258f406ef7SJames Smart node_els_trace();
5268f406ef7SJames Smart
5278f406ef7SJames Smart sparams = (struct fc_els_flogi *)node->nport->service_params;
5288f406ef7SJames Smart
5298f406ef7SJames Smart els = efc_els_io_alloc(node, sizeof(*logo));
5308f406ef7SJames Smart if (!els) {
5318f406ef7SJames Smart efc_log_err(efc, "IO alloc failed\n");
5328f406ef7SJames Smart return -EIO;
5338f406ef7SJames Smart }
5348f406ef7SJames Smart
5358f406ef7SJames Smart els->display_name = "logo";
5368f406ef7SJames Smart
5378f406ef7SJames Smart /* Build LOGO request */
5388f406ef7SJames Smart
5398f406ef7SJames Smart logo = els->io.req.virt;
5408f406ef7SJames Smart
5418f406ef7SJames Smart memset(logo, 0, sizeof(*logo));
5428f406ef7SJames Smart logo->fl_cmd = ELS_LOGO;
5438f406ef7SJames Smart hton24(logo->fl_n_port_id, node->rnode.nport->fc_id);
5448f406ef7SJames Smart logo->fl_n_port_wwn = sparams->fl_wwpn;
5458f406ef7SJames Smart
5468f406ef7SJames Smart return efc_els_send_req(node, els, EFC_DISC_IO_ELS_REQ);
5478f406ef7SJames Smart }
5488f406ef7SJames Smart
5498f406ef7SJames Smart int
efc_send_adisc(struct efc_node * node)5508f406ef7SJames Smart efc_send_adisc(struct efc_node *node)
5518f406ef7SJames Smart {
5528f406ef7SJames Smart struct efc *efc = node->efc;
5538f406ef7SJames Smart struct efc_els_io_req *els;
5548f406ef7SJames Smart struct fc_els_adisc *adisc;
5558f406ef7SJames Smart struct fc_els_flogi *sparams;
5568f406ef7SJames Smart struct efc_nport *nport = node->nport;
5578f406ef7SJames Smart
5588f406ef7SJames Smart node_els_trace();
5598f406ef7SJames Smart
5608f406ef7SJames Smart sparams = (struct fc_els_flogi *)node->nport->service_params;
5618f406ef7SJames Smart
5628f406ef7SJames Smart els = efc_els_io_alloc(node, sizeof(*adisc));
5638f406ef7SJames Smart if (!els) {
5648f406ef7SJames Smart efc_log_err(efc, "IO alloc failed\n");
5658f406ef7SJames Smart return -EIO;
5668f406ef7SJames Smart }
5678f406ef7SJames Smart
5688f406ef7SJames Smart els->display_name = "adisc";
5698f406ef7SJames Smart
5708f406ef7SJames Smart /* Build ADISC request */
5718f406ef7SJames Smart
5728f406ef7SJames Smart adisc = els->io.req.virt;
5738f406ef7SJames Smart
5748f406ef7SJames Smart memset(adisc, 0, sizeof(*adisc));
5758f406ef7SJames Smart adisc->adisc_cmd = ELS_ADISC;
5768f406ef7SJames Smart hton24(adisc->adisc_hard_addr, nport->fc_id);
5778f406ef7SJames Smart adisc->adisc_wwpn = sparams->fl_wwpn;
5788f406ef7SJames Smart adisc->adisc_wwnn = sparams->fl_wwnn;
5798f406ef7SJames Smart hton24(adisc->adisc_port_id, node->rnode.nport->fc_id);
5808f406ef7SJames Smart
5818f406ef7SJames Smart return efc_els_send_req(node, els, EFC_DISC_IO_ELS_REQ);
5828f406ef7SJames Smart }
5838f406ef7SJames Smart
5848f406ef7SJames Smart int
efc_send_scr(struct efc_node * node)5858f406ef7SJames Smart efc_send_scr(struct efc_node *node)
5868f406ef7SJames Smart {
5878f406ef7SJames Smart struct efc_els_io_req *els;
5888f406ef7SJames Smart struct efc *efc = node->efc;
5898f406ef7SJames Smart struct fc_els_scr *req;
5908f406ef7SJames Smart
5918f406ef7SJames Smart node_els_trace();
5928f406ef7SJames Smart
5938f406ef7SJames Smart els = efc_els_io_alloc(node, sizeof(*req));
5948f406ef7SJames Smart if (!els) {
5958f406ef7SJames Smart efc_log_err(efc, "IO alloc failed\n");
5968f406ef7SJames Smart return -EIO;
5978f406ef7SJames Smart }
5988f406ef7SJames Smart
5998f406ef7SJames Smart els->display_name = "scr";
6008f406ef7SJames Smart
6018f406ef7SJames Smart req = els->io.req.virt;
6028f406ef7SJames Smart
6038f406ef7SJames Smart memset(req, 0, sizeof(*req));
6048f406ef7SJames Smart req->scr_cmd = ELS_SCR;
6058f406ef7SJames Smart req->scr_reg_func = ELS_SCRF_FULL;
6068f406ef7SJames Smart
6078f406ef7SJames Smart return efc_els_send_req(node, els, EFC_DISC_IO_ELS_REQ);
6088f406ef7SJames Smart }
6098f406ef7SJames Smart
6108f406ef7SJames Smart int
efc_send_ls_rjt(struct efc_node * node,u32 ox_id,u32 reason_code,u32 reason_code_expl,u32 vendor_unique)6118f406ef7SJames Smart efc_send_ls_rjt(struct efc_node *node, u32 ox_id, u32 reason_code,
6128f406ef7SJames Smart u32 reason_code_expl, u32 vendor_unique)
6138f406ef7SJames Smart {
6148f406ef7SJames Smart struct efc *efc = node->efc;
6158f406ef7SJames Smart struct efc_els_io_req *els = NULL;
6168f406ef7SJames Smart struct fc_els_ls_rjt *rjt;
6178f406ef7SJames Smart
6188f406ef7SJames Smart els = efc_els_io_alloc(node, sizeof(*rjt));
6198f406ef7SJames Smart if (!els) {
6208f406ef7SJames Smart efc_log_err(efc, "els IO alloc failed\n");
6218f406ef7SJames Smart return -EIO;
6228f406ef7SJames Smart }
6238f406ef7SJames Smart
6248f406ef7SJames Smart node_els_trace();
6258f406ef7SJames Smart
6268f406ef7SJames Smart els->display_name = "ls_rjt";
6278f406ef7SJames Smart
6288f406ef7SJames Smart memset(&els->io.iparam, 0, sizeof(els->io.iparam));
6298f406ef7SJames Smart els->io.iparam.els.ox_id = ox_id;
6308f406ef7SJames Smart
6318f406ef7SJames Smart rjt = els->io.req.virt;
6328f406ef7SJames Smart memset(rjt, 0, sizeof(*rjt));
6338f406ef7SJames Smart
6348f406ef7SJames Smart rjt->er_cmd = ELS_LS_RJT;
6358f406ef7SJames Smart rjt->er_reason = reason_code;
6368f406ef7SJames Smart rjt->er_explan = reason_code_expl;
6378f406ef7SJames Smart
6388f406ef7SJames Smart return efc_els_send_rsp(els, sizeof(*rjt));
6398f406ef7SJames Smart }
6408f406ef7SJames Smart
6418f406ef7SJames Smart int
efc_send_plogi_acc(struct efc_node * node,u32 ox_id)6428f406ef7SJames Smart efc_send_plogi_acc(struct efc_node *node, u32 ox_id)
6438f406ef7SJames Smart {
6448f406ef7SJames Smart struct efc *efc = node->efc;
6458f406ef7SJames Smart struct efc_els_io_req *els = NULL;
6468f406ef7SJames Smart struct fc_els_flogi *plogi;
6478f406ef7SJames Smart struct fc_els_flogi *req = (struct fc_els_flogi *)node->service_params;
6488f406ef7SJames Smart
6498f406ef7SJames Smart node_els_trace();
6508f406ef7SJames Smart
6518f406ef7SJames Smart els = efc_els_io_alloc(node, sizeof(*plogi));
6528f406ef7SJames Smart if (!els) {
6538f406ef7SJames Smart efc_log_err(efc, "els IO alloc failed\n");
6548f406ef7SJames Smart return -EIO;
6558f406ef7SJames Smart }
6568f406ef7SJames Smart
6578f406ef7SJames Smart els->display_name = "plogi_acc";
6588f406ef7SJames Smart
6598f406ef7SJames Smart memset(&els->io.iparam, 0, sizeof(els->io.iparam));
6608f406ef7SJames Smart els->io.iparam.els.ox_id = ox_id;
6618f406ef7SJames Smart
6628f406ef7SJames Smart plogi = els->io.req.virt;
6638f406ef7SJames Smart
6648f406ef7SJames Smart /* copy our port's service parameters to payload */
6658f406ef7SJames Smart memcpy(plogi, node->nport->service_params, sizeof(*plogi));
6668f406ef7SJames Smart plogi->fl_cmd = ELS_LS_ACC;
6678f406ef7SJames Smart memset(plogi->_fl_resvd, 0, sizeof(plogi->_fl_resvd));
6688f406ef7SJames Smart
6698f406ef7SJames Smart /* Set Application header support bit if requested */
6708f406ef7SJames Smart if (req->fl_csp.sp_features & cpu_to_be16(FC_SP_FT_BCAST))
6718f406ef7SJames Smart plogi->fl_csp.sp_features |= cpu_to_be16(FC_SP_FT_BCAST);
6728f406ef7SJames Smart
6738f406ef7SJames Smart return efc_els_send_rsp(els, sizeof(*plogi));
6748f406ef7SJames Smart }
6758f406ef7SJames Smart
6768f406ef7SJames Smart int
efc_send_flogi_p2p_acc(struct efc_node * node,u32 ox_id,u32 s_id)6778f406ef7SJames Smart efc_send_flogi_p2p_acc(struct efc_node *node, u32 ox_id, u32 s_id)
6788f406ef7SJames Smart {
6798f406ef7SJames Smart struct efc *efc = node->efc;
6808f406ef7SJames Smart struct efc_els_io_req *els = NULL;
6818f406ef7SJames Smart struct fc_els_flogi *flogi;
6828f406ef7SJames Smart
6838f406ef7SJames Smart node_els_trace();
6848f406ef7SJames Smart
6858f406ef7SJames Smart els = efc_els_io_alloc(node, sizeof(*flogi));
6868f406ef7SJames Smart if (!els) {
6878f406ef7SJames Smart efc_log_err(efc, "els IO alloc failed\n");
6888f406ef7SJames Smart return -EIO;
6898f406ef7SJames Smart }
6908f406ef7SJames Smart
6918f406ef7SJames Smart els->display_name = "flogi_p2p_acc";
6928f406ef7SJames Smart
6938f406ef7SJames Smart memset(&els->io.iparam, 0, sizeof(els->io.iparam));
6948f406ef7SJames Smart els->io.iparam.els.ox_id = ox_id;
6958f406ef7SJames Smart els->io.iparam.els.s_id = s_id;
6968f406ef7SJames Smart
6978f406ef7SJames Smart flogi = els->io.req.virt;
6988f406ef7SJames Smart
6998f406ef7SJames Smart /* copy our port's service parameters to payload */
7008f406ef7SJames Smart memcpy(flogi, node->nport->service_params, sizeof(*flogi));
7018f406ef7SJames Smart flogi->fl_cmd = ELS_LS_ACC;
7028f406ef7SJames Smart memset(flogi->_fl_resvd, 0, sizeof(flogi->_fl_resvd));
7038f406ef7SJames Smart
7048f406ef7SJames Smart memset(flogi->fl_cssp, 0, sizeof(flogi->fl_cssp));
7058f406ef7SJames Smart
7068f406ef7SJames Smart return efc_els_send_rsp(els, sizeof(*flogi));
7078f406ef7SJames Smart }
7088f406ef7SJames Smart
7098f406ef7SJames Smart int
efc_send_prli_acc(struct efc_node * node,u32 ox_id)7108f406ef7SJames Smart efc_send_prli_acc(struct efc_node *node, u32 ox_id)
7118f406ef7SJames Smart {
7128f406ef7SJames Smart struct efc *efc = node->efc;
7138f406ef7SJames Smart struct efc_els_io_req *els = NULL;
7148f406ef7SJames Smart struct {
7158f406ef7SJames Smart struct fc_els_prli prli;
7168f406ef7SJames Smart struct fc_els_spp spp;
7178f406ef7SJames Smart } *pp;
7188f406ef7SJames Smart
7198f406ef7SJames Smart node_els_trace();
7208f406ef7SJames Smart
7218f406ef7SJames Smart els = efc_els_io_alloc(node, sizeof(*pp));
7228f406ef7SJames Smart if (!els) {
7238f406ef7SJames Smart efc_log_err(efc, "els IO alloc failed\n");
7248f406ef7SJames Smart return -EIO;
7258f406ef7SJames Smart }
7268f406ef7SJames Smart
7278f406ef7SJames Smart els->display_name = "prli_acc";
7288f406ef7SJames Smart
7298f406ef7SJames Smart memset(&els->io.iparam, 0, sizeof(els->io.iparam));
7308f406ef7SJames Smart els->io.iparam.els.ox_id = ox_id;
7318f406ef7SJames Smart
7328f406ef7SJames Smart pp = els->io.req.virt;
7338f406ef7SJames Smart memset(pp, 0, sizeof(*pp));
7348f406ef7SJames Smart
7358f406ef7SJames Smart pp->prli.prli_cmd = ELS_LS_ACC;
7368f406ef7SJames Smart pp->prli.prli_spp_len = 0x10;
7378f406ef7SJames Smart pp->prli.prli_len = cpu_to_be16(sizeof(*pp));
7388f406ef7SJames Smart pp->spp.spp_type = FC_TYPE_FCP;
7398f406ef7SJames Smart pp->spp.spp_type_ext = 0;
7408f406ef7SJames Smart pp->spp.spp_flags = FC_SPP_EST_IMG_PAIR | FC_SPP_RESP_ACK;
7418f406ef7SJames Smart
7428f406ef7SJames Smart pp->spp.spp_params = cpu_to_be32(FCP_SPPF_RD_XRDY_DIS |
7438f406ef7SJames Smart (node->nport->enable_ini ?
7448f406ef7SJames Smart FCP_SPPF_INIT_FCN : 0) |
7458f406ef7SJames Smart (node->nport->enable_tgt ?
7468f406ef7SJames Smart FCP_SPPF_TARG_FCN : 0));
7478f406ef7SJames Smart
7488f406ef7SJames Smart return efc_els_send_rsp(els, sizeof(*pp));
7498f406ef7SJames Smart }
7508f406ef7SJames Smart
7518f406ef7SJames Smart int
efc_send_prlo_acc(struct efc_node * node,u32 ox_id)7528f406ef7SJames Smart efc_send_prlo_acc(struct efc_node *node, u32 ox_id)
7538f406ef7SJames Smart {
7548f406ef7SJames Smart struct efc *efc = node->efc;
7558f406ef7SJames Smart struct efc_els_io_req *els = NULL;
7568f406ef7SJames Smart struct {
7578f406ef7SJames Smart struct fc_els_prlo prlo;
7588f406ef7SJames Smart struct fc_els_spp spp;
7598f406ef7SJames Smart } *pp;
7608f406ef7SJames Smart
7618f406ef7SJames Smart node_els_trace();
7628f406ef7SJames Smart
7638f406ef7SJames Smart els = efc_els_io_alloc(node, sizeof(*pp));
7648f406ef7SJames Smart if (!els) {
7658f406ef7SJames Smart efc_log_err(efc, "els IO alloc failed\n");
7668f406ef7SJames Smart return -EIO;
7678f406ef7SJames Smart }
7688f406ef7SJames Smart
7698f406ef7SJames Smart els->display_name = "prlo_acc";
7708f406ef7SJames Smart
7718f406ef7SJames Smart memset(&els->io.iparam, 0, sizeof(els->io.iparam));
7728f406ef7SJames Smart els->io.iparam.els.ox_id = ox_id;
7738f406ef7SJames Smart
7748f406ef7SJames Smart pp = els->io.req.virt;
7758f406ef7SJames Smart memset(pp, 0, sizeof(*pp));
7768f406ef7SJames Smart pp->prlo.prlo_cmd = ELS_LS_ACC;
7778f406ef7SJames Smart pp->prlo.prlo_obs = 0x10;
7788f406ef7SJames Smart pp->prlo.prlo_len = cpu_to_be16(sizeof(*pp));
7798f406ef7SJames Smart
7808f406ef7SJames Smart pp->spp.spp_type = FC_TYPE_FCP;
7818f406ef7SJames Smart pp->spp.spp_type_ext = 0;
7828f406ef7SJames Smart pp->spp.spp_flags = FC_SPP_RESP_ACK;
7838f406ef7SJames Smart
7848f406ef7SJames Smart return efc_els_send_rsp(els, sizeof(*pp));
7858f406ef7SJames Smart }
7868f406ef7SJames Smart
7878f406ef7SJames Smart int
efc_send_ls_acc(struct efc_node * node,u32 ox_id)7888f406ef7SJames Smart efc_send_ls_acc(struct efc_node *node, u32 ox_id)
7898f406ef7SJames Smart {
7908f406ef7SJames Smart struct efc *efc = node->efc;
7918f406ef7SJames Smart struct efc_els_io_req *els = NULL;
7928f406ef7SJames Smart struct fc_els_ls_acc *acc;
7938f406ef7SJames Smart
7948f406ef7SJames Smart node_els_trace();
7958f406ef7SJames Smart
7968f406ef7SJames Smart els = efc_els_io_alloc(node, sizeof(*acc));
7978f406ef7SJames Smart if (!els) {
7988f406ef7SJames Smart efc_log_err(efc, "els IO alloc failed\n");
7998f406ef7SJames Smart return -EIO;
8008f406ef7SJames Smart }
8018f406ef7SJames Smart
8028f406ef7SJames Smart els->display_name = "ls_acc";
8038f406ef7SJames Smart
8048f406ef7SJames Smart memset(&els->io.iparam, 0, sizeof(els->io.iparam));
8058f406ef7SJames Smart els->io.iparam.els.ox_id = ox_id;
8068f406ef7SJames Smart
8078f406ef7SJames Smart acc = els->io.req.virt;
8088f406ef7SJames Smart memset(acc, 0, sizeof(*acc));
8098f406ef7SJames Smart
8108f406ef7SJames Smart acc->la_cmd = ELS_LS_ACC;
8118f406ef7SJames Smart
8128f406ef7SJames Smart return efc_els_send_rsp(els, sizeof(*acc));
8138f406ef7SJames Smart }
8148f406ef7SJames Smart
8158f406ef7SJames Smart int
efc_send_logo_acc(struct efc_node * node,u32 ox_id)8168f406ef7SJames Smart efc_send_logo_acc(struct efc_node *node, u32 ox_id)
8178f406ef7SJames Smart {
8188f406ef7SJames Smart struct efc_els_io_req *els = NULL;
8198f406ef7SJames Smart struct efc *efc = node->efc;
8208f406ef7SJames Smart struct fc_els_ls_acc *logo;
8218f406ef7SJames Smart
8228f406ef7SJames Smart node_els_trace();
8238f406ef7SJames Smart
8248f406ef7SJames Smart els = efc_els_io_alloc(node, sizeof(*logo));
8258f406ef7SJames Smart if (!els) {
8268f406ef7SJames Smart efc_log_err(efc, "els IO alloc failed\n");
8278f406ef7SJames Smart return -EIO;
8288f406ef7SJames Smart }
8298f406ef7SJames Smart
8308f406ef7SJames Smart els->display_name = "logo_acc";
8318f406ef7SJames Smart
8328f406ef7SJames Smart memset(&els->io.iparam, 0, sizeof(els->io.iparam));
8338f406ef7SJames Smart els->io.iparam.els.ox_id = ox_id;
8348f406ef7SJames Smart
8358f406ef7SJames Smart logo = els->io.req.virt;
8368f406ef7SJames Smart memset(logo, 0, sizeof(*logo));
8378f406ef7SJames Smart
8388f406ef7SJames Smart logo->la_cmd = ELS_LS_ACC;
8398f406ef7SJames Smart
8408f406ef7SJames Smart return efc_els_send_rsp(els, sizeof(*logo));
8418f406ef7SJames Smart }
8428f406ef7SJames Smart
8438f406ef7SJames Smart int
efc_send_adisc_acc(struct efc_node * node,u32 ox_id)8448f406ef7SJames Smart efc_send_adisc_acc(struct efc_node *node, u32 ox_id)
8458f406ef7SJames Smart {
8468f406ef7SJames Smart struct efc *efc = node->efc;
8478f406ef7SJames Smart struct efc_els_io_req *els = NULL;
8488f406ef7SJames Smart struct fc_els_adisc *adisc;
8498f406ef7SJames Smart struct fc_els_flogi *sparams;
8508f406ef7SJames Smart
8518f406ef7SJames Smart node_els_trace();
8528f406ef7SJames Smart
8538f406ef7SJames Smart els = efc_els_io_alloc(node, sizeof(*adisc));
8548f406ef7SJames Smart if (!els) {
8558f406ef7SJames Smart efc_log_err(efc, "els IO alloc failed\n");
8568f406ef7SJames Smart return -EIO;
8578f406ef7SJames Smart }
8588f406ef7SJames Smart
8598f406ef7SJames Smart els->display_name = "adisc_acc";
8608f406ef7SJames Smart
8618f406ef7SJames Smart /* Go ahead and send the ELS_ACC */
8628f406ef7SJames Smart memset(&els->io.iparam, 0, sizeof(els->io.iparam));
8638f406ef7SJames Smart els->io.iparam.els.ox_id = ox_id;
8648f406ef7SJames Smart
8658f406ef7SJames Smart sparams = (struct fc_els_flogi *)node->nport->service_params;
8668f406ef7SJames Smart adisc = els->io.req.virt;
8678f406ef7SJames Smart memset(adisc, 0, sizeof(*adisc));
8688f406ef7SJames Smart adisc->adisc_cmd = ELS_LS_ACC;
8698f406ef7SJames Smart adisc->adisc_wwpn = sparams->fl_wwpn;
8708f406ef7SJames Smart adisc->adisc_wwnn = sparams->fl_wwnn;
8718f406ef7SJames Smart hton24(adisc->adisc_port_id, node->rnode.nport->fc_id);
8728f406ef7SJames Smart
8738f406ef7SJames Smart return efc_els_send_rsp(els, sizeof(*adisc));
8748f406ef7SJames Smart }
8758f406ef7SJames Smart
8768f406ef7SJames Smart static inline void
fcct_build_req_header(struct fc_ct_hdr * hdr,u16 cmd,u16 max_size)8778f406ef7SJames Smart fcct_build_req_header(struct fc_ct_hdr *hdr, u16 cmd, u16 max_size)
8788f406ef7SJames Smart {
8798f406ef7SJames Smart hdr->ct_rev = FC_CT_REV;
8808f406ef7SJames Smart hdr->ct_fs_type = FC_FST_DIR;
8818f406ef7SJames Smart hdr->ct_fs_subtype = FC_NS_SUBTYPE;
8828f406ef7SJames Smart hdr->ct_options = 0;
8838f406ef7SJames Smart hdr->ct_cmd = cpu_to_be16(cmd);
8848f406ef7SJames Smart /* words */
8858f406ef7SJames Smart hdr->ct_mr_size = cpu_to_be16(max_size / (sizeof(u32)));
8868f406ef7SJames Smart hdr->ct_reason = 0;
8878f406ef7SJames Smart hdr->ct_explan = 0;
8888f406ef7SJames Smart hdr->ct_vendor = 0;
8898f406ef7SJames Smart }
8908f406ef7SJames Smart
8918f406ef7SJames Smart int
efc_ns_send_rftid(struct efc_node * node)8928f406ef7SJames Smart efc_ns_send_rftid(struct efc_node *node)
8938f406ef7SJames Smart {
8948f406ef7SJames Smart struct efc *efc = node->efc;
8958f406ef7SJames Smart struct efc_els_io_req *els;
8968f406ef7SJames Smart struct {
8978f406ef7SJames Smart struct fc_ct_hdr hdr;
8988f406ef7SJames Smart struct fc_ns_rft_id rftid;
8998f406ef7SJames Smart } *ct;
9008f406ef7SJames Smart
9018f406ef7SJames Smart node_els_trace();
9028f406ef7SJames Smart
9038f406ef7SJames Smart els = efc_els_io_alloc(node, sizeof(*ct));
9048f406ef7SJames Smart if (!els) {
9058f406ef7SJames Smart efc_log_err(efc, "IO alloc failed\n");
9068f406ef7SJames Smart return -EIO;
9078f406ef7SJames Smart }
9088f406ef7SJames Smart
9098f406ef7SJames Smart els->io.iparam.ct.r_ctl = FC_RCTL_ELS_REQ;
9108f406ef7SJames Smart els->io.iparam.ct.type = FC_TYPE_CT;
9118f406ef7SJames Smart els->io.iparam.ct.df_ctl = 0;
9128f406ef7SJames Smart els->io.iparam.ct.timeout = EFC_FC_ELS_SEND_DEFAULT_TIMEOUT;
9138f406ef7SJames Smart
9148f406ef7SJames Smart els->display_name = "rftid";
9158f406ef7SJames Smart
9168f406ef7SJames Smart ct = els->io.req.virt;
9178f406ef7SJames Smart memset(ct, 0, sizeof(*ct));
9188f406ef7SJames Smart fcct_build_req_header(&ct->hdr, FC_NS_RFT_ID,
9198f406ef7SJames Smart sizeof(struct fc_ns_rft_id));
9208f406ef7SJames Smart
9218f406ef7SJames Smart hton24(ct->rftid.fr_fid.fp_fid, node->rnode.nport->fc_id);
9228f406ef7SJames Smart ct->rftid.fr_fts.ff_type_map[FC_TYPE_FCP / FC_NS_BPW] =
9238f406ef7SJames Smart cpu_to_be32(1 << (FC_TYPE_FCP % FC_NS_BPW));
9248f406ef7SJames Smart
9258f406ef7SJames Smart return efc_els_send_req(node, els, EFC_DISC_IO_CT_REQ);
9268f406ef7SJames Smart }
9278f406ef7SJames Smart
9288f406ef7SJames Smart int
efc_ns_send_rffid(struct efc_node * node)9298f406ef7SJames Smart efc_ns_send_rffid(struct efc_node *node)
9308f406ef7SJames Smart {
9318f406ef7SJames Smart struct efc *efc = node->efc;
9328f406ef7SJames Smart struct efc_els_io_req *els;
9338f406ef7SJames Smart struct {
9348f406ef7SJames Smart struct fc_ct_hdr hdr;
9358f406ef7SJames Smart struct fc_ns_rff_id rffid;
9368f406ef7SJames Smart } *ct;
9378f406ef7SJames Smart
9388f406ef7SJames Smart node_els_trace();
9398f406ef7SJames Smart
9408f406ef7SJames Smart els = efc_els_io_alloc(node, sizeof(*ct));
9418f406ef7SJames Smart if (!els) {
9428f406ef7SJames Smart efc_log_err(efc, "IO alloc failed\n");
9438f406ef7SJames Smart return -EIO;
9448f406ef7SJames Smart }
9458f406ef7SJames Smart
9468f406ef7SJames Smart els->io.iparam.ct.r_ctl = FC_RCTL_ELS_REQ;
9478f406ef7SJames Smart els->io.iparam.ct.type = FC_TYPE_CT;
9488f406ef7SJames Smart els->io.iparam.ct.df_ctl = 0;
9498f406ef7SJames Smart els->io.iparam.ct.timeout = EFC_FC_ELS_SEND_DEFAULT_TIMEOUT;
9508f406ef7SJames Smart
9518f406ef7SJames Smart els->display_name = "rffid";
9528f406ef7SJames Smart ct = els->io.req.virt;
9538f406ef7SJames Smart
9548f406ef7SJames Smart memset(ct, 0, sizeof(*ct));
9558f406ef7SJames Smart fcct_build_req_header(&ct->hdr, FC_NS_RFF_ID,
9568f406ef7SJames Smart sizeof(struct fc_ns_rff_id));
9578f406ef7SJames Smart
9588f406ef7SJames Smart hton24(ct->rffid.fr_fid.fp_fid, node->rnode.nport->fc_id);
9598f406ef7SJames Smart if (node->nport->enable_ini)
9608f406ef7SJames Smart ct->rffid.fr_feat |= FCP_FEAT_INIT;
9618f406ef7SJames Smart if (node->nport->enable_tgt)
9628f406ef7SJames Smart ct->rffid.fr_feat |= FCP_FEAT_TARG;
9638f406ef7SJames Smart ct->rffid.fr_type = FC_TYPE_FCP;
9648f406ef7SJames Smart
9658f406ef7SJames Smart return efc_els_send_req(node, els, EFC_DISC_IO_CT_REQ);
9668f406ef7SJames Smart }
9678f406ef7SJames Smart
9688f406ef7SJames Smart int
efc_ns_send_gidpt(struct efc_node * node)9698f406ef7SJames Smart efc_ns_send_gidpt(struct efc_node *node)
9708f406ef7SJames Smart {
9718f406ef7SJames Smart struct efc_els_io_req *els = NULL;
9728f406ef7SJames Smart struct efc *efc = node->efc;
9738f406ef7SJames Smart struct {
9748f406ef7SJames Smart struct fc_ct_hdr hdr;
9758f406ef7SJames Smart struct fc_ns_gid_pt gidpt;
9768f406ef7SJames Smart } *ct;
9778f406ef7SJames Smart
9788f406ef7SJames Smart node_els_trace();
9798f406ef7SJames Smart
9808f406ef7SJames Smart els = efc_els_io_alloc_size(node, sizeof(*ct), EFC_ELS_GID_PT_RSP_LEN);
9818f406ef7SJames Smart if (!els) {
9828f406ef7SJames Smart efc_log_err(efc, "IO alloc failed\n");
9838f406ef7SJames Smart return -EIO;
9848f406ef7SJames Smart }
9858f406ef7SJames Smart
9868f406ef7SJames Smart els->io.iparam.ct.r_ctl = FC_RCTL_ELS_REQ;
9878f406ef7SJames Smart els->io.iparam.ct.type = FC_TYPE_CT;
9888f406ef7SJames Smart els->io.iparam.ct.df_ctl = 0;
9898f406ef7SJames Smart els->io.iparam.ct.timeout = EFC_FC_ELS_SEND_DEFAULT_TIMEOUT;
9908f406ef7SJames Smart
9918f406ef7SJames Smart els->display_name = "gidpt";
9928f406ef7SJames Smart
9938f406ef7SJames Smart ct = els->io.req.virt;
9948f406ef7SJames Smart
9958f406ef7SJames Smart memset(ct, 0, sizeof(*ct));
9968f406ef7SJames Smart fcct_build_req_header(&ct->hdr, FC_NS_GID_PT,
9978f406ef7SJames Smart sizeof(struct fc_ns_gid_pt));
9988f406ef7SJames Smart
9998f406ef7SJames Smart ct->gidpt.fn_pt_type = FC_TYPE_FCP;
10008f406ef7SJames Smart
10018f406ef7SJames Smart return efc_els_send_req(node, els, EFC_DISC_IO_CT_REQ);
10028f406ef7SJames Smart }
10038f406ef7SJames Smart
10048f406ef7SJames Smart void
efc_els_io_cleanup(struct efc_els_io_req * els,int evt,void * arg)10058f406ef7SJames Smart efc_els_io_cleanup(struct efc_els_io_req *els, int evt, void *arg)
10068f406ef7SJames Smart {
10078f406ef7SJames Smart /* don't want further events that could come; e.g. abort requests
10088f406ef7SJames Smart * from the node state machine; thus, disable state machine
10098f406ef7SJames Smart */
10108f406ef7SJames Smart els->els_req_free = true;
10118f406ef7SJames Smart efc_node_post_els_resp(els->node, evt, arg);
10128f406ef7SJames Smart
10138f406ef7SJames Smart efc_els_io_free(els);
10148f406ef7SJames Smart }
10158f406ef7SJames Smart
10168f406ef7SJames Smart static int
efc_ct_acc_cb(void * arg,u32 length,int status,u32 ext_status)10178f406ef7SJames Smart efc_ct_acc_cb(void *arg, u32 length, int status, u32 ext_status)
10188f406ef7SJames Smart {
10198f406ef7SJames Smart struct efc_els_io_req *els = arg;
10208f406ef7SJames Smart
10218f406ef7SJames Smart efc_els_io_free(els);
10228f406ef7SJames Smart
10238f406ef7SJames Smart return 0;
10248f406ef7SJames Smart }
10258f406ef7SJames Smart
10268f406ef7SJames Smart int
efc_send_ct_rsp(struct efc * efc,struct efc_node * node,u16 ox_id,struct fc_ct_hdr * ct_hdr,u32 cmd_rsp_code,u32 reason_code,u32 reason_code_explanation)10278f406ef7SJames Smart efc_send_ct_rsp(struct efc *efc, struct efc_node *node, u16 ox_id,
10288f406ef7SJames Smart struct fc_ct_hdr *ct_hdr, u32 cmd_rsp_code,
10298f406ef7SJames Smart u32 reason_code, u32 reason_code_explanation)
10308f406ef7SJames Smart {
10318f406ef7SJames Smart struct efc_els_io_req *els = NULL;
10328f406ef7SJames Smart struct fc_ct_hdr *rsp = NULL;
10338f406ef7SJames Smart
10348f406ef7SJames Smart els = efc_els_io_alloc(node, 256);
10358f406ef7SJames Smart if (!els) {
10368f406ef7SJames Smart efc_log_err(efc, "IO alloc failed\n");
10378f406ef7SJames Smart return -EIO;
10388f406ef7SJames Smart }
10398f406ef7SJames Smart
10408f406ef7SJames Smart rsp = els->io.rsp.virt;
10418f406ef7SJames Smart
10428f406ef7SJames Smart *rsp = *ct_hdr;
10438f406ef7SJames Smart
10448f406ef7SJames Smart fcct_build_req_header(rsp, cmd_rsp_code, 0);
10458f406ef7SJames Smart rsp->ct_reason = reason_code;
10468f406ef7SJames Smart rsp->ct_explan = reason_code_explanation;
10478f406ef7SJames Smart
10488f406ef7SJames Smart els->display_name = "ct_rsp";
10498f406ef7SJames Smart els->cb = efc_ct_acc_cb;
10508f406ef7SJames Smart
10518f406ef7SJames Smart /* Prepare the IO request details */
10528f406ef7SJames Smart els->io.io_type = EFC_DISC_IO_CT_RESP;
10538f406ef7SJames Smart els->io.xmit_len = sizeof(*rsp);
10548f406ef7SJames Smart
10558f406ef7SJames Smart els->io.rpi = node->rnode.indicator;
10568f406ef7SJames Smart els->io.d_id = node->rnode.fc_id;
10578f406ef7SJames Smart
10588f406ef7SJames Smart memset(&els->io.iparam, 0, sizeof(els->io.iparam));
10598f406ef7SJames Smart
10608f406ef7SJames Smart els->io.iparam.ct.ox_id = ox_id;
10618f406ef7SJames Smart els->io.iparam.ct.r_ctl = 3;
10628f406ef7SJames Smart els->io.iparam.ct.type = FC_TYPE_CT;
10638f406ef7SJames Smart els->io.iparam.ct.df_ctl = 0;
10648f406ef7SJames Smart els->io.iparam.ct.timeout = 5;
10658f406ef7SJames Smart
10668f406ef7SJames Smart if (efc->tt.send_els(efc, &els->io)) {
10678f406ef7SJames Smart efc_els_io_free(els);
10688f406ef7SJames Smart return -EIO;
10698f406ef7SJames Smart }
10708f406ef7SJames Smart return 0;
10718f406ef7SJames Smart }
10728f406ef7SJames Smart
10738f406ef7SJames Smart int
efc_send_bls_acc(struct efc_node * node,struct fc_frame_header * hdr)10748f406ef7SJames Smart efc_send_bls_acc(struct efc_node *node, struct fc_frame_header *hdr)
10758f406ef7SJames Smart {
10768f406ef7SJames Smart struct sli_bls_params bls;
10778f406ef7SJames Smart struct fc_ba_acc *acc;
10788f406ef7SJames Smart struct efc *efc = node->efc;
10798f406ef7SJames Smart
10808f406ef7SJames Smart memset(&bls, 0, sizeof(bls));
10818f406ef7SJames Smart bls.ox_id = be16_to_cpu(hdr->fh_ox_id);
10828f406ef7SJames Smart bls.rx_id = be16_to_cpu(hdr->fh_rx_id);
10838f406ef7SJames Smart bls.s_id = ntoh24(hdr->fh_d_id);
10848f406ef7SJames Smart bls.d_id = node->rnode.fc_id;
10858f406ef7SJames Smart bls.rpi = node->rnode.indicator;
10868f406ef7SJames Smart bls.vpi = node->nport->indicator;
10878f406ef7SJames Smart
10888f406ef7SJames Smart acc = (void *)bls.payload;
10898f406ef7SJames Smart acc->ba_ox_id = cpu_to_be16(bls.ox_id);
10908f406ef7SJames Smart acc->ba_rx_id = cpu_to_be16(bls.rx_id);
10918f406ef7SJames Smart acc->ba_high_seq_cnt = cpu_to_be16(U16_MAX);
10928f406ef7SJames Smart
10938f406ef7SJames Smart return efc->tt.send_bls(efc, FC_RCTL_BA_ACC, &bls);
10948f406ef7SJames Smart }
1095