2 * Copyright (c) 2012 The FreeBSD Foundation
5 * This software was developed by Edward Tomasz Napierala under sponsorship
6 * from the FreeBSD Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
34 #include <sys/ioctl.h>
35 #include <sys/param.h>
36 #include <sys/linker.h>
48 #include <iscsi_ioctl.h>
56 conf = calloc(1, sizeof(*conf));
60 TAILQ_INIT(&conf->conf_targets);
66 target_find(struct conf *conf, const char *nickname)
70 TAILQ_FOREACH(targ, &conf->conf_targets, t_next) {
71 if (targ->t_nickname != NULL &&
72 strcasecmp(targ->t_nickname, nickname) == 0)
80 target_new(struct conf *conf)
84 targ = calloc(1, sizeof(*targ));
88 TAILQ_INSERT_TAIL(&conf->conf_targets, targ, t_next);
94 target_delete(struct target *targ)
97 TAILQ_REMOVE(&targ->t_conf->conf_targets, targ, t_next);
102 default_initiator_name(void)
108 namelen = _POSIX_HOST_NAME_MAX + strlen(DEFAULT_IQN);
110 name = calloc(1, namelen + 1);
113 strcpy(name, DEFAULT_IQN);
114 error = gethostname(name + strlen(DEFAULT_IQN),
115 namelen - strlen(DEFAULT_IQN));
117 xo_err(1, "gethostname");
123 valid_hex(const char ch)
155 parse_enable(const char *enable)
158 return (ENABLE_UNSPECIFIED);
160 if (strcasecmp(enable, "on") == 0 ||
161 strcasecmp(enable, "yes") == 0)
164 if (strcasecmp(enable, "off") == 0 ||
165 strcasecmp(enable, "no") == 0)
168 return (ENABLE_UNSPECIFIED);
172 valid_iscsi_name(const char *name)
176 if (strlen(name) >= MAX_NAME_LEN) {
177 xo_warnx("overlong name for \"%s\"; max length allowed "
178 "by iSCSI specification is %d characters",
184 * In the cases below, we don't return an error, just in case the admin
185 * was right, and we're wrong.
187 if (strncasecmp(name, "iqn.", strlen("iqn.")) == 0) {
188 for (i = strlen("iqn."); name[i] != '\0'; i++) {
190 * XXX: We should verify UTF-8 normalisation, as defined
191 * by 3.2.6.2: iSCSI Name Encoding.
193 if (isalnum(name[i]))
195 if (name[i] == '-' || name[i] == '.' || name[i] == ':')
197 xo_warnx("invalid character \"%c\" in iSCSI name "
198 "\"%s\"; allowed characters are letters, digits, "
199 "'-', '.', and ':'", name[i], name);
203 * XXX: Check more stuff: valid date and a valid reversed domain.
205 } else if (strncasecmp(name, "eui.", strlen("eui.")) == 0) {
206 if (strlen(name) != strlen("eui.") + 16)
207 xo_warnx("invalid iSCSI name \"%s\"; the \"eui.\" "
208 "should be followed by exactly 16 hexadecimal "
210 for (i = strlen("eui."); name[i] != '\0'; i++) {
211 if (!valid_hex(name[i])) {
212 xo_warnx("invalid character \"%c\" in iSCSI "
213 "name \"%s\"; allowed characters are 1-9 "
214 "and A-F", name[i], name);
218 } else if (strncasecmp(name, "naa.", strlen("naa.")) == 0) {
219 if (strlen(name) > strlen("naa.") + 32)
220 xo_warnx("invalid iSCSI name \"%s\"; the \"naa.\" "
221 "should be followed by at most 32 hexadecimal "
223 for (i = strlen("naa."); name[i] != '\0'; i++) {
224 if (!valid_hex(name[i])) {
225 xo_warnx("invalid character \"%c\" in ISCSI "
226 "name \"%s\"; allowed characters are 1-9 "
227 "and A-F", name[i], name);
232 xo_warnx("invalid iSCSI name \"%s\"; should start with "
233 "either \".iqn\", \"eui.\", or \"naa.\"",
240 conf_verify(struct conf *conf)
244 TAILQ_FOREACH(targ, &conf->conf_targets, t_next) {
245 assert(targ->t_nickname != NULL);
246 if (targ->t_session_type == SESSION_TYPE_UNSPECIFIED)
247 targ->t_session_type = SESSION_TYPE_NORMAL;
248 if (targ->t_session_type == SESSION_TYPE_NORMAL &&
249 targ->t_name == NULL)
250 xo_errx(1, "missing TargetName for target \"%s\"",
252 if (targ->t_session_type == SESSION_TYPE_DISCOVERY &&
253 targ->t_name != NULL)
254 xo_errx(1, "cannot specify TargetName for discovery "
255 "sessions for target \"%s\"", targ->t_nickname);
256 if (targ->t_name != NULL) {
257 if (valid_iscsi_name(targ->t_name) == false)
258 xo_errx(1, "invalid target name \"%s\"",
261 if (targ->t_protocol == PROTOCOL_UNSPECIFIED)
262 targ->t_protocol = PROTOCOL_ISCSI;
263 if (targ->t_address == NULL)
264 xo_errx(1, "missing TargetAddress for target \"%s\"",
266 if (targ->t_initiator_name == NULL)
267 targ->t_initiator_name = default_initiator_name();
268 if (valid_iscsi_name(targ->t_initiator_name) == false)
269 xo_errx(1, "invalid initiator name \"%s\"",
270 targ->t_initiator_name);
271 if (targ->t_header_digest == DIGEST_UNSPECIFIED)
272 targ->t_header_digest = DIGEST_NONE;
273 if (targ->t_data_digest == DIGEST_UNSPECIFIED)
274 targ->t_data_digest = DIGEST_NONE;
275 if (targ->t_auth_method == AUTH_METHOD_UNSPECIFIED) {
276 if (targ->t_user != NULL || targ->t_secret != NULL ||
277 targ->t_mutual_user != NULL ||
278 targ->t_mutual_secret != NULL)
279 targ->t_auth_method =
282 targ->t_auth_method =
285 if (targ->t_auth_method == AUTH_METHOD_CHAP) {
286 if (targ->t_user == NULL) {
287 xo_errx(1, "missing chapIName for target \"%s\"",
290 if (targ->t_secret == NULL)
291 xo_errx(1, "missing chapSecret for target \"%s\"",
293 if (targ->t_mutual_user != NULL ||
294 targ->t_mutual_secret != NULL) {
295 if (targ->t_mutual_user == NULL)
296 xo_errx(1, "missing tgtChapName for "
297 "target \"%s\"", targ->t_nickname);
298 if (targ->t_mutual_secret == NULL)
299 xo_errx(1, "missing tgtChapSecret for "
300 "target \"%s\"", targ->t_nickname);
307 conf_from_target(struct iscsi_session_conf *conf,
308 const struct target *targ)
310 memset(conf, 0, sizeof(*conf));
313 * XXX: Check bounds and return error instead of silently truncating.
315 if (targ->t_initiator_name != NULL)
316 strlcpy(conf->isc_initiator, targ->t_initiator_name,
317 sizeof(conf->isc_initiator));
318 if (targ->t_initiator_address != NULL)
319 strlcpy(conf->isc_initiator_addr, targ->t_initiator_address,
320 sizeof(conf->isc_initiator_addr));
321 if (targ->t_initiator_alias != NULL)
322 strlcpy(conf->isc_initiator_alias, targ->t_initiator_alias,
323 sizeof(conf->isc_initiator_alias));
324 if (targ->t_name != NULL)
325 strlcpy(conf->isc_target, targ->t_name,
326 sizeof(conf->isc_target));
327 if (targ->t_address != NULL)
328 strlcpy(conf->isc_target_addr, targ->t_address,
329 sizeof(conf->isc_target_addr));
330 if (targ->t_user != NULL)
331 strlcpy(conf->isc_user, targ->t_user,
332 sizeof(conf->isc_user));
333 if (targ->t_secret != NULL)
334 strlcpy(conf->isc_secret, targ->t_secret,
335 sizeof(conf->isc_secret));
336 if (targ->t_mutual_user != NULL)
337 strlcpy(conf->isc_mutual_user, targ->t_mutual_user,
338 sizeof(conf->isc_mutual_user));
339 if (targ->t_mutual_secret != NULL)
340 strlcpy(conf->isc_mutual_secret, targ->t_mutual_secret,
341 sizeof(conf->isc_mutual_secret));
342 if (targ->t_session_type == SESSION_TYPE_DISCOVERY)
343 conf->isc_discovery = 1;
344 if (targ->t_enable != ENABLE_OFF)
345 conf->isc_enable = 1;
346 if (targ->t_protocol == PROTOCOL_ISER)
348 if (targ->t_offload != NULL)
349 strlcpy(conf->isc_offload, targ->t_offload,
350 sizeof(conf->isc_offload));
351 if (targ->t_header_digest == DIGEST_CRC32C)
352 conf->isc_header_digest = ISCSI_DIGEST_CRC32C;
354 conf->isc_header_digest = ISCSI_DIGEST_NONE;
355 if (targ->t_data_digest == DIGEST_CRC32C)
356 conf->isc_data_digest = ISCSI_DIGEST_CRC32C;
358 conf->isc_data_digest = ISCSI_DIGEST_NONE;
362 kernel_add(int iscsi_fd, const struct target *targ)
364 struct iscsi_session_add isa;
367 memset(&isa, 0, sizeof(isa));
368 conf_from_target(&isa.isa_conf, targ);
369 error = ioctl(iscsi_fd, ISCSISADD, &isa);
371 xo_warn("ISCSISADD");
376 kernel_modify(int iscsi_fd, unsigned int session_id, const struct target *targ)
378 struct iscsi_session_modify ism;
381 memset(&ism, 0, sizeof(ism));
382 ism.ism_session_id = session_id;
383 conf_from_target(&ism.ism_conf, targ);
384 error = ioctl(iscsi_fd, ISCSISMODIFY, &ism);
386 xo_warn("ISCSISMODIFY");
391 kernel_modify_some(int iscsi_fd, unsigned int session_id, const char *target,
392 const char *target_addr, const char *user, const char *secret, int enable)
394 struct iscsi_session_state *states = NULL;
395 struct iscsi_session_state *state;
396 struct iscsi_session_conf *conf;
397 struct iscsi_session_list isl;
398 struct iscsi_session_modify ism;
399 unsigned int i, nentries = 1;
403 states = realloc(states,
404 nentries * sizeof(struct iscsi_session_state));
406 xo_err(1, "realloc");
408 memset(&isl, 0, sizeof(isl));
409 isl.isl_nentries = nentries;
410 isl.isl_pstates = states;
412 error = ioctl(iscsi_fd, ISCSISLIST, &isl);
413 if (error != 0 && errno == EMSGSIZE) {
420 xo_errx(1, "ISCSISLIST");
422 for (i = 0; i < isl.isl_nentries; i++) {
425 if (state->iss_id == session_id)
428 if (i == isl.isl_nentries)
429 xo_errx(1, "session-id %u not found", session_id);
431 conf = &state->iss_conf;
434 strlcpy(conf->isc_target, target, sizeof(conf->isc_target));
435 if (target_addr != NULL)
436 strlcpy(conf->isc_target_addr, target_addr,
437 sizeof(conf->isc_target_addr));
439 strlcpy(conf->isc_user, user, sizeof(conf->isc_user));
441 strlcpy(conf->isc_secret, secret, sizeof(conf->isc_secret));
442 if (enable == ENABLE_ON)
443 conf->isc_enable = 1;
444 else if (enable == ENABLE_OFF)
445 conf->isc_enable = 0;
447 memset(&ism, 0, sizeof(ism));
448 ism.ism_session_id = session_id;
449 memcpy(&ism.ism_conf, conf, sizeof(ism.ism_conf));
450 error = ioctl(iscsi_fd, ISCSISMODIFY, &ism);
452 xo_warn("ISCSISMODIFY");
456 kernel_remove(int iscsi_fd, const struct target *targ)
458 struct iscsi_session_remove isr;
461 memset(&isr, 0, sizeof(isr));
462 conf_from_target(&isr.isr_conf, targ);
463 error = ioctl(iscsi_fd, ISCSISREMOVE, &isr);
465 xo_warn("ISCSISREMOVE");
470 * XXX: Add filtering.
473 kernel_list(int iscsi_fd, const struct target *targ __unused,
476 struct iscsi_session_state *states = NULL;
477 const struct iscsi_session_state *state;
478 const struct iscsi_session_conf *conf;
479 struct iscsi_session_list isl;
480 unsigned int i, nentries = 1;
484 states = realloc(states,
485 nentries * sizeof(struct iscsi_session_state));
487 xo_err(1, "realloc");
489 memset(&isl, 0, sizeof(isl));
490 isl.isl_nentries = nentries;
491 isl.isl_pstates = states;
493 error = ioctl(iscsi_fd, ISCSISLIST, &isl);
494 if (error != 0 && errno == EMSGSIZE) {
501 xo_warn("ISCSISLIST");
506 xo_open_list("session");
507 for (i = 0; i < isl.isl_nentries; i++) {
509 conf = &state->iss_conf;
511 xo_open_instance("session");
514 * Display-only modifier as this information
515 * is also present within the 'session' container
517 xo_emit("{L:/%-26s}{V:sessionId/%u}\n",
518 "Session ID:", state->iss_id);
520 xo_open_container("initiator");
521 xo_emit("{L:/%-26s}{V:name/%s}\n",
522 "Initiator name:", conf->isc_initiator);
523 xo_emit("{L:/%-26s}{V:portal/%s}\n",
524 "Initiator portal:", conf->isc_initiator_addr);
525 xo_emit("{L:/%-26s}{V:alias/%s}\n",
526 "Initiator alias:", conf->isc_initiator_alias);
527 xo_close_container("initiator");
529 xo_open_container("target");
530 xo_emit("{L:/%-26s}{V:name/%s}\n",
531 "Target name:", conf->isc_target);
532 xo_emit("{L:/%-26s}{V:portal/%s}\n",
533 "Target portal:", conf->isc_target_addr);
534 xo_emit("{L:/%-26s}{V:alias/%s}\n",
535 "Target alias:", state->iss_target_alias);
536 xo_close_container("target");
538 xo_open_container("auth");
539 xo_emit("{L:/%-26s}{V:user/%s}\n",
540 "User:", conf->isc_user);
541 xo_emit("{L:/%-26s}{V:secret/%s}\n",
542 "Secret:", conf->isc_secret);
543 xo_emit("{L:/%-26s}{V:mutualUser/%s}\n",
544 "Mutual user:", conf->isc_mutual_user);
545 xo_emit("{L:/%-26s}{V:mutualSecret/%s}\n",
546 "Mutual secret:", conf->isc_mutual_secret);
547 xo_close_container("auth");
549 xo_emit("{L:/%-26s}{V:type/%s}\n",
551 conf->isc_discovery ? "Discovery" : "Normal");
552 xo_emit("{L:/%-26s}{V:enable/%s}\n",
554 conf->isc_enable ? "Yes" : "No");
555 xo_emit("{L:/%-26s}{V:state/%s}\n",
557 state->iss_connected ? "Connected" : "Disconnected");
558 xo_emit("{L:/%-26s}{V:failureReason/%s}\n",
559 "Failure reason:", state->iss_reason);
560 xo_emit("{L:/%-26s}{V:headerDigest/%s}\n",
562 state->iss_header_digest == ISCSI_DIGEST_CRC32C ?
564 xo_emit("{L:/%-26s}{V:dataDigest/%s}\n",
566 state->iss_data_digest == ISCSI_DIGEST_CRC32C ?
568 xo_emit("{L:/%-26s}{V:recvDataSegmentLen/%d}\n",
569 "MaxRecvDataSegmentLength:",
570 state->iss_max_recv_data_segment_length);
571 xo_emit("{L:/%-26s}{V:sendDataSegmentLen/%d}\n",
572 "MaxSendDataSegmentLength:",
573 state->iss_max_send_data_segment_length);
574 xo_emit("{L:/%-26s}{V:maxBurstLen/%d}\n",
575 "MaxBurstLen:", state->iss_max_burst_length);
576 xo_emit("{L:/%-26s}{V:firstBurstLen/%d}\n",
577 "FirstBurstLen:", state->iss_first_burst_length);
578 xo_emit("{L:/%-26s}{V:immediateData/%s}\n",
579 "ImmediateData:", state->iss_immediate_data ? "Yes" : "No");
580 xo_emit("{L:/%-26s}{V:iSER/%s}\n",
581 "iSER (RDMA):", conf->isc_iser ? "Yes" : "No");
582 xo_emit("{L:/%-26s}{V:offloadDriver/%s}\n",
583 "Offload driver:", state->iss_offload);
584 xo_emit("{L:/%-26s}",
586 print_periphs(state->iss_id);
588 xo_close_instance("session");
590 xo_close_list("session");
592 xo_emit("{T:/%-36s} {T:/%-16s} {T:/%s}\n",
593 "Target name", "Target portal", "State");
595 if (isl.isl_nentries != 0)
596 xo_open_list("session");
597 for (i = 0; i < isl.isl_nentries; i++) {
600 conf = &state->iss_conf;
602 xo_open_instance("session");
603 xo_emit("{V:name/%-36s/%s} {V:portal/%-16s/%s} ",
604 conf->isc_target, conf->isc_target_addr);
606 if (state->iss_reason[0] != '\0') {
607 xo_emit("{V:state/%s}\n", state->iss_reason);
609 if (conf->isc_discovery) {
610 xo_emit("{V:state}\n", "Discovery");
611 } else if (conf->isc_enable == 0) {
612 xo_emit("{V:state}\n", "Disabled");
613 } else if (state->iss_connected) {
614 xo_emit("{V:state}: ", "Connected");
615 print_periphs(state->iss_id);
618 xo_emit("{V:state}\n", "Disconnected");
621 xo_close_instance("session");
623 if (isl.isl_nentries != 0)
624 xo_close_list("session");
631 kernel_wait(int iscsi_fd, int timeout)
633 struct iscsi_session_state *states = NULL;
634 const struct iscsi_session_state *state;
635 struct iscsi_session_list isl;
636 unsigned int i, nentries = 1;
642 states = realloc(states,
643 nentries * sizeof(struct iscsi_session_state));
645 xo_err(1, "realloc");
647 memset(&isl, 0, sizeof(isl));
648 isl.isl_nentries = nentries;
649 isl.isl_pstates = states;
651 error = ioctl(iscsi_fd, ISCSISLIST, &isl);
652 if (error != 0 && errno == EMSGSIZE) {
659 xo_warn("ISCSISLIST");
663 all_connected = true;
664 for (i = 0; i < isl.isl_nentries; i++) {
667 if (!state->iss_connected) {
668 all_connected = false;
690 fprintf(stderr, "usage: iscsictl -A -p portal -t target "
691 "[-u user -s secret] [-w timeout] [-e on | off]\n");
692 fprintf(stderr, " iscsictl -A -d discovery-host "
693 "[-u user -s secret] [-e on | off]\n");
694 fprintf(stderr, " iscsictl -A -a [-c path]\n");
695 fprintf(stderr, " iscsictl -A -n nickname [-c path]\n");
696 fprintf(stderr, " iscsictl -M -i session-id [-p portal] "
697 "[-t target] [-u user] [-s secret] [-e on | off]\n");
698 fprintf(stderr, " iscsictl -M -i session-id -n nickname "
700 fprintf(stderr, " iscsictl -R [-p portal] [-t target]\n");
701 fprintf(stderr, " iscsictl -R -a\n");
702 fprintf(stderr, " iscsictl -R -n nickname [-c path]\n");
703 fprintf(stderr, " iscsictl -L [-v] [-w timeout]\n");
708 main(int argc, char **argv)
710 int Aflag = 0, Mflag = 0, Rflag = 0, Lflag = 0, aflag = 0,
711 rflag = 0, vflag = 0;
712 const char *conf_path = DEFAULT_CONFIG_PATH;
713 char *nickname = NULL, *discovery_host = NULL, *portal = NULL,
714 *target = NULL, *user = NULL, *secret = NULL;
715 int timeout = -1, enable = ENABLE_UNSPECIFIED;
716 long long session_id = -1;
718 int ch, error, iscsi_fd, retval, saved_errno;
723 argc = xo_parse_args(argc, argv);
724 xo_open_container("iscsictl");
726 while ((ch = getopt(argc, argv, "AMRLac:d:e:i:n:p:rt:u:s:vw:")) != -1) {
747 discovery_host = optarg;
750 enable = parse_enable(optarg);
751 if (enable == ENABLE_UNSPECIFIED) {
752 xo_errx(1, "invalid argument to -e, "
753 "must be either \"on\" or \"off\"");
757 session_id = strtol(optarg, &end, 10);
758 if ((size_t)(end - optarg) != strlen(optarg))
759 xo_errx(1, "trailing characters after session-id");
761 xo_errx(1, "session-id cannot be negative");
762 if (session_id > UINT_MAX)
763 xo_errx(1, "session-id cannot be greater than %u",
788 timeout = strtol(optarg, &end, 10);
789 if ((size_t)(end - optarg) != strlen(optarg))
790 xo_errx(1, "trailing characters after timeout");
792 xo_errx(1, "timeout cannot be negative");
803 if (Aflag + Mflag + Rflag + Lflag == 0)
805 if (Aflag + Mflag + Rflag + Lflag > 1)
806 xo_errx(1, "at most one of -A, -M, -R, or -L may be specified");
809 * Note that we ignore unnecessary/inapplicable "-c" flag; so that
810 * people can do something like "alias ISCSICTL="iscsictl -c path"
815 if (enable != ENABLE_UNSPECIFIED)
816 xo_errx(1, "-a and -e and mutually exclusive");
818 xo_errx(1, "-a and -p and mutually exclusive");
820 xo_errx(1, "-a and -t and mutually exclusive");
822 xo_errx(1, "-a and -u and mutually exclusive");
824 xo_errx(1, "-a and -s and mutually exclusive");
825 if (nickname != NULL)
826 xo_errx(1, "-a and -n and mutually exclusive");
827 if (discovery_host != NULL)
828 xo_errx(1, "-a and -d and mutually exclusive");
830 xo_errx(1, "-a and -r and mutually exclusive");
831 } else if (nickname != NULL) {
832 if (enable != ENABLE_UNSPECIFIED)
833 xo_errx(1, "-n and -e and mutually exclusive");
835 xo_errx(1, "-n and -p and mutually exclusive");
837 xo_errx(1, "-n and -t and mutually exclusive");
839 xo_errx(1, "-n and -u and mutually exclusive");
841 xo_errx(1, "-n and -s and mutually exclusive");
842 if (discovery_host != NULL)
843 xo_errx(1, "-n and -d and mutually exclusive");
845 xo_errx(1, "-n and -r and mutually exclusive");
846 } else if (discovery_host != NULL) {
848 xo_errx(1, "-d and -p and mutually exclusive");
850 xo_errx(1, "-d and -t and mutually exclusive");
852 if (target == NULL && portal == NULL)
853 xo_errx(1, "must specify -a, -n or -t/-p");
855 if (target != NULL && portal == NULL)
856 xo_errx(1, "-t must always be used with -p");
857 if (portal != NULL && target == NULL)
858 xo_errx(1, "-p must always be used with -t");
861 if (user != NULL && secret == NULL)
862 xo_errx(1, "-u must always be used with -s");
863 if (secret != NULL && user == NULL)
864 xo_errx(1, "-s must always be used with -u");
866 if (session_id != -1)
867 xo_errx(1, "-i cannot be used with -A");
869 xo_errx(1, "-v cannot be used with -A");
871 } else if (Mflag != 0) {
872 if (session_id == -1)
873 xo_errx(1, "-M requires -i");
875 if (nickname != NULL) {
876 if (enable != ENABLE_UNSPECIFIED)
877 xo_errx(1, "-n and -e and mutually exclusive");
879 xo_errx(1, "-n and -p and mutually exclusive");
881 xo_errx(1, "-n and -t and mutually exclusive");
883 xo_errx(1, "-n and -u and mutually exclusive");
885 xo_errx(1, "-n and -s and mutually exclusive");
889 xo_errx(1, "-a cannot be used with -M");
890 if (discovery_host != NULL)
891 xo_errx(1, "-d cannot be used with -M");
893 xo_errx(1, "-r cannot be used with -M");
895 xo_errx(1, "-v cannot be used with -M");
897 xo_errx(1, "-w cannot be used with -M");
899 } else if (Rflag != 0) {
902 xo_errx(1, "-a and -p and mutually exclusive");
904 xo_errx(1, "-a and -t and mutually exclusive");
905 if (nickname != NULL)
906 xo_errx(1, "-a and -n and mutually exclusive");
907 } else if (nickname != NULL) {
909 xo_errx(1, "-n and -p and mutually exclusive");
911 xo_errx(1, "-n and -t and mutually exclusive");
912 } else if (target == NULL && portal == NULL) {
913 xo_errx(1, "must specify either -a, -n, -t, or -p");
916 if (discovery_host != NULL)
917 xo_errx(1, "-d cannot be used with -R");
918 if (enable != ENABLE_UNSPECIFIED)
919 xo_errx(1, "-e cannot be used with -R");
920 if (session_id != -1)
921 xo_errx(1, "-i cannot be used with -R");
923 xo_errx(1, "-r cannot be used with -R");
925 xo_errx(1, "-u cannot be used with -R");
927 xo_errx(1, "-s cannot be used with -R");
929 xo_errx(1, "-v cannot be used with -R");
931 xo_errx(1, "-w cannot be used with -R");
936 if (discovery_host != NULL)
937 xo_errx(1, "-d cannot be used with -L");
938 if (session_id != -1)
939 xo_errx(1, "-i cannot be used with -L");
940 if (nickname != NULL)
941 xo_errx(1, "-n cannot be used with -L");
943 xo_errx(1, "-p cannot be used with -L");
945 xo_errx(1, "-r cannot be used with -L");
947 xo_errx(1, "-t cannot be used with -L");
949 xo_errx(1, "-u cannot be used with -L");
951 xo_errx(1, "-s cannot be used with -L");
954 iscsi_fd = open(ISCSI_PATH, O_RDWR);
955 if (iscsi_fd < 0 && errno == ENOENT) {
957 retval = kldload("iscsi");
959 iscsi_fd = open(ISCSI_PATH, O_RDWR);
964 xo_err(1, "failed to open %s", ISCSI_PATH);
966 if (Aflag != 0 && aflag != 0) {
967 conf = conf_new_from_file(conf_path);
969 TAILQ_FOREACH(targ, &conf->conf_targets, t_next)
970 failed += kernel_add(iscsi_fd, targ);
971 } else if (nickname != NULL) {
972 conf = conf_new_from_file(conf_path);
973 targ = target_find(conf, nickname);
975 xo_errx(1, "target %s not found in %s",
976 nickname, conf_path);
979 failed += kernel_add(iscsi_fd, targ);
981 failed += kernel_modify(iscsi_fd, session_id, targ);
983 failed += kernel_remove(iscsi_fd, targ);
985 failed += kernel_list(iscsi_fd, targ, vflag);
986 } else if (Mflag != 0) {
987 kernel_modify_some(iscsi_fd, session_id, target, portal,
988 user, secret, enable);
990 if (Aflag != 0 && target != NULL) {
991 if (valid_iscsi_name(target) == false)
992 xo_errx(1, "invalid target name \"%s\"", target);
995 targ = target_new(conf);
996 targ->t_initiator_name = default_initiator_name();
997 targ->t_header_digest = DIGEST_NONE;
998 targ->t_data_digest = DIGEST_NONE;
999 targ->t_name = target;
1000 if (discovery_host != NULL) {
1001 targ->t_session_type = SESSION_TYPE_DISCOVERY;
1002 targ->t_address = discovery_host;
1004 targ->t_session_type = SESSION_TYPE_NORMAL;
1005 targ->t_address = portal;
1007 targ->t_enable = enable;
1009 targ->t_protocol = PROTOCOL_ISER;
1010 targ->t_user = user;
1011 targ->t_secret = secret;
1014 failed += kernel_add(iscsi_fd, targ);
1015 else if (Rflag != 0)
1016 failed += kernel_remove(iscsi_fd, targ);
1018 failed += kernel_list(iscsi_fd, targ, vflag);
1022 failed += kernel_wait(iscsi_fd, timeout);
1024 error = close(iscsi_fd);
1028 xo_close_container("iscsictl");