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