xref: /freebsd/sys/dev/smartpqi/smartpqi_helper.c (revision d53e97bb5490cdedb37bd4e25646c5379b196c93)
11e66f787SSean Bruno /*-
29fac68fcSPAPANI SRIKANTH  * Copyright 2016-2021 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 /* $FreeBSD$ */
271e66f787SSean Bruno 
281e66f787SSean Bruno #include "smartpqi_includes.h"
291e66f787SSean Bruno 
309fac68fcSPAPANI SRIKANTH /* read and modify controller diagnostic option - PQI_PTRAID_UPDATE_ON_RESCAN_LUNS */
319fac68fcSPAPANI SRIKANTH void
329fac68fcSPAPANI SRIKANTH pqisrc_ctrl_diagnostic_options(pqisrc_softstate_t *softs)
339fac68fcSPAPANI SRIKANTH {
349fac68fcSPAPANI SRIKANTH 	int ret = PQI_STATUS_SUCCESS;
359fac68fcSPAPANI SRIKANTH 	uint32_t diags_options = 0;
369fac68fcSPAPANI SRIKANTH 	pqisrc_raid_req_t request;
379fac68fcSPAPANI SRIKANTH 
389fac68fcSPAPANI SRIKANTH 	DBG_NOTE("IN\n");
399fac68fcSPAPANI SRIKANTH 
409fac68fcSPAPANI SRIKANTH 	memset(&request, 0, sizeof(request));
419fac68fcSPAPANI SRIKANTH 	/* read diags options of controller */
429fac68fcSPAPANI SRIKANTH 	ret =  pqisrc_build_send_raid_request(softs, &request,
439fac68fcSPAPANI SRIKANTH 					(void*)&diags_options,
449fac68fcSPAPANI SRIKANTH 					sizeof(diags_options),
459fac68fcSPAPANI SRIKANTH 					BMIC_SENSE_DIAGS_OPTIONS,
469fac68fcSPAPANI SRIKANTH 					0, (uint8_t *)RAID_CTLR_LUNID, NULL);
479fac68fcSPAPANI SRIKANTH 	if (ret != PQI_STATUS_SUCCESS) {
489fac68fcSPAPANI SRIKANTH 		DBG_WARN("Request failed for BMIC Sense Diags Option command."
499fac68fcSPAPANI SRIKANTH 			"ret:%d\n",ret);
509fac68fcSPAPANI SRIKANTH 		return;
519fac68fcSPAPANI SRIKANTH 	}
529fac68fcSPAPANI SRIKANTH 	DBG_NOTE("diags options data after read: %#x\n",diags_options);
539fac68fcSPAPANI SRIKANTH 	diags_options |= PQI_PTRAID_UPDATE_ON_RESCAN_LUNS;
549fac68fcSPAPANI SRIKANTH 	DBG_NOTE("diags options data to write: %#x\n",diags_options);
559fac68fcSPAPANI SRIKANTH 	memset(&request, 0, sizeof(request));
569fac68fcSPAPANI SRIKANTH 	/* write specified diags options to controller */
579fac68fcSPAPANI SRIKANTH 	ret =  pqisrc_build_send_raid_request(softs, &request,
589fac68fcSPAPANI SRIKANTH 					(void*)&diags_options,
599fac68fcSPAPANI SRIKANTH 					sizeof(diags_options),
609fac68fcSPAPANI SRIKANTH 					BMIC_SET_DIAGS_OPTIONS,
619fac68fcSPAPANI SRIKANTH 					0, (uint8_t *)RAID_CTLR_LUNID, NULL);
629fac68fcSPAPANI SRIKANTH 	if (ret != PQI_STATUS_SUCCESS)
639fac68fcSPAPANI SRIKANTH 		DBG_WARN("Request failed for BMIC Set Diags Option command."
649fac68fcSPAPANI SRIKANTH 			"ret:%d\n",ret);
659fac68fcSPAPANI SRIKANTH #if 0
669fac68fcSPAPANI SRIKANTH 	diags_options = 0;
679fac68fcSPAPANI SRIKANTH 	memset(&request, 0, sizeof(request));
689fac68fcSPAPANI SRIKANTH 	ret =  pqisrc_build_send_raid_request(softs, &request,
699fac68fcSPAPANI SRIKANTH 					(void*)&diags_options,
709fac68fcSPAPANI SRIKANTH 					sizeof(diags_options),
719fac68fcSPAPANI SRIKANTH 					BMIC_SENSE_DIAGS_OPTIONS,
729fac68fcSPAPANI SRIKANTH 					0, (uint8_t *)RAID_CTLR_LUNID, NULL);
739fac68fcSPAPANI SRIKANTH 	if (ret != PQI_STATUS_SUCCESS)
749fac68fcSPAPANI SRIKANTH 		DBG_WARN("Request failed for BMIC Sense Diags Option command."
759fac68fcSPAPANI SRIKANTH 			"ret:%d\n",ret);
769fac68fcSPAPANI SRIKANTH 	DBG_NOTE("diags options after re-read: %#x\n",diags_options);
779fac68fcSPAPANI SRIKANTH #endif
789fac68fcSPAPANI SRIKANTH 	DBG_NOTE("OUT\n");
799fac68fcSPAPANI SRIKANTH }
809fac68fcSPAPANI SRIKANTH 
811e66f787SSean Bruno /*
821e66f787SSean Bruno  * Function used to validate the adapter health.
831e66f787SSean Bruno  */
849fac68fcSPAPANI SRIKANTH boolean_t
859fac68fcSPAPANI SRIKANTH pqisrc_ctrl_offline(pqisrc_softstate_t *softs)
861e66f787SSean Bruno {
871e66f787SSean Bruno 	DBG_FUNC("IN\n");
881e66f787SSean Bruno 
891e66f787SSean Bruno 	DBG_FUNC("OUT\n");
901e66f787SSean Bruno 
911e66f787SSean Bruno 	return !softs->ctrl_online;
921e66f787SSean Bruno }
931e66f787SSean Bruno 
94b17f4335SSean Bruno /* Function used set/clear legacy INTx bit in Legacy Interrupt INTx
95b17f4335SSean Bruno  * mask clear pqi register
96b17f4335SSean Bruno  */
979fac68fcSPAPANI SRIKANTH void
989fac68fcSPAPANI SRIKANTH pqisrc_configure_legacy_intx(pqisrc_softstate_t *softs, boolean_t enable_intx)
99b17f4335SSean Bruno {
100b17f4335SSean Bruno 	uint32_t intx_mask;
101e28289caSScott Long 	uint32_t *reg_addr __unused;
102b17f4335SSean Bruno 
103b17f4335SSean Bruno 	DBG_FUNC("IN\n");
104b17f4335SSean Bruno 
105b17f4335SSean Bruno 	if (enable_intx)
106b17f4335SSean Bruno 		reg_addr = &softs->pqi_reg->legacy_intr_mask_clr;
107b17f4335SSean Bruno 	else
108b17f4335SSean Bruno 		reg_addr = &softs->pqi_reg->legacy_intr_mask_set;
109b17f4335SSean Bruno 
110b17f4335SSean Bruno 	intx_mask = PCI_MEM_GET32(softs, reg_addr, PQI_LEGACY_INTR_MASK_CLR);
111b17f4335SSean Bruno 	intx_mask |= PQISRC_LEGACY_INTX_MASK;
112b17f4335SSean Bruno 	PCI_MEM_PUT32(softs, reg_addr, PQI_LEGACY_INTR_MASK_CLR ,intx_mask);
113b17f4335SSean Bruno 
114b17f4335SSean Bruno 	DBG_FUNC("OUT\n");
115b17f4335SSean Bruno }
116b17f4335SSean Bruno 
1171e66f787SSean Bruno /*
1181e66f787SSean Bruno  * Function used to take exposed devices to OS as offline.
1191e66f787SSean Bruno  */
1209fac68fcSPAPANI SRIKANTH void
1219fac68fcSPAPANI SRIKANTH pqisrc_take_devices_offline(pqisrc_softstate_t *softs)
1221e66f787SSean Bruno {
1231e66f787SSean Bruno 	pqi_scsi_dev_t *device = NULL;
1241e66f787SSean Bruno 	int i,j;
1251e66f787SSean Bruno 
1261e66f787SSean Bruno 	DBG_FUNC("IN\n");
1271e66f787SSean Bruno 	for(i = 0; i < PQI_MAX_DEVICES; i++) {
1281e66f787SSean Bruno 		for(j = 0; j < PQI_MAX_MULTILUN; j++) {
1291e66f787SSean Bruno 			if(softs->device_list[i][j] == NULL)
1301e66f787SSean Bruno 				continue;
1311e66f787SSean Bruno 			device = softs->device_list[i][j];
1321e66f787SSean Bruno 			pqisrc_remove_device(softs, device);
1331e66f787SSean Bruno 		}
1341e66f787SSean Bruno 	}
1351e66f787SSean Bruno 
1361e66f787SSean Bruno 	DBG_FUNC("OUT\n");
1371e66f787SSean Bruno }
1381e66f787SSean Bruno 
1391e66f787SSean Bruno /*
1401e66f787SSean Bruno  * Function used to take adapter offline.
1411e66f787SSean Bruno  */
1429fac68fcSPAPANI SRIKANTH void
1439fac68fcSPAPANI SRIKANTH pqisrc_take_ctrl_offline(pqisrc_softstate_t *softs)
1441e66f787SSean Bruno {
1451e66f787SSean Bruno 	DBG_FUNC("IN\n");
1461e66f787SSean Bruno 
1471e66f787SSean Bruno 	softs->ctrl_online = false;
1489fac68fcSPAPANI SRIKANTH 
1499fac68fcSPAPANI SRIKANTH 	int lockupcode = 0;
1509fac68fcSPAPANI SRIKANTH 
1519fac68fcSPAPANI SRIKANTH 	if (SIS_IS_KERNEL_PANIC(softs)) {
1529fac68fcSPAPANI SRIKANTH                 lockupcode = PCI_MEM_GET32(softs, &softs->ioa_reg->mb[7], LEGACY_SIS_SRCV_OFFSET_MAILBOX_7);
153*d53e97bbSGordon Bergling                 DBG_ERR("Controller FW is not running, Lockup code = %x\n", lockupcode);
1549fac68fcSPAPANI SRIKANTH         }
1559fac68fcSPAPANI SRIKANTH         else {
1561e66f787SSean Bruno                 pqisrc_trigger_nmi_sis(softs);
1579fac68fcSPAPANI SRIKANTH         }
1589fac68fcSPAPANI SRIKANTH 
1591e66f787SSean Bruno 	os_complete_outstanding_cmds_nodevice(softs);
1609fac68fcSPAPANI SRIKANTH 	pqisrc_wait_for_rescan_complete(softs);
1611e66f787SSean Bruno 	pqisrc_take_devices_offline(softs);
1621e66f787SSean Bruno 
1631e66f787SSean Bruno 	DBG_FUNC("OUT\n");
1641e66f787SSean Bruno }
1651e66f787SSean Bruno 
1661e66f787SSean Bruno /*
1671e66f787SSean Bruno  * Timer handler for the adapter heart-beat.
1681e66f787SSean Bruno  */
1699fac68fcSPAPANI SRIKANTH void
1709fac68fcSPAPANI SRIKANTH pqisrc_heartbeat_timer_handler(pqisrc_softstate_t *softs)
1711e66f787SSean Bruno {
1721e66f787SSean Bruno 	uint8_t take_offline = false;
1731e66f787SSean Bruno 
1741e66f787SSean Bruno 	DBG_FUNC("IN\n");
1751e66f787SSean Bruno 
1761e66f787SSean Bruno 	if (CTRLR_HEARTBEAT_CNT(softs) == softs->prev_heartbeat_count) {
1771e66f787SSean Bruno 		take_offline = true;
1781e66f787SSean Bruno 		goto take_ctrl_offline;
1791e66f787SSean Bruno 	}
1801e66f787SSean Bruno 	softs->prev_heartbeat_count = CTRLR_HEARTBEAT_CNT(softs);
1811e66f787SSean Bruno 	DBG_INFO("CTRLR_HEARTBEAT_CNT(softs)  = %lx \
1821e66f787SSean Bruno 		softs->prev_heartbeat_count = %lx\n",
1831e66f787SSean Bruno 		CTRLR_HEARTBEAT_CNT(softs), softs->prev_heartbeat_count);
1841e66f787SSean Bruno 
1851e66f787SSean Bruno take_ctrl_offline:
1861e66f787SSean Bruno 	if (take_offline){
1871e66f787SSean Bruno 		DBG_ERR("controller is offline\n");
1881e66f787SSean Bruno 		pqisrc_take_ctrl_offline(softs);
1891e66f787SSean Bruno 		os_stop_heartbeat_timer(softs);
1901e66f787SSean Bruno 	}
1911e66f787SSean Bruno 	DBG_FUNC("OUT\n");
1921e66f787SSean Bruno }
1931e66f787SSean Bruno 
1941e66f787SSean Bruno /*
1951e66f787SSean Bruno  * Conditional variable management routine for internal commands.
1961e66f787SSean Bruno  */
1979fac68fcSPAPANI SRIKANTH int
1989fac68fcSPAPANI SRIKANTH pqisrc_wait_on_condition(pqisrc_softstate_t *softs, rcb_t *rcb,
1999fac68fcSPAPANI SRIKANTH 				uint32_t timeout_in_msec)
2009fac68fcSPAPANI SRIKANTH {
2011e66f787SSean Bruno 	DBG_FUNC("IN\n");
2021e66f787SSean Bruno 
2031e66f787SSean Bruno 	int ret = PQI_STATUS_SUCCESS;
2049fac68fcSPAPANI SRIKANTH 
2059fac68fcSPAPANI SRIKANTH 	/* 1 msec = 500 usec * 2 */
2069fac68fcSPAPANI SRIKANTH 	uint32_t loop_cnt = timeout_in_msec * 2;
2079fac68fcSPAPANI SRIKANTH 	uint32_t i = 0;
2081e66f787SSean Bruno 
2091e66f787SSean Bruno 	while (rcb->req_pending == true) {
2101e66f787SSean Bruno 		OS_SLEEP(500); /* Micro sec */
2111e66f787SSean Bruno 		/* Polling needed for FreeBSD : since ithread routine is not scheduled
2129fac68fcSPAPANI SRIKANTH 		 * during bootup, we could use polling until interrupts are
2139fac68fcSPAPANI SRIKANTH 		 * enabled (using 'if (cold)'to check for the boot time before
2149fac68fcSPAPANI SRIKANTH 		 * interrupts are enabled). */
2151e66f787SSean Bruno 		IS_POLLING_REQUIRED(softs);
2161e66f787SSean Bruno 
2179fac68fcSPAPANI SRIKANTH 		if ((timeout_in_msec != TIMEOUT_INFINITE) && (i++ == loop_cnt)) {
2181e66f787SSean Bruno 			DBG_ERR("ERR: Requested cmd timed out !!!\n");
2191e66f787SSean Bruno 			ret = PQI_STATUS_TIMEOUT;
2209fac68fcSPAPANI SRIKANTH 			rcb->timedout = true;
2211e66f787SSean Bruno 			break;
2221e66f787SSean Bruno 		}
2231e66f787SSean Bruno 
2241e66f787SSean Bruno 		if (pqisrc_ctrl_offline(softs)) {
2251e66f787SSean Bruno 			DBG_ERR("Controller is Offline");
2261e66f787SSean Bruno 			ret = PQI_STATUS_FAILURE;
2271e66f787SSean Bruno 			break;
2281e66f787SSean Bruno 		}
2299fac68fcSPAPANI SRIKANTH 
2301e66f787SSean Bruno 	}
2311e66f787SSean Bruno 	rcb->req_pending = true;
2321e66f787SSean Bruno 
2331e66f787SSean Bruno 	DBG_FUNC("OUT\n");
2341e66f787SSean Bruno 
2351e66f787SSean Bruno 	return ret;
2361e66f787SSean Bruno }
2371e66f787SSean Bruno 
2381e66f787SSean Bruno /* Function used to validate the device wwid. */
2399fac68fcSPAPANI SRIKANTH boolean_t
2409fac68fcSPAPANI SRIKANTH pqisrc_device_equal(pqi_scsi_dev_t *dev1,
2411e66f787SSean Bruno 	pqi_scsi_dev_t *dev2)
2421e66f787SSean Bruno {
2431e66f787SSean Bruno 	return dev1->wwid == dev2->wwid;
2441e66f787SSean Bruno }
2451e66f787SSean Bruno 
2461e66f787SSean Bruno /* Function used to validate the device scsi3addr. */
2479fac68fcSPAPANI SRIKANTH boolean_t
2489fac68fcSPAPANI SRIKANTH pqisrc_scsi3addr_equal(uint8_t *scsi3addr1, uint8_t *scsi3addr2)
2491e66f787SSean Bruno {
2501e66f787SSean Bruno 	return memcmp(scsi3addr1, scsi3addr2, 8) == 0;
2511e66f787SSean Bruno }
2521e66f787SSean Bruno 
2531e66f787SSean Bruno /* Function used to validate hba_lunid */
2549fac68fcSPAPANI SRIKANTH boolean_t
2559fac68fcSPAPANI SRIKANTH pqisrc_is_hba_lunid(uint8_t *scsi3addr)
2561e66f787SSean Bruno {
2571e66f787SSean Bruno 	return pqisrc_scsi3addr_equal(scsi3addr, (uint8_t*)RAID_CTLR_LUNID);
2581e66f787SSean Bruno }
2591e66f787SSean Bruno 
2601e66f787SSean Bruno /* Function used to validate type of device */
2619fac68fcSPAPANI SRIKANTH boolean_t
2629fac68fcSPAPANI SRIKANTH pqisrc_is_logical_device(pqi_scsi_dev_t *device)
2631e66f787SSean Bruno {
2641e66f787SSean Bruno 	return !device->is_physical_device;
2651e66f787SSean Bruno }
2661e66f787SSean Bruno 
2671e66f787SSean Bruno /* Function used to sanitize inquiry string */
2689fac68fcSPAPANI SRIKANTH void
2699fac68fcSPAPANI SRIKANTH pqisrc_sanitize_inquiry_string(unsigned char *s, int len)
2701e66f787SSean Bruno {
2711e66f787SSean Bruno 	boolean_t terminated = false;
2721e66f787SSean Bruno 
2731e66f787SSean Bruno 	DBG_FUNC("IN\n");
2741e66f787SSean Bruno 
2751e66f787SSean Bruno 	for (; len > 0; (--len, ++s)) {
2761e66f787SSean Bruno 		if (*s == 0)
2771e66f787SSean Bruno 			terminated = true;
2781e66f787SSean Bruno 		if (terminated || *s < 0x20 || *s > 0x7e)
2791e66f787SSean Bruno 			*s = ' ';
2801e66f787SSean Bruno 	}
2811e66f787SSean Bruno 
2821e66f787SSean Bruno 	DBG_FUNC("OUT\n");
2831e66f787SSean Bruno }
2841e66f787SSean Bruno 
2851e66f787SSean Bruno static char *raid_levels[] = {
2861e66f787SSean Bruno 	"RAID 0",
2871e66f787SSean Bruno 	"RAID 4",
2881e66f787SSean Bruno 	"RAID 1(1+0)",
2891e66f787SSean Bruno 	"RAID 5",
2901e66f787SSean Bruno 	"RAID 5+1",
2911e66f787SSean Bruno 	"RAID ADG",
2921e66f787SSean Bruno 	"RAID 1(ADM)",
2931e66f787SSean Bruno };
2941e66f787SSean Bruno 
2951e66f787SSean Bruno /* Get the RAID level from the index */
2969fac68fcSPAPANI SRIKANTH char *
2979fac68fcSPAPANI SRIKANTH pqisrc_raidlevel_to_string(uint8_t raid_level)
2981e66f787SSean Bruno {
2991e66f787SSean Bruno 	DBG_FUNC("IN\n");
3001e66f787SSean Bruno 	if (raid_level < ARRAY_SIZE(raid_levels))
3011e66f787SSean Bruno 		return raid_levels[raid_level];
3021e66f787SSean Bruno 	DBG_FUNC("OUT\n");
3031e66f787SSean Bruno 
3041e66f787SSean Bruno 	return " ";
3051e66f787SSean Bruno }
3061e66f787SSean Bruno 
3071e66f787SSean Bruno /* Debug routine for displaying device info */
3084f77349dSWarner Losh void pqisrc_display_device_info(pqisrc_softstate_t *softs,
3091e66f787SSean Bruno 	char *action, pqi_scsi_dev_t *device)
3101e66f787SSean Bruno {
3114f77349dSWarner Losh 	if (device->is_physical_device) {
3124f77349dSWarner Losh 		DBG_NOTE("%s scsi BTL %d:%d:%d:  %.8s %.16s %-12s "
3134f77349dSWarner Losh 		"SSDSmartPathCap%c En%c Exp%c qd=%d\n",
3144f77349dSWarner Losh 		action,
3154f77349dSWarner Losh 		device->bus,
3164f77349dSWarner Losh 		device->target,
3174f77349dSWarner Losh 		device->lun,
3184f77349dSWarner Losh 		device->vendor,
3194f77349dSWarner Losh 		device->model,
3204f77349dSWarner Losh 		"Physical",
3214f77349dSWarner Losh 		device->offload_config ? '+' : '-',
3224f77349dSWarner Losh 		device->offload_enabled_pending ? '+' : '-',
3234f77349dSWarner Losh 		device->expose_device ? '+' : '-',
3244f77349dSWarner Losh 		device->queue_depth);
3254f77349dSWarner Losh 	} else if (device->devtype == RAID_DEVICE) {
3264f77349dSWarner Losh 		DBG_NOTE("%s scsi BTL %d:%d:%d:  %.8s %.16s %-12s "
3274f77349dSWarner Losh 		"SSDSmartPathCap%c En%c Exp%c qd=%d\n",
3284f77349dSWarner Losh 		action,
3294f77349dSWarner Losh 		device->bus,
3304f77349dSWarner Losh 		device->target,
3314f77349dSWarner Losh 		device->lun,
3324f77349dSWarner Losh 		device->vendor,
3334f77349dSWarner Losh 		device->model,
3344f77349dSWarner Losh 		"Controller",
3354f77349dSWarner Losh 		device->offload_config ? '+' : '-',
3364f77349dSWarner Losh 		device->offload_enabled_pending ? '+' : '-',
3374f77349dSWarner Losh 		device->expose_device ? '+' : '-',
3384f77349dSWarner Losh 		device->queue_depth);
3394f77349dSWarner Losh 	} else if (device->devtype == CONTROLLER_DEVICE) {
3404f77349dSWarner Losh 		DBG_NOTE("%s scsi BTL %d:%d:%d:  %.8s %.16s %-12s "
3414f77349dSWarner Losh 		"SSDSmartPathCap%c En%c Exp%c qd=%d\n",
3424f77349dSWarner Losh 		action,
3434f77349dSWarner Losh 		device->bus,
3444f77349dSWarner Losh 		device->target,
3454f77349dSWarner Losh 		device->lun,
3464f77349dSWarner Losh 		device->vendor,
3474f77349dSWarner Losh 		device->model,
3484f77349dSWarner Losh 		"External",
3494f77349dSWarner Losh 		device->offload_config ? '+' : '-',
3504f77349dSWarner Losh 		device->offload_enabled_pending ? '+' : '-',
3514f77349dSWarner Losh 		device->expose_device ? '+' : '-',
3524f77349dSWarner Losh 		device->queue_depth);
3534f77349dSWarner Losh 	} else {
3544f77349dSWarner Losh 		DBG_NOTE("%s scsi BTL %d:%d:%d:  %.8s %.16s %-12s "
3554f77349dSWarner Losh 		"SSDSmartPathCap%c En%c Exp%c qd=%d devtype=%d\n",
3561e66f787SSean Bruno 		action,
3571e66f787SSean Bruno 		device->bus,
3581e66f787SSean Bruno 		device->target,
3591e66f787SSean Bruno 		device->lun,
3601e66f787SSean Bruno 		device->vendor,
3611e66f787SSean Bruno 		device->model,
3621e66f787SSean Bruno 		pqisrc_raidlevel_to_string(device->raid_level),
3631e66f787SSean Bruno 		device->offload_config ? '+' : '-',
3641e66f787SSean Bruno 		device->offload_enabled_pending ? '+' : '-',
3651e66f787SSean Bruno 		device->expose_device ? '+' : '-',
3664f77349dSWarner Losh 		device->queue_depth,
3674f77349dSWarner Losh 		device->devtype);
3681e66f787SSean Bruno 	pqisrc_raidlevel_to_string(device->raid_level); /* To use this function */
3691e66f787SSean Bruno 	}
3704f77349dSWarner Losh }
3711e66f787SSean Bruno 
3721e66f787SSean Bruno /* validate the structure sizes */
3739fac68fcSPAPANI SRIKANTH void
374fb1c2168SDimitry Andric check_struct_sizes(void)
3751e66f787SSean Bruno {
3761e66f787SSean Bruno 
3771e66f787SSean Bruno     ASSERT(sizeof(SCSI3Addr_struct)== 2);
3781e66f787SSean Bruno     ASSERT(sizeof(PhysDevAddr_struct) == 8);
3791e66f787SSean Bruno     ASSERT(sizeof(LogDevAddr_struct)== 8);
3801e66f787SSean Bruno     ASSERT(sizeof(LUNAddr_struct)==8);
3811e66f787SSean Bruno     ASSERT(sizeof(RequestBlock_struct) == 20);
3821e66f787SSean Bruno     ASSERT(sizeof(MoreErrInfo_struct)== 8);
3831e66f787SSean Bruno     ASSERT(sizeof(ErrorInfo_struct)== 48);
3849fac68fcSPAPANI SRIKANTH     /* Checking the size of IOCTL_Command_struct for both
3859fac68fcSPAPANI SRIKANTH        64 bit and 32 bit system*/
3869fac68fcSPAPANI SRIKANTH     ASSERT(sizeof(IOCTL_Command_struct)== 86 ||
3879fac68fcSPAPANI SRIKANTH            sizeof(IOCTL_Command_struct)== 82);
3881e66f787SSean Bruno     ASSERT(sizeof(struct bmic_host_wellness_driver_version)== 42);
3891e66f787SSean Bruno     ASSERT(sizeof(struct bmic_host_wellness_time)== 20);
3901e66f787SSean Bruno     ASSERT(sizeof(struct pqi_dev_adminq_cap)== 8);
3911e66f787SSean Bruno     ASSERT(sizeof(struct admin_q_param)== 4);
3921e66f787SSean Bruno     ASSERT(sizeof(struct pqi_registers)== 256);
3931e66f787SSean Bruno     ASSERT(sizeof(struct ioa_registers)== 4128);
3941e66f787SSean Bruno     ASSERT(sizeof(struct pqi_pref_settings)==4);
3951e66f787SSean Bruno     ASSERT(sizeof(struct pqi_cap)== 20);
3961e66f787SSean Bruno     ASSERT(sizeof(iu_header_t)== 4);
3971e66f787SSean Bruno     ASSERT(sizeof(gen_adm_req_iu_t)== 64);
3981e66f787SSean Bruno     ASSERT(sizeof(gen_adm_resp_iu_t)== 64);
3991e66f787SSean Bruno     ASSERT(sizeof(op_q_params) == 9);
4001e66f787SSean Bruno     ASSERT(sizeof(raid_path_error_info_elem_t)== 276);
4011e66f787SSean Bruno     ASSERT(sizeof(aio_path_error_info_elem_t)== 276);
4021e66f787SSean Bruno     ASSERT(sizeof(struct init_base_struct)== 24);
4031e66f787SSean Bruno     ASSERT(sizeof(pqi_iu_layer_desc_t)== 16);
4041e66f787SSean Bruno     ASSERT(sizeof(pqi_dev_cap_t)== 576);
4051e66f787SSean Bruno     ASSERT(sizeof(pqi_aio_req_t)== 128);
4061e66f787SSean Bruno     ASSERT(sizeof(pqisrc_raid_req_t)== 128);
4079fac68fcSPAPANI SRIKANTH     ASSERT(sizeof(pqi_raid_tmf_req_t)== 32);
4089fac68fcSPAPANI SRIKANTH     ASSERT(sizeof(pqi_aio_tmf_req_t)== 32);
4091e66f787SSean Bruno     ASSERT(sizeof(struct pqi_io_response)== 16);
4101e66f787SSean Bruno     ASSERT(sizeof(struct sense_header_scsi)== 8);
4111e66f787SSean Bruno     ASSERT(sizeof(reportlun_header_t)==8);
4121e66f787SSean Bruno     ASSERT(sizeof(reportlun_ext_entry_t)== 24);
4131e66f787SSean Bruno     ASSERT(sizeof(reportlun_data_ext_t)== 32);
4141e66f787SSean Bruno     ASSERT(sizeof(raidmap_data_t)==8);
4151e66f787SSean Bruno     ASSERT(sizeof(pqisrc_raid_map_t)== 8256);
4161e66f787SSean Bruno     ASSERT(sizeof(bmic_ident_ctrl_t)== 325);
4171e66f787SSean Bruno     ASSERT(sizeof(bmic_ident_physdev_t)==2048);
4181e66f787SSean Bruno 
4191e66f787SSean Bruno }
4209fac68fcSPAPANI SRIKANTH 
4219fac68fcSPAPANI SRIKANTH uint32_t
4229fac68fcSPAPANI SRIKANTH pqisrc_count_num_scsi_active_requests_on_dev(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device)
4239fac68fcSPAPANI SRIKANTH {
4249fac68fcSPAPANI SRIKANTH 	uint32_t i, active_io = 0;
4259fac68fcSPAPANI SRIKANTH 	rcb_t* rcb;
4269fac68fcSPAPANI SRIKANTH 
4279fac68fcSPAPANI SRIKANTH 	for(i = 1; i <= softs->max_outstanding_io; i++) {
4289fac68fcSPAPANI SRIKANTH 		rcb = &softs->rcb[i];
4299fac68fcSPAPANI SRIKANTH 		if(rcb && IS_OS_SCSICMD(rcb) && (rcb->dvp == device) && rcb->req_pending) {
4309fac68fcSPAPANI SRIKANTH 			active_io++;
4319fac68fcSPAPANI SRIKANTH 		}
4329fac68fcSPAPANI SRIKANTH 	}
4339fac68fcSPAPANI SRIKANTH 	return active_io;
4349fac68fcSPAPANI SRIKANTH }
4359fac68fcSPAPANI SRIKANTH 
4369fac68fcSPAPANI SRIKANTH void
4379fac68fcSPAPANI SRIKANTH check_device_pending_commands_to_complete(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device)
4389fac68fcSPAPANI SRIKANTH {
4399fac68fcSPAPANI SRIKANTH 	uint32_t tag = softs->max_outstanding_io, active_requests;
4409fac68fcSPAPANI SRIKANTH 	uint64_t timeout = 0, delay_in_usec = 1000; //In micro Seconds
4419fac68fcSPAPANI SRIKANTH 	rcb_t* rcb;
4429fac68fcSPAPANI SRIKANTH 
4439fac68fcSPAPANI SRIKANTH 	DBG_FUNC("IN\n");
4449fac68fcSPAPANI SRIKANTH 
4459fac68fcSPAPANI SRIKANTH 	active_requests = pqisrc_count_num_scsi_active_requests_on_dev(softs, device);
4469fac68fcSPAPANI SRIKANTH 
4479fac68fcSPAPANI SRIKANTH 	DBG_WARN("Device Outstanding IO count = %u\n", active_requests);
4489fac68fcSPAPANI SRIKANTH 
4499fac68fcSPAPANI SRIKANTH 	if(!active_requests)
4509fac68fcSPAPANI SRIKANTH 		return;
4519fac68fcSPAPANI SRIKANTH 
4529fac68fcSPAPANI SRIKANTH 	do {
4539fac68fcSPAPANI SRIKANTH 		rcb = &softs->rcb[tag];
4549fac68fcSPAPANI SRIKANTH 		if(rcb && IS_OS_SCSICMD(rcb) && (rcb->dvp == device) && rcb->req_pending) {
4559fac68fcSPAPANI SRIKANTH 			OS_BUSYWAIT(delay_in_usec);
4569fac68fcSPAPANI SRIKANTH 			timeout += delay_in_usec;
4579fac68fcSPAPANI SRIKANTH 		}
4589fac68fcSPAPANI SRIKANTH 		else
4599fac68fcSPAPANI SRIKANTH 			tag--;
4609fac68fcSPAPANI SRIKANTH 		if(timeout >= PQISRC_PENDING_IO_TIMEOUT_USEC) {
4619fac68fcSPAPANI SRIKANTH 			DBG_WARN("timed out waiting for pending IO\n");
4629fac68fcSPAPANI SRIKANTH 			return;
4639fac68fcSPAPANI SRIKANTH 		}
4649fac68fcSPAPANI SRIKANTH 	} while(tag);
4659fac68fcSPAPANI SRIKANTH 
4669fac68fcSPAPANI SRIKANTH }
4679fac68fcSPAPANI SRIKANTH 
4689fac68fcSPAPANI SRIKANTH inline uint64_t
4699fac68fcSPAPANI SRIKANTH pqisrc_increment_device_active_io(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device)
4709fac68fcSPAPANI SRIKANTH {
4719fac68fcSPAPANI SRIKANTH #if PQISRC_DEVICE_IO_COUNTER
4729fac68fcSPAPANI SRIKANTH 	/*Increment device active io count by one*/
4739fac68fcSPAPANI SRIKANTH 	return OS_ATOMIC64_INC(&device->active_requests);
4749fac68fcSPAPANI SRIKANTH #endif
4759fac68fcSPAPANI SRIKANTH }
4769fac68fcSPAPANI SRIKANTH 
4779fac68fcSPAPANI SRIKANTH inline uint64_t
4789fac68fcSPAPANI SRIKANTH pqisrc_decrement_device_active_io(pqisrc_softstate_t *softs,  pqi_scsi_dev_t *device)
4799fac68fcSPAPANI SRIKANTH {
4809fac68fcSPAPANI SRIKANTH #if PQISRC_DEVICE_IO_COUNTER
4819fac68fcSPAPANI SRIKANTH 	/*Decrement device active io count by one*/
4829fac68fcSPAPANI SRIKANTH 	return OS_ATOMIC64_DEC(&device->active_requests);
4839fac68fcSPAPANI SRIKANTH #endif
4849fac68fcSPAPANI SRIKANTH }
4859fac68fcSPAPANI SRIKANTH 
4869fac68fcSPAPANI SRIKANTH inline void
4879fac68fcSPAPANI SRIKANTH pqisrc_init_device_active_io(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device)
4889fac68fcSPAPANI SRIKANTH {
4899fac68fcSPAPANI SRIKANTH #if PQISRC_DEVICE_IO_COUNTER
4909fac68fcSPAPANI SRIKANTH 	/* Reset device count to Zero */
4919fac68fcSPAPANI SRIKANTH 	OS_ATOMIC64_INIT(&device->active_requests, 0);
4929fac68fcSPAPANI SRIKANTH #endif
4939fac68fcSPAPANI SRIKANTH }
4949fac68fcSPAPANI SRIKANTH 
4959fac68fcSPAPANI SRIKANTH inline uint64_t
4969fac68fcSPAPANI SRIKANTH pqisrc_read_device_active_io(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device)
4979fac68fcSPAPANI SRIKANTH {
4989fac68fcSPAPANI SRIKANTH #if PQISRC_DEVICE_IO_COUNTER
4999fac68fcSPAPANI SRIKANTH 	/* read device active count*/
5009fac68fcSPAPANI SRIKANTH 	return OS_ATOMIC64_READ(&device->active_requests);
5019fac68fcSPAPANI SRIKANTH #endif
5029fac68fcSPAPANI SRIKANTH }
5039fac68fcSPAPANI SRIKANTH 
5049fac68fcSPAPANI SRIKANTH void
5059fac68fcSPAPANI SRIKANTH pqisrc_wait_for_device_commands_to_complete(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device)
5069fac68fcSPAPANI SRIKANTH {
5079fac68fcSPAPANI SRIKANTH 	uint64_t timeout_in_usec = 0, delay_in_usec = 1000; //In microseconds
5089fac68fcSPAPANI SRIKANTH 
5099fac68fcSPAPANI SRIKANTH 	DBG_FUNC("IN\n");
5109fac68fcSPAPANI SRIKANTH 
5119fac68fcSPAPANI SRIKANTH 	if(!softs->ctrl_online)
5129fac68fcSPAPANI SRIKANTH 		return;
5139fac68fcSPAPANI SRIKANTH 
5149fac68fcSPAPANI SRIKANTH #if PQISRC_DEVICE_IO_COUNTER
5159fac68fcSPAPANI SRIKANTH 	DBG_NOTE("Device Outstanding IO count = %ld\n", pqisrc_read_device_active_io(softs, device));
5169fac68fcSPAPANI SRIKANTH 
5179fac68fcSPAPANI SRIKANTH 	while(pqisrc_read_device_active_io(softs, device)) {
5189fac68fcSPAPANI SRIKANTH 		OS_BUSYWAIT(delay_in_usec); // In microseconds
5199fac68fcSPAPANI SRIKANTH 		if(!softs->ctrl_online) {
5209fac68fcSPAPANI SRIKANTH 			DBG_WARN("Controller Offline was detected.\n");
5219fac68fcSPAPANI SRIKANTH 		}
5229fac68fcSPAPANI SRIKANTH 		timeout_in_usec += delay_in_usec;
5239fac68fcSPAPANI SRIKANTH 		if(timeout_in_usec >= PQISRC_PENDING_IO_TIMEOUT_USEC) {
5249fac68fcSPAPANI SRIKANTH 			DBG_WARN("timed out waiting for pending IO. DeviceOutStandingIo's=%ld\n",
5259fac68fcSPAPANI SRIKANTH                                  pqisrc_read_device_active_io(softs, device));
5269fac68fcSPAPANI SRIKANTH 			return;
5279fac68fcSPAPANI SRIKANTH 		}
5289fac68fcSPAPANI SRIKANTH 	}
5299fac68fcSPAPANI SRIKANTH #else
5309fac68fcSPAPANI SRIKANTH 	check_device_pending_commands_to_complete(softs, device);
5319fac68fcSPAPANI SRIKANTH #endif
5329fac68fcSPAPANI SRIKANTH }
533