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