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