xref: /illumos-gate/usr/src/cmd/mdb/common/modules/idm/idm.c (revision e911f24978ffe03577079badeef02cfc5e9aa296)
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 (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 
25 #include <mdb/mdb_modapi.h>
26 #include <mdb/mdb_ks.h>
27 
28 #include <sys/cpuvar.h>
29 #include <sys/conf.h>
30 #include <sys/file.h>
31 #include <sys/types.h>
32 #include <sys/taskq.h>
33 #include <sys/sysmacros.h>
34 #include <sys/socket.h>		/* networking stuff */
35 #include <sys/strsubr.h>	/* networking stuff */
36 #include <sys/nvpair.h>
37 #include <sys/sunldi.h>
38 #include <sys/stmf.h>
39 #include <sys/stmf_ioctl.h>
40 #include <sys/portif.h>
41 
42 #define	IDM_CONN_SM_STRINGS
43 #define	IDM_TASK_SM_STRINGS
44 #define	ISCSIT_TGT_SM_STRINGS
45 #define	ISCSIT_SESS_SM_STRINGS
46 #define	ISCSIT_LOGIN_SM_STRINGS
47 #define	ISCSI_SESS_SM_STRINGS
48 #define	ISCSI_CMD_SM_STRINGS
49 #define	ISCSI_ICS_NAMES
50 #define	ISCSI_LOGIN_STATE_NAMES
51 #define	IDM_CN_NOTIFY_STRINGS
52 #include <sys/idm/idm.h>
53 #include <iscsi.h>
54 #include <iscsit.h>
55 #include <iscsit_isns.h>
56 #include <sys/ib/clients/iser/iser.h>
57 
58 /*
59  * We want to be able to print multiple levels of object hierarchy with a
60  * single dcmd information, and preferably also exclude intermediate
61  * levels if desired.  For example some of the target objects have the
62  * following relationship:
63  *
64  * target --> session --> connection --> task
65  *
66  * The session dcmd should allow the printing of all associated tasks for the
67  * sessions without printing all the associated connections.  To accomplish
68  * this the following structure contains a bit for each object type.  Dcmds
69  * should invoke the functions for child objects if any bits are set
70  * in iscsi_dcmd_ctrl_t but the functions for the child object should only
71  * print data if their associated bit is set. Each object type should print
72  * a header for its first occurrence or if it is being printed as a child
73  * object for the first occurrence under each parent. For the model to follow
74  * see how idc->idc_header is handled in iscsi_sess_impl.
75  *
76  * Each dcmd should provide an external interface with the standard MDB API
77  * and an internal interface that accepts iscsi_dcmd_ctrl_t.  To display
78  * child objects the dcmd calls the internal interface for the child object
79  * directly.  Dcmds invoked from the command line will, of course, call the
80  * external interface.  See iscsi_conn() and iscsi_conn_impl().
81  */
82 
83 typedef struct {
84 	union	{
85 		uint32_t	idc_children;
86 		struct {
87 			uint32_t	idc_tgt:1,
88 					idc_tpg:1,
89 					idc_tpgt:1,
90 					idc_portal:1,
91 					idc_sess:1,
92 					idc_conn:1,
93 					idc_svc:1,
94 					idc_print_ip:1,
95 					idc_task:1,
96 					idc_buffer:1,
97 					idc_states:1,
98 					idc_rc_audit:1,
99 					idc_lun:1,
100 					idc_hba:1,
101 					idc_cmd:1;
102 		} child;
103 	} u;
104 	boolean_t		idc_ini;
105 	boolean_t		idc_tgt;
106 	boolean_t		idc_verbose;
107 	boolean_t		idc_header;
108 	/*
109 	 * Our connection dcmd code works off the global connection lists
110 	 * in IDM since we want to know about connections even when they
111 	 * have not progressed to the point that they have an associated
112 	 * session.  If we use "::iscsi_sess [-c]" then we only want to
113 	 * see connections associated with particular session.  To avoid
114 	 * writing a separate set of code to print session-specific connection
115 	 * the session code should set the sessions kernel address in the
116 	 * following field.  The connection code will then only print
117 	 * connections that match.
118 	 */
119 	uintptr_t		idc_assoc_session;
120 } iscsi_dcmd_ctrl_t;
121 
122 typedef struct idm_hba_walk_info {
123 	void	**array;
124 	int	n_elements;
125 	int	cur_element;
126 	void	*data;
127 } idm_hba_walk_info_t;
128 
129 static int iscsi_walk_all_sess(iscsi_dcmd_ctrl_t *idc);
130 static int iscsi_walk_all_conn(iscsi_dcmd_ctrl_t *idc);
131 static int iscsi_tgt_walk_cb(uintptr_t addr, const void *list_walker_data,
132     void *idc_void);
133 static int iscsi_tpgt_walk_cb(uintptr_t addr, const void *list_walker_data,
134     void *idc_void);
135 static int iscsi_tpg_walk_cb(uintptr_t addr, const void *list_walker_data,
136     void *idc_void);
137 static int iscsi_portal_walk_cb(uintptr_t addr, const void *list_walker_data,
138     void *idc_void);
139 static int iscsi_sess_walk_cb(uintptr_t addr, const void *list_walker_data,
140     void *idc_void);
141 static int iscsi_conn_walk_cb(uintptr_t addr, const void *list_walker_data,
142     void *idc_void);
143 static int iscsi_buffer_walk_cb(uintptr_t addr, const void *list_walker_data,
144     void *idc_void);
145 static int iscsi_svc_walk_cb(uintptr_t addr, const void *list_walker_data,
146     void *idc_void);
147 static int iscsi_ini_hba_walk_cb(uintptr_t addr, const void *vhba,
148     void *idc_void);
149 static int iscsi_ini_sess_walk_cb(uintptr_t addr, const void *vsess,
150     void *idc);
151 static int iscsi_ini_conn_walk_cb(uintptr_t addr, const void *vconn,
152     void *idc_void);
153 static int iscsi_ini_lun_walk_cb(uintptr_t addr, const void *vlun,
154     void *idc_void);
155 static int iscsi_ini_cmd_walk_cb(uintptr_t addr, const void *vcmd,
156     void *idc);
157 static int iscsi_tgt_impl(uintptr_t addr, iscsi_dcmd_ctrl_t *idc);
158 static int iscsi_tpgt_impl(uintptr_t addr, iscsi_dcmd_ctrl_t *idc);
159 static int iscsi_tpg_impl(uintptr_t addr, iscsi_dcmd_ctrl_t *idc);
160 static int iscsi_portal_impl(uintptr_t addr, iscsi_dcmd_ctrl_t *idc);
161 static int iscsi_sess_impl(uintptr_t addr, iscsi_dcmd_ctrl_t *idc);
162 static int iscsi_conn_impl(uintptr_t addr, iscsi_dcmd_ctrl_t *idc);
163 static void iscsi_print_iscsit_conn_data(idm_conn_t *ict);
164 static void iscsi_print_ini_conn_data(idm_conn_t *ict);
165 static void iscsi_print_idm_conn_data(idm_conn_t *ict);
166 static int iscsi_task_impl(uintptr_t addr, iscsi_dcmd_ctrl_t *idc);
167 static void iscsi_print_iscsit_task_data(idm_task_t *idt);
168 static int iscsi_buffer_impl(uintptr_t addr, iscsi_dcmd_ctrl_t *idc);
169 static idm_conn_type_t idm_conn_type(uintptr_t addr);
170 static int iscsi_i_task_impl(idm_task_t *idt, uintptr_t addr,
171     iscsi_dcmd_ctrl_t *idc);
172 static int iscsi_refcnt_impl(uintptr_t addr);
173 static int iscsi_sm_audit_impl(uintptr_t addr);
174 static int iscsi_isns(uintptr_t addr, uint_t flags, int argc,
175     const mdb_arg_t *argv);
176 static int iscsi_svc_impl(uintptr_t addr, iscsi_dcmd_ctrl_t *idc);
177 static int iscsi_ini_hba_impl(uintptr_t addr, iscsi_dcmd_ctrl_t *idc);
178 static int iscsi_print_ini_sess(uintptr_t addr, iscsi_sess_t *sess,
179     iscsi_dcmd_ctrl_t *idc);
180 static int iscsi_print_ini_lun(uintptr_t addr, const iscsi_lun_t *lun,
181     iscsi_dcmd_ctrl_t *idc);
182 static int iscsi_print_ini_cmd(uintptr_t addr, const iscsi_cmd_t *cmd,
183     iscsi_dcmd_ctrl_t *idc);
184 static int iscsi_ini_sess_walk_init(mdb_walk_state_t *wsp);
185 static int iscsi_ini_sess_step(mdb_walk_state_t *wsp);
186 static int iscsi_ini_conn_walk_init(mdb_walk_state_t *wsp);
187 static int iscsi_ini_conn_step(mdb_walk_state_t *wsp);
188 static int iscsi_ini_lun_walk_init(mdb_walk_state_t *wsp);
189 static int iscsi_ini_lun_step(mdb_walk_state_t *wsp);
190 static int iscsi_ini_cmd_walk_init(mdb_walk_state_t *wsp);
191 static int iscsi_ini_cmd_step(mdb_walk_state_t *wsp);
192 static const char *iscsi_idm_conn_event(unsigned int event);
193 static const char *iscsi_iscsit_tgt_event(unsigned int event);
194 static const char *iscsi_iscsit_sess_event(unsigned int event);
195 static const char *iscsi_iscsit_login_event(unsigned int event);
196 static const char *iscsi_iscsi_cmd_event(unsigned int event);
197 static const char *iscsi_iscsi_sess_event(unsigned int event);
198 static const char *iscsi_idm_conn_state(unsigned int state);
199 static const char *iscsi_idm_task_state(unsigned int state);
200 static const char *iscsi_iscsit_tgt_state(unsigned int state);
201 static const char *iscsi_iscsit_sess_state(unsigned int state);
202 static const char *iscsi_iscsit_login_state(unsigned int state);
203 static const char *iscsi_iscsi_cmd_state(unsigned int state);
204 static const char *iscsi_iscsi_sess_state(unsigned int state);
205 static const char *iscsi_iscsi_conn_state(unsigned int state);
206 static const char *iscsi_iscsi_conn_event(unsigned int event);
207 static const char *iscsi_iscsi_login_state(unsigned int state);
208 
209 static void iscsi_format_timestamp(char *ts_str, int strlen,
210     timespec_t *ts);
211 static char *iscsi_inet_ntop(int af, const void *addr, char *buf, int addrlen);
212 static void convert2ascii(char *, const in6_addr_t *);
213 static int sa_to_str(struct sockaddr_storage *sa, char *addr);
214 static int iscsi_isns_esi_cb(uintptr_t addr, const void *walker_data,
215     void *data);
216 static int iscsi_isns_portal_cb(uintptr_t addr, const void *walker_data,
217     void *data);
218 
219 #define	PORTAL_STR_LEN	(INET6_ADDRSTRLEN + 7)
220 
221 /*
222  * ::iscsi_tgt [-scatgpbSRv]
223  *
224  * iscsi_tgt - Print out information associated with an iscsit target instance
225  *
226  * s	Print associated session information
227  * c	Print associated connection information
228  * a	Print IP addresses with connection information
229  * t	Print associated task information
230  * g	Print associated TPG information
231  * p	Print portals with TPG information
232  * b	Print associated buffer information
233  * S	Print recent state events and transitions
234  * R	Print reference count audit data
235  * v	Verbose output about the connection
236  */
237 /*ARGSUSED*/
238 static int
239 iscsi_tgt(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
240 {
241 	iscsi_dcmd_ctrl_t	idc;
242 	int			buffer = 0, task = 0, print_ip = 0;
243 	int			tpgt = 0, conn = 0, sess = 0, portal = 0;
244 	int			states = 0, rc_audit = 0;
245 	uintptr_t		iscsit_global_addr, avl_addr, list_addr;
246 	GElf_Sym		sym;
247 
248 	bzero(&idc, sizeof (idc));
249 	if (mdb_getopts(argc, argv,
250 	    'a', MDB_OPT_SETBITS, TRUE, &print_ip,
251 	    'g', MDB_OPT_SETBITS, TRUE, &tpgt,
252 	    's', MDB_OPT_SETBITS, TRUE, &sess,
253 	    'c', MDB_OPT_SETBITS, TRUE, &conn,
254 	    't', MDB_OPT_SETBITS, TRUE, &task,
255 	    'b', MDB_OPT_SETBITS, TRUE, &buffer,
256 	    'p', MDB_OPT_SETBITS, TRUE, &portal,
257 	    'S', MDB_OPT_SETBITS, TRUE, &states,
258 	    'R', MDB_OPT_SETBITS, TRUE, &rc_audit,
259 	    'v', MDB_OPT_SETBITS, TRUE, &idc.idc_verbose,
260 	    NULL) != argc)
261 		return (DCMD_USAGE);
262 
263 	idc.u.child.idc_tgt = 1;
264 	idc.u.child.idc_print_ip = print_ip;
265 	idc.u.child.idc_tpgt = tpgt;
266 	idc.u.child.idc_portal = portal;
267 	idc.u.child.idc_sess = sess;
268 	idc.u.child.idc_conn = conn;
269 	idc.u.child.idc_task = task;
270 	idc.u.child.idc_buffer = buffer;
271 	idc.u.child.idc_states = states;
272 	idc.u.child.idc_rc_audit = rc_audit;
273 
274 	if (DCMD_HDRSPEC(flags))
275 		idc.idc_header = 1;
276 
277 	/*
278 	 * If no address was specified on the command line, we
279 	 * print out all tgtions
280 	 */
281 	if (!(flags & DCMD_ADDRSPEC)) {
282 		if (mdb_lookup_by_name("iscsit_global", &sym) == -1) {
283 			mdb_warn("failed to find symbol 'iscsit_global'");
284 			return (DCMD_ERR);
285 		}
286 		iscsit_global_addr = (uintptr_t)sym.st_value;
287 		avl_addr = iscsit_global_addr +
288 		    offsetof(iscsit_global_t, global_target_list);
289 		if (mdb_pwalk("avl", iscsi_tgt_walk_cb, &idc, avl_addr) == -1) {
290 			mdb_warn("avl walk failed for global target tree");
291 			return (DCMD_ERR);
292 		}
293 		list_addr = iscsit_global_addr +
294 		    offsetof(iscsit_global_t, global_deleted_target_list);
295 		if (mdb_pwalk("list", iscsi_tgt_walk_cb,
296 		    &idc, list_addr) == -1) {
297 			mdb_warn("list walk failed for deleted target list");
298 			return (DCMD_ERR);
299 		}
300 		return (DCMD_OK);
301 	}
302 	return (iscsi_tgt_impl(addr, &idc));
303 }
304 
305 static int
306 iscsi_tpg(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
307 {
308 	iscsi_dcmd_ctrl_t	idc;
309 	uintptr_t		iscsit_global_addr, avl_addr;
310 	GElf_Sym		sym;
311 	int			rc_audit = 0;
312 
313 	bzero(&idc, sizeof (idc));
314 	if (mdb_getopts(argc, argv,
315 	    'R', MDB_OPT_SETBITS, TRUE, &rc_audit,
316 	    NULL) != argc)
317 		return (DCMD_USAGE);
318 
319 	/* Always print tpgs and portals */
320 	idc.u.child.idc_tpg = 1;
321 	idc.u.child.idc_portal = 1;
322 	idc.u.child.idc_rc_audit = rc_audit;
323 	if (DCMD_HDRSPEC(flags))
324 		idc.idc_header = 1;
325 
326 	/*
327 	 * If no address was specified on the command line, we
328 	 * print out all tgtions
329 	 */
330 	if (!(flags & DCMD_ADDRSPEC)) {
331 		if (mdb_lookup_by_name("iscsit_global", &sym) == -1) {
332 			mdb_warn("failed to find symbol 'iscsit_global'");
333 			return (DCMD_ERR);
334 		}
335 		iscsit_global_addr = (uintptr_t)sym.st_value;
336 		avl_addr = iscsit_global_addr +
337 		    offsetof(iscsit_global_t, global_tpg_list);
338 		if (mdb_pwalk("avl", iscsi_tpg_walk_cb, &idc, avl_addr) == -1) {
339 			mdb_warn("avl walk failed for global target tree");
340 			return (DCMD_ERR);
341 		}
342 		return (DCMD_OK);
343 	}
344 	return (iscsi_tpg_impl(addr, &idc));
345 }
346 
347 /*
348  * ::iscsi_tpgt [-pR]
349  *
350  * Print tpgt information.
351  * R	Print reference count audit data
352  * p	Print portal data
353  */
354 static int
355 iscsi_tpgt(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
356 {
357 	iscsi_dcmd_ctrl_t	idc;
358 	uintptr_t		iscsit_global_addr, avl_addr, list_addr;
359 	GElf_Sym		sym;
360 	int			rc_audit = 0, portal = 0;
361 
362 	bzero(&idc, sizeof (idc));
363 	if (mdb_getopts(argc, argv,
364 	    'p', MDB_OPT_SETBITS, TRUE, &portal,
365 	    'R', MDB_OPT_SETBITS, TRUE, &rc_audit,
366 	    NULL) != argc)
367 		return (DCMD_USAGE);
368 
369 	idc.u.child.idc_tpgt = 1;
370 	idc.u.child.idc_portal = portal;
371 	idc.u.child.idc_rc_audit = rc_audit;
372 	if (DCMD_HDRSPEC(flags))
373 		idc.idc_header = 1;
374 
375 	/*
376 	 * If no address was specified on the command line,
377 	 * print out all tpgts
378 	 */
379 	if (!(flags & DCMD_ADDRSPEC)) {
380 		if (mdb_lookup_by_name("iscsit_global", &sym) == -1) {
381 			mdb_warn("failed to find symbol 'iscsit_global'");
382 			return (DCMD_ERR);
383 		}
384 		iscsit_global_addr = (uintptr_t)sym.st_value;
385 		avl_addr = iscsit_global_addr +
386 		    offsetof(iscsit_global_t, global_target_list);
387 		if (mdb_pwalk("avl", iscsi_tgt_walk_cb, &idc, avl_addr) == -1) {
388 			mdb_warn("avl walk failed for global target tree");
389 			return (DCMD_ERR);
390 		}
391 		list_addr = iscsit_global_addr +
392 		    offsetof(iscsit_global_t, global_deleted_target_list);
393 		if (mdb_pwalk("list", iscsi_tgt_walk_cb,
394 		    &idc, list_addr) == -1) {
395 			mdb_warn("list walk failed for deleted target list");
396 			return (DCMD_ERR);
397 		}
398 		return (DCMD_OK);
399 	}
400 	return (iscsi_tpgt_impl(addr, &idc));
401 }
402 
403 /*
404  * ::iscsi_sess [-ablmtvcSRIT]
405  *
406  * iscsi_sess - Print out information associated with an iSCSI session
407  *
408  * I	Print only initiator sessions
409  * T	Print only target sessions
410  * c	Print associated connection information
411  * a	Print IP addresses with connection information
412  * t	Print associated task information
413  * l	Print associated lun information (with -I)
414  * m	Print associated initiator command information (with -I)
415  * b	Print associated buffer information
416  * S	Print recent state events and transitions
417  * R	Print reference count audit data
418  * v	Verbose output about the connection
419  */
420 /*ARGSUSED*/
421 static int
422 iscsi_sess(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
423 {
424 	iscsi_dcmd_ctrl_t	idc;
425 	int			buffer = 0, task = 0, conn = 0, print_ip = 0;
426 	int			states = 0, rc_audit = 0, commands = 0;
427 	int			luns = 0;
428 
429 	bzero(&idc, sizeof (idc));
430 	if (mdb_getopts(argc, argv,
431 	    'I', MDB_OPT_SETBITS, TRUE, &idc.idc_ini,
432 	    'T', MDB_OPT_SETBITS, TRUE, &idc.idc_tgt,
433 	    'a', MDB_OPT_SETBITS, TRUE, &print_ip,
434 	    'c', MDB_OPT_SETBITS, TRUE, &conn,
435 	    't', MDB_OPT_SETBITS, TRUE, &task,
436 	    'l', MDB_OPT_SETBITS, TRUE, &luns,
437 	    'm', MDB_OPT_SETBITS, TRUE, &commands,
438 	    'b', MDB_OPT_SETBITS, TRUE, &buffer,
439 	    'S', MDB_OPT_SETBITS, TRUE, &states,
440 	    'R', MDB_OPT_SETBITS, TRUE, &rc_audit,
441 	    'v', MDB_OPT_SETBITS, TRUE, &idc.idc_verbose,
442 	    NULL) != argc)
443 		return (DCMD_USAGE);
444 
445 	idc.u.child.idc_sess = 1;
446 	idc.u.child.idc_print_ip = print_ip;
447 	idc.u.child.idc_conn = conn;
448 	idc.u.child.idc_task = task;
449 	idc.u.child.idc_cmd = commands;
450 	idc.u.child.idc_lun = luns;
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 sessions
460 	 */
461 	if (!(flags & DCMD_ADDRSPEC)) {
462 		return (iscsi_walk_all_sess(&idc));
463 	}
464 	return (iscsi_sess_impl(addr, &idc));
465 }
466 
467 
468 
469 /*
470  * ::iscsi_conn [-abmtvSRIT]
471  *
472  * iscsi_conn - Print out information associated with an iSCSI connection
473  *
474  * I	Print only initiator connections
475  * T	Print only target connections
476  * a	Print IP addresses with connection information
477  * t	Print associated task information
478  * b	Print associated buffer information
479  * m	Print associated initiator commands (with -I)
480  * S	Print recent state events and transitions
481  * R	Print reference count audit data
482  * v	Verbose output about the connection
483  */
484 /*ARGSUSED*/
485 static int
486 iscsi_conn(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
487 {
488 	iscsi_dcmd_ctrl_t	idc;
489 	int			buffer = 0, task = 0, print_ip = 0;
490 	int			states = 0, rc_audit = 0, commands = 0;
491 
492 	bzero(&idc, sizeof (idc));
493 	if (mdb_getopts(argc, argv,
494 	    'I', MDB_OPT_SETBITS, TRUE, &idc.idc_ini,
495 	    'T', MDB_OPT_SETBITS, TRUE, &idc.idc_tgt,
496 	    'a', MDB_OPT_SETBITS, TRUE, &print_ip,
497 	    't', MDB_OPT_SETBITS, TRUE, &task,
498 	    'b', MDB_OPT_SETBITS, TRUE, &buffer,
499 	    'm', MDB_OPT_SETBITS, TRUE, &commands,
500 	    'S', MDB_OPT_SETBITS, TRUE, &states,
501 	    'R', MDB_OPT_SETBITS, TRUE, &rc_audit,
502 	    'v', MDB_OPT_SETBITS, TRUE, &idc.idc_verbose,
503 	    NULL) != argc)
504 		return (DCMD_USAGE);
505 
506 	idc.u.child.idc_conn = 1;
507 	idc.u.child.idc_print_ip = print_ip;
508 	idc.u.child.idc_task = task;
509 	idc.u.child.idc_buffer = buffer;
510 	idc.u.child.idc_cmd = commands;
511 	idc.u.child.idc_states = states;
512 	idc.u.child.idc_rc_audit = rc_audit;
513 	if (DCMD_HDRSPEC(flags))
514 		idc.idc_header = 1;
515 
516 	/*
517 	 * If no address was specified on the command line, we
518 	 * print out all connections
519 	 */
520 	if (!(flags & DCMD_ADDRSPEC)) {
521 		return (iscsi_walk_all_conn(&idc));
522 	}
523 	return (iscsi_conn_impl(addr, &idc));
524 }
525 
526 
527 /*
528  * ::iscsi_svc [-vR]
529  *
530  * iscsi_svc - Print out information associated with an iSCSI svc
531  *
532  * R	Print reference count audit data
533  * v	Verbose output about the service
534  */
535 static int
536 iscsi_svc(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
537 {
538 	iscsi_dcmd_ctrl_t	idc;
539 	GElf_Sym		sym;
540 	uintptr_t		idm_addr;
541 	uintptr_t		svc_list_addr;
542 	int			rc_audit = 0;
543 
544 	bzero(&idc, sizeof (iscsi_dcmd_ctrl_t));
545 
546 	if (mdb_getopts(argc, argv,
547 	    'R', MDB_OPT_SETBITS, TRUE, &rc_audit,
548 	    'v', MDB_OPT_SETBITS, TRUE, &idc.idc_verbose,
549 	    NULL) != argc)
550 		return (DCMD_USAGE);
551 
552 	idc.u.child.idc_svc = 1;
553 	idc.u.child.idc_rc_audit = rc_audit;
554 	if (DCMD_HDRSPEC(flags)) {
555 		idc.idc_header = 1;
556 	}
557 
558 	if (!(flags & DCMD_ADDRSPEC)) {
559 		if (mdb_lookup_by_name("idm", &sym) == -1) {
560 			mdb_warn("failed to find symbol 'idm'");
561 			return (DCMD_ERR);
562 		}
563 		idm_addr = (uintptr_t)sym.st_value;
564 		svc_list_addr = idm_addr + offsetof(idm_global_t,
565 		    idm_tgt_svc_list);
566 
567 		if (mdb_pwalk("list", iscsi_svc_walk_cb, &idc,
568 		    svc_list_addr) == -1) {
569 			mdb_warn("list walk failed for idm services");
570 			return (DCMD_ERR);
571 		}
572 		return (DCMD_OK);
573 	}
574 	return (iscsi_svc_impl(addr, &idc));
575 }
576 
577 /*
578  * ::iscsi_portal -R
579  *
580  * iscsi_portal - Print out information associated with an iSCSI portal
581  *
582  * R	Print reference count audit data
583  */
584 static int
585 iscsi_portal(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
586 {
587 	iscsi_dcmd_ctrl_t	idc;
588 	GElf_Sym		sym;
589 	iscsit_global_t		iscsit_global;
590 	uintptr_t		iscsit_global_addr;
591 	uintptr_t		tpg_avl_addr;
592 	int			rc_audit = 0;
593 
594 	bzero(&idc, sizeof (iscsi_dcmd_ctrl_t));
595 
596 	if (mdb_getopts(argc, argv,
597 	    'R', MDB_OPT_SETBITS, TRUE, &rc_audit,
598 	    NULL) != argc)
599 		return (DCMD_USAGE);
600 
601 	idc.u.child.idc_rc_audit = rc_audit;
602 	idc.u.child.idc_portal = 1;
603 	if (DCMD_HDRSPEC(flags)) {
604 		idc.idc_header = 1;
605 	}
606 
607 	if (!(flags & DCMD_ADDRSPEC)) {
608 		if (mdb_lookup_by_name("iscsit_global", &sym) == -1) {
609 			mdb_warn("failed to find symbol 'iscsit_global'");
610 			return (DCMD_ERR);
611 		}
612 
613 		iscsit_global_addr = (uintptr_t)sym.st_value;
614 
615 		/* get and print the global default tpg */
616 		if (mdb_vread(&iscsit_global, sizeof (iscsit_global_t),
617 		    iscsit_global_addr) != sizeof (iscsit_global_t)) {
618 			mdb_warn("failed to read iscsit_global_t");
619 			return (DCMD_ERR);
620 		}
621 		if (iscsi_tpg_impl((uintptr_t)iscsit_global.global_default_tpg,
622 		    &idc) != DCMD_OK) {
623 			return (DCMD_ERR);
624 		}
625 
626 		/* Walk the tpgs for the rest of the portals */
627 		tpg_avl_addr = iscsit_global_addr + offsetof(iscsit_global_t,
628 		    global_tpg_list);
629 		if (mdb_pwalk("avl", iscsi_tpg_walk_cb, &idc,
630 		    tpg_avl_addr) == -1) {
631 			mdb_warn("list walk failed for global tpg tree");
632 			return (DCMD_ERR);
633 		}
634 		return (DCMD_OK);
635 	}
636 	return (iscsi_portal_impl(addr, &idc));
637 }
638 
639 
640 /*
641  * ::iscsi_cmd -S
642  *
643  * iscsi_cmd - Print out information associated with an iSCSI cmd
644  *
645  * S	Print state audit data
646  */
647 static int
648 iscsi_cmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
649 {
650 	iscsi_dcmd_ctrl_t	idc;
651 	iscsi_cmd_t		cmd;
652 	int			states = 0;
653 
654 	bzero(&idc, sizeof (iscsi_dcmd_ctrl_t));
655 
656 	if (mdb_getopts(argc, argv,
657 	    'S', MDB_OPT_SETBITS, TRUE, &states,
658 	    NULL) != argc)
659 		return (DCMD_USAGE);
660 
661 	idc.u.child.idc_states = states;
662 	idc.u.child.idc_cmd = 1;
663 	idc.idc_ini = 1;
664 	if (DCMD_HDRSPEC(flags)) {
665 		idc.idc_header = 1;
666 	}
667 
668 	if (!(flags & DCMD_ADDRSPEC)) {
669 		if (mdb_pwalk("iscsi_ini_hba", iscsi_ini_hba_walk_cb,
670 		    &idc, NULL) == -1) {
671 			mdb_warn("iscsi cmd hba list walk failed");
672 			return (DCMD_ERR);
673 		}
674 	} else {
675 		if (mdb_vread(&cmd, sizeof (iscsi_cmd_t), addr) !=
676 		    sizeof (iscsi_cmd_t)) {
677 			return (DCMD_ERR);
678 		}
679 		return (iscsi_print_ini_cmd(addr, &cmd, &idc));
680 	}
681 	return (DCMD_OK);
682 }
683 
684 
685 static int
686 iscsi_ini_hba_impl(uintptr_t addr, iscsi_dcmd_ctrl_t *idc)
687 {
688 	iscsi_hba_t ih;
689 
690 	if (mdb_vread(&ih, sizeof (ih), addr) != sizeof (ih)) {
691 		mdb_warn("Invalid HBA\n");
692 		return (DCMD_ERR);
693 	}
694 
695 	if (idc->u.child.idc_hba) {
696 		mdb_printf("iscsi_hba %p sessions: \n", addr);
697 	}
698 
699 	if (mdb_pwalk("iscsi_ini_sess", iscsi_ini_sess_walk_cb, idc,
700 	    (uintptr_t)ih.hba_sess_list) == -1) {
701 		mdb_warn("iscsi_sess_t walk failed");
702 		return (DCMD_ERR);
703 	}
704 	return (DCMD_OK);
705 }
706 
707 /*
708  * ::iscsi_task [-bv]
709  *
710  * iscsi_task - Print out information associated with an iSCSI task
711  *
712  * b	Print associated buffer information
713  * S	Print recent state events and transitions
714  * R	Print reference count audit data
715  * v	Verbose output about the connection
716  */
717 /*ARGSUSED*/
718 static int
719 iscsi_task(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
720 {
721 	iscsi_dcmd_ctrl_t	idc;
722 	int			buffer = 0;
723 	int			states = 0, rc_audit = 0;
724 
725 	bzero(&idc, sizeof (idc));
726 	if (mdb_getopts(argc, argv,
727 	    'b', MDB_OPT_SETBITS, TRUE, &buffer,
728 	    'S', MDB_OPT_SETBITS, TRUE, &states,
729 	    'R', MDB_OPT_SETBITS, TRUE, &rc_audit,
730 	    'v', MDB_OPT_SETBITS, TRUE, &idc.idc_verbose,
731 	    NULL) != argc)
732 		return (DCMD_USAGE);
733 
734 	idc.u.child.idc_conn = 0;
735 	idc.u.child.idc_task = 1;
736 	idc.u.child.idc_buffer = buffer;
737 	idc.u.child.idc_states = states;
738 	idc.u.child.idc_rc_audit = rc_audit;
739 	if (DCMD_HDRSPEC(flags))
740 		idc.idc_header = 1;
741 
742 	/*
743 	 * If no address was specified on the command line, we
744 	 * print out all connections
745 	 */
746 	if (!(flags & DCMD_ADDRSPEC)) {
747 		return (iscsi_walk_all_conn(&idc));
748 	}
749 	return (iscsi_task_impl(addr, &idc));
750 }
751 
752 /*
753  * ::iscsi_refcnt
754  *
755  * iscsi_refcnt - Dump an idm_refcnt_t structure
756  *
757  */
758 /*ARGSUSED*/
759 static int
760 iscsi_refcnt(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
761 {
762 	if (!(flags & DCMD_ADDRSPEC)) {
763 		return (DCMD_ERR);
764 	}
765 	return (iscsi_refcnt_impl(addr));
766 }
767 
768 /*
769  * ::iscsi_states
770  *
771  * iscsi_states - Dump events and state transitions recoreded in an
772  * idm_sm_audit_t structure
773  *
774  */
775 /*ARGSUSED*/
776 static int
777 iscsi_states(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
778 {
779 	if (!(flags & DCMD_ADDRSPEC)) {
780 		return (DCMD_ERR);
781 	}
782 	return (iscsi_sm_audit_impl(addr));
783 }
784 
785 
786 static int
787 iscsi_walk_all_sess(iscsi_dcmd_ctrl_t *idc)
788 {
789 	uintptr_t	iscsit_global_addr;
790 	uintptr_t	avl_addr;
791 	uintptr_t	list_addr;
792 	GElf_Sym	sym;
793 
794 	/* Initiator sessions */
795 	if (idc->idc_ini) {
796 		/* Always print hba info on this path */
797 		idc->u.child.idc_hba = 1;
798 		if (mdb_pwalk("iscsi_ini_hba", iscsi_ini_hba_walk_cb,
799 		    idc, NULL) == -1) {
800 			mdb_warn("iscsi cmd hba list walk failed");
801 			return (DCMD_ERR);
802 		}
803 		return (DCMD_OK);
804 	}
805 
806 	/* Target sessions */
807 	/* Walk discovery sessions */
808 	if (mdb_lookup_by_name("iscsit_global", &sym) == -1) {
809 		mdb_warn("failed to find symbol 'iscsit_global'");
810 		return (DCMD_ERR);
811 	}
812 	iscsit_global_addr = (uintptr_t)sym.st_value;
813 	avl_addr = iscsit_global_addr +
814 	    offsetof(iscsit_global_t, global_discovery_sessions);
815 	if (mdb_pwalk("avl", iscsi_sess_walk_cb, idc, avl_addr) == -1) {
816 		mdb_warn("avl walk failed for discovery sessions");
817 		return (DCMD_ERR);
818 	}
819 
820 	/* Walk targets printing all session info */
821 	avl_addr = iscsit_global_addr +
822 	    offsetof(iscsit_global_t, global_target_list);
823 	if (mdb_pwalk("avl", iscsi_tgt_walk_cb, idc, avl_addr) == -1) {
824 		mdb_warn("avl walk failed for target/session tree");
825 		return (DCMD_ERR);
826 	}
827 
828 	/* Walk deleting targets printing all session info */
829 	list_addr = iscsit_global_addr +
830 	    offsetof(iscsit_global_t, global_deleted_target_list);
831 	if (mdb_pwalk("list", iscsi_tgt_walk_cb, idc, list_addr) == -1) {
832 		mdb_warn("list walk failed for deleted target list");
833 		return (DCMD_ERR);
834 	}
835 
836 	return (DCMD_OK);
837 }
838 
839 static int
840 iscsi_walk_all_conn(iscsi_dcmd_ctrl_t *idc)
841 {
842 	uintptr_t	idm_global_addr;
843 	uintptr_t	list_addr;
844 	GElf_Sym	sym;
845 
846 	/* Walk initiator connections */
847 	if (mdb_lookup_by_name("idm", &sym) == -1) {
848 		mdb_warn("failed to find symbol 'idm'");
849 		return (DCMD_ERR);
850 	}
851 	idm_global_addr = (uintptr_t)sym.st_value;
852 	/* Walk connection list associated with the initiator */
853 	list_addr = idm_global_addr + offsetof(idm_global_t, idm_ini_conn_list);
854 	if (mdb_pwalk("list", iscsi_conn_walk_cb, idc, list_addr) == -1) {
855 		mdb_warn("list walk failed for initiator connections");
856 		return (DCMD_ERR);
857 	}
858 
859 	/* Walk connection list associated with the target */
860 	list_addr = idm_global_addr + offsetof(idm_global_t, idm_tgt_conn_list);
861 	if (mdb_pwalk("list", iscsi_conn_walk_cb, idc, list_addr) == -1) {
862 		mdb_warn("list walk failed for target service instances");
863 		return (DCMD_ERR);
864 	}
865 
866 	return (DCMD_OK);
867 }
868 
869 /*ARGSUSED*/
870 static int
871 iscsi_tpg_walk_cb(uintptr_t addr, const void *list_walker_data,
872     void *idc_void)
873 {
874 	/* We don't particularly care about the list walker data */
875 	iscsi_dcmd_ctrl_t	*idc = idc_void;
876 	int			rc;
877 
878 	rc = iscsi_tpg_impl(addr, idc);
879 
880 	return ((rc == DCMD_OK) ? WALK_NEXT : WALK_ERR);
881 }
882 
883 /*ARGSUSED*/
884 static int
885 iscsi_tgt_walk_cb(uintptr_t addr, const void *list_walker_data,
886     void *idc_void)
887 {
888 	/* We don't particularly care about the list walker data */
889 	iscsi_dcmd_ctrl_t	*idc = idc_void;
890 	int			rc;
891 
892 	rc = iscsi_tgt_impl(addr, idc);
893 
894 	return ((rc == DCMD_OK) ? WALK_NEXT : WALK_ERR);
895 }
896 
897 /*ARGSUSED*/
898 static int
899 iscsi_tpgt_walk_cb(uintptr_t addr, const void *list_walker_data,
900     void *idc_void)
901 {
902 	/* We don't particularly care about the list walker data */
903 	iscsi_dcmd_ctrl_t	*idc = idc_void;
904 	int			rc;
905 
906 	rc = iscsi_tpgt_impl(addr, idc);
907 
908 	return ((rc == DCMD_OK) ? WALK_NEXT : WALK_ERR);
909 }
910 
911 /*ARGSUSED*/
912 static int
913 iscsi_portal_walk_cb(uintptr_t addr, const void *list_walker_data,
914     void *idc_void)
915 {
916 	/* We don't particularly care about the list walker data */
917 	iscsi_dcmd_ctrl_t	*idc = idc_void;
918 	int			rc;
919 
920 	rc = iscsi_portal_impl(addr, idc);
921 
922 	return ((rc == DCMD_OK) ? WALK_NEXT : WALK_ERR);
923 }
924 
925 /*ARGSUSED*/
926 static int
927 iscsi_sess_walk_cb(uintptr_t addr, const void *list_walker_data,
928     void *idc_void)
929 {
930 	/* We don't particularly care about the list walker data */
931 	iscsi_dcmd_ctrl_t	*idc = idc_void;
932 	int			rc;
933 
934 	rc = iscsi_sess_impl(addr, idc);
935 
936 	return ((rc == DCMD_OK) ? WALK_NEXT : WALK_ERR);
937 }
938 
939 /*ARGSUSED*/
940 static int
941 iscsi_sess_conn_walk_cb(uintptr_t addr, const void *list_walker_data,
942     void *idc_void)
943 {
944 	/* We don't particularly care about the list walker data */
945 	iscsi_dcmd_ctrl_t	*idc = idc_void;
946 	iscsit_conn_t		ict;
947 	int			rc;
948 
949 	/*
950 	 * This function is different from iscsi_conn_walk_cb because
951 	 * we get an iscsit_conn_t instead of an idm_conn_t
952 	 *
953 	 * Read iscsit_conn_t, use to get idm_conn_t pointer
954 	 */
955 	if (mdb_vread(&ict, sizeof (iscsit_conn_t), addr) !=
956 	    sizeof (iscsit_conn_t)) {
957 		return (DCMD_ERR);
958 	}
959 	rc = iscsi_conn_impl((uintptr_t)ict.ict_ic, idc);
960 
961 	return ((rc == DCMD_OK) ? WALK_NEXT : WALK_ERR);
962 }
963 
964 /*ARGSUSED*/
965 static int
966 iscsi_conn_walk_cb(uintptr_t addr, const void *list_walker_data,
967     void *idc_void)
968 {
969 	/* We don't particularly care about the list walker data */
970 	iscsi_dcmd_ctrl_t	*idc = idc_void;
971 	int			rc;
972 
973 	rc = iscsi_conn_impl(addr, idc);
974 
975 	return ((rc == DCMD_OK) ? WALK_NEXT : WALK_ERR);
976 }
977 
978 /*ARGSUSED*/
979 static int
980 iscsi_buffer_walk_cb(uintptr_t addr, const void *list_walker_data,
981     void *idc_void)
982 {
983 	/* We don't particularly care about the list walker data */
984 	iscsi_dcmd_ctrl_t	*idc = idc_void;
985 	int			rc;
986 
987 	rc = iscsi_buffer_impl(addr, idc);
988 
989 	return ((rc == DCMD_OK) ? WALK_NEXT : WALK_ERR);
990 }
991 
992 /*ARGSUSED*/
993 static int
994 iscsi_svc_walk_cb(uintptr_t addr, const void *list_walker_data,
995     void *idc_void)
996 {
997 	iscsi_dcmd_ctrl_t	*idc = idc_void;
998 	int			rc;
999 
1000 	rc = iscsi_svc_impl(addr, idc);
1001 
1002 	return ((rc == DCMD_OK) ? WALK_NEXT : WALK_ERR);
1003 }
1004 
1005 /*ARGSUSED*/
1006 static int
1007 iscsi_ini_hba_walk_cb(uintptr_t addr, const void *vhba, void *idc_void)
1008 {
1009 
1010 	iscsi_dcmd_ctrl_t	*idc = idc_void;
1011 	int			rc;
1012 
1013 	rc = iscsi_ini_hba_impl(addr, idc);
1014 
1015 	return ((rc == DCMD_OK) ? WALK_NEXT : WALK_ERR);
1016 }
1017 
1018 static int
1019 iscsi_ini_sess_walk_cb(uintptr_t addr, const void *vsess, void *idc_void)
1020 {
1021 	int rc;
1022 
1023 	if (vsess == NULL) {
1024 		return (WALK_ERR);
1025 	}
1026 
1027 	rc = iscsi_print_ini_sess(addr, (iscsi_sess_t *)vsess,
1028 	    (iscsi_dcmd_ctrl_t *)idc_void);
1029 
1030 	return ((rc == DCMD_OK) ? WALK_NEXT : WALK_ERR);
1031 }
1032 
1033 /*ARGSUSED*/
1034 static int
1035 iscsi_ini_conn_walk_cb(uintptr_t addr, const void *vconn, void *idc_void)
1036 {
1037 	const iscsi_conn_t	*ict = vconn;
1038 	int			rc;
1039 
1040 	if (vconn == NULL) {
1041 		return (WALK_ERR);
1042 	}
1043 
1044 	/*
1045 	 * Look up the idm_conn_t in the iscsi_conn_t and call the general
1046 	 * connection handler.
1047 	 */
1048 	rc = iscsi_conn_impl((uintptr_t)ict->conn_ic,
1049 	    (iscsi_dcmd_ctrl_t *)idc_void);
1050 
1051 	return ((rc == DCMD_OK) ? WALK_NEXT : WALK_ERR);
1052 }
1053 
1054 static int
1055 iscsi_ini_lun_walk_cb(uintptr_t addr, const void *vlun, void *idc_void)
1056 {
1057 	int			rc;
1058 
1059 	if (vlun == NULL) {
1060 		return (WALK_ERR);
1061 	}
1062 
1063 	rc = iscsi_print_ini_lun(addr, (iscsi_lun_t *)vlun,
1064 	    (iscsi_dcmd_ctrl_t *)idc_void);
1065 
1066 	return ((rc == DCMD_OK) ? WALK_NEXT : WALK_ERR);
1067 }
1068 
1069 
1070 static int
1071 iscsi_tgt_impl(uintptr_t addr, iscsi_dcmd_ctrl_t *idc)
1072 {
1073 	iscsit_tgt_t	tgt;
1074 	uintptr_t	avl_addr, rc_addr, states_addr;
1075 	char		tgt_name[MAX_ISCSI_NODENAMELEN];
1076 	int		verbose, states, rc_audit;
1077 
1078 	/*
1079 	 * Read iscsit_tgt_t
1080 	 */
1081 	if (mdb_vread(&tgt, sizeof (iscsit_tgt_t), addr) !=
1082 	    sizeof (iscsit_tgt_t)) {
1083 		return (DCMD_ERR);
1084 	}
1085 
1086 	/*
1087 	 * Read target name if available
1088 	 */
1089 	if ((tgt.target_name == NULL) ||
1090 	    (mdb_readstr(tgt_name, sizeof (tgt_name),
1091 	    (uintptr_t)tgt.target_name) == -1)) {
1092 		strcpy(tgt_name, "N/A");
1093 	}
1094 
1095 	/*
1096 	 * Brief output
1097 	 *
1098 	 * iscsit_tgt_t pointer
1099 	 * iscsit_tgt_t.target_stmf_state
1100 	 * iscsit_tgt_t.target_sess_list.avl_numnodes (session count)
1101 	 * iscsit_tgt_t.target_name;
1102 	 */
1103 
1104 	verbose = idc->idc_verbose;
1105 	states = idc->u.child.idc_states;
1106 	rc_audit = idc->u.child.idc_rc_audit;
1107 
1108 	/* For now we will ignore the verbose flag */
1109 	if (idc->u.child.idc_tgt) {
1110 		/* Print target data */
1111 		if (idc->idc_header) {
1112 			mdb_printf("%<u>%-19s %-4s  %-8s%</u>\n",
1113 			    "iscsit_tgt_t", "Sess", "State");
1114 		}
1115 		mdb_printf("%-19p %-4d %-8d\n", addr,
1116 		    tgt.target_sess_list.avl_numnodes,
1117 		    tgt.target_state);
1118 		mdb_printf("  %s\n", tgt_name);
1119 
1120 		/* Indent and disable verbose for any child structures */
1121 		mdb_inc_indent(4);
1122 		idc->idc_verbose = 0;
1123 	}
1124 
1125 	/*
1126 	 * Print states if requested
1127 	 */
1128 	if (idc->u.child.idc_tgt && states) {
1129 		states_addr = addr + offsetof(iscsit_tgt_t, target_state_audit);
1130 
1131 		mdb_printf("State History(target_state_audit):\n");
1132 		if (iscsi_sm_audit_impl(states_addr) != DCMD_OK)
1133 			return (DCMD_ERR);
1134 		idc->u.child.idc_states = 0;
1135 	}
1136 
1137 	/*
1138 	 * Print refcnt audit data if requested
1139 	 */
1140 	if (idc->u.child.idc_tgt && rc_audit) {
1141 		mdb_printf("Reference History(target_sess_refcnt):\n");
1142 		rc_addr = addr +
1143 		    offsetof(iscsit_tgt_t, target_sess_refcnt);
1144 		if (iscsi_refcnt_impl(rc_addr) != DCMD_OK)
1145 			return (DCMD_ERR);
1146 
1147 		mdb_printf("Reference History(target_refcnt):\n");
1148 		rc_addr = addr +
1149 		    offsetof(iscsit_tgt_t, target_refcnt);
1150 
1151 		if (iscsi_refcnt_impl(rc_addr) != DCMD_OK)
1152 			return (DCMD_ERR);
1153 		idc->u.child.idc_rc_audit = 0;
1154 	}
1155 
1156 	/* Any child objects to walk? */
1157 	if (idc->u.child.idc_tpgt || idc->u.child.idc_portal) {
1158 
1159 		if (idc->u.child.idc_tgt) {
1160 			idc->idc_header = 1;
1161 		}
1162 
1163 		/* Walk TPGT tree */
1164 		avl_addr = addr +
1165 		    offsetof(iscsit_tgt_t, target_tpgt_list);
1166 		if (mdb_pwalk("avl", iscsi_tpgt_walk_cb, idc,
1167 		    avl_addr) == -1) {
1168 			mdb_warn("target tpgt list walk failed");
1169 			(void) mdb_dec_indent(4);
1170 			return (DCMD_ERR);
1171 		}
1172 	}
1173 
1174 	if (idc->u.child.idc_sess || idc->u.child.idc_conn ||
1175 	    idc->u.child.idc_task || idc->u.child.idc_buffer) {
1176 
1177 		if (idc->u.child.idc_tgt || idc->u.child.idc_tpgt ||
1178 		    idc->u.child.idc_portal) {
1179 			idc->idc_header = 1;
1180 		}
1181 
1182 		/* Walk sess tree */
1183 		avl_addr = addr + offsetof(iscsit_tgt_t, target_sess_list);
1184 		if (mdb_pwalk("avl", iscsi_sess_walk_cb, idc,
1185 		    avl_addr) == -1) {
1186 			mdb_warn("target sess list walk failed");
1187 			(void) mdb_dec_indent(4);
1188 			return (DCMD_ERR);
1189 		}
1190 	}
1191 
1192 	/* If tgts were handled decrease indent and reset header */
1193 	if (idc->u.child.idc_tgt) {
1194 		idc->idc_header = 0;
1195 		mdb_dec_indent(4);
1196 	}
1197 
1198 	idc->idc_verbose = verbose;
1199 	idc->u.child.idc_states = states;
1200 	idc->u.child.idc_rc_audit = rc_audit;
1201 	return (DCMD_OK);
1202 }
1203 
1204 static int
1205 iscsi_tpgt_impl(uintptr_t addr, iscsi_dcmd_ctrl_t *idc)
1206 {
1207 	iscsit_tpgt_t	tpgt;
1208 	iscsit_tpg_t	tpg;
1209 	uintptr_t	avl_addr, tpg_addr, rc_addr;
1210 	int		rc_audit;
1211 
1212 	/*
1213 	 * Read iscsit_tpgt_t
1214 	 */
1215 	if (mdb_vread(&tpgt, sizeof (iscsit_tpgt_t), addr) !=
1216 	    sizeof (iscsit_tpgt_t)) {
1217 		return (DCMD_ERR);
1218 	}
1219 
1220 	tpg_addr = (uintptr_t)tpgt.tpgt_tpg;
1221 
1222 	/*
1223 	 * Read iscsit_tpg_t
1224 	 */
1225 	if (mdb_vread(&tpg, sizeof (iscsit_tpg_t), tpg_addr) !=
1226 	    sizeof (iscsit_tpg_t)) {
1227 		return (DCMD_ERR);
1228 	}
1229 
1230 	rc_audit = idc->u.child.idc_rc_audit;
1231 
1232 	/*
1233 	 * Brief output
1234 	 *
1235 	 * iscsit_tpgt_t pointer
1236 	 * iscsit_tpg_t pointer
1237 	 * iscsit_tpg_t.tpg_name
1238 	 * iscsit_tpgt_t.tpgt_tag;
1239 	 */
1240 
1241 	/* For now we will ignore the verbose flag */
1242 	if (idc->u.child.idc_tpgt) {
1243 		/* Print target data */
1244 		if (idc->idc_header) {
1245 			mdb_printf("%<u>%-?s %-?s %-18s %-6s%</u>\n",
1246 			    "iscsit_tpgt_t", "iscsit_tpg_t", "Name", "Tag");
1247 		}
1248 		mdb_printf("%?p %?p %-18s 0x%04x\n", addr, tpgt.tpgt_tpg,
1249 		    tpg.tpg_name, tpgt.tpgt_tag);
1250 
1251 		if (rc_audit) {
1252 			(void) mdb_inc_indent(4);
1253 
1254 			mdb_printf("Reference History(tpgt_refcnt):\n");
1255 			rc_addr = addr + offsetof(iscsit_tpgt_t, tpgt_refcnt);
1256 			if (iscsi_refcnt_impl(rc_addr) != DCMD_OK)
1257 				return (DCMD_ERR);
1258 
1259 			idc->u.child.idc_rc_audit = 0;
1260 			(void) mdb_dec_indent(4);
1261 		}
1262 	}
1263 
1264 	/*
1265 	 * Assume for now that anyone interested in TPGT wants to see the
1266 	 * portals as well. Enable idc_header for the portals.
1267 	 */
1268 	idc->idc_header = 1;
1269 	(void) mdb_inc_indent(4);
1270 	avl_addr = tpg_addr + offsetof(iscsit_tpg_t, tpg_portal_list);
1271 	if (mdb_pwalk("avl", iscsi_portal_walk_cb, idc, avl_addr) == -1) {
1272 		mdb_warn("portal list walk failed");
1273 		(void) mdb_dec_indent(4);
1274 		return (DCMD_ERR);
1275 	}
1276 	(void) mdb_dec_indent(4);
1277 	idc->idc_header = 0;
1278 
1279 	idc->u.child.idc_rc_audit = rc_audit;
1280 	return (DCMD_OK);
1281 }
1282 
1283 static int
1284 iscsi_tpg_impl(uintptr_t addr, iscsi_dcmd_ctrl_t *idc)
1285 {
1286 	iscsit_tpg_t	tpg;
1287 	uintptr_t	avl_addr, rc_addr;
1288 	int		rc_audit = 0;
1289 
1290 	rc_audit = idc->u.child.idc_rc_audit;
1291 
1292 	/*
1293 	 * Read iscsit_tpg_t
1294 	 */
1295 	if (mdb_vread(&tpg, sizeof (iscsit_tpg_t), addr) !=
1296 	    sizeof (iscsit_tpg_t)) {
1297 		return (DCMD_ERR);
1298 	}
1299 
1300 	/*
1301 	 * Brief output
1302 	 *
1303 	 * iscsit_tpgt_t pointer
1304 	 * iscsit_tpg_t pointer
1305 	 * iscsit_tpg_t.tpg_name
1306 	 * iscsit_tpgt_t.tpgt_tag;
1307 	 */
1308 
1309 	/* Print tpg data */
1310 	if (idc->u.child.idc_tpg) {
1311 		if (idc->idc_header) {
1312 			mdb_printf("%<u>%-?s %-18s%</u>\n",
1313 			    "iscsit_tpg_t", "Name");
1314 		}
1315 		mdb_printf("%?p %-18s\n", addr, tpg.tpg_name);
1316 
1317 		(void) mdb_inc_indent(4);
1318 
1319 		if (rc_audit) {
1320 			mdb_printf("Reference History(tpg_refcnt):\n");
1321 			rc_addr = addr + offsetof(iscsit_tpg_t, tpg_refcnt);
1322 			if (iscsi_refcnt_impl(rc_addr) != DCMD_OK) {
1323 				return (DCMD_ERR);
1324 			}
1325 			idc->u.child.idc_rc_audit = 0;
1326 		}
1327 	}
1328 
1329 	if (idc->u.child.idc_portal) {
1330 		if (idc->u.child.idc_tpg) {
1331 			idc->idc_header = 1;
1332 		}
1333 
1334 		avl_addr = addr + offsetof(iscsit_tpg_t, tpg_portal_list);
1335 		if (mdb_pwalk("avl", iscsi_portal_walk_cb, idc,
1336 		    avl_addr) == -1) {
1337 			mdb_warn("portal list walk failed");
1338 			if (idc->u.child.idc_tpg) {
1339 				(void) mdb_dec_indent(4);
1340 			}
1341 			return (DCMD_ERR);
1342 		}
1343 	}
1344 
1345 	if (idc->u.child.idc_tpg) {
1346 		(void) mdb_dec_indent(4);
1347 		idc->idc_header = 0;
1348 	}
1349 
1350 	idc->u.child.idc_rc_audit = rc_audit;
1351 	return (DCMD_OK);
1352 }
1353 
1354 static int
1355 iscsi_portal_impl(uintptr_t addr, iscsi_dcmd_ctrl_t *idc)
1356 {
1357 	iscsit_portal_t	portal;
1358 	char		portal_addr[PORTAL_STR_LEN];
1359 	uintptr_t	rc_addr;
1360 
1361 	if (idc->u.child.idc_portal) {
1362 		/*
1363 		 * Read iscsit_portal_t
1364 		 */
1365 		if (mdb_vread(&portal, sizeof (iscsit_portal_t), addr) !=
1366 		    sizeof (iscsit_portal_t)) {
1367 			return (DCMD_ERR);
1368 		}
1369 
1370 		/* Print portal data */
1371 		if (idc->idc_header) {
1372 			mdb_printf("%<u>%-?s %-?s %-30s%</u>\n",
1373 			    "iscsit_portal_t", "idm_svc_t", "IP:Port");
1374 			idc->idc_header = 0;
1375 		}
1376 		sa_to_str(&portal.portal_addr, portal_addr);
1377 		mdb_printf("%?p %?p %s\n", addr, portal.portal_svc,
1378 		    portal.portal_default ? "(Default)" : portal_addr);
1379 
1380 		if (idc->u.child.idc_rc_audit) {
1381 			(void) mdb_inc_indent(4);
1382 			mdb_printf("Reference History(portal_refcnt):\n");
1383 			rc_addr = addr + offsetof(iscsit_portal_t,
1384 			    portal_refcnt);
1385 			if (iscsi_refcnt_impl(rc_addr) != DCMD_OK) {
1386 				return (DCMD_ERR);
1387 			}
1388 			(void) mdb_dec_indent(4);
1389 		}
1390 	}
1391 
1392 	return (DCMD_OK);
1393 }
1394 
1395 static int
1396 iscsi_sess_impl(uintptr_t addr, iscsi_dcmd_ctrl_t *idc)
1397 {
1398 	iscsit_sess_t	ist;
1399 	iscsi_sess_t	ini_sess;
1400 	uintptr_t	list_addr, states_addr, rc_addr;
1401 	char		ini_name[80];
1402 	char		tgt_name[80];
1403 	int		verbose, states, rc_audit;
1404 
1405 	if (idc->idc_ini) {
1406 		if ((mdb_vread(&ini_sess, sizeof (iscsi_sess_t),
1407 		    (uintptr_t)addr)) != sizeof (iscsi_sess_t)) {
1408 			mdb_warn("Failed to read initiator session\n");
1409 			return (DCMD_ERR);
1410 		}
1411 		if (iscsi_print_ini_sess(addr, &ini_sess, idc) != DCMD_OK) {
1412 			return (DCMD_ERR);
1413 		}
1414 		return (DCMD_OK);
1415 	}
1416 	/*
1417 	 * Read iscsit_sess_t
1418 	 */
1419 	if (mdb_vread(&ist, sizeof (iscsit_sess_t), addr) !=
1420 	    sizeof (iscsit_sess_t)) {
1421 		return (DCMD_ERR);
1422 	}
1423 
1424 	/*
1425 	 * Brief output
1426 	 *
1427 	 * iscsit_sess_t pointer
1428 	 * iscsit_sess_t.ist_state/iscsit_sess_t.ist_ffp_conn_count
1429 	 * iscsit_sess_t.ist_tsih
1430 	 * iscsit_sess_t.ist_initiator_name
1431 	 */
1432 
1433 	verbose = idc->idc_verbose;
1434 	states = idc->u.child.idc_states;
1435 	rc_audit = idc->u.child.idc_rc_audit;
1436 
1437 	if (idc->u.child.idc_sess) {
1438 		if (verbose) {
1439 			/*
1440 			 * Read initiator name if available
1441 			 */
1442 			if ((ist.ist_initiator_name == NULL) ||
1443 			    (mdb_readstr(ini_name, sizeof (ini_name),
1444 			    (uintptr_t)ist.ist_initiator_name) == -1)) {
1445 				strcpy(ini_name, "N/A");
1446 			}
1447 
1448 			/*
1449 			 * Read target name if available
1450 			 */
1451 			if ((ist.ist_target_name == NULL) ||
1452 			    (mdb_readstr(tgt_name, sizeof (tgt_name),
1453 			    (uintptr_t)ist.ist_target_name) == -1)) {
1454 				strcpy(tgt_name, "N/A");
1455 			}
1456 
1457 			mdb_printf("Session %p\n", addr);
1458 			mdb_printf("%16s: %d\n", "State",
1459 			    ist.ist_state);
1460 			mdb_printf("%16s: %d\n", "Last State",
1461 			    ist.ist_last_state);
1462 			mdb_printf("%16s: %d\n", "FFP Connections",
1463 			    ist.ist_ffp_conn_count);
1464 			mdb_printf("%16s: %02x%02x%02x%02x%02x%02x\n", "ISID",
1465 			    ist.ist_isid[0], ist.ist_isid[1], ist.ist_isid[2],
1466 			    ist.ist_isid[3], ist.ist_isid[4], ist.ist_isid[5]);
1467 			mdb_printf("%16s: 0x%04x\n", "TSIH",
1468 			    ist.ist_tsih);
1469 			mdb_printf("%16s: %s\n", "Initiator IQN",
1470 			    ini_name);
1471 			mdb_printf("%16s: %s\n", "Target IQN",
1472 			    tgt_name);
1473 			mdb_printf("%16s: %08x\n", "ExpCmdSN",
1474 			    ist.ist_expcmdsn);
1475 			mdb_printf("%16s: %08x\n", "MaxCmdSN",
1476 			    ist.ist_maxcmdsn);
1477 
1478 			idc->idc_verbose = 0;
1479 		} else {
1480 			/* Print session data */
1481 			if (idc->idc_header) {
1482 				mdb_printf("%<u>%-?s %10s %-12s %-6s%</u>\n",
1483 				    "iscsit_sess_t", "State/Conn", "ISID",
1484 				    "TSIH");
1485 			}
1486 			mdb_printf("%?p  %4d/%-4d %02x%02x%02x%02x%02x%02x "
1487 			    "0x%04x\n", addr,
1488 			    ist.ist_state, ist.ist_ffp_conn_count,
1489 			    ist.ist_isid[0], ist.ist_isid[1], ist.ist_isid[2],
1490 			    ist.ist_isid[3], ist.ist_isid[4], ist.ist_isid[5],
1491 			    ist.ist_tsih);
1492 		}
1493 
1494 		/*
1495 		 * Indent for any child structures
1496 		 */
1497 		(void) mdb_inc_indent(4);
1498 	}
1499 
1500 	/*
1501 	 * Print states if requested
1502 	 */
1503 	if (idc->u.child.idc_sess && states) {
1504 		states_addr = addr + offsetof(iscsit_sess_t, ist_state_audit);
1505 
1506 		mdb_printf("State History(ist_state_audit):\n");
1507 		if (iscsi_sm_audit_impl(states_addr) != DCMD_OK)
1508 			return (DCMD_ERR);
1509 
1510 		/* Don't print state history for child objects */
1511 		idc->u.child.idc_states = 0;
1512 	}
1513 
1514 	/*
1515 	 * Print refcnt audit data if requested
1516 	 */
1517 	if (idc->u.child.idc_sess && rc_audit) {
1518 		mdb_printf("Reference History(ist_refcnt):\n");
1519 		rc_addr = addr +
1520 		    offsetof(iscsit_sess_t, ist_refcnt);
1521 		if (iscsi_refcnt_impl(rc_addr) != DCMD_OK)
1522 			return (DCMD_ERR);
1523 
1524 		/* Don't print audit data for child objects */
1525 		idc->u.child.idc_rc_audit = 0;
1526 	}
1527 
1528 	/* Any child objects to walk? */
1529 	if (idc->u.child.idc_conn || idc->u.child.idc_task ||
1530 	    idc->u.child.idc_buffer) {
1531 		/*
1532 		 * If a session has been printed enable headers for
1533 		 * any child structs.
1534 		 */
1535 		if (idc->u.child.idc_sess) {
1536 			idc->idc_header = 1;
1537 		}
1538 
1539 		/* Walk conn list */
1540 		list_addr = addr + offsetof(iscsit_sess_t, ist_conn_list);
1541 		if (mdb_pwalk("list", iscsi_sess_conn_walk_cb, idc,
1542 		    list_addr) == -1) {
1543 			mdb_warn("session conn list walk failed");
1544 			(void) mdb_dec_indent(4);
1545 			return (DCMD_ERR);
1546 		}
1547 	}
1548 
1549 	/* If a session was handled decrease indent and reset header. */
1550 	if (idc->u.child.idc_sess) {
1551 		idc->idc_header = 0;
1552 		mdb_dec_indent(4);
1553 	}
1554 
1555 	idc->idc_verbose = verbose;
1556 	idc->u.child.idc_states = states;
1557 	idc->u.child.idc_rc_audit = rc_audit;
1558 
1559 	return (DCMD_OK);
1560 }
1561 
1562 static int
1563 iscsi_print_ini_sess(uintptr_t addr, iscsi_sess_t *sess,
1564     iscsi_dcmd_ctrl_t *idc)
1565 {
1566 
1567 	int verbose, states;
1568 	uintptr_t states_addr;
1569 
1570 	verbose = idc->idc_verbose;
1571 	states = idc->u.child.idc_states;
1572 
1573 
1574 	if (idc->u.child.idc_sess) {
1575 		if (!idc->idc_verbose) {
1576 			if (idc->idc_header) {
1577 				mdb_printf("%<u>%-?s %-4s  %-8s%</u>\n",
1578 				    "iscsi_sess_t", "Type", "State");
1579 			}
1580 			mdb_printf("%-19p %-4d %-8d\n", addr,
1581 			    sess->sess_type, sess->sess_state);
1582 		} else {
1583 			mdb_printf("Session %p\n", addr);
1584 			mdb_printf("%22s: %d\n", "State",
1585 			    sess->sess_state);
1586 			mdb_printf("%22s: %d\n", "Last State",
1587 			    sess->sess_prev_state);
1588 			mdb_printf("%22s: %s\n", "Session Name",
1589 			    sess->sess_name);
1590 			mdb_printf("%22s: %s\n", "Alias",
1591 			    sess->sess_alias);
1592 			mdb_printf("%22s: %08x\n", "CmdSN",
1593 			    sess->sess_cmdsn);
1594 			mdb_printf("%22s: %08x\n", "ExpCmdSN",
1595 			    sess->sess_expcmdsn);
1596 			mdb_printf("%22s: %08x\n", "MaxCmdSN",
1597 			    sess->sess_maxcmdsn);
1598 			mdb_printf("%22s: %p\n", "Pending Queue Head",
1599 			    sess->sess_queue_pending.head);
1600 			mdb_printf("%22s: %p\n", "Completion Queue Head",
1601 			    sess->sess_queue_completion.head);
1602 			mdb_printf("%22s: %p\n", "Connnection List Head",
1603 			    sess->sess_conn_list);
1604 
1605 			idc->idc_verbose = 0;
1606 		}
1607 
1608 		/* Indent for any child structures */
1609 		mdb_inc_indent(4);
1610 
1611 		if (idc->u.child.idc_states) {
1612 			states_addr = (uintptr_t)addr +
1613 			    offsetof(iscsi_sess_t, sess_state_audit);
1614 
1615 			mdb_printf("State History(sess_state_audit):\n");
1616 			if (iscsi_sm_audit_impl(states_addr) != DCMD_OK) {
1617 				(void) mdb_dec_indent(4);
1618 				return (DCMD_ERR);
1619 			}
1620 			idc->u.child.idc_states = 0;
1621 		}
1622 	}
1623 
1624 	if (idc->u.child.idc_lun && sess->sess_lun_list) {
1625 		if (idc->u.child.idc_sess) {
1626 			idc->idc_header = 1;
1627 		}
1628 
1629 		if (mdb_pwalk("iscsi_ini_lun", iscsi_ini_lun_walk_cb, idc,
1630 		    (uintptr_t)sess->sess_lun_list) == -1) {
1631 			mdb_warn("iscsi_ini_lun walk failed");
1632 			(void) mdb_dec_indent(4);
1633 			return (DCMD_ERR);
1634 		}
1635 	}
1636 
1637 
1638 	/* If requested print the cmds in the session queue */
1639 	if (idc->u.child.idc_cmd) {
1640 
1641 		/* If any other structs printed enable header */
1642 		if (idc->u.child.idc_sess || idc->u.child.idc_lun) {
1643 			idc->idc_header = 1;
1644 		}
1645 
1646 		if (sess->sess_queue_pending.head) {
1647 			if (mdb_pwalk("iscsi_ini_cmd", iscsi_ini_cmd_walk_cb,
1648 			    idc, (uintptr_t)sess->sess_queue_pending.head)
1649 			    == -1) {
1650 				mdb_warn("list walk failed for iscsi cmds");
1651 			}
1652 		}
1653 		if (sess->sess_queue_completion.head) {
1654 			if (mdb_pwalk("iscsi_ini_cmd", iscsi_ini_cmd_walk_cb,
1655 			    idc, (uintptr_t)sess->sess_queue_completion.head)
1656 			    == -1) {
1657 				mdb_warn("list walk failed for iscsi cmds");
1658 			}
1659 		}
1660 	}
1661 
1662 	/* If connections or cmds requested walk the connections */
1663 	if (idc->u.child.idc_conn || idc->u.child.idc_cmd) {
1664 		/*
1665 		 * If idc_conn is not set don't enable header or the
1666 		 * commands may get extraneous headers.
1667 		 */
1668 		if (idc->u.child.idc_conn) {
1669 			idc->idc_header = 1;
1670 		}
1671 		if (mdb_pwalk("iscsi_ini_conn", iscsi_ini_conn_walk_cb, idc,
1672 		    (uintptr_t)sess->sess_conn_list) == -1) {
1673 			mdb_warn("iscsi_ini_conn walk failed");
1674 			return (DCMD_ERR);
1675 		}
1676 	}
1677 
1678 	/* If sessions were handled decrease indent and reset header */
1679 	if (idc->u.child.idc_sess) {
1680 		idc->idc_header = 0;
1681 		mdb_dec_indent(4);
1682 	}
1683 
1684 	idc->u.child.idc_states = states;
1685 	idc->idc_verbose = verbose;
1686 	return (DCMD_OK);
1687 }
1688 
1689 
1690 static int
1691 iscsi_conn_impl(uintptr_t addr, iscsi_dcmd_ctrl_t *idc)
1692 {
1693 	uintptr_t	idm_global_addr, states_addr, rc_addr;
1694 	uintptr_t	task_addr, task_ptr;
1695 	GElf_Sym	sym;
1696 	idm_task_t	idt;
1697 	idm_conn_t	ic;
1698 	iscsit_conn_t	ict;
1699 	iscsi_conn_t	ini_conn;
1700 	char		*conn_type;
1701 	int		task_idx;
1702 	char		laddr[PORTAL_STR_LEN];
1703 	char		raddr[PORTAL_STR_LEN];
1704 	int		verbose, states, rc_audit;
1705 
1706 	/*
1707 	 * Get pointer to task table
1708 	 */
1709 
1710 	if (mdb_lookup_by_name("idm", &sym) == -1) {
1711 		mdb_warn("failed to find symbol 'idm'");
1712 		return (DCMD_ERR);
1713 	}
1714 
1715 	idm_global_addr = (uintptr_t)sym.st_value;
1716 
1717 	if (mdb_vread(&task_ptr, sizeof (uintptr_t),
1718 	    idm_global_addr + offsetof(idm_global_t, idm_taskid_table)) !=
1719 	    sizeof (uintptr_t)) {
1720 		mdb_warn("Failed to read address of task table");
1721 		return (DCMD_ERR);
1722 	}
1723 
1724 	/*
1725 	 * Read idm_conn_t
1726 	 */
1727 	if (mdb_vread(&ic, sizeof (idm_conn_t), addr) != sizeof (idm_conn_t)) {
1728 		return (DCMD_ERR);
1729 	}
1730 
1731 	/*
1732 	 * If filter bits are set to only print targets or only initiators
1733 	 * skip entries of the other type.
1734 	 */
1735 	if (!(idc->idc_ini && idc->idc_tgt) &&
1736 	    ((idc->idc_ini && (ic.ic_conn_type != CONN_TYPE_INI)) ||
1737 	    (idc->idc_tgt && (ic.ic_conn_type != CONN_TYPE_TGT)))) {
1738 		return (DCMD_OK);
1739 	}
1740 
1741 
1742 	conn_type = (ic.ic_conn_type == CONN_TYPE_INI) ? "Ini" :
1743 	    (ic.ic_conn_type == CONN_TYPE_TGT) ? "Tgt" : "Unk";
1744 
1745 	/*
1746 	 * Brief output
1747 	 *
1748 	 * idm_conn_t pointer
1749 	 * idm_conn_t.ic_conn_type
1750 	 * idm_conn_t.ic_statet+idm_conn_t.ic_ffp
1751 	 */
1752 
1753 	verbose = idc->idc_verbose;
1754 	states = idc->u.child.idc_states;
1755 	rc_audit = idc->u.child.idc_rc_audit;
1756 
1757 	/*
1758 	 * If targets(-T) and/or initiators (-I) are specifically requested,
1759 	 * fetch the iscsit_conn_t and/or iscsi_conn_t struct as a sanity
1760 	 * check and for use below.
1761 	 */
1762 	if (idc->idc_tgt && IDM_CONN_ISTGT(&ic)) {
1763 		if (mdb_vread(&ict, sizeof (iscsit_conn_t),
1764 		    (uintptr_t)ic.ic_handle) !=
1765 		    sizeof (iscsit_conn_t)) {
1766 			mdb_printf("Failed to read target connection "
1767 			    "handle data\n");
1768 			return (DCMD_ERR);
1769 		}
1770 	}
1771 
1772 	if (idc->idc_ini && IDM_CONN_ISINI(&ic)) {
1773 		if (mdb_vread(&ini_conn, sizeof (iscsi_conn_t),
1774 		    (uintptr_t)ic.ic_handle) !=
1775 		    sizeof (iscsi_conn_t)) {
1776 			mdb_printf("Failed to read initiator "
1777 			    "connection handle data\n");
1778 			return (DCMD_ERR);
1779 		}
1780 	}
1781 
1782 	if (idc->u.child.idc_conn) {
1783 		if (idc->idc_verbose) {
1784 			mdb_printf("IDM Conn %p\n", addr);
1785 			if (ic.ic_conn_type == CONN_TYPE_TGT) {
1786 				iscsi_print_iscsit_conn_data(&ic);
1787 			} else {
1788 				iscsi_print_ini_conn_data(&ic);
1789 			}
1790 			idc->idc_verbose = 0;
1791 		} else {
1792 			/* Print connection data */
1793 			if (idc->idc_header) {
1794 				mdb_printf("%<u>%-?s %-6s %-10s %12s%</u>\n",
1795 				    "idm_conn_t", "Type", "Transport",
1796 				    "State/FFP");
1797 			}
1798 			mdb_printf("%?p %-6s %-10s %6d/%-6d\n", addr, conn_type,
1799 			    (ic.ic_transport_type ==
1800 			    IDM_TRANSPORT_TYPE_ISER) ? "ISER_IB" :
1801 			    (ic.ic_transport_type ==
1802 			    IDM_TRANSPORT_TYPE_SOCKETS) ? "SOCKETS" :
1803 			    "N/A",
1804 			    ic.ic_state, ic.ic_ffp);
1805 			if (idc->u.child.idc_print_ip) {
1806 				sa_to_str(&ic.ic_laddr, laddr);
1807 				sa_to_str(&ic.ic_raddr, raddr);
1808 				mdb_printf("  L%s  R%s\n",
1809 				    laddr, raddr);
1810 			}
1811 		}
1812 
1813 		/* Indent for any child structs */
1814 		mdb_inc_indent(4);
1815 	}
1816 
1817 	/*
1818 	 * Print states if requested
1819 	 */
1820 	if (idc->u.child.idc_conn && states) {
1821 		states_addr = addr + offsetof(idm_conn_t, ic_state_audit);
1822 
1823 		mdb_printf("State History(ic_state_audit):\n");
1824 		if (iscsi_sm_audit_impl(states_addr) != DCMD_OK)
1825 			return (DCMD_ERR);
1826 
1827 		/*
1828 		 * If targets are specifically requested show the
1829 		 * state audit for the target specific connection struct
1830 		 */
1831 		if (idc->idc_tgt && IDM_CONN_ISTGT(&ic)) {
1832 			states_addr = (uintptr_t)ic.ic_handle +
1833 			    offsetof(iscsit_conn_t, ict_login_sm) +
1834 			    offsetof(iscsit_conn_login_t, icl_state_audit);
1835 
1836 			mdb_printf("State History(icl_state_audit):\n");
1837 			if (iscsi_sm_audit_impl(states_addr) != DCMD_OK) {
1838 				return (DCMD_ERR);
1839 			}
1840 		}
1841 
1842 		/*
1843 		 * If initiators are specifically requested show the
1844 		 * state audit for the initiator specific connection struct
1845 		 */
1846 		if (idc->idc_ini && IDM_CONN_ISINI(&ic)) {
1847 			states_addr = (uintptr_t)ic.ic_handle +
1848 			    offsetof(iscsi_conn_t, conn_state_audit);
1849 
1850 			mdb_printf("State History(iscsi_conn_t "
1851 			    "conn_state_audit):\n");
1852 			if (iscsi_sm_audit_impl(states_addr) != DCMD_OK) {
1853 				return (DCMD_ERR);
1854 			}
1855 		}
1856 
1857 		/* Don't print state history for child objects */
1858 		idc->u.child.idc_states = 0;
1859 	}
1860 
1861 	/*
1862 	 * Print refcnt audit data for the connection struct if requested.
1863 	 */
1864 	if (idc->u.child.idc_conn && rc_audit) {
1865 		mdb_printf("Reference History(ic_refcnt):\n");
1866 		rc_addr = addr + offsetof(idm_conn_t, ic_refcnt);
1867 		if (iscsi_refcnt_impl(rc_addr) != DCMD_OK)
1868 			return (DCMD_ERR);
1869 
1870 		/*
1871 		 * If targets are specifically requested show the
1872 		 * Refcounts for the target specific connection struct
1873 		 */
1874 		if (idc->idc_tgt && IDM_CONN_ISTGT(&ic)) {
1875 			mdb_printf("Reference History(ict_refcnt):\n");
1876 			rc_addr = (uintptr_t)ic.ic_handle +
1877 			    offsetof(iscsit_conn_t, ict_refcnt);
1878 			if (iscsi_refcnt_impl(rc_addr) != DCMD_OK) {
1879 				return (DCMD_ERR);
1880 			}
1881 
1882 			mdb_printf("Reference History(ict_dispatch_refcnt):\n");
1883 			rc_addr = (uintptr_t)ic.ic_handle +
1884 			    offsetof(iscsit_conn_t, ict_dispatch_refcnt);
1885 			if (iscsi_refcnt_impl(rc_addr) != DCMD_OK) {
1886 				return (DCMD_ERR);
1887 			}
1888 		}
1889 
1890 		/* Don't print audit data for child objects */
1891 		idc->u.child.idc_rc_audit = 0;
1892 	}
1893 
1894 	task_idx = 0;
1895 
1896 	if (idc->u.child.idc_task || idc->u.child.idc_buffer) {
1897 
1898 		if (idc->u.child.idc_conn) {
1899 			idc->idc_header = 1;
1900 		}
1901 
1902 		while (task_idx < IDM_TASKIDS_MAX) {
1903 			/*
1904 			 * Read the next idm_task_t
1905 			 */
1906 			if (mdb_vread(&task_addr, sizeof (uintptr_t),
1907 			    task_ptr) != sizeof (uintptr_t)) {
1908 				mdb_warn("Failed to read task pointer");
1909 				return (DCMD_ERR);
1910 			}
1911 
1912 			if (task_addr == NULL) {
1913 				task_ptr += sizeof (uintptr_t);
1914 				task_idx++;
1915 				continue;
1916 			}
1917 
1918 			if (mdb_vread(&idt, sizeof (idm_task_t), task_addr)
1919 			    != sizeof (idm_task_t)) {
1920 				mdb_warn("Failed to read task pointer");
1921 				return (DCMD_ERR);
1922 			}
1923 
1924 			if (((uintptr_t)idt.idt_ic == addr) &&
1925 			    (idt.idt_state != TASK_IDLE)) {
1926 				if (iscsi_i_task_impl(&idt, task_addr, idc)
1927 				    == -1) {
1928 					mdb_warn("Failed to walk connection "
1929 					    "task tree");
1930 					return (DCMD_ERR);
1931 				}
1932 			}
1933 
1934 			task_ptr += sizeof (uintptr_t);
1935 			task_idx++;
1936 		}
1937 	}
1938 
1939 	if (idc->idc_ini && IDM_CONN_ISINI(&ic) && idc->u.child.idc_cmd) {
1940 		if (idc->u.child.idc_conn || idc->u.child.idc_task) {
1941 			idc->idc_header = 1;
1942 		}
1943 		if (ini_conn.conn_queue_active.head &&
1944 		    (mdb_pwalk("iscsi_ini_cmd", iscsi_ini_cmd_walk_cb, idc,
1945 		    (uintptr_t)ini_conn.conn_queue_active.head) == -1)) {
1946 			mdb_warn("list walk failed for iscsi cmds");
1947 		}
1948 		if (ini_conn.conn_queue_idm_aborting.head &&
1949 		    (mdb_pwalk("iscsi_ini_cmd", iscsi_ini_cmd_walk_cb, idc,
1950 		    (uintptr_t)ini_conn.conn_queue_idm_aborting.head) == -1)) {
1951 			mdb_warn("list walk failed for iscsi cmds");
1952 		}
1953 	}
1954 
1955 	/*
1956 	 * If connection information was handled unset header and
1957 	 * decrease indent
1958 	 */
1959 	if (idc->u.child.idc_conn) {
1960 		idc->idc_header = 0;
1961 		mdb_dec_indent(4);
1962 	}
1963 
1964 	idc->idc_verbose = verbose;
1965 	idc->u.child.idc_states = states;
1966 	idc->u.child.idc_rc_audit = rc_audit;
1967 
1968 	return (DCMD_OK);
1969 }
1970 
1971 static int
1972 iscsi_svc_impl(uintptr_t addr, iscsi_dcmd_ctrl_t *idc)
1973 {
1974 	idm_svc_t	svc;
1975 	iser_svc_t	iser_svc;
1976 	uintptr_t	rc_addr;
1977 
1978 	if (mdb_vread(&svc, sizeof (idm_svc_t), addr) !=
1979 	    sizeof (idm_svc_t)) {
1980 		return (DCMD_ERR);
1981 	}
1982 
1983 	if (idc->u.child.idc_svc) {
1984 		if (idc->idc_verbose) {
1985 			mdb_printf("Service %p\n", addr);
1986 			mdb_printf("%20s: %d\n", "Port",
1987 			    svc.is_svc_req.sr_port);
1988 			mdb_printf("%20s: %d\n", "Online",
1989 			    svc.is_online);
1990 			mdb_printf("%20s: %p\n", "Socket Service",
1991 			    svc.is_so_svc);
1992 			mdb_printf("%20s: %p\n", "iSER Service",
1993 			    svc.is_iser_svc);
1994 		} else {
1995 			if (idc->idc_header) {
1996 				mdb_printf("%<u>%-?s %-8s %-8s%</u>\n",
1997 				    "idm_svc_t", "Port", "Online");
1998 				idc->idc_header = 0;
1999 			}
2000 
2001 			mdb_printf("%?p %-8d %-8d\n", addr,
2002 			    svc.is_svc_req.sr_port, svc.is_online);
2003 		}
2004 
2005 		if (idc->u.child.idc_rc_audit) {
2006 			(void) mdb_inc_indent(4);
2007 			mdb_printf("Reference History(is_refcnt):\n");
2008 			rc_addr = addr + offsetof(idm_svc_t, is_refcnt);
2009 			if (iscsi_refcnt_impl(rc_addr) != DCMD_OK) {
2010 				(void) mdb_dec_indent(4);
2011 				return (DCMD_ERR);
2012 			}
2013 
2014 			if (svc.is_iser_svc != NULL) {
2015 				mdb_printf("Reference History"
2016 				    "(iser_svc is_refcnt):\n");
2017 
2018 				/* Sanity check the iser svc struct */
2019 				if (mdb_vread(&iser_svc, sizeof (iser_svc_t),
2020 				    (uintptr_t)svc.is_iser_svc) !=
2021 				    sizeof (iser_svc_t)) {
2022 					return (DCMD_ERR);
2023 				}
2024 
2025 				rc_addr = (uintptr_t)svc.is_iser_svc +
2026 				    offsetof(iser_svc_t, is_refcnt);
2027 
2028 				if (iscsi_refcnt_impl(rc_addr) != DCMD_OK) {
2029 					return (DCMD_ERR);
2030 				}
2031 			}
2032 			(void) mdb_dec_indent(4);
2033 		}
2034 	}
2035 	return (DCMD_OK);
2036 }
2037 
2038 static void
2039 iscsi_print_iscsit_conn_data(idm_conn_t *ic)
2040 {
2041 	iscsit_conn_t	ict;
2042 	char		*csg;
2043 	char		*nsg;
2044 
2045 	iscsi_print_idm_conn_data(ic);
2046 
2047 	if (mdb_vread(&ict, sizeof (iscsit_conn_t),
2048 	    (uintptr_t)ic->ic_handle) != sizeof (iscsit_conn_t)) {
2049 		mdb_printf("**Failed to read conn private data\n");
2050 		return;
2051 	}
2052 
2053 	mdb_printf("%20s: %p\n", "iSCSIT TGT Conn",
2054 	    ic->ic_handle);
2055 
2056 	if (ict.ict_login_sm.icl_login_state != ILS_LOGIN_DONE) {
2057 		switch (ict.ict_login_sm.icl_login_csg) {
2058 		case ISCSI_SECURITY_NEGOTIATION_STAGE:
2059 			csg = "Security";
2060 			break;
2061 		case ISCSI_OP_PARMS_NEGOTIATION_STAGE:
2062 			csg = "Operational";
2063 			break;
2064 		case ISCSI_FULL_FEATURE_PHASE:
2065 			csg = "FFP";
2066 			break;
2067 		default:
2068 			csg = "Unknown";
2069 		}
2070 		switch (ict.ict_login_sm.icl_login_nsg) {
2071 		case ISCSI_SECURITY_NEGOTIATION_STAGE:
2072 			nsg = "Security";
2073 			break;
2074 		case ISCSI_OP_PARMS_NEGOTIATION_STAGE:
2075 			nsg = "Operational";
2076 			break;
2077 		case ISCSI_FULL_FEATURE_PHASE:
2078 			nsg = "FFP";
2079 			break;
2080 		default:
2081 			nsg = "Unknown";
2082 		}
2083 		mdb_printf("%20s: %d\n", "Login State",
2084 		    ict.ict_login_sm.icl_login_state);
2085 		mdb_printf("%20s: %d\n", "Login Last State",
2086 		    ict.ict_login_sm.icl_login_last_state);
2087 		mdb_printf("%20s: %s\n", "CSG", csg);
2088 		mdb_printf("%20s: %s\n", "NSG", nsg);
2089 		mdb_printf("%20s: %d\n", "Transit",
2090 		    ict.ict_login_sm.icl_login_transit >> 7);
2091 		mdb_printf("%20s: %p\n", "Request nvlist",
2092 		    ict.ict_login_sm.icl_request_nvlist);
2093 		mdb_printf("%20s: %p\n", "Response nvlist",
2094 		    ict.ict_login_sm.icl_response_nvlist);
2095 		mdb_printf("%20s: %p\n", "Negotiated nvlist",
2096 		    ict.ict_login_sm.icl_negotiated_values);
2097 		if (ict.ict_login_sm.icl_login_state == ILS_LOGIN_ERROR) {
2098 			mdb_printf("%20s: 0x%02x\n", "Error Class",
2099 			    ict.ict_login_sm.icl_login_resp_err_class);
2100 			mdb_printf("%20s: 0x%02x\n", "Error Detail",
2101 			    ict.ict_login_sm.icl_login_resp_err_detail);
2102 		}
2103 	}
2104 	mdb_printf("%20s: 0x%04x\n", "CID", ict.ict_cid);
2105 	mdb_printf("%20s: 0x%08x\n", "StatSN", ict.ict_statsn);
2106 }
2107 
2108 static void
2109 iscsi_print_ini_conn_data(idm_conn_t *ic)
2110 {
2111 	iscsi_conn_t	ini_conn;
2112 
2113 	iscsi_print_idm_conn_data(ic);
2114 
2115 	if (mdb_vread(&ini_conn, sizeof (iscsi_conn_t),
2116 	    (uintptr_t)ic->ic_handle) != sizeof (iscsi_conn_t)) {
2117 		mdb_printf("Failed to read conn private data\n");
2118 		return;
2119 	}
2120 
2121 	mdb_printf("%20s: %p\n", "iSCSI Ini Conn",
2122 	    ic->ic_handle);
2123 	mdb_printf("%20s: %p\n", "Parent Session",
2124 	    ini_conn.conn_sess);
2125 	mdb_printf("%20s: %d\n", "Conn State",
2126 	    ini_conn.conn_state);
2127 	mdb_printf("%20s: %d\n", "Last Conn State",
2128 	    ini_conn.conn_prev_state);
2129 
2130 	mdb_printf("%20s: %d\n", "Login Stage",
2131 	    ini_conn.conn_current_stage);
2132 	mdb_printf("%20s: %d\n", "Next Login Stage",
2133 	    ini_conn.conn_next_stage);
2134 
2135 	mdb_printf("%20s: 0x%08x\n", "Expected StatSN",
2136 	    ini_conn.conn_expstatsn);
2137 	mdb_printf("%20s: %p\n", "Active Queue Head",
2138 	    ini_conn.conn_queue_active.head);
2139 	mdb_printf("%20s: %d\n", "Abort Queue Head",
2140 	    ini_conn.conn_queue_idm_aborting.head);
2141 }
2142 
2143 static void
2144 iscsi_print_idm_conn_data(idm_conn_t *ic)
2145 {
2146 	char		laddr[PORTAL_STR_LEN];
2147 	char		raddr[PORTAL_STR_LEN];
2148 
2149 	sa_to_str(&ic->ic_laddr, laddr);
2150 	sa_to_str(&ic->ic_raddr, raddr);
2151 
2152 	mdb_printf("%20s: %s\n", "Conn Type",
2153 	    ((ic->ic_conn_type == CONN_TYPE_TGT) ? "Target" :
2154 	    ((ic->ic_conn_type == CONN_TYPE_INI) ? "Initiator" :
2155 	    "Unknown")));
2156 	if (ic->ic_conn_type == CONN_TYPE_TGT) {
2157 		mdb_printf("%20s: %p\n", "Svc. Binding",
2158 		    ic->ic_svc_binding);
2159 	}
2160 	mdb_printf("%20s: %s\n", "Transport",
2161 	    (ic->ic_transport_type == IDM_TRANSPORT_TYPE_ISER) ? "ISER_IB" :
2162 	    (ic->ic_transport_type == IDM_TRANSPORT_TYPE_SOCKETS) ? "SOCKETS" :
2163 	    "N/A");
2164 
2165 	mdb_printf("%20s: %s\n", "Local IP", laddr);
2166 	mdb_printf("%20s: %s\n", "Remote IP", raddr);
2167 	mdb_printf("%20s: %d\n", "State",
2168 	    ic->ic_state);
2169 	mdb_printf("%20s: %d\n", "Last State",
2170 	    ic->ic_last_state);
2171 	mdb_printf("%20s: %d %s\n", "Refcount",
2172 	    ic->ic_refcnt.ir_refcnt,
2173 	    (ic->ic_refcnt.ir_waiting == REF_NOWAIT) ? "" :
2174 	    ((ic->ic_refcnt.ir_waiting == REF_WAIT_SYNC) ? "REF_WAIT_SYNC" :
2175 	    ((ic->ic_refcnt.ir_waiting == REF_WAIT_ASYNC) ? "REF_WAIT_ASYNC" :
2176 	    "UNKNOWN")));
2177 }
2178 
2179 static int
2180 iscsi_i_task_impl(idm_task_t *idt, uintptr_t addr, iscsi_dcmd_ctrl_t *idc)
2181 {
2182 	uintptr_t	list_addr, rc_addr;
2183 	idm_conn_type_t	conn_type;
2184 	int		verbose, states, rc_audit;
2185 
2186 	conn_type = idm_conn_type((uintptr_t)idt->idt_ic);
2187 
2188 	verbose = idc->idc_verbose;
2189 	states = idc->u.child.idc_states;
2190 	rc_audit = idc->u.child.idc_rc_audit;
2191 
2192 	if (idc->u.child.idc_task) {
2193 		if (verbose) {
2194 			mdb_printf("Task %p\n", addr);
2195 			(void) mdb_inc_indent(2);
2196 			if (conn_type == CONN_TYPE_TGT) {
2197 				iscsi_print_iscsit_task_data(idt);
2198 			}
2199 			(void) mdb_dec_indent(2);
2200 		} else {
2201 			/* Print task data */
2202 			if (idc->idc_header) {
2203 				mdb_printf(
2204 				    "%<u>%-?s %-16s %-4s %-8s %-8s%</u>\n",
2205 				    "Tasks:", "State", "Ref",
2206 				    (conn_type == CONN_TYPE_TGT ? "TTT" :
2207 				    (conn_type == CONN_TYPE_INI ? "ITT" :
2208 				    "TT")), "Handle");
2209 			}
2210 			mdb_printf("%?p %-16s %04x %08x %08x\n", addr,
2211 			    idm_ts_name[idt->idt_state],
2212 			    idt->idt_refcnt.ir_refcnt,
2213 			    idt->idt_tt, idt->idt_client_handle);
2214 		}
2215 	}
2216 	idc->idc_header = 0;
2217 	idc->idc_verbose = 0;
2218 
2219 	/*
2220 	 * Print states if requested
2221 	 */
2222 #if 0
2223 	if (states) {
2224 		states_addr = addr + offsetof(idm_task_t, idt_state_audit);
2225 
2226 		(void) mdb_inc_indent(4);
2227 		mdb_printf("State History(idt_state_audit):\n");
2228 		if (iscsi_sm_audit_impl(states_addr) != DCMD_OK)
2229 			return (DCMD_ERR);
2230 
2231 		/* Don't print state history for child objects */
2232 		idc->u.child.idc_states = 0;
2233 		(void) mdb_dec_indent(4);
2234 	}
2235 #endif
2236 
2237 	/*
2238 	 * Print refcnt audit data if requested
2239 	 */
2240 	if (rc_audit) {
2241 		(void) mdb_inc_indent(4);
2242 		mdb_printf("Reference History(idt_refcnt):\n");
2243 		rc_addr = addr +
2244 		    offsetof(idm_task_t, idt_refcnt);
2245 		if (iscsi_refcnt_impl(rc_addr) != DCMD_OK)
2246 			return (DCMD_ERR);
2247 
2248 		/* Don't print audit data for child objects */
2249 		idc->u.child.idc_rc_audit = 0;
2250 		(void) mdb_dec_indent(4);
2251 	}
2252 
2253 
2254 	/*
2255 	 * Buffers are leaf objects and always get headers so the
2256 	 * user can discern between in and out buffers.
2257 	 */
2258 	if (idc->u.child.idc_buffer) {
2259 		/* Walk in buffer list */
2260 		(void) mdb_inc_indent(2);
2261 		mdb_printf("In buffers:\n");
2262 		idc->idc_header = 1;
2263 		(void) mdb_inc_indent(2);
2264 		list_addr = addr + offsetof(idm_task_t, idt_inbufv);
2265 		if (mdb_pwalk("list", iscsi_buffer_walk_cb, idc, list_addr) ==
2266 		    -1) {
2267 			mdb_warn("list walk failed for task in buffers");
2268 			(void) mdb_dec_indent(4);
2269 			return (DCMD_ERR);
2270 		}
2271 		(void) mdb_dec_indent(2);
2272 		/* Walk out buffer list */
2273 		mdb_printf("Out buffers:\n");
2274 		idc->idc_header = 1;
2275 		(void) mdb_inc_indent(2);
2276 		list_addr = addr + offsetof(idm_task_t, idt_outbufv);
2277 		if (mdb_pwalk("list", iscsi_buffer_walk_cb, idc, list_addr) ==
2278 		    -1) {
2279 			mdb_warn("list walk failed for task out buffers\n");
2280 			(void) mdb_dec_indent(2);
2281 			return (DCMD_ERR);
2282 		}
2283 		(void) mdb_dec_indent(4);
2284 	}
2285 
2286 	idc->idc_verbose = verbose;
2287 	idc->u.child.idc_states = states;
2288 	idc->u.child.idc_rc_audit = rc_audit;
2289 
2290 	return (DCMD_OK);
2291 }
2292 
2293 static int
2294 iscsi_task_impl(uintptr_t addr, iscsi_dcmd_ctrl_t *idc)
2295 {
2296 	idm_task_t	idt;
2297 
2298 	/*
2299 	 * Read idm_conn_t
2300 	 */
2301 	if (mdb_vread(&idt, sizeof (idm_task_t), addr) != sizeof (idm_task_t)) {
2302 		return (DCMD_ERR);
2303 	}
2304 
2305 	return (iscsi_i_task_impl(&idt, addr, idc));
2306 }
2307 
2308 #define	ISCSI_CDB_INDENT	16
2309 
2310 static void
2311 iscsi_print_iscsit_task_data(idm_task_t *idt)
2312 {
2313 	iscsit_task_t	itask;
2314 	boolean_t	good_scsi_task = B_TRUE;
2315 	scsi_task_t	scsi_task;
2316 
2317 	if (mdb_vread(&itask, sizeof (iscsit_task_t),
2318 	    (uintptr_t)idt->idt_private) != sizeof (iscsit_task_t)) {
2319 		mdb_printf("**Failed to read idt_private data\n");
2320 		return;
2321 	}
2322 
2323 	if (mdb_vread(&scsi_task, sizeof (scsi_task_t),
2324 	    (uintptr_t)itask.it_stmf_task) != sizeof (scsi_task_t)) {
2325 		good_scsi_task = B_FALSE;
2326 	}
2327 
2328 	mdb_printf("%20s: %s(%d)\n", "State",
2329 	    idt->idt_state > TASK_MAX_STATE ?
2330 	    "UNKNOWN" : idm_ts_name[idt->idt_state],
2331 	    idt->idt_state);
2332 	mdb_printf("%20s: %d/%d\n", "STMF abort/IDM aborted",
2333 	    itask.it_stmf_abort, itask.it_aborted);
2334 	mdb_printf("%20s: %p/%p/%p%s\n",
2335 	    "iscsit/STMF/LU", idt->idt_private,
2336 	    itask.it_stmf_task, good_scsi_task ? scsi_task.task_lu_private : 0,
2337 	    good_scsi_task ? "" : "**");
2338 	if (good_scsi_task) {
2339 		mdb_printf("%20s: %08x/%08x\n", "ITT/TTT",
2340 		    itask.it_itt, itask.it_ttt);
2341 		mdb_printf("%20s: %08x\n", "CmdSN",
2342 		    itask.it_cmdsn);
2343 		mdb_printf("%20s: %02x %02x %02x %02x %02x %02x %02x %02x\n",
2344 		    "LU number",
2345 		    scsi_task.task_lun_no[0], scsi_task.task_lun_no[1],
2346 		    scsi_task.task_lun_no[2], scsi_task.task_lun_no[3],
2347 		    scsi_task.task_lun_no[4], scsi_task.task_lun_no[5],
2348 		    scsi_task.task_lun_no[6], scsi_task.task_lun_no[7]);
2349 		mdb_printf("     CDB (%d bytes):\n",
2350 		    scsi_task.task_cdb_length);
2351 		(void) mdb_inc_indent(ISCSI_CDB_INDENT);
2352 		if (mdb_dumpptr((uintptr_t)scsi_task.task_cdb,
2353 		    scsi_task.task_cdb_length,
2354 		    MDB_DUMP_RELATIVE | MDB_DUMP_TRIM |
2355 		    MDB_DUMP_GROUP(1),
2356 		    (mdb_dumpptr_cb_t)mdb_vread, NULL)) {
2357 			mdb_printf("** Invalid CDB addr (%p)\n",
2358 			    scsi_task.task_cdb);
2359 		}
2360 		(void) mdb_dec_indent(ISCSI_CDB_INDENT);
2361 		mdb_printf("%20s: %d/%d\n", "STMF cur/max bufs",
2362 		    scsi_task.task_cur_nbufs,
2363 		    scsi_task.task_max_nbufs);
2364 		mdb_printf("%20s: 0x%08x/0x%08x/0x%08x\n", "Bytes Exp/Cmd/Done",
2365 		    scsi_task.task_expected_xfer_length,
2366 		    scsi_task.task_cmd_xfer_length,
2367 		    scsi_task.task_nbytes_transferred);
2368 		mdb_printf("%20s: 0x%x/0x%x\n", "TX-ini start/done",
2369 		    idt->idt_tx_to_ini_start,
2370 		    idt->idt_tx_to_ini_done);
2371 		mdb_printf("%20s: 0x%x/0x%x\n", "RX-ini start/done",
2372 		    idt->idt_rx_from_ini_start,
2373 		    idt->idt_rx_from_ini_done);
2374 	}
2375 }
2376 
2377 static int
2378 iscsi_print_ini_lun(uintptr_t addr, const iscsi_lun_t *lun,
2379     iscsi_dcmd_ctrl_t *idc)
2380 {
2381 
2382 	if (idc->u.child.idc_lun) {
2383 		if (idc->idc_header) {
2384 			mdb_printf("%<u>%-?s %-5s %-10s%</u>\n",
2385 			    "iscsi_lun_t", "State", "Lun Number");
2386 			idc->idc_header = 0;
2387 		}
2388 		mdb_printf("%?p %-5d %-10d\n", addr,
2389 		    lun->lun_state, lun->lun_num);
2390 	}
2391 	return (DCMD_OK);
2392 }
2393 
2394 static int
2395 iscsi_print_ini_cmd(uintptr_t addr, const iscsi_cmd_t *cmd,
2396     iscsi_dcmd_ctrl_t *idc)
2397 {
2398 
2399 	uintptr_t states_addr;
2400 
2401 	if (idc->idc_header) {
2402 		mdb_printf("%<u>%-?s %-?s %4s %6s/%-6s %-?s%</u>\n",
2403 		    "iscsi_cmd_t", "idm_task_t", "Type",
2404 		    "State", "Prev", "iscsi_lun_t");
2405 		idc->idc_header = 0;
2406 	}
2407 
2408 	mdb_printf("%?p %?p %4d %6d/%-6d %?p\n",
2409 	    addr, cmd->cmd_itp, cmd->cmd_type, cmd->cmd_state,
2410 	    cmd->cmd_prev_state, cmd->cmd_lun);
2411 
2412 	/*
2413 	 * Print states if requested
2414 	 */
2415 	if (idc->u.child.idc_states) {
2416 		states_addr = addr + offsetof(iscsi_cmd_t, cmd_state_audit);
2417 
2418 		(void) mdb_inc_indent(4);
2419 		mdb_printf("State History(cmd_state_audit):\n");
2420 		if (iscsi_sm_audit_impl(states_addr) != DCMD_OK)
2421 			return (DCMD_ERR);
2422 		idc->u.child.idc_states = 0;
2423 		(void) mdb_dec_indent(4);
2424 	}
2425 	return (DCMD_OK);
2426 }
2427 
2428 static int
2429 iscsi_buffer_impl(uintptr_t addr, iscsi_dcmd_ctrl_t *idc)
2430 {
2431 	idm_buf_t	idb;
2432 
2433 	/*
2434 	 * Read idm_buf_t
2435 	 */
2436 	if (mdb_vread(&idb, sizeof (idm_buf_t), addr) != sizeof (idm_buf_t)) {
2437 		return (DCMD_ERR);
2438 	}
2439 
2440 
2441 	if (idc->idc_header) {
2442 		mdb_printf("%<u>%-?s %?s/%-8s %8s %8s %8s%</u>\n",
2443 		    "idm_buf_t", "Mem Rgn", "Length",
2444 		    "Rel Off", "Xfer Len", "Exp. Off");
2445 		idc->idc_header = 0;
2446 	}
2447 
2448 	/* Print buffer data */
2449 	mdb_printf("%?p %?p/%08x %8x %8x %08x\n", addr,
2450 	    idb.idb_buf, idb.idb_buflen,
2451 	    idb.idb_bufoffset, idb.idb_xfer_len,
2452 	    idb.idb_exp_offset);
2453 
2454 
2455 	/* Buffers are leaf objects */
2456 
2457 	return (DCMD_OK);
2458 }
2459 
2460 static int
2461 iscsi_refcnt_impl(uintptr_t addr)
2462 {
2463 	idm_refcnt_t		refcnt;
2464 	refcnt_audit_buf_t	*anb;
2465 	int			ctr;
2466 
2467 	/*
2468 	 * Print refcnt info
2469 	 */
2470 	if (mdb_vread(&refcnt, sizeof (idm_refcnt_t), addr) !=
2471 	    sizeof (idm_refcnt_t)) {
2472 		mdb_warn("read refcnt failed");
2473 		return (DCMD_ERR);
2474 	}
2475 
2476 	anb = &refcnt.ir_audit_buf;
2477 
2478 	ctr = anb->anb_max_index + 1;
2479 	anb->anb_index--;
2480 	anb->anb_index &= anb->anb_max_index;
2481 
2482 	while (ctr) {
2483 		refcnt_audit_record_t	*anr;
2484 
2485 		anr = anb->anb_records + anb->anb_index;
2486 
2487 		if (anr->anr_depth) {
2488 			char c[MDB_SYM_NAMLEN];
2489 			GElf_Sym sym;
2490 			int i;
2491 
2492 			mdb_printf("\nRefCnt: %u\t", anr->anr_refcnt);
2493 
2494 			for (i = 0; i < anr->anr_depth; i++) {
2495 				if (mdb_lookup_by_addr(anr->anr_stack[i],
2496 				    MDB_SYM_FUZZY, c, sizeof (c),
2497 				    &sym) == -1) {
2498 					continue;
2499 				}
2500 				mdb_printf("%s+0x%1x", c,
2501 				    anr->anr_stack[i] -
2502 				    (uintptr_t)sym.st_value);
2503 				++i;
2504 				break;
2505 			}
2506 
2507 			while (i < anr->anr_depth) {
2508 				if (mdb_lookup_by_addr(anr->anr_stack[i],
2509 				    MDB_SYM_FUZZY, c, sizeof (c),
2510 				    &sym) == -1) {
2511 					++i;
2512 					continue;
2513 				}
2514 				mdb_printf("\n\t\t%s+0x%1x", c,
2515 				    anr->anr_stack[i] -
2516 				    (uintptr_t)sym.st_value);
2517 				++i;
2518 			}
2519 			mdb_printf("\n");
2520 		}
2521 		anb->anb_index--;
2522 		anb->anb_index &= anb->anb_max_index;
2523 		ctr--;
2524 	}
2525 
2526 	return (DCMD_OK);
2527 }
2528 
2529 static int
2530 iscsi_sm_audit_impl(uintptr_t addr)
2531 {
2532 	sm_audit_buf_t		audit_buf;
2533 	int			ctr;
2534 	const char		*event_name;
2535 	const char		*state_name;
2536 	const char		*new_state_name;
2537 	char			ts_string[40];
2538 	/*
2539 	 * Print refcnt info
2540 	 */
2541 	if (mdb_vread(&audit_buf, sizeof (sm_audit_buf_t), addr) !=
2542 	    sizeof (sm_audit_buf_t)) {
2543 		mdb_warn("failed to read audit buf");
2544 		return (DCMD_ERR);
2545 	}
2546 
2547 	ctr = audit_buf.sab_max_index + 1;
2548 	audit_buf.sab_index++;
2549 	audit_buf.sab_index &= audit_buf.sab_max_index;
2550 
2551 	while (ctr) {
2552 		sm_audit_record_t	*sar;
2553 
2554 		sar = audit_buf.sab_records + audit_buf.sab_index;
2555 
2556 		iscsi_format_timestamp(ts_string, 40, &sar->sar_timestamp);
2557 
2558 		switch (sar->sar_type) {
2559 		case SAR_STATE_EVENT:
2560 			switch (sar->sar_sm_type) {
2561 			case SAS_IDM_CONN:
2562 				state_name =
2563 				    iscsi_idm_conn_state(sar->sar_state);
2564 				event_name =
2565 				    iscsi_idm_conn_event(sar->sar_event);
2566 				break;
2567 			case SAS_ISCSIT_TGT:
2568 				state_name =
2569 				    iscsi_iscsit_tgt_state(sar->sar_state);
2570 				event_name =
2571 				    iscsi_iscsit_tgt_event(sar->sar_event);
2572 				break;
2573 			case SAS_ISCSIT_SESS:
2574 				state_name =
2575 				    iscsi_iscsit_sess_state(sar->sar_state);
2576 				event_name =
2577 				    iscsi_iscsit_sess_event(sar->sar_event);
2578 				break;
2579 			case SAS_ISCSIT_LOGIN:
2580 				state_name =
2581 				    iscsi_iscsit_login_state(sar->sar_state);
2582 				event_name =
2583 				    iscsi_iscsit_login_event(sar->sar_event);
2584 				break;
2585 			case SAS_ISCSI_CMD:
2586 				state_name =
2587 				    iscsi_iscsi_cmd_state(sar->sar_state);
2588 				event_name=
2589 				    iscsi_iscsi_cmd_event(sar->sar_event);
2590 				break;
2591 			case SAS_ISCSI_SESS:
2592 				state_name =
2593 				    iscsi_iscsi_sess_state(sar->sar_state);
2594 				event_name=
2595 				    iscsi_iscsi_sess_event(sar->sar_event);
2596 				break;
2597 			case SAS_ISCSI_CONN:
2598 				state_name =
2599 				    iscsi_iscsi_conn_state(sar->sar_state);
2600 				event_name=
2601 				    iscsi_iscsi_conn_event(sar->sar_event);
2602 				break;
2603 			default:
2604 				state_name = event_name = "N/A";
2605 				break;
2606 			}
2607 			mdb_printf("%s|%s (%d)\n\t%9s %s (%d) %p\n",
2608 			    ts_string, state_name, sar->sar_state,
2609 			    "Event", event_name,
2610 			    sar->sar_event, sar->sar_event_info);
2611 
2612 			break;
2613 		case SAR_STATE_CHANGE:
2614 			switch (sar->sar_sm_type) {
2615 			case SAS_IDM_CONN:
2616 				state_name =
2617 				    iscsi_idm_conn_state(sar->sar_state);
2618 				new_state_name =
2619 				    iscsi_idm_conn_state(sar->sar_new_state);
2620 				break;
2621 			case SAS_IDM_TASK:
2622 				state_name =
2623 				    iscsi_idm_task_state(sar->sar_state);
2624 				new_state_name =
2625 				    iscsi_idm_task_state(sar->sar_new_state);
2626 				break;
2627 			case SAS_ISCSIT_TGT:
2628 				state_name =
2629 				    iscsi_iscsit_tgt_state(sar->sar_state);
2630 				new_state_name =
2631 				    iscsi_iscsit_tgt_state(sar->sar_new_state);
2632 				break;
2633 			case SAS_ISCSIT_SESS:
2634 				state_name =
2635 				    iscsi_iscsit_sess_state(sar->sar_state);
2636 				new_state_name =
2637 				    iscsi_iscsit_sess_state(sar->sar_new_state);
2638 				break;
2639 			case SAS_ISCSIT_LOGIN:
2640 				state_name =
2641 				    iscsi_iscsit_login_state(sar->sar_state);
2642 				new_state_name =
2643 				    iscsi_iscsit_login_state(
2644 				    sar->sar_new_state);
2645 				break;
2646 			case SAS_ISCSI_CMD:
2647 				state_name =
2648 				    iscsi_iscsi_cmd_state(sar->sar_state);
2649 				new_state_name=
2650 				    iscsi_iscsi_cmd_state(sar->sar_new_state);
2651 				break;
2652 			case SAS_ISCSI_SESS:
2653 				state_name =
2654 				    iscsi_iscsi_sess_state(sar->sar_state);
2655 				new_state_name=
2656 				    iscsi_iscsi_sess_state(sar->sar_new_state);
2657 				break;
2658 			case SAS_ISCSI_CONN:
2659 				state_name =
2660 				    iscsi_iscsi_conn_state(sar->sar_state);
2661 				new_state_name=
2662 				    iscsi_iscsi_conn_state(sar->sar_new_state);
2663 				break;
2664 			case SAS_ISCSI_LOGIN:
2665 				state_name =
2666 				    iscsi_iscsi_login_state(sar->sar_state);
2667 				new_state_name=
2668 				    iscsi_iscsi_login_state(sar->sar_new_state);
2669 				break;
2670 			default:
2671 				state_name = new_state_name = "N/A";
2672 				break;
2673 			}
2674 			mdb_printf("%s|%s (%d)\n\t%9s %s (%d)\n",
2675 			    ts_string, state_name, sar->sar_state,
2676 			    "New State", new_state_name, sar->sar_new_state);
2677 
2678 			break;
2679 		default:
2680 			break;
2681 		}
2682 
2683 		audit_buf.sab_index++;
2684 		audit_buf.sab_index &= audit_buf.sab_max_index;
2685 		ctr--;
2686 	}
2687 
2688 	return (DCMD_OK);
2689 }
2690 
2691 static const char *
2692 iscsi_idm_conn_event(unsigned int event)
2693 {
2694 	return ((event < CE_MAX_EVENT) ? idm_ce_name[event] : "N/A");
2695 }
2696 
2697 static const char *
2698 iscsi_iscsit_tgt_event(unsigned int event)
2699 {
2700 	return ((event < TE_MAX_EVENT) ? iscsit_te_name[event] : "N/A");
2701 }
2702 
2703 static const char *
2704 iscsi_iscsit_sess_event(unsigned int event)
2705 {
2706 	return ((event < SE_MAX_EVENT) ? iscsit_se_name[event] : "N/A");
2707 }
2708 
2709 static const char *
2710 iscsi_iscsit_login_event(unsigned int event)
2711 {
2712 	return ((event < ILE_MAX_EVENT) ? iscsit_ile_name[event] : "N/A");
2713 }
2714 
2715 static const char *
2716 iscsi_iscsi_cmd_event(unsigned int event)
2717 {
2718 	return ((event < ISCSI_CMD_EVENT_MAX) ?
2719 	    iscsi_cmd_event_names[event] : "N/A");
2720 }
2721 
2722 static const char *
2723 iscsi_iscsi_sess_event(unsigned int event)
2724 {
2725 
2726 	return ((event < ISCSI_SESS_EVENT_MAX) ?
2727 	    iscsi_sess_event_names[event] : "N/A");
2728 }
2729 
2730 static const char *
2731 iscsi_idm_conn_state(unsigned int state)
2732 {
2733 	return ((state < CS_MAX_STATE) ? idm_cs_name[state] : "N/A");
2734 }
2735 
2736 static const char *
2737 iscsi_iscsi_conn_event(unsigned int event)
2738 {
2739 
2740 	return ((event < CN_MAX) ? idm_cn_strings[event] : "N/A");
2741 }
2742 
2743 /*ARGSUSED*/
2744 static const char *
2745 iscsi_idm_task_state(unsigned int state)
2746 {
2747 	return ("N/A");
2748 }
2749 
2750 static const char *
2751 iscsi_iscsit_tgt_state(unsigned int state)
2752 {
2753 	return ((state < TS_MAX_STATE) ? iscsit_ts_name[state] : "N/A");
2754 }
2755 
2756 static const char *
2757 iscsi_iscsit_sess_state(unsigned int state)
2758 {
2759 	return ((state < SS_MAX_STATE) ? iscsit_ss_name[state] : "N/A");
2760 }
2761 
2762 static const char *
2763 iscsi_iscsit_login_state(unsigned int state)
2764 {
2765 	return ((state < ILS_MAX_STATE) ? iscsit_ils_name[state] : "N/A");
2766 }
2767 
2768 static const char *
2769 iscsi_iscsi_cmd_state(unsigned int state)
2770 {
2771 	return ((state < ISCSI_CMD_STATE_MAX) ?
2772 	    iscsi_cmd_state_names[state] : "N/A");
2773 }
2774 
2775 static const char *
2776 iscsi_iscsi_sess_state(unsigned int state)
2777 {
2778 	return ((state < ISCSI_SESS_STATE_MAX) ?
2779 	    iscsi_sess_state_names[state] : "N/A");
2780 }
2781 
2782 static const char *
2783 iscsi_iscsi_conn_state(unsigned int state)
2784 {
2785 	return ((state < ISCSI_CONN_STATE_MAX) ? iscsi_ics_name[state] : "N/A");
2786 }
2787 
2788 static const char *
2789 iscsi_iscsi_login_state(unsigned int state)
2790 {
2791 	return ((state < LOGIN_MAX) ? iscsi_login_state_names[state] : "N/A");
2792 }
2793 
2794 
2795 /*
2796  * Retrieve connection type given a kernel address
2797  */
2798 static idm_conn_type_t
2799 idm_conn_type(uintptr_t addr)
2800 {
2801 	idm_conn_type_t result = 0; /* Unknown */
2802 	uintptr_t idm_conn_type_addr;
2803 
2804 	idm_conn_type_addr = addr + offsetof(idm_conn_t, ic_conn_type);
2805 	(void) mdb_vread(&result, sizeof (result), idm_conn_type_addr);
2806 
2807 	return (result);
2808 }
2809 
2810 /*
2811  * Convert a sockaddr to the string representation, suitable for
2812  * storing in an nvlist or printing out in a list.
2813  */
2814 static int
2815 sa_to_str(struct sockaddr_storage *sa, char *buf)
2816 {
2817 	char			pbuf[7];
2818 	const char		*bufp;
2819 	struct sockaddr_in	*sin;
2820 	struct sockaddr_in6	*sin6;
2821 	uint16_t		port;
2822 
2823 	if (!sa || !buf) {
2824 		return (EINVAL);
2825 	}
2826 
2827 	buf[0] = '\0';
2828 
2829 	if (sa->ss_family == AF_INET) {
2830 		sin = (struct sockaddr_in *)sa;
2831 		bufp = iscsi_inet_ntop(AF_INET,
2832 		    (const void *)&(sin->sin_addr.s_addr),
2833 		    buf, PORTAL_STR_LEN);
2834 		if (bufp == NULL) {
2835 			return (-1);
2836 		}
2837 		mdb_nhconvert(&port, &sin->sin_port, sizeof (uint16_t));
2838 	} else if (sa->ss_family == AF_INET6) {
2839 		strlcat(buf, "[", sizeof (buf));
2840 		sin6 = (struct sockaddr_in6 *)sa;
2841 		bufp = iscsi_inet_ntop(AF_INET6,
2842 		    (const void *)&sin6->sin6_addr.s6_addr,
2843 		    &buf[1], PORTAL_STR_LEN - 1);
2844 		if (bufp == NULL) {
2845 			return (-1);
2846 		}
2847 		strlcat(buf, "]", PORTAL_STR_LEN);
2848 		mdb_nhconvert(&port, &sin6->sin6_port, sizeof (uint16_t));
2849 	} else {
2850 		return (EINVAL);
2851 	}
2852 
2853 
2854 	mdb_snprintf(pbuf, sizeof (pbuf), ":%u", port);
2855 	strlcat(buf, pbuf, PORTAL_STR_LEN);
2856 
2857 	return (0);
2858 }
2859 
2860 
2861 static void
2862 iscsi_format_timestamp(char *ts_str, int strlen, timespec_t *ts)
2863 {
2864 	mdb_snprintf(ts_str, strlen, "%Y:%03d:%03d:%03d", ts->tv_sec,
2865 	    (ts->tv_nsec / 1000000) % 1000, (ts->tv_nsec / 1000) % 1000,
2866 	    ts->tv_nsec % 1000);
2867 }
2868 
2869 /*
2870  * Help information for the iscsi_isns dcmd
2871  */
2872 static void
2873 iscsi_isns_help(void)
2874 {
2875 	mdb_printf("iscsi_isns:\n");
2876 	mdb_inc_indent(4);
2877 	mdb_printf("-e: Print ESI information\n");
2878 	mdb_printf("-p: Print portal information\n");
2879 	mdb_printf("-s: Print iSNS server information\n");
2880 	mdb_printf("-t: Print target information\n");
2881 	mdb_printf("-v: Add verbosity to the other options' output\n");
2882 	mdb_printf("-R: Add Refcount information to '-t' output\n");
2883 	mdb_dec_indent(4);
2884 }
2885 
2886 /* ARGSUSED */
2887 static int
2888 iscsi_isns_esi_cb(uintptr_t addr, const void *walker_data, void *data)
2889 {
2890 	isns_esi_tinfo_t tinfo;
2891 
2892 	if (mdb_vread(&tinfo, sizeof (isns_esi_tinfo_t), addr) !=
2893 	    sizeof (isns_esi_tinfo_t)) {
2894 		return (WALK_ERR);
2895 	}
2896 
2897 	mdb_printf("ESI thread/thr did : 0x%p / %d\n", tinfo.esi_thread,
2898 	    tinfo.esi_thread_did);
2899 	mdb_printf("ESI sonode         : 0x%p\n", tinfo.esi_so);
2900 	mdb_printf("ESI port           : %d\n", tinfo.esi_port);
2901 	mdb_printf("ESI thread running : %s\n",
2902 	    (tinfo.esi_thread_running) ? "Yes" : "No");
2903 
2904 	return (WALK_NEXT);
2905 }
2906 
2907 static int
2908 iscsi_isns_esi(iscsi_dcmd_ctrl_t *idc)
2909 {
2910 	GElf_Sym		sym;
2911 	uintptr_t		addr;
2912 
2913 	if (mdb_lookup_by_name("esi", &sym) == -1) {
2914 		mdb_warn("failed to find symbol 'esi_list'");
2915 		return (DCMD_ERR);
2916 	}
2917 	addr = (uintptr_t)sym.st_value;
2918 
2919 	idc->idc_header = 1;
2920 	(void) iscsi_isns_esi_cb(addr, NULL, idc);
2921 
2922 	return (0);
2923 }
2924 
2925 /* ARGSUSED */
2926 static int
2927 iscsi_isns_portal_cb(uintptr_t addr, const void *walker_data, void *data)
2928 {
2929 	iscsi_dcmd_ctrl_t *idc = (iscsi_dcmd_ctrl_t *)data;
2930 	isns_portal_t portal;
2931 	char portal_addr[PORTAL_STR_LEN];
2932 	struct sockaddr_storage *ss;
2933 	char			ts_string[40];
2934 
2935 	if (mdb_vread(&portal, sizeof (isns_portal_t), addr) !=
2936 	    sizeof (isns_portal_t)) {
2937 		return (WALK_ERR);
2938 	}
2939 
2940 	ss = &portal.portal_addr;
2941 	sa_to_str(ss, portal_addr);
2942 	mdb_printf("Portal IP address ");
2943 
2944 	if (ss->ss_family == AF_INET) {
2945 		mdb_printf("(v4): %s", portal_addr);
2946 	} else {
2947 		mdb_printf("(v6): %s", portal_addr);
2948 	}
2949 
2950 	if (portal.portal_default == B_TRUE) {
2951 		mdb_printf(" (Default portal)\n");
2952 	} else {
2953 		mdb_printf("\n");
2954 	}
2955 	if (portal.portal_iscsit != NULL) {
2956 		mdb_printf("(Part of TPG: 0x%p)\n", portal.portal_iscsit);
2957 	}
2958 
2959 	iscsi_format_timestamp(ts_string, 40, &portal.portal_esi_timestamp);
2960 	mdb_printf("Portal ESI timestamp: %s\n\n", ts_string);
2961 
2962 	if ((portal.portal_iscsit != NULL) && (idc->idc_verbose)) {
2963 		mdb_inc_indent(4);
2964 		iscsi_portal_impl((uintptr_t)portal.portal_iscsit, idc);
2965 		mdb_dec_indent(4);
2966 	}
2967 
2968 
2969 	return (WALK_NEXT);
2970 }
2971 
2972 static int
2973 iscsi_isns_portals(iscsi_dcmd_ctrl_t *idc)
2974 {
2975 	GElf_Sym sym;
2976 	uintptr_t portal_list;
2977 
2978 	mdb_printf("All Active Portals:\n");
2979 
2980 	if (mdb_lookup_by_name("isns_all_portals", &sym) == -1) {
2981 		mdb_warn("failed to find symbol 'isns_all_portals'");
2982 		return (DCMD_ERR);
2983 	}
2984 
2985 	portal_list = (uintptr_t)sym.st_value;
2986 	idc->idc_header = 1;
2987 
2988 	if (mdb_pwalk("avl", iscsi_isns_portal_cb, idc, portal_list) == -1) {
2989 		mdb_warn("avl walk failed for isns_all_portals");
2990 		return (DCMD_ERR);
2991 	}
2992 	mdb_printf("\nPortals from TPGs:\n");
2993 
2994 	if (mdb_lookup_by_name("isns_tpg_portals", &sym) == -1) {
2995 		mdb_warn("failed to find symbol 'isns_tpg_portals'");
2996 		return (DCMD_ERR);
2997 	}
2998 
2999 	portal_list = (uintptr_t)sym.st_value;
3000 	idc->idc_header = 1;
3001 
3002 	if (mdb_pwalk("avl", iscsi_isns_portal_cb, idc, portal_list) == -1) {
3003 		mdb_warn("avl walk failed for isns_tpg_portals");
3004 		return (DCMD_ERR);
3005 	}
3006 
3007 
3008 	return (0);
3009 }
3010 
3011 /* ARGSUSED */
3012 static int
3013 iscsi_isns_targets_cb(uintptr_t addr, const void *walker_data, void *data)
3014 {
3015 	iscsi_dcmd_ctrl_t	*idc = (iscsi_dcmd_ctrl_t *)data;
3016 	isns_target_t		itarget;
3017 	int			rc = 0;
3018 	int			rc_audit = 0;
3019 	uintptr_t		rc_addr;
3020 
3021 	if (mdb_vread(&itarget, sizeof (isns_target_t), addr) !=
3022 	    sizeof (isns_target_t)) {
3023 		return (WALK_ERR);
3024 	}
3025 
3026 	idc->idc_header = 1;
3027 	rc_audit = idc->u.child.idc_rc_audit;
3028 
3029 	mdb_printf("Target: %p\n", addr);
3030 	mdb_inc_indent(4);
3031 	mdb_printf("Registered: %s\n",
3032 	    (itarget.target_registered) ? "Yes" : "No");
3033 	mdb_printf("Update needed: %s\n",
3034 	    (itarget.target_update_needed) ? "Yes" : "No");
3035 	mdb_printf("Target Info: %p\n", itarget.target_info);
3036 
3037 	/* Prevent target refcounts from showing through this path */
3038 	idc->u.child.idc_rc_audit = 0;
3039 	rc = iscsi_tgt_impl((uintptr_t)itarget.target, idc);
3040 
3041 	idc->u.child.idc_rc_audit = rc_audit;
3042 	if (idc->u.child.idc_rc_audit) {
3043 		rc_addr = (uintptr_t)itarget.target_info +
3044 		    offsetof(isns_target_info_t, ti_refcnt);
3045 
3046 		mdb_printf("Reference History(isns_target_info ti_refcnt):\n");
3047 		if (iscsi_refcnt_impl(rc_addr) != 0) {
3048 			return (WALK_ERR);
3049 		}
3050 	}
3051 
3052 	mdb_dec_indent(4);
3053 
3054 	if (rc == DCMD_OK) {
3055 		return (WALK_NEXT);
3056 	}
3057 
3058 	return (WALK_ERR);
3059 }
3060 
3061 static int
3062 iscsi_isns_targets(iscsi_dcmd_ctrl_t *idc)
3063 {
3064 	GElf_Sym sym;
3065 	uintptr_t isns_target_list;
3066 
3067 	if (mdb_lookup_by_name("isns_target_list", &sym) == -1) {
3068 		mdb_warn("failed to find symbol 'isns_target_list'");
3069 		return (DCMD_ERR);
3070 	}
3071 
3072 	isns_target_list = (uintptr_t)sym.st_value;
3073 	idc->idc_header = 1;
3074 	idc->u.child.idc_tgt = 1;
3075 
3076 	if (mdb_pwalk("avl", iscsi_isns_targets_cb, idc,
3077 	    isns_target_list) == -1) {
3078 		mdb_warn("avl walk failed for isns_target_list");
3079 		return (DCMD_ERR);
3080 	}
3081 
3082 	return (0);
3083 }
3084 
3085 /* ARGSUSED */
3086 static int
3087 iscsi_isns_servers_cb(uintptr_t addr, const void *walker_data, void *data)
3088 {
3089 	iscsit_isns_svr_t	server;
3090 	char			server_addr[PORTAL_STR_LEN];
3091 	struct sockaddr_storage *ss;
3092 	clock_t			lbolt;
3093 	iscsi_dcmd_ctrl_t	*idc = (iscsi_dcmd_ctrl_t *)data;
3094 	uintptr_t		avl_addr;
3095 
3096 	if (mdb_vread(&server, sizeof (iscsit_isns_svr_t), addr) !=
3097 	    sizeof (iscsit_isns_svr_t)) {
3098 		return (WALK_ERR);
3099 	}
3100 
3101 	if ((lbolt = (clock_t)mdb_get_lbolt()) == -1)
3102 		return (WALK_ERR);
3103 
3104 	mdb_printf("iSNS server %p:\n", addr);
3105 	mdb_inc_indent(4);
3106 	ss = &server.svr_sa;
3107 	sa_to_str(ss, server_addr);
3108 
3109 	mdb_printf("IP address ");
3110 	if (ss->ss_family == AF_INET) {
3111 		mdb_printf("(v4): %s\n", server_addr);
3112 	} else {
3113 		mdb_printf("(v6): %s\n", server_addr);
3114 	}
3115 
3116 	mdb_printf("ESI Interval: %d seconds\n",
3117 	    server.svr_esi_interval);
3118 	mdb_printf("Last message: %d seconds ago\n",
3119 	    ((lbolt - server.svr_last_msg) / 100));
3120 	mdb_printf("Client registered: %s\n",
3121 	    (server.svr_registered) ? "Yes" : "No");
3122 	mdb_printf("Retry Count: %d\n",
3123 	    server.svr_retry_count);
3124 	mdb_printf("Targets Changes Pending: %s\n",
3125 	    (server.svr_targets_changed) ? "Yes" : "No");
3126 	mdb_printf("Delete Pending: %s\n",
3127 	    (server.svr_delete_needed) ? "Yes" : "No");
3128 	mdb_printf("Replace-All Needed: %s\n",
3129 	    (server.svr_reset_needed) ? "Yes" : "No");
3130 
3131 	if (idc->idc_verbose) {
3132 		idc->idc_header = 1;
3133 		idc->u.child.idc_tgt = 1;
3134 
3135 		mdb_inc_indent(2);
3136 		avl_addr = addr + offsetof(iscsit_isns_svr_t,
3137 		    svr_target_list);
3138 		if (mdb_pwalk("avl", iscsi_isns_targets_cb, idc,
3139 		    avl_addr) == -1) {
3140 			mdb_warn("avl walk failed for svr_target_list");
3141 			return (WALK_ERR);
3142 		}
3143 		mdb_dec_indent(2);
3144 	}
3145 
3146 	mdb_dec_indent(4);
3147 
3148 	return (WALK_NEXT);
3149 }
3150 
3151 static int
3152 iscsi_isns_servers(iscsi_dcmd_ctrl_t *idc)
3153 {
3154 	uintptr_t	iscsit_global_addr;
3155 	uintptr_t	list_addr;
3156 	GElf_Sym	sym;
3157 
3158 	if (mdb_lookup_by_name("iscsit_global", &sym) == -1) {
3159 		mdb_warn("failed to find symbol 'iscsit_global'");
3160 		return (DCMD_ERR);
3161 	}
3162 
3163 	iscsit_global_addr = (uintptr_t)sym.st_value;
3164 	idc->idc_header = 1;
3165 	list_addr = iscsit_global_addr +
3166 	    offsetof(iscsit_global_t, global_isns_cfg.isns_svrs);
3167 
3168 	if (mdb_pwalk("list", iscsi_isns_servers_cb, idc, list_addr) == -1) {
3169 		mdb_warn("list walk failed for iSNS servers");
3170 		return (DCMD_ERR);
3171 	}
3172 
3173 	return (0);
3174 }
3175 
3176 /* ARGSUSED */
3177 static int
3178 iscsi_isns(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
3179 {
3180 	iscsi_dcmd_ctrl_t idc;
3181 	int portals = 0, esi = 0, targets = 0, verbose = 0, servers = 0;
3182 	int rc_audit = 0;
3183 
3184 	if (flags & DCMD_ADDRSPEC) {
3185 		mdb_warn("iscsi_isns is only a global dcmd.");
3186 		return (DCMD_ERR);
3187 	}
3188 
3189 	bzero(&idc, sizeof (idc));
3190 	if (mdb_getopts(argc, argv,
3191 	    'e', MDB_OPT_SETBITS, TRUE, &esi,
3192 	    'p', MDB_OPT_SETBITS, TRUE, &portals,
3193 	    's', MDB_OPT_SETBITS, TRUE, &servers,
3194 	    't', MDB_OPT_SETBITS, TRUE, &targets,
3195 	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
3196 	    'R', MDB_OPT_SETBITS, TRUE, &rc_audit,
3197 	    NULL) != argc)
3198 		return (DCMD_USAGE);
3199 
3200 	if ((esi + portals + targets + servers) > 1) {
3201 		mdb_printf("Only one of e, p, s, and t must be provided");
3202 		return (DCMD_ERR);
3203 	}
3204 
3205 	if ((esi | portals | targets | servers) == 0) {
3206 		mdb_printf("Exactly one of e, p, s, or t must be provided");
3207 		return (DCMD_ERR);
3208 	}
3209 
3210 	idc.idc_verbose = verbose;
3211 	idc.u.child.idc_rc_audit = rc_audit;
3212 
3213 	if (esi) {
3214 		return (iscsi_isns_esi(&idc));
3215 	}
3216 
3217 	if (portals) {
3218 		return (iscsi_isns_portals(&idc));
3219 	}
3220 
3221 	if (servers) {
3222 		return (iscsi_isns_servers(&idc));
3223 	}
3224 
3225 	return (iscsi_isns_targets(&idc));
3226 }
3227 
3228 static int
3229 iscsi_ini_sess_walk_init(mdb_walk_state_t *wsp)
3230 {
3231 	if (wsp->walk_addr == NULL) {
3232 		mdb_warn("<iscsi_sess_t addr>::walk iscsi_ini_sess");
3233 		return (WALK_ERR);
3234 	}
3235 
3236 	wsp->walk_data = mdb_alloc(sizeof (iscsi_sess_t), UM_SLEEP|UM_GC);
3237 	if (!wsp->walk_data) {
3238 		mdb_warn("iscsi_ini_sess walk failed");
3239 		return (WALK_ERR);
3240 	}
3241 
3242 	return (WALK_NEXT);
3243 }
3244 
3245 static int
3246 iscsi_ini_sess_step(mdb_walk_state_t *wsp)
3247 {
3248 	int status;
3249 
3250 	if (wsp->walk_addr == NULL) {
3251 		return (WALK_DONE);
3252 	}
3253 
3254 	if (mdb_vread(wsp->walk_data, sizeof (iscsi_sess_t), wsp->walk_addr)
3255 	    != sizeof (iscsi_sess_t)) {
3256 		mdb_warn("failed to read iscsi_sess_t at %p", wsp->walk_addr);
3257 		return (WALK_DONE);
3258 	}
3259 
3260 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
3261 	    wsp->walk_cbdata);
3262 
3263 	wsp->walk_addr =
3264 	    (uintptr_t)(((iscsi_sess_t *)wsp->walk_data)->sess_next);
3265 
3266 	return (status);
3267 }
3268 
3269 static int
3270 iscsi_ini_conn_walk_init(mdb_walk_state_t *wsp)
3271 {
3272 	if (wsp->walk_addr == NULL) {
3273 		mdb_warn("<iscsi_conn_t addr>::walk iscsi_ini_conn");
3274 		return (WALK_DONE);
3275 	}
3276 
3277 	wsp->walk_data = mdb_alloc(sizeof (iscsi_conn_t), UM_SLEEP|UM_GC);
3278 	if (!wsp->walk_data) {
3279 		mdb_warn("iscsi_ini_conn walk failed");
3280 		return (WALK_ERR);
3281 	}
3282 
3283 	return (WALK_NEXT);
3284 }
3285 
3286 static int
3287 iscsi_ini_conn_step(mdb_walk_state_t *wsp)
3288 {
3289 	int status;
3290 
3291 	if (wsp->walk_addr == NULL) {
3292 		return (WALK_DONE);
3293 	}
3294 
3295 	if (mdb_vread(wsp->walk_data, sizeof (iscsi_conn_t), wsp->walk_addr)
3296 	    != sizeof (iscsi_conn_t)) {
3297 		mdb_warn("failed to read iscsi_conn_t at %p", wsp->walk_addr);
3298 		return (WALK_DONE);
3299 	}
3300 
3301 
3302 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
3303 	    wsp->walk_cbdata);
3304 
3305 	wsp->walk_addr =
3306 	    (uintptr_t)(((iscsi_conn_t *)wsp->walk_data)->conn_next);
3307 
3308 	return (status);
3309 }
3310 
3311 static int
3312 iscsi_ini_lun_walk_init(mdb_walk_state_t *wsp)
3313 {
3314 	if (wsp->walk_addr == NULL) {
3315 		mdb_warn("<iscsi_lun_t addr>::walk iscsi_ini_lun");
3316 		return (WALK_DONE);
3317 	}
3318 
3319 	wsp->walk_data = mdb_alloc(sizeof (iscsi_lun_t), UM_SLEEP|UM_GC);
3320 	if (!wsp->walk_data) {
3321 		return (WALK_ERR);
3322 	}
3323 
3324 	return (WALK_NEXT);
3325 }
3326 
3327 static int
3328 iscsi_ini_lun_step(mdb_walk_state_t *wsp)
3329 {
3330 	int status;
3331 
3332 	if (wsp->walk_addr == NULL) {
3333 		return (WALK_DONE);
3334 	}
3335 
3336 	if (mdb_vread(wsp->walk_data, sizeof (iscsi_lun_t), wsp->walk_addr)
3337 	    != sizeof (iscsi_lun_t)) {
3338 		mdb_warn("failed to read iscsi_lun_t at %p", wsp->walk_addr);
3339 		return (WALK_DONE);
3340 	}
3341 
3342 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
3343 	    wsp->walk_cbdata);
3344 
3345 	wsp->walk_addr =
3346 	    (uintptr_t)(((iscsi_lun_t *)wsp->walk_data)->lun_next);
3347 
3348 	return (status);
3349 }
3350 
3351 static int
3352 iscsi_ini_cmd_walk_init(mdb_walk_state_t *wsp)
3353 {
3354 	if (wsp->walk_addr == NULL) {
3355 		mdb_warn("<iscsi_cmd_t addr>::walk iscsi_ini_cmd");
3356 		return (WALK_DONE);
3357 	}
3358 
3359 	wsp->walk_data = mdb_alloc(sizeof (iscsi_cmd_t), UM_SLEEP|UM_GC);
3360 	if (!wsp->walk_data) {
3361 		return (WALK_ERR);
3362 	}
3363 
3364 	return (WALK_NEXT);
3365 }
3366 
3367 static int
3368 iscsi_ini_cmd_step(mdb_walk_state_t *wsp)
3369 {
3370 	int status;
3371 
3372 	if (wsp->walk_addr == NULL) {
3373 		return (WALK_DONE);
3374 	}
3375 
3376 	if (mdb_vread(wsp->walk_data, sizeof (iscsi_cmd_t), wsp->walk_addr)
3377 	    != sizeof (iscsi_cmd_t)) {
3378 		mdb_warn("failed to read iscsi_cmd_t at %p", wsp->walk_addr);
3379 		return (WALK_DONE);
3380 	}
3381 
3382 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
3383 	    wsp->walk_cbdata);
3384 
3385 	wsp->walk_addr =
3386 	    (uintptr_t)(((iscsi_cmd_t *)wsp->walk_data)->cmd_next);
3387 
3388 	return (status);
3389 }
3390 
3391 static int
3392 iscsi_ini_cmd_walk_cb(uintptr_t addr, const void *vcmd, void *vidc)
3393 {
3394 	const iscsi_cmd_t	*cmd = vcmd;
3395 	iscsi_dcmd_ctrl_t	*idc = vidc;
3396 	int			rc;
3397 
3398 	if (cmd == NULL) {
3399 		mdb_warn("list walk failed. Null cmd");
3400 		return (WALK_ERR);
3401 	}
3402 
3403 	rc = iscsi_print_ini_cmd(addr, cmd, idc);
3404 
3405 	return ((rc == DCMD_OK) ? WALK_NEXT : WALK_ERR);
3406 }
3407 
3408 static int
3409 iscsi_ini_hba_walk_init(mdb_walk_state_t *wsp)
3410 {
3411 	uintptr_t state_addr, array_addr;
3412 	int array_size;
3413 	struct i_ddi_soft_state *ss;
3414 	idm_hba_walk_info_t *hwi;
3415 
3416 
3417 	hwi = (idm_hba_walk_info_t *)mdb_zalloc(
3418 	    sizeof (idm_hba_walk_info_t), UM_SLEEP|UM_GC);
3419 
3420 	if (!hwi) {
3421 		mdb_warn("unable to allocate storage for iscsi_ini_hba walk");
3422 		return (WALK_ERR);
3423 	}
3424 
3425 	if (wsp->walk_addr != NULL) {
3426 		mdb_warn("iscsi_ini_hba only supports global walk");
3427 		return (WALK_ERR);
3428 	} else {
3429 
3430 		/*
3431 		 * Read in the array and setup the walk struct.
3432 		 */
3433 		if (mdb_readvar(&state_addr, "iscsi_state") == -1) {
3434 			mdb_warn("state variable iscsi_state not found.\n");
3435 			mdb_warn("Is the driver loaded ?\n");
3436 			return (WALK_ERR);
3437 		}
3438 
3439 		ss = (struct i_ddi_soft_state *)mdb_alloc(sizeof (*ss),
3440 		    UM_SLEEP|UM_GC);
3441 		if (mdb_vread(ss, sizeof (*ss), state_addr) != sizeof (*ss)) {
3442 			mdb_warn("Cannot read softstate struct "
3443 			    "(Invalid pointer?).\n");
3444 			return (WALK_ERR);
3445 		}
3446 
3447 		/* Where to get the data */
3448 		array_size = ss->n_items * (sizeof (void *));
3449 		array_addr = (uintptr_t)ss->array;
3450 
3451 		/* Where to put the data */
3452 		hwi->n_elements = ss->n_items;
3453 		hwi->array = mdb_alloc(array_size, UM_SLEEP|UM_GC);
3454 		if (!hwi->array) {
3455 			mdb_warn("list walk failed");
3456 			return (WALK_ERR);
3457 		}
3458 		if (mdb_vread(hwi->array, array_size, array_addr) !=
3459 		    array_size) {
3460 			mdb_warn("Corrupted softstate struct.\n");
3461 			return (WALK_ERR);
3462 		}
3463 		hwi->cur_element = 0;
3464 		wsp->walk_data =  hwi;
3465 	}
3466 
3467 	return (WALK_NEXT);
3468 }
3469 
3470 static int
3471 iscsi_ini_hba_step(mdb_walk_state_t *wsp)
3472 {
3473 	int status;
3474 	idm_hba_walk_info_t *hwi = (idm_hba_walk_info_t *)wsp->walk_data;
3475 
3476 	for (; hwi->cur_element < hwi->n_elements; hwi->cur_element++) {
3477 		if (hwi->array[hwi->cur_element] != NULL) {
3478 			break;
3479 		}
3480 	}
3481 	if (hwi->cur_element >= hwi->n_elements) {
3482 		return (WALK_DONE);
3483 	}
3484 
3485 	hwi->data = (iscsi_hba_t *)mdb_alloc(sizeof (iscsi_hba_t),
3486 	    UM_SLEEP|UM_GC);
3487 	if (mdb_vread(hwi->data, sizeof (iscsi_hba_t),
3488 	    (uintptr_t)hwi->array[hwi->cur_element]) != sizeof (iscsi_hba_t)) {
3489 		mdb_warn("failed to read iscsi_sess_t at %p", wsp->walk_addr);
3490 		return (WALK_DONE);
3491 	}
3492 
3493 
3494 	status = wsp->walk_callback((uintptr_t)hwi->array[hwi->cur_element],
3495 	    hwi->data, wsp->walk_cbdata);
3496 
3497 	/* Increment cur_element for next iteration */
3498 	hwi->cur_element++;
3499 
3500 	return (status);
3501 }
3502 
3503 /*
3504  * iscsi_inet_ntop -- Convert an IPv4 or IPv6 address in binary form into
3505  * printable form, and return a pointer to that string. Caller should
3506  * provide a buffer of correct length to store string into.
3507  * Note: this routine is kernel version of inet_ntop. It has similar
3508  * format as iscsi_inet_ntop() defined in rfc2553. But it does not do
3509  * error handling operations exactly as rfc2553 defines. This function
3510  * is used by kernel inet directory routines only for debugging.
3511  * This iscsi_inet_ntop() function, does not return NULL if third argument
3512  * is NULL. The reason is simple that we don't want kernel to panic
3513  * as the output of this function is directly fed to ip<n>dbg macro.
3514  * Instead it uses a local buffer for destination address for
3515  * those calls which purposely pass NULL ptr for the destination
3516  * buffer. This function is thread-safe when the caller passes a non-
3517  * null buffer with the third argument.
3518  */
3519 /* ARGSUSED */
3520 
3521 #define	OK_16PTR(p)	(!((uintptr_t)(p) & 0x1))
3522 #if defined(__x86)
3523 #define	OK_32PTR(p)	OK_16PTR(p)
3524 #else
3525 #define	OK_32PTR(p)	(!((uintptr_t)(p) & 0x3))
3526 #endif
3527 
3528 char *
3529 iscsi_inet_ntop(int af, const void *addr, char *buf, int addrlen)
3530 {
3531 	static char local_buf[PORTAL_STR_LEN];
3532 	static char *err_buf1 = "<badaddr>";
3533 	static char *err_buf2 = "<badfamily>";
3534 	in6_addr_t	*v6addr;
3535 	uchar_t		*v4addr;
3536 	char		*caddr;
3537 
3538 	/*
3539 	 * We don't allow thread unsafe iscsi_inet_ntop calls, they
3540 	 * must pass a non-null buffer pointer. For DEBUG mode
3541 	 * we use the ASSERT() and for non-debug kernel it will
3542 	 * silently allow it for now. Someday we should remove
3543 	 * the static buffer from this function.
3544 	 */
3545 
3546 	ASSERT(buf != NULL);
3547 	if (buf == NULL)
3548 		buf = local_buf;
3549 	buf[0] = '\0';
3550 
3551 	/* Let user know politely not to send NULL or unaligned addr */
3552 	if (addr == NULL || !(OK_32PTR(addr))) {
3553 		return (err_buf1);
3554 	}
3555 
3556 
3557 #define	UC(b)	(((int)b) & 0xff)
3558 	switch (af) {
3559 	case AF_INET:
3560 		ASSERT(addrlen >= INET_ADDRSTRLEN);
3561 		v4addr = (uchar_t *)addr;
3562 		(void) mdb_snprintf(buf, INET6_ADDRSTRLEN,
3563 		    "%03d.%03d.%03d.%03d",
3564 		    UC(v4addr[0]), UC(v4addr[1]), UC(v4addr[2]), UC(v4addr[3]));
3565 		return (buf);
3566 
3567 	case AF_INET6:
3568 		ASSERT(addrlen >= INET6_ADDRSTRLEN);
3569 		v6addr = (in6_addr_t *)addr;
3570 		if (IN6_IS_ADDR_V4MAPPED(v6addr)) {
3571 			caddr = (char *)addr;
3572 			(void) mdb_snprintf(buf, INET6_ADDRSTRLEN,
3573 			    "::ffff:%d.%d.%d.%d",
3574 			    UC(caddr[12]), UC(caddr[13]),
3575 			    UC(caddr[14]), UC(caddr[15]));
3576 		} else if (IN6_IS_ADDR_V4COMPAT(v6addr)) {
3577 			caddr = (char *)addr;
3578 			(void) mdb_snprintf(buf, INET6_ADDRSTRLEN,
3579 			    "::%d.%d.%d.%d",
3580 			    UC(caddr[12]), UC(caddr[13]), UC(caddr[14]),
3581 			    UC(caddr[15]));
3582 		} else if (IN6_IS_ADDR_UNSPECIFIED(v6addr)) {
3583 			(void) mdb_snprintf(buf, INET6_ADDRSTRLEN, "::");
3584 		} else {
3585 			convert2ascii(buf, v6addr);
3586 		}
3587 		return (buf);
3588 
3589 	default:
3590 		return (err_buf2);
3591 	}
3592 #undef UC
3593 }
3594 
3595 /*
3596  *
3597  * v6 formats supported
3598  * General format xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
3599  * The short hand notation :: is used for COMPAT addr
3600  * Other forms : fe80::xxxx:xxxx:xxxx:xxxx
3601  */
3602 static void
3603 convert2ascii(char *buf, const in6_addr_t *addr)
3604 {
3605 	int		hexdigits;
3606 	int		head_zero = 0;
3607 	int		tail_zero = 0;
3608 	/* tempbuf must be big enough to hold ffff:\0 */
3609 	char		tempbuf[6];
3610 	char		*ptr;
3611 	uint16_t	out_addr_component;
3612 	uint16_t	*addr_component;
3613 	size_t		len;
3614 	boolean_t	first = B_FALSE;
3615 	boolean_t	med_zero = B_FALSE;
3616 	boolean_t	end_zero = B_FALSE;
3617 
3618 	addr_component = (uint16_t *)addr;
3619 	ptr = buf;
3620 
3621 	/* First count if trailing zeroes higher in number */
3622 	for (hexdigits = 0; hexdigits < 8; hexdigits++) {
3623 		if (*addr_component == 0) {
3624 			if (hexdigits < 4)
3625 				head_zero++;
3626 			else
3627 				tail_zero++;
3628 		}
3629 		addr_component++;
3630 	}
3631 	addr_component = (uint16_t *)addr;
3632 	if (tail_zero > head_zero && (head_zero + tail_zero) != 7)
3633 		end_zero = B_TRUE;
3634 
3635 	for (hexdigits = 0; hexdigits < 8; hexdigits++) {
3636 
3637 		/* if entry is a 0 */
3638 
3639 		if (*addr_component == 0) {
3640 			if (!first && *(addr_component + 1) == 0) {
3641 				if (end_zero && (hexdigits < 4)) {
3642 					*ptr++ = '0';
3643 					*ptr++ = ':';
3644 				} else {
3645 					/*
3646 					 * address starts with 0s ..
3647 					 * stick in leading ':' of pair
3648 					 */
3649 					if (hexdigits == 0)
3650 						*ptr++ = ':';
3651 					/* add another */
3652 					*ptr++ = ':';
3653 					first = B_TRUE;
3654 					med_zero = B_TRUE;
3655 				}
3656 			} else if (first && med_zero) {
3657 				if (hexdigits == 7)
3658 					*ptr++ = ':';
3659 				addr_component++;
3660 				continue;
3661 			} else {
3662 				*ptr++ = '0';
3663 				*ptr++ = ':';
3664 			}
3665 			addr_component++;
3666 			continue;
3667 		}
3668 		if (med_zero)
3669 			med_zero = B_FALSE;
3670 
3671 		tempbuf[0] = '\0';
3672 		mdb_nhconvert(&out_addr_component, addr_component,
3673 		    sizeof (uint16_t));
3674 		(void) mdb_snprintf(tempbuf, 6, "%x:", out_addr_component);
3675 		len = strlen(tempbuf);
3676 		bcopy(tempbuf, ptr, len);
3677 		ptr = ptr + len;
3678 		addr_component++;
3679 	}
3680 	*--ptr = '\0';
3681 }
3682 
3683 /*
3684  * MDB module linkage information:
3685  *
3686  * We declare a list of structures describing our dcmds, a list of structures
3687  * describing our walkers and a function named _mdb_init to return a pointer
3688  * to our module information.
3689  */
3690 static const mdb_dcmd_t dcmds[] = {
3691 	{   "iscsi_tgt", "[-agscptbSRv]",
3692 	    "iSCSI target information", iscsi_tgt },
3693 	{   "iscsi_tpgt", "[-R]",
3694 	    "iSCSI target portal group tag information", iscsi_tpgt },
3695 	{   "iscsi_tpg", "[-R]",
3696 	    "iSCSI target portal group information", iscsi_tpg },
3697 	{   "iscsi_sess", "[-ablmtvcSRIT]",
3698 	    "iSCSI session information", iscsi_sess },
3699 	{   "iscsi_conn", "[-abmtvSRIT]",
3700 	    "iSCSI connection information", iscsi_conn },
3701 	{   "iscsi_task", "[-bSRv]",
3702 	    "iSCSI task information", iscsi_task },
3703 	{   "iscsi_refcnt", "",
3704 	    "print audit informtion for idm_refcnt_t", iscsi_refcnt },
3705 	{   "iscsi_states", "",
3706 	    "dump events and state transitions recorded in an\t"
3707 	    "\t\tidm_sm_audit_t structure", iscsi_states },
3708 	{   "iscsi_isns", "[-epstvR]",
3709 	    "print iscsit iSNS information", iscsi_isns, iscsi_isns_help },
3710 	{   "iscsi_svc", "[-vR]",
3711 	    "iSCSI service information", iscsi_svc },
3712 	{   "iscsi_portal", "[-R]",
3713 	    "iSCSI portal information", iscsi_portal },
3714 	{   "iscsi_cmd", "[-S]",
3715 	    "iSCSI command information (initiator only)", iscsi_cmd },
3716 	{ NULL }
3717 };
3718 
3719 /*
3720  * Basic walkers for the initiator linked lists
3721  */
3722 static const mdb_walker_t walkers[] = {
3723 	{ "iscsi_ini_hba", "global walk of the initiator iscsi_hba_t "
3724 	    "list", iscsi_ini_hba_walk_init, iscsi_ini_hba_step, NULL},
3725 	{ "iscsi_ini_sess", "walk list of initiator iscsi_sess_t structures",
3726 	    iscsi_ini_sess_walk_init, iscsi_ini_sess_step, NULL },
3727 	{ "iscsi_ini_conn", "walk list of initiator iscsi_conn_t structures",
3728 	    iscsi_ini_conn_walk_init, iscsi_ini_conn_step, NULL },
3729 	{ "iscsi_ini_lun", "walk list of initiator iscsi_lun_t structures",
3730 	    iscsi_ini_lun_walk_init, iscsi_ini_lun_step, NULL },
3731 	{ "iscsi_ini_cmd", "walk list of initiator iscsi_cmd_t structures",
3732 	    iscsi_ini_cmd_walk_init, iscsi_ini_cmd_step, NULL },
3733 	{ NULL }
3734 };
3735 
3736 static const mdb_modinfo_t modinfo = {
3737 	MDB_API_VERSION, dcmds, walkers
3738 };
3739 
3740 const mdb_modinfo_t *
3741 _mdb_init(void)
3742 {
3743 	return (&modinfo);
3744 }
3745