Commit | Line | Data |
---|---|---|
f931551b RC |
1 | /* |
2 | * Copyright (c) 2006, 2007, 2008, 2009 QLogic Corporation. All rights reserved. | |
3 | * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved. | |
4 | * | |
5 | * This software is available to you under a choice of one of two | |
6 | * licenses. You may choose to be licensed under the terms of the GNU | |
7 | * General Public License (GPL) Version 2, available from the file | |
8 | * COPYING in the main directory of this source tree, or the | |
9 | * OpenIB.org BSD license below: | |
10 | * | |
11 | * Redistribution and use in source and binary forms, with or | |
12 | * without modification, are permitted provided that the following | |
13 | * conditions are met: | |
14 | * | |
15 | * - Redistributions of source code must retain the above | |
16 | * copyright notice, this list of conditions and the following | |
17 | * disclaimer. | |
18 | * | |
19 | * - Redistributions in binary form must reproduce the above | |
20 | * copyright notice, this list of conditions and the following | |
21 | * disclaimer in the documentation and/or other materials | |
22 | * provided with the distribution. | |
23 | * | |
24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
26 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | |
28 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | |
29 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
30 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
31 | * SOFTWARE. | |
32 | */ | |
33 | ||
34 | #include <linux/delay.h> | |
35 | #include <linux/pci.h> | |
36 | #include <linux/vmalloc.h> | |
37 | ||
38 | #include "qib.h" | |
39 | #include "qib_qsfp.h" | |
40 | ||
41 | /* | |
42 | * QSFP support for ib_qib driver, using "Two Wire Serial Interface" driver | |
43 | * in qib_twsi.c | |
44 | */ | |
45 | #define QSFP_MAX_RETRY 4 | |
46 | ||
47 | static int qsfp_read(struct qib_pportdata *ppd, int addr, void *bp, int len) | |
48 | { | |
49 | struct qib_devdata *dd = ppd->dd; | |
50 | u32 out, mask; | |
51 | int ret, cnt, pass = 0; | |
52 | int stuck = 0; | |
53 | u8 *buff = bp; | |
54 | ||
55 | ret = mutex_lock_interruptible(&dd->eep_lock); | |
56 | if (ret) | |
57 | goto no_unlock; | |
58 | ||
59 | if (dd->twsi_eeprom_dev == QIB_TWSI_NO_DEV) { | |
60 | ret = -ENXIO; | |
61 | goto bail; | |
62 | } | |
63 | ||
64 | /* | |
65 | * We presume, if we are called at all, that this board has | |
66 | * QSFP. This is on the same i2c chain as the legacy parts, | |
67 | * but only responds if the module is selected via GPIO pins. | |
68 | * Further, there are very long setup and hold requirements | |
69 | * on MODSEL. | |
70 | */ | |
71 | mask = QSFP_GPIO_MOD_SEL_N | QSFP_GPIO_MOD_RST_N | QSFP_GPIO_LP_MODE; | |
72 | out = QSFP_GPIO_MOD_RST_N | QSFP_GPIO_LP_MODE; | |
73 | if (ppd->hw_pidx) { | |
74 | mask <<= QSFP_GPIO_PORT2_SHIFT; | |
75 | out <<= QSFP_GPIO_PORT2_SHIFT; | |
76 | } | |
77 | ||
78 | dd->f_gpio_mod(dd, out, mask, mask); | |
79 | ||
80 | /* | |
81 | * Module could take up to 2 Msec to respond to MOD_SEL, and there | |
82 | * is no way to tell if it is ready, so we must wait. | |
83 | */ | |
84 | msleep(2); | |
85 | ||
86 | /* Make sure TWSI bus is in sane state. */ | |
87 | ret = qib_twsi_reset(dd); | |
88 | if (ret) { | |
89 | qib_dev_porterr(dd, ppd->port, | |
90 | "QSFP interface Reset for read failed\n"); | |
91 | ret = -EIO; | |
92 | stuck = 1; | |
93 | goto deselect; | |
94 | } | |
95 | ||
96 | /* All QSFP modules are at A0 */ | |
97 | ||
98 | cnt = 0; | |
99 | while (cnt < len) { | |
100 | unsigned in_page; | |
101 | int wlen = len - cnt; | |
102 | in_page = addr % QSFP_PAGESIZE; | |
103 | if ((in_page + wlen) > QSFP_PAGESIZE) | |
104 | wlen = QSFP_PAGESIZE - in_page; | |
105 | ret = qib_twsi_blk_rd(dd, QSFP_DEV, addr, buff + cnt, wlen); | |
106 | /* Some QSFP's fail first try. Retry as experiment */ | |
107 | if (ret && cnt == 0 && ++pass < QSFP_MAX_RETRY) | |
108 | continue; | |
109 | if (ret) { | |
110 | /* qib_twsi_blk_rd() 1 for error, else 0 */ | |
111 | ret = -EIO; | |
112 | goto deselect; | |
113 | } | |
114 | addr += wlen; | |
115 | cnt += wlen; | |
116 | } | |
117 | ret = cnt; | |
118 | ||
119 | deselect: | |
120 | /* | |
121 | * Module could take up to 10 uSec after transfer before | |
122 | * ready to respond to MOD_SEL negation, and there is no way | |
123 | * to tell if it is ready, so we must wait. | |
124 | */ | |
125 | udelay(10); | |
126 | /* set QSFP MODSEL, RST. LP all high */ | |
127 | dd->f_gpio_mod(dd, mask, mask, mask); | |
128 | ||
129 | /* | |
130 | * Module could take up to 2 Msec to respond to MOD_SEL | |
131 | * going away, and there is no way to tell if it is ready. | |
132 | * so we must wait. | |
133 | */ | |
134 | if (stuck) | |
135 | qib_dev_err(dd, "QSFP interface bus stuck non-idle\n"); | |
136 | ||
137 | if (pass >= QSFP_MAX_RETRY && ret) | |
138 | qib_dev_porterr(dd, ppd->port, "QSFP failed even retrying\n"); | |
139 | else if (pass) | |
140 | qib_dev_porterr(dd, ppd->port, "QSFP retries: %d\n", pass); | |
141 | ||
142 | msleep(2); | |
143 | ||
144 | bail: | |
145 | mutex_unlock(&dd->eep_lock); | |
146 | ||
147 | no_unlock: | |
148 | return ret; | |
149 | } | |
150 | ||
151 | /* | |
152 | * qsfp_write | |
153 | * We do not ordinarily write the QSFP, but this is needed to select | |
154 | * the page on non-flat QSFPs, and possibly later unusual cases | |
155 | */ | |
156 | static int qib_qsfp_write(struct qib_pportdata *ppd, int addr, void *bp, | |
157 | int len) | |
158 | { | |
159 | struct qib_devdata *dd = ppd->dd; | |
160 | u32 out, mask; | |
161 | int ret, cnt; | |
162 | u8 *buff = bp; | |
163 | ||
164 | ret = mutex_lock_interruptible(&dd->eep_lock); | |
165 | if (ret) | |
166 | goto no_unlock; | |
167 | ||
168 | if (dd->twsi_eeprom_dev == QIB_TWSI_NO_DEV) { | |
169 | ret = -ENXIO; | |
170 | goto bail; | |
171 | } | |
172 | ||
173 | /* | |
174 | * We presume, if we are called at all, that this board has | |
175 | * QSFP. This is on the same i2c chain as the legacy parts, | |
176 | * but only responds if the module is selected via GPIO pins. | |
177 | * Further, there are very long setup and hold requirements | |
178 | * on MODSEL. | |
179 | */ | |
180 | mask = QSFP_GPIO_MOD_SEL_N | QSFP_GPIO_MOD_RST_N | QSFP_GPIO_LP_MODE; | |
181 | out = QSFP_GPIO_MOD_RST_N | QSFP_GPIO_LP_MODE; | |
182 | if (ppd->hw_pidx) { | |
183 | mask <<= QSFP_GPIO_PORT2_SHIFT; | |
184 | out <<= QSFP_GPIO_PORT2_SHIFT; | |
185 | } | |
186 | dd->f_gpio_mod(dd, out, mask, mask); | |
187 | ||
188 | /* | |
189 | * Module could take up to 2 Msec to respond to MOD_SEL, | |
190 | * and there is no way to tell if it is ready, so we must wait. | |
191 | */ | |
192 | msleep(2); | |
193 | ||
194 | /* Make sure TWSI bus is in sane state. */ | |
195 | ret = qib_twsi_reset(dd); | |
196 | if (ret) { | |
197 | qib_dev_porterr(dd, ppd->port, | |
198 | "QSFP interface Reset for write failed\n"); | |
199 | ret = -EIO; | |
200 | goto deselect; | |
201 | } | |
202 | ||
203 | /* All QSFP modules are at A0 */ | |
204 | ||
205 | cnt = 0; | |
206 | while (cnt < len) { | |
207 | unsigned in_page; | |
208 | int wlen = len - cnt; | |
209 | in_page = addr % QSFP_PAGESIZE; | |
210 | if ((in_page + wlen) > QSFP_PAGESIZE) | |
211 | wlen = QSFP_PAGESIZE - in_page; | |
212 | ret = qib_twsi_blk_wr(dd, QSFP_DEV, addr, buff + cnt, wlen); | |
213 | if (ret) { | |
214 | /* qib_twsi_blk_wr() 1 for error, else 0 */ | |
215 | ret = -EIO; | |
216 | goto deselect; | |
217 | } | |
218 | addr += wlen; | |
219 | cnt += wlen; | |
220 | } | |
221 | ret = cnt; | |
222 | ||
223 | deselect: | |
224 | /* | |
225 | * Module could take up to 10 uSec after transfer before | |
226 | * ready to respond to MOD_SEL negation, and there is no way | |
227 | * to tell if it is ready, so we must wait. | |
228 | */ | |
229 | udelay(10); | |
230 | /* set QSFP MODSEL, RST, LP high */ | |
231 | dd->f_gpio_mod(dd, mask, mask, mask); | |
232 | /* | |
233 | * Module could take up to 2 Msec to respond to MOD_SEL | |
234 | * going away, and there is no way to tell if it is ready. | |
235 | * so we must wait. | |
236 | */ | |
237 | msleep(2); | |
238 | ||
239 | bail: | |
240 | mutex_unlock(&dd->eep_lock); | |
241 | ||
242 | no_unlock: | |
243 | return ret; | |
244 | } | |
245 | ||
246 | /* | |
247 | * For validation, we want to check the checksums, even of the | |
248 | * fields we do not otherwise use. This function reads the bytes from | |
249 | * <first> to <next-1> and returns the 8lsbs of the sum, or <0 for errors | |
250 | */ | |
251 | static int qsfp_cks(struct qib_pportdata *ppd, int first, int next) | |
252 | { | |
253 | int ret; | |
254 | u16 cks; | |
255 | u8 bval; | |
256 | ||
257 | cks = 0; | |
258 | while (first < next) { | |
259 | ret = qsfp_read(ppd, first, &bval, 1); | |
260 | if (ret < 0) | |
261 | goto bail; | |
262 | cks += bval; | |
263 | ++first; | |
264 | } | |
265 | ret = cks & 0xFF; | |
266 | bail: | |
267 | return ret; | |
268 | ||
269 | } | |
270 | ||
271 | int qib_refresh_qsfp_cache(struct qib_pportdata *ppd, struct qib_qsfp_cache *cp) | |
272 | { | |
273 | int ret; | |
274 | int idx; | |
275 | u16 cks; | |
f931551b RC |
276 | u8 peek[4]; |
277 | ||
278 | /* ensure sane contents on invalid reads, for cable swaps */ | |
279 | memset(cp, 0, sizeof(*cp)); | |
280 | ||
dde05cbd | 281 | if (!qib_qsfp_mod_present(ppd)) { |
f931551b RC |
282 | ret = -ENODEV; |
283 | goto bail; | |
284 | } | |
285 | ||
286 | ret = qsfp_read(ppd, 0, peek, 3); | |
287 | if (ret < 0) | |
288 | goto bail; | |
289 | if ((peek[0] & 0xFE) != 0x0C) | |
290 | qib_dev_porterr(ppd->dd, ppd->port, | |
291 | "QSFP byte0 is 0x%02X, S/B 0x0C/D\n", peek[0]); | |
292 | ||
293 | if ((peek[2] & 2) == 0) { | |
294 | /* | |
295 | * If cable is paged, rather than "flat memory", we need to | |
296 | * set the page to zero, Even if it already appears to be zero. | |
297 | */ | |
298 | u8 poke = 0; | |
299 | ret = qib_qsfp_write(ppd, 127, &poke, 1); | |
300 | udelay(50); | |
301 | if (ret != 1) { | |
302 | qib_dev_porterr(ppd->dd, ppd->port, | |
303 | "Failed QSFP Page set\n"); | |
304 | goto bail; | |
305 | } | |
306 | } | |
307 | ||
308 | ret = qsfp_read(ppd, QSFP_MOD_ID_OFFS, &cp->id, 1); | |
309 | if (ret < 0) | |
310 | goto bail; | |
311 | if ((cp->id & 0xFE) != 0x0C) | |
312 | qib_dev_porterr(ppd->dd, ppd->port, | |
313 | "QSFP ID byte is 0x%02X, S/B 0x0C/D\n", cp->id); | |
314 | cks = cp->id; | |
315 | ||
316 | ret = qsfp_read(ppd, QSFP_MOD_PWR_OFFS, &cp->pwr, 1); | |
317 | if (ret < 0) | |
318 | goto bail; | |
319 | cks += cp->pwr; | |
320 | ||
321 | ret = qsfp_cks(ppd, QSFP_MOD_PWR_OFFS + 1, QSFP_MOD_LEN_OFFS); | |
322 | if (ret < 0) | |
323 | goto bail; | |
324 | cks += ret; | |
325 | ||
326 | ret = qsfp_read(ppd, QSFP_MOD_LEN_OFFS, &cp->len, 1); | |
327 | if (ret < 0) | |
328 | goto bail; | |
329 | cks += cp->len; | |
330 | ||
331 | ret = qsfp_read(ppd, QSFP_MOD_TECH_OFFS, &cp->tech, 1); | |
332 | if (ret < 0) | |
333 | goto bail; | |
334 | cks += cp->tech; | |
335 | ||
336 | ret = qsfp_read(ppd, QSFP_VEND_OFFS, &cp->vendor, QSFP_VEND_LEN); | |
337 | if (ret < 0) | |
338 | goto bail; | |
339 | for (idx = 0; idx < QSFP_VEND_LEN; ++idx) | |
340 | cks += cp->vendor[idx]; | |
341 | ||
342 | ret = qsfp_read(ppd, QSFP_IBXCV_OFFS, &cp->xt_xcv, 1); | |
343 | if (ret < 0) | |
344 | goto bail; | |
345 | cks += cp->xt_xcv; | |
346 | ||
347 | ret = qsfp_read(ppd, QSFP_VOUI_OFFS, &cp->oui, QSFP_VOUI_LEN); | |
348 | if (ret < 0) | |
349 | goto bail; | |
350 | for (idx = 0; idx < QSFP_VOUI_LEN; ++idx) | |
351 | cks += cp->oui[idx]; | |
352 | ||
353 | ret = qsfp_read(ppd, QSFP_PN_OFFS, &cp->partnum, QSFP_PN_LEN); | |
354 | if (ret < 0) | |
355 | goto bail; | |
356 | for (idx = 0; idx < QSFP_PN_LEN; ++idx) | |
357 | cks += cp->partnum[idx]; | |
358 | ||
359 | ret = qsfp_read(ppd, QSFP_REV_OFFS, &cp->rev, QSFP_REV_LEN); | |
360 | if (ret < 0) | |
361 | goto bail; | |
362 | for (idx = 0; idx < QSFP_REV_LEN; ++idx) | |
363 | cks += cp->rev[idx]; | |
364 | ||
365 | ret = qsfp_read(ppd, QSFP_ATTEN_OFFS, &cp->atten, QSFP_ATTEN_LEN); | |
366 | if (ret < 0) | |
367 | goto bail; | |
368 | for (idx = 0; idx < QSFP_ATTEN_LEN; ++idx) | |
369 | cks += cp->atten[idx]; | |
370 | ||
371 | ret = qsfp_cks(ppd, QSFP_ATTEN_OFFS + QSFP_ATTEN_LEN, QSFP_CC_OFFS); | |
372 | if (ret < 0) | |
373 | goto bail; | |
374 | cks += ret; | |
375 | ||
376 | cks &= 0xFF; | |
377 | ret = qsfp_read(ppd, QSFP_CC_OFFS, &cp->cks1, 1); | |
378 | if (ret < 0) | |
379 | goto bail; | |
380 | if (cks != cp->cks1) | |
381 | qib_dev_porterr(ppd->dd, ppd->port, | |
382 | "QSFP cks1 is %02X, computed %02X\n", cp->cks1, | |
383 | cks); | |
384 | ||
385 | /* Second checksum covers 192 to (serial, date, lot) */ | |
386 | ret = qsfp_cks(ppd, QSFP_CC_OFFS + 1, QSFP_SN_OFFS); | |
387 | if (ret < 0) | |
388 | goto bail; | |
389 | cks = ret; | |
390 | ||
391 | ret = qsfp_read(ppd, QSFP_SN_OFFS, &cp->serial, QSFP_SN_LEN); | |
392 | if (ret < 0) | |
393 | goto bail; | |
394 | for (idx = 0; idx < QSFP_SN_LEN; ++idx) | |
395 | cks += cp->serial[idx]; | |
396 | ||
397 | ret = qsfp_read(ppd, QSFP_DATE_OFFS, &cp->date, QSFP_DATE_LEN); | |
398 | if (ret < 0) | |
399 | goto bail; | |
400 | for (idx = 0; idx < QSFP_DATE_LEN; ++idx) | |
401 | cks += cp->date[idx]; | |
402 | ||
403 | ret = qsfp_read(ppd, QSFP_LOT_OFFS, &cp->lot, QSFP_LOT_LEN); | |
404 | if (ret < 0) | |
405 | goto bail; | |
406 | for (idx = 0; idx < QSFP_LOT_LEN; ++idx) | |
407 | cks += cp->lot[idx]; | |
408 | ||
409 | ret = qsfp_cks(ppd, QSFP_LOT_OFFS + QSFP_LOT_LEN, QSFP_CC_EXT_OFFS); | |
410 | if (ret < 0) | |
411 | goto bail; | |
412 | cks += ret; | |
413 | ||
414 | ret = qsfp_read(ppd, QSFP_CC_EXT_OFFS, &cp->cks2, 1); | |
415 | if (ret < 0) | |
416 | goto bail; | |
417 | cks &= 0xFF; | |
418 | if (cks != cp->cks2) | |
419 | qib_dev_porterr(ppd->dd, ppd->port, | |
420 | "QSFP cks2 is %02X, computed %02X\n", cp->cks2, | |
421 | cks); | |
422 | return 0; | |
423 | ||
424 | bail: | |
425 | cp->id = 0; | |
426 | return ret; | |
427 | } | |
428 | ||
429 | const char * const qib_qsfp_devtech[16] = { | |
430 | "850nm VCSEL", "1310nm VCSEL", "1550nm VCSEL", "1310nm FP", | |
431 | "1310nm DFB", "1550nm DFB", "1310nm EML", "1550nm EML", | |
432 | "Cu Misc", "1490nm DFB", "Cu NoEq", "Cu Eq", | |
433 | "Undef", "Cu Active BothEq", "Cu FarEq", "Cu NearEq" | |
434 | }; | |
435 | ||
436 | #define QSFP_DUMP_CHUNK 16 /* Holds longest string */ | |
437 | #define QSFP_DEFAULT_HDR_CNT 224 | |
438 | ||
439 | static const char *pwr_codes = "1.5W2.0W2.5W3.5W"; | |
440 | ||
dde05cbd MH |
441 | int qib_qsfp_mod_present(struct qib_pportdata *ppd) |
442 | { | |
443 | u32 mask; | |
444 | int ret; | |
445 | ||
446 | mask = QSFP_GPIO_MOD_PRS_N << | |
447 | (ppd->hw_pidx * QSFP_GPIO_PORT2_SHIFT); | |
448 | ret = ppd->dd->f_gpio_mod(ppd->dd, 0, 0, 0); | |
449 | ||
450 | return !((ret & mask) >> | |
451 | ((ppd->hw_pidx * QSFP_GPIO_PORT2_SHIFT) + 3)); | |
452 | } | |
453 | ||
f931551b RC |
454 | /* |
455 | * Initialize structures that control access to QSFP. Called once per port | |
456 | * on cards that support QSFP. | |
457 | */ | |
458 | void qib_qsfp_init(struct qib_qsfp_data *qd, | |
459 | void (*fevent)(struct work_struct *)) | |
460 | { | |
461 | u32 mask, highs; | |
f931551b RC |
462 | |
463 | struct qib_devdata *dd = qd->ppd->dd; | |
464 | ||
465 | /* Initialize work struct for later QSFP events */ | |
466 | INIT_WORK(&qd->work, fevent); | |
467 | ||
468 | /* | |
469 | * Later, we may want more validation. For now, just set up pins and | |
470 | * blip reset. If module is present, call qib_refresh_qsfp_cache(), | |
471 | * to do further init. | |
472 | */ | |
473 | mask = QSFP_GPIO_MOD_SEL_N | QSFP_GPIO_MOD_RST_N | QSFP_GPIO_LP_MODE; | |
474 | highs = mask - QSFP_GPIO_MOD_RST_N; | |
475 | if (qd->ppd->hw_pidx) { | |
476 | mask <<= QSFP_GPIO_PORT2_SHIFT; | |
477 | highs <<= QSFP_GPIO_PORT2_SHIFT; | |
478 | } | |
479 | dd->f_gpio_mod(dd, highs, mask, mask); | |
480 | udelay(20); /* Generous RST dwell */ | |
481 | ||
482 | dd->f_gpio_mod(dd, mask, mask, mask); | |
f931551b RC |
483 | return; |
484 | } | |
485 | ||
486 | void qib_qsfp_deinit(struct qib_qsfp_data *qd) | |
487 | { | |
488 | /* | |
f0626710 TH |
489 | * There is nothing to do here for now. our work is scheduled |
490 | * with queue_work(), and flush_workqueue() from remove_one | |
491 | * will block until all work setup with queue_work() | |
f931551b RC |
492 | * completes. |
493 | */ | |
494 | } | |
495 | ||
496 | int qib_qsfp_dump(struct qib_pportdata *ppd, char *buf, int len) | |
497 | { | |
498 | struct qib_qsfp_cache cd; | |
499 | u8 bin_buff[QSFP_DUMP_CHUNK]; | |
500 | char lenstr[6]; | |
501 | int sofar, ret; | |
502 | int bidx = 0; | |
503 | ||
504 | sofar = 0; | |
505 | ret = qib_refresh_qsfp_cache(ppd, &cd); | |
506 | if (ret < 0) | |
507 | goto bail; | |
508 | ||
509 | lenstr[0] = ' '; | |
510 | lenstr[1] = '\0'; | |
511 | if (QSFP_IS_CU(cd.tech)) | |
512 | sprintf(lenstr, "%dM ", cd.len); | |
513 | ||
514 | sofar += scnprintf(buf + sofar, len - sofar, "PWR:%.3sW\n", pwr_codes + | |
515 | (QSFP_PWR(cd.pwr) * 4)); | |
516 | ||
517 | sofar += scnprintf(buf + sofar, len - sofar, "TECH:%s%s\n", lenstr, | |
518 | qib_qsfp_devtech[cd.tech >> 4]); | |
519 | ||
520 | sofar += scnprintf(buf + sofar, len - sofar, "Vendor:%.*s\n", | |
521 | QSFP_VEND_LEN, cd.vendor); | |
522 | ||
523 | sofar += scnprintf(buf + sofar, len - sofar, "OUI:%06X\n", | |
524 | QSFP_OUI(cd.oui)); | |
525 | ||
526 | sofar += scnprintf(buf + sofar, len - sofar, "Part#:%.*s\n", | |
527 | QSFP_PN_LEN, cd.partnum); | |
528 | sofar += scnprintf(buf + sofar, len - sofar, "Rev:%.*s\n", | |
529 | QSFP_REV_LEN, cd.rev); | |
530 | if (QSFP_IS_CU(cd.tech)) | |
531 | sofar += scnprintf(buf + sofar, len - sofar, "Atten:%d, %d\n", | |
532 | QSFP_ATTEN_SDR(cd.atten), | |
533 | QSFP_ATTEN_DDR(cd.atten)); | |
534 | sofar += scnprintf(buf + sofar, len - sofar, "Serial:%.*s\n", | |
535 | QSFP_SN_LEN, cd.serial); | |
536 | sofar += scnprintf(buf + sofar, len - sofar, "Date:%.*s\n", | |
537 | QSFP_DATE_LEN, cd.date); | |
538 | sofar += scnprintf(buf + sofar, len - sofar, "Lot:%.*s\n", | |
539 | QSFP_LOT_LEN, cd.date); | |
540 | ||
541 | while (bidx < QSFP_DEFAULT_HDR_CNT) { | |
542 | int iidx; | |
543 | ret = qsfp_read(ppd, bidx, bin_buff, QSFP_DUMP_CHUNK); | |
544 | if (ret < 0) | |
545 | goto bail; | |
546 | for (iidx = 0; iidx < ret; ++iidx) { | |
547 | sofar += scnprintf(buf + sofar, len-sofar, " %02X", | |
548 | bin_buff[iidx]); | |
549 | } | |
550 | sofar += scnprintf(buf + sofar, len - sofar, "\n"); | |
551 | bidx += QSFP_DUMP_CHUNK; | |
552 | } | |
553 | ret = sofar; | |
554 | bail: | |
555 | return ret; | |
556 | } |