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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 /* 27 * Copyright 2022 RackTop Systems, Inc. 28 */ 29 30 #include <sys/mdb_modapi.h> 31 #include <sys/scsi/scsi.h> 32 #include <sys/dkio.h> 33 #include <sys/taskq.h> 34 #include <sys/scsi/targets/sddef.h> 35 36 /* Represents global soft state data in walk_step, walk_init */ 37 #define SD_DATA(param) ((sd_str_p)wsp->walk_data)->param 38 39 /* Represents global soft state data in callback and related routines */ 40 #define SD_DATA_IN_CBACK(param) ((sd_str_p)walk_data)->param 41 42 #define SUCCESS WALK_NEXT 43 #define FAIL WALK_ERR 44 45 /* 46 * Primary attribute struct for buf extensions. 47 */ 48 struct __ddi_xbuf_attr { 49 kmutex_t xa_mutex; 50 size_t xa_allocsize; 51 uint32_t xa_pending; /* call to xbuf_iostart() is iminent */ 52 uint32_t xa_active_limit; 53 uint32_t xa_active_count; 54 uint32_t xa_active_lowater; 55 struct buf *xa_headp; /* FIFO buf queue head ptr */ 56 struct buf *xa_tailp; /* FIFO buf queue tail ptr */ 57 kmutex_t xa_reserve_mutex; 58 uint32_t xa_reserve_limit; 59 uint32_t xa_reserve_count; 60 void *xa_reserve_headp; 61 void (*xa_strategy)(struct buf *, void *, void *); 62 void *xa_attr_arg; 63 timeout_id_t xa_timeid; 64 taskq_t *xa_tq; 65 }; 66 67 /* 68 * Provides soft state information like the number of elements, pointer 69 * to soft state elements etc 70 */ 71 typedef struct i_ddi_soft_state sd_state_str_t, *sd_state_str_ptr; 72 73 /* structure to store soft state statistics */ 74 typedef struct sd_str { 75 void *sd_state; 76 uintptr_t current_root; 77 int current_list_count; 78 int valid_root_count; 79 int silent; 80 sd_state_str_t sd_state_data; 81 } sd_str_t, *sd_str_p; 82 83 84 /* 85 * Function: buf_avforw_walk_init 86 * 87 * Description: MDB calls the init function to initiate the walk, 88 * in response to mdb_walk() function called by the 89 * dcmd 'buf_avforw' or when the user executes the 90 * walk dcmd 'address::walk buf_avforw'. 91 * 92 * Arguments: new mdb_walk_state_t structure. A new structure is 93 * created for each walk, so that multiple instances of 94 * the walker can be active simultaneously. 95 */ 96 static int 97 buf_avforw_walk_init(mdb_walk_state_t *wsp) 98 { 99 if (wsp->walk_addr == 0) { 100 mdb_warn("buffer address required with the command\n"); 101 return (WALK_ERR); 102 } 103 104 wsp->walk_data = mdb_alloc(sizeof (buf_t), UM_SLEEP); 105 return (WALK_NEXT); 106 } 107 108 109 /* 110 * Function: buf_avforw_walk_step 111 * 112 * Description: The step function is invoked by the walker during each 113 * iteration. Its primary job is to determine the address 114 * of the next 'buf_avforw' object, read in the local copy 115 * of this object, call the callback 'buf_callback' function, 116 * and return its status. The iteration is terminated when 117 * the walker encounters a null queue pointer which signifies 118 * end of queue. 119 * 120 * Arguments: mdb_walk_state_t structure 121 */ 122 static int 123 buf_avforw_walk_step(mdb_walk_state_t *wsp) 124 { 125 int status; 126 127 /* 128 * if walk_addr is null then it effectively means an end of all 129 * buf structures, hence end the iterations. 130 */ 131 if (wsp->walk_addr == 0) { 132 return (WALK_DONE); 133 } 134 135 /* 136 * Read the contents of the current object, invoke the callback 137 * and assign the next objects address to mdb_walk_state_t structure. 138 */ 139 if (mdb_vread(wsp->walk_data, sizeof (buf_t), wsp->walk_addr) == -1) { 140 mdb_warn("failed to read buf at %p", wsp->walk_addr); 141 return (WALK_DONE); 142 } 143 144 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 145 wsp->walk_cbdata); 146 wsp->walk_addr = (uintptr_t)(((buf_t *)wsp->walk_data)->av_forw); 147 148 return (status); 149 } 150 151 /* 152 * Function: buf_callback 153 * 154 * Description: This is the callback function called by the 'buf_avforw' 155 * walker when 'buf_avforw' dcmd is invoked. 156 * It is called during each walk step. It displays the contents 157 * of the current object (addr) passed to it by the step 158 * function. It also prints the header and footer during the 159 * first and the last iteration of the walker. 160 * 161 * Arguments: addr -> current buf_avforw objects address. 162 * walk_data -> private storage for the walker. 163 * buf_entries -> private data for the callback. It represents 164 * the count of objects processed so far. 165 */ 166 static int 167 buf_callback(uintptr_t addr, const void *walk_data, void *buf_entries) 168 { 169 int *count = (int *)buf_entries; 170 171 /* 172 * If this is the first invocation of the command, print a 173 * header line for the output that will follow. 174 */ 175 if (*count == 0) { 176 mdb_printf("============================\n"); 177 mdb_printf("Walking buf list via av_forw\n"); 178 mdb_printf("============================\n"); 179 } 180 181 /* 182 * read the object and print the contents. 183 */ 184 mdb_set_dot(addr); 185 mdb_eval("$<buf"); 186 187 mdb_printf("---\n"); 188 (*count)++; 189 190 /* if this is the last entry and print the footer */ 191 if (((buf_t *)walk_data)->av_forw == NULL) { 192 mdb_printf("---------------------------\n"); 193 mdb_printf("Processed %d Buf entries\n", *count); 194 mdb_printf("---------------------------\n"); 195 return (WALK_DONE); 196 } 197 198 return (WALK_NEXT); 199 } 200 201 /* 202 * Function: buf_avforw_walk_fini 203 * 204 * Description: The buf_avforw_walk_fini is called when the walk is terminated 205 * in response to WALK_DONE in buf_avforw_walk_step. It frees 206 * the walk_data structure. 207 * 208 * Arguments: mdb_walk_state_t structure 209 */ 210 static void 211 buf_avforw_walk_fini(mdb_walk_state_t *wsp) 212 { 213 mdb_free(wsp->walk_data, sizeof (buf_t)); 214 } 215 216 /* 217 * Function: dump_xbuf_attr 218 * 219 * Description: Prints the contents of Xbuf queue. 220 * 221 * Arguments: object contents pointer and address. 222 */ 223 static void 224 dump_xbuf_attr(struct __ddi_xbuf_attr *xba_ptr, uintptr_t mem_addr) 225 { 226 mdb_printf("0x%8lx:\tmutex\t\tallocsize\tpending\n", 227 mem_addr + offsetof(struct __ddi_xbuf_attr, xa_mutex)); 228 229 mdb_printf(" \t%lx\t\t%d\t\t%d\n", 230 xba_ptr->xa_mutex._opaque[0], xba_ptr->xa_allocsize, 231 xba_ptr->xa_pending); 232 mdb_printf("0x%8lx:\tactive_limit\tactive_count\tactive_lowater\n", 233 mem_addr + offsetof(struct __ddi_xbuf_attr, xa_active_limit)); 234 235 mdb_printf(" \t%lx\t\t%lx\t\t%lx\n", 236 xba_ptr->xa_active_limit, xba_ptr->xa_active_count, 237 xba_ptr->xa_active_lowater); 238 mdb_printf("0x%8lx:\theadp\t\ttailp\n", 239 mem_addr + offsetof(struct __ddi_xbuf_attr, xa_headp)); 240 241 mdb_printf(" \t%lx%c\t%lx\n", 242 xba_ptr->xa_headp, (xba_ptr->xa_headp == 0?'\t':' '), 243 xba_ptr->xa_tailp); 244 mdb_printf( 245 "0x%8lx:\treserve_mutex\treserve_limit\treserve_count\treserve_headp\n", 246 mem_addr + offsetof(struct __ddi_xbuf_attr, xa_reserve_mutex)); 247 248 mdb_printf(" \t%lx\t\t%lx\t\t%lx\t\t%lx\n", 249 xba_ptr->xa_reserve_mutex._opaque[0], xba_ptr->xa_reserve_limit, 250 xba_ptr->xa_reserve_count, xba_ptr->xa_reserve_headp); 251 252 mdb_printf("0x%8lx:\ttimeid\t\ttq\n", 253 mem_addr + offsetof(struct __ddi_xbuf_attr, xa_timeid)); 254 255 mdb_printf(" \t%lx%c\t%lx\n", 256 xba_ptr->xa_timeid, (xba_ptr->xa_timeid == 0?'\t':' '), 257 xba_ptr->xa_tq); 258 } 259 260 /* 261 * Function: init_softstate_members 262 * 263 * Description: Initialize mdb_walk_state_t structure with either 'sd' or 264 * 'ssd' related information. 265 * 266 * Arguments: new mdb_walk_state_t structure 267 */ 268 static int 269 init_softstate_members(mdb_walk_state_t *wsp) 270 { 271 wsp->walk_data = mdb_alloc(sizeof (sd_str_t), UM_SLEEP); 272 273 /* 274 * store the soft state statistics variables like non-zero 275 * soft state entries, base address, actual count of soft state 276 * processed etc. 277 */ 278 SD_DATA(sd_state) = (sd_state_str_ptr)wsp->walk_addr; 279 280 SD_DATA(current_list_count) = 0; 281 SD_DATA(valid_root_count) = 0; 282 283 if (mdb_vread((void *)&SD_DATA(sd_state_data), 284 sizeof (sd_state_str_t), wsp->walk_addr) == -1) { 285 mdb_warn("failed to sd_state at %p", wsp->walk_addr); 286 return (WALK_ERR); 287 } 288 289 wsp->walk_addr = (uintptr_t)(SD_DATA(sd_state_data.array)); 290 291 SD_DATA(current_root) = wsp->walk_addr; 292 return (WALK_NEXT); 293 } 294 295 #if (!defined(__fibre)) 296 /* 297 * Function: sd_state_walk_init 298 * 299 * Description: MDB calls the init function to initiate the walk, 300 * in response to mdb_walk() function called by the 301 * dcmd 'sd_state' or when the user executes the 302 * walk dcmd '::walk sd_state'. 303 * The init function initializes the walker to either 304 * the user specified address or the default kernel 305 * 'sd_state' pointer. 306 * 307 * Arguments: new mdb_walk_state_t structure 308 */ 309 static int 310 sd_state_walk_init(mdb_walk_state_t *wsp) 311 { 312 if (wsp->walk_addr == 0 && 313 mdb_readvar(&wsp->walk_addr, "sd_state") == -1) { 314 mdb_warn("failed to read 'sd_state'"); 315 return (WALK_ERR); 316 } 317 318 return (init_softstate_members(wsp)); 319 } 320 321 #else 322 323 /* 324 * Function: ssd_state_walk_init 325 * 326 * Description: MDB calls the init function to initiate the walk, 327 * in response to mdb_walk() function called by the 328 * dcmd 'ssd_state' or when the user executes the 329 * walk dcmd '::walk ssd_state'. 330 * The init function initializes the walker to either 331 * the user specified address or the default kernel 332 * 'ssd_state' pointer. 333 * 334 * Arguments: new mdb_walk_state_t structure 335 */ 336 static int 337 ssd_state_walk_init(mdb_walk_state_t *wsp) 338 { 339 if (wsp->walk_addr == (uintptr_t)NULL && 340 mdb_readvar(&wsp->walk_addr, "ssd_state") == -1) { 341 mdb_warn("failed to read 'ssd_state'"); 342 return (WALK_ERR); 343 } 344 345 return (init_softstate_members(wsp)); 346 } 347 #endif 348 349 350 /* 351 * Function: sd_state_walk_step 352 * 353 * Description: The step function is invoked by the walker during each 354 * iteration. Its primary job is to determine the address 355 * of the next 'soft state' object, read in the local copy 356 * of this object, call the callback 'sd_callback' function, 357 * and return its status. The iteration is terminated when 358 * the soft state counter equals the total soft state count 359 * obtained initially. 360 * 361 * Arguments: mdb_walk_state_t structure 362 */ 363 static int 364 sd_state_walk_step(mdb_walk_state_t *wsp) 365 { 366 int status; 367 void *tp; 368 369 /* 370 * If all the soft state entries have been processed then stop 371 * future iterations. 372 */ 373 if (SD_DATA(current_list_count) >= SD_DATA(sd_state_data.n_items)) { 374 return (WALK_DONE); 375 } 376 377 /* 378 * read the object contents, invoke the callback and set the 379 * mdb_walk_state_t structure to the next object. 380 */ 381 if (mdb_vread(&tp, sizeof (void *), wsp->walk_addr) == -1) { 382 mdb_warn("failed to read at %p", wsp->walk_addr); 383 return (WALK_ERR); 384 } 385 386 status = wsp->walk_callback((uintptr_t)tp, wsp->walk_data, 387 wsp->walk_cbdata); 388 if (tp != 0) { 389 /* Count the number of non-zero un entries. */ 390 SD_DATA(valid_root_count++); 391 } 392 393 wsp->walk_addr += sizeof (void *); 394 SD_DATA(current_list_count++); 395 return (status); 396 } 397 398 399 /* 400 * Function: sd_state_walk_fini 401 * 402 * Description: The sd_state_walk_fini is called when the walk is terminated 403 * in response to WALK_DONE in sd_state_walk_step. It frees 404 * the walk_data structure. 405 * 406 * Arguments: mdb_walk_state_t structure 407 */ 408 static void 409 sd_state_walk_fini(mdb_walk_state_t *wsp) 410 { 411 mdb_free(wsp->walk_data, sizeof (sd_str_t)); 412 } 413 414 /* 415 * Function: process_sdlun_waitq 416 * 417 * Description: Iterate over the wait Q members of the soft state. 418 * Print the contents of each member. In case of silent mode 419 * the contents are avoided and only the address is printed. 420 * 421 * Arguments: starting queue address, print mode. 422 */ 423 static int 424 process_sdlun_waitq(uintptr_t walk_addr, int silent) 425 { 426 uintptr_t rootBuf; 427 buf_t currentBuf; 428 int sdLunQ_count = 0; 429 430 rootBuf = walk_addr; 431 432 if (!silent) { 433 mdb_printf("\nUN WAIT Q:\n"); 434 mdb_printf("----------\n"); 435 } 436 mdb_printf("UN wait Q head: %lx\n", rootBuf); 437 438 while (rootBuf) { 439 /* Process the device's cmd. wait Q */ 440 if (!silent) { 441 mdb_printf("UN WAIT Q list entry:\n"); 442 mdb_printf("------------------\n"); 443 } 444 445 if (mdb_vread(¤tBuf, sizeof (buf_t), 446 (uintptr_t)rootBuf) == -1) { 447 mdb_warn("failed to read buf at %p", 448 (uintptr_t)rootBuf); 449 return (FAIL); 450 } 451 452 if (!silent) { 453 mdb_set_dot(rootBuf); 454 mdb_eval("$<buf"); 455 mdb_printf("---\n"); 456 } 457 458 rootBuf = (uintptr_t)currentBuf.av_forw; 459 ++sdLunQ_count; 460 } 461 462 if (rootBuf == 0) { 463 mdb_printf("------------------------------\n"); 464 mdb_printf("Processed %d UN WAIT Q entries\n", sdLunQ_count); 465 mdb_printf("------------------------------\n"); 466 } 467 468 return (SUCCESS); 469 } 470 471 /* 472 * Function: process_xbuf 473 * 474 * Description: Iterate over the Xbuf Attr and Xbuf Attr wait Q of the soft 475 * state. 476 * Print the contents of each member. In case of silent mode 477 * the contents are avoided and only the address is printed. 478 * 479 * Arguments: starting xbuf address, print mode. 480 */ 481 static int 482 process_xbuf(uintptr_t xbuf_attr, int silent) 483 { 484 struct __ddi_xbuf_attr xba; 485 buf_t xba_current; 486 void *xba_root; 487 int xbuf_q_count = 0; 488 489 if (xbuf_attr == 0) { 490 mdb_printf("---------------------------\n"); 491 mdb_printf("No XBUF ATTR entry\n"); 492 mdb_printf("---------------------------\n"); 493 return (SUCCESS); 494 } 495 496 /* Process the Xbuf Attr struct for a device. */ 497 if (mdb_vread((void *)&xba, sizeof (struct __ddi_xbuf_attr), 498 xbuf_attr) == -1) { 499 mdb_warn("failed to read xbuf_attr at %p", xbuf_attr); 500 return (FAIL); 501 } 502 503 if (!silent) { 504 mdb_printf("\nXBUF ATTR:\n"); 505 mdb_printf("----------\n"); 506 507 dump_xbuf_attr(&xba, xbuf_attr); 508 mdb_printf("---\n"); 509 510 mdb_printf("\nXBUF Q:\n"); 511 mdb_printf("-------\n"); 512 } 513 514 mdb_printf("xbuf Q head: %lx\n", xba.xa_headp); 515 516 xba_root = (void *) xba.xa_headp; 517 518 /* Process the Xbuf Attr wait Q, if there are any entries. */ 519 while ((uintptr_t)xba_root) { 520 if (!silent) { 521 mdb_printf("XBUF_Q list entry:\n"); 522 mdb_printf("------------------\n"); 523 } 524 525 if (mdb_vread((void *)&xba_current, sizeof (buf_t), 526 (uintptr_t)xba_root) == -1) { 527 mdb_warn("failed to read buf at %p", 528 (uintptr_t)xba_root); 529 return (FAIL); 530 } 531 if (!silent) { 532 mdb_set_dot((uintptr_t)xba_root); 533 mdb_eval("$<buf"); 534 mdb_printf("---\n"); 535 } 536 ++xbuf_q_count; 537 538 xba_root = (void *)xba_current.av_forw; 539 } 540 541 if (xba_root == NULL) { 542 mdb_printf("---------------------------\n"); 543 mdb_printf("Processed %d XBUF Q entries\n", xbuf_q_count); 544 mdb_printf("---------------------------\n"); 545 } 546 return (SUCCESS); 547 } 548 549 /* 550 * Function: print_footer 551 * 552 * Description: Prints the footer if all the soft state entries are processed. 553 * 554 * Arguments: private storage of the walker. 555 */ 556 static void 557 print_footer(const void *walk_data) 558 { 559 if (SD_DATA_IN_CBACK(current_list_count) >= 560 (SD_DATA_IN_CBACK(sd_state_data.n_items) - 1)) { 561 mdb_printf("---------------------------\n"); 562 mdb_printf("Processed %d UN softstate entries\n", 563 SD_DATA_IN_CBACK(valid_root_count)); 564 mdb_printf("---------------------------\n"); 565 } 566 } 567 568 /* 569 * Function: sd_callback 570 * 571 * Description: This is the callback function called by the 572 * 'sd_state/ssd_state' walker when 'sd_state/ssd_state' dcmd 573 * invokes the walker. 574 * It is called during each walk step. It displays the contents 575 * of the current soft state object (addr) passed to it by the 576 * step function. It also prints the header and footer during the 577 * first and the last step of the walker. 578 * The contents of the soft state also includes various queues 579 * it includes like Xbuf, semo_close, sdlun_waitq. 580 * 581 * Arguments: addr -> current soft state objects address. 582 * walk_data -> private storage for the walker. 583 * flg_silent -> private data for the callback. It represents 584 * the silent mode of operation. 585 */ 586 static int 587 sd_callback(uintptr_t addr, const void *walk_data, void *flg_silent) 588 { 589 struct sd_lun sdLun; 590 int silent = *(int *)flg_silent; 591 592 /* 593 * If this is the first invocation of the command, print a 594 * header line for the output that will follow. 595 */ 596 if (SD_DATA_IN_CBACK(current_list_count) == 0) { 597 mdb_printf("walk_addr = %lx\n", SD_DATA_IN_CBACK(sd_state)); 598 mdb_printf("walking sd_state units via ptr: %lx\n", 599 SD_DATA_IN_CBACK(current_root)); 600 mdb_printf("%d entries in sd_state table\n", 601 SD_DATA_IN_CBACK(sd_state_data.n_items)); 602 } 603 604 mdb_printf("\nun %d: %lx\n", SD_DATA_IN_CBACK(current_list_count), 605 addr); 606 607 mdb_printf("--------------\n"); 608 609 /* if null soft state iterate over to next one */ 610 if (addr == 0) { 611 print_footer(walk_data); 612 return (SUCCESS); 613 } 614 /* 615 * For each buf, we need to read the sd_lun struct, 616 * and then print out its contents, and get the next. 617 */ 618 else if (mdb_vread(&sdLun, sizeof (struct sd_lun), (uintptr_t)addr) == 619 sizeof (sdLun)) { 620 if (!silent) { 621 mdb_set_dot(addr); 622 mdb_eval("$<sd_lun"); 623 mdb_printf("---\n"); 624 } 625 } else { 626 mdb_warn("failed to read softstate at %p", addr); 627 return (FAIL); 628 } 629 630 /* process device Xbuf Attr struct and wait Q */ 631 process_xbuf((uintptr_t)sdLun.un_xbuf_attr, silent); 632 633 /* process device cmd wait Q */ 634 process_sdlun_waitq((uintptr_t)sdLun.un_waitq_headp, silent); 635 636 /* print the actual number of soft state processed */ 637 print_footer(walk_data); 638 return (SUCCESS); 639 } 640 641 #if (!defined(__fibre)) 642 /* 643 * Function: dcmd_sd_state 644 * 645 * Description: Scans through the sd soft state entries and prints their 646 * contents including of various queues it contains. It uses 647 * 'sd_state' walker to perform a global walk. If a particular 648 * soft state address is specified than it performs the above job 649 * itself (local walk). 650 * 651 * Arguments: addr -> user specified address or NULL if no address is 652 * specified. 653 * flags -> integer reflecting whether an address was specified, 654 * or if it was invoked by the walker in a loop etc. 655 * argc -> the number of arguments supplied to the dcmd. 656 * argv -> the actual arguments supplied by the user. 657 */ 658 /*ARGSUSED*/ 659 static int 660 dcmd_sd_state(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 661 { 662 struct sd_lun sdLun; 663 uint_t silent = 0; 664 665 /* Enable the silent mode if '-s' option specified the user */ 666 if (mdb_getopts(argc, argv, 's', MDB_OPT_SETBITS, TRUE, &silent, NULL) 667 != argc) { 668 return (DCMD_USAGE); 669 } 670 671 /* 672 * If no address is specified on the command line, perform 673 * a global walk invoking 'sd_state' walker. If a particular address 674 * is specified then print the soft state and its queues. 675 */ 676 if (!(flags & DCMD_ADDRSPEC)) { 677 mdb_walk("sd_state", sd_callback, (void *)&silent); 678 return (DCMD_OK); 679 } else { 680 mdb_printf("\nun: %lx\n", addr); 681 mdb_printf("--------------\n"); 682 683 /* read the sd_lun struct and print the contents */ 684 if (mdb_vread(&sdLun, sizeof (struct sd_lun), 685 (uintptr_t)addr) == sizeof (sdLun)) { 686 687 if (!silent) { 688 mdb_set_dot(addr); 689 mdb_eval("$<sd_lun"); 690 mdb_printf("---\n"); 691 } 692 } else { 693 mdb_warn("failed to read softstate at %p", addr); 694 return (DCMD_OK); 695 } 696 697 /* process Xbuf Attr struct and wait Q for the soft state */ 698 process_xbuf((uintptr_t)sdLun.un_xbuf_attr, silent); 699 700 /* process device' cmd wait Q */ 701 process_sdlun_waitq((uintptr_t)sdLun.un_waitq_headp, silent); 702 } 703 return (DCMD_OK); 704 } 705 706 #else 707 708 /* 709 * Function: dcmd_ssd_state 710 * 711 * Description: Scans through the ssd soft state entries and prints their 712 * contents including of various queues it contains. It uses 713 * 'ssd_state' walker to perform a global walk. If a particular 714 * soft state address is specified than it performs the above job 715 * itself (local walk). 716 * 717 * Arguments: addr -> user specified address or NULL if no address is 718 * specified. 719 * flags -> integer reflecting whether an address was specified, 720 * or if it was invoked by the walker in a loop etc. 721 * argc -> the number of arguments supplied to the dcmd. 722 * argv -> the actual arguments supplied by the user. 723 */ 724 /*ARGSUSED*/ 725 static int 726 dcmd_ssd_state(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 727 { 728 struct sd_lun sdLun; 729 uint_t silent = 0; 730 731 /* Enable the silent mode if '-s' option specified the user */ 732 if (mdb_getopts(argc, argv, 's', MDB_OPT_SETBITS, TRUE, &silent, NULL) 733 != argc) { 734 return (DCMD_USAGE); 735 } 736 737 /* 738 * If no address is specified on the command line, perform 739 * a global walk invoking 'sd_state' walker. If a particular address 740 * is specified then print the soft state and its queues. 741 */ 742 if (!(flags & DCMD_ADDRSPEC)) { 743 mdb_walk("ssd_state", sd_callback, (void *)&silent); 744 return (DCMD_OK); 745 } else { 746 mdb_printf("\nun: %lx\n", addr); 747 mdb_printf("--------------\n"); 748 749 /* read the sd_lun struct and print the contents */ 750 if (mdb_vread(&sdLun, sizeof (struct sd_lun), 751 (uintptr_t)addr) == sizeof (sdLun)) { 752 if (!silent) { 753 mdb_set_dot(addr); 754 mdb_eval("$<sd_lun"); 755 mdb_printf("---\n"); 756 } 757 } else { 758 mdb_warn("failed to read softstate at %p", addr); 759 return (DCMD_OK); 760 } 761 762 /* process Xbuf Attr struct and wait Q for the soft state */ 763 process_xbuf((uintptr_t)sdLun.un_xbuf_attr, silent); 764 765 /* process device' cmd wait Q */ 766 process_sdlun_waitq((uintptr_t)sdLun.un_waitq_headp, silent); 767 } 768 return (DCMD_OK); 769 } 770 #endif 771 772 /* 773 * Function: dcmd_buf_avforw 774 * 775 * Description: Scans through the buf list via av_forw and prints 776 * their contents. 777 * It uses the 'buf_avforw' walker to perform the walk. 778 * 779 * Arguments: addr -> user specified address. 780 * flags -> integer reflecting whether an address was specified, 781 * or if it was invoked by the walker in a loop etc. 782 * argc -> the number of arguments supplied to the dcmd. 783 * argv -> the actual arguments supplied by the user. 784 */ 785 /*ARGSUSED*/ 786 static int 787 dcmd_buf_avforw(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 788 { 789 int buf_entries = 0; 790 791 /* it does not take any arguments */ 792 if (argc != 0) 793 return (DCMD_USAGE); 794 795 /* 796 * If no address was specified on the command line, print the 797 * error msg, else scan and 798 * print out all the buffers available by invoking buf_avforw walker. 799 */ 800 if ((flags & DCMD_ADDRSPEC)) { 801 mdb_pwalk("buf_avforw", buf_callback, (void *)&buf_entries, 802 addr); 803 return (DCMD_OK); 804 } else { 805 mdb_printf("buffer address required with the command\n"); 806 } 807 808 return (DCMD_USAGE); 809 } 810 811 /* 812 * MDB module linkage information: 813 * 814 * List of structures describing our dcmds, a list of structures 815 * describing our walkers, and a function named _mdb_init to return a pointer 816 * to our module information. 817 */ 818 819 static const mdb_dcmd_t dcmds[] = { 820 { "buf_avforw", ":", "buf_t list via av_forw", dcmd_buf_avforw}, 821 #if (!defined(__fibre)) 822 { "sd_state", "[-s]", "sd soft state list", dcmd_sd_state}, 823 #else 824 { "ssd_state", "[-s]", "ssd soft state list", dcmd_ssd_state}, 825 #endif 826 { NULL } 827 }; 828 829 static const mdb_walker_t walkers[] = { 830 { "buf_avforw", "walk list of buf_t structures via av_forw", 831 buf_avforw_walk_init, buf_avforw_walk_step, buf_avforw_walk_fini }, 832 #if (!defined(__fibre)) 833 { "sd_state", "walk all sd soft state queues", 834 sd_state_walk_init, sd_state_walk_step, sd_state_walk_fini }, 835 #else 836 { "ssd_state", "walk all ssd soft state queues", 837 ssd_state_walk_init, sd_state_walk_step, sd_state_walk_fini }, 838 #endif 839 { NULL } 840 }; 841 842 static const mdb_modinfo_t modinfo = { 843 MDB_API_VERSION, dcmds, walkers 844 }; 845 846 /* 847 * Function: _mdb_init 848 * 849 * Description: Returns mdb_modinfo_t structure which provides linkage and 850 * module identification information to the debugger. 851 * 852 * Arguments: void 853 */ 854 const mdb_modinfo_t * 855 _mdb_init(void) 856 { 857 return (&modinfo); 858 } 859