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