xref: /illumos-gate/usr/src/cmd/mdb/common/modules/stmf_sbd/stmf_sbd.c (revision dea05b66b1fa2d0242e78345542e72df4f14a55f)
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 (c) 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 
25 #include <sys/dditypes.h>
26 #include <sys/mdb_modapi.h>
27 #include <sys/modctl.h>
28 #include <sys/sunddi.h>
29 
30 #include <lpif.h>
31 #include <stmf.h>
32 #include <stmf_ioctl.h>
33 #include <portif.h>
34 #include <stmf_sbd.h>
35 #include <sbd_impl.h>
36 #include <scsi/generic/persist.h>
37 
38 #define	STMF_SBD_FLAG_ARY_SZ	32
39 #define	STMF_SBD_STR_MAX	2048
40 #define	STMF_SBD_VERBOSE	0x00000001
41 
42 /* structure to pass arguments to mdb_walker callback function */
43 typedef struct stmf_sbd_cb_s {
44 	uint32_t flag;
45 } stmf_sbd_cb_t;
46 
47 char stmf_protocol_str [9][STMF_SBD_FLAG_ARY_SZ] = {
48 	"FIBRE_CHANNEL",	/* PROTOCOL_FIBRE_CHANNEL	0 */
49 	"PARALLEL_SCSI",	/* PROTOCOL_PARALLEL_SCSI	1 */
50 	"SSA",			/* PROTOCOL_SSA			2 */
51 	"IEEE_1394",		/* PROTOCOL_IEEE_1394		3 */
52 	"SRP",			/* PROTOCOL_SRP			4 */
53 	"iSCSI",		/* PROTOCOL_iSCSI		5 */
54 	"SAS",			/* PROTOCOL_SAS			6 */
55 	"ADT",			/* PROTOCOL_ADT			7 */
56 	"ATAPI",		/* PROTOCOL_ATAPI		8 */
57 };
58 
59 /*
60  * Support functions.
61  */
62 
63 /*
64  *        Variable 'bits' is a collection of flags for which a corresponding
65  *        description string is available at flag_ary.
66  *        So flag_ary should be an ary of strings with total_bits + 1 strings.
67  */
68 static void
69 stmf_sbd_print_bit_flags(char flag_ary[][STMF_SBD_FLAG_ARY_SZ],
70 					int total_bits, uint32_t bits) {
71 	uint32_t curbit = 0x01;
72 	int i, delim = 0;
73 
74 	for (i = 0; i < total_bits; i++) {
75 		if (bits & curbit) {
76 			mdb_printf("%s%s", (delim) ? " | " : "", flag_ary[i]);
77 			delim = 1;
78 		}
79 		curbit <<= 1;
80 	}
81 	mdb_printf("\n");
82 }
83 
84 
85 static void
86 stmf_sbd_print_pgr_info(sbd_pgr_t *pgr)
87 {
88 	char pgr_flag_str [5][STMF_SBD_FLAG_ARY_SZ] = {
89 		"SBD_PGR_APTPL",			/* 0x01 */
90 		"SBD_PGR_RSVD_ONE",			/* 0x02 */
91 		"SBD_PGR_RSVD_ALL_REGISTRANTS",		/* 0x04 */
92 		"SBD_PGR_ALL_KEYS_HAS_IT"		/* 0x08 */
93 	};
94 	char pgr_type_desc[9][48] = {"ILLEGAL",
95 	    "Write Exclusive",				/* 0x1 */
96 	    "ILLEGAL",
97 	    "Exclusive Access",				/* 0x3 */
98 	    "Write Exclusive, Registrants Only",	/* 0x5 */
99 	    "Exclusive Access, Registrants Only",	/* 0x6 */
100 	    "Write Exclusive, All Registrants",		/* 0x7 */
101 	    "Exclusive Access, All Registrants"		/* 0x8 */
102 	};
103 	char *type_str = pgr_type_desc[0];
104 
105 
106 	mdb_printf("PGR flags: ");
107 	stmf_sbd_print_bit_flags(pgr_flag_str, 4, pgr->pgr_flags);
108 	if (pgr->pgr_rsvholder || pgr->pgr_flags &
109 	    SBD_PGR_RSVD_ALL_REGISTRANTS) {
110 		mdb_printf("Reservation Details \n");
111 		mdb_printf("\tReservation holder: ");
112 		if (pgr->pgr_rsvholder)
113 			mdb_printf("%p\n", pgr->pgr_rsvholder);
114 		else
115 			mdb_printf("All Registrants\n");
116 		if (pgr->pgr_rsv_type < 8)
117 			type_str = pgr_type_desc[pgr->pgr_rsv_type];
118 		mdb_printf("\t            type  : %d => %s\n",
119 		    pgr->pgr_rsv_type, type_str);
120 		mdb_printf("\t            scope : %d\n", pgr->pgr_rsv_scope);
121 	} else {
122 		mdb_printf("No reservations.\n");
123 	}
124 }
125 
126 void
127 print_scsi_devid_desc(uintptr_t addr, uint16_t len, char *s)
128 {
129 	scsi_devid_desc_t   *id;
130 
131 	id = mdb_zalloc(len, UM_SLEEP);
132 	if (mdb_vread(id, len, addr) == -1) {
133 		mdb_warn("failed to read scsi_devid_desc at %p\n", addr);
134 		mdb_free(id, len);
135 		return;
136 	}
137 
138 	mdb_printf("%sTotal length:\t%d\n", s, len);
139 	mdb_printf("%sProtocol:\t%d => %-16s\n", s, id->protocol_id,
140 	    (id->protocol_id < 8) ? stmf_protocol_str[id->protocol_id] : "");
141 	mdb_printf("%sCode Set:\t%d\n", s, id->code_set);
142 	mdb_printf("%sIdent Length:\t%d\n", s, id->ident_length);
143 
144 	if (len > id->ident_length + 3) {
145 		id->ident[id->ident_length] = '\0';
146 		mdb_printf("%sIdent:\t%s\n", s, id->ident);
147 	} else {
148 		mdb_printf("%s(Can not recognize ident data)\n", s);
149 	}
150 	mdb_free(id, len);
151 	mdb_printf("\n");
152 }
153 
154 void
155 stmf_sbd_pgr_key_dcmd_help(void)
156 {
157 	mdb_printf(
158 	    "Prints info about pgr keys and reservations on the given lun.\n\n"
159 	    "Usage:  <addr>::stmf_sbd_pgr_key [-akv]\n"
160 	    "    where <addr> represent the address of\n"
161 	    "          sbd_lu_t by default\n"
162 	    "             or\n"
163 	    "          sbd_pgr_key_t if '-a' option is specified.\n"
164 	    "Options:\n"
165 	    "   -a   if specified, <addr> represents address of sbd_pgr_key_t\n"
166 	    "   -k   if specified, only prints key information\n"
167 	    "   -v   verbose output\n");
168 }
169 
170 
171 /*
172  * MDB WALKERS implementations
173  */
174 
175 static int
176 stmf_sbd_lu_walk_init(mdb_walk_state_t *wsp)
177 {
178 	if (wsp->walk_addr == NULL) {
179 		if (mdb_readvar(&wsp->walk_addr, "sbd_lu_list") == -1) {
180 			mdb_warn("failed to read sbd_lu_list\n");
181 			return (WALK_ERR);
182 		}
183 	}
184 	return (WALK_NEXT);
185 }
186 
187 static int
188 stmf_sbd_lu_walk_step(mdb_walk_state_t *wsp)
189 {
190 	uintptr_t	addr = wsp->walk_addr;
191 	sbd_lu_t	slu;
192 
193 	if (wsp->walk_addr == NULL)
194 		return (WALK_DONE);
195 
196 	if (mdb_vread(&slu, sizeof (sbd_lu_t), addr) == -1) {
197 		mdb_warn("failed to read sbd_lu_t at %p\n", addr);
198 		return (WALK_ERR);
199 	}
200 	wsp->walk_addr = (uintptr_t)slu.sl_next;
201 	return (wsp->walk_callback(addr, &slu, wsp->walk_cbdata));
202 }
203 
204 char *
205 stmf_sbd_getstr(uintptr_t addr, char *str) {
206 	if ((addr == 0) || (mdb_readstr(str, STMF_SBD_STR_MAX, addr) == -1))
207 		str = NULL;
208 	return (str);
209 }
210 
211 static int
212 stmf_sbd_lu_cb(uintptr_t addr, const sbd_lu_t *slu, stmf_sbd_cb_t *cb_st)
213 {
214 	if (cb_st->flag & STMF_SBD_VERBOSE) {
215 		char str[STMF_SBD_STR_MAX];
216 
217 		mdb_printf("sbd_lu - %p\n", addr);
218 		mdb_printf("\tsl_name:          %-?p  %s\n", slu->sl_name,
219 		    stmf_sbd_getstr((uintptr_t)slu->sl_name, str));
220 		mdb_printf("\tsl_alias:         %-?p  %s\n", slu->sl_alias,
221 		    stmf_sbd_getstr((uintptr_t)slu->sl_alias, str));
222 		mdb_printf("\tsl_meta_filename: %-?p  %s\n",
223 		    slu->sl_meta_filename,
224 		    stmf_sbd_getstr((uintptr_t)slu->sl_meta_filename, str));
225 		mdb_printf("\tsl_data_filename: %-?p  %s\n",
226 		    slu->sl_data_filename,
227 		    stmf_sbd_getstr((uintptr_t)slu->sl_data_filename, str));
228 		mdb_printf("\tsl_mgmt_url:      %-?p  %s\n", slu->sl_mgmt_url,
229 		    stmf_sbd_getstr((uintptr_t)slu->sl_mgmt_url, str));
230 		mdb_printf("\tsl_zfs_meta:      %-?p\n", slu->sl_zfs_meta);
231 		mdb_printf("\tsl_it_list:       %-?p\n", slu->sl_it_list);
232 		mdb_printf("\tsl_pgr:           %-?p\n", slu->sl_pgr);
233 		mdb_printf("\n");
234 	} else {
235 		mdb_printf("%p\n", addr);
236 	}
237 	return (WALK_NEXT);
238 }
239 
240 static int
241 stmf_sbd_pgr_key_walk_init(mdb_walk_state_t *wsp)
242 {
243 	if (wsp->walk_addr == NULL) {
244 		mdb_warn("<pgr_key_list addr>::walk stmf_sbd_pgr_key\n");
245 		return (WALK_ERR);
246 	}
247 	return (WALK_NEXT);
248 }
249 
250 static int
251 stmf_sbd_pgr_key_walk_step(mdb_walk_state_t *wsp)
252 {
253 	uintptr_t	addr = wsp->walk_addr;
254 	sbd_pgr_key_t	key;
255 
256 	if (wsp->walk_addr == NULL)
257 		return (WALK_DONE);
258 
259 	if (mdb_vread(&key, sizeof (sbd_pgr_key_t), addr) == -1) {
260 		mdb_warn("failed to read sbd_pgr_key_t at %p\n", addr);
261 		return (WALK_ERR);
262 	}
263 	wsp->walk_addr = (uintptr_t)key.pgr_key_next;
264 	return (wsp->walk_callback(addr, &key, wsp->walk_cbdata));
265 }
266 
267 static int
268 stmf_sbd_pgr_key_cb(uintptr_t addr, const sbd_pgr_key_t *key,
269 					stmf_sbd_cb_t *cb_st)
270 {
271 	char key_flag_str [5][STMF_SBD_FLAG_ARY_SZ] = {
272 		"SBD_PGR_KEY_ALL_TG_PT",   /* 0x01 */
273 		"SBD_PGR_KEY_TPT_ID_FLAG", /* 0x02 */
274 	};
275 
276 	if (cb_st->flag & STMF_SBD_VERBOSE) {
277 		mdb_printf("sbd_pgr_key - %p\n", addr);
278 		mdb_printf("\tRegistered key:      0x%llx\n", key->pgr_key);
279 		mdb_printf("\tKey Flags:           ");
280 		stmf_sbd_print_bit_flags(key_flag_str, 2, key->pgr_key_flags);
281 		mdb_printf("\tpgr_key_it:          %?-p\n", key->pgr_key_it);
282 		mdb_printf("\tLocal Device ID:     %?-p\n",
283 		    key->pgr_key_lpt_id);
284 		print_scsi_devid_desc((uintptr_t)key->pgr_key_lpt_id,
285 		    key->pgr_key_lpt_len, "		");
286 		mdb_printf("\tRemote scsi devid desc: %?-p\n",
287 		    key->pgr_key_rpt_id);
288 		print_scsi_devid_desc((uintptr_t)key->pgr_key_rpt_id,
289 		    key->pgr_key_rpt_len, "		");
290 	} else {
291 		mdb_printf("%p\n", addr);
292 	}
293 	return (WALK_NEXT);
294 }
295 
296 static int
297 stmf_sbd_it_walk_init(mdb_walk_state_t *wsp)
298 {
299 	if (wsp->walk_addr == NULL) {
300 		mdb_warn("<sbd_it_list addr>::walk stmf_sbd_pgr_key\n");
301 		return (WALK_ERR);
302 	}
303 	return (WALK_NEXT);
304 }
305 
306 static int
307 stmf_sbd_it_walk_step(mdb_walk_state_t *wsp)
308 {
309 	uintptr_t	addr = wsp->walk_addr;
310 	sbd_it_data_t	it;
311 
312 	if (wsp->walk_addr == NULL)
313 		return (WALK_DONE);
314 
315 	if (mdb_vread(&it, sizeof (sbd_it_data_t), addr) == -1) {
316 		mdb_warn("failed to read sbd_it_data_t at %p\n", addr);
317 		return (WALK_ERR);
318 	}
319 	wsp->walk_addr = (uintptr_t)it.sbd_it_next;
320 	return (wsp->walk_callback(addr, &it, wsp->walk_cbdata));
321 }
322 
323 static int
324 stmf_sbd_it_cb(uintptr_t addr, const sbd_it_data_t *it, stmf_sbd_cb_t *cb_st)
325 {
326 	char it_flag_str [5][STMF_SBD_FLAG_ARY_SZ] = {
327 		"SBD_IT_HAS_SCSI2_RESERVATION",		/* 0x0001 */
328 		"SBD_IT_PGR_REGISTERED",		/* 0x0002 */
329 		"SBD_IT_PGR_EXCLUSIVE_RSV_HOLDER",	/* 0x0004 */
330 		"SBD_IT_PGR_CHECK_FLAG",		/* 0x0008 */
331 	};
332 
333 	if (cb_st->flag & STMF_SBD_VERBOSE) {
334 		mdb_printf("SBD IT DATA - %p\n", addr);
335 		mdb_printf("\tSession ID: 0x%0-lx\n", it->sbd_it_session_id);
336 		mdb_printf("\tIT Flags:   ");
337 		stmf_sbd_print_bit_flags(it_flag_str, 4, it->sbd_it_flags);
338 		mdb_printf("\tPGR Key:    %-p\n", it->pgr_key_ptr);
339 		mdb_printf("\n");
340 	} else {
341 		mdb_printf("%p\n", addr);
342 	}
343 	return (WALK_NEXT);
344 }
345 
346 /*
347  * MDB DCMDS implementations.
348  */
349 
350 int
351 stmf_sbd_lu(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
352 {
353 	uint_t		verbose = FALSE;
354 	sbd_lu_t	slu;
355 	stmf_sbd_cb_t	cb_st = {0};
356 
357 	if (mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, TRUE, &verbose, NULL)
358 	    != argc)
359 		return (DCMD_USAGE);
360 	if (verbose)
361 		cb_st.flag |= STMF_SBD_VERBOSE;
362 
363 	if (flags & DCMD_ADDRSPEC) {
364 		cb_st.flag |= STMF_SBD_VERBOSE;
365 		if (mdb_vread(&slu, sizeof (sbd_lu_t), addr) == -1) {
366 			mdb_warn("failed to read sbd_lu_t at %p\n", addr);
367 			return (DCMD_ERR);
368 		}
369 		if (stmf_sbd_lu_cb(addr, &slu, &cb_st) == WALK_ERR)
370 			return (DCMD_ERR);
371 	} else {
372 		if (mdb_walk("stmf_sbd_lu", (mdb_walk_cb_t)stmf_sbd_lu_cb,
373 		    &cb_st) == -1) {
374 			mdb_warn("failed to walk sbd_lu_list\n");
375 			return (DCMD_ERR);
376 		}
377 	}
378 	return (DCMD_OK);
379 }
380 
381 static int
382 stmf_sbd_pgr_key(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
383 {
384 	uint_t		verbose = FALSE, keyonly = FALSE, pgrkeyaddr = FALSE;
385 	sbd_lu_t	slu;
386 	sbd_pgr_t	pgr;
387 	sbd_pgr_key_t	key;
388 	stmf_sbd_cb_t	cb_st = {0};
389 
390 	if (!(flags & DCMD_ADDRSPEC))
391 		return (DCMD_USAGE);
392 
393 	if (mdb_getopts(argc, argv,
394 	    'a', MDB_OPT_SETBITS, TRUE, &pgrkeyaddr,
395 	    'k', MDB_OPT_SETBITS, TRUE, &keyonly,
396 	    'v', MDB_OPT_SETBITS, TRUE, &verbose, NULL) != argc)
397 		return (DCMD_USAGE);
398 
399 	if (pgrkeyaddr || verbose)
400 		cb_st.flag |= STMF_SBD_VERBOSE;
401 
402 	/* If address of pgr_key is given, just print that key and return */
403 	if (pgrkeyaddr) {
404 		if (mdb_vread(&key, sizeof (sbd_pgr_key_t), addr) == -1) {
405 			mdb_warn("failed to read sbd_pgr_key at %p\n", addr);
406 			return (DCMD_ERR);
407 		}
408 		if (stmf_sbd_pgr_key_cb(addr, &key, &cb_st) == WALK_ERR) {
409 			return (DCMD_ERR);
410 		}
411 		return (DCMD_OK);
412 	} else {
413 		if (mdb_vread(&slu, sizeof (sbd_lu_t), addr) == -1) {
414 			mdb_warn("failed to read sbd_lu at %p\n", addr);
415 			return (DCMD_ERR);
416 		}
417 	}
418 
419 	if (verbose) {
420 		mdb_printf("\nLU:- %p\n", addr);
421 	}
422 	/* Just a sanity check, not necessarily needed */
423 	if (slu.sl_pgr == NULL) {
424 		if (verbose)
425 			mdb_warn("pgr structure not found for lun %p\n", addr);
426 		return (DCMD_OK);
427 	}
428 
429 	if (mdb_vread(&pgr, sizeof (sbd_pgr_t), (uintptr_t)slu.sl_pgr) == -1) {
430 		mdb_warn("failed to read sbd_lu at %p\n", slu.sl_pgr);
431 		return (DCMD_ERR);
432 	}
433 
434 	if (!keyonly)
435 		stmf_sbd_print_pgr_info(&pgr);
436 
437 	if (pgr.pgr_keylist == NULL) {
438 		if (verbose)
439 			mdb_printf("No registered pgr keys found\n");
440 		return (DCMD_OK);
441 	} else {
442 		if (!keyonly)
443 			mdb_printf("\nKeys\n");
444 	}
445 
446 	if (mdb_pwalk("stmf_sbd_pgr_key", (mdb_walk_cb_t)stmf_sbd_pgr_key_cb,
447 	    &cb_st, (uintptr_t)pgr.pgr_keylist) == -1) {
448 		mdb_warn("failed to walk pgr_keylist\n");
449 		return (DCMD_ERR);
450 	}
451 	return (DCMD_OK);
452 }
453 
454 static int
455 stmf_sbd_it(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
456 {
457 	uint_t		verbose = FALSE;
458 	sbd_lu_t	slu;
459 	stmf_sbd_cb_t	cb_st = {0};
460 
461 	if (!(flags & DCMD_ADDRSPEC))
462 		return (DCMD_USAGE);
463 
464 	if (mdb_getopts(argc, argv,
465 	    'v', MDB_OPT_SETBITS, TRUE, &verbose, NULL) != argc)
466 		return (DCMD_USAGE);
467 
468 	if (verbose) {
469 		cb_st.flag |= STMF_SBD_VERBOSE;
470 		mdb_printf("LU:- %p\n", addr);
471 	}
472 
473 	/* If address of pgr_key is given, just print that key and return */
474 	if (mdb_vread(&slu, sizeof (sbd_lu_t), addr) == -1) {
475 		mdb_warn("failed to read sbd_lu at %p\n", addr);
476 		return (DCMD_ERR);
477 	}
478 
479 	/* Just a sanity check, not necessarily needed */
480 	if (slu.sl_it_list == NULL) {
481 		if (verbose)
482 			mdb_warn("sbd_it_list is empty%p\n", addr);
483 		return (DCMD_OK);
484 	}
485 
486 	if (mdb_pwalk("stmf_sbd_it", (mdb_walk_cb_t)stmf_sbd_it_cb, &cb_st,
487 	    (uintptr_t)slu.sl_it_list) == -1) {
488 		mdb_warn("failed to walk sbd_lu_it_list\n");
489 		return (DCMD_ERR);
490 	}
491 	return (DCMD_OK);
492 }
493 
494 /*
495  * MDB dmcds and walkers definitions
496  */
497 
498 static const mdb_dcmd_t dcmds[] = {
499 	{ "stmf_sbd_lu", "?[-v]", "Print the list of sbd_lu_t",
500 	    stmf_sbd_lu, NULL },
501 	{ "stmf_sbd_it", ":[-v]", "Print the list of sbd_it_data for given lu",
502 	    stmf_sbd_it, NULL },
503 	{ "stmf_sbd_pgr_key", ":[-kov]", "Print the list of pgr keys",
504 	    stmf_sbd_pgr_key, stmf_sbd_pgr_key_dcmd_help },
505 	{ NULL }
506 };
507 
508 static const mdb_walker_t walkers[] = {
509 	{ "stmf_sbd_lu", "walk list of stmf_sbd_lu structures",
510 	    stmf_sbd_lu_walk_init, stmf_sbd_lu_walk_step, NULL },
511 	{ "stmf_sbd_pgr_key", "walk the pgr keys of the given pgr key list",
512 	    stmf_sbd_pgr_key_walk_init, stmf_sbd_pgr_key_walk_step, NULL },
513 	{ "stmf_sbd_it", "walk the sbd_it_data for the given it list",
514 	    stmf_sbd_it_walk_init, stmf_sbd_it_walk_step, NULL },
515 	{ NULL }
516 };
517 
518 static const mdb_modinfo_t modinfo = {
519 	MDB_API_VERSION, dcmds, walkers
520 };
521 
522 const mdb_modinfo_t *
523 _mdb_init(void)
524 {
525 	return (&modinfo);
526 }
527