xref: /freebsd/sys/dev/smartpqi/smartpqi_helper.c (revision b17f4335d2becd4ad1a74636675e4a3d273807a2)
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