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