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