siena_vpd.c revision 330897
195144Sgshapiro/*-
295144Sgshapiro * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
395144Sgshapiro *
495144Sgshapiro * Copyright (c) 2009-2016 Solarflare Communications Inc.
595144Sgshapiro * All rights reserved.
695144Sgshapiro *
7123051Sru * Redistribution and use in source and binary forms, with or without
8123051Sru * modification, are permitted provided that the following conditions are met:
9123051Sru *
1095144Sgshapiro * 1. Redistributions of source code must retain the above copyright notice,
1195144Sgshapiro *    this list of conditions and the following disclaimer.
1295144Sgshapiro * 2. Redistributions in binary form must reproduce the above copyright notice,
1395144Sgshapiro *    this list of conditions and the following disclaimer in the documentation
1495144Sgshapiro *    and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
26 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * The views and conclusions contained in the software and documentation are
29 * those of the authors and should not be interpreted as representing official
30 * policies, either expressed or implied, of the FreeBSD Project.
31 */
32
33#include <sys/cdefs.h>
34__FBSDID("$FreeBSD: stable/11/sys/dev/sfxge/common/siena_vpd.c 330897 2018-03-14 03:19:51Z eadler $");
35
36#include "efx.h"
37#include "efx_impl.h"
38
39#if EFSYS_OPT_VPD
40
41#if EFSYS_OPT_SIENA
42
43static	__checkReturn			efx_rc_t
44siena_vpd_get_static(
45	__in				efx_nic_t *enp,
46	__in				uint32_t partn,
47	__deref_out_bcount_opt(*sizep)	caddr_t *svpdp,
48	__out				size_t *sizep)
49{
50	siena_mc_static_config_hdr_t *scfg;
51	caddr_t svpd;
52	size_t size;
53	uint8_t cksum;
54	unsigned int vpd_offset;
55	unsigned int vpd_length;
56	unsigned int hdr_length;
57	unsigned int pos;
58	unsigned int region;
59	efx_rc_t rc;
60
61	EFSYS_ASSERT(partn == MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT0 ||
62		    partn == MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT1);
63
64	/* Allocate sufficient memory for the entire static cfg area */
65	if ((rc = siena_nvram_partn_size(enp, partn, &size)) != 0)
66		goto fail1;
67
68	EFSYS_KMEM_ALLOC(enp->en_esip, size, scfg);
69	if (scfg == NULL) {
70		rc = ENOMEM;
71		goto fail2;
72	}
73
74	if ((rc = siena_nvram_partn_read(enp, partn, 0,
75	    (caddr_t)scfg, SIENA_NVRAM_CHUNK)) != 0)
76		goto fail3;
77
78	/* Verify the magic number */
79	if (EFX_DWORD_FIELD(scfg->magic, EFX_DWORD_0) !=
80	    SIENA_MC_STATIC_CONFIG_MAGIC) {
81		rc = EINVAL;
82		goto fail4;
83	}
84
85	/* All future versions of the structure must be backwards compatible */
86	EFX_STATIC_ASSERT(SIENA_MC_STATIC_CONFIG_VERSION == 0);
87
88	hdr_length = EFX_WORD_FIELD(scfg->length, EFX_WORD_0);
89	vpd_offset = EFX_DWORD_FIELD(scfg->static_vpd_offset, EFX_DWORD_0);
90	vpd_length = EFX_DWORD_FIELD(scfg->static_vpd_length, EFX_DWORD_0);
91
92	/* Verify the hdr doesn't overflow the sector size */
93	if (hdr_length > size || vpd_offset > size || vpd_length > size ||
94	    vpd_length + vpd_offset > size) {
95		rc = EINVAL;
96		goto fail5;
97	}
98
99	/* Read the remainder of scfg + static vpd */
100	region = vpd_offset + vpd_length;
101	if (region > SIENA_NVRAM_CHUNK) {
102		if ((rc = siena_nvram_partn_read(enp, partn, SIENA_NVRAM_CHUNK,
103		    (caddr_t)scfg + SIENA_NVRAM_CHUNK,
104		    region - SIENA_NVRAM_CHUNK)) != 0)
105			goto fail6;
106	}
107
108	/* Verify checksum */
109	cksum = 0;
110	for (pos = 0; pos < hdr_length; pos++)
111		cksum += ((uint8_t *)scfg)[pos];
112	if (cksum != 0) {
113		rc = EINVAL;
114		goto fail7;
115	}
116
117	if (vpd_length == 0)
118		svpd = NULL;
119	else {
120		/* Copy the vpd data out */
121		EFSYS_KMEM_ALLOC(enp->en_esip, vpd_length, svpd);
122		if (svpd == NULL) {
123			rc = ENOMEM;
124			goto fail8;
125		}
126		memcpy(svpd, (caddr_t)scfg + vpd_offset, vpd_length);
127	}
128
129	EFSYS_KMEM_FREE(enp->en_esip, size, scfg);
130
131	*svpdp = svpd;
132	*sizep = vpd_length;
133
134	return (0);
135
136fail8:
137	EFSYS_PROBE(fail8);
138fail7:
139	EFSYS_PROBE(fail7);
140fail6:
141	EFSYS_PROBE(fail6);
142fail5:
143	EFSYS_PROBE(fail5);
144fail4:
145	EFSYS_PROBE(fail4);
146fail3:
147	EFSYS_PROBE(fail3);
148
149	EFSYS_KMEM_FREE(enp->en_esip, size, scfg);
150
151fail2:
152	EFSYS_PROBE(fail2);
153fail1:
154	EFSYS_PROBE1(fail1, efx_rc_t, rc);
155
156	return (rc);
157}
158
159	__checkReturn		efx_rc_t
160siena_vpd_init(
161	__in			efx_nic_t *enp)
162{
163	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
164	caddr_t svpd = NULL;
165	unsigned int partn;
166	size_t size = 0;
167	efx_rc_t rc;
168
169	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
170
171	partn = (emip->emi_port == 1)
172		? MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT0
173		: MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT1;
174
175	/*
176	 * We need the static VPD sector to present a unified static+dynamic
177	 * VPD, that is, basically on every read, write, verify cycle. Since
178	 * it should *never* change we can just cache it here.
179	 */
180	if ((rc = siena_vpd_get_static(enp, partn, &svpd, &size)) != 0)
181		goto fail1;
182
183	if (svpd != NULL && size > 0) {
184		if ((rc = efx_vpd_hunk_verify(svpd, size, NULL)) != 0)
185			goto fail2;
186	}
187
188	enp->en_u.siena.enu_svpd = svpd;
189	enp->en_u.siena.enu_svpd_length = size;
190
191	return (0);
192
193fail2:
194	EFSYS_PROBE(fail2);
195
196	EFSYS_KMEM_FREE(enp->en_esip, size, svpd);
197fail1:
198	EFSYS_PROBE1(fail1, efx_rc_t, rc);
199
200	return (rc);
201}
202
203	__checkReturn		efx_rc_t
204siena_vpd_size(
205	__in			efx_nic_t *enp,
206	__out			size_t *sizep)
207{
208	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
209	uint32_t partn;
210	efx_rc_t rc;
211
212	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
213
214	/*
215	 * This function returns the total size the user should allocate
216	 * for all VPD operations. We've already cached the static vpd,
217	 * so we just need to return an upper bound on the dynamic vpd.
218	 * Since the dynamic_config structure can change under our feet,
219	 * (as version numbers are inserted), just be safe and return the
220	 * total size of the dynamic_config *sector*
221	 */
222	partn = (emip->emi_port == 1)
223		? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0
224		: MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1;
225
226	if ((rc = siena_nvram_partn_size(enp, partn, sizep)) != 0)
227		goto fail1;
228
229	return (0);
230
231fail1:
232	EFSYS_PROBE1(fail1, efx_rc_t, rc);
233
234	return (rc);
235}
236
237	__checkReturn		efx_rc_t
238siena_vpd_read(
239	__in			efx_nic_t *enp,
240	__out_bcount(size)	caddr_t data,
241	__in			size_t size)
242{
243	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
244	siena_mc_dynamic_config_hdr_t *dcfg = NULL;
245	unsigned int vpd_length;
246	unsigned int vpd_offset;
247	unsigned int dcfg_partn;
248	size_t dcfg_size;
249	efx_rc_t rc;
250
251	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
252
253	dcfg_partn = (emip->emi_port == 1)
254		? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0
255		: MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1;
256
257	if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn,
258	    B_TRUE, &dcfg, &dcfg_size)) != 0)
259		goto fail1;
260
261	vpd_length = EFX_DWORD_FIELD(dcfg->dynamic_vpd_length, EFX_DWORD_0);
262	vpd_offset = EFX_DWORD_FIELD(dcfg->dynamic_vpd_offset, EFX_DWORD_0);
263
264	if (vpd_length > size) {
265		rc = EFAULT;	/* Invalid dcfg: header bigger than sector */
266		goto fail2;
267	}
268
269	EFSYS_ASSERT3U(vpd_length, <=, size);
270	memcpy(data, (caddr_t)dcfg + vpd_offset, vpd_length);
271
272	/* Pad data with all-1s, consistent with update operations */
273	memset(data + vpd_length, 0xff, size - vpd_length);
274
275	EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg);
276
277	return (0);
278
279fail2:
280	EFSYS_PROBE(fail2);
281
282	EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg);
283fail1:
284	EFSYS_PROBE1(fail1, efx_rc_t, rc);
285
286	return (rc);
287}
288
289	__checkReturn		efx_rc_t
290siena_vpd_verify(
291	__in			efx_nic_t *enp,
292	__in_bcount(size)	caddr_t data,
293	__in			size_t size)
294{
295	efx_vpd_tag_t stag;
296	efx_vpd_tag_t dtag;
297	efx_vpd_keyword_t skey;
298	efx_vpd_keyword_t dkey;
299	unsigned int scont;
300	unsigned int dcont;
301
302	efx_rc_t rc;
303
304	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
305
306	/*
307	 * Strictly you could take the view that dynamic vpd is optional.
308	 * Instead, to conform more closely to the read/verify/reinit()
309	 * paradigm, we require dynamic vpd. siena_vpd_reinit() will
310	 * reinitialize it as required.
311	 */
312	if ((rc = efx_vpd_hunk_verify(data, size, NULL)) != 0)
313		goto fail1;
314
315	/*
316	 * Verify that there is no duplication between the static and
317	 * dynamic cfg sectors.
318	 */
319	if (enp->en_u.siena.enu_svpd_length == 0)
320		goto done;
321
322	dcont = 0;
323	_NOTE(CONSTANTCONDITION)
324	while (1) {
325		if ((rc = efx_vpd_hunk_next(data, size, &dtag,
326		    &dkey, NULL, NULL, &dcont)) != 0)
327			goto fail2;
328		if (dcont == 0)
329			break;
330
331		/*
332		 * Skip the RV keyword. It should be present in both the static
333		 * and dynamic cfg sectors.
334		 */
335		if (dtag == EFX_VPD_RO && dkey == EFX_VPD_KEYWORD('R', 'V'))
336			continue;
337
338		scont = 0;
339		_NOTE(CONSTANTCONDITION)
340		while (1) {
341			if ((rc = efx_vpd_hunk_next(
342			    enp->en_u.siena.enu_svpd,
343			    enp->en_u.siena.enu_svpd_length, &stag, &skey,
344			    NULL, NULL, &scont)) != 0)
345				goto fail3;
346			if (scont == 0)
347				break;
348
349			if (stag == dtag && skey == dkey) {
350				rc = EEXIST;
351				goto fail4;
352			}
353		}
354	}
355
356done:
357	return (0);
358
359fail4:
360	EFSYS_PROBE(fail4);
361fail3:
362	EFSYS_PROBE(fail3);
363fail2:
364	EFSYS_PROBE(fail2);
365fail1:
366	EFSYS_PROBE1(fail1, efx_rc_t, rc);
367
368	return (rc);
369}
370
371	__checkReturn		efx_rc_t
372siena_vpd_reinit(
373	__in			efx_nic_t *enp,
374	__in_bcount(size)	caddr_t data,
375	__in			size_t size)
376{
377	boolean_t wantpid;
378	efx_rc_t rc;
379
380	/*
381	 * Only create a PID if the dynamic cfg doesn't have one
382	 */
383	if (enp->en_u.siena.enu_svpd_length == 0)
384		wantpid = B_TRUE;
385	else {
386		unsigned int offset;
387		uint8_t length;
388
389		rc = efx_vpd_hunk_get(enp->en_u.siena.enu_svpd,
390				    enp->en_u.siena.enu_svpd_length,
391				    EFX_VPD_ID, 0, &offset, &length);
392		if (rc == 0)
393			wantpid = B_FALSE;
394		else if (rc == ENOENT)
395			wantpid = B_TRUE;
396		else
397			goto fail1;
398	}
399
400	if ((rc = efx_vpd_hunk_reinit(data, size, wantpid)) != 0)
401		goto fail2;
402
403	return (0);
404
405fail2:
406	EFSYS_PROBE(fail2);
407fail1:
408	EFSYS_PROBE1(fail1, efx_rc_t, rc);
409
410	return (rc);
411}
412
413	__checkReturn		efx_rc_t
414siena_vpd_get(
415	__in			efx_nic_t *enp,
416	__in_bcount(size)	caddr_t data,
417	__in			size_t size,
418	__inout			efx_vpd_value_t *evvp)
419{
420	unsigned int offset;
421	uint8_t length;
422	efx_rc_t rc;
423
424	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
425
426	/* Attempt to satisfy the request from svpd first */
427	if (enp->en_u.siena.enu_svpd_length > 0) {
428		if ((rc = efx_vpd_hunk_get(enp->en_u.siena.enu_svpd,
429		    enp->en_u.siena.enu_svpd_length, evvp->evv_tag,
430		    evvp->evv_keyword, &offset, &length)) == 0) {
431			evvp->evv_length = length;
432			memcpy(evvp->evv_value,
433			    enp->en_u.siena.enu_svpd + offset, length);
434			return (0);
435		} else if (rc != ENOENT)
436			goto fail1;
437	}
438
439	/* And then from the provided data buffer */
440	if ((rc = efx_vpd_hunk_get(data, size, evvp->evv_tag,
441	    evvp->evv_keyword, &offset, &length)) != 0) {
442		if (rc == ENOENT)
443			return (rc);
444
445		goto fail2;
446	}
447
448	evvp->evv_length = length;
449	memcpy(evvp->evv_value, data + offset, length);
450
451	return (0);
452
453fail2:
454	EFSYS_PROBE(fail2);
455fail1:
456	EFSYS_PROBE1(fail1, efx_rc_t, rc);
457
458	return (rc);
459}
460
461	__checkReturn		efx_rc_t
462siena_vpd_set(
463	__in			efx_nic_t *enp,
464	__in_bcount(size)	caddr_t data,
465	__in			size_t size,
466	__in			efx_vpd_value_t *evvp)
467{
468	efx_rc_t rc;
469
470	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
471
472	/* If the provided (tag,keyword) exists in svpd, then it is readonly */
473	if (enp->en_u.siena.enu_svpd_length > 0) {
474		unsigned int offset;
475		uint8_t length;
476
477		if ((rc = efx_vpd_hunk_get(enp->en_u.siena.enu_svpd,
478		    enp->en_u.siena.enu_svpd_length, evvp->evv_tag,
479		    evvp->evv_keyword, &offset, &length)) == 0) {
480			rc = EACCES;
481			goto fail1;
482		}
483	}
484
485	if ((rc = efx_vpd_hunk_set(data, size, evvp)) != 0)
486		goto fail2;
487
488	return (0);
489
490fail2:
491	EFSYS_PROBE(fail2);
492fail1:
493	EFSYS_PROBE1(fail1, efx_rc_t, rc);
494
495	return (rc);
496}
497
498	__checkReturn		efx_rc_t
499siena_vpd_next(
500	__in			efx_nic_t *enp,
501	__in_bcount(size)	caddr_t data,
502	__in			size_t size,
503	__out			efx_vpd_value_t *evvp,
504	__inout			unsigned int *contp)
505{
506	_NOTE(ARGUNUSED(enp, data, size, evvp, contp))
507
508	return (ENOTSUP);
509}
510
511	__checkReturn		efx_rc_t
512siena_vpd_write(
513	__in			efx_nic_t *enp,
514	__in_bcount(size)	caddr_t data,
515	__in			size_t size)
516{
517	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
518	siena_mc_dynamic_config_hdr_t *dcfg = NULL;
519	unsigned int vpd_offset;
520	unsigned int dcfg_partn;
521	unsigned int hdr_length;
522	unsigned int pos;
523	uint8_t cksum;
524	size_t partn_size, dcfg_size;
525	size_t vpd_length;
526	efx_rc_t rc;
527
528	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
529
530	/* Determine total length of all tags */
531	if ((rc = efx_vpd_hunk_length(data, size, &vpd_length)) != 0)
532		goto fail1;
533
534	/* Lock dynamic config sector for write, and read structure only */
535	dcfg_partn = (emip->emi_port == 1)
536		? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0
537		: MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1;
538
539	if ((rc = siena_nvram_partn_size(enp, dcfg_partn, &partn_size)) != 0)
540		goto fail2;
541
542	if ((rc = siena_nvram_partn_lock(enp, dcfg_partn)) != 0)
543		goto fail3;
544
545	if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn,
546	    B_FALSE, &dcfg, &dcfg_size)) != 0)
547		goto fail4;
548
549	hdr_length = EFX_WORD_FIELD(dcfg->length, EFX_WORD_0);
550
551	/* Allocated memory should have room for the new VPD */
552	if (hdr_length + vpd_length > dcfg_size) {
553		rc = ENOSPC;
554		goto fail5;
555	}
556
557	/* Copy in new vpd and update header */
558	vpd_offset = dcfg_size - vpd_length;
559	EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_offset, EFX_DWORD_0, vpd_offset);
560	memcpy((caddr_t)dcfg + vpd_offset, data, vpd_length);
561	EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_length, EFX_DWORD_0, vpd_length);
562
563	/* Update the checksum */
564	cksum = 0;
565	for (pos = 0; pos < hdr_length; pos++)
566		cksum += ((uint8_t *)dcfg)[pos];
567	dcfg->csum.eb_u8[0] -= cksum;
568
569	/* Erase and write the new sector */
570	if ((rc = siena_nvram_partn_erase(enp, dcfg_partn, 0, partn_size)) != 0)
571		goto fail6;
572
573	/* Write out the new structure to nvram */
574	if ((rc = siena_nvram_partn_write(enp, dcfg_partn, 0, (caddr_t)dcfg,
575	    vpd_offset + vpd_length)) != 0)
576		goto fail7;
577
578	EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg);
579
580	siena_nvram_partn_unlock(enp, dcfg_partn);
581
582	return (0);
583
584fail7:
585	EFSYS_PROBE(fail7);
586fail6:
587	EFSYS_PROBE(fail6);
588fail5:
589	EFSYS_PROBE(fail5);
590
591	EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg);
592fail4:
593	EFSYS_PROBE(fail4);
594
595	siena_nvram_partn_unlock(enp, dcfg_partn);
596fail3:
597	EFSYS_PROBE(fail3);
598fail2:
599	EFSYS_PROBE(fail2);
600fail1:
601	EFSYS_PROBE1(fail1, efx_rc_t, rc);
602
603	return (rc);
604}
605
606				void
607siena_vpd_fini(
608	__in			efx_nic_t *enp)
609{
610	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
611
612	if (enp->en_u.siena.enu_svpd_length > 0) {
613		EFSYS_KMEM_FREE(enp->en_esip, enp->en_u.siena.enu_svpd_length,
614				enp->en_u.siena.enu_svpd);
615
616		enp->en_u.siena.enu_svpd = NULL;
617		enp->en_u.siena.enu_svpd_length = 0;
618	}
619}
620
621#endif	/* EFSYS_OPT_SIENA */
622
623#endif	/* EFSYS_OPT_VPD */
624