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