Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/usr.sbin/ctladm/ctladm.c
105686 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2003, 2004 Silicon Graphics International Corp.
5
* Copyright (c) 1997-2007 Kenneth D. Merry
6
* Copyright (c) 2012 The FreeBSD Foundation
7
* Copyright (c) 2018 Marcelo Araujo <[email protected]>
8
* All rights reserved.
9
*
10
* Portions of this software were developed by Edward Tomasz Napierala
11
* under sponsorship from the FreeBSD Foundation.
12
*
13
* Redistribution and use in source and binary forms, with or without
14
* modification, are permitted provided that the following conditions
15
* are met:
16
* 1. Redistributions of source code must retain the above copyright
17
* notice, this list of conditions, and the following disclaimer,
18
* without modification.
19
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
20
* substantially similar to the "NO WARRANTY" disclaimer below
21
* ("Disclaimer") and any redistribution must be conditioned upon
22
* including a substantially similar Disclaimer requirement for further
23
* binary redistribution.
24
*
25
* NO WARRANTY
26
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
29
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
34
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
35
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36
* POSSIBILITY OF SUCH DAMAGES.
37
*
38
* $Id: //depot/users/kenm/FreeBSD-test2/usr.sbin/ctladm/ctladm.c#4 $
39
*/
40
/*
41
* CAM Target Layer exercise program.
42
*
43
* Author: Ken Merry <[email protected]>
44
*/
45
46
#include <sys/param.h>
47
#include <sys/callout.h>
48
#include <sys/ioctl.h>
49
#include <sys/linker.h>
50
#include <sys/module.h>
51
#include <sys/queue.h>
52
#include <sys/sbuf.h>
53
#include <sys/nv.h>
54
#include <sys/stat.h>
55
#include <bsdxml.h>
56
#include <ctype.h>
57
#include <err.h>
58
#include <errno.h>
59
#include <fcntl.h>
60
#include <getopt.h>
61
#include <stdlib.h>
62
#include <stdint.h>
63
#include <stdio.h>
64
#include <string.h>
65
#include <unistd.h>
66
#include <cam/scsi/scsi_all.h>
67
#include <cam/scsi/scsi_message.h>
68
#include <cam/ctl/ctl.h>
69
#include <cam/ctl/ctl_io.h>
70
#include <cam/ctl/ctl_backend.h>
71
#include <cam/ctl/ctl_ioctl.h>
72
#include <cam/ctl/ctl_util.h>
73
#include <cam/ctl/ctl_scsi_all.h>
74
#include <dev/nvmf/nvmf_proto.h>
75
#include <camlib.h>
76
#include <libutil.h>
77
#include "ctladm.h"
78
79
#ifdef min
80
#undef min
81
#endif
82
#define min(x,y) (x < y) ? x : y
83
84
typedef enum {
85
CTLADM_CMD_TUR,
86
CTLADM_CMD_INQUIRY,
87
CTLADM_CMD_REQ_SENSE,
88
CTLADM_CMD_ARRAYLIST,
89
CTLADM_CMD_REPORT_LUNS,
90
CTLADM_CMD_HELP,
91
CTLADM_CMD_DEVLIST,
92
CTLADM_CMD_ADDDEV,
93
CTLADM_CMD_RM,
94
CTLADM_CMD_CREATE,
95
CTLADM_CMD_READ,
96
CTLADM_CMD_WRITE,
97
CTLADM_CMD_PORT,
98
CTLADM_CMD_PORTLIST,
99
CTLADM_CMD_READCAPACITY,
100
CTLADM_CMD_MODESENSE,
101
CTLADM_CMD_DUMPOOA,
102
CTLADM_CMD_DUMPSTRUCTS,
103
CTLADM_CMD_START,
104
CTLADM_CMD_STOP,
105
CTLADM_CMD_SYNC_CACHE,
106
CTLADM_CMD_LUNLIST,
107
CTLADM_CMD_DELAY,
108
CTLADM_CMD_ERR_INJECT,
109
CTLADM_CMD_PRES_IN,
110
CTLADM_CMD_PRES_OUT,
111
CTLADM_CMD_INQ_VPD_DEVID,
112
CTLADM_CMD_RTPG,
113
CTLADM_CMD_MODIFY,
114
CTLADM_CMD_ISLIST,
115
CTLADM_CMD_ISLOGOUT,
116
CTLADM_CMD_ISTERMINATE,
117
CTLADM_CMD_LUNMAP,
118
CTLADM_CMD_NVLIST,
119
CTLADM_CMD_NVTERMINATE
120
} ctladm_cmdfunction;
121
122
typedef enum {
123
CTLADM_ARG_NONE = 0x0000000,
124
CTLADM_ARG_AUTOSENSE = 0x0000001,
125
CTLADM_ARG_DEVICE = 0x0000002,
126
CTLADM_ARG_ARRAYSIZE = 0x0000004,
127
CTLADM_ARG_BACKEND = 0x0000008,
128
CTLADM_ARG_CDBSIZE = 0x0000010,
129
CTLADM_ARG_DATALEN = 0x0000020,
130
CTLADM_ARG_FILENAME = 0x0000040,
131
CTLADM_ARG_LBA = 0x0000080,
132
CTLADM_ARG_PC = 0x0000100,
133
CTLADM_ARG_PAGE_CODE = 0x0000200,
134
CTLADM_ARG_PAGE_LIST = 0x0000400,
135
CTLADM_ARG_SUBPAGE = 0x0000800,
136
CTLADM_ARG_PAGELIST = 0x0001000,
137
CTLADM_ARG_DBD = 0x0002000,
138
CTLADM_ARG_TARG_LUN = 0x0004000,
139
CTLADM_ARG_BLOCKSIZE = 0x0008000,
140
CTLADM_ARG_IMMED = 0x0010000,
141
CTLADM_ARG_RELADR = 0x0020000,
142
CTLADM_ARG_RETRIES = 0x0040000,
143
CTLADM_ARG_ONOFFLINE = 0x0080000,
144
CTLADM_ARG_ONESHOT = 0x0100000,
145
CTLADM_ARG_TIMEOUT = 0x0200000,
146
CTLADM_ARG_INITIATOR = 0x0400000,
147
CTLADM_ARG_NOCOPY = 0x0800000,
148
CTLADM_ARG_NEED_TL = 0x1000000
149
} ctladm_cmdargs;
150
151
struct ctladm_opts {
152
const char *optname;
153
uint32_t cmdnum;
154
ctladm_cmdargs argnum;
155
const char *subopt;
156
};
157
158
typedef enum {
159
CC_OR_NOT_FOUND,
160
CC_OR_AMBIGUOUS,
161
CC_OR_FOUND
162
} ctladm_optret;
163
164
static const char rw_opts[] = "Nb:c:d:f:l:";
165
static const char startstop_opts[] = "i";
166
167
static struct ctladm_opts option_table[] = {
168
{"adddev", CTLADM_CMD_ADDDEV, CTLADM_ARG_NONE, NULL},
169
{"create", CTLADM_CMD_CREATE, CTLADM_ARG_NONE, "b:B:d:l:o:s:S:t:"},
170
{"delay", CTLADM_CMD_DELAY, CTLADM_ARG_NEED_TL, "T:l:t:"},
171
{"devid", CTLADM_CMD_INQ_VPD_DEVID, CTLADM_ARG_NEED_TL, NULL},
172
{"devlist", CTLADM_CMD_DEVLIST, CTLADM_ARG_NONE, "b:vx"},
173
{"dumpooa", CTLADM_CMD_DUMPOOA, CTLADM_ARG_NONE, NULL},
174
{"dumpstructs", CTLADM_CMD_DUMPSTRUCTS, CTLADM_ARG_NONE, NULL},
175
{"help", CTLADM_CMD_HELP, CTLADM_ARG_NONE, NULL},
176
{"inject", CTLADM_CMD_ERR_INJECT, CTLADM_ARG_NEED_TL, "cd:i:p:r:s:"},
177
{"inquiry", CTLADM_CMD_INQUIRY, CTLADM_ARG_NEED_TL, NULL},
178
{"islist", CTLADM_CMD_ISLIST, CTLADM_ARG_NONE, "vx"},
179
{"islogout", CTLADM_CMD_ISLOGOUT, CTLADM_ARG_NONE, "ac:i:p:"},
180
{"isterminate", CTLADM_CMD_ISTERMINATE, CTLADM_ARG_NONE, "ac:i:p:"},
181
{"lunlist", CTLADM_CMD_LUNLIST, CTLADM_ARG_NONE, NULL},
182
{"lunmap", CTLADM_CMD_LUNMAP, CTLADM_ARG_NONE, "p:l:L:"},
183
{"modesense", CTLADM_CMD_MODESENSE, CTLADM_ARG_NEED_TL, "P:S:dlm:c:"},
184
{"modify", CTLADM_CMD_MODIFY, CTLADM_ARG_NONE, "b:l:o:s:"},
185
{"nvlist", CTLADM_CMD_NVLIST, CTLADM_ARG_NONE, "vx"},
186
{"nvterminate", CTLADM_CMD_NVTERMINATE, CTLADM_ARG_NONE, "ac:h:"},
187
#if (__FreeBSD_version < 1600000)
188
{"port", CTLADM_CMD_PORT, CTLADM_ARG_NONE, "lo:O:d:crp:qt:w:W:x"},
189
#else
190
{"port", CTLADM_CMD_PORT, CTLADM_ARG_NONE, "o:O:d:crp:t:w:W:"},
191
#endif
192
{"portlist", CTLADM_CMD_PORTLIST, CTLADM_ARG_NONE, "f:ilp:qvx"},
193
{"prin", CTLADM_CMD_PRES_IN, CTLADM_ARG_NEED_TL, "a:"},
194
{"prout", CTLADM_CMD_PRES_OUT, CTLADM_ARG_NEED_TL, "a:k:r:s:"},
195
{"read", CTLADM_CMD_READ, CTLADM_ARG_NEED_TL, rw_opts},
196
{"readcapacity", CTLADM_CMD_READCAPACITY, CTLADM_ARG_NEED_TL, "c:"},
197
{"remove", CTLADM_CMD_RM, CTLADM_ARG_NONE, "b:l:o:"},
198
{"reportluns", CTLADM_CMD_REPORT_LUNS, CTLADM_ARG_NEED_TL, NULL},
199
{"reqsense", CTLADM_CMD_REQ_SENSE, CTLADM_ARG_NEED_TL, NULL},
200
{"rtpg", CTLADM_CMD_RTPG, CTLADM_ARG_NEED_TL, NULL},
201
{"start", CTLADM_CMD_START, CTLADM_ARG_NEED_TL, startstop_opts},
202
{"stop", CTLADM_CMD_STOP, CTLADM_ARG_NEED_TL, startstop_opts},
203
{"synccache", CTLADM_CMD_SYNC_CACHE, CTLADM_ARG_NEED_TL, "b:c:il:r"},
204
{"tur", CTLADM_CMD_TUR, CTLADM_ARG_NEED_TL, NULL},
205
{"write", CTLADM_CMD_WRITE, CTLADM_ARG_NEED_TL, rw_opts},
206
{"-?", CTLADM_CMD_HELP, CTLADM_ARG_NONE, NULL},
207
{"-h", CTLADM_CMD_HELP, CTLADM_ARG_NONE, NULL},
208
{NULL, 0, 0, NULL}
209
};
210
211
212
ctladm_optret getoption(struct ctladm_opts *table, char *arg, uint32_t *cmdnum,
213
ctladm_cmdargs *argnum, const char **subopt);
214
static int cctl_dump_ooa(int fd, int argc, char **argv);
215
static int cctl_port(int fd, int argc, char **argv, char *combinedopt);
216
static int cctl_do_io(int fd, int retries, union ctl_io *io, const char *func);
217
static int cctl_delay(int fd, int lun, int argc, char **argv,
218
char *combinedopt);
219
static int cctl_lunlist(int fd);
220
static int cctl_sync_cache(int fd, int lun, int iid, int retries,
221
int argc, char **argv, char *combinedopt);
222
static int cctl_start_stop(int fd, int lun, int iid, int retries,
223
int start, int argc, char **argv, char *combinedopt);
224
static int cctl_mode_sense(int fd, int lun, int iid, int retries,
225
int argc, char **argv, char *combinedopt);
226
static int cctl_read_capacity(int fd, int lun, int iid,
227
int retries, int argc, char **argv,
228
char *combinedopt);
229
static int cctl_read_write(int fd, int lun, int iid, int retries,
230
int argc, char **argv, char *combinedopt,
231
ctladm_cmdfunction command);
232
static int cctl_get_luns(int fd, int lun, int iid, int retries,
233
struct scsi_report_luns_data **lun_data,
234
uint32_t *num_luns);
235
static int cctl_report_luns(int fd, int lun, int iid, int retries);
236
static int cctl_tur(int fd, int lun, int iid, int retries);
237
static int cctl_get_inquiry(int fd, int lun, int iid, int retries,
238
char *path_str, int path_len,
239
struct scsi_inquiry_data *inq_data);
240
static int cctl_inquiry(int fd, int lun, int iid, int retries);
241
static int cctl_req_sense(int fd, int lun, int iid, int retries);
242
static int cctl_persistent_reserve_in(int fd, int lun,
243
int initiator, int argc, char **argv,
244
char *combinedopt, int retry_count);
245
static int cctl_persistent_reserve_out(int fd, int lun,
246
int initiator, int argc, char **argv,
247
char *combinedopt, int retry_count);
248
static int cctl_create_lun(int fd, int argc, char **argv, char *combinedopt);
249
static int cctl_inquiry_vpd_devid(int fd, int lun, int initiator);
250
static int cctl_report_target_port_group(int fd, int lun, int initiator);
251
static int cctl_modify_lun(int fd, int argc, char **argv, char *combinedopt);
252
static int cctl_portlist(int fd, int argc, char **argv, char *combinedopt);
253
254
ctladm_optret
255
getoption(struct ctladm_opts *table, char *arg, uint32_t *cmdnum,
256
ctladm_cmdargs *argnum, const char **subopt)
257
{
258
struct ctladm_opts *opts;
259
int num_matches = 0;
260
261
for (opts = table; (opts != NULL) && (opts->optname != NULL);
262
opts++) {
263
if (strncmp(opts->optname, arg, strlen(arg)) == 0) {
264
*cmdnum = opts->cmdnum;
265
*argnum = opts->argnum;
266
*subopt = opts->subopt;
267
268
if (strcmp(opts->optname, arg) == 0)
269
return (CC_OR_FOUND);
270
271
if (++num_matches > 1)
272
return(CC_OR_AMBIGUOUS);
273
}
274
}
275
276
if (num_matches > 0)
277
return(CC_OR_FOUND);
278
else
279
return(CC_OR_NOT_FOUND);
280
}
281
282
static int
283
cctl_dump_ooa(int fd, int argc, char **argv)
284
{
285
struct ctl_ooa ooa;
286
long double cmd_latency;
287
int num_entries, len, lun = -1, retval = 0;
288
unsigned int i;
289
290
num_entries = 104;
291
292
if ((argc > 2) && (isdigit(argv[2][0])))
293
lun = strtol(argv[2], NULL, 0);
294
retry:
295
296
len = num_entries * sizeof(struct ctl_ooa_entry);
297
bzero(&ooa, sizeof(ooa));
298
ooa.entries = malloc(len);
299
if (ooa.entries == NULL) {
300
warn("%s: error mallocing %d bytes", __func__, len);
301
return (1);
302
}
303
if (lun >= 0) {
304
ooa.lun_num = lun;
305
} else
306
ooa.flags |= CTL_OOA_FLAG_ALL_LUNS;
307
ooa.alloc_len = len;
308
ooa.alloc_num = num_entries;
309
if (ioctl(fd, CTL_GET_OOA, &ooa) == -1) {
310
warn("%s: CTL_GET_OOA ioctl failed", __func__);
311
retval = 1;
312
goto bailout;
313
}
314
315
if (ooa.status == CTL_OOA_NEED_MORE_SPACE) {
316
num_entries = num_entries * 2;
317
free(ooa.entries);
318
ooa.entries = NULL;
319
goto retry;
320
}
321
322
if (ooa.status != CTL_OOA_OK) {
323
warnx("%s: CTL_GET_OOA ioctl returned error %d", __func__,
324
ooa.status);
325
retval = 1;
326
goto bailout;
327
}
328
329
fprintf(stdout, "Dumping OOA queues\n");
330
for (i = 0; i < ooa.fill_num; i++) {
331
struct ctl_ooa_entry *entry;
332
char cdb_str[(SCSI_MAX_CDBLEN * 3) +1];
333
struct bintime delta_bt;
334
struct timespec ts;
335
336
entry = &ooa.entries[i];
337
338
delta_bt = ooa.cur_bt;
339
bintime_sub(&delta_bt, &entry->start_bt);
340
bintime2timespec(&delta_bt, &ts);
341
cmd_latency = ts.tv_sec * 1000;
342
if (ts.tv_nsec > 0)
343
cmd_latency += ts.tv_nsec / 1000000;
344
345
fprintf(stdout, "LUN %jd tag 0x%jx%s%s%s%s%s%s%s: %s. CDB: %s "
346
"(%0.0Lf ms)\n",
347
(intmax_t)entry->lun_num, entry->tag_num,
348
(entry->cmd_flags & CTL_OOACMD_FLAG_BLOCKED) ?
349
" BLOCKED" : "",
350
(entry->cmd_flags & CTL_OOACMD_FLAG_RTR) ? " RTR" :"",
351
(entry->cmd_flags & CTL_OOACMD_FLAG_DMA_QUEUED) ?
352
" DMAQUEUED" : "",
353
(entry->cmd_flags & CTL_OOACMD_FLAG_DMA) ? " DMA" : "",
354
(entry->cmd_flags & CTL_OOACMD_FLAG_STATUS_QUEUED) ?
355
" STATUSQUEUED" : "",
356
(entry->cmd_flags & CTL_OOACMD_FLAG_STATUS_SENT) ? " STATUS" : "",
357
(entry->cmd_flags & CTL_OOACMD_FLAG_ABORT) ?
358
" ABORT" : "",
359
scsi_op_desc(entry->cdb[0], NULL),
360
scsi_cdb_string(entry->cdb, cdb_str, sizeof(cdb_str)),
361
cmd_latency);
362
}
363
fprintf(stdout, "OOA queues dump done\n");
364
365
bailout:
366
free(ooa.entries);
367
return (retval);
368
}
369
370
static int
371
cctl_dump_structs(int fd, ctladm_cmdargs cmdargs __unused)
372
{
373
if (ioctl(fd, CTL_DUMP_STRUCTS) == -1) {
374
warn(__func__);
375
return (1);
376
}
377
return (0);
378
}
379
380
typedef enum {
381
CCTL_PORT_MODE_NONE,
382
CCTL_PORT_MODE_LIST,
383
CCTL_PORT_MODE_SET,
384
CCTL_PORT_MODE_ON,
385
CCTL_PORT_MODE_OFF,
386
CCTL_PORT_MODE_CREATE,
387
CCTL_PORT_MODE_REMOVE
388
} cctl_port_mode;
389
390
static struct ctladm_opts cctl_fe_table[] = {
391
{"fc", CTL_PORT_FC, CTLADM_ARG_NONE, NULL},
392
{"scsi", CTL_PORT_SCSI, CTLADM_ARG_NONE, NULL},
393
{"internal", CTL_PORT_INTERNAL, CTLADM_ARG_NONE, NULL},
394
{"iscsi", CTL_PORT_ISCSI, CTLADM_ARG_NONE, NULL},
395
{"nvmf", CTL_PORT_NVMF, CTLADM_ARG_NONE, NULL},
396
{"sas", CTL_PORT_SAS, CTLADM_ARG_NONE, NULL},
397
{"all", CTL_PORT_ALL, CTLADM_ARG_NONE, NULL},
398
{NULL, 0, 0, NULL}
399
};
400
401
static int
402
cctl_port(int fd, int argc, char **argv, char *combinedopt)
403
{
404
char result_buf[1024];
405
int c;
406
uint64_t created_port = -1;
407
int32_t targ_port = -1;
408
int retval = 0;
409
int wwnn_set = 0, wwpn_set = 0;
410
uint64_t wwnn = 0, wwpn = 0;
411
cctl_port_mode port_mode = CCTL_PORT_MODE_NONE;
412
struct ctl_port_entry entry;
413
struct ctl_req req;
414
char *driver = NULL;
415
nvlist_t *option_list;
416
ctl_port_type port_type = CTL_PORT_NONE;
417
#if (__FreeBSD_version < 1600000)
418
int quiet = 0, xml = 0;
419
#endif
420
421
option_list = nvlist_create(0);
422
if (option_list == NULL)
423
err(1, "%s: unable to allocate nvlist", __func__);
424
425
while ((c = getopt(argc, argv, combinedopt)) != -1) {
426
switch (c) {
427
#if (__FreeBSD_version < 1600000)
428
case 'l':
429
warnx("ctladm port -l is deprecated. "
430
"Use ctladm portlist instead");
431
if (port_mode != CCTL_PORT_MODE_NONE)
432
goto bailout_badarg;
433
434
port_mode = CCTL_PORT_MODE_LIST;
435
break;
436
case 'q':
437
quiet = 1;
438
break;
439
case 'x':
440
xml = 1;
441
break;
442
#endif
443
case 'c':
444
port_mode = CCTL_PORT_MODE_CREATE;
445
break;
446
case 'r':
447
port_mode = CCTL_PORT_MODE_REMOVE;
448
break;
449
case 'o':
450
if (port_mode != CCTL_PORT_MODE_NONE)
451
goto bailout_badarg;
452
453
if (strcasecmp(optarg, "on") == 0)
454
port_mode = CCTL_PORT_MODE_ON;
455
else if (strcasecmp(optarg, "off") == 0)
456
port_mode = CCTL_PORT_MODE_OFF;
457
else {
458
warnx("Invalid -o argument %s, \"on\" or "
459
"\"off\" are the only valid args",
460
optarg);
461
retval = 1;
462
goto bailout;
463
}
464
break;
465
case 'O': {
466
char *tmpstr;
467
char *name, *value;
468
469
tmpstr = strdup(optarg);
470
name = strsep(&tmpstr, "=");
471
if (name == NULL) {
472
warnx("%s: option -O takes \"name=value\""
473
"argument", __func__);
474
retval = 1;
475
goto bailout;
476
}
477
value = strsep(&tmpstr, "=");
478
if (value == NULL) {
479
warnx("%s: option -O takes \"name=value\""
480
"argument", __func__);
481
retval = 1;
482
goto bailout;
483
}
484
485
free(tmpstr);
486
nvlist_add_string(option_list, name, value);
487
break;
488
}
489
case 'd':
490
if (driver != NULL) {
491
warnx("%s: option -d cannot be specified twice",
492
__func__);
493
retval = 1;
494
goto bailout;
495
}
496
497
driver = strdup(optarg);
498
break;
499
case 'p':
500
targ_port = strtol(optarg, NULL, 0);
501
break;
502
case 't': {
503
ctladm_optret optret;
504
ctladm_cmdargs argnum;
505
const char *subopt;
506
ctl_port_type tmp_port_type;
507
508
optret = getoption(cctl_fe_table, optarg, &tmp_port_type,
509
&argnum, &subopt);
510
if (optret == CC_OR_AMBIGUOUS) {
511
warnx("%s: ambiguous frontend type %s",
512
__func__, optarg);
513
retval = 1;
514
goto bailout;
515
} else if (optret == CC_OR_NOT_FOUND) {
516
warnx("%s: invalid frontend type %s",
517
__func__, optarg);
518
retval = 1;
519
goto bailout;
520
}
521
522
port_type |= tmp_port_type;
523
break;
524
}
525
case 'w':
526
if ((port_mode != CCTL_PORT_MODE_NONE)
527
&& (port_mode != CCTL_PORT_MODE_SET))
528
goto bailout_badarg;
529
530
port_mode = CCTL_PORT_MODE_SET;
531
532
wwnn = strtoull(optarg, NULL, 0);
533
wwnn_set = 1;
534
break;
535
case 'W':
536
if ((port_mode != CCTL_PORT_MODE_NONE)
537
&& (port_mode != CCTL_PORT_MODE_SET))
538
goto bailout_badarg;
539
540
port_mode = CCTL_PORT_MODE_SET;
541
542
wwpn = strtoull(optarg, NULL, 0);
543
wwpn_set = 1;
544
break;
545
}
546
}
547
548
if (driver == NULL)
549
driver = strdup("ioctl");
550
551
/*
552
* The user can specify either one or more frontend types (-t), or
553
* a specific frontend, but not both.
554
*
555
* If the user didn't specify a frontend type or number, set it to
556
* all. This is primarily needed for the enable/disable ioctls.
557
* This will be a no-op for the listing code. For the set ioctl,
558
* we'll throw an error, since that only works on one port at a time.
559
*/
560
if ((port_type != CTL_PORT_NONE) && (targ_port != -1)) {
561
warnx("%s: can only specify one of -t or -p", __func__);
562
retval = 1;
563
goto bailout;
564
} else if ((targ_port == -1) && (port_type == CTL_PORT_NONE))
565
port_type = CTL_PORT_ALL;
566
567
bzero(&entry, sizeof(entry));
568
569
/*
570
* These are needed for all but list/dump mode.
571
*/
572
entry.port_type = port_type;
573
entry.targ_port = targ_port;
574
575
switch (port_mode) {
576
#if (__FreeBSD_version < 1600000)
577
case CCTL_PORT_MODE_LIST: {
578
char opts[] = "xq";
579
char argx[] = "-x";
580
char argq[] = "-q";
581
char *argvx[2];
582
int argcx = 0;
583
584
optind = 0;
585
optreset = 1;
586
if (xml)
587
argvx[argcx++] = argx;
588
if (quiet)
589
argvx[argcx++] = argq;
590
cctl_portlist(fd, argcx, argvx, opts);
591
break;
592
}
593
#endif
594
case CCTL_PORT_MODE_REMOVE:
595
case CCTL_PORT_MODE_CREATE: {
596
bzero(&req, sizeof(req));
597
strlcpy(req.driver, driver, sizeof(req.driver));
598
req.result = result_buf;
599
req.result_len = sizeof(result_buf);
600
601
if (port_mode == CCTL_PORT_MODE_REMOVE) {
602
req.reqtype = CTL_REQ_REMOVE;
603
if (targ_port != -1)
604
nvlist_add_stringf(option_list, "port_id", "%d",
605
targ_port);
606
} else
607
req.reqtype = CTL_REQ_CREATE;
608
609
req.args = nvlist_pack(option_list, &req.args_len);
610
if (req.args == NULL) {
611
warn("%s: error packing nvlist", __func__);
612
retval = 1;
613
goto bailout;
614
}
615
616
retval = ioctl(fd, CTL_PORT_REQ, &req);
617
free(req.args);
618
if (retval == -1) {
619
warn("%s: CTL_PORT_REQ ioctl failed", __func__);
620
retval = 1;
621
goto bailout;
622
}
623
624
switch (req.status) {
625
case CTL_LUN_ERROR:
626
warnx("error: %s", req.error_str);
627
retval = 1;
628
goto bailout;
629
case CTL_LUN_WARNING:
630
warnx("warning: %s", req.error_str);
631
break;
632
case CTL_LUN_OK:
633
if (port_mode == CCTL_PORT_MODE_CREATE) {
634
req.result_nvl = nvlist_unpack(result_buf, req.result_len, 0);
635
if (req.result_nvl == NULL) {
636
warnx("error unpacking result nvlist");
637
break;
638
}
639
created_port = nvlist_get_number(req.result_nvl, "port_id");
640
printf("Port created successfully\n"
641
"frontend: %s\n"
642
"port: %ju\n", driver,
643
(uintmax_t) created_port);
644
nvlist_destroy(req.result_nvl);
645
} else
646
printf("Port destroyed successfully\n");
647
break;
648
default:
649
warnx("unknown status: %d", req.status);
650
retval = 1;
651
goto bailout;
652
}
653
654
break;
655
}
656
case CCTL_PORT_MODE_SET:
657
if (targ_port == -1) {
658
warnx("%s: -w and -W require -p", __func__);
659
retval = 1;
660
goto bailout;
661
}
662
663
if (wwnn_set) {
664
entry.flags |= CTL_PORT_WWNN_VALID;
665
entry.wwnn = wwnn;
666
}
667
if (wwpn_set) {
668
entry.flags |= CTL_PORT_WWPN_VALID;
669
entry.wwpn = wwpn;
670
}
671
672
if (ioctl(fd, CTL_SET_PORT_WWNS, &entry) == -1) {
673
warn("%s: CTL_SET_PORT_WWNS ioctl failed", __func__);
674
retval = 1;
675
goto bailout;
676
}
677
break;
678
case CCTL_PORT_MODE_ON:
679
if (ioctl(fd, CTL_ENABLE_PORT, &entry) == -1) {
680
warn("%s: CTL_ENABLE_PORT ioctl failed", __func__);
681
retval = 1;
682
goto bailout;
683
}
684
fprintf(stdout, "Front End Ports enabled\n");
685
break;
686
case CCTL_PORT_MODE_OFF:
687
if (ioctl(fd, CTL_DISABLE_PORT, &entry) == -1) {
688
warn("%s: CTL_DISABLE_PORT ioctl failed", __func__);
689
retval = 1;
690
goto bailout;
691
}
692
fprintf(stdout, "Front End Ports disabled\n");
693
break;
694
default:
695
warnx("%s: one of -c, -r, -o or -w/-W must be specified", __func__);
696
retval = 1;
697
goto bailout;
698
break;
699
}
700
701
bailout:
702
nvlist_destroy(option_list);
703
free(driver);
704
return (retval);
705
706
bailout_badarg:
707
warnx("%s: only one of -c, -r, -l, -o or -w/-W may be specified",
708
__func__);
709
return (1);
710
}
711
712
static int
713
cctl_do_io(int fd, int retries, union ctl_io *io, const char *func)
714
{
715
do {
716
if (ioctl(fd, CTL_IO, io) == -1) {
717
warn("%s: error sending CTL_IO ioctl", func);
718
return (-1);
719
}
720
} while (((io->io_hdr.status & CTL_STATUS_MASK) != CTL_SUCCESS)
721
&& (retries-- > 0));
722
723
return (0);
724
}
725
726
static int
727
cctl_delay(int fd, int lun, int argc, char **argv,
728
char *combinedopt)
729
{
730
struct ctl_io_delay_info delay_info;
731
char *delayloc = NULL;
732
char *delaytype = NULL;
733
int delaytime = -1;
734
int retval;
735
int c;
736
737
retval = 0;
738
739
memset(&delay_info, 0, sizeof(delay_info));
740
741
while ((c = getopt(argc, argv, combinedopt)) != -1) {
742
switch (c) {
743
case 'T':
744
delaytype = strdup(optarg);
745
break;
746
case 'l':
747
delayloc = strdup(optarg);
748
break;
749
case 't':
750
delaytime = strtoul(optarg, NULL, 0);
751
break;
752
}
753
}
754
755
if (delaytime == -1) {
756
warnx("%s: you must specify the delaytime with -t", __func__);
757
retval = 1;
758
goto bailout;
759
}
760
761
if (strcasecmp(delayloc, "datamove") == 0)
762
delay_info.delay_loc = CTL_DELAY_LOC_DATAMOVE;
763
else if (strcasecmp(delayloc, "done") == 0)
764
delay_info.delay_loc = CTL_DELAY_LOC_DONE;
765
else {
766
warnx("%s: invalid delay location %s", __func__, delayloc);
767
retval = 1;
768
goto bailout;
769
}
770
771
if ((delaytype == NULL)
772
|| (strcmp(delaytype, "oneshot") == 0))
773
delay_info.delay_type = CTL_DELAY_TYPE_ONESHOT;
774
else if (strcmp(delaytype, "cont") == 0)
775
delay_info.delay_type = CTL_DELAY_TYPE_CONT;
776
else {
777
warnx("%s: invalid delay type %s", __func__, delaytype);
778
retval = 1;
779
goto bailout;
780
}
781
782
delay_info.lun_id = lun;
783
delay_info.delay_secs = delaytime;
784
785
if (ioctl(fd, CTL_DELAY_IO, &delay_info) == -1) {
786
warn("%s: CTL_DELAY_IO ioctl failed", __func__);
787
retval = 1;
788
goto bailout;
789
}
790
switch (delay_info.status) {
791
case CTL_DELAY_STATUS_NONE:
792
warnx("%s: no delay status??", __func__);
793
retval = 1;
794
break;
795
case CTL_DELAY_STATUS_OK:
796
break;
797
case CTL_DELAY_STATUS_INVALID_LUN:
798
warnx("%s: invalid lun %d", __func__, lun);
799
retval = 1;
800
break;
801
case CTL_DELAY_STATUS_INVALID_TYPE:
802
warnx("%s: invalid delay type %d", __func__,
803
delay_info.delay_type);
804
retval = 1;
805
break;
806
case CTL_DELAY_STATUS_INVALID_LOC:
807
warnx("%s: delay location %s not implemented?", __func__,
808
delayloc);
809
retval = 1;
810
break;
811
case CTL_DELAY_STATUS_NOT_IMPLEMENTED:
812
warnx("%s: delay not implemented in the kernel", __func__);
813
warnx("%s: recompile with the CTL_IO_DELAY flag set", __func__);
814
retval = 1;
815
break;
816
default:
817
warnx("%s: unknown delay return status %d", __func__,
818
delay_info.status);
819
retval = 1;
820
break;
821
}
822
823
bailout:
824
free(delayloc);
825
free(delaytype);
826
return (retval);
827
}
828
829
static struct ctladm_opts cctl_err_types[] = {
830
{"aborted", CTL_LUN_INJ_ABORTED, CTLADM_ARG_NONE, NULL},
831
{"mediumerr", CTL_LUN_INJ_MEDIUM_ERR, CTLADM_ARG_NONE, NULL},
832
{"ua", CTL_LUN_INJ_UA, CTLADM_ARG_NONE, NULL},
833
{"custom", CTL_LUN_INJ_CUSTOM, CTLADM_ARG_NONE, NULL},
834
{NULL, 0, 0, NULL}
835
836
};
837
838
static struct ctladm_opts cctl_err_patterns[] = {
839
{"read", CTL_LUN_PAT_READ, CTLADM_ARG_NONE, NULL},
840
{"write", CTL_LUN_PAT_WRITE, CTLADM_ARG_NONE, NULL},
841
{"rw", CTL_LUN_PAT_READWRITE, CTLADM_ARG_NONE, NULL},
842
{"readwrite", CTL_LUN_PAT_READWRITE, CTLADM_ARG_NONE, NULL},
843
{"readcap", CTL_LUN_PAT_READCAP, CTLADM_ARG_NONE, NULL},
844
{"tur", CTL_LUN_PAT_TUR, CTLADM_ARG_NONE, NULL},
845
{"any", CTL_LUN_PAT_ANY, CTLADM_ARG_NONE, NULL},
846
#if 0
847
{"cmd", CTL_LUN_PAT_CMD, CTLADM_ARG_NONE, NULL},
848
#endif
849
{NULL, 0, 0, NULL}
850
};
851
852
static int
853
cctl_error_inject(int fd, uint32_t lun, int argc, char **argv,
854
char *combinedopt)
855
{
856
int retval = 0;
857
struct ctl_error_desc err_desc;
858
uint64_t lba = 0;
859
uint32_t len = 0;
860
uint64_t delete_id = 0;
861
int delete_id_set = 0;
862
int continuous = 0;
863
int sense_len = 0;
864
int fd_sense = 0;
865
int c;
866
867
bzero(&err_desc, sizeof(err_desc));
868
err_desc.lun_id = lun;
869
870
while ((c = getopt(argc, argv, combinedopt)) != -1) {
871
switch (c) {
872
case 'c':
873
continuous = 1;
874
break;
875
case 'd':
876
delete_id = strtoull(optarg, NULL, 0);
877
delete_id_set = 1;
878
break;
879
case 'i':
880
case 'p': {
881
ctladm_optret optret;
882
ctladm_cmdargs argnum;
883
const char *subopt;
884
885
if (c == 'i') {
886
ctl_lun_error err_type;
887
888
if (err_desc.lun_error != CTL_LUN_INJ_NONE) {
889
warnx("%s: can't specify multiple -i "
890
"arguments", __func__);
891
retval = 1;
892
goto bailout;
893
}
894
optret = getoption(cctl_err_types, optarg,
895
&err_type, &argnum, &subopt);
896
err_desc.lun_error = err_type;
897
} else {
898
ctl_lun_error_pattern pattern;
899
900
optret = getoption(cctl_err_patterns, optarg,
901
&pattern, &argnum, &subopt);
902
err_desc.error_pattern |= pattern;
903
}
904
905
if (optret == CC_OR_AMBIGUOUS) {
906
warnx("%s: ambiguous argument %s", __func__,
907
optarg);
908
retval = 1;
909
goto bailout;
910
} else if (optret == CC_OR_NOT_FOUND) {
911
warnx("%s: argument %s not found", __func__,
912
optarg);
913
retval = 1;
914
goto bailout;
915
}
916
break;
917
}
918
case 'r': {
919
char *tmpstr, *tmpstr2;
920
921
tmpstr = strdup(optarg);
922
if (tmpstr == NULL) {
923
warn("%s: error duplicating string %s",
924
__func__, optarg);
925
retval = 1;
926
goto bailout;
927
}
928
929
tmpstr2 = strsep(&tmpstr, ",");
930
if (tmpstr2 == NULL) {
931
warnx("%s: invalid -r argument %s", __func__,
932
optarg);
933
retval = 1;
934
free(tmpstr);
935
goto bailout;
936
}
937
lba = strtoull(tmpstr2, NULL, 0);
938
tmpstr2 = strsep(&tmpstr, ",");
939
if (tmpstr2 == NULL) {
940
warnx("%s: no len argument for -r lba,len, got"
941
" %s", __func__, optarg);
942
retval = 1;
943
free(tmpstr);
944
goto bailout;
945
}
946
len = strtoul(tmpstr2, NULL, 0);
947
free(tmpstr);
948
break;
949
}
950
case 's': {
951
struct get_hook hook;
952
char *sensestr;
953
954
sense_len = strtol(optarg, NULL, 0);
955
if (sense_len <= 0) {
956
warnx("invalid number of sense bytes %d",
957
sense_len);
958
retval = 1;
959
goto bailout;
960
}
961
962
sense_len = MIN(sense_len, SSD_FULL_SIZE);
963
964
hook.argc = argc - optind;
965
hook.argv = argv + optind;
966
hook.got = 0;
967
968
sensestr = cget(&hook, NULL);
969
if ((sensestr != NULL)
970
&& (sensestr[0] == '-')) {
971
fd_sense = 1;
972
} else {
973
buff_encode_visit(
974
(uint8_t *)&err_desc.custom_sense,
975
sense_len, sensestr, iget, &hook);
976
}
977
optind += hook.got;
978
break;
979
}
980
default:
981
break;
982
}
983
}
984
985
if (delete_id_set != 0) {
986
err_desc.serial = delete_id;
987
if (ioctl(fd, CTL_ERROR_INJECT_DELETE, &err_desc) == -1) {
988
warn("%s: error issuing CTL_ERROR_INJECT_DELETE ioctl",
989
__func__);
990
retval = 1;
991
}
992
goto bailout;
993
}
994
995
if (err_desc.lun_error == CTL_LUN_INJ_NONE) {
996
warnx("%s: error injection command (-i) needed",
997
__func__);
998
retval = 1;
999
goto bailout;
1000
} else if ((err_desc.lun_error == CTL_LUN_INJ_CUSTOM)
1001
&& (sense_len == 0)) {
1002
warnx("%s: custom error requires -s", __func__);
1003
retval = 1;
1004
goto bailout;
1005
}
1006
1007
if (continuous != 0)
1008
err_desc.lun_error |= CTL_LUN_INJ_CONTINUOUS;
1009
1010
/*
1011
* If fd_sense is set, we need to read the sense data the user
1012
* wants returned from stdin.
1013
*/
1014
if (fd_sense == 1) {
1015
ssize_t amt_read;
1016
int amt_to_read = sense_len;
1017
u_int8_t *buf_ptr = (uint8_t *)&err_desc.custom_sense;
1018
1019
for (amt_read = 0; amt_to_read > 0;
1020
amt_read = read(STDIN_FILENO, buf_ptr, amt_to_read)) {
1021
if (amt_read == -1) {
1022
warn("error reading sense data from stdin");
1023
retval = 1;
1024
goto bailout;
1025
}
1026
amt_to_read -= amt_read;
1027
buf_ptr += amt_read;
1028
}
1029
}
1030
1031
if (err_desc.error_pattern == CTL_LUN_PAT_NONE) {
1032
warnx("%s: command pattern (-p) needed", __func__);
1033
retval = 1;
1034
goto bailout;
1035
}
1036
1037
if (len != 0) {
1038
err_desc.error_pattern |= CTL_LUN_PAT_RANGE;
1039
/*
1040
* We could check here to see whether it's a read/write
1041
* command, but that will be pointless once we allow
1042
* custom patterns. At that point, the user could specify
1043
* a READ(6) CDB type, and we wouldn't have an easy way here
1044
* to verify whether range checking is possible there. The
1045
* user will just figure it out when his error never gets
1046
* executed.
1047
*/
1048
#if 0
1049
if ((err_desc.pattern & CTL_LUN_PAT_READWRITE) == 0) {
1050
warnx("%s: need read and/or write pattern if range "
1051
"is specified", __func__);
1052
retval = 1;
1053
goto bailout;
1054
}
1055
#endif
1056
err_desc.lba_range.lba = lba;
1057
err_desc.lba_range.len = len;
1058
}
1059
1060
if (ioctl(fd, CTL_ERROR_INJECT, &err_desc) == -1) {
1061
warn("%s: error issuing CTL_ERROR_INJECT ioctl", __func__);
1062
retval = 1;
1063
} else {
1064
printf("Error injection succeeded, serial number is %ju\n",
1065
(uintmax_t)err_desc.serial);
1066
}
1067
bailout:
1068
1069
return (retval);
1070
}
1071
1072
static int
1073
cctl_lunlist(int fd)
1074
{
1075
struct scsi_report_luns_data *lun_data;
1076
struct scsi_inquiry_data *inq_data;
1077
uint32_t num_luns;
1078
int initid;
1079
unsigned int i;
1080
int retval;
1081
1082
inq_data = NULL;
1083
initid = 7;
1084
1085
/*
1086
* XXX KDM assuming LUN 0 is fine, but we may need to change this
1087
* if we ever acquire the ability to have multiple targets.
1088
*/
1089
if ((retval = cctl_get_luns(fd, /*lun*/ 0, initid,
1090
/*retries*/ 2, &lun_data, &num_luns)) != 0)
1091
goto bailout;
1092
1093
inq_data = malloc(sizeof(*inq_data));
1094
if (inq_data == NULL) {
1095
warn("%s: couldn't allocate memory for inquiry data\n",
1096
__func__);
1097
retval = 1;
1098
goto bailout;
1099
}
1100
for (i = 0; i < num_luns; i++) {
1101
char scsi_path[40];
1102
int lun_val;
1103
1104
switch (lun_data->luns[i].lundata[0] & RPL_LUNDATA_ATYP_MASK) {
1105
case RPL_LUNDATA_ATYP_PERIPH:
1106
lun_val = lun_data->luns[i].lundata[1];
1107
break;
1108
case RPL_LUNDATA_ATYP_FLAT:
1109
lun_val = (lun_data->luns[i].lundata[0] &
1110
RPL_LUNDATA_FLAT_LUN_MASK) |
1111
(lun_data->luns[i].lundata[1] <<
1112
RPL_LUNDATA_FLAT_LUN_BITS);
1113
break;
1114
case RPL_LUNDATA_ATYP_LUN:
1115
case RPL_LUNDATA_ATYP_EXTLUN:
1116
default:
1117
fprintf(stdout, "Unsupported LUN format %d\n",
1118
lun_data->luns[i].lundata[0] &
1119
RPL_LUNDATA_ATYP_MASK);
1120
lun_val = -1;
1121
break;
1122
}
1123
if (lun_val == -1)
1124
continue;
1125
1126
if ((retval = cctl_get_inquiry(fd, lun_val, initid,
1127
/*retries*/ 2, scsi_path,
1128
sizeof(scsi_path),
1129
inq_data)) != 0) {
1130
goto bailout;
1131
}
1132
printf("%s", scsi_path);
1133
scsi_print_inquiry(inq_data);
1134
}
1135
bailout:
1136
1137
if (lun_data != NULL)
1138
free(lun_data);
1139
1140
if (inq_data != NULL)
1141
free(inq_data);
1142
1143
return (retval);
1144
}
1145
1146
static int
1147
cctl_sync_cache(int fd, int lun, int iid, int retries,
1148
int argc, char **argv, char *combinedopt)
1149
{
1150
union ctl_io *io;
1151
int cdb_size = -1;
1152
int retval;
1153
uint64_t our_lba = 0;
1154
uint32_t our_block_count = 0;
1155
int reladr = 0, immed = 0;
1156
int c;
1157
1158
retval = 0;
1159
1160
io = ctl_scsi_alloc_io(iid);
1161
if (io == NULL) {
1162
warnx("%s: can't allocate memory", __func__);
1163
return (1);
1164
}
1165
1166
while ((c = getopt(argc, argv, combinedopt)) != -1) {
1167
switch (c) {
1168
case 'b':
1169
our_block_count = strtoul(optarg, NULL, 0);
1170
break;
1171
case 'c':
1172
cdb_size = strtol(optarg, NULL, 0);
1173
break;
1174
case 'i':
1175
immed = 1;
1176
break;
1177
case 'l':
1178
our_lba = strtoull(optarg, NULL, 0);
1179
break;
1180
case 'r':
1181
reladr = 1;
1182
break;
1183
default:
1184
break;
1185
}
1186
}
1187
1188
if (cdb_size != -1) {
1189
switch (cdb_size) {
1190
case 10:
1191
case 16:
1192
break;
1193
default:
1194
warnx("%s: invalid cdbsize %d, valid sizes are 10 "
1195
"and 16", __func__, cdb_size);
1196
retval = 1;
1197
goto bailout;
1198
break; /* NOTREACHED */
1199
}
1200
} else
1201
cdb_size = 10;
1202
1203
ctl_scsi_sync_cache(/*io*/ io,
1204
/*immed*/ immed,
1205
/*reladr*/ reladr,
1206
/*minimum_cdb_size*/ cdb_size,
1207
/*starting_lba*/ our_lba,
1208
/*block_count*/ our_block_count,
1209
/*tag_type*/ CTL_TAG_SIMPLE,
1210
/*control*/ 0);
1211
1212
io->io_hdr.nexus.targ_lun = lun;
1213
io->io_hdr.nexus.initid = iid;
1214
1215
if (cctl_do_io(fd, retries, io, __func__) != 0) {
1216
retval = 1;
1217
goto bailout;
1218
}
1219
1220
if ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS) {
1221
fprintf(stdout, "Cache synchronized successfully\n");
1222
} else
1223
ctl_io_error_print(io, NULL, stderr);
1224
bailout:
1225
ctl_scsi_free_io(io);
1226
1227
return (retval);
1228
}
1229
1230
static int
1231
cctl_start_stop(int fd, int lun, int iid, int retries, int start,
1232
int argc, char **argv, char *combinedopt)
1233
{
1234
union ctl_io *io;
1235
char scsi_path[40];
1236
int immed = 0;
1237
int retval, c;
1238
1239
retval = 0;
1240
1241
io = ctl_scsi_alloc_io(iid);
1242
if (io == NULL) {
1243
warnx("%s: can't allocate memory", __func__);
1244
return (1);
1245
}
1246
1247
while ((c = getopt(argc, argv, combinedopt)) != -1) {
1248
switch (c) {
1249
case 'i':
1250
immed = 1;
1251
break;
1252
default:
1253
break;
1254
}
1255
}
1256
/*
1257
* Use an ordered tag for the stop command, to guarantee that any
1258
* pending I/O will finish before the stop command executes. This
1259
* would normally be the case anyway, since CTL will basically
1260
* treat the start/stop command as an ordered command with respect
1261
* to any other command except an INQUIRY. (See ctl_ser_table.c.)
1262
*/
1263
ctl_scsi_start_stop(/*io*/ io,
1264
/*start*/ start,
1265
/*load_eject*/ 0,
1266
/*immediate*/ immed,
1267
/*power_conditions*/ SSS_PC_START_VALID,
1268
/*ctl_tag_type*/ start ? CTL_TAG_SIMPLE :
1269
CTL_TAG_ORDERED,
1270
/*control*/ 0);
1271
1272
io->io_hdr.nexus.targ_lun = lun;
1273
io->io_hdr.nexus.initid = iid;
1274
1275
if (cctl_do_io(fd, retries, io, __func__) != 0) {
1276
retval = 1;
1277
goto bailout;
1278
}
1279
1280
ctl_scsi_path_string(&io->io_hdr, scsi_path, sizeof(scsi_path));
1281
if ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS) {
1282
fprintf(stdout, "%s LUN %s successfully\n", scsi_path,
1283
(start) ? "started" : "stopped");
1284
} else
1285
ctl_io_error_print(io, NULL, stderr);
1286
1287
bailout:
1288
ctl_scsi_free_io(io);
1289
1290
return (retval);
1291
}
1292
1293
static int
1294
cctl_mode_sense(int fd, int lun, int iid, int retries,
1295
int argc, char **argv, char *combinedopt)
1296
{
1297
union ctl_io *io;
1298
uint32_t datalen;
1299
uint8_t *dataptr;
1300
int pc = -1, cdbsize, retval, dbd = 0, subpage = -1;
1301
int list = 0;
1302
int page_code = -1;
1303
int c;
1304
1305
cdbsize = 0;
1306
retval = 0;
1307
dataptr = NULL;
1308
1309
io = ctl_scsi_alloc_io(iid);
1310
if (io == NULL) {
1311
warn("%s: can't allocate memory", __func__);
1312
return (1);
1313
}
1314
1315
while ((c = getopt(argc, argv, combinedopt)) != -1) {
1316
switch (c) {
1317
case 'P':
1318
pc = strtoul(optarg, NULL, 0);
1319
break;
1320
case 'S':
1321
subpage = strtoul(optarg, NULL, 0);
1322
break;
1323
case 'd':
1324
dbd = 1;
1325
break;
1326
case 'l':
1327
list = 1;
1328
break;
1329
case 'm':
1330
page_code = strtoul(optarg, NULL, 0);
1331
break;
1332
case 'c':
1333
cdbsize = strtol(optarg, NULL, 0);
1334
break;
1335
default:
1336
break;
1337
}
1338
}
1339
1340
if (((list == 0) && (page_code == -1))
1341
|| ((list != 0) && (page_code != -1))) {
1342
warnx("%s: you must specify either a page code (-m) or -l",
1343
__func__);
1344
retval = 1;
1345
goto bailout;
1346
}
1347
1348
if ((page_code != -1)
1349
&& ((page_code > SMS_ALL_PAGES_PAGE)
1350
|| (page_code < 0))) {
1351
warnx("%s: page code %d is out of range", __func__,
1352
page_code);
1353
retval = 1;
1354
goto bailout;
1355
}
1356
1357
if (list == 1) {
1358
page_code = SMS_ALL_PAGES_PAGE;
1359
if (pc != -1) {
1360
warnx("%s: arg -P makes no sense with -l",
1361
__func__);
1362
retval = 1;
1363
goto bailout;
1364
}
1365
if (subpage != -1) {
1366
warnx("%s: arg -S makes no sense with -l", __func__);
1367
retval = 1;
1368
goto bailout;
1369
}
1370
}
1371
1372
if (pc == -1)
1373
pc = SMS_PAGE_CTRL_CURRENT;
1374
else {
1375
if ((pc > 3)
1376
|| (pc < 0)) {
1377
warnx("%s: page control value %d is out of range: 0-3",
1378
__func__, pc);
1379
retval = 1;
1380
goto bailout;
1381
}
1382
}
1383
1384
1385
if ((subpage != -1)
1386
&& ((subpage > 255)
1387
|| (subpage < 0))) {
1388
warnx("%s: subpage code %d is out of range: 0-255", __func__,
1389
subpage);
1390
retval = 1;
1391
goto bailout;
1392
}
1393
if (cdbsize != 0) {
1394
switch (cdbsize) {
1395
case 6:
1396
case 10:
1397
break;
1398
default:
1399
warnx("%s: invalid cdbsize %d, valid sizes are 6 "
1400
"and 10", __func__, cdbsize);
1401
retval = 1;
1402
goto bailout;
1403
break;
1404
}
1405
} else
1406
cdbsize = 6;
1407
1408
if (subpage == -1)
1409
subpage = 0;
1410
1411
if (cdbsize == 6)
1412
datalen = 255;
1413
else
1414
datalen = 65535;
1415
1416
dataptr = (uint8_t *)malloc(datalen);
1417
if (dataptr == NULL) {
1418
warn("%s: can't allocate %d bytes", __func__, datalen);
1419
retval = 1;
1420
goto bailout;
1421
}
1422
1423
memset(dataptr, 0, datalen);
1424
1425
ctl_scsi_mode_sense(io,
1426
/*data_ptr*/ dataptr,
1427
/*data_len*/ datalen,
1428
/*dbd*/ dbd,
1429
/*llbaa*/ 0,
1430
/*page_code*/ page_code,
1431
/*pc*/ pc << 6,
1432
/*subpage*/ subpage,
1433
/*minimum_cdb_size*/ cdbsize,
1434
/*tag_type*/ CTL_TAG_SIMPLE,
1435
/*control*/ 0);
1436
1437
io->io_hdr.nexus.targ_lun = lun;
1438
io->io_hdr.nexus.initid = iid;
1439
1440
if (cctl_do_io(fd, retries, io, __func__) != 0) {
1441
retval = 1;
1442
goto bailout;
1443
}
1444
1445
if ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS) {
1446
int pages_len, used_len;
1447
uint32_t returned_len;
1448
uint8_t *ndataptr;
1449
1450
if (io->scsiio.cdb[0] == MODE_SENSE_6) {
1451
struct scsi_mode_hdr_6 *hdr6;
1452
int bdlen;
1453
1454
hdr6 = (struct scsi_mode_hdr_6 *)dataptr;
1455
1456
returned_len = hdr6->datalen + 1;
1457
bdlen = hdr6->block_descr_len;
1458
1459
ndataptr = (uint8_t *)((uint8_t *)&hdr6[1] + bdlen);
1460
} else {
1461
struct scsi_mode_hdr_10 *hdr10;
1462
int bdlen;
1463
1464
hdr10 = (struct scsi_mode_hdr_10 *)dataptr;
1465
1466
returned_len = scsi_2btoul(hdr10->datalen) + 2;
1467
bdlen = scsi_2btoul(hdr10->block_descr_len);
1468
1469
ndataptr = (uint8_t *)((uint8_t *)&hdr10[1] + bdlen);
1470
}
1471
/* just in case they can give us more than we allocated for */
1472
returned_len = min(returned_len, datalen);
1473
pages_len = returned_len - (ndataptr - dataptr);
1474
#if 0
1475
fprintf(stdout, "returned_len = %d, pages_len = %d\n",
1476
returned_len, pages_len);
1477
#endif
1478
if (list == 1) {
1479
fprintf(stdout, "Supported mode pages:\n");
1480
for (used_len = 0; used_len < pages_len;) {
1481
struct scsi_mode_page_header *header;
1482
1483
header = (struct scsi_mode_page_header *)
1484
&ndataptr[used_len];
1485
fprintf(stdout, "%d\n", header->page_code);
1486
used_len += header->page_length + 2;
1487
}
1488
} else {
1489
for (used_len = 0; used_len < pages_len; used_len++) {
1490
fprintf(stdout, "0x%x ", ndataptr[used_len]);
1491
if (((used_len+1) % 16) == 0)
1492
fprintf(stdout, "\n");
1493
}
1494
fprintf(stdout, "\n");
1495
}
1496
} else
1497
ctl_io_error_print(io, NULL, stderr);
1498
bailout:
1499
1500
ctl_scsi_free_io(io);
1501
1502
if (dataptr != NULL)
1503
free(dataptr);
1504
1505
return (retval);
1506
}
1507
1508
static int
1509
cctl_read_capacity(int fd, int lun, int iid, int retries,
1510
int argc, char **argv, char *combinedopt)
1511
{
1512
union ctl_io *io;
1513
struct scsi_read_capacity_data *data;
1514
struct scsi_read_capacity_data_long *longdata;
1515
int cdbsize = -1, retval;
1516
uint8_t *dataptr;
1517
int c;
1518
1519
cdbsize = 10;
1520
dataptr = NULL;
1521
retval = 0;
1522
1523
io = ctl_scsi_alloc_io(iid);
1524
if (io == NULL) {
1525
warn("%s: can't allocate memory\n", __func__);
1526
return (1);
1527
}
1528
1529
while ((c = getopt(argc, argv, combinedopt)) != -1) {
1530
switch (c) {
1531
case 'c':
1532
cdbsize = strtol(optarg, NULL, 0);
1533
break;
1534
default:
1535
break;
1536
}
1537
}
1538
if (cdbsize != -1) {
1539
switch (cdbsize) {
1540
case 10:
1541
case 16:
1542
break;
1543
default:
1544
warnx("%s: invalid cdbsize %d, valid sizes are 10 "
1545
"and 16", __func__, cdbsize);
1546
retval = 1;
1547
goto bailout;
1548
break; /* NOTREACHED */
1549
}
1550
} else
1551
cdbsize = 10;
1552
1553
dataptr = (uint8_t *)malloc(sizeof(*longdata));
1554
if (dataptr == NULL) {
1555
warn("%s: can't allocate %zd bytes\n", __func__,
1556
sizeof(*longdata));
1557
retval = 1;
1558
goto bailout;
1559
}
1560
memset(dataptr, 0, sizeof(*longdata));
1561
1562
retry:
1563
1564
switch (cdbsize) {
1565
case 10:
1566
ctl_scsi_read_capacity(io,
1567
/*data_ptr*/ dataptr,
1568
/*data_len*/ sizeof(*longdata),
1569
/*addr*/ 0,
1570
/*reladr*/ 0,
1571
/*pmi*/ 0,
1572
/*tag_type*/ CTL_TAG_SIMPLE,
1573
/*control*/ 0);
1574
break;
1575
case 16:
1576
ctl_scsi_read_capacity_16(io,
1577
/*data_ptr*/ dataptr,
1578
/*data_len*/ sizeof(*longdata),
1579
/*addr*/ 0,
1580
/*reladr*/ 0,
1581
/*pmi*/ 0,
1582
/*tag_type*/ CTL_TAG_SIMPLE,
1583
/*control*/ 0);
1584
break;
1585
}
1586
1587
io->io_hdr.nexus.initid = iid;
1588
io->io_hdr.nexus.targ_lun = lun;
1589
1590
if (cctl_do_io(fd, retries, io, __func__) != 0) {
1591
retval = 1;
1592
goto bailout;
1593
}
1594
1595
if ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS) {
1596
uint64_t maxlba;
1597
uint32_t blocksize;
1598
1599
if (cdbsize == 10) {
1600
1601
data = (struct scsi_read_capacity_data *)dataptr;
1602
1603
maxlba = scsi_4btoul(data->addr);
1604
blocksize = scsi_4btoul(data->length);
1605
1606
if (maxlba == 0xffffffff) {
1607
cdbsize = 16;
1608
goto retry;
1609
}
1610
} else {
1611
longdata=(struct scsi_read_capacity_data_long *)dataptr;
1612
1613
maxlba = scsi_8btou64(longdata->addr);
1614
blocksize = scsi_4btoul(longdata->length);
1615
}
1616
1617
fprintf(stdout, "Disk Capacity: %ju, Blocksize: %d\n",
1618
(uintmax_t)maxlba, blocksize);
1619
} else {
1620
ctl_io_error_print(io, NULL, stderr);
1621
}
1622
bailout:
1623
ctl_scsi_free_io(io);
1624
1625
if (dataptr != NULL)
1626
free(dataptr);
1627
1628
return (retval);
1629
}
1630
1631
static int
1632
cctl_read_write(int fd, int lun, int iid, int retries,
1633
int argc, char **argv, char *combinedopt,
1634
ctladm_cmdfunction command)
1635
{
1636
union ctl_io *io;
1637
int file_fd, do_stdio;
1638
int cdbsize = -1, databytes;
1639
uint8_t *dataptr;
1640
char *filename = NULL;
1641
int datalen = -1, blocksize = -1;
1642
uint64_t lba = 0;
1643
int lba_set = 0;
1644
int retval;
1645
int c;
1646
1647
retval = 0;
1648
do_stdio = 0;
1649
dataptr = NULL;
1650
file_fd = -1;
1651
1652
io = ctl_scsi_alloc_io(iid);
1653
if (io == NULL) {
1654
warn("%s: can't allocate memory\n", __func__);
1655
return (1);
1656
}
1657
1658
while ((c = getopt(argc, argv, combinedopt)) != -1) {
1659
switch (c) {
1660
case 'N':
1661
io->io_hdr.flags |= CTL_FLAG_NO_DATAMOVE;
1662
break;
1663
case 'b':
1664
blocksize = strtoul(optarg, NULL, 0);
1665
break;
1666
case 'c':
1667
cdbsize = strtoul(optarg, NULL, 0);
1668
break;
1669
case 'd':
1670
datalen = strtoul(optarg, NULL, 0);
1671
break;
1672
case 'f':
1673
filename = strdup(optarg);
1674
break;
1675
case 'l':
1676
lba = strtoull(optarg, NULL, 0);
1677
lba_set = 1;
1678
break;
1679
default:
1680
break;
1681
}
1682
}
1683
if (filename == NULL) {
1684
warnx("%s: you must supply a filename using -f", __func__);
1685
retval = 1;
1686
goto bailout;
1687
}
1688
1689
if (datalen == -1) {
1690
warnx("%s: you must specify the data length with -d", __func__);
1691
retval = 1;
1692
goto bailout;
1693
}
1694
1695
if (lba_set == 0) {
1696
warnx("%s: you must specify the LBA with -l", __func__);
1697
retval = 1;
1698
goto bailout;
1699
}
1700
1701
if (blocksize == -1) {
1702
warnx("%s: you must specify the blocksize with -b", __func__);
1703
retval = 1;
1704
goto bailout;
1705
}
1706
1707
if (cdbsize != -1) {
1708
switch (cdbsize) {
1709
case 6:
1710
case 10:
1711
case 12:
1712
case 16:
1713
break;
1714
default:
1715
warnx("%s: invalid cdbsize %d, valid sizes are 6, "
1716
"10, 12 or 16", __func__, cdbsize);
1717
retval = 1;
1718
goto bailout;
1719
break; /* NOTREACHED */
1720
}
1721
} else
1722
cdbsize = 6;
1723
1724
databytes = datalen * blocksize;
1725
dataptr = (uint8_t *)malloc(databytes);
1726
1727
if (dataptr == NULL) {
1728
warn("%s: can't allocate %d bytes\n", __func__, databytes);
1729
retval = 1;
1730
goto bailout;
1731
}
1732
if (strcmp(filename, "-") == 0) {
1733
if (command == CTLADM_CMD_READ)
1734
file_fd = STDOUT_FILENO;
1735
else
1736
file_fd = STDIN_FILENO;
1737
do_stdio = 1;
1738
} else {
1739
file_fd = open(filename, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
1740
if (file_fd == -1) {
1741
warn("%s: can't open file %s", __func__, filename);
1742
retval = 1;
1743
goto bailout;
1744
}
1745
}
1746
1747
memset(dataptr, 0, databytes);
1748
1749
if (command == CTLADM_CMD_WRITE) {
1750
int bytes_read;
1751
1752
bytes_read = read(file_fd, dataptr, databytes);
1753
if (bytes_read == -1) {
1754
warn("%s: error reading file %s", __func__, filename);
1755
retval = 1;
1756
goto bailout;
1757
}
1758
if (bytes_read != databytes) {
1759
warnx("%s: only read %d bytes from file %s",
1760
__func__, bytes_read, filename);
1761
retval = 1;
1762
goto bailout;
1763
}
1764
}
1765
ctl_scsi_read_write(io,
1766
/*data_ptr*/ dataptr,
1767
/*data_len*/ databytes,
1768
/*read_op*/ (command == CTLADM_CMD_READ) ? 1 : 0,
1769
/*byte2*/ 0,
1770
/*minimum_cdb_size*/ cdbsize,
1771
/*lba*/ lba,
1772
/*num_blocks*/ datalen,
1773
/*tag_type*/ CTL_TAG_SIMPLE,
1774
/*control*/ 0);
1775
1776
io->io_hdr.nexus.targ_lun = lun;
1777
io->io_hdr.nexus.initid = iid;
1778
1779
if (cctl_do_io(fd, retries, io, __func__) != 0) {
1780
retval = 1;
1781
goto bailout;
1782
}
1783
1784
if (((io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS)
1785
&& (command == CTLADM_CMD_READ)) {
1786
int bytes_written;
1787
1788
bytes_written = write(file_fd, dataptr, databytes);
1789
if (bytes_written == -1) {
1790
warn("%s: can't write to %s", __func__, filename);
1791
goto bailout;
1792
}
1793
} else if ((io->io_hdr.status & CTL_STATUS_MASK) != CTL_SUCCESS)
1794
ctl_io_error_print(io, NULL, stderr);
1795
1796
1797
bailout:
1798
1799
ctl_scsi_free_io(io);
1800
1801
if (dataptr != NULL)
1802
free(dataptr);
1803
1804
if ((do_stdio == 0)
1805
&& (file_fd != -1))
1806
close(file_fd);
1807
1808
return (retval);
1809
}
1810
1811
static int
1812
cctl_get_luns(int fd, int lun, int iid, int retries, struct
1813
scsi_report_luns_data **lun_data, uint32_t *num_luns)
1814
{
1815
union ctl_io *io;
1816
uint32_t nluns;
1817
int lun_datalen;
1818
int retval;
1819
1820
retval = 0;
1821
1822
io = ctl_scsi_alloc_io(iid);
1823
if (io == NULL) {
1824
warnx("%s: can't allocate memory", __func__);
1825
return (1);
1826
}
1827
1828
/*
1829
* lun_data includes space for 1 lun, allocate space for 4 initially.
1830
* If that isn't enough, we'll allocate more.
1831
*/
1832
nluns = 4;
1833
retry:
1834
lun_datalen = sizeof(*lun_data) +
1835
(nluns * sizeof(struct scsi_report_luns_lundata));
1836
*lun_data = malloc(lun_datalen);
1837
1838
if (*lun_data == NULL) {
1839
warnx("%s: can't allocate memory", __func__);
1840
ctl_scsi_free_io(io);
1841
return (1);
1842
}
1843
1844
ctl_scsi_report_luns(io,
1845
/*data_ptr*/ (uint8_t *)*lun_data,
1846
/*data_len*/ lun_datalen,
1847
/*select_report*/ RPL_REPORT_ALL,
1848
/*tag_type*/ CTL_TAG_SIMPLE,
1849
/*control*/ 0);
1850
1851
io->io_hdr.nexus.initid = iid;
1852
io->io_hdr.nexus.targ_lun = lun;
1853
1854
if (cctl_do_io(fd, retries, io, __func__) != 0) {
1855
retval = 1;
1856
goto bailout;
1857
}
1858
1859
if ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS) {
1860
uint32_t returned_len, returned_luns;
1861
1862
returned_len = scsi_4btoul((*lun_data)->length);
1863
returned_luns = returned_len / 8;
1864
if (returned_luns > nluns) {
1865
nluns = returned_luns;
1866
free(*lun_data);
1867
goto retry;
1868
}
1869
/* These should be the same */
1870
*num_luns = MIN(returned_luns, nluns);
1871
} else {
1872
ctl_io_error_print(io, NULL, stderr);
1873
retval = 1;
1874
}
1875
bailout:
1876
ctl_scsi_free_io(io);
1877
1878
return (retval);
1879
}
1880
1881
static int
1882
cctl_report_luns(int fd, int lun, int iid, int retries)
1883
{
1884
struct scsi_report_luns_data *lun_data;
1885
uint32_t num_luns, i;
1886
int retval;
1887
1888
lun_data = NULL;
1889
1890
if ((retval = cctl_get_luns(fd, lun, iid, retries, &lun_data,
1891
&num_luns)) != 0)
1892
goto bailout;
1893
1894
fprintf(stdout, "%u LUNs returned\n", num_luns);
1895
for (i = 0; i < num_luns; i++) {
1896
int lun_val;
1897
1898
/*
1899
* XXX KDM figure out a way to share this code with
1900
* cctl_lunlist()?
1901
*/
1902
switch (lun_data->luns[i].lundata[0] & RPL_LUNDATA_ATYP_MASK) {
1903
case RPL_LUNDATA_ATYP_PERIPH:
1904
lun_val = lun_data->luns[i].lundata[1];
1905
break;
1906
case RPL_LUNDATA_ATYP_FLAT:
1907
lun_val = (lun_data->luns[i].lundata[0] &
1908
RPL_LUNDATA_FLAT_LUN_MASK) |
1909
(lun_data->luns[i].lundata[1] <<
1910
RPL_LUNDATA_FLAT_LUN_BITS);
1911
break;
1912
case RPL_LUNDATA_ATYP_LUN:
1913
case RPL_LUNDATA_ATYP_EXTLUN:
1914
default:
1915
fprintf(stdout, "Unsupported LUN format %d\n",
1916
lun_data->luns[i].lundata[0] &
1917
RPL_LUNDATA_ATYP_MASK);
1918
lun_val = -1;
1919
break;
1920
}
1921
if (lun_val == -1)
1922
continue;
1923
1924
fprintf(stdout, "%d\n", lun_val);
1925
}
1926
1927
bailout:
1928
if (lun_data != NULL)
1929
free(lun_data);
1930
1931
return (retval);
1932
}
1933
1934
static int
1935
cctl_tur(int fd, int lun, int iid, int retries)
1936
{
1937
union ctl_io *io;
1938
1939
io = ctl_scsi_alloc_io(iid);
1940
if (io == NULL) {
1941
fprintf(stderr, "can't allocate memory\n");
1942
return (1);
1943
}
1944
1945
ctl_scsi_tur(io,
1946
/* tag_type */ CTL_TAG_SIMPLE,
1947
/* control */ 0);
1948
1949
io->io_hdr.nexus.targ_lun = lun;
1950
io->io_hdr.nexus.initid = iid;
1951
1952
if (cctl_do_io(fd, retries, io, __func__) != 0) {
1953
ctl_scsi_free_io(io);
1954
return (1);
1955
}
1956
1957
if ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS)
1958
fprintf(stdout, "Unit is ready\n");
1959
else
1960
ctl_io_error_print(io, NULL, stderr);
1961
1962
return (0);
1963
}
1964
1965
static int
1966
cctl_get_inquiry(int fd, int lun, int iid, int retries,
1967
char *path_str, int path_len,
1968
struct scsi_inquiry_data *inq_data)
1969
{
1970
union ctl_io *io;
1971
int retval;
1972
1973
retval = 0;
1974
1975
io = ctl_scsi_alloc_io(iid);
1976
if (io == NULL) {
1977
warnx("cctl_inquiry: can't allocate memory\n");
1978
return (1);
1979
}
1980
1981
ctl_scsi_inquiry(/*io*/ io,
1982
/*data_ptr*/ (uint8_t *)inq_data,
1983
/*data_len*/ sizeof(*inq_data),
1984
/*byte2*/ 0,
1985
/*page_code*/ 0,
1986
/*tag_type*/ CTL_TAG_SIMPLE,
1987
/*control*/ 0);
1988
1989
io->io_hdr.nexus.targ_lun = lun;
1990
io->io_hdr.nexus.initid = iid;
1991
1992
if (cctl_do_io(fd, retries, io, __func__) != 0) {
1993
retval = 1;
1994
goto bailout;
1995
}
1996
1997
if ((io->io_hdr.status & CTL_STATUS_MASK) != CTL_SUCCESS) {
1998
retval = 1;
1999
ctl_io_error_print(io, NULL, stderr);
2000
} else if (path_str != NULL)
2001
ctl_scsi_path_string(&io->io_hdr, path_str, path_len);
2002
2003
bailout:
2004
ctl_scsi_free_io(io);
2005
2006
return (retval);
2007
}
2008
2009
static int
2010
cctl_inquiry(int fd, int lun, int iid, int retries)
2011
{
2012
struct scsi_inquiry_data *inq_data;
2013
char scsi_path[40];
2014
int retval;
2015
2016
inq_data = malloc(sizeof(*inq_data));
2017
if (inq_data == NULL) {
2018
warnx("%s: can't allocate inquiry data", __func__);
2019
retval = 1;
2020
goto bailout;
2021
}
2022
2023
if ((retval = cctl_get_inquiry(fd, lun, iid, retries, scsi_path,
2024
sizeof(scsi_path), inq_data)) != 0)
2025
goto bailout;
2026
2027
printf("%s", scsi_path);
2028
scsi_print_inquiry(inq_data);
2029
2030
bailout:
2031
if (inq_data != NULL)
2032
free(inq_data);
2033
2034
return (retval);
2035
}
2036
2037
static int
2038
cctl_req_sense(int fd, int lun, int iid, int retries)
2039
{
2040
union ctl_io *io;
2041
struct scsi_sense_data *sense_data;
2042
int retval;
2043
2044
retval = 0;
2045
2046
io = ctl_scsi_alloc_io(iid);
2047
if (io == NULL) {
2048
warnx("cctl_req_sense: can't allocate memory\n");
2049
return (1);
2050
}
2051
sense_data = malloc(sizeof(*sense_data));
2052
memset(sense_data, 0, sizeof(*sense_data));
2053
2054
ctl_scsi_request_sense(/*io*/ io,
2055
/*data_ptr*/ (uint8_t *)sense_data,
2056
/*data_len*/ sizeof(*sense_data),
2057
/*byte2*/ 0,
2058
/*tag_type*/ CTL_TAG_SIMPLE,
2059
/*control*/ 0);
2060
2061
io->io_hdr.nexus.targ_lun = lun;
2062
io->io_hdr.nexus.initid = iid;
2063
2064
if (cctl_do_io(fd, retries, io, __func__) != 0) {
2065
retval = 1;
2066
goto bailout;
2067
}
2068
2069
if ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS) {
2070
bcopy(sense_data, &io->scsiio.sense_data, sizeof(*sense_data));
2071
io->scsiio.sense_len = sizeof(*sense_data);
2072
ctl_scsi_sense_print(&io->scsiio, NULL, stdout);
2073
} else
2074
ctl_io_error_print(io, NULL, stderr);
2075
2076
bailout:
2077
2078
ctl_scsi_free_io(io);
2079
free(sense_data);
2080
2081
return (retval);
2082
}
2083
2084
static int
2085
cctl_report_target_port_group(int fd, int lun, int iid)
2086
{
2087
union ctl_io *io;
2088
uint32_t datalen;
2089
uint8_t *dataptr;
2090
int retval;
2091
2092
dataptr = NULL;
2093
retval = 0;
2094
2095
io = ctl_scsi_alloc_io(iid);
2096
if (io == NULL) {
2097
warn("%s: can't allocate memory", __func__);
2098
return (1);
2099
}
2100
2101
datalen = 64;
2102
dataptr = (uint8_t *)malloc(datalen);
2103
if (dataptr == NULL) {
2104
warn("%s: can't allocate %d bytes", __func__, datalen);
2105
retval = 1;
2106
goto bailout;
2107
}
2108
2109
memset(dataptr, 0, datalen);
2110
2111
ctl_scsi_maintenance_in(/*io*/ io,
2112
/*data_ptr*/ dataptr,
2113
/*data_len*/ datalen,
2114
/*action*/ SA_RPRT_TRGT_GRP,
2115
/*tag_type*/ CTL_TAG_SIMPLE,
2116
/*control*/ 0);
2117
2118
io->io_hdr.nexus.targ_lun = lun;
2119
io->io_hdr.nexus.initid = iid;
2120
2121
if (cctl_do_io(fd, 0, io, __func__) != 0) {
2122
retval = 1;
2123
goto bailout;
2124
}
2125
2126
if ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS) {
2127
int returned_len, used_len;
2128
2129
returned_len = scsi_4btoul(&dataptr[0]) + 4;
2130
2131
for (used_len = 0; used_len < returned_len; used_len++) {
2132
fprintf(stdout, "0x%02x ", dataptr[used_len]);
2133
if (((used_len+1) % 8) == 0)
2134
fprintf(stdout, "\n");
2135
}
2136
fprintf(stdout, "\n");
2137
} else
2138
ctl_io_error_print(io, NULL, stderr);
2139
2140
bailout:
2141
ctl_scsi_free_io(io);
2142
2143
if (dataptr != NULL)
2144
free(dataptr);
2145
2146
return (retval);
2147
}
2148
2149
static int
2150
cctl_inquiry_vpd_devid(int fd, int lun, int iid)
2151
{
2152
union ctl_io *io;
2153
uint32_t datalen;
2154
uint8_t *dataptr;
2155
int retval;
2156
2157
retval = 0;
2158
dataptr = NULL;
2159
2160
io = ctl_scsi_alloc_io(iid);
2161
if (io == NULL) {
2162
warn("%s: can't allocate memory", __func__);
2163
return (1);
2164
}
2165
2166
datalen = 256;
2167
dataptr = (uint8_t *)malloc(datalen);
2168
if (dataptr == NULL) {
2169
warn("%s: can't allocate %d bytes", __func__, datalen);
2170
retval = 1;
2171
goto bailout;
2172
}
2173
2174
memset(dataptr, 0, datalen);
2175
2176
ctl_scsi_inquiry(/*io*/ io,
2177
/*data_ptr*/ dataptr,
2178
/*data_len*/ datalen,
2179
/*byte2*/ SI_EVPD,
2180
/*page_code*/ SVPD_DEVICE_ID,
2181
/*tag_type*/ CTL_TAG_SIMPLE,
2182
/*control*/ 0);
2183
2184
io->io_hdr.nexus.targ_lun = lun;
2185
io->io_hdr.nexus.initid = iid;
2186
2187
if (cctl_do_io(fd, 0, io, __func__) != 0) {
2188
retval = 1;
2189
goto bailout;
2190
}
2191
2192
if ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS) {
2193
int returned_len, used_len;
2194
2195
returned_len = scsi_2btoul(&dataptr[2]) + 4;
2196
2197
for (used_len = 0; used_len < returned_len; used_len++) {
2198
fprintf(stdout, "0x%02x ", dataptr[used_len]);
2199
if (((used_len+1) % 8) == 0)
2200
fprintf(stdout, "\n");
2201
}
2202
fprintf(stdout, "\n");
2203
} else
2204
ctl_io_error_print(io, NULL, stderr);
2205
2206
bailout:
2207
ctl_scsi_free_io(io);
2208
2209
if (dataptr != NULL)
2210
free(dataptr);
2211
2212
return (retval);
2213
}
2214
2215
static int
2216
cctl_persistent_reserve_in(int fd, int lun, int iid,
2217
int argc, char **argv, char *combinedopt,
2218
int retry_count)
2219
{
2220
union ctl_io *io;
2221
uint32_t datalen;
2222
uint8_t *dataptr;
2223
int action = -1;
2224
int retval;
2225
int c;
2226
2227
retval = 0;
2228
dataptr = NULL;
2229
2230
io = ctl_scsi_alloc_io(iid);
2231
if (io == NULL) {
2232
warn("%s: can't allocate memory", __func__);
2233
return (1);
2234
}
2235
2236
while ((c = getopt(argc, argv, combinedopt)) != -1) {
2237
switch (c) {
2238
case 'a':
2239
action = strtol(optarg, NULL, 0);
2240
break;
2241
default:
2242
break;
2243
}
2244
}
2245
2246
if (action < 0 || action > 2) {
2247
warn("action must be specified and in the range: 0-2");
2248
retval = 1;
2249
goto bailout;
2250
}
2251
2252
2253
datalen = 256;
2254
dataptr = (uint8_t *)malloc(datalen);
2255
if (dataptr == NULL) {
2256
warn("%s: can't allocate %d bytes", __func__, datalen);
2257
retval = 1;
2258
goto bailout;
2259
}
2260
2261
memset(dataptr, 0, datalen);
2262
2263
ctl_scsi_persistent_res_in(io,
2264
/*data_ptr*/ dataptr,
2265
/*data_len*/ datalen,
2266
/*action*/ action,
2267
/*tag_type*/ CTL_TAG_SIMPLE,
2268
/*control*/ 0);
2269
2270
io->io_hdr.nexus.targ_lun = lun;
2271
io->io_hdr.nexus.initid = iid;
2272
2273
if (cctl_do_io(fd, retry_count, io, __func__) != 0) {
2274
retval = 1;
2275
goto bailout;
2276
}
2277
2278
if ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS) {
2279
int returned_len, used_len;
2280
2281
switch (action) {
2282
case 0:
2283
returned_len = scsi_4btoul(&dataptr[4]) + 8;
2284
returned_len = min(returned_len, 256);
2285
break;
2286
case 1:
2287
returned_len = scsi_4btoul(&dataptr[4]) + 8;
2288
break;
2289
case 2:
2290
returned_len = 8;
2291
break;
2292
default:
2293
warnx("%s: invalid action %d", __func__, action);
2294
goto bailout;
2295
break; /* NOTREACHED */
2296
}
2297
2298
for (used_len = 0; used_len < returned_len; used_len++) {
2299
fprintf(stdout, "0x%02x ", dataptr[used_len]);
2300
if (((used_len+1) % 8) == 0)
2301
fprintf(stdout, "\n");
2302
}
2303
fprintf(stdout, "\n");
2304
} else
2305
ctl_io_error_print(io, NULL, stderr);
2306
2307
bailout:
2308
ctl_scsi_free_io(io);
2309
2310
if (dataptr != NULL)
2311
free(dataptr);
2312
2313
return (retval);
2314
}
2315
2316
static int
2317
cctl_persistent_reserve_out(int fd, int lun, int iid,
2318
int argc, char **argv, char *combinedopt,
2319
int retry_count)
2320
{
2321
union ctl_io *io;
2322
uint32_t datalen;
2323
uint64_t key = 0, sa_key = 0;
2324
int action = -1, restype = -1;
2325
uint8_t *dataptr;
2326
int retval;
2327
int c;
2328
2329
retval = 0;
2330
dataptr = NULL;
2331
2332
io = ctl_scsi_alloc_io(iid);
2333
if (io == NULL) {
2334
warn("%s: can't allocate memory", __func__);
2335
return (1);
2336
}
2337
2338
while ((c = getopt(argc, argv, combinedopt)) != -1) {
2339
switch (c) {
2340
case 'a':
2341
action = strtol(optarg, NULL, 0);
2342
break;
2343
case 'k':
2344
key = strtoull(optarg, NULL, 0);
2345
break;
2346
case 'r':
2347
restype = strtol(optarg, NULL, 0);
2348
break;
2349
case 's':
2350
sa_key = strtoull(optarg, NULL, 0);
2351
break;
2352
default:
2353
break;
2354
}
2355
}
2356
if (action < 0 || action > 5) {
2357
warn("action must be specified and in the range: 0-5");
2358
retval = 1;
2359
goto bailout;
2360
}
2361
2362
if (restype < 0 || restype > 5) {
2363
if (action != 0 && action != 5 && action != 3) {
2364
warn("'restype' must specified and in the range: 0-5");
2365
retval = 1;
2366
goto bailout;
2367
}
2368
}
2369
2370
datalen = 24;
2371
dataptr = (uint8_t *)malloc(datalen);
2372
if (dataptr == NULL) {
2373
warn("%s: can't allocate %d bytes", __func__, datalen);
2374
retval = 1;
2375
goto bailout;
2376
}
2377
2378
memset(dataptr, 0, datalen);
2379
2380
ctl_scsi_persistent_res_out(io,
2381
/*data_ptr*/ dataptr,
2382
/*data_len*/ datalen,
2383
/*action*/ action,
2384
/*type*/ restype,
2385
/*key*/ key,
2386
/*sa key*/ sa_key,
2387
/*tag_type*/ CTL_TAG_SIMPLE,
2388
/*control*/ 0);
2389
2390
io->io_hdr.nexus.targ_lun = lun;
2391
io->io_hdr.nexus.initid = iid;
2392
2393
if (cctl_do_io(fd, retry_count, io, __func__) != 0) {
2394
retval = 1;
2395
goto bailout;
2396
}
2397
if ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS) {
2398
char scsi_path[40];
2399
ctl_scsi_path_string(&io->io_hdr, scsi_path, sizeof(scsi_path));
2400
fprintf( stdout, "%sPERSISTENT RESERVE OUT executed "
2401
"successfully\n", scsi_path);
2402
} else
2403
ctl_io_error_print(io, NULL, stderr);
2404
2405
bailout:
2406
ctl_scsi_free_io(io);
2407
2408
if (dataptr != NULL)
2409
free(dataptr);
2410
2411
return (retval);
2412
}
2413
2414
static int
2415
cctl_create_lun(int fd, int argc, char **argv, char *combinedopt)
2416
{
2417
struct ctl_lun_req req;
2418
int device_type = -1;
2419
uint64_t lun_size = 0;
2420
uint32_t blocksize = 0, req_lun_id = 0;
2421
char *serial_num = NULL;
2422
char *device_id = NULL;
2423
int lun_size_set = 0, blocksize_set = 0, lun_id_set = 0;
2424
char *backend_name = NULL;
2425
nvlist_t *option_list;
2426
int retval = 0, c;
2427
2428
option_list = nvlist_create(0);
2429
if (option_list == NULL)
2430
err(1, "%s: unable to allocate nvlist", __func__);
2431
2432
while ((c = getopt(argc, argv, combinedopt)) != -1) {
2433
switch (c) {
2434
case 'b':
2435
backend_name = strdup(optarg);
2436
break;
2437
case 'B':
2438
blocksize = strtoul(optarg, NULL, 0);
2439
blocksize_set = 1;
2440
break;
2441
case 'd':
2442
device_id = strdup(optarg);
2443
break;
2444
case 'l':
2445
req_lun_id = strtoul(optarg, NULL, 0);
2446
lun_id_set = 1;
2447
break;
2448
case 'o': {
2449
char *tmpstr;
2450
char *name, *value;
2451
2452
tmpstr = strdup(optarg);
2453
name = strsep(&tmpstr, "=");
2454
if (name == NULL) {
2455
warnx("%s: option -o takes \"name=value\""
2456
"argument", __func__);
2457
retval = 1;
2458
goto bailout;
2459
}
2460
value = strsep(&tmpstr, "=");
2461
if (value == NULL) {
2462
warnx("%s: option -o takes \"name=value\""
2463
"argument", __func__);
2464
retval = 1;
2465
goto bailout;
2466
}
2467
free(tmpstr);
2468
nvlist_add_string(option_list, name, value);
2469
break;
2470
}
2471
case 's':
2472
if (strcasecmp(optarg, "auto") != 0) {
2473
retval = expand_number(optarg, &lun_size);
2474
if (retval != 0) {
2475
warn("%s: invalid -s argument",
2476
__func__);
2477
retval = 1;
2478
goto bailout;
2479
}
2480
}
2481
lun_size_set = 1;
2482
break;
2483
case 'S':
2484
serial_num = strdup(optarg);
2485
break;
2486
case 't':
2487
device_type = strtoul(optarg, NULL, 0);
2488
break;
2489
default:
2490
break;
2491
}
2492
}
2493
2494
if (backend_name == NULL) {
2495
warnx("%s: backend name (-b) must be specified", __func__);
2496
retval = 1;
2497
goto bailout;
2498
}
2499
2500
bzero(&req, sizeof(req));
2501
2502
strlcpy(req.backend, backend_name, sizeof(req.backend));
2503
req.reqtype = CTL_LUNREQ_CREATE;
2504
2505
if (blocksize_set != 0)
2506
req.reqdata.create.blocksize_bytes = blocksize;
2507
2508
if (lun_size_set != 0)
2509
req.reqdata.create.lun_size_bytes = lun_size;
2510
2511
if (lun_id_set != 0) {
2512
req.reqdata.create.flags |= CTL_LUN_FLAG_ID_REQ;
2513
req.reqdata.create.req_lun_id = req_lun_id;
2514
}
2515
2516
req.reqdata.create.flags |= CTL_LUN_FLAG_DEV_TYPE;
2517
2518
if (device_type != -1)
2519
req.reqdata.create.device_type = device_type;
2520
else
2521
req.reqdata.create.device_type = T_DIRECT;
2522
2523
if (serial_num != NULL) {
2524
strlcpy(req.reqdata.create.serial_num, serial_num,
2525
sizeof(req.reqdata.create.serial_num));
2526
req.reqdata.create.flags |= CTL_LUN_FLAG_SERIAL_NUM;
2527
}
2528
2529
if (device_id != NULL) {
2530
strlcpy(req.reqdata.create.device_id, device_id,
2531
sizeof(req.reqdata.create.device_id));
2532
req.reqdata.create.flags |= CTL_LUN_FLAG_DEVID;
2533
}
2534
2535
req.args = nvlist_pack(option_list, &req.args_len);
2536
if (req.args == NULL) {
2537
warn("%s: error packing nvlist", __func__);
2538
retval = 1;
2539
goto bailout;
2540
}
2541
2542
retval = ioctl(fd, CTL_LUN_REQ, &req);
2543
free(req.args);
2544
if (retval == -1) {
2545
warn("%s: error issuing CTL_LUN_REQ ioctl", __func__);
2546
retval = 1;
2547
goto bailout;
2548
}
2549
2550
switch (req.status) {
2551
case CTL_LUN_ERROR:
2552
warnx("LUN creation error: %s", req.error_str);
2553
retval = 1;
2554
goto bailout;
2555
case CTL_LUN_WARNING:
2556
warnx("LUN creation warning: %s", req.error_str);
2557
break;
2558
case CTL_LUN_OK:
2559
break;
2560
default:
2561
warnx("unknown LUN creation status: %d", req.status);
2562
retval = 1;
2563
goto bailout;
2564
}
2565
2566
fprintf(stdout, "LUN created successfully\n");
2567
fprintf(stdout, "backend: %s\n", req.backend);
2568
fprintf(stdout, "device type: %d\n",req.reqdata.create.device_type);
2569
fprintf(stdout, "LUN size: %ju bytes\n",
2570
(uintmax_t)req.reqdata.create.lun_size_bytes);
2571
fprintf(stdout, "blocksize %u bytes\n",
2572
req.reqdata.create.blocksize_bytes);
2573
fprintf(stdout, "LUN ID: %d\n", req.reqdata.create.req_lun_id);
2574
fprintf(stdout, "Serial Number: %s\n", req.reqdata.create.serial_num);
2575
fprintf(stdout, "Device ID: %s\n", req.reqdata.create.device_id);
2576
2577
bailout:
2578
nvlist_destroy(option_list);
2579
return (retval);
2580
}
2581
2582
static int
2583
cctl_rm_lun(int fd, int argc, char **argv, char *combinedopt)
2584
{
2585
struct ctl_lun_req req;
2586
uint32_t lun_id = 0;
2587
int lun_id_set = 0;
2588
char *backend_name = NULL;
2589
nvlist_t *option_list;
2590
int retval = 0, c;
2591
2592
option_list = nvlist_create(0);
2593
if (option_list == NULL)
2594
err(1, "%s: unable to allocate nvlist", __func__);
2595
2596
while ((c = getopt(argc, argv, combinedopt)) != -1) {
2597
switch (c) {
2598
case 'b':
2599
backend_name = strdup(optarg);
2600
break;
2601
case 'l':
2602
lun_id = strtoul(optarg, NULL, 0);
2603
lun_id_set = 1;
2604
break;
2605
case 'o': {
2606
char *tmpstr;
2607
char *name, *value;
2608
2609
tmpstr = strdup(optarg);
2610
name = strsep(&tmpstr, "=");
2611
if (name == NULL) {
2612
warnx("%s: option -o takes \"name=value\""
2613
"argument", __func__);
2614
retval = 1;
2615
goto bailout;
2616
}
2617
value = strsep(&tmpstr, "=");
2618
if (value == NULL) {
2619
warnx("%s: option -o takes \"name=value\""
2620
"argument", __func__);
2621
retval = 1;
2622
goto bailout;
2623
}
2624
free(tmpstr);
2625
nvlist_add_string(option_list, name, value);
2626
break;
2627
}
2628
default:
2629
break;
2630
}
2631
}
2632
2633
if (backend_name == NULL)
2634
errx(1, "%s: backend name (-b) must be specified", __func__);
2635
2636
if (lun_id_set == 0)
2637
errx(1, "%s: LUN id (-l) must be specified", __func__);
2638
2639
bzero(&req, sizeof(req));
2640
2641
strlcpy(req.backend, backend_name, sizeof(req.backend));
2642
req.reqtype = CTL_LUNREQ_RM;
2643
2644
req.reqdata.rm.lun_id = lun_id;
2645
2646
req.args = nvlist_pack(option_list, &req.args_len);
2647
if (req.args == NULL) {
2648
warn("%s: error packing nvlist", __func__);
2649
retval = 1;
2650
goto bailout;
2651
}
2652
2653
retval = ioctl(fd, CTL_LUN_REQ, &req);
2654
free(req.args);
2655
if (retval == -1) {
2656
warn("%s: error issuing CTL_LUN_REQ ioctl", __func__);
2657
retval = 1;
2658
goto bailout;
2659
}
2660
2661
switch (req.status) {
2662
case CTL_LUN_ERROR:
2663
warnx("LUN removal error: %s", req.error_str);
2664
retval = 1;
2665
goto bailout;
2666
case CTL_LUN_WARNING:
2667
warnx("LUN removal warning: %s", req.error_str);
2668
break;
2669
case CTL_LUN_OK:
2670
break;
2671
default:
2672
warnx("unknown LUN removal status: %d", req.status);
2673
retval = 1;
2674
goto bailout;
2675
}
2676
2677
printf("LUN %d removed successfully\n", lun_id);
2678
2679
bailout:
2680
nvlist_destroy(option_list);
2681
return (retval);
2682
}
2683
2684
static int
2685
cctl_modify_lun(int fd, int argc, char **argv, char *combinedopt)
2686
{
2687
struct ctl_lun_req req;
2688
uint64_t lun_size = 0;
2689
uint32_t lun_id = 0;
2690
int lun_id_set = 0, lun_size_set = 0;
2691
char *backend_name = NULL;
2692
nvlist_t *option_list;
2693
int retval = 0, c;
2694
2695
option_list = nvlist_create(0);
2696
if (option_list == NULL)
2697
err(1, "%s: unable to allocate nvlist", __func__);
2698
2699
while ((c = getopt(argc, argv, combinedopt)) != -1) {
2700
switch (c) {
2701
case 'b':
2702
backend_name = strdup(optarg);
2703
break;
2704
case 'l':
2705
lun_id = strtoul(optarg, NULL, 0);
2706
lun_id_set = 1;
2707
break;
2708
case 'o': {
2709
char *tmpstr;
2710
char *name, *value;
2711
2712
tmpstr = strdup(optarg);
2713
name = strsep(&tmpstr, "=");
2714
if (name == NULL) {
2715
warnx("%s: option -o takes \"name=value\""
2716
"argument", __func__);
2717
retval = 1;
2718
goto bailout;
2719
}
2720
value = strsep(&tmpstr, "=");
2721
if (value == NULL) {
2722
warnx("%s: option -o takes \"name=value\""
2723
"argument", __func__);
2724
retval = 1;
2725
goto bailout;
2726
}
2727
free(tmpstr);
2728
nvlist_add_string(option_list, name, value);
2729
break;
2730
}
2731
case 's':
2732
if (strcasecmp(optarg, "auto") != 0) {
2733
retval = expand_number(optarg, &lun_size);
2734
if (retval != 0) {
2735
warn("%s: invalid -s argument",
2736
__func__);
2737
retval = 1;
2738
goto bailout;
2739
}
2740
}
2741
lun_size_set = 1;
2742
break;
2743
default:
2744
break;
2745
}
2746
}
2747
2748
if (backend_name == NULL)
2749
errx(1, "%s: backend name (-b) must be specified", __func__);
2750
2751
if (lun_id_set == 0)
2752
errx(1, "%s: LUN id (-l) must be specified", __func__);
2753
2754
if (lun_size_set == 0 && nvlist_empty(option_list))
2755
errx(1, "%s: size (-s) or options (-o) must be specified",
2756
__func__);
2757
2758
bzero(&req, sizeof(req));
2759
2760
strlcpy(req.backend, backend_name, sizeof(req.backend));
2761
req.reqtype = CTL_LUNREQ_MODIFY;
2762
2763
req.reqdata.modify.lun_id = lun_id;
2764
req.reqdata.modify.lun_size_bytes = lun_size;
2765
2766
req.args = nvlist_pack(option_list, &req.args_len);
2767
if (req.args == NULL) {
2768
warn("%s: error packing nvlist", __func__);
2769
retval = 1;
2770
goto bailout;
2771
}
2772
2773
retval = ioctl(fd, CTL_LUN_REQ, &req);
2774
free(req.args);
2775
if (retval == -1) {
2776
warn("%s: error issuing CTL_LUN_REQ ioctl", __func__);
2777
retval = 1;
2778
goto bailout;
2779
}
2780
2781
switch (req.status) {
2782
case CTL_LUN_ERROR:
2783
warnx("LUN modification error: %s", req.error_str);
2784
retval = 1;
2785
goto bailout;
2786
case CTL_LUN_WARNING:
2787
warnx("LUN modification warning: %s", req.error_str);
2788
break;
2789
case CTL_LUN_OK:
2790
break;
2791
default:
2792
warnx("unknown LUN modification status: %d", req.status);
2793
retval = 1;
2794
goto bailout;
2795
}
2796
2797
printf("LUN %d modified successfully\n", lun_id);
2798
2799
bailout:
2800
nvlist_destroy(option_list);
2801
return (retval);
2802
}
2803
2804
struct cctl_islist_conn {
2805
int connection_id;
2806
char *initiator;
2807
char *initiator_addr;
2808
char *initiator_alias;
2809
char *target;
2810
char *target_alias;
2811
char *header_digest;
2812
char *data_digest;
2813
char *max_recv_data_segment_length;
2814
char *max_send_data_segment_length;
2815
char *max_burst_length;
2816
char *first_burst_length;
2817
char *offload;
2818
int immediate_data;
2819
int iser;
2820
STAILQ_ENTRY(cctl_islist_conn) links;
2821
};
2822
2823
struct cctl_islist_data {
2824
int num_conns;
2825
STAILQ_HEAD(,cctl_islist_conn) conn_list;
2826
struct cctl_islist_conn *cur_conn;
2827
int level;
2828
struct sbuf *cur_sb[32];
2829
};
2830
2831
static void
2832
cctl_islist_start_element(void *user_data, const char *name, const char **attr)
2833
{
2834
int i;
2835
struct cctl_islist_data *islist;
2836
struct cctl_islist_conn *cur_conn;
2837
2838
islist = (struct cctl_islist_data *)user_data;
2839
cur_conn = islist->cur_conn;
2840
islist->level++;
2841
if ((u_int)islist->level >= nitems(islist->cur_sb))
2842
errx(1, "%s: too many nesting levels, %zd max", __func__,
2843
nitems(islist->cur_sb));
2844
2845
islist->cur_sb[islist->level] = sbuf_new_auto();
2846
if (islist->cur_sb[islist->level] == NULL)
2847
err(1, "%s: Unable to allocate sbuf", __func__);
2848
2849
if (strcmp(name, "connection") == 0) {
2850
if (cur_conn != NULL)
2851
errx(1, "%s: improper connection element nesting",
2852
__func__);
2853
2854
cur_conn = calloc(1, sizeof(*cur_conn));
2855
if (cur_conn == NULL)
2856
err(1, "%s: cannot allocate %zd bytes", __func__,
2857
sizeof(*cur_conn));
2858
2859
islist->num_conns++;
2860
islist->cur_conn = cur_conn;
2861
2862
STAILQ_INSERT_TAIL(&islist->conn_list, cur_conn, links);
2863
2864
for (i = 0; attr[i] != NULL; i += 2) {
2865
if (strcmp(attr[i], "id") == 0) {
2866
cur_conn->connection_id =
2867
strtoull(attr[i+1], NULL, 0);
2868
} else {
2869
errx(1,
2870
"%s: invalid connection attribute %s = %s",
2871
__func__, attr[i], attr[i+1]);
2872
}
2873
}
2874
}
2875
}
2876
2877
static void
2878
cctl_islist_end_element(void *user_data, const char *name)
2879
{
2880
struct cctl_islist_data *islist;
2881
struct cctl_islist_conn *cur_conn;
2882
char *str;
2883
2884
islist = (struct cctl_islist_data *)user_data;
2885
cur_conn = islist->cur_conn;
2886
2887
if ((cur_conn == NULL)
2888
&& (strcmp(name, "ctlislist") != 0))
2889
errx(1, "%s: cur_conn == NULL! (name = %s)", __func__, name);
2890
2891
if (islist->cur_sb[islist->level] == NULL)
2892
errx(1, "%s: no valid sbuf at level %d (name %s)", __func__,
2893
islist->level, name);
2894
2895
sbuf_finish(islist->cur_sb[islist->level]);
2896
str = strdup(sbuf_data(islist->cur_sb[islist->level]));
2897
if (str == NULL)
2898
err(1, "%s can't allocate %zd bytes for string", __func__,
2899
sbuf_len(islist->cur_sb[islist->level]));
2900
2901
sbuf_delete(islist->cur_sb[islist->level]);
2902
islist->cur_sb[islist->level] = NULL;
2903
islist->level--;
2904
2905
if (strcmp(name, "initiator") == 0) {
2906
cur_conn->initiator = str;
2907
str = NULL;
2908
} else if (strcmp(name, "initiator_addr") == 0) {
2909
cur_conn->initiator_addr = str;
2910
str = NULL;
2911
} else if (strcmp(name, "initiator_alias") == 0) {
2912
cur_conn->initiator_alias = str;
2913
str = NULL;
2914
} else if (strcmp(name, "target") == 0) {
2915
cur_conn->target = str;
2916
str = NULL;
2917
} else if (strcmp(name, "target_alias") == 0) {
2918
cur_conn->target_alias = str;
2919
str = NULL;
2920
} else if (strcmp(name, "target_portal_group_tag") == 0) {
2921
} else if (strcmp(name, "header_digest") == 0) {
2922
cur_conn->header_digest = str;
2923
str = NULL;
2924
} else if (strcmp(name, "data_digest") == 0) {
2925
cur_conn->data_digest = str;
2926
str = NULL;
2927
} else if (strcmp(name, "max_recv_data_segment_length") == 0) {
2928
cur_conn->max_recv_data_segment_length = str;
2929
str = NULL;
2930
} else if (strcmp(name, "max_send_data_segment_length") == 0) {
2931
cur_conn->max_send_data_segment_length = str;
2932
str = NULL;
2933
} else if (strcmp(name, "max_burst_length") == 0) {
2934
cur_conn->max_burst_length = str;
2935
str = NULL;
2936
} else if (strcmp(name, "first_burst_length") == 0) {
2937
cur_conn->first_burst_length = str;
2938
str = NULL;
2939
} else if (strcmp(name, "offload") == 0) {
2940
cur_conn->offload = str;
2941
str = NULL;
2942
} else if (strcmp(name, "immediate_data") == 0) {
2943
cur_conn->immediate_data = atoi(str);
2944
} else if (strcmp(name, "iser") == 0) {
2945
cur_conn->iser = atoi(str);
2946
} else if (strcmp(name, "connection") == 0) {
2947
islist->cur_conn = NULL;
2948
} else if (strcmp(name, "ctlislist") == 0) {
2949
/* Nothing. */
2950
} else {
2951
/*
2952
* Unknown element; ignore it for forward compatibility.
2953
*/
2954
}
2955
2956
free(str);
2957
}
2958
2959
static void
2960
cctl_islist_char_handler(void *user_data, const XML_Char *str, int len)
2961
{
2962
struct cctl_islist_data *islist;
2963
2964
islist = (struct cctl_islist_data *)user_data;
2965
2966
sbuf_bcat(islist->cur_sb[islist->level], str, len);
2967
}
2968
2969
static int
2970
cctl_islist(int fd, int argc, char **argv, char *combinedopt)
2971
{
2972
struct ctl_iscsi req;
2973
struct cctl_islist_data islist;
2974
struct cctl_islist_conn *conn;
2975
XML_Parser parser;
2976
char *conn_str;
2977
int conn_len;
2978
int dump_xml = 0;
2979
int c, retval, verbose = 0;
2980
2981
retval = 0;
2982
conn_len = 4096;
2983
2984
bzero(&islist, sizeof(islist));
2985
STAILQ_INIT(&islist.conn_list);
2986
2987
while ((c = getopt(argc, argv, combinedopt)) != -1) {
2988
switch (c) {
2989
case 'v':
2990
verbose = 1;
2991
break;
2992
case 'x':
2993
dump_xml = 1;
2994
break;
2995
default:
2996
break;
2997
}
2998
}
2999
3000
retry:
3001
conn_str = malloc(conn_len);
3002
3003
bzero(&req, sizeof(req));
3004
req.type = CTL_ISCSI_LIST;
3005
req.data.list.alloc_len = conn_len;
3006
req.data.list.conn_xml = conn_str;
3007
3008
if (ioctl(fd, CTL_ISCSI, &req) == -1) {
3009
warn("%s: error issuing CTL_ISCSI ioctl", __func__);
3010
retval = 1;
3011
goto bailout;
3012
}
3013
3014
if (req.status == CTL_ISCSI_ERROR) {
3015
warnx("%s: error returned from CTL_ISCSI ioctl:\n%s",
3016
__func__, req.error_str);
3017
} else if (req.status == CTL_ISCSI_LIST_NEED_MORE_SPACE) {
3018
conn_len = conn_len << 1;
3019
goto retry;
3020
}
3021
3022
if (dump_xml != 0) {
3023
printf("%s", conn_str);
3024
goto bailout;
3025
}
3026
3027
parser = XML_ParserCreate(NULL);
3028
if (parser == NULL) {
3029
warn("%s: Unable to create XML parser", __func__);
3030
retval = 1;
3031
goto bailout;
3032
}
3033
3034
XML_SetUserData(parser, &islist);
3035
XML_SetElementHandler(parser, cctl_islist_start_element,
3036
cctl_islist_end_element);
3037
XML_SetCharacterDataHandler(parser, cctl_islist_char_handler);
3038
3039
retval = XML_Parse(parser, conn_str, strlen(conn_str), 1);
3040
if (retval != 1) {
3041
warnx("%s: Unable to parse XML: Error %d", __func__,
3042
XML_GetErrorCode(parser));
3043
XML_ParserFree(parser);
3044
retval = 1;
3045
goto bailout;
3046
}
3047
retval = 0;
3048
XML_ParserFree(parser);
3049
3050
if (verbose != 0) {
3051
STAILQ_FOREACH(conn, &islist.conn_list, links) {
3052
printf("%-25s %d\n", "Session ID:", conn->connection_id);
3053
printf("%-25s %s\n", "Initiator name:", conn->initiator);
3054
printf("%-25s %s\n", "Initiator portal:", conn->initiator_addr);
3055
printf("%-25s %s\n", "Initiator alias:", conn->initiator_alias);
3056
printf("%-25s %s\n", "Target name:", conn->target);
3057
printf("%-25s %s\n", "Target alias:", conn->target_alias);
3058
printf("%-25s %s\n", "Header digest:", conn->header_digest);
3059
printf("%-25s %s\n", "Data digest:", conn->data_digest);
3060
printf("%-25s %s\n", "MaxRecvDataSegmentLength:", conn->max_recv_data_segment_length);
3061
printf("%-25s %s\n", "MaxSendDataSegmentLength:", conn->max_send_data_segment_length);
3062
printf("%-25s %s\n", "MaxBurstLen:", conn->max_burst_length);
3063
printf("%-25s %s\n", "FirstBurstLen:", conn->first_burst_length);
3064
printf("%-25s %s\n", "ImmediateData:", conn->immediate_data ? "Yes" : "No");
3065
printf("%-25s %s\n", "iSER (RDMA):", conn->iser ? "Yes" : "No");
3066
printf("%-25s %s\n", "Offload driver:", conn->offload);
3067
printf("\n");
3068
}
3069
} else {
3070
printf("%4s %-16s %-36s %-36s\n", "ID", "Portal", "Initiator name",
3071
"Target name");
3072
STAILQ_FOREACH(conn, &islist.conn_list, links) {
3073
printf("%4u %-16s %-36s %-36s\n",
3074
conn->connection_id, conn->initiator_addr, conn->initiator,
3075
conn->target);
3076
}
3077
}
3078
bailout:
3079
free(conn_str);
3080
3081
return (retval);
3082
}
3083
3084
static int
3085
cctl_islogout(int fd, int argc, char **argv, char *combinedopt)
3086
{
3087
struct ctl_iscsi req;
3088
int retval = 0, c;
3089
int all = 0, connection_id = -1, nargs = 0;
3090
char *initiator_name = NULL, *initiator_addr = NULL;
3091
3092
while ((c = getopt(argc, argv, combinedopt)) != -1) {
3093
switch (c) {
3094
case 'a':
3095
all = 1;
3096
nargs++;
3097
break;
3098
case 'c':
3099
connection_id = strtoul(optarg, NULL, 0);
3100
nargs++;
3101
break;
3102
case 'i':
3103
initiator_name = strdup(optarg);
3104
if (initiator_name == NULL)
3105
err(1, "%s: strdup", __func__);
3106
nargs++;
3107
break;
3108
case 'p':
3109
initiator_addr = strdup(optarg);
3110
if (initiator_addr == NULL)
3111
err(1, "%s: strdup", __func__);
3112
nargs++;
3113
break;
3114
default:
3115
break;
3116
}
3117
}
3118
3119
if (nargs == 0)
3120
errx(1, "%s: either -a, -c, -i, or -p must be specified",
3121
__func__);
3122
if (nargs > 1)
3123
errx(1, "%s: only one of -a, -c, -i, or -p may be specified",
3124
__func__);
3125
3126
bzero(&req, sizeof(req));
3127
req.type = CTL_ISCSI_LOGOUT;
3128
req.data.logout.connection_id = connection_id;
3129
if (initiator_addr != NULL)
3130
strlcpy(req.data.logout.initiator_addr,
3131
initiator_addr, sizeof(req.data.logout.initiator_addr));
3132
if (initiator_name != NULL)
3133
strlcpy(req.data.logout.initiator_name,
3134
initiator_name, sizeof(req.data.logout.initiator_name));
3135
if (all != 0)
3136
req.data.logout.all = 1;
3137
3138
if (ioctl(fd, CTL_ISCSI, &req) == -1) {
3139
warn("%s: error issuing CTL_ISCSI ioctl", __func__);
3140
retval = 1;
3141
goto bailout;
3142
}
3143
3144
if (req.status != CTL_ISCSI_OK) {
3145
warnx("%s: error returned from CTL iSCSI logout request:\n%s",
3146
__func__, req.error_str);
3147
retval = 1;
3148
goto bailout;
3149
}
3150
3151
printf("iSCSI logout requests submitted\n");
3152
3153
bailout:
3154
return (retval);
3155
}
3156
3157
static int
3158
cctl_isterminate(int fd, int argc, char **argv, char *combinedopt)
3159
{
3160
struct ctl_iscsi req;
3161
int retval = 0, c;
3162
int all = 0, connection_id = -1, nargs = 0;
3163
char *initiator_name = NULL, *initiator_addr = NULL;
3164
3165
while ((c = getopt(argc, argv, combinedopt)) != -1) {
3166
switch (c) {
3167
case 'a':
3168
all = 1;
3169
nargs++;
3170
break;
3171
case 'c':
3172
connection_id = strtoul(optarg, NULL, 0);
3173
nargs++;
3174
break;
3175
case 'i':
3176
initiator_name = strdup(optarg);
3177
if (initiator_name == NULL)
3178
err(1, "%s: strdup", __func__);
3179
nargs++;
3180
break;
3181
case 'p':
3182
initiator_addr = strdup(optarg);
3183
if (initiator_addr == NULL)
3184
err(1, "%s: strdup", __func__);
3185
nargs++;
3186
break;
3187
default:
3188
break;
3189
}
3190
}
3191
3192
if (nargs == 0)
3193
errx(1, "%s: either -a, -c, -i, or -p must be specified",
3194
__func__);
3195
if (nargs > 1)
3196
errx(1, "%s: only one of -a, -c, -i, or -p may be specified",
3197
__func__);
3198
3199
bzero(&req, sizeof(req));
3200
req.type = CTL_ISCSI_TERMINATE;
3201
req.data.terminate.connection_id = connection_id;
3202
if (initiator_addr != NULL)
3203
strlcpy(req.data.terminate.initiator_addr,
3204
initiator_addr, sizeof(req.data.terminate.initiator_addr));
3205
if (initiator_name != NULL)
3206
strlcpy(req.data.terminate.initiator_name,
3207
initiator_name, sizeof(req.data.terminate.initiator_name));
3208
if (all != 0)
3209
req.data.terminate.all = 1;
3210
3211
if (ioctl(fd, CTL_ISCSI, &req) == -1) {
3212
warn("%s: error issuing CTL_ISCSI ioctl", __func__);
3213
retval = 1;
3214
goto bailout;
3215
}
3216
3217
if (req.status != CTL_ISCSI_OK) {
3218
warnx("%s: error returned from CTL iSCSI connection "
3219
"termination request:\n%s", __func__, req.error_str);
3220
retval = 1;
3221
goto bailout;
3222
}
3223
3224
printf("iSCSI connections terminated\n");
3225
3226
bailout:
3227
return (retval);
3228
}
3229
3230
/* Helper function to output values from an nvlist of strings. */
3231
static void
3232
print_nvlist(const nvlist_t *nvl, const char *fmt)
3233
{
3234
const char *name;
3235
void *cookie;
3236
3237
cookie = NULL;
3238
while ((name = nvlist_next(nvl, NULL, &cookie)) != NULL)
3239
printf(fmt, name, nvlist_get_string(nvl, name));
3240
}
3241
3242
/*
3243
* Backend LUN information.
3244
*/
3245
struct cctl_lun {
3246
uint64_t lun_id;
3247
char *backend_type;
3248
uint64_t size_blocks;
3249
uint32_t blocksize;
3250
char *serial_number;
3251
char *device_id;
3252
nvlist_t *attr_list;
3253
STAILQ_ENTRY(cctl_lun) links;
3254
};
3255
3256
struct cctl_devlist_data {
3257
int num_luns;
3258
STAILQ_HEAD(,cctl_lun) lun_list;
3259
struct cctl_lun *cur_lun;
3260
int level;
3261
struct sbuf *cur_sb[32];
3262
};
3263
3264
static void
3265
cctl_start_element(void *user_data, const char *name, const char **attr)
3266
{
3267
int i;
3268
struct cctl_devlist_data *devlist;
3269
struct cctl_lun *cur_lun;
3270
3271
devlist = (struct cctl_devlist_data *)user_data;
3272
cur_lun = devlist->cur_lun;
3273
devlist->level++;
3274
if ((u_int)devlist->level >= nitems(devlist->cur_sb))
3275
errx(1, "%s: too many nesting levels, %zd max", __func__,
3276
nitems(devlist->cur_sb));
3277
3278
devlist->cur_sb[devlist->level] = sbuf_new_auto();
3279
if (devlist->cur_sb[devlist->level] == NULL)
3280
err(1, "%s: Unable to allocate sbuf", __func__);
3281
3282
if (strcmp(name, "lun") == 0) {
3283
if (cur_lun != NULL)
3284
errx(1, "%s: improper lun element nesting", __func__);
3285
3286
cur_lun = calloc(1, sizeof(*cur_lun));
3287
if (cur_lun == NULL)
3288
err(1, "%s: cannot allocate %zd bytes", __func__,
3289
sizeof(*cur_lun));
3290
3291
devlist->num_luns++;
3292
devlist->cur_lun = cur_lun;
3293
3294
cur_lun->attr_list = nvlist_create(NV_FLAG_NO_UNIQUE);
3295
STAILQ_INSERT_TAIL(&devlist->lun_list, cur_lun, links);
3296
3297
for (i = 0; attr[i] != NULL; i += 2) {
3298
if (strcmp(attr[i], "id") == 0) {
3299
cur_lun->lun_id = strtoull(attr[i+1], NULL, 0);
3300
} else {
3301
errx(1, "%s: invalid LUN attribute %s = %s",
3302
__func__, attr[i], attr[i+1]);
3303
}
3304
}
3305
}
3306
}
3307
3308
static void
3309
cctl_end_element(void *user_data, const char *name)
3310
{
3311
struct cctl_devlist_data *devlist;
3312
struct cctl_lun *cur_lun;
3313
char *str;
3314
int error;
3315
3316
devlist = (struct cctl_devlist_data *)user_data;
3317
cur_lun = devlist->cur_lun;
3318
3319
if ((cur_lun == NULL)
3320
&& (strcmp(name, "ctllunlist") != 0))
3321
errx(1, "%s: cur_lun == NULL! (name = %s)", __func__, name);
3322
3323
if (devlist->cur_sb[devlist->level] == NULL)
3324
errx(1, "%s: no valid sbuf at level %d (name %s)", __func__,
3325
devlist->level, name);
3326
3327
if (sbuf_finish(devlist->cur_sb[devlist->level]) != 0)
3328
err(1, "%s: sbuf_finish", __func__);
3329
str = strdup(sbuf_data(devlist->cur_sb[devlist->level]));
3330
if (str == NULL)
3331
err(1, "%s can't allocate %zd bytes for string", __func__,
3332
sbuf_len(devlist->cur_sb[devlist->level]));
3333
3334
if (strlen(str) == 0) {
3335
free(str);
3336
str = NULL;
3337
}
3338
3339
sbuf_delete(devlist->cur_sb[devlist->level]);
3340
devlist->cur_sb[devlist->level] = NULL;
3341
devlist->level--;
3342
3343
if (strcmp(name, "backend_type") == 0) {
3344
cur_lun->backend_type = str;
3345
str = NULL;
3346
} else if (strcmp(name, "size") == 0) {
3347
cur_lun->size_blocks = strtoull(str, NULL, 0);
3348
} else if (strcmp(name, "blocksize") == 0) {
3349
cur_lun->blocksize = strtoul(str, NULL, 0);
3350
} else if (strcmp(name, "serial_number") == 0) {
3351
cur_lun->serial_number = str;
3352
str = NULL;
3353
} else if (strcmp(name, "device_id") == 0) {
3354
cur_lun->device_id = str;
3355
str = NULL;
3356
} else if (strcmp(name, "lun") == 0) {
3357
devlist->cur_lun = NULL;
3358
} else if (strcmp(name, "ctllunlist") == 0) {
3359
/* Nothing. */
3360
} else {
3361
nvlist_move_string(cur_lun->attr_list, name, str);
3362
error = nvlist_error(cur_lun->attr_list);
3363
if (error != 0)
3364
errc(1, error, "%s: can't add lun attribute nv pair",
3365
__func__);
3366
str = NULL;
3367
}
3368
3369
free(str);
3370
}
3371
3372
static void
3373
cctl_char_handler(void *user_data, const XML_Char *str, int len)
3374
{
3375
struct cctl_devlist_data *devlist;
3376
3377
devlist = (struct cctl_devlist_data *)user_data;
3378
3379
sbuf_bcat(devlist->cur_sb[devlist->level], str, len);
3380
}
3381
3382
static int
3383
cctl_devlist(int fd, int argc, char **argv, char *combinedopt)
3384
{
3385
struct ctl_lun_list list;
3386
struct cctl_devlist_data devlist;
3387
struct cctl_lun *lun;
3388
XML_Parser parser;
3389
char *lun_str;
3390
int lun_len;
3391
int dump_xml = 0;
3392
int retval, c;
3393
char *backend = NULL;
3394
int verbose = 0;
3395
3396
retval = 0;
3397
lun_len = 4096;
3398
3399
bzero(&devlist, sizeof(devlist));
3400
STAILQ_INIT(&devlist.lun_list);
3401
3402
while ((c = getopt(argc, argv, combinedopt)) != -1) {
3403
switch (c) {
3404
case 'b':
3405
backend = strdup(optarg);
3406
break;
3407
case 'v':
3408
verbose++;
3409
break;
3410
case 'x':
3411
dump_xml = 1;
3412
break;
3413
default:
3414
break;
3415
}
3416
}
3417
3418
retry:
3419
lun_str = malloc(lun_len);
3420
3421
bzero(&list, sizeof(list));
3422
list.alloc_len = lun_len;
3423
list.status = CTL_LUN_LIST_NONE;
3424
list.lun_xml = lun_str;
3425
3426
if (ioctl(fd, CTL_LUN_LIST, &list) == -1) {
3427
warn("%s: error issuing CTL_LUN_LIST ioctl", __func__);
3428
retval = 1;
3429
goto bailout;
3430
}
3431
3432
if (list.status == CTL_LUN_LIST_ERROR) {
3433
warnx("%s: error returned from CTL_LUN_LIST ioctl:\n%s",
3434
__func__, list.error_str);
3435
} else if (list.status == CTL_LUN_LIST_NEED_MORE_SPACE) {
3436
lun_len = lun_len << 1;
3437
goto retry;
3438
}
3439
3440
if (dump_xml != 0) {
3441
printf("%s", lun_str);
3442
goto bailout;
3443
}
3444
3445
parser = XML_ParserCreate(NULL);
3446
if (parser == NULL) {
3447
warn("%s: Unable to create XML parser", __func__);
3448
retval = 1;
3449
goto bailout;
3450
}
3451
3452
XML_SetUserData(parser, &devlist);
3453
XML_SetElementHandler(parser, cctl_start_element, cctl_end_element);
3454
XML_SetCharacterDataHandler(parser, cctl_char_handler);
3455
3456
retval = XML_Parse(parser, lun_str, strlen(lun_str), 1);
3457
if (retval != 1) {
3458
warnx("%s: Unable to parse XML: Error %d", __func__,
3459
XML_GetErrorCode(parser));
3460
XML_ParserFree(parser);
3461
retval = 1;
3462
goto bailout;
3463
}
3464
retval = 0;
3465
XML_ParserFree(parser);
3466
3467
printf("LUN Backend %18s %4s %-16s %-16s\n", "Size (Blocks)", "BS",
3468
"Serial Number", "Device ID");
3469
STAILQ_FOREACH(lun, &devlist.lun_list, links) {
3470
if ((backend != NULL)
3471
&& (strcmp(lun->backend_type, backend) != 0))
3472
continue;
3473
3474
printf("%3ju %-8s %18ju %4u %-16s %-16s\n",
3475
(uintmax_t)lun->lun_id,
3476
lun->backend_type, (uintmax_t)lun->size_blocks,
3477
lun->blocksize, lun->serial_number, lun->device_id);
3478
3479
if (verbose == 0)
3480
continue;
3481
3482
print_nvlist(lun->attr_list, " %s=%s\n");
3483
}
3484
bailout:
3485
free(lun_str);
3486
3487
return (retval);
3488
}
3489
3490
/*
3491
* Port information.
3492
*/
3493
struct cctl_port {
3494
uint64_t port_id;
3495
char *online;
3496
char *frontend_type;
3497
char *name;
3498
int pp, vp;
3499
char *controller, *target, *port, *lun_map;
3500
nvlist_t *host_list;
3501
nvlist_t *init_list;
3502
nvlist_t *lun_list;
3503
nvlist_t *attr_list;
3504
STAILQ_ENTRY(cctl_port) links;
3505
};
3506
3507
struct cctl_portlist_data {
3508
int num_ports;
3509
STAILQ_HEAD(,cctl_port) port_list;
3510
struct cctl_port *cur_port;
3511
int level;
3512
uint64_t cur_id;
3513
struct sbuf *cur_sb[32];
3514
};
3515
3516
static void
3517
cctl_start_pelement(void *user_data, const char *name, const char **attr)
3518
{
3519
int i;
3520
struct cctl_portlist_data *portlist;
3521
struct cctl_port *cur_port;
3522
3523
portlist = (struct cctl_portlist_data *)user_data;
3524
cur_port = portlist->cur_port;
3525
portlist->level++;
3526
if ((u_int)portlist->level >= nitems(portlist->cur_sb))
3527
errx(1, "%s: too many nesting levels, %zd max", __func__,
3528
nitems(portlist->cur_sb));
3529
3530
portlist->cur_sb[portlist->level] = sbuf_new_auto();
3531
if (portlist->cur_sb[portlist->level] == NULL)
3532
err(1, "%s: Unable to allocate sbuf", __func__);
3533
3534
portlist->cur_id = 0;
3535
for (i = 0; attr[i] != NULL; i += 2) {
3536
if (strcmp(attr[i], "id") == 0) {
3537
portlist->cur_id = strtoull(attr[i+1], NULL, 0);
3538
break;
3539
}
3540
}
3541
3542
if (strcmp(name, "targ_port") == 0) {
3543
if (cur_port != NULL)
3544
errx(1, "%s: improper port element nesting", __func__);
3545
3546
cur_port = calloc(1, sizeof(*cur_port));
3547
if (cur_port == NULL)
3548
err(1, "%s: cannot allocate %zd bytes", __func__,
3549
sizeof(*cur_port));
3550
3551
portlist->num_ports++;
3552
portlist->cur_port = cur_port;
3553
3554
cur_port->host_list = nvlist_create(0);
3555
cur_port->init_list = nvlist_create(0);
3556
cur_port->lun_list = nvlist_create(0);
3557
cur_port->attr_list = nvlist_create(NV_FLAG_NO_UNIQUE);
3558
cur_port->port_id = portlist->cur_id;
3559
STAILQ_INSERT_TAIL(&portlist->port_list, cur_port, links);
3560
}
3561
}
3562
3563
static void
3564
cctl_end_pelement(void *user_data, const char *name)
3565
{
3566
struct cctl_portlist_data *portlist;
3567
struct cctl_port *cur_port;
3568
char idname[16];
3569
char *str;
3570
int error;
3571
3572
portlist = (struct cctl_portlist_data *)user_data;
3573
cur_port = portlist->cur_port;
3574
3575
if ((cur_port == NULL)
3576
&& (strcmp(name, "ctlportlist") != 0))
3577
errx(1, "%s: cur_port == NULL! (name = %s)", __func__, name);
3578
3579
if (portlist->cur_sb[portlist->level] == NULL)
3580
errx(1, "%s: no valid sbuf at level %d (name %s)", __func__,
3581
portlist->level, name);
3582
3583
if (sbuf_finish(portlist->cur_sb[portlist->level]) != 0)
3584
err(1, "%s: sbuf_finish", __func__);
3585
str = strdup(sbuf_data(portlist->cur_sb[portlist->level]));
3586
if (str == NULL)
3587
err(1, "%s can't allocate %zd bytes for string", __func__,
3588
sbuf_len(portlist->cur_sb[portlist->level]));
3589
3590
if (strlen(str) == 0) {
3591
free(str);
3592
str = NULL;
3593
}
3594
3595
sbuf_delete(portlist->cur_sb[portlist->level]);
3596
portlist->cur_sb[portlist->level] = NULL;
3597
portlist->level--;
3598
3599
if (strcmp(name, "frontend_type") == 0) {
3600
cur_port->frontend_type = str;
3601
str = NULL;
3602
} else if (strcmp(name, "port_name") == 0) {
3603
cur_port->name = str;
3604
str = NULL;
3605
} else if (strcmp(name, "online") == 0) {
3606
cur_port->online = str;
3607
str = NULL;
3608
} else if (strcmp(name, "physical_port") == 0) {
3609
cur_port->pp = strtoull(str, NULL, 0);
3610
} else if (strcmp(name, "virtual_port") == 0) {
3611
cur_port->vp = strtoull(str, NULL, 0);
3612
} else if (strcmp(name, "target") == 0) {
3613
cur_port->target = str;
3614
str = NULL;
3615
} else if (strcmp(name, "subnqn") == 0) {
3616
cur_port->controller = str;
3617
str = NULL;
3618
} else if (strcmp(name, "port") == 0) {
3619
cur_port->port = str;
3620
str = NULL;
3621
} else if (strcmp(name, "lun_map") == 0) {
3622
cur_port->lun_map = str;
3623
str = NULL;
3624
} else if (strcmp(name, "targ_port") == 0) {
3625
portlist->cur_port = NULL;
3626
} else if (strcmp(name, "ctlportlist") == 0) {
3627
/* Nothing. */
3628
} else if (strcmp(name, "host") == 0) {
3629
snprintf(idname, sizeof(idname), "%ju", portlist->cur_id);
3630
nvlist_move_string(cur_port->host_list, idname, str);
3631
error = nvlist_error(cur_port->host_list);
3632
if (error != 0)
3633
errc(1, error, "%s: can't add host nv pair",
3634
__func__);
3635
str = NULL;
3636
} else if (strcmp(name, "initiator") == 0) {
3637
snprintf(idname, sizeof(idname), "%ju", portlist->cur_id);
3638
nvlist_move_string(cur_port->init_list, idname, str);
3639
error = nvlist_error(cur_port->init_list);
3640
if (error != 0)
3641
errc(1, error, "%s: can't add initiator nv pair",
3642
__func__);
3643
str = NULL;
3644
} else if (strcmp(name, "lun") == 0) {
3645
snprintf(idname, sizeof(idname), "%ju", portlist->cur_id);
3646
nvlist_move_string(cur_port->lun_list, idname, str);
3647
error = nvlist_error(cur_port->lun_list);
3648
if (error != 0)
3649
errc(1, error, "%s: can't add LUN nv pair", __func__);
3650
str = NULL;
3651
} else {
3652
nvlist_move_string(cur_port->attr_list, name, str);
3653
error = nvlist_error(cur_port->attr_list);
3654
if (error != 0)
3655
errc(1, error, "%s: can't add lun attribute nv pair",
3656
__func__);
3657
str = NULL;
3658
}
3659
3660
free(str);
3661
}
3662
3663
static void
3664
cctl_char_phandler(void *user_data, const XML_Char *str, int len)
3665
{
3666
struct cctl_portlist_data *portlist;
3667
3668
portlist = (struct cctl_portlist_data *)user_data;
3669
3670
sbuf_bcat(portlist->cur_sb[portlist->level], str, len);
3671
}
3672
3673
static int
3674
cctl_portlist(int fd, int argc, char **argv, char *combinedopt)
3675
{
3676
struct ctl_lun_list list;
3677
struct cctl_portlist_data portlist;
3678
struct cctl_port *port;
3679
XML_Parser parser;
3680
char *port_str = NULL;
3681
int port_len;
3682
int dump_xml = 0;
3683
int retval, c;
3684
char *frontend = NULL;
3685
uint64_t portarg = UINT64_MAX;
3686
int verbose = 0, init = 0, lun = 0, quiet = 0;
3687
3688
retval = 0;
3689
port_len = 4096;
3690
3691
bzero(&portlist, sizeof(portlist));
3692
STAILQ_INIT(&portlist.port_list);
3693
3694
while ((c = getopt(argc, argv, combinedopt)) != -1) {
3695
switch (c) {
3696
case 'f':
3697
frontend = strdup(optarg);
3698
break;
3699
case 'i':
3700
init++;
3701
break;
3702
case 'l':
3703
lun++;
3704
break;
3705
case 'p':
3706
portarg = strtoll(optarg, NULL, 0);
3707
break;
3708
case 'q':
3709
quiet++;
3710
break;
3711
case 'v':
3712
verbose++;
3713
break;
3714
case 'x':
3715
dump_xml = 1;
3716
break;
3717
default:
3718
break;
3719
}
3720
}
3721
3722
retry:
3723
port_str = (char *)realloc(port_str, port_len);
3724
3725
bzero(&list, sizeof(list));
3726
list.alloc_len = port_len;
3727
list.status = CTL_LUN_LIST_NONE;
3728
list.lun_xml = port_str;
3729
3730
if (ioctl(fd, CTL_PORT_LIST, &list) == -1) {
3731
warn("%s: error issuing CTL_PORT_LIST ioctl", __func__);
3732
retval = 1;
3733
goto bailout;
3734
}
3735
3736
if (list.status == CTL_LUN_LIST_ERROR) {
3737
warnx("%s: error returned from CTL_PORT_LIST ioctl:\n%s",
3738
__func__, list.error_str);
3739
} else if (list.status == CTL_LUN_LIST_NEED_MORE_SPACE) {
3740
port_len = port_len << 1;
3741
goto retry;
3742
}
3743
3744
if (dump_xml != 0) {
3745
printf("%s", port_str);
3746
goto bailout;
3747
}
3748
3749
parser = XML_ParserCreate(NULL);
3750
if (parser == NULL) {
3751
warn("%s: Unable to create XML parser", __func__);
3752
retval = 1;
3753
goto bailout;
3754
}
3755
3756
XML_SetUserData(parser, &portlist);
3757
XML_SetElementHandler(parser, cctl_start_pelement, cctl_end_pelement);
3758
XML_SetCharacterDataHandler(parser, cctl_char_phandler);
3759
3760
retval = XML_Parse(parser, port_str, strlen(port_str), 1);
3761
if (retval != 1) {
3762
warnx("%s: Unable to parse XML: Error %d", __func__,
3763
XML_GetErrorCode(parser));
3764
XML_ParserFree(parser);
3765
retval = 1;
3766
goto bailout;
3767
}
3768
retval = 0;
3769
XML_ParserFree(parser);
3770
3771
if (quiet == 0)
3772
printf("Port Online Frontend Name pp vp\n");
3773
STAILQ_FOREACH(port, &portlist.port_list, links) {
3774
if ((frontend != NULL)
3775
&& (strcmp(port->frontend_type, frontend) != 0))
3776
continue;
3777
3778
if ((portarg != UINT64_MAX) && (portarg != port->port_id))
3779
continue;
3780
3781
printf("%-4ju %-6s %-8s %-8s %-2d %-2d %s\n",
3782
(uintmax_t)port->port_id, port->online,
3783
port->frontend_type, port->name, port->pp, port->vp,
3784
port->port ? port->port : "");
3785
3786
if (init || verbose) {
3787
if (port->controller)
3788
printf(" Controller: %s\n", port->controller);
3789
print_nvlist(port->host_list, " Host %s: %s\n");
3790
if (port->target)
3791
printf(" Target: %s\n", port->target);
3792
print_nvlist(port->init_list, " Initiator %s: %s\n");
3793
}
3794
3795
if (lun || verbose) {
3796
if (port->lun_map) {
3797
if (nvlist_empty(port->lun_list))
3798
printf(" No LUNs mapped\n");
3799
else
3800
print_nvlist(port->lun_list,
3801
" LUN %s: %s\n");
3802
} else
3803
printf(" All LUNs mapped\n");
3804
}
3805
3806
if (verbose) {
3807
print_nvlist(port->attr_list, " %s=%s\n");
3808
}
3809
}
3810
bailout:
3811
free(port_str);
3812
3813
return (retval);
3814
}
3815
3816
static int
3817
cctl_lunmap(int fd, int argc, char **argv, char *combinedopt)
3818
{
3819
struct ctl_lun_map lm;
3820
int retval = 0, c;
3821
3822
retval = 0;
3823
lm.port = UINT32_MAX;
3824
lm.plun = UINT32_MAX;
3825
lm.lun = UINT32_MAX;
3826
3827
while ((c = getopt(argc, argv, combinedopt)) != -1) {
3828
switch (c) {
3829
case 'p':
3830
lm.port = strtoll(optarg, NULL, 0);
3831
break;
3832
case 'l':
3833
lm.plun = strtoll(optarg, NULL, 0);
3834
break;
3835
case 'L':
3836
lm.lun = strtoll(optarg, NULL, 0);
3837
break;
3838
default:
3839
break;
3840
}
3841
}
3842
3843
if (ioctl(fd, CTL_LUN_MAP, &lm) == -1) {
3844
warn("%s: error issuing CTL_LUN_MAP ioctl", __func__);
3845
retval = 1;
3846
}
3847
3848
return (retval);
3849
}
3850
3851
struct cctl_nvlist_conn {
3852
int connection_id;
3853
char *hostnqn;
3854
char *subnqn;
3855
int trtype;
3856
STAILQ_ENTRY(cctl_nvlist_conn) links;
3857
};
3858
3859
struct cctl_nvlist_data {
3860
int num_conns;
3861
STAILQ_HEAD(,cctl_nvlist_conn) conn_list;
3862
struct cctl_nvlist_conn *cur_conn;
3863
u_int level;
3864
struct sbuf *cur_sb[32];
3865
};
3866
3867
static void
3868
cctl_nvlist_start_element(void *user_data, const char *name, const char **attr)
3869
{
3870
int i;
3871
struct cctl_nvlist_data *nvlist;
3872
struct cctl_nvlist_conn *cur_conn;
3873
3874
nvlist = (struct cctl_nvlist_data *)user_data;
3875
cur_conn = nvlist->cur_conn;
3876
nvlist->level++;
3877
if ((u_int)nvlist->level >= nitems(nvlist->cur_sb))
3878
errx(1, "%s: too many nesting levels, %zd max", __func__,
3879
nitems(nvlist->cur_sb));
3880
3881
nvlist->cur_sb[nvlist->level] = sbuf_new_auto();
3882
if (nvlist->cur_sb[nvlist->level] == NULL)
3883
err(1, "%s: Unable to allocate sbuf", __func__);
3884
3885
if (strcmp(name, "connection") == 0) {
3886
if (cur_conn != NULL)
3887
errx(1, "%s: improper connection element nesting",
3888
__func__);
3889
3890
cur_conn = calloc(1, sizeof(*cur_conn));
3891
if (cur_conn == NULL)
3892
err(1, "%s: cannot allocate %zd bytes", __func__,
3893
sizeof(*cur_conn));
3894
3895
nvlist->num_conns++;
3896
nvlist->cur_conn = cur_conn;
3897
3898
STAILQ_INSERT_TAIL(&nvlist->conn_list, cur_conn, links);
3899
3900
for (i = 0; attr[i] != NULL; i += 2) {
3901
if (strcmp(attr[i], "id") == 0) {
3902
cur_conn->connection_id =
3903
strtoull(attr[i+1], NULL, 0);
3904
} else {
3905
errx(1,
3906
"%s: invalid connection attribute %s = %s",
3907
__func__, attr[i], attr[i+1]);
3908
}
3909
}
3910
}
3911
}
3912
3913
static void
3914
cctl_nvlist_end_element(void *user_data, const char *name)
3915
{
3916
struct cctl_nvlist_data *nvlist;
3917
struct cctl_nvlist_conn *cur_conn;
3918
char *str;
3919
3920
nvlist = (struct cctl_nvlist_data *)user_data;
3921
cur_conn = nvlist->cur_conn;
3922
3923
if ((cur_conn == NULL) && (strcmp(name, "ctlnvmflist") != 0))
3924
errx(1, "%s: cur_conn == NULL! (name = %s)", __func__, name);
3925
3926
if (nvlist->cur_sb[nvlist->level] == NULL)
3927
errx(1, "%s: no valid sbuf at level %d (name %s)", __func__,
3928
nvlist->level, name);
3929
3930
sbuf_finish(nvlist->cur_sb[nvlist->level]);
3931
str = strdup(sbuf_data(nvlist->cur_sb[nvlist->level]));
3932
if (str == NULL)
3933
err(1, "%s can't allocate %zd bytes for string", __func__,
3934
sbuf_len(nvlist->cur_sb[nvlist->level]));
3935
3936
sbuf_delete(nvlist->cur_sb[nvlist->level]);
3937
nvlist->cur_sb[nvlist->level] = NULL;
3938
nvlist->level--;
3939
3940
if (strcmp(name, "hostnqn") == 0) {
3941
cur_conn->hostnqn = str;
3942
str = NULL;
3943
} else if (strcmp(name, "subnqn") == 0) {
3944
cur_conn->subnqn = str;
3945
str = NULL;
3946
} else if (strcmp(name, "trtype") == 0) {
3947
cur_conn->trtype = atoi(str);
3948
} else if (strcmp(name, "connection") == 0) {
3949
nvlist->cur_conn = NULL;
3950
} else if (strcmp(name, "ctlnvmflist") == 0) {
3951
/* Nothing. */
3952
} else {
3953
/*
3954
* Unknown element; ignore it for forward compatibility.
3955
*/
3956
}
3957
3958
free(str);
3959
}
3960
3961
static void
3962
cctl_nvlist_char_handler(void *user_data, const XML_Char *str, int len)
3963
{
3964
struct cctl_nvlist_data *nvlist;
3965
3966
nvlist = (struct cctl_nvlist_data *)user_data;
3967
3968
sbuf_bcat(nvlist->cur_sb[nvlist->level], str, len);
3969
}
3970
3971
static const char *
3972
nvmf_transport_descr(u_int trtype)
3973
{
3974
static char buf[16];
3975
3976
switch (trtype) {
3977
case NVMF_TRTYPE_RDMA:
3978
return ("RDMA");
3979
case NVMF_TRTYPE_FC:
3980
return ("Fibre Channel");
3981
case NVMF_TRTYPE_TCP:
3982
return ("TCP");
3983
default:
3984
snprintf(buf, sizeof(buf), "%#x", trtype);
3985
return (buf);
3986
}
3987
}
3988
3989
static int
3990
cctl_nvlist(int fd, int argc, char **argv, char *combinedopt)
3991
{
3992
struct ctl_nvmf req;
3993
struct cctl_nvlist_data nvlist;
3994
struct cctl_nvlist_conn *conn;
3995
XML_Parser parser;
3996
char *conn_str;
3997
int conn_len;
3998
int dump_xml = 0;
3999
int c, retval, verbose = 0;
4000
4001
retval = 0;
4002
conn_len = 4096;
4003
4004
bzero(&nvlist, sizeof(nvlist));
4005
STAILQ_INIT(&nvlist.conn_list);
4006
4007
while ((c = getopt(argc, argv, combinedopt)) != -1) {
4008
switch (c) {
4009
case 'v':
4010
verbose = 1;
4011
break;
4012
case 'x':
4013
dump_xml = 1;
4014
break;
4015
default:
4016
break;
4017
}
4018
}
4019
4020
retry:
4021
conn_str = malloc(conn_len);
4022
4023
bzero(&req, sizeof(req));
4024
req.type = CTL_NVMF_LIST;
4025
req.data.list.alloc_len = conn_len;
4026
req.data.list.conn_xml = conn_str;
4027
4028
if (ioctl(fd, CTL_NVMF, &req) == -1) {
4029
warn("%s: error issuing CTL_NVMF ioctl", __func__);
4030
retval = 1;
4031
goto bailout;
4032
}
4033
4034
if (req.status == CTL_NVMF_ERROR) {
4035
warnx("%s: error returned from CTL_NVMF ioctl:\n%s",
4036
__func__, req.error_str);
4037
} else if (req.status == CTL_NVMF_LIST_NEED_MORE_SPACE) {
4038
conn_len = conn_len << 1;
4039
goto retry;
4040
}
4041
4042
if (dump_xml != 0) {
4043
printf("%s", conn_str);
4044
goto bailout;
4045
}
4046
4047
parser = XML_ParserCreate(NULL);
4048
if (parser == NULL) {
4049
warn("%s: Unable to create XML parser", __func__);
4050
retval = 1;
4051
goto bailout;
4052
}
4053
4054
XML_SetUserData(parser, &nvlist);
4055
XML_SetElementHandler(parser, cctl_nvlist_start_element,
4056
cctl_nvlist_end_element);
4057
XML_SetCharacterDataHandler(parser, cctl_nvlist_char_handler);
4058
4059
retval = XML_Parse(parser, conn_str, strlen(conn_str), 1);
4060
if (retval != 1) {
4061
warnx("%s: Unable to parse XML: Error %d", __func__,
4062
XML_GetErrorCode(parser));
4063
XML_ParserFree(parser);
4064
retval = 1;
4065
goto bailout;
4066
}
4067
retval = 0;
4068
XML_ParserFree(parser);
4069
4070
if (verbose != 0) {
4071
STAILQ_FOREACH(conn, &nvlist.conn_list, links) {
4072
printf("%-25s %d\n", "Controller ID:", conn->connection_id);
4073
printf("%-25s %s\n", "Host NQN:", conn->hostnqn);
4074
printf("%-25s %s\n", "Subsystem NQN:", conn->subnqn);
4075
printf("%-25s %s\n", "Transport:",
4076
nvmf_transport_descr(conn->trtype));
4077
printf("\n");
4078
}
4079
} else {
4080
printf("%4s %-16s %-36s %-36s\n", "ID", "Transport", "HostNQN",
4081
"SubNQN");
4082
STAILQ_FOREACH(conn, &nvlist.conn_list, links) {
4083
printf("%4u %-16s %-36s %-36s\n",
4084
conn->connection_id,
4085
nvmf_transport_descr(conn->trtype),
4086
conn->hostnqn, conn->subnqn);
4087
}
4088
}
4089
bailout:
4090
free(conn_str);
4091
4092
return (retval);
4093
}
4094
4095
static int
4096
cctl_nvterminate(int fd, int argc, char **argv, char *combinedopt)
4097
{
4098
struct ctl_nvmf req;
4099
int retval = 0, c;
4100
int all = 0, cntlid = -1, nargs = 0;
4101
char *hostnqn = NULL;
4102
4103
while ((c = getopt(argc, argv, combinedopt)) != -1) {
4104
switch (c) {
4105
case 'a':
4106
all = 1;
4107
nargs++;
4108
break;
4109
case 'c':
4110
cntlid = strtoul(optarg, NULL, 0);
4111
nargs++;
4112
break;
4113
case 'h':
4114
hostnqn = strdup(optarg);
4115
if (hostnqn == NULL)
4116
err(1, "%s: strdup", __func__);
4117
nargs++;
4118
break;
4119
default:
4120
break;
4121
}
4122
}
4123
4124
if (nargs == 0)
4125
errx(1, "%s: either -a, -c, or -h must be specified",
4126
__func__);
4127
if (nargs > 1)
4128
errx(1, "%s: only one of -a, -c, or -h may be specified",
4129
__func__);
4130
4131
bzero(&req, sizeof(req));
4132
req.type = CTL_NVMF_TERMINATE;
4133
req.data.terminate.cntlid = cntlid;
4134
if (hostnqn != NULL)
4135
strlcpy(req.data.terminate.hostnqn,
4136
hostnqn, sizeof(req.data.terminate.hostnqn));
4137
if (all != 0)
4138
req.data.terminate.all = 1;
4139
4140
if (ioctl(fd, CTL_NVMF, &req) == -1) {
4141
warn("%s: error issuing CTL_NVMF ioctl", __func__);
4142
retval = 1;
4143
goto bailout;
4144
}
4145
4146
if (req.status != CTL_NVMF_OK) {
4147
warnx("%s: error returned from CTL NVMeoF connection "
4148
"termination request:\n%s", __func__, req.error_str);
4149
retval = 1;
4150
goto bailout;
4151
}
4152
4153
printf("NVMeoF connections terminated\n");
4154
4155
bailout:
4156
return (retval);
4157
}
4158
4159
void
4160
usage(int error)
4161
{
4162
fprintf(error ? stderr : stdout,
4163
"Usage:\n"
4164
"Primary commands:\n"
4165
" ctladm tur [dev_id][general options]\n"
4166
" ctladm inquiry [dev_id][general options]\n"
4167
" ctladm devid [dev_id][general options]\n"
4168
" ctladm reqsense [dev_id][general options]\n"
4169
" ctladm reportluns [dev_id][general options]\n"
4170
" ctladm read [dev_id][general options] <-l lba> <-d len>\n"
4171
" <-f file|-> <-b blocksize> [-c cdbsize][-N]\n"
4172
" ctladm write [dev_id][general options] <-l lba> <-d len>\n"
4173
" <-f file|-> <-b blocksize> [-c cdbsize][-N]\n"
4174
" ctladm readcap [dev_id][general options] [-c cdbsize]\n"
4175
" ctladm modesense [dev_id][general options] <-m page|-l> [-P pc]\n"
4176
" [-d] [-S subpage] [-c cdbsize]\n"
4177
" ctladm prin [dev_id][general options] <-a action>\n"
4178
" ctladm prout [dev_id][general options] <-a action>\n"
4179
" <-r restype] [-k key] [-s sa_key]\n"
4180
" ctladm rtpg [dev_id][general options]\n"
4181
" ctladm start [dev_id][general options] [-i] [-o]\n"
4182
" ctladm stop [dev_id][general options] [-i] [-o]\n"
4183
" ctladm synccache [dev_id][general options] [-l lba]\n"
4184
" [-b blockcount] [-r] [-i] [-c cdbsize]\n"
4185
" ctladm create <-b backend> [-B blocksize] [-d device_id]\n"
4186
" [-l lun_id] [-o name=value] [-s size_bytes]\n"
4187
" [-S serial_num] [-t dev_type]\n"
4188
" ctladm remove <-b backend> <-l lun_id> [-o name=value]\n"
4189
" ctladm modify <-b backend> <-l lun_id> <-s size_bytes>\n"
4190
" ctladm devlist [-b backend] [-v] [-x]\n"
4191
" ctladm lunlist\n"
4192
" ctladm lunmap -p targ_port [-l pLUN] [-L cLUN]\n"
4193
" ctladm delay [dev_id] <-l datamove|done> [-T oneshot|cont]\n"
4194
" [-t secs]\n"
4195
" ctladm inject [dev_id] <-i action> <-p pattern> [-r lba,len]\n"
4196
" [-s len fmt [args]] [-c] [-d delete_id]\n"
4197
" ctladm port <-o <on|off> | [-w wwnn][-W wwpn]>\n"
4198
" [-p targ_port] [-t port_type]\n"
4199
" <-c> [-d driver] [-O name=value]\n"
4200
" <-r> <-p targ_port>\n"
4201
" ctladm portlist [-f frontend] [-i] [-p targ_port] [-q] [-v] [-x]\n"
4202
" ctladm islist [-v | -x]\n"
4203
" ctladm islogout <-a | -c connection-id | -i name | -p portal>\n"
4204
" ctladm isterminate <-a | -c connection-id | -i name | -p portal>\n"
4205
" ctladm nvlist [-v | -x]\n"
4206
" ctladm nvterminate <-a | -c controller-id | -h name>\n"
4207
" ctladm dumpooa\n"
4208
" ctladm dumpstructs\n"
4209
" ctladm help\n"
4210
"General Options:\n"
4211
"-I initiator_id : defaults to 7, used to change the initiator id\n"
4212
"-C retries : specify the number of times to retry this command\n"
4213
"-D devicename : specify the device to operate on\n"
4214
" : (default is %s)\n"
4215
"read/write options:\n"
4216
"-l lba : logical block address\n"
4217
"-d len : read/write length, in blocks\n"
4218
"-f file|- : write/read data to/from file or stdout/stdin\n"
4219
"-b blocksize : block size, in bytes\n"
4220
"-c cdbsize : specify minimum cdb size: 6, 10, 12 or 16\n"
4221
"-N : do not copy data to/from userland\n"
4222
"readcapacity options:\n"
4223
"-c cdbsize : specify minimum cdb size: 10 or 16\n"
4224
"modesense options:\n"
4225
"-m page : specify the mode page to view\n"
4226
"-l : request a list of supported pages\n"
4227
"-P pc : specify the page control value: 0-3 (current,\n"
4228
" changeable, default, saved, respectively)\n"
4229
"-d : disable block descriptors for mode sense\n"
4230
"-S subpage : specify a subpage\n"
4231
"-c cdbsize : specify minimum cdb size: 6 or 10\n"
4232
"persistent reserve in options:\n"
4233
"-a action : specify the action value: 0-2 (read key, read\n"
4234
" reservation, read capabilities, respectively)\n"
4235
"persistent reserve out options:\n"
4236
"-a action : specify the action value: 0-5 (register, reserve,\n"
4237
" release, clear, preempt, register and ignore)\n"
4238
"-k key : key value\n"
4239
"-s sa_key : service action value\n"
4240
"-r restype : specify the reservation type: 0-5(wr ex, ex ac,\n"
4241
" wr ex ro, ex ac ro, wr ex ar, ex ac ar)\n"
4242
"start/stop options:\n"
4243
"-i : set the immediate bit (CTL does not support this)\n"
4244
"-o : set the on/offline bit\n"
4245
"synccache options:\n"
4246
"-l lba : set the starting LBA\n"
4247
"-b blockcount : set the length to sync in blocks\n"
4248
"-r : set the relative addressing bit\n"
4249
"-i : set the immediate bit\n"
4250
"-c cdbsize : specify minimum cdb size: 10 or 16\n"
4251
"create options:\n"
4252
"-b backend : backend name (\"block\", \"ramdisk\", etc.)\n"
4253
"-B blocksize : LUN blocksize in bytes (some backends)\n"
4254
"-d device_id : SCSI VPD page 0x83 ID\n"
4255
"-l lun_id : requested LUN number\n"
4256
"-o name=value : backend-specific options, multiple allowed\n"
4257
"-s size_bytes : LUN size in bytes (some backends)\n"
4258
"-S serial_num : SCSI VPD page 0x80 serial number\n"
4259
"-t dev_type : SCSI device type (0=disk, 3=processor)\n"
4260
"remove options:\n"
4261
"-b backend : backend name (\"block\", \"ramdisk\", etc.)\n"
4262
"-l lun_id : LUN number to delete\n"
4263
"-o name=value : backend-specific options, multiple allowed\n"
4264
"devlist options:\n"
4265
"-b backend : list devices from specified backend only\n"
4266
"-v : be verbose, show backend attributes\n"
4267
"-x : dump raw XML\n"
4268
"delay options:\n"
4269
"-l datamove|done : delay command at datamove or done phase\n"
4270
"-T oneshot : delay one command, then resume normal completion\n"
4271
"-T cont : delay all commands\n"
4272
"-t secs : number of seconds to delay\n"
4273
"inject options:\n"
4274
"-i error_action : action to perform\n"
4275
"-p pattern : command pattern to look for\n"
4276
"-r lba,len : LBA range for pattern\n"
4277
"-s len fmt [args] : sense data for custom sense action\n"
4278
"-c : continuous operation\n"
4279
"-d delete_id : error id to delete\n"
4280
"port options:\n"
4281
"-c : create new ioctl or iscsi frontend port\n"
4282
"-d : specify ioctl or iscsi frontend type\n"
4283
"-o on|off : turn frontend ports on or off\n"
4284
"-O pp|vp : create new frontend port using pp and/or vp\n"
4285
"-w wwnn : set WWNN for one frontend\n"
4286
"-W wwpn : set WWPN for one frontend\n"
4287
"-t port_type : specify fc, scsi, ioctl, internal frontend type\n"
4288
"-p targ_port : specify target port number\n"
4289
"-r : remove frontend port\n"
4290
"portlist options:\n"
4291
"-f frontend : specify frontend type\n"
4292
"-i : report target and connected initiator names\n"
4293
"-l : report LUN mapping\n"
4294
"-p targ_port : specify target port number\n"
4295
"-q : omit header in list output\n"
4296
"-v : verbose output (report all port options)\n"
4297
"-x : output port list in XML format\n"
4298
"lunmap options:\n"
4299
"-p targ_port : specify target port number\n"
4300
"-l pLUN : specify port-visible LUN\n"
4301
"-L cLUN : specify CTL LUN\n",
4302
CTL_DEFAULT_DEV);
4303
}
4304
4305
int
4306
main(int argc, char **argv)
4307
{
4308
int c;
4309
ctladm_cmdfunction command;
4310
ctladm_cmdargs cmdargs;
4311
ctladm_optret optreturn;
4312
char *device;
4313
const char *mainopt = "C:D:I:";
4314
const char *subopt = NULL;
4315
char combinedopt[256];
4316
int lun;
4317
int optstart = 2;
4318
int retval, fd;
4319
int retries;
4320
int initid;
4321
int saved_errno;
4322
4323
retval = 0;
4324
cmdargs = CTLADM_ARG_NONE;
4325
command = CTLADM_CMD_HELP;
4326
device = NULL;
4327
fd = -1;
4328
retries = 0;
4329
lun = 0;
4330
initid = 7;
4331
4332
if (argc < 2) {
4333
usage(1);
4334
retval = 1;
4335
goto bailout;
4336
}
4337
4338
/*
4339
* Get the base option.
4340
*/
4341
optreturn = getoption(option_table,argv[1], &command, &cmdargs,&subopt);
4342
4343
if (optreturn == CC_OR_AMBIGUOUS) {
4344
warnx("ambiguous option %s", argv[1]);
4345
usage(0);
4346
exit(1);
4347
} else if (optreturn == CC_OR_NOT_FOUND) {
4348
warnx("option %s not found", argv[1]);
4349
usage(0);
4350
exit(1);
4351
}
4352
4353
if (cmdargs & CTLADM_ARG_NEED_TL) {
4354
if ((argc < 3) || (!isdigit(argv[2][0]))) {
4355
warnx("option %s requires a lun argument",
4356
argv[1]);
4357
usage(0);
4358
exit(1);
4359
}
4360
lun = strtol(argv[2], NULL, 0);
4361
4362
cmdargs |= CTLADM_ARG_TARG_LUN;
4363
optstart++;
4364
}
4365
4366
/*
4367
* Ahh, getopt(3) is a pain.
4368
*
4369
* This is a gross hack. There really aren't many other good
4370
* options (excuse the pun) for parsing options in a situation like
4371
* this. getopt is kinda braindead, so you end up having to run
4372
* through the options twice, and give each invocation of getopt
4373
* the option string for the other invocation.
4374
*
4375
* You would think that you could just have two groups of options.
4376
* The first group would get parsed by the first invocation of
4377
* getopt, and the second group would get parsed by the second
4378
* invocation of getopt. It doesn't quite work out that way. When
4379
* the first invocation of getopt finishes, it leaves optind pointing
4380
* to the argument _after_ the first argument in the second group.
4381
* So when the second invocation of getopt comes around, it doesn't
4382
* recognize the first argument it gets and then bails out.
4383
*
4384
* A nice alternative would be to have a flag for getopt that says
4385
* "just keep parsing arguments even when you encounter an unknown
4386
* argument", but there isn't one. So there's no real clean way to
4387
* easily parse two sets of arguments without having one invocation
4388
* of getopt know about the other.
4389
*
4390
* Without this hack, the first invocation of getopt would work as
4391
* long as the generic arguments are first, but the second invocation
4392
* (in the subfunction) would fail in one of two ways. In the case
4393
* where you don't set optreset, it would fail because optind may be
4394
* pointing to the argument after the one it should be pointing at.
4395
* In the case where you do set optreset, and reset optind, it would
4396
* fail because getopt would run into the first set of options, which
4397
* it doesn't understand.
4398
*
4399
* All of this would "sort of" work if you could somehow figure out
4400
* whether optind had been incremented one option too far. The
4401
* mechanics of that, however, are more daunting than just giving
4402
* both invocations all of the expect options for either invocation.
4403
*
4404
* Needless to say, I wouldn't mind if someone invented a better
4405
* (non-GPL!) command line parsing interface than getopt. I
4406
* wouldn't mind if someone added more knobs to getopt to make it
4407
* work better. Who knows, I may talk myself into doing it someday,
4408
* if the standards weenies let me. As it is, it just leads to
4409
* hackery like this and causes people to avoid it in some cases.
4410
*
4411
* KDM, September 8th, 1998
4412
*/
4413
if (subopt != NULL)
4414
sprintf(combinedopt, "%s%s", mainopt, subopt);
4415
else
4416
sprintf(combinedopt, "%s", mainopt);
4417
4418
/*
4419
* Start getopt processing at argv[2/3], since we've already
4420
* accepted argv[1..2] as the command name, and as a possible
4421
* device name.
4422
*/
4423
optind = optstart;
4424
4425
/*
4426
* Now we run through the argument list looking for generic
4427
* options, and ignoring options that possibly belong to
4428
* subfunctions.
4429
*/
4430
while ((c = getopt(argc, argv, combinedopt))!= -1){
4431
switch (c) {
4432
case 'C':
4433
cmdargs |= CTLADM_ARG_RETRIES;
4434
retries = strtol(optarg, NULL, 0);
4435
break;
4436
case 'D':
4437
device = strdup(optarg);
4438
cmdargs |= CTLADM_ARG_DEVICE;
4439
break;
4440
case 'I':
4441
cmdargs |= CTLADM_ARG_INITIATOR;
4442
initid = strtol(optarg, NULL, 0);
4443
break;
4444
default:
4445
break;
4446
}
4447
}
4448
4449
if ((cmdargs & CTLADM_ARG_INITIATOR) == 0)
4450
initid = 7;
4451
4452
optind = optstart;
4453
optreset = 1;
4454
4455
/*
4456
* Default to opening the CTL device for now.
4457
*/
4458
if (((cmdargs & CTLADM_ARG_DEVICE) == 0)
4459
&& (command != CTLADM_CMD_HELP)) {
4460
device = strdup(CTL_DEFAULT_DEV);
4461
cmdargs |= CTLADM_ARG_DEVICE;
4462
}
4463
4464
if ((cmdargs & CTLADM_ARG_DEVICE)
4465
&& (command != CTLADM_CMD_HELP)) {
4466
fd = open(device, O_RDWR);
4467
if (fd == -1 && errno == ENOENT) {
4468
saved_errno = errno;
4469
retval = kldload("ctl");
4470
if (retval != -1 || errno == EEXIST)
4471
fd = open(device, O_RDWR);
4472
else
4473
errno = saved_errno;
4474
}
4475
if (fd == -1) {
4476
fprintf(stderr, "%s: error opening %s: %s\n",
4477
argv[0], device, strerror(errno));
4478
retval = 1;
4479
goto bailout;
4480
}
4481
#ifdef WANT_ISCSI
4482
switch (command) {
4483
case CTLADM_CMD_ISLIST:
4484
case CTLADM_CMD_ISLOGOUT:
4485
case CTLADM_CMD_ISTERMINATE:
4486
if (modfind("cfiscsi") == -1 &&
4487
kldload("cfiscsi") == -1)
4488
warn("couldn't load cfiscsi");
4489
break;
4490
default:
4491
break;
4492
}
4493
#endif
4494
} else if ((command != CTLADM_CMD_HELP)
4495
&& ((cmdargs & CTLADM_ARG_DEVICE) == 0)) {
4496
fprintf(stderr, "%s: you must specify a device with the "
4497
"--device argument for this command\n", argv[0]);
4498
command = CTLADM_CMD_HELP;
4499
retval = 1;
4500
}
4501
4502
switch (command) {
4503
case CTLADM_CMD_TUR:
4504
retval = cctl_tur(fd, lun, initid, retries);
4505
break;
4506
case CTLADM_CMD_INQUIRY:
4507
retval = cctl_inquiry(fd, lun, initid, retries);
4508
break;
4509
case CTLADM_CMD_REQ_SENSE:
4510
retval = cctl_req_sense(fd, lun, initid, retries);
4511
break;
4512
case CTLADM_CMD_REPORT_LUNS:
4513
retval = cctl_report_luns(fd, lun, initid, retries);
4514
break;
4515
case CTLADM_CMD_CREATE:
4516
retval = cctl_create_lun(fd, argc, argv, combinedopt);
4517
break;
4518
case CTLADM_CMD_RM:
4519
retval = cctl_rm_lun(fd, argc, argv, combinedopt);
4520
break;
4521
case CTLADM_CMD_DEVLIST:
4522
retval = cctl_devlist(fd, argc, argv, combinedopt);
4523
break;
4524
case CTLADM_CMD_READ:
4525
case CTLADM_CMD_WRITE:
4526
retval = cctl_read_write(fd, lun, initid, retries,
4527
argc, argv, combinedopt, command);
4528
break;
4529
case CTLADM_CMD_PORT:
4530
retval = cctl_port(fd, argc, argv, combinedopt);
4531
break;
4532
case CTLADM_CMD_PORTLIST:
4533
retval = cctl_portlist(fd, argc, argv, combinedopt);
4534
break;
4535
case CTLADM_CMD_LUNMAP:
4536
retval = cctl_lunmap(fd, argc, argv, combinedopt);
4537
break;
4538
case CTLADM_CMD_READCAPACITY:
4539
retval = cctl_read_capacity(fd, lun, initid, retries,
4540
argc, argv, combinedopt);
4541
break;
4542
case CTLADM_CMD_MODESENSE:
4543
retval = cctl_mode_sense(fd, lun, initid, retries,
4544
argc, argv, combinedopt);
4545
break;
4546
case CTLADM_CMD_START:
4547
case CTLADM_CMD_STOP:
4548
retval = cctl_start_stop(fd, lun, initid, retries,
4549
(command == CTLADM_CMD_START) ? 1 : 0,
4550
argc, argv, combinedopt);
4551
break;
4552
case CTLADM_CMD_SYNC_CACHE:
4553
retval = cctl_sync_cache(fd, lun, initid, retries,
4554
argc, argv, combinedopt);
4555
break;
4556
case CTLADM_CMD_LUNLIST:
4557
retval = cctl_lunlist(fd);
4558
break;
4559
case CTLADM_CMD_DELAY:
4560
retval = cctl_delay(fd, lun, argc, argv, combinedopt);
4561
break;
4562
case CTLADM_CMD_ERR_INJECT:
4563
retval = cctl_error_inject(fd, lun, argc, argv,
4564
combinedopt);
4565
break;
4566
case CTLADM_CMD_DUMPOOA:
4567
retval = cctl_dump_ooa(fd, argc, argv);
4568
break;
4569
case CTLADM_CMD_DUMPSTRUCTS:
4570
retval = cctl_dump_structs(fd, cmdargs);
4571
break;
4572
case CTLADM_CMD_PRES_IN:
4573
retval = cctl_persistent_reserve_in(fd, lun, initid,
4574
argc, argv, combinedopt,
4575
retries);
4576
break;
4577
case CTLADM_CMD_PRES_OUT:
4578
retval = cctl_persistent_reserve_out(fd, lun, initid,
4579
argc, argv, combinedopt,
4580
retries);
4581
break;
4582
case CTLADM_CMD_INQ_VPD_DEVID:
4583
retval = cctl_inquiry_vpd_devid(fd, lun, initid);
4584
break;
4585
case CTLADM_CMD_RTPG:
4586
retval = cctl_report_target_port_group(fd, lun, initid);
4587
break;
4588
case CTLADM_CMD_MODIFY:
4589
retval = cctl_modify_lun(fd, argc, argv, combinedopt);
4590
break;
4591
case CTLADM_CMD_ISLIST:
4592
retval = cctl_islist(fd, argc, argv, combinedopt);
4593
break;
4594
case CTLADM_CMD_ISLOGOUT:
4595
retval = cctl_islogout(fd, argc, argv, combinedopt);
4596
break;
4597
case CTLADM_CMD_ISTERMINATE:
4598
retval = cctl_isterminate(fd, argc, argv, combinedopt);
4599
break;
4600
case CTLADM_CMD_NVLIST:
4601
retval = cctl_nvlist(fd, argc, argv, combinedopt);
4602
break;
4603
case CTLADM_CMD_NVTERMINATE:
4604
retval = cctl_nvterminate(fd, argc, argv, combinedopt);
4605
break;
4606
case CTLADM_CMD_HELP:
4607
default:
4608
usage(retval);
4609
break;
4610
}
4611
bailout:
4612
4613
if (fd != -1)
4614
close(fd);
4615
4616
exit (retval);
4617
}
4618
4619
/*
4620
* vim: ts=8
4621
*/
4622
4623