xref: /illumos-gate/usr/src/cmd/mdb/common/modules/fctl/fctl.c (revision fa4a3e77edc40df6d92e8da6fc4961d275e9896d)
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  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * Copyright 2019 Joyent, Inc.
28  */
29 
30 #include <sys/mdb_modapi.h>
31 #include <sys/mutex.h>
32 #include <sys/modctl.h>
33 #include <time.h>
34 #include <sys/fibre-channel/fc.h>
35 #include <sys/fibre-channel/impl/fctl_private.h>
36 #include <sys/fibre-channel/impl/fc_ulpif.h>
37 #include <sys/fibre-channel/impl/fc_portif.h>
38 #include <sys/fibre-channel/impl/fc_fcaif.h>
39 
40 
41 /*
42  * If we #include <string.h> then other definitions fail. This is
43  * the easiest way of getting access to the function
44  */
45 extern char *strtok(char *string, const char *sepset);
46 
47 /* we need 26 bytes for the cftime() call */
48 #define	TIMESTAMPSIZE	26 * sizeof (char)
49 
50 /* for backward compatibility */
51 typedef struct fc_trace_dmsgv1 {
52 	int			id_size;
53 	int			id_flag;
54 	time_t			id_time;
55 	caddr_t			id_buf;
56 	struct fc_trace_dmsgv1	*id_next;
57 } fc_trace_dmsgv1_t;
58 
59 static struct pwwn_hash *fp_pwwn_table;
60 static struct d_id_hash *fp_did_table;
61 static uint32_t pd_hash_index;
62 struct fc_local_port port;
63 
64 /*
65  * Leadville port walker/dcmd code
66  */
67 
68 /*
69  * Initialize the fc_fca_port_t walker by either using the given starting
70  * address, or reading the value of the kernel's fctl_fca_portlist pointer.
71  * We also allocate a fc_fca_port_t for storage, and save this using the
72  * walk_data pointer.
73  */
74 static int
75 port_walk_i(mdb_walk_state_t *wsp)
76 {
77 	if (wsp->walk_addr == 0 &&
78 	    mdb_readvar(&wsp->walk_addr, "fctl_fca_portlist") == -1) {
79 		mdb_warn("failed to read 'fctl_fca_portlist'");
80 		return (WALK_ERR);
81 	}
82 
83 	wsp->walk_data = mdb_alloc(sizeof (fc_fca_port_t), UM_SLEEP);
84 	return (WALK_NEXT);
85 }
86 
87 /*
88  * At each step, read a fc_fca_port_t into our private storage, and then invoke
89  * the callback function.  We terminate when we reach a NULL p_next pointer.
90  */
91 static int
92 port_walk_s(mdb_walk_state_t *wsp)
93 {
94 	int status;
95 
96 	if (wsp->walk_addr == 0)
97 		return (WALK_DONE);
98 
99 	if (mdb_vread(wsp->walk_data, sizeof (fc_fca_port_t), wsp->walk_addr)
100 	    == -1) {
101 		mdb_warn("failed to read fc_fca_port_t at %p", wsp->walk_addr);
102 		return (WALK_DONE);
103 	}
104 
105 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
106 	    wsp->walk_cbdata);
107 
108 	wsp->walk_addr =
109 	    (uintptr_t)(((fc_fca_port_t *)wsp->walk_data)->port_next);
110 
111 	return (status);
112 }
113 
114 /*
115  * The walker's fini function is invoked at the end of each walk.  Since we
116  * dynamically allocated a fc_fca_port_t in port_walk_i, we must free it now.
117  */
118 static void
119 port_walk_f(mdb_walk_state_t *wsp)
120 {
121 	mdb_free(wsp->walk_data, sizeof (fc_fca_port_t));
122 }
123 
124 
125 static int
126 ports(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
127 {
128 	fc_fca_port_t	portlist;
129 	fc_local_port_t port;
130 	int		longlist = FALSE;
131 
132 	if (argc > 1) {
133 		return (DCMD_USAGE);
134 	}
135 
136 	if (mdb_getopts(argc, argv,
137 	    'l', MDB_OPT_SETBITS, TRUE, &longlist, NULL) != argc) {
138 		return (DCMD_USAGE);
139 	}
140 
141 
142 	if (!(flags & DCMD_ADDRSPEC)) {
143 		if (longlist == 0) {
144 			if (mdb_walk_dcmd("ports", "ports",
145 			    argc, argv) == -1) {
146 				mdb_warn("failed to walk 'fctl_fca_portlist'");
147 				return (DCMD_ERR);
148 			}
149 		} else {
150 			if (mdb_walk_dcmd("ports", "fcport",
151 			    argc, argv) == -1) {
152 				mdb_warn("failed to walk 'fctl_fca_portlist'");
153 				return (DCMD_ERR);
154 			}
155 		}
156 
157 		return (DCMD_OK);
158 	}
159 
160 	/*
161 	 * If this is the first invocation of the command, print a nice
162 	 * header line for the output that will follow.
163 	 */
164 	if (DCMD_HDRSPEC(flags))
165 		mdb_printf("%16s %-2s %4s %-4s%16s %16s %16s\n",
166 		    "Port", "I#", "State", "Soft", "FCA Handle",
167 		    "Port DIP", "FCA Port DIP");
168 
169 	/*
170 	 * For each port, we just need to read the fc_fca_port_t struct, read
171 	 * the port_handle
172 	 */
173 	if (mdb_vread(&portlist, sizeof (fc_fca_port_t), addr) ==
174 	    sizeof (fc_fca_port_t)) {
175 		/*
176 		 * Now read that port in
177 		 */
178 
179 		if (mdb_vread(&port, sizeof (fc_local_port_t), (uintptr_t)
180 		    portlist.port_handle) == sizeof (fc_local_port_t)) {
181 			mdb_printf("%16p %2d %4x %4x %16p %16p %16p\n",
182 			    portlist.port_handle, port.fp_instance,
183 			    port.fp_state, port.fp_soft_state,
184 			    port.fp_fca_handle, port.fp_port_dip,
185 			    port.fp_fca_dip);
186 		} else
187 			mdb_warn("failed to read port at %p",
188 			    portlist.port_handle);
189 
190 	} else
191 		mdb_warn("failed to read port info at %p", addr);
192 
193 	return (DCMD_OK);
194 }
195 
196 
197 /*
198  * Leadville ULP walker/dcmd code
199  */
200 
201 static int
202 ulp_walk_i(mdb_walk_state_t *wsp)
203 {
204 	if (wsp->walk_addr == 0 &&
205 	    mdb_readvar(&wsp->walk_addr, "fctl_ulp_list") == -1) {
206 		mdb_warn("failed to read 'fctl_ulp_list'");
207 		return (WALK_ERR);
208 	}
209 
210 	wsp->walk_data = mdb_alloc(sizeof (fc_ulp_list_t), UM_SLEEP);
211 	return (WALK_NEXT);
212 }
213 
214 
215 
216 static int
217 ulp_walk_s(mdb_walk_state_t *wsp)
218 {
219 	int status;
220 
221 	if (wsp->walk_addr == 0)
222 		return (WALK_DONE);
223 
224 	if (mdb_vread(wsp->walk_data, sizeof (fc_ulp_list_t), wsp->walk_addr)
225 	    == -1) {
226 		mdb_warn("failed to read fctl_ulp_list %p", wsp->walk_addr);
227 		return (WALK_DONE);
228 	}
229 
230 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
231 	    wsp->walk_cbdata);
232 
233 	wsp->walk_addr =
234 	    (uintptr_t)(((fc_ulp_list_t *)wsp->walk_data)->ulp_next);
235 
236 	return (status);
237 }
238 
239 
240 static void
241 ulp_walk_f(mdb_walk_state_t *wsp)
242 {
243 	mdb_free(wsp->walk_data, sizeof (fc_ulp_list_t));
244 }
245 
246 
247 static int
248 ulps(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
249 {
250 	fc_ulp_list_t		ulplist;
251 	fc_ulp_modinfo_t	ulp;
252 	char			ulp_name[30];
253 
254 	if (argc != 0) {
255 		return (DCMD_USAGE);
256 	}
257 
258 	/*
259 	 * If no fc_ulp_list_t address was specified on the command line, we can
260 	 * print out all processes by invoking the walker, using this
261 	 * dcmd itself as the callback.
262 	 */
263 	if (!(flags & DCMD_ADDRSPEC)) {
264 		if (mdb_walk_dcmd("ulps", "ulps", argc, argv) == -1) {
265 			mdb_warn("failed to walk 'fc_ulp_list_t'");
266 			return (DCMD_ERR);
267 		}
268 		return (DCMD_OK);
269 	}
270 
271 	/*
272 	 * If this is the first invocation of the command, print a nice
273 	 * header line for the output that will follow.
274 	 */
275 	if (DCMD_HDRSPEC(flags))
276 		mdb_printf("%30s %4s %8s\n", "ULP Name", "Type", "Revision");
277 
278 	/*
279 	 * For each port, we just need to read the fc_fca_port_t struct, read
280 	 * the port_handle
281 	 */
282 	if (mdb_vread(&ulplist, sizeof (fc_ulp_list_t), addr) ==
283 	    sizeof (fc_ulp_list_t)) {
284 		/*
285 		 * Now read that port in
286 		 */
287 
288 		if (mdb_vread(&ulp, sizeof (fc_ulp_modinfo_t),
289 		    (uintptr_t)ulplist.ulp_info) == sizeof (fc_ulp_modinfo_t)) {
290 			if (mdb_vread(&ulp_name, 30,
291 			    (uintptr_t)ulp.ulp_name) > 0) {
292 				mdb_printf("%30s %4x %8x\n",
293 				    ulp_name, ulp.ulp_type, ulp.ulp_rev);
294 			}
295 		} else
296 			mdb_warn("failed to read ulp at %p",
297 			    ulplist.ulp_info);
298 
299 	} else
300 		mdb_warn("failed to read ulplist at %p", addr);
301 
302 	return (DCMD_OK);
303 }
304 
305 
306 
307 /*
308  * Leadville ULP module walker/dcmd code
309  */
310 
311 static int
312 ulpmod_walk_i(mdb_walk_state_t *wsp)
313 {
314 	if (wsp->walk_addr == 0 &&
315 	    mdb_readvar(&wsp->walk_addr, "fctl_ulp_modules") == -1) {
316 		mdb_warn("failed to read 'fctl_ulp_modules'");
317 		return (WALK_ERR);
318 	}
319 
320 	wsp->walk_data = mdb_alloc(sizeof (fc_ulp_module_t), UM_SLEEP);
321 	return (WALK_NEXT);
322 }
323 
324 
325 
326 static int
327 ulpmod_walk_s(mdb_walk_state_t *wsp)
328 {
329 	int status;
330 
331 	if (wsp->walk_addr == 0)
332 		return (WALK_DONE);
333 
334 	if (mdb_vread(wsp->walk_data, sizeof (fc_ulp_module_t), wsp->walk_addr)
335 	    == -1) {
336 		mdb_warn("failed to read fctl_ulp_modules %p", wsp->walk_addr);
337 		return (WALK_DONE);
338 	}
339 
340 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
341 	    wsp->walk_cbdata);
342 
343 	wsp->walk_addr =
344 	    (uintptr_t)(((fc_ulp_module_t *)wsp->walk_data)->mod_next);
345 
346 	return (status);
347 }
348 
349 
350 static void
351 ulpmod_walk_f(mdb_walk_state_t *wsp)
352 {
353 	mdb_free(wsp->walk_data, sizeof (fc_ulp_module_t));
354 }
355 
356 
357 static int
358 ulpmods(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
359 {
360 	fc_ulp_module_t		modlist;
361 	fc_ulp_modinfo_t	modinfo;
362 	fc_ulp_ports_t		ulp_port;
363 
364 	if (argc != 0) {
365 		return (DCMD_USAGE);
366 	}
367 
368 	if (!(flags & DCMD_ADDRSPEC)) {
369 		if (mdb_walk_dcmd("ulpmods", "ulpmods", argc, argv)
370 		    == -1) {
371 			mdb_warn("failed to walk 'fc_ulp_module_t'");
372 			return (DCMD_ERR);
373 		}
374 		return (DCMD_OK);
375 	}
376 
377 	/*
378 	 * If this is the first invocation of the command, print a nice
379 	 * header line for the output that will follow.
380 	 */
381 	if (DCMD_HDRSPEC(flags))
382 		mdb_printf("%4s %16s %8s %8s\n",
383 		    "Type", "Port Handle", "dstate", "statec");
384 
385 	/*
386 	 * For each port, we just need to read the fc_fca_port_t struct, read
387 	 * the port_handle
388 	 */
389 	if (mdb_vread(&modlist, sizeof (fc_ulp_module_t), addr) ==
390 	    sizeof (fc_ulp_module_t)) {
391 		/*
392 		 * Now read that module info in
393 		 */
394 
395 		if (mdb_vread(&modinfo, sizeof (fc_ulp_modinfo_t),
396 		    (uintptr_t)modlist.mod_info) == sizeof (fc_ulp_modinfo_t)) {
397 			/* Now read all the ports for this module */
398 			if (mdb_vread(&ulp_port, sizeof (fc_ulp_ports_t),
399 			    (uintptr_t)modlist.mod_ports) ==
400 			    sizeof (fc_ulp_ports_t)) {
401 				while (ulp_port.port_handle != NULL) {
402 					mdb_printf("%4x %16p %8x %8x\n",
403 					    modinfo.ulp_type,
404 					    ulp_port.port_handle,
405 					    ulp_port.port_dstate,
406 					    ulp_port.port_statec);
407 
408 					if (ulp_port.port_next == NULL)
409 						break;
410 
411 					mdb_vread(&ulp_port,
412 					    sizeof (fc_ulp_ports_t),
413 					    (uintptr_t)ulp_port.port_next);
414 				}
415 			}
416 		} else
417 			mdb_warn("failed to read modinfo at %p",
418 			    modlist.mod_info);
419 
420 	} else
421 		mdb_warn("failed to read modlist at %p", addr);
422 
423 	return (DCMD_OK);
424 }
425 
426 
427 /*
428  * Display an fc_local_port_t struct
429  */
430 static int
431 fcport(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
432 {
433 	fc_fca_port_t	portlist;
434 	fc_local_port_t	port;
435 	int		idx;
436 	int		first = 1;
437 	int		walking_fc_fca_portlist = 0;
438 
439 	if (argc != 0) {
440 		int result;
441 
442 		if (argc != 1)
443 			return (DCMD_USAGE);
444 
445 		if (argv->a_type != MDB_TYPE_STRING)
446 			return (DCMD_USAGE);
447 
448 		walking_fc_fca_portlist = 1;
449 	}
450 
451 	if (!(flags & DCMD_ADDRSPEC)) {
452 		mdb_printf("Sorry, you must provide an address\n");
453 		return (DCMD_ERR);
454 	}
455 
456 	if (walking_fc_fca_portlist) {
457 		/*
458 		 * Must read the fc_fca_portlist to get the fc_local_port addr
459 		 */
460 		if (mdb_vread(&portlist, sizeof (fc_fca_port_t), addr) ==
461 		    sizeof (fc_fca_port_t)) {
462 			addr = (uintptr_t)portlist.port_handle;
463 		}
464 	}
465 
466 	mdb_printf("Reading fc_local_port_t at %p:\n", addr);
467 
468 	/*
469 	 * For each port, we just need to read the fc_local_port_t struct
470 	 */
471 
472 	if (mdb_vread(&port, sizeof (fc_local_port_t),
473 	    addr) == sizeof (fc_local_port_t)) {
474 		mdb_printf("  fp_mutex          : 0x%p\n", port.fp_mutex);
475 		mdb_printf("  fp_state          : 0x%-8x\n", port.fp_state);
476 		mdb_printf("  fp_port_id        : 0x%-06x\n",
477 		    port.fp_port_id.port_id);
478 		mdb_printf("  fp_fca_handle     : 0x%p\n", port.fp_fca_handle);
479 		mdb_printf("  fp_fca_tran       : 0x%p\n", port.fp_fca_tran);
480 		mdb_printf("  fp_job_head       : 0x%p\n", port.fp_job_head);
481 		mdb_printf("  fp_job_tail       : 0x%p\n", port.fp_job_tail);
482 		mdb_printf("  fp_wait_head      : 0x%p\n", port.fp_wait_head);
483 		mdb_printf("  fp_wait_tail      : 0x%p\n", port.fp_wait_tail);
484 		mdb_printf("  fp_topology       : %u\n", port.fp_topology);
485 		mdb_printf("  fp_task           : %d\n", port.fp_task);
486 		mdb_printf("  fp_last_task      : %d\n", port.fp_last_task);
487 		mdb_printf("  fp_soft_state     : 0x%-4x\n",
488 		    port.fp_soft_state);
489 		mdb_printf("  fp_flag           : 0x%-2x\n", port.fp_flag);
490 		mdb_printf("  fp_statec_busy    : 0x%-8x\n",
491 		    port.fp_statec_busy);
492 		mdb_printf("  fp_port_num       : %d\n", port.fp_port_num);
493 		mdb_printf("  fp_instance       : %d\n", port.fp_instance);
494 		mdb_printf("  fp_ulp_attach     : %d\n", port.fp_ulp_attach);
495 		mdb_printf("  fp_dev_count      : %d\n", port.fp_dev_count);
496 		mdb_printf("  fp_total_devices  : %d\n", port.fp_total_devices);
497 		mdb_printf("  fp_bind_state     : 0x%-8x\n",
498 		    port.fp_bind_state);
499 		mdb_printf("  fp_options        : 0x%-8x\n", port.fp_options);
500 		mdb_printf("  fp_port_type      : 0x%-2x\n",
501 		    port.fp_port_type.port_type);
502 		mdb_printf("  fp_ub_count       : %d\n", port.fp_ub_count);
503 		mdb_printf("  fp_active_ubs     : %d\n", port.fp_active_ubs);
504 		mdb_printf("  fp_port_dip       : 0x%p\n", port.fp_port_dip);
505 		mdb_printf("  fp_fca_dip        : 0x%p\n", port.fp_fca_dip);
506 
507 		for (idx = 0; idx < 16; idx++) {
508 			if (port.fp_ip_addr[idx] != 0)
509 				break;
510 		}
511 
512 		if (idx != 16) {
513 			mdb_printf("  fp_ip_addr        : %-2x:%-2x:%-2x:%-2x:"
514 			    "%-2x:%-2x:%-2x:%-2x:%-2x:%-2x:%-2x:%-2x:%-2x:%-2x"
515 			    ":%-2x:%-2x\n",
516 			    port.fp_ip_addr[0], port.fp_ip_addr[1],
517 			    port.fp_ip_addr[2], port.fp_ip_addr[3],
518 			    port.fp_ip_addr[4], port.fp_ip_addr[5],
519 			    port.fp_ip_addr[6], port.fp_ip_addr[7],
520 			    port.fp_ip_addr[8], port.fp_ip_addr[9],
521 			    port.fp_ip_addr[10], port.fp_ip_addr[11],
522 			    port.fp_ip_addr[12], port.fp_ip_addr[13],
523 			    port.fp_ip_addr[14], port.fp_ip_addr[15]);
524 		} else {
525 			mdb_printf("  fp_ip_addr        : N/A\n");
526 		}
527 
528 		mdb_printf("  fp_fc4_types      : ");
529 
530 		for (idx = 0; idx < 8; idx++) {
531 			if (port.fp_fc4_types[idx] != 0) {
532 				if (first) {
533 					mdb_printf("%d",
534 					    port.fp_fc4_types[idx]);
535 					first = 0;
536 				} else {
537 					mdb_printf(", %d",
538 					    port.fp_fc4_types[idx]);
539 				}
540 			}
541 		}
542 
543 		if (first) {
544 			mdb_printf("None\n");
545 		} else {
546 			mdb_printf("\n");
547 		}
548 
549 		mdb_printf("  fp_pm_level       : %d\n", port.fp_pm_level);
550 		mdb_printf("  fp_pm_busy        : %d\n", port.fp_pm_busy);
551 		mdb_printf("  fp_pm_busy_nocomp : 0x%-8x\n",
552 		    port.fp_pm_busy_nocomp);
553 		mdb_printf("  fp_hard_addr      : 0x%-6x\n",
554 		    port.fp_hard_addr.hard_addr);
555 		mdb_printf("  fp_sym_port_name  : \"%s\"\n",
556 		    port.fp_sym_port_name);
557 		mdb_printf("  fp_sym_node_name  : \"%s\"\n",
558 		    port.fp_sym_node_name);
559 		mdb_printf("  fp_rscn_count     : %d\n", port.fp_rscn_count);
560 	} else {
561 		mdb_warn("failed to read fc_local_port_t at 0x%p", addr);
562 	}
563 
564 	mdb_printf("\n");
565 
566 	return (DCMD_OK);
567 }
568 
569 
570 /*
571  * Leadville remote_port walker/dcmd code
572  */
573 
574 /*
575  * We need to be given the address of a port structure in order to start
576  * walking.  From that, we can read the pwwn table.
577  */
578 static int
579 pd_by_pwwn_walk_i(mdb_walk_state_t *wsp)
580 {
581 	fc_local_port_t port;
582 
583 	if (wsp->walk_addr == 0) {
584 		mdb_warn("pd_by_pwwn walk doesn't support global walks\n");
585 		return (WALK_ERR);
586 	}
587 
588 	/*
589 	 * Allocate space for the pwwn_hash table
590 	 */
591 
592 	fp_pwwn_table = mdb_alloc(sizeof (struct pwwn_hash) *
593 	    PWWN_HASH_TABLE_SIZE, UM_SLEEP);
594 
595 	/*
596 	 * Input should be an fc_local_port_t, so read it to get the pwwn
597 	 * table's head
598 	 */
599 
600 	if (mdb_vread(&port, sizeof (fc_local_port_t), wsp->walk_addr) !=
601 	    sizeof (fc_local_port_t)) {
602 		mdb_warn("Unable to read in the port structure address\n");
603 		return (WALK_ERR);
604 	}
605 
606 	if (mdb_vread(fp_pwwn_table, sizeof (struct pwwn_hash) *
607 	    PWWN_HASH_TABLE_SIZE, (uintptr_t)port.fp_pwwn_table) == -1) {
608 		mdb_warn("Unable to read in the pwwn hash table\n");
609 		return (WALK_ERR);
610 	}
611 
612 	pd_hash_index = 0;
613 
614 	while ((fp_pwwn_table[pd_hash_index].pwwn_head == NULL) &&
615 	    (pd_hash_index < PWWN_HASH_TABLE_SIZE)) {
616 		pd_hash_index++;
617 	}
618 
619 	wsp->walk_addr = (uintptr_t)fp_pwwn_table[pd_hash_index].pwwn_head;
620 
621 	wsp->walk_data = mdb_alloc(sizeof (fc_remote_port_t), UM_SLEEP);
622 	return (WALK_NEXT);
623 }
624 
625 /*
626  * At each step, read a fc_remote_port_t into our private storage, and then
627  * invoke the callback function.  We terminate when we reach a NULL p_next
628  * pointer.
629  */
630 static int
631 pd_by_pwwn_walk_s(mdb_walk_state_t *wsp)
632 {
633 	int status;
634 
635 	if ((wsp->walk_addr == 0) &&
636 	    (pd_hash_index >= (PWWN_HASH_TABLE_SIZE - 1))) {
637 		return (WALK_DONE);
638 	}
639 
640 	if (mdb_vread(wsp->walk_data, sizeof (fc_remote_port_t), wsp->walk_addr)
641 	    == -1) {
642 		mdb_warn("failed to read fc_remote_port at %p", wsp->walk_addr);
643 		return (WALK_DONE);
644 	}
645 
646 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
647 	    wsp->walk_cbdata);
648 
649 	wsp->walk_addr =
650 	    (uintptr_t)(((fc_remote_port_t *)wsp->walk_data)->pd_wwn_hnext);
651 
652 	if (wsp->walk_addr == 0) {
653 		/*
654 		 * Try the next hash list, if there is one.
655 		 */
656 
657 		pd_hash_index++;
658 
659 		while ((fp_pwwn_table[pd_hash_index].pwwn_head == NULL) &&
660 		    (pd_hash_index < PWWN_HASH_TABLE_SIZE)) {
661 			pd_hash_index++;
662 		}
663 
664 		if (pd_hash_index == PWWN_HASH_TABLE_SIZE) {
665 			/* We're done */
666 			return (status);
667 		}
668 
669 		wsp->walk_addr =
670 		    (uintptr_t)fp_pwwn_table[pd_hash_index].pwwn_head;
671 	}
672 
673 	return (status);
674 }
675 
676 /*
677  * The walker's fini function is invoked at the end of each walk.
678  */
679 static void
680 pd_by_pwwn_walk_f(mdb_walk_state_t *wsp)
681 {
682 	mdb_free(wsp->walk_data, sizeof (fc_remote_port_t));
683 	mdb_free(fp_pwwn_table, sizeof (struct pwwn_hash) *
684 	    PWWN_HASH_TABLE_SIZE);
685 	fp_pwwn_table = NULL;
686 }
687 
688 /*
689  * This is the same walker as pd_by_pwwn, but we walk the D_ID hash table
690  */
691 
692 static int
693 pd_by_did_walk_i(mdb_walk_state_t *wsp)
694 {
695 	fc_local_port_t port;
696 
697 	if (wsp->walk_addr == 0) {
698 		mdb_warn("pd_by_did walk doesn't support global walks\n");
699 		return (WALK_ERR);
700 	}
701 
702 	/*
703 	 * Allocate space for the did_hash table
704 	 */
705 
706 	fp_did_table = mdb_alloc(sizeof (struct d_id_hash) *
707 	    D_ID_HASH_TABLE_SIZE, UM_SLEEP);
708 
709 	/*
710 	 * Input should be an fc_local_port_t, so read it to get the d_id
711 	 * table's head
712 	 */
713 
714 	if (mdb_vread(&port, sizeof (fc_local_port_t), wsp->walk_addr) !=
715 	    sizeof (fc_local_port_t)) {
716 		mdb_warn("Unable to read in the port structure address\n");
717 		return (WALK_ERR);
718 	}
719 
720 	if (mdb_vread(fp_did_table, sizeof (struct d_id_hash) *
721 	    D_ID_HASH_TABLE_SIZE, (uintptr_t)port.fp_did_table) == -1) {
722 		mdb_warn("Unable to read in the D_ID hash table\n");
723 		return (WALK_ERR);
724 	}
725 	pd_hash_index = 0;
726 
727 	while ((fp_did_table[pd_hash_index].d_id_head == NULL) &&
728 	    (pd_hash_index < D_ID_HASH_TABLE_SIZE)) {
729 		pd_hash_index++;
730 	}
731 
732 	wsp->walk_addr = (uintptr_t)fp_did_table[pd_hash_index].d_id_head;
733 
734 	wsp->walk_data = mdb_alloc(sizeof (fc_remote_port_t), UM_SLEEP);
735 	return (WALK_NEXT);
736 }
737 
738 /*
739  * At each step, read a fc_remote_port_t into our private storage, and then
740  * invoke the callback function.  We terminate when we reach a NULL p_next
741  * pointer.
742  */
743 static int
744 pd_by_did_walk_s(mdb_walk_state_t *wsp)
745 {
746 	int status;
747 
748 	if ((wsp->walk_addr == 0) &&
749 	    (pd_hash_index >= (D_ID_HASH_TABLE_SIZE - 1))) {
750 		return (WALK_DONE);
751 	}
752 
753 	if (mdb_vread(wsp->walk_data, sizeof (fc_remote_port_t), wsp->walk_addr)
754 	    == -1) {
755 		mdb_warn("failed to read fc_remote_port at %p", wsp->walk_addr);
756 		return (WALK_DONE);
757 	}
758 
759 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
760 	    wsp->walk_cbdata);
761 
762 	wsp->walk_addr =
763 	    (uintptr_t)(((fc_remote_port_t *)wsp->walk_data)->pd_did_hnext);
764 
765 	if (wsp->walk_addr == 0) {
766 		/*
767 		 * Try the next hash list, if there is one.
768 		 */
769 
770 		pd_hash_index++;
771 
772 		while ((fp_did_table[pd_hash_index].d_id_head == NULL) &&
773 		    (pd_hash_index < D_ID_HASH_TABLE_SIZE)) {
774 			pd_hash_index++;
775 		}
776 
777 		if (pd_hash_index == D_ID_HASH_TABLE_SIZE) {
778 			/* We're done */
779 			return (status);
780 		}
781 
782 		wsp->walk_addr =
783 		    (uintptr_t)fp_did_table[pd_hash_index].d_id_head;
784 	}
785 
786 	return (status);
787 }
788 
789 /*
790  * The walker's fini function is invoked at the end of each walk.
791  */
792 static void
793 pd_by_did_walk_f(mdb_walk_state_t *wsp)
794 {
795 	mdb_free(wsp->walk_data, sizeof (fc_remote_port_t));
796 	mdb_free(fp_did_table, sizeof (struct d_id_hash) *
797 	    D_ID_HASH_TABLE_SIZE);
798 	fp_did_table = NULL;
799 }
800 
801 
802 /*
803  * Display a remote_port structure
804  */
805 static int
806 remote_port(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
807 {
808 	fc_remote_port_t	pd;
809 	int			idx;
810 	int			first = 1;
811 
812 	if (argc > 0) {
813 		return (DCMD_USAGE);
814 	}
815 
816 	if (!(flags & DCMD_ADDRSPEC)) {
817 		mdb_printf("Sorry, you must provide an address\n");
818 		return (DCMD_ERR);
819 	}
820 
821 	if (mdb_vread(&pd, sizeof (fc_remote_port_t), addr) !=
822 	    sizeof (fc_remote_port_t)) {
823 		mdb_warn("Error reading pd at 0x%x\n", addr);
824 		return (DCMD_ERR);
825 	}
826 
827 	mdb_printf("Reading remote_port at 0x%p\n", addr);
828 	mdb_printf("  mutex          : 0x%p\n", pd.pd_mutex);
829 	mdb_printf("  port_id        : 0x%-8x\n", pd.pd_port_id);
830 	mdb_printf("  port_name      : 0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
831 	    pd.pd_port_name.raw_wwn[0], pd.pd_port_name.raw_wwn[1],
832 	    pd.pd_port_name.raw_wwn[2], pd.pd_port_name.raw_wwn[3],
833 	    pd.pd_port_name.raw_wwn[4], pd.pd_port_name.raw_wwn[5],
834 	    pd.pd_port_name.raw_wwn[6], pd.pd_port_name.raw_wwn[7]);
835 	mdb_printf("  login_count    : %d\n", pd.pd_login_count);
836 	mdb_printf("  state          : 0x%x ", pd.pd_state);
837 
838 	switch (pd.pd_state) {
839 	case PORT_DEVICE_INVALID:
840 		mdb_printf("(invalid)\n");
841 		break;
842 	case PORT_DEVICE_VALID:
843 		mdb_printf("(valid)\n");
844 		break;
845 	case PORT_DEVICE_LOGGED_IN:
846 		mdb_printf("(logged in)\n");
847 		break;
848 	default:
849 		mdb_printf("(Unknown state)\n");
850 	}
851 
852 	mdb_printf("  remote node    : 0x%p\n", pd.pd_remote_nodep);
853 	mdb_printf("  hard_addr      : 0x%x\n", pd.pd_hard_addr);
854 	mdb_printf("  local port     : 0x%p\n", pd.pd_port);
855 	mdb_printf("  type           : %d ", pd.pd_type);
856 
857 	switch (pd.pd_type) {
858 	case PORT_DEVICE_NOCHANGE:
859 		mdb_printf("(No change)\n");
860 		break;
861 	case PORT_DEVICE_NEW:
862 		mdb_printf("(New)\n");
863 		break;
864 	case PORT_DEVICE_OLD:
865 		mdb_printf("(Old)\n");
866 		break;
867 	case PORT_DEVICE_CHANGED:
868 		mdb_printf("(Changed)\n");
869 		break;
870 	case PORT_DEVICE_DELETE:
871 		mdb_printf("(Delete)\n");
872 		break;
873 	case PORT_DEVICE_USER_LOGIN:
874 		mdb_printf("(User login)\n");
875 		break;
876 	case PORT_DEVICE_USER_LOGOUT:
877 		mdb_printf("(User logout)\n");
878 		break;
879 	case PORT_DEVICE_USER_CREATE:
880 		mdb_printf("(User create)\n");
881 		break;
882 	case PORT_DEVICE_USER_DELETE:
883 		mdb_printf("(User delete)\n");
884 		break;
885 	default:
886 		mdb_printf("(Unknown type)\n");
887 	}
888 
889 	mdb_printf("  flags          : 0x%x ", pd.pd_flags);
890 
891 	switch (pd.pd_flags) {
892 	case PD_IDLE:
893 		mdb_printf("(Idle)\n");
894 		break;
895 	case PD_ELS_IN_PROGRESS:
896 		mdb_printf("(ELS in progress)\n");
897 		break;
898 	case PD_ELS_MARK:
899 		mdb_printf("(Mark)\n");
900 		break;
901 	default:
902 		mdb_printf("(Unknown flag value)\n");
903 	}
904 
905 	mdb_printf("  login_class    : 0x%x\n", pd.pd_login_class);
906 	mdb_printf("  recipient      : %d\n", pd.pd_recepient);
907 	mdb_printf("  ref_count      : %d\n", pd.pd_ref_count);
908 	mdb_printf("  aux_flags      : 0x%x ", pd.pd_aux_flags);
909 
910 	first = 1;
911 	if (pd.pd_aux_flags & PD_IN_DID_QUEUE) {
912 		mdb_printf("(IN_DID_QUEUE");
913 		first = 0;
914 	}
915 
916 	if (pd.pd_aux_flags & PD_DISABLE_RELOGIN) {
917 		if (first) {
918 			mdb_printf("(DISABLE_RELOGIN");
919 		} else {
920 			mdb_printf(", DISABLE_RELOGIN");
921 		}
922 		first = 0;
923 	}
924 
925 	if (pd.pd_aux_flags & PD_NEEDS_REMOVAL) {
926 		if (first) {
927 			mdb_printf("(NEEDS_REMOVAL");
928 		} else {
929 			mdb_printf(", NEEDS_REMOVAL");
930 		}
931 		first = 0;
932 	}
933 
934 	if (pd.pd_aux_flags & PD_LOGGED_OUT) {
935 		if (first) {
936 			mdb_printf("(LOGGED_OUT");
937 		} else {
938 			mdb_printf(", LOGGED_OUT");
939 		}
940 		first = 0;
941 	}
942 
943 	if (pd.pd_aux_flags & PD_GIVEN_TO_ULPS) {
944 		if (first) {
945 			mdb_printf("(GIVEN_TO_ULPS");
946 		} else {
947 			mdb_printf(", GIVEN_TO_ULPS");
948 		}
949 		first = 0;
950 	}
951 
952 	if (first == 0) {
953 		mdb_printf(")\n");
954 	} else {
955 		mdb_printf("\n");
956 	}
957 
958 	mdb_printf("  sig            : %p\n", pd.pd_logo_tc.sig);
959 	mdb_printf("  active         : %d\n", pd.pd_logo_tc.active);
960 	mdb_printf("  counter        : %d\n", pd.pd_logo_tc.counter);
961 	mdb_printf("  max_value      : %d\n", pd.pd_logo_tc.max_value);
962 	mdb_printf("  timer          : %d\n", pd.pd_logo_tc.timer);
963 	mdb_printf("\n");
964 
965 	return (DCMD_OK);
966 }
967 
968 int
969 fc_dump_logmsg(fc_trace_dmsg_t *addr, uint_t pktstart, uint_t pktend,
970     uint_t *printed)
971 {
972 	fc_trace_dmsg_t	msg;
973 	caddr_t		buf;
974 	char		merge[1024];
975 	caddr_t		tmppkt;
976 	char		*tmpbuf; /* for tokenising the buffer */
977 	uint_t		pktnum = 0;
978 
979 	while (addr != NULL) {
980 		if (mdb_vread(&msg, sizeof (msg), (uintptr_t)addr) !=
981 		    sizeof (msg)) {
982 			mdb_warn("failed to read message pointer in kernel");
983 			return (DCMD_ERR);
984 		}
985 
986 		if (msg.id_size) {
987 
988 			buf = mdb_alloc(msg.id_size + 1, UM_SLEEP);
989 			tmppkt = mdb_alloc(msg.id_size + 1, UM_SLEEP);
990 
991 			if (mdb_vread(buf, msg.id_size,
992 			    (uintptr_t)msg.id_buf) != msg.id_size) {
993 				mdb_warn("failed to read buffer contents"
994 				    " in kernel");
995 				mdb_free(buf, msg.id_size + 1);
996 				return (DCMD_ERR);
997 			}
998 
999 			if (buf[0] == '\n') {
1000 				mdb_printf("There is a problem in"
1001 				    "the buffer\n");
1002 			}
1003 			/* funky packet processing stuff */
1004 			bcopy(buf, tmppkt, msg.id_size + 1);
1005 
1006 			/* find the equals sign, and put a null there */
1007 			tmpbuf = strchr(tmppkt, '=');
1008 			*tmpbuf = 0;
1009 			pktnum = (uint_t)mdb_strtoull(tmppkt);
1010 
1011 			if ((pktnum >= pktstart) && (pktnum <= pktend)) {
1012 				(void) mdb_snprintf(merge, sizeof (merge),
1013 				    "[%Y:%03d:%03d:%03d] %s",
1014 				    msg.id_time.tv_sec,
1015 				    (int)msg.id_time.tv_nsec/1000000,
1016 				    (int)(msg.id_time.tv_nsec/1000)%1000,
1017 				    (int)msg.id_time.tv_nsec%1000, buf);
1018 				mdb_printf("%s", merge);
1019 				if (printed != NULL)
1020 					(*printed) ++;
1021 			}
1022 			mdb_free(buf, msg.id_size + 1);
1023 			mdb_free(tmppkt, msg.id_size + 1);
1024 		}
1025 		addr = msg.id_next;
1026 	}
1027 
1028 	return (DCMD_OK);
1029 }
1030 
1031 int
1032 fc_dump_old_logmsg(fc_trace_dmsgv1_t *addr, uint_t pktstart, uint_t pktend,
1033     uint_t *printed)
1034 {
1035 	fc_trace_dmsgv1_t	msg;
1036 	caddr_t			buf;
1037 	char			merge[1024];
1038 	caddr_t			tmppkt;
1039 	char			*tmpbuf; /* for tokenising the buffer */
1040 	uint_t			pktnum = 0;
1041 
1042 	while (addr != NULL) {
1043 		if (mdb_vread(&msg, sizeof (msg), (uintptr_t)addr) !=
1044 		    sizeof (msg)) {
1045 			mdb_warn("failed to read message pointer in kernel");
1046 			return (DCMD_ERR);
1047 		}
1048 
1049 		if (msg.id_size) {
1050 
1051 			buf = mdb_alloc(msg.id_size + 1, UM_SLEEP);
1052 			tmppkt = mdb_alloc(msg.id_size + 1, UM_SLEEP);
1053 
1054 			if (mdb_vread(buf, msg.id_size,
1055 			    (uintptr_t)msg.id_buf) != msg.id_size) {
1056 				mdb_warn("failed to read buffer contents"
1057 				    " in kernel");
1058 				mdb_free(buf, msg.id_size + 1);
1059 				return (DCMD_ERR);
1060 			}
1061 
1062 			if (buf[0] == '\n') {
1063 				mdb_printf("There is a problem in"
1064 				    "the buffer\n");
1065 			}
1066 			/* funky packet processing stuff */
1067 			bcopy(buf, tmppkt, msg.id_size + 1);
1068 
1069 			tmpbuf = strchr(tmppkt, '=');
1070 			*tmpbuf = 0;
1071 			pktnum = (uint_t)mdb_strtoull(tmppkt);
1072 
1073 			if ((pktnum >= pktstart) && (pktnum <= pktend)) {
1074 				(void) mdb_snprintf(merge, sizeof (merge),
1075 				    "[%Y] %s", msg.id_time, buf);
1076 				mdb_printf("%s", merge);
1077 				if (printed != NULL)
1078 					(*printed) ++;
1079 			}
1080 			mdb_free(buf, msg.id_size + 1);
1081 			mdb_free(tmppkt, msg.id_size + 1);
1082 		}
1083 		addr = msg.id_next;
1084 	}
1085 
1086 	return (DCMD_OK);
1087 }
1088 
1089 int
1090 fc_trace_dump(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1091 {
1092 	fc_trace_logq_t logq;
1093 	uint_t		pktnum = 0;
1094 	uint_t		printed = 0; /* have we printed anything? */
1095 
1096 	uintptr_t	pktstart = 0;
1097 	uintptr_t	pktend = UINT_MAX;
1098 	int		rval = DCMD_OK;
1099 
1100 	if (mdb_vread(&logq, sizeof (logq), addr) != sizeof (logq)) {
1101 		mdb_warn("Failed to read log queue in kernel");
1102 		return (DCMD_ERR);
1103 	}
1104 
1105 	if (mdb_getopts(argc, argv,
1106 	    's', MDB_OPT_UINTPTR, &pktstart,
1107 	    'e', MDB_OPT_UINTPTR, &pktend,
1108 	    NULL) != argc) {
1109 		return (DCMD_USAGE);
1110 	}
1111 
1112 	if (pktstart > pktend) {
1113 		return (DCMD_USAGE);
1114 	}
1115 
1116 	if ((logq.il_flags & FC_TRACE_LOGQ_V2) != 0) {
1117 		rval = fc_dump_logmsg((fc_trace_dmsg_t *)logq.il_msgh, pktstart,
1118 		    pktend, &printed);
1119 	} else {
1120 		rval = fc_dump_old_logmsg((fc_trace_dmsgv1_t *)logq.il_msgh,
1121 		    pktstart, pktend, &printed);
1122 	}
1123 
1124 	if (rval != DCMD_OK) {
1125 		return (rval);
1126 	}
1127 
1128 	if (printed == 0) {
1129 		mdb_printf("No packets in the buffer match the"
1130 		    " criteria given");
1131 	}
1132 
1133 	return (rval);
1134 }
1135 
1136 int
1137 fp_trace_dump(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1138 {
1139 	if (mdb_readvar(&addr, "fp_logq") == -1) {
1140 		mdb_warn("failed to read fp_logq");
1141 		return (DCMD_ERR);
1142 	}
1143 
1144 	if (DCMD_HDRSPEC(flags)) {
1145 		mdb_printf("fp trace buffer contents\n");
1146 	}
1147 
1148 	return (fc_trace_dump(addr, flags, argc, argv));
1149 }
1150 
1151 
1152 int
1153 fcp_trace_dump(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1154 {
1155 	if (mdb_readvar(&addr, "fcp_logq") == -1) {
1156 		mdb_warn("failed to read fcp_logq");
1157 		return (DCMD_ERR);
1158 	}
1159 
1160 	if (DCMD_HDRSPEC(flags)) {
1161 		mdb_printf("fcp trace buffer contents\n");
1162 	}
1163 
1164 	return (fc_trace_dump(addr, flags, argc, argv));
1165 }
1166 
1167 /*
1168  * Leadville job_request walker/dcmd code
1169  */
1170 
1171 /*
1172  * We need to be given the address of a local port structure in order to start
1173  * walking.  From that, we can read the job_request list.
1174  */
1175 
1176 static int
1177 job_request_walk_i(mdb_walk_state_t *wsp)
1178 {
1179 	if (wsp->walk_addr == 0) {
1180 		mdb_warn("The address of a fc_local_port"
1181 		    " structure must be given\n");
1182 		return (WALK_ERR);
1183 	}
1184 
1185 	/*
1186 	 * Input should be a fc_local_port_t, so read it to get the job_request
1187 	 * lists's head
1188 	 */
1189 
1190 	if (mdb_vread(&port, sizeof (fc_local_port_t), wsp->walk_addr) !=
1191 	    sizeof (fc_local_port_t)) {
1192 		mdb_warn("Failed to read in the fc_local_port"
1193 		    " at 0x%p\n", wsp->walk_addr);
1194 		return (WALK_ERR);
1195 	}
1196 
1197 	wsp->walk_addr = (uintptr_t)(port.fp_job_head);
1198 	wsp->walk_data = mdb_alloc(sizeof (struct job_request), UM_SLEEP);
1199 
1200 	return (WALK_NEXT);
1201 }
1202 
1203 static int
1204 job_request_walk_s(mdb_walk_state_t *wsp)
1205 {
1206 	int status;
1207 
1208 	if (wsp->walk_addr == 0)
1209 		return (WALK_DONE);
1210 
1211 	if (mdb_vread(wsp->walk_data, sizeof (struct job_request),
1212 	    wsp->walk_addr) == -1) {
1213 		mdb_warn("Failed to read in the job_request at 0x%p\n",
1214 		    wsp->walk_addr);
1215 		return (WALK_DONE);
1216 	}
1217 
1218 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
1219 	    wsp->walk_cbdata);
1220 
1221 	wsp->walk_addr =
1222 	    (uintptr_t)(((struct job_request *)wsp->walk_data)->job_next);
1223 
1224 	return (status);
1225 }
1226 
1227 /*
1228  * The walker's fini function is invoked at the end of each walk.
1229  */
1230 static void
1231 job_request_walk_f(mdb_walk_state_t *wsp)
1232 {
1233 	mdb_free(wsp->walk_data, sizeof (struct job_request));
1234 }
1235 
1236 
1237 /*
1238  * Leadville fc_orphan walker/dcmd code
1239  */
1240 
1241 /*
1242  * We need to be given the address of a port structure in order to start
1243  * walking.  From that, we can read the orphan list.
1244  */
1245 
1246 static int
1247 orphan_walk_i(mdb_walk_state_t *wsp)
1248 {
1249 	if (wsp->walk_addr == 0) {
1250 		mdb_warn("The address of a fc_local_port"
1251 		    " structure must be given\n");
1252 		return (WALK_ERR);
1253 	}
1254 
1255 	/*
1256 	 * Input should be a fc_local_port_t, so read it to get the orphan
1257 	 * lists's head
1258 	 */
1259 
1260 	if (mdb_vread(&port, sizeof (fc_local_port_t), wsp->walk_addr) !=
1261 	    sizeof (fc_local_port_t)) {
1262 		mdb_warn("Failed to read in the fc_local_port"
1263 		    " at 0x%p\n", wsp->walk_addr);
1264 		return (WALK_ERR);
1265 	}
1266 
1267 	wsp->walk_addr = (uintptr_t)(port.fp_orphan_list);
1268 	wsp->walk_data = mdb_alloc(sizeof (struct fc_orphan), UM_SLEEP);
1269 
1270 	return (WALK_NEXT);
1271 }
1272 
1273 static int
1274 orphan_walk_s(mdb_walk_state_t *wsp)
1275 {
1276 	int status;
1277 
1278 	if (wsp->walk_addr == 0)
1279 		return (WALK_DONE);
1280 
1281 	if (mdb_vread(wsp->walk_data, sizeof (struct fc_orphan),
1282 	    wsp->walk_addr) == -1) {
1283 		mdb_warn("Failed to read in the fc_orphan at 0x%p\n",
1284 		    wsp->walk_addr);
1285 		return (WALK_DONE);
1286 	}
1287 
1288 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
1289 	    wsp->walk_cbdata);
1290 
1291 	wsp->walk_addr =
1292 	    (uintptr_t)(((struct fc_orphan *)wsp->walk_data)->orp_next);
1293 
1294 	return (status);
1295 }
1296 
1297 /*
1298  * The walker's fini function is invoked at the end of each walk.
1299  */
1300 static void
1301 orphan_walk_f(mdb_walk_state_t *wsp)
1302 {
1303 	mdb_free(wsp->walk_data, sizeof (struct fc_orphan));
1304 }
1305 
1306 
1307 /*
1308  * MDB module linkage information:
1309  *
1310  * We declare a list of structures describing our dcmds, a list of structures
1311  * describing our walkers, and a function named _mdb_init to return a pointer
1312  * to our module information.
1313  */
1314 
1315 static const mdb_dcmd_t dcmds[] = {
1316 	{ "ports", "[-l]", "Leadville port list", ports },
1317 	{ "ulps", NULL, "Leadville ULP list", ulps },
1318 	{ "ulpmods", NULL, "Leadville ULP module list", ulpmods },
1319 	{ "fcport", NULL, "Display a Leadville fc_local_port structure",
1320 	    fcport },
1321 	{ "remote_port", NULL, "Display fc_remote_port structures",
1322 	    remote_port },
1323 	{ "fcptrace", "[-s m][-e n] (m < n)", "Dump the fcp trace buffer, "
1324 	    "optionally supplying starting and ending packet numbers.",
1325 	    fcp_trace_dump, NULL },
1326 	{ "fptrace", "[-s m][-e n] (m < n)", "Dump the fp trace buffer, "
1327 	    "optionally supplying starting and ending packet numbers.",
1328 	    fp_trace_dump, NULL },
1329 	{ NULL }
1330 };
1331 
1332 static const mdb_walker_t walkers[] = {
1333 	{ "ports", "walk list of Leadville port structures",
1334 	    port_walk_i, port_walk_s, port_walk_f },
1335 	{ "ulps", "walk list of Leadville ULP structures",
1336 	    ulp_walk_i, ulp_walk_s, ulp_walk_f },
1337 	{ "ulpmods", "walk list of Leadville ULP module structures",
1338 	    ulpmod_walk_i, ulpmod_walk_s, ulpmod_walk_f },
1339 	{ "pd_by_pwwn", "walk list of fc_remote_port structures hashed by PWWN",
1340 	    pd_by_pwwn_walk_i, pd_by_pwwn_walk_s, pd_by_pwwn_walk_f },
1341 	{ "pd_by_did", "walk list of fc_remote_port structures hashed by D_ID",
1342 	    pd_by_did_walk_i, pd_by_did_walk_s, pd_by_did_walk_f },
1343 	{ "job_request", "walk list of job_request structures for a local port",
1344 	    job_request_walk_i, job_request_walk_s, job_request_walk_f },
1345 	{ "orphan", "walk list of orphan structures for a local port",
1346 	    orphan_walk_i, orphan_walk_s, orphan_walk_f },
1347 	{ NULL }
1348 };
1349 
1350 static const mdb_modinfo_t modinfo = {
1351 	MDB_API_VERSION, dcmds, walkers
1352 };
1353 
1354 const mdb_modinfo_t *
1355 _mdb_init(void)
1356 {
1357 	return (&modinfo);
1358 }
1359