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