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