skvpd.c 29 KB

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