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
buf_avforw_walk_init(mdb_walk_state_t * wsp)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
buf_avforw_walk_step(mdb_walk_state_t * wsp)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
buf_callback(uintptr_t addr,const void * walk_data,void * buf_entries)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
buf_avforw_walk_fini(mdb_walk_state_t * wsp)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
dump_xbuf_attr(struct __ddi_xbuf_attr * xba_ptr,uintptr_t mem_addr)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
init_softstate_members(mdb_walk_state_t * wsp)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
sd_state_walk_init(mdb_walk_state_t * wsp)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
ssd_state_walk_init(mdb_walk_state_t * wsp)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
sd_state_walk_step(mdb_walk_state_t * wsp)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
sd_state_walk_fini(mdb_walk_state_t * wsp)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
process_sdlun_waitq(uintptr_t walk_addr,int silent)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
process_xbuf(uintptr_t xbuf_attr,int silent)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
print_footer(const void * walk_data)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
sd_callback(uintptr_t addr,const void * walk_data,void * flg_silent)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
dcmd_sd_state(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
dcmd_ssd_state(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
dcmd_buf_avforw(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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 *
_mdb_init(void)855 _mdb_init(void)
856 {
857 return (&modinfo);
858 }
859