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