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 * Request the adapter to get PQI capabilities supported.
311e66f787SSean Bruno */
329fac68fcSPAPANI SRIKANTH static int
pqisrc_report_pqi_capability(pqisrc_softstate_t * softs)339fac68fcSPAPANI SRIKANTH pqisrc_report_pqi_capability(pqisrc_softstate_t *softs)
341e66f787SSean Bruno {
351e66f787SSean Bruno int ret = PQI_STATUS_SUCCESS;
361e66f787SSean Bruno
371e66f787SSean Bruno DBG_FUNC("IN\n");
381e66f787SSean Bruno
391e66f787SSean Bruno gen_adm_req_iu_t admin_req;
401e66f787SSean Bruno gen_adm_resp_iu_t admin_resp;
411e66f787SSean Bruno dma_mem_t pqi_cap_dma_buf;
421e66f787SSean Bruno pqi_dev_cap_t *capability = NULL;
431e66f787SSean Bruno pqi_iu_layer_desc_t *iu_layer_desc = NULL;
441e66f787SSean Bruno
451e66f787SSean Bruno /* Allocate Non DMA memory */
461e66f787SSean Bruno capability = os_mem_alloc(softs, sizeof(*capability));
471e66f787SSean Bruno if (!capability) {
481e66f787SSean Bruno DBG_ERR("Failed to allocate memory for capability\n");
491e66f787SSean Bruno goto err_out;
501e66f787SSean Bruno }
511e66f787SSean Bruno
521e66f787SSean Bruno memset(&admin_req, 0, sizeof(admin_req));
531e66f787SSean Bruno memset(&admin_resp, 0, sizeof(admin_resp));
541e66f787SSean Bruno
551e66f787SSean Bruno memset(&pqi_cap_dma_buf, 0, sizeof(struct dma_mem));
56*7ea28254SJohn Hall os_strlcpy(pqi_cap_dma_buf.tag, "pqi_cap_buf", sizeof(pqi_cap_dma_buf.tag));
571e66f787SSean Bruno pqi_cap_dma_buf.size = REPORT_PQI_DEV_CAP_DATA_BUF_SIZE;
581e66f787SSean Bruno pqi_cap_dma_buf.align = PQISRC_DEFAULT_DMA_ALIGN;
591e66f787SSean Bruno
601e66f787SSean Bruno ret = os_dma_mem_alloc(softs, &pqi_cap_dma_buf);
611e66f787SSean Bruno if (ret) {
621e66f787SSean Bruno DBG_ERR("Failed to allocate capability DMA buffer : %d\n", ret);
631e66f787SSean Bruno goto err_dma_alloc;
641e66f787SSean Bruno }
651e66f787SSean Bruno
661e66f787SSean Bruno admin_req.fn_code = PQI_FUNCTION_REPORT_DEV_CAP;
671e66f787SSean Bruno admin_req.req_type.general_func.buf_size = pqi_cap_dma_buf.size;
681e66f787SSean Bruno admin_req.req_type.general_func.sg_desc.length = pqi_cap_dma_buf.size;
691e66f787SSean Bruno admin_req.req_type.general_func.sg_desc.addr = pqi_cap_dma_buf.dma_addr;
701e66f787SSean Bruno admin_req.req_type.general_func.sg_desc.type = SGL_DESCRIPTOR_CODE_DATA_BLOCK;
711e66f787SSean Bruno
721e66f787SSean Bruno ret = pqisrc_submit_admin_req(softs, &admin_req, &admin_resp);
731e66f787SSean Bruno if( PQI_STATUS_SUCCESS == ret) {
741e66f787SSean Bruno memcpy(capability,
751e66f787SSean Bruno pqi_cap_dma_buf.virt_addr,
761e66f787SSean Bruno pqi_cap_dma_buf.size);
771e66f787SSean Bruno } else {
781e66f787SSean Bruno DBG_ERR("Failed to send admin req report pqi device capability\n");
791e66f787SSean Bruno goto err_admin_req;
801e66f787SSean Bruno
811e66f787SSean Bruno }
821e66f787SSean Bruno
831e66f787SSean Bruno softs->pqi_dev_cap.max_iqs = capability->max_iqs;
841e66f787SSean Bruno softs->pqi_dev_cap.max_iq_elements = capability->max_iq_elements;
851e66f787SSean Bruno softs->pqi_dev_cap.max_iq_elem_len = capability->max_iq_elem_len;
861e66f787SSean Bruno softs->pqi_dev_cap.min_iq_elem_len = capability->min_iq_elem_len;
871e66f787SSean Bruno softs->pqi_dev_cap.max_oqs = capability->max_oqs;
881e66f787SSean Bruno softs->pqi_dev_cap.max_oq_elements = capability->max_oq_elements;
891e66f787SSean Bruno softs->pqi_dev_cap.max_oq_elem_len = capability->max_oq_elem_len;
901e66f787SSean Bruno softs->pqi_dev_cap.intr_coales_time_granularity = capability->intr_coales_time_granularity;
911e66f787SSean Bruno
921e66f787SSean Bruno iu_layer_desc = &capability->iu_layer_desc[PQI_PROTOCOL_SOP];
931e66f787SSean Bruno softs->max_ib_iu_length_per_fw = iu_layer_desc->max_ib_iu_len;
941e66f787SSean Bruno softs->ib_spanning_supported = iu_layer_desc->ib_spanning_supported;
951e66f787SSean Bruno softs->ob_spanning_supported = iu_layer_desc->ob_spanning_supported;
961e66f787SSean Bruno
97b17f4335SSean Bruno DBG_INIT("softs->pqi_dev_cap.max_iqs: %d\n", softs->pqi_dev_cap.max_iqs);
98b17f4335SSean Bruno DBG_INIT("softs->pqi_dev_cap.max_iq_elements: %d\n", softs->pqi_dev_cap.max_iq_elements);
99b17f4335SSean Bruno DBG_INIT("softs->pqi_dev_cap.max_iq_elem_len: %d\n", softs->pqi_dev_cap.max_iq_elem_len);
100b17f4335SSean Bruno DBG_INIT("softs->pqi_dev_cap.min_iq_elem_len: %d\n", softs->pqi_dev_cap.min_iq_elem_len);
101b17f4335SSean Bruno DBG_INIT("softs->pqi_dev_cap.max_oqs: %d\n", softs->pqi_dev_cap.max_oqs);
102b17f4335SSean Bruno DBG_INIT("softs->pqi_dev_cap.max_oq_elements: %d\n", softs->pqi_dev_cap.max_oq_elements);
103b17f4335SSean Bruno DBG_INIT("softs->pqi_dev_cap.max_oq_elem_len: %d\n", softs->pqi_dev_cap.max_oq_elem_len);
104b17f4335SSean Bruno DBG_INIT("softs->pqi_dev_cap.intr_coales_time_granularity: %d\n", softs->pqi_dev_cap.intr_coales_time_granularity);
105b17f4335SSean Bruno DBG_INIT("softs->max_ib_iu_length_per_fw: %d\n", softs->max_ib_iu_length_per_fw);
106b17f4335SSean Bruno DBG_INIT("softs->ib_spanning_supported: %d\n", softs->ib_spanning_supported);
107b17f4335SSean Bruno DBG_INIT("softs->ob_spanning_supported: %d\n", softs->ob_spanning_supported);
1081e66f787SSean Bruno
109*7ea28254SJohn Hall /* Not expecting these to change, could cause problems if they do */
110*7ea28254SJohn Hall ASSERT(softs->pqi_dev_cap.max_iq_elem_len == PQISRC_OP_MAX_ELEM_SIZE);
111*7ea28254SJohn Hall ASSERT(softs->pqi_dev_cap.min_iq_elem_len == PQISRC_OP_MIN_ELEM_SIZE);
112*7ea28254SJohn Hall ASSERT(softs->max_ib_iu_length_per_fw == PQISRC_MAX_SPANNING_IU_LENGTH);
113*7ea28254SJohn Hall ASSERT(softs->ib_spanning_supported == true);
114*7ea28254SJohn Hall
1159fac68fcSPAPANI SRIKANTH
1161e66f787SSean Bruno os_mem_free(softs, (void *)capability,
1171e66f787SSean Bruno REPORT_PQI_DEV_CAP_DATA_BUF_SIZE);
1181e66f787SSean Bruno os_dma_mem_free(softs, &pqi_cap_dma_buf);
1191e66f787SSean Bruno
1201e66f787SSean Bruno DBG_FUNC("OUT\n");
1211e66f787SSean Bruno return ret;
1221e66f787SSean Bruno
1231e66f787SSean Bruno err_admin_req:
1241e66f787SSean Bruno os_dma_mem_free(softs, &pqi_cap_dma_buf);
1251e66f787SSean Bruno err_dma_alloc:
1261e66f787SSean Bruno if (capability)
1271e66f787SSean Bruno os_mem_free(softs, (void *)capability,
1281e66f787SSean Bruno REPORT_PQI_DEV_CAP_DATA_BUF_SIZE);
1291e66f787SSean Bruno err_out:
1301e66f787SSean Bruno DBG_FUNC("failed OUT\n");
1311e66f787SSean Bruno return PQI_STATUS_FAILURE;
1321e66f787SSean Bruno }
1331e66f787SSean Bruno
1341e66f787SSean Bruno /*
1351e66f787SSean Bruno * Function used to deallocate the used rcb.
1361e66f787SSean Bruno */
1379fac68fcSPAPANI SRIKANTH void
pqisrc_free_rcb(pqisrc_softstate_t * softs,int req_count)1389fac68fcSPAPANI SRIKANTH pqisrc_free_rcb(pqisrc_softstate_t *softs, int req_count)
1391e66f787SSean Bruno {
140*7ea28254SJohn Hall
1411e66f787SSean Bruno uint32_t num_req;
1421e66f787SSean Bruno size_t size;
1431e66f787SSean Bruno int i;
1441e66f787SSean Bruno
1451e66f787SSean Bruno DBG_FUNC("IN\n");
1461e66f787SSean Bruno num_req = softs->max_outstanding_io + 1;
1471e66f787SSean Bruno size = num_req * sizeof(rcb_t);
1481e66f787SSean Bruno for (i = 1; i < req_count; i++)
1491e66f787SSean Bruno os_dma_mem_free(softs, &softs->sg_dma_desc[i]);
1501e66f787SSean Bruno os_mem_free(softs, (void *)softs->rcb, size);
1511e66f787SSean Bruno softs->rcb = NULL;
1521e66f787SSean Bruno DBG_FUNC("OUT\n");
1531e66f787SSean Bruno }
1541e66f787SSean Bruno
1559fac68fcSPAPANI SRIKANTH
1561e66f787SSean Bruno /*
1571e66f787SSean Bruno * Allocate memory for rcb and SG descriptors.
158*7ea28254SJohn Hall * TODO : Sg list should be created separately
1591e66f787SSean Bruno */
1609fac68fcSPAPANI SRIKANTH static int
pqisrc_allocate_rcb(pqisrc_softstate_t * softs)1619fac68fcSPAPANI SRIKANTH pqisrc_allocate_rcb(pqisrc_softstate_t *softs)
1621e66f787SSean Bruno {
1631e66f787SSean Bruno int ret = PQI_STATUS_SUCCESS;
1641e66f787SSean Bruno int i = 0;
1651e66f787SSean Bruno uint32_t num_req = 0;
1661e66f787SSean Bruno uint32_t sg_buf_size = 0;
1671e66f787SSean Bruno uint64_t alloc_size = 0;
1681e66f787SSean Bruno rcb_t *rcb = NULL;
1691e66f787SSean Bruno rcb_t *prcb = NULL;
1701e66f787SSean Bruno DBG_FUNC("IN\n");
1711e66f787SSean Bruno
1721e66f787SSean Bruno /* Set maximum outstanding requests */
1731e66f787SSean Bruno /* The valid tag values are from 1, 2, ..., softs->max_outstanding_io
1741e66f787SSean Bruno * The rcb will be accessed by using the tag as index
1759fac68fcSPAPANI SRIKANTH * As 0 tag index is not used, we need to allocate one extra.
1761e66f787SSean Bruno */
1771e66f787SSean Bruno softs->max_outstanding_io = softs->pqi_cap.max_outstanding_io;
1781e66f787SSean Bruno num_req = softs->max_outstanding_io + 1;
179*7ea28254SJohn Hall DBG_INIT("Max Outstanding IO reset to %u\n", num_req);
1801e66f787SSean Bruno
1811e66f787SSean Bruno alloc_size = num_req * sizeof(rcb_t);
1821e66f787SSean Bruno
1831e66f787SSean Bruno /* Allocate Non DMA memory */
1841e66f787SSean Bruno rcb = os_mem_alloc(softs, alloc_size);
1851e66f787SSean Bruno if (!rcb) {
1861e66f787SSean Bruno DBG_ERR("Failed to allocate memory for rcb\n");
1871e66f787SSean Bruno ret = PQI_STATUS_FAILURE;
1881e66f787SSean Bruno goto err_out;
1891e66f787SSean Bruno }
1901e66f787SSean Bruno softs->rcb = rcb;
1911e66f787SSean Bruno
1921e66f787SSean Bruno /* Allocate sg dma memory for sg chain */
1931e66f787SSean Bruno sg_buf_size = softs->pqi_cap.max_sg_elem *
1941e66f787SSean Bruno sizeof(sgt_t);
1951e66f787SSean Bruno
1961e66f787SSean Bruno prcb = &softs->rcb[1];
1971e66f787SSean Bruno /* Initialize rcb */
1981e66f787SSean Bruno for(i=1; i < num_req; i++) {
199*7ea28254SJohn Hall /* TODO:Here tag is local variable */
2001e66f787SSean Bruno char tag[15];
2011e66f787SSean Bruno sprintf(tag, "sg_dma_buf%d", i);
202*7ea28254SJohn Hall os_strlcpy(softs->sg_dma_desc[i].tag, tag, sizeof(softs->sg_dma_desc[i].tag));
2031e66f787SSean Bruno softs->sg_dma_desc[i].size = sg_buf_size;
2041e66f787SSean Bruno softs->sg_dma_desc[i].align = PQISRC_DEFAULT_DMA_ALIGN;
2051e66f787SSean Bruno
2061e66f787SSean Bruno ret = os_dma_mem_alloc(softs, &softs->sg_dma_desc[i]);
2071e66f787SSean Bruno if (ret) {
2081e66f787SSean Bruno DBG_ERR("Failed to Allocate sg desc %d\n", ret);
2091e66f787SSean Bruno ret = PQI_STATUS_FAILURE;
2101e66f787SSean Bruno goto error;
2111e66f787SSean Bruno }
2121e66f787SSean Bruno prcb->sg_chain_virt = (sgt_t *)(softs->sg_dma_desc[i].virt_addr);
2131e66f787SSean Bruno prcb->sg_chain_dma = (dma_addr_t)(softs->sg_dma_desc[i].dma_addr);
2141e66f787SSean Bruno prcb ++;
2151e66f787SSean Bruno }
2161e66f787SSean Bruno
2171e66f787SSean Bruno DBG_FUNC("OUT\n");
2181e66f787SSean Bruno return ret;
2191e66f787SSean Bruno error:
2201e66f787SSean Bruno pqisrc_free_rcb(softs, i);
2211e66f787SSean Bruno err_out:
2221e66f787SSean Bruno DBG_FUNC("failed OUT\n");
2231e66f787SSean Bruno return ret;
2241e66f787SSean Bruno }
2251e66f787SSean Bruno
2261e66f787SSean Bruno /*
2271e66f787SSean Bruno * Function used to decide the operational queue configuration params
2281e66f787SSean Bruno * - no of ibq/obq, shared/non-shared interrupt resource, IU spanning support
2291e66f787SSean Bruno */
2309fac68fcSPAPANI SRIKANTH void
pqisrc_decide_opq_config(pqisrc_softstate_t * softs)2319fac68fcSPAPANI SRIKANTH pqisrc_decide_opq_config(pqisrc_softstate_t *softs)
2321e66f787SSean Bruno {
2331e66f787SSean Bruno uint16_t total_iq_elements;
2341e66f787SSean Bruno
2351e66f787SSean Bruno DBG_FUNC("IN\n");
2361e66f787SSean Bruno
237b17f4335SSean Bruno DBG_INIT("softs->intr_count : %d softs->num_cpus_online : %d",
2381e66f787SSean Bruno softs->intr_count, softs->num_cpus_online);
2391e66f787SSean Bruno
240*7ea28254SJohn Hall /* TODO : Get the number of IB and OB queues from OS layer */
241*7ea28254SJohn Hall
2421e66f787SSean Bruno if (softs->intr_count == 1 || softs->num_cpus_online == 1) {
2431e66f787SSean Bruno /* Share the event and Operational queue. */
2441e66f787SSean Bruno softs->num_op_obq = 1;
2451e66f787SSean Bruno softs->share_opq_and_eventq = true;
2461e66f787SSean Bruno }
2471e66f787SSean Bruno else {
2481e66f787SSean Bruno /* Note : One OBQ (OBQ0) reserved for event queue */
2491e66f787SSean Bruno softs->num_op_obq = MIN(softs->num_cpus_online,
2501e66f787SSean Bruno softs->intr_count) - 1;
2511e66f787SSean Bruno softs->share_opq_and_eventq = false;
2521e66f787SSean Bruno }
2539fac68fcSPAPANI SRIKANTH /* If the available interrupt count is more than one,
254*7ea28254SJohn Hall we don’t need to share the interrupt for IO and event queue */
2551e66f787SSean Bruno if (softs->intr_count > 1)
2561e66f787SSean Bruno softs->share_opq_and_eventq = false;
2571e66f787SSean Bruno
258*7ea28254SJohn Hall DBG_INIT("softs->num_op_obq : %u\n",softs->num_op_obq);
259*7ea28254SJohn Hall
260*7ea28254SJohn Hall /* TODO : Reset the interrupt count based on number of queues*/
2611e66f787SSean Bruno
2621e66f787SSean Bruno softs->num_op_raid_ibq = softs->num_op_obq;
2631e66f787SSean Bruno softs->num_op_aio_ibq = softs->num_op_raid_ibq;
264*7ea28254SJohn Hall softs->max_ibq_elem_size = softs->pqi_dev_cap.max_iq_elem_len * 16;
265*7ea28254SJohn Hall softs->max_obq_elem_size = softs->pqi_dev_cap.max_oq_elem_len * 16;
2661e66f787SSean Bruno if (softs->max_ib_iu_length_per_fw == 256 &&
2671e66f787SSean Bruno softs->ob_spanning_supported) {
2681e66f787SSean Bruno /* older f/w that doesn't actually support spanning. */
269*7ea28254SJohn Hall softs->max_ib_iu_length = softs->max_ibq_elem_size;
2701e66f787SSean Bruno } else {
2711e66f787SSean Bruno /* max. inbound IU length is an multiple of our inbound element size. */
272*7ea28254SJohn Hall softs->max_ib_iu_length = PQISRC_ROUND_DOWN(softs->max_ib_iu_length_per_fw,
273*7ea28254SJohn Hall softs->max_ibq_elem_size);
2741e66f787SSean Bruno }
275*7ea28254SJohn Hall
2761e66f787SSean Bruno /* If Max. Outstanding IO came with Max. Spanning element count then,
2771e66f787SSean Bruno needed elements per IO are multiplication of
2781e66f787SSean Bruno Max.Outstanding IO and Max.Spanning element */
2791e66f787SSean Bruno total_iq_elements = (softs->max_outstanding_io *
280*7ea28254SJohn Hall (softs->max_ib_iu_length / softs->max_ibq_elem_size));
2811e66f787SSean Bruno
2821e66f787SSean Bruno softs->num_elem_per_op_ibq = total_iq_elements / softs->num_op_raid_ibq;
2831e66f787SSean Bruno softs->num_elem_per_op_ibq = MIN(softs->num_elem_per_op_ibq,
2841e66f787SSean Bruno softs->pqi_dev_cap.max_iq_elements);
2851e66f787SSean Bruno
2861e66f787SSean Bruno softs->num_elem_per_op_obq = softs->max_outstanding_io / softs->num_op_obq;
2871e66f787SSean Bruno softs->num_elem_per_op_obq = MIN(softs->num_elem_per_op_obq,
2881e66f787SSean Bruno softs->pqi_dev_cap.max_oq_elements);
2891e66f787SSean Bruno
290*7ea28254SJohn Hall /* spanning elements should be 9 (1152/128) */
291*7ea28254SJohn Hall softs->max_spanning_elems = softs->max_ib_iu_length/softs->max_ibq_elem_size;
292*7ea28254SJohn Hall ASSERT(softs->max_spanning_elems == PQISRC_MAX_SPANNING_ELEMS);
2931e66f787SSean Bruno
294*7ea28254SJohn Hall /* max SGs should be 8 (128/16) */
295*7ea28254SJohn Hall softs->max_sg_per_single_iu_element = softs->max_ibq_elem_size / sizeof(sgt_t);
296*7ea28254SJohn Hall ASSERT(softs->max_sg_per_single_iu_element == MAX_EMBEDDED_SG_IN_IU);
297*7ea28254SJohn Hall
298*7ea28254SJohn Hall /* max SGs for spanning cmd should be 68*/
299*7ea28254SJohn Hall softs->max_sg_per_spanning_cmd = (softs->max_spanning_elems - 1) * softs->max_sg_per_single_iu_element;
300*7ea28254SJohn Hall softs->max_sg_per_spanning_cmd += MAX_EMBEDDED_SG_IN_FIRST_IU_DEFAULT;
301*7ea28254SJohn Hall
302*7ea28254SJohn Hall DBG_INIT("softs->max_ib_iu_length: %d\n", softs->max_ib_iu_length); /* 1152 per FW advertisement */
303*7ea28254SJohn Hall DBG_INIT("softs->num_elem_per_op_ibq: %u\n", softs->num_elem_per_op_ibq); /* 32 for xcal */
304*7ea28254SJohn Hall DBG_INIT("softs->num_elem_per_op_obq: %u\n", softs->num_elem_per_op_obq); /* 256 for xcal */
305*7ea28254SJohn Hall DBG_INIT("softs->max_spanning_elems: %d\n", softs->max_spanning_elems); /* 9 */
306*7ea28254SJohn Hall DBG_INIT("softs->max_sg_per_spanning_cmd: %u\n", softs->max_sg_per_spanning_cmd); /* 68 until we add AIO writes */
3071e66f787SSean Bruno
3081e66f787SSean Bruno DBG_FUNC("OUT\n");
3091e66f787SSean Bruno }
3101e66f787SSean Bruno
3111e66f787SSean Bruno /*
3121e66f787SSean Bruno * Configure the operational queue parameters.
3131e66f787SSean Bruno */
3149fac68fcSPAPANI SRIKANTH int
pqisrc_configure_op_queues(pqisrc_softstate_t * softs)3159fac68fcSPAPANI SRIKANTH pqisrc_configure_op_queues(pqisrc_softstate_t *softs)
3161e66f787SSean Bruno {
3171e66f787SSean Bruno int ret = PQI_STATUS_SUCCESS;
3181e66f787SSean Bruno
3191e66f787SSean Bruno /* Get the PQI capability,
3201e66f787SSean Bruno REPORT PQI DEVICE CAPABILITY request */
3211e66f787SSean Bruno ret = pqisrc_report_pqi_capability(softs);
3221e66f787SSean Bruno if (ret) {
3231e66f787SSean Bruno DBG_ERR("Failed to send report pqi dev capability request : %d\n",
3241e66f787SSean Bruno ret);
3251e66f787SSean Bruno goto err_out;
3261e66f787SSean Bruno }
3271e66f787SSean Bruno
3281e66f787SSean Bruno /* Reserve required no of slots for internal requests */
3291e66f787SSean Bruno softs->max_io_for_scsi_ml = softs->max_outstanding_io - PQI_RESERVED_IO_SLOTS_CNT;
3301e66f787SSean Bruno
3311e66f787SSean Bruno /* Decide the Op queue configuration */
3321e66f787SSean Bruno pqisrc_decide_opq_config(softs);
3331e66f787SSean Bruno
3341e66f787SSean Bruno DBG_FUNC("OUT\n");
3351e66f787SSean Bruno return ret;
3361e66f787SSean Bruno
3371e66f787SSean Bruno err_out:
3381e66f787SSean Bruno DBG_FUNC("OUT failed\n");
3391e66f787SSean Bruno return ret;
3401e66f787SSean Bruno }
3411e66f787SSean Bruno
3421e66f787SSean Bruno /*
3431e66f787SSean Bruno * Validate the PQI mode of adapter.
3441e66f787SSean Bruno */
3459fac68fcSPAPANI SRIKANTH int
pqisrc_check_pqimode(pqisrc_softstate_t * softs)3469fac68fcSPAPANI SRIKANTH pqisrc_check_pqimode(pqisrc_softstate_t *softs)
3471e66f787SSean Bruno {
3481e66f787SSean Bruno int ret = PQI_STATUS_FAILURE;
3491e66f787SSean Bruno int tmo = 0;
3501e66f787SSean Bruno uint64_t signature = 0;
3511e66f787SSean Bruno
3521e66f787SSean Bruno DBG_FUNC("IN\n");
3531e66f787SSean Bruno
3541e66f787SSean Bruno /* Check the PQI device signature */
3551e66f787SSean Bruno tmo = PQISRC_PQIMODE_READY_TIMEOUT;
3561e66f787SSean Bruno do {
3571e66f787SSean Bruno signature = LE_64(PCI_MEM_GET64(softs, &softs->pqi_reg->signature, PQI_SIGNATURE));
3581e66f787SSean Bruno
3591e66f787SSean Bruno if (memcmp(&signature, PQISRC_PQI_DEVICE_SIGNATURE,
3601e66f787SSean Bruno sizeof(uint64_t)) == 0) {
3611e66f787SSean Bruno ret = PQI_STATUS_SUCCESS;
3621e66f787SSean Bruno break;
3631e66f787SSean Bruno }
3641e66f787SSean Bruno OS_SLEEP(PQISRC_MODE_READY_POLL_INTERVAL);
3651e66f787SSean Bruno } while (tmo--);
3661e66f787SSean Bruno
3671e66f787SSean Bruno PRINT_PQI_SIGNATURE(signature);
3681e66f787SSean Bruno
3691e66f787SSean Bruno if (tmo <= 0) {
3701e66f787SSean Bruno DBG_ERR("PQI Signature is invalid\n");
3711e66f787SSean Bruno ret = PQI_STATUS_TIMEOUT;
3721e66f787SSean Bruno goto err_out;
3731e66f787SSean Bruno }
3741e66f787SSean Bruno
3751e66f787SSean Bruno tmo = PQISRC_PQIMODE_READY_TIMEOUT;
3761e66f787SSean Bruno /* Check function and status code for the device */
3771e66f787SSean Bruno COND_WAIT((PCI_MEM_GET64(softs, &softs->pqi_reg->admin_q_config,
3781e66f787SSean Bruno PQI_ADMINQ_CONFIG) == PQI_ADMIN_QUEUE_CONF_FUNC_STATUS_IDLE), tmo);
3791e66f787SSean Bruno if (!tmo) {
3801e66f787SSean Bruno DBG_ERR("PQI device is not in IDLE state\n");
3811e66f787SSean Bruno ret = PQI_STATUS_TIMEOUT;
3821e66f787SSean Bruno goto err_out;
3831e66f787SSean Bruno }
3841e66f787SSean Bruno
3859fac68fcSPAPANI SRIKANTH
3861e66f787SSean Bruno tmo = PQISRC_PQIMODE_READY_TIMEOUT;
3871e66f787SSean Bruno /* Check the PQI device status register */
3881e66f787SSean Bruno COND_WAIT(LE_32(PCI_MEM_GET32(softs, &softs->pqi_reg->pqi_dev_status, PQI_DEV_STATUS)) &
3891e66f787SSean Bruno PQI_DEV_STATE_AT_INIT, tmo);
3901e66f787SSean Bruno if (!tmo) {
3911e66f787SSean Bruno DBG_ERR("PQI Registers are not ready\n");
3921e66f787SSean Bruno ret = PQI_STATUS_TIMEOUT;
3931e66f787SSean Bruno goto err_out;
3941e66f787SSean Bruno }
3951e66f787SSean Bruno
3961e66f787SSean Bruno DBG_FUNC("OUT\n");
3971e66f787SSean Bruno return ret;
3981e66f787SSean Bruno err_out:
3991e66f787SSean Bruno DBG_FUNC("OUT failed\n");
4001e66f787SSean Bruno return ret;
4011e66f787SSean Bruno }
4021e66f787SSean Bruno
4031e66f787SSean Bruno /* Wait for PQI reset completion for the adapter*/
4049fac68fcSPAPANI SRIKANTH int
pqisrc_wait_for_pqi_reset_completion(pqisrc_softstate_t * softs)4059fac68fcSPAPANI SRIKANTH pqisrc_wait_for_pqi_reset_completion(pqisrc_softstate_t *softs)
4061e66f787SSean Bruno {
4071e66f787SSean Bruno int ret = PQI_STATUS_SUCCESS;
4081e66f787SSean Bruno pqi_reset_reg_t reset_reg;
4091e66f787SSean Bruno int pqi_reset_timeout = 0;
4101e66f787SSean Bruno uint64_t val = 0;
4111e66f787SSean Bruno uint32_t max_timeout = 0;
4121e66f787SSean Bruno
4131e66f787SSean Bruno val = PCI_MEM_GET64(softs, &softs->pqi_reg->pqi_dev_adminq_cap, PQI_ADMINQ_CAP);
4141e66f787SSean Bruno
4151e66f787SSean Bruno max_timeout = (val & 0xFFFF00000000) >> 32;
4161e66f787SSean Bruno
417b17f4335SSean Bruno DBG_INIT("max_timeout for PQI reset completion in 100 msec units = %u\n", max_timeout);
4181e66f787SSean Bruno
4191e66f787SSean Bruno while(1) {
4201e66f787SSean Bruno if (pqi_reset_timeout++ == max_timeout) {
4211e66f787SSean Bruno return PQI_STATUS_TIMEOUT;
4221e66f787SSean Bruno }
4231e66f787SSean Bruno OS_SLEEP(PQI_RESET_POLL_INTERVAL);/* 100 msec */
4241e66f787SSean Bruno reset_reg.all_bits = PCI_MEM_GET32(softs,
4251e66f787SSean Bruno &softs->pqi_reg->dev_reset, PQI_DEV_RESET);
4261e66f787SSean Bruno if (reset_reg.bits.reset_action == PQI_RESET_ACTION_COMPLETED)
4271e66f787SSean Bruno break;
4281e66f787SSean Bruno }
4291e66f787SSean Bruno
4301e66f787SSean Bruno return ret;
4311e66f787SSean Bruno }
4321e66f787SSean Bruno
4331e66f787SSean Bruno /*
4341e66f787SSean Bruno * Function used to perform PQI hard reset.
4351e66f787SSean Bruno */
4369fac68fcSPAPANI SRIKANTH int
pqi_reset(pqisrc_softstate_t * softs)4379fac68fcSPAPANI SRIKANTH pqi_reset(pqisrc_softstate_t *softs)
4381e66f787SSean Bruno {
4391e66f787SSean Bruno int ret = PQI_STATUS_SUCCESS;
4401e66f787SSean Bruno uint32_t val = 0;
4411e66f787SSean Bruno pqi_reset_reg_t pqi_reset_reg;
4421e66f787SSean Bruno
4431e66f787SSean Bruno DBG_FUNC("IN\n");
4441e66f787SSean Bruno
4451e66f787SSean Bruno if (true == softs->ctrl_in_pqi_mode) {
4461e66f787SSean Bruno
4471e66f787SSean Bruno if (softs->pqi_reset_quiesce_allowed) {
4481e66f787SSean Bruno val = PCI_MEM_GET32(softs, &softs->ioa_reg->host_to_ioa_db,
4491e66f787SSean Bruno LEGACY_SIS_IDBR);
4501e66f787SSean Bruno val |= SIS_PQI_RESET_QUIESCE;
4511e66f787SSean Bruno PCI_MEM_PUT32(softs, &softs->ioa_reg->host_to_ioa_db,
4521e66f787SSean Bruno LEGACY_SIS_IDBR, LE_32(val));
453*7ea28254SJohn Hall OS_SLEEP(1000); /* 1 ms delay for PCI W/R ordering issue */
4541e66f787SSean Bruno ret = pqisrc_sis_wait_for_db_bit_to_clear(softs, SIS_PQI_RESET_QUIESCE);
4551e66f787SSean Bruno if (ret) {
4561e66f787SSean Bruno DBG_ERR("failed with error %d during quiesce\n", ret);
4571e66f787SSean Bruno return ret;
4581e66f787SSean Bruno }
4591e66f787SSean Bruno }
4601e66f787SSean Bruno
4611e66f787SSean Bruno pqi_reset_reg.all_bits = 0;
4621e66f787SSean Bruno pqi_reset_reg.bits.reset_type = PQI_RESET_TYPE_HARD_RESET;
4631e66f787SSean Bruno pqi_reset_reg.bits.reset_action = PQI_RESET_ACTION_RESET;
4641e66f787SSean Bruno
4651e66f787SSean Bruno PCI_MEM_PUT32(softs, &softs->pqi_reg->dev_reset, PQI_DEV_RESET,
4661e66f787SSean Bruno LE_32(pqi_reset_reg.all_bits));
467*7ea28254SJohn Hall OS_SLEEP(1000); /* 1 ms delay for PCI W/R ordering issue */
4681e66f787SSean Bruno
4691e66f787SSean Bruno ret = pqisrc_wait_for_pqi_reset_completion(softs);
4701e66f787SSean Bruno if (ret) {
4711e66f787SSean Bruno DBG_ERR("PQI reset timed out: ret = %d!\n", ret);
4721e66f787SSean Bruno return ret;
4731e66f787SSean Bruno }
4741e66f787SSean Bruno }
4751e66f787SSean Bruno softs->ctrl_in_pqi_mode = false;
4761e66f787SSean Bruno DBG_FUNC("OUT\n");
4771e66f787SSean Bruno return ret;
4781e66f787SSean Bruno }
4791e66f787SSean Bruno
4801e66f787SSean Bruno /*
4811e66f787SSean Bruno * Initialize the adapter with supported PQI configuration.
4821e66f787SSean Bruno */
4839fac68fcSPAPANI SRIKANTH int
pqisrc_pqi_init(pqisrc_softstate_t * softs)4849fac68fcSPAPANI SRIKANTH pqisrc_pqi_init(pqisrc_softstate_t *softs)
4851e66f787SSean Bruno {
4861e66f787SSean Bruno int ret = PQI_STATUS_SUCCESS;
4871e66f787SSean Bruno
4881e66f787SSean Bruno DBG_FUNC("IN\n");
4891e66f787SSean Bruno
4901e66f787SSean Bruno /* Check the PQI signature */
4911e66f787SSean Bruno ret = pqisrc_check_pqimode(softs);
4921e66f787SSean Bruno if(ret) {
4931e66f787SSean Bruno DBG_ERR("failed to switch to pqi\n");
4941e66f787SSean Bruno goto err_out;
4951e66f787SSean Bruno }
4961e66f787SSean Bruno
4971e66f787SSean Bruno PQI_SAVE_CTRL_MODE(softs, CTRL_PQI_MODE);
4981e66f787SSean Bruno softs->ctrl_in_pqi_mode = true;
4991e66f787SSean Bruno
5001e66f787SSean Bruno /* Get the No. of Online CPUs,NUMA/Processor config from OS */
5011e66f787SSean Bruno ret = os_get_processor_config(softs);
5021e66f787SSean Bruno if (ret) {
5031e66f787SSean Bruno DBG_ERR("Failed to get processor config from OS %d\n",
5041e66f787SSean Bruno ret);
5051e66f787SSean Bruno goto err_out;
5061e66f787SSean Bruno }
5071e66f787SSean Bruno
508b17f4335SSean Bruno softs->intr_type = INTR_TYPE_NONE;
509b17f4335SSean Bruno
5101e66f787SSean Bruno /* Get the interrupt count, type, priority available from OS */
5111e66f787SSean Bruno ret = os_get_intr_config(softs);
5121e66f787SSean Bruno if (ret) {
5131e66f787SSean Bruno DBG_ERR("Failed to get interrupt config from OS %d\n",
5141e66f787SSean Bruno ret);
5151e66f787SSean Bruno goto err_out;
5161e66f787SSean Bruno }
5171e66f787SSean Bruno
518b17f4335SSean Bruno /*Enable/Set Legacy INTx Interrupt mask clear pqi register,
519b17f4335SSean Bruno *if allocated interrupt is legacy type.
520b17f4335SSean Bruno */
521b17f4335SSean Bruno if (INTR_TYPE_FIXED == softs->intr_type) {
522b17f4335SSean Bruno pqisrc_configure_legacy_intx(softs, true);
523b17f4335SSean Bruno sis_enable_intx(softs);
524b17f4335SSean Bruno }
525b17f4335SSean Bruno
5261e66f787SSean Bruno /* Create Admin Queue pair*/
5271e66f787SSean Bruno ret = pqisrc_create_admin_queue(softs);
5281e66f787SSean Bruno if(ret) {
5291e66f787SSean Bruno DBG_ERR("Failed to configure admin queue\n");
5301e66f787SSean Bruno goto err_admin_queue;
5311e66f787SSean Bruno }
5321e66f787SSean Bruno
5331e66f787SSean Bruno /* For creating event and IO operational queues we have to submit
5341e66f787SSean Bruno admin IU requests.So Allocate resources for submitting IUs */
5351e66f787SSean Bruno
5361e66f787SSean Bruno /* Allocate the request container block (rcb) */
5371e66f787SSean Bruno ret = pqisrc_allocate_rcb(softs);
5381e66f787SSean Bruno if (ret == PQI_STATUS_FAILURE) {
5391e66f787SSean Bruno DBG_ERR("Failed to allocate rcb \n");
5401e66f787SSean Bruno goto err_rcb;
5411e66f787SSean Bruno }
5421e66f787SSean Bruno
5431e66f787SSean Bruno /* Allocate & initialize request id queue */
5441e66f787SSean Bruno ret = pqisrc_init_taglist(softs,&softs->taglist,
5451e66f787SSean Bruno softs->max_outstanding_io);
5461e66f787SSean Bruno if (ret) {
5471e66f787SSean Bruno DBG_ERR("Failed to allocate memory for request id q : %d\n",
5481e66f787SSean Bruno ret);
5491e66f787SSean Bruno goto err_taglist;
5501e66f787SSean Bruno }
5511e66f787SSean Bruno
5521e66f787SSean Bruno ret = pqisrc_configure_op_queues(softs);
5531e66f787SSean Bruno if (ret) {
5541e66f787SSean Bruno DBG_ERR("Failed to configure op queue\n");
5551e66f787SSean Bruno goto err_config_opq;
5561e66f787SSean Bruno }
5571e66f787SSean Bruno
5581e66f787SSean Bruno /* Create Operational queues */
5591e66f787SSean Bruno ret = pqisrc_create_op_queues(softs);
5601e66f787SSean Bruno if(ret) {
5611e66f787SSean Bruno DBG_ERR("Failed to create op queue\n");
5621e66f787SSean Bruno goto err_create_opq;
5631e66f787SSean Bruno }
5641e66f787SSean Bruno
5651e66f787SSean Bruno softs->ctrl_online = true;
5661e66f787SSean Bruno
5671e66f787SSean Bruno DBG_FUNC("OUT\n");
5681e66f787SSean Bruno return ret;
5691e66f787SSean Bruno
5701e66f787SSean Bruno err_create_opq:
5711e66f787SSean Bruno err_config_opq:
5721e66f787SSean Bruno pqisrc_destroy_taglist(softs,&softs->taglist);
5731e66f787SSean Bruno err_taglist:
5741e66f787SSean Bruno pqisrc_free_rcb(softs, softs->max_outstanding_io + 1);
5751e66f787SSean Bruno err_rcb:
5761e66f787SSean Bruno pqisrc_destroy_admin_queue(softs);
5771e66f787SSean Bruno err_admin_queue:
5781e66f787SSean Bruno os_free_intr_config(softs);
5791e66f787SSean Bruno err_out:
5801e66f787SSean Bruno DBG_FUNC("OUT failed\n");
5811e66f787SSean Bruno return PQI_STATUS_FAILURE;
5821e66f787SSean Bruno }
5831e66f787SSean Bruno
584*7ea28254SJohn Hall /* */
5859fac68fcSPAPANI SRIKANTH int
pqisrc_force_sis(pqisrc_softstate_t * softs)5869fac68fcSPAPANI SRIKANTH pqisrc_force_sis(pqisrc_softstate_t *softs)
5871e66f787SSean Bruno {
5881e66f787SSean Bruno int ret = PQI_STATUS_SUCCESS;
5891e66f787SSean Bruno
5901e66f787SSean Bruno if (SIS_IS_KERNEL_PANIC(softs)) {
591*7ea28254SJohn Hall DBG_ERR("Controller FW is not running\n");
5921e66f787SSean Bruno return PQI_STATUS_FAILURE;
5931e66f787SSean Bruno }
5941e66f787SSean Bruno
5951e66f787SSean Bruno if (PQI_GET_CTRL_MODE(softs) == CTRL_SIS_MODE) {
5961e66f787SSean Bruno return ret;
5971e66f787SSean Bruno }
5981e66f787SSean Bruno
5991e66f787SSean Bruno if (SIS_IS_KERNEL_UP(softs)) {
6001e66f787SSean Bruno PQI_SAVE_CTRL_MODE(softs, CTRL_SIS_MODE);
6011e66f787SSean Bruno return ret;
6021e66f787SSean Bruno }
6031e66f787SSean Bruno /* Disable interrupts ? */
604b17f4335SSean Bruno sis_disable_interrupt(softs);
6051e66f787SSean Bruno
6061e66f787SSean Bruno /* reset pqi, this will delete queues */
6071e66f787SSean Bruno ret = pqi_reset(softs);
6081e66f787SSean Bruno if (ret) {
6091e66f787SSean Bruno return ret;
6101e66f787SSean Bruno }
6111e66f787SSean Bruno /* Re enable SIS */
6121e66f787SSean Bruno ret = pqisrc_reenable_sis(softs);
6131e66f787SSean Bruno if (ret) {
6141e66f787SSean Bruno return ret;
6151e66f787SSean Bruno }
6161e66f787SSean Bruno
6171e66f787SSean Bruno PQI_SAVE_CTRL_MODE(softs, CTRL_SIS_MODE);
6181e66f787SSean Bruno
6191e66f787SSean Bruno return ret;
6201e66f787SSean Bruno }
6211e66f787SSean Bruno
622*7ea28254SJohn Hall /* 5 mins timeout for quiesce */
623*7ea28254SJohn Hall #define PQI_QUIESCE_TIMEOUT 300000
624*7ea28254SJohn Hall
625*7ea28254SJohn Hall int
pqisrc_wait_for_cmnd_complete(pqisrc_softstate_t * softs)6269fac68fcSPAPANI SRIKANTH pqisrc_wait_for_cmnd_complete(pqisrc_softstate_t *softs)
627b17f4335SSean Bruno {
628*7ea28254SJohn Hall
6299fac68fcSPAPANI SRIKANTH int count = 0;
630b17f4335SSean Bruno int ret = PQI_STATUS_SUCCESS;
631b17f4335SSean Bruno
632*7ea28254SJohn Hall DBG_NOTE("softs->taglist.num_elem : %u",softs->taglist.num_elem);
6339fac68fcSPAPANI SRIKANTH
6349fac68fcSPAPANI SRIKANTH if (softs->taglist.num_elem == softs->max_outstanding_io)
6359fac68fcSPAPANI SRIKANTH return ret;
6369fac68fcSPAPANI SRIKANTH else {
637*7ea28254SJohn Hall DBG_WARN("%u commands pending\n",
6389fac68fcSPAPANI SRIKANTH softs->max_outstanding_io - softs->taglist.num_elem);
6399fac68fcSPAPANI SRIKANTH
6409fac68fcSPAPANI SRIKANTH while(1) {
6419fac68fcSPAPANI SRIKANTH
6429fac68fcSPAPANI SRIKANTH /* Since heartbeat timer stopped ,check for firmware status*/
6439fac68fcSPAPANI SRIKANTH if (SIS_IS_KERNEL_PANIC(softs)) {
6449fac68fcSPAPANI SRIKANTH DBG_ERR("Controller FW is not running\n");
6459fac68fcSPAPANI SRIKANTH return PQI_STATUS_FAILURE;
6469fac68fcSPAPANI SRIKANTH }
6479fac68fcSPAPANI SRIKANTH
6489fac68fcSPAPANI SRIKANTH if (softs->taglist.num_elem != softs->max_outstanding_io) {
6499fac68fcSPAPANI SRIKANTH /* Sleep for 1 msec */
6509fac68fcSPAPANI SRIKANTH OS_SLEEP(1000);
6519fac68fcSPAPANI SRIKANTH count++;
6529fac68fcSPAPANI SRIKANTH if(count % 1000 == 0) {
6539fac68fcSPAPANI SRIKANTH DBG_WARN("Waited for %d seconds", count/1000);
6549fac68fcSPAPANI SRIKANTH }
6559fac68fcSPAPANI SRIKANTH if (count >= PQI_QUIESCE_TIMEOUT) {
6569fac68fcSPAPANI SRIKANTH return PQI_STATUS_FAILURE;
6579fac68fcSPAPANI SRIKANTH }
6589fac68fcSPAPANI SRIKANTH continue;
6599fac68fcSPAPANI SRIKANTH }
6609fac68fcSPAPANI SRIKANTH break;
6619fac68fcSPAPANI SRIKANTH }
662b17f4335SSean Bruno }
663b17f4335SSean Bruno return ret;
664b17f4335SSean Bruno }
665b17f4335SSean Bruno
666*7ea28254SJohn Hall void
pqisrc_complete_internal_cmds(pqisrc_softstate_t * softs)6679fac68fcSPAPANI SRIKANTH pqisrc_complete_internal_cmds(pqisrc_softstate_t *softs)
668b17f4335SSean Bruno {
6699fac68fcSPAPANI SRIKANTH
670b17f4335SSean Bruno int tag = 0;
671b17f4335SSean Bruno rcb_t *rcb;
672b17f4335SSean Bruno
673b17f4335SSean Bruno for (tag = 1; tag <= softs->max_outstanding_io; tag++) {
674b17f4335SSean Bruno rcb = &softs->rcb[tag];
675b17f4335SSean Bruno if(rcb->req_pending && is_internal_req(rcb)) {
676*7ea28254SJohn Hall rcb->status = PQI_STATUS_TIMEOUT;
677b17f4335SSean Bruno rcb->req_pending = false;
678b17f4335SSean Bruno }
679b17f4335SSean Bruno }
680b17f4335SSean Bruno }
681b17f4335SSean Bruno
6829fac68fcSPAPANI SRIKANTH
6831e66f787SSean Bruno /*
6841e66f787SSean Bruno * Uninitialize the resources used during PQI initialization.
6851e66f787SSean Bruno */
6869fac68fcSPAPANI SRIKANTH void
pqisrc_pqi_uninit(pqisrc_softstate_t * softs)6879fac68fcSPAPANI SRIKANTH pqisrc_pqi_uninit(pqisrc_softstate_t *softs)
6881e66f787SSean Bruno {
689*7ea28254SJohn Hall int ret;
690b17f4335SSean Bruno
6911e66f787SSean Bruno DBG_FUNC("IN\n");
6921e66f787SSean Bruno
693b17f4335SSean Bruno /* Wait for any rescan to finish */
694b17f4335SSean Bruno pqisrc_wait_for_rescan_complete(softs);
695b17f4335SSean Bruno
696b17f4335SSean Bruno /* Wait for commands to complete */
697b17f4335SSean Bruno ret = pqisrc_wait_for_cmnd_complete(softs);
698b17f4335SSean Bruno
6999fac68fcSPAPANI SRIKANTH /* disable and free the interrupt resources */
7009fac68fcSPAPANI SRIKANTH os_destroy_intr(softs);
7019fac68fcSPAPANI SRIKANTH
702b17f4335SSean Bruno /* Complete all pending commands. */
703b17f4335SSean Bruno if(ret != PQI_STATUS_SUCCESS) {
704b17f4335SSean Bruno pqisrc_complete_internal_cmds(softs);
705b17f4335SSean Bruno os_complete_outstanding_cmds_nodevice(softs);
706b17f4335SSean Bruno }
707b17f4335SSean Bruno
7081e66f787SSean Bruno if(softs->devlist_lockcreated==true){
7091e66f787SSean Bruno os_uninit_spinlock(&softs->devlist_lock);
7101e66f787SSean Bruno softs->devlist_lockcreated = false;
7111e66f787SSean Bruno }
7121e66f787SSean Bruno
713*7ea28254SJohn Hall /* Free all queues */
714*7ea28254SJohn Hall pqisrc_destroy_op_ib_queues(softs);
715*7ea28254SJohn Hall pqisrc_destroy_op_ob_queues(softs);
716*7ea28254SJohn Hall pqisrc_destroy_event_queue(softs);
7179fac68fcSPAPANI SRIKANTH
7181e66f787SSean Bruno /* Free rcb */
7191e66f787SSean Bruno pqisrc_free_rcb(softs, softs->max_outstanding_io + 1);
7201e66f787SSean Bruno
7211e66f787SSean Bruno /* Free request id lists */
7221e66f787SSean Bruno pqisrc_destroy_taglist(softs,&softs->taglist);
7231e66f787SSean Bruno
7241e66f787SSean Bruno /* Free Admin Queue */
725*7ea28254SJohn Hall pqisrc_destroy_admin_queue(softs);
7261e66f787SSean Bruno
7271e66f787SSean Bruno /* Switch back to SIS mode */
7281e66f787SSean Bruno if (pqisrc_force_sis(softs)) {
7291e66f787SSean Bruno DBG_ERR("Failed to switch back the adapter to SIS mode!\n");
7301e66f787SSean Bruno }
7311e66f787SSean Bruno
7321e66f787SSean Bruno DBG_FUNC("OUT\n");
7331e66f787SSean Bruno }
7341e66f787SSean Bruno
735*7ea28254SJohn Hall
736*7ea28254SJohn Hall /*
737*7ea28254SJohn Hall * Function to do any sanity checks for OS macros
738*7ea28254SJohn Hall */
739*7ea28254SJohn Hall void
sanity_check_os_behavior(pqisrc_softstate_t * softs)740*7ea28254SJohn Hall sanity_check_os_behavior(pqisrc_softstate_t *softs)
741*7ea28254SJohn Hall {
742*7ea28254SJohn Hall #ifdef OS_ATOMIC64_INC
743*7ea28254SJohn Hall OS_ATOMIC64_T atomic_test_var = 0;
744*7ea28254SJohn Hall OS_ATOMIC64_T atomic_ret = 0;
745*7ea28254SJohn Hall
746*7ea28254SJohn Hall atomic_ret = OS_ATOMIC64_INC(&atomic_test_var);
747*7ea28254SJohn Hall ASSERT(atomic_ret == 1);
748*7ea28254SJohn Hall
749*7ea28254SJohn Hall atomic_ret = OS_ATOMIC64_INC(&atomic_test_var);
750*7ea28254SJohn Hall ASSERT(atomic_ret == 2);
751*7ea28254SJohn Hall
752*7ea28254SJohn Hall atomic_ret = OS_ATOMIC64_DEC(&atomic_test_var);
753*7ea28254SJohn Hall ASSERT(atomic_ret == 1);
754*7ea28254SJohn Hall #else
755*7ea28254SJohn Hall DBG_INIT("OS needs to define/implement atomic macros\n");
756*7ea28254SJohn Hall #endif
757*7ea28254SJohn Hall }
758*7ea28254SJohn Hall
7591e66f787SSean Bruno /*
7601e66f787SSean Bruno * Function to initialize the adapter settings.
7611e66f787SSean Bruno */
7629fac68fcSPAPANI SRIKANTH int
pqisrc_init(pqisrc_softstate_t * softs)7639fac68fcSPAPANI SRIKANTH pqisrc_init(pqisrc_softstate_t *softs)
7641e66f787SSean Bruno {
7651e66f787SSean Bruno int ret = 0;
766*7ea28254SJohn Hall uint32_t ctrl_type;
7671e66f787SSean Bruno
7681e66f787SSean Bruno DBG_FUNC("IN\n");
7691e66f787SSean Bruno
770*7ea28254SJohn Hall sanity_check_os_behavior(softs);
771*7ea28254SJohn Hall
7721e66f787SSean Bruno check_struct_sizes();
7731e66f787SSean Bruno
774*7ea28254SJohn Hall /*Get verbose flags, defined in OS code XX_debug.h or so*/
775*7ea28254SJohn Hall #ifdef DISABLE_ERR_RESP_VERBOSE
776*7ea28254SJohn Hall softs->err_resp_verbose = false;
777*7ea28254SJohn Hall #else
778*7ea28254SJohn Hall softs->err_resp_verbose = true;
779*7ea28254SJohn Hall #endif
780*7ea28254SJohn Hall
781*7ea28254SJohn Hall /* prevent attachment of revA hardware. */
782*7ea28254SJohn Hall ctrl_type = PQI_GET_CTRL_TYPE(softs);
783*7ea28254SJohn Hall if (ctrl_type == PQI_CTRL_PRODUCT_ID_GEN2_REV_A) {
784*7ea28254SJohn Hall DBG_ERR("adapter at B.D.F=%u.%u.%u: unsupported RevA card.\n",
785*7ea28254SJohn Hall softs->bus_id, softs->device_id, softs->func_id);
786*7ea28254SJohn Hall ret = PQI_STATUS_FAILURE;
787*7ea28254SJohn Hall goto err_out;
788*7ea28254SJohn Hall }
789*7ea28254SJohn Hall
790*7ea28254SJohn Hall /* Increment the global adapter ID and tie it to this BDF */
791*7ea28254SJohn Hall #ifdef OS_ATOMIC64_INC
792*7ea28254SJohn Hall static OS_ATOMIC64_T g_adapter_cnt = 0;
793*7ea28254SJohn Hall softs->adapter_num = (uint8_t)OS_ATOMIC64_INC(&g_adapter_cnt);
794*7ea28254SJohn Hall #else
795*7ea28254SJohn Hall static uint64_t g_adapter_cnt = 0;
796*7ea28254SJohn Hall softs->adapter_num = (uint8_t)++g_adapter_cnt;
797*7ea28254SJohn Hall #endif
798*7ea28254SJohn Hall DBG_NOTE("Initializing adapter %u\n", (uint32_t)softs->adapter_num);
799*7ea28254SJohn Hall
800*7ea28254SJohn Hall ret = os_create_semaphore("scan_lock", 1, &softs->scan_lock);
801*7ea28254SJohn Hall if(ret != PQI_STATUS_SUCCESS){
802*7ea28254SJohn Hall DBG_ERR(" Failed to initialize scan lock\n");
803*7ea28254SJohn Hall goto err_out;
804*7ea28254SJohn Hall }
805*7ea28254SJohn Hall
8061e66f787SSean Bruno /* Init the Sync interface */
8071e66f787SSean Bruno ret = pqisrc_sis_init(softs);
8081e66f787SSean Bruno if (ret) {
8091e66f787SSean Bruno DBG_ERR("SIS Init failed with error %d\n", ret);
810*7ea28254SJohn Hall goto err_sis;
8111e66f787SSean Bruno }
8121e66f787SSean Bruno
813b17f4335SSean Bruno
8141e66f787SSean Bruno /* Init the PQI interface */
8151e66f787SSean Bruno ret = pqisrc_pqi_init(softs);
8161e66f787SSean Bruno if (ret) {
8171e66f787SSean Bruno DBG_ERR("PQI Init failed with error %d\n", ret);
8181e66f787SSean Bruno goto err_pqi;
8191e66f787SSean Bruno }
8201e66f787SSean Bruno
8211e66f787SSean Bruno /* Setup interrupt */
8221e66f787SSean Bruno ret = os_setup_intr(softs);
8231e66f787SSean Bruno if (ret) {
8241e66f787SSean Bruno DBG_ERR("Interrupt setup failed with error %d\n", ret);
8251e66f787SSean Bruno goto err_intr;
8261e66f787SSean Bruno }
8271e66f787SSean Bruno
8281e66f787SSean Bruno /* Report event configuration */
8291e66f787SSean Bruno ret = pqisrc_report_event_config(softs);
8301e66f787SSean Bruno if(ret){
8311e66f787SSean Bruno DBG_ERR(" Failed to configure Report events\n");
8321e66f787SSean Bruno goto err_event;
8331e66f787SSean Bruno }
8341e66f787SSean Bruno
8351e66f787SSean Bruno /* Set event configuration*/
8361e66f787SSean Bruno ret = pqisrc_set_event_config(softs);
8371e66f787SSean Bruno if(ret){
8381e66f787SSean Bruno DBG_ERR(" Failed to configure Set events\n");
8391e66f787SSean Bruno goto err_event;
8401e66f787SSean Bruno }
8411e66f787SSean Bruno
8421e66f787SSean Bruno /* Check for For PQI spanning */
8431e66f787SSean Bruno ret = pqisrc_get_ctrl_fw_version(softs);
8441e66f787SSean Bruno if(ret){
8451e66f787SSean Bruno DBG_ERR(" Failed to get ctrl fw version\n");
8461e66f787SSean Bruno goto err_fw_version;
8471e66f787SSean Bruno }
8481e66f787SSean Bruno
8491e66f787SSean Bruno /* update driver version in to FW */
8501e66f787SSean Bruno ret = pqisrc_write_driver_version_to_host_wellness(softs);
8511e66f787SSean Bruno if (ret) {
8521e66f787SSean Bruno DBG_ERR(" Failed to update driver version in to FW");
8531e66f787SSean Bruno goto err_host_wellness;
8541e66f787SSean Bruno }
8551e66f787SSean Bruno
856*7ea28254SJohn Hall /* Setup sense features */
857*7ea28254SJohn Hall ret = pqisrc_QuerySenseFeatures(softs);
858*7ea28254SJohn Hall if (ret) {
859*7ea28254SJohn Hall DBG_ERR("Failed to get sense features\n");
860*7ea28254SJohn Hall goto err_sense;
861*7ea28254SJohn Hall }
8621e66f787SSean Bruno
8631e66f787SSean Bruno os_strlcpy(softs->devlist_lock_name, "devlist_lock", LOCKNAME_SIZE);
8641e66f787SSean Bruno ret = os_init_spinlock(softs, &softs->devlist_lock, softs->devlist_lock_name);
8651e66f787SSean Bruno if(ret){
8661e66f787SSean Bruno DBG_ERR(" Failed to initialize devlist_lock\n");
8671e66f787SSean Bruno softs->devlist_lockcreated=false;
8681e66f787SSean Bruno goto err_lock;
8691e66f787SSean Bruno }
8701e66f787SSean Bruno softs->devlist_lockcreated = true;
8711e66f787SSean Bruno
8721e66f787SSean Bruno /* Get the PQI configuration table to read heart-beat counter*/
8731e66f787SSean Bruno ret = pqisrc_process_config_table(softs);
8741e66f787SSean Bruno if (ret) {
8751e66f787SSean Bruno DBG_ERR("Failed to process PQI configuration table %d\n", ret);
8761e66f787SSean Bruno goto err_config_tab;
8771e66f787SSean Bruno }
8781e66f787SSean Bruno
8791e66f787SSean Bruno softs->prev_heartbeat_count = CTRLR_HEARTBEAT_CNT(softs) - OS_FW_HEARTBEAT_TIMER_INTERVAL;
8801e66f787SSean Bruno
881*7ea28254SJohn Hall memset(softs->dev_list, 0, sizeof(*softs->dev_list));
882*7ea28254SJohn Hall pqisrc_init_bitmap(softs);
883b17f4335SSean Bruno
8841e66f787SSean Bruno DBG_FUNC("OUT\n");
8851e66f787SSean Bruno return ret;
8861e66f787SSean Bruno
8871e66f787SSean Bruno err_config_tab:
8881e66f787SSean Bruno if(softs->devlist_lockcreated==true){
8891e66f787SSean Bruno os_uninit_spinlock(&softs->devlist_lock);
8901e66f787SSean Bruno softs->devlist_lockcreated = false;
8911e66f787SSean Bruno }
8921e66f787SSean Bruno err_lock:
8931e66f787SSean Bruno err_fw_version:
8941e66f787SSean Bruno err_event:
8951e66f787SSean Bruno err_host_wellness:
8961e66f787SSean Bruno err_intr:
897*7ea28254SJohn Hall err_sense:
8981e66f787SSean Bruno pqisrc_pqi_uninit(softs);
8991e66f787SSean Bruno err_pqi:
9001e66f787SSean Bruno pqisrc_sis_uninit(softs);
901*7ea28254SJohn Hall err_sis:
902*7ea28254SJohn Hall os_destroy_semaphore(&softs->scan_lock);
9031e66f787SSean Bruno err_out:
9041e66f787SSean Bruno DBG_FUNC("OUT failed\n");
9051e66f787SSean Bruno return ret;
9061e66f787SSean Bruno }
9071e66f787SSean Bruno
9081e66f787SSean Bruno /*
9091e66f787SSean Bruno * Write all data in the adapter's battery-backed cache to
9101e66f787SSean Bruno * storage.
9111e66f787SSean Bruno */
9129fac68fcSPAPANI SRIKANTH int
pqisrc_flush_cache(pqisrc_softstate_t * softs,enum pqisrc_flush_cache_event_type event_type)9139fac68fcSPAPANI SRIKANTH pqisrc_flush_cache( pqisrc_softstate_t *softs,
9141e66f787SSean Bruno enum pqisrc_flush_cache_event_type event_type)
9151e66f787SSean Bruno {
9161e66f787SSean Bruno int rval = PQI_STATUS_SUCCESS;
9171e66f787SSean Bruno pqisrc_raid_req_t request;
9181e66f787SSean Bruno pqisrc_bmic_flush_cache_t *flush_buff = NULL;
9191e66f787SSean Bruno
9201e66f787SSean Bruno DBG_FUNC("IN\n");
9211e66f787SSean Bruno
9221e66f787SSean Bruno if (pqisrc_ctrl_offline(softs))
9231e66f787SSean Bruno return PQI_STATUS_FAILURE;
9241e66f787SSean Bruno
9251e66f787SSean Bruno flush_buff = os_mem_alloc(softs, sizeof(pqisrc_bmic_flush_cache_t));
9261e66f787SSean Bruno if (!flush_buff) {
9271e66f787SSean Bruno DBG_ERR("Failed to allocate memory for flush cache params\n");
9281e66f787SSean Bruno rval = PQI_STATUS_FAILURE;
9291e66f787SSean Bruno return rval;
9301e66f787SSean Bruno }
9311e66f787SSean Bruno
9321e66f787SSean Bruno flush_buff->halt_event = event_type;
9331e66f787SSean Bruno
9341e66f787SSean Bruno memset(&request, 0, sizeof(request));
9351e66f787SSean Bruno
936*7ea28254SJohn Hall request.data_direction = SOP_DATA_DIR_FROM_DEVICE;
937*7ea28254SJohn Hall request.cmd.bmic_cdb.op_code = BMIC_WRITE;
938*7ea28254SJohn Hall request.cmd.bmic_cdb.cmd = BMIC_CACHE_FLUSH;
939*7ea28254SJohn Hall request.cmd.bmic_cdb.xfer_len = BE_16(sizeof(*flush_buff));
940*7ea28254SJohn Hall
941*7ea28254SJohn Hall rval = pqisrc_prepare_send_ctrlr_request(softs, &request, flush_buff, sizeof(*flush_buff));
942*7ea28254SJohn Hall
9431e66f787SSean Bruno if (rval) {
9441e66f787SSean Bruno DBG_ERR("error in build send raid req ret=%d\n", rval);
9451e66f787SSean Bruno }
9461e66f787SSean Bruno
947*7ea28254SJohn Hall os_mem_free(softs, (void *)flush_buff, sizeof(pqisrc_bmic_flush_cache_t));
9481e66f787SSean Bruno
9491e66f787SSean Bruno DBG_FUNC("OUT\n");
9501e66f787SSean Bruno
9511e66f787SSean Bruno return rval;
9521e66f787SSean Bruno }
9531e66f787SSean Bruno
9541e66f787SSean Bruno /*
9551e66f787SSean Bruno * Uninitialize the adapter.
9561e66f787SSean Bruno */
9579fac68fcSPAPANI SRIKANTH void
pqisrc_uninit(pqisrc_softstate_t * softs)9589fac68fcSPAPANI SRIKANTH pqisrc_uninit(pqisrc_softstate_t *softs)
9591e66f787SSean Bruno {
9601e66f787SSean Bruno DBG_FUNC("IN\n");
9611e66f787SSean Bruno
9621e66f787SSean Bruno pqisrc_pqi_uninit(softs);
9631e66f787SSean Bruno
9641e66f787SSean Bruno pqisrc_sis_uninit(softs);
9651e66f787SSean Bruno
966b17f4335SSean Bruno os_destroy_semaphore(&softs->scan_lock);
967b17f4335SSean Bruno
9681e66f787SSean Bruno pqisrc_cleanup_devices(softs);
9691e66f787SSean Bruno
9701e66f787SSean Bruno DBG_FUNC("OUT\n");
9711e66f787SSean Bruno }
972