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
68static 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
77static 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
93typedef enum {
94	ZONE_OF_NORMAL	= 0x00,
95	ZONE_OF_SUMMARY	= 0x01,
96	ZONE_OF_SCRIPT	= 0x02
97} zone_output_flags;
98
99static 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
107typedef enum {
108	ZONE_PRINT_OK,
109	ZONE_PRINT_MORE_DATA,
110	ZONE_PRINT_ERROR
111} zone_print_status;
112
113typedef 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
124zone_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
129zone_print_status
130zone_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	}
312bailout:
313	*next_start_lba = next_lba;
314
315	return (status);
316}
317
318int
319zone(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
443restart_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;
663bailout:
664	if (ccb != NULL)
665		cam_freeccb(ccb);
666
667	free(data_ptr);
668	free(cdb_storage);
669
670	return (error);
671}
672