diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-10-07 09:28:53 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-10-07 09:28:53 -0700 |
commit | 4dfddf503670d8def0fddb497e628130fc4522a8 (patch) | |
tree | f4bbf85589c13a1994fef75622ec80c48684f475 /drivers/scsi/be2iscsi | |
parent | d4e65476bc68dbc9231b3c772b71f1576579b6fb (diff) | |
parent | 14bf41dcef651c13911a1715e83220732a3a4071 (diff) |
Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
Pull SCSI updates from James Bottomley:
"This update includes the usual round of major driver updates (hpsa,
be2iscsi, hisi_sas, zfcp, cxlflash). There's a new incarnation of hpsa
called smartpqi for which a driver is added, there's some cleanup work
of the ibm vscsi target and updates to libfc, plus a whole host of
minor fixes and updates and finally the removal of several ISA drivers
which seem not to have been used for years"
* tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi: (173 commits)
scsi: mvsas: Mark symbols static where possible
scsi: pm8001: Mark symbols static where possible
scsi: arcmsr: Simplify user_len checking
scsi: fcoe: fix off by one in eth2fc_speed()
scsi: dtc: remove from tree
scsi: t128: remove from tree
scsi: pas16: remove from tree
scsi: u14-34f: remove from tree
scsi: ultrastor: remove from tree
scsi: in2000: remove from tree
scsi: wd7000: remove from tree
scsi: scsi_dh_alua: Fix memory leak in alua_rtpg()
scsi: lpfc: Mark symbols static where possible
scsi: hpsa: correct call to hpsa_do_reset
scsi: ufs: Get a TM service response from the correct offset
scsi: ibmvfc: Fix I/O hang when port is not mapped
scsi: megaraid_sas: clean function declarations in megaraid_sas_base.c up
scsi: ipr: Remove redundant messages at adapter init time
scsi: ipr: Don't log unnecessary 9084 error details
scsi: smartpqi: raid bypass lba calculation fix
...
Diffstat (limited to 'drivers/scsi/be2iscsi')
-rw-r--r-- | drivers/scsi/be2iscsi/be.h | 15 | ||||
-rw-r--r-- | drivers/scsi/be2iscsi/be_cmds.c | 1096 | ||||
-rw-r--r-- | drivers/scsi/be2iscsi/be_cmds.h | 142 | ||||
-rw-r--r-- | drivers/scsi/be2iscsi/be_iscsi.c | 408 | ||||
-rw-r--r-- | drivers/scsi/be2iscsi/be_iscsi.h | 25 | ||||
-rw-r--r-- | drivers/scsi/be2iscsi/be_main.c | 2478 | ||||
-rw-r--r-- | drivers/scsi/be2iscsi/be_main.h | 220 | ||||
-rw-r--r-- | drivers/scsi/be2iscsi/be_mgmt.c | 1497 | ||||
-rw-r--r-- | drivers/scsi/be2iscsi/be_mgmt.h | 51 |
9 files changed, 3046 insertions, 2886 deletions
diff --git a/drivers/scsi/be2iscsi/be.h b/drivers/scsi/be2iscsi/be.h index ee5ace873535..b1d0fdc5d5e1 100644 --- a/drivers/scsi/be2iscsi/be.h +++ b/drivers/scsi/be2iscsi/be.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2015 Emulex + * Copyright (C) 2005 - 2016 Broadcom * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -8,7 +8,7 @@ * Public License is included in this distribution in the file called COPYING. * * Contact Information: - * linux-drivers@avagotech.com + * linux-drivers@broadcom.com * * Emulex * 3333 Susan Street @@ -89,7 +89,7 @@ struct be_aic_obj { /* Adaptive interrupt coalescing (AIC) info */ u32 max_eqd; /* in usecs */ u32 prev_eqd; /* in usecs */ u32 et_eqd; /* configured val when aic is off */ - ulong jiffs; + ulong jiffies; u64 eq_prev; /* Used to calculate eqe */ }; @@ -100,7 +100,7 @@ struct be_eq_obj { struct be_queue_info q; struct beiscsi_hba *phba; struct be_queue_info *cq; - struct work_struct work_cqs; /* Work Item */ + struct work_struct mcc_work; /* Work Item */ struct irq_poll iopoll; }; @@ -111,8 +111,11 @@ struct be_mcc_obj { struct beiscsi_mcc_tag_state { unsigned long tag_state; -#define MCC_TAG_STATE_RUNNING 1 -#define MCC_TAG_STATE_TIMEOUT 2 +#define MCC_TAG_STATE_RUNNING 0 +#define MCC_TAG_STATE_TIMEOUT 1 +#define MCC_TAG_STATE_ASYNC 2 +#define MCC_TAG_STATE_IGNORE 3 + void (*cbfn)(struct beiscsi_hba *, unsigned int); struct be_dma_mem tag_mem_state; }; diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c index a55eaeea37e7..be65da2988fb 100644 --- a/drivers/scsi/be2iscsi/be_cmds.c +++ b/drivers/scsi/be2iscsi/be_cmds.c @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2015 Emulex + * Copyright (C) 2005 - 2016 Broadcom * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -8,7 +8,7 @@ * Public License is included in this distribution in the file called COPYING. * * Contact Information: - * linux-drivers@avagotech.com + * linux-drivers@broadcom.com * * Emulex * 3333 Susan Street @@ -21,110 +21,77 @@ #include "be.h" #include "be_mgmt.h" -int beiscsi_pci_soft_reset(struct beiscsi_hba *phba) -{ - u32 sreset; - u8 *pci_reset_offset = 0; - u8 *pci_online0_offset = 0; - u8 *pci_online1_offset = 0; - u32 pconline0 = 0; - u32 pconline1 = 0; - u32 i; - - pci_reset_offset = (u8 *)phba->pci_va + BE2_SOFT_RESET; - pci_online0_offset = (u8 *)phba->pci_va + BE2_PCI_ONLINE0; - pci_online1_offset = (u8 *)phba->pci_va + BE2_PCI_ONLINE1; - sreset = readl((void *)pci_reset_offset); - sreset |= BE2_SET_RESET; - writel(sreset, (void *)pci_reset_offset); - - i = 0; - while (sreset & BE2_SET_RESET) { - if (i > 64) - break; - msleep(100); - sreset = readl((void *)pci_reset_offset); - i++; - } - - if (sreset & BE2_SET_RESET) { - printk(KERN_ERR DRV_NAME - " Soft Reset did not deassert\n"); - return -EIO; - } - pconline1 = BE2_MPU_IRAM_ONLINE; - writel(pconline0, (void *)pci_online0_offset); - writel(pconline1, (void *)pci_online1_offset); - - sreset |= BE2_SET_RESET; - writel(sreset, (void *)pci_reset_offset); - - i = 0; - while (sreset & BE2_SET_RESET) { - if (i > 64) - break; - msleep(1); - sreset = readl((void *)pci_reset_offset); - i++; - } - if (sreset & BE2_SET_RESET) { - printk(KERN_ERR DRV_NAME - " MPU Online Soft Reset did not deassert\n"); - return -EIO; - } - return 0; -} - -int be_chk_reset_complete(struct beiscsi_hba *phba) -{ - unsigned int num_loop; - u8 *mpu_sem = 0; - u32 status; - - num_loop = 1000; - mpu_sem = (u8 *)phba->csr_va + MPU_EP_SEMAPHORE; - msleep(5000); - - while (num_loop) { - status = readl((void *)mpu_sem); - - if ((status & 0x80000000) || (status & 0x0000FFFF) == 0xC000) - break; - msleep(60); - num_loop--; - } - - if ((status & 0x80000000) || (!num_loop)) { - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, - "BC_%d : Failed in be_chk_reset_complete" - "status = 0x%x\n", status); - return -EIO; - } - - return 0; -} - -unsigned int alloc_mcc_tag(struct beiscsi_hba *phba) -{ - unsigned int tag = 0; +/* UE Status Low CSR */ +static const char * const desc_ue_status_low[] = { + "CEV", + "CTX", + "DBUF", + "ERX", + "Host", + "MPU", + "NDMA", + "PTC ", + "RDMA ", + "RXF ", + "RXIPS ", + "RXULP0 ", + "RXULP1 ", + "RXULP2 ", + "TIM ", + "TPOST ", + "TPRE ", + "TXIPS ", + "TXULP0 ", + "TXULP1 ", + "UC ", + "WDMA ", + "TXULP2 ", + "HOST1 ", + "P0_OB_LINK ", + "P1_OB_LINK ", + "HOST_GPIO ", + "MBOX ", + "AXGMAC0", + "AXGMAC1", + "JTAG", + "MPU_INTPEND" +}; - spin_lock(&phba->ctrl.mcc_lock); - if (phba->ctrl.mcc_tag_available) { - tag = phba->ctrl.mcc_tag[phba->ctrl.mcc_alloc_index]; - phba->ctrl.mcc_tag[phba->ctrl.mcc_alloc_index] = 0; - phba->ctrl.mcc_tag_status[tag] = 0; - phba->ctrl.ptag_state[tag].tag_state = 0; - } - if (tag) { - phba->ctrl.mcc_tag_available--; - if (phba->ctrl.mcc_alloc_index == (MAX_MCC_CMD - 1)) - phba->ctrl.mcc_alloc_index = 0; - else - phba->ctrl.mcc_alloc_index++; - } - spin_unlock(&phba->ctrl.mcc_lock); - return tag; -} +/* UE Status High CSR */ +static const char * const desc_ue_status_hi[] = { + "LPCMEMHOST", + "MGMT_MAC", + "PCS0ONLINE", + "MPU_IRAM", + "PCS1ONLINE", + "PCTL0", + "PCTL1", + "PMEM", + "RR", + "TXPB", + "RXPP", + "XAUI", + "TXP", + "ARM", + "IPC", + "HOST2", + "HOST3", + "HOST4", + "HOST5", + "HOST6", + "HOST7", + "HOST8", + "HOST9", + "NETC", + "Unknown", + "Unknown", + "Unknown", + "Unknown", + "Unknown", + "Unknown", + "Unknown", + "Unknown" +}; struct be_mcc_wrb *alloc_mcc_wrb(struct beiscsi_hba *phba, unsigned int *ref_tag) @@ -133,7 +100,7 @@ struct be_mcc_wrb *alloc_mcc_wrb(struct beiscsi_hba *phba, struct be_mcc_wrb *wrb = NULL; unsigned int tag; - spin_lock_bh(&phba->ctrl.mcc_lock); + spin_lock(&phba->ctrl.mcc_lock); if (mccq->used == mccq->len) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX, @@ -160,6 +127,7 @@ struct be_mcc_wrb *alloc_mcc_wrb(struct beiscsi_hba *phba, phba->ctrl.mcc_tag[phba->ctrl.mcc_alloc_index] = 0; phba->ctrl.mcc_tag_status[tag] = 0; phba->ctrl.ptag_state[tag].tag_state = 0; + phba->ctrl.ptag_state[tag].cbfn = NULL; phba->ctrl.mcc_tag_available--; if (phba->ctrl.mcc_alloc_index == (MAX_MCC_CMD - 1)) phba->ctrl.mcc_alloc_index = 0; @@ -174,7 +142,7 @@ struct be_mcc_wrb *alloc_mcc_wrb(struct beiscsi_hba *phba, mccq->used++; alloc_failed: - spin_unlock_bh(&phba->ctrl.mcc_lock); + spin_unlock(&phba->ctrl.mcc_lock); return wrb; } @@ -182,7 +150,7 @@ void free_mcc_wrb(struct be_ctrl_info *ctrl, unsigned int tag) { struct be_queue_info *mccq = &ctrl->mcc_obj.q; - spin_lock_bh(&ctrl->mcc_lock); + spin_lock(&ctrl->mcc_lock); tag = tag & MCC_Q_CMD_TAG_MASK; ctrl->mcc_tag[ctrl->mcc_free_index] = tag; if (ctrl->mcc_free_index == (MAX_MCC_CMD - 1)) @@ -191,16 +159,71 @@ void free_mcc_wrb(struct be_ctrl_info *ctrl, unsigned int tag) ctrl->mcc_free_index++; ctrl->mcc_tag_available++; mccq->used--; - spin_unlock_bh(&ctrl->mcc_lock); + spin_unlock(&ctrl->mcc_lock); } -/** - * beiscsi_fail_session(): Closing session with appropriate error - * @cls_session: ptr to session - **/ -void beiscsi_fail_session(struct iscsi_cls_session *cls_session) +/* + * beiscsi_mcc_compl_status - Return the status of MCC completion + * @phba: Driver private structure + * @tag: Tag for the MBX Command + * @wrb: the WRB used for the MBX Command + * @mbx_cmd_mem: ptr to memory allocated for MBX Cmd + * + * return + * Success: 0 + * Failure: Non-Zero + */ +int __beiscsi_mcc_compl_status(struct beiscsi_hba *phba, + unsigned int tag, + struct be_mcc_wrb **wrb, + struct be_dma_mem *mbx_cmd_mem) { - iscsi_session_failure(cls_session->dd_data, ISCSI_ERR_CONN_FAILED); + struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q; + uint16_t status = 0, addl_status = 0, wrb_num = 0; + struct be_cmd_resp_hdr *mbx_resp_hdr; + struct be_cmd_req_hdr *mbx_hdr; + struct be_mcc_wrb *temp_wrb; + uint32_t mcc_tag_status; + int rc = 0; + + mcc_tag_status = phba->ctrl.mcc_tag_status[tag]; + status = (mcc_tag_status & CQE_STATUS_MASK); + addl_status = ((mcc_tag_status & CQE_STATUS_ADDL_MASK) >> + CQE_STATUS_ADDL_SHIFT); + + if (mbx_cmd_mem) { + mbx_hdr = (struct be_cmd_req_hdr *)mbx_cmd_mem->va; + } else { + wrb_num = (mcc_tag_status & CQE_STATUS_WRB_MASK) >> + CQE_STATUS_WRB_SHIFT; + temp_wrb = (struct be_mcc_wrb *)queue_get_wrb(mccq, wrb_num); + mbx_hdr = embedded_payload(temp_wrb); + + if (wrb) + *wrb = temp_wrb; + } + + if (status || addl_status) { + beiscsi_log(phba, KERN_WARNING, + BEISCSI_LOG_INIT | BEISCSI_LOG_EH | + BEISCSI_LOG_CONFIG, + "BC_%d : MBX Cmd Failed for Subsys : %d Opcode : %d with Status : %d and Extd_Status : %d\n", + mbx_hdr->subsystem, mbx_hdr->opcode, + status, addl_status); + rc = -EIO; + if (status == MCC_STATUS_INSUFFICIENT_BUFFER) { + mbx_resp_hdr = (struct be_cmd_resp_hdr *)mbx_hdr; + beiscsi_log(phba, KERN_WARNING, + BEISCSI_LOG_INIT | BEISCSI_LOG_EH | + BEISCSI_LOG_CONFIG, + "BC_%d : Insufficient Buffer Error Resp_Len : %d Actual_Resp_Len : %d\n", + mbx_resp_hdr->response_length, + mbx_resp_hdr->actual_resp_len); + rc = -EAGAIN; + } + } + + return rc; } /* @@ -217,26 +240,34 @@ void beiscsi_fail_session(struct iscsi_cls_session *cls_session) * Failure: Non-Zero **/ int beiscsi_mccq_compl_wait(struct beiscsi_hba *phba, - uint32_t tag, struct be_mcc_wrb **wrb, + unsigned int tag, + struct be_mcc_wrb **wrb, struct be_dma_mem *mbx_cmd_mem) { int rc = 0; - uint32_t mcc_tag_status; - uint16_t status = 0, addl_status = 0, wrb_num = 0; - struct be_mcc_wrb *temp_wrb; - struct be_cmd_req_hdr *mbx_hdr; - struct be_cmd_resp_hdr *mbx_resp_hdr; - struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q; - if (beiscsi_error(phba)) - return -EPERM; + if (beiscsi_hba_in_error(phba)) { + clear_bit(MCC_TAG_STATE_RUNNING, + &phba->ctrl.ptag_state[tag].tag_state); + return -EIO; + } /* wait for the mccq completion */ - rc = wait_event_interruptible_timeout( - phba->ctrl.mcc_wait[tag], - phba->ctrl.mcc_tag_status[tag], - msecs_to_jiffies( - BEISCSI_HOST_MBX_TIMEOUT)); + rc = wait_event_interruptible_timeout(phba->ctrl.mcc_wait[tag], + phba->ctrl.mcc_tag_status[tag], + msecs_to_jiffies( + BEISCSI_HOST_MBX_TIMEOUT)); + /** + * Return EIO if port is being disabled. Associated DMA memory, if any, + * is freed by the caller. When port goes offline, MCCQ is cleaned up + * so does WRB. + */ + if (!test_bit(BEISCSI_HBA_ONLINE, &phba->state)) { + clear_bit(MCC_TAG_STATE_RUNNING, + &phba->ctrl.ptag_state[tag].tag_state); + return -EIO; + } + /** * If MBOX cmd timeout expired, tag and resource allocated * for cmd is not freed until FW returns completion. @@ -270,47 +301,7 @@ int beiscsi_mccq_compl_wait(struct beiscsi_hba *phba, return -EBUSY; } - rc = 0; - mcc_tag_status = phba->ctrl.mcc_tag_status[tag]; - status = (mcc_tag_status & CQE_STATUS_MASK); - addl_status = ((mcc_tag_status & CQE_STATUS_ADDL_MASK) >> - CQE_STATUS_ADDL_SHIFT); - - if (mbx_cmd_mem) { - mbx_hdr = (struct be_cmd_req_hdr *)mbx_cmd_mem->va; - } else { - wrb_num = (mcc_tag_status & CQE_STATUS_WRB_MASK) >> - CQE_STATUS_WRB_SHIFT; - temp_wrb = (struct be_mcc_wrb *)queue_get_wrb(mccq, wrb_num); - mbx_hdr = embedded_payload(temp_wrb); - - if (wrb) - *wrb = temp_wrb; - } - - if (status || addl_status) { - beiscsi_log(phba, KERN_WARNING, - BEISCSI_LOG_INIT | BEISCSI_LOG_EH | - BEISCSI_LOG_CONFIG, - "BC_%d : MBX Cmd Failed for " - "Subsys : %d Opcode : %d with " - "Status : %d and Extd_Status : %d\n", - mbx_hdr->subsystem, - mbx_hdr->opcode, - status, addl_status); - rc = -EIO; - if (status == MCC_STATUS_INSUFFICIENT_BUFFER) { - mbx_resp_hdr = (struct be_cmd_resp_hdr *) mbx_hdr; - beiscsi_log(phba, KERN_WARNING, - BEISCSI_LOG_INIT | BEISCSI_LOG_EH | - BEISCSI_LOG_CONFIG, - "BC_%d : Insufficient Buffer Error " - "Resp_Len : %d Actual_Resp_Len : %d\n", - mbx_resp_hdr->response_length, - mbx_resp_hdr->actual_resp_len); - rc = -EAGAIN; - } - } + rc = __beiscsi_mcc_compl_status(phba, tag, wrb, mbx_cmd_mem); free_mcc_wrb(&phba->ctrl, tag); return rc; @@ -330,11 +321,10 @@ int beiscsi_mccq_compl_wait(struct beiscsi_hba *phba, static int beiscsi_process_mbox_compl(struct be_ctrl_info *ctrl, struct be_mcc_compl *compl) { - u16 compl_status, extd_status; struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); struct beiscsi_hba *phba = pci_get_drvdata(ctrl->pdev); struct be_cmd_req_hdr *hdr = embedded_payload(wrb); - struct be_cmd_resp_hdr *resp_hdr; + u16 compl_status, extd_status; /** * To check if valid bit is set, check the entire word as we don't know @@ -368,14 +358,7 @@ static int beiscsi_process_mbox_compl(struct be_ctrl_info *ctrl, beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX, "BC_%d : error in cmd completion: Subsystem : %d Opcode : %d status(compl/extd)=%d/%d\n", hdr->subsystem, hdr->opcode, compl_status, extd_status); - - if (compl_status == MCC_STATUS_INSUFFICIENT_BUFFER) { - /* if status is insufficient buffer, check the length */ - resp_hdr = (struct be_cmd_resp_hdr *) hdr; - if (resp_hdr->response_length) - return 0; - } - return -EINVAL; + return compl_status; } static void beiscsi_process_async_link(struct beiscsi_hba *phba, @@ -391,18 +374,19 @@ static void beiscsi_process_async_link(struct beiscsi_hba *phba, * This has been newly introduced in SKH-R Firmware 10.0.338.45. **/ if (evt->port_link_status & BE_ASYNC_LINK_UP_MASK) { - phba->state = BE_ADAPTER_LINK_UP | BE_ADAPTER_CHECK_BOOT; - phba->get_boot = BE_GET_BOOT_RETRIES; + set_bit(BEISCSI_HBA_LINK_UP, &phba->state); + if (test_bit(BEISCSI_HBA_BOOT_FOUND, &phba->state)) + beiscsi_start_boot_work(phba, BE_BOOT_INVALID_SHANDLE); __beiscsi_log(phba, KERN_ERR, "BC_%d : Link Up on Port %d tag 0x%x\n", evt->physical_port, evt->event_tag); } else { - phba->state = BE_ADAPTER_LINK_DOWN; + clear_bit(BEISCSI_HBA_LINK_UP, &phba->state); __beiscsi_log(phba, KERN_ERR, "BC_%d : Link Down on Port %d tag 0x%x\n", evt->physical_port, evt->event_tag); iscsi_host_for_each_session(phba->shost, - beiscsi_fail_session); + beiscsi_session_fail); } } @@ -482,8 +466,8 @@ void beiscsi_process_async_event(struct beiscsi_hba *phba, beiscsi_process_async_link(phba, compl); break; case ASYNC_EVENT_CODE_ISCSI: - phba->state |= BE_ADAPTER_CHECK_BOOT; - phba->get_boot = BE_GET_BOOT_RETRIES; + if (test_bit(BEISCSI_HBA_BOOT_FOUND, &phba->state)) + beiscsi_start_boot_work(phba, BE_BOOT_INVALID_SHANDLE); sev = KERN_ERR; break; case ASYNC_EVENT_CODE_SLI: @@ -519,6 +503,9 @@ int beiscsi_process_mcc_compl(struct be_ctrl_info *ctrl, return 0; } + /* end MCC with this tag */ + clear_bit(MCC_TAG_STATE_RUNNING, &ctrl->ptag_state[tag].tag_state); + if (test_bit(MCC_TAG_STATE_TIMEOUT, &ctrl->ptag_state[tag].tag_state)) { beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_MBOX | BEISCSI_LOG_INIT | @@ -529,9 +516,11 @@ int beiscsi_process_mcc_compl(struct be_ctrl_info *ctrl, * Only for non-embedded cmd, PCI resource is allocated. **/ tag_mem = &ctrl->ptag_state[tag].tag_mem_state; - if (tag_mem->size) + if (tag_mem->size) { pci_free_consistent(ctrl->pdev, tag_mem->size, tag_mem->va, tag_mem->dma); + tag_mem->size = 0; + } free_mcc_wrb(ctrl, tag); return 0; } @@ -550,57 +539,25 @@ int beiscsi_process_mcc_compl(struct be_ctrl_info *ctrl, CQE_STATUS_ADDL_MASK; ctrl->mcc_tag_status[tag] |= (compl_status & CQE_STATUS_MASK); - /* write ordering forced in wake_up_interruptible */ - clear_bit(MCC_TAG_STATE_RUNNING, &ctrl->ptag_state[tag].tag_state); - wake_up_interruptible(&ctrl->mcc_wait[tag]); - return 0; -} - -/* - * be_mcc_compl_poll()- Wait for MBX completion - * @phba: driver private structure - * - * Wait till no more pending mcc requests are present - * - * return - * Success: 0 - * Failure: Non-Zero - * - **/ -int be_mcc_compl_poll(struct beiscsi_hba *phba, unsigned int tag) -{ - struct be_ctrl_info *ctrl = &phba->ctrl; - int i; - - if (!test_bit(MCC_TAG_STATE_RUNNING, - &ctrl->ptag_state[tag].tag_state)) { - beiscsi_log(phba, KERN_ERR, - BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX, - "BC_%d: tag %u state not running\n", tag); + if (test_bit(MCC_TAG_STATE_ASYNC, &ctrl->ptag_state[tag].tag_state)) { + if (ctrl->ptag_state[tag].cbfn) + ctrl->ptag_state[tag].cbfn(phba, tag); + else + __beiscsi_log(phba, KERN_ERR, + "BC_%d : MBX ASYNC command with no callback\n"); + free_mcc_wrb(ctrl, tag); return 0; } - for (i = 0; i < mcc_timeout; i++) { - if (beiscsi_error(phba)) - return -EIO; - beiscsi_process_mcc_cq(phba); - /* after polling, wrb and tag need to be released */ - if (!test_bit(MCC_TAG_STATE_RUNNING, - &ctrl->ptag_state[tag].tag_state)) { - free_mcc_wrb(ctrl, tag); - break; - } - udelay(100); - } - - if (i < mcc_timeout) + if (test_bit(MCC_TAG_STATE_IGNORE, &ctrl->ptag_state[tag].tag_state)) { + /* just check completion status and free wrb */ + __beiscsi_mcc_compl_status(phba, tag, NULL, NULL); + free_mcc_wrb(ctrl, tag); return 0; + } - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX, - "BC_%d : FW Timed Out\n"); - phba->fw_timeout = true; - beiscsi_ue_detect(phba); - return -EBUSY; + wake_up_interruptible(&ctrl->mcc_wait[tag]); + return 0; } void be_mcc_notify(struct beiscsi_hba *phba, unsigned int tag) @@ -642,7 +599,7 @@ static int be_mbox_db_ready_poll(struct be_ctrl_info *ctrl) */ timeout = jiffies + msecs_to_jiffies(BEISCSI_MBX_RDY_BIT_TIMEOUT); do { - if (beiscsi_error(phba)) + if (beiscsi_hba_in_error(phba)) return -EIO; ready = ioread32(db); @@ -655,16 +612,14 @@ static int be_mbox_db_ready_poll(struct be_ctrl_info *ctrl) if (time_after(jiffies, timeout)) break; - msleep(20); + /* 1ms sleep is enough in most cases */ + schedule_timeout_uninterruptible(msecs_to_jiffies(1)); } while (!ready); beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX, "BC_%d : FW Timed Out\n"); - - phba->fw_timeout = true; - beiscsi_ue_detect(phba); - + set_bit(BEISCSI_HBA_FW_TIMEOUT, &phba->state); return -EBUSY; } @@ -679,7 +634,7 @@ static int be_mbox_db_ready_poll(struct be_ctrl_info *ctrl) * Success: 0 * Failure: Non-Zero **/ -int be_mbox_notify(struct be_ctrl_info *ctrl) +static int be_mbox_notify(struct be_ctrl_info *ctrl) { int status; u32 val = 0; @@ -819,87 +774,6 @@ int beiscsi_cmd_eq_create(struct be_ctrl_info *ctrl, return status; } -/** - * be_cmd_fw_initialize()- Initialize FW - * @ctrl: Pointer to function control structure - * - * Send FW initialize pattern for the function. - * - * return - * Success: 0 - * Failure: Non-Zero value - **/ -int be_cmd_fw_initialize(struct be_ctrl_info *ctrl) -{ - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); - struct beiscsi_hba *phba = pci_get_drvdata(ctrl->pdev); - int status; - u8 *endian_check; - - mutex_lock(&ctrl->mbox_lock); - memset(wrb, 0, sizeof(*wrb)); - - endian_check = (u8 *) wrb; - *endian_check++ = 0xFF; - *endian_check++ = 0x12; - *endian_check++ = 0x34; - *endian_check++ = 0xFF; - *endian_check++ = 0xFF; - *endian_check++ = 0x56; - *endian_check++ = 0x78; - *endian_check++ = 0xFF; - be_dws_cpu_to_le(wrb, sizeof(*wrb)); - - status = be_mbox_notify(ctrl); - if (status) - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, - "BC_%d : be_cmd_fw_initialize Failed\n"); - - mutex_unlock(&ctrl->mbox_lock); - return status; -} - -/** - * be_cmd_fw_uninit()- Uinitialize FW - * @ctrl: Pointer to function control structure - * - * Send FW uninitialize pattern for the function - * - * return - * Success: 0 - * Failure: Non-Zero value - **/ -int be_cmd_fw_uninit(struct be_ctrl_info *ctrl) -{ - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); - struct beiscsi_hba *phba = pci_get_drvdata(ctrl->pdev); - int status; - u8 *endian_check; - - mutex_lock(&ctrl->mbox_lock); - memset(wrb, 0, sizeof(*wrb)); - - endian_check = (u8 *) wrb; - *endian_check++ = 0xFF; - *endian_check++ = 0xAA; - *endian_check++ = 0xBB; - *endian_check++ = 0xFF; - *endian_check++ = 0xFF; - *endian_check++ = 0xCC; - *endian_check++ = 0xDD; - *endian_check = 0xFF; - - be_dws_cpu_to_le(wrb, sizeof(*wrb)); - - status = be_mbox_notify(ctrl); - if (status) - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, - "BC_%d : be_cmd_fw_uninit Failed\n"); - - mutex_unlock(&ctrl->mbox_lock); - return status; -} - int beiscsi_cmd_cq_create(struct be_ctrl_info *ctrl, struct be_queue_info *cq, struct be_queue_info *eq, bool sol_evts, bool no_delay, int coalesce_wm) @@ -1343,25 +1217,6 @@ error: return status; } -int beiscsi_cmd_reset_function(struct beiscsi_hba *phba) -{ - struct be_ctrl_info *ctrl = &phba->ctrl; - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); - struct be_post_sgl_pages_req *req = embedded_payload(wrb); - int status; - - mutex_lock(&ctrl->mbox_lock); - - req = embedded_payload(wrb); - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); - be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, - OPCODE_COMMON_FUNCTION_RESET, sizeof(*req)); - status = be_mbox_notify(ctrl); - - mutex_unlock(&ctrl->mbox_lock); - return status; -} - /** * be_cmd_set_vlan()- Configure VLAN paramters on the adapter * @phba: device priv structure instance @@ -1402,3 +1257,564 @@ int be_cmd_set_vlan(struct beiscsi_hba *phba, return tag; } + +int beiscsi_check_supported_fw(struct be_ctrl_info *ctrl, + struct beiscsi_hba *phba) +{ + struct be_dma_mem nonemb_cmd; + struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); + struct be_mgmt_controller_attributes *req; + struct be_sge *sge = nonembedded_sgl(wrb); + int status = 0; + + nonemb_cmd.va = pci_alloc_consistent(ctrl->pdev, + sizeof(struct be_mgmt_controller_attributes), + &nonemb_cmd.dma); + if (nonemb_cmd.va == NULL) { + beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, + "BG_%d : pci_alloc_consistent failed in %s\n", + __func__); + return -ENOMEM; + } + nonemb_cmd.size = sizeof(struct be_mgmt_controller_attributes); + req = nonemb_cmd.va; + memset(req, 0, sizeof(*req)); + mutex_lock(&ctrl->mbox_lock); + memset(wrb, 0, sizeof(*wrb)); + be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1); + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_GET_CNTL_ATTRIBUTES, sizeof(*req)); + sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd.dma)); + sge->pa_lo = cpu_to_le32(nonemb_cmd.dma & 0xFFFFFFFF); + sge->len = cpu_to_le32(nonemb_cmd.size); + status = be_mbox_notify(ctrl); + if (!status) { + struct be_mgmt_controller_attributes_resp *resp = nonemb_cmd.va; + + beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, + "BG_%d : Firmware Version of CMD : %s\n" + "Firmware Version is : %s\n" + "Developer Build, not performing version check...\n", + resp->params.hba_attribs + .flashrom_version_string, + resp->params.hba_attribs. + firmware_version_string); + + phba->fw_config.iscsi_features = + resp->params.hba_attribs.iscsi_features; + beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, + "BM_%d : phba->fw_config.iscsi_features = %d\n", + phba->fw_config.iscsi_features); + memcpy(phba->fw_ver_str, resp->params.hba_attribs. + firmware_version_string, BEISCSI_VER_STRLEN); + } else + beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, + "BG_%d : Failed in beiscsi_check_supported_fw\n"); + mutex_unlock(&ctrl->mbox_lock); + if (nonemb_cmd.va) + pci_free_consistent(ctrl->pdev, nonemb_cmd.size, + nonemb_cmd.va, nonemb_cmd.dma); + + return status; +} + +/** + * beiscsi_get_fw_config()- Get the FW config for the function + * @ctrl: ptr to Ctrl Info + * @phba: ptr to the dev priv structure + * + * Get the FW config and resources available for the function. + * The resources are created based on the count received here. + * + * return + * Success: 0 + * Failure: Non-Zero Value + **/ +int beiscsi_get_fw_config(struct be_ctrl_info *ctrl, + struct beiscsi_hba *phba) +{ + struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); + struct be_fw_cfg *pfw_cfg = embedded_payload(wrb); + uint32_t cid_count, icd_count; + int status = -EINVAL; + uint8_t ulp_num = 0; + + mutex_lock(&ctrl->mbox_lock); + memset(wrb, 0, sizeof(*wrb)); + be_wrb_hdr_prepare(wrb, sizeof(*pfw_cfg), true, 0); + + be_cmd_hdr_prepare(&pfw_cfg->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_QUERY_FIRMWARE_CONFIG, + EMBED_MBX_MAX_PAYLOAD_SIZE); + + if (be_mbox_notify(ctrl)) { + beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, + "BG_%d : Failed in beiscsi_get_fw_config\n"); + goto fail_init; + } + + /* FW response formats depend on port id */ + phba->fw_config.phys_port = pfw_cfg->phys_port; + if (phba->fw_config.phys_port >= BEISCSI_PHYS_PORT_MAX) { + beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, + "BG_%d : invalid physical port id %d\n", + phba->fw_config.phys_port); + goto fail_init; + } + + /* populate and check FW config against min and max values */ + if (!is_chip_be2_be3r(phba)) { + phba->fw_config.eqid_count = pfw_cfg->eqid_count; + phba->fw_config.cqid_count = pfw_cfg->cqid_count; + if (phba->fw_config.eqid_count == 0 || + phba->fw_config.eqid_count > 2048) { + beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, + "BG_%d : invalid EQ count %d\n", + phba->fw_config.eqid_count); + goto fail_init; + } + if (phba->fw_config.cqid_count == 0 || + phba->fw_config.cqid_count > 4096) { + beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, + "BG_%d : invalid CQ count %d\n", + phba->fw_config.cqid_count); + goto fail_init; + } + beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, + "BG_%d : EQ_Count : %d CQ_Count : %d\n", + phba->fw_config.eqid_count, + phba->fw_config.cqid_count); + } + + /** + * Check on which all ULP iSCSI Protocol is loaded. + * Set the Bit for those ULP. This set flag is used + * at all places in the code to check on which ULP + * iSCSi Protocol is loaded + **/ + for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) { + if (pfw_cfg->ulp[ulp_num].ulp_mode & + BEISCSI_ULP_ISCSI_INI_MODE) { + set_bit(ulp_num, &phba->fw_config.ulp_supported); + + /* Get the CID, ICD and Chain count for each ULP */ + phba->fw_config.iscsi_cid_start[ulp_num] = + pfw_cfg->ulp[ulp_num].sq_base; + phba->fw_config.iscsi_cid_count[ulp_num] = + pfw_cfg->ulp[ulp_num].sq_count; + + phba->fw_config.iscsi_icd_start[ulp_num] = + pfw_cfg->ulp[ulp_num].icd_base; + phba->fw_config.iscsi_icd_count[ulp_num] = + pfw_cfg->ulp[ulp_num].icd_count; + + phba->fw_config.iscsi_chain_start[ulp_num] = + pfw_cfg->chain_icd[ulp_num].chain_base; + phba->fw_config.iscsi_chain_count[ulp_num] = + pfw_cfg->chain_icd[ulp_num].chain_count; + + beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, + "BG_%d : Function loaded on ULP : %d\n" + "\tiscsi_cid_count : %d\n" + "\tiscsi_cid_start : %d\n" + "\t iscsi_icd_count : %d\n" + "\t iscsi_icd_start : %d\n", + ulp_num, + phba->fw_config. + iscsi_cid_count[ulp_num], + phba->fw_config. + iscsi_cid_start[ulp_num], + phba->fw_config. + iscsi_icd_count[ulp_num], + phba->fw_config. + iscsi_icd_start[ulp_num]); + } + } + + if (phba->fw_config.ulp_supported == 0) { + beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, + "BG_%d : iSCSI initiator mode not set: ULP0 %x ULP1 %x\n", + pfw_cfg->ulp[BEISCSI_ULP0].ulp_mode, + pfw_cfg->ulp[BEISCSI_ULP1].ulp_mode); + goto fail_init; + } + + /** + * ICD is shared among ULPs. Use icd_count of any one loaded ULP + **/ + for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) + if (test_bit(ulp_num, &phba->fw_config.ulp_supported)) + break; + icd_count = phba->fw_config.iscsi_icd_count[ulp_num]; + if (icd_count == 0 || icd_count > 65536) { + beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, + "BG_%d: invalid ICD count %d\n", icd_count); + goto fail_init; + } + + cid_count = BEISCSI_GET_CID_COUNT(phba, BEISCSI_ULP0) + + BEISCSI_GET_CID_COUNT(phba, BEISCSI_ULP1); + if (cid_count == 0 || cid_count > 4096) { + beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, + "BG_%d: invalid CID count %d\n", cid_count); + goto fail_init; + } + + /** + * Check FW is dual ULP aware i.e. can handle either + * of the protocols. + */ + phba->fw_config.dual_ulp_aware = (pfw_cfg->function_mode & + BEISCSI_FUNC_DUA_MODE); + + beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, + "BG_%d : DUA Mode : 0x%x\n", + phba->fw_config.dual_ulp_aware); + + /* all set, continue using this FW config */ + status = 0; +fail_init: + mutex_unlock(&ctrl->mbox_lock); + return status; +} + +/** + * beiscsi_get_port_name()- Get port name for the function + * @ctrl: ptr to Ctrl Info + * @phba: ptr to the dev priv structure + * + * Get the alphanumeric character for port + * + **/ +int beiscsi_get_port_name(struct be_ctrl_info *ctrl, struct beiscsi_hba *phba) +{ + int ret = 0; + struct be_mcc_wrb *wrb; + struct be_cmd_get_port_name *ioctl; + + mutex_lock(&ctrl->mbox_lock); + wrb = wrb_from_mbox(&ctrl->mbox_mem); + memset(wrb, 0, sizeof(*wrb)); + ioctl = embedded_payload(wrb); + + be_wrb_hdr_prepare(wrb, sizeof(*ioctl), true, 0); + be_cmd_hdr_prepare(&ioctl->h.req_hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_GET_PORT_NAME, + EMBED_MBX_MAX_PAYLOAD_SIZE); + ret = be_mbox_notify(ctrl); + phba->port_name = 0; + if (!ret) { + phba->port_name = ioctl->p.resp.port_names >> + (phba->fw_config.phys_port * 8) & 0xff; + } else { + beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, + "BG_%d : GET_PORT_NAME ret 0x%x status 0x%x\n", + ret, ioctl->h.resp_hdr.status); + } + + if (phba->port_name == 0) + phba->port_name = '?'; + + mutex_unlock(&ctrl->mbox_lock); + return ret; +} + +int beiscsi_set_uer_feature(struct beiscsi_hba *phba) +{ + struct be_ctrl_info *ctrl = &phba->ctrl; + struct be_cmd_set_features *ioctl; + struct be_mcc_wrb *wrb; + int ret = 0; + + mutex_lock(&ctrl->mbox_lock); + wrb = wrb_from_mbox(&ctrl->mbox_mem); + memset(wrb, 0, sizeof(*wrb)); + ioctl = embedded_payload(wrb); + + be_wrb_hdr_prepare(wrb, sizeof(*ioctl), true, 0); + be_cmd_hdr_prepare(&ioctl->h.req_hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_SET_FEATURES, + EMBED_MBX_MAX_PAYLOAD_SIZE); + ioctl->feature = BE_CMD_SET_FEATURE_UER; + ioctl->param_len = sizeof(ioctl->param.req); + ioctl->param.req.uer = BE_CMD_UER_SUPP_BIT; + ret = be_mbox_notify(ctrl); + if (!ret) { + phba->ue2rp = ioctl->param.resp.ue2rp; + set_bit(BEISCSI_HBA_UER_SUPP, &phba->state); + beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, + "BG_%d : HBA error recovery supported\n"); + } else { + /** + * Check "MCC_STATUS_INVALID_LENGTH" for SKH. + * Older FW versions return this error. + */ + if (ret == MCC_STATUS_ILLEGAL_REQUEST || + ret == MCC_STATUS_INVALID_LENGTH) + __beiscsi_log(phba, KERN_INFO, + "BG_%d : HBA error recovery not supported\n"); + } + + mutex_unlock(&ctrl->mbox_lock); + return ret; +} + +static u32 beiscsi_get_post_stage(struct beiscsi_hba *phba) +{ + u32 sem; + + if (is_chip_be2_be3r(phba)) + sem = ioread32(phba->csr_va + SLIPORT_SEMAPHORE_OFFSET_BEx); + else + pci_read_config_dword(phba->pcidev, + SLIPORT_SEMAPHORE_OFFSET_SH, &sem); + return sem; +} + +int beiscsi_check_fw_rdy(struct beiscsi_hba *phba) +{ + u32 loop, post, rdy = 0; + + loop = 1000; + while (loop--) { + post = beiscsi_get_post_stage(phba); + if (post & POST_ERROR_BIT) + break; + if ((post & POST_STAGE_MASK) == POST_STAGE_ARMFW_RDY) { + rdy = 1; + break; + } + msleep(60); + } + + if (!rdy) { + __beiscsi_log(phba, KERN_ERR, + "BC_%d : FW not ready 0x%x\n", post); + } + + return rdy; +} + +int beiscsi_cmd_function_reset(struct beiscsi_hba *phba) +{ + struct be_ctrl_info *ctrl = &phba->ctrl; + struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); + struct be_post_sgl_pages_req *req = embedded_payload(wrb); + int status; + + mutex_lock(&ctrl->mbox_lock); + + req = embedded_payload(wrb); + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_FUNCTION_RESET, sizeof(*req)); + status = be_mbox_notify(ctrl); + + mutex_unlock(&ctrl->mbox_lock); + return status; +} + +int beiscsi_cmd_special_wrb(struct be_ctrl_info *ctrl, u32 load) +{ + struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); + struct beiscsi_hba *phba = pci_get_drvdata(ctrl->pdev); + u8 *endian_check; + int status; + + mutex_lock(&ctrl->mbox_lock); + memset(wrb, 0, sizeof(*wrb)); + + endian_check = (u8 *) wrb; + if (load) { + /* to start communicating */ + *endian_check++ = 0xFF; + *endian_check++ = 0x12; + *endian_check++ = 0x34; + *endian_check++ = 0xFF; + *endian_check++ = 0xFF; + *endian_check++ = 0x56; + *endian_check++ = 0x78; + *endian_check++ = 0xFF; + } else { + /* to stop communicating */ + *endian_check++ = 0xFF; + *endian_check++ = 0xAA; + *endian_check++ = 0xBB; + *endian_check++ = 0xFF; + *endian_check++ = 0xFF; + *endian_check++ = 0xCC; + *endian_check++ = 0xDD; + *endian_check = 0xFF; + } + be_dws_cpu_to_le(wrb, sizeof(*wrb)); + + status = be_mbox_notify(ctrl); + if (status) + beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, + "BC_%d : special WRB message failed\n"); + mutex_unlock(&ctrl->mbox_lock); + return status; +} + +int beiscsi_init_sliport(struct beiscsi_hba *phba) +{ + int status; + + /* check POST stage before talking to FW */ + status = beiscsi_check_fw_rdy(phba); + if (!status) + return -EIO; + + /* clear all error states after checking FW rdy */ + phba->state &= ~BEISCSI_HBA_IN_ERR; + + /* check again UER support */ + phba->state &= ~BEISCSI_HBA_UER_SUPP; + + /* + * SLI COMMON_FUNCTION_RESET completion is indicated by BMBX RDY bit. + * It should clean up any stale info in FW for this fn. + */ + status = beiscsi_cmd_function_reset(phba); + if (status) { + beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, + "BC_%d : SLI Function Reset failed\n"); + return status; + } + + /* indicate driver is loading */ + return beiscsi_cmd_special_wrb(&phba->ctrl, 1); +} + +/** + * beiscsi_cmd_iscsi_cleanup()- Inform FW to cleanup EP data structures. + * @phba: pointer to dev priv structure + * @ulp: ULP number. + * + * return + * Success: 0 + * Failure: Non-Zero Value + **/ +int beiscsi_cmd_iscsi_cleanup(struct beiscsi_hba *phba, unsigned short ulp) +{ + struct be_ctrl_info *ctrl = &phba->ctrl; + struct iscsi_cleanup_req_v1 *req_v1; + struct iscsi_cleanup_req *req; + struct be_mcc_wrb *wrb; + int status; + + mutex_lock(&ctrl->mbox_lock); + wrb = wrb_from_mbox(&ctrl->mbox_mem); + req = embedded_payload(wrb); + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI, + OPCODE_COMMON_ISCSI_CLEANUP, sizeof(*req)); + + /** + * TODO: Check with FW folks the chute value to be set. + * For now, use the ULP_MASK as the chute value. + */ + if (is_chip_be2_be3r(phba)) { + req->chute = (1 << ulp); + req->hdr_ring_id = HWI_GET_DEF_HDRQ_ID(phba, ulp); + req->data_ring_id = HWI_GET_DEF_BUFQ_ID(phba, ulp); + } else { + req_v1 = (struct iscsi_cleanup_req_v1 *)req; + req_v1->hdr.version = 1; + req_v1->hdr_ring_id = cpu_to_le16(HWI_GET_DEF_HDRQ_ID(phba, + ulp)); + req_v1->data_ring_id = cpu_to_le16(HWI_GET_DEF_BUFQ_ID(phba, + ulp)); + } + + status = be_mbox_notify(ctrl); + if (status) + beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_INIT, + "BG_%d : %s failed %d\n", __func__, ulp); + mutex_unlock(&ctrl->mbox_lock); + return status; +} + +/* + * beiscsi_detect_ue()- Detect Unrecoverable Error on adapter + * @phba: Driver priv structure + * + * Read registers linked to UE and check for the UE status + **/ +int beiscsi_detect_ue(struct beiscsi_hba *phba) +{ + uint32_t ue_mask_hi = 0, ue_mask_lo = 0; + uint32_t ue_hi = 0, ue_lo = 0; + uint8_t i = 0; + int ret = 0; + + pci_read_config_dword(phba->pcidev, + PCICFG_UE_STATUS_LOW, &ue_lo); + pci_read_config_dword(phba->pcidev, + PCICFG_UE_STATUS_MASK_LOW, + &ue_mask_lo); + pci_read_config_dword(phba->pcidev, + PCICFG_UE_STATUS_HIGH, + &ue_hi); + pci_read_config_dword(phba->pcidev, + PCICFG_UE_STATUS_MASK_HI, + &ue_mask_hi); + + ue_lo = (ue_lo & ~ue_mask_lo); + ue_hi = (ue_hi & ~ue_mask_hi); + + + if (ue_lo || ue_hi) { + set_bit(BEISCSI_HBA_IN_UE, &phba->state); + __beiscsi_log(phba, KERN_ERR, + "BC_%d : HBA error detected\n"); + ret = 1; + } + + if (ue_lo) { + for (i = 0; ue_lo; ue_lo >>= 1, i++) { + if (ue_lo & 1) + __beiscsi_log(phba, KERN_ERR, + "BC_%d : UE_LOW %s bit set\n", + desc_ue_status_low[i]); + } + } + + if (ue_hi) { + for (i = 0; ue_hi; ue_hi >>= 1, i++) { + if (ue_hi & 1) + __beiscsi_log(phba, KERN_ERR, + "BC_%d : UE_HIGH %s bit set\n", + desc_ue_status_hi[i]); + } + } + return ret; +} + +/* + * beiscsi_detect_tpe()- Detect Transient Parity Error on adapter + * @phba: Driver priv structure + * + * Read SLIPORT SEMAPHORE register to check for UER + * + **/ +int beiscsi_detect_tpe(struct beiscsi_hba *phba) +{ + u32 post, status; + int ret = 0; + + post = beiscsi_get_post_stage(phba); + status = post & POST_STAGE_MASK; + if ((status & POST_ERR_RECOVERY_CODE_MASK) == + POST_STAGE_RECOVERABLE_ERR) { + set_bit(BEISCSI_HBA_IN_TPE, &phba->state); + __beiscsi_log(phba, KERN_INFO, + "BC_%d : HBA error recoverable: 0x%x\n", post); + ret = 1; + } else { + __beiscsi_log(phba, KERN_INFO, + "BC_%d : HBA in UE: 0x%x\n", post); + } + + return ret; +} diff --git a/drivers/scsi/be2iscsi/be_cmds.h b/drivers/scsi/be2iscsi/be_cmds.h index deeb951e6874..328fb5b973cd 100644 --- a/drivers/scsi/be2iscsi/be_cmds.h +++ b/drivers/scsi/be2iscsi/be_cmds.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2015 Emulex + * Copyright (C) 2005 - 2016 Broadcom * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -8,7 +8,7 @@ * Public License is included in this distribution in the file called COPYING. * * Contact Information: - * linux-drivers@avagotech.com + * linux-drivers@broadcom.com * * Emulex * 3333 Susan Street @@ -57,6 +57,7 @@ struct be_mcc_wrb { #define MCC_STATUS_ILLEGAL_REQUEST 0x2 #define MCC_STATUS_ILLEGAL_FIELD 0x3 #define MCC_STATUS_INSUFFICIENT_BUFFER 0x4 +#define MCC_STATUS_INVALID_LENGTH 0x74 #define CQE_STATUS_COMPL_MASK 0xFFFF #define CQE_STATUS_COMPL_SHIFT 0 /* bits 0 - 15 */ @@ -97,11 +98,23 @@ struct be_mcc_compl { #define MPU_MAILBOX_DB_RDY_MASK 0x1 /* bit 0 */ #define MPU_MAILBOX_DB_HI_MASK 0x2 /* bit 1 */ -/********** MPU semphore ******************/ -#define MPU_EP_SEMAPHORE_OFFSET 0xac -#define EP_SEMAPHORE_POST_STAGE_MASK 0x0000FFFF -#define EP_SEMAPHORE_POST_ERR_MASK 0x1 -#define EP_SEMAPHORE_POST_ERR_SHIFT 31 +/********** MPU semphore: used for SH & BE ******************/ +#define SLIPORT_SOFTRESET_OFFSET 0x5c /* CSR BAR offset */ +#define SLIPORT_SEMAPHORE_OFFSET_BEx 0xac /* CSR BAR offset */ +#define SLIPORT_SEMAPHORE_OFFSET_SH 0x94 /* PCI-CFG offset */ +#define POST_STAGE_MASK 0x0000FFFF +#define POST_ERROR_BIT 0x80000000 +#define POST_ERR_RECOVERY_CODE_MASK 0xF000 + +/* Soft Reset register masks */ +#define SLIPORT_SOFTRESET_SR_MASK 0x00000080 /* SR bit */ + +/* MPU semphore POST stage values */ +#define POST_STAGE_AWAITING_HOST_RDY 0x1 /* FW awaiting goahead from host */ +#define POST_STAGE_HOST_RDY 0x2 /* Host has given go-ahed to FW */ +#define POST_STAGE_BE_RESET 0x3 /* Host wants to reset chip */ +#define POST_STAGE_ARMFW_RDY 0xC000 /* FW is done with POST */ +#define POST_STAGE_RECOVERABLE_ERR 0xE000 /* Recoverable err detected */ /********** MCC door bell ************/ #define DB_MCCQ_OFFSET 0x140 @@ -109,9 +122,6 @@ struct be_mcc_compl { /* Number of entries posted */ #define DB_MCCQ_NUM_POSTED_SHIFT 16 /* bits 16 - 29 */ -/* MPU semphore POST stage values */ -#define POST_STAGE_ARMFW_RDY 0xc000 /* FW is done with POST */ - /** * When the async bit of mcc_compl is set, the last 4 bytes of * mcc_compl is interpreted as follows: @@ -217,6 +227,7 @@ struct be_mcc_mailbox { #define OPCODE_COMMON_QUERY_FIRMWARE_CONFIG 58 #define OPCODE_COMMON_FUNCTION_RESET 61 #define OPCODE_COMMON_GET_PORT_NAME 77 +#define OPCODE_COMMON_SET_FEATURES 191 /** * LIST of opcodes that are common between Initiator and Target @@ -345,8 +356,8 @@ struct be_cmd_req_logout_fw_sess { struct be_cmd_resp_logout_fw_sess { struct be_cmd_resp_hdr hdr; /* dw[4] */ -#define BEISCSI_MGMT_SESSION_CLOSE 0x20 uint32_t session_status; +#define BE_SESS_STATUS_CLOSE 0x20 } __packed; struct mgmt_conn_login_options { @@ -365,6 +376,14 @@ struct ip_addr_format { u16 size_of_structure; u8 reserved; u8 ip_type; +#define BEISCSI_IP_TYPE_V4 0x1 +#define BEISCSI_IP_TYPE_STATIC_V4 0x3 +#define BEISCSI_IP_TYPE_DHCP_V4 0x5 +/* type v4 values < type v6 values */ +#define BEISCSI_IP_TYPE_V6 0x10 +#define BEISCSI_IP_TYPE_ROUTABLE_V6 0x30 +#define BEISCSI_IP_TYPE_LINK_LOCAL_V6 0x50 +#define BEISCSI_IP_TYPE_AUTO_V6 0x90 u8 addr[16]; u32 rsvd0; } __packed; @@ -430,8 +449,13 @@ struct be_cmd_get_boot_target_req { struct be_cmd_get_boot_target_resp { struct be_cmd_resp_hdr hdr; - u32 boot_session_count; - int boot_session_handle; + u32 boot_session_count; + u32 boot_session_handle; +/** + * FW returns 0xffffffff if it couldn't establish connection with + * configured boot target. + */ +#define BE_BOOT_INVALID_SHANDLE 0xffffffff }; struct be_cmd_reopen_session_req { @@ -699,16 +723,59 @@ struct be_cmd_get_nic_conf_resp { u8 mac_address[ETH_ALEN]; } __packed; -#define BEISCSI_ALIAS_LEN 32 +/******************** Get HBA NAME *******************/ struct be_cmd_hba_name { struct be_cmd_req_hdr hdr; u16 flags; u16 rsvd0; u8 initiator_name[ISCSI_NAME_LEN]; - u8 initiator_alias[BEISCSI_ALIAS_LEN]; +#define BE_INI_ALIAS_LEN 32 + u8 initiator_alias[BE_INI_ALIAS_LEN]; } __packed; +/******************** COMMON SET Features *******************/ +#define BE_CMD_SET_FEATURE_UER 0x10 +#define BE_CMD_UER_SUPP_BIT 0x1 +struct be_uer_req { + u32 uer; + u32 rsvd; +}; + +struct be_uer_resp { + u32 uer; + u16 ue2rp; + u16 ue2sr; +}; + +struct be_cmd_set_features { + union { + struct be_cmd_req_hdr req_hdr; + struct be_cmd_resp_hdr resp_hdr; + } h; + u32 feature; + u32 param_len; + union { + struct be_uer_req req; + struct be_uer_resp resp; + u32 rsvd[2]; + } param; +} __packed; + +int beiscsi_cmd_function_reset(struct beiscsi_hba *phba); + +int beiscsi_cmd_special_wrb(struct be_ctrl_info *ctrl, u32 load); + +int beiscsi_check_fw_rdy(struct beiscsi_hba *phba); + +int beiscsi_init_sliport(struct beiscsi_hba *phba); + +int beiscsi_cmd_iscsi_cleanup(struct beiscsi_hba *phba, unsigned short ulp_num); + +int beiscsi_detect_ue(struct beiscsi_hba *phba); + +int beiscsi_detect_tpe(struct beiscsi_hba *phba); + int beiscsi_cmd_eq_create(struct be_ctrl_info *ctrl, struct be_queue_info *eq, int eq_delay); @@ -723,24 +790,21 @@ int beiscsi_cmd_mccq_create(struct beiscsi_hba *phba, struct be_queue_info *mccq, struct be_queue_info *cq); -int be_poll_mcc(struct be_ctrl_info *ctrl); -int mgmt_check_supported_fw(struct be_ctrl_info *ctrl, - struct beiscsi_hba *phba); unsigned int be_cmd_get_initname(struct beiscsi_hba *phba); void free_mcc_wrb(struct be_ctrl_info *ctrl, unsigned int tag); -int be_cmd_modify_eq_delay(struct beiscsi_hba *phba, struct be_set_eqd *, +int beiscsi_modify_eq_delay(struct beiscsi_hba *phba, struct be_set_eqd *, int num); int beiscsi_mccq_compl_wait(struct beiscsi_hba *phba, - uint32_t tag, struct be_mcc_wrb **wrb, + unsigned int tag, + struct be_mcc_wrb **wrb, struct be_dma_mem *mbx_cmd_mem); -/*ISCSI Functuions */ -int be_cmd_fw_initialize(struct be_ctrl_info *ctrl); -int be_cmd_fw_uninit(struct be_ctrl_info *ctrl); - +int __beiscsi_mcc_compl_status(struct beiscsi_hba *phba, + unsigned int tag, + struct be_mcc_wrb **wrb, + struct be_dma_mem *mbx_cmd_mem); struct be_mcc_wrb *wrb_from_mbox(struct be_dma_mem *mbox_mem); -int be_mcc_compl_poll(struct beiscsi_hba *phba, unsigned int tag); void be_mcc_notify(struct beiscsi_hba *phba, unsigned int tag); struct be_mcc_wrb *alloc_mcc_wrb(struct beiscsi_hba *phba, unsigned int *ref_tag); @@ -749,9 +813,6 @@ void beiscsi_process_async_event(struct beiscsi_hba *phba, int beiscsi_process_mcc_compl(struct be_ctrl_info *ctrl, struct be_mcc_compl *compl); - -int be_mbox_notify(struct be_ctrl_info *ctrl); - int be_cmd_create_default_pdu_queue(struct be_ctrl_info *ctrl, struct be_queue_info *cq, struct be_queue_info *dq, int length, @@ -767,8 +828,6 @@ int be_cmd_iscsi_post_sgl_pages(struct be_ctrl_info *ctrl, struct be_dma_mem *q_mem, u32 page_offset, u32 num_pages); -int beiscsi_cmd_reset_function(struct beiscsi_hba *phba); - int be_cmd_wrbq_create(struct be_ctrl_info *ctrl, struct be_dma_mem *q_mem, struct be_queue_info *wrbq, struct hwi_wrb_context *pwrb_context, @@ -777,6 +836,15 @@ int be_cmd_wrbq_create(struct be_ctrl_info *ctrl, struct be_dma_mem *q_mem, /* Configuration Functions */ int be_cmd_set_vlan(struct beiscsi_hba *phba, uint16_t vlan_tag); +int beiscsi_check_supported_fw(struct be_ctrl_info *ctrl, + struct beiscsi_hba *phba); + +int beiscsi_get_fw_config(struct be_ctrl_info *ctrl, struct beiscsi_hba *phba); + +int beiscsi_get_port_name(struct be_ctrl_info *ctrl, struct beiscsi_hba *phba); + +int beiscsi_set_uer_feature(struct beiscsi_hba *phba); + struct be_default_pdu_context { u32 dw[4]; } __packed; @@ -999,7 +1067,16 @@ struct iscsi_cleanup_req { u16 chute; u8 hdr_ring_id; u8 data_ring_id; +} __packed; +struct iscsi_cleanup_req_v1 { + struct be_cmd_req_hdr hdr; + u16 chute; + u16 rsvd1; + u16 hdr_ring_id; + u16 rsvd2; + u16 data_ring_id; + u16 rsvd3; } __packed; struct eq_delay { @@ -1368,14 +1445,9 @@ struct be_cmd_get_port_name { * the cxn */ -int beiscsi_pci_soft_reset(struct beiscsi_hba *phba); -int be_chk_reset_complete(struct beiscsi_hba *phba); - void be_wrb_hdr_prepare(struct be_mcc_wrb *wrb, int payload_len, bool embedded, u8 sge_cnt); void be_cmd_hdr_prepare(struct be_cmd_req_hdr *req_hdr, u8 subsystem, u8 opcode, int cmd_len); - -void beiscsi_fail_session(struct iscsi_cls_session *cls_session); #endif /* !BEISCSI_CMDS_H */ diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c index 09f89a3eaa87..ba258217614e 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.c +++ b/drivers/scsi/be2iscsi/be_iscsi.c @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2015 Emulex + * Copyright (C) 2005 - 2016 Broadcom * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -7,10 +7,10 @@ * as published by the Free Software Foundation. The full GNU General * Public License is included in this distribution in the file called COPYING. * - * Written by: Jayamohan Kallickal (jayamohan.kallickal@avagotech.com) + * Written by: Jayamohan Kallickal (jayamohan.kallickal@broadcom.com) * * Contact Information: - * linux-drivers@avagotech.com + * linux-drivers@broadcom.com * * Emulex * 3333 Susan Street @@ -52,22 +52,20 @@ struct iscsi_cls_session *beiscsi_session_create(struct iscsi_endpoint *ep, if (!ep) { - printk(KERN_ERR - "beiscsi_session_create: invalid ep\n"); + pr_err("beiscsi_session_create: invalid ep\n"); return NULL; } beiscsi_ep = ep->dd_data; phba = beiscsi_ep->phba; - if (phba->state & BE_ADAPTER_PCI_ERR) { - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, - "BS_%d : PCI_ERROR Recovery\n"); - return NULL; - } else { + if (!beiscsi_hba_is_online(phba)) { beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, - "BS_%d : In beiscsi_session_create\n"); + "BS_%d : HBA in error 0x%lx\n", phba->state); + return NULL; } + beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, + "BS_%d : In beiscsi_session_create\n"); if (cmds_max > beiscsi_ep->phba->params.wrbs_per_cxn) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, "BS_%d : Cannot handle %d cmds." @@ -120,6 +118,16 @@ void beiscsi_session_destroy(struct iscsi_cls_session *cls_session) } /** + * beiscsi_session_fail(): Closing session with appropriate error + * @cls_session: ptr to session + **/ +void beiscsi_session_fail(struct iscsi_cls_session *cls_session) +{ + iscsi_session_failure(cls_session->dd_data, ISCSI_ERR_CONN_FAILED); +} + + +/** * beiscsi_conn_create - create an instance of iscsi connection * @cls_session: ptr to iscsi_cls_session * @cid: iscsi cid @@ -237,7 +245,7 @@ int beiscsi_conn_bind(struct iscsi_cls_session *cls_session, return beiscsi_bindconn_cid(phba, beiscsi_conn, beiscsi_ep->ep_cid); } -static int beiscsi_create_ipv4_iface(struct beiscsi_hba *phba) +static int beiscsi_iface_create_ipv4(struct beiscsi_hba *phba) { if (phba->ipv4_iface) return 0; @@ -256,7 +264,7 @@ static int beiscsi_create_ipv4_iface(struct beiscsi_hba *phba) return 0; } -static int beiscsi_create_ipv6_iface(struct beiscsi_hba *phba) +static int beiscsi_iface_create_ipv6(struct beiscsi_hba *phba) { if (phba->ipv6_iface) return 0; @@ -275,79 +283,31 @@ static int beiscsi_create_ipv6_iface(struct beiscsi_hba *phba) return 0; } -void beiscsi_create_def_ifaces(struct beiscsi_hba *phba) +void beiscsi_iface_create_default(struct beiscsi_hba *phba) { struct be_cmd_get_if_info_resp *if_info; - if (!mgmt_get_if_info(phba, BE2_IPV4, &if_info)) { - beiscsi_create_ipv4_iface(phba); + if (!beiscsi_if_get_info(phba, BEISCSI_IP_TYPE_V4, &if_info)) { + beiscsi_iface_create_ipv4(phba); kfree(if_info); } - if (!mgmt_get_if_info(phba, BE2_IPV6, &if_info)) { - beiscsi_create_ipv6_iface(phba); + if (!beiscsi_if_get_info(phba, BEISCSI_IP_TYPE_V6, &if_info)) { + beiscsi_iface_create_ipv6(phba); kfree(if_info); } } -void beiscsi_destroy_def_ifaces(struct beiscsi_hba *phba) +void beiscsi_iface_destroy_default(struct beiscsi_hba *phba) { - if (phba->ipv6_iface) + if (phba->ipv6_iface) { iscsi_destroy_iface(phba->ipv6_iface); - if (phba->ipv4_iface) - iscsi_destroy_iface(phba->ipv4_iface); -} - -static int -beiscsi_set_static_ip(struct Scsi_Host *shost, - struct iscsi_iface_param_info *iface_param, - void *data, uint32_t dt_len) -{ - struct beiscsi_hba *phba = iscsi_host_priv(shost); - struct iscsi_iface_param_info *iface_ip = NULL; - struct iscsi_iface_param_info *iface_subnet = NULL; - struct nlattr *nla; - int ret; - - - switch (iface_param->param) { - case ISCSI_NET_PARAM_IPV4_BOOTPROTO: - nla = nla_find(data, dt_len, ISCSI_NET_PARAM_IPV4_ADDR); - if (nla) - iface_ip = nla_data(nla); - - nla = nla_find(data, dt_len, ISCSI_NET_PARAM_IPV4_SUBNET); - if (nla) - iface_subnet = nla_data(nla); - break; - case ISCSI_NET_PARAM_IPV4_ADDR: - iface_ip = iface_param; - nla = nla_find(data, dt_len, ISCSI_NET_PARAM_IPV4_SUBNET); - if (nla) - iface_subnet = nla_data(nla); - break; - case ISCSI_NET_PARAM_IPV4_SUBNET: - iface_subnet = iface_param; - nla = nla_find(data, dt_len, ISCSI_NET_PARAM_IPV4_ADDR); - if (nla) - iface_ip = nla_data(nla); - break; - default: - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, - "BS_%d : Unsupported param %d\n", - iface_param->param); + phba->ipv6_iface = NULL; } - - if (!iface_ip || !iface_subnet) { - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, - "BS_%d : IP and Subnet Mask required\n"); - return -EINVAL; + if (phba->ipv4_iface) { + iscsi_destroy_iface(phba->ipv4_iface); + phba->ipv4_iface = NULL; } - - ret = mgmt_set_ip(phba, iface_ip, iface_subnet, - ISCSI_BOOTPROTO_STATIC); - - return ret; } /** @@ -363,137 +323,141 @@ beiscsi_set_static_ip(struct Scsi_Host *shost, * Failure: Non-Zero Value **/ static int -beiscsi_set_vlan_tag(struct Scsi_Host *shost, - struct iscsi_iface_param_info *iface_param) +beiscsi_iface_config_vlan(struct Scsi_Host *shost, + struct iscsi_iface_param_info *iface_param) { struct beiscsi_hba *phba = iscsi_host_priv(shost); - int ret; - - /* Get the Interface Handle */ - ret = mgmt_get_all_if_id(phba); - if (ret) { - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, - "BS_%d : Getting Interface Handle Failed\n"); - return ret; - } + int ret = -EPERM; switch (iface_param->param) { case ISCSI_NET_PARAM_VLAN_ENABLED: + ret = 0; if (iface_param->value[0] != ISCSI_VLAN_ENABLE) - ret = mgmt_set_vlan(phba, BEISCSI_VLAN_DISABLE); + ret = beiscsi_if_set_vlan(phba, BEISCSI_VLAN_DISABLE); break; case ISCSI_NET_PARAM_VLAN_TAG: - ret = mgmt_set_vlan(phba, - *((uint16_t *)iface_param->value)); + ret = beiscsi_if_set_vlan(phba, + *((uint16_t *)iface_param->value)); break; - default: - beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG, - "BS_%d : Unknown Param Type : %d\n", - iface_param->param); - return -ENOSYS; } return ret; } static int -beiscsi_set_ipv4(struct Scsi_Host *shost, - struct iscsi_iface_param_info *iface_param, - void *data, uint32_t dt_len) +beiscsi_iface_config_ipv4(struct Scsi_Host *shost, + struct iscsi_iface_param_info *info, + void *data, uint32_t dt_len) { struct beiscsi_hba *phba = iscsi_host_priv(shost); - int ret = 0; + u8 *ip = NULL, *subnet = NULL, *gw; + struct nlattr *nla; + int ret = -EPERM; /* Check the param */ - switch (iface_param->param) { + switch (info->param) { + case ISCSI_NET_PARAM_IFACE_ENABLE: + if (info->value[0] == ISCSI_IFACE_ENABLE) + ret = beiscsi_iface_create_ipv4(phba); + else { + iscsi_destroy_iface(phba->ipv4_iface); + phba->ipv4_iface = NULL; + } + break; case ISCSI_NET_PARAM_IPV4_GW: - ret = mgmt_set_gateway(phba, iface_param); + gw = info->value; + ret = beiscsi_if_set_gw(phba, BEISCSI_IP_TYPE_V4, gw); break; case ISCSI_NET_PARAM_IPV4_BOOTPROTO: - if (iface_param->value[0] == ISCSI_BOOTPROTO_DHCP) - ret = mgmt_set_ip(phba, iface_param, - NULL, ISCSI_BOOTPROTO_DHCP); - else if (iface_param->value[0] == ISCSI_BOOTPROTO_STATIC) - ret = beiscsi_set_static_ip(shost, iface_param, - data, dt_len); + if (info->value[0] == ISCSI_BOOTPROTO_DHCP) + ret = beiscsi_if_en_dhcp(phba, BEISCSI_IP_TYPE_V4); + else if (info->value[0] == ISCSI_BOOTPROTO_STATIC) + /* release DHCP IP address */ + ret = beiscsi_if_en_static(phba, BEISCSI_IP_TYPE_V4, + NULL, NULL); else beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, "BS_%d : Invalid BOOTPROTO: %d\n", - iface_param->value[0]); + info->value[0]); break; - case ISCSI_NET_PARAM_IFACE_ENABLE: - if (iface_param->value[0] == ISCSI_IFACE_ENABLE) - ret = beiscsi_create_ipv4_iface(phba); - else - iscsi_destroy_iface(phba->ipv4_iface); - break; - case ISCSI_NET_PARAM_IPV4_SUBNET: case ISCSI_NET_PARAM_IPV4_ADDR: - ret = beiscsi_set_static_ip(shost, iface_param, - data, dt_len); + ip = info->value; + nla = nla_find(data, dt_len, ISCSI_NET_PARAM_IPV4_SUBNET); + if (nla) { + info = nla_data(nla); + subnet = info->value; + } + ret = beiscsi_if_en_static(phba, BEISCSI_IP_TYPE_V4, + ip, subnet); break; - case ISCSI_NET_PARAM_VLAN_ENABLED: - case ISCSI_NET_PARAM_VLAN_TAG: - ret = beiscsi_set_vlan_tag(shost, iface_param); + case ISCSI_NET_PARAM_IPV4_SUBNET: + /* + * OPCODE_COMMON_ISCSI_NTWK_MODIFY_IP_ADDR ioctl needs IP + * and subnet both. Find IP to be applied for this subnet. + */ + subnet = info->value; + nla = nla_find(data, dt_len, ISCSI_NET_PARAM_IPV4_ADDR); + if (nla) { + info = nla_data(nla); + ip = info->value; + } + ret = beiscsi_if_en_static(phba, BEISCSI_IP_TYPE_V4, + ip, subnet); break; - default: - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, - "BS_%d : Param %d not supported\n", - iface_param->param); } return ret; } static int -beiscsi_set_ipv6(struct Scsi_Host *shost, - struct iscsi_iface_param_info *iface_param, - void *data, uint32_t dt_len) +beiscsi_iface_config_ipv6(struct Scsi_Host *shost, + struct iscsi_iface_param_info *iface_param, + void *data, uint32_t dt_len) { struct beiscsi_hba *phba = iscsi_host_priv(shost); - int ret = 0; + int ret = -EPERM; switch (iface_param->param) { case ISCSI_NET_PARAM_IFACE_ENABLE: if (iface_param->value[0] == ISCSI_IFACE_ENABLE) - ret = beiscsi_create_ipv6_iface(phba); + ret = beiscsi_iface_create_ipv6(phba); else { iscsi_destroy_iface(phba->ipv6_iface); - ret = 0; + phba->ipv6_iface = NULL; } break; case ISCSI_NET_PARAM_IPV6_ADDR: - ret = mgmt_set_ip(phba, iface_param, NULL, - ISCSI_BOOTPROTO_STATIC); + ret = beiscsi_if_en_static(phba, BEISCSI_IP_TYPE_V6, + iface_param->value, NULL); break; - case ISCSI_NET_PARAM_VLAN_ENABLED: - case ISCSI_NET_PARAM_VLAN_TAG: - ret = beiscsi_set_vlan_tag(shost, iface_param); - break; - default: - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, - "BS_%d : Param %d not supported\n", - iface_param->param); } return ret; } -int be2iscsi_iface_set_param(struct Scsi_Host *shost, - void *data, uint32_t dt_len) +int beiscsi_iface_set_param(struct Scsi_Host *shost, + void *data, uint32_t dt_len) { struct iscsi_iface_param_info *iface_param = NULL; struct beiscsi_hba *phba = iscsi_host_priv(shost); struct nlattr *attrib; uint32_t rm_len = dt_len; - int ret = 0 ; + int ret; - if (phba->state & BE_ADAPTER_PCI_ERR) { - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, - "BS_%d : In PCI_ERROR Recovery\n"); + if (!beiscsi_hba_is_online(phba)) { + beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, + "BS_%d : HBA in error 0x%lx\n", phba->state); return -EBUSY; } + /* update interface_handle */ + ret = beiscsi_if_get_handle(phba); + if (ret) { + beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, + "BS_%d : Getting Interface Handle Failed\n"); + return ret; + } + nla_for_each_attr(attrib, data, dt_len, rm_len) { iface_param = nla_data(attrib); @@ -512,40 +476,58 @@ int be2iscsi_iface_set_param(struct Scsi_Host *shost, return -EINVAL; } - switch (iface_param->iface_type) { - case ISCSI_IFACE_TYPE_IPV4: - ret = beiscsi_set_ipv4(shost, iface_param, - data, dt_len); - break; - case ISCSI_IFACE_TYPE_IPV6: - ret = beiscsi_set_ipv6(shost, iface_param, - data, dt_len); + beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, + "BS_%d : %s.0 set param %d", + (iface_param->iface_type == ISCSI_IFACE_TYPE_IPV4) ? + "ipv4" : "ipv6", iface_param->param); + + ret = -EPERM; + switch (iface_param->param) { + case ISCSI_NET_PARAM_VLAN_ENABLED: + case ISCSI_NET_PARAM_VLAN_TAG: + ret = beiscsi_iface_config_vlan(shost, iface_param); break; default: - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, - "BS_%d : Invalid iface type :%d passed\n", - iface_param->iface_type); - break; + switch (iface_param->iface_type) { + case ISCSI_IFACE_TYPE_IPV4: + ret = beiscsi_iface_config_ipv4(shost, + iface_param, + data, dt_len); + break; + case ISCSI_IFACE_TYPE_IPV6: + ret = beiscsi_iface_config_ipv6(shost, + iface_param, + data, dt_len); + break; + } } + if (ret == -EPERM) { + __beiscsi_log(phba, KERN_ERR, + "BS_%d : %s.0 set param %d not permitted", + (iface_param->iface_type == + ISCSI_IFACE_TYPE_IPV4) ? "ipv4" : "ipv6", + iface_param->param); + ret = 0; + } if (ret) - return ret; + break; } return ret; } -static int be2iscsi_get_if_param(struct beiscsi_hba *phba, - struct iscsi_iface *iface, int param, - char *buf) +static int __beiscsi_iface_get_param(struct beiscsi_hba *phba, + struct iscsi_iface *iface, + int param, char *buf) { struct be_cmd_get_if_info_resp *if_info; - int len, ip_type = BE2_IPV4; + int len, ip_type = BEISCSI_IP_TYPE_V4; if (iface->iface_type == ISCSI_IFACE_TYPE_IPV6) - ip_type = BE2_IPV6; + ip_type = BEISCSI_IP_TYPE_V6; - len = mgmt_get_if_info(phba, ip_type, &if_info); + len = beiscsi_if_get_info(phba, ip_type, &if_info); if (len) return len; @@ -567,24 +549,24 @@ static int be2iscsi_get_if_param(struct beiscsi_hba *phba, break; case ISCSI_NET_PARAM_VLAN_ENABLED: len = sprintf(buf, "%s\n", - (if_info->vlan_priority == BEISCSI_VLAN_DISABLE) - ? "Disabled\n" : "Enabled\n"); + (if_info->vlan_priority == BEISCSI_VLAN_DISABLE) ? + "disable" : "enable"); break; case ISCSI_NET_PARAM_VLAN_ID: if (if_info->vlan_priority == BEISCSI_VLAN_DISABLE) len = -EINVAL; else len = sprintf(buf, "%d\n", - (if_info->vlan_priority & - ISCSI_MAX_VLAN_ID)); + (if_info->vlan_priority & + ISCSI_MAX_VLAN_ID)); break; case ISCSI_NET_PARAM_VLAN_PRIORITY: if (if_info->vlan_priority == BEISCSI_VLAN_DISABLE) len = -EINVAL; else len = sprintf(buf, "%d\n", - ((if_info->vlan_priority >> 13) & - ISCSI_MAX_VLAN_PRIORITY)); + ((if_info->vlan_priority >> 13) & + ISCSI_MAX_VLAN_PRIORITY)); break; default: WARN_ON(1); @@ -594,18 +576,20 @@ static int be2iscsi_get_if_param(struct beiscsi_hba *phba, return len; } -int be2iscsi_iface_get_param(struct iscsi_iface *iface, - enum iscsi_param_type param_type, - int param, char *buf) +int beiscsi_iface_get_param(struct iscsi_iface *iface, + enum iscsi_param_type param_type, + int param, char *buf) { struct Scsi_Host *shost = iscsi_iface_to_shost(iface); struct beiscsi_hba *phba = iscsi_host_priv(shost); struct be_cmd_get_def_gateway_resp gateway; - int len = -ENOSYS; + int len = -EPERM; - if (phba->state & BE_ADAPTER_PCI_ERR) { - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, - "BS_%d : In PCI_ERROR Recovery\n"); + if (param_type != ISCSI_NET_PARAM) + return 0; + if (!beiscsi_hba_is_online(phba)) { + beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, + "BS_%d : HBA in error 0x%lx\n", phba->state); return -EBUSY; } @@ -617,19 +601,22 @@ int be2iscsi_iface_get_param(struct iscsi_iface *iface, case ISCSI_NET_PARAM_VLAN_ENABLED: case ISCSI_NET_PARAM_VLAN_ID: case ISCSI_NET_PARAM_VLAN_PRIORITY: - len = be2iscsi_get_if_param(phba, iface, param, buf); + len = __beiscsi_iface_get_param(phba, iface, param, buf); break; case ISCSI_NET_PARAM_IFACE_ENABLE: - len = sprintf(buf, "enabled\n"); + if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) + len = sprintf(buf, "%s\n", + phba->ipv4_iface ? "enable" : "disable"); + else if (iface->iface_type == ISCSI_IFACE_TYPE_IPV6) + len = sprintf(buf, "%s\n", + phba->ipv6_iface ? "enable" : "disable"); break; case ISCSI_NET_PARAM_IPV4_GW: memset(&gateway, 0, sizeof(gateway)); - len = mgmt_get_gateway(phba, BE2_IPV4, &gateway); + len = beiscsi_if_get_gw(phba, BEISCSI_IP_TYPE_V4, &gateway); if (!len) len = sprintf(buf, "%pI4\n", &gateway.ip_addr.addr); break; - default: - len = -ENOSYS; } return len; @@ -647,7 +634,7 @@ int beiscsi_ep_get_param(struct iscsi_endpoint *ep, enum iscsi_param param, char *buf) { struct beiscsi_endpoint *beiscsi_ep = ep->dd_data; - int len = 0; + int len; beiscsi_log(beiscsi_ep->phba, KERN_INFO, BEISCSI_LOG_CONFIG, @@ -659,13 +646,13 @@ int beiscsi_ep_get_param(struct iscsi_endpoint *ep, len = sprintf(buf, "%hu\n", beiscsi_ep->dst_tcpport); break; case ISCSI_PARAM_CONN_ADDRESS: - if (beiscsi_ep->ip_type == BE2_IPV4) + if (beiscsi_ep->ip_type == BEISCSI_IP_TYPE_V4) len = sprintf(buf, "%pI4\n", &beiscsi_ep->dst_addr); else len = sprintf(buf, "%pI6\n", &beiscsi_ep->dst6_addr); break; default: - return -ENOSYS; + len = -EPERM; } return len; } @@ -758,7 +745,7 @@ static void beiscsi_get_port_state(struct Scsi_Host *shost) struct beiscsi_hba *phba = iscsi_host_priv(shost); struct iscsi_cls_host *ihost = shost->shost_data; - ihost->port_state = (phba->state & BE_ADAPTER_LINK_UP) ? + ihost->port_state = test_bit(BEISCSI_HBA_LINK_UP, &phba->state) ? ISCSI_PORT_STATE_UP : ISCSI_PORT_STATE_DOWN; } @@ -810,16 +797,13 @@ int beiscsi_get_host_param(struct Scsi_Host *shost, struct beiscsi_hba *phba = iscsi_host_priv(shost); int status = 0; - - if (phba->state & BE_ADAPTER_PCI_ERR) { - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, - "BS_%d : In PCI_ERROR Recovery\n"); - return -EBUSY; - } else { + if (!beiscsi_hba_is_online(phba)) { beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, - "BS_%d : In beiscsi_get_host_param," - " param = %d\n", param); + "BS_%d : HBA in error 0x%lx\n", phba->state); + return -EBUSY; } + beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, + "BS_%d : In beiscsi_get_host_param, param = %d\n", param); switch (param) { case ISCSI_HOST_PARAM_HWADDRESS: @@ -961,15 +945,13 @@ int beiscsi_conn_start(struct iscsi_cls_conn *cls_conn) phba = ((struct beiscsi_conn *)conn->dd_data)->phba; - if (phba->state & BE_ADAPTER_PCI_ERR) { - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, - "BS_%d : In PCI_ERROR Recovery\n"); + if (!beiscsi_hba_is_online(phba)) { + beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, + "BS_%d : HBA in error 0x%lx\n", phba->state); return -EBUSY; - } else { - beiscsi_log(beiscsi_conn->phba, KERN_INFO, - BEISCSI_LOG_CONFIG, - "BS_%d : In beiscsi_conn_start\n"); } + beiscsi_log(beiscsi_conn->phba, KERN_INFO, BEISCSI_LOG_CONFIG, + "BS_%d : In beiscsi_conn_start\n"); memset(¶ms, 0, sizeof(struct beiscsi_offload_params)); beiscsi_ep = beiscsi_conn->ep; @@ -1186,28 +1168,20 @@ beiscsi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr, struct iscsi_endpoint *ep; int ret; - if (shost) - phba = iscsi_host_priv(shost); - else { + if (!shost) { ret = -ENXIO; - printk(KERN_ERR - "beiscsi_ep_connect shost is NULL\n"); + pr_err("beiscsi_ep_connect shost is NULL\n"); return ERR_PTR(ret); } - if (beiscsi_error(phba)) { + phba = iscsi_host_priv(shost); + if (!beiscsi_hba_is_online(phba)) { ret = -EIO; - beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG, - "BS_%d : The FW state Not Stable!!!\n"); + beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, + "BS_%d : HBA in error 0x%lx\n", phba->state); return ERR_PTR(ret); } - - if (phba->state & BE_ADAPTER_PCI_ERR) { - ret = -EBUSY; - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, - "BS_%d : In PCI_ERROR Recovery\n"); - return ERR_PTR(ret); - } else if (phba->state & BE_ADAPTER_LINK_DOWN) { + if (!test_bit(BEISCSI_HBA_LINK_UP, &phba->state)) { ret = -EBUSY; beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG, "BS_%d : The Adapter Port state is Down!!!\n"); @@ -1361,9 +1335,9 @@ void beiscsi_ep_disconnect(struct iscsi_endpoint *ep) tcp_upload_flag = CONNECTION_UPLOAD_ABORT; } - if (phba->state & BE_ADAPTER_PCI_ERR) { - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, - "BS_%d : PCI_ERROR Recovery\n"); + if (!beiscsi_hba_is_online(phba)) { + beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, + "BS_%d : HBA in error 0x%lx\n", phba->state); goto free_ep; } @@ -1386,7 +1360,7 @@ free_ep: iscsi_destroy_endpoint(beiscsi_ep->openiscsi_ep); } -umode_t be2iscsi_attr_is_visible(int param_type, int param) +umode_t beiscsi_attr_is_visible(int param_type, int param) { switch (param_type) { case ISCSI_NET_PARAM: diff --git a/drivers/scsi/be2iscsi/be_iscsi.h b/drivers/scsi/be2iscsi/be_iscsi.h index 0c84e1c0763a..e4d67dfea4cb 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.h +++ b/drivers/scsi/be2iscsi/be_iscsi.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2015 Avago Technologies + * Copyright (C) 2005 - 2016 Broadcom * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -7,10 +7,10 @@ * as published by the Free Software Foundation. The full GNU General * Public License is included in this distribution in the file called COPYING. * - * Written by: Jayamohan Kallickal (jayamohan.kallickal@avagotech.com) + * Written by: Jayamohan Kallickal (jayamohan.kallickal@broadcom.com) * * Contact Information: - * linux-drivers@avagotech.com + * linux-drivers@broadcom.com * * Avago Technologies * 3333 Susan Street @@ -23,25 +23,18 @@ #include "be_main.h" #include "be_mgmt.h" -#define BE2_IPV4 0x1 -#define BE2_IPV6 0x10 -#define BE2_DHCP_V4 0x05 +void beiscsi_iface_create_default(struct beiscsi_hba *phba); -#define NON_BLOCKING 0x0 -#define BLOCKING 0x1 +void beiscsi_iface_destroy_default(struct beiscsi_hba *phba); -void beiscsi_create_def_ifaces(struct beiscsi_hba *phba); - -void beiscsi_destroy_def_ifaces(struct beiscsi_hba *phba); - -int be2iscsi_iface_get_param(struct iscsi_iface *iface, +int beiscsi_iface_get_param(struct iscsi_iface *iface, enum iscsi_param_type param_type, int param, char *buf); -int be2iscsi_iface_set_param(struct Scsi_Host *shost, +int beiscsi_iface_set_param(struct Scsi_Host *shost, void *data, uint32_t count); -umode_t be2iscsi_attr_is_visible(int param_type, int param); +umode_t beiscsi_attr_is_visible(int param_type, int param); void beiscsi_offload_connection(struct beiscsi_conn *beiscsi_conn, struct beiscsi_offload_params *params); @@ -57,6 +50,8 @@ struct iscsi_cls_session *beiscsi_session_create(struct iscsi_endpoint *ep, void beiscsi_session_destroy(struct iscsi_cls_session *cls_session); +void beiscsi_session_fail(struct iscsi_cls_session *cls_session); + struct iscsi_cls_conn *beiscsi_conn_create(struct iscsi_cls_session *cls_session, uint32_t cid); diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index f05e7737107d..6a6906f847db 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2015 Emulex + * Copyright (C) 2005 - 2016 Broadcom * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -7,10 +7,10 @@ * as published by the Free Software Foundation. The full GNU General * Public License is included in this distribution in the file called COPYING. * - * Written by: Jayamohan Kallickal (jayamohan.kallickal@avagotech.com) + * Written by: Jayamohan Kallickal (jayamohan.kallickal@broadcom.com) * * Contact Information: - * linux-drivers@avagotech.com + * linux-drivers@broadcom.com * * Emulex * 3333 Susan Street @@ -374,170 +374,6 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc) return iscsi_eh_device_reset(sc); } -static ssize_t beiscsi_show_boot_tgt_info(void *data, int type, char *buf) -{ - struct beiscsi_hba *phba = data; - struct mgmt_session_info *boot_sess = &phba->boot_sess; - struct mgmt_conn_info *boot_conn = &boot_sess->conn_list[0]; - char *str = buf; - int rc; - - switch (type) { - case ISCSI_BOOT_TGT_NAME: - rc = sprintf(buf, "%.*s\n", - (int)strlen(boot_sess->target_name), - (char *)&boot_sess->target_name); - break; - case ISCSI_BOOT_TGT_IP_ADDR: - if (boot_conn->dest_ipaddr.ip_type == 0x1) - rc = sprintf(buf, "%pI4\n", - (char *)&boot_conn->dest_ipaddr.addr); - else - rc = sprintf(str, "%pI6\n", - (char *)&boot_conn->dest_ipaddr.addr); - break; - case ISCSI_BOOT_TGT_PORT: - rc = sprintf(str, "%d\n", boot_conn->dest_port); - break; - - case ISCSI_BOOT_TGT_CHAP_NAME: - rc = sprintf(str, "%.*s\n", - boot_conn->negotiated_login_options.auth_data.chap. - target_chap_name_length, - (char *)&boot_conn->negotiated_login_options. - auth_data.chap.target_chap_name); - break; - case ISCSI_BOOT_TGT_CHAP_SECRET: - rc = sprintf(str, "%.*s\n", - boot_conn->negotiated_login_options.auth_data.chap. - target_secret_length, - (char *)&boot_conn->negotiated_login_options. - auth_data.chap.target_secret); - break; - case ISCSI_BOOT_TGT_REV_CHAP_NAME: - rc = sprintf(str, "%.*s\n", - boot_conn->negotiated_login_options.auth_data.chap. - intr_chap_name_length, - (char *)&boot_conn->negotiated_login_options. - auth_data.chap.intr_chap_name); - break; - case ISCSI_BOOT_TGT_REV_CHAP_SECRET: - rc = sprintf(str, "%.*s\n", - boot_conn->negotiated_login_options.auth_data.chap. - intr_secret_length, - (char *)&boot_conn->negotiated_login_options. - auth_data.chap.intr_secret); - break; - case ISCSI_BOOT_TGT_FLAGS: - rc = sprintf(str, "2\n"); - break; - case ISCSI_BOOT_TGT_NIC_ASSOC: - rc = sprintf(str, "0\n"); - break; - default: - rc = -ENOSYS; - break; - } - return rc; -} - -static ssize_t beiscsi_show_boot_ini_info(void *data, int type, char *buf) -{ - struct beiscsi_hba *phba = data; - char *str = buf; - int rc; - - switch (type) { - case ISCSI_BOOT_INI_INITIATOR_NAME: - rc = sprintf(str, "%s\n", phba->boot_sess.initiator_iscsiname); - break; - default: - rc = -ENOSYS; - break; - } - return rc; -} - -static ssize_t beiscsi_show_boot_eth_info(void *data, int type, char *buf) -{ - struct beiscsi_hba *phba = data; - char *str = buf; - int rc; - - switch (type) { - case ISCSI_BOOT_ETH_FLAGS: - rc = sprintf(str, "2\n"); - break; - case ISCSI_BOOT_ETH_INDEX: - rc = sprintf(str, "0\n"); - break; - case ISCSI_BOOT_ETH_MAC: - rc = beiscsi_get_macaddr(str, phba); - break; - default: - rc = -ENOSYS; - break; - } - return rc; -} - - -static umode_t beiscsi_tgt_get_attr_visibility(void *data, int type) -{ - umode_t rc; - - switch (type) { - case ISCSI_BOOT_TGT_NAME: - case ISCSI_BOOT_TGT_IP_ADDR: - case ISCSI_BOOT_TGT_PORT: - case ISCSI_BOOT_TGT_CHAP_NAME: - case ISCSI_BOOT_TGT_CHAP_SECRET: - case ISCSI_BOOT_TGT_REV_CHAP_NAME: - case ISCSI_BOOT_TGT_REV_CHAP_SECRET: - case ISCSI_BOOT_TGT_NIC_ASSOC: - case ISCSI_BOOT_TGT_FLAGS: - rc = S_IRUGO; - break; - default: - rc = 0; - break; - } - return rc; -} - -static umode_t beiscsi_ini_get_attr_visibility(void *data, int type) -{ - umode_t rc; - - switch (type) { - case ISCSI_BOOT_INI_INITIATOR_NAME: - rc = S_IRUGO; - break; - default: - rc = 0; - break; - } - return rc; -} - - -static umode_t beiscsi_eth_get_attr_visibility(void *data, int type) -{ - umode_t rc; - - switch (type) { - case ISCSI_BOOT_ETH_FLAGS: - case ISCSI_BOOT_ETH_MAC: - case ISCSI_BOOT_ETH_INDEX: - rc = S_IRUGO; - break; - default: - rc = 0; - break; - } - return rc; -} - /*------------------- PCI Driver operations and data ----------------- */ static const struct pci_device_id beiscsi_pci_id_table[] = { { PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID1) }, @@ -850,12 +686,11 @@ static void hwi_ring_eq_db(struct beiscsi_hba *phba, static irqreturn_t be_isr_mcc(int irq, void *dev_id) { struct beiscsi_hba *phba; - struct be_eq_entry *eqe = NULL; + struct be_eq_entry *eqe; struct be_queue_info *eq; struct be_queue_info *mcc; - unsigned int num_eq_processed; + unsigned int mcc_events; struct be_eq_obj *pbe_eq; - unsigned long flags; pbe_eq = dev_id; eq = &pbe_eq->q; @@ -863,27 +698,23 @@ static irqreturn_t be_isr_mcc(int irq, void *dev_id) mcc = &phba->ctrl.mcc_obj.cq; eqe = queue_tail_node(eq); - num_eq_processed = 0; - + mcc_events = 0; while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32] & EQE_VALID_MASK) { if (((eqe->dw[offsetof(struct amap_eq_entry, resource_id) / 32] & EQE_RESID_MASK) >> 16) == mcc->id) { - spin_lock_irqsave(&phba->isr_lock, flags); - pbe_eq->todo_mcc_cq = true; - spin_unlock_irqrestore(&phba->isr_lock, flags); + mcc_events++; } AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0); queue_tail_inc(eq); eqe = queue_tail_node(eq); - num_eq_processed++; } - if (pbe_eq->todo_mcc_cq) - queue_work(phba->wq, &pbe_eq->work_cqs); - if (num_eq_processed) - hwi_ring_eq_db(phba, eq->id, 1, num_eq_processed, 1, 1); + if (mcc_events) { + queue_work(phba->wq, &pbe_eq->mcc_work); + hwi_ring_eq_db(phba, eq->id, 1, mcc_events, 1, 1); + } return IRQ_HANDLED; } @@ -902,7 +733,6 @@ static irqreturn_t be_isr_msix(int irq, void *dev_id) eq = &pbe_eq->q; phba = pbe_eq->phba; - /* disable interrupt till iopoll completes */ hwi_ring_eq_db(phba, eq->id, 1, 0, 0, 1); irq_poll_sched(&pbe_eq->iopoll); @@ -920,14 +750,13 @@ static irqreturn_t be_isr(int irq, void *dev_id) struct beiscsi_hba *phba; struct hwi_controller *phwi_ctrlr; struct hwi_context_memory *phwi_context; - struct be_eq_entry *eqe = NULL; + struct be_eq_entry *eqe; struct be_queue_info *eq; struct be_queue_info *mcc; - unsigned long flags, index; - unsigned int num_mcceq_processed, num_ioeq_processed; + unsigned int mcc_events, io_events; struct be_ctrl_info *ctrl; struct be_eq_obj *pbe_eq; - int isr; + int isr, rearm; phba = dev_id; ctrl = &phba->ctrl; @@ -942,44 +771,35 @@ static irqreturn_t be_isr(int irq, void *dev_id) eq = &phwi_context->be_eq[0].q; mcc = &phba->ctrl.mcc_obj.cq; - index = 0; eqe = queue_tail_node(eq); - num_ioeq_processed = 0; - num_mcceq_processed = 0; + io_events = 0; + mcc_events = 0; while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32] & EQE_VALID_MASK) { if (((eqe->dw[offsetof(struct amap_eq_entry, - resource_id) / 32] & - EQE_RESID_MASK) >> 16) == mcc->id) { - spin_lock_irqsave(&phba->isr_lock, flags); - pbe_eq->todo_mcc_cq = true; - spin_unlock_irqrestore(&phba->isr_lock, flags); - num_mcceq_processed++; - } else { - irq_poll_sched(&pbe_eq->iopoll); - num_ioeq_processed++; - } + resource_id) / 32] & EQE_RESID_MASK) >> 16) == mcc->id) + mcc_events++; + else + io_events++; AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0); queue_tail_inc(eq); eqe = queue_tail_node(eq); } - if (num_ioeq_processed || num_mcceq_processed) { - if (pbe_eq->todo_mcc_cq) - queue_work(phba->wq, &pbe_eq->work_cqs); - - if ((num_mcceq_processed) && (!num_ioeq_processed)) - hwi_ring_eq_db(phba, eq->id, 0, - (num_ioeq_processed + - num_mcceq_processed) , 1, 1); - else - hwi_ring_eq_db(phba, eq->id, 0, - (num_ioeq_processed + - num_mcceq_processed), 0, 1); - - return IRQ_HANDLED; - } else + if (!io_events && !mcc_events) return IRQ_NONE; + + /* no need to rearm if interrupt is only for IOs */ + rearm = 0; + if (mcc_events) { + queue_work(phba->wq, &pbe_eq->mcc_work); + /* rearm for MCCQ */ + rearm = 1; + } + if (io_events) + irq_poll_sched(&pbe_eq->iopoll); + hwi_ring_eq_db(phba, eq->id, 0, (io_events + mcc_events), rearm, 1); + return IRQ_HANDLED; } @@ -1077,57 +897,6 @@ void hwi_ring_cq_db(struct beiscsi_hba *phba, iowrite32(val, phba->db_va + DB_CQ_OFFSET); } -static unsigned int -beiscsi_process_async_pdu(struct beiscsi_conn *beiscsi_conn, - struct beiscsi_hba *phba, - struct pdu_base *ppdu, - unsigned long pdu_len, - void *pbuffer, unsigned long buf_len) -{ - struct iscsi_conn *conn = beiscsi_conn->conn; - struct iscsi_session *session = conn->session; - struct iscsi_task *task; - struct beiscsi_io_task *io_task; - struct iscsi_hdr *login_hdr; - - switch (ppdu->dw[offsetof(struct amap_pdu_base, opcode) / 32] & - PDUBASE_OPCODE_MASK) { - case ISCSI_OP_NOOP_IN: - pbuffer = NULL; - buf_len = 0; - break; - case ISCSI_OP_ASYNC_EVENT: - break; - case ISCSI_OP_REJECT: - WARN_ON(!pbuffer); - WARN_ON(!(buf_len == 48)); - beiscsi_log(phba, KERN_ERR, - BEISCSI_LOG_CONFIG | BEISCSI_LOG_IO, - "BM_%d : In ISCSI_OP_REJECT\n"); - break; - case ISCSI_OP_LOGIN_RSP: - case ISCSI_OP_TEXT_RSP: - task = conn->login_task; - io_task = task->dd_data; - login_hdr = (struct iscsi_hdr *)ppdu; - login_hdr->itt = io_task->libiscsi_itt; - break; - default: - beiscsi_log(phba, KERN_WARNING, - BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG, - "BM_%d : Unrecognized opcode 0x%x in async msg\n", - (ppdu-> - dw[offsetof(struct amap_pdu_base, opcode) / 32] - & PDUBASE_OPCODE_MASK)); - return 1; - } - - spin_lock_bh(&session->back_lock); - __iscsi_complete_pdu(conn, (struct iscsi_hdr *)ppdu, pbuffer, buf_len); - spin_unlock_bh(&session->back_lock); - return 0; -} - static struct sgl_handle *alloc_io_sgl_handle(struct beiscsi_hba *phba) { struct sgl_handle *psgl_handle; @@ -1199,6 +968,9 @@ beiscsi_get_wrb_handle(struct hwi_wrb_context *pwrb_context, pwrb_context->alloc_index++; spin_unlock_bh(&pwrb_context->wrb_lock); + if (pwrb_handle) + memset(pwrb_handle->pwrb, 0, sizeof(*pwrb_handle->pwrb)); + return pwrb_handle; } @@ -1440,11 +1212,10 @@ hwi_complete_drvr_msgs(struct beiscsi_conn *beiscsi_conn, struct beiscsi_hba *phba, struct sol_cqe *psol) { struct hwi_wrb_context *pwrb_context; - struct wrb_handle *pwrb_handle = NULL; + uint16_t wrb_index, cid, cri_index; struct hwi_controller *phwi_ctrlr; + struct wrb_handle *pwrb_handle; struct iscsi_task *task; - struct beiscsi_io_task *io_task; - uint16_t wrb_index, cid, cri_index; phwi_ctrlr = phba->phwi_ctrlr; if (is_chip_be2_be3r(phba)) { @@ -1463,9 +1234,6 @@ hwi_complete_drvr_msgs(struct beiscsi_conn *beiscsi_conn, pwrb_context = &phwi_ctrlr->wrb_context[cri_index]; pwrb_handle = pwrb_context->pwrb_handle_basestd[wrb_index]; task = pwrb_handle->pio_handle; - - io_task = task->dd_data; - memset(io_task->pwrb_handle->pwrb, 0, sizeof(struct iscsi_wrb)); iscsi_put_task(task); } @@ -1614,431 +1382,428 @@ static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn, spin_unlock_bh(&session->back_lock); } -static struct list_head *hwi_get_async_busy_list(struct hwi_async_pdu_context - *pasync_ctx, unsigned int is_header, - unsigned int host_write_ptr) +/** + * ASYNC PDUs include + * a. Unsolicited NOP-In (target initiated NOP-In) + * b. ASYNC Messages + * c. Reject PDU + * d. Login response + * These headers arrive unprocessed by the EP firmware. + * iSCSI layer processes them. + */ +static unsigned int +beiscsi_complete_pdu(struct beiscsi_conn *beiscsi_conn, + struct pdu_base *phdr, void *pdata, unsigned int dlen) { - if (is_header) - return &pasync_ctx->async_entry[host_write_ptr]. - header_busy_list; - else - return &pasync_ctx->async_entry[host_write_ptr].data_busy_list; + struct beiscsi_hba *phba = beiscsi_conn->phba; + struct iscsi_conn *conn = beiscsi_conn->conn; + struct beiscsi_io_task *io_task; + struct iscsi_hdr *login_hdr; + struct iscsi_task *task; + u8 code; + + code = AMAP_GET_BITS(struct amap_pdu_base, opcode, phdr); + switch (code) { + case ISCSI_OP_NOOP_IN: + pdata = NULL; + dlen = 0; + break; + case ISCSI_OP_ASYNC_EVENT: + break; + case ISCSI_OP_REJECT: + WARN_ON(!pdata); + WARN_ON(!(dlen == 48)); + beiscsi_log(phba, KERN_ERR, + BEISCSI_LOG_CONFIG | BEISCSI_LOG_IO, + "BM_%d : In ISCSI_OP_REJECT\n"); + break; + case ISCSI_OP_LOGIN_RSP: + case ISCSI_OP_TEXT_RSP: + task = conn->login_task; + io_task = task->dd_data; + login_hdr = (struct iscsi_hdr *)phdr; + login_hdr->itt = io_task->libiscsi_itt; + break; + default: + beiscsi_log(phba, KERN_WARNING, + BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG, + "BM_%d : unrecognized async PDU opcode 0x%x\n", + code); + return 1; + } + __iscsi_complete_pdu(conn, (struct iscsi_hdr *)phdr, pdata, dlen); + return 0; +} + +static inline void +beiscsi_hdl_put_handle(struct hd_async_context *pasync_ctx, + struct hd_async_handle *pasync_handle) +{ + if (pasync_handle->is_header) { + list_add_tail(&pasync_handle->link, + &pasync_ctx->async_header.free_list); + pasync_ctx->async_header.free_entries++; + } else { + list_add_tail(&pasync_handle->link, + &pasync_ctx->async_data.free_list); + pasync_ctx->async_data.free_entries++; + } } -static struct async_pdu_handle * -hwi_get_async_handle(struct beiscsi_hba *phba, - struct beiscsi_conn *beiscsi_conn, - struct hwi_async_pdu_context *pasync_ctx, - struct i_t_dpdu_cqe *pdpdu_cqe, unsigned int *pcq_index) +static struct hd_async_handle * +beiscsi_hdl_get_handle(struct beiscsi_conn *beiscsi_conn, + struct hd_async_context *pasync_ctx, + struct i_t_dpdu_cqe *pdpdu_cqe) { + struct beiscsi_hba *phba = beiscsi_conn->phba; + struct hd_async_handle *pasync_handle; struct be_bus_address phys_addr; - struct list_head *pbusy_list; - struct async_pdu_handle *pasync_handle = NULL; - unsigned char is_header = 0; - unsigned int index, dpl; + u8 final, error = 0; + u16 cid, code, ci; + u32 dpl; + cid = beiscsi_conn->beiscsi_conn_cid; + /** + * This function is invoked to get the right async_handle structure + * from a given DEF PDU CQ entry. + * + * - index in CQ entry gives the vertical index + * - address in CQ entry is the offset where the DMA last ended + * - final - no more notifications for this PDU + */ if (is_chip_be2_be3r(phba)) { dpl = AMAP_GET_BITS(struct amap_i_t_dpdu_cqe, dpl, pdpdu_cqe); - index = AMAP_GET_BITS(struct amap_i_t_dpdu_cqe, + ci = AMAP_GET_BITS(struct amap_i_t_dpdu_cqe, index, pdpdu_cqe); + final = AMAP_GET_BITS(struct amap_i_t_dpdu_cqe, + final, pdpdu_cqe); } else { dpl = AMAP_GET_BITS(struct amap_i_t_dpdu_cqe_v2, dpl, pdpdu_cqe); - index = AMAP_GET_BITS(struct amap_i_t_dpdu_cqe_v2, + ci = AMAP_GET_BITS(struct amap_i_t_dpdu_cqe_v2, index, pdpdu_cqe); + final = AMAP_GET_BITS(struct amap_i_t_dpdu_cqe_v2, + final, pdpdu_cqe); } - phys_addr.u.a32.address_lo = - (pdpdu_cqe->dw[offsetof(struct amap_i_t_dpdu_cqe, - db_addr_lo) / 32] - dpl); - phys_addr.u.a32.address_hi = - pdpdu_cqe->dw[offsetof(struct amap_i_t_dpdu_cqe, - db_addr_hi) / 32]; - - phys_addr.u.a64.address = - *((unsigned long long *)(&phys_addr.u.a64.address)); - - switch (pdpdu_cqe->dw[offsetof(struct amap_i_t_dpdu_cqe, code) / 32] - & PDUCQE_CODE_MASK) { + /** + * DB addr Hi/Lo is same for BE and SKH. + * Subtract the dataplacementlength to get to the base. + */ + phys_addr.u.a32.address_lo = AMAP_GET_BITS(struct amap_i_t_dpdu_cqe, + db_addr_lo, pdpdu_cqe); + phys_addr.u.a32.address_lo -= dpl; + phys_addr.u.a32.address_hi = AMAP_GET_BITS(struct amap_i_t_dpdu_cqe, + db_addr_hi, pdpdu_cqe); + + code = AMAP_GET_BITS(struct amap_i_t_dpdu_cqe, code, pdpdu_cqe); + switch (code) { case UNSOL_HDR_NOTIFY: - is_header = 1; - - pbusy_list = hwi_get_async_busy_list(pasync_ctx, - is_header, index); + pasync_handle = pasync_ctx->async_entry[ci].header; break; + case UNSOL_DATA_DIGEST_ERROR_NOTIFY: + error = 1; case UNSOL_DATA_NOTIFY: - pbusy_list = hwi_get_async_busy_list(pasync_ctx, - is_header, index); + pasync_handle = pasync_ctx->async_entry[ci].data; break; + /* called only for above codes */ default: - pbusy_list = NULL; - beiscsi_log(phba, KERN_WARNING, - BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG, - "BM_%d : Unexpected code=%d\n", - pdpdu_cqe->dw[offsetof(struct amap_i_t_dpdu_cqe, - code) / 32] & PDUCQE_CODE_MASK); - return NULL; + pasync_handle = NULL; + break; } - WARN_ON(list_empty(pbusy_list)); - list_for_each_entry(pasync_handle, pbusy_list, link) { - if (pasync_handle->pa.u.a64.address == phys_addr.u.a64.address) - break; + if (!pasync_handle) { + beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_ISCSI, + "BM_%d : cid %d async PDU handle not found - code %d ci %d addr %llx\n", + cid, code, ci, phys_addr.u.a64.address); + return pasync_handle; } - WARN_ON(!pasync_handle); + if (pasync_handle->pa.u.a64.address != phys_addr.u.a64.address || + pasync_handle->index != ci) { + /* driver bug - if ci does not match async handle index */ + error = 1; + beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_ISCSI, + "BM_%d : cid %u async PDU handle mismatch - addr in %cQE %llx at %u:addr in CQE %llx ci %u\n", + cid, pasync_handle->is_header ? 'H' : 'D', + pasync_handle->pa.u.a64.address, + pasync_handle->index, + phys_addr.u.a64.address, ci); + /* FW has stale address - attempt continuing by dropping */ + } - pasync_handle->cri = BE_GET_ASYNC_CRI_FROM_CID( - beiscsi_conn->beiscsi_conn_cid); - pasync_handle->is_header = is_header; + /** + * Each CID is associated with unique CRI. + * ASYNC_CRI_FROM_CID mapping and CRI_FROM_CID are totaly different. + **/ + pasync_handle->cri = BE_GET_ASYNC_CRI_FROM_CID(cid); + pasync_handle->is_final = final; pasync_handle->buffer_len = dpl; - *pcq_index = index; + /* empty the slot */ + if (pasync_handle->is_header) + pasync_ctx->async_entry[ci].header = NULL; + else + pasync_ctx->async_entry[ci].data = NULL; + /** + * DEF PDU header and data buffers with errors should be simply + * dropped as there are no consumers for it. + */ + if (error) { + beiscsi_hdl_put_handle(pasync_ctx, pasync_handle); + pasync_handle = NULL; + } return pasync_handle; } -static unsigned int -hwi_update_async_writables(struct beiscsi_hba *phba, - struct hwi_async_pdu_context *pasync_ctx, - unsigned int is_header, unsigned int cq_index) +static void +beiscsi_hdl_purge_handles(struct beiscsi_hba *phba, + struct hd_async_context *pasync_ctx, + u16 cri) { - struct list_head *pbusy_list; - struct async_pdu_handle *pasync_handle; - unsigned int num_entries, writables = 0; - unsigned int *pep_read_ptr, *pwritables; - - num_entries = pasync_ctx->num_entries; - if (is_header) { - pep_read_ptr = &pasync_ctx->async_header.ep_read_ptr; - pwritables = &pasync_ctx->async_header.writables; - } else { - pep_read_ptr = &pasync_ctx->async_data.ep_read_ptr; - pwritables = &pasync_ctx->async_data.writables; - } - - while ((*pep_read_ptr) != cq_index) { - (*pep_read_ptr)++; - *pep_read_ptr = (*pep_read_ptr) % num_entries; - - pbusy_list = hwi_get_async_busy_list(pasync_ctx, is_header, - *pep_read_ptr); - if (writables == 0) - WARN_ON(list_empty(pbusy_list)); - - if (!list_empty(pbusy_list)) { - pasync_handle = list_entry(pbusy_list->next, - struct async_pdu_handle, - link); - WARN_ON(!pasync_handle); - pasync_handle->consumed = 1; - } - - writables++; - } + struct hd_async_handle *pasync_handle, *tmp_handle; + struct list_head *plist; - if (!writables) { - beiscsi_log(phba, KERN_ERR, - BEISCSI_LOG_CONFIG | BEISCSI_LOG_IO, - "BM_%d : Duplicate notification received - index 0x%x!!\n", - cq_index); - WARN_ON(1); + plist = &pasync_ctx->async_entry[cri].wq.list; + list_for_each_entry_safe(pasync_handle, tmp_handle, plist, link) { + list_del(&pasync_handle->link); + beiscsi_hdl_put_handle(pasync_ctx, pasync_handle); } - *pwritables = *pwritables + writables; - return 0; + INIT_LIST_HEAD(&pasync_ctx->async_entry[cri].wq.list); + pasync_ctx->async_entry[cri].wq.hdr_len = 0; + pasync_ctx->async_entry[cri].wq.bytes_received = 0; + pasync_ctx->async_entry[cri].wq.bytes_needed = 0; } -static void hwi_free_async_msg(struct beiscsi_hba *phba, - struct hwi_async_pdu_context *pasync_ctx, - unsigned int cri) +static unsigned int +beiscsi_hdl_fwd_pdu(struct beiscsi_conn *beiscsi_conn, + struct hd_async_context *pasync_ctx, + u16 cri) { - struct async_pdu_handle *pasync_handle, *tmp_handle; + struct iscsi_session *session = beiscsi_conn->conn->session; + struct hd_async_handle *pasync_handle, *plast_handle; + struct beiscsi_hba *phba = beiscsi_conn->phba; + void *phdr = NULL, *pdata = NULL; + u32 dlen = 0, status = 0; struct list_head *plist; - plist = &pasync_ctx->async_entry[cri].wait_queue.list; - list_for_each_entry_safe(pasync_handle, tmp_handle, plist, link) { - list_del(&pasync_handle->link); - - if (pasync_handle->is_header) { - list_add_tail(&pasync_handle->link, - &pasync_ctx->async_header.free_list); - pasync_ctx->async_header.free_entries++; - } else { - list_add_tail(&pasync_handle->link, - &pasync_ctx->async_data.free_list); - pasync_ctx->async_data.free_entries++; + plist = &pasync_ctx->async_entry[cri].wq.list; + plast_handle = NULL; + list_for_each_entry(pasync_handle, plist, link) { + plast_handle = pasync_handle; + /* get the header, the first entry */ + if (!phdr) { + phdr = pasync_handle->pbuffer; + continue; + } + /* use first buffer to collect all the data */ + if (!pdata) { + pdata = pasync_handle->pbuffer; + dlen = pasync_handle->buffer_len; + continue; } + memcpy(pdata + dlen, pasync_handle->pbuffer, + pasync_handle->buffer_len); + dlen += pasync_handle->buffer_len; } - INIT_LIST_HEAD(&pasync_ctx->async_entry[cri].wait_queue.list); - pasync_ctx->async_entry[cri].wait_queue.hdr_received = 0; - pasync_ctx->async_entry[cri].wait_queue.bytes_received = 0; + if (!plast_handle->is_final) { + /* last handle should have final PDU notification from FW */ + beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_ISCSI, + "BM_%d : cid %u %p fwd async PDU with last handle missing - HL%u:DN%u:DR%u\n", + beiscsi_conn->beiscsi_conn_cid, plast_handle, + pasync_ctx->async_entry[cri].wq.hdr_len, + pasync_ctx->async_entry[cri].wq.bytes_needed, + pasync_ctx->async_entry[cri].wq.bytes_received); + } + spin_lock_bh(&session->back_lock); + status = beiscsi_complete_pdu(beiscsi_conn, phdr, pdata, dlen); + spin_unlock_bh(&session->back_lock); + beiscsi_hdl_purge_handles(phba, pasync_ctx, cri); + return status; } -static struct phys_addr * -hwi_get_ring_address(struct hwi_async_pdu_context *pasync_ctx, - unsigned int is_header, unsigned int host_write_ptr) +static unsigned int +beiscsi_hdl_gather_pdu(struct beiscsi_conn *beiscsi_conn, + struct hd_async_context *pasync_ctx, + struct hd_async_handle *pasync_handle) { - struct phys_addr *pasync_sge = NULL; + unsigned int bytes_needed = 0, status = 0; + u16 cri = pasync_handle->cri; + struct cri_wait_queue *wq; + struct beiscsi_hba *phba; + struct pdu_base *ppdu; + char *err = ""; - if (is_header) - pasync_sge = pasync_ctx->async_header.ring_base; - else - pasync_sge = pasync_ctx->async_data.ring_base; + phba = beiscsi_conn->phba; + wq = &pasync_ctx->async_entry[cri].wq; + if (pasync_handle->is_header) { + /* check if PDU hdr is rcv'd when old hdr not completed */ + if (wq->hdr_len) { + err = "incomplete"; + goto drop_pdu; + } + ppdu = pasync_handle->pbuffer; + bytes_needed = AMAP_GET_BITS(struct amap_pdu_base, + data_len_hi, ppdu); + bytes_needed <<= 16; + bytes_needed |= be16_to_cpu(AMAP_GET_BITS(struct amap_pdu_base, + data_len_lo, ppdu)); + wq->hdr_len = pasync_handle->buffer_len; + wq->bytes_received = 0; + wq->bytes_needed = bytes_needed; + list_add_tail(&pasync_handle->link, &wq->list); + if (!bytes_needed) + status = beiscsi_hdl_fwd_pdu(beiscsi_conn, + pasync_ctx, cri); + } else { + /* check if data received has header and is needed */ + if (!wq->hdr_len || !wq->bytes_needed) { + err = "header less"; + goto drop_pdu; + } + wq->bytes_received += pasync_handle->buffer_len; + /* Something got overwritten? Better catch it here. */ + if (wq->bytes_received > wq->bytes_needed) { + err = "overflow"; + goto drop_pdu; + } + list_add_tail(&pasync_handle->link, &wq->list); + if (wq->bytes_received == wq->bytes_needed) + status = beiscsi_hdl_fwd_pdu(beiscsi_conn, + pasync_ctx, cri); + } + return status; - return pasync_sge + host_write_ptr; +drop_pdu: + beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_ISCSI, + "BM_%d : cid %u async PDU %s - def-%c:HL%u:DN%u:DR%u\n", + beiscsi_conn->beiscsi_conn_cid, err, + pasync_handle->is_header ? 'H' : 'D', + wq->hdr_len, wq->bytes_needed, + pasync_handle->buffer_len); + /* discard this handle */ + beiscsi_hdl_put_handle(pasync_ctx, pasync_handle); + /* free all the other handles in cri_wait_queue */ + beiscsi_hdl_purge_handles(phba, pasync_ctx, cri); + /* try continuing */ + return status; } -static void hwi_post_async_buffers(struct beiscsi_hba *phba, - unsigned int is_header, uint8_t ulp_num) +static void +beiscsi_hdq_post_handles(struct beiscsi_hba *phba, + u8 header, u8 ulp_num) { + struct hd_async_handle *pasync_handle, *tmp, **slot; + struct hd_async_context *pasync_ctx; struct hwi_controller *phwi_ctrlr; - struct hwi_async_pdu_context *pasync_ctx; - struct async_pdu_handle *pasync_handle; - struct list_head *pfree_link, *pbusy_list; + struct list_head *hfree_list; struct phys_addr *pasync_sge; - unsigned int ring_id, num_entries; - unsigned int host_write_num, doorbell_offset; - unsigned int writables; - unsigned int i = 0; - u32 doorbell = 0; + u32 ring_id, doorbell = 0; + u16 index, num_entries; + u32 doorbell_offset; + u16 prod = 0, cons; phwi_ctrlr = phba->phwi_ctrlr; pasync_ctx = HWI_GET_ASYNC_PDU_CTX(phwi_ctrlr, ulp_num); num_entries = pasync_ctx->num_entries; - - if (is_header) { - writables = min(pasync_ctx->async_header.writables, - pasync_ctx->async_header.free_entries); - pfree_link = pasync_ctx->async_header.free_list.next; - host_write_num = pasync_ctx->async_header.host_write_ptr; + if (header) { + cons = pasync_ctx->async_header.free_entries; + hfree_list = &pasync_ctx->async_header.free_list; ring_id = phwi_ctrlr->default_pdu_hdr[ulp_num].id; doorbell_offset = phwi_ctrlr->default_pdu_hdr[ulp_num]. - doorbell_offset; + doorbell_offset; } else { - writables = min(pasync_ctx->async_data.writables, - pasync_ctx->async_data.free_entries); - pfree_link = pasync_ctx->async_data.free_list.next; - host_write_num = pasync_ctx->async_data.host_write_ptr; + cons = pasync_ctx->async_data.free_entries; + hfree_list = &pasync_ctx->async_data.free_list; ring_id = phwi_ctrlr->default_pdu_data[ulp_num].id; doorbell_offset = phwi_ctrlr->default_pdu_data[ulp_num]. - doorbell_offset; + doorbell_offset; } + /* number of entries posted must be in multiples of 8 */ + if (cons % 8) + return; - writables = (writables / 8) * 8; - if (writables) { - for (i = 0; i < writables; i++) { - pbusy_list = - hwi_get_async_busy_list(pasync_ctx, is_header, - host_write_num); - pasync_handle = - list_entry(pfree_link, struct async_pdu_handle, - link); - WARN_ON(!pasync_handle); - pasync_handle->consumed = 0; - - pfree_link = pfree_link->next; - - pasync_sge = hwi_get_ring_address(pasync_ctx, - is_header, host_write_num); - - pasync_sge->hi = pasync_handle->pa.u.a32.address_lo; - pasync_sge->lo = pasync_handle->pa.u.a32.address_hi; - - list_move(&pasync_handle->link, pbusy_list); - - host_write_num++; - host_write_num = host_write_num % num_entries; - } - - if (is_header) { - pasync_ctx->async_header.host_write_ptr = - host_write_num; - pasync_ctx->async_header.free_entries -= writables; - pasync_ctx->async_header.writables -= writables; - pasync_ctx->async_header.busy_entries += writables; - } else { - pasync_ctx->async_data.host_write_ptr = host_write_num; - pasync_ctx->async_data.free_entries -= writables; - pasync_ctx->async_data.writables -= writables; - pasync_ctx->async_data.busy_entries += writables; - } - - doorbell |= ring_id & DB_DEF_PDU_RING_ID_MASK; - doorbell |= 1 << DB_DEF_PDU_REARM_SHIFT; - doorbell |= 0 << DB_DEF_PDU_EVENT_SHIFT; - doorbell |= (writables & DB_DEF_PDU_CQPROC_MASK) - << DB_DEF_PDU_CQPROC_SHIFT; - - iowrite32(doorbell, phba->db_va + doorbell_offset); - } -} - -static void hwi_flush_default_pdu_buffer(struct beiscsi_hba *phba, - struct beiscsi_conn *beiscsi_conn, - struct i_t_dpdu_cqe *pdpdu_cqe) -{ - struct hwi_controller *phwi_ctrlr; - struct hwi_async_pdu_context *pasync_ctx; - struct async_pdu_handle *pasync_handle = NULL; - unsigned int cq_index = -1; - uint16_t cri_index = BE_GET_CRI_FROM_CID( - beiscsi_conn->beiscsi_conn_cid); - - phwi_ctrlr = phba->phwi_ctrlr; - pasync_ctx = HWI_GET_ASYNC_PDU_CTX(phwi_ctrlr, - BEISCSI_GET_ULP_FROM_CRI(phwi_ctrlr, - cri_index)); - - pasync_handle = hwi_get_async_handle(phba, beiscsi_conn, pasync_ctx, - pdpdu_cqe, &cq_index); - BUG_ON(pasync_handle->is_header != 0); - if (pasync_handle->consumed == 0) - hwi_update_async_writables(phba, pasync_ctx, - pasync_handle->is_header, cq_index); - - hwi_free_async_msg(phba, pasync_ctx, pasync_handle->cri); - hwi_post_async_buffers(phba, pasync_handle->is_header, - BEISCSI_GET_ULP_FROM_CRI(phwi_ctrlr, - cri_index)); -} - -static unsigned int -hwi_fwd_async_msg(struct beiscsi_conn *beiscsi_conn, - struct beiscsi_hba *phba, - struct hwi_async_pdu_context *pasync_ctx, unsigned short cri) -{ - struct list_head *plist; - struct async_pdu_handle *pasync_handle; - void *phdr = NULL; - unsigned int hdr_len = 0, buf_len = 0; - unsigned int status, index = 0, offset = 0; - void *pfirst_buffer = NULL; - unsigned int num_buf = 0; - - plist = &pasync_ctx->async_entry[cri].wait_queue.list; + list_for_each_entry_safe(pasync_handle, tmp, hfree_list, link) { + list_del_init(&pasync_handle->link); + pasync_handle->is_final = 0; + pasync_handle->buffer_len = 0; - list_for_each_entry(pasync_handle, plist, link) { - if (index == 0) { - phdr = pasync_handle->pbuffer; - hdr_len = pasync_handle->buffer_len; - } else { - buf_len = pasync_handle->buffer_len; - if (!num_buf) { - pfirst_buffer = pasync_handle->pbuffer; - num_buf++; - } - memcpy(pfirst_buffer + offset, - pasync_handle->pbuffer, buf_len); - offset += buf_len; + /* handles can be consumed out of order, use index in handle */ + index = pasync_handle->index; + WARN_ON(pasync_handle->is_header != header); + if (header) + slot = &pasync_ctx->async_entry[index].header; + else + slot = &pasync_ctx->async_entry[index].data; + /** + * The slot just tracks handle's hold and release, so + * overwriting at the same index won't do any harm but + * needs to be caught. + */ + if (*slot != NULL) { + beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_ISCSI, + "BM_%d : async PDU %s slot at %u not empty\n", + header ? "header" : "data", index); } - index++; + /** + * We use same freed index as in completion to post so this + * operation is not required for refills. Its required only + * for ring creation. + */ + if (header) + pasync_sge = pasync_ctx->async_header.ring_base; + else + pasync_sge = pasync_ctx->async_data.ring_base; + pasync_sge += index; + /* if its a refill then address is same; hi is lo */ + WARN_ON(pasync_sge->hi && + pasync_sge->hi != pasync_handle->pa.u.a32.address_lo); + WARN_ON(pasync_sge->lo && + pasync_sge->lo != pasync_handle->pa.u.a32.address_hi); + pasync_sge->hi = pasync_handle->pa.u.a32.address_lo; + pasync_sge->lo = pasync_handle->pa.u.a32.address_hi; + + *slot = pasync_handle; + if (++prod == cons) + break; } + if (header) + pasync_ctx->async_header.free_entries -= prod; + else + pasync_ctx->async_data.free_entries -= prod; - status = beiscsi_process_async_pdu(beiscsi_conn, phba, - phdr, hdr_len, pfirst_buffer, - offset); - - hwi_free_async_msg(phba, pasync_ctx, cri); - return 0; -} - -static unsigned int -hwi_gather_async_pdu(struct beiscsi_conn *beiscsi_conn, - struct beiscsi_hba *phba, - struct async_pdu_handle *pasync_handle) -{ - struct hwi_async_pdu_context *pasync_ctx; - struct hwi_controller *phwi_ctrlr; - unsigned int bytes_needed = 0, status = 0; - unsigned short cri = pasync_handle->cri; - struct pdu_base *ppdu; - - phwi_ctrlr = phba->phwi_ctrlr; - pasync_ctx = HWI_GET_ASYNC_PDU_CTX(phwi_ctrlr, - BEISCSI_GET_ULP_FROM_CRI(phwi_ctrlr, - BE_GET_CRI_FROM_CID(beiscsi_conn-> - beiscsi_conn_cid))); - - list_del(&pasync_handle->link); - if (pasync_handle->is_header) { - pasync_ctx->async_header.busy_entries--; - if (pasync_ctx->async_entry[cri].wait_queue.hdr_received) { - hwi_free_async_msg(phba, pasync_ctx, cri); - BUG(); - } - - pasync_ctx->async_entry[cri].wait_queue.bytes_received = 0; - pasync_ctx->async_entry[cri].wait_queue.hdr_received = 1; - pasync_ctx->async_entry[cri].wait_queue.hdr_len = - (unsigned short)pasync_handle->buffer_len; - list_add_tail(&pasync_handle->link, - &pasync_ctx->async_entry[cri].wait_queue.list); - - ppdu = pasync_handle->pbuffer; - bytes_needed = ((((ppdu->dw[offsetof(struct amap_pdu_base, - data_len_hi) / 32] & PDUBASE_DATALENHI_MASK) << 8) & - 0xFFFF0000) | ((be16_to_cpu((ppdu-> - dw[offsetof(struct amap_pdu_base, data_len_lo) / 32] - & PDUBASE_DATALENLO_MASK) >> 16)) & 0x0000FFFF)); - - if (status == 0) { - pasync_ctx->async_entry[cri].wait_queue.bytes_needed = - bytes_needed; - - if (bytes_needed == 0) - status = hwi_fwd_async_msg(beiscsi_conn, phba, - pasync_ctx, cri); - } - } else { - pasync_ctx->async_data.busy_entries--; - if (pasync_ctx->async_entry[cri].wait_queue.hdr_received) { - list_add_tail(&pasync_handle->link, - &pasync_ctx->async_entry[cri].wait_queue. - list); - pasync_ctx->async_entry[cri].wait_queue. - bytes_received += - (unsigned short)pasync_handle->buffer_len; - - if (pasync_ctx->async_entry[cri].wait_queue. - bytes_received >= - pasync_ctx->async_entry[cri].wait_queue. - bytes_needed) - status = hwi_fwd_async_msg(beiscsi_conn, phba, - pasync_ctx, cri); - } - } - return status; + doorbell |= ring_id & DB_DEF_PDU_RING_ID_MASK; + doorbell |= 1 << DB_DEF_PDU_REARM_SHIFT; + doorbell |= 0 << DB_DEF_PDU_EVENT_SHIFT; + doorbell |= (prod & DB_DEF_PDU_CQPROC_MASK) << DB_DEF_PDU_CQPROC_SHIFT; + iowrite32(doorbell, phba->db_va + doorbell_offset); } -static void hwi_process_default_pdu_ring(struct beiscsi_conn *beiscsi_conn, - struct beiscsi_hba *phba, - struct i_t_dpdu_cqe *pdpdu_cqe) +static void +beiscsi_hdq_process_compl(struct beiscsi_conn *beiscsi_conn, + struct i_t_dpdu_cqe *pdpdu_cqe) { + struct beiscsi_hba *phba = beiscsi_conn->phba; + struct hd_async_handle *pasync_handle = NULL; + struct hd_async_context *pasync_ctx; struct hwi_controller *phwi_ctrlr; - struct hwi_async_pdu_context *pasync_ctx; - struct async_pdu_handle *pasync_handle = NULL; - unsigned int cq_index = -1; - uint16_t cri_index = BE_GET_CRI_FROM_CID( - beiscsi_conn->beiscsi_conn_cid); + u16 cid_cri; + u8 ulp_num; phwi_ctrlr = phba->phwi_ctrlr; - pasync_ctx = HWI_GET_ASYNC_PDU_CTX(phwi_ctrlr, - BEISCSI_GET_ULP_FROM_CRI(phwi_ctrlr, - cri_index)); - - pasync_handle = hwi_get_async_handle(phba, beiscsi_conn, pasync_ctx, - pdpdu_cqe, &cq_index); - - if (pasync_handle->consumed == 0) - hwi_update_async_writables(phba, pasync_ctx, - pasync_handle->is_header, cq_index); + cid_cri = BE_GET_CRI_FROM_CID(beiscsi_conn->beiscsi_conn_cid); + ulp_num = BEISCSI_GET_ULP_FROM_CRI(phwi_ctrlr, cid_cri); + pasync_ctx = HWI_GET_ASYNC_PDU_CTX(phwi_ctrlr, ulp_num); + pasync_handle = beiscsi_hdl_get_handle(beiscsi_conn, pasync_ctx, + pdpdu_cqe); + if (!pasync_handle) + return; - hwi_gather_async_pdu(beiscsi_conn, phba, pasync_handle); - hwi_post_async_buffers(phba, pasync_handle->is_header, - BEISCSI_GET_ULP_FROM_CRI( - phwi_ctrlr, cri_index)); + beiscsi_hdl_gather_pdu(beiscsi_conn, pasync_ctx, pasync_handle); + beiscsi_hdq_post_handles(phba, pasync_handle->is_header, ulp_num); } void beiscsi_process_mcc_cq(struct beiscsi_hba *phba) @@ -2051,6 +1816,9 @@ void beiscsi_process_mcc_cq(struct beiscsi_hba *phba) mcc_compl = queue_tail_node(mcc_cq); mcc_compl->flags = le32_to_cpu(mcc_compl->flags); while (mcc_compl->flags & CQE_FLAGS_VALID_MASK) { + if (beiscsi_hba_in_error(phba)) + return; + if (num_processed >= 32) { hwi_ring_cq_db(phba, mcc_cq->id, num_processed, 0); @@ -2073,6 +1841,19 @@ void beiscsi_process_mcc_cq(struct beiscsi_hba *phba) hwi_ring_cq_db(phba, mcc_cq->id, num_processed, 1); } +static void beiscsi_mcc_work(struct work_struct *work) +{ + struct be_eq_obj *pbe_eq; + struct beiscsi_hba *phba; + + pbe_eq = container_of(work, struct be_eq_obj, mcc_work); + phba = pbe_eq->phba; + beiscsi_process_mcc_cq(phba); + /* rearm EQ for further interrupts */ + if (!beiscsi_hba_in_error(phba)) + hwi_ring_eq_db(phba, pbe_eq->q.id, 0, 0, 1, 1); +} + /** * beiscsi_process_cq()- Process the Completion Queue * @pbe_eq: Event Q on which the Completion has come @@ -2101,6 +1882,9 @@ unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq, int budget) while (sol->dw[offsetof(struct amap_sol_cqe, valid) / 32] & CQE_VALID_MASK) { + if (beiscsi_hba_in_error(phba)) + return 0; + be_dws_le_to_cpu(sol, sizeof(struct sol_cqe)); code = (sol->dw[offsetof(struct amap_sol_cqe, code) / @@ -2165,8 +1949,8 @@ unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq, int budget) cqe_desc[code], code, cid); spin_lock_bh(&phba->async_pdu_lock); - hwi_process_default_pdu_ring(beiscsi_conn, phba, - (struct i_t_dpdu_cqe *)sol); + beiscsi_hdq_process_compl(beiscsi_conn, + (struct i_t_dpdu_cqe *)sol); spin_unlock_bh(&phba->async_pdu_lock); break; case UNSOL_DATA_NOTIFY: @@ -2176,8 +1960,8 @@ unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq, int budget) cqe_desc[code], code, cid); spin_lock_bh(&phba->async_pdu_lock); - hwi_process_default_pdu_ring(beiscsi_conn, phba, - (struct i_t_dpdu_cqe *)sol); + beiscsi_hdq_process_compl(beiscsi_conn, + (struct i_t_dpdu_cqe *)sol); spin_unlock_bh(&phba->async_pdu_lock); break; case CXN_INVALIDATE_INDEX_NOTIFY: @@ -2213,8 +1997,9 @@ unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq, int budget) "BM_%d : Dropping %s[%d] on DPDU ring on CID : %d\n", cqe_desc[code], code, cid); spin_lock_bh(&phba->async_pdu_lock); - hwi_flush_default_pdu_buffer(phba, beiscsi_conn, - (struct i_t_dpdu_cqe *) sol); + /* driver consumes the entry and drops the contents */ + beiscsi_hdq_process_compl(beiscsi_conn, + (struct i_t_dpdu_cqe *)sol); spin_unlock_bh(&phba->async_pdu_lock); break; case CXN_KILLED_PDU_SIZE_EXCEEDS_DSL: @@ -2262,60 +2047,32 @@ proc_next_cqe: return total; } -void beiscsi_process_all_cqs(struct work_struct *work) -{ - unsigned long flags; - struct hwi_controller *phwi_ctrlr; - struct hwi_context_memory *phwi_context; - struct beiscsi_hba *phba; - struct be_eq_obj *pbe_eq = - container_of(work, struct be_eq_obj, work_cqs); - - phba = pbe_eq->phba; - phwi_ctrlr = phba->phwi_ctrlr; - phwi_context = phwi_ctrlr->phwi_ctxt; - - if (pbe_eq->todo_mcc_cq) { - spin_lock_irqsave(&phba->isr_lock, flags); - pbe_eq->todo_mcc_cq = false; - spin_unlock_irqrestore(&phba->isr_lock, flags); - beiscsi_process_mcc_cq(phba); - } - - if (pbe_eq->todo_cq) { - spin_lock_irqsave(&phba->isr_lock, flags); - pbe_eq->todo_cq = false; - spin_unlock_irqrestore(&phba->isr_lock, flags); - beiscsi_process_cq(pbe_eq, BE2_MAX_NUM_CQ_PROC); - } - - /* rearm EQ for further interrupts */ - hwi_ring_eq_db(phba, pbe_eq->q.id, 0, 0, 1, 1); -} - static int be_iopoll(struct irq_poll *iop, int budget) { - unsigned int ret, num_eq_processed; + unsigned int ret, io_events; struct beiscsi_hba *phba; struct be_eq_obj *pbe_eq; struct be_eq_entry *eqe = NULL; struct be_queue_info *eq; - num_eq_processed = 0; pbe_eq = container_of(iop, struct be_eq_obj, iopoll); phba = pbe_eq->phba; + if (beiscsi_hba_in_error(phba)) { + irq_poll_complete(iop); + return 0; + } + + io_events = 0; eq = &pbe_eq->q; eqe = queue_tail_node(eq); - while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32] & EQE_VALID_MASK) { AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0); queue_tail_inc(eq); eqe = queue_tail_node(eq); - num_eq_processed++; + io_events++; } - - hwi_ring_eq_db(phba, eq->id, 1, num_eq_processed, 0, 1); + hwi_ring_eq_db(phba, eq->id, 1, io_events, 0, 1); ret = beiscsi_process_cq(pbe_eq, budget); pbe_eq->cq_count += ret; @@ -2325,7 +2082,8 @@ static int be_iopoll(struct irq_poll *iop, int budget) BEISCSI_LOG_CONFIG | BEISCSI_LOG_IO, "BM_%d : rearm pbe_eq->q.id =%d ret %d\n", pbe_eq->q.id, ret); - hwi_ring_eq_db(phba, pbe_eq->q.id, 0, 0, 1, 1); + if (!beiscsi_hba_in_error(phba)) + hwi_ring_eq_db(phba, pbe_eq->q.id, 0, 0, 1, 1); } return ret; } @@ -2691,20 +2449,20 @@ static void beiscsi_find_mem_req(struct beiscsi_hba *phba) (ulp_num * MEM_DESCR_OFFSET)); phba->mem_req[mem_descr_index] = BEISCSI_GET_CID_COUNT(phba, ulp_num) * - sizeof(struct async_pdu_handle); + sizeof(struct hd_async_handle); mem_descr_index = (HWI_MEM_ASYNC_DATA_HANDLE_ULP0 + (ulp_num * MEM_DESCR_OFFSET)); phba->mem_req[mem_descr_index] = BEISCSI_GET_CID_COUNT(phba, ulp_num) * - sizeof(struct async_pdu_handle); + sizeof(struct hd_async_handle); mem_descr_index = (HWI_MEM_ASYNC_PDU_CONTEXT_ULP0 + (ulp_num * MEM_DESCR_OFFSET)); phba->mem_req[mem_descr_index] = - sizeof(struct hwi_async_pdu_context) + + sizeof(struct hd_async_context) + (BEISCSI_GET_CID_COUNT(phba, ulp_num) * - sizeof(struct hwi_async_entry)); + sizeof(struct hd_async_entry)); } } } @@ -2963,35 +2721,34 @@ static int hwi_init_async_pdu_ctx(struct beiscsi_hba *phba) uint8_t ulp_num; struct hwi_controller *phwi_ctrlr; struct hba_parameters *p = &phba->params; - struct hwi_async_pdu_context *pasync_ctx; - struct async_pdu_handle *pasync_header_h, *pasync_data_h; + struct hd_async_context *pasync_ctx; + struct hd_async_handle *pasync_header_h, *pasync_data_h; unsigned int index, idx, num_per_mem, num_async_data; struct be_mem_descriptor *mem_descr; for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) { if (test_bit(ulp_num, &phba->fw_config.ulp_supported)) { - + /* get async_ctx for each ULP */ mem_descr = (struct be_mem_descriptor *)phba->init_mem; mem_descr += (HWI_MEM_ASYNC_PDU_CONTEXT_ULP0 + (ulp_num * MEM_DESCR_OFFSET)); phwi_ctrlr = phba->phwi_ctrlr; phwi_ctrlr->phwi_ctxt->pasync_ctx[ulp_num] = - (struct hwi_async_pdu_context *) + (struct hd_async_context *) mem_descr->mem_array[0].virtual_address; pasync_ctx = phwi_ctrlr->phwi_ctxt->pasync_ctx[ulp_num]; memset(pasync_ctx, 0, sizeof(*pasync_ctx)); pasync_ctx->async_entry = - (struct hwi_async_entry *) + (struct hd_async_entry *) ((long unsigned int)pasync_ctx + - sizeof(struct hwi_async_pdu_context)); + sizeof(struct hd_async_context)); pasync_ctx->num_entries = BEISCSI_GET_CID_COUNT(phba, ulp_num); - pasync_ctx->buffer_size = p->defpdu_hdr_sz; - + /* setup header buffers */ mem_descr = (struct be_mem_descriptor *)phba->init_mem; mem_descr += HWI_MEM_ASYNC_HEADER_BUF_ULP0 + (ulp_num * MEM_DESCR_OFFSET); @@ -3008,6 +2765,7 @@ static int hwi_init_async_pdu_ctx(struct beiscsi_hba *phba) "BM_%d : No Virtual address for ULP : %d\n", ulp_num); + pasync_ctx->async_header.buffer_size = p->defpdu_hdr_sz; pasync_ctx->async_header.va_base = mem_descr->mem_array[0].virtual_address; @@ -3015,6 +2773,7 @@ static int hwi_init_async_pdu_ctx(struct beiscsi_hba *phba) mem_descr->mem_array[0]. bus_address.u.a64.address; + /* setup header buffer sgls */ mem_descr = (struct be_mem_descriptor *)phba->init_mem; mem_descr += HWI_MEM_ASYNC_HEADER_RING_ULP0 + (ulp_num * MEM_DESCR_OFFSET); @@ -3034,6 +2793,7 @@ static int hwi_init_async_pdu_ctx(struct beiscsi_hba *phba) pasync_ctx->async_header.ring_base = mem_descr->mem_array[0].virtual_address; + /* setup header buffer handles */ mem_descr = (struct be_mem_descriptor *)phba->init_mem; mem_descr += HWI_MEM_ASYNC_HEADER_HANDLE_ULP0 + (ulp_num * MEM_DESCR_OFFSET); @@ -3052,9 +2812,9 @@ static int hwi_init_async_pdu_ctx(struct beiscsi_hba *phba) pasync_ctx->async_header.handle_base = mem_descr->mem_array[0].virtual_address; - pasync_ctx->async_header.writables = 0; INIT_LIST_HEAD(&pasync_ctx->async_header.free_list); + /* setup data buffer sgls */ mem_descr = (struct be_mem_descriptor *)phba->init_mem; mem_descr += HWI_MEM_ASYNC_DATA_RING_ULP0 + (ulp_num * MEM_DESCR_OFFSET); @@ -3074,6 +2834,7 @@ static int hwi_init_async_pdu_ctx(struct beiscsi_hba *phba) pasync_ctx->async_data.ring_base = mem_descr->mem_array[0].virtual_address; + /* setup data buffer handles */ mem_descr = (struct be_mem_descriptor *)phba->init_mem; mem_descr += HWI_MEM_ASYNC_DATA_HANDLE_ULP0 + (ulp_num * MEM_DESCR_OFFSET); @@ -3085,16 +2846,16 @@ static int hwi_init_async_pdu_ctx(struct beiscsi_hba *phba) pasync_ctx->async_data.handle_base = mem_descr->mem_array[0].virtual_address; - pasync_ctx->async_data.writables = 0; INIT_LIST_HEAD(&pasync_ctx->async_data.free_list); pasync_header_h = - (struct async_pdu_handle *) + (struct hd_async_handle *) pasync_ctx->async_header.handle_base; pasync_data_h = - (struct async_pdu_handle *) + (struct hd_async_handle *) pasync_ctx->async_data.handle_base; + /* setup data buffers */ mem_descr = (struct be_mem_descriptor *)phba->init_mem; mem_descr += HWI_MEM_ASYNC_DATA_BUF_ULP0 + (ulp_num * MEM_DESCR_OFFSET); @@ -3112,6 +2873,7 @@ static int hwi_init_async_pdu_ctx(struct beiscsi_hba *phba) ulp_num); idx = 0; + pasync_ctx->async_data.buffer_size = p->defpdu_data_sz; pasync_ctx->async_data.va_base = mem_descr->mem_array[idx].virtual_address; pasync_ctx->async_data.pa_base.u.a64.address = @@ -3125,7 +2887,8 @@ static int hwi_init_async_pdu_ctx(struct beiscsi_hba *phba) for (index = 0; index < BEISCSI_GET_CID_COUNT (phba, ulp_num); index++) { pasync_header_h->cri = -1; - pasync_header_h->index = (char)index; + pasync_header_h->is_header = 1; + pasync_header_h->index = index; INIT_LIST_HEAD(&pasync_header_h->link); pasync_header_h->pbuffer = (void *)((unsigned long) @@ -3142,14 +2905,13 @@ static int hwi_init_async_pdu_ctx(struct beiscsi_hba *phba) free_list); pasync_header_h++; pasync_ctx->async_header.free_entries++; - pasync_ctx->async_header.writables++; - INIT_LIST_HEAD(&pasync_ctx->async_entry[index]. - wait_queue.list); - INIT_LIST_HEAD(&pasync_ctx->async_entry[index]. - header_busy_list); + wq.list); + pasync_ctx->async_entry[index].header = NULL; + pasync_data_h->cri = -1; - pasync_data_h->index = (char)index; + pasync_data_h->is_header = 0; + pasync_data_h->index = index; INIT_LIST_HEAD(&pasync_data_h->link); if (!num_async_data) { @@ -3184,16 +2946,8 @@ static int hwi_init_async_pdu_ctx(struct beiscsi_hba *phba) free_list); pasync_data_h++; pasync_ctx->async_data.free_entries++; - pasync_ctx->async_data.writables++; - - INIT_LIST_HEAD(&pasync_ctx->async_entry[index]. - data_busy_list); + pasync_ctx->async_entry[index].data = NULL; } - - pasync_ctx->async_header.host_write_ptr = 0; - pasync_ctx->async_header.ep_read_ptr = -1; - pasync_ctx->async_data.host_write_ptr = 0; - pasync_ctx->async_data.ep_read_ptr = -1; } } @@ -3265,8 +3019,8 @@ static int be_fill_queue(struct be_queue_info *q, static int beiscsi_create_eqs(struct beiscsi_hba *phba, struct hwi_context_memory *phwi_context) { + int ret = -ENOMEM, eq_for_mcc; unsigned int i, num_eq_pages; - int ret = 0, eq_for_mcc; struct be_queue_info *eq; struct be_dma_mem *mem; void *eq_vaddress; @@ -3284,8 +3038,8 @@ static int beiscsi_create_eqs(struct beiscsi_hba *phba, mem = &eq->dma_mem; phwi_context->be_eq[i].phba = phba; eq_vaddress = pci_alloc_consistent(phba->pcidev, - num_eq_pages * PAGE_SIZE, - &paddr); + num_eq_pages * PAGE_SIZE, + &paddr); if (!eq_vaddress) goto create_eq_error; @@ -3313,6 +3067,7 @@ static int beiscsi_create_eqs(struct beiscsi_hba *phba, phwi_context->be_eq[i].q.id); } return 0; + create_eq_error: for (i = 0; i < (phba->num_cpus + eq_for_mcc); i++) { eq = &phwi_context->be_eq[i].q; @@ -3329,11 +3084,11 @@ static int beiscsi_create_cqs(struct beiscsi_hba *phba, struct hwi_context_memory *phwi_context) { unsigned int i, num_cq_pages; - int ret = 0; struct be_queue_info *cq, *eq; struct be_dma_mem *mem; struct be_eq_obj *pbe_eq; void *cq_vaddress; + int ret = -ENOMEM; dma_addr_t paddr; num_cq_pages = PAGES_REQUIRED(phba->params.num_cq_entries * \ @@ -3347,10 +3102,11 @@ static int beiscsi_create_cqs(struct beiscsi_hba *phba, pbe_eq->phba = phba; mem = &cq->dma_mem; cq_vaddress = pci_alloc_consistent(phba->pcidev, - num_cq_pages * PAGE_SIZE, - &paddr); + num_cq_pages * PAGE_SIZE, + &paddr); if (!cq_vaddress) goto create_cq_error; + ret = be_fill_queue(cq, phba->params.num_cq_entries, sizeof(struct sol_cqe), cq_vaddress); if (ret) { @@ -3385,7 +3141,6 @@ create_cq_error: mem->va, mem->dma); } return ret; - } static int @@ -3437,7 +3192,6 @@ beiscsi_create_def_hdr(struct beiscsi_hba *phba, "BM_%d : iscsi hdr def pdu id for ULP : %d is %d\n", ulp_num, phwi_context->be_def_hdrq[ulp_num].id); - hwi_post_async_buffers(phba, BEISCSI_DEFQ_HDR, ulp_num); return 0; } @@ -3492,11 +3246,9 @@ beiscsi_create_def_data(struct beiscsi_hba *phba, ulp_num, phwi_context->be_def_dataq[ulp_num].id); - hwi_post_async_buffers(phba, BEISCSI_DEFQ_DATA, ulp_num); beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, "BM_%d : DEFAULT PDU DATA RING CREATED" "on ULP : %d\n", ulp_num); - return 0; } @@ -3716,10 +3468,53 @@ static void free_wrb_handles(struct beiscsi_hba *phba) static void be_mcc_queues_destroy(struct beiscsi_hba *phba) { - struct be_queue_info *q; struct be_ctrl_info *ctrl = &phba->ctrl; + struct be_dma_mem *ptag_mem; + struct be_queue_info *q; + int i, tag; q = &phba->ctrl.mcc_obj.q; + for (i = 0; i < MAX_MCC_CMD; i++) { + tag = i + 1; + if (!test_bit(MCC_TAG_STATE_RUNNING, + &ctrl->ptag_state[tag].tag_state)) + continue; + + if (test_bit(MCC_TAG_STATE_TIMEOUT, + &ctrl->ptag_state[tag].tag_state)) { + ptag_mem = &ctrl->ptag_state[tag].tag_mem_state; + if (ptag_mem->size) { + pci_free_consistent(ctrl->pdev, + ptag_mem->size, + ptag_mem->va, + ptag_mem->dma); + ptag_mem->size = 0; + } + continue; + } + /** + * If MCC is still active and waiting then wake up the process. + * We are here only because port is going offline. The process + * sees that (BEISCSI_HBA_ONLINE is cleared) and EIO error is + * returned for the operation and allocated memory cleaned up. + */ + if (waitqueue_active(&ctrl->mcc_wait[tag])) { + ctrl->mcc_tag_status[tag] = MCC_STATUS_FAILED; + ctrl->mcc_tag_status[tag] |= CQE_VALID_MASK; + wake_up_interruptible(&ctrl->mcc_wait[tag]); + /* + * Control tag info gets reinitialized in enable + * so wait for the process to clear running state. + */ + while (test_bit(MCC_TAG_STATE_RUNNING, + &ctrl->ptag_state[tag].tag_state)) + schedule_timeout_uninterruptible(HZ); + } + /** + * For MCC with tag_states MCC_TAG_STATE_ASYNC and + * MCC_TAG_STATE_IGNORE nothing needs to done. + */ + } if (q->created) { beiscsi_cmd_q_destroy(ctrl, q, QTYPE_MCCQ); be_queue_free(phba, q); @@ -3732,68 +3527,6 @@ static void be_mcc_queues_destroy(struct beiscsi_hba *phba) } } -static void hwi_cleanup(struct beiscsi_hba *phba) -{ - struct be_queue_info *q; - struct be_ctrl_info *ctrl = &phba->ctrl; - struct hwi_controller *phwi_ctrlr; - struct hwi_context_memory *phwi_context; - struct hwi_async_pdu_context *pasync_ctx; - int i, eq_for_mcc, ulp_num; - - phwi_ctrlr = phba->phwi_ctrlr; - phwi_context = phwi_ctrlr->phwi_ctxt; - - be_cmd_iscsi_remove_template_hdr(ctrl); - - for (i = 0; i < phba->params.cxns_per_ctrl; i++) { - q = &phwi_context->be_wrbq[i]; - if (q->created) - beiscsi_cmd_q_destroy(ctrl, q, QTYPE_WRBQ); - } - kfree(phwi_context->be_wrbq); - free_wrb_handles(phba); - - for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) { - if (test_bit(ulp_num, &phba->fw_config.ulp_supported)) { - - q = &phwi_context->be_def_hdrq[ulp_num]; - if (q->created) - beiscsi_cmd_q_destroy(ctrl, q, QTYPE_DPDUQ); - - q = &phwi_context->be_def_dataq[ulp_num]; - if (q->created) - beiscsi_cmd_q_destroy(ctrl, q, QTYPE_DPDUQ); - - pasync_ctx = phwi_ctrlr->phwi_ctxt->pasync_ctx[ulp_num]; - } - } - - beiscsi_cmd_q_destroy(ctrl, NULL, QTYPE_SGL); - - for (i = 0; i < (phba->num_cpus); i++) { - q = &phwi_context->be_cq[i]; - if (q->created) { - be_queue_free(phba, q); - beiscsi_cmd_q_destroy(ctrl, q, QTYPE_CQ); - } - } - - be_mcc_queues_destroy(phba); - if (phba->msix_enabled) - eq_for_mcc = 1; - else - eq_for_mcc = 0; - for (i = 0; i < (phba->num_cpus + eq_for_mcc); i++) { - q = &phwi_context->be_eq[i].q; - if (q->created) { - be_queue_free(phba, q); - beiscsi_cmd_q_destroy(ctrl, q, QTYPE_EQ); - } - } - be_cmd_fw_uninit(ctrl); -} - static int be_mcc_queues_create(struct beiscsi_hba *phba, struct hwi_context_memory *phwi_context) { @@ -3875,6 +3608,118 @@ static void find_num_cpus(struct beiscsi_hba *phba) } } +static void hwi_purge_eq(struct beiscsi_hba *phba) +{ + struct hwi_controller *phwi_ctrlr; + struct hwi_context_memory *phwi_context; + struct be_queue_info *eq; + struct be_eq_entry *eqe = NULL; + int i, eq_msix; + unsigned int num_processed; + + if (beiscsi_hba_in_error(phba)) + return; + + phwi_ctrlr = phba->phwi_ctrlr; + phwi_context = phwi_ctrlr->phwi_ctxt; + if (phba->msix_enabled) + eq_msix = 1; + else + eq_msix = 0; + + for (i = 0; i < (phba->num_cpus + eq_msix); i++) { + eq = &phwi_context->be_eq[i].q; + eqe = queue_tail_node(eq); + num_processed = 0; + while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32] + & EQE_VALID_MASK) { + AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0); + queue_tail_inc(eq); + eqe = queue_tail_node(eq); + num_processed++; + } + + if (num_processed) + hwi_ring_eq_db(phba, eq->id, 1, num_processed, 1, 1); + } +} + +static void hwi_cleanup_port(struct beiscsi_hba *phba) +{ + struct be_queue_info *q; + struct be_ctrl_info *ctrl = &phba->ctrl; + struct hwi_controller *phwi_ctrlr; + struct hwi_context_memory *phwi_context; + struct hd_async_context *pasync_ctx; + int i, eq_for_mcc, ulp_num; + + for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) + if (test_bit(ulp_num, &phba->fw_config.ulp_supported)) + beiscsi_cmd_iscsi_cleanup(phba, ulp_num); + + /** + * Purge all EQ entries that may have been left out. This is to + * workaround a problem we've seen occasionally where driver gets an + * interrupt with EQ entry bit set after stopping the controller. + */ + hwi_purge_eq(phba); + + phwi_ctrlr = phba->phwi_ctrlr; + phwi_context = phwi_ctrlr->phwi_ctxt; + + be_cmd_iscsi_remove_template_hdr(ctrl); + + for (i = 0; i < phba->params.cxns_per_ctrl; i++) { + q = &phwi_context->be_wrbq[i]; + if (q->created) + beiscsi_cmd_q_destroy(ctrl, q, QTYPE_WRBQ); + } + kfree(phwi_context->be_wrbq); + free_wrb_handles(phba); + + for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) { + if (test_bit(ulp_num, &phba->fw_config.ulp_supported)) { + + q = &phwi_context->be_def_hdrq[ulp_num]; + if (q->created) + beiscsi_cmd_q_destroy(ctrl, q, QTYPE_DPDUQ); + + q = &phwi_context->be_def_dataq[ulp_num]; + if (q->created) + beiscsi_cmd_q_destroy(ctrl, q, QTYPE_DPDUQ); + + pasync_ctx = phwi_ctrlr->phwi_ctxt->pasync_ctx[ulp_num]; + } + } + + beiscsi_cmd_q_destroy(ctrl, NULL, QTYPE_SGL); + + for (i = 0; i < (phba->num_cpus); i++) { + q = &phwi_context->be_cq[i]; + if (q->created) { + be_queue_free(phba, q); + beiscsi_cmd_q_destroy(ctrl, q, QTYPE_CQ); + } + } + + be_mcc_queues_destroy(phba); + if (phba->msix_enabled) + eq_for_mcc = 1; + else + eq_for_mcc = 0; + for (i = 0; i < (phba->num_cpus + eq_for_mcc); i++) { + q = &phwi_context->be_eq[i].q; + if (q->created) { + be_queue_free(phba, q); + beiscsi_cmd_q_destroy(ctrl, q, QTYPE_EQ); + } + } + /* this ensures complete FW cleanup */ + beiscsi_cmd_function_reset(phba); + /* last communication, indicate driver is unloading */ + beiscsi_cmd_special_wrb(&phba->ctrl, 0); +} + static int hwi_init_port(struct beiscsi_hba *phba) { struct hwi_controller *phwi_ctrlr; @@ -3887,9 +3732,8 @@ static int hwi_init_port(struct beiscsi_hba *phba) phwi_context = phwi_ctrlr->phwi_ctxt; phwi_context->max_eqd = 128; phwi_context->min_eqd = 0; - phwi_context->cur_eqd = 0; - be_cmd_fw_initialize(&phba->ctrl); - /* set optic state to unknown */ + phwi_context->cur_eqd = 32; + /* set port optic state to unknown */ phba->optic_state = 0xff; status = beiscsi_create_eqs(phba, phwi_context); @@ -3903,7 +3747,7 @@ static int hwi_init_port(struct beiscsi_hba *phba) if (status != 0) goto error; - status = mgmt_check_supported_fw(ctrl, phba); + status = beiscsi_check_supported_fw(ctrl, phba); if (status != 0) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, "BM_%d : Unsupported fw version\n"); @@ -3919,7 +3763,6 @@ static int hwi_init_port(struct beiscsi_hba *phba) for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) { if (test_bit(ulp_num, &phba->fw_config.ulp_supported)) { - def_pdu_ring_sz = BEISCSI_GET_CID_COUNT(phba, ulp_num) * sizeof(struct phys_addr); @@ -3945,6 +3788,15 @@ static int hwi_init_port(struct beiscsi_hba *phba) ulp_num); goto error; } + /** + * Now that the default PDU rings have been created, + * let EP know about it. + * Call beiscsi_cmd_iscsi_cleanup before posting? + */ + beiscsi_hdq_post_handles(phba, BEISCSI_DEFQ_HDR, + ulp_num); + beiscsi_hdq_post_handles(phba, BEISCSI_DEFQ_DATA, + ulp_num); } } @@ -3973,7 +3825,7 @@ static int hwi_init_port(struct beiscsi_hba *phba) if (test_bit(ulp_num, &phba->fw_config.ulp_supported)) { uint16_t cri = 0; - struct hwi_async_pdu_context *pasync_ctx; + struct hd_async_context *pasync_ctx; pasync_ctx = HWI_GET_ASYNC_PDU_CTX( phwi_ctrlr, ulp_num); @@ -3985,6 +3837,14 @@ static int hwi_init_port(struct beiscsi_hba *phba) phwi_ctrlr->wrb_context[cri].cid] = async_arr_idx++; } + /** + * Now that the default PDU rings have been created, + * let EP know about it. + */ + beiscsi_hdq_post_handles(phba, BEISCSI_DEFQ_HDR, + ulp_num); + beiscsi_hdq_post_handles(phba, BEISCSI_DEFQ_DATA, + ulp_num); } } @@ -3995,7 +3855,7 @@ static int hwi_init_port(struct beiscsi_hba *phba) error: beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, "BM_%d : hwi_init_port failed"); - hwi_cleanup(phba); + hwi_cleanup_port(phba); return status; } @@ -4354,149 +4214,6 @@ static void hwi_disable_intr(struct beiscsi_hba *phba) "BM_%d : In hwi_disable_intr, Already Disabled\n"); } -/** - * beiscsi_get_boot_info()- Get the boot session info - * @phba: The device priv structure instance - * - * Get the boot target info and store in driver priv structure - * - * return values - * Success: 0 - * Failure: Non-Zero Value - **/ -static int beiscsi_get_boot_info(struct beiscsi_hba *phba) -{ - struct be_cmd_get_session_resp *session_resp; - struct be_dma_mem nonemb_cmd; - unsigned int tag; - unsigned int s_handle; - int ret = -ENOMEM; - - /* Get the session handle of the boot target */ - ret = be_mgmt_get_boot_shandle(phba, &s_handle); - if (ret) { - beiscsi_log(phba, KERN_ERR, - BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG, - "BM_%d : No boot session\n"); - - if (ret == -ENXIO) - phba->get_boot = 0; - - - return ret; - } - phba->get_boot = 0; - nonemb_cmd.va = pci_zalloc_consistent(phba->ctrl.pdev, - sizeof(*session_resp), - &nonemb_cmd.dma); - if (nonemb_cmd.va == NULL) { - beiscsi_log(phba, KERN_ERR, - BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG, - "BM_%d : Failed to allocate memory for" - "beiscsi_get_session_info\n"); - - return -ENOMEM; - } - - tag = mgmt_get_session_info(phba, s_handle, - &nonemb_cmd); - if (!tag) { - beiscsi_log(phba, KERN_ERR, - BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG, - "BM_%d : beiscsi_get_session_info" - " Failed\n"); - - goto boot_freemem; - } - - ret = beiscsi_mccq_compl_wait(phba, tag, NULL, &nonemb_cmd); - if (ret) { - beiscsi_log(phba, KERN_ERR, - BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG, - "BM_%d : beiscsi_get_session_info Failed"); - - if (ret != -EBUSY) - goto boot_freemem; - else - return ret; - } - - session_resp = nonemb_cmd.va ; - - memcpy(&phba->boot_sess, &session_resp->session_info, - sizeof(struct mgmt_session_info)); - - beiscsi_logout_fw_sess(phba, - phba->boot_sess.session_handle); - ret = 0; - -boot_freemem: - pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, - nonemb_cmd.va, nonemb_cmd.dma); - return ret; -} - -static void beiscsi_boot_release(void *data) -{ - struct beiscsi_hba *phba = data; - - scsi_host_put(phba->shost); -} - -static int beiscsi_setup_boot_info(struct beiscsi_hba *phba) -{ - struct iscsi_boot_kobj *boot_kobj; - - /* it has been created previously */ - if (phba->boot_kset) - return 0; - - /* get boot info using mgmt cmd */ - if (beiscsi_get_boot_info(phba)) - /* Try to see if we can carry on without this */ - return 0; - - phba->boot_kset = iscsi_boot_create_host_kset(phba->shost->host_no); - if (!phba->boot_kset) - return -ENOMEM; - - /* get a ref because the show function will ref the phba */ - if (!scsi_host_get(phba->shost)) - goto free_kset; - boot_kobj = iscsi_boot_create_target(phba->boot_kset, 0, phba, - beiscsi_show_boot_tgt_info, - beiscsi_tgt_get_attr_visibility, - beiscsi_boot_release); - if (!boot_kobj) - goto put_shost; - - if (!scsi_host_get(phba->shost)) - goto free_kset; - boot_kobj = iscsi_boot_create_initiator(phba->boot_kset, 0, phba, - beiscsi_show_boot_ini_info, - beiscsi_ini_get_attr_visibility, - beiscsi_boot_release); - if (!boot_kobj) - goto put_shost; - - if (!scsi_host_get(phba->shost)) - goto free_kset; - boot_kobj = iscsi_boot_create_ethernet(phba->boot_kset, 0, phba, - beiscsi_show_boot_eth_info, - beiscsi_eth_get_attr_visibility, - beiscsi_boot_release); - if (!boot_kobj) - goto put_shost; - return 0; - -put_shost: - scsi_host_put(phba->shost); -free_kset: - iscsi_boot_destroy_kset(phba->boot_kset); - phba->boot_kset = NULL; - return -ENOMEM; -} - static int beiscsi_init_port(struct beiscsi_hba *phba) { int ret; @@ -4516,7 +4233,8 @@ static int beiscsi_init_port(struct beiscsi_hba *phba) goto do_cleanup_ctrlr; } - if (hba_setup_cid_tbls(phba)) { + ret = hba_setup_cid_tbls(phba); + if (ret < 0) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, "BM_%d : Failed in hba_setup_cid_tbls\n"); kfree(phba->io_sgl_hndl_base); @@ -4527,61 +4245,15 @@ static int beiscsi_init_port(struct beiscsi_hba *phba) return ret; do_cleanup_ctrlr: - hwi_cleanup(phba); + hwi_cleanup_port(phba); return ret; } -static void hwi_purge_eq(struct beiscsi_hba *phba) -{ - struct hwi_controller *phwi_ctrlr; - struct hwi_context_memory *phwi_context; - struct be_queue_info *eq; - struct be_eq_entry *eqe = NULL; - int i, eq_msix; - unsigned int num_processed; - - phwi_ctrlr = phba->phwi_ctrlr; - phwi_context = phwi_ctrlr->phwi_ctxt; - if (phba->msix_enabled) - eq_msix = 1; - else - eq_msix = 0; - - for (i = 0; i < (phba->num_cpus + eq_msix); i++) { - eq = &phwi_context->be_eq[i].q; - eqe = queue_tail_node(eq); - num_processed = 0; - while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32] - & EQE_VALID_MASK) { - AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0); - queue_tail_inc(eq); - eqe = queue_tail_node(eq); - num_processed++; - } - - if (num_processed) - hwi_ring_eq_db(phba, eq->id, 1, num_processed, 1, 1); - } -} - -static void beiscsi_clean_port(struct beiscsi_hba *phba) +static void beiscsi_cleanup_port(struct beiscsi_hba *phba) { - int mgmt_status, ulp_num; struct ulp_cid_info *ptr_cid_info = NULL; + int ulp_num; - for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) { - if (test_bit(ulp_num, (void *)&phba->fw_config.ulp_supported)) { - mgmt_status = mgmt_epfw_cleanup(phba, ulp_num); - if (mgmt_status) - beiscsi_log(phba, KERN_WARNING, - BEISCSI_LOG_INIT, - "BM_%d : mgmt_epfw_cleanup FAILED" - " for ULP_%d\n", ulp_num); - } - } - - hwi_purge_eq(phba); - hwi_cleanup(phba); kfree(phba->io_sgl_hndl_base); kfree(phba->eh_sgl_hndl_base); kfree(phba->ep_array); @@ -4598,7 +4270,6 @@ static void beiscsi_clean_port(struct beiscsi_hba *phba) } } } - } /** @@ -4625,16 +4296,12 @@ beiscsi_free_mgmt_task_handles(struct beiscsi_conn *beiscsi_conn, io_task = task->dd_data; if (io_task->pwrb_handle) { - memset(io_task->pwrb_handle->pwrb, 0, - sizeof(struct iscsi_wrb)); - free_wrb_handle(phba, pwrb_context, - io_task->pwrb_handle); + free_wrb_handle(phba, pwrb_context, io_task->pwrb_handle); io_task->pwrb_handle = NULL; } if (io_task->psgl_handle) { - free_mgmt_sgl_handle(phba, - io_task->psgl_handle); + free_mgmt_sgl_handle(phba, io_task->psgl_handle); io_task->psgl_handle = NULL; } @@ -4671,6 +4338,7 @@ static void beiscsi_cleanup_task(struct iscsi_task *task) pci_pool_free(beiscsi_sess->bhs_pool, io_task->cmd_bhs, io_task->bhs_pa.u.a64.address); io_task->cmd_bhs = NULL; + task->hdr = NULL; } if (task->sc) { @@ -4686,7 +4354,8 @@ static void beiscsi_cleanup_task(struct iscsi_task *task) } if (io_task->scsi_cmnd) { - scsi_dma_unmap(io_task->scsi_cmnd); + if (io_task->num_sg) + scsi_dma_unmap(io_task->scsi_cmnd); io_task->scsi_cmnd = NULL; } } else { @@ -5051,7 +4720,6 @@ static int beiscsi_mtask(struct iscsi_task *task) cid = beiscsi_conn->beiscsi_conn_cid; pwrb = io_task->pwrb_handle->pwrb; - memset(pwrb, 0, sizeof(*pwrb)); if (is_chip_be2_be3r(phba)) { AMAP_SET_BITS(struct amap_iscsi_wrb, cmdsn_itt, pwrb, @@ -5165,6 +4833,15 @@ static int beiscsi_task_xmit(struct iscsi_task *task) int num_sg; unsigned int writedir = 0, xferlen = 0; + phba = io_task->conn->phba; + /** + * HBA in error includes BEISCSI_HBA_FW_TIMEOUT. IO path might be + * operational if FW still gets heartbeat from EP FW. Is management + * path really needed to continue further? + */ + if (!beiscsi_hba_is_online(phba)) + return -EIO; + if (!io_task->conn->login_in_progress) task->hdr->exp_statsn = 0; @@ -5172,8 +4849,8 @@ static int beiscsi_task_xmit(struct iscsi_task *task) return beiscsi_mtask(task); io_task->scsi_cmnd = sc; + io_task->num_sg = 0; num_sg = scsi_dma_map(sc); - phba = io_task->conn->phba; if (num_sg < 0) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_IO | BEISCSI_LOG_ISCSI, @@ -5184,6 +4861,11 @@ static int beiscsi_task_xmit(struct iscsi_task *task) return num_sg; } + /** + * For scsi cmd task, check num_sg before unmapping in cleanup_task. + * For management task, cleanup_task checks mtask_addr before unmapping. + */ + io_task->num_sg = num_sg; xferlen = scsi_bufflen(sc); sg = scsi_sglist(sc); if (sc->sc_data_direction == DMA_TO_DEVICE) @@ -5213,6 +4895,12 @@ static int beiscsi_bsg_request(struct bsg_job *job) shost = iscsi_job_to_shost(job); phba = iscsi_host_priv(shost); + if (!beiscsi_hba_is_online(phba)) { + beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, + "BM_%d : HBA in error 0x%lx\n", phba->state); + return -ENXIO; + } + switch (bsg_req->msgcode) { case ISCSI_BSG_HST_VENDOR: nonemb_cmd.va = pci_alloc_consistent(phba->ctrl.pdev, @@ -5240,6 +4928,14 @@ static int beiscsi_bsg_request(struct bsg_job *job) phba->ctrl.mcc_tag_status[tag], msecs_to_jiffies( BEISCSI_HOST_MBX_TIMEOUT)); + + if (!test_bit(BEISCSI_HBA_ONLINE, &phba->state)) { + clear_bit(MCC_TAG_STATE_RUNNING, + &phba->ctrl.ptag_state[tag].tag_state); + pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, + nonemb_cmd.va, nonemb_cmd.dma); + return -EIO; + } extd_status = (phba->ctrl.mcc_tag_status[tag] & CQE_STATUS_ADDL_MASK) >> CQE_STATUS_ADDL_SHIFT; status = phba->ctrl.mcc_tag_status[tag] & CQE_STATUS_MASK; @@ -5283,106 +4979,294 @@ void beiscsi_hba_attrs_init(struct beiscsi_hba *phba) beiscsi_log_enable_init(phba, beiscsi_log_enable); } -/* - * beiscsi_quiesce()- Cleanup Driver resources - * @phba: Instance Priv structure - * @unload_state:i Clean or EEH unload state - * - * Free the OS and HW resources held by the driver - **/ -static void beiscsi_quiesce(struct beiscsi_hba *phba, - uint32_t unload_state) +void beiscsi_start_boot_work(struct beiscsi_hba *phba, unsigned int s_handle) { - struct hwi_controller *phwi_ctrlr; - struct hwi_context_memory *phwi_context; - struct be_eq_obj *pbe_eq; - unsigned int i, msix_vec; + if (phba->boot_struct.boot_kset) + return; - phwi_ctrlr = phba->phwi_ctrlr; - phwi_context = phwi_ctrlr->phwi_ctxt; - hwi_disable_intr(phba); - if (phba->msix_enabled) { - for (i = 0; i <= phba->num_cpus; i++) { - msix_vec = phba->msix_entries[i].vector; - free_irq(msix_vec, &phwi_context->be_eq[i]); - kfree(phba->msi_name[i]); - } - } else - if (phba->pcidev->irq) - free_irq(phba->pcidev->irq, phba); - pci_disable_msix(phba->pcidev); - cancel_delayed_work_sync(&phba->beiscsi_hw_check_task); + /* skip if boot work is already in progress */ + if (test_and_set_bit(BEISCSI_HBA_BOOT_WORK, &phba->state)) + return; - for (i = 0; i < phba->num_cpus; i++) { - pbe_eq = &phwi_context->be_eq[i]; - irq_poll_disable(&pbe_eq->iopoll); + phba->boot_struct.retry = 3; + phba->boot_struct.tag = 0; + phba->boot_struct.s_handle = s_handle; + phba->boot_struct.action = BEISCSI_BOOT_GET_SHANDLE; + schedule_work(&phba->boot_work); +} + +static ssize_t beiscsi_show_boot_tgt_info(void *data, int type, char *buf) +{ + struct beiscsi_hba *phba = data; + struct mgmt_session_info *boot_sess = &phba->boot_struct.boot_sess; + struct mgmt_conn_info *boot_conn = &boot_sess->conn_list[0]; + char *str = buf; + int rc = -EPERM; + + switch (type) { + case ISCSI_BOOT_TGT_NAME: + rc = sprintf(buf, "%.*s\n", + (int)strlen(boot_sess->target_name), + (char *)&boot_sess->target_name); + break; + case ISCSI_BOOT_TGT_IP_ADDR: + if (boot_conn->dest_ipaddr.ip_type == BEISCSI_IP_TYPE_V4) + rc = sprintf(buf, "%pI4\n", + (char *)&boot_conn->dest_ipaddr.addr); + else + rc = sprintf(str, "%pI6\n", + (char *)&boot_conn->dest_ipaddr.addr); + break; + case ISCSI_BOOT_TGT_PORT: + rc = sprintf(str, "%d\n", boot_conn->dest_port); + break; + + case ISCSI_BOOT_TGT_CHAP_NAME: + rc = sprintf(str, "%.*s\n", + boot_conn->negotiated_login_options.auth_data.chap. + target_chap_name_length, + (char *)&boot_conn->negotiated_login_options. + auth_data.chap.target_chap_name); + break; + case ISCSI_BOOT_TGT_CHAP_SECRET: + rc = sprintf(str, "%.*s\n", + boot_conn->negotiated_login_options.auth_data.chap. + target_secret_length, + (char *)&boot_conn->negotiated_login_options. + auth_data.chap.target_secret); + break; + case ISCSI_BOOT_TGT_REV_CHAP_NAME: + rc = sprintf(str, "%.*s\n", + boot_conn->negotiated_login_options.auth_data.chap. + intr_chap_name_length, + (char *)&boot_conn->negotiated_login_options. + auth_data.chap.intr_chap_name); + break; + case ISCSI_BOOT_TGT_REV_CHAP_SECRET: + rc = sprintf(str, "%.*s\n", + boot_conn->negotiated_login_options.auth_data.chap. + intr_secret_length, + (char *)&boot_conn->negotiated_login_options. + auth_data.chap.intr_secret); + break; + case ISCSI_BOOT_TGT_FLAGS: + rc = sprintf(str, "2\n"); + break; + case ISCSI_BOOT_TGT_NIC_ASSOC: + rc = sprintf(str, "0\n"); + break; } + return rc; +} - if (unload_state == BEISCSI_CLEAN_UNLOAD) { - destroy_workqueue(phba->wq); - beiscsi_clean_port(phba); - beiscsi_free_mem(phba); +static ssize_t beiscsi_show_boot_ini_info(void *data, int type, char *buf) +{ + struct beiscsi_hba *phba = data; + char *str = buf; + int rc = -EPERM; - beiscsi_unmap_pci_function(phba); - pci_free_consistent(phba->pcidev, - phba->ctrl.mbox_mem_alloced.size, - phba->ctrl.mbox_mem_alloced.va, - phba->ctrl.mbox_mem_alloced.dma); - } else { - hwi_purge_eq(phba); - hwi_cleanup(phba); + switch (type) { + case ISCSI_BOOT_INI_INITIATOR_NAME: + rc = sprintf(str, "%s\n", + phba->boot_struct.boot_sess.initiator_iscsiname); + break; } + return rc; +} + +static ssize_t beiscsi_show_boot_eth_info(void *data, int type, char *buf) +{ + struct beiscsi_hba *phba = data; + char *str = buf; + int rc = -EPERM; + switch (type) { + case ISCSI_BOOT_ETH_FLAGS: + rc = sprintf(str, "2\n"); + break; + case ISCSI_BOOT_ETH_INDEX: + rc = sprintf(str, "0\n"); + break; + case ISCSI_BOOT_ETH_MAC: + rc = beiscsi_get_macaddr(str, phba); + break; + } + return rc; } -static void beiscsi_remove(struct pci_dev *pcidev) +static umode_t beiscsi_tgt_get_attr_visibility(void *data, int type) { - struct beiscsi_hba *phba = NULL; + umode_t rc = 0; - phba = pci_get_drvdata(pcidev); - if (!phba) { - dev_err(&pcidev->dev, "beiscsi_remove called with no phba\n"); - return; + switch (type) { + case ISCSI_BOOT_TGT_NAME: + case ISCSI_BOOT_TGT_IP_ADDR: + case ISCSI_BOOT_TGT_PORT: + case ISCSI_BOOT_TGT_CHAP_NAME: + case ISCSI_BOOT_TGT_CHAP_SECRET: + case ISCSI_BOOT_TGT_REV_CHAP_NAME: + case ISCSI_BOOT_TGT_REV_CHAP_SECRET: + case ISCSI_BOOT_TGT_NIC_ASSOC: + case ISCSI_BOOT_TGT_FLAGS: + rc = S_IRUGO; + break; } + return rc; +} - beiscsi_destroy_def_ifaces(phba); - iscsi_boot_destroy_kset(phba->boot_kset); - iscsi_host_remove(phba->shost); - beiscsi_quiesce(phba, BEISCSI_CLEAN_UNLOAD); - pci_dev_put(phba->pcidev); - iscsi_host_free(phba->shost); - pci_disable_pcie_error_reporting(pcidev); - pci_set_drvdata(pcidev, NULL); - pci_release_regions(pcidev); - pci_disable_device(pcidev); +static umode_t beiscsi_ini_get_attr_visibility(void *data, int type) +{ + umode_t rc = 0; + + switch (type) { + case ISCSI_BOOT_INI_INITIATOR_NAME: + rc = S_IRUGO; + break; + } + return rc; } -static void beiscsi_msix_enable(struct beiscsi_hba *phba) +static umode_t beiscsi_eth_get_attr_visibility(void *data, int type) { - int i, status; + umode_t rc = 0; - for (i = 0; i <= phba->num_cpus; i++) - phba->msix_entries[i].entry = i; + switch (type) { + case ISCSI_BOOT_ETH_FLAGS: + case ISCSI_BOOT_ETH_MAC: + case ISCSI_BOOT_ETH_INDEX: + rc = S_IRUGO; + break; + } + return rc; +} - status = pci_enable_msix_range(phba->pcidev, phba->msix_entries, - phba->num_cpus + 1, phba->num_cpus + 1); - if (status > 0) - phba->msix_enabled = true; +static void beiscsi_boot_kobj_release(void *data) +{ + struct beiscsi_hba *phba = data; - return; + scsi_host_put(phba->shost); } -static void be_eqd_update(struct beiscsi_hba *phba) +static int beiscsi_boot_create_kset(struct beiscsi_hba *phba) { + struct boot_struct *bs = &phba->boot_struct; + struct iscsi_boot_kobj *boot_kobj; + + if (bs->boot_kset) { + __beiscsi_log(phba, KERN_ERR, + "BM_%d: boot_kset already created\n"); + return 0; + } + + bs->boot_kset = iscsi_boot_create_host_kset(phba->shost->host_no); + if (!bs->boot_kset) { + __beiscsi_log(phba, KERN_ERR, + "BM_%d: boot_kset alloc failed\n"); + return -ENOMEM; + } + + /* get shost ref because the show function will refer phba */ + if (!scsi_host_get(phba->shost)) + goto free_kset; + + boot_kobj = iscsi_boot_create_target(bs->boot_kset, 0, phba, + beiscsi_show_boot_tgt_info, + beiscsi_tgt_get_attr_visibility, + beiscsi_boot_kobj_release); + if (!boot_kobj) + goto put_shost; + + if (!scsi_host_get(phba->shost)) + goto free_kset; + + boot_kobj = iscsi_boot_create_initiator(bs->boot_kset, 0, phba, + beiscsi_show_boot_ini_info, + beiscsi_ini_get_attr_visibility, + beiscsi_boot_kobj_release); + if (!boot_kobj) + goto put_shost; + + if (!scsi_host_get(phba->shost)) + goto free_kset; + + boot_kobj = iscsi_boot_create_ethernet(bs->boot_kset, 0, phba, + beiscsi_show_boot_eth_info, + beiscsi_eth_get_attr_visibility, + beiscsi_boot_kobj_release); + if (!boot_kobj) + goto put_shost; + + return 0; + +put_shost: + scsi_host_put(phba->shost); +free_kset: + iscsi_boot_destroy_kset(bs->boot_kset); + bs->boot_kset = NULL; + return -ENOMEM; +} + +static void beiscsi_boot_work(struct work_struct *work) +{ + struct beiscsi_hba *phba = + container_of(work, struct beiscsi_hba, boot_work); + struct boot_struct *bs = &phba->boot_struct; + unsigned int tag = 0; + + if (!beiscsi_hba_is_online(phba)) + return; + + beiscsi_log(phba, KERN_INFO, + BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX, + "BM_%d : %s action %d\n", + __func__, phba->boot_struct.action); + + switch (phba->boot_struct.action) { + case BEISCSI_BOOT_REOPEN_SESS: + tag = beiscsi_boot_reopen_sess(phba); + break; + case BEISCSI_BOOT_GET_SHANDLE: + tag = __beiscsi_boot_get_shandle(phba, 1); + break; + case BEISCSI_BOOT_GET_SINFO: + tag = beiscsi_boot_get_sinfo(phba); + break; + case BEISCSI_BOOT_LOGOUT_SESS: + tag = beiscsi_boot_logout_sess(phba); + break; + case BEISCSI_BOOT_CREATE_KSET: + beiscsi_boot_create_kset(phba); + /** + * updated boot_kset is made visible to all before + * ending the boot work. + */ + mb(); + clear_bit(BEISCSI_HBA_BOOT_WORK, &phba->state); + return; + } + if (!tag) { + if (bs->retry--) + schedule_work(&phba->boot_work); + else + clear_bit(BEISCSI_HBA_BOOT_WORK, &phba->state); + } +} + +static void beiscsi_eqd_update_work(struct work_struct *work) +{ + struct hwi_context_memory *phwi_context; struct be_set_eqd set_eqd[MAX_CPUS]; - struct be_aic_obj *aic; - struct be_eq_obj *pbe_eq; struct hwi_controller *phwi_ctrlr; - struct hwi_context_memory *phwi_context; + struct be_eq_obj *pbe_eq; + struct beiscsi_hba *phba; + unsigned int pps, delta; + struct be_aic_obj *aic; int eqd, i, num = 0; - ulong now; - u32 pps, delta; - unsigned int tag; + unsigned long now; + + phba = container_of(work, struct beiscsi_hba, eqd_update.work); + if (!beiscsi_hba_is_online(phba)) + return; phwi_ctrlr = phba->phwi_ctrlr; phwi_context = phwi_ctrlr->phwi_ctxt; @@ -5391,13 +5275,13 @@ static void be_eqd_update(struct beiscsi_hba *phba) aic = &phba->aic_obj[i]; pbe_eq = &phwi_context->be_eq[i]; now = jiffies; - if (!aic->jiffs || time_before(now, aic->jiffs) || + if (!aic->jiffies || time_before(now, aic->jiffies) || pbe_eq->cq_count < aic->eq_prev) { - aic->jiffs = now; + aic->jiffies = now; aic->eq_prev = pbe_eq->cq_count; continue; } - delta = jiffies_to_msecs(now - aic->jiffs); + delta = jiffies_to_msecs(now - aic->jiffies); pps = (((u32)(pbe_eq->cq_count - aic->eq_prev) * 1000) / delta); eqd = (pps / 1500) << 2; @@ -5406,7 +5290,7 @@ static void be_eqd_update(struct beiscsi_hba *phba) eqd = min_t(u32, eqd, phwi_context->max_eqd); eqd = max_t(u32, eqd, phwi_context->min_eqd); - aic->jiffs = now; + aic->jiffies = now; aic->eq_prev = pbe_eq->cq_count; if (eqd != aic->prev_eqd) { @@ -5416,53 +5300,242 @@ static void be_eqd_update(struct beiscsi_hba *phba) num++; } } - if (num) { - tag = be_cmd_modify_eq_delay(phba, set_eqd, num); - if (tag) - beiscsi_mccq_compl_wait(phba, tag, NULL, NULL); + if (num) + /* completion of this is ignored */ + beiscsi_modify_eq_delay(phba, set_eqd, num); + + schedule_delayed_work(&phba->eqd_update, + msecs_to_jiffies(BEISCSI_EQD_UPDATE_INTERVAL)); +} + +static void beiscsi_msix_enable(struct beiscsi_hba *phba) +{ + int i, status; + + for (i = 0; i <= phba->num_cpus; i++) + phba->msix_entries[i].entry = i; + + status = pci_enable_msix_range(phba->pcidev, phba->msix_entries, + phba->num_cpus + 1, phba->num_cpus + 1); + if (status > 0) + phba->msix_enabled = true; +} + +static void beiscsi_hw_tpe_check(unsigned long ptr) +{ + struct beiscsi_hba *phba; + u32 wait; + + phba = (struct beiscsi_hba *)ptr; + /* if not TPE, do nothing */ + if (!beiscsi_detect_tpe(phba)) + return; + + /* wait default 4000ms before recovering */ + wait = 4000; + if (phba->ue2rp > BEISCSI_UE_DETECT_INTERVAL) + wait = phba->ue2rp - BEISCSI_UE_DETECT_INTERVAL; + queue_delayed_work(phba->wq, &phba->recover_port, + msecs_to_jiffies(wait)); +} + +static void beiscsi_hw_health_check(unsigned long ptr) +{ + struct beiscsi_hba *phba; + + phba = (struct beiscsi_hba *)ptr; + beiscsi_detect_ue(phba); + if (beiscsi_detect_ue(phba)) { + __beiscsi_log(phba, KERN_ERR, + "BM_%d : port in error: %lx\n", phba->state); + /* sessions are no longer valid, so first fail the sessions */ + queue_work(phba->wq, &phba->sess_work); + + /* detect UER supported */ + if (!test_bit(BEISCSI_HBA_UER_SUPP, &phba->state)) + return; + /* modify this timer to check TPE */ + phba->hw_check.function = beiscsi_hw_tpe_check; } + + mod_timer(&phba->hw_check, + jiffies + msecs_to_jiffies(BEISCSI_UE_DETECT_INTERVAL)); } -static void be_check_boot_session(struct beiscsi_hba *phba) +/* + * beiscsi_enable_port()- Enables the disabled port. + * Only port resources freed in disable function are reallocated. + * This is called in HBA error handling path. + * + * @phba: Instance of driver private structure + * + **/ +static int beiscsi_enable_port(struct beiscsi_hba *phba) { - if (beiscsi_setup_boot_info(phba)) - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, - "BM_%d : Could not set up " - "iSCSI boot info on async event.\n"); + struct hwi_context_memory *phwi_context; + struct hwi_controller *phwi_ctrlr; + struct be_eq_obj *pbe_eq; + int ret, i; + + if (test_bit(BEISCSI_HBA_ONLINE, &phba->state)) { + __beiscsi_log(phba, KERN_ERR, + "BM_%d : %s : port is online %lx\n", + __func__, phba->state); + return 0; + } + + ret = beiscsi_init_sliport(phba); + if (ret) + return ret; + + if (enable_msix) + find_num_cpus(phba); + else + phba->num_cpus = 1; + if (enable_msix) { + beiscsi_msix_enable(phba); + if (!phba->msix_enabled) + phba->num_cpus = 1; + } + + beiscsi_get_params(phba); + /* Re-enable UER. If different TPE occurs then it is recoverable. */ + beiscsi_set_uer_feature(phba); + + phba->shost->max_id = phba->params.cxns_per_ctrl; + phba->shost->can_queue = phba->params.ios_per_ctrl; + ret = hwi_init_controller(phba); + if (ret) { + __beiscsi_log(phba, KERN_ERR, + "BM_%d : init controller failed %d\n", ret); + goto disable_msix; + } + + for (i = 0; i < MAX_MCC_CMD; i++) { + init_waitqueue_head(&phba->ctrl.mcc_wait[i + 1]); + phba->ctrl.mcc_tag[i] = i + 1; + phba->ctrl.mcc_tag_status[i + 1] = 0; + phba->ctrl.mcc_tag_available++; + } + + phwi_ctrlr = phba->phwi_ctrlr; + phwi_context = phwi_ctrlr->phwi_ctxt; + for (i = 0; i < phba->num_cpus; i++) { + pbe_eq = &phwi_context->be_eq[i]; + irq_poll_init(&pbe_eq->iopoll, be_iopoll_budget, be_iopoll); + } + + i = (phba->msix_enabled) ? i : 0; + /* Work item for MCC handling */ + pbe_eq = &phwi_context->be_eq[i]; + INIT_WORK(&pbe_eq->mcc_work, beiscsi_mcc_work); + + ret = beiscsi_init_irqs(phba); + if (ret < 0) { + __beiscsi_log(phba, KERN_ERR, + "BM_%d : setup IRQs failed %d\n", ret); + goto cleanup_port; + } + hwi_enable_intr(phba); + /* port operational: clear all error bits */ + set_bit(BEISCSI_HBA_ONLINE, &phba->state); + __beiscsi_log(phba, KERN_INFO, + "BM_%d : port online: 0x%lx\n", phba->state); + + /* start hw_check timer and eqd_update work */ + schedule_delayed_work(&phba->eqd_update, + msecs_to_jiffies(BEISCSI_EQD_UPDATE_INTERVAL)); + + /** + * Timer function gets modified for TPE detection. + * Always reinit to do health check first. + */ + phba->hw_check.function = beiscsi_hw_health_check; + mod_timer(&phba->hw_check, + jiffies + msecs_to_jiffies(BEISCSI_UE_DETECT_INTERVAL)); + return 0; + +cleanup_port: + for (i = 0; i < phba->num_cpus; i++) { + pbe_eq = &phwi_context->be_eq[i]; + irq_poll_disable(&pbe_eq->iopoll); + } + hwi_cleanup_port(phba); + +disable_msix: + if (phba->msix_enabled) + pci_disable_msix(phba->pcidev); + + return ret; } /* - * beiscsi_hw_health_check()- Check adapter health - * @work: work item to check HW health + * beiscsi_disable_port()- Disable port and cleanup driver resources. + * This is called in HBA error handling and driver removal. + * @phba: Instance Priv structure + * @unload: indicate driver is unloading * - * Check if adapter in an unrecoverable state or not. + * Free the OS and HW resources held by the driver **/ -static void -beiscsi_hw_health_check(struct work_struct *work) +static void beiscsi_disable_port(struct beiscsi_hba *phba, int unload) { - struct beiscsi_hba *phba = - container_of(work, struct beiscsi_hba, - beiscsi_hw_check_task.work); + struct hwi_context_memory *phwi_context; + struct hwi_controller *phwi_ctrlr; + struct be_eq_obj *pbe_eq; + unsigned int i, msix_vec; - be_eqd_update(phba); + if (!test_and_clear_bit(BEISCSI_HBA_ONLINE, &phba->state)) + return; - if (phba->state & BE_ADAPTER_CHECK_BOOT) { - if ((phba->get_boot > 0) && (!phba->boot_kset)) { - phba->get_boot--; - if (!(phba->get_boot % BE_GET_BOOT_TO)) - be_check_boot_session(phba); - } else { - phba->state &= ~BE_ADAPTER_CHECK_BOOT; - phba->get_boot = 0; + phwi_ctrlr = phba->phwi_ctrlr; + phwi_context = phwi_ctrlr->phwi_ctxt; + hwi_disable_intr(phba); + if (phba->msix_enabled) { + for (i = 0; i <= phba->num_cpus; i++) { + msix_vec = phba->msix_entries[i].vector; + free_irq(msix_vec, &phwi_context->be_eq[i]); + kfree(phba->msi_name[i]); } + } else + if (phba->pcidev->irq) + free_irq(phba->pcidev->irq, phba); + pci_disable_msix(phba->pcidev); + + for (i = 0; i < phba->num_cpus; i++) { + pbe_eq = &phwi_context->be_eq[i]; + irq_poll_disable(&pbe_eq->iopoll); } + cancel_delayed_work_sync(&phba->eqd_update); + cancel_work_sync(&phba->boot_work); + /* WQ might be running cancel queued mcc_work if we are not exiting */ + if (!unload && beiscsi_hba_in_error(phba)) { + pbe_eq = &phwi_context->be_eq[i]; + cancel_work_sync(&pbe_eq->mcc_work); + } + hwi_cleanup_port(phba); +} - beiscsi_ue_detect(phba); +static void beiscsi_sess_work(struct work_struct *work) +{ + struct beiscsi_hba *phba; - schedule_delayed_work(&phba->beiscsi_hw_check_task, - msecs_to_jiffies(1000)); + phba = container_of(work, struct beiscsi_hba, sess_work); + /* + * This work gets scheduled only in case of HBA error. + * Old sessions are gone so need to be re-established. + * iscsi_session_failure needs process context hence this work. + */ + iscsi_host_for_each_session(phba->shost, beiscsi_session_fail); } +static void beiscsi_recover_port(struct work_struct *work) +{ + struct beiscsi_hba *phba; + + phba = container_of(work, struct beiscsi_hba, recover_port.work); + beiscsi_disable_port(phba, 0); + beiscsi_enable_port(phba); +} static pci_ers_result_t beiscsi_eeh_err_detected(struct pci_dev *pdev, pci_channel_state_t state) @@ -5470,12 +5543,18 @@ static pci_ers_result_t beiscsi_eeh_err_detected(struct pci_dev *pdev, struct beiscsi_hba *phba = NULL; phba = (struct beiscsi_hba *)pci_get_drvdata(pdev); - phba->state |= BE_ADAPTER_PCI_ERR; + set_bit(BEISCSI_HBA_PCI_ERR, &phba->state); beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, "BM_%d : EEH error detected\n"); - beiscsi_quiesce(phba, BEISCSI_EEH_UNLOAD); + /* first stop UE detection when PCI error detected */ + del_timer_sync(&phba->hw_check); + cancel_delayed_work_sync(&phba->recover_port); + + /* sessions are no longer valid, so first fail the sessions */ + iscsi_host_for_each_session(phba->shost, beiscsi_session_fail); + beiscsi_disable_port(phba, 0); if (state == pci_channel_io_perm_failure) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, @@ -5515,9 +5594,8 @@ static pci_ers_result_t beiscsi_eeh_reset(struct pci_dev *pdev) pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); - /* Wait for the CHIP Reset to complete */ - status = be_chk_reset_complete(phba); - if (!status) { + status = beiscsi_check_fw_rdy(phba); + if (status) { beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_INIT, "BM_%d : EEH Reset Completed\n"); } else { @@ -5532,87 +5610,16 @@ static pci_ers_result_t beiscsi_eeh_reset(struct pci_dev *pdev) static void beiscsi_eeh_resume(struct pci_dev *pdev) { - int ret = 0, i; - struct be_eq_obj *pbe_eq; - struct beiscsi_hba *phba = NULL; - struct hwi_controller *phwi_ctrlr; - struct hwi_context_memory *phwi_context; + struct beiscsi_hba *phba; + int ret; phba = (struct beiscsi_hba *)pci_get_drvdata(pdev); pci_save_state(pdev); - if (enable_msix) - find_num_cpus(phba); - else - phba->num_cpus = 1; - - if (enable_msix) { - beiscsi_msix_enable(phba); - if (!phba->msix_enabled) - phba->num_cpus = 1; - } - - ret = beiscsi_cmd_reset_function(phba); - if (ret) { - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, - "BM_%d : Reset Failed\n"); - goto ret_err; - } - - ret = be_chk_reset_complete(phba); - if (ret) { - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, - "BM_%d : Failed to get out of reset.\n"); - goto ret_err; - } - - beiscsi_get_params(phba); - phba->shost->max_id = phba->params.cxns_per_ctrl; - phba->shost->can_queue = phba->params.ios_per_ctrl; - ret = hwi_init_controller(phba); - if (ret) { - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, - "BM_%d : beiscsi_eeh_resume -" - "Failed to initialize beiscsi_hba.\n"); - goto ret_err; - } - - for (i = 0; i < MAX_MCC_CMD; i++) { - init_waitqueue_head(&phba->ctrl.mcc_wait[i + 1]); - phba->ctrl.mcc_tag[i] = i + 1; - phba->ctrl.mcc_tag_status[i + 1] = 0; - phba->ctrl.mcc_tag_available++; - } - - phwi_ctrlr = phba->phwi_ctrlr; - phwi_context = phwi_ctrlr->phwi_ctxt; - - for (i = 0; i < phba->num_cpus; i++) { - pbe_eq = &phwi_context->be_eq[i]; - irq_poll_init(&pbe_eq->iopoll, be_iopoll_budget, - be_iopoll); - } - - i = (phba->msix_enabled) ? i : 0; - /* Work item for MCC handling */ - pbe_eq = &phwi_context->be_eq[i]; - INIT_WORK(&pbe_eq->work_cqs, beiscsi_process_all_cqs); - - ret = beiscsi_init_irqs(phba); - if (ret < 0) { - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, - "BM_%d : beiscsi_eeh_resume - " - "Failed to beiscsi_init_irqs\n"); - goto ret_err; - } - - hwi_enable_intr(phba); - phba->state &= ~BE_ADAPTER_PCI_ERR; - - return; -ret_err: - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, - "BM_%d : AER EEH Resume Failed\n"); + ret = beiscsi_enable_port(phba); + if (ret) + __beiscsi_log(phba, KERN_ERR, + "BM_%d : AER EEH resume failed\n"); } static int beiscsi_dev_probe(struct pci_dev *pcidev, @@ -5622,7 +5629,8 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev, struct hwi_controller *phwi_ctrlr; struct hwi_context_memory *phwi_context; struct be_eq_obj *pbe_eq; - int ret = 0, i; + unsigned int s_handle; + int ret, i; ret = beiscsi_enable_pci(pcidev); if (ret < 0) { @@ -5635,6 +5643,7 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev, if (!phba) { dev_err(&pcidev->dev, "beiscsi_dev_probe - Failed in beiscsi_hba_alloc\n"); + ret = -ENOMEM; goto disable_pci; } @@ -5650,10 +5659,8 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev, /* Initialize Driver configuration Paramters */ beiscsi_hba_attrs_init(phba); - phba->fw_timeout = false; phba->mac_addr_set = false; - switch (pcidev->device) { case BE_DEVICE_ID1: case OC_DEVICE_ID1: @@ -5677,39 +5684,26 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev, ret = be_ctrl_init(phba, pcidev); if (ret) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, - "BM_%d : beiscsi_dev_probe-" - "Failed in be_ctrl_init\n"); + "BM_%d : be_ctrl_init failed\n"); goto hba_free; } - /* - * FUNCTION_RESET should clean up any stale info in FW for this fn - */ - ret = beiscsi_cmd_reset_function(phba); - if (ret) { - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, - "BM_%d : Reset Failed\n"); - goto hba_free; - } - ret = be_chk_reset_complete(phba); - if (ret) { - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, - "BM_%d : Failed to get out of reset.\n"); + ret = beiscsi_init_sliport(phba); + if (ret) goto hba_free; - } spin_lock_init(&phba->io_sgl_lock); spin_lock_init(&phba->mgmt_sgl_lock); - spin_lock_init(&phba->isr_lock); spin_lock_init(&phba->async_pdu_lock); - ret = mgmt_get_fw_config(&phba->ctrl, phba); + ret = beiscsi_get_fw_config(&phba->ctrl, phba); if (ret != 0) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, "BM_%d : Error getting fw config\n"); goto free_port; } - mgmt_get_port_name(&phba->ctrl, phba); + beiscsi_get_port_name(&phba->ctrl, phba); beiscsi_get_params(phba); + beiscsi_set_uer_feature(phba); if (enable_msix) find_num_cpus(phba); @@ -5754,25 +5748,24 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev, beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, "BM_%d : beiscsi_dev_probe-" "Failed to allocate work queue\n"); + ret = -ENOMEM; goto free_twq; } - INIT_DELAYED_WORK(&phba->beiscsi_hw_check_task, - beiscsi_hw_health_check); + INIT_DELAYED_WORK(&phba->eqd_update, beiscsi_eqd_update_work); phwi_ctrlr = phba->phwi_ctrlr; phwi_context = phwi_ctrlr->phwi_ctxt; for (i = 0; i < phba->num_cpus; i++) { pbe_eq = &phwi_context->be_eq[i]; - irq_poll_init(&pbe_eq->iopoll, be_iopoll_budget, - be_iopoll); + irq_poll_init(&pbe_eq->iopoll, be_iopoll_budget, be_iopoll); } i = (phba->msix_enabled) ? i : 0; /* Work item for MCC handling */ pbe_eq = &phwi_context->be_eq[i]; - INIT_WORK(&pbe_eq->work_cqs, beiscsi_process_all_cqs); + INIT_WORK(&pbe_eq->mcc_work, beiscsi_mcc_work); ret = beiscsi_init_irqs(phba); if (ret < 0) { @@ -5783,22 +5776,42 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev, } hwi_enable_intr(phba); - if (iscsi_host_add(phba->shost, &phba->pcidev->dev)) + ret = iscsi_host_add(phba->shost, &phba->pcidev->dev); + if (ret) goto free_blkenbld; - if (beiscsi_setup_boot_info(phba)) - /* - * log error but continue, because we may not be using - * iscsi boot. + /* set online bit after port is operational */ + set_bit(BEISCSI_HBA_ONLINE, &phba->state); + __beiscsi_log(phba, KERN_INFO, + "BM_%d : port online: 0x%lx\n", phba->state); + + INIT_WORK(&phba->boot_work, beiscsi_boot_work); + ret = beiscsi_boot_get_shandle(phba, &s_handle); + if (ret > 0) { + beiscsi_start_boot_work(phba, s_handle); + /** + * Set this bit after starting the work to let + * probe handle it first. + * ASYNC event can too schedule this work. */ - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, - "BM_%d : Could not set up " - "iSCSI boot info.\n"); + set_bit(BEISCSI_HBA_BOOT_FOUND, &phba->state); + } - beiscsi_create_def_ifaces(phba); - schedule_delayed_work(&phba->beiscsi_hw_check_task, - msecs_to_jiffies(1000)); + beiscsi_iface_create_default(phba); + schedule_delayed_work(&phba->eqd_update, + msecs_to_jiffies(BEISCSI_EQD_UPDATE_INTERVAL)); + INIT_WORK(&phba->sess_work, beiscsi_sess_work); + INIT_DELAYED_WORK(&phba->recover_port, beiscsi_recover_port); + /** + * Start UE detection here. UE before this will cause stall in probe + * and eventually fail the probe. + */ + init_timer(&phba->hw_check); + phba->hw_check.function = beiscsi_hw_health_check; + phba->hw_check.data = (unsigned long)phba; + mod_timer(&phba->hw_check, + jiffies + msecs_to_jiffies(BEISCSI_UE_DETECT_INTERVAL)); beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, "\n\n\n BM_%d : SUCCESS - DRIVER LOADED\n\n\n"); return 0; @@ -5810,7 +5823,8 @@ free_blkenbld: irq_poll_disable(&pbe_eq->iopoll); } free_twq: - beiscsi_clean_port(phba); + hwi_cleanup_port(phba); + beiscsi_cleanup_port(phba); beiscsi_free_mem(phba); free_port: pci_free_consistent(phba->pcidev, @@ -5830,6 +5844,49 @@ disable_pci: return ret; } +static void beiscsi_remove(struct pci_dev *pcidev) +{ + struct beiscsi_hba *phba = NULL; + + phba = pci_get_drvdata(pcidev); + if (!phba) { + dev_err(&pcidev->dev, "beiscsi_remove called with no phba\n"); + return; + } + + /* first stop UE detection before unloading */ + del_timer_sync(&phba->hw_check); + cancel_delayed_work_sync(&phba->recover_port); + cancel_work_sync(&phba->sess_work); + + beiscsi_iface_destroy_default(phba); + iscsi_host_remove(phba->shost); + beiscsi_disable_port(phba, 1); + + /* after cancelling boot_work */ + iscsi_boot_destroy_kset(phba->boot_struct.boot_kset); + + /* free all resources */ + destroy_workqueue(phba->wq); + beiscsi_cleanup_port(phba); + beiscsi_free_mem(phba); + + /* ctrl uninit */ + beiscsi_unmap_pci_function(phba); + pci_free_consistent(phba->pcidev, + phba->ctrl.mbox_mem_alloced.size, + phba->ctrl.mbox_mem_alloced.va, + phba->ctrl.mbox_mem_alloced.dma); + + pci_dev_put(phba->pcidev); + iscsi_host_free(phba->shost); + pci_disable_pcie_error_reporting(pcidev); + pci_set_drvdata(pcidev, NULL); + pci_release_regions(pcidev); + pci_disable_device(pcidev); +} + + static struct pci_error_handlers beiscsi_eeh_handlers = { .error_detected = beiscsi_eeh_err_detected, .slot_reset = beiscsi_eeh_reset, @@ -5846,9 +5903,9 @@ struct iscsi_transport beiscsi_iscsi_transport = { .create_conn = beiscsi_conn_create, .bind_conn = beiscsi_conn_bind, .destroy_conn = iscsi_conn_teardown, - .attr_is_visible = be2iscsi_attr_is_visible, - .set_iface_param = be2iscsi_iface_set_param, - .get_iface_param = be2iscsi_iface_get_param, + .attr_is_visible = beiscsi_attr_is_visible, + .set_iface_param = beiscsi_iface_set_param, + .get_iface_param = beiscsi_iface_get_param, .set_param = beiscsi_set_param, .get_conn_param = iscsi_conn_get_param, .get_session_param = iscsi_session_get_param, @@ -5877,7 +5934,6 @@ static struct pci_driver beiscsi_pci_driver = { .err_handler = &beiscsi_eeh_handlers }; - static int __init beiscsi_module_init(void) { int ret; diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h index 30a4606d9a3b..6376657e45f7 100644 --- a/drivers/scsi/be2iscsi/be_main.h +++ b/drivers/scsi/be2iscsi/be_main.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2015 Emulex + * Copyright (C) 2005 - 2016 Broadcom * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -7,10 +7,10 @@ * as published by the Free Software Foundation. The full GNU General * Public License is included in this distribution in the file called COPYING. * - * Written by: Jayamohan Kallickal (jayamohan.kallickal@avagotech.com) + * Written by: Jayamohan Kallickal (jayamohan.kallickal@broadcom.com) * * Contact Information: - * linux-drivers@avagotech.com + * linux-drivers@broadcom.com * * Emulex * 3333 Susan Street @@ -36,7 +36,7 @@ #include <scsi/scsi_transport_iscsi.h> #define DRV_NAME "be2iscsi" -#define BUILD_STR "11.0.0.0" +#define BUILD_STR "11.2.0.0" #define BE_NAME "Emulex OneConnect" \ "Open-iSCSI Driver version" BUILD_STR #define DRV_DESC BE_NAME " " "Driver" @@ -82,36 +82,12 @@ #define BEISCSI_MAX_FRAGS_INIT 192 #define BE_NUM_MSIX_ENTRIES 1 -#define MPU_EP_CONTROL 0 -#define MPU_EP_SEMAPHORE 0xac -#define BE2_SOFT_RESET 0x5c -#define BE2_PCI_ONLINE0 0xb0 -#define BE2_PCI_ONLINE1 0xb4 -#define BE2_SET_RESET 0x80 -#define BE2_MPU_IRAM_ONLINE 0x00000080 - #define BE_SENSE_INFO_SIZE 258 #define BE_ISCSI_PDU_HEADER_SIZE 64 #define BE_MIN_MEM_SIZE 16384 #define MAX_CMD_SZ 65536 #define IIOC_SCSI_DATA 0x05 /* Write Operation */ -#define INVALID_SESS_HANDLE 0xFFFFFFFF - -/** - * Adapter States - **/ -#define BE_ADAPTER_LINK_UP 0x001 -#define BE_ADAPTER_LINK_DOWN 0x002 -#define BE_ADAPTER_PCI_ERR 0x004 -#define BE_ADAPTER_CHECK_BOOT 0x008 - - -#define BEISCSI_CLEAN_UNLOAD 0x01 -#define BEISCSI_EEH_UNLOAD 0x02 - -#define BE_GET_BOOT_RETRIES 45 -#define BE_GET_BOOT_TO 20 /** * hardware needs the async PDU buffers to be posted in multiples of 8 * So have atleast 8 of them by default @@ -378,7 +354,6 @@ struct beiscsi_hba { struct sgl_handle **eh_sgl_hndl_base; spinlock_t io_sgl_lock; spinlock_t mgmt_sgl_lock; - spinlock_t isr_lock; spinlock_t async_pdu_lock; unsigned int age; struct list_head hba_queue; @@ -390,7 +365,6 @@ struct beiscsi_hba { struct ulp_cid_info *cid_array_info[BEISCSI_ULP_COUNT]; struct iscsi_endpoint **ep_array; struct beiscsi_conn **conn_table; - struct iscsi_boot_kset *boot_kset; struct Scsi_Host *shost; struct iscsi_iface *ipv4_iface; struct iscsi_iface *ipv6_iface; @@ -418,12 +392,33 @@ struct beiscsi_hba { unsigned long ulp_supported; } fw_config; - unsigned int state; + unsigned long state; +#define BEISCSI_HBA_ONLINE 0 +#define BEISCSI_HBA_LINK_UP 1 +#define BEISCSI_HBA_BOOT_FOUND 2 +#define BEISCSI_HBA_BOOT_WORK 3 +#define BEISCSI_HBA_UER_SUPP 4 +#define BEISCSI_HBA_PCI_ERR 5 +#define BEISCSI_HBA_FW_TIMEOUT 6 +#define BEISCSI_HBA_IN_UE 7 +#define BEISCSI_HBA_IN_TPE 8 + +/* error bits */ +#define BEISCSI_HBA_IN_ERR ((1 << BEISCSI_HBA_PCI_ERR) | \ + (1 << BEISCSI_HBA_FW_TIMEOUT) | \ + (1 << BEISCSI_HBA_IN_UE) | \ + (1 << BEISCSI_HBA_IN_TPE)) + u8 optic_state; - int get_boot; - bool fw_timeout; - bool ue_detected; - struct delayed_work beiscsi_hw_check_task; + struct delayed_work eqd_update; + /* update EQ delay timer every 1000ms */ +#define BEISCSI_EQD_UPDATE_INTERVAL 1000 + struct timer_list hw_check; + /* check for UE every 1000ms */ +#define BEISCSI_UE_DETECT_INTERVAL 1000 + u32 ue2rp; + struct delayed_work recover_port; + struct work_struct sess_work; bool mac_addr_set; u8 mac_address[ETH_ALEN]; @@ -435,7 +430,6 @@ struct beiscsi_hba { struct be_ctrl_info ctrl; unsigned int generation; unsigned int interface_handle; - struct mgmt_session_info boot_sess; struct invalidate_command_table inv_tbl[128]; struct be_aic_obj aic_obj[MAX_CPUS]; @@ -444,8 +438,29 @@ struct beiscsi_hba { struct scatterlist *sg, uint32_t num_sg, uint32_t xferlen, uint32_t writedir); + struct boot_struct { + int retry; + unsigned int tag; + unsigned int s_handle; + struct be_dma_mem nonemb_cmd; + enum { + BEISCSI_BOOT_REOPEN_SESS = 1, + BEISCSI_BOOT_GET_SHANDLE, + BEISCSI_BOOT_GET_SINFO, + BEISCSI_BOOT_LOGOUT_SESS, + BEISCSI_BOOT_CREATE_KSET, + } action; + struct mgmt_session_info boot_sess; + struct iscsi_boot_kset *boot_kset; + } boot_struct; + struct work_struct boot_work; }; +#define beiscsi_hba_in_error(phba) ((phba)->state & BEISCSI_HBA_IN_ERR) +#define beiscsi_hba_is_online(phba) \ + (!beiscsi_hba_in_error((phba)) && \ + test_bit(BEISCSI_HBA_ONLINE, &phba->state)) + struct beiscsi_session { struct pci_pool *bhs_pool; }; @@ -508,6 +523,7 @@ struct beiscsi_io_task { struct sgl_handle *psgl_handle; struct beiscsi_conn *conn; struct scsi_cmnd *scsi_cmnd; + int num_sg; struct hwi_wrb_context *pwrb_context; unsigned int cmd_sn; unsigned int flags; @@ -592,80 +608,81 @@ struct amap_beiscsi_offload_params { u8 max_recv_data_segment_length[32]; }; -/* void hwi_complete_drvr_msgs(struct beiscsi_conn *beiscsi_conn, - struct beiscsi_hba *phba, struct sol_cqe *psol);*/ - -struct async_pdu_handle { +struct hd_async_handle { struct list_head link; struct be_bus_address pa; void *pbuffer; - unsigned int consumed; - unsigned char index; - unsigned char is_header; - unsigned short cri; - unsigned long buffer_len; + u32 buffer_len; + u16 index; + u16 cri; + u8 is_header; + u8 is_final; }; -struct hwi_async_entry { - struct { - unsigned char hdr_received; - unsigned char hdr_len; - unsigned short bytes_received; +/** + * This has list of async PDUs that are waiting to be processed. + * Buffers live in this list for a brief duration before they get + * processed and posted back to hardware. + * Note that we don't really need one cri_wait_queue per async_entry. + * We need one cri_wait_queue per CRI. Its easier to manage if this + * is tagged along with the async_entry. + */ +struct hd_async_entry { + struct cri_wait_queue { + unsigned short hdr_len; + unsigned int bytes_received; unsigned int bytes_needed; struct list_head list; - } wait_queue; - - struct list_head header_busy_list; - struct list_head data_busy_list; + } wq; + /* handles posted to FW resides here */ + struct hd_async_handle *header; + struct hd_async_handle *data; }; -struct hwi_async_pdu_context { - struct { - struct be_bus_address pa_base; - void *va_base; - void *ring_base; - struct async_pdu_handle *handle_base; - - unsigned int host_write_ptr; - unsigned int ep_read_ptr; - unsigned int writables; - - unsigned int free_entries; - unsigned int busy_entries; - - struct list_head free_list; - } async_header; +struct hd_async_buf_context { + struct be_bus_address pa_base; + void *va_base; + void *ring_base; + struct hd_async_handle *handle_base; + u16 free_entries; + u32 buffer_size; + /** + * Once iSCSI layer finishes processing an async PDU, the + * handles used for the PDU are added to this list. + * They are posted back to FW in groups of 8. + */ + struct list_head free_list; +}; - struct { - struct be_bus_address pa_base; - void *va_base; - void *ring_base; - struct async_pdu_handle *handle_base; - - unsigned int host_write_ptr; - unsigned int ep_read_ptr; - unsigned int writables; - - unsigned int free_entries; - unsigned int busy_entries; - struct list_head free_list; - } async_data; - - unsigned int buffer_size; - unsigned int num_entries; +/** + * hd_async_context is declared for each ULP supporting iSCSI function. + */ +struct hd_async_context { + struct hd_async_buf_context async_header; + struct hd_async_buf_context async_data; + u16 num_entries; + /** + * When unsol PDU is in, it needs to be chained till all the bytes are + * received and then processing is done. hd_async_entry is created + * based on the cid_count for each ULP. When unsol PDU comes in based + * on the conn_id it needs to be added to the correct async_entry wq. + * Below defined cid_to_async_cri_map is used to reterive the + * async_cri_map for a particular connection. + * + * This array is initialized after beiscsi_create_wrb_rings returns. + * + * - this method takes more memory space, fixed to 2K + * - any support for connections greater than this the array size needs + * to be incremented + */ #define BE_GET_ASYNC_CRI_FROM_CID(cid) (pasync_ctx->cid_to_async_cri_map[cid]) unsigned short cid_to_async_cri_map[BE_MAX_SESSION]; /** - * This is a varying size list! Do not add anything - * after this entry!! + * This is a variable size array. Don`t add anything after this field!! */ - struct hwi_async_entry *async_entry; + struct hd_async_entry *async_entry; }; -#define PDUCQE_CODE_MASK 0x0000003F -#define PDUCQE_DPL_MASK 0xFFFF0000 -#define PDUCQE_INDEX_MASK 0x0000FFFF - struct i_t_dpdu_cqe { u32 dw[4]; } __packed; @@ -845,7 +862,6 @@ struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid, void free_mgmt_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle); -void beiscsi_process_all_cqs(struct work_struct *work); void beiscsi_free_mgmt_task_handles(struct beiscsi_conn *beiscsi_conn, struct iscsi_task *task); @@ -856,11 +872,6 @@ void hwi_ring_cq_db(struct beiscsi_hba *phba, unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq, int budget); void beiscsi_process_mcc_cq(struct beiscsi_hba *phba); -static inline bool beiscsi_error(struct beiscsi_hba *phba) -{ - return phba->ue_detected || phba->fw_timeout; -} - struct pdu_nop_out { u32 dw[12]; }; @@ -1067,11 +1078,18 @@ struct hwi_context_memory { struct be_queue_info be_cq[MAX_CPUS - 1]; struct be_queue_info *be_wrbq; + /** + * Create array of ULP number for below entries as DEFQ + * will be created for both ULP if iSCSI Protocol is + * loaded on both ULP. + */ struct be_queue_info be_def_hdrq[BEISCSI_ULP_COUNT]; struct be_queue_info be_def_dataq[BEISCSI_ULP_COUNT]; - struct hwi_async_pdu_context *pasync_ctx[BEISCSI_ULP_COUNT]; + struct hd_async_context *pasync_ctx[BEISCSI_ULP_COUNT]; }; +void beiscsi_start_boot_work(struct beiscsi_hba *phba, unsigned int s_handle); + /* Logging related definitions */ #define BEISCSI_LOG_INIT 0x0001 /* Initialization events */ #define BEISCSI_LOG_MBOX 0x0002 /* Mailbox Events */ diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c index 83926e221f1e..aebc4ddb3060 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.c +++ b/drivers/scsi/be2iscsi/be_mgmt.c @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2015 Emulex + * Copyright (C) 2005 - 2016 Broadcom * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -7,10 +7,10 @@ * as published by the Free Software Foundation. The full GNU General * Public License is included in this distribution in the file called COPYING. * - * Written by: Jayamohan Kallickal (jayamohan.kallickal@avagotech.com) + * Written by: Jayamohan Kallickal (jayamohan.kallickal@broadcom.com) * * Contact Information: - * linux-drivers@avagotech.com + * linux-drivers@broadcom.com * * Emulex * 3333 Susan Street @@ -24,139 +24,9 @@ #include "be_iscsi.h" #include "be_main.h" -/* UE Status Low CSR */ -static const char * const desc_ue_status_low[] = { - "CEV", - "CTX", - "DBUF", - "ERX", - "Host", - "MPU", - "NDMA", - "PTC ", - "RDMA ", - "RXF ", - "RXIPS ", - "RXULP0 ", - "RXULP1 ", - "RXULP2 ", - "TIM ", - "TPOST ", - "TPRE ", - "TXIPS ", - "TXULP0 ", - "TXULP1 ", - "UC ", - "WDMA ", - "TXULP2 ", - "HOST1 ", - "P0_OB_LINK ", - "P1_OB_LINK ", - "HOST_GPIO ", - "MBOX ", - "AXGMAC0", - "AXGMAC1", - "JTAG", - "MPU_INTPEND" -}; - -/* UE Status High CSR */ -static const char * const desc_ue_status_hi[] = { - "LPCMEMHOST", - "MGMT_MAC", - "PCS0ONLINE", - "MPU_IRAM", - "PCS1ONLINE", - "PCTL0", - "PCTL1", - "PMEM", - "RR", - "TXPB", - "RXPP", - "XAUI", - "TXP", - "ARM", - "IPC", - "HOST2", - "HOST3", - "HOST4", - "HOST5", - "HOST6", - "HOST7", - "HOST8", - "HOST9", - "NETC", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown" -}; - -/* - * beiscsi_ue_detec()- Detect Unrecoverable Error on adapter - * @phba: Driver priv structure - * - * Read registers linked to UE and check for the UE status - **/ -void beiscsi_ue_detect(struct beiscsi_hba *phba) -{ - uint32_t ue_hi = 0, ue_lo = 0; - uint32_t ue_mask_hi = 0, ue_mask_lo = 0; - uint8_t i = 0; - - if (phba->ue_detected) - return; - - pci_read_config_dword(phba->pcidev, - PCICFG_UE_STATUS_LOW, &ue_lo); - pci_read_config_dword(phba->pcidev, - PCICFG_UE_STATUS_MASK_LOW, - &ue_mask_lo); - pci_read_config_dword(phba->pcidev, - PCICFG_UE_STATUS_HIGH, - &ue_hi); - pci_read_config_dword(phba->pcidev, - PCICFG_UE_STATUS_MASK_HI, - &ue_mask_hi); - - ue_lo = (ue_lo & ~ue_mask_lo); - ue_hi = (ue_hi & ~ue_mask_hi); - - - if (ue_lo || ue_hi) { - phba->ue_detected = true; - beiscsi_log(phba, KERN_ERR, - BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX, - "BG_%d : Error detected on the adapter\n"); - } - - if (ue_lo) { - for (i = 0; ue_lo; ue_lo >>= 1, i++) { - if (ue_lo & 1) - beiscsi_log(phba, KERN_ERR, - BEISCSI_LOG_CONFIG, - "BG_%d : UE_LOW %s bit set\n", - desc_ue_status_low[i]); - } - } - - if (ue_hi) { - for (i = 0; ue_hi; ue_hi >>= 1, i++) { - if (ue_hi & 1) - beiscsi_log(phba, KERN_ERR, - BEISCSI_LOG_CONFIG, - "BG_%d : UE_HIGH %s bit set\n", - desc_ue_status_hi[i]); - } - } -} - -int be_cmd_modify_eq_delay(struct beiscsi_hba *phba, - struct be_set_eqd *set_eqd, int num) +int beiscsi_modify_eq_delay(struct beiscsi_hba *phba, + struct be_set_eqd *set_eqd, + int num) { struct be_ctrl_info *ctrl = &phba->ctrl; struct be_mcc_wrb *wrb; @@ -174,7 +44,7 @@ int be_cmd_modify_eq_delay(struct beiscsi_hba *phba, req = embedded_payload(wrb); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, - OPCODE_COMMON_MODIFY_EQ_DELAY, sizeof(*req)); + OPCODE_COMMON_MODIFY_EQ_DELAY, sizeof(*req)); req->num_eq = cpu_to_le32(num); for (i = 0; i < num; i++) { @@ -184,386 +54,13 @@ int be_cmd_modify_eq_delay(struct beiscsi_hba *phba, cpu_to_le32(set_eqd[i].delay_multiplier); } + /* ignore the completion of this mbox command */ + set_bit(MCC_TAG_STATE_IGNORE, &ctrl->ptag_state[tag].tag_state); be_mcc_notify(phba, tag); mutex_unlock(&ctrl->mbox_lock); return tag; } -/** - * mgmt_reopen_session()- Reopen a session based on reopen_type - * @phba: Device priv structure instance - * @reopen_type: Type of reopen_session FW should do. - * @sess_handle: Session Handle of the session to be re-opened - * - * return - * the TAG used for MBOX Command - * - **/ -unsigned int mgmt_reopen_session(struct beiscsi_hba *phba, - unsigned int reopen_type, - unsigned int sess_handle) -{ - struct be_ctrl_info *ctrl = &phba->ctrl; - struct be_mcc_wrb *wrb; - struct be_cmd_reopen_session_req *req; - unsigned int tag; - - beiscsi_log(phba, KERN_INFO, - BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX, - "BG_%d : In bescsi_get_boot_target\n"); - - mutex_lock(&ctrl->mbox_lock); - wrb = alloc_mcc_wrb(phba, &tag); - if (!wrb) { - mutex_unlock(&ctrl->mbox_lock); - return 0; - } - - req = embedded_payload(wrb); - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); - be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI, - OPCODE_ISCSI_INI_DRIVER_REOPEN_ALL_SESSIONS, - sizeof(struct be_cmd_reopen_session_resp)); - - /* set the reopen_type,sess_handle */ - req->reopen_type = reopen_type; - req->session_handle = sess_handle; - - be_mcc_notify(phba, tag); - mutex_unlock(&ctrl->mbox_lock); - return tag; -} - -unsigned int mgmt_get_boot_target(struct beiscsi_hba *phba) -{ - struct be_ctrl_info *ctrl = &phba->ctrl; - struct be_mcc_wrb *wrb; - struct be_cmd_get_boot_target_req *req; - unsigned int tag; - - beiscsi_log(phba, KERN_INFO, - BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX, - "BG_%d : In bescsi_get_boot_target\n"); - - mutex_lock(&ctrl->mbox_lock); - wrb = alloc_mcc_wrb(phba, &tag); - if (!wrb) { - mutex_unlock(&ctrl->mbox_lock); - return 0; - } - - req = embedded_payload(wrb); - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); - be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI, - OPCODE_ISCSI_INI_BOOT_GET_BOOT_TARGET, - sizeof(struct be_cmd_get_boot_target_resp)); - - be_mcc_notify(phba, tag); - mutex_unlock(&ctrl->mbox_lock); - return tag; -} - -unsigned int mgmt_get_session_info(struct beiscsi_hba *phba, - u32 boot_session_handle, - struct be_dma_mem *nonemb_cmd) -{ - struct be_ctrl_info *ctrl = &phba->ctrl; - struct be_mcc_wrb *wrb; - unsigned int tag; - struct be_cmd_get_session_req *req; - struct be_cmd_get_session_resp *resp; - struct be_sge *sge; - - beiscsi_log(phba, KERN_INFO, - BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX, - "BG_%d : In beiscsi_get_session_info\n"); - - mutex_lock(&ctrl->mbox_lock); - wrb = alloc_mcc_wrb(phba, &tag); - if (!wrb) { - mutex_unlock(&ctrl->mbox_lock); - return 0; - } - - nonemb_cmd->size = sizeof(*resp); - req = nonemb_cmd->va; - memset(req, 0, sizeof(*req)); - sge = nonembedded_sgl(wrb); - be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1); - be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI, - OPCODE_ISCSI_INI_SESSION_GET_A_SESSION, - sizeof(*resp)); - req->session_handle = boot_session_handle; - sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma)); - sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF); - sge->len = cpu_to_le32(nonemb_cmd->size); - - be_mcc_notify(phba, tag); - mutex_unlock(&ctrl->mbox_lock); - return tag; -} - -/** - * mgmt_get_port_name()- Get port name for the function - * @ctrl: ptr to Ctrl Info - * @phba: ptr to the dev priv structure - * - * Get the alphanumeric character for port - * - **/ -int mgmt_get_port_name(struct be_ctrl_info *ctrl, - struct beiscsi_hba *phba) -{ - int ret = 0; - struct be_mcc_wrb *wrb; - struct be_cmd_get_port_name *ioctl; - - mutex_lock(&ctrl->mbox_lock); - wrb = wrb_from_mbox(&ctrl->mbox_mem); - memset(wrb, 0, sizeof(*wrb)); - ioctl = embedded_payload(wrb); - - be_wrb_hdr_prepare(wrb, sizeof(*ioctl), true, 0); - be_cmd_hdr_prepare(&ioctl->h.req_hdr, CMD_SUBSYSTEM_COMMON, - OPCODE_COMMON_GET_PORT_NAME, - EMBED_MBX_MAX_PAYLOAD_SIZE); - ret = be_mbox_notify(ctrl); - phba->port_name = 0; - if (!ret) { - phba->port_name = ioctl->p.resp.port_names >> - (phba->fw_config.phys_port * 8) & 0xff; - } else { - beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, - "BG_%d : GET_PORT_NAME ret 0x%x status 0x%x\n", - ret, ioctl->h.resp_hdr.status); - } - - if (phba->port_name == 0) - phba->port_name = '?'; - - mutex_unlock(&ctrl->mbox_lock); - return ret; -} - -/** - * mgmt_get_fw_config()- Get the FW config for the function - * @ctrl: ptr to Ctrl Info - * @phba: ptr to the dev priv structure - * - * Get the FW config and resources available for the function. - * The resources are created based on the count received here. - * - * return - * Success: 0 - * Failure: Non-Zero Value - **/ -int mgmt_get_fw_config(struct be_ctrl_info *ctrl, - struct beiscsi_hba *phba) -{ - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); - struct be_fw_cfg *pfw_cfg = embedded_payload(wrb); - uint32_t cid_count, icd_count; - int status = -EINVAL; - uint8_t ulp_num = 0; - - mutex_lock(&ctrl->mbox_lock); - memset(wrb, 0, sizeof(*wrb)); - be_wrb_hdr_prepare(wrb, sizeof(*pfw_cfg), true, 0); - - be_cmd_hdr_prepare(&pfw_cfg->hdr, CMD_SUBSYSTEM_COMMON, - OPCODE_COMMON_QUERY_FIRMWARE_CONFIG, - EMBED_MBX_MAX_PAYLOAD_SIZE); - - if (be_mbox_notify(ctrl)) { - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, - "BG_%d : Failed in mgmt_get_fw_config\n"); - goto fail_init; - } - - /* FW response formats depend on port id */ - phba->fw_config.phys_port = pfw_cfg->phys_port; - if (phba->fw_config.phys_port >= BEISCSI_PHYS_PORT_MAX) { - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, - "BG_%d : invalid physical port id %d\n", - phba->fw_config.phys_port); - goto fail_init; - } - - /* populate and check FW config against min and max values */ - if (!is_chip_be2_be3r(phba)) { - phba->fw_config.eqid_count = pfw_cfg->eqid_count; - phba->fw_config.cqid_count = pfw_cfg->cqid_count; - if (phba->fw_config.eqid_count == 0 || - phba->fw_config.eqid_count > 2048) { - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, - "BG_%d : invalid EQ count %d\n", - phba->fw_config.eqid_count); - goto fail_init; - } - if (phba->fw_config.cqid_count == 0 || - phba->fw_config.cqid_count > 4096) { - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, - "BG_%d : invalid CQ count %d\n", - phba->fw_config.cqid_count); - goto fail_init; - } - beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, - "BG_%d : EQ_Count : %d CQ_Count : %d\n", - phba->fw_config.eqid_count, - phba->fw_config.cqid_count); - } - - /** - * Check on which all ULP iSCSI Protocol is loaded. - * Set the Bit for those ULP. This set flag is used - * at all places in the code to check on which ULP - * iSCSi Protocol is loaded - **/ - for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) { - if (pfw_cfg->ulp[ulp_num].ulp_mode & - BEISCSI_ULP_ISCSI_INI_MODE) { - set_bit(ulp_num, &phba->fw_config.ulp_supported); - - /* Get the CID, ICD and Chain count for each ULP */ - phba->fw_config.iscsi_cid_start[ulp_num] = - pfw_cfg->ulp[ulp_num].sq_base; - phba->fw_config.iscsi_cid_count[ulp_num] = - pfw_cfg->ulp[ulp_num].sq_count; - - phba->fw_config.iscsi_icd_start[ulp_num] = - pfw_cfg->ulp[ulp_num].icd_base; - phba->fw_config.iscsi_icd_count[ulp_num] = - pfw_cfg->ulp[ulp_num].icd_count; - - phba->fw_config.iscsi_chain_start[ulp_num] = - pfw_cfg->chain_icd[ulp_num].chain_base; - phba->fw_config.iscsi_chain_count[ulp_num] = - pfw_cfg->chain_icd[ulp_num].chain_count; - - beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, - "BG_%d : Function loaded on ULP : %d\n" - "\tiscsi_cid_count : %d\n" - "\tiscsi_cid_start : %d\n" - "\t iscsi_icd_count : %d\n" - "\t iscsi_icd_start : %d\n", - ulp_num, - phba->fw_config. - iscsi_cid_count[ulp_num], - phba->fw_config. - iscsi_cid_start[ulp_num], - phba->fw_config. - iscsi_icd_count[ulp_num], - phba->fw_config. - iscsi_icd_start[ulp_num]); - } - } - - if (phba->fw_config.ulp_supported == 0) { - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, - "BG_%d : iSCSI initiator mode not set: ULP0 %x ULP1 %x\n", - pfw_cfg->ulp[BEISCSI_ULP0].ulp_mode, - pfw_cfg->ulp[BEISCSI_ULP1].ulp_mode); - goto fail_init; - } - - /** - * ICD is shared among ULPs. Use icd_count of any one loaded ULP - **/ - for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) - if (test_bit(ulp_num, &phba->fw_config.ulp_supported)) - break; - icd_count = phba->fw_config.iscsi_icd_count[ulp_num]; - if (icd_count == 0 || icd_count > 65536) { - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, - "BG_%d: invalid ICD count %d\n", icd_count); - goto fail_init; - } - - cid_count = BEISCSI_GET_CID_COUNT(phba, BEISCSI_ULP0) + - BEISCSI_GET_CID_COUNT(phba, BEISCSI_ULP1); - if (cid_count == 0 || cid_count > 4096) { - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, - "BG_%d: invalid CID count %d\n", cid_count); - goto fail_init; - } - - /** - * Check FW is dual ULP aware i.e. can handle either - * of the protocols. - */ - phba->fw_config.dual_ulp_aware = (pfw_cfg->function_mode & - BEISCSI_FUNC_DUA_MODE); - - beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, - "BG_%d : DUA Mode : 0x%x\n", - phba->fw_config.dual_ulp_aware); - - /* all set, continue using this FW config */ - status = 0; -fail_init: - mutex_unlock(&ctrl->mbox_lock); - return status; -} - -int mgmt_check_supported_fw(struct be_ctrl_info *ctrl, - struct beiscsi_hba *phba) -{ - struct be_dma_mem nonemb_cmd; - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); - struct be_mgmt_controller_attributes *req; - struct be_sge *sge = nonembedded_sgl(wrb); - int status = 0; - - nonemb_cmd.va = pci_alloc_consistent(ctrl->pdev, - sizeof(struct be_mgmt_controller_attributes), - &nonemb_cmd.dma); - if (nonemb_cmd.va == NULL) { - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, - "BG_%d : Failed to allocate memory for " - "mgmt_check_supported_fw\n"); - return -ENOMEM; - } - nonemb_cmd.size = sizeof(struct be_mgmt_controller_attributes); - req = nonemb_cmd.va; - memset(req, 0, sizeof(*req)); - mutex_lock(&ctrl->mbox_lock); - memset(wrb, 0, sizeof(*wrb)); - be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1); - be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, - OPCODE_COMMON_GET_CNTL_ATTRIBUTES, sizeof(*req)); - sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd.dma)); - sge->pa_lo = cpu_to_le32(nonemb_cmd.dma & 0xFFFFFFFF); - sge->len = cpu_to_le32(nonemb_cmd.size); - status = be_mbox_notify(ctrl); - if (!status) { - struct be_mgmt_controller_attributes_resp *resp = nonemb_cmd.va; - beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, - "BG_%d : Firmware Version of CMD : %s\n" - "Firmware Version is : %s\n" - "Developer Build, not performing version check...\n", - resp->params.hba_attribs - .flashrom_version_string, - resp->params.hba_attribs. - firmware_version_string); - - phba->fw_config.iscsi_features = - resp->params.hba_attribs.iscsi_features; - beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, - "BM_%d : phba->fw_config.iscsi_features = %d\n", - phba->fw_config.iscsi_features); - memcpy(phba->fw_ver_str, resp->params.hba_attribs. - firmware_version_string, BEISCSI_VER_STRLEN); - } else - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, - "BG_%d : Failed in mgmt_check_supported_fw\n"); - mutex_unlock(&ctrl->mbox_lock); - if (nonemb_cmd.va) - pci_free_consistent(ctrl->pdev, nonemb_cmd.size, - nonemb_cmd.va, nonemb_cmd.dma); - - return status; -} - unsigned int mgmt_vendor_specific_fw_cmd(struct be_ctrl_info *ctrl, struct beiscsi_hba *phba, struct bsg_job *job, @@ -609,7 +106,7 @@ unsigned int mgmt_vendor_specific_fw_cmd(struct be_ctrl_info *ctrl, bsg_req->rqst_data.h_vendor.vendor_cmd[0]); mutex_unlock(&ctrl->mbox_lock); - return -ENOSYS; + return -EPERM; } wrb = alloc_mcc_wrb(phba, &tag); @@ -631,48 +128,6 @@ unsigned int mgmt_vendor_specific_fw_cmd(struct be_ctrl_info *ctrl, return tag; } -/** - * mgmt_epfw_cleanup()- Inform FW to cleanup data structures. - * @phba: pointer to dev priv structure - * @ulp_num: ULP number. - * - * return - * Success: 0 - * Failure: Non-Zero Value - **/ -int mgmt_epfw_cleanup(struct beiscsi_hba *phba, unsigned short ulp_num) -{ - struct be_ctrl_info *ctrl = &phba->ctrl; - struct be_mcc_wrb *wrb; - struct iscsi_cleanup_req *req; - unsigned int tag; - int status; - - mutex_lock(&ctrl->mbox_lock); - wrb = alloc_mcc_wrb(phba, &tag); - if (!wrb) { - mutex_unlock(&ctrl->mbox_lock); - return -EBUSY; - } - - req = embedded_payload(wrb); - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); - be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI, - OPCODE_COMMON_ISCSI_CLEANUP, sizeof(*req)); - - req->chute = (1 << ulp_num); - req->hdr_ring_id = cpu_to_le16(HWI_GET_DEF_HDRQ_ID(phba, ulp_num)); - req->data_ring_id = cpu_to_le16(HWI_GET_DEF_BUFQ_ID(phba, ulp_num)); - - be_mcc_notify(phba, tag); - status = be_mcc_compl_poll(phba, tag); - if (status) - beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_INIT, - "BG_%d : mgmt_epfw_cleanup , FAILED\n"); - mutex_unlock(&ctrl->mbox_lock); - return status; -} - unsigned int mgmt_invalidate_icds(struct beiscsi_hba *phba, struct invalidate_command_table *inv_tbl, unsigned int num_invalidate, unsigned int cid, @@ -844,7 +299,7 @@ int mgmt_open_connection(struct beiscsi_hba *phba, nonemb_cmd->size); if (dst_addr->sa_family == PF_INET) { __be32 s_addr = daddr_in->sin_addr.s_addr; - req->ip_address.ip_type = BE2_IPV4; + req->ip_address.ip_type = BEISCSI_IP_TYPE_V4; req->ip_address.addr[0] = s_addr & 0x000000ff; req->ip_address.addr[1] = (s_addr & 0x0000ff00) >> 8; req->ip_address.addr[2] = (s_addr & 0x00ff0000) >> 16; @@ -852,17 +307,17 @@ int mgmt_open_connection(struct beiscsi_hba *phba, req->tcp_port = ntohs(daddr_in->sin_port); beiscsi_ep->dst_addr = daddr_in->sin_addr.s_addr; beiscsi_ep->dst_tcpport = ntohs(daddr_in->sin_port); - beiscsi_ep->ip_type = BE2_IPV4; + beiscsi_ep->ip_type = BEISCSI_IP_TYPE_V4; } else { /* else its PF_INET6 family */ - req->ip_address.ip_type = BE2_IPV6; + req->ip_address.ip_type = BEISCSI_IP_TYPE_V6; memcpy(&req->ip_address.addr, &daddr_in6->sin6_addr.in6_u.u6_addr8, 16); req->tcp_port = ntohs(daddr_in6->sin6_port); beiscsi_ep->dst_tcpport = ntohs(daddr_in6->sin6_port); memcpy(&beiscsi_ep->dst6_addr, &daddr_in6->sin6_addr.in6_u.u6_addr8, 16); - beiscsi_ep->ip_type = BE2_IPV6; + beiscsi_ep->ip_type = BEISCSI_IP_TYPE_V6; } req->cid = cid; i = phba->nxt_cqid++; @@ -883,7 +338,7 @@ int mgmt_open_connection(struct beiscsi_hba *phba, if (!is_chip_be2_be3r(phba)) { req->hdr.version = MBX_CMD_VER1; - req->tcp_window_size = 0; + req->tcp_window_size = 0x8000; req->tcp_window_scale_count = 2; } @@ -892,44 +347,6 @@ int mgmt_open_connection(struct beiscsi_hba *phba, return tag; } -unsigned int mgmt_get_all_if_id(struct beiscsi_hba *phba) -{ - struct be_ctrl_info *ctrl = &phba->ctrl; - struct be_mcc_wrb *wrb; - struct be_cmd_get_all_if_id_req *req; - struct be_cmd_get_all_if_id_req *pbe_allid; - unsigned int tag; - int status = 0; - - if (mutex_lock_interruptible(&ctrl->mbox_lock)) - return -EINTR; - wrb = alloc_mcc_wrb(phba, &tag); - if (!wrb) { - mutex_unlock(&ctrl->mbox_lock); - return -ENOMEM; - } - - req = embedded_payload(wrb); - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); - be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI, - OPCODE_COMMON_ISCSI_NTWK_GET_ALL_IF_ID, - sizeof(*req)); - be_mcc_notify(phba, tag); - mutex_unlock(&ctrl->mbox_lock); - - status = beiscsi_mccq_compl_wait(phba, tag, &wrb, NULL); - if (status) { - beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG, - "BG_%d : Failed in mgmt_get_all_if_id\n"); - return -EBUSY; - } - - pbe_allid = embedded_payload(wrb); - phba->interface_handle = pbe_allid->if_hndl_list[0]; - - return status; -} - /* * mgmt_exec_nonemb_cmd()- Execute Non Embedded MBX Cmd * @phba: Driver priv structure @@ -1001,72 +418,68 @@ static int mgmt_alloc_cmd_data(struct beiscsi_hba *phba, struct be_dma_mem *cmd, } cmd->size = size; be_cmd_hdr_prepare(cmd->va, CMD_SUBSYSTEM_ISCSI, iscsi_cmd, size); + beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, + "BG_%d : subsystem iSCSI cmd %d size %d\n", + iscsi_cmd, size); return 0; } -static int -mgmt_static_ip_modify(struct beiscsi_hba *phba, - struct be_cmd_get_if_info_resp *if_info, - struct iscsi_iface_param_info *ip_param, - struct iscsi_iface_param_info *subnet_param, - uint32_t ip_action) +unsigned int beiscsi_if_get_handle(struct beiscsi_hba *phba) { - struct be_cmd_set_ip_addr_req *req; - struct be_dma_mem nonemb_cmd; - uint32_t ip_type; - int rc; + struct be_ctrl_info *ctrl = &phba->ctrl; + struct be_mcc_wrb *wrb; + struct be_cmd_get_all_if_id_req *req; + struct be_cmd_get_all_if_id_req *pbe_allid; + unsigned int tag; + int status = 0; - rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd, - OPCODE_COMMON_ISCSI_NTWK_MODIFY_IP_ADDR, - sizeof(*req)); - if (rc) - return rc; + if (mutex_lock_interruptible(&ctrl->mbox_lock)) + return -EINTR; + wrb = alloc_mcc_wrb(phba, &tag); + if (!wrb) { + mutex_unlock(&ctrl->mbox_lock); + return -ENOMEM; + } - ip_type = (ip_param->param == ISCSI_NET_PARAM_IPV6_ADDR) ? - BE2_IPV6 : BE2_IPV4 ; + req = embedded_payload(wrb); + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI, + OPCODE_COMMON_ISCSI_NTWK_GET_ALL_IF_ID, + sizeof(*req)); + be_mcc_notify(phba, tag); + mutex_unlock(&ctrl->mbox_lock); - req = nonemb_cmd.va; - req->ip_params.record_entry_count = 1; - req->ip_params.ip_record.action = ip_action; - req->ip_params.ip_record.interface_hndl = - phba->interface_handle; - req->ip_params.ip_record.ip_addr.size_of_structure = - sizeof(struct be_ip_addr_subnet_format); - req->ip_params.ip_record.ip_addr.ip_type = ip_type; + status = beiscsi_mccq_compl_wait(phba, tag, &wrb, NULL); + if (status) { + beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG, + "BG_%d : %s failed: %d\n", __func__, status); + return -EBUSY; + } - if (ip_action == IP_ACTION_ADD) { - memcpy(req->ip_params.ip_record.ip_addr.addr, ip_param->value, - sizeof(req->ip_params.ip_record.ip_addr.addr)); + pbe_allid = embedded_payload(wrb); + /* we now support only one interface per function */ + phba->interface_handle = pbe_allid->if_hndl_list[0]; - if (subnet_param) - memcpy(req->ip_params.ip_record.ip_addr.subnet_mask, - subnet_param->value, - sizeof(req->ip_params.ip_record.ip_addr.subnet_mask)); - } else { - memcpy(req->ip_params.ip_record.ip_addr.addr, - if_info->ip_addr.addr, - sizeof(req->ip_params.ip_record.ip_addr.addr)); + return status; +} - memcpy(req->ip_params.ip_record.ip_addr.subnet_mask, - if_info->ip_addr.subnet_mask, - sizeof(req->ip_params.ip_record.ip_addr.subnet_mask)); - } +static inline bool beiscsi_if_zero_ip(u8 *ip, u32 ip_type) +{ + u32 len; - rc = mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, NULL, 0); - if (rc < 0) - beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG, - "BG_%d : Failed to Modify existing IP Address\n"); - return rc; + len = (ip_type < BEISCSI_IP_TYPE_V6) ? IP_V4_LEN : IP_V6_LEN; + while (len && !ip[len - 1]) + len--; + return (len == 0); } -static int mgmt_modify_gateway(struct beiscsi_hba *phba, uint8_t *gt_addr, - uint32_t gtway_action, uint32_t param_len) +static int beiscsi_if_mod_gw(struct beiscsi_hba *phba, + u32 action, u32 ip_type, u8 *gw) { struct be_cmd_set_def_gateway_req *req; struct be_dma_mem nonemb_cmd; int rt_val; - rt_val = mgmt_alloc_cmd_data(phba, &nonemb_cmd, OPCODE_COMMON_ISCSI_NTWK_MODIFY_DEFAULT_GATEWAY, sizeof(*req)); @@ -1074,200 +487,300 @@ static int mgmt_modify_gateway(struct beiscsi_hba *phba, uint8_t *gt_addr, return rt_val; req = nonemb_cmd.va; - req->action = gtway_action; - req->ip_addr.ip_type = BE2_IPV4; + req->action = action; + req->ip_addr.ip_type = ip_type; + memcpy(req->ip_addr.addr, gw, + (ip_type < BEISCSI_IP_TYPE_V6) ? IP_V4_LEN : IP_V6_LEN); + return mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, NULL, 0); +} - memcpy(req->ip_addr.addr, gt_addr, sizeof(req->ip_addr.addr)); +int beiscsi_if_set_gw(struct beiscsi_hba *phba, u32 ip_type, u8 *gw) +{ + struct be_cmd_get_def_gateway_resp gw_resp; + int rt_val; - return mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, NULL, 0); + memset(&gw_resp, 0, sizeof(gw_resp)); + rt_val = beiscsi_if_get_gw(phba, ip_type, &gw_resp); + if (rt_val) { + beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG, + "BG_%d : Failed to Get Gateway Addr\n"); + return rt_val; + } + + if (!beiscsi_if_zero_ip(gw_resp.ip_addr.addr, ip_type)) { + rt_val = beiscsi_if_mod_gw(phba, IP_ACTION_DEL, ip_type, + gw_resp.ip_addr.addr); + if (rt_val) { + beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG, + "BG_%d : Failed to clear Gateway Addr Set\n"); + return rt_val; + } + } + + rt_val = beiscsi_if_mod_gw(phba, IP_ACTION_ADD, ip_type, gw); + if (rt_val) + beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG, + "BG_%d : Failed to Set Gateway Addr\n"); + + return rt_val; } -int mgmt_set_ip(struct beiscsi_hba *phba, - struct iscsi_iface_param_info *ip_param, - struct iscsi_iface_param_info *subnet_param, - uint32_t boot_proto) +int beiscsi_if_get_gw(struct beiscsi_hba *phba, u32 ip_type, + struct be_cmd_get_def_gateway_resp *resp) { - struct be_cmd_get_def_gateway_resp gtway_addr_set; - struct be_cmd_get_if_info_resp *if_info; - struct be_cmd_set_dhcp_req *dhcpreq; - struct be_cmd_rel_dhcp_req *reldhcp; + struct be_cmd_get_def_gateway_req *req; struct be_dma_mem nonemb_cmd; - uint8_t *gtway_addr; - uint32_t ip_type; int rc; - rc = mgmt_get_all_if_id(phba); + rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd, + OPCODE_COMMON_ISCSI_NTWK_GET_DEFAULT_GATEWAY, + sizeof(*resp)); if (rc) return rc; - ip_type = (ip_param->param == ISCSI_NET_PARAM_IPV6_ADDR) ? - BE2_IPV6 : BE2_IPV4 ; + req = nonemb_cmd.va; + req->ip_type = ip_type; + + return mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, resp, + sizeof(*resp)); +} + +static int +beiscsi_if_clr_ip(struct beiscsi_hba *phba, + struct be_cmd_get_if_info_resp *if_info) +{ + struct be_cmd_set_ip_addr_req *req; + struct be_dma_mem nonemb_cmd; + int rc; - rc = mgmt_get_if_info(phba, ip_type, &if_info); + rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd, + OPCODE_COMMON_ISCSI_NTWK_MODIFY_IP_ADDR, + sizeof(*req)); if (rc) return rc; - if (boot_proto == ISCSI_BOOTPROTO_DHCP) { - if (if_info->dhcp_state) { - beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG, - "BG_%d : DHCP Already Enabled\n"); - goto exit; - } - /* The ip_param->len is 1 in DHCP case. Setting - proper IP len as this it is used while - freeing the Static IP. - */ - ip_param->len = (ip_param->param == ISCSI_NET_PARAM_IPV6_ADDR) ? - IP_V6_LEN : IP_V4_LEN; - - } else { - if (if_info->dhcp_state) { + req = nonemb_cmd.va; + req->ip_params.record_entry_count = 1; + req->ip_params.ip_record.action = IP_ACTION_DEL; + req->ip_params.ip_record.interface_hndl = + phba->interface_handle; + req->ip_params.ip_record.ip_addr.size_of_structure = + sizeof(struct be_ip_addr_subnet_format); + req->ip_params.ip_record.ip_addr.ip_type = if_info->ip_addr.ip_type; + memcpy(req->ip_params.ip_record.ip_addr.addr, + if_info->ip_addr.addr, + sizeof(if_info->ip_addr.addr)); + memcpy(req->ip_params.ip_record.ip_addr.subnet_mask, + if_info->ip_addr.subnet_mask, + sizeof(if_info->ip_addr.subnet_mask)); + rc = mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, NULL, 0); + if (rc < 0 || req->ip_params.ip_record.status) { + beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, + "BG_%d : failed to clear IP: rc %d status %d\n", + rc, req->ip_params.ip_record.status); + } + return rc; +} - memset(if_info, 0, sizeof(*if_info)); - rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd, - OPCODE_COMMON_ISCSI_NTWK_REL_STATELESS_IP_ADDR, - sizeof(*reldhcp)); +static int +beiscsi_if_set_ip(struct beiscsi_hba *phba, u8 *ip, + u8 *subnet, u32 ip_type) +{ + struct be_cmd_set_ip_addr_req *req; + struct be_dma_mem nonemb_cmd; + uint32_t ip_len; + int rc; - if (rc) - goto exit; + rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd, + OPCODE_COMMON_ISCSI_NTWK_MODIFY_IP_ADDR, + sizeof(*req)); + if (rc) + return rc; - reldhcp = nonemb_cmd.va; - reldhcp->interface_hndl = phba->interface_handle; - reldhcp->ip_type = ip_type; + req = nonemb_cmd.va; + req->ip_params.record_entry_count = 1; + req->ip_params.ip_record.action = IP_ACTION_ADD; + req->ip_params.ip_record.interface_hndl = + phba->interface_handle; + req->ip_params.ip_record.ip_addr.size_of_structure = + sizeof(struct be_ip_addr_subnet_format); + req->ip_params.ip_record.ip_addr.ip_type = ip_type; + ip_len = (ip_type < BEISCSI_IP_TYPE_V6) ? IP_V4_LEN : IP_V6_LEN; + memcpy(req->ip_params.ip_record.ip_addr.addr, ip, ip_len); + if (subnet) + memcpy(req->ip_params.ip_record.ip_addr.subnet_mask, + subnet, ip_len); - rc = mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, NULL, 0); - if (rc < 0) { - beiscsi_log(phba, KERN_WARNING, - BEISCSI_LOG_CONFIG, - "BG_%d : Failed to Delete existing dhcp\n"); - goto exit; - } - } + rc = mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, NULL, 0); + /** + * In some cases, host needs to look into individual record status + * even though FW reported success for that IOCTL. + */ + if (rc < 0 || req->ip_params.ip_record.status) { + __beiscsi_log(phba, KERN_ERR, + "BG_%d : failed to set IP: rc %d status %d\n", + rc, req->ip_params.ip_record.status); + if (req->ip_params.ip_record.status) + rc = -EINVAL; } + return rc; +} - /* Delete the Static IP Set */ - if (if_info->ip_addr.addr[0]) { - rc = mgmt_static_ip_modify(phba, if_info, ip_param, NULL, - IP_ACTION_DEL); +int beiscsi_if_en_static(struct beiscsi_hba *phba, u32 ip_type, + u8 *ip, u8 *subnet) +{ + struct be_cmd_get_if_info_resp *if_info; + struct be_cmd_rel_dhcp_req *reldhcp; + struct be_dma_mem nonemb_cmd; + int rc; + + rc = beiscsi_if_get_info(phba, ip_type, &if_info); + if (rc) + return rc; + + if (if_info->dhcp_state) { + rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd, + OPCODE_COMMON_ISCSI_NTWK_REL_STATELESS_IP_ADDR, + sizeof(*reldhcp)); if (rc) goto exit; - } - /* Delete the Gateway settings if mode change is to DHCP */ - if (boot_proto == ISCSI_BOOTPROTO_DHCP) { - memset(>way_addr_set, 0, sizeof(gtway_addr_set)); - rc = mgmt_get_gateway(phba, BE2_IPV4, >way_addr_set); - if (rc) { + reldhcp = nonemb_cmd.va; + reldhcp->interface_hndl = phba->interface_handle; + reldhcp->ip_type = ip_type; + rc = mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, NULL, 0); + if (rc < 0) { beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG, - "BG_%d : Failed to Get Gateway Addr\n"); + "BG_%d : failed to release existing DHCP: %d\n", + rc); goto exit; } - - if (gtway_addr_set.ip_addr.addr[0]) { - gtway_addr = (uint8_t *)>way_addr_set.ip_addr.addr; - rc = mgmt_modify_gateway(phba, gtway_addr, - IP_ACTION_DEL, IP_V4_LEN); - - if (rc) { - beiscsi_log(phba, KERN_WARNING, - BEISCSI_LOG_CONFIG, - "BG_%d : Failed to clear Gateway Addr Set\n"); - goto exit; - } - } } - /* Set Adapter to DHCP/Static Mode */ - if (boot_proto == ISCSI_BOOTPROTO_DHCP) { - rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd, - OPCODE_COMMON_ISCSI_NTWK_CONFIG_STATELESS_IP_ADDR, - sizeof(*dhcpreq)); + /* first delete any IP set */ + if (!beiscsi_if_zero_ip(if_info->ip_addr.addr, ip_type)) { + rc = beiscsi_if_clr_ip(phba, if_info); if (rc) goto exit; - - dhcpreq = nonemb_cmd.va; - dhcpreq->flags = BLOCKING; - dhcpreq->retry_count = 1; - dhcpreq->interface_hndl = phba->interface_handle; - dhcpreq->ip_type = BE2_DHCP_V4; - - rc = mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, NULL, 0); - } else { - rc = mgmt_static_ip_modify(phba, if_info, ip_param, - subnet_param, IP_ACTION_ADD); } + /* if ip == NULL then this is called just to release DHCP IP */ + if (ip) + rc = beiscsi_if_set_ip(phba, ip, subnet, ip_type); exit: kfree(if_info); return rc; } -int mgmt_set_gateway(struct beiscsi_hba *phba, - struct iscsi_iface_param_info *gateway_param) +int beiscsi_if_en_dhcp(struct beiscsi_hba *phba, u32 ip_type) { - struct be_cmd_get_def_gateway_resp gtway_addr_set; - uint8_t *gtway_addr; - int rt_val; + struct be_cmd_get_def_gateway_resp gw_resp; + struct be_cmd_get_if_info_resp *if_info; + struct be_cmd_set_dhcp_req *dhcpreq; + struct be_dma_mem nonemb_cmd; + u8 *gw; + int rc; - memset(>way_addr_set, 0, sizeof(gtway_addr_set)); - rt_val = mgmt_get_gateway(phba, BE2_IPV4, >way_addr_set); - if (rt_val) { + rc = beiscsi_if_get_info(phba, ip_type, &if_info); + if (rc) + return rc; + + if (if_info->dhcp_state) { beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG, - "BG_%d : Failed to Get Gateway Addr\n"); - return rt_val; + "BG_%d : DHCP Already Enabled\n"); + goto exit; } - if (gtway_addr_set.ip_addr.addr[0]) { - gtway_addr = (uint8_t *)>way_addr_set.ip_addr.addr; - rt_val = mgmt_modify_gateway(phba, gtway_addr, IP_ACTION_DEL, - gateway_param->len); - if (rt_val) { + /* first delete any IP set */ + if (!beiscsi_if_zero_ip(if_info->ip_addr.addr, ip_type)) { + rc = beiscsi_if_clr_ip(phba, if_info); + if (rc) + goto exit; + } + + /* delete gateway settings if mode change is to DHCP */ + memset(&gw_resp, 0, sizeof(gw_resp)); + /* use ip_type provided in if_info */ + rc = beiscsi_if_get_gw(phba, if_info->ip_addr.ip_type, &gw_resp); + if (rc) { + beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG, + "BG_%d : Failed to Get Gateway Addr\n"); + goto exit; + } + gw = (u8 *)&gw_resp.ip_addr.addr; + if (!beiscsi_if_zero_ip(gw, if_info->ip_addr.ip_type)) { + rc = beiscsi_if_mod_gw(phba, IP_ACTION_DEL, + if_info->ip_addr.ip_type, gw); + if (rc) { beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG, "BG_%d : Failed to clear Gateway Addr Set\n"); - return rt_val; + goto exit; } } - gtway_addr = (uint8_t *)&gateway_param->value; - rt_val = mgmt_modify_gateway(phba, gtway_addr, IP_ACTION_ADD, - gateway_param->len); + rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd, + OPCODE_COMMON_ISCSI_NTWK_CONFIG_STATELESS_IP_ADDR, + sizeof(*dhcpreq)); + if (rc) + goto exit; - if (rt_val) - beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG, - "BG_%d : Failed to Set Gateway Addr\n"); + dhcpreq = nonemb_cmd.va; + dhcpreq->flags = 1; /* 1 - blocking; 0 - non-blocking */ + dhcpreq->retry_count = 1; + dhcpreq->interface_hndl = phba->interface_handle; + dhcpreq->ip_type = ip_type; + rc = mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, NULL, 0); - return rt_val; +exit: + kfree(if_info); + return rc; } -int mgmt_get_gateway(struct beiscsi_hba *phba, int ip_type, - struct be_cmd_get_def_gateway_resp *gateway) +/** + * beiscsi_if_set_vlan()- Issue and wait for CMD completion + * @phba: device private structure instance + * @vlan_tag: VLAN tag + * + * Issue the MBX Cmd and wait for the completion of the + * command. + * + * returns + * Success: 0 + * Failure: Non-Xero Value + **/ +int beiscsi_if_set_vlan(struct beiscsi_hba *phba, uint16_t vlan_tag) { - struct be_cmd_get_def_gateway_req *req; - struct be_dma_mem nonemb_cmd; int rc; + unsigned int tag; - rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd, - OPCODE_COMMON_ISCSI_NTWK_GET_DEFAULT_GATEWAY, - sizeof(*gateway)); - if (rc) - return rc; - - req = nonemb_cmd.va; - req->ip_type = ip_type; + tag = be_cmd_set_vlan(phba, vlan_tag); + if (!tag) { + beiscsi_log(phba, KERN_ERR, + (BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX), + "BG_%d : VLAN Setting Failed\n"); + return -EBUSY; + } - return mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, gateway, - sizeof(*gateway)); + rc = beiscsi_mccq_compl_wait(phba, tag, NULL, NULL); + if (rc) { + beiscsi_log(phba, KERN_ERR, + (BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX), + "BS_%d : VLAN MBX Cmd Failed\n"); + return rc; + } + return rc; } -int mgmt_get_if_info(struct beiscsi_hba *phba, int ip_type, - struct be_cmd_get_if_info_resp **if_info) + +int beiscsi_if_get_info(struct beiscsi_hba *phba, int ip_type, + struct be_cmd_get_if_info_resp **if_info) { struct be_cmd_get_if_info_req *req; struct be_dma_mem nonemb_cmd; uint32_t ioctl_size = sizeof(struct be_cmd_get_if_info_resp); int rc; - rc = mgmt_get_all_if_id(phba); + rc = beiscsi_if_get_handle(phba); if (rc) return rc; @@ -1364,123 +877,317 @@ unsigned int be_cmd_get_initname(struct beiscsi_hba *phba) return tag; } +static void beiscsi_boot_process_compl(struct beiscsi_hba *phba, + unsigned int tag) +{ + struct be_cmd_get_boot_target_resp *boot_resp; + struct be_cmd_resp_logout_fw_sess *logo_resp; + struct be_cmd_get_session_resp *sess_resp; + struct be_mcc_wrb *wrb; + struct boot_struct *bs; + int boot_work, status; + + if (!test_bit(BEISCSI_HBA_BOOT_WORK, &phba->state)) { + __beiscsi_log(phba, KERN_ERR, + "BG_%d : %s no boot work %lx\n", + __func__, phba->state); + return; + } + + if (phba->boot_struct.tag != tag) { + __beiscsi_log(phba, KERN_ERR, + "BG_%d : %s tag mismatch %d:%d\n", + __func__, tag, phba->boot_struct.tag); + return; + } + bs = &phba->boot_struct; + boot_work = 1; + status = 0; + switch (bs->action) { + case BEISCSI_BOOT_REOPEN_SESS: + status = __beiscsi_mcc_compl_status(phba, tag, NULL, NULL); + if (!status) + bs->action = BEISCSI_BOOT_GET_SHANDLE; + else + bs->retry--; + break; + case BEISCSI_BOOT_GET_SHANDLE: + status = __beiscsi_mcc_compl_status(phba, tag, &wrb, NULL); + if (!status) { + boot_resp = embedded_payload(wrb); + bs->s_handle = boot_resp->boot_session_handle; + } + if (bs->s_handle == BE_BOOT_INVALID_SHANDLE) { + bs->action = BEISCSI_BOOT_REOPEN_SESS; + bs->retry--; + } else { + bs->action = BEISCSI_BOOT_GET_SINFO; + } + break; + case BEISCSI_BOOT_GET_SINFO: + status = __beiscsi_mcc_compl_status(phba, tag, NULL, + &bs->nonemb_cmd); + if (!status) { + sess_resp = bs->nonemb_cmd.va; + memcpy(&bs->boot_sess, &sess_resp->session_info, + sizeof(struct mgmt_session_info)); + bs->action = BEISCSI_BOOT_LOGOUT_SESS; + } else { + __beiscsi_log(phba, KERN_ERR, + "BG_%d : get boot session info error : 0x%x\n", + status); + boot_work = 0; + } + pci_free_consistent(phba->ctrl.pdev, bs->nonemb_cmd.size, + bs->nonemb_cmd.va, bs->nonemb_cmd.dma); + bs->nonemb_cmd.va = NULL; + break; + case BEISCSI_BOOT_LOGOUT_SESS: + status = __beiscsi_mcc_compl_status(phba, tag, &wrb, NULL); + if (!status) { + logo_resp = embedded_payload(wrb); + if (logo_resp->session_status != BE_SESS_STATUS_CLOSE) { + __beiscsi_log(phba, KERN_ERR, + "BG_%d : FW boot session logout error : 0x%x\n", + logo_resp->session_status); + } + } + /* continue to create boot_kset even if logout failed? */ + bs->action = BEISCSI_BOOT_CREATE_KSET; + break; + default: + break; + } + + /* clear the tag so no other completion matches this tag */ + bs->tag = 0; + if (!bs->retry) { + boot_work = 0; + __beiscsi_log(phba, KERN_ERR, + "BG_%d : failed to setup boot target: status %d action %d\n", + status, bs->action); + } + if (!boot_work) { + /* wait for next event to start boot_work */ + clear_bit(BEISCSI_HBA_BOOT_WORK, &phba->state); + return; + } + schedule_work(&phba->boot_work); +} + /** - * be_mgmt_get_boot_shandle()- Get the session handle - * @phba: device priv structure instance - * @s_handle: session handle returned for boot session. + * beiscsi_boot_logout_sess()- Logout from boot FW session + * @phba: Device priv structure instance * - * Get the boot target session handle. In case of - * crashdump mode driver has to issue and MBX Cmd - * for FW to login to boot target + * return + * the TAG used for MBOX Command + * + */ +unsigned int beiscsi_boot_logout_sess(struct beiscsi_hba *phba) +{ + struct be_ctrl_info *ctrl = &phba->ctrl; + struct be_mcc_wrb *wrb; + struct be_cmd_req_logout_fw_sess *req; + unsigned int tag; + + mutex_lock(&ctrl->mbox_lock); + wrb = alloc_mcc_wrb(phba, &tag); + if (!wrb) { + mutex_unlock(&ctrl->mbox_lock); + return 0; + } + + req = embedded_payload(wrb); + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI, + OPCODE_ISCSI_INI_SESSION_LOGOUT_TARGET, + sizeof(struct be_cmd_req_logout_fw_sess)); + /* Use the session handle copied into boot_sess */ + req->session_handle = phba->boot_struct.boot_sess.session_handle; + + phba->boot_struct.tag = tag; + set_bit(MCC_TAG_STATE_ASYNC, &ctrl->ptag_state[tag].tag_state); + ctrl->ptag_state[tag].cbfn = beiscsi_boot_process_compl; + + be_mcc_notify(phba, tag); + mutex_unlock(&ctrl->mbox_lock); + + return tag; +} +/** + * beiscsi_boot_reopen_sess()- Reopen boot session + * @phba: Device priv structure instance * * return - * Success: 0 - * Failure: Non-Zero value + * the TAG used for MBOX Command * **/ -int be_mgmt_get_boot_shandle(struct beiscsi_hba *phba, - unsigned int *s_handle) +unsigned int beiscsi_boot_reopen_sess(struct beiscsi_hba *phba) { - struct be_cmd_get_boot_target_resp *boot_resp; + struct be_ctrl_info *ctrl = &phba->ctrl; struct be_mcc_wrb *wrb; + struct be_cmd_reopen_session_req *req; unsigned int tag; - uint8_t boot_retry = 3; - int rc; - do { - /* Get the Boot Target Session Handle and Count*/ - tag = mgmt_get_boot_target(phba); - if (!tag) { - beiscsi_log(phba, KERN_ERR, - BEISCSI_LOG_CONFIG | BEISCSI_LOG_INIT, - "BG_%d : Getting Boot Target Info Failed\n"); - return -EAGAIN; - } + mutex_lock(&ctrl->mbox_lock); + wrb = alloc_mcc_wrb(phba, &tag); + if (!wrb) { + mutex_unlock(&ctrl->mbox_lock); + return 0; + } - rc = beiscsi_mccq_compl_wait(phba, tag, &wrb, NULL); - if (rc) { - beiscsi_log(phba, KERN_ERR, - BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG, - "BG_%d : MBX CMD get_boot_target Failed\n"); - return -EBUSY; - } + req = embedded_payload(wrb); + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI, + OPCODE_ISCSI_INI_DRIVER_REOPEN_ALL_SESSIONS, + sizeof(struct be_cmd_reopen_session_resp)); + req->reopen_type = BE_REOPEN_BOOT_SESSIONS; + req->session_handle = BE_BOOT_INVALID_SHANDLE; - boot_resp = embedded_payload(wrb); + phba->boot_struct.tag = tag; + set_bit(MCC_TAG_STATE_ASYNC, &ctrl->ptag_state[tag].tag_state); + ctrl->ptag_state[tag].cbfn = beiscsi_boot_process_compl; - /* Check if the there are any Boot targets configured */ - if (!boot_resp->boot_session_count) { - beiscsi_log(phba, KERN_INFO, - BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG, - "BG_%d ;No boot targets configured\n"); - return -ENXIO; - } + be_mcc_notify(phba, tag); + mutex_unlock(&ctrl->mbox_lock); + return tag; +} - /* FW returns the session handle of the boot session */ - if (boot_resp->boot_session_handle != INVALID_SESS_HANDLE) { - *s_handle = boot_resp->boot_session_handle; - return 0; - } - /* Issue MBX Cmd to FW to login to the boot target */ - tag = mgmt_reopen_session(phba, BE_REOPEN_BOOT_SESSIONS, - INVALID_SESS_HANDLE); - if (!tag) { - beiscsi_log(phba, KERN_ERR, - BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG, - "BG_%d : mgmt_reopen_session Failed\n"); - return -EAGAIN; - } +/** + * beiscsi_boot_get_sinfo()- Get boot session info + * @phba: device priv structure instance + * + * Fetches the boot_struct.s_handle info from FW. + * return + * the TAG used for MBOX Command + * + **/ +unsigned int beiscsi_boot_get_sinfo(struct beiscsi_hba *phba) +{ + struct be_ctrl_info *ctrl = &phba->ctrl; + struct be_cmd_get_session_resp *resp; + struct be_cmd_get_session_req *req; + struct be_dma_mem *nonemb_cmd; + struct be_mcc_wrb *wrb; + struct be_sge *sge; + unsigned int tag; - rc = beiscsi_mccq_compl_wait(phba, tag, NULL, NULL); - if (rc) { - beiscsi_log(phba, KERN_ERR, - BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG, - "BG_%d : mgmt_reopen_session Failed"); - return rc; - } - } while (--boot_retry); + mutex_lock(&ctrl->mbox_lock); + wrb = alloc_mcc_wrb(phba, &tag); + if (!wrb) { + mutex_unlock(&ctrl->mbox_lock); + return 0; + } - /* Couldn't log into the boot target */ - beiscsi_log(phba, KERN_ERR, - BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG, - "BG_%d : Login to Boot Target Failed\n"); - return -ENXIO; + nonemb_cmd = &phba->boot_struct.nonemb_cmd; + nonemb_cmd->size = sizeof(*resp); + nonemb_cmd->va = pci_alloc_consistent(phba->ctrl.pdev, + sizeof(nonemb_cmd->size), + &nonemb_cmd->dma); + if (!nonemb_cmd->va) { + mutex_unlock(&ctrl->mbox_lock); + return 0; + } + + req = nonemb_cmd->va; + memset(req, 0, sizeof(*req)); + sge = nonembedded_sgl(wrb); + be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1); + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI, + OPCODE_ISCSI_INI_SESSION_GET_A_SESSION, + sizeof(*resp)); + req->session_handle = phba->boot_struct.s_handle; + sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma)); + sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF); + sge->len = cpu_to_le32(nonemb_cmd->size); + + phba->boot_struct.tag = tag; + set_bit(MCC_TAG_STATE_ASYNC, &ctrl->ptag_state[tag].tag_state); + ctrl->ptag_state[tag].cbfn = beiscsi_boot_process_compl; + + be_mcc_notify(phba, tag); + mutex_unlock(&ctrl->mbox_lock); + return tag; +} + +unsigned int __beiscsi_boot_get_shandle(struct beiscsi_hba *phba, int async) +{ + struct be_ctrl_info *ctrl = &phba->ctrl; + struct be_mcc_wrb *wrb; + struct be_cmd_get_boot_target_req *req; + unsigned int tag; + + mutex_lock(&ctrl->mbox_lock); + wrb = alloc_mcc_wrb(phba, &tag); + if (!wrb) { + mutex_unlock(&ctrl->mbox_lock); + return 0; + } + + req = embedded_payload(wrb); + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI, + OPCODE_ISCSI_INI_BOOT_GET_BOOT_TARGET, + sizeof(struct be_cmd_get_boot_target_resp)); + + if (async) { + phba->boot_struct.tag = tag; + set_bit(MCC_TAG_STATE_ASYNC, &ctrl->ptag_state[tag].tag_state); + ctrl->ptag_state[tag].cbfn = beiscsi_boot_process_compl; + } + + be_mcc_notify(phba, tag); + mutex_unlock(&ctrl->mbox_lock); + return tag; } /** - * mgmt_set_vlan()- Issue and wait for CMD completion - * @phba: device private structure instance - * @vlan_tag: VLAN tag + * beiscsi_boot_get_shandle()- Get boot session handle + * @phba: device priv structure instance + * @s_handle: session handle returned for boot session. * - * Issue the MBX Cmd and wait for the completion of the - * command. + * return + * Success: 1 + * Failure: negative * - * returns - * Success: 0 - * Failure: Non-Xero Value **/ -int mgmt_set_vlan(struct beiscsi_hba *phba, - uint16_t vlan_tag) +int beiscsi_boot_get_shandle(struct beiscsi_hba *phba, unsigned int *s_handle) { - int rc; + struct be_cmd_get_boot_target_resp *boot_resp; + struct be_mcc_wrb *wrb; unsigned int tag; + int rc; - tag = be_cmd_set_vlan(phba, vlan_tag); + *s_handle = BE_BOOT_INVALID_SHANDLE; + /* get configured boot session count and handle */ + tag = __beiscsi_boot_get_shandle(phba, 0); if (!tag) { beiscsi_log(phba, KERN_ERR, - (BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX), - "BG_%d : VLAN Setting Failed\n"); - return -EBUSY; + BEISCSI_LOG_CONFIG | BEISCSI_LOG_INIT, + "BG_%d : Getting Boot Target Info Failed\n"); + return -EAGAIN; } - rc = beiscsi_mccq_compl_wait(phba, tag, NULL, NULL); + rc = beiscsi_mccq_compl_wait(phba, tag, &wrb, NULL); if (rc) { beiscsi_log(phba, KERN_ERR, - (BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX), - "BS_%d : VLAN MBX Cmd Failed\n"); - return rc; + BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG, + "BG_%d : MBX CMD get_boot_target Failed\n"); + return -EBUSY; } - return rc; + + boot_resp = embedded_payload(wrb); + /* check if there are any boot targets configured */ + if (!boot_resp->boot_session_count) { + __beiscsi_log(phba, KERN_INFO, + "BG_%d : No boot targets configured\n"); + return -ENXIO; + } + + /* only if FW has logged in to the boot target, s_handle is valid */ + *s_handle = boot_resp->boot_session_handle; + return 1; } /** @@ -1645,7 +1352,6 @@ void beiscsi_offload_cxn_v0(struct beiscsi_offload_params *params, { struct iscsi_wrb *pwrb = pwrb_handle->pwrb; - memset(pwrb, 0, sizeof(*pwrb)); AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, max_send_data_segment_length, pwrb, params->dw[offsetof(struct amap_beiscsi_offload_params, @@ -1717,8 +1423,6 @@ void beiscsi_offload_cxn_v2(struct beiscsi_offload_params *params, { struct iscsi_wrb *pwrb = pwrb_handle->pwrb; - memset(pwrb, 0, sizeof(*pwrb)); - AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, max_burst_length, pwrb, params->dw[offsetof (struct amap_beiscsi_offload_params, @@ -1790,70 +1494,3 @@ void beiscsi_offload_cxn_v2(struct beiscsi_offload_params *params, (params->dw[offsetof(struct amap_beiscsi_offload_params, exp_statsn) / 32] + 1)); } - -/** - * beiscsi_logout_fw_sess()- Firmware Session Logout - * @phba: Device priv structure instance - * @fw_sess_handle: FW session handle - * - * Logout from the FW established sessions. - * returns - * Success: 0 - * Failure: Non-Zero Value - * - */ -int beiscsi_logout_fw_sess(struct beiscsi_hba *phba, - uint32_t fw_sess_handle) -{ - struct be_ctrl_info *ctrl = &phba->ctrl; - struct be_mcc_wrb *wrb; - struct be_cmd_req_logout_fw_sess *req; - struct be_cmd_resp_logout_fw_sess *resp; - unsigned int tag; - int rc; - - beiscsi_log(phba, KERN_INFO, - BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX, - "BG_%d : In bescsi_logout_fwboot_sess\n"); - - mutex_lock(&ctrl->mbox_lock); - wrb = alloc_mcc_wrb(phba, &tag); - if (!wrb) { - mutex_unlock(&ctrl->mbox_lock); - beiscsi_log(phba, KERN_INFO, - BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX, - "BG_%d : MBX Tag Failure\n"); - return -EINVAL; - } - - req = embedded_payload(wrb); - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); - be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI, - OPCODE_ISCSI_INI_SESSION_LOGOUT_TARGET, - sizeof(struct be_cmd_req_logout_fw_sess)); - - /* Set the session handle */ - req->session_handle = fw_sess_handle; - be_mcc_notify(phba, tag); - mutex_unlock(&ctrl->mbox_lock); - - rc = beiscsi_mccq_compl_wait(phba, tag, &wrb, NULL); - if (rc) { - beiscsi_log(phba, KERN_ERR, - BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG, - "BG_%d : MBX CMD FW_SESSION_LOGOUT_TARGET Failed\n"); - return -EBUSY; - } - - resp = embedded_payload(wrb); - if (resp->session_status != - BEISCSI_MGMT_SESSION_CLOSE) { - beiscsi_log(phba, KERN_ERR, - BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG, - "BG_%d : FW_SESSION_LOGOUT_TARGET resp : 0x%x\n", - resp->session_status); - rc = -EINVAL; - } - - return rc; -} diff --git a/drivers/scsi/be2iscsi/be_mgmt.h b/drivers/scsi/be2iscsi/be_mgmt.h index f3a48a04b2ca..b897cfd57c72 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.h +++ b/drivers/scsi/be2iscsi/be_mgmt.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2015 Emulex + * Copyright (C) 2005 - 2016 Broadcom * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -7,10 +7,10 @@ * as published by the Free Software Foundation. The full GNU General * Public License is included in this distribution in the file called COPYING. * - * Written by: Jayamohan Kallickal (jayamohan.kallickal@avagotech.com) + * Written by: Jayamohan Kallickal (jayamohan.kallickal@broadcom.com) * * Contact Information: - * linux-drivers@avagotech.com + * linux-drivers@broadcom.com * * Emulex * 3333 Susan Street @@ -96,7 +96,6 @@ struct mcc_wrb { struct mcc_wrb_payload payload; }; -int mgmt_epfw_cleanup(struct beiscsi_hba *phba, unsigned short chute); int mgmt_open_connection(struct beiscsi_hba *phba, struct sockaddr *dst_addr, struct beiscsi_endpoint *beiscsi_ep, @@ -266,50 +265,41 @@ struct beiscsi_endpoint { u16 cid_vld; }; -int mgmt_get_fw_config(struct be_ctrl_info *ctrl, - struct beiscsi_hba *phba); -int mgmt_get_port_name(struct be_ctrl_info *ctrl, - struct beiscsi_hba *phba); - unsigned int mgmt_invalidate_connection(struct beiscsi_hba *phba, struct beiscsi_endpoint *beiscsi_ep, unsigned short cid, unsigned short issue_reset, unsigned short savecfg_flag); -int mgmt_set_ip(struct beiscsi_hba *phba, - struct iscsi_iface_param_info *ip_param, - struct iscsi_iface_param_info *subnet_param, - uint32_t boot_proto); +int beiscsi_if_en_dhcp(struct beiscsi_hba *phba, u32 ip_type); -unsigned int mgmt_get_boot_target(struct beiscsi_hba *phba); +int beiscsi_if_en_static(struct beiscsi_hba *phba, u32 ip_type, + u8 *ip, u8 *subnet); -unsigned int mgmt_reopen_session(struct beiscsi_hba *phba, - unsigned int reopen_type, - unsigned sess_handle); +int beiscsi_if_set_gw(struct beiscsi_hba *phba, u32 ip_type, u8 *gw); -unsigned int mgmt_get_session_info(struct beiscsi_hba *phba, - u32 boot_session_handle, - struct be_dma_mem *nonemb_cmd); +int beiscsi_if_get_gw(struct beiscsi_hba *phba, u32 ip_type, + struct be_cmd_get_def_gateway_resp *resp); int mgmt_get_nic_conf(struct beiscsi_hba *phba, struct be_cmd_get_nic_conf_resp *mac); -int mgmt_get_if_info(struct beiscsi_hba *phba, int ip_type, - struct be_cmd_get_if_info_resp **if_info); +int beiscsi_if_get_info(struct beiscsi_hba *phba, int ip_type, + struct be_cmd_get_if_info_resp **if_info); + +unsigned int beiscsi_if_get_handle(struct beiscsi_hba *phba); + +int beiscsi_if_set_vlan(struct beiscsi_hba *phba, uint16_t vlan_tag); -int mgmt_get_gateway(struct beiscsi_hba *phba, int ip_type, - struct be_cmd_get_def_gateway_resp *gateway); +unsigned int beiscsi_boot_logout_sess(struct beiscsi_hba *phba); -int mgmt_set_gateway(struct beiscsi_hba *phba, - struct iscsi_iface_param_info *gateway_param); +unsigned int beiscsi_boot_reopen_sess(struct beiscsi_hba *phba); -int be_mgmt_get_boot_shandle(struct beiscsi_hba *phba, - unsigned int *s_handle); +unsigned int beiscsi_boot_get_sinfo(struct beiscsi_hba *phba); -unsigned int mgmt_get_all_if_id(struct beiscsi_hba *phba); +unsigned int __beiscsi_boot_get_shandle(struct beiscsi_hba *phba, int async); -int mgmt_set_vlan(struct beiscsi_hba *phba, uint16_t vlan_tag); +int beiscsi_boot_get_shandle(struct beiscsi_hba *phba, unsigned int *s_handle); ssize_t beiscsi_drvr_ver_disp(struct device *dev, struct device_attribute *attr, char *buf); @@ -339,7 +329,6 @@ void beiscsi_offload_cxn_v2(struct beiscsi_offload_params *params, struct wrb_handle *pwrb_handle, struct hwi_wrb_context *pwrb_context); -void beiscsi_ue_detect(struct beiscsi_hba *phba); int be_cmd_modify_eq_delay(struct beiscsi_hba *phba, struct be_set_eqd *, int num); |