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 * FCP mdb module 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 == NULL && 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 == NULL) 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 == NULL) { 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 == NULL) 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 == NULL) { 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 == NULL) 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 == NULL) { 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 ((port.port_tgt_hash_table[tgt_hash_index] == NULL) && 332 (tgt_hash_index < FCP_NUM_HASH)) { 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 == NULL) && 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 == NULL) { 366 /* 367 * locate the next hash list 368 */ 369 370 tgt_hash_index++; 371 372 while ((port.port_tgt_hash_table[tgt_hash_index] == NULL) && 373 (tgt_hash_index < FCP_NUM_HASH)) { 374 tgt_hash_index++; 375 } 376 377 if (tgt_hash_index == FCP_NUM_HASH) { 378 /* You're done */ 379 return (status); 380 } 381 382 wsp->walk_addr = 383 (uintptr_t)(port.port_tgt_hash_table[tgt_hash_index]); 384 } 385 386 return (status); 387 } 388 389 /* 390 * The walker's fini function is invoked at the end of each walk. 391 */ 392 static void 393 targets_walk_f(mdb_walk_state_t *wsp) 394 { 395 mdb_free(wsp->walk_data, sizeof (struct fcp_tgt)); 396 } 397 398 399 /* 400 * Leadville fcp_ipkt walker/dcmd code 401 */ 402 403 static int 404 ipkt_walk_i(mdb_walk_state_t *wsp) 405 { 406 if (wsp->walk_addr == NULL) { 407 mdb_warn("The address of a fcp_port" 408 " structure must be given\n"); 409 return (WALK_ERR); 410 } 411 412 /* 413 * Input should be a fcp_port, so read it to get the ipkt 414 * list's head 415 */ 416 417 if (mdb_vread(&port, sizeof (struct fcp_port), wsp->walk_addr) != 418 sizeof (struct fcp_port)) { 419 mdb_warn("Failed to read in the fcp_port" 420 " at 0x%p\n", wsp->walk_addr); 421 return (WALK_ERR); 422 } 423 424 wsp->walk_addr = (uintptr_t)(port.port_ipkt_list); 425 wsp->walk_data = mdb_alloc(sizeof (struct fcp_ipkt), UM_SLEEP); 426 427 return (WALK_NEXT); 428 } 429 430 static int 431 ipkt_walk_s(mdb_walk_state_t *wsp) 432 { 433 int status; 434 435 if (wsp->walk_addr == NULL) 436 return (WALK_DONE); 437 438 if (mdb_vread(wsp->walk_data, sizeof (struct fcp_ipkt), 439 wsp->walk_addr) == -1) { 440 mdb_warn("Failed to read in the fcp_ipkt" 441 " at 0x%p\n", wsp->walk_addr); 442 return (WALK_DONE); 443 } 444 445 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 446 wsp->walk_cbdata); 447 448 wsp->walk_addr = 449 (uintptr_t)(((struct fcp_ipkt *)wsp->walk_data)->ipkt_next); 450 451 return (status); 452 } 453 454 /* 455 * The walker's fini function is invoked at the end of each walk. 456 */ 457 static void 458 ipkt_walk_f(mdb_walk_state_t *wsp) 459 { 460 mdb_free(wsp->walk_data, sizeof (struct fcp_ipkt)); 461 } 462 463 /* 464 * Leadville fcp_pkt walker/dcmd code 465 */ 466 467 static int 468 pkt_walk_i(mdb_walk_state_t *wsp) 469 { 470 if (wsp->walk_addr == NULL) { 471 mdb_warn("The address of a fcp_port" 472 " structure must be given\n"); 473 return (WALK_ERR); 474 } 475 476 /* 477 * Input should be an fcp_port, so read it to get the pkt 478 * list's head 479 */ 480 481 if (mdb_vread(&port, sizeof (struct fcp_port), wsp->walk_addr) != 482 sizeof (struct fcp_port)) { 483 mdb_warn("Failed to read in the fcp_port" 484 " at 0x%p\n", wsp->walk_addr); 485 return (WALK_ERR); 486 } 487 488 wsp->walk_addr = (uintptr_t)(port.port_pkt_head); 489 wsp->walk_data = mdb_alloc(sizeof (struct fcp_pkt), UM_SLEEP); 490 491 return (WALK_NEXT); 492 } 493 494 static int 495 pkt_walk_s(mdb_walk_state_t *wsp) 496 { 497 int status; 498 499 if (wsp->walk_addr == NULL) 500 return (WALK_DONE); 501 502 if (mdb_vread(wsp->walk_data, sizeof (struct fcp_pkt), 503 wsp->walk_addr) == -1) { 504 mdb_warn("Failed to read in the fcp_pkt" 505 " at 0x%p\n", wsp->walk_addr); 506 return (WALK_DONE); 507 } 508 509 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 510 wsp->walk_cbdata); 511 512 wsp->walk_addr = 513 (uintptr_t)(((struct fcp_pkt *)wsp->walk_data)->cmd_next); 514 515 return (status); 516 } 517 518 /* 519 * The walker's fini function is invoked at the end of each walk. 520 */ 521 static void 522 pkt_walk_f(mdb_walk_state_t *wsp) 523 { 524 mdb_free(wsp->walk_data, sizeof (struct fcp_pkt)); 525 } 526 527 /* 528 * MDB module linkage information: 529 * 530 * We declare a list of structures describing our dcmds, a list of structures 531 * describing our walkers, and a function named _mdb_init to return a pointer 532 * to our module information. 533 */ 534 535 static const mdb_dcmd_t dcmds[] = { 536 { "fcp", NULL, "Leadville fcp instances", fcp }, 537 { NULL } 538 }; 539 540 static const mdb_walker_t walkers[] = { 541 { "fcp", "Walk list of Leadville fcp instances", 542 fcp_walk_i, fcp_walk_s, fcp_walk_f }, 543 { "cmds", "Walk list of SCSI commands in fcp's per-lun queue", 544 cmds_walk_i, cmds_walk_s, cmds_walk_f }, 545 { "luns", "Walk list of LUNs in an fcp target", 546 luns_walk_i, luns_walk_s, luns_walk_f }, 547 { "targets", "Walk list of fcp targets attached to the local port", 548 targets_walk_i, targets_walk_s, targets_walk_f }, 549 { "fcp_ipkt", "Walk list of internal packets queued on a local port", 550 ipkt_walk_i, ipkt_walk_s, ipkt_walk_f}, 551 { "fcp_pkt", "Walk list of packets queued on a local port", 552 pkt_walk_i, pkt_walk_s, pkt_walk_f}, 553 { NULL } 554 }; 555 556 static const mdb_modinfo_t modinfo = { 557 MDB_API_VERSION, dcmds, walkers 558 }; 559 560 const mdb_modinfo_t * 561 _mdb_init(void) 562 { 563 return (&modinfo); 564 }