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