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
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.
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]
23 * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #include <sys/mdb_modapi.h>
28 #include <sys/scsi/scsi.h>
30 #include <sys/taskq.h>
31 #include <sys/scsi/targets/sddef.h>
33 /* Represents global soft state data in walk_step, walk_init */
34 #define SD_DATA(param) ((sd_str_p)wsp->walk_data)->param
36 /* Represents global soft state data in callback and related routines */
37 #define SD_DATA_IN_CBACK(param) ((sd_str_p)walk_data)->param
39 #define SUCCESS WALK_NEXT
43 * Primary attribute struct for buf extensions.
45 struct __ddi_xbuf_attr
{
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 *);
60 timeout_id_t xa_timeid
;
65 * Provides soft state information like the number of elements, pointer
66 * to soft state elements etc
68 typedef struct i_ddi_soft_state sd_state_str_t
, *sd_state_str_ptr
;
70 /* structure to store soft state statistics */
71 typedef struct sd_str
{
73 uintptr_t current_root
;
74 int current_list_count
;
77 sd_state_str_t sd_state_data
;
78 } sd_str_t
, *sd_str_p
;
82 * Function: buf_avforw_walk_init
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'.
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.
94 buf_avforw_walk_init(mdb_walk_state_t
*wsp
)
96 if (wsp
->walk_addr
== (uintptr_t)NULL
) {
97 mdb_warn("buffer address required with the command\n");
101 wsp
->walk_data
= mdb_alloc(sizeof (buf_t
), UM_SLEEP
);
107 * Function: buf_avforw_walk_step
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
117 * Arguments: mdb_walk_state_t structure
120 buf_avforw_walk_step(mdb_walk_state_t
*wsp
)
125 * if walk_addr is null then it effectively means an end of all
126 * buf structures, hence end the iterations.
128 if (wsp
->walk_addr
== (uintptr_t)NULL
) {
133 * Read the contents of the current object, invoke the callback
134 * and assign the next objects address to mdb_walk_state_t structure.
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
);
141 status
= wsp
->walk_callback(wsp
->walk_addr
, wsp
->walk_data
,
143 wsp
->walk_addr
= (uintptr_t)(((buf_t
*)wsp
->walk_data
)->av_forw
);
149 * Function: buf_callback
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.
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.
164 buf_callback(uintptr_t addr
, const void *walk_data
, void *buf_entries
)
166 int *count
= (int *)buf_entries
;
169 * If this is the first invocation of the command, print a
170 * header line for the output that will follow.
173 mdb_printf("============================\n");
174 mdb_printf("Walking buf list via av_forw\n");
175 mdb_printf("============================\n");
179 * read the object and print the contents.
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");
199 * Function: buf_avforw_walk_fini
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.
205 * Arguments: mdb_walk_state_t structure
208 buf_avforw_walk_fini(mdb_walk_state_t
*wsp
)
210 mdb_free(wsp
->walk_data
, sizeof (buf_t
));
214 * Function: dump_xbuf_attr
216 * Description: Prints the contents of Xbuf queue.
218 * Arguments: object contents pointer and address.
221 dump_xbuf_attr(struct __ddi_xbuf_attr
*xba_ptr
, uintptr_t mem_addr
)
223 mdb_printf("0x%8lx:\tmutex\t\tallocsize\tpending\n",
224 mem_addr
+ offsetof(struct __ddi_xbuf_attr
, xa_mutex
));
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
));
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
));
238 mdb_printf(" \t%lx%c\t%lx\n",
239 xba_ptr
->xa_headp
, (xba_ptr
->xa_headp
== 0?'\t':' '),
241 mdb_printf("0x%8lx:\treserve_mutex\treserve_limit\t"
242 "reserve_count\treserve_headp\n",
243 mem_addr
+ offsetof(struct __ddi_xbuf_attr
, xa_reserve_mutex
));
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
);
249 mdb_printf("0x%8lx:\ttimeid\t\ttq\n",
250 mem_addr
+ offsetof(struct __ddi_xbuf_attr
, xa_timeid
));
252 mdb_printf(" \t%lx%c\t%lx\n",
253 xba_ptr
->xa_timeid
, (xba_ptr
->xa_timeid
== 0?'\t':' '),
258 * Function: init_softstate_members
260 * Description: Initialize mdb_walk_state_t structure with either 'sd' or
261 * 'ssd' related information.
263 * Arguments: new mdb_walk_state_t structure
266 init_softstate_members(mdb_walk_state_t
*wsp
)
268 wsp
->walk_data
= mdb_alloc(sizeof (sd_str_t
), UM_SLEEP
);
271 * store the soft state statistics variables like non-zero
272 * soft state entries, base address, actual count of soft state
275 SD_DATA(sd_state
) = (sd_state_str_ptr
)wsp
->walk_addr
;
277 SD_DATA(current_list_count
) = 0;
278 SD_DATA(valid_root_count
) = 0;
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
);
286 wsp
->walk_addr
= (uintptr_t)(SD_DATA(sd_state_data
.array
));
288 SD_DATA(current_root
) = wsp
->walk_addr
;
293 * Function: sd_state_walk_init
295 * Description: MDB calls the init function to initiate the walk,
296 * in response to mdb_walk() function called by the
297 * dcmd 'sd_state' or when the user executes the
298 * walk dcmd '::walk sd_state'.
299 * The init function initializes the walker to either
300 * the user specified address or the default kernel
301 * 'sd_state' pointer.
303 * Arguments: new mdb_walk_state_t structure
306 sd_state_walk_init(mdb_walk_state_t
*wsp
)
308 if (wsp
->walk_addr
== (uintptr_t)NULL
&&
309 mdb_readvar(&wsp
->walk_addr
, "sd_state") == -1) {
310 mdb_warn("failed to read 'sd_state'");
314 return (init_softstate_members(wsp
));
318 * Function: sd_state_walk_step
320 * Description: The step function is invoked by the walker during each
321 * iteration. Its primary job is to determine the address
322 * of the next 'soft state' object, read in the local copy
323 * of this object, call the callback 'sd_callback' function,
324 * and return its status. The iteration is terminated when
325 * the soft state counter equals the total soft state count
326 * obtained initially.
328 * Arguments: mdb_walk_state_t structure
331 sd_state_walk_step(mdb_walk_state_t
*wsp
)
337 * If all the soft state entries have been processed then stop
340 if (SD_DATA(current_list_count
) >= SD_DATA(sd_state_data
.n_items
)) {
345 * read the object contents, invoke the callback and set the
346 * mdb_walk_state_t structure to the next object.
348 if (mdb_vread(&tp
, sizeof (void *), wsp
->walk_addr
) == -1) {
349 mdb_warn("failed to read at %p", wsp
->walk_addr
);
353 status
= wsp
->walk_callback((uintptr_t)tp
, wsp
->walk_data
,
356 /* Count the number of non-zero un entries. */
357 SD_DATA(valid_root_count
++);
360 wsp
->walk_addr
+= sizeof (void *);
361 SD_DATA(current_list_count
++);
367 * Function: sd_state_walk_fini
369 * Description: The sd_state_walk_fini is called when the walk is terminated
370 * in response to WALK_DONE in sd_state_walk_step. It frees
371 * the walk_data structure.
373 * Arguments: mdb_walk_state_t structure
376 sd_state_walk_fini(mdb_walk_state_t
*wsp
)
378 mdb_free(wsp
->walk_data
, sizeof (sd_str_t
));
382 * Function: process_semo_sleepq
384 * Description: Iterate over the semoclose wait Q members of the soft state.
385 * Print the contents of each member. In case of silent mode
386 * the contents are avoided and only the address is printed.
388 * Arguments: starting queue address, print mode.
391 process_semo_sleepq(uintptr_t walk_addr
, int silent
)
395 int semo_sleepq_count
= 0;
397 /* Set up to process the device's semoclose wait Q */
401 mdb_printf("\nSEMOCLOSE SLEEP Q:\n");
402 mdb_printf("----------\n");
405 mdb_printf("SEMOCLOSE sleep Q head: %lx\n", rootBuf
);
408 /* Process the device's cmd. wait Q */
410 mdb_printf("SEMOCLOSE SLEEP Q list entry:\n");
411 mdb_printf("------------------\n");
414 if (mdb_vread((void *)¤tBuf
, sizeof (buf_t
),
416 mdb_warn("failed to read buf at %p", rootBuf
);
421 mdb_set_dot(rootBuf
);
426 rootBuf
= (uintptr_t)currentBuf
.av_forw
;
429 if (rootBuf
== (uintptr_t)NULL
) {
430 mdb_printf("------------------------------\n");
431 mdb_printf("Processed %d SEMOCLOSE SLEEP Q entries\n",
433 mdb_printf("------------------------------\n");
440 * Function: process_sdlun_waitq
442 * Description: Iterate over the wait Q members of the soft state.
443 * Print the contents of each member. In case of silent mode
444 * the contents are avoided and only the address is printed.
446 * Arguments: starting queue address, print mode.
449 process_sdlun_waitq(uintptr_t walk_addr
, int silent
)
453 int sdLunQ_count
= 0;
458 mdb_printf("\nUN WAIT Q:\n");
459 mdb_printf("----------\n");
461 mdb_printf("UN wait Q head: %lx\n", rootBuf
);
464 /* Process the device's cmd. wait Q */
466 mdb_printf("UN WAIT Q list entry:\n");
467 mdb_printf("------------------\n");
470 if (mdb_vread(¤tBuf
, sizeof (buf_t
),
471 (uintptr_t)rootBuf
) == -1) {
472 mdb_warn("failed to read buf at %p",
478 mdb_set_dot(rootBuf
);
483 rootBuf
= (uintptr_t)currentBuf
.av_forw
;
487 if (rootBuf
== (uintptr_t)NULL
) {
488 mdb_printf("------------------------------\n");
489 mdb_printf("Processed %d UN WAIT Q entries\n", sdLunQ_count
);
490 mdb_printf("------------------------------\n");
497 * Function: process_xbuf
499 * Description: Iterate over the Xbuf Attr and Xbuf Attr wait Q of the soft
501 * Print the contents of each member. In case of silent mode
502 * the contents are avoided and only the address is printed.
504 * Arguments: starting xbuf address, print mode.
507 process_xbuf(uintptr_t xbuf_attr
, int silent
)
509 struct __ddi_xbuf_attr xba
;
512 int xbuf_q_count
= 0;
514 if (xbuf_attr
== (uintptr_t)NULL
) {
515 mdb_printf("---------------------------\n");
516 mdb_printf("No XBUF ATTR entry\n");
517 mdb_printf("---------------------------\n");
521 /* Process the Xbuf Attr struct for a device. */
522 if (mdb_vread((void *)&xba
, sizeof (struct __ddi_xbuf_attr
),
524 mdb_warn("failed to read xbuf_attr at %p", xbuf_attr
);
529 mdb_printf("\nXBUF ATTR:\n");
530 mdb_printf("----------\n");
532 dump_xbuf_attr(&xba
, xbuf_attr
);
535 mdb_printf("\nXBUF Q:\n");
536 mdb_printf("-------\n");
539 mdb_printf("xbuf Q head: %lx\n", xba
.xa_headp
);
541 xba_root
= (void *) xba
.xa_headp
;
543 /* Process the Xbuf Attr wait Q, if there are any entries. */
544 while ((uintptr_t)xba_root
) {
546 mdb_printf("XBUF_Q list entry:\n");
547 mdb_printf("------------------\n");
550 if (mdb_vread((void *)&xba_current
, sizeof (buf_t
),
551 (uintptr_t)xba_root
) == -1) {
552 mdb_warn("failed to read buf at %p",
553 (uintptr_t)xba_root
);
557 mdb_set_dot((uintptr_t)xba_root
);
563 xba_root
= (void *)xba_current
.av_forw
;
566 if (xba_root
== NULL
) {
567 mdb_printf("---------------------------\n");
568 mdb_printf("Processed %d XBUF Q entries\n", xbuf_q_count
);
569 mdb_printf("---------------------------\n");
575 * Function: print_footer
577 * Description: Prints the footer if all the soft state entries are processed.
579 * Arguments: private storage of the walker.
582 print_footer(const void *walk_data
)
584 if (SD_DATA_IN_CBACK(current_list_count
) >=
585 (SD_DATA_IN_CBACK(sd_state_data
.n_items
) - 1)) {
586 mdb_printf("---------------------------\n");
587 mdb_printf("Processed %d UN softstate entries\n",
588 SD_DATA_IN_CBACK(valid_root_count
));
589 mdb_printf("---------------------------\n");
594 * Function: sd_callback
596 * Description: This is the callback function called by the
597 * 'sd_state/ssd_state' walker when 'sd_state/ssd_state' dcmd
598 * invokes the walker.
599 * It is called during each walk step. It displays the contents
600 * of the current soft state object (addr) passed to it by the
601 * step function. It also prints the header and footer during the
602 * first and the last step of the walker.
603 * The contents of the soft state also includes various queues
604 * it includes like Xbuf, semo_close, sdlun_waitq.
606 * Arguments: addr -> current soft state objects address.
607 * walk_data -> private storage for the walker.
608 * flg_silent -> private data for the callback. It represents
609 * the silent mode of operation.
612 sd_callback(uintptr_t addr
, const void *walk_data
, void *flg_silent
)
615 int silent
= *(int *)flg_silent
;
618 * If this is the first invocation of the command, print a
619 * header line for the output that will follow.
621 if (SD_DATA_IN_CBACK(current_list_count
) == 0) {
622 mdb_printf("walk_addr = %lx\n", SD_DATA_IN_CBACK(sd_state
));
623 mdb_printf("walking sd_state units via ptr: %lx\n",
624 SD_DATA_IN_CBACK(current_root
));
625 mdb_printf("%d entries in sd_state table\n",
626 SD_DATA_IN_CBACK(sd_state_data
.n_items
));
629 mdb_printf("\nun %d: %lx\n", SD_DATA_IN_CBACK(current_list_count
),
632 mdb_printf("--------------\n");
634 /* if null soft state iterate over to next one */
635 if (addr
== (uintptr_t)NULL
) {
636 print_footer(walk_data
);
640 * For each buf, we need to read the sd_lun struct,
641 * and then print out its contents, and get the next.
643 else if (mdb_vread(&sdLun
, sizeof (struct sd_lun
), (uintptr_t)addr
) ==
647 mdb_eval("$<sd_lun");
651 mdb_warn("failed to read softstate at %p", addr
);
655 /* process device Xbuf Attr struct and wait Q */
656 process_xbuf((uintptr_t)sdLun
.un_xbuf_attr
, silent
);
658 /* process device cmd wait Q */
659 process_sdlun_waitq((uintptr_t)sdLun
.un_waitq_headp
, silent
);
661 /* process device semoclose wait Q */
662 if (sdLun
.un_semoclose
._opaque
[1] == 0) {
663 process_semo_sleepq((uintptr_t)sdLun
.un_semoclose
._opaque
[0],
667 /* print the actual number of soft state processed */
668 print_footer(walk_data
);
673 * Function: dcmd_sd_state
675 * Description: Scans through the sd soft state entries and prints their
676 * contents including of various queues it contains. It uses
677 * 'sd_state' walker to perform a global walk. If a particular
678 * soft state address is specified than it performs the above job
679 * itself (local walk).
681 * Arguments: addr -> user specified address or NULL if no address is
683 * flags -> integer reflecting whether an address was specified,
684 * or if it was invoked by the walker in a loop etc.
685 * argc -> the number of arguments supplied to the dcmd.
686 * argv -> the actual arguments supplied by the user.
690 dcmd_sd_state(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
695 /* Enable the silent mode if '-s' option specified the user */
696 if (mdb_getopts(argc
, argv
, 's', MDB_OPT_SETBITS
, TRUE
, &silent
, NULL
)
702 * If no address is specified on the command line, perform
703 * a global walk invoking 'sd_state' walker. If a particular address
704 * is specified then print the soft state and its queues.
706 if (!(flags
& DCMD_ADDRSPEC
)) {
707 mdb_walk("sd_state", sd_callback
, (void *)&silent
);
710 mdb_printf("\nun: %lx\n", addr
);
711 mdb_printf("--------------\n");
713 /* read the sd_lun struct and print the contents */
714 if (mdb_vread(&sdLun
, sizeof (struct sd_lun
),
715 (uintptr_t)addr
) == sizeof (sdLun
)) {
719 mdb_eval("$<sd_lun");
723 mdb_warn("failed to read softstate at %p", addr
);
727 /* process Xbuf Attr struct and wait Q for the soft state */
728 process_xbuf((uintptr_t)sdLun
.un_xbuf_attr
, silent
);
730 /* process device' cmd wait Q */
731 process_sdlun_waitq((uintptr_t)sdLun
.un_waitq_headp
, silent
);
733 /* process device's semoclose wait Q */
734 if (sdLun
.un_semoclose
._opaque
[1] == 0) {
736 (uintptr_t)sdLun
.un_semoclose
._opaque
[0], silent
);
743 * Function: dcmd_buf_avforw
745 * Description: Scans through the buf list via av_forw and prints
747 * It uses the 'buf_avforw' walker to perform the walk.
749 * Arguments: addr -> user specified address.
750 * flags -> integer reflecting whether an address was specified,
751 * or if it was invoked by the walker in a loop etc.
752 * argc -> the number of arguments supplied to the dcmd.
753 * argv -> the actual arguments supplied by the user.
757 dcmd_buf_avforw(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
761 /* it does not take any arguments */
766 * If no address was specified on the command line, print the
767 * error msg, else scan and
768 * print out all the buffers available by invoking buf_avforw walker.
770 if ((flags
& DCMD_ADDRSPEC
)) {
771 mdb_pwalk("buf_avforw", buf_callback
, (void *)&buf_entries
,
775 mdb_printf("buffer address required with the command\n");
782 * MDB module linkage information:
784 * List of structures describing our dcmds, a list of structures
785 * describing our walkers, and a function named _mdb_init to return a pointer
786 * to our module information.
789 static const mdb_dcmd_t dcmds
[] = {
790 { "buf_avforw", ":", "buf_t list via av_forw", dcmd_buf_avforw
},
791 { "sd_state", "[-s]", "sd soft state list", dcmd_sd_state
},
795 static const mdb_walker_t walkers
[] = {
796 { "buf_avforw", "walk list of buf_t structures via av_forw",
797 buf_avforw_walk_init
, buf_avforw_walk_step
, buf_avforw_walk_fini
},
798 { "sd_state", "walk all sd soft state queues",
799 sd_state_walk_init
, sd_state_walk_step
, sd_state_walk_fini
},
803 static const mdb_modinfo_t modinfo
= {
804 MDB_API_VERSION
, dcmds
, walkers
808 * Function: _mdb_init
810 * Description: Returns mdb_modinfo_t structure which provides linkage and
811 * module identification information to the debugger.
815 const mdb_modinfo_t
*