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 * SCSI and ATA Shingled Media Recording (SMR) support for camcontrol(8).
349a6844d5SKenneth D. Merry * This is an implementation of the SCSI ZBC and ATA ZAC specs.
359a6844d5SKenneth D. Merry */
369a6844d5SKenneth D. Merry
37*7028e630SElyes Haouas #include <sys/param.h>
389a6844d5SKenneth D. Merry #include <sys/ioctl.h>
399a6844d5SKenneth D. Merry #include <sys/stdint.h>
409a6844d5SKenneth D. Merry #include <sys/endian.h>
419a6844d5SKenneth D. Merry #include <sys/sbuf.h>
429a6844d5SKenneth D. Merry #include <sys/queue.h>
439a6844d5SKenneth D. Merry #include <sys/chio.h>
449a6844d5SKenneth D. Merry
459a6844d5SKenneth D. Merry #include <stdio.h>
469a6844d5SKenneth D. Merry #include <stdlib.h>
479a6844d5SKenneth D. Merry #include <inttypes.h>
489a6844d5SKenneth D. Merry #include <unistd.h>
499a6844d5SKenneth D. Merry #include <string.h>
509a6844d5SKenneth D. Merry #include <strings.h>
519a6844d5SKenneth D. Merry #include <fcntl.h>
529a6844d5SKenneth D. Merry #include <ctype.h>
539a6844d5SKenneth D. Merry #include <limits.h>
549a6844d5SKenneth D. Merry #include <err.h>
559a6844d5SKenneth D. Merry #include <locale.h>
569a6844d5SKenneth D. Merry
579a6844d5SKenneth D. Merry #include <cam/cam.h>
589a6844d5SKenneth D. Merry #include <cam/cam_debug.h>
599a6844d5SKenneth D. Merry #include <cam/cam_ccb.h>
609a6844d5SKenneth D. Merry #include <cam/scsi/scsi_all.h>
619a6844d5SKenneth D. Merry #include <cam/scsi/scsi_da.h>
629a6844d5SKenneth D. Merry #include <cam/scsi/scsi_pass.h>
639a6844d5SKenneth D. Merry #include <cam/scsi/scsi_ch.h>
649a6844d5SKenneth D. Merry #include <cam/scsi/scsi_message.h>
659a6844d5SKenneth D. Merry #include <camlib.h>
669a6844d5SKenneth D. Merry #include "camcontrol.h"
679a6844d5SKenneth D. Merry
689a6844d5SKenneth D. Merry static struct scsi_nv zone_cmd_map[] = {
699a6844d5SKenneth D. Merry { "rz", ZBC_IN_SA_REPORT_ZONES },
709a6844d5SKenneth D. Merry { "reportzones", ZBC_IN_SA_REPORT_ZONES },
719a6844d5SKenneth D. Merry { "close", ZBC_OUT_SA_CLOSE },
729a6844d5SKenneth D. Merry { "finish", ZBC_OUT_SA_FINISH },
739a6844d5SKenneth D. Merry { "open", ZBC_OUT_SA_OPEN },
749a6844d5SKenneth D. Merry { "rwp", ZBC_OUT_SA_RWP }
759a6844d5SKenneth D. Merry };
769a6844d5SKenneth D. Merry
779a6844d5SKenneth D. Merry static struct scsi_nv zone_rep_opts[] = {
789a6844d5SKenneth D. Merry { "all", ZBC_IN_REP_ALL_ZONES },
799a6844d5SKenneth D. Merry { "empty", ZBC_IN_REP_EMPTY },
809a6844d5SKenneth D. Merry { "imp_open", ZBC_IN_REP_IMP_OPEN },
819a6844d5SKenneth D. Merry { "exp_open", ZBC_IN_REP_EXP_OPEN },
829a6844d5SKenneth D. Merry { "closed", ZBC_IN_REP_CLOSED },
839a6844d5SKenneth D. Merry { "full", ZBC_IN_REP_FULL },
849a6844d5SKenneth D. Merry { "readonly", ZBC_IN_REP_READONLY },
859a6844d5SKenneth D. Merry { "ro", ZBC_IN_REP_READONLY },
869a6844d5SKenneth D. Merry { "offline", ZBC_IN_REP_OFFLINE },
879a6844d5SKenneth D. Merry { "rwp", ZBC_IN_REP_RESET },
889a6844d5SKenneth D. Merry { "reset", ZBC_IN_REP_RESET },
899a6844d5SKenneth D. Merry { "nonseq", ZBC_IN_REP_NON_SEQ },
909a6844d5SKenneth D. Merry { "nonwp", ZBC_IN_REP_NON_WP }
919a6844d5SKenneth D. Merry };
929a6844d5SKenneth D. Merry
939a6844d5SKenneth D. Merry typedef enum {
949a6844d5SKenneth D. Merry ZONE_OF_NORMAL = 0x00,
959a6844d5SKenneth D. Merry ZONE_OF_SUMMARY = 0x01,
969a6844d5SKenneth D. Merry ZONE_OF_SCRIPT = 0x02
979a6844d5SKenneth D. Merry } zone_output_flags;
989a6844d5SKenneth D. Merry
999a6844d5SKenneth D. Merry static struct scsi_nv zone_print_opts[] = {
1009a6844d5SKenneth D. Merry { "normal", ZONE_OF_NORMAL },
1019a6844d5SKenneth D. Merry { "summary", ZONE_OF_SUMMARY },
1029a6844d5SKenneth D. Merry { "script", ZONE_OF_SCRIPT }
1039a6844d5SKenneth D. Merry };
1049a6844d5SKenneth D. Merry
1059a6844d5SKenneth D. Merry #define ZAC_ATA_SECTOR_COUNT(bcount) (((bcount) / 512) & 0xffff)
1069a6844d5SKenneth D. Merry
1079a6844d5SKenneth D. Merry typedef enum {
1089a6844d5SKenneth D. Merry ZONE_PRINT_OK,
1099a6844d5SKenneth D. Merry ZONE_PRINT_MORE_DATA,
1109a6844d5SKenneth D. Merry ZONE_PRINT_ERROR
1119a6844d5SKenneth D. Merry } zone_print_status;
1129a6844d5SKenneth D. Merry
1139a6844d5SKenneth D. Merry typedef enum {
1149a6844d5SKenneth D. Merry ZONE_FW_START,
1159a6844d5SKenneth D. Merry ZONE_FW_LEN,
1169a6844d5SKenneth D. Merry ZONE_FW_WP,
1179a6844d5SKenneth D. Merry ZONE_FW_TYPE,
1189a6844d5SKenneth D. Merry ZONE_FW_COND,
1199a6844d5SKenneth D. Merry ZONE_FW_SEQ,
1209a6844d5SKenneth D. Merry ZONE_FW_RESET,
1219a6844d5SKenneth D. Merry ZONE_NUM_FIELDS
1229a6844d5SKenneth D. Merry } zone_field_widths;
1239a6844d5SKenneth D. Merry
1249a6844d5SKenneth D. Merry zone_print_status zone_rz_print(uint8_t *data_ptr, uint32_t valid_len,
1259a6844d5SKenneth D. Merry int ata_format, zone_output_flags out_flags,
1269a6844d5SKenneth D. Merry int first_pass, uint64_t *next_start_lba);
1279a6844d5SKenneth D. Merry
1289a6844d5SKenneth D. Merry
1299a6844d5SKenneth D. Merry zone_print_status
zone_rz_print(uint8_t * data_ptr,uint32_t valid_len,int ata_format,zone_output_flags out_flags,int first_pass,uint64_t * next_start_lba)1309a6844d5SKenneth D. Merry zone_rz_print(uint8_t *data_ptr, uint32_t valid_len, int ata_format,
1319a6844d5SKenneth D. Merry zone_output_flags out_flags, int first_pass,
1329a6844d5SKenneth D. Merry uint64_t *next_start_lba)
1339a6844d5SKenneth D. Merry {
1349a6844d5SKenneth D. Merry struct scsi_report_zones_hdr *hdr = NULL;
1359a6844d5SKenneth D. Merry struct scsi_report_zones_desc *desc = NULL;
1369a6844d5SKenneth D. Merry uint32_t hdr_len, len;
1379a6844d5SKenneth D. Merry uint64_t max_lba, next_lba = 0;
1389a6844d5SKenneth D. Merry zone_print_status status = ZONE_PRINT_OK;
1399a6844d5SKenneth D. Merry char tmpstr[80];
1409a6844d5SKenneth D. Merry int field_widths[ZONE_NUM_FIELDS];
1419a6844d5SKenneth D. Merry char word_sep;
1429a6844d5SKenneth D. Merry
1439a6844d5SKenneth D. Merry if (valid_len < sizeof(*hdr)) {
1449a6844d5SKenneth D. Merry status = ZONE_PRINT_ERROR;
1459a6844d5SKenneth D. Merry goto bailout;
1469a6844d5SKenneth D. Merry }
1479a6844d5SKenneth D. Merry
1489a6844d5SKenneth D. Merry hdr = (struct scsi_report_zones_hdr *)data_ptr;
1499a6844d5SKenneth D. Merry
1509a6844d5SKenneth D. Merry field_widths[ZONE_FW_START] = 11;
1519a6844d5SKenneth D. Merry field_widths[ZONE_FW_LEN] = 6;
1529a6844d5SKenneth D. Merry field_widths[ZONE_FW_WP] = 11;
1539a6844d5SKenneth D. Merry field_widths[ZONE_FW_TYPE] = 13;
1549a6844d5SKenneth D. Merry field_widths[ZONE_FW_COND] = 13;
1559a6844d5SKenneth D. Merry field_widths[ZONE_FW_SEQ] = 14;
1569a6844d5SKenneth D. Merry field_widths[ZONE_FW_RESET] = 16;
1579a6844d5SKenneth D. Merry
1589a6844d5SKenneth D. Merry if (ata_format == 0) {
1599a6844d5SKenneth D. Merry hdr_len = scsi_4btoul(hdr->length);
1609a6844d5SKenneth D. Merry max_lba = scsi_8btou64(hdr->maximum_lba);
1619a6844d5SKenneth D. Merry } else {
1629a6844d5SKenneth D. Merry hdr_len = le32dec(hdr->length);
1639a6844d5SKenneth D. Merry max_lba = le64dec(hdr->maximum_lba);
1649a6844d5SKenneth D. Merry }
1659a6844d5SKenneth D. Merry
1669a6844d5SKenneth D. Merry if (hdr_len > (valid_len + sizeof(*hdr))) {
1679a6844d5SKenneth D. Merry status = ZONE_PRINT_MORE_DATA;
1689a6844d5SKenneth D. Merry }
1699a6844d5SKenneth D. Merry
1709a6844d5SKenneth D. Merry len = MIN(valid_len - sizeof(*hdr), hdr_len);
1719a6844d5SKenneth D. Merry
1729a6844d5SKenneth D. Merry if (out_flags == ZONE_OF_SCRIPT)
1739a6844d5SKenneth D. Merry word_sep = '_';
1749a6844d5SKenneth D. Merry else
1759a6844d5SKenneth D. Merry word_sep = ' ';
1769a6844d5SKenneth D. Merry
1779a6844d5SKenneth D. Merry if ((out_flags != ZONE_OF_SCRIPT)
1789a6844d5SKenneth D. Merry && (first_pass != 0)) {
1799a6844d5SKenneth D. Merry printf("%zu zones, Maximum LBA %#jx (%ju)\n",
1809a6844d5SKenneth D. Merry hdr_len / sizeof(*desc), (uintmax_t)max_lba,
1819a6844d5SKenneth D. Merry (uintmax_t)max_lba);
1829a6844d5SKenneth D. Merry
1839a6844d5SKenneth D. Merry switch (hdr->byte4 & SRZ_SAME_MASK) {
1849a6844d5SKenneth D. Merry case SRZ_SAME_ALL_DIFFERENT:
1859a6844d5SKenneth D. Merry printf("Zone lengths and types may vary\n");
1869a6844d5SKenneth D. Merry break;
1879a6844d5SKenneth D. Merry case SRZ_SAME_ALL_SAME:
1889a6844d5SKenneth D. Merry printf("Zone lengths and types are all the same\n");
1899a6844d5SKenneth D. Merry break;
1909a6844d5SKenneth D. Merry case SRZ_SAME_LAST_DIFFERENT:
1919a6844d5SKenneth D. Merry printf("Zone types are the same, last zone length "
1929a6844d5SKenneth D. Merry "differs\n");
1939a6844d5SKenneth D. Merry break;
1949a6844d5SKenneth D. Merry case SRZ_SAME_TYPES_DIFFERENT:
1959a6844d5SKenneth D. Merry printf("Zone lengths are the same, types vary\n");
1969a6844d5SKenneth D. Merry break;
1979a6844d5SKenneth D. Merry default:
1989a6844d5SKenneth D. Merry printf("Unknown SAME field value %#x\n",
1999a6844d5SKenneth D. Merry hdr->byte4 & SRZ_SAME_MASK);
2009a6844d5SKenneth D. Merry break;
2019a6844d5SKenneth D. Merry }
2029a6844d5SKenneth D. Merry }
2039a6844d5SKenneth D. Merry if (out_flags == ZONE_OF_SUMMARY) {
2049a6844d5SKenneth D. Merry status = ZONE_PRINT_OK;
2059a6844d5SKenneth D. Merry goto bailout;
2069a6844d5SKenneth D. Merry }
2079a6844d5SKenneth D. Merry
2089a6844d5SKenneth D. Merry if ((out_flags == ZONE_OF_NORMAL)
2099a6844d5SKenneth D. Merry && (first_pass != 0)) {
2109a6844d5SKenneth D. Merry printf("%*s %*s %*s %*s %*s %*s %*s\n",
2119a6844d5SKenneth D. Merry field_widths[ZONE_FW_START], "Start LBA",
2129a6844d5SKenneth D. Merry field_widths[ZONE_FW_LEN], "Length",
2139a6844d5SKenneth D. Merry field_widths[ZONE_FW_WP], "WP LBA",
2149a6844d5SKenneth D. Merry field_widths[ZONE_FW_TYPE], "Zone Type",
2159a6844d5SKenneth D. Merry field_widths[ZONE_FW_COND], "Condition",
2169a6844d5SKenneth D. Merry field_widths[ZONE_FW_SEQ], "Sequential",
2179a6844d5SKenneth D. Merry field_widths[ZONE_FW_RESET], "Reset");
2189a6844d5SKenneth D. Merry }
2199a6844d5SKenneth D. Merry
2209a6844d5SKenneth D. Merry for (desc = &hdr->desc_list[0]; len >= sizeof(*desc);
2219a6844d5SKenneth D. Merry len -= sizeof(*desc), desc++) {
2229a6844d5SKenneth D. Merry uint64_t length, start_lba, wp_lba;
2239a6844d5SKenneth D. Merry
2249a6844d5SKenneth D. Merry if (ata_format == 0) {
2259a6844d5SKenneth D. Merry length = scsi_8btou64(desc->zone_length);
2269a6844d5SKenneth D. Merry start_lba = scsi_8btou64(desc->zone_start_lba);
2279a6844d5SKenneth D. Merry wp_lba = scsi_8btou64(desc->write_pointer_lba);
2289a6844d5SKenneth D. Merry } else {
2299a6844d5SKenneth D. Merry length = le64dec(desc->zone_length);
2309a6844d5SKenneth D. Merry start_lba = le64dec(desc->zone_start_lba);
2319a6844d5SKenneth D. Merry wp_lba = le64dec(desc->write_pointer_lba);
2329a6844d5SKenneth D. Merry }
2339a6844d5SKenneth D. Merry
2349a6844d5SKenneth D. Merry printf("%#*jx, %*ju, %#*jx, ", field_widths[ZONE_FW_START],
2359a6844d5SKenneth D. Merry (uintmax_t)start_lba, field_widths[ZONE_FW_LEN],
2369a6844d5SKenneth D. Merry (uintmax_t)length, field_widths[ZONE_FW_WP],
2379a6844d5SKenneth D. Merry (uintmax_t)wp_lba);
2389a6844d5SKenneth D. Merry
2399a6844d5SKenneth D. Merry switch (desc->zone_type & SRZ_TYPE_MASK) {
2409a6844d5SKenneth D. Merry case SRZ_TYPE_CONVENTIONAL:
2419a6844d5SKenneth D. Merry snprintf(tmpstr, sizeof(tmpstr), "Conventional");
2429a6844d5SKenneth D. Merry break;
2439a6844d5SKenneth D. Merry case SRZ_TYPE_SEQ_PREFERRED:
2449a6844d5SKenneth D. Merry case SRZ_TYPE_SEQ_REQUIRED:
2459a6844d5SKenneth D. Merry snprintf(tmpstr, sizeof(tmpstr), "Seq%c%s",
2469a6844d5SKenneth D. Merry word_sep, ((desc->zone_type & SRZ_TYPE_MASK) ==
2479a6844d5SKenneth D. Merry SRZ_TYPE_SEQ_PREFERRED) ? "Preferred" :
2489a6844d5SKenneth D. Merry "Required");
2499a6844d5SKenneth D. Merry break;
2509a6844d5SKenneth D. Merry default:
2519a6844d5SKenneth D. Merry snprintf(tmpstr, sizeof(tmpstr), "Zone%ctype%c%#x",
2529a6844d5SKenneth D. Merry word_sep, word_sep,desc->zone_type &
2539a6844d5SKenneth D. Merry SRZ_TYPE_MASK);
2549a6844d5SKenneth D. Merry break;
2559a6844d5SKenneth D. Merry }
2569a6844d5SKenneth D. Merry printf("%*s, ", field_widths[ZONE_FW_TYPE], tmpstr);
2579a6844d5SKenneth D. Merry
2589a6844d5SKenneth D. Merry switch (desc->zone_flags & SRZ_ZONE_COND_MASK) {
2599a6844d5SKenneth D. Merry case SRZ_ZONE_COND_NWP:
2609a6844d5SKenneth D. Merry snprintf(tmpstr, sizeof(tmpstr), "NWP");
2619a6844d5SKenneth D. Merry break;
2629a6844d5SKenneth D. Merry case SRZ_ZONE_COND_EMPTY:
2639a6844d5SKenneth D. Merry snprintf(tmpstr, sizeof(tmpstr), "Empty");
2649a6844d5SKenneth D. Merry break;
2659a6844d5SKenneth D. Merry case SRZ_ZONE_COND_IMP_OPEN:
2669a6844d5SKenneth D. Merry snprintf(tmpstr, sizeof(tmpstr), "Implicit%cOpen",
2679a6844d5SKenneth D. Merry word_sep);
2689a6844d5SKenneth D. Merry break;
2699a6844d5SKenneth D. Merry case SRZ_ZONE_COND_EXP_OPEN:
2709a6844d5SKenneth D. Merry snprintf(tmpstr, sizeof(tmpstr), "Explicit%cOpen",
2719a6844d5SKenneth D. Merry word_sep);
2729a6844d5SKenneth D. Merry break;
2739a6844d5SKenneth D. Merry case SRZ_ZONE_COND_CLOSED:
2749a6844d5SKenneth D. Merry snprintf(tmpstr, sizeof(tmpstr), "Closed");
2759a6844d5SKenneth D. Merry break;
2769a6844d5SKenneth D. Merry case SRZ_ZONE_COND_READONLY:
2779a6844d5SKenneth D. Merry snprintf(tmpstr, sizeof(tmpstr), "Readonly");
2789a6844d5SKenneth D. Merry break;
2799a6844d5SKenneth D. Merry case SRZ_ZONE_COND_FULL:
2809a6844d5SKenneth D. Merry snprintf(tmpstr, sizeof(tmpstr), "Full");
2819a6844d5SKenneth D. Merry break;
2829a6844d5SKenneth D. Merry case SRZ_ZONE_COND_OFFLINE:
2839a6844d5SKenneth D. Merry snprintf(tmpstr, sizeof(tmpstr), "Offline");
2849a6844d5SKenneth D. Merry break;
2859a6844d5SKenneth D. Merry default:
2869a6844d5SKenneth D. Merry snprintf(tmpstr, sizeof(tmpstr), "%#x",
2879a6844d5SKenneth D. Merry desc->zone_flags & SRZ_ZONE_COND_MASK);
2889a6844d5SKenneth D. Merry break;
2899a6844d5SKenneth D. Merry }
2909a6844d5SKenneth D. Merry
2919a6844d5SKenneth D. Merry printf("%*s, ", field_widths[ZONE_FW_COND], tmpstr);
2929a6844d5SKenneth D. Merry
2939a6844d5SKenneth D. Merry if (desc->zone_flags & SRZ_ZONE_NON_SEQ)
2949a6844d5SKenneth D. Merry snprintf(tmpstr, sizeof(tmpstr), "Non%cSequential",
2959a6844d5SKenneth D. Merry word_sep);
2969a6844d5SKenneth D. Merry else
2979a6844d5SKenneth D. Merry snprintf(tmpstr, sizeof(tmpstr), "Sequential");
2989a6844d5SKenneth D. Merry
2999a6844d5SKenneth D. Merry printf("%*s, ", field_widths[ZONE_FW_SEQ], tmpstr);
3009a6844d5SKenneth D. Merry
3019a6844d5SKenneth D. Merry if (desc->zone_flags & SRZ_ZONE_RESET)
3029a6844d5SKenneth D. Merry snprintf(tmpstr, sizeof(tmpstr), "Reset%cNeeded",
3039a6844d5SKenneth D. Merry word_sep);
3049a6844d5SKenneth D. Merry else
3059a6844d5SKenneth D. Merry snprintf(tmpstr, sizeof(tmpstr), "No%cReset%cNeeded",
3069a6844d5SKenneth D. Merry word_sep, word_sep);
3079a6844d5SKenneth D. Merry
3089a6844d5SKenneth D. Merry printf("%*s\n", field_widths[ZONE_FW_RESET], tmpstr);
3099a6844d5SKenneth D. Merry
3109a6844d5SKenneth D. Merry next_lba = start_lba + length;
3119a6844d5SKenneth D. Merry }
3129a6844d5SKenneth D. Merry bailout:
3139a6844d5SKenneth D. Merry *next_start_lba = next_lba;
3149a6844d5SKenneth D. Merry
3159a6844d5SKenneth D. Merry return (status);
3169a6844d5SKenneth D. Merry }
3179a6844d5SKenneth D. Merry
3189a6844d5SKenneth D. Merry int
zone(struct cam_device * device,int argc,char ** argv,char * combinedopt,int task_attr,int retry_count,int timeout,int verbosemode __unused)3199a6844d5SKenneth D. Merry zone(struct cam_device *device, int argc, char **argv, char *combinedopt,
320492a2ef5SKenneth D. Merry int task_attr, int retry_count, int timeout, int verbosemode __unused)
3219a6844d5SKenneth D. Merry {
3229a6844d5SKenneth D. Merry union ccb *ccb = NULL;
3239a6844d5SKenneth D. Merry int action = -1, rep_option = -1;
3249a6844d5SKenneth D. Merry int all_zones = 0;
3259a6844d5SKenneth D. Merry uint64_t lba = 0;
3269a6844d5SKenneth D. Merry int error = 0;
3279a6844d5SKenneth D. Merry uint8_t *data_ptr = NULL;
3289a6844d5SKenneth D. Merry uint32_t alloc_len = 65536, valid_len = 0;
3299a6844d5SKenneth D. Merry camcontrol_devtype devtype;
3309a6844d5SKenneth D. Merry int ata_format = 0, use_ncq = 0;
3319a6844d5SKenneth D. Merry int first_pass = 1;
3329a6844d5SKenneth D. Merry zone_print_status zp_status;
3339a6844d5SKenneth D. Merry zone_output_flags out_flags = ZONE_OF_NORMAL;
3349a6844d5SKenneth D. Merry uint8_t *cdb_storage = NULL;
3359a6844d5SKenneth D. Merry int cdb_storage_len = 32;
3369a6844d5SKenneth D. Merry int c;
3379a6844d5SKenneth D. Merry
3389a6844d5SKenneth D. Merry ccb = cam_getccb(device);
3399a6844d5SKenneth D. Merry if (ccb == NULL) {
3409a6844d5SKenneth D. Merry warnx("%s: error allocating CCB", __func__);
3419a6844d5SKenneth D. Merry error = 1;
3429a6844d5SKenneth D. Merry goto bailout;
3439a6844d5SKenneth D. Merry }
3449a6844d5SKenneth D. Merry
3459a6844d5SKenneth D. Merry while ((c = getopt(argc, argv, combinedopt)) != -1) {
3469a6844d5SKenneth D. Merry switch (c) {
3479a6844d5SKenneth D. Merry case 'a':
3489a6844d5SKenneth D. Merry all_zones = 1;
3499a6844d5SKenneth D. Merry break;
3509a6844d5SKenneth D. Merry case 'c': {
3519a6844d5SKenneth D. Merry scsi_nv_status status;
3529a6844d5SKenneth D. Merry int entry_num;
3539a6844d5SKenneth D. Merry
3549a6844d5SKenneth D. Merry status = scsi_get_nv(zone_cmd_map,
355*7028e630SElyes Haouas nitems(zone_cmd_map),
3569a6844d5SKenneth D. Merry optarg, &entry_num, SCSI_NV_FLAG_IG_CASE);
3579a6844d5SKenneth D. Merry if (status == SCSI_NV_FOUND)
3589a6844d5SKenneth D. Merry action = zone_cmd_map[entry_num].value;
3599a6844d5SKenneth D. Merry else {
3609a6844d5SKenneth D. Merry warnx("%s: %s: %s option %s", __func__,
3619a6844d5SKenneth D. Merry (status == SCSI_NV_AMBIGUOUS) ?
3629a6844d5SKenneth D. Merry "ambiguous" : "invalid", "zone command",
3639a6844d5SKenneth D. Merry optarg);
3649a6844d5SKenneth D. Merry error = 1;
3659a6844d5SKenneth D. Merry goto bailout;
3669a6844d5SKenneth D. Merry }
3679a6844d5SKenneth D. Merry break;
3689a6844d5SKenneth D. Merry }
3699a6844d5SKenneth D. Merry case 'l': {
3709a6844d5SKenneth D. Merry char *endptr;
3719a6844d5SKenneth D. Merry
3729a6844d5SKenneth D. Merry lba = strtoull(optarg, &endptr, 0);
3739a6844d5SKenneth D. Merry if (*endptr != '\0') {
3749a6844d5SKenneth D. Merry warnx("%s: invalid lba argument %s", __func__,
3759a6844d5SKenneth D. Merry optarg);
3769a6844d5SKenneth D. Merry error = 1;
3779a6844d5SKenneth D. Merry goto bailout;
3789a6844d5SKenneth D. Merry }
3799a6844d5SKenneth D. Merry break;
3809a6844d5SKenneth D. Merry }
3819a6844d5SKenneth D. Merry case 'N':
3829a6844d5SKenneth D. Merry use_ncq = 1;
3839a6844d5SKenneth D. Merry break;
3849a6844d5SKenneth D. Merry case 'o': {
3859a6844d5SKenneth D. Merry scsi_nv_status status;
3869a6844d5SKenneth D. Merry int entry_num;
3879a6844d5SKenneth D. Merry
3889a6844d5SKenneth D. Merry status = scsi_get_nv(zone_rep_opts,
389*7028e630SElyes Haouas nitems(zone_rep_opts),
3909a6844d5SKenneth D. Merry optarg, &entry_num, SCSI_NV_FLAG_IG_CASE);
3919a6844d5SKenneth D. Merry if (status == SCSI_NV_FOUND)
3929a6844d5SKenneth D. Merry rep_option = zone_rep_opts[entry_num].value;
3939a6844d5SKenneth D. Merry else {
3949a6844d5SKenneth D. Merry warnx("%s: %s: %s option %s", __func__,
3959a6844d5SKenneth D. Merry (status == SCSI_NV_AMBIGUOUS) ?
3969a6844d5SKenneth D. Merry "ambiguous" : "invalid", "report zones",
3979a6844d5SKenneth D. Merry optarg);
3989a6844d5SKenneth D. Merry error = 1;
3999a6844d5SKenneth D. Merry goto bailout;
4009a6844d5SKenneth D. Merry }
4019a6844d5SKenneth D. Merry break;
4029a6844d5SKenneth D. Merry }
4039a6844d5SKenneth D. Merry case 'P': {
4049a6844d5SKenneth D. Merry scsi_nv_status status;
4059a6844d5SKenneth D. Merry int entry_num;
4069a6844d5SKenneth D. Merry
4079a6844d5SKenneth D. Merry status = scsi_get_nv(zone_print_opts,
4089a6844d5SKenneth D. Merry (sizeof(zone_print_opts) /
4099a6844d5SKenneth D. Merry sizeof(zone_print_opts[0])), optarg, &entry_num,
4109a6844d5SKenneth D. Merry SCSI_NV_FLAG_IG_CASE);
4119a6844d5SKenneth D. Merry if (status == SCSI_NV_FOUND)
4129a6844d5SKenneth D. Merry out_flags = zone_print_opts[entry_num].value;
4139a6844d5SKenneth D. Merry else {
4149a6844d5SKenneth D. Merry warnx("%s: %s: %s option %s", __func__,
4159a6844d5SKenneth D. Merry (status == SCSI_NV_AMBIGUOUS) ?
4169a6844d5SKenneth D. Merry "ambiguous" : "invalid", "print",
4179a6844d5SKenneth D. Merry optarg);
4189a6844d5SKenneth D. Merry error = 1;
4199a6844d5SKenneth D. Merry goto bailout;
4209a6844d5SKenneth D. Merry }
4219a6844d5SKenneth D. Merry break;
4229a6844d5SKenneth D. Merry }
4239a6844d5SKenneth D. Merry default:
4249a6844d5SKenneth D. Merry break;
4259a6844d5SKenneth D. Merry }
4269a6844d5SKenneth D. Merry }
4279a6844d5SKenneth D. Merry if (action == -1) {
4289a6844d5SKenneth D. Merry warnx("%s: must specify -c <zone_cmd>", __func__);
4299a6844d5SKenneth D. Merry error = 1;
4309a6844d5SKenneth D. Merry goto bailout;
4319a6844d5SKenneth D. Merry }
4329a6844d5SKenneth D. Merry error = get_device_type(device, retry_count, timeout,
4339a6844d5SKenneth D. Merry /*printerrors*/ 1, &devtype);
4349a6844d5SKenneth D. Merry if (error != 0)
4359a6844d5SKenneth D. Merry errx(1, "Unable to determine device type");
4369a6844d5SKenneth D. Merry
4379a6844d5SKenneth D. Merry if (action == ZBC_IN_SA_REPORT_ZONES) {
4389a6844d5SKenneth D. Merry
4399a6844d5SKenneth D. Merry data_ptr = malloc(alloc_len);
4409a6844d5SKenneth D. Merry if (data_ptr == NULL)
4419a6844d5SKenneth D. Merry err(1, "unable to allocate %u bytes", alloc_len);
4429a6844d5SKenneth D. Merry
4439a6844d5SKenneth D. Merry restart_report:
4449a6844d5SKenneth D. Merry bzero(data_ptr, alloc_len);
4459a6844d5SKenneth D. Merry
4469a6844d5SKenneth D. Merry switch (devtype) {
4479a6844d5SKenneth D. Merry case CC_DT_SCSI:
4489a6844d5SKenneth D. Merry scsi_zbc_in(&ccb->csio,
4499a6844d5SKenneth D. Merry /*retries*/ retry_count,
4509a6844d5SKenneth D. Merry /*cbfcnp*/ NULL,
451492a2ef5SKenneth D. Merry /*tag_action*/ task_attr,
4529a6844d5SKenneth D. Merry /*service_action*/ action,
4539a6844d5SKenneth D. Merry /*zone_start_lba*/ lba,
4549a6844d5SKenneth D. Merry /*zone_options*/ (rep_option != -1) ?
4559a6844d5SKenneth D. Merry rep_option : 0,
4569a6844d5SKenneth D. Merry /*data_ptr*/ data_ptr,
4579a6844d5SKenneth D. Merry /*dxfer_len*/ alloc_len,
4589a6844d5SKenneth D. Merry /*sense_len*/ SSD_FULL_SIZE,
4599a6844d5SKenneth D. Merry /*timeout*/ timeout ? timeout : 60000);
4609a6844d5SKenneth D. Merry break;
4619a6844d5SKenneth D. Merry case CC_DT_ATA:
46240152db5SWarner Losh case CC_DT_SATL: {
4639a6844d5SKenneth D. Merry uint8_t command = 0;
4649a6844d5SKenneth D. Merry uint8_t protocol = 0;
4659a6844d5SKenneth D. Merry uint16_t features = 0, sector_count = 0;
4669a6844d5SKenneth D. Merry uint32_t auxiliary = 0;
4679a6844d5SKenneth D. Merry
4689a6844d5SKenneth D. Merry /*
4699a6844d5SKenneth D. Merry * XXX KDM support the partial bit?
4709a6844d5SKenneth D. Merry */
4719a6844d5SKenneth D. Merry if (use_ncq == 0) {
4729a6844d5SKenneth D. Merry command = ATA_ZAC_MANAGEMENT_IN;
4739a6844d5SKenneth D. Merry features = action;
4749a6844d5SKenneth D. Merry if (rep_option != -1)
4759a6844d5SKenneth D. Merry features |= (rep_option << 8);
4769a6844d5SKenneth D. Merry sector_count = ZAC_ATA_SECTOR_COUNT(alloc_len);
4779a6844d5SKenneth D. Merry protocol = AP_PROTO_DMA;
4789a6844d5SKenneth D. Merry } else {
4794992a192SDon Lewis if (cdb_storage == NULL)
4809a6844d5SKenneth D. Merry cdb_storage = calloc(cdb_storage_len, 1);
4819a6844d5SKenneth D. Merry if (cdb_storage == NULL)
4829a6844d5SKenneth D. Merry err(1, "couldn't allocate memory");
4839a6844d5SKenneth D. Merry
4849a6844d5SKenneth D. Merry command = ATA_RECV_FPDMA_QUEUED;
4859a6844d5SKenneth D. Merry features = ZAC_ATA_SECTOR_COUNT(alloc_len);
4869a6844d5SKenneth D. Merry sector_count = ATA_RFPDMA_ZAC_MGMT_IN << 8;
4879a6844d5SKenneth D. Merry auxiliary = action & 0xf;
4889a6844d5SKenneth D. Merry if (rep_option != -1)
4899a6844d5SKenneth D. Merry auxiliary |= rep_option << 8;
4909a6844d5SKenneth D. Merry protocol = AP_PROTO_FPDMA;
4919a6844d5SKenneth D. Merry }
4929a6844d5SKenneth D. Merry
4939a6844d5SKenneth D. Merry error = build_ata_cmd(ccb,
4949a6844d5SKenneth D. Merry /*retry_count*/ retry_count,
4959a6844d5SKenneth D. Merry /*flags*/ CAM_DIR_IN | CAM_DEV_QFRZDIS,
496492a2ef5SKenneth D. Merry /*tag_action*/ task_attr,
4979a6844d5SKenneth D. Merry /*protocol*/ protocol,
4989a6844d5SKenneth D. Merry /*ata_flags*/ AP_FLAG_BYT_BLOK_BLOCKS |
4999a6844d5SKenneth D. Merry AP_FLAG_TLEN_SECT_CNT |
5009a6844d5SKenneth D. Merry AP_FLAG_TDIR_FROM_DEV,
5019a6844d5SKenneth D. Merry /*features*/ features,
5029a6844d5SKenneth D. Merry /*sector_count*/ sector_count,
5039a6844d5SKenneth D. Merry /*lba*/ lba,
5049a6844d5SKenneth D. Merry /*command*/ command,
5059a6844d5SKenneth D. Merry /*auxiliary*/ auxiliary,
5069a6844d5SKenneth D. Merry /*data_ptr*/ data_ptr,
5079a6844d5SKenneth D. Merry /*dxfer_len*/ ZAC_ATA_SECTOR_COUNT(alloc_len)*512,
5089a6844d5SKenneth D. Merry /*cdb_storage*/ cdb_storage,
5099a6844d5SKenneth D. Merry /*cdb_storage_len*/ cdb_storage_len,
5109a6844d5SKenneth D. Merry /*sense_len*/ SSD_FULL_SIZE,
5119a6844d5SKenneth D. Merry /*timeout*/ timeout ? timeout : 60000,
5129a6844d5SKenneth D. Merry /*is48bit*/ 1,
5139a6844d5SKenneth D. Merry /*devtype*/ devtype);
5149a6844d5SKenneth D. Merry
5159a6844d5SKenneth D. Merry if (error != 0) {
5169a6844d5SKenneth D. Merry warnx("%s: build_ata_cmd() failed, likely "
5179a6844d5SKenneth D. Merry "programmer error", __func__);
5189a6844d5SKenneth D. Merry goto bailout;
5199a6844d5SKenneth D. Merry }
5209a6844d5SKenneth D. Merry
5219a6844d5SKenneth D. Merry ata_format = 1;
5229a6844d5SKenneth D. Merry
5239a6844d5SKenneth D. Merry break;
5249a6844d5SKenneth D. Merry }
5259a6844d5SKenneth D. Merry default:
5269a6844d5SKenneth D. Merry warnx("%s: Unknown device type %d", __func__,devtype);
5279a6844d5SKenneth D. Merry error = 1;
5289a6844d5SKenneth D. Merry goto bailout;
5299a6844d5SKenneth D. Merry break; /*NOTREACHED*/
5309a6844d5SKenneth D. Merry }
5319a6844d5SKenneth D. Merry } else {
5329a6844d5SKenneth D. Merry /*
5339a6844d5SKenneth D. Merry * XXX KDM the current methodology is to always send ATA
5349a6844d5SKenneth D. Merry * commands to ATA devices. Need to figure out how to
5359a6844d5SKenneth D. Merry * detect whether a SCSI to ATA translation layer will
5369a6844d5SKenneth D. Merry * translate ZBC IN/OUT commands to the appropriate ZAC
5379a6844d5SKenneth D. Merry * command.
5389a6844d5SKenneth D. Merry */
5399a6844d5SKenneth D. Merry switch (devtype) {
5409a6844d5SKenneth D. Merry case CC_DT_SCSI:
5419a6844d5SKenneth D. Merry scsi_zbc_out(&ccb->csio,
5429a6844d5SKenneth D. Merry /*retries*/ retry_count,
5439a6844d5SKenneth D. Merry /*cbfcnp*/ NULL,
544492a2ef5SKenneth D. Merry /*tag_action*/ task_attr,
5459a6844d5SKenneth D. Merry /*service_action*/ action,
5469a6844d5SKenneth D. Merry /*zone_id*/ lba,
5479a6844d5SKenneth D. Merry /*zone_flags*/ (all_zones != 0) ? ZBC_OUT_ALL : 0,
5489a6844d5SKenneth D. Merry /*data_ptr*/ NULL,
5499a6844d5SKenneth D. Merry /*dxfer_len*/ 0,
5509a6844d5SKenneth D. Merry /*sense_len*/ SSD_FULL_SIZE,
5519a6844d5SKenneth D. Merry /*timeout*/ timeout ? timeout : 60000);
5529a6844d5SKenneth D. Merry break;
5539a6844d5SKenneth D. Merry case CC_DT_ATA:
55440152db5SWarner Losh case CC_DT_SATL: {
5559a6844d5SKenneth D. Merry uint8_t command = 0;
5569a6844d5SKenneth D. Merry uint8_t protocol = 0;
5579a6844d5SKenneth D. Merry uint16_t features = 0, sector_count = 0;
5589a6844d5SKenneth D. Merry uint32_t auxiliary = 0;
5599a6844d5SKenneth D. Merry
5609a6844d5SKenneth D. Merry /*
5619a6844d5SKenneth D. Merry * Note that we're taking advantage of the fact
5629a6844d5SKenneth D. Merry * that the action numbers are the same between the
5639a6844d5SKenneth D. Merry * ZBC and ZAC specs.
5649a6844d5SKenneth D. Merry */
5659a6844d5SKenneth D. Merry
5669a6844d5SKenneth D. Merry if (use_ncq == 0) {
5679a6844d5SKenneth D. Merry protocol = AP_PROTO_NON_DATA;
5689a6844d5SKenneth D. Merry command = ATA_ZAC_MANAGEMENT_OUT;
5699a6844d5SKenneth D. Merry features = action & 0xf;
5709a6844d5SKenneth D. Merry if (all_zones != 0)
5719a6844d5SKenneth D. Merry features |= (ZBC_OUT_ALL << 8);
5729a6844d5SKenneth D. Merry } else {
5739a6844d5SKenneth D. Merry cdb_storage = calloc(cdb_storage_len, 1);
5749a6844d5SKenneth D. Merry if (cdb_storage == NULL)
5759a6844d5SKenneth D. Merry err(1, "couldn't allocate memory");
5769a6844d5SKenneth D. Merry
5779a6844d5SKenneth D. Merry protocol = AP_PROTO_FPDMA;
5789a6844d5SKenneth D. Merry command = ATA_NCQ_NON_DATA;
5799a6844d5SKenneth D. Merry features = ATA_NCQ_ZAC_MGMT_OUT;
5809a6844d5SKenneth D. Merry auxiliary = action & 0xf;
5819a6844d5SKenneth D. Merry if (all_zones != 0)
5829a6844d5SKenneth D. Merry auxiliary |= (ZBC_OUT_ALL << 8);
5839a6844d5SKenneth D. Merry }
5849a6844d5SKenneth D. Merry
5859a6844d5SKenneth D. Merry
5869a6844d5SKenneth D. Merry error = build_ata_cmd(ccb,
5879a6844d5SKenneth D. Merry /*retry_count*/ retry_count,
5889a6844d5SKenneth D. Merry /*flags*/ CAM_DIR_NONE | CAM_DEV_QFRZDIS,
589492a2ef5SKenneth D. Merry /*tag_action*/ task_attr,
59090f05f68SWarner Losh /*protocol*/ protocol,
5919a6844d5SKenneth D. Merry /*ata_flags*/ AP_FLAG_BYT_BLOK_BYTES |
5929a6844d5SKenneth D. Merry AP_FLAG_TLEN_NO_DATA,
5939a6844d5SKenneth D. Merry /*features*/ features,
5949a6844d5SKenneth D. Merry /*sector_count*/ sector_count,
5959a6844d5SKenneth D. Merry /*lba*/ lba,
5969a6844d5SKenneth D. Merry /*command*/ command,
5979a6844d5SKenneth D. Merry /*auxiliary*/ auxiliary,
5989a6844d5SKenneth D. Merry /*data_ptr*/ NULL,
5999a6844d5SKenneth D. Merry /*dxfer_len*/ 0,
6009a6844d5SKenneth D. Merry /*cdb_storage*/ cdb_storage,
6019a6844d5SKenneth D. Merry /*cdb_storage_len*/ cdb_storage_len,
6029a6844d5SKenneth D. Merry /*sense_len*/ SSD_FULL_SIZE,
6039a6844d5SKenneth D. Merry /*timeout*/ timeout ? timeout : 60000,
6049a6844d5SKenneth D. Merry /*is48bit*/ 1,
6059a6844d5SKenneth D. Merry /*devtype*/ devtype);
6069a6844d5SKenneth D. Merry if (error != 0) {
6079a6844d5SKenneth D. Merry warnx("%s: build_ata_cmd() failed, likely "
6089a6844d5SKenneth D. Merry "programmer error", __func__);
6099a6844d5SKenneth D. Merry goto bailout;
6109a6844d5SKenneth D. Merry }
6119a6844d5SKenneth D. Merry ata_format = 1;
6129a6844d5SKenneth D. Merry break;
6139a6844d5SKenneth D. Merry }
6149a6844d5SKenneth D. Merry default:
6159a6844d5SKenneth D. Merry warnx("%s: Unknown device type %d", __func__,devtype);
6169a6844d5SKenneth D. Merry error = 1;
6179a6844d5SKenneth D. Merry goto bailout;
6189a6844d5SKenneth D. Merry break; /*NOTREACHED*/
6199a6844d5SKenneth D. Merry }
6209a6844d5SKenneth D. Merry }
6219a6844d5SKenneth D. Merry
6229a6844d5SKenneth D. Merry ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
6239a6844d5SKenneth D. Merry if (retry_count > 0)
6249a6844d5SKenneth D. Merry ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
6259a6844d5SKenneth D. Merry
6269a6844d5SKenneth D. Merry error = cam_send_ccb(device, ccb);
6279a6844d5SKenneth D. Merry if (error != 0) {
6289a6844d5SKenneth D. Merry warn("error sending %s %s CCB", (devtype == CC_DT_SCSI) ?
6299a6844d5SKenneth D. Merry "ZBC" : "ZAC Management",
6309a6844d5SKenneth D. Merry (action == ZBC_IN_SA_REPORT_ZONES) ? "In" : "Out");
6319a6844d5SKenneth D. Merry error = -1;
6329a6844d5SKenneth D. Merry goto bailout;
6339a6844d5SKenneth D. Merry }
6349a6844d5SKenneth D. Merry
6359a6844d5SKenneth D. Merry if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
6369a6844d5SKenneth D. Merry cam_error_print(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL,stderr);
6379a6844d5SKenneth D. Merry error = 1;
6389a6844d5SKenneth D. Merry goto bailout;
6399a6844d5SKenneth D. Merry }
6409a6844d5SKenneth D. Merry
6419a6844d5SKenneth D. Merry /*
6429a6844d5SKenneth D. Merry * If we aren't reading the list of zones, we're done.
6439a6844d5SKenneth D. Merry */
6449a6844d5SKenneth D. Merry if (action != ZBC_IN_SA_REPORT_ZONES)
6459a6844d5SKenneth D. Merry goto bailout;
6469a6844d5SKenneth D. Merry
6479a6844d5SKenneth D. Merry if (ccb->ccb_h.func_code == XPT_SCSI_IO)
6489a6844d5SKenneth D. Merry valid_len = ccb->csio.dxfer_len - ccb->csio.resid;
6499a6844d5SKenneth D. Merry else
6509a6844d5SKenneth D. Merry valid_len = ccb->ataio.dxfer_len - ccb->ataio.resid;
6519a6844d5SKenneth D. Merry
6529a6844d5SKenneth D. Merry zp_status = zone_rz_print(data_ptr, valid_len, ata_format, out_flags,
6539a6844d5SKenneth D. Merry first_pass, &lba);
6549a6844d5SKenneth D. Merry
6559a6844d5SKenneth D. Merry if (zp_status == ZONE_PRINT_MORE_DATA) {
6569a6844d5SKenneth D. Merry bzero(ccb, sizeof(*ccb));
6579a6844d5SKenneth D. Merry first_pass = 0;
6584992a192SDon Lewis if (cdb_storage != NULL)
6594992a192SDon Lewis bzero(cdb_storage, cdb_storage_len);
6609a6844d5SKenneth D. Merry goto restart_report;
6619a6844d5SKenneth D. Merry } else if (zp_status == ZONE_PRINT_ERROR)
6629a6844d5SKenneth D. Merry error = 1;
6639a6844d5SKenneth D. Merry bailout:
6649a6844d5SKenneth D. Merry if (ccb != NULL)
6659a6844d5SKenneth D. Merry cam_freeccb(ccb);
6669a6844d5SKenneth D. Merry
6679a6844d5SKenneth D. Merry free(data_ptr);
6689a6844d5SKenneth D. Merry free(cdb_storage);
6699a6844d5SKenneth D. Merry
6709a6844d5SKenneth D. Merry return (error);
6719a6844d5SKenneth D. Merry }
672