1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * 25 * Copyright (c) 2018, Joyent, Inc. 26 */ 27 28 29 #include <sys/mdb_modapi.h> 30 #include <sys/mutex.h> 31 #include <sys/modctl.h> 32 #include <sys/scsi/scsi.h> 33 #include <sys/sunndi.h> 34 #include <sys/fibre-channel/fc.h> 35 #include <sys/fibre-channel/ulp/fcpvar.h> 36 37 static struct fcp_port port; 38 static struct fcp_tgt tgt; 39 static struct fcp_lun lun; 40 static uint32_t tgt_hash_index; 41 42 43 /* 44 * Leadville fcp walker/dcmd code 45 */ 46 47 static int 48 fcp_walk_i(mdb_walk_state_t *wsp) 49 { 50 if (wsp->walk_addr == 0 && 51 mdb_readvar(&wsp->walk_addr, "fcp_port_head") == -1) { 52 mdb_warn("failed to read 'fcp_port_head'"); 53 return (WALK_ERR); 54 } 55 56 wsp->walk_data = mdb_alloc(sizeof (struct fcp_port), UM_SLEEP); 57 return (WALK_NEXT); 58 } 59 60 static int 61 fcp_walk_s(mdb_walk_state_t *wsp) 62 { 63 int status; 64 65 if (wsp->walk_addr == 0) 66 return (WALK_DONE); 67 68 if (mdb_vread(wsp->walk_data, sizeof (struct fcp_port), 69 wsp->walk_addr) == -1) { 70 mdb_warn("failed to read fcp_port at %p", wsp->walk_addr); 71 return (WALK_DONE); 72 } 73 74 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 75 wsp->walk_cbdata); 76 77 wsp->walk_addr = 78 (uintptr_t)(((struct fcp_port *)wsp->walk_data)->port_next); 79 80 return (status); 81 } 82 83 /* 84 * The walker's fini function is invoked at the end of each walk. 85 */ 86 static void 87 fcp_walk_f(mdb_walk_state_t *wsp) 88 { 89 mdb_free(wsp->walk_data, sizeof (struct fcp_port)); 90 } 91 92 93 static int 94 fcp(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 95 { 96 struct fcp_port pinfo; 97 98 if (argc != 0) { 99 return (DCMD_USAGE); 100 } 101 102 if (!(flags & DCMD_ADDRSPEC)) { 103 if (mdb_walk_dcmd("fcp", "fcp", 104 argc, argv) == -1) { 105 mdb_warn("failed to walk 'fcp_port_head'"); 106 return (DCMD_ERR); 107 } 108 return (DCMD_OK); 109 } 110 111 mdb_printf("FCP structure at %p\n", addr); 112 113 /* 114 * For each port, we just need to read the fc_fca_port_t struct, read 115 * the port_handle 116 */ 117 if (mdb_vread(&pinfo, sizeof (struct fcp_port), addr) != 118 sizeof (struct fcp_port)) { 119 mdb_warn("failed to read fcp_port at %p", addr); 120 return (DCMD_OK); 121 } 122 123 mdb_printf(" mutex : 0x%-08x\n", pinfo.port_mutex); 124 mdb_printf(" ipkt_list : 0x%p\n", pinfo.port_ipkt_list); 125 mdb_printf(" state : 0x%-08x\n", pinfo.port_state); 126 mdb_printf(" phys_state : 0x%-08x\n", pinfo.port_phys_state); 127 mdb_printf(" top : %u\n", pinfo.port_topology); 128 mdb_printf(" sid : 0x%-06x\n", pinfo.port_id); 129 mdb_printf(" reset_list : 0x%p\n", pinfo.port_reset_list); 130 mdb_printf(" link_cnt : %u\n", pinfo.port_link_cnt); 131 mdb_printf(" deadline : %d\n", pinfo.port_deadline); 132 mdb_printf(" port wwn : " 133 "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", 134 pinfo.port_pwwn.raw_wwn[0], pinfo.port_pwwn.raw_wwn[1], 135 pinfo.port_pwwn.raw_wwn[2], pinfo.port_pwwn.raw_wwn[3], 136 pinfo.port_pwwn.raw_wwn[4], pinfo.port_pwwn.raw_wwn[5], 137 pinfo.port_pwwn.raw_wwn[6], pinfo.port_pwwn.raw_wwn[7]); 138 mdb_printf(" node wwn : " 139 "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", 140 pinfo.port_nwwn.raw_wwn[0], pinfo.port_nwwn.raw_wwn[1], 141 pinfo.port_nwwn.raw_wwn[2], pinfo.port_nwwn.raw_wwn[3], 142 pinfo.port_nwwn.raw_wwn[4], pinfo.port_nwwn.raw_wwn[5], 143 pinfo.port_nwwn.raw_wwn[6], pinfo.port_nwwn.raw_wwn[7]); 144 mdb_printf(" handle : 0x%p\n", pinfo.port_fp_handle); 145 mdb_printf(" cmd_mutex : 0x%-08x\n", pinfo.port_pkt_mutex); 146 mdb_printf(" ncmds : %u\n", pinfo.port_npkts); 147 mdb_printf(" pkt_head : 0x%p\n", pinfo.port_pkt_head); 148 mdb_printf(" pkt_tail : 0x%p\n", pinfo.port_pkt_tail); 149 mdb_printf(" ipkt_cnt : %d\n", pinfo.port_ipkt_cnt); 150 mdb_printf(" instance : %u\n", pinfo.port_instance); 151 mdb_printf(" max_exch : %u\n", pinfo.port_max_exch); 152 mdb_printf(" cmds_aborted : 0x%-08x\n", 153 pinfo.port_reset_action); 154 mdb_printf(" cmds_dma_flags : 0x%-08x\n", 155 pinfo.port_cmds_dma_flags); 156 mdb_printf(" fcp_dma : 0x%-08x\n", pinfo.port_fcp_dma); 157 mdb_printf(" priv_pkt_len : %u\n", pinfo.port_priv_pkt_len); 158 mdb_printf(" data_dma_attr : 0x%-08x\n", 159 pinfo.port_data_dma_attr); 160 mdb_printf(" cmd_dma_attr : 0x%-08x\n", 161 pinfo.port_cmd_dma_attr); 162 mdb_printf(" resp_dma_attr : 0x%-08x\n", 163 pinfo.port_resp_dma_attr); 164 mdb_printf(" dma_acc_attr : 0x%-08x\n", 165 pinfo.port_dma_acc_attr); 166 mdb_printf(" tran : 0x%p\n", pinfo.port_tran); 167 mdb_printf(" dip : 0x%p\n", pinfo.port_dip); 168 mdb_printf(" reset_notify_listf: 0x%p\n", 169 pinfo.port_reset_notify_listf); 170 mdb_printf(" event_defs : 0x%p\n", pinfo.port_ndi_event_defs); 171 mdb_printf(" event_hdl : 0x%p\n", pinfo.port_ndi_event_hdl); 172 mdb_printf(" events : 0x%p\n", pinfo.port_ndi_events); 173 mdb_printf(" tgt_hash_table : 0x%p\n", pinfo.port_tgt_hash_table); 174 mdb_printf(" mpxio : %d\n", pinfo.port_mpxio); 175 176 mdb_printf("\n"); 177 178 return (DCMD_OK); 179 } 180 181 182 /* 183 * Leadville cmds walker/dcmd code 184 */ 185 186 static int 187 cmds_walk_i(mdb_walk_state_t *wsp) 188 { 189 if (wsp->walk_addr == 0) { 190 mdb_warn("Can not perform global walk"); 191 return (WALK_ERR); 192 } 193 194 /* 195 * Input should be a fcp_lun, so read it to get the fcp_pkt 196 * lists's head 197 */ 198 199 if (mdb_vread(&lun, sizeof (struct fcp_lun), wsp->walk_addr) != 200 sizeof (struct fcp_lun)) { 201 mdb_warn("Unable to read in the fcp_lun structure address\n"); 202 return (WALK_ERR); 203 } 204 205 wsp->walk_addr = (uintptr_t)(lun.lun_pkt_head); 206 wsp->walk_data = mdb_alloc(sizeof (struct fcp_pkt), UM_SLEEP); 207 208 return (WALK_NEXT); 209 } 210 211 static int 212 cmds_walk_s(mdb_walk_state_t *wsp) 213 { 214 int status; 215 216 if (wsp->walk_addr == 0) 217 return (WALK_DONE); 218 219 if (mdb_vread(wsp->walk_data, sizeof (struct fcp_pkt), 220 wsp->walk_addr) == -1) { 221 mdb_warn("failed to read fcp_pkt at %p", wsp->walk_addr); 222 return (WALK_DONE); 223 } 224 225 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 226 wsp->walk_cbdata); 227 228 wsp->walk_addr = 229 (uintptr_t)(((struct fcp_pkt *)wsp->walk_data)->cmd_forw); 230 231 return (status); 232 } 233 234 /* 235 * The walker's fini function is invoked at the end of each walk. 236 */ 237 static void 238 cmds_walk_f(mdb_walk_state_t *wsp) 239 { 240 mdb_free(wsp->walk_data, sizeof (struct fcp_pkt)); 241 } 242 243 244 /* 245 * Leadville luns walker/dcmd code 246 */ 247 248 static int 249 luns_walk_i(mdb_walk_state_t *wsp) 250 { 251 if (wsp->walk_addr == 0) { 252 mdb_warn("Can not perform global walk"); 253 return (WALK_ERR); 254 } 255 256 /* 257 * Input should be a fcp_tgt, so read it to get the fcp_lun 258 * lists's head 259 */ 260 261 if (mdb_vread(&tgt, sizeof (struct fcp_tgt), wsp->walk_addr) != 262 sizeof (struct fcp_tgt)) { 263 mdb_warn("Unable to read in the fcp_tgt structure address\n"); 264 return (WALK_ERR); 265 } 266 267 wsp->walk_addr = (uintptr_t)(tgt.tgt_lun); 268 wsp->walk_data = mdb_alloc(sizeof (struct fcp_lun), UM_SLEEP); 269 270 return (WALK_NEXT); 271 } 272 273 static int 274 luns_walk_s(mdb_walk_state_t *wsp) 275 { 276 int status; 277 278 if (wsp->walk_addr == 0) 279 return (WALK_DONE); 280 281 if (mdb_vread(wsp->walk_data, sizeof (struct fcp_lun), 282 wsp->walk_addr) == -1) { 283 mdb_warn("failed to read fcp_pkt at %p", wsp->walk_addr); 284 return (WALK_DONE); 285 } 286 287 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 288 wsp->walk_cbdata); 289 290 wsp->walk_addr = 291 (uintptr_t)(((struct fcp_lun *)wsp->walk_data)->lun_next); 292 293 return (status); 294 } 295 296 /* 297 * The walker's fini function is invoked at the end of each walk. 298 */ 299 static void 300 luns_walk_f(mdb_walk_state_t *wsp) 301 { 302 mdb_free(wsp->walk_data, sizeof (struct fcp_lun)); 303 } 304 305 306 /* 307 * Leadville targets walker/dcmd code 308 */ 309 310 static int 311 targets_walk_i(mdb_walk_state_t *wsp) 312 { 313 if (wsp->walk_addr == 0) { 314 mdb_warn("Can not perform global walk\n"); 315 return (WALK_ERR); 316 } 317 318 /* 319 * Input should be a fcp_port, so read it to get the port_tgt 320 * table's head 321 */ 322 323 if (mdb_vread(&port, sizeof (struct fcp_port), wsp->walk_addr) != 324 sizeof (struct fcp_port)) { 325 mdb_warn("Unable to read in the port structure address\n"); 326 return (WALK_ERR); 327 } 328 329 tgt_hash_index = 0; 330 331 while (tgt_hash_index < FCP_NUM_HASH && 332 port.port_tgt_hash_table[tgt_hash_index] == NULL) { 333 tgt_hash_index++; 334 } 335 336 wsp->walk_addr = (uintptr_t)(port.port_tgt_hash_table[tgt_hash_index]); 337 338 wsp->walk_data = mdb_alloc(sizeof (struct fcp_tgt), UM_SLEEP); 339 340 return (WALK_NEXT); 341 } 342 343 static int 344 targets_walk_s(mdb_walk_state_t *wsp) 345 { 346 int status; 347 348 if ((wsp->walk_addr == 0) && 349 (tgt_hash_index >= (FCP_NUM_HASH - 1))) { 350 return (WALK_DONE); 351 } 352 353 if (mdb_vread(wsp->walk_data, sizeof (struct fcp_tgt), 354 wsp->walk_addr) == -1) { 355 mdb_warn("failed to read fcp_tgt at %p", wsp->walk_addr); 356 return (WALK_DONE); 357 } 358 359 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 360 wsp->walk_cbdata); 361 362 wsp->walk_addr = 363 (uintptr_t)(((struct fcp_tgt *)wsp->walk_data)->tgt_next); 364 365 if (wsp->walk_addr == 0) { 366 /* 367 * locate the next hash list 368 */ 369 370 tgt_hash_index++; 371 372 while (tgt_hash_index < FCP_NUM_HASH && 373 port.port_tgt_hash_table[tgt_hash_index] == NULL) 374 tgt_hash_index++; 375 376 if (tgt_hash_index == FCP_NUM_HASH) { 377 /* You're done */ 378 return (status); 379 } 380 381 wsp->walk_addr = 382 (uintptr_t)(port.port_tgt_hash_table[tgt_hash_index]); 383 } 384 385 return (status); 386 } 387 388 /* 389 * The walker's fini function is invoked at the end of each walk. 390 */ 391 static void 392 targets_walk_f(mdb_walk_state_t *wsp) 393 { 394 mdb_free(wsp->walk_data, sizeof (struct fcp_tgt)); 395 } 396 397 398 /* 399 * Leadville fcp_ipkt walker/dcmd code 400 */ 401 402 static int 403 ipkt_walk_i(mdb_walk_state_t *wsp) 404 { 405 if (wsp->walk_addr == 0) { 406 mdb_warn("The address of a fcp_port" 407 " structure must be given\n"); 408 return (WALK_ERR); 409 } 410 411 /* 412 * Input should be a fcp_port, so read it to get the ipkt 413 * list's head 414 */ 415 416 if (mdb_vread(&port, sizeof (struct fcp_port), wsp->walk_addr) != 417 sizeof (struct fcp_port)) { 418 mdb_warn("Failed to read in the fcp_port" 419 " at 0x%p\n", wsp->walk_addr); 420 return (WALK_ERR); 421 } 422 423 wsp->walk_addr = (uintptr_t)(port.port_ipkt_list); 424 wsp->walk_data = mdb_alloc(sizeof (struct fcp_ipkt), UM_SLEEP); 425 426 return (WALK_NEXT); 427 } 428 429 static int 430 ipkt_walk_s(mdb_walk_state_t *wsp) 431 { 432 int status; 433 434 if (wsp->walk_addr == 0) 435 return (WALK_DONE); 436 437 if (mdb_vread(wsp->walk_data, sizeof (struct fcp_ipkt), 438 wsp->walk_addr) == -1) { 439 mdb_warn("Failed to read in the fcp_ipkt" 440 " at 0x%p\n", wsp->walk_addr); 441 return (WALK_DONE); 442 } 443 444 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 445 wsp->walk_cbdata); 446 447 wsp->walk_addr = 448 (uintptr_t)(((struct fcp_ipkt *)wsp->walk_data)->ipkt_next); 449 450 return (status); 451 } 452 453 /* 454 * The walker's fini function is invoked at the end of each walk. 455 */ 456 static void 457 ipkt_walk_f(mdb_walk_state_t *wsp) 458 { 459 mdb_free(wsp->walk_data, sizeof (struct fcp_ipkt)); 460 } 461 462 /* 463 * Leadville fcp_pkt walker/dcmd code 464 */ 465 466 static int 467 pkt_walk_i(mdb_walk_state_t *wsp) 468 { 469 if (wsp->walk_addr == 0) { 470 mdb_warn("The address of a fcp_port" 471 " structure must be given\n"); 472 return (WALK_ERR); 473 } 474 475 /* 476 * Input should be an fcp_port, so read it to get the pkt 477 * list's head 478 */ 479 480 if (mdb_vread(&port, sizeof (struct fcp_port), wsp->walk_addr) != 481 sizeof (struct fcp_port)) { 482 mdb_warn("Failed to read in the fcp_port" 483 " at 0x%p\n", wsp->walk_addr); 484 return (WALK_ERR); 485 } 486 487 wsp->walk_addr = (uintptr_t)(port.port_pkt_head); 488 wsp->walk_data = mdb_alloc(sizeof (struct fcp_pkt), UM_SLEEP); 489 490 return (WALK_NEXT); 491 } 492 493 static int 494 pkt_walk_s(mdb_walk_state_t *wsp) 495 { 496 int status; 497 498 if (wsp->walk_addr == 0) 499 return (WALK_DONE); 500 501 if (mdb_vread(wsp->walk_data, sizeof (struct fcp_pkt), 502 wsp->walk_addr) == -1) { 503 mdb_warn("Failed to read in the fcp_pkt" 504 " at 0x%p\n", wsp->walk_addr); 505 return (WALK_DONE); 506 } 507 508 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 509 wsp->walk_cbdata); 510 511 wsp->walk_addr = 512 (uintptr_t)(((struct fcp_pkt *)wsp->walk_data)->cmd_next); 513 514 return (status); 515 } 516 517 /* 518 * The walker's fini function is invoked at the end of each walk. 519 */ 520 static void 521 pkt_walk_f(mdb_walk_state_t *wsp) 522 { 523 mdb_free(wsp->walk_data, sizeof (struct fcp_pkt)); 524 } 525 526 /* 527 * MDB module linkage information: 528 * 529 * We declare a list of structures describing our dcmds, a list of structures 530 * describing our walkers, and a function named _mdb_init to return a pointer 531 * to our module information. 532 */ 533 534 static const mdb_dcmd_t dcmds[] = { 535 { "fcp", NULL, "Leadville fcp instances", fcp }, 536 { NULL } 537 }; 538 539 static const mdb_walker_t walkers[] = { 540 { "fcp", "Walk list of Leadville fcp instances", 541 fcp_walk_i, fcp_walk_s, fcp_walk_f }, 542 { "cmds", "Walk list of SCSI commands in fcp's per-lun queue", 543 cmds_walk_i, cmds_walk_s, cmds_walk_f }, 544 { "luns", "Walk list of LUNs in an fcp target", 545 luns_walk_i, luns_walk_s, luns_walk_f }, 546 { "targets", "Walk list of fcp targets attached to the local port", 547 targets_walk_i, targets_walk_s, targets_walk_f }, 548 { "fcp_ipkt", "Walk list of internal packets queued on a local port", 549 ipkt_walk_i, ipkt_walk_s, ipkt_walk_f}, 550 { "fcp_pkt", "Walk list of packets queued on a local port", 551 pkt_walk_i, pkt_walk_s, pkt_walk_f}, 552 { NULL } 553 }; 554 555 static const mdb_modinfo_t modinfo = { 556 MDB_API_VERSION, dcmds, walkers 557 }; 558 559 const mdb_modinfo_t * 560 _mdb_init(void) 561 { 562 return (&modinfo); 563 } 564