xref: /illumos-gate/usr/src/cmd/mdb/common/modules/sd/sd.c (revision dd72704bd9e794056c558153663c739e2012d721)
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
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
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
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
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
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
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
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
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
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
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
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(&currentBuf, 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
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
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
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
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
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
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 *
855 _mdb_init(void)
856 {
857 	return (&modinfo);
858 }
859