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$ */
27
28#include "smartpqi_includes.h"
29
30/* read and modify controller diagnostic option - PQI_PTRAID_UPDATE_ON_RESCAN_LUNS */
31void
32pqisrc_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 */
84boolean_t
85pqisrc_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 */
97void
98pqisrc_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 */
120void
121pqisrc_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 */
142void
143pqisrc_take_ctrl_offline(pqisrc_softstate_t *softs)
144{
145	DBG_FUNC("IN\n");
146
147	softs->ctrl_online = false;
148
149	int lockupcode = 0;
150
151	if (SIS_IS_KERNEL_PANIC(softs)) {
152                lockupcode = PCI_MEM_GET32(softs, &softs->ioa_reg->mb[7], LEGACY_SIS_SRCV_OFFSET_MAILBOX_7);
153                DBG_ERR("Controller FW is not runnning, Lockup code = %x\n", lockupcode);
154        }
155        else {
156                pqisrc_trigger_nmi_sis(softs);
157        }
158
159	os_complete_outstanding_cmds_nodevice(softs);
160	pqisrc_wait_for_rescan_complete(softs);
161	pqisrc_take_devices_offline(softs);
162
163	DBG_FUNC("OUT\n");
164}
165
166/*
167 * Timer handler for the adapter heart-beat.
168 */
169void
170pqisrc_heartbeat_timer_handler(pqisrc_softstate_t *softs)
171{
172	uint8_t take_offline = false;
173
174	DBG_FUNC("IN\n");
175
176	if (CTRLR_HEARTBEAT_CNT(softs) == softs->prev_heartbeat_count) {
177		take_offline = true;
178		goto take_ctrl_offline;
179	}
180	softs->prev_heartbeat_count = CTRLR_HEARTBEAT_CNT(softs);
181	DBG_INFO("CTRLR_HEARTBEAT_CNT(softs)  = %lx \
182		softs->prev_heartbeat_count = %lx\n",
183		CTRLR_HEARTBEAT_CNT(softs), softs->prev_heartbeat_count);
184
185take_ctrl_offline:
186	if (take_offline){
187		DBG_ERR("controller is offline\n");
188		pqisrc_take_ctrl_offline(softs);
189		os_stop_heartbeat_timer(softs);
190	}
191	DBG_FUNC("OUT\n");
192}
193
194/*
195 * Conditional variable management routine for internal commands.
196 */
197int
198pqisrc_wait_on_condition(pqisrc_softstate_t *softs, rcb_t *rcb,
199				uint32_t timeout_in_msec)
200{
201	DBG_FUNC("IN\n");
202
203	int ret = PQI_STATUS_SUCCESS;
204
205	/* 1 msec = 500 usec * 2 */
206	uint32_t loop_cnt = timeout_in_msec * 2;
207	uint32_t i = 0;
208
209	while (rcb->req_pending == true) {
210		OS_SLEEP(500); /* Micro sec */
211		/* Polling needed for FreeBSD : since ithread routine is not scheduled
212		 * during bootup, we could use polling until interrupts are
213		 * enabled (using 'if (cold)'to check for the boot time before
214		 * interrupts are enabled). */
215		IS_POLLING_REQUIRED(softs);
216
217		if ((timeout_in_msec != TIMEOUT_INFINITE) && (i++ == loop_cnt)) {
218			DBG_ERR("ERR: Requested cmd timed out !!!\n");
219			ret = PQI_STATUS_TIMEOUT;
220			rcb->timedout = true;
221			break;
222		}
223
224		if (pqisrc_ctrl_offline(softs)) {
225			DBG_ERR("Controller is Offline");
226			ret = PQI_STATUS_FAILURE;
227			break;
228		}
229
230	}
231	rcb->req_pending = true;
232
233	DBG_FUNC("OUT\n");
234
235	return ret;
236}
237
238/* Function used to validate the device wwid. */
239boolean_t
240pqisrc_device_equal(pqi_scsi_dev_t *dev1,
241	pqi_scsi_dev_t *dev2)
242{
243	return dev1->wwid == dev2->wwid;
244}
245
246/* Function used to validate the device scsi3addr. */
247boolean_t
248pqisrc_scsi3addr_equal(uint8_t *scsi3addr1, uint8_t *scsi3addr2)
249{
250	return memcmp(scsi3addr1, scsi3addr2, 8) == 0;
251}
252
253/* Function used to validate hba_lunid */
254boolean_t
255pqisrc_is_hba_lunid(uint8_t *scsi3addr)
256{
257	return pqisrc_scsi3addr_equal(scsi3addr, (uint8_t*)RAID_CTLR_LUNID);
258}
259
260/* Function used to validate type of device */
261boolean_t
262pqisrc_is_logical_device(pqi_scsi_dev_t *device)
263{
264	return !device->is_physical_device;
265}
266
267/* Function used to sanitize inquiry string */
268void
269pqisrc_sanitize_inquiry_string(unsigned char *s, int len)
270{
271	boolean_t terminated = false;
272
273	DBG_FUNC("IN\n");
274
275	for (; len > 0; (--len, ++s)) {
276		if (*s == 0)
277			terminated = true;
278		if (terminated || *s < 0x20 || *s > 0x7e)
279			*s = ' ';
280	}
281
282	DBG_FUNC("OUT\n");
283}
284
285static char *raid_levels[] = {
286	"RAID 0",
287	"RAID 4",
288	"RAID 1(1+0)",
289	"RAID 5",
290	"RAID 5+1",
291	"RAID ADG",
292	"RAID 1(ADM)",
293};
294
295/* Get the RAID level from the index */
296char *
297pqisrc_raidlevel_to_string(uint8_t raid_level)
298{
299	DBG_FUNC("IN\n");
300	if (raid_level < ARRAY_SIZE(raid_levels))
301		return raid_levels[raid_level];
302	DBG_FUNC("OUT\n");
303
304	return " ";
305}
306
307/* Debug routine for displaying device info */
308void
309pqisrc_display_device_info(pqisrc_softstate_t *softs,
310	char *action, pqi_scsi_dev_t *device)
311{
312	DBG_INFO( "%s scsi BTL %d:%d:%d:  %.8s %.16s %-12s SSDSmartPathCap%c En%c Exp%c qd=%d\n",
313		action,
314		device->bus,
315		device->target,
316		device->lun,
317		device->vendor,
318		device->model,
319		pqisrc_raidlevel_to_string(device->raid_level),
320		device->offload_config ? '+' : '-',
321		device->offload_enabled_pending ? '+' : '-',
322		device->expose_device ? '+' : '-',
323		device->queue_depth);
324	pqisrc_raidlevel_to_string(device->raid_level); /* To use this function */
325}
326
327/* validate the structure sizes */
328void
329check_struct_sizes()
330{
331
332    ASSERT(sizeof(SCSI3Addr_struct)== 2);
333    ASSERT(sizeof(PhysDevAddr_struct) == 8);
334    ASSERT(sizeof(LogDevAddr_struct)== 8);
335    ASSERT(sizeof(LUNAddr_struct)==8);
336    ASSERT(sizeof(RequestBlock_struct) == 20);
337    ASSERT(sizeof(MoreErrInfo_struct)== 8);
338    ASSERT(sizeof(ErrorInfo_struct)== 48);
339    /* Checking the size of IOCTL_Command_struct for both
340       64 bit and 32 bit system*/
341    ASSERT(sizeof(IOCTL_Command_struct)== 86 ||
342           sizeof(IOCTL_Command_struct)== 82);
343    ASSERT(sizeof(struct bmic_host_wellness_driver_version)== 42);
344    ASSERT(sizeof(struct bmic_host_wellness_time)== 20);
345    ASSERT(sizeof(struct pqi_dev_adminq_cap)== 8);
346    ASSERT(sizeof(struct admin_q_param)== 4);
347    ASSERT(sizeof(struct pqi_registers)== 256);
348    ASSERT(sizeof(struct ioa_registers)== 4128);
349    ASSERT(sizeof(struct pqi_pref_settings)==4);
350    ASSERT(sizeof(struct pqi_cap)== 20);
351    ASSERT(sizeof(iu_header_t)== 4);
352    ASSERT(sizeof(gen_adm_req_iu_t)== 64);
353    ASSERT(sizeof(gen_adm_resp_iu_t)== 64);
354    ASSERT(sizeof(op_q_params) == 9);
355    ASSERT(sizeof(raid_path_error_info_elem_t)== 276);
356    ASSERT(sizeof(aio_path_error_info_elem_t)== 276);
357    ASSERT(sizeof(struct init_base_struct)== 24);
358    ASSERT(sizeof(pqi_iu_layer_desc_t)== 16);
359    ASSERT(sizeof(pqi_dev_cap_t)== 576);
360    ASSERT(sizeof(pqi_aio_req_t)== 128);
361    ASSERT(sizeof(pqisrc_raid_req_t)== 128);
362    ASSERT(sizeof(pqi_raid_tmf_req_t)== 32);
363    ASSERT(sizeof(pqi_aio_tmf_req_t)== 32);
364    ASSERT(sizeof(struct pqi_io_response)== 16);
365    ASSERT(sizeof(struct sense_header_scsi)== 8);
366    ASSERT(sizeof(reportlun_header_t)==8);
367    ASSERT(sizeof(reportlun_ext_entry_t)== 24);
368    ASSERT(sizeof(reportlun_data_ext_t)== 32);
369    ASSERT(sizeof(raidmap_data_t)==8);
370    ASSERT(sizeof(pqisrc_raid_map_t)== 8256);
371    ASSERT(sizeof(bmic_ident_ctrl_t)== 325);
372    ASSERT(sizeof(bmic_ident_physdev_t)==2048);
373
374}
375
376uint32_t
377pqisrc_count_num_scsi_active_requests_on_dev(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device)
378{
379	uint32_t i, active_io = 0;
380	rcb_t* rcb;
381
382	for(i = 1; i <= softs->max_outstanding_io; i++) {
383		rcb = &softs->rcb[i];
384		if(rcb && IS_OS_SCSICMD(rcb) && (rcb->dvp == device) && rcb->req_pending) {
385			active_io++;
386		}
387	}
388	return active_io;
389}
390
391void
392check_device_pending_commands_to_complete(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device)
393{
394	uint32_t tag = softs->max_outstanding_io, active_requests;
395	uint64_t timeout = 0, delay_in_usec = 1000; //In micro Seconds
396	rcb_t* rcb;
397
398	DBG_FUNC("IN\n");
399
400	active_requests = pqisrc_count_num_scsi_active_requests_on_dev(softs, device);
401
402	DBG_WARN("Device Outstanding IO count = %u\n", active_requests);
403
404	if(!active_requests)
405		return;
406
407	do {
408		rcb = &softs->rcb[tag];
409		if(rcb && IS_OS_SCSICMD(rcb) && (rcb->dvp == device) && rcb->req_pending) {
410			OS_BUSYWAIT(delay_in_usec);
411			timeout += delay_in_usec;
412		}
413		else
414			tag--;
415		if(timeout >= PQISRC_PENDING_IO_TIMEOUT_USEC) {
416			DBG_WARN("timed out waiting for pending IO\n");
417			return;
418		}
419	} while(tag);
420
421}
422
423inline uint64_t
424pqisrc_increment_device_active_io(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device)
425{
426#if PQISRC_DEVICE_IO_COUNTER
427	/*Increment device active io count by one*/
428	return OS_ATOMIC64_INC(&device->active_requests);
429#endif
430}
431
432inline uint64_t
433pqisrc_decrement_device_active_io(pqisrc_softstate_t *softs,  pqi_scsi_dev_t *device)
434{
435#if PQISRC_DEVICE_IO_COUNTER
436	/*Decrement device active io count by one*/
437	return OS_ATOMIC64_DEC(&device->active_requests);
438#endif
439}
440
441inline void
442pqisrc_init_device_active_io(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device)
443{
444#if PQISRC_DEVICE_IO_COUNTER
445	/* Reset device count to Zero */
446	OS_ATOMIC64_INIT(&device->active_requests, 0);
447#endif
448}
449
450inline uint64_t
451pqisrc_read_device_active_io(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device)
452{
453#if PQISRC_DEVICE_IO_COUNTER
454	/* read device active count*/
455	return OS_ATOMIC64_READ(&device->active_requests);
456#endif
457}
458
459void
460pqisrc_wait_for_device_commands_to_complete(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device)
461{
462	uint64_t timeout_in_usec = 0, delay_in_usec = 1000; //In microseconds
463
464	DBG_FUNC("IN\n");
465
466	if(!softs->ctrl_online)
467		return;
468
469#if PQISRC_DEVICE_IO_COUNTER
470	DBG_NOTE("Device Outstanding IO count = %ld\n", pqisrc_read_device_active_io(softs, device));
471
472	while(pqisrc_read_device_active_io(softs, device)) {
473		OS_BUSYWAIT(delay_in_usec); // In microseconds
474		if(!softs->ctrl_online) {
475			DBG_WARN("Controller Offline was detected.\n");
476		}
477		timeout_in_usec += delay_in_usec;
478		if(timeout_in_usec >= PQISRC_PENDING_IO_TIMEOUT_USEC) {
479			DBG_WARN("timed out waiting for pending IO. DeviceOutStandingIo's=%ld\n",
480                                 pqisrc_read_device_active_io(softs, device));
481			return;
482		}
483	}
484#else
485	check_device_pending_commands_to_complete(softs, device);
486#endif
487}
488