xref: /freebsd/sys/dev/smartpqi/smartpqi_features.c (revision 7ea28254ec5376b5deb86c136e1838d0134dbb22)
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  * Checks a firmware feature status, given bit position.
31  */
32 static inline boolean_t
pqi_is_firmware_feature_supported(struct pqi_config_table_firmware_features * firmware_features,unsigned int bit_position)33 pqi_is_firmware_feature_supported(
34 	struct pqi_config_table_firmware_features *firmware_features,
35 	unsigned int bit_position)
36 {
37 	unsigned int byte_index;
38 
39 	byte_index = bit_position / BITS_PER_BYTE;
40 
41 	if (byte_index >= firmware_features->num_elements) {
42 		DBG_ERR_NO_SOFTS("Invalid byte index for bit position %u\n",
43 			bit_position);
44 		return false;
45 	}
46 
47 	return (firmware_features->features_supported[byte_index] &
48 		(1 << (bit_position % BITS_PER_BYTE))) ? true : false;
49 }
50 
51 /*
52  * Counts down into the enabled section of firmware
53  * features and reports current enabled status, given
54  * bit position.
55  */
56 static inline boolean_t
pqi_is_firmware_feature_enabled(struct pqi_config_table_firmware_features * firmware_features,uint8_t * firmware_features_iomem_addr,unsigned int bit_position)57 pqi_is_firmware_feature_enabled(
58 	struct pqi_config_table_firmware_features *firmware_features,
59 	uint8_t *firmware_features_iomem_addr,
60 	unsigned int bit_position)
61 {
62 	unsigned int byte_index;
63 	uint8_t *features_enabled_iomem_addr;
64 
65 	byte_index = (bit_position / BITS_PER_BYTE) +
66 		(firmware_features->num_elements * 2);
67 
68 	features_enabled_iomem_addr = firmware_features_iomem_addr +
69 		offsetof(struct pqi_config_table_firmware_features,
70 			features_supported) + byte_index;
71 
72 	return (*features_enabled_iomem_addr &
73 		(1 << (bit_position % BITS_PER_BYTE))) ? true : false;
74 }
75 
76 /*
77  * Sets the given bit position for the driver to request the indicated
78  * firmware feature be enabled.
79  */
80 static inline void
pqi_request_firmware_feature(struct pqi_config_table_firmware_features * firmware_features,unsigned int bit_position)81 pqi_request_firmware_feature(
82 	struct pqi_config_table_firmware_features *firmware_features,
83 	unsigned int bit_position)
84 {
85 	unsigned int byte_index;
86 
87 	/* byte_index adjusted to index into requested start bits */
88 	byte_index = (bit_position / BITS_PER_BYTE) +
89 		firmware_features->num_elements;
90 
91 	/* setting requested bits of local firmware_features */
92 	firmware_features->features_supported[byte_index] |=
93 		(1 << (bit_position % BITS_PER_BYTE));
94 }
95 
96 /*
97  * Creates and sends the request for firmware to update the config
98  * table.
99  */
100 static int
pqi_config_table_update(pqisrc_softstate_t * softs,uint16_t first_section,uint16_t last_section)101 pqi_config_table_update(pqisrc_softstate_t *softs,
102 	uint16_t first_section, uint16_t last_section)
103 {
104 	struct pqi_vendor_general_request request;
105 	int ret;
106 
107 	memset(&request, 0, sizeof(request));
108 
109 	request.header.iu_type = PQI_REQUEST_IU_VENDOR_GENERAL;
110 	request.header.iu_length = sizeof(request) - PQI_REQUEST_HEADER_LENGTH;
111 	request.function_code = PQI_VENDOR_GENERAL_CONFIG_TABLE_UPDATE;
112 	request.data.config_table_update.first_section = first_section;
113 	request.data.config_table_update.last_section = last_section;
114 
115 	ret = pqisrc_build_send_vendor_request(softs, &request);
116 
117 	if (ret != PQI_STATUS_SUCCESS) {
118 		DBG_ERR("Failed to submit vendor general request IU, Ret status: %d\n", ret);
119 	}
120 
121 	return ret;
122 }
123 
124 /*
125  * Copies requested features bits into firmware config table,
126  * checks for support, and returns status of updating the config table.
127  */
128 static int
pqi_enable_firmware_features(pqisrc_softstate_t * softs,struct pqi_config_table_firmware_features * firmware_features,uint8_t * firmware_features_abs_addr)129 pqi_enable_firmware_features(pqisrc_softstate_t *softs,
130 	struct pqi_config_table_firmware_features *firmware_features,
131 	uint8_t *firmware_features_abs_addr)
132 {
133 	uint8_t *features_requested;
134 	uint8_t *features_requested_abs_addr;
135 	uint16_t *host_max_known_feature_iomem_addr;
136 	uint16_t pqi_max_feature = PQI_FIRMWARE_FEATURE_MAXIMUM;
137 
138 	features_requested = firmware_features->features_supported +
139 		firmware_features->num_elements;
140 
141 	features_requested_abs_addr = firmware_features_abs_addr +
142 		(features_requested - (uint8_t*)firmware_features);
143 	/*
144 	 * NOTE: This memcpy is writing to a BAR-mapped address
145 	 * which may not be safe for all OSes without proper API
146 	 */
147 	memcpy(features_requested_abs_addr, features_requested,
148 		firmware_features->num_elements);
149 
150 	if (pqi_is_firmware_feature_supported(firmware_features,
151 		PQI_FIRMWARE_FEATURE_MAX_KNOWN_FEATURE)) {
152 		host_max_known_feature_iomem_addr =
153 			(uint16_t*)(features_requested_abs_addr +
154 			(firmware_features->num_elements * 2) + sizeof(uint16_t));
155 			/*
156 			 * NOTE: This writes to a BAR-mapped address
157 			 * which may not be safe for all OSes without proper API
158 			 */
159 			*host_max_known_feature_iomem_addr = pqi_max_feature;
160 	}
161 
162 	return pqi_config_table_update(softs,
163 		PQI_CONF_TABLE_SECTION_FIRMWARE_FEATURES,
164 		PQI_CONF_TABLE_SECTION_FIRMWARE_FEATURES);
165 }
166 
167 typedef struct pqi_firmware_feature pqi_firmware_feature_t;
168 typedef void (*feature_status_fn)(pqisrc_softstate_t *softs,
169 	pqi_firmware_feature_t *firmware_feature);
170 
171 struct pqi_firmware_feature {
172 	char		*feature_name;
173 	unsigned int	feature_bit;
174 	boolean_t		supported;
175 	boolean_t		enabled;
176 	feature_status_fn	feature_status;
177 };
178 
179 static void
pqi_firmware_feature_status(pqisrc_softstate_t * softs,struct pqi_firmware_feature * firmware_feature)180 pqi_firmware_feature_status(pqisrc_softstate_t *softs,
181 	struct pqi_firmware_feature *firmware_feature)
182 {
183 	if (!firmware_feature->supported) {
184 		DBG_NOTE("%s not supported by controller\n",
185 			firmware_feature->feature_name);
186 		return;
187 	}
188 
189 	if (firmware_feature->enabled) {
190 		DBG_NOTE("%s enabled\n", firmware_feature->feature_name);
191 		return;
192 	}
193 
194 	DBG_NOTE("failed to enable %s\n", firmware_feature->feature_name);
195 }
196 
197 static void
pqi_ctrl_update_feature_flags(pqisrc_softstate_t * softs,struct pqi_firmware_feature * firmware_feature)198 pqi_ctrl_update_feature_flags(pqisrc_softstate_t *softs,
199 	struct pqi_firmware_feature *firmware_feature)
200 {
201 	switch (firmware_feature->feature_bit) {
202 	case PQI_FIRMWARE_FEATURE_RAID_1_WRITE_BYPASS:
203 		softs->aio_raid1_write_bypass = firmware_feature->enabled;
204 		break;
205 	case PQI_FIRMWARE_FEATURE_RAID_5_WRITE_BYPASS:
206 		softs->aio_raid5_write_bypass = firmware_feature->enabled;
207 		break;
208 	case PQI_FIRMWARE_FEATURE_RAID_6_WRITE_BYPASS:
209 		softs->aio_raid6_write_bypass = firmware_feature->enabled;
210 		break;
211 	case PQI_FIRMWARE_FEATURE_RAID_IU_TIMEOUT:
212 		softs->timeout_in_passthrough = true;
213 		break;
214 	case PQI_FIRMWARE_FEATURE_TMF_IU_TIMEOUT:
215 		softs->timeout_in_tmf = true;
216 		break;
217 	case PQI_FIRMWARE_FEATURE_UNIQUE_SATA_WWN:
218 		break;
219 	case PQI_FIRMWARE_FEATURE_PAGE83_IDENTIFIER_FOR_RPL_WWID:
220 		softs->page83id_in_rpl = true;
221 		break;
222 	default:
223 		DBG_NOTE("Nothing to do\n");
224 		return;
225 		break;
226 	}
227 	/* for any valid feature, also go update the feature status. */
228 	pqi_firmware_feature_status(softs, firmware_feature);
229 }
230 
231 
232 static inline void
pqi_firmware_feature_update(pqisrc_softstate_t * softs,struct pqi_firmware_feature * firmware_feature)233 pqi_firmware_feature_update(pqisrc_softstate_t *softs,
234 	struct pqi_firmware_feature *firmware_feature)
235 {
236 	if (firmware_feature->feature_status)
237 		firmware_feature->feature_status(softs, firmware_feature);
238 }
239 
240 /* Defines PQI features that driver wishes to support */
241 static struct pqi_firmware_feature pqi_firmware_features[] = {
242 #if 0
243 	{
244 		.feature_name = "Online Firmware Activation",
245 		.feature_bit = PQI_FIRMWARE_FEATURE_OFA,
246 		.feature_status = pqi_firmware_feature_status,
247 	},
248 	{
249 		.feature_name = "Serial Management Protocol",
250 		.feature_bit = PQI_FIRMWARE_FEATURE_SMP,
251 		.feature_status = pqi_firmware_feature_status,
252 	},
253 #endif
254 	{
255 		.feature_name = "SATA WWN Unique ID",
256 		.feature_bit = PQI_FIRMWARE_FEATURE_UNIQUE_SATA_WWN,
257 		.feature_status = pqi_ctrl_update_feature_flags,
258 	},
259 	{
260 		.feature_name = "RAID IU Timeout",
261 		.feature_bit = PQI_FIRMWARE_FEATURE_RAID_IU_TIMEOUT,
262 		.feature_status = pqi_ctrl_update_feature_flags,
263 	},
264 	{
265 		.feature_name = "TMF IU Timeout",
266 		.feature_bit = PQI_FIRMWARE_FEATURE_TMF_IU_TIMEOUT,
267 		.feature_status = pqi_ctrl_update_feature_flags,
268 	},
269 	{
270 		.feature_name = "Support for RPL WWID filled by Page83 identifier",
271 		.feature_bit = PQI_FIRMWARE_FEATURE_PAGE83_IDENTIFIER_FOR_RPL_WWID,
272 		.feature_status = pqi_ctrl_update_feature_flags,
273 	},
274 	/* Features independent of Maximum Known Feature should be added
275 	before Maximum Known Feature*/
276 	{
277 		.feature_name = "Maximum Known Feature",
278 		.feature_bit = PQI_FIRMWARE_FEATURE_MAX_KNOWN_FEATURE,
279 		.feature_status = pqi_firmware_feature_status,
280 	},
281 	{
282 		.feature_name = "RAID 0 Read Bypass",
283 		.feature_bit = PQI_FIRMWARE_FEATURE_RAID_0_READ_BYPASS,
284 		.feature_status = pqi_firmware_feature_status,
285 	},
286 	{
287 		.feature_name = "RAID 1 Read Bypass",
288 		.feature_bit = PQI_FIRMWARE_FEATURE_RAID_1_READ_BYPASS,
289 		.feature_status = pqi_firmware_feature_status,
290 	},
291 	{
292 		.feature_name = "RAID 5 Read Bypass",
293 		.feature_bit = PQI_FIRMWARE_FEATURE_RAID_5_READ_BYPASS,
294 		.feature_status = pqi_firmware_feature_status,
295 	},
296 	{
297 		.feature_name = "RAID 6 Read Bypass",
298 		.feature_bit = PQI_FIRMWARE_FEATURE_RAID_6_READ_BYPASS,
299 		.feature_status = pqi_firmware_feature_status,
300 	},
301 	{
302 		.feature_name = "RAID 0 Write Bypass",
303 		.feature_bit = PQI_FIRMWARE_FEATURE_RAID_0_WRITE_BYPASS,
304 		.feature_status = pqi_firmware_feature_status,
305 	},
306 	{
307 		.feature_name = "RAID 1 Write Bypass",
308 		.feature_bit = PQI_FIRMWARE_FEATURE_RAID_1_WRITE_BYPASS,
309 		.feature_status = pqi_ctrl_update_feature_flags,
310 	},
311 	{
312 		.feature_name = "RAID 5 Write Bypass",
313 		.feature_bit = PQI_FIRMWARE_FEATURE_RAID_5_WRITE_BYPASS,
314 		.feature_status = pqi_ctrl_update_feature_flags,
315 	},
316 	{
317 		.feature_name = "RAID 6 Write Bypass",
318 		.feature_bit = PQI_FIRMWARE_FEATURE_RAID_6_WRITE_BYPASS,
319 		.feature_status = pqi_ctrl_update_feature_flags,
320 	},
321 #if 0
322 	{
323 		.feature_name = "New Soft Reset Handshake",
324 		.feature_bit = PQI_FIRMWARE_FEATURE_SOFT_RESET_HANDSHAKE,
325 		.feature_status = pqi_ctrl_update_feature_flags,
326 	},
327 #endif
328 
329 };
330 
331 static void
pqi_process_firmware_features(pqisrc_softstate_t * softs,void * features,void * firmware_features_abs_addr)332 pqi_process_firmware_features(pqisrc_softstate_t *softs,
333 	void *features, void *firmware_features_abs_addr)
334 {
335 	int rc;
336 	struct pqi_config_table_firmware_features *firmware_features = features;
337 	unsigned int i;
338 	unsigned int num_features_supported;
339 
340 	/* Iterates through local PQI feature support list to
341 	see if the controller also supports the feature */
342 	for (i = 0, num_features_supported = 0;
343 		i < ARRAY_SIZE(pqi_firmware_features); i++) {
344 		/*Check if SATA_WWN_FOR_DEV_UNIQUE_ID feature enabled by setting module
345 		parameter if not avoid checking for the feature*/
346 		if ((pqi_firmware_features[i].feature_bit ==
347 			PQI_FIRMWARE_FEATURE_UNIQUE_SATA_WWN) &&
348 			(!softs->sata_unique_wwn)) {
349 			continue;
350 		}
351 		if (pqi_is_firmware_feature_supported(firmware_features,
352 			pqi_firmware_features[i].feature_bit)) {
353 			pqi_firmware_features[i].supported = true;
354 			num_features_supported++;
355 		} else {
356 			DBG_WARN("Feature %s is not supported by firmware\n",
357 			pqi_firmware_features[i].feature_name);
358 			pqi_firmware_feature_update(softs,
359 				&pqi_firmware_features[i]);
360 
361 			/* if max known feature bit isn't supported,
362  			 * then no other feature bits are supported.
363  			 */
364 			if (pqi_firmware_features[i].feature_bit ==
365 				PQI_FIRMWARE_FEATURE_MAX_KNOWN_FEATURE)
366 				break;
367 		}
368 	}
369 
370 	DBG_INFO("Num joint features supported : %u \n", num_features_supported);
371 
372 	if (num_features_supported == 0)
373 		return;
374 
375 	/* request driver features that are also on firmware-supported list */
376 	for (i = 0; i < ARRAY_SIZE(pqi_firmware_features); i++) {
377 		if (!pqi_firmware_features[i].supported)
378 			continue;
379 #ifdef DEVICE_HINT
380 		if (check_device_hint_status(softs, pqi_firmware_features[i].feature_bit))
381 			continue;
382 #endif
383 		pqi_request_firmware_feature(firmware_features,
384 			pqi_firmware_features[i].feature_bit);
385 	}
386 
387 	/* enable the features that were successfully requested. */
388 	rc = pqi_enable_firmware_features(softs, firmware_features,
389 		firmware_features_abs_addr);
390 	if (rc) {
391 		DBG_ERR("failed to enable firmware features in PQI configuration table\n");
392 		for (i = 0; i < ARRAY_SIZE(pqi_firmware_features); i++) {
393 			if (!pqi_firmware_features[i].supported)
394 				continue;
395 			pqi_firmware_feature_update(softs,
396 				&pqi_firmware_features[i]);
397 		}
398 		return;
399 	}
400 
401 	/* report the features that were successfully enabled. */
402 	for (i = 0; i < ARRAY_SIZE(pqi_firmware_features); i++) {
403 		if (!pqi_firmware_features[i].supported)
404 			continue;
405 		if (pqi_is_firmware_feature_enabled(firmware_features,
406 			firmware_features_abs_addr,
407 			pqi_firmware_features[i].feature_bit)) {
408 				pqi_firmware_features[i].enabled = true;
409 		} else {
410 			DBG_WARN("Feature %s could not be enabled.\n",
411 				pqi_firmware_features[i].feature_name);
412 		}
413 		pqi_firmware_feature_update(softs,
414 			&pqi_firmware_features[i]);
415 	}
416 }
417 
418 static void
pqi_init_firmware_features(void)419 pqi_init_firmware_features(void)
420 {
421 	unsigned int i;
422 
423 	for (i = 0; i < ARRAY_SIZE(pqi_firmware_features); i++) {
424 		pqi_firmware_features[i].supported = false;
425 		pqi_firmware_features[i].enabled = false;
426 	}
427 }
428 
429 static void
pqi_process_firmware_features_section(pqisrc_softstate_t * softs,void * features,void * firmware_features_abs_addr)430 pqi_process_firmware_features_section(pqisrc_softstate_t *softs,
431 	void *features, void *firmware_features_abs_addr)
432 {
433 	pqi_init_firmware_features();
434 	pqi_process_firmware_features(softs, features, firmware_features_abs_addr);
435 }
436 
437 
438 /*
439  * Get the PQI configuration table parameters.
440  * Currently using for heart-beat counter scratch-pad register.
441  */
442 int
pqisrc_process_config_table(pqisrc_softstate_t * softs)443 pqisrc_process_config_table(pqisrc_softstate_t *softs)
444 {
445 	int ret = PQI_STATUS_FAILURE;
446 	uint32_t config_table_size;
447 	uint32_t section_off;
448 	uint8_t *config_table_abs_addr;
449 	struct pqi_conf_table *conf_table;
450 	struct pqi_conf_table_section_header *section_hdr;
451 
452 	config_table_size = softs->pqi_cap.conf_tab_sz;
453 
454 	if (config_table_size < sizeof(*conf_table) ||
455 		config_table_size > PQI_CONF_TABLE_MAX_LEN) {
456 		DBG_ERR("Invalid PQI conf table length of %u\n",
457 			config_table_size);
458 		return ret;
459 	}
460 
461 	conf_table = os_mem_alloc(softs, config_table_size);
462 	if (!conf_table) {
463 		DBG_ERR("Failed to allocate memory for PQI conf table\n");
464 		return ret;
465 	}
466 
467 	config_table_abs_addr = (uint8_t *)(softs->pci_mem_base_vaddr +
468 					softs->pqi_cap.conf_tab_off);
469 
470 	PCI_MEM_GET_BUF(softs, config_table_abs_addr,
471 			softs->pqi_cap.conf_tab_off,
472 			(uint8_t*)conf_table, config_table_size);
473 
474 	if (memcmp(conf_table->sign, PQI_CONF_TABLE_SIGNATURE,
475 			sizeof(conf_table->sign)) != 0) {
476 		DBG_ERR("Invalid PQI config signature\n");
477 		goto out;
478 	}
479 
480 	section_off = LE_32(conf_table->first_section_off);
481 
482 	while (section_off) {
483 
484 		if (section_off+ sizeof(*section_hdr) >= config_table_size) {
485 			DBG_INFO("Reached end of PQI config table. Breaking off.\n");
486 			break;
487 		}
488 
489 		section_hdr = (struct pqi_conf_table_section_header *)((uint8_t *)conf_table + section_off);
490 
491 		switch (LE_16(section_hdr->section_id)) {
492 		case PQI_CONF_TABLE_SECTION_GENERAL_INFO:
493 			break;
494 		case PQI_CONF_TABLE_SECTION_FIRMWARE_FEATURES:
495 			pqi_process_firmware_features_section(softs, section_hdr, (config_table_abs_addr + section_off));
496 			break;
497 		case PQI_CONF_TABLE_SECTION_FIRMWARE_ERRATA:
498 		case PQI_CONF_TABLE_SECTION_DEBUG:
499 			break;
500 		case PQI_CONF_TABLE_SECTION_HEARTBEAT:
501 			softs->heartbeat_counter_off = softs->pqi_cap.conf_tab_off +
502 				section_off +
503 				offsetof(struct pqi_conf_table_heartbeat, heartbeat_counter);
504 			softs->heartbeat_counter_abs_addr = (uint64_t *)(softs->pci_mem_base_vaddr +
505 				softs->heartbeat_counter_off);
506 			ret = PQI_STATUS_SUCCESS;
507 			break;
508 		case PQI_CONF_TABLE_SOFT_RESET:
509 			break;
510 		default:
511 			DBG_NOTE("unrecognized PQI config table section ID: 0x%x\n",
512 				LE_16(section_hdr->section_id));
513 			break;
514 		}
515 		section_off = LE_16(section_hdr->next_section_off);
516 	}
517 out:
518 	os_mem_free(softs, (void *)conf_table,config_table_size);
519 	return ret;
520 }
521