xref: /illumos-gate/usr/src/cmd/mdb/common/modules/stmf/stmf.c (revision fcf3ce441efd61da9bb2884968af01cb7c1452cc)
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 2008 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 struct find_options *
1128 parse_options(int argc, const mdb_arg_t *argv)
1129 {
1130 	int i;
1131 	struct find_options *options;
1132 	int len;
1133 	char *ptr;
1134 	int ret;
1135 
1136 	if (argc == 0)
1137 		return (NULL);
1138 	options = mdb_zalloc(sizeof (struct find_options), UM_SLEEP);
1139 	for (i = 0; i < argc; i++) {
1140 		switch (argv[i].a_type) {
1141 		case MDB_TYPE_STRING:
1142 			break;
1143 		case MDB_TYPE_IMMEDIATE:
1144 		case MDB_TYPE_CHAR:
1145 			mdb_printf("unknown type\n");
1146 		}
1147 		if ((ptr = strchr(argv[i].a_un.a_str, '=')) == NULL) {
1148 			mdb_printf("invalid argument: %s\n",
1149 			    argv[i].a_un.a_str);
1150 			goto out;
1151 		}
1152 		len = ptr - argv[i].a_un.a_str;
1153 		ptr++;	/* point to value now */
1154 
1155 		if (len == strlen("lpname") &&
1156 		    strncmp(argv[i].a_un.a_str, "lpname", len) == 0) {
1157 			if (strstr(ptr, "wwn.") == ptr)
1158 				ptr += 4;
1159 			ret = string2wwn(ptr, options->lpname);
1160 			if (ret == -1)
1161 				goto out;
1162 #if 0
1163 	mdb_printf("wwn=%02x%02x%02x%02x%02x%02x%02x%02x\n",
1164 	    wwn[0], wwn[1], wwn[2], wwn[3], wwn[4], wwn[5], wwn[6], wwn[7]);
1165 #endif
1166 			options->lpname_defined = 1;
1167 
1168 		} else if (len == strlen("rp") &&
1169 		    strncmp(argv[i].a_un.a_str, "rp", len) == 0) {
1170 			options->rp_defined = 1;
1171 			options->rp =
1172 			    (void *)(unsigned long)mdb_strtoull(ptr);
1173 
1174 		} else if (len == strlen("rpname") &&
1175 		    strncmp(argv[i].a_un.a_str, "rpname", len) == 0) {
1176 			if (strstr(ptr, "wwn.") == ptr)
1177 				ptr += 4;
1178 			ret = string2wwn(ptr, options->rpname);
1179 			if (ret == -1)
1180 				goto out;
1181 			options->rpname_defined = 1;
1182 
1183 		} else if (len == strlen("show") &&
1184 		    strncmp(argv[i].a_un.a_str, "show", len) == 0) {
1185 			char *s;
1186 			int l;
1187 
1188 			for (;;) {
1189 				s = strchr(ptr, ',');
1190 				if (s)
1191 					l = s - ptr;
1192 				else
1193 					l = strlen(ptr);
1194 				if (l == strlen("task_flags") &&
1195 				    strncmp(ptr, "task_flags", l) == 0)
1196 					options->show_task_flags = 1;
1197 				else if (l == strlen("lport") &&
1198 				    strncmp(ptr, "lport", l) == 0)
1199 					options->show_lport = 1;
1200 				else {
1201 					mdb_printf("unknown shower: %s\n",
1202 					    ptr);
1203 					goto out;
1204 				}
1205 				if (s == NULL)
1206 					break;
1207 				ptr = s + 1;
1208 			}
1209 		} else {
1210 			mdb_printf("unknown argument: %s\n",
1211 			    argv[i].a_un.a_str);
1212 			goto out;
1213 		}
1214 	}
1215 
1216 	return (options);
1217 out:
1218 	mdb_free(options, sizeof (struct find_options));
1219 	return (NULL);
1220 }
1221 
1222 int
1223 string2wwn(const char *s, uint8_t wwn[8])
1224 {
1225 	int i;
1226 	char tmp[17];
1227 	char *p;
1228 
1229 	if (strlen(s) > 16) {
1230 		mdb_printf("invalid wwn %s\n", s);
1231 		return (-1);
1232 	}
1233 
1234 	strcpy(tmp, s);
1235 	p = tmp + strlen(tmp) - 2;
1236 	memset(wwn, 0, 8);
1237 	/* figure out wwn from the tail to beginning */
1238 	for (i = 7; i >= 0 && p >= tmp; i--, p -= 2) {
1239 		wwn[i] = mdb_strtoull(p);
1240 		*p = 0;
1241 	}
1242 	return (0);
1243 }
1244 
1245 void
1246 fct_find_cmds_help(void)
1247 {
1248 	mdb_printf(
1249 	    "Find all cached fct_i_cmd_t for a local port. If a local port \n"
1250 	    "name is specified, find all pending cmds for it and print the \n"
1251 	    "address. Example:\n"
1252 	    "    fct_find_cmds lpname=<wwn.12345678 or 12345678>\n");
1253 }
1254 void
1255 stmf_find_ilport_help(void)
1256 {
1257 	mdb_printf(
1258 	    "Find the fct_i_local_port if local port name is "
1259 	    "specified. Example:\n"
1260 	    "    stmf_find_ilport lpname=<wwn.12345678 or 12345678>\n");
1261 }
1262 void
1263 stmf_find_fct_irp_help(void)
1264 {
1265 	mdb_printf(
1266 	    "If a remote port name or stmf_i_remote_port_t address is\n"
1267 	    "specified, loop through all local ports, to which this remote \n"
1268 	    "port has logged in, print address for stmf_i_local_port_t and \n"
1269 	    "stmf_i_remote_port. Example:\n"
1270 	    "    stmf_find_fct_irp rpname=<wwn.12345678 or 12345678>\n"
1271 	    "    stmf_find_fct_irp rp=<3000586778734>\n");
1272 }
1273 void
1274 stmf_find_tasks_help(void)
1275 {
1276 	mdb_printf(
1277 	    "Find all pending scsi_task_t for a given local port and/or\n"
1278 	    "remote port. Various different fields for each task are printed\n"
1279 	    "depending on what is requested. Example:\n"
1280 	    "    stmf_find_tasks rpname=<wwn.12345678 or 12345678>\n"
1281 	    "    stmf_find_tasks lpname=<wwn.12345678 or 12345678> "
1282 	    "show=task_flags,lport\n");
1283 }
1284 
1285 static const mdb_dcmd_t dcmds[] = {
1286 	{ "stmf_ilports", "[-v]",
1287 	    "Print a list of stmf_i_local_port", stmf_ilports },
1288 	{ "ilport2iport", "?[-v]",
1289 	    "Convert stmf_i_local_port to corresponding fct_i_local_port",
1290 	    ilport2iport },
1291 	{ "stmf_iss", "?[-v]",
1292 	    "List all active sessions for a given local port",
1293 	    stmf_iss },
1294 	{ "stmf_ilus", "[-v]", "Print a list of stmf_i_lu", stmf_ilus },
1295 	{ "stmf_i_lu_providers", "[-v]",
1296 	    "Print a list of stmf_i_lu_provider", stmf_i_lu_providers },
1297 	{ "stmf_i_port_providers", "[-v]",
1298 	    "Print a list of stmf_i_port_provider", stmf_i_port_providers },
1299 	{ "fct_irps", "?[-v]",
1300 	    "Print all fct_i_remote_port for a given fct_i_local_port",
1301 	    fct_irps },
1302 	{ "fct_icmds", "?[-v]",
1303 	    "Print all cached fct_i_cmd_t on fct_i_local_port",
1304 	    fct_icmds },
1305 	{ "fct_find_cmds", "lpname",
1306 	    "Find all fct_i_cmd_t for a given local port",
1307 	    fct_find_cmds, fct_find_cmds_help},
1308 	{ "stmf_find_ilport", "lpname",
1309 	    "Find local port information based on its wwn",
1310 	    stmf_find_ilport, stmf_find_ilport_help},
1311 	{ "stmf_find_fct_irp", "rpname|rp",
1312 	    "Print fct remote port information based on its wwn",
1313 	    stmf_find_fct_irp, stmf_find_fct_irp_help},
1314 	{ "stmf_find_tasks", "lpname|rpname [show]",
1315 	    "Find all pending task for a local port or remote port",
1316 	    stmf_find_tasks, stmf_find_tasks_help},
1317 	{ NULL }
1318 };
1319 
1320 static const mdb_walker_t walkers[] = {
1321 	{ NULL }
1322 };
1323 
1324 static const mdb_modinfo_t modinfo = {
1325 	MDB_API_VERSION, dcmds, walkers
1326 };
1327 
1328 const mdb_modinfo_t *
1329 _mdb_init(void)
1330 {
1331 	return (&modinfo);
1332 }
1333