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