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