1/****************************************************************************** 2 * 3 * Name: skvpd.c 4 * Project: GEnesis, PCI Gigabit Ethernet Adapter 5 * Version: $Revision: 1.1.1.1 $ 6 * Date: $Date: 2008/10/15 03:26:44 $ 7 * Purpose: Shared software to read and write VPD data 8 * 9 ******************************************************************************/ 10 11/****************************************************************************** 12 * 13 * (C)Copyright 1998,1999 SysKonnect, 14 * a business unit of Schneider & Koch & Co. Datensysteme GmbH. 15 * 16 * This program is free software; you can redistribute it and/or modify 17 * it under the terms of the GNU General Public License as published by 18 * the Free Software Foundation; either version 2 of the License, or 19 * (at your option) any later version. 20 * 21 * The information in this file is provided "AS IS" without warranty. 22 * 23 ******************************************************************************/ 24 25/****************************************************************************** 26 * 27 * History: 28 * 29 * $Log: skvpd.c,v $ 30 * Revision 1.1.1.1 2008/10/15 03:26:44 james26_jang 31 * Initial. 32 * 33 * Revision 1.1.1.1 2008/07/21 09:15:07 james26_jang 34 * New UI, New QoS, New wireless driver(4.151.10.29), ipmonitor. 35 * 36 * Revision 1.1 2008/07/17 12:42:44 james26_jang 37 * *** empty log message *** 38 * 39 * Revision 1.1.1.1 2007/02/15 12:11:35 jiahao 40 * initial update 41 * 42 * Revision 1.1.1.1 2007/01/25 12:51:56 jiahao_jhou 43 * 44 * 45 * Revision 1.1.1.1 2003/02/03 22:37:48 mhuang 46 * LINUX_2_4 branch snapshot from linux-mips.org CVS 47 * 48 * Revision 1.26 2000/06/13 08:00:01 mkarl 49 * additional cast to avoid compile problems in 64 bit environment 50 * 51 * Revision 1.25 1999/11/22 13:39:32 cgoos 52 * Changed license header to GPL. 53 * 54 * Revision 1.24 1999/03/11 14:25:49 malthoff 55 * Replace __STDC__ with SK_KR_PROTO. 56 * 57 * Revision 1.23 1999/01/11 15:13:11 gklug 58 * fix: syntax error 59 * 60 * Revision 1.22 1998/10/30 06:41:15 gklug 61 * rmv: WARNING 62 * 63 * Revision 1.21 1998/10/29 07:15:14 gklug 64 * fix: Write Stream function needs verify. 65 * 66 * Revision 1.20 1998/10/28 18:05:08 gklug 67 * chg: no DEBUG in VpdMayWrite 68 * 69 * Revision 1.19 1998/10/28 15:56:11 gklug 70 * fix: Return len at end of ReadStream 71 * fix: Write even less than 4 bytes correctly 72 * 73 * Revision 1.18 1998/10/28 09:00:47 gklug 74 * fix: unreferenced local vars 75 * 76 * Revision 1.17 1998/10/28 08:25:45 gklug 77 * fix: WARNING 78 * 79 * Revision 1.16 1998/10/28 08:17:30 gklug 80 * fix: typo 81 * 82 * Revision 1.15 1998/10/28 07:50:32 gklug 83 * fix: typo 84 * 85 * Revision 1.14 1998/10/28 07:20:38 gklug 86 * chg: Interface functions to use IoC as parameter as well 87 * fix: VpdRead/WriteDWord now return SK_U32 88 * chg: VPD_IN/OUT names conform to SK_IN/OUT 89 * add: usage of VPD_IN/OUT8 macros 90 * add: VpdRead/Write Stream functions to r/w a stream of data 91 * fix: VpdTransferBlock swapped illeagal 92 * add: VpdMayWrite 93 * 94 * Revision 1.13 1998/10/22 10:02:37 gklug 95 * fix: SysKonnectFileId typo 96 * 97 * Revision 1.12 1998/10/20 10:01:01 gklug 98 * fix: parameter to SkOsGetTime 99 * 100 * Revision 1.11 1998/10/15 12:51:48 malthoff 101 * Remove unrequired parameter p in vpd_setup_para(). 102 * 103 * Revision 1.10 1998/10/08 14:52:43 malthoff 104 * Remove CvsId by SysKonnectFileId. 105 * 106 * Revision 1.9 1998/09/16 07:33:52 malthoff 107 * remove memcmp() by SK_MEMCMP and 108 * memcpy() by SK_MEMCPY() to be 109 * independant from the 'C' Standard Library. 110 * 111 * Revision 1.8 1998/08/19 12:52:35 malthoff 112 * compiler fix: use SK_VPD_KEY instead of S_VPD. 113 * 114 * Revision 1.7 1998/08/19 08:14:01 gklug 115 * fix: remove struct keyword as much as possible from the c-code (see CCC) 116 * 117 * Revision 1.6 1998/08/18 13:03:58 gklug 118 * SkOsGetTime now returns SK_U64 119 * 120 * Revision 1.5 1998/08/18 08:17:29 malthoff 121 * Ensure we issue a VPD read in vpd_read_dword(). 122 * Discard all VPD keywords other than Vx or Yx, where 123 * x is '0..9' or 'A..Z'. 124 * 125 * Revision 1.4 1998/07/03 14:52:19 malthoff 126 * Add category SK_DBGCAT_FATAL to some debug macros. 127 * bug fix: correct the keyword name check in vpd_write(). 128 * 129 * Revision 1.3 1998/06/26 11:16:53 malthoff 130 * Correct the modified File Identifier. 131 * 132 * Revision 1.2 1998/06/26 11:13:43 malthoff 133 * Modify the File Identifier. 134 * 135 * Revision 1.1 1998/06/19 14:11:08 malthoff 136 * Created, Tests with AIX were performed successfully 137 * 138 * 139 ******************************************************************************/ 140 141/* 142 Please refer skvpd.txt for infomation how to include this module 143 */ 144static const char SysKonnectFileId[] = 145 "@(#)$Id: skvpd.c,v 1.1.1.1 2008/10/15 03:26:44 james26_jang Exp $ (C) SK" ; 146 147#include "h/skdrv1st.h" 148#include "h/sktypes.h" 149#include "h/skdebug.h" 150#include "h/skdrv2nd.h" 151 152/* 153 * Static functions 154 */ 155#ifndef SK_KR_PROTO 156static SK_VPD_PARA *vpd_find_para( 157 SK_AC *pAC, 158 char *key, 159 SK_VPD_PARA *p) ; 160#else /* SK_KR_PROTO */ 161static SK_VPD_PARA *vpd_find_para() ; 162#endif /* SK_KR_PROTO */ 163 164/* 165 * waits for a completetion of a VPD transfer 166 * The VPD transfer must complete within SK_TICKS_PER_SEC/16 167 * 168 * returns 0: success, transfer completes 169 * error exit(9) with a error message 170 */ 171static int VpdWait( 172SK_AC *pAC, /* Adapters context */ 173SK_IOC IoC, /* IO Context */ 174int event) /* event to wait for (VPD_READ / VPD_write) completion*/ 175{ 176 SK_U64 start_time ; 177 SK_U16 state ; 178 179 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL, 180 ("vpd wait for %s\n",event?"Write":"Read")) ; 181 start_time = SkOsGetTime(pAC) ; 182 do { 183 if (SkOsGetTime(pAC) - start_time > SK_TICKS_PER_SEC/16) { 184 VPD_STOP(pAC,IoC) ; 185 SK_DBG_MSG(pAC,SK_DBGMOD_VPD, 186 SK_DBGCAT_FATAL|SK_DBGCAT_ERR, 187 ("ERROR:vpd wait timeout\n")) ; 188 return(1) ; 189 } 190 VPD_IN16(pAC,IoC,PCI_VPD_ADR_REG,&state) ; 191 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL, 192 ("state = %x, event %x\n",state,event)) ; 193 } while((int)(state & PCI_VPD_FLAG) == event) ; 194 195 return(0) ; 196} 197 198 199/* 200 * Read the dword at address 'addr' from the VPD EEPROM. 201 * 202 * Needed Time: MIN 1,3 ms MAX 2,6 ms 203 * 204 * Note: The DWord is returned in the endianess of the machine the routine 205 * is running on. 206 * 207 * Returns the data read. 208 */ 209SK_U32 VpdReadDWord( 210SK_AC *pAC, /* Adapters context */ 211SK_IOC IoC, /* IO Context */ 212int addr) /* VPD address */ 213{ 214 SK_U32 Rtv ; 215 216 /* start VPD read */ 217 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL, 218 ("vpd read dword at 0x%x\n",addr)) ; 219 addr &= ~VPD_WRITE ; /* ensure the R/W bit is set to read */ 220 221 VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, (SK_U16) addr) ; 222 223 /* ignore return code here */ 224 (void)VpdWait(pAC,IoC,VPD_READ) ; 225 226 /* Don't swap here, it's a data stream of bytes */ 227 Rtv = 0 ; 228 229 VPD_IN32(pAC,IoC,PCI_VPD_DAT_REG,&Rtv) ; 230 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL, 231 ("vpd read dword data = 0x%x\n",Rtv)) ; 232 return (Rtv) ; 233} 234 235/* 236 Write the dword 'data' at address 'addr' into the VPD EEPROM, and 237 verify that the data is written. 238 239 Needed Time: 240 241. MIN MAX 242. ------------------------------------------------------------------- 243. write 1.8 ms 3.6 ms 244. internal write cyles 0.7 ms 7.0 ms 245. ------------------------------------------------------------------- 246. over all program time 2.5 ms 10.6 ms 247. read 1.3 ms 2.6 ms 248. ------------------------------------------------------------------- 249. over all 3.8 ms 13.2 ms 250. 251 252 253 Returns 0: success 254 1: error, I2C transfer does not terminate 255 2: error, data verify error 256 257 */ 258 259/* 260 * Read one Stream of 'len' bytes of VPD data, starting at 'addr' from 261 * or to the I2C EEPROM. 262 * 263 * Returns number of bytes read / written. 264 */ 265static int VpdWriteStream( 266SK_AC *pAC, /* Adapters context */ 267SK_IOC IoC, /* IO Context */ 268char *buf, /* data buffer */ 269int Addr, /* VPD start address */ 270int Len) /* number of bytes to read / to write */ 271{ 272 int i ; 273 int j ; 274 SK_U16 AdrReg ; 275 int Rtv ; 276 SK_U8 * pComp; /* Compare pointer */ 277 SK_U8 Data ; /* Input Data for Compare */ 278 279 /* Init Compare Pointer */ 280 pComp = (SK_U8 *) buf; 281 282 for (i=0; i < Len; i ++, buf++) { 283 if ((i%sizeof(SK_U32)) == 0) { 284 /* 285 * At the begin of each cycle read the Data Reg 286 * So it is initialized even if only a few bytes 287 * are written. 288 */ 289 AdrReg = (SK_U16) Addr ; 290 AdrReg &= ~VPD_WRITE ; /* READ operation */ 291 292 VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, AdrReg) ; 293 294 /* ignore return code here */ 295 Rtv = VpdWait(pAC,IoC,VPD_READ) ; 296 if (Rtv != 0) { 297 return(i) ; 298 } 299 } 300 301 /* Write current Byte */ 302 VPD_OUT8(pAC,IoC,PCI_VPD_DAT_REG+(i%sizeof(SK_U32)), 303 *(SK_U8*)buf) ; 304 305 if (((i%sizeof(SK_U32)) == 3) || (i == (Len - 1))) { 306 /* New Address needs to be written to VPD_ADDR reg */ 307 AdrReg = (SK_U16) Addr ; 308 Addr += sizeof(SK_U32); 309 AdrReg |= VPD_WRITE ; /* WRITE operation */ 310 311 VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, AdrReg) ; 312 313 /* Wait for termination */ 314 Rtv = VpdWait(pAC,IoC,VPD_WRITE) ; 315 if (Rtv != 0) { 316 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, 317 ("Write Timed Out\n")) ; 318 return(i - (i%sizeof(SK_U32))) ; 319 } 320 321 /* 322 * Now re-read to verify 323 */ 324 AdrReg &= ~VPD_WRITE ; /* READ operation */ 325 326 VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, AdrReg) ; 327 328 /* Wait for termination */ 329 Rtv = VpdWait(pAC,IoC,VPD_READ) ; 330 if (Rtv != 0) { 331 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, 332 ("Verify Timed Out\n")) ; 333 return(i - (i%sizeof(SK_U32))) ; 334 } 335 336 for (j = 0; j <= (int) (i%sizeof(SK_U32)); 337 j ++, pComp ++ ) { 338 VPD_IN8(pAC,IoC,PCI_VPD_DAT_REG+j, &Data) ; 339 if (Data != *pComp) { 340 /* Verify Error */ 341 SK_DBG_MSG(pAC,SK_DBGMOD_VPD, 342 SK_DBGCAT_ERR, 343 ("WriteStream Verify Error\n")); 344 return(i - (i%sizeof(SK_U32)) + j); 345 } 346 } 347 348 } 349 } 350 351 return(Len); 352} 353 354 355/* 356 * Read one Stream of 'len' bytes of VPD data, starting at 'addr' from 357 * or to the I2C EEPROM. 358 * 359 * Returns number of bytes read / written. 360 */ 361static int VpdReadStream( 362SK_AC *pAC, /* Adapters context */ 363SK_IOC IoC, /* IO Context */ 364char *buf, /* data buffer */ 365int Addr, /* VPD start address */ 366int Len) /* number of bytes to read / to write */ 367{ 368 int i ; 369 SK_U16 AdrReg ; 370 int Rtv ; 371 372 for (i=0; i < Len; i ++, buf++) { 373 if ((i%sizeof(SK_U32)) == 0) { 374 /* New Address needs to be written to VPD_ADDR reg */ 375 AdrReg = (SK_U16) Addr ; 376 Addr += sizeof(SK_U32); 377 AdrReg &= ~VPD_WRITE ; /* READ operation */ 378 379 VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, AdrReg) ; 380 381 /* ignore return code here */ 382 Rtv = VpdWait(pAC,IoC,VPD_READ) ; 383 if (Rtv != 0) { 384 return(i) ; 385 } 386 387 } 388 VPD_IN8(pAC,IoC,PCI_VPD_DAT_REG+(i%sizeof(SK_U32)), 389 (SK_U8 *)buf) ; 390 } 391 392 return(Len) ; 393} 394 395/* 396 * Read ore wirtes 'len' bytes of VPD data, starting at 'addr' from 397 * or to the I2C EEPROM. 398 * 399 * Returns number of bytes read / written. 400 */ 401static int VpdTransferBlock( 402SK_AC *pAC, /* Adapters context */ 403SK_IOC IoC, /* IO Context */ 404char *buf, /* data buffer */ 405int addr, /* VPD start address */ 406int len, /* number of bytes to read / to write */ 407int dir) /* transfer direction may be VPD_READ or VPD_WRITE */ 408{ 409 int Rtv ; /* Return value */ 410 int vpd_rom_size ; 411 SK_U32 our_reg2 ; 412 413 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL, 414 ("vpd %s block, addr = 0x%x, len = %d\n", 415 dir?"write":"read",addr,len)) ; 416 417 if (len == 0) 418 return (0) ; 419 420 VPD_IN32(pAC,IoC,PCI_OUR_REG_2,&our_reg2) ; 421 vpd_rom_size = 256 << ((our_reg2 & PCI_VPD_ROM_SZ) >> 14); 422 if (addr > vpd_rom_size - 4) { 423 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR|SK_DBGCAT_FATAL, 424 ("Address error: 0x%x, exp. < 0x%x\n", 425 addr, vpd_rom_size - 4)) ; 426 return (0) ; 427 } 428 if (addr + len > vpd_rom_size) { 429 len = vpd_rom_size - addr ; 430 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, 431 ("Warning: len was cut to %d\n",len)) ; 432 } 433 434 if (dir == VPD_READ) { 435 Rtv = VpdReadStream(pAC, IoC, buf, addr, len); 436 } else { 437 Rtv = VpdWriteStream(pAC, IoC, buf, addr, len); 438 } 439 440 return (Rtv) ; 441} 442 443#ifdef SKDIAG 444 445/* 446 * Read 'len' bytes of VPD data, starting at 'addr'. 447 * 448 * Returns number of bytes read. 449 */ 450int VpdReadBlock( 451SK_AC *pAC, /* pAC pointer */ 452SK_IOC IoC, /* IO Context */ 453char *buf, /* buffer were the data should be stored */ 454int addr, /* start reading at the VPD address */ 455int len) /* number of bytes to read */ 456{ 457 return (VpdTransferBlock(pAC, IoC, buf, addr, len, VPD_READ)) ; 458} 459 460/* 461 * Write 'len' bytes of *but to the VPD EEPROM, starting at 'addr'. 462 * 463 * Returns number of bytes writes. 464 */ 465int VpdWriteBlock( 466SK_AC *pAC, /* pAC pointer */ 467SK_IOC IoC, /* IO Context */ 468char *buf, /* buffer, holds the data to write */ 469int addr, /* start writing at the VPD address */ 470int len) /* number of bytes to write */ 471{ 472 return (VpdTransferBlock(pAC, IoC, buf, addr, len, VPD_WRITE)) ; 473} 474#endif /* SKDIAG */ 475 476/* 477 * (re)initialize the VPD buffer 478 * 479 * Reads the VPD data from the EEPROM into the VPD buffer. 480 * Get the remaining read only and read / write space. 481 * 482 * return 0: success 483 * 1: fatal VPD error 484 */ 485static int VpdInit( 486SK_AC *pAC, /* Adapters context */ 487SK_IOC IoC) /* IO Context */ 488{ 489 SK_VPD_PARA *r, rp ; /* RW or RV */ 490 int i ; 491 unsigned char x ; 492 493 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_INIT,("VpdInit .. ")) ; 494 /* read the VPD data into the VPD buffer */ 495 if (VpdTransferBlock(pAC,IoC,pAC->vpd.vpd_buf,0,VPD_SIZE,VPD_READ) 496 != VPD_SIZE) { 497 498 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, 499 ("Block Read Error\n")) ; 500 return(1) ; 501 } 502 503 /* find the end tag of the RO area */ 504 if (!(r = vpd_find_para(pAC,VPD_RV,&rp))) { 505 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL, 506 ("Encoding Error: RV Tag not found\n")) ; 507 return (1) ; 508 } 509 if (r->p_val + r->p_len > pAC->vpd.vpd_buf + VPD_SIZE/2) { 510 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL, 511 ("Encoding Error: Invalid VPD struct size\n")) ; 512 return (1) ; 513 } 514 pAC->vpd.v.vpd_free_ro = r->p_len - 1 ; 515 516 /* test the checksum */ 517 for (i = 0, x = 0; (unsigned)i<=(unsigned)VPD_SIZE/2 - r->p_len; i++) { 518 x += pAC->vpd.vpd_buf[i] ; 519 } 520 if (x != 0) { 521 /* checksum error */ 522 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL, 523 ("VPD Checksum Error\n")) ; 524 return (1) ; 525 } 526 527 /* find and check the end tag of the RW area */ 528 if (!(r = vpd_find_para(pAC,VPD_RW,&rp))) { 529 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL, 530 ("Encoding Error: RV Tag not found\n")) ; 531 return (1) ; 532 } 533 if (r->p_val < pAC->vpd.vpd_buf + VPD_SIZE/2) { 534 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL, 535 ("Encoding Error: Invalid VPD struct size\n")) ; 536 return (1) ; 537 } 538 pAC->vpd.v.vpd_free_rw = r->p_len ; 539 540 /* everything seems to be ok */ 541 pAC->vpd.v.vpd_status |= VPD_VALID ; 542 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_INIT, 543 ("done. Free RO = %d, Free RW = %d\n", 544 pAC->vpd.v.vpd_free_ro, pAC->vpd.v.vpd_free_rw)) ; 545 546 return(0) ; 547} 548 549/* 550 * find the Keyword 'key' in the VPD buffer and fills the 551 * parameter sturct 'p' with it's values 552 * 553 * returns *p success 554 * 0: parameter was not found or VPD encoding error 555 */ 556static SK_VPD_PARA *vpd_find_para( 557SK_AC *pAC, /* common data base */ 558char *key, /* keyword to find (e.g. "MN") */ 559SK_VPD_PARA *p) /* parameter description struct */ 560{ 561 char *v ; /* points to vpd buffer */ 562 int max ; /* Maximum Number of Iterations */ 563 564 v = pAC->vpd.vpd_buf ; 565 max = 128 ; 566 567 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL, 568 ("vpd find para %s .. ",key)) ; 569 570 /* check mandatory resource type ID string (Product Name) */ 571 if (*v != (char) RES_ID) { 572 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL, 573 ("Error: 0x%x missing\n",RES_ID)) ; 574 return (0) ; 575 } 576 577 if (strcmp(key,VPD_NAME) == 0) { 578 p->p_len = VPD_GET_RES_LEN(v) ; 579 p->p_val = VPD_GET_VAL(v) ; 580 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL, 581 ("found, len = %d\n",p->p_len)) ; 582 return(p) ; 583 } 584 585 v += 3 + VPD_GET_RES_LEN(v) + 3 ; 586 for ( ; ; ) { 587 if (SK_MEMCMP(key,v,2) == 0) { 588 p->p_len = VPD_GET_VPD_LEN(v) ; 589 p->p_val = VPD_GET_VAL(v) ; 590 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL, 591 ("found, len = %d\n",p->p_len)) ; 592 return (p) ; 593 } 594 595 /* exit when reaching the "RW" Tag or the maximum of itera. */ 596 max-- ; 597 if (SK_MEMCMP(VPD_RW,v,2) == 0 || max == 0) { 598 break ; 599 } 600 601 if (SK_MEMCMP(VPD_RV,v,2) == 0) { 602 v += 3 + VPD_GET_VPD_LEN(v) + 3 ; /* skip VPD-W */ 603 } else { 604 v += 3 + VPD_GET_VPD_LEN(v) ; 605 } 606 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL, 607 ("scanning '%c%c' len = %d\n",v[0],v[1],v[2])) ; 608 } 609 610#ifdef DEBUG 611 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,("not found\n")) ; 612 if (max == 0) { 613 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL, 614 ("Key/Len Encoding error\n")) ; 615 } 616#endif 617 return (0) ; 618} 619 620/* 621 * Move 'n' bytes. Begin with the last byte if 'n' is > 0, 622 * Start with the last byte if n is < 0. 623 * 624 * returns nothing 625 */ 626static void vpd_move_para( 627char *start, /* start of memory block */ 628char *end, /* end of memory block to move */ 629int n) /* number of bytes the memory block has to be moved */ 630{ 631 char *p ; 632 int i ; /* number of byte copied */ 633 634 if (n == 0) 635 return ; 636 637 i = (int) (end - start + 1) ; 638 if (n < 0) { 639 p = start + n ; 640 while (i != 0) { 641 *p++ = *start++ ; 642 i-- ; 643 } 644 } else { 645 p = end + n ; 646 while (i != 0) { 647 *p-- = *end-- ; 648 i-- ; 649 } 650 } 651} 652 653/* 654 * setup the VPD keyword 'key' at 'ip'. 655 * 656 * returns nothing 657 */ 658static void vpd_insert_key( 659char *key, /* keyword to insert */ 660char *buf, /* buffer with the keyword value */ 661int len, /* length of the value string */ 662char *ip) /* inseration point */ 663{ 664 SK_VPD_KEY *p ; 665 666 p = (SK_VPD_KEY *) ip ; 667 p->p_key[0] = key[0] ; 668 p->p_key[1] = key[1] ; 669 p->p_len = (unsigned char) len ; 670 SK_MEMCPY(&p->p_val,buf,len) ; 671} 672 673/* 674 * Setup the VPD end tag "RV" / "RW". 675 * Also correct the remaining space variables vpd_free_ro / vpd_free_rw. 676 * 677 * returns 0: success 678 * 1: encoding error 679 */ 680static int vpd_mod_endtag( 681SK_AC *pAC, /* common data base */ 682char *etp) /* end pointer input position */ 683{ 684 SK_VPD_KEY *p ; 685 unsigned char x ; 686 int i ; 687 688 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL, 689 ("vpd modify endtag at 0x%x = '%c%c'\n",etp,etp[0],etp[1])) ; 690 691 p = (SK_VPD_KEY *) etp ; 692 693 if (p->p_key[0] != 'R' || (p->p_key[1] != 'V' && p->p_key[1] != 'W')) { 694 /* something wrong here, encoding error */ 695 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL, 696 ("Encoding Error: invalid end tag\n")) ; 697 return(1) ; 698 } 699 if (etp > pAC->vpd.vpd_buf + VPD_SIZE/2) { 700 /* create "RW" tag */ 701 p->p_len = (unsigned char)(pAC->vpd.vpd_buf+VPD_SIZE-etp-3-1) ; 702 pAC->vpd.v.vpd_free_rw = (int) p->p_len ; 703 i = pAC->vpd.v.vpd_free_rw ; 704 etp += 3 ; 705 } else { 706 /* create "RV" tag */ 707 p->p_len = (unsigned char)(pAC->vpd.vpd_buf+VPD_SIZE/2-etp-3) ; 708 pAC->vpd.v.vpd_free_ro = (int) p->p_len - 1 ; 709 710 /* setup checksum */ 711 for (i = 0, x = 0; i < VPD_SIZE/2 - p->p_len; i++) { 712 x += pAC->vpd.vpd_buf[i] ; 713 } 714 p->p_val = (char) 0 - x ; 715 i = pAC->vpd.v.vpd_free_ro ; 716 etp += 4 ; 717 } 718 while (i) { 719 *etp++ = 0x00 ; 720 i-- ; 721 } 722 723 return (0) ; 724} 725 726/* 727 * Insert a VPD keyword into the VPD buffer. 728 * 729 * The keyword 'key' is inserted at the position 'ip' in the 730 * VPD buffer. 731 * The keywords behind the input position will 732 * be moved. The VPD end tag "RV" or "RW" is generated again. 733 * 734 * returns 0: success 735 * 2: value string was cut 736 * 4: VPD full, keyword was not written 737 * 6: fatal VPD error 738 * 739 */ 740int VpdSetupPara( 741SK_AC *pAC, /* common data base */ 742char *key, /* keyword to insert */ 743char *buf, /* buffer with the keyword value */ 744int len, /* length of the keyword value */ 745int type, /* VPD_RO_KEY or VPD_RW_KEY */ 746int op) /* operation to do: ADD_KEY or OWR_KEY */ 747{ 748 SK_VPD_PARA vp ; 749 char *etp ; /* end tag position */ 750 int free ; /* remaining space in selected area */ 751 char *ip ; /* input position inside the VPD buffer */ 752 int rtv ; /* return code */ 753 int head ; /* additional haeder bytes to move */ 754 int found ; /* additinoal bytes if the keyword was found */ 755 756 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL, 757 ("vpd setup para key = %s, val = %s\n",key,buf)) ; 758 759 rtv = 0 ; 760 ip = 0 ; 761 if (type == VPD_RW_KEY) { 762 /* end tag is "RW" */ 763 free = pAC->vpd.v.vpd_free_rw ; 764 etp = pAC->vpd.vpd_buf + (VPD_SIZE - free - 1 - 3) ; 765 } else { 766 /* end tag is "RV" */ 767 free = pAC->vpd.v.vpd_free_ro ; 768 etp = pAC->vpd.vpd_buf + (VPD_SIZE/2 - free - 4) ; 769 } 770 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL, 771 ("Free RO = %d, Free RW = %d\n", 772 pAC->vpd.v.vpd_free_ro, pAC->vpd.v.vpd_free_rw)) ; 773 774 head = 0 ; 775 found = 0 ; 776 if (op == OWR_KEY) { 777 if (vpd_find_para(pAC,key,&vp)) { 778 found = 3 ; 779 ip = vp.p_val - 3 ; 780 free += vp.p_len + 3 ; 781 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL, 782 ("Overwrite Key\n")) ; 783 } else { 784 op = ADD_KEY ; 785 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL, 786 ("Add Key\n")) ; 787 } 788 } 789 if (op == ADD_KEY) { 790 ip = etp ; 791 vp.p_len = 0 ; 792 head = 3 ; 793 } 794 795 if (len + 3 > free) { 796 if (free < 7) { 797 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, 798 ("VPD Buffer Overflow, keyword not written\n")); 799 return (4) ; 800 } 801 /* cut it again */ 802 len = free - 3 ; 803 rtv = 2 ; 804 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, 805 ("VPD Buffer Full, Keyword was cut\n")) ; 806 } 807 808 vpd_move_para(ip + vp.p_len + found, etp+2, len-vp.p_len+head) ; 809 vpd_insert_key(key, buf, len, ip) ; 810 if (vpd_mod_endtag(pAC, etp + len - vp.p_len + head)) { 811 pAC->vpd.v.vpd_status &= ~VPD_VALID ; 812 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, 813 ("VPD Encoding Error\n")) ; 814 return(6) ; 815 } 816 817 return (rtv) ; 818} 819 820 821/* 822 * Read the contents of the VPD EEPROM and copy it to the 823 * VPD buffer if not already done. 824 * 825 * return: A pointer to the vpd_status structure. The structure contain 826 * this fields. 827 */ 828SK_VPD_STATUS *VpdStat( 829SK_AC *pAC, /* Adapters context */ 830SK_IOC IoC) /* IO Context */ 831{ 832 if (!(pAC->vpd.v.vpd_status & VPD_VALID)) { 833 (void)VpdInit(pAC,IoC) ; 834 } 835 return(&pAC->vpd.v) ; 836} 837 838 839/* 840 * Read the contents of the VPD EEPROM and copy it to the VPD 841 * buffer if not already done. 842 * Scan the VPD buffer for VPD keywords and create the VPD 843 * keyword list by copying the keywords to 'buf', all after 844 * each other and terminated with a '\0'. 845 * 846 * Exceptions: o The Resource Type ID String (product name) is called "Name" 847 * o The VPD end tags 'RV' and 'RW' are not listed 848 * 849 * The number of copied keywords is counted in 'elements'. 850 * 851 * returns 0: success 852 * 2: buffer overfull, one or more keywords are missing 853 * 6: fatal VPD error 854 * 855 * example values after returning: 856 * 857 * buf = "Name\0PN\0EC\0MN\0SN\0CP\0VF\0VL\0YA\0" 858 * *len = 30 859 * *elements = 9 860 */ 861int VpdKeys( 862SK_AC *pAC, /* common data base */ 863SK_IOC IoC, /* IO Context */ 864char *buf, /* buffer where to copy the keywords */ 865int *len, /* buffer length */ 866int *elements) /* number of keywords returned */ 867{ 868 char *v ; 869 int n ; 870 871 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_RX,("list vpd keys .. ")) ; 872 *elements = 0 ; 873 if (!(pAC->vpd.v.vpd_status & VPD_VALID)) { 874 if (VpdInit(pAC,IoC) != 0 ) { 875 *len = 0 ; 876 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, 877 ("VPD Init Error, terminated\n")) ; 878 return(6) ; 879 } 880 } 881 882 if ((signed)strlen(VPD_NAME) + 1 <= *len) { 883 v = pAC->vpd.vpd_buf ; 884 strcpy(buf,VPD_NAME) ; 885 n = strlen(VPD_NAME) + 1 ; 886 buf += n ; 887 *elements = 1 ; 888 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_RX, 889 ("'%c%c' ",v[0],v[1])) ; 890 } else { 891 *len = 0 ; 892 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, 893 ("buffer overflow\n")) ; 894 return(2) ; 895 } 896 897 v += 3 + VPD_GET_RES_LEN(v) + 3 ; 898 for ( ; ; ) { 899 /* exit when reaching the "RW" Tag */ 900 if (SK_MEMCMP(VPD_RW,v,2) == 0) { 901 break ; 902 } 903 904 if (SK_MEMCMP(VPD_RV,v,2) == 0) { 905 v += 3 + VPD_GET_VPD_LEN(v) + 3 ; /* skip VPD-W */ 906 continue ; 907 } 908 909 if (n+3 <= *len) { 910 SK_MEMCPY(buf,v,2) ; 911 buf += 2 ; 912 *buf++ = '\0' ; 913 n += 3 ; 914 v += 3 + VPD_GET_VPD_LEN(v) ; 915 *elements += 1 ; 916 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_RX, 917 ("'%c%c' ",v[0],v[1])) ; 918 } else { 919 *len = n ; 920 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, 921 ("buffer overflow\n")) ; 922 return (2) ; 923 } 924 } 925 926 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_RX,("\n")) ; 927 *len = n ; 928 return(0) ; 929} 930 931 932/* 933 * Read the contents of the VPD EEPROM and copy it to the 934 * VPD buffer if not already done. Search for the VPD keyword 935 * 'key' and copy its value to 'buf'. Add a terminating '\0'. 936 * If the value does not fit into the buffer cut it after 937 * 'len' - 1 bytes. 938 * 939 * returns 0: success 940 * 1: keyword not found 941 * 2: value string was cut 942 * 3: VPD transfer timeout 943 * 6: fatal VPD error 944 */ 945int VpdRead( 946SK_AC *pAC, /* common data base */ 947SK_IOC IoC, /* IO Context */ 948char *key, /* keyword to read (e.g. "MN") */ 949char *buf, /* buffer where to copy the keyword value */ 950int *len) /* buffer length */ 951{ 952 SK_VPD_PARA *p, vp ; 953 954 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_RX,("vpd read %s .. ",key)) ; 955 if (!(pAC->vpd.v.vpd_status & VPD_VALID)) { 956 if (VpdInit(pAC,IoC) != 0 ) { 957 *len = 0 ; 958 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, 959 ("vpd init error\n")) ; 960 return(6) ; 961 } 962 } 963 964 if ((p = vpd_find_para(pAC,key,&vp))) { 965 if (p->p_len > (*(unsigned *)len)-1) { 966 p->p_len = *len - 1 ; 967 } 968 SK_MEMCPY(buf,p->p_val,p->p_len) ; 969 buf[p->p_len] = '\0' ; 970 *len = p->p_len ; 971 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_RX, 972 ("%c%c%c%c.., len = %d\n", 973 buf[0],buf[1],buf[2],buf[3],*len)) ; 974 } else { 975 *len = 0 ; 976 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,("not found\n")) ; 977 return (1) ; 978 } 979 return (0) ; 980} 981 982 983/* 984 * Check whether a given key may be written 985 * 986 * returns 987 * SK_TRUE Yes it may be written 988 * SK_FALSE No it may be written 989 */ 990SK_BOOL VpdMayWrite( 991char *key) /* keyword to write (allowed values "Yx", "Vx") */ 992{ 993 if ((*key != 'Y' && *key != 'V') || 994 key[1] < '0' || key[1] > 'Z' || 995 (key[1] > '9' && key[1] < 'A') || strlen(key) != 2) { 996 997 return (SK_FALSE) ; 998 } 999 return (SK_TRUE) ; 1000} 1001 1002/* 1003 * Read the contents of the VPD EEPROM and copy it to the VPD 1004 * buffer if not already done. Insert/overwrite the keyword 'key' 1005 * in the VPD buffer. Cut the keyword value if it does not fit 1006 * into the VPD read / write area. 1007 * 1008 * returns 0: success 1009 * 2: value string was cut 1010 * 3: VPD transfer timeout 1011 * 4: VPD full, keyword was not written 1012 * 5: keyword cannot be written 1013 * 6: fatal VPD error 1014 */ 1015int VpdWrite( 1016SK_AC *pAC, /* common data base */ 1017SK_IOC IoC, /* IO Context */ 1018char *key, /* keyword to write (allowed values "Yx", "Vx") */ 1019char *buf) /* buffer where the keyword value can be read from */ 1020{ 1021 int len ; /* lenght of the keyword to write */ 1022 int rtv ; /* return code */ 1023 int rtv2 ; 1024 1025 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX, 1026 ("vpd write %s = %s\n",key,buf)) ; 1027 1028 if ((*key != 'Y' && *key != 'V') || 1029 key[1] < '0' || key[1] > 'Z' || 1030 (key[1] > '9' && key[1] < 'A') || strlen(key) != 2) { 1031 1032 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, 1033 ("illegal key tag, keyword not written\n")) ; 1034 return (5) ; 1035 } 1036 1037 if (!(pAC->vpd.v.vpd_status & VPD_VALID)) { 1038 if (VpdInit(pAC,IoC) != 0 ) { 1039 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, 1040 ("vpd init error\n")) ; 1041 return(6) ; 1042 } 1043 } 1044 1045 rtv = 0 ; 1046 len = strlen(buf) ; 1047 if (len > VPD_MAX_LEN) { 1048 /* cut it */ 1049 len = VPD_MAX_LEN ; 1050 rtv = 2 ; 1051 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, 1052 ("keyword to long, cut after %d bytes\n",VPD_MAX_LEN)) ; 1053 } 1054 if ((rtv2 = VpdSetupPara(pAC,key,buf,len,VPD_RW_KEY,OWR_KEY)) != 0) { 1055 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, 1056 ("vpd write error\n")) ; 1057 return(rtv2) ; 1058 } 1059 1060 return (rtv) ; 1061} 1062 1063/* 1064 * Read the contents of the VPD EEPROM and copy it to the 1065 * VPD buffer if not already done. Remove the VPD keyword 1066 * 'key' from the VPD buffer. 1067 * Only the keywords in the read/write area can be deleted. 1068 * Keywords in the read only area cannot be deleted. 1069 * 1070 * returns 0: success, keyword was removed 1071 * 1: keyword not found 1072 * 5: keyword cannot be deleted 1073 * 6: fatal VPD error 1074 */ 1075int VpdDelete( 1076SK_AC *pAC, /* common data base */ 1077SK_IOC IoC, /* IO Context */ 1078char *key) /* keyword to read (e.g. "MN") */ 1079{ 1080 SK_VPD_PARA *p, vp ; 1081 char *etp ; 1082 1083 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("vpd delete key %s\n",key)) ; 1084 if (!(pAC->vpd.v.vpd_status & VPD_VALID)) { 1085 if (VpdInit(pAC,IoC) != 0 ) { 1086 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, 1087 ("vpd init error\n")) ; 1088 return(6) ; 1089 } 1090 } 1091 1092 if ((p = vpd_find_para(pAC,key,&vp))) { 1093 if (p->p_val < pAC->vpd.vpd_buf + VPD_SIZE/2) { 1094 /* try to delete read only keyword */ 1095 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, 1096 ("cannot delete RO keyword\n")) ; 1097 return (5) ; 1098 } 1099 1100 etp = pAC->vpd.vpd_buf + (VPD_SIZE-pAC->vpd.v.vpd_free_rw-1-3) ; 1101 1102 vpd_move_para(vp.p_val+vp.p_len, etp+2, 1103 - ((int)(vp.p_len + 3))) ; 1104 if (vpd_mod_endtag(pAC, etp - vp.p_len - 3)) { 1105 pAC->vpd.v.vpd_status &= ~VPD_VALID ; 1106 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, 1107 ("vpd encoding error\n")) ; 1108 return(6) ; 1109 } 1110 } else { 1111 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, 1112 ("keyword not found\n")) ; 1113 return (1) ; 1114 } 1115 1116 return (0) ; 1117} 1118 1119/* 1120 * If the VPD buffer contains valid data write the VPD 1121 * read/write area back to the VPD EEPROM. 1122 * 1123 * returns 0: success 1124 * 3: VPD transfer timeout 1125 */ 1126int VpdUpdate( 1127SK_AC *pAC, /* Adapters context */ 1128SK_IOC IoC) /* IO Context */ 1129{ 1130 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("vpd update .. ")) ; 1131 if (pAC->vpd.v.vpd_status & VPD_VALID) { 1132 if (VpdTransferBlock(pAC,IoC,pAC->vpd.vpd_buf + VPD_SIZE/2, 1133 VPD_SIZE/2, VPD_SIZE/2, VPD_WRITE) != VPD_SIZE/2) { 1134 1135 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, 1136 ("transfer timed out\n")) ; 1137 return(3) ; 1138 } 1139 } 1140 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("done\n")) ; 1141 return (0) ; 1142} 1143 1144 1145 1146/* 1147 * Read the contents of the VPD EEPROM and copy it to the VPD buffer 1148 * if not already done. If the keyword "VF" is not present it will be 1149 * created and the error log message will be stored to this keyword. 1150 * If "VF" is not present the error log message will be stored to the 1151 * keyword "VL". "VL" will created or overwritten if "VF" is present. 1152 * The VPD read/write area is saved to the VPD EEPROM. 1153 * 1154 * returns nothing, errors will be ignored. 1155 */ 1156void VpdErrLog( 1157SK_AC *pAC, /* common data base */ 1158SK_IOC IoC, /* IO Context */ 1159char *msg) /* error log message */ 1160{ 1161 SK_VPD_PARA *v, vf ; /* VF */ 1162 int len ; 1163 1164 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX, 1165 ("vpd error log msg %s\n",msg)) ; 1166 if (!(pAC->vpd.v.vpd_status & VPD_VALID)) { 1167 if (VpdInit(pAC,IoC) != 0 ) { 1168 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, 1169 ("vpd init error\n")) ; 1170 return ; 1171 } 1172 } 1173 1174 len = strlen(msg) ; 1175 if (len > VPD_MAX_LEN) { 1176 /* cut it */ 1177 len = VPD_MAX_LEN ; 1178 } 1179 if ((v = vpd_find_para(pAC,VPD_VF,&vf))) { 1180 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("overwrite VL\n")) ; 1181 (void)VpdSetupPara(pAC,VPD_VL,msg,len,VPD_RW_KEY,OWR_KEY) ; 1182 } else { 1183 SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("write VF\n")) ; 1184 (void)VpdSetupPara(pAC,VPD_VF,msg,len,VPD_RW_KEY,ADD_KEY) ; 1185 } 1186 1187 (void)VpdUpdate(pAC,IoC) ; 1188} 1189 1190