dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / mdb / common / modules / scsi_vhci / scsi_vhci.c
blob486dcd82b1ab0947d64869dbb462bc335f61a8d2
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
28 #include <sys/kmem.h>
29 #include <sys/proc.h>
30 #include <sys/time.h>
31 #include <sys/conf.h>
32 #include <sys/file.h>
33 #include <sys/ddi.h>
34 #include <sys/ddi_impldefs.h>
35 #include <sys/modctl.h>
36 #include <sys/sunddi.h>
37 #include <sys/scsi/scsi.h>
38 #include <sys/scsi/impl/scsi_reset_notify.h>
39 #include <sys/sunmdi.h>
40 #include <sys/mdi_impldefs.h>
41 #include <sys/scsi/adapters/scsi_vhci.h>
42 #include <sys/scsi/scsi_types.h>
43 #include <sys/disp.h>
44 #include <sys/types.h>
45 #include <sys/mdb_modapi.h>
47 #define FT(var, typ) (*((typ *)(&(var))))
49 static int dump_states(uintptr_t array_vaddr, int verbose,
50 struct i_ddi_soft_state *sp);
51 static int i_vhci_states(uintptr_t addr, uint_t flags, int argc,
52 const mdb_arg_t *argv, struct i_ddi_soft_state *sp);
53 static int vhci_states(uintptr_t addr, uint_t flags, int argc,
54 const mdb_arg_t *argv);
56 static int mdiclient(uintptr_t addr, uint_t flags, int argc,
57 const mdb_arg_t *argv);
58 static int vhciguid(uintptr_t addr, uint_t flags, int argc,
59 const mdb_arg_t *argv);
60 static int vhcilun(uintptr_t addr, uint_t flags, int argc,
61 const mdb_arg_t *argv);
62 static int i_vhcilun(uintptr_t addr, uint_t display_single_guid, char *guid);
64 /* Utils */
65 static int get_mdbstr(uintptr_t addr, char *name);
66 static void dump_mutex(kmutex_t m, char *name);
67 static void dump_condvar(kcondvar_t c, char *name);
68 static void dump_string(uintptr_t addr, char *name);
69 static void dump_flags(unsigned long long flags, char **strings);
70 static void dump_state_str(char *name, uintptr_t addr, char **strings);
72 static int mpxio_walk_cb(uintptr_t addr, const void *data, void *cbdata);
74 static const mdb_dcmd_t dcmds[] = {
75 { "vhci_states", "[ -v ]", "dump all the vhci state pointers",
76 vhci_states },
77 { "vhciguid", NULL, "list all clients or given a guid, list one client",
78 vhciguid },
79 { NULL }
82 static const mdb_modinfo_t modinfo = {
83 MDB_API_VERSION, dcmds, NULL
86 static char *client_lb_str[] =
88 "NONE",
89 "RR",
90 "LBA",
91 NULL
94 static char *mdi_client_states[] =
96 NULL,
97 "OPTIMAL",
98 "DEGRADED",
99 "FAILED",
100 NULL
103 static char *client_flags[] =
105 "MDI_CLIENT_FLAGS_OFFLINE",
106 "MDI_CLIENT_FLAGS_SUSPEND",
107 "MDI_CLIENT_FLAGS_POWER_DOWN",
108 "MDI_CLIENT_FLAGS_DETACH",
109 "MDI_CLIENT_FLAGS_FAILOVER",
110 "MDI_CLIENT_FLAGS_REPORT_DEV",
111 "MDI_CLIENT_FLAGS_PATH_FREE_IN_PROGRESS",
112 "MDI_CLIENT_FLAGS_ASYNC_FREE",
113 "MDI_CLIENT_FLAGS_DEV_NOT_SUPPORTED",
114 NULL
117 static char *vhci_conf_flags[] =
119 "VHCI_CONF_FLAGS_AUTO_FAILBACK",
120 NULL
123 static char *svlun_flags[] =
125 "VLUN_TASK_D_ALIVE_FLG",
126 "VLUN_RESERVE_ACTIVE_FLG",
127 "VLUN_QUIESCED_FLG",
128 NULL
131 static char mdipathinfo_cb_str[] = "::print struct mdi_pathinfo";
133 const mdb_modinfo_t *
134 _mdb_init(void)
136 return (&modinfo);
140 * mdiclient()
142 * Dump mdi_client_t info and list all paths.
144 /* ARGSUSED */
145 static int
146 mdiclient(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
148 struct mdi_client value;
150 if (!(flags & DCMD_ADDRSPEC)) {
151 mdb_warn("mdiclient: requires an address");
152 return (DCMD_ERR);
155 if (mdb_vread(&value, sizeof (struct mdi_client), addr)
156 != sizeof (struct mdi_client)) {
157 mdb_warn("mdiclient: Failed read on %l#r\n", addr);
158 return (DCMD_ERR);
160 mdb_printf("----------------- mdi_client @ %#lr ----------\n", addr);
161 dump_string((uintptr_t)value.ct_guid, "GUID (ct_guid)");
162 dump_string((uintptr_t)value.ct_drvname, "Driver Name (ct_drvname)");
163 dump_state_str("Load Balance (ct_lb)", value.ct_lb, client_lb_str);
164 mdb_printf("\n");
165 mdb_printf("ct_hnext: %26l#r::print struct mdi_client\n",
166 value.ct_hnext);
167 mdb_printf("ct_hprev: %26l#r::print struct mdi_client\n",
168 value.ct_hprev);
169 mdb_printf("ct_dip: %28l#r::print struct dev_info\n", value.ct_dip);
170 mdb_printf("ct_vhci: %27l#r::print struct mdi_vhci\n", value.ct_vhci);
171 mdb_printf("ct_cprivate: %23l#r\n", value.ct_cprivate);
172 mdb_printf("\nct_path_head: %22l#r::print struct mdi_pathinfo\n",
173 value.ct_path_head);
174 mdb_printf("ct_path_tail: %22l#r::print struct mdi_pathinfo\n",
175 value.ct_path_tail);
176 mdb_printf("ct_path_last: %22l#r::print struct mdi_pathfinfo\n",
177 value.ct_path_last);
178 mdb_printf("ct_path_count: %21d\n", value.ct_path_count);
179 mdb_printf("List of paths:\n");
180 mdb_pwalk("mdipi_client_list", (mdb_walk_cb_t)mpxio_walk_cb,
181 mdipathinfo_cb_str, (uintptr_t)value.ct_path_head);
183 mdb_printf("\n");
184 dump_state_str("Client State (ct_state)", value.ct_state,
185 mdi_client_states);
186 dump_mutex(value.ct_mutex, "per-client mutex (ct_mutex):");
187 mdb_printf("ct_flags: %26d\n", value.ct_flags);
188 if (value.ct_flags) {
189 dump_flags((unsigned long long)value.ct_flags, client_flags);
191 mdb_printf("ct_unstable: %23d\n", value.ct_unstable);
192 dump_condvar(value.ct_unstable_cv, "ct_unstable_cv");
193 dump_condvar(value.ct_failover_cv, "ct_failover_cv");
195 mdb_printf("\n");
196 mdb_printf("ct_failover_flags TEMP_VAR: %8d\n", value.ct_failover_flags)
198 mdb_printf("ct_failover_status UNUSED: %9d\n", value.ct_failover_status)
201 return (DCMD_OK);
205 * vhcilun()
207 * Get client info given a guid.
209 /* ARGSUSED */
210 static int
211 vhcilun(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
213 if (!(flags & DCMD_ADDRSPEC)) {
214 mdb_warn("sv_lun: requires an address");
215 return (DCMD_ERR);
218 return (i_vhcilun(addr, 0 /* display_single_guid */, 0));
222 * vhciguid()
224 * List all the clients.
226 /* ARGSUSED */
227 static int
228 vhciguid(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
231 struct i_ddi_soft_state ss;
232 int i;
234 mdi_vhci_t *mdi_vhci_value;
235 mdi_client_t *mdi_client_value;
236 struct client_hash *ct_hash_val;
237 struct client_hash *ct_hash_table_val;
239 int len = strlen(MDI_HCI_CLASS_SCSI);
240 int mdi_vhci_len = sizeof (*mdi_vhci_value);
241 int mdi_client_len = sizeof (*mdi_client_value);
242 int ct_hash_len = sizeof (*ct_hash_val);
244 int ct_hash_count = 0;
245 char *class;
246 int found = 0;
247 uintptr_t buf;
248 uintptr_t temp;
252 if (flags & DCMD_ADDRSPEC)
253 mdb_warn("This command doesn't use an address\n");
255 if (i_vhci_states(0, 0, 0, 0, &ss) != DCMD_OK)
256 return (DCMD_ERR);
258 if (mdb_readvar(&buf, "mdi_vhci_head") == -1) {
259 mdb_warn("mdi driver variable mdi_vhci_head not found.\n");
260 mdb_warn("Is the driver loaded ?\n");
261 return (DCMD_ERR);
263 mdb_printf("----------------- mdi_vhci_head @ %#lr ----------\n", buf);
264 mdi_vhci_value = (mdi_vhci_t *)mdb_alloc(mdi_vhci_len, UM_SLEEP|UM_GC);
265 if (mdb_vread(mdi_vhci_value, mdi_vhci_len, buf) != mdi_vhci_len) {
266 mdb_warn("vhciguid: Failed read on %l#r\n", mdi_vhci_value);
267 mdb_free(mdi_vhci_value, mdi_vhci_len);
268 return (DCMD_ERR);
270 temp = (uintptr_t)mdi_vhci_value->vh_class;
271 class = (char *)mdb_alloc(len, UM_SLEEP|UM_GC);
272 if (mdb_vread(class, strlen(MDI_HCI_CLASS_SCSI), temp)
273 != strlen(MDI_HCI_CLASS_SCSI)) {
274 mdb_warn("vhciguid: Failed read of class %l#r\n",
275 mdi_vhci_value);
276 mdb_free(mdi_vhci_value, mdi_vhci_len);
277 mdb_free(class, len);
278 return (DCMD_ERR);
280 class[len] = 0;
281 mdb_printf("----------------- class @ %s----------\n", class);
282 while (class) {
283 if (strcmp(class, MDI_HCI_CLASS_SCSI) == 0) {
284 found = 1;
285 break;
287 if (mdi_vhci_value->vh_next == NULL) {
288 break;
290 temp = (uintptr_t)mdi_vhci_value->vh_next;
291 if (mdb_vread(mdi_vhci_value, mdi_vhci_len, temp)
292 != mdi_vhci_len) {
293 mdb_warn("vhciguid: Failed read on vh->next %l#r\n",
294 mdi_vhci_value);
295 break;
297 temp = (uintptr_t)mdi_vhci_value->vh_class;
298 if (mdb_vread(class, strlen(MDI_HCI_CLASS_SCSI), temp) !=
299 strlen(MDI_HCI_CLASS_SCSI)) {
300 mdb_warn("vhciguid: Failed read on vh->next %l#r\n",
301 mdi_vhci_value);
302 break;
304 class[len] = 0;
307 if (found == 0) {
308 mdb_warn("vhciguid: No scsi_vhci class found");
309 mdb_free(mdi_vhci_value, mdi_vhci_len);
310 mdb_free(class, len);
311 return (DCMD_ERR);
313 mdb_printf("----- Number of devices found %d ----------\n",
314 mdi_vhci_value->vh_client_count);
315 for (i = 0; i < CLIENT_HASH_TABLE_SIZE; i++) {
316 ct_hash_table_val = &mdi_vhci_value->vh_client_table[i];
317 if (ct_hash_table_val == NULL)
318 continue;
320 /* Read client_hash structure */
321 ct_hash_val = (struct client_hash *)mdb_alloc(ct_hash_len,
322 UM_SLEEP|UM_GC);
323 temp = (uintptr_t)ct_hash_table_val;
324 if (mdb_vread(ct_hash_val, ct_hash_len, temp) != ct_hash_len) {
325 mdb_warn("Failed read on hash %l#r\n",
326 ct_hash_val);
327 break;
329 mdb_printf("----hash[%d] %l#r: devices mapped = %d --\n",
330 i, ct_hash_table_val, ct_hash_val->ct_hash_count);
331 if (ct_hash_val->ct_hash_count == 0) {
332 continue;
335 ct_hash_count = ct_hash_val->ct_hash_count;
337 /* Read mdi_client structures */
338 mdi_client_value = (mdi_client_t *)mdb_alloc(mdi_client_len,
339 UM_SLEEP|UM_GC);
340 temp = (uintptr_t)ct_hash_val->ct_hash_head;
341 if (mdb_vread(mdi_client_value, mdi_client_len, temp)
342 != mdi_client_len) {
343 mdb_warn("Failed read on client %l#r\n",
344 mdi_client_value);
345 break;
347 mdb_printf("mdi_client %l#r %l#r ------\n",
348 mdi_client_value, mdi_client_value->ct_vprivate);
349 vhcilun((uintptr_t)mdi_client_value->ct_vprivate,
350 DCMD_ADDRSPEC, 0, 0);
352 while (--ct_hash_count) {
353 temp = (uintptr_t)mdi_client_value->ct_hnext;
354 if (mdb_vread(mdi_client_value, mdi_client_len,
355 temp) != mdi_client_len) {
356 mdb_warn("Failed read on client %l#r\n",
357 mdi_client_value);
358 break;
360 vhcilun((uintptr_t)mdi_client_value->ct_vprivate,
361 DCMD_ADDRSPEC, 0, 0);
364 mdb_printf("----------done----------\n");
366 return (DCMD_OK);
370 * Print the flag name by comparing flags to the mask variable.
372 static void
373 dump_flags(unsigned long long flags, char **strings)
375 int i, linel = 8, first = 1;
376 unsigned long long mask = 1;
378 for (i = 0; i < 64; i++) {
379 if (strings[i] == NULL)
380 break;
381 if (flags & mask) {
382 if (!first) {
383 mdb_printf(" | ");
384 } else {
385 first = 0;
387 /* make output pretty */
388 linel += strlen(strings[i]) + 3;
389 if (linel > 80) {
390 mdb_printf("\n\t");
391 linel = strlen(strings[i]) + 1 + 8;
393 mdb_printf("%s", strings[i]);
395 mask <<= 1;
397 mdb_printf("\n");
400 /* ARGSUSED */
401 static int
402 vhci_states(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
404 return (i_vhci_states(addr, flags, argc, argv, NULL));
408 * dump_states()
410 * Print the state information for vhci_states().
412 static int
413 dump_states(uintptr_t array_vaddr, int verbose, struct i_ddi_soft_state *sp)
415 int i;
416 int array_size;
417 struct i_ddi_soft_state *ss;
418 struct scsi_vhci vhci;
420 if (sp == NULL) {
421 ss = (struct i_ddi_soft_state *)mdb_alloc(sizeof (*ss),
422 UM_SLEEP|UM_GC);
423 } else {
424 ss = sp;
426 if (mdb_vread(ss, sizeof (*ss), array_vaddr) != sizeof (*ss)) {
427 mdb_warn("Cannot read softstate struct (Invalid pointer?).\n");
428 return (DCMD_ERR);
430 array_size = ss->n_items * (sizeof (void *));
431 array_vaddr = (uintptr_t)ss->array;
432 ss->array = mdb_alloc(array_size, UM_SLEEP|UM_GC);
433 if (mdb_vread(ss->array, array_size, array_vaddr) != array_size) {
434 mdb_warn("Corrupted softstate struct.\n");
435 return (DCMD_ERR);
437 if (sp != NULL)
438 return (DCMD_OK);
439 if (verbose) {
441 * ss->size is of type size_t which is 4 bytes and 8 bytes
442 * on 32-bit and 64-bit systems respectively.
444 #ifdef _LP64
445 mdb_printf("Softstate size is %lld(0x%llx) bytes.\n\n",
446 ss->size, ss->size);
447 #else
448 mdb_printf("Softstate size is %ld(0x%lx) bytes.\n\n",
449 ss->size, ss->size);
450 #endif
451 mdb_printf("state pointer\t\t\t\t\tinstance\n");
452 mdb_printf("=============\t\t\t\t\t========\n");
454 for (i = 0; i < ss->n_items; i++) {
455 if (ss->array[i] == 0)
456 continue;
458 if (mdb_vread(&vhci, sizeof (vhci), (uintptr_t)ss->array[i])
459 != sizeof (vhci)) {
460 mdb_warn("Corrupted softstate struct.\n");
461 return (DCMD_ERR);
463 if (verbose) {
464 mdb_printf("%l#r::print struct scsi_vhci\t\t %d\n",
465 ss->array[i], i);
466 mdb_printf("\nvhci_conf_flags: %d\n",
467 vhci.vhci_conf_flags);
468 if (vhci.vhci_conf_flags) {
469 mdb_printf("\t");
470 dump_flags((unsigned long long)
471 vhci.vhci_conf_flags, vhci_conf_flags);
473 } else {
474 mdb_printf("%l#r\n", ss->array[i]);
477 return (DCMD_OK);
480 static int
481 get_mdbstr(uintptr_t addr, char *string_val)
483 if (mdb_readstr(string_val, MAXNAMELEN, addr) == -1) {
484 mdb_warn("Error Reading String from %l#r\n", addr);
485 return (1);
488 return (0);
491 static void
492 dump_state_str(char *name, uintptr_t addr, char **strings)
494 mdb_printf("%s: %s (%l#r)\n", name, strings[(unsigned long)addr], addr);
497 /* VHCI UTILS */
500 * i_vhci_states()
502 * Internal routine for vhci_states() to check for -v arg and then
503 * print state info.
505 /* ARGSUSED */
506 static int
507 i_vhci_states(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv,
508 struct i_ddi_soft_state *sp)
510 uintptr_t adr;
511 int verbose = 0;
513 if (mdb_readvar(&adr, "vhci_softstate") == -1) {
514 mdb_warn("vhci driver variable vhci_softstate not found.\n");
515 mdb_warn("Is the driver loaded ?\n");
516 return (DCMD_ERR);
518 if (sp == NULL) {
519 if (mdb_getopts(argc, argv,
520 'v', MDB_OPT_SETBITS, TRUE, &verbose) != argc) {
521 return (DCMD_USAGE);
525 return (dump_states(adr, verbose, sp));
529 * i_vhcilun()
531 * Internal routine for vhciguid() to print client info.
533 static int
534 i_vhcilun(uintptr_t addr, uint_t display_single_guid, char *guid)
537 scsi_vhci_lun_t value;
538 struct dev_info dev_info_value;
539 char string_val[MAXNAMELEN];
540 int found = 0;
541 struct mdi_client ct_value;
542 uintptr_t temp_addr;
544 do {
545 if (mdb_vread(&value, sizeof (scsi_vhci_lun_t), addr) !=
546 sizeof (scsi_vhci_lun_t)) {
547 mdb_warn("sv_lun: Failed read on %l#r", addr);
548 return (DCMD_ERR);
551 temp_addr = addr;
552 addr = (uintptr_t)value.svl_hash_next;
554 if (!get_mdbstr((uintptr_t)value.svl_lun_wwn, string_val)) {
555 if (display_single_guid) {
556 if (strcmp(string_val, guid) == 0) {
557 found = 1;
558 } else continue;
562 mdb_printf("%t%l#r::print struct scsi_vhci_lun", temp_addr);
564 if (mdb_vread(&dev_info_value, sizeof (struct dev_info),
565 (uintptr_t)value.svl_dip) != sizeof (struct dev_info)) {
566 mdb_warn("svl_dip: Failed read on %l#r",
567 value.svl_dip);
568 return (DCMD_ERR);
571 mdb_printf("\n%tGUID: %s\n", string_val);
572 if (value.svl_active_pclass != NULL) {
573 if (!get_mdbstr((uintptr_t)value.svl_active_pclass,
574 string_val)) {
575 mdb_printf("%tActv_cl: %s", string_val);
577 } else {
578 mdb_printf(" No active pclass");
580 if (display_single_guid) {
581 mdb_printf(" (%l#r)", value.svl_active_pclass);
584 mdb_printf("\n%t%l#r::print struct mdi_client",
585 dev_info_value.devi_mdi_client);
587 if (value.svl_flags) {
588 mdb_printf("\t");
589 dump_flags((unsigned long long)value.svl_flags,
590 svlun_flags);
591 } else {
592 mdb_printf("\n");
595 if (found) {
596 mdiclient((uintptr_t)dev_info_value.devi_mdi_client,
597 DCMD_ADDRSPEC, 0, 0);
598 } else {
599 if (mdb_vread(&ct_value, sizeof (struct mdi_client),
600 (uintptr_t)dev_info_value.devi_mdi_client) !=
601 sizeof (struct mdi_client)) {
602 mdb_warn("mdiclient: Failed read on %l#r",
603 dev_info_value.devi_mdi_client);
604 return (DCMD_ERR);
606 if (ct_value.ct_flags) {
607 mdb_printf("\t");
608 dump_flags((unsigned long long)
609 ct_value.ct_flags, client_flags);
611 mdb_printf("%t");
612 dump_state_str("LB", ct_value.ct_lb, client_lb_str);
613 mdb_printf("\n");
615 } while (addr && !found);
616 return (DCMD_OK);
619 static void
620 dump_mutex(kmutex_t m, char *name)
622 mdb_printf("%s is%s held\n", name, FT(m, uint64_t) == 0 ? " not" : "");
625 static void
626 dump_condvar(kcondvar_t c, char *name)
628 mdb_printf("Threads sleeping on %s = %d\n", name, (int)FT(c, ushort_t));
631 static void
632 dump_string(uintptr_t addr, char *name)
634 char string_val[MAXNAMELEN];
636 if (get_mdbstr(addr, string_val)) {
637 return;
639 mdb_printf("%s: %s (%l#r)\n", name, string_val, addr);
642 /* ARGSUSED */
643 static int
644 mpxio_walk_cb(uintptr_t addr, const void *data, void *cbdata)
646 mdb_printf("%t%l#r%s\n", addr, (char *)cbdata);
647 return (0);