From: Daniel Wagner <dwagner@suse.de>
To: James Smart <jsmart2021@gmail.com>
Cc: linux-scsi@vger.kernel.org, maier@linux.ibm.com,
bvanassche@acm.org, herbszt@gmx.de, natechancellor@gmail.com,
rdunlap@infradead.org, hare@suse.de,
Ram Vegesna <ram.vegesna@broadcom.com>
Subject: Re: [PATCH v3 28/31] elx: efct: Firmware update, async link processing
Date: Thu, 16 Apr 2020 15:10:59 +0200 [thread overview]
Message-ID: <20200416131059.gbmyevc25625dhyz@carbon> (raw)
In-Reply-To: <20200412033303.29574-29-jsmart2021@gmail.com>
On Sat, Apr 11, 2020 at 08:33:00PM -0700, James Smart wrote:
> This patch continues the efct driver population.
>
> This patch adds driver definitions for:
> Handling of async link event.
> Registrations for VFI, VPI and RPI.
> Add Firmware update helper routines.
>
> Signed-off-by: Ram Vegesna <ram.vegesna@broadcom.com>
> Signed-off-by: James Smart <jsmart2021@gmail.com>
>
> ---
> v3:
> Reworked efct_hw_port_attach_reg_vpi() and efct_hw_port_attach_reg_vfi()
> Return defined values
> ---
> drivers/scsi/elx/efct/efct_hw.c | 1509 +++++++++++++++++++++++++++++++++++++++
> drivers/scsi/elx/efct/efct_hw.h | 58 ++
> 2 files changed, 1567 insertions(+)
>
> diff --git a/drivers/scsi/elx/efct/efct_hw.c b/drivers/scsi/elx/efct/efct_hw.c
> index a007ca98895d..b3a1ec0f674b 100644
> --- a/drivers/scsi/elx/efct/efct_hw.c
> +++ b/drivers/scsi/elx/efct/efct_hw.c
> @@ -42,6 +42,12 @@ struct efct_hw_host_stat_cb_arg {
> void *arg;
> };
>
> +struct efct_hw_fw_wr_cb_arg {
> + void (*cb)(int status, u32 bytes_written,
> + u32 change_status, void *arg);
> + void *arg;
> +};
> +
> static enum efct_hw_rtn
> efct_hw_link_event_init(struct efct_hw *hw)
> {
> @@ -3836,3 +3842,1506 @@ efct_hw_get_num_eq(struct efct_hw *hw)
> {
> return hw->eq_count;
> }
> +
> +/* HW async call context structure */
> +struct efct_hw_async_call_ctx {
> + efct_hw_async_cb_t callback;
> + void *arg;
> + u8 cmd[SLI4_BMBX_SIZE];
> +};
> +
> +static void
> +efct_hw_async_cb(struct efct_hw *hw, int status, u8 *mqe, void *arg)
> +{
> + struct efct_hw_async_call_ctx *ctx = arg;
> +
> + if (ctx) {
> + if (ctx->callback)
> + (*ctx->callback)(hw, status, mqe, ctx->arg);
> +
> + kfree(ctx);
> + }
> +}
> +
> +/*
> + * Post a NOP mbox cmd; the callback with argument is invoked upon completion
> + * while in the event processing context.
> + */
> +int
> +efct_hw_async_call(struct efct_hw *hw,
> + efct_hw_async_cb_t callback, void *arg)
> +{
> + int rc = 0;
> + struct efct_hw_async_call_ctx *ctx;
> +
> + /*
> + * Allocate a callback context (which includes the mbox cmd buffer),
> + * we need this to be persistent as the mbox cmd submission may be
> + * queued and executed later execution.
> + */
> + ctx = kmalloc(sizeof(*ctx), GFP_ATOMIC);
Ah, maybe I got that wrong in the other places where I asked for
GFP_ATOMIC. If this gets called while holding spinlocks GFP_ATOMIC is
needed.
> + if (!ctx)
> + return EFCT_HW_RTN_NO_MEMORY;
> +
> + memset(ctx, 0, sizeof(*ctx));
kzalloc
> + ctx->callback = callback;
> + ctx->arg = arg;
> +
> + /* Build and send a NOP mailbox command */
> + if (sli_cmd_common_nop(&hw->sli, ctx->cmd, sizeof(ctx->cmd), 0)) {
> + efc_log_err(hw->os, "COMMON_NOP format failure\n");
> + kfree(ctx);
> + rc = -1;
> + }
> +
> + if (efct_hw_command(hw, ctx->cmd, EFCT_CMD_NOWAIT, efct_hw_async_cb,
> + ctx)) {
> + efc_log_err(hw->os, "COMMON_NOP command failure\n");
> + kfree(ctx);
> + rc = -1;
> + }
> + return rc;
> +}
> +
> +static void
> +efct_hw_port_free_resources(struct efc_sli_port *sport, int evt, void *data)
> +{
> + struct efct_hw *hw = sport->hw;
> + struct efct *efct = hw->os;
> +
> + /* Clear the sport attached flag */
> + sport->attached = false;
> +
> + /* Free the service parameters buffer */
> + if (sport->dma.virt) {
> + dma_free_coherent(&efct->pcidev->dev,
> + sport->dma.size, sport->dma.virt,
> + sport->dma.phys);
> + memset(&sport->dma, 0, sizeof(struct efc_dma));
> + }
> +
> + /* Free the command buffer */
> + kfree(data);
> +
> + /* Free the SLI resources */
> + sli_resource_free(&hw->sli, SLI_RSRC_VPI, sport->indicator);
> +
> + efc_lport_cb(efct->efcport, evt, sport);
> +}
> +
> +static int
> +efct_hw_port_get_mbox_status(struct efc_sli_port *sport,
> + u8 *mqe, int status)
> +{
> + struct efct_hw *hw = sport->hw;
> + struct sli4_mbox_command_header *hdr =
> + (struct sli4_mbox_command_header *)mqe;
> + int rc = 0;
> +
> + if (status || le16_to_cpu(hdr->status)) {
> + efc_log_debug(hw->os, "bad status vpi=%#x st=%x hdr=%x\n",
> + sport->indicator, status,
> + le16_to_cpu(hdr->status));
> + rc = -1;
> + }
> +
> + return rc;
> +}
> +
> +static int
> +efct_hw_port_free_unreg_vpi_cb(struct efct_hw *hw,
> + int status, u8 *mqe, void *arg)
> +{
> + struct efc_sli_port *sport = arg;
> + int evt = EFC_HW_PORT_FREE_OK;
> + int rc = 0;
> +
> + rc = efct_hw_port_get_mbox_status(sport, mqe, status);
> + if (rc) {
> + evt = EFC_HW_PORT_FREE_FAIL;
> + rc = -1;
> + }
> +
> + efct_hw_port_free_resources(sport, evt, mqe);
> + return rc;
> +}
> +
> +static void
> +efct_hw_port_free_unreg_vpi(struct efc_sli_port *sport, void *data)
> +{
> + struct efct_hw *hw = sport->hw;
> + int rc;
> +
> + /* Allocate memory and send unreg_vpi */
> + if (!data) {
> + data = kmalloc(SLI4_BMBX_SIZE, GFP_ATOMIC);
> + if (!data) {
> + efct_hw_port_free_resources(sport,
> + EFC_HW_PORT_FREE_FAIL,
> + data);
> + return;
> + }
> + memset(data, 0, SLI4_BMBX_SIZE);
kzalloc
> + }
> +
> + rc = sli_cmd_unreg_vpi(&hw->sli, data, SLI4_BMBX_SIZE,
> + sport->indicator, SLI4_UNREG_TYPE_PORT);
> + if (rc) {
> + efc_log_err(hw->os, "UNREG_VPI format failure\n");
> + efct_hw_port_free_resources(sport,
> + EFC_HW_PORT_FREE_FAIL, data);
> + return;
> + }
> +
> + rc = efct_hw_command(hw, data, EFCT_CMD_NOWAIT,
> + efct_hw_port_free_unreg_vpi_cb, sport);
> + if (rc) {
> + efc_log_err(hw->os, "UNREG_VPI command failure\n");
> + efct_hw_port_free_resources(sport,
> + EFC_HW_PORT_FREE_FAIL, data);
> + }
> +}
> +
> +static void
> +efct_hw_port_send_evt(struct efc_sli_port *sport, int evt, void *data)
> +{
> + struct efct_hw *hw = sport->hw;
> + struct efct *efct = hw->os;
> +
> + /* Free the mbox buffer */
> + kfree(data);
> +
> + /* Now inform the registered callbacks */
> + efc_lport_cb(efct->efcport, evt, sport);
> +
> + /* Set the sport attached flag */
> + if (evt == EFC_HW_PORT_ATTACH_OK)
> + sport->attached = true;
> +
> + /* If there is a pending free request, then handle it now */
> + if (sport->free_req_pending)
> + efct_hw_port_free_unreg_vpi(sport, NULL);
> +}
> +
> +static int
> +efct_hw_port_alloc_init_vpi_cb(struct efct_hw *hw,
> + int status, u8 *mqe, void *arg)
> +{
> + struct efc_sli_port *sport = arg;
> + int rc;
> +
> + rc = efct_hw_port_get_mbox_status(sport, mqe, status);
> + if (rc) {
> + efct_hw_port_free_resources(sport,
> + EFC_HW_PORT_ALLOC_FAIL, mqe);
> + return EFC_FAIL;
> + }
> +
> + efct_hw_port_send_evt(sport, EFC_HW_PORT_ALLOC_OK, mqe);
> + return EFC_SUCCESS;
> +}
> +
> +static void
> +efct_hw_port_alloc_init_vpi(struct efc_sli_port *sport, void *data)
> +{
> + struct efct_hw *hw = sport->hw;
> + int rc;
> +
> + /* If there is a pending free request, then handle it now */
> + if (sport->free_req_pending) {
> + efct_hw_port_free_resources(sport, EFC_HW_PORT_FREE_OK, data);
> + return;
> + }
> +
> + rc = sli_cmd_init_vpi(&hw->sli, data, SLI4_BMBX_SIZE,
> + sport->indicator, sport->domain->indicator);
> + if (rc) {
> + efc_log_err(hw->os, "INIT_VPI format failure\n");
> + efct_hw_port_free_resources(sport,
> + EFC_HW_PORT_ALLOC_FAIL, data);
> + return;
> + }
> +
> + rc = efct_hw_command(hw, data, EFCT_CMD_NOWAIT,
> + efct_hw_port_alloc_init_vpi_cb, sport);
> + if (rc) {
> + efc_log_err(hw->os, "INIT_VPI command failure\n");
> + efct_hw_port_free_resources(sport,
> + EFC_HW_PORT_ALLOC_FAIL, data);
> + }
> +}
> +
> +static int
> +efct_hw_port_alloc_read_sparm64_cb(struct efct_hw *hw,
> + int status, u8 *mqe, void *arg)
> +{
> + struct efc_sli_port *sport = arg;
> + u8 *payload = NULL;
> + struct efct *efct = hw->os;
> + int rc;
> +
> + rc = efct_hw_port_get_mbox_status(sport, mqe, status);
> + if (rc) {
> + efct_hw_port_free_resources(sport,
> + EFC_HW_PORT_ALLOC_FAIL, mqe);
> + return EFC_FAIL;
> + }
> +
> + payload = sport->dma.virt;
> +
> + memcpy(&sport->sli_wwpn,
> + payload + SLI4_READ_SPARM64_WWPN_OFFSET,
> + sizeof(sport->sli_wwpn));
> + memcpy(&sport->sli_wwnn,
> + payload + SLI4_READ_SPARM64_WWNN_OFFSET,
> + sizeof(sport->sli_wwnn));
> +
> + dma_free_coherent(&efct->pcidev->dev,
> + sport->dma.size, sport->dma.virt, sport->dma.phys);
> + memset(&sport->dma, 0, sizeof(struct efc_dma));
> + efct_hw_port_alloc_init_vpi(sport, mqe);
> + return EFC_SUCCESS;
> +}
> +
> +static void
> +efct_hw_port_alloc_read_sparm64(struct efc_sli_port *sport, void *data)
> +{
> + struct efct_hw *hw = sport->hw;
> + struct efct *efct = hw->os;
> + int rc;
> +
> + /* Allocate memory for the service parameters */
> + sport->dma.size = 112;
> + sport->dma.virt = dma_alloc_coherent(&efct->pcidev->dev,
> + sport->dma.size, &sport->dma.phys,
> + GFP_DMA);
> + if (!sport->dma.virt) {
> + efc_log_err(hw->os, "Failed to allocate DMA memory\n");
> + efct_hw_port_free_resources(sport,
> + EFC_HW_PORT_ALLOC_FAIL, data);
> + return;
> + }
> +
> + rc = sli_cmd_read_sparm64(&hw->sli, data, SLI4_BMBX_SIZE,
> + &sport->dma, sport->indicator);
> + if (rc) {
> + efc_log_err(hw->os, "READ_SPARM64 format failure\n");
> + efct_hw_port_free_resources(sport,
> + EFC_HW_PORT_ALLOC_FAIL, data);
> + return;
> + }
> +
> + rc = efct_hw_command(hw, data, EFCT_CMD_NOWAIT,
> + efct_hw_port_alloc_read_sparm64_cb, sport);
> + if (rc) {
> + efc_log_err(hw->os, "READ_SPARM64 command failure\n");
> + efct_hw_port_free_resources(sport,
> + EFC_HW_PORT_ALLOC_FAIL, data);
> + }
> +}
> +
> +/*
> + * This function allocates a VPI object for the port and stores it in the
> + * indicator field of the port object.
> + */
> +enum efct_hw_rtn
> +efct_hw_port_alloc(struct efc *efc, struct efc_sli_port *sport,
> + struct efc_domain *domain, u8 *wwpn)
> +{
> + struct efct *efct = efc->base;
> + struct efct_hw *hw = &efct->hw;
> +
> + u8 *cmd = NULL;
> + enum efct_hw_rtn rc = EFCT_HW_RTN_SUCCESS;
> + u32 index;
> +
> + sport->indicator = U32_MAX;
> + sport->hw = hw;
> + sport->free_req_pending = false;
> +
> + /*
> + * Check if the chip is in an error state (UE'd) before proceeding.
> + */
> + if (sli_fw_error_status(&hw->sli) > 0) {
> + efc_log_crit(hw->os,
> + "Chip is in an error state - reset needed\n");
> + return EFCT_HW_RTN_ERROR;
> + }
> +
> + if (wwpn)
> + memcpy(&sport->sli_wwpn, wwpn, sizeof(sport->sli_wwpn));
> +
> + if (sli_resource_alloc(&hw->sli, SLI_RSRC_VPI,
> + &sport->indicator, &index)) {
> + efc_log_err(hw->os, "VPI allocation failure\n");
> + return EFCT_HW_RTN_ERROR;
> + }
> +
> + if (domain) {
> + cmd = kmalloc(SLI4_BMBX_SIZE, GFP_ATOMIC);
> + if (!cmd) {
> + rc = EFCT_HW_RTN_NO_MEMORY;
> + goto efct_hw_port_alloc_out;
> + }
> + memset(cmd, 0, SLI4_BMBX_SIZE);
> +
> + /*
> + * If the WWPN is NULL, fetch the default
> + * WWPN and WWNN before initializing the VPI
> + */
> + if (!wwpn)
> + efct_hw_port_alloc_read_sparm64(sport, cmd);
> + else
> + efct_hw_port_alloc_init_vpi(sport, cmd);
> + } else if (!wwpn) {
> + /* This is the convention for the HW, not SLI */
> + efc_log_test(hw->os, "need WWN for physical port\n");
> + rc = EFCT_HW_RTN_ERROR;
> + }
> + /* domain NULL and wwpn non-NULL */
> + // no-op;
left over?
> +
> +efct_hw_port_alloc_out:
> + if (rc != EFCT_HW_RTN_SUCCESS) {
> + kfree(cmd);
> +
> + sli_resource_free(&hw->sli, SLI_RSRC_VPI,
> + sport->indicator);
> + }
> +
> + return rc;
> +}
> +
> +static int
> +efct_hw_port_attach_reg_vpi_cb(struct efct_hw *hw,
> + int status, u8 *mqe, void *arg)
> +{
> + struct efc_sli_port *sport = arg;
> + int rc;
> +
> + rc = efct_hw_port_get_mbox_status(sport, mqe, status);
> + if (rc) {
> + efct_hw_port_free_resources(sport,
> + EFC_HW_PORT_ATTACH_FAIL, mqe);
> + return EFC_FAIL;
> + }
> +
> + efct_hw_port_send_evt(sport, EFC_HW_PORT_ATTACH_OK, mqe);
> + return EFC_SUCCESS;
> +}
> +
> +/**
> + * This function registers a previously-allocated VPI with the
> + * device.
> + */
> +enum efct_hw_rtn
> +efct_hw_port_attach(struct efc *efc, struct efc_sli_port *sport,
> + u32 fc_id)
> +{
> + struct efct *efct = efc->base;
> + struct efct_hw *hw = &efct->hw;
> +
> + u8 *buf = NULL;
> + enum efct_hw_rtn rc = EFCT_HW_RTN_SUCCESS;
> +
> + if (!sport) {
> + efc_log_err(hw->os,
> + "bad parameter(s) hw=%p sport=%p\n", hw,
> + sport);
> + return EFCT_HW_RTN_ERROR;
> + }
> +
> + /*
> + * Check if the chip is in an error state (UE'd) before proceeding.
> + */
> + if (sli_fw_error_status(&hw->sli) > 0) {
> + efc_log_crit(hw->os,
> + "Chip is in an error state - reset needed\n");
> + return EFCT_HW_RTN_ERROR;
> + }
> +
> + buf = kmalloc(SLI4_BMBX_SIZE, GFP_ATOMIC);
> + if (!buf)
> + return EFCT_HW_RTN_NO_MEMORY;
> +
> + memset(buf, 0, SLI4_BMBX_SIZE);
> + sport->fc_id = fc_id;
> +
> + rc = sli_cmd_reg_vpi(&hw->sli, buf, SLI4_BMBX_SIZE, sport->fc_id,
> + sport->sli_wwpn, sport->indicator,
> + sport->domain->indicator, false);
> + if (rc) {
> + efc_log_err(hw->os, "REG_VPI format failure\n");
> + efct_hw_port_free_resources(sport,
> + EFC_HW_PORT_ATTACH_FAIL, buf);
> + return rc;
> + }
> +
> + rc = efct_hw_command(hw, buf, EFCT_CMD_NOWAIT,
> + efct_hw_port_attach_reg_vpi_cb, sport);
> + if (rc) {
> + efc_log_err(hw->os, "REG_VPI command failure\n");
> + efct_hw_port_free_resources(sport,
> + EFC_HW_PORT_ATTACH_FAIL, buf);
> + }
> +
> + return rc;
> +}
> +
> +/* Issue the UNREG_VPI command to free the assigned VPI context */
> +enum efct_hw_rtn
> +efct_hw_port_free(struct efc *efc, struct efc_sli_port *sport)
> +{
> + struct efct *efct = efc->base;
> + struct efct_hw *hw = &efct->hw;
> +
> + enum efct_hw_rtn rc = EFCT_HW_RTN_SUCCESS;
> +
> + if (!sport) {
> + efc_log_err(hw->os,
> + "bad parameter(s) hw=%p sport=%p\n", hw,
> + sport);
> + return EFCT_HW_RTN_ERROR;
> + }
> +
> + /*
> + * Check if the chip is in an error state (UE'd) before proceeding.
> + */
> + if (sli_fw_error_status(&hw->sli) > 0) {
> + efc_log_crit(hw->os,
> + "Chip is in an error state - reset needed\n");
> + return EFCT_HW_RTN_ERROR;
> + }
> +
> + if (sport->attached)
> + efct_hw_port_free_unreg_vpi(sport, NULL);
> + else
> + sport->free_req_pending = true;
> +
> + return rc;
> +}
> +
> +static int
> +efct_hw_domain_get_mbox_status(struct efc_domain *domain,
> + u8 *mqe, int status)
> +{
> + struct efct_hw *hw = domain->hw;
> + struct sli4_mbox_command_header *hdr =
> + (struct sli4_mbox_command_header *)mqe;
> + int rc = 0;
> +
> + if (status || le16_to_cpu(hdr->status)) {
> + efc_log_debug(hw->os, "bad status vfi=%#x st=%x hdr=%x\n",
> + domain->indicator, status,
> + le16_to_cpu(hdr->status));
> + rc = -1;
> + }
> +
> + return rc;
> +}
> +
> +static void
> +efct_hw_domain_free_resources(struct efc_domain *domain,
> + int evt, void *data)
> +{
> + struct efct_hw *hw = domain->hw;
> + struct efct *efct = hw->os;
> +
> + /* Free the service parameters buffer */
> + if (domain->dma.virt) {
> + dma_free_coherent(&efct->pcidev->dev,
> + domain->dma.size, domain->dma.virt,
> + domain->dma.phys);
> + memset(&domain->dma, 0, sizeof(struct efc_dma));
> + }
> +
> + /* Free the command buffer */
> + kfree(data);
> +
> + /* Free the SLI resources */
> + sli_resource_free(&hw->sli, SLI_RSRC_VFI, domain->indicator);
> +
> + efc_domain_cb(efct->efcport, evt, domain);
> +}
> +
> +static void
> +efct_hw_domain_send_sport_evt(struct efc_domain *domain,
> + int port_evt, int domain_evt, void *data)
> +{
> + struct efct_hw *hw = domain->hw;
> + struct efct *efct = hw->os;
> +
> + /* Free the mbox buffer */
> + kfree(data);
> +
> + /* Send alloc/attach ok to the physical sport */
> + efct_hw_port_send_evt(domain->sport, port_evt, NULL);
> +
> + /* Now inform the registered callbacks */
> + efc_domain_cb(efct->efcport, domain_evt, domain);
> +}
> +
> +static int
> +efct_hw_domain_alloc_read_sparm64_cb(struct efct_hw *hw,
> + int status, u8 *mqe, void *arg)
> +{
> + struct efc_domain *domain = arg;
> + int rc;
> +
> + rc = efct_hw_domain_get_mbox_status(domain, mqe, status);
> + if (rc) {
> + efct_hw_domain_free_resources(domain,
> + EFC_HW_DOMAIN_ALLOC_FAIL, mqe);
> + return EFC_FAIL;
> + }
> +
> + hw->domain = domain;
> + efct_hw_domain_send_sport_evt(domain, EFC_HW_PORT_ALLOC_OK,
> + EFC_HW_DOMAIN_ALLOC_OK, mqe);
> + return EFC_SUCCESS;
> +}
> +
> +static void
> +efct_hw_domain_alloc_read_sparm64(struct efc_domain *domain, void *data)
> +{
> + struct efct_hw *hw = domain->hw;
> + int rc;
> +
> + rc = sli_cmd_read_sparm64(&hw->sli, data, SLI4_BMBX_SIZE,
> + &domain->dma, 0);
> + if (rc) {
> + efc_log_err(hw->os, "READ_SPARM64 format failure\n");
> + efct_hw_domain_free_resources(domain,
> + EFC_HW_DOMAIN_ALLOC_FAIL, data);
> + return;
> + }
> +
> + rc = efct_hw_command(hw, data, EFCT_CMD_NOWAIT,
> + efct_hw_domain_alloc_read_sparm64_cb, domain);
> + if (rc) {
> + efc_log_err(hw->os, "READ_SPARM64 command failure\n");
> + efct_hw_domain_free_resources(domain,
> + EFC_HW_DOMAIN_ALLOC_FAIL, data);
> + }
> +}
> +
> +static int
> +efct_hw_domain_alloc_init_vfi_cb(struct efct_hw *hw,
> + int status, u8 *mqe, void *arg)
> +{
> + struct efc_domain *domain = arg;
> + int rc;
> +
> + rc = efct_hw_domain_get_mbox_status(domain, mqe, status);
> + if (rc) {
> + efct_hw_domain_free_resources(domain,
> + EFC_HW_DOMAIN_ALLOC_FAIL, mqe);
> + return EFC_FAIL;
> + }
> +
> + efct_hw_domain_alloc_read_sparm64(domain, mqe);
> + return EFC_SUCCESS;
> +}
> +
> +static void
> +efct_hw_domain_alloc_init_vfi(struct efc_domain *domain, void *data)
> +{
> + struct efct_hw *hw = domain->hw;
> + struct efc_sli_port *sport = domain->sport;
> + int rc;
> +
> + /*
> + * For FC, the HW alread registered an FCFI.
> + * Copy FCF information into the domain and jump to INIT_VFI.
> + */
> + domain->fcf_indicator = hw->fcf_indicator;
> + rc = sli_cmd_init_vfi(&hw->sli, data, SLI4_BMBX_SIZE,
> + domain->indicator, domain->fcf_indicator,
> + sport->indicator);
> + if (rc) {
> + efc_log_err(hw->os, "INIT_VFI format failure\n");
> + efct_hw_domain_free_resources(domain,
> + EFC_HW_DOMAIN_ALLOC_FAIL, data);
> + return;
> + }
> +
> + rc = efct_hw_command(hw, data, EFCT_CMD_NOWAIT,
> + efct_hw_domain_alloc_init_vfi_cb, domain);
> + if (rc) {
> + efc_log_err(hw->os, "INIT_VFI command failure\n");
> + efct_hw_domain_free_resources(domain,
> + EFC_HW_DOMAIN_ALLOC_FAIL, data);
> + }
> +}
> +
> +/**
> + * This function starts a series of commands needed to connect to the domain,
> + * including
> + * - REG_FCFI
> + * - INIT_VFI
> + * - READ_SPARMS
> + */
> +enum efct_hw_rtn
> +efct_hw_domain_alloc(struct efc *efc, struct efc_domain *domain,
> + u32 fcf)
> +{
> + struct efct *efct = efc->base;
> + struct efct_hw *hw = &efct->hw;
> + u8 *cmd = NULL;
> + u32 index;
> +
> + if (!domain || !domain->sport) {
> + efc_log_err(efct,
> + "bad parameter(s) hw=%p domain=%p sport=%p\n",
> + hw, domain, domain ? domain->sport : NULL);
> + return EFCT_HW_RTN_ERROR;
> + }
> +
> + /*
> + * Check if the chip is in an error state (UE'd) before proceeding.
> + */
> + if (sli_fw_error_status(&hw->sli) > 0) {
> + efc_log_crit(efct,
> + "Chip is in an error state - reset needed\n");
> + return EFCT_HW_RTN_ERROR;
> + }
> +
> + cmd = kmalloc(SLI4_BMBX_SIZE, GFP_ATOMIC);
> + if (!cmd)
> + return EFCT_HW_RTN_NO_MEMORY;
> +
> + memset(cmd, 0, SLI4_BMBX_SIZE);
> +
> + /* allocate memory for the service parameters */
> + domain->dma.size = 112;
> + domain->dma.virt = dma_alloc_coherent(&efct->pcidev->dev,
> + domain->dma.size,
> + &domain->dma.phys, GFP_DMA);
> + if (!domain->dma.virt) {
> + efc_log_err(hw->os, "Failed to allocate DMA memory\n");
> + kfree(cmd);
> + return EFCT_HW_RTN_NO_MEMORY;
> + }
> +
> + domain->hw = hw;
> + domain->fcf = fcf;
> + domain->fcf_indicator = U32_MAX;
> + domain->indicator = U32_MAX;
> +
> + if (sli_resource_alloc(&hw->sli,
> + SLI_RSRC_VFI, &domain->indicator,
> + &index)) {
> + efc_log_err(hw->os, "VFI allocation failure\n");
> +
> + kfree(cmd);
> + dma_free_coherent(&efct->pcidev->dev,
> + domain->dma.size, domain->dma.virt,
> + domain->dma.phys);
> + memset(&domain->dma, 0, sizeof(struct efc_dma));
> +
> + return EFCT_HW_RTN_ERROR;
> + }
> +
> + efct_hw_domain_alloc_init_vfi(domain, cmd);
> + return EFCT_HW_RTN_SUCCESS;
> +}
> +
> +static int
> +efct_hw_domain_attach_reg_vfi_cb(struct efct_hw *hw,
> + int status, u8 *mqe, void *arg)
> +{
> + struct efc_domain *domain = arg;
> + int rc;
> +
> + rc = efct_hw_domain_get_mbox_status(domain, mqe, status);
> + if (rc) {
> + hw->domain = NULL;
> + efct_hw_domain_free_resources(domain,
> + EFC_HW_DOMAIN_ATTACH_FAIL, mqe);
> + return EFC_FAIL;
> + }
> +
> + efct_hw_domain_send_sport_evt(domain, EFC_HW_PORT_ATTACH_OK,
> + EFC_HW_DOMAIN_ATTACH_OK, mqe);
> + return EFC_SUCCESS;
> +}
> +
> +enum efct_hw_rtn
> +efct_hw_domain_attach(struct efc *efc,
> + struct efc_domain *domain, u32 fc_id)
> +{
> + struct efct *efct = efc->base;
> + struct efct_hw *hw = &efct->hw;
> +
> + u8 *buf = NULL;
> + enum efct_hw_rtn rc = EFCT_HW_RTN_SUCCESS;
> +
> + if (!domain) {
> + efc_log_err(hw->os,
> + "bad parameter(s) hw=%p domain=%p\n",
> + hw, domain);
> + return EFCT_HW_RTN_ERROR;
> + }
> +
> + /*
> + * Check if the chip is in an error state (UE'd) before proceeding.
> + */
> + if (sli_fw_error_status(&hw->sli) > 0) {
> + efc_log_crit(hw->os,
> + "Chip is in an error state - reset needed\n");
> + return EFCT_HW_RTN_ERROR;
> + }
> +
> + buf = kmalloc(SLI4_BMBX_SIZE, GFP_ATOMIC);
> + if (!buf)
> + return EFCT_HW_RTN_NO_MEMORY;
> +
> + memset(buf, 0, SLI4_BMBX_SIZE);
> + domain->sport->fc_id = fc_id;
> +
> + rc = sli_cmd_reg_vfi(&hw->sli, buf, SLI4_BMBX_SIZE, domain->indicator,
> + domain->fcf_indicator, domain->dma,
> + domain->sport->indicator, domain->sport->sli_wwpn,
> + domain->sport->fc_id);
> + if (rc) {
> + efc_log_err(hw->os, "REG_VFI format failure\n");
> + goto cleanup;
> + }
> +
> + rc = efct_hw_command(hw, buf, EFCT_CMD_NOWAIT,
> + efct_hw_domain_attach_reg_vfi_cb, domain);
> + if (rc) {
> + efc_log_err(hw->os, "REG_VFI command failure\n");
> + goto cleanup;
> + }
> +
> + return rc;
> +
> +cleanup:
> + hw->domain = NULL;
> + efct_hw_domain_free_resources(domain, EFC_HW_DOMAIN_ATTACH_FAIL, buf);
> +
> + return rc;
> +}
> +
> +static int
> +efct_hw_domain_free_unreg_vfi_cb(struct efct_hw *hw,
> + int status, u8 *mqe, void *arg)
> +{
> + struct efc_domain *domain = arg;
> + int evt = EFC_HW_DOMAIN_FREE_OK;
> + int rc = 0;
> +
> + rc = efct_hw_domain_get_mbox_status(domain, mqe, status);
> + if (rc) {
> + evt = EFC_HW_DOMAIN_FREE_FAIL;
> + rc = -1;
> + }
> +
> + hw->domain = NULL;
> + efct_hw_domain_free_resources(domain, evt, mqe);
> + return rc;
> +}
> +
> +static void
> +efct_hw_domain_free_unreg_vfi(struct efc_domain *domain, void *data)
> +{
> + struct efct_hw *hw = domain->hw;
> + int rc;
> +
> + if (!data) {
> + data = kzalloc(SLI4_BMBX_SIZE, GFP_ATOMIC);
> + if (!data)
> + goto cleanup;
> + }
> +
> + rc = sli_cmd_unreg_vfi(&hw->sli, data, SLI4_BMBX_SIZE,
> + domain->indicator, SLI4_UNREG_TYPE_DOMAIN);
> + if (rc) {
> + efc_log_err(hw->os, "UNREG_VFI format failure\n");
> + goto cleanup;
> + }
> +
> + rc = efct_hw_command(hw, data, EFCT_CMD_NOWAIT,
> + efct_hw_domain_free_unreg_vfi_cb, domain);
> + if (rc) {
> + efc_log_err(hw->os, "UNREG_VFI command failure\n");
> + goto cleanup;
> + }
> +
> + return;
> +
> +cleanup:
> + hw->domain = NULL;
> + efct_hw_domain_free_resources(domain, EFC_HW_DOMAIN_FREE_FAIL, data);
> +}
> +
> +enum efct_hw_rtn
> +efct_hw_domain_free(struct efc *efc, struct efc_domain *domain)
> +{
> + struct efct *efct = efc->base;
> + struct efct_hw *hw = &efct->hw;
> +
> + enum efct_hw_rtn rc = EFCT_HW_RTN_SUCCESS;
> +
> + if (!domain) {
> + efc_log_err(hw->os,
> + "bad parameter(s) hw=%p domain=%p\n",
> + hw, domain);
> + return EFCT_HW_RTN_ERROR;
> + }
> +
> + /*
> + * Check if the chip is in an error state (UE'd) before proceeding.
> + */
> + if (sli_fw_error_status(&hw->sli) > 0) {
> + efc_log_crit(hw->os,
> + "Chip is in an error state - reset needed\n");
> + return EFCT_HW_RTN_ERROR;
> + }
> +
> + efct_hw_domain_free_unreg_vfi(domain, NULL);
> + return rc;
> +}
> +
> +enum efct_hw_rtn
> +efct_hw_domain_force_free(struct efc *efc, struct efc_domain *domain)
> +{
> + struct efct *efct = efc->base;
> + struct efct_hw *hw = &efct->hw;
> +
> + if (!domain) {
> + efc_log_err(efct,
> + "bad parameter(s) hw=%p domain=%p\n", hw, domain);
> + return EFCT_HW_RTN_ERROR;
> + }
> +
> + dma_free_coherent(&efct->pcidev->dev,
> + domain->dma.size, domain->dma.virt, domain->dma.phys);
> + memset(&domain->dma, 0, sizeof(struct efc_dma));
> + sli_resource_free(&hw->sli, SLI_RSRC_VFI,
> + domain->indicator);
> +
> + return EFCT_HW_RTN_SUCCESS;
> +}
> +
> +enum efct_hw_rtn
> +efct_hw_node_alloc(struct efc *efc, struct efc_remote_node *rnode,
> + u32 fc_addr, struct efc_sli_port *sport)
> +{
> + struct efct *efct = efc->base;
> + struct efct_hw *hw = &efct->hw;
> +
> + /* Check for invalid indicator */
> + if (rnode->indicator != U32_MAX) {
> + efc_log_err(hw->os,
> + "RPI allocation failure addr=%#x rpi=%#x\n",
> + fc_addr, rnode->indicator);
> + return EFCT_HW_RTN_ERROR;
> + }
> +
> + /*
> + * Check if the chip is in an error state (UE'd) before proceeding.
> + */
> + if (sli_fw_error_status(&hw->sli) > 0) {
> + efc_log_crit(hw->os,
> + "Chip is in an error state - reset needed\n");
> + return EFCT_HW_RTN_ERROR;
> + }
> +
> + /* NULL SLI port indicates an unallocated remote node */
> + rnode->sport = NULL;
> +
> + if (sli_resource_alloc(&hw->sli, SLI_RSRC_RPI,
> + &rnode->indicator, &rnode->index)) {
> + efc_log_err(hw->os, "RPI allocation failure addr=%#x\n",
> + fc_addr);
> + return EFCT_HW_RTN_ERROR;
> + }
> +
> + rnode->fc_id = fc_addr;
> + rnode->sport = sport;
> +
> + return EFCT_HW_RTN_SUCCESS;
> +}
> +
> +static int
> +efct_hw_cb_node_attach(struct efct_hw *hw, int status,
> + u8 *mqe, void *arg)
> +{
> + struct efc_remote_node *rnode = arg;
> + struct sli4_mbox_command_header *hdr =
> + (struct sli4_mbox_command_header *)mqe;
> + enum efc_hw_remote_node_event evt = 0;
> +
> + struct efct *efct = hw->os;
> +
> + if (status || le16_to_cpu(hdr->status)) {
> + efc_log_debug(hw->os, "bad status cqe=%#x mqe=%#x\n", status,
> + le16_to_cpu(hdr->status));
> + atomic_sub_return(1, &hw->rpi_ref[rnode->index].rpi_count);
> + rnode->attached = false;
> + atomic_set(&hw->rpi_ref[rnode->index].rpi_attached, 0);
> + evt = EFC_HW_NODE_ATTACH_FAIL;
> + } else {
> + rnode->attached = true;
> + atomic_set(&hw->rpi_ref[rnode->index].rpi_attached, 1);
> + evt = EFC_HW_NODE_ATTACH_OK;
> + }
> +
> + efc_remote_node_cb(efct->efcport, evt, rnode);
> +
> + kfree(mqe);
> +
> + return EFC_SUCCESS;
> +}
> +
> +/* Update a remote node object with the remote port's service parameters */
> +enum efct_hw_rtn
> +efct_hw_node_attach(struct efc *efc, struct efc_remote_node *rnode,
> + struct efc_dma *sparms)
> +{
> + struct efct *efct = efc->base;
> + struct efct_hw *hw = &efct->hw;
> +
> + enum efct_hw_rtn rc = EFCT_HW_RTN_ERROR;
> + u8 *buf = NULL;
> + u32 count = 0;
aligment
> +
> + if (!hw || !rnode || !sparms) {
> + efc_log_err(efct,
> + "bad parameter(s) hw=%p rnode=%p sparms=%p\n",
> + hw, rnode, sparms);
> + return EFCT_HW_RTN_ERROR;
> + }
> +
> + /*
> + * Check if the chip is in an error state (UE'd) before proceeding.
> + */
> + if (sli_fw_error_status(&hw->sli) > 0) {
> + efc_log_crit(hw->os,
> + "Chip is in an error state - reset needed\n");
> + return EFCT_HW_RTN_ERROR;
> + }
> +
> + buf = kmalloc(SLI4_BMBX_SIZE, GFP_ATOMIC);
> + if (!buf)
> + return EFCT_HW_RTN_NO_MEMORY;
> +
> + memset(buf, 0, SLI4_BMBX_SIZE);
> + /*
> + * If the attach count is non-zero, this RPI has already been reg'd.
> + * Otherwise, register the RPI
> + */
> + if (rnode->index == U32_MAX) {
> + efc_log_err(efct, "bad parameter rnode->index invalid\n");
> + kfree(buf);
> + return EFCT_HW_RTN_ERROR;
> + }
> + count = atomic_add_return(1, &hw->rpi_ref[rnode->index].rpi_count);
> + count--;
> + if (count) {
> + /*
> + * Can't attach multiple FC_ID's to a node unless High Login
> + * Mode is enabled
> + */
> + if (!hw->sli.high_login_mode) {
> + efc_log_test(hw->os,
> + "attach to attached node HLM=%d cnt=%d\n",
> + hw->sli.high_login_mode, count);
> + rc = EFCT_HW_RTN_SUCCESS;
> + } else {
> + rnode->node_group = true;
> + rnode->attached =
> + atomic_read(&hw->rpi_ref[rnode->index].rpi_attached);
> + rc = rnode->attached ? EFCT_HW_RTN_SUCCESS_SYNC :
> + EFCT_HW_RTN_SUCCESS;
> + }
> + } else {
> + rnode->node_group = false;
> +
> + if (!sli_cmd_reg_rpi(&hw->sli, buf, SLI4_BMBX_SIZE,
> + rnode->fc_id,
> + rnode->indicator, rnode->sport->indicator,
> + sparms, 0, 0))
> + rc = efct_hw_command(hw, buf, EFCT_CMD_NOWAIT,
> + efct_hw_cb_node_attach, rnode);
> + }
> +
> + if (count || rc) {
> + if (rc < EFCT_HW_RTN_SUCCESS) {
> + atomic_sub_return(1,
> + &hw->rpi_ref[rnode->index].rpi_count);
> + efc_log_err(hw->os,
> + "%s error\n", count ? "HLM" : "REG_RPI");
> + }
> + kfree(buf);
> + }
> +
> + return rc;
> +}
> +
> +enum efct_hw_rtn
> +efct_hw_node_free_resources(struct efc *efc,
> + struct efc_remote_node *rnode)
> +{
> + struct efct *efct = efc->base;
> + struct efct_hw *hw = &efct->hw;
> + enum efct_hw_rtn rc = EFCT_HW_RTN_SUCCESS;
alignment
> +
> + if (!hw || !rnode) {
> + efc_log_err(efct, "bad parameter(s) hw=%p rnode=%p\n",
> + hw, rnode);
> + return EFCT_HW_RTN_ERROR;
> + }
> +
> + if (rnode->sport) {
> + if (rnode->attached) {
> + efc_log_err(hw->os, "Err: rnode is still attached\n");
> + return EFCT_HW_RTN_ERROR;
> + }
> + if (rnode->indicator != U32_MAX) {
> + if (sli_resource_free(&hw->sli, SLI_RSRC_RPI,
> + rnode->indicator)) {
> + efc_log_err(hw->os,
> + "RPI free fail RPI %d addr=%#x\n",
> + rnode->indicator,
> + rnode->fc_id);
> + rc = EFCT_HW_RTN_ERROR;
> + } else {
> + rnode->node_group = false;
> + rnode->indicator = U32_MAX;
> + rnode->index = U32_MAX;
> + rnode->free_group = false;
> + }
> + }
> + }
> +
> + return rc;
> +}
> +
> +static int
> +efct_hw_cb_node_free(struct efct_hw *hw,
> + int status, u8 *mqe, void *arg)
> +{
> + struct efc_remote_node *rnode = arg;
> + struct sli4_mbox_command_header *hdr =
> + (struct sli4_mbox_command_header *)mqe;
> + enum efc_hw_remote_node_event evt = EFC_HW_NODE_FREE_FAIL;
> + int rc = 0;
> + struct efct *efct = hw->os;
> +
> + if (status || le16_to_cpu(hdr->status)) {
> + efc_log_debug(hw->os, "bad status cqe=%#x mqe=%#x\n", status,
> + le16_to_cpu(hdr->status));
> +
> + /*
> + * In certain cases, a non-zero MQE status is OK (all must be
> + * true):
> + * - node is attached
> + * - if High Login Mode is enabled, node is part of a node
> + * group
> + * - status is 0x1400
> + */
> + if (!rnode->attached ||
> + (hw->sli.high_login_mode && !rnode->node_group) ||
> + (le16_to_cpu(hdr->status) !=
> + MBX_STATUS_RPI_NOT_REG))
if (!rnode->attached ||
(hw->sli.high_login_mode && !rnode->node_group) ||
(le16_to_cpu(hdr->status) != MBX_STATUS_RPI_NOT_REG))
> + rc = -1;
> + }
> +
> + if (rc == 0) {
> + rnode->node_group = false;
> + rnode->attached = false;
> +
> + if (atomic_read(&hw->rpi_ref[rnode->index].rpi_count) == 0)
> + atomic_set(&hw->rpi_ref[rnode->index].rpi_attached,
> + 0);
> + evt = EFC_HW_NODE_FREE_OK;
> + }
> +
> + efc_remote_node_cb(efct->efcport, evt, rnode);
> +
> + kfree(mqe);
> +
> + return rc;
> +}
> +
> +enum efct_hw_rtn
> +efct_hw_node_detach(struct efc *efc, struct efc_remote_node *rnode)
> +{
> + struct efct *efct = efc->base;
> + struct efct_hw *hw = &efct->hw;
> + u8 *buf = NULL;
> + enum efct_hw_rtn rc = EFCT_HW_RTN_SUCCESS_SYNC;
> + u32 index = U32_MAX;
> +
> + if (!hw || !rnode) {
> + efc_log_err(efct, "bad parameter(s) hw=%p rnode=%p\n",
> + hw, rnode);
> + return EFCT_HW_RTN_ERROR;
> + }
> +
> + /*
> + * Check if the chip is in an error state (UE'd) before proceeding.
> + */
> + if (sli_fw_error_status(&hw->sli) > 0) {
> + efc_log_crit(hw->os,
> + "Chip is in an error state - reset needed\n");
> + return EFCT_HW_RTN_ERROR;
> + }
> +
> + index = rnode->index;
> +
> + if (rnode->sport) {
> + u32 count = 0;
> + u32 fc_id;
> +
> + if (!rnode->attached)
> + return EFCT_HW_RTN_SUCCESS_SYNC;
> +
> + buf = kmalloc(SLI4_BMBX_SIZE, GFP_ATOMIC);
> + if (!buf)
> + return EFCT_HW_RTN_NO_MEMORY;
> +
> + memset(buf, 0, SLI4_BMBX_SIZE);
> + count = atomic_sub_return(1, &hw->rpi_ref[index].rpi_count);
> + count++;
> + if (count <= 1) {
> + /*
> + * There are no other references to this RPI so
> + * unregister it
> + */
> + fc_id = U32_MAX;
> + /* and free the resource */
> + rnode->node_group = false;
> + rnode->free_group = true;
> + } else {
> + if (!hw->sli.high_login_mode)
> + efc_log_test(hw->os,
> + "Inval cnt with HLM off, cnt=%d\n",
> + count);
> + fc_id = rnode->fc_id & 0x00ffffff;
> + }
> +
> + rc = EFCT_HW_RTN_ERROR;
> +
> + if (!sli_cmd_unreg_rpi(&hw->sli, buf, SLI4_BMBX_SIZE,
> + rnode->indicator,
> + SLI_RSRC_RPI, fc_id))
> + rc = efct_hw_command(hw, buf, EFCT_CMD_NOWAIT,
> + efct_hw_cb_node_free, rnode);
> +
> + if (rc != EFCT_HW_RTN_SUCCESS) {
> + efc_log_err(hw->os, "UNREG_RPI failed\n");
> + kfree(buf);
> + rc = EFCT_HW_RTN_ERROR;
> + }
> + }
> +
> + return rc;
> +}
> +
> +static int
> +efct_hw_cb_node_free_all(struct efct_hw *hw, int status, u8 *mqe,
> + void *arg)
> +{
> + struct sli4_mbox_command_header *hdr =
> + (struct sli4_mbox_command_header *)mqe;
> + enum efc_hw_remote_node_event evt = EFC_HW_NODE_FREE_FAIL;
> + int rc = 0;
> + u32 i;
> + struct efct *efct = hw->os;
> +
> + if (status || le16_to_cpu(hdr->status)) {
> + efc_log_debug(hw->os, "bad status cqe=%#x mqe=%#x\n", status,
> + le16_to_cpu(hdr->status));
> + } else {
> + evt = EFC_HW_NODE_FREE_ALL_OK;
> + }
> +
> + if (evt == EFC_HW_NODE_FREE_ALL_OK) {
> + for (i = 0; i < hw->sli.extent[SLI_RSRC_RPI].size;
> + i++)
this fits on one line
> + atomic_set(&hw->rpi_ref[i].rpi_count, 0);
> +
> + if (sli_resource_reset(&hw->sli, SLI_RSRC_RPI)) {
> + efc_log_test(hw->os, "RPI free all failure\n");
> + rc = -1;
> + }
> + }
> +
> + efc_remote_node_cb(efct->efcport, evt, NULL);
> +
> + kfree(mqe);
> +
> + return rc;
> +}
> +
> +enum efct_hw_rtn
> +efct_hw_node_free_all(struct efct_hw *hw)
> +{
> + u8 *buf = NULL;
> + enum efct_hw_rtn rc = EFCT_HW_RTN_ERROR;
alignmnent
> +
> + /*
> + * Check if the chip is in an error state (UE'd) before proceeding.
> + */
> + if (sli_fw_error_status(&hw->sli) > 0) {
> + efc_log_crit(hw->os,
> + "Chip is in an error state - reset needed\n");
> + return EFCT_HW_RTN_ERROR;
> + }
> +
> + buf = kmalloc(SLI4_BMBX_SIZE, GFP_ATOMIC);
> + if (!buf)
> + return EFCT_HW_RTN_NO_MEMORY;
> +
> + memset(buf, 0, SLI4_BMBX_SIZE);
kzalloc
> +
> + if (!sli_cmd_unreg_rpi(&hw->sli, buf, SLI4_BMBX_SIZE, 0xffff,
> + SLI_RSRC_FCFI, U32_MAX))
> + rc = efct_hw_command(hw, buf, EFCT_CMD_NOWAIT,
> + efct_hw_cb_node_free_all,
> + NULL);
> +
> + if (rc != EFCT_HW_RTN_SUCCESS) {
> + efc_log_err(hw->os, "UNREG_RPI failed\n");
> + kfree(buf);
> + rc = EFCT_HW_RTN_ERROR;
> + }
> +
> + return rc;
> +}
> +
> +struct efct_hw_get_nvparms_cb_arg {
> + void (*cb)(int status,
> + u8 *wwpn, u8 *wwnn,
> + u8 hard_alpa, u32 preferred_d_id,
> + void *arg);
> + void *arg;
> +};
> +
> +static int
> +efct_hw_get_nvparms_cb(struct efct_hw *hw, int status,
> + u8 *mqe, void *arg)
> +{
> + struct efct_hw_get_nvparms_cb_arg *cb_arg = arg;
> + struct sli4_cmd_read_nvparms *mbox_rsp =
> + (struct sli4_cmd_read_nvparms *)mqe;
> + u8 hard_alpa;
> + u32 preferred_d_id;
> +
> + hard_alpa = le32_to_cpu(mbox_rsp->hard_alpa_d_id) &
> + SLI4_READ_NVPARAMS_HARD_ALPA;
> + preferred_d_id = (le32_to_cpu(mbox_rsp->hard_alpa_d_id) &
> + SLI4_READ_NVPARAMS_PREFERRED_D_ID) >> 8;
> + if (cb_arg->cb)
> + cb_arg->cb(status, mbox_rsp->wwpn, mbox_rsp->wwnn,
> + hard_alpa, preferred_d_id,
> + cb_arg->arg);
> +
> + kfree(mqe);
> + kfree(cb_arg);
> +
> + return EFC_SUCCESS;
> +}
> +
> +int
> +efct_hw_get_nvparms(struct efct_hw *hw,
> + void (*cb)(int status, u8 *wwpn,
> + u8 *wwnn, u8 hard_alpa,
> + u32 preferred_d_id, void *arg),
> + void *ul_arg)
> +{
> + u8 *mbxdata;
> + struct efct_hw_get_nvparms_cb_arg *cb_arg;
> + enum efct_hw_rtn rc = EFCT_HW_RTN_SUCCESS;
> +
> + /* mbxdata holds the header of the command */
> + mbxdata = kmalloc(SLI4_BMBX_SIZE, GFP_KERNEL);
> + if (!mbxdata)
> + return EFCT_HW_RTN_NO_MEMORY;
> +
> + memset(mbxdata, 0, SLI4_BMBX_SIZE);
> +
> + /*
> + * cb_arg holds the data that will be passed to the callback on
> + * completion
> + */
> + cb_arg = kmalloc(sizeof(*cb_arg), GFP_KERNEL);
> + if (!cb_arg) {
> + kfree(mbxdata);
> + return EFCT_HW_RTN_NO_MEMORY;
> + }
> +
> + cb_arg->cb = cb;
> + cb_arg->arg = ul_arg;
> +
> + /* Send the HW command */
> + if (!sli_cmd_read_nvparms(&hw->sli, mbxdata, SLI4_BMBX_SIZE))
> + rc = efct_hw_command(hw, mbxdata, EFCT_CMD_NOWAIT,
> + efct_hw_get_nvparms_cb, cb_arg);
> +
> + if (rc != EFCT_HW_RTN_SUCCESS) {
> + efc_log_test(hw->os, "READ_NVPARMS failed\n");
> + kfree(mbxdata);
> + kfree(cb_arg);
> + }
> +
> + return rc;
> +}
> +
> +struct efct_hw_set_nvparms_cb_arg {
> + void (*cb)(int status, void *arg);
> + void *arg;
> +};
> +
> +static int
> +efct_hw_set_nvparms_cb(struct efct_hw *hw, int status,
> + u8 *mqe, void *arg)
> +{
> + struct efct_hw_set_nvparms_cb_arg *cb_arg = arg;
> +
> + if (cb_arg->cb)
> + cb_arg->cb(status, cb_arg->arg);
> +
> + kfree(mqe);
> + kfree(cb_arg);
> +
> + return EFC_SUCCESS;
> +}
> +
> +int
> +efct_hw_set_nvparms(struct efct_hw *hw,
> + void (*cb)(int status, void *arg),
> + u8 *wwpn, u8 *wwnn, u8 hard_alpa,
> + u32 preferred_d_id,
> + void *ul_arg)
> +{
> + u8 *mbxdata;
> + struct efct_hw_set_nvparms_cb_arg *cb_arg;
> + enum efct_hw_rtn rc = EFCT_HW_RTN_SUCCESS;
> +
> + /* mbxdata holds the header of the command */
> + mbxdata = kmalloc(SLI4_BMBX_SIZE, GFP_KERNEL);
> + if (!mbxdata)
> + return EFCT_HW_RTN_NO_MEMORY;
> +
> + /*
> + * cb_arg holds the data that will be passed to the callback on
> + * completion
> + */
> + cb_arg = kmalloc(sizeof(*cb_arg), GFP_KERNEL);
> + if (!cb_arg) {
> + kfree(mbxdata);
> + return EFCT_HW_RTN_NO_MEMORY;
> + }
> +
> + cb_arg->cb = cb;
> + cb_arg->arg = ul_arg;
> +
> + /* Send the HW command */
> + if (!sli_cmd_write_nvparms(&hw->sli, mbxdata, SLI4_BMBX_SIZE, wwpn,
> + wwnn, hard_alpa, preferred_d_id))
> + rc = efct_hw_command(hw, mbxdata, EFCT_CMD_NOWAIT,
> + efct_hw_set_nvparms_cb, cb_arg);
> +
> + if (rc != EFCT_HW_RTN_SUCCESS) {
> + efc_log_test(hw->os, "SET_NVPARMS failed\n");
> + kfree(mbxdata);
> + kfree(cb_arg);
> + }
> +
> + return rc;
> +}
> +
> +static int
> +efct_hw_cb_fw_write(struct efct_hw *hw, int status,
> + u8 *mqe, void *arg)
> +{
> + struct sli4_cmd_sli_config *mbox_rsp =
> + (struct sli4_cmd_sli_config *)mqe;
> + struct sli4_rsp_cmn_write_object *wr_obj_rsp;
> + struct efct_hw_fw_wr_cb_arg *cb_arg = arg;
> + u32 bytes_written;
> + u16 mbox_status;
> + u32 change_status;
> +
> + wr_obj_rsp = (struct sli4_rsp_cmn_write_object *)
> + &mbox_rsp->payload.embed;
> + bytes_written = le32_to_cpu(wr_obj_rsp->actual_write_length);
> + mbox_status = le16_to_cpu(mbox_rsp->hdr.status);
> + change_status = (le32_to_cpu(wr_obj_rsp->change_status_dword) &
> + RSP_CHANGE_STATUS);
> +
> + kfree(mqe);
> +
> + if (cb_arg) {
> + if (cb_arg->cb) {
> + if (!status && mbox_status)
> + status = mbox_status;
> + cb_arg->cb(status, bytes_written, change_status,
> + cb_arg->arg);
> + }
> +
> + kfree(cb_arg);
> + }
> +
> + return EFC_SUCCESS;
> +}
> +
> +static enum efct_hw_rtn
> +efct_hw_firmware_write_sli4_intf_2(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)
> +{
> + enum efct_hw_rtn rc = EFCT_HW_RTN_ERROR;
> + u8 *mbxdata;
> + struct efct_hw_fw_wr_cb_arg *cb_arg;
> + int noc = 0;
> +
> + mbxdata = kmalloc(SLI4_BMBX_SIZE, GFP_KERNEL);
> + if (!mbxdata)
> + return EFCT_HW_RTN_NO_MEMORY;
> +
> + memset(mbxdata, 0, SLI4_BMBX_SIZE);
> +
> + cb_arg = kmalloc(sizeof(*cb_arg), GFP_KERNEL);
> + if (!cb_arg) {
> + kfree(mbxdata);
> + return EFCT_HW_RTN_NO_MEMORY;
> + }
> + memset(cb_arg, 0, sizeof(struct efct_hw_fw_wr_cb_arg));
> + cb_arg->cb = cb;
> + cb_arg->arg = arg;
> +
> + /* Send the HW command */
> + if (!sli_cmd_common_write_object(&hw->sli, mbxdata, SLI4_BMBX_SIZE,
> + noc, last, size, offset, "/prg/",
> + dma))
> + rc = efct_hw_command(hw, mbxdata, EFCT_CMD_NOWAIT,
> + efct_hw_cb_fw_write, cb_arg);
> +
> + if (rc != EFCT_HW_RTN_SUCCESS) {
> + efc_log_test(hw->os, "COMMON_WRITE_OBJECT failed\n");
> + kfree(mbxdata);
> + kfree(cb_arg);
> + }
> +
> + return rc;
> +}
> +
> +/* Write a portion of a firmware image to the device */
> +enum efct_hw_rtn
> +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)
> +{
> + return efct_hw_firmware_write_sli4_intf_2(hw, dma, size, offset,
> + last, cb, arg);
> +}
> diff --git a/drivers/scsi/elx/efct/efct_hw.h b/drivers/scsi/elx/efct/efct_hw.h
> index 9c025a1709e3..6bd1fde177cd 100644
> --- a/drivers/scsi/elx/efct/efct_hw.h
> +++ b/drivers/scsi/elx/efct/efct_hw.h
> @@ -802,5 +802,63 @@ 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);
> +extern enum efct_hw_rtn
extern is not needed
> +efct_hw_port_alloc(struct efc *efc, struct efc_sli_port *sport,
> + struct efc_domain *domain, u8 *wwpn);
> +extern enum efct_hw_rtn
> +efct_hw_port_attach(struct efc *efc, struct efc_sli_port *sport,
> + u32 fc_id);
> +extern enum efct_hw_rtn
> +efct_hw_port_free(struct efc *efc, struct efc_sli_port *sport);
> +extern enum efct_hw_rtn
> +efct_hw_domain_alloc(struct efc *efc, struct efc_domain *domain,
> + u32 fcf);
> +extern enum efct_hw_rtn
> +efct_hw_domain_attach(struct efc *efc,
> + struct efc_domain *domain, u32 fc_id);
> +extern enum efct_hw_rtn
> +efct_hw_domain_free(struct efc *efc, struct efc_domain *domain);
> +extern enum efct_hw_rtn
> +efct_hw_domain_force_free(struct efc *efc, struct efc_domain *domain);
> +extern enum efct_hw_rtn
> +efct_hw_node_alloc(struct efc *efc, struct efc_remote_node *rnode,
> + u32 fc_addr, struct efc_sli_port *sport);
> +extern enum efct_hw_rtn
> +efct_hw_node_free_all(struct efct_hw *hw);
> +extern enum efct_hw_rtn
> +efct_hw_node_attach(struct efc *efc, struct efc_remote_node *rnode,
> + struct efc_dma *sparms);
> +extern enum efct_hw_rtn
> +efct_hw_node_detach(struct efc *efc, struct efc_remote_node *rnode);
> +extern enum efct_hw_rtn
> +efct_hw_node_free_resources(struct efc *efc,
> + struct efc_remote_node *rnode);
> +
> +extern enum efct_hw_rtn
> +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);
> +
> +extern enum efct_hw_rtn
> +efct_hw_get_nvparms(struct efct_hw *hw,
> + void (*mgmt_cb)(int status, u8 *wwpn,
> + u8 *wwnn, u8 hard_alpa,
> + u32 preferred_d_id, void *arg),
> + void *arg);
> +extern
> +enum efct_hw_rtn efct_hw_set_nvparms(struct efct_hw *hw,
> + void (*mgmt_cb)(int status, void *arg),
> + u8 *wwpn, u8 *wwnn, u8 hard_alpa,
> + u32 preferred_d_id, void *arg);
> +
> +typedef int (*efct_hw_async_cb_t)(struct efct_hw *hw, int status,
> + u8 *mqe, void *arg);
> +extern int
> +efct_hw_async_call(struct efct_hw *hw,
> + efct_hw_async_cb_t callback, void *arg);
> +enum efct_hw_rtn
> +efct_hw_init_queues(struct efct_hw *hw);
>
> #endif /* __EFCT_H__ */
> --
> 2.16.4
>
>
Thanks,
Daniel
next prev parent reply other threads:[~2020-04-16 13:11 UTC|newest]
Thread overview: 122+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-04-12 3:32 [PATCH v3 00/31] [NEW] efct: Broadcom (Emulex) FC Target driver James Smart
2020-04-12 3:32 ` [PATCH v3 01/31] elx: libefc_sli: SLI-4 register offsets and field definitions James Smart
2020-04-14 15:23 ` Daniel Wagner
2020-04-22 4:28 ` James Smart
2020-04-15 12:06 ` Hannes Reinecke
2020-04-23 1:52 ` Roman Bolshakov
2020-04-12 3:32 ` [PATCH v3 02/31] elx: libefc_sli: SLI Descriptors and Queue entries James Smart
2020-04-14 18:02 ` Daniel Wagner
2020-04-22 4:41 ` James Smart
2020-04-15 12:14 ` Hannes Reinecke
2020-04-15 17:43 ` James Bottomley
2020-04-22 4:44 ` James Smart
2020-04-12 3:32 ` [PATCH v3 03/31] elx: libefc_sli: Data structures and defines for mbox commands James Smart
2020-04-14 19:01 ` Daniel Wagner
2020-04-15 12:22 ` Hannes Reinecke
2020-04-12 3:32 ` [PATCH v3 04/31] elx: libefc_sli: queue create/destroy/parse routines James Smart
2020-04-15 10:04 ` Daniel Wagner
2020-04-22 5:05 ` James Smart
2020-04-24 7:29 ` Daniel Wagner
2020-04-24 15:21 ` James Smart
2020-04-15 12:27 ` Hannes Reinecke
2020-04-12 3:32 ` [PATCH v3 05/31] elx: libefc_sli: Populate and post different WQEs James Smart
2020-04-15 14:34 ` Daniel Wagner
2020-04-22 5:08 ` James Smart
2020-04-12 3:32 ` [PATCH v3 06/31] elx: libefc_sli: bmbx routines and SLI config commands James Smart
2020-04-15 16:10 ` Daniel Wagner
2020-04-22 5:12 ` James Smart
2020-04-12 3:32 ` [PATCH v3 07/31] elx: libefc_sli: APIs to setup SLI library James Smart
2020-04-15 12:49 ` Hannes Reinecke
2020-04-15 17:06 ` Daniel Wagner
2020-04-12 3:32 ` [PATCH v3 08/31] elx: libefc: Generic state machine framework James Smart
2020-04-15 12:37 ` Hannes Reinecke
2020-04-15 17:20 ` Daniel Wagner
2020-04-12 3:32 ` [PATCH v3 09/31] elx: libefc: Emulex FC discovery library APIs and definitions James Smart
2020-04-15 12:41 ` Hannes Reinecke
2020-04-15 17:32 ` Daniel Wagner
2020-04-12 3:32 ` [PATCH v3 10/31] elx: libefc: FC Domain state machine interfaces James Smart
2020-04-15 12:50 ` Hannes Reinecke
2020-04-15 17:50 ` Daniel Wagner
2020-04-12 3:32 ` [PATCH v3 11/31] elx: libefc: SLI and FC PORT " James Smart
2020-04-15 15:38 ` Hannes Reinecke
2020-04-22 23:12 ` James Smart
2020-04-15 18:04 ` Daniel Wagner
2020-04-12 3:32 ` [PATCH v3 12/31] elx: libefc: Remote node " James Smart
2020-04-15 15:51 ` Hannes Reinecke
2020-04-23 1:35 ` James Smart
2020-04-23 8:02 ` Daniel Wagner
2020-04-23 18:24 ` James Smart
2020-04-15 18:19 ` Daniel Wagner
2020-04-23 1:32 ` James Smart
2020-04-23 7:49 ` Daniel Wagner
2020-04-12 3:32 ` [PATCH v3 13/31] elx: libefc: Fabric " James Smart
2020-04-15 18:51 ` Daniel Wagner
2020-04-16 6:37 ` Hannes Reinecke
2020-04-23 1:38 ` James Smart
2020-04-12 3:32 ` [PATCH v3 14/31] elx: libefc: FC node ELS and state handling James Smart
2020-04-15 18:56 ` Daniel Wagner
2020-04-23 2:50 ` James Smart
2020-04-23 8:05 ` Daniel Wagner
2020-04-23 8:12 ` Nathan Chancellor
2020-04-16 6:47 ` Hannes Reinecke
2020-04-23 2:55 ` James Smart
2020-04-12 3:32 ` [PATCH v3 15/31] elx: efct: Data structures and defines for hw operations James Smart
2020-04-16 6:51 ` Hannes Reinecke
2020-04-23 2:57 ` James Smart
2020-04-16 7:22 ` Daniel Wagner
2020-04-23 2:59 ` James Smart
2020-04-12 3:32 ` [PATCH v3 16/31] elx: efct: Driver initialization routines James Smart
2020-04-16 7:11 ` Hannes Reinecke
2020-04-23 3:09 ` James Smart
2020-04-16 8:03 ` Daniel Wagner
2020-04-12 3:32 ` [PATCH v3 17/31] elx: efct: Hardware queues creation and deletion James Smart
2020-04-16 7:14 ` Hannes Reinecke
2020-04-16 8:24 ` Daniel Wagner
2020-04-12 3:32 ` [PATCH v3 18/31] elx: efct: RQ buffer, memory pool allocation and deallocation APIs James Smart
2020-04-16 7:24 ` Hannes Reinecke
2020-04-23 3:16 ` James Smart
2020-04-16 8:41 ` Daniel Wagner
2020-04-12 3:32 ` [PATCH v3 19/31] elx: efct: Hardware IO and SGL initialization James Smart
2020-04-16 7:32 ` Hannes Reinecke
2020-04-16 8:47 ` Daniel Wagner
2020-04-12 3:32 ` [PATCH v3 20/31] elx: efct: Hardware queues processing James Smart
2020-04-16 7:37 ` Hannes Reinecke
2020-04-16 9:17 ` Daniel Wagner
2020-04-12 3:32 ` [PATCH v3 21/31] elx: efct: Unsolicited FC frame processing routines James Smart
2020-04-16 9:36 ` Daniel Wagner
2020-04-12 3:32 ` [PATCH v3 22/31] elx: efct: Extended link Service IO handling James Smart
2020-04-16 7:58 ` Hannes Reinecke
2020-04-23 3:30 ` James Smart
2020-04-16 9:49 ` Daniel Wagner
2020-04-12 3:32 ` [PATCH v3 23/31] elx: efct: SCSI IO handling routines James Smart
2020-04-16 11:40 ` Daniel Wagner
2020-04-12 3:32 ` [PATCH v3 24/31] elx: efct: LIO backend interface routines James Smart
2020-04-12 4:57 ` Bart Van Assche
2020-04-16 11:48 ` Daniel Wagner
2020-04-22 4:20 ` James Smart
2020-04-22 5:09 ` Bart Van Assche
2020-04-23 1:39 ` James Smart
2020-04-16 8:02 ` Hannes Reinecke
2020-04-16 12:34 ` Daniel Wagner
2020-04-22 4:20 ` James Smart
2020-04-12 3:32 ` [PATCH v3 25/31] elx: efct: Hardware IO submission routines James Smart
2020-04-16 8:10 ` Hannes Reinecke
2020-04-16 12:45 ` Daniel Wagner
2020-04-23 3:37 ` James Smart
2020-04-16 12:44 ` Daniel Wagner
2020-04-12 3:32 ` [PATCH v3 26/31] elx: efct: link statistics and SFP data James Smart
2020-04-16 12:55 ` Daniel Wagner
2020-04-12 3:32 ` [PATCH v3 27/31] elx: efct: xport and hardware teardown routines James Smart
2020-04-16 9:45 ` Hannes Reinecke
2020-04-16 13:01 ` Daniel Wagner
2020-04-12 3:33 ` [PATCH v3 28/31] elx: efct: Firmware update, async link processing James Smart
2020-04-16 10:01 ` Hannes Reinecke
2020-04-16 13:10 ` Daniel Wagner [this message]
2020-04-12 3:33 ` [PATCH v3 29/31] elx: efct: scsi_transport_fc host interface support James Smart
2020-04-12 3:33 ` [PATCH v3 30/31] elx: efct: Add Makefile and Kconfig for efct driver James Smart
2020-04-16 10:02 ` Hannes Reinecke
2020-04-16 13:15 ` Daniel Wagner
2020-04-12 3:33 ` [PATCH v3 31/31] elx: efct: Tie into kernel Kconfig and build process James Smart
2020-04-12 6:16 ` kbuild test robot
2020-04-12 7:56 ` kbuild test robot
2020-04-16 13:15 ` Daniel Wagner
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200416131059.gbmyevc25625dhyz@carbon \
--to=dwagner@suse.de \
--cc=bvanassche@acm.org \
--cc=hare@suse.de \
--cc=herbszt@gmx.de \
--cc=jsmart2021@gmail.com \
--cc=linux-scsi@vger.kernel.org \
--cc=maier@linux.ibm.com \
--cc=natechancellor@gmail.com \
--cc=ram.vegesna@broadcom.com \
--cc=rdunlap@infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox