1/******************************************************************************
2 *
3 * Name:	skvpd.c
4 * Project:	GEnesis, PCI Gigabit Ethernet Adapter
5 * Version:	$Revision: 1.1.1.1 $
6 * Date:	$Date: 2008/10/15 03:26:44 $
7 * Purpose:	Shared software to read and write VPD data
8 *
9 ******************************************************************************/
10
11/******************************************************************************
12 *
13 *	(C)Copyright 1998,1999 SysKonnect,
14 *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
15 *
16 *	This program is free software; you can redistribute it and/or modify
17 *	it under the terms of the GNU General Public License as published by
18 *	the Free Software Foundation; either version 2 of the License, or
19 *	(at your option) any later version.
20 *
21 *	The information in this file is provided "AS IS" without warranty.
22 *
23 ******************************************************************************/
24
25/******************************************************************************
26 *
27 * History:
28 *
29 *	$Log: skvpd.c,v $
30 *	Revision 1.1.1.1  2008/10/15 03:26:44  james26_jang
31 *	Initial.
32 *
33 *	Revision 1.1.1.1  2008/07/21 09:15:07  james26_jang
34 *	New UI, New QoS, New wireless driver(4.151.10.29), ipmonitor.
35 *
36 *	Revision 1.1  2008/07/17 12:42:44  james26_jang
37 *	*** empty log message ***
38 *
39 *	Revision 1.1.1.1  2007/02/15 12:11:35  jiahao
40 *	initial update
41 *
42 *	Revision 1.1.1.1  2007/01/25 12:51:56  jiahao_jhou
43 *
44 *
45 *	Revision 1.1.1.1  2003/02/03 22:37:48  mhuang
46 *	LINUX_2_4 branch snapshot from linux-mips.org CVS
47 *
48 *	Revision 1.26  2000/06/13 08:00:01  mkarl
49 *	additional cast to avoid compile problems in 64 bit environment
50 *
51 *	Revision 1.25  1999/11/22 13:39:32  cgoos
52 *	Changed license header to GPL.
53 *
54 *	Revision 1.24  1999/03/11 14:25:49  malthoff
55 *	Replace __STDC__ with SK_KR_PROTO.
56 *
57 *	Revision 1.23  1999/01/11 15:13:11  gklug
58 *	fix: syntax error
59 *
60 *	Revision 1.22  1998/10/30 06:41:15  gklug
61 *	rmv: WARNING
62 *
63 *	Revision 1.21  1998/10/29 07:15:14  gklug
64 *	fix: Write Stream function needs verify.
65 *
66 *	Revision 1.20  1998/10/28 18:05:08  gklug
67 *	chg: no DEBUG in VpdMayWrite
68 *
69 *	Revision 1.19  1998/10/28 15:56:11  gklug
70 *	fix: Return len at end of ReadStream
71 *	fix: Write even less than 4 bytes correctly
72 *
73 *	Revision 1.18  1998/10/28 09:00:47  gklug
74 *	fix: unreferenced local vars
75 *
76 *	Revision 1.17  1998/10/28 08:25:45  gklug
77 *	fix: WARNING
78 *
79 *	Revision 1.16  1998/10/28 08:17:30  gklug
80 *	fix: typo
81 *
82 *	Revision 1.15  1998/10/28 07:50:32  gklug
83 *	fix: typo
84 *
85 *	Revision 1.14  1998/10/28 07:20:38  gklug
86 *	chg: Interface functions to use IoC as parameter as well
87 *	fix: VpdRead/WriteDWord now return SK_U32
88 *	chg: VPD_IN/OUT names conform to SK_IN/OUT
89 *	add: usage of VPD_IN/OUT8 macros
90 *	add: VpdRead/Write Stream functions to r/w a stream of data
91 *	fix: VpdTransferBlock swapped illeagal
92 *	add: VpdMayWrite
93 *
94 *	Revision 1.13  1998/10/22 10:02:37  gklug
95 *	fix: SysKonnectFileId typo
96 *
97 *	Revision 1.12  1998/10/20 10:01:01  gklug
98 *	fix: parameter to SkOsGetTime
99 *
100 *	Revision 1.11  1998/10/15 12:51:48  malthoff
101 *	Remove unrequired parameter p in vpd_setup_para().
102 *
103 *	Revision 1.10  1998/10/08 14:52:43  malthoff
104 *	Remove CvsId by SysKonnectFileId.
105 *
106 *	Revision 1.9  1998/09/16 07:33:52  malthoff
107 *	remove memcmp() by SK_MEMCMP and
108 *	memcpy() by SK_MEMCPY() to be
109 *	independant from the 'C' Standard Library.
110 *
111 *	Revision 1.8  1998/08/19 12:52:35  malthoff
112 *	compiler fix: use SK_VPD_KEY instead of S_VPD.
113 *
114 *	Revision 1.7  1998/08/19 08:14:01  gklug
115 *	fix: remove struct keyword as much as possible from the c-code (see CCC)
116 *
117 *	Revision 1.6  1998/08/18 13:03:58  gklug
118 *	SkOsGetTime now returns SK_U64
119 *
120 *	Revision 1.5  1998/08/18 08:17:29  malthoff
121 *	Ensure we issue a VPD read in vpd_read_dword().
122 *	Discard all VPD keywords other than Vx or Yx, where
123 *	x is '0..9' or 'A..Z'.
124 *
125 *	Revision 1.4  1998/07/03 14:52:19  malthoff
126 *	Add category SK_DBGCAT_FATAL to some debug macros.
127 *	bug fix: correct the keyword name check in vpd_write().
128 *
129 *	Revision 1.3  1998/06/26 11:16:53  malthoff
130 *	Correct the modified File Identifier.
131 *
132 *	Revision 1.2  1998/06/26 11:13:43  malthoff
133 *	Modify the File Identifier.
134 *
135 *	Revision 1.1  1998/06/19 14:11:08  malthoff
136 *	Created, Tests with AIX were performed successfully
137 *
138 *
139 ******************************************************************************/
140
141/*
142	Please refer skvpd.txt for infomation how to include this module
143 */
144static const char SysKonnectFileId[] =
145	"@(#)$Id: skvpd.c,v 1.1.1.1 2008/10/15 03:26:44 james26_jang Exp $ (C) SK" ;
146
147#include "h/skdrv1st.h"
148#include "h/sktypes.h"
149#include "h/skdebug.h"
150#include "h/skdrv2nd.h"
151
152/*
153 * Static functions
154 */
155#ifndef SK_KR_PROTO
156static SK_VPD_PARA	*vpd_find_para(
157	SK_AC	*pAC,
158	char		*key,
159	SK_VPD_PARA *p) ;
160#else	/* SK_KR_PROTO */
161static SK_VPD_PARA	*vpd_find_para() ;
162#endif	/* SK_KR_PROTO */
163
164/*
165 * waits for a completetion of a VPD transfer
166 * The VPD transfer must complete within SK_TICKS_PER_SEC/16
167 *
168 * returns	0:	success, transfer completes
169 *		error	exit(9) with a error message
170 */
171static int	VpdWait(
172SK_AC		*pAC,	/* Adapters context */
173SK_IOC		IoC,	/* IO Context */
174int		event)	/* event to wait for (VPD_READ / VPD_write) completion*/
175{
176	SK_U64	start_time ;
177	SK_U16	state ;
178
179	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
180		("vpd wait for %s\n",event?"Write":"Read")) ;
181	start_time = SkOsGetTime(pAC) ;
182	do {
183		if (SkOsGetTime(pAC) - start_time > SK_TICKS_PER_SEC/16) {
184			VPD_STOP(pAC,IoC) ;
185			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,
186				SK_DBGCAT_FATAL|SK_DBGCAT_ERR,
187				("ERROR:vpd wait timeout\n")) ;
188			return(1) ;
189		}
190		VPD_IN16(pAC,IoC,PCI_VPD_ADR_REG,&state) ;
191		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
192			("state = %x, event %x\n",state,event)) ;
193	} while((int)(state & PCI_VPD_FLAG) == event) ;
194
195	return(0) ;
196}
197
198
199/*
200 * Read the dword at address 'addr' from the VPD EEPROM.
201 *
202 * Needed Time:	MIN 1,3 ms	MAX 2,6 ms
203 *
204 * Note: The DWord is returned in the endianess of the machine the routine
205 *       is running on.
206 *
207 * Returns the data read.
208 */
209SK_U32		VpdReadDWord(
210SK_AC		*pAC,	/* Adapters context */
211SK_IOC		IoC,	/* IO Context */
212int		addr)	/* VPD address */
213{
214	SK_U32	Rtv ;
215
216	/* start VPD read */
217	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
218		("vpd read dword at 0x%x\n",addr)) ;
219	addr &= ~VPD_WRITE ;		/* ensure the R/W bit is set to read */
220
221	VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, (SK_U16) addr) ;
222
223	/* ignore return code here */
224	(void)VpdWait(pAC,IoC,VPD_READ) ;
225
226	/* Don't swap here, it's a data stream of bytes */
227	Rtv = 0 ;
228
229	VPD_IN32(pAC,IoC,PCI_VPD_DAT_REG,&Rtv) ;
230	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
231		("vpd read dword data = 0x%x\n",Rtv)) ;
232	return (Rtv) ;
233}
234
235/*
236	Write the dword 'data' at address 'addr' into the VPD EEPROM, and
237	verify that the data is written.
238
239 Needed Time:
240
241.				MIN		MAX
242. -------------------------------------------------------------------
243. write				1.8 ms		3.6 ms
244. internal write cyles		0.7 ms		7.0 ms
245. -------------------------------------------------------------------
246. over all program time	 	2.5 ms		10.6 ms
247. read				1.3 ms		2.6 ms
248. -------------------------------------------------------------------
249. over all 			3.8 ms		13.2 ms
250.
251
252
253 Returns	0:	success
254		1:	error,	I2C transfer does not terminate
255		2:	error,	data verify error
256
257 */
258
259/*
260 *	Read one Stream of 'len' bytes of VPD data, starting at 'addr' from
261 *	or to the I2C EEPROM.
262 *
263 * Returns number of bytes read / written.
264 */
265static int	VpdWriteStream(
266SK_AC		*pAC,	/* Adapters context */
267SK_IOC		IoC,	/* IO Context */
268char		*buf,	/* data buffer */
269int		Addr,	/* VPD start address */
270int		Len)	/* number of bytes to read / to write */
271{
272	int		i ;
273	int		j ;
274	SK_U16		AdrReg ;
275	int		Rtv ;
276	SK_U8		* pComp;	/* Compare pointer */
277	SK_U8		Data ;		/* Input Data for Compare */
278
279	/* Init Compare Pointer */
280	pComp = (SK_U8 *) buf;
281
282	for (i=0; i < Len; i ++, buf++) {
283		if ((i%sizeof(SK_U32)) == 0) {
284			/*
285			 * At the begin of each cycle read the Data Reg
286			 * So it is initialized even if only a few bytes
287			 * are written.
288			 */
289			AdrReg = (SK_U16) Addr ;
290			AdrReg &= ~VPD_WRITE ;	/* READ operation */
291
292			VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, AdrReg) ;
293
294			/* ignore return code here */
295			Rtv = VpdWait(pAC,IoC,VPD_READ) ;
296			if (Rtv != 0) {
297				return(i) ;
298			}
299		}
300
301		/* Write current Byte */
302		VPD_OUT8(pAC,IoC,PCI_VPD_DAT_REG+(i%sizeof(SK_U32)),
303				*(SK_U8*)buf) ;
304
305		if (((i%sizeof(SK_U32)) == 3) || (i == (Len - 1))) {
306			/* New Address needs to be written to VPD_ADDR reg */
307			AdrReg = (SK_U16) Addr ;
308			Addr += sizeof(SK_U32);
309			AdrReg |= VPD_WRITE ;	/* WRITE operation */
310
311			VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, AdrReg) ;
312
313			/* Wait for termination */
314			Rtv = VpdWait(pAC,IoC,VPD_WRITE) ;
315			if (Rtv != 0) {
316				SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
317					("Write Timed Out\n")) ;
318				return(i - (i%sizeof(SK_U32))) ;
319			}
320
321			/*
322			 * Now re-read to verify
323			 */
324			AdrReg &= ~VPD_WRITE ;	/* READ operation */
325
326			VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, AdrReg) ;
327
328			/* Wait for termination */
329			Rtv = VpdWait(pAC,IoC,VPD_READ) ;
330			if (Rtv != 0) {
331				SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
332					("Verify Timed Out\n")) ;
333				return(i - (i%sizeof(SK_U32))) ;
334			}
335
336			for (j = 0; j <= (int) (i%sizeof(SK_U32));
337				j ++, pComp ++ ) {
338				VPD_IN8(pAC,IoC,PCI_VPD_DAT_REG+j, &Data) ;
339				if (Data != *pComp) {
340					/* Verify Error */
341					SK_DBG_MSG(pAC,SK_DBGMOD_VPD,
342						SK_DBGCAT_ERR,
343						("WriteStream Verify Error\n"));
344					return(i - (i%sizeof(SK_U32)) + j);
345				}
346			}
347
348		}
349	}
350
351	return(Len);
352}
353
354
355/*
356 *	Read one Stream of 'len' bytes of VPD data, starting at 'addr' from
357 *	or to the I2C EEPROM.
358 *
359 * Returns number of bytes read / written.
360 */
361static int	VpdReadStream(
362SK_AC		*pAC,	/* Adapters context */
363SK_IOC		IoC,	/* IO Context */
364char		*buf,	/* data buffer */
365int		Addr,	/* VPD start address */
366int		Len)	/* number of bytes to read / to write */
367{
368	int		i ;
369	SK_U16		AdrReg ;
370	int		Rtv ;
371
372	for (i=0; i < Len; i ++, buf++) {
373		if ((i%sizeof(SK_U32)) == 0) {
374			/* New Address needs to be written to VPD_ADDR reg */
375			AdrReg = (SK_U16) Addr ;
376			Addr += sizeof(SK_U32);
377			AdrReg &= ~VPD_WRITE ;	/* READ operation */
378
379			VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, AdrReg) ;
380
381			/* ignore return code here */
382			Rtv = VpdWait(pAC,IoC,VPD_READ) ;
383			if (Rtv != 0) {
384				return(i) ;
385			}
386
387		}
388		VPD_IN8(pAC,IoC,PCI_VPD_DAT_REG+(i%sizeof(SK_U32)),
389			(SK_U8 *)buf) ;
390	}
391
392	return(Len) ;
393}
394
395/*
396 *	Read ore wirtes 'len' bytes of VPD data, starting at 'addr' from
397 *	or to the I2C EEPROM.
398 *
399 * Returns number of bytes read / written.
400 */
401static int	VpdTransferBlock(
402SK_AC		*pAC,	/* Adapters context */
403SK_IOC		IoC,	/* IO Context */
404char		*buf,	/* data buffer */
405int		addr,	/* VPD start address */
406int		len,	/* number of bytes to read / to write */
407int		dir)	/* transfer direction may be VPD_READ or VPD_WRITE */
408{
409	int		Rtv ;	/* Return value */
410	int		vpd_rom_size ;
411	SK_U32		our_reg2 ;
412
413	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
414		("vpd %s block, addr = 0x%x, len = %d\n",
415		dir?"write":"read",addr,len)) ;
416
417	if (len == 0)
418		return (0) ;
419
420	VPD_IN32(pAC,IoC,PCI_OUR_REG_2,&our_reg2) ;
421	vpd_rom_size = 256 << ((our_reg2 & PCI_VPD_ROM_SZ) >> 14);
422	if (addr > vpd_rom_size - 4) {
423		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR|SK_DBGCAT_FATAL,
424			("Address error: 0x%x, exp. < 0x%x\n",
425			addr, vpd_rom_size - 4)) ;
426		return (0) ;
427	}
428	if (addr + len > vpd_rom_size) {
429		len = vpd_rom_size - addr ;
430		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
431			("Warning: len was cut to %d\n",len)) ;
432	}
433
434	if (dir == VPD_READ) {
435		Rtv = VpdReadStream(pAC, IoC, buf, addr, len);
436	} else {
437		Rtv = VpdWriteStream(pAC, IoC, buf, addr, len);
438	}
439
440	return (Rtv) ;
441}
442
443#ifdef SKDIAG
444
445/*
446 *	Read 'len' bytes of VPD data, starting at 'addr'.
447 *
448 * Returns number of bytes read.
449 */
450int		VpdReadBlock(
451SK_AC		*pAC,	/* pAC pointer */
452SK_IOC		IoC,	/* IO Context */
453char		*buf,	/* buffer were the data should be stored */
454int		addr,	/* start reading at the VPD address */
455int		len)	/* number of bytes to read */
456{
457	return (VpdTransferBlock(pAC, IoC, buf, addr, len, VPD_READ)) ;
458}
459
460/*
461 *	Write 'len' bytes of *but to the VPD EEPROM, starting at 'addr'.
462 *
463 * Returns number of bytes writes.
464 */
465int		VpdWriteBlock(
466SK_AC		*pAC,	/* pAC pointer */
467SK_IOC		IoC,	/* IO Context */
468char		*buf,	/* buffer, holds the data to write */
469int		addr,	/* start writing at the VPD address */
470int		len)	/* number of bytes to write */
471{
472	return (VpdTransferBlock(pAC, IoC, buf, addr, len, VPD_WRITE)) ;
473}
474#endif	/* SKDIAG */
475
476/*
477 * (re)initialize the VPD buffer
478 *
479 * Reads the VPD data from the EEPROM into the VPD buffer.
480 * Get the remaining read only and read / write space.
481 *
482 * return	0:	success
483 *		1:	fatal VPD error
484 */
485static int	VpdInit(
486SK_AC		*pAC,	/* Adapters context */
487SK_IOC		IoC)	/* IO Context */
488{
489	SK_VPD_PARA *r, rp ;	/* RW or RV */
490	int		i ;
491	unsigned char	x ;
492
493	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_INIT,("VpdInit .. ")) ;
494	/* read the VPD data into the VPD buffer */
495	if (VpdTransferBlock(pAC,IoC,pAC->vpd.vpd_buf,0,VPD_SIZE,VPD_READ)
496		!= VPD_SIZE) {
497
498		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
499			("Block Read Error\n")) ;
500		return(1) ;
501	}
502
503	/* find the end tag of the RO area */
504	if (!(r = vpd_find_para(pAC,VPD_RV,&rp))) {
505		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
506			("Encoding Error: RV Tag not found\n")) ;
507		return (1) ;
508	}
509	if (r->p_val + r->p_len > pAC->vpd.vpd_buf + VPD_SIZE/2) {
510		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
511			("Encoding Error: Invalid VPD struct size\n")) ;
512		return (1) ;
513	}
514	pAC->vpd.v.vpd_free_ro = r->p_len - 1 ;
515
516	/* test the checksum */
517	for (i = 0, x = 0; (unsigned)i<=(unsigned)VPD_SIZE/2 - r->p_len; i++) {
518		x += pAC->vpd.vpd_buf[i] ;
519	}
520	if (x != 0) {
521		/* checksum error */
522		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
523			("VPD Checksum Error\n")) ;
524		return (1) ;
525	}
526
527	/* find and check the end tag of the RW area */
528	if (!(r = vpd_find_para(pAC,VPD_RW,&rp))) {
529		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
530			("Encoding Error: RV Tag not found\n")) ;
531		return (1) ;
532	}
533	if (r->p_val < pAC->vpd.vpd_buf + VPD_SIZE/2) {
534		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
535			("Encoding Error: Invalid VPD struct size\n")) ;
536		return (1) ;
537	}
538	pAC->vpd.v.vpd_free_rw = r->p_len ;
539
540	/* everything seems to be ok */
541	pAC->vpd.v.vpd_status |= VPD_VALID ;
542	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_INIT,
543		("done. Free RO = %d, Free RW = %d\n",
544		pAC->vpd.v.vpd_free_ro, pAC->vpd.v.vpd_free_rw)) ;
545
546	return(0) ;
547}
548
549/*
550 *	find the Keyword 'key' in the VPD buffer and fills the
551 *	parameter sturct 'p' with it's values
552 *
553 * returns	*p	success
554 *		0:	parameter was not found or VPD encoding error
555 */
556static SK_VPD_PARA *vpd_find_para(
557SK_AC *pAC,	/* common data base */
558char *key,		/* keyword to find (e.g. "MN") */
559SK_VPD_PARA *p)	/* parameter description struct */
560{
561	char *v	;	/* points to vpd buffer */
562	int max ;	/* Maximum Number of Iterations */
563
564	v = pAC->vpd.vpd_buf ;
565	max = 128 ;
566
567	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
568		("vpd find para %s .. ",key)) ;
569
570	/* check mandatory resource type ID string (Product Name) */
571	if (*v != (char) RES_ID) {
572		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
573			("Error: 0x%x missing\n",RES_ID)) ;
574		return (0) ;
575	}
576
577	if (strcmp(key,VPD_NAME) == 0) {
578		p->p_len = VPD_GET_RES_LEN(v) ;
579		p->p_val = VPD_GET_VAL(v) ;
580		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
581			("found, len = %d\n",p->p_len)) ;
582		return(p) ;
583	}
584
585	v += 3 + VPD_GET_RES_LEN(v) + 3 ;
586	for ( ; ; ) {
587		if (SK_MEMCMP(key,v,2) == 0) {
588			p->p_len = VPD_GET_VPD_LEN(v) ;
589			p->p_val = VPD_GET_VAL(v) ;
590			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
591				("found, len = %d\n",p->p_len)) ;
592			return (p) ;
593		}
594
595		/* exit when reaching the "RW" Tag or the maximum of itera. */
596		max-- ;
597		if (SK_MEMCMP(VPD_RW,v,2) == 0 || max == 0) {
598			break ;
599		}
600
601		if (SK_MEMCMP(VPD_RV,v,2) == 0) {
602			v += 3 + VPD_GET_VPD_LEN(v) + 3 ;	/* skip VPD-W */
603		} else {
604			v += 3 + VPD_GET_VPD_LEN(v) ;
605		}
606		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
607			("scanning '%c%c' len = %d\n",v[0],v[1],v[2])) ;
608	}
609
610#ifdef DEBUG
611	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,("not found\n")) ;
612	if (max == 0) {
613		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
614			("Key/Len Encoding error\n")) ;
615	}
616#endif
617	return (0) ;
618}
619
620/*
621 *	Move 'n' bytes. Begin with the last byte if 'n' is > 0,
622 *	Start with the last byte if n is < 0.
623 *
624 * returns nothing
625 */
626static void vpd_move_para(
627char *start,		/* start of memory block */
628char *end,		/* end of memory block to move */
629int n)			/* number of bytes the memory block has to be moved */
630{
631	char *p ;
632	int i ;		/* number of byte copied */
633
634	if (n == 0)
635		return ;
636
637	i = (int) (end - start + 1) ;
638	if (n < 0) {
639		p = start + n ;
640		while (i != 0) {
641			*p++ = *start++ ;
642			i-- ;
643		}
644	} else {
645		p = end + n ;
646		while (i != 0) {
647			*p-- = *end-- ;
648			i-- ;
649		}
650	}
651}
652
653/*
654 *	setup the VPD keyword 'key' at 'ip'.
655 *
656 * returns nothing
657 */
658static void vpd_insert_key(
659char *key,		/* keyword to insert */
660char *buf,		/* buffer with the keyword value */
661int len,		/* length of the value string */
662char *ip)		/* inseration point */
663{
664	SK_VPD_KEY *p ;
665
666	p = (SK_VPD_KEY *) ip ;
667	p->p_key[0] = key[0] ;
668	p->p_key[1] = key[1] ;
669	p->p_len = (unsigned char) len ;
670	SK_MEMCPY(&p->p_val,buf,len) ;
671}
672
673/*
674 *	Setup the VPD end tag "RV" / "RW".
675 *	Also correct the remaining space variables vpd_free_ro / vpd_free_rw.
676 *
677 * returns	0:	success
678 *		1:	encoding error
679 */
680static int vpd_mod_endtag(
681SK_AC *pAC,	/* common data base */
682char *etp)		/* end pointer input position */
683{
684	SK_VPD_KEY *p ;
685	unsigned char	x ;
686	int	i ;
687
688	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
689		("vpd modify endtag at 0x%x = '%c%c'\n",etp,etp[0],etp[1])) ;
690
691	p = (SK_VPD_KEY *) etp ;
692
693	if (p->p_key[0] != 'R' || (p->p_key[1] != 'V' && p->p_key[1] != 'W')) {
694		/* something wrong here, encoding error */
695		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
696			("Encoding Error: invalid end tag\n")) ;
697		return(1) ;
698	}
699	if (etp > pAC->vpd.vpd_buf + VPD_SIZE/2) {
700		/* create "RW" tag */
701		p->p_len = (unsigned char)(pAC->vpd.vpd_buf+VPD_SIZE-etp-3-1) ;
702		pAC->vpd.v.vpd_free_rw = (int) p->p_len ;
703		i = pAC->vpd.v.vpd_free_rw ;
704		etp += 3 ;
705	} else {
706		/* create "RV" tag */
707		p->p_len = (unsigned char)(pAC->vpd.vpd_buf+VPD_SIZE/2-etp-3) ;
708		pAC->vpd.v.vpd_free_ro = (int) p->p_len - 1 ;
709
710		/* setup checksum */
711		for (i = 0, x = 0; i < VPD_SIZE/2 - p->p_len; i++) {
712			x += pAC->vpd.vpd_buf[i] ;
713		}
714		p->p_val = (char) 0 - x ;
715		i = pAC->vpd.v.vpd_free_ro ;
716		etp += 4 ;
717	}
718	while (i) {
719		*etp++ = 0x00 ;
720		i-- ;
721	}
722
723	return (0) ;
724}
725
726/*
727 *	Insert a VPD keyword into the VPD buffer.
728 *
729 *	The keyword 'key' is inserted at the position 'ip' in the
730 *	VPD buffer.
731 *	The keywords behind the input position will
732 *	be moved. The VPD end tag "RV" or "RW" is generated again.
733 *
734 * returns	0:	success
735 *		2:	value string was cut
736 *		4:	VPD full, keyword was not written
737 *		6:	fatal VPD error
738 *
739 */
740int	VpdSetupPara(
741SK_AC	*pAC,		/* common data base */
742char	*key,		/* keyword to insert */
743char	*buf,		/* buffer with the keyword value */
744int	len,		/* length of the keyword value */
745int	type,		/* VPD_RO_KEY or VPD_RW_KEY */
746int	op)			/* operation to do: ADD_KEY or OWR_KEY */
747{
748	SK_VPD_PARA vp ;
749	char	*etp ;		/* end tag position */
750	int	free ;		/* remaining space in selected area */
751	char	*ip ;		/* input position inside the VPD buffer */
752	int	rtv ;		/* return code */
753	int	head ;		/* additional haeder bytes to move */
754	int	found ;		/* additinoal bytes if the keyword was found */
755
756	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
757		("vpd setup para key = %s, val = %s\n",key,buf)) ;
758
759	rtv = 0 ;
760	ip = 0 ;
761	if (type == VPD_RW_KEY) {
762		/* end tag is "RW" */
763		free = pAC->vpd.v.vpd_free_rw ;
764		etp = pAC->vpd.vpd_buf + (VPD_SIZE - free - 1 - 3) ;
765	} else {
766		/* end tag is "RV" */
767		free = pAC->vpd.v.vpd_free_ro ;
768		etp = pAC->vpd.vpd_buf + (VPD_SIZE/2 - free - 4) ;
769	}
770	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
771		("Free RO = %d, Free RW = %d\n",
772		pAC->vpd.v.vpd_free_ro, pAC->vpd.v.vpd_free_rw)) ;
773
774	head = 0 ;
775	found = 0 ;
776	if (op == OWR_KEY) {
777		if (vpd_find_para(pAC,key,&vp)) {
778			found = 3 ;
779			ip = vp.p_val - 3 ;
780			free += vp.p_len + 3 ;
781			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
782				("Overwrite Key\n")) ;
783		} else {
784			op = ADD_KEY ;
785			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
786				("Add Key\n")) ;
787		}
788	}
789	if (op == ADD_KEY) {
790		ip = etp ;
791		vp.p_len = 0 ;
792		head = 3 ;
793	}
794
795	if (len + 3 > free) {
796		if (free < 7) {
797			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
798				("VPD Buffer Overflow, keyword not written\n"));
799			return (4) ;
800		}
801		/* cut it again */
802		len = free - 3 ;
803		rtv = 2 ;
804		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
805			("VPD Buffer Full, Keyword was cut\n")) ;
806	}
807
808	vpd_move_para(ip + vp.p_len + found, etp+2, len-vp.p_len+head) ;
809	vpd_insert_key(key, buf, len, ip) ;
810	if (vpd_mod_endtag(pAC, etp + len - vp.p_len + head)) {
811		pAC->vpd.v.vpd_status &= ~VPD_VALID ;
812		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
813			("VPD Encoding Error\n")) ;
814		return(6) ;
815	}
816
817	return (rtv) ;
818}
819
820
821/*
822 *	Read the contents of the VPD EEPROM and copy it to the
823 *	VPD buffer if not already done.
824 *
825 * return:	A pointer to the vpd_status structure. The structure contain
826 *		this fields.
827 */
828SK_VPD_STATUS	*VpdStat(
829SK_AC		*pAC,	/* Adapters context */
830SK_IOC		IoC)	/* IO Context */
831{
832	if (!(pAC->vpd.v.vpd_status & VPD_VALID)) {
833		(void)VpdInit(pAC,IoC) ;
834	}
835	return(&pAC->vpd.v) ;
836}
837
838
839/*
840 *	Read the contents of the VPD EEPROM and copy it to the VPD
841 *	buffer if not already done.
842 *	Scan the VPD buffer for VPD keywords and create the VPD
843 *	keyword list by copying the keywords to 'buf', all after
844 *	each other and terminated with a '\0'.
845 *
846 * Exceptions:	o The Resource Type ID String (product name) is called "Name"
847 *		o The VPD end tags 'RV' and 'RW' are not listed
848 *
849 *	The number of copied keywords is counted in 'elements'.
850 *
851 * returns	0:	success
852 *		2:	buffer overfull, one or more keywords are missing
853 *		6:	fatal VPD error
854 *
855 *	example values after returning:
856 *
857 *		buf =	"Name\0PN\0EC\0MN\0SN\0CP\0VF\0VL\0YA\0"
858 *		*len =		30
859 *		*elements =	 9
860 */
861int		VpdKeys(
862SK_AC		*pAC,		/* common data base */
863SK_IOC		IoC,		/* IO Context */
864char		*buf,		/* buffer where to copy the keywords */
865int		*len,		/* buffer length */
866int		*elements)	/* number of keywords returned */
867{
868	char *v ;
869	int n ;
870
871	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_RX,("list vpd keys .. ")) ;
872	*elements = 0 ;
873	if (!(pAC->vpd.v.vpd_status & VPD_VALID)) {
874		if (VpdInit(pAC,IoC) != 0 ) {
875			*len = 0 ;
876			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
877				("VPD Init Error, terminated\n")) ;
878			return(6) ;
879		}
880	}
881
882	if ((signed)strlen(VPD_NAME) + 1 <= *len) {
883		v = pAC->vpd.vpd_buf ;
884		strcpy(buf,VPD_NAME) ;
885		n = strlen(VPD_NAME) + 1 ;
886		buf += n ;
887		*elements = 1 ;
888		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_RX,
889			("'%c%c' ",v[0],v[1])) ;
890	} else {
891		*len = 0 ;
892		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
893			("buffer overflow\n")) ;
894		return(2) ;
895	}
896
897	v += 3 + VPD_GET_RES_LEN(v) + 3 ;
898	for ( ; ; ) {
899		/* exit when reaching the "RW" Tag */
900		if (SK_MEMCMP(VPD_RW,v,2) == 0) {
901			break ;
902		}
903
904		if (SK_MEMCMP(VPD_RV,v,2) == 0) {
905			v += 3 + VPD_GET_VPD_LEN(v) + 3 ;	/* skip VPD-W */
906			continue ;
907		}
908
909		if (n+3 <= *len) {
910			SK_MEMCPY(buf,v,2) ;
911			buf += 2 ;
912			*buf++ = '\0' ;
913			n += 3 ;
914			v += 3 + VPD_GET_VPD_LEN(v) ;
915			*elements += 1 ;
916			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_RX,
917				("'%c%c' ",v[0],v[1])) ;
918		} else {
919			*len = n ;
920			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
921				("buffer overflow\n")) ;
922			return (2) ;
923		}
924	}
925
926	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_RX,("\n")) ;
927	*len = n ;
928	return(0) ;
929}
930
931
932/*
933 *	Read the contents of the VPD EEPROM and copy it to the
934 *	VPD buffer if not already done. Search for the VPD keyword
935 *	'key' and copy its value to 'buf'. Add a terminating '\0'.
936 *	If the value does not fit into the buffer cut it after
937 *	'len' - 1 bytes.
938 *
939 * returns	0:	success
940 *		1:	keyword not found
941 *		2:	value string was cut
942 *		3:	VPD transfer timeout
943 *		6:	fatal VPD error
944 */
945int		VpdRead(
946SK_AC		*pAC,	/* common data base */
947SK_IOC		IoC,	/* IO Context */
948char		*key,	/* keyword to read (e.g. "MN") */
949char		*buf,	/* buffer where to copy the keyword value */
950int		*len)	/* buffer length */
951{
952	SK_VPD_PARA *p, vp ;
953
954	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_RX,("vpd read %s .. ",key)) ;
955	if (!(pAC->vpd.v.vpd_status & VPD_VALID)) {
956		if (VpdInit(pAC,IoC) != 0 ) {
957			*len = 0 ;
958			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
959				("vpd init error\n")) ;
960			return(6) ;
961		}
962	}
963
964	if ((p = vpd_find_para(pAC,key,&vp))) {
965		if (p->p_len > (*(unsigned *)len)-1) {
966			p->p_len = *len - 1 ;
967		}
968		SK_MEMCPY(buf,p->p_val,p->p_len) ;
969		buf[p->p_len] = '\0' ;
970		*len = p->p_len ;
971		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_RX,
972			("%c%c%c%c.., len = %d\n",
973			buf[0],buf[1],buf[2],buf[3],*len)) ;
974	} else {
975		*len = 0 ;
976		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,("not found\n")) ;
977		return (1) ;
978	}
979	return (0) ;
980}
981
982
983/*
984 *	Check whether a given key may be written
985 *
986 * returns
987 *	SK_TRUE		Yes it may be written
988 *	SK_FALSE	No it may be written
989 */
990SK_BOOL		VpdMayWrite(
991char		*key)	/* keyword to write (allowed values "Yx", "Vx") */
992{
993	if ((*key != 'Y' && *key != 'V') ||
994		key[1] < '0' || key[1] > 'Z' ||
995		(key[1] > '9' && key[1] < 'A') || strlen(key) != 2) {
996
997		return (SK_FALSE) ;
998	}
999	return (SK_TRUE) ;
1000}
1001
1002/*
1003 *	Read the contents of the VPD EEPROM and copy it to the VPD
1004 *	buffer if not already done. Insert/overwrite the keyword 'key'
1005 *	in the VPD buffer. Cut the keyword value if it does not fit
1006 *	into the VPD read / write area.
1007 *
1008 * returns	0:	success
1009 *		2:	value string was cut
1010 *		3:	VPD transfer timeout
1011 *		4:	VPD full, keyword was not written
1012 *		5:	keyword cannot be written
1013 *		6:	fatal VPD error
1014 */
1015int		VpdWrite(
1016SK_AC		*pAC,	/* common data base */
1017SK_IOC		IoC,	/* IO Context */
1018char		*key,	/* keyword to write (allowed values "Yx", "Vx") */
1019char		*buf)	/* buffer where the keyword value can be read from */
1020{
1021	int len ;			/* lenght of the keyword to write */
1022	int rtv ;			/* return code */
1023	int rtv2 ;
1024
1025	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,
1026		("vpd write %s = %s\n",key,buf)) ;
1027
1028	if ((*key != 'Y' && *key != 'V') ||
1029		key[1] < '0' || key[1] > 'Z' ||
1030		(key[1] > '9' && key[1] < 'A') || strlen(key) != 2) {
1031
1032		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
1033			("illegal key tag, keyword not written\n")) ;
1034		return (5) ;
1035	}
1036
1037	if (!(pAC->vpd.v.vpd_status & VPD_VALID)) {
1038		if (VpdInit(pAC,IoC) != 0 ) {
1039			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
1040				("vpd init error\n")) ;
1041			return(6) ;
1042		}
1043	}
1044
1045	rtv = 0 ;
1046	len = strlen(buf) ;
1047	if (len > VPD_MAX_LEN) {
1048		/* cut it */
1049		len = VPD_MAX_LEN ;
1050		rtv = 2 ;
1051		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
1052			("keyword to long, cut after %d bytes\n",VPD_MAX_LEN)) ;
1053	}
1054	if ((rtv2 = VpdSetupPara(pAC,key,buf,len,VPD_RW_KEY,OWR_KEY)) != 0) {
1055		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
1056			("vpd write error\n")) ;
1057		return(rtv2) ;
1058	}
1059
1060	return (rtv) ;
1061}
1062
1063/*
1064 *	Read the contents of the VPD EEPROM and copy it to the
1065 *	VPD buffer if not already done. Remove the VPD keyword
1066 *	'key' from the VPD buffer.
1067 *	Only the keywords in the read/write area can be deleted.
1068 *	Keywords in the read only area cannot be deleted.
1069 *
1070 * returns	0:	success, keyword was removed
1071 *		1:	keyword not found
1072 *		5:	keyword cannot be deleted
1073 *		6:	fatal VPD error
1074 */
1075int		VpdDelete(
1076SK_AC		*pAC,	/* common data base */
1077SK_IOC		IoC,	/* IO Context */
1078char		*key)	/* keyword to read (e.g. "MN") */
1079{
1080	SK_VPD_PARA *p, vp ;
1081	char *etp ;
1082
1083	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("vpd delete key %s\n",key)) ;
1084	if (!(pAC->vpd.v.vpd_status & VPD_VALID)) {
1085		if (VpdInit(pAC,IoC) != 0 ) {
1086			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
1087				("vpd init error\n")) ;
1088			return(6) ;
1089		}
1090	}
1091
1092	if ((p = vpd_find_para(pAC,key,&vp))) {
1093		if (p->p_val < pAC->vpd.vpd_buf + VPD_SIZE/2) {
1094			/* try to delete read only keyword */
1095			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
1096				("cannot delete RO keyword\n")) ;
1097			return (5) ;
1098		}
1099
1100		etp = pAC->vpd.vpd_buf + (VPD_SIZE-pAC->vpd.v.vpd_free_rw-1-3) ;
1101
1102		vpd_move_para(vp.p_val+vp.p_len, etp+2,
1103			- ((int)(vp.p_len + 3))) ;
1104		if (vpd_mod_endtag(pAC, etp - vp.p_len - 3)) {
1105			pAC->vpd.v.vpd_status &= ~VPD_VALID ;
1106			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
1107				("vpd encoding error\n")) ;
1108			return(6) ;
1109		}
1110	} else {
1111		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
1112			("keyword not found\n")) ;
1113		return (1) ;
1114	}
1115
1116	return (0) ;
1117}
1118
1119/*
1120 *	If the VPD buffer contains valid data write the VPD
1121 *	read/write area back to the VPD EEPROM.
1122 *
1123 * returns	0:	success
1124 *		3:	VPD transfer timeout
1125 */
1126int		VpdUpdate(
1127SK_AC		*pAC,	/* Adapters context */
1128SK_IOC		IoC)	/* IO Context */
1129{
1130	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("vpd update .. ")) ;
1131	if (pAC->vpd.v.vpd_status & VPD_VALID) {
1132		if (VpdTransferBlock(pAC,IoC,pAC->vpd.vpd_buf + VPD_SIZE/2,
1133			VPD_SIZE/2, VPD_SIZE/2, VPD_WRITE) != VPD_SIZE/2) {
1134
1135			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
1136				("transfer timed out\n")) ;
1137			return(3) ;
1138		}
1139	}
1140	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("done\n")) ;
1141	return (0) ;
1142}
1143
1144
1145
1146/*
1147 *	Read the contents of the VPD EEPROM and copy it to the VPD buffer
1148 *	if not already done. If the keyword "VF" is not present it will be
1149 *	created and the error log message will be stored to this keyword.
1150 *	If "VF" is not present the error log message will be stored to the
1151 *	keyword "VL". "VL" will created or overwritten if "VF" is present.
1152 *	The VPD read/write area is saved to the VPD EEPROM.
1153 *
1154 * returns nothing, errors will be ignored.
1155 */
1156void		VpdErrLog(
1157SK_AC		*pAC,	/* common data base */
1158SK_IOC		IoC,	/* IO Context */
1159char		*msg)	/* error log message */
1160{
1161	SK_VPD_PARA *v, vf ;	/* VF */
1162	int len ;
1163
1164	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,
1165		("vpd error log msg %s\n",msg)) ;
1166	if (!(pAC->vpd.v.vpd_status & VPD_VALID)) {
1167		if (VpdInit(pAC,IoC) != 0 ) {
1168			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
1169				("vpd init error\n")) ;
1170			return ;
1171		}
1172	}
1173
1174	len = strlen(msg) ;
1175	if (len > VPD_MAX_LEN) {
1176		/* cut it */
1177		len = VPD_MAX_LEN ;
1178	}
1179	if ((v = vpd_find_para(pAC,VPD_VF,&vf))) {
1180		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("overwrite VL\n")) ;
1181		(void)VpdSetupPara(pAC,VPD_VL,msg,len,VPD_RW_KEY,OWR_KEY) ;
1182	} else {
1183		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("write VF\n")) ;
1184		(void)VpdSetupPara(pAC,VPD_VF,msg,len,VPD_RW_KEY,ADD_KEY) ;
1185	}
1186
1187	(void)VpdUpdate(pAC,IoC) ;
1188}
1189
1190