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