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