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 IDM_TASK_SM_STRINGS 43 #define ISCSIT_TGT_SM_STRINGS 44 #define ISCSIT_SESS_SM_STRINGS 45 #define ISCSIT_LOGIN_SM_STRINGS 46 #include <sys/idm/idm.h> 47 #include <iscsit.h> 48 #include <iscsit_isns.h> 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 %-16s %-4s %-8s %-8s%</u>\n", 1398 "Tasks:", "State", "Ref", 1399 (conn_type == CONN_TYPE_TGT ? "TTT" : 1400 (conn_type == CONN_TYPE_INI ? "ITT" : 1401 "TT")), "Handle"); 1402 } 1403 mdb_printf("%?p %-16s %04x %08x %08x\n", addr, 1404 idm_ts_name[idt->idt_state], 1405 idt->idt_refcnt.ir_refcnt, 1406 idt->idt_tt, idt->idt_client_handle); 1407 } 1408 } 1409 idc->idc_header = 0; 1410 idc->idc_verbose = 0; 1411 1412 /* 1413 * Print states if requested 1414 */ 1415 #if 0 1416 if (states) { 1417 states_addr = addr + offsetof(idm_task_t, idt_state_audit); 1418 1419 (void) mdb_inc_indent(4); 1420 mdb_printf("State History:\n"); 1421 if (iscsi_sm_audit_impl(states_addr) != DCMD_OK) 1422 return (DCMD_ERR); 1423 1424 /* Don't print state history for child objects */ 1425 idc->u.child.idc_states = 0; 1426 (void) mdb_dec_indent(4); 1427 } 1428 #endif 1429 1430 /* 1431 * Print refcnt audit data if requested 1432 */ 1433 if (rc_audit) { 1434 (void) mdb_inc_indent(4); 1435 mdb_printf("Reference History:\n"); 1436 rc_addr = addr + 1437 offsetof(idm_task_t, idt_refcnt); 1438 if (iscsi_refcnt_impl(rc_addr) != DCMD_OK) 1439 return (DCMD_ERR); 1440 1441 /* Don't print audit data for child objects */ 1442 idc->u.child.idc_rc_audit = 0; 1443 (void) mdb_dec_indent(4); 1444 } 1445 1446 1447 /* Buffers are leaf objects */ 1448 if (idc->u.child.idc_buffer) { 1449 /* Walk in buffer list */ 1450 (void) mdb_inc_indent(2); 1451 mdb_printf("In buffers:\n"); 1452 idc->idc_header = 1; 1453 (void) mdb_inc_indent(2); 1454 list_addr = addr + offsetof(idm_task_t, idt_inbufv); 1455 if (mdb_pwalk("list", iscsi_buffer_walk_cb, idc, list_addr) == 1456 -1) { 1457 mdb_warn("list walk failed for task in buffers"); 1458 (void) mdb_dec_indent(4); 1459 return (DCMD_ERR); 1460 } 1461 (void) mdb_dec_indent(2); 1462 /* Walk out buffer list */ 1463 mdb_printf("Out buffers:\n"); 1464 idc->idc_header = 1; 1465 (void) mdb_inc_indent(2); 1466 list_addr = addr + offsetof(idm_task_t, idt_outbufv); 1467 if (mdb_pwalk("list", iscsi_buffer_walk_cb, idc, list_addr) == 1468 -1) { 1469 mdb_warn("list walk failed for task out buffers\n"); 1470 (void) mdb_dec_indent(2); 1471 return (DCMD_ERR); 1472 } 1473 (void) mdb_dec_indent(4); 1474 } 1475 1476 idc->idc_verbose = verbose; 1477 idc->u.child.idc_states = states; 1478 idc->u.child.idc_rc_audit = rc_audit; 1479 1480 return (DCMD_OK); 1481 } 1482 1483 static int 1484 iscsi_task_impl(uintptr_t addr, iscsi_dcmd_ctrl_t *idc) 1485 { 1486 idm_task_t idt; 1487 1488 /* 1489 * Read idm_conn_t 1490 */ 1491 if (mdb_vread(&idt, sizeof (idm_task_t), addr) != sizeof (idm_task_t)) { 1492 return (DCMD_ERR); 1493 } 1494 1495 return (iscsi_i_task_impl(&idt, addr, idc)); 1496 } 1497 1498 #define ISCSI_CDB_INDENT 16 1499 1500 static void 1501 iscsi_print_iscsit_task_data(idm_task_t *idt) 1502 { 1503 iscsit_task_t itask; 1504 boolean_t good_scsi_task = B_TRUE; 1505 scsi_task_t scsi_task; 1506 1507 if (mdb_vread(&itask, sizeof (iscsit_task_t), 1508 (uintptr_t)idt->idt_private) != sizeof (iscsit_task_t)) { 1509 mdb_printf("**Failed to read idt_private data\n"); 1510 return; 1511 } 1512 1513 if (mdb_vread(&scsi_task, sizeof (scsi_task_t), 1514 (uintptr_t)itask.it_stmf_task) != sizeof (scsi_task_t)) { 1515 good_scsi_task = B_FALSE; 1516 } 1517 1518 mdb_printf("%20s: %s(%d)\n", "State", 1519 idt->idt_state > TASK_MAX_STATE ? 1520 "UNKNOWN" : idm_ts_name[idt->idt_state], 1521 idt->idt_state); 1522 mdb_printf("%20s: %d/%d\n", "STMF abort/IDM aborted", 1523 itask.it_stmf_abort, itask.it_aborted); 1524 mdb_printf("%20s: %p/%p/%p%s\n", 1525 "iscsit/STMF/LU", idt->idt_private, 1526 itask.it_stmf_task, good_scsi_task ? scsi_task.task_lu_private : 0, 1527 good_scsi_task ? "" : "**"); 1528 if (good_scsi_task) { 1529 mdb_printf("%20s: %08x/%08x\n", "ITT/TTT", 1530 itask.it_itt, itask.it_ttt); 1531 mdb_printf("%20s: %08x\n", "CmdSN", 1532 itask.it_cmdsn); 1533 mdb_printf("%20s: %02x %02x %02x %02x %02x %02x %02x %02x\n", 1534 "LU number", 1535 scsi_task.task_lun_no[0], scsi_task.task_lun_no[1], 1536 scsi_task.task_lun_no[2], scsi_task.task_lun_no[3], 1537 scsi_task.task_lun_no[4], scsi_task.task_lun_no[5], 1538 scsi_task.task_lun_no[6], scsi_task.task_lun_no[7]); 1539 mdb_printf(" CDB (%d bytes):\n", 1540 scsi_task.task_cdb_length); 1541 (void) mdb_inc_indent(ISCSI_CDB_INDENT); 1542 if (mdb_dumpptr((uintptr_t)scsi_task.task_cdb, 1543 scsi_task.task_cdb_length, 1544 MDB_DUMP_RELATIVE | MDB_DUMP_TRIM | 1545 MDB_DUMP_GROUP(1), 1546 (mdb_dumpptr_cb_t)mdb_vread, NULL)) { 1547 mdb_printf("** Invalid CDB addr (%p)\n", 1548 scsi_task.task_cdb); 1549 } 1550 (void) mdb_dec_indent(ISCSI_CDB_INDENT); 1551 mdb_printf("%20s: %d/%d\n", "STMF cur/max bufs", 1552 scsi_task.task_cur_nbufs, 1553 scsi_task.task_max_nbufs); 1554 mdb_printf("%20s: 0x%08x/0x%08x/0x%08x\n", "Bytes Exp/Cmd/Done", 1555 scsi_task.task_expected_xfer_length, 1556 scsi_task.task_cmd_xfer_length, 1557 scsi_task.task_nbytes_transferred); 1558 mdb_printf("%20s: 0x%x/0x%x\n", "TX-ini start/done", 1559 idt->idt_tx_to_ini_start, 1560 idt->idt_tx_to_ini_done); 1561 mdb_printf("%20s: 0x%x/0x%x\n", "RX-ini start/done", 1562 idt->idt_rx_from_ini_start, 1563 idt->idt_rx_from_ini_done); 1564 } 1565 } 1566 1567 static int 1568 iscsi_buffer_impl(uintptr_t addr, iscsi_dcmd_ctrl_t *idc) 1569 { 1570 idm_buf_t idb; 1571 1572 /* 1573 * Read idm_buf_t 1574 */ 1575 if (mdb_vread(&idb, sizeof (idm_buf_t), addr) != sizeof (idm_buf_t)) { 1576 return (DCMD_ERR); 1577 } 1578 1579 1580 if (idc->idc_header) { 1581 mdb_printf("%<u>%-?s %?s/%-8s %8s %8s %8s%</u>\n", 1582 "idm_buf_t", "Mem Rgn", "Length", 1583 "Rel Off", "Xfer Len", "Exp. Off"); 1584 } 1585 idc->idc_header = 0; 1586 1587 /* Print buffer data */ 1588 mdb_printf("%?p %?p/%08x %8x %8x %08x\n", addr, 1589 idb.idb_buf, idb.idb_buflen, 1590 idb.idb_bufoffset, idb.idb_xfer_len, 1591 idb.idb_exp_offset); 1592 1593 1594 /* Buffers are leaf objects */ 1595 1596 return (DCMD_OK); 1597 } 1598 1599 static int 1600 iscsi_refcnt_impl(uintptr_t addr) 1601 { 1602 idm_refcnt_t refcnt; 1603 refcnt_audit_buf_t *anb; 1604 int ctr; 1605 1606 /* 1607 * Print refcnt info 1608 */ 1609 if (mdb_vread(&refcnt, sizeof (idm_refcnt_t), addr) != 1610 sizeof (idm_refcnt_t)) { 1611 return (DCMD_ERR); 1612 } 1613 1614 anb = &refcnt.ir_audit_buf; 1615 1616 ctr = anb->anb_max_index + 1; 1617 anb->anb_index--; 1618 anb->anb_index &= anb->anb_max_index; 1619 1620 while (ctr) { 1621 refcnt_audit_record_t *anr; 1622 1623 anr = anb->anb_records + anb->anb_index; 1624 1625 if (anr->anr_depth) { 1626 char c[MDB_SYM_NAMLEN]; 1627 GElf_Sym sym; 1628 int i; 1629 1630 mdb_printf("\nRefCnt: %u\t", anr->anr_refcnt); 1631 1632 for (i = 0; i < anr->anr_depth; i++) { 1633 if (mdb_lookup_by_addr(anr->anr_stack[i], 1634 MDB_SYM_FUZZY, c, sizeof (c), 1635 &sym) == -1) { 1636 continue; 1637 } 1638 mdb_printf("%s+0x%1x", c, 1639 anr->anr_stack[i] - 1640 (uintptr_t)sym.st_value); 1641 ++i; 1642 break; 1643 } 1644 1645 while (i < anr->anr_depth) { 1646 if (mdb_lookup_by_addr(anr->anr_stack[i], 1647 MDB_SYM_FUZZY, c, sizeof (c), 1648 &sym) == -1) { 1649 ++i; 1650 continue; 1651 } 1652 mdb_printf("\n\t\t%s+0x%1x", c, 1653 anr->anr_stack[i] - 1654 (uintptr_t)sym.st_value); 1655 ++i; 1656 } 1657 mdb_printf("\n"); 1658 } 1659 anb->anb_index--; 1660 anb->anb_index &= anb->anb_max_index; 1661 ctr--; 1662 } 1663 1664 return (DCMD_OK); 1665 } 1666 1667 static int 1668 iscsi_sm_audit_impl(uintptr_t addr) 1669 { 1670 sm_audit_buf_t audit_buf; 1671 int ctr; 1672 const char *event_name; 1673 const char *state_name; 1674 const char *new_state_name; 1675 char ts_string[40]; 1676 /* 1677 * Print refcnt info 1678 */ 1679 if (mdb_vread(&audit_buf, sizeof (sm_audit_buf_t), addr) != 1680 sizeof (sm_audit_buf_t)) { 1681 return (DCMD_ERR); 1682 } 1683 1684 ctr = audit_buf.sab_max_index + 1; 1685 audit_buf.sab_index++; 1686 audit_buf.sab_index &= audit_buf.sab_max_index; 1687 1688 while (ctr) { 1689 sm_audit_record_t *sar; 1690 1691 sar = audit_buf.sab_records + audit_buf.sab_index; 1692 1693 iscsi_format_timestamp(ts_string, 40, &sar->sar_timestamp); 1694 1695 switch (sar->sar_type) { 1696 case SAR_STATE_EVENT: 1697 switch (sar->sar_sm_type) { 1698 case SAS_IDM_CONN: 1699 state_name = 1700 iscsi_idm_conn_state(sar->sar_state); 1701 event_name = 1702 iscsi_idm_conn_event(sar->sar_event); 1703 break; 1704 case SAS_ISCSIT_TGT: 1705 state_name = 1706 iscsi_iscsit_tgt_state(sar->sar_state); 1707 event_name = 1708 iscsi_iscsit_tgt_event(sar->sar_event); 1709 break; 1710 case SAS_ISCSIT_SESS: 1711 state_name = 1712 iscsi_iscsit_sess_state(sar->sar_state); 1713 event_name = 1714 iscsi_iscsit_sess_event(sar->sar_event); 1715 break; 1716 case SAS_ISCSIT_LOGIN: 1717 state_name = 1718 iscsi_iscsit_login_state(sar->sar_state); 1719 event_name = 1720 iscsi_iscsit_login_event(sar->sar_event); 1721 break; 1722 default: 1723 state_name = event_name = "N/A"; 1724 break; 1725 } 1726 mdb_printf("%s|%s (%d)\n\t%9s %s (%d) %p\n", 1727 ts_string, state_name, sar->sar_state, 1728 "Event", event_name, 1729 sar->sar_event, sar->sar_event_info); 1730 1731 break; 1732 case SAR_STATE_CHANGE: 1733 switch (sar->sar_sm_type) { 1734 case SAS_IDM_CONN: 1735 state_name = 1736 iscsi_idm_conn_state(sar->sar_state); 1737 new_state_name = 1738 iscsi_idm_conn_state(sar->sar_new_state); 1739 break; 1740 case SAS_IDM_TASK: 1741 state_name = 1742 iscsi_idm_task_state(sar->sar_state); 1743 new_state_name = 1744 iscsi_idm_task_state(sar->sar_new_state); 1745 break; 1746 case SAS_ISCSIT_TGT: 1747 state_name = 1748 iscsi_iscsit_tgt_state(sar->sar_state); 1749 new_state_name = 1750 iscsi_iscsit_tgt_state(sar->sar_new_state); 1751 break; 1752 case SAS_ISCSIT_SESS: 1753 state_name = 1754 iscsi_iscsit_sess_state(sar->sar_state); 1755 new_state_name = 1756 iscsi_iscsit_sess_state(sar->sar_new_state); 1757 break; 1758 case SAS_ISCSIT_LOGIN: 1759 state_name = 1760 iscsi_iscsit_login_state(sar->sar_state); 1761 new_state_name = 1762 iscsi_iscsit_login_state( 1763 sar->sar_new_state); 1764 break; 1765 default: 1766 break; 1767 } 1768 mdb_printf("%s|%s (%d)\n\t%9s %s (%d)\n", 1769 ts_string, state_name, sar->sar_state, 1770 "New State", new_state_name, sar->sar_new_state); 1771 default: 1772 state_name = new_state_name = "N/A"; 1773 break; 1774 } 1775 1776 audit_buf.sab_index++; 1777 audit_buf.sab_index &= audit_buf.sab_max_index; 1778 ctr--; 1779 } 1780 1781 return (DCMD_OK); 1782 } 1783 1784 static const char * 1785 iscsi_idm_conn_event(int event) 1786 { 1787 const char *name = "N/A"; 1788 1789 event = (event > CE_MAX_EVENT) ? CE_MAX_EVENT : event; 1790 name = idm_ce_name[event]; 1791 1792 return (name); 1793 } 1794 1795 static const char * 1796 iscsi_iscsit_tgt_event(int event) 1797 { 1798 const char *name = "N/A"; 1799 1800 event = (event > TE_MAX_EVENT) ? TE_MAX_EVENT : event; 1801 name = iscsit_te_name[event]; 1802 1803 return (name); 1804 } 1805 1806 static const char * 1807 iscsi_iscsit_sess_event(int event) 1808 { 1809 const char *name = "N/A"; 1810 1811 event = (event > SE_MAX_EVENT) ? SE_MAX_EVENT : event; 1812 name = iscsit_se_name[event]; 1813 1814 return (name); 1815 } 1816 1817 static const char * 1818 iscsi_iscsit_login_event(int event) 1819 { 1820 const char *name = "N/A"; 1821 1822 event = (event > ILE_MAX_EVENT) ? ILE_MAX_EVENT : event; 1823 name = iscsit_ile_name[event]; 1824 1825 return (name); 1826 } 1827 1828 static const char * 1829 iscsi_idm_conn_state(int state) 1830 { 1831 const char *name = "N/A"; 1832 1833 state = (state > CS_MAX_STATE) ? CS_MAX_STATE : state; 1834 name = idm_cs_name[state]; 1835 1836 return (name); 1837 } 1838 1839 /*ARGSUSED*/ 1840 static const char * 1841 iscsi_idm_task_state(int state) 1842 { 1843 const char *name = "N/A"; 1844 return (name); 1845 } 1846 1847 static const char * 1848 iscsi_iscsit_tgt_state(int state) 1849 { 1850 const char *name = "N/A"; 1851 1852 state = (state > TS_MAX_STATE) ? TS_MAX_STATE : state; 1853 name = iscsit_ts_name[state]; 1854 1855 return (name); 1856 } 1857 1858 static const char * 1859 iscsi_iscsit_sess_state(int state) 1860 { 1861 const char *name = "N/A"; 1862 1863 state = (state > SS_MAX_STATE) ? SS_MAX_STATE : state; 1864 name = iscsit_ss_name[state]; 1865 1866 return (name); 1867 } 1868 1869 static const char * 1870 iscsi_iscsit_login_state(int state) 1871 { 1872 const char *name = "N/A"; 1873 1874 state = (state > ILS_MAX_STATE) ? ILS_MAX_STATE : state; 1875 name = iscsit_ils_name[state]; 1876 1877 return (name); 1878 } 1879 1880 1881 1882 /* 1883 * Retrieve connection type given a kernel address 1884 */ 1885 static idm_conn_type_t 1886 idm_conn_type(uintptr_t addr) 1887 { 1888 idm_conn_type_t result = 0; /* Unknown */ 1889 uintptr_t idm_conn_type_addr; 1890 1891 idm_conn_type_addr = addr + offsetof(idm_conn_t, ic_conn_type); 1892 (void) mdb_vread(&result, sizeof (result), idm_conn_type_addr); 1893 1894 return (result); 1895 } 1896 1897 /* 1898 * Convert a sockaddr to the string representation, suitable for 1899 * storing in an nvlist or printing out in a list. 1900 */ 1901 static int 1902 sa_to_str(struct sockaddr_storage *sa, char *buf) 1903 { 1904 char pbuf[7]; 1905 const char *bufp; 1906 struct sockaddr_in *sin; 1907 struct sockaddr_in6 *sin6; 1908 uint16_t port; 1909 1910 if (!sa || !buf) { 1911 return (EINVAL); 1912 } 1913 1914 buf[0] = '\0'; 1915 1916 if (sa->ss_family == AF_INET) { 1917 sin = (struct sockaddr_in *)sa; 1918 bufp = inet_ntop(AF_INET, 1919 (const void *)&(sin->sin_addr.s_addr), 1920 buf, PORTAL_STR_LEN); 1921 if (bufp == NULL) { 1922 return (-1); 1923 } 1924 mdb_nhconvert(&port, &sin->sin_port, sizeof (uint16_t)); 1925 } else if (sa->ss_family == AF_INET6) { 1926 strlcat(buf, "[", sizeof (buf)); 1927 sin6 = (struct sockaddr_in6 *)sa; 1928 bufp = inet_ntop(AF_INET6, 1929 (const void *)&sin6->sin6_addr.s6_addr, 1930 &buf[1], PORTAL_STR_LEN - 1); 1931 if (bufp == NULL) { 1932 return (-1); 1933 } 1934 strlcat(buf, "]", PORTAL_STR_LEN); 1935 mdb_nhconvert(&port, &sin->sin_port, sizeof (uint16_t)); 1936 } else { 1937 return (EINVAL); 1938 } 1939 1940 1941 mdb_snprintf(pbuf, sizeof (pbuf), ":%u", port); 1942 strlcat(buf, pbuf, PORTAL_STR_LEN); 1943 1944 return (0); 1945 } 1946 1947 1948 static void 1949 iscsi_format_timestamp(char *ts_str, int strlen, timespec_t *ts) 1950 { 1951 mdb_snprintf(ts_str, strlen, "%Y:%03d:%03d:%03d", ts->tv_sec, 1952 (ts->tv_nsec / 1000000) % 1000, (ts->tv_nsec / 1000) % 1000, 1953 ts->tv_nsec % 1000); 1954 } 1955 1956 /* 1957 * Help information for the iscsi_isns dcmd 1958 */ 1959 static void 1960 iscsi_isns_help(void) 1961 { 1962 mdb_printf("iscsi_isns:\n"); 1963 mdb_inc_indent(4); 1964 mdb_printf("-e: Print ESI information\n"); 1965 mdb_printf("-p: Print portal information\n"); 1966 mdb_printf("-s: Print iSNS server information\n"); 1967 mdb_printf("-t: Print target information\n"); 1968 mdb_printf("-v: Add verbosity to the other options' output\n"); 1969 mdb_dec_indent(4); 1970 } 1971 1972 /* ARGSUSED */ 1973 static int 1974 iscsi_isns_esi_cb(uintptr_t addr, const void *walker_data, void *data) 1975 { 1976 iscsi_dcmd_ctrl_t *idc = (iscsi_dcmd_ctrl_t *)data; 1977 isns_esi_tinfo_t tinfo; 1978 1979 if (mdb_vread(&tinfo, sizeof (isns_esi_tinfo_t), addr) != 1980 sizeof (isns_esi_tinfo_t)) { 1981 return (WALK_ERR); 1982 } 1983 1984 mdb_printf("ESI portal : 0x%p\n", tinfo.esi_portal); 1985 if (idc->idc_verbose) { 1986 mdb_inc_indent(4); 1987 iscsi_isns_portal_cb((uintptr_t)tinfo.esi_portal, NULL, data); 1988 mdb_dec_indent(4); 1989 } 1990 mdb_printf("ESI thread/thr did : 0x%p / %d\n", tinfo.esi_thread, 1991 tinfo.esi_thread_did); 1992 mdb_printf("ESI sonode : 0x%p\n", tinfo.esi_so); 1993 mdb_printf("ESI port : %d\n", tinfo.esi_port); 1994 mdb_printf("ESI thread running : %s\n", 1995 (tinfo.esi_thread_running) ? "Yes" : "No"); 1996 if (!tinfo.esi_thread_running) { 1997 mdb_printf("ESI thread failed : %s\n", 1998 (tinfo.esi_thread_failed) ? "Yes" : "No"); 1999 } 2000 mdb_printf("ESI registered : %s\n\n", 2001 (tinfo.esi_registered) ? "Yes" : "No"); 2002 2003 return (WALK_NEXT); 2004 } 2005 2006 static int 2007 iscsi_isns_esi(iscsi_dcmd_ctrl_t *idc) 2008 { 2009 GElf_Sym sym; 2010 uintptr_t esi_list; 2011 2012 if (mdb_lookup_by_name("esi_list", &sym) == -1) { 2013 mdb_warn("failed to find symbol 'esi_list'"); 2014 return (DCMD_ERR); 2015 } 2016 2017 esi_list = (uintptr_t)sym.st_value; 2018 idc->idc_header = 1; 2019 2020 if (mdb_pwalk("list", iscsi_isns_esi_cb, idc, esi_list) == -1) { 2021 mdb_warn("avl walk failed for esi_list"); 2022 return (DCMD_ERR); 2023 } 2024 2025 return (0); 2026 } 2027 2028 /* ARGSUSED */ 2029 static int 2030 iscsi_isns_portal_cb(uintptr_t addr, const void *walker_data, void *data) 2031 { 2032 iscsi_dcmd_ctrl_t *idc = (iscsi_dcmd_ctrl_t *)data; 2033 isns_portal_list_t portal; 2034 char portal_addr[PORTAL_STR_LEN]; 2035 struct sockaddr_storage *ss; 2036 2037 if (mdb_vread(&portal, sizeof (isns_portal_list_t), addr) != 2038 sizeof (isns_portal_list_t)) { 2039 return (WALK_ERR); 2040 } 2041 2042 ss = &portal.portal_addr; 2043 sa_to_str(ss, portal_addr); 2044 mdb_printf("Portal IP address "); 2045 2046 if (ss->ss_family == AF_INET) { 2047 mdb_printf("(v4): %s", portal_addr); 2048 } else { 2049 mdb_printf("(v6): %s", portal_addr); 2050 } 2051 2052 if (portal.portal_iscsit == NULL) { 2053 mdb_printf(" (Default portal)\n"); 2054 } else { 2055 mdb_printf("\n"); 2056 } 2057 2058 if ((portal.portal_iscsit != NULL) && (idc->idc_verbose)) { 2059 iscsi_portal_impl((uintptr_t)portal.portal_iscsit, idc); 2060 } 2061 2062 mdb_printf("Portal ESI info: 0x%p\n\n", portal.portal_esi); 2063 2064 return (WALK_NEXT); 2065 } 2066 2067 static int 2068 iscsi_isns_portals(iscsi_dcmd_ctrl_t *idc) 2069 { 2070 GElf_Sym sym; 2071 uintptr_t portal_list; 2072 2073 if (mdb_lookup_by_name("portal_list", &sym) == -1) { 2074 mdb_warn("failed to find symbol 'portal_list'"); 2075 return (DCMD_ERR); 2076 } 2077 2078 portal_list = (uintptr_t)sym.st_value; 2079 idc->idc_header = 1; 2080 2081 if (mdb_pwalk("list", iscsi_isns_portal_cb, idc, portal_list) == -1) { 2082 mdb_warn("avl walk failed for portal_list"); 2083 return (DCMD_ERR); 2084 } 2085 2086 return (0); 2087 } 2088 2089 /* ARGSUSED */ 2090 static int 2091 iscsi_isns_targets_cb(uintptr_t addr, const void *walker_data, void *data) 2092 { 2093 iscsi_dcmd_ctrl_t *idc = (iscsi_dcmd_ctrl_t *)data; 2094 isns_target_t itarget; 2095 int rc = 0; 2096 2097 if (mdb_vread(&itarget, sizeof (isns_target_t), addr) != 2098 sizeof (isns_target_t)) { 2099 return (WALK_ERR); 2100 } 2101 2102 idc->idc_header = 1; 2103 2104 mdb_printf("Target: %p\n", itarget.target); 2105 mdb_inc_indent(4); 2106 mdb_printf("Registered: %s\n", 2107 (itarget.target_registered) ? "Yes" : "No"); 2108 2109 rc = iscsi_tgt_impl((uintptr_t)itarget.target, idc); 2110 2111 mdb_dec_indent(4); 2112 2113 if (rc == DCMD_OK) { 2114 return (WALK_NEXT); 2115 } 2116 2117 return (WALK_ERR); 2118 } 2119 2120 static int 2121 iscsi_isns_targets(iscsi_dcmd_ctrl_t *idc) 2122 { 2123 GElf_Sym sym; 2124 uintptr_t isns_target_list; 2125 2126 if (mdb_lookup_by_name("isns_target_list", &sym) == -1) { 2127 mdb_warn("failed to find symbol 'isns_target_list'"); 2128 return (DCMD_ERR); 2129 } 2130 2131 isns_target_list = (uintptr_t)sym.st_value; 2132 idc->idc_header = 1; 2133 idc->u.child.idc_tgt = 1; 2134 2135 if (mdb_pwalk("avl", iscsi_isns_targets_cb, idc, 2136 isns_target_list) == -1) { 2137 mdb_warn("avl walk failed for isns_target_list"); 2138 return (DCMD_ERR); 2139 } 2140 2141 return (0); 2142 } 2143 2144 /* ARGSUSED */ 2145 static int 2146 iscsi_isns_servers_cb(uintptr_t addr, const void *walker_data, void *data) 2147 { 2148 GElf_Sym sym; 2149 iscsit_isns_svr_t server; 2150 char server_addr[PORTAL_STR_LEN]; 2151 struct sockaddr_storage *ss; 2152 clock_t lbolt; 2153 2154 if (mdb_vread(&server, sizeof (iscsit_isns_svr_t), addr) != 2155 sizeof (iscsit_isns_svr_t)) { 2156 return (WALK_ERR); 2157 } 2158 2159 if (mdb_lookup_by_name("lbolt", &sym) == -1) { 2160 mdb_warn("failed to find symbol 'lbolt'"); 2161 return (DCMD_ERR); 2162 } 2163 2164 if (mdb_vread(&lbolt, sizeof (clock_t), sym.st_value) != 2165 sizeof (clock_t)) { 2166 return (WALK_ERR); 2167 } 2168 2169 mdb_printf("iSNS server %p:\n", addr); 2170 mdb_inc_indent(4); 2171 ss = &server.svr_sa; 2172 sa_to_str(ss, server_addr); 2173 2174 mdb_printf("IP address "); 2175 if (ss->ss_family == AF_INET) { 2176 mdb_printf("(v4): %s\n", server_addr); 2177 } else { 2178 mdb_printf("(v6): %s\n", server_addr); 2179 } 2180 2181 mdb_printf("Last ESI message : %d seconds ago\n", 2182 ((lbolt - server.svr_last_msg) / 100)); 2183 mdb_printf("Client registered: %s\n", 2184 (server.svr_registered) ? "Yes" : "No"); 2185 mdb_dec_indent(4); 2186 2187 return (WALK_ERR); 2188 } 2189 2190 static int 2191 iscsi_isns_servers(iscsi_dcmd_ctrl_t *idc) 2192 { 2193 uintptr_t iscsit_global_addr; 2194 uintptr_t list_addr; 2195 GElf_Sym sym; 2196 2197 if (mdb_lookup_by_name("iscsit_global", &sym) == -1) { 2198 mdb_warn("failed to find symbol 'iscsit_global'"); 2199 return (DCMD_ERR); 2200 } 2201 2202 iscsit_global_addr = (uintptr_t)sym.st_value; 2203 idc->idc_header = 1; 2204 list_addr = iscsit_global_addr + 2205 offsetof(iscsit_global_t, global_isns_cfg.isns_svrs); 2206 2207 if (mdb_pwalk("list", iscsi_isns_servers_cb, idc, list_addr) == -1) { 2208 mdb_warn("list walk failed for iSNS servers"); 2209 return (DCMD_ERR); 2210 } 2211 2212 return (0); 2213 } 2214 2215 /* ARGSUSED */ 2216 static int 2217 iscsi_isns(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2218 { 2219 iscsi_dcmd_ctrl_t idc; 2220 int portals = 0, esi = 0, targets = 0, verbose = 0, servers = 0; 2221 2222 if (flags & DCMD_ADDRSPEC) { 2223 mdb_warn("iscsi_isns is only a global dcmd."); 2224 return (DCMD_ERR); 2225 } 2226 2227 bzero(&idc, sizeof (idc)); 2228 if (mdb_getopts(argc, argv, 2229 'e', MDB_OPT_SETBITS, TRUE, &esi, 2230 'p', MDB_OPT_SETBITS, TRUE, &portals, 2231 's', MDB_OPT_SETBITS, TRUE, &servers, 2232 't', MDB_OPT_SETBITS, TRUE, &targets, 2233 'v', MDB_OPT_SETBITS, TRUE, &verbose, 2234 NULL) != argc) 2235 return (DCMD_USAGE); 2236 2237 if ((esi + portals + targets + servers) > 1) { 2238 mdb_printf("Only one of e, p, s, and t must be provided"); 2239 return (DCMD_ERR); 2240 } 2241 2242 if ((esi | portals | targets | servers) == 0) { 2243 mdb_printf("Exactly one of e, p, s, or t must be provided"); 2244 return (DCMD_ERR); 2245 } 2246 2247 idc.idc_verbose = verbose; 2248 2249 if (esi) { 2250 return (iscsi_isns_esi(&idc)); 2251 } 2252 2253 if (portals) { 2254 return (iscsi_isns_portals(&idc)); 2255 } 2256 2257 if (servers) { 2258 return (iscsi_isns_servers(&idc)); 2259 } 2260 2261 return (iscsi_isns_targets(&idc)); 2262 } 2263 2264 /* 2265 * inet_ntop -- Convert an IPv4 or IPv6 address in binary form into 2266 * printable form, and return a pointer to that string. Caller should 2267 * provide a buffer of correct length to store string into. 2268 * Note: this routine is kernel version of inet_ntop. It has similar 2269 * format as inet_ntop() defined in rfc2553. But it does not do 2270 * error handling operations exactly as rfc2553 defines. This function 2271 * is used by kernel inet directory routines only for debugging. 2272 * This inet_ntop() function, does not return NULL if third argument 2273 * is NULL. The reason is simple that we don't want kernel to panic 2274 * as the output of this function is directly fed to ip<n>dbg macro. 2275 * Instead it uses a local buffer for destination address for 2276 * those calls which purposely pass NULL ptr for the destination 2277 * buffer. This function is thread-safe when the caller passes a non- 2278 * null buffer with the third argument. 2279 */ 2280 /* ARGSUSED */ 2281 2282 #define OK_16PTR(p) (!((uintptr_t)(p) & 0x1)) 2283 #if defined(__x86) 2284 #define OK_32PTR(p) OK_16PTR(p) 2285 #else 2286 #define OK_32PTR(p) (!((uintptr_t)(p) & 0x3)) 2287 #endif 2288 2289 char * 2290 inet_ntop(int af, const void *addr, char *buf, int addrlen) 2291 { 2292 static char local_buf[PORTAL_STR_LEN]; 2293 static char *err_buf1 = "<badaddr>"; 2294 static char *err_buf2 = "<badfamily>"; 2295 in6_addr_t *v6addr; 2296 uchar_t *v4addr; 2297 char *caddr; 2298 2299 /* 2300 * We don't allow thread unsafe inet_ntop calls, they 2301 * must pass a non-null buffer pointer. For DEBUG mode 2302 * we use the ASSERT() and for non-debug kernel it will 2303 * silently allow it for now. Someday we should remove 2304 * the static buffer from this function. 2305 */ 2306 2307 ASSERT(buf != NULL); 2308 if (buf == NULL) 2309 buf = local_buf; 2310 buf[0] = '\0'; 2311 2312 /* Let user know politely not to send NULL or unaligned addr */ 2313 if (addr == NULL || !(OK_32PTR(addr))) { 2314 return (err_buf1); 2315 } 2316 2317 2318 #define UC(b) (((int)b) & 0xff) 2319 switch (af) { 2320 case AF_INET: 2321 ASSERT(addrlen >= INET_ADDRSTRLEN); 2322 v4addr = (uchar_t *)addr; 2323 (void) mdb_snprintf(buf, INET6_ADDRSTRLEN, 2324 "%03d.%03d.%03d.%03d", 2325 UC(v4addr[0]), UC(v4addr[1]), UC(v4addr[2]), UC(v4addr[3])); 2326 return (buf); 2327 2328 case AF_INET6: 2329 ASSERT(addrlen >= INET6_ADDRSTRLEN); 2330 v6addr = (in6_addr_t *)addr; 2331 if (IN6_IS_ADDR_V4MAPPED(v6addr)) { 2332 caddr = (char *)addr; 2333 (void) mdb_snprintf(buf, INET6_ADDRSTRLEN, 2334 "::ffff:%d.%d.%d.%d", 2335 UC(caddr[12]), UC(caddr[13]), 2336 UC(caddr[14]), UC(caddr[15])); 2337 } else if (IN6_IS_ADDR_V4COMPAT(v6addr)) { 2338 caddr = (char *)addr; 2339 (void) mdb_snprintf(buf, INET6_ADDRSTRLEN, 2340 "::%d.%d.%d.%d", 2341 UC(caddr[12]), UC(caddr[13]), UC(caddr[14]), 2342 UC(caddr[15])); 2343 } else if (IN6_IS_ADDR_UNSPECIFIED(v6addr)) { 2344 (void) mdb_snprintf(buf, INET6_ADDRSTRLEN, "::"); 2345 } else { 2346 convert2ascii(buf, v6addr); 2347 } 2348 return (buf); 2349 2350 default: 2351 return (err_buf2); 2352 } 2353 #undef UC 2354 } 2355 2356 /* 2357 * 2358 * v6 formats supported 2359 * General format xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx 2360 * The short hand notation :: is used for COMPAT addr 2361 * Other forms : fe80::xxxx:xxxx:xxxx:xxxx 2362 */ 2363 static void 2364 convert2ascii(char *buf, const in6_addr_t *addr) 2365 { 2366 int hexdigits; 2367 int head_zero = 0; 2368 int tail_zero = 0; 2369 /* tempbuf must be big enough to hold ffff:\0 */ 2370 char tempbuf[6]; 2371 char *ptr; 2372 uint16_t out_addr_component; 2373 uint16_t *addr_component; 2374 size_t len; 2375 boolean_t first = B_FALSE; 2376 boolean_t med_zero = B_FALSE; 2377 boolean_t end_zero = B_FALSE; 2378 2379 addr_component = (uint16_t *)addr; 2380 ptr = buf; 2381 2382 /* First count if trailing zeroes higher in number */ 2383 for (hexdigits = 0; hexdigits < 8; hexdigits++) { 2384 if (*addr_component == 0) { 2385 if (hexdigits < 4) 2386 head_zero++; 2387 else 2388 tail_zero++; 2389 } 2390 addr_component++; 2391 } 2392 addr_component = (uint16_t *)addr; 2393 if (tail_zero > head_zero && (head_zero + tail_zero) != 7) 2394 end_zero = B_TRUE; 2395 2396 for (hexdigits = 0; hexdigits < 8; hexdigits++) { 2397 2398 /* if entry is a 0 */ 2399 2400 if (*addr_component == 0) { 2401 if (!first && *(addr_component + 1) == 0) { 2402 if (end_zero && (hexdigits < 4)) { 2403 *ptr++ = '0'; 2404 *ptr++ = ':'; 2405 } else { 2406 /* 2407 * address starts with 0s .. 2408 * stick in leading ':' of pair 2409 */ 2410 if (hexdigits == 0) 2411 *ptr++ = ':'; 2412 /* add another */ 2413 *ptr++ = ':'; 2414 first = B_TRUE; 2415 med_zero = B_TRUE; 2416 } 2417 } else if (first && med_zero) { 2418 if (hexdigits == 7) 2419 *ptr++ = ':'; 2420 addr_component++; 2421 continue; 2422 } else { 2423 *ptr++ = '0'; 2424 *ptr++ = ':'; 2425 } 2426 addr_component++; 2427 continue; 2428 } 2429 if (med_zero) 2430 med_zero = B_FALSE; 2431 2432 tempbuf[0] = '\0'; 2433 mdb_nhconvert(&out_addr_component, addr_component, 2434 sizeof (uint16_t)); 2435 (void) mdb_snprintf(tempbuf, 6, "%x:", out_addr_component); 2436 len = strlen(tempbuf); 2437 bcopy(tempbuf, ptr, len); 2438 ptr = ptr + len; 2439 addr_component++; 2440 } 2441 *--ptr = '\0'; 2442 } 2443 2444 2445 /* 2446 * MDB module linkage information: 2447 * 2448 * We declare a list of structures describing our dcmds, a list of structures 2449 * describing our walkers and a function named _mdb_init to return a pointer 2450 * to our module information. 2451 */ 2452 static const mdb_dcmd_t dcmds[] = { 2453 { "iscsi_tgt", "[-agsctbSRv]", 2454 "iSCSI target information", iscsi_tgt }, 2455 { "iscsi_tpg", "[-v]", 2456 "iSCSI target portal group information", iscsi_tpg }, 2457 { "iscsi_sess", "[-abtvcSRIT]", 2458 "iSCSI session information", iscsi_sess }, 2459 { "iscsi_conn", "[-abtvSRIT]", 2460 "iSCSI connection information", iscsi_conn }, 2461 { "iscsi_task", "[-bSRv]", 2462 "iSCSI task information", iscsi_task }, 2463 { "iscsi_refcnt", "", 2464 "Print audit informtion for idm_refcnt_t", iscsi_refcnt }, 2465 { "iscsi_states", "", 2466 "Dump events and state transitions recorded in an\t" 2467 "\t\tidm_sm_audit_t structure", iscsi_states }, 2468 { "iscsi_isns", "[-epstv]", 2469 "Print iscsit iSNS information", iscsi_isns, iscsi_isns_help }, 2470 { NULL } 2471 }; 2472 2473 /* 2474 * No walkers for now. Initiator might need some since it doesn't use list_t 2475 */ 2476 2477 static const mdb_modinfo_t modinfo = { 2478 MDB_API_VERSION, dcmds, NULL 2479 }; 2480 2481 const mdb_modinfo_t * 2482 _mdb_init(void) 2483 { 2484 return (&modinfo); 2485 } 2486