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