/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2014 QLogic Corporation * The contents of this file are subject to the terms of the * QLogic End User License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the License at * http://www.qlogic.com/Resources/Documents/DriverDownloadHelp/ * QLogic_End_User_Software_License.txt * See the License for the specific language governing permissions * and limitations under the License. */ #include "bnxe.h" #define VERIFY_FCOE_BINDING(pUM) \ if (!BNXE_FCOE(pUM)) \ { \ BnxeLogWarn((pUM), "FCoE not supported on this device!"); \ return B_FALSE; \ } \ if (!(CLIENT_BOUND(pUM, LM_CLI_IDX_FCOE))) \ { \ BnxeLogWarn((pUM), "FCoE client not bound!"); \ return B_FALSE; \ } void BnxeFcoeFreeResc(um_device_t * pUM, BnxeFcoeState * pFcoeState) { BNXE_LOCK_ENTER_OFFLOAD(pUM); lm_fc_del_fcoe_state(&pUM->lm_dev, &pFcoeState->lm_fcoe); BNXE_LOCK_EXIT_OFFLOAD(pUM); lm_fc_free_con_resc(&pUM->lm_dev, &pFcoeState->lm_fcoe); kmem_free(pFcoeState, sizeof(BnxeFcoeState)); } static boolean_t BnxeFcoeCqeIndicate(um_device_t * pUM, void * pData, u32_t dataLen) { struct fcoe_kcqe * kcqe = (struct fcoe_kcqe *)pData; if (dataLen != (sizeof(*kcqe))) { BnxeLogWarn(pUM, "Invalid FCoE CQE"); return B_FALSE; } /* XXX * Need to add a mutex or reference count to ensure that bnxef isn't * unloaded underneath this taskq dispatch routine. */ ASSERT(CLIENT_BOUND(pUM, LM_CLI_IDX_FCOE)); pUM->fcoe.bind.cliIndicateCqes(pUM->fcoe.pDev, (void **)&kcqe, 1); /* XXX release mutex or decrement reference count */ return B_TRUE; } static void BnxeFcoeInitCqeWork(um_device_t * pUM, void * pData, u32_t dataLen) { if (!BnxeFcoeCqeIndicate(pUM, pData, dataLen)) { pUM->fcoe.stats.initCqeRxErr++; } else { pUM->fcoe.stats.initCqeRx++; } } boolean_t BnxeFcoeInitCqe(um_device_t * pUM, struct fcoe_kcqe * kcqe) { struct fcoe_kcqe tmp_kcqe = {0}; tmp_kcqe.op_code = FCOE_KCQE_OPCODE_INIT_FUNC; tmp_kcqe.flags |= (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); tmp_kcqe.completion_status = mm_cpu_to_le32((mm_le32_to_cpu(kcqe->completion_status) == 0) ? FCOE_KCQE_COMPLETION_STATUS_SUCCESS : FCOE_KCQE_COMPLETION_STATUS_NIC_ERROR); return BnxeWorkQueueAdd(pUM, BnxeFcoeInitCqeWork, &tmp_kcqe, sizeof(tmp_kcqe)); } static void BnxeFcoeInitWqeWork(um_device_t * pUM, void * pData, u32_t dataLen) { union fcoe_kwqe * kwqe = (union fcoe_kwqe *)pData; struct fcoe_kcqe kcqe = {0}; if (dataLen != (3 * sizeof(*kwqe))) { BnxeLogWarn(pUM, "Invalid FCoE Init WQE"); pUM->fcoe.stats.initWqeTxErr++; return; } if (kwqe[1].init2.hsi_major_version != FCOE_HSI_MAJOR_VERSION) { BnxeLogWarn(pUM, "ERROR: Invalid FCoE HSI major version (L5=%d vs FW=%d)", kwqe[1].init2.hsi_major_version, FCOE_HSI_MAJOR_VERSION); kcqe.completion_status = FCOE_KCQE_COMPLETION_STATUS_WRONG_HSI_VERSION; goto BnxeFcoeInitWqeWork_error; } if (lm_fc_init(&pUM->lm_dev, &kwqe[0].init1, &kwqe[1].init2, &kwqe[2].init3) != LM_STATUS_SUCCESS) { BnxeLogWarn(pUM, "Failed to post FCoE Init WQE"); kcqe.completion_status = FCOE_KCQE_COMPLETION_STATUS_ERROR; goto BnxeFcoeInitWqeWork_error; } pUM->fcoe.stats.initWqeTx++; return; BnxeFcoeInitWqeWork_error: pUM->fcoe.stats.initWqeTxErr++; kcqe.op_code = FCOE_KCQE_OPCODE_INIT_FUNC; kcqe.flags |= (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); kcqe.completion_status = mm_cpu_to_le32(kcqe.completion_status); kcqe.fcoe_conn_id = kwqe[1].conn_offload1.fcoe_conn_id; /* call here directly (for error case) */ /* XXX * Need to add a mutex or reference count to ensure that bnxef isn't * unloaded underneath this taskq dispatch routine. */ { struct fcoe_kcqe * pKcqe = &kcqe; ASSERT(CLIENT_BOUND(pUM, LM_CLI_IDX_FCOE)); pUM->fcoe.bind.cliIndicateCqes(pUM->fcoe.pDev, (void **)&pKcqe, 1); } /* XXX release mutex or decrement reference count */ } static boolean_t BnxeFcoeInitWqe(um_device_t * pUM, union fcoe_kwqe ** kwqes) { union fcoe_kwqe wqe[3]; wqe[0] =*(kwqes[0]); wqe[1] =*(kwqes[1]); wqe[2] =*(kwqes[2]); return BnxeWorkQueueAdd(pUM, BnxeFcoeInitWqeWork, wqe, sizeof(wqe)); } static void BnxeFcoeOffloadConnCqeWork(um_device_t * pUM, void * pData, u32_t dataLen) { if (!BnxeFcoeCqeIndicate(pUM, pData, dataLen)) { pUM->fcoe.stats.offloadConnCqeRxErr++; } else { pUM->fcoe.stats.offloadConnCqeRx++; } } boolean_t BnxeFcoeOffloadConnCqe(um_device_t * pUM, BnxeFcoeState * pFcoeState, struct fcoe_kcqe * kcqe) { struct fcoe_kcqe tmp_kcqe = {0}; tmp_kcqe.op_code = FCOE_KCQE_OPCODE_OFFLOAD_CONN; tmp_kcqe.flags |= (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); tmp_kcqe.fcoe_conn_context_id = kcqe->fcoe_conn_context_id; tmp_kcqe.fcoe_conn_id = kcqe->fcoe_conn_id; tmp_kcqe.completion_status = mm_cpu_to_le32((mm_le32_to_cpu(kcqe->completion_status) == 0) ? FCOE_KCQE_COMPLETION_STATUS_SUCCESS : FCOE_KCQE_COMPLETION_STATUS_CTX_ALLOC_FAILURE); if (pFcoeState != NULL) { pFcoeState->lm_fcoe.hdr.status = (mm_le32_to_cpu(kcqe->completion_status) == 0) ? STATE_STATUS_NORMAL : STATE_STATUS_INIT_OFFLOAD_ERR; } return BnxeWorkQueueAdd(pUM, BnxeFcoeOffloadConnCqeWork, &tmp_kcqe, sizeof(tmp_kcqe)); } static void BnxeFcoeOffloadConnWqeWork(um_device_t * pUM, void * pData, u32_t dataLen) { union fcoe_kwqe * kwqe = (union fcoe_kwqe *)pData; struct fcoe_kcqe kcqe = {0}; BnxeFcoeState * pFcoeState; lm_status_t rc; if (dataLen != (4 * sizeof(*kwqe))) { BnxeLogWarn(pUM, "Invalid FCoE Offload Conn WQE"); pUM->fcoe.stats.offloadConnWqeTxErr++; return; } if ((pFcoeState = kmem_zalloc(sizeof(BnxeFcoeState), KM_NOSLEEP)) == NULL) { BnxeLogWarn(pUM, "Failed to allocate memory for FCoE state"); goto BnxeFcoeOffloadConnWqeWork_error; } BNXE_LOCK_ENTER_OFFLOAD(pUM); rc = lm_fc_init_fcoe_state(&pUM->lm_dev, &pUM->lm_dev.fcoe_info.run_time.state_blk, &pFcoeState->lm_fcoe); BNXE_LOCK_EXIT_OFFLOAD(pUM); if (rc != LM_STATUS_SUCCESS) { kmem_free(pFcoeState, sizeof(BnxeFcoeState)); BnxeLogWarn(pUM, "Failed to initialize FCoE state"); goto BnxeFcoeOffloadConnWqeWork_error; } pFcoeState->lm_fcoe.ofld1 = kwqe[0].conn_offload1; pFcoeState->lm_fcoe.ofld2 = kwqe[1].conn_offload2; pFcoeState->lm_fcoe.ofld3 = kwqe[2].conn_offload3; pFcoeState->lm_fcoe.ofld4 = kwqe[3].conn_offload4; rc = lm_fc_alloc_con_resc(&pUM->lm_dev, &pFcoeState->lm_fcoe); if (rc == LM_STATUS_SUCCESS) { lm_fc_init_fcoe_context(&pUM->lm_dev, &pFcoeState->lm_fcoe); lm_fc_post_offload_ramrod(&pUM->lm_dev, &pFcoeState->lm_fcoe); } else if (rc == LM_STATUS_PENDING) { /* * the cid is pending - its too soon to initialize the context, it will * be initialized from the recycle cid callback and completed as well. */ BnxeLogInfo(pUM, "lm_fc_alloc_con_resc returned pending?"); } else { BnxeFcoeFreeResc(pUM, pFcoeState); BnxeLogInfo(pUM, "lm_fc_alloc_con_resc failed (%d)", rc); goto BnxeFcoeOffloadConnWqeWork_error; } pUM->fcoe.stats.offloadConnWqeTx++; return; BnxeFcoeOffloadConnWqeWork_error: pUM->fcoe.stats.offloadConnWqeTxErr++; kcqe.op_code = FCOE_KCQE_OPCODE_OFFLOAD_CONN; kcqe.flags |= (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); kcqe.completion_status = mm_cpu_to_le32(FCOE_KCQE_COMPLETION_STATUS_CTX_ALLOC_FAILURE); kcqe.fcoe_conn_id = kwqe[0].conn_offload1.fcoe_conn_id; /* call here directly (for error case) */ /* XXX * Need to add a mutex or reference count to ensure that bnxef isn't * unloaded underneath this taskq dispatch routine. */ { struct fcoe_kcqe * pKcqe = &kcqe; ASSERT(CLIENT_BOUND(pUM, LM_CLI_IDX_FCOE)); pUM->fcoe.bind.cliIndicateCqes(pUM->fcoe.pDev, (void **)&pKcqe, 1); } /* XXX release mutex or decrement reference count */ } static boolean_t BnxeFcoeOffloadConnWqe(um_device_t * pUM, union fcoe_kwqe ** kwqes) { union fcoe_kwqe wqe[4]; wqe[0] =*(kwqes[0]); wqe[1] =*(kwqes[1]); wqe[2] =*(kwqes[2]); wqe[3] =*(kwqes[3]); return BnxeWorkQueueAdd(pUM, BnxeFcoeOffloadConnWqeWork, wqe, sizeof(wqe)); } static void BnxeFcoeEnableConnCqeWork(um_device_t * pUM, void * pData, u32_t dataLen) { if (!BnxeFcoeCqeIndicate(pUM, pData, dataLen)) { pUM->fcoe.stats.enableConnCqeRxErr++; } else { pUM->fcoe.stats.enableConnCqeRx++; } } boolean_t BnxeFcoeEnableConnCqe(um_device_t * pUM, BnxeFcoeState * pFcoeState, struct fcoe_kcqe * kcqe) { struct fcoe_kcqe tmp_kcqe = {0}; tmp_kcqe.op_code = FCOE_KCQE_OPCODE_ENABLE_CONN; tmp_kcqe.flags |= (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); tmp_kcqe.fcoe_conn_context_id = kcqe->fcoe_conn_context_id; tmp_kcqe.fcoe_conn_id = kcqe->fcoe_conn_id; tmp_kcqe.completion_status = mm_cpu_to_le32((mm_le32_to_cpu(kcqe->completion_status) == 0) ? FCOE_KCQE_COMPLETION_STATUS_SUCCESS : FCOE_KCQE_COMPLETION_STATUS_CTX_ALLOC_FAILURE); if (pFcoeState != NULL) { pFcoeState->lm_fcoe.hdr.status = (mm_le32_to_cpu(kcqe->completion_status) == 0) ? STATE_STATUS_NORMAL : STATE_STATUS_INIT_OFFLOAD_ERR; } return BnxeWorkQueueAdd(pUM, BnxeFcoeEnableConnCqeWork, &tmp_kcqe, sizeof(tmp_kcqe)); } static void BnxeFcoeEnableConnWqeWork(um_device_t * pUM, void * pData, u32_t dataLen) { union fcoe_kwqe * kwqe = (union fcoe_kwqe *)pData; struct fcoe_kcqe kcqe = {0}; BnxeFcoeState * pFcoeState; if (dataLen != sizeof(*kwqe)) { BnxeLogWarn(pUM, "Invalid FCoE Enable Conn WQE"); pUM->fcoe.stats.enableConnWqeTxErr++; return; } pFcoeState = lm_cid_cookie(&pUM->lm_dev, FCOE_CONNECTION_TYPE, SW_CID(mm_le32_to_cpu(kwqe->conn_enable_disable.context_id))); if (pFcoeState == NULL) { goto BnxeFcoeEnableConnWqeWork_error; } if (lm_fc_post_enable_ramrod(&pUM->lm_dev, &pFcoeState->lm_fcoe, &kwqe->conn_enable_disable) != LM_STATUS_SUCCESS) { goto BnxeFcoeEnableConnWqeWork_error; } pUM->fcoe.stats.enableConnWqeTx++; return; BnxeFcoeEnableConnWqeWork_error: pUM->fcoe.stats.enableConnWqeTxErr++; BnxeLogWarn(pUM, "Failed to post FCoE Enable Conn WQE"); kcqe.op_code = FCOE_KCQE_OPCODE_ENABLE_CONN; kcqe.flags |= (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); kcqe.fcoe_conn_context_id = kwqe->conn_enable_disable.context_id; kcqe.completion_status = mm_cpu_to_le32(FCOE_KCQE_COMPLETION_STATUS_NIC_ERROR); /* call here directly (for error case) */ /* XXX * Need to add a mutex or reference count to ensure that bnxef isn't * unloaded underneath this taskq dispatch routine. */ { struct fcoe_kcqe * pKcqe = &kcqe; ASSERT(CLIENT_BOUND(pUM, LM_CLI_IDX_FCOE)); pUM->fcoe.bind.cliIndicateCqes(pUM->fcoe.pDev, (void **)&pKcqe, 1); } /* XXX release mutex or decrement reference count */ } static boolean_t BnxeFcoeEnableConnWqe(um_device_t * pUM, union fcoe_kwqe ** kwqes) { return BnxeWorkQueueAdd(pUM, BnxeFcoeEnableConnWqeWork, kwqes[0], sizeof(*(kwqes[0]))); } static void BnxeFcoeDisableConnCqeWork(um_device_t * pUM, void * pData, u32_t dataLen) { if (!BnxeFcoeCqeIndicate(pUM, pData, dataLen)) { pUM->fcoe.stats.disableConnCqeRxErr++; } else { pUM->fcoe.stats.disableConnCqeRx++; } } boolean_t BnxeFcoeDisableConnCqe(um_device_t * pUM, BnxeFcoeState * pFcoeState, struct fcoe_kcqe * kcqe) { struct fcoe_kcqe tmp_kcqe = {0}; tmp_kcqe.op_code = FCOE_KCQE_OPCODE_DISABLE_CONN; tmp_kcqe.flags |= (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); tmp_kcqe.fcoe_conn_context_id = kcqe->fcoe_conn_context_id; tmp_kcqe.fcoe_conn_id = kcqe->fcoe_conn_id; tmp_kcqe.completion_status = mm_cpu_to_le32((mm_le32_to_cpu(kcqe->completion_status) == 0) ? FCOE_KCQE_COMPLETION_STATUS_SUCCESS : FCOE_KCQE_COMPLETION_STATUS_NIC_ERROR); if (pFcoeState != NULL) { pFcoeState->lm_fcoe.hdr.status = (mm_le32_to_cpu(kcqe->completion_status) == 0) ? STATE_STATUS_NORMAL : STATE_STATUS_INIT_OFFLOAD_ERR; } return BnxeWorkQueueAdd(pUM, BnxeFcoeDisableConnCqeWork, &tmp_kcqe, sizeof(tmp_kcqe)); } static void BnxeFcoeDisableConnWqeWork(um_device_t * pUM, void * pData, u32_t dataLen) { union fcoe_kwqe * kwqe = (union fcoe_kwqe *)pData; struct fcoe_kcqe kcqe = {0}; BnxeFcoeState * pFcoeState; if (dataLen != sizeof(*kwqe)) { BnxeLogWarn(pUM, "Invalid FCoE Disable Conn WQE"); pUM->fcoe.stats.disableConnWqeTxErr++; return; } pFcoeState = lm_cid_cookie(&pUM->lm_dev, FCOE_CONNECTION_TYPE, SW_CID(mm_le32_to_cpu(kwqe->conn_enable_disable.context_id))); if (pFcoeState == NULL) { goto BnxeFcoeDisableConnWqeWork_error; } if (lm_fc_post_disable_ramrod(&pUM->lm_dev, &pFcoeState->lm_fcoe, &kwqe->conn_enable_disable) != LM_STATUS_SUCCESS) { goto BnxeFcoeDisableConnWqeWork_error; } pUM->fcoe.stats.disableConnWqeTx++; return; BnxeFcoeDisableConnWqeWork_error: pUM->fcoe.stats.disableConnWqeTxErr++; BnxeLogWarn(pUM, "Failed to post FCoE Disable Conn WQE"); kcqe.op_code = FCOE_KCQE_OPCODE_DISABLE_CONN; kcqe.flags |= (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); kcqe.fcoe_conn_context_id = kwqe->conn_enable_disable.context_id; kcqe.completion_status = mm_cpu_to_le32(FCOE_KCQE_COMPLETION_STATUS_NIC_ERROR); /* call here directly (for error case) */ /* XXX * Need to add a mutex or reference count to ensure that bnxef isn't * unloaded underneath this taskq dispatch routine. */ { struct fcoe_kcqe * pKcqe = &kcqe; ASSERT(CLIENT_BOUND(pUM, LM_CLI_IDX_FCOE)); pUM->fcoe.bind.cliIndicateCqes(pUM->fcoe.pDev, (void **)&pKcqe, 1); } /* XXX release mutex or decrement reference count */ } static boolean_t BnxeFcoeDisableConnWqe(um_device_t * pUM, union fcoe_kwqe ** kwqes) { return BnxeWorkQueueAdd(pUM, BnxeFcoeDisableConnWqeWork, kwqes[0], sizeof(*(kwqes[0]))); } static void BnxeFcoeDestroyConnCqeWork(um_device_t * pUM, void * pData, u32_t dataLen) { struct fcoe_kcqe * kcqe = (struct fcoe_kcqe *)pData; BnxeFcoeState * pFcoeState; if (dataLen != (sizeof(*kcqe))) { BnxeLogWarn(pUM, "Invalid FCoE Destroy Conn CQE"); pUM->fcoe.stats.destroyConnCqeRxErr++; return; } pFcoeState = lm_cid_cookie(&pUM->lm_dev, FCOE_CONNECTION_TYPE, SW_CID(mm_le32_to_cpu(kcqe->fcoe_conn_context_id))); BnxeFcoeFreeResc(pUM, pFcoeState); if (!BnxeFcoeCqeIndicate(pUM, pData, dataLen)) { pUM->fcoe.stats.destroyConnCqeRxErr++; } else { pUM->fcoe.stats.destroyConnCqeRx++; } } boolean_t BnxeFcoeDestroyConnCqe(um_device_t * pUM, BnxeFcoeState * pFcoeState, struct fcoe_kcqe * kcqe) { struct fcoe_kcqe tmp_kcqe = {0}; tmp_kcqe.op_code = FCOE_KCQE_OPCODE_DESTROY_CONN; tmp_kcqe.flags |= (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); tmp_kcqe.fcoe_conn_context_id = kcqe->fcoe_conn_context_id; tmp_kcqe.fcoe_conn_id = kcqe->fcoe_conn_id; tmp_kcqe.completion_status = mm_cpu_to_le32((mm_le32_to_cpu(kcqe->completion_status) == 0) ? FCOE_KCQE_COMPLETION_STATUS_SUCCESS : FCOE_KCQE_COMPLETION_STATUS_NIC_ERROR); if (pFcoeState != NULL) { pFcoeState->lm_fcoe.hdr.status = (mm_le32_to_cpu(kcqe->completion_status) == 0) ? STATE_STATUS_NORMAL : STATE_STATUS_INIT_OFFLOAD_ERR; } return BnxeWorkQueueAdd(pUM, BnxeFcoeDestroyConnCqeWork, &tmp_kcqe, sizeof(tmp_kcqe)); } static void BnxeFcoeDestroyConnWqeWork(um_device_t * pUM, void * pData, u32_t dataLen) { union fcoe_kwqe * kwqe = (union fcoe_kwqe *)pData; struct fcoe_kcqe kcqe = {0}; BnxeFcoeState * pFcoeState; if (dataLen != sizeof(*kwqe)) { BnxeLogWarn(pUM, "Invalid FCoE Destroy Conn WQE"); pUM->fcoe.stats.destroyConnWqeTxErr++; return; } pFcoeState = lm_cid_cookie(&pUM->lm_dev, FCOE_CONNECTION_TYPE, SW_CID(mm_le32_to_cpu(kwqe->conn_destroy.context_id))); if (pFcoeState == NULL) { goto BnxeFcoeDestroyConnWqeWork_error; } if (lm_fc_post_terminate_ramrod(&pUM->lm_dev, &pFcoeState->lm_fcoe) != LM_STATUS_SUCCESS) { goto BnxeFcoeDestroyConnWqeWork_error; } pUM->fcoe.stats.destroyConnWqeTx++; return; BnxeFcoeDestroyConnWqeWork_error: pUM->fcoe.stats.destroyConnWqeTxErr++; BnxeLogWarn(pUM, "Failed to post FCoE Destroy Conn WQE"); kcqe.op_code = FCOE_KCQE_OPCODE_DESTROY_CONN; kcqe.flags |= (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); kcqe.fcoe_conn_context_id = kwqe->conn_destroy.context_id; kcqe.fcoe_conn_id = kwqe->conn_destroy.conn_id; kcqe.completion_status = mm_cpu_to_le32(FCOE_KCQE_COMPLETION_STATUS_NIC_ERROR); /* call here directly (for error case) */ /* XXX * Need to add a mutex or reference count to ensure that bnxef isn't * unloaded underneath this taskq dispatch routine. */ { struct fcoe_kcqe * pKcqe = &kcqe; ASSERT(CLIENT_BOUND(pUM, LM_CLI_IDX_FCOE)); pUM->fcoe.bind.cliIndicateCqes(pUM->fcoe.pDev, (void **)&pKcqe, 1); } /* XXX release mutex or decrement reference count */ } static boolean_t BnxeFcoeDestroyConnWqe(um_device_t * pUM, union fcoe_kwqe ** kwqes) { return BnxeWorkQueueAdd(pUM, BnxeFcoeDestroyConnWqeWork, kwqes[0], sizeof(*(kwqes[0]))); } static void BnxeFcoeDestroyCqeWork(um_device_t * pUM, void * pData, u32_t dataLen) { if (!BnxeFcoeCqeIndicate(pUM, pData, dataLen)) { pUM->fcoe.stats.destroyCqeRxErr++; } else { pUM->fcoe.stats.destroyCqeRx++; } } boolean_t BnxeFcoeDestroyCqe(um_device_t * pUM, struct fcoe_kcqe * kcqe) { struct fcoe_kcqe tmp_kcqe = {0}; tmp_kcqe.op_code = FCOE_KCQE_OPCODE_DESTROY_FUNC; tmp_kcqe.flags |= (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); tmp_kcqe.completion_status = mm_le32_to_cpu((mm_le32_to_cpu(kcqe->completion_status) == 0) ? FCOE_KCQE_COMPLETION_STATUS_SUCCESS : FCOE_KCQE_COMPLETION_STATUS_NIC_ERROR); return BnxeWorkQueueAdd(pUM, BnxeFcoeDestroyCqeWork, &tmp_kcqe, sizeof(tmp_kcqe)); } static void BnxeFcoeDestroyWqeWork(um_device_t * pUM, void * pData, u32_t dataLen) { union fcoe_kwqe * kwqe = (union fcoe_kwqe *)pData; struct fcoe_kcqe kcqe = {0}; BnxeFcoeState * pFcoeState; if (dataLen != sizeof(*kwqe)) { BnxeLogWarn(pUM, "Invalid FCoE Destroy WQE"); pUM->fcoe.stats.destroyWqeTxErr++; return; } if (lm_fc_post_destroy_ramrod(&pUM->lm_dev) == LM_STATUS_SUCCESS) { pUM->fcoe.stats.destroyWqeTx++; return; } pUM->fcoe.stats.destroyWqeTxErr++; BnxeLogWarn(pUM, "Failed to post FCoE Destroy WQE"); kcqe.op_code = FCOE_KCQE_OPCODE_DESTROY_FUNC; kcqe.flags |= (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); kcqe.completion_status = mm_cpu_to_le32(FCOE_KCQE_COMPLETION_STATUS_NIC_ERROR); /* call here directly (for error case) */ /* XXX * Need to add a mutex or reference count to ensure that bnxef isn't * unloaded underneath this taskq dispatch routine. */ { struct fcoe_kcqe * pKcqe = &kcqe; ASSERT(CLIENT_BOUND(pUM, LM_CLI_IDX_FCOE)); pUM->fcoe.bind.cliIndicateCqes(pUM->fcoe.pDev, (void **)&pKcqe, 1); } /* XXX release mutex or decrement reference count */ } static boolean_t BnxeFcoeDestroyWqe(um_device_t * pUM, union fcoe_kwqe ** kwqes) { return BnxeWorkQueueAdd(pUM, BnxeFcoeDestroyWqeWork, kwqes[0], sizeof(*(kwqes[0]))); } static void BnxeFcoeStatCqeWork(um_device_t * pUM, void * pData, u32_t dataLen) { if (!BnxeFcoeCqeIndicate(pUM, pData, dataLen)) { pUM->fcoe.stats.statCqeRxErr++; } else { pUM->fcoe.stats.statCqeRx++; } } boolean_t BnxeFcoeStatCqe(um_device_t * pUM, struct fcoe_kcqe * kcqe) { struct fcoe_kcqe tmp_kcqe = {0}; tmp_kcqe.op_code = FCOE_KCQE_OPCODE_STAT_FUNC; tmp_kcqe.flags |= (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); tmp_kcqe.completion_status = mm_cpu_to_le32((mm_le32_to_cpu(kcqe->completion_status) == 0) ? FCOE_KCQE_COMPLETION_STATUS_SUCCESS : FCOE_KCQE_COMPLETION_STATUS_NIC_ERROR); return BnxeWorkQueueAdd(pUM, BnxeFcoeStatCqeWork, &tmp_kcqe, sizeof(tmp_kcqe)); } static void BnxeFcoeStatWqeWork(um_device_t * pUM, void * pData, u32_t dataLen) { union fcoe_kwqe * kwqe = (union fcoe_kwqe *)pData; struct fcoe_kcqe kcqe = {0}; if (dataLen != sizeof(*kwqe)) { BnxeLogWarn(pUM, "Invalid FCoE Stat WQE"); pUM->fcoe.stats.statWqeTxErr++; return; } if (lm_fc_post_stat_ramrod(&pUM->lm_dev, &kwqe->statistics) == LM_STATUS_SUCCESS) { pUM->fcoe.stats.statWqeTx++; return; } pUM->fcoe.stats.statWqeTxErr++; BnxeLogWarn(pUM, "Failed to post FCoE Stat WQE"); kcqe.op_code = FCOE_KCQE_OPCODE_STAT_FUNC; kcqe.flags |= (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); kcqe.completion_status = mm_cpu_to_le32(FCOE_KCQE_COMPLETION_STATUS_NIC_ERROR); /* call here directly (for error case) */ /* XXX * Need to add a mutex or reference count to ensure that bnxef isn't * unloaded underneath this taskq dispatch routine. */ { struct fcoe_kcqe * pKcqe = &kcqe; ASSERT(CLIENT_BOUND(pUM, LM_CLI_IDX_FCOE)); pUM->fcoe.bind.cliIndicateCqes(pUM->fcoe.pDev, (void **)&pKcqe, 1); } /* XXX release mutex or decrement reference count */ } static boolean_t BnxeFcoeStatWqe(um_device_t * pUM, union fcoe_kwqe ** kwqes) { return BnxeWorkQueueAdd(pUM, BnxeFcoeStatWqeWork, kwqes[0], sizeof(*(kwqes[0]))); } #define KCQE_LIMIT 64 static void BnxeFcoeCompRequestCqeWork(um_device_t * pUM, void * pData, u32_t dataLen) { struct fcoe_kcqe * kcqe_arr = (struct fcoe_kcqe *)pData; struct fcoe_kcqe * kcqes[KCQE_LIMIT]; u32_t num_kcqes; int i; if ((dataLen % (sizeof(*kcqe_arr))) != 0) { BnxeLogWarn(pUM, "Invalid FCoE Comp Request CQE array"); pUM->fcoe.stats.compRequestCqeRxErr++; return; } num_kcqes = (dataLen / (sizeof(*kcqe_arr))); /* init the kcqe pointer array */ for (i = 0; i < num_kcqes; i++) { kcqes[i] = &kcqe_arr[i]; } ASSERT(CLIENT_BOUND(pUM, LM_CLI_IDX_FCOE)); if (!pUM->fcoe.bind.cliIndicateCqes(pUM->fcoe.pDev, (void **)kcqes, num_kcqes)) { pUM->fcoe.stats.compRequestCqeRxErr++; } else { pUM->fcoe.stats.compRequestCqeRx += num_kcqes; } } boolean_t BnxeFcoeCompRequestCqe(um_device_t * pUM, struct fcoe_kcqe * kcqes, u32_t num_kcqes) { u32_t kcqesIdx = 0; u32_t kcqesLimit = 0; u32_t numUp; /* Send up KCQE_LIMIT kcqes at a time... */ while (kcqesIdx < num_kcqes) { if (num_kcqes - kcqesIdx > KCQE_LIMIT) { kcqesLimit += KCQE_LIMIT; } else { kcqesLimit = num_kcqes; } numUp = (kcqesLimit % KCQE_LIMIT == 0) ? KCQE_LIMIT : (kcqesLimit % KCQE_LIMIT); #if 0 if (!BnxeWorkQueueAdd(pUM, BnxeFcoeCompRequestCqeWork, kcqes + kcqesIdx, (sizeof(struct fcoe_kcqe) * numUp))) { return B_FALSE; } #else BnxeFcoeCompRequestCqeWork(pUM, kcqes + kcqesIdx, (sizeof(struct fcoe_kcqe) * numUp)); #endif kcqesIdx += (kcqesLimit - kcqesIdx); } return B_TRUE; } boolean_t BnxeFcoePrvCtl(dev_info_t * pDev, int cmd, void * pData, int dataLen) { um_device_t * pUM = (um_device_t *)ddi_get_driver_private(pDev); BnxeFcoeInfo * pFcoeInfo; int rc, i; /* sanity check */ if (pUM == NULL || pUM->pDev != pDev) { BnxeLogWarn(NULL, "%s: dev_info_t match failed", __func__); return B_FALSE; } BnxeLogDbg(pUM, "*** %s ***", __func__); VERIFY_FCOE_BINDING(pUM); switch (cmd) { case PRV_CTL_GET_MAC_ADDR: if (dataLen < ETHERNET_ADDRESS_SIZE) { BnxeLogWarn(pUM, "Invalid MAC Address buffer length for get (%d)", dataLen); return B_FALSE; } if (!pData) { BnxeLogWarn(pUM, "NULL MAC Address buffer for get"); return B_FALSE; } COPY_ETH_ADDRESS(pUM->lm_dev.hw_info.fcoe_mac_addr, pData); return B_TRUE; case PRV_CTL_SET_MAC_ADDR: if (dataLen < ETHERNET_ADDRESS_SIZE) { BnxeLogWarn(pUM, "Invalid MAC Address length for set (%d)", dataLen); return B_FALSE; } if (!pData) { BnxeLogWarn(pUM, "NULL MAC Address buffer for set"); return B_FALSE; } /* Validate MAC address */ if (IS_ETH_MULTICAST(pData)) { BnxeLogWarn(pUM, "Cannot program a mcast/bcast address as an MAC Address."); return B_FALSE; } BNXE_LOCK_ENTER_HWINIT(pUM); /* XXX wrong? (overwriting fcoe hw programmed address!) */ COPY_ETH_ADDRESS(pData, pUM->lm_dev.hw_info.fcoe_mac_addr); rc = BnxeMacAddress(pUM, LM_CLI_IDX_FCOE, B_TRUE, pUM->lm_dev.hw_info.fcoe_mac_addr); BNXE_LOCK_EXIT_HWINIT(pUM); return (rc < 0) ? B_FALSE : B_TRUE; case PRV_CTL_QUERY_PARAMS: if (dataLen != sizeof(BnxeFcoeInfo)) { BnxeLogWarn(pUM, "Invalid query buffer for FCoE (%d)", dataLen); return B_FALSE; } if (!pData) { BnxeLogWarn(pUM, "Invalid query buffer for FCoE"); return B_FALSE; } pFcoeInfo = (BnxeFcoeInfo *)pData; pFcoeInfo->flags = 0; /* * Always set the FORCE_LOAD flags which tells bnxef to perform any * necessary delays needed when bringing up targets. This allows ample * time for bnxef to come up and finish for FCoE boot. If we don't * force a delay then there is a race condition and the kernel won't * find the root disk. */ pFcoeInfo->flags |= FCOE_INFO_FLAG_FORCE_LOAD; switch (pUM->lm_dev.params.mf_mode) { case SINGLE_FUNCTION: pFcoeInfo->flags |= FCOE_INFO_FLAG_MF_MODE_SF; break; case MULTI_FUNCTION_SD: pFcoeInfo->flags |= FCOE_INFO_FLAG_MF_MODE_SD; break; case MULTI_FUNCTION_SI: pFcoeInfo->flags |= FCOE_INFO_FLAG_MF_MODE_SI; break; case MULTI_FUNCTION_AFEX: pFcoeInfo->flags |= FCOE_INFO_FLAG_MF_MODE_AFEX; break; default: break; } pFcoeInfo->max_fcoe_conn = pUM->lm_dev.params.max_func_fcoe_cons; pFcoeInfo->max_fcoe_exchanges = pUM->lm_dev.params.max_fcoe_task; memcpy(&pFcoeInfo->wwn, &pUM->fcoe.wwn, sizeof(BnxeWwnInfo)); return B_TRUE; case PRV_CTL_DISABLE_INTR: BnxeIntrIguSbDisable(pUM, FCOE_CID(&pUM->lm_dev), B_FALSE); return B_TRUE; case PRV_CTL_ENABLE_INTR: BnxeIntrIguSbEnable(pUM, FCOE_CID(&pUM->lm_dev), B_FALSE); return B_TRUE; case PRV_CTL_MBA_BOOT: if (dataLen != sizeof(boolean_t)) { BnxeLogWarn(pUM, "Invalid MBA boot check buffer for FCoE (%d)", dataLen); return B_FALSE; } if (!pData) { BnxeLogWarn(pUM, "Invalid MBA boot check buffer for FCoE"); return B_FALSE; } *((boolean_t *)pData) = (pUM->iscsiInfo.signature != 0) ? B_TRUE : B_FALSE; return B_TRUE; case PRV_CTL_LINK_STATE: if (dataLen != sizeof(boolean_t)) { BnxeLogWarn(pUM, "Invalid link state buffer for FCoE (%d)", dataLen); return B_FALSE; } if (!pData) { BnxeLogWarn(pUM, "Invalid link state buffer for FCoE"); return B_FALSE; } *((boolean_t *)pData) = (pUM->devParams.lastIndLink == LM_STATUS_LINK_ACTIVE) ? B_TRUE : B_FALSE; return B_TRUE; case PRV_CTL_BOARD_TYPE: if (!pData || (dataLen <= 0)) { BnxeLogWarn(pUM, "Invalid board type buffer for FCoE"); return B_FALSE; } snprintf((char *)pData, dataLen, "%s", pUM->chipName); return B_TRUE; case PRV_CTL_BOARD_SERNUM: if (!pData || (dataLen <= 0)) { BnxeLogWarn(pUM, "Invalid board serial number buffer for FCoE"); return B_FALSE; } snprintf((char *)pData, dataLen, "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c", pUM->lm_dev.hw_info.board_num[0], pUM->lm_dev.hw_info.board_num[1], pUM->lm_dev.hw_info.board_num[2], pUM->lm_dev.hw_info.board_num[3], pUM->lm_dev.hw_info.board_num[4], pUM->lm_dev.hw_info.board_num[5], pUM->lm_dev.hw_info.board_num[6], pUM->lm_dev.hw_info.board_num[7], pUM->lm_dev.hw_info.board_num[8], pUM->lm_dev.hw_info.board_num[9], pUM->lm_dev.hw_info.board_num[10], pUM->lm_dev.hw_info.board_num[11], pUM->lm_dev.hw_info.board_num[12], pUM->lm_dev.hw_info.board_num[13], pUM->lm_dev.hw_info.board_num[14], pUM->lm_dev.hw_info.board_num[15]); return B_TRUE; case PRV_CTL_BOOTCODE_VERSION: if (!pData || (dataLen <= 0)) { BnxeLogWarn(pUM, "Invalid boot code version buffer for FCoE"); return B_FALSE; } snprintf((char *)pData, dataLen, "%s", pUM->versionBC); return B_TRUE; case PRV_CTL_REPORT_FCOE_STATS: if (!pData || (dataLen != sizeof(pUM->lm_dev.vars.stats.stats_mirror. stats_drv.drv_info_to_mfw.fcoe_stats))) { BnxeLogWarn(pUM, "Invalid stats reporting buffer for FCoE"); return B_FALSE; } memcpy(&pUM->lm_dev.vars.stats.stats_mirror. stats_drv.drv_info_to_mfw.fcoe_stats, (fcoe_stats_info_t *)pData, sizeof(fcoe_stats_info_t)); return B_TRUE; case PRV_CTL_SET_CAPS: if (!pData || (dataLen != sizeof(struct fcoe_capabilities))) { BnxeLogWarn(pUM, "Invalid capabilities buffer for FCoE"); return B_FALSE; } memcpy(&pUM->lm_dev.vars.stats.stats_mirror.stats_drv. drv_info_to_shmem.fcoe_capabilities, pData, sizeof(pUM->lm_dev.vars.stats.stats_mirror.stats_drv. drv_info_to_shmem.fcoe_capabilities)); lm_ncsi_fcoe_cap_to_scratchpad(&pUM->lm_dev); return B_TRUE; default: BnxeLogWarn(pUM, "Unknown provider command %d", cmd); return B_FALSE; } } mblk_t * BnxeFcoePrvTx(dev_info_t * pDev, mblk_t * pMblk, u32_t flags, u16_t vlan_tag) { um_device_t * pUM = (um_device_t *)ddi_get_driver_private(pDev); lm_device_t * pLM = &pUM->lm_dev; mblk_t * pNextMblk = NULL; int txCount = 0; int rc; /* sanity check */ if (pUM == NULL || pUM->pDev != pDev) { BnxeLogWarn(NULL, "%s: dev_info_t match failed", __func__); return pMblk; } VERIFY_FCOE_BINDING(pUM); BnxeLogDbg(pUM, "*** %s ***", __func__); while (pMblk) { txCount++; pNextMblk = pMblk->b_next; pMblk->b_next = NULL; rc = BnxeTxSendMblk(pUM, FCOE_CID(pLM), pMblk, flags, vlan_tag); if (rc == BNXE_TX_GOODXMIT) { pMblk = pNextMblk; continue; } else if (rc == BNXE_TX_DEFERPKT) { pMblk = pNextMblk; } else { pMblk->b_next = pNextMblk; } break; } return pMblk; } boolean_t BnxeFcoePrvPoll(dev_info_t * pDev) { um_device_t * pUM = (um_device_t *)ddi_get_driver_private(pDev); RxQueue * pRxQ = &pUM->rxq[FCOE_CID(&pUM->lm_dev)]; u32_t idx = pRxQ->idx; /* sanity check */ if (pUM == NULL || pUM->pDev != pDev) { BnxeLogWarn(NULL, "%s: dev_info_t match failed", __func__); return B_FALSE; } VERIFY_FCOE_BINDING(pUM); BnxeLogDbg(pUM, "*** %s ***", __func__); if (pRxQ->inPollMode == B_FALSE) { BnxeLogWarn(pUM, "Polling on FCoE ring %d when NOT in poll mode!", idx); return B_FALSE; } pRxQ->pollCnt++; BnxePollRxRingFCOE(pUM); return B_TRUE; } boolean_t BnxeFcoePrvSendWqes(dev_info_t * pDev, void * wqes[], int wqeCnt) { union fcoe_kwqe ** kwqes = (union fcoe_kwqe **)wqes; int kwqeCnt = 0; um_device_t * pUM = (um_device_t *)ddi_get_driver_private(pDev); /* sanity check */ if (pUM == NULL || pUM->pDev != pDev) { BnxeLogWarn(NULL, "%s: dev_info_t match failed", __func__); return B_FALSE; } VERIFY_FCOE_BINDING(pUM); if ((kwqes == NULL) || (kwqes[0] == NULL)) { BnxeLogWarn(pUM, "Invalid WQE array"); return B_FALSE; } BnxeLogDbg(pUM, "*** %s ***", __func__); while (kwqeCnt < wqeCnt) { switch (kwqes[kwqeCnt]->init1.hdr.op_code) { case FCOE_KWQE_OPCODE_INIT1: BnxeLogDbg(pUM, "*** %s - FCOE_KWQE_OPCODE_INIT", __func__); if ((wqeCnt <= kwqeCnt + 2) || (kwqes[kwqeCnt + 1] == NULL) || (kwqes[kwqeCnt + 2] == NULL) || (kwqes[kwqeCnt + 1]->init2.hdr.op_code != FCOE_KWQE_OPCODE_INIT2) || (kwqes[kwqeCnt + 2]->init3.hdr.op_code != FCOE_KWQE_OPCODE_INIT3)) { BnxeLogWarn(pUM, "FCoE Init kwqes error"); pUM->fcoe.stats.initWqeTxErr++; return B_FALSE; } if (!BnxeFcoeInitWqe(pUM, &kwqes[kwqeCnt])) { BnxeLogWarn(pUM, "Failed to init FCoE Init WQE work"); return B_FALSE; } kwqeCnt += 3; break; case FCOE_KWQE_OPCODE_OFFLOAD_CONN1: BnxeLogDbg(pUM, "*** %s - FCOE_KWQE_OPCODE_OFFLOAD_CONN1", __func__); if ((wqeCnt <= kwqeCnt + 3) || (kwqes[kwqeCnt + 1] == NULL) || (kwqes[kwqeCnt + 2] == NULL) || (kwqes[kwqeCnt + 3] == NULL) || (kwqes[kwqeCnt + 1]->conn_offload2.hdr.op_code != FCOE_KWQE_OPCODE_OFFLOAD_CONN2) || (kwqes[kwqeCnt + 2]->conn_offload3.hdr.op_code != FCOE_KWQE_OPCODE_OFFLOAD_CONN3) || (kwqes[kwqeCnt + 3]->conn_offload4.hdr.op_code != FCOE_KWQE_OPCODE_OFFLOAD_CONN4)) { BnxeLogWarn(pUM, "FCoE Offload Conn kwqes error"); pUM->fcoe.stats.offloadConnWqeTxErr++; return B_FALSE; } if (!BnxeFcoeOffloadConnWqe(pUM, &kwqes[kwqeCnt])) { BnxeLogWarn(pUM, "Failed to init FCoE Offload Conn WQE work"); return B_FALSE; } kwqeCnt += 4; break; case FCOE_KWQE_OPCODE_ENABLE_CONN: BnxeLogDbg(pUM, "*** %s - FCOE_KWQE_OPCODE_ENABLE_CONN", __func__); if (!BnxeFcoeEnableConnWqe(pUM, &kwqes[kwqeCnt])) { BnxeLogWarn(pUM, "Failed to init FCoE Enable Conn WQE work"); return B_FALSE; } kwqeCnt += 1; break; case FCOE_KWQE_OPCODE_DISABLE_CONN: BnxeLogDbg(pUM, "*** %s - FCOE_KWQE_OPCODE_DISABLE_CONN", __func__); if (!BnxeFcoeDisableConnWqe(pUM, &kwqes[kwqeCnt])) { BnxeLogWarn(pUM, "Failed to init FCoE Disable Conn WQE work"); return B_FALSE; } kwqeCnt += 1; break; case FCOE_KWQE_OPCODE_DESTROY_CONN: BnxeLogDbg(pUM, "*** %s - FCOE_KWQE_OPCODE_DESTROY_CONN", __func__); if (!BnxeFcoeDestroyConnWqe(pUM, &kwqes[kwqeCnt])) { BnxeLogWarn(pUM, "Failed to init FCoE Destroy Conn WQE work"); return B_FALSE; } kwqeCnt += 1; break; case FCOE_KWQE_OPCODE_DESTROY: BnxeLogDbg(pUM, "*** %s - FCOE_KWQE_OPCODE_DESTROY", __func__); if (!BnxeFcoeDestroyWqe(pUM, &kwqes[kwqeCnt])) { BnxeLogWarn(pUM, "Failed to init FCoE Destroy WQE work"); return B_FALSE; } kwqeCnt += 1; break; case FCOE_KWQE_OPCODE_STAT: BnxeLogDbg(pUM, "*** %s - FCOE_KWQE_OPCODE_STAT", __func__); if (!BnxeFcoeStatWqe(pUM, &kwqes[kwqeCnt])) { BnxeLogWarn(pUM, "Failed to init FCoE Stat WQE work"); return B_FALSE; } kwqeCnt += 1; break; default: BnxeDbgBreakMsg(pUM, "Invalid KWQE opcode"); return B_FALSE; } } return B_TRUE; } boolean_t BnxeFcoePrvMapMailboxq(dev_info_t * pDev, u32_t cid, void ** ppMap, ddi_acc_handle_t * pAccHandle) { um_device_t * pUM = (um_device_t *)ddi_get_driver_private(pDev); /* sanity check */ if (pUM == NULL || pUM->pDev != pDev) { BnxeLogWarn(NULL, "%s: dev_info_t match failed", __func__); return B_FALSE; } VERIFY_FCOE_BINDING(pUM); BnxeLogDbg(pUM, "*** %s ***", __func__); /* get the right offset from the mapped bar */ *ppMap = (void *)((u8_t *)pUM->lm_dev.context_info->array[SW_CID(cid)].cid_resc.mapped_cid_bar_addr + DPM_TRIGER_TYPE); *pAccHandle = pUM->lm_dev.context_info->array[SW_CID(cid)].cid_resc.reg_handle; if (!(*ppMap) || !(*pAccHandle)) { BnxeLogWarn(pUM, "Cannot map mailboxq base address for FCoE"); return B_FALSE; } return B_TRUE; } boolean_t BnxeFcoePrvUnmapMailboxq(dev_info_t * pDev, u32_t cid, void * pMap, ddi_acc_handle_t accHandle) { um_device_t * pUM = (um_device_t *)ddi_get_driver_private(pDev); void * pTmp; ddi_acc_handle_t tmpAcc; /* sanity check */ if (pUM == NULL || pUM->pDev != pDev) { BnxeLogWarn(NULL, "%s: dev_info_t match failed", __func__); return B_FALSE; } VERIFY_FCOE_BINDING(pUM); BnxeLogDbg(pUM, "*** %s ***", __func__); /* verify the mapped bar address */ pTmp = (void *)((u8_t *)pUM->lm_dev.context_info->array[SW_CID(cid)].cid_resc.mapped_cid_bar_addr + DPM_TRIGER_TYPE); tmpAcc = pUM->lm_dev.context_info->array[SW_CID(cid)].cid_resc.reg_handle; if ((pMap != pTmp) || (accHandle != tmpAcc)) { BnxeLogWarn(pUM, "Invalid map info for FCoE (%p)", pMap); return B_FALSE; } return B_TRUE; } int BnxeFcoeInit(um_device_t * pUM) { char * pCompat[2] = { BNXEF_NAME, NULL }; char name[256]; int rc; BnxeLogInfo(pUM, "Starting FCoE"); if (!BNXE_FCOE(pUM)) { BnxeLogWarn(pUM, "FCoE not supported on this device"); return ENOTSUP; } //if (CLIENT_DEVI(pUM, LM_CLI_IDX_FCOE)) if (pUM->fcoe.pDev) { BnxeLogWarn(pUM, "FCoE child node already initialized"); return EEXIST; } if (ndi_devi_alloc(pUM->pDev, BNXEF_NAME, DEVI_PSEUDO_NODEID, &pUM->fcoe.pDev) != NDI_SUCCESS) { BnxeLogWarn(pUM, "Failed to allocate a child node for FCoE"); pUM->fcoe.pDev = NULL; return ENOMEM; } if (ndi_prop_update_string_array(DDI_DEV_T_NONE, pUM->fcoe.pDev, "name", pCompat, 1) != DDI_PROP_SUCCESS) { BnxeLogWarn(pUM, "Failed to set the name string for FCoE"); /* XXX see other call to ndi_devi_free below */ //ndi_devi_free(pUM->fcoe.pDev); pUM->fcoe.pDev = NULL; return ENOENT; } CLIENT_DEVI_SET(pUM, LM_CLI_IDX_FCOE); /* * XXX If/when supporting custom wwn's then prime them * here in so they will be passed to bnxef during BINDING. * Ideally custom wwn's will be set via the driver .conf * file and via a private driver property. */ memset(&pUM->fcoe.wwn, 0, sizeof(BnxeWwnInfo)); pUM->fcoe.wwn.fcp_pwwn_provided = B_TRUE; memcpy(pUM->fcoe.wwn.fcp_pwwn, pUM->lm_dev.hw_info.fcoe_wwn_port_name, BNXE_FCOE_WWN_SIZE); pUM->fcoe.wwn.fcp_nwwn_provided = B_TRUE; memcpy(pUM->fcoe.wwn.fcp_nwwn, pUM->lm_dev.hw_info.fcoe_wwn_node_name, BNXE_FCOE_WWN_SIZE); BnxeLogInfo(pUM, "Created the FCoE child node %s@%s", BNXEF_NAME, ddi_get_name_addr(pUM->pDev)); if ((rc = ndi_devi_online(pUM->fcoe.pDev, NDI_ONLINE_ATTACH)) != NDI_SUCCESS) { /* XXX * ndi_devi_free will cause a panic. Don't know why and we've * verified that Sun's FCoE driver does not free it either. */ //ndi_devi_free(pUM->fcoe.pDev); CLIENT_DEVI_RESET(pUM, LM_CLI_IDX_FCOE); pUM->fcoe.pDev = NULL; BnxeLogInfo(pUM, "Unable to bind the QLogic FCoE driver (%d)", rc); return ECHILD; } #if 0 /* bring bnxef online and attach it */ if (ndi_devi_bind_driver(pUM->fcoe.pDev, 0) != NDI_SUCCESS) { BnxeLogInfo(pUM, "Unable to bind the QLogic FCoE driver"); } #endif return 0; } int BnxeFcoeFini(um_device_t * pUM) { int rc = 0; int nullDev = B_FALSE; /* false = wait for bnxef UNBIND */ BnxeLogInfo(pUM, "Stopping FCoE"); if (!BNXE_FCOE(pUM)) { BnxeLogWarn(pUM, "FCoE not supported on this device"); return ENOTSUP; } if (CLIENT_BOUND(pUM, LM_CLI_IDX_FCOE)) { if (pUM->fcoe.pDev == NULL) { BnxeLogWarn(pUM, "FCoE Client bound and pDev is NULL, FINI failed! %s@%s", BNXEF_NAME, ddi_get_name_addr(pUM->pDev)); return ENOENT; } else if (pUM->fcoe.bind.cliCtl == NULL) { BnxeLogWarn(pUM, "FCoE Client bound and cliCtl is NULL, FINI failed! %s@%s", BNXEF_NAME, ddi_get_name_addr(pUM->pDev)); return ENOENT; } else if (pUM->fcoe.bind.cliCtl(pUM->fcoe.pDev, CLI_CTL_UNLOAD, NULL, 0) == B_FALSE) { BnxeLogWarn(pUM, "FCoE Client bound and UNLOAD failed! %s@%s", BNXEF_NAME, ddi_get_name_addr(pUM->pDev)); return ENOMSG; /* no graceful unload with bnxef */ } } else { rc = ENODEV; nullDev = B_TRUE; } /* * There are times when delete-port doesn't fully work and bnxef is unable * to detach and never calls UNBIND. So here we'll just make sure that * the child dev node is not NULL which semi-gaurantees the UNBIND hasn't * been called yet. Multiple offline calls will hopefully kick bnxef... */ //if (CLIENT_DEVI(pUM, LM_CLI_IDX_FCOE)) if (pUM->fcoe.pDev) { CLIENT_DEVI_RESET(pUM, LM_CLI_IDX_FCOE); BnxeLogWarn(pUM, "Bringing down QLogic FCoE driver %s@%s", BNXEF_NAME, ddi_get_name_addr(pUM->pDev)); #if 1 if (ndi_devi_offline(pUM->fcoe.pDev, NDI_DEVI_REMOVE) != NDI_SUCCESS) { BnxeLogWarn(pUM, "Failed to bring the QLogic FCoE driver offline %s@%s", BNXEF_NAME, ddi_get_name_addr(pUM->pDev)); return EBUSY; } #else ndi_devi_offline(pUM->fcoe.pDev, NDI_DEVI_REMOVE); if (nullDev) pUM->fcoe.pDev = NULL; #endif memset(&pUM->fcoe.wwn, 0, sizeof(BnxeWwnInfo)); BnxeLogInfo(pUM, "Destroyed the FCoE child node %s@%s", BNXEF_NAME, ddi_get_name_addr(pUM->pDev)); } return rc; } void BnxeFcoeStartStop(um_device_t * pUM) { int rc; if (!BNXE_FCOE(pUM)) { BnxeLogWarn(pUM, "FCoE is not supported on this device"); return; } if (pUM->devParams.fcoeEnable) { BnxeFcoeInit(pUM); } else { BnxeFcoeFini(pUM); } }