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