xref: /titanic_41/usr/src/cmd/mdb/common/modules/emlxs/emlxs.c (revision d478d0a82b5f273f7eac89c8df47960d9d22820b)
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