Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sbin/camcontrol/zone.c
39475 views
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
673