xref: /freebsd/sys/dev/smartpqi/smartpqi_helper.c (revision 1e66f787c838b5af7de716e266caf4e5d190d54b)
1*1e66f787SSean Bruno /*-
2*1e66f787SSean Bruno  * Copyright (c) 2018 Microsemi Corporation.
3*1e66f787SSean Bruno  * All rights reserved.
4*1e66f787SSean Bruno  *
5*1e66f787SSean Bruno  * Redistribution and use in source and binary forms, with or without
6*1e66f787SSean Bruno  * modification, are permitted provided that the following conditions
7*1e66f787SSean Bruno  * are met:
8*1e66f787SSean Bruno  * 1. Redistributions of source code must retain the above copyright
9*1e66f787SSean Bruno  *    notice, this list of conditions and the following disclaimer.
10*1e66f787SSean Bruno  * 2. Redistributions in binary form must reproduce the above copyright
11*1e66f787SSean Bruno  *    notice, this list of conditions and the following disclaimer in the
12*1e66f787SSean Bruno  *    documentation and/or other materials provided with the distribution.
13*1e66f787SSean Bruno  *
14*1e66f787SSean Bruno  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15*1e66f787SSean Bruno  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16*1e66f787SSean Bruno  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17*1e66f787SSean Bruno  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18*1e66f787SSean Bruno  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19*1e66f787SSean Bruno  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20*1e66f787SSean Bruno  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*1e66f787SSean Bruno  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22*1e66f787SSean Bruno  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23*1e66f787SSean Bruno  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24*1e66f787SSean Bruno  * SUCH DAMAGE.
25*1e66f787SSean Bruno  */
26*1e66f787SSean Bruno 
27*1e66f787SSean Bruno /* $FreeBSD$ */
28*1e66f787SSean Bruno 
29*1e66f787SSean Bruno #include "smartpqi_includes.h"
30*1e66f787SSean Bruno 
31*1e66f787SSean Bruno /*
32*1e66f787SSean Bruno  * Function used to validate the adapter health.
33*1e66f787SSean Bruno  */
34*1e66f787SSean Bruno boolean_t pqisrc_ctrl_offline(pqisrc_softstate_t *softs)
35*1e66f787SSean Bruno {
36*1e66f787SSean Bruno 	DBG_FUNC("IN\n");
37*1e66f787SSean Bruno 
38*1e66f787SSean Bruno 	DBG_FUNC("OUT\n");
39*1e66f787SSean Bruno 
40*1e66f787SSean Bruno 	return !softs->ctrl_online;
41*1e66f787SSean Bruno }
42*1e66f787SSean Bruno 
43*1e66f787SSean Bruno /*
44*1e66f787SSean Bruno  * Function used to take exposed devices to OS as offline.
45*1e66f787SSean Bruno  */
46*1e66f787SSean Bruno void pqisrc_take_devices_offline(pqisrc_softstate_t *softs)
47*1e66f787SSean Bruno {
48*1e66f787SSean Bruno 	pqi_scsi_dev_t *device = NULL;
49*1e66f787SSean Bruno 	int i,j;
50*1e66f787SSean Bruno 
51*1e66f787SSean Bruno 	DBG_FUNC("IN\n");
52*1e66f787SSean Bruno 	for(i = 0; i < PQI_MAX_DEVICES; i++) {
53*1e66f787SSean Bruno 		for(j = 0; j < PQI_MAX_MULTILUN; j++) {
54*1e66f787SSean Bruno 			if(softs->device_list[i][j] == NULL)
55*1e66f787SSean Bruno 				continue;
56*1e66f787SSean Bruno 			device = softs->device_list[i][j];
57*1e66f787SSean Bruno 			pqisrc_remove_device(softs, device);
58*1e66f787SSean Bruno 		}
59*1e66f787SSean Bruno 	}
60*1e66f787SSean Bruno 
61*1e66f787SSean Bruno 	DBG_FUNC("OUT\n");
62*1e66f787SSean Bruno }
63*1e66f787SSean Bruno 
64*1e66f787SSean Bruno /*
65*1e66f787SSean Bruno  * Function used to take adapter offline.
66*1e66f787SSean Bruno  */
67*1e66f787SSean Bruno void pqisrc_take_ctrl_offline(pqisrc_softstate_t *softs)
68*1e66f787SSean Bruno {
69*1e66f787SSean Bruno 
70*1e66f787SSean Bruno 	DBG_FUNC("IN\n");
71*1e66f787SSean Bruno 
72*1e66f787SSean Bruno 	softs->ctrl_online = false;
73*1e66f787SSean Bruno 	pqisrc_trigger_nmi_sis(softs);
74*1e66f787SSean Bruno 	os_complete_outstanding_cmds_nodevice(softs);
75*1e66f787SSean Bruno 	pqisrc_take_devices_offline(softs);
76*1e66f787SSean Bruno 
77*1e66f787SSean Bruno 	DBG_FUNC("OUT\n");
78*1e66f787SSean Bruno }
79*1e66f787SSean Bruno 
80*1e66f787SSean Bruno /*
81*1e66f787SSean Bruno  * Timer handler for the adapter heart-beat.
82*1e66f787SSean Bruno  */
83*1e66f787SSean Bruno void pqisrc_heartbeat_timer_handler(pqisrc_softstate_t *softs)
84*1e66f787SSean Bruno {
85*1e66f787SSean Bruno 	uint64_t num_intrs;
86*1e66f787SSean Bruno 	uint8_t take_offline = false;
87*1e66f787SSean Bruno 
88*1e66f787SSean Bruno 	DBG_FUNC("IN\n");
89*1e66f787SSean Bruno 
90*1e66f787SSean Bruno 	num_intrs = OS_ATOMIC64_READ(softs, num_intrs);
91*1e66f787SSean Bruno 
92*1e66f787SSean Bruno 	if (PQI_NEW_HEARTBEAT_MECHANISM(softs)) {
93*1e66f787SSean Bruno 		if (CTRLR_HEARTBEAT_CNT(softs) == softs->prev_heartbeat_count) {
94*1e66f787SSean Bruno 			take_offline = true;
95*1e66f787SSean Bruno 			goto take_ctrl_offline;
96*1e66f787SSean Bruno 		}
97*1e66f787SSean Bruno 		softs->prev_heartbeat_count = CTRLR_HEARTBEAT_CNT(softs);
98*1e66f787SSean Bruno 		DBG_INFO("CTRLR_HEARTBEAT_CNT(softs)  = %lx \
99*1e66f787SSean Bruno 		softs->prev_heartbeat_count = %lx\n",
100*1e66f787SSean Bruno 		CTRLR_HEARTBEAT_CNT(softs), softs->prev_heartbeat_count);
101*1e66f787SSean Bruno 	} else {
102*1e66f787SSean Bruno 		if (num_intrs == softs->prev_num_intrs) {
103*1e66f787SSean Bruno 			softs->num_heartbeats_requested++;
104*1e66f787SSean Bruno 			if (softs->num_heartbeats_requested > PQI_MAX_HEARTBEAT_REQUESTS) {
105*1e66f787SSean Bruno 				take_offline = true;
106*1e66f787SSean Bruno 				goto take_ctrl_offline;
107*1e66f787SSean Bruno 			}
108*1e66f787SSean Bruno 			softs->pending_events[PQI_EVENT_HEARTBEAT].pending = true;
109*1e66f787SSean Bruno 
110*1e66f787SSean Bruno 			pqisrc_ack_all_events((void*)softs);
111*1e66f787SSean Bruno 
112*1e66f787SSean Bruno 		} else {
113*1e66f787SSean Bruno 			softs->num_heartbeats_requested = 0;
114*1e66f787SSean Bruno 		}
115*1e66f787SSean Bruno 		softs->prev_num_intrs = num_intrs;
116*1e66f787SSean Bruno 	}
117*1e66f787SSean Bruno 
118*1e66f787SSean Bruno take_ctrl_offline:
119*1e66f787SSean Bruno 	if (take_offline){
120*1e66f787SSean Bruno 		DBG_ERR("controller is offline\n");
121*1e66f787SSean Bruno 		pqisrc_take_ctrl_offline(softs);
122*1e66f787SSean Bruno 		os_stop_heartbeat_timer(softs);
123*1e66f787SSean Bruno 	}
124*1e66f787SSean Bruno 	DBG_FUNC("OUT\n");
125*1e66f787SSean Bruno }
126*1e66f787SSean Bruno 
127*1e66f787SSean Bruno /*
128*1e66f787SSean Bruno  * Conditional variable management routine for internal commands.
129*1e66f787SSean Bruno  */
130*1e66f787SSean Bruno int pqisrc_wait_on_condition(pqisrc_softstate_t *softs, rcb_t *rcb){
131*1e66f787SSean Bruno 
132*1e66f787SSean Bruno 	DBG_FUNC("IN\n");
133*1e66f787SSean Bruno 
134*1e66f787SSean Bruno 	int ret = PQI_STATUS_SUCCESS;
135*1e66f787SSean Bruno 	uint32_t loop_cnt = 0;
136*1e66f787SSean Bruno 
137*1e66f787SSean Bruno 	while (rcb->req_pending == true) {
138*1e66f787SSean Bruno 		OS_SLEEP(500); /* Micro sec */
139*1e66f787SSean Bruno 
140*1e66f787SSean Bruno 		/*Polling needed for FreeBSD : since ithread routine is not scheduled
141*1e66f787SSean Bruno                 during bootup, we could use polling until interrupts are
142*1e66f787SSean Bruno                 enabled (using 'if (cold)'to check for the boot time before
143*1e66f787SSean Bruno                 interrupts are enabled). */
144*1e66f787SSean Bruno 		IS_POLLING_REQUIRED(softs);
145*1e66f787SSean Bruno 
146*1e66f787SSean Bruno 		if (loop_cnt++ == PQISRC_CMD_TIMEOUT_CNT) {
147*1e66f787SSean Bruno 			DBG_ERR("ERR: Requested cmd timed out !!!\n");
148*1e66f787SSean Bruno 			ret = PQI_STATUS_TIMEOUT;
149*1e66f787SSean Bruno 			break;
150*1e66f787SSean Bruno 		}
151*1e66f787SSean Bruno 
152*1e66f787SSean Bruno 		if (pqisrc_ctrl_offline(softs)) {
153*1e66f787SSean Bruno 			DBG_ERR("Controller is Offline");
154*1e66f787SSean Bruno 			ret = PQI_STATUS_FAILURE;
155*1e66f787SSean Bruno 			break;
156*1e66f787SSean Bruno 		}
157*1e66f787SSean Bruno 
158*1e66f787SSean Bruno 	}
159*1e66f787SSean Bruno 	rcb->req_pending = true;
160*1e66f787SSean Bruno 
161*1e66f787SSean Bruno 	DBG_FUNC("OUT\n");
162*1e66f787SSean Bruno 
163*1e66f787SSean Bruno 	return ret;
164*1e66f787SSean Bruno }
165*1e66f787SSean Bruno 
166*1e66f787SSean Bruno /* Function used to validate the device wwid. */
167*1e66f787SSean Bruno boolean_t pqisrc_device_equal(pqi_scsi_dev_t *dev1,
168*1e66f787SSean Bruno 	pqi_scsi_dev_t *dev2)
169*1e66f787SSean Bruno {
170*1e66f787SSean Bruno 	return dev1->wwid == dev2->wwid;
171*1e66f787SSean Bruno }
172*1e66f787SSean Bruno 
173*1e66f787SSean Bruno /* Function used to validate the device scsi3addr. */
174*1e66f787SSean Bruno boolean_t pqisrc_scsi3addr_equal(uint8_t *scsi3addr1, uint8_t *scsi3addr2)
175*1e66f787SSean Bruno {
176*1e66f787SSean Bruno 	return memcmp(scsi3addr1, scsi3addr2, 8) == 0;
177*1e66f787SSean Bruno }
178*1e66f787SSean Bruno 
179*1e66f787SSean Bruno /* Function used to validate hba_lunid */
180*1e66f787SSean Bruno boolean_t pqisrc_is_hba_lunid(uint8_t *scsi3addr)
181*1e66f787SSean Bruno {
182*1e66f787SSean Bruno 	return pqisrc_scsi3addr_equal(scsi3addr, (uint8_t*)RAID_CTLR_LUNID);
183*1e66f787SSean Bruno }
184*1e66f787SSean Bruno 
185*1e66f787SSean Bruno /* Function used to validate type of device */
186*1e66f787SSean Bruno boolean_t pqisrc_is_logical_device(pqi_scsi_dev_t *device)
187*1e66f787SSean Bruno {
188*1e66f787SSean Bruno 	return !device->is_physical_device;
189*1e66f787SSean Bruno }
190*1e66f787SSean Bruno 
191*1e66f787SSean Bruno /* Function used to sanitize inquiry string */
192*1e66f787SSean Bruno void pqisrc_sanitize_inquiry_string(unsigned char *s, int len)
193*1e66f787SSean Bruno {
194*1e66f787SSean Bruno 	boolean_t terminated = false;
195*1e66f787SSean Bruno 
196*1e66f787SSean Bruno 	DBG_FUNC("IN\n");
197*1e66f787SSean Bruno 
198*1e66f787SSean Bruno 	for (; len > 0; (--len, ++s)) {
199*1e66f787SSean Bruno 		if (*s == 0)
200*1e66f787SSean Bruno 			terminated = true;
201*1e66f787SSean Bruno 		if (terminated || *s < 0x20 || *s > 0x7e)
202*1e66f787SSean Bruno 			*s = ' ';
203*1e66f787SSean Bruno 	}
204*1e66f787SSean Bruno 
205*1e66f787SSean Bruno 	DBG_FUNC("OUT\n");
206*1e66f787SSean Bruno }
207*1e66f787SSean Bruno 
208*1e66f787SSean Bruno static char *raid_levels[] = {
209*1e66f787SSean Bruno 	"RAID 0",
210*1e66f787SSean Bruno 	"RAID 4",
211*1e66f787SSean Bruno 	"RAID 1(1+0)",
212*1e66f787SSean Bruno 	"RAID 5",
213*1e66f787SSean Bruno 	"RAID 5+1",
214*1e66f787SSean Bruno 	"RAID ADG",
215*1e66f787SSean Bruno 	"RAID 1(ADM)",
216*1e66f787SSean Bruno 	"RAID 6",
217*1e66f787SSean Bruno };
218*1e66f787SSean Bruno 
219*1e66f787SSean Bruno /* Get the RAID level from the index */
220*1e66f787SSean Bruno char *pqisrc_raidlevel_to_string(uint8_t raid_level)
221*1e66f787SSean Bruno {
222*1e66f787SSean Bruno 	DBG_FUNC("IN\n");
223*1e66f787SSean Bruno 	if (raid_level < ARRAY_SIZE(raid_levels))
224*1e66f787SSean Bruno 		return raid_levels[raid_level];
225*1e66f787SSean Bruno 	DBG_FUNC("OUT\n");
226*1e66f787SSean Bruno 
227*1e66f787SSean Bruno 	return " ";
228*1e66f787SSean Bruno }
229*1e66f787SSean Bruno 
230*1e66f787SSean Bruno /* Debug routine for displaying device info */
231*1e66f787SSean Bruno void pqisrc_display_device_info(pqisrc_softstate_t *softs,
232*1e66f787SSean Bruno 	char *action, pqi_scsi_dev_t *device)
233*1e66f787SSean Bruno {
234*1e66f787SSean Bruno 	DBG_INFO( "%s scsi BTL %d:%d:%d:  %.8s %.16s %-12s SSDSmartPathCap%c En%c Exp%c qd=%d\n",
235*1e66f787SSean Bruno 		action,
236*1e66f787SSean Bruno 		device->bus,
237*1e66f787SSean Bruno 		device->target,
238*1e66f787SSean Bruno 		device->lun,
239*1e66f787SSean Bruno 		device->vendor,
240*1e66f787SSean Bruno 		device->model,
241*1e66f787SSean Bruno 		pqisrc_raidlevel_to_string(device->raid_level),
242*1e66f787SSean Bruno 		device->offload_config ? '+' : '-',
243*1e66f787SSean Bruno 		device->offload_enabled_pending ? '+' : '-',
244*1e66f787SSean Bruno 		device->expose_device ? '+' : '-',
245*1e66f787SSean Bruno 		device->queue_depth);
246*1e66f787SSean Bruno 	pqisrc_raidlevel_to_string(device->raid_level); /* To use this function */
247*1e66f787SSean Bruno }
248*1e66f787SSean Bruno 
249*1e66f787SSean Bruno /* validate the structure sizes */
250*1e66f787SSean Bruno void check_struct_sizes()
251*1e66f787SSean Bruno {
252*1e66f787SSean Bruno 
253*1e66f787SSean Bruno     ASSERT(sizeof(SCSI3Addr_struct)== 2);
254*1e66f787SSean Bruno     ASSERT(sizeof(PhysDevAddr_struct) == 8);
255*1e66f787SSean Bruno     ASSERT(sizeof(LogDevAddr_struct)== 8);
256*1e66f787SSean Bruno     ASSERT(sizeof(LUNAddr_struct)==8);
257*1e66f787SSean Bruno     ASSERT(sizeof(RequestBlock_struct) == 20);
258*1e66f787SSean Bruno     ASSERT(sizeof(MoreErrInfo_struct)== 8);
259*1e66f787SSean Bruno     ASSERT(sizeof(ErrorInfo_struct)== 48);
260*1e66f787SSean Bruno     ASSERT(sizeof(IOCTL_Command_struct)== 86);
261*1e66f787SSean Bruno     ASSERT(sizeof(struct bmic_host_wellness_driver_version)== 42);
262*1e66f787SSean Bruno     ASSERT(sizeof(struct bmic_host_wellness_time)== 20);
263*1e66f787SSean Bruno     ASSERT(sizeof(struct pqi_dev_adminq_cap)== 8);
264*1e66f787SSean Bruno     ASSERT(sizeof(struct admin_q_param)== 4);
265*1e66f787SSean Bruno     ASSERT(sizeof(struct pqi_registers)== 256);
266*1e66f787SSean Bruno     ASSERT(sizeof(struct ioa_registers)== 4128);
267*1e66f787SSean Bruno     ASSERT(sizeof(struct pqi_pref_settings)==4);
268*1e66f787SSean Bruno     ASSERT(sizeof(struct pqi_cap)== 20);
269*1e66f787SSean Bruno     ASSERT(sizeof(iu_header_t)== 4);
270*1e66f787SSean Bruno     ASSERT(sizeof(gen_adm_req_iu_t)== 64);
271*1e66f787SSean Bruno     ASSERT(sizeof(gen_adm_resp_iu_t)== 64);
272*1e66f787SSean Bruno     ASSERT(sizeof(op_q_params) == 9);
273*1e66f787SSean Bruno     ASSERT(sizeof(raid_path_error_info_elem_t)== 276);
274*1e66f787SSean Bruno     ASSERT(sizeof(aio_path_error_info_elem_t)== 276);
275*1e66f787SSean Bruno     ASSERT(sizeof(struct init_base_struct)== 24);
276*1e66f787SSean Bruno     ASSERT(sizeof(pqi_iu_layer_desc_t)== 16);
277*1e66f787SSean Bruno     ASSERT(sizeof(pqi_dev_cap_t)== 576);
278*1e66f787SSean Bruno     ASSERT(sizeof(pqi_aio_req_t)== 128);
279*1e66f787SSean Bruno     ASSERT(sizeof(pqisrc_raid_req_t)== 128);
280*1e66f787SSean Bruno     ASSERT(sizeof(pqi_tmf_req_t)== 32);
281*1e66f787SSean Bruno     ASSERT(sizeof(struct pqi_io_response)== 16);
282*1e66f787SSean Bruno     ASSERT(sizeof(struct sense_header_scsi)== 8);
283*1e66f787SSean Bruno     ASSERT(sizeof(reportlun_header_t)==8);
284*1e66f787SSean Bruno     ASSERT(sizeof(reportlun_ext_entry_t)== 24);
285*1e66f787SSean Bruno     ASSERT(sizeof(reportlun_data_ext_t)== 32);
286*1e66f787SSean Bruno     ASSERT(sizeof(raidmap_data_t)==8);
287*1e66f787SSean Bruno     ASSERT(sizeof(pqisrc_raid_map_t)== 8256);
288*1e66f787SSean Bruno     ASSERT(sizeof(bmic_ident_ctrl_t)== 325);
289*1e66f787SSean Bruno     ASSERT(sizeof(bmic_ident_physdev_t)==2048);
290*1e66f787SSean Bruno 
291*1e66f787SSean Bruno }
292