kernel.c revision 319152
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: stable/11/usr.sbin/ctld/kernel.c 319152 2017-05-29 18:17:34Z ngie $");
39270279Strasz
40316252Sngie#include <sys/param.h>
41316252Sngie#include <sys/capsicum.h>
42316252Sngie#include <sys/callout.h>
43255570Strasz#include <sys/ioctl.h>
44255570Strasz#include <sys/linker.h>
45319152Sngie#include <sys/module.h>
46255570Strasz#include <sys/queue.h>
47255570Strasz#include <sys/sbuf.h>
48316252Sngie#include <sys/stat.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_backend.h>
64255570Strasz#include <cam/ctl/ctl_ioctl.h>
65255570Strasz#include <cam/ctl/ctl_util.h>
66255570Strasz#include <cam/ctl/ctl_scsi_all.h>
67255570Strasz
68264524Strasz#include "ctld.h"
69264524Strasz
70255570Strasz#ifdef ICL_KERNEL_PROXY
71255570Strasz#include <netdb.h>
72255570Strasz#endif
73255570Strasz
74264524Straszextern bool proxy_mode;
75255570Strasz
76255570Straszstatic int	ctl_fd = 0;
77255570Strasz
78255570Straszvoid
79255570Straszkernel_init(void)
80255570Strasz{
81255570Strasz	int retval, saved_errno;
82255570Strasz
83255570Strasz	ctl_fd = open(CTL_DEFAULT_DEV, O_RDWR);
84255665Strasz	if (ctl_fd < 0 && errno == ENOENT) {
85255570Strasz		saved_errno = errno;
86255570Strasz		retval = kldload("ctl");
87255570Strasz		if (retval != -1)
88255570Strasz			ctl_fd = open(CTL_DEFAULT_DEV, O_RDWR);
89255570Strasz		else
90255570Strasz			errno = saved_errno;
91255570Strasz	}
92255570Strasz	if (ctl_fd < 0)
93255570Strasz		log_err(1, "failed to open %s", CTL_DEFAULT_DEV);
94319152Sngie#ifdef	WANT_ISCSI
95319152Sngie	else {
96319152Sngie		saved_errno = errno;
97319152Sngie		if (modfind("cfiscsi") == -1 && kldload("cfiscsi") == -1)
98319152Sngie			log_warn("couldn't load cfiscsi");
99319152Sngie		errno = saved_errno;
100319152Sngie	}
101319152Sngie#endif
102255570Strasz}
103255570Strasz
104255570Strasz/*
105255570Strasz * Name/value pair used for per-LUN attributes.
106255570Strasz */
107255570Straszstruct cctl_lun_nv {
108255570Strasz	char *name;
109255570Strasz	char *value;
110255570Strasz	STAILQ_ENTRY(cctl_lun_nv) links;
111255570Strasz};
112255570Strasz
113255570Strasz/*
114273464Strasz * Backend LUN information.
115255570Strasz */
116255570Straszstruct cctl_lun {
117255570Strasz	uint64_t lun_id;
118255570Strasz	char *backend_type;
119288310Smav	uint8_t device_type;
120255570Strasz	uint64_t size_blocks;
121255570Strasz	uint32_t blocksize;
122255570Strasz	char *serial_number;
123255570Strasz	char *device_id;
124278037Smav	char *ctld_name;
125255570Strasz	STAILQ_HEAD(,cctl_lun_nv) attr_list;
126255570Strasz	STAILQ_ENTRY(cctl_lun) links;
127255570Strasz};
128255570Strasz
129268291Smavstruct cctl_port {
130268291Smav	uint32_t port_id;
131288061Smav	char *port_frontend;
132278354Smav	char *port_name;
133284765Smav	int pp;
134284765Smav	int vp;
135278322Smav	int cfiscsi_state;
136268291Smav	char *cfiscsi_target;
137268291Smav	uint16_t cfiscsi_portal_group_tag;
138278322Smav	char *ctld_portal_group_name;
139268291Smav	STAILQ_HEAD(,cctl_lun_nv) attr_list;
140268291Smav	STAILQ_ENTRY(cctl_port) links;
141268291Smav};
142268291Smav
143255570Straszstruct cctl_devlist_data {
144255570Strasz	int num_luns;
145255570Strasz	STAILQ_HEAD(,cctl_lun) lun_list;
146255570Strasz	struct cctl_lun *cur_lun;
147268291Smav	int num_ports;
148268291Smav	STAILQ_HEAD(,cctl_port) port_list;
149268291Smav	struct cctl_port *cur_port;
150255570Strasz	int level;
151255570Strasz	struct sbuf *cur_sb[32];
152255570Strasz};
153255570Strasz
154255570Straszstatic void
155255570Straszcctl_start_element(void *user_data, const char *name, const char **attr)
156255570Strasz{
157255570Strasz	int i;
158255570Strasz	struct cctl_devlist_data *devlist;
159255570Strasz	struct cctl_lun *cur_lun;
160255570Strasz
161255570Strasz	devlist = (struct cctl_devlist_data *)user_data;
162255570Strasz	cur_lun = devlist->cur_lun;
163255570Strasz	devlist->level++;
164256189Strasz	if ((u_int)devlist->level >= (sizeof(devlist->cur_sb) /
165255570Strasz	    sizeof(devlist->cur_sb[0])))
166255570Strasz		log_errx(1, "%s: too many nesting levels, %zd max", __func__,
167255570Strasz		     sizeof(devlist->cur_sb) / sizeof(devlist->cur_sb[0]));
168255570Strasz
169255570Strasz	devlist->cur_sb[devlist->level] = sbuf_new_auto();
170255570Strasz	if (devlist->cur_sb[devlist->level] == NULL)
171255570Strasz		log_err(1, "%s: unable to allocate sbuf", __func__);
172255570Strasz
173255570Strasz	if (strcmp(name, "lun") == 0) {
174255570Strasz		if (cur_lun != NULL)
175255570Strasz			log_errx(1, "%s: improper lun element nesting",
176255570Strasz			    __func__);
177255570Strasz
178255570Strasz		cur_lun = calloc(1, sizeof(*cur_lun));
179255570Strasz		if (cur_lun == NULL)
180255570Strasz			log_err(1, "%s: cannot allocate %zd bytes", __func__,
181255570Strasz			    sizeof(*cur_lun));
182255570Strasz
183255570Strasz		devlist->num_luns++;
184255570Strasz		devlist->cur_lun = cur_lun;
185255570Strasz
186255570Strasz		STAILQ_INIT(&cur_lun->attr_list);
187255570Strasz		STAILQ_INSERT_TAIL(&devlist->lun_list, cur_lun, links);
188255570Strasz
189255570Strasz		for (i = 0; attr[i] != NULL; i += 2) {
190255570Strasz			if (strcmp(attr[i], "id") == 0) {
191255570Strasz				cur_lun->lun_id = strtoull(attr[i+1], NULL, 0);
192255570Strasz			} else {
193255570Strasz				log_errx(1, "%s: invalid LUN attribute %s = %s",
194255570Strasz				     __func__, attr[i], attr[i+1]);
195255570Strasz			}
196255570Strasz		}
197255570Strasz	}
198255570Strasz}
199255570Strasz
200255570Straszstatic void
201255570Straszcctl_end_element(void *user_data, const char *name)
202255570Strasz{
203255570Strasz	struct cctl_devlist_data *devlist;
204255570Strasz	struct cctl_lun *cur_lun;
205255570Strasz	char *str;
206255570Strasz
207255570Strasz	devlist = (struct cctl_devlist_data *)user_data;
208255570Strasz	cur_lun = devlist->cur_lun;
209255570Strasz
210255570Strasz	if ((cur_lun == NULL)
211255570Strasz	 && (strcmp(name, "ctllunlist") != 0))
212255570Strasz		log_errx(1, "%s: cur_lun == NULL! (name = %s)", __func__, name);
213255570Strasz
214255570Strasz	if (devlist->cur_sb[devlist->level] == NULL)
215255570Strasz		log_errx(1, "%s: no valid sbuf at level %d (name %s)", __func__,
216255570Strasz		     devlist->level, name);
217255570Strasz
218255570Strasz	sbuf_finish(devlist->cur_sb[devlist->level]);
219255570Strasz	str = checked_strdup(sbuf_data(devlist->cur_sb[devlist->level]));
220255570Strasz
221255570Strasz	if (strlen(str) == 0) {
222255570Strasz		free(str);
223255570Strasz		str = NULL;
224255570Strasz	}
225255570Strasz
226255570Strasz	sbuf_delete(devlist->cur_sb[devlist->level]);
227255570Strasz	devlist->cur_sb[devlist->level] = NULL;
228255570Strasz	devlist->level--;
229255570Strasz
230255570Strasz	if (strcmp(name, "backend_type") == 0) {
231255570Strasz		cur_lun->backend_type = str;
232255570Strasz		str = NULL;
233288310Smav	} else if (strcmp(name, "lun_type") == 0) {
234288310Smav		cur_lun->device_type = strtoull(str, NULL, 0);
235255570Strasz	} else if (strcmp(name, "size") == 0) {
236255570Strasz		cur_lun->size_blocks = strtoull(str, NULL, 0);
237255570Strasz	} else if (strcmp(name, "blocksize") == 0) {
238255570Strasz		cur_lun->blocksize = strtoul(str, NULL, 0);
239255570Strasz	} else if (strcmp(name, "serial_number") == 0) {
240255570Strasz		cur_lun->serial_number = str;
241255570Strasz		str = NULL;
242255570Strasz	} else if (strcmp(name, "device_id") == 0) {
243255570Strasz		cur_lun->device_id = str;
244255570Strasz		str = NULL;
245278037Smav	} else if (strcmp(name, "ctld_name") == 0) {
246278037Smav		cur_lun->ctld_name = str;
247255570Strasz		str = NULL;
248255570Strasz	} else if (strcmp(name, "lun") == 0) {
249255570Strasz		devlist->cur_lun = NULL;
250255570Strasz	} else if (strcmp(name, "ctllunlist") == 0) {
251273464Strasz		/* Nothing. */
252255570Strasz	} else {
253255570Strasz		struct cctl_lun_nv *nv;
254255570Strasz
255255570Strasz		nv = calloc(1, sizeof(*nv));
256255570Strasz		if (nv == NULL)
257255570Strasz			log_err(1, "%s: can't allocate %zd bytes for nv pair",
258255570Strasz			    __func__, sizeof(*nv));
259255570Strasz
260255570Strasz		nv->name = checked_strdup(name);
261255570Strasz
262255570Strasz		nv->value = str;
263255570Strasz		str = NULL;
264255570Strasz		STAILQ_INSERT_TAIL(&cur_lun->attr_list, nv, links);
265255570Strasz	}
266255570Strasz
267255570Strasz	free(str);
268255570Strasz}
269255570Strasz
270255570Straszstatic void
271268291Smavcctl_start_pelement(void *user_data, const char *name, const char **attr)
272268291Smav{
273268291Smav	int i;
274268291Smav	struct cctl_devlist_data *devlist;
275268291Smav	struct cctl_port *cur_port;
276268291Smav
277268291Smav	devlist = (struct cctl_devlist_data *)user_data;
278268291Smav	cur_port = devlist->cur_port;
279268291Smav	devlist->level++;
280268291Smav	if ((u_int)devlist->level >= (sizeof(devlist->cur_sb) /
281268291Smav	    sizeof(devlist->cur_sb[0])))
282268291Smav		log_errx(1, "%s: too many nesting levels, %zd max", __func__,
283268291Smav		     sizeof(devlist->cur_sb) / sizeof(devlist->cur_sb[0]));
284268291Smav
285268291Smav	devlist->cur_sb[devlist->level] = sbuf_new_auto();
286268291Smav	if (devlist->cur_sb[devlist->level] == NULL)
287268291Smav		log_err(1, "%s: unable to allocate sbuf", __func__);
288268291Smav
289268291Smav	if (strcmp(name, "targ_port") == 0) {
290268291Smav		if (cur_port != NULL)
291268291Smav			log_errx(1, "%s: improper port element nesting (%s)",
292268291Smav			    __func__, name);
293268291Smav
294268291Smav		cur_port = calloc(1, sizeof(*cur_port));
295268291Smav		if (cur_port == NULL)
296268291Smav			log_err(1, "%s: cannot allocate %zd bytes", __func__,
297268291Smav			    sizeof(*cur_port));
298268291Smav
299268291Smav		devlist->num_ports++;
300268291Smav		devlist->cur_port = cur_port;
301268291Smav
302268291Smav		STAILQ_INIT(&cur_port->attr_list);
303268291Smav		STAILQ_INSERT_TAIL(&devlist->port_list, cur_port, links);
304268291Smav
305268291Smav		for (i = 0; attr[i] != NULL; i += 2) {
306268291Smav			if (strcmp(attr[i], "id") == 0) {
307268291Smav				cur_port->port_id = strtoul(attr[i+1], NULL, 0);
308268291Smav			} else {
309268291Smav				log_errx(1, "%s: invalid LUN attribute %s = %s",
310268291Smav				     __func__, attr[i], attr[i+1]);
311268291Smav			}
312268291Smav		}
313268291Smav	}
314268291Smav}
315268291Smav
316268291Smavstatic void
317268291Smavcctl_end_pelement(void *user_data, const char *name)
318268291Smav{
319268291Smav	struct cctl_devlist_data *devlist;
320268291Smav	struct cctl_port *cur_port;
321268291Smav	char *str;
322268291Smav
323268291Smav	devlist = (struct cctl_devlist_data *)user_data;
324268291Smav	cur_port = devlist->cur_port;
325268291Smav
326268291Smav	if ((cur_port == NULL)
327268291Smav	 && (strcmp(name, "ctlportlist") != 0))
328268291Smav		log_errx(1, "%s: cur_port == NULL! (name = %s)", __func__, name);
329268291Smav
330268291Smav	if (devlist->cur_sb[devlist->level] == NULL)
331268291Smav		log_errx(1, "%s: no valid sbuf at level %d (name %s)", __func__,
332268291Smav		     devlist->level, name);
333268291Smav
334268291Smav	sbuf_finish(devlist->cur_sb[devlist->level]);
335268291Smav	str = checked_strdup(sbuf_data(devlist->cur_sb[devlist->level]));
336268291Smav
337268291Smav	if (strlen(str) == 0) {
338268291Smav		free(str);
339268291Smav		str = NULL;
340268291Smav	}
341268291Smav
342268291Smav	sbuf_delete(devlist->cur_sb[devlist->level]);
343268291Smav	devlist->cur_sb[devlist->level] = NULL;
344268291Smav	devlist->level--;
345268291Smav
346288061Smav	if (strcmp(name, "frontend_type") == 0) {
347288061Smav		cur_port->port_frontend = str;
348288061Smav		str = NULL;
349288061Smav	} else if (strcmp(name, "port_name") == 0) {
350278354Smav		cur_port->port_name = str;
351278354Smav		str = NULL;
352284765Smav	} else if (strcmp(name, "physical_port") == 0) {
353284765Smav		cur_port->pp = strtoul(str, NULL, 0);
354284765Smav	} else if (strcmp(name, "virtual_port") == 0) {
355284765Smav		cur_port->vp = strtoul(str, NULL, 0);
356278354Smav	} else if (strcmp(name, "cfiscsi_target") == 0) {
357268291Smav		cur_port->cfiscsi_target = str;
358268291Smav		str = NULL;
359278322Smav	} else if (strcmp(name, "cfiscsi_state") == 0) {
360278322Smav		cur_port->cfiscsi_state = strtoul(str, NULL, 0);
361268291Smav	} else if (strcmp(name, "cfiscsi_portal_group_tag") == 0) {
362268291Smav		cur_port->cfiscsi_portal_group_tag = strtoul(str, NULL, 0);
363278322Smav	} else if (strcmp(name, "ctld_portal_group_name") == 0) {
364278322Smav		cur_port->ctld_portal_group_name = str;
365278322Smav		str = NULL;
366268291Smav	} else if (strcmp(name, "targ_port") == 0) {
367268291Smav		devlist->cur_port = NULL;
368268291Smav	} else if (strcmp(name, "ctlportlist") == 0) {
369273464Strasz		/* Nothing. */
370268291Smav	} else {
371268291Smav		struct cctl_lun_nv *nv;
372268291Smav
373268291Smav		nv = calloc(1, sizeof(*nv));
374268291Smav		if (nv == NULL)
375268291Smav			log_err(1, "%s: can't allocate %zd bytes for nv pair",
376268291Smav			    __func__, sizeof(*nv));
377268291Smav
378268291Smav		nv->name = checked_strdup(name);
379268291Smav
380268291Smav		nv->value = str;
381268291Smav		str = NULL;
382268291Smav		STAILQ_INSERT_TAIL(&cur_port->attr_list, nv, links);
383268291Smav	}
384268291Smav
385268291Smav	free(str);
386268291Smav}
387268291Smav
388268291Smavstatic void
389255570Straszcctl_char_handler(void *user_data, const XML_Char *str, int len)
390255570Strasz{
391255570Strasz	struct cctl_devlist_data *devlist;
392255570Strasz
393255570Strasz	devlist = (struct cctl_devlist_data *)user_data;
394255570Strasz
395255570Strasz	sbuf_bcat(devlist->cur_sb[devlist->level], str, len);
396255570Strasz}
397255570Strasz
398255570Straszstruct conf *
399255570Straszconf_new_from_kernel(void)
400255570Strasz{
401255570Strasz	struct conf *conf = NULL;
402255570Strasz	struct target *targ;
403278322Smav	struct portal_group *pg;
404278354Smav	struct pport *pp;
405278322Smav	struct port *cp;
406255570Strasz	struct lun *cl;
407290615Smav	struct option *o;
408255570Strasz	struct ctl_lun_list list;
409255570Strasz	struct cctl_devlist_data devlist;
410255570Strasz	struct cctl_lun *lun;
411268291Smav	struct cctl_port *port;
412255570Strasz	XML_Parser parser;
413284765Smav	char *str, *name;
414268291Smav	int len, retval;
415255570Strasz
416255570Strasz	bzero(&devlist, sizeof(devlist));
417255570Strasz	STAILQ_INIT(&devlist.lun_list);
418268291Smav	STAILQ_INIT(&devlist.port_list);
419255570Strasz
420255570Strasz	log_debugx("obtaining previously configured CTL luns from the kernel");
421255570Strasz
422268291Smav	str = NULL;
423268291Smav	len = 4096;
424255570Straszretry:
425268291Smav	str = realloc(str, len);
426268291Smav	if (str == NULL)
427255570Strasz		log_err(1, "realloc");
428255570Strasz
429255570Strasz	bzero(&list, sizeof(list));
430268291Smav	list.alloc_len = len;
431255570Strasz	list.status = CTL_LUN_LIST_NONE;
432268291Smav	list.lun_xml = str;
433255570Strasz
434255570Strasz	if (ioctl(ctl_fd, CTL_LUN_LIST, &list) == -1) {
435255570Strasz		log_warn("error issuing CTL_LUN_LIST ioctl");
436268291Smav		free(str);
437255570Strasz		return (NULL);
438255570Strasz	}
439255570Strasz
440255570Strasz	if (list.status == CTL_LUN_LIST_ERROR) {
441255570Strasz		log_warnx("error returned from CTL_LUN_LIST ioctl: %s",
442255570Strasz		    list.error_str);
443268291Smav		free(str);
444255570Strasz		return (NULL);
445255570Strasz	}
446255570Strasz
447255570Strasz	if (list.status == CTL_LUN_LIST_NEED_MORE_SPACE) {
448268291Smav		len = len << 1;
449255570Strasz		goto retry;
450255570Strasz	}
451255570Strasz
452255570Strasz	parser = XML_ParserCreate(NULL);
453255570Strasz	if (parser == NULL) {
454255570Strasz		log_warnx("unable to create XML parser");
455268291Smav		free(str);
456255570Strasz		return (NULL);
457255570Strasz	}
458255570Strasz
459255570Strasz	XML_SetUserData(parser, &devlist);
460255570Strasz	XML_SetElementHandler(parser, cctl_start_element, cctl_end_element);
461255570Strasz	XML_SetCharacterDataHandler(parser, cctl_char_handler);
462255570Strasz
463268291Smav	retval = XML_Parse(parser, str, strlen(str), 1);
464255570Strasz	XML_ParserFree(parser);
465268291Smav	free(str);
466255570Strasz	if (retval != 1) {
467255570Strasz		log_warnx("XML_Parse failed");
468255570Strasz		return (NULL);
469255570Strasz	}
470255570Strasz
471268291Smav	str = NULL;
472268291Smav	len = 4096;
473268291Smavretry_port:
474268291Smav	str = realloc(str, len);
475268291Smav	if (str == NULL)
476268291Smav		log_err(1, "realloc");
477268291Smav
478268291Smav	bzero(&list, sizeof(list));
479268291Smav	list.alloc_len = len;
480268291Smav	list.status = CTL_LUN_LIST_NONE;
481268291Smav	list.lun_xml = str;
482268291Smav
483268291Smav	if (ioctl(ctl_fd, CTL_PORT_LIST, &list) == -1) {
484268291Smav		log_warn("error issuing CTL_PORT_LIST ioctl");
485268291Smav		free(str);
486268291Smav		return (NULL);
487268291Smav	}
488268291Smav
489288259Smav	if (list.status == CTL_LUN_LIST_ERROR) {
490268291Smav		log_warnx("error returned from CTL_PORT_LIST ioctl: %s",
491268291Smav		    list.error_str);
492268291Smav		free(str);
493268291Smav		return (NULL);
494268291Smav	}
495268291Smav
496268291Smav	if (list.status == CTL_LUN_LIST_NEED_MORE_SPACE) {
497268291Smav		len = len << 1;
498268291Smav		goto retry_port;
499268291Smav	}
500268291Smav
501268291Smav	parser = XML_ParserCreate(NULL);
502268291Smav	if (parser == NULL) {
503268291Smav		log_warnx("unable to create XML parser");
504268291Smav		free(str);
505268291Smav		return (NULL);
506268291Smav	}
507268291Smav
508268291Smav	XML_SetUserData(parser, &devlist);
509268291Smav	XML_SetElementHandler(parser, cctl_start_pelement, cctl_end_pelement);
510268291Smav	XML_SetCharacterDataHandler(parser, cctl_char_handler);
511268291Smav
512268291Smav	retval = XML_Parse(parser, str, strlen(str), 1);
513268291Smav	XML_ParserFree(parser);
514268291Smav	free(str);
515268291Smav	if (retval != 1) {
516268291Smav		log_warnx("XML_Parse failed");
517268291Smav		return (NULL);
518268291Smav	}
519268291Smav
520255570Strasz	conf = conf_new();
521255570Strasz
522284765Smav	name = NULL;
523268291Smav	STAILQ_FOREACH(port, &devlist.port_list, links) {
524288061Smav		if (strcmp(port->port_frontend, "ha") == 0)
525288061Smav			continue;
526290821Strasz		free(name);
527290824Strasz		if (port->pp == 0 && port->vp == 0) {
528284765Smav			name = checked_strdup(port->port_name);
529290824Strasz		} else if (port->vp == 0) {
530290824Strasz			retval = asprintf(&name, "%s/%d",
531290824Strasz			    port->port_name, port->pp);
532290824Strasz			if (retval <= 0)
533290824Strasz				log_err(1, "asprintf");
534290824Strasz		} else {
535290824Strasz			retval = asprintf(&name, "%s/%d/%d",
536290824Strasz			    port->port_name, port->pp, port->vp);
537290824Strasz			if (retval <= 0)
538290824Strasz				log_err(1, "asprintf");
539290824Strasz		}
540268291Smav
541268291Smav		if (port->cfiscsi_target == NULL) {
542278354Smav			log_debugx("CTL port %u \"%s\" wasn't managed by ctld; ",
543284765Smav			    port->port_id, name);
544284765Smav			pp = pport_find(conf, name);
545278354Smav			if (pp == NULL) {
546278354Smav#if 0
547278354Smav				log_debugx("found new kernel port %u \"%s\"",
548284765Smav				    port->port_id, name);
549278354Smav#endif
550284765Smav				pp = pport_new(conf, name, port->port_id);
551278354Smav				if (pp == NULL) {
552278354Smav					log_warnx("pport_new failed");
553278354Smav					continue;
554278354Smav				}
555278354Smav			}
556268291Smav			continue;
557268291Smav		}
558278322Smav		if (port->cfiscsi_state != 1) {
559268328Smav			log_debugx("CTL port %ju is not active (%d); ignoring",
560278322Smav			    (uintmax_t)port->port_id, port->cfiscsi_state);
561268328Smav			continue;
562268328Smav		}
563268291Smav
564268291Smav		targ = target_find(conf, port->cfiscsi_target);
565268291Smav		if (targ == NULL) {
566268291Smav#if 0
567268291Smav			log_debugx("found new kernel target %s for CTL port %ld",
568268291Smav			    port->cfiscsi_target, port->port_id);
569268291Smav#endif
570268291Smav			targ = target_new(conf, port->cfiscsi_target);
571268291Smav			if (targ == NULL) {
572268291Smav				log_warnx("target_new failed");
573268291Smav				continue;
574268291Smav			}
575268291Smav		}
576278322Smav
577278322Smav		if (port->ctld_portal_group_name == NULL)
578278322Smav			continue;
579278322Smav		pg = portal_group_find(conf, port->ctld_portal_group_name);
580278322Smav		if (pg == NULL) {
581278322Smav#if 0
582278322Smav			log_debugx("found new kernel portal group %s for CTL port %ld",
583278322Smav			    port->ctld_portal_group_name, port->port_id);
584278322Smav#endif
585278322Smav			pg = portal_group_new(conf, port->ctld_portal_group_name);
586278322Smav			if (pg == NULL) {
587278322Smav				log_warnx("portal_group_new failed");
588278322Smav				continue;
589278322Smav			}
590278322Smav		}
591278322Smav		pg->pg_tag = port->cfiscsi_portal_group_tag;
592278322Smav		cp = port_new(conf, targ, pg);
593278322Smav		if (cp == NULL) {
594278322Smav			log_warnx("port_new failed");
595278322Smav			continue;
596278322Smav		}
597278322Smav		cp->p_ctl_port = port->port_id;
598268291Smav	}
599290821Strasz	free(name);
600268291Smav
601255570Strasz	STAILQ_FOREACH(lun, &devlist.lun_list, links) {
602255570Strasz		struct cctl_lun_nv *nv;
603255570Strasz
604278037Smav		if (lun->ctld_name == NULL) {
605255570Strasz			log_debugx("CTL lun %ju wasn't managed by ctld; "
606255570Strasz			    "ignoring", (uintmax_t)lun->lun_id);
607255570Strasz			continue;
608255570Strasz		}
609255570Strasz
610278037Smav		cl = lun_find(conf, lun->ctld_name);
611255570Strasz		if (cl != NULL) {
612278037Smav			log_warnx("found CTL lun %ju \"%s\", "
613278037Smav			    "also backed by CTL lun %d; ignoring",
614278037Smav			    (uintmax_t)lun->lun_id, lun->ctld_name,
615278037Smav			    cl->l_ctl_lun);
616255570Strasz			continue;
617255570Strasz		}
618255570Strasz
619278037Smav		log_debugx("found CTL lun %ju \"%s\"",
620278037Smav		    (uintmax_t)lun->lun_id, lun->ctld_name);
621255570Strasz
622278037Smav		cl = lun_new(conf, lun->ctld_name);
623255570Strasz		if (cl == NULL) {
624255570Strasz			log_warnx("lun_new failed");
625255570Strasz			continue;
626255570Strasz		}
627255570Strasz		lun_set_backend(cl, lun->backend_type);
628288310Smav		lun_set_device_type(cl, lun->device_type);
629255570Strasz		lun_set_blocksize(cl, lun->blocksize);
630255570Strasz		lun_set_device_id(cl, lun->device_id);
631255570Strasz		lun_set_serial(cl, lun->serial_number);
632255570Strasz		lun_set_size(cl, lun->size_blocks * cl->l_blocksize);
633255570Strasz		lun_set_ctl_lun(cl, lun->lun_id);
634255570Strasz
635255570Strasz		STAILQ_FOREACH(nv, &lun->attr_list, links) {
636255570Strasz			if (strcmp(nv->name, "file") == 0 ||
637255570Strasz			    strcmp(nv->name, "dev") == 0) {
638255570Strasz				lun_set_path(cl, nv->value);
639255570Strasz				continue;
640255570Strasz			}
641290615Smav			o = option_new(&cl->l_options, nv->name, nv->value);
642290615Smav			if (o == NULL)
643255570Strasz				log_warnx("unable to add CTL lun option %s "
644278037Smav				    "for CTL lun %ju \"%s\"",
645255570Strasz				    nv->name, (uintmax_t) lun->lun_id,
646278037Smav				    cl->l_name);
647255570Strasz		}
648255570Strasz	}
649255570Strasz
650255570Strasz	return (conf);
651255570Strasz}
652255570Strasz
653268291Smavstatic void
654268291Smavstr_arg(struct ctl_be_arg *arg, const char *name, const char *value)
655268291Smav{
656268291Smav
657268291Smav	arg->namelen = strlen(name) + 1;
658268291Smav	arg->name = __DECONST(char *, name);
659268291Smav	arg->vallen = strlen(value) + 1;
660268291Smav	arg->value = __DECONST(char *, value);
661268291Smav	arg->flags = CTL_BEARG_ASCII | CTL_BEARG_RD;
662268291Smav}
663268291Smav
664255570Straszint
665255570Straszkernel_lun_add(struct lun *lun)
666255570Strasz{
667290615Smav	struct option *o;
668255570Strasz	struct ctl_lun_req req;
669255570Strasz	int error, i, num_options;
670255570Strasz
671255570Strasz	bzero(&req, sizeof(req));
672255570Strasz
673255570Strasz	strlcpy(req.backend, lun->l_backend, sizeof(req.backend));
674255570Strasz	req.reqtype = CTL_LUNREQ_CREATE;
675255570Strasz
676255570Strasz	req.reqdata.create.blocksize_bytes = lun->l_blocksize;
677255570Strasz
678255570Strasz	if (lun->l_size != 0)
679255570Strasz		req.reqdata.create.lun_size_bytes = lun->l_size;
680255570Strasz
681287823Smav	if (lun->l_ctl_lun >= 0) {
682287823Smav		req.reqdata.create.req_lun_id = lun->l_ctl_lun;
683287823Smav		req.reqdata.create.flags |= CTL_LUN_FLAG_ID_REQ;
684287823Smav	}
685287823Smav
686255570Strasz	req.reqdata.create.flags |= CTL_LUN_FLAG_DEV_TYPE;
687288310Smav	req.reqdata.create.device_type = lun->l_device_type;
688255570Strasz
689255570Strasz	if (lun->l_serial != NULL) {
690267648Smav		strncpy(req.reqdata.create.serial_num, lun->l_serial,
691255570Strasz			sizeof(req.reqdata.create.serial_num));
692255570Strasz		req.reqdata.create.flags |= CTL_LUN_FLAG_SERIAL_NUM;
693255570Strasz	}
694255570Strasz
695255570Strasz	if (lun->l_device_id != NULL) {
696267648Smav		strncpy(req.reqdata.create.device_id, lun->l_device_id,
697255570Strasz			sizeof(req.reqdata.create.device_id));
698255570Strasz		req.reqdata.create.flags |= CTL_LUN_FLAG_DEVID;
699255570Strasz	}
700255570Strasz
701255570Strasz	if (lun->l_path != NULL) {
702290615Smav		o = option_find(&lun->l_options, "file");
703290615Smav		if (o != NULL) {
704290615Smav			option_set(o, lun->l_path);
705255570Strasz		} else {
706290615Smav			o = option_new(&lun->l_options, "file", lun->l_path);
707290615Smav			assert(o != NULL);
708255570Strasz		}
709255570Strasz	}
710255570Strasz
711290615Smav	o = option_find(&lun->l_options, "ctld_name");
712290615Smav	if (o != NULL) {
713290615Smav		option_set(o, lun->l_name);
714255570Strasz	} else {
715290615Smav		o = option_new(&lun->l_options, "ctld_name", lun->l_name);
716290615Smav		assert(o != NULL);
717255570Strasz	}
718255570Strasz
719290615Smav	o = option_find(&lun->l_options, "scsiname");
720290615Smav	if (o == NULL && lun->l_scsiname != NULL) {
721290615Smav		o = option_new(&lun->l_options, "scsiname", lun->l_scsiname);
722290615Smav		assert(o != NULL);
723268293Smav	}
724268293Smav
725255570Strasz	num_options = 0;
726290615Smav	TAILQ_FOREACH(o, &lun->l_options, o_next)
727255570Strasz		num_options++;
728255570Strasz
729255570Strasz	req.num_be_args = num_options;
730255570Strasz	if (num_options > 0) {
731255570Strasz		req.be_args = malloc(num_options * sizeof(*req.be_args));
732255570Strasz		if (req.be_args == NULL) {
733255570Strasz			log_warn("error allocating %zd bytes",
734255570Strasz			    num_options * sizeof(*req.be_args));
735255570Strasz			return (1);
736255570Strasz		}
737255570Strasz
738255570Strasz		i = 0;
739290615Smav		TAILQ_FOREACH(o, &lun->l_options, o_next) {
740290615Smav			str_arg(&req.be_args[i], o->o_name, o->o_value);
741255570Strasz			i++;
742255570Strasz		}
743255570Strasz		assert(i == num_options);
744255570Strasz	}
745255570Strasz
746255570Strasz	error = ioctl(ctl_fd, CTL_LUN_REQ, &req);
747255570Strasz	free(req.be_args);
748255570Strasz	if (error != 0) {
749255570Strasz		log_warn("error issuing CTL_LUN_REQ ioctl");
750255570Strasz		return (1);
751255570Strasz	}
752255570Strasz
753272911Smav	switch (req.status) {
754272911Smav	case CTL_LUN_ERROR:
755272911Smav		log_warnx("LUN creation error: %s", req.error_str);
756255570Strasz		return (1);
757272911Smav	case CTL_LUN_WARNING:
758272911Smav		log_warnx("LUN creation warning: %s", req.error_str);
759272911Smav		break;
760272911Smav	case CTL_LUN_OK:
761272911Smav		break;
762272911Smav	default:
763272911Smav		log_warnx("unknown LUN creation status: %d",
764255570Strasz		    req.status);
765255570Strasz		return (1);
766255570Strasz	}
767255570Strasz
768255570Strasz	lun_set_ctl_lun(lun, req.reqdata.create.req_lun_id);
769255570Strasz	return (0);
770255570Strasz}
771255570Strasz
772255570Straszint
773287500Smavkernel_lun_modify(struct lun *lun)
774255570Strasz{
775290615Smav	struct option *o;
776255570Strasz	struct ctl_lun_req req;
777287500Smav	int error, i, num_options;
778255570Strasz
779255570Strasz	bzero(&req, sizeof(req));
780255570Strasz
781255570Strasz	strlcpy(req.backend, lun->l_backend, sizeof(req.backend));
782255570Strasz	req.reqtype = CTL_LUNREQ_MODIFY;
783255570Strasz
784255570Strasz	req.reqdata.modify.lun_id = lun->l_ctl_lun;
785255570Strasz	req.reqdata.modify.lun_size_bytes = lun->l_size;
786255570Strasz
787287500Smav	num_options = 0;
788290615Smav	TAILQ_FOREACH(o, &lun->l_options, o_next)
789287500Smav		num_options++;
790287500Smav
791287500Smav	req.num_be_args = num_options;
792287500Smav	if (num_options > 0) {
793287500Smav		req.be_args = malloc(num_options * sizeof(*req.be_args));
794287500Smav		if (req.be_args == NULL) {
795287500Smav			log_warn("error allocating %zd bytes",
796287500Smav			    num_options * sizeof(*req.be_args));
797287500Smav			return (1);
798287500Smav		}
799287500Smav
800287500Smav		i = 0;
801290615Smav		TAILQ_FOREACH(o, &lun->l_options, o_next) {
802290615Smav			str_arg(&req.be_args[i], o->o_name, o->o_value);
803287500Smav			i++;
804287500Smav		}
805287500Smav		assert(i == num_options);
806287500Smav	}
807287500Smav
808287500Smav	error = ioctl(ctl_fd, CTL_LUN_REQ, &req);
809287500Smav	free(req.be_args);
810287500Smav	if (error != 0) {
811255570Strasz		log_warn("error issuing CTL_LUN_REQ ioctl");
812255570Strasz		return (1);
813255570Strasz	}
814255570Strasz
815272911Smav	switch (req.status) {
816272911Smav	case CTL_LUN_ERROR:
817272911Smav		log_warnx("LUN modification error: %s", req.error_str);
818255570Strasz		return (1);
819272911Smav	case CTL_LUN_WARNING:
820272911Smav		log_warnx("LUN modification warning: %s", req.error_str);
821272911Smav		break;
822272911Smav	case CTL_LUN_OK:
823272911Smav		break;
824272911Smav	default:
825272911Smav		log_warnx("unknown LUN modification status: %d",
826255570Strasz		    req.status);
827255570Strasz		return (1);
828255570Strasz	}
829255570Strasz
830255570Strasz	return (0);
831255570Strasz}
832255570Strasz
833255570Straszint
834255570Straszkernel_lun_remove(struct lun *lun)
835255570Strasz{
836255570Strasz	struct ctl_lun_req req;
837255570Strasz
838255570Strasz	bzero(&req, sizeof(req));
839255570Strasz
840255570Strasz	strlcpy(req.backend, lun->l_backend, sizeof(req.backend));
841255570Strasz	req.reqtype = CTL_LUNREQ_RM;
842255570Strasz
843255570Strasz	req.reqdata.rm.lun_id = lun->l_ctl_lun;
844255570Strasz
845255570Strasz	if (ioctl(ctl_fd, CTL_LUN_REQ, &req) == -1) {
846255570Strasz		log_warn("error issuing CTL_LUN_REQ ioctl");
847255570Strasz		return (1);
848255570Strasz	}
849255570Strasz
850272911Smav	switch (req.status) {
851272911Smav	case CTL_LUN_ERROR:
852272911Smav		log_warnx("LUN removal error: %s", req.error_str);
853255570Strasz		return (1);
854272911Smav	case CTL_LUN_WARNING:
855272911Smav		log_warnx("LUN removal warning: %s", req.error_str);
856272911Smav		break;
857272911Smav	case CTL_LUN_OK:
858272911Smav		break;
859272911Smav	default:
860272911Smav		log_warnx("unknown LUN removal status: %d", req.status);
861255570Strasz		return (1);
862255570Strasz	}
863255570Strasz
864255570Strasz	return (0);
865255570Strasz}
866255570Strasz
867255570Straszvoid
868255570Straszkernel_handoff(struct connection *conn)
869255570Strasz{
870255570Strasz	struct ctl_iscsi req;
871255570Strasz
872255570Strasz	bzero(&req, sizeof(req));
873255570Strasz
874255570Strasz	req.type = CTL_ISCSI_HANDOFF;
875255570Strasz	strlcpy(req.data.handoff.initiator_name,
876255570Strasz	    conn->conn_initiator_name, sizeof(req.data.handoff.initiator_name));
877255570Strasz	strlcpy(req.data.handoff.initiator_addr,
878255570Strasz	    conn->conn_initiator_addr, sizeof(req.data.handoff.initiator_addr));
879255570Strasz	if (conn->conn_initiator_alias != NULL) {
880255570Strasz		strlcpy(req.data.handoff.initiator_alias,
881255570Strasz		    conn->conn_initiator_alias, sizeof(req.data.handoff.initiator_alias));
882255570Strasz	}
883268302Smav	memcpy(req.data.handoff.initiator_isid, conn->conn_initiator_isid,
884268302Smav	    sizeof(req.data.handoff.initiator_isid));
885255570Strasz	strlcpy(req.data.handoff.target_name,
886261757Strasz	    conn->conn_target->t_name, sizeof(req.data.handoff.target_name));
887279392Strasz	if (conn->conn_portal->p_portal_group->pg_offload != NULL) {
888278331Strasz		strlcpy(req.data.handoff.offload,
889279392Strasz		    conn->conn_portal->p_portal_group->pg_offload,
890279392Strasz		    sizeof(req.data.handoff.offload));
891278331Strasz	}
892264524Strasz#ifdef ICL_KERNEL_PROXY
893264524Strasz	if (proxy_mode)
894264524Strasz		req.data.handoff.connection_id = conn->conn_socket;
895264524Strasz	else
896264524Strasz		req.data.handoff.socket = conn->conn_socket;
897264524Strasz#else
898255570Strasz	req.data.handoff.socket = conn->conn_socket;
899264524Strasz#endif
900255570Strasz	req.data.handoff.portal_group_tag =
901255570Strasz	    conn->conn_portal->p_portal_group->pg_tag;
902255570Strasz	if (conn->conn_header_digest == CONN_DIGEST_CRC32C)
903255570Strasz		req.data.handoff.header_digest = CTL_ISCSI_DIGEST_CRC32C;
904255570Strasz	if (conn->conn_data_digest == CONN_DIGEST_CRC32C)
905255570Strasz		req.data.handoff.data_digest = CTL_ISCSI_DIGEST_CRC32C;
906255570Strasz	req.data.handoff.cmdsn = conn->conn_cmdsn;
907255570Strasz	req.data.handoff.statsn = conn->conn_statsn;
908255570Strasz	req.data.handoff.max_recv_data_segment_length =
909255570Strasz	    conn->conn_max_data_segment_length;
910255570Strasz	req.data.handoff.max_burst_length = conn->conn_max_burst_length;
911301437Strasz	req.data.handoff.first_burst_length = conn->conn_first_burst_length;
912255570Strasz	req.data.handoff.immediate_data = conn->conn_immediate_data;
913255570Strasz
914264526Strasz	if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) {
915255570Strasz		log_err(1, "error issuing CTL_ISCSI ioctl; "
916255570Strasz		    "dropping connection");
917264526Strasz	}
918255570Strasz
919264526Strasz	if (req.status != CTL_ISCSI_OK) {
920255570Strasz		log_errx(1, "error returned from CTL iSCSI handoff request: "
921255570Strasz		    "%s; dropping connection", req.error_str);
922264526Strasz	}
923255570Strasz}
924255570Strasz
925278331Straszvoid
926278331Straszkernel_limits(const char *offload, size_t *max_data_segment_length)
927278331Strasz{
928278331Strasz	struct ctl_iscsi req;
929278331Strasz
930278331Strasz	bzero(&req, sizeof(req));
931278331Strasz
932278331Strasz	req.type = CTL_ISCSI_LIMITS;
933278331Strasz	if (offload != NULL) {
934278331Strasz		strlcpy(req.data.limits.offload, offload,
935278331Strasz		    sizeof(req.data.limits.offload));
936278331Strasz	}
937278331Strasz
938278331Strasz	if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) {
939278331Strasz		log_err(1, "error issuing CTL_ISCSI ioctl; "
940278331Strasz		    "dropping connection");
941278331Strasz	}
942278331Strasz
943278331Strasz	if (req.status != CTL_ISCSI_OK) {
944278331Strasz		log_errx(1, "error returned from CTL iSCSI limits request: "
945278331Strasz		    "%s; dropping connection", req.error_str);
946278331Strasz	}
947278331Strasz
948278331Strasz	*max_data_segment_length = req.data.limits.data_segment_limit;
949278331Strasz	if (offload != NULL) {
950278331Strasz		log_debugx("MaxRecvDataSegment kernel limit for offload "
951278331Strasz		    "\"%s\" is %zd", offload, *max_data_segment_length);
952278331Strasz	} else {
953278331Strasz		log_debugx("MaxRecvDataSegment kernel limit is %zd",
954278331Strasz		    *max_data_segment_length);
955278331Strasz	}
956278331Strasz}
957278331Strasz
958255570Straszint
959278322Smavkernel_port_add(struct port *port)
960255570Strasz{
961290615Smav	struct option *o;
962255570Strasz	struct ctl_port_entry entry;
963268291Smav	struct ctl_req req;
964278037Smav	struct ctl_lun_map lm;
965278322Smav	struct target *targ = port->p_target;
966278322Smav	struct portal_group *pg = port->p_portal_group;
967268291Smav	char tagstr[16];
968278322Smav	int error, i, n;
969255570Strasz
970278037Smav	/* Create iSCSI port. */
971278354Smav	if (port->p_portal_group) {
972278354Smav		bzero(&req, sizeof(req));
973278354Smav		strlcpy(req.driver, "iscsi", sizeof(req.driver));
974278354Smav		req.reqtype = CTL_REQ_CREATE;
975279276Smav		req.num_args = 5;
976290615Smav		TAILQ_FOREACH(o, &pg->pg_options, o_next)
977290615Smav			req.num_args++;
978278354Smav		req.args = malloc(req.num_args * sizeof(*req.args));
979279276Smav		if (req.args == NULL)
980279276Smav			log_err(1, "malloc");
981278354Smav		n = 0;
982278354Smav		req.args[n].namelen = sizeof("port_id");
983278354Smav		req.args[n].name = __DECONST(char *, "port_id");
984278354Smav		req.args[n].vallen = sizeof(port->p_ctl_port);
985278354Smav		req.args[n].value = &port->p_ctl_port;
986278354Smav		req.args[n++].flags = CTL_BEARG_WR;
987278354Smav		str_arg(&req.args[n++], "cfiscsi_target", targ->t_name);
988278354Smav		snprintf(tagstr, sizeof(tagstr), "%d", pg->pg_tag);
989278354Smav		str_arg(&req.args[n++], "cfiscsi_portal_group_tag", tagstr);
990278354Smav		if (targ->t_alias)
991278354Smav			str_arg(&req.args[n++], "cfiscsi_target_alias", targ->t_alias);
992278354Smav		str_arg(&req.args[n++], "ctld_portal_group_name", pg->pg_name);
993290615Smav		TAILQ_FOREACH(o, &pg->pg_options, o_next)
994290615Smav			str_arg(&req.args[n++], o->o_name, o->o_value);
995278354Smav		req.num_args = n;
996278354Smav		error = ioctl(ctl_fd, CTL_PORT_REQ, &req);
997278354Smav		free(req.args);
998278354Smav		if (error != 0) {
999278354Smav			log_warn("error issuing CTL_PORT_REQ ioctl");
1000278354Smav			return (1);
1001278354Smav		}
1002278354Smav		if (req.status == CTL_LUN_ERROR) {
1003278354Smav			log_warnx("error returned from port creation request: %s",
1004278354Smav			    req.error_str);
1005278354Smav			return (1);
1006278354Smav		}
1007278354Smav		if (req.status != CTL_LUN_OK) {
1008278354Smav			log_warnx("unknown port creation request status %d",
1009278354Smav			    req.status);
1010278354Smav			return (1);
1011278354Smav		}
1012279590Smav	} else if (port->p_pport) {
1013278354Smav		port->p_ctl_port = port->p_pport->pp_ctl_port;
1014268291Smav
1015279590Smav		if (strncmp(targ->t_name, "naa.", 4) == 0 &&
1016279590Smav		    strlen(targ->t_name) == 20) {
1017279590Smav			bzero(&entry, sizeof(entry));
1018279590Smav			entry.port_type = CTL_PORT_NONE;
1019279590Smav			entry.targ_port = port->p_ctl_port;
1020279590Smav			entry.flags |= CTL_PORT_WWNN_VALID;
1021279590Smav			entry.wwnn = strtoull(targ->t_name + 4, NULL, 16);
1022279590Smav			if (ioctl(ctl_fd, CTL_SET_PORT_WWNS, &entry) == -1)
1023279590Smav				log_warn("CTL_SET_PORT_WWNS ioctl failed");
1024279590Smav		}
1025279590Smav	}
1026279590Smav
1027278037Smav	/* Explicitly enable mapping to block any access except allowed. */
1028278322Smav	lm.port = port->p_ctl_port;
1029278037Smav	lm.plun = UINT32_MAX;
1030278037Smav	lm.lun = 0;
1031278037Smav	error = ioctl(ctl_fd, CTL_LUN_MAP, &lm);
1032278037Smav	if (error != 0)
1033278037Smav		log_warn("CTL_LUN_MAP ioctl failed");
1034278037Smav
1035278037Smav	/* Map configured LUNs */
1036278037Smav	for (i = 0; i < MAX_LUNS; i++) {
1037278037Smav		if (targ->t_luns[i] == NULL)
1038278037Smav			continue;
1039278322Smav		lm.port = port->p_ctl_port;
1040278037Smav		lm.plun = i;
1041278037Smav		lm.lun = targ->t_luns[i]->l_ctl_lun;
1042278037Smav		error = ioctl(ctl_fd, CTL_LUN_MAP, &lm);
1043278037Smav		if (error != 0)
1044278037Smav			log_warn("CTL_LUN_MAP ioctl failed");
1045278037Smav	}
1046278037Smav
1047278037Smav	/* Enable port */
1048255678Strasz	bzero(&entry, sizeof(entry));
1049278322Smav	entry.targ_port = port->p_ctl_port;
1050255570Strasz	error = ioctl(ctl_fd, CTL_ENABLE_PORT, &entry);
1051255570Strasz	if (error != 0) {
1052255570Strasz		log_warn("CTL_ENABLE_PORT ioctl failed");
1053255570Strasz		return (-1);
1054255570Strasz	}
1055255570Strasz
1056255570Strasz	return (0);
1057255570Strasz}
1058255570Strasz
1059255570Straszint
1060287757Smavkernel_port_update(struct port *port, struct port *oport)
1061278037Smav{
1062278037Smav	struct ctl_lun_map lm;
1063278322Smav	struct target *targ = port->p_target;
1064287757Smav	struct target *otarg = oport->p_target;
1065278037Smav	int error, i;
1066287757Smav	uint32_t olun;
1067278037Smav
1068278037Smav	/* Map configured LUNs and unmap others */
1069278037Smav	for (i = 0; i < MAX_LUNS; i++) {
1070278322Smav		lm.port = port->p_ctl_port;
1071278037Smav		lm.plun = i;
1072278037Smav		if (targ->t_luns[i] == NULL)
1073278037Smav			lm.lun = UINT32_MAX;
1074278037Smav		else
1075278037Smav			lm.lun = targ->t_luns[i]->l_ctl_lun;
1076287757Smav		if (otarg->t_luns[i] == NULL)
1077287757Smav			olun = UINT32_MAX;
1078287757Smav		else
1079287757Smav			olun = otarg->t_luns[i]->l_ctl_lun;
1080287757Smav		if (lm.lun == olun)
1081287757Smav			continue;
1082278037Smav		error = ioctl(ctl_fd, CTL_LUN_MAP, &lm);
1083278037Smav		if (error != 0)
1084278037Smav			log_warn("CTL_LUN_MAP ioctl failed");
1085278037Smav	}
1086278037Smav	return (0);
1087278037Smav}
1088278037Smav
1089278037Smavint
1090278322Smavkernel_port_remove(struct port *port)
1091255570Strasz{
1092278354Smav	struct ctl_port_entry entry;
1093278354Smav	struct ctl_lun_map lm;
1094268291Smav	struct ctl_req req;
1095268291Smav	char tagstr[16];
1096278322Smav	struct target *targ = port->p_target;
1097278322Smav	struct portal_group *pg = port->p_portal_group;
1098255570Strasz	int error;
1099255570Strasz
1100278354Smav	/* Disable port */
1101278354Smav	bzero(&entry, sizeof(entry));
1102278354Smav	entry.targ_port = port->p_ctl_port;
1103278354Smav	error = ioctl(ctl_fd, CTL_DISABLE_PORT, &entry);
1104255570Strasz	if (error != 0) {
1105278354Smav		log_warn("CTL_DISABLE_PORT ioctl failed");
1106278354Smav		return (-1);
1107255570Strasz	}
1108255570Strasz
1109278354Smav	/* Remove iSCSI port. */
1110278354Smav	if (port->p_portal_group) {
1111278354Smav		bzero(&req, sizeof(req));
1112278354Smav		strlcpy(req.driver, "iscsi", sizeof(req.driver));
1113278354Smav		req.reqtype = CTL_REQ_REMOVE;
1114278354Smav		req.num_args = 2;
1115278354Smav		req.args = malloc(req.num_args * sizeof(*req.args));
1116279276Smav		if (req.args == NULL)
1117279276Smav			log_err(1, "malloc");
1118278354Smav		str_arg(&req.args[0], "cfiscsi_target", targ->t_name);
1119278354Smav		snprintf(tagstr, sizeof(tagstr), "%d", pg->pg_tag);
1120278354Smav		str_arg(&req.args[1], "cfiscsi_portal_group_tag", tagstr);
1121278354Smav		error = ioctl(ctl_fd, CTL_PORT_REQ, &req);
1122278354Smav		free(req.args);
1123278354Smav		if (error != 0) {
1124278354Smav			log_warn("error issuing CTL_PORT_REQ ioctl");
1125278354Smav			return (1);
1126278354Smav		}
1127278354Smav		if (req.status == CTL_LUN_ERROR) {
1128278354Smav			log_warnx("error returned from port removal request: %s",
1129278354Smav			    req.error_str);
1130278354Smav			return (1);
1131278354Smav		}
1132278354Smav		if (req.status != CTL_LUN_OK) {
1133278354Smav			log_warnx("unknown port removal request status %d",
1134278354Smav			    req.status);
1135278354Smav			return (1);
1136278354Smav		}
1137278354Smav	} else {
1138278354Smav		/* Disable LUN mapping. */
1139278354Smav		lm.port = port->p_ctl_port;
1140278354Smav		lm.plun = UINT32_MAX;
1141278354Smav		lm.lun = UINT32_MAX;
1142278354Smav		error = ioctl(ctl_fd, CTL_LUN_MAP, &lm);
1143278354Smav		if (error != 0)
1144278354Smav			log_warn("CTL_LUN_MAP ioctl failed");
1145268291Smav	}
1146255570Strasz	return (0);
1147255570Strasz}
1148255570Strasz
1149255570Strasz#ifdef ICL_KERNEL_PROXY
1150255570Straszvoid
1151264526Straszkernel_listen(struct addrinfo *ai, bool iser, int portal_id)
1152255570Strasz{
1153255570Strasz	struct ctl_iscsi req;
1154255570Strasz
1155255570Strasz	bzero(&req, sizeof(req));
1156255570Strasz
1157255570Strasz	req.type = CTL_ISCSI_LISTEN;
1158255570Strasz	req.data.listen.iser = iser;
1159255570Strasz	req.data.listen.domain = ai->ai_family;
1160255570Strasz	req.data.listen.socktype = ai->ai_socktype;
1161255570Strasz	req.data.listen.protocol = ai->ai_protocol;
1162255570Strasz	req.data.listen.addr = ai->ai_addr;
1163255570Strasz	req.data.listen.addrlen = ai->ai_addrlen;
1164264526Strasz	req.data.listen.portal_id = portal_id;
1165255570Strasz
1166264526Strasz	if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1)
1167261765Strasz		log_err(1, "error issuing CTL_ISCSI ioctl");
1168261765Strasz
1169261765Strasz	if (req.status != CTL_ISCSI_OK) {
1170261765Strasz		log_errx(1, "error returned from CTL iSCSI listen: %s",
1171261765Strasz		    req.error_str);
1172261765Strasz	}
1173255570Strasz}
1174255570Strasz
1175264526Straszvoid
1176264530Straszkernel_accept(int *connection_id, int *portal_id,
1177264530Strasz    struct sockaddr *client_sa, socklen_t *client_salen)
1178255570Strasz{
1179255570Strasz	struct ctl_iscsi req;
1180264530Strasz	struct sockaddr_storage ss;
1181255570Strasz
1182255570Strasz	bzero(&req, sizeof(req));
1183255570Strasz
1184255570Strasz	req.type = CTL_ISCSI_ACCEPT;
1185264530Strasz	req.data.accept.initiator_addr = (struct sockaddr *)&ss;
1186255570Strasz
1187264526Strasz	if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1)
1188264526Strasz		log_err(1, "error issuing CTL_ISCSI ioctl");
1189255570Strasz
1190261765Strasz	if (req.status != CTL_ISCSI_OK) {
1191264526Strasz		log_errx(1, "error returned from CTL iSCSI accept: %s",
1192261765Strasz		    req.error_str);
1193261765Strasz	}
1194261765Strasz
1195264526Strasz	*connection_id = req.data.accept.connection_id;
1196264526Strasz	*portal_id = req.data.accept.portal_id;
1197264530Strasz	*client_salen = req.data.accept.initiator_addrlen;
1198264530Strasz	memcpy(client_sa, &ss, *client_salen);
1199255570Strasz}
1200255570Strasz
1201255570Straszvoid
1202255570Straszkernel_send(struct pdu *pdu)
1203255570Strasz{
1204255570Strasz	struct ctl_iscsi req;
1205255570Strasz
1206255570Strasz	bzero(&req, sizeof(req));
1207255570Strasz
1208255570Strasz	req.type = CTL_ISCSI_SEND;
1209255570Strasz	req.data.send.connection_id = pdu->pdu_connection->conn_socket;
1210255570Strasz	req.data.send.bhs = pdu->pdu_bhs;
1211255570Strasz	req.data.send.data_segment_len = pdu->pdu_data_len;
1212255570Strasz	req.data.send.data_segment = pdu->pdu_data;
1213255570Strasz
1214261765Strasz	if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) {
1215255570Strasz		log_err(1, "error issuing CTL_ISCSI ioctl; "
1216255570Strasz		    "dropping connection");
1217261765Strasz	}
1218255570Strasz
1219261765Strasz	if (req.status != CTL_ISCSI_OK) {
1220255570Strasz		log_errx(1, "error returned from CTL iSCSI send: "
1221255570Strasz		    "%s; dropping connection", req.error_str);
1222261765Strasz	}
1223255570Strasz}
1224255570Strasz
1225255570Straszvoid
1226255570Straszkernel_receive(struct pdu *pdu)
1227255570Strasz{
1228255570Strasz	struct ctl_iscsi req;
1229255570Strasz
1230255570Strasz	pdu->pdu_data = malloc(MAX_DATA_SEGMENT_LENGTH);
1231255570Strasz	if (pdu->pdu_data == NULL)
1232255570Strasz		log_err(1, "malloc");
1233255570Strasz
1234255570Strasz	bzero(&req, sizeof(req));
1235255570Strasz
1236255570Strasz	req.type = CTL_ISCSI_RECEIVE;
1237255570Strasz	req.data.receive.connection_id = pdu->pdu_connection->conn_socket;
1238255570Strasz	req.data.receive.bhs = pdu->pdu_bhs;
1239255570Strasz	req.data.receive.data_segment_len = MAX_DATA_SEGMENT_LENGTH;
1240255570Strasz	req.data.receive.data_segment = pdu->pdu_data;
1241255570Strasz
1242261765Strasz	if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) {
1243255570Strasz		log_err(1, "error issuing CTL_ISCSI ioctl; "
1244255570Strasz		    "dropping connection");
1245261765Strasz	}
1246255570Strasz
1247261765Strasz	if (req.status != CTL_ISCSI_OK) {
1248255570Strasz		log_errx(1, "error returned from CTL iSCSI receive: "
1249255570Strasz		    "%s; dropping connection", req.error_str);
1250261765Strasz	}
1251255570Strasz
1252255570Strasz}
1253255570Strasz
1254255570Strasz#endif /* ICL_KERNEL_PROXY */
1255255570Strasz
1256255570Strasz/*
1257255570Strasz * XXX: I CANT INTO LATIN
1258255570Strasz */
1259255570Straszvoid
1260255570Straszkernel_capsicate(void)
1261255570Strasz{
1262255570Strasz	int error;
1263255570Strasz	cap_rights_t rights;
1264255570Strasz	const unsigned long cmds[] = { CTL_ISCSI };
1265255570Strasz
1266255570Strasz	cap_rights_init(&rights, CAP_IOCTL);
1267255570Strasz	error = cap_rights_limit(ctl_fd, &rights);
1268255570Strasz	if (error != 0 && errno != ENOSYS)
1269255570Strasz		log_err(1, "cap_rights_limit");
1270255570Strasz
1271317062Saraujo	error = cap_ioctls_limit(ctl_fd, cmds, nitems(cmds));
1272317062Saraujo
1273255570Strasz	if (error != 0 && errno != ENOSYS)
1274255570Strasz		log_err(1, "cap_ioctls_limit");
1275255570Strasz
1276255570Strasz	error = cap_enter();
1277255570Strasz	if (error != 0 && errno != ENOSYS)
1278255570Strasz		log_err(1, "cap_enter");
1279255570Strasz
1280255570Strasz	if (cap_sandboxed())
1281255570Strasz		log_debugx("Capsicum capability mode enabled");
1282255570Strasz	else
1283255570Strasz		log_warnx("Capsicum capability mode not supported");
1284255570Strasz}
1285255570Strasz
1286