kernel.c revision 279590
1255570Strasz/*-
2255570Strasz * Copyright (c) 2003, 2004 Silicon Graphics International Corp.
3255570Strasz * Copyright (c) 1997-2007 Kenneth D. Merry
4255570Strasz * Copyright (c) 2012 The FreeBSD Foundation
5255570Strasz * All rights reserved.
6255570Strasz *
7255570Strasz * Portions of this software were developed by Edward Tomasz Napierala
8255570Strasz * under sponsorship from the FreeBSD Foundation.
9255570Strasz *
10255570Strasz * Redistribution and use in source and binary forms, with or without
11255570Strasz * modification, are permitted provided that the following conditions
12255570Strasz * are met:
13255570Strasz * 1. Redistributions of source code must retain the above copyright
14255570Strasz *    notice, this list of conditions, and the following disclaimer,
15255570Strasz *    without modification.
16255570Strasz * 2. Redistributions in binary form must reproduce at minimum a disclaimer
17255570Strasz *    substantially similar to the "NO WARRANTY" disclaimer below
18255570Strasz *    ("Disclaimer") and any redistribution must be conditioned upon
19255570Strasz *    including a substantially similar Disclaimer requirement for further
20255570Strasz *    binary redistribution.
21255570Strasz *
22255570Strasz * NO WARRANTY
23255570Strasz * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24255570Strasz * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25255570Strasz * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
26255570Strasz * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27255570Strasz * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28255570Strasz * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29255570Strasz * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30255570Strasz * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31255570Strasz * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
32255570Strasz * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33255570Strasz * POSSIBILITY OF SUCH DAMAGES.
34255570Strasz *
35255570Strasz */
36255570Strasz
37270279Strasz#include <sys/cdefs.h>
38270279Strasz__FBSDID("$FreeBSD: head/usr.sbin/ctld/kernel.c 279590 2015-03-04 14:12:38Z mav $");
39270279Strasz
40255570Strasz#include <sys/ioctl.h>
41255570Strasz#include <sys/types.h>
42255570Strasz#include <sys/stat.h>
43255570Strasz#include <sys/param.h>
44255570Strasz#include <sys/linker.h>
45255570Strasz#include <sys/queue.h>
46255570Strasz#include <sys/callout.h>
47255570Strasz#include <sys/sbuf.h>
48263234Srwatson#include <sys/capsicum.h>
49255570Strasz#include <assert.h>
50255570Strasz#include <bsdxml.h>
51255570Strasz#include <ctype.h>
52255570Strasz#include <errno.h>
53255570Strasz#include <fcntl.h>
54255570Strasz#include <stdint.h>
55255570Strasz#include <stdio.h>
56255570Strasz#include <stdlib.h>
57255570Strasz#include <string.h>
58255570Strasz#include <strings.h>
59255570Strasz#include <cam/scsi/scsi_all.h>
60255570Strasz#include <cam/scsi/scsi_message.h>
61255570Strasz#include <cam/ctl/ctl.h>
62255570Strasz#include <cam/ctl/ctl_io.h>
63255570Strasz#include <cam/ctl/ctl_frontend_internal.h>
64255570Strasz#include <cam/ctl/ctl_backend.h>
65255570Strasz#include <cam/ctl/ctl_ioctl.h>
66255570Strasz#include <cam/ctl/ctl_backend_block.h>
67255570Strasz#include <cam/ctl/ctl_util.h>
68255570Strasz#include <cam/ctl/ctl_scsi_all.h>
69255570Strasz
70264524Strasz#include "ctld.h"
71264524Strasz
72255570Strasz#ifdef ICL_KERNEL_PROXY
73255570Strasz#include <netdb.h>
74255570Strasz#endif
75255570Strasz
76264524Straszextern bool proxy_mode;
77255570Strasz
78255570Straszstatic int	ctl_fd = 0;
79255570Strasz
80255570Straszvoid
81255570Straszkernel_init(void)
82255570Strasz{
83255570Strasz	int retval, saved_errno;
84255570Strasz
85255570Strasz	ctl_fd = open(CTL_DEFAULT_DEV, O_RDWR);
86255665Strasz	if (ctl_fd < 0 && errno == ENOENT) {
87255570Strasz		saved_errno = errno;
88255570Strasz		retval = kldload("ctl");
89255570Strasz		if (retval != -1)
90255570Strasz			ctl_fd = open(CTL_DEFAULT_DEV, O_RDWR);
91255570Strasz		else
92255570Strasz			errno = saved_errno;
93255570Strasz	}
94255570Strasz	if (ctl_fd < 0)
95255570Strasz		log_err(1, "failed to open %s", CTL_DEFAULT_DEV);
96255570Strasz}
97255570Strasz
98255570Strasz/*
99255570Strasz * Name/value pair used for per-LUN attributes.
100255570Strasz */
101255570Straszstruct cctl_lun_nv {
102255570Strasz	char *name;
103255570Strasz	char *value;
104255570Strasz	STAILQ_ENTRY(cctl_lun_nv) links;
105255570Strasz};
106255570Strasz
107255570Strasz/*
108273464Strasz * Backend LUN information.
109255570Strasz */
110255570Straszstruct cctl_lun {
111255570Strasz	uint64_t lun_id;
112255570Strasz	char *backend_type;
113255570Strasz	uint64_t size_blocks;
114255570Strasz	uint32_t blocksize;
115255570Strasz	char *serial_number;
116255570Strasz	char *device_id;
117278037Smav	char *ctld_name;
118255570Strasz	STAILQ_HEAD(,cctl_lun_nv) attr_list;
119255570Strasz	STAILQ_ENTRY(cctl_lun) links;
120255570Strasz};
121255570Strasz
122268291Smavstruct cctl_port {
123268291Smav	uint32_t port_id;
124278354Smav	char *port_name;
125278322Smav	int cfiscsi_state;
126268291Smav	char *cfiscsi_target;
127268291Smav	uint16_t cfiscsi_portal_group_tag;
128278322Smav	char *ctld_portal_group_name;
129268291Smav	STAILQ_HEAD(,cctl_lun_nv) attr_list;
130268291Smav	STAILQ_ENTRY(cctl_port) links;
131268291Smav};
132268291Smav
133255570Straszstruct cctl_devlist_data {
134255570Strasz	int num_luns;
135255570Strasz	STAILQ_HEAD(,cctl_lun) lun_list;
136255570Strasz	struct cctl_lun *cur_lun;
137268291Smav	int num_ports;
138268291Smav	STAILQ_HEAD(,cctl_port) port_list;
139268291Smav	struct cctl_port *cur_port;
140255570Strasz	int level;
141255570Strasz	struct sbuf *cur_sb[32];
142255570Strasz};
143255570Strasz
144255570Straszstatic void
145255570Straszcctl_start_element(void *user_data, const char *name, const char **attr)
146255570Strasz{
147255570Strasz	int i;
148255570Strasz	struct cctl_devlist_data *devlist;
149255570Strasz	struct cctl_lun *cur_lun;
150255570Strasz
151255570Strasz	devlist = (struct cctl_devlist_data *)user_data;
152255570Strasz	cur_lun = devlist->cur_lun;
153255570Strasz	devlist->level++;
154256189Strasz	if ((u_int)devlist->level >= (sizeof(devlist->cur_sb) /
155255570Strasz	    sizeof(devlist->cur_sb[0])))
156255570Strasz		log_errx(1, "%s: too many nesting levels, %zd max", __func__,
157255570Strasz		     sizeof(devlist->cur_sb) / sizeof(devlist->cur_sb[0]));
158255570Strasz
159255570Strasz	devlist->cur_sb[devlist->level] = sbuf_new_auto();
160255570Strasz	if (devlist->cur_sb[devlist->level] == NULL)
161255570Strasz		log_err(1, "%s: unable to allocate sbuf", __func__);
162255570Strasz
163255570Strasz	if (strcmp(name, "lun") == 0) {
164255570Strasz		if (cur_lun != NULL)
165255570Strasz			log_errx(1, "%s: improper lun element nesting",
166255570Strasz			    __func__);
167255570Strasz
168255570Strasz		cur_lun = calloc(1, sizeof(*cur_lun));
169255570Strasz		if (cur_lun == NULL)
170255570Strasz			log_err(1, "%s: cannot allocate %zd bytes", __func__,
171255570Strasz			    sizeof(*cur_lun));
172255570Strasz
173255570Strasz		devlist->num_luns++;
174255570Strasz		devlist->cur_lun = cur_lun;
175255570Strasz
176255570Strasz		STAILQ_INIT(&cur_lun->attr_list);
177255570Strasz		STAILQ_INSERT_TAIL(&devlist->lun_list, cur_lun, links);
178255570Strasz
179255570Strasz		for (i = 0; attr[i] != NULL; i += 2) {
180255570Strasz			if (strcmp(attr[i], "id") == 0) {
181255570Strasz				cur_lun->lun_id = strtoull(attr[i+1], NULL, 0);
182255570Strasz			} else {
183255570Strasz				log_errx(1, "%s: invalid LUN attribute %s = %s",
184255570Strasz				     __func__, attr[i], attr[i+1]);
185255570Strasz			}
186255570Strasz		}
187255570Strasz	}
188255570Strasz}
189255570Strasz
190255570Straszstatic void
191255570Straszcctl_end_element(void *user_data, const char *name)
192255570Strasz{
193255570Strasz	struct cctl_devlist_data *devlist;
194255570Strasz	struct cctl_lun *cur_lun;
195255570Strasz	char *str;
196255570Strasz
197255570Strasz	devlist = (struct cctl_devlist_data *)user_data;
198255570Strasz	cur_lun = devlist->cur_lun;
199255570Strasz
200255570Strasz	if ((cur_lun == NULL)
201255570Strasz	 && (strcmp(name, "ctllunlist") != 0))
202255570Strasz		log_errx(1, "%s: cur_lun == NULL! (name = %s)", __func__, name);
203255570Strasz
204255570Strasz	if (devlist->cur_sb[devlist->level] == NULL)
205255570Strasz		log_errx(1, "%s: no valid sbuf at level %d (name %s)", __func__,
206255570Strasz		     devlist->level, name);
207255570Strasz
208255570Strasz	sbuf_finish(devlist->cur_sb[devlist->level]);
209255570Strasz	str = checked_strdup(sbuf_data(devlist->cur_sb[devlist->level]));
210255570Strasz
211255570Strasz	if (strlen(str) == 0) {
212255570Strasz		free(str);
213255570Strasz		str = NULL;
214255570Strasz	}
215255570Strasz
216255570Strasz	sbuf_delete(devlist->cur_sb[devlist->level]);
217255570Strasz	devlist->cur_sb[devlist->level] = NULL;
218255570Strasz	devlist->level--;
219255570Strasz
220255570Strasz	if (strcmp(name, "backend_type") == 0) {
221255570Strasz		cur_lun->backend_type = str;
222255570Strasz		str = NULL;
223255570Strasz	} else if (strcmp(name, "size") == 0) {
224255570Strasz		cur_lun->size_blocks = strtoull(str, NULL, 0);
225255570Strasz	} else if (strcmp(name, "blocksize") == 0) {
226255570Strasz		cur_lun->blocksize = strtoul(str, NULL, 0);
227255570Strasz	} else if (strcmp(name, "serial_number") == 0) {
228255570Strasz		cur_lun->serial_number = str;
229255570Strasz		str = NULL;
230255570Strasz	} else if (strcmp(name, "device_id") == 0) {
231255570Strasz		cur_lun->device_id = str;
232255570Strasz		str = NULL;
233278037Smav	} else if (strcmp(name, "ctld_name") == 0) {
234278037Smav		cur_lun->ctld_name = str;
235255570Strasz		str = NULL;
236255570Strasz	} else if (strcmp(name, "lun") == 0) {
237255570Strasz		devlist->cur_lun = NULL;
238255570Strasz	} else if (strcmp(name, "ctllunlist") == 0) {
239273464Strasz		/* Nothing. */
240255570Strasz	} else {
241255570Strasz		struct cctl_lun_nv *nv;
242255570Strasz
243255570Strasz		nv = calloc(1, sizeof(*nv));
244255570Strasz		if (nv == NULL)
245255570Strasz			log_err(1, "%s: can't allocate %zd bytes for nv pair",
246255570Strasz			    __func__, sizeof(*nv));
247255570Strasz
248255570Strasz		nv->name = checked_strdup(name);
249255570Strasz
250255570Strasz		nv->value = str;
251255570Strasz		str = NULL;
252255570Strasz		STAILQ_INSERT_TAIL(&cur_lun->attr_list, nv, links);
253255570Strasz	}
254255570Strasz
255255570Strasz	free(str);
256255570Strasz}
257255570Strasz
258255570Straszstatic void
259268291Smavcctl_start_pelement(void *user_data, const char *name, const char **attr)
260268291Smav{
261268291Smav	int i;
262268291Smav	struct cctl_devlist_data *devlist;
263268291Smav	struct cctl_port *cur_port;
264268291Smav
265268291Smav	devlist = (struct cctl_devlist_data *)user_data;
266268291Smav	cur_port = devlist->cur_port;
267268291Smav	devlist->level++;
268268291Smav	if ((u_int)devlist->level >= (sizeof(devlist->cur_sb) /
269268291Smav	    sizeof(devlist->cur_sb[0])))
270268291Smav		log_errx(1, "%s: too many nesting levels, %zd max", __func__,
271268291Smav		     sizeof(devlist->cur_sb) / sizeof(devlist->cur_sb[0]));
272268291Smav
273268291Smav	devlist->cur_sb[devlist->level] = sbuf_new_auto();
274268291Smav	if (devlist->cur_sb[devlist->level] == NULL)
275268291Smav		log_err(1, "%s: unable to allocate sbuf", __func__);
276268291Smav
277268291Smav	if (strcmp(name, "targ_port") == 0) {
278268291Smav		if (cur_port != NULL)
279268291Smav			log_errx(1, "%s: improper port element nesting (%s)",
280268291Smav			    __func__, name);
281268291Smav
282268291Smav		cur_port = calloc(1, sizeof(*cur_port));
283268291Smav		if (cur_port == NULL)
284268291Smav			log_err(1, "%s: cannot allocate %zd bytes", __func__,
285268291Smav			    sizeof(*cur_port));
286268291Smav
287268291Smav		devlist->num_ports++;
288268291Smav		devlist->cur_port = cur_port;
289268291Smav
290268291Smav		STAILQ_INIT(&cur_port->attr_list);
291268291Smav		STAILQ_INSERT_TAIL(&devlist->port_list, cur_port, links);
292268291Smav
293268291Smav		for (i = 0; attr[i] != NULL; i += 2) {
294268291Smav			if (strcmp(attr[i], "id") == 0) {
295268291Smav				cur_port->port_id = strtoul(attr[i+1], NULL, 0);
296268291Smav			} else {
297268291Smav				log_errx(1, "%s: invalid LUN attribute %s = %s",
298268291Smav				     __func__, attr[i], attr[i+1]);
299268291Smav			}
300268291Smav		}
301268291Smav	}
302268291Smav}
303268291Smav
304268291Smavstatic void
305268291Smavcctl_end_pelement(void *user_data, const char *name)
306268291Smav{
307268291Smav	struct cctl_devlist_data *devlist;
308268291Smav	struct cctl_port *cur_port;
309268291Smav	char *str;
310268291Smav
311268291Smav	devlist = (struct cctl_devlist_data *)user_data;
312268291Smav	cur_port = devlist->cur_port;
313268291Smav
314268291Smav	if ((cur_port == NULL)
315268291Smav	 && (strcmp(name, "ctlportlist") != 0))
316268291Smav		log_errx(1, "%s: cur_port == NULL! (name = %s)", __func__, name);
317268291Smav
318268291Smav	if (devlist->cur_sb[devlist->level] == NULL)
319268291Smav		log_errx(1, "%s: no valid sbuf at level %d (name %s)", __func__,
320268291Smav		     devlist->level, name);
321268291Smav
322268291Smav	sbuf_finish(devlist->cur_sb[devlist->level]);
323268291Smav	str = checked_strdup(sbuf_data(devlist->cur_sb[devlist->level]));
324268291Smav
325268291Smav	if (strlen(str) == 0) {
326268291Smav		free(str);
327268291Smav		str = NULL;
328268291Smav	}
329268291Smav
330268291Smav	sbuf_delete(devlist->cur_sb[devlist->level]);
331268291Smav	devlist->cur_sb[devlist->level] = NULL;
332268291Smav	devlist->level--;
333268291Smav
334278354Smav	if (strcmp(name, "port_name") == 0) {
335278354Smav		cur_port->port_name = str;
336278354Smav		str = NULL;
337278354Smav	} else if (strcmp(name, "cfiscsi_target") == 0) {
338268291Smav		cur_port->cfiscsi_target = str;
339268291Smav		str = NULL;
340278322Smav	} else if (strcmp(name, "cfiscsi_state") == 0) {
341278322Smav		cur_port->cfiscsi_state = strtoul(str, NULL, 0);
342268291Smav	} else if (strcmp(name, "cfiscsi_portal_group_tag") == 0) {
343268291Smav		cur_port->cfiscsi_portal_group_tag = strtoul(str, NULL, 0);
344278322Smav	} else if (strcmp(name, "ctld_portal_group_name") == 0) {
345278322Smav		cur_port->ctld_portal_group_name = str;
346278322Smav		str = NULL;
347268291Smav	} else if (strcmp(name, "targ_port") == 0) {
348268291Smav		devlist->cur_port = NULL;
349268291Smav	} else if (strcmp(name, "ctlportlist") == 0) {
350273464Strasz		/* Nothing. */
351268291Smav	} else {
352268291Smav		struct cctl_lun_nv *nv;
353268291Smav
354268291Smav		nv = calloc(1, sizeof(*nv));
355268291Smav		if (nv == NULL)
356268291Smav			log_err(1, "%s: can't allocate %zd bytes for nv pair",
357268291Smav			    __func__, sizeof(*nv));
358268291Smav
359268291Smav		nv->name = checked_strdup(name);
360268291Smav
361268291Smav		nv->value = str;
362268291Smav		str = NULL;
363268291Smav		STAILQ_INSERT_TAIL(&cur_port->attr_list, nv, links);
364268291Smav	}
365268291Smav
366268291Smav	free(str);
367268291Smav}
368268291Smav
369268291Smavstatic void
370255570Straszcctl_char_handler(void *user_data, const XML_Char *str, int len)
371255570Strasz{
372255570Strasz	struct cctl_devlist_data *devlist;
373255570Strasz
374255570Strasz	devlist = (struct cctl_devlist_data *)user_data;
375255570Strasz
376255570Strasz	sbuf_bcat(devlist->cur_sb[devlist->level], str, len);
377255570Strasz}
378255570Strasz
379255570Straszstruct conf *
380255570Straszconf_new_from_kernel(void)
381255570Strasz{
382255570Strasz	struct conf *conf = NULL;
383255570Strasz	struct target *targ;
384278322Smav	struct portal_group *pg;
385278354Smav	struct pport *pp;
386278322Smav	struct port *cp;
387255570Strasz	struct lun *cl;
388255570Strasz	struct lun_option *lo;
389255570Strasz	struct ctl_lun_list list;
390255570Strasz	struct cctl_devlist_data devlist;
391255570Strasz	struct cctl_lun *lun;
392268291Smav	struct cctl_port *port;
393255570Strasz	XML_Parser parser;
394268291Smav	char *str;
395268291Smav	int len, retval;
396255570Strasz
397255570Strasz	bzero(&devlist, sizeof(devlist));
398255570Strasz	STAILQ_INIT(&devlist.lun_list);
399268291Smav	STAILQ_INIT(&devlist.port_list);
400255570Strasz
401255570Strasz	log_debugx("obtaining previously configured CTL luns from the kernel");
402255570Strasz
403268291Smav	str = NULL;
404268291Smav	len = 4096;
405255570Straszretry:
406268291Smav	str = realloc(str, len);
407268291Smav	if (str == NULL)
408255570Strasz		log_err(1, "realloc");
409255570Strasz
410255570Strasz	bzero(&list, sizeof(list));
411268291Smav	list.alloc_len = len;
412255570Strasz	list.status = CTL_LUN_LIST_NONE;
413268291Smav	list.lun_xml = str;
414255570Strasz
415255570Strasz	if (ioctl(ctl_fd, CTL_LUN_LIST, &list) == -1) {
416255570Strasz		log_warn("error issuing CTL_LUN_LIST ioctl");
417268291Smav		free(str);
418255570Strasz		return (NULL);
419255570Strasz	}
420255570Strasz
421255570Strasz	if (list.status == CTL_LUN_LIST_ERROR) {
422255570Strasz		log_warnx("error returned from CTL_LUN_LIST ioctl: %s",
423255570Strasz		    list.error_str);
424268291Smav		free(str);
425255570Strasz		return (NULL);
426255570Strasz	}
427255570Strasz
428255570Strasz	if (list.status == CTL_LUN_LIST_NEED_MORE_SPACE) {
429268291Smav		len = len << 1;
430255570Strasz		goto retry;
431255570Strasz	}
432255570Strasz
433255570Strasz	parser = XML_ParserCreate(NULL);
434255570Strasz	if (parser == NULL) {
435255570Strasz		log_warnx("unable to create XML parser");
436268291Smav		free(str);
437255570Strasz		return (NULL);
438255570Strasz	}
439255570Strasz
440255570Strasz	XML_SetUserData(parser, &devlist);
441255570Strasz	XML_SetElementHandler(parser, cctl_start_element, cctl_end_element);
442255570Strasz	XML_SetCharacterDataHandler(parser, cctl_char_handler);
443255570Strasz
444268291Smav	retval = XML_Parse(parser, str, strlen(str), 1);
445255570Strasz	XML_ParserFree(parser);
446268291Smav	free(str);
447255570Strasz	if (retval != 1) {
448255570Strasz		log_warnx("XML_Parse failed");
449255570Strasz		return (NULL);
450255570Strasz	}
451255570Strasz
452268291Smav	str = NULL;
453268291Smav	len = 4096;
454268291Smavretry_port:
455268291Smav	str = realloc(str, len);
456268291Smav	if (str == NULL)
457268291Smav		log_err(1, "realloc");
458268291Smav
459268291Smav	bzero(&list, sizeof(list));
460268291Smav	list.alloc_len = len;
461268291Smav	list.status = CTL_LUN_LIST_NONE;
462268291Smav	list.lun_xml = str;
463268291Smav
464268291Smav	if (ioctl(ctl_fd, CTL_PORT_LIST, &list) == -1) {
465268291Smav		log_warn("error issuing CTL_PORT_LIST ioctl");
466268291Smav		free(str);
467268291Smav		return (NULL);
468268291Smav	}
469268291Smav
470268291Smav	if (list.status == CTL_PORT_LIST_ERROR) {
471268291Smav		log_warnx("error returned from CTL_PORT_LIST ioctl: %s",
472268291Smav		    list.error_str);
473268291Smav		free(str);
474268291Smav		return (NULL);
475268291Smav	}
476268291Smav
477268291Smav	if (list.status == CTL_LUN_LIST_NEED_MORE_SPACE) {
478268291Smav		len = len << 1;
479268291Smav		goto retry_port;
480268291Smav	}
481268291Smav
482268291Smav	parser = XML_ParserCreate(NULL);
483268291Smav	if (parser == NULL) {
484268291Smav		log_warnx("unable to create XML parser");
485268291Smav		free(str);
486268291Smav		return (NULL);
487268291Smav	}
488268291Smav
489268291Smav	XML_SetUserData(parser, &devlist);
490268291Smav	XML_SetElementHandler(parser, cctl_start_pelement, cctl_end_pelement);
491268291Smav	XML_SetCharacterDataHandler(parser, cctl_char_handler);
492268291Smav
493268291Smav	retval = XML_Parse(parser, str, strlen(str), 1);
494268291Smav	XML_ParserFree(parser);
495268291Smav	free(str);
496268291Smav	if (retval != 1) {
497268291Smav		log_warnx("XML_Parse failed");
498268291Smav		return (NULL);
499268291Smav	}
500268291Smav
501255570Strasz	conf = conf_new();
502255570Strasz
503268291Smav	STAILQ_FOREACH(port, &devlist.port_list, links) {
504268291Smav
505268291Smav		if (port->cfiscsi_target == NULL) {
506278354Smav			log_debugx("CTL port %u \"%s\" wasn't managed by ctld; ",
507278354Smav			    port->port_id, port->port_name);
508278354Smav			pp = pport_find(conf, port->port_name);
509278354Smav			if (pp == NULL) {
510278354Smav#if 0
511278354Smav				log_debugx("found new kernel port %u \"%s\"",
512278354Smav				    port->port_id, port->port_name);
513278354Smav#endif
514278354Smav				pp = pport_new(conf, port->port_name, port->port_id);
515278354Smav				if (pp == NULL) {
516278354Smav					log_warnx("pport_new failed");
517278354Smav					continue;
518278354Smav				}
519278354Smav			}
520268291Smav			continue;
521268291Smav		}
522278322Smav		if (port->cfiscsi_state != 1) {
523268328Smav			log_debugx("CTL port %ju is not active (%d); ignoring",
524278322Smav			    (uintmax_t)port->port_id, port->cfiscsi_state);
525268328Smav			continue;
526268328Smav		}
527268291Smav
528268291Smav		targ = target_find(conf, port->cfiscsi_target);
529268291Smav		if (targ == NULL) {
530268291Smav#if 0
531268291Smav			log_debugx("found new kernel target %s for CTL port %ld",
532268291Smav			    port->cfiscsi_target, port->port_id);
533268291Smav#endif
534268291Smav			targ = target_new(conf, port->cfiscsi_target);
535268291Smav			if (targ == NULL) {
536268291Smav				log_warnx("target_new failed");
537268291Smav				continue;
538268291Smav			}
539268291Smav		}
540278322Smav
541278322Smav		if (port->ctld_portal_group_name == NULL)
542278322Smav			continue;
543278322Smav		pg = portal_group_find(conf, port->ctld_portal_group_name);
544278322Smav		if (pg == NULL) {
545278322Smav#if 0
546278322Smav			log_debugx("found new kernel portal group %s for CTL port %ld",
547278322Smav			    port->ctld_portal_group_name, port->port_id);
548278322Smav#endif
549278322Smav			pg = portal_group_new(conf, port->ctld_portal_group_name);
550278322Smav			if (pg == NULL) {
551278322Smav				log_warnx("portal_group_new failed");
552278322Smav				continue;
553278322Smav			}
554278322Smav		}
555278322Smav		pg->pg_tag = port->cfiscsi_portal_group_tag;
556278322Smav		cp = port_new(conf, targ, pg);
557278322Smav		if (cp == NULL) {
558278322Smav			log_warnx("port_new failed");
559278322Smav			continue;
560278322Smav		}
561278322Smav		cp->p_ctl_port = port->port_id;
562268291Smav	}
563268291Smav
564255570Strasz	STAILQ_FOREACH(lun, &devlist.lun_list, links) {
565255570Strasz		struct cctl_lun_nv *nv;
566255570Strasz
567278037Smav		if (lun->ctld_name == NULL) {
568255570Strasz			log_debugx("CTL lun %ju wasn't managed by ctld; "
569255570Strasz			    "ignoring", (uintmax_t)lun->lun_id);
570255570Strasz			continue;
571255570Strasz		}
572255570Strasz
573278037Smav		cl = lun_find(conf, lun->ctld_name);
574255570Strasz		if (cl != NULL) {
575278037Smav			log_warnx("found CTL lun %ju \"%s\", "
576278037Smav			    "also backed by CTL lun %d; ignoring",
577278037Smav			    (uintmax_t)lun->lun_id, lun->ctld_name,
578278037Smav			    cl->l_ctl_lun);
579255570Strasz			continue;
580255570Strasz		}
581255570Strasz
582278037Smav		log_debugx("found CTL lun %ju \"%s\"",
583278037Smav		    (uintmax_t)lun->lun_id, lun->ctld_name);
584255570Strasz
585278037Smav		cl = lun_new(conf, lun->ctld_name);
586255570Strasz		if (cl == NULL) {
587255570Strasz			log_warnx("lun_new failed");
588255570Strasz			continue;
589255570Strasz		}
590255570Strasz		lun_set_backend(cl, lun->backend_type);
591255570Strasz		lun_set_blocksize(cl, lun->blocksize);
592255570Strasz		lun_set_device_id(cl, lun->device_id);
593255570Strasz		lun_set_serial(cl, lun->serial_number);
594255570Strasz		lun_set_size(cl, lun->size_blocks * cl->l_blocksize);
595255570Strasz		lun_set_ctl_lun(cl, lun->lun_id);
596255570Strasz
597255570Strasz		STAILQ_FOREACH(nv, &lun->attr_list, links) {
598255570Strasz			if (strcmp(nv->name, "file") == 0 ||
599255570Strasz			    strcmp(nv->name, "dev") == 0) {
600255570Strasz				lun_set_path(cl, nv->value);
601255570Strasz				continue;
602255570Strasz			}
603255570Strasz			lo = lun_option_new(cl, nv->name, nv->value);
604255570Strasz			if (lo == NULL)
605255570Strasz				log_warnx("unable to add CTL lun option %s "
606278037Smav				    "for CTL lun %ju \"%s\"",
607255570Strasz				    nv->name, (uintmax_t) lun->lun_id,
608278037Smav				    cl->l_name);
609255570Strasz		}
610255570Strasz	}
611255570Strasz
612255570Strasz	return (conf);
613255570Strasz}
614255570Strasz
615268291Smavstatic void
616268291Smavstr_arg(struct ctl_be_arg *arg, const char *name, const char *value)
617268291Smav{
618268291Smav
619268291Smav	arg->namelen = strlen(name) + 1;
620268291Smav	arg->name = __DECONST(char *, name);
621268291Smav	arg->vallen = strlen(value) + 1;
622268291Smav	arg->value = __DECONST(char *, value);
623268291Smav	arg->flags = CTL_BEARG_ASCII | CTL_BEARG_RD;
624268291Smav}
625268291Smav
626255570Straszint
627255570Straszkernel_lun_add(struct lun *lun)
628255570Strasz{
629255570Strasz	struct lun_option *lo;
630255570Strasz	struct ctl_lun_req req;
631255570Strasz	int error, i, num_options;
632255570Strasz
633255570Strasz	bzero(&req, sizeof(req));
634255570Strasz
635255570Strasz	strlcpy(req.backend, lun->l_backend, sizeof(req.backend));
636255570Strasz	req.reqtype = CTL_LUNREQ_CREATE;
637255570Strasz
638255570Strasz	req.reqdata.create.blocksize_bytes = lun->l_blocksize;
639255570Strasz
640255570Strasz	if (lun->l_size != 0)
641255570Strasz		req.reqdata.create.lun_size_bytes = lun->l_size;
642255570Strasz
643255570Strasz	req.reqdata.create.flags |= CTL_LUN_FLAG_DEV_TYPE;
644255570Strasz	req.reqdata.create.device_type = T_DIRECT;
645255570Strasz
646255570Strasz	if (lun->l_serial != NULL) {
647267648Smav		strncpy(req.reqdata.create.serial_num, lun->l_serial,
648255570Strasz			sizeof(req.reqdata.create.serial_num));
649255570Strasz		req.reqdata.create.flags |= CTL_LUN_FLAG_SERIAL_NUM;
650255570Strasz	}
651255570Strasz
652255570Strasz	if (lun->l_device_id != NULL) {
653267648Smav		strncpy(req.reqdata.create.device_id, lun->l_device_id,
654255570Strasz			sizeof(req.reqdata.create.device_id));
655255570Strasz		req.reqdata.create.flags |= CTL_LUN_FLAG_DEVID;
656255570Strasz	}
657255570Strasz
658255570Strasz	if (lun->l_path != NULL) {
659255570Strasz		lo = lun_option_find(lun, "file");
660255570Strasz		if (lo != NULL) {
661255570Strasz			lun_option_set(lo, lun->l_path);
662255570Strasz		} else {
663255570Strasz			lo = lun_option_new(lun, "file", lun->l_path);
664255570Strasz			assert(lo != NULL);
665255570Strasz		}
666255570Strasz	}
667255570Strasz
668278037Smav	lo = lun_option_find(lun, "ctld_name");
669255570Strasz	if (lo != NULL) {
670278037Smav		lun_option_set(lo, lun->l_name);
671255570Strasz	} else {
672278037Smav		lo = lun_option_new(lun, "ctld_name", lun->l_name);
673255570Strasz		assert(lo != NULL);
674255570Strasz	}
675255570Strasz
676268293Smav	lo = lun_option_find(lun, "scsiname");
677278037Smav	if (lo == NULL && lun->l_scsiname != NULL) {
678278037Smav		lo = lun_option_new(lun, "scsiname", lun->l_scsiname);
679268293Smav		assert(lo != NULL);
680268293Smav	}
681268293Smav
682255570Strasz	num_options = 0;
683255570Strasz	TAILQ_FOREACH(lo, &lun->l_options, lo_next)
684255570Strasz		num_options++;
685255570Strasz
686255570Strasz	req.num_be_args = num_options;
687255570Strasz	if (num_options > 0) {
688255570Strasz		req.be_args = malloc(num_options * sizeof(*req.be_args));
689255570Strasz		if (req.be_args == NULL) {
690255570Strasz			log_warn("error allocating %zd bytes",
691255570Strasz			    num_options * sizeof(*req.be_args));
692255570Strasz			return (1);
693255570Strasz		}
694255570Strasz
695255570Strasz		i = 0;
696255570Strasz		TAILQ_FOREACH(lo, &lun->l_options, lo_next) {
697268291Smav			str_arg(&req.be_args[i], lo->lo_name, lo->lo_value);
698255570Strasz			i++;
699255570Strasz		}
700255570Strasz		assert(i == num_options);
701255570Strasz	}
702255570Strasz
703255570Strasz	error = ioctl(ctl_fd, CTL_LUN_REQ, &req);
704255570Strasz	free(req.be_args);
705255570Strasz	if (error != 0) {
706255570Strasz		log_warn("error issuing CTL_LUN_REQ ioctl");
707255570Strasz		return (1);
708255570Strasz	}
709255570Strasz
710272911Smav	switch (req.status) {
711272911Smav	case CTL_LUN_ERROR:
712272911Smav		log_warnx("LUN creation error: %s", req.error_str);
713255570Strasz		return (1);
714272911Smav	case CTL_LUN_WARNING:
715272911Smav		log_warnx("LUN creation warning: %s", req.error_str);
716272911Smav		break;
717272911Smav	case CTL_LUN_OK:
718272911Smav		break;
719272911Smav	default:
720272911Smav		log_warnx("unknown LUN creation status: %d",
721255570Strasz		    req.status);
722255570Strasz		return (1);
723255570Strasz	}
724255570Strasz
725255570Strasz	lun_set_ctl_lun(lun, req.reqdata.create.req_lun_id);
726255570Strasz	return (0);
727255570Strasz}
728255570Strasz
729255570Straszint
730255570Straszkernel_lun_resize(struct lun *lun)
731255570Strasz{
732255570Strasz	struct ctl_lun_req req;
733255570Strasz
734255570Strasz	bzero(&req, sizeof(req));
735255570Strasz
736255570Strasz	strlcpy(req.backend, lun->l_backend, sizeof(req.backend));
737255570Strasz	req.reqtype = CTL_LUNREQ_MODIFY;
738255570Strasz
739255570Strasz	req.reqdata.modify.lun_id = lun->l_ctl_lun;
740255570Strasz	req.reqdata.modify.lun_size_bytes = lun->l_size;
741255570Strasz
742255570Strasz	if (ioctl(ctl_fd, CTL_LUN_REQ, &req) == -1) {
743255570Strasz		log_warn("error issuing CTL_LUN_REQ ioctl");
744255570Strasz		return (1);
745255570Strasz	}
746255570Strasz
747272911Smav	switch (req.status) {
748272911Smav	case CTL_LUN_ERROR:
749272911Smav		log_warnx("LUN modification error: %s", req.error_str);
750255570Strasz		return (1);
751272911Smav	case CTL_LUN_WARNING:
752272911Smav		log_warnx("LUN modification warning: %s", req.error_str);
753272911Smav		break;
754272911Smav	case CTL_LUN_OK:
755272911Smav		break;
756272911Smav	default:
757272911Smav		log_warnx("unknown LUN modification status: %d",
758255570Strasz		    req.status);
759255570Strasz		return (1);
760255570Strasz	}
761255570Strasz
762255570Strasz	return (0);
763255570Strasz}
764255570Strasz
765255570Straszint
766255570Straszkernel_lun_remove(struct lun *lun)
767255570Strasz{
768255570Strasz	struct ctl_lun_req req;
769255570Strasz
770255570Strasz	bzero(&req, sizeof(req));
771255570Strasz
772255570Strasz	strlcpy(req.backend, lun->l_backend, sizeof(req.backend));
773255570Strasz	req.reqtype = CTL_LUNREQ_RM;
774255570Strasz
775255570Strasz	req.reqdata.rm.lun_id = lun->l_ctl_lun;
776255570Strasz
777255570Strasz	if (ioctl(ctl_fd, CTL_LUN_REQ, &req) == -1) {
778255570Strasz		log_warn("error issuing CTL_LUN_REQ ioctl");
779255570Strasz		return (1);
780255570Strasz	}
781255570Strasz
782272911Smav	switch (req.status) {
783272911Smav	case CTL_LUN_ERROR:
784272911Smav		log_warnx("LUN removal error: %s", req.error_str);
785255570Strasz		return (1);
786272911Smav	case CTL_LUN_WARNING:
787272911Smav		log_warnx("LUN removal warning: %s", req.error_str);
788272911Smav		break;
789272911Smav	case CTL_LUN_OK:
790272911Smav		break;
791272911Smav	default:
792272911Smav		log_warnx("unknown LUN removal status: %d", req.status);
793255570Strasz		return (1);
794255570Strasz	}
795255570Strasz
796255570Strasz	return (0);
797255570Strasz}
798255570Strasz
799255570Straszvoid
800255570Straszkernel_handoff(struct connection *conn)
801255570Strasz{
802255570Strasz	struct ctl_iscsi req;
803255570Strasz
804255570Strasz	bzero(&req, sizeof(req));
805255570Strasz
806255570Strasz	req.type = CTL_ISCSI_HANDOFF;
807255570Strasz	strlcpy(req.data.handoff.initiator_name,
808255570Strasz	    conn->conn_initiator_name, sizeof(req.data.handoff.initiator_name));
809255570Strasz	strlcpy(req.data.handoff.initiator_addr,
810255570Strasz	    conn->conn_initiator_addr, sizeof(req.data.handoff.initiator_addr));
811255570Strasz	if (conn->conn_initiator_alias != NULL) {
812255570Strasz		strlcpy(req.data.handoff.initiator_alias,
813255570Strasz		    conn->conn_initiator_alias, sizeof(req.data.handoff.initiator_alias));
814255570Strasz	}
815268302Smav	memcpy(req.data.handoff.initiator_isid, conn->conn_initiator_isid,
816268302Smav	    sizeof(req.data.handoff.initiator_isid));
817255570Strasz	strlcpy(req.data.handoff.target_name,
818261757Strasz	    conn->conn_target->t_name, sizeof(req.data.handoff.target_name));
819279392Strasz	if (conn->conn_portal->p_portal_group->pg_offload != NULL) {
820278331Strasz		strlcpy(req.data.handoff.offload,
821279392Strasz		    conn->conn_portal->p_portal_group->pg_offload,
822279392Strasz		    sizeof(req.data.handoff.offload));
823278331Strasz	}
824264524Strasz#ifdef ICL_KERNEL_PROXY
825264524Strasz	if (proxy_mode)
826264524Strasz		req.data.handoff.connection_id = conn->conn_socket;
827264524Strasz	else
828264524Strasz		req.data.handoff.socket = conn->conn_socket;
829264524Strasz#else
830255570Strasz	req.data.handoff.socket = conn->conn_socket;
831264524Strasz#endif
832255570Strasz	req.data.handoff.portal_group_tag =
833255570Strasz	    conn->conn_portal->p_portal_group->pg_tag;
834255570Strasz	if (conn->conn_header_digest == CONN_DIGEST_CRC32C)
835255570Strasz		req.data.handoff.header_digest = CTL_ISCSI_DIGEST_CRC32C;
836255570Strasz	if (conn->conn_data_digest == CONN_DIGEST_CRC32C)
837255570Strasz		req.data.handoff.data_digest = CTL_ISCSI_DIGEST_CRC32C;
838255570Strasz	req.data.handoff.cmdsn = conn->conn_cmdsn;
839255570Strasz	req.data.handoff.statsn = conn->conn_statsn;
840255570Strasz	req.data.handoff.max_recv_data_segment_length =
841255570Strasz	    conn->conn_max_data_segment_length;
842255570Strasz	req.data.handoff.max_burst_length = conn->conn_max_burst_length;
843255570Strasz	req.data.handoff.immediate_data = conn->conn_immediate_data;
844255570Strasz
845264526Strasz	if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) {
846255570Strasz		log_err(1, "error issuing CTL_ISCSI ioctl; "
847255570Strasz		    "dropping connection");
848264526Strasz	}
849255570Strasz
850264526Strasz	if (req.status != CTL_ISCSI_OK) {
851255570Strasz		log_errx(1, "error returned from CTL iSCSI handoff request: "
852255570Strasz		    "%s; dropping connection", req.error_str);
853264526Strasz	}
854255570Strasz}
855255570Strasz
856278331Straszvoid
857278331Straszkernel_limits(const char *offload, size_t *max_data_segment_length)
858278331Strasz{
859278331Strasz	struct ctl_iscsi req;
860278331Strasz
861278331Strasz	bzero(&req, sizeof(req));
862278331Strasz
863278331Strasz	req.type = CTL_ISCSI_LIMITS;
864278331Strasz	if (offload != NULL) {
865278331Strasz		strlcpy(req.data.limits.offload, offload,
866278331Strasz		    sizeof(req.data.limits.offload));
867278331Strasz	}
868278331Strasz
869278331Strasz	if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) {
870278331Strasz		log_err(1, "error issuing CTL_ISCSI ioctl; "
871278331Strasz		    "dropping connection");
872278331Strasz	}
873278331Strasz
874278331Strasz	if (req.status != CTL_ISCSI_OK) {
875278331Strasz		log_errx(1, "error returned from CTL iSCSI limits request: "
876278331Strasz		    "%s; dropping connection", req.error_str);
877278331Strasz	}
878278331Strasz
879278331Strasz	*max_data_segment_length = req.data.limits.data_segment_limit;
880278331Strasz	if (offload != NULL) {
881278331Strasz		log_debugx("MaxRecvDataSegment kernel limit for offload "
882278331Strasz		    "\"%s\" is %zd", offload, *max_data_segment_length);
883278331Strasz	} else {
884278331Strasz		log_debugx("MaxRecvDataSegment kernel limit is %zd",
885278331Strasz		    *max_data_segment_length);
886278331Strasz	}
887278331Strasz}
888278331Strasz
889255570Straszint
890278322Smavkernel_port_add(struct port *port)
891255570Strasz{
892255570Strasz	struct ctl_port_entry entry;
893268291Smav	struct ctl_req req;
894278037Smav	struct ctl_lun_map lm;
895278322Smav	struct target *targ = port->p_target;
896278322Smav	struct portal_group *pg = port->p_portal_group;
897268291Smav	char tagstr[16];
898278322Smav	int error, i, n;
899255570Strasz
900278037Smav	/* Create iSCSI port. */
901278354Smav	if (port->p_portal_group) {
902278354Smav		bzero(&req, sizeof(req));
903278354Smav		strlcpy(req.driver, "iscsi", sizeof(req.driver));
904278354Smav		req.reqtype = CTL_REQ_CREATE;
905279276Smav		req.num_args = 5;
906278354Smav		req.args = malloc(req.num_args * sizeof(*req.args));
907279276Smav		if (req.args == NULL)
908279276Smav			log_err(1, "malloc");
909278354Smav		n = 0;
910278354Smav		req.args[n].namelen = sizeof("port_id");
911278354Smav		req.args[n].name = __DECONST(char *, "port_id");
912278354Smav		req.args[n].vallen = sizeof(port->p_ctl_port);
913278354Smav		req.args[n].value = &port->p_ctl_port;
914278354Smav		req.args[n++].flags = CTL_BEARG_WR;
915278354Smav		str_arg(&req.args[n++], "cfiscsi_target", targ->t_name);
916278354Smav		snprintf(tagstr, sizeof(tagstr), "%d", pg->pg_tag);
917278354Smav		str_arg(&req.args[n++], "cfiscsi_portal_group_tag", tagstr);
918278354Smav		if (targ->t_alias)
919278354Smav			str_arg(&req.args[n++], "cfiscsi_target_alias", targ->t_alias);
920278354Smav		str_arg(&req.args[n++], "ctld_portal_group_name", pg->pg_name);
921278354Smav		req.num_args = n;
922278354Smav		error = ioctl(ctl_fd, CTL_PORT_REQ, &req);
923278354Smav		free(req.args);
924278354Smav		if (error != 0) {
925278354Smav			log_warn("error issuing CTL_PORT_REQ ioctl");
926278354Smav			return (1);
927278354Smav		}
928278354Smav		if (req.status == CTL_LUN_ERROR) {
929278354Smav			log_warnx("error returned from port creation request: %s",
930278354Smav			    req.error_str);
931278354Smav			return (1);
932278354Smav		}
933278354Smav		if (req.status != CTL_LUN_OK) {
934278354Smav			log_warnx("unknown port creation request status %d",
935278354Smav			    req.status);
936278354Smav			return (1);
937278354Smav		}
938279590Smav	} else if (port->p_pport) {
939278354Smav		port->p_ctl_port = port->p_pport->pp_ctl_port;
940268291Smav
941279590Smav		if (strncmp(targ->t_name, "naa.", 4) == 0 &&
942279590Smav		    strlen(targ->t_name) == 20) {
943279590Smav			bzero(&entry, sizeof(entry));
944279590Smav			entry.port_type = CTL_PORT_NONE;
945279590Smav			entry.targ_port = port->p_ctl_port;
946279590Smav			entry.flags |= CTL_PORT_WWNN_VALID;
947279590Smav			entry.wwnn = strtoull(targ->t_name + 4, NULL, 16);
948279590Smav			if (ioctl(ctl_fd, CTL_SET_PORT_WWNS, &entry) == -1)
949279590Smav				log_warn("CTL_SET_PORT_WWNS ioctl failed");
950279590Smav		}
951279590Smav	}
952279590Smav
953278037Smav	/* Explicitly enable mapping to block any access except allowed. */
954278322Smav	lm.port = port->p_ctl_port;
955278037Smav	lm.plun = UINT32_MAX;
956278037Smav	lm.lun = 0;
957278037Smav	error = ioctl(ctl_fd, CTL_LUN_MAP, &lm);
958278037Smav	if (error != 0)
959278037Smav		log_warn("CTL_LUN_MAP ioctl failed");
960278037Smav
961278037Smav	/* Map configured LUNs */
962278037Smav	for (i = 0; i < MAX_LUNS; i++) {
963278037Smav		if (targ->t_luns[i] == NULL)
964278037Smav			continue;
965278322Smav		lm.port = port->p_ctl_port;
966278037Smav		lm.plun = i;
967278037Smav		lm.lun = targ->t_luns[i]->l_ctl_lun;
968278037Smav		error = ioctl(ctl_fd, CTL_LUN_MAP, &lm);
969278037Smav		if (error != 0)
970278037Smav			log_warn("CTL_LUN_MAP ioctl failed");
971278037Smav	}
972278037Smav
973278037Smav	/* Enable port */
974255678Strasz	bzero(&entry, sizeof(entry));
975278322Smav	entry.targ_port = port->p_ctl_port;
976255570Strasz	error = ioctl(ctl_fd, CTL_ENABLE_PORT, &entry);
977255570Strasz	if (error != 0) {
978255570Strasz		log_warn("CTL_ENABLE_PORT ioctl failed");
979255570Strasz		return (-1);
980255570Strasz	}
981255570Strasz
982255570Strasz	return (0);
983255570Strasz}
984255570Strasz
985255570Straszint
986278322Smavkernel_port_update(struct port *port)
987278037Smav{
988278037Smav	struct ctl_lun_map lm;
989278322Smav	struct target *targ = port->p_target;
990278037Smav	int error, i;
991278037Smav
992278037Smav	/* Map configured LUNs and unmap others */
993278037Smav	for (i = 0; i < MAX_LUNS; i++) {
994278322Smav		lm.port = port->p_ctl_port;
995278037Smav		lm.plun = i;
996278037Smav		if (targ->t_luns[i] == NULL)
997278037Smav			lm.lun = UINT32_MAX;
998278037Smav		else
999278037Smav			lm.lun = targ->t_luns[i]->l_ctl_lun;
1000278037Smav		error = ioctl(ctl_fd, CTL_LUN_MAP, &lm);
1001278037Smav		if (error != 0)
1002278037Smav			log_warn("CTL_LUN_MAP ioctl failed");
1003278037Smav	}
1004278037Smav	return (0);
1005278037Smav}
1006278037Smav
1007278037Smavint
1008278322Smavkernel_port_remove(struct port *port)
1009255570Strasz{
1010278354Smav	struct ctl_port_entry entry;
1011278354Smav	struct ctl_lun_map lm;
1012268291Smav	struct ctl_req req;
1013268291Smav	char tagstr[16];
1014278322Smav	struct target *targ = port->p_target;
1015278322Smav	struct portal_group *pg = port->p_portal_group;
1016255570Strasz	int error;
1017255570Strasz
1018278354Smav	/* Disable port */
1019278354Smav	bzero(&entry, sizeof(entry));
1020278354Smav	entry.targ_port = port->p_ctl_port;
1021278354Smav	error = ioctl(ctl_fd, CTL_DISABLE_PORT, &entry);
1022255570Strasz	if (error != 0) {
1023278354Smav		log_warn("CTL_DISABLE_PORT ioctl failed");
1024278354Smav		return (-1);
1025255570Strasz	}
1026255570Strasz
1027278354Smav	/* Remove iSCSI port. */
1028278354Smav	if (port->p_portal_group) {
1029278354Smav		bzero(&req, sizeof(req));
1030278354Smav		strlcpy(req.driver, "iscsi", sizeof(req.driver));
1031278354Smav		req.reqtype = CTL_REQ_REMOVE;
1032278354Smav		req.num_args = 2;
1033278354Smav		req.args = malloc(req.num_args * sizeof(*req.args));
1034279276Smav		if (req.args == NULL)
1035279276Smav			log_err(1, "malloc");
1036278354Smav		str_arg(&req.args[0], "cfiscsi_target", targ->t_name);
1037278354Smav		snprintf(tagstr, sizeof(tagstr), "%d", pg->pg_tag);
1038278354Smav		str_arg(&req.args[1], "cfiscsi_portal_group_tag", tagstr);
1039278354Smav		error = ioctl(ctl_fd, CTL_PORT_REQ, &req);
1040278354Smav		free(req.args);
1041278354Smav		if (error != 0) {
1042278354Smav			log_warn("error issuing CTL_PORT_REQ ioctl");
1043278354Smav			return (1);
1044278354Smav		}
1045278354Smav		if (req.status == CTL_LUN_ERROR) {
1046278354Smav			log_warnx("error returned from port removal request: %s",
1047278354Smav			    req.error_str);
1048278354Smav			return (1);
1049278354Smav		}
1050278354Smav		if (req.status != CTL_LUN_OK) {
1051278354Smav			log_warnx("unknown port removal request status %d",
1052278354Smav			    req.status);
1053278354Smav			return (1);
1054278354Smav		}
1055278354Smav	} else {
1056278354Smav		/* Disable LUN mapping. */
1057278354Smav		lm.port = port->p_ctl_port;
1058278354Smav		lm.plun = UINT32_MAX;
1059278354Smav		lm.lun = UINT32_MAX;
1060278354Smav		error = ioctl(ctl_fd, CTL_LUN_MAP, &lm);
1061278354Smav		if (error != 0)
1062278354Smav			log_warn("CTL_LUN_MAP ioctl failed");
1063268291Smav	}
1064255570Strasz	return (0);
1065255570Strasz}
1066255570Strasz
1067255570Strasz#ifdef ICL_KERNEL_PROXY
1068255570Straszvoid
1069264526Straszkernel_listen(struct addrinfo *ai, bool iser, int portal_id)
1070255570Strasz{
1071255570Strasz	struct ctl_iscsi req;
1072255570Strasz
1073255570Strasz	bzero(&req, sizeof(req));
1074255570Strasz
1075255570Strasz	req.type = CTL_ISCSI_LISTEN;
1076255570Strasz	req.data.listen.iser = iser;
1077255570Strasz	req.data.listen.domain = ai->ai_family;
1078255570Strasz	req.data.listen.socktype = ai->ai_socktype;
1079255570Strasz	req.data.listen.protocol = ai->ai_protocol;
1080255570Strasz	req.data.listen.addr = ai->ai_addr;
1081255570Strasz	req.data.listen.addrlen = ai->ai_addrlen;
1082264526Strasz	req.data.listen.portal_id = portal_id;
1083255570Strasz
1084264526Strasz	if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1)
1085261765Strasz		log_err(1, "error issuing CTL_ISCSI ioctl");
1086261765Strasz
1087261765Strasz	if (req.status != CTL_ISCSI_OK) {
1088261765Strasz		log_errx(1, "error returned from CTL iSCSI listen: %s",
1089261765Strasz		    req.error_str);
1090261765Strasz	}
1091255570Strasz}
1092255570Strasz
1093264526Straszvoid
1094264530Straszkernel_accept(int *connection_id, int *portal_id,
1095264530Strasz    struct sockaddr *client_sa, socklen_t *client_salen)
1096255570Strasz{
1097255570Strasz	struct ctl_iscsi req;
1098264530Strasz	struct sockaddr_storage ss;
1099255570Strasz
1100255570Strasz	bzero(&req, sizeof(req));
1101255570Strasz
1102255570Strasz	req.type = CTL_ISCSI_ACCEPT;
1103264530Strasz	req.data.accept.initiator_addr = (struct sockaddr *)&ss;
1104255570Strasz
1105264526Strasz	if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1)
1106264526Strasz		log_err(1, "error issuing CTL_ISCSI ioctl");
1107255570Strasz
1108261765Strasz	if (req.status != CTL_ISCSI_OK) {
1109264526Strasz		log_errx(1, "error returned from CTL iSCSI accept: %s",
1110261765Strasz		    req.error_str);
1111261765Strasz	}
1112261765Strasz
1113264526Strasz	*connection_id = req.data.accept.connection_id;
1114264526Strasz	*portal_id = req.data.accept.portal_id;
1115264530Strasz	*client_salen = req.data.accept.initiator_addrlen;
1116264530Strasz	memcpy(client_sa, &ss, *client_salen);
1117255570Strasz}
1118255570Strasz
1119255570Straszvoid
1120255570Straszkernel_send(struct pdu *pdu)
1121255570Strasz{
1122255570Strasz	struct ctl_iscsi req;
1123255570Strasz
1124255570Strasz	bzero(&req, sizeof(req));
1125255570Strasz
1126255570Strasz	req.type = CTL_ISCSI_SEND;
1127255570Strasz	req.data.send.connection_id = pdu->pdu_connection->conn_socket;
1128255570Strasz	req.data.send.bhs = pdu->pdu_bhs;
1129255570Strasz	req.data.send.data_segment_len = pdu->pdu_data_len;
1130255570Strasz	req.data.send.data_segment = pdu->pdu_data;
1131255570Strasz
1132261765Strasz	if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) {
1133255570Strasz		log_err(1, "error issuing CTL_ISCSI ioctl; "
1134255570Strasz		    "dropping connection");
1135261765Strasz	}
1136255570Strasz
1137261765Strasz	if (req.status != CTL_ISCSI_OK) {
1138255570Strasz		log_errx(1, "error returned from CTL iSCSI send: "
1139255570Strasz		    "%s; dropping connection", req.error_str);
1140261765Strasz	}
1141255570Strasz}
1142255570Strasz
1143255570Straszvoid
1144255570Straszkernel_receive(struct pdu *pdu)
1145255570Strasz{
1146255570Strasz	struct ctl_iscsi req;
1147255570Strasz
1148255570Strasz	pdu->pdu_data = malloc(MAX_DATA_SEGMENT_LENGTH);
1149255570Strasz	if (pdu->pdu_data == NULL)
1150255570Strasz		log_err(1, "malloc");
1151255570Strasz
1152255570Strasz	bzero(&req, sizeof(req));
1153255570Strasz
1154255570Strasz	req.type = CTL_ISCSI_RECEIVE;
1155255570Strasz	req.data.receive.connection_id = pdu->pdu_connection->conn_socket;
1156255570Strasz	req.data.receive.bhs = pdu->pdu_bhs;
1157255570Strasz	req.data.receive.data_segment_len = MAX_DATA_SEGMENT_LENGTH;
1158255570Strasz	req.data.receive.data_segment = pdu->pdu_data;
1159255570Strasz
1160261765Strasz	if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) {
1161255570Strasz		log_err(1, "error issuing CTL_ISCSI ioctl; "
1162255570Strasz		    "dropping connection");
1163261765Strasz	}
1164255570Strasz
1165261765Strasz	if (req.status != CTL_ISCSI_OK) {
1166255570Strasz		log_errx(1, "error returned from CTL iSCSI receive: "
1167255570Strasz		    "%s; dropping connection", req.error_str);
1168261765Strasz	}
1169255570Strasz
1170255570Strasz}
1171255570Strasz
1172255570Strasz#endif /* ICL_KERNEL_PROXY */
1173255570Strasz
1174255570Strasz/*
1175255570Strasz * XXX: I CANT INTO LATIN
1176255570Strasz */
1177255570Straszvoid
1178255570Straszkernel_capsicate(void)
1179255570Strasz{
1180255570Strasz	int error;
1181255570Strasz	cap_rights_t rights;
1182255570Strasz	const unsigned long cmds[] = { CTL_ISCSI };
1183255570Strasz
1184255570Strasz	cap_rights_init(&rights, CAP_IOCTL);
1185255570Strasz	error = cap_rights_limit(ctl_fd, &rights);
1186255570Strasz	if (error != 0 && errno != ENOSYS)
1187255570Strasz		log_err(1, "cap_rights_limit");
1188255570Strasz
1189255570Strasz	error = cap_ioctls_limit(ctl_fd, cmds,
1190255570Strasz	    sizeof(cmds) / sizeof(cmds[0]));
1191255570Strasz	if (error != 0 && errno != ENOSYS)
1192255570Strasz		log_err(1, "cap_ioctls_limit");
1193255570Strasz
1194255570Strasz	error = cap_enter();
1195255570Strasz	if (error != 0 && errno != ENOSYS)
1196255570Strasz		log_err(1, "cap_enter");
1197255570Strasz
1198255570Strasz	if (cap_sandboxed())
1199255570Strasz		log_debugx("Capsicum capability mode enabled");
1200255570Strasz	else
1201255570Strasz		log_warnx("Capsicum capability mode not supported");
1202255570Strasz}
1203255570Strasz
1204