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