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