xref: /titanic_50/usr/src/cmd/mdb/common/modules/idm/idm.c (revision bf604c6405d5cbc4e94e3d0ecc9e6e074ed4ea67)
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	IDM_TASK_SM_STRINGS
43 #define	ISCSIT_TGT_SM_STRINGS
44 #define	ISCSIT_SESS_SM_STRINGS
45 #define	ISCSIT_LOGIN_SM_STRINGS
46 #include <sys/idm/idm.h>
47 #include <iscsit.h>
48 #include <iscsit_isns.h>
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 %-16s %-4s %-8s %-8s%</u>\n",
1398 				    "Tasks:", "State", "Ref",
1399 				    (conn_type == CONN_TYPE_TGT ? "TTT" :
1400 				    (conn_type == CONN_TYPE_INI ? "ITT" :
1401 				    "TT")), "Handle");
1402 			}
1403 			mdb_printf("%?p %-16s %04x %08x %08x\n", addr,
1404 			    idm_ts_name[idt->idt_state],
1405 			    idt->idt_refcnt.ir_refcnt,
1406 			    idt->idt_tt, idt->idt_client_handle);
1407 		}
1408 	}
1409 	idc->idc_header = 0;
1410 	idc->idc_verbose = 0;
1411 
1412 	/*
1413 	 * Print states if requested
1414 	 */
1415 #if 0
1416 	if (states) {
1417 		states_addr = addr + offsetof(idm_task_t, idt_state_audit);
1418 
1419 		(void) mdb_inc_indent(4);
1420 		mdb_printf("State History:\n");
1421 		if (iscsi_sm_audit_impl(states_addr) != DCMD_OK)
1422 			return (DCMD_ERR);
1423 
1424 		/* Don't print state history for child objects */
1425 		idc->u.child.idc_states = 0;
1426 		(void) mdb_dec_indent(4);
1427 	}
1428 #endif
1429 
1430 	/*
1431 	 * Print refcnt audit data if requested
1432 	 */
1433 	if (rc_audit) {
1434 		(void) mdb_inc_indent(4);
1435 		mdb_printf("Reference History:\n");
1436 		rc_addr = addr +
1437 		    offsetof(idm_task_t, idt_refcnt);
1438 		if (iscsi_refcnt_impl(rc_addr) != DCMD_OK)
1439 			return (DCMD_ERR);
1440 
1441 		/* Don't print audit data for child objects */
1442 		idc->u.child.idc_rc_audit = 0;
1443 		(void) mdb_dec_indent(4);
1444 	}
1445 
1446 
1447 	/* Buffers are leaf objects */
1448 	if (idc->u.child.idc_buffer) {
1449 		/* Walk in buffer list */
1450 		(void) mdb_inc_indent(2);
1451 		mdb_printf("In buffers:\n");
1452 		idc->idc_header = 1;
1453 		(void) mdb_inc_indent(2);
1454 		list_addr = addr + offsetof(idm_task_t, idt_inbufv);
1455 		if (mdb_pwalk("list", iscsi_buffer_walk_cb, idc, list_addr) ==
1456 		    -1) {
1457 			mdb_warn("list walk failed for task in buffers");
1458 			(void) mdb_dec_indent(4);
1459 			return (DCMD_ERR);
1460 		}
1461 		(void) mdb_dec_indent(2);
1462 		/* Walk out buffer list */
1463 		mdb_printf("Out buffers:\n");
1464 		idc->idc_header = 1;
1465 		(void) mdb_inc_indent(2);
1466 		list_addr = addr + offsetof(idm_task_t, idt_outbufv);
1467 		if (mdb_pwalk("list", iscsi_buffer_walk_cb, idc, list_addr) ==
1468 		    -1) {
1469 			mdb_warn("list walk failed for task out buffers\n");
1470 			(void) mdb_dec_indent(2);
1471 			return (DCMD_ERR);
1472 		}
1473 		(void) mdb_dec_indent(4);
1474 	}
1475 
1476 	idc->idc_verbose = verbose;
1477 	idc->u.child.idc_states = states;
1478 	idc->u.child.idc_rc_audit = rc_audit;
1479 
1480 	return (DCMD_OK);
1481 }
1482 
1483 static int
1484 iscsi_task_impl(uintptr_t addr, iscsi_dcmd_ctrl_t *idc)
1485 {
1486 	idm_task_t	idt;
1487 
1488 	/*
1489 	 * Read idm_conn_t
1490 	 */
1491 	if (mdb_vread(&idt, sizeof (idm_task_t), addr) != sizeof (idm_task_t)) {
1492 		return (DCMD_ERR);
1493 	}
1494 
1495 	return (iscsi_i_task_impl(&idt, addr, idc));
1496 }
1497 
1498 #define	ISCSI_CDB_INDENT	16
1499 
1500 static void
1501 iscsi_print_iscsit_task_data(idm_task_t *idt)
1502 {
1503 	iscsit_task_t	itask;
1504 	boolean_t	good_scsi_task = B_TRUE;
1505 	scsi_task_t	scsi_task;
1506 
1507 	if (mdb_vread(&itask, sizeof (iscsit_task_t),
1508 	    (uintptr_t)idt->idt_private) != sizeof (iscsit_task_t)) {
1509 		mdb_printf("**Failed to read idt_private data\n");
1510 		return;
1511 	}
1512 
1513 	if (mdb_vread(&scsi_task, sizeof (scsi_task_t),
1514 	    (uintptr_t)itask.it_stmf_task) != sizeof (scsi_task_t)) {
1515 		good_scsi_task = B_FALSE;
1516 	}
1517 
1518 	mdb_printf("%20s: %s(%d)\n", "State",
1519 	    idt->idt_state > TASK_MAX_STATE ?
1520 	    "UNKNOWN" : idm_ts_name[idt->idt_state],
1521 	    idt->idt_state);
1522 	mdb_printf("%20s: %d/%d\n", "STMF abort/IDM aborted",
1523 	    itask.it_stmf_abort, itask.it_aborted);
1524 	mdb_printf("%20s: %p/%p/%p%s\n",
1525 	    "iscsit/STMF/LU", idt->idt_private,
1526 	    itask.it_stmf_task, good_scsi_task ? scsi_task.task_lu_private : 0,
1527 	    good_scsi_task ? "" : "**");
1528 	if (good_scsi_task) {
1529 		mdb_printf("%20s: %08x/%08x\n", "ITT/TTT",
1530 		    itask.it_itt, itask.it_ttt);
1531 		mdb_printf("%20s: %08x\n", "CmdSN",
1532 		    itask.it_cmdsn);
1533 		mdb_printf("%20s: %02x %02x %02x %02x %02x %02x %02x %02x\n",
1534 		    "LU number",
1535 		    scsi_task.task_lun_no[0], scsi_task.task_lun_no[1],
1536 		    scsi_task.task_lun_no[2], scsi_task.task_lun_no[3],
1537 		    scsi_task.task_lun_no[4], scsi_task.task_lun_no[5],
1538 		    scsi_task.task_lun_no[6], scsi_task.task_lun_no[7]);
1539 		mdb_printf("     CDB (%d bytes):\n",
1540 		    scsi_task.task_cdb_length);
1541 		(void) mdb_inc_indent(ISCSI_CDB_INDENT);
1542 		if (mdb_dumpptr((uintptr_t)scsi_task.task_cdb,
1543 		    scsi_task.task_cdb_length,
1544 		    MDB_DUMP_RELATIVE | MDB_DUMP_TRIM |
1545 		    MDB_DUMP_GROUP(1),
1546 		    (mdb_dumpptr_cb_t)mdb_vread, NULL)) {
1547 			mdb_printf("** Invalid CDB addr (%p)\n",
1548 			    scsi_task.task_cdb);
1549 		}
1550 		(void) mdb_dec_indent(ISCSI_CDB_INDENT);
1551 		mdb_printf("%20s: %d/%d\n", "STMF cur/max bufs",
1552 		    scsi_task.task_cur_nbufs,
1553 		    scsi_task.task_max_nbufs);
1554 		mdb_printf("%20s: 0x%08x/0x%08x/0x%08x\n", "Bytes Exp/Cmd/Done",
1555 		    scsi_task.task_expected_xfer_length,
1556 		    scsi_task.task_cmd_xfer_length,
1557 		    scsi_task.task_nbytes_transferred);
1558 		mdb_printf("%20s: 0x%x/0x%x\n", "TX-ini start/done",
1559 		    idt->idt_tx_to_ini_start,
1560 		    idt->idt_tx_to_ini_done);
1561 		mdb_printf("%20s: 0x%x/0x%x\n", "RX-ini start/done",
1562 		    idt->idt_rx_from_ini_start,
1563 		    idt->idt_rx_from_ini_done);
1564 	}
1565 }
1566 
1567 static int
1568 iscsi_buffer_impl(uintptr_t addr, iscsi_dcmd_ctrl_t *idc)
1569 {
1570 	idm_buf_t	idb;
1571 
1572 	/*
1573 	 * Read idm_buf_t
1574 	 */
1575 	if (mdb_vread(&idb, sizeof (idm_buf_t), addr) != sizeof (idm_buf_t)) {
1576 		return (DCMD_ERR);
1577 	}
1578 
1579 
1580 	if (idc->idc_header) {
1581 		mdb_printf("%<u>%-?s %?s/%-8s %8s %8s %8s%</u>\n",
1582 		    "idm_buf_t", "Mem Rgn", "Length",
1583 		    "Rel Off", "Xfer Len", "Exp. Off");
1584 	}
1585 	idc->idc_header = 0;
1586 
1587 	/* Print buffer data */
1588 	mdb_printf("%?p %?p/%08x %8x %8x %08x\n", addr,
1589 	    idb.idb_buf, idb.idb_buflen,
1590 	    idb.idb_bufoffset, idb.idb_xfer_len,
1591 	    idb.idb_exp_offset);
1592 
1593 
1594 	/* Buffers are leaf objects */
1595 
1596 	return (DCMD_OK);
1597 }
1598 
1599 static int
1600 iscsi_refcnt_impl(uintptr_t addr)
1601 {
1602 	idm_refcnt_t		refcnt;
1603 	refcnt_audit_buf_t	*anb;
1604 	int			ctr;
1605 
1606 	/*
1607 	 * Print refcnt info
1608 	 */
1609 	if (mdb_vread(&refcnt, sizeof (idm_refcnt_t), addr) !=
1610 	    sizeof (idm_refcnt_t)) {
1611 		return (DCMD_ERR);
1612 	}
1613 
1614 	anb = &refcnt.ir_audit_buf;
1615 
1616 	ctr = anb->anb_max_index + 1;
1617 	anb->anb_index--;
1618 	anb->anb_index &= anb->anb_max_index;
1619 
1620 	while (ctr) {
1621 		refcnt_audit_record_t	*anr;
1622 
1623 		anr = anb->anb_records + anb->anb_index;
1624 
1625 		if (anr->anr_depth) {
1626 			char c[MDB_SYM_NAMLEN];
1627 			GElf_Sym sym;
1628 			int i;
1629 
1630 			mdb_printf("\nRefCnt: %u\t", anr->anr_refcnt);
1631 
1632 			for (i = 0; i < anr->anr_depth; i++) {
1633 				if (mdb_lookup_by_addr(anr->anr_stack[i],
1634 				    MDB_SYM_FUZZY, c, sizeof (c),
1635 				    &sym) == -1) {
1636 					continue;
1637 				}
1638 				mdb_printf("%s+0x%1x", c,
1639 				    anr->anr_stack[i] -
1640 				    (uintptr_t)sym.st_value);
1641 				++i;
1642 				break;
1643 			}
1644 
1645 			while (i < anr->anr_depth) {
1646 				if (mdb_lookup_by_addr(anr->anr_stack[i],
1647 				    MDB_SYM_FUZZY, c, sizeof (c),
1648 				    &sym) == -1) {
1649 					++i;
1650 					continue;
1651 				}
1652 				mdb_printf("\n\t\t%s+0x%1x", c,
1653 				    anr->anr_stack[i] -
1654 				    (uintptr_t)sym.st_value);
1655 				++i;
1656 			}
1657 			mdb_printf("\n");
1658 		}
1659 		anb->anb_index--;
1660 		anb->anb_index &= anb->anb_max_index;
1661 		ctr--;
1662 	}
1663 
1664 	return (DCMD_OK);
1665 }
1666 
1667 static int
1668 iscsi_sm_audit_impl(uintptr_t addr)
1669 {
1670 	sm_audit_buf_t		audit_buf;
1671 	int			ctr;
1672 	const char		*event_name;
1673 	const char		*state_name;
1674 	const char		*new_state_name;
1675 	char			ts_string[40];
1676 	/*
1677 	 * Print refcnt info
1678 	 */
1679 	if (mdb_vread(&audit_buf, sizeof (sm_audit_buf_t), addr) !=
1680 	    sizeof (sm_audit_buf_t)) {
1681 		return (DCMD_ERR);
1682 	}
1683 
1684 	ctr = audit_buf.sab_max_index + 1;
1685 	audit_buf.sab_index++;
1686 	audit_buf.sab_index &= audit_buf.sab_max_index;
1687 
1688 	while (ctr) {
1689 		sm_audit_record_t	*sar;
1690 
1691 		sar = audit_buf.sab_records + audit_buf.sab_index;
1692 
1693 		iscsi_format_timestamp(ts_string, 40, &sar->sar_timestamp);
1694 
1695 		switch (sar->sar_type) {
1696 		case SAR_STATE_EVENT:
1697 			switch (sar->sar_sm_type) {
1698 			case SAS_IDM_CONN:
1699 				state_name =
1700 				    iscsi_idm_conn_state(sar->sar_state);
1701 				event_name =
1702 				    iscsi_idm_conn_event(sar->sar_event);
1703 				break;
1704 			case SAS_ISCSIT_TGT:
1705 				state_name =
1706 				    iscsi_iscsit_tgt_state(sar->sar_state);
1707 				event_name =
1708 				    iscsi_iscsit_tgt_event(sar->sar_event);
1709 				break;
1710 			case SAS_ISCSIT_SESS:
1711 				state_name =
1712 				    iscsi_iscsit_sess_state(sar->sar_state);
1713 				event_name =
1714 				    iscsi_iscsit_sess_event(sar->sar_event);
1715 				break;
1716 			case SAS_ISCSIT_LOGIN:
1717 				state_name =
1718 				    iscsi_iscsit_login_state(sar->sar_state);
1719 				event_name =
1720 				    iscsi_iscsit_login_event(sar->sar_event);
1721 				break;
1722 			default:
1723 				state_name = event_name = "N/A";
1724 				break;
1725 			}
1726 			mdb_printf("%s|%s (%d)\n\t%9s %s (%d) %p\n",
1727 			    ts_string, state_name, sar->sar_state,
1728 			    "Event", event_name,
1729 			    sar->sar_event, sar->sar_event_info);
1730 
1731 			break;
1732 		case SAR_STATE_CHANGE:
1733 			switch (sar->sar_sm_type) {
1734 			case SAS_IDM_CONN:
1735 				state_name =
1736 				    iscsi_idm_conn_state(sar->sar_state);
1737 				new_state_name =
1738 				    iscsi_idm_conn_state(sar->sar_new_state);
1739 				break;
1740 			case SAS_IDM_TASK:
1741 				state_name =
1742 				    iscsi_idm_task_state(sar->sar_state);
1743 				new_state_name =
1744 				    iscsi_idm_task_state(sar->sar_new_state);
1745 				break;
1746 			case SAS_ISCSIT_TGT:
1747 				state_name =
1748 				    iscsi_iscsit_tgt_state(sar->sar_state);
1749 				new_state_name =
1750 				    iscsi_iscsit_tgt_state(sar->sar_new_state);
1751 				break;
1752 			case SAS_ISCSIT_SESS:
1753 				state_name =
1754 				    iscsi_iscsit_sess_state(sar->sar_state);
1755 				new_state_name =
1756 				    iscsi_iscsit_sess_state(sar->sar_new_state);
1757 				break;
1758 			case SAS_ISCSIT_LOGIN:
1759 				state_name =
1760 				    iscsi_iscsit_login_state(sar->sar_state);
1761 				new_state_name =
1762 				    iscsi_iscsit_login_state(
1763 				    sar->sar_new_state);
1764 				break;
1765 			default:
1766 				break;
1767 			}
1768 			mdb_printf("%s|%s (%d)\n\t%9s %s (%d)\n",
1769 			    ts_string, state_name, sar->sar_state,
1770 			    "New State", new_state_name, sar->sar_new_state);
1771 		default:
1772 			state_name = new_state_name = "N/A";
1773 			break;
1774 		}
1775 
1776 		audit_buf.sab_index++;
1777 		audit_buf.sab_index &= audit_buf.sab_max_index;
1778 		ctr--;
1779 	}
1780 
1781 	return (DCMD_OK);
1782 }
1783 
1784 static const char *
1785 iscsi_idm_conn_event(int event)
1786 {
1787 	const char *name = "N/A";
1788 
1789 	event = (event > CE_MAX_EVENT) ? CE_MAX_EVENT : event;
1790 	name = idm_ce_name[event];
1791 
1792 	return (name);
1793 }
1794 
1795 static const char *
1796 iscsi_iscsit_tgt_event(int event)
1797 {
1798 	const char *name = "N/A";
1799 
1800 	event = (event > TE_MAX_EVENT) ? TE_MAX_EVENT : event;
1801 	name = iscsit_te_name[event];
1802 
1803 	return (name);
1804 }
1805 
1806 static const char *
1807 iscsi_iscsit_sess_event(int event)
1808 {
1809 	const char *name = "N/A";
1810 
1811 	event = (event > SE_MAX_EVENT) ? SE_MAX_EVENT : event;
1812 	name = iscsit_se_name[event];
1813 
1814 	return (name);
1815 }
1816 
1817 static const char *
1818 iscsi_iscsit_login_event(int event)
1819 {
1820 	const char *name = "N/A";
1821 
1822 	event = (event > ILE_MAX_EVENT) ? ILE_MAX_EVENT : event;
1823 	name = iscsit_ile_name[event];
1824 
1825 	return (name);
1826 }
1827 
1828 static const char *
1829 iscsi_idm_conn_state(int state)
1830 {
1831 	const char *name = "N/A";
1832 
1833 	state = (state > CS_MAX_STATE) ? CS_MAX_STATE : state;
1834 	name = idm_cs_name[state];
1835 
1836 	return (name);
1837 }
1838 
1839 /*ARGSUSED*/
1840 static const char *
1841 iscsi_idm_task_state(int state)
1842 {
1843 	const char *name = "N/A";
1844 	return (name);
1845 }
1846 
1847 static const char *
1848 iscsi_iscsit_tgt_state(int state)
1849 {
1850 	const char *name = "N/A";
1851 
1852 	state = (state > TS_MAX_STATE) ? TS_MAX_STATE : state;
1853 	name = iscsit_ts_name[state];
1854 
1855 	return (name);
1856 }
1857 
1858 static const char *
1859 iscsi_iscsit_sess_state(int state)
1860 {
1861 	const char *name = "N/A";
1862 
1863 	state = (state > SS_MAX_STATE) ? SS_MAX_STATE : state;
1864 	name = iscsit_ss_name[state];
1865 
1866 	return (name);
1867 }
1868 
1869 static const char *
1870 iscsi_iscsit_login_state(int state)
1871 {
1872 	const char *name = "N/A";
1873 
1874 	state = (state > ILS_MAX_STATE) ? ILS_MAX_STATE : state;
1875 	name = iscsit_ils_name[state];
1876 
1877 	return (name);
1878 }
1879 
1880 
1881 
1882 /*
1883  * Retrieve connection type given a kernel address
1884  */
1885 static idm_conn_type_t
1886 idm_conn_type(uintptr_t addr)
1887 {
1888 	idm_conn_type_t result = 0; /* Unknown */
1889 	uintptr_t idm_conn_type_addr;
1890 
1891 	idm_conn_type_addr = addr + offsetof(idm_conn_t, ic_conn_type);
1892 	(void) mdb_vread(&result, sizeof (result), idm_conn_type_addr);
1893 
1894 	return (result);
1895 }
1896 
1897 /*
1898  * Convert a sockaddr to the string representation, suitable for
1899  * storing in an nvlist or printing out in a list.
1900  */
1901 static int
1902 sa_to_str(struct sockaddr_storage *sa, char *buf)
1903 {
1904 	char			pbuf[7];
1905 	const char		*bufp;
1906 	struct sockaddr_in	*sin;
1907 	struct sockaddr_in6	*sin6;
1908 	uint16_t		port;
1909 
1910 	if (!sa || !buf) {
1911 		return (EINVAL);
1912 	}
1913 
1914 	buf[0] = '\0';
1915 
1916 	if (sa->ss_family == AF_INET) {
1917 		sin = (struct sockaddr_in *)sa;
1918 		bufp = inet_ntop(AF_INET,
1919 		    (const void *)&(sin->sin_addr.s_addr),
1920 		    buf, PORTAL_STR_LEN);
1921 		if (bufp == NULL) {
1922 			return (-1);
1923 		}
1924 		mdb_nhconvert(&port, &sin->sin_port, sizeof (uint16_t));
1925 	} else if (sa->ss_family == AF_INET6) {
1926 		strlcat(buf, "[", sizeof (buf));
1927 		sin6 = (struct sockaddr_in6 *)sa;
1928 		bufp = inet_ntop(AF_INET6,
1929 		    (const void *)&sin6->sin6_addr.s6_addr,
1930 		    &buf[1], PORTAL_STR_LEN - 1);
1931 		if (bufp == NULL) {
1932 			return (-1);
1933 		}
1934 		strlcat(buf, "]", PORTAL_STR_LEN);
1935 		mdb_nhconvert(&port, &sin->sin_port, sizeof (uint16_t));
1936 	} else {
1937 		return (EINVAL);
1938 	}
1939 
1940 
1941 	mdb_snprintf(pbuf, sizeof (pbuf), ":%u", port);
1942 	strlcat(buf, pbuf, PORTAL_STR_LEN);
1943 
1944 	return (0);
1945 }
1946 
1947 
1948 static void
1949 iscsi_format_timestamp(char *ts_str, int strlen, timespec_t *ts)
1950 {
1951 	mdb_snprintf(ts_str, strlen, "%Y:%03d:%03d:%03d", ts->tv_sec,
1952 	    (ts->tv_nsec / 1000000) % 1000, (ts->tv_nsec / 1000) % 1000,
1953 	    ts->tv_nsec % 1000);
1954 }
1955 
1956 /*
1957  * Help information for the iscsi_isns dcmd
1958  */
1959 static void
1960 iscsi_isns_help(void)
1961 {
1962 	mdb_printf("iscsi_isns:\n");
1963 	mdb_inc_indent(4);
1964 	mdb_printf("-e: Print ESI information\n");
1965 	mdb_printf("-p: Print portal information\n");
1966 	mdb_printf("-s: Print iSNS server information\n");
1967 	mdb_printf("-t: Print target information\n");
1968 	mdb_printf("-v: Add verbosity to the other options' output\n");
1969 	mdb_dec_indent(4);
1970 }
1971 
1972 /* ARGSUSED */
1973 static int
1974 iscsi_isns_esi_cb(uintptr_t addr, const void *walker_data, void *data)
1975 {
1976 	iscsi_dcmd_ctrl_t *idc = (iscsi_dcmd_ctrl_t *)data;
1977 	isns_esi_tinfo_t tinfo;
1978 
1979 	if (mdb_vread(&tinfo, sizeof (isns_esi_tinfo_t), addr) !=
1980 	    sizeof (isns_esi_tinfo_t)) {
1981 		return (WALK_ERR);
1982 	}
1983 
1984 	mdb_printf("ESI portal         : 0x%p\n", tinfo.esi_portal);
1985 	if (idc->idc_verbose) {
1986 		mdb_inc_indent(4);
1987 		iscsi_isns_portal_cb((uintptr_t)tinfo.esi_portal, NULL, data);
1988 		mdb_dec_indent(4);
1989 	}
1990 	mdb_printf("ESI thread/thr did : 0x%p / %d\n", tinfo.esi_thread,
1991 	    tinfo.esi_thread_did);
1992 	mdb_printf("ESI sonode         : 0x%p\n", tinfo.esi_so);
1993 	mdb_printf("ESI port           : %d\n", tinfo.esi_port);
1994 	mdb_printf("ESI thread running : %s\n",
1995 	    (tinfo.esi_thread_running) ? "Yes" : "No");
1996 	if (!tinfo.esi_thread_running) {
1997 		mdb_printf("ESI thread failed  : %s\n",
1998 		    (tinfo.esi_thread_failed) ? "Yes" : "No");
1999 	}
2000 	mdb_printf("ESI registered     : %s\n\n",
2001 	    (tinfo.esi_registered) ? "Yes" : "No");
2002 
2003 	return (WALK_NEXT);
2004 }
2005 
2006 static int
2007 iscsi_isns_esi(iscsi_dcmd_ctrl_t *idc)
2008 {
2009 	GElf_Sym sym;
2010 	uintptr_t esi_list;
2011 
2012 	if (mdb_lookup_by_name("esi_list", &sym) == -1) {
2013 		mdb_warn("failed to find symbol 'esi_list'");
2014 		return (DCMD_ERR);
2015 	}
2016 
2017 	esi_list = (uintptr_t)sym.st_value;
2018 	idc->idc_header = 1;
2019 
2020 	if (mdb_pwalk("list", iscsi_isns_esi_cb, idc, esi_list) == -1) {
2021 		mdb_warn("avl walk failed for esi_list");
2022 		return (DCMD_ERR);
2023 	}
2024 
2025 	return (0);
2026 }
2027 
2028 /* ARGSUSED */
2029 static int
2030 iscsi_isns_portal_cb(uintptr_t addr, const void *walker_data, void *data)
2031 {
2032 	iscsi_dcmd_ctrl_t *idc = (iscsi_dcmd_ctrl_t *)data;
2033 	isns_portal_list_t portal;
2034 	char portal_addr[PORTAL_STR_LEN];
2035 	struct sockaddr_storage *ss;
2036 
2037 	if (mdb_vread(&portal, sizeof (isns_portal_list_t), addr) !=
2038 	    sizeof (isns_portal_list_t)) {
2039 		return (WALK_ERR);
2040 	}
2041 
2042 	ss = &portal.portal_addr;
2043 	sa_to_str(ss, portal_addr);
2044 	mdb_printf("Portal IP address ");
2045 
2046 	if (ss->ss_family == AF_INET) {
2047 		mdb_printf("(v4): %s", portal_addr);
2048 	} else {
2049 		mdb_printf("(v6): %s", portal_addr);
2050 	}
2051 
2052 	if (portal.portal_iscsit == NULL) {
2053 		mdb_printf(" (Default portal)\n");
2054 	} else {
2055 		mdb_printf("\n");
2056 	}
2057 
2058 	if ((portal.portal_iscsit != NULL) && (idc->idc_verbose)) {
2059 		iscsi_portal_impl((uintptr_t)portal.portal_iscsit, idc);
2060 	}
2061 
2062 	mdb_printf("Portal ESI info: 0x%p\n\n", portal.portal_esi);
2063 
2064 	return (WALK_NEXT);
2065 }
2066 
2067 static int
2068 iscsi_isns_portals(iscsi_dcmd_ctrl_t *idc)
2069 {
2070 	GElf_Sym sym;
2071 	uintptr_t portal_list;
2072 
2073 	if (mdb_lookup_by_name("portal_list", &sym) == -1) {
2074 		mdb_warn("failed to find symbol 'portal_list'");
2075 		return (DCMD_ERR);
2076 	}
2077 
2078 	portal_list = (uintptr_t)sym.st_value;
2079 	idc->idc_header = 1;
2080 
2081 	if (mdb_pwalk("list", iscsi_isns_portal_cb, idc, portal_list) == -1) {
2082 		mdb_warn("avl walk failed for portal_list");
2083 		return (DCMD_ERR);
2084 	}
2085 
2086 	return (0);
2087 }
2088 
2089 /* ARGSUSED */
2090 static int
2091 iscsi_isns_targets_cb(uintptr_t addr, const void *walker_data, void *data)
2092 {
2093 	iscsi_dcmd_ctrl_t *idc = (iscsi_dcmd_ctrl_t *)data;
2094 	isns_target_t	itarget;
2095 	int		rc = 0;
2096 
2097 	if (mdb_vread(&itarget, sizeof (isns_target_t), addr) !=
2098 	    sizeof (isns_target_t)) {
2099 		return (WALK_ERR);
2100 	}
2101 
2102 	idc->idc_header = 1;
2103 
2104 	mdb_printf("Target: %p\n", itarget.target);
2105 	mdb_inc_indent(4);
2106 	mdb_printf("Registered: %s\n",
2107 	    (itarget.target_registered) ? "Yes" : "No");
2108 
2109 	rc = iscsi_tgt_impl((uintptr_t)itarget.target, idc);
2110 
2111 	mdb_dec_indent(4);
2112 
2113 	if (rc == DCMD_OK) {
2114 		return (WALK_NEXT);
2115 	}
2116 
2117 	return (WALK_ERR);
2118 }
2119 
2120 static int
2121 iscsi_isns_targets(iscsi_dcmd_ctrl_t *idc)
2122 {
2123 	GElf_Sym sym;
2124 	uintptr_t isns_target_list;
2125 
2126 	if (mdb_lookup_by_name("isns_target_list", &sym) == -1) {
2127 		mdb_warn("failed to find symbol 'isns_target_list'");
2128 		return (DCMD_ERR);
2129 	}
2130 
2131 	isns_target_list = (uintptr_t)sym.st_value;
2132 	idc->idc_header = 1;
2133 	idc->u.child.idc_tgt = 1;
2134 
2135 	if (mdb_pwalk("avl", iscsi_isns_targets_cb, idc,
2136 	    isns_target_list) == -1) {
2137 		mdb_warn("avl walk failed for isns_target_list");
2138 		return (DCMD_ERR);
2139 	}
2140 
2141 	return (0);
2142 }
2143 
2144 /* ARGSUSED */
2145 static int
2146 iscsi_isns_servers_cb(uintptr_t addr, const void *walker_data, void *data)
2147 {
2148 	GElf_Sym		sym;
2149 	iscsit_isns_svr_t	server;
2150 	char			server_addr[PORTAL_STR_LEN];
2151 	struct sockaddr_storage *ss;
2152 	clock_t			lbolt;
2153 
2154 	if (mdb_vread(&server, sizeof (iscsit_isns_svr_t), addr) !=
2155 	    sizeof (iscsit_isns_svr_t)) {
2156 		return (WALK_ERR);
2157 	}
2158 
2159 	if (mdb_lookup_by_name("lbolt", &sym) == -1) {
2160 		mdb_warn("failed to find symbol 'lbolt'");
2161 		return (DCMD_ERR);
2162 	}
2163 
2164 	if (mdb_vread(&lbolt, sizeof (clock_t), sym.st_value) !=
2165 	    sizeof (clock_t)) {
2166 		return (WALK_ERR);
2167 	}
2168 
2169 	mdb_printf("iSNS server %p:\n", addr);
2170 	mdb_inc_indent(4);
2171 	ss = &server.svr_sa;
2172 	sa_to_str(ss, server_addr);
2173 
2174 	mdb_printf("IP address ");
2175 	if (ss->ss_family == AF_INET) {
2176 		mdb_printf("(v4): %s\n", server_addr);
2177 	} else {
2178 		mdb_printf("(v6): %s\n", server_addr);
2179 	}
2180 
2181 	mdb_printf("Last ESI message : %d seconds ago\n",
2182 	    ((lbolt - server.svr_last_msg) / 100));
2183 	mdb_printf("Client registered: %s\n",
2184 	    (server.svr_registered) ? "Yes" : "No");
2185 	mdb_dec_indent(4);
2186 
2187 	return (WALK_ERR);
2188 }
2189 
2190 static int
2191 iscsi_isns_servers(iscsi_dcmd_ctrl_t *idc)
2192 {
2193 	uintptr_t	iscsit_global_addr;
2194 	uintptr_t	list_addr;
2195 	GElf_Sym	sym;
2196 
2197 	if (mdb_lookup_by_name("iscsit_global", &sym) == -1) {
2198 		mdb_warn("failed to find symbol 'iscsit_global'");
2199 		return (DCMD_ERR);
2200 	}
2201 
2202 	iscsit_global_addr = (uintptr_t)sym.st_value;
2203 	idc->idc_header = 1;
2204 	list_addr = iscsit_global_addr +
2205 	    offsetof(iscsit_global_t, global_isns_cfg.isns_svrs);
2206 
2207 	if (mdb_pwalk("list", iscsi_isns_servers_cb, idc, list_addr) == -1) {
2208 		mdb_warn("list walk failed for iSNS servers");
2209 		return (DCMD_ERR);
2210 	}
2211 
2212 	return (0);
2213 }
2214 
2215 /* ARGSUSED */
2216 static int
2217 iscsi_isns(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2218 {
2219 	iscsi_dcmd_ctrl_t idc;
2220 	int portals = 0, esi = 0, targets = 0, verbose = 0, servers = 0;
2221 
2222 	if (flags & DCMD_ADDRSPEC) {
2223 		mdb_warn("iscsi_isns is only a global dcmd.");
2224 		return (DCMD_ERR);
2225 	}
2226 
2227 	bzero(&idc, sizeof (idc));
2228 	if (mdb_getopts(argc, argv,
2229 	    'e', MDB_OPT_SETBITS, TRUE, &esi,
2230 	    'p', MDB_OPT_SETBITS, TRUE, &portals,
2231 	    's', MDB_OPT_SETBITS, TRUE, &servers,
2232 	    't', MDB_OPT_SETBITS, TRUE, &targets,
2233 	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
2234 	    NULL) != argc)
2235 		return (DCMD_USAGE);
2236 
2237 	if ((esi + portals + targets + servers) > 1) {
2238 		mdb_printf("Only one of e, p, s, and t must be provided");
2239 		return (DCMD_ERR);
2240 	}
2241 
2242 	if ((esi | portals | targets | servers) == 0) {
2243 		mdb_printf("Exactly one of e, p, s, or t must be provided");
2244 		return (DCMD_ERR);
2245 	}
2246 
2247 	idc.idc_verbose = verbose;
2248 
2249 	if (esi) {
2250 		return (iscsi_isns_esi(&idc));
2251 	}
2252 
2253 	if (portals) {
2254 		return (iscsi_isns_portals(&idc));
2255 	}
2256 
2257 	if (servers) {
2258 		return (iscsi_isns_servers(&idc));
2259 	}
2260 
2261 	return (iscsi_isns_targets(&idc));
2262 }
2263 
2264 /*
2265  * inet_ntop -- Convert an IPv4 or IPv6 address in binary form into
2266  * printable form, and return a pointer to that string. Caller should
2267  * provide a buffer of correct length to store string into.
2268  * Note: this routine is kernel version of inet_ntop. It has similar
2269  * format as inet_ntop() defined in rfc2553. But it does not do
2270  * error handling operations exactly as rfc2553 defines. This function
2271  * is used by kernel inet directory routines only for debugging.
2272  * This inet_ntop() function, does not return NULL if third argument
2273  * is NULL. The reason is simple that we don't want kernel to panic
2274  * as the output of this function is directly fed to ip<n>dbg macro.
2275  * Instead it uses a local buffer for destination address for
2276  * those calls which purposely pass NULL ptr for the destination
2277  * buffer. This function is thread-safe when the caller passes a non-
2278  * null buffer with the third argument.
2279  */
2280 /* ARGSUSED */
2281 
2282 #define	OK_16PTR(p)	(!((uintptr_t)(p) & 0x1))
2283 #if defined(__x86)
2284 #define	OK_32PTR(p)	OK_16PTR(p)
2285 #else
2286 #define	OK_32PTR(p)	(!((uintptr_t)(p) & 0x3))
2287 #endif
2288 
2289 char *
2290 inet_ntop(int af, const void *addr, char *buf, int addrlen)
2291 {
2292 	static char local_buf[PORTAL_STR_LEN];
2293 	static char *err_buf1 = "<badaddr>";
2294 	static char *err_buf2 = "<badfamily>";
2295 	in6_addr_t	*v6addr;
2296 	uchar_t		*v4addr;
2297 	char		*caddr;
2298 
2299 	/*
2300 	 * We don't allow thread unsafe inet_ntop calls, they
2301 	 * must pass a non-null buffer pointer. For DEBUG mode
2302 	 * we use the ASSERT() and for non-debug kernel it will
2303 	 * silently allow it for now. Someday we should remove
2304 	 * the static buffer from this function.
2305 	 */
2306 
2307 	ASSERT(buf != NULL);
2308 	if (buf == NULL)
2309 		buf = local_buf;
2310 	buf[0] = '\0';
2311 
2312 	/* Let user know politely not to send NULL or unaligned addr */
2313 	if (addr == NULL || !(OK_32PTR(addr))) {
2314 		return (err_buf1);
2315 	}
2316 
2317 
2318 #define	UC(b)	(((int)b) & 0xff)
2319 	switch (af) {
2320 	case AF_INET:
2321 		ASSERT(addrlen >= INET_ADDRSTRLEN);
2322 		v4addr = (uchar_t *)addr;
2323 		(void) mdb_snprintf(buf, INET6_ADDRSTRLEN,
2324 		    "%03d.%03d.%03d.%03d",
2325 		    UC(v4addr[0]), UC(v4addr[1]), UC(v4addr[2]), UC(v4addr[3]));
2326 		return (buf);
2327 
2328 	case AF_INET6:
2329 		ASSERT(addrlen >= INET6_ADDRSTRLEN);
2330 		v6addr = (in6_addr_t *)addr;
2331 		if (IN6_IS_ADDR_V4MAPPED(v6addr)) {
2332 			caddr = (char *)addr;
2333 			(void) mdb_snprintf(buf, INET6_ADDRSTRLEN,
2334 			    "::ffff:%d.%d.%d.%d",
2335 			    UC(caddr[12]), UC(caddr[13]),
2336 			    UC(caddr[14]), UC(caddr[15]));
2337 		} else if (IN6_IS_ADDR_V4COMPAT(v6addr)) {
2338 			caddr = (char *)addr;
2339 			(void) mdb_snprintf(buf, INET6_ADDRSTRLEN,
2340 			    "::%d.%d.%d.%d",
2341 			    UC(caddr[12]), UC(caddr[13]), UC(caddr[14]),
2342 			    UC(caddr[15]));
2343 		} else if (IN6_IS_ADDR_UNSPECIFIED(v6addr)) {
2344 			(void) mdb_snprintf(buf, INET6_ADDRSTRLEN, "::");
2345 		} else {
2346 			convert2ascii(buf, v6addr);
2347 		}
2348 		return (buf);
2349 
2350 	default:
2351 		return (err_buf2);
2352 	}
2353 #undef UC
2354 }
2355 
2356 /*
2357  *
2358  * v6 formats supported
2359  * General format xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
2360  * The short hand notation :: is used for COMPAT addr
2361  * Other forms : fe80::xxxx:xxxx:xxxx:xxxx
2362  */
2363 static void
2364 convert2ascii(char *buf, const in6_addr_t *addr)
2365 {
2366 	int		hexdigits;
2367 	int		head_zero = 0;
2368 	int		tail_zero = 0;
2369 	/* tempbuf must be big enough to hold ffff:\0 */
2370 	char		tempbuf[6];
2371 	char		*ptr;
2372 	uint16_t	out_addr_component;
2373 	uint16_t	*addr_component;
2374 	size_t		len;
2375 	boolean_t	first = B_FALSE;
2376 	boolean_t	med_zero = B_FALSE;
2377 	boolean_t	end_zero = B_FALSE;
2378 
2379 	addr_component = (uint16_t *)addr;
2380 	ptr = buf;
2381 
2382 	/* First count if trailing zeroes higher in number */
2383 	for (hexdigits = 0; hexdigits < 8; hexdigits++) {
2384 		if (*addr_component == 0) {
2385 			if (hexdigits < 4)
2386 				head_zero++;
2387 			else
2388 				tail_zero++;
2389 		}
2390 		addr_component++;
2391 	}
2392 	addr_component = (uint16_t *)addr;
2393 	if (tail_zero > head_zero && (head_zero + tail_zero) != 7)
2394 		end_zero = B_TRUE;
2395 
2396 	for (hexdigits = 0; hexdigits < 8; hexdigits++) {
2397 
2398 		/* if entry is a 0 */
2399 
2400 		if (*addr_component == 0) {
2401 			if (!first && *(addr_component + 1) == 0) {
2402 				if (end_zero && (hexdigits < 4)) {
2403 					*ptr++ = '0';
2404 					*ptr++ = ':';
2405 				} else {
2406 					/*
2407 					 * address starts with 0s ..
2408 					 * stick in leading ':' of pair
2409 					 */
2410 					if (hexdigits == 0)
2411 						*ptr++ = ':';
2412 					/* add another */
2413 					*ptr++ = ':';
2414 					first = B_TRUE;
2415 					med_zero = B_TRUE;
2416 				}
2417 			} else if (first && med_zero) {
2418 				if (hexdigits == 7)
2419 					*ptr++ = ':';
2420 				addr_component++;
2421 				continue;
2422 			} else {
2423 				*ptr++ = '0';
2424 				*ptr++ = ':';
2425 			}
2426 			addr_component++;
2427 			continue;
2428 		}
2429 		if (med_zero)
2430 			med_zero = B_FALSE;
2431 
2432 		tempbuf[0] = '\0';
2433 		mdb_nhconvert(&out_addr_component, addr_component,
2434 		    sizeof (uint16_t));
2435 		(void) mdb_snprintf(tempbuf, 6, "%x:", out_addr_component);
2436 		len = strlen(tempbuf);
2437 		bcopy(tempbuf, ptr, len);
2438 		ptr = ptr + len;
2439 		addr_component++;
2440 	}
2441 	*--ptr = '\0';
2442 }
2443 
2444 
2445 /*
2446  * MDB module linkage information:
2447  *
2448  * We declare a list of structures describing our dcmds, a list of structures
2449  * describing our walkers and a function named _mdb_init to return a pointer
2450  * to our module information.
2451  */
2452 static const mdb_dcmd_t dcmds[] = {
2453 	{   "iscsi_tgt", "[-agsctbSRv]",
2454 	    "iSCSI target information", iscsi_tgt },
2455 	{   "iscsi_tpg", "[-v]",
2456 	    "iSCSI target portal group information", iscsi_tpg },
2457 	{   "iscsi_sess", "[-abtvcSRIT]",
2458 	    "iSCSI session information", iscsi_sess },
2459 	{   "iscsi_conn", "[-abtvSRIT]",
2460 	    "iSCSI connection information", iscsi_conn },
2461 	{   "iscsi_task", "[-bSRv]",
2462 	    "iSCSI task information", iscsi_task },
2463 	{   "iscsi_refcnt", "",
2464 	    "Print audit informtion for idm_refcnt_t", iscsi_refcnt },
2465 	{   "iscsi_states", "",
2466 	    "Dump events and state transitions recorded in an\t"
2467 	    "\t\tidm_sm_audit_t structure", iscsi_states },
2468 	{   "iscsi_isns", "[-epstv]",
2469 	    "Print iscsit iSNS information", iscsi_isns, iscsi_isns_help },
2470 	{ NULL }
2471 };
2472 
2473 /*
2474  * No walkers for now.  Initiator might need some since it doesn't use list_t
2475  */
2476 
2477 static const mdb_modinfo_t modinfo = {
2478 	MDB_API_VERSION, dcmds, NULL
2479 };
2480 
2481 const mdb_modinfo_t *
2482 _mdb_init(void)
2483 {
2484 	return (&modinfo);
2485 }
2486