9fac68fc38
It includes: 1)Newly added TMF feature. 2)Added newly Huawei & Inspur PCI ID's 3)Fixed smartpqi driver hangs in Z-Pool while running on FreeBSD12.1 4)Fixed flooding dmesg in kernel while the controller is offline during in ioctls. 5)Avoided unnecessary host memory allocation for rcb sg buffers. 6)Fixed race conditions while accessing internal rcb structure. 7)Fixed where Logical volumes exposing two different names to the OS it's due to the system memory is overwritten with DMA stale data. 8)Fixed dynamically unloading a smartpqi driver. 9)Added device_shutdown callback instead of deprecated shutdown_final kernel event in smartpqi driver. 10)Fixed where Os is crashed during physical drive hot removal during heavy IO. 11)Fixed OS crash during controller lockup/offline during heavy IO. 12)Fixed coverity issues in smartpqi driver 13)Fixed system crash while creating and deleting logical volume in a continuous loop. 14)Fixed where the volume size is not exposing to OS when it expands. 15)Added HC3 pci id's. Reviewed by: Scott Benesh (microsemi), Murthy Bhat (microsemi), imp Differential Revision: https://reviews.freebsd.org/D30182 Sponsored by: Netflix
1024 lines
29 KiB
C
1024 lines
29 KiB
C
/*-
|
|
* Copyright 2016-2021 Microchip Technology, Inc. and/or its subsidiaries.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*/
|
|
|
|
/* $FreeBSD$ */
|
|
|
|
#include "smartpqi_includes.h"
|
|
|
|
/*
|
|
* Submit an admin IU to the adapter.
|
|
* Add interrupt support, if required
|
|
*/
|
|
int
|
|
pqisrc_submit_admin_req(pqisrc_softstate_t *softs,
|
|
gen_adm_req_iu_t *req, gen_adm_resp_iu_t *resp)
|
|
{
|
|
int ret = PQI_STATUS_SUCCESS;
|
|
ob_queue_t *ob_q = &softs->admin_ob_queue;
|
|
ib_queue_t *ib_q = &softs->admin_ib_queue;
|
|
int tmo = PQISRC_ADMIN_CMD_RESP_TIMEOUT;
|
|
|
|
DBG_FUNC("IN\n");
|
|
|
|
req->header.iu_type =
|
|
PQI_IU_TYPE_GENERAL_ADMIN_REQUEST;
|
|
req->header.comp_feature = 0x00;
|
|
req->header.iu_length = PQI_STANDARD_IU_LENGTH;
|
|
req->res1 = 0;
|
|
req->work = 0;
|
|
|
|
/* Get the tag */
|
|
req->req_id = pqisrc_get_tag(&softs->taglist);
|
|
if (INVALID_ELEM == req->req_id) {
|
|
DBG_ERR("Tag not available0x%x\n",(uint16_t)req->req_id);
|
|
ret = PQI_STATUS_FAILURE;
|
|
goto err_out;
|
|
}
|
|
softs->rcb[req->req_id].tag = req->req_id;
|
|
|
|
/* Submit the command to the admin ib queue */
|
|
ret = pqisrc_submit_cmnd(softs, ib_q, req);
|
|
if (ret != PQI_STATUS_SUCCESS) {
|
|
DBG_ERR("Unable to submit command\n");
|
|
goto err_cmd;
|
|
}
|
|
|
|
/* Wait for completion */
|
|
COND_WAIT((*(ob_q->pi_virt_addr) != ob_q->ci_local), tmo);
|
|
if (tmo <= 0) {
|
|
DBG_ERR("Admin cmd timeout\n");
|
|
DBG_ERR("tmo : %d\n",tmo); \
|
|
/* TODO : PQI device status and error register and report */
|
|
ret = PQI_STATUS_TIMEOUT;
|
|
goto err_cmd;
|
|
}
|
|
|
|
/* Copy the response */
|
|
memcpy(resp, ob_q->array_virt_addr + (ob_q->ci_local * ob_q->elem_size),
|
|
sizeof(gen_adm_resp_iu_t));
|
|
|
|
/* Update CI */
|
|
ob_q->ci_local = (ob_q->ci_local + 1 ) % ob_q->num_elem;
|
|
PCI_MEM_PUT32(softs, ob_q->ci_register_abs,
|
|
ob_q->ci_register_offset, LE_32(ob_q->ci_local));
|
|
|
|
/* Validate the response data */
|
|
ASSERT(req->fn_code == resp->fn_code);
|
|
ASSERT(resp->header.iu_type == PQI_IU_TYPE_GENERAL_ADMIN_RESPONSE);
|
|
ret = resp->status;
|
|
if (ret)
|
|
goto err_cmd;
|
|
|
|
os_reset_rcb(&softs->rcb[req->req_id]);
|
|
pqisrc_put_tag(&softs->taglist,req->req_id);
|
|
DBG_FUNC("OUT\n");
|
|
return ret;
|
|
err_cmd:
|
|
os_reset_rcb(&softs->rcb[req->req_id]);
|
|
pqisrc_put_tag(&softs->taglist,req->req_id);
|
|
err_out:
|
|
DBG_FUNC("failed OUT : %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Get the administration queue config parameters.
|
|
*/
|
|
void
|
|
pqisrc_get_admin_queue_config(pqisrc_softstate_t *softs)
|
|
{
|
|
uint64_t val = 0;
|
|
|
|
|
|
val = LE_64(PCI_MEM_GET64(softs, &softs->pqi_reg->pqi_dev_adminq_cap, PQI_ADMINQ_CAP));
|
|
|
|
/* pqi_cap = (struct pqi_dev_adminq_cap *)&val;*/
|
|
softs->admin_ib_queue.num_elem = val & 0xFF;
|
|
softs->admin_ob_queue.num_elem = (val & 0xFF00) >> 8;
|
|
/* Note : size in unit of 16 byte s*/
|
|
softs->admin_ib_queue.elem_size = ((val & 0xFF0000) >> 16) * 16;
|
|
softs->admin_ob_queue.elem_size = ((val & 0xFF000000) >> 24) * 16;
|
|
|
|
DBG_FUNC(" softs->admin_ib_queue.num_elem : %d\n",
|
|
softs->admin_ib_queue.num_elem);
|
|
DBG_FUNC(" softs->admin_ib_queue.elem_size : %d\n",
|
|
softs->admin_ib_queue.elem_size);
|
|
}
|
|
|
|
/*
|
|
* Decide the no of elements in admin ib and ob queues.
|
|
*/
|
|
void
|
|
pqisrc_decide_admin_queue_config(pqisrc_softstate_t *softs)
|
|
{
|
|
/* Determine num elements in Admin IBQ */
|
|
softs->admin_ib_queue.num_elem = MIN(softs->admin_ib_queue.num_elem,
|
|
PQISRC_MAX_ADMIN_IB_QUEUE_ELEM_NUM);
|
|
|
|
/* Determine num elements in Admin OBQ */
|
|
softs->admin_ob_queue.num_elem = MIN(softs->admin_ob_queue.num_elem,
|
|
PQISRC_MAX_ADMIN_OB_QUEUE_ELEM_NUM);
|
|
}
|
|
|
|
/*
|
|
* Allocate DMA memory for admin queue and initialize.
|
|
*/
|
|
int
|
|
pqisrc_allocate_and_init_adminq(pqisrc_softstate_t *softs)
|
|
{
|
|
uint32_t ib_array_size = 0;
|
|
uint32_t ob_array_size = 0;
|
|
uint32_t alloc_size = 0;
|
|
char *virt_addr = NULL;
|
|
dma_addr_t dma_addr = 0;
|
|
int ret = PQI_STATUS_SUCCESS;
|
|
|
|
ib_array_size = (softs->admin_ib_queue.num_elem *
|
|
softs->admin_ib_queue.elem_size);
|
|
|
|
ob_array_size = (softs->admin_ob_queue.num_elem *
|
|
softs->admin_ob_queue.elem_size);
|
|
|
|
alloc_size = ib_array_size + ob_array_size +
|
|
2 * sizeof(uint32_t) + PQI_ADDR_ALIGN_MASK_64 + 1; /* for IB CI and OB PI */
|
|
/* Allocate memory for Admin Q */
|
|
softs->admin_queue_dma_mem.tag = "admin_queue";
|
|
softs->admin_queue_dma_mem.size = alloc_size;
|
|
softs->admin_queue_dma_mem.align = PQI_ADMINQ_ELEM_ARRAY_ALIGN;
|
|
ret = os_dma_mem_alloc(softs, &softs->admin_queue_dma_mem);
|
|
if (ret) {
|
|
DBG_ERR("Failed to Allocate Admin Q ret : %d\n", ret);
|
|
goto err_out;
|
|
}
|
|
|
|
/* Setup the address */
|
|
virt_addr = softs->admin_queue_dma_mem.virt_addr;
|
|
dma_addr = softs->admin_queue_dma_mem.dma_addr;
|
|
|
|
/* IB */
|
|
softs->admin_ib_queue.q_id = 0;
|
|
softs->admin_ib_queue.array_virt_addr = virt_addr;
|
|
softs->admin_ib_queue.array_dma_addr = dma_addr;
|
|
softs->admin_ib_queue.pi_local = 0;
|
|
/* OB */
|
|
softs->admin_ob_queue.q_id = 0;
|
|
softs->admin_ob_queue.array_virt_addr = virt_addr + ib_array_size;
|
|
softs->admin_ob_queue.array_dma_addr = dma_addr + ib_array_size;
|
|
softs->admin_ob_queue.ci_local = 0;
|
|
|
|
/* IB CI */
|
|
softs->admin_ib_queue.ci_virt_addr =
|
|
(uint32_t*)((uint8_t*)softs->admin_ob_queue.array_virt_addr
|
|
+ ob_array_size);
|
|
softs->admin_ib_queue.ci_dma_addr =
|
|
(dma_addr_t)((uint8_t*)softs->admin_ob_queue.array_dma_addr +
|
|
ob_array_size);
|
|
|
|
/* OB PI */
|
|
softs->admin_ob_queue.pi_virt_addr =
|
|
(uint32_t*)((uint8_t*)(softs->admin_ib_queue.ci_virt_addr) +
|
|
PQI_ADDR_ALIGN_MASK_64 + 1);
|
|
softs->admin_ob_queue.pi_dma_addr =
|
|
(dma_addr_t)((uint8_t*)(softs->admin_ib_queue.ci_dma_addr) +
|
|
PQI_ADDR_ALIGN_MASK_64 + 1);
|
|
|
|
DBG_INIT("softs->admin_ib_queue.ci_dma_addr : %p,softs->admin_ob_queue.pi_dma_addr :%p\n",
|
|
(void*)softs->admin_ib_queue.ci_dma_addr, (void*)softs->admin_ob_queue.pi_dma_addr );
|
|
|
|
/* Verify alignment */
|
|
ASSERT(!(softs->admin_ib_queue.array_dma_addr &
|
|
PQI_ADDR_ALIGN_MASK_64));
|
|
ASSERT(!(softs->admin_ib_queue.ci_dma_addr &
|
|
PQI_ADDR_ALIGN_MASK_64));
|
|
ASSERT(!(softs->admin_ob_queue.array_dma_addr &
|
|
PQI_ADDR_ALIGN_MASK_64));
|
|
ASSERT(!(softs->admin_ob_queue.pi_dma_addr &
|
|
PQI_ADDR_ALIGN_MASK_64));
|
|
|
|
DBG_FUNC("OUT\n");
|
|
return ret;
|
|
|
|
err_out:
|
|
DBG_FUNC("failed OUT\n");
|
|
return PQI_STATUS_FAILURE;
|
|
}
|
|
|
|
/*
|
|
* Subroutine used to create (or) delete the admin queue requested.
|
|
*/
|
|
int
|
|
pqisrc_create_delete_adminq(pqisrc_softstate_t *softs, uint32_t cmd)
|
|
{
|
|
int tmo = 0;
|
|
int ret = PQI_STATUS_SUCCESS;
|
|
|
|
/* Create Admin Q pair writing to Admin Q config function reg */
|
|
|
|
PCI_MEM_PUT64(softs, &softs->pqi_reg->admin_q_config, PQI_ADMINQ_CONFIG, LE_64(cmd));
|
|
|
|
if (cmd == PQI_ADMIN_QUEUE_CONF_FUNC_CREATE_Q_PAIR)
|
|
tmo = PQISRC_ADMIN_QUEUE_CREATE_TIMEOUT;
|
|
else
|
|
tmo = PQISRC_ADMIN_QUEUE_DELETE_TIMEOUT;
|
|
|
|
/* Wait for completion */
|
|
COND_WAIT((PCI_MEM_GET64(softs, &softs->pqi_reg->admin_q_config, PQI_ADMINQ_CONFIG) ==
|
|
PQI_ADMIN_QUEUE_CONF_FUNC_STATUS_IDLE), tmo);
|
|
if (tmo <= 0) {
|
|
DBG_ERR("Unable to create/delete admin queue pair\n");
|
|
/* TODO : PQI device status and error register and report */
|
|
ret = PQI_STATUS_TIMEOUT;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Debug admin queue configuration params.
|
|
*/
|
|
void
|
|
pqisrc_print_adminq_config(pqisrc_softstate_t *softs)
|
|
{
|
|
DBG_INFO(" softs->admin_ib_queue.array_dma_addr : %p\n",
|
|
(void*)softs->admin_ib_queue.array_dma_addr);
|
|
DBG_INFO(" softs->admin_ib_queue.array_virt_addr : %p\n",
|
|
(void*)softs->admin_ib_queue.array_virt_addr);
|
|
DBG_INFO(" softs->admin_ib_queue.num_elem : %d\n",
|
|
softs->admin_ib_queue.num_elem);
|
|
DBG_INFO(" softs->admin_ib_queue.elem_size : %d\n",
|
|
softs->admin_ib_queue.elem_size);
|
|
DBG_INFO(" softs->admin_ob_queue.array_dma_addr : %p\n",
|
|
(void*)softs->admin_ob_queue.array_dma_addr);
|
|
DBG_INFO(" softs->admin_ob_queue.array_virt_addr : %p\n",
|
|
(void*)softs->admin_ob_queue.array_virt_addr);
|
|
DBG_INFO(" softs->admin_ob_queue.num_elem : %d\n",
|
|
softs->admin_ob_queue.num_elem);
|
|
DBG_INFO(" softs->admin_ob_queue.elem_size : %d\n",
|
|
softs->admin_ob_queue.elem_size);
|
|
DBG_INFO(" softs->admin_ib_queue.pi_register_abs : %p\n",
|
|
(void*)softs->admin_ib_queue.pi_register_abs);
|
|
DBG_INFO(" softs->admin_ob_queue.ci_register_abs : %p\n",
|
|
(void*)softs->admin_ob_queue.ci_register_abs);
|
|
}
|
|
|
|
/*
|
|
* Function used to create an admin queue.
|
|
*/
|
|
int
|
|
pqisrc_create_admin_queue(pqisrc_softstate_t *softs)
|
|
{
|
|
int ret = PQI_STATUS_SUCCESS;
|
|
uint32_t admin_q_param = 0;
|
|
|
|
DBG_FUNC("IN\n");
|
|
|
|
/* Get admin queue details - pqi2-r00a - table 24 */
|
|
pqisrc_get_admin_queue_config(softs);
|
|
|
|
/* Decide admin Q config */
|
|
pqisrc_decide_admin_queue_config(softs);
|
|
|
|
/* Allocate and init Admin Q pair */
|
|
ret = pqisrc_allocate_and_init_adminq(softs);
|
|
if (ret) {
|
|
DBG_ERR("Failed to Allocate Admin Q ret : %d\n", ret);
|
|
goto err_out;
|
|
}
|
|
|
|
/* Write IB Q element array address */
|
|
PCI_MEM_PUT64(softs, &softs->pqi_reg->admin_ibq_elem_array_addr,
|
|
PQI_ADMIN_IBQ_ELEM_ARRAY_ADDR, LE_64(softs->admin_ib_queue.array_dma_addr));
|
|
|
|
/* Write OB Q element array address */
|
|
PCI_MEM_PUT64(softs, &softs->pqi_reg->admin_obq_elem_array_addr,
|
|
PQI_ADMIN_OBQ_ELEM_ARRAY_ADDR, LE_64(softs->admin_ob_queue.array_dma_addr));
|
|
|
|
/* Write IB Q CI address */
|
|
PCI_MEM_PUT64(softs, &softs->pqi_reg->admin_ibq_ci_addr,
|
|
PQI_ADMIN_IBQ_CI_ADDR, LE_64(softs->admin_ib_queue.ci_dma_addr));
|
|
|
|
/* Write OB Q PI address */
|
|
PCI_MEM_PUT64(softs, &softs->pqi_reg->admin_obq_pi_addr,
|
|
PQI_ADMIN_OBQ_PI_ADDR, LE_64(softs->admin_ob_queue.pi_dma_addr));
|
|
|
|
|
|
/* Write Admin Q params pqi-r200a table 36 */
|
|
|
|
admin_q_param = softs->admin_ib_queue.num_elem |
|
|
(softs->admin_ob_queue.num_elem << 8)|
|
|
PQI_ADMIN_QUEUE_MSIX_DISABLE;
|
|
|
|
PCI_MEM_PUT32(softs, &softs->pqi_reg->admin_q_param,
|
|
PQI_ADMINQ_PARAM, LE_32(admin_q_param));
|
|
|
|
/* Submit cmd to create Admin Q pair */
|
|
ret = pqisrc_create_delete_adminq(softs,
|
|
PQI_ADMIN_QUEUE_CONF_FUNC_CREATE_Q_PAIR);
|
|
if (ret) {
|
|
DBG_ERR("Failed to Allocate Admin Q ret : %d\n", ret);
|
|
goto err_q_create;
|
|
}
|
|
|
|
/* Admin queue created, get ci,pi offset */
|
|
softs->admin_ib_queue.pi_register_offset =(PQISRC_PQI_REG_OFFSET +
|
|
PCI_MEM_GET64(softs, &softs->pqi_reg->admin_ibq_pi_offset, PQI_ADMIN_IBQ_PI_OFFSET));
|
|
|
|
softs->admin_ib_queue.pi_register_abs =(uint32_t *)(softs->pci_mem_base_vaddr +
|
|
softs->admin_ib_queue.pi_register_offset);
|
|
|
|
softs->admin_ob_queue.ci_register_offset = (PQISRC_PQI_REG_OFFSET +
|
|
PCI_MEM_GET64(softs, &softs->pqi_reg->admin_obq_ci_offset, PQI_ADMIN_OBQ_CI_OFFSET));
|
|
|
|
softs->admin_ob_queue.ci_register_abs = (uint32_t *)(softs->pci_mem_base_vaddr +
|
|
softs->admin_ob_queue.ci_register_offset);
|
|
|
|
os_strlcpy(softs->admin_ib_queue.lockname, "admin_ibqlock", LOCKNAME_SIZE);
|
|
|
|
ret =OS_INIT_PQILOCK(softs, &softs->admin_ib_queue.lock,
|
|
softs->admin_ib_queue.lockname);
|
|
if(ret){
|
|
DBG_ERR("Admin spinlock initialization failed\n");
|
|
softs->admin_ib_queue.lockcreated = false;
|
|
goto err_lock;
|
|
}
|
|
softs->admin_ib_queue.lockcreated = true;
|
|
|
|
/* Print admin q config details */
|
|
pqisrc_print_adminq_config(softs);
|
|
|
|
DBG_FUNC("OUT\n");
|
|
return ret;
|
|
|
|
err_lock:
|
|
err_q_create:
|
|
os_dma_mem_free(softs, &softs->admin_queue_dma_mem);
|
|
err_out:
|
|
DBG_FUNC("failed OUT\n");
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Subroutine used to delete an operational queue.
|
|
*/
|
|
int
|
|
pqisrc_delete_op_queue(pqisrc_softstate_t *softs,
|
|
uint32_t q_id, boolean_t ibq)
|
|
{
|
|
int ret = PQI_STATUS_SUCCESS;
|
|
/* Firmware doesn't support this now */
|
|
|
|
#if 0
|
|
gen_adm_req_iu_t admin_req;
|
|
gen_adm_resp_iu_t admin_resp;
|
|
|
|
|
|
memset(&admin_req, 0, sizeof(admin_req));
|
|
memset(&admin_resp, 0, sizeof(admin_resp));
|
|
|
|
DBG_FUNC("IN\n");
|
|
|
|
admin_req.req_type.create_op_iq.qid = q_id;
|
|
|
|
if (ibq)
|
|
admin_req.fn_code = PQI_FUNCTION_DELETE_OPERATIONAL_IQ;
|
|
else
|
|
admin_req.fn_code = PQI_FUNCTION_DELETE_OPERATIONAL_OQ;
|
|
|
|
|
|
ret = pqisrc_submit_admin_req(softs, &admin_req, &admin_resp);
|
|
|
|
DBG_FUNC("OUT\n");
|
|
#endif
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Function used to destroy the event queue.
|
|
*/
|
|
void
|
|
pqisrc_destroy_event_queue(pqisrc_softstate_t *softs)
|
|
{
|
|
DBG_FUNC("IN\n");
|
|
|
|
if (softs->event_q.created == true) {
|
|
int ret = PQI_STATUS_SUCCESS;
|
|
ret = pqisrc_delete_op_queue(softs, softs->event_q.q_id, false);
|
|
if (ret) {
|
|
DBG_ERR("Failed to Delete Event Q %d\n", softs->event_q.q_id);
|
|
}
|
|
softs->event_q.created = false;
|
|
}
|
|
|
|
/* Free the memory */
|
|
os_dma_mem_free(softs, &softs->event_q_dma_mem);
|
|
|
|
DBG_FUNC("OUT\n");
|
|
}
|
|
|
|
/*
|
|
* Function used to destroy operational ib queues.
|
|
*/
|
|
void
|
|
pqisrc_destroy_op_ib_queues(pqisrc_softstate_t *softs)
|
|
{
|
|
int ret = PQI_STATUS_SUCCESS;
|
|
ib_queue_t *op_ib_q = NULL;
|
|
int i;
|
|
|
|
DBG_FUNC("IN\n");
|
|
|
|
for (i = 0; i < softs->num_op_raid_ibq; i++) {
|
|
/* OP RAID IB Q */
|
|
op_ib_q = &softs->op_raid_ib_q[i];
|
|
if (op_ib_q->created == true) {
|
|
ret = pqisrc_delete_op_queue(softs, op_ib_q->q_id, true);
|
|
if (ret) {
|
|
DBG_ERR("Failed to Delete Raid IB Q %d\n",op_ib_q->q_id);
|
|
}
|
|
op_ib_q->created = false;
|
|
}
|
|
|
|
if(op_ib_q->lockcreated==true){
|
|
OS_UNINIT_PQILOCK(&op_ib_q->lock);
|
|
op_ib_q->lockcreated = false;
|
|
}
|
|
|
|
/* OP AIO IB Q */
|
|
op_ib_q = &softs->op_aio_ib_q[i];
|
|
if (op_ib_q->created == true) {
|
|
ret = pqisrc_delete_op_queue(softs, op_ib_q->q_id, true);
|
|
if (ret) {
|
|
DBG_ERR("Failed to Delete AIO IB Q %d\n",op_ib_q->q_id);
|
|
}
|
|
op_ib_q->created = false;
|
|
}
|
|
|
|
if(op_ib_q->lockcreated==true){
|
|
OS_UNINIT_PQILOCK(&op_ib_q->lock);
|
|
op_ib_q->lockcreated = false;
|
|
}
|
|
}
|
|
|
|
/* Free the memory */
|
|
os_dma_mem_free(softs, &softs->op_ibq_dma_mem);
|
|
DBG_FUNC("OUT\n");
|
|
}
|
|
|
|
/*
|
|
* Function used to destroy operational ob queues.
|
|
*/
|
|
void
|
|
pqisrc_destroy_op_ob_queues(pqisrc_softstate_t *softs)
|
|
{
|
|
int ret = PQI_STATUS_SUCCESS;
|
|
int i;
|
|
|
|
DBG_FUNC("IN\n");
|
|
|
|
for (i = 0; i < softs->num_op_obq; i++) {
|
|
ob_queue_t *op_ob_q = NULL;
|
|
op_ob_q = &softs->op_ob_q[i];
|
|
if (op_ob_q->created == true) {
|
|
ret = pqisrc_delete_op_queue(softs, op_ob_q->q_id, false);
|
|
if (ret) {
|
|
DBG_ERR("Failed to Delete OB Q %d\n",op_ob_q->q_id);
|
|
}
|
|
op_ob_q->created = false;
|
|
}
|
|
}
|
|
|
|
/* Free the memory */
|
|
os_dma_mem_free(softs, &softs->op_obq_dma_mem);
|
|
DBG_FUNC("OUT\n");
|
|
}
|
|
|
|
/*
|
|
* Function used to destroy an admin queue.
|
|
*/
|
|
int
|
|
pqisrc_destroy_admin_queue(pqisrc_softstate_t *softs)
|
|
{
|
|
int ret = PQI_STATUS_SUCCESS;
|
|
|
|
DBG_FUNC("IN\n");
|
|
#if 0
|
|
ret = pqisrc_create_delete_adminq(softs,
|
|
PQI_ADMIN_QUEUE_CONF_FUNC_DEL_Q_PAIR);
|
|
#endif
|
|
os_dma_mem_free(softs, &softs->admin_queue_dma_mem);
|
|
|
|
DBG_FUNC("OUT\n");
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Function used to change operational ib queue properties.
|
|
*/
|
|
int
|
|
pqisrc_change_op_ibq_queue_prop(pqisrc_softstate_t *softs,
|
|
ib_queue_t *op_ib_q, uint32_t prop)
|
|
{
|
|
int ret = PQI_STATUS_SUCCESS;
|
|
gen_adm_req_iu_t admin_req;
|
|
gen_adm_resp_iu_t admin_resp;
|
|
|
|
memset(&admin_req, 0, sizeof(admin_req));
|
|
memset(&admin_resp, 0, sizeof(admin_resp));
|
|
|
|
DBG_FUNC("IN\n");
|
|
|
|
admin_req.fn_code = PQI_FUNCTION_CHANGE_OPERATIONAL_IQ_PROP;
|
|
admin_req.req_type.change_op_iq_prop.qid = op_ib_q->q_id;
|
|
admin_req.req_type.change_op_iq_prop.vend_specific = prop;
|
|
|
|
ret = pqisrc_submit_admin_req(softs, &admin_req, &admin_resp);
|
|
|
|
DBG_FUNC("OUT\n");
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Function used to create an operational ob queue.
|
|
*/
|
|
int
|
|
pqisrc_create_op_obq(pqisrc_softstate_t *softs,
|
|
ob_queue_t *op_ob_q)
|
|
{
|
|
int ret = PQI_STATUS_SUCCESS;
|
|
gen_adm_req_iu_t admin_req;
|
|
gen_adm_resp_iu_t admin_resp;
|
|
|
|
DBG_FUNC("IN\n");
|
|
|
|
memset(&admin_req, 0, sizeof(admin_req));
|
|
memset(&admin_resp, 0, sizeof(admin_resp));
|
|
|
|
admin_req.fn_code = PQI_FUNCTION_CREATE_OPERATIONAL_OQ;
|
|
admin_req.req_type.create_op_oq.qid = op_ob_q->q_id;
|
|
admin_req.req_type.create_op_oq.intr_msg_num = op_ob_q->intr_msg_num;
|
|
admin_req.req_type.create_op_oq.elem_arr_addr = op_ob_q->array_dma_addr;
|
|
admin_req.req_type.create_op_oq.ob_pi_addr = op_ob_q->pi_dma_addr;
|
|
admin_req.req_type.create_op_oq.num_elem = op_ob_q->num_elem;
|
|
admin_req.req_type.create_op_oq.elem_len = op_ob_q->elem_size / 16;
|
|
|
|
DBG_INFO("admin_req.req_type.create_op_oq.qid : %x\n",admin_req.req_type.create_op_oq.qid);
|
|
DBG_INFO("admin_req.req_type.create_op_oq.intr_msg_num : %x\n", admin_req.req_type.create_op_oq.intr_msg_num );
|
|
|
|
ret = pqisrc_submit_admin_req(softs, &admin_req, &admin_resp);
|
|
if( PQI_STATUS_SUCCESS == ret) {
|
|
op_ob_q->ci_register_offset = (PQISRC_PQI_REG_OFFSET +
|
|
admin_resp.resp_type.create_op_oq.ci_offset);
|
|
op_ob_q->ci_register_abs = (uint32_t *)(softs->pci_mem_base_vaddr +
|
|
op_ob_q->ci_register_offset);
|
|
} else {
|
|
int i = 0;
|
|
DBG_WARN("Error Status Descriptors\n");
|
|
for(i = 0; i < 4;i++)
|
|
DBG_WARN(" %x ",admin_resp.resp_type.create_op_oq.status_desc[i]);
|
|
}
|
|
|
|
DBG_FUNC("OUT ret : %d\n", ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Function used to create an operational ib queue.
|
|
*/
|
|
int
|
|
pqisrc_create_op_ibq(pqisrc_softstate_t *softs,
|
|
ib_queue_t *op_ib_q)
|
|
{
|
|
int ret = PQI_STATUS_SUCCESS;
|
|
gen_adm_req_iu_t admin_req;
|
|
gen_adm_resp_iu_t admin_resp;
|
|
|
|
DBG_FUNC("IN\n");
|
|
|
|
memset(&admin_req, 0, sizeof(admin_req));
|
|
memset(&admin_resp, 0, sizeof(admin_resp));
|
|
|
|
admin_req.fn_code = PQI_FUNCTION_CREATE_OPERATIONAL_IQ;
|
|
admin_req.req_type.create_op_iq.qid = op_ib_q->q_id;
|
|
admin_req.req_type.create_op_iq.elem_arr_addr = op_ib_q->array_dma_addr;
|
|
admin_req.req_type.create_op_iq.iq_ci_addr = op_ib_q->ci_dma_addr;
|
|
admin_req.req_type.create_op_iq.num_elem = op_ib_q->num_elem;
|
|
admin_req.req_type.create_op_iq.elem_len = op_ib_q->elem_size / 16;
|
|
|
|
ret = pqisrc_submit_admin_req(softs, &admin_req, &admin_resp);
|
|
|
|
if( PQI_STATUS_SUCCESS == ret) {
|
|
op_ib_q->pi_register_offset =(PQISRC_PQI_REG_OFFSET +
|
|
admin_resp.resp_type.create_op_iq.pi_offset);
|
|
|
|
op_ib_q->pi_register_abs =(uint32_t *)(softs->pci_mem_base_vaddr +
|
|
op_ib_q->pi_register_offset);
|
|
} else {
|
|
int i = 0;
|
|
DBG_WARN("Error Status Decsriptors\n");
|
|
for(i = 0; i < 4;i++)
|
|
DBG_WARN(" %x ",admin_resp.resp_type.create_op_iq.status_desc[i]);
|
|
}
|
|
|
|
DBG_FUNC("OUT ret : %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* subroutine used to create an operational ib queue for AIO.
|
|
*/
|
|
int
|
|
pqisrc_create_op_aio_ibq(pqisrc_softstate_t *softs,
|
|
ib_queue_t *op_aio_ib_q)
|
|
{
|
|
int ret = PQI_STATUS_SUCCESS;
|
|
|
|
DBG_FUNC("IN\n");
|
|
|
|
ret = pqisrc_create_op_ibq(softs,op_aio_ib_q);
|
|
if ( PQI_STATUS_SUCCESS == ret)
|
|
ret = pqisrc_change_op_ibq_queue_prop(softs,
|
|
op_aio_ib_q, PQI_CHANGE_OP_IQ_PROP_ASSIGN_AIO);
|
|
|
|
DBG_FUNC("OUT ret : %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* subroutine used to create an operational ib queue for RAID.
|
|
*/
|
|
int
|
|
pqisrc_create_op_raid_ibq(pqisrc_softstate_t *softs,
|
|
ib_queue_t *op_raid_ib_q)
|
|
{
|
|
int ret = PQI_STATUS_SUCCESS;
|
|
|
|
DBG_FUNC("IN\n");
|
|
|
|
ret = pqisrc_create_op_ibq(softs,op_raid_ib_q);
|
|
|
|
DBG_FUNC("OUT\n");
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Allocate and create an event queue to process supported events.
|
|
*/
|
|
int
|
|
pqisrc_alloc_and_create_event_queue(pqisrc_softstate_t *softs)
|
|
{
|
|
int ret = PQI_STATUS_SUCCESS;
|
|
uint32_t alloc_size = 0;
|
|
uint32_t num_elem;
|
|
char *virt_addr = NULL;
|
|
dma_addr_t dma_addr = 0;
|
|
uint64_t event_q_pi_dma_start_offset = 0;
|
|
uint32_t event_q_pi_virt_start_offset = 0;
|
|
char *event_q_pi_virt_start_addr = NULL;
|
|
ob_queue_t *event_q = NULL;
|
|
|
|
|
|
DBG_FUNC("IN\n");
|
|
|
|
/*
|
|
* Calculate memory requirements.
|
|
* If event queue is shared for IO response, number of
|
|
* elements in event queue depends on num elements in OP OB Q
|
|
* also. Since event queue element size (32) is more than IO
|
|
* response size , event queue element size need not be checked
|
|
* for queue size calculation.
|
|
*/
|
|
#ifdef SHARE_EVENT_QUEUE_FOR_IO
|
|
num_elem = MIN(softs->num_elem_per_op_obq, PQISRC_NUM_EVENT_Q_ELEM);
|
|
#else
|
|
num_elem = PQISRC_NUM_EVENT_Q_ELEM;
|
|
#endif
|
|
|
|
alloc_size = num_elem * PQISRC_EVENT_Q_ELEM_SIZE;
|
|
event_q_pi_dma_start_offset = alloc_size;
|
|
event_q_pi_virt_start_offset = alloc_size;
|
|
alloc_size += sizeof(uint32_t); /*For IBQ CI*/
|
|
|
|
/* Allocate memory for event queues */
|
|
softs->event_q_dma_mem.tag = "event_queue";
|
|
softs->event_q_dma_mem.size = alloc_size;
|
|
softs->event_q_dma_mem.align = PQI_OPQ_ELEM_ARRAY_ALIGN;
|
|
ret = os_dma_mem_alloc(softs, &softs->event_q_dma_mem);
|
|
if (ret) {
|
|
DBG_ERR("Failed to Allocate Event Q ret : %d\n"
|
|
, ret);
|
|
goto err_out;
|
|
}
|
|
|
|
/* Set up the address */
|
|
virt_addr = softs->event_q_dma_mem.virt_addr;
|
|
dma_addr = softs->event_q_dma_mem.dma_addr;
|
|
event_q_pi_dma_start_offset += dma_addr;
|
|
event_q_pi_virt_start_addr = virt_addr + event_q_pi_virt_start_offset;
|
|
|
|
event_q = &softs->event_q;
|
|
ASSERT(!(dma_addr & PQI_ADDR_ALIGN_MASK_64));
|
|
FILL_QUEUE_ARRAY_ADDR(event_q,virt_addr,dma_addr);
|
|
event_q->q_id = PQI_OP_EVENT_QUEUE_ID;
|
|
event_q->num_elem = num_elem;
|
|
event_q->elem_size = PQISRC_EVENT_Q_ELEM_SIZE;
|
|
event_q->pi_dma_addr = event_q_pi_dma_start_offset;
|
|
event_q->pi_virt_addr = (uint32_t *)event_q_pi_virt_start_addr;
|
|
event_q->intr_msg_num = 0; /* vector zero for event */
|
|
ASSERT(!(event_q->pi_dma_addr & PQI_ADDR_ALIGN_MASK_4));
|
|
|
|
ret = pqisrc_create_op_obq(softs,event_q);
|
|
if (ret) {
|
|
DBG_ERR("Failed to Create EventQ %d\n",event_q->q_id);
|
|
goto err_out_create;
|
|
}
|
|
event_q->created = true;
|
|
|
|
DBG_FUNC("OUT\n");
|
|
return ret;
|
|
|
|
err_out_create:
|
|
pqisrc_destroy_event_queue(softs);
|
|
err_out:
|
|
DBG_FUNC("OUT failed %d\n", ret);
|
|
return PQI_STATUS_FAILURE;
|
|
}
|
|
|
|
/*
|
|
* Allocate DMA memory and create operational ib queues.
|
|
*/
|
|
int
|
|
pqisrc_alloc_and_create_ib_queues(pqisrc_softstate_t *softs)
|
|
{
|
|
int ret = PQI_STATUS_SUCCESS;
|
|
uint32_t alloc_size = 0;
|
|
char *virt_addr = NULL;
|
|
dma_addr_t dma_addr = 0;
|
|
uint32_t ibq_size = 0;
|
|
uint64_t ib_ci_dma_start_offset = 0;
|
|
char *ib_ci_virt_start_addr = NULL;
|
|
uint32_t ib_ci_virt_start_offset = 0;
|
|
uint32_t ibq_id = PQI_MIN_OP_IB_QUEUE_ID;
|
|
ib_queue_t *op_ib_q = NULL;
|
|
uint32_t num_op_ibq = softs->num_op_raid_ibq +
|
|
softs->num_op_aio_ibq;
|
|
int i = 0;
|
|
|
|
DBG_FUNC("IN\n");
|
|
|
|
/* Calculate memory requirements */
|
|
ibq_size = softs->num_elem_per_op_ibq * softs->ibq_elem_size;
|
|
alloc_size = num_op_ibq * ibq_size;
|
|
/* CI indexes starts after Queue element array */
|
|
ib_ci_dma_start_offset = alloc_size;
|
|
ib_ci_virt_start_offset = alloc_size;
|
|
alloc_size += num_op_ibq * sizeof(uint32_t); /*For IBQ CI*/
|
|
|
|
/* Allocate memory for IB queues */
|
|
softs->op_ibq_dma_mem.tag = "op_ib_queue";
|
|
softs->op_ibq_dma_mem.size = alloc_size;
|
|
softs->op_ibq_dma_mem.align = PQI_OPQ_ELEM_ARRAY_ALIGN;
|
|
ret = os_dma_mem_alloc(softs, &softs->op_ibq_dma_mem);
|
|
if (ret) {
|
|
DBG_ERR("Failed to Allocate Operational IBQ memory ret : %d\n",
|
|
ret);
|
|
goto err_out;
|
|
}
|
|
|
|
/* Set up the address */
|
|
virt_addr = softs->op_ibq_dma_mem.virt_addr;
|
|
dma_addr = softs->op_ibq_dma_mem.dma_addr;
|
|
ib_ci_dma_start_offset += dma_addr;
|
|
ib_ci_virt_start_addr = virt_addr + ib_ci_virt_start_offset;
|
|
|
|
ASSERT(softs->num_op_raid_ibq == softs->num_op_aio_ibq);
|
|
|
|
for (i = 0; i < softs->num_op_raid_ibq; i++) {
|
|
/* OP RAID IB Q */
|
|
op_ib_q = &softs->op_raid_ib_q[i];
|
|
ASSERT(!(dma_addr & PQI_ADDR_ALIGN_MASK_64));
|
|
FILL_QUEUE_ARRAY_ADDR(op_ib_q,virt_addr,dma_addr);
|
|
op_ib_q->q_id = ibq_id++;
|
|
|
|
snprintf(op_ib_q->lockname, LOCKNAME_SIZE, "raid_ibqlock%d", i);
|
|
ret = OS_INIT_PQILOCK(softs, &op_ib_q->lock, op_ib_q->lockname);
|
|
if(ret){
|
|
/* TODO: error handling */
|
|
DBG_ERR("raid_ibqlock %d init failed\n", i);
|
|
op_ib_q->lockcreated = false;
|
|
goto err_lock;
|
|
}
|
|
op_ib_q->lockcreated = true;
|
|
|
|
op_ib_q->num_elem = softs->num_elem_per_op_ibq;
|
|
op_ib_q->elem_size = softs->ibq_elem_size;
|
|
op_ib_q->ci_dma_addr = ib_ci_dma_start_offset +
|
|
(2 * i * sizeof(uint32_t));
|
|
op_ib_q->ci_virt_addr = (uint32_t*)(ib_ci_virt_start_addr +
|
|
(2 * i * sizeof(uint32_t)));
|
|
ASSERT(!(op_ib_q->ci_dma_addr & PQI_ADDR_ALIGN_MASK_4));
|
|
|
|
ret = pqisrc_create_op_raid_ibq(softs, op_ib_q);
|
|
if (ret) {
|
|
DBG_ERR("[ %s ] Failed to Create OP Raid IBQ %d\n",
|
|
__func__, op_ib_q->q_id);
|
|
goto err_out_create;
|
|
}
|
|
op_ib_q->created = true;
|
|
|
|
/* OP AIO IB Q */
|
|
virt_addr += ibq_size;
|
|
dma_addr += ibq_size;
|
|
op_ib_q = &softs->op_aio_ib_q[i];
|
|
ASSERT(!(dma_addr & PQI_ADDR_ALIGN_MASK_64));
|
|
FILL_QUEUE_ARRAY_ADDR(op_ib_q,virt_addr,dma_addr);
|
|
op_ib_q->q_id = ibq_id++;
|
|
snprintf(op_ib_q->lockname, LOCKNAME_SIZE, "aio_ibqlock%d", i);
|
|
ret = OS_INIT_PQILOCK(softs, &op_ib_q->lock, op_ib_q->lockname);
|
|
if(ret){
|
|
/* TODO: error handling */
|
|
DBG_ERR("aio_ibqlock %d init failed\n", i);
|
|
op_ib_q->lockcreated = false;
|
|
goto err_lock;
|
|
}
|
|
op_ib_q->lockcreated = true;
|
|
|
|
op_ib_q->num_elem = softs->num_elem_per_op_ibq;
|
|
op_ib_q->elem_size = softs->ibq_elem_size;
|
|
op_ib_q->ci_dma_addr = ib_ci_dma_start_offset +
|
|
(((2 * i) + 1) * sizeof(uint32_t));
|
|
op_ib_q->ci_virt_addr = (uint32_t*)(ib_ci_virt_start_addr +
|
|
(((2 * i) + 1) * sizeof(uint32_t)));
|
|
ASSERT(!(op_ib_q->ci_dma_addr & PQI_ADDR_ALIGN_MASK_4));
|
|
|
|
ret = pqisrc_create_op_aio_ibq(softs, op_ib_q);
|
|
if (ret) {
|
|
DBG_ERR("Failed to Create OP AIO IBQ %d\n",op_ib_q->q_id);
|
|
goto err_out_create;
|
|
}
|
|
op_ib_q->created = true;
|
|
|
|
virt_addr += ibq_size;
|
|
dma_addr += ibq_size;
|
|
}
|
|
|
|
DBG_FUNC("OUT\n");
|
|
return ret;
|
|
|
|
err_lock:
|
|
err_out_create:
|
|
pqisrc_destroy_op_ib_queues(softs);
|
|
err_out:
|
|
DBG_FUNC("OUT failed %d\n", ret);
|
|
return PQI_STATUS_FAILURE;
|
|
}
|
|
|
|
/*
|
|
* Allocate DMA memory and create operational ob queues.
|
|
*/
|
|
int
|
|
pqisrc_alloc_and_create_ob_queues(pqisrc_softstate_t *softs)
|
|
{
|
|
int ret = PQI_STATUS_SUCCESS;
|
|
uint32_t alloc_size = 0;
|
|
char *virt_addr = NULL;
|
|
dma_addr_t dma_addr = 0;
|
|
uint32_t obq_size = 0;
|
|
uint64_t ob_pi_dma_start_offset = 0;
|
|
uint32_t ob_pi_virt_start_offset = 0;
|
|
char *ob_pi_virt_start_addr = NULL;
|
|
uint32_t obq_id = PQI_MIN_OP_OB_QUEUE_ID;
|
|
ob_queue_t *op_ob_q = NULL;
|
|
uint32_t num_op_obq = softs->num_op_obq;
|
|
int i = 0;
|
|
|
|
DBG_FUNC("IN\n");
|
|
|
|
/*
|
|
* OB Q element array should be 64 byte aligned.
|
|
* So the number of elements in OB Q should be multiple
|
|
* of 4, so that OB Queue element size (16) * num elements
|
|
* will be multiple of 64.
|
|
*/
|
|
|
|
ALIGN_BOUNDARY(softs->num_elem_per_op_obq, 4);
|
|
obq_size = softs->num_elem_per_op_obq * softs->obq_elem_size;
|
|
alloc_size += num_op_obq * obq_size;
|
|
/* PI indexes starts after Queue element array */
|
|
ob_pi_dma_start_offset = alloc_size;
|
|
ob_pi_virt_start_offset = alloc_size;
|
|
alloc_size += num_op_obq * sizeof(uint32_t); /*For OBQ PI*/
|
|
|
|
/* Allocate memory for OB queues */
|
|
softs->op_obq_dma_mem.tag = "op_ob_queue";
|
|
softs->op_obq_dma_mem.size = alloc_size;
|
|
softs->op_obq_dma_mem.align = PQI_OPQ_ELEM_ARRAY_ALIGN;
|
|
ret = os_dma_mem_alloc(softs, &softs->op_obq_dma_mem);
|
|
if (ret) {
|
|
DBG_ERR("Failed to Allocate Operational OBQ memory ret : %d\n",
|
|
ret);
|
|
goto err_out;
|
|
}
|
|
|
|
/* Set up the address */
|
|
virt_addr = softs->op_obq_dma_mem.virt_addr;
|
|
dma_addr = softs->op_obq_dma_mem.dma_addr;
|
|
ob_pi_dma_start_offset += dma_addr;
|
|
ob_pi_virt_start_addr = virt_addr + ob_pi_virt_start_offset;
|
|
|
|
DBG_INFO("softs->num_op_obq %d\n",softs->num_op_obq);
|
|
|
|
for (i = 0; i < softs->num_op_obq; i++) {
|
|
op_ob_q = &softs->op_ob_q[i];
|
|
ASSERT(!(dma_addr & PQI_ADDR_ALIGN_MASK_64));
|
|
FILL_QUEUE_ARRAY_ADDR(op_ob_q,virt_addr,dma_addr);
|
|
op_ob_q->q_id = obq_id++;
|
|
if(softs->share_opq_and_eventq == true)
|
|
op_ob_q->intr_msg_num = i;
|
|
else
|
|
op_ob_q->intr_msg_num = i + 1; /* msg num zero for event */
|
|
op_ob_q->num_elem = softs->num_elem_per_op_obq;
|
|
op_ob_q->elem_size = softs->obq_elem_size;
|
|
op_ob_q->pi_dma_addr = ob_pi_dma_start_offset +
|
|
(i * sizeof(uint32_t));
|
|
op_ob_q->pi_virt_addr = (uint32_t*)(ob_pi_virt_start_addr +
|
|
(i * sizeof(uint32_t)));
|
|
ASSERT(!(op_ob_q->pi_dma_addr & PQI_ADDR_ALIGN_MASK_4));
|
|
|
|
ret = pqisrc_create_op_obq(softs,op_ob_q);
|
|
if (ret) {
|
|
DBG_ERR("Failed to Create OP OBQ %d\n",op_ob_q->q_id);
|
|
goto err_out_create;
|
|
}
|
|
op_ob_q->created = true;
|
|
virt_addr += obq_size;
|
|
dma_addr += obq_size;
|
|
}
|
|
|
|
DBG_FUNC("OUT\n");
|
|
return ret;
|
|
|
|
err_out_create:
|
|
pqisrc_destroy_op_ob_queues(softs);
|
|
err_out:
|
|
DBG_FUNC("OUT failed %d\n", ret);
|
|
return PQI_STATUS_FAILURE;
|
|
}
|
|
|
|
/*
|
|
* Function used to create operational queues for the adapter.
|
|
*/
|
|
int
|
|
pqisrc_create_op_queues(pqisrc_softstate_t *softs)
|
|
{
|
|
int ret = PQI_STATUS_SUCCESS;
|
|
|
|
DBG_FUNC("IN\n");
|
|
|
|
/* Create Operational IB queues */
|
|
ret = pqisrc_alloc_and_create_ib_queues(softs);
|
|
if (ret)
|
|
goto err_out;
|
|
/* Create Operational OB queues */
|
|
ret = pqisrc_alloc_and_create_ob_queues(softs);
|
|
if (ret)
|
|
goto err_out_obq;
|
|
|
|
/* Create Event queue */
|
|
ret = pqisrc_alloc_and_create_event_queue(softs);
|
|
if (ret)
|
|
goto err_out_eventq;
|
|
|
|
DBG_FUNC("OUT\n");
|
|
return ret;
|
|
err_out_eventq:
|
|
pqisrc_destroy_op_ob_queues(softs);
|
|
err_out_obq:
|
|
pqisrc_destroy_op_ib_queues(softs);
|
|
err_out:
|
|
DBG_FUNC("OUT failed %d\n", ret);
|
|
return PQI_STATUS_FAILURE;
|
|
}
|