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