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