kernel.c revision 255570
1141414Snjl/*-
2141414Snjl * Copyright (c) 2003, 2004 Silicon Graphics International Corp.
3141414Snjl * Copyright (c) 1997-2007 Kenneth D. Merry
4141414Snjl * Copyright (c) 2012 The FreeBSD Foundation
5141414Snjl * All rights reserved.
6141414Snjl *
7141414Snjl * Portions of this software were developed by Edward Tomasz Napierala
8141414Snjl * under sponsorship from the FreeBSD Foundation.
9141414Snjl *
10141414Snjl * Redistribution and use in source and binary forms, with or without
11141414Snjl * modification, are permitted provided that the following conditions
12141414Snjl * are met:
13141414Snjl * 1. Redistributions of source code must retain the above copyright
14141414Snjl *    notice, this list of conditions, and the following disclaimer,
15141414Snjl *    without modification.
16141414Snjl * 2. Redistributions in binary form must reproduce at minimum a disclaimer
17141414Snjl *    substantially similar to the "NO WARRANTY" disclaimer below
18141414Snjl *    ("Disclaimer") and any redistribution must be conditioned upon
19141414Snjl *    including a substantially similar Disclaimer requirement for further
20141414Snjl *    binary redistribution.
21141414Snjl *
22141414Snjl * NO WARRANTY
23141414Snjl * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24141414Snjl * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25141414Snjl * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
26141414Snjl * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27141414Snjl * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28141414Snjl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29141414Snjl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30141414Snjl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31141414Snjl * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
32141414Snjl * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33141414Snjl * POSSIBILITY OF SUCH DAMAGES.
34141414Snjl *
35141414Snjl * $FreeBSD: head/usr.sbin/ctld/kernel.c 255570 2013-09-14 15:29:06Z trasz $
36141414Snjl */
37141414Snjl
38141414Snjl#include <sys/ioctl.h>
39141414Snjl#include <sys/types.h>
40141414Snjl#include <sys/stat.h>
41141414Snjl#include <sys/param.h>
42141414Snjl#include <sys/linker.h>
43141414Snjl#include <sys/queue.h>
44141414Snjl#include <sys/callout.h>
45141414Snjl#include <sys/sbuf.h>
46141414Snjl#include <sys/capability.h>
47141414Snjl#include <assert.h>
48141414Snjl#include <bsdxml.h>
49141414Snjl#include <ctype.h>
50141414Snjl#include <errno.h>
51141414Snjl#include <fcntl.h>
52141414Snjl#include <stdint.h>
53141414Snjl#include <stdio.h>
54141414Snjl#include <stdlib.h>
55141414Snjl#include <string.h>
56141414Snjl#include <strings.h>
57141414Snjl#include <cam/scsi/scsi_all.h>
58141414Snjl#include <cam/scsi/scsi_message.h>
59141414Snjl#include <cam/ctl/ctl.h>
60141414Snjl#include <cam/ctl/ctl_io.h>
61141414Snjl#include <cam/ctl/ctl_frontend_internal.h>
62141414Snjl#include <cam/ctl/ctl_backend.h>
63141780Snjl#include <cam/ctl/ctl_ioctl.h>
64141414Snjl#include <cam/ctl/ctl_backend_block.h>
65141414Snjl#include <cam/ctl/ctl_util.h>
66141414Snjl#include <cam/ctl/ctl_scsi_all.h>
67141414Snjl
68141414Snjl#ifdef ICL_KERNEL_PROXY
69141414Snjl#include <netdb.h>
70141414Snjl#endif
71141414Snjl
72141414Snjl#include "ctld.h"
73141414Snjl
74141414Snjlstatic int	ctl_fd = 0;
75141414Snjl
76141414Snjlvoid
77141414Snjlkernel_init(void)
78141414Snjl{
79141414Snjl	int retval, saved_errno;
80141414Snjl
81141414Snjl	ctl_fd = open(CTL_DEFAULT_DEV, O_RDWR);
82141414Snjl	if (ctl_fd < 0) {
83141414Snjl		saved_errno = errno;
84141414Snjl		retval = kldload("ctl");
85141414Snjl		if (retval != -1)
86141414Snjl			ctl_fd = open(CTL_DEFAULT_DEV, O_RDWR);
87141414Snjl		else
88141414Snjl			errno = saved_errno;
89141414Snjl	}
90141414Snjl	if (ctl_fd < 0)
91141414Snjl		log_err(1, "failed to open %s", CTL_DEFAULT_DEV);
92141414Snjl}
93141414Snjl
94141414Snjl/*
95141414Snjl * Name/value pair used for per-LUN attributes.
96141414Snjl */
97141414Snjlstruct cctl_lun_nv {
98141414Snjl	char *name;
99141414Snjl	char *value;
100142032Snjl	STAILQ_ENTRY(cctl_lun_nv) links;
101141414Snjl};
102141414Snjl
103142032Snjl/*
104141414Snjl * Backend LUN information.
105141414Snjl */
106141414Snjlstruct cctl_lun {
107141414Snjl	uint64_t lun_id;
108141414Snjl	char *backend_type;
109141414Snjl	uint64_t size_blocks;
110141414Snjl	uint32_t blocksize;
111141414Snjl	char *serial_number;
112141414Snjl	char *device_id;
113141414Snjl	char *cfiscsi_target;
114142032Snjl	char *cfiscsi_target_alias;
115141414Snjl	int cfiscsi_lun;
116141414Snjl	STAILQ_HEAD(,cctl_lun_nv) attr_list;
117141414Snjl	STAILQ_ENTRY(cctl_lun) links;
118141414Snjl};
119141414Snjl
120141414Snjlstruct cctl_devlist_data {
121141414Snjl	int num_luns;
122141414Snjl	STAILQ_HEAD(,cctl_lun) lun_list;
123141414Snjl	struct cctl_lun *cur_lun;
124141414Snjl	int level;
125141414Snjl	struct sbuf *cur_sb[32];
126141414Snjl};
127141414Snjl
128141414Snjlstatic void
129141414Snjlcctl_start_element(void *user_data, const char *name, const char **attr)
130141414Snjl{
131141414Snjl	int i;
132141780Snjl	struct cctl_devlist_data *devlist;
133141780Snjl	struct cctl_lun *cur_lun;
134141780Snjl
135141414Snjl	devlist = (struct cctl_devlist_data *)user_data;
136141414Snjl	cur_lun = devlist->cur_lun;
137141780Snjl	devlist->level++;
138141414Snjl	if ((u_int)devlist->level > (sizeof(devlist->cur_sb) /
139141414Snjl	    sizeof(devlist->cur_sb[0])))
140141414Snjl		log_errx(1, "%s: too many nesting levels, %zd max", __func__,
141141780Snjl		     sizeof(devlist->cur_sb) / sizeof(devlist->cur_sb[0]));
142141780Snjl
143141414Snjl	devlist->cur_sb[devlist->level] = sbuf_new_auto();
144141414Snjl	if (devlist->cur_sb[devlist->level] == NULL)
145141414Snjl		log_err(1, "%s: unable to allocate sbuf", __func__);
146141414Snjl
147141780Snjl	if (strcmp(name, "lun") == 0) {
148141780Snjl		if (cur_lun != NULL)
149141780Snjl			log_errx(1, "%s: improper lun element nesting",
150141780Snjl			    __func__);
151141780Snjl
152141780Snjl		cur_lun = calloc(1, sizeof(*cur_lun));
153141780Snjl		if (cur_lun == NULL)
154141780Snjl			log_err(1, "%s: cannot allocate %zd bytes", __func__,
155141780Snjl			    sizeof(*cur_lun));
156141780Snjl
157141780Snjl		devlist->num_luns++;
158141780Snjl		devlist->cur_lun = cur_lun;
159141780Snjl
160141780Snjl		STAILQ_INIT(&cur_lun->attr_list);
161141780Snjl		STAILQ_INSERT_TAIL(&devlist->lun_list, cur_lun, links);
162141780Snjl
163141414Snjl		for (i = 0; attr[i] != NULL; i += 2) {
164141414Snjl			if (strcmp(attr[i], "id") == 0) {
165141414Snjl				cur_lun->lun_id = strtoull(attr[i+1], NULL, 0);
166141414Snjl			} else {
167141414Snjl				log_errx(1, "%s: invalid LUN attribute %s = %s",
168141414Snjl				     __func__, attr[i], attr[i+1]);
169141414Snjl			}
170141414Snjl		}
171141414Snjl	}
172141414Snjl}
173141414Snjl
174141414Snjlstatic void
175141414Snjlcctl_end_element(void *user_data, const char *name)
176141414Snjl{
177141414Snjl	struct cctl_devlist_data *devlist;
178141780Snjl	struct cctl_lun *cur_lun;
179141414Snjl	char *str;
180141780Snjl
181141414Snjl	devlist = (struct cctl_devlist_data *)user_data;
182141414Snjl	cur_lun = devlist->cur_lun;
183141414Snjl
184141414Snjl	if ((cur_lun == NULL)
185141414Snjl	 && (strcmp(name, "ctllunlist") != 0))
186141414Snjl		log_errx(1, "%s: cur_lun == NULL! (name = %s)", __func__, name);
187141414Snjl
188141414Snjl	if (devlist->cur_sb[devlist->level] == NULL)
189141414Snjl		log_errx(1, "%s: no valid sbuf at level %d (name %s)", __func__,
190141414Snjl		     devlist->level, name);
191141414Snjl
192141414Snjl	sbuf_finish(devlist->cur_sb[devlist->level]);
193141414Snjl	str = checked_strdup(sbuf_data(devlist->cur_sb[devlist->level]));
194141414Snjl
195141414Snjl	if (strlen(str) == 0) {
196141414Snjl		free(str);
197141414Snjl		str = NULL;
198141414Snjl	}
199141414Snjl
200141414Snjl	sbuf_delete(devlist->cur_sb[devlist->level]);
201141414Snjl	devlist->cur_sb[devlist->level] = NULL;
202141414Snjl	devlist->level--;
203141780Snjl
204141780Snjl	if (strcmp(name, "backend_type") == 0) {
205141780Snjl		cur_lun->backend_type = str;
206141780Snjl		str = NULL;
207141780Snjl	} else if (strcmp(name, "size") == 0) {
208141780Snjl		cur_lun->size_blocks = strtoull(str, NULL, 0);
209141780Snjl	} else if (strcmp(name, "blocksize") == 0) {
210141780Snjl		cur_lun->blocksize = strtoul(str, NULL, 0);
211141414Snjl	} else if (strcmp(name, "serial_number") == 0) {
212141414Snjl		cur_lun->serial_number = str;
213141414Snjl		str = NULL;
214141414Snjl	} else if (strcmp(name, "device_id") == 0) {
215141414Snjl		cur_lun->device_id = str;
216141414Snjl		str = NULL;
217141414Snjl	} else if (strcmp(name, "cfiscsi_target") == 0) {
218141414Snjl		cur_lun->cfiscsi_target = str;
219141414Snjl		str = NULL;
220141414Snjl	} else if (strcmp(name, "cfiscsi_target_alias") == 0) {
221141414Snjl		cur_lun->cfiscsi_target_alias = str;
222141414Snjl		str = NULL;
223141414Snjl	} else if (strcmp(name, "cfiscsi_lun") == 0) {
224141414Snjl		cur_lun->cfiscsi_lun = strtoul(str, NULL, 0);
225141414Snjl	} else if (strcmp(name, "lun") == 0) {
226141414Snjl		devlist->cur_lun = NULL;
227141414Snjl	} else if (strcmp(name, "ctllunlist") == 0) {
228141414Snjl
229141414Snjl	} else {
230141414Snjl		struct cctl_lun_nv *nv;
231141414Snjl
232141414Snjl		nv = calloc(1, sizeof(*nv));
233141414Snjl		if (nv == NULL)
234141414Snjl			log_err(1, "%s: can't allocate %zd bytes for nv pair",
235141414Snjl			    __func__, sizeof(*nv));
236141414Snjl
237141414Snjl		nv->name = checked_strdup(name);
238141414Snjl
239141414Snjl		nv->value = str;
240141414Snjl		str = NULL;
241141414Snjl		STAILQ_INSERT_TAIL(&cur_lun->attr_list, nv, links);
242141414Snjl	}
243141414Snjl
244141414Snjl	free(str);
245141414Snjl}
246141414Snjl
247141414Snjlstatic void
248141414Snjlcctl_char_handler(void *user_data, const XML_Char *str, int len)
249141414Snjl{
250141414Snjl	struct cctl_devlist_data *devlist;
251141414Snjl
252141414Snjl	devlist = (struct cctl_devlist_data *)user_data;
253141414Snjl
254141414Snjl	sbuf_bcat(devlist->cur_sb[devlist->level], str, len);
255141414Snjl}
256141414Snjl
257141414Snjlstruct conf *
258141414Snjlconf_new_from_kernel(void)
259141414Snjl{
260141414Snjl	struct conf *conf = NULL;
261141414Snjl	struct target *targ;
262141414Snjl	struct lun *cl;
263141414Snjl	struct lun_option *lo;
264141414Snjl	struct ctl_lun_list list;
265141414Snjl	struct cctl_devlist_data devlist;
266141414Snjl	struct cctl_lun *lun;
267141414Snjl	XML_Parser parser;
268141414Snjl	char *lun_str = NULL;
269141414Snjl	int lun_len;
270141414Snjl	int retval;
271141414Snjl
272141414Snjl	lun_len = 4096;
273141414Snjl
274141414Snjl	bzero(&devlist, sizeof(devlist));
275141414Snjl	STAILQ_INIT(&devlist.lun_list);
276141414Snjl
277141414Snjl	log_debugx("obtaining previously configured CTL luns from the kernel");
278141414Snjl
279141414Snjlretry:
280141414Snjl	lun_str = realloc(lun_str, lun_len);
281141414Snjl	if (lun_str == NULL)
282141414Snjl		log_err(1, "realloc");
283141414Snjl
284141414Snjl	bzero(&list, sizeof(list));
285141414Snjl	list.alloc_len = lun_len;
286141414Snjl	list.status = CTL_LUN_LIST_NONE;
287141414Snjl	list.lun_xml = lun_str;
288141414Snjl
289141414Snjl	if (ioctl(ctl_fd, CTL_LUN_LIST, &list) == -1) {
290141414Snjl		log_warn("error issuing CTL_LUN_LIST ioctl");
291141414Snjl		free(lun_str);
292141414Snjl		return (NULL);
293141414Snjl	}
294141414Snjl
295141414Snjl	if (list.status == CTL_LUN_LIST_ERROR) {
296141414Snjl		log_warnx("error returned from CTL_LUN_LIST ioctl: %s",
297141414Snjl		    list.error_str);
298141414Snjl		free(lun_str);
299141414Snjl		return (NULL);
300141414Snjl	}
301141414Snjl
302141414Snjl	if (list.status == CTL_LUN_LIST_NEED_MORE_SPACE) {
303141414Snjl		lun_len = lun_len << 1;
304141414Snjl		goto retry;
305141414Snjl	}
306141414Snjl
307141414Snjl	parser = XML_ParserCreate(NULL);
308141414Snjl	if (parser == NULL) {
309141414Snjl		log_warnx("unable to create XML parser");
310141414Snjl		free(lun_str);
311141414Snjl		return (NULL);
312141414Snjl	}
313141414Snjl
314141414Snjl	XML_SetUserData(parser, &devlist);
315141414Snjl	XML_SetElementHandler(parser, cctl_start_element, cctl_end_element);
316141414Snjl	XML_SetCharacterDataHandler(parser, cctl_char_handler);
317141414Snjl
318141414Snjl	retval = XML_Parse(parser, lun_str, strlen(lun_str), 1);
319141414Snjl	XML_ParserFree(parser);
320141414Snjl	free(lun_str);
321141414Snjl	if (retval != 1) {
322141414Snjl		log_warnx("XML_Parse failed");
323141414Snjl		return (NULL);
324141414Snjl	}
325142032Snjl
326141414Snjl	conf = conf_new();
327141414Snjl
328141414Snjl	STAILQ_FOREACH(lun, &devlist.lun_list, links) {
329141414Snjl		struct cctl_lun_nv *nv;
330141414Snjl
331141414Snjl		if (lun->cfiscsi_target == NULL) {
332141414Snjl			log_debugx("CTL lun %ju wasn't managed by ctld; "
333141414Snjl			    "ignoring", (uintmax_t)lun->lun_id);
334142003Snjl			continue;
335141414Snjl		}
336141414Snjl
337141414Snjl		targ = target_find(conf, lun->cfiscsi_target);
338141414Snjl		if (targ == NULL) {
339141414Snjl#if 0
340141414Snjl			log_debugx("found new kernel target %s for CTL lun %ld",
341141414Snjl			    lun->cfiscsi_target, lun->lun_id);
342141414Snjl#endif
343141414Snjl			targ = target_new(conf, lun->cfiscsi_target);
344141414Snjl			if (targ == NULL) {
345141414Snjl				log_warnx("target_new failed");
346141414Snjl				continue;
347141414Snjl			}
348141414Snjl		}
349141414Snjl
350141414Snjl		cl = lun_find(targ, lun->cfiscsi_lun);
351141414Snjl		if (cl != NULL) {
352141414Snjl			log_warnx("found CTL lun %ju, backing lun %d, target "
353141414Snjl			    "%s, also backed by CTL lun %d; ignoring",
354141414Snjl			    (uintmax_t) lun->lun_id, cl->l_lun,
355141414Snjl			    cl->l_target->t_iqn, cl->l_ctl_lun);
356141414Snjl			continue;
357141414Snjl		}
358141414Snjl
359141414Snjl		log_debugx("found CTL lun %ju, backing lun %d, target %s",
360141414Snjl		    (uintmax_t)lun->lun_id, lun->cfiscsi_lun, lun->cfiscsi_target);
361141414Snjl
362141414Snjl		cl = lun_new(targ, lun->cfiscsi_lun);
363141414Snjl		if (cl == NULL) {
364141414Snjl			log_warnx("lun_new failed");
365141414Snjl			continue;
366141414Snjl		}
367141780Snjl		lun_set_backend(cl, lun->backend_type);
368141414Snjl		lun_set_blocksize(cl, lun->blocksize);
369141414Snjl		lun_set_device_id(cl, lun->device_id);
370141414Snjl		lun_set_serial(cl, lun->serial_number);
371141414Snjl		lun_set_size(cl, lun->size_blocks * cl->l_blocksize);
372141414Snjl		lun_set_ctl_lun(cl, lun->lun_id);
373141414Snjl
374141414Snjl		STAILQ_FOREACH(nv, &lun->attr_list, links) {
375141414Snjl			if (strcmp(nv->name, "file") == 0 ||
376141414Snjl			    strcmp(nv->name, "dev") == 0) {
377141414Snjl				lun_set_path(cl, nv->value);
378141414Snjl				continue;
379141414Snjl			}
380141414Snjl			lo = lun_option_new(cl, nv->name, nv->value);
381141414Snjl			if (lo == NULL)
382141414Snjl				log_warnx("unable to add CTL lun option %s "
383141414Snjl				    "for CTL lun %ju for lun %d, target %s",
384141414Snjl				    nv->name, (uintmax_t) lun->lun_id,
385141414Snjl				    cl->l_lun, cl->l_target->t_iqn);
386141414Snjl		}
387141780Snjl	}
388141414Snjl
389141414Snjl	return (conf);
390141414Snjl}
391141414Snjl
392141414Snjlint
393141414Snjlkernel_lun_add(struct lun *lun)
394141414Snjl{
395141414Snjl	struct lun_option *lo;
396141414Snjl	struct ctl_lun_req req;
397141414Snjl	char *tmp;
398141414Snjl	int error, i, num_options;
399141414Snjl
400141414Snjl	bzero(&req, sizeof(req));
401141414Snjl
402141414Snjl	strlcpy(req.backend, lun->l_backend, sizeof(req.backend));
403141414Snjl	req.reqtype = CTL_LUNREQ_CREATE;
404141414Snjl
405141780Snjl	req.reqdata.create.blocksize_bytes = lun->l_blocksize;
406141414Snjl
407141414Snjl	if (lun->l_size != 0)
408141414Snjl		req.reqdata.create.lun_size_bytes = lun->l_size;
409141414Snjl
410141414Snjl	req.reqdata.create.flags |= CTL_LUN_FLAG_DEV_TYPE;
411141414Snjl	req.reqdata.create.device_type = T_DIRECT;
412141414Snjl
413142032Snjl	if (lun->l_serial != NULL) {
414142032Snjl		strlcpy(req.reqdata.create.serial_num, lun->l_serial,
415142032Snjl			sizeof(req.reqdata.create.serial_num));
416142032Snjl		req.reqdata.create.flags |= CTL_LUN_FLAG_SERIAL_NUM;
417142032Snjl	}
418142032Snjl
419142032Snjl	if (lun->l_device_id != NULL) {
420142032Snjl		strlcpy(req.reqdata.create.device_id, lun->l_device_id,
421142032Snjl			sizeof(req.reqdata.create.device_id));
422142032Snjl		req.reqdata.create.flags |= CTL_LUN_FLAG_DEVID;
423142032Snjl	}
424
425	if (lun->l_path != NULL) {
426		lo = lun_option_find(lun, "file");
427		if (lo != NULL) {
428			lun_option_set(lo, lun->l_path);
429		} else {
430			lo = lun_option_new(lun, "file", lun->l_path);
431			assert(lo != NULL);
432		}
433	}
434
435	lo = lun_option_find(lun, "cfiscsi_target");
436	if (lo != NULL) {
437		lun_option_set(lo, lun->l_target->t_iqn);
438	} else {
439		lo = lun_option_new(lun, "cfiscsi_target",
440		    lun->l_target->t_iqn);
441		assert(lo != NULL);
442	}
443
444	if (lun->l_target->t_alias != NULL) {
445		lo = lun_option_find(lun, "cfiscsi_target_alias");
446		if (lo != NULL) {
447			lun_option_set(lo, lun->l_target->t_alias);
448		} else {
449			lo = lun_option_new(lun, "cfiscsi_target_alias",
450			    lun->l_target->t_alias);
451			assert(lo != NULL);
452		}
453	}
454
455	asprintf(&tmp, "%d", lun->l_lun);
456	if (tmp == NULL)
457		log_errx(1, "asprintf");
458	lo = lun_option_find(lun, "cfiscsi_lun");
459	if (lo != NULL) {
460		lun_option_set(lo, tmp);
461		free(tmp);
462	} else {
463		lo = lun_option_new(lun, "cfiscsi_lun", tmp);
464		free(tmp);
465		assert(lo != NULL);
466	}
467
468	num_options = 0;
469	TAILQ_FOREACH(lo, &lun->l_options, lo_next)
470		num_options++;
471
472	req.num_be_args = num_options;
473	if (num_options > 0) {
474		req.be_args = malloc(num_options * sizeof(*req.be_args));
475		if (req.be_args == NULL) {
476			log_warn("error allocating %zd bytes",
477			    num_options * sizeof(*req.be_args));
478			return (1);
479		}
480
481		i = 0;
482		TAILQ_FOREACH(lo, &lun->l_options, lo_next) {
483			 /*
484			  * +1 for the terminating '\0'
485			  */
486			req.be_args[i].namelen = strlen(lo->lo_name) + 1;
487			req.be_args[i].name = lo->lo_name;
488			req.be_args[i].vallen = strlen(lo->lo_value) + 1;
489			req.be_args[i].value = lo->lo_value;
490			req.be_args[i].flags = CTL_BEARG_ASCII | CTL_BEARG_RD;
491			i++;
492		}
493		assert(i == num_options);
494	}
495
496	error = ioctl(ctl_fd, CTL_LUN_REQ, &req);
497	free(req.be_args);
498	if (error != 0) {
499		log_warn("error issuing CTL_LUN_REQ ioctl");
500		return (1);
501	}
502
503	if (req.status == CTL_LUN_ERROR) {
504		log_warnx("error returned from LUN creation request: %s",
505		    req.error_str);
506		return (1);
507	}
508
509	if (req.status != CTL_LUN_OK) {
510		log_warnx("unknown LUN creation request status %d",
511		    req.status);
512		return (1);
513	}
514
515	lun_set_ctl_lun(lun, req.reqdata.create.req_lun_id);
516
517	return (0);
518}
519
520int
521kernel_lun_resize(struct lun *lun)
522{
523	struct ctl_lun_req req;
524
525	bzero(&req, sizeof(req));
526
527	strlcpy(req.backend, lun->l_backend, sizeof(req.backend));
528	req.reqtype = CTL_LUNREQ_MODIFY;
529
530	req.reqdata.modify.lun_id = lun->l_ctl_lun;
531	req.reqdata.modify.lun_size_bytes = lun->l_size;
532
533	if (ioctl(ctl_fd, CTL_LUN_REQ, &req) == -1) {
534		log_warn("error issuing CTL_LUN_REQ ioctl");
535		return (1);
536	}
537
538	if (req.status == CTL_LUN_ERROR) {
539		log_warnx("error returned from LUN modification request: %s",
540		    req.error_str);
541		return (1);
542	}
543
544	if (req.status != CTL_LUN_OK) {
545		log_warnx("unknown LUN modification request status %d",
546		    req.status);
547		return (1);
548	}
549
550	return (0);
551}
552
553int
554kernel_lun_remove(struct lun *lun)
555{
556	struct ctl_lun_req req;
557
558	bzero(&req, sizeof(req));
559
560	strlcpy(req.backend, lun->l_backend, sizeof(req.backend));
561	req.reqtype = CTL_LUNREQ_RM;
562
563	req.reqdata.rm.lun_id = lun->l_ctl_lun;
564
565	if (ioctl(ctl_fd, CTL_LUN_REQ, &req) == -1) {
566		log_warn("error issuing CTL_LUN_REQ ioctl");
567		return (1);
568	}
569
570	if (req.status == CTL_LUN_ERROR) {
571		log_warnx("error returned from LUN removal request: %s",
572		    req.error_str);
573		return (1);
574	}
575
576	if (req.status != CTL_LUN_OK) {
577		log_warnx("unknown LUN removal request status %d", req.status);
578		return (1);
579	}
580
581	return (0);
582}
583
584void
585kernel_handoff(struct connection *conn)
586{
587	struct ctl_iscsi req;
588
589	bzero(&req, sizeof(req));
590
591	req.type = CTL_ISCSI_HANDOFF;
592	strlcpy(req.data.handoff.initiator_name,
593	    conn->conn_initiator_name, sizeof(req.data.handoff.initiator_name));
594	strlcpy(req.data.handoff.initiator_addr,
595	    conn->conn_initiator_addr, sizeof(req.data.handoff.initiator_addr));
596	if (conn->conn_initiator_alias != NULL) {
597		strlcpy(req.data.handoff.initiator_alias,
598		    conn->conn_initiator_alias, sizeof(req.data.handoff.initiator_alias));
599	}
600	strlcpy(req.data.handoff.target_name,
601	    conn->conn_target->t_iqn, sizeof(req.data.handoff.target_name));
602	req.data.handoff.socket = conn->conn_socket;
603	req.data.handoff.portal_group_tag =
604	    conn->conn_portal->p_portal_group->pg_tag;
605	if (conn->conn_header_digest == CONN_DIGEST_CRC32C)
606		req.data.handoff.header_digest = CTL_ISCSI_DIGEST_CRC32C;
607	if (conn->conn_data_digest == CONN_DIGEST_CRC32C)
608		req.data.handoff.data_digest = CTL_ISCSI_DIGEST_CRC32C;
609	req.data.handoff.cmdsn = conn->conn_cmdsn;
610	req.data.handoff.statsn = conn->conn_statsn;
611	req.data.handoff.max_recv_data_segment_length =
612	    conn->conn_max_data_segment_length;
613	req.data.handoff.max_burst_length = conn->conn_max_burst_length;
614	req.data.handoff.immediate_data = conn->conn_immediate_data;
615
616	if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1)
617		log_err(1, "error issuing CTL_ISCSI ioctl; "
618		    "dropping connection");
619
620	if (req.status != CTL_ISCSI_OK)
621		log_errx(1, "error returned from CTL iSCSI handoff request: "
622		    "%s; dropping connection", req.error_str);
623}
624
625int
626kernel_port_on(void)
627{
628	struct ctl_port_entry entry;
629	int error;
630
631	bzero(&entry, sizeof(&entry));
632
633	entry.port_type = CTL_PORT_ISCSI;
634	entry.targ_port = -1;
635
636	error = ioctl(ctl_fd, CTL_ENABLE_PORT, &entry);
637	if (error != 0) {
638		log_warn("CTL_ENABLE_PORT ioctl failed");
639		return (-1);
640	}
641
642	return (0);
643}
644
645int
646kernel_port_off(void)
647{
648	struct ctl_port_entry entry;
649	int error;
650
651	bzero(&entry, sizeof(&entry));
652
653	entry.port_type = CTL_PORT_ISCSI;
654	entry.targ_port = -1;
655
656	error = ioctl(ctl_fd, CTL_DISABLE_PORT, &entry);
657	if (error != 0) {
658		log_warn("CTL_DISABLE_PORT ioctl failed");
659		return (-1);
660	}
661
662	return (0);
663}
664
665#ifdef ICL_KERNEL_PROXY
666void
667kernel_listen(struct addrinfo *ai, bool iser)
668{
669	struct ctl_iscsi req;
670
671	bzero(&req, sizeof(req));
672
673	req.type = CTL_ISCSI_LISTEN;
674	req.data.listen.iser = iser;
675	req.data.listen.domain = ai->ai_family;
676	req.data.listen.socktype = ai->ai_socktype;
677	req.data.listen.protocol = ai->ai_protocol;
678	req.data.listen.addr = ai->ai_addr;
679	req.data.listen.addrlen = ai->ai_addrlen;
680
681	if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1)
682		log_warn("error issuing CTL_ISCSI_LISTEN ioctl");
683}
684
685int
686kernel_accept(void)
687{
688	struct ctl_iscsi req;
689
690	bzero(&req, sizeof(req));
691
692	req.type = CTL_ISCSI_ACCEPT;
693
694	if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) {
695		log_warn("error issuing CTL_ISCSI_LISTEN ioctl");
696		return (0);
697	}
698
699	return (req.data.accept.connection_id);
700}
701
702void
703kernel_send(struct pdu *pdu)
704{
705	struct ctl_iscsi req;
706
707	bzero(&req, sizeof(req));
708
709	req.type = CTL_ISCSI_SEND;
710	req.data.send.connection_id = pdu->pdu_connection->conn_socket;
711	req.data.send.bhs = pdu->pdu_bhs;
712	req.data.send.data_segment_len = pdu->pdu_data_len;
713	req.data.send.data_segment = pdu->pdu_data;
714
715	if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1)
716		log_err(1, "error issuing CTL_ISCSI ioctl; "
717		    "dropping connection");
718
719	if (req.status != CTL_ISCSI_OK)
720		log_errx(1, "error returned from CTL iSCSI send: "
721		    "%s; dropping connection", req.error_str);
722}
723
724void
725kernel_receive(struct pdu *pdu)
726{
727	struct ctl_iscsi req;
728
729	pdu->pdu_data = malloc(MAX_DATA_SEGMENT_LENGTH);
730	if (pdu->pdu_data == NULL)
731		log_err(1, "malloc");
732
733	bzero(&req, sizeof(req));
734
735	req.type = CTL_ISCSI_RECEIVE;
736	req.data.receive.connection_id = pdu->pdu_connection->conn_socket;
737	req.data.receive.bhs = pdu->pdu_bhs;
738	req.data.receive.data_segment_len = MAX_DATA_SEGMENT_LENGTH;
739	req.data.receive.data_segment = pdu->pdu_data;
740
741	if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1)
742		log_err(1, "error issuing CTL_ISCSI ioctl; "
743		    "dropping connection");
744
745	if (req.status != CTL_ISCSI_OK)
746		log_errx(1, "error returned from CTL iSCSI receive: "
747		    "%s; dropping connection", req.error_str);
748
749}
750
751#endif /* ICL_KERNEL_PROXY */
752
753/*
754 * XXX: I CANT INTO LATIN
755 */
756void
757kernel_capsicate(void)
758{
759	int error;
760	cap_rights_t rights;
761	const unsigned long cmds[] = { CTL_ISCSI };
762
763	cap_rights_init(&rights, CAP_IOCTL);
764	error = cap_rights_limit(ctl_fd, &rights);
765	if (error != 0 && errno != ENOSYS)
766		log_err(1, "cap_rights_limit");
767
768	error = cap_ioctls_limit(ctl_fd, cmds,
769	    sizeof(cmds) / sizeof(cmds[0]));
770	if (error != 0 && errno != ENOSYS)
771		log_err(1, "cap_ioctls_limit");
772
773	error = cap_enter();
774	if (error != 0 && errno != ENOSYS)
775		log_err(1, "cap_enter");
776
777	if (cap_sandboxed())
778		log_debugx("Capsicum capability mode enabled");
779	else
780		log_warnx("Capsicum capability mode not supported");
781}
782
783