xref: /illumos-gate/usr/src/cmd/mdb/common/modules/emlxs/emlxs.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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 usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
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 2009 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 	{ "emlxs_msgbuf", "<instance>", "dumps the emlxs driver internal " \
41 	    "message buffer", emlxs_msgbuf, emlxs_msgbuf_help},
42 	{ "emlxs_dump", "<type> <instance>", "dumps the emlxs driver " \
43 	    "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 *
55 _mdb_init(void)
56 {
57 	return (&modinfo);
58 }
59 
60 
61 /*
62  * emlxs_msgbuf library
63  */
64 void
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*/
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 	uint32_t secs;
92 	uint32_t hsecs;
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 		hsecs = (entry.time%100);
217 		secs  = entry.time/100;
218 
219 		switch (msg.level) {
220 		case EMLXS_DEBUG:
221 			level = "  DEBUG";
222 			break;
223 
224 		case EMLXS_NOTICE:
225 			level = " NOTICE";
226 			break;
227 
228 		case EMLXS_WARNING:
229 			level = "WARNING";
230 			break;
231 
232 		case EMLXS_ERROR:
233 			level = "  ERROR";
234 			break;
235 
236 		case EMLXS_PANIC:
237 			level = "  PANIC";
238 			break;
239 
240 		case EMLXS_EVENT:
241 			level = "  EVENT";
242 			break;
243 
244 		default:
245 			level = "UNKNOWN";
246 			break;
247 		}
248 
249 		if (entry.vpi == 0) {
250 			mdb_snprintf(driver, sizeof (driver), "%s%d",
251 			    DRIVER_NAME, entry.instance);
252 		} else {
253 			mdb_snprintf(driver, sizeof (driver), "%s%d.%d",
254 			    DRIVER_NAME, entry.instance, entry.vpi);
255 		}
256 
257 		/* Generate the message string */
258 		if (msg.buffer[0] != 0) {
259 			if (entry.buffer[0] != 0) {
260 				mdb_snprintf(buffer, sizeof (buffer),
261 				    "%8d.%02d: "
262 				    "%6d:[%1X.%04X]%s:%7s:%4d: %s\n(%s)\n",
263 				    secs, hsecs, entry.id, entry.fileno,
264 				    entry.line, driver, level, msg.id,
265 				    msg.buffer, entry.buffer);
266 
267 			} else {
268 				mdb_snprintf(buffer, sizeof (buffer),
269 				    "%8d.%02d: %6d:[%1X.%04X]%s:%7s:%4d: %s\n",
270 				    secs, hsecs, entry.id, entry.fileno,
271 				    entry.line, driver, level, msg.id,
272 				    msg.buffer);
273 			}
274 		} else {
275 			if (entry.buffer[0] != 0) {
276 				mdb_snprintf(buffer, sizeof (buffer),
277 				    "%8d.%02d: "
278 				    "%6d:[%1X.%04X]%s:%7s:%4d:\n(%s)\n",
279 				    secs, hsecs, entry.id, entry.fileno,
280 				    entry.line, driver, level, msg.id,
281 				    entry.buffer);
282 			} else {
283 				mdb_snprintf(buffer, sizeof (buffer),
284 				    "%8d.%02d: %6d:[%1X.%04X]%s:%7s:%4d:\n",
285 				    secs, hsecs, entry.id, entry.fileno,
286 				    entry.line, driver, level, msg.id);
287 			}
288 		}
289 
290 		mdb_printf("%s", buffer);
291 
292 		/* Increment index */
293 		if (++idx >= log.size) {
294 			idx = 0;
295 		}
296 	}
297 
298 	mdb_printf("\n");
299 
300 	return (0);
301 
302 } /* emlxs_msgbuf() */
303 
304 
305 void
306 emlxs_dump_help()
307 {
308 	mdb_printf("Usage:   ::%s_dump all <instance(hex)>\n", DRIVER_NAME);
309 	mdb_printf("         ::%s_dump txt <instance(hex)>\n", DRIVER_NAME);
310 	mdb_printf("         ::%s_dump dmp <instance(hex)>\n", DRIVER_NAME);
311 	mdb_printf("         ::%s_dump cee <instance(hex)>\n", DRIVER_NAME);
312 	mdb_printf("\n");
313 	mdb_printf("                txt   Display firmware text summary " \
314 	    "file.\n");
315 	mdb_printf("                dmp   Display firmware dmp binary file.\n");
316 	mdb_printf("                cee   Display firmware cee binary file. " \
317 	    "(FCOE adapters only)\n");
318 	mdb_printf("                all   Display all firmware core files.\n");
319 	mdb_printf("         <instance>   This is the %s driver instance " \
320 	    "number in hex.\n", DRIVER_NAME);
321 	mdb_printf("                      (e.g. 0, 1,..., e, f, etc.)\n");
322 
323 } /* emlxs_dump_help() */
324 
325 
326 /*ARGSUSED*/
327 int
328 emlxs_dump(uintptr_t base_addr, uint_t flags, int argc,
329 				const mdb_arg_t *argv)
330 {
331 	uintptr_t  addr;
332 	emlxs_device_t device;
333 	uint32_t brd_no;
334 	uint32_t i;
335 	char buffer[256];
336 	char buffer2[256];
337 	int32_t instance[MAX_FC_BRDS];
338 	int32_t instance_count;
339 	uint32_t ddiinst;
340 	uint8_t *bptr;
341 	char *cptr;
342 	emlxs_file_t dump_txtfile;
343 	emlxs_file_t dump_dmpfile;
344 	emlxs_file_t dump_ceefile;
345 	uint32_t size;
346 	uint32_t file;
347 
348 	if (argc != 2) {
349 		goto usage;
350 	}
351 
352 	if ((strcmp(argv[0].a_un.a_str, "all") == 0) ||
353 	    (strcmp(argv[0].a_un.a_str, "ALL") == 0) ||
354 	    (strcmp(argv[0].a_un.a_str, "All") == 0)) {
355 		file = 0;
356 	} else if ((strcmp(argv[0].a_un.a_str, "txt") == 0) ||
357 	    (strcmp(argv[0].a_un.a_str, "TXT") == 0) ||
358 	    (strcmp(argv[0].a_un.a_str, "Txt") == 0)) {
359 		file = 1;
360 	} else if ((strcmp(argv[0].a_un.a_str, "dmp") == 0) ||
361 	    (strcmp(argv[0].a_un.a_str, "DMP") == 0) ||
362 	    (strcmp(argv[0].a_un.a_str, "Dmp") == 0)) {
363 		file = 2;
364 	} else if ((strcmp(argv[0].a_un.a_str, "cee") == 0) ||
365 	    (strcmp(argv[0].a_un.a_str, "CEE") == 0) ||
366 	    (strcmp(argv[0].a_un.a_str, "Cee") == 0)) {
367 		file = 3;
368 	} else {
369 		goto usage;
370 	}
371 
372 	/* Get the device address */
373 	mdb_snprintf(buffer, sizeof (buffer), "%s_device", DRIVER_NAME);
374 	if (mdb_readvar(&device, buffer) == -1) {
375 		mdb_snprintf(buffer2, sizeof (buffer2),
376 		    "%s not found.\n", buffer);
377 		mdb_warn(buffer2);
378 
379 		mdb_snprintf(buffer2, sizeof (buffer2),
380 		    "Is the %s driver loaded ?\n", DRIVER_NAME);
381 		mdb_warn(buffer2);
382 		return (DCMD_ERR);
383 	}
384 
385 	/* Get the device instance table */
386 	mdb_snprintf(buffer, sizeof (buffer), "%s_instance", DRIVER_NAME);
387 	if (mdb_readvar(&instance, buffer) == -1) {
388 		mdb_snprintf(buffer2, sizeof (buffer2), "%s not found.\n",
389 		    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 count */
399 	mdb_snprintf(buffer, sizeof (buffer), "%s_instance_count", DRIVER_NAME);
400 	if (mdb_readvar(&instance_count, 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 	ddiinst = (uint32_t)mdb_strtoull(argv[1].a_un.a_str);
412 
413 	for (brd_no = 0; brd_no < instance_count; brd_no++) {
414 		if (instance[brd_no] == ddiinst) {
415 			break;
416 		}
417 	}
418 
419 	if (brd_no == instance_count) {
420 		mdb_warn("Device instance not found. ddinst=%d\n", ddiinst);
421 		return (DCMD_ERR);
422 	}
423 
424 	if (file == 0 || file == 1) {
425 
426 		addr = (uintptr_t)device.dump_txtfile[brd_no];
427 		if (addr == 0) {
428 			mdb_warn("TXT file: Device instance not found. " \
429 			    "ddinst=%d\n", ddiinst);
430 			goto dmp_file;
431 		}
432 
433 		if (mdb_vread(&dump_txtfile, sizeof (dump_txtfile), addr)
434 		    != sizeof (dump_txtfile)) {
435 			mdb_warn("TXT file: Unable to read %d bytes @ %llx.\n",
436 			    sizeof (dump_txtfile), addr);
437 			goto dmp_file;
438 		}
439 
440 		size = (uintptr_t)dump_txtfile.ptr -
441 		    (uintptr_t)dump_txtfile.buffer;
442 
443 		if (size == 0) {
444 			mdb_printf("TXT file: Not available.\n");
445 			goto dmp_file;
446 		}
447 		bptr  = (uint8_t *)mdb_zalloc(size, UM_SLEEP|UM_GC);
448 
449 		if (bptr == 0) {
450 			mdb_warn("TXT file: Unable to allocate file buffer. " \
451 			    "ddinst=%d size=%d\n", ddiinst, size);
452 			goto dmp_file;
453 		}
454 
455 		if (mdb_vread(bptr, size, (uintptr_t)dump_txtfile.buffer)
456 		    != size) {
457 			mdb_warn("TXT file: Unable to read %d bytes @ %llx.\n",
458 			    size, dump_txtfile.buffer);
459 			goto dmp_file;
460 		}
461 
462 		mdb_printf("<TXT File Start>\n");
463 		mdb_printf("\n");
464 		mdb_printf("%s", bptr);
465 		mdb_printf("\n");
466 		mdb_printf("<TXT File End>\n");
467 	}
468 
469 dmp_file:
470 
471 	if (file == 0 || file == 2) {
472 		addr = (uintptr_t)device.dump_dmpfile[brd_no];
473 		if (addr == 0) {
474 			mdb_warn("DMP file: Device instance not found. " \
475 			    "ddinst=%d\n", ddiinst);
476 			goto cee_file;
477 		}
478 
479 		if (mdb_vread(&dump_dmpfile, sizeof (dump_dmpfile), addr)
480 		    != sizeof (dump_dmpfile)) {
481 			mdb_warn("DMP file: Unable to read %d bytes @ %llx.\n",
482 			    sizeof (dump_dmpfile), addr);
483 			goto cee_file;
484 		}
485 
486 		size = (uintptr_t)dump_dmpfile.ptr -
487 		    (uintptr_t)dump_dmpfile.buffer;
488 
489 		if (size == 0) {
490 			mdb_printf("DMP file: Not available.\n");
491 			goto cee_file;
492 		}
493 
494 		bptr  = (uint8_t *)mdb_zalloc(size, UM_SLEEP|UM_GC);
495 
496 		if (bptr == 0) {
497 			mdb_warn("DMP file: Unable to allocate file buffer. " \
498 			    "ddinst=%d size=%d\n", ddiinst, size);
499 			goto cee_file;
500 		}
501 
502 		if (mdb_vread(bptr, size, (uintptr_t)dump_dmpfile.buffer)
503 		    != size) {
504 			mdb_warn("DMP file: Unable to read %d bytes @ %llx.\n",
505 			    size, dump_dmpfile.buffer);
506 			goto cee_file;
507 		}
508 
509 		mdb_printf("<DMP File Start>\n");
510 		mdb_printf("\n");
511 
512 		bzero(buffer2, sizeof (buffer2));
513 		cptr = buffer2;
514 		for (i = 0; i < size; i++) {
515 			if (i && !(i % 16)) {
516 				mdb_printf(" %s\n", buffer2);
517 				bzero(buffer2, sizeof (buffer2));
518 				cptr = buffer2;
519 			}
520 
521 			if (!(i % 16)) {
522 				mdb_printf("%08X: ", i);
523 			}
524 
525 			if (!(i % 4)) {
526 				mdb_printf(" ");
527 			}
528 
529 			if ((*bptr >= 32) && (*bptr <= 126)) {
530 				*cptr++ = *bptr;
531 			} else {
532 				*cptr++ = '.';
533 			}
534 
535 			mdb_printf("%02X ", *bptr++);
536 		}
537 
538 		size = 16 - (i % 16);
539 		for (i = 0; size < 16 && i < size; i++) {
540 			if (!(i % 4)) {
541 				mdb_printf(" ");
542 			}
543 
544 			mdb_printf("   ");
545 		}
546 		mdb_printf(" %s\n", buffer2);
547 		mdb_printf("\n");
548 		mdb_printf("<DMP File End>\n");
549 	}
550 
551 cee_file:
552 
553 	if (file == 0 || file == 3) {
554 
555 		addr = (uintptr_t)device.dump_ceefile[brd_no];
556 		if (addr == 0) {
557 			mdb_warn("CEE file: Device instance not found. " \
558 			    "ddinst=%d\n", ddiinst);
559 			goto done;
560 		}
561 
562 		if (mdb_vread(&dump_ceefile, sizeof (dump_ceefile), addr)
563 		    != sizeof (dump_ceefile)) {
564 			mdb_warn("CEE file: Unable to read %d bytes @ %llx.\n",
565 			    sizeof (dump_ceefile), addr);
566 			goto done;
567 		}
568 
569 		size = (uintptr_t)dump_ceefile.ptr -
570 		    (uintptr_t)dump_ceefile.buffer;
571 
572 		if (size == 0) {
573 			mdb_printf("CEE file: Not available.\n");
574 			goto done;
575 		}
576 
577 		bptr  = (uint8_t *)mdb_zalloc(size, UM_SLEEP|UM_GC);
578 
579 		if (bptr == 0) {
580 			mdb_warn("CEE file: Unable to allocate file buffer. " \
581 			    "ddinst=%d size=%d\n", ddiinst, size);
582 			goto done;
583 		}
584 
585 		if (mdb_vread(bptr, size, (uintptr_t)dump_ceefile.buffer)
586 		    != size) {
587 			mdb_warn("CEE file: Unable to read %d bytes @ %llx.\n",
588 			    size, dump_ceefile.buffer);
589 			goto done;
590 		}
591 
592 		mdb_printf("<CEE File Start>\n");
593 		mdb_printf("\n");
594 
595 		bzero(buffer2, sizeof (buffer2));
596 		cptr = buffer2;
597 		for (i = 0; i < size; i++) {
598 			if (i && !(i % 16)) {
599 				mdb_printf(" %s\n", buffer2);
600 				bzero(buffer2, sizeof (buffer2));
601 				cptr = buffer2;
602 			}
603 
604 			if (!(i % 16)) {
605 				mdb_printf("%08X: ", i);
606 			}
607 
608 			if (!(i % 4)) {
609 				mdb_printf(" ");
610 			}
611 
612 			if ((*bptr >= 32) && (*bptr <= 126)) {
613 				*cptr++ = *bptr;
614 			} else {
615 				*cptr++ = '.';
616 			}
617 
618 			mdb_printf("%02X ", *bptr++);
619 		}
620 
621 		size = 16 - (i % 16);
622 		for (i = 0; size < 16 && i < size; i++) {
623 			if (!(i % 4)) {
624 				mdb_printf(" ");
625 			}
626 
627 			mdb_printf("   ");
628 		}
629 		mdb_printf(" %s\n", buffer2);
630 		mdb_printf("\n");
631 		mdb_printf("<CEE File End>\n");
632 	}
633 done:
634 
635 	mdb_printf("\n");
636 	return (0);
637 
638 usage:
639 	mdb_printf("Usage:   ::%s_dump <file> <instance (hex)>\n",
640 	    DRIVER_NAME);
641 	mdb_printf("mdb: try \"::help %s_dump\" for more information",
642 	    DRIVER_NAME);
643 
644 	return (DCMD_ERR);
645 
646 } /* emlxs_dump() */
647