1 /*-
2  * Copyright 2016-2021 Microchip Technology, Inc. and/or its subsidiaries.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  */
25 
26 /* $FreeBSD: stable/12/sys/dev/smartpqi/smartpqi_helper.c 372347 2022-07-29 18:50:59Z git2svn $ */
27 
28 #include "smartpqi_includes.h"
29 
30 /* read and modify controller diagnostic option - PQI_PTRAID_UPDATE_ON_RESCAN_LUNS */
31 void
pqisrc_ctrl_diagnostic_options(pqisrc_softstate_t * softs)32 pqisrc_ctrl_diagnostic_options(pqisrc_softstate_t *softs)
33 {
34 	int ret = PQI_STATUS_SUCCESS;
35 	uint32_t diags_options = 0;
36 	pqisrc_raid_req_t request;
37 
38 	DBG_NOTE("IN\n");
39 
40 	memset(&request, 0, sizeof(request));
41 	/* read diags options of controller */
42 	ret =  pqisrc_build_send_raid_request(softs, &request,
43 					(void*)&diags_options,
44 					sizeof(diags_options),
45 					BMIC_SENSE_DIAGS_OPTIONS,
46 					0, (uint8_t *)RAID_CTLR_LUNID, NULL);
47 	if (ret != PQI_STATUS_SUCCESS) {
48 		DBG_WARN("Request failed for BMIC Sense Diags Option command."
49 			"ret:%d\n",ret);
50 		return;
51 	}
52 	DBG_NOTE("diags options data after read: %#x\n",diags_options);
53 	diags_options |= PQI_PTRAID_UPDATE_ON_RESCAN_LUNS;
54 	DBG_NOTE("diags options data to write: %#x\n",diags_options);
55 	memset(&request, 0, sizeof(request));
56 	/* write specified diags options to controller */
57 	ret =  pqisrc_build_send_raid_request(softs, &request,
58 					(void*)&diags_options,
59 					sizeof(diags_options),
60 					BMIC_SET_DIAGS_OPTIONS,
61 					0, (uint8_t *)RAID_CTLR_LUNID, NULL);
62 	if (ret != PQI_STATUS_SUCCESS)
63 		DBG_WARN("Request failed for BMIC Set Diags Option command."
64 			"ret:%d\n",ret);
65 #if 0
66 	diags_options = 0;
67 	memset(&request, 0, sizeof(request));
68 	ret =  pqisrc_build_send_raid_request(softs, &request,
69 					(void*)&diags_options,
70 					sizeof(diags_options),
71 					BMIC_SENSE_DIAGS_OPTIONS,
72 					0, (uint8_t *)RAID_CTLR_LUNID, NULL);
73 	if (ret != PQI_STATUS_SUCCESS)
74 		DBG_WARN("Request failed for BMIC Sense Diags Option command."
75 			"ret:%d\n",ret);
76 	DBG_NOTE("diags options after re-read: %#x\n",diags_options);
77 #endif
78 	DBG_NOTE("OUT\n");
79 }
80 
81 /*
82  * Function used to validate the adapter health.
83  */
84 boolean_t
pqisrc_ctrl_offline(pqisrc_softstate_t * softs)85 pqisrc_ctrl_offline(pqisrc_softstate_t *softs)
86 {
87 	DBG_FUNC("IN\n");
88 
89 	DBG_FUNC("OUT\n");
90 
91 	return !softs->ctrl_online;
92 }
93 
94 /* Function used set/clear legacy INTx bit in Legacy Interrupt INTx
95  * mask clear pqi register
96  */
97 void
pqisrc_configure_legacy_intx(pqisrc_softstate_t * softs,boolean_t enable_intx)98 pqisrc_configure_legacy_intx(pqisrc_softstate_t *softs, boolean_t enable_intx)
99 {
100 	uint32_t intx_mask;
101 	uint32_t *reg_addr = NULL;
102 
103 	DBG_FUNC("IN\n");
104 
105 	if (enable_intx)
106 		reg_addr = &softs->pqi_reg->legacy_intr_mask_clr;
107 	else
108 		reg_addr = &softs->pqi_reg->legacy_intr_mask_set;
109 
110 	intx_mask = PCI_MEM_GET32(softs, reg_addr, PQI_LEGACY_INTR_MASK_CLR);
111 	intx_mask |= PQISRC_LEGACY_INTX_MASK;
112 	PCI_MEM_PUT32(softs, reg_addr, PQI_LEGACY_INTR_MASK_CLR ,intx_mask);
113 
114 	DBG_FUNC("OUT\n");
115 }
116 
117 /*
118  * Function used to take exposed devices to OS as offline.
119  */
120 void
pqisrc_take_devices_offline(pqisrc_softstate_t * softs)121 pqisrc_take_devices_offline(pqisrc_softstate_t *softs)
122 {
123 	pqi_scsi_dev_t *device = NULL;
124 	int i,j;
125 
126 	DBG_FUNC("IN\n");
127 	for(i = 0; i < PQI_MAX_DEVICES; i++) {
128 		for(j = 0; j < PQI_MAX_MULTILUN; j++) {
129 			if(softs->device_list[i][j] == NULL)
130 				continue;
131 			device = softs->device_list[i][j];
132 			pqisrc_remove_device(softs, device);
133 		}
134 	}
135 
136 	DBG_FUNC("OUT\n");
137 }
138 
139 /*
140  * Function used to take adapter offline.
141  */
142 void
pqisrc_take_ctrl_offline(pqisrc_softstate_t * softs)143 pqisrc_take_ctrl_offline(pqisrc_softstate_t *softs)
144 {
145 
146 	DBG_FUNC("IN\n");
147 
148 	softs->ctrl_online = false;
149 
150 	int lockupcode = 0;
151 
152 	if (SIS_IS_KERNEL_PANIC(softs)) {
153                 lockupcode = PCI_MEM_GET32(softs, &softs->ioa_reg->mb[7], LEGACY_SIS_SRCV_OFFSET_MAILBOX_7);
154                 DBG_ERR("Controller FW is not running, Lockup code = %x\n", lockupcode);
155         }
156         else {
157                 pqisrc_trigger_nmi_sis(softs);
158         }
159 
160 	os_complete_outstanding_cmds_nodevice(softs);
161 	pqisrc_wait_for_rescan_complete(softs);
162 	pqisrc_take_devices_offline(softs);
163 
164 	DBG_FUNC("OUT\n");
165 }
166 
167 /*
168  * Timer handler for the adapter heart-beat.
169  */
170 void
pqisrc_heartbeat_timer_handler(pqisrc_softstate_t * softs)171 pqisrc_heartbeat_timer_handler(pqisrc_softstate_t *softs)
172 {
173 	uint8_t take_offline = false;
174 
175 	DBG_FUNC("IN\n");
176 
177 	if (CTRLR_HEARTBEAT_CNT(softs) == softs->prev_heartbeat_count) {
178 		take_offline = true;
179 		goto take_ctrl_offline;
180 	}
181 	softs->prev_heartbeat_count = CTRLR_HEARTBEAT_CNT(softs);
182 	DBG_INFO("CTRLR_HEARTBEAT_CNT(softs)  = %lx \
183 		softs->prev_heartbeat_count = %lx\n",
184 		CTRLR_HEARTBEAT_CNT(softs), softs->prev_heartbeat_count);
185 
186 take_ctrl_offline:
187 	if (take_offline){
188 		DBG_ERR("controller is offline\n");
189 		os_stop_heartbeat_timer(softs);
190 		pqisrc_take_ctrl_offline(softs);
191 	}
192 	DBG_FUNC("OUT\n");
193 }
194 
195 /*
196  * Conditional variable management routine for internal commands.
197  */
198 int
pqisrc_wait_on_condition(pqisrc_softstate_t * softs,rcb_t * rcb,uint32_t timeout_in_msec)199 pqisrc_wait_on_condition(pqisrc_softstate_t *softs, rcb_t *rcb,
200 				uint32_t timeout_in_msec)
201 {
202 	DBG_FUNC("IN\n");
203 
204 	int ret = PQI_STATUS_SUCCESS;
205 
206 	/* 1 msec = 500 usec * 2 */
207 	uint32_t loop_cnt = timeout_in_msec * 2;
208 	uint32_t i = 0;
209 
210 	while (rcb->req_pending == true) {
211 		OS_SLEEP(500); /* Micro sec */
212 		/* Polling needed for FreeBSD : since ithread routine is not scheduled
213 		 * during bootup, we could use polling until interrupts are
214 		 * enabled (using 'if (cold)'to check for the boot time before
215 		 * interrupts are enabled). */
216 		IS_POLLING_REQUIRED(softs);
217 
218 		if ((timeout_in_msec != TIMEOUT_INFINITE) && (i++ == loop_cnt)) {
219 			DBG_ERR("ERR: Requested cmd timed out !!!\n");
220 			ret = PQI_STATUS_TIMEOUT;
221 			rcb->timedout = true;
222 			break;
223 		}
224 
225 		if (pqisrc_ctrl_offline(softs)) {
226 			DBG_ERR("Controller is Offline");
227 			ret = PQI_STATUS_FAILURE;
228 			break;
229 		}
230 
231 	}
232 	rcb->req_pending = true;
233 
234 	DBG_FUNC("OUT\n");
235 
236 	return ret;
237 }
238 
239 /* Function used to validate the device wwid. */
240 boolean_t
pqisrc_device_equal(pqi_scsi_dev_t * dev1,pqi_scsi_dev_t * dev2)241 pqisrc_device_equal(pqi_scsi_dev_t *dev1,
242 	pqi_scsi_dev_t *dev2)
243 {
244 	return dev1->wwid == dev2->wwid;
245 }
246 
247 /* Function used to validate the device scsi3addr. */
248 boolean_t
pqisrc_scsi3addr_equal(uint8_t * scsi3addr1,uint8_t * scsi3addr2)249 pqisrc_scsi3addr_equal(uint8_t *scsi3addr1, uint8_t *scsi3addr2)
250 {
251 	return memcmp(scsi3addr1, scsi3addr2, 8) == 0;
252 }
253 
254 /* Function used to validate hba_lunid */
255 boolean_t
pqisrc_is_hba_lunid(uint8_t * scsi3addr)256 pqisrc_is_hba_lunid(uint8_t *scsi3addr)
257 {
258 	return pqisrc_scsi3addr_equal(scsi3addr, (uint8_t*)RAID_CTLR_LUNID);
259 }
260 
261 /* Function used to validate type of device */
262 boolean_t
pqisrc_is_logical_device(pqi_scsi_dev_t * device)263 pqisrc_is_logical_device(pqi_scsi_dev_t *device)
264 {
265 	return !device->is_physical_device;
266 }
267 
268 /* Function used to sanitize inquiry string */
269 void
pqisrc_sanitize_inquiry_string(unsigned char * s,int len)270 pqisrc_sanitize_inquiry_string(unsigned char *s, int len)
271 {
272 	boolean_t terminated = false;
273 
274 	DBG_FUNC("IN\n");
275 
276 	for (; len > 0; (--len, ++s)) {
277 		if (*s == 0)
278 			terminated = true;
279 		if (terminated || *s < 0x20 || *s > 0x7e)
280 			*s = ' ';
281 	}
282 
283 	DBG_FUNC("OUT\n");
284 }
285 
286 static char *raid_levels[] = {
287 	"RAID 0",
288 	"RAID 4",
289 	"RAID 1(1+0)",
290 	"RAID 5",
291 	"RAID 5+1",
292 	"RAID ADG",
293 	"RAID 1(ADM)",
294 };
295 
296 /* Get the RAID level from the index */
297 char *
pqisrc_raidlevel_to_string(uint8_t raid_level)298 pqisrc_raidlevel_to_string(uint8_t raid_level)
299 {
300 	DBG_FUNC("IN\n");
301 	if (raid_level < ARRAY_SIZE(raid_levels))
302 		return raid_levels[raid_level];
303 	DBG_FUNC("OUT\n");
304 
305 	return " ";
306 }
307 
308 /* Debug routine for displaying device info */
309 void
pqisrc_display_device_info(pqisrc_softstate_t * softs,char * action,pqi_scsi_dev_t * device)310 pqisrc_display_device_info(pqisrc_softstate_t *softs,
311 	char *action, pqi_scsi_dev_t *device)
312 {
313 	DBG_INFO( "%s scsi BTL %d:%d:%d:  %.8s %.16s %-12s SSDSmartPathCap%c En%c Exp%c qd=%d\n",
314 		action,
315 		device->bus,
316 		device->target,
317 		device->lun,
318 		device->vendor,
319 		device->model,
320 		pqisrc_raidlevel_to_string(device->raid_level),
321 		device->offload_config ? '+' : '-',
322 		device->offload_enabled_pending ? '+' : '-',
323 		device->expose_device ? '+' : '-',
324 		device->queue_depth);
325 	pqisrc_raidlevel_to_string(device->raid_level); /* To use this function */
326 }
327 
328 /* validate the structure sizes */
329 void
check_struct_sizes(void)330 check_struct_sizes(void)
331 {
332 
333     ASSERT(sizeof(SCSI3Addr_struct)== 2);
334     ASSERT(sizeof(PhysDevAddr_struct) == 8);
335     ASSERT(sizeof(LogDevAddr_struct)== 8);
336     ASSERT(sizeof(LUNAddr_struct)==8);
337     ASSERT(sizeof(RequestBlock_struct) == 20);
338     ASSERT(sizeof(MoreErrInfo_struct)== 8);
339     ASSERT(sizeof(ErrorInfo_struct)== 48);
340     /* Checking the size of IOCTL_Command_struct for both
341        64 bit and 32 bit system*/
342     ASSERT(sizeof(IOCTL_Command_struct)== 86 ||
343            sizeof(IOCTL_Command_struct)== 82);
344     ASSERT(sizeof(struct bmic_host_wellness_driver_version)== 42);
345     ASSERT(sizeof(struct bmic_host_wellness_time)== 20);
346     ASSERT(sizeof(struct pqi_dev_adminq_cap)== 8);
347     ASSERT(sizeof(struct admin_q_param)== 4);
348     ASSERT(sizeof(struct pqi_registers)== 256);
349     ASSERT(sizeof(struct ioa_registers)== 4128);
350     ASSERT(sizeof(struct pqi_pref_settings)==4);
351     ASSERT(sizeof(struct pqi_cap)== 20);
352     ASSERT(sizeof(iu_header_t)== 4);
353     ASSERT(sizeof(gen_adm_req_iu_t)== 64);
354     ASSERT(sizeof(gen_adm_resp_iu_t)== 64);
355     ASSERT(sizeof(op_q_params) == 9);
356     ASSERT(sizeof(raid_path_error_info_elem_t)== 276);
357     ASSERT(sizeof(aio_path_error_info_elem_t)== 276);
358     ASSERT(sizeof(struct init_base_struct)== 24);
359     ASSERT(sizeof(pqi_iu_layer_desc_t)== 16);
360     ASSERT(sizeof(pqi_dev_cap_t)== 576);
361     ASSERT(sizeof(pqi_aio_req_t)== 128);
362     ASSERT(sizeof(pqisrc_raid_req_t)== 128);
363     ASSERT(sizeof(pqi_raid_tmf_req_t)== 32);
364     ASSERT(sizeof(pqi_aio_tmf_req_t)== 32);
365     ASSERT(sizeof(struct pqi_io_response)== 16);
366     ASSERT(sizeof(struct sense_header_scsi)== 8);
367     ASSERT(sizeof(reportlun_header_t)==8);
368     ASSERT(sizeof(reportlun_ext_entry_t)== 24);
369     ASSERT(sizeof(reportlun_data_ext_t)== 32);
370     ASSERT(sizeof(raidmap_data_t)==8);
371     ASSERT(sizeof(pqisrc_raid_map_t)== 8256);
372     ASSERT(sizeof(bmic_ident_ctrl_t)== 325);
373     ASSERT(sizeof(bmic_ident_physdev_t)==2048);
374 
375 }
376 
377 uint32_t
pqisrc_count_num_scsi_active_requests_on_dev(pqisrc_softstate_t * softs,pqi_scsi_dev_t * device)378 pqisrc_count_num_scsi_active_requests_on_dev(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device)
379 {
380 	uint32_t i, active_io = 0;
381 	rcb_t* rcb;
382 
383 	for(i = 1; i <= softs->max_outstanding_io; i++) {
384 		rcb = &softs->rcb[i];
385 		if(rcb && IS_OS_SCSICMD(rcb) && (rcb->dvp == device) && rcb->req_pending) {
386 			active_io++;
387 		}
388 	}
389 	return active_io;
390 }
391 
392 void
check_device_pending_commands_to_complete(pqisrc_softstate_t * softs,pqi_scsi_dev_t * device)393 check_device_pending_commands_to_complete(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device)
394 {
395 	uint32_t tag = softs->max_outstanding_io, active_requests;
396 	uint64_t timeout = 0, delay_in_usec = 1000; //In micro Seconds
397 	rcb_t* rcb;
398 
399 	DBG_FUNC("IN\n");
400 
401 	active_requests = pqisrc_count_num_scsi_active_requests_on_dev(softs, device);
402 
403 	DBG_WARN("Device Outstanding IO count = %u\n", active_requests);
404 
405 	if(!active_requests)
406 		return;
407 
408 	do {
409 		rcb = &softs->rcb[tag];
410 		if(rcb && IS_OS_SCSICMD(rcb) && (rcb->dvp == device) && rcb->req_pending) {
411 			OS_BUSYWAIT(delay_in_usec);
412 			timeout += delay_in_usec;
413 		}
414 		else
415 			tag--;
416 		if(timeout >= PQISRC_PENDING_IO_TIMEOUT_USEC) {
417 			DBG_WARN("timed out waiting for pending IO\n");
418 			return;
419 		}
420 	} while(tag);
421 
422 }
423 
424 inline uint64_t
pqisrc_increment_device_active_io(pqisrc_softstate_t * softs,pqi_scsi_dev_t * device)425 pqisrc_increment_device_active_io(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device)
426 {
427 #if PQISRC_DEVICE_IO_COUNTER
428 	/*Increment device active io count by one*/
429 	return OS_ATOMIC64_INC(&device->active_requests);
430 #endif
431 }
432 
433 inline uint64_t
pqisrc_decrement_device_active_io(pqisrc_softstate_t * softs,pqi_scsi_dev_t * device)434 pqisrc_decrement_device_active_io(pqisrc_softstate_t *softs,  pqi_scsi_dev_t *device)
435 {
436 #if PQISRC_DEVICE_IO_COUNTER
437 	/*Decrement device active io count by one*/
438 	return OS_ATOMIC64_DEC(&device->active_requests);
439 #endif
440 }
441 
442 inline void
pqisrc_init_device_active_io(pqisrc_softstate_t * softs,pqi_scsi_dev_t * device)443 pqisrc_init_device_active_io(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device)
444 {
445 #if PQISRC_DEVICE_IO_COUNTER
446 	/* Reset device count to Zero */
447 	OS_ATOMIC64_INIT(&device->active_requests, 0);
448 #endif
449 }
450 
451 inline uint64_t
pqisrc_read_device_active_io(pqisrc_softstate_t * softs,pqi_scsi_dev_t * device)452 pqisrc_read_device_active_io(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device)
453 {
454 #if PQISRC_DEVICE_IO_COUNTER
455 	/* read device active count*/
456 	return OS_ATOMIC64_READ(&device->active_requests);
457 #endif
458 }
459 
460 void
pqisrc_wait_for_device_commands_to_complete(pqisrc_softstate_t * softs,pqi_scsi_dev_t * device)461 pqisrc_wait_for_device_commands_to_complete(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device)
462 {
463 	uint64_t timeout_in_usec = 0, delay_in_usec = 1000; //In microseconds
464 
465 	DBG_FUNC("IN\n");
466 
467 	if(!softs->ctrl_online)
468 		return;
469 
470 #if PQISRC_DEVICE_IO_COUNTER
471 	DBG_NOTE("Device Outstanding IO count = %ld\n", pqisrc_read_device_active_io(softs, device));
472 
473 	while(pqisrc_read_device_active_io(softs, device)) {
474 		OS_BUSYWAIT(delay_in_usec); // In microseconds
475 		if(!softs->ctrl_online) {
476 			DBG_WARN("Controller Offline was detected.\n");
477 		}
478 		timeout_in_usec += delay_in_usec;
479 		if(timeout_in_usec >= PQISRC_PENDING_IO_TIMEOUT_USEC) {
480 			DBG_WARN("timed out waiting for pending IO. DeviceOutStandingIo's=%ld\n",
481                                  pqisrc_read_device_active_io(softs, device));
482 			return;
483 		}
484 	}
485 #else
486 	check_device_pending_commands_to_complete(softs, device);
487 #endif
488 }
489