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