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