xref: /illumos-gate/usr/src/cmd/mdb/common/modules/idm/idm.c (revision 2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1f)
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 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <sys/mdb_modapi.h>
27 #include <sys/cpuvar.h>
28 #include <sys/conf.h>
29 #include <sys/file.h>
30 #include <sys/types.h>
31 #include <sys/taskq.h>
32 #include <sys/sysmacros.h>
33 #include <sys/socket.h>		/* networking stuff */
34 #include <sys/strsubr.h>	/* networking stuff */
35 #include <sys/nvpair.h>
36 #include <sys/sunldi.h>
37 #include <sys/stmf.h>
38 #include <sys/stmf_ioctl.h>
39 #include <sys/portif.h>
40 
41 #define	IDM_CONN_SM_STRINGS
42 #define	ISCSIT_TGT_SM_STRINGS
43 #define	ISCSIT_SESS_SM_STRINGS
44 #define	ISCSIT_LOGIN_SM_STRINGS
45 #include <sys/idm/idm.h>
46 #include <iscsit.h>
47 #include <iscsit_isns.h>
48 
49 
50 /*
51  * We want to be able to print multiple levels of object hierarchy with a
52  * single dcmd information, and preferably also exclude intermediate
53  * levels if desired.  For example some of the target objects have the
54  * following relationship:
55  *
56  * target --> session --> connection --> task
57  *
58  * The session dcmd should allow the printing of all associated tasks for the
59  * sessions without printing all the associated connections.  To accomplish
60  * this the following structure contains a bit for each object type.  Dcmds
61  * should invoked the functions for child objects if any bits are set
62  * in iscsi_dcmd_ctrl_t but the functions for the child object should only
63  * print data if their associated bit is set.
64  *
65  * Each dcmd should provide an external interface with the standard MDB API
66  * and an internal interface that accepts iscsi_dcmd_ctrl_t.  To display
67  * child objects the dcmd calls the internal interface for the child object
68  * directly.  Dcmds invoked from the command line will, of course, call the
69  * external interface.  See iscsi_conn() and iscsi_conn_impl().
70  */
71 
72 typedef struct {
73 	union	{
74 		uint32_t	idc_children;
75 		struct {
76 			uint32_t	idc_tgt:1,
77 					idc_tpgt:1,
78 					idc_portal:1,
79 					idc_sess:1,
80 					idc_conn:1,
81 					idc_print_ip:1,
82 					idc_task:1,
83 					idc_buffer:1,
84 					idc_states:1,
85 					idc_rc_audit:1,
86 					idc_lun:1,
87 					idc_hba:1;
88 		} child;
89 	} u;
90 	boolean_t		idc_ini;
91 	boolean_t		idc_tgt;
92 	boolean_t		idc_verbose;
93 	boolean_t		idc_header;
94 	/*
95 	 * Our connection dcmd code works off the global connection lists
96 	 * in IDM since we want to know about connections even when they
97 	 * have not progressed to the point that they have an associated
98 	 * session.  If we use "::iscsi_sess [-c]" then we only want to
99 	 * see connections associated with particular session.  To avoid
100 	 * writing a separate set of code to print session-specific connection
101 	 * the session code should set the sessions kernel address in the
102 	 * following field.  The connection code will then only print
103 	 * connections that match.
104 	 */
105 	uintptr_t		idc_assoc_session;
106 } iscsi_dcmd_ctrl_t;
107 
108 static int iscsi_walk_all_sess(iscsi_dcmd_ctrl_t *idc);
109 static int iscsi_walk_all_conn(iscsi_dcmd_ctrl_t *idc);
110 static int iscsi_tgt_walk_cb(uintptr_t addr, const void *list_walker_data,
111     void *idc_void);
112 static int iscsi_tpgt_walk_cb(uintptr_t addr, const void *list_walker_data,
113     void *idc_void);
114 static int iscsi_tpg_walk_cb(uintptr_t addr, const void *list_walker_data,
115     void *idc_void);
116 static int iscsi_portal_walk_cb(uintptr_t addr, const void *list_walker_data,
117     void *idc_void);
118 static int iscsi_sess_walk_cb(uintptr_t addr, const void *list_walker_data,
119     void *idc_void);
120 static int iscsi_conn_walk_cb(uintptr_t addr, const void *list_walker_data,
121     void *idc_void);
122 static int iscsi_buffer_walk_cb(uintptr_t addr, const void *list_walker_data,
123     void *idc_void);
124 static int iscsi_tgt_impl(uintptr_t addr, iscsi_dcmd_ctrl_t *idc);
125 static int iscsi_tpgt_impl(uintptr_t addr, iscsi_dcmd_ctrl_t *idc);
126 static int iscsi_tpg_impl(uintptr_t addr, iscsi_dcmd_ctrl_t *idc);
127 static int iscsi_portal_impl(uintptr_t addr, iscsi_dcmd_ctrl_t *idc);
128 static int iscsi_sess_impl(uintptr_t addr, iscsi_dcmd_ctrl_t *idc);
129 static int iscsi_conn_impl(uintptr_t addr, iscsi_dcmd_ctrl_t *idc);
130 static void iscsi_print_iscsit_conn_data(idm_conn_t *ict);
131 static void iscsi_print_idm_conn_data(idm_conn_t *ict);
132 static int iscsi_task_impl(uintptr_t addr, iscsi_dcmd_ctrl_t *idc);
133 static void iscsi_print_iscsit_task_data(idm_task_t *idt);
134 static int iscsi_buffer_impl(uintptr_t addr, iscsi_dcmd_ctrl_t *idc);
135 static idm_conn_type_t idm_conn_type(uintptr_t addr);
136 static int iscsi_i_task_impl(idm_task_t *idt, uintptr_t addr,
137     iscsi_dcmd_ctrl_t *idc);
138 static int iscsi_refcnt_impl(uintptr_t addr);
139 static int iscsi_sm_audit_impl(uintptr_t addr);
140 static int iscsi_isns(uintptr_t addr, uint_t flags, int argc,
141     const mdb_arg_t *argv);
142 
143 static const char *iscsi_idm_conn_event(int event);
144 static const char *iscsi_iscsit_tgt_event(int event);
145 static const char *iscsi_iscsit_sess_event(int event);
146 static const char *iscsi_iscsit_login_event(int event);
147 static const char *iscsi_idm_conn_state(int state);
148 static const char *iscsi_idm_task_state(int state);
149 static const char *iscsi_iscsit_tgt_state(int state);
150 static const char *iscsi_iscsit_sess_state(int state);
151 static const char *iscsi_iscsit_login_state(int state);
152 
153 static void iscsi_format_timestamp(char *ts_str, int strlen,
154     timespec_t *ts);
155 static char *inet_ntop(int af, const void *addr, char *buf, int addrlen);
156 static void convert2ascii(char *, const in6_addr_t *);
157 static int sa_to_str(struct sockaddr_storage *sa, char *addr);
158 static int iscsi_isns_portal_cb(uintptr_t addr, const void *walker_data,
159     void *data);
160 
161 #define	PORTAL_STR_LEN	(INET6_ADDRSTRLEN + 7)
162 
163 /*
164  * ::iscsi_tgt [-scatgpbSRv]
165  *
166  * iscsi_tgt - Print out information associated with an iscsit target instance
167  *
168  * s	Print associated session information
169  * c	Print associated connection information
170  * a	Print IP addresses with connection information
171  * t	Print associated task information
172  * g	Print associated TPG information
173  * p	Print portals with TPG information
174  * b	Print associated buffer information
175  * S	Print recent state events and transitions
176  * R	Print reference count audit data
177  * v	Verbose output about the connection
178  */
179 /*ARGSUSED*/
180 static int
181 iscsi_tgt(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
182 {
183 	iscsi_dcmd_ctrl_t	idc;
184 	int			buffer = 0, task = 0, print_ip = 0;
185 	int			tpgt = 0, conn = 0, sess = 0, portal = 0;
186 	int			states = 0, rc_audit = 0;
187 	uintptr_t		iscsit_global_addr, avl_addr, list_addr;
188 	GElf_Sym		sym;
189 
190 	bzero(&idc, sizeof (idc));
191 	if (mdb_getopts(argc, argv,
192 	    'a', MDB_OPT_SETBITS, TRUE, &print_ip,
193 	    'g', MDB_OPT_SETBITS, TRUE, &tpgt,
194 	    's', MDB_OPT_SETBITS, TRUE, &sess,
195 	    'c', MDB_OPT_SETBITS, TRUE, &conn,
196 	    't', MDB_OPT_SETBITS, TRUE, &task,
197 	    'b', MDB_OPT_SETBITS, TRUE, &buffer,
198 	    'p', MDB_OPT_SETBITS, TRUE, &portal,
199 	    'S', MDB_OPT_SETBITS, TRUE, &states,
200 	    'R', MDB_OPT_SETBITS, TRUE, &rc_audit,
201 	    'v', MDB_OPT_SETBITS, TRUE, &idc.idc_verbose,
202 	    NULL) != argc)
203 		return (DCMD_USAGE);
204 
205 	idc.u.child.idc_tgt = 1;
206 	idc.u.child.idc_print_ip = print_ip;
207 	idc.u.child.idc_tpgt = tpgt;
208 	idc.u.child.idc_portal = portal;
209 	idc.u.child.idc_sess = sess;
210 	idc.u.child.idc_conn = conn;
211 	idc.u.child.idc_task = task;
212 	idc.u.child.idc_buffer = buffer;
213 	idc.u.child.idc_states = states;
214 	idc.u.child.idc_rc_audit = rc_audit;
215 
216 	if (DCMD_HDRSPEC(flags))
217 		idc.idc_header = 1;
218 
219 	/*
220 	 * If no address was specified on the command line, we
221 	 * print out all tgtions
222 	 */
223 	if (!(flags & DCMD_ADDRSPEC)) {
224 		if (mdb_lookup_by_name("iscsit_global", &sym) == -1) {
225 			mdb_warn("failed to find symbol 'iscsit_global'");
226 			return (DCMD_ERR);
227 		}
228 		iscsit_global_addr = (uintptr_t)sym.st_value;
229 		avl_addr = iscsit_global_addr +
230 		    offsetof(iscsit_global_t, global_target_list);
231 		if (mdb_pwalk("avl", iscsi_tgt_walk_cb, &idc, avl_addr) == -1) {
232 			mdb_warn("avl walk failed for global target tree");
233 			return (DCMD_ERR);
234 		}
235 		list_addr = iscsit_global_addr +
236 		    offsetof(iscsit_global_t, global_deleted_target_list);
237 		if (mdb_pwalk("list", iscsi_tgt_walk_cb,
238 		    &idc, list_addr) == -1) {
239 			mdb_warn("list walk failed for deleted target list");
240 			return (DCMD_ERR);
241 		}
242 		return (DCMD_OK);
243 	} else {
244 		return (iscsi_tgt_impl(addr, &idc));
245 	}
246 	/*NOTREACHED*/
247 }
248 
249 static int
250 iscsi_tpg(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
251 {
252 	iscsi_dcmd_ctrl_t	idc;
253 	uintptr_t		iscsit_global_addr, avl_addr;
254 	GElf_Sym		sym;
255 
256 	bzero(&idc, sizeof (idc));
257 	if (mdb_getopts(argc, argv,
258 	    'v', MDB_OPT_SETBITS, TRUE, &idc.idc_verbose,
259 	    NULL) != argc)
260 		return (DCMD_USAGE);
261 
262 	idc.u.child.idc_portal = 1; /* Always print portals */
263 	if (DCMD_HDRSPEC(flags))
264 		idc.idc_header = 1;
265 
266 	/*
267 	 * If no address was specified on the command line, we
268 	 * print out all tgtions
269 	 */
270 	if (!(flags & DCMD_ADDRSPEC)) {
271 		if (mdb_lookup_by_name("iscsit_global", &sym) == -1) {
272 			mdb_warn("failed to find symbol 'iscsit_global'");
273 			return (DCMD_ERR);
274 		}
275 		iscsit_global_addr = (uintptr_t)sym.st_value;
276 		avl_addr = iscsit_global_addr +
277 		    offsetof(iscsit_global_t, global_tpg_list);
278 		if (mdb_pwalk("avl", iscsi_tpg_walk_cb, &idc, avl_addr) == -1) {
279 			mdb_warn("avl walk failed for global target tree");
280 			return (DCMD_ERR);
281 		}
282 		return (DCMD_OK);
283 	} else {
284 		return (iscsi_tpg_impl(addr, &idc));
285 	}
286 	/*NOTREACHED*/
287 }
288 
289 /*
290  * ::iscsi_sess [-bctvIT]
291  *
292  * iscsi_sess - Print out information associated with an iSCSI session
293  *
294  * I	Print only initiator sessions
295  * T	Print only target sessions
296  * c	Print associated connection information
297  * a	Print IP addresses with connection information
298  * t	Print associated task information
299  * b	Print associated buffer information
300  * S	Print recent state events and transitions
301  * R	Print reference count audit data
302  * v	Verbose output about the connection
303  */
304 /*ARGSUSED*/
305 static int
306 iscsi_sess(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
307 {
308 	iscsi_dcmd_ctrl_t	idc;
309 	int			buffer = 0, task = 0, conn = 0, print_ip = 0;
310 	int			states = 0, rc_audit = 0;
311 
312 	bzero(&idc, sizeof (idc));
313 	if (mdb_getopts(argc, argv,
314 	    'I', MDB_OPT_SETBITS, TRUE, &idc.idc_ini,
315 	    'T', MDB_OPT_SETBITS, TRUE, &idc.idc_tgt,
316 	    'a', MDB_OPT_SETBITS, TRUE, &print_ip,
317 	    'c', MDB_OPT_SETBITS, TRUE, &conn,
318 	    't', MDB_OPT_SETBITS, TRUE, &task,
319 	    'b', MDB_OPT_SETBITS, TRUE, &buffer,
320 	    'S', MDB_OPT_SETBITS, TRUE, &states,
321 	    'R', MDB_OPT_SETBITS, TRUE, &rc_audit,
322 	    'v', MDB_OPT_SETBITS, TRUE, &idc.idc_verbose,
323 	    NULL) != argc)
324 		return (DCMD_USAGE);
325 
326 	idc.u.child.idc_sess = 1;
327 	idc.u.child.idc_print_ip = print_ip;
328 	idc.u.child.idc_conn = conn;
329 	idc.u.child.idc_task = task;
330 	idc.u.child.idc_buffer = buffer;
331 	idc.u.child.idc_states = states;
332 	idc.u.child.idc_rc_audit = rc_audit;
333 	if (DCMD_HDRSPEC(flags))
334 		idc.idc_header = 1;
335 
336 	/*
337 	 * If no address was specified on the command line, we
338 	 * print out all sessions
339 	 */
340 	if (!(flags & DCMD_ADDRSPEC)) {
341 		return (iscsi_walk_all_sess(&idc));
342 	} else {
343 		return (iscsi_sess_impl(addr, &idc));
344 	}
345 	/*NOTREACHED*/
346 }
347 
348 
349 
350 /*
351  * ::iscsi_conn [-btvIT]
352  *
353  * iscsi_conn - Print out information associated with an iSCSI connection
354  *
355  * I	Print only initiator connections
356  * T	Print only target connections
357  * a	Print IP addresses with connection information
358  * t	Print associated task information
359  * b	Print associated buffer information
360  * S	Print recent state events and transitions
361  * R	Print reference count audit data
362  * v	Verbose output about the connection
363  */
364 /*ARGSUSED*/
365 static int
366 iscsi_conn(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
367 {
368 	iscsi_dcmd_ctrl_t	idc;
369 	int			buffer = 0, task = 0, print_ip = 0;
370 	int			states = 0, rc_audit = 0;
371 
372 	bzero(&idc, sizeof (idc));
373 	if (mdb_getopts(argc, argv,
374 	    'I', MDB_OPT_SETBITS, TRUE, &idc.idc_ini,
375 	    'T', MDB_OPT_SETBITS, TRUE, &idc.idc_tgt,
376 	    'a', MDB_OPT_SETBITS, TRUE, &print_ip,
377 	    't', MDB_OPT_SETBITS, TRUE, &task,
378 	    'b', MDB_OPT_SETBITS, TRUE, &buffer,
379 	    'S', MDB_OPT_SETBITS, TRUE, &states,
380 	    'R', MDB_OPT_SETBITS, TRUE, &rc_audit,
381 	    'v', MDB_OPT_SETBITS, TRUE, &idc.idc_verbose,
382 	    NULL) != argc)
383 		return (DCMD_USAGE);
384 
385 	idc.u.child.idc_conn = 1;
386 	idc.u.child.idc_print_ip = print_ip;
387 	idc.u.child.idc_task = task;
388 	idc.u.child.idc_buffer = buffer;
389 	idc.u.child.idc_states = states;
390 	idc.u.child.idc_rc_audit = rc_audit;
391 	if (DCMD_HDRSPEC(flags))
392 		idc.idc_header = 1;
393 
394 	/*
395 	 * If no address was specified on the command line, we
396 	 * print out all connections
397 	 */
398 	if (!(flags & DCMD_ADDRSPEC)) {
399 		return (iscsi_walk_all_conn(&idc));
400 	} else {
401 		return (iscsi_conn_impl(addr, &idc));
402 	}
403 	/*NOTREACHED*/
404 }
405 
406 /*
407  * ::iscsi_task [-bv]
408  *
409  * iscsi_task - Print out information associated with an iSCSI task
410  *
411  * b	Print associated buffer information
412  * S	Print recent state events and transitions
413  * R	Print reference count audit data
414  * v	Verbose output about the connection
415  */
416 /*ARGSUSED*/
417 static int
418 iscsi_task(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
419 {
420 	iscsi_dcmd_ctrl_t	idc;
421 	int			buffer = 0;
422 	int			states = 0, rc_audit = 0;
423 
424 	bzero(&idc, sizeof (idc));
425 	if (mdb_getopts(argc, argv,
426 	    'b', MDB_OPT_SETBITS, TRUE, &buffer,
427 	    'S', MDB_OPT_SETBITS, TRUE, &states,
428 	    'R', MDB_OPT_SETBITS, TRUE, &rc_audit,
429 	    'v', MDB_OPT_SETBITS, TRUE, &idc.idc_verbose,
430 	    NULL) != argc)
431 		return (DCMD_USAGE);
432 
433 	idc.u.child.idc_conn = 0;
434 	idc.u.child.idc_task = 1;
435 	idc.u.child.idc_buffer = buffer;
436 	idc.u.child.idc_states = states;
437 	idc.u.child.idc_rc_audit = rc_audit;
438 	if (DCMD_HDRSPEC(flags))
439 		idc.idc_header = 1;
440 
441 	/*
442 	 * If no address was specified on the command line, we
443 	 * print out all connections
444 	 */
445 	if (!(flags & DCMD_ADDRSPEC)) {
446 		return (iscsi_walk_all_conn(&idc));
447 	} else {
448 		return (iscsi_task_impl(addr, &idc));
449 	}
450 	/*NOTREACHED*/
451 }
452 
453 /*
454  * ::iscsi_refcnt
455  *
456  * iscsi_refcnt - Dump an idm_refcnt_t structure
457  *
458  */
459 /*ARGSUSED*/
460 static int
461 iscsi_refcnt(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
462 {
463 	if (!(flags & DCMD_ADDRSPEC)) {
464 		return (DCMD_ERR);
465 	} else {
466 		return (iscsi_refcnt_impl(addr));
467 	}
468 	/*NOTREACHED*/
469 }
470 
471 /*
472  * ::iscsi_states
473  *
474  * iscsi_states - Dump events and state transitions recoreded in an
475  * idm_sm_audit_t structure
476  *
477  */
478 /*ARGSUSED*/
479 static int
480 iscsi_states(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
481 {
482 	if (!(flags & DCMD_ADDRSPEC)) {
483 		return (DCMD_ERR);
484 	} else {
485 		return (iscsi_sm_audit_impl(addr));
486 	}
487 	/*NOTREACHED*/
488 }
489 
490 static int
491 iscsi_walk_all_sess(iscsi_dcmd_ctrl_t *idc)
492 {
493 	uintptr_t	iscsit_global_addr;
494 	uintptr_t	avl_addr;
495 	uintptr_t	list_addr;
496 	GElf_Sym	sym;
497 
498 	/* Walk discovery sessions */
499 	if (mdb_lookup_by_name("iscsit_global", &sym) == -1) {
500 		mdb_warn("failed to find symbol 'iscsit_global'");
501 		return (DCMD_ERR);
502 	}
503 	iscsit_global_addr = (uintptr_t)sym.st_value;
504 	avl_addr = iscsit_global_addr +
505 	    offsetof(iscsit_global_t, global_discovery_sessions);
506 	if (mdb_pwalk("avl", iscsi_sess_walk_cb, idc, avl_addr) == -1) {
507 		mdb_warn("avl walk failed for discovery sessions");
508 		return (DCMD_ERR);
509 	}
510 
511 	/* Walk targets printing all session info */
512 	avl_addr = iscsit_global_addr +
513 	    offsetof(iscsit_global_t, global_target_list);
514 	if (mdb_pwalk("avl", iscsi_tgt_walk_cb, idc, avl_addr) == -1) {
515 		mdb_warn("avl walk failed for target/session tree");
516 		return (DCMD_ERR);
517 	}
518 
519 	/* Walk deleting targets printing all session info */
520 	list_addr = iscsit_global_addr +
521 	    offsetof(iscsit_global_t, global_deleted_target_list);
522 	if (mdb_pwalk("list", iscsi_tgt_walk_cb, idc, list_addr) == -1) {
523 		mdb_warn("list walk failed for deleted target list");
524 		return (DCMD_ERR);
525 	}
526 
527 	return (DCMD_OK);
528 }
529 
530 static int
531 iscsi_walk_all_conn(iscsi_dcmd_ctrl_t *idc)
532 {
533 	uintptr_t	idm_global_addr;
534 	uintptr_t	list_addr;
535 	GElf_Sym	sym;
536 
537 	/* Walk initiator connections */
538 	if (mdb_lookup_by_name("idm", &sym) == -1) {
539 		mdb_warn("failed to find symbol 'idm'");
540 		return (DCMD_ERR);
541 	}
542 	idm_global_addr = (uintptr_t)sym.st_value;
543 	/* Walk connection list associated with the initiator */
544 	list_addr = idm_global_addr + offsetof(idm_global_t, idm_ini_conn_list);
545 	if (mdb_pwalk("list", iscsi_conn_walk_cb, idc, list_addr) == -1) {
546 		mdb_warn("list walk failed for initiator connections");
547 		return (DCMD_ERR);
548 	}
549 
550 	/* Walk connection list associated with the target */
551 	list_addr = idm_global_addr + offsetof(idm_global_t, idm_tgt_conn_list);
552 	if (mdb_pwalk("list", iscsi_conn_walk_cb, idc, list_addr) == -1) {
553 		mdb_warn("list walk failed for target service instances");
554 		return (DCMD_ERR);
555 	}
556 
557 	return (DCMD_OK);
558 }
559 
560 /*ARGSUSED*/
561 static int
562 iscsi_tpg_walk_cb(uintptr_t addr, const void *list_walker_data,
563     void *idc_void)
564 {
565 	/* We don't particularly care about the list walker data */
566 	iscsi_dcmd_ctrl_t	*idc = idc_void;
567 	int			rc;
568 
569 	rc = iscsi_tpg_impl(addr, idc);
570 
571 	return ((rc == DCMD_OK) ? WALK_NEXT : WALK_ERR);
572 }
573 
574 /*ARGSUSED*/
575 static int
576 iscsi_tgt_walk_cb(uintptr_t addr, const void *list_walker_data,
577     void *idc_void)
578 {
579 	/* We don't particularly care about the list walker data */
580 	iscsi_dcmd_ctrl_t	*idc = idc_void;
581 	int			rc;
582 
583 	rc = iscsi_tgt_impl(addr, idc);
584 
585 	return ((rc == DCMD_OK) ? WALK_NEXT : WALK_ERR);
586 }
587 
588 /*ARGSUSED*/
589 static int
590 iscsi_tpgt_walk_cb(uintptr_t addr, const void *list_walker_data,
591     void *idc_void)
592 {
593 	/* We don't particularly care about the list walker data */
594 	iscsi_dcmd_ctrl_t	*idc = idc_void;
595 	int			rc;
596 
597 	rc = iscsi_tpgt_impl(addr, idc);
598 
599 	return ((rc == DCMD_OK) ? WALK_NEXT : WALK_ERR);
600 }
601 
602 /*ARGSUSED*/
603 static int
604 iscsi_portal_walk_cb(uintptr_t addr, const void *list_walker_data,
605     void *idc_void)
606 {
607 	/* We don't particularly care about the list walker data */
608 	iscsi_dcmd_ctrl_t	*idc = idc_void;
609 	int			rc;
610 
611 	rc = iscsi_portal_impl(addr, idc);
612 
613 	return ((rc == DCMD_OK) ? WALK_NEXT : WALK_ERR);
614 }
615 
616 /*ARGSUSED*/
617 static int
618 iscsi_sess_walk_cb(uintptr_t addr, const void *list_walker_data,
619     void *idc_void)
620 {
621 	/* We don't particularly care about the list walker data */
622 	iscsi_dcmd_ctrl_t	*idc = idc_void;
623 	int			rc;
624 
625 	rc = iscsi_sess_impl(addr, idc);
626 
627 	return ((rc == DCMD_OK) ? WALK_NEXT : WALK_ERR);
628 }
629 
630 /*ARGSUSED*/
631 static int
632 iscsi_sess_conn_walk_cb(uintptr_t addr, const void *list_walker_data,
633     void *idc_void)
634 {
635 	/* We don't particularly care about the list walker data */
636 	iscsi_dcmd_ctrl_t	*idc = idc_void;
637 	iscsit_conn_t		ict;
638 	int			rc;
639 
640 	/*
641 	 * This function is different from iscsi_conn_walk_cb because
642 	 * we get an iscsit_conn_t instead of an idm_conn_t
643 	 *
644 	 * Read iscsit_conn_t, use to get idm_conn_t pointer
645 	 */
646 	if (mdb_vread(&ict, sizeof (iscsit_conn_t), addr) !=
647 	    sizeof (iscsit_conn_t)) {
648 		return (DCMD_ERR);
649 	}
650 	rc = iscsi_conn_impl((uintptr_t)ict.ict_ic, idc);
651 
652 	return ((rc == DCMD_OK) ? WALK_NEXT : WALK_ERR);
653 }
654 
655 /*ARGSUSED*/
656 static int
657 iscsi_conn_walk_cb(uintptr_t addr, const void *list_walker_data,
658     void *idc_void)
659 {
660 	/* We don't particularly care about the list walker data */
661 	iscsi_dcmd_ctrl_t	*idc = idc_void;
662 	int			rc;
663 
664 	rc = iscsi_conn_impl(addr, idc);
665 
666 	return ((rc == DCMD_OK) ? WALK_NEXT : WALK_ERR);
667 }
668 
669 /*ARGSUSED*/
670 static int
671 iscsi_buffer_walk_cb(uintptr_t addr, const void *list_walker_data,
672     void *idc_void)
673 {
674 	/* We don't particularly care about the list walker data */
675 	iscsi_dcmd_ctrl_t	*idc = idc_void;
676 	int			rc;
677 
678 	rc = iscsi_buffer_impl(addr, idc);
679 
680 	return ((rc == DCMD_OK) ? WALK_NEXT : WALK_ERR);
681 }
682 
683 static int
684 iscsi_tgt_impl(uintptr_t addr, iscsi_dcmd_ctrl_t *idc)
685 {
686 	iscsit_tgt_t	tgt;
687 	uintptr_t	avl_addr, rc_addr, states_addr;
688 	char		tgt_name[MAX_ISCSI_NODENAMELEN];
689 	int		verbose, states, rc_audit;
690 
691 	/*
692 	 * Read iscsit_tgt_t
693 	 */
694 	if (mdb_vread(&tgt, sizeof (iscsit_tgt_t), addr) !=
695 	    sizeof (iscsit_tgt_t)) {
696 		return (DCMD_ERR);
697 	}
698 
699 	/*
700 	 * Read target name if available
701 	 */
702 	if ((tgt.target_name == NULL) ||
703 	    (mdb_readstr(tgt_name, sizeof (tgt_name),
704 	    (uintptr_t)tgt.target_name) == -1)) {
705 		strcpy(tgt_name, "N/A");
706 	}
707 
708 	/*
709 	 * Brief output
710 	 *
711 	 * iscsit_tgt_t pointer
712 	 * iscsit_tgt_t.target_stmf_state
713 	 * iscsit_tgt_t.target_sess_list.avl_numnodes (session count)
714 	 * iscsit_tgt_t.target_name;
715 	 */
716 
717 	verbose = idc->idc_verbose;
718 	states = idc->u.child.idc_states;
719 	rc_audit = idc->u.child.idc_rc_audit;
720 
721 	/* For now we will ignore the verbose flag */
722 	if (idc->u.child.idc_tgt) {
723 		/* Print target data */
724 		if (idc->idc_header) {
725 			mdb_printf("%<u>%-19s %-4s  %-8s%</u>\n",
726 			    "iscsit_tgt_t", "Sess", "State");
727 		}
728 		mdb_printf("%-19p %-4d %-8d\n", addr,
729 		    tgt.target_sess_list.avl_numnodes,
730 		    tgt.target_state);
731 		mdb_printf("  %s\n", tgt_name);
732 	}
733 
734 	idc->idc_header = 0;
735 	idc->idc_verbose = 0;
736 
737 	/*
738 	 * Print states if requested
739 	 */
740 	if (idc->u.child.idc_tgt && states) {
741 		states_addr = addr + offsetof(iscsit_tgt_t, target_state_audit);
742 
743 		(void) mdb_inc_indent(4);
744 		mdb_printf("State History:\n");
745 		if (iscsi_sm_audit_impl(states_addr) != DCMD_OK)
746 			return (DCMD_ERR);
747 		idc->u.child.idc_states = 0;
748 		(void) mdb_dec_indent(4);
749 	}
750 
751 	/*
752 	 * Print refcnt audit data if requested
753 	 */
754 	if (idc->u.child.idc_tgt && rc_audit) {
755 		(void) mdb_inc_indent(4);
756 		mdb_printf("target_sess_refcnt:\n");
757 		rc_addr = addr +
758 		    offsetof(iscsit_tgt_t, target_sess_refcnt);
759 		if (iscsi_refcnt_impl(rc_addr) != DCMD_OK)
760 			return (DCMD_ERR);
761 
762 		mdb_printf("target_refcnt:\n");
763 		rc_addr = addr +
764 		    offsetof(iscsit_tgt_t, target_refcnt);
765 
766 		if (iscsi_refcnt_impl(rc_addr) != DCMD_OK)
767 			return (DCMD_ERR);
768 		idc->u.child.idc_rc_audit = 0;
769 		(void) mdb_dec_indent(4);
770 	}
771 
772 	/* Any child objects to walk? */
773 	if (idc->u.child.idc_tpgt || idc->u.child.idc_sess ||
774 	    idc->u.child.idc_conn || idc->u.child.idc_task ||
775 	    idc->u.child.idc_buffer) {
776 		/* Walk TPGT tree */
777 		idc->idc_header = 1;
778 		(void) mdb_inc_indent(4);
779 		avl_addr = addr +
780 		    offsetof(iscsit_tgt_t, target_tpgt_list);
781 		if (mdb_pwalk("avl", iscsi_tpgt_walk_cb, idc,
782 		    avl_addr) == -1) {
783 			mdb_warn("target tpgt list walk failed");
784 			(void) mdb_dec_indent(4);
785 			return (DCMD_ERR);
786 		}
787 		(void) mdb_dec_indent(4);
788 
789 		/* Walk sess tree */
790 		idc->idc_header = 1;
791 		(void) mdb_inc_indent(4);
792 		avl_addr = addr + offsetof(iscsit_tgt_t, target_sess_list);
793 		if (mdb_pwalk("avl", iscsi_sess_walk_cb, idc,
794 		    avl_addr) == -1) {
795 			mdb_warn("target sess list walk failed");
796 			(void) mdb_dec_indent(4);
797 			return (DCMD_ERR);
798 		}
799 		(void) mdb_dec_indent(4);
800 
801 		idc->idc_header = 0;
802 	}
803 
804 	idc->idc_verbose = verbose;
805 	idc->u.child.idc_states = states;
806 	idc->u.child.idc_rc_audit = rc_audit;
807 	return (DCMD_OK);
808 }
809 
810 static int
811 iscsi_tpgt_impl(uintptr_t addr, iscsi_dcmd_ctrl_t *idc)
812 {
813 	iscsit_tpgt_t	tpgt;
814 	iscsit_tpg_t	tpg;
815 	uintptr_t	avl_addr, tpg_addr;
816 
817 	/*
818 	 * Read iscsit_tpgt_t
819 	 */
820 	if (mdb_vread(&tpgt, sizeof (iscsit_tpgt_t), addr) !=
821 	    sizeof (iscsit_tpgt_t)) {
822 		return (DCMD_ERR);
823 	}
824 
825 	tpg_addr = (uintptr_t)tpgt.tpgt_tpg;
826 
827 	/*
828 	 * Read iscsit_tpg_t
829 	 */
830 	if (mdb_vread(&tpg, sizeof (iscsit_tpg_t), tpg_addr) !=
831 	    sizeof (iscsit_tpg_t)) {
832 		return (DCMD_ERR);
833 	}
834 
835 	/*
836 	 * Brief output
837 	 *
838 	 * iscsit_tpgt_t pointer
839 	 * iscsit_tpg_t pointer
840 	 * iscsit_tpg_t.tpg_name
841 	 * iscsit_tpgt_t.tpgt_tag;
842 	 */
843 
844 	/* For now we will ignore the verbose flag */
845 	if (idc->u.child.idc_tpgt) {
846 		/* Print target data */
847 		if (idc->idc_header) {
848 			mdb_printf("%<u>%-?s %-?s %-18s %-6s%</u>\n",
849 			    "iscsit_tpgt_t", "iscsit_tpg_t", "Name", "Tag");
850 		}
851 		mdb_printf("%?p %?p %-18s 0x%04x\n", addr, tpgt.tpgt_tpg,
852 		    tpg.tpg_name, tpgt.tpgt_tag);
853 	}
854 
855 	/*
856 	 * Assume for now that anyone interested in TPGT wants to see the
857 	 * portals as well.
858 	 */
859 	idc->idc_header = 1;
860 	(void) mdb_inc_indent(4);
861 	avl_addr = tpg_addr + offsetof(iscsit_tpg_t, tpg_portal_list);
862 	if (mdb_pwalk("avl", iscsi_portal_walk_cb, idc, avl_addr) == -1) {
863 		mdb_warn("portal list walk failed");
864 		(void) mdb_dec_indent(4);
865 		return (DCMD_ERR);
866 	}
867 	(void) mdb_dec_indent(4);
868 	idc->idc_header = 0;
869 
870 	return (DCMD_OK);
871 }
872 
873 static int
874 iscsi_tpg_impl(uintptr_t addr, iscsi_dcmd_ctrl_t *idc)
875 {
876 	iscsit_tpg_t	tpg;
877 	uintptr_t	avl_addr;
878 
879 	/*
880 	 * Read iscsit_tpg_t
881 	 */
882 	if (mdb_vread(&tpg, sizeof (iscsit_tpg_t), addr) !=
883 	    sizeof (iscsit_tpg_t)) {
884 		return (DCMD_ERR);
885 	}
886 
887 	/*
888 	 * Brief output
889 	 *
890 	 * iscsit_tpgt_t pointer
891 	 * iscsit_tpg_t pointer
892 	 * iscsit_tpg_t.tpg_name
893 	 * iscsit_tpgt_t.tpgt_tag;
894 	 */
895 
896 	/* For now we will ignore the verbose flag */
897 
898 	/* Print target data */
899 	if (idc->idc_header) {
900 		mdb_printf("%<u>%-?s %-18s%</u>\n",
901 		    "iscsit_tpg_t", "Name");
902 	}
903 	mdb_printf("%?p %-18s\n", addr, tpg.tpg_name);
904 
905 
906 	/*
907 	 * Assume for now that anyone interested in TPG wants to see the
908 	 * portals as well.
909 	 */
910 	idc->idc_header = 1;
911 	(void) mdb_inc_indent(4);
912 	avl_addr = addr + offsetof(iscsit_tpg_t, tpg_portal_list);
913 	if (mdb_pwalk("avl", iscsi_portal_walk_cb, idc, avl_addr) == -1) {
914 		mdb_warn("portal list walk failed");
915 		(void) mdb_dec_indent(4);
916 		return (DCMD_ERR);
917 	}
918 	(void) mdb_dec_indent(4);
919 	idc->idc_header = 0;
920 
921 	return (DCMD_OK);
922 }
923 
924 static int
925 iscsi_portal_impl(uintptr_t addr, iscsi_dcmd_ctrl_t *idc)
926 {
927 	iscsit_portal_t	portal;
928 	char		portal_addr[PORTAL_STR_LEN];
929 	if (idc->u.child.idc_portal) {
930 		/*
931 		 * Read iscsit_portal_t
932 		 */
933 		if (mdb_vread(&portal, sizeof (iscsit_portal_t), addr) !=
934 		    sizeof (iscsit_portal_t)) {
935 			return (DCMD_ERR);
936 		}
937 
938 		/* Print portal data */
939 		if (idc->idc_header) {
940 			mdb_printf("%<u>%-?s %-?s %-30s%</u>\n",
941 			    "iscsit_portal_t", "idm_svc_t", "IP:Port");
942 		}
943 		sa_to_str(&portal.portal_addr, portal_addr);
944 		mdb_printf("%?p %?p %s\n", addr, portal.portal_svc,
945 		    portal_addr);
946 	}
947 
948 	return (DCMD_OK);
949 }
950 
951 static int
952 iscsi_sess_impl(uintptr_t addr, iscsi_dcmd_ctrl_t *idc)
953 {
954 	iscsit_sess_t	ist;
955 	uintptr_t	list_addr, states_addr, rc_addr;
956 	char		ini_name[80];
957 	char		tgt_name[80];
958 	int		verbose, states, rc_audit;
959 
960 	/*
961 	 * Read iscsit_sess_t
962 	 */
963 	if (mdb_vread(&ist, sizeof (iscsit_sess_t), addr) !=
964 	    sizeof (iscsit_sess_t)) {
965 		return (DCMD_ERR);
966 	}
967 
968 	/*
969 	 * Brief output
970 	 *
971 	 * iscsit_sess_t pointer
972 	 * iscsit_sess_t.ist_state/iscsit_sess_t.ist_ffp_conn_count
973 	 * iscsit_sess_t.ist_tsih
974 	 * iscsit_sess_t.ist_initiator_name
975 	 */
976 
977 	verbose = idc->idc_verbose;
978 	states = idc->u.child.idc_states;
979 	rc_audit = idc->u.child.idc_rc_audit;
980 
981 	if (idc->u.child.idc_sess) {
982 		if (verbose) {
983 			/*
984 			 * Read initiator name if available
985 			 */
986 			if ((ist.ist_initiator_name == NULL) ||
987 			    (mdb_readstr(ini_name, sizeof (ini_name),
988 			    (uintptr_t)ist.ist_initiator_name) == -1)) {
989 				strcpy(ini_name, "N/A");
990 			}
991 
992 			/*
993 			 * Read target name if available
994 			 */
995 			if ((ist.ist_target_name == NULL) ||
996 			    (mdb_readstr(tgt_name, sizeof (tgt_name),
997 			    (uintptr_t)ist.ist_target_name) == -1)) {
998 				strcpy(tgt_name, "N/A");
999 			}
1000 
1001 			mdb_printf("Session %p\n", addr);
1002 			mdb_printf("%16s: %d\n", "State",
1003 			    ist.ist_state);
1004 			mdb_printf("%16s: %d\n", "Last State",
1005 			    ist.ist_last_state);
1006 			mdb_printf("%16s: %d\n", "FFP Connections",
1007 			    ist.ist_ffp_conn_count);
1008 			mdb_printf("%16s: %02x%02x%02x%02x%02x%02x\n", "ISID",
1009 			    ist.ist_isid[0], ist.ist_isid[1], ist.ist_isid[2],
1010 			    ist.ist_isid[3], ist.ist_isid[4], ist.ist_isid[5]);
1011 			mdb_printf("%16s: 0x%04x\n", "TSIH",
1012 			    ist.ist_tsih);
1013 			mdb_printf("%16s: %s\n", "Initiator IQN",
1014 			    ini_name);
1015 			mdb_printf("%16s: %s\n", "Target IQN",
1016 			    tgt_name);
1017 			mdb_printf("%16s: %08x\n", "ExpCmdSN",
1018 			    ist.ist_expcmdsn);
1019 			mdb_printf("%16s: %08x\n", "MaxCmdSN",
1020 			    ist.ist_maxcmdsn);
1021 		} else {
1022 			/* Print session data */
1023 			if (idc->idc_header) {
1024 				mdb_printf("%<u>%-?s %10s %-12s %-6s%</u>\n",
1025 				    "iscsit_sess_t", "State/Conn", "ISID",
1026 				    "TSIH");
1027 			}
1028 			mdb_printf("%?p  %4d/%-4d %02x%02x%02x%02x%02x%02x "
1029 			    "0x%04x\n", addr,
1030 			    ist.ist_state, ist.ist_ffp_conn_count,
1031 			    ist.ist_isid[0], ist.ist_isid[1], ist.ist_isid[2],
1032 			    ist.ist_isid[3], ist.ist_isid[4], ist.ist_isid[5],
1033 			    ist.ist_tsih);
1034 		}
1035 		idc->idc_header = 0;
1036 	}
1037 
1038 	idc->idc_verbose = 0;
1039 
1040 	/*
1041 	 * Print states if requested
1042 	 */
1043 	if (states) {
1044 		states_addr = addr + offsetof(iscsit_sess_t, ist_state_audit);
1045 
1046 		(void) mdb_inc_indent(4);
1047 		mdb_printf("State History:\n");
1048 		if (iscsi_sm_audit_impl(states_addr) != DCMD_OK)
1049 			return (DCMD_ERR);
1050 
1051 		/* Don't print state history for child objects */
1052 		idc->u.child.idc_states = 0;
1053 		(void) mdb_dec_indent(4);
1054 	}
1055 
1056 	/*
1057 	 * Print refcnt audit data if requested
1058 	 */
1059 	if (rc_audit) {
1060 		(void) mdb_inc_indent(4);
1061 		mdb_printf("Reference History:\n");
1062 		rc_addr = addr +
1063 		    offsetof(iscsit_sess_t, ist_refcnt);
1064 		if (iscsi_refcnt_impl(rc_addr) != DCMD_OK)
1065 			return (DCMD_ERR);
1066 
1067 		/* Don't print audit data for child objects */
1068 		idc->u.child.idc_rc_audit = 0;
1069 		(void) mdb_dec_indent(4);
1070 	}
1071 
1072 	/* Any child objects to walk? */
1073 	if (idc->u.child.idc_conn || idc->u.child.idc_task ||
1074 	    idc->u.child.idc_buffer) {
1075 		/* Walk conn list */
1076 		idc->idc_header = 1;
1077 		(void) mdb_inc_indent(4);
1078 		list_addr = addr + offsetof(iscsit_sess_t, ist_conn_list);
1079 		if (mdb_pwalk("list", iscsi_sess_conn_walk_cb, idc,
1080 		    list_addr) == -1) {
1081 			mdb_warn("session conn list walk failed");
1082 			(void) mdb_dec_indent(4);
1083 			return (DCMD_ERR);
1084 		}
1085 		(void) mdb_dec_indent(4);
1086 		idc->idc_header = 0;
1087 	}
1088 
1089 	idc->idc_verbose = verbose;
1090 	idc->u.child.idc_states = states;
1091 	idc->u.child.idc_rc_audit = rc_audit;
1092 
1093 	return (DCMD_OK);
1094 }
1095 
1096 static int
1097 iscsi_conn_impl(uintptr_t addr, iscsi_dcmd_ctrl_t *idc)
1098 {
1099 	uintptr_t	idm_global_addr, states_addr, rc_addr;
1100 	uintptr_t	task_addr, task_ptr;
1101 	GElf_Sym	sym;
1102 	idm_task_t	idt;
1103 	idm_conn_t	ic;
1104 	char		*conn_type;
1105 	int		task_idx;
1106 	char		laddr[PORTAL_STR_LEN];
1107 	char		raddr[PORTAL_STR_LEN];
1108 	int		verbose, states, rc_audit;
1109 
1110 	/*
1111 	 * Get pointer to task table
1112 	 */
1113 
1114 	if (mdb_lookup_by_name("idm", &sym) == -1) {
1115 		mdb_warn("failed to find symbol 'idm'");
1116 		return (DCMD_ERR);
1117 	}
1118 
1119 	idm_global_addr = (uintptr_t)sym.st_value;
1120 
1121 	if (mdb_vread(&task_ptr, sizeof (uintptr_t),
1122 	    idm_global_addr + offsetof(idm_global_t, idm_taskid_table)) !=
1123 	    sizeof (uintptr_t)) {
1124 		mdb_warn("Failed to read address of task table");
1125 		return (DCMD_ERR);
1126 	}
1127 
1128 	/*
1129 	 * Read idm_conn_t
1130 	 */
1131 	if (mdb_vread(&ic, sizeof (idm_conn_t), addr) != sizeof (idm_conn_t)) {
1132 		return (DCMD_ERR);
1133 	}
1134 	conn_type = (ic.ic_conn_type == CONN_TYPE_INI) ? "Ini" :
1135 	    (ic.ic_conn_type == CONN_TYPE_TGT) ? "Tgt" : "Unk";
1136 
1137 	/*
1138 	 * Brief output
1139 	 *
1140 	 * idm_conn_t pointer
1141 	 * idm_conn_t.ic_conn_type
1142 	 * idm_conn_t.ic_statet+idm_conn_t.ic_ffp
1143 	 */
1144 
1145 	verbose = idc->idc_verbose;
1146 	states = idc->u.child.idc_states;
1147 	rc_audit = idc->u.child.idc_rc_audit;
1148 
1149 	if (idc->u.child.idc_conn) {
1150 		if (idc->idc_verbose) {
1151 			mdb_printf("IDM Conn %p\n", addr);
1152 			if (ic.ic_conn_type == CONN_TYPE_TGT) {
1153 				iscsi_print_iscsit_conn_data(&ic);
1154 			} else {
1155 				iscsi_print_idm_conn_data(&ic);
1156 			}
1157 		} else {
1158 			/* Print connection data */
1159 			if (idc->idc_header) {
1160 				mdb_printf("%<u>%-?s %-6s %-10s %12s%</u>\n",
1161 				    "idm_conn_t", "Type", "Transport",
1162 				    "State/FFP");
1163 			}
1164 			mdb_printf("%?p %-6s %-10s %6d/%-6d\n", addr, conn_type,
1165 			    (ic.ic_transport_type ==
1166 			    IDM_TRANSPORT_TYPE_ISER) ? "ISER_IB" :
1167 			    (ic.ic_transport_type ==
1168 			    IDM_TRANSPORT_TYPE_SOCKETS) ? "SOCKETS" :
1169 			    "N/A",
1170 			    ic.ic_state, ic.ic_ffp);
1171 			if (idc->u.child.idc_print_ip) {
1172 				sa_to_str(&ic.ic_laddr, laddr);
1173 				sa_to_str(&ic.ic_raddr, raddr);
1174 				mdb_printf("  L%s  R%s\n",
1175 				    laddr, raddr);
1176 			}
1177 		}
1178 	}
1179 	idc->idc_header = 0;
1180 
1181 	idc->idc_verbose = 0;
1182 
1183 	/*
1184 	 * Print states if requested
1185 	 */
1186 	if (states) {
1187 		states_addr = addr + offsetof(idm_conn_t, ic_state_audit);
1188 
1189 		(void) mdb_inc_indent(4);
1190 		mdb_printf("State History:\n");
1191 		if (iscsi_sm_audit_impl(states_addr) != DCMD_OK)
1192 			return (DCMD_ERR);
1193 
1194 		/* Don't print state history for child objects */
1195 		idc->u.child.idc_states = 0;
1196 		(void) mdb_dec_indent(4);
1197 	}
1198 
1199 	/*
1200 	 * Print refcnt audit data if requested
1201 	 */
1202 	if (rc_audit) {
1203 		(void) mdb_inc_indent(4);
1204 		mdb_printf("Reference History:\n");
1205 		rc_addr = addr + offsetof(idm_conn_t, ic_refcnt);
1206 		if (iscsi_refcnt_impl(rc_addr) != DCMD_OK)
1207 			return (DCMD_ERR);
1208 
1209 		/* Don't print audit data for child objects */
1210 		idc->u.child.idc_rc_audit = 0;
1211 		(void) mdb_dec_indent(4);
1212 	}
1213 
1214 	task_idx = 0;
1215 
1216 	/* Any child objects to walk? */
1217 	if (idc->u.child.idc_task || idc->u.child.idc_buffer) {
1218 		idc->idc_header = 1;
1219 		while (task_idx < IDM_TASKIDS_MAX) {
1220 
1221 			/*
1222 			 * Read the next idm_task_t
1223 			 */
1224 
1225 			if (mdb_vread(&task_addr, sizeof (uintptr_t),
1226 			    task_ptr) != sizeof (uintptr_t)) {
1227 				mdb_warn("Failed to read task pointer");
1228 				return (DCMD_ERR);
1229 			}
1230 
1231 			if (task_addr == NULL) {
1232 				task_ptr += sizeof (uintptr_t);
1233 				task_idx++;
1234 				continue;
1235 			}
1236 
1237 			if (mdb_vread(&idt, sizeof (idm_task_t), task_addr)
1238 			    != sizeof (idm_task_t)) {
1239 				mdb_warn("Failed to read task pointer");
1240 				return (DCMD_ERR);
1241 			}
1242 
1243 			if (((uintptr_t)idt.idt_ic == addr) &&
1244 			    (idt.idt_state != TASK_IDLE)) {
1245 				(void) mdb_inc_indent(4);
1246 				if (iscsi_i_task_impl(&idt, task_addr, idc)
1247 				    == -1) {
1248 					mdb_warn("Failed to walk connection "
1249 					    "task tree");
1250 					(void) mdb_dec_indent(4);
1251 					return (DCMD_ERR);
1252 				}
1253 				(void) mdb_dec_indent(4);
1254 			}
1255 
1256 			task_ptr += sizeof (uintptr_t);
1257 			task_idx++;
1258 		}
1259 		idc->idc_header = 0;
1260 	}
1261 
1262 	idc->idc_verbose = verbose;
1263 	idc->u.child.idc_states = states;
1264 	idc->u.child.idc_rc_audit = rc_audit;
1265 
1266 	return (DCMD_OK);
1267 }
1268 
1269 static void
1270 iscsi_print_iscsit_conn_data(idm_conn_t *ic)
1271 {
1272 	iscsit_conn_t	ict;
1273 	char		*csg;
1274 	char		*nsg;
1275 
1276 	iscsi_print_idm_conn_data(ic);
1277 
1278 	if (mdb_vread(&ict, sizeof (iscsit_conn_t),
1279 	    (uintptr_t)ic->ic_handle) != sizeof (iscsit_conn_t)) {
1280 		mdb_printf("**Failed to read conn private data\n");
1281 		return;
1282 	}
1283 
1284 	if (ict.ict_login_sm.icl_login_state != ILS_LOGIN_DONE) {
1285 		switch (ict.ict_login_sm.icl_login_csg) {
1286 		case ISCSI_SECURITY_NEGOTIATION_STAGE:
1287 			csg = "Security";
1288 			break;
1289 		case ISCSI_OP_PARMS_NEGOTIATION_STAGE:
1290 			csg = "Operational";
1291 			break;
1292 		case ISCSI_FULL_FEATURE_PHASE:
1293 			csg = "FFP";
1294 			break;
1295 		default:
1296 			csg = "Unknown";
1297 		}
1298 		switch (ict.ict_login_sm.icl_login_nsg) {
1299 		case ISCSI_SECURITY_NEGOTIATION_STAGE:
1300 			nsg = "Security";
1301 			break;
1302 		case ISCSI_OP_PARMS_NEGOTIATION_STAGE:
1303 			nsg = "Operational";
1304 			break;
1305 		case ISCSI_FULL_FEATURE_PHASE:
1306 			nsg = "FFP";
1307 			break;
1308 		default:
1309 			nsg = "Unknown";
1310 		}
1311 		mdb_printf("%20s: %d\n", "Login State",
1312 		    ict.ict_login_sm.icl_login_state);
1313 		mdb_printf("%20s: %d\n", "Login Last State",
1314 		    ict.ict_login_sm.icl_login_last_state);
1315 		mdb_printf("%20s: %s\n", "CSG", csg);
1316 		mdb_printf("%20s: %s\n", "NSG", nsg);
1317 		mdb_printf("%20s: %d\n", "Transit",
1318 		    ict.ict_login_sm.icl_login_transit >> 7);
1319 		mdb_printf("%20s: %p\n", "Request nvlist",
1320 		    ict.ict_login_sm.icl_request_nvlist);
1321 		mdb_printf("%20s: %p\n", "Response nvlist",
1322 		    ict.ict_login_sm.icl_response_nvlist);
1323 		mdb_printf("%20s: %p\n", "Negotiated nvlist",
1324 		    ict.ict_login_sm.icl_negotiated_values);
1325 		if (ict.ict_login_sm.icl_login_state == ILS_LOGIN_ERROR) {
1326 			mdb_printf("%20s: 0x%02x\n", "Error Class",
1327 			    ict.ict_login_sm.icl_login_resp_err_class);
1328 			mdb_printf("%20s: 0x%02x\n", "Error Detail",
1329 			    ict.ict_login_sm.icl_login_resp_err_detail);
1330 		}
1331 	}
1332 	mdb_printf("%20s: 0x%04x\n", "CID", ict.ict_cid);
1333 	mdb_printf("%20s: 0x%08x\n", "StatSN", ict.ict_statsn);
1334 }
1335 
1336 static void
1337 iscsi_print_idm_conn_data(idm_conn_t *ic)
1338 {
1339 	char		laddr[PORTAL_STR_LEN];
1340 	char		raddr[PORTAL_STR_LEN];
1341 
1342 	sa_to_str(&ic->ic_laddr, laddr);
1343 	sa_to_str(&ic->ic_raddr, raddr);
1344 
1345 	mdb_printf("%20s: %s\n", "Conn Type",
1346 	    ((ic->ic_conn_type == CONN_TYPE_TGT) ? "Target" :
1347 	    ((ic->ic_conn_type == CONN_TYPE_INI) ? "Initiator" :
1348 	    "Unknown")));
1349 	if (ic->ic_conn_type == CONN_TYPE_TGT) {
1350 		mdb_printf("%20s: %p\n", "Svc. Binding",
1351 		    ic->ic_svc_binding);
1352 	}
1353 	mdb_printf("%20s: %s\n", "Transport",
1354 	    (ic->ic_transport_type == IDM_TRANSPORT_TYPE_ISER) ? "ISER_IB" :
1355 	    (ic->ic_transport_type == IDM_TRANSPORT_TYPE_SOCKETS) ? "SOCKETS" :
1356 	    "N/A");
1357 
1358 	mdb_printf("%20s: %s\n", "Local IP", laddr);
1359 	mdb_printf("%20s: %s\n", "Remote IP", raddr);
1360 	mdb_printf("%20s: %d\n", "State",
1361 	    ic->ic_state);
1362 	mdb_printf("%20s: %d\n", "Last State",
1363 	    ic->ic_last_state);
1364 	mdb_printf("%20s: %d %s\n", "Refcount",
1365 	    ic->ic_refcnt.ir_refcnt,
1366 	    (ic->ic_refcnt.ir_waiting == REF_NOWAIT) ? "" :
1367 	    ((ic->ic_refcnt.ir_waiting == REF_WAIT_SYNC) ? "REF_WAIT_SYNC" :
1368 	    ((ic->ic_refcnt.ir_waiting == REF_WAIT_ASYNC) ? "REF_WAIT_ASYNC" :
1369 	    "UNKNOWN")));
1370 }
1371 
1372 static int
1373 iscsi_i_task_impl(idm_task_t *idt, uintptr_t addr, iscsi_dcmd_ctrl_t *idc)
1374 {
1375 	uintptr_t	list_addr, rc_addr;
1376 	idm_conn_type_t	conn_type;
1377 	int		verbose, states, rc_audit;
1378 
1379 	conn_type = idm_conn_type((uintptr_t)idt->idt_ic);
1380 
1381 	verbose = idc->idc_verbose;
1382 	states = idc->u.child.idc_states;
1383 	rc_audit = idc->u.child.idc_rc_audit;
1384 
1385 	if (idc->u.child.idc_task) {
1386 		if (verbose) {
1387 			mdb_printf("Task %p\n", addr);
1388 			(void) mdb_inc_indent(2);
1389 			if (conn_type == CONN_TYPE_TGT) {
1390 				iscsi_print_iscsit_task_data(idt);
1391 			}
1392 			(void) mdb_dec_indent(2);
1393 		} else {
1394 			/* Print task data */
1395 			if (idc->idc_header) {
1396 				mdb_printf(
1397 				    "%<u>%-?s   %-?s %-8s %-8s %-8s%</u>\n",
1398 				    "Tasks/Active:", "Private",
1399 				    "Data SN", "Exp SN",
1400 				    (conn_type == CONN_TYPE_TGT ? "TTT" :
1401 				    (conn_type == CONN_TYPE_INI ? "ITT" :
1402 				    "TT")), "Handle");
1403 			}
1404 			mdb_printf("%?p %?p %08x %08x %08x %08x\n", addr,
1405 			    idt->idt_private, idt->idt_exp_datasn,
1406 			    idt->idt_exp_rttsn, idt->idt_tt,
1407 			    idt->idt_client_handle);
1408 		}
1409 	}
1410 	idc->idc_header = 0;
1411 	idc->idc_verbose = 0;
1412 
1413 	/*
1414 	 * Print states if requested
1415 	 */
1416 #if 0
1417 	if (states) {
1418 		states_addr = addr + offsetof(idm_task_t, idt_state_audit);
1419 
1420 		(void) mdb_inc_indent(4);
1421 		mdb_printf("State History:\n");
1422 		if (iscsi_sm_audit_impl(states_addr) != DCMD_OK)
1423 			return (DCMD_ERR);
1424 
1425 		/* Don't print state history for child objects */
1426 		idc->u.child.idc_states = 0;
1427 		(void) mdb_dec_indent(4);
1428 	}
1429 #endif
1430 
1431 	/*
1432 	 * Print refcnt audit data if requested
1433 	 */
1434 	if (rc_audit) {
1435 		(void) mdb_inc_indent(4);
1436 		mdb_printf("Reference History:\n");
1437 		rc_addr = addr +
1438 		    offsetof(idm_task_t, idt_refcnt);
1439 		if (iscsi_refcnt_impl(rc_addr) != DCMD_OK)
1440 			return (DCMD_ERR);
1441 
1442 		/* Don't print audit data for child objects */
1443 		idc->u.child.idc_rc_audit = 0;
1444 		(void) mdb_dec_indent(4);
1445 	}
1446 
1447 
1448 	/* Buffers are leaf objects */
1449 	if (idc->u.child.idc_buffer) {
1450 		/* Walk in buffer list */
1451 		(void) mdb_inc_indent(2);
1452 		mdb_printf("In buffers:\n");
1453 		idc->idc_header = 1;
1454 		(void) mdb_inc_indent(2);
1455 		list_addr = addr + offsetof(idm_task_t, idt_inbufv);
1456 		if (mdb_pwalk("list", iscsi_buffer_walk_cb, idc, list_addr) ==
1457 		    -1) {
1458 			mdb_warn("list walk failed for task in buffers");
1459 			(void) mdb_dec_indent(4);
1460 			return (DCMD_ERR);
1461 		}
1462 		(void) mdb_dec_indent(2);
1463 		/* Walk out buffer list */
1464 		mdb_printf("Out buffers:\n");
1465 		idc->idc_header = 1;
1466 		(void) mdb_inc_indent(2);
1467 		list_addr = addr + offsetof(idm_task_t, idt_outbufv);
1468 		if (mdb_pwalk("list", iscsi_buffer_walk_cb, idc, list_addr) ==
1469 		    -1) {
1470 			mdb_warn("list walk failed for task out buffers\n");
1471 			(void) mdb_dec_indent(2);
1472 			return (DCMD_ERR);
1473 		}
1474 		(void) mdb_dec_indent(4);
1475 	}
1476 
1477 	idc->idc_verbose = verbose;
1478 	idc->u.child.idc_states = states;
1479 	idc->u.child.idc_rc_audit = rc_audit;
1480 
1481 	return (DCMD_OK);
1482 }
1483 
1484 static int
1485 iscsi_task_impl(uintptr_t addr, iscsi_dcmd_ctrl_t *idc)
1486 {
1487 	idm_task_t	idt;
1488 
1489 	/*
1490 	 * Read idm_conn_t
1491 	 */
1492 	if (mdb_vread(&idt, sizeof (idm_task_t), addr) != sizeof (idm_task_t)) {
1493 		return (DCMD_ERR);
1494 	}
1495 
1496 	return (iscsi_i_task_impl(&idt, addr, idc));
1497 }
1498 
1499 #define	ISCSI_CDB_INDENT	16
1500 
1501 static void
1502 iscsi_print_iscsit_task_data(idm_task_t *idt)
1503 {
1504 	iscsit_task_t	itask;
1505 	boolean_t	good_scsi_task = B_TRUE;
1506 	scsi_task_t	scsi_task;
1507 
1508 	if (mdb_vread(&itask, sizeof (iscsit_task_t),
1509 	    (uintptr_t)idt->idt_private) != sizeof (iscsit_task_t)) {
1510 		mdb_printf("**Failed to read idt_private data\n");
1511 		return;
1512 	}
1513 
1514 	if (mdb_vread(&scsi_task, sizeof (scsi_task_t),
1515 	    (uintptr_t)itask.it_stmf_task) != sizeof (scsi_task_t)) {
1516 		good_scsi_task = B_FALSE;
1517 	}
1518 
1519 	mdb_printf("%20s: %p/%p/%p%s\n",
1520 	    "iscsit/STMF/LU", idt->idt_private,
1521 	    itask.it_stmf_task, good_scsi_task ? scsi_task.task_lu_private : 0,
1522 	    good_scsi_task ? "" : "**");
1523 	if (good_scsi_task) {
1524 		mdb_printf("%20s: %08x/%08x\n", "ITT/TTT",
1525 		    itask.it_itt, itask.it_ttt);
1526 		mdb_printf("%20s: %08x\n", "CmdSN",
1527 		    itask.it_cmdsn);
1528 		mdb_printf("%20s: %02x %02x %02x %02x %02x %02x %02x %02x\n",
1529 		    "LU number",
1530 		    scsi_task.task_lun_no[0], scsi_task.task_lun_no[1],
1531 		    scsi_task.task_lun_no[2], scsi_task.task_lun_no[3],
1532 		    scsi_task.task_lun_no[4], scsi_task.task_lun_no[5],
1533 		    scsi_task.task_lun_no[6], scsi_task.task_lun_no[7]);
1534 		mdb_printf("      CDB (%d bytes):\n",
1535 		    scsi_task.task_cdb_length);
1536 		(void) mdb_inc_indent(ISCSI_CDB_INDENT);
1537 		if (mdb_dumpptr((uintptr_t)scsi_task.task_cdb,
1538 		    scsi_task.task_cdb_length,
1539 		    MDB_DUMP_RELATIVE | MDB_DUMP_TRIM |
1540 		    MDB_DUMP_GROUP(1),
1541 		    (mdb_dumpptr_cb_t)mdb_vread, NULL)) {
1542 			mdb_printf("** Invalid CDB addr (%p)\n",
1543 			    scsi_task.task_cdb);
1544 		}
1545 		(void) mdb_dec_indent(ISCSI_CDB_INDENT);
1546 		mdb_printf("%20s: %d/%d\n", "STMF cur/max bufs",
1547 		    scsi_task.task_cur_nbufs,
1548 		    scsi_task.task_max_nbufs);
1549 		mdb_printf("%20s: 0x%08x/0x%08x/0x%08x\n", "Bytes Exp/Cmd/Done",
1550 		    scsi_task.task_expected_xfer_length,
1551 		    scsi_task.task_cmd_xfer_length,
1552 		    scsi_task.task_nbytes_transferred);
1553 		mdb_printf("%20s: 0x%x/0x%x\n", "TX-ini start/done",
1554 		    idt->idt_tx_to_ini_start,
1555 		    idt->idt_tx_to_ini_done);
1556 		mdb_printf("%20s: 0x%x/0x%x\n", "RX-ini start/done",
1557 		    idt->idt_rx_from_ini_start,
1558 		    idt->idt_rx_from_ini_done);
1559 	}
1560 }
1561 
1562 static int
1563 iscsi_buffer_impl(uintptr_t addr, iscsi_dcmd_ctrl_t *idc)
1564 {
1565 	idm_buf_t	idb;
1566 
1567 	/*
1568 	 * Read idm_buf_t
1569 	 */
1570 	if (mdb_vread(&idb, sizeof (idm_buf_t), addr) != sizeof (idm_buf_t)) {
1571 		return (DCMD_ERR);
1572 	}
1573 
1574 
1575 	if (idc->idc_header) {
1576 		mdb_printf("%<u>%-?s %?s/%-8s %8s %8s %8s%</u>\n",
1577 		    "idm_buf_t", "Mem Rgn", "Length",
1578 		    "Rel Off", "Xfer Len", "Exp. Off");
1579 	}
1580 	idc->idc_header = 0;
1581 
1582 	/* Print buffer data */
1583 	mdb_printf("%?p %?p/%08x %8x %8x %08x\n", addr,
1584 	    idb.idb_buf, idb.idb_buflen,
1585 	    idb.idb_bufoffset, idb.idb_xfer_len,
1586 	    idb.idb_exp_offset);
1587 
1588 
1589 	/* Buffers are leaf objects */
1590 
1591 	return (DCMD_OK);
1592 }
1593 
1594 static int
1595 iscsi_refcnt_impl(uintptr_t addr)
1596 {
1597 	idm_refcnt_t		refcnt;
1598 	refcnt_audit_buf_t	*anb;
1599 	int			ctr;
1600 
1601 	/*
1602 	 * Print refcnt info
1603 	 */
1604 	if (mdb_vread(&refcnt, sizeof (idm_refcnt_t), addr) !=
1605 	    sizeof (idm_refcnt_t)) {
1606 		return (DCMD_ERR);
1607 	}
1608 
1609 	anb = &refcnt.ir_audit_buf;
1610 
1611 	ctr = anb->anb_max_index + 1;
1612 	anb->anb_index--;
1613 	anb->anb_index &= anb->anb_max_index;
1614 
1615 	while (ctr) {
1616 		refcnt_audit_record_t	*anr;
1617 
1618 		anr = anb->anb_records + anb->anb_index;
1619 
1620 		if (anr->anr_depth) {
1621 			char c[MDB_SYM_NAMLEN];
1622 			GElf_Sym sym;
1623 			int i;
1624 
1625 			mdb_printf("\nRefCnt: %u\t", anr->anr_refcnt);
1626 
1627 			for (i = 0; i < anr->anr_depth; i++) {
1628 				if (mdb_lookup_by_addr(anr->anr_stack[i],
1629 				    MDB_SYM_FUZZY, c, sizeof (c),
1630 				    &sym) == -1) {
1631 					continue;
1632 				}
1633 				mdb_printf("%s+0x%1x", c,
1634 				    anr->anr_stack[i] -
1635 				    (uintptr_t)sym.st_value);
1636 				++i;
1637 				break;
1638 			}
1639 
1640 			while (i < anr->anr_depth) {
1641 				if (mdb_lookup_by_addr(anr->anr_stack[i],
1642 				    MDB_SYM_FUZZY, c, sizeof (c),
1643 				    &sym) == -1) {
1644 					++i;
1645 					continue;
1646 				}
1647 				mdb_printf("\n\t\t%s+0x%1x", c,
1648 				    anr->anr_stack[i] -
1649 				    (uintptr_t)sym.st_value);
1650 				++i;
1651 			}
1652 			mdb_printf("\n");
1653 		}
1654 		anb->anb_index--;
1655 		anb->anb_index &= anb->anb_max_index;
1656 		ctr--;
1657 	}
1658 
1659 	return (DCMD_OK);
1660 }
1661 
1662 static int
1663 iscsi_sm_audit_impl(uintptr_t addr)
1664 {
1665 	sm_audit_buf_t		audit_buf;
1666 	int			ctr;
1667 	const char		*event_name;
1668 	const char		*state_name;
1669 	const char		*new_state_name;
1670 	char			ts_string[40];
1671 	/*
1672 	 * Print refcnt info
1673 	 */
1674 	if (mdb_vread(&audit_buf, sizeof (sm_audit_buf_t), addr) !=
1675 	    sizeof (sm_audit_buf_t)) {
1676 		return (DCMD_ERR);
1677 	}
1678 
1679 	ctr = audit_buf.sab_max_index + 1;
1680 	audit_buf.sab_index++;
1681 	audit_buf.sab_index &= audit_buf.sab_max_index;
1682 
1683 	while (ctr) {
1684 		sm_audit_record_t	*sar;
1685 
1686 		sar = audit_buf.sab_records + audit_buf.sab_index;
1687 
1688 		iscsi_format_timestamp(ts_string, 40, &sar->sar_timestamp);
1689 
1690 		switch (sar->sar_type) {
1691 		case SAR_STATE_EVENT:
1692 			switch (sar->sar_sm_type) {
1693 			case SAS_IDM_CONN:
1694 				state_name =
1695 				    iscsi_idm_conn_state(sar->sar_state);
1696 				event_name =
1697 				    iscsi_idm_conn_event(sar->sar_event);
1698 				break;
1699 			case SAS_ISCSIT_TGT:
1700 				state_name =
1701 				    iscsi_iscsit_tgt_state(sar->sar_state);
1702 				event_name =
1703 				    iscsi_iscsit_tgt_event(sar->sar_event);
1704 				break;
1705 			case SAS_ISCSIT_SESS:
1706 				state_name =
1707 				    iscsi_iscsit_sess_state(sar->sar_state);
1708 				event_name =
1709 				    iscsi_iscsit_sess_event(sar->sar_event);
1710 				break;
1711 			case SAS_ISCSIT_LOGIN:
1712 				state_name =
1713 				    iscsi_iscsit_login_state(sar->sar_state);
1714 				event_name =
1715 				    iscsi_iscsit_login_event(sar->sar_event);
1716 				break;
1717 			default:
1718 				state_name = event_name = "N/A";
1719 				break;
1720 			}
1721 			mdb_printf("%s|%s (%d)\n\t%9s %s (%d) %p\n",
1722 			    ts_string, state_name, sar->sar_state,
1723 			    "Event", event_name,
1724 			    sar->sar_event, sar->sar_event_info);
1725 
1726 			break;
1727 		case SAR_STATE_CHANGE:
1728 			switch (sar->sar_sm_type) {
1729 			case SAS_IDM_CONN:
1730 				state_name =
1731 				    iscsi_idm_conn_state(sar->sar_state);
1732 				new_state_name =
1733 				    iscsi_idm_conn_state(sar->sar_new_state);
1734 				break;
1735 			case SAS_IDM_TASK:
1736 				state_name =
1737 				    iscsi_idm_task_state(sar->sar_state);
1738 				new_state_name =
1739 				    iscsi_idm_task_state(sar->sar_new_state);
1740 				break;
1741 			case SAS_ISCSIT_TGT:
1742 				state_name =
1743 				    iscsi_iscsit_tgt_state(sar->sar_state);
1744 				new_state_name =
1745 				    iscsi_iscsit_tgt_state(sar->sar_new_state);
1746 				break;
1747 			case SAS_ISCSIT_SESS:
1748 				state_name =
1749 				    iscsi_iscsit_sess_state(sar->sar_state);
1750 				new_state_name =
1751 				    iscsi_iscsit_sess_state(sar->sar_new_state);
1752 				break;
1753 			case SAS_ISCSIT_LOGIN:
1754 				state_name =
1755 				    iscsi_iscsit_login_state(sar->sar_state);
1756 				new_state_name =
1757 				    iscsi_iscsit_login_state(
1758 				    sar->sar_new_state);
1759 				break;
1760 			default:
1761 				break;
1762 			}
1763 			mdb_printf("%s|%s (%d)\n\t%9s %s (%d)\n",
1764 			    ts_string, state_name, sar->sar_state,
1765 			    "New State", new_state_name, sar->sar_new_state);
1766 		default:
1767 			state_name = new_state_name = "N/A";
1768 			break;
1769 		}
1770 
1771 		audit_buf.sab_index++;
1772 		audit_buf.sab_index &= audit_buf.sab_max_index;
1773 		ctr--;
1774 	}
1775 
1776 	return (DCMD_OK);
1777 }
1778 
1779 static const char *
1780 iscsi_idm_conn_event(int event)
1781 {
1782 	const char *name = "N/A";
1783 
1784 	event = (event > CE_MAX_EVENT) ? CE_MAX_EVENT : event;
1785 	name = idm_ce_name[event];
1786 
1787 	return (name);
1788 }
1789 
1790 static const char *
1791 iscsi_iscsit_tgt_event(int event)
1792 {
1793 	const char *name = "N/A";
1794 
1795 	event = (event > TE_MAX_EVENT) ? TE_MAX_EVENT : event;
1796 	name = iscsit_te_name[event];
1797 
1798 	return (name);
1799 }
1800 
1801 static const char *
1802 iscsi_iscsit_sess_event(int event)
1803 {
1804 	const char *name = "N/A";
1805 
1806 	event = (event > SE_MAX_EVENT) ? SE_MAX_EVENT : event;
1807 	name = iscsit_se_name[event];
1808 
1809 	return (name);
1810 }
1811 
1812 static const char *
1813 iscsi_iscsit_login_event(int event)
1814 {
1815 	const char *name = "N/A";
1816 
1817 	event = (event > ILE_MAX_EVENT) ? ILE_MAX_EVENT : event;
1818 	name = iscsit_ile_name[event];
1819 
1820 	return (name);
1821 }
1822 
1823 static const char *
1824 iscsi_idm_conn_state(int state)
1825 {
1826 	const char *name = "N/A";
1827 
1828 	state = (state > CS_MAX_STATE) ? CS_MAX_STATE : state;
1829 	name = idm_cs_name[state];
1830 
1831 	return (name);
1832 }
1833 
1834 /*ARGSUSED*/
1835 static const char *
1836 iscsi_idm_task_state(int state)
1837 {
1838 	const char *name = "N/A";
1839 	return (name);
1840 }
1841 
1842 static const char *
1843 iscsi_iscsit_tgt_state(int state)
1844 {
1845 	const char *name = "N/A";
1846 
1847 	state = (state > TS_MAX_STATE) ? TS_MAX_STATE : state;
1848 	name = iscsit_ts_name[state];
1849 
1850 	return (name);
1851 }
1852 
1853 static const char *
1854 iscsi_iscsit_sess_state(int state)
1855 {
1856 	const char *name = "N/A";
1857 
1858 	state = (state > SS_MAX_STATE) ? SS_MAX_STATE : state;
1859 	name = iscsit_ss_name[state];
1860 
1861 	return (name);
1862 }
1863 
1864 static const char *
1865 iscsi_iscsit_login_state(int state)
1866 {
1867 	const char *name = "N/A";
1868 
1869 	state = (state > ILS_MAX_STATE) ? ILS_MAX_STATE : state;
1870 	name = iscsit_ils_name[state];
1871 
1872 	return (name);
1873 }
1874 
1875 
1876 
1877 /*
1878  * Retrieve connection type given a kernel address
1879  */
1880 static idm_conn_type_t
1881 idm_conn_type(uintptr_t addr)
1882 {
1883 	idm_conn_type_t result = 0; /* Unknown */
1884 	uintptr_t idm_conn_type_addr;
1885 
1886 	idm_conn_type_addr = addr + offsetof(idm_conn_t, ic_conn_type);
1887 	(void) mdb_vread(&result, sizeof (result), idm_conn_type_addr);
1888 
1889 	return (result);
1890 }
1891 
1892 /*
1893  * Convert a sockaddr to the string representation, suitable for
1894  * storing in an nvlist or printing out in a list.
1895  */
1896 static int
1897 sa_to_str(struct sockaddr_storage *sa, char *buf)
1898 {
1899 	char			pbuf[7];
1900 	const char		*bufp;
1901 	struct sockaddr_in	*sin;
1902 	struct sockaddr_in6	*sin6;
1903 	uint16_t		port;
1904 
1905 	if (!sa || !buf) {
1906 		return (EINVAL);
1907 	}
1908 
1909 	buf[0] = '\0';
1910 
1911 	if (sa->ss_family == AF_INET) {
1912 		sin = (struct sockaddr_in *)sa;
1913 		bufp = inet_ntop(AF_INET,
1914 		    (const void *)&(sin->sin_addr.s_addr),
1915 		    buf, PORTAL_STR_LEN);
1916 		if (bufp == NULL) {
1917 			return (-1);
1918 		}
1919 		mdb_nhconvert(&port, &sin->sin_port, sizeof (uint16_t));
1920 	} else if (sa->ss_family == AF_INET6) {
1921 		strlcat(buf, "[", sizeof (buf));
1922 		sin6 = (struct sockaddr_in6 *)sa;
1923 		bufp = inet_ntop(AF_INET6,
1924 		    (const void *)&sin6->sin6_addr.s6_addr,
1925 		    &buf[1], PORTAL_STR_LEN - 1);
1926 		if (bufp == NULL) {
1927 			return (-1);
1928 		}
1929 		strlcat(buf, "]", PORTAL_STR_LEN);
1930 		mdb_nhconvert(&port, &sin->sin_port, sizeof (uint16_t));
1931 	} else {
1932 		return (EINVAL);
1933 	}
1934 
1935 
1936 	mdb_snprintf(pbuf, sizeof (pbuf), ":%u", port);
1937 	strlcat(buf, pbuf, PORTAL_STR_LEN);
1938 
1939 	return (0);
1940 }
1941 
1942 
1943 static void
1944 iscsi_format_timestamp(char *ts_str, int strlen, timespec_t *ts)
1945 {
1946 	mdb_snprintf(ts_str, strlen, "%Y:%03d:%03d:%03d", ts->tv_sec,
1947 	    (ts->tv_nsec / 1000000) % 1000, (ts->tv_nsec / 1000) % 1000,
1948 	    ts->tv_nsec % 1000);
1949 }
1950 
1951 /*
1952  * Help information for the iscsi_isns dcmd
1953  */
1954 static void
1955 iscsi_isns_help(void)
1956 {
1957 	mdb_printf("iscsi_isns:\n");
1958 	mdb_inc_indent(4);
1959 	mdb_printf("-e: Print ESI information\n");
1960 	mdb_printf("-p: Print portal information\n");
1961 	mdb_printf("-s: Print iSNS server information\n");
1962 	mdb_printf("-t: Print target information\n");
1963 	mdb_printf("-v: Add verbosity to the other options' output\n");
1964 	mdb_dec_indent(4);
1965 }
1966 
1967 /* ARGSUSED */
1968 static int
1969 iscsi_isns_esi_cb(uintptr_t addr, const void *walker_data, void *data)
1970 {
1971 	iscsi_dcmd_ctrl_t *idc = (iscsi_dcmd_ctrl_t *)data;
1972 	isns_esi_tinfo_t tinfo;
1973 
1974 	if (mdb_vread(&tinfo, sizeof (isns_esi_tinfo_t), addr) !=
1975 	    sizeof (isns_esi_tinfo_t)) {
1976 		return (WALK_ERR);
1977 	}
1978 
1979 	mdb_printf("ESI portal         : 0x%p\n", tinfo.esi_portal);
1980 	if (idc->idc_verbose) {
1981 		mdb_inc_indent(4);
1982 		iscsi_isns_portal_cb((uintptr_t)tinfo.esi_portal, NULL, data);
1983 		mdb_dec_indent(4);
1984 	}
1985 	mdb_printf("ESI thread/thr did : 0x%p / %d\n", tinfo.esi_thread,
1986 	    tinfo.esi_thread_did);
1987 	mdb_printf("ESI sonode         : 0x%p\n", tinfo.esi_so);
1988 	mdb_printf("ESI port           : %d\n", tinfo.esi_port);
1989 	mdb_printf("ESI thread running : %s\n",
1990 	    (tinfo.esi_thread_running) ? "Yes" : "No");
1991 	if (!tinfo.esi_thread_running) {
1992 		mdb_printf("ESI thread failed  : %s\n",
1993 		    (tinfo.esi_thread_failed) ? "Yes" : "No");
1994 	}
1995 	mdb_printf("ESI registered     : %s\n\n",
1996 	    (tinfo.esi_registered) ? "Yes" : "No");
1997 
1998 	return (WALK_NEXT);
1999 }
2000 
2001 static int
2002 iscsi_isns_esi(iscsi_dcmd_ctrl_t *idc)
2003 {
2004 	GElf_Sym sym;
2005 	uintptr_t esi_list;
2006 
2007 	if (mdb_lookup_by_name("esi_list", &sym) == -1) {
2008 		mdb_warn("failed to find symbol 'esi_list'");
2009 		return (DCMD_ERR);
2010 	}
2011 
2012 	esi_list = (uintptr_t)sym.st_value;
2013 	idc->idc_header = 1;
2014 
2015 	if (mdb_pwalk("list", iscsi_isns_esi_cb, idc, esi_list) == -1) {
2016 		mdb_warn("avl walk failed for esi_list");
2017 		return (DCMD_ERR);
2018 	}
2019 
2020 	return (0);
2021 }
2022 
2023 /* ARGSUSED */
2024 static int
2025 iscsi_isns_portal_cb(uintptr_t addr, const void *walker_data, void *data)
2026 {
2027 	iscsi_dcmd_ctrl_t *idc = (iscsi_dcmd_ctrl_t *)data;
2028 	isns_portal_list_t portal;
2029 	char portal_addr[PORTAL_STR_LEN];
2030 	struct sockaddr_storage *ss;
2031 
2032 	if (mdb_vread(&portal, sizeof (isns_portal_list_t), addr) !=
2033 	    sizeof (isns_portal_list_t)) {
2034 		return (WALK_ERR);
2035 	}
2036 
2037 	ss = &portal.portal_addr;
2038 	sa_to_str(ss, portal_addr);
2039 	mdb_printf("Portal IP address ");
2040 
2041 	if (ss->ss_family == AF_INET) {
2042 		mdb_printf("(v4): %s", portal_addr);
2043 	} else {
2044 		mdb_printf("(v6): %s", portal_addr);
2045 	}
2046 
2047 	if (portal.portal_iscsit == NULL) {
2048 		mdb_printf(" (Default portal)\n");
2049 	} else {
2050 		mdb_printf("\n");
2051 	}
2052 
2053 	if ((portal.portal_iscsit != NULL) && (idc->idc_verbose)) {
2054 		iscsi_portal_impl((uintptr_t)portal.portal_iscsit, idc);
2055 	}
2056 
2057 	mdb_printf("Portal ESI info: 0x%p\n\n", portal.portal_esi);
2058 
2059 	return (WALK_NEXT);
2060 }
2061 
2062 static int
2063 iscsi_isns_portals(iscsi_dcmd_ctrl_t *idc)
2064 {
2065 	GElf_Sym sym;
2066 	uintptr_t portal_list;
2067 
2068 	if (mdb_lookup_by_name("portal_list", &sym) == -1) {
2069 		mdb_warn("failed to find symbol 'portal_list'");
2070 		return (DCMD_ERR);
2071 	}
2072 
2073 	portal_list = (uintptr_t)sym.st_value;
2074 	idc->idc_header = 1;
2075 
2076 	if (mdb_pwalk("list", iscsi_isns_portal_cb, idc, portal_list) == -1) {
2077 		mdb_warn("avl walk failed for portal_list");
2078 		return (DCMD_ERR);
2079 	}
2080 
2081 	return (0);
2082 }
2083 
2084 /* ARGSUSED */
2085 static int
2086 iscsi_isns_targets_cb(uintptr_t addr, const void *walker_data, void *data)
2087 {
2088 	iscsi_dcmd_ctrl_t *idc = (iscsi_dcmd_ctrl_t *)data;
2089 	isns_target_t	itarget;
2090 	int		rc = 0;
2091 
2092 	if (mdb_vread(&itarget, sizeof (isns_target_t), addr) !=
2093 	    sizeof (isns_target_t)) {
2094 		return (WALK_ERR);
2095 	}
2096 
2097 	idc->idc_header = 1;
2098 
2099 	mdb_printf("Target: %p\n", itarget.target);
2100 	mdb_inc_indent(4);
2101 	mdb_printf("Registered: %s\n",
2102 	    (itarget.target_registered) ? "Yes" : "No");
2103 
2104 	rc = iscsi_tgt_impl((uintptr_t)itarget.target, idc);
2105 
2106 	mdb_dec_indent(4);
2107 
2108 	if (rc == DCMD_OK) {
2109 		return (WALK_NEXT);
2110 	}
2111 
2112 	return (WALK_ERR);
2113 }
2114 
2115 static int
2116 iscsi_isns_targets(iscsi_dcmd_ctrl_t *idc)
2117 {
2118 	GElf_Sym sym;
2119 	uintptr_t isns_target_list;
2120 
2121 	if (mdb_lookup_by_name("isns_target_list", &sym) == -1) {
2122 		mdb_warn("failed to find symbol 'isns_target_list'");
2123 		return (DCMD_ERR);
2124 	}
2125 
2126 	isns_target_list = (uintptr_t)sym.st_value;
2127 	idc->idc_header = 1;
2128 	idc->u.child.idc_tgt = 1;
2129 
2130 	if (mdb_pwalk("avl", iscsi_isns_targets_cb, idc,
2131 	    isns_target_list) == -1) {
2132 		mdb_warn("avl walk failed for isns_target_list");
2133 		return (DCMD_ERR);
2134 	}
2135 
2136 	return (0);
2137 }
2138 
2139 /* ARGSUSED */
2140 static int
2141 iscsi_isns_servers_cb(uintptr_t addr, const void *walker_data, void *data)
2142 {
2143 	GElf_Sym		sym;
2144 	iscsit_isns_svr_t	server;
2145 	char			server_addr[PORTAL_STR_LEN];
2146 	struct sockaddr_storage *ss;
2147 	clock_t			lbolt;
2148 
2149 	if (mdb_vread(&server, sizeof (iscsit_isns_svr_t), addr) !=
2150 	    sizeof (iscsit_isns_svr_t)) {
2151 		return (WALK_ERR);
2152 	}
2153 
2154 	if (mdb_lookup_by_name("lbolt", &sym) == -1) {
2155 		mdb_warn("failed to find symbol 'lbolt'");
2156 		return (DCMD_ERR);
2157 	}
2158 
2159 	if (mdb_vread(&lbolt, sizeof (clock_t), sym.st_value) !=
2160 	    sizeof (clock_t)) {
2161 		return (WALK_ERR);
2162 	}
2163 
2164 	mdb_printf("iSNS server %p:\n", addr);
2165 	mdb_inc_indent(4);
2166 	ss = &server.svr_sa;
2167 	sa_to_str(ss, server_addr);
2168 
2169 	mdb_printf("IP address ");
2170 	if (ss->ss_family == AF_INET) {
2171 		mdb_printf("(v4): %s\n", server_addr);
2172 	} else {
2173 		mdb_printf("(v6): %s\n", server_addr);
2174 	}
2175 
2176 	mdb_printf("Last ESI message : %d seconds ago\n",
2177 	    ((lbolt - server.svr_last_msg) / 100));
2178 	mdb_printf("Client registered: %s\n",
2179 	    (server.svr_registered) ? "Yes" : "No");
2180 	mdb_dec_indent(4);
2181 
2182 	return (WALK_ERR);
2183 }
2184 
2185 static int
2186 iscsi_isns_servers(iscsi_dcmd_ctrl_t *idc)
2187 {
2188 	uintptr_t	iscsit_global_addr;
2189 	uintptr_t	list_addr;
2190 	GElf_Sym	sym;
2191 
2192 	if (mdb_lookup_by_name("iscsit_global", &sym) == -1) {
2193 		mdb_warn("failed to find symbol 'iscsit_global'");
2194 		return (DCMD_ERR);
2195 	}
2196 
2197 	iscsit_global_addr = (uintptr_t)sym.st_value;
2198 	idc->idc_header = 1;
2199 	list_addr = iscsit_global_addr +
2200 	    offsetof(iscsit_global_t, global_isns_cfg.isns_svrs);
2201 
2202 	if (mdb_pwalk("list", iscsi_isns_servers_cb, idc, list_addr) == -1) {
2203 		mdb_warn("list walk failed for iSNS servers");
2204 		return (DCMD_ERR);
2205 	}
2206 
2207 	return (0);
2208 }
2209 
2210 /* ARGSUSED */
2211 static int
2212 iscsi_isns(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2213 {
2214 	iscsi_dcmd_ctrl_t idc;
2215 	int portals = 0, esi = 0, targets = 0, verbose = 0, servers = 0;
2216 
2217 	if (flags & DCMD_ADDRSPEC) {
2218 		mdb_warn("iscsi_isns is only a global dcmd.");
2219 		return (DCMD_ERR);
2220 	}
2221 
2222 	bzero(&idc, sizeof (idc));
2223 	if (mdb_getopts(argc, argv,
2224 	    'e', MDB_OPT_SETBITS, TRUE, &esi,
2225 	    'p', MDB_OPT_SETBITS, TRUE, &portals,
2226 	    's', MDB_OPT_SETBITS, TRUE, &servers,
2227 	    't', MDB_OPT_SETBITS, TRUE, &targets,
2228 	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
2229 	    NULL) != argc)
2230 		return (DCMD_USAGE);
2231 
2232 	if ((esi + portals + targets + servers) > 1) {
2233 		mdb_printf("Only one of e, p, s, and t must be provided");
2234 		return (DCMD_ERR);
2235 	}
2236 
2237 	if ((esi | portals | targets | servers) == 0) {
2238 		mdb_printf("Exactly one of e, p, s, or t must be provided");
2239 		return (DCMD_ERR);
2240 	}
2241 
2242 	idc.idc_verbose = verbose;
2243 
2244 	if (esi) {
2245 		return (iscsi_isns_esi(&idc));
2246 	}
2247 
2248 	if (portals) {
2249 		return (iscsi_isns_portals(&idc));
2250 	}
2251 
2252 	if (servers) {
2253 		return (iscsi_isns_servers(&idc));
2254 	}
2255 
2256 	return (iscsi_isns_targets(&idc));
2257 }
2258 
2259 /*
2260  * inet_ntop -- Convert an IPv4 or IPv6 address in binary form into
2261  * printable form, and return a pointer to that string. Caller should
2262  * provide a buffer of correct length to store string into.
2263  * Note: this routine is kernel version of inet_ntop. It has similar
2264  * format as inet_ntop() defined in rfc2553. But it does not do
2265  * error handling operations exactly as rfc2553 defines. This function
2266  * is used by kernel inet directory routines only for debugging.
2267  * This inet_ntop() function, does not return NULL if third argument
2268  * is NULL. The reason is simple that we don't want kernel to panic
2269  * as the output of this function is directly fed to ip<n>dbg macro.
2270  * Instead it uses a local buffer for destination address for
2271  * those calls which purposely pass NULL ptr for the destination
2272  * buffer. This function is thread-safe when the caller passes a non-
2273  * null buffer with the third argument.
2274  */
2275 /* ARGSUSED */
2276 
2277 #define	OK_16PTR(p)	(!((uintptr_t)(p) & 0x1))
2278 #if defined(__x86)
2279 #define	OK_32PTR(p)	OK_16PTR(p)
2280 #else
2281 #define	OK_32PTR(p)	(!((uintptr_t)(p) & 0x3))
2282 #endif
2283 
2284 char *
2285 inet_ntop(int af, const void *addr, char *buf, int addrlen)
2286 {
2287 	static char local_buf[PORTAL_STR_LEN];
2288 	static char *err_buf1 = "<badaddr>";
2289 	static char *err_buf2 = "<badfamily>";
2290 	in6_addr_t	*v6addr;
2291 	uchar_t		*v4addr;
2292 	char		*caddr;
2293 
2294 	/*
2295 	 * We don't allow thread unsafe inet_ntop calls, they
2296 	 * must pass a non-null buffer pointer. For DEBUG mode
2297 	 * we use the ASSERT() and for non-debug kernel it will
2298 	 * silently allow it for now. Someday we should remove
2299 	 * the static buffer from this function.
2300 	 */
2301 
2302 	ASSERT(buf != NULL);
2303 	if (buf == NULL)
2304 		buf = local_buf;
2305 	buf[0] = '\0';
2306 
2307 	/* Let user know politely not to send NULL or unaligned addr */
2308 	if (addr == NULL || !(OK_32PTR(addr))) {
2309 		return (err_buf1);
2310 	}
2311 
2312 
2313 #define	UC(b)	(((int)b) & 0xff)
2314 	switch (af) {
2315 	case AF_INET:
2316 		ASSERT(addrlen >= INET_ADDRSTRLEN);
2317 		v4addr = (uchar_t *)addr;
2318 		(void) mdb_snprintf(buf, INET6_ADDRSTRLEN,
2319 		    "%03d.%03d.%03d.%03d",
2320 		    UC(v4addr[0]), UC(v4addr[1]), UC(v4addr[2]), UC(v4addr[3]));
2321 		return (buf);
2322 
2323 	case AF_INET6:
2324 		ASSERT(addrlen >= INET6_ADDRSTRLEN);
2325 		v6addr = (in6_addr_t *)addr;
2326 		if (IN6_IS_ADDR_V4MAPPED(v6addr)) {
2327 			caddr = (char *)addr;
2328 			(void) mdb_snprintf(buf, INET6_ADDRSTRLEN,
2329 			    "::ffff:%d.%d.%d.%d",
2330 			    UC(caddr[12]), UC(caddr[13]),
2331 			    UC(caddr[14]), UC(caddr[15]));
2332 		} else if (IN6_IS_ADDR_V4COMPAT(v6addr)) {
2333 			caddr = (char *)addr;
2334 			(void) mdb_snprintf(buf, INET6_ADDRSTRLEN,
2335 			    "::%d.%d.%d.%d",
2336 			    UC(caddr[12]), UC(caddr[13]), UC(caddr[14]),
2337 			    UC(caddr[15]));
2338 		} else if (IN6_IS_ADDR_UNSPECIFIED(v6addr)) {
2339 			(void) mdb_snprintf(buf, INET6_ADDRSTRLEN, "::");
2340 		} else {
2341 			convert2ascii(buf, v6addr);
2342 		}
2343 		return (buf);
2344 
2345 	default:
2346 		return (err_buf2);
2347 	}
2348 #undef UC
2349 }
2350 
2351 /*
2352  *
2353  * v6 formats supported
2354  * General format xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
2355  * The short hand notation :: is used for COMPAT addr
2356  * Other forms : fe80::xxxx:xxxx:xxxx:xxxx
2357  */
2358 static void
2359 convert2ascii(char *buf, const in6_addr_t *addr)
2360 {
2361 	int		hexdigits;
2362 	int		head_zero = 0;
2363 	int		tail_zero = 0;
2364 	/* tempbuf must be big enough to hold ffff:\0 */
2365 	char		tempbuf[6];
2366 	char		*ptr;
2367 	uint16_t	out_addr_component;
2368 	uint16_t	*addr_component;
2369 	size_t		len;
2370 	boolean_t	first = B_FALSE;
2371 	boolean_t	med_zero = B_FALSE;
2372 	boolean_t	end_zero = B_FALSE;
2373 
2374 	addr_component = (uint16_t *)addr;
2375 	ptr = buf;
2376 
2377 	/* First count if trailing zeroes higher in number */
2378 	for (hexdigits = 0; hexdigits < 8; hexdigits++) {
2379 		if (*addr_component == 0) {
2380 			if (hexdigits < 4)
2381 				head_zero++;
2382 			else
2383 				tail_zero++;
2384 		}
2385 		addr_component++;
2386 	}
2387 	addr_component = (uint16_t *)addr;
2388 	if (tail_zero > head_zero && (head_zero + tail_zero) != 7)
2389 		end_zero = B_TRUE;
2390 
2391 	for (hexdigits = 0; hexdigits < 8; hexdigits++) {
2392 
2393 		/* if entry is a 0 */
2394 
2395 		if (*addr_component == 0) {
2396 			if (!first && *(addr_component + 1) == 0) {
2397 				if (end_zero && (hexdigits < 4)) {
2398 					*ptr++ = '0';
2399 					*ptr++ = ':';
2400 				} else {
2401 					/*
2402 					 * address starts with 0s ..
2403 					 * stick in leading ':' of pair
2404 					 */
2405 					if (hexdigits == 0)
2406 						*ptr++ = ':';
2407 					/* add another */
2408 					*ptr++ = ':';
2409 					first = B_TRUE;
2410 					med_zero = B_TRUE;
2411 				}
2412 			} else if (first && med_zero) {
2413 				if (hexdigits == 7)
2414 					*ptr++ = ':';
2415 				addr_component++;
2416 				continue;
2417 			} else {
2418 				*ptr++ = '0';
2419 				*ptr++ = ':';
2420 			}
2421 			addr_component++;
2422 			continue;
2423 		}
2424 		if (med_zero)
2425 			med_zero = B_FALSE;
2426 
2427 		tempbuf[0] = '\0';
2428 		mdb_nhconvert(&out_addr_component, addr_component,
2429 		    sizeof (uint16_t));
2430 		(void) mdb_snprintf(tempbuf, 6, "%x:", out_addr_component);
2431 		len = strlen(tempbuf);
2432 		bcopy(tempbuf, ptr, len);
2433 		ptr = ptr + len;
2434 		addr_component++;
2435 	}
2436 	*--ptr = '\0';
2437 }
2438 
2439 
2440 /*
2441  * MDB module linkage information:
2442  *
2443  * We declare a list of structures describing our dcmds, a list of structures
2444  * describing our walkers and a function named _mdb_init to return a pointer
2445  * to our module information.
2446  */
2447 static const mdb_dcmd_t dcmds[] = {
2448 	{   "iscsi_tgt", "[-agsctbSRv]",
2449 	    "iSCSI target information", iscsi_tgt },
2450 	{   "iscsi_tpg", "[-v]",
2451 	    "iSCSI target portal group information", iscsi_tpg },
2452 	{   "iscsi_sess", "[-abtvcSRIT]",
2453 	    "iSCSI session information", iscsi_sess },
2454 	{   "iscsi_conn", "[-abtvSRIT]",
2455 	    "iSCSI connection information", iscsi_conn },
2456 	{   "iscsi_task", "[-bSRv]",
2457 	    "iSCSI task information", iscsi_task },
2458 	{   "iscsi_refcnt", "",
2459 	    "Print audit informtion for idm_refcnt_t", iscsi_refcnt },
2460 	{   "iscsi_states", "",
2461 	    "Dump events and state transitions recorded in an\t"
2462 	    "\t\tidm_sm_audit_t structure", iscsi_states },
2463 	{   "iscsi_isns", "[-epstv]",
2464 	    "Print iscsit iSNS information", iscsi_isns, iscsi_isns_help },
2465 	{ NULL }
2466 };
2467 
2468 /*
2469  * No walkers for now.  Initiator might need some since it doesn't use list_t
2470  */
2471 
2472 static const mdb_modinfo_t modinfo = {
2473 	MDB_API_VERSION, dcmds, NULL
2474 };
2475 
2476 const mdb_modinfo_t *
2477 _mdb_init(void)
2478 {
2479 	return (&modinfo);
2480 }
2481