zone.c revision 314220
1168457Skato/*- 264123Skato * Copyright (c) 2015, 2016 Spectra Logic Corporation 364123Skato * All rights reserved. 464123Skato * 564123Skato * Redistribution and use in source and binary forms, with or without 664123Skato * modification, are permitted provided that the following conditions 764123Skato * are met: 864123Skato * 1. Redistributions of source code must retain the above copyright 964123Skato * notice, this list of conditions, and the following disclaimer, 1064123Skato * without modification. 1164123Skato * 2. Redistributions in binary form must reproduce at minimum a disclaimer 1264123Skato * substantially similar to the "NO WARRANTY" disclaimer below 1364123Skato * ("Disclaimer") and any redistribution must be conditioned upon 1464123Skato * including a substantially similar Disclaimer requirement for further 1564123Skato * binary redistribution. 1664123Skato * 1764123Skato * NO WARRANTY 1864123Skato * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1964123Skato * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2064123Skato * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 2164123Skato * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2264123Skato * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2364123Skato * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2464123Skato * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2564123Skato * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 2664123Skato * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 2764123Skato * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 2864123Skato * POSSIBILITY OF SUCH DAMAGES. 2964123Skato * 3064123Skato * Authors: Ken Merry (Spectra Logic Corporation) 3164123Skato */ 3264123Skato/* 3364123Skato * SCSI and ATA Shingled Media Recording (SMR) support for camcontrol(8). 3464123Skato * This is an implementation of the SCSI ZBC and ATA ZAC specs. 3564123Skato */ 3664123Skato 3764123Skato#include <sys/cdefs.h> 38201399Smbr__FBSDID("$FreeBSD: stable/11/sbin/camcontrol/zone.c 314220 2017-02-24 20:47:56Z ken $"); 3964123Skato 4064123Skato#include <sys/ioctl.h> 4164123Skato#include <sys/stdint.h> 4264123Skato#include <sys/types.h> 4364123Skato#include <sys/endian.h> 4464123Skato#include <sys/sbuf.h> 4564123Skato#include <sys/queue.h> 4664123Skato#include <sys/chio.h> 4764123Skato 4864123Skato#include <stdio.h> 4964123Skato#include <stdlib.h> 5064123Skato#include <inttypes.h> 5164123Skato#include <unistd.h> 5264123Skato#include <string.h> 5364123Skato#include <strings.h> 5464123Skato#include <fcntl.h> 5564123Skato#include <ctype.h> 5664123Skato#include <limits.h> 5764123Skato#include <err.h> 5864123Skato#include <locale.h> 5964123Skato 6064123Skato#include <cam/cam.h> 6164123Skato#include <cam/cam_debug.h> 6264123Skato#include <cam/cam_ccb.h> 6364123Skato#include <cam/scsi/scsi_all.h> 6464123Skato#include <cam/scsi/scsi_da.h> 6564123Skato#include <cam/scsi/scsi_pass.h> 6664123Skato#include <cam/scsi/scsi_ch.h> 6764123Skato#include <cam/scsi/scsi_message.h> 6864123Skato#include <camlib.h> 6964123Skato#include "camcontrol.h" 7064123Skato 7164123Skatostatic struct scsi_nv zone_cmd_map[] = { 7264123Skato { "rz", ZBC_IN_SA_REPORT_ZONES }, 7364123Skato { "reportzones", ZBC_IN_SA_REPORT_ZONES }, 7464123Skato { "close", ZBC_OUT_SA_CLOSE }, 7564123Skato { "finish", ZBC_OUT_SA_FINISH }, 7664123Skato { "open", ZBC_OUT_SA_OPEN }, 7764123Skato { "rwp", ZBC_OUT_SA_RWP } 7864123Skato}; 7964123Skato 8064123Skatostatic struct scsi_nv zone_rep_opts[] = { 8164123Skato { "all", ZBC_IN_REP_ALL_ZONES }, 8264123Skato { "empty", ZBC_IN_REP_EMPTY }, 8364123Skato { "imp_open", ZBC_IN_REP_IMP_OPEN }, 8464123Skato { "exp_open", ZBC_IN_REP_EXP_OPEN }, 8564123Skato { "closed", ZBC_IN_REP_CLOSED }, 8664123Skato { "full", ZBC_IN_REP_FULL }, 8764123Skato { "readonly", ZBC_IN_REP_READONLY }, 8864123Skato { "ro", ZBC_IN_REP_READONLY }, 8964123Skato { "offline", ZBC_IN_REP_OFFLINE }, 9064123Skato { "rwp", ZBC_IN_REP_RESET }, 9164123Skato { "reset", ZBC_IN_REP_RESET }, 9264123Skato { "nonseq", ZBC_IN_REP_NON_SEQ }, 9364123Skato { "nonwp", ZBC_IN_REP_NON_WP } 9464123Skato}; 9564123Skato 9664123Skatotypedef enum { 9764123Skato ZONE_OF_NORMAL = 0x00, 9864123Skato ZONE_OF_SUMMARY = 0x01, 9964123Skato ZONE_OF_SCRIPT = 0x02 10064123Skato} zone_output_flags; 10164123Skato 10264123Skatostatic struct scsi_nv zone_print_opts[] = { 10364123Skato { "normal", ZONE_OF_NORMAL }, 10464123Skato { "summary", ZONE_OF_SUMMARY }, 10564123Skato { "script", ZONE_OF_SCRIPT } 10664123Skato}; 10764123Skato 10864123Skato#define ZAC_ATA_SECTOR_COUNT(bcount) (((bcount) / 512) & 0xffff) 10964123Skato 11064123Skatotypedef enum { 11164123Skato ZONE_PRINT_OK, 11264123Skato ZONE_PRINT_MORE_DATA, 11364123Skato ZONE_PRINT_ERROR 11464123Skato} zone_print_status; 11564123Skato 11664123Skatotypedef enum { 11764123Skato ZONE_FW_START, 11864123Skato ZONE_FW_LEN, 11964123Skato ZONE_FW_WP, 12064123Skato ZONE_FW_TYPE, 12164123Skato ZONE_FW_COND, 12264123Skato ZONE_FW_SEQ, 12364123Skato ZONE_FW_RESET, 12464123Skato ZONE_NUM_FIELDS 12564123Skato} zone_field_widths; 12664123Skato 12764123Skatozone_print_status zone_rz_print(uint8_t *data_ptr, uint32_t valid_len, 12864123Skato int ata_format, zone_output_flags out_flags, 12964123Skato int first_pass, uint64_t *next_start_lba); 13064123Skato 13164123Skato 13264123Skatozone_print_status 13364123Skatozone_rz_print(uint8_t *data_ptr, uint32_t valid_len, int ata_format, 13464123Skato zone_output_flags out_flags, int first_pass, 13564123Skato uint64_t *next_start_lba) 13664123Skato{ 13764123Skato struct scsi_report_zones_hdr *hdr = NULL; 13864123Skato struct scsi_report_zones_desc *desc = NULL; 13964123Skato uint32_t hdr_len, len; 14064123Skato uint64_t max_lba, next_lba = 0; 14164123Skato int more_data = 0; 14264123Skato zone_print_status status = ZONE_PRINT_OK; 14364123Skato char tmpstr[80]; 14464123Skato int field_widths[ZONE_NUM_FIELDS]; 14564123Skato char word_sep; 14664123Skato 14764123Skato if (valid_len < sizeof(*hdr)) { 14864123Skato status = ZONE_PRINT_ERROR; 14964123Skato goto bailout; 15064123Skato } 15164123Skato 15264123Skato hdr = (struct scsi_report_zones_hdr *)data_ptr; 15364123Skato 15464123Skato field_widths[ZONE_FW_START] = 11; 15564123Skato field_widths[ZONE_FW_LEN] = 6; 15664123Skato field_widths[ZONE_FW_WP] = 11; 15764123Skato field_widths[ZONE_FW_TYPE] = 13; 15864123Skato field_widths[ZONE_FW_COND] = 13; 15964123Skato field_widths[ZONE_FW_SEQ] = 14; 16064123Skato field_widths[ZONE_FW_RESET] = 16; 16164123Skato 16264123Skato if (ata_format == 0) { 16364123Skato hdr_len = scsi_4btoul(hdr->length); 16464123Skato max_lba = scsi_8btou64(hdr->maximum_lba); 16564123Skato } else { 16664123Skato hdr_len = le32dec(hdr->length); 16764123Skato max_lba = le64dec(hdr->maximum_lba); 16864123Skato } 16964123Skato 17064123Skato if (hdr_len > (valid_len + sizeof(*hdr))) { 17164123Skato more_data = 1; 17264123Skato status = ZONE_PRINT_MORE_DATA; 17364123Skato } 17464123Skato 17564123Skato len = MIN(valid_len - sizeof(*hdr), hdr_len); 17664123Skato 17764123Skato if (out_flags == ZONE_OF_SCRIPT) 17864123Skato word_sep = '_'; 17964123Skato else 18064123Skato word_sep = ' '; 18164123Skato 18264123Skato if ((out_flags != ZONE_OF_SCRIPT) 18364123Skato && (first_pass != 0)) { 18464123Skato printf("%zu zones, Maximum LBA %#jx (%ju)\n", 18564123Skato hdr_len / sizeof(*desc), (uintmax_t)max_lba, 18664123Skato (uintmax_t)max_lba); 18764123Skato 18864123Skato switch (hdr->byte4 & SRZ_SAME_MASK) { 18964123Skato case SRZ_SAME_ALL_DIFFERENT: 19064123Skato printf("Zone lengths and types may vary\n"); 19164123Skato break; 19264123Skato case SRZ_SAME_ALL_SAME: 19364123Skato printf("Zone lengths and types are all the same\n"); 19464123Skato break; 19564123Skato case SRZ_SAME_LAST_DIFFERENT: 19664123Skato printf("Zone types are the same, last zone length " 19764123Skato "differs\n"); 19864123Skato break; 19964123Skato case SRZ_SAME_TYPES_DIFFERENT: 20064123Skato printf("Zone lengths are the same, types vary\n"); 20164123Skato break; 20264123Skato default: 20364123Skato printf("Unknown SAME field value %#x\n", 20464123Skato hdr->byte4 & SRZ_SAME_MASK); 20564123Skato break; 20664123Skato } 20764123Skato } 20864123Skato if (out_flags == ZONE_OF_SUMMARY) { 20964123Skato status = ZONE_PRINT_OK; 21064123Skato goto bailout; 21164123Skato } 21264123Skato 21364123Skato if ((out_flags == ZONE_OF_NORMAL) 21464123Skato && (first_pass != 0)) { 21564123Skato printf("%*s %*s %*s %*s %*s %*s %*s\n", 21664123Skato field_widths[ZONE_FW_START], "Start LBA", 21764123Skato field_widths[ZONE_FW_LEN], "Length", 21864123Skato field_widths[ZONE_FW_WP], "WP LBA", 21964123Skato field_widths[ZONE_FW_TYPE], "Zone Type", 22064123Skato field_widths[ZONE_FW_COND], "Condition", 22164123Skato field_widths[ZONE_FW_SEQ], "Sequential", 22264123Skato field_widths[ZONE_FW_RESET], "Reset"); 22364123Skato } 22464123Skato 22564123Skato for (desc = &hdr->desc_list[0]; len >= sizeof(*desc); 22664123Skato len -= sizeof(*desc), desc++) { 22764123Skato uint64_t length, start_lba, wp_lba; 22864123Skato 22964123Skato if (ata_format == 0) { 23064123Skato length = scsi_8btou64(desc->zone_length); 23164123Skato start_lba = scsi_8btou64(desc->zone_start_lba); 23264123Skato wp_lba = scsi_8btou64(desc->write_pointer_lba); 23364123Skato } else { 23464123Skato length = le64dec(desc->zone_length); 23564123Skato start_lba = le64dec(desc->zone_start_lba); 23664123Skato wp_lba = le64dec(desc->write_pointer_lba); 23764123Skato } 23864123Skato 23964123Skato printf("%#*jx, %*ju, %#*jx, ", field_widths[ZONE_FW_START], 24064123Skato (uintmax_t)start_lba, field_widths[ZONE_FW_LEN], 24164123Skato (uintmax_t)length, field_widths[ZONE_FW_WP], 24264123Skato (uintmax_t)wp_lba); 24364123Skato 24464123Skato switch (desc->zone_type & SRZ_TYPE_MASK) { 24564123Skato case SRZ_TYPE_CONVENTIONAL: 24664123Skato snprintf(tmpstr, sizeof(tmpstr), "Conventional"); 24764123Skato break; 24864123Skato case SRZ_TYPE_SEQ_PREFERRED: 24964123Skato case SRZ_TYPE_SEQ_REQUIRED: 25064123Skato snprintf(tmpstr, sizeof(tmpstr), "Seq%c%s", 25164123Skato word_sep, ((desc->zone_type & SRZ_TYPE_MASK) == 25264123Skato SRZ_TYPE_SEQ_PREFERRED) ? "Preferred" : 25364123Skato "Required"); 25464123Skato break; 25564123Skato default: 25664123Skato snprintf(tmpstr, sizeof(tmpstr), "Zone%ctype%c%#x", 25764123Skato word_sep, word_sep,desc->zone_type & 25864123Skato SRZ_TYPE_MASK); 25964123Skato break; 26064123Skato } 26164123Skato printf("%*s, ", field_widths[ZONE_FW_TYPE], tmpstr); 26264123Skato 26364123Skato switch (desc->zone_flags & SRZ_ZONE_COND_MASK) { 26464123Skato case SRZ_ZONE_COND_NWP: 26564123Skato snprintf(tmpstr, sizeof(tmpstr), "NWP"); 26664123Skato break; 26764123Skato case SRZ_ZONE_COND_EMPTY: 26864123Skato snprintf(tmpstr, sizeof(tmpstr), "Empty"); 26964123Skato break; 27064123Skato case SRZ_ZONE_COND_IMP_OPEN: 27164123Skato snprintf(tmpstr, sizeof(tmpstr), "Implicit%cOpen", 27264123Skato word_sep); 27364123Skato break; 27464123Skato case SRZ_ZONE_COND_EXP_OPEN: 27564123Skato snprintf(tmpstr, sizeof(tmpstr), "Explicit%cOpen", 27664123Skato word_sep); 27764123Skato break; 27864123Skato case SRZ_ZONE_COND_CLOSED: 27964123Skato snprintf(tmpstr, sizeof(tmpstr), "Closed"); 28064123Skato break; 28164123Skato case SRZ_ZONE_COND_READONLY: 28264123Skato snprintf(tmpstr, sizeof(tmpstr), "Readonly"); 28364123Skato break; 28464123Skato case SRZ_ZONE_COND_FULL: 28564123Skato snprintf(tmpstr, sizeof(tmpstr), "Full"); 28664123Skato break; 28764123Skato case SRZ_ZONE_COND_OFFLINE: 28864123Skato snprintf(tmpstr, sizeof(tmpstr), "Offline"); 28964123Skato break; 29064123Skato default: 29164123Skato snprintf(tmpstr, sizeof(tmpstr), "%#x", 29264123Skato desc->zone_flags & SRZ_ZONE_COND_MASK); 29364123Skato break; 29464123Skato } 29564123Skato 29664123Skato printf("%*s, ", field_widths[ZONE_FW_COND], tmpstr); 29764123Skato 29864123Skato if (desc->zone_flags & SRZ_ZONE_NON_SEQ) 29964123Skato snprintf(tmpstr, sizeof(tmpstr), "Non%cSequential", 30064123Skato word_sep); 30164123Skato else 302168457Skato snprintf(tmpstr, sizeof(tmpstr), "Sequential"); 303168457Skato 304168457Skato printf("%*s, ", field_widths[ZONE_FW_SEQ], tmpstr); 305168457Skato 306168457Skato if (desc->zone_flags & SRZ_ZONE_RESET) 30764123Skato snprintf(tmpstr, sizeof(tmpstr), "Reset%cNeeded", 30864123Skato word_sep); 30964123Skato else 31064123Skato snprintf(tmpstr, sizeof(tmpstr), "No%cReset%cNeeded", 31164123Skato word_sep, word_sep); 31264123Skato 31364123Skato printf("%*s\n", field_widths[ZONE_FW_RESET], tmpstr); 31464123Skato 31564123Skato next_lba = start_lba + length; 31664123Skato } 31764123Skatobailout: 31864123Skato *next_start_lba = next_lba; 31964123Skato 32064123Skato return (status); 32164123Skato} 32264123Skato 32364123Skatoint 32464123Skatozone(struct cam_device *device, int argc, char **argv, char *combinedopt, 32564123Skato int task_attr, int retry_count, int timeout, int verbosemode __unused) 32664123Skato{ 32764123Skato union ccb *ccb = NULL; 32864123Skato int action = -1, rep_option = -1; 32964123Skato int all_zones = 0; 33064123Skato uint64_t lba = 0; 33164123Skato int error = 0; 33264123Skato uint8_t *data_ptr = NULL; 33364123Skato uint32_t alloc_len = 65536, valid_len = 0; 33464123Skato camcontrol_devtype devtype; 33564123Skato int ata_format = 0, use_ncq = 0; 33664123Skato int first_pass = 1; 33764123Skato zone_print_status zp_status; 33864123Skato zone_output_flags out_flags = ZONE_OF_NORMAL; 33964123Skato uint8_t *cdb_storage = NULL; 34064123Skato int cdb_storage_len = 32; 34164123Skato int c; 34264123Skato 34364123Skato ccb = cam_getccb(device); 34464123Skato if (ccb == NULL) { 34564123Skato warnx("%s: error allocating CCB", __func__); 34664123Skato error = 1; 34764123Skato goto bailout; 34864123Skato } 34964123Skato 35064123Skato CCB_CLEAR_ALL_EXCEPT_HDR(ccb); 35164123Skato 35264123Skato while ((c = getopt(argc, argv, combinedopt)) != -1) { 35364123Skato switch (c) { 35464123Skato case 'a': 35564123Skato all_zones = 1; 35664123Skato break; 35764123Skato case 'c': { 35864123Skato scsi_nv_status status; 35964123Skato int entry_num; 36064123Skato 36164123Skato status = scsi_get_nv(zone_cmd_map, 36264123Skato (sizeof(zone_cmd_map) / sizeof(zone_cmd_map[0])), 36364123Skato optarg, &entry_num, SCSI_NV_FLAG_IG_CASE); 36464123Skato if (status == SCSI_NV_FOUND) 36564123Skato action = zone_cmd_map[entry_num].value; 36664123Skato else { 36764123Skato warnx("%s: %s: %s option %s", __func__, 36864123Skato (status == SCSI_NV_AMBIGUOUS) ? 36964123Skato "ambiguous" : "invalid", "zone command", 37064123Skato optarg); 37164123Skato error = 1; 37264123Skato goto bailout; 37364123Skato } 37464123Skato break; 37564123Skato } 37664123Skato case 'l': { 37764123Skato char *endptr; 37864123Skato 37964123Skato lba = strtoull(optarg, &endptr, 0); 38064123Skato if (*endptr != '\0') { 38164123Skato warnx("%s: invalid lba argument %s", __func__, 38264123Skato optarg); 38364123Skato error = 1; 38464123Skato goto bailout; 38564123Skato } 38664123Skato break; 38764123Skato } 38864123Skato case 'N': 38964123Skato use_ncq = 1; 39064123Skato break; 39164123Skato case 'o': { 39264123Skato scsi_nv_status status; 39364123Skato int entry_num; 39464123Skato 39564123Skato status = scsi_get_nv(zone_rep_opts, 39664123Skato (sizeof(zone_rep_opts) /sizeof(zone_rep_opts[0])), 39764123Skato optarg, &entry_num, SCSI_NV_FLAG_IG_CASE); 39864123Skato if (status == SCSI_NV_FOUND) 39964123Skato rep_option = zone_rep_opts[entry_num].value; 40064123Skato else { 40164123Skato warnx("%s: %s: %s option %s", __func__, 40264123Skato (status == SCSI_NV_AMBIGUOUS) ? 40364123Skato "ambiguous" : "invalid", "report zones", 40464123Skato optarg); 40564123Skato error = 1; 40664123Skato goto bailout; 40764123Skato } 40864123Skato break; 40964123Skato } 41064123Skato case 'P': { 41164123Skato scsi_nv_status status; 41264123Skato int entry_num; 41364123Skato 41464123Skato status = scsi_get_nv(zone_print_opts, 41564123Skato (sizeof(zone_print_opts) / 41664123Skato sizeof(zone_print_opts[0])), optarg, &entry_num, 41764123Skato SCSI_NV_FLAG_IG_CASE); 41864123Skato if (status == SCSI_NV_FOUND) 41964123Skato out_flags = zone_print_opts[entry_num].value; 42064123Skato else { 42164123Skato warnx("%s: %s: %s option %s", __func__, 42264123Skato (status == SCSI_NV_AMBIGUOUS) ? 42364123Skato "ambiguous" : "invalid", "print", 42464123Skato optarg); 42564295Skato error = 1; 42664123Skato goto bailout; 42764123Skato } 42864123Skato break; 42964123Skato } 43064123Skato default: 43164123Skato break; 43264123Skato } 43364123Skato } 43464123Skato if (action == -1) { 43564123Skato warnx("%s: must specify -c <zone_cmd>", __func__); 43664123Skato error = 1; 43764123Skato goto bailout; 43864123Skato } 43964123Skato error = get_device_type(device, retry_count, timeout, 44064123Skato /*printerrors*/ 1, &devtype); 44164123Skato if (error != 0) 44264123Skato errx(1, "Unable to determine device type"); 44364123Skato 44464123Skato if (action == ZBC_IN_SA_REPORT_ZONES) { 44564123Skato 44664123Skato data_ptr = malloc(alloc_len); 44764123Skato if (data_ptr == NULL) 44864123Skato err(1, "unable to allocate %u bytes", alloc_len); 44964123Skato 45064123Skatorestart_report: 451 bzero(data_ptr, alloc_len); 452 453 switch (devtype) { 454 case CC_DT_SCSI: 455 scsi_zbc_in(&ccb->csio, 456 /*retries*/ retry_count, 457 /*cbfcnp*/ NULL, 458 /*tag_action*/ task_attr, 459 /*service_action*/ action, 460 /*zone_start_lba*/ lba, 461 /*zone_options*/ (rep_option != -1) ? 462 rep_option : 0, 463 /*data_ptr*/ data_ptr, 464 /*dxfer_len*/ alloc_len, 465 /*sense_len*/ SSD_FULL_SIZE, 466 /*timeout*/ timeout ? timeout : 60000); 467 break; 468 case CC_DT_ATA: 469 case CC_DT_ATA_BEHIND_SCSI: { 470 uint8_t command = 0; 471 uint8_t protocol = 0; 472 uint16_t features = 0, sector_count = 0; 473 uint32_t auxiliary = 0; 474 475 /* 476 * XXX KDM support the partial bit? 477 */ 478 if (use_ncq == 0) { 479 command = ATA_ZAC_MANAGEMENT_IN; 480 features = action; 481 if (rep_option != -1) 482 features |= (rep_option << 8); 483 sector_count = ZAC_ATA_SECTOR_COUNT(alloc_len); 484 protocol = AP_PROTO_DMA; 485 } else { 486 if (cdb_storage == NULL) 487 cdb_storage = calloc(cdb_storage_len, 1); 488 if (cdb_storage == NULL) 489 err(1, "couldn't allocate memory"); 490 491 command = ATA_RECV_FPDMA_QUEUED; 492 features = ZAC_ATA_SECTOR_COUNT(alloc_len); 493 sector_count = ATA_RFPDMA_ZAC_MGMT_IN << 8; 494 auxiliary = action & 0xf; 495 if (rep_option != -1) 496 auxiliary |= rep_option << 8; 497 protocol = AP_PROTO_FPDMA; 498 } 499 500 error = build_ata_cmd(ccb, 501 /*retry_count*/ retry_count, 502 /*flags*/ CAM_DIR_IN | CAM_DEV_QFRZDIS, 503 /*tag_action*/ task_attr, 504 /*protocol*/ protocol, 505 /*ata_flags*/ AP_FLAG_BYT_BLOK_BLOCKS | 506 AP_FLAG_TLEN_SECT_CNT | 507 AP_FLAG_TDIR_FROM_DEV, 508 /*features*/ features, 509 /*sector_count*/ sector_count, 510 /*lba*/ lba, 511 /*command*/ command, 512 /*auxiliary*/ auxiliary, 513 /*data_ptr*/ data_ptr, 514 /*dxfer_len*/ ZAC_ATA_SECTOR_COUNT(alloc_len)*512, 515 /*cdb_storage*/ cdb_storage, 516 /*cdb_storage_len*/ cdb_storage_len, 517 /*sense_len*/ SSD_FULL_SIZE, 518 /*timeout*/ timeout ? timeout : 60000, 519 /*is48bit*/ 1, 520 /*devtype*/ devtype); 521 522 if (error != 0) { 523 warnx("%s: build_ata_cmd() failed, likely " 524 "programmer error", __func__); 525 goto bailout; 526 } 527 528 ata_format = 1; 529 530 break; 531 } 532 default: 533 warnx("%s: Unknown device type %d", __func__,devtype); 534 error = 1; 535 goto bailout; 536 break; /*NOTREACHED*/ 537 } 538 } else { 539 /* 540 * XXX KDM the current methodology is to always send ATA 541 * commands to ATA devices. Need to figure out how to 542 * detect whether a SCSI to ATA translation layer will 543 * translate ZBC IN/OUT commands to the appropriate ZAC 544 * command. 545 */ 546 switch (devtype) { 547 case CC_DT_SCSI: 548 scsi_zbc_out(&ccb->csio, 549 /*retries*/ retry_count, 550 /*cbfcnp*/ NULL, 551 /*tag_action*/ task_attr, 552 /*service_action*/ action, 553 /*zone_id*/ lba, 554 /*zone_flags*/ (all_zones != 0) ? ZBC_OUT_ALL : 0, 555 /*data_ptr*/ NULL, 556 /*dxfer_len*/ 0, 557 /*sense_len*/ SSD_FULL_SIZE, 558 /*timeout*/ timeout ? timeout : 60000); 559 break; 560 case CC_DT_ATA: 561 case CC_DT_ATA_BEHIND_SCSI: { 562 uint8_t command = 0; 563 uint8_t protocol = 0; 564 uint16_t features = 0, sector_count = 0; 565 uint32_t auxiliary = 0; 566 567 /* 568 * Note that we're taking advantage of the fact 569 * that the action numbers are the same between the 570 * ZBC and ZAC specs. 571 */ 572 573 if (use_ncq == 0) { 574 protocol = AP_PROTO_NON_DATA; 575 command = ATA_ZAC_MANAGEMENT_OUT; 576 features = action & 0xf; 577 if (all_zones != 0) 578 features |= (ZBC_OUT_ALL << 8); 579 } else { 580 cdb_storage = calloc(cdb_storage_len, 1); 581 if (cdb_storage == NULL) 582 err(1, "couldn't allocate memory"); 583 584 protocol = AP_PROTO_FPDMA; 585 command = ATA_NCQ_NON_DATA; 586 features = ATA_NCQ_ZAC_MGMT_OUT; 587 auxiliary = action & 0xf; 588 if (all_zones != 0) 589 auxiliary |= (ZBC_OUT_ALL << 8); 590 } 591 592 593 error = build_ata_cmd(ccb, 594 /*retry_count*/ retry_count, 595 /*flags*/ CAM_DIR_NONE | CAM_DEV_QFRZDIS, 596 /*tag_action*/ task_attr, 597 /*protocol*/ AP_PROTO_NON_DATA, 598 /*ata_flags*/ AP_FLAG_BYT_BLOK_BYTES | 599 AP_FLAG_TLEN_NO_DATA, 600 /*features*/ features, 601 /*sector_count*/ sector_count, 602 /*lba*/ lba, 603 /*command*/ command, 604 /*auxiliary*/ auxiliary, 605 /*data_ptr*/ NULL, 606 /*dxfer_len*/ 0, 607 /*cdb_storage*/ cdb_storage, 608 /*cdb_storage_len*/ cdb_storage_len, 609 /*sense_len*/ SSD_FULL_SIZE, 610 /*timeout*/ timeout ? timeout : 60000, 611 /*is48bit*/ 1, 612 /*devtype*/ devtype); 613 if (error != 0) { 614 warnx("%s: build_ata_cmd() failed, likely " 615 "programmer error", __func__); 616 goto bailout; 617 } 618 ata_format = 1; 619 break; 620 } 621 default: 622 warnx("%s: Unknown device type %d", __func__,devtype); 623 error = 1; 624 goto bailout; 625 break; /*NOTREACHED*/ 626 } 627 } 628 629 ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 630 if (retry_count > 0) 631 ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 632 633 error = cam_send_ccb(device, ccb); 634 if (error != 0) { 635 warn("error sending %s %s CCB", (devtype == CC_DT_SCSI) ? 636 "ZBC" : "ZAC Management", 637 (action == ZBC_IN_SA_REPORT_ZONES) ? "In" : "Out"); 638 error = -1; 639 goto bailout; 640 } 641 642 if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 643 cam_error_print(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL,stderr); 644 error = 1; 645 goto bailout; 646 } 647 648 /* 649 * If we aren't reading the list of zones, we're done. 650 */ 651 if (action != ZBC_IN_SA_REPORT_ZONES) 652 goto bailout; 653 654 if (ccb->ccb_h.func_code == XPT_SCSI_IO) 655 valid_len = ccb->csio.dxfer_len - ccb->csio.resid; 656 else 657 valid_len = ccb->ataio.dxfer_len - ccb->ataio.resid; 658 659 zp_status = zone_rz_print(data_ptr, valid_len, ata_format, out_flags, 660 first_pass, &lba); 661 662 if (zp_status == ZONE_PRINT_MORE_DATA) { 663 bzero(ccb, sizeof(*ccb)); 664 first_pass = 0; 665 if (cdb_storage != NULL) 666 bzero(cdb_storage, cdb_storage_len); 667 goto restart_report; 668 } else if (zp_status == ZONE_PRINT_ERROR) 669 error = 1; 670bailout: 671 if (ccb != NULL) 672 cam_freeccb(ccb); 673 674 free(data_ptr); 675 free(cdb_storage); 676 677 return (error); 678} 679