1300207Sken/*- 2300207Sken * Copyright (c) 2015, 2016 Spectra Logic Corporation 3300207Sken * All rights reserved. 4300207Sken * 5300207Sken * Redistribution and use in source and binary forms, with or without 6300207Sken * modification, are permitted provided that the following conditions 7300207Sken * are met: 8300207Sken * 1. Redistributions of source code must retain the above copyright 9300207Sken * notice, this list of conditions, and the following disclaimer, 10300207Sken * without modification. 11300207Sken * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12300207Sken * substantially similar to the "NO WARRANTY" disclaimer below 13300207Sken * ("Disclaimer") and any redistribution must be conditioned upon 14300207Sken * including a substantially similar Disclaimer requirement for further 15300207Sken * binary redistribution. 16300207Sken * 17300207Sken * NO WARRANTY 18300207Sken * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19300207Sken * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20300207Sken * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 21300207Sken * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22300207Sken * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23300207Sken * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24300207Sken * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25300207Sken * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26300207Sken * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 27300207Sken * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28300207Sken * POSSIBILITY OF SUCH DAMAGES. 29300207Sken * 30300207Sken * Authors: Ken Merry (Spectra Logic Corporation) 31300207Sken */ 32300207Sken/* 33300207Sken * SCSI and ATA Shingled Media Recording (SMR) support for camcontrol(8). 34300207Sken * This is an implementation of the SCSI ZBC and ATA ZAC specs. 35300207Sken */ 36300207Sken 37300207Sken#include <sys/cdefs.h> 38300207Sken__FBSDID("$FreeBSD: stable/11/sbin/camcontrol/zone.c 350796 2019-08-08 21:55:49Z mav $"); 39300207Sken 40300207Sken#include <sys/ioctl.h> 41300207Sken#include <sys/stdint.h> 42300207Sken#include <sys/types.h> 43300207Sken#include <sys/endian.h> 44300207Sken#include <sys/sbuf.h> 45300207Sken#include <sys/queue.h> 46300207Sken#include <sys/chio.h> 47300207Sken 48300207Sken#include <stdio.h> 49300207Sken#include <stdlib.h> 50300207Sken#include <inttypes.h> 51300207Sken#include <unistd.h> 52300207Sken#include <string.h> 53300207Sken#include <strings.h> 54300207Sken#include <fcntl.h> 55300207Sken#include <ctype.h> 56300207Sken#include <limits.h> 57300207Sken#include <err.h> 58300207Sken#include <locale.h> 59300207Sken 60300207Sken#include <cam/cam.h> 61300207Sken#include <cam/cam_debug.h> 62300207Sken#include <cam/cam_ccb.h> 63300207Sken#include <cam/scsi/scsi_all.h> 64300207Sken#include <cam/scsi/scsi_da.h> 65300207Sken#include <cam/scsi/scsi_pass.h> 66300207Sken#include <cam/scsi/scsi_ch.h> 67300207Sken#include <cam/scsi/scsi_message.h> 68300207Sken#include <camlib.h> 69300207Sken#include "camcontrol.h" 70300207Sken 71300207Skenstatic struct scsi_nv zone_cmd_map[] = { 72300207Sken { "rz", ZBC_IN_SA_REPORT_ZONES }, 73300207Sken { "reportzones", ZBC_IN_SA_REPORT_ZONES }, 74300207Sken { "close", ZBC_OUT_SA_CLOSE }, 75300207Sken { "finish", ZBC_OUT_SA_FINISH }, 76300207Sken { "open", ZBC_OUT_SA_OPEN }, 77300207Sken { "rwp", ZBC_OUT_SA_RWP } 78300207Sken}; 79300207Sken 80300207Skenstatic struct scsi_nv zone_rep_opts[] = { 81300207Sken { "all", ZBC_IN_REP_ALL_ZONES }, 82300207Sken { "empty", ZBC_IN_REP_EMPTY }, 83300207Sken { "imp_open", ZBC_IN_REP_IMP_OPEN }, 84300207Sken { "exp_open", ZBC_IN_REP_EXP_OPEN }, 85300207Sken { "closed", ZBC_IN_REP_CLOSED }, 86300207Sken { "full", ZBC_IN_REP_FULL }, 87300207Sken { "readonly", ZBC_IN_REP_READONLY }, 88300207Sken { "ro", ZBC_IN_REP_READONLY }, 89300207Sken { "offline", ZBC_IN_REP_OFFLINE }, 90300207Sken { "rwp", ZBC_IN_REP_RESET }, 91300207Sken { "reset", ZBC_IN_REP_RESET }, 92300207Sken { "nonseq", ZBC_IN_REP_NON_SEQ }, 93300207Sken { "nonwp", ZBC_IN_REP_NON_WP } 94300207Sken}; 95300207Sken 96300207Skentypedef enum { 97300207Sken ZONE_OF_NORMAL = 0x00, 98300207Sken ZONE_OF_SUMMARY = 0x01, 99300207Sken ZONE_OF_SCRIPT = 0x02 100300207Sken} zone_output_flags; 101300207Sken 102300207Skenstatic struct scsi_nv zone_print_opts[] = { 103300207Sken { "normal", ZONE_OF_NORMAL }, 104300207Sken { "summary", ZONE_OF_SUMMARY }, 105300207Sken { "script", ZONE_OF_SCRIPT } 106300207Sken}; 107300207Sken 108300207Sken#define ZAC_ATA_SECTOR_COUNT(bcount) (((bcount) / 512) & 0xffff) 109300207Sken 110300207Skentypedef enum { 111300207Sken ZONE_PRINT_OK, 112300207Sken ZONE_PRINT_MORE_DATA, 113300207Sken ZONE_PRINT_ERROR 114300207Sken} zone_print_status; 115300207Sken 116300207Skentypedef enum { 117300207Sken ZONE_FW_START, 118300207Sken ZONE_FW_LEN, 119300207Sken ZONE_FW_WP, 120300207Sken ZONE_FW_TYPE, 121300207Sken ZONE_FW_COND, 122300207Sken ZONE_FW_SEQ, 123300207Sken ZONE_FW_RESET, 124300207Sken ZONE_NUM_FIELDS 125300207Sken} zone_field_widths; 126300207Sken 127300207Skenzone_print_status zone_rz_print(uint8_t *data_ptr, uint32_t valid_len, 128300207Sken int ata_format, zone_output_flags out_flags, 129300207Sken int first_pass, uint64_t *next_start_lba); 130300207Sken 131300207Sken 132300207Skenzone_print_status 133300207Skenzone_rz_print(uint8_t *data_ptr, uint32_t valid_len, int ata_format, 134300207Sken zone_output_flags out_flags, int first_pass, 135300207Sken uint64_t *next_start_lba) 136300207Sken{ 137300207Sken struct scsi_report_zones_hdr *hdr = NULL; 138300207Sken struct scsi_report_zones_desc *desc = NULL; 139300207Sken uint32_t hdr_len, len; 140300207Sken uint64_t max_lba, next_lba = 0; 141300207Sken int more_data = 0; 142300207Sken zone_print_status status = ZONE_PRINT_OK; 143300207Sken char tmpstr[80]; 144300207Sken int field_widths[ZONE_NUM_FIELDS]; 145300207Sken char word_sep; 146300207Sken 147300207Sken if (valid_len < sizeof(*hdr)) { 148300207Sken status = ZONE_PRINT_ERROR; 149300207Sken goto bailout; 150300207Sken } 151300207Sken 152300207Sken hdr = (struct scsi_report_zones_hdr *)data_ptr; 153300207Sken 154300207Sken field_widths[ZONE_FW_START] = 11; 155300207Sken field_widths[ZONE_FW_LEN] = 6; 156300207Sken field_widths[ZONE_FW_WP] = 11; 157300207Sken field_widths[ZONE_FW_TYPE] = 13; 158300207Sken field_widths[ZONE_FW_COND] = 13; 159300207Sken field_widths[ZONE_FW_SEQ] = 14; 160300207Sken field_widths[ZONE_FW_RESET] = 16; 161300207Sken 162300207Sken if (ata_format == 0) { 163300207Sken hdr_len = scsi_4btoul(hdr->length); 164300207Sken max_lba = scsi_8btou64(hdr->maximum_lba); 165300207Sken } else { 166300207Sken hdr_len = le32dec(hdr->length); 167300207Sken max_lba = le64dec(hdr->maximum_lba); 168300207Sken } 169300207Sken 170300207Sken if (hdr_len > (valid_len + sizeof(*hdr))) { 171300207Sken more_data = 1; 172300207Sken status = ZONE_PRINT_MORE_DATA; 173300207Sken } 174300207Sken 175300207Sken len = MIN(valid_len - sizeof(*hdr), hdr_len); 176300207Sken 177300207Sken if (out_flags == ZONE_OF_SCRIPT) 178300207Sken word_sep = '_'; 179300207Sken else 180300207Sken word_sep = ' '; 181300207Sken 182300207Sken if ((out_flags != ZONE_OF_SCRIPT) 183300207Sken && (first_pass != 0)) { 184300207Sken printf("%zu zones, Maximum LBA %#jx (%ju)\n", 185300207Sken hdr_len / sizeof(*desc), (uintmax_t)max_lba, 186300207Sken (uintmax_t)max_lba); 187300207Sken 188300207Sken switch (hdr->byte4 & SRZ_SAME_MASK) { 189300207Sken case SRZ_SAME_ALL_DIFFERENT: 190300207Sken printf("Zone lengths and types may vary\n"); 191300207Sken break; 192300207Sken case SRZ_SAME_ALL_SAME: 193300207Sken printf("Zone lengths and types are all the same\n"); 194300207Sken break; 195300207Sken case SRZ_SAME_LAST_DIFFERENT: 196300207Sken printf("Zone types are the same, last zone length " 197300207Sken "differs\n"); 198300207Sken break; 199300207Sken case SRZ_SAME_TYPES_DIFFERENT: 200300207Sken printf("Zone lengths are the same, types vary\n"); 201300207Sken break; 202300207Sken default: 203300207Sken printf("Unknown SAME field value %#x\n", 204300207Sken hdr->byte4 & SRZ_SAME_MASK); 205300207Sken break; 206300207Sken } 207300207Sken } 208300207Sken if (out_flags == ZONE_OF_SUMMARY) { 209300207Sken status = ZONE_PRINT_OK; 210300207Sken goto bailout; 211300207Sken } 212300207Sken 213300207Sken if ((out_flags == ZONE_OF_NORMAL) 214300207Sken && (first_pass != 0)) { 215300207Sken printf("%*s %*s %*s %*s %*s %*s %*s\n", 216300207Sken field_widths[ZONE_FW_START], "Start LBA", 217300207Sken field_widths[ZONE_FW_LEN], "Length", 218300207Sken field_widths[ZONE_FW_WP], "WP LBA", 219300207Sken field_widths[ZONE_FW_TYPE], "Zone Type", 220300207Sken field_widths[ZONE_FW_COND], "Condition", 221300207Sken field_widths[ZONE_FW_SEQ], "Sequential", 222300207Sken field_widths[ZONE_FW_RESET], "Reset"); 223300207Sken } 224300207Sken 225300207Sken for (desc = &hdr->desc_list[0]; len >= sizeof(*desc); 226300207Sken len -= sizeof(*desc), desc++) { 227300207Sken uint64_t length, start_lba, wp_lba; 228300207Sken 229300207Sken if (ata_format == 0) { 230300207Sken length = scsi_8btou64(desc->zone_length); 231300207Sken start_lba = scsi_8btou64(desc->zone_start_lba); 232300207Sken wp_lba = scsi_8btou64(desc->write_pointer_lba); 233300207Sken } else { 234300207Sken length = le64dec(desc->zone_length); 235300207Sken start_lba = le64dec(desc->zone_start_lba); 236300207Sken wp_lba = le64dec(desc->write_pointer_lba); 237300207Sken } 238300207Sken 239300207Sken printf("%#*jx, %*ju, %#*jx, ", field_widths[ZONE_FW_START], 240300207Sken (uintmax_t)start_lba, field_widths[ZONE_FW_LEN], 241300207Sken (uintmax_t)length, field_widths[ZONE_FW_WP], 242300207Sken (uintmax_t)wp_lba); 243300207Sken 244300207Sken switch (desc->zone_type & SRZ_TYPE_MASK) { 245300207Sken case SRZ_TYPE_CONVENTIONAL: 246300207Sken snprintf(tmpstr, sizeof(tmpstr), "Conventional"); 247300207Sken break; 248300207Sken case SRZ_TYPE_SEQ_PREFERRED: 249300207Sken case SRZ_TYPE_SEQ_REQUIRED: 250300207Sken snprintf(tmpstr, sizeof(tmpstr), "Seq%c%s", 251300207Sken word_sep, ((desc->zone_type & SRZ_TYPE_MASK) == 252300207Sken SRZ_TYPE_SEQ_PREFERRED) ? "Preferred" : 253300207Sken "Required"); 254300207Sken break; 255300207Sken default: 256300207Sken snprintf(tmpstr, sizeof(tmpstr), "Zone%ctype%c%#x", 257300207Sken word_sep, word_sep,desc->zone_type & 258300207Sken SRZ_TYPE_MASK); 259300207Sken break; 260300207Sken } 261300207Sken printf("%*s, ", field_widths[ZONE_FW_TYPE], tmpstr); 262300207Sken 263300207Sken switch (desc->zone_flags & SRZ_ZONE_COND_MASK) { 264300207Sken case SRZ_ZONE_COND_NWP: 265300207Sken snprintf(tmpstr, sizeof(tmpstr), "NWP"); 266300207Sken break; 267300207Sken case SRZ_ZONE_COND_EMPTY: 268300207Sken snprintf(tmpstr, sizeof(tmpstr), "Empty"); 269300207Sken break; 270300207Sken case SRZ_ZONE_COND_IMP_OPEN: 271300207Sken snprintf(tmpstr, sizeof(tmpstr), "Implicit%cOpen", 272300207Sken word_sep); 273300207Sken break; 274300207Sken case SRZ_ZONE_COND_EXP_OPEN: 275300207Sken snprintf(tmpstr, sizeof(tmpstr), "Explicit%cOpen", 276300207Sken word_sep); 277300207Sken break; 278300207Sken case SRZ_ZONE_COND_CLOSED: 279300207Sken snprintf(tmpstr, sizeof(tmpstr), "Closed"); 280300207Sken break; 281300207Sken case SRZ_ZONE_COND_READONLY: 282300207Sken snprintf(tmpstr, sizeof(tmpstr), "Readonly"); 283300207Sken break; 284300207Sken case SRZ_ZONE_COND_FULL: 285300207Sken snprintf(tmpstr, sizeof(tmpstr), "Full"); 286300207Sken break; 287300207Sken case SRZ_ZONE_COND_OFFLINE: 288300207Sken snprintf(tmpstr, sizeof(tmpstr), "Offline"); 289300207Sken break; 290300207Sken default: 291300207Sken snprintf(tmpstr, sizeof(tmpstr), "%#x", 292300207Sken desc->zone_flags & SRZ_ZONE_COND_MASK); 293300207Sken break; 294300207Sken } 295300207Sken 296300207Sken printf("%*s, ", field_widths[ZONE_FW_COND], tmpstr); 297300207Sken 298300207Sken if (desc->zone_flags & SRZ_ZONE_NON_SEQ) 299300207Sken snprintf(tmpstr, sizeof(tmpstr), "Non%cSequential", 300300207Sken word_sep); 301300207Sken else 302300207Sken snprintf(tmpstr, sizeof(tmpstr), "Sequential"); 303300207Sken 304300207Sken printf("%*s, ", field_widths[ZONE_FW_SEQ], tmpstr); 305300207Sken 306300207Sken if (desc->zone_flags & SRZ_ZONE_RESET) 307300207Sken snprintf(tmpstr, sizeof(tmpstr), "Reset%cNeeded", 308300207Sken word_sep); 309300207Sken else 310300207Sken snprintf(tmpstr, sizeof(tmpstr), "No%cReset%cNeeded", 311300207Sken word_sep, word_sep); 312300207Sken 313300207Sken printf("%*s\n", field_widths[ZONE_FW_RESET], tmpstr); 314300207Sken 315300207Sken next_lba = start_lba + length; 316300207Sken } 317300207Skenbailout: 318300207Sken *next_start_lba = next_lba; 319300207Sken 320300207Sken return (status); 321300207Sken} 322300207Sken 323300207Skenint 324300207Skenzone(struct cam_device *device, int argc, char **argv, char *combinedopt, 325314220Sken int task_attr, int retry_count, int timeout, int verbosemode __unused) 326300207Sken{ 327300207Sken union ccb *ccb = NULL; 328300207Sken int action = -1, rep_option = -1; 329300207Sken int all_zones = 0; 330300207Sken uint64_t lba = 0; 331300207Sken int error = 0; 332300207Sken uint8_t *data_ptr = NULL; 333300207Sken uint32_t alloc_len = 65536, valid_len = 0; 334300207Sken camcontrol_devtype devtype; 335300207Sken int ata_format = 0, use_ncq = 0; 336300207Sken int first_pass = 1; 337300207Sken zone_print_status zp_status; 338300207Sken zone_output_flags out_flags = ZONE_OF_NORMAL; 339300207Sken uint8_t *cdb_storage = NULL; 340300207Sken int cdb_storage_len = 32; 341300207Sken int c; 342300207Sken 343300207Sken ccb = cam_getccb(device); 344300207Sken if (ccb == NULL) { 345300207Sken warnx("%s: error allocating CCB", __func__); 346300207Sken error = 1; 347300207Sken goto bailout; 348300207Sken } 349300207Sken 350300685Struckman CCB_CLEAR_ALL_EXCEPT_HDR(ccb); 351300207Sken 352300207Sken while ((c = getopt(argc, argv, combinedopt)) != -1) { 353300207Sken switch (c) { 354300207Sken case 'a': 355300207Sken all_zones = 1; 356300207Sken break; 357300207Sken case 'c': { 358300207Sken scsi_nv_status status; 359300207Sken int entry_num; 360300207Sken 361300207Sken status = scsi_get_nv(zone_cmd_map, 362300207Sken (sizeof(zone_cmd_map) / sizeof(zone_cmd_map[0])), 363300207Sken optarg, &entry_num, SCSI_NV_FLAG_IG_CASE); 364300207Sken if (status == SCSI_NV_FOUND) 365300207Sken action = zone_cmd_map[entry_num].value; 366300207Sken else { 367300207Sken warnx("%s: %s: %s option %s", __func__, 368300207Sken (status == SCSI_NV_AMBIGUOUS) ? 369300207Sken "ambiguous" : "invalid", "zone command", 370300207Sken optarg); 371300207Sken error = 1; 372300207Sken goto bailout; 373300207Sken } 374300207Sken break; 375300207Sken } 376300207Sken case 'l': { 377300207Sken char *endptr; 378300207Sken 379300207Sken lba = strtoull(optarg, &endptr, 0); 380300207Sken if (*endptr != '\0') { 381300207Sken warnx("%s: invalid lba argument %s", __func__, 382300207Sken optarg); 383300207Sken error = 1; 384300207Sken goto bailout; 385300207Sken } 386300207Sken break; 387300207Sken } 388300207Sken case 'N': 389300207Sken use_ncq = 1; 390300207Sken break; 391300207Sken case 'o': { 392300207Sken scsi_nv_status status; 393300207Sken int entry_num; 394300207Sken 395300207Sken status = scsi_get_nv(zone_rep_opts, 396300207Sken (sizeof(zone_rep_opts) /sizeof(zone_rep_opts[0])), 397300207Sken optarg, &entry_num, SCSI_NV_FLAG_IG_CASE); 398300207Sken if (status == SCSI_NV_FOUND) 399300207Sken rep_option = zone_rep_opts[entry_num].value; 400300207Sken else { 401300207Sken warnx("%s: %s: %s option %s", __func__, 402300207Sken (status == SCSI_NV_AMBIGUOUS) ? 403300207Sken "ambiguous" : "invalid", "report zones", 404300207Sken optarg); 405300207Sken error = 1; 406300207Sken goto bailout; 407300207Sken } 408300207Sken break; 409300207Sken } 410300207Sken case 'P': { 411300207Sken scsi_nv_status status; 412300207Sken int entry_num; 413300207Sken 414300207Sken status = scsi_get_nv(zone_print_opts, 415300207Sken (sizeof(zone_print_opts) / 416300207Sken sizeof(zone_print_opts[0])), optarg, &entry_num, 417300207Sken SCSI_NV_FLAG_IG_CASE); 418300207Sken if (status == SCSI_NV_FOUND) 419300207Sken out_flags = zone_print_opts[entry_num].value; 420300207Sken else { 421300207Sken warnx("%s: %s: %s option %s", __func__, 422300207Sken (status == SCSI_NV_AMBIGUOUS) ? 423300207Sken "ambiguous" : "invalid", "print", 424300207Sken optarg); 425300207Sken error = 1; 426300207Sken goto bailout; 427300207Sken } 428300207Sken break; 429300207Sken } 430300207Sken default: 431300207Sken break; 432300207Sken } 433300207Sken } 434300207Sken if (action == -1) { 435300207Sken warnx("%s: must specify -c <zone_cmd>", __func__); 436300207Sken error = 1; 437300207Sken goto bailout; 438300207Sken } 439300207Sken error = get_device_type(device, retry_count, timeout, 440300207Sken /*printerrors*/ 1, &devtype); 441300207Sken if (error != 0) 442300207Sken errx(1, "Unable to determine device type"); 443300207Sken 444300207Sken if (action == ZBC_IN_SA_REPORT_ZONES) { 445300207Sken 446300207Sken data_ptr = malloc(alloc_len); 447300207Sken if (data_ptr == NULL) 448300207Sken err(1, "unable to allocate %u bytes", alloc_len); 449300207Sken 450300207Skenrestart_report: 451300207Sken bzero(data_ptr, alloc_len); 452300207Sken 453300207Sken switch (devtype) { 454300207Sken case CC_DT_SCSI: 455300207Sken scsi_zbc_in(&ccb->csio, 456300207Sken /*retries*/ retry_count, 457300207Sken /*cbfcnp*/ NULL, 458314220Sken /*tag_action*/ task_attr, 459300207Sken /*service_action*/ action, 460300207Sken /*zone_start_lba*/ lba, 461300207Sken /*zone_options*/ (rep_option != -1) ? 462300207Sken rep_option : 0, 463300207Sken /*data_ptr*/ data_ptr, 464300207Sken /*dxfer_len*/ alloc_len, 465300207Sken /*sense_len*/ SSD_FULL_SIZE, 466300207Sken /*timeout*/ timeout ? timeout : 60000); 467300207Sken break; 468300207Sken case CC_DT_ATA: 469350796Smav case CC_DT_SATL: { 470300207Sken uint8_t command = 0; 471300207Sken uint8_t protocol = 0; 472300207Sken uint16_t features = 0, sector_count = 0; 473300207Sken uint32_t auxiliary = 0; 474300207Sken 475300207Sken /* 476300207Sken * XXX KDM support the partial bit? 477300207Sken */ 478300207Sken if (use_ncq == 0) { 479300207Sken command = ATA_ZAC_MANAGEMENT_IN; 480300207Sken features = action; 481300207Sken if (rep_option != -1) 482300207Sken features |= (rep_option << 8); 483300207Sken sector_count = ZAC_ATA_SECTOR_COUNT(alloc_len); 484300207Sken protocol = AP_PROTO_DMA; 485300207Sken } else { 486300207Sken if (cdb_storage == NULL) 487300685Struckman cdb_storage = calloc(cdb_storage_len, 1); 488300685Struckman if (cdb_storage == NULL) 489300207Sken err(1, "couldn't allocate memory"); 490300207Sken 491300207Sken command = ATA_RECV_FPDMA_QUEUED; 492300207Sken features = ZAC_ATA_SECTOR_COUNT(alloc_len); 493300207Sken sector_count = ATA_RFPDMA_ZAC_MGMT_IN << 8; 494300207Sken auxiliary = action & 0xf; 495300207Sken if (rep_option != -1) 496300207Sken auxiliary |= rep_option << 8; 497300207Sken protocol = AP_PROTO_FPDMA; 498300207Sken } 499300207Sken 500300207Sken error = build_ata_cmd(ccb, 501300207Sken /*retry_count*/ retry_count, 502300207Sken /*flags*/ CAM_DIR_IN | CAM_DEV_QFRZDIS, 503314220Sken /*tag_action*/ task_attr, 504300207Sken /*protocol*/ protocol, 505300207Sken /*ata_flags*/ AP_FLAG_BYT_BLOK_BLOCKS | 506300207Sken AP_FLAG_TLEN_SECT_CNT | 507300207Sken AP_FLAG_TDIR_FROM_DEV, 508300207Sken /*features*/ features, 509300207Sken /*sector_count*/ sector_count, 510300207Sken /*lba*/ lba, 511300207Sken /*command*/ command, 512300207Sken /*auxiliary*/ auxiliary, 513300207Sken /*data_ptr*/ data_ptr, 514300207Sken /*dxfer_len*/ ZAC_ATA_SECTOR_COUNT(alloc_len)*512, 515300207Sken /*cdb_storage*/ cdb_storage, 516300207Sken /*cdb_storage_len*/ cdb_storage_len, 517300207Sken /*sense_len*/ SSD_FULL_SIZE, 518300207Sken /*timeout*/ timeout ? timeout : 60000, 519300207Sken /*is48bit*/ 1, 520300207Sken /*devtype*/ devtype); 521300207Sken 522300207Sken if (error != 0) { 523300207Sken warnx("%s: build_ata_cmd() failed, likely " 524300207Sken "programmer error", __func__); 525300207Sken goto bailout; 526300207Sken } 527300207Sken 528300207Sken ata_format = 1; 529300207Sken 530300207Sken break; 531300207Sken } 532300207Sken default: 533300207Sken warnx("%s: Unknown device type %d", __func__,devtype); 534300207Sken error = 1; 535300207Sken goto bailout; 536300207Sken break; /*NOTREACHED*/ 537300207Sken } 538300207Sken } else { 539300207Sken /* 540300207Sken * XXX KDM the current methodology is to always send ATA 541300207Sken * commands to ATA devices. Need to figure out how to 542300207Sken * detect whether a SCSI to ATA translation layer will 543300207Sken * translate ZBC IN/OUT commands to the appropriate ZAC 544300207Sken * command. 545300207Sken */ 546300207Sken switch (devtype) { 547300207Sken case CC_DT_SCSI: 548300207Sken scsi_zbc_out(&ccb->csio, 549300207Sken /*retries*/ retry_count, 550300207Sken /*cbfcnp*/ NULL, 551314220Sken /*tag_action*/ task_attr, 552300207Sken /*service_action*/ action, 553300207Sken /*zone_id*/ lba, 554300207Sken /*zone_flags*/ (all_zones != 0) ? ZBC_OUT_ALL : 0, 555300207Sken /*data_ptr*/ NULL, 556300207Sken /*dxfer_len*/ 0, 557300207Sken /*sense_len*/ SSD_FULL_SIZE, 558300207Sken /*timeout*/ timeout ? timeout : 60000); 559300207Sken break; 560300207Sken case CC_DT_ATA: 561350796Smav case CC_DT_SATL: { 562300207Sken uint8_t command = 0; 563300207Sken uint8_t protocol = 0; 564300207Sken uint16_t features = 0, sector_count = 0; 565300207Sken uint32_t auxiliary = 0; 566300207Sken 567300207Sken /* 568300207Sken * Note that we're taking advantage of the fact 569300207Sken * that the action numbers are the same between the 570300207Sken * ZBC and ZAC specs. 571300207Sken */ 572300207Sken 573300207Sken if (use_ncq == 0) { 574300207Sken protocol = AP_PROTO_NON_DATA; 575300207Sken command = ATA_ZAC_MANAGEMENT_OUT; 576300207Sken features = action & 0xf; 577300207Sken if (all_zones != 0) 578300207Sken features |= (ZBC_OUT_ALL << 8); 579300207Sken } else { 580300207Sken cdb_storage = calloc(cdb_storage_len, 1); 581300207Sken if (cdb_storage == NULL) 582300207Sken err(1, "couldn't allocate memory"); 583300207Sken 584300207Sken protocol = AP_PROTO_FPDMA; 585300207Sken command = ATA_NCQ_NON_DATA; 586300207Sken features = ATA_NCQ_ZAC_MGMT_OUT; 587300207Sken auxiliary = action & 0xf; 588300207Sken if (all_zones != 0) 589300207Sken auxiliary |= (ZBC_OUT_ALL << 8); 590300207Sken } 591300207Sken 592300207Sken 593300207Sken error = build_ata_cmd(ccb, 594300207Sken /*retry_count*/ retry_count, 595300207Sken /*flags*/ CAM_DIR_NONE | CAM_DEV_QFRZDIS, 596314220Sken /*tag_action*/ task_attr, 597300207Sken /*protocol*/ AP_PROTO_NON_DATA, 598300207Sken /*ata_flags*/ AP_FLAG_BYT_BLOK_BYTES | 599300207Sken AP_FLAG_TLEN_NO_DATA, 600300207Sken /*features*/ features, 601300207Sken /*sector_count*/ sector_count, 602300207Sken /*lba*/ lba, 603300207Sken /*command*/ command, 604300207Sken /*auxiliary*/ auxiliary, 605300207Sken /*data_ptr*/ NULL, 606300207Sken /*dxfer_len*/ 0, 607300207Sken /*cdb_storage*/ cdb_storage, 608300207Sken /*cdb_storage_len*/ cdb_storage_len, 609300207Sken /*sense_len*/ SSD_FULL_SIZE, 610300207Sken /*timeout*/ timeout ? timeout : 60000, 611300207Sken /*is48bit*/ 1, 612300207Sken /*devtype*/ devtype); 613300207Sken if (error != 0) { 614300207Sken warnx("%s: build_ata_cmd() failed, likely " 615300207Sken "programmer error", __func__); 616300207Sken goto bailout; 617300207Sken } 618300207Sken ata_format = 1; 619300207Sken break; 620300207Sken } 621300207Sken default: 622300207Sken warnx("%s: Unknown device type %d", __func__,devtype); 623300207Sken error = 1; 624300207Sken goto bailout; 625300207Sken break; /*NOTREACHED*/ 626300207Sken } 627300207Sken } 628300207Sken 629300207Sken ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 630300207Sken if (retry_count > 0) 631300207Sken ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 632300207Sken 633300207Sken error = cam_send_ccb(device, ccb); 634300207Sken if (error != 0) { 635300207Sken warn("error sending %s %s CCB", (devtype == CC_DT_SCSI) ? 636300207Sken "ZBC" : "ZAC Management", 637300207Sken (action == ZBC_IN_SA_REPORT_ZONES) ? "In" : "Out"); 638300207Sken error = -1; 639300207Sken goto bailout; 640300207Sken } 641300207Sken 642300207Sken if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 643300207Sken cam_error_print(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL,stderr); 644300207Sken error = 1; 645300207Sken goto bailout; 646300207Sken } 647300207Sken 648300207Sken /* 649300207Sken * If we aren't reading the list of zones, we're done. 650300207Sken */ 651300207Sken if (action != ZBC_IN_SA_REPORT_ZONES) 652300207Sken goto bailout; 653300207Sken 654300207Sken if (ccb->ccb_h.func_code == XPT_SCSI_IO) 655300207Sken valid_len = ccb->csio.dxfer_len - ccb->csio.resid; 656300207Sken else 657300207Sken valid_len = ccb->ataio.dxfer_len - ccb->ataio.resid; 658300207Sken 659300207Sken zp_status = zone_rz_print(data_ptr, valid_len, ata_format, out_flags, 660300207Sken first_pass, &lba); 661300207Sken 662300207Sken if (zp_status == ZONE_PRINT_MORE_DATA) { 663300207Sken bzero(ccb, sizeof(*ccb)); 664300207Sken first_pass = 0; 665300685Struckman if (cdb_storage != NULL) 666300685Struckman bzero(cdb_storage, cdb_storage_len); 667300207Sken goto restart_report; 668300207Sken } else if (zp_status == ZONE_PRINT_ERROR) 669300207Sken error = 1; 670300207Skenbailout: 671300207Sken if (ccb != NULL) 672300207Sken cam_freeccb(ccb); 673300207Sken 674300207Sken free(data_ptr); 675300207Sken free(cdb_storage); 676300207Sken 677300207Sken return (error); 678300207Sken} 679