11e66f787SSean Bruno /*-
2*7ea28254SJohn Hall * Copyright 2016-2023 Microchip Technology, Inc. and/or its subsidiaries.
31e66f787SSean Bruno *
41e66f787SSean Bruno * Redistribution and use in source and binary forms, with or without
51e66f787SSean Bruno * modification, are permitted provided that the following conditions
61e66f787SSean Bruno * are met:
71e66f787SSean Bruno * 1. Redistributions of source code must retain the above copyright
81e66f787SSean Bruno * notice, this list of conditions and the following disclaimer.
91e66f787SSean Bruno * 2. Redistributions in binary form must reproduce the above copyright
101e66f787SSean Bruno * notice, this list of conditions and the following disclaimer in the
111e66f787SSean Bruno * documentation and/or other materials provided with the distribution.
121e66f787SSean Bruno *
131e66f787SSean Bruno * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
141e66f787SSean Bruno * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
151e66f787SSean Bruno * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
161e66f787SSean Bruno * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
171e66f787SSean Bruno * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
181e66f787SSean Bruno * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
191e66f787SSean Bruno * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
201e66f787SSean Bruno * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
211e66f787SSean Bruno * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
221e66f787SSean Bruno * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
231e66f787SSean Bruno * SUCH DAMAGE.
241e66f787SSean Bruno */
251e66f787SSean Bruno
261e66f787SSean Bruno
271e66f787SSean Bruno #include "smartpqi_includes.h"
281e66f787SSean Bruno
291e66f787SSean Bruno /*
301e66f787SSean Bruno * Submit an admin IU to the adapter.
31*7ea28254SJohn Hall * TODO : Admin command implemented using polling,
321e66f787SSean Bruno * Add interrupt support, if required
331e66f787SSean Bruno */
349fac68fcSPAPANI SRIKANTH int
pqisrc_submit_admin_req(pqisrc_softstate_t * softs,gen_adm_req_iu_t * req,gen_adm_resp_iu_t * resp)359fac68fcSPAPANI SRIKANTH pqisrc_submit_admin_req(pqisrc_softstate_t *softs,
361e66f787SSean Bruno gen_adm_req_iu_t *req, gen_adm_resp_iu_t *resp)
371e66f787SSean Bruno {
381e66f787SSean Bruno int ret = PQI_STATUS_SUCCESS;
391e66f787SSean Bruno ob_queue_t *ob_q = &softs->admin_ob_queue;
401e66f787SSean Bruno ib_queue_t *ib_q = &softs->admin_ib_queue;
411e66f787SSean Bruno int tmo = PQISRC_ADMIN_CMD_RESP_TIMEOUT;
421e66f787SSean Bruno
431e66f787SSean Bruno DBG_FUNC("IN\n");
441e66f787SSean Bruno
451e66f787SSean Bruno req->header.iu_type =
461e66f787SSean Bruno PQI_IU_TYPE_GENERAL_ADMIN_REQUEST;
471e66f787SSean Bruno req->header.comp_feature = 0x00;
481e66f787SSean Bruno req->header.iu_length = PQI_STANDARD_IU_LENGTH;
491e66f787SSean Bruno req->res1 = 0;
501e66f787SSean Bruno req->work = 0;
511e66f787SSean Bruno
521e66f787SSean Bruno /* Get the tag */
531e66f787SSean Bruno req->req_id = pqisrc_get_tag(&softs->taglist);
541e66f787SSean Bruno if (INVALID_ELEM == req->req_id) {
551e66f787SSean Bruno DBG_ERR("Tag not available0x%x\n",(uint16_t)req->req_id);
561e66f787SSean Bruno ret = PQI_STATUS_FAILURE;
571e66f787SSean Bruno goto err_out;
581e66f787SSean Bruno }
591e66f787SSean Bruno softs->rcb[req->req_id].tag = req->req_id;
601e66f787SSean Bruno
611e66f787SSean Bruno /* Submit the command to the admin ib queue */
621e66f787SSean Bruno ret = pqisrc_submit_cmnd(softs, ib_q, req);
631e66f787SSean Bruno if (ret != PQI_STATUS_SUCCESS) {
641e66f787SSean Bruno DBG_ERR("Unable to submit command\n");
651e66f787SSean Bruno goto err_cmd;
661e66f787SSean Bruno }
671e66f787SSean Bruno
681e66f787SSean Bruno /* Wait for completion */
691e66f787SSean Bruno COND_WAIT((*(ob_q->pi_virt_addr) != ob_q->ci_local), tmo);
701e66f787SSean Bruno if (tmo <= 0) {
711e66f787SSean Bruno DBG_ERR("Admin cmd timeout\n");
721e66f787SSean Bruno DBG_ERR("tmo : %d\n",tmo); \
739fac68fcSPAPANI SRIKANTH /* TODO : PQI device status and error register and report */
741e66f787SSean Bruno ret = PQI_STATUS_TIMEOUT;
751e66f787SSean Bruno goto err_cmd;
761e66f787SSean Bruno }
771e66f787SSean Bruno
781e66f787SSean Bruno /* Copy the response */
791e66f787SSean Bruno memcpy(resp, ob_q->array_virt_addr + (ob_q->ci_local * ob_q->elem_size),
801e66f787SSean Bruno sizeof(gen_adm_resp_iu_t));
811e66f787SSean Bruno
821e66f787SSean Bruno /* Update CI */
831e66f787SSean Bruno ob_q->ci_local = (ob_q->ci_local + 1 ) % ob_q->num_elem;
841e66f787SSean Bruno PCI_MEM_PUT32(softs, ob_q->ci_register_abs,
851e66f787SSean Bruno ob_q->ci_register_offset, LE_32(ob_q->ci_local));
861e66f787SSean Bruno
871e66f787SSean Bruno /* Validate the response data */
881e66f787SSean Bruno ASSERT(req->fn_code == resp->fn_code);
891e66f787SSean Bruno ASSERT(resp->header.iu_type == PQI_IU_TYPE_GENERAL_ADMIN_RESPONSE);
901e66f787SSean Bruno ret = resp->status;
911e66f787SSean Bruno if (ret)
921e66f787SSean Bruno goto err_cmd;
931e66f787SSean Bruno
941e66f787SSean Bruno os_reset_rcb(&softs->rcb[req->req_id]);
951e66f787SSean Bruno pqisrc_put_tag(&softs->taglist,req->req_id);
961e66f787SSean Bruno DBG_FUNC("OUT\n");
971e66f787SSean Bruno return ret;
981e66f787SSean Bruno err_cmd:
991e66f787SSean Bruno os_reset_rcb(&softs->rcb[req->req_id]);
1001e66f787SSean Bruno pqisrc_put_tag(&softs->taglist,req->req_id);
1011e66f787SSean Bruno err_out:
1021e66f787SSean Bruno DBG_FUNC("failed OUT : %d\n", ret);
1031e66f787SSean Bruno return ret;
1041e66f787SSean Bruno }
1051e66f787SSean Bruno
1061e66f787SSean Bruno /*
1071e66f787SSean Bruno * Get the administration queue config parameters.
1081e66f787SSean Bruno */
1099fac68fcSPAPANI SRIKANTH void
pqisrc_get_admin_queue_config(pqisrc_softstate_t * softs)1109fac68fcSPAPANI SRIKANTH pqisrc_get_admin_queue_config(pqisrc_softstate_t *softs)
1111e66f787SSean Bruno {
1121e66f787SSean Bruno uint64_t val = 0;
1131e66f787SSean Bruno
1149fac68fcSPAPANI SRIKANTH
1151e66f787SSean Bruno val = LE_64(PCI_MEM_GET64(softs, &softs->pqi_reg->pqi_dev_adminq_cap, PQI_ADMINQ_CAP));
1161e66f787SSean Bruno
1171e66f787SSean Bruno /* pqi_cap = (struct pqi_dev_adminq_cap *)&val;*/
1181e66f787SSean Bruno softs->admin_ib_queue.num_elem = val & 0xFF;
1191e66f787SSean Bruno softs->admin_ob_queue.num_elem = (val & 0xFF00) >> 8;
1201e66f787SSean Bruno /* Note : size in unit of 16 byte s*/
1211e66f787SSean Bruno softs->admin_ib_queue.elem_size = ((val & 0xFF0000) >> 16) * 16;
1221e66f787SSean Bruno softs->admin_ob_queue.elem_size = ((val & 0xFF000000) >> 24) * 16;
1231e66f787SSean Bruno
124*7ea28254SJohn Hall DBG_INIT(" admin ib: num_elem=%u elem_size=%u\n",
125*7ea28254SJohn Hall softs->admin_ib_queue.num_elem, softs->admin_ib_queue.elem_size);
126*7ea28254SJohn Hall DBG_INIT(" admin ob: num_elem=%u elem_size=%u\n",
127*7ea28254SJohn Hall softs->admin_ob_queue.num_elem, softs->admin_ob_queue.elem_size);
1281e66f787SSean Bruno }
1291e66f787SSean Bruno
1301e66f787SSean Bruno /*
1311e66f787SSean Bruno * Decide the no of elements in admin ib and ob queues.
1321e66f787SSean Bruno */
1339fac68fcSPAPANI SRIKANTH void
pqisrc_decide_admin_queue_config(pqisrc_softstate_t * softs)1349fac68fcSPAPANI SRIKANTH pqisrc_decide_admin_queue_config(pqisrc_softstate_t *softs)
1351e66f787SSean Bruno {
1361e66f787SSean Bruno /* Determine num elements in Admin IBQ */
1371e66f787SSean Bruno softs->admin_ib_queue.num_elem = MIN(softs->admin_ib_queue.num_elem,
1381e66f787SSean Bruno PQISRC_MAX_ADMIN_IB_QUEUE_ELEM_NUM);
1391e66f787SSean Bruno
1401e66f787SSean Bruno /* Determine num elements in Admin OBQ */
1411e66f787SSean Bruno softs->admin_ob_queue.num_elem = MIN(softs->admin_ob_queue.num_elem,
1421e66f787SSean Bruno PQISRC_MAX_ADMIN_OB_QUEUE_ELEM_NUM);
1431e66f787SSean Bruno }
1441e66f787SSean Bruno
1451e66f787SSean Bruno /*
146*7ea28254SJohn Hall * Allocate DMA memory for inbound queue and initialize.
1471e66f787SSean Bruno */
1489fac68fcSPAPANI SRIKANTH int
pqisrc_allocate_and_init_inbound_q(pqisrc_softstate_t * softs,ib_queue_t * ib_q,char * tag)149*7ea28254SJohn Hall pqisrc_allocate_and_init_inbound_q(pqisrc_softstate_t *softs, ib_queue_t *ib_q, char *tag)
1501e66f787SSean Bruno {
151*7ea28254SJohn Hall struct dma_mem *dma_mem = &ib_q->alloc_dma;
1521e66f787SSean Bruno uint32_t ib_array_size = 0;
1531e66f787SSean Bruno uint32_t alloc_size = 0;
1541e66f787SSean Bruno char *virt_addr = NULL;
1551e66f787SSean Bruno dma_addr_t dma_addr = 0;
1561e66f787SSean Bruno int ret = PQI_STATUS_SUCCESS;
1571e66f787SSean Bruno
158*7ea28254SJohn Hall ib_array_size = ib_q->num_elem * ib_q->elem_size;
159*7ea28254SJohn Hall ASSERT(ib_array_size > 0);
1601e66f787SSean Bruno
161*7ea28254SJohn Hall alloc_size = ib_array_size + PQI_CI_PI_ALIGN + PQI_ADDR_ALIGN; /* for IB CI and OB PI */
1621e66f787SSean Bruno
163*7ea28254SJohn Hall /* Allocate memory for the Q */
164*7ea28254SJohn Hall memset(dma_mem, 0, sizeof(*dma_mem));
165*7ea28254SJohn Hall os_strlcpy(dma_mem->tag, tag, sizeof(dma_mem->tag));
166*7ea28254SJohn Hall dma_mem->size = alloc_size;
167*7ea28254SJohn Hall dma_mem->align = PQI_ADDR_ALIGN;
168*7ea28254SJohn Hall ret = os_dma_mem_alloc(softs, &ib_q->alloc_dma);
1691e66f787SSean Bruno if (ret) {
170*7ea28254SJohn Hall DBG_ERR("Failed to Allocate Q tag=%s ret=%d\n", dma_mem->tag, ret);
1711e66f787SSean Bruno goto err_out;
1721e66f787SSean Bruno }
1731e66f787SSean Bruno
174*7ea28254SJohn Hall DBG_INIT("alloc tag=%s size=0x%x align=0x%x virt_addr=%p dma_addr=%p\n",
175*7ea28254SJohn Hall dma_mem->tag, dma_mem->size, dma_mem->align, dma_mem->virt_addr, (void*)dma_mem->dma_addr);
176*7ea28254SJohn Hall
1771e66f787SSean Bruno /* Setup the address */
178*7ea28254SJohn Hall virt_addr = dma_mem->virt_addr;
179*7ea28254SJohn Hall dma_addr = dma_mem->dma_addr;
180*7ea28254SJohn Hall ASSERT(!((uint64_t)virt_addr & PQI_ADDR_ALIGN_MASK));
181*7ea28254SJohn Hall ASSERT(!(dma_addr & PQI_ADDR_ALIGN_MASK));
1821e66f787SSean Bruno
1831e66f787SSean Bruno /* IB */
184*7ea28254SJohn Hall ASSERT(!(dma_addr & PQI_ADDR_ALIGN_MASK));
185*7ea28254SJohn Hall ib_q->array_virt_addr = virt_addr;
186*7ea28254SJohn Hall ib_q->array_dma_addr = dma_addr;
187*7ea28254SJohn Hall ib_q->pi_local = 0;
188*7ea28254SJohn Hall
189*7ea28254SJohn Hall /* update addr for the next user */
190*7ea28254SJohn Hall virt_addr += ib_array_size;
191*7ea28254SJohn Hall dma_addr += ib_array_size;
1921e66f787SSean Bruno
1931e66f787SSean Bruno /* IB CI */
194*7ea28254SJohn Hall ASSERT(!(dma_addr & PQI_CI_PI_ALIGN_MASK));
195*7ea28254SJohn Hall ib_q->ci_virt_addr = (uint32_t*)virt_addr;
196*7ea28254SJohn Hall ib_q->ci_dma_addr = dma_addr;
1971e66f787SSean Bruno
198*7ea28254SJohn Hall /* update addr for the next user */
199*7ea28254SJohn Hall virt_addr += PQI_CI_PI_ALIGN;
2001e66f787SSean Bruno
201*7ea28254SJohn Hall DBG_INIT("ib_q: virt_addr=%p, ci_dma_addr=%p elem=%u size=%u\n",
202*7ea28254SJohn Hall ib_q->array_virt_addr, (void*)ib_q->ci_dma_addr, ib_q->num_elem, ib_array_size);
2031e66f787SSean Bruno
204*7ea28254SJohn Hall /* Verify we aren't out of bounds from allocation */
205*7ea28254SJohn Hall ASSERT(virt_addr <= ((char*)dma_mem->virt_addr + alloc_size));
2061e66f787SSean Bruno
2071e66f787SSean Bruno DBG_FUNC("OUT\n");
2081e66f787SSean Bruno return ret;
2091e66f787SSean Bruno
2101e66f787SSean Bruno err_out:
2111e66f787SSean Bruno DBG_FUNC("failed OUT\n");
2121e66f787SSean Bruno return PQI_STATUS_FAILURE;
2131e66f787SSean Bruno }
2141e66f787SSean Bruno
215*7ea28254SJohn Hall
216*7ea28254SJohn Hall /*
217*7ea28254SJohn Hall * Allocate DMA memory for outbound queue and initialize.
218*7ea28254SJohn Hall */
219*7ea28254SJohn Hall int
pqisrc_allocate_and_init_outbound_q(pqisrc_softstate_t * softs,ob_queue_t * ob_q,char * tag)220*7ea28254SJohn Hall pqisrc_allocate_and_init_outbound_q(pqisrc_softstate_t *softs, ob_queue_t *ob_q,
221*7ea28254SJohn Hall char *tag)
222*7ea28254SJohn Hall {
223*7ea28254SJohn Hall struct dma_mem *dma_mem = &ob_q->alloc_dma;
224*7ea28254SJohn Hall uint32_t ob_array_size = 0;
225*7ea28254SJohn Hall uint32_t alloc_size = 0;
226*7ea28254SJohn Hall char *virt_addr = NULL;
227*7ea28254SJohn Hall dma_addr_t dma_addr = 0;
228*7ea28254SJohn Hall int ret = PQI_STATUS_SUCCESS;
229*7ea28254SJohn Hall
230*7ea28254SJohn Hall ob_array_size = ob_q->num_elem * ob_q->elem_size;
231*7ea28254SJohn Hall ASSERT(ob_array_size > 0);
232*7ea28254SJohn Hall
233*7ea28254SJohn Hall alloc_size = ob_array_size + PQI_CI_PI_ALIGN + PQI_ADDR_ALIGN; /* for OB PI */
234*7ea28254SJohn Hall
235*7ea28254SJohn Hall /* Allocate memory for the Q */
236*7ea28254SJohn Hall memset(dma_mem, 0, sizeof(*dma_mem));
237*7ea28254SJohn Hall os_strlcpy(dma_mem->tag, tag, sizeof(dma_mem->tag));
238*7ea28254SJohn Hall dma_mem->size = alloc_size;
239*7ea28254SJohn Hall dma_mem->align = PQI_ADDR_ALIGN;
240*7ea28254SJohn Hall ret = os_dma_mem_alloc(softs, &ob_q->alloc_dma);
241*7ea28254SJohn Hall if (ret) {
242*7ea28254SJohn Hall DBG_ERR("Failed to Allocate Q tag=%s ret=%d\n", dma_mem->tag, ret);
243*7ea28254SJohn Hall goto err_out;
244*7ea28254SJohn Hall }
245*7ea28254SJohn Hall
246*7ea28254SJohn Hall DBG_INIT("alloc tag=%s size=0x%x align=0x%x virt_addr=%p dma_addr=%p\n",
247*7ea28254SJohn Hall dma_mem->tag, dma_mem->size, dma_mem->align, dma_mem->virt_addr, (void*)dma_mem->dma_addr);
248*7ea28254SJohn Hall
249*7ea28254SJohn Hall /* Setup the address */
250*7ea28254SJohn Hall virt_addr = dma_mem->virt_addr;
251*7ea28254SJohn Hall dma_addr = dma_mem->dma_addr;
252*7ea28254SJohn Hall ASSERT(!((uint64_t)virt_addr & PQI_ADDR_ALIGN_MASK));
253*7ea28254SJohn Hall ASSERT(!(dma_addr & PQI_ADDR_ALIGN_MASK));
254*7ea28254SJohn Hall
255*7ea28254SJohn Hall ob_q->array_virt_addr = virt_addr;
256*7ea28254SJohn Hall ob_q->array_dma_addr = dma_addr;
257*7ea28254SJohn Hall ob_q->ci_local = 0;
258*7ea28254SJohn Hall
259*7ea28254SJohn Hall /* update addr for the next user */
260*7ea28254SJohn Hall virt_addr += ob_array_size;
261*7ea28254SJohn Hall dma_addr += ob_array_size;
262*7ea28254SJohn Hall
263*7ea28254SJohn Hall /* OB PI */
264*7ea28254SJohn Hall ASSERT(!(dma_addr & PQI_CI_PI_ALIGN_MASK));
265*7ea28254SJohn Hall ob_q->pi_virt_addr = (uint32_t*)virt_addr;
266*7ea28254SJohn Hall ob_q->pi_dma_addr = dma_addr;
267*7ea28254SJohn Hall
268*7ea28254SJohn Hall /* update addr to show the end next user */
269*7ea28254SJohn Hall virt_addr += PQI_CI_PI_ALIGN;
270*7ea28254SJohn Hall
271*7ea28254SJohn Hall DBG_INIT("ob_q: virt_addr=%p, pi_dma_addr=%p elem=%u size=%u\n",
272*7ea28254SJohn Hall ob_q->array_virt_addr, (void*)ob_q->pi_dma_addr, ob_q->num_elem, ob_array_size);
273*7ea28254SJohn Hall
274*7ea28254SJohn Hall /* Verify we aren't out of bounds from allocation */
275*7ea28254SJohn Hall ASSERT(virt_addr <= ((char*)dma_mem->virt_addr + alloc_size));
276*7ea28254SJohn Hall
277*7ea28254SJohn Hall DBG_FUNC("OUT\n");
278*7ea28254SJohn Hall return ret;
279*7ea28254SJohn Hall
280*7ea28254SJohn Hall err_out:
281*7ea28254SJohn Hall DBG_FUNC("failed OUT\n");
282*7ea28254SJohn Hall return PQI_STATUS_FAILURE;
283*7ea28254SJohn Hall }
284*7ea28254SJohn Hall
285*7ea28254SJohn Hall /*
286*7ea28254SJohn Hall * Allocate DMA memory for admin queue and initialize.
287*7ea28254SJohn Hall */
pqisrc_allocate_and_init_adminq(pqisrc_softstate_t * softs)288*7ea28254SJohn Hall int pqisrc_allocate_and_init_adminq(pqisrc_softstate_t *softs)
289*7ea28254SJohn Hall {
290*7ea28254SJohn Hall int ret;
291*7ea28254SJohn Hall ib_queue_t *admin_ib_q = &softs->admin_ib_queue;
292*7ea28254SJohn Hall ob_queue_t *admin_ob_q = &softs->admin_ob_queue;
293*7ea28254SJohn Hall
294*7ea28254SJohn Hall ret = pqisrc_allocate_and_init_inbound_q(softs, admin_ib_q, "admin_queue");
295*7ea28254SJohn Hall if (!ret) {
296*7ea28254SJohn Hall admin_ib_q->q_id = PQI_ADMIN_IB_QUEUE_ID;
297*7ea28254SJohn Hall ret = pqisrc_allocate_and_init_outbound_q(softs, admin_ob_q, "admin_queue");
298*7ea28254SJohn Hall if(!ret)
299*7ea28254SJohn Hall admin_ob_q->q_id = PQI_ADMIN_OB_QUEUE_ID;
300*7ea28254SJohn Hall else {
301*7ea28254SJohn Hall if(softs->admin_ib_queue.lockcreated==true) {
302*7ea28254SJohn Hall OS_UNINIT_PQILOCK(&softs->admin_ib_queue.lock);
303*7ea28254SJohn Hall softs->admin_ib_queue.lockcreated = false;
304*7ea28254SJohn Hall }
305*7ea28254SJohn Hall if (softs->admin_ib_queue.alloc_dma.virt_addr)
306*7ea28254SJohn Hall os_dma_mem_free(softs, &softs->admin_ib_queue.alloc_dma);
307*7ea28254SJohn Hall }
308*7ea28254SJohn Hall }
309*7ea28254SJohn Hall else
310*7ea28254SJohn Hall DBG_ERR("Failed to create Admin Queue pair\n");
311*7ea28254SJohn Hall
312*7ea28254SJohn Hall return ret;
313*7ea28254SJohn Hall }
314*7ea28254SJohn Hall
3151e66f787SSean Bruno /*
3161e66f787SSean Bruno * Subroutine used to create (or) delete the admin queue requested.
3171e66f787SSean Bruno */
3189fac68fcSPAPANI SRIKANTH int
pqisrc_create_delete_adminq(pqisrc_softstate_t * softs,uint32_t cmd)3199fac68fcSPAPANI SRIKANTH pqisrc_create_delete_adminq(pqisrc_softstate_t *softs, uint32_t cmd)
3201e66f787SSean Bruno {
3211e66f787SSean Bruno int tmo = 0;
3221e66f787SSean Bruno int ret = PQI_STATUS_SUCCESS;
3231e66f787SSean Bruno
3241e66f787SSean Bruno /* Create Admin Q pair writing to Admin Q config function reg */
3251e66f787SSean Bruno
3261e66f787SSean Bruno PCI_MEM_PUT64(softs, &softs->pqi_reg->admin_q_config, PQI_ADMINQ_CONFIG, LE_64(cmd));
3271e66f787SSean Bruno
3281e66f787SSean Bruno if (cmd == PQI_ADMIN_QUEUE_CONF_FUNC_CREATE_Q_PAIR)
3291e66f787SSean Bruno tmo = PQISRC_ADMIN_QUEUE_CREATE_TIMEOUT;
3301e66f787SSean Bruno else
3311e66f787SSean Bruno tmo = PQISRC_ADMIN_QUEUE_DELETE_TIMEOUT;
3321e66f787SSean Bruno
3331e66f787SSean Bruno /* Wait for completion */
3341e66f787SSean Bruno COND_WAIT((PCI_MEM_GET64(softs, &softs->pqi_reg->admin_q_config, PQI_ADMINQ_CONFIG) ==
3351e66f787SSean Bruno PQI_ADMIN_QUEUE_CONF_FUNC_STATUS_IDLE), tmo);
3361e66f787SSean Bruno if (tmo <= 0) {
3371e66f787SSean Bruno DBG_ERR("Unable to create/delete admin queue pair\n");
3389fac68fcSPAPANI SRIKANTH /* TODO : PQI device status and error register and report */
3391e66f787SSean Bruno ret = PQI_STATUS_TIMEOUT;
3401e66f787SSean Bruno }
3411e66f787SSean Bruno
3421e66f787SSean Bruno return ret;
3431e66f787SSean Bruno }
3441e66f787SSean Bruno
3451e66f787SSean Bruno /*
3461e66f787SSean Bruno * Debug admin queue configuration params.
3471e66f787SSean Bruno */
3489fac68fcSPAPANI SRIKANTH void
pqisrc_print_adminq_config(pqisrc_softstate_t * softs)3499fac68fcSPAPANI SRIKANTH pqisrc_print_adminq_config(pqisrc_softstate_t *softs)
3501e66f787SSean Bruno {
3511e66f787SSean Bruno DBG_INFO(" softs->admin_ib_queue.array_dma_addr : %p\n",
3521e66f787SSean Bruno (void*)softs->admin_ib_queue.array_dma_addr);
3531e66f787SSean Bruno DBG_INFO(" softs->admin_ib_queue.array_virt_addr : %p\n",
3541e66f787SSean Bruno (void*)softs->admin_ib_queue.array_virt_addr);
355*7ea28254SJohn Hall DBG_INFO(" softs->admin_ib_queue.num_elem : %u\n",
3561e66f787SSean Bruno softs->admin_ib_queue.num_elem);
357*7ea28254SJohn Hall DBG_INFO(" softs->admin_ib_queue.elem_size : %u\n",
3581e66f787SSean Bruno softs->admin_ib_queue.elem_size);
3591e66f787SSean Bruno DBG_INFO(" softs->admin_ob_queue.array_dma_addr : %p\n",
3601e66f787SSean Bruno (void*)softs->admin_ob_queue.array_dma_addr);
3611e66f787SSean Bruno DBG_INFO(" softs->admin_ob_queue.array_virt_addr : %p\n",
3621e66f787SSean Bruno (void*)softs->admin_ob_queue.array_virt_addr);
363*7ea28254SJohn Hall DBG_INFO(" softs->admin_ob_queue.num_elem : %u\n",
3641e66f787SSean Bruno softs->admin_ob_queue.num_elem);
365*7ea28254SJohn Hall DBG_INFO(" softs->admin_ob_queue.elem_size : %u\n",
3661e66f787SSean Bruno softs->admin_ob_queue.elem_size);
3671e66f787SSean Bruno DBG_INFO(" softs->admin_ib_queue.pi_register_abs : %p\n",
3681e66f787SSean Bruno (void*)softs->admin_ib_queue.pi_register_abs);
3691e66f787SSean Bruno DBG_INFO(" softs->admin_ob_queue.ci_register_abs : %p\n",
3701e66f787SSean Bruno (void*)softs->admin_ob_queue.ci_register_abs);
3711e66f787SSean Bruno }
3721e66f787SSean Bruno
3731e66f787SSean Bruno /*
3741e66f787SSean Bruno * Function used to create an admin queue.
3751e66f787SSean Bruno */
3769fac68fcSPAPANI SRIKANTH int
pqisrc_create_admin_queue(pqisrc_softstate_t * softs)3779fac68fcSPAPANI SRIKANTH pqisrc_create_admin_queue(pqisrc_softstate_t *softs)
3781e66f787SSean Bruno {
379aeb665b5SEd Maste int ret = PQI_STATUS_SUCCESS;
380*7ea28254SJohn Hall /* struct pqi_dev_adminq_cap *pqi_cap; */
3811e66f787SSean Bruno uint32_t admin_q_param = 0;
3821e66f787SSean Bruno
3831e66f787SSean Bruno DBG_FUNC("IN\n");
3841e66f787SSean Bruno
3851e66f787SSean Bruno /* Get admin queue details - pqi2-r00a - table 24 */
3861e66f787SSean Bruno pqisrc_get_admin_queue_config(softs);
3871e66f787SSean Bruno
3881e66f787SSean Bruno /* Decide admin Q config */
3891e66f787SSean Bruno pqisrc_decide_admin_queue_config(softs);
3901e66f787SSean Bruno
3911e66f787SSean Bruno /* Allocate and init Admin Q pair */
3921e66f787SSean Bruno ret = pqisrc_allocate_and_init_adminq(softs);
3931e66f787SSean Bruno if (ret) {
3941e66f787SSean Bruno DBG_ERR("Failed to Allocate Admin Q ret : %d\n", ret);
3951e66f787SSean Bruno goto err_out;
3961e66f787SSean Bruno }
3971e66f787SSean Bruno
3981e66f787SSean Bruno /* Write IB Q element array address */
3991e66f787SSean Bruno PCI_MEM_PUT64(softs, &softs->pqi_reg->admin_ibq_elem_array_addr,
4001e66f787SSean Bruno PQI_ADMIN_IBQ_ELEM_ARRAY_ADDR, LE_64(softs->admin_ib_queue.array_dma_addr));
4011e66f787SSean Bruno
4021e66f787SSean Bruno /* Write OB Q element array address */
4031e66f787SSean Bruno PCI_MEM_PUT64(softs, &softs->pqi_reg->admin_obq_elem_array_addr,
4041e66f787SSean Bruno PQI_ADMIN_OBQ_ELEM_ARRAY_ADDR, LE_64(softs->admin_ob_queue.array_dma_addr));
4051e66f787SSean Bruno
4061e66f787SSean Bruno /* Write IB Q CI address */
4071e66f787SSean Bruno PCI_MEM_PUT64(softs, &softs->pqi_reg->admin_ibq_ci_addr,
4081e66f787SSean Bruno PQI_ADMIN_IBQ_CI_ADDR, LE_64(softs->admin_ib_queue.ci_dma_addr));
4091e66f787SSean Bruno
4101e66f787SSean Bruno /* Write OB Q PI address */
4111e66f787SSean Bruno PCI_MEM_PUT64(softs, &softs->pqi_reg->admin_obq_pi_addr,
4121e66f787SSean Bruno PQI_ADMIN_OBQ_PI_ADDR, LE_64(softs->admin_ob_queue.pi_dma_addr));
4131e66f787SSean Bruno
4149fac68fcSPAPANI SRIKANTH
4151e66f787SSean Bruno /* Write Admin Q params pqi-r200a table 36 */
4161e66f787SSean Bruno
4171e66f787SSean Bruno admin_q_param = softs->admin_ib_queue.num_elem |
4181e66f787SSean Bruno (softs->admin_ob_queue.num_elem << 8)|
4191e66f787SSean Bruno PQI_ADMIN_QUEUE_MSIX_DISABLE;
4201e66f787SSean Bruno
4211e66f787SSean Bruno PCI_MEM_PUT32(softs, &softs->pqi_reg->admin_q_param,
4221e66f787SSean Bruno PQI_ADMINQ_PARAM, LE_32(admin_q_param));
4231e66f787SSean Bruno
4241e66f787SSean Bruno /* Submit cmd to create Admin Q pair */
4251e66f787SSean Bruno ret = pqisrc_create_delete_adminq(softs,
4261e66f787SSean Bruno PQI_ADMIN_QUEUE_CONF_FUNC_CREATE_Q_PAIR);
4271e66f787SSean Bruno if (ret) {
4281e66f787SSean Bruno DBG_ERR("Failed to Allocate Admin Q ret : %d\n", ret);
4291e66f787SSean Bruno goto err_q_create;
4301e66f787SSean Bruno }
4311e66f787SSean Bruno
4321e66f787SSean Bruno /* Admin queue created, get ci,pi offset */
4331e66f787SSean Bruno softs->admin_ib_queue.pi_register_offset =(PQISRC_PQI_REG_OFFSET +
4341e66f787SSean Bruno PCI_MEM_GET64(softs, &softs->pqi_reg->admin_ibq_pi_offset, PQI_ADMIN_IBQ_PI_OFFSET));
4351e66f787SSean Bruno
4361e66f787SSean Bruno softs->admin_ib_queue.pi_register_abs =(uint32_t *)(softs->pci_mem_base_vaddr +
4371e66f787SSean Bruno softs->admin_ib_queue.pi_register_offset);
4381e66f787SSean Bruno
4391e66f787SSean Bruno softs->admin_ob_queue.ci_register_offset = (PQISRC_PQI_REG_OFFSET +
4401e66f787SSean Bruno PCI_MEM_GET64(softs, &softs->pqi_reg->admin_obq_ci_offset, PQI_ADMIN_OBQ_CI_OFFSET));
4411e66f787SSean Bruno
4421e66f787SSean Bruno softs->admin_ob_queue.ci_register_abs = (uint32_t *)(softs->pci_mem_base_vaddr +
4431e66f787SSean Bruno softs->admin_ob_queue.ci_register_offset);
4441e66f787SSean Bruno
4451e66f787SSean Bruno os_strlcpy(softs->admin_ib_queue.lockname, "admin_ibqlock", LOCKNAME_SIZE);
4461e66f787SSean Bruno
4471e66f787SSean Bruno ret =OS_INIT_PQILOCK(softs, &softs->admin_ib_queue.lock,
4481e66f787SSean Bruno softs->admin_ib_queue.lockname);
4491e66f787SSean Bruno if(ret){
4501e66f787SSean Bruno DBG_ERR("Admin spinlock initialization failed\n");
4511e66f787SSean Bruno softs->admin_ib_queue.lockcreated = false;
452b17f4335SSean Bruno goto err_lock;
4531e66f787SSean Bruno }
4541e66f787SSean Bruno softs->admin_ib_queue.lockcreated = true;
4551e66f787SSean Bruno
4561e66f787SSean Bruno /* Print admin q config details */
4571e66f787SSean Bruno pqisrc_print_adminq_config(softs);
4581e66f787SSean Bruno
4591e66f787SSean Bruno DBG_FUNC("OUT\n");
4601e66f787SSean Bruno return ret;
4611e66f787SSean Bruno
462b17f4335SSean Bruno err_lock:
463*7ea28254SJohn Hall #if 0
464*7ea28254SJohn Hall pqisrc_create_delete_adminq(softs, PQI_ADMIN_QUEUE_CONF_FUNC_DEL_Q_PAIR);
465*7ea28254SJohn Hall #endif
4661e66f787SSean Bruno err_q_create:
467*7ea28254SJohn Hall pqisrc_destroy_admin_queue(softs);
4681e66f787SSean Bruno err_out:
4691e66f787SSean Bruno DBG_FUNC("failed OUT\n");
4701e66f787SSean Bruno return ret;
4711e66f787SSean Bruno }
4721e66f787SSean Bruno
4731e66f787SSean Bruno /*
4741e66f787SSean Bruno * Subroutine used to delete an operational queue.
4751e66f787SSean Bruno */
4769fac68fcSPAPANI SRIKANTH int
pqisrc_delete_op_queue(pqisrc_softstate_t * softs,uint32_t q_id,boolean_t ibq)4779fac68fcSPAPANI SRIKANTH pqisrc_delete_op_queue(pqisrc_softstate_t *softs,
4781e66f787SSean Bruno uint32_t q_id, boolean_t ibq)
4791e66f787SSean Bruno {
4801e66f787SSean Bruno int ret = PQI_STATUS_SUCCESS;
4811e66f787SSean Bruno /* Firmware doesn't support this now */
4821e66f787SSean Bruno
4831e66f787SSean Bruno #if 0
4841e66f787SSean Bruno gen_adm_req_iu_t admin_req;
4851e66f787SSean Bruno gen_adm_resp_iu_t admin_resp;
4861e66f787SSean Bruno
4879fac68fcSPAPANI SRIKANTH
4881e66f787SSean Bruno memset(&admin_req, 0, sizeof(admin_req));
4891e66f787SSean Bruno memset(&admin_resp, 0, sizeof(admin_resp));
4901e66f787SSean Bruno
4911e66f787SSean Bruno DBG_FUNC("IN\n");
4921e66f787SSean Bruno
4931e66f787SSean Bruno admin_req.req_type.create_op_iq.qid = q_id;
4941e66f787SSean Bruno
4951e66f787SSean Bruno if (ibq)
4961e66f787SSean Bruno admin_req.fn_code = PQI_FUNCTION_DELETE_OPERATIONAL_IQ;
4971e66f787SSean Bruno else
4981e66f787SSean Bruno admin_req.fn_code = PQI_FUNCTION_DELETE_OPERATIONAL_OQ;
4991e66f787SSean Bruno
5009fac68fcSPAPANI SRIKANTH
5011e66f787SSean Bruno ret = pqisrc_submit_admin_req(softs, &admin_req, &admin_resp);
5021e66f787SSean Bruno
5031e66f787SSean Bruno DBG_FUNC("OUT\n");
5041e66f787SSean Bruno #endif
5051e66f787SSean Bruno return ret;
5061e66f787SSean Bruno }
5071e66f787SSean Bruno
5081e66f787SSean Bruno /*
5091e66f787SSean Bruno * Function used to destroy the event queue.
5101e66f787SSean Bruno */
5119fac68fcSPAPANI SRIKANTH void
pqisrc_destroy_event_queue(pqisrc_softstate_t * softs)5129fac68fcSPAPANI SRIKANTH pqisrc_destroy_event_queue(pqisrc_softstate_t *softs)
5131e66f787SSean Bruno {
5141e66f787SSean Bruno DBG_FUNC("IN\n");
5151e66f787SSean Bruno
5161e66f787SSean Bruno if (softs->event_q.created == true) {
5171e66f787SSean Bruno int ret = PQI_STATUS_SUCCESS;
5181e66f787SSean Bruno ret = pqisrc_delete_op_queue(softs, softs->event_q.q_id, false);
5191e66f787SSean Bruno if (ret) {
520*7ea28254SJohn Hall DBG_ERR("Failed to Delete Event Q %u\n", softs->event_q.q_id);
5211e66f787SSean Bruno }
5221e66f787SSean Bruno softs->event_q.created = false;
5231e66f787SSean Bruno }
5241e66f787SSean Bruno
5251e66f787SSean Bruno /* Free the memory */
526*7ea28254SJohn Hall if (softs->event_q.alloc_dma.virt_addr)
527*7ea28254SJohn Hall os_dma_mem_free(softs, &softs->event_q.alloc_dma);
5281e66f787SSean Bruno
5291e66f787SSean Bruno DBG_FUNC("OUT\n");
5301e66f787SSean Bruno }
5311e66f787SSean Bruno
5321e66f787SSean Bruno /*
5331e66f787SSean Bruno * Function used to destroy operational ib queues.
5341e66f787SSean Bruno */
5359fac68fcSPAPANI SRIKANTH void
pqisrc_destroy_op_ib_queues(pqisrc_softstate_t * softs)5369fac68fcSPAPANI SRIKANTH pqisrc_destroy_op_ib_queues(pqisrc_softstate_t *softs)
5371e66f787SSean Bruno {
5381e66f787SSean Bruno int ret = PQI_STATUS_SUCCESS;
5391e66f787SSean Bruno ib_queue_t *op_ib_q = NULL;
540*7ea28254SJohn Hall uint32_t total_op_ibq = softs->num_op_raid_ibq;
5411e66f787SSean Bruno int i;
5421e66f787SSean Bruno
5431e66f787SSean Bruno DBG_FUNC("IN\n");
5441e66f787SSean Bruno
545*7ea28254SJohn Hall for (i = 0; i < total_op_ibq; i++) {
546*7ea28254SJohn Hall int repeat = 0;
547*7ea28254SJohn Hall /* RAID first */
5481e66f787SSean Bruno op_ib_q = &softs->op_raid_ib_q[i];
549*7ea28254SJohn Hall release_queue:
5501e66f787SSean Bruno if (op_ib_q->created == true) {
551*7ea28254SJohn Hall ret = pqisrc_delete_op_queue(softs, op_ib_q->q_id,
552*7ea28254SJohn Hall true);
5531e66f787SSean Bruno if (ret) {
554*7ea28254SJohn Hall DBG_ERR("Failed to Delete IB Q %u\n",
555*7ea28254SJohn Hall op_ib_q->q_id);
5561e66f787SSean Bruno }
5571e66f787SSean Bruno op_ib_q->created = false;
5581e66f787SSean Bruno }
5591e66f787SSean Bruno
5601e66f787SSean Bruno if (op_ib_q->lockcreated == true) {
5611e66f787SSean Bruno OS_UNINIT_PQILOCK(&op_ib_q->lock);
5621e66f787SSean Bruno op_ib_q->lockcreated = false;
5631e66f787SSean Bruno }
5641e66f787SSean Bruno
5651e66f787SSean Bruno /* Free the memory */
566*7ea28254SJohn Hall if (op_ib_q->alloc_dma.virt_addr)
567*7ea28254SJohn Hall os_dma_mem_free(softs, &op_ib_q->alloc_dma);
568*7ea28254SJohn Hall
569*7ea28254SJohn Hall if (repeat < 1) {
570*7ea28254SJohn Hall repeat++;
571*7ea28254SJohn Hall op_ib_q = &softs->op_aio_ib_q[i];
572*7ea28254SJohn Hall goto release_queue;
573*7ea28254SJohn Hall }
574*7ea28254SJohn Hall }
575*7ea28254SJohn Hall
5761e66f787SSean Bruno DBG_FUNC("OUT\n");
5771e66f787SSean Bruno }
5781e66f787SSean Bruno
5791e66f787SSean Bruno /*
5801e66f787SSean Bruno * Function used to destroy operational ob queues.
5811e66f787SSean Bruno */
5829fac68fcSPAPANI SRIKANTH void
pqisrc_destroy_op_ob_queues(pqisrc_softstate_t * softs)5839fac68fcSPAPANI SRIKANTH pqisrc_destroy_op_ob_queues(pqisrc_softstate_t *softs)
5841e66f787SSean Bruno {
5851e66f787SSean Bruno int ret = PQI_STATUS_SUCCESS;
5861e66f787SSean Bruno int i;
587*7ea28254SJohn Hall ob_queue_t *op_ob_q = NULL;
5881e66f787SSean Bruno
5891e66f787SSean Bruno DBG_FUNC("IN\n");
5901e66f787SSean Bruno
5911e66f787SSean Bruno for (i = 0; i < softs->num_op_obq; i++) {
5921e66f787SSean Bruno op_ob_q = &softs->op_ob_q[i];
593*7ea28254SJohn Hall
5941e66f787SSean Bruno if (op_ob_q->created == true) {
5951e66f787SSean Bruno ret = pqisrc_delete_op_queue(softs, op_ob_q->q_id, false);
5961e66f787SSean Bruno if (ret) {
597*7ea28254SJohn Hall DBG_ERR("Failed to Delete OB Q %u\n",op_ob_q->q_id);
5981e66f787SSean Bruno }
5991e66f787SSean Bruno op_ob_q->created = false;
6001e66f787SSean Bruno }
601*7ea28254SJohn Hall
602*7ea28254SJohn Hall /* Free the memory */
603*7ea28254SJohn Hall if (op_ob_q->alloc_dma.virt_addr)
604*7ea28254SJohn Hall os_dma_mem_free(softs, &op_ob_q->alloc_dma);
6051e66f787SSean Bruno }
6061e66f787SSean Bruno
6071e66f787SSean Bruno /* Free the memory */
6081e66f787SSean Bruno DBG_FUNC("OUT\n");
6091e66f787SSean Bruno }
6101e66f787SSean Bruno
6111e66f787SSean Bruno /*
6121e66f787SSean Bruno * Function used to destroy an admin queue.
6131e66f787SSean Bruno */
6149fac68fcSPAPANI SRIKANTH int
pqisrc_destroy_admin_queue(pqisrc_softstate_t * softs)6159fac68fcSPAPANI SRIKANTH pqisrc_destroy_admin_queue(pqisrc_softstate_t *softs)
6161e66f787SSean Bruno {
6171e66f787SSean Bruno int ret = PQI_STATUS_SUCCESS;
6181e66f787SSean Bruno
6191e66f787SSean Bruno DBG_FUNC("IN\n");
620*7ea28254SJohn Hall
621*7ea28254SJohn Hall if(softs->admin_ib_queue.lockcreated==true) {
622*7ea28254SJohn Hall OS_UNINIT_PQILOCK(&softs->admin_ib_queue.lock);
623*7ea28254SJohn Hall softs->admin_ib_queue.lockcreated = false;
624*7ea28254SJohn Hall }
625*7ea28254SJohn Hall
6261e66f787SSean Bruno #if 0
6271e66f787SSean Bruno ret = pqisrc_create_delete_adminq(softs,
6281e66f787SSean Bruno PQI_ADMIN_QUEUE_CONF_FUNC_DEL_Q_PAIR);
6291e66f787SSean Bruno #endif
630*7ea28254SJohn Hall
631*7ea28254SJohn Hall if (softs->admin_ib_queue.alloc_dma.virt_addr)
632*7ea28254SJohn Hall os_dma_mem_free(softs, &softs->admin_ib_queue.alloc_dma);
633*7ea28254SJohn Hall
634*7ea28254SJohn Hall if (softs->admin_ob_queue.alloc_dma.virt_addr)
635*7ea28254SJohn Hall os_dma_mem_free(softs, &softs->admin_ob_queue.alloc_dma);
6361e66f787SSean Bruno
6371e66f787SSean Bruno DBG_FUNC("OUT\n");
6381e66f787SSean Bruno return ret;
6391e66f787SSean Bruno }
6401e66f787SSean Bruno
6411e66f787SSean Bruno /*
6421e66f787SSean Bruno * Function used to change operational ib queue properties.
6431e66f787SSean Bruno */
6449fac68fcSPAPANI SRIKANTH int
pqisrc_change_op_ibq_queue_prop(pqisrc_softstate_t * softs,ib_queue_t * op_ib_q,uint32_t prop)6459fac68fcSPAPANI SRIKANTH pqisrc_change_op_ibq_queue_prop(pqisrc_softstate_t *softs,
6461e66f787SSean Bruno ib_queue_t *op_ib_q, uint32_t prop)
6471e66f787SSean Bruno {
648aeb665b5SEd Maste int ret = PQI_STATUS_SUCCESS;
6491e66f787SSean Bruno gen_adm_req_iu_t admin_req;
6501e66f787SSean Bruno gen_adm_resp_iu_t admin_resp;
6511e66f787SSean Bruno
6521e66f787SSean Bruno memset(&admin_req, 0, sizeof(admin_req));
6531e66f787SSean Bruno memset(&admin_resp, 0, sizeof(admin_resp));
6541e66f787SSean Bruno
6551e66f787SSean Bruno DBG_FUNC("IN\n");
6561e66f787SSean Bruno
6571e66f787SSean Bruno admin_req.fn_code = PQI_FUNCTION_CHANGE_OPERATIONAL_IQ_PROP;
6581e66f787SSean Bruno admin_req.req_type.change_op_iq_prop.qid = op_ib_q->q_id;
6591e66f787SSean Bruno admin_req.req_type.change_op_iq_prop.vend_specific = prop;
6601e66f787SSean Bruno
6611e66f787SSean Bruno ret = pqisrc_submit_admin_req(softs, &admin_req, &admin_resp);
6621e66f787SSean Bruno
6631e66f787SSean Bruno DBG_FUNC("OUT\n");
6641e66f787SSean Bruno return ret;
6651e66f787SSean Bruno }
6661e66f787SSean Bruno
6671e66f787SSean Bruno /*
6681e66f787SSean Bruno * Function used to create an operational ob queue.
6691e66f787SSean Bruno */
6709fac68fcSPAPANI SRIKANTH int
pqisrc_create_op_obq(pqisrc_softstate_t * softs,ob_queue_t * op_ob_q)6719fac68fcSPAPANI SRIKANTH pqisrc_create_op_obq(pqisrc_softstate_t *softs,
6721e66f787SSean Bruno ob_queue_t *op_ob_q)
6731e66f787SSean Bruno {
674aeb665b5SEd Maste int ret = PQI_STATUS_SUCCESS;
6751e66f787SSean Bruno gen_adm_req_iu_t admin_req;
6761e66f787SSean Bruno gen_adm_resp_iu_t admin_resp;
6771e66f787SSean Bruno
6781e66f787SSean Bruno DBG_FUNC("IN\n");
6791e66f787SSean Bruno
6801e66f787SSean Bruno memset(&admin_req, 0, sizeof(admin_req));
6811e66f787SSean Bruno memset(&admin_resp, 0, sizeof(admin_resp));
6821e66f787SSean Bruno
6831e66f787SSean Bruno admin_req.fn_code = PQI_FUNCTION_CREATE_OPERATIONAL_OQ;
6841e66f787SSean Bruno admin_req.req_type.create_op_oq.qid = op_ob_q->q_id;
6851e66f787SSean Bruno admin_req.req_type.create_op_oq.intr_msg_num = op_ob_q->intr_msg_num;
6861e66f787SSean Bruno admin_req.req_type.create_op_oq.elem_arr_addr = op_ob_q->array_dma_addr;
6871e66f787SSean Bruno admin_req.req_type.create_op_oq.ob_pi_addr = op_ob_q->pi_dma_addr;
6881e66f787SSean Bruno admin_req.req_type.create_op_oq.num_elem = op_ob_q->num_elem;
6891e66f787SSean Bruno admin_req.req_type.create_op_oq.elem_len = op_ob_q->elem_size / 16;
6901e66f787SSean Bruno
6911e66f787SSean Bruno DBG_INFO("admin_req.req_type.create_op_oq.qid : %x\n",admin_req.req_type.create_op_oq.qid);
6921e66f787SSean Bruno DBG_INFO("admin_req.req_type.create_op_oq.intr_msg_num : %x\n", admin_req.req_type.create_op_oq.intr_msg_num );
6931e66f787SSean Bruno
6941e66f787SSean Bruno ret = pqisrc_submit_admin_req(softs, &admin_req, &admin_resp);
6951e66f787SSean Bruno if( PQI_STATUS_SUCCESS == ret) {
6961e66f787SSean Bruno op_ob_q->ci_register_offset = (PQISRC_PQI_REG_OFFSET +
6971e66f787SSean Bruno admin_resp.resp_type.create_op_oq.ci_offset);
6981e66f787SSean Bruno op_ob_q->ci_register_abs = (uint32_t *)(softs->pci_mem_base_vaddr +
6991e66f787SSean Bruno op_ob_q->ci_register_offset);
7001e66f787SSean Bruno } else {
7011e66f787SSean Bruno int i = 0;
7021e66f787SSean Bruno DBG_WARN("Error Status Descriptors\n");
7031e66f787SSean Bruno for(i = 0; i < 4;i++)
7041e66f787SSean Bruno DBG_WARN(" %x ",admin_resp.resp_type.create_op_oq.status_desc[i]);
7051e66f787SSean Bruno }
7061e66f787SSean Bruno
7071e66f787SSean Bruno DBG_FUNC("OUT ret : %d\n", ret);
7081e66f787SSean Bruno
7091e66f787SSean Bruno return ret;
7101e66f787SSean Bruno }
7111e66f787SSean Bruno
7121e66f787SSean Bruno /*
7131e66f787SSean Bruno * Function used to create an operational ib queue.
7141e66f787SSean Bruno */
7159fac68fcSPAPANI SRIKANTH int
pqisrc_create_op_ibq(pqisrc_softstate_t * softs,ib_queue_t * op_ib_q)7169fac68fcSPAPANI SRIKANTH pqisrc_create_op_ibq(pqisrc_softstate_t *softs,
7171e66f787SSean Bruno ib_queue_t *op_ib_q)
7181e66f787SSean Bruno {
719aeb665b5SEd Maste int ret = PQI_STATUS_SUCCESS;
7201e66f787SSean Bruno gen_adm_req_iu_t admin_req;
7211e66f787SSean Bruno gen_adm_resp_iu_t admin_resp;
7221e66f787SSean Bruno
7231e66f787SSean Bruno DBG_FUNC("IN\n");
7241e66f787SSean Bruno
7251e66f787SSean Bruno memset(&admin_req, 0, sizeof(admin_req));
7261e66f787SSean Bruno memset(&admin_resp, 0, sizeof(admin_resp));
7271e66f787SSean Bruno
7281e66f787SSean Bruno admin_req.fn_code = PQI_FUNCTION_CREATE_OPERATIONAL_IQ;
7291e66f787SSean Bruno admin_req.req_type.create_op_iq.qid = op_ib_q->q_id;
7301e66f787SSean Bruno admin_req.req_type.create_op_iq.elem_arr_addr = op_ib_q->array_dma_addr;
7311e66f787SSean Bruno admin_req.req_type.create_op_iq.iq_ci_addr = op_ib_q->ci_dma_addr;
7321e66f787SSean Bruno admin_req.req_type.create_op_iq.num_elem = op_ib_q->num_elem;
7331e66f787SSean Bruno admin_req.req_type.create_op_iq.elem_len = op_ib_q->elem_size / 16;
7341e66f787SSean Bruno
7351e66f787SSean Bruno ret = pqisrc_submit_admin_req(softs, &admin_req, &admin_resp);
7361e66f787SSean Bruno
7371e66f787SSean Bruno if( PQI_STATUS_SUCCESS == ret) {
7381e66f787SSean Bruno op_ib_q->pi_register_offset =(PQISRC_PQI_REG_OFFSET +
7391e66f787SSean Bruno admin_resp.resp_type.create_op_iq.pi_offset);
7401e66f787SSean Bruno
7411e66f787SSean Bruno op_ib_q->pi_register_abs =(uint32_t *)(softs->pci_mem_base_vaddr +
7421e66f787SSean Bruno op_ib_q->pi_register_offset);
7431e66f787SSean Bruno } else {
7441e66f787SSean Bruno int i = 0;
7451e66f787SSean Bruno DBG_WARN("Error Status Decsriptors\n");
7461e66f787SSean Bruno for(i = 0; i < 4;i++)
7471e66f787SSean Bruno DBG_WARN(" %x ",admin_resp.resp_type.create_op_iq.status_desc[i]);
7481e66f787SSean Bruno }
7491e66f787SSean Bruno
7501e66f787SSean Bruno DBG_FUNC("OUT ret : %d\n", ret);
7511e66f787SSean Bruno return ret;
7521e66f787SSean Bruno }
7531e66f787SSean Bruno
7541e66f787SSean Bruno /*
7551e66f787SSean Bruno * subroutine used to create an operational ib queue for AIO.
7561e66f787SSean Bruno */
7579fac68fcSPAPANI SRIKANTH int
pqisrc_create_op_aio_ibq(pqisrc_softstate_t * softs,ib_queue_t * op_aio_ib_q)7589fac68fcSPAPANI SRIKANTH pqisrc_create_op_aio_ibq(pqisrc_softstate_t *softs,
7591e66f787SSean Bruno ib_queue_t *op_aio_ib_q)
7601e66f787SSean Bruno {
7611e66f787SSean Bruno int ret = PQI_STATUS_SUCCESS;
7621e66f787SSean Bruno
7631e66f787SSean Bruno DBG_FUNC("IN\n");
7641e66f787SSean Bruno
7651e66f787SSean Bruno ret = pqisrc_create_op_ibq(softs,op_aio_ib_q);
7661e66f787SSean Bruno if ( PQI_STATUS_SUCCESS == ret)
7671e66f787SSean Bruno ret = pqisrc_change_op_ibq_queue_prop(softs,
7681e66f787SSean Bruno op_aio_ib_q, PQI_CHANGE_OP_IQ_PROP_ASSIGN_AIO);
7691e66f787SSean Bruno
7701e66f787SSean Bruno DBG_FUNC("OUT ret : %d\n", ret);
7711e66f787SSean Bruno return ret;
7721e66f787SSean Bruno }
7731e66f787SSean Bruno
7741e66f787SSean Bruno /*
7751e66f787SSean Bruno * subroutine used to create an operational ib queue for RAID.
7761e66f787SSean Bruno */
7779fac68fcSPAPANI SRIKANTH int
pqisrc_create_op_raid_ibq(pqisrc_softstate_t * softs,ib_queue_t * op_raid_ib_q)7789fac68fcSPAPANI SRIKANTH pqisrc_create_op_raid_ibq(pqisrc_softstate_t *softs,
7791e66f787SSean Bruno ib_queue_t *op_raid_ib_q)
7801e66f787SSean Bruno {
781aeb665b5SEd Maste int ret = PQI_STATUS_SUCCESS;
7821e66f787SSean Bruno
7831e66f787SSean Bruno DBG_FUNC("IN\n");
7841e66f787SSean Bruno
7851e66f787SSean Bruno ret = pqisrc_create_op_ibq(softs,op_raid_ib_q);
7861e66f787SSean Bruno
7871e66f787SSean Bruno DBG_FUNC("OUT\n");
7881e66f787SSean Bruno return ret;
7891e66f787SSean Bruno }
7901e66f787SSean Bruno
7911e66f787SSean Bruno /*
7921e66f787SSean Bruno * Allocate and create an event queue to process supported events.
7931e66f787SSean Bruno */
7949fac68fcSPAPANI SRIKANTH int
pqisrc_alloc_and_create_event_queue(pqisrc_softstate_t * softs)7959fac68fcSPAPANI SRIKANTH pqisrc_alloc_and_create_event_queue(pqisrc_softstate_t *softs)
7961e66f787SSean Bruno {
7971e66f787SSean Bruno int ret = PQI_STATUS_SUCCESS;
7981e66f787SSean Bruno uint32_t num_elem;
799*7ea28254SJohn Hall ob_queue_t *event_q = &softs->event_q;
8009fac68fcSPAPANI SRIKANTH
8011e66f787SSean Bruno DBG_FUNC("IN\n");
8021e66f787SSean Bruno
8031e66f787SSean Bruno /*
8041e66f787SSean Bruno * Calculate memory requirements.
8051e66f787SSean Bruno * If event queue is shared for IO response, number of
8061e66f787SSean Bruno * elements in event queue depends on num elements in OP OB Q
8071e66f787SSean Bruno * also. Since event queue element size (32) is more than IO
8081e66f787SSean Bruno * response size , event queue element size need not be checked
8091e66f787SSean Bruno * for queue size calculation.
8101e66f787SSean Bruno */
8111e66f787SSean Bruno #ifdef SHARE_EVENT_QUEUE_FOR_IO
812*7ea28254SJohn Hall num_elem = MIN(softs->num_elem_per_op_obq, PQISRC_MAX_EVENT_QUEUE_ELEM_NUM);
8131e66f787SSean Bruno #else
814*7ea28254SJohn Hall num_elem = PQISRC_MAX_EVENT_QUEUE_ELEM_NUM;
8151e66f787SSean Bruno #endif
8161e66f787SSean Bruno
817*7ea28254SJohn Hall event_q->num_elem = num_elem;
818*7ea28254SJohn Hall event_q->elem_size = PQISRC_EVENT_Q_ELEM_SIZE_BYTES;
8191e66f787SSean Bruno
820*7ea28254SJohn Hall ret = pqisrc_allocate_and_init_outbound_q(softs, event_q, "event_queue");
821*7ea28254SJohn Hall
8221e66f787SSean Bruno if (ret) {
823*7ea28254SJohn Hall DBG_ERR("Failed to Allocate EventQ\n");
8241e66f787SSean Bruno goto err_out;
8251e66f787SSean Bruno }
8261e66f787SSean Bruno event_q->q_id = PQI_OP_EVENT_QUEUE_ID;
8271e66f787SSean Bruno event_q->intr_msg_num = 0; /* vector zero for event */
8281e66f787SSean Bruno
8291e66f787SSean Bruno ret = pqisrc_create_op_obq(softs,event_q);
8301e66f787SSean Bruno if (ret) {
831*7ea28254SJohn Hall DBG_ERR("Failed to Create EventQ %u\n",event_q->q_id);
8321e66f787SSean Bruno goto err_out_create;
8331e66f787SSean Bruno }
8341e66f787SSean Bruno event_q->created = true;
8351e66f787SSean Bruno
8361e66f787SSean Bruno DBG_FUNC("OUT\n");
8371e66f787SSean Bruno return ret;
8381e66f787SSean Bruno
8391e66f787SSean Bruno err_out_create:
8401e66f787SSean Bruno pqisrc_destroy_event_queue(softs);
8411e66f787SSean Bruno err_out:
8421e66f787SSean Bruno DBG_FUNC("OUT failed %d\n", ret);
8431e66f787SSean Bruno return PQI_STATUS_FAILURE;
8441e66f787SSean Bruno }
8451e66f787SSean Bruno
8461e66f787SSean Bruno /*
8471e66f787SSean Bruno * Allocate DMA memory and create operational ib queues.
8481e66f787SSean Bruno */
8499fac68fcSPAPANI SRIKANTH int
pqisrc_alloc_and_create_ib_queues(pqisrc_softstate_t * softs)8509fac68fcSPAPANI SRIKANTH pqisrc_alloc_and_create_ib_queues(pqisrc_softstate_t *softs)
8511e66f787SSean Bruno {
8521e66f787SSean Bruno int ret = PQI_STATUS_SUCCESS;
8531e66f787SSean Bruno ib_queue_t *op_ib_q = NULL;
854*7ea28254SJohn Hall uint32_t ibq_id = PQI_MIN_OP_IB_QUEUE_ID;
855*7ea28254SJohn Hall uint32_t total_op_ibq = softs->num_op_raid_ibq + softs->num_op_aio_ibq;
8561e66f787SSean Bruno int i = 0;
857*7ea28254SJohn Hall char *string = NULL;
8581e66f787SSean Bruno
8591e66f787SSean Bruno DBG_FUNC("IN\n");
8601e66f787SSean Bruno
861*7ea28254SJohn Hall ASSERT(softs->num_op_raid_ibq == softs->num_op_aio_ibq);
862*7ea28254SJohn Hall
863*7ea28254SJohn Hall for (i = 0; i < total_op_ibq; i++) {
864*7ea28254SJohn Hall
865*7ea28254SJohn Hall /* OP RAID IB Q */
866*7ea28254SJohn Hall if (i % 2 == 0)
867*7ea28254SJohn Hall {
868*7ea28254SJohn Hall op_ib_q = &softs->op_raid_ib_q[i/2];
869*7ea28254SJohn Hall string = "raid";
870*7ea28254SJohn Hall }
871*7ea28254SJohn Hall else
872*7ea28254SJohn Hall {
873*7ea28254SJohn Hall op_ib_q = &softs->op_aio_ib_q[i/2];
874*7ea28254SJohn Hall string = "aio";
875*7ea28254SJohn Hall }
8761e66f787SSean Bruno
8771e66f787SSean Bruno /* Allocate memory for IB queues */
878*7ea28254SJohn Hall op_ib_q->num_elem = softs->num_elem_per_op_ibq;
879*7ea28254SJohn Hall op_ib_q->elem_size = softs->max_ibq_elem_size;
880*7ea28254SJohn Hall
881*7ea28254SJohn Hall ret = pqisrc_allocate_and_init_inbound_q(softs, op_ib_q, "op_ib_queue");
8821e66f787SSean Bruno if (ret) {
8831e66f787SSean Bruno DBG_ERR("Failed to Allocate Operational IBQ memory ret : %d\n",
8841e66f787SSean Bruno ret);
8851e66f787SSean Bruno goto err_out;
8861e66f787SSean Bruno }
8871e66f787SSean Bruno op_ib_q->q_id = ibq_id++;
8881e66f787SSean Bruno
889*7ea28254SJohn Hall snprintf(op_ib_q->lockname, LOCKNAME_SIZE, "%s_ibqlock_%d", string, i);
8901e66f787SSean Bruno ret = OS_INIT_PQILOCK(softs, &op_ib_q->lock, op_ib_q->lockname);
8911e66f787SSean Bruno if(ret){
8929fac68fcSPAPANI SRIKANTH /* TODO: error handling */
893*7ea28254SJohn Hall DBG_ERR("%s %d init failed\n", string, i);
8941e66f787SSean Bruno op_ib_q->lockcreated = false;
8951e66f787SSean Bruno goto err_lock;
8961e66f787SSean Bruno }
8971e66f787SSean Bruno op_ib_q->lockcreated = true;
8989fac68fcSPAPANI SRIKANTH
899*7ea28254SJohn Hall if (i % 2 == 0)
9001e66f787SSean Bruno ret = pqisrc_create_op_raid_ibq(softs, op_ib_q);
901*7ea28254SJohn Hall else
9021e66f787SSean Bruno ret = pqisrc_create_op_aio_ibq(softs, op_ib_q);
9031e66f787SSean Bruno if (ret) {
904*7ea28254SJohn Hall DBG_ERR("Failed to Create OP IBQ type=%s id=%u\n",
905*7ea28254SJohn Hall string, op_ib_q->q_id);
9061e66f787SSean Bruno goto err_out_create;
9071e66f787SSean Bruno }
9081e66f787SSean Bruno op_ib_q->created = true;
9091e66f787SSean Bruno }
9101e66f787SSean Bruno
9111e66f787SSean Bruno DBG_FUNC("OUT\n");
9121e66f787SSean Bruno return ret;
9131e66f787SSean Bruno
9141e66f787SSean Bruno err_lock:
9151e66f787SSean Bruno err_out_create:
9161e66f787SSean Bruno err_out:
917*7ea28254SJohn Hall pqisrc_destroy_op_ib_queues(softs);
9181e66f787SSean Bruno DBG_FUNC("OUT failed %d\n", ret);
9191e66f787SSean Bruno return PQI_STATUS_FAILURE;
9201e66f787SSean Bruno }
9211e66f787SSean Bruno
9221e66f787SSean Bruno /*
9231e66f787SSean Bruno * Allocate DMA memory and create operational ob queues.
9241e66f787SSean Bruno */
9259fac68fcSPAPANI SRIKANTH int
pqisrc_alloc_and_create_ob_queues(pqisrc_softstate_t * softs)9269fac68fcSPAPANI SRIKANTH pqisrc_alloc_and_create_ob_queues(pqisrc_softstate_t *softs)
9271e66f787SSean Bruno {
9281e66f787SSean Bruno int ret = PQI_STATUS_SUCCESS;
9291e66f787SSean Bruno uint32_t obq_id = PQI_MIN_OP_OB_QUEUE_ID;
9301e66f787SSean Bruno ob_queue_t *op_ob_q = NULL;
9311e66f787SSean Bruno int i = 0;
9321e66f787SSean Bruno
9331e66f787SSean Bruno DBG_FUNC("IN\n");
9341e66f787SSean Bruno
9351e66f787SSean Bruno /*
9361e66f787SSean Bruno * OB Q element array should be 64 byte aligned.
9371e66f787SSean Bruno * So the number of elements in OB Q should be multiple
9381e66f787SSean Bruno * of 4, so that OB Queue element size (16) * num elements
9391e66f787SSean Bruno * will be multiple of 64.
9401e66f787SSean Bruno */
9411e66f787SSean Bruno
9421e66f787SSean Bruno ALIGN_BOUNDARY(softs->num_elem_per_op_obq, 4);
943*7ea28254SJohn Hall
944*7ea28254SJohn Hall DBG_INIT("softs->num_op_obq %u max_obq_elem_size=%u\n",softs->num_op_obq, softs->max_obq_elem_size);
945*7ea28254SJohn Hall
946*7ea28254SJohn Hall for (i = 0; i < softs->num_op_obq; i++) {
947*7ea28254SJohn Hall op_ob_q = &softs->op_ob_q[i];
9481e66f787SSean Bruno
9491e66f787SSean Bruno /* Allocate memory for OB queues */
950*7ea28254SJohn Hall op_ob_q->num_elem = softs->num_elem_per_op_obq;
951*7ea28254SJohn Hall op_ob_q->elem_size = PQISRC_OP_OBQ_ELEM_SIZE_BYTES;
952*7ea28254SJohn Hall ret = pqisrc_allocate_and_init_outbound_q(softs, op_ob_q, "op_ob_queue");
9531e66f787SSean Bruno if (ret) {
9541e66f787SSean Bruno DBG_ERR("Failed to Allocate Operational OBQ memory ret : %d\n",
9551e66f787SSean Bruno ret);
9561e66f787SSean Bruno goto err_out;
9571e66f787SSean Bruno }
9581e66f787SSean Bruno op_ob_q->q_id = obq_id++;
9591e66f787SSean Bruno if(softs->share_opq_and_eventq == true)
9601e66f787SSean Bruno op_ob_q->intr_msg_num = i;
9611e66f787SSean Bruno else
9621e66f787SSean Bruno op_ob_q->intr_msg_num = i + 1; /* msg num zero for event */
9631e66f787SSean Bruno
9641e66f787SSean Bruno ret = pqisrc_create_op_obq(softs, op_ob_q);
9651e66f787SSean Bruno if (ret) {
966*7ea28254SJohn Hall DBG_ERR("Failed to Create OP OBQ %u\n",op_ob_q->q_id);
9671e66f787SSean Bruno goto err_out_create;
9681e66f787SSean Bruno }
9691e66f787SSean Bruno op_ob_q->created = true;
9701e66f787SSean Bruno }
9711e66f787SSean Bruno
9721e66f787SSean Bruno DBG_FUNC("OUT\n");
9731e66f787SSean Bruno return ret;
9741e66f787SSean Bruno
9751e66f787SSean Bruno err_out_create:
9761e66f787SSean Bruno err_out:
977*7ea28254SJohn Hall pqisrc_destroy_op_ob_queues(softs);
9781e66f787SSean Bruno DBG_FUNC("OUT failed %d\n", ret);
9791e66f787SSean Bruno return PQI_STATUS_FAILURE;
9801e66f787SSean Bruno }
9811e66f787SSean Bruno
9821e66f787SSean Bruno /*
9831e66f787SSean Bruno * Function used to create operational queues for the adapter.
9841e66f787SSean Bruno */
9859fac68fcSPAPANI SRIKANTH int
pqisrc_create_op_queues(pqisrc_softstate_t * softs)9869fac68fcSPAPANI SRIKANTH pqisrc_create_op_queues(pqisrc_softstate_t *softs)
9871e66f787SSean Bruno {
9881e66f787SSean Bruno int ret = PQI_STATUS_SUCCESS;
9891e66f787SSean Bruno
9901e66f787SSean Bruno DBG_FUNC("IN\n");
9911e66f787SSean Bruno
9921e66f787SSean Bruno /* Create Operational IB queues */
9931e66f787SSean Bruno ret = pqisrc_alloc_and_create_ib_queues(softs);
9941e66f787SSean Bruno if (ret)
9951e66f787SSean Bruno goto err_out;
9961e66f787SSean Bruno /* Create Operational OB queues */
9971e66f787SSean Bruno ret = pqisrc_alloc_and_create_ob_queues(softs);
9981e66f787SSean Bruno if (ret)
9991e66f787SSean Bruno goto err_out_obq;
10001e66f787SSean Bruno
10011e66f787SSean Bruno /* Create Event queue */
10021e66f787SSean Bruno ret = pqisrc_alloc_and_create_event_queue(softs);
10031e66f787SSean Bruno if (ret)
10041e66f787SSean Bruno goto err_out_eventq;
10051e66f787SSean Bruno
10061e66f787SSean Bruno DBG_FUNC("OUT\n");
10071e66f787SSean Bruno return ret;
10081e66f787SSean Bruno err_out_eventq:
10091e66f787SSean Bruno pqisrc_destroy_op_ob_queues(softs);
10101e66f787SSean Bruno err_out_obq:
10111e66f787SSean Bruno pqisrc_destroy_op_ib_queues(softs);
10121e66f787SSean Bruno err_out:
10131e66f787SSean Bruno DBG_FUNC("OUT failed %d\n", ret);
10141e66f787SSean Bruno return PQI_STATUS_FAILURE;
10151e66f787SSean Bruno }
1016