kernel.c revision 255665
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 * $FreeBSD: head/usr.sbin/ctld/kernel.c 255665 2013-09-18 08:37:14Z trasz $ 36255570Strasz */ 37255570Strasz 38255570Strasz#include <sys/ioctl.h> 39255570Strasz#include <sys/types.h> 40255570Strasz#include <sys/stat.h> 41255570Strasz#include <sys/param.h> 42255570Strasz#include <sys/linker.h> 43255570Strasz#include <sys/queue.h> 44255570Strasz#include <sys/callout.h> 45255570Strasz#include <sys/sbuf.h> 46255570Strasz#include <sys/capability.h> 47255570Strasz#include <assert.h> 48255570Strasz#include <bsdxml.h> 49255570Strasz#include <ctype.h> 50255570Strasz#include <errno.h> 51255570Strasz#include <fcntl.h> 52255570Strasz#include <stdint.h> 53255570Strasz#include <stdio.h> 54255570Strasz#include <stdlib.h> 55255570Strasz#include <string.h> 56255570Strasz#include <strings.h> 57255570Strasz#include <cam/scsi/scsi_all.h> 58255570Strasz#include <cam/scsi/scsi_message.h> 59255570Strasz#include <cam/ctl/ctl.h> 60255570Strasz#include <cam/ctl/ctl_io.h> 61255570Strasz#include <cam/ctl/ctl_frontend_internal.h> 62255570Strasz#include <cam/ctl/ctl_backend.h> 63255570Strasz#include <cam/ctl/ctl_ioctl.h> 64255570Strasz#include <cam/ctl/ctl_backend_block.h> 65255570Strasz#include <cam/ctl/ctl_util.h> 66255570Strasz#include <cam/ctl/ctl_scsi_all.h> 67255570Strasz 68255570Strasz#ifdef ICL_KERNEL_PROXY 69255570Strasz#include <netdb.h> 70255570Strasz#endif 71255570Strasz 72255570Strasz#include "ctld.h" 73255570Strasz 74255570Straszstatic int ctl_fd = 0; 75255570Strasz 76255570Straszvoid 77255570Straszkernel_init(void) 78255570Strasz{ 79255570Strasz int retval, saved_errno; 80255570Strasz 81255570Strasz ctl_fd = open(CTL_DEFAULT_DEV, O_RDWR); 82255665Strasz if (ctl_fd < 0 && errno == ENOENT) { 83255570Strasz saved_errno = errno; 84255570Strasz retval = kldload("ctl"); 85255570Strasz if (retval != -1) 86255570Strasz ctl_fd = open(CTL_DEFAULT_DEV, O_RDWR); 87255570Strasz else 88255570Strasz errno = saved_errno; 89255570Strasz } 90255570Strasz if (ctl_fd < 0) 91255570Strasz log_err(1, "failed to open %s", CTL_DEFAULT_DEV); 92255570Strasz} 93255570Strasz 94255570Strasz/* 95255570Strasz * Name/value pair used for per-LUN attributes. 96255570Strasz */ 97255570Straszstruct cctl_lun_nv { 98255570Strasz char *name; 99255570Strasz char *value; 100255570Strasz STAILQ_ENTRY(cctl_lun_nv) links; 101255570Strasz}; 102255570Strasz 103255570Strasz/* 104255570Strasz * Backend LUN information. 105255570Strasz */ 106255570Straszstruct cctl_lun { 107255570Strasz uint64_t lun_id; 108255570Strasz char *backend_type; 109255570Strasz uint64_t size_blocks; 110255570Strasz uint32_t blocksize; 111255570Strasz char *serial_number; 112255570Strasz char *device_id; 113255570Strasz char *cfiscsi_target; 114255570Strasz char *cfiscsi_target_alias; 115255570Strasz int cfiscsi_lun; 116255570Strasz STAILQ_HEAD(,cctl_lun_nv) attr_list; 117255570Strasz STAILQ_ENTRY(cctl_lun) links; 118255570Strasz}; 119255570Strasz 120255570Straszstruct cctl_devlist_data { 121255570Strasz int num_luns; 122255570Strasz STAILQ_HEAD(,cctl_lun) lun_list; 123255570Strasz struct cctl_lun *cur_lun; 124255570Strasz int level; 125255570Strasz struct sbuf *cur_sb[32]; 126255570Strasz}; 127255570Strasz 128255570Straszstatic void 129255570Straszcctl_start_element(void *user_data, const char *name, const char **attr) 130255570Strasz{ 131255570Strasz int i; 132255570Strasz struct cctl_devlist_data *devlist; 133255570Strasz struct cctl_lun *cur_lun; 134255570Strasz 135255570Strasz devlist = (struct cctl_devlist_data *)user_data; 136255570Strasz cur_lun = devlist->cur_lun; 137255570Strasz devlist->level++; 138255570Strasz if ((u_int)devlist->level > (sizeof(devlist->cur_sb) / 139255570Strasz sizeof(devlist->cur_sb[0]))) 140255570Strasz log_errx(1, "%s: too many nesting levels, %zd max", __func__, 141255570Strasz sizeof(devlist->cur_sb) / sizeof(devlist->cur_sb[0])); 142255570Strasz 143255570Strasz devlist->cur_sb[devlist->level] = sbuf_new_auto(); 144255570Strasz if (devlist->cur_sb[devlist->level] == NULL) 145255570Strasz log_err(1, "%s: unable to allocate sbuf", __func__); 146255570Strasz 147255570Strasz if (strcmp(name, "lun") == 0) { 148255570Strasz if (cur_lun != NULL) 149255570Strasz log_errx(1, "%s: improper lun element nesting", 150255570Strasz __func__); 151255570Strasz 152255570Strasz cur_lun = calloc(1, sizeof(*cur_lun)); 153255570Strasz if (cur_lun == NULL) 154255570Strasz log_err(1, "%s: cannot allocate %zd bytes", __func__, 155255570Strasz sizeof(*cur_lun)); 156255570Strasz 157255570Strasz devlist->num_luns++; 158255570Strasz devlist->cur_lun = cur_lun; 159255570Strasz 160255570Strasz STAILQ_INIT(&cur_lun->attr_list); 161255570Strasz STAILQ_INSERT_TAIL(&devlist->lun_list, cur_lun, links); 162255570Strasz 163255570Strasz for (i = 0; attr[i] != NULL; i += 2) { 164255570Strasz if (strcmp(attr[i], "id") == 0) { 165255570Strasz cur_lun->lun_id = strtoull(attr[i+1], NULL, 0); 166255570Strasz } else { 167255570Strasz log_errx(1, "%s: invalid LUN attribute %s = %s", 168255570Strasz __func__, attr[i], attr[i+1]); 169255570Strasz } 170255570Strasz } 171255570Strasz } 172255570Strasz} 173255570Strasz 174255570Straszstatic void 175255570Straszcctl_end_element(void *user_data, const char *name) 176255570Strasz{ 177255570Strasz struct cctl_devlist_data *devlist; 178255570Strasz struct cctl_lun *cur_lun; 179255570Strasz char *str; 180255570Strasz 181255570Strasz devlist = (struct cctl_devlist_data *)user_data; 182255570Strasz cur_lun = devlist->cur_lun; 183255570Strasz 184255570Strasz if ((cur_lun == NULL) 185255570Strasz && (strcmp(name, "ctllunlist") != 0)) 186255570Strasz log_errx(1, "%s: cur_lun == NULL! (name = %s)", __func__, name); 187255570Strasz 188255570Strasz if (devlist->cur_sb[devlist->level] == NULL) 189255570Strasz log_errx(1, "%s: no valid sbuf at level %d (name %s)", __func__, 190255570Strasz devlist->level, name); 191255570Strasz 192255570Strasz sbuf_finish(devlist->cur_sb[devlist->level]); 193255570Strasz str = checked_strdup(sbuf_data(devlist->cur_sb[devlist->level])); 194255570Strasz 195255570Strasz if (strlen(str) == 0) { 196255570Strasz free(str); 197255570Strasz str = NULL; 198255570Strasz } 199255570Strasz 200255570Strasz sbuf_delete(devlist->cur_sb[devlist->level]); 201255570Strasz devlist->cur_sb[devlist->level] = NULL; 202255570Strasz devlist->level--; 203255570Strasz 204255570Strasz if (strcmp(name, "backend_type") == 0) { 205255570Strasz cur_lun->backend_type = str; 206255570Strasz str = NULL; 207255570Strasz } else if (strcmp(name, "size") == 0) { 208255570Strasz cur_lun->size_blocks = strtoull(str, NULL, 0); 209255570Strasz } else if (strcmp(name, "blocksize") == 0) { 210255570Strasz cur_lun->blocksize = strtoul(str, NULL, 0); 211255570Strasz } else if (strcmp(name, "serial_number") == 0) { 212255570Strasz cur_lun->serial_number = str; 213255570Strasz str = NULL; 214255570Strasz } else if (strcmp(name, "device_id") == 0) { 215255570Strasz cur_lun->device_id = str; 216255570Strasz str = NULL; 217255570Strasz } else if (strcmp(name, "cfiscsi_target") == 0) { 218255570Strasz cur_lun->cfiscsi_target = str; 219255570Strasz str = NULL; 220255570Strasz } else if (strcmp(name, "cfiscsi_target_alias") == 0) { 221255570Strasz cur_lun->cfiscsi_target_alias = str; 222255570Strasz str = NULL; 223255570Strasz } else if (strcmp(name, "cfiscsi_lun") == 0) { 224255570Strasz cur_lun->cfiscsi_lun = strtoul(str, NULL, 0); 225255570Strasz } else if (strcmp(name, "lun") == 0) { 226255570Strasz devlist->cur_lun = NULL; 227255570Strasz } else if (strcmp(name, "ctllunlist") == 0) { 228255570Strasz 229255570Strasz } else { 230255570Strasz struct cctl_lun_nv *nv; 231255570Strasz 232255570Strasz nv = calloc(1, sizeof(*nv)); 233255570Strasz if (nv == NULL) 234255570Strasz log_err(1, "%s: can't allocate %zd bytes for nv pair", 235255570Strasz __func__, sizeof(*nv)); 236255570Strasz 237255570Strasz nv->name = checked_strdup(name); 238255570Strasz 239255570Strasz nv->value = str; 240255570Strasz str = NULL; 241255570Strasz STAILQ_INSERT_TAIL(&cur_lun->attr_list, nv, links); 242255570Strasz } 243255570Strasz 244255570Strasz free(str); 245255570Strasz} 246255570Strasz 247255570Straszstatic void 248255570Straszcctl_char_handler(void *user_data, const XML_Char *str, int len) 249255570Strasz{ 250255570Strasz struct cctl_devlist_data *devlist; 251255570Strasz 252255570Strasz devlist = (struct cctl_devlist_data *)user_data; 253255570Strasz 254255570Strasz sbuf_bcat(devlist->cur_sb[devlist->level], str, len); 255255570Strasz} 256255570Strasz 257255570Straszstruct conf * 258255570Straszconf_new_from_kernel(void) 259255570Strasz{ 260255570Strasz struct conf *conf = NULL; 261255570Strasz struct target *targ; 262255570Strasz struct lun *cl; 263255570Strasz struct lun_option *lo; 264255570Strasz struct ctl_lun_list list; 265255570Strasz struct cctl_devlist_data devlist; 266255570Strasz struct cctl_lun *lun; 267255570Strasz XML_Parser parser; 268255570Strasz char *lun_str = NULL; 269255570Strasz int lun_len; 270255570Strasz int retval; 271255570Strasz 272255570Strasz lun_len = 4096; 273255570Strasz 274255570Strasz bzero(&devlist, sizeof(devlist)); 275255570Strasz STAILQ_INIT(&devlist.lun_list); 276255570Strasz 277255570Strasz log_debugx("obtaining previously configured CTL luns from the kernel"); 278255570Strasz 279255570Straszretry: 280255570Strasz lun_str = realloc(lun_str, lun_len); 281255570Strasz if (lun_str == NULL) 282255570Strasz log_err(1, "realloc"); 283255570Strasz 284255570Strasz bzero(&list, sizeof(list)); 285255570Strasz list.alloc_len = lun_len; 286255570Strasz list.status = CTL_LUN_LIST_NONE; 287255570Strasz list.lun_xml = lun_str; 288255570Strasz 289255570Strasz if (ioctl(ctl_fd, CTL_LUN_LIST, &list) == -1) { 290255570Strasz log_warn("error issuing CTL_LUN_LIST ioctl"); 291255570Strasz free(lun_str); 292255570Strasz return (NULL); 293255570Strasz } 294255570Strasz 295255570Strasz if (list.status == CTL_LUN_LIST_ERROR) { 296255570Strasz log_warnx("error returned from CTL_LUN_LIST ioctl: %s", 297255570Strasz list.error_str); 298255570Strasz free(lun_str); 299255570Strasz return (NULL); 300255570Strasz } 301255570Strasz 302255570Strasz if (list.status == CTL_LUN_LIST_NEED_MORE_SPACE) { 303255570Strasz lun_len = lun_len << 1; 304255570Strasz goto retry; 305255570Strasz } 306255570Strasz 307255570Strasz parser = XML_ParserCreate(NULL); 308255570Strasz if (parser == NULL) { 309255570Strasz log_warnx("unable to create XML parser"); 310255570Strasz free(lun_str); 311255570Strasz return (NULL); 312255570Strasz } 313255570Strasz 314255570Strasz XML_SetUserData(parser, &devlist); 315255570Strasz XML_SetElementHandler(parser, cctl_start_element, cctl_end_element); 316255570Strasz XML_SetCharacterDataHandler(parser, cctl_char_handler); 317255570Strasz 318255570Strasz retval = XML_Parse(parser, lun_str, strlen(lun_str), 1); 319255570Strasz XML_ParserFree(parser); 320255570Strasz free(lun_str); 321255570Strasz if (retval != 1) { 322255570Strasz log_warnx("XML_Parse failed"); 323255570Strasz return (NULL); 324255570Strasz } 325255570Strasz 326255570Strasz conf = conf_new(); 327255570Strasz 328255570Strasz STAILQ_FOREACH(lun, &devlist.lun_list, links) { 329255570Strasz struct cctl_lun_nv *nv; 330255570Strasz 331255570Strasz if (lun->cfiscsi_target == NULL) { 332255570Strasz log_debugx("CTL lun %ju wasn't managed by ctld; " 333255570Strasz "ignoring", (uintmax_t)lun->lun_id); 334255570Strasz continue; 335255570Strasz } 336255570Strasz 337255570Strasz targ = target_find(conf, lun->cfiscsi_target); 338255570Strasz if (targ == NULL) { 339255570Strasz#if 0 340255570Strasz log_debugx("found new kernel target %s for CTL lun %ld", 341255570Strasz lun->cfiscsi_target, lun->lun_id); 342255570Strasz#endif 343255570Strasz targ = target_new(conf, lun->cfiscsi_target); 344255570Strasz if (targ == NULL) { 345255570Strasz log_warnx("target_new failed"); 346255570Strasz continue; 347255570Strasz } 348255570Strasz } 349255570Strasz 350255570Strasz cl = lun_find(targ, lun->cfiscsi_lun); 351255570Strasz if (cl != NULL) { 352255570Strasz log_warnx("found CTL lun %ju, backing lun %d, target " 353255570Strasz "%s, also backed by CTL lun %d; ignoring", 354255570Strasz (uintmax_t) lun->lun_id, cl->l_lun, 355255570Strasz cl->l_target->t_iqn, cl->l_ctl_lun); 356255570Strasz continue; 357255570Strasz } 358255570Strasz 359255570Strasz log_debugx("found CTL lun %ju, backing lun %d, target %s", 360255570Strasz (uintmax_t)lun->lun_id, lun->cfiscsi_lun, lun->cfiscsi_target); 361255570Strasz 362255570Strasz cl = lun_new(targ, lun->cfiscsi_lun); 363255570Strasz if (cl == NULL) { 364255570Strasz log_warnx("lun_new failed"); 365255570Strasz continue; 366255570Strasz } 367255570Strasz lun_set_backend(cl, lun->backend_type); 368255570Strasz lun_set_blocksize(cl, lun->blocksize); 369255570Strasz lun_set_device_id(cl, lun->device_id); 370255570Strasz lun_set_serial(cl, lun->serial_number); 371255570Strasz lun_set_size(cl, lun->size_blocks * cl->l_blocksize); 372255570Strasz lun_set_ctl_lun(cl, lun->lun_id); 373255570Strasz 374255570Strasz STAILQ_FOREACH(nv, &lun->attr_list, links) { 375255570Strasz if (strcmp(nv->name, "file") == 0 || 376255570Strasz strcmp(nv->name, "dev") == 0) { 377255570Strasz lun_set_path(cl, nv->value); 378255570Strasz continue; 379255570Strasz } 380255570Strasz lo = lun_option_new(cl, nv->name, nv->value); 381255570Strasz if (lo == NULL) 382255570Strasz log_warnx("unable to add CTL lun option %s " 383255570Strasz "for CTL lun %ju for lun %d, target %s", 384255570Strasz nv->name, (uintmax_t) lun->lun_id, 385255570Strasz cl->l_lun, cl->l_target->t_iqn); 386255570Strasz } 387255570Strasz } 388255570Strasz 389255570Strasz return (conf); 390255570Strasz} 391255570Strasz 392255570Straszint 393255570Straszkernel_lun_add(struct lun *lun) 394255570Strasz{ 395255570Strasz struct lun_option *lo; 396255570Strasz struct ctl_lun_req req; 397255570Strasz char *tmp; 398255570Strasz int error, i, num_options; 399255570Strasz 400255570Strasz bzero(&req, sizeof(req)); 401255570Strasz 402255570Strasz strlcpy(req.backend, lun->l_backend, sizeof(req.backend)); 403255570Strasz req.reqtype = CTL_LUNREQ_CREATE; 404255570Strasz 405255570Strasz req.reqdata.create.blocksize_bytes = lun->l_blocksize; 406255570Strasz 407255570Strasz if (lun->l_size != 0) 408255570Strasz req.reqdata.create.lun_size_bytes = lun->l_size; 409255570Strasz 410255570Strasz req.reqdata.create.flags |= CTL_LUN_FLAG_DEV_TYPE; 411255570Strasz req.reqdata.create.device_type = T_DIRECT; 412255570Strasz 413255570Strasz if (lun->l_serial != NULL) { 414255570Strasz strlcpy(req.reqdata.create.serial_num, lun->l_serial, 415255570Strasz sizeof(req.reqdata.create.serial_num)); 416255570Strasz req.reqdata.create.flags |= CTL_LUN_FLAG_SERIAL_NUM; 417255570Strasz } 418255570Strasz 419255570Strasz if (lun->l_device_id != NULL) { 420255570Strasz strlcpy(req.reqdata.create.device_id, lun->l_device_id, 421255570Strasz sizeof(req.reqdata.create.device_id)); 422255570Strasz req.reqdata.create.flags |= CTL_LUN_FLAG_DEVID; 423255570Strasz } 424255570Strasz 425255570Strasz if (lun->l_path != NULL) { 426255570Strasz lo = lun_option_find(lun, "file"); 427255570Strasz if (lo != NULL) { 428255570Strasz lun_option_set(lo, lun->l_path); 429255570Strasz } else { 430255570Strasz lo = lun_option_new(lun, "file", lun->l_path); 431255570Strasz assert(lo != NULL); 432255570Strasz } 433255570Strasz } 434255570Strasz 435255570Strasz lo = lun_option_find(lun, "cfiscsi_target"); 436255570Strasz if (lo != NULL) { 437255570Strasz lun_option_set(lo, lun->l_target->t_iqn); 438255570Strasz } else { 439255570Strasz lo = lun_option_new(lun, "cfiscsi_target", 440255570Strasz lun->l_target->t_iqn); 441255570Strasz assert(lo != NULL); 442255570Strasz } 443255570Strasz 444255570Strasz if (lun->l_target->t_alias != NULL) { 445255570Strasz lo = lun_option_find(lun, "cfiscsi_target_alias"); 446255570Strasz if (lo != NULL) { 447255570Strasz lun_option_set(lo, lun->l_target->t_alias); 448255570Strasz } else { 449255570Strasz lo = lun_option_new(lun, "cfiscsi_target_alias", 450255570Strasz lun->l_target->t_alias); 451255570Strasz assert(lo != NULL); 452255570Strasz } 453255570Strasz } 454255570Strasz 455255570Strasz asprintf(&tmp, "%d", lun->l_lun); 456255570Strasz if (tmp == NULL) 457255570Strasz log_errx(1, "asprintf"); 458255570Strasz lo = lun_option_find(lun, "cfiscsi_lun"); 459255570Strasz if (lo != NULL) { 460255570Strasz lun_option_set(lo, tmp); 461255570Strasz free(tmp); 462255570Strasz } else { 463255570Strasz lo = lun_option_new(lun, "cfiscsi_lun", tmp); 464255570Strasz free(tmp); 465255570Strasz assert(lo != NULL); 466255570Strasz } 467255570Strasz 468255570Strasz num_options = 0; 469255570Strasz TAILQ_FOREACH(lo, &lun->l_options, lo_next) 470255570Strasz num_options++; 471255570Strasz 472255570Strasz req.num_be_args = num_options; 473255570Strasz if (num_options > 0) { 474255570Strasz req.be_args = malloc(num_options * sizeof(*req.be_args)); 475255570Strasz if (req.be_args == NULL) { 476255570Strasz log_warn("error allocating %zd bytes", 477255570Strasz num_options * sizeof(*req.be_args)); 478255570Strasz return (1); 479255570Strasz } 480255570Strasz 481255570Strasz i = 0; 482255570Strasz TAILQ_FOREACH(lo, &lun->l_options, lo_next) { 483255570Strasz /* 484255570Strasz * +1 for the terminating '\0' 485255570Strasz */ 486255570Strasz req.be_args[i].namelen = strlen(lo->lo_name) + 1; 487255570Strasz req.be_args[i].name = lo->lo_name; 488255570Strasz req.be_args[i].vallen = strlen(lo->lo_value) + 1; 489255570Strasz req.be_args[i].value = lo->lo_value; 490255570Strasz req.be_args[i].flags = CTL_BEARG_ASCII | CTL_BEARG_RD; 491255570Strasz i++; 492255570Strasz } 493255570Strasz assert(i == num_options); 494255570Strasz } 495255570Strasz 496255570Strasz error = ioctl(ctl_fd, CTL_LUN_REQ, &req); 497255570Strasz free(req.be_args); 498255570Strasz if (error != 0) { 499255570Strasz log_warn("error issuing CTL_LUN_REQ ioctl"); 500255570Strasz return (1); 501255570Strasz } 502255570Strasz 503255570Strasz if (req.status == CTL_LUN_ERROR) { 504255570Strasz log_warnx("error returned from LUN creation request: %s", 505255570Strasz req.error_str); 506255570Strasz return (1); 507255570Strasz } 508255570Strasz 509255570Strasz if (req.status != CTL_LUN_OK) { 510255570Strasz log_warnx("unknown LUN creation request status %d", 511255570Strasz req.status); 512255570Strasz return (1); 513255570Strasz } 514255570Strasz 515255570Strasz lun_set_ctl_lun(lun, req.reqdata.create.req_lun_id); 516255570Strasz 517255570Strasz return (0); 518255570Strasz} 519255570Strasz 520255570Straszint 521255570Straszkernel_lun_resize(struct lun *lun) 522255570Strasz{ 523255570Strasz struct ctl_lun_req req; 524255570Strasz 525255570Strasz bzero(&req, sizeof(req)); 526255570Strasz 527255570Strasz strlcpy(req.backend, lun->l_backend, sizeof(req.backend)); 528255570Strasz req.reqtype = CTL_LUNREQ_MODIFY; 529255570Strasz 530255570Strasz req.reqdata.modify.lun_id = lun->l_ctl_lun; 531255570Strasz req.reqdata.modify.lun_size_bytes = lun->l_size; 532255570Strasz 533255570Strasz if (ioctl(ctl_fd, CTL_LUN_REQ, &req) == -1) { 534255570Strasz log_warn("error issuing CTL_LUN_REQ ioctl"); 535255570Strasz return (1); 536255570Strasz } 537255570Strasz 538255570Strasz if (req.status == CTL_LUN_ERROR) { 539255570Strasz log_warnx("error returned from LUN modification request: %s", 540255570Strasz req.error_str); 541255570Strasz return (1); 542255570Strasz } 543255570Strasz 544255570Strasz if (req.status != CTL_LUN_OK) { 545255570Strasz log_warnx("unknown LUN modification request status %d", 546255570Strasz req.status); 547255570Strasz return (1); 548255570Strasz } 549255570Strasz 550255570Strasz return (0); 551255570Strasz} 552255570Strasz 553255570Straszint 554255570Straszkernel_lun_remove(struct lun *lun) 555255570Strasz{ 556255570Strasz struct ctl_lun_req req; 557255570Strasz 558255570Strasz bzero(&req, sizeof(req)); 559255570Strasz 560255570Strasz strlcpy(req.backend, lun->l_backend, sizeof(req.backend)); 561255570Strasz req.reqtype = CTL_LUNREQ_RM; 562255570Strasz 563255570Strasz req.reqdata.rm.lun_id = lun->l_ctl_lun; 564255570Strasz 565255570Strasz if (ioctl(ctl_fd, CTL_LUN_REQ, &req) == -1) { 566255570Strasz log_warn("error issuing CTL_LUN_REQ ioctl"); 567255570Strasz return (1); 568255570Strasz } 569255570Strasz 570255570Strasz if (req.status == CTL_LUN_ERROR) { 571255570Strasz log_warnx("error returned from LUN removal request: %s", 572255570Strasz req.error_str); 573255570Strasz return (1); 574255570Strasz } 575255570Strasz 576255570Strasz if (req.status != CTL_LUN_OK) { 577255570Strasz log_warnx("unknown LUN removal request status %d", req.status); 578255570Strasz return (1); 579255570Strasz } 580255570Strasz 581255570Strasz return (0); 582255570Strasz} 583255570Strasz 584255570Straszvoid 585255570Straszkernel_handoff(struct connection *conn) 586255570Strasz{ 587255570Strasz struct ctl_iscsi req; 588255570Strasz 589255570Strasz bzero(&req, sizeof(req)); 590255570Strasz 591255570Strasz req.type = CTL_ISCSI_HANDOFF; 592255570Strasz strlcpy(req.data.handoff.initiator_name, 593255570Strasz conn->conn_initiator_name, sizeof(req.data.handoff.initiator_name)); 594255570Strasz strlcpy(req.data.handoff.initiator_addr, 595255570Strasz conn->conn_initiator_addr, sizeof(req.data.handoff.initiator_addr)); 596255570Strasz if (conn->conn_initiator_alias != NULL) { 597255570Strasz strlcpy(req.data.handoff.initiator_alias, 598255570Strasz conn->conn_initiator_alias, sizeof(req.data.handoff.initiator_alias)); 599255570Strasz } 600255570Strasz strlcpy(req.data.handoff.target_name, 601255570Strasz conn->conn_target->t_iqn, sizeof(req.data.handoff.target_name)); 602255570Strasz req.data.handoff.socket = conn->conn_socket; 603255570Strasz req.data.handoff.portal_group_tag = 604255570Strasz conn->conn_portal->p_portal_group->pg_tag; 605255570Strasz if (conn->conn_header_digest == CONN_DIGEST_CRC32C) 606255570Strasz req.data.handoff.header_digest = CTL_ISCSI_DIGEST_CRC32C; 607255570Strasz if (conn->conn_data_digest == CONN_DIGEST_CRC32C) 608255570Strasz req.data.handoff.data_digest = CTL_ISCSI_DIGEST_CRC32C; 609255570Strasz req.data.handoff.cmdsn = conn->conn_cmdsn; 610255570Strasz req.data.handoff.statsn = conn->conn_statsn; 611255570Strasz req.data.handoff.max_recv_data_segment_length = 612255570Strasz conn->conn_max_data_segment_length; 613255570Strasz req.data.handoff.max_burst_length = conn->conn_max_burst_length; 614255570Strasz req.data.handoff.immediate_data = conn->conn_immediate_data; 615255570Strasz 616255570Strasz if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) 617255570Strasz log_err(1, "error issuing CTL_ISCSI ioctl; " 618255570Strasz "dropping connection"); 619255570Strasz 620255570Strasz if (req.status != CTL_ISCSI_OK) 621255570Strasz log_errx(1, "error returned from CTL iSCSI handoff request: " 622255570Strasz "%s; dropping connection", req.error_str); 623255570Strasz} 624255570Strasz 625255570Straszint 626255570Straszkernel_port_on(void) 627255570Strasz{ 628255570Strasz struct ctl_port_entry entry; 629255570Strasz int error; 630255570Strasz 631255570Strasz bzero(&entry, sizeof(&entry)); 632255570Strasz 633255570Strasz entry.port_type = CTL_PORT_ISCSI; 634255570Strasz entry.targ_port = -1; 635255570Strasz 636255570Strasz error = ioctl(ctl_fd, CTL_ENABLE_PORT, &entry); 637255570Strasz if (error != 0) { 638255570Strasz log_warn("CTL_ENABLE_PORT ioctl failed"); 639255570Strasz return (-1); 640255570Strasz } 641255570Strasz 642255570Strasz return (0); 643255570Strasz} 644255570Strasz 645255570Straszint 646255570Straszkernel_port_off(void) 647255570Strasz{ 648255570Strasz struct ctl_port_entry entry; 649255570Strasz int error; 650255570Strasz 651255570Strasz bzero(&entry, sizeof(&entry)); 652255570Strasz 653255570Strasz entry.port_type = CTL_PORT_ISCSI; 654255570Strasz entry.targ_port = -1; 655255570Strasz 656255570Strasz error = ioctl(ctl_fd, CTL_DISABLE_PORT, &entry); 657255570Strasz if (error != 0) { 658255570Strasz log_warn("CTL_DISABLE_PORT ioctl failed"); 659255570Strasz return (-1); 660255570Strasz } 661255570Strasz 662255570Strasz return (0); 663255570Strasz} 664255570Strasz 665255570Strasz#ifdef ICL_KERNEL_PROXY 666255570Straszvoid 667255570Straszkernel_listen(struct addrinfo *ai, bool iser) 668255570Strasz{ 669255570Strasz struct ctl_iscsi req; 670255570Strasz 671255570Strasz bzero(&req, sizeof(req)); 672255570Strasz 673255570Strasz req.type = CTL_ISCSI_LISTEN; 674255570Strasz req.data.listen.iser = iser; 675255570Strasz req.data.listen.domain = ai->ai_family; 676255570Strasz req.data.listen.socktype = ai->ai_socktype; 677255570Strasz req.data.listen.protocol = ai->ai_protocol; 678255570Strasz req.data.listen.addr = ai->ai_addr; 679255570Strasz req.data.listen.addrlen = ai->ai_addrlen; 680255570Strasz 681255570Strasz if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) 682255570Strasz log_warn("error issuing CTL_ISCSI_LISTEN ioctl"); 683255570Strasz} 684255570Strasz 685255570Straszint 686255570Straszkernel_accept(void) 687255570Strasz{ 688255570Strasz struct ctl_iscsi req; 689255570Strasz 690255570Strasz bzero(&req, sizeof(req)); 691255570Strasz 692255570Strasz req.type = CTL_ISCSI_ACCEPT; 693255570Strasz 694255570Strasz if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) { 695255570Strasz log_warn("error issuing CTL_ISCSI_LISTEN ioctl"); 696255570Strasz return (0); 697255570Strasz } 698255570Strasz 699255570Strasz return (req.data.accept.connection_id); 700255570Strasz} 701255570Strasz 702255570Straszvoid 703255570Straszkernel_send(struct pdu *pdu) 704255570Strasz{ 705255570Strasz struct ctl_iscsi req; 706255570Strasz 707255570Strasz bzero(&req, sizeof(req)); 708255570Strasz 709255570Strasz req.type = CTL_ISCSI_SEND; 710255570Strasz req.data.send.connection_id = pdu->pdu_connection->conn_socket; 711255570Strasz req.data.send.bhs = pdu->pdu_bhs; 712255570Strasz req.data.send.data_segment_len = pdu->pdu_data_len; 713255570Strasz req.data.send.data_segment = pdu->pdu_data; 714255570Strasz 715255570Strasz if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) 716255570Strasz log_err(1, "error issuing CTL_ISCSI ioctl; " 717255570Strasz "dropping connection"); 718255570Strasz 719255570Strasz if (req.status != CTL_ISCSI_OK) 720255570Strasz log_errx(1, "error returned from CTL iSCSI send: " 721255570Strasz "%s; dropping connection", req.error_str); 722255570Strasz} 723255570Strasz 724255570Straszvoid 725255570Straszkernel_receive(struct pdu *pdu) 726255570Strasz{ 727255570Strasz struct ctl_iscsi req; 728255570Strasz 729255570Strasz pdu->pdu_data = malloc(MAX_DATA_SEGMENT_LENGTH); 730255570Strasz if (pdu->pdu_data == NULL) 731255570Strasz log_err(1, "malloc"); 732255570Strasz 733255570Strasz bzero(&req, sizeof(req)); 734255570Strasz 735255570Strasz req.type = CTL_ISCSI_RECEIVE; 736255570Strasz req.data.receive.connection_id = pdu->pdu_connection->conn_socket; 737255570Strasz req.data.receive.bhs = pdu->pdu_bhs; 738255570Strasz req.data.receive.data_segment_len = MAX_DATA_SEGMENT_LENGTH; 739255570Strasz req.data.receive.data_segment = pdu->pdu_data; 740255570Strasz 741255570Strasz if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) 742255570Strasz log_err(1, "error issuing CTL_ISCSI ioctl; " 743255570Strasz "dropping connection"); 744255570Strasz 745255570Strasz if (req.status != CTL_ISCSI_OK) 746255570Strasz log_errx(1, "error returned from CTL iSCSI receive: " 747255570Strasz "%s; dropping connection", req.error_str); 748255570Strasz 749255570Strasz} 750255570Strasz 751255570Strasz#endif /* ICL_KERNEL_PROXY */ 752255570Strasz 753255570Strasz/* 754255570Strasz * XXX: I CANT INTO LATIN 755255570Strasz */ 756255570Straszvoid 757255570Straszkernel_capsicate(void) 758255570Strasz{ 759255570Strasz int error; 760255570Strasz cap_rights_t rights; 761255570Strasz const unsigned long cmds[] = { CTL_ISCSI }; 762255570Strasz 763255570Strasz cap_rights_init(&rights, CAP_IOCTL); 764255570Strasz error = cap_rights_limit(ctl_fd, &rights); 765255570Strasz if (error != 0 && errno != ENOSYS) 766255570Strasz log_err(1, "cap_rights_limit"); 767255570Strasz 768255570Strasz error = cap_ioctls_limit(ctl_fd, cmds, 769255570Strasz sizeof(cmds) / sizeof(cmds[0])); 770255570Strasz if (error != 0 && errno != ENOSYS) 771255570Strasz log_err(1, "cap_ioctls_limit"); 772255570Strasz 773255570Strasz error = cap_enter(); 774255570Strasz if (error != 0 && errno != ENOSYS) 775255570Strasz log_err(1, "cap_enter"); 776255570Strasz 777255570Strasz if (cap_sandboxed()) 778255570Strasz log_debugx("Capsicum capability mode enabled"); 779255570Strasz else 780255570Strasz log_warnx("Capsicum capability mode not supported"); 781255570Strasz} 782255570Strasz 783