14df84e84SJames Smart // SPDX-License-Identifier: GPL-2.0
24df84e84SJames Smart /*
34df84e84SJames Smart * Copyright (C) 2021 Broadcom. All Rights Reserved. The term
44df84e84SJames Smart * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
54df84e84SJames Smart */
64df84e84SJames Smart
74df84e84SJames Smart #include "efct_driver.h"
84df84e84SJames Smart #include "efct_hw.h"
94df84e84SJames Smart #include "efct_unsol.h"
104df84e84SJames Smart
116ae7147bSJames Smart struct efct_hw_link_stat_cb_arg {
126ae7147bSJames Smart void (*cb)(int status, u32 num_counters,
136ae7147bSJames Smart struct efct_hw_link_stat_counts *counters, void *arg);
146ae7147bSJames Smart void *arg;
156ae7147bSJames Smart };
166ae7147bSJames Smart
176ae7147bSJames Smart struct efct_hw_host_stat_cb_arg {
186ae7147bSJames Smart void (*cb)(int status, u32 num_counters,
196ae7147bSJames Smart struct efct_hw_host_stat_counts *counters, void *arg);
206ae7147bSJames Smart void *arg;
216ae7147bSJames Smart };
226ae7147bSJames Smart
236ae7147bSJames Smart struct efct_hw_fw_wr_cb_arg {
246ae7147bSJames Smart void (*cb)(int status, u32 bytes_written, u32 change_status, void *arg);
256ae7147bSJames Smart void *arg;
266ae7147bSJames Smart };
276ae7147bSJames Smart
284df84e84SJames Smart struct efct_mbox_rqst_ctx {
294df84e84SJames Smart int (*callback)(struct efc *efc, int status, u8 *mqe, void *arg);
304df84e84SJames Smart void *arg;
314df84e84SJames Smart };
324df84e84SJames Smart
334df84e84SJames Smart static int
efct_hw_link_event_init(struct efct_hw * hw)344df84e84SJames Smart efct_hw_link_event_init(struct efct_hw *hw)
354df84e84SJames Smart {
364df84e84SJames Smart hw->link.status = SLI4_LINK_STATUS_MAX;
374df84e84SJames Smart hw->link.topology = SLI4_LINK_TOPO_NONE;
384df84e84SJames Smart hw->link.medium = SLI4_LINK_MEDIUM_MAX;
394df84e84SJames Smart hw->link.speed = 0;
404df84e84SJames Smart hw->link.loop_map = NULL;
414df84e84SJames Smart hw->link.fc_id = U32_MAX;
424df84e84SJames Smart
434df84e84SJames Smart return 0;
444df84e84SJames Smart }
454df84e84SJames Smart
464df84e84SJames Smart static int
efct_hw_read_max_dump_size(struct efct_hw * hw)474df84e84SJames Smart efct_hw_read_max_dump_size(struct efct_hw *hw)
484df84e84SJames Smart {
494df84e84SJames Smart u8 buf[SLI4_BMBX_SIZE];
504df84e84SJames Smart struct efct *efct = hw->os;
514df84e84SJames Smart int rc = 0;
524df84e84SJames Smart struct sli4_rsp_cmn_set_dump_location *rsp;
534df84e84SJames Smart
544df84e84SJames Smart /* attempt to detemine the dump size for function 0 only. */
554df84e84SJames Smart if (PCI_FUNC(efct->pci->devfn) != 0)
564df84e84SJames Smart return rc;
574df84e84SJames Smart
584df84e84SJames Smart if (sli_cmd_common_set_dump_location(&hw->sli, buf, 1, 0, NULL, 0))
594df84e84SJames Smart return -EIO;
604df84e84SJames Smart
614df84e84SJames Smart rsp = (struct sli4_rsp_cmn_set_dump_location *)
624df84e84SJames Smart (buf + offsetof(struct sli4_cmd_sli_config, payload.embed));
634df84e84SJames Smart
644df84e84SJames Smart rc = efct_hw_command(hw, buf, EFCT_CMD_POLL, NULL, NULL);
654df84e84SJames Smart if (rc != 0) {
664df84e84SJames Smart efc_log_debug(hw->os, "set dump location cmd failed\n");
674df84e84SJames Smart return rc;
684df84e84SJames Smart }
694df84e84SJames Smart
704df84e84SJames Smart hw->dump_size =
714df84e84SJames Smart le32_to_cpu(rsp->buffer_length_dword) & SLI4_CMN_SET_DUMP_BUFFER_LEN;
724df84e84SJames Smart
734df84e84SJames Smart efc_log_debug(hw->os, "Dump size %x\n", hw->dump_size);
744df84e84SJames Smart
754df84e84SJames Smart return rc;
764df84e84SJames Smart }
774df84e84SJames Smart
784df84e84SJames Smart static int
__efct_read_topology_cb(struct efct_hw * hw,int status,u8 * mqe,void * arg)794df84e84SJames Smart __efct_read_topology_cb(struct efct_hw *hw, int status, u8 *mqe, void *arg)
804df84e84SJames Smart {
814df84e84SJames Smart struct sli4_cmd_read_topology *read_topo =
824df84e84SJames Smart (struct sli4_cmd_read_topology *)mqe;
834df84e84SJames Smart u8 speed;
844df84e84SJames Smart struct efc_domain_record drec = {0};
854df84e84SJames Smart struct efct *efct = hw->os;
864df84e84SJames Smart
874df84e84SJames Smart if (status || le16_to_cpu(read_topo->hdr.status)) {
884df84e84SJames Smart efc_log_debug(hw->os, "bad status cqe=%#x mqe=%#x\n", status,
894df84e84SJames Smart le16_to_cpu(read_topo->hdr.status));
904df84e84SJames Smart return -EIO;
914df84e84SJames Smart }
924df84e84SJames Smart
934df84e84SJames Smart switch (le32_to_cpu(read_topo->dw2_attentype) &
944df84e84SJames Smart SLI4_READTOPO_ATTEN_TYPE) {
954df84e84SJames Smart case SLI4_READ_TOPOLOGY_LINK_UP:
964df84e84SJames Smart hw->link.status = SLI4_LINK_STATUS_UP;
974df84e84SJames Smart break;
984df84e84SJames Smart case SLI4_READ_TOPOLOGY_LINK_DOWN:
994df84e84SJames Smart hw->link.status = SLI4_LINK_STATUS_DOWN;
1004df84e84SJames Smart break;
1014df84e84SJames Smart case SLI4_READ_TOPOLOGY_LINK_NO_ALPA:
1024df84e84SJames Smart hw->link.status = SLI4_LINK_STATUS_NO_ALPA;
1034df84e84SJames Smart break;
1044df84e84SJames Smart default:
1054df84e84SJames Smart hw->link.status = SLI4_LINK_STATUS_MAX;
1064df84e84SJames Smart break;
1074df84e84SJames Smart }
1084df84e84SJames Smart
1094df84e84SJames Smart switch (read_topo->topology) {
1104df84e84SJames Smart case SLI4_READ_TOPO_NON_FC_AL:
1114df84e84SJames Smart hw->link.topology = SLI4_LINK_TOPO_NON_FC_AL;
1124df84e84SJames Smart break;
1134df84e84SJames Smart case SLI4_READ_TOPO_FC_AL:
1144df84e84SJames Smart hw->link.topology = SLI4_LINK_TOPO_FC_AL;
1154df84e84SJames Smart if (hw->link.status == SLI4_LINK_STATUS_UP)
1164df84e84SJames Smart hw->link.loop_map = hw->loop_map.virt;
1174df84e84SJames Smart hw->link.fc_id = read_topo->acquired_al_pa;
1184df84e84SJames Smart break;
1194df84e84SJames Smart default:
1204df84e84SJames Smart hw->link.topology = SLI4_LINK_TOPO_MAX;
1214df84e84SJames Smart break;
1224df84e84SJames Smart }
1234df84e84SJames Smart
1244df84e84SJames Smart hw->link.medium = SLI4_LINK_MEDIUM_FC;
1254df84e84SJames Smart
1264df84e84SJames Smart speed = (le32_to_cpu(read_topo->currlink_state) &
1274df84e84SJames Smart SLI4_READTOPO_LINKSTATE_SPEED) >> 8;
1284df84e84SJames Smart switch (speed) {
1294df84e84SJames Smart case SLI4_READ_TOPOLOGY_SPEED_1G:
1304df84e84SJames Smart hw->link.speed = 1 * 1000;
1314df84e84SJames Smart break;
1324df84e84SJames Smart case SLI4_READ_TOPOLOGY_SPEED_2G:
1334df84e84SJames Smart hw->link.speed = 2 * 1000;
1344df84e84SJames Smart break;
1354df84e84SJames Smart case SLI4_READ_TOPOLOGY_SPEED_4G:
1364df84e84SJames Smart hw->link.speed = 4 * 1000;
1374df84e84SJames Smart break;
1384df84e84SJames Smart case SLI4_READ_TOPOLOGY_SPEED_8G:
1394df84e84SJames Smart hw->link.speed = 8 * 1000;
1404df84e84SJames Smart break;
1414df84e84SJames Smart case SLI4_READ_TOPOLOGY_SPEED_16G:
1424df84e84SJames Smart hw->link.speed = 16 * 1000;
1434df84e84SJames Smart break;
1444df84e84SJames Smart case SLI4_READ_TOPOLOGY_SPEED_32G:
1454df84e84SJames Smart hw->link.speed = 32 * 1000;
1464df84e84SJames Smart break;
1474df84e84SJames Smart case SLI4_READ_TOPOLOGY_SPEED_64G:
1484df84e84SJames Smart hw->link.speed = 64 * 1000;
1494df84e84SJames Smart break;
1504df84e84SJames Smart case SLI4_READ_TOPOLOGY_SPEED_128G:
1514df84e84SJames Smart hw->link.speed = 128 * 1000;
1524df84e84SJames Smart break;
1534df84e84SJames Smart }
1544df84e84SJames Smart
1554df84e84SJames Smart drec.speed = hw->link.speed;
1564df84e84SJames Smart drec.fc_id = hw->link.fc_id;
1574df84e84SJames Smart drec.is_nport = true;
1584df84e84SJames Smart efc_domain_cb(efct->efcport, EFC_HW_DOMAIN_FOUND, &drec);
1594df84e84SJames Smart
1604df84e84SJames Smart return 0;
1614df84e84SJames Smart }
1624df84e84SJames Smart
1634df84e84SJames Smart static int
efct_hw_cb_link(void * ctx,void * e)1644df84e84SJames Smart efct_hw_cb_link(void *ctx, void *e)
1654df84e84SJames Smart {
1664df84e84SJames Smart struct efct_hw *hw = ctx;
1674df84e84SJames Smart struct sli4_link_event *event = e;
1684df84e84SJames Smart struct efc_domain *d = NULL;
1694df84e84SJames Smart int rc = 0;
1704df84e84SJames Smart struct efct *efct = hw->os;
1714df84e84SJames Smart
1724df84e84SJames Smart efct_hw_link_event_init(hw);
1734df84e84SJames Smart
1744df84e84SJames Smart switch (event->status) {
1754df84e84SJames Smart case SLI4_LINK_STATUS_UP:
1764df84e84SJames Smart
1774df84e84SJames Smart hw->link = *event;
1784df84e84SJames Smart efct->efcport->link_status = EFC_LINK_STATUS_UP;
1794df84e84SJames Smart
1804df84e84SJames Smart if (event->topology == SLI4_LINK_TOPO_NON_FC_AL) {
1814df84e84SJames Smart struct efc_domain_record drec = {0};
1824df84e84SJames Smart
1834df84e84SJames Smart efc_log_info(hw->os, "Link Up, NPORT, speed is %d\n",
1844df84e84SJames Smart event->speed);
1854df84e84SJames Smart drec.speed = event->speed;
1864df84e84SJames Smart drec.fc_id = event->fc_id;
1874df84e84SJames Smart drec.is_nport = true;
1884df84e84SJames Smart efc_domain_cb(efct->efcport, EFC_HW_DOMAIN_FOUND,
1894df84e84SJames Smart &drec);
1904df84e84SJames Smart } else if (event->topology == SLI4_LINK_TOPO_FC_AL) {
1914df84e84SJames Smart u8 buf[SLI4_BMBX_SIZE];
1924df84e84SJames Smart
1934df84e84SJames Smart efc_log_info(hw->os, "Link Up, LOOP, speed is %d\n",
1944df84e84SJames Smart event->speed);
1954df84e84SJames Smart
1964df84e84SJames Smart if (!sli_cmd_read_topology(&hw->sli, buf,
1974df84e84SJames Smart &hw->loop_map)) {
1984df84e84SJames Smart rc = efct_hw_command(hw, buf, EFCT_CMD_NOWAIT,
1994df84e84SJames Smart __efct_read_topology_cb, NULL);
2004df84e84SJames Smart }
2014df84e84SJames Smart
2024df84e84SJames Smart if (rc)
2034df84e84SJames Smart efc_log_debug(hw->os, "READ_TOPOLOGY failed\n");
2044df84e84SJames Smart } else {
2054df84e84SJames Smart efc_log_info(hw->os, "%s(%#x), speed is %d\n",
2064df84e84SJames Smart "Link Up, unsupported topology ",
2074df84e84SJames Smart event->topology, event->speed);
2084df84e84SJames Smart }
2094df84e84SJames Smart break;
2104df84e84SJames Smart case SLI4_LINK_STATUS_DOWN:
2114df84e84SJames Smart efc_log_info(hw->os, "Link down\n");
2124df84e84SJames Smart
2134df84e84SJames Smart hw->link.status = event->status;
2144df84e84SJames Smart efct->efcport->link_status = EFC_LINK_STATUS_DOWN;
2154df84e84SJames Smart
2164df84e84SJames Smart d = efct->efcport->domain;
2174df84e84SJames Smart if (d)
2184df84e84SJames Smart efc_domain_cb(efct->efcport, EFC_HW_DOMAIN_LOST, d);
2194df84e84SJames Smart break;
2204df84e84SJames Smart default:
2214df84e84SJames Smart efc_log_debug(hw->os, "unhandled link status %#x\n",
2224df84e84SJames Smart event->status);
2234df84e84SJames Smart break;
2244df84e84SJames Smart }
2254df84e84SJames Smart
2264df84e84SJames Smart return 0;
2274df84e84SJames Smart }
2284df84e84SJames Smart
2294df84e84SJames Smart int
efct_hw_setup(struct efct_hw * hw,void * os,struct pci_dev * pdev)2304df84e84SJames Smart efct_hw_setup(struct efct_hw *hw, void *os, struct pci_dev *pdev)
2314df84e84SJames Smart {
2324df84e84SJames Smart u32 i, max_sgl, cpus;
2334df84e84SJames Smart
2344df84e84SJames Smart if (hw->hw_setup_called)
2354df84e84SJames Smart return 0;
2364df84e84SJames Smart
2374df84e84SJames Smart /*
2384df84e84SJames Smart * efct_hw_init() relies on NULL pointers indicating that a structure
2394df84e84SJames Smart * needs allocation. If a structure is non-NULL, efct_hw_init() won't
2404df84e84SJames Smart * free/realloc that memory
2414df84e84SJames Smart */
2424df84e84SJames Smart memset(hw, 0, sizeof(struct efct_hw));
2434df84e84SJames Smart
2444df84e84SJames Smart hw->hw_setup_called = true;
2454df84e84SJames Smart
2464df84e84SJames Smart hw->os = os;
2474df84e84SJames Smart
2484df84e84SJames Smart mutex_init(&hw->bmbx_lock);
2494df84e84SJames Smart spin_lock_init(&hw->cmd_lock);
2504df84e84SJames Smart INIT_LIST_HEAD(&hw->cmd_head);
2514df84e84SJames Smart INIT_LIST_HEAD(&hw->cmd_pending);
2524df84e84SJames Smart hw->cmd_head_count = 0;
2534df84e84SJames Smart
2544df84e84SJames Smart /* Create mailbox command ctx pool */
2554df84e84SJames Smart hw->cmd_ctx_pool = mempool_create_kmalloc_pool(EFCT_CMD_CTX_POOL_SZ,
2564df84e84SJames Smart sizeof(struct efct_command_ctx));
2574df84e84SJames Smart if (!hw->cmd_ctx_pool) {
2584df84e84SJames Smart efc_log_err(hw->os, "failed to allocate mailbox buffer pool\n");
2594df84e84SJames Smart return -EIO;
2604df84e84SJames Smart }
2614df84e84SJames Smart
2624df84e84SJames Smart /* Create mailbox request ctx pool for library callback */
2634df84e84SJames Smart hw->mbox_rqst_pool = mempool_create_kmalloc_pool(EFCT_CMD_CTX_POOL_SZ,
2644df84e84SJames Smart sizeof(struct efct_mbox_rqst_ctx));
2654df84e84SJames Smart if (!hw->mbox_rqst_pool) {
2664df84e84SJames Smart efc_log_err(hw->os, "failed to allocate mbox request pool\n");
2674df84e84SJames Smart return -EIO;
2684df84e84SJames Smart }
2694df84e84SJames Smart
2704df84e84SJames Smart spin_lock_init(&hw->io_lock);
2714df84e84SJames Smart INIT_LIST_HEAD(&hw->io_inuse);
2724df84e84SJames Smart INIT_LIST_HEAD(&hw->io_free);
2734df84e84SJames Smart INIT_LIST_HEAD(&hw->io_wait_free);
2744df84e84SJames Smart
2754df84e84SJames Smart atomic_set(&hw->io_alloc_failed_count, 0);
2764df84e84SJames Smart
2774df84e84SJames Smart hw->config.speed = SLI4_LINK_SPEED_AUTO_16_8_4;
2784df84e84SJames Smart if (sli_setup(&hw->sli, hw->os, pdev, ((struct efct *)os)->reg)) {
2794df84e84SJames Smart efc_log_err(hw->os, "SLI setup failed\n");
2804df84e84SJames Smart return -EIO;
2814df84e84SJames Smart }
2824df84e84SJames Smart
2834df84e84SJames Smart efct_hw_link_event_init(hw);
2844df84e84SJames Smart
2854df84e84SJames Smart sli_callback(&hw->sli, SLI4_CB_LINK, efct_hw_cb_link, hw);
2864df84e84SJames Smart
2874df84e84SJames Smart /*
2884df84e84SJames Smart * Set all the queue sizes to the maximum allowed.
2894df84e84SJames Smart */
2904df84e84SJames Smart for (i = 0; i < ARRAY_SIZE(hw->num_qentries); i++)
2914df84e84SJames Smart hw->num_qentries[i] = hw->sli.qinfo.max_qentries[i];
2924df84e84SJames Smart /*
2934df84e84SJames Smart * Adjust the size of the WQs so that the CQ is twice as big as
2944df84e84SJames Smart * the WQ to allow for 2 completions per IO. This allows us to
2954df84e84SJames Smart * handle multi-phase as well as aborts.
2964df84e84SJames Smart */
2974df84e84SJames Smart hw->num_qentries[SLI4_QTYPE_WQ] = hw->num_qentries[SLI4_QTYPE_CQ] / 2;
2984df84e84SJames Smart
2994df84e84SJames Smart /*
3004df84e84SJames Smart * The RQ assignment for RQ pair mode.
3014df84e84SJames Smart */
3024df84e84SJames Smart
3034df84e84SJames Smart hw->config.rq_default_buffer_size = EFCT_HW_RQ_SIZE_PAYLOAD;
3044df84e84SJames Smart hw->config.n_io = hw->sli.ext[SLI4_RSRC_XRI].size;
3054df84e84SJames Smart
3064df84e84SJames Smart cpus = num_possible_cpus();
3074df84e84SJames Smart hw->config.n_eq = cpus > EFCT_HW_MAX_NUM_EQ ? EFCT_HW_MAX_NUM_EQ : cpus;
3084df84e84SJames Smart
3094df84e84SJames Smart max_sgl = sli_get_max_sgl(&hw->sli) - SLI4_SGE_MAX_RESERVED;
3104df84e84SJames Smart max_sgl = (max_sgl > EFCT_FC_MAX_SGL) ? EFCT_FC_MAX_SGL : max_sgl;
3114df84e84SJames Smart hw->config.n_sgl = max_sgl;
3124df84e84SJames Smart
3134df84e84SJames Smart (void)efct_hw_read_max_dump_size(hw);
3144df84e84SJames Smart
3154df84e84SJames Smart return 0;
3164df84e84SJames Smart }
3174df84e84SJames Smart
3184df84e84SJames Smart static void
efct_logfcfi(struct efct_hw * hw,u32 j,u32 i,u32 id)3194df84e84SJames Smart efct_logfcfi(struct efct_hw *hw, u32 j, u32 i, u32 id)
3204df84e84SJames Smart {
3214df84e84SJames Smart efc_log_info(hw->os,
3224df84e84SJames Smart "REG_FCFI: filter[%d] %08X -> RQ[%d] id=%d\n",
3234df84e84SJames Smart j, hw->config.filter_def[j], i, id);
3244df84e84SJames Smart }
3254df84e84SJames Smart
3264df84e84SJames Smart static inline void
efct_hw_init_free_io(struct efct_hw_io * io)3274df84e84SJames Smart efct_hw_init_free_io(struct efct_hw_io *io)
3284df84e84SJames Smart {
3294df84e84SJames Smart /*
3304df84e84SJames Smart * Set io->done to NULL, to avoid any callbacks, should
3314df84e84SJames Smart * a completion be received for one of these IOs
3324df84e84SJames Smart */
3334df84e84SJames Smart io->done = NULL;
3344df84e84SJames Smart io->abort_done = NULL;
3354df84e84SJames Smart io->status_saved = false;
3364df84e84SJames Smart io->abort_in_progress = false;
3374df84e84SJames Smart io->type = 0xFFFF;
3384df84e84SJames Smart io->wq = NULL;
3394df84e84SJames Smart }
3404df84e84SJames Smart
efct_hw_iotype_is_originator(u16 io_type)341ca7f33c6SJames Smart static bool efct_hw_iotype_is_originator(u16 io_type)
3424df84e84SJames Smart {
3434df84e84SJames Smart switch (io_type) {
3444df84e84SJames Smart case EFCT_HW_FC_CT:
3454df84e84SJames Smart case EFCT_HW_ELS_REQ:
346ca7f33c6SJames Smart return true;
3474df84e84SJames Smart default:
348ca7f33c6SJames Smart return false;
3494df84e84SJames Smart }
3504df84e84SJames Smart }
3514df84e84SJames Smart
3524df84e84SJames Smart static void
efct_hw_io_restore_sgl(struct efct_hw * hw,struct efct_hw_io * io)3534df84e84SJames Smart efct_hw_io_restore_sgl(struct efct_hw *hw, struct efct_hw_io *io)
3544df84e84SJames Smart {
3554df84e84SJames Smart /* Restore the default */
3564df84e84SJames Smart io->sgl = &io->def_sgl;
3574df84e84SJames Smart io->sgl_count = io->def_sgl_count;
3584df84e84SJames Smart }
3594df84e84SJames Smart
3604df84e84SJames Smart static void
efct_hw_wq_process_io(void * arg,u8 * cqe,int status)3614df84e84SJames Smart efct_hw_wq_process_io(void *arg, u8 *cqe, int status)
3624df84e84SJames Smart {
3634df84e84SJames Smart struct efct_hw_io *io = arg;
3644df84e84SJames Smart struct efct_hw *hw = io->hw;
3654df84e84SJames Smart struct sli4_fc_wcqe *wcqe = (void *)cqe;
3664df84e84SJames Smart u32 len = 0;
3674df84e84SJames Smart u32 ext = 0;
3684df84e84SJames Smart
3694df84e84SJames Smart /* clear xbusy flag if WCQE[XB] is clear */
3704df84e84SJames Smart if (io->xbusy && (wcqe->flags & SLI4_WCQE_XB) == 0)
3714df84e84SJames Smart io->xbusy = false;
3724df84e84SJames Smart
3734df84e84SJames Smart /* get extended CQE status */
3744df84e84SJames Smart switch (io->type) {
3754df84e84SJames Smart case EFCT_HW_BLS_ACC:
3764df84e84SJames Smart case EFCT_HW_BLS_RJT:
3774df84e84SJames Smart break;
3784df84e84SJames Smart case EFCT_HW_ELS_REQ:
3794df84e84SJames Smart sli_fc_els_did(&hw->sli, cqe, &ext);
3804df84e84SJames Smart len = sli_fc_response_length(&hw->sli, cqe);
3814df84e84SJames Smart break;
3824df84e84SJames Smart case EFCT_HW_ELS_RSP:
3834df84e84SJames Smart case EFCT_HW_FC_CT_RSP:
3844df84e84SJames Smart break;
3854df84e84SJames Smart case EFCT_HW_FC_CT:
3864df84e84SJames Smart len = sli_fc_response_length(&hw->sli, cqe);
3874df84e84SJames Smart break;
3884df84e84SJames Smart case EFCT_HW_IO_TARGET_WRITE:
3894df84e84SJames Smart len = sli_fc_io_length(&hw->sli, cqe);
3904df84e84SJames Smart break;
3914df84e84SJames Smart case EFCT_HW_IO_TARGET_READ:
3924df84e84SJames Smart len = sli_fc_io_length(&hw->sli, cqe);
3934df84e84SJames Smart break;
3944df84e84SJames Smart case EFCT_HW_IO_TARGET_RSP:
3954df84e84SJames Smart break;
3964df84e84SJames Smart case EFCT_HW_IO_DNRX_REQUEUE:
3974df84e84SJames Smart /* release the count for re-posting the buffer */
3984df84e84SJames Smart /* efct_hw_io_free(hw, io); */
3994df84e84SJames Smart break;
4004df84e84SJames Smart default:
4014df84e84SJames Smart efc_log_err(hw->os, "unhandled io type %#x for XRI 0x%x\n",
4024df84e84SJames Smart io->type, io->indicator);
4034df84e84SJames Smart break;
4044df84e84SJames Smart }
4054df84e84SJames Smart if (status) {
4064df84e84SJames Smart ext = sli_fc_ext_status(&hw->sli, cqe);
4074df84e84SJames Smart /*
4084df84e84SJames Smart * If we're not an originator IO, and XB is set, then issue
4094df84e84SJames Smart * abort for the IO from within the HW
4104df84e84SJames Smart */
411ca7f33c6SJames Smart if (efct_hw_iotype_is_originator(io->type) &&
4124df84e84SJames Smart wcqe->flags & SLI4_WCQE_XB) {
4134df84e84SJames Smart int rc;
4144df84e84SJames Smart
4154df84e84SJames Smart efc_log_debug(hw->os, "aborting xri=%#x tag=%#x\n",
4164df84e84SJames Smart io->indicator, io->reqtag);
4174df84e84SJames Smart
4184df84e84SJames Smart /*
4194df84e84SJames Smart * Because targets may send a response when the IO
4204df84e84SJames Smart * completes using the same XRI, we must wait for the
4214df84e84SJames Smart * XRI_ABORTED CQE to issue the IO callback
4224df84e84SJames Smart */
4234df84e84SJames Smart rc = efct_hw_io_abort(hw, io, false, NULL, NULL);
4244df84e84SJames Smart if (rc == 0) {
4254df84e84SJames Smart /*
4264df84e84SJames Smart * latch status to return after abort is
4274df84e84SJames Smart * complete
4284df84e84SJames Smart */
4294df84e84SJames Smart io->status_saved = true;
4304df84e84SJames Smart io->saved_status = status;
4314df84e84SJames Smart io->saved_ext = ext;
4324df84e84SJames Smart io->saved_len = len;
4334df84e84SJames Smart goto exit_efct_hw_wq_process_io;
4344df84e84SJames Smart } else if (rc == -EINPROGRESS) {
4354df84e84SJames Smart /*
4364df84e84SJames Smart * Already being aborted by someone else (ABTS
4374df84e84SJames Smart * perhaps). Just return original
4384df84e84SJames Smart * error.
4394df84e84SJames Smart */
4404df84e84SJames Smart efc_log_debug(hw->os, "%s%#x tag=%#x\n",
4414df84e84SJames Smart "abort in progress xri=",
4424df84e84SJames Smart io->indicator, io->reqtag);
4434df84e84SJames Smart
4444df84e84SJames Smart } else {
4454df84e84SJames Smart /* Failed to abort for some other reason, log
4464df84e84SJames Smart * error
4474df84e84SJames Smart */
4484df84e84SJames Smart efc_log_debug(hw->os, "%s%#x tag=%#x rc=%d\n",
4494df84e84SJames Smart "Failed to abort xri=",
4504df84e84SJames Smart io->indicator, io->reqtag, rc);
4514df84e84SJames Smart }
4524df84e84SJames Smart }
4534df84e84SJames Smart }
4544df84e84SJames Smart
4554df84e84SJames Smart if (io->done) {
4564df84e84SJames Smart efct_hw_done_t done = io->done;
4574df84e84SJames Smart
4584df84e84SJames Smart io->done = NULL;
4594df84e84SJames Smart
4604df84e84SJames Smart if (io->status_saved) {
4614df84e84SJames Smart /* use latched status if exists */
4624df84e84SJames Smart status = io->saved_status;
4634df84e84SJames Smart len = io->saved_len;
4644df84e84SJames Smart ext = io->saved_ext;
4654df84e84SJames Smart io->status_saved = false;
4664df84e84SJames Smart }
4674df84e84SJames Smart
4684df84e84SJames Smart /* Restore default SGL */
4694df84e84SJames Smart efct_hw_io_restore_sgl(hw, io);
4704df84e84SJames Smart done(io, len, status, ext, io->arg);
4714df84e84SJames Smart }
4724df84e84SJames Smart
4734df84e84SJames Smart exit_efct_hw_wq_process_io:
4744df84e84SJames Smart return;
4754df84e84SJames Smart }
4764df84e84SJames Smart
4774df84e84SJames Smart static int
efct_hw_setup_io(struct efct_hw * hw)4784df84e84SJames Smart efct_hw_setup_io(struct efct_hw *hw)
4794df84e84SJames Smart {
4804df84e84SJames Smart u32 i = 0;
4814df84e84SJames Smart struct efct_hw_io *io = NULL;
4824df84e84SJames Smart uintptr_t xfer_virt = 0;
4834df84e84SJames Smart uintptr_t xfer_phys = 0;
4844df84e84SJames Smart u32 index;
4854df84e84SJames Smart bool new_alloc = true;
4864df84e84SJames Smart struct efc_dma *dma;
4874df84e84SJames Smart struct efct *efct = hw->os;
4884df84e84SJames Smart
4894df84e84SJames Smart if (!hw->io) {
4904df84e84SJames Smart hw->io = kmalloc_array(hw->config.n_io, sizeof(io), GFP_KERNEL);
4914df84e84SJames Smart if (!hw->io)
4924df84e84SJames Smart return -ENOMEM;
4934df84e84SJames Smart
4944df84e84SJames Smart memset(hw->io, 0, hw->config.n_io * sizeof(io));
4954df84e84SJames Smart
4964df84e84SJames Smart for (i = 0; i < hw->config.n_io; i++) {
4974df84e84SJames Smart hw->io[i] = kzalloc(sizeof(*io), GFP_KERNEL);
4984df84e84SJames Smart if (!hw->io[i])
4994df84e84SJames Smart goto error;
5004df84e84SJames Smart }
5014df84e84SJames Smart
5024df84e84SJames Smart /* Create WQE buffs for IO */
5034df84e84SJames Smart hw->wqe_buffs = kzalloc((hw->config.n_io * hw->sli.wqe_size),
5044df84e84SJames Smart GFP_KERNEL);
5054df84e84SJames Smart if (!hw->wqe_buffs) {
5064df84e84SJames Smart kfree(hw->io);
5074df84e84SJames Smart return -ENOMEM;
5084df84e84SJames Smart }
5094df84e84SJames Smart
5104df84e84SJames Smart } else {
5114df84e84SJames Smart /* re-use existing IOs, including SGLs */
5124df84e84SJames Smart new_alloc = false;
5134df84e84SJames Smart }
5144df84e84SJames Smart
5154df84e84SJames Smart if (new_alloc) {
5164df84e84SJames Smart dma = &hw->xfer_rdy;
5174df84e84SJames Smart dma->size = sizeof(struct fcp_txrdy) * hw->config.n_io;
5184df84e84SJames Smart dma->virt = dma_alloc_coherent(&efct->pci->dev,
519efac162aSChristoph Hellwig dma->size, &dma->phys, GFP_KERNEL);
5204df84e84SJames Smart if (!dma->virt)
5214df84e84SJames Smart return -ENOMEM;
5224df84e84SJames Smart }
5234df84e84SJames Smart xfer_virt = (uintptr_t)hw->xfer_rdy.virt;
5244df84e84SJames Smart xfer_phys = hw->xfer_rdy.phys;
5254df84e84SJames Smart
5264df84e84SJames Smart /* Initialize the pool of HW IO objects */
5274df84e84SJames Smart for (i = 0; i < hw->config.n_io; i++) {
5284df84e84SJames Smart struct hw_wq_callback *wqcb;
5294df84e84SJames Smart
5304df84e84SJames Smart io = hw->io[i];
5314df84e84SJames Smart
5324df84e84SJames Smart /* initialize IO fields */
5334df84e84SJames Smart io->hw = hw;
5344df84e84SJames Smart
5354df84e84SJames Smart /* Assign a WQE buff */
5364df84e84SJames Smart io->wqe.wqebuf = &hw->wqe_buffs[i * hw->sli.wqe_size];
5374df84e84SJames Smart
5384df84e84SJames Smart /* Allocate the request tag for this IO */
5394df84e84SJames Smart wqcb = efct_hw_reqtag_alloc(hw, efct_hw_wq_process_io, io);
5404df84e84SJames Smart if (!wqcb) {
5414df84e84SJames Smart efc_log_err(hw->os, "can't allocate request tag\n");
5424df84e84SJames Smart return -ENOSPC;
5434df84e84SJames Smart }
5444df84e84SJames Smart io->reqtag = wqcb->instance_index;
5454df84e84SJames Smart
5464df84e84SJames Smart /* Now for the fields that are initialized on each free */
5474df84e84SJames Smart efct_hw_init_free_io(io);
5484df84e84SJames Smart
5494df84e84SJames Smart /* The XB flag isn't cleared on IO free, so init to zero */
5504df84e84SJames Smart io->xbusy = 0;
5514df84e84SJames Smart
5524df84e84SJames Smart if (sli_resource_alloc(&hw->sli, SLI4_RSRC_XRI,
5534df84e84SJames Smart &io->indicator, &index)) {
5544df84e84SJames Smart efc_log_err(hw->os,
5554df84e84SJames Smart "sli_resource_alloc failed @ %d\n", i);
5564df84e84SJames Smart return -ENOMEM;
5574df84e84SJames Smart }
5584df84e84SJames Smart
5594df84e84SJames Smart if (new_alloc) {
5604df84e84SJames Smart dma = &io->def_sgl;
5614df84e84SJames Smart dma->size = hw->config.n_sgl *
5624df84e84SJames Smart sizeof(struct sli4_sge);
5634df84e84SJames Smart dma->virt = dma_alloc_coherent(&efct->pci->dev,
5644df84e84SJames Smart dma->size, &dma->phys,
565efac162aSChristoph Hellwig GFP_KERNEL);
5664df84e84SJames Smart if (!dma->virt) {
5674df84e84SJames Smart efc_log_err(hw->os, "dma_alloc fail %d\n", i);
5684df84e84SJames Smart memset(&io->def_sgl, 0,
5694df84e84SJames Smart sizeof(struct efc_dma));
5704df84e84SJames Smart return -ENOMEM;
5714df84e84SJames Smart }
5724df84e84SJames Smart }
5734df84e84SJames Smart io->def_sgl_count = hw->config.n_sgl;
5744df84e84SJames Smart io->sgl = &io->def_sgl;
5754df84e84SJames Smart io->sgl_count = io->def_sgl_count;
5764df84e84SJames Smart
5774df84e84SJames Smart if (hw->xfer_rdy.size) {
5784df84e84SJames Smart io->xfer_rdy.virt = (void *)xfer_virt;
5794df84e84SJames Smart io->xfer_rdy.phys = xfer_phys;
5804df84e84SJames Smart io->xfer_rdy.size = sizeof(struct fcp_txrdy);
5814df84e84SJames Smart
5824df84e84SJames Smart xfer_virt += sizeof(struct fcp_txrdy);
5834df84e84SJames Smart xfer_phys += sizeof(struct fcp_txrdy);
5844df84e84SJames Smart }
5854df84e84SJames Smart }
5864df84e84SJames Smart
5874df84e84SJames Smart return 0;
5884df84e84SJames Smart error:
5894df84e84SJames Smart for (i = 0; i < hw->config.n_io && hw->io[i]; i++) {
5904df84e84SJames Smart kfree(hw->io[i]);
5914df84e84SJames Smart hw->io[i] = NULL;
5924df84e84SJames Smart }
5934df84e84SJames Smart
5944df84e84SJames Smart kfree(hw->io);
5954df84e84SJames Smart hw->io = NULL;
5964df84e84SJames Smart
5974df84e84SJames Smart return -ENOMEM;
5984df84e84SJames Smart }
5994df84e84SJames Smart
6004df84e84SJames Smart static int
efct_hw_init_prereg_io(struct efct_hw * hw)6014df84e84SJames Smart efct_hw_init_prereg_io(struct efct_hw *hw)
6024df84e84SJames Smart {
6034df84e84SJames Smart u32 i, idx = 0;
6044df84e84SJames Smart struct efct_hw_io *io = NULL;
6054df84e84SJames Smart u8 cmd[SLI4_BMBX_SIZE];
6064df84e84SJames Smart int rc = 0;
6074df84e84SJames Smart u32 n_rem;
6084df84e84SJames Smart u32 n = 0;
6094df84e84SJames Smart u32 sgls_per_request = 256;
6104df84e84SJames Smart struct efc_dma **sgls = NULL;
6114df84e84SJames Smart struct efc_dma req;
6124df84e84SJames Smart struct efct *efct = hw->os;
6134df84e84SJames Smart
6144df84e84SJames Smart sgls = kmalloc_array(sgls_per_request, sizeof(*sgls), GFP_KERNEL);
6154df84e84SJames Smart if (!sgls)
6164df84e84SJames Smart return -ENOMEM;
6174df84e84SJames Smart
6184df84e84SJames Smart memset(&req, 0, sizeof(struct efc_dma));
6194df84e84SJames Smart req.size = 32 + sgls_per_request * 16;
6204df84e84SJames Smart req.virt = dma_alloc_coherent(&efct->pci->dev, req.size, &req.phys,
621efac162aSChristoph Hellwig GFP_KERNEL);
6224df84e84SJames Smart if (!req.virt) {
6234df84e84SJames Smart kfree(sgls);
6244df84e84SJames Smart return -ENOMEM;
6254df84e84SJames Smart }
6264df84e84SJames Smart
6274df84e84SJames Smart for (n_rem = hw->config.n_io; n_rem; n_rem -= n) {
6284df84e84SJames Smart /* Copy address of SGL's into local sgls[] array, break
6294df84e84SJames Smart * out if the xri is not contiguous.
6304df84e84SJames Smart */
6314df84e84SJames Smart u32 min = (sgls_per_request < n_rem) ? sgls_per_request : n_rem;
6324df84e84SJames Smart
6334df84e84SJames Smart for (n = 0; n < min; n++) {
6344df84e84SJames Smart /* Check that we have contiguous xri values */
6354df84e84SJames Smart if (n > 0) {
6364df84e84SJames Smart if (hw->io[idx + n]->indicator !=
6374df84e84SJames Smart hw->io[idx + n - 1]->indicator + 1)
6384df84e84SJames Smart break;
6394df84e84SJames Smart }
6404df84e84SJames Smart
6414df84e84SJames Smart sgls[n] = hw->io[idx + n]->sgl;
6424df84e84SJames Smart }
6434df84e84SJames Smart
6444df84e84SJames Smart if (sli_cmd_post_sgl_pages(&hw->sli, cmd,
6454df84e84SJames Smart hw->io[idx]->indicator, n, sgls, NULL, &req)) {
6464df84e84SJames Smart rc = -EIO;
6474df84e84SJames Smart break;
6484df84e84SJames Smart }
6494df84e84SJames Smart
6504df84e84SJames Smart rc = efct_hw_command(hw, cmd, EFCT_CMD_POLL, NULL, NULL);
6514df84e84SJames Smart if (rc) {
6524df84e84SJames Smart efc_log_err(hw->os, "SGL post failed, rc=%d\n", rc);
6534df84e84SJames Smart break;
6544df84e84SJames Smart }
6554df84e84SJames Smart
6564df84e84SJames Smart /* Add to tail if successful */
6574df84e84SJames Smart for (i = 0; i < n; i++, idx++) {
6584df84e84SJames Smart io = hw->io[idx];
6594df84e84SJames Smart io->state = EFCT_HW_IO_STATE_FREE;
6604df84e84SJames Smart INIT_LIST_HEAD(&io->list_entry);
6614df84e84SJames Smart list_add_tail(&io->list_entry, &hw->io_free);
6624df84e84SJames Smart }
6634df84e84SJames Smart }
6644df84e84SJames Smart
6654df84e84SJames Smart dma_free_coherent(&efct->pci->dev, req.size, req.virt, req.phys);
6664df84e84SJames Smart memset(&req, 0, sizeof(struct efc_dma));
6674df84e84SJames Smart kfree(sgls);
6684df84e84SJames Smart
6694df84e84SJames Smart return rc;
6704df84e84SJames Smart }
6714df84e84SJames Smart
6724df84e84SJames Smart static int
efct_hw_init_io(struct efct_hw * hw)6734df84e84SJames Smart efct_hw_init_io(struct efct_hw *hw)
6744df84e84SJames Smart {
6754df84e84SJames Smart u32 i, idx = 0;
6764df84e84SJames Smart bool prereg = false;
6774df84e84SJames Smart struct efct_hw_io *io = NULL;
6784df84e84SJames Smart int rc = 0;
6794df84e84SJames Smart
6804df84e84SJames Smart prereg = hw->sli.params.sgl_pre_registered;
6814df84e84SJames Smart
6824df84e84SJames Smart if (prereg)
6834df84e84SJames Smart return efct_hw_init_prereg_io(hw);
6844df84e84SJames Smart
6854df84e84SJames Smart for (i = 0; i < hw->config.n_io; i++, idx++) {
6864df84e84SJames Smart io = hw->io[idx];
6874df84e84SJames Smart io->state = EFCT_HW_IO_STATE_FREE;
6884df84e84SJames Smart INIT_LIST_HEAD(&io->list_entry);
6894df84e84SJames Smart list_add_tail(&io->list_entry, &hw->io_free);
6904df84e84SJames Smart }
6914df84e84SJames Smart
6924df84e84SJames Smart return rc;
6934df84e84SJames Smart }
6944df84e84SJames Smart
6954df84e84SJames Smart static int
efct_hw_config_set_fdt_xfer_hint(struct efct_hw * hw,u32 fdt_xfer_hint)6964df84e84SJames Smart efct_hw_config_set_fdt_xfer_hint(struct efct_hw *hw, u32 fdt_xfer_hint)
6974df84e84SJames Smart {
6984df84e84SJames Smart int rc = 0;
6994df84e84SJames Smart u8 buf[SLI4_BMBX_SIZE];
7004df84e84SJames Smart struct sli4_rqst_cmn_set_features_set_fdt_xfer_hint param;
7014df84e84SJames Smart
7024df84e84SJames Smart memset(¶m, 0, sizeof(param));
7034df84e84SJames Smart param.fdt_xfer_hint = cpu_to_le32(fdt_xfer_hint);
7044df84e84SJames Smart /* build the set_features command */
7054df84e84SJames Smart sli_cmd_common_set_features(&hw->sli, buf,
7064df84e84SJames Smart SLI4_SET_FEATURES_SET_FTD_XFER_HINT, sizeof(param), ¶m);
7074df84e84SJames Smart
7084df84e84SJames Smart rc = efct_hw_command(hw, buf, EFCT_CMD_POLL, NULL, NULL);
7094df84e84SJames Smart if (rc)
7104df84e84SJames Smart efc_log_warn(hw->os, "set FDT hint %d failed: %d\n",
7114df84e84SJames Smart fdt_xfer_hint, rc);
7124df84e84SJames Smart else
7134df84e84SJames Smart efc_log_info(hw->os, "Set FTD transfer hint to %d\n",
7144df84e84SJames Smart le32_to_cpu(param.fdt_xfer_hint));
7154df84e84SJames Smart
7164df84e84SJames Smart return rc;
7174df84e84SJames Smart }
7184df84e84SJames Smart
7194df84e84SJames Smart static int
efct_hw_config_rq(struct efct_hw * hw)7204df84e84SJames Smart efct_hw_config_rq(struct efct_hw *hw)
7214df84e84SJames Smart {
7224df84e84SJames Smart u32 min_rq_count, i, rc;
7234df84e84SJames Smart struct sli4_cmd_rq_cfg rq_cfg[SLI4_CMD_REG_FCFI_NUM_RQ_CFG];
7244df84e84SJames Smart u8 buf[SLI4_BMBX_SIZE];
7254df84e84SJames Smart
7264df84e84SJames Smart efc_log_info(hw->os, "using REG_FCFI standard\n");
7274df84e84SJames Smart
7284df84e84SJames Smart /*
7294df84e84SJames Smart * Set the filter match/mask values from hw's
7304df84e84SJames Smart * filter_def values
7314df84e84SJames Smart */
7324df84e84SJames Smart for (i = 0; i < SLI4_CMD_REG_FCFI_NUM_RQ_CFG; i++) {
7334df84e84SJames Smart rq_cfg[i].rq_id = cpu_to_le16(0xffff);
7344df84e84SJames Smart rq_cfg[i].r_ctl_mask = (u8)hw->config.filter_def[i];
7354df84e84SJames Smart rq_cfg[i].r_ctl_match = (u8)(hw->config.filter_def[i] >> 8);
7364df84e84SJames Smart rq_cfg[i].type_mask = (u8)(hw->config.filter_def[i] >> 16);
7374df84e84SJames Smart rq_cfg[i].type_match = (u8)(hw->config.filter_def[i] >> 24);
7384df84e84SJames Smart }
7394df84e84SJames Smart
7404df84e84SJames Smart /*
7414df84e84SJames Smart * Update the rq_id's of the FCF configuration
7424df84e84SJames Smart * (don't update more than the number of rq_cfg
7434df84e84SJames Smart * elements)
7444df84e84SJames Smart */
7454df84e84SJames Smart min_rq_count = (hw->hw_rq_count < SLI4_CMD_REG_FCFI_NUM_RQ_CFG) ?
7464df84e84SJames Smart hw->hw_rq_count : SLI4_CMD_REG_FCFI_NUM_RQ_CFG;
7474df84e84SJames Smart for (i = 0; i < min_rq_count; i++) {
7484df84e84SJames Smart struct hw_rq *rq = hw->hw_rq[i];
7494df84e84SJames Smart u32 j;
7504df84e84SJames Smart
7514df84e84SJames Smart for (j = 0; j < SLI4_CMD_REG_FCFI_NUM_RQ_CFG; j++) {
7524df84e84SJames Smart u32 mask = (rq->filter_mask != 0) ?
7534df84e84SJames Smart rq->filter_mask : 1;
7544df84e84SJames Smart
7554df84e84SJames Smart if (!(mask & (1U << j)))
7564df84e84SJames Smart continue;
7574df84e84SJames Smart
7584df84e84SJames Smart rq_cfg[i].rq_id = cpu_to_le16(rq->hdr->id);
7594df84e84SJames Smart efct_logfcfi(hw, j, i, rq->hdr->id);
7604df84e84SJames Smart }
7614df84e84SJames Smart }
7624df84e84SJames Smart
7634df84e84SJames Smart rc = -EIO;
7644df84e84SJames Smart if (!sli_cmd_reg_fcfi(&hw->sli, buf, 0, rq_cfg))
7654df84e84SJames Smart rc = efct_hw_command(hw, buf, EFCT_CMD_POLL, NULL, NULL);
7664df84e84SJames Smart
7674df84e84SJames Smart if (rc != 0) {
7684df84e84SJames Smart efc_log_err(hw->os, "FCFI registration failed\n");
7694df84e84SJames Smart return rc;
7704df84e84SJames Smart }
7714df84e84SJames Smart hw->fcf_indicator =
7724df84e84SJames Smart le16_to_cpu(((struct sli4_cmd_reg_fcfi *)buf)->fcfi);
7734df84e84SJames Smart
7744df84e84SJames Smart return rc;
7754df84e84SJames Smart }
7764df84e84SJames Smart
7774df84e84SJames Smart static int
efct_hw_config_mrq(struct efct_hw * hw,u8 mode,u16 fcf_index)7784df84e84SJames Smart efct_hw_config_mrq(struct efct_hw *hw, u8 mode, u16 fcf_index)
7794df84e84SJames Smart {
7804df84e84SJames Smart u8 buf[SLI4_BMBX_SIZE], mrq_bitmask = 0;
7814df84e84SJames Smart struct hw_rq *rq;
7824df84e84SJames Smart struct sli4_cmd_reg_fcfi_mrq *rsp = NULL;
7834df84e84SJames Smart struct sli4_cmd_rq_cfg rq_filter[SLI4_CMD_REG_FCFI_MRQ_NUM_RQ_CFG];
7844df84e84SJames Smart u32 rc, i;
7854df84e84SJames Smart
7864df84e84SJames Smart if (mode == SLI4_CMD_REG_FCFI_SET_FCFI_MODE)
7874df84e84SJames Smart goto issue_cmd;
7884df84e84SJames Smart
7894df84e84SJames Smart /* Set the filter match/mask values from hw's filter_def values */
7904df84e84SJames Smart for (i = 0; i < SLI4_CMD_REG_FCFI_NUM_RQ_CFG; i++) {
7914df84e84SJames Smart rq_filter[i].rq_id = cpu_to_le16(0xffff);
7924df84e84SJames Smart rq_filter[i].type_mask = (u8)hw->config.filter_def[i];
7934df84e84SJames Smart rq_filter[i].type_match = (u8)(hw->config.filter_def[i] >> 8);
7944df84e84SJames Smart rq_filter[i].r_ctl_mask = (u8)(hw->config.filter_def[i] >> 16);
7954df84e84SJames Smart rq_filter[i].r_ctl_match = (u8)(hw->config.filter_def[i] >> 24);
7964df84e84SJames Smart }
7974df84e84SJames Smart
7984df84e84SJames Smart rq = hw->hw_rq[0];
7994df84e84SJames Smart rq_filter[0].rq_id = cpu_to_le16(rq->hdr->id);
8004df84e84SJames Smart rq_filter[1].rq_id = cpu_to_le16(rq->hdr->id);
8014df84e84SJames Smart
8024df84e84SJames Smart mrq_bitmask = 0x2;
8034df84e84SJames Smart issue_cmd:
8044df84e84SJames Smart efc_log_debug(hw->os, "Issue reg_fcfi_mrq count:%d policy:%d mode:%d\n",
8054df84e84SJames Smart hw->hw_rq_count, hw->config.rq_selection_policy, mode);
8064df84e84SJames Smart /* Invoke REG_FCFI_MRQ */
8074df84e84SJames Smart rc = sli_cmd_reg_fcfi_mrq(&hw->sli, buf, mode, fcf_index,
8084df84e84SJames Smart hw->config.rq_selection_policy, mrq_bitmask,
8094df84e84SJames Smart hw->hw_mrq_count, rq_filter);
8104df84e84SJames Smart if (rc) {
8114df84e84SJames Smart efc_log_err(hw->os, "sli_cmd_reg_fcfi_mrq() failed\n");
8124df84e84SJames Smart return -EIO;
8134df84e84SJames Smart }
8144df84e84SJames Smart
8154df84e84SJames Smart rc = efct_hw_command(hw, buf, EFCT_CMD_POLL, NULL, NULL);
8164df84e84SJames Smart
8174df84e84SJames Smart rsp = (struct sli4_cmd_reg_fcfi_mrq *)buf;
8184df84e84SJames Smart
8194df84e84SJames Smart if ((rc) || (le16_to_cpu(rsp->hdr.status))) {
8204df84e84SJames Smart efc_log_err(hw->os, "FCFI MRQ reg failed. cmd=%x status=%x\n",
8214df84e84SJames Smart rsp->hdr.command, le16_to_cpu(rsp->hdr.status));
8224df84e84SJames Smart return -EIO;
8234df84e84SJames Smart }
8244df84e84SJames Smart
8254df84e84SJames Smart if (mode == SLI4_CMD_REG_FCFI_SET_FCFI_MODE)
8264df84e84SJames Smart hw->fcf_indicator = le16_to_cpu(rsp->fcfi);
8274df84e84SJames Smart
8284df84e84SJames Smart return 0;
8294df84e84SJames Smart }
8304df84e84SJames Smart
8314df84e84SJames Smart static void
efct_hw_queue_hash_add(struct efct_queue_hash * hash,u16 id,u16 index)8324df84e84SJames Smart efct_hw_queue_hash_add(struct efct_queue_hash *hash,
8334df84e84SJames Smart u16 id, u16 index)
8344df84e84SJames Smart {
8354df84e84SJames Smart u32 hash_index = id & (EFCT_HW_Q_HASH_SIZE - 1);
8364df84e84SJames Smart
8374df84e84SJames Smart /*
8384df84e84SJames Smart * Since the hash is always bigger than the number of queues, then we
8394df84e84SJames Smart * never have to worry about an infinite loop.
8404df84e84SJames Smart */
8414df84e84SJames Smart while (hash[hash_index].in_use)
8424df84e84SJames Smart hash_index = (hash_index + 1) & (EFCT_HW_Q_HASH_SIZE - 1);
8434df84e84SJames Smart
8444df84e84SJames Smart /* not used, claim the entry */
8454df84e84SJames Smart hash[hash_index].id = id;
8464df84e84SJames Smart hash[hash_index].in_use = true;
8474df84e84SJames Smart hash[hash_index].index = index;
8484df84e84SJames Smart }
8494df84e84SJames Smart
8504df84e84SJames Smart static int
efct_hw_config_sli_port_health_check(struct efct_hw * hw,u8 query,u8 enable)8514df84e84SJames Smart efct_hw_config_sli_port_health_check(struct efct_hw *hw, u8 query, u8 enable)
8524df84e84SJames Smart {
8534df84e84SJames Smart int rc = 0;
8544df84e84SJames Smart u8 buf[SLI4_BMBX_SIZE];
8554df84e84SJames Smart struct sli4_rqst_cmn_set_features_health_check param;
8564df84e84SJames Smart u32 health_check_flag = 0;
8574df84e84SJames Smart
8584df84e84SJames Smart memset(¶m, 0, sizeof(param));
8594df84e84SJames Smart
8604df84e84SJames Smart if (enable)
8614df84e84SJames Smart health_check_flag |= SLI4_RQ_HEALTH_CHECK_ENABLE;
8624df84e84SJames Smart
8634df84e84SJames Smart if (query)
8644df84e84SJames Smart health_check_flag |= SLI4_RQ_HEALTH_CHECK_QUERY;
8654df84e84SJames Smart
8664df84e84SJames Smart param.health_check_dword = cpu_to_le32(health_check_flag);
8674df84e84SJames Smart
8684df84e84SJames Smart /* build the set_features command */
8694df84e84SJames Smart sli_cmd_common_set_features(&hw->sli, buf,
8704df84e84SJames Smart SLI4_SET_FEATURES_SLI_PORT_HEALTH_CHECK, sizeof(param), ¶m);
8714df84e84SJames Smart
8724df84e84SJames Smart rc = efct_hw_command(hw, buf, EFCT_CMD_POLL, NULL, NULL);
8734df84e84SJames Smart if (rc)
8744df84e84SJames Smart efc_log_err(hw->os, "efct_hw_command returns %d\n", rc);
8754df84e84SJames Smart else
8764df84e84SJames Smart efc_log_debug(hw->os, "SLI Port Health Check is enabled\n");
8774df84e84SJames Smart
8784df84e84SJames Smart return rc;
8794df84e84SJames Smart }
8804df84e84SJames Smart
8814df84e84SJames Smart int
efct_hw_init(struct efct_hw * hw)8824df84e84SJames Smart efct_hw_init(struct efct_hw *hw)
8834df84e84SJames Smart {
8844df84e84SJames Smart int rc;
8854df84e84SJames Smart u32 i = 0;
8864df84e84SJames Smart int rem_count;
8874df84e84SJames Smart unsigned long flags = 0;
8884df84e84SJames Smart struct efct_hw_io *temp;
8894df84e84SJames Smart struct efc_dma *dma;
8904df84e84SJames Smart
8914df84e84SJames Smart /*
8924df84e84SJames Smart * Make sure the command lists are empty. If this is start-of-day,
8934df84e84SJames Smart * they'll be empty since they were just initialized in efct_hw_setup.
8944df84e84SJames Smart * If we've just gone through a reset, the command and command pending
8954df84e84SJames Smart * lists should have been cleaned up as part of the reset
8964df84e84SJames Smart * (efct_hw_reset()).
8974df84e84SJames Smart */
8984df84e84SJames Smart spin_lock_irqsave(&hw->cmd_lock, flags);
8994df84e84SJames Smart if (!list_empty(&hw->cmd_head)) {
9004df84e84SJames Smart spin_unlock_irqrestore(&hw->cmd_lock, flags);
9014df84e84SJames Smart efc_log_err(hw->os, "command found on cmd list\n");
9024df84e84SJames Smart return -EIO;
9034df84e84SJames Smart }
9044df84e84SJames Smart if (!list_empty(&hw->cmd_pending)) {
9054df84e84SJames Smart spin_unlock_irqrestore(&hw->cmd_lock, flags);
9064df84e84SJames Smart efc_log_err(hw->os, "command found on pending list\n");
9074df84e84SJames Smart return -EIO;
9084df84e84SJames Smart }
9094df84e84SJames Smart spin_unlock_irqrestore(&hw->cmd_lock, flags);
9104df84e84SJames Smart
9114df84e84SJames Smart /* Free RQ buffers if prevously allocated */
9124df84e84SJames Smart efct_hw_rx_free(hw);
9134df84e84SJames Smart
9144df84e84SJames Smart /*
9154df84e84SJames Smart * The IO queues must be initialized here for the reset case. The
9164df84e84SJames Smart * efct_hw_init_io() function will re-add the IOs to the free list.
9174df84e84SJames Smart * The cmd_head list should be OK since we free all entries in
9184df84e84SJames Smart * efct_hw_command_cancel() that is called in the efct_hw_reset().
9194df84e84SJames Smart */
9204df84e84SJames Smart
9214df84e84SJames Smart /* If we are in this function due to a reset, there may be stale items
9224df84e84SJames Smart * on lists that need to be removed. Clean them up.
9234df84e84SJames Smart */
9244df84e84SJames Smart rem_count = 0;
9254df84e84SJames Smart while ((!list_empty(&hw->io_wait_free))) {
9264df84e84SJames Smart rem_count++;
9274df84e84SJames Smart temp = list_first_entry(&hw->io_wait_free, struct efct_hw_io,
9284df84e84SJames Smart list_entry);
9294df84e84SJames Smart list_del_init(&temp->list_entry);
9304df84e84SJames Smart }
9314df84e84SJames Smart if (rem_count > 0)
9324df84e84SJames Smart efc_log_debug(hw->os, "rmvd %d items from io_wait_free list\n",
9334df84e84SJames Smart rem_count);
9344df84e84SJames Smart
9354df84e84SJames Smart rem_count = 0;
9364df84e84SJames Smart while ((!list_empty(&hw->io_inuse))) {
9374df84e84SJames Smart rem_count++;
9384df84e84SJames Smart temp = list_first_entry(&hw->io_inuse, struct efct_hw_io,
9394df84e84SJames Smart list_entry);
9404df84e84SJames Smart list_del_init(&temp->list_entry);
9414df84e84SJames Smart }
9424df84e84SJames Smart if (rem_count > 0)
9434df84e84SJames Smart efc_log_debug(hw->os, "rmvd %d items from io_inuse list\n",
9444df84e84SJames Smart rem_count);
9454df84e84SJames Smart
9464df84e84SJames Smart rem_count = 0;
9474df84e84SJames Smart while ((!list_empty(&hw->io_free))) {
9484df84e84SJames Smart rem_count++;
9494df84e84SJames Smart temp = list_first_entry(&hw->io_free, struct efct_hw_io,
9504df84e84SJames Smart list_entry);
9514df84e84SJames Smart list_del_init(&temp->list_entry);
9524df84e84SJames Smart }
9534df84e84SJames Smart if (rem_count > 0)
9544df84e84SJames Smart efc_log_debug(hw->os, "rmvd %d items from io_free list\n",
9554df84e84SJames Smart rem_count);
9564df84e84SJames Smart
9574df84e84SJames Smart /* If MRQ not required, Make sure we dont request feature. */
9584df84e84SJames Smart if (hw->config.n_rq == 1)
9594df84e84SJames Smart hw->sli.features &= (~SLI4_REQFEAT_MRQP);
9604df84e84SJames Smart
9614df84e84SJames Smart if (sli_init(&hw->sli)) {
9624df84e84SJames Smart efc_log_err(hw->os, "SLI failed to initialize\n");
9634df84e84SJames Smart return -EIO;
9644df84e84SJames Smart }
9654df84e84SJames Smart
9664df84e84SJames Smart if (hw->sliport_healthcheck) {
9674df84e84SJames Smart rc = efct_hw_config_sli_port_health_check(hw, 0, 1);
9684df84e84SJames Smart if (rc != 0) {
9694df84e84SJames Smart efc_log_err(hw->os, "Enable port Health check fail\n");
9704df84e84SJames Smart return rc;
9714df84e84SJames Smart }
9724df84e84SJames Smart }
9734df84e84SJames Smart
9744df84e84SJames Smart /*
9754df84e84SJames Smart * Set FDT transfer hint, only works on Lancer
9764df84e84SJames Smart */
9774df84e84SJames Smart if (hw->sli.if_type == SLI4_INTF_IF_TYPE_2) {
9784df84e84SJames Smart /*
9794df84e84SJames Smart * Non-fatal error. In particular, we can disregard failure to
9804df84e84SJames Smart * set EFCT_HW_FDT_XFER_HINT on devices with legacy firmware
9814df84e84SJames Smart * that do not support EFCT_HW_FDT_XFER_HINT feature.
9824df84e84SJames Smart */
9834df84e84SJames Smart efct_hw_config_set_fdt_xfer_hint(hw, EFCT_HW_FDT_XFER_HINT);
9844df84e84SJames Smart }
9854df84e84SJames Smart
9864df84e84SJames Smart /* zero the hashes */
9874df84e84SJames Smart memset(hw->cq_hash, 0, sizeof(hw->cq_hash));
9884df84e84SJames Smart efc_log_debug(hw->os, "Max CQs %d, hash size = %d\n",
9894df84e84SJames Smart EFCT_HW_MAX_NUM_CQ, EFCT_HW_Q_HASH_SIZE);
9904df84e84SJames Smart
9914df84e84SJames Smart memset(hw->rq_hash, 0, sizeof(hw->rq_hash));
9924df84e84SJames Smart efc_log_debug(hw->os, "Max RQs %d, hash size = %d\n",
9934df84e84SJames Smart EFCT_HW_MAX_NUM_RQ, EFCT_HW_Q_HASH_SIZE);
9944df84e84SJames Smart
9954df84e84SJames Smart memset(hw->wq_hash, 0, sizeof(hw->wq_hash));
9964df84e84SJames Smart efc_log_debug(hw->os, "Max WQs %d, hash size = %d\n",
9974df84e84SJames Smart EFCT_HW_MAX_NUM_WQ, EFCT_HW_Q_HASH_SIZE);
9984df84e84SJames Smart
9994df84e84SJames Smart rc = efct_hw_init_queues(hw);
10004df84e84SJames Smart if (rc)
10014df84e84SJames Smart return rc;
10024df84e84SJames Smart
10034df84e84SJames Smart rc = efct_hw_map_wq_cpu(hw);
10044df84e84SJames Smart if (rc)
10054df84e84SJames Smart return rc;
10064df84e84SJames Smart
10074df84e84SJames Smart /* Allocate and p_st RQ buffers */
10084df84e84SJames Smart rc = efct_hw_rx_allocate(hw);
10094df84e84SJames Smart if (rc) {
10104df84e84SJames Smart efc_log_err(hw->os, "rx_allocate failed\n");
10114df84e84SJames Smart return rc;
10124df84e84SJames Smart }
10134df84e84SJames Smart
10144df84e84SJames Smart rc = efct_hw_rx_post(hw);
10154df84e84SJames Smart if (rc) {
10164df84e84SJames Smart efc_log_err(hw->os, "WARNING - error posting RQ buffers\n");
10174df84e84SJames Smart return rc;
10184df84e84SJames Smart }
10194df84e84SJames Smart
10204df84e84SJames Smart if (hw->config.n_eq == 1) {
10214df84e84SJames Smart rc = efct_hw_config_rq(hw);
10224df84e84SJames Smart if (rc) {
10234df84e84SJames Smart efc_log_err(hw->os, "config rq failed %d\n", rc);
10244df84e84SJames Smart return rc;
10254df84e84SJames Smart }
10264df84e84SJames Smart } else {
10274df84e84SJames Smart rc = efct_hw_config_mrq(hw, SLI4_CMD_REG_FCFI_SET_FCFI_MODE, 0);
10284df84e84SJames Smart if (rc != 0) {
10294df84e84SJames Smart efc_log_err(hw->os, "REG_FCFI_MRQ FCFI reg failed\n");
10304df84e84SJames Smart return rc;
10314df84e84SJames Smart }
10324df84e84SJames Smart
10334df84e84SJames Smart rc = efct_hw_config_mrq(hw, SLI4_CMD_REG_FCFI_SET_MRQ_MODE, 0);
10344df84e84SJames Smart if (rc != 0) {
10354df84e84SJames Smart efc_log_err(hw->os, "REG_FCFI_MRQ MRQ reg failed\n");
10364df84e84SJames Smart return rc;
10374df84e84SJames Smart }
10384df84e84SJames Smart }
10394df84e84SJames Smart
10404df84e84SJames Smart /*
10414df84e84SJames Smart * Allocate the WQ request tag pool, if not previously allocated
10424df84e84SJames Smart * (the request tag value is 16 bits, thus the pool allocation size
10434df84e84SJames Smart * of 64k)
10444df84e84SJames Smart */
10454df84e84SJames Smart hw->wq_reqtag_pool = efct_hw_reqtag_pool_alloc(hw);
10464df84e84SJames Smart if (!hw->wq_reqtag_pool) {
104741962abaSWei Yongjun efc_log_err(hw->os, "efct_hw_reqtag_pool_alloc failed\n");
104841962abaSWei Yongjun return -ENOMEM;
10494df84e84SJames Smart }
10504df84e84SJames Smart
10514df84e84SJames Smart rc = efct_hw_setup_io(hw);
10524df84e84SJames Smart if (rc) {
10534df84e84SJames Smart efc_log_err(hw->os, "IO allocation failure\n");
10544df84e84SJames Smart return rc;
10554df84e84SJames Smart }
10564df84e84SJames Smart
10574df84e84SJames Smart rc = efct_hw_init_io(hw);
10584df84e84SJames Smart if (rc) {
10594df84e84SJames Smart efc_log_err(hw->os, "IO initialization failure\n");
10604df84e84SJames Smart return rc;
10614df84e84SJames Smart }
10624df84e84SJames Smart
10634df84e84SJames Smart dma = &hw->loop_map;
10644df84e84SJames Smart dma->size = SLI4_MIN_LOOP_MAP_BYTES;
10654df84e84SJames Smart dma->virt = dma_alloc_coherent(&hw->os->pci->dev, dma->size, &dma->phys,
1066efac162aSChristoph Hellwig GFP_KERNEL);
10674df84e84SJames Smart if (!dma->virt)
10684df84e84SJames Smart return -EIO;
10694df84e84SJames Smart
10704df84e84SJames Smart /*
10714df84e84SJames Smart * Arming the EQ allows (e.g.) interrupts when CQ completions write EQ
10724df84e84SJames Smart * entries
10734df84e84SJames Smart */
10744df84e84SJames Smart for (i = 0; i < hw->eq_count; i++)
10754df84e84SJames Smart sli_queue_arm(&hw->sli, &hw->eq[i], true);
10764df84e84SJames Smart
10774df84e84SJames Smart /*
10784df84e84SJames Smart * Initialize RQ hash
10794df84e84SJames Smart */
10804df84e84SJames Smart for (i = 0; i < hw->rq_count; i++)
10814df84e84SJames Smart efct_hw_queue_hash_add(hw->rq_hash, hw->rq[i].id, i);
10824df84e84SJames Smart
10834df84e84SJames Smart /*
10844df84e84SJames Smart * Initialize WQ hash
10854df84e84SJames Smart */
10864df84e84SJames Smart for (i = 0; i < hw->wq_count; i++)
10874df84e84SJames Smart efct_hw_queue_hash_add(hw->wq_hash, hw->wq[i].id, i);
10884df84e84SJames Smart
10894df84e84SJames Smart /*
10904df84e84SJames Smart * Arming the CQ allows (e.g.) MQ completions to write CQ entries
10914df84e84SJames Smart */
10924df84e84SJames Smart for (i = 0; i < hw->cq_count; i++) {
10934df84e84SJames Smart efct_hw_queue_hash_add(hw->cq_hash, hw->cq[i].id, i);
10944df84e84SJames Smart sli_queue_arm(&hw->sli, &hw->cq[i], true);
10954df84e84SJames Smart }
10964df84e84SJames Smart
10974df84e84SJames Smart /* Set RQ process limit*/
10984df84e84SJames Smart for (i = 0; i < hw->hw_rq_count; i++) {
10994df84e84SJames Smart struct hw_rq *rq = hw->hw_rq[i];
11004df84e84SJames Smart
11014df84e84SJames Smart hw->cq[rq->cq->instance].proc_limit = hw->config.n_io / 2;
11024df84e84SJames Smart }
11034df84e84SJames Smart
11044df84e84SJames Smart /* record the fact that the queues are functional */
11054df84e84SJames Smart hw->state = EFCT_HW_STATE_ACTIVE;
11064df84e84SJames Smart /*
11074df84e84SJames Smart * Allocate a HW IOs for send frame.
11084df84e84SJames Smart */
11094df84e84SJames Smart hw->hw_wq[0]->send_frame_io = efct_hw_io_alloc(hw);
11104df84e84SJames Smart if (!hw->hw_wq[0]->send_frame_io)
11114df84e84SJames Smart efc_log_err(hw->os, "alloc for send_frame_io failed\n");
11124df84e84SJames Smart
11134df84e84SJames Smart /* Initialize send frame sequence id */
11144df84e84SJames Smart atomic_set(&hw->send_frame_seq_id, 0);
11154df84e84SJames Smart
11164df84e84SJames Smart return 0;
11174df84e84SJames Smart }
11184df84e84SJames Smart
11194df84e84SJames Smart int
efct_hw_parse_filter(struct efct_hw * hw,void * value)11204df84e84SJames Smart efct_hw_parse_filter(struct efct_hw *hw, void *value)
11214df84e84SJames Smart {
11224df84e84SJames Smart int rc = 0;
1123*2a8a5a5dSVitaliy Shevtsov char *p = NULL, *pp = NULL;
11244df84e84SJames Smart char *token;
11254df84e84SJames Smart u32 idx = 0;
11264df84e84SJames Smart
11274df84e84SJames Smart for (idx = 0; idx < ARRAY_SIZE(hw->config.filter_def); idx++)
11284df84e84SJames Smart hw->config.filter_def[idx] = 0;
11294df84e84SJames Smart
11304df84e84SJames Smart p = kstrdup(value, GFP_KERNEL);
11314df84e84SJames Smart if (!p || !*p) {
11324df84e84SJames Smart efc_log_err(hw->os, "p is NULL\n");
11334df84e84SJames Smart return -ENOMEM;
11344df84e84SJames Smart }
1135*2a8a5a5dSVitaliy Shevtsov pp = p;
11364df84e84SJames Smart
11374df84e84SJames Smart idx = 0;
11384df84e84SJames Smart while ((token = strsep(&p, ",")) && *token) {
11394df84e84SJames Smart if (kstrtou32(token, 0, &hw->config.filter_def[idx++]))
11404df84e84SJames Smart efc_log_err(hw->os, "kstrtoint failed\n");
11414df84e84SJames Smart
11424df84e84SJames Smart if (!p || !*p)
11434df84e84SJames Smart break;
11444df84e84SJames Smart
11454df84e84SJames Smart if (idx == ARRAY_SIZE(hw->config.filter_def))
11464df84e84SJames Smart break;
11474df84e84SJames Smart }
1148*2a8a5a5dSVitaliy Shevtsov kfree(pp);
11494df84e84SJames Smart
11504df84e84SJames Smart return rc;
11514df84e84SJames Smart }
11524df84e84SJames Smart
11534df84e84SJames Smart u64
efct_get_wwnn(struct efct_hw * hw)11544df84e84SJames Smart efct_get_wwnn(struct efct_hw *hw)
11554df84e84SJames Smart {
11564df84e84SJames Smart struct sli4 *sli = &hw->sli;
11574df84e84SJames Smart u8 p[8];
11584df84e84SJames Smart
11594df84e84SJames Smart memcpy(p, sli->wwnn, sizeof(p));
11604df84e84SJames Smart return get_unaligned_be64(p);
11614df84e84SJames Smart }
11624df84e84SJames Smart
11634df84e84SJames Smart u64
efct_get_wwpn(struct efct_hw * hw)11644df84e84SJames Smart efct_get_wwpn(struct efct_hw *hw)
11654df84e84SJames Smart {
11664df84e84SJames Smart struct sli4 *sli = &hw->sli;
11674df84e84SJames Smart u8 p[8];
11684df84e84SJames Smart
11694df84e84SJames Smart memcpy(p, sli->wwpn, sizeof(p));
11704df84e84SJames Smart return get_unaligned_be64(p);
11714df84e84SJames Smart }
1172580c0255SJames Smart
1173580c0255SJames Smart static struct efc_hw_rq_buffer *
efct_hw_rx_buffer_alloc(struct efct_hw * hw,u32 rqindex,u32 count,u32 size)1174580c0255SJames Smart efct_hw_rx_buffer_alloc(struct efct_hw *hw, u32 rqindex, u32 count,
1175580c0255SJames Smart u32 size)
1176580c0255SJames Smart {
1177580c0255SJames Smart struct efct *efct = hw->os;
1178580c0255SJames Smart struct efc_hw_rq_buffer *rq_buf = NULL;
1179580c0255SJames Smart struct efc_hw_rq_buffer *prq;
1180580c0255SJames Smart u32 i;
1181580c0255SJames Smart
1182580c0255SJames Smart if (!count)
1183580c0255SJames Smart return NULL;
1184580c0255SJames Smart
1185580c0255SJames Smart rq_buf = kmalloc_array(count, sizeof(*rq_buf), GFP_KERNEL);
1186580c0255SJames Smart if (!rq_buf)
1187580c0255SJames Smart return NULL;
1188580c0255SJames Smart memset(rq_buf, 0, sizeof(*rq_buf) * count);
1189580c0255SJames Smart
1190580c0255SJames Smart for (i = 0, prq = rq_buf; i < count; i ++, prq++) {
1191580c0255SJames Smart prq->rqindex = rqindex;
1192580c0255SJames Smart prq->dma.size = size;
1193580c0255SJames Smart prq->dma.virt = dma_alloc_coherent(&efct->pci->dev,
1194580c0255SJames Smart prq->dma.size,
1195580c0255SJames Smart &prq->dma.phys,
1196efac162aSChristoph Hellwig GFP_KERNEL);
1197580c0255SJames Smart if (!prq->dma.virt) {
1198580c0255SJames Smart efc_log_err(hw->os, "DMA allocation failed\n");
1199580c0255SJames Smart kfree(rq_buf);
1200580c0255SJames Smart return NULL;
1201580c0255SJames Smart }
1202580c0255SJames Smart }
1203580c0255SJames Smart return rq_buf;
1204580c0255SJames Smart }
1205580c0255SJames Smart
1206580c0255SJames Smart static void
efct_hw_rx_buffer_free(struct efct_hw * hw,struct efc_hw_rq_buffer * rq_buf,u32 count)1207580c0255SJames Smart efct_hw_rx_buffer_free(struct efct_hw *hw,
1208580c0255SJames Smart struct efc_hw_rq_buffer *rq_buf,
1209580c0255SJames Smart u32 count)
1210580c0255SJames Smart {
1211580c0255SJames Smart struct efct *efct = hw->os;
1212580c0255SJames Smart u32 i;
1213580c0255SJames Smart struct efc_hw_rq_buffer *prq;
1214580c0255SJames Smart
1215580c0255SJames Smart if (rq_buf) {
1216580c0255SJames Smart for (i = 0, prq = rq_buf; i < count; i++, prq++) {
1217580c0255SJames Smart dma_free_coherent(&efct->pci->dev,
1218580c0255SJames Smart prq->dma.size, prq->dma.virt,
1219580c0255SJames Smart prq->dma.phys);
1220580c0255SJames Smart memset(&prq->dma, 0, sizeof(struct efc_dma));
1221580c0255SJames Smart }
1222580c0255SJames Smart
1223580c0255SJames Smart kfree(rq_buf);
1224580c0255SJames Smart }
1225580c0255SJames Smart }
1226580c0255SJames Smart
1227580c0255SJames Smart int
efct_hw_rx_allocate(struct efct_hw * hw)1228580c0255SJames Smart efct_hw_rx_allocate(struct efct_hw *hw)
1229580c0255SJames Smart {
1230580c0255SJames Smart struct efct *efct = hw->os;
1231580c0255SJames Smart u32 i;
1232580c0255SJames Smart int rc = 0;
1233580c0255SJames Smart u32 rqindex = 0;
1234580c0255SJames Smart u32 hdr_size = EFCT_HW_RQ_SIZE_HDR;
1235580c0255SJames Smart u32 payload_size = hw->config.rq_default_buffer_size;
1236580c0255SJames Smart
1237580c0255SJames Smart rqindex = 0;
1238580c0255SJames Smart
1239580c0255SJames Smart for (i = 0; i < hw->hw_rq_count; i++) {
1240580c0255SJames Smart struct hw_rq *rq = hw->hw_rq[i];
1241580c0255SJames Smart
1242580c0255SJames Smart /* Allocate header buffers */
1243580c0255SJames Smart rq->hdr_buf = efct_hw_rx_buffer_alloc(hw, rqindex,
1244580c0255SJames Smart rq->entry_count,
1245580c0255SJames Smart hdr_size);
1246580c0255SJames Smart if (!rq->hdr_buf) {
1247580c0255SJames Smart efc_log_err(efct, "rx_buffer_alloc hdr_buf failed\n");
1248580c0255SJames Smart rc = -EIO;
1249580c0255SJames Smart break;
1250580c0255SJames Smart }
1251580c0255SJames Smart
1252580c0255SJames Smart efc_log_debug(hw->os,
1253580c0255SJames Smart "rq[%2d] rq_id %02d header %4d by %4d bytes\n",
1254580c0255SJames Smart i, rq->hdr->id, rq->entry_count, hdr_size);
1255580c0255SJames Smart
1256580c0255SJames Smart rqindex++;
1257580c0255SJames Smart
1258580c0255SJames Smart /* Allocate payload buffers */
1259580c0255SJames Smart rq->payload_buf = efct_hw_rx_buffer_alloc(hw, rqindex,
1260580c0255SJames Smart rq->entry_count,
1261580c0255SJames Smart payload_size);
1262580c0255SJames Smart if (!rq->payload_buf) {
1263580c0255SJames Smart efc_log_err(efct, "rx_buffer_alloc fb_buf failed\n");
1264580c0255SJames Smart rc = -EIO;
1265580c0255SJames Smart break;
1266580c0255SJames Smart }
1267580c0255SJames Smart efc_log_debug(hw->os,
1268580c0255SJames Smart "rq[%2d] rq_id %02d default %4d by %4d bytes\n",
1269580c0255SJames Smart i, rq->data->id, rq->entry_count, payload_size);
1270580c0255SJames Smart rqindex++;
1271580c0255SJames Smart }
1272580c0255SJames Smart
1273580c0255SJames Smart return rc ? -EIO : 0;
1274580c0255SJames Smart }
1275580c0255SJames Smart
1276580c0255SJames Smart int
efct_hw_rx_post(struct efct_hw * hw)1277580c0255SJames Smart efct_hw_rx_post(struct efct_hw *hw)
1278580c0255SJames Smart {
1279580c0255SJames Smart u32 i;
1280580c0255SJames Smart u32 idx;
1281580c0255SJames Smart u32 rq_idx;
1282580c0255SJames Smart int rc = 0;
1283580c0255SJames Smart
1284580c0255SJames Smart if (!hw->seq_pool) {
1285580c0255SJames Smart u32 count = 0;
1286580c0255SJames Smart
1287580c0255SJames Smart for (i = 0; i < hw->hw_rq_count; i++)
1288580c0255SJames Smart count += hw->hw_rq[i]->entry_count;
1289580c0255SJames Smart
1290580c0255SJames Smart hw->seq_pool = kmalloc_array(count,
1291580c0255SJames Smart sizeof(struct efc_hw_sequence), GFP_KERNEL);
1292580c0255SJames Smart if (!hw->seq_pool)
1293580c0255SJames Smart return -ENOMEM;
1294580c0255SJames Smart }
1295580c0255SJames Smart
1296580c0255SJames Smart /*
1297580c0255SJames Smart * In RQ pair mode, we MUST post the header and payload buffer at the
1298580c0255SJames Smart * same time.
1299580c0255SJames Smart */
1300580c0255SJames Smart for (rq_idx = 0, idx = 0; rq_idx < hw->hw_rq_count; rq_idx++) {
1301580c0255SJames Smart struct hw_rq *rq = hw->hw_rq[rq_idx];
1302580c0255SJames Smart
1303580c0255SJames Smart for (i = 0; i < rq->entry_count - 1; i++) {
1304580c0255SJames Smart struct efc_hw_sequence *seq;
1305580c0255SJames Smart
1306580c0255SJames Smart seq = hw->seq_pool + idx;
1307580c0255SJames Smart idx++;
1308580c0255SJames Smart seq->header = &rq->hdr_buf[i];
1309580c0255SJames Smart seq->payload = &rq->payload_buf[i];
1310580c0255SJames Smart rc = efct_hw_sequence_free(hw, seq);
1311580c0255SJames Smart if (rc)
1312580c0255SJames Smart break;
1313580c0255SJames Smart }
1314580c0255SJames Smart if (rc)
1315580c0255SJames Smart break;
1316580c0255SJames Smart }
1317580c0255SJames Smart
1318580c0255SJames Smart if (rc && hw->seq_pool)
1319580c0255SJames Smart kfree(hw->seq_pool);
1320580c0255SJames Smart
1321580c0255SJames Smart return rc;
1322580c0255SJames Smart }
1323580c0255SJames Smart
1324580c0255SJames Smart void
efct_hw_rx_free(struct efct_hw * hw)1325580c0255SJames Smart efct_hw_rx_free(struct efct_hw *hw)
1326580c0255SJames Smart {
1327580c0255SJames Smart u32 i;
1328580c0255SJames Smart
1329580c0255SJames Smart /* Free hw_rq buffers */
1330580c0255SJames Smart for (i = 0; i < hw->hw_rq_count; i++) {
1331580c0255SJames Smart struct hw_rq *rq = hw->hw_rq[i];
1332580c0255SJames Smart
1333580c0255SJames Smart if (rq) {
1334580c0255SJames Smart efct_hw_rx_buffer_free(hw, rq->hdr_buf,
1335580c0255SJames Smart rq->entry_count);
1336580c0255SJames Smart rq->hdr_buf = NULL;
1337580c0255SJames Smart efct_hw_rx_buffer_free(hw, rq->payload_buf,
1338580c0255SJames Smart rq->entry_count);
1339580c0255SJames Smart rq->payload_buf = NULL;
1340580c0255SJames Smart }
1341580c0255SJames Smart }
1342580c0255SJames Smart }
1343580c0255SJames Smart
1344580c0255SJames Smart static int
efct_hw_cmd_submit_pending(struct efct_hw * hw)1345580c0255SJames Smart efct_hw_cmd_submit_pending(struct efct_hw *hw)
1346580c0255SJames Smart {
1347580c0255SJames Smart int rc = 0;
1348580c0255SJames Smart
1349580c0255SJames Smart /* Assumes lock held */
1350580c0255SJames Smart
1351580c0255SJames Smart /* Only submit MQE if there's room */
1352580c0255SJames Smart while (hw->cmd_head_count < (EFCT_HW_MQ_DEPTH - 1) &&
1353580c0255SJames Smart !list_empty(&hw->cmd_pending)) {
1354580c0255SJames Smart struct efct_command_ctx *ctx;
1355580c0255SJames Smart
1356580c0255SJames Smart ctx = list_first_entry(&hw->cmd_pending,
1357580c0255SJames Smart struct efct_command_ctx, list_entry);
1358580c0255SJames Smart if (!ctx)
1359580c0255SJames Smart break;
1360580c0255SJames Smart
1361580c0255SJames Smart list_del_init(&ctx->list_entry);
1362580c0255SJames Smart
1363580c0255SJames Smart list_add_tail(&ctx->list_entry, &hw->cmd_head);
1364580c0255SJames Smart hw->cmd_head_count++;
1365580c0255SJames Smart if (sli_mq_write(&hw->sli, hw->mq, ctx->buf) < 0) {
1366580c0255SJames Smart efc_log_debug(hw->os,
1367580c0255SJames Smart "sli_queue_write failed: %d\n", rc);
1368580c0255SJames Smart rc = -EIO;
1369580c0255SJames Smart break;
1370580c0255SJames Smart }
1371580c0255SJames Smart }
1372580c0255SJames Smart return rc;
1373580c0255SJames Smart }
1374580c0255SJames Smart
1375580c0255SJames Smart int
efct_hw_command(struct efct_hw * hw,u8 * cmd,u32 opts,void * cb,void * arg)1376580c0255SJames Smart efct_hw_command(struct efct_hw *hw, u8 *cmd, u32 opts, void *cb, void *arg)
1377580c0255SJames Smart {
1378580c0255SJames Smart int rc = -EIO;
1379580c0255SJames Smart unsigned long flags = 0;
1380580c0255SJames Smart void *bmbx = NULL;
1381580c0255SJames Smart
1382580c0255SJames Smart /*
1383580c0255SJames Smart * If the chip is in an error state (UE'd) then reject this mailbox
1384580c0255SJames Smart * command.
1385580c0255SJames Smart */
1386580c0255SJames Smart if (sli_fw_error_status(&hw->sli) > 0) {
1387580c0255SJames Smart efc_log_crit(hw->os, "Chip in an error state - reset needed\n");
1388580c0255SJames Smart efc_log_crit(hw->os, "status=%#x error1=%#x error2=%#x\n",
1389580c0255SJames Smart sli_reg_read_status(&hw->sli),
1390580c0255SJames Smart sli_reg_read_err1(&hw->sli),
1391580c0255SJames Smart sli_reg_read_err2(&hw->sli));
1392580c0255SJames Smart
1393580c0255SJames Smart return -EIO;
1394580c0255SJames Smart }
1395580c0255SJames Smart
1396580c0255SJames Smart /*
1397580c0255SJames Smart * Send a mailbox command to the hardware, and either wait for
1398580c0255SJames Smart * a completion (EFCT_CMD_POLL) or get an optional asynchronous
1399580c0255SJames Smart * completion (EFCT_CMD_NOWAIT).
1400580c0255SJames Smart */
1401580c0255SJames Smart
1402580c0255SJames Smart if (opts == EFCT_CMD_POLL) {
1403580c0255SJames Smart mutex_lock(&hw->bmbx_lock);
1404580c0255SJames Smart bmbx = hw->sli.bmbx.virt;
1405580c0255SJames Smart
1406580c0255SJames Smart memcpy(bmbx, cmd, SLI4_BMBX_SIZE);
1407580c0255SJames Smart
1408580c0255SJames Smart if (sli_bmbx_command(&hw->sli) == 0) {
1409580c0255SJames Smart rc = 0;
1410580c0255SJames Smart memcpy(cmd, bmbx, SLI4_BMBX_SIZE);
1411580c0255SJames Smart }
1412580c0255SJames Smart mutex_unlock(&hw->bmbx_lock);
1413580c0255SJames Smart } else if (opts == EFCT_CMD_NOWAIT) {
1414580c0255SJames Smart struct efct_command_ctx *ctx = NULL;
1415580c0255SJames Smart
1416580c0255SJames Smart if (hw->state != EFCT_HW_STATE_ACTIVE) {
1417580c0255SJames Smart efc_log_err(hw->os, "Can't send command, HW state=%d\n",
1418580c0255SJames Smart hw->state);
1419580c0255SJames Smart return -EIO;
1420580c0255SJames Smart }
1421580c0255SJames Smart
1422580c0255SJames Smart ctx = mempool_alloc(hw->cmd_ctx_pool, GFP_ATOMIC);
1423580c0255SJames Smart if (!ctx)
1424580c0255SJames Smart return -ENOSPC;
1425580c0255SJames Smart
1426580c0255SJames Smart memset(ctx, 0, sizeof(struct efct_command_ctx));
1427580c0255SJames Smart
1428580c0255SJames Smart if (cb) {
1429580c0255SJames Smart ctx->cb = cb;
1430580c0255SJames Smart ctx->arg = arg;
1431580c0255SJames Smart }
1432580c0255SJames Smart
1433580c0255SJames Smart memcpy(ctx->buf, cmd, SLI4_BMBX_SIZE);
1434580c0255SJames Smart ctx->ctx = hw;
1435580c0255SJames Smart
1436580c0255SJames Smart spin_lock_irqsave(&hw->cmd_lock, flags);
1437580c0255SJames Smart
1438580c0255SJames Smart /* Add to pending list */
1439580c0255SJames Smart INIT_LIST_HEAD(&ctx->list_entry);
1440580c0255SJames Smart list_add_tail(&ctx->list_entry, &hw->cmd_pending);
1441580c0255SJames Smart
1442580c0255SJames Smart /* Submit as much of the pending list as we can */
1443580c0255SJames Smart rc = efct_hw_cmd_submit_pending(hw);
1444580c0255SJames Smart
1445580c0255SJames Smart spin_unlock_irqrestore(&hw->cmd_lock, flags);
1446580c0255SJames Smart }
1447580c0255SJames Smart
1448580c0255SJames Smart return rc;
1449580c0255SJames Smart }
1450580c0255SJames Smart
1451580c0255SJames Smart static int
efct_hw_command_process(struct efct_hw * hw,int status,u8 * mqe,size_t size)1452580c0255SJames Smart efct_hw_command_process(struct efct_hw *hw, int status, u8 *mqe,
1453580c0255SJames Smart size_t size)
1454580c0255SJames Smart {
1455580c0255SJames Smart struct efct_command_ctx *ctx = NULL;
1456580c0255SJames Smart unsigned long flags = 0;
1457580c0255SJames Smart
1458580c0255SJames Smart spin_lock_irqsave(&hw->cmd_lock, flags);
1459580c0255SJames Smart if (!list_empty(&hw->cmd_head)) {
1460580c0255SJames Smart ctx = list_first_entry(&hw->cmd_head,
1461580c0255SJames Smart struct efct_command_ctx, list_entry);
1462580c0255SJames Smart list_del_init(&ctx->list_entry);
1463580c0255SJames Smart }
1464580c0255SJames Smart if (!ctx) {
1465580c0255SJames Smart efc_log_err(hw->os, "no command context\n");
1466580c0255SJames Smart spin_unlock_irqrestore(&hw->cmd_lock, flags);
1467580c0255SJames Smart return -EIO;
1468580c0255SJames Smart }
1469580c0255SJames Smart
1470580c0255SJames Smart hw->cmd_head_count--;
1471580c0255SJames Smart
1472580c0255SJames Smart /* Post any pending requests */
1473580c0255SJames Smart efct_hw_cmd_submit_pending(hw);
1474580c0255SJames Smart
1475580c0255SJames Smart spin_unlock_irqrestore(&hw->cmd_lock, flags);
1476580c0255SJames Smart
1477580c0255SJames Smart if (ctx->cb) {
1478580c0255SJames Smart memcpy(ctx->buf, mqe, size);
1479580c0255SJames Smart ctx->cb(hw, status, ctx->buf, ctx->arg);
1480580c0255SJames Smart }
1481580c0255SJames Smart
1482580c0255SJames Smart mempool_free(ctx, hw->cmd_ctx_pool);
1483580c0255SJames Smart
1484580c0255SJames Smart return 0;
1485580c0255SJames Smart }
1486580c0255SJames Smart
1487580c0255SJames Smart static int
efct_hw_mq_process(struct efct_hw * hw,int status,struct sli4_queue * mq)1488580c0255SJames Smart efct_hw_mq_process(struct efct_hw *hw,
1489580c0255SJames Smart int status, struct sli4_queue *mq)
1490580c0255SJames Smart {
1491580c0255SJames Smart u8 mqe[SLI4_BMBX_SIZE];
1492580c0255SJames Smart int rc;
1493580c0255SJames Smart
1494580c0255SJames Smart rc = sli_mq_read(&hw->sli, mq, mqe);
1495580c0255SJames Smart if (!rc)
1496580c0255SJames Smart rc = efct_hw_command_process(hw, status, mqe, mq->size);
1497580c0255SJames Smart
1498580c0255SJames Smart return rc;
1499580c0255SJames Smart }
1500580c0255SJames Smart
1501580c0255SJames Smart static int
efct_hw_command_cancel(struct efct_hw * hw)1502580c0255SJames Smart efct_hw_command_cancel(struct efct_hw *hw)
1503580c0255SJames Smart {
1504580c0255SJames Smart unsigned long flags = 0;
1505580c0255SJames Smart int rc = 0;
1506580c0255SJames Smart
1507580c0255SJames Smart spin_lock_irqsave(&hw->cmd_lock, flags);
1508580c0255SJames Smart
1509580c0255SJames Smart /*
1510580c0255SJames Smart * Manually clean up remaining commands. Note: since this calls
1511580c0255SJames Smart * efct_hw_command_process(), we'll also process the cmd_pending
1512580c0255SJames Smart * list, so no need to manually clean that out.
1513580c0255SJames Smart */
1514580c0255SJames Smart while (!list_empty(&hw->cmd_head)) {
1515580c0255SJames Smart u8 mqe[SLI4_BMBX_SIZE] = { 0 };
1516580c0255SJames Smart struct efct_command_ctx *ctx;
1517580c0255SJames Smart
1518580c0255SJames Smart ctx = list_first_entry(&hw->cmd_head,
1519580c0255SJames Smart struct efct_command_ctx, list_entry);
1520580c0255SJames Smart
1521580c0255SJames Smart efc_log_debug(hw->os, "hung command %08x\n",
15220d7be7a8SNathan Chancellor !ctx ? U32_MAX : *((u32 *)ctx->buf));
1523580c0255SJames Smart spin_unlock_irqrestore(&hw->cmd_lock, flags);
1524580c0255SJames Smart rc = efct_hw_command_process(hw, -1, mqe, SLI4_BMBX_SIZE);
1525580c0255SJames Smart spin_lock_irqsave(&hw->cmd_lock, flags);
1526580c0255SJames Smart }
1527580c0255SJames Smart
1528580c0255SJames Smart spin_unlock_irqrestore(&hw->cmd_lock, flags);
1529580c0255SJames Smart
1530580c0255SJames Smart return rc;
1531580c0255SJames Smart }
1532580c0255SJames Smart
1533580c0255SJames Smart static void
efct_mbox_rsp_cb(struct efct_hw * hw,int status,u8 * mqe,void * arg)1534580c0255SJames Smart efct_mbox_rsp_cb(struct efct_hw *hw, int status, u8 *mqe, void *arg)
1535580c0255SJames Smart {
1536580c0255SJames Smart struct efct_mbox_rqst_ctx *ctx = arg;
1537580c0255SJames Smart
1538580c0255SJames Smart if (ctx) {
1539580c0255SJames Smart if (ctx->callback)
1540580c0255SJames Smart (*ctx->callback)(hw->os->efcport, status, mqe,
1541580c0255SJames Smart ctx->arg);
1542580c0255SJames Smart
1543580c0255SJames Smart mempool_free(ctx, hw->mbox_rqst_pool);
1544580c0255SJames Smart }
1545580c0255SJames Smart }
1546580c0255SJames Smart
1547580c0255SJames Smart int
efct_issue_mbox_rqst(void * base,void * cmd,void * cb,void * arg)1548580c0255SJames Smart efct_issue_mbox_rqst(void *base, void *cmd, void *cb, void *arg)
1549580c0255SJames Smart {
1550580c0255SJames Smart struct efct_mbox_rqst_ctx *ctx;
1551580c0255SJames Smart struct efct *efct = base;
1552580c0255SJames Smart struct efct_hw *hw = &efct->hw;
1553580c0255SJames Smart int rc;
1554580c0255SJames Smart
1555580c0255SJames Smart /*
1556580c0255SJames Smart * Allocate a callback context (which includes the mbox cmd buffer),
1557580c0255SJames Smart * we need this to be persistent as the mbox cmd submission may be
1558580c0255SJames Smart * queued and executed later execution.
1559580c0255SJames Smart */
1560580c0255SJames Smart ctx = mempool_alloc(hw->mbox_rqst_pool, GFP_ATOMIC);
1561580c0255SJames Smart if (!ctx)
1562580c0255SJames Smart return -EIO;
1563580c0255SJames Smart
1564580c0255SJames Smart ctx->callback = cb;
1565580c0255SJames Smart ctx->arg = arg;
1566580c0255SJames Smart
1567580c0255SJames Smart rc = efct_hw_command(hw, cmd, EFCT_CMD_NOWAIT, efct_mbox_rsp_cb, ctx);
1568580c0255SJames Smart if (rc) {
1569580c0255SJames Smart efc_log_err(efct, "issue mbox rqst failure rc:%d\n", rc);
1570580c0255SJames Smart mempool_free(ctx, hw->mbox_rqst_pool);
1571580c0255SJames Smart return -EIO;
1572580c0255SJames Smart }
1573580c0255SJames Smart
1574580c0255SJames Smart return 0;
1575580c0255SJames Smart }
157663de5132SJames Smart
157763de5132SJames Smart static inline struct efct_hw_io *
_efct_hw_io_alloc(struct efct_hw * hw)157863de5132SJames Smart _efct_hw_io_alloc(struct efct_hw *hw)
157963de5132SJames Smart {
158063de5132SJames Smart struct efct_hw_io *io = NULL;
158163de5132SJames Smart
158263de5132SJames Smart if (!list_empty(&hw->io_free)) {
158363de5132SJames Smart io = list_first_entry(&hw->io_free, struct efct_hw_io,
158463de5132SJames Smart list_entry);
158563de5132SJames Smart list_del(&io->list_entry);
158663de5132SJames Smart }
158763de5132SJames Smart if (io) {
158863de5132SJames Smart INIT_LIST_HEAD(&io->list_entry);
158963de5132SJames Smart list_add_tail(&io->list_entry, &hw->io_inuse);
159063de5132SJames Smart io->state = EFCT_HW_IO_STATE_INUSE;
159163de5132SJames Smart io->abort_reqtag = U32_MAX;
159263de5132SJames Smart io->wq = hw->wq_cpu_array[raw_smp_processor_id()];
159363de5132SJames Smart if (!io->wq) {
159463de5132SJames Smart efc_log_err(hw->os, "WQ not assigned for cpu:%d\n",
159563de5132SJames Smart raw_smp_processor_id());
159663de5132SJames Smart io->wq = hw->hw_wq[0];
159763de5132SJames Smart }
159863de5132SJames Smart kref_init(&io->ref);
159963de5132SJames Smart io->release = efct_hw_io_free_internal;
160063de5132SJames Smart } else {
160163de5132SJames Smart atomic_add(1, &hw->io_alloc_failed_count);
160263de5132SJames Smart }
160363de5132SJames Smart
160463de5132SJames Smart return io;
160563de5132SJames Smart }
160663de5132SJames Smart
160763de5132SJames Smart struct efct_hw_io *
efct_hw_io_alloc(struct efct_hw * hw)160863de5132SJames Smart efct_hw_io_alloc(struct efct_hw *hw)
160963de5132SJames Smart {
161063de5132SJames Smart struct efct_hw_io *io = NULL;
161163de5132SJames Smart unsigned long flags = 0;
161263de5132SJames Smart
161363de5132SJames Smart spin_lock_irqsave(&hw->io_lock, flags);
161463de5132SJames Smart io = _efct_hw_io_alloc(hw);
161563de5132SJames Smart spin_unlock_irqrestore(&hw->io_lock, flags);
161663de5132SJames Smart
161763de5132SJames Smart return io;
161863de5132SJames Smart }
161963de5132SJames Smart
162063de5132SJames Smart static void
efct_hw_io_free_move_correct_list(struct efct_hw * hw,struct efct_hw_io * io)162163de5132SJames Smart efct_hw_io_free_move_correct_list(struct efct_hw *hw,
162263de5132SJames Smart struct efct_hw_io *io)
162363de5132SJames Smart {
162463de5132SJames Smart /*
162563de5132SJames Smart * When an IO is freed, depending on the exchange busy flag,
162663de5132SJames Smart * move it to the correct list.
162763de5132SJames Smart */
162863de5132SJames Smart if (io->xbusy) {
162963de5132SJames Smart /*
163063de5132SJames Smart * add to wait_free list and wait for XRI_ABORTED CQEs to clean
163163de5132SJames Smart * up
163263de5132SJames Smart */
163363de5132SJames Smart INIT_LIST_HEAD(&io->list_entry);
163463de5132SJames Smart list_add_tail(&io->list_entry, &hw->io_wait_free);
163563de5132SJames Smart io->state = EFCT_HW_IO_STATE_WAIT_FREE;
163663de5132SJames Smart } else {
163763de5132SJames Smart /* IO not busy, add to free list */
163863de5132SJames Smart INIT_LIST_HEAD(&io->list_entry);
163963de5132SJames Smart list_add_tail(&io->list_entry, &hw->io_free);
164063de5132SJames Smart io->state = EFCT_HW_IO_STATE_FREE;
164163de5132SJames Smart }
164263de5132SJames Smart }
164363de5132SJames Smart
164463de5132SJames Smart static inline void
efct_hw_io_free_common(struct efct_hw * hw,struct efct_hw_io * io)164563de5132SJames Smart efct_hw_io_free_common(struct efct_hw *hw, struct efct_hw_io *io)
164663de5132SJames Smart {
164763de5132SJames Smart /* initialize IO fields */
164863de5132SJames Smart efct_hw_init_free_io(io);
164963de5132SJames Smart
165063de5132SJames Smart /* Restore default SGL */
165163de5132SJames Smart efct_hw_io_restore_sgl(hw, io);
165263de5132SJames Smart }
165363de5132SJames Smart
165463de5132SJames Smart void
efct_hw_io_free_internal(struct kref * arg)165563de5132SJames Smart efct_hw_io_free_internal(struct kref *arg)
165663de5132SJames Smart {
165763de5132SJames Smart unsigned long flags = 0;
165863de5132SJames Smart struct efct_hw_io *io = container_of(arg, struct efct_hw_io, ref);
165963de5132SJames Smart struct efct_hw *hw = io->hw;
166063de5132SJames Smart
166163de5132SJames Smart /* perform common cleanup */
166263de5132SJames Smart efct_hw_io_free_common(hw, io);
166363de5132SJames Smart
166463de5132SJames Smart spin_lock_irqsave(&hw->io_lock, flags);
166563de5132SJames Smart /* remove from in-use list */
166663de5132SJames Smart if (!list_empty(&io->list_entry) && !list_empty(&hw->io_inuse)) {
166763de5132SJames Smart list_del_init(&io->list_entry);
166863de5132SJames Smart efct_hw_io_free_move_correct_list(hw, io);
166963de5132SJames Smart }
167063de5132SJames Smart spin_unlock_irqrestore(&hw->io_lock, flags);
167163de5132SJames Smart }
167263de5132SJames Smart
167363de5132SJames Smart int
efct_hw_io_free(struct efct_hw * hw,struct efct_hw_io * io)167463de5132SJames Smart efct_hw_io_free(struct efct_hw *hw, struct efct_hw_io *io)
167563de5132SJames Smart {
167663de5132SJames Smart return kref_put(&io->ref, io->release);
167763de5132SJames Smart }
167863de5132SJames Smart
167963de5132SJames Smart struct efct_hw_io *
efct_hw_io_lookup(struct efct_hw * hw,u32 xri)168063de5132SJames Smart efct_hw_io_lookup(struct efct_hw *hw, u32 xri)
168163de5132SJames Smart {
168263de5132SJames Smart u32 ioindex;
168363de5132SJames Smart
168463de5132SJames Smart ioindex = xri - hw->sli.ext[SLI4_RSRC_XRI].base[0];
168563de5132SJames Smart return hw->io[ioindex];
168663de5132SJames Smart }
168763de5132SJames Smart
168863de5132SJames Smart int
efct_hw_io_init_sges(struct efct_hw * hw,struct efct_hw_io * io,enum efct_hw_io_type type)168963de5132SJames Smart efct_hw_io_init_sges(struct efct_hw *hw, struct efct_hw_io *io,
169063de5132SJames Smart enum efct_hw_io_type type)
169163de5132SJames Smart {
169263de5132SJames Smart struct sli4_sge *data = NULL;
169363de5132SJames Smart u32 i = 0;
169463de5132SJames Smart u32 skips = 0;
169563de5132SJames Smart u32 sge_flags = 0;
169663de5132SJames Smart
169763de5132SJames Smart if (!io) {
169863de5132SJames Smart efc_log_err(hw->os, "bad parameter hw=%p io=%p\n", hw, io);
169963de5132SJames Smart return -EIO;
170063de5132SJames Smart }
170163de5132SJames Smart
170263de5132SJames Smart /* Clear / reset the scatter-gather list */
170363de5132SJames Smart io->sgl = &io->def_sgl;
170463de5132SJames Smart io->sgl_count = io->def_sgl_count;
170563de5132SJames Smart io->first_data_sge = 0;
170663de5132SJames Smart
170763de5132SJames Smart memset(io->sgl->virt, 0, 2 * sizeof(struct sli4_sge));
170863de5132SJames Smart io->n_sge = 0;
170963de5132SJames Smart io->sge_offset = 0;
171063de5132SJames Smart
171163de5132SJames Smart io->type = type;
171263de5132SJames Smart
171363de5132SJames Smart data = io->sgl->virt;
171463de5132SJames Smart
171563de5132SJames Smart /*
171663de5132SJames Smart * Some IO types have underlying hardware requirements on the order
171763de5132SJames Smart * of SGEs. Process all special entries here.
171863de5132SJames Smart */
171963de5132SJames Smart switch (type) {
172063de5132SJames Smart case EFCT_HW_IO_TARGET_WRITE:
172163de5132SJames Smart
172263de5132SJames Smart /* populate host resident XFER_RDY buffer */
172363de5132SJames Smart sge_flags = le32_to_cpu(data->dw2_flags);
172463de5132SJames Smart sge_flags &= (~SLI4_SGE_TYPE_MASK);
172563de5132SJames Smart sge_flags |= (SLI4_SGE_TYPE_DATA << SLI4_SGE_TYPE_SHIFT);
172663de5132SJames Smart data->buffer_address_high =
172763de5132SJames Smart cpu_to_le32(upper_32_bits(io->xfer_rdy.phys));
172863de5132SJames Smart data->buffer_address_low =
172963de5132SJames Smart cpu_to_le32(lower_32_bits(io->xfer_rdy.phys));
173063de5132SJames Smart data->buffer_length = cpu_to_le32(io->xfer_rdy.size);
173163de5132SJames Smart data->dw2_flags = cpu_to_le32(sge_flags);
173263de5132SJames Smart data++;
173363de5132SJames Smart
173463de5132SJames Smart skips = EFCT_TARGET_WRITE_SKIPS;
173563de5132SJames Smart
173663de5132SJames Smart io->n_sge = 1;
173763de5132SJames Smart break;
173863de5132SJames Smart case EFCT_HW_IO_TARGET_READ:
173963de5132SJames Smart /*
174063de5132SJames Smart * For FCP_TSEND64, the first 2 entries are SKIP SGE's
174163de5132SJames Smart */
174263de5132SJames Smart skips = EFCT_TARGET_READ_SKIPS;
174363de5132SJames Smart break;
174463de5132SJames Smart case EFCT_HW_IO_TARGET_RSP:
174563de5132SJames Smart /*
174663de5132SJames Smart * No skips, etc. for FCP_TRSP64
174763de5132SJames Smart */
174863de5132SJames Smart break;
174963de5132SJames Smart default:
175063de5132SJames Smart efc_log_err(hw->os, "unsupported IO type %#x\n", type);
175163de5132SJames Smart return -EIO;
175263de5132SJames Smart }
175363de5132SJames Smart
175463de5132SJames Smart /*
175563de5132SJames Smart * Write skip entries
175663de5132SJames Smart */
175763de5132SJames Smart for (i = 0; i < skips; i++) {
175863de5132SJames Smart sge_flags = le32_to_cpu(data->dw2_flags);
175963de5132SJames Smart sge_flags &= (~SLI4_SGE_TYPE_MASK);
176063de5132SJames Smart sge_flags |= (SLI4_SGE_TYPE_SKIP << SLI4_SGE_TYPE_SHIFT);
176163de5132SJames Smart data->dw2_flags = cpu_to_le32(sge_flags);
176263de5132SJames Smart data++;
176363de5132SJames Smart }
176463de5132SJames Smart
176563de5132SJames Smart io->n_sge += skips;
176663de5132SJames Smart
176763de5132SJames Smart /*
176863de5132SJames Smart * Set last
176963de5132SJames Smart */
177063de5132SJames Smart sge_flags = le32_to_cpu(data->dw2_flags);
177163de5132SJames Smart sge_flags |= SLI4_SGE_LAST;
177263de5132SJames Smart data->dw2_flags = cpu_to_le32(sge_flags);
177363de5132SJames Smart
177463de5132SJames Smart return 0;
177563de5132SJames Smart }
177663de5132SJames Smart
177763de5132SJames Smart int
efct_hw_io_add_sge(struct efct_hw * hw,struct efct_hw_io * io,uintptr_t addr,u32 length)177863de5132SJames Smart efct_hw_io_add_sge(struct efct_hw *hw, struct efct_hw_io *io,
177963de5132SJames Smart uintptr_t addr, u32 length)
178063de5132SJames Smart {
178163de5132SJames Smart struct sli4_sge *data = NULL;
178263de5132SJames Smart u32 sge_flags = 0;
178363de5132SJames Smart
178463de5132SJames Smart if (!io || !addr || !length) {
178563de5132SJames Smart efc_log_err(hw->os,
178663de5132SJames Smart "bad parameter hw=%p io=%p addr=%lx length=%u\n",
178763de5132SJames Smart hw, io, addr, length);
178863de5132SJames Smart return -EIO;
178963de5132SJames Smart }
179063de5132SJames Smart
179163de5132SJames Smart if (length > hw->sli.sge_supported_length) {
179263de5132SJames Smart efc_log_err(hw->os,
179363de5132SJames Smart "length of SGE %d bigger than allowed %d\n",
179463de5132SJames Smart length, hw->sli.sge_supported_length);
179563de5132SJames Smart return -EIO;
179663de5132SJames Smart }
179763de5132SJames Smart
179863de5132SJames Smart data = io->sgl->virt;
179963de5132SJames Smart data += io->n_sge;
180063de5132SJames Smart
180163de5132SJames Smart sge_flags = le32_to_cpu(data->dw2_flags);
180263de5132SJames Smart sge_flags &= ~SLI4_SGE_TYPE_MASK;
180363de5132SJames Smart sge_flags |= SLI4_SGE_TYPE_DATA << SLI4_SGE_TYPE_SHIFT;
180463de5132SJames Smart sge_flags &= ~SLI4_SGE_DATA_OFFSET_MASK;
180563de5132SJames Smart sge_flags |= SLI4_SGE_DATA_OFFSET_MASK & io->sge_offset;
180663de5132SJames Smart
180763de5132SJames Smart data->buffer_address_high = cpu_to_le32(upper_32_bits(addr));
180863de5132SJames Smart data->buffer_address_low = cpu_to_le32(lower_32_bits(addr));
180963de5132SJames Smart data->buffer_length = cpu_to_le32(length);
181063de5132SJames Smart
181163de5132SJames Smart /*
181263de5132SJames Smart * Always assume this is the last entry and mark as such.
181363de5132SJames Smart * If this is not the first entry unset the "last SGE"
181463de5132SJames Smart * indication for the previous entry
181563de5132SJames Smart */
181663de5132SJames Smart sge_flags |= SLI4_SGE_LAST;
181763de5132SJames Smart data->dw2_flags = cpu_to_le32(sge_flags);
181863de5132SJames Smart
181963de5132SJames Smart if (io->n_sge) {
182063de5132SJames Smart sge_flags = le32_to_cpu(data[-1].dw2_flags);
182163de5132SJames Smart sge_flags &= ~SLI4_SGE_LAST;
182263de5132SJames Smart data[-1].dw2_flags = cpu_to_le32(sge_flags);
182363de5132SJames Smart }
182463de5132SJames Smart
182563de5132SJames Smart /* Set first_data_bde if not previously set */
182663de5132SJames Smart if (io->first_data_sge == 0)
182763de5132SJames Smart io->first_data_sge = io->n_sge;
182863de5132SJames Smart
182963de5132SJames Smart io->sge_offset += length;
183063de5132SJames Smart io->n_sge++;
183163de5132SJames Smart
183263de5132SJames Smart return 0;
183363de5132SJames Smart }
183463de5132SJames Smart
183563de5132SJames Smart void
efct_hw_io_abort_all(struct efct_hw * hw)183663de5132SJames Smart efct_hw_io_abort_all(struct efct_hw *hw)
183763de5132SJames Smart {
183863de5132SJames Smart struct efct_hw_io *io_to_abort = NULL;
183963de5132SJames Smart struct efct_hw_io *next_io = NULL;
184063de5132SJames Smart
184163de5132SJames Smart list_for_each_entry_safe(io_to_abort, next_io,
184263de5132SJames Smart &hw->io_inuse, list_entry) {
184363de5132SJames Smart efct_hw_io_abort(hw, io_to_abort, true, NULL, NULL);
184463de5132SJames Smart }
184563de5132SJames Smart }
184663de5132SJames Smart
184763de5132SJames Smart static void
efct_hw_wq_process_abort(void * arg,u8 * cqe,int status)184863de5132SJames Smart efct_hw_wq_process_abort(void *arg, u8 *cqe, int status)
184963de5132SJames Smart {
185063de5132SJames Smart struct efct_hw_io *io = arg;
185163de5132SJames Smart struct efct_hw *hw = io->hw;
185263de5132SJames Smart u32 ext = 0;
185363de5132SJames Smart u32 len = 0;
185463de5132SJames Smart struct hw_wq_callback *wqcb;
185563de5132SJames Smart
185663de5132SJames Smart /*
185763de5132SJames Smart * For IOs that were aborted internally, we may need to issue the
185863de5132SJames Smart * callback here depending on whether a XRI_ABORTED CQE is expected ot
185963de5132SJames Smart * not. If the status is Local Reject/No XRI, then
186063de5132SJames Smart * issue the callback now.
186163de5132SJames Smart */
186263de5132SJames Smart ext = sli_fc_ext_status(&hw->sli, cqe);
186363de5132SJames Smart if (status == SLI4_FC_WCQE_STATUS_LOCAL_REJECT &&
186463de5132SJames Smart ext == SLI4_FC_LOCAL_REJECT_NO_XRI && io->done) {
186563de5132SJames Smart efct_hw_done_t done = io->done;
186663de5132SJames Smart
186763de5132SJames Smart io->done = NULL;
186863de5132SJames Smart
186963de5132SJames Smart /*
187063de5132SJames Smart * Use latched status as this is always saved for an internal
187163de5132SJames Smart * abort Note: We won't have both a done and abort_done
187263de5132SJames Smart * function, so don't worry about
187363de5132SJames Smart * clobbering the len, status and ext fields.
187463de5132SJames Smart */
187563de5132SJames Smart status = io->saved_status;
187663de5132SJames Smart len = io->saved_len;
187763de5132SJames Smart ext = io->saved_ext;
187863de5132SJames Smart io->status_saved = false;
187963de5132SJames Smart done(io, len, status, ext, io->arg);
188063de5132SJames Smart }
188163de5132SJames Smart
188263de5132SJames Smart if (io->abort_done) {
188363de5132SJames Smart efct_hw_done_t done = io->abort_done;
188463de5132SJames Smart
188563de5132SJames Smart io->abort_done = NULL;
188663de5132SJames Smart done(io, len, status, ext, io->abort_arg);
188763de5132SJames Smart }
188863de5132SJames Smart
188963de5132SJames Smart /* clear abort bit to indicate abort is complete */
189063de5132SJames Smart io->abort_in_progress = false;
189163de5132SJames Smart
189263de5132SJames Smart /* Free the WQ callback */
189363de5132SJames Smart if (io->abort_reqtag == U32_MAX) {
189463de5132SJames Smart efc_log_err(hw->os, "HW IO already freed\n");
189563de5132SJames Smart return;
189663de5132SJames Smart }
189763de5132SJames Smart
189863de5132SJames Smart wqcb = efct_hw_reqtag_get_instance(hw, io->abort_reqtag);
189963de5132SJames Smart efct_hw_reqtag_free(hw, wqcb);
190063de5132SJames Smart
190163de5132SJames Smart /*
190263de5132SJames Smart * Call efct_hw_io_free() because this releases the WQ reservation as
190363de5132SJames Smart * well as doing the refcount put. Don't duplicate the code here.
190463de5132SJames Smart */
190563de5132SJames Smart (void)efct_hw_io_free(hw, io);
190663de5132SJames Smart }
190763de5132SJames Smart
190863de5132SJames Smart static void
efct_hw_fill_abort_wqe(struct efct_hw * hw,struct efct_hw_wqe * wqe)190963de5132SJames Smart efct_hw_fill_abort_wqe(struct efct_hw *hw, struct efct_hw_wqe *wqe)
191063de5132SJames Smart {
191163de5132SJames Smart struct sli4_abort_wqe *abort = (void *)wqe->wqebuf;
191263de5132SJames Smart
191363de5132SJames Smart memset(abort, 0, hw->sli.wqe_size);
191463de5132SJames Smart
191563de5132SJames Smart abort->criteria = SLI4_ABORT_CRITERIA_XRI_TAG;
191663de5132SJames Smart abort->ia_ir_byte |= wqe->send_abts ? 0 : 1;
191763de5132SJames Smart
191863de5132SJames Smart /* Suppress ABTS retries */
191963de5132SJames Smart abort->ia_ir_byte |= SLI4_ABRT_WQE_IR;
192063de5132SJames Smart
192163de5132SJames Smart abort->t_tag = cpu_to_le32(wqe->id);
192263de5132SJames Smart abort->command = SLI4_WQE_ABORT;
192363de5132SJames Smart abort->request_tag = cpu_to_le16(wqe->abort_reqtag);
192463de5132SJames Smart
192563de5132SJames Smart abort->dw10w0_flags = cpu_to_le16(SLI4_ABRT_WQE_QOSD);
192663de5132SJames Smart
192763de5132SJames Smart abort->cq_id = cpu_to_le16(SLI4_CQ_DEFAULT);
192863de5132SJames Smart }
192963de5132SJames Smart
193063de5132SJames Smart int
efct_hw_io_abort(struct efct_hw * hw,struct efct_hw_io * io_to_abort,bool send_abts,void * cb,void * arg)193163de5132SJames Smart efct_hw_io_abort(struct efct_hw *hw, struct efct_hw_io *io_to_abort,
193263de5132SJames Smart bool send_abts, void *cb, void *arg)
193363de5132SJames Smart {
193463de5132SJames Smart struct hw_wq_callback *wqcb;
193563de5132SJames Smart unsigned long flags = 0;
193663de5132SJames Smart
193763de5132SJames Smart if (!io_to_abort) {
193863de5132SJames Smart efc_log_err(hw->os, "bad parameter hw=%p io=%p\n",
193963de5132SJames Smart hw, io_to_abort);
194063de5132SJames Smart return -EIO;
194163de5132SJames Smart }
194263de5132SJames Smart
194363de5132SJames Smart if (hw->state != EFCT_HW_STATE_ACTIVE) {
194463de5132SJames Smart efc_log_err(hw->os, "cannot send IO abort, HW state=%d\n",
194563de5132SJames Smart hw->state);
194663de5132SJames Smart return -EIO;
194763de5132SJames Smart }
194863de5132SJames Smart
194963de5132SJames Smart /* take a reference on IO being aborted */
195063de5132SJames Smart if (kref_get_unless_zero(&io_to_abort->ref) == 0) {
195163de5132SJames Smart /* command no longer active */
195263de5132SJames Smart efc_log_debug(hw->os,
195363de5132SJames Smart "io not active xri=0x%x tag=0x%x\n",
195463de5132SJames Smart io_to_abort->indicator, io_to_abort->reqtag);
195563de5132SJames Smart return -ENOENT;
195663de5132SJames Smart }
195763de5132SJames Smart
195863de5132SJames Smart /* Must have a valid WQ reference */
195963de5132SJames Smart if (!io_to_abort->wq) {
196063de5132SJames Smart efc_log_debug(hw->os, "io_to_abort xri=0x%x not active on WQ\n",
196163de5132SJames Smart io_to_abort->indicator);
196263de5132SJames Smart /* efct_ref_get(): same function */
196363de5132SJames Smart kref_put(&io_to_abort->ref, io_to_abort->release);
196463de5132SJames Smart return -ENOENT;
196563de5132SJames Smart }
196663de5132SJames Smart
196763de5132SJames Smart /*
196863de5132SJames Smart * Validation checks complete; now check to see if already being
196963de5132SJames Smart * aborted, if not set the flag.
197063de5132SJames Smart */
197163de5132SJames Smart if (cmpxchg(&io_to_abort->abort_in_progress, false, true)) {
197263de5132SJames Smart /* efct_ref_get(): same function */
197363de5132SJames Smart kref_put(&io_to_abort->ref, io_to_abort->release);
197463de5132SJames Smart efc_log_debug(hw->os,
197563de5132SJames Smart "io already being aborted xri=0x%x tag=0x%x\n",
197663de5132SJames Smart io_to_abort->indicator, io_to_abort->reqtag);
197763de5132SJames Smart return -EINPROGRESS;
197863de5132SJames Smart }
197963de5132SJames Smart
198063de5132SJames Smart /*
198163de5132SJames Smart * If we got here, the possibilities are:
198263de5132SJames Smart * - host owned xri
198363de5132SJames Smart * - io_to_abort->wq_index != U32_MAX
198463de5132SJames Smart * - submit ABORT_WQE to same WQ
198563de5132SJames Smart * - port owned xri:
198663de5132SJames Smart * - rxri: io_to_abort->wq_index == U32_MAX
198763de5132SJames Smart * - submit ABORT_WQE to any WQ
198863de5132SJames Smart * - non-rxri
198963de5132SJames Smart * - io_to_abort->index != U32_MAX
199063de5132SJames Smart * - submit ABORT_WQE to same WQ
199163de5132SJames Smart * - io_to_abort->index == U32_MAX
199263de5132SJames Smart * - submit ABORT_WQE to any WQ
199363de5132SJames Smart */
199463de5132SJames Smart io_to_abort->abort_done = cb;
199563de5132SJames Smart io_to_abort->abort_arg = arg;
199663de5132SJames Smart
199763de5132SJames Smart /* Allocate a request tag for the abort portion of this IO */
199863de5132SJames Smart wqcb = efct_hw_reqtag_alloc(hw, efct_hw_wq_process_abort, io_to_abort);
199963de5132SJames Smart if (!wqcb) {
200063de5132SJames Smart efc_log_err(hw->os, "can't allocate request tag\n");
200163de5132SJames Smart return -ENOSPC;
200263de5132SJames Smart }
200363de5132SJames Smart
200463de5132SJames Smart io_to_abort->abort_reqtag = wqcb->instance_index;
200563de5132SJames Smart io_to_abort->wqe.send_abts = send_abts;
200663de5132SJames Smart io_to_abort->wqe.id = io_to_abort->indicator;
200763de5132SJames Smart io_to_abort->wqe.abort_reqtag = io_to_abort->abort_reqtag;
200863de5132SJames Smart
200963de5132SJames Smart /*
201063de5132SJames Smart * If the wqe is on the pending list, then set this wqe to be
201163de5132SJames Smart * aborted when the IO's wqe is removed from the list.
201263de5132SJames Smart */
201363de5132SJames Smart if (io_to_abort->wq) {
201463de5132SJames Smart spin_lock_irqsave(&io_to_abort->wq->queue->lock, flags);
201563de5132SJames Smart if (io_to_abort->wqe.list_entry.next) {
201663de5132SJames Smart io_to_abort->wqe.abort_wqe_submit_needed = true;
201763de5132SJames Smart spin_unlock_irqrestore(&io_to_abort->wq->queue->lock,
201863de5132SJames Smart flags);
201963de5132SJames Smart return 0;
202063de5132SJames Smart }
202163de5132SJames Smart spin_unlock_irqrestore(&io_to_abort->wq->queue->lock, flags);
202263de5132SJames Smart }
202363de5132SJames Smart
202463de5132SJames Smart efct_hw_fill_abort_wqe(hw, &io_to_abort->wqe);
202563de5132SJames Smart
202663de5132SJames Smart /* ABORT_WQE does not actually utilize an XRI on the Port,
202763de5132SJames Smart * therefore, keep xbusy as-is to track the exchange's state,
202863de5132SJames Smart * not the ABORT_WQE's state
202963de5132SJames Smart */
203063de5132SJames Smart if (efct_hw_wq_write(io_to_abort->wq, &io_to_abort->wqe)) {
203163de5132SJames Smart io_to_abort->abort_in_progress = false;
203263de5132SJames Smart /* efct_ref_get(): same function */
203363de5132SJames Smart kref_put(&io_to_abort->ref, io_to_abort->release);
203463de5132SJames Smart return -EIO;
203563de5132SJames Smart }
203663de5132SJames Smart
203763de5132SJames Smart return 0;
203863de5132SJames Smart }
203963de5132SJames Smart
204063de5132SJames Smart void
efct_hw_reqtag_pool_free(struct efct_hw * hw)204163de5132SJames Smart efct_hw_reqtag_pool_free(struct efct_hw *hw)
204263de5132SJames Smart {
204363de5132SJames Smart u32 i;
204463de5132SJames Smart struct reqtag_pool *reqtag_pool = hw->wq_reqtag_pool;
204563de5132SJames Smart struct hw_wq_callback *wqcb = NULL;
204663de5132SJames Smart
204763de5132SJames Smart if (reqtag_pool) {
204863de5132SJames Smart for (i = 0; i < U16_MAX; i++) {
204963de5132SJames Smart wqcb = reqtag_pool->tags[i];
205063de5132SJames Smart if (!wqcb)
205163de5132SJames Smart continue;
205263de5132SJames Smart
205363de5132SJames Smart kfree(wqcb);
205463de5132SJames Smart }
205563de5132SJames Smart kfree(reqtag_pool);
205663de5132SJames Smart hw->wq_reqtag_pool = NULL;
205763de5132SJames Smart }
205863de5132SJames Smart }
205963de5132SJames Smart
206063de5132SJames Smart struct reqtag_pool *
efct_hw_reqtag_pool_alloc(struct efct_hw * hw)206163de5132SJames Smart efct_hw_reqtag_pool_alloc(struct efct_hw *hw)
206263de5132SJames Smart {
206363de5132SJames Smart u32 i = 0;
206463de5132SJames Smart struct reqtag_pool *reqtag_pool;
206563de5132SJames Smart struct hw_wq_callback *wqcb;
206663de5132SJames Smart
206763de5132SJames Smart reqtag_pool = kzalloc(sizeof(*reqtag_pool), GFP_KERNEL);
206863de5132SJames Smart if (!reqtag_pool)
206963de5132SJames Smart return NULL;
207063de5132SJames Smart
207163de5132SJames Smart INIT_LIST_HEAD(&reqtag_pool->freelist);
207263de5132SJames Smart /* initialize reqtag pool lock */
207363de5132SJames Smart spin_lock_init(&reqtag_pool->lock);
207463de5132SJames Smart for (i = 0; i < U16_MAX; i++) {
207563de5132SJames Smart wqcb = kmalloc(sizeof(*wqcb), GFP_KERNEL);
207663de5132SJames Smart if (!wqcb)
207763de5132SJames Smart break;
207863de5132SJames Smart
207963de5132SJames Smart reqtag_pool->tags[i] = wqcb;
208063de5132SJames Smart wqcb->instance_index = i;
208163de5132SJames Smart wqcb->callback = NULL;
208263de5132SJames Smart wqcb->arg = NULL;
208363de5132SJames Smart INIT_LIST_HEAD(&wqcb->list_entry);
208463de5132SJames Smart list_add_tail(&wqcb->list_entry, &reqtag_pool->freelist);
208563de5132SJames Smart }
208663de5132SJames Smart
208763de5132SJames Smart return reqtag_pool;
208863de5132SJames Smart }
208963de5132SJames Smart
209063de5132SJames Smart struct hw_wq_callback *
efct_hw_reqtag_alloc(struct efct_hw * hw,void (* callback)(void * arg,u8 * cqe,int status),void * arg)209163de5132SJames Smart efct_hw_reqtag_alloc(struct efct_hw *hw,
209263de5132SJames Smart void (*callback)(void *arg, u8 *cqe, int status),
209363de5132SJames Smart void *arg)
209463de5132SJames Smart {
209563de5132SJames Smart struct hw_wq_callback *wqcb = NULL;
209663de5132SJames Smart struct reqtag_pool *reqtag_pool = hw->wq_reqtag_pool;
209763de5132SJames Smart unsigned long flags = 0;
209863de5132SJames Smart
209963de5132SJames Smart if (!callback)
210063de5132SJames Smart return wqcb;
210163de5132SJames Smart
210263de5132SJames Smart spin_lock_irqsave(&reqtag_pool->lock, flags);
210363de5132SJames Smart
210463de5132SJames Smart if (!list_empty(&reqtag_pool->freelist)) {
210563de5132SJames Smart wqcb = list_first_entry(&reqtag_pool->freelist,
210663de5132SJames Smart struct hw_wq_callback, list_entry);
210763de5132SJames Smart }
210863de5132SJames Smart
210963de5132SJames Smart if (wqcb) {
211063de5132SJames Smart list_del_init(&wqcb->list_entry);
211163de5132SJames Smart spin_unlock_irqrestore(&reqtag_pool->lock, flags);
211263de5132SJames Smart wqcb->callback = callback;
211363de5132SJames Smart wqcb->arg = arg;
211463de5132SJames Smart } else {
211563de5132SJames Smart spin_unlock_irqrestore(&reqtag_pool->lock, flags);
211663de5132SJames Smart }
211763de5132SJames Smart
211863de5132SJames Smart return wqcb;
211963de5132SJames Smart }
212063de5132SJames Smart
212163de5132SJames Smart void
efct_hw_reqtag_free(struct efct_hw * hw,struct hw_wq_callback * wqcb)212263de5132SJames Smart efct_hw_reqtag_free(struct efct_hw *hw, struct hw_wq_callback *wqcb)
212363de5132SJames Smart {
212463de5132SJames Smart unsigned long flags = 0;
212563de5132SJames Smart struct reqtag_pool *reqtag_pool = hw->wq_reqtag_pool;
212663de5132SJames Smart
212763de5132SJames Smart if (!wqcb->callback)
212863de5132SJames Smart efc_log_err(hw->os, "WQCB is already freed\n");
212963de5132SJames Smart
213063de5132SJames Smart spin_lock_irqsave(&reqtag_pool->lock, flags);
213163de5132SJames Smart wqcb->callback = NULL;
213263de5132SJames Smart wqcb->arg = NULL;
213363de5132SJames Smart INIT_LIST_HEAD(&wqcb->list_entry);
213463de5132SJames Smart list_add(&wqcb->list_entry, &hw->wq_reqtag_pool->freelist);
213563de5132SJames Smart spin_unlock_irqrestore(&reqtag_pool->lock, flags);
213663de5132SJames Smart }
213763de5132SJames Smart
213863de5132SJames Smart struct hw_wq_callback *
efct_hw_reqtag_get_instance(struct efct_hw * hw,u32 instance_index)213963de5132SJames Smart efct_hw_reqtag_get_instance(struct efct_hw *hw, u32 instance_index)
214063de5132SJames Smart {
214163de5132SJames Smart struct hw_wq_callback *wqcb;
214263de5132SJames Smart
214363de5132SJames Smart wqcb = hw->wq_reqtag_pool->tags[instance_index];
214463de5132SJames Smart if (!wqcb)
214563de5132SJames Smart efc_log_err(hw->os, "wqcb for instance %d is null\n",
214663de5132SJames Smart instance_index);
214763de5132SJames Smart
214863de5132SJames Smart return wqcb;
214963de5132SJames Smart }
2150e2cf422bSJames Smart
2151e2cf422bSJames Smart int
efct_hw_queue_hash_find(struct efct_queue_hash * hash,u16 id)2152e2cf422bSJames Smart efct_hw_queue_hash_find(struct efct_queue_hash *hash, u16 id)
2153e2cf422bSJames Smart {
2154e2cf422bSJames Smart int index = -1;
2155e2cf422bSJames Smart int i = id & (EFCT_HW_Q_HASH_SIZE - 1);
2156e2cf422bSJames Smart
2157e2cf422bSJames Smart /*
2158e2cf422bSJames Smart * Since the hash is always bigger than the maximum number of Qs, then
2159e2cf422bSJames Smart * we never have to worry about an infinite loop. We will always find
2160e2cf422bSJames Smart * an unused entry.
2161e2cf422bSJames Smart */
2162e2cf422bSJames Smart do {
2163e2cf422bSJames Smart if (hash[i].in_use && hash[i].id == id)
2164e2cf422bSJames Smart index = hash[i].index;
2165e2cf422bSJames Smart else
2166e2cf422bSJames Smart i = (i + 1) & (EFCT_HW_Q_HASH_SIZE - 1);
2167e2cf422bSJames Smart } while (index == -1 && hash[i].in_use);
2168e2cf422bSJames Smart
2169e2cf422bSJames Smart return index;
2170e2cf422bSJames Smart }
2171e2cf422bSJames Smart
2172e2cf422bSJames Smart int
efct_hw_process(struct efct_hw * hw,u32 vector,u32 max_isr_time_msec)2173e2cf422bSJames Smart efct_hw_process(struct efct_hw *hw, u32 vector,
2174e2cf422bSJames Smart u32 max_isr_time_msec)
2175e2cf422bSJames Smart {
2176e2cf422bSJames Smart struct hw_eq *eq;
2177e2cf422bSJames Smart
2178e2cf422bSJames Smart /*
2179e2cf422bSJames Smart * The caller should disable interrupts if they wish to prevent us
2180e2cf422bSJames Smart * from processing during a shutdown. The following states are defined:
2181e2cf422bSJames Smart * EFCT_HW_STATE_UNINITIALIZED - No queues allocated
2182e2cf422bSJames Smart * EFCT_HW_STATE_QUEUES_ALLOCATED - The state after a chip reset,
2183e2cf422bSJames Smart * queues are cleared.
2184e2cf422bSJames Smart * EFCT_HW_STATE_ACTIVE - Chip and queues are operational
2185e2cf422bSJames Smart * EFCT_HW_STATE_RESET_IN_PROGRESS - reset, we still want completions
2186e2cf422bSJames Smart * EFCT_HW_STATE_TEARDOWN_IN_PROGRESS - We still want mailbox
2187e2cf422bSJames Smart * completions.
2188e2cf422bSJames Smart */
2189e2cf422bSJames Smart if (hw->state == EFCT_HW_STATE_UNINITIALIZED)
2190e2cf422bSJames Smart return 0;
2191e2cf422bSJames Smart
2192e2cf422bSJames Smart /* Get pointer to struct hw_eq */
2193e2cf422bSJames Smart eq = hw->hw_eq[vector];
2194e2cf422bSJames Smart if (!eq)
2195e2cf422bSJames Smart return 0;
2196e2cf422bSJames Smart
2197e2cf422bSJames Smart eq->use_count++;
2198e2cf422bSJames Smart
2199e2cf422bSJames Smart return efct_hw_eq_process(hw, eq, max_isr_time_msec);
2200e2cf422bSJames Smart }
2201e2cf422bSJames Smart
2202e2cf422bSJames Smart int
efct_hw_eq_process(struct efct_hw * hw,struct hw_eq * eq,u32 max_isr_time_msec)2203e2cf422bSJames Smart efct_hw_eq_process(struct efct_hw *hw, struct hw_eq *eq,
2204e2cf422bSJames Smart u32 max_isr_time_msec)
2205e2cf422bSJames Smart {
2206e2cf422bSJames Smart u8 eqe[sizeof(struct sli4_eqe)] = { 0 };
2207e2cf422bSJames Smart u32 tcheck_count;
2208e2cf422bSJames Smart u64 tstart;
2209e2cf422bSJames Smart u64 telapsed;
2210e2cf422bSJames Smart bool done = false;
2211e2cf422bSJames Smart
2212e2cf422bSJames Smart tcheck_count = EFCT_HW_TIMECHECK_ITERATIONS;
2213e2cf422bSJames Smart tstart = jiffies_to_msecs(jiffies);
2214e2cf422bSJames Smart
2215e2cf422bSJames Smart while (!done && !sli_eq_read(&hw->sli, eq->queue, eqe)) {
2216e2cf422bSJames Smart u16 cq_id = 0;
2217e2cf422bSJames Smart int rc;
2218e2cf422bSJames Smart
2219e2cf422bSJames Smart rc = sli_eq_parse(&hw->sli, eqe, &cq_id);
2220e2cf422bSJames Smart if (unlikely(rc)) {
2221e2cf422bSJames Smart if (rc == SLI4_EQE_STATUS_EQ_FULL) {
2222e2cf422bSJames Smart u32 i;
2223e2cf422bSJames Smart
2224e2cf422bSJames Smart /*
2225e2cf422bSJames Smart * Received a sentinel EQE indicating the
2226e2cf422bSJames Smart * EQ is full. Process all CQs
2227e2cf422bSJames Smart */
2228e2cf422bSJames Smart for (i = 0; i < hw->cq_count; i++)
2229e2cf422bSJames Smart efct_hw_cq_process(hw, hw->hw_cq[i]);
2230e2cf422bSJames Smart continue;
2231e2cf422bSJames Smart } else {
2232e2cf422bSJames Smart return rc;
2233e2cf422bSJames Smart }
2234e2cf422bSJames Smart } else {
2235e2cf422bSJames Smart int index;
2236e2cf422bSJames Smart
2237e2cf422bSJames Smart index = efct_hw_queue_hash_find(hw->cq_hash, cq_id);
2238e2cf422bSJames Smart
2239e2cf422bSJames Smart if (likely(index >= 0))
2240e2cf422bSJames Smart efct_hw_cq_process(hw, hw->hw_cq[index]);
2241e2cf422bSJames Smart else
2242e2cf422bSJames Smart efc_log_err(hw->os, "bad CQ_ID %#06x\n", cq_id);
2243e2cf422bSJames Smart }
2244e2cf422bSJames Smart
2245e2cf422bSJames Smart if (eq->queue->n_posted > eq->queue->posted_limit)
2246e2cf422bSJames Smart sli_queue_arm(&hw->sli, eq->queue, false);
2247e2cf422bSJames Smart
2248e2cf422bSJames Smart if (tcheck_count && (--tcheck_count == 0)) {
2249e2cf422bSJames Smart tcheck_count = EFCT_HW_TIMECHECK_ITERATIONS;
2250e2cf422bSJames Smart telapsed = jiffies_to_msecs(jiffies) - tstart;
2251e2cf422bSJames Smart if (telapsed >= max_isr_time_msec)
2252e2cf422bSJames Smart done = true;
2253e2cf422bSJames Smart }
2254e2cf422bSJames Smart }
2255e2cf422bSJames Smart sli_queue_eq_arm(&hw->sli, eq->queue, true);
2256e2cf422bSJames Smart
2257e2cf422bSJames Smart return 0;
2258e2cf422bSJames Smart }
2259e2cf422bSJames Smart
2260e2cf422bSJames Smart static int
_efct_hw_wq_write(struct hw_wq * wq,struct efct_hw_wqe * wqe)2261e2cf422bSJames Smart _efct_hw_wq_write(struct hw_wq *wq, struct efct_hw_wqe *wqe)
2262e2cf422bSJames Smart {
2263e2cf422bSJames Smart int queue_rc;
2264e2cf422bSJames Smart
2265e2cf422bSJames Smart /* Every so often, set the wqec bit to generate comsummed completions */
2266e2cf422bSJames Smart if (wq->wqec_count)
2267e2cf422bSJames Smart wq->wqec_count--;
2268e2cf422bSJames Smart
2269e2cf422bSJames Smart if (wq->wqec_count == 0) {
2270e2cf422bSJames Smart struct sli4_generic_wqe *genwqe = (void *)wqe->wqebuf;
2271e2cf422bSJames Smart
2272e2cf422bSJames Smart genwqe->cmdtype_wqec_byte |= SLI4_GEN_WQE_WQEC;
2273e2cf422bSJames Smart wq->wqec_count = wq->wqec_set_count;
2274e2cf422bSJames Smart }
2275e2cf422bSJames Smart
2276e2cf422bSJames Smart /* Decrement WQ free count */
2277e2cf422bSJames Smart wq->free_count--;
2278e2cf422bSJames Smart
2279e2cf422bSJames Smart queue_rc = sli_wq_write(&wq->hw->sli, wq->queue, wqe->wqebuf);
2280e2cf422bSJames Smart
2281e2cf422bSJames Smart return (queue_rc < 0) ? -EIO : 0;
2282e2cf422bSJames Smart }
2283e2cf422bSJames Smart
2284e2cf422bSJames Smart static void
hw_wq_submit_pending(struct hw_wq * wq,u32 update_free_count)2285e2cf422bSJames Smart hw_wq_submit_pending(struct hw_wq *wq, u32 update_free_count)
2286e2cf422bSJames Smart {
2287e2cf422bSJames Smart struct efct_hw_wqe *wqe;
2288e2cf422bSJames Smart unsigned long flags = 0;
2289e2cf422bSJames Smart
2290e2cf422bSJames Smart spin_lock_irqsave(&wq->queue->lock, flags);
2291e2cf422bSJames Smart
2292e2cf422bSJames Smart /* Update free count with value passed in */
2293e2cf422bSJames Smart wq->free_count += update_free_count;
2294e2cf422bSJames Smart
2295e2cf422bSJames Smart while ((wq->free_count > 0) && (!list_empty(&wq->pending_list))) {
2296e2cf422bSJames Smart wqe = list_first_entry(&wq->pending_list,
2297e2cf422bSJames Smart struct efct_hw_wqe, list_entry);
2298e2cf422bSJames Smart list_del_init(&wqe->list_entry);
2299e2cf422bSJames Smart _efct_hw_wq_write(wq, wqe);
2300e2cf422bSJames Smart
2301e2cf422bSJames Smart if (wqe->abort_wqe_submit_needed) {
2302e2cf422bSJames Smart wqe->abort_wqe_submit_needed = false;
2303e2cf422bSJames Smart efct_hw_fill_abort_wqe(wq->hw, wqe);
2304e2cf422bSJames Smart INIT_LIST_HEAD(&wqe->list_entry);
2305e2cf422bSJames Smart list_add_tail(&wqe->list_entry, &wq->pending_list);
2306e2cf422bSJames Smart wq->wq_pending_count++;
2307e2cf422bSJames Smart }
2308e2cf422bSJames Smart }
2309e2cf422bSJames Smart
2310e2cf422bSJames Smart spin_unlock_irqrestore(&wq->queue->lock, flags);
2311e2cf422bSJames Smart }
2312e2cf422bSJames Smart
2313e2cf422bSJames Smart void
efct_hw_cq_process(struct efct_hw * hw,struct hw_cq * cq)2314e2cf422bSJames Smart efct_hw_cq_process(struct efct_hw *hw, struct hw_cq *cq)
2315e2cf422bSJames Smart {
2316e2cf422bSJames Smart u8 cqe[sizeof(struct sli4_mcqe)];
2317e2cf422bSJames Smart u16 rid = U16_MAX;
2318e2cf422bSJames Smart /* completion type */
2319e2cf422bSJames Smart enum sli4_qentry ctype;
2320e2cf422bSJames Smart u32 n_processed = 0;
2321e2cf422bSJames Smart u32 tstart, telapsed;
2322e2cf422bSJames Smart
2323e2cf422bSJames Smart tstart = jiffies_to_msecs(jiffies);
2324e2cf422bSJames Smart
2325e2cf422bSJames Smart while (!sli_cq_read(&hw->sli, cq->queue, cqe)) {
2326e2cf422bSJames Smart int status;
2327e2cf422bSJames Smart
2328e2cf422bSJames Smart status = sli_cq_parse(&hw->sli, cq->queue, cqe, &ctype, &rid);
2329e2cf422bSJames Smart /*
2330e2cf422bSJames Smart * The sign of status is significant. If status is:
2331e2cf422bSJames Smart * == 0 : call completed correctly and
2332e2cf422bSJames Smart * the CQE indicated success
2333e2cf422bSJames Smart * > 0 : call completed correctly and
2334e2cf422bSJames Smart * the CQE indicated an error
2335e2cf422bSJames Smart * < 0 : call failed and no information is available about the
2336e2cf422bSJames Smart * CQE
2337e2cf422bSJames Smart */
2338e2cf422bSJames Smart if (status < 0) {
2339e2cf422bSJames Smart if (status == SLI4_MCQE_STATUS_NOT_COMPLETED)
2340e2cf422bSJames Smart /*
2341e2cf422bSJames Smart * Notification that an entry was consumed,
2342e2cf422bSJames Smart * but not completed
2343e2cf422bSJames Smart */
2344e2cf422bSJames Smart continue;
2345e2cf422bSJames Smart
2346e2cf422bSJames Smart break;
2347e2cf422bSJames Smart }
2348e2cf422bSJames Smart
2349e2cf422bSJames Smart switch (ctype) {
2350e2cf422bSJames Smart case SLI4_QENTRY_ASYNC:
2351e2cf422bSJames Smart sli_cqe_async(&hw->sli, cqe);
2352e2cf422bSJames Smart break;
2353e2cf422bSJames Smart case SLI4_QENTRY_MQ:
2354e2cf422bSJames Smart /*
2355e2cf422bSJames Smart * Process MQ entry. Note there is no way to determine
2356e2cf422bSJames Smart * the MQ_ID from the completion entry.
2357e2cf422bSJames Smart */
2358e2cf422bSJames Smart efct_hw_mq_process(hw, status, hw->mq);
2359e2cf422bSJames Smart break;
2360e2cf422bSJames Smart case SLI4_QENTRY_WQ:
2361e2cf422bSJames Smart efct_hw_wq_process(hw, cq, cqe, status, rid);
2362e2cf422bSJames Smart break;
2363e2cf422bSJames Smart case SLI4_QENTRY_WQ_RELEASE: {
2364e2cf422bSJames Smart u32 wq_id = rid;
2365e2cf422bSJames Smart int index;
2366e2cf422bSJames Smart struct hw_wq *wq = NULL;
2367e2cf422bSJames Smart
2368e2cf422bSJames Smart index = efct_hw_queue_hash_find(hw->wq_hash, wq_id);
2369e2cf422bSJames Smart
2370e2cf422bSJames Smart if (likely(index >= 0)) {
2371e2cf422bSJames Smart wq = hw->hw_wq[index];
2372e2cf422bSJames Smart } else {
2373e2cf422bSJames Smart efc_log_err(hw->os, "bad WQ_ID %#06x\n", wq_id);
2374e2cf422bSJames Smart break;
2375e2cf422bSJames Smart }
2376e2cf422bSJames Smart /* Submit any HW IOs that are on the WQ pending list */
2377e2cf422bSJames Smart hw_wq_submit_pending(wq, wq->wqec_set_count);
2378e2cf422bSJames Smart
2379e2cf422bSJames Smart break;
2380e2cf422bSJames Smart }
2381e2cf422bSJames Smart
2382e2cf422bSJames Smart case SLI4_QENTRY_RQ:
2383e2cf422bSJames Smart efct_hw_rqpair_process_rq(hw, cq, cqe);
2384e2cf422bSJames Smart break;
2385e2cf422bSJames Smart case SLI4_QENTRY_XABT: {
2386e2cf422bSJames Smart efct_hw_xabt_process(hw, cq, cqe, rid);
2387e2cf422bSJames Smart break;
2388e2cf422bSJames Smart }
2389e2cf422bSJames Smart default:
2390e2cf422bSJames Smart efc_log_debug(hw->os, "unhandled ctype=%#x rid=%#x\n",
2391e2cf422bSJames Smart ctype, rid);
2392e2cf422bSJames Smart break;
2393e2cf422bSJames Smart }
2394e2cf422bSJames Smart
2395e2cf422bSJames Smart n_processed++;
2396e2cf422bSJames Smart if (n_processed == cq->queue->proc_limit)
2397e2cf422bSJames Smart break;
2398e2cf422bSJames Smart
2399e2cf422bSJames Smart if (cq->queue->n_posted >= cq->queue->posted_limit)
2400e2cf422bSJames Smart sli_queue_arm(&hw->sli, cq->queue, false);
2401e2cf422bSJames Smart }
2402e2cf422bSJames Smart
2403e2cf422bSJames Smart sli_queue_arm(&hw->sli, cq->queue, true);
2404e2cf422bSJames Smart
2405e2cf422bSJames Smart if (n_processed > cq->queue->max_num_processed)
2406e2cf422bSJames Smart cq->queue->max_num_processed = n_processed;
2407e2cf422bSJames Smart telapsed = jiffies_to_msecs(jiffies) - tstart;
2408e2cf422bSJames Smart if (telapsed > cq->queue->max_process_time)
2409e2cf422bSJames Smart cq->queue->max_process_time = telapsed;
2410e2cf422bSJames Smart }
2411e2cf422bSJames Smart
2412e2cf422bSJames Smart void
efct_hw_wq_process(struct efct_hw * hw,struct hw_cq * cq,u8 * cqe,int status,u16 rid)2413e2cf422bSJames Smart efct_hw_wq_process(struct efct_hw *hw, struct hw_cq *cq,
2414e2cf422bSJames Smart u8 *cqe, int status, u16 rid)
2415e2cf422bSJames Smart {
2416e2cf422bSJames Smart struct hw_wq_callback *wqcb;
2417e2cf422bSJames Smart
2418e2cf422bSJames Smart if (rid == EFCT_HW_REQUE_XRI_REGTAG) {
2419e2cf422bSJames Smart if (status)
2420e2cf422bSJames Smart efc_log_err(hw->os, "reque xri failed, status = %d\n",
2421e2cf422bSJames Smart status);
2422e2cf422bSJames Smart return;
2423e2cf422bSJames Smart }
2424e2cf422bSJames Smart
2425e2cf422bSJames Smart wqcb = efct_hw_reqtag_get_instance(hw, rid);
2426e2cf422bSJames Smart if (!wqcb) {
2427e2cf422bSJames Smart efc_log_err(hw->os, "invalid request tag: x%x\n", rid);
2428e2cf422bSJames Smart return;
2429e2cf422bSJames Smart }
2430e2cf422bSJames Smart
2431e2cf422bSJames Smart if (!wqcb->callback) {
2432e2cf422bSJames Smart efc_log_err(hw->os, "wqcb callback is NULL\n");
2433e2cf422bSJames Smart return;
2434e2cf422bSJames Smart }
2435e2cf422bSJames Smart
2436e2cf422bSJames Smart (*wqcb->callback)(wqcb->arg, cqe, status);
2437e2cf422bSJames Smart }
2438e2cf422bSJames Smart
2439e2cf422bSJames Smart void
efct_hw_xabt_process(struct efct_hw * hw,struct hw_cq * cq,u8 * cqe,u16 rid)2440e2cf422bSJames Smart efct_hw_xabt_process(struct efct_hw *hw, struct hw_cq *cq,
2441e2cf422bSJames Smart u8 *cqe, u16 rid)
2442e2cf422bSJames Smart {
2443e2cf422bSJames Smart /* search IOs wait free list */
2444e2cf422bSJames Smart struct efct_hw_io *io = NULL;
2445e2cf422bSJames Smart unsigned long flags = 0;
2446e2cf422bSJames Smart
2447e2cf422bSJames Smart io = efct_hw_io_lookup(hw, rid);
2448e2cf422bSJames Smart if (!io) {
2449e2cf422bSJames Smart /* IO lookup failure should never happen */
2450e2cf422bSJames Smart efc_log_err(hw->os, "xabt io lookup failed rid=%#x\n", rid);
2451e2cf422bSJames Smart return;
2452e2cf422bSJames Smart }
2453e2cf422bSJames Smart
2454e2cf422bSJames Smart if (!io->xbusy)
2455e2cf422bSJames Smart efc_log_debug(hw->os, "xabt io not busy rid=%#x\n", rid);
2456e2cf422bSJames Smart else
2457e2cf422bSJames Smart /* mark IO as no longer busy */
2458e2cf422bSJames Smart io->xbusy = false;
2459e2cf422bSJames Smart
2460e2cf422bSJames Smart /*
2461e2cf422bSJames Smart * For IOs that were aborted internally, we need to issue any pending
2462e2cf422bSJames Smart * callback here.
2463e2cf422bSJames Smart */
2464e2cf422bSJames Smart if (io->done) {
2465e2cf422bSJames Smart efct_hw_done_t done = io->done;
2466e2cf422bSJames Smart void *arg = io->arg;
2467e2cf422bSJames Smart
2468e2cf422bSJames Smart /*
2469e2cf422bSJames Smart * Use latched status as this is always saved for an internal
2470e2cf422bSJames Smart * abort
2471e2cf422bSJames Smart */
2472e2cf422bSJames Smart int status = io->saved_status;
2473e2cf422bSJames Smart u32 len = io->saved_len;
2474e2cf422bSJames Smart u32 ext = io->saved_ext;
2475e2cf422bSJames Smart
2476e2cf422bSJames Smart io->done = NULL;
2477e2cf422bSJames Smart io->status_saved = false;
2478e2cf422bSJames Smart
2479e2cf422bSJames Smart done(io, len, status, ext, arg);
2480e2cf422bSJames Smart }
2481e2cf422bSJames Smart
2482e2cf422bSJames Smart spin_lock_irqsave(&hw->io_lock, flags);
2483e2cf422bSJames Smart if (io->state == EFCT_HW_IO_STATE_INUSE ||
2484e2cf422bSJames Smart io->state == EFCT_HW_IO_STATE_WAIT_FREE) {
2485e2cf422bSJames Smart /* if on wait_free list, caller has already freed IO;
2486e2cf422bSJames Smart * remove from wait_free list and add to free list.
2487e2cf422bSJames Smart * if on in-use list, already marked as no longer busy;
2488e2cf422bSJames Smart * just leave there and wait for caller to free.
2489e2cf422bSJames Smart */
2490e2cf422bSJames Smart if (io->state == EFCT_HW_IO_STATE_WAIT_FREE) {
2491e2cf422bSJames Smart io->state = EFCT_HW_IO_STATE_FREE;
2492e2cf422bSJames Smart list_del_init(&io->list_entry);
2493e2cf422bSJames Smart efct_hw_io_free_move_correct_list(hw, io);
2494e2cf422bSJames Smart }
2495e2cf422bSJames Smart }
2496e2cf422bSJames Smart spin_unlock_irqrestore(&hw->io_lock, flags);
2497e2cf422bSJames Smart }
2498e2cf422bSJames Smart
2499e2cf422bSJames Smart static int
efct_hw_flush(struct efct_hw * hw)2500e2cf422bSJames Smart efct_hw_flush(struct efct_hw *hw)
2501e2cf422bSJames Smart {
2502e2cf422bSJames Smart u32 i = 0;
2503e2cf422bSJames Smart
2504e2cf422bSJames Smart /* Process any remaining completions */
2505e2cf422bSJames Smart for (i = 0; i < hw->eq_count; i++)
2506e2cf422bSJames Smart efct_hw_process(hw, i, ~0);
2507e2cf422bSJames Smart
2508e2cf422bSJames Smart return 0;
2509e2cf422bSJames Smart }
2510dd53d333SJames Smart
2511dd53d333SJames Smart int
efct_hw_wq_write(struct hw_wq * wq,struct efct_hw_wqe * wqe)2512dd53d333SJames Smart efct_hw_wq_write(struct hw_wq *wq, struct efct_hw_wqe *wqe)
2513dd53d333SJames Smart {
2514dd53d333SJames Smart int rc = 0;
2515dd53d333SJames Smart unsigned long flags = 0;
2516dd53d333SJames Smart
2517dd53d333SJames Smart spin_lock_irqsave(&wq->queue->lock, flags);
2518dd53d333SJames Smart if (list_empty(&wq->pending_list)) {
2519dd53d333SJames Smart if (wq->free_count > 0) {
2520dd53d333SJames Smart rc = _efct_hw_wq_write(wq, wqe);
2521dd53d333SJames Smart } else {
2522dd53d333SJames Smart INIT_LIST_HEAD(&wqe->list_entry);
2523dd53d333SJames Smart list_add_tail(&wqe->list_entry, &wq->pending_list);
2524dd53d333SJames Smart wq->wq_pending_count++;
2525dd53d333SJames Smart }
2526dd53d333SJames Smart
2527dd53d333SJames Smart spin_unlock_irqrestore(&wq->queue->lock, flags);
2528dd53d333SJames Smart return rc;
2529dd53d333SJames Smart }
2530dd53d333SJames Smart
2531dd53d333SJames Smart INIT_LIST_HEAD(&wqe->list_entry);
2532dd53d333SJames Smart list_add_tail(&wqe->list_entry, &wq->pending_list);
2533dd53d333SJames Smart wq->wq_pending_count++;
2534dd53d333SJames Smart while (wq->free_count > 0) {
2535dd53d333SJames Smart wqe = list_first_entry(&wq->pending_list, struct efct_hw_wqe,
2536dd53d333SJames Smart list_entry);
2537dd53d333SJames Smart if (!wqe)
2538dd53d333SJames Smart break;
2539dd53d333SJames Smart
2540dd53d333SJames Smart list_del_init(&wqe->list_entry);
2541dd53d333SJames Smart rc = _efct_hw_wq_write(wq, wqe);
2542dd53d333SJames Smart if (rc)
2543dd53d333SJames Smart break;
2544dd53d333SJames Smart
2545dd53d333SJames Smart if (wqe->abort_wqe_submit_needed) {
2546dd53d333SJames Smart wqe->abort_wqe_submit_needed = false;
2547dd53d333SJames Smart efct_hw_fill_abort_wqe(wq->hw, wqe);
2548dd53d333SJames Smart
2549dd53d333SJames Smart INIT_LIST_HEAD(&wqe->list_entry);
2550dd53d333SJames Smart list_add_tail(&wqe->list_entry, &wq->pending_list);
2551dd53d333SJames Smart wq->wq_pending_count++;
2552dd53d333SJames Smart }
2553dd53d333SJames Smart }
2554dd53d333SJames Smart
2555dd53d333SJames Smart spin_unlock_irqrestore(&wq->queue->lock, flags);
2556dd53d333SJames Smart
2557dd53d333SJames Smart return rc;
2558dd53d333SJames Smart }
2559dd53d333SJames Smart
2560dd53d333SJames Smart int
efct_efc_bls_send(struct efc * efc,u32 type,struct sli_bls_params * bls)2561dd53d333SJames Smart efct_efc_bls_send(struct efc *efc, u32 type, struct sli_bls_params *bls)
2562dd53d333SJames Smart {
2563dd53d333SJames Smart struct efct *efct = efc->base;
2564dd53d333SJames Smart
2565dd53d333SJames Smart return efct_hw_bls_send(efct, type, bls, NULL, NULL);
2566dd53d333SJames Smart }
2567dd53d333SJames Smart
2568dd53d333SJames Smart int
efct_hw_bls_send(struct efct * efct,u32 type,struct sli_bls_params * bls_params,void * cb,void * arg)2569dd53d333SJames Smart efct_hw_bls_send(struct efct *efct, u32 type, struct sli_bls_params *bls_params,
2570dd53d333SJames Smart void *cb, void *arg)
2571dd53d333SJames Smart {
2572dd53d333SJames Smart struct efct_hw *hw = &efct->hw;
2573dd53d333SJames Smart struct efct_hw_io *hio;
2574dd53d333SJames Smart struct sli_bls_payload bls;
2575dd53d333SJames Smart int rc;
2576dd53d333SJames Smart
2577dd53d333SJames Smart if (hw->state != EFCT_HW_STATE_ACTIVE) {
2578dd53d333SJames Smart efc_log_err(hw->os,
2579dd53d333SJames Smart "cannot send BLS, HW state=%d\n", hw->state);
2580dd53d333SJames Smart return -EIO;
2581dd53d333SJames Smart }
2582dd53d333SJames Smart
2583dd53d333SJames Smart hio = efct_hw_io_alloc(hw);
2584dd53d333SJames Smart if (!hio) {
2585dd53d333SJames Smart efc_log_err(hw->os, "HIO allocation failed\n");
2586dd53d333SJames Smart return -EIO;
2587dd53d333SJames Smart }
2588dd53d333SJames Smart
2589dd53d333SJames Smart hio->done = cb;
2590dd53d333SJames Smart hio->arg = arg;
2591dd53d333SJames Smart
2592dd53d333SJames Smart bls_params->xri = hio->indicator;
2593dd53d333SJames Smart bls_params->tag = hio->reqtag;
2594dd53d333SJames Smart
2595dd53d333SJames Smart if (type == FC_RCTL_BA_ACC) {
2596dd53d333SJames Smart hio->type = EFCT_HW_BLS_ACC;
2597dd53d333SJames Smart bls.type = SLI4_SLI_BLS_ACC;
2598dd53d333SJames Smart memcpy(&bls.u.acc, bls_params->payload, sizeof(bls.u.acc));
2599dd53d333SJames Smart } else {
2600dd53d333SJames Smart hio->type = EFCT_HW_BLS_RJT;
2601dd53d333SJames Smart bls.type = SLI4_SLI_BLS_RJT;
2602dd53d333SJames Smart memcpy(&bls.u.rjt, bls_params->payload, sizeof(bls.u.rjt));
2603dd53d333SJames Smart }
2604dd53d333SJames Smart
2605dd53d333SJames Smart bls.ox_id = cpu_to_le16(bls_params->ox_id);
2606dd53d333SJames Smart bls.rx_id = cpu_to_le16(bls_params->rx_id);
2607dd53d333SJames Smart
2608dd53d333SJames Smart if (sli_xmit_bls_rsp64_wqe(&hw->sli, hio->wqe.wqebuf,
2609dd53d333SJames Smart &bls, bls_params)) {
2610dd53d333SJames Smart efc_log_err(hw->os, "XMIT_BLS_RSP64 WQE error\n");
2611dd53d333SJames Smart return -EIO;
2612dd53d333SJames Smart }
2613dd53d333SJames Smart
2614dd53d333SJames Smart hio->xbusy = true;
2615dd53d333SJames Smart
2616dd53d333SJames Smart /*
2617dd53d333SJames Smart * Add IO to active io wqe list before submitting, in case the
2618dd53d333SJames Smart * wcqe processing preempts this thread.
2619dd53d333SJames Smart */
2620dd53d333SJames Smart hio->wq->use_count++;
2621dd53d333SJames Smart rc = efct_hw_wq_write(hio->wq, &hio->wqe);
2622dd53d333SJames Smart if (rc >= 0) {
2623dd53d333SJames Smart /* non-negative return is success */
2624dd53d333SJames Smart rc = 0;
2625dd53d333SJames Smart } else {
2626dd53d333SJames Smart /* failed to write wqe, remove from active wqe list */
2627dd53d333SJames Smart efc_log_err(hw->os,
2628dd53d333SJames Smart "sli_queue_write failed: %d\n", rc);
2629dd53d333SJames Smart hio->xbusy = false;
2630dd53d333SJames Smart }
2631dd53d333SJames Smart
2632dd53d333SJames Smart return rc;
2633dd53d333SJames Smart }
2634dd53d333SJames Smart
2635dd53d333SJames Smart static int
efct_els_ssrs_send_cb(struct efct_hw_io * hio,u32 length,int status,u32 ext_status,void * arg)2636dd53d333SJames Smart efct_els_ssrs_send_cb(struct efct_hw_io *hio, u32 length, int status,
2637dd53d333SJames Smart u32 ext_status, void *arg)
2638dd53d333SJames Smart {
2639dd53d333SJames Smart struct efc_disc_io *io = arg;
2640dd53d333SJames Smart
2641dd53d333SJames Smart efc_disc_io_complete(io, length, status, ext_status);
2642dd53d333SJames Smart return 0;
2643dd53d333SJames Smart }
2644dd53d333SJames Smart
2645dd53d333SJames Smart static inline void
efct_fill_els_params(struct efc_disc_io * io,struct sli_els_params * params)2646dd53d333SJames Smart efct_fill_els_params(struct efc_disc_io *io, struct sli_els_params *params)
2647dd53d333SJames Smart {
2648dd53d333SJames Smart u8 *cmd = io->req.virt;
2649dd53d333SJames Smart
2650dd53d333SJames Smart params->cmd = *cmd;
2651dd53d333SJames Smart params->s_id = io->s_id;
2652dd53d333SJames Smart params->d_id = io->d_id;
2653dd53d333SJames Smart params->ox_id = io->iparam.els.ox_id;
2654dd53d333SJames Smart params->rpi = io->rpi;
2655dd53d333SJames Smart params->vpi = io->vpi;
2656dd53d333SJames Smart params->rpi_registered = io->rpi_registered;
2657dd53d333SJames Smart params->xmit_len = io->xmit_len;
2658dd53d333SJames Smart params->rsp_len = io->rsp_len;
2659dd53d333SJames Smart params->timeout = io->iparam.els.timeout;
2660dd53d333SJames Smart }
2661dd53d333SJames Smart
2662dd53d333SJames Smart static inline void
efct_fill_ct_params(struct efc_disc_io * io,struct sli_ct_params * params)2663dd53d333SJames Smart efct_fill_ct_params(struct efc_disc_io *io, struct sli_ct_params *params)
2664dd53d333SJames Smart {
2665dd53d333SJames Smart params->r_ctl = io->iparam.ct.r_ctl;
2666dd53d333SJames Smart params->type = io->iparam.ct.type;
2667dd53d333SJames Smart params->df_ctl = io->iparam.ct.df_ctl;
2668dd53d333SJames Smart params->d_id = io->d_id;
2669dd53d333SJames Smart params->ox_id = io->iparam.ct.ox_id;
2670dd53d333SJames Smart params->rpi = io->rpi;
2671dd53d333SJames Smart params->vpi = io->vpi;
2672dd53d333SJames Smart params->rpi_registered = io->rpi_registered;
2673dd53d333SJames Smart params->xmit_len = io->xmit_len;
2674dd53d333SJames Smart params->rsp_len = io->rsp_len;
2675dd53d333SJames Smart params->timeout = io->iparam.ct.timeout;
2676dd53d333SJames Smart }
2677dd53d333SJames Smart
2678dd53d333SJames Smart /**
2679dd53d333SJames Smart * efct_els_hw_srrs_send() - Send a single request and response cmd.
2680dd53d333SJames Smart * @efc: efc library structure
2681dd53d333SJames Smart * @io: Discovery IO used to hold els and ct cmd context.
2682dd53d333SJames Smart *
2683dd53d333SJames Smart * This routine supports communication sequences consisting of a single
2684dd53d333SJames Smart * request and single response between two endpoints. Examples include:
2685dd53d333SJames Smart * - Sending an ELS request.
2686dd53d333SJames Smart * - Sending an ELS response - To send an ELS response, the caller must provide
2687dd53d333SJames Smart * the OX_ID from the received request.
2688dd53d333SJames Smart * - Sending a FC Common Transport (FC-CT) request - To send a FC-CT request,
2689dd53d333SJames Smart * the caller must provide the R_CTL, TYPE, and DF_CTL
2690dd53d333SJames Smart * values to place in the FC frame header.
2691dd53d333SJames Smart *
2692dd53d333SJames Smart * Return: Status of the request.
2693dd53d333SJames Smart */
2694dd53d333SJames Smart int
efct_els_hw_srrs_send(struct efc * efc,struct efc_disc_io * io)2695dd53d333SJames Smart efct_els_hw_srrs_send(struct efc *efc, struct efc_disc_io *io)
2696dd53d333SJames Smart {
2697dd53d333SJames Smart struct efct *efct = efc->base;
2698dd53d333SJames Smart struct efct_hw_io *hio;
2699dd53d333SJames Smart struct efct_hw *hw = &efct->hw;
2700dd53d333SJames Smart struct efc_dma *send = &io->req;
2701dd53d333SJames Smart struct efc_dma *receive = &io->rsp;
2702dd53d333SJames Smart struct sli4_sge *sge = NULL;
2703dd53d333SJames Smart int rc = 0;
2704dd53d333SJames Smart u32 len = io->xmit_len;
2705dd53d333SJames Smart u32 sge0_flags;
2706dd53d333SJames Smart u32 sge1_flags;
2707dd53d333SJames Smart
2708dd53d333SJames Smart hio = efct_hw_io_alloc(hw);
2709dd53d333SJames Smart if (!hio) {
2710dd53d333SJames Smart pr_err("HIO alloc failed\n");
2711dd53d333SJames Smart return -EIO;
2712dd53d333SJames Smart }
2713dd53d333SJames Smart
2714dd53d333SJames Smart if (hw->state != EFCT_HW_STATE_ACTIVE) {
2715dd53d333SJames Smart efc_log_debug(hw->os,
2716dd53d333SJames Smart "cannot send SRRS, HW state=%d\n", hw->state);
2717dd53d333SJames Smart return -EIO;
2718dd53d333SJames Smart }
2719dd53d333SJames Smart
2720dd53d333SJames Smart hio->done = efct_els_ssrs_send_cb;
2721dd53d333SJames Smart hio->arg = io;
2722dd53d333SJames Smart
2723dd53d333SJames Smart sge = hio->sgl->virt;
2724dd53d333SJames Smart
2725dd53d333SJames Smart /* clear both SGE */
2726dd53d333SJames Smart memset(hio->sgl->virt, 0, 2 * sizeof(struct sli4_sge));
2727dd53d333SJames Smart
2728dd53d333SJames Smart sge0_flags = le32_to_cpu(sge[0].dw2_flags);
2729dd53d333SJames Smart sge1_flags = le32_to_cpu(sge[1].dw2_flags);
2730dd53d333SJames Smart if (send->size) {
2731dd53d333SJames Smart sge[0].buffer_address_high =
2732dd53d333SJames Smart cpu_to_le32(upper_32_bits(send->phys));
2733dd53d333SJames Smart sge[0].buffer_address_low =
2734dd53d333SJames Smart cpu_to_le32(lower_32_bits(send->phys));
2735dd53d333SJames Smart
2736dd53d333SJames Smart sge0_flags |= (SLI4_SGE_TYPE_DATA << SLI4_SGE_TYPE_SHIFT);
2737dd53d333SJames Smart
2738dd53d333SJames Smart sge[0].buffer_length = cpu_to_le32(len);
2739dd53d333SJames Smart }
2740dd53d333SJames Smart
2741dd53d333SJames Smart if (io->io_type == EFC_DISC_IO_ELS_REQ ||
2742dd53d333SJames Smart io->io_type == EFC_DISC_IO_CT_REQ) {
2743dd53d333SJames Smart sge[1].buffer_address_high =
2744dd53d333SJames Smart cpu_to_le32(upper_32_bits(receive->phys));
2745dd53d333SJames Smart sge[1].buffer_address_low =
2746dd53d333SJames Smart cpu_to_le32(lower_32_bits(receive->phys));
2747dd53d333SJames Smart
2748dd53d333SJames Smart sge1_flags |= (SLI4_SGE_TYPE_DATA << SLI4_SGE_TYPE_SHIFT);
2749dd53d333SJames Smart sge1_flags |= SLI4_SGE_LAST;
2750dd53d333SJames Smart
2751dd53d333SJames Smart sge[1].buffer_length = cpu_to_le32(receive->size);
2752dd53d333SJames Smart } else {
2753dd53d333SJames Smart sge0_flags |= SLI4_SGE_LAST;
2754dd53d333SJames Smart }
2755dd53d333SJames Smart
2756dd53d333SJames Smart sge[0].dw2_flags = cpu_to_le32(sge0_flags);
2757dd53d333SJames Smart sge[1].dw2_flags = cpu_to_le32(sge1_flags);
2758dd53d333SJames Smart
2759dd53d333SJames Smart switch (io->io_type) {
2760dd53d333SJames Smart case EFC_DISC_IO_ELS_REQ: {
2761dd53d333SJames Smart struct sli_els_params els_params;
2762dd53d333SJames Smart
2763dd53d333SJames Smart hio->type = EFCT_HW_ELS_REQ;
2764dd53d333SJames Smart efct_fill_els_params(io, &els_params);
2765dd53d333SJames Smart els_params.xri = hio->indicator;
2766dd53d333SJames Smart els_params.tag = hio->reqtag;
2767dd53d333SJames Smart
2768dd53d333SJames Smart if (sli_els_request64_wqe(&hw->sli, hio->wqe.wqebuf, hio->sgl,
2769dd53d333SJames Smart &els_params)) {
2770dd53d333SJames Smart efc_log_err(hw->os, "REQ WQE error\n");
2771dd53d333SJames Smart rc = -EIO;
2772dd53d333SJames Smart }
2773dd53d333SJames Smart break;
2774dd53d333SJames Smart }
2775dd53d333SJames Smart case EFC_DISC_IO_ELS_RESP: {
2776dd53d333SJames Smart struct sli_els_params els_params;
2777dd53d333SJames Smart
2778dd53d333SJames Smart hio->type = EFCT_HW_ELS_RSP;
2779dd53d333SJames Smart efct_fill_els_params(io, &els_params);
2780dd53d333SJames Smart els_params.xri = hio->indicator;
2781dd53d333SJames Smart els_params.tag = hio->reqtag;
2782dd53d333SJames Smart if (sli_xmit_els_rsp64_wqe(&hw->sli, hio->wqe.wqebuf, send,
2783dd53d333SJames Smart &els_params)){
2784dd53d333SJames Smart efc_log_err(hw->os, "RSP WQE error\n");
2785dd53d333SJames Smart rc = -EIO;
2786dd53d333SJames Smart }
2787dd53d333SJames Smart break;
2788dd53d333SJames Smart }
2789dd53d333SJames Smart case EFC_DISC_IO_CT_REQ: {
2790dd53d333SJames Smart struct sli_ct_params ct_params;
2791dd53d333SJames Smart
2792dd53d333SJames Smart hio->type = EFCT_HW_FC_CT;
2793dd53d333SJames Smart efct_fill_ct_params(io, &ct_params);
2794dd53d333SJames Smart ct_params.xri = hio->indicator;
2795dd53d333SJames Smart ct_params.tag = hio->reqtag;
2796dd53d333SJames Smart if (sli_gen_request64_wqe(&hw->sli, hio->wqe.wqebuf, hio->sgl,
2797dd53d333SJames Smart &ct_params)){
2798dd53d333SJames Smart efc_log_err(hw->os, "GEN WQE error\n");
2799dd53d333SJames Smart rc = -EIO;
2800dd53d333SJames Smart }
2801dd53d333SJames Smart break;
2802dd53d333SJames Smart }
2803dd53d333SJames Smart case EFC_DISC_IO_CT_RESP: {
2804dd53d333SJames Smart struct sli_ct_params ct_params;
2805dd53d333SJames Smart
2806dd53d333SJames Smart hio->type = EFCT_HW_FC_CT_RSP;
2807dd53d333SJames Smart efct_fill_ct_params(io, &ct_params);
2808dd53d333SJames Smart ct_params.xri = hio->indicator;
2809dd53d333SJames Smart ct_params.tag = hio->reqtag;
2810dd53d333SJames Smart if (sli_xmit_sequence64_wqe(&hw->sli, hio->wqe.wqebuf, hio->sgl,
2811dd53d333SJames Smart &ct_params)){
2812dd53d333SJames Smart efc_log_err(hw->os, "XMIT SEQ WQE error\n");
2813dd53d333SJames Smart rc = -EIO;
2814dd53d333SJames Smart }
2815dd53d333SJames Smart break;
2816dd53d333SJames Smart }
2817dd53d333SJames Smart default:
2818dd53d333SJames Smart efc_log_err(hw->os, "bad SRRS type %#x\n", io->io_type);
2819dd53d333SJames Smart rc = -EIO;
2820dd53d333SJames Smart }
2821dd53d333SJames Smart
2822dd53d333SJames Smart if (rc == 0) {
2823dd53d333SJames Smart hio->xbusy = true;
2824dd53d333SJames Smart
2825dd53d333SJames Smart /*
2826dd53d333SJames Smart * Add IO to active io wqe list before submitting, in case the
2827dd53d333SJames Smart * wcqe processing preempts this thread.
2828dd53d333SJames Smart */
2829dd53d333SJames Smart hio->wq->use_count++;
2830dd53d333SJames Smart rc = efct_hw_wq_write(hio->wq, &hio->wqe);
2831dd53d333SJames Smart if (rc >= 0) {
2832dd53d333SJames Smart /* non-negative return is success */
2833dd53d333SJames Smart rc = 0;
2834dd53d333SJames Smart } else {
2835dd53d333SJames Smart /* failed to write wqe, remove from active wqe list */
2836dd53d333SJames Smart efc_log_err(hw->os,
2837dd53d333SJames Smart "sli_queue_write failed: %d\n", rc);
2838dd53d333SJames Smart hio->xbusy = false;
2839dd53d333SJames Smart }
2840dd53d333SJames Smart }
2841dd53d333SJames Smart
2842dd53d333SJames Smart return rc;
2843dd53d333SJames Smart }
2844dd53d333SJames Smart
2845dd53d333SJames Smart int
efct_hw_io_send(struct efct_hw * hw,enum efct_hw_io_type type,struct efct_hw_io * io,union efct_hw_io_param_u * iparam,void * cb,void * arg)2846dd53d333SJames Smart efct_hw_io_send(struct efct_hw *hw, enum efct_hw_io_type type,
2847dd53d333SJames Smart struct efct_hw_io *io, union efct_hw_io_param_u *iparam,
2848dd53d333SJames Smart void *cb, void *arg)
2849dd53d333SJames Smart {
2850dd53d333SJames Smart int rc = 0;
2851dd53d333SJames Smart bool send_wqe = true;
2852dd53d333SJames Smart
2853dd53d333SJames Smart if (!io) {
2854dd53d333SJames Smart pr_err("bad parm hw=%p io=%p\n", hw, io);
2855dd53d333SJames Smart return -EIO;
2856dd53d333SJames Smart }
2857dd53d333SJames Smart
2858dd53d333SJames Smart if (hw->state != EFCT_HW_STATE_ACTIVE) {
2859dd53d333SJames Smart efc_log_err(hw->os, "cannot send IO, HW state=%d\n", hw->state);
2860dd53d333SJames Smart return -EIO;
2861dd53d333SJames Smart }
2862dd53d333SJames Smart
2863dd53d333SJames Smart /*
2864dd53d333SJames Smart * Save state needed during later stages
2865dd53d333SJames Smart */
2866dd53d333SJames Smart io->type = type;
2867dd53d333SJames Smart io->done = cb;
2868dd53d333SJames Smart io->arg = arg;
2869dd53d333SJames Smart
2870dd53d333SJames Smart /*
2871dd53d333SJames Smart * Format the work queue entry used to send the IO
2872dd53d333SJames Smart */
2873dd53d333SJames Smart switch (type) {
2874dd53d333SJames Smart case EFCT_HW_IO_TARGET_WRITE: {
2875dd53d333SJames Smart u16 *flags = &iparam->fcp_tgt.flags;
2876dd53d333SJames Smart struct fcp_txrdy *xfer = io->xfer_rdy.virt;
2877dd53d333SJames Smart
2878dd53d333SJames Smart /*
2879dd53d333SJames Smart * Fill in the XFER_RDY for IF_TYPE 0 devices
2880dd53d333SJames Smart */
2881dd53d333SJames Smart xfer->ft_data_ro = cpu_to_be32(iparam->fcp_tgt.offset);
2882dd53d333SJames Smart xfer->ft_burst_len = cpu_to_be32(iparam->fcp_tgt.xmit_len);
2883dd53d333SJames Smart
2884dd53d333SJames Smart if (io->xbusy)
2885dd53d333SJames Smart *flags |= SLI4_IO_CONTINUATION;
2886dd53d333SJames Smart else
2887dd53d333SJames Smart *flags &= ~SLI4_IO_CONTINUATION;
2888dd53d333SJames Smart iparam->fcp_tgt.xri = io->indicator;
2889dd53d333SJames Smart iparam->fcp_tgt.tag = io->reqtag;
2890dd53d333SJames Smart
2891dd53d333SJames Smart if (sli_fcp_treceive64_wqe(&hw->sli, io->wqe.wqebuf,
2892dd53d333SJames Smart &io->def_sgl, io->first_data_sge,
2893dd53d333SJames Smart SLI4_CQ_DEFAULT,
2894dd53d333SJames Smart 0, 0, &iparam->fcp_tgt)) {
2895dd53d333SJames Smart efc_log_err(hw->os, "TRECEIVE WQE error\n");
2896dd53d333SJames Smart rc = -EIO;
2897dd53d333SJames Smart }
2898dd53d333SJames Smart break;
2899dd53d333SJames Smart }
2900dd53d333SJames Smart case EFCT_HW_IO_TARGET_READ: {
2901dd53d333SJames Smart u16 *flags = &iparam->fcp_tgt.flags;
2902dd53d333SJames Smart
2903dd53d333SJames Smart if (io->xbusy)
2904dd53d333SJames Smart *flags |= SLI4_IO_CONTINUATION;
2905dd53d333SJames Smart else
2906dd53d333SJames Smart *flags &= ~SLI4_IO_CONTINUATION;
2907dd53d333SJames Smart
2908dd53d333SJames Smart iparam->fcp_tgt.xri = io->indicator;
2909dd53d333SJames Smart iparam->fcp_tgt.tag = io->reqtag;
2910dd53d333SJames Smart
2911dd53d333SJames Smart if (sli_fcp_tsend64_wqe(&hw->sli, io->wqe.wqebuf,
2912dd53d333SJames Smart &io->def_sgl, io->first_data_sge,
2913dd53d333SJames Smart SLI4_CQ_DEFAULT,
2914dd53d333SJames Smart 0, 0, &iparam->fcp_tgt)) {
2915dd53d333SJames Smart efc_log_err(hw->os, "TSEND WQE error\n");
2916dd53d333SJames Smart rc = -EIO;
2917dd53d333SJames Smart }
2918dd53d333SJames Smart break;
2919dd53d333SJames Smart }
2920dd53d333SJames Smart case EFCT_HW_IO_TARGET_RSP: {
2921dd53d333SJames Smart u16 *flags = &iparam->fcp_tgt.flags;
2922dd53d333SJames Smart
2923dd53d333SJames Smart if (io->xbusy)
2924dd53d333SJames Smart *flags |= SLI4_IO_CONTINUATION;
2925dd53d333SJames Smart else
2926dd53d333SJames Smart *flags &= ~SLI4_IO_CONTINUATION;
2927dd53d333SJames Smart
2928dd53d333SJames Smart iparam->fcp_tgt.xri = io->indicator;
2929dd53d333SJames Smart iparam->fcp_tgt.tag = io->reqtag;
2930dd53d333SJames Smart
2931dd53d333SJames Smart if (sli_fcp_trsp64_wqe(&hw->sli, io->wqe.wqebuf,
2932dd53d333SJames Smart &io->def_sgl, SLI4_CQ_DEFAULT,
2933dd53d333SJames Smart 0, &iparam->fcp_tgt)) {
2934dd53d333SJames Smart efc_log_err(hw->os, "TRSP WQE error\n");
2935dd53d333SJames Smart rc = -EIO;
2936dd53d333SJames Smart }
2937dd53d333SJames Smart
2938dd53d333SJames Smart break;
2939dd53d333SJames Smart }
2940dd53d333SJames Smart default:
2941dd53d333SJames Smart efc_log_err(hw->os, "unsupported IO type %#x\n", type);
2942dd53d333SJames Smart rc = -EIO;
2943dd53d333SJames Smart }
2944dd53d333SJames Smart
2945dd53d333SJames Smart if (send_wqe && rc == 0) {
2946dd53d333SJames Smart io->xbusy = true;
2947dd53d333SJames Smart
2948dd53d333SJames Smart /*
2949dd53d333SJames Smart * Add IO to active io wqe list before submitting, in case the
2950dd53d333SJames Smart * wcqe processing preempts this thread.
2951dd53d333SJames Smart */
2952dd53d333SJames Smart hw->tcmd_wq_submit[io->wq->instance]++;
2953dd53d333SJames Smart io->wq->use_count++;
2954dd53d333SJames Smart rc = efct_hw_wq_write(io->wq, &io->wqe);
2955dd53d333SJames Smart if (rc >= 0) {
2956dd53d333SJames Smart /* non-negative return is success */
2957dd53d333SJames Smart rc = 0;
2958dd53d333SJames Smart } else {
2959dd53d333SJames Smart /* failed to write wqe, remove from active wqe list */
2960dd53d333SJames Smart efc_log_err(hw->os,
2961dd53d333SJames Smart "sli_queue_write failed: %d\n", rc);
2962dd53d333SJames Smart io->xbusy = false;
2963dd53d333SJames Smart }
2964dd53d333SJames Smart }
2965dd53d333SJames Smart
2966dd53d333SJames Smart return rc;
2967dd53d333SJames Smart }
2968dd53d333SJames Smart
2969dd53d333SJames Smart int
efct_hw_send_frame(struct efct_hw * hw,struct fc_frame_header * hdr,u8 sof,u8 eof,struct efc_dma * payload,struct efct_hw_send_frame_context * ctx,void (* callback)(void * arg,u8 * cqe,int status),void * arg)2970dd53d333SJames Smart efct_hw_send_frame(struct efct_hw *hw, struct fc_frame_header *hdr,
2971dd53d333SJames Smart u8 sof, u8 eof, struct efc_dma *payload,
2972dd53d333SJames Smart struct efct_hw_send_frame_context *ctx,
2973dd53d333SJames Smart void (*callback)(void *arg, u8 *cqe, int status),
2974dd53d333SJames Smart void *arg)
2975dd53d333SJames Smart {
2976dd53d333SJames Smart int rc;
2977dd53d333SJames Smart struct efct_hw_wqe *wqe;
2978dd53d333SJames Smart u32 xri;
2979dd53d333SJames Smart struct hw_wq *wq;
2980dd53d333SJames Smart
2981dd53d333SJames Smart wqe = &ctx->wqe;
2982dd53d333SJames Smart
2983dd53d333SJames Smart /* populate the callback object */
2984dd53d333SJames Smart ctx->hw = hw;
2985dd53d333SJames Smart
2986dd53d333SJames Smart /* Fetch and populate request tag */
2987dd53d333SJames Smart ctx->wqcb = efct_hw_reqtag_alloc(hw, callback, arg);
2988dd53d333SJames Smart if (!ctx->wqcb) {
2989dd53d333SJames Smart efc_log_err(hw->os, "can't allocate request tag\n");
2990dd53d333SJames Smart return -ENOSPC;
2991dd53d333SJames Smart }
2992dd53d333SJames Smart
2993dd53d333SJames Smart wq = hw->hw_wq[0];
2994dd53d333SJames Smart
2995dd53d333SJames Smart /* Set XRI and RX_ID in the header based on which WQ, and which
2996dd53d333SJames Smart * send_frame_io we are using
2997dd53d333SJames Smart */
2998dd53d333SJames Smart xri = wq->send_frame_io->indicator;
2999dd53d333SJames Smart
3000dd53d333SJames Smart /* Build the send frame WQE */
3001dd53d333SJames Smart rc = sli_send_frame_wqe(&hw->sli, wqe->wqebuf,
3002dd53d333SJames Smart sof, eof, (u32 *)hdr, payload, payload->len,
3003dd53d333SJames Smart EFCT_HW_SEND_FRAME_TIMEOUT, xri,
3004dd53d333SJames Smart ctx->wqcb->instance_index);
3005dd53d333SJames Smart if (rc) {
3006dd53d333SJames Smart efc_log_err(hw->os, "sli_send_frame_wqe failed: %d\n", rc);
3007dd53d333SJames Smart return -EIO;
3008dd53d333SJames Smart }
3009dd53d333SJames Smart
3010dd53d333SJames Smart /* Write to WQ */
3011dd53d333SJames Smart rc = efct_hw_wq_write(wq, wqe);
3012dd53d333SJames Smart if (rc) {
3013dd53d333SJames Smart efc_log_err(hw->os, "efct_hw_wq_write failed: %d\n", rc);
3014dd53d333SJames Smart return -EIO;
3015dd53d333SJames Smart }
3016dd53d333SJames Smart
3017dd53d333SJames Smart wq->use_count++;
3018dd53d333SJames Smart
3019dd53d333SJames Smart return 0;
3020dd53d333SJames Smart }
30216ae7147bSJames Smart
30226ae7147bSJames Smart static int
efct_hw_cb_link_stat(struct efct_hw * hw,int status,u8 * mqe,void * arg)30236ae7147bSJames Smart efct_hw_cb_link_stat(struct efct_hw *hw, int status,
30246ae7147bSJames Smart u8 *mqe, void *arg)
30256ae7147bSJames Smart {
30266ae7147bSJames Smart struct sli4_cmd_read_link_stats *mbox_rsp;
30276ae7147bSJames Smart struct efct_hw_link_stat_cb_arg *cb_arg = arg;
30286ae7147bSJames Smart struct efct_hw_link_stat_counts counts[EFCT_HW_LINK_STAT_MAX];
30296ae7147bSJames Smart u32 num_counters, i;
30306ae7147bSJames Smart u32 mbox_rsp_flags = 0;
30316ae7147bSJames Smart
30326ae7147bSJames Smart mbox_rsp = (struct sli4_cmd_read_link_stats *)mqe;
30336ae7147bSJames Smart mbox_rsp_flags = le32_to_cpu(mbox_rsp->dw1_flags);
30346ae7147bSJames Smart num_counters = (mbox_rsp_flags & SLI4_READ_LNKSTAT_GEC) ? 20 : 13;
30356ae7147bSJames Smart memset(counts, 0, sizeof(struct efct_hw_link_stat_counts) *
30366ae7147bSJames Smart EFCT_HW_LINK_STAT_MAX);
30376ae7147bSJames Smart
30386ae7147bSJames Smart /* Fill overflow counts, mask starts from SLI4_READ_LNKSTAT_W02OF*/
30396ae7147bSJames Smart for (i = 0; i < EFCT_HW_LINK_STAT_MAX; i++)
30406ae7147bSJames Smart counts[i].overflow = (mbox_rsp_flags & (1 << (i + 2)));
30416ae7147bSJames Smart
30426ae7147bSJames Smart counts[EFCT_HW_LINK_STAT_LINK_FAILURE_COUNT].counter =
30436ae7147bSJames Smart le32_to_cpu(mbox_rsp->linkfail_errcnt);
30446ae7147bSJames Smart counts[EFCT_HW_LINK_STAT_LOSS_OF_SYNC_COUNT].counter =
30456ae7147bSJames Smart le32_to_cpu(mbox_rsp->losssync_errcnt);
30466ae7147bSJames Smart counts[EFCT_HW_LINK_STAT_LOSS_OF_SIGNAL_COUNT].counter =
30476ae7147bSJames Smart le32_to_cpu(mbox_rsp->losssignal_errcnt);
30486ae7147bSJames Smart counts[EFCT_HW_LINK_STAT_PRIMITIVE_SEQ_COUNT].counter =
30496ae7147bSJames Smart le32_to_cpu(mbox_rsp->primseq_errcnt);
30506ae7147bSJames Smart counts[EFCT_HW_LINK_STAT_INVALID_XMIT_WORD_COUNT].counter =
30516ae7147bSJames Smart le32_to_cpu(mbox_rsp->inval_txword_errcnt);
30526ae7147bSJames Smart counts[EFCT_HW_LINK_STAT_CRC_COUNT].counter =
30536ae7147bSJames Smart le32_to_cpu(mbox_rsp->crc_errcnt);
30546ae7147bSJames Smart counts[EFCT_HW_LINK_STAT_PRIMITIVE_SEQ_TIMEOUT_COUNT].counter =
30556ae7147bSJames Smart le32_to_cpu(mbox_rsp->primseq_eventtimeout_cnt);
30566ae7147bSJames Smart counts[EFCT_HW_LINK_STAT_ELASTIC_BUFFER_OVERRUN_COUNT].counter =
30576ae7147bSJames Smart le32_to_cpu(mbox_rsp->elastic_bufoverrun_errcnt);
30586ae7147bSJames Smart counts[EFCT_HW_LINK_STAT_ARB_TIMEOUT_COUNT].counter =
30596ae7147bSJames Smart le32_to_cpu(mbox_rsp->arbit_fc_al_timeout_cnt);
30606ae7147bSJames Smart counts[EFCT_HW_LINK_STAT_ADVERTISED_RCV_B2B_CREDIT].counter =
30616ae7147bSJames Smart le32_to_cpu(mbox_rsp->adv_rx_buftor_to_buf_credit);
30626ae7147bSJames Smart counts[EFCT_HW_LINK_STAT_CURR_RCV_B2B_CREDIT].counter =
30636ae7147bSJames Smart le32_to_cpu(mbox_rsp->curr_rx_buf_to_buf_credit);
30646ae7147bSJames Smart counts[EFCT_HW_LINK_STAT_ADVERTISED_XMIT_B2B_CREDIT].counter =
30656ae7147bSJames Smart le32_to_cpu(mbox_rsp->adv_tx_buf_to_buf_credit);
30666ae7147bSJames Smart counts[EFCT_HW_LINK_STAT_CURR_XMIT_B2B_CREDIT].counter =
30676ae7147bSJames Smart le32_to_cpu(mbox_rsp->curr_tx_buf_to_buf_credit);
30686ae7147bSJames Smart counts[EFCT_HW_LINK_STAT_RCV_EOFA_COUNT].counter =
30696ae7147bSJames Smart le32_to_cpu(mbox_rsp->rx_eofa_cnt);
30706ae7147bSJames Smart counts[EFCT_HW_LINK_STAT_RCV_EOFDTI_COUNT].counter =
30716ae7147bSJames Smart le32_to_cpu(mbox_rsp->rx_eofdti_cnt);
30726ae7147bSJames Smart counts[EFCT_HW_LINK_STAT_RCV_EOFNI_COUNT].counter =
30736ae7147bSJames Smart le32_to_cpu(mbox_rsp->rx_eofni_cnt);
30746ae7147bSJames Smart counts[EFCT_HW_LINK_STAT_RCV_SOFF_COUNT].counter =
30756ae7147bSJames Smart le32_to_cpu(mbox_rsp->rx_soff_cnt);
30766ae7147bSJames Smart counts[EFCT_HW_LINK_STAT_RCV_DROPPED_NO_AER_COUNT].counter =
30776ae7147bSJames Smart le32_to_cpu(mbox_rsp->rx_dropped_no_aer_cnt);
30786ae7147bSJames Smart counts[EFCT_HW_LINK_STAT_RCV_DROPPED_NO_RPI_COUNT].counter =
30796ae7147bSJames Smart le32_to_cpu(mbox_rsp->rx_dropped_no_avail_rpi_rescnt);
30806ae7147bSJames Smart counts[EFCT_HW_LINK_STAT_RCV_DROPPED_NO_XRI_COUNT].counter =
30816ae7147bSJames Smart le32_to_cpu(mbox_rsp->rx_dropped_no_avail_xri_rescnt);
30826ae7147bSJames Smart
30836ae7147bSJames Smart if (cb_arg) {
30846ae7147bSJames Smart if (cb_arg->cb) {
30856ae7147bSJames Smart if (status == 0 && le16_to_cpu(mbox_rsp->hdr.status))
30866ae7147bSJames Smart status = le16_to_cpu(mbox_rsp->hdr.status);
30876ae7147bSJames Smart cb_arg->cb(status, num_counters, counts, cb_arg->arg);
30886ae7147bSJames Smart }
30896ae7147bSJames Smart
30906ae7147bSJames Smart kfree(cb_arg);
30916ae7147bSJames Smart }
30926ae7147bSJames Smart
30936ae7147bSJames Smart return 0;
30946ae7147bSJames Smart }
30956ae7147bSJames Smart
30966ae7147bSJames Smart int
efct_hw_get_link_stats(struct efct_hw * hw,u8 req_ext_counters,u8 clear_overflow_flags,u8 clear_all_counters,void (* cb)(int status,u32 num_counters,struct efct_hw_link_stat_counts * counters,void * arg),void * arg)30976ae7147bSJames Smart efct_hw_get_link_stats(struct efct_hw *hw, u8 req_ext_counters,
30986ae7147bSJames Smart u8 clear_overflow_flags, u8 clear_all_counters,
30996ae7147bSJames Smart void (*cb)(int status, u32 num_counters,
31006ae7147bSJames Smart struct efct_hw_link_stat_counts *counters,
31016ae7147bSJames Smart void *arg),
31026ae7147bSJames Smart void *arg)
31036ae7147bSJames Smart {
31046ae7147bSJames Smart int rc = -EIO;
31056ae7147bSJames Smart struct efct_hw_link_stat_cb_arg *cb_arg;
31066ae7147bSJames Smart u8 mbxdata[SLI4_BMBX_SIZE];
31076ae7147bSJames Smart
31086ae7147bSJames Smart cb_arg = kzalloc(sizeof(*cb_arg), GFP_ATOMIC);
31096ae7147bSJames Smart if (!cb_arg)
31106ae7147bSJames Smart return -ENOMEM;
31116ae7147bSJames Smart
31126ae7147bSJames Smart cb_arg->cb = cb;
31136ae7147bSJames Smart cb_arg->arg = arg;
31146ae7147bSJames Smart
31156ae7147bSJames Smart /* Send the HW command */
31166ae7147bSJames Smart if (!sli_cmd_read_link_stats(&hw->sli, mbxdata, req_ext_counters,
31176ae7147bSJames Smart clear_overflow_flags, clear_all_counters))
31186ae7147bSJames Smart rc = efct_hw_command(hw, mbxdata, EFCT_CMD_NOWAIT,
31196ae7147bSJames Smart efct_hw_cb_link_stat, cb_arg);
31206ae7147bSJames Smart
31216ae7147bSJames Smart if (rc)
31226ae7147bSJames Smart kfree(cb_arg);
31236ae7147bSJames Smart
31246ae7147bSJames Smart return rc;
31256ae7147bSJames Smart }
31266ae7147bSJames Smart
31276ae7147bSJames Smart static int
efct_hw_cb_host_stat(struct efct_hw * hw,int status,u8 * mqe,void * arg)31286ae7147bSJames Smart efct_hw_cb_host_stat(struct efct_hw *hw, int status, u8 *mqe, void *arg)
31296ae7147bSJames Smart {
31306ae7147bSJames Smart struct sli4_cmd_read_status *mbox_rsp =
31316ae7147bSJames Smart (struct sli4_cmd_read_status *)mqe;
31326ae7147bSJames Smart struct efct_hw_host_stat_cb_arg *cb_arg = arg;
31336ae7147bSJames Smart struct efct_hw_host_stat_counts counts[EFCT_HW_HOST_STAT_MAX];
31346ae7147bSJames Smart u32 num_counters = EFCT_HW_HOST_STAT_MAX;
31356ae7147bSJames Smart
31366ae7147bSJames Smart memset(counts, 0, sizeof(struct efct_hw_host_stat_counts) *
31376ae7147bSJames Smart EFCT_HW_HOST_STAT_MAX);
31386ae7147bSJames Smart
31396ae7147bSJames Smart counts[EFCT_HW_HOST_STAT_TX_KBYTE_COUNT].counter =
31406ae7147bSJames Smart le32_to_cpu(mbox_rsp->trans_kbyte_cnt);
31416ae7147bSJames Smart counts[EFCT_HW_HOST_STAT_RX_KBYTE_COUNT].counter =
31426ae7147bSJames Smart le32_to_cpu(mbox_rsp->recv_kbyte_cnt);
31436ae7147bSJames Smart counts[EFCT_HW_HOST_STAT_TX_FRAME_COUNT].counter =
31446ae7147bSJames Smart le32_to_cpu(mbox_rsp->trans_frame_cnt);
31456ae7147bSJames Smart counts[EFCT_HW_HOST_STAT_RX_FRAME_COUNT].counter =
31466ae7147bSJames Smart le32_to_cpu(mbox_rsp->recv_frame_cnt);
31476ae7147bSJames Smart counts[EFCT_HW_HOST_STAT_TX_SEQ_COUNT].counter =
31486ae7147bSJames Smart le32_to_cpu(mbox_rsp->trans_seq_cnt);
31496ae7147bSJames Smart counts[EFCT_HW_HOST_STAT_RX_SEQ_COUNT].counter =
31506ae7147bSJames Smart le32_to_cpu(mbox_rsp->recv_seq_cnt);
31516ae7147bSJames Smart counts[EFCT_HW_HOST_STAT_TOTAL_EXCH_ORIG].counter =
31526ae7147bSJames Smart le32_to_cpu(mbox_rsp->tot_exchanges_orig);
31536ae7147bSJames Smart counts[EFCT_HW_HOST_STAT_TOTAL_EXCH_RESP].counter =
31546ae7147bSJames Smart le32_to_cpu(mbox_rsp->tot_exchanges_resp);
31556ae7147bSJames Smart counts[EFCT_HW_HOSY_STAT_RX_P_BSY_COUNT].counter =
31566ae7147bSJames Smart le32_to_cpu(mbox_rsp->recv_p_bsy_cnt);
31576ae7147bSJames Smart counts[EFCT_HW_HOST_STAT_RX_F_BSY_COUNT].counter =
31586ae7147bSJames Smart le32_to_cpu(mbox_rsp->recv_f_bsy_cnt);
31596ae7147bSJames Smart counts[EFCT_HW_HOST_STAT_DROP_FRM_DUE_TO_NO_RQ_BUF_COUNT].counter =
31606ae7147bSJames Smart le32_to_cpu(mbox_rsp->no_rq_buf_dropped_frames_cnt);
31616ae7147bSJames Smart counts[EFCT_HW_HOST_STAT_EMPTY_RQ_TIMEOUT_COUNT].counter =
31626ae7147bSJames Smart le32_to_cpu(mbox_rsp->empty_rq_timeout_cnt);
31636ae7147bSJames Smart counts[EFCT_HW_HOST_STAT_DROP_FRM_DUE_TO_NO_XRI_COUNT].counter =
31646ae7147bSJames Smart le32_to_cpu(mbox_rsp->no_xri_dropped_frames_cnt);
31656ae7147bSJames Smart counts[EFCT_HW_HOST_STAT_EMPTY_XRI_POOL_COUNT].counter =
31666ae7147bSJames Smart le32_to_cpu(mbox_rsp->empty_xri_pool_cnt);
31676ae7147bSJames Smart
31686ae7147bSJames Smart if (cb_arg) {
31696ae7147bSJames Smart if (cb_arg->cb) {
31706ae7147bSJames Smart if (status == 0 && le16_to_cpu(mbox_rsp->hdr.status))
31716ae7147bSJames Smart status = le16_to_cpu(mbox_rsp->hdr.status);
31726ae7147bSJames Smart cb_arg->cb(status, num_counters, counts, cb_arg->arg);
31736ae7147bSJames Smart }
31746ae7147bSJames Smart
31756ae7147bSJames Smart kfree(cb_arg);
31766ae7147bSJames Smart }
31776ae7147bSJames Smart
31786ae7147bSJames Smart return 0;
31796ae7147bSJames Smart }
31806ae7147bSJames Smart
31816ae7147bSJames Smart int
efct_hw_get_host_stats(struct efct_hw * hw,u8 cc,void (* cb)(int status,u32 num_counters,struct efct_hw_host_stat_counts * counters,void * arg),void * arg)31826ae7147bSJames Smart efct_hw_get_host_stats(struct efct_hw *hw, u8 cc,
31836ae7147bSJames Smart void (*cb)(int status, u32 num_counters,
31846ae7147bSJames Smart struct efct_hw_host_stat_counts *counters,
31856ae7147bSJames Smart void *arg),
31866ae7147bSJames Smart void *arg)
31876ae7147bSJames Smart {
31886ae7147bSJames Smart int rc = -EIO;
31896ae7147bSJames Smart struct efct_hw_host_stat_cb_arg *cb_arg;
31906ae7147bSJames Smart u8 mbxdata[SLI4_BMBX_SIZE];
31916ae7147bSJames Smart
31926ae7147bSJames Smart cb_arg = kmalloc(sizeof(*cb_arg), GFP_ATOMIC);
31936ae7147bSJames Smart if (!cb_arg)
31946ae7147bSJames Smart return -ENOMEM;
31956ae7147bSJames Smart
31966ae7147bSJames Smart cb_arg->cb = cb;
31976ae7147bSJames Smart cb_arg->arg = arg;
31986ae7147bSJames Smart
31996ae7147bSJames Smart /* Send the HW command to get the host stats */
32006ae7147bSJames Smart if (!sli_cmd_read_status(&hw->sli, mbxdata, cc))
32016ae7147bSJames Smart rc = efct_hw_command(hw, mbxdata, EFCT_CMD_NOWAIT,
32026ae7147bSJames Smart efct_hw_cb_host_stat, cb_arg);
32036ae7147bSJames Smart
32046ae7147bSJames Smart if (rc) {
32056ae7147bSJames Smart efc_log_debug(hw->os, "READ_HOST_STATS failed\n");
32066ae7147bSJames Smart kfree(cb_arg);
32076ae7147bSJames Smart }
32086ae7147bSJames Smart
32096ae7147bSJames Smart return rc;
32106ae7147bSJames Smart }
32116ae7147bSJames Smart
32126ae7147bSJames Smart struct efct_hw_async_call_ctx {
32136ae7147bSJames Smart efct_hw_async_cb_t callback;
32146ae7147bSJames Smart void *arg;
32156ae7147bSJames Smart u8 cmd[SLI4_BMBX_SIZE];
32166ae7147bSJames Smart };
32176ae7147bSJames Smart
32186ae7147bSJames Smart static void
efct_hw_async_cb(struct efct_hw * hw,int status,u8 * mqe,void * arg)32196ae7147bSJames Smart efct_hw_async_cb(struct efct_hw *hw, int status, u8 *mqe, void *arg)
32206ae7147bSJames Smart {
32216ae7147bSJames Smart struct efct_hw_async_call_ctx *ctx = arg;
32226ae7147bSJames Smart
32236ae7147bSJames Smart if (ctx) {
32246ae7147bSJames Smart if (ctx->callback)
32256ae7147bSJames Smart (*ctx->callback)(hw, status, mqe, ctx->arg);
32266ae7147bSJames Smart
32276ae7147bSJames Smart kfree(ctx);
32286ae7147bSJames Smart }
32296ae7147bSJames Smart }
32306ae7147bSJames Smart
32316ae7147bSJames Smart int
efct_hw_async_call(struct efct_hw * hw,efct_hw_async_cb_t callback,void * arg)32326ae7147bSJames Smart efct_hw_async_call(struct efct_hw *hw, efct_hw_async_cb_t callback, void *arg)
32336ae7147bSJames Smart {
32346ae7147bSJames Smart struct efct_hw_async_call_ctx *ctx;
32356ae7147bSJames Smart int rc;
32366ae7147bSJames Smart
32376ae7147bSJames Smart /*
32386ae7147bSJames Smart * Allocate a callback context (which includes the mbox cmd buffer),
32396ae7147bSJames Smart * we need this to be persistent as the mbox cmd submission may be
32406ae7147bSJames Smart * queued and executed later execution.
32416ae7147bSJames Smart */
32426ae7147bSJames Smart ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
32436ae7147bSJames Smart if (!ctx)
32446ae7147bSJames Smart return -ENOMEM;
32456ae7147bSJames Smart
32466ae7147bSJames Smart ctx->callback = callback;
32476ae7147bSJames Smart ctx->arg = arg;
32486ae7147bSJames Smart
32496ae7147bSJames Smart /* Build and send a NOP mailbox command */
32506ae7147bSJames Smart if (sli_cmd_common_nop(&hw->sli, ctx->cmd, 0)) {
32516ae7147bSJames Smart efc_log_err(hw->os, "COMMON_NOP format failure\n");
32526ae7147bSJames Smart kfree(ctx);
32536ae7147bSJames Smart return -EIO;
32546ae7147bSJames Smart }
32556ae7147bSJames Smart
32566ae7147bSJames Smart rc = efct_hw_command(hw, ctx->cmd, EFCT_CMD_NOWAIT, efct_hw_async_cb,
32576ae7147bSJames Smart ctx);
32586ae7147bSJames Smart if (rc) {
32596ae7147bSJames Smart efc_log_err(hw->os, "COMMON_NOP command failure, rc=%d\n", rc);
32606ae7147bSJames Smart kfree(ctx);
32616ae7147bSJames Smart return -EIO;
32626ae7147bSJames Smart }
32636ae7147bSJames Smart return 0;
32646ae7147bSJames Smart }
32656ae7147bSJames Smart
32666ae7147bSJames Smart static int
efct_hw_cb_fw_write(struct efct_hw * hw,int status,u8 * mqe,void * arg)32676ae7147bSJames Smart efct_hw_cb_fw_write(struct efct_hw *hw, int status, u8 *mqe, void *arg)
32686ae7147bSJames Smart {
32696ae7147bSJames Smart struct sli4_cmd_sli_config *mbox_rsp =
32706ae7147bSJames Smart (struct sli4_cmd_sli_config *)mqe;
32716ae7147bSJames Smart struct sli4_rsp_cmn_write_object *wr_obj_rsp;
32726ae7147bSJames Smart struct efct_hw_fw_wr_cb_arg *cb_arg = arg;
32736ae7147bSJames Smart u32 bytes_written;
32746ae7147bSJames Smart u16 mbox_status;
32756ae7147bSJames Smart u32 change_status;
32766ae7147bSJames Smart
32776ae7147bSJames Smart wr_obj_rsp = (struct sli4_rsp_cmn_write_object *)
32786ae7147bSJames Smart &mbox_rsp->payload.embed;
32796ae7147bSJames Smart bytes_written = le32_to_cpu(wr_obj_rsp->actual_write_length);
32806ae7147bSJames Smart mbox_status = le16_to_cpu(mbox_rsp->hdr.status);
32816ae7147bSJames Smart change_status = (le32_to_cpu(wr_obj_rsp->change_status_dword) &
32826ae7147bSJames Smart RSP_CHANGE_STATUS);
32836ae7147bSJames Smart
32846ae7147bSJames Smart if (cb_arg) {
32856ae7147bSJames Smart if (cb_arg->cb) {
32866ae7147bSJames Smart if (!status && mbox_status)
32876ae7147bSJames Smart status = mbox_status;
32886ae7147bSJames Smart cb_arg->cb(status, bytes_written, change_status,
32896ae7147bSJames Smart cb_arg->arg);
32906ae7147bSJames Smart }
32916ae7147bSJames Smart
32926ae7147bSJames Smart kfree(cb_arg);
32936ae7147bSJames Smart }
32946ae7147bSJames Smart
32956ae7147bSJames Smart return 0;
32966ae7147bSJames Smart }
32976ae7147bSJames Smart
32986ae7147bSJames Smart int
efct_hw_firmware_write(struct efct_hw * hw,struct efc_dma * dma,u32 size,u32 offset,int last,void (* cb)(int status,u32 bytes_written,u32 change_status,void * arg),void * arg)32996ae7147bSJames Smart efct_hw_firmware_write(struct efct_hw *hw, struct efc_dma *dma, u32 size,
33006ae7147bSJames Smart u32 offset, int last,
33016ae7147bSJames Smart void (*cb)(int status, u32 bytes_written,
33026ae7147bSJames Smart u32 change_status, void *arg),
33036ae7147bSJames Smart void *arg)
33046ae7147bSJames Smart {
33056ae7147bSJames Smart int rc = -EIO;
33066ae7147bSJames Smart u8 mbxdata[SLI4_BMBX_SIZE];
33076ae7147bSJames Smart struct efct_hw_fw_wr_cb_arg *cb_arg;
33086ae7147bSJames Smart int noc = 0;
33096ae7147bSJames Smart
33106ae7147bSJames Smart cb_arg = kzalloc(sizeof(*cb_arg), GFP_KERNEL);
33116ae7147bSJames Smart if (!cb_arg)
33126ae7147bSJames Smart return -ENOMEM;
33136ae7147bSJames Smart
33146ae7147bSJames Smart cb_arg->cb = cb;
33156ae7147bSJames Smart cb_arg->arg = arg;
33166ae7147bSJames Smart
33176ae7147bSJames Smart /* Write a portion of a firmware image to the device */
33186ae7147bSJames Smart if (!sli_cmd_common_write_object(&hw->sli, mbxdata,
33196ae7147bSJames Smart noc, last, size, offset, "/prg/",
33206ae7147bSJames Smart dma))
33216ae7147bSJames Smart rc = efct_hw_command(hw, mbxdata, EFCT_CMD_NOWAIT,
33226ae7147bSJames Smart efct_hw_cb_fw_write, cb_arg);
33236ae7147bSJames Smart
33246ae7147bSJames Smart if (rc != 0) {
33256ae7147bSJames Smart efc_log_debug(hw->os, "COMMON_WRITE_OBJECT failed\n");
33266ae7147bSJames Smart kfree(cb_arg);
33276ae7147bSJames Smart }
33286ae7147bSJames Smart
33296ae7147bSJames Smart return rc;
33306ae7147bSJames Smart }
3331ab332fcbSJames Smart
3332ab332fcbSJames Smart static int
efct_hw_cb_port_control(struct efct_hw * hw,int status,u8 * mqe,void * arg)3333ab332fcbSJames Smart efct_hw_cb_port_control(struct efct_hw *hw, int status, u8 *mqe,
3334ab332fcbSJames Smart void *arg)
3335ab332fcbSJames Smart {
3336ab332fcbSJames Smart return 0;
3337ab332fcbSJames Smart }
3338ab332fcbSJames Smart
3339ab332fcbSJames Smart int
efct_hw_port_control(struct efct_hw * hw,enum efct_hw_port ctrl,uintptr_t value,void (* cb)(int status,uintptr_t value,void * arg),void * arg)3340ab332fcbSJames Smart efct_hw_port_control(struct efct_hw *hw, enum efct_hw_port ctrl,
3341ab332fcbSJames Smart uintptr_t value,
3342ab332fcbSJames Smart void (*cb)(int status, uintptr_t value, void *arg),
3343ab332fcbSJames Smart void *arg)
3344ab332fcbSJames Smart {
3345ab332fcbSJames Smart int rc = -EIO;
3346ab332fcbSJames Smart u8 link[SLI4_BMBX_SIZE];
3347ab332fcbSJames Smart u32 speed = 0;
3348ab332fcbSJames Smart u8 reset_alpa = 0;
3349ab332fcbSJames Smart
3350ab332fcbSJames Smart switch (ctrl) {
3351ab332fcbSJames Smart case EFCT_HW_PORT_INIT:
3352ab332fcbSJames Smart if (!sli_cmd_config_link(&hw->sli, link))
3353ab332fcbSJames Smart rc = efct_hw_command(hw, link, EFCT_CMD_NOWAIT,
3354ab332fcbSJames Smart efct_hw_cb_port_control, NULL);
3355ab332fcbSJames Smart
3356ab332fcbSJames Smart if (rc != 0) {
3357ab332fcbSJames Smart efc_log_err(hw->os, "CONFIG_LINK failed\n");
3358ab332fcbSJames Smart break;
3359ab332fcbSJames Smart }
3360ab332fcbSJames Smart speed = hw->config.speed;
3361ab332fcbSJames Smart reset_alpa = (u8)(value & 0xff);
3362ab332fcbSJames Smart
3363ab332fcbSJames Smart rc = -EIO;
3364ab332fcbSJames Smart if (!sli_cmd_init_link(&hw->sli, link, speed, reset_alpa))
3365ab332fcbSJames Smart rc = efct_hw_command(hw, link, EFCT_CMD_NOWAIT,
3366ab332fcbSJames Smart efct_hw_cb_port_control, NULL);
3367ab332fcbSJames Smart /* Free buffer on error, since no callback is coming */
3368ab332fcbSJames Smart if (rc)
3369ab332fcbSJames Smart efc_log_err(hw->os, "INIT_LINK failed\n");
3370ab332fcbSJames Smart break;
3371ab332fcbSJames Smart
3372ab332fcbSJames Smart case EFCT_HW_PORT_SHUTDOWN:
3373ab332fcbSJames Smart if (!sli_cmd_down_link(&hw->sli, link))
3374ab332fcbSJames Smart rc = efct_hw_command(hw, link, EFCT_CMD_NOWAIT,
3375ab332fcbSJames Smart efct_hw_cb_port_control, NULL);
3376ab332fcbSJames Smart /* Free buffer on error, since no callback is coming */
3377ab332fcbSJames Smart if (rc)
3378ab332fcbSJames Smart efc_log_err(hw->os, "DOWN_LINK failed\n");
3379ab332fcbSJames Smart break;
3380ab332fcbSJames Smart
3381ab332fcbSJames Smart default:
3382ab332fcbSJames Smart efc_log_debug(hw->os, "unhandled control %#x\n", ctrl);
3383ab332fcbSJames Smart break;
3384ab332fcbSJames Smart }
3385ab332fcbSJames Smart
3386ab332fcbSJames Smart return rc;
3387ab332fcbSJames Smart }
3388ab332fcbSJames Smart
3389ab332fcbSJames Smart void
efct_hw_teardown(struct efct_hw * hw)3390ab332fcbSJames Smart efct_hw_teardown(struct efct_hw *hw)
3391ab332fcbSJames Smart {
3392ab332fcbSJames Smart u32 i = 0;
3393ab332fcbSJames Smart u32 destroy_queues;
3394ab332fcbSJames Smart u32 free_memory;
3395ab332fcbSJames Smart struct efc_dma *dma;
3396ab332fcbSJames Smart struct efct *efct = hw->os;
3397ab332fcbSJames Smart
3398ab332fcbSJames Smart destroy_queues = (hw->state == EFCT_HW_STATE_ACTIVE);
3399ab332fcbSJames Smart free_memory = (hw->state != EFCT_HW_STATE_UNINITIALIZED);
3400ab332fcbSJames Smart
3401ab332fcbSJames Smart /* Cancel Sliport Healthcheck */
3402ab332fcbSJames Smart if (hw->sliport_healthcheck) {
3403ab332fcbSJames Smart hw->sliport_healthcheck = 0;
3404ab332fcbSJames Smart efct_hw_config_sli_port_health_check(hw, 0, 0);
3405ab332fcbSJames Smart }
3406ab332fcbSJames Smart
3407ab332fcbSJames Smart if (hw->state != EFCT_HW_STATE_QUEUES_ALLOCATED) {
3408ab332fcbSJames Smart hw->state = EFCT_HW_STATE_TEARDOWN_IN_PROGRESS;
3409ab332fcbSJames Smart
3410ab332fcbSJames Smart efct_hw_flush(hw);
3411ab332fcbSJames Smart
3412ab332fcbSJames Smart if (list_empty(&hw->cmd_head))
3413ab332fcbSJames Smart efc_log_debug(hw->os,
3414ab332fcbSJames Smart "All commands completed on MQ queue\n");
3415ab332fcbSJames Smart else
3416ab332fcbSJames Smart efc_log_debug(hw->os,
3417ab332fcbSJames Smart "Some cmds still pending on MQ queue\n");
3418ab332fcbSJames Smart
3419ab332fcbSJames Smart /* Cancel any remaining commands */
3420ab332fcbSJames Smart efct_hw_command_cancel(hw);
3421ab332fcbSJames Smart } else {
3422ab332fcbSJames Smart hw->state = EFCT_HW_STATE_TEARDOWN_IN_PROGRESS;
3423ab332fcbSJames Smart }
3424ab332fcbSJames Smart
3425ab332fcbSJames Smart dma_free_coherent(&efct->pci->dev,
3426ab332fcbSJames Smart hw->rnode_mem.size, hw->rnode_mem.virt,
3427ab332fcbSJames Smart hw->rnode_mem.phys);
3428ab332fcbSJames Smart memset(&hw->rnode_mem, 0, sizeof(struct efc_dma));
3429ab332fcbSJames Smart
3430ab332fcbSJames Smart if (hw->io) {
3431ab332fcbSJames Smart for (i = 0; i < hw->config.n_io; i++) {
3432ab332fcbSJames Smart if (hw->io[i] && hw->io[i]->sgl &&
3433ab332fcbSJames Smart hw->io[i]->sgl->virt) {
3434ab332fcbSJames Smart dma_free_coherent(&efct->pci->dev,
3435ab332fcbSJames Smart hw->io[i]->sgl->size,
3436ab332fcbSJames Smart hw->io[i]->sgl->virt,
3437ab332fcbSJames Smart hw->io[i]->sgl->phys);
3438ab332fcbSJames Smart }
3439ab332fcbSJames Smart kfree(hw->io[i]);
3440ab332fcbSJames Smart hw->io[i] = NULL;
3441ab332fcbSJames Smart }
3442ab332fcbSJames Smart kfree(hw->io);
3443ab332fcbSJames Smart hw->io = NULL;
3444ab332fcbSJames Smart kfree(hw->wqe_buffs);
3445ab332fcbSJames Smart hw->wqe_buffs = NULL;
3446ab332fcbSJames Smart }
3447ab332fcbSJames Smart
3448ab332fcbSJames Smart dma = &hw->xfer_rdy;
3449ab332fcbSJames Smart dma_free_coherent(&efct->pci->dev,
3450ab332fcbSJames Smart dma->size, dma->virt, dma->phys);
3451ab332fcbSJames Smart memset(dma, 0, sizeof(struct efc_dma));
3452ab332fcbSJames Smart
3453ab332fcbSJames Smart dma = &hw->loop_map;
3454ab332fcbSJames Smart dma_free_coherent(&efct->pci->dev,
3455ab332fcbSJames Smart dma->size, dma->virt, dma->phys);
3456ab332fcbSJames Smart memset(dma, 0, sizeof(struct efc_dma));
3457ab332fcbSJames Smart
3458ab332fcbSJames Smart for (i = 0; i < hw->wq_count; i++)
3459ab332fcbSJames Smart sli_queue_free(&hw->sli, &hw->wq[i], destroy_queues,
3460ab332fcbSJames Smart free_memory);
3461ab332fcbSJames Smart
3462ab332fcbSJames Smart for (i = 0; i < hw->rq_count; i++)
3463ab332fcbSJames Smart sli_queue_free(&hw->sli, &hw->rq[i], destroy_queues,
3464ab332fcbSJames Smart free_memory);
3465ab332fcbSJames Smart
3466ab332fcbSJames Smart for (i = 0; i < hw->mq_count; i++)
3467ab332fcbSJames Smart sli_queue_free(&hw->sli, &hw->mq[i], destroy_queues,
3468ab332fcbSJames Smart free_memory);
3469ab332fcbSJames Smart
3470ab332fcbSJames Smart for (i = 0; i < hw->cq_count; i++)
3471ab332fcbSJames Smart sli_queue_free(&hw->sli, &hw->cq[i], destroy_queues,
3472ab332fcbSJames Smart free_memory);
3473ab332fcbSJames Smart
3474ab332fcbSJames Smart for (i = 0; i < hw->eq_count; i++)
3475ab332fcbSJames Smart sli_queue_free(&hw->sli, &hw->eq[i], destroy_queues,
3476ab332fcbSJames Smart free_memory);
3477ab332fcbSJames Smart
3478ab332fcbSJames Smart /* Free rq buffers */
3479ab332fcbSJames Smart efct_hw_rx_free(hw);
3480ab332fcbSJames Smart
3481ab332fcbSJames Smart efct_hw_queue_teardown(hw);
3482ab332fcbSJames Smart
3483ab332fcbSJames Smart kfree(hw->wq_cpu_array);
3484ab332fcbSJames Smart
3485ab332fcbSJames Smart sli_teardown(&hw->sli);
3486ab332fcbSJames Smart
3487ab332fcbSJames Smart /* record the fact that the queues are non-functional */
3488ab332fcbSJames Smart hw->state = EFCT_HW_STATE_UNINITIALIZED;
3489ab332fcbSJames Smart
3490ab332fcbSJames Smart /* free sequence free pool */
3491ab332fcbSJames Smart kfree(hw->seq_pool);
3492ab332fcbSJames Smart hw->seq_pool = NULL;
3493ab332fcbSJames Smart
3494ab332fcbSJames Smart /* free hw_wq_callback pool */
3495ab332fcbSJames Smart efct_hw_reqtag_pool_free(hw);
3496ab332fcbSJames Smart
3497ab332fcbSJames Smart mempool_destroy(hw->cmd_ctx_pool);
3498ab332fcbSJames Smart mempool_destroy(hw->mbox_rqst_pool);
3499ab332fcbSJames Smart
3500ab332fcbSJames Smart /* Mark HW setup as not having been called */
3501ab332fcbSJames Smart hw->hw_setup_called = false;
3502ab332fcbSJames Smart }
3503ab332fcbSJames Smart
3504ab332fcbSJames Smart static int
efct_hw_sli_reset(struct efct_hw * hw,enum efct_hw_reset reset,enum efct_hw_state prev_state)3505ab332fcbSJames Smart efct_hw_sli_reset(struct efct_hw *hw, enum efct_hw_reset reset,
3506ab332fcbSJames Smart enum efct_hw_state prev_state)
3507ab332fcbSJames Smart {
3508ab332fcbSJames Smart int rc = 0;
3509ab332fcbSJames Smart
3510ab332fcbSJames Smart switch (reset) {
3511ab332fcbSJames Smart case EFCT_HW_RESET_FUNCTION:
3512ab332fcbSJames Smart efc_log_debug(hw->os, "issuing function level reset\n");
3513ab332fcbSJames Smart if (sli_reset(&hw->sli)) {
3514ab332fcbSJames Smart efc_log_err(hw->os, "sli_reset failed\n");
3515ab332fcbSJames Smart rc = -EIO;
3516ab332fcbSJames Smart }
3517ab332fcbSJames Smart break;
3518ab332fcbSJames Smart case EFCT_HW_RESET_FIRMWARE:
3519ab332fcbSJames Smart efc_log_debug(hw->os, "issuing firmware reset\n");
3520ab332fcbSJames Smart if (sli_fw_reset(&hw->sli)) {
3521ab332fcbSJames Smart efc_log_err(hw->os, "sli_soft_reset failed\n");
3522ab332fcbSJames Smart rc = -EIO;
3523ab332fcbSJames Smart }
3524ab332fcbSJames Smart /*
3525ab332fcbSJames Smart * Because the FW reset leaves the FW in a non-running state,
3526ab332fcbSJames Smart * follow that with a regular reset.
3527ab332fcbSJames Smart */
3528ab332fcbSJames Smart efc_log_debug(hw->os, "issuing function level reset\n");
3529ab332fcbSJames Smart if (sli_reset(&hw->sli)) {
3530ab332fcbSJames Smart efc_log_err(hw->os, "sli_reset failed\n");
3531ab332fcbSJames Smart rc = -EIO;
3532ab332fcbSJames Smart }
3533ab332fcbSJames Smart break;
3534ab332fcbSJames Smart default:
3535ab332fcbSJames Smart efc_log_err(hw->os, "unknown type - no reset performed\n");
3536ab332fcbSJames Smart hw->state = prev_state;
3537ab332fcbSJames Smart rc = -EINVAL;
3538ab332fcbSJames Smart break;
3539ab332fcbSJames Smart }
3540ab332fcbSJames Smart
3541ab332fcbSJames Smart return rc;
3542ab332fcbSJames Smart }
3543ab332fcbSJames Smart
3544ab332fcbSJames Smart int
efct_hw_reset(struct efct_hw * hw,enum efct_hw_reset reset)3545ab332fcbSJames Smart efct_hw_reset(struct efct_hw *hw, enum efct_hw_reset reset)
3546ab332fcbSJames Smart {
3547ab332fcbSJames Smart int rc = 0;
3548ab332fcbSJames Smart enum efct_hw_state prev_state = hw->state;
3549ab332fcbSJames Smart
3550ab332fcbSJames Smart if (hw->state != EFCT_HW_STATE_ACTIVE)
3551ab332fcbSJames Smart efc_log_debug(hw->os,
3552ab332fcbSJames Smart "HW state %d is not active\n", hw->state);
3553ab332fcbSJames Smart
3554ab332fcbSJames Smart hw->state = EFCT_HW_STATE_RESET_IN_PROGRESS;
3555ab332fcbSJames Smart
3556ab332fcbSJames Smart /*
3557ab332fcbSJames Smart * If the prev_state is already reset/teardown in progress,
3558ab332fcbSJames Smart * don't continue further
3559ab332fcbSJames Smart */
3560ab332fcbSJames Smart if (prev_state == EFCT_HW_STATE_RESET_IN_PROGRESS ||
3561ab332fcbSJames Smart prev_state == EFCT_HW_STATE_TEARDOWN_IN_PROGRESS)
3562ab332fcbSJames Smart return efct_hw_sli_reset(hw, reset, prev_state);
3563ab332fcbSJames Smart
3564ab332fcbSJames Smart if (prev_state != EFCT_HW_STATE_UNINITIALIZED) {
3565ab332fcbSJames Smart efct_hw_flush(hw);
3566ab332fcbSJames Smart
3567ab332fcbSJames Smart if (list_empty(&hw->cmd_head))
3568ab332fcbSJames Smart efc_log_debug(hw->os,
3569ab332fcbSJames Smart "All commands completed on MQ queue\n");
3570ab332fcbSJames Smart else
3571ab332fcbSJames Smart efc_log_err(hw->os,
3572ab332fcbSJames Smart "Some commands still pending on MQ queue\n");
3573ab332fcbSJames Smart }
3574ab332fcbSJames Smart
3575ab332fcbSJames Smart /* Reset the chip */
3576ab332fcbSJames Smart rc = efct_hw_sli_reset(hw, reset, prev_state);
3577ab332fcbSJames Smart if (rc == -EINVAL)
3578ab332fcbSJames Smart return -EIO;
3579ab332fcbSJames Smart
3580ab332fcbSJames Smart return rc;
3581ab332fcbSJames Smart }
3582