ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[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         /* find the end tag of the RO area */
472         if (!(r = vpd_find_para(pAC, VPD_RV, &rp))) {
473                 SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
474                         ("Encoding Error: RV Tag not found\n"));
475                 return(1);
476         }
477         
478         if (r->p_val + r->p_len > pAC->vpd.vpd_buf + vpd_size/2) {
479                 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
480                         ("Encoding Error: Invalid VPD struct size\n"));
481                 return(1);
482         }
483         pAC->vpd.v.vpd_free_ro = r->p_len - 1;
484
485         /* test the checksum */
486         for (i = 0, x = 0; (unsigned)i <= (unsigned)vpd_size/2 - r->p_len; i++) {
487                 x += pAC->vpd.vpd_buf[i];
488         }
489         
490         if (x != 0) {
491                 /* checksum error */
492                 SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
493                         ("VPD Checksum Error\n"));
494                 return(1);
495         }
496
497         /* find and check the end tag of the RW area */
498         if (!(r = vpd_find_para(pAC, VPD_RW, &rp))) {
499                 SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
500                         ("Encoding Error: RV Tag not found\n"));
501                 return(1);
502         }
503         
504         if (r->p_val < pAC->vpd.vpd_buf + vpd_size/2) {
505                 SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
506                         ("Encoding Error: Invalid VPD struct size\n"));
507                 return(1);
508         }
509         pAC->vpd.v.vpd_free_rw = r->p_len;
510
511         /* everything seems to be ok */
512         if (pAC->GIni.GIChipId != 0) {
513                 pAC->vpd.v.vpd_status |= VPD_VALID;
514         }
515
516         SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_INIT,
517                 ("done. Free RO = %d, Free RW = %d\n",
518                 pAC->vpd.v.vpd_free_ro, pAC->vpd.v.vpd_free_rw));
519
520         return(0);
521 }
522
523 /*
524  *      find the Keyword 'key' in the VPD buffer and fills the
525  *      parameter struct 'p' with it's values
526  *
527  * returns      *p      success
528  *              0:      parameter was not found or VPD encoding error
529  */
530 static SK_VPD_PARA *vpd_find_para(
531 SK_AC           *pAC,   /* common data base */
532 const char      *key,   /* keyword to find (e.g. "MN") */
533 SK_VPD_PARA *p)         /* parameter description struct */
534 {
535         char *v ;       /* points to VPD buffer */
536         int max;        /* Maximum Number of Iterations */
537
538         v = pAC->vpd.vpd_buf;
539         max = 128;
540
541         SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
542                 ("VPD find para %s .. ",key));
543
544         /* check mandatory resource type ID string (Product Name) */
545         if (*v != (char)RES_ID) {
546                 SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
547                         ("Error: 0x%x missing\n", RES_ID));
548                 return(0);
549         }
550
551         if (strcmp(key, VPD_NAME) == 0) {
552                 p->p_len = VPD_GET_RES_LEN(v);
553                 p->p_val = VPD_GET_VAL(v);
554                 SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
555                         ("found, len = %d\n", p->p_len));
556                 return(p);
557         }
558
559         v += 3 + VPD_GET_RES_LEN(v) + 3;
560         for (;; ) {
561                 if (SK_MEMCMP(key,v,2) == 0) {
562                         p->p_len = VPD_GET_VPD_LEN(v);
563                         p->p_val = VPD_GET_VAL(v);
564                         SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
565                                 ("found, len = %d\n",p->p_len));
566                         return(p);
567                 }
568
569                 /* exit when reaching the "RW" Tag or the maximum of itera. */
570                 max--;
571                 if (SK_MEMCMP(VPD_RW,v,2) == 0 || max == 0) {
572                         break;
573                 }
574
575                 if (SK_MEMCMP(VPD_RV,v,2) == 0) {
576                         v += 3 + VPD_GET_VPD_LEN(v) + 3;        /* skip VPD-W */
577                 }
578                 else {
579                         v += 3 + VPD_GET_VPD_LEN(v);
580                 }
581                 SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
582                         ("scanning '%c%c' len = %d\n",v[0],v[1],v[2]));
583         }
584
585 #ifdef DEBUG
586         SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL, ("not found\n"));
587         if (max == 0) {
588                 SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
589                         ("Key/Len Encoding error\n"));
590         }
591 #endif /* DEBUG */
592         return(0);
593 }
594
595 /*
596  *      Move 'n' bytes. Begin with the last byte if 'n' is > 0,
597  *      Start with the last byte if n is < 0.
598  *
599  * returns nothing
600  */
601 static void vpd_move_para(
602 char    *start,         /* start of memory block */
603 char    *end,           /* end of memory block to move */
604 int             n)                      /* number of bytes the memory block has to be moved */
605 {
606         char *p;
607         int i;          /* number of byte copied */
608
609         if (n == 0)
610                 return;
611
612         i = (int) (end - start + 1);
613         if (n < 0) {
614                 p = start + n;
615                 while (i != 0) {
616                         *p++ = *start++;
617                         i--;
618                 }
619         }
620         else {
621                 p = end + n;
622                 while (i != 0) {
623                         *p-- = *end--;
624                         i--;
625                 }
626         }
627 }
628
629 /*
630  *      setup the VPD keyword 'key' at 'ip'.
631  *
632  * returns nothing
633  */
634 static void vpd_insert_key(
635 const char      *key,   /* keyword to insert */
636 const char      *buf,   /* buffer with the keyword value */
637 int             len,            /* length of the value string */
638 char    *ip)            /* inseration point */
639 {
640         SK_VPD_KEY *p;
641
642         p = (SK_VPD_KEY *) ip;
643         p->p_key[0] = key[0];
644         p->p_key[1] = key[1];
645         p->p_len = (unsigned char) len;
646         SK_MEMCPY(&p->p_val,buf,len);
647 }
648
649 /*
650  *      Setup the VPD end tag "RV" / "RW".
651  *      Also correct the remaining space variables vpd_free_ro / vpd_free_rw.
652  *
653  * returns      0:      success
654  *              1:      encoding error
655  */
656 static int vpd_mod_endtag(
657 SK_AC   *pAC,           /* common data base */
658 char    *etp)           /* end pointer input position */
659 {
660         SK_VPD_KEY *p;
661         unsigned char   x;
662         int     i;
663         int     vpd_size;
664
665         SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
666                 ("VPD modify endtag at 0x%x = '%c%c'\n",etp,etp[0],etp[1]));
667
668         vpd_size = pAC->vpd.vpd_size;
669
670         p = (SK_VPD_KEY *) etp;
671
672         if (p->p_key[0] != 'R' || (p->p_key[1] != 'V' && p->p_key[1] != 'W')) {
673                 /* something wrong here, encoding error */
674                 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
675                         ("Encoding Error: invalid end tag\n"));
676                 return(1);
677         }
678         if (etp > pAC->vpd.vpd_buf + vpd_size/2) {
679                 /* create "RW" tag */
680                 p->p_len = (unsigned char)(pAC->vpd.vpd_buf+vpd_size-etp-3-1);
681                 pAC->vpd.v.vpd_free_rw = (int) p->p_len;
682                 i = pAC->vpd.v.vpd_free_rw;
683                 etp += 3;
684         }
685         else {
686                 /* create "RV" tag */
687                 p->p_len = (unsigned char)(pAC->vpd.vpd_buf+vpd_size/2-etp-3);
688                 pAC->vpd.v.vpd_free_ro = (int) p->p_len - 1;
689
690                 /* setup checksum */
691                 for (i = 0, x = 0; i < vpd_size/2 - p->p_len; i++) {
692                         x += pAC->vpd.vpd_buf[i];
693                 }
694                 p->p_val = (char) 0 - x;
695                 i = pAC->vpd.v.vpd_free_ro;
696                 etp += 4;
697         }
698         while (i) {
699                 *etp++ = 0x00;
700                 i--;
701         }
702
703         return(0);
704 }
705
706 /*
707  *      Insert a VPD keyword into the VPD buffer.
708  *
709  *      The keyword 'key' is inserted at the position 'ip' in the
710  *      VPD buffer.
711  *      The keywords behind the input position will
712  *      be moved. The VPD end tag "RV" or "RW" is generated again.
713  *
714  * returns      0:      success
715  *              2:      value string was cut
716  *              4:      VPD full, keyword was not written
717  *              6:      fatal VPD error
718  *
719  */
720 int     VpdSetupPara(
721 SK_AC   *pAC,           /* common data base */
722 const char      *key,   /* keyword to insert */
723 const char      *buf,   /* buffer with the keyword value */
724 int             len,            /* length of the keyword value */
725 int             type,           /* VPD_RO_KEY or VPD_RW_KEY */
726 int             op)                     /* operation to do: ADD_KEY or OWR_KEY */
727 {
728         SK_VPD_PARA vp;
729         char    *etp;           /* end tag position */
730         int     free;           /* remaining space in selected area */
731         char    *ip;            /* input position inside the VPD buffer */
732         int     rtv;            /* return code */
733         int     head;           /* additional haeder bytes to move */
734         int     found;          /* additinoal bytes if the keyword was found */
735         int vpd_size;
736
737         SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
738                 ("VPD setup para key = %s, val = %s\n",key,buf));
739         
740         vpd_size = pAC->vpd.vpd_size;
741
742         rtv = 0;
743         ip = 0;
744         if (type == VPD_RW_KEY) {
745                 /* end tag is "RW" */
746                 free = pAC->vpd.v.vpd_free_rw;
747                 etp = pAC->vpd.vpd_buf + (vpd_size - free - 1 - 3);
748         }
749         else {
750                 /* end tag is "RV" */
751                 free = pAC->vpd.v.vpd_free_ro;
752                 etp = pAC->vpd.vpd_buf + (vpd_size/2 - free - 4);
753         }
754         SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
755                 ("Free RO = %d, Free RW = %d\n",
756                 pAC->vpd.v.vpd_free_ro, pAC->vpd.v.vpd_free_rw));
757
758         head = 0;
759         found = 0;
760         if (op == OWR_KEY) {
761                 if (vpd_find_para(pAC, key, &vp)) {
762                         found = 3;
763                         ip = vp.p_val - 3;
764                         free += vp.p_len + 3;
765                         SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
766                                 ("Overwrite Key\n"));
767                 }
768                 else {
769                         op = ADD_KEY;
770                         SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
771                                 ("Add Key\n"));
772                 }
773         }
774         if (op == ADD_KEY) {
775                 ip = etp;
776                 vp.p_len = 0;
777                 head = 3;
778         }
779
780         if (len + 3 > free) {
781                 if (free < 7) {
782                         SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
783                                 ("VPD Buffer Overflow, keyword not written\n"));
784                         return(4);
785                 }
786                 /* cut it again */
787                 len = free - 3;
788                 rtv = 2;
789                 SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
790                         ("VPD Buffer Full, Keyword was cut\n"));
791         }
792
793         vpd_move_para(ip + vp.p_len + found, etp+2, len-vp.p_len+head);
794         vpd_insert_key(key, buf, len, ip);
795         if (vpd_mod_endtag(pAC, etp + len - vp.p_len + head)) {
796                 pAC->vpd.v.vpd_status &= ~VPD_VALID;
797                 SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
798                         ("VPD Encoding Error\n"));
799                 return(6);
800         }
801
802         return(rtv);
803 }
804
805
806 /*
807  *      Read the contents of the VPD EEPROM and copy it to the
808  *      VPD buffer if not already done.
809  *
810  * return:      A pointer to the vpd_status structure. The structure contains
811  *              this fields.
812  */
813 SK_VPD_STATUS *VpdStat(
814 SK_AC   *pAC,   /* Adapters context */
815 SK_IOC  IoC)    /* IO Context */
816 {
817         if ((pAC->vpd.v.vpd_status & VPD_VALID) == 0) {
818                 (void)VpdInit(pAC, IoC);
819         }
820         return(&pAC->vpd.v);
821 }
822
823
824 /*
825  *      Read the contents of the VPD EEPROM and copy it to the VPD
826  *      buffer if not already done.
827  *      Scan the VPD buffer for VPD keywords and create the VPD
828  *      keyword list by copying the keywords to 'buf', all after
829  *      each other and terminated with a '\0'.
830  *
831  * Exceptions:  o The Resource Type ID String (product name) is called "Name"
832  *              o The VPD end tags 'RV' and 'RW' are not listed
833  *
834  *      The number of copied keywords is counted in 'elements'.
835  *
836  * returns      0:      success
837  *              2:      buffer overfull, one or more keywords are missing
838  *              6:      fatal VPD error
839  *
840  *      example values after returning:
841  *
842  *              buf =   "Name\0PN\0EC\0MN\0SN\0CP\0VF\0VL\0YA\0"
843  *              *len =          30
844  *              *elements =      9
845  */
846 int VpdKeys(
847 SK_AC   *pAC,           /* common data base */
848 SK_IOC  IoC,            /* IO Context */
849 char    *buf,           /* buffer where to copy the keywords */
850 int             *len,           /* buffer length */
851 int             *elements)      /* number of keywords returned */
852 {
853         char *v;
854         int n;
855
856         SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_RX, ("list VPD keys .. "));
857         *elements = 0;
858         if ((pAC->vpd.v.vpd_status & VPD_VALID) == 0) {
859                 if (VpdInit(pAC, IoC) != 0) {
860                         *len = 0;
861                         SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
862                                 ("VPD Init Error, terminated\n"));
863                         return(6);
864                 }
865         }
866
867         if ((signed)strlen(VPD_NAME) + 1 <= *len) {
868                 v = pAC->vpd.vpd_buf;
869                 strcpy(buf,VPD_NAME);
870                 n = strlen(VPD_NAME) + 1;
871                 buf += n;
872                 *elements = 1;
873                 SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_RX,
874                         ("'%c%c' ",v[0],v[1]));
875         }
876         else {
877                 *len = 0;
878                 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
879                         ("buffer overflow\n"));
880                 return(2);
881         }
882
883         v += 3 + VPD_GET_RES_LEN(v) + 3;
884         for (;; ) {
885                 /* exit when reaching the "RW" Tag */
886                 if (SK_MEMCMP(VPD_RW,v,2) == 0) {
887                         break;
888                 }
889
890                 if (SK_MEMCMP(VPD_RV,v,2) == 0) {
891                         v += 3 + VPD_GET_VPD_LEN(v) + 3;        /* skip VPD-W */
892                         continue;
893                 }
894
895                 if (n+3 <= *len) {
896                         SK_MEMCPY(buf,v,2);
897                         buf += 2;
898                         *buf++ = '\0';
899                         n += 3;
900                         v += 3 + VPD_GET_VPD_LEN(v);
901                         *elements += 1;
902                         SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_RX,
903                                 ("'%c%c' ",v[0],v[1]));
904                 }
905                 else {
906                         *len = n;
907                         SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
908                                 ("buffer overflow\n"));
909                         return(2);
910                 }
911         }
912
913         SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_RX, ("\n"));
914         *len = n;
915         return(0);
916 }
917
918
919 /*
920  *      Read the contents of the VPD EEPROM and copy it to the
921  *      VPD buffer if not already done. Search for the VPD keyword
922  *      'key' and copy its value to 'buf'. Add a terminating '\0'.
923  *      If the value does not fit into the buffer cut it after
924  *      'len' - 1 bytes.
925  *
926  * returns      0:      success
927  *              1:      keyword not found
928  *              2:      value string was cut
929  *              3:      VPD transfer timeout
930  *              6:      fatal VPD error
931  */
932 int VpdRead(
933 SK_AC           *pAC,   /* common data base */
934 SK_IOC          IoC,    /* IO Context */
935 const char      *key,   /* keyword to read (e.g. "MN") */
936 char            *buf,   /* buffer where to copy the keyword value */
937 int                     *len)   /* buffer length */
938 {
939         SK_VPD_PARA *p, vp;
940
941         SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_RX, ("VPD read %s .. ", key));
942         if ((pAC->vpd.v.vpd_status & VPD_VALID) == 0) {
943                 if (VpdInit(pAC, IoC) != 0) {
944                         *len = 0;
945                         SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
946                                 ("VPD init error\n"));
947                         return(6);
948                 }
949         }
950
951         if ((p = vpd_find_para(pAC, key, &vp)) != NULL) {
952                 if (p->p_len > (*(unsigned *)len)-1) {
953                         p->p_len = *len - 1;
954                 }
955                 SK_MEMCPY(buf, p->p_val, p->p_len);
956                 buf[p->p_len] = '\0';
957                 *len = p->p_len;
958                 SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_RX,
959                         ("%c%c%c%c.., len = %d\n",
960                         buf[0],buf[1],buf[2],buf[3],*len));
961         }
962         else {
963                 *len = 0;
964                 SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR, ("not found\n"));
965                 return(1);
966         }
967         return(0);
968 }
969
970
971 /*
972  *      Check whether a given key may be written
973  *
974  * returns
975  *      SK_TRUE         Yes it may be written
976  *      SK_FALSE        No it may be written
977  */
978 SK_BOOL VpdMayWrite(
979 char    *key)   /* keyword to write (allowed values "Yx", "Vx") */
980 {
981         if ((*key != 'Y' && *key != 'V') ||
982                 key[1] < '0' || key[1] > 'Z' ||
983                 (key[1] > '9' && key[1] < 'A') || strlen(key) != 2) {
984
985                 return(SK_FALSE);
986         }
987         return(SK_TRUE);
988 }
989
990 /*
991  *      Read the contents of the VPD EEPROM and copy it to the VPD
992  *      buffer if not already done. Insert/overwrite the keyword 'key'
993  *      in the VPD buffer. Cut the keyword value if it does not fit
994  *      into the VPD read / write area.
995  *
996  * returns      0:      success
997  *              2:      value string was cut
998  *              3:      VPD transfer timeout
999  *              4:      VPD full, keyword was not written
1000  *              5:      keyword cannot be written
1001  *              6:      fatal VPD error
1002  */
1003 int VpdWrite(
1004 SK_AC           *pAC,   /* common data base */
1005 SK_IOC          IoC,    /* IO Context */
1006 const char      *key,   /* keyword to write (allowed values "Yx", "Vx") */
1007 const char      *buf)   /* buffer where the keyword value can be read from */
1008 {
1009         int len;                /* length of the keyword to write */
1010         int rtv;                /* return code */
1011         int rtv2;
1012
1013         SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_TX,
1014                 ("VPD write %s = %s\n",key,buf));
1015
1016         if ((*key != 'Y' && *key != 'V') ||
1017                 key[1] < '0' || key[1] > 'Z' ||
1018                 (key[1] > '9' && key[1] < 'A') || strlen(key) != 2) {
1019
1020                 SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
1021                         ("illegal key tag, keyword not written\n"));
1022                 return(5);
1023         }
1024
1025         if ((pAC->vpd.v.vpd_status & VPD_VALID) == 0) {
1026                 if (VpdInit(pAC, IoC) != 0) {
1027                         SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
1028                                 ("VPD init error\n"));
1029                         return(6);
1030                 }
1031         }
1032
1033         rtv = 0;
1034         len = strlen(buf);
1035         if (len > VPD_MAX_LEN) {
1036                 /* cut it */
1037                 len = VPD_MAX_LEN;
1038                 rtv = 2;
1039                 SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
1040                         ("keyword too long, cut after %d bytes\n",VPD_MAX_LEN));
1041         }
1042         if ((rtv2 = VpdSetupPara(pAC, key, buf, len, VPD_RW_KEY, OWR_KEY)) != 0) {
1043                 SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
1044                         ("VPD write error\n"));
1045                 return(rtv2);
1046         }
1047
1048         return(rtv);
1049 }
1050
1051 /*
1052  *      Read the contents of the VPD EEPROM and copy it to the
1053  *      VPD buffer if not already done. Remove the VPD keyword
1054  *      'key' from the VPD buffer.
1055  *      Only the keywords in the read/write area can be deleted.
1056  *      Keywords in the read only area cannot be deleted.
1057  *
1058  * returns      0:      success, keyword was removed
1059  *              1:      keyword not found
1060  *              5:      keyword cannot be deleted
1061  *              6:      fatal VPD error
1062  */
1063 int VpdDelete(
1064 SK_AC   *pAC,   /* common data base */
1065 SK_IOC  IoC,    /* IO Context */
1066 char    *key)   /* keyword to read (e.g. "MN") */
1067 {
1068         SK_VPD_PARA *p, vp;
1069         char *etp;
1070         int     vpd_size;
1071
1072         vpd_size = pAC->vpd.vpd_size;
1073
1074         SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("VPD delete key %s\n",key));
1075         if ((pAC->vpd.v.vpd_status & VPD_VALID) == 0) {
1076                 if (VpdInit(pAC, IoC) != 0) {
1077                         SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
1078                                 ("VPD init error\n"));
1079                         return(6);
1080                 }
1081         }
1082
1083         if ((p = vpd_find_para(pAC, key, &vp)) != NULL) {
1084                 if (p->p_val < pAC->vpd.vpd_buf + vpd_size/2) {
1085                         /* try to delete read only keyword */
1086                         SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
1087                                 ("cannot delete RO keyword\n"));
1088                         return(5);
1089                 }
1090
1091                 etp = pAC->vpd.vpd_buf + (vpd_size-pAC->vpd.v.vpd_free_rw-1-3);
1092
1093                 vpd_move_para(vp.p_val+vp.p_len, etp+2,
1094                         - ((int)(vp.p_len + 3)));
1095                 if (vpd_mod_endtag(pAC, etp - vp.p_len - 3)) {
1096                         pAC->vpd.v.vpd_status &= ~VPD_VALID;
1097                         SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
1098                                 ("VPD encoding error\n"));
1099                         return(6);
1100                 }
1101         }
1102         else {
1103                 SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
1104                         ("keyword not found\n"));
1105                 return(1);
1106         }
1107
1108         return(0);
1109 }
1110
1111 /*
1112  *      If the VPD buffer contains valid data write the VPD
1113  *      read/write area back to the VPD EEPROM.
1114  *
1115  * returns      0:      success
1116  *              3:      VPD transfer timeout
1117  */
1118 int VpdUpdate(
1119 SK_AC   *pAC,   /* Adapters context */
1120 SK_IOC  IoC)    /* IO Context */
1121 {
1122         int vpd_size;
1123
1124         vpd_size = pAC->vpd.vpd_size;
1125
1126         SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_TX, ("VPD update .. "));
1127         if ((pAC->vpd.v.vpd_status & VPD_VALID) != 0) {
1128                 if (VpdTransferBlock(pAC, IoC, pAC->vpd.vpd_buf + vpd_size/2,
1129                         vpd_size/2, vpd_size/2, VPD_WRITE) != vpd_size/2) {
1130
1131                         SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
1132                                 ("transfer timed out\n"));
1133                         return(3);
1134                 }
1135         }
1136         SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_TX, ("done\n"));
1137         return(0);
1138 }
1139
1140
1141
1142 /*
1143  *      Read the contents of the VPD EEPROM and copy it to the VPD buffer
1144  *      if not already done. If the keyword "VF" is not present it will be
1145  *      created and the error log message will be stored to this keyword.
1146  *      If "VF" is not present the error log message will be stored to the
1147  *      keyword "VL". "VL" will created or overwritten if "VF" is present.
1148  *      The VPD read/write area is saved to the VPD EEPROM.
1149  *
1150  * returns nothing, errors will be ignored.
1151  */
1152 void VpdErrLog(
1153 SK_AC   *pAC,   /* common data base */
1154 SK_IOC  IoC,    /* IO Context */
1155 char    *msg)   /* error log message */
1156 {
1157         SK_VPD_PARA *v, vf;     /* VF */
1158         int len;
1159
1160         SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_TX,
1161                 ("VPD error log msg %s\n", msg));
1162         if ((pAC->vpd.v.vpd_status & VPD_VALID) == 0) {
1163                 if (VpdInit(pAC, IoC) != 0) {
1164                         SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
1165                                 ("VPD init error\n"));
1166                         return;
1167                 }
1168         }
1169
1170         len = strlen(msg);
1171         if (len > VPD_MAX_LEN) {
1172                 /* cut it */
1173                 len = VPD_MAX_LEN;
1174         }
1175         if ((v = vpd_find_para(pAC, VPD_VF, &vf)) != NULL) {
1176                 SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_TX, ("overwrite VL\n"));
1177                 (void)VpdSetupPara(pAC, VPD_VL, msg, len, VPD_RW_KEY, OWR_KEY);
1178         }
1179         else {
1180                 SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_TX, ("write VF\n"));
1181                 (void)VpdSetupPara(pAC, VPD_VF, msg, len, VPD_RW_KEY, ADD_KEY);
1182         }
1183
1184         (void)VpdUpdate(pAC, IoC);
1185 }
1186