kernel.c revision 279880
1152851Sariff/*-
2152851Sariff * Copyright (c) 2003, 2004 Silicon Graphics International Corp.
3152851Sariff * Copyright (c) 1997-2007 Kenneth D. Merry
4152851Sariff * Copyright (c) 2012 The FreeBSD Foundation
5152851Sariff * All rights reserved.
6152851Sariff *
7152851Sariff * Portions of this software were developed by Edward Tomasz Napierala
8152851Sariff * under sponsorship from the FreeBSD Foundation.
9152851Sariff *
10152851Sariff * Redistribution and use in source and binary forms, with or without
11152851Sariff * modification, are permitted provided that the following conditions
12152851Sariff * are met:
13152851Sariff * 1. Redistributions of source code must retain the above copyright
14152851Sariff *    notice, this list of conditions, and the following disclaimer,
15152851Sariff *    without modification.
16152851Sariff * 2. Redistributions in binary form must reproduce at minimum a disclaimer
17152851Sariff *    substantially similar to the "NO WARRANTY" disclaimer below
18152851Sariff *    ("Disclaimer") and any redistribution must be conditioned upon
19152851Sariff *    including a substantially similar Disclaimer requirement for further
20152851Sariff *    binary redistribution.
21152851Sariff *
22152851Sariff * NO WARRANTY
23152851Sariff * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24152851Sariff * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25152851Sariff * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
26152851Sariff * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27152851Sariff * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28152851Sariff * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29152851Sariff * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30152851Sariff * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31152851Sariff * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
32152851Sariff * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33155800Sariff * POSSIBILITY OF SUCH DAMAGES.
34152851Sariff *
35152851Sariff */
36152851Sariff
37152851Sariff#include <sys/cdefs.h>
38152851Sariff__FBSDID("$FreeBSD: stable/10/usr.sbin/ctld/kernel.c 279880 2015-03-11 09:52:54Z mav $");
39155800Sariff
40155800Sariff#include <sys/ioctl.h>
41152851Sariff#include <sys/types.h>
42152851Sariff#include <sys/stat.h>
43152851Sariff#include <sys/param.h>
44152851Sariff#include <sys/linker.h>
45152851Sariff#include <sys/queue.h>
46152851Sariff#include <sys/callout.h>
47152851Sariff#include <sys/sbuf.h>
48152851Sariff#include <sys/capability.h>
49152851Sariff#include <assert.h>
50152851Sariff#include <bsdxml.h>
51152851Sariff#include <ctype.h>
52152851Sariff#include <errno.h>
53152851Sariff#include <fcntl.h>
54152851Sariff#include <stdint.h>
55152851Sariff#include <stdio.h>
56193640Sariff#include <stdlib.h>
57193640Sariff#include <string.h>
58193640Sariff#include <strings.h>
59193640Sariff#include <cam/scsi/scsi_all.h>
60152851Sariff#include <cam/scsi/scsi_message.h>
61152851Sariff#include <cam/ctl/ctl.h>
62152851Sariff#include <cam/ctl/ctl_io.h>
63152851Sariff#include <cam/ctl/ctl_frontend_internal.h>
64152851Sariff#include <cam/ctl/ctl_backend.h>
65152851Sariff#include <cam/ctl/ctl_ioctl.h>
66152851Sariff#include <cam/ctl/ctl_backend_block.h>
67152851Sariff#include <cam/ctl/ctl_util.h>
68152851Sariff#include <cam/ctl/ctl_scsi_all.h>
69152851Sariff
70152851Sariff#include "ctld.h"
71152851Sariff
72167648Sariff#ifdef ICL_KERNEL_PROXY
73162931Sariff#include <netdb.h>
74167648Sariff#endif
75167648Sariff
76167648Sariffextern bool proxy_mode;
77162931Sariff
78167648Sariffstatic int	ctl_fd = 0;
79167648Sariff
80167648Sariffvoid
81171329Sariffkernel_init(void)
82171329Sariff{
83171329Sariff	int retval, saved_errno;
84152851Sariff
85155800Sariff	ctl_fd = open(CTL_DEFAULT_DEV, O_RDWR);
86155800Sariff	if (ctl_fd < 0 && errno == ENOENT) {
87155800Sariff		saved_errno = errno;
88155800Sariff		retval = kldload("ctl");
89152851Sariff		if (retval != -1)
90152851Sariff			ctl_fd = open(CTL_DEFAULT_DEV, O_RDWR);
91152851Sariff		else
92152851Sariff			errno = saved_errno;
93152851Sariff	}
94152851Sariff	if (ctl_fd < 0)
95152851Sariff		log_err(1, "failed to open %s", CTL_DEFAULT_DEV);
96152851Sariff}
97152851Sariff
98152851Sariff/*
99164614Sariff * Name/value pair used for per-LUN attributes.
100164614Sariff */
101164614Sariffstruct cctl_lun_nv {
102153708Sariff	char *name;
103171329Sariff	char *value;
104171329Sariff	STAILQ_ENTRY(cctl_lun_nv) links;
105152851Sariff};
106152851Sariff
107152851Sariff/*
108152851Sariff * Backend LUN information.
109152851Sariff */
110152851Sariffstruct cctl_lun {
111152851Sariff	uint64_t lun_id;
112152851Sariff	char *backend_type;
113152851Sariff	uint64_t size_blocks;
114152851Sariff	uint32_t blocksize;
115152851Sariff	char *serial_number;
116152851Sariff	char *device_id;
117152851Sariff	char *ctld_name;
118152851Sariff	STAILQ_HEAD(,cctl_lun_nv) attr_list;
119152851Sariff	STAILQ_ENTRY(cctl_lun) links;
120152851Sariff};
121152851Sariff
122152851Sariffstruct cctl_port {
123152851Sariff	uint32_t port_id;
124152851Sariff	char *port_name;
125152851Sariff	int cfiscsi_state;
126152851Sariff	char *cfiscsi_target;
127152851Sariff	uint16_t cfiscsi_portal_group_tag;
128152851Sariff	char *ctld_portal_group_name;
129164614Sariff	STAILQ_HEAD(,cctl_lun_nv) attr_list;
130152851Sariff	STAILQ_ENTRY(cctl_port) links;
131152851Sariff};
132152851Sariff
133164614Sariffstruct cctl_devlist_data {
134164614Sariff	int num_luns;
135152851Sariff	STAILQ_HEAD(,cctl_lun) lun_list;
136152851Sariff	struct cctl_lun *cur_lun;
137152851Sariff	int num_ports;
138152851Sariff	STAILQ_HEAD(,cctl_port) port_list;
139152851Sariff	struct cctl_port *cur_port;
140152851Sariff	int level;
141152851Sariff	struct sbuf *cur_sb[32];
142152851Sariff};
143152851Sariff
144152851Sariffstatic void
145152851Sariffcctl_start_element(void *user_data, const char *name, const char **attr)
146152851Sariff{
147193640Sariff	int i;
148193640Sariff	struct cctl_devlist_data *devlist;
149152851Sariff	struct cctl_lun *cur_lun;
150152851Sariff
151152851Sariff	devlist = (struct cctl_devlist_data *)user_data;
152152851Sariff	cur_lun = devlist->cur_lun;
153193640Sariff	devlist->level++;
154152851Sariff	if ((u_int)devlist->level >= (sizeof(devlist->cur_sb) /
155152851Sariff	    sizeof(devlist->cur_sb[0])))
156152851Sariff		log_errx(1, "%s: too many nesting levels, %zd max", __func__,
157152851Sariff		     sizeof(devlist->cur_sb) / sizeof(devlist->cur_sb[0]));
158152851Sariff
159152851Sariff	devlist->cur_sb[devlist->level] = sbuf_new_auto();
160152851Sariff	if (devlist->cur_sb[devlist->level] == NULL)
161152851Sariff		log_err(1, "%s: unable to allocate sbuf", __func__);
162152851Sariff
163152851Sariff	if (strcmp(name, "lun") == 0) {
164152851Sariff		if (cur_lun != NULL)
165162931Sariff			log_errx(1, "%s: improper lun element nesting",
166152851Sariff			    __func__);
167152851Sariff
168152851Sariff		cur_lun = calloc(1, sizeof(*cur_lun));
169152851Sariff		if (cur_lun == NULL)
170152851Sariff			log_err(1, "%s: cannot allocate %zd bytes", __func__,
171152851Sariff			    sizeof(*cur_lun));
172152851Sariff
173152851Sariff		devlist->num_luns++;
174152851Sariff		devlist->cur_lun = cur_lun;
175152851Sariff
176152851Sariff		STAILQ_INIT(&cur_lun->attr_list);
177173329Sariff		STAILQ_INSERT_TAIL(&devlist->lun_list, cur_lun, links);
178152851Sariff
179152851Sariff		for (i = 0; attr[i] != NULL; i += 2) {
180152851Sariff			if (strcmp(attr[i], "id") == 0) {
181152851Sariff				cur_lun->lun_id = strtoull(attr[i+1], NULL, 0);
182152851Sariff			} else {
183162931Sariff				log_errx(1, "%s: invalid LUN attribute %s = %s",
184162931Sariff				     __func__, attr[i], attr[i+1]);
185162931Sariff			}
186152851Sariff		}
187152851Sariff	}
188152851Sariff}
189152851Sariff
190152851Sariffstatic void
191152851Sariffcctl_end_element(void *user_data, const char *name)
192152851Sariff{
193152851Sariff	struct cctl_devlist_data *devlist;
194193640Sariff	struct cctl_lun *cur_lun;
195193640Sariff	char *str;
196193640Sariff
197152851Sariff	devlist = (struct cctl_devlist_data *)user_data;
198152851Sariff	cur_lun = devlist->cur_lun;
199162931Sariff
200193640Sariff	if ((cur_lun == NULL)
201152851Sariff	 && (strcmp(name, "ctllunlist") != 0))
202152851Sariff		log_errx(1, "%s: cur_lun == NULL! (name = %s)", __func__, name);
203152851Sariff
204152851Sariff	if (devlist->cur_sb[devlist->level] == NULL)
205152851Sariff		log_errx(1, "%s: no valid sbuf at level %d (name %s)", __func__,
206152851Sariff		     devlist->level, name);
207157026Sariff
208152851Sariff	sbuf_finish(devlist->cur_sb[devlist->level]);
209152851Sariff	str = checked_strdup(sbuf_data(devlist->cur_sb[devlist->level]));
210152851Sariff
211153708Sariff	if (strlen(str) == 0) {
212153708Sariff		free(str);
213152851Sariff		str = NULL;
214152851Sariff	}
215152851Sariff
216152851Sariff	sbuf_delete(devlist->cur_sb[devlist->level]);
217152851Sariff	devlist->cur_sb[devlist->level] = NULL;
218152851Sariff	devlist->level--;
219152851Sariff
220152851Sariff	if (strcmp(name, "backend_type") == 0) {
221152851Sariff		cur_lun->backend_type = str;
222152851Sariff		str = NULL;
223152851Sariff	} else if (strcmp(name, "size") == 0) {
224152851Sariff		cur_lun->size_blocks = strtoull(str, NULL, 0);
225152851Sariff	} else if (strcmp(name, "blocksize") == 0) {
226152851Sariff		cur_lun->blocksize = strtoul(str, NULL, 0);
227152851Sariff	} else if (strcmp(name, "serial_number") == 0) {
228152851Sariff		cur_lun->serial_number = str;
229152851Sariff		str = NULL;
230152851Sariff	} else if (strcmp(name, "device_id") == 0) {
231152851Sariff		cur_lun->device_id = str;
232152851Sariff		str = NULL;
233152851Sariff	} else if (strcmp(name, "ctld_name") == 0) {
234162931Sariff		cur_lun->ctld_name = str;
235162931Sariff		str = NULL;
236164614Sariff	} else if (strcmp(name, "lun") == 0) {
237162931Sariff		devlist->cur_lun = NULL;
238152851Sariff	} else if (strcmp(name, "ctllunlist") == 0) {
239152851Sariff		/* Nothing. */
240152851Sariff	} else {
241152851Sariff		struct cctl_lun_nv *nv;
242152851Sariff
243152851Sariff		nv = calloc(1, sizeof(*nv));
244152851Sariff		if (nv == NULL)
245152851Sariff			log_err(1, "%s: can't allocate %zd bytes for nv pair",
246152851Sariff			    __func__, sizeof(*nv));
247152851Sariff
248152851Sariff		nv->name = checked_strdup(name);
249152851Sariff
250152851Sariff		nv->value = str;
251152851Sariff		str = NULL;
252152851Sariff		STAILQ_INSERT_TAIL(&cur_lun->attr_list, nv, links);
253152851Sariff	}
254152851Sariff
255152851Sariff	free(str);
256152851Sariff}
257152851Sariff
258152851Sariffstatic void
259152851Sariffcctl_start_pelement(void *user_data, const char *name, const char **attr)
260152851Sariff{
261152851Sariff	int i;
262152851Sariff	struct cctl_devlist_data *devlist;
263152851Sariff	struct cctl_port *cur_port;
264152851Sariff
265152851Sariff	devlist = (struct cctl_devlist_data *)user_data;
266152851Sariff	cur_port = devlist->cur_port;
267152851Sariff	devlist->level++;
268152851Sariff	if ((u_int)devlist->level >= (sizeof(devlist->cur_sb) /
269152851Sariff	    sizeof(devlist->cur_sb[0])))
270152851Sariff		log_errx(1, "%s: too many nesting levels, %zd max", __func__,
271152851Sariff		     sizeof(devlist->cur_sb) / sizeof(devlist->cur_sb[0]));
272162931Sariff
273152851Sariff	devlist->cur_sb[devlist->level] = sbuf_new_auto();
274152851Sariff	if (devlist->cur_sb[devlist->level] == NULL)
275152851Sariff		log_err(1, "%s: unable to allocate sbuf", __func__);
276152851Sariff
277152851Sariff	if (strcmp(name, "targ_port") == 0) {
278152851Sariff		if (cur_port != NULL)
279152851Sariff			log_errx(1, "%s: improper port element nesting (%s)",
280152851Sariff			    __func__, name);
281152851Sariff
282152851Sariff		cur_port = calloc(1, sizeof(*cur_port));
283152851Sariff		if (cur_port == NULL)
284152851Sariff			log_err(1, "%s: cannot allocate %zd bytes", __func__,
285152851Sariff			    sizeof(*cur_port));
286152851Sariff
287152851Sariff		devlist->num_ports++;
288152851Sariff		devlist->cur_port = cur_port;
289152851Sariff
290152851Sariff		STAILQ_INIT(&cur_port->attr_list);
291164614Sariff		STAILQ_INSERT_TAIL(&devlist->port_list, cur_port, links);
292153708Sariff
293152851Sariff		for (i = 0; attr[i] != NULL; i += 2) {
294153708Sariff			if (strcmp(attr[i], "id") == 0) {
295152851Sariff				cur_port->port_id = strtoul(attr[i+1], NULL, 0);
296152851Sariff			} else {
297152851Sariff				log_errx(1, "%s: invalid LUN attribute %s = %s",
298152851Sariff				     __func__, attr[i], attr[i+1]);
299152851Sariff			}
300152851Sariff		}
301152851Sariff	}
302152851Sariff}
303152851Sariff
304152851Sariffstatic void
305152851Sariffcctl_end_pelement(void *user_data, const char *name)
306152851Sariff{
307152851Sariff	struct cctl_devlist_data *devlist;
308152851Sariff	struct cctl_port *cur_port;
309152851Sariff	char *str;
310152851Sariff
311152851Sariff	devlist = (struct cctl_devlist_data *)user_data;
312162931Sariff	cur_port = devlist->cur_port;
313152851Sariff
314152851Sariff	if ((cur_port == NULL)
315152851Sariff	 && (strcmp(name, "ctlportlist") != 0))
316153708Sariff		log_errx(1, "%s: cur_port == NULL! (name = %s)", __func__, name);
317152851Sariff
318152851Sariff	if (devlist->cur_sb[devlist->level] == NULL)
319153708Sariff		log_errx(1, "%s: no valid sbuf at level %d (name %s)", __func__,
320152851Sariff		     devlist->level, name);
321152851Sariff
322152851Sariff	sbuf_finish(devlist->cur_sb[devlist->level]);
323152851Sariff	str = checked_strdup(sbuf_data(devlist->cur_sb[devlist->level]));
324152851Sariff
325152851Sariff	if (strlen(str) == 0) {
326152851Sariff		free(str);
327152851Sariff		str = NULL;
328162931Sariff	}
329152851Sariff
330162931Sariff	sbuf_delete(devlist->cur_sb[devlist->level]);
331152851Sariff	devlist->cur_sb[devlist->level] = NULL;
332152851Sariff	devlist->level--;
333152851Sariff
334162931Sariff	if (strcmp(name, "port_name") == 0) {
335152851Sariff		cur_port->port_name = str;
336152851Sariff		str = NULL;
337152851Sariff	} else if (strcmp(name, "cfiscsi_target") == 0) {
338162931Sariff		cur_port->cfiscsi_target = str;
339152851Sariff		str = NULL;
340152851Sariff	} else if (strcmp(name, "cfiscsi_state") == 0) {
341162931Sariff		cur_port->cfiscsi_state = strtoul(str, NULL, 0);
342152851Sariff	} else if (strcmp(name, "cfiscsi_portal_group_tag") == 0) {
343152851Sariff		cur_port->cfiscsi_portal_group_tag = strtoul(str, NULL, 0);
344152851Sariff	} else if (strcmp(name, "ctld_portal_group_name") == 0) {
345162931Sariff		cur_port->ctld_portal_group_name = str;
346162931Sariff		str = NULL;
347152851Sariff	} else if (strcmp(name, "targ_port") == 0) {
348152851Sariff		devlist->cur_port = NULL;
349152851Sariff	} else if (strcmp(name, "ctlportlist") == 0) {
350162931Sariff		/* Nothing. */
351152851Sariff	} else {
352152851Sariff		struct cctl_lun_nv *nv;
353162931Sariff
354152851Sariff		nv = calloc(1, sizeof(*nv));
355152851Sariff		if (nv == NULL)
356152851Sariff			log_err(1, "%s: can't allocate %zd bytes for nv pair",
357152851Sariff			    __func__, sizeof(*nv));
358152851Sariff
359152851Sariff		nv->name = checked_strdup(name);
360152851Sariff
361152851Sariff		nv->value = str;
362152851Sariff		str = NULL;
363152851Sariff		STAILQ_INSERT_TAIL(&cur_port->attr_list, nv, links);
364152851Sariff	}
365152851Sariff
366152851Sariff	free(str);
367164614Sariff}
368162931Sariff
369152851Sariffstatic void
370162931Sariffcctl_char_handler(void *user_data, const XML_Char *str, int len)
371152851Sariff{
372162931Sariff	struct cctl_devlist_data *devlist;
373152851Sariff
374152851Sariff	devlist = (struct cctl_devlist_data *)user_data;
375152851Sariff
376152851Sariff	sbuf_bcat(devlist->cur_sb[devlist->level], str, len);
377152851Sariff}
378152851Sariff
379152851Sariffstruct conf *
380152851Sariffconf_new_from_kernel(void)
381152851Sariff{
382152851Sariff	struct conf *conf = NULL;
383162931Sariff	struct target *targ;
384152851Sariff	struct portal_group *pg;
385152851Sariff	struct pport *pp;
386164614Sariff	struct port *cp;
387152851Sariff	struct lun *cl;
388152851Sariff	struct lun_option *lo;
389152851Sariff	struct ctl_lun_list list;
390152851Sariff	struct cctl_devlist_data devlist;
391162931Sariff	struct cctl_lun *lun;
392152851Sariff	struct cctl_port *port;
393152851Sariff	XML_Parser parser;
394152851Sariff	char *str;
395152851Sariff	int len, retval;
396152851Sariff
397162931Sariff	bzero(&devlist, sizeof(devlist));
398152851Sariff	STAILQ_INIT(&devlist.lun_list);
399162931Sariff	STAILQ_INIT(&devlist.port_list);
400152851Sariff
401152851Sariff	log_debugx("obtaining previously configured CTL luns from the kernel");
402152851Sariff
403152851Sariff	str = NULL;
404162931Sariff	len = 4096;
405152851Sariffretry:
406152851Sariff	str = realloc(str, len);
407152851Sariff	if (str == NULL)
408152851Sariff		log_err(1, "realloc");
409152851Sariff
410152851Sariff	bzero(&list, sizeof(list));
411152851Sariff	list.alloc_len = len;
412152851Sariff	list.status = CTL_LUN_LIST_NONE;
413162931Sariff	list.lun_xml = str;
414152851Sariff
415152851Sariff	if (ioctl(ctl_fd, CTL_LUN_LIST, &list) == -1) {
416164614Sariff		log_warn("error issuing CTL_LUN_LIST ioctl");
417164614Sariff		free(str);
418152851Sariff		return (NULL);
419152851Sariff	}
420152851Sariff
421162931Sariff	if (list.status == CTL_LUN_LIST_ERROR) {
422152851Sariff		log_warnx("error returned from CTL_LUN_LIST ioctl: %s",
423152851Sariff		    list.error_str);
424152851Sariff		free(str);
425164614Sariff		return (NULL);
426164614Sariff	}
427193640Sariff
428152851Sariff	if (list.status == CTL_LUN_LIST_NEED_MORE_SPACE) {
429152851Sariff		len = len << 1;
430152851Sariff		goto retry;
431152851Sariff	}
432152851Sariff
433152851Sariff	parser = XML_ParserCreate(NULL);
434152851Sariff	if (parser == NULL) {
435152851Sariff		log_warnx("unable to create XML parser");
436152851Sariff		free(str);
437152851Sariff		return (NULL);
438152851Sariff	}
439152851Sariff
440152851Sariff	XML_SetUserData(parser, &devlist);
441152851Sariff	XML_SetElementHandler(parser, cctl_start_element, cctl_end_element);
442152851Sariff	XML_SetCharacterDataHandler(parser, cctl_char_handler);
443152851Sariff
444152851Sariff	retval = XML_Parse(parser, str, strlen(str), 1);
445152851Sariff	XML_ParserFree(parser);
446152851Sariff	free(str);
447152851Sariff	if (retval != 1) {
448152851Sariff		log_warnx("XML_Parse failed");
449164614Sariff		return (NULL);
450152851Sariff	}
451152851Sariff
452152851Sariff	str = NULL;
453152851Sariff	len = 4096;
454152851Sariffretry_port:
455164614Sariff	str = realloc(str, len);
456152851Sariff	if (str == NULL)
457164614Sariff		log_err(1, "realloc");
458152851Sariff
459154595Sariff	bzero(&list, sizeof(list));
460152851Sariff	list.alloc_len = len;
461152851Sariff	list.status = CTL_LUN_LIST_NONE;
462152851Sariff	list.lun_xml = str;
463152851Sariff
464152851Sariff	if (ioctl(ctl_fd, CTL_PORT_LIST, &list) == -1) {
465152851Sariff		log_warn("error issuing CTL_PORT_LIST ioctl");
466164614Sariff		free(str);
467164614Sariff		return (NULL);
468152851Sariff	}
469152851Sariff
470152851Sariff	if (list.status == CTL_PORT_LIST_ERROR) {
471168847Sariff		log_warnx("error returned from CTL_PORT_LIST ioctl: %s",
472162931Sariff		    list.error_str);
473152851Sariff		free(str);
474152851Sariff		return (NULL);
475152851Sariff	}
476167648Sariff
477167648Sariff	if (list.status == CTL_LUN_LIST_NEED_MORE_SPACE) {
478164614Sariff		len = len << 1;
479162931Sariff		goto retry_port;
480152851Sariff	}
481152851Sariff
482162931Sariff	parser = XML_ParserCreate(NULL);
483152851Sariff	if (parser == NULL) {
484152851Sariff		log_warnx("unable to create XML parser");
485152851Sariff		free(str);
486152851Sariff		return (NULL);
487152851Sariff	}
488152851Sariff
489152851Sariff	XML_SetUserData(parser, &devlist);
490152851Sariff	XML_SetElementHandler(parser, cctl_start_pelement, cctl_end_pelement);
491152851Sariff	XML_SetCharacterDataHandler(parser, cctl_char_handler);
492152851Sariff
493152851Sariff	retval = XML_Parse(parser, str, strlen(str), 1);
494152851Sariff	XML_ParserFree(parser);
495152851Sariff	free(str);
496155800Sariff	if (retval != 1) {
497152851Sariff		log_warnx("XML_Parse failed");
498152851Sariff		return (NULL);
499152851Sariff	}
500152851Sariff
501152851Sariff	conf = conf_new();
502152851Sariff
503152851Sariff	STAILQ_FOREACH(port, &devlist.port_list, links) {
504164614Sariff
505152851Sariff		if (port->cfiscsi_target == NULL) {
506152851Sariff			log_debugx("CTL port %u \"%s\" wasn't managed by ctld; ",
507152851Sariff			    port->port_id, port->port_name);
508152851Sariff			pp = pport_find(conf, port->port_name);
509155800Sariff			if (pp == NULL) {
510152851Sariff#if 0
511152851Sariff				log_debugx("found new kernel port %u \"%s\"",
512152851Sariff				    port->port_id, port->port_name);
513152851Sariff#endif
514152851Sariff				pp = pport_new(conf, port->port_name, port->port_id);
515152851Sariff				if (pp == NULL) {
516153708Sariff					log_warnx("pport_new failed");
517152851Sariff					continue;
518152851Sariff				}
519162931Sariff			}
520152851Sariff			continue;
521152851Sariff		}
522193640Sariff		if (port->cfiscsi_state != 1) {
523152851Sariff			log_debugx("CTL port %ju is not active (%d); ignoring",
524152851Sariff			    (uintmax_t)port->port_id, port->cfiscsi_state);
525152851Sariff			continue;
526162931Sariff		}
527152851Sariff
528152851Sariff		targ = target_find(conf, port->cfiscsi_target);
529152851Sariff		if (targ == NULL) {
530167648Sariff#if 0
531167648Sariff			log_debugx("found new kernel target %s for CTL port %ld",
532152851Sariff			    port->cfiscsi_target, port->port_id);
533152851Sariff#endif
534152851Sariff			targ = target_new(conf, port->cfiscsi_target);
535152851Sariff			if (targ == NULL) {
536167648Sariff				log_warnx("target_new failed");
537152851Sariff				continue;
538167648Sariff			}
539167648Sariff		}
540167648Sariff
541167648Sariff		if (port->ctld_portal_group_name == NULL)
542167648Sariff			continue;
543167648Sariff		pg = portal_group_find(conf, port->ctld_portal_group_name);
544167648Sariff		if (pg == NULL) {
545167648Sariff#if 0
546167648Sariff			log_debugx("found new kernel portal group %s for CTL port %ld",
547167648Sariff			    port->ctld_portal_group_name, port->port_id);
548167648Sariff#endif
549167648Sariff			pg = portal_group_new(conf, port->ctld_portal_group_name);
550167648Sariff			if (pg == NULL) {
551167648Sariff				log_warnx("portal_group_new failed");
552167648Sariff				continue;
553167648Sariff			}
554167648Sariff		}
555167648Sariff		pg->pg_tag = port->cfiscsi_portal_group_tag;
556164614Sariff		cp = port_new(conf, targ, pg);
557167648Sariff		if (cp == NULL) {
558167648Sariff			log_warnx("port_new failed");
559164614Sariff			continue;
560167648Sariff		}
561152851Sariff		cp->p_ctl_port = port->port_id;
562164614Sariff	}
563167648Sariff
564164614Sariff	STAILQ_FOREACH(lun, &devlist.lun_list, links) {
565193640Sariff		struct cctl_lun_nv *nv;
566167648Sariff
567167648Sariff		if (lun->ctld_name == NULL) {
568193640Sariff			log_debugx("CTL lun %ju wasn't managed by ctld; "
569167648Sariff			    "ignoring", (uintmax_t)lun->lun_id);
570167648Sariff			continue;
571167648Sariff		}
572167648Sariff
573167648Sariff		cl = lun_find(conf, lun->ctld_name);
574167648Sariff		if (cl != NULL) {
575167648Sariff			log_warnx("found CTL lun %ju \"%s\", "
576164614Sariff			    "also backed by CTL lun %d; ignoring",
577152851Sariff			    (uintmax_t)lun->lun_id, lun->ctld_name,
578152851Sariff			    cl->l_ctl_lun);
579152851Sariff			continue;
580152851Sariff		}
581152851Sariff
582164614Sariff		log_debugx("found CTL lun %ju \"%s\"",
583164614Sariff		    (uintmax_t)lun->lun_id, lun->ctld_name);
584152851Sariff
585152851Sariff		cl = lun_new(conf, lun->ctld_name);
586152851Sariff		if (cl == NULL) {
587152851Sariff			log_warnx("lun_new failed");
588164614Sariff			continue;
589164614Sariff		}
590164614Sariff		lun_set_backend(cl, lun->backend_type);
591164614Sariff		lun_set_blocksize(cl, lun->blocksize);
592164614Sariff		lun_set_device_id(cl, lun->device_id);
593164614Sariff		lun_set_serial(cl, lun->serial_number);
594164614Sariff		lun_set_size(cl, lun->size_blocks * cl->l_blocksize);
595164614Sariff		lun_set_ctl_lun(cl, lun->lun_id);
596164614Sariff
597164614Sariff		STAILQ_FOREACH(nv, &lun->attr_list, links) {
598152851Sariff			if (strcmp(nv->name, "file") == 0 ||
599164614Sariff			    strcmp(nv->name, "dev") == 0) {
600162931Sariff				lun_set_path(cl, nv->value);
601164614Sariff				continue;
602152851Sariff			}
603152851Sariff			lo = lun_option_new(cl, nv->name, nv->value);
604152851Sariff			if (lo == NULL)
605162931Sariff				log_warnx("unable to add CTL lun option %s "
606162931Sariff				    "for CTL lun %ju \"%s\"",
607152851Sariff				    nv->name, (uintmax_t) lun->lun_id,
608152851Sariff				    cl->l_name);
609162931Sariff		}
610155800Sariff	}
611152851Sariff
612164614Sariff	return (conf);
613155800Sariff}
614164614Sariff
615162931Sariffstatic void
616155800Sariffstr_arg(struct ctl_be_arg *arg, const char *name, const char *value)
617155800Sariff{
618162931Sariff
619155800Sariff	arg->namelen = strlen(name) + 1;
620155800Sariff	arg->name = __DECONST(char *, name);
621155800Sariff	arg->vallen = strlen(value) + 1;
622162931Sariff	arg->value = __DECONST(char *, value);
623164614Sariff	arg->flags = CTL_BEARG_ASCII | CTL_BEARG_RD;
624162931Sariff}
625164614Sariff
626162931Sariffint
627152851Sariffkernel_lun_add(struct lun *lun)
628164614Sariff{
629162931Sariff	struct lun_option *lo;
630164614Sariff	struct ctl_lun_req req;
631155800Sariff	int error, i, num_options;
632162931Sariff
633162931Sariff	bzero(&req, sizeof(req));
634164614Sariff
635164614Sariff	strlcpy(req.backend, lun->l_backend, sizeof(req.backend));
636164614Sariff	req.reqtype = CTL_LUNREQ_CREATE;
637162931Sariff
638162931Sariff	req.reqdata.create.blocksize_bytes = lun->l_blocksize;
639162931Sariff
640164614Sariff	if (lun->l_size != 0)
641164614Sariff		req.reqdata.create.lun_size_bytes = lun->l_size;
642164614Sariff
643164614Sariff	req.reqdata.create.flags |= CTL_LUN_FLAG_DEV_TYPE;
644162931Sariff	req.reqdata.create.device_type = T_DIRECT;
645164614Sariff
646162931Sariff	if (lun->l_serial != NULL) {
647164614Sariff		strncpy(req.reqdata.create.serial_num, lun->l_serial,
648162931Sariff			sizeof(req.reqdata.create.serial_num));
649164614Sariff		req.reqdata.create.flags |= CTL_LUN_FLAG_SERIAL_NUM;
650162931Sariff	}
651162931Sariff
652162931Sariff	if (lun->l_device_id != NULL) {
653155800Sariff		strncpy(req.reqdata.create.device_id, lun->l_device_id,
654162931Sariff			sizeof(req.reqdata.create.device_id));
655164614Sariff		req.reqdata.create.flags |= CTL_LUN_FLAG_DEVID;
656162931Sariff	}
657162931Sariff
658152851Sariff	if (lun->l_path != NULL) {
659152851Sariff		lo = lun_option_find(lun, "file");
660164614Sariff		if (lo != NULL) {
661164614Sariff			lun_option_set(lo, lun->l_path);
662164614Sariff		} else {
663164614Sariff			lo = lun_option_new(lun, "file", lun->l_path);
664164614Sariff			assert(lo != NULL);
665164614Sariff		}
666171329Sariff	}
667164614Sariff
668164614Sariff	lo = lun_option_find(lun, "ctld_name");
669164614Sariff	if (lo != NULL) {
670164614Sariff		lun_option_set(lo, lun->l_name);
671164614Sariff	} else {
672164614Sariff		lo = lun_option_new(lun, "ctld_name", lun->l_name);
673164614Sariff		assert(lo != NULL);
674164614Sariff	}
675164614Sariff
676164614Sariff	lo = lun_option_find(lun, "scsiname");
677164614Sariff	if (lo == NULL && lun->l_scsiname != NULL) {
678164614Sariff		lo = lun_option_new(lun, "scsiname", lun->l_scsiname);
679164614Sariff		assert(lo != NULL);
680164614Sariff	}
681164614Sariff
682164614Sariff	num_options = 0;
683164614Sariff	TAILQ_FOREACH(lo, &lun->l_options, lo_next)
684171329Sariff		num_options++;
685171329Sariff
686164614Sariff	req.num_be_args = num_options;
687164614Sariff	if (num_options > 0) {
688164614Sariff		req.be_args = malloc(num_options * sizeof(*req.be_args));
689164614Sariff		if (req.be_args == NULL) {
690164614Sariff			log_warn("error allocating %zd bytes",
691164614Sariff			    num_options * sizeof(*req.be_args));
692164614Sariff			return (1);
693164614Sariff		}
694164614Sariff
695164614Sariff		i = 0;
696164614Sariff		TAILQ_FOREACH(lo, &lun->l_options, lo_next) {
697164614Sariff			str_arg(&req.be_args[i], lo->lo_name, lo->lo_value);
698164614Sariff			i++;
699164614Sariff		}
700164614Sariff		assert(i == num_options);
701164614Sariff	}
702164614Sariff
703164614Sariff	error = ioctl(ctl_fd, CTL_LUN_REQ, &req);
704164614Sariff	free(req.be_args);
705164614Sariff	if (error != 0) {
706164614Sariff		log_warn("error issuing CTL_LUN_REQ ioctl");
707164614Sariff		return (1);
708164614Sariff	}
709164614Sariff
710164614Sariff	switch (req.status) {
711164614Sariff	case CTL_LUN_ERROR:
712164614Sariff		log_warnx("LUN creation error: %s", req.error_str);
713164614Sariff		return (1);
714164614Sariff	case CTL_LUN_WARNING:
715164614Sariff		log_warnx("LUN creation warning: %s", req.error_str);
716164614Sariff		break;
717162931Sariff	case CTL_LUN_OK:
718164614Sariff		break;
719164614Sariff	default:
720164614Sariff		log_warnx("unknown LUN creation status: %d",
721164614Sariff		    req.status);
722164614Sariff		return (1);
723164614Sariff	}
724164614Sariff
725170521Sariff	lun_set_ctl_lun(lun, req.reqdata.create.req_lun_id);
726170521Sariff	return (0);
727170521Sariff}
728164614Sariff
729164614Sariffint
730164614Sariffkernel_lun_resize(struct lun *lun)
731164614Sariff{
732164614Sariff	struct ctl_lun_req req;
733164614Sariff
734164614Sariff	bzero(&req, sizeof(req));
735164614Sariff
736164614Sariff	strlcpy(req.backend, lun->l_backend, sizeof(req.backend));
737164614Sariff	req.reqtype = CTL_LUNREQ_MODIFY;
738164614Sariff
739164614Sariff	req.reqdata.modify.lun_id = lun->l_ctl_lun;
740164614Sariff	req.reqdata.modify.lun_size_bytes = lun->l_size;
741164614Sariff
742193640Sariff	if (ioctl(ctl_fd, CTL_LUN_REQ, &req) == -1) {
743164614Sariff		log_warn("error issuing CTL_LUN_REQ ioctl");
744164614Sariff		return (1);
745164614Sariff	}
746164614Sariff
747164614Sariff	switch (req.status) {
748164614Sariff	case CTL_LUN_ERROR:
749164614Sariff		log_warnx("LUN modification error: %s", req.error_str);
750164614Sariff		return (1);
751164614Sariff	case CTL_LUN_WARNING:
752164614Sariff		log_warnx("LUN modification warning: %s", req.error_str);
753164614Sariff		break;
754164614Sariff	case CTL_LUN_OK:
755164614Sariff		break;
756164614Sariff	default:
757164614Sariff		log_warnx("unknown LUN modification status: %d",
758164614Sariff		    req.status);
759164614Sariff		return (1);
760164614Sariff	}
761164614Sariff
762164614Sariff	return (0);
763164614Sariff}
764164614Sariff
765164614Sariffint
766164614Sariffkernel_lun_remove(struct lun *lun)
767171329Sariff{
768164614Sariff	struct ctl_lun_req req;
769164614Sariff
770164614Sariff	bzero(&req, sizeof(req));
771164614Sariff
772164614Sariff	strlcpy(req.backend, lun->l_backend, sizeof(req.backend));
773171329Sariff	req.reqtype = CTL_LUNREQ_RM;
774164614Sariff
775164614Sariff	req.reqdata.rm.lun_id = lun->l_ctl_lun;
776164614Sariff
777164614Sariff	if (ioctl(ctl_fd, CTL_LUN_REQ, &req) == -1) {
778164614Sariff		log_warn("error issuing CTL_LUN_REQ ioctl");
779171329Sariff		return (1);
780164614Sariff	}
781164614Sariff
782164614Sariff	switch (req.status) {
783164614Sariff	case CTL_LUN_ERROR:
784193640Sariff		log_warnx("LUN removal error: %s", req.error_str);
785164614Sariff		return (1);
786164614Sariff	case CTL_LUN_WARNING:
787164614Sariff		log_warnx("LUN removal warning: %s", req.error_str);
788164614Sariff		break;
789164614Sariff	case CTL_LUN_OK:
790164614Sariff		break;
791164614Sariff	default:
792164614Sariff		log_warnx("unknown LUN removal status: %d", req.status);
793164614Sariff		return (1);
794164614Sariff	}
795164614Sariff
796164614Sariff	return (0);
797164614Sariff}
798164614Sariff
799164614Sariffvoid
800164614Sariffkernel_handoff(struct connection *conn)
801164614Sariff{
802164614Sariff	struct ctl_iscsi req;
803164614Sariff
804164614Sariff	bzero(&req, sizeof(req));
805164614Sariff
806164614Sariff	req.type = CTL_ISCSI_HANDOFF;
807164614Sariff	strlcpy(req.data.handoff.initiator_name,
808164614Sariff	    conn->conn_initiator_name, sizeof(req.data.handoff.initiator_name));
809164614Sariff	strlcpy(req.data.handoff.initiator_addr,
810164614Sariff	    conn->conn_initiator_addr, sizeof(req.data.handoff.initiator_addr));
811164614Sariff	if (conn->conn_initiator_alias != NULL) {
812164614Sariff		strlcpy(req.data.handoff.initiator_alias,
813164614Sariff		    conn->conn_initiator_alias, sizeof(req.data.handoff.initiator_alias));
814164614Sariff	}
815164614Sariff	memcpy(req.data.handoff.initiator_isid, conn->conn_initiator_isid,
816164614Sariff	    sizeof(req.data.handoff.initiator_isid));
817164614Sariff	strlcpy(req.data.handoff.target_name,
818164614Sariff	    conn->conn_target->t_name, sizeof(req.data.handoff.target_name));
819164614Sariff#ifdef ICL_KERNEL_PROXY
820164614Sariff	if (proxy_mode)
821164614Sariff		req.data.handoff.connection_id = conn->conn_socket;
822164614Sariff	else
823164614Sariff		req.data.handoff.socket = conn->conn_socket;
824164614Sariff#else
825193640Sariff	req.data.handoff.socket = conn->conn_socket;
826162931Sariff#endif
827162931Sariff	req.data.handoff.portal_group_tag =
828162931Sariff	    conn->conn_portal->p_portal_group->pg_tag;
829162931Sariff	if (conn->conn_header_digest == CONN_DIGEST_CRC32C)
830162931Sariff		req.data.handoff.header_digest = CTL_ISCSI_DIGEST_CRC32C;
831162931Sariff	if (conn->conn_data_digest == CONN_DIGEST_CRC32C)
832162931Sariff		req.data.handoff.data_digest = CTL_ISCSI_DIGEST_CRC32C;
833164614Sariff	req.data.handoff.cmdsn = conn->conn_cmdsn;
834164614Sariff	req.data.handoff.statsn = conn->conn_statsn;
835164614Sariff	req.data.handoff.max_recv_data_segment_length =
836164614Sariff	    conn->conn_max_data_segment_length;
837162931Sariff	req.data.handoff.max_burst_length = conn->conn_max_burst_length;
838162931Sariff	req.data.handoff.immediate_data = conn->conn_immediate_data;
839162931Sariff
840162931Sariff	if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) {
841162931Sariff		log_err(1, "error issuing CTL_ISCSI ioctl; "
842152851Sariff		    "dropping connection");
843152851Sariff	}
844152851Sariff
845152851Sariff	if (req.status != CTL_ISCSI_OK) {
846152851Sariff		log_errx(1, "error returned from CTL iSCSI handoff request: "
847152851Sariff		    "%s; dropping connection", req.error_str);
848162931Sariff	}
849162931Sariff}
850152851Sariff
851152851Sariffint
852152851Sariffkernel_port_add(struct port *port)
853152851Sariff{
854152851Sariff	struct ctl_port_entry entry;
855152851Sariff	struct ctl_req req;
856152851Sariff	struct ctl_lun_map lm;
857167648Sariff	struct target *targ = port->p_target;
858152851Sariff	struct portal_group *pg = port->p_portal_group;
859152851Sariff	char tagstr[16];
860152851Sariff	int error, i, n;
861193640Sariff
862152851Sariff	/* Create iSCSI port. */
863152851Sariff	if (port->p_portal_group) {
864152851Sariff		bzero(&req, sizeof(req));
865152851Sariff		strlcpy(req.driver, "iscsi", sizeof(req.driver));
866152851Sariff		req.reqtype = CTL_REQ_CREATE;
867152851Sariff		req.num_args = 5;
868152851Sariff		req.args = malloc(req.num_args * sizeof(*req.args));
869152851Sariff		if (req.args == NULL)
870152851Sariff			log_err(1, "malloc");
871152851Sariff		n = 0;
872152851Sariff		req.args[n].namelen = sizeof("port_id");
873164614Sariff		req.args[n].name = __DECONST(char *, "port_id");
874152851Sariff		req.args[n].vallen = sizeof(port->p_ctl_port);
875152851Sariff		req.args[n].value = &port->p_ctl_port;
876164614Sariff		req.args[n++].flags = CTL_BEARG_WR;
877164614Sariff		str_arg(&req.args[n++], "cfiscsi_target", targ->t_name);
878164614Sariff		snprintf(tagstr, sizeof(tagstr), "%d", pg->pg_tag);
879164614Sariff		str_arg(&req.args[n++], "cfiscsi_portal_group_tag", tagstr);
880152851Sariff		if (targ->t_alias)
881152851Sariff			str_arg(&req.args[n++], "cfiscsi_target_alias", targ->t_alias);
882152851Sariff		str_arg(&req.args[n++], "ctld_portal_group_name", pg->pg_name);
883152851Sariff		req.num_args = n;
884152851Sariff		error = ioctl(ctl_fd, CTL_PORT_REQ, &req);
885152851Sariff		free(req.args);
886152851Sariff		if (error != 0) {
887171329Sariff			log_warn("error issuing CTL_PORT_REQ ioctl");
888171329Sariff			return (1);
889164614Sariff		}
890171329Sariff		if (req.status == CTL_LUN_ERROR) {
891171329Sariff			log_warnx("error returned from port creation request: %s",
892164614Sariff			    req.error_str);
893152851Sariff			return (1);
894152851Sariff		}
895152851Sariff		if (req.status != CTL_LUN_OK) {
896152851Sariff			log_warnx("unknown port creation request status %d",
897152851Sariff			    req.status);
898152851Sariff			return (1);
899152851Sariff		}
900152851Sariff	} else if (port->p_pport) {
901152851Sariff		port->p_ctl_port = port->p_pport->pp_ctl_port;
902152851Sariff
903152851Sariff		if (strncmp(targ->t_name, "naa.", 4) == 0 &&
904152851Sariff		    strlen(targ->t_name) == 20) {
905152851Sariff			bzero(&entry, sizeof(entry));
906152851Sariff			entry.port_type = CTL_PORT_NONE;
907152851Sariff			entry.targ_port = port->p_ctl_port;
908152851Sariff			entry.flags |= CTL_PORT_WWNN_VALID;
909152851Sariff			entry.wwnn = strtoull(targ->t_name + 4, NULL, 16);
910172568Skevlo			if (ioctl(ctl_fd, CTL_SET_PORT_WWNS, &entry) == -1)
911152851Sariff				log_warn("CTL_SET_PORT_WWNS ioctl failed");
912152851Sariff		}
913152851Sariff	}
914170720Sariff
915152851Sariff	/* Explicitly enable mapping to block any access except allowed. */
916152851Sariff	lm.port = port->p_ctl_port;
917152851Sariff	lm.plun = UINT32_MAX;
918152851Sariff	lm.lun = 0;
919152851Sariff	error = ioctl(ctl_fd, CTL_LUN_MAP, &lm);
920164614Sariff	if (error != 0)
921164614Sariff		log_warn("CTL_LUN_MAP ioctl failed");
922164614Sariff
923164614Sariff	/* Map configured LUNs */
924164614Sariff	for (i = 0; i < MAX_LUNS; i++) {
925152851Sariff		if (targ->t_luns[i] == NULL)
926152851Sariff			continue;
927152851Sariff		lm.port = port->p_ctl_port;
928152851Sariff		lm.plun = i;
929152851Sariff		lm.lun = targ->t_luns[i]->l_ctl_lun;
930152851Sariff		error = ioctl(ctl_fd, CTL_LUN_MAP, &lm);
931152851Sariff		if (error != 0)
932152851Sariff			log_warn("CTL_LUN_MAP ioctl failed");
933152851Sariff	}
934152851Sariff
935152851Sariff	/* Enable port */
936152851Sariff	bzero(&entry, sizeof(entry));
937152851Sariff	entry.targ_port = port->p_ctl_port;
938152851Sariff	error = ioctl(ctl_fd, CTL_ENABLE_PORT, &entry);
939152851Sariff	if (error != 0) {
940152851Sariff		log_warn("CTL_ENABLE_PORT ioctl failed");
941152851Sariff		return (-1);
942152851Sariff	}
943152851Sariff
944152851Sariff	return (0);
945152851Sariff}
946152851Sariff
947164614Sariffint
948152851Sariffkernel_port_update(struct port *port)
949152851Sariff{
950152851Sariff	struct ctl_lun_map lm;
951152851Sariff	struct target *targ = port->p_target;
952152851Sariff	int error, i;
953152851Sariff
954152851Sariff	/* Map configured LUNs and unmap others */
955152851Sariff	for (i = 0; i < MAX_LUNS; i++) {
956152851Sariff		lm.port = port->p_ctl_port;
957152851Sariff		lm.plun = i;
958152851Sariff		if (targ->t_luns[i] == NULL)
959152851Sariff			lm.lun = UINT32_MAX;
960152851Sariff		else
961164614Sariff			lm.lun = targ->t_luns[i]->l_ctl_lun;
962164614Sariff		error = ioctl(ctl_fd, CTL_LUN_MAP, &lm);
963164614Sariff		if (error != 0)
964164614Sariff			log_warn("CTL_LUN_MAP ioctl failed");
965164614Sariff	}
966164614Sariff	return (0);
967164614Sariff}
968164614Sariff
969164614Sariffint
970164614Sariffkernel_port_remove(struct port *port)
971164614Sariff{
972164614Sariff	struct ctl_port_entry entry;
973164614Sariff	struct ctl_lun_map lm;
974164614Sariff	struct ctl_req req;
975170289Sdwmalone	char tagstr[16];
976164614Sariff	struct target *targ = port->p_target;
977164614Sariff	struct portal_group *pg = port->p_portal_group;
978164614Sariff	int error;
979164614Sariff
980164614Sariff	/* Disable port */
981164614Sariff	bzero(&entry, sizeof(entry));
982164614Sariff	entry.targ_port = port->p_ctl_port;
983164614Sariff	error = ioctl(ctl_fd, CTL_DISABLE_PORT, &entry);
984164614Sariff	if (error != 0) {
985164614Sariff		log_warn("CTL_DISABLE_PORT ioctl failed");
986164614Sariff		return (-1);
987164614Sariff	}
988164614Sariff
989164614Sariff	/* Remove iSCSI port. */
990164614Sariff	if (port->p_portal_group) {
991164614Sariff		bzero(&req, sizeof(req));
992164614Sariff		strlcpy(req.driver, "iscsi", sizeof(req.driver));
993164614Sariff		req.reqtype = CTL_REQ_REMOVE;
994164614Sariff		req.num_args = 2;
995164614Sariff		req.args = malloc(req.num_args * sizeof(*req.args));
996164614Sariff		if (req.args == NULL)
997164614Sariff			log_err(1, "malloc");
998164614Sariff		str_arg(&req.args[0], "cfiscsi_target", targ->t_name);
999164614Sariff		snprintf(tagstr, sizeof(tagstr), "%d", pg->pg_tag);
1000164614Sariff		str_arg(&req.args[1], "cfiscsi_portal_group_tag", tagstr);
1001152851Sariff		error = ioctl(ctl_fd, CTL_PORT_REQ, &req);
1002152851Sariff		free(req.args);
1003152851Sariff		if (error != 0) {
1004152851Sariff			log_warn("error issuing CTL_PORT_REQ ioctl");
1005155800Sariff			return (1);
1006164614Sariff		}
1007152851Sariff		if (req.status == CTL_LUN_ERROR) {
1008152851Sariff			log_warnx("error returned from port removal request: %s",
1009152851Sariff			    req.error_str);
1010152851Sariff			return (1);
1011152851Sariff		}
1012152851Sariff		if (req.status != CTL_LUN_OK) {
1013152851Sariff			log_warnx("unknown port removal request status %d",
1014152851Sariff			    req.status);
1015152851Sariff			return (1);
1016164614Sariff		}
1017164614Sariff	} else {
1018164614Sariff		/* Disable LUN mapping. */
1019170720Sariff		lm.port = port->p_ctl_port;
1020170720Sariff		lm.plun = UINT32_MAX;
1021170720Sariff		lm.lun = UINT32_MAX;
1022170720Sariff		error = ioctl(ctl_fd, CTL_LUN_MAP, &lm);
1023170720Sariff		if (error != 0)
1024170720Sariff			log_warn("CTL_LUN_MAP ioctl failed");
1025170720Sariff	}
1026170720Sariff	return (0);
1027170720Sariff}
1028152851Sariff
1029164614Sariff#ifdef ICL_KERNEL_PROXY
1030152851Sariffvoid
1031152851Sariffkernel_listen(struct addrinfo *ai, bool iser, int portal_id)
1032170720Sariff{
1033152851Sariff	struct ctl_iscsi req;
1034152851Sariff
1035152851Sariff	bzero(&req, sizeof(req));
1036152851Sariff
1037157026Sariff	req.type = CTL_ISCSI_LISTEN;
1038152851Sariff	req.data.listen.iser = iser;
1039152851Sariff	req.data.listen.domain = ai->ai_family;
1040152851Sariff	req.data.listen.socktype = ai->ai_socktype;
1041152851Sariff	req.data.listen.protocol = ai->ai_protocol;
1042152851Sariff	req.data.listen.addr = ai->ai_addr;
1043152851Sariff	req.data.listen.addrlen = ai->ai_addrlen;
1044152851Sariff	req.data.listen.portal_id = portal_id;
1045152851Sariff
1046164614Sariff	if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1)
1047152851Sariff		log_err(1, "error issuing CTL_ISCSI ioctl");
1048152851Sariff
1049152851Sariff	if (req.status != CTL_ISCSI_OK) {
1050152851Sariff		log_errx(1, "error returned from CTL iSCSI listen: %s",
1051152851Sariff		    req.error_str);
1052152851Sariff	}
1053164614Sariff}
1054152851Sariff
1055152851Sariffvoid
1056152851Sariffkernel_accept(int *connection_id, int *portal_id,
1057152851Sariff    struct sockaddr *client_sa, socklen_t *client_salen)
1058164614Sariff{
1059152851Sariff	struct ctl_iscsi req;
1060152851Sariff	struct sockaddr_storage ss;
1061152851Sariff
1062152851Sariff	bzero(&req, sizeof(req));
1063152851Sariff
1064152851Sariff	req.type = CTL_ISCSI_ACCEPT;
1065152851Sariff	req.data.accept.initiator_addr = (struct sockaddr *)&ss;
1066157026Sariff
1067152851Sariff	if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1)
1068152851Sariff		log_err(1, "error issuing CTL_ISCSI ioctl");
1069152851Sariff
1070152851Sariff	if (req.status != CTL_ISCSI_OK) {
1071152851Sariff		log_errx(1, "error returned from CTL iSCSI accept: %s",
1072152851Sariff		    req.error_str);
1073164614Sariff	}
1074164614Sariff
1075155800Sariff	*connection_id = req.data.accept.connection_id;
1076167502Sariff	*portal_id = req.data.accept.portal_id;
1077155800Sariff	*client_salen = req.data.accept.initiator_addrlen;
1078164614Sariff	memcpy(client_sa, &ss, *client_salen);
1079164614Sariff}
1080155800Sariff
1081155800Sariffvoid
1082155800Sariffkernel_send(struct pdu *pdu)
1083155800Sariff{
1084155800Sariff	struct ctl_iscsi req;
1085152851Sariff
1086152851Sariff	bzero(&req, sizeof(req));
1087152851Sariff
1088152851Sariff	req.type = CTL_ISCSI_SEND;
1089152851Sariff	req.data.send.connection_id = pdu->pdu_connection->conn_socket;
1090152851Sariff	req.data.send.bhs = pdu->pdu_bhs;
1091152851Sariff	req.data.send.data_segment_len = pdu->pdu_data_len;
1092152851Sariff	req.data.send.data_segment = pdu->pdu_data;
1093152851Sariff
1094152851Sariff	if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) {
1095164614Sariff		log_err(1, "error issuing CTL_ISCSI ioctl; "
1096164614Sariff		    "dropping connection");
1097164614Sariff	}
1098164614Sariff
1099164614Sariff	if (req.status != CTL_ISCSI_OK) {
1100162931Sariff		log_errx(1, "error returned from CTL iSCSI send: "
1101164614Sariff		    "%s; dropping connection", req.error_str);
1102164614Sariff	}
1103152851Sariff}
1104152851Sariff
1105152851Sariffvoid
1106152851Sariffkernel_receive(struct pdu *pdu)
1107164614Sariff{
1108164614Sariff	struct ctl_iscsi req;
1109152851Sariff
1110152851Sariff	pdu->pdu_data = malloc(MAX_DATA_SEGMENT_LENGTH);
1111152851Sariff	if (pdu->pdu_data == NULL)
1112152851Sariff		log_err(1, "malloc");
1113152851Sariff
1114157026Sariff	bzero(&req, sizeof(req));
1115157026Sariff
1116157026Sariff	req.type = CTL_ISCSI_RECEIVE;
1117157026Sariff	req.data.receive.connection_id = pdu->pdu_connection->conn_socket;
1118157026Sariff	req.data.receive.bhs = pdu->pdu_bhs;
1119157026Sariff	req.data.receive.data_segment_len = MAX_DATA_SEGMENT_LENGTH;
1120157026Sariff	req.data.receive.data_segment = pdu->pdu_data;
1121157026Sariff
1122170721Sariff	if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) {
1123170721Sariff		log_err(1, "error issuing CTL_ISCSI ioctl; "
1124170721Sariff		    "dropping connection");
1125170721Sariff	}
1126170721Sariff
1127170721Sariff	if (req.status != CTL_ISCSI_OK) {
1128170721Sariff		log_errx(1, "error returned from CTL iSCSI receive: "
1129157026Sariff		    "%s; dropping connection", req.error_str);
1130152851Sariff	}
1131157026Sariff
1132157026Sariff}
1133157026Sariff
1134152851Sariff#endif /* ICL_KERNEL_PROXY */
1135167773Sariff
1136157026Sariff/*
1137157026Sariff * XXX: I CANT INTO LATIN
1138152851Sariff */
1139167773Sariffvoid
1140157026Sariffkernel_capsicate(void)
1141157026Sariff{
1142152851Sariff	int error;
1143167773Sariff	cap_rights_t rights;
1144157026Sariff	const unsigned long cmds[] = { CTL_ISCSI };
1145157026Sariff
1146152851Sariff	cap_rights_init(&rights, CAP_IOCTL);
1147167773Sariff	error = cap_rights_limit(ctl_fd, &rights);
1148157026Sariff	if (error != 0 && errno != ENOSYS)
1149167773Sariff		log_err(1, "cap_rights_limit");
1150152851Sariff
1151167773Sariff	error = cap_ioctls_limit(ctl_fd, cmds,
1152167773Sariff	    sizeof(cmds) / sizeof(cmds[0]));
1153167773Sariff	if (error != 0 && errno != ENOSYS)
1154157026Sariff		log_err(1, "cap_ioctls_limit");
1155167773Sariff
1156157026Sariff	error = cap_enter();
1157152851Sariff	if (error != 0 && errno != ENOSYS)
1158167773Sariff		log_err(1, "cap_enter");
1159157026Sariff
1160157026Sariff	if (cap_sandboxed())
1161152851Sariff		log_debugx("Capsicum capability mode enabled");
1162157026Sariff	else
1163157026Sariff		log_warnx("Capsicum capability mode not supported");
1164170721Sariff}
1165152851Sariff
1166152851Sariff