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
fcp_walk_i(mdb_walk_state_t * wsp)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
fcp_walk_s(mdb_walk_state_t * wsp)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
fcp_walk_f(mdb_walk_state_t * wsp)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
fcp(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
cmds_walk_i(mdb_walk_state_t * wsp)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
cmds_walk_s(mdb_walk_state_t * wsp)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
cmds_walk_f(mdb_walk_state_t * wsp)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
luns_walk_i(mdb_walk_state_t * wsp)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
luns_walk_s(mdb_walk_state_t * wsp)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
luns_walk_f(mdb_walk_state_t * wsp)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
targets_walk_i(mdb_walk_state_t * wsp)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
targets_walk_s(mdb_walk_state_t * wsp)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
targets_walk_f(mdb_walk_state_t * wsp)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
ipkt_walk_i(mdb_walk_state_t * wsp)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
ipkt_walk_s(mdb_walk_state_t * wsp)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
ipkt_walk_f(mdb_walk_state_t * wsp)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
pkt_walk_i(mdb_walk_state_t * wsp)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
pkt_walk_s(mdb_walk_state_t * wsp)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
pkt_walk_f(mdb_walk_state_t * wsp)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 *
_mdb_init(void)560 _mdb_init(void)
561 {
562 return (&modinfo);
563 }
564