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 /*
27 * Copyright 2019 Joyent, Inc.
28 */
29
30 #include <sys/mdb_modapi.h>
31 #include <sys/mutex.h>
32 #include <sys/modctl.h>
33 #include <time.h>
34 #include <sys/fibre-channel/fc.h>
35 #include <sys/fibre-channel/impl/fctl_private.h>
36 #include <sys/fibre-channel/impl/fc_ulpif.h>
37 #include <sys/fibre-channel/impl/fc_portif.h>
38 #include <sys/fibre-channel/impl/fc_fcaif.h>
39
40
41 /*
42 * If we #include <string.h> then other definitions fail. This is
43 * the easiest way of getting access to the function
44 */
45 extern char *strtok(char *string, const char *sepset);
46
47 /* we need 26 bytes for the cftime() call */
48 #define TIMESTAMPSIZE 26 * sizeof (char)
49
50 /* for backward compatibility */
51 typedef struct fc_trace_dmsgv1 {
52 int id_size;
53 int id_flag;
54 time_t id_time;
55 caddr_t id_buf;
56 struct fc_trace_dmsgv1 *id_next;
57 } fc_trace_dmsgv1_t;
58
59 static struct pwwn_hash *fp_pwwn_table;
60 static struct d_id_hash *fp_did_table;
61 static uint32_t pd_hash_index;
62 struct fc_local_port port;
63
64 /*
65 * Leadville port walker/dcmd code
66 */
67
68 /*
69 * Initialize the fc_fca_port_t walker by either using the given starting
70 * address, or reading the value of the kernel's fctl_fca_portlist pointer.
71 * We also allocate a fc_fca_port_t for storage, and save this using the
72 * walk_data pointer.
73 */
74 static int
port_walk_i(mdb_walk_state_t * wsp)75 port_walk_i(mdb_walk_state_t *wsp)
76 {
77 if (wsp->walk_addr == 0 &&
78 mdb_readvar(&wsp->walk_addr, "fctl_fca_portlist") == -1) {
79 mdb_warn("failed to read 'fctl_fca_portlist'");
80 return (WALK_ERR);
81 }
82
83 wsp->walk_data = mdb_alloc(sizeof (fc_fca_port_t), UM_SLEEP);
84 return (WALK_NEXT);
85 }
86
87 /*
88 * At each step, read a fc_fca_port_t into our private storage, and then invoke
89 * the callback function. We terminate when we reach a NULL p_next pointer.
90 */
91 static int
port_walk_s(mdb_walk_state_t * wsp)92 port_walk_s(mdb_walk_state_t *wsp)
93 {
94 int status;
95
96 if (wsp->walk_addr == 0)
97 return (WALK_DONE);
98
99 if (mdb_vread(wsp->walk_data, sizeof (fc_fca_port_t), wsp->walk_addr)
100 == -1) {
101 mdb_warn("failed to read fc_fca_port_t at %p", wsp->walk_addr);
102 return (WALK_DONE);
103 }
104
105 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
106 wsp->walk_cbdata);
107
108 wsp->walk_addr =
109 (uintptr_t)(((fc_fca_port_t *)wsp->walk_data)->port_next);
110
111 return (status);
112 }
113
114 /*
115 * The walker's fini function is invoked at the end of each walk. Since we
116 * dynamically allocated a fc_fca_port_t in port_walk_i, we must free it now.
117 */
118 static void
port_walk_f(mdb_walk_state_t * wsp)119 port_walk_f(mdb_walk_state_t *wsp)
120 {
121 mdb_free(wsp->walk_data, sizeof (fc_fca_port_t));
122 }
123
124
125 static int
ports(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)126 ports(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
127 {
128 fc_fca_port_t portlist;
129 fc_local_port_t port;
130 int longlist = FALSE;
131
132 if (argc > 1) {
133 return (DCMD_USAGE);
134 }
135
136 if (mdb_getopts(argc, argv,
137 'l', MDB_OPT_SETBITS, TRUE, &longlist, NULL) != argc) {
138 return (DCMD_USAGE);
139 }
140
141
142 if (!(flags & DCMD_ADDRSPEC)) {
143 if (longlist == 0) {
144 if (mdb_walk_dcmd("ports", "ports",
145 argc, argv) == -1) {
146 mdb_warn("failed to walk 'fctl_fca_portlist'");
147 return (DCMD_ERR);
148 }
149 } else {
150 if (mdb_walk_dcmd("ports", "fcport",
151 argc, argv) == -1) {
152 mdb_warn("failed to walk 'fctl_fca_portlist'");
153 return (DCMD_ERR);
154 }
155 }
156
157 return (DCMD_OK);
158 }
159
160 /*
161 * If this is the first invocation of the command, print a nice
162 * header line for the output that will follow.
163 */
164 if (DCMD_HDRSPEC(flags))
165 mdb_printf("%16s %-2s %4s %-4s%16s %16s %16s\n",
166 "Port", "I#", "State", "Soft", "FCA Handle",
167 "Port DIP", "FCA Port DIP");
168
169 /*
170 * For each port, we just need to read the fc_fca_port_t struct, read
171 * the port_handle
172 */
173 if (mdb_vread(&portlist, sizeof (fc_fca_port_t), addr) ==
174 sizeof (fc_fca_port_t)) {
175 /*
176 * Now read that port in
177 */
178
179 if (mdb_vread(&port, sizeof (fc_local_port_t), (uintptr_t)
180 portlist.port_handle) == sizeof (fc_local_port_t)) {
181 mdb_printf("%16p %2d %4x %4x %16p %16p %16p\n",
182 portlist.port_handle, port.fp_instance,
183 port.fp_state, port.fp_soft_state,
184 port.fp_fca_handle, port.fp_port_dip,
185 port.fp_fca_dip);
186 } else
187 mdb_warn("failed to read port at %p",
188 portlist.port_handle);
189
190 } else
191 mdb_warn("failed to read port info at %p", addr);
192
193 return (DCMD_OK);
194 }
195
196
197 /*
198 * Leadville ULP walker/dcmd code
199 */
200
201 static int
ulp_walk_i(mdb_walk_state_t * wsp)202 ulp_walk_i(mdb_walk_state_t *wsp)
203 {
204 if (wsp->walk_addr == 0 &&
205 mdb_readvar(&wsp->walk_addr, "fctl_ulp_list") == -1) {
206 mdb_warn("failed to read 'fctl_ulp_list'");
207 return (WALK_ERR);
208 }
209
210 wsp->walk_data = mdb_alloc(sizeof (fc_ulp_list_t), UM_SLEEP);
211 return (WALK_NEXT);
212 }
213
214
215
216 static int
ulp_walk_s(mdb_walk_state_t * wsp)217 ulp_walk_s(mdb_walk_state_t *wsp)
218 {
219 int status;
220
221 if (wsp->walk_addr == 0)
222 return (WALK_DONE);
223
224 if (mdb_vread(wsp->walk_data, sizeof (fc_ulp_list_t), wsp->walk_addr)
225 == -1) {
226 mdb_warn("failed to read fctl_ulp_list %p", wsp->walk_addr);
227 return (WALK_DONE);
228 }
229
230 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
231 wsp->walk_cbdata);
232
233 wsp->walk_addr =
234 (uintptr_t)(((fc_ulp_list_t *)wsp->walk_data)->ulp_next);
235
236 return (status);
237 }
238
239
240 static void
ulp_walk_f(mdb_walk_state_t * wsp)241 ulp_walk_f(mdb_walk_state_t *wsp)
242 {
243 mdb_free(wsp->walk_data, sizeof (fc_ulp_list_t));
244 }
245
246
247 static int
ulps(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)248 ulps(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
249 {
250 fc_ulp_list_t ulplist;
251 fc_ulp_modinfo_t ulp;
252 char ulp_name[30];
253
254 if (argc != 0) {
255 return (DCMD_USAGE);
256 }
257
258 /*
259 * If no fc_ulp_list_t address was specified on the command line, we can
260 * print out all processes by invoking the walker, using this
261 * dcmd itself as the callback.
262 */
263 if (!(flags & DCMD_ADDRSPEC)) {
264 if (mdb_walk_dcmd("ulps", "ulps", argc, argv) == -1) {
265 mdb_warn("failed to walk 'fc_ulp_list_t'");
266 return (DCMD_ERR);
267 }
268 return (DCMD_OK);
269 }
270
271 /*
272 * If this is the first invocation of the command, print a nice
273 * header line for the output that will follow.
274 */
275 if (DCMD_HDRSPEC(flags))
276 mdb_printf("%30s %4s %8s\n", "ULP Name", "Type", "Revision");
277
278 /*
279 * For each port, we just need to read the fc_fca_port_t struct, read
280 * the port_handle
281 */
282 if (mdb_vread(&ulplist, sizeof (fc_ulp_list_t), addr) ==
283 sizeof (fc_ulp_list_t)) {
284 /*
285 * Now read that port in
286 */
287
288 if (mdb_vread(&ulp, sizeof (fc_ulp_modinfo_t),
289 (uintptr_t)ulplist.ulp_info) == sizeof (fc_ulp_modinfo_t)) {
290 if (mdb_vread(&ulp_name, 30,
291 (uintptr_t)ulp.ulp_name) > 0) {
292 mdb_printf("%30s %4x %8x\n",
293 ulp_name, ulp.ulp_type, ulp.ulp_rev);
294 }
295 } else
296 mdb_warn("failed to read ulp at %p",
297 ulplist.ulp_info);
298
299 } else
300 mdb_warn("failed to read ulplist at %p", addr);
301
302 return (DCMD_OK);
303 }
304
305
306
307 /*
308 * Leadville ULP module walker/dcmd code
309 */
310
311 static int
ulpmod_walk_i(mdb_walk_state_t * wsp)312 ulpmod_walk_i(mdb_walk_state_t *wsp)
313 {
314 if (wsp->walk_addr == 0 &&
315 mdb_readvar(&wsp->walk_addr, "fctl_ulp_modules") == -1) {
316 mdb_warn("failed to read 'fctl_ulp_modules'");
317 return (WALK_ERR);
318 }
319
320 wsp->walk_data = mdb_alloc(sizeof (fc_ulp_module_t), UM_SLEEP);
321 return (WALK_NEXT);
322 }
323
324
325
326 static int
ulpmod_walk_s(mdb_walk_state_t * wsp)327 ulpmod_walk_s(mdb_walk_state_t *wsp)
328 {
329 int status;
330
331 if (wsp->walk_addr == 0)
332 return (WALK_DONE);
333
334 if (mdb_vread(wsp->walk_data, sizeof (fc_ulp_module_t), wsp->walk_addr)
335 == -1) {
336 mdb_warn("failed to read fctl_ulp_modules %p", wsp->walk_addr);
337 return (WALK_DONE);
338 }
339
340 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
341 wsp->walk_cbdata);
342
343 wsp->walk_addr =
344 (uintptr_t)(((fc_ulp_module_t *)wsp->walk_data)->mod_next);
345
346 return (status);
347 }
348
349
350 static void
ulpmod_walk_f(mdb_walk_state_t * wsp)351 ulpmod_walk_f(mdb_walk_state_t *wsp)
352 {
353 mdb_free(wsp->walk_data, sizeof (fc_ulp_module_t));
354 }
355
356
357 static int
ulpmods(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)358 ulpmods(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
359 {
360 fc_ulp_module_t modlist;
361 fc_ulp_modinfo_t modinfo;
362 fc_ulp_ports_t ulp_port;
363
364 if (argc != 0) {
365 return (DCMD_USAGE);
366 }
367
368 if (!(flags & DCMD_ADDRSPEC)) {
369 if (mdb_walk_dcmd("ulpmods", "ulpmods", argc, argv)
370 == -1) {
371 mdb_warn("failed to walk 'fc_ulp_module_t'");
372 return (DCMD_ERR);
373 }
374 return (DCMD_OK);
375 }
376
377 /*
378 * If this is the first invocation of the command, print a nice
379 * header line for the output that will follow.
380 */
381 if (DCMD_HDRSPEC(flags))
382 mdb_printf("%4s %16s %8s %8s\n",
383 "Type", "Port Handle", "dstate", "statec");
384
385 /*
386 * For each port, we just need to read the fc_fca_port_t struct, read
387 * the port_handle
388 */
389 if (mdb_vread(&modlist, sizeof (fc_ulp_module_t), addr) ==
390 sizeof (fc_ulp_module_t)) {
391 /*
392 * Now read that module info in
393 */
394
395 if (mdb_vread(&modinfo, sizeof (fc_ulp_modinfo_t),
396 (uintptr_t)modlist.mod_info) == sizeof (fc_ulp_modinfo_t)) {
397 /* Now read all the ports for this module */
398 if (mdb_vread(&ulp_port, sizeof (fc_ulp_ports_t),
399 (uintptr_t)modlist.mod_ports) ==
400 sizeof (fc_ulp_ports_t)) {
401 while (ulp_port.port_handle != NULL) {
402 mdb_printf("%4x %16p %8x %8x\n",
403 modinfo.ulp_type,
404 ulp_port.port_handle,
405 ulp_port.port_dstate,
406 ulp_port.port_statec);
407
408 if (ulp_port.port_next == NULL)
409 break;
410
411 mdb_vread(&ulp_port,
412 sizeof (fc_ulp_ports_t),
413 (uintptr_t)ulp_port.port_next);
414 }
415 }
416 } else
417 mdb_warn("failed to read modinfo at %p",
418 modlist.mod_info);
419
420 } else
421 mdb_warn("failed to read modlist at %p", addr);
422
423 return (DCMD_OK);
424 }
425
426
427 /*
428 * Display an fc_local_port_t struct
429 */
430 static int
fcport(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)431 fcport(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
432 {
433 fc_fca_port_t portlist;
434 fc_local_port_t port;
435 int idx;
436 int first = 1;
437 int walking_fc_fca_portlist = 0;
438
439 if (argc != 0) {
440 int result;
441
442 if (argc != 1)
443 return (DCMD_USAGE);
444
445 if (argv->a_type != MDB_TYPE_STRING)
446 return (DCMD_USAGE);
447
448 walking_fc_fca_portlist = 1;
449 }
450
451 if (!(flags & DCMD_ADDRSPEC)) {
452 mdb_printf("Sorry, you must provide an address\n");
453 return (DCMD_ERR);
454 }
455
456 if (walking_fc_fca_portlist) {
457 /*
458 * Must read the fc_fca_portlist to get the fc_local_port addr
459 */
460 if (mdb_vread(&portlist, sizeof (fc_fca_port_t), addr) ==
461 sizeof (fc_fca_port_t)) {
462 addr = (uintptr_t)portlist.port_handle;
463 }
464 }
465
466 mdb_printf("Reading fc_local_port_t at %p:\n", addr);
467
468 /*
469 * For each port, we just need to read the fc_local_port_t struct
470 */
471
472 if (mdb_vread(&port, sizeof (fc_local_port_t),
473 addr) == sizeof (fc_local_port_t)) {
474 mdb_printf(" fp_mutex : 0x%p\n", port.fp_mutex);
475 mdb_printf(" fp_state : 0x%-8x\n", port.fp_state);
476 mdb_printf(" fp_port_id : 0x%-06x\n",
477 port.fp_port_id.port_id);
478 mdb_printf(" fp_fca_handle : 0x%p\n", port.fp_fca_handle);
479 mdb_printf(" fp_fca_tran : 0x%p\n", port.fp_fca_tran);
480 mdb_printf(" fp_job_head : 0x%p\n", port.fp_job_head);
481 mdb_printf(" fp_job_tail : 0x%p\n", port.fp_job_tail);
482 mdb_printf(" fp_wait_head : 0x%p\n", port.fp_wait_head);
483 mdb_printf(" fp_wait_tail : 0x%p\n", port.fp_wait_tail);
484 mdb_printf(" fp_topology : %u\n", port.fp_topology);
485 mdb_printf(" fp_task : %d\n", port.fp_task);
486 mdb_printf(" fp_last_task : %d\n", port.fp_last_task);
487 mdb_printf(" fp_soft_state : 0x%-4x\n",
488 port.fp_soft_state);
489 mdb_printf(" fp_flag : 0x%-2x\n", port.fp_flag);
490 mdb_printf(" fp_statec_busy : 0x%-8x\n",
491 port.fp_statec_busy);
492 mdb_printf(" fp_port_num : %d\n", port.fp_port_num);
493 mdb_printf(" fp_instance : %d\n", port.fp_instance);
494 mdb_printf(" fp_ulp_attach : %d\n", port.fp_ulp_attach);
495 mdb_printf(" fp_dev_count : %d\n", port.fp_dev_count);
496 mdb_printf(" fp_total_devices : %d\n", port.fp_total_devices);
497 mdb_printf(" fp_bind_state : 0x%-8x\n",
498 port.fp_bind_state);
499 mdb_printf(" fp_options : 0x%-8x\n", port.fp_options);
500 mdb_printf(" fp_port_type : 0x%-2x\n",
501 port.fp_port_type.port_type);
502 mdb_printf(" fp_ub_count : %d\n", port.fp_ub_count);
503 mdb_printf(" fp_active_ubs : %d\n", port.fp_active_ubs);
504 mdb_printf(" fp_port_dip : 0x%p\n", port.fp_port_dip);
505 mdb_printf(" fp_fca_dip : 0x%p\n", port.fp_fca_dip);
506
507 for (idx = 0; idx < 16; idx++) {
508 if (port.fp_ip_addr[idx] != 0)
509 break;
510 }
511
512 if (idx != 16) {
513 mdb_printf(" fp_ip_addr : %-2x:%-2x:%-2x:%-2x:"
514 "%-2x:%-2x:%-2x:%-2x:%-2x:%-2x:%-2x:%-2x:%-2x:%-2x"
515 ":%-2x:%-2x\n",
516 port.fp_ip_addr[0], port.fp_ip_addr[1],
517 port.fp_ip_addr[2], port.fp_ip_addr[3],
518 port.fp_ip_addr[4], port.fp_ip_addr[5],
519 port.fp_ip_addr[6], port.fp_ip_addr[7],
520 port.fp_ip_addr[8], port.fp_ip_addr[9],
521 port.fp_ip_addr[10], port.fp_ip_addr[11],
522 port.fp_ip_addr[12], port.fp_ip_addr[13],
523 port.fp_ip_addr[14], port.fp_ip_addr[15]);
524 } else {
525 mdb_printf(" fp_ip_addr : N/A\n");
526 }
527
528 mdb_printf(" fp_fc4_types : ");
529
530 for (idx = 0; idx < 8; idx++) {
531 if (port.fp_fc4_types[idx] != 0) {
532 if (first) {
533 mdb_printf("%d",
534 port.fp_fc4_types[idx]);
535 first = 0;
536 } else {
537 mdb_printf(", %d",
538 port.fp_fc4_types[idx]);
539 }
540 }
541 }
542
543 if (first) {
544 mdb_printf("None\n");
545 } else {
546 mdb_printf("\n");
547 }
548
549 mdb_printf(" fp_pm_level : %d\n", port.fp_pm_level);
550 mdb_printf(" fp_pm_busy : %d\n", port.fp_pm_busy);
551 mdb_printf(" fp_pm_busy_nocomp : 0x%-8x\n",
552 port.fp_pm_busy_nocomp);
553 mdb_printf(" fp_hard_addr : 0x%-6x\n",
554 port.fp_hard_addr.hard_addr);
555 mdb_printf(" fp_sym_port_name : \"%s\"\n",
556 port.fp_sym_port_name);
557 mdb_printf(" fp_sym_node_name : \"%s\"\n",
558 port.fp_sym_node_name);
559 mdb_printf(" fp_rscn_count : %d\n", port.fp_rscn_count);
560 } else {
561 mdb_warn("failed to read fc_local_port_t at 0x%p", addr);
562 }
563
564 mdb_printf("\n");
565
566 return (DCMD_OK);
567 }
568
569
570 /*
571 * Leadville remote_port walker/dcmd code
572 */
573
574 /*
575 * We need to be given the address of a port structure in order to start
576 * walking. From that, we can read the pwwn table.
577 */
578 static int
pd_by_pwwn_walk_i(mdb_walk_state_t * wsp)579 pd_by_pwwn_walk_i(mdb_walk_state_t *wsp)
580 {
581 fc_local_port_t port;
582
583 if (wsp->walk_addr == 0) {
584 mdb_warn("pd_by_pwwn walk doesn't support global walks\n");
585 return (WALK_ERR);
586 }
587
588 /*
589 * Allocate space for the pwwn_hash table
590 */
591
592 fp_pwwn_table = mdb_alloc(sizeof (struct pwwn_hash) *
593 PWWN_HASH_TABLE_SIZE, UM_SLEEP);
594
595 /*
596 * Input should be an fc_local_port_t, so read it to get the pwwn
597 * table's head
598 */
599
600 if (mdb_vread(&port, sizeof (fc_local_port_t), wsp->walk_addr) !=
601 sizeof (fc_local_port_t)) {
602 mdb_warn("Unable to read in the port structure address\n");
603 return (WALK_ERR);
604 }
605
606 if (mdb_vread(fp_pwwn_table, sizeof (struct pwwn_hash) *
607 PWWN_HASH_TABLE_SIZE, (uintptr_t)port.fp_pwwn_table) == -1) {
608 mdb_warn("Unable to read in the pwwn hash table\n");
609 return (WALK_ERR);
610 }
611
612 pd_hash_index = 0;
613
614 while ((fp_pwwn_table[pd_hash_index].pwwn_head == NULL) &&
615 (pd_hash_index < PWWN_HASH_TABLE_SIZE)) {
616 pd_hash_index++;
617 }
618
619 wsp->walk_addr = (uintptr_t)fp_pwwn_table[pd_hash_index].pwwn_head;
620
621 wsp->walk_data = mdb_alloc(sizeof (fc_remote_port_t), UM_SLEEP);
622 return (WALK_NEXT);
623 }
624
625 /*
626 * At each step, read a fc_remote_port_t into our private storage, and then
627 * invoke the callback function. We terminate when we reach a NULL p_next
628 * pointer.
629 */
630 static int
pd_by_pwwn_walk_s(mdb_walk_state_t * wsp)631 pd_by_pwwn_walk_s(mdb_walk_state_t *wsp)
632 {
633 int status;
634
635 if ((wsp->walk_addr == 0) &&
636 (pd_hash_index >= (PWWN_HASH_TABLE_SIZE - 1))) {
637 return (WALK_DONE);
638 }
639
640 if (mdb_vread(wsp->walk_data, sizeof (fc_remote_port_t), wsp->walk_addr)
641 == -1) {
642 mdb_warn("failed to read fc_remote_port at %p", wsp->walk_addr);
643 return (WALK_DONE);
644 }
645
646 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
647 wsp->walk_cbdata);
648
649 wsp->walk_addr =
650 (uintptr_t)(((fc_remote_port_t *)wsp->walk_data)->pd_wwn_hnext);
651
652 if (wsp->walk_addr == 0) {
653 /*
654 * Try the next hash list, if there is one.
655 */
656
657 pd_hash_index++;
658
659 while ((fp_pwwn_table[pd_hash_index].pwwn_head == NULL) &&
660 (pd_hash_index < PWWN_HASH_TABLE_SIZE)) {
661 pd_hash_index++;
662 }
663
664 if (pd_hash_index == PWWN_HASH_TABLE_SIZE) {
665 /* We're done */
666 return (status);
667 }
668
669 wsp->walk_addr =
670 (uintptr_t)fp_pwwn_table[pd_hash_index].pwwn_head;
671 }
672
673 return (status);
674 }
675
676 /*
677 * The walker's fini function is invoked at the end of each walk.
678 */
679 static void
pd_by_pwwn_walk_f(mdb_walk_state_t * wsp)680 pd_by_pwwn_walk_f(mdb_walk_state_t *wsp)
681 {
682 mdb_free(wsp->walk_data, sizeof (fc_remote_port_t));
683 mdb_free(fp_pwwn_table, sizeof (struct pwwn_hash) *
684 PWWN_HASH_TABLE_SIZE);
685 fp_pwwn_table = NULL;
686 }
687
688 /*
689 * This is the same walker as pd_by_pwwn, but we walk the D_ID hash table
690 */
691
692 static int
pd_by_did_walk_i(mdb_walk_state_t * wsp)693 pd_by_did_walk_i(mdb_walk_state_t *wsp)
694 {
695 fc_local_port_t port;
696
697 if (wsp->walk_addr == 0) {
698 mdb_warn("pd_by_did walk doesn't support global walks\n");
699 return (WALK_ERR);
700 }
701
702 /*
703 * Allocate space for the did_hash table
704 */
705
706 fp_did_table = mdb_alloc(sizeof (struct d_id_hash) *
707 D_ID_HASH_TABLE_SIZE, UM_SLEEP);
708
709 /*
710 * Input should be an fc_local_port_t, so read it to get the d_id
711 * table's head
712 */
713
714 if (mdb_vread(&port, sizeof (fc_local_port_t), wsp->walk_addr) !=
715 sizeof (fc_local_port_t)) {
716 mdb_warn("Unable to read in the port structure address\n");
717 return (WALK_ERR);
718 }
719
720 if (mdb_vread(fp_did_table, sizeof (struct d_id_hash) *
721 D_ID_HASH_TABLE_SIZE, (uintptr_t)port.fp_did_table) == -1) {
722 mdb_warn("Unable to read in the D_ID hash table\n");
723 return (WALK_ERR);
724 }
725 pd_hash_index = 0;
726
727 while ((fp_did_table[pd_hash_index].d_id_head == NULL) &&
728 (pd_hash_index < D_ID_HASH_TABLE_SIZE)) {
729 pd_hash_index++;
730 }
731
732 wsp->walk_addr = (uintptr_t)fp_did_table[pd_hash_index].d_id_head;
733
734 wsp->walk_data = mdb_alloc(sizeof (fc_remote_port_t), UM_SLEEP);
735 return (WALK_NEXT);
736 }
737
738 /*
739 * At each step, read a fc_remote_port_t into our private storage, and then
740 * invoke the callback function. We terminate when we reach a NULL p_next
741 * pointer.
742 */
743 static int
pd_by_did_walk_s(mdb_walk_state_t * wsp)744 pd_by_did_walk_s(mdb_walk_state_t *wsp)
745 {
746 int status;
747
748 if ((wsp->walk_addr == 0) &&
749 (pd_hash_index >= (D_ID_HASH_TABLE_SIZE - 1))) {
750 return (WALK_DONE);
751 }
752
753 if (mdb_vread(wsp->walk_data, sizeof (fc_remote_port_t), wsp->walk_addr)
754 == -1) {
755 mdb_warn("failed to read fc_remote_port at %p", wsp->walk_addr);
756 return (WALK_DONE);
757 }
758
759 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
760 wsp->walk_cbdata);
761
762 wsp->walk_addr =
763 (uintptr_t)(((fc_remote_port_t *)wsp->walk_data)->pd_did_hnext);
764
765 if (wsp->walk_addr == 0) {
766 /*
767 * Try the next hash list, if there is one.
768 */
769
770 pd_hash_index++;
771
772 while ((fp_did_table[pd_hash_index].d_id_head == NULL) &&
773 (pd_hash_index < D_ID_HASH_TABLE_SIZE)) {
774 pd_hash_index++;
775 }
776
777 if (pd_hash_index == D_ID_HASH_TABLE_SIZE) {
778 /* We're done */
779 return (status);
780 }
781
782 wsp->walk_addr =
783 (uintptr_t)fp_did_table[pd_hash_index].d_id_head;
784 }
785
786 return (status);
787 }
788
789 /*
790 * The walker's fini function is invoked at the end of each walk.
791 */
792 static void
pd_by_did_walk_f(mdb_walk_state_t * wsp)793 pd_by_did_walk_f(mdb_walk_state_t *wsp)
794 {
795 mdb_free(wsp->walk_data, sizeof (fc_remote_port_t));
796 mdb_free(fp_did_table, sizeof (struct d_id_hash) *
797 D_ID_HASH_TABLE_SIZE);
798 fp_did_table = NULL;
799 }
800
801
802 /*
803 * Display a remote_port structure
804 */
805 static int
remote_port(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)806 remote_port(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
807 {
808 fc_remote_port_t pd;
809 int idx;
810 int first = 1;
811
812 if (argc > 0) {
813 return (DCMD_USAGE);
814 }
815
816 if (!(flags & DCMD_ADDRSPEC)) {
817 mdb_printf("Sorry, you must provide an address\n");
818 return (DCMD_ERR);
819 }
820
821 if (mdb_vread(&pd, sizeof (fc_remote_port_t), addr) !=
822 sizeof (fc_remote_port_t)) {
823 mdb_warn("Error reading pd at 0x%x\n", addr);
824 return (DCMD_ERR);
825 }
826
827 mdb_printf("Reading remote_port at 0x%p\n", addr);
828 mdb_printf(" mutex : 0x%p\n", pd.pd_mutex);
829 mdb_printf(" port_id : 0x%-8x\n", pd.pd_port_id);
830 mdb_printf(" port_name : 0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
831 pd.pd_port_name.raw_wwn[0], pd.pd_port_name.raw_wwn[1],
832 pd.pd_port_name.raw_wwn[2], pd.pd_port_name.raw_wwn[3],
833 pd.pd_port_name.raw_wwn[4], pd.pd_port_name.raw_wwn[5],
834 pd.pd_port_name.raw_wwn[6], pd.pd_port_name.raw_wwn[7]);
835 mdb_printf(" login_count : %d\n", pd.pd_login_count);
836 mdb_printf(" state : 0x%x ", pd.pd_state);
837
838 switch (pd.pd_state) {
839 case PORT_DEVICE_INVALID:
840 mdb_printf("(invalid)\n");
841 break;
842 case PORT_DEVICE_VALID:
843 mdb_printf("(valid)\n");
844 break;
845 case PORT_DEVICE_LOGGED_IN:
846 mdb_printf("(logged in)\n");
847 break;
848 default:
849 mdb_printf("(Unknown state)\n");
850 }
851
852 mdb_printf(" remote node : 0x%p\n", pd.pd_remote_nodep);
853 mdb_printf(" hard_addr : 0x%x\n", pd.pd_hard_addr);
854 mdb_printf(" local port : 0x%p\n", pd.pd_port);
855 mdb_printf(" type : %d ", pd.pd_type);
856
857 switch (pd.pd_type) {
858 case PORT_DEVICE_NOCHANGE:
859 mdb_printf("(No change)\n");
860 break;
861 case PORT_DEVICE_NEW:
862 mdb_printf("(New)\n");
863 break;
864 case PORT_DEVICE_OLD:
865 mdb_printf("(Old)\n");
866 break;
867 case PORT_DEVICE_CHANGED:
868 mdb_printf("(Changed)\n");
869 break;
870 case PORT_DEVICE_DELETE:
871 mdb_printf("(Delete)\n");
872 break;
873 case PORT_DEVICE_USER_LOGIN:
874 mdb_printf("(User login)\n");
875 break;
876 case PORT_DEVICE_USER_LOGOUT:
877 mdb_printf("(User logout)\n");
878 break;
879 case PORT_DEVICE_USER_CREATE:
880 mdb_printf("(User create)\n");
881 break;
882 case PORT_DEVICE_USER_DELETE:
883 mdb_printf("(User delete)\n");
884 break;
885 default:
886 mdb_printf("(Unknown type)\n");
887 }
888
889 mdb_printf(" flags : 0x%x ", pd.pd_flags);
890
891 switch (pd.pd_flags) {
892 case PD_IDLE:
893 mdb_printf("(Idle)\n");
894 break;
895 case PD_ELS_IN_PROGRESS:
896 mdb_printf("(ELS in progress)\n");
897 break;
898 case PD_ELS_MARK:
899 mdb_printf("(Mark)\n");
900 break;
901 default:
902 mdb_printf("(Unknown flag value)\n");
903 }
904
905 mdb_printf(" login_class : 0x%x\n", pd.pd_login_class);
906 mdb_printf(" recipient : %d\n", pd.pd_recepient);
907 mdb_printf(" ref_count : %d\n", pd.pd_ref_count);
908 mdb_printf(" aux_flags : 0x%x ", pd.pd_aux_flags);
909
910 first = 1;
911 if (pd.pd_aux_flags & PD_IN_DID_QUEUE) {
912 mdb_printf("(IN_DID_QUEUE");
913 first = 0;
914 }
915
916 if (pd.pd_aux_flags & PD_DISABLE_RELOGIN) {
917 if (first) {
918 mdb_printf("(DISABLE_RELOGIN");
919 } else {
920 mdb_printf(", DISABLE_RELOGIN");
921 }
922 first = 0;
923 }
924
925 if (pd.pd_aux_flags & PD_NEEDS_REMOVAL) {
926 if (first) {
927 mdb_printf("(NEEDS_REMOVAL");
928 } else {
929 mdb_printf(", NEEDS_REMOVAL");
930 }
931 first = 0;
932 }
933
934 if (pd.pd_aux_flags & PD_LOGGED_OUT) {
935 if (first) {
936 mdb_printf("(LOGGED_OUT");
937 } else {
938 mdb_printf(", LOGGED_OUT");
939 }
940 first = 0;
941 }
942
943 if (pd.pd_aux_flags & PD_GIVEN_TO_ULPS) {
944 if (first) {
945 mdb_printf("(GIVEN_TO_ULPS");
946 } else {
947 mdb_printf(", GIVEN_TO_ULPS");
948 }
949 first = 0;
950 }
951
952 if (first == 0) {
953 mdb_printf(")\n");
954 } else {
955 mdb_printf("\n");
956 }
957
958 mdb_printf(" sig : %p\n", pd.pd_logo_tc.sig);
959 mdb_printf(" active : %d\n", pd.pd_logo_tc.active);
960 mdb_printf(" counter : %d\n", pd.pd_logo_tc.counter);
961 mdb_printf(" max_value : %d\n", pd.pd_logo_tc.max_value);
962 mdb_printf(" timer : %d\n", pd.pd_logo_tc.timer);
963 mdb_printf("\n");
964
965 return (DCMD_OK);
966 }
967
968 int
fc_dump_logmsg(fc_trace_dmsg_t * addr,uint_t pktstart,uint_t pktend,uint_t * printed)969 fc_dump_logmsg(fc_trace_dmsg_t *addr, uint_t pktstart, uint_t pktend,
970 uint_t *printed)
971 {
972 fc_trace_dmsg_t msg;
973 caddr_t buf;
974 char merge[1024];
975 caddr_t tmppkt;
976 char *tmpbuf; /* for tokenising the buffer */
977 uint_t pktnum = 0;
978
979 while (addr != NULL) {
980 if (mdb_vread(&msg, sizeof (msg), (uintptr_t)addr) !=
981 sizeof (msg)) {
982 mdb_warn("failed to read message pointer in kernel");
983 return (DCMD_ERR);
984 }
985
986 if (msg.id_size) {
987
988 buf = mdb_alloc(msg.id_size + 1, UM_SLEEP);
989 tmppkt = mdb_alloc(msg.id_size + 1, UM_SLEEP);
990
991 if (mdb_vread(buf, msg.id_size,
992 (uintptr_t)msg.id_buf) != msg.id_size) {
993 mdb_warn("failed to read buffer contents"
994 " in kernel");
995 mdb_free(buf, msg.id_size + 1);
996 return (DCMD_ERR);
997 }
998
999 if (buf[0] == '\n') {
1000 mdb_printf("There is a problem in"
1001 "the buffer\n");
1002 }
1003 /* funky packet processing stuff */
1004 bcopy(buf, tmppkt, msg.id_size + 1);
1005
1006 /* find the equals sign, and put a null there */
1007 tmpbuf = strchr(tmppkt, '=');
1008 *tmpbuf = 0;
1009 pktnum = (uint_t)mdb_strtoull(tmppkt);
1010
1011 if ((pktnum >= pktstart) && (pktnum <= pktend)) {
1012 (void) mdb_snprintf(merge, sizeof (merge),
1013 "[%Y:%03d:%03d:%03d] %s",
1014 msg.id_time.tv_sec,
1015 (int)msg.id_time.tv_nsec/1000000,
1016 (int)(msg.id_time.tv_nsec/1000)%1000,
1017 (int)msg.id_time.tv_nsec%1000, buf);
1018 mdb_printf("%s", merge);
1019 if (printed != NULL)
1020 (*printed) ++;
1021 }
1022 mdb_free(buf, msg.id_size + 1);
1023 mdb_free(tmppkt, msg.id_size + 1);
1024 }
1025 addr = msg.id_next;
1026 }
1027
1028 return (DCMD_OK);
1029 }
1030
1031 int
fc_dump_old_logmsg(fc_trace_dmsgv1_t * addr,uint_t pktstart,uint_t pktend,uint_t * printed)1032 fc_dump_old_logmsg(fc_trace_dmsgv1_t *addr, uint_t pktstart, uint_t pktend,
1033 uint_t *printed)
1034 {
1035 fc_trace_dmsgv1_t msg;
1036 caddr_t buf;
1037 char merge[1024];
1038 caddr_t tmppkt;
1039 char *tmpbuf; /* for tokenising the buffer */
1040 uint_t pktnum = 0;
1041
1042 while (addr != NULL) {
1043 if (mdb_vread(&msg, sizeof (msg), (uintptr_t)addr) !=
1044 sizeof (msg)) {
1045 mdb_warn("failed to read message pointer in kernel");
1046 return (DCMD_ERR);
1047 }
1048
1049 if (msg.id_size) {
1050
1051 buf = mdb_alloc(msg.id_size + 1, UM_SLEEP);
1052 tmppkt = mdb_alloc(msg.id_size + 1, UM_SLEEP);
1053
1054 if (mdb_vread(buf, msg.id_size,
1055 (uintptr_t)msg.id_buf) != msg.id_size) {
1056 mdb_warn("failed to read buffer contents"
1057 " in kernel");
1058 mdb_free(buf, msg.id_size + 1);
1059 return (DCMD_ERR);
1060 }
1061
1062 if (buf[0] == '\n') {
1063 mdb_printf("There is a problem in"
1064 "the buffer\n");
1065 }
1066 /* funky packet processing stuff */
1067 bcopy(buf, tmppkt, msg.id_size + 1);
1068
1069 tmpbuf = strchr(tmppkt, '=');
1070 *tmpbuf = 0;
1071 pktnum = (uint_t)mdb_strtoull(tmppkt);
1072
1073 if ((pktnum >= pktstart) && (pktnum <= pktend)) {
1074 (void) mdb_snprintf(merge, sizeof (merge),
1075 "[%Y] %s", msg.id_time, buf);
1076 mdb_printf("%s", merge);
1077 if (printed != NULL)
1078 (*printed) ++;
1079 }
1080 mdb_free(buf, msg.id_size + 1);
1081 mdb_free(tmppkt, msg.id_size + 1);
1082 }
1083 addr = msg.id_next;
1084 }
1085
1086 return (DCMD_OK);
1087 }
1088
1089 int
fc_trace_dump(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)1090 fc_trace_dump(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1091 {
1092 fc_trace_logq_t logq;
1093 uint_t pktnum = 0;
1094 uint_t printed = 0; /* have we printed anything? */
1095
1096 uintptr_t pktstart = 0;
1097 uintptr_t pktend = UINT_MAX;
1098 int rval = DCMD_OK;
1099
1100 if (mdb_vread(&logq, sizeof (logq), addr) != sizeof (logq)) {
1101 mdb_warn("Failed to read log queue in kernel");
1102 return (DCMD_ERR);
1103 }
1104
1105 if (mdb_getopts(argc, argv,
1106 's', MDB_OPT_UINTPTR, &pktstart,
1107 'e', MDB_OPT_UINTPTR, &pktend,
1108 NULL) != argc) {
1109 return (DCMD_USAGE);
1110 }
1111
1112 if (pktstart > pktend) {
1113 return (DCMD_USAGE);
1114 }
1115
1116 if ((logq.il_flags & FC_TRACE_LOGQ_V2) != 0) {
1117 rval = fc_dump_logmsg((fc_trace_dmsg_t *)logq.il_msgh, pktstart,
1118 pktend, &printed);
1119 } else {
1120 rval = fc_dump_old_logmsg((fc_trace_dmsgv1_t *)logq.il_msgh,
1121 pktstart, pktend, &printed);
1122 }
1123
1124 if (rval != DCMD_OK) {
1125 return (rval);
1126 }
1127
1128 if (printed == 0) {
1129 mdb_printf("No packets in the buffer match the"
1130 " criteria given");
1131 }
1132
1133 return (rval);
1134 }
1135
1136 int
fp_trace_dump(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)1137 fp_trace_dump(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1138 {
1139 if (mdb_readvar(&addr, "fp_logq") == -1) {
1140 mdb_warn("failed to read fp_logq");
1141 return (DCMD_ERR);
1142 }
1143
1144 if (DCMD_HDRSPEC(flags)) {
1145 mdb_printf("fp trace buffer contents\n");
1146 }
1147
1148 return (fc_trace_dump(addr, flags, argc, argv));
1149 }
1150
1151
1152 int
fcp_trace_dump(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)1153 fcp_trace_dump(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1154 {
1155 if (mdb_readvar(&addr, "fcp_logq") == -1) {
1156 mdb_warn("failed to read fcp_logq");
1157 return (DCMD_ERR);
1158 }
1159
1160 if (DCMD_HDRSPEC(flags)) {
1161 mdb_printf("fcp trace buffer contents\n");
1162 }
1163
1164 return (fc_trace_dump(addr, flags, argc, argv));
1165 }
1166
1167 /*
1168 * Leadville job_request walker/dcmd code
1169 */
1170
1171 /*
1172 * We need to be given the address of a local port structure in order to start
1173 * walking. From that, we can read the job_request list.
1174 */
1175
1176 static int
job_request_walk_i(mdb_walk_state_t * wsp)1177 job_request_walk_i(mdb_walk_state_t *wsp)
1178 {
1179 if (wsp->walk_addr == 0) {
1180 mdb_warn("The address of a fc_local_port"
1181 " structure must be given\n");
1182 return (WALK_ERR);
1183 }
1184
1185 /*
1186 * Input should be a fc_local_port_t, so read it to get the job_request
1187 * lists's head
1188 */
1189
1190 if (mdb_vread(&port, sizeof (fc_local_port_t), wsp->walk_addr) !=
1191 sizeof (fc_local_port_t)) {
1192 mdb_warn("Failed to read in the fc_local_port"
1193 " at 0x%p\n", wsp->walk_addr);
1194 return (WALK_ERR);
1195 }
1196
1197 wsp->walk_addr = (uintptr_t)(port.fp_job_head);
1198 wsp->walk_data = mdb_alloc(sizeof (struct job_request), UM_SLEEP);
1199
1200 return (WALK_NEXT);
1201 }
1202
1203 static int
job_request_walk_s(mdb_walk_state_t * wsp)1204 job_request_walk_s(mdb_walk_state_t *wsp)
1205 {
1206 int status;
1207
1208 if (wsp->walk_addr == 0)
1209 return (WALK_DONE);
1210
1211 if (mdb_vread(wsp->walk_data, sizeof (struct job_request),
1212 wsp->walk_addr) == -1) {
1213 mdb_warn("Failed to read in the job_request at 0x%p\n",
1214 wsp->walk_addr);
1215 return (WALK_DONE);
1216 }
1217
1218 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
1219 wsp->walk_cbdata);
1220
1221 wsp->walk_addr =
1222 (uintptr_t)(((struct job_request *)wsp->walk_data)->job_next);
1223
1224 return (status);
1225 }
1226
1227 /*
1228 * The walker's fini function is invoked at the end of each walk.
1229 */
1230 static void
job_request_walk_f(mdb_walk_state_t * wsp)1231 job_request_walk_f(mdb_walk_state_t *wsp)
1232 {
1233 mdb_free(wsp->walk_data, sizeof (struct job_request));
1234 }
1235
1236
1237 /*
1238 * Leadville fc_orphan walker/dcmd code
1239 */
1240
1241 /*
1242 * We need to be given the address of a port structure in order to start
1243 * walking. From that, we can read the orphan list.
1244 */
1245
1246 static int
orphan_walk_i(mdb_walk_state_t * wsp)1247 orphan_walk_i(mdb_walk_state_t *wsp)
1248 {
1249 if (wsp->walk_addr == 0) {
1250 mdb_warn("The address of a fc_local_port"
1251 " structure must be given\n");
1252 return (WALK_ERR);
1253 }
1254
1255 /*
1256 * Input should be a fc_local_port_t, so read it to get the orphan
1257 * lists's head
1258 */
1259
1260 if (mdb_vread(&port, sizeof (fc_local_port_t), wsp->walk_addr) !=
1261 sizeof (fc_local_port_t)) {
1262 mdb_warn("Failed to read in the fc_local_port"
1263 " at 0x%p\n", wsp->walk_addr);
1264 return (WALK_ERR);
1265 }
1266
1267 wsp->walk_addr = (uintptr_t)(port.fp_orphan_list);
1268 wsp->walk_data = mdb_alloc(sizeof (struct fc_orphan), UM_SLEEP);
1269
1270 return (WALK_NEXT);
1271 }
1272
1273 static int
orphan_walk_s(mdb_walk_state_t * wsp)1274 orphan_walk_s(mdb_walk_state_t *wsp)
1275 {
1276 int status;
1277
1278 if (wsp->walk_addr == 0)
1279 return (WALK_DONE);
1280
1281 if (mdb_vread(wsp->walk_data, sizeof (struct fc_orphan),
1282 wsp->walk_addr) == -1) {
1283 mdb_warn("Failed to read in the fc_orphan at 0x%p\n",
1284 wsp->walk_addr);
1285 return (WALK_DONE);
1286 }
1287
1288 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
1289 wsp->walk_cbdata);
1290
1291 wsp->walk_addr =
1292 (uintptr_t)(((struct fc_orphan *)wsp->walk_data)->orp_next);
1293
1294 return (status);
1295 }
1296
1297 /*
1298 * The walker's fini function is invoked at the end of each walk.
1299 */
1300 static void
orphan_walk_f(mdb_walk_state_t * wsp)1301 orphan_walk_f(mdb_walk_state_t *wsp)
1302 {
1303 mdb_free(wsp->walk_data, sizeof (struct fc_orphan));
1304 }
1305
1306
1307 /*
1308 * MDB module linkage information:
1309 *
1310 * We declare a list of structures describing our dcmds, a list of structures
1311 * describing our walkers, and a function named _mdb_init to return a pointer
1312 * to our module information.
1313 */
1314
1315 static const mdb_dcmd_t dcmds[] = {
1316 { "ports", "[-l]", "Leadville port list", ports },
1317 { "ulps", NULL, "Leadville ULP list", ulps },
1318 { "ulpmods", NULL, "Leadville ULP module list", ulpmods },
1319 { "fcport", NULL, "Display a Leadville fc_local_port structure",
1320 fcport },
1321 { "remote_port", NULL, "Display fc_remote_port structures",
1322 remote_port },
1323 { "fcptrace", "[-s m][-e n] (m < n)", "Dump the fcp trace buffer, "
1324 "optionally supplying starting and ending packet numbers.",
1325 fcp_trace_dump, NULL },
1326 { "fptrace", "[-s m][-e n] (m < n)", "Dump the fp trace buffer, "
1327 "optionally supplying starting and ending packet numbers.",
1328 fp_trace_dump, NULL },
1329 { NULL }
1330 };
1331
1332 static const mdb_walker_t walkers[] = {
1333 { "ports", "walk list of Leadville port structures",
1334 port_walk_i, port_walk_s, port_walk_f },
1335 { "ulps", "walk list of Leadville ULP structures",
1336 ulp_walk_i, ulp_walk_s, ulp_walk_f },
1337 { "ulpmods", "walk list of Leadville ULP module structures",
1338 ulpmod_walk_i, ulpmod_walk_s, ulpmod_walk_f },
1339 { "pd_by_pwwn", "walk list of fc_remote_port structures hashed by PWWN",
1340 pd_by_pwwn_walk_i, pd_by_pwwn_walk_s, pd_by_pwwn_walk_f },
1341 { "pd_by_did", "walk list of fc_remote_port structures hashed by D_ID",
1342 pd_by_did_walk_i, pd_by_did_walk_s, pd_by_did_walk_f },
1343 { "job_request", "walk list of job_request structures for a local port",
1344 job_request_walk_i, job_request_walk_s, job_request_walk_f },
1345 { "orphan", "walk list of orphan structures for a local port",
1346 orphan_walk_i, orphan_walk_s, orphan_walk_f },
1347 { NULL }
1348 };
1349
1350 static const mdb_modinfo_t modinfo = {
1351 MDB_API_VERSION, dcmds, walkers
1352 };
1353
1354 const mdb_modinfo_t *
_mdb_init(void)1355 _mdb_init(void)
1356 {
1357 return (&modinfo);
1358 }
1359