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