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