xref: /illumos-gate/usr/src/cmd/mdb/common/modules/fcp/fcp.c (revision 45ede40b2394db7967e59f19288fae9b62efd4aa)
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  * Copyright (c) 2018, Joyent, Inc.
26  */
27 
28 
29 #include <sys/mdb_modapi.h>
30 #include <sys/mutex.h>
31 #include <sys/modctl.h>
32 #include <sys/scsi/scsi.h>
33 #include <sys/sunndi.h>
34 #include <sys/fibre-channel/fc.h>
35 #include <sys/fibre-channel/ulp/fcpvar.h>
36 
37 static struct fcp_port	port;
38 static struct fcp_tgt	tgt;
39 static struct fcp_lun	lun;
40 static uint32_t	tgt_hash_index;
41 
42 
43 /*
44  * Leadville fcp walker/dcmd code
45  */
46 
47 static int
48 fcp_walk_i(mdb_walk_state_t *wsp)
49 {
50 	if (wsp->walk_addr == 0 &&
51 	    mdb_readvar(&wsp->walk_addr, "fcp_port_head") == -1) {
52 		mdb_warn("failed to read 'fcp_port_head'");
53 		return (WALK_ERR);
54 	}
55 
56 	wsp->walk_data = mdb_alloc(sizeof (struct fcp_port), UM_SLEEP);
57 	return (WALK_NEXT);
58 }
59 
60 static int
61 fcp_walk_s(mdb_walk_state_t *wsp)
62 {
63 	int status;
64 
65 	if (wsp->walk_addr == 0)
66 		return (WALK_DONE);
67 
68 	if (mdb_vread(wsp->walk_data, sizeof (struct fcp_port),
69 	    wsp->walk_addr) == -1) {
70 		mdb_warn("failed to read fcp_port at %p", wsp->walk_addr);
71 		return (WALK_DONE);
72 	}
73 
74 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
75 	    wsp->walk_cbdata);
76 
77 	wsp->walk_addr =
78 	    (uintptr_t)(((struct fcp_port *)wsp->walk_data)->port_next);
79 
80 	return (status);
81 }
82 
83 /*
84  * The walker's fini function is invoked at the end of each walk.
85  */
86 static void
87 fcp_walk_f(mdb_walk_state_t *wsp)
88 {
89 	mdb_free(wsp->walk_data, sizeof (struct fcp_port));
90 }
91 
92 
93 static int
94 fcp(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
95 {
96 	struct fcp_port		pinfo;
97 
98 	if (argc != 0) {
99 		return (DCMD_USAGE);
100 	}
101 
102 	if (!(flags & DCMD_ADDRSPEC)) {
103 		if (mdb_walk_dcmd("fcp", "fcp",
104 		    argc, argv) == -1) {
105 			mdb_warn("failed to walk 'fcp_port_head'");
106 			return (DCMD_ERR);
107 		}
108 		return (DCMD_OK);
109 	}
110 
111 	mdb_printf("FCP structure at %p\n", addr);
112 
113 	/*
114 	 * For each port, we just need to read the fc_fca_port_t struct, read
115 	 * the port_handle
116 	 */
117 	if (mdb_vread(&pinfo, sizeof (struct fcp_port), addr) !=
118 	    sizeof (struct fcp_port)) {
119 		mdb_warn("failed to read fcp_port at %p", addr);
120 		return (DCMD_OK);
121 	}
122 
123 	mdb_printf("  mutex             : 0x%-08x\n", pinfo.port_mutex);
124 	mdb_printf("  ipkt_list         : 0x%p\n", pinfo.port_ipkt_list);
125 	mdb_printf("  state             : 0x%-08x\n", pinfo.port_state);
126 	mdb_printf("  phys_state        : 0x%-08x\n", pinfo.port_phys_state);
127 	mdb_printf("  top               : %u\n", pinfo.port_topology);
128 	mdb_printf("  sid               : 0x%-06x\n", pinfo.port_id);
129 	mdb_printf("  reset_list        : 0x%p\n", pinfo.port_reset_list);
130 	mdb_printf("  link_cnt          : %u\n", pinfo.port_link_cnt);
131 	mdb_printf("  deadline          : %d\n", pinfo.port_deadline);
132 	mdb_printf("  port wwn          : "
133 	    "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
134 	    pinfo.port_pwwn.raw_wwn[0], pinfo.port_pwwn.raw_wwn[1],
135 	    pinfo.port_pwwn.raw_wwn[2], pinfo.port_pwwn.raw_wwn[3],
136 	    pinfo.port_pwwn.raw_wwn[4], pinfo.port_pwwn.raw_wwn[5],
137 	    pinfo.port_pwwn.raw_wwn[6], pinfo.port_pwwn.raw_wwn[7]);
138 	mdb_printf("  node wwn          : "
139 	    "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
140 	    pinfo.port_nwwn.raw_wwn[0], pinfo.port_nwwn.raw_wwn[1],
141 	    pinfo.port_nwwn.raw_wwn[2], pinfo.port_nwwn.raw_wwn[3],
142 	    pinfo.port_nwwn.raw_wwn[4], pinfo.port_nwwn.raw_wwn[5],
143 	    pinfo.port_nwwn.raw_wwn[6], pinfo.port_nwwn.raw_wwn[7]);
144 	mdb_printf("  handle            : 0x%p\n", pinfo.port_fp_handle);
145 	mdb_printf("  cmd_mutex         : 0x%-08x\n", pinfo.port_pkt_mutex);
146 	mdb_printf("  ncmds             : %u\n", pinfo.port_npkts);
147 	mdb_printf("  pkt_head          : 0x%p\n", pinfo.port_pkt_head);
148 	mdb_printf("  pkt_tail          : 0x%p\n", pinfo.port_pkt_tail);
149 	mdb_printf("  ipkt_cnt          : %d\n", pinfo.port_ipkt_cnt);
150 	mdb_printf("  instance          : %u\n", pinfo.port_instance);
151 	mdb_printf("  max_exch          : %u\n", pinfo.port_max_exch);
152 	mdb_printf("  cmds_aborted      : 0x%-08x\n",
153 	    pinfo.port_reset_action);
154 	mdb_printf("  cmds_dma_flags    : 0x%-08x\n",
155 	    pinfo.port_cmds_dma_flags);
156 	mdb_printf("  fcp_dma           : 0x%-08x\n", pinfo.port_fcp_dma);
157 	mdb_printf("  priv_pkt_len      : %u\n", pinfo.port_priv_pkt_len);
158 	mdb_printf("  data_dma_attr     : 0x%-08x\n",
159 	    pinfo.port_data_dma_attr);
160 	mdb_printf("  cmd_dma_attr      : 0x%-08x\n",
161 	    pinfo.port_cmd_dma_attr);
162 	mdb_printf("  resp_dma_attr     : 0x%-08x\n",
163 	    pinfo.port_resp_dma_attr);
164 	mdb_printf("  dma_acc_attr      : 0x%-08x\n",
165 	    pinfo.port_dma_acc_attr);
166 	mdb_printf("  tran              : 0x%p\n", pinfo.port_tran);
167 	mdb_printf("  dip               : 0x%p\n", pinfo.port_dip);
168 	mdb_printf("  reset_notify_listf: 0x%p\n",
169 	    pinfo.port_reset_notify_listf);
170 	mdb_printf("  event_defs        : 0x%p\n", pinfo.port_ndi_event_defs);
171 	mdb_printf("  event_hdl         : 0x%p\n", pinfo.port_ndi_event_hdl);
172 	mdb_printf("  events            : 0x%p\n", pinfo.port_ndi_events);
173 	mdb_printf("  tgt_hash_table    : 0x%p\n", pinfo.port_tgt_hash_table);
174 	mdb_printf("  mpxio             : %d\n", pinfo.port_mpxio);
175 
176 	mdb_printf("\n");
177 
178 	return (DCMD_OK);
179 }
180 
181 
182 /*
183  * Leadville cmds walker/dcmd code
184  */
185 
186 static int
187 cmds_walk_i(mdb_walk_state_t *wsp)
188 {
189 	if (wsp->walk_addr == 0) {
190 		mdb_warn("Can not perform global walk");
191 		return (WALK_ERR);
192 	}
193 
194 	/*
195 	 * Input should be a fcp_lun, so read it to get the fcp_pkt
196 	 * lists's head
197 	 */
198 
199 	if (mdb_vread(&lun, sizeof (struct fcp_lun), wsp->walk_addr) !=
200 	    sizeof (struct fcp_lun)) {
201 		mdb_warn("Unable to read in the fcp_lun structure address\n");
202 		return (WALK_ERR);
203 	}
204 
205 	wsp->walk_addr = (uintptr_t)(lun.lun_pkt_head);
206 	wsp->walk_data = mdb_alloc(sizeof (struct fcp_pkt), UM_SLEEP);
207 
208 	return (WALK_NEXT);
209 }
210 
211 static int
212 cmds_walk_s(mdb_walk_state_t *wsp)
213 {
214 	int status;
215 
216 	if (wsp->walk_addr == 0)
217 		return (WALK_DONE);
218 
219 	if (mdb_vread(wsp->walk_data, sizeof (struct fcp_pkt),
220 	    wsp->walk_addr) == -1) {
221 		mdb_warn("failed to read fcp_pkt at %p", wsp->walk_addr);
222 		return (WALK_DONE);
223 	}
224 
225 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
226 	    wsp->walk_cbdata);
227 
228 	wsp->walk_addr =
229 	    (uintptr_t)(((struct fcp_pkt *)wsp->walk_data)->cmd_forw);
230 
231 	return (status);
232 }
233 
234 /*
235  * The walker's fini function is invoked at the end of each walk.
236  */
237 static void
238 cmds_walk_f(mdb_walk_state_t *wsp)
239 {
240 	mdb_free(wsp->walk_data, sizeof (struct fcp_pkt));
241 }
242 
243 
244 /*
245  * Leadville luns walker/dcmd code
246  */
247 
248 static int
249 luns_walk_i(mdb_walk_state_t *wsp)
250 {
251 	if (wsp->walk_addr == 0) {
252 		mdb_warn("Can not perform global walk");
253 		return (WALK_ERR);
254 	}
255 
256 	/*
257 	 * Input should be a fcp_tgt, so read it to get the fcp_lun
258 	 * lists's head
259 	 */
260 
261 	if (mdb_vread(&tgt, sizeof (struct fcp_tgt), wsp->walk_addr) !=
262 	    sizeof (struct fcp_tgt)) {
263 		mdb_warn("Unable to read in the fcp_tgt structure address\n");
264 		return (WALK_ERR);
265 	}
266 
267 	wsp->walk_addr = (uintptr_t)(tgt.tgt_lun);
268 	wsp->walk_data = mdb_alloc(sizeof (struct fcp_lun), UM_SLEEP);
269 
270 	return (WALK_NEXT);
271 }
272 
273 static int
274 luns_walk_s(mdb_walk_state_t *wsp)
275 {
276 	int status;
277 
278 	if (wsp->walk_addr == 0)
279 		return (WALK_DONE);
280 
281 	if (mdb_vread(wsp->walk_data, sizeof (struct fcp_lun),
282 	    wsp->walk_addr) == -1) {
283 		mdb_warn("failed to read fcp_pkt at %p", wsp->walk_addr);
284 		return (WALK_DONE);
285 	}
286 
287 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
288 	    wsp->walk_cbdata);
289 
290 	wsp->walk_addr =
291 	    (uintptr_t)(((struct fcp_lun *)wsp->walk_data)->lun_next);
292 
293 	return (status);
294 }
295 
296 /*
297  * The walker's fini function is invoked at the end of each walk.
298  */
299 static void
300 luns_walk_f(mdb_walk_state_t *wsp)
301 {
302 	mdb_free(wsp->walk_data, sizeof (struct fcp_lun));
303 }
304 
305 
306 /*
307  * Leadville targets walker/dcmd code
308  */
309 
310 static int
311 targets_walk_i(mdb_walk_state_t *wsp)
312 {
313 	if (wsp->walk_addr == 0) {
314 		mdb_warn("Can not perform global walk\n");
315 		return (WALK_ERR);
316 	}
317 
318 	/*
319 	 * Input should be a fcp_port, so read it to get the port_tgt
320 	 * table's head
321 	 */
322 
323 	if (mdb_vread(&port, sizeof (struct fcp_port), wsp->walk_addr) !=
324 	    sizeof (struct fcp_port)) {
325 		mdb_warn("Unable to read in the port structure address\n");
326 		return (WALK_ERR);
327 	}
328 
329 	tgt_hash_index = 0;
330 
331 	while (tgt_hash_index < FCP_NUM_HASH &&
332 	    port.port_tgt_hash_table[tgt_hash_index] == NULL) {
333 		tgt_hash_index++;
334 	}
335 
336 	wsp->walk_addr = (uintptr_t)(port.port_tgt_hash_table[tgt_hash_index]);
337 
338 	wsp->walk_data = mdb_alloc(sizeof (struct fcp_tgt), UM_SLEEP);
339 
340 	return (WALK_NEXT);
341 }
342 
343 static int
344 targets_walk_s(mdb_walk_state_t *wsp)
345 {
346 	int status;
347 
348 	if ((wsp->walk_addr == 0) &&
349 	    (tgt_hash_index >= (FCP_NUM_HASH - 1))) {
350 		return (WALK_DONE);
351 	}
352 
353 	if (mdb_vread(wsp->walk_data, sizeof (struct fcp_tgt),
354 	    wsp->walk_addr) == -1) {
355 		mdb_warn("failed to read fcp_tgt at %p", wsp->walk_addr);
356 		return (WALK_DONE);
357 	}
358 
359 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
360 	    wsp->walk_cbdata);
361 
362 	wsp->walk_addr =
363 	    (uintptr_t)(((struct fcp_tgt *)wsp->walk_data)->tgt_next);
364 
365 	if (wsp->walk_addr == 0) {
366 		/*
367 		 * locate the next hash list
368 		 */
369 
370 		tgt_hash_index++;
371 
372 		while (tgt_hash_index < FCP_NUM_HASH &&
373 		    port.port_tgt_hash_table[tgt_hash_index] == NULL)
374 			tgt_hash_index++;
375 
376 		if (tgt_hash_index == FCP_NUM_HASH) {
377 			/* You're done */
378 			return (status);
379 		}
380 
381 		wsp->walk_addr =
382 		    (uintptr_t)(port.port_tgt_hash_table[tgt_hash_index]);
383 	}
384 
385 	return (status);
386 }
387 
388 /*
389  * The walker's fini function is invoked at the end of each walk.
390  */
391 static void
392 targets_walk_f(mdb_walk_state_t *wsp)
393 {
394 	mdb_free(wsp->walk_data, sizeof (struct fcp_tgt));
395 }
396 
397 
398 /*
399  * Leadville fcp_ipkt walker/dcmd code
400  */
401 
402 static int
403 ipkt_walk_i(mdb_walk_state_t *wsp)
404 {
405 	if (wsp->walk_addr == 0) {
406 		mdb_warn("The address of a fcp_port"
407 		    " structure must be given\n");
408 		return (WALK_ERR);
409 	}
410 
411 	/*
412 	 * Input should be a fcp_port, so read it to get the ipkt
413 	 * list's head
414 	 */
415 
416 	if (mdb_vread(&port, sizeof (struct fcp_port), wsp->walk_addr) !=
417 	    sizeof (struct fcp_port)) {
418 		mdb_warn("Failed to read in the fcp_port"
419 		    " at 0x%p\n", wsp->walk_addr);
420 		return (WALK_ERR);
421 	}
422 
423 	wsp->walk_addr = (uintptr_t)(port.port_ipkt_list);
424 	wsp->walk_data = mdb_alloc(sizeof (struct fcp_ipkt), UM_SLEEP);
425 
426 	return (WALK_NEXT);
427 }
428 
429 static int
430 ipkt_walk_s(mdb_walk_state_t *wsp)
431 {
432 	int status;
433 
434 	if (wsp->walk_addr == 0)
435 		return (WALK_DONE);
436 
437 	if (mdb_vread(wsp->walk_data, sizeof (struct fcp_ipkt),
438 	    wsp->walk_addr) == -1) {
439 		mdb_warn("Failed to read in the fcp_ipkt"
440 		    " at 0x%p\n", wsp->walk_addr);
441 		return (WALK_DONE);
442 	}
443 
444 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
445 	    wsp->walk_cbdata);
446 
447 	wsp->walk_addr =
448 	    (uintptr_t)(((struct fcp_ipkt *)wsp->walk_data)->ipkt_next);
449 
450 	return (status);
451 }
452 
453 /*
454  * The walker's fini function is invoked at the end of each walk.
455  */
456 static void
457 ipkt_walk_f(mdb_walk_state_t *wsp)
458 {
459 	mdb_free(wsp->walk_data, sizeof (struct fcp_ipkt));
460 }
461 
462 /*
463  * Leadville fcp_pkt walker/dcmd code
464  */
465 
466 static int
467 pkt_walk_i(mdb_walk_state_t *wsp)
468 {
469 	if (wsp->walk_addr == 0) {
470 		mdb_warn("The address of a fcp_port"
471 		    " structure must be given\n");
472 		return (WALK_ERR);
473 	}
474 
475 	/*
476 	 * Input should be an fcp_port, so read it to get the pkt
477 	 * list's head
478 	 */
479 
480 	if (mdb_vread(&port, sizeof (struct fcp_port), wsp->walk_addr) !=
481 	    sizeof (struct fcp_port)) {
482 		mdb_warn("Failed to read in the fcp_port"
483 		    " at 0x%p\n", wsp->walk_addr);
484 		return (WALK_ERR);
485 	}
486 
487 	wsp->walk_addr = (uintptr_t)(port.port_pkt_head);
488 	wsp->walk_data = mdb_alloc(sizeof (struct fcp_pkt), UM_SLEEP);
489 
490 	return (WALK_NEXT);
491 }
492 
493 static int
494 pkt_walk_s(mdb_walk_state_t *wsp)
495 {
496 	int status;
497 
498 	if (wsp->walk_addr == 0)
499 		return (WALK_DONE);
500 
501 	if (mdb_vread(wsp->walk_data, sizeof (struct fcp_pkt),
502 	    wsp->walk_addr) == -1) {
503 		mdb_warn("Failed to read in the fcp_pkt"
504 		    " at 0x%p\n", wsp->walk_addr);
505 		return (WALK_DONE);
506 	}
507 
508 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
509 	    wsp->walk_cbdata);
510 
511 	wsp->walk_addr =
512 	    (uintptr_t)(((struct fcp_pkt *)wsp->walk_data)->cmd_next);
513 
514 	return (status);
515 }
516 
517 /*
518  * The walker's fini function is invoked at the end of each walk.
519  */
520 static void
521 pkt_walk_f(mdb_walk_state_t *wsp)
522 {
523 	mdb_free(wsp->walk_data, sizeof (struct fcp_pkt));
524 }
525 
526 /*
527  * MDB module linkage information:
528  *
529  * We declare a list of structures describing our dcmds, a list of structures
530  * describing our walkers, and a function named _mdb_init to return a pointer
531  * to our module information.
532  */
533 
534 static const mdb_dcmd_t dcmds[] = {
535 	{ "fcp", NULL, "Leadville fcp instances", fcp },
536 	{ NULL }
537 };
538 
539 static const mdb_walker_t walkers[] = {
540 	{ "fcp", "Walk list of Leadville fcp instances",
541 		fcp_walk_i, fcp_walk_s, fcp_walk_f },
542 	{ "cmds", "Walk list of SCSI commands in fcp's per-lun queue",
543 		cmds_walk_i, cmds_walk_s, cmds_walk_f },
544 	{ "luns", "Walk list of LUNs in an fcp target",
545 		luns_walk_i, luns_walk_s, luns_walk_f },
546 	{ "targets", "Walk list of fcp targets attached to the local port",
547 		targets_walk_i, targets_walk_s, targets_walk_f },
548 	{ "fcp_ipkt", "Walk list of internal packets queued on a local port",
549 		ipkt_walk_i, ipkt_walk_s, ipkt_walk_f},
550 	{ "fcp_pkt", "Walk list of packets queued on a local port",
551 		pkt_walk_i, pkt_walk_s, pkt_walk_f},
552 	{ NULL }
553 };
554 
555 static const mdb_modinfo_t modinfo = {
556 	MDB_API_VERSION, dcmds, walkers
557 };
558 
559 const mdb_modinfo_t *
560 _mdb_init(void)
561 {
562 	return (&modinfo);
563 }
564