1 /*- 2 * Copyright (c) 2015, 2016 Spectra Logic Corporation 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions, and the following disclaimer, 10 * without modification. 11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12 * substantially similar to the "NO WARRANTY" disclaimer below 13 * ("Disclaimer") and any redistribution must be conditioned upon 14 * including a substantially similar Disclaimer requirement for further 15 * binary redistribution. 16 * 17 * NO WARRANTY 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 27 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGES. 29 * 30 * Authors: Ken Merry (Spectra Logic Corporation) 31 */ 32 /* 33 * SCSI and ATA Shingled Media Recording (SMR) support for camcontrol(8). 34 * This is an implementation of the SCSI ZBC and ATA ZAC specs. 35 */ 36 37 #include <sys/param.h> 38 #include <sys/ioctl.h> 39 #include <sys/stdint.h> 40 #include <sys/endian.h> 41 #include <sys/sbuf.h> 42 #include <sys/queue.h> 43 #include <sys/chio.h> 44 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <inttypes.h> 48 #include <unistd.h> 49 #include <string.h> 50 #include <strings.h> 51 #include <fcntl.h> 52 #include <ctype.h> 53 #include <limits.h> 54 #include <err.h> 55 #include <locale.h> 56 57 #include <cam/cam.h> 58 #include <cam/cam_debug.h> 59 #include <cam/cam_ccb.h> 60 #include <cam/scsi/scsi_all.h> 61 #include <cam/scsi/scsi_da.h> 62 #include <cam/scsi/scsi_pass.h> 63 #include <cam/scsi/scsi_ch.h> 64 #include <cam/scsi/scsi_message.h> 65 #include <camlib.h> 66 #include "camcontrol.h" 67 68 static struct scsi_nv zone_cmd_map[] = { 69 { "rz", ZBC_IN_SA_REPORT_ZONES }, 70 { "reportzones", ZBC_IN_SA_REPORT_ZONES }, 71 { "close", ZBC_OUT_SA_CLOSE }, 72 { "finish", ZBC_OUT_SA_FINISH }, 73 { "open", ZBC_OUT_SA_OPEN }, 74 { "rwp", ZBC_OUT_SA_RWP } 75 }; 76 77 static struct scsi_nv zone_rep_opts[] = { 78 { "all", ZBC_IN_REP_ALL_ZONES }, 79 { "empty", ZBC_IN_REP_EMPTY }, 80 { "imp_open", ZBC_IN_REP_IMP_OPEN }, 81 { "exp_open", ZBC_IN_REP_EXP_OPEN }, 82 { "closed", ZBC_IN_REP_CLOSED }, 83 { "full", ZBC_IN_REP_FULL }, 84 { "readonly", ZBC_IN_REP_READONLY }, 85 { "ro", ZBC_IN_REP_READONLY }, 86 { "offline", ZBC_IN_REP_OFFLINE }, 87 { "rwp", ZBC_IN_REP_RESET }, 88 { "reset", ZBC_IN_REP_RESET }, 89 { "nonseq", ZBC_IN_REP_NON_SEQ }, 90 { "nonwp", ZBC_IN_REP_NON_WP } 91 }; 92 93 typedef enum { 94 ZONE_OF_NORMAL = 0x00, 95 ZONE_OF_SUMMARY = 0x01, 96 ZONE_OF_SCRIPT = 0x02 97 } zone_output_flags; 98 99 static struct scsi_nv zone_print_opts[] = { 100 { "normal", ZONE_OF_NORMAL }, 101 { "summary", ZONE_OF_SUMMARY }, 102 { "script", ZONE_OF_SCRIPT } 103 }; 104 105 #define ZAC_ATA_SECTOR_COUNT(bcount) (((bcount) / 512) & 0xffff) 106 107 typedef enum { 108 ZONE_PRINT_OK, 109 ZONE_PRINT_MORE_DATA, 110 ZONE_PRINT_ERROR 111 } zone_print_status; 112 113 typedef enum { 114 ZONE_FW_START, 115 ZONE_FW_LEN, 116 ZONE_FW_WP, 117 ZONE_FW_TYPE, 118 ZONE_FW_COND, 119 ZONE_FW_SEQ, 120 ZONE_FW_RESET, 121 ZONE_NUM_FIELDS 122 } zone_field_widths; 123 124 zone_print_status zone_rz_print(uint8_t *data_ptr, uint32_t valid_len, 125 int ata_format, zone_output_flags out_flags, 126 int first_pass, uint64_t *next_start_lba); 127 128 129 zone_print_status 130 zone_rz_print(uint8_t *data_ptr, uint32_t valid_len, int ata_format, 131 zone_output_flags out_flags, int first_pass, 132 uint64_t *next_start_lba) 133 { 134 struct scsi_report_zones_hdr *hdr = NULL; 135 struct scsi_report_zones_desc *desc = NULL; 136 uint32_t hdr_len, len; 137 uint64_t max_lba, next_lba = 0; 138 zone_print_status status = ZONE_PRINT_OK; 139 char tmpstr[80]; 140 int field_widths[ZONE_NUM_FIELDS]; 141 char word_sep; 142 143 if (valid_len < sizeof(*hdr)) { 144 status = ZONE_PRINT_ERROR; 145 goto bailout; 146 } 147 148 hdr = (struct scsi_report_zones_hdr *)data_ptr; 149 150 field_widths[ZONE_FW_START] = 11; 151 field_widths[ZONE_FW_LEN] = 6; 152 field_widths[ZONE_FW_WP] = 11; 153 field_widths[ZONE_FW_TYPE] = 13; 154 field_widths[ZONE_FW_COND] = 13; 155 field_widths[ZONE_FW_SEQ] = 14; 156 field_widths[ZONE_FW_RESET] = 16; 157 158 if (ata_format == 0) { 159 hdr_len = scsi_4btoul(hdr->length); 160 max_lba = scsi_8btou64(hdr->maximum_lba); 161 } else { 162 hdr_len = le32dec(hdr->length); 163 max_lba = le64dec(hdr->maximum_lba); 164 } 165 166 if (hdr_len > (valid_len + sizeof(*hdr))) { 167 status = ZONE_PRINT_MORE_DATA; 168 } 169 170 len = MIN(valid_len - sizeof(*hdr), hdr_len); 171 172 if (out_flags == ZONE_OF_SCRIPT) 173 word_sep = '_'; 174 else 175 word_sep = ' '; 176 177 if ((out_flags != ZONE_OF_SCRIPT) 178 && (first_pass != 0)) { 179 printf("%zu zones, Maximum LBA %#jx (%ju)\n", 180 hdr_len / sizeof(*desc), (uintmax_t)max_lba, 181 (uintmax_t)max_lba); 182 183 switch (hdr->byte4 & SRZ_SAME_MASK) { 184 case SRZ_SAME_ALL_DIFFERENT: 185 printf("Zone lengths and types may vary\n"); 186 break; 187 case SRZ_SAME_ALL_SAME: 188 printf("Zone lengths and types are all the same\n"); 189 break; 190 case SRZ_SAME_LAST_DIFFERENT: 191 printf("Zone types are the same, last zone length " 192 "differs\n"); 193 break; 194 case SRZ_SAME_TYPES_DIFFERENT: 195 printf("Zone lengths are the same, types vary\n"); 196 break; 197 default: 198 printf("Unknown SAME field value %#x\n", 199 hdr->byte4 & SRZ_SAME_MASK); 200 break; 201 } 202 } 203 if (out_flags == ZONE_OF_SUMMARY) { 204 status = ZONE_PRINT_OK; 205 goto bailout; 206 } 207 208 if ((out_flags == ZONE_OF_NORMAL) 209 && (first_pass != 0)) { 210 printf("%*s %*s %*s %*s %*s %*s %*s\n", 211 field_widths[ZONE_FW_START], "Start LBA", 212 field_widths[ZONE_FW_LEN], "Length", 213 field_widths[ZONE_FW_WP], "WP LBA", 214 field_widths[ZONE_FW_TYPE], "Zone Type", 215 field_widths[ZONE_FW_COND], "Condition", 216 field_widths[ZONE_FW_SEQ], "Sequential", 217 field_widths[ZONE_FW_RESET], "Reset"); 218 } 219 220 for (desc = &hdr->desc_list[0]; len >= sizeof(*desc); 221 len -= sizeof(*desc), desc++) { 222 uint64_t length, start_lba, wp_lba; 223 224 if (ata_format == 0) { 225 length = scsi_8btou64(desc->zone_length); 226 start_lba = scsi_8btou64(desc->zone_start_lba); 227 wp_lba = scsi_8btou64(desc->write_pointer_lba); 228 } else { 229 length = le64dec(desc->zone_length); 230 start_lba = le64dec(desc->zone_start_lba); 231 wp_lba = le64dec(desc->write_pointer_lba); 232 } 233 234 printf("%#*jx, %*ju, %#*jx, ", field_widths[ZONE_FW_START], 235 (uintmax_t)start_lba, field_widths[ZONE_FW_LEN], 236 (uintmax_t)length, field_widths[ZONE_FW_WP], 237 (uintmax_t)wp_lba); 238 239 switch (desc->zone_type & SRZ_TYPE_MASK) { 240 case SRZ_TYPE_CONVENTIONAL: 241 snprintf(tmpstr, sizeof(tmpstr), "Conventional"); 242 break; 243 case SRZ_TYPE_SEQ_PREFERRED: 244 case SRZ_TYPE_SEQ_REQUIRED: 245 snprintf(tmpstr, sizeof(tmpstr), "Seq%c%s", 246 word_sep, ((desc->zone_type & SRZ_TYPE_MASK) == 247 SRZ_TYPE_SEQ_PREFERRED) ? "Preferred" : 248 "Required"); 249 break; 250 default: 251 snprintf(tmpstr, sizeof(tmpstr), "Zone%ctype%c%#x", 252 word_sep, word_sep,desc->zone_type & 253 SRZ_TYPE_MASK); 254 break; 255 } 256 printf("%*s, ", field_widths[ZONE_FW_TYPE], tmpstr); 257 258 switch (desc->zone_flags & SRZ_ZONE_COND_MASK) { 259 case SRZ_ZONE_COND_NWP: 260 snprintf(tmpstr, sizeof(tmpstr), "NWP"); 261 break; 262 case SRZ_ZONE_COND_EMPTY: 263 snprintf(tmpstr, sizeof(tmpstr), "Empty"); 264 break; 265 case SRZ_ZONE_COND_IMP_OPEN: 266 snprintf(tmpstr, sizeof(tmpstr), "Implicit%cOpen", 267 word_sep); 268 break; 269 case SRZ_ZONE_COND_EXP_OPEN: 270 snprintf(tmpstr, sizeof(tmpstr), "Explicit%cOpen", 271 word_sep); 272 break; 273 case SRZ_ZONE_COND_CLOSED: 274 snprintf(tmpstr, sizeof(tmpstr), "Closed"); 275 break; 276 case SRZ_ZONE_COND_READONLY: 277 snprintf(tmpstr, sizeof(tmpstr), "Readonly"); 278 break; 279 case SRZ_ZONE_COND_FULL: 280 snprintf(tmpstr, sizeof(tmpstr), "Full"); 281 break; 282 case SRZ_ZONE_COND_OFFLINE: 283 snprintf(tmpstr, sizeof(tmpstr), "Offline"); 284 break; 285 default: 286 snprintf(tmpstr, sizeof(tmpstr), "%#x", 287 desc->zone_flags & SRZ_ZONE_COND_MASK); 288 break; 289 } 290 291 printf("%*s, ", field_widths[ZONE_FW_COND], tmpstr); 292 293 if (desc->zone_flags & SRZ_ZONE_NON_SEQ) 294 snprintf(tmpstr, sizeof(tmpstr), "Non%cSequential", 295 word_sep); 296 else 297 snprintf(tmpstr, sizeof(tmpstr), "Sequential"); 298 299 printf("%*s, ", field_widths[ZONE_FW_SEQ], tmpstr); 300 301 if (desc->zone_flags & SRZ_ZONE_RESET) 302 snprintf(tmpstr, sizeof(tmpstr), "Reset%cNeeded", 303 word_sep); 304 else 305 snprintf(tmpstr, sizeof(tmpstr), "No%cReset%cNeeded", 306 word_sep, word_sep); 307 308 printf("%*s\n", field_widths[ZONE_FW_RESET], tmpstr); 309 310 next_lba = start_lba + length; 311 } 312 bailout: 313 *next_start_lba = next_lba; 314 315 return (status); 316 } 317 318 int 319 zone(struct cam_device *device, int argc, char **argv, char *combinedopt, 320 int task_attr, int retry_count, int timeout, int verbosemode __unused) 321 { 322 union ccb *ccb = NULL; 323 int action = -1, rep_option = -1; 324 int all_zones = 0; 325 uint64_t lba = 0; 326 int error = 0; 327 uint8_t *data_ptr = NULL; 328 uint32_t alloc_len = 65536, valid_len = 0; 329 camcontrol_devtype devtype; 330 int ata_format = 0, use_ncq = 0; 331 int first_pass = 1; 332 zone_print_status zp_status; 333 zone_output_flags out_flags = ZONE_OF_NORMAL; 334 uint8_t *cdb_storage = NULL; 335 int cdb_storage_len = 32; 336 int c; 337 338 ccb = cam_getccb(device); 339 if (ccb == NULL) { 340 warnx("%s: error allocating CCB", __func__); 341 error = 1; 342 goto bailout; 343 } 344 345 while ((c = getopt(argc, argv, combinedopt)) != -1) { 346 switch (c) { 347 case 'a': 348 all_zones = 1; 349 break; 350 case 'c': { 351 scsi_nv_status status; 352 int entry_num; 353 354 status = scsi_get_nv(zone_cmd_map, 355 nitems(zone_cmd_map), 356 optarg, &entry_num, SCSI_NV_FLAG_IG_CASE); 357 if (status == SCSI_NV_FOUND) 358 action = zone_cmd_map[entry_num].value; 359 else { 360 warnx("%s: %s: %s option %s", __func__, 361 (status == SCSI_NV_AMBIGUOUS) ? 362 "ambiguous" : "invalid", "zone command", 363 optarg); 364 error = 1; 365 goto bailout; 366 } 367 break; 368 } 369 case 'l': { 370 char *endptr; 371 372 lba = strtoull(optarg, &endptr, 0); 373 if (*endptr != '\0') { 374 warnx("%s: invalid lba argument %s", __func__, 375 optarg); 376 error = 1; 377 goto bailout; 378 } 379 break; 380 } 381 case 'N': 382 use_ncq = 1; 383 break; 384 case 'o': { 385 scsi_nv_status status; 386 int entry_num; 387 388 status = scsi_get_nv(zone_rep_opts, 389 nitems(zone_rep_opts), 390 optarg, &entry_num, SCSI_NV_FLAG_IG_CASE); 391 if (status == SCSI_NV_FOUND) 392 rep_option = zone_rep_opts[entry_num].value; 393 else { 394 warnx("%s: %s: %s option %s", __func__, 395 (status == SCSI_NV_AMBIGUOUS) ? 396 "ambiguous" : "invalid", "report zones", 397 optarg); 398 error = 1; 399 goto bailout; 400 } 401 break; 402 } 403 case 'P': { 404 scsi_nv_status status; 405 int entry_num; 406 407 status = scsi_get_nv(zone_print_opts, 408 (sizeof(zone_print_opts) / 409 sizeof(zone_print_opts[0])), optarg, &entry_num, 410 SCSI_NV_FLAG_IG_CASE); 411 if (status == SCSI_NV_FOUND) 412 out_flags = zone_print_opts[entry_num].value; 413 else { 414 warnx("%s: %s: %s option %s", __func__, 415 (status == SCSI_NV_AMBIGUOUS) ? 416 "ambiguous" : "invalid", "print", 417 optarg); 418 error = 1; 419 goto bailout; 420 } 421 break; 422 } 423 default: 424 break; 425 } 426 } 427 if (action == -1) { 428 warnx("%s: must specify -c <zone_cmd>", __func__); 429 error = 1; 430 goto bailout; 431 } 432 error = get_device_type(device, retry_count, timeout, 433 /*printerrors*/ 1, &devtype); 434 if (error != 0) 435 errx(1, "Unable to determine device type"); 436 437 if (action == ZBC_IN_SA_REPORT_ZONES) { 438 439 data_ptr = malloc(alloc_len); 440 if (data_ptr == NULL) 441 err(1, "unable to allocate %u bytes", alloc_len); 442 443 restart_report: 444 bzero(data_ptr, alloc_len); 445 446 switch (devtype) { 447 case CC_DT_SCSI: 448 scsi_zbc_in(&ccb->csio, 449 /*retries*/ retry_count, 450 /*cbfcnp*/ NULL, 451 /*tag_action*/ task_attr, 452 /*service_action*/ action, 453 /*zone_start_lba*/ lba, 454 /*zone_options*/ (rep_option != -1) ? 455 rep_option : 0, 456 /*data_ptr*/ data_ptr, 457 /*dxfer_len*/ alloc_len, 458 /*sense_len*/ SSD_FULL_SIZE, 459 /*timeout*/ timeout ? timeout : 60000); 460 break; 461 case CC_DT_ATA: 462 case CC_DT_SATL: { 463 uint8_t command = 0; 464 uint8_t protocol = 0; 465 uint16_t features = 0, sector_count = 0; 466 uint32_t auxiliary = 0; 467 468 /* 469 * XXX KDM support the partial bit? 470 */ 471 if (use_ncq == 0) { 472 command = ATA_ZAC_MANAGEMENT_IN; 473 features = action; 474 if (rep_option != -1) 475 features |= (rep_option << 8); 476 sector_count = ZAC_ATA_SECTOR_COUNT(alloc_len); 477 protocol = AP_PROTO_DMA; 478 } else { 479 if (cdb_storage == NULL) 480 cdb_storage = calloc(cdb_storage_len, 1); 481 if (cdb_storage == NULL) 482 err(1, "couldn't allocate memory"); 483 484 command = ATA_RECV_FPDMA_QUEUED; 485 features = ZAC_ATA_SECTOR_COUNT(alloc_len); 486 sector_count = ATA_RFPDMA_ZAC_MGMT_IN << 8; 487 auxiliary = action & 0xf; 488 if (rep_option != -1) 489 auxiliary |= rep_option << 8; 490 protocol = AP_PROTO_FPDMA; 491 } 492 493 error = build_ata_cmd(ccb, 494 /*retry_count*/ retry_count, 495 /*flags*/ CAM_DIR_IN | CAM_DEV_QFRZDIS, 496 /*tag_action*/ task_attr, 497 /*protocol*/ protocol, 498 /*ata_flags*/ AP_FLAG_BYT_BLOK_BLOCKS | 499 AP_FLAG_TLEN_SECT_CNT | 500 AP_FLAG_TDIR_FROM_DEV, 501 /*features*/ features, 502 /*sector_count*/ sector_count, 503 /*lba*/ lba, 504 /*command*/ command, 505 /*auxiliary*/ auxiliary, 506 /*data_ptr*/ data_ptr, 507 /*dxfer_len*/ ZAC_ATA_SECTOR_COUNT(alloc_len)*512, 508 /*cdb_storage*/ cdb_storage, 509 /*cdb_storage_len*/ cdb_storage_len, 510 /*sense_len*/ SSD_FULL_SIZE, 511 /*timeout*/ timeout ? timeout : 60000, 512 /*is48bit*/ 1, 513 /*devtype*/ devtype); 514 515 if (error != 0) { 516 warnx("%s: build_ata_cmd() failed, likely " 517 "programmer error", __func__); 518 goto bailout; 519 } 520 521 ata_format = 1; 522 523 break; 524 } 525 default: 526 warnx("%s: Unknown device type %d", __func__,devtype); 527 error = 1; 528 goto bailout; 529 break; /*NOTREACHED*/ 530 } 531 } else { 532 /* 533 * XXX KDM the current methodology is to always send ATA 534 * commands to ATA devices. Need to figure out how to 535 * detect whether a SCSI to ATA translation layer will 536 * translate ZBC IN/OUT commands to the appropriate ZAC 537 * command. 538 */ 539 switch (devtype) { 540 case CC_DT_SCSI: 541 scsi_zbc_out(&ccb->csio, 542 /*retries*/ retry_count, 543 /*cbfcnp*/ NULL, 544 /*tag_action*/ task_attr, 545 /*service_action*/ action, 546 /*zone_id*/ lba, 547 /*zone_flags*/ (all_zones != 0) ? ZBC_OUT_ALL : 0, 548 /*data_ptr*/ NULL, 549 /*dxfer_len*/ 0, 550 /*sense_len*/ SSD_FULL_SIZE, 551 /*timeout*/ timeout ? timeout : 60000); 552 break; 553 case CC_DT_ATA: 554 case CC_DT_SATL: { 555 uint8_t command = 0; 556 uint8_t protocol = 0; 557 uint16_t features = 0, sector_count = 0; 558 uint32_t auxiliary = 0; 559 560 /* 561 * Note that we're taking advantage of the fact 562 * that the action numbers are the same between the 563 * ZBC and ZAC specs. 564 */ 565 566 if (use_ncq == 0) { 567 protocol = AP_PROTO_NON_DATA; 568 command = ATA_ZAC_MANAGEMENT_OUT; 569 features = action & 0xf; 570 if (all_zones != 0) 571 features |= (ZBC_OUT_ALL << 8); 572 } else { 573 cdb_storage = calloc(cdb_storage_len, 1); 574 if (cdb_storage == NULL) 575 err(1, "couldn't allocate memory"); 576 577 protocol = AP_PROTO_FPDMA; 578 command = ATA_NCQ_NON_DATA; 579 features = ATA_NCQ_ZAC_MGMT_OUT; 580 auxiliary = action & 0xf; 581 if (all_zones != 0) 582 auxiliary |= (ZBC_OUT_ALL << 8); 583 } 584 585 586 error = build_ata_cmd(ccb, 587 /*retry_count*/ retry_count, 588 /*flags*/ CAM_DIR_NONE | CAM_DEV_QFRZDIS, 589 /*tag_action*/ task_attr, 590 /*protocol*/ protocol, 591 /*ata_flags*/ AP_FLAG_BYT_BLOK_BYTES | 592 AP_FLAG_TLEN_NO_DATA, 593 /*features*/ features, 594 /*sector_count*/ sector_count, 595 /*lba*/ lba, 596 /*command*/ command, 597 /*auxiliary*/ auxiliary, 598 /*data_ptr*/ NULL, 599 /*dxfer_len*/ 0, 600 /*cdb_storage*/ cdb_storage, 601 /*cdb_storage_len*/ cdb_storage_len, 602 /*sense_len*/ SSD_FULL_SIZE, 603 /*timeout*/ timeout ? timeout : 60000, 604 /*is48bit*/ 1, 605 /*devtype*/ devtype); 606 if (error != 0) { 607 warnx("%s: build_ata_cmd() failed, likely " 608 "programmer error", __func__); 609 goto bailout; 610 } 611 ata_format = 1; 612 break; 613 } 614 default: 615 warnx("%s: Unknown device type %d", __func__,devtype); 616 error = 1; 617 goto bailout; 618 break; /*NOTREACHED*/ 619 } 620 } 621 622 ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 623 if (retry_count > 0) 624 ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 625 626 error = cam_send_ccb(device, ccb); 627 if (error != 0) { 628 warn("error sending %s %s CCB", (devtype == CC_DT_SCSI) ? 629 "ZBC" : "ZAC Management", 630 (action == ZBC_IN_SA_REPORT_ZONES) ? "In" : "Out"); 631 error = -1; 632 goto bailout; 633 } 634 635 if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 636 cam_error_print(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL,stderr); 637 error = 1; 638 goto bailout; 639 } 640 641 /* 642 * If we aren't reading the list of zones, we're done. 643 */ 644 if (action != ZBC_IN_SA_REPORT_ZONES) 645 goto bailout; 646 647 if (ccb->ccb_h.func_code == XPT_SCSI_IO) 648 valid_len = ccb->csio.dxfer_len - ccb->csio.resid; 649 else 650 valid_len = ccb->ataio.dxfer_len - ccb->ataio.resid; 651 652 zp_status = zone_rz_print(data_ptr, valid_len, ata_format, out_flags, 653 first_pass, &lba); 654 655 if (zp_status == ZONE_PRINT_MORE_DATA) { 656 bzero(ccb, sizeof(*ccb)); 657 first_pass = 0; 658 if (cdb_storage != NULL) 659 bzero(cdb_storage, cdb_storage_len); 660 goto restart_report; 661 } else if (zp_status == ZONE_PRINT_ERROR) 662 error = 1; 663 bailout: 664 if (ccb != NULL) 665 cam_freeccb(ccb); 666 667 free(data_ptr); 668 free(cdb_storage); 669 670 return (error); 671 } 672