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