11e66f787SSean Bruno /*- 21e66f787SSean Bruno * Copyright (c) 2018 Microsemi Corporation. 31e66f787SSean Bruno * All rights reserved. 41e66f787SSean Bruno * 51e66f787SSean Bruno * Redistribution and use in source and binary forms, with or without 61e66f787SSean Bruno * modification, are permitted provided that the following conditions 71e66f787SSean Bruno * are met: 81e66f787SSean Bruno * 1. Redistributions of source code must retain the above copyright 91e66f787SSean Bruno * notice, this list of conditions and the following disclaimer. 101e66f787SSean Bruno * 2. Redistributions in binary form must reproduce the above copyright 111e66f787SSean Bruno * notice, this list of conditions and the following disclaimer in the 121e66f787SSean Bruno * documentation and/or other materials provided with the distribution. 131e66f787SSean Bruno * 141e66f787SSean Bruno * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 151e66f787SSean Bruno * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 161e66f787SSean Bruno * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 171e66f787SSean Bruno * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 181e66f787SSean Bruno * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 191e66f787SSean Bruno * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 201e66f787SSean Bruno * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 211e66f787SSean Bruno * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 221e66f787SSean Bruno * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 231e66f787SSean Bruno * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 241e66f787SSean Bruno * SUCH DAMAGE. 251e66f787SSean Bruno */ 261e66f787SSean Bruno 271e66f787SSean Bruno /* $FreeBSD$ */ 281e66f787SSean Bruno 291e66f787SSean Bruno #include "smartpqi_includes.h" 301e66f787SSean Bruno 311e66f787SSean Bruno /* 321e66f787SSean Bruno * Function used to validate the adapter health. 331e66f787SSean Bruno */ 341e66f787SSean Bruno boolean_t pqisrc_ctrl_offline(pqisrc_softstate_t *softs) 351e66f787SSean Bruno { 361e66f787SSean Bruno DBG_FUNC("IN\n"); 371e66f787SSean Bruno 381e66f787SSean Bruno DBG_FUNC("OUT\n"); 391e66f787SSean Bruno 401e66f787SSean Bruno return !softs->ctrl_online; 411e66f787SSean Bruno } 421e66f787SSean Bruno 43*b17f4335SSean Bruno /* Function used set/clear legacy INTx bit in Legacy Interrupt INTx 44*b17f4335SSean Bruno * mask clear pqi register 45*b17f4335SSean Bruno */ 46*b17f4335SSean Bruno void pqisrc_configure_legacy_intx(pqisrc_softstate_t *softs, boolean_t enable_intx) 47*b17f4335SSean Bruno { 48*b17f4335SSean Bruno uint32_t intx_mask; 49*b17f4335SSean Bruno uint32_t *reg_addr = NULL; 50*b17f4335SSean Bruno 51*b17f4335SSean Bruno DBG_FUNC("IN\n"); 52*b17f4335SSean Bruno 53*b17f4335SSean Bruno if (enable_intx) 54*b17f4335SSean Bruno reg_addr = &softs->pqi_reg->legacy_intr_mask_clr; 55*b17f4335SSean Bruno else 56*b17f4335SSean Bruno reg_addr = &softs->pqi_reg->legacy_intr_mask_set; 57*b17f4335SSean Bruno 58*b17f4335SSean Bruno intx_mask = PCI_MEM_GET32(softs, reg_addr, PQI_LEGACY_INTR_MASK_CLR); 59*b17f4335SSean Bruno intx_mask |= PQISRC_LEGACY_INTX_MASK; 60*b17f4335SSean Bruno PCI_MEM_PUT32(softs, reg_addr, PQI_LEGACY_INTR_MASK_CLR ,intx_mask); 61*b17f4335SSean Bruno 62*b17f4335SSean Bruno DBG_FUNC("OUT\n"); 63*b17f4335SSean Bruno } 64*b17f4335SSean Bruno 651e66f787SSean Bruno /* 661e66f787SSean Bruno * Function used to take exposed devices to OS as offline. 671e66f787SSean Bruno */ 681e66f787SSean Bruno void pqisrc_take_devices_offline(pqisrc_softstate_t *softs) 691e66f787SSean Bruno { 701e66f787SSean Bruno pqi_scsi_dev_t *device = NULL; 711e66f787SSean Bruno int i,j; 721e66f787SSean Bruno 731e66f787SSean Bruno DBG_FUNC("IN\n"); 741e66f787SSean Bruno for(i = 0; i < PQI_MAX_DEVICES; i++) { 751e66f787SSean Bruno for(j = 0; j < PQI_MAX_MULTILUN; j++) { 761e66f787SSean Bruno if(softs->device_list[i][j] == NULL) 771e66f787SSean Bruno continue; 781e66f787SSean Bruno device = softs->device_list[i][j]; 791e66f787SSean Bruno pqisrc_remove_device(softs, device); 801e66f787SSean Bruno } 811e66f787SSean Bruno } 821e66f787SSean Bruno 831e66f787SSean Bruno DBG_FUNC("OUT\n"); 841e66f787SSean Bruno } 851e66f787SSean Bruno 861e66f787SSean Bruno /* 871e66f787SSean Bruno * Function used to take adapter offline. 881e66f787SSean Bruno */ 891e66f787SSean Bruno void pqisrc_take_ctrl_offline(pqisrc_softstate_t *softs) 901e66f787SSean Bruno { 911e66f787SSean Bruno 921e66f787SSean Bruno DBG_FUNC("IN\n"); 931e66f787SSean Bruno 941e66f787SSean Bruno softs->ctrl_online = false; 951e66f787SSean Bruno pqisrc_trigger_nmi_sis(softs); 961e66f787SSean Bruno os_complete_outstanding_cmds_nodevice(softs); 971e66f787SSean Bruno pqisrc_take_devices_offline(softs); 981e66f787SSean Bruno 991e66f787SSean Bruno DBG_FUNC("OUT\n"); 1001e66f787SSean Bruno } 1011e66f787SSean Bruno 1021e66f787SSean Bruno /* 1031e66f787SSean Bruno * Timer handler for the adapter heart-beat. 1041e66f787SSean Bruno */ 1051e66f787SSean Bruno void pqisrc_heartbeat_timer_handler(pqisrc_softstate_t *softs) 1061e66f787SSean Bruno { 1071e66f787SSean Bruno uint64_t num_intrs; 1081e66f787SSean Bruno uint8_t take_offline = false; 1091e66f787SSean Bruno 1101e66f787SSean Bruno DBG_FUNC("IN\n"); 1111e66f787SSean Bruno 1121e66f787SSean Bruno num_intrs = OS_ATOMIC64_READ(softs, num_intrs); 1131e66f787SSean Bruno 1141e66f787SSean Bruno if (PQI_NEW_HEARTBEAT_MECHANISM(softs)) { 1151e66f787SSean Bruno if (CTRLR_HEARTBEAT_CNT(softs) == softs->prev_heartbeat_count) { 1161e66f787SSean Bruno take_offline = true; 1171e66f787SSean Bruno goto take_ctrl_offline; 1181e66f787SSean Bruno } 1191e66f787SSean Bruno softs->prev_heartbeat_count = CTRLR_HEARTBEAT_CNT(softs); 1201e66f787SSean Bruno DBG_INFO("CTRLR_HEARTBEAT_CNT(softs) = %lx \ 1211e66f787SSean Bruno softs->prev_heartbeat_count = %lx\n", 1221e66f787SSean Bruno CTRLR_HEARTBEAT_CNT(softs), softs->prev_heartbeat_count); 1231e66f787SSean Bruno } else { 1241e66f787SSean Bruno if (num_intrs == softs->prev_num_intrs) { 1251e66f787SSean Bruno softs->num_heartbeats_requested++; 1261e66f787SSean Bruno if (softs->num_heartbeats_requested > PQI_MAX_HEARTBEAT_REQUESTS) { 1271e66f787SSean Bruno take_offline = true; 1281e66f787SSean Bruno goto take_ctrl_offline; 1291e66f787SSean Bruno } 1301e66f787SSean Bruno softs->pending_events[PQI_EVENT_HEARTBEAT].pending = true; 1311e66f787SSean Bruno 1321e66f787SSean Bruno pqisrc_ack_all_events((void*)softs); 1331e66f787SSean Bruno 1341e66f787SSean Bruno } else { 1351e66f787SSean Bruno softs->num_heartbeats_requested = 0; 1361e66f787SSean Bruno } 1371e66f787SSean Bruno softs->prev_num_intrs = num_intrs; 1381e66f787SSean Bruno } 1391e66f787SSean Bruno 1401e66f787SSean Bruno take_ctrl_offline: 1411e66f787SSean Bruno if (take_offline){ 1421e66f787SSean Bruno DBG_ERR("controller is offline\n"); 1431e66f787SSean Bruno pqisrc_take_ctrl_offline(softs); 1441e66f787SSean Bruno os_stop_heartbeat_timer(softs); 1451e66f787SSean Bruno } 1461e66f787SSean Bruno DBG_FUNC("OUT\n"); 1471e66f787SSean Bruno } 1481e66f787SSean Bruno 1491e66f787SSean Bruno /* 1501e66f787SSean Bruno * Conditional variable management routine for internal commands. 1511e66f787SSean Bruno */ 1521e66f787SSean Bruno int pqisrc_wait_on_condition(pqisrc_softstate_t *softs, rcb_t *rcb){ 1531e66f787SSean Bruno 1541e66f787SSean Bruno DBG_FUNC("IN\n"); 1551e66f787SSean Bruno 1561e66f787SSean Bruno int ret = PQI_STATUS_SUCCESS; 1571e66f787SSean Bruno uint32_t loop_cnt = 0; 1581e66f787SSean Bruno 1591e66f787SSean Bruno while (rcb->req_pending == true) { 1601e66f787SSean Bruno OS_SLEEP(500); /* Micro sec */ 1611e66f787SSean Bruno 1621e66f787SSean Bruno /*Polling needed for FreeBSD : since ithread routine is not scheduled 1631e66f787SSean Bruno during bootup, we could use polling until interrupts are 1641e66f787SSean Bruno enabled (using 'if (cold)'to check for the boot time before 1651e66f787SSean Bruno interrupts are enabled). */ 1661e66f787SSean Bruno IS_POLLING_REQUIRED(softs); 1671e66f787SSean Bruno 1681e66f787SSean Bruno if (loop_cnt++ == PQISRC_CMD_TIMEOUT_CNT) { 1691e66f787SSean Bruno DBG_ERR("ERR: Requested cmd timed out !!!\n"); 1701e66f787SSean Bruno ret = PQI_STATUS_TIMEOUT; 1711e66f787SSean Bruno break; 1721e66f787SSean Bruno } 1731e66f787SSean Bruno 1741e66f787SSean Bruno if (pqisrc_ctrl_offline(softs)) { 1751e66f787SSean Bruno DBG_ERR("Controller is Offline"); 1761e66f787SSean Bruno ret = PQI_STATUS_FAILURE; 1771e66f787SSean Bruno break; 1781e66f787SSean Bruno } 1791e66f787SSean Bruno 1801e66f787SSean Bruno } 1811e66f787SSean Bruno rcb->req_pending = true; 1821e66f787SSean Bruno 1831e66f787SSean Bruno DBG_FUNC("OUT\n"); 1841e66f787SSean Bruno 1851e66f787SSean Bruno return ret; 1861e66f787SSean Bruno } 1871e66f787SSean Bruno 1881e66f787SSean Bruno /* Function used to validate the device wwid. */ 1891e66f787SSean Bruno boolean_t pqisrc_device_equal(pqi_scsi_dev_t *dev1, 1901e66f787SSean Bruno pqi_scsi_dev_t *dev2) 1911e66f787SSean Bruno { 1921e66f787SSean Bruno return dev1->wwid == dev2->wwid; 1931e66f787SSean Bruno } 1941e66f787SSean Bruno 1951e66f787SSean Bruno /* Function used to validate the device scsi3addr. */ 1961e66f787SSean Bruno boolean_t pqisrc_scsi3addr_equal(uint8_t *scsi3addr1, uint8_t *scsi3addr2) 1971e66f787SSean Bruno { 1981e66f787SSean Bruno return memcmp(scsi3addr1, scsi3addr2, 8) == 0; 1991e66f787SSean Bruno } 2001e66f787SSean Bruno 2011e66f787SSean Bruno /* Function used to validate hba_lunid */ 2021e66f787SSean Bruno boolean_t pqisrc_is_hba_lunid(uint8_t *scsi3addr) 2031e66f787SSean Bruno { 2041e66f787SSean Bruno return pqisrc_scsi3addr_equal(scsi3addr, (uint8_t*)RAID_CTLR_LUNID); 2051e66f787SSean Bruno } 2061e66f787SSean Bruno 2071e66f787SSean Bruno /* Function used to validate type of device */ 2081e66f787SSean Bruno boolean_t pqisrc_is_logical_device(pqi_scsi_dev_t *device) 2091e66f787SSean Bruno { 2101e66f787SSean Bruno return !device->is_physical_device; 2111e66f787SSean Bruno } 2121e66f787SSean Bruno 2131e66f787SSean Bruno /* Function used to sanitize inquiry string */ 2141e66f787SSean Bruno void pqisrc_sanitize_inquiry_string(unsigned char *s, int len) 2151e66f787SSean Bruno { 2161e66f787SSean Bruno boolean_t terminated = false; 2171e66f787SSean Bruno 2181e66f787SSean Bruno DBG_FUNC("IN\n"); 2191e66f787SSean Bruno 2201e66f787SSean Bruno for (; len > 0; (--len, ++s)) { 2211e66f787SSean Bruno if (*s == 0) 2221e66f787SSean Bruno terminated = true; 2231e66f787SSean Bruno if (terminated || *s < 0x20 || *s > 0x7e) 2241e66f787SSean Bruno *s = ' '; 2251e66f787SSean Bruno } 2261e66f787SSean Bruno 2271e66f787SSean Bruno DBG_FUNC("OUT\n"); 2281e66f787SSean Bruno } 2291e66f787SSean Bruno 2301e66f787SSean Bruno static char *raid_levels[] = { 2311e66f787SSean Bruno "RAID 0", 2321e66f787SSean Bruno "RAID 4", 2331e66f787SSean Bruno "RAID 1(1+0)", 2341e66f787SSean Bruno "RAID 5", 2351e66f787SSean Bruno "RAID 5+1", 2361e66f787SSean Bruno "RAID ADG", 2371e66f787SSean Bruno "RAID 1(ADM)", 2381e66f787SSean Bruno }; 2391e66f787SSean Bruno 2401e66f787SSean Bruno /* Get the RAID level from the index */ 2411e66f787SSean Bruno char *pqisrc_raidlevel_to_string(uint8_t raid_level) 2421e66f787SSean Bruno { 2431e66f787SSean Bruno DBG_FUNC("IN\n"); 2441e66f787SSean Bruno if (raid_level < ARRAY_SIZE(raid_levels)) 2451e66f787SSean Bruno return raid_levels[raid_level]; 2461e66f787SSean Bruno DBG_FUNC("OUT\n"); 2471e66f787SSean Bruno 2481e66f787SSean Bruno return " "; 2491e66f787SSean Bruno } 2501e66f787SSean Bruno 2511e66f787SSean Bruno /* Debug routine for displaying device info */ 2521e66f787SSean Bruno void pqisrc_display_device_info(pqisrc_softstate_t *softs, 2531e66f787SSean Bruno char *action, pqi_scsi_dev_t *device) 2541e66f787SSean Bruno { 2551e66f787SSean Bruno DBG_INFO( "%s scsi BTL %d:%d:%d: %.8s %.16s %-12s SSDSmartPathCap%c En%c Exp%c qd=%d\n", 2561e66f787SSean Bruno action, 2571e66f787SSean Bruno device->bus, 2581e66f787SSean Bruno device->target, 2591e66f787SSean Bruno device->lun, 2601e66f787SSean Bruno device->vendor, 2611e66f787SSean Bruno device->model, 2621e66f787SSean Bruno pqisrc_raidlevel_to_string(device->raid_level), 2631e66f787SSean Bruno device->offload_config ? '+' : '-', 2641e66f787SSean Bruno device->offload_enabled_pending ? '+' : '-', 2651e66f787SSean Bruno device->expose_device ? '+' : '-', 2661e66f787SSean Bruno device->queue_depth); 2671e66f787SSean Bruno pqisrc_raidlevel_to_string(device->raid_level); /* To use this function */ 2681e66f787SSean Bruno } 2691e66f787SSean Bruno 2701e66f787SSean Bruno /* validate the structure sizes */ 2711e66f787SSean Bruno void check_struct_sizes() 2721e66f787SSean Bruno { 2731e66f787SSean Bruno 2741e66f787SSean Bruno ASSERT(sizeof(SCSI3Addr_struct)== 2); 2751e66f787SSean Bruno ASSERT(sizeof(PhysDevAddr_struct) == 8); 2761e66f787SSean Bruno ASSERT(sizeof(LogDevAddr_struct)== 8); 2771e66f787SSean Bruno ASSERT(sizeof(LUNAddr_struct)==8); 2781e66f787SSean Bruno ASSERT(sizeof(RequestBlock_struct) == 20); 2791e66f787SSean Bruno ASSERT(sizeof(MoreErrInfo_struct)== 8); 2801e66f787SSean Bruno ASSERT(sizeof(ErrorInfo_struct)== 48); 2811e66f787SSean Bruno ASSERT(sizeof(IOCTL_Command_struct)== 86); 2821e66f787SSean Bruno ASSERT(sizeof(struct bmic_host_wellness_driver_version)== 42); 2831e66f787SSean Bruno ASSERT(sizeof(struct bmic_host_wellness_time)== 20); 2841e66f787SSean Bruno ASSERT(sizeof(struct pqi_dev_adminq_cap)== 8); 2851e66f787SSean Bruno ASSERT(sizeof(struct admin_q_param)== 4); 2861e66f787SSean Bruno ASSERT(sizeof(struct pqi_registers)== 256); 2871e66f787SSean Bruno ASSERT(sizeof(struct ioa_registers)== 4128); 2881e66f787SSean Bruno ASSERT(sizeof(struct pqi_pref_settings)==4); 2891e66f787SSean Bruno ASSERT(sizeof(struct pqi_cap)== 20); 2901e66f787SSean Bruno ASSERT(sizeof(iu_header_t)== 4); 2911e66f787SSean Bruno ASSERT(sizeof(gen_adm_req_iu_t)== 64); 2921e66f787SSean Bruno ASSERT(sizeof(gen_adm_resp_iu_t)== 64); 2931e66f787SSean Bruno ASSERT(sizeof(op_q_params) == 9); 2941e66f787SSean Bruno ASSERT(sizeof(raid_path_error_info_elem_t)== 276); 2951e66f787SSean Bruno ASSERT(sizeof(aio_path_error_info_elem_t)== 276); 2961e66f787SSean Bruno ASSERT(sizeof(struct init_base_struct)== 24); 2971e66f787SSean Bruno ASSERT(sizeof(pqi_iu_layer_desc_t)== 16); 2981e66f787SSean Bruno ASSERT(sizeof(pqi_dev_cap_t)== 576); 2991e66f787SSean Bruno ASSERT(sizeof(pqi_aio_req_t)== 128); 3001e66f787SSean Bruno ASSERT(sizeof(pqisrc_raid_req_t)== 128); 3011e66f787SSean Bruno ASSERT(sizeof(pqi_tmf_req_t)== 32); 3021e66f787SSean Bruno ASSERT(sizeof(struct pqi_io_response)== 16); 3031e66f787SSean Bruno ASSERT(sizeof(struct sense_header_scsi)== 8); 3041e66f787SSean Bruno ASSERT(sizeof(reportlun_header_t)==8); 3051e66f787SSean Bruno ASSERT(sizeof(reportlun_ext_entry_t)== 24); 3061e66f787SSean Bruno ASSERT(sizeof(reportlun_data_ext_t)== 32); 3071e66f787SSean Bruno ASSERT(sizeof(raidmap_data_t)==8); 3081e66f787SSean Bruno ASSERT(sizeof(pqisrc_raid_map_t)== 8256); 3091e66f787SSean Bruno ASSERT(sizeof(bmic_ident_ctrl_t)== 325); 3101e66f787SSean Bruno ASSERT(sizeof(bmic_ident_physdev_t)==2048); 3111e66f787SSean Bruno 3121e66f787SSean Bruno } 313