xref: /freebsd-src/usr.sbin/zonectl/zonectl.c (revision b561d8f59c7de56f5da576530961aaeea2d89875)
19a6844d5SKenneth D. Merry /*-
29a6844d5SKenneth D. Merry  * Copyright (c) 2015, 2016 Spectra Logic Corporation
39a6844d5SKenneth D. Merry  * All rights reserved.
49a6844d5SKenneth D. Merry  *
59a6844d5SKenneth D. Merry  * Redistribution and use in source and binary forms, with or without
69a6844d5SKenneth D. Merry  * modification, are permitted provided that the following conditions
79a6844d5SKenneth D. Merry  * are met:
89a6844d5SKenneth D. Merry  * 1. Redistributions of source code must retain the above copyright
99a6844d5SKenneth D. Merry  *    notice, this list of conditions, and the following disclaimer,
109a6844d5SKenneth D. Merry  *    without modification.
119a6844d5SKenneth D. Merry  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
129a6844d5SKenneth D. Merry  *    substantially similar to the "NO WARRANTY" disclaimer below
139a6844d5SKenneth D. Merry  *    ("Disclaimer") and any redistribution must be conditioned upon
149a6844d5SKenneth D. Merry  *    including a substantially similar Disclaimer requirement for further
159a6844d5SKenneth D. Merry  *    binary redistribution.
169a6844d5SKenneth D. Merry  *
179a6844d5SKenneth D. Merry  * NO WARRANTY
189a6844d5SKenneth D. Merry  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
199a6844d5SKenneth D. Merry  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
209a6844d5SKenneth D. Merry  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
219a6844d5SKenneth D. Merry  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
229a6844d5SKenneth D. Merry  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
239a6844d5SKenneth D. Merry  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
249a6844d5SKenneth D. Merry  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
259a6844d5SKenneth D. Merry  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
269a6844d5SKenneth D. Merry  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
279a6844d5SKenneth D. Merry  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
289a6844d5SKenneth D. Merry  * POSSIBILITY OF SUCH DAMAGES.
299a6844d5SKenneth D. Merry  *
309a6844d5SKenneth D. Merry  * Authors: Ken Merry           (Spectra Logic Corporation)
319a6844d5SKenneth D. Merry  */
329a6844d5SKenneth D. Merry 
339a6844d5SKenneth D. Merry #include <sys/cdefs.h>
349a6844d5SKenneth D. Merry #include <sys/ioctl.h>
35*b561d8f5SElyes Haouas #include <sys/param.h>
369a6844d5SKenneth D. Merry #include <sys/stdint.h>
379a6844d5SKenneth D. Merry #include <sys/endian.h>
389a6844d5SKenneth D. Merry #include <sys/sbuf.h>
399a6844d5SKenneth D. Merry #include <sys/queue.h>
409a6844d5SKenneth D. Merry #include <sys/disk.h>
419a6844d5SKenneth D. Merry #include <sys/disk_zone.h>
429a6844d5SKenneth D. Merry #include <stdio.h>
439a6844d5SKenneth D. Merry #include <stdlib.h>
449a6844d5SKenneth D. Merry #include <inttypes.h>
459a6844d5SKenneth D. Merry #include <unistd.h>
469a6844d5SKenneth D. Merry #include <string.h>
479a6844d5SKenneth D. Merry #include <strings.h>
489a6844d5SKenneth D. Merry #include <fcntl.h>
499a6844d5SKenneth D. Merry #include <ctype.h>
509a6844d5SKenneth D. Merry #include <limits.h>
519a6844d5SKenneth D. Merry #include <err.h>
529a6844d5SKenneth D. Merry #include <locale.h>
539a6844d5SKenneth D. Merry 
549a6844d5SKenneth D. Merry #include <cam/cam.h>
559a6844d5SKenneth D. Merry #include <cam/cam_debug.h>
569a6844d5SKenneth D. Merry #include <cam/cam_ccb.h>
579a6844d5SKenneth D. Merry #include <cam/scsi/scsi_all.h>
589a6844d5SKenneth D. Merry 
599a6844d5SKenneth D. Merry static struct scsi_nv zone_cmd_map[] = {
609a6844d5SKenneth D. Merry 	{ "rz", DISK_ZONE_REPORT_ZONES },
619a6844d5SKenneth D. Merry 	{ "reportzones", DISK_ZONE_REPORT_ZONES },
629a6844d5SKenneth D. Merry 	{ "close", DISK_ZONE_CLOSE },
639a6844d5SKenneth D. Merry 	{ "finish", DISK_ZONE_FINISH },
649a6844d5SKenneth D. Merry 	{ "open", DISK_ZONE_OPEN },
659a6844d5SKenneth D. Merry 	{ "rwp", DISK_ZONE_RWP },
669a6844d5SKenneth D. Merry 	{ "params", DISK_ZONE_GET_PARAMS }
679a6844d5SKenneth D. Merry };
689a6844d5SKenneth D. Merry 
699a6844d5SKenneth D. Merry static struct scsi_nv zone_rep_opts[] = {
709a6844d5SKenneth D. Merry 	{ "all", DISK_ZONE_REP_ALL },
719a6844d5SKenneth D. Merry 	{ "empty", DISK_ZONE_REP_EMPTY },
729a6844d5SKenneth D. Merry 	{ "imp_open", DISK_ZONE_REP_IMP_OPEN },
739a6844d5SKenneth D. Merry 	{ "exp_open", DISK_ZONE_REP_EXP_OPEN },
749a6844d5SKenneth D. Merry 	{ "closed", DISK_ZONE_REP_CLOSED },
759a6844d5SKenneth D. Merry 	{ "full", DISK_ZONE_REP_FULL },
769a6844d5SKenneth D. Merry 	{ "readonly", DISK_ZONE_REP_READONLY },
779a6844d5SKenneth D. Merry 	{ "ro", DISK_ZONE_REP_READONLY },
789a6844d5SKenneth D. Merry 	{ "offline", DISK_ZONE_REP_OFFLINE },
799a6844d5SKenneth D. Merry 	{ "reset", DISK_ZONE_REP_RWP },
809a6844d5SKenneth D. Merry 	{ "rwp", DISK_ZONE_REP_RWP },
819a6844d5SKenneth D. Merry 	{ "nonseq", DISK_ZONE_REP_NON_SEQ },
829a6844d5SKenneth D. Merry 	{ "nonwp", DISK_ZONE_REP_NON_WP }
839a6844d5SKenneth D. Merry };
849a6844d5SKenneth D. Merry 
859a6844d5SKenneth D. Merry 
869a6844d5SKenneth D. Merry typedef enum {
879a6844d5SKenneth D. Merry 	ZONE_OF_NORMAL	= 0x00,
889a6844d5SKenneth D. Merry 	ZONE_OF_SUMMARY	= 0x01,
899a6844d5SKenneth D. Merry 	ZONE_OF_SCRIPT	= 0x02
909a6844d5SKenneth D. Merry } zone_output_flags;
919a6844d5SKenneth D. Merry 
929a6844d5SKenneth D. Merry static struct scsi_nv zone_print_opts[] = {
939a6844d5SKenneth D. Merry 	{ "normal", ZONE_OF_NORMAL },
949a6844d5SKenneth D. Merry 	{ "summary", ZONE_OF_SUMMARY },
959a6844d5SKenneth D. Merry 	{ "script", ZONE_OF_SCRIPT }
969a6844d5SKenneth D. Merry };
979a6844d5SKenneth D. Merry 
989a6844d5SKenneth D. Merry static struct scsi_nv zone_cmd_desc_table[] = {
999a6844d5SKenneth D. Merry 	{"Report Zones", DISK_ZONE_RZ_SUP },
1009a6844d5SKenneth D. Merry 	{"Open", DISK_ZONE_OPEN_SUP },
1019a6844d5SKenneth D. Merry 	{"Close", DISK_ZONE_CLOSE_SUP },
1029a6844d5SKenneth D. Merry 	{"Finish", DISK_ZONE_FINISH_SUP },
1039a6844d5SKenneth D. Merry 	{"Reset Write Pointer", DISK_ZONE_RWP_SUP }
1049a6844d5SKenneth D. Merry };
1059a6844d5SKenneth D. Merry 
1069a6844d5SKenneth D. Merry typedef enum {
1079a6844d5SKenneth D. Merry 	ZONE_PRINT_OK,
1089a6844d5SKenneth D. Merry 	ZONE_PRINT_MORE_DATA,
1099a6844d5SKenneth D. Merry 	ZONE_PRINT_ERROR
1109a6844d5SKenneth D. Merry } zone_print_status;
1119a6844d5SKenneth D. Merry 
1129a6844d5SKenneth D. Merry typedef enum {
1139a6844d5SKenneth D. Merry 	ZONE_FW_START,
1149a6844d5SKenneth D. Merry 	ZONE_FW_LEN,
1159a6844d5SKenneth D. Merry 	ZONE_FW_WP,
1169a6844d5SKenneth D. Merry 	ZONE_FW_TYPE,
1179a6844d5SKenneth D. Merry 	ZONE_FW_COND,
1189a6844d5SKenneth D. Merry 	ZONE_FW_SEQ,
1199a6844d5SKenneth D. Merry 	ZONE_FW_RESET,
1209a6844d5SKenneth D. Merry 	ZONE_NUM_FIELDS
1219a6844d5SKenneth D. Merry } zone_field_widths;
1229a6844d5SKenneth D. Merry 
1239a6844d5SKenneth D. Merry 
1249a6844d5SKenneth D. Merry static void usage(int error);
1259a6844d5SKenneth D. Merry static void zonectl_print_params(struct disk_zone_disk_params *params);
1269a6844d5SKenneth D. Merry zone_print_status zonectl_print_rz(struct disk_zone_report *report,
1279a6844d5SKenneth D. Merry 				   zone_output_flags out_flags, int first_pass);
1289a6844d5SKenneth D. Merry 
1299a6844d5SKenneth D. Merry static void
usage(int error)1309a6844d5SKenneth D. Merry usage(int error)
1319a6844d5SKenneth D. Merry {
1329a6844d5SKenneth D. Merry 	fprintf(error ? stderr : stdout,
1339a6844d5SKenneth D. Merry "usage: zonectl <-d dev> <-c cmd> [-a][-o rep_opts] [-l lba][-P print_opts]\n"
1349a6844d5SKenneth D. Merry 	);
1359a6844d5SKenneth D. Merry }
1369a6844d5SKenneth D. Merry 
1379a6844d5SKenneth D. Merry static void
zonectl_print_params(struct disk_zone_disk_params * params)1389a6844d5SKenneth D. Merry zonectl_print_params(struct disk_zone_disk_params *params)
1399a6844d5SKenneth D. Merry {
1409a6844d5SKenneth D. Merry 	unsigned int i;
1419a6844d5SKenneth D. Merry 	int first;
1429a6844d5SKenneth D. Merry 
1439a6844d5SKenneth D. Merry 	printf("Zone Mode: ");
1449a6844d5SKenneth D. Merry 	switch (params->zone_mode) {
1459a6844d5SKenneth D. Merry 	case DISK_ZONE_MODE_NONE:
1469a6844d5SKenneth D. Merry 		printf("None");
1479a6844d5SKenneth D. Merry 		break;
1489a6844d5SKenneth D. Merry 	case DISK_ZONE_MODE_HOST_AWARE:
1499a6844d5SKenneth D. Merry 		printf("Host Aware");
1509a6844d5SKenneth D. Merry 		break;
1519a6844d5SKenneth D. Merry 	case DISK_ZONE_MODE_DRIVE_MANAGED:
1529a6844d5SKenneth D. Merry 		printf("Drive Managed");
1539a6844d5SKenneth D. Merry 		break;
1549a6844d5SKenneth D. Merry 	case DISK_ZONE_MODE_HOST_MANAGED:
1559a6844d5SKenneth D. Merry 		printf("Host Managed");
1569a6844d5SKenneth D. Merry 		break;
1579a6844d5SKenneth D. Merry 	default:
1589a6844d5SKenneth D. Merry 		printf("Unknown mode %#x", params->zone_mode);
1599a6844d5SKenneth D. Merry 		break;
1609a6844d5SKenneth D. Merry 	}
1619a6844d5SKenneth D. Merry 	printf("\n");
1629a6844d5SKenneth D. Merry 
1639a6844d5SKenneth D. Merry 	first = 1;
1649a6844d5SKenneth D. Merry 	printf("Command support: ");
1659a6844d5SKenneth D. Merry 	for (i = 0; i < sizeof(zone_cmd_desc_table) /
1669a6844d5SKenneth D. Merry 	     sizeof(zone_cmd_desc_table[0]); i++) {
1679a6844d5SKenneth D. Merry 		if (params->flags & zone_cmd_desc_table[i].value) {
1689a6844d5SKenneth D. Merry 			if (first == 0)
1699a6844d5SKenneth D. Merry 				printf(", ");
1709a6844d5SKenneth D. Merry 			else
1719a6844d5SKenneth D. Merry 				first = 0;
1729a6844d5SKenneth D. Merry 			printf("%s", zone_cmd_desc_table[i].name);
1739a6844d5SKenneth D. Merry 		}
1749a6844d5SKenneth D. Merry 	}
1759a6844d5SKenneth D. Merry 	if (first == 1)
1769a6844d5SKenneth D. Merry 		printf("None");
1779a6844d5SKenneth D. Merry 	printf("\n");
1789a6844d5SKenneth D. Merry 
1799a6844d5SKenneth D. Merry 	printf("Unrestricted Read in Sequential Write Required Zone "
1809a6844d5SKenneth D. Merry 	    "(URSWRZ): %s\n", (params->flags & DISK_ZONE_DISK_URSWRZ) ?
1819a6844d5SKenneth D. Merry 	    "Yes" : "No");
1829a6844d5SKenneth D. Merry 
1839a6844d5SKenneth D. Merry 	printf("Optimal Number of Open Sequential Write Preferred Zones: ");
1849a6844d5SKenneth D. Merry 	if (params->flags & DISK_ZONE_OPT_SEQ_SET)
1859a6844d5SKenneth D. Merry 		if (params->optimal_seq_zones == SVPD_ZBDC_OPT_SEQ_NR)
1869a6844d5SKenneth D. Merry 			printf("Not Reported");
1879a6844d5SKenneth D. Merry 		else
1889a6844d5SKenneth D. Merry 			printf("%ju", (uintmax_t)params->optimal_seq_zones);
1899a6844d5SKenneth D. Merry 	else
1909a6844d5SKenneth D. Merry 		printf("Not Set");
1919a6844d5SKenneth D. Merry 	printf("\n");
1929a6844d5SKenneth D. Merry 
1939a6844d5SKenneth D. Merry 
1949a6844d5SKenneth D. Merry 	printf("Optimal Number of Non-Sequentially Written Sequential Write "
1959a6844d5SKenneth D. Merry 	   "Preferred Zones: ");
1969a6844d5SKenneth D. Merry 	if (params->flags & DISK_ZONE_OPT_NONSEQ_SET)
1979a6844d5SKenneth D. Merry 		if (params->optimal_nonseq_zones == SVPD_ZBDC_OPT_NONSEQ_NR)
1989a6844d5SKenneth D. Merry 			printf("Not Reported");
1999a6844d5SKenneth D. Merry 		else
2009a6844d5SKenneth D. Merry 			printf("%ju",(uintmax_t)params->optimal_nonseq_zones);
2019a6844d5SKenneth D. Merry 	else
2029a6844d5SKenneth D. Merry 		printf("Not Set");
2039a6844d5SKenneth D. Merry 	printf("\n");
2049a6844d5SKenneth D. Merry 
2059a6844d5SKenneth D. Merry 	printf("Maximum Number of Open Sequential Write Required Zones: ");
2069a6844d5SKenneth D. Merry 	if (params->flags & DISK_ZONE_MAX_SEQ_SET)
2079a6844d5SKenneth D. Merry 		if (params->max_seq_zones == SVPD_ZBDC_MAX_SEQ_UNLIMITED)
2089a6844d5SKenneth D. Merry 			printf("Unlimited");
2099a6844d5SKenneth D. Merry 		else
2109a6844d5SKenneth D. Merry 			printf("%ju", (uintmax_t)params->max_seq_zones);
2119a6844d5SKenneth D. Merry 	else
2129a6844d5SKenneth D. Merry 		printf("Not Set");
2139a6844d5SKenneth D. Merry 	printf("\n");
2149a6844d5SKenneth D. Merry }
2159a6844d5SKenneth D. Merry 
2169a6844d5SKenneth D. Merry zone_print_status
zonectl_print_rz(struct disk_zone_report * report,zone_output_flags out_flags,int first_pass)2179a6844d5SKenneth D. Merry zonectl_print_rz(struct disk_zone_report *report, zone_output_flags out_flags,
2189a6844d5SKenneth D. Merry 		 int first_pass)
2199a6844d5SKenneth D. Merry {
2209a6844d5SKenneth D. Merry 	zone_print_status status = ZONE_PRINT_OK;
2219a6844d5SKenneth D. Merry 	struct disk_zone_rep_header *header = &report->header;
2229a6844d5SKenneth D. Merry 	int field_widths[ZONE_NUM_FIELDS];
2239a6844d5SKenneth D. Merry 	struct disk_zone_rep_entry *entry;
2249a6844d5SKenneth D. Merry 	uint64_t next_lba = 0;
2259a6844d5SKenneth D. Merry 	char tmpstr[80];
2269a6844d5SKenneth D. Merry 	char word_sep;
2279a6844d5SKenneth D. Merry 	uint32_t i;
2289a6844d5SKenneth D. Merry 
2299a6844d5SKenneth D. Merry 	field_widths[ZONE_FW_START] = 11;
2309a6844d5SKenneth D. Merry 	field_widths[ZONE_FW_LEN] = 6;
2319a6844d5SKenneth D. Merry 	field_widths[ZONE_FW_WP] = 11;
2329a6844d5SKenneth D. Merry 	field_widths[ZONE_FW_TYPE] = 13;
2339a6844d5SKenneth D. Merry 	field_widths[ZONE_FW_COND] = 13;
2349a6844d5SKenneth D. Merry 	field_widths[ZONE_FW_SEQ] = 14;
2359a6844d5SKenneth D. Merry 	field_widths[ZONE_FW_RESET] = 16;
2369a6844d5SKenneth D. Merry 
237760dbe84SXin LI 	if ((report->entries_available - report->entries_filled) > 0)
2389a6844d5SKenneth D. Merry 		status = ZONE_PRINT_MORE_DATA;
2399a6844d5SKenneth D. Merry 
2409a6844d5SKenneth D. Merry 	if (out_flags == ZONE_OF_SCRIPT)
2419a6844d5SKenneth D. Merry 		word_sep = '_';
2429a6844d5SKenneth D. Merry 	else
2439a6844d5SKenneth D. Merry 		word_sep = ' ';
2449a6844d5SKenneth D. Merry 
2459a6844d5SKenneth D. Merry 	if ((out_flags != ZONE_OF_SCRIPT)
2469a6844d5SKenneth D. Merry 	 && (first_pass != 0)) {
2479a6844d5SKenneth D. Merry 		printf("%u zones, Maximum LBA %#jx (%ju)\n",
2489a6844d5SKenneth D. Merry 		    report->entries_available,
2499a6844d5SKenneth D. Merry 		    (uintmax_t)header->maximum_lba,
2509a6844d5SKenneth D. Merry 		    (uintmax_t)header->maximum_lba);
2519a6844d5SKenneth D. Merry 
2529a6844d5SKenneth D. Merry 		switch (header->same) {
2539a6844d5SKenneth D. Merry 		case DISK_ZONE_SAME_ALL_DIFFERENT:
2549a6844d5SKenneth D. Merry 			printf("Zone lengths and types may vary\n");
2559a6844d5SKenneth D. Merry 			break;
2569a6844d5SKenneth D. Merry 		case DISK_ZONE_SAME_ALL_SAME:
2579a6844d5SKenneth D. Merry 			printf("Zone lengths and types are all the same\n");
2589a6844d5SKenneth D. Merry 			break;
2599a6844d5SKenneth D. Merry 		case DISK_ZONE_SAME_LAST_DIFFERENT:
2609a6844d5SKenneth D. Merry 			printf("Zone types are the same, last zone length "
2619a6844d5SKenneth D. Merry 			    "differs\n");
2629a6844d5SKenneth D. Merry 			break;
2639a6844d5SKenneth D. Merry 		case DISK_ZONE_SAME_TYPES_DIFFERENT:
2649a6844d5SKenneth D. Merry 			printf("Zone lengths are the same, types vary\n");
2659a6844d5SKenneth D. Merry 			break;
2669a6844d5SKenneth D. Merry 		default:
2679a6844d5SKenneth D. Merry 			printf("Unknown SAME field value %#x\n",header->same);
2689a6844d5SKenneth D. Merry 			break;
2699a6844d5SKenneth D. Merry 		}
2709a6844d5SKenneth D. Merry 	}
2719a6844d5SKenneth D. Merry 	if (out_flags == ZONE_OF_SUMMARY) {
2729a6844d5SKenneth D. Merry 		status = ZONE_PRINT_OK;
2739a6844d5SKenneth D. Merry 		goto bailout;
2749a6844d5SKenneth D. Merry 	}
2759a6844d5SKenneth D. Merry 
2769a6844d5SKenneth D. Merry 	if ((out_flags == ZONE_OF_NORMAL)
2779a6844d5SKenneth D. Merry 	 && (first_pass != 0)) {
2789a6844d5SKenneth D. Merry 		printf("%*s  %*s  %*s  %*s  %*s  %*s  %*s\n",
2799a6844d5SKenneth D. Merry 		    field_widths[ZONE_FW_START], "Start LBA",
2809a6844d5SKenneth D. Merry 		    field_widths[ZONE_FW_LEN], "Length",
2819a6844d5SKenneth D. Merry 		    field_widths[ZONE_FW_WP], "WP LBA",
2829a6844d5SKenneth D. Merry 		    field_widths[ZONE_FW_TYPE], "Zone Type",
2839a6844d5SKenneth D. Merry 		    field_widths[ZONE_FW_COND], "Condition",
2849a6844d5SKenneth D. Merry 		    field_widths[ZONE_FW_SEQ], "Sequential",
2859a6844d5SKenneth D. Merry 		    field_widths[ZONE_FW_RESET], "Reset");
2869a6844d5SKenneth D. Merry 	}
2879a6844d5SKenneth D. Merry 
2889a6844d5SKenneth D. Merry 	for (i = 0; i < report->entries_filled; i++) {
2899a6844d5SKenneth D. Merry 		entry = &report->entries[i];
2909a6844d5SKenneth D. Merry 
2919a6844d5SKenneth D. Merry 		printf("%#*jx, %*ju, %#*jx, ", field_widths[ZONE_FW_START],
2929a6844d5SKenneth D. Merry 		    (uintmax_t)entry->zone_start_lba,
2939a6844d5SKenneth D. Merry 		    field_widths[ZONE_FW_LEN],
2949a6844d5SKenneth D. Merry 		    (uintmax_t)entry->zone_length, field_widths[ZONE_FW_WP],
2959a6844d5SKenneth D. Merry 		    (uintmax_t)entry->write_pointer_lba);
2969a6844d5SKenneth D. Merry 
2979a6844d5SKenneth D. Merry 		switch (entry->zone_type) {
2989a6844d5SKenneth D. Merry 		case DISK_ZONE_TYPE_CONVENTIONAL:
2999a6844d5SKenneth D. Merry 			snprintf(tmpstr, sizeof(tmpstr), "Conventional");
3009a6844d5SKenneth D. Merry 			break;
3019a6844d5SKenneth D. Merry 		case DISK_ZONE_TYPE_SEQ_PREFERRED:
3029a6844d5SKenneth D. Merry 		case DISK_ZONE_TYPE_SEQ_REQUIRED:
3039a6844d5SKenneth D. Merry 			snprintf(tmpstr, sizeof(tmpstr), "Seq%c%s",
3049a6844d5SKenneth D. Merry 			    word_sep, (entry->zone_type ==
3059a6844d5SKenneth D. Merry 			    DISK_ZONE_TYPE_SEQ_PREFERRED) ? "Preferred" :
3069a6844d5SKenneth D. Merry 			    "Required");
3079a6844d5SKenneth D. Merry 			break;
3089a6844d5SKenneth D. Merry 		default:
3099a6844d5SKenneth D. Merry 			snprintf(tmpstr, sizeof(tmpstr), "Zone%ctype%c%#x",
3109a6844d5SKenneth D. Merry 			    word_sep, word_sep, entry->zone_type);
3119a6844d5SKenneth D. Merry 			break;
3129a6844d5SKenneth D. Merry 		}
3139a6844d5SKenneth D. Merry 		printf("%*s, ", field_widths[ZONE_FW_TYPE], tmpstr);
3149a6844d5SKenneth D. Merry 
3159a6844d5SKenneth D. Merry 		switch (entry->zone_condition) {
3169a6844d5SKenneth D. Merry 		case DISK_ZONE_COND_NOT_WP:
3179a6844d5SKenneth D. Merry 			snprintf(tmpstr, sizeof(tmpstr), "NWP");
3189a6844d5SKenneth D. Merry 			break;
3199a6844d5SKenneth D. Merry 		case DISK_ZONE_COND_EMPTY:
3209a6844d5SKenneth D. Merry 			snprintf(tmpstr, sizeof(tmpstr), "Empty");
3219a6844d5SKenneth D. Merry 			break;
3229a6844d5SKenneth D. Merry 		case DISK_ZONE_COND_IMPLICIT_OPEN:
3239a6844d5SKenneth D. Merry 			snprintf(tmpstr, sizeof(tmpstr), "Implicit%cOpen",
3249a6844d5SKenneth D. Merry 			    word_sep);
3259a6844d5SKenneth D. Merry 			break;
3269a6844d5SKenneth D. Merry 		case DISK_ZONE_COND_EXPLICIT_OPEN:
3279a6844d5SKenneth D. Merry 			snprintf(tmpstr, sizeof(tmpstr), "Explicit%cOpen",
3289a6844d5SKenneth D. Merry 			    word_sep);
3299a6844d5SKenneth D. Merry 			break;
3309a6844d5SKenneth D. Merry 		case DISK_ZONE_COND_CLOSED:
3319a6844d5SKenneth D. Merry 			snprintf(tmpstr, sizeof(tmpstr), "Closed");
3329a6844d5SKenneth D. Merry 			break;
3339a6844d5SKenneth D. Merry 		case DISK_ZONE_COND_READONLY:
3349a6844d5SKenneth D. Merry 			snprintf(tmpstr, sizeof(tmpstr), "Readonly");
3359a6844d5SKenneth D. Merry 			break;
3369a6844d5SKenneth D. Merry 		case DISK_ZONE_COND_FULL:
3379a6844d5SKenneth D. Merry 			snprintf(tmpstr, sizeof(tmpstr), "Full");
3389a6844d5SKenneth D. Merry 			break;
3399a6844d5SKenneth D. Merry 		case DISK_ZONE_COND_OFFLINE:
3409a6844d5SKenneth D. Merry 			snprintf(tmpstr, sizeof(tmpstr), "Offline");
3419a6844d5SKenneth D. Merry 			break;
3429a6844d5SKenneth D. Merry 		default:
3439a6844d5SKenneth D. Merry 			snprintf(tmpstr, sizeof(tmpstr), "%#x",
3449a6844d5SKenneth D. Merry 			    entry->zone_condition);
3459a6844d5SKenneth D. Merry 			break;
3469a6844d5SKenneth D. Merry 		}
3479a6844d5SKenneth D. Merry 
3489a6844d5SKenneth D. Merry 		printf("%*s, ", field_widths[ZONE_FW_COND], tmpstr);
3499a6844d5SKenneth D. Merry 
3509a6844d5SKenneth D. Merry 		if (entry->zone_flags & DISK_ZONE_FLAG_NON_SEQ)
3519a6844d5SKenneth D. Merry 			snprintf(tmpstr, sizeof(tmpstr), "Non%cSequential",
3529a6844d5SKenneth D. Merry 			    word_sep);
3539a6844d5SKenneth D. Merry 		else
3549a6844d5SKenneth D. Merry 			snprintf(tmpstr, sizeof(tmpstr), "Sequential");
3559a6844d5SKenneth D. Merry 
3569a6844d5SKenneth D. Merry 		printf("%*s, ", field_widths[ZONE_FW_SEQ], tmpstr);
3579a6844d5SKenneth D. Merry 
3589a6844d5SKenneth D. Merry 		if (entry->zone_flags & DISK_ZONE_FLAG_RESET)
3599a6844d5SKenneth D. Merry 			snprintf(tmpstr, sizeof(tmpstr), "Reset%cNeeded",
3609a6844d5SKenneth D. Merry 			    word_sep);
3619a6844d5SKenneth D. Merry 		else
3629a6844d5SKenneth D. Merry 			snprintf(tmpstr, sizeof(tmpstr), "No%cReset%cNeeded",
3639a6844d5SKenneth D. Merry 			    word_sep, word_sep);
3649a6844d5SKenneth D. Merry 
3659a6844d5SKenneth D. Merry 		printf("%*s\n", field_widths[ZONE_FW_RESET], tmpstr);
3669a6844d5SKenneth D. Merry 
3679a6844d5SKenneth D. Merry 		next_lba = entry->zone_start_lba + entry->zone_length;
3689a6844d5SKenneth D. Merry 	}
3699a6844d5SKenneth D. Merry bailout:
3709a6844d5SKenneth D. Merry 	report->starting_id = next_lba;
3719a6844d5SKenneth D. Merry 
3729a6844d5SKenneth D. Merry 	return (status);
3739a6844d5SKenneth D. Merry }
3749a6844d5SKenneth D. Merry 
3759a6844d5SKenneth D. Merry int
main(int argc,char ** argv)3769a6844d5SKenneth D. Merry main(int argc, char **argv)
3779a6844d5SKenneth D. Merry {
3789a6844d5SKenneth D. Merry 	int c;
3799a6844d5SKenneth D. Merry 	int all_zones = 0;
3809a6844d5SKenneth D. Merry 	int error = 0;
3819a6844d5SKenneth D. Merry 	int action = -1, rep_option = -1;
3829a6844d5SKenneth D. Merry 	int fd = -1;
3839a6844d5SKenneth D. Merry 	uint64_t lba = 0;
3849a6844d5SKenneth D. Merry 	zone_output_flags out_flags = ZONE_OF_NORMAL;
3859a6844d5SKenneth D. Merry 	char *filename = NULL;
3869a6844d5SKenneth D. Merry 	struct disk_zone_args zone_args;
3879a6844d5SKenneth D. Merry 	struct disk_zone_rep_entry *entries = NULL;
3889a6844d5SKenneth D. Merry 	uint32_t num_entries = 16384;
3899a6844d5SKenneth D. Merry 	zone_print_status zp_status;
3909a6844d5SKenneth D. Merry 	int first_pass = 1;
3919a6844d5SKenneth D. Merry 	size_t entry_alloc_size;
3929a6844d5SKenneth D. Merry 	int open_flags = O_RDONLY;
3939a6844d5SKenneth D. Merry 
3949a6844d5SKenneth D. Merry 	while ((c = getopt(argc, argv, "ac:d:hl:o:P:?")) != -1) {
3959a6844d5SKenneth D. Merry 		switch (c) {
3969a6844d5SKenneth D. Merry 		case 'a':
3979a6844d5SKenneth D. Merry 			all_zones = 1;
3989a6844d5SKenneth D. Merry 			break;
3999a6844d5SKenneth D. Merry 		case 'c': {
4009a6844d5SKenneth D. Merry 			scsi_nv_status status;
4019a6844d5SKenneth D. Merry 			int entry_num;
4029a6844d5SKenneth D. Merry 
4039a6844d5SKenneth D. Merry 			status = scsi_get_nv(zone_cmd_map,
404*b561d8f5SElyes Haouas 			    nitems(zone_cmd_map),
4059a6844d5SKenneth D. Merry 			    optarg, &entry_num, SCSI_NV_FLAG_IG_CASE);
4069a6844d5SKenneth D. Merry 			if (status == SCSI_NV_FOUND)
4079a6844d5SKenneth D. Merry 				action = zone_cmd_map[entry_num].value;
4089a6844d5SKenneth D. Merry 			else {
4099a6844d5SKenneth D. Merry 				warnx("%s: %s: %s option %s", __func__,
4109a6844d5SKenneth D. Merry 				    (status == SCSI_NV_AMBIGUOUS) ?
4119a6844d5SKenneth D. Merry 				    "ambiguous" : "invalid", "zone command",
4129a6844d5SKenneth D. Merry 				    optarg);
4139a6844d5SKenneth D. Merry 				error = 1;
4149a6844d5SKenneth D. Merry 				goto bailout;
4159a6844d5SKenneth D. Merry 			}
4169a6844d5SKenneth D. Merry 			break;
4179a6844d5SKenneth D. Merry 		}
4189a6844d5SKenneth D. Merry 		case 'd':
4199a6844d5SKenneth D. Merry 			filename = strdup(optarg);
4209a6844d5SKenneth D. Merry 			if (filename == NULL)
4219a6844d5SKenneth D. Merry 				err(1, "Unable to allocate memory for "
4229a6844d5SKenneth D. Merry 				    "filename");
4239a6844d5SKenneth D. Merry 			break;
4249a6844d5SKenneth D. Merry 		case 'l': {
4259a6844d5SKenneth D. Merry 			char *endptr;
4269a6844d5SKenneth D. Merry 
4279a6844d5SKenneth D. Merry 			lba = strtoull(optarg, &endptr, 0);
4289a6844d5SKenneth D. Merry 			if (*endptr != '\0') {
4299a6844d5SKenneth D. Merry 				warnx("%s: invalid lba argument %s", __func__,
4309a6844d5SKenneth D. Merry 				    optarg);
4319a6844d5SKenneth D. Merry 				error = 1;
4329a6844d5SKenneth D. Merry 				goto bailout;
4339a6844d5SKenneth D. Merry 			}
4349a6844d5SKenneth D. Merry 			break;
4359a6844d5SKenneth D. Merry 		}
4369a6844d5SKenneth D. Merry 		case 'o': {
4379a6844d5SKenneth D. Merry 			scsi_nv_status status;
4389a6844d5SKenneth D. Merry 			int entry_num;
4399a6844d5SKenneth D. Merry 
4409a6844d5SKenneth D. Merry 			status = scsi_get_nv(zone_rep_opts,
4419a6844d5SKenneth D. Merry 			    (sizeof(zone_rep_opts) /
4429a6844d5SKenneth D. Merry 			    sizeof(zone_rep_opts[0])),
4439a6844d5SKenneth D. Merry 			    optarg, &entry_num, SCSI_NV_FLAG_IG_CASE);
4449a6844d5SKenneth D. Merry 			if (status == SCSI_NV_FOUND)
4459a6844d5SKenneth D. Merry 				rep_option = zone_rep_opts[entry_num].value;
4469a6844d5SKenneth D. Merry 			else {
4479a6844d5SKenneth D. Merry 				warnx("%s: %s: %s option %s", __func__,
4489a6844d5SKenneth D. Merry 				    (status == SCSI_NV_AMBIGUOUS) ?
4499a6844d5SKenneth D. Merry 				    "ambiguous" : "invalid", "report zones",
4509a6844d5SKenneth D. Merry 				    optarg);
4519a6844d5SKenneth D. Merry 				error = 1;
4529a6844d5SKenneth D. Merry 				goto bailout;
4539a6844d5SKenneth D. Merry 			}
4549a6844d5SKenneth D. Merry 			break;
4559a6844d5SKenneth D. Merry 		}
4569a6844d5SKenneth D. Merry 		case 'P': {
4579a6844d5SKenneth D. Merry 			scsi_nv_status status;
4589a6844d5SKenneth D. Merry 			int entry_num;
4599a6844d5SKenneth D. Merry 
4609a6844d5SKenneth D. Merry 			status = scsi_get_nv(zone_print_opts,
4619a6844d5SKenneth D. Merry 			    (sizeof(zone_print_opts) /
4629a6844d5SKenneth D. Merry 			    sizeof(zone_print_opts[0])), optarg, &entry_num,
4639a6844d5SKenneth D. Merry 			    SCSI_NV_FLAG_IG_CASE);
4649a6844d5SKenneth D. Merry 			if (status == SCSI_NV_FOUND)
4659a6844d5SKenneth D. Merry 				out_flags = zone_print_opts[entry_num].value;
4669a6844d5SKenneth D. Merry 			else {
4679a6844d5SKenneth D. Merry 				warnx("%s: %s: %s option %s", __func__,
4689a6844d5SKenneth D. Merry 				    (status == SCSI_NV_AMBIGUOUS) ?
4699a6844d5SKenneth D. Merry 				    "ambiguous" : "invalid", "print",
4709a6844d5SKenneth D. Merry 				    optarg);
4719a6844d5SKenneth D. Merry 				error = 1;
4729a6844d5SKenneth D. Merry 				goto bailout;
4739a6844d5SKenneth D. Merry 			}
4749a6844d5SKenneth D. Merry 			break;
4759a6844d5SKenneth D. Merry 		}
4769a6844d5SKenneth D. Merry 		default:
4779a6844d5SKenneth D. Merry 			error = 1;
4789a6844d5SKenneth D. Merry 		case 'h': /*FALLTHROUGH*/
4799a6844d5SKenneth D. Merry 			usage(error);
4809a6844d5SKenneth D. Merry 			goto bailout;
4819a6844d5SKenneth D. Merry 			break; /*NOTREACHED*/
4829a6844d5SKenneth D. Merry 		}
4839a6844d5SKenneth D. Merry 	}
4849a6844d5SKenneth D. Merry 
4859a6844d5SKenneth D. Merry 	if (filename == NULL) {
4869a6844d5SKenneth D. Merry 		warnx("You must specify a device with -d");
4879a6844d5SKenneth D. Merry 		error = 1;
4889a6844d5SKenneth D. Merry 	}
4899a6844d5SKenneth D. Merry 	if (action == -1) {
4909a6844d5SKenneth D. Merry 		warnx("You must specify an action with -c");
4919a6844d5SKenneth D. Merry 		error = 1;
4929a6844d5SKenneth D. Merry 	}
4939a6844d5SKenneth D. Merry 
4949a6844d5SKenneth D. Merry 	if (error != 0) {
4959a6844d5SKenneth D. Merry 		usage(error);
4969a6844d5SKenneth D. Merry 		goto bailout;
4979a6844d5SKenneth D. Merry 	}
4989a6844d5SKenneth D. Merry 
4999a6844d5SKenneth D. Merry 	bzero(&zone_args, sizeof(zone_args));
5009a6844d5SKenneth D. Merry 
5019a6844d5SKenneth D. Merry 	zone_args.zone_cmd = action;
5029a6844d5SKenneth D. Merry 
5039a6844d5SKenneth D. Merry 	switch (action) {
5049a6844d5SKenneth D. Merry 	case DISK_ZONE_OPEN:
5059a6844d5SKenneth D. Merry 	case DISK_ZONE_CLOSE:
5069a6844d5SKenneth D. Merry 	case DISK_ZONE_FINISH:
5079a6844d5SKenneth D. Merry 	case DISK_ZONE_RWP:
5089a6844d5SKenneth D. Merry 		open_flags = O_RDWR;
5099a6844d5SKenneth D. Merry 		zone_args.zone_params.rwp.id = lba;
5109a6844d5SKenneth D. Merry 		if (all_zones != 0)
5119a6844d5SKenneth D. Merry 			zone_args.zone_params.rwp.flags |=
5129a6844d5SKenneth D. Merry 			    DISK_ZONE_RWP_FLAG_ALL;
5139a6844d5SKenneth D. Merry 		break;
5149a6844d5SKenneth D. Merry 	case DISK_ZONE_REPORT_ZONES: {
5159a6844d5SKenneth D. Merry 		entry_alloc_size = num_entries *
5169a6844d5SKenneth D. Merry 		    sizeof(struct disk_zone_rep_entry);
5179a6844d5SKenneth D. Merry 		entries = malloc(entry_alloc_size);
5189a6844d5SKenneth D. Merry 		if (entries == NULL) {
5199a6844d5SKenneth D. Merry 			warn("Could not allocate %zu bytes",
5209a6844d5SKenneth D. Merry 			    entry_alloc_size);
5219a6844d5SKenneth D. Merry 			error = 1;
5229a6844d5SKenneth D. Merry 			goto bailout;
5239a6844d5SKenneth D. Merry 		}
5249a6844d5SKenneth D. Merry 		zone_args.zone_params.report.entries_allocated = num_entries;
5259a6844d5SKenneth D. Merry 		zone_args.zone_params.report.entries = entries;
5269a6844d5SKenneth D. Merry 		zone_args.zone_params.report.starting_id = lba;
5279a6844d5SKenneth D. Merry 		if (rep_option != -1)
5289a6844d5SKenneth D. Merry 			zone_args.zone_params.report.rep_options = rep_option;
5299a6844d5SKenneth D. Merry 		break;
5309a6844d5SKenneth D. Merry 	}
5319a6844d5SKenneth D. Merry 	case DISK_ZONE_GET_PARAMS:
5329a6844d5SKenneth D. Merry 		break;
5339a6844d5SKenneth D. Merry 	default:
5349a6844d5SKenneth D. Merry 		warnx("Unknown action %d", action);
5359a6844d5SKenneth D. Merry 		error = 1;
5369a6844d5SKenneth D. Merry 		goto bailout;
5379a6844d5SKenneth D. Merry 		break; /*NOTREACHED*/
5389a6844d5SKenneth D. Merry 	}
5399a6844d5SKenneth D. Merry 
5409a6844d5SKenneth D. Merry 	fd = open(filename, open_flags);
5419a6844d5SKenneth D. Merry 	if (fd == -1) {
5429a6844d5SKenneth D. Merry 		warn("Unable to open device %s", filename);
5439a6844d5SKenneth D. Merry 		error = 1;
5449a6844d5SKenneth D. Merry 		goto bailout;
5459a6844d5SKenneth D. Merry 	}
5469a6844d5SKenneth D. Merry next_chunk:
5479a6844d5SKenneth D. Merry 	error = ioctl(fd, DIOCZONECMD, &zone_args);
5489a6844d5SKenneth D. Merry 	if (error == -1) {
5499a6844d5SKenneth D. Merry 		warn("DIOCZONECMD ioctl failed");
5509a6844d5SKenneth D. Merry 		error = 1;
5519a6844d5SKenneth D. Merry 		goto bailout;
5529a6844d5SKenneth D. Merry 	}
5539a6844d5SKenneth D. Merry 
5549a6844d5SKenneth D. Merry 	switch (action) {
5559a6844d5SKenneth D. Merry 	case DISK_ZONE_OPEN:
5569a6844d5SKenneth D. Merry 	case DISK_ZONE_CLOSE:
5579a6844d5SKenneth D. Merry 	case DISK_ZONE_FINISH:
5589a6844d5SKenneth D. Merry 	case DISK_ZONE_RWP:
5599a6844d5SKenneth D. Merry 		break;
5609a6844d5SKenneth D. Merry 	case DISK_ZONE_REPORT_ZONES:
5619a6844d5SKenneth D. Merry 		zp_status = zonectl_print_rz(&zone_args.zone_params.report,
5629a6844d5SKenneth D. Merry 		    out_flags, first_pass);
5639a6844d5SKenneth D. Merry 		if (zp_status == ZONE_PRINT_MORE_DATA) {
5649a6844d5SKenneth D. Merry 			first_pass = 0;
5659a6844d5SKenneth D. Merry 			bzero(entries, entry_alloc_size);
5669a6844d5SKenneth D. Merry 			zone_args.zone_params.report.entries_filled = 0;
5679a6844d5SKenneth D. Merry 			goto next_chunk;
5689a6844d5SKenneth D. Merry 		} else if (zp_status == ZONE_PRINT_ERROR)
5699a6844d5SKenneth D. Merry 			error = 1;
5709a6844d5SKenneth D. Merry 		break;
5719a6844d5SKenneth D. Merry 	case DISK_ZONE_GET_PARAMS:
5729a6844d5SKenneth D. Merry 		zonectl_print_params(&zone_args.zone_params.disk_params);
5739a6844d5SKenneth D. Merry 		break;
5749a6844d5SKenneth D. Merry 	default:
5759a6844d5SKenneth D. Merry 		warnx("Unknown action %d", action);
5769a6844d5SKenneth D. Merry 		error = 1;
5779a6844d5SKenneth D. Merry 		goto bailout;
5789a6844d5SKenneth D. Merry 		break; /*NOTREACHED*/
5799a6844d5SKenneth D. Merry 	}
5809a6844d5SKenneth D. Merry bailout:
5819a6844d5SKenneth D. Merry 	free(entries);
5829a6844d5SKenneth D. Merry 
5839a6844d5SKenneth D. Merry 	if (fd != -1)
5849a6844d5SKenneth D. Merry 		close(fd);
5859a6844d5SKenneth D. Merry 	exit (error);
5869a6844d5SKenneth D. Merry }
587