Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.14 1197 lines 30 kB view raw
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 */ 27static 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 39static SK_VPD_PARA *vpd_find_para( 40 SK_AC *pAC, 41 const char *key, 42 SK_VPD_PARA *p); 43#else /* SK_KR_PROTO */ 44static 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 */ 54static int VpdWait( 55SK_AC *pAC, /* Adapters context */ 56SK_IOC IoC, /* IO Context */ 57int 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 */ 106SK_U32 VpdReadDWord( 107SK_AC *pAC, /* Adapters context */ 108SK_IOC IoC, /* IO Context */ 109int 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 */ 160static int VpdWriteDWord( 161SK_AC *pAC, /* pAC pointer */ 162SK_IOC IoC, /* IO Context */ 163int addr, /* VPD address */ 164SK_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 */ 200static int VpdWriteStream( 201SK_AC *pAC, /* Adapters context */ 202SK_IOC IoC, /* IO Context */ 203char *buf, /* data buffer */ 204int Addr, /* VPD start address */ 205int 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 */ 295static int VpdReadStream( 296SK_AC *pAC, /* Adapters context */ 297SK_IOC IoC, /* IO Context */ 298char *buf, /* data buffer */ 299int Addr, /* VPD start address */ 300int 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 */ 334static int VpdTransferBlock( 335SK_AC *pAC, /* Adapters context */ 336SK_IOC IoC, /* IO Context */ 337char *buf, /* data buffer */ 338int addr, /* VPD start address */ 339int len, /* number of bytes to read / to write */ 340int 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 */ 384int VpdReadBlock( 385SK_AC *pAC, /* pAC pointer */ 386SK_IOC IoC, /* IO Context */ 387char *buf, /* buffer were the data should be stored */ 388int addr, /* start reading at the VPD address */ 389int 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 */ 399int VpdWriteBlock( 400SK_AC *pAC, /* pAC pointer */ 401SK_IOC IoC, /* IO Context */ 402char *buf, /* buffer, holds the data to write */ 403int addr, /* start writing at the VPD address */ 404int 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 */ 419static int VpdInit( 420SK_AC *pAC, /* Adapters context */ 421SK_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 */ 541static SK_VPD_PARA *vpd_find_para( 542SK_AC *pAC, /* common data base */ 543const char *key, /* keyword to find (e.g. "MN") */ 544SK_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 NULL; 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 NULL; 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 */ 612static void vpd_move_para( 613char *start, /* start of memory block */ 614char *end, /* end of memory block to move */ 615int 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 */ 645static void vpd_insert_key( 646const char *key, /* keyword to insert */ 647const char *buf, /* buffer with the keyword value */ 648int len, /* length of the value string */ 649char *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 */ 667static int vpd_mod_endtag( 668SK_AC *pAC, /* common data base */ 669char *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 */ 731int VpdSetupPara( 732SK_AC *pAC, /* common data base */ 733const char *key, /* keyword to insert */ 734const char *buf, /* buffer with the keyword value */ 735int len, /* length of the keyword value */ 736int type, /* VPD_RO_KEY or VPD_RW_KEY */ 737int 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 = NULL; 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 */ 824SK_VPD_STATUS *VpdStat( 825SK_AC *pAC, /* Adapters context */ 826SK_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 */ 857int VpdKeys( 858SK_AC *pAC, /* common data base */ 859SK_IOC IoC, /* IO Context */ 860char *buf, /* buffer where to copy the keywords */ 861int *len, /* buffer length */ 862int *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 */ 943int VpdRead( 944SK_AC *pAC, /* common data base */ 945SK_IOC IoC, /* IO Context */ 946const char *key, /* keyword to read (e.g. "MN") */ 947char *buf, /* buffer where to copy the keyword value */ 948int *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 */ 989SK_BOOL VpdMayWrite( 990char *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 */ 1014int VpdWrite( 1015SK_AC *pAC, /* common data base */ 1016SK_IOC IoC, /* IO Context */ 1017const char *key, /* keyword to write (allowed values "Yx", "Vx") */ 1018const 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 */ 1074int VpdDelete( 1075SK_AC *pAC, /* common data base */ 1076SK_IOC IoC, /* IO Context */ 1077char *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 */ 1129int VpdUpdate( 1130SK_AC *pAC, /* Adapters context */ 1131SK_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 */ 1163void VpdErrLog( 1164SK_AC *pAC, /* common data base */ 1165SK_IOC IoC, /* IO Context */ 1166char *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