1/*-
2 * Copyright 2016-2023 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
27#include "smartpqi_includes.h"
28
29/*
30 * Function used to validate the adapter health.
31 */
32boolean_t
33pqisrc_ctrl_offline(pqisrc_softstate_t *softs)
34{
35	DBG_FUNC("IN\n");
36
37	DBG_FUNC("OUT\n");
38
39	return !softs->ctrl_online;
40}
41/* Function used set/clear legacy INTx bit in Legacy Interrupt INTx
42 * mask clear pqi register
43 */
44void
45pqisrc_configure_legacy_intx(pqisrc_softstate_t *softs, boolean_t enable_intx)
46{
47	uint32_t intx_mask;
48
49 	DBG_FUNC("IN\n");
50
51	intx_mask = PCI_MEM_GET32(softs, 0, PQI_LEGACY_INTR_MASK_CLR);
52	intx_mask |= PQISRC_LEGACY_INTX_MASK;
53	PCI_MEM_PUT32(softs, 0, PQI_LEGACY_INTR_MASK_CLR ,intx_mask);
54
55 	DBG_FUNC("OUT\n");
56}
57
58/*
59 * Function used to take exposed devices to OS as offline.
60 */
61void
62pqisrc_take_devices_offline(pqisrc_softstate_t *softs)
63{
64	pqi_scsi_dev_t *device = NULL;
65	int i;
66
67	DBG_FUNC("IN\n");
68	for(i = 0; i < PQI_MAX_DEVICES; i++) {
69		device = softs->dev_list[i];
70		if(device == NULL)
71			continue;
72		pqisrc_remove_device(softs, device);
73	}
74
75	DBG_FUNC("OUT\n");
76}
77
78/*
79 * Function used to take adapter offline.
80 */
81void
82pqisrc_take_ctrl_offline(pqisrc_softstate_t *softs)
83{
84	DBG_FUNC("IN\n");
85
86	int lockupcode = 0;
87
88	softs->ctrl_online = false;
89
90	if (SIS_IS_KERNEL_PANIC(softs)) {
91		lockupcode = PCI_MEM_GET32(softs, &softs->ioa_reg->mb[7], LEGACY_SIS_SRCV_OFFSET_MAILBOX_7);
92        DBG_ERR("Controller FW is not running, Lockup code = %x\n", lockupcode);
93	}
94	else {
95	pqisrc_trigger_nmi_sis(softs);
96	}
97
98	os_complete_outstanding_cmds_nodevice(softs);
99	pqisrc_wait_for_rescan_complete(softs);
100	pqisrc_take_devices_offline(softs);
101
102	DBG_FUNC("OUT\n");
103}
104
105/*
106 * Timer handler for the adapter heart-beat.
107 */
108void
109pqisrc_heartbeat_timer_handler(pqisrc_softstate_t *softs)
110{
111	uint8_t take_offline = false;
112	uint64_t new_heartbeat;
113	static uint32_t running_ping_cnt = 0;
114
115	DBG_FUNC("IN\n");
116
117	new_heartbeat = CTRLR_HEARTBEAT_CNT(softs);
118	DBG_IO("heartbeat old=%lx new=%lx\n", softs->prev_heartbeat_count, new_heartbeat);
119
120	if (new_heartbeat == softs->prev_heartbeat_count) {
121		take_offline = true;
122		goto take_ctrl_offline;
123	}
124
125#if 1
126	/* print every 30 calls (should print once/minute) */
127	running_ping_cnt++;
128
129	if ((running_ping_cnt % 30) == 0)
130		print_all_counters(softs, COUNTER_FLAG_ONLY_NON_ZERO);
131#endif
132
133	softs->prev_heartbeat_count = new_heartbeat;
134
135take_ctrl_offline:
136	if (take_offline){
137		DBG_ERR("controller is offline\n");
138		os_stop_heartbeat_timer(softs);
139		pqisrc_take_ctrl_offline(softs);
140	}
141	DBG_FUNC("OUT\n");
142}
143
144/*
145 * Conditional variable management routine for internal commands.
146 */
147int
148pqisrc_wait_on_condition(pqisrc_softstate_t *softs, rcb_t *rcb,
149				uint32_t timeout_in_msec)
150{
151	DBG_FUNC("IN\n");
152
153	int ret = PQI_STATUS_SUCCESS;
154
155	/* 1 msec = 500 usec * 2 */
156	uint32_t loop_cnt = timeout_in_msec * 2;
157	uint32_t i = 0;
158
159	while (rcb->req_pending == true) {
160		OS_SLEEP(500); /* Micro sec */
161		/* Polling needed for FreeBSD : since ithread routine is not scheduled
162		 * during bootup, we could use polling until interrupts are
163		 * enabled (using 'if (cold)'to check for the boot time before
164		 * interrupts are enabled). */
165		IS_POLLING_REQUIRED(softs);
166
167		if ((timeout_in_msec != TIMEOUT_INFINITE) && (i++ == loop_cnt)) {
168			DBG_ERR("ERR: Requested cmd timed out !!!\n");
169			ret = PQI_STATUS_TIMEOUT;
170			rcb->timedout = true;
171			break;
172		}
173
174		if (pqisrc_ctrl_offline(softs)) {
175			DBG_ERR("Controller is Offline");
176			ret = PQI_STATUS_FAILURE;
177			break;
178		}
179
180	}
181	rcb->req_pending = true;
182
183	DBG_FUNC("OUT\n");
184
185	return ret;
186}
187
188/* Function used to validate the device wwid. */
189boolean_t
190pqisrc_device_equal(pqi_scsi_dev_t *dev1,
191	pqi_scsi_dev_t *dev2)
192{
193	return dev1->wwid == dev2->wwid;
194}
195
196/* Function used to validate the device scsi3addr. */
197boolean_t
198pqisrc_scsi3addr_equal(uint8_t *scsi3addr1, uint8_t *scsi3addr2)
199{
200	return memcmp(scsi3addr1, scsi3addr2, 8) == 0;
201}
202
203/* Function used to validate hba_lunid */
204boolean_t
205pqisrc_is_hba_lunid(uint8_t *scsi3addr)
206{
207	return pqisrc_scsi3addr_equal(scsi3addr, RAID_CTLR_LUNID);
208}
209
210/* Function used to validate type of device */
211boolean_t
212pqisrc_is_logical_device(pqi_scsi_dev_t *device)
213{
214	return !device->is_physical_device;
215}
216
217/* Function used to sanitize inquiry string */
218void
219pqisrc_sanitize_inquiry_string(unsigned char *s, int len)
220{
221	boolean_t terminated = false;
222
223	DBG_FUNC("IN\n");
224
225	for (; len > 0; (--len, ++s)) {
226		if (*s == 0)
227			terminated = true;
228		if (terminated || *s < 0x20 || *s > 0x7e)
229			*s = ' ';
230	}
231
232	DBG_FUNC("OUT\n");
233}
234
235static char *raid_levels[] = {
236	"RAID 0",
237	"RAID 4",
238	"RAID 1(1+0)",
239	"RAID 5",
240	"RAID 5+1",
241	"RAID 6",
242	"RAID 1(Triple)",
243};
244
245/* Get the RAID level from the index */
246char *
247pqisrc_raidlevel_to_string(uint8_t raid_level)
248{
249	DBG_FUNC("IN\n");
250	if (raid_level < ARRAY_SIZE(raid_levels))
251		return raid_levels[raid_level];
252	DBG_FUNC("OUT\n");
253
254	return " ";
255}
256
257/* Debug routine for displaying device info */
258void pqisrc_display_device_info(pqisrc_softstate_t *softs,
259	char *action, pqi_scsi_dev_t *device)
260{
261	if (device->is_physical_device) {
262		DBG_NOTE("%s scsi BTL %d:%d:%d:  %.8s %.16s %-12s "
263		"SSDSmartPathCap%c En%c Exp%c qd=%d\n",
264		action,
265		device->bus,
266		device->target,
267		device->lun,
268		device->vendor,
269		device->model,
270		"Physical",
271		device->offload_config ? '+' : '-',
272		device->offload_enabled_pending ? '+' : '-',
273		device->expose_device ? '+' : '-',
274		device->queue_depth);
275	} else if (device->devtype == RAID_DEVICE) {
276		DBG_NOTE("%s scsi BTL %d:%d:%d:  %.8s %.16s %-12s "
277		"SSDSmartPathCap%c En%c Exp%c qd=%d\n",
278		action,
279		device->bus,
280		device->target,
281		device->lun,
282		device->vendor,
283		device->model,
284		"Controller",
285		device->offload_config ? '+' : '-',
286		device->offload_enabled_pending ? '+' : '-',
287		device->expose_device ? '+' : '-',
288		device->queue_depth);
289	} else if (device->devtype == CONTROLLER_DEVICE) {
290		DBG_NOTE("%s scsi BTL %d:%d:%d:  %.8s %.16s %-12s "
291		"SSDSmartPathCap%c En%c Exp%c qd=%d\n",
292		action,
293		device->bus,
294		device->target,
295		device->lun,
296		device->vendor,
297		device->model,
298		"External",
299		device->offload_config ? '+' : '-',
300		device->offload_enabled_pending ? '+' : '-',
301		device->expose_device ? '+' : '-',
302		device->queue_depth);
303	} else {
304		DBG_NOTE("%s scsi BTL %d:%d:%d:  %.8s %.16s %-12s "
305		"SSDSmartPathCap%c En%c Exp%c qd=%d devtype=%d\n",
306		action,
307		device->bus,
308		device->target,
309		device->lun,
310		device->vendor,
311		device->model,
312		pqisrc_raidlevel_to_string(device->raid_level),
313		device->offload_config ? '+' : '-',
314		device->offload_enabled_pending ? '+' : '-',
315		device->expose_device ? '+' : '-',
316		device->queue_depth,
317		device->devtype);
318	pqisrc_raidlevel_to_string(device->raid_level); /* To use this function */
319	}
320}
321
322/* validate the structure sizes */
323void
324check_struct_sizes(void)
325{
326
327    ASSERT(sizeof(SCSI3Addr_struct)== 2);
328    ASSERT(sizeof(PhysDevAddr_struct) == 8);
329    ASSERT(sizeof(LogDevAddr_struct)== 8);
330    ASSERT(sizeof(LUNAddr_struct)==8);
331    ASSERT(sizeof(RequestBlock_struct) == 20);
332    ASSERT(sizeof(MoreErrInfo_struct)== 8);
333    ASSERT(sizeof(ErrorInfo_struct)== 48);
334    /* Checking the size of IOCTL_Command_struct for both
335       64 bit and 32 bit system*/
336    ASSERT(sizeof(IOCTL_Command_struct)== 86 ||
337           sizeof(IOCTL_Command_struct)== 82);
338    ASSERT(sizeof(struct bmic_host_wellness_driver_version)== 42);
339    ASSERT(sizeof(struct bmic_host_wellness_time)== 20);
340    ASSERT(sizeof(struct pqi_dev_adminq_cap)== 8);
341    ASSERT(sizeof(struct admin_q_param)== 4);
342    ASSERT(sizeof(struct pqi_registers)== 256);
343    ASSERT(sizeof(struct ioa_registers)== 4128);
344    ASSERT(sizeof(struct pqi_pref_settings)==4);
345    ASSERT(sizeof(struct pqi_cap)== 20);
346    ASSERT(sizeof(iu_header_t)== 4);
347    ASSERT(sizeof(gen_adm_req_iu_t)== 64);
348    ASSERT(sizeof(gen_adm_resp_iu_t)== 64);
349    ASSERT(sizeof(op_q_params) == 9);
350    ASSERT(sizeof(raid_path_error_info_elem_t)== 276);
351    ASSERT(sizeof(aio_path_error_info_elem_t)== 276);
352    ASSERT(sizeof(struct init_base_struct)== 24);
353    ASSERT(sizeof(pqi_iu_layer_desc_t)== 16);
354    ASSERT(sizeof(pqi_dev_cap_t)== 576);
355    ASSERT(sizeof(pqi_aio_req_t)== 128);
356    ASSERT(sizeof(pqisrc_raid_req_t)== 128);
357    ASSERT(sizeof(pqi_raid_tmf_req_t)== 32);
358    ASSERT(sizeof(pqi_aio_tmf_req_t)== 32);
359    ASSERT(sizeof(struct pqi_io_response)== 16);
360    ASSERT(sizeof(struct sense_header_scsi)== 8);
361    ASSERT(sizeof(reportlun_header_t)==8);
362    ASSERT(sizeof(reportlun_ext_entry_t)== 24);
363    ASSERT(sizeof(reportlun_data_ext_t)== 32);
364    ASSERT(sizeof(raidmap_data_t)==8);
365    ASSERT(sizeof(pqisrc_raid_map_t)== 8256);
366    ASSERT(sizeof(bmic_ident_ctrl_t)== 325);
367    ASSERT(sizeof(bmic_ident_physdev_t)==2048);
368
369}
370
371#if 0
372uint32_t
373pqisrc_count_num_scsi_active_requests_on_dev(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device)
374{
375	uint32_t i, active_io = 0;
376	rcb_t* rcb;
377
378	for(i = 1; i <= softs->max_outstanding_io; i++) {
379		rcb = &softs->rcb[i];
380		if(rcb && IS_OS_SCSICMD(rcb) && (rcb->dvp == device) && rcb->req_pending) {
381			active_io++;
382		}
383	}
384	return active_io;
385}
386
387void
388check_device_pending_commands_to_complete(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device)
389{
390	uint32_t tag = softs->max_outstanding_io, active_requests;
391	uint64_t timeout = 0, delay_in_usec = 1000; /* In micro Seconds  */
392	rcb_t* rcb;
393
394	DBG_FUNC("IN\n");
395
396	active_requests = pqisrc_count_num_scsi_active_requests_on_dev(softs, device);
397
398	DBG_WARN("Device Outstanding IO count = %u\n", active_requests);
399
400	if(!active_requests)
401		return;
402
403	do {
404		rcb = &softs->rcb[tag];
405		if(rcb && IS_OS_SCSICMD(rcb) && (rcb->dvp == device) && rcb->req_pending) {
406			OS_SLEEP(delay_in_usec);
407			timeout += delay_in_usec;
408		}
409		else
410			tag--;
411		if(timeout >= PQISRC_PENDING_IO_TIMEOUT_USEC) {
412			DBG_WARN("timed out waiting for pending IO\n");
413			return;
414		}
415	} while(tag);
416}
417#endif
418
419void
420pqisrc_wait_for_device_commands_to_complete(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device)
421{
422	uint64_t timeout_in_usec = 0, delay_in_usec = 1000; /* In microseconds */
423
424	DBG_FUNC("IN\n");
425
426	if(!softs->ctrl_online)
427		return;
428
429#if PQISRC_DEVICE_IO_COUNTER
430	DBG_WARN_BTL(device,"Device Outstanding IO count = %lu\n", pqisrc_read_device_active_io(softs, device));
431
432	while(pqisrc_read_device_active_io(softs, device)) {
433		OS_BUSYWAIT(delay_in_usec); /* In microseconds */
434		if(!softs->ctrl_online) {
435			DBG_WARN("Controller Offline was detected.\n");
436		}
437		timeout_in_usec += delay_in_usec;
438		if(timeout_in_usec >= PQISRC_PENDING_IO_TIMEOUT_USEC) {
439			DBG_WARN_BTL(device,"timed out waiting for pending IO. DeviceOutStandingIo's=%lu\n",
440                                 pqisrc_read_device_active_io(softs, device));
441			return;
442		}
443	}
444#else
445	check_device_pending_commands_to_complete(softs, device);
446#endif
447}
448