1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at
9 * http://www.opensource.org/licenses/cddl1.txt.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2004-2011 Emulex. All rights reserved.
24 * Use is subject to license terms.
25 * Copyright 2025 Oxide Computer Company
26 */
27
28 #define DUMP_SUPPORT
29
30 #include <emlxs_mdb.h>
31 #include <emlxs_msg.h>
32 #include <emlxs_dump.h>
33 #include <emlxs_device.h>
34
35 /*
36 * MDB module linkage information:
37 */
38
39 static const mdb_dcmd_t dcmds[] =
40 {
41 { DRIVER_NAME"_msgbuf", "<instance>", "dumps the "DRIVER_NAME
42 " driver internal message buffer", emlxs_msgbuf, emlxs_msgbuf_help},
43 { DRIVER_NAME"_dump", "<type> <instance>", "dumps the "DRIVER_NAME
44 " driver firmware core", emlxs_dump, emlxs_dump_help},
45 { NULL }
46 };
47
48 static const mdb_modinfo_t modinfo =
49 {
50 MDB_API_VERSION,
51 dcmds,
52 NULL
53 };
54
55 const mdb_modinfo_t *
_mdb_init(void)56 _mdb_init(void)
57 {
58 return (&modinfo);
59 }
60
61
62 /*
63 * emlxs_msgbuf library
64 */
65 void
emlxs_msgbuf_help()66 emlxs_msgbuf_help()
67 {
68
69 mdb_printf("Usage: ::%s_msgbuf <instance(hex)>\n\n", DRIVER_NAME);
70 mdb_printf(" <instance> This is the %s driver instance " \
71 "number in hex.\n", DRIVER_NAME);
72 mdb_printf(" (e.g. 0, 1,..., e, f, etc.)\n");
73
74 } /* emlxs_msgbuf_help() */
75
76
77 /*ARGSUSED*/
emlxs_msgbuf(uintptr_t base_addr,uint_t flags,int argc,const mdb_arg_t * argv)78 int emlxs_msgbuf(uintptr_t base_addr, uint_t flags, int argc,
79 const mdb_arg_t *argv)
80 {
81 uintptr_t addr;
82 emlxs_device_t device;
83 uint32_t brd_no;
84 emlxs_msg_log_t log;
85 uint32_t count;
86 uint32_t first;
87 uint32_t last;
88 uint32_t idx;
89 uint32_t i;
90 char *level;
91 emlxs_msg_t msg;
92 char merge[1024];
93
94 emlxs_msg_entry_t entry;
95 char buffer[256];
96 char buffer2[256];
97 int32_t instance[MAX_FC_BRDS];
98 char driver[32];
99 int32_t instance_count;
100 uint32_t ddiinst;
101
102 if (argc != 1 || argv[0].a_type != MDB_TYPE_STRING) {
103 mdb_printf("Usage: ::%s_msgbuf <instance(hex)>\n",
104 DRIVER_NAME);
105 mdb_printf("mdb: try \"::help %s_msgbuf\" for more information",
106 DRIVER_NAME);
107
108 return (DCMD_ERR);
109 }
110
111 /* Get the device address */
112 mdb_snprintf(buffer, sizeof (buffer), "%s_device", DRIVER_NAME);
113 if (mdb_readvar(&device, buffer) == -1) {
114 mdb_snprintf(buffer2, sizeof (buffer2),
115 "%s not found.\n", buffer);
116 mdb_warn(buffer2);
117
118 mdb_snprintf(buffer2, sizeof (buffer2),
119 "Is the %s driver loaded ?\n", DRIVER_NAME);
120 mdb_warn(buffer2);
121 return (DCMD_ERR);
122 }
123
124 /* Get the device instance table */
125 mdb_snprintf(buffer, sizeof (buffer), "%s_instance", DRIVER_NAME);
126 if (mdb_readvar(&instance, buffer) == -1) {
127 mdb_snprintf(buffer2, sizeof (buffer2), "%s not found.\n",
128 buffer);
129 mdb_warn(buffer2);
130
131 mdb_snprintf(buffer2, sizeof (buffer2),
132 "Is the %s driver loaded ?\n", DRIVER_NAME);
133 mdb_warn(buffer2);
134 return (DCMD_ERR);
135 }
136
137 /* Get the device instance count */
138 mdb_snprintf(buffer, sizeof (buffer), "%s_instance_count", DRIVER_NAME);
139 if (mdb_readvar(&instance_count, buffer) == -1) {
140 mdb_snprintf(buffer2, sizeof (buffer2), "%s not found.\n",
141 buffer);
142 mdb_warn(buffer2);
143
144 mdb_snprintf(buffer2, sizeof (buffer2),
145 "Is the %s driver loaded ?\n", DRIVER_NAME);
146 mdb_warn(buffer2);
147 return (DCMD_ERR);
148 }
149
150 ddiinst = (uint32_t)mdb_strtoull(argv[0].a_un.a_str);
151
152 for (brd_no = 0; brd_no < instance_count; brd_no++) {
153 if (instance[brd_no] == ddiinst) {
154 break;
155 }
156 }
157
158 if (brd_no == instance_count) {
159 mdb_warn("Device instance not found. ddinst=%d\n", ddiinst);
160 return (DCMD_ERR);
161 }
162
163 /* Check if buffer is null */
164 addr = (uintptr_t)device.log[brd_no];
165 if (addr == 0) {
166 mdb_warn("Device instance not found. ddinst=%d\n", ddiinst);
167 return (0);
168 }
169
170 if (mdb_vread(&log, sizeof (emlxs_msg_log_t), addr) !=
171 sizeof (emlxs_msg_log_t)) {
172 mdb_warn("\nUnable to read %d bytes @ %llx.\n",
173 sizeof (emlxs_msg_log_t), addr);
174 return (0);
175 }
176
177 /* Check if buffer is empty */
178 if (log.count == 0) {
179 mdb_warn("Log buffer empty.\n");
180 return (0);
181 }
182
183 /* Get last entry id saved */
184 last = log.count - 1;
185
186 /* Check if buffer has already been filled once */
187 if (log.count >= log.size) {
188 first = log.count - log.size;
189 idx = log.next;
190 } else {
191 /* Buffer not yet filled */
192 first = 0;
193 idx = 0;
194 }
195
196 /* Get the total number of messages available for return */
197 count = last - first + 1;
198
199 mdb_printf("\n");
200
201 /* Print the messages */
202 for (i = 0; i < count; i++) {
203 if (mdb_vread(&entry, sizeof (emlxs_msg_entry_t),
204 (uintptr_t)&log.entry[idx]) != sizeof (emlxs_msg_entry_t)) {
205 mdb_warn("Cannot read log entry. index=%d count=%d\n",
206 idx, count);
207 return (DCMD_ERR);
208 }
209
210 if (mdb_vread(&msg, sizeof (emlxs_msg_t),
211 (uintptr_t)entry.msg) != sizeof (emlxs_msg_t)) {
212 mdb_warn("Cannot read msg. index=%d count=%d\n",
213 idx, count);
214 return (DCMD_ERR);
215 }
216
217 switch (msg.level) {
218 case EMLXS_DEBUG:
219 level = " DEBUG";
220 break;
221
222 case EMLXS_NOTICE:
223 level = " NOTICE";
224 break;
225
226 case EMLXS_WARNING:
227 level = "WARNING";
228 break;
229
230 case EMLXS_ERROR:
231 level = " ERROR";
232 break;
233
234 case EMLXS_PANIC:
235 level = " PANIC";
236 break;
237
238 default:
239 level = "UNKNOWN";
240 break;
241 }
242
243 if (entry.vpi == 0) {
244 mdb_snprintf(driver, sizeof (driver), "%s%d",
245 DRIVER_NAME, entry.instance);
246 } else {
247 mdb_snprintf(driver, sizeof (driver), "%s%d.%d",
248 DRIVER_NAME, entry.instance, entry.vpi);
249 }
250
251 /* Generate the message string */
252 if (msg.buffer[0] != 0) {
253 if (entry.buffer[0] != 0) {
254 mdb_snprintf(merge, sizeof (merge),
255 "[%Y:%03d:%03d:%03d] "
256 "%6d:[%1X.%04X]%s:%7s:%4d:\n%s\n(%s)\n",
257 entry.id_time.tv_sec,
258 (int)entry.id_time.tv_nsec/1000000,
259 (int)(entry.id_time.tv_nsec/1000)%1000,
260 (int)entry.id_time.tv_nsec%1000,
261 entry.id, entry.fileno,
262 entry.line, driver, level, msg.id,
263 msg.buffer, entry.buffer);
264
265 } else {
266 mdb_snprintf(merge, sizeof (merge),
267 "[%Y:%03d:%03d:%03d] "
268 "%6d:[%1X.%04X]%s:%7s:%4d:\n%s\n",
269 entry.id_time.tv_sec,
270 (int)entry.id_time.tv_nsec/1000000,
271 (int)(entry.id_time.tv_nsec/1000)%1000,
272 (int)entry.id_time.tv_nsec%1000,
273 entry.id, entry.fileno,
274 entry.line, driver, level, msg.id,
275 msg.buffer);
276 }
277 } else {
278 if (entry.buffer[0] != 0) {
279 mdb_snprintf(merge, sizeof (merge),
280 "[%Y:%03d:%03d:%03d] "
281 "%6d:[%1X.%04X]%s:%7s:%4d:\n(%s)\n",
282 entry.id_time.tv_sec,
283 (int)entry.id_time.tv_nsec/1000000,
284 (int)(entry.id_time.tv_nsec/1000)%1000,
285 (int)entry.id_time.tv_nsec%1000,
286 entry.id, entry.fileno,
287 entry.line, driver, level, msg.id,
288 entry.buffer);
289
290 } else {
291 mdb_snprintf(merge, sizeof (merge),
292 "[%Y:%03d:%03d:%03d] "
293 "%6d:[%1X.%04X]%s:%7s:%4d:\n%s\n",
294 entry.id_time.tv_sec,
295 (int)entry.id_time.tv_nsec/1000000,
296 (int)(entry.id_time.tv_nsec/1000)%1000,
297 (int)entry.id_time.tv_nsec%1000,
298 entry.id, entry.fileno,
299 entry.line, driver, level, msg.id,
300 msg.buffer);
301 }
302 }
303
304 mdb_printf("%s", merge);
305
306 /* Increment index */
307 if (++idx >= log.size) {
308 idx = 0;
309 }
310 }
311
312 mdb_printf("\n");
313
314 return (0);
315
316 } /* emlxs_msgbuf() */
317
318
319 void
emlxs_dump_help()320 emlxs_dump_help()
321 {
322 mdb_printf("Usage: ::%s_dump all <instance(hex)>\n", DRIVER_NAME);
323 mdb_printf(" ::%s_dump txt <instance(hex)>\n", DRIVER_NAME);
324 mdb_printf(" ::%s_dump dmp <instance(hex)>\n", DRIVER_NAME);
325 mdb_printf(" ::%s_dump cee <instance(hex)>\n", DRIVER_NAME);
326 mdb_printf("\n");
327 mdb_printf(" txt Display firmware text summary " \
328 "file.\n");
329 mdb_printf(" dmp Display firmware dmp binary file.\n");
330 mdb_printf(" cee Display firmware cee binary file. " \
331 "(FCOE adapters only)\n");
332 mdb_printf(" all Display all firmware core files.\n");
333 mdb_printf(" <instance> This is the %s driver instance " \
334 "number in hex.\n", DRIVER_NAME);
335 mdb_printf(" (e.g. 0, 1,..., e, f, etc.)\n");
336
337 } /* emlxs_dump_help() */
338
339
340 /*ARGSUSED*/
341 int
emlxs_dump(uintptr_t base_addr,uint_t flags,int argc,const mdb_arg_t * argv)342 emlxs_dump(uintptr_t base_addr, uint_t flags, int argc, const mdb_arg_t *argv)
343 {
344 uintptr_t addr;
345 emlxs_device_t device;
346 uint32_t brd_no;
347 uint32_t i;
348 char buffer[256];
349 char buffer2[256];
350 int32_t instance[MAX_FC_BRDS];
351 int32_t instance_count;
352 uint32_t ddiinst;
353 uint8_t *bptr;
354 char *cptr;
355 emlxs_file_t dump_txtfile;
356 emlxs_file_t dump_dmpfile;
357 emlxs_file_t dump_ceefile;
358 uint32_t size;
359 uint32_t file;
360
361 if (argc != 2 || argv[0].a_type != MDB_TYPE_STRING ||
362 argv[1].a_type != MDB_TYPE_STRING) {
363 goto usage;
364 }
365
366 if ((strcmp(argv[0].a_un.a_str, "all") == 0) ||
367 (strcmp(argv[0].a_un.a_str, "ALL") == 0) ||
368 (strcmp(argv[0].a_un.a_str, "All") == 0)) {
369 file = 0;
370 } else if ((strcmp(argv[0].a_un.a_str, "txt") == 0) ||
371 (strcmp(argv[0].a_un.a_str, "TXT") == 0) ||
372 (strcmp(argv[0].a_un.a_str, "Txt") == 0)) {
373 file = 1;
374 } else if ((strcmp(argv[0].a_un.a_str, "dmp") == 0) ||
375 (strcmp(argv[0].a_un.a_str, "DMP") == 0) ||
376 (strcmp(argv[0].a_un.a_str, "Dmp") == 0)) {
377 file = 2;
378 } else if ((strcmp(argv[0].a_un.a_str, "cee") == 0) ||
379 (strcmp(argv[0].a_un.a_str, "CEE") == 0) ||
380 (strcmp(argv[0].a_un.a_str, "Cee") == 0)) {
381 file = 3;
382 } else {
383 goto usage;
384 }
385
386 /* Get the device address */
387 mdb_snprintf(buffer, sizeof (buffer), "%s_device", DRIVER_NAME);
388 if (mdb_readvar(&device, buffer) == -1) {
389 mdb_snprintf(buffer2, sizeof (buffer2),
390 "%s not found.\n", buffer);
391 mdb_warn(buffer2);
392
393 mdb_snprintf(buffer2, sizeof (buffer2),
394 "Is the %s driver loaded ?\n", DRIVER_NAME);
395 mdb_warn(buffer2);
396 return (DCMD_ERR);
397 }
398
399 /* Get the device instance table */
400 mdb_snprintf(buffer, sizeof (buffer), "%s_instance", DRIVER_NAME);
401 if (mdb_readvar(&instance, buffer) == -1) {
402 mdb_snprintf(buffer2, sizeof (buffer2), "%s not found.\n",
403 buffer);
404 mdb_warn(buffer2);
405
406 mdb_snprintf(buffer2, sizeof (buffer2),
407 "Is the %s driver loaded ?\n", DRIVER_NAME);
408 mdb_warn(buffer2);
409 return (DCMD_ERR);
410 }
411
412 /* Get the device instance count */
413 mdb_snprintf(buffer, sizeof (buffer), "%s_instance_count", DRIVER_NAME);
414 if (mdb_readvar(&instance_count, buffer) == -1) {
415 mdb_snprintf(buffer2, sizeof (buffer2), "%s not found.\n",
416 buffer);
417 mdb_warn(buffer2);
418
419 mdb_snprintf(buffer2, sizeof (buffer2),
420 "Is the %s driver loaded ?\n", DRIVER_NAME);
421 mdb_warn(buffer2);
422 return (DCMD_ERR);
423 }
424
425 ddiinst = (uint32_t)mdb_strtoull(argv[1].a_un.a_str);
426
427 for (brd_no = 0; brd_no < instance_count; brd_no++) {
428 if (instance[brd_no] == ddiinst) {
429 break;
430 }
431 }
432
433 if (brd_no == instance_count) {
434 mdb_warn("Device instance not found. ddinst=%d\n", ddiinst);
435 return (DCMD_ERR);
436 }
437
438 if (file == 0 || file == 1) {
439
440 addr = (uintptr_t)device.dump_txtfile[brd_no];
441 if (addr == 0) {
442 mdb_warn("TXT file: Device instance not found. " \
443 "ddinst=%d\n", ddiinst);
444 goto dmp_file;
445 }
446
447 if (mdb_vread(&dump_txtfile, sizeof (dump_txtfile), addr)
448 != sizeof (dump_txtfile)) {
449 mdb_warn("TXT file: Unable to read %d bytes @ %llx.\n",
450 sizeof (dump_txtfile), addr);
451 goto dmp_file;
452 }
453
454 size = (uintptr_t)dump_txtfile.ptr -
455 (uintptr_t)dump_txtfile.buffer;
456
457 if (size == 0) {
458 mdb_printf("TXT file: Not available.\n");
459 goto dmp_file;
460 }
461 bptr = (uint8_t *)mdb_zalloc(size, UM_SLEEP|UM_GC);
462
463 if (bptr == 0) {
464 mdb_warn("TXT file: Unable to allocate file buffer. " \
465 "ddinst=%d size=%d\n", ddiinst, size);
466 goto dmp_file;
467 }
468
469 if (mdb_vread(bptr, size, (uintptr_t)dump_txtfile.buffer)
470 != size) {
471 mdb_warn("TXT file: Unable to read %d bytes @ %llx.\n",
472 size, dump_txtfile.buffer);
473 goto dmp_file;
474 }
475
476 mdb_printf("<TXT File Start>\n");
477 mdb_printf("\n");
478 mdb_printf("%s", bptr);
479 mdb_printf("\n");
480 mdb_printf("<TXT File End>\n");
481 }
482
483 dmp_file:
484
485 if (file == 0 || file == 2) {
486 addr = (uintptr_t)device.dump_dmpfile[brd_no];
487 if (addr == 0) {
488 mdb_warn("DMP file: Device instance not found. " \
489 "ddinst=%d\n", ddiinst);
490 goto cee_file;
491 }
492
493 if (mdb_vread(&dump_dmpfile, sizeof (dump_dmpfile), addr)
494 != sizeof (dump_dmpfile)) {
495 mdb_warn("DMP file: Unable to read %d bytes @ %llx.\n",
496 sizeof (dump_dmpfile), addr);
497 goto cee_file;
498 }
499
500 size = (uintptr_t)dump_dmpfile.ptr -
501 (uintptr_t)dump_dmpfile.buffer;
502
503 if (size == 0) {
504 mdb_printf("DMP file: Not available.\n");
505 goto cee_file;
506 }
507
508 bptr = (uint8_t *)mdb_zalloc(size, UM_SLEEP|UM_GC);
509
510 if (bptr == 0) {
511 mdb_warn("DMP file: Unable to allocate file buffer. " \
512 "ddinst=%d size=%d\n", ddiinst, size);
513 goto cee_file;
514 }
515
516 if (mdb_vread(bptr, size, (uintptr_t)dump_dmpfile.buffer)
517 != size) {
518 mdb_warn("DMP file: Unable to read %d bytes @ %llx.\n",
519 size, dump_dmpfile.buffer);
520 goto cee_file;
521 }
522
523 mdb_printf("<DMP File Start>\n");
524 mdb_printf("\n");
525
526 bzero(buffer2, sizeof (buffer2));
527 cptr = buffer2;
528 for (i = 0; i < size; i++) {
529 if (i && !(i % 16)) {
530 mdb_printf(" %s\n", buffer2);
531 bzero(buffer2, sizeof (buffer2));
532 cptr = buffer2;
533 }
534
535 if (!(i % 16)) {
536 mdb_printf("%08X: ", i);
537 }
538
539 if (!(i % 4)) {
540 mdb_printf(" ");
541 }
542
543 if ((*bptr >= 32) && (*bptr <= 126)) {
544 *cptr++ = *bptr;
545 } else {
546 *cptr++ = '.';
547 }
548
549 mdb_printf("%02X ", *bptr++);
550 }
551
552 size = 16 - (i % 16);
553 for (i = 0; size < 16 && i < size; i++) {
554 if (!(i % 4)) {
555 mdb_printf(" ");
556 }
557
558 mdb_printf(" ");
559 }
560 mdb_printf(" %s\n", buffer2);
561 mdb_printf("\n");
562 mdb_printf("<DMP File End>\n");
563 }
564
565 cee_file:
566
567 if (file == 0 || file == 3) {
568
569 addr = (uintptr_t)device.dump_ceefile[brd_no];
570 if (addr == 0) {
571 mdb_warn("CEE file: Device instance not found. " \
572 "ddinst=%d\n", ddiinst);
573 goto done;
574 }
575
576 if (mdb_vread(&dump_ceefile, sizeof (dump_ceefile), addr)
577 != sizeof (dump_ceefile)) {
578 mdb_warn("CEE file: Unable to read %d bytes @ %llx.\n",
579 sizeof (dump_ceefile), addr);
580 goto done;
581 }
582
583 size = (uintptr_t)dump_ceefile.ptr -
584 (uintptr_t)dump_ceefile.buffer;
585
586 if (size == 0) {
587 mdb_printf("CEE file: Not available.\n");
588 goto done;
589 }
590
591 bptr = (uint8_t *)mdb_zalloc(size, UM_SLEEP|UM_GC);
592
593 if (bptr == 0) {
594 mdb_warn("CEE file: Unable to allocate file buffer. " \
595 "ddinst=%d size=%d\n", ddiinst, size);
596 goto done;
597 }
598
599 if (mdb_vread(bptr, size, (uintptr_t)dump_ceefile.buffer)
600 != size) {
601 mdb_warn("CEE file: Unable to read %d bytes @ %llx.\n",
602 size, dump_ceefile.buffer);
603 goto done;
604 }
605
606 mdb_printf("<CEE File Start>\n");
607 mdb_printf("\n");
608
609 bzero(buffer2, sizeof (buffer2));
610 cptr = buffer2;
611 for (i = 0; i < size; i++) {
612 if (i && !(i % 16)) {
613 mdb_printf(" %s\n", buffer2);
614 bzero(buffer2, sizeof (buffer2));
615 cptr = buffer2;
616 }
617
618 if (!(i % 16)) {
619 mdb_printf("%08X: ", i);
620 }
621
622 if (!(i % 4)) {
623 mdb_printf(" ");
624 }
625
626 if ((*bptr >= 32) && (*bptr <= 126)) {
627 *cptr++ = *bptr;
628 } else {
629 *cptr++ = '.';
630 }
631
632 mdb_printf("%02X ", *bptr++);
633 }
634
635 size = 16 - (i % 16);
636 for (i = 0; size < 16 && i < size; i++) {
637 if (!(i % 4)) {
638 mdb_printf(" ");
639 }
640
641 mdb_printf(" ");
642 }
643 mdb_printf(" %s\n", buffer2);
644 mdb_printf("\n");
645 mdb_printf("<CEE File End>\n");
646 }
647 done:
648
649 mdb_printf("\n");
650 return (0);
651
652 usage:
653 mdb_printf("Usage: ::%s_dump <file> <instance (hex)>\n",
654 DRIVER_NAME);
655 mdb_printf("mdb: try \"::help %s_dump\" for more information",
656 DRIVER_NAME);
657
658 return (DCMD_ERR);
659
660 } /* emlxs_dump() */
661