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