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/cdefs.h>
38 __FBSDID("$FreeBSD$");
39
40 #include <sys/ioctl.h>
41 #include <sys/stdint.h>
42 #include <sys/types.h>
43 #include <sys/endian.h>
44 #include <sys/sbuf.h>
45 #include <sys/queue.h>
46 #include <sys/chio.h>
47
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <inttypes.h>
51 #include <unistd.h>
52 #include <string.h>
53 #include <strings.h>
54 #include <fcntl.h>
55 #include <ctype.h>
56 #include <limits.h>
57 #include <err.h>
58 #include <locale.h>
59
60 #include <cam/cam.h>
61 #include <cam/cam_debug.h>
62 #include <cam/cam_ccb.h>
63 #include <cam/scsi/scsi_all.h>
64 #include <cam/scsi/scsi_da.h>
65 #include <cam/scsi/scsi_pass.h>
66 #include <cam/scsi/scsi_ch.h>
67 #include <cam/scsi/scsi_message.h>
68 #include <camlib.h>
69 #include "camcontrol.h"
70
71 static struct scsi_nv zone_cmd_map[] = {
72 { "rz", ZBC_IN_SA_REPORT_ZONES },
73 { "reportzones", ZBC_IN_SA_REPORT_ZONES },
74 { "close", ZBC_OUT_SA_CLOSE },
75 { "finish", ZBC_OUT_SA_FINISH },
76 { "open", ZBC_OUT_SA_OPEN },
77 { "rwp", ZBC_OUT_SA_RWP }
78 };
79
80 static struct scsi_nv zone_rep_opts[] = {
81 { "all", ZBC_IN_REP_ALL_ZONES },
82 { "empty", ZBC_IN_REP_EMPTY },
83 { "imp_open", ZBC_IN_REP_IMP_OPEN },
84 { "exp_open", ZBC_IN_REP_EXP_OPEN },
85 { "closed", ZBC_IN_REP_CLOSED },
86 { "full", ZBC_IN_REP_FULL },
87 { "readonly", ZBC_IN_REP_READONLY },
88 { "ro", ZBC_IN_REP_READONLY },
89 { "offline", ZBC_IN_REP_OFFLINE },
90 { "rwp", ZBC_IN_REP_RESET },
91 { "reset", ZBC_IN_REP_RESET },
92 { "nonseq", ZBC_IN_REP_NON_SEQ },
93 { "nonwp", ZBC_IN_REP_NON_WP }
94 };
95
96 typedef enum {
97 ZONE_OF_NORMAL = 0x00,
98 ZONE_OF_SUMMARY = 0x01,
99 ZONE_OF_SCRIPT = 0x02
100 } zone_output_flags;
101
102 static struct scsi_nv zone_print_opts[] = {
103 { "normal", ZONE_OF_NORMAL },
104 { "summary", ZONE_OF_SUMMARY },
105 { "script", ZONE_OF_SCRIPT }
106 };
107
108 #define ZAC_ATA_SECTOR_COUNT(bcount) (((bcount) / 512) & 0xffff)
109
110 typedef enum {
111 ZONE_PRINT_OK,
112 ZONE_PRINT_MORE_DATA,
113 ZONE_PRINT_ERROR
114 } zone_print_status;
115
116 typedef enum {
117 ZONE_FW_START,
118 ZONE_FW_LEN,
119 ZONE_FW_WP,
120 ZONE_FW_TYPE,
121 ZONE_FW_COND,
122 ZONE_FW_SEQ,
123 ZONE_FW_RESET,
124 ZONE_NUM_FIELDS
125 } zone_field_widths;
126
127 zone_print_status zone_rz_print(uint8_t *data_ptr, uint32_t valid_len,
128 int ata_format, zone_output_flags out_flags,
129 int first_pass, uint64_t *next_start_lba);
130
131
132 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)133 zone_rz_print(uint8_t *data_ptr, uint32_t valid_len, int ata_format,
134 zone_output_flags out_flags, int first_pass,
135 uint64_t *next_start_lba)
136 {
137 struct scsi_report_zones_hdr *hdr = NULL;
138 struct scsi_report_zones_desc *desc = NULL;
139 uint32_t hdr_len, len;
140 uint64_t max_lba, next_lba = 0;
141 int more_data = 0;
142 zone_print_status status = ZONE_PRINT_OK;
143 char tmpstr[80];
144 int field_widths[ZONE_NUM_FIELDS];
145 char word_sep;
146
147 if (valid_len < sizeof(*hdr)) {
148 status = ZONE_PRINT_ERROR;
149 goto bailout;
150 }
151
152 hdr = (struct scsi_report_zones_hdr *)data_ptr;
153
154 field_widths[ZONE_FW_START] = 11;
155 field_widths[ZONE_FW_LEN] = 6;
156 field_widths[ZONE_FW_WP] = 11;
157 field_widths[ZONE_FW_TYPE] = 13;
158 field_widths[ZONE_FW_COND] = 13;
159 field_widths[ZONE_FW_SEQ] = 14;
160 field_widths[ZONE_FW_RESET] = 16;
161
162 if (ata_format == 0) {
163 hdr_len = scsi_4btoul(hdr->length);
164 max_lba = scsi_8btou64(hdr->maximum_lba);
165 } else {
166 hdr_len = le32dec(hdr->length);
167 max_lba = le64dec(hdr->maximum_lba);
168 }
169
170 if (hdr_len > (valid_len + sizeof(*hdr))) {
171 more_data = 1;
172 status = ZONE_PRINT_MORE_DATA;
173 }
174
175 len = MIN(valid_len - sizeof(*hdr), hdr_len);
176
177 if (out_flags == ZONE_OF_SCRIPT)
178 word_sep = '_';
179 else
180 word_sep = ' ';
181
182 if ((out_flags != ZONE_OF_SCRIPT)
183 && (first_pass != 0)) {
184 printf("%zu zones, Maximum LBA %#jx (%ju)\n",
185 hdr_len / sizeof(*desc), (uintmax_t)max_lba,
186 (uintmax_t)max_lba);
187
188 switch (hdr->byte4 & SRZ_SAME_MASK) {
189 case SRZ_SAME_ALL_DIFFERENT:
190 printf("Zone lengths and types may vary\n");
191 break;
192 case SRZ_SAME_ALL_SAME:
193 printf("Zone lengths and types are all the same\n");
194 break;
195 case SRZ_SAME_LAST_DIFFERENT:
196 printf("Zone types are the same, last zone length "
197 "differs\n");
198 break;
199 case SRZ_SAME_TYPES_DIFFERENT:
200 printf("Zone lengths are the same, types vary\n");
201 break;
202 default:
203 printf("Unknown SAME field value %#x\n",
204 hdr->byte4 & SRZ_SAME_MASK);
205 break;
206 }
207 }
208 if (out_flags == ZONE_OF_SUMMARY) {
209 status = ZONE_PRINT_OK;
210 goto bailout;
211 }
212
213 if ((out_flags == ZONE_OF_NORMAL)
214 && (first_pass != 0)) {
215 printf("%*s %*s %*s %*s %*s %*s %*s\n",
216 field_widths[ZONE_FW_START], "Start LBA",
217 field_widths[ZONE_FW_LEN], "Length",
218 field_widths[ZONE_FW_WP], "WP LBA",
219 field_widths[ZONE_FW_TYPE], "Zone Type",
220 field_widths[ZONE_FW_COND], "Condition",
221 field_widths[ZONE_FW_SEQ], "Sequential",
222 field_widths[ZONE_FW_RESET], "Reset");
223 }
224
225 for (desc = &hdr->desc_list[0]; len >= sizeof(*desc);
226 len -= sizeof(*desc), desc++) {
227 uint64_t length, start_lba, wp_lba;
228
229 if (ata_format == 0) {
230 length = scsi_8btou64(desc->zone_length);
231 start_lba = scsi_8btou64(desc->zone_start_lba);
232 wp_lba = scsi_8btou64(desc->write_pointer_lba);
233 } else {
234 length = le64dec(desc->zone_length);
235 start_lba = le64dec(desc->zone_start_lba);
236 wp_lba = le64dec(desc->write_pointer_lba);
237 }
238
239 printf("%#*jx, %*ju, %#*jx, ", field_widths[ZONE_FW_START],
240 (uintmax_t)start_lba, field_widths[ZONE_FW_LEN],
241 (uintmax_t)length, field_widths[ZONE_FW_WP],
242 (uintmax_t)wp_lba);
243
244 switch (desc->zone_type & SRZ_TYPE_MASK) {
245 case SRZ_TYPE_CONVENTIONAL:
246 snprintf(tmpstr, sizeof(tmpstr), "Conventional");
247 break;
248 case SRZ_TYPE_SEQ_PREFERRED:
249 case SRZ_TYPE_SEQ_REQUIRED:
250 snprintf(tmpstr, sizeof(tmpstr), "Seq%c%s",
251 word_sep, ((desc->zone_type & SRZ_TYPE_MASK) ==
252 SRZ_TYPE_SEQ_PREFERRED) ? "Preferred" :
253 "Required");
254 break;
255 default:
256 snprintf(tmpstr, sizeof(tmpstr), "Zone%ctype%c%#x",
257 word_sep, word_sep,desc->zone_type &
258 SRZ_TYPE_MASK);
259 break;
260 }
261 printf("%*s, ", field_widths[ZONE_FW_TYPE], tmpstr);
262
263 switch (desc->zone_flags & SRZ_ZONE_COND_MASK) {
264 case SRZ_ZONE_COND_NWP:
265 snprintf(tmpstr, sizeof(tmpstr), "NWP");
266 break;
267 case SRZ_ZONE_COND_EMPTY:
268 snprintf(tmpstr, sizeof(tmpstr), "Empty");
269 break;
270 case SRZ_ZONE_COND_IMP_OPEN:
271 snprintf(tmpstr, sizeof(tmpstr), "Implicit%cOpen",
272 word_sep);
273 break;
274 case SRZ_ZONE_COND_EXP_OPEN:
275 snprintf(tmpstr, sizeof(tmpstr), "Explicit%cOpen",
276 word_sep);
277 break;
278 case SRZ_ZONE_COND_CLOSED:
279 snprintf(tmpstr, sizeof(tmpstr), "Closed");
280 break;
281 case SRZ_ZONE_COND_READONLY:
282 snprintf(tmpstr, sizeof(tmpstr), "Readonly");
283 break;
284 case SRZ_ZONE_COND_FULL:
285 snprintf(tmpstr, sizeof(tmpstr), "Full");
286 break;
287 case SRZ_ZONE_COND_OFFLINE:
288 snprintf(tmpstr, sizeof(tmpstr), "Offline");
289 break;
290 default:
291 snprintf(tmpstr, sizeof(tmpstr), "%#x",
292 desc->zone_flags & SRZ_ZONE_COND_MASK);
293 break;
294 }
295
296 printf("%*s, ", field_widths[ZONE_FW_COND], tmpstr);
297
298 if (desc->zone_flags & SRZ_ZONE_NON_SEQ)
299 snprintf(tmpstr, sizeof(tmpstr), "Non%cSequential",
300 word_sep);
301 else
302 snprintf(tmpstr, sizeof(tmpstr), "Sequential");
303
304 printf("%*s, ", field_widths[ZONE_FW_SEQ], tmpstr);
305
306 if (desc->zone_flags & SRZ_ZONE_RESET)
307 snprintf(tmpstr, sizeof(tmpstr), "Reset%cNeeded",
308 word_sep);
309 else
310 snprintf(tmpstr, sizeof(tmpstr), "No%cReset%cNeeded",
311 word_sep, word_sep);
312
313 printf("%*s\n", field_widths[ZONE_FW_RESET], tmpstr);
314
315 next_lba = start_lba + length;
316 }
317 bailout:
318 *next_start_lba = next_lba;
319
320 return (status);
321 }
322
323 int
zone(struct cam_device * device,int argc,char ** argv,char * combinedopt,int task_attr,int retry_count,int timeout,int verbosemode __unused)324 zone(struct cam_device *device, int argc, char **argv, char *combinedopt,
325 int task_attr, int retry_count, int timeout, int verbosemode __unused)
326 {
327 union ccb *ccb = NULL;
328 int action = -1, rep_option = -1;
329 int all_zones = 0;
330 uint64_t lba = 0;
331 int error = 0;
332 uint8_t *data_ptr = NULL;
333 uint32_t alloc_len = 65536, valid_len = 0;
334 camcontrol_devtype devtype;
335 int ata_format = 0, use_ncq = 0;
336 int first_pass = 1;
337 zone_print_status zp_status;
338 zone_output_flags out_flags = ZONE_OF_NORMAL;
339 uint8_t *cdb_storage = NULL;
340 int cdb_storage_len = 32;
341 int c;
342
343 ccb = cam_getccb(device);
344 if (ccb == NULL) {
345 warnx("%s: error allocating CCB", __func__);
346 error = 1;
347 goto bailout;
348 }
349
350 CCB_CLEAR_ALL_EXCEPT_HDR(ccb);
351
352 while ((c = getopt(argc, argv, combinedopt)) != -1) {
353 switch (c) {
354 case 'a':
355 all_zones = 1;
356 break;
357 case 'c': {
358 scsi_nv_status status;
359 int entry_num;
360
361 status = scsi_get_nv(zone_cmd_map,
362 (sizeof(zone_cmd_map) / sizeof(zone_cmd_map[0])),
363 optarg, &entry_num, SCSI_NV_FLAG_IG_CASE);
364 if (status == SCSI_NV_FOUND)
365 action = zone_cmd_map[entry_num].value;
366 else {
367 warnx("%s: %s: %s option %s", __func__,
368 (status == SCSI_NV_AMBIGUOUS) ?
369 "ambiguous" : "invalid", "zone command",
370 optarg);
371 error = 1;
372 goto bailout;
373 }
374 break;
375 }
376 case 'l': {
377 char *endptr;
378
379 lba = strtoull(optarg, &endptr, 0);
380 if (*endptr != '\0') {
381 warnx("%s: invalid lba argument %s", __func__,
382 optarg);
383 error = 1;
384 goto bailout;
385 }
386 break;
387 }
388 case 'N':
389 use_ncq = 1;
390 break;
391 case 'o': {
392 scsi_nv_status status;
393 int entry_num;
394
395 status = scsi_get_nv(zone_rep_opts,
396 (sizeof(zone_rep_opts) /sizeof(zone_rep_opts[0])),
397 optarg, &entry_num, SCSI_NV_FLAG_IG_CASE);
398 if (status == SCSI_NV_FOUND)
399 rep_option = zone_rep_opts[entry_num].value;
400 else {
401 warnx("%s: %s: %s option %s", __func__,
402 (status == SCSI_NV_AMBIGUOUS) ?
403 "ambiguous" : "invalid", "report zones",
404 optarg);
405 error = 1;
406 goto bailout;
407 }
408 break;
409 }
410 case 'P': {
411 scsi_nv_status status;
412 int entry_num;
413
414 status = scsi_get_nv(zone_print_opts,
415 (sizeof(zone_print_opts) /
416 sizeof(zone_print_opts[0])), optarg, &entry_num,
417 SCSI_NV_FLAG_IG_CASE);
418 if (status == SCSI_NV_FOUND)
419 out_flags = zone_print_opts[entry_num].value;
420 else {
421 warnx("%s: %s: %s option %s", __func__,
422 (status == SCSI_NV_AMBIGUOUS) ?
423 "ambiguous" : "invalid", "print",
424 optarg);
425 error = 1;
426 goto bailout;
427 }
428 break;
429 }
430 default:
431 break;
432 }
433 }
434 if (action == -1) {
435 warnx("%s: must specify -c <zone_cmd>", __func__);
436 error = 1;
437 goto bailout;
438 }
439 error = get_device_type(device, retry_count, timeout,
440 /*printerrors*/ 1, &devtype);
441 if (error != 0)
442 errx(1, "Unable to determine device type");
443
444 if (action == ZBC_IN_SA_REPORT_ZONES) {
445
446 data_ptr = malloc(alloc_len);
447 if (data_ptr == NULL)
448 err(1, "unable to allocate %u bytes", alloc_len);
449
450 restart_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_SATL: {
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_SATL: {
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;
670 bailout:
671 if (ccb != NULL)
672 cam_freeccb(ccb);
673
674 free(data_ptr);
675 free(cdb_storage);
676
677 return (error);
678 }
679