xref: /illumos-gate/usr/src/cmd/mdb/common/modules/stmf/stmf.c (revision fb2a9bae0030340ad72b9c26ba1ffee2ee3cafec)
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 (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <sys/dditypes.h>
27 #include <sys/mdb_modapi.h>
28 #include <sys/modctl.h>
29 #include <sys/sunddi.h>
30 #include <sys/lpif.h>
31 #include <sys/stmf.h>
32 #include <sys/portif.h>
33 #include <stmf_impl.h>
34 #include <lun_map.h>
35 #include <stmf_state.h>
36 
37 #include <sys/fct.h>
38 #include <fct_impl.h>
39 
40 #include "cmd_options.h"
41 
42 static int
43 stmf_ilport_walk_i(mdb_walk_state_t *wsp)
44 {
45 	if (wsp->walk_addr == NULL) {
46 		struct stmf_state state;
47 
48 		if (mdb_readsym(&state, sizeof (struct stmf_state),
49 		    "stmf_state") == -1) {
50 			mdb_warn("failed to read stmf_state");
51 			return (WALK_ERR);
52 		}
53 		wsp->walk_addr = (uintptr_t)state.stmf_ilportlist;
54 	}
55 
56 	wsp->walk_data = mdb_alloc(sizeof (stmf_i_local_port_t), UM_SLEEP);
57 	return (WALK_NEXT);
58 }
59 
60 static int
61 stmf_ilport_walk_s(mdb_walk_state_t *wsp)
62 {
63 	int status = WALK_NEXT;
64 
65 	if (wsp->walk_addr == NULL)
66 		return (WALK_DONE);
67 
68 	if (mdb_vread(wsp->walk_data, sizeof (struct stmf_i_local_port),
69 	    wsp->walk_addr) == -1) {
70 		mdb_warn("failed to read stmf_i_local_port_t at %p",
71 		    wsp->walk_addr);
72 		return (WALK_ERR);
73 	}
74 
75 	if (wsp->walk_callback)
76 		status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
77 		    wsp->walk_cbdata);
78 
79 	wsp->walk_addr = (uintptr_t)
80 	    (((struct stmf_i_local_port *)wsp->walk_data)->ilport_next);
81 
82 	return (status);
83 }
84 
85 static void
86 stmf_ilport_walk_f(mdb_walk_state_t *wsp)
87 {
88 	mdb_free(wsp->walk_data, sizeof (struct stmf_i_local_port));
89 }
90 
91 static int
92 dump_ilport(struct stmf_i_local_port *ilportp, int verbose)
93 {
94 	if (ilportp == NULL)
95 		return (DCMD_OK);
96 
97 	mdb_printf("%p\n", ilportp);
98 
99 	if (verbose) {
100 		/* here assume the alias is maximumly 1024 bytes */
101 		char alias[255];
102 		struct stmf_local_port lport;
103 		struct stmf_i_local_port ilport;
104 
105 		if (mdb_vread(&ilport, sizeof (ilport), (uintptr_t)ilportp)
106 		    == -1) {
107 			mdb_warn("failed to read stmf_i_local_port at %p",
108 			    ilportp);
109 			return (DCMD_ERR);
110 		}
111 
112 		memset(alias, 0, sizeof (alias));
113 		if (mdb_vread(&lport, sizeof (lport),
114 		    (uintptr_t)ilport.ilport_lport) == -1) {
115 			mdb_warn("failed to read stmf_local_port at %p",
116 			    ilport.ilport_lport);
117 			return (DCMD_ERR);
118 		}
119 		if (lport.lport_alias && mdb_vread(alias, sizeof (alias),
120 		    (uintptr_t)lport.lport_alias) == -1) {
121 			mdb_warn("failed to read memory at %p",
122 			    lport.lport_alias);
123 			return (DCMD_ERR);
124 		}
125 
126 		mdb_printf("  lport: %p\n", ilport.ilport_lport);
127 		if (lport.lport_alias)
128 			mdb_printf("  port alias: %s\n", alias);
129 		mdb_printf("  port provider: %p\n", lport.lport_pp);
130 	}
131 
132 	return (DCMD_OK);
133 }
134 
135 /*ARGSUSED*/
136 static int
137 stmf_ilports(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
138 {
139 	int i;
140 	int verbose = 0;
141 	mdb_walk_state_t ws = {NULL, };
142 
143 	for (i = 0; i < argc; i++) {
144 		char *ptr = (char *)argv[i].a_un.a_str;
145 
146 		if (ptr[0] == '-')
147 			ptr++;
148 		while (*ptr) {
149 			if (*ptr == 'v')
150 				verbose = 1;
151 			ptr++;
152 		}
153 	}
154 
155 	if (stmf_ilport_walk_i(&ws) == WALK_ERR)
156 		return (DCMD_ERR);
157 
158 	dump_ilport((stmf_i_local_port_t *)ws.walk_addr, verbose);
159 
160 	while (stmf_ilport_walk_s(&ws) == WALK_NEXT)
161 		dump_ilport((stmf_i_local_port_t *)ws.walk_addr, verbose);
162 
163 	stmf_ilport_walk_f(&ws);
164 	return (DCMD_OK);
165 }
166 
167 struct stmf_i_local_port *
168 next_stmf_port(mdb_walk_state_t *wsp)
169 {
170 	if (wsp->walk_addr == NULL) {
171 		if (stmf_ilport_walk_i(wsp) == WALK_ERR) {
172 			stmf_ilport_walk_f(wsp);
173 			return (NULL);
174 		}
175 		if (wsp->walk_addr == NULL)
176 			stmf_ilport_walk_f(wsp);
177 		return ((struct stmf_i_local_port *)wsp->walk_addr);
178 	}
179 
180 	if (stmf_ilport_walk_s(wsp) == WALK_ERR) {
181 		stmf_ilport_walk_f(wsp);
182 		return (NULL);
183 	}
184 	if (wsp->walk_addr == NULL)
185 		stmf_ilport_walk_f(wsp);
186 	return ((struct stmf_i_local_port *)wsp->walk_addr);
187 }
188 
189 
190 /*ARGSUSED*/
191 static int
192 stmf_iss(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
193 {
194 	struct stmf_i_local_port iport;
195 	struct stmf_i_scsi_session *issp;
196 	struct stmf_i_scsi_session iss;
197 	int i;
198 	int verbose = 0;
199 
200 	for (i = 0; i < argc; i++) {
201 		char *ptr = (char *)argv[i].a_un.a_str;
202 
203 		if (ptr[0] == '-')
204 			ptr++;
205 		while (*ptr) {
206 			if (*ptr == 'v')
207 				verbose = 1;
208 			ptr++;
209 		}
210 	}
211 
212 	if (addr == NULL) {
213 		mdb_warn("address of stmf_i_local_port should be specified\n");
214 		return (DCMD_ERR);
215 	}
216 
217 	/*
218 	 * Input should be stmf_i_local_port_t.
219 	 */
220 	if (mdb_vread(&iport, sizeof (struct stmf_i_local_port), addr)
221 	    != sizeof (struct stmf_i_local_port)) {
222 		mdb_warn("Unable to read in stmf_i_local_port at %p\n", addr);
223 		return (DCMD_ERR);
224 	}
225 
226 	issp = iport.ilport_ss_list;
227 
228 	while (issp) {
229 		if (mdb_vread(&iss, sizeof (iss), (uintptr_t)issp) == -1) {
230 			mdb_warn("failed to read stmf_i_scsi_session_t at %p",
231 			    issp);
232 			return (DCMD_ERR);
233 		}
234 
235 		mdb_printf("%p\n", issp);
236 		if (verbose) {
237 			mdb_printf("  scsi session: %p\n", iss.iss_ss);
238 		}
239 
240 		issp = iss.iss_next;
241 	}
242 
243 	return (DCMD_OK);
244 }
245 
246 /*ARGSUSED*/
247 static int
248 stmf_ilus(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
249 {
250 	struct stmf_state state;
251 	struct stmf_i_lu ilu;
252 	struct stmf_i_lu *ilup;
253 	int i;
254 	int verbose = 0;
255 
256 	for (i = 0; i < argc; i++) {
257 		char *ptr = (char *)argv[i].a_un.a_str;
258 
259 		if (ptr[0] == '-')
260 			ptr++;
261 		while (*ptr) {
262 			if (*ptr == 'v')
263 				verbose = 1;
264 			ptr++;
265 		}
266 	}
267 
268 	if (mdb_readsym(&state, sizeof (struct stmf_state), "stmf_state")
269 	    == -1) {
270 		mdb_warn("failed to read stmf_state");
271 		return (DCMD_ERR);
272 	}
273 
274 	ilup = state.stmf_ilulist;
275 	while (ilup) {
276 		if (mdb_vread(&ilu, sizeof (struct stmf_i_lu), (uintptr_t)ilup)
277 		    == -1) {
278 			mdb_warn("failed to read stmf_i_lu_t at %p", ilup);
279 			return (DCMD_ERR);
280 		}
281 
282 		mdb_printf("%p\n", ilup);
283 		if (verbose) {
284 			mdb_printf("  lu: %p\n", ilu.ilu_lu);
285 
286 			/* XXX lu_alias? what is its size? */
287 		}
288 
289 		ilup = ilu.ilu_next;
290 	}
291 
292 	return (DCMD_OK);
293 }
294 
295 /*ARGSUSED*/
296 static int
297 stmf_i_lu_providers(uintptr_t addr, uint_t flags, int argc,
298     const mdb_arg_t *argv)
299 {
300 	struct stmf_state state;
301 	struct stmf_i_lu_provider ilp;
302 	struct stmf_i_lu_provider *ilpp;
303 	int i;
304 	int verbose = 0;
305 
306 	for (i = 0; i < argc; i++) {
307 		char *ptr = (char *)argv[i].a_un.a_str;
308 
309 		if (ptr[0] == '-')
310 			ptr++;
311 		while (*ptr) {
312 			if (*ptr == 'v')
313 				verbose = 1;
314 			ptr++;
315 		}
316 	}
317 
318 	if (mdb_readsym(&state, sizeof (struct stmf_state), "stmf_state")
319 	    == -1) {
320 		mdb_warn("failed to read stmf_state");
321 		return (DCMD_ERR);
322 	}
323 
324 	ilpp = state.stmf_ilplist;
325 	while (ilpp) {
326 		if (mdb_vread(&ilp, sizeof (stmf_i_lu_provider_t),
327 		    (uintptr_t)ilpp) == -1) {
328 			mdb_warn("failed to read stmf_i_lu_provider_t at %p",
329 			    ilpp);
330 			return (DCMD_ERR);
331 		}
332 
333 		mdb_printf("%p\n", ilpp);
334 		if (verbose) {
335 			mdb_printf("  lu provider: %p\n", ilp.ilp_lp);
336 		}
337 
338 		ilpp = ilp.ilp_next;
339 	}
340 
341 	return (DCMD_OK);
342 }
343 
344 /*ARGSUSED*/
345 static int
346 stmf_i_port_providers(uintptr_t addr, uint_t flags, int argc,
347     const mdb_arg_t *argv)
348 {
349 	struct stmf_state state;
350 	struct stmf_i_port_provider ipp;
351 	struct stmf_i_port_provider *ippp;
352 	int i;
353 	int verbose = 0;
354 
355 	for (i = 0; i < argc; i++) {
356 		char *ptr = (char *)argv[i].a_un.a_str;
357 
358 		if (ptr[0] == '-')
359 			ptr++;
360 		while (*ptr) {
361 			if (*ptr == 'v')
362 				verbose = 1;
363 			ptr++;
364 		}
365 	}
366 
367 	if (mdb_readsym(&state, sizeof (struct stmf_state), "stmf_state")
368 	    == -1) {
369 		mdb_warn("failed to read stmf_state");
370 		return (DCMD_ERR);
371 	}
372 
373 	ippp = state.stmf_ipplist;
374 	while (ippp) {
375 		if (mdb_vread(&ipp, sizeof (stmf_i_port_provider_t),
376 		    (uintptr_t)ippp) == -1) {
377 			mdb_warn("failed to read stmf_i_port_provider_t at %p",
378 			    ippp);
379 			return (DCMD_ERR);
380 		}
381 
382 		mdb_printf("%p\n", ippp);
383 		if (verbose) {
384 			mdb_printf("  port provider: %p\n", ipp.ipp_pp);
385 		}
386 
387 		ippp = ipp.ipp_next;
388 	}
389 
390 	return (DCMD_OK);
391 }
392 
393 int string2wwn(const char *s, uint8_t wwn[8]);
394 
395 static uint16_t port_max_logins;
396 static int	rp_index;
397 
398 /*
399  * Cervert stmf_i_local_port to fct_i_local_port
400  */
401 /*ARGSUSED*/
402 static struct fct_i_local_port *
403 __ilport2iport(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
404 {
405 	struct stmf_i_local_port iport;
406 	struct stmf_local_port   lport;
407 	struct fct_local_port    fport;
408 
409 	if (!(flags & DCMD_ADDRSPEC)) {
410 		mdb_warn("stmf_i_local_port address should be specified");
411 		return (NULL);
412 	}
413 
414 	/*
415 	 * Input should be stmf_i_local_port_t.
416 	 */
417 	if (mdb_vread(&iport, sizeof (struct stmf_i_local_port), addr)
418 	    != sizeof (struct stmf_i_local_port)) {
419 		mdb_warn("Unable to read in stmf_i_local_port\n");
420 		return (NULL);
421 	}
422 
423 	if (mdb_vread(&lport, sizeof (stmf_local_port_t),
424 	    (uintptr_t)iport.ilport_lport) != sizeof (stmf_local_port_t)) {
425 		mdb_warn("Unable to read in stmf_local_port\n");
426 		return (NULL);
427 	}
428 
429 	if (mdb_vread(&fport, sizeof (fct_local_port_t),
430 	    (uintptr_t)lport.lport_port_private)
431 	    != sizeof (fct_local_port_t)) {
432 		mdb_warn("Unable to read in fct_local_port\n");
433 		return (NULL);
434 	}
435 
436 	return (fport.port_fct_private);
437 }
438 
439 static int
440 ilport2iport(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
441 {
442 	struct fct_i_local_port *iportp;
443 	int i;
444 	int verbose = 0;
445 
446 	for (i = 0; i < argc; i++) {
447 		char *ptr = (char *)argv[i].a_un.a_str;
448 
449 		if (ptr[0] == '-')
450 			ptr++;
451 		while (*ptr) {
452 			if (*ptr == 'v')
453 				verbose = 1;
454 			ptr++;
455 		}
456 	}
457 
458 
459 	iportp = __ilport2iport(addr, flags, argc, argv);
460 	if (iportp) {
461 		mdb_printf("%p\n", iportp);
462 		if (verbose) {
463 			struct fct_i_local_port iport;
464 			/* is the alias always 16 bytes in size ? */
465 			char alias[16];
466 
467 			memset(alias, 0, sizeof (alias));
468 			if (mdb_vread(&iport, sizeof (fct_i_local_port_t),
469 			    (uintptr_t)iportp)
470 			    != sizeof (fct_i_local_port_t)) {
471 				mdb_warn("Unable to read in fct_i_local_port"
472 				    "at %p\n", iportp);
473 				return (DCMD_ERR);
474 			}
475 			if (iport.iport_alias &&
476 			    mdb_vread(alias, sizeof (alias),
477 			    (uintptr_t)iport.iport_alias)
478 			    != sizeof (alias)) {
479 				mdb_warn("Unable to read in memory at %p",
480 				    iport.iport_alias);
481 				return (DCMD_ERR);
482 			}
483 			mdb_printf("  port: %p\n", iport.iport_port);
484 			if (iport.iport_alias)
485 				mdb_printf("  alias: %s\n", alias);
486 		}
487 	}
488 	return (DCMD_OK);
489 }
490 
491 /*
492  * by wwn, we can only find one local port
493  */
494 static struct stmf_i_local_port *
495 find_lport_by_wwn(uint8_t wwn[8])
496 {
497 	struct stmf_i_local_port *siport;
498 	struct fct_i_local_port *fiport;
499 	struct fct_i_local_port iport;
500 	struct fct_local_port fport;
501 	mdb_walk_state_t ws = {NULL, };
502 
503 	while ((siport = next_stmf_port(&ws)) != NULL) {
504 		fiport = __ilport2iport((uintptr_t)siport, DCMD_ADDRSPEC,
505 		    0, NULL);
506 		if (fiport == NULL)
507 			return (NULL);
508 
509 		if (mdb_vread(&iport, sizeof (fct_i_local_port_t),
510 		    (uintptr_t)fiport)
511 		    != sizeof (fct_i_local_port_t)) {
512 			mdb_warn("Unable to read in fct_i_local_port\n");
513 			return (NULL);
514 		}
515 		if (mdb_vread(&fport, sizeof (fct_local_port_t),
516 		    (uintptr_t)iport.iport_port)
517 		    != sizeof (fct_local_port_t)) {
518 			mdb_warn("Unable to read in fct_local_port\n");
519 			return (NULL);
520 		}
521 
522 #if 0
523 		mdb_printf("pwwn=%02x%02x%02x%02x%02x%02x%02x%02x\n",
524 		    fport.port_pwwn[0], fport.port_pwwn[1],
525 		    fport.port_pwwn[2], fport.port_pwwn[3],
526 		    fport.port_pwwn[4], fport.port_pwwn[5],
527 		    fport.port_pwwn[6], fport.port_pwwn[7]);
528 #endif
529 		if (memcmp(fport.port_pwwn, wwn, 8) == 0) {
530 			return (siport);
531 		}
532 	}
533 
534 	return (NULL);
535 }
536 
537 /*ARGSUSED*/
538 static int
539 stmf_find_ilport(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
540 {
541 	struct find_options *options;
542 	struct stmf_i_local_port *siport;
543 
544 	options = parse_options(argc, argv);
545 	/* need to free options manually ? */
546 	if (options == NULL || ! options->lpname_defined) {
547 		mdb_printf("lpname=<wwn.12345678 or 12345678> "
548 		    "should be specified\n");
549 		return (DCMD_OK);
550 	}
551 
552 	if ((siport = find_lport_by_wwn(options->lpname)) != NULL)
553 		mdb_printf("%p\n", siport);
554 
555 	return (DCMD_OK);
556 }
557 
558 static int
559 fct_irp_walk_i(mdb_walk_state_t *wsp)
560 {
561 	struct fct_local_port port;
562 	struct fct_i_local_port iport;
563 
564 	if (wsp->walk_addr == NULL) {
565 		mdb_warn("Can not perform global walk");
566 		return (WALK_ERR);
567 	}
568 
569 	/*
570 	 * Input should be fct_i_local_port_t.
571 	 */
572 	if (mdb_vread(&iport, sizeof (struct fct_i_local_port), wsp->walk_addr)
573 	    != sizeof (struct fct_i_local_port)) {
574 		mdb_warn("Unable to read in fct_i_local_port\n");
575 		return (WALK_ERR);
576 	}
577 
578 	if (mdb_vread(&port, sizeof (struct fct_local_port),
579 	    (uintptr_t)iport.iport_port)
580 	    != sizeof (struct fct_local_port)) {
581 		mdb_warn("Unable to read in fct_local_port\n");
582 		return (WALK_ERR);
583 	}
584 
585 	port_max_logins = port.port_max_logins;
586 	rp_index = 0;
587 	wsp->walk_addr = (uintptr_t)iport.iport_rp_slots;
588 
589 	return (WALK_NEXT);
590 }
591 
592 static int
593 fct_irp_walk_s(mdb_walk_state_t *wsp)
594 {
595 	int status = WALK_NEXT;
596 	fct_i_remote_port_t *rp;
597 
598 	if (wsp->walk_addr == NULL)
599 		return (WALK_DONE);
600 
601 	if (rp_index++ >= port_max_logins)
602 		return (WALK_DONE);
603 
604 	if (mdb_vread(&rp, sizeof (fct_i_remote_port_t *),
605 	    wsp->walk_addr) == -1) {
606 		mdb_warn("failed to read address of fct_i_remote_port_t at %p",
607 		    wsp->walk_addr);
608 		return (WALK_DONE);
609 	}
610 
611 	if (rp != NULL && wsp->walk_callback != NULL)
612 		status = wsp->walk_callback((uintptr_t)rp, rp,
613 		    wsp->walk_cbdata);
614 
615 	wsp->walk_addr = (uintptr_t)
616 	    &(((fct_i_remote_port_t **)wsp->walk_addr)[1]);
617 
618 	return (status);
619 }
620 
621 static void
622 fct_irp_walk_f(mdb_walk_state_t *wsp)
623 {
624 	wsp->walk_addr = NULL;
625 }
626 
627 /*
628  * to set remote_port
629  */
630 /*ARGSUSED*/
631 static int
632 walk_fct_irp_cb(uintptr_t p, const void * arg, void *cbdata)
633 {
634 	*((uintptr_t *)cbdata) = p;
635 	return (WALK_NEXT);
636 }
637 
638 static int
639 fct_irps(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
640 {
641 	static uint64_t cbdata = 0;
642 	mdb_walk_state_t ws = {walk_fct_irp_cb, &cbdata, addr};
643 	fct_i_remote_port_t *irpp;
644 	int i;
645 	int verbose = 0;
646 
647 	for (i = 0; i < argc; i++) {
648 		char *ptr = (char *)argv[i].a_un.a_str;
649 
650 		if (ptr[0] == '-')
651 			ptr++;
652 		while (*ptr) {
653 			if (*ptr == 'v')
654 				verbose = 1;
655 			ptr++;
656 		}
657 	}
658 
659 	if (!(flags & DCMD_ADDRSPEC)) {
660 		mdb_warn("fct_i_local_port_t address should be specified");
661 		return (DCMD_ERR);
662 	}
663 
664 	fct_irp_walk_i(&ws);
665 	while (fct_irp_walk_s(&ws) == WALK_NEXT) {
666 		irpp = *((fct_i_remote_port_t **)ws.walk_cbdata);
667 
668 		if (irpp) {
669 			*((fct_i_remote_port_t **)ws.walk_cbdata) = NULL;
670 
671 			mdb_printf("%p\n", irpp);
672 			if (verbose) {
673 				fct_i_remote_port_t irp;
674 
675 				if (mdb_vread(&irp, sizeof (irp),
676 				    (uintptr_t)irpp) != sizeof (irp)) {
677 					mdb_warn("Unable to read in "
678 					    "fct_i_remote_port at %p\n", irpp);
679 					return (DCMD_ERR);
680 				}
681 				mdb_printf("  remote port: %p\n", irp.irp_rp);
682 				mdb_printf("  port id: %x\n", irp.irp_portid);
683 			}
684 		}
685 	}
686 	fct_irp_walk_f(&ws);
687 
688 	return (DCMD_OK);
689 }
690 
691 static uintptr_t cur_iport_for_irp_loop = NULL;
692 
693 static fct_i_remote_port_t *
694 next_rport(struct fct_i_local_port *iport)
695 {
696 	static uint64_t cbdata = 0;
697 	static mdb_walk_state_t ws = {walk_fct_irp_cb, &cbdata};
698 	int ret;
699 	fct_i_remote_port_t *irp;
700 
701 	if (ws.walk_addr == NULL || cur_iport_for_irp_loop !=
702 	    (uintptr_t)iport) {
703 		*((fct_i_remote_port_t **)ws.walk_cbdata) = NULL;
704 		cur_iport_for_irp_loop = (uintptr_t)iport;
705 		ws.walk_addr = (uintptr_t)iport;
706 		if (fct_irp_walk_i(&ws) == WALK_ERR) {
707 			fct_irp_walk_f(&ws);
708 			return (NULL);
709 		}
710 		if (ws.walk_addr == NULL) {
711 			fct_irp_walk_f(&ws);
712 			return (NULL);
713 		}
714 	}
715 
716 	while ((ret = fct_irp_walk_s(&ws)) == WALK_NEXT) {
717 		if (*((fct_i_remote_port_t **)ws.walk_cbdata) != 0) {
718 			irp = *((fct_i_remote_port_t **)ws.walk_cbdata);
719 			*((fct_i_remote_port_t **)ws.walk_cbdata) = NULL;
720 			return (irp);
721 		}
722 	}
723 	fct_irp_walk_f(&ws);
724 
725 	/*
726 	 * If it is WALK_DONE, there may be one remote port there
727 	 */
728 	if (ret == WALK_DONE) {
729 		irp = *((fct_i_remote_port_t **)ws.walk_cbdata);
730 		*((fct_i_remote_port_t **)ws.walk_cbdata) = NULL;
731 		return (irp);
732 	}
733 	return (NULL);
734 }
735 
736 static struct stmf_i_local_port *
737 irp_to_ilport(struct fct_i_remote_port *irpp)
738 {
739 	struct fct_i_remote_port irp;
740 	struct fct_remote_port rp;
741 	struct fct_local_port port;
742 	struct stmf_local_port lport;
743 
744 	if (mdb_vread(&irp, sizeof (struct fct_i_remote_port),
745 	    (uintptr_t)irpp)
746 	    != sizeof (struct fct_i_remote_port)) {
747 		mdb_warn("Unable to read in fct_i_remote_port\n");
748 		return (NULL);
749 	}
750 	if (mdb_vread(&rp, sizeof (struct fct_remote_port),
751 	    (uintptr_t)irp.irp_rp)
752 	    != sizeof (struct fct_remote_port)) {
753 		mdb_warn("Unable to read in fct_remote_port\n");
754 		return (NULL);
755 	}
756 
757 	if (mdb_vread(&port, sizeof (struct fct_local_port),
758 	    (uintptr_t)rp.rp_port)
759 	    != sizeof (struct fct_local_port)) {
760 		mdb_warn("Unable to read in fct_local_port\n");
761 		return (NULL);
762 	}
763 	if (mdb_vread(&lport, sizeof (struct stmf_local_port),
764 	    (uintptr_t)port.port_lport)
765 	    != sizeof (struct stmf_local_port)) {
766 		mdb_warn("Unable to read in stmf_local_port\n");
767 		return (NULL);
768 	}
769 	return (lport.lport_stmf_private);
770 }
771 
772 /*
773  * by wwn, we may find more than one remote port, so we need to know its
774  * corresponding local port
775  */
776 static struct fct_i_remote_port *
777 find_irp_by_wwn(struct stmf_i_local_port *siport, uint8_t wwn[8])
778 {
779 	struct fct_i_local_port *fiport;
780 	fct_i_remote_port_t *irpp;
781 	struct fct_i_remote_port irp;
782 	struct fct_remote_port rp;
783 	fct_i_remote_port_t *ret = NULL;
784 
785 	fiport = __ilport2iport((uintptr_t)siport, DCMD_ADDRSPEC, 0, NULL);
786 	if (fiport == NULL)
787 		return (NULL);
788 
789 	while ((irpp = next_rport(fiport)) != NULL) {
790 		if (mdb_vread(&irp, sizeof (struct fct_i_remote_port),
791 		    (uintptr_t)irpp)
792 		    != sizeof (struct fct_i_remote_port)) {
793 			mdb_warn("Unable to read in fct_i_remote_port\n");
794 			break;
795 		}
796 		if (mdb_vread(&rp, sizeof (struct fct_remote_port),
797 		    (uintptr_t)irp.irp_rp)
798 		    != sizeof (struct fct_remote_port)) {
799 			mdb_warn("Unable to read in fct_remote_port\n");
800 			break;
801 		}
802 
803 		if (memcmp(rp.rp_pwwn, wwn, 8) == 0) {
804 			ret = irpp;
805 			break;
806 		}
807 	}
808 	cur_iport_for_irp_loop = NULL;
809 	return (ret);
810 }
811 
812 /*ARGSUSED*/
813 static int
814 stmf_find_fct_irp(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
815 {
816 	struct stmf_i_local_port *siport;
817 	struct find_options *options;
818 	fct_i_remote_port_t *irpp;
819 	mdb_walk_state_t ws = {NULL, };
820 
821 	options = parse_options(argc, argv);
822 	/* need to free options manually ? */
823 	if (options == NULL || (options->rpname_defined == 0 &&
824 	    options->rp_defined == 0)) {
825 		mdb_printf("rpname=<wwn.12345678> or rp=<3000586778734>"
826 		    " should be specified\n");
827 		return (DCMD_OK);
828 	}
829 	if (options->rpname_defined && options->rp_defined) {
830 		mdb_printf("rpname=<wwn.12345678> or rp=<3000586778734>"
831 		    " should be specified, but not both\n");
832 		return (DCMD_OK);
833 	}
834 
835 	if (options->rp_defined) {
836 		siport = irp_to_ilport(options->rp);
837 		if (siport != NULL)
838 			mdb_printf("stmf_i_local_port=%p,"
839 			    " fct_i_remote_port=%p\n",
840 			    siport, options->rp);
841 		return (DCMD_OK);
842 	}
843 
844 	/* if options->rpname_defined */
845 	while ((siport = next_stmf_port(&ws)) != NULL) {
846 		if ((irpp = find_irp_by_wwn(siport, options->rpname)) != NULL)
847 			mdb_printf("stmf_i_local_port=%p, "
848 			    "fct_i_remote_port=%p\n",
849 			    siport, irpp);
850 	}
851 
852 	return (DCMD_OK);
853 }
854 
855 typedef void (*cmd_filter_t) (struct fct_i_cmd *,
856     struct find_options *, void *);
857 
858 /*ARGSUSED*/
859 static void
860 print_tasks(struct fct_i_cmd *icmdp, struct find_options *options, void *arg)
861 {
862 	struct fct_i_cmd icmd;
863 	struct fct_cmd cmd;
864 
865 	if (mdb_vread(&icmd, sizeof (struct fct_i_cmd),
866 	    (uintptr_t)icmdp) != sizeof (struct fct_i_cmd)) {
867 		mdb_warn("Unable to read in fct_i_cmd\n");
868 		return;
869 	}
870 	if (mdb_vread(&cmd, sizeof (struct fct_cmd),
871 	    (uintptr_t)icmd.icmd_cmd) != sizeof (struct fct_cmd)) {
872 		mdb_warn("Unable to read in fct_cmd\n");
873 		return;
874 	}
875 
876 	if (cmd.cmd_type == FCT_CMD_FCP_XCHG) {
877 		struct scsi_task task;
878 		int colon_printed = 0;
879 
880 		if (mdb_vread(&task, sizeof (struct scsi_task),
881 		    (uintptr_t)cmd.cmd_specific)
882 		    != sizeof (struct scsi_task)) {
883 			mdb_warn("Unable to read in scsi_task\n");
884 			return;
885 		}
886 
887 		mdb_printf("%p", cmd.cmd_specific);
888 		if (options->show_task_flags) {
889 			mdb_printf(":");
890 			colon_printed = 1;
891 			mdb_printf(" task_flags=%x", task.task_flags);
892 		}
893 
894 		if (options->show_lport) {
895 			if (colon_printed == 0) {
896 				mdb_printf(":");
897 				colon_printed = 1;
898 			}
899 			mdb_printf(" lport=%p", task.task_lport);
900 		}
901 		mdb_printf("\n");
902 	}
903 }
904 
905 static void
906 print_tasks_on_rp(struct fct_i_cmd *icmdp, struct find_options *options,
907     void *arg)
908 {
909 	struct fct_i_cmd icmd;
910 	struct fct_cmd cmd;
911 	fct_i_remote_port_t irp;
912 
913 	if (mdb_vread(&icmd, sizeof (struct fct_i_cmd),
914 	    (uintptr_t)icmdp) != sizeof (struct fct_i_cmd)) {
915 		mdb_warn("Unable to read in fct_i_cmd\n");
916 		return;
917 	}
918 	if (mdb_vread(&cmd, sizeof (struct fct_cmd),
919 	    (uintptr_t)icmd.icmd_cmd) != sizeof (struct fct_cmd)) {
920 		mdb_warn("Unable to read in fct_cmd\n");
921 		return;
922 	}
923 
924 	/* arg is a pointer to fct_i_remote_port */
925 	if (mdb_vread(&irp, sizeof (struct fct_i_remote_port),
926 	    (uintptr_t)arg) != sizeof (struct fct_i_remote_port)) {
927 		mdb_warn("Unable to read in fct_i_remote_port\n");
928 		return;
929 	}
930 
931 	if (cmd.cmd_type == FCT_CMD_FCP_XCHG && cmd.cmd_rp == irp.irp_rp) {
932 		struct scsi_task task;
933 		int colon_printed = 0;
934 
935 		if (mdb_vread(&task, sizeof (struct scsi_task),
936 		    (uintptr_t)cmd.cmd_specific)
937 		    != sizeof (struct scsi_task)) {
938 			mdb_warn("Unable to read in scsi_task\n");
939 			return;
940 		}
941 
942 		mdb_printf("%p", cmd.cmd_specific);
943 		if (options->show_task_flags) {
944 			mdb_printf(":");
945 			colon_printed = 1;
946 			mdb_printf(" task_flags=%x", task.task_flags);
947 		}
948 
949 		if (options->show_lport) {
950 			if (colon_printed == 0) {
951 				mdb_printf(":");
952 				colon_printed = 1;
953 			}
954 			mdb_printf(" lport=%p", task.task_lport);
955 		}
956 		mdb_printf("\n");
957 	}
958 }
959 
960 /*ARGSUSED*/
961 static void
962 print_all_cmds(struct fct_i_cmd *icmd, struct find_options *options, void *arg)
963 {
964 	mdb_printf("%p\n", icmd);
965 }
966 
967 /*
968  * find outstanding cmds (fct_i_cmd) on local port
969  */
970 static int
971 outstanding_cmds_on_lport(struct stmf_i_local_port *siport, cmd_filter_t filter,
972     struct find_options *options, void *arg)
973 {
974 	struct fct_i_local_port *iportp;
975 	struct fct_i_local_port iport;
976 	struct fct_local_port port;
977 	struct fct_cmd_slot *slotp;
978 	struct fct_cmd_slot slot;
979 	int i;
980 
981 	iportp = __ilport2iport((uintptr_t)siport, DCMD_ADDRSPEC, 0, NULL);
982 	if (iportp == NULL)
983 		return (DCMD_ERR);
984 
985 	if (mdb_vread(&iport, sizeof (struct fct_i_local_port),
986 	    (uintptr_t)iportp) != sizeof (struct fct_i_local_port)) {
987 		mdb_warn("Unable to read in fct_i_local_port\n");
988 		return (DCMD_ERR);
989 	}
990 	if (mdb_vread(&port, sizeof (struct fct_local_port),
991 	    (uintptr_t)iport.iport_port) != sizeof (struct fct_local_port)) {
992 		mdb_warn("Unable to read in fct_local_port\n");
993 		return (DCMD_ERR);
994 	}
995 
996 	slotp = iport.iport_cmd_slots;
997 	for (i = 0; i < port.port_max_xchges; i++) {
998 		if (mdb_vread(&slot, sizeof (struct fct_cmd_slot),
999 		    (uintptr_t)slotp) != sizeof (struct fct_cmd_slot)) {
1000 			mdb_warn("Unable to read in fct_cmd_slot\n");
1001 			return (DCMD_ERR);
1002 		}
1003 		if (slot.slot_cmd != NULL) {
1004 			if (filter == NULL)
1005 				mdb_printf("%p\n", slot.slot_cmd);
1006 			else
1007 				filter(slot.slot_cmd, options, arg);
1008 		}
1009 		slotp ++;
1010 	}
1011 
1012 	return (DCMD_OK);
1013 }
1014 
1015 /*ARGSUSED*/
1016 static int
1017 stmf_find_tasks(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1018 {
1019 	struct find_options *options;
1020 	struct stmf_i_local_port *siport;
1021 
1022 	options = parse_options(argc, argv);
1023 	if (options == NULL ||
1024 	    (options->lpname_defined == 0 && options->rpname_defined == 0)) {
1025 		mdb_printf("lpname=<wwn.12345678> or rpname=<wwn.12345678>"
1026 		    " should be specified\n");
1027 		return (DCMD_OK);
1028 	}
1029 
1030 	if (options->lpname_defined) {
1031 		siport = find_lport_by_wwn(options->lpname);
1032 		if (siport == NULL)
1033 			return (DCMD_ERR);
1034 
1035 		outstanding_cmds_on_lport(siport, print_tasks, options, NULL);
1036 		return (DCMD_OK);
1037 	}
1038 
1039 	if (options->rpname_defined) {
1040 		mdb_walk_state_t ws = {NULL, };
1041 		fct_i_remote_port_t *irpp;
1042 
1043 		while ((siport = next_stmf_port(&ws)) != NULL) {
1044 			if ((irpp = find_irp_by_wwn(siport, options->rpname))
1045 			    != NULL) {
1046 				outstanding_cmds_on_lport(siport,
1047 				    print_tasks_on_rp, options, irpp);
1048 			}
1049 		}
1050 	}
1051 
1052 	return (DCMD_OK);
1053 }
1054 
1055 /*ARGSUSED*/
1056 static int
1057 fct_find_cmds(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1058 {
1059 	struct find_options *options;
1060 	struct stmf_i_local_port *siport;
1061 
1062 	options = parse_options(argc, argv);
1063 	if (options == NULL || options->lpname_defined == 0) {
1064 		mdb_printf("lpname=<wwn.12345678> should be specified\n");
1065 		return (DCMD_OK);
1066 	}
1067 
1068 	siport = find_lport_by_wwn(options->lpname);
1069 	if (siport == NULL)
1070 		return (DCMD_ERR);
1071 
1072 	outstanding_cmds_on_lport(siport, print_all_cmds, options, NULL);
1073 	return (DCMD_OK);
1074 }
1075 
1076 static int
1077 fct_icmds(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1078 {
1079 	struct fct_i_local_port iport;
1080 	struct fct_i_cmd icmd;
1081 	struct fct_i_cmd *icmdp;
1082 	int i;
1083 	int verbose = 0;
1084 
1085 	for (i = 0; i < argc; i++) {
1086 		char *ptr = (char *)argv[i].a_un.a_str;
1087 
1088 		if (ptr[0] == '-')
1089 			ptr++;
1090 		while (*ptr) {
1091 			if (*ptr == 'v')
1092 				verbose = 1;
1093 			ptr++;
1094 		}
1095 	}
1096 
1097 	if (!(flags & DCMD_ADDRSPEC)) {
1098 		mdb_warn("fct_i_local_port_t address should be specified");
1099 		return (DCMD_ERR);
1100 	}
1101 
1102 	if (mdb_vread(&iport, sizeof (struct fct_i_local_port), addr)
1103 	    != sizeof (struct fct_i_local_port)) {
1104 		mdb_warn("Unable to read in fct_i_local_port at %p\n", addr);
1105 		return (DCMD_ERR);
1106 	}
1107 
1108 	icmdp = iport.iport_cached_cmdlist;
1109 	while (icmdp) {
1110 		if (mdb_vread(&icmd, sizeof (struct fct_i_cmd),
1111 		    (uintptr_t)icmdp) == -1) {
1112 			mdb_warn("failed to read fct_i_cmd at %p", icmdp);
1113 			return (DCMD_ERR);
1114 		}
1115 
1116 		mdb_printf("%p\n", icmdp);
1117 		if (verbose) {
1118 			mdb_printf("  fct cmd: %p\n", icmd.icmd_cmd);
1119 		}
1120 
1121 		icmdp = icmd.icmd_next;
1122 	}
1123 
1124 	return (DCMD_OK);
1125 }
1126 
1127 /*
1128  * Walker to list the addresses of all the active STMF scsi tasks (scsi_task_t),
1129  * given a stmf_worker address
1130  *
1131  * To list all the active STMF scsi tasks, use
1132  * "::walk stmf_worker |::walk stmf_scsi_task"
1133  * To list the active tasks of a particular worker, use
1134  * <stmf_worker addr>::walk stmf_scsi_task
1135  */
1136 static int
1137 stmf_scsi_task_walk_init(mdb_walk_state_t *wsp)
1138 {
1139 	stmf_worker_t	worker;
1140 
1141 	/*
1142 	 * Input should be a stmf_worker, so read it to get the
1143 	 * worker_task_head to get the start of the task list
1144 	 */
1145 	if (wsp->walk_addr == NULL) {
1146 		mdb_warn("<worker addr>::walk stmf_scsi_task\n");
1147 		return (WALK_ERR);
1148 	}
1149 
1150 	if (mdb_vread(&worker, sizeof (stmf_worker_t), wsp->walk_addr) !=
1151 	    sizeof (stmf_worker_t)) {
1152 		mdb_warn("failed to read in the task address\n");
1153 		return (WALK_ERR);
1154 	}
1155 
1156 	wsp->walk_addr = (uintptr_t)(worker.worker_task_head);
1157 	wsp->walk_data = mdb_alloc(sizeof (scsi_task_t), UM_SLEEP);
1158 
1159 	return (WALK_NEXT);
1160 }
1161 
1162 static int
1163 stmf_scsi_task_walk_step(mdb_walk_state_t *wsp)
1164 {
1165 	stmf_i_scsi_task_t	itask;
1166 	int			status;
1167 
1168 	if (wsp->walk_addr == NULL) {
1169 		return (WALK_DONE);
1170 	}
1171 
1172 	/* Save the stmf_i_scsi_task for use later to get the next entry */
1173 	if (mdb_vread(&itask, sizeof (stmf_i_scsi_task_t),
1174 	    wsp->walk_addr) != sizeof (stmf_i_scsi_task_t)) {
1175 		mdb_warn("failed to read stmf_i_scsi_task at %p",
1176 		    wsp->walk_addr);
1177 		return (WALK_DONE);
1178 	}
1179 
1180 	wsp->walk_addr = (uintptr_t)itask.itask_task;
1181 
1182 	if (mdb_vread(wsp->walk_data, sizeof (scsi_task_t),
1183 	    wsp->walk_addr) != sizeof (scsi_task_t)) {
1184 		mdb_warn("failed to read scsi_task_t at %p", wsp->walk_addr);
1185 		return (DCMD_ERR);
1186 	}
1187 
1188 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
1189 	    wsp->walk_cbdata);
1190 
1191 	wsp->walk_addr = (uintptr_t)(itask.itask_worker_next);
1192 
1193 	return (status);
1194 }
1195 
1196 static void
1197 stmf_scsi_task_walk_fini(mdb_walk_state_t *wsp)
1198 {
1199 	mdb_free(wsp->walk_data, sizeof (scsi_task_t));
1200 }
1201 
1202 /*ARGSUSED*/
1203 static int
1204 stmf_scsi_task(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1205 {
1206 	stmf_worker_t		worker;
1207 	stmf_i_scsi_task_t	itask;
1208 	scsi_task_t		*task_addr, task;
1209 
1210 	/*
1211 	 * A stmf_worker address is given to the left of ::stmf_scsi_task
1212 	 * i.e. display the scsi_task for the given worker
1213 	 */
1214 	if (!(flags & DCMD_ADDRSPEC)) {
1215 		if (mdb_walk_dcmd("stmf_worker", "stmf_scsi_task", argc,
1216 		    argv) == -1) {
1217 			mdb_warn("Failed to walk the stmf_scsi_task entries");
1218 			return (DCMD_ERR);
1219 		}
1220 		return (DCMD_OK);
1221 	}
1222 
1223 	if (DCMD_HDRSPEC(flags) && (!(flags & DCMD_PIPE_OUT))) {
1224 		mdb_printf("%<u>%-19s %-10s %-19s%</u>\n",
1225 		    "scsi_task_t", "Flags", "LPort");
1226 	}
1227 
1228 	if (mdb_vread(&worker, sizeof (stmf_worker_t),
1229 	    addr) != sizeof (stmf_worker_t)) {
1230 		mdb_warn("failed to read in the worker address");
1231 		return (DCMD_ERR);
1232 	}
1233 
1234 	/* Read the scsi_task */
1235 	if (worker.worker_task_head == NULL) {
1236 		return (DCMD_OK);
1237 	}
1238 
1239 	if (mdb_vread(&itask, sizeof (stmf_i_scsi_task_t),
1240 	    (uintptr_t)worker.worker_task_head) == -1) {
1241 		mdb_warn("failed to read stmf_i_scsi_task_t at %p",
1242 		    worker.worker_task_head);
1243 		return (DCMD_ERR);
1244 	}
1245 
1246 	task_addr = itask.itask_task;
1247 
1248 	if (mdb_vread(&task, sizeof (scsi_task_t),
1249 	    (uintptr_t)task_addr) != sizeof (scsi_task_t)) {
1250 		mdb_warn("failed to read scsi_task_t at %p", task_addr);
1251 		return (DCMD_ERR);
1252 	}
1253 
1254 	if ((flags & DCMD_PIPE_OUT)) {
1255 		mdb_printf("%p\n", task_addr);
1256 	} else {
1257 		/* pretty print */
1258 		mdb_printf("%-19p %-10x %-19p\n",
1259 		    task_addr, task.task_flags, task.task_lport);
1260 	}
1261 
1262 	return (DCMD_OK);
1263 }
1264 
1265 /*
1266  * Walker to list the addresses of all the stmf_worker in the queue
1267  */
1268 typedef struct stmf_worker_walk_data {
1269 	int		worker_current;
1270 	int		worker_count;
1271 } stmf_worker_walk_data_t;
1272 
1273 /* stmf_workers_state definition from stmf.c (static) */
1274 enum {
1275 	STMF_WORKERS_DISABLED = 0,
1276 	STMF_WORKERS_ENABLING,
1277 	STMF_WORKERS_ENABLED
1278 } stmf_workers_state;
1279 
1280 /*
1281  * Initialize the stmf_worker_t walker by either using the given starting
1282  * address, or reading the value of the kernel's global stmf_workers pointer.
1283  */
1284 /*ARGSUSED*/
1285 static int
1286 stmf_worker_walk_init(mdb_walk_state_t *wsp)
1287 {
1288 	int			worker_state;
1289 	int			nworkers;
1290 	stmf_worker_t		*worker;
1291 	stmf_worker_walk_data_t	*walk_data;
1292 
1293 	if (mdb_readvar(&worker_state, "stmf_workers_state") == -1) {
1294 		mdb_warn("failed to read stmf_workers_state");
1295 		return (WALK_ERR);
1296 	}
1297 	if (worker_state != STMF_WORKERS_ENABLED) {
1298 		mdb_warn("stmf_workers_state not initialized");
1299 		return (WALK_ERR);
1300 	}
1301 
1302 	/*
1303 	 * Look up the stmf_nworkers_accepting_cmds to
1304 	 * determine number of entries in the worker queue
1305 	 */
1306 	if (mdb_readvar(&nworkers, "stmf_nworkers_accepting_cmds") == -1) {
1307 		mdb_warn("failed to read stmf_nworkers_accepting_cmds");
1308 		return (WALK_ERR);
1309 	}
1310 
1311 	if (mdb_readvar(&worker, "stmf_workers") == -1) {
1312 		mdb_warn("failed to read stmf_workers");
1313 		return (WALK_ERR);
1314 	}
1315 
1316 	walk_data = mdb_alloc(sizeof (stmf_worker_walk_data_t), UM_SLEEP);
1317 	walk_data->worker_current	= 0;
1318 	walk_data->worker_count		= nworkers;
1319 
1320 	wsp->walk_addr = (uintptr_t)worker;
1321 	wsp->walk_data = walk_data;
1322 
1323 	return (WALK_NEXT);
1324 }
1325 
1326 static int
1327 stmf_worker_walk_step(mdb_walk_state_t *wsp)
1328 {
1329 	stmf_worker_walk_data_t	*walk_data = wsp->walk_data;
1330 	int			status;
1331 
1332 	if (wsp->walk_addr == NULL) {
1333 		return (WALK_DONE);
1334 	}
1335 
1336 	if (walk_data->worker_current >= walk_data->worker_count) {
1337 		return (WALK_DONE);
1338 	}
1339 
1340 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
1341 	    wsp->walk_cbdata);
1342 
1343 	walk_data->worker_current++;
1344 	wsp->walk_addr += sizeof (stmf_worker_t);
1345 
1346 	return (status);
1347 }
1348 
1349 static void
1350 stmf_worker_walk_fini(mdb_walk_state_t *wsp)
1351 {
1352 	mdb_free(wsp->walk_data, sizeof (stmf_worker_walk_data_t));
1353 }
1354 
1355 int
1356 stmf_worker(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1357 {
1358 	stmf_worker_t		worker;
1359 
1360 	if (!(flags & DCMD_ADDRSPEC)) {
1361 		if (mdb_walk_dcmd("stmf_worker", "stmf_worker", argc,
1362 		    argv) == -1) {
1363 			mdb_warn("Failed to walk the stmf_worker entries");
1364 			return (DCMD_ERR);
1365 		}
1366 		return (DCMD_OK);
1367 	}
1368 
1369 	if (mdb_vread(&worker, sizeof (stmf_worker_t),
1370 	    addr) != sizeof (stmf_worker_t)) {
1371 		mdb_warn("failed to read stmf_worker at %p", addr);
1372 		return (DCMD_ERR);
1373 	}
1374 
1375 	if (flags & DCMD_PIPE_OUT) {
1376 		mdb_printf("%-19p\n", addr);
1377 	} else {
1378 		/* pretty print */
1379 		if (DCMD_HDRSPEC(flags)) {
1380 			mdb_printf("%<u>%-19s %-10s %-10s %-10s%</u>\n",
1381 			    "stmf_worker_t", "State", "Ref_Count", "Tasks");
1382 		}
1383 
1384 		mdb_printf("%-19p %-10s %-10d %-5d%\n", addr,
1385 		    (worker.worker_flags == STMF_WORKER_STARTED) ? "STARTED" :
1386 		    (worker.worker_flags & STMF_WORKER_ACTIVE) ?
1387 		    "ACTIVE" : "TERMINATED",
1388 		    worker.worker_ref_count,
1389 		    worker.worker_queue_depth);
1390 	}
1391 
1392 	return (DCMD_OK);
1393 }
1394 
1395 struct find_options *
1396 parse_options(int argc, const mdb_arg_t *argv)
1397 {
1398 	int i;
1399 	struct find_options *options;
1400 	int len;
1401 	char *ptr;
1402 	int ret;
1403 
1404 	if (argc == 0)
1405 		return (NULL);
1406 	options = mdb_zalloc(sizeof (struct find_options), UM_SLEEP);
1407 	for (i = 0; i < argc; i++) {
1408 		switch (argv[i].a_type) {
1409 		case MDB_TYPE_STRING:
1410 			break;
1411 		case MDB_TYPE_IMMEDIATE:
1412 		case MDB_TYPE_CHAR:
1413 			mdb_printf("unknown type\n");
1414 		}
1415 		if ((ptr = strchr(argv[i].a_un.a_str, '=')) == NULL) {
1416 			mdb_printf("invalid argument: %s\n",
1417 			    argv[i].a_un.a_str);
1418 			goto out;
1419 		}
1420 		len = ptr - argv[i].a_un.a_str;
1421 		ptr++;	/* point to value now */
1422 
1423 		if (len == strlen("lpname") &&
1424 		    strncmp(argv[i].a_un.a_str, "lpname", len) == 0) {
1425 			if (strstr(ptr, "wwn.") == ptr)
1426 				ptr += 4;
1427 			ret = string2wwn(ptr, options->lpname);
1428 			if (ret == -1)
1429 				goto out;
1430 #if 0
1431 	mdb_printf("wwn=%02x%02x%02x%02x%02x%02x%02x%02x\n",
1432 	    wwn[0], wwn[1], wwn[2], wwn[3], wwn[4], wwn[5], wwn[6], wwn[7]);
1433 #endif
1434 			options->lpname_defined = 1;
1435 
1436 		} else if (len == strlen("rp") &&
1437 		    strncmp(argv[i].a_un.a_str, "rp", len) == 0) {
1438 			options->rp_defined = 1;
1439 			options->rp =
1440 			    (void *)(unsigned long)mdb_strtoull(ptr);
1441 
1442 		} else if (len == strlen("rpname") &&
1443 		    strncmp(argv[i].a_un.a_str, "rpname", len) == 0) {
1444 			if (strstr(ptr, "wwn.") == ptr)
1445 				ptr += 4;
1446 			ret = string2wwn(ptr, options->rpname);
1447 			if (ret == -1)
1448 				goto out;
1449 			options->rpname_defined = 1;
1450 
1451 		} else if (len == strlen("show") &&
1452 		    strncmp(argv[i].a_un.a_str, "show", len) == 0) {
1453 			char *s;
1454 			int l;
1455 
1456 			for (;;) {
1457 				s = strchr(ptr, ',');
1458 				if (s)
1459 					l = s - ptr;
1460 				else
1461 					l = strlen(ptr);
1462 				if (l == strlen("task_flags") &&
1463 				    strncmp(ptr, "task_flags", l) == 0)
1464 					options->show_task_flags = 1;
1465 				else if (l == strlen("lport") &&
1466 				    strncmp(ptr, "lport", l) == 0)
1467 					options->show_lport = 1;
1468 				else {
1469 					mdb_printf("unknown shower: %s\n",
1470 					    ptr);
1471 					goto out;
1472 				}
1473 				if (s == NULL)
1474 					break;
1475 				ptr = s + 1;
1476 			}
1477 		} else {
1478 			mdb_printf("unknown argument: %s\n",
1479 			    argv[i].a_un.a_str);
1480 			goto out;
1481 		}
1482 	}
1483 
1484 	return (options);
1485 out:
1486 	mdb_free(options, sizeof (struct find_options));
1487 	return (NULL);
1488 }
1489 
1490 int
1491 string2wwn(const char *s, uint8_t wwn[8])
1492 {
1493 	int i;
1494 	char tmp[17];
1495 	char *p;
1496 
1497 	if (strlen(s) > 16) {
1498 		mdb_printf("invalid wwn %s\n", s);
1499 		return (-1);
1500 	}
1501 
1502 	strcpy(tmp, s);
1503 	p = tmp + strlen(tmp) - 2;
1504 	memset(wwn, 0, 8);
1505 	/* figure out wwn from the tail to beginning */
1506 	for (i = 7; i >= 0 && p >= tmp; i--, p -= 2) {
1507 		wwn[i] = mdb_strtoull(p);
1508 		*p = 0;
1509 	}
1510 	return (0);
1511 }
1512 
1513 void
1514 fct_find_cmds_help(void)
1515 {
1516 	mdb_printf(
1517 	    "Find all cached fct_i_cmd_t for a local port. If a local port \n"
1518 	    "name is specified, find all pending cmds for it and print the \n"
1519 	    "address. Example:\n"
1520 	    "    fct_find_cmds lpname=<wwn.12345678 or 12345678>\n");
1521 }
1522 void
1523 stmf_find_ilport_help(void)
1524 {
1525 	mdb_printf(
1526 	    "Find the fct_i_local_port if local port name is "
1527 	    "specified. Example:\n"
1528 	    "    stmf_find_ilport lpname=<wwn.12345678 or 12345678>\n");
1529 }
1530 void
1531 stmf_find_fct_irp_help(void)
1532 {
1533 	mdb_printf(
1534 	    "If a remote port name or stmf_i_remote_port_t address is\n"
1535 	    "specified, loop through all local ports, to which this remote \n"
1536 	    "port has logged in, print address for stmf_i_local_port_t and \n"
1537 	    "stmf_i_remote_port. Example:\n"
1538 	    "    stmf_find_fct_irp rpname=<wwn.12345678 or 12345678>\n"
1539 	    "    stmf_find_fct_irp rp=<3000586778734>\n");
1540 }
1541 
1542 void
1543 stmf_find_tasks_help(void)
1544 {
1545 	mdb_printf(
1546 	    "Find all pending scsi_task_t for a given local port and/or\n"
1547 	    "remote port. Various different fields for each task are printed\n"
1548 	    "depending on what is requested. Example:\n"
1549 	    "    stmf_find_tasks rpname=<wwn.12345678 or 12345678>\n"
1550 	    "    stmf_find_tasks lpname=<wwn.12345678 or 12345678> "
1551 	    "show=task_flags,lport\n");
1552 }
1553 
1554 void
1555 stmf_scsi_task_help(void)
1556 {
1557 	mdb_printf(
1558 	    "List all active scsi_task_t on a given stmf_worker_t. Example\n"
1559 	    "    addr::stmf_scsi_task\n");
1560 }
1561 
1562 static const mdb_dcmd_t dcmds[] = {
1563 	{ "stmf_ilports", "[-v]",
1564 	    "Print a list of stmf_i_local_port", stmf_ilports },
1565 	{ "ilport2iport", "?[-v]",
1566 	    "Convert stmf_i_local_port to corresponding fct_i_local_port",
1567 	    ilport2iport },
1568 	{ "stmf_iss", "?[-v]",
1569 	    "List all active sessions for a given local port",
1570 	    stmf_iss },
1571 	{ "stmf_ilus", "[-v]", "Print a list of stmf_i_lu", stmf_ilus },
1572 	{ "stmf_i_lu_providers", "[-v]",
1573 	    "Print a list of stmf_i_lu_provider", stmf_i_lu_providers },
1574 	{ "stmf_i_port_providers", "[-v]",
1575 	    "Print a list of stmf_i_port_provider", stmf_i_port_providers },
1576 	{ "fct_irps", "?[-v]",
1577 	    "Print all fct_i_remote_port for a given fct_i_local_port",
1578 	    fct_irps },
1579 	{ "fct_icmds", "?[-v]",
1580 	    "Print all cached fct_i_cmd_t on fct_i_local_port",
1581 	    fct_icmds },
1582 	{ "fct_find_cmds", "lpname",
1583 	    "Find all fct_i_cmd_t for a given local port",
1584 	    fct_find_cmds, fct_find_cmds_help},
1585 	{ "stmf_find_ilport", "lpname",
1586 	    "Find local port information based on its wwn",
1587 	    stmf_find_ilport, stmf_find_ilport_help},
1588 	{ "stmf_find_fct_irp", "rpname|rp",
1589 	    "Print fct remote port information based on its wwn",
1590 	    stmf_find_fct_irp, stmf_find_fct_irp_help},
1591 	{ "stmf_find_tasks", "lpname|rpname [show]",
1592 	    "Find all pending task for a local port or remote port",
1593 	    stmf_find_tasks, stmf_find_tasks_help},
1594 	{ "stmf_worker", "?", "List all the stmf_worker entries", stmf_worker},
1595 	{ "stmf_scsi_task", ":",
1596 	    "List all the active STMF SCSI tasks per worker", stmf_scsi_task,
1597 	    stmf_scsi_task_help},
1598 	{ NULL }
1599 };
1600 
1601 static const mdb_walker_t walkers[] = {
1602 	{ "stmf_worker", "Walk STMF worker queue", stmf_worker_walk_init,
1603 	    stmf_worker_walk_step, stmf_worker_walk_fini},
1604 	{ "stmf_scsi_task", "Walk active STMF SCSI tasks per worker",
1605 	    stmf_scsi_task_walk_init,
1606 	    stmf_scsi_task_walk_step, stmf_scsi_task_walk_fini },
1607 	{ NULL }
1608 };
1609 
1610 static const mdb_modinfo_t modinfo = {
1611 	MDB_API_VERSION, dcmds, walkers
1612 };
1613 
1614 const mdb_modinfo_t *
1615 _mdb_init(void)
1616 {
1617 	return (&modinfo);
1618 }
1619