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