1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2000 by Cisco Systems, Inc. All rights reserved. 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 * 26 * iSCSI Software Initiator 27 */ 28 29 /* 30 * Framework interface routines for iSCSI 31 */ 32 #include "iscsi.h" /* main header */ 33 #include <sys/scsi/adapters/iscsi_if.h> /* ioctl interfaces */ 34 #include <sys/scsi/adapters/iscsi_protocol.h> 35 /* protocol structs and defines */ 36 37 #include "iscsi_targetparam.h" 38 #include "persistent.h" 39 #include <sys/scsi/adapters/iscsi_door.h> 40 #include <sys/dlpi.h> 41 #include <sys/utsname.h> 42 #include "isns_client.h" 43 #include "isns_protocol.h" 44 #include <sys/bootprops.h> 45 46 #define ISCSI_NAME_VERSION "iSCSI Initiator v-1.55" 47 48 #define MAX_GET_NAME_SIZE 1024 49 #define MAX_NAME_PROP_SIZE 256 50 #define UNDEFINED -1 51 52 /* 53 * +--------------------------------------------------------------------+ 54 * | iscsi globals | 55 * +--------------------------------------------------------------------+ 56 */ 57 void *iscsi_state; 58 kmutex_t iscsi_oid_mutex; 59 uint32_t iscsi_oid; 60 int iscsi_nop_delay = ISCSI_DEFAULT_NOP_DELAY; 61 int iscsi_rx_window = ISCSI_DEFAULT_RX_WINDOW; 62 int iscsi_rx_max_window = ISCSI_DEFAULT_RX_MAX_WINDOW; 63 64 extern ib_boot_prop_t *iscsiboot_prop; 65 66 /* 67 * +--------------------------------------------------------------------+ 68 * | iscsi.c prototypes | 69 * +--------------------------------------------------------------------+ 70 */ 71 static int iscsi_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, 72 void *arg, void **result); 73 static int iscsi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 74 static int iscsi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 75 76 /* scsi_tran prototypes */ 77 static int iscsi_tran_lun_init(dev_info_t *hba_dip, dev_info_t *lun_dip, 78 scsi_hba_tran_t *hba_tran, struct scsi_device *sd); 79 static int iscsi_tran_lun_probe(struct scsi_device *sd, int (*callback) ()); 80 static struct scsi_pkt *iscsi_tran_init_pkt(struct scsi_address *ap, 81 struct scsi_pkt *pkt, struct buf *bp, int cmdlen, int statuslen, 82 int tgtlen, int flags, int (*callback) (), caddr_t arg); 83 static void iscsi_tran_lun_free(dev_info_t *hba_dip, dev_info_t *lun_dip, 84 scsi_hba_tran_t *hba_tran, struct scsi_device *sd); 85 static int iscsi_tran_start(struct scsi_address *ap, struct scsi_pkt *pkt); 86 static int iscsi_tran_abort(struct scsi_address *ap, struct scsi_pkt *pkt); 87 static int iscsi_tran_reset(struct scsi_address *ap, int level); 88 static int iscsi_tran_getcap(struct scsi_address *ap, char *cap, int whom); 89 static int iscsi_tran_setcap(struct scsi_address *ap, char *cap, 90 int value, int whom); 91 static void iscsi_tran_destroy_pkt(struct scsi_address *ap, 92 struct scsi_pkt *pkt); 93 static void iscsi_tran_dmafree(struct scsi_address *ap, 94 struct scsi_pkt *pkt); 95 static void iscsi_tran_sync_pkt(struct scsi_address *ap, 96 struct scsi_pkt *pkt); 97 static void iscsi_tran_sync_pkt(struct scsi_address *ap, 98 struct scsi_pkt *pkt); 99 static int iscsi_tran_reset_notify(struct scsi_address *ap, int flag, 100 void (*callback) (caddr_t), caddr_t arg); 101 static int iscsi_tran_bus_config(dev_info_t *parent, uint_t flags, 102 ddi_bus_config_op_t op, void *arg, dev_info_t **childp); 103 static int iscsi_tran_bus_unconfig(dev_info_t *parent, uint_t flags, 104 ddi_bus_config_op_t op, void *arg); 105 static int iscsi_tran_get_name(struct scsi_device *sd, char *name, int len); 106 static int iscsi_tran_get_bus_addr(struct scsi_device *sd, char *name, int len); 107 108 /* bus_ops prototypes */ 109 /* LINTED E_STATIC_UNUSED */ 110 static ddi_intrspec_t iscsi_get_intrspec(dev_info_t *dip, dev_info_t *rdip, 111 uint_t inumber); 112 /* LINTED E_STATIC_UNUSED */ 113 static int iscsi_add_intrspec(dev_info_t *dip, dev_info_t *rdip, 114 ddi_intrspec_t intrspec, ddi_iblock_cookie_t *iblock_cookiep, 115 ddi_idevice_cookie_t *idevice_cookiep, uint_t (*int_handler)(caddr_t 116 int_handler_arg), caddr_t int_handler_arg, int kind); 117 /* LINTED E_STATIC_UNUSED */ 118 static void iscsi_remove_intrspec(dev_info_t *dip, dev_info_t *rdip, 119 ddi_intrspec_t intrspec, ddi_iblock_cookie_t iblock_cookie); 120 /* LINTED E_STATIC_UNUSED */ 121 static int iscsi_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop, 122 void *arg, void *result); 123 124 /* cb_ops prototypes */ 125 static int iscsi_open(dev_t *devp, int flags, int otyp, cred_t *credp); 126 static int iscsi_close(dev_t dev, int flag, int otyp, cred_t *credp); 127 /* --- iscsi_ioctl is called by the discovery code so needs to be global --- */ 128 int iscsi_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 129 cred_t *credp, int *rvalp); 130 131 int iscsi_get_persisted_param(uchar_t *name, 132 iscsi_param_get_t *ipgp, 133 iscsi_login_params_t *params); 134 static void iscsi_override_target_default(iscsi_hba_t *ihp, 135 iscsi_param_get_t *ipg); 136 137 /* scsi_tran helpers */ 138 static int iscsi_virt_lun_init(dev_info_t *hba_dip, dev_info_t *lun_dip, 139 scsi_hba_tran_t *hba_tran, struct scsi_device *sd); 140 static int iscsi_phys_lun_init(dev_info_t *hba_dip, dev_info_t *lun_dip, 141 scsi_hba_tran_t *hba_tran, struct scsi_device *sd); 142 static int iscsi_i_commoncap(struct scsi_address *ap, char *cap, 143 int val, int lunonly, int doset); 144 static void iscsi_get_name_to_iqn(char *name, int name_max_len); 145 static void iscsi_get_name_from_iqn(char *name, int name_max_len); 146 static boolean_t iscsi_cmp_boot_sess_oid(iscsi_hba_t *ihp, uint32_t oid); 147 148 /* struct helpers prototypes */ 149 150 /* 151 * At this point this driver doesn't need this structure because nothing 152 * is done during the open, close or ioctl. Code put in place because 153 * some admin related work might be done in the ioctl routine. 154 */ 155 static struct cb_ops iscsi_cb_ops = { 156 iscsi_open, /* open */ 157 iscsi_close, /* close */ 158 nodev, /* strategy */ 159 nodev, /* print */ 160 nodev, /* dump */ 161 nodev, /* read */ 162 nodev, /* write */ 163 iscsi_ioctl, /* ioctl */ 164 nodev, /* devmap */ 165 nodev, /* mmap */ 166 nodev, /* segmap */ 167 nochpoll, /* poll */ 168 ddi_prop_op, /* prop_op */ 169 NULL, /* streamtab */ 170 D_NEW | D_MP | D_HOTPLUG, /* flags */ 171 CB_REV, /* cb_rev */ 172 nodev, /* aread */ 173 nodev, /* awrite */ 174 }; 175 176 static struct dev_ops iscsi_dev_ops = { 177 DEVO_REV, /* devo_rev */ 178 0, /* refcnt */ 179 iscsi_getinfo, /* getinfo */ 180 nulldev, /* identify */ 181 nulldev, /* probe */ 182 iscsi_attach, /* attach */ 183 iscsi_detach, /* detach */ 184 nodev, /* reset */ 185 &iscsi_cb_ops, /* driver operations */ 186 NULL, /* bus ops */ 187 NULL, /* power management */ 188 }; 189 190 static struct modldrv modldrv = { 191 &mod_driverops, /* drv_modops */ 192 ISCSI_NAME_VERSION, /* drv_linkinfo */ 193 &iscsi_dev_ops /* drv_dev_ops */ 194 }; 195 196 static struct modlinkage modlinkage = { 197 MODREV_1, /* ml_rev */ 198 &modldrv, /* ml_linkage[] */ 199 NULL /* NULL termination */ 200 }; 201 202 /* 203 * This structure is bogus. scsi_hba_attach_setup() requires, as in the kernel 204 * will panic if you don't pass this in to the routine, this information. 205 * Need to determine what the actual impact to the system is by providing 206 * this information if any. Since dma allocation is done in pkt_init it may 207 * not have any impact. These values are straight from the Writing Device 208 * Driver manual. 209 */ 210 static ddi_dma_attr_t iscsi_dma_attr = { 211 DMA_ATTR_V0, /* ddi_dma_attr version */ 212 0, /* low address */ 213 0xffffffff, /* high address */ 214 0x00ffffff, /* counter upper bound */ 215 1, /* alignment requirements */ 216 0x3f, /* burst sizes */ 217 1, /* minimum DMA access */ 218 0xffffffff, /* maximum DMA access */ 219 (1 << 24) - 1, /* segment boundary restrictions */ 220 1, /* scater/gather list length */ 221 512, /* device granularity */ 222 0 /* DMA flags */ 223 }; 224 225 /* 226 * _init - General driver init entry 227 */ 228 int 229 _init(void) 230 { 231 int rval = 0; 232 233 iscsi_net_init(); 234 235 mutex_init(&iscsi_oid_mutex, NULL, MUTEX_DRIVER, NULL); 236 iscsi_oid = ISCSI_INITIATOR_OID; 237 238 /* 239 * Set up the soft state structures. If this driver is actually 240 * being attached to the system then we'll have at least one 241 * HBA/NIC used. 242 */ 243 rval = ddi_soft_state_init(&iscsi_state, 244 sizeof (iscsi_hba_t), 1); 245 if (rval != 0) { 246 iscsi_net_fini(); 247 goto init_done; 248 } 249 250 rval = scsi_hba_init(&modlinkage); 251 if (rval != 0) { 252 ddi_soft_state_fini(&iscsi_state); 253 iscsi_net_fini(); 254 goto init_done; 255 } 256 257 rval = mod_install(&modlinkage); 258 if (rval != 0) { 259 ddi_soft_state_fini(&iscsi_state); 260 scsi_hba_fini(&modlinkage); 261 iscsi_net_fini(); 262 goto init_done; 263 } 264 (void) iscsi_door_ini(); 265 266 init_done: 267 return (rval); 268 } 269 270 /* 271 * _fini - General driver destructor entry 272 */ 273 int 274 _fini(void) 275 { 276 int rval = 0; 277 278 rval = mod_remove(&modlinkage); 279 if (rval == 0) { 280 scsi_hba_fini(&modlinkage); 281 ddi_soft_state_fini(&iscsi_state); 282 mutex_destroy(&iscsi_oid_mutex); 283 (void) iscsi_door_term(); 284 iscsi_net_fini(); 285 } 286 return (rval); 287 } 288 289 /* 290 * _info - General driver info entry 291 */ 292 int 293 _info(struct modinfo *mp) 294 { 295 int rval = 0; 296 297 rval = mod_info(&modlinkage, mp); 298 299 return (rval); 300 } 301 302 303 /* 304 * +--------------------------------------------------------------------+ 305 * | Start of dev_ops routines | 306 * +--------------------------------------------------------------------+ 307 */ 308 309 /* 310 * iscsi_getinfo - returns general driver information 311 */ 312 /* ARGSUSED */ 313 static int 314 iscsi_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, 315 void *arg, void **result) 316 { 317 int rval = DDI_SUCCESS; 318 int instance = getminor((dev_t)arg); 319 iscsi_hba_t *ip; 320 321 switch (infocmd) { 322 case DDI_INFO_DEVT2DEVINFO: 323 if ((ip = ddi_get_soft_state(iscsi_state, instance)) == NULL) { 324 return (DDI_FAILURE); 325 } 326 *result = ip->hba_dip; 327 if (ip->hba_dip == NULL) 328 rval = DDI_FAILURE; 329 else 330 rval = DDI_SUCCESS; 331 break; 332 333 case DDI_INFO_DEVT2INSTANCE: 334 *result = (void *)(uintptr_t)instance; 335 rval = DDI_SUCCESS; 336 break; 337 338 default: 339 rval = DDI_FAILURE; 340 break; 341 } 342 return (rval); 343 } 344 345 346 /* 347 * iscsi_attach -- Attach instance of an iSCSI HBA. We 348 * will attempt to create our HBA and register it with 349 * scsi_vhci. If it's not possible to create the HBA 350 * or register with vhci we will fail the attach. 351 */ 352 static int 353 iscsi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 354 { 355 int rval = DDI_SUCCESS; 356 int instance = ddi_get_instance(dip); 357 iscsi_hba_t *ihp = NULL; 358 scsi_hba_tran_t *tran = NULL; 359 char init_port_name[MAX_NAME_PROP_SIZE]; 360 361 switch (cmd) { 362 case DDI_ATTACH: 363 /* create iSCSH HBA devctl device node */ 364 if (ddi_create_minor_node(dip, ISCSI_DEVCTL, S_IFCHR, 0, 365 DDI_PSEUDO, 0) == DDI_SUCCESS) { 366 367 /* allocate HBA soft state */ 368 if (ddi_soft_state_zalloc(iscsi_state, instance) != 369 DDI_SUCCESS) { 370 ddi_remove_minor_node(dip, NULL); 371 rval = DDI_FAILURE; 372 break; 373 } 374 375 /* get reference to soft state */ 376 if ((ihp = (iscsi_hba_t *)ddi_get_soft_state( 377 iscsi_state, instance)) == NULL) { 378 ddi_remove_minor_node(dip, NULL); 379 ddi_soft_state_free(iscsi_state, instance); 380 rval = DDI_FAILURE; 381 break; 382 } 383 384 /* init HBA mutex used to protect discovery events */ 385 mutex_init(&ihp->hba_discovery_events_mutex, NULL, 386 MUTEX_DRIVER, NULL); 387 388 /* 389 * init SendTargets semaphore that is used to allow 390 * only one operation at a time 391 */ 392 sema_init(&ihp->hba_sendtgts_semaphore, 1, NULL, 393 SEMA_DRIVER, NULL); 394 395 ihp->hba_sess_list = NULL; 396 rw_init(&ihp->hba_sess_list_rwlock, NULL, 397 RW_DRIVER, NULL); 398 399 /* allocate scsi_hba_tran */ 400 if ((tran = scsi_hba_tran_alloc(dip, SCSI_HBA_CANSLEEP)) 401 == NULL) { 402 ddi_remove_minor_node(dip, NULL); 403 goto iscsi_attach_failed2; 404 } 405 406 /* soft state setup */ 407 ihp->hba_sig = ISCSI_SIG_HBA; 408 ihp->hba_tran = tran; 409 ihp->hba_dip = dip; 410 411 mutex_enter(&iscsi_oid_mutex); 412 ihp->hba_oid = iscsi_oid++; 413 mutex_exit(&iscsi_oid_mutex); 414 415 ihp->hba_name[0] = '\0'; 416 ihp->hba_name_length = 0; 417 ihp->hba_alias_length = 0; 418 ihp->hba_alias[0] = '\0'; 419 420 iscsi_net->tweaks.rcvbuf = ddi_prop_get_int( 421 DDI_DEV_T_ANY, ihp->hba_dip, 0, "so-rcvbuf", 422 ISCSI_SOCKET_RCVBUF_SIZE); 423 424 iscsi_net->tweaks.sndbuf = ddi_prop_get_int( 425 DDI_DEV_T_ANY, ihp->hba_dip, 0, "so-sndbuf", 426 ISCSI_SOCKET_SNDBUF_SIZE); 427 428 iscsi_net->tweaks.nodelay = ddi_prop_get_int( 429 DDI_DEV_T_ANY, ihp->hba_dip, 0, "tcp-nodelay", 430 ISCSI_TCP_NODELAY_DEFAULT); 431 432 iscsi_net->tweaks.conn_notify_threshold = 433 ddi_prop_get_int(DDI_DEV_T_ANY, 434 ihp->hba_dip, 0, "tcp-conn-notify-threshold", 435 ISCSI_TCP_CNOTIFY_THRESHOLD_DEFAULT); 436 437 iscsi_net->tweaks.conn_abort_threshold = 438 ddi_prop_get_int(DDI_DEV_T_ANY, ihp->hba_dip, 439 0, "tcp-conn-abort-threshold", 440 ISCSI_TCP_CABORT_THRESHOLD_DEFAULT); 441 442 iscsi_net->tweaks.abort_threshold = ddi_prop_get_int( 443 DDI_DEV_T_ANY, ihp->hba_dip, 0, 444 "tcp-abort-threshold", 445 ISCSI_TCP_ABORT_THRESHOLD_DEFAULT); 446 447 ihp->hba_config_storm_delay = ddi_prop_get_int( 448 DDI_DEV_T_ANY, ihp->hba_dip, 0, 449 "config-storm-delay", 450 ISCSI_CONFIG_STORM_DELAY_DEFAULT); 451 452 (void) ddi_prop_update_int(DDI_DEV_T_NONE, ihp->hba_dip, 453 "so-rcvbuf", iscsi_net->tweaks.rcvbuf); 454 455 (void) ddi_prop_update_int(DDI_DEV_T_NONE, ihp->hba_dip, 456 "so-sndbuf", iscsi_net->tweaks.sndbuf); 457 458 (void) ddi_prop_update_int(DDI_DEV_T_NONE, ihp->hba_dip, 459 "tcp-nodelay", iscsi_net->tweaks.nodelay); 460 461 (void) ddi_prop_update_int(DDI_DEV_T_NONE, ihp->hba_dip, 462 "tcp-conn-notify-threshold", 463 iscsi_net->tweaks.conn_notify_threshold); 464 465 (void) ddi_prop_update_int(DDI_DEV_T_NONE, ihp->hba_dip, 466 "tcp-conn-abort-threshold", 467 iscsi_net->tweaks.conn_abort_threshold); 468 469 (void) ddi_prop_update_int(DDI_DEV_T_NONE, ihp->hba_dip, 470 "tcp-abort-threshold", 471 iscsi_net->tweaks.abort_threshold); 472 473 (void) ddi_prop_update_int(DDI_DEV_T_NONE, ihp->hba_dip, 474 "config-storm-delay", 475 ihp->hba_config_storm_delay); 476 477 /* setup hba defaults */ 478 iscsi_set_default_login_params(&ihp->hba_params); 479 480 /* hba set up */ 481 tran->tran_hba_private = ihp; 482 tran->tran_tgt_private = NULL; 483 tran->tran_tgt_init = iscsi_tran_lun_init; 484 tran->tran_tgt_probe = iscsi_tran_lun_probe; 485 tran->tran_tgt_free = iscsi_tran_lun_free; 486 tran->tran_start = iscsi_tran_start; 487 tran->tran_abort = iscsi_tran_abort; 488 tran->tran_reset = iscsi_tran_reset; 489 tran->tran_getcap = iscsi_tran_getcap; 490 tran->tran_setcap = iscsi_tran_setcap; 491 tran->tran_init_pkt = iscsi_tran_init_pkt; 492 tran->tran_destroy_pkt = iscsi_tran_destroy_pkt; 493 tran->tran_dmafree = iscsi_tran_dmafree; 494 tran->tran_sync_pkt = iscsi_tran_sync_pkt; 495 tran->tran_reset_notify = iscsi_tran_reset_notify; 496 tran->tran_bus_config = iscsi_tran_bus_config; 497 tran->tran_bus_unconfig = iscsi_tran_bus_unconfig; 498 499 tran->tran_get_name = iscsi_tran_get_name; 500 tran->tran_get_bus_addr = iscsi_tran_get_bus_addr; 501 tran->tran_interconnect_type = INTERCONNECT_ISCSI; 502 503 /* register scsi hba with scsa */ 504 if (scsi_hba_attach_setup(dip, &iscsi_dma_attr, 505 tran, SCSI_HBA_TRAN_CLONE) != DDI_SUCCESS) { 506 goto iscsi_attach_failed1; 507 } 508 509 /* register scsi hba with mdi (MPxIO/vhci) */ 510 if (mdi_phci_register(MDI_HCI_CLASS_SCSI, dip, 0) != 511 MDI_SUCCESS) { 512 ihp->hba_mpxio_enabled = B_FALSE; 513 } else { 514 ihp->hba_mpxio_enabled = B_TRUE; 515 } 516 517 (void) iscsi_hba_kstat_init(ihp); 518 519 /* Initialize targetparam list */ 520 iscsi_targetparam_init(); 521 522 /* Initialize ISID */ 523 ihp->hba_isid[0] = ISCSI_SUN_ISID_0; 524 ihp->hba_isid[1] = ISCSI_SUN_ISID_1; 525 ihp->hba_isid[2] = ISCSI_SUN_ISID_2; 526 ihp->hba_isid[3] = ISCSI_SUN_ISID_3; 527 ihp->hba_isid[4] = ISCSI_SUN_ISID_4; 528 ihp->hba_isid[5] = ISCSI_SUN_ISID_5; 529 530 /* Setup iSNS transport services and client */ 531 isns_client_init(); 532 533 /* 534 * initialize the discovery processes and 535 * persistent store. 536 */ 537 ihp->persistent_loaded = B_FALSE; 538 if (iscsid_init(ihp, B_FALSE) == B_FALSE) { 539 goto iscsi_attach_failed0; 540 } 541 542 /* Setup init_port_name for MPAPI */ 543 (void) snprintf(init_port_name, MAX_NAME_PROP_SIZE, 544 "%s,%02x%02x%02x%02x%02x%02x", 545 (char *)ihp->hba_name, ihp->hba_isid[0], 546 ihp->hba_isid[1], ihp->hba_isid[2], 547 ihp->hba_isid[3], ihp->hba_isid[4], 548 ihp->hba_isid[5]); 549 550 if (ddi_prop_update_string(DDI_DEV_T_NONE, dip, 551 "initiator-port", init_port_name) != 552 DDI_PROP_SUCCESS) { 553 cmn_err(CE_WARN, "iscsi_attach: Creating " 554 "initiator-port property on iSCSI " 555 "HBA(%s) with dip(%d) Failed", 556 (char *)ihp->hba_name, 557 ddi_get_instance(dip)); 558 } 559 560 ddi_report_dev(dip); 561 } else { 562 rval = DDI_FAILURE; 563 } 564 break; 565 566 iscsi_attach_failed0: 567 isns_client_cleanup(); 568 if (ihp->stats.ks) { 569 (void) iscsi_hba_kstat_term(ihp); 570 } 571 if (ihp->hba_mpxio_enabled == B_TRUE) { 572 (void) mdi_phci_unregister(dip, 0); 573 } 574 (void) scsi_hba_detach(ihp->hba_dip); 575 iscsi_attach_failed1: 576 ddi_remove_minor_node(dip, NULL); 577 ddi_prop_remove_all(ihp->hba_dip); 578 scsi_hba_tran_free(tran); 579 iscsi_attach_failed2: 580 mutex_destroy(&ihp->hba_discovery_events_mutex); 581 sema_destroy(&ihp->hba_sendtgts_semaphore); 582 rw_destroy(&ihp->hba_sess_list_rwlock); 583 ddi_soft_state_free(iscsi_state, instance); 584 rval = DDI_FAILURE; 585 break; 586 587 case DDI_RESUME: 588 break; 589 590 default: 591 rval = DDI_FAILURE; 592 } 593 594 if (rval != DDI_SUCCESS) { 595 cmn_err(CE_WARN, "iscsi driver unable to attach " 596 "hba instance %d", instance); 597 } 598 599 return (rval); 600 } 601 602 /* 603 * iscsi_detach - called on unload of hba instance 604 */ 605 static int 606 iscsi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 607 { 608 int rval = DDI_SUCCESS; 609 scsi_hba_tran_t *tran = NULL; 610 iscsi_hba_t *ihp = NULL; 611 iscsi_hba_t *ihp_check = NULL; 612 int instance; 613 char *init_node_name; 614 615 instance = ddi_get_instance(dip); 616 617 switch (cmd) { 618 case DDI_DETACH: 619 if (!(tran = (scsi_hba_tran_t *)ddi_get_driver_private(dip))) { 620 rval = DDI_SUCCESS; 621 break; 622 } 623 624 if ((ihp = (iscsi_hba_t *)tran->tran_hba_private) == NULL) { 625 rval = DDI_FAILURE; 626 break; 627 } 628 629 /* 630 * Validate that what is stored by the DDI framework is still 631 * the same state structure referenced by the SCSI framework 632 */ 633 ihp_check = ddi_get_soft_state(iscsi_state, instance); 634 if (ihp_check != ihp) { 635 rval = DDI_FAILURE; 636 break; 637 } 638 639 /* If a session exists we can't safely detach */ 640 rw_enter(&ihp->hba_sess_list_rwlock, RW_READER); 641 if (ihp->hba_sess_list != NULL) { 642 rw_exit(&ihp->hba_sess_list_rwlock); 643 rval = DDI_FAILURE; 644 break; 645 } 646 rw_exit(&ihp->hba_sess_list_rwlock); 647 648 /* Disable all discovery services */ 649 if (iscsid_disable_discovery(ihp, 650 ISCSI_ALL_DISCOVERY_METHODS) == B_FALSE) { 651 /* Disable failed. Fail detach */ 652 rval = DDI_FAILURE; 653 break; 654 } 655 656 /* Deregister from iSNS server(s). */ 657 init_node_name = kmem_zalloc(ISCSI_MAX_NAME_LEN, KM_SLEEP); 658 if (persistent_initiator_name_get(init_node_name, 659 ISCSI_MAX_NAME_LEN) == B_TRUE) { 660 if (strlen(init_node_name) > 0) { 661 (void) isns_dereg(ihp->hba_isid, 662 (uint8_t *)init_node_name); 663 } 664 } 665 kmem_free(init_node_name, ISCSI_MAX_NAME_LEN); 666 init_node_name = NULL; 667 668 /* Cleanup iSNS Client */ 669 isns_client_cleanup(); 670 671 iscsi_targetparam_cleanup(); 672 673 /* Cleanup iscsid resources */ 674 iscsid_fini(); 675 676 if (rval != DDI_SUCCESS) { 677 break; 678 } 679 /* kstat hba. destroy */ 680 KSTAT_DEC_HBA_CNTR_SESS(ihp); 681 682 if (ihp->hba_mpxio_enabled == B_TRUE) { 683 (void) mdi_phci_unregister(dip, 0); 684 } 685 ddi_remove_minor_node(dip, NULL); 686 687 ddi_prop_remove_all(ihp->hba_dip); 688 mutex_destroy(&ihp->hba_discovery_events_mutex); 689 rw_destroy(&ihp->hba_sess_list_rwlock); 690 (void) iscsi_hba_kstat_term(ihp); 691 692 (void) scsi_hba_detach(dip); 693 if (tran != NULL) { 694 scsi_hba_tran_free(tran); 695 } 696 ddi_soft_state_free(iscsi_state, instance); 697 break; 698 default: 699 break; 700 } 701 702 if (rval != DDI_SUCCESS) { 703 cmn_err(CE_WARN, "iscsi driver unable to " 704 "detach hba instance %d", instance); 705 } 706 707 return (rval); 708 } 709 710 /* 711 * +--------------------------------------------------------------------+ 712 * | End of dev_ops routines | 713 * +--------------------------------------------------------------------+ 714 */ 715 716 /* 717 * +--------------------------------------------------------------------+ 718 * | scsi_tran(9E) routines | 719 * +--------------------------------------------------------------------+ 720 */ 721 722 /* 723 * iscsi_tran_lun_init - Find target device based on SCSI device 724 * Based on the information given (SCSI device, target dev_info) find 725 * the target iSCSI device and put a pointer to that information in 726 * the scsi_hba_tran_t structure. 727 */ 728 static int 729 iscsi_tran_lun_init(dev_info_t *hba_dip, dev_info_t *lun_dip, 730 scsi_hba_tran_t *hba_tran, struct scsi_device *sd) 731 { 732 int rval = 0; 733 int type = 0; 734 735 ASSERT(hba_tran->tran_hba_private != NULL); 736 737 /* 738 * Child node is getting initialized. Look at the mpxio component 739 * type on the child device to see if this device is mpxio managed 740 * or not. 741 */ 742 type = mdi_get_component_type(lun_dip); 743 if (type != MDI_COMPONENT_CLIENT) { 744 rval = iscsi_phys_lun_init(hba_dip, lun_dip, hba_tran, sd); 745 } else { 746 rval = iscsi_virt_lun_init(hba_dip, lun_dip, hba_tran, sd); 747 } 748 749 return (rval); 750 } 751 752 /* 753 * iscsi_tran_lun_probe - This function didn't need to be implemented. 754 * We could have left NULL in the tran table. Since this isn't a 755 * performance path this seems safe. We are just wrappering the 756 * function so we can see the call go through if we have debugging 757 * enabled. 758 */ 759 static int 760 iscsi_tran_lun_probe(struct scsi_device *sd, int (*callback) ()) 761 { 762 int rval = 0; 763 764 rval = scsi_hba_probe(sd, callback); 765 766 return (rval); 767 } 768 769 /* 770 * iscsi_init_pkt - Allocate SCSI packet and fill in required info. 771 */ 772 /* ARGSUSED */ 773 static struct scsi_pkt * 774 iscsi_tran_init_pkt(struct scsi_address *ap, struct scsi_pkt *pkt, 775 struct buf *bp, int cmdlen, int statuslen, int tgtlen, int flags, 776 int (*callback) (), caddr_t arg) 777 { 778 iscsi_lun_t *ilp; 779 iscsi_cmd_t *icmdp; 780 781 ASSERT(ap != NULL); 782 ASSERT(callback == NULL_FUNC || callback == SLEEP_FUNC); 783 784 /* 785 * The software stack doesn't have DMA which means the iSCSI 786 * protocol layer will be doing a bcopy from bp to outgoing 787 * streams buffers. Make sure that the buffer is mapped in 788 * so that the copy won't panic the system. 789 */ 790 if (bp && bp_mapin_common(bp, (callback == NULL_FUNC) ? 791 VM_NOSLEEP : VM_SLEEP) == NULL) { 792 return (NULL); 793 } 794 795 ilp = (iscsi_lun_t *)ap->a_hba_tran->tran_tgt_private; 796 ASSERT(ilp != NULL); 797 798 if (pkt == NULL) { 799 pkt = scsi_hba_pkt_alloc(ilp->lun_sess->sess_hba->hba_dip, 800 ap, cmdlen, statuslen, tgtlen, sizeof (iscsi_cmd_t), 801 callback, arg); 802 if (pkt == NULL) { 803 return (NULL); 804 } 805 icmdp = (iscsi_cmd_t *)pkt->pkt_ha_private; 806 icmdp->cmd_sig = ISCSI_SIG_CMD; 807 icmdp->cmd_state = ISCSI_CMD_STATE_FREE; 808 icmdp->cmd_lun = ilp; 809 icmdp->cmd_type = ISCSI_CMD_TYPE_SCSI; 810 /* add the report lun addressing type on to the lun */ 811 icmdp->cmd_un.scsi.lun = ilp->lun_addr_type << 14; 812 icmdp->cmd_un.scsi.lun = icmdp->cmd_un.scsi.lun | 813 ilp->lun_num; 814 icmdp->cmd_un.scsi.pkt = pkt; 815 icmdp->cmd_un.scsi.bp = bp; 816 icmdp->cmd_un.scsi.cmdlen = cmdlen; 817 icmdp->cmd_un.scsi.statuslen = statuslen; 818 icmdp->cmd_crc_error_seen = B_FALSE; 819 icmdp->cmd_internal = B_FALSE; 820 icmdp->cmd_free = B_FALSE; 821 mutex_init(&icmdp->cmd_mutex, NULL, MUTEX_DRIVER, NULL); 822 cv_init(&icmdp->cmd_completion, NULL, CV_DRIVER, NULL); 823 824 pkt->pkt_address = *ap; 825 pkt->pkt_comp = (void (*)())NULL; 826 pkt->pkt_flags = 0; 827 pkt->pkt_time = 0; 828 pkt->pkt_resid = 0; 829 pkt->pkt_statistics = 0; 830 pkt->pkt_reason = 0; 831 } 832 return (pkt); 833 } 834 835 /* 836 * iscsi_tran_lun_free - Free a SCSI LUN 837 */ 838 static void 839 iscsi_tran_lun_free(dev_info_t *hba_dip, dev_info_t *lun_dip, 840 scsi_hba_tran_t *hba_tran, struct scsi_device *sd) 841 { 842 iscsi_lun_t *ilp = NULL; 843 844 ASSERT(hba_dip != NULL); 845 ASSERT(lun_dip != NULL); 846 ASSERT(hba_tran != NULL); 847 ASSERT(sd != NULL); 848 ilp = (iscsi_lun_t *)hba_tran->tran_tgt_private; 849 ASSERT(ilp != NULL); 850 851 (void) mdi_prop_remove(ilp->lun_pip, NULL); 852 } 853 854 /* 855 * iscsi_start -- Start a SCSI transaction based on the packet 856 * This will attempt to add the icmdp to the pending queue 857 * for the connection and kick the queue. If the enqueue 858 * fails that means the queue is full. 859 */ 860 static int 861 iscsi_tran_start(struct scsi_address *ap, struct scsi_pkt *pkt) 862 { 863 iscsi_lun_t *ilp = NULL; 864 iscsi_sess_t *isp = NULL; 865 iscsi_cmd_t *icmdp = NULL; 866 uint_t flags; 867 868 ASSERT(ap != NULL); 869 ASSERT(pkt != NULL); 870 ilp = (iscsi_lun_t *)ap->a_hba_tran->tran_tgt_private; 871 isp = (iscsi_sess_t *)ilp->lun_sess; 872 icmdp = (iscsi_cmd_t *)pkt->pkt_ha_private; 873 flags = pkt->pkt_flags; 874 ASSERT(ilp != NULL); 875 ASSERT(isp != NULL); 876 ASSERT(icmdp != NULL); 877 878 /* 879 * If the session is in the FREE state then 880 * all connections are down and retries have 881 * been exhausted. Fail command with fatal error. 882 */ 883 mutex_enter(&isp->sess_state_mutex); 884 if (isp->sess_state == ISCSI_SESS_STATE_FREE) { 885 mutex_exit(&isp->sess_state_mutex); 886 return (TRAN_FATAL_ERROR); 887 } 888 889 /* 890 * If the session is not in LOGGED_IN then we have 891 * no connections LOGGED_IN, but we haven't exhuasted 892 * our retries. Fail the command with busy so the 893 * caller might try again later. Once retries are 894 * exhausted the state machine will move us to FREE. 895 */ 896 if (isp->sess_state != ISCSI_SESS_STATE_LOGGED_IN) { 897 mutex_exit(&isp->sess_state_mutex); 898 return (TRAN_BUSY); 899 } 900 901 /* 902 * If we haven't received data from the target in the 903 * max specified period something is wrong with the 904 * transport. Fail IO with FATAL_ERROR. 905 */ 906 if (isp->sess_rx_lbolt + SEC_TO_TICK(iscsi_rx_max_window) < 907 ddi_get_lbolt()) { 908 mutex_exit(&isp->sess_state_mutex); 909 return (TRAN_FATAL_ERROR); 910 } 911 912 /* 913 * If we haven't received data from the target in the 914 * specified period something is probably wrong with 915 * the transport. Just return back BUSY until either 916 * the problem is resolved of the transport fails. 917 */ 918 if (isp->sess_rx_lbolt + SEC_TO_TICK(iscsi_rx_window) < 919 ddi_get_lbolt()) { 920 mutex_exit(&isp->sess_state_mutex); 921 return (TRAN_BUSY); 922 } 923 924 925 /* reset cmd values in case upper level driver is retrying cmd */ 926 icmdp->cmd_prev = icmdp->cmd_next = NULL; 927 icmdp->cmd_crc_error_seen = B_FALSE; 928 icmdp->cmd_lbolt_pending = icmdp->cmd_lbolt_active = 929 icmdp->cmd_lbolt_aborting = icmdp->cmd_lbolt_timeout = 930 (clock_t)NULL; 931 icmdp->cmd_itt = icmdp->cmd_ttt = 0; 932 icmdp->cmd_un.scsi.abort_icmdp = NULL; 933 934 mutex_enter(&isp->sess_queue_pending.mutex); 935 iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E1, isp); 936 mutex_exit(&isp->sess_queue_pending.mutex); 937 mutex_exit(&isp->sess_state_mutex); 938 939 /* 940 * If this packet doesn't have FLAG_NOINTR set, it could have 941 * already run to completion (and the memory freed) at this 942 * point, so check our local copy of pkt_flags. Otherwise we 943 * have to wait for completion before returning to the caller. 944 */ 945 if (flags & FLAG_NOINTR) { 946 mutex_enter(&icmdp->cmd_mutex); 947 while ((icmdp->cmd_state != ISCSI_CMD_STATE_COMPLETED) || 948 (icmdp->cmd_un.scsi.r2t_icmdp != NULL) || 949 (icmdp->cmd_un.scsi.abort_icmdp != NULL)) { 950 cv_wait(&icmdp->cmd_completion, &icmdp->cmd_mutex); 951 } 952 icmdp->cmd_state = ISCSI_CMD_STATE_FREE; 953 mutex_exit(&icmdp->cmd_mutex); 954 } 955 956 return (TRAN_ACCEPT); 957 } 958 959 /* 960 * iscsi_tran_abort - Called when an upper level application 961 * or driver wants to kill a scsi_pkt that was already sent to 962 * this driver. 963 */ 964 /* ARGSUSED */ 965 static int 966 iscsi_tran_abort(struct scsi_address *ap, struct scsi_pkt *pkt) 967 { 968 return (0); 969 } 970 971 /* 972 * iscsi_tran_reset - Reset target at either BUS, TARGET, or LUN 973 * level. This will require the issuing of a task management 974 * command down to the target/lun. 975 */ 976 static int 977 iscsi_tran_reset(struct scsi_address *ap, int level) 978 { 979 int rval = ISCSI_STATUS_INTERNAL_ERROR; 980 iscsi_sess_t *isp = NULL; 981 iscsi_lun_t *ilp = NULL; 982 983 ilp = (iscsi_lun_t *)ap->a_hba_tran->tran_tgt_private; 984 ASSERT(ilp != NULL); 985 isp = ilp->lun_sess; 986 ASSERT(isp != NULL); 987 988 switch (level) { 989 case RESET_LUN: 990 /* reset attempt will block until attempt is complete */ 991 rval = iscsi_handle_reset(isp, level, ilp); 992 break; 993 case RESET_BUS: 994 /* 995 * What are we going to realy reset the ethernet 996 * network!? Just fall through to a target reset. 997 */ 998 case RESET_TARGET: 999 /* reset attempt will block until attempt is complete */ 1000 rval = iscsi_handle_reset(isp, level, NULL); 1001 break; 1002 case RESET_ALL: 1003 default: 1004 break; 1005 } 1006 1007 return (ISCSI_SUCCESS(rval) ? 1 : 0); 1008 } 1009 1010 /* 1011 * iscsi_tran_getcap - Get target/lun capabilities. 1012 */ 1013 static int 1014 iscsi_tran_getcap(struct scsi_address *ap, char *cap, int whom) 1015 { 1016 return (iscsi_i_commoncap(ap, cap, 0, whom, 0)); 1017 } 1018 1019 1020 /* 1021 * iscsi_tran_setcap - Set target/lun capabilities. 1022 */ 1023 /* ARGSUSED */ 1024 static int 1025 iscsi_tran_setcap(struct scsi_address *ap, char *cap, int value, int whom) 1026 { 1027 return (iscsi_i_commoncap(ap, cap, 0, whom, 1)); 1028 } 1029 1030 1031 /* 1032 * iscsi_tran_destroy_pkt - Clean up packet 1033 */ 1034 static void 1035 iscsi_tran_destroy_pkt(struct scsi_address *ap, struct scsi_pkt *pkt) 1036 { 1037 iscsi_cmd_t *icmdp; 1038 1039 icmdp = (iscsi_cmd_t *)pkt->pkt_ha_private; 1040 1041 ASSERT(icmdp != NULL); 1042 ASSERT(icmdp->cmd_sig == ISCSI_SIG_CMD); 1043 ASSERT(icmdp->cmd_state == ISCSI_CMD_STATE_FREE); 1044 1045 mutex_destroy(&icmdp->cmd_mutex); 1046 cv_destroy(&icmdp->cmd_completion); 1047 scsi_hba_pkt_free(ap, pkt); 1048 } 1049 1050 /* 1051 * iscsi_tran_dmafree - This is a software driver, NO DMA 1052 */ 1053 /* ARGSUSED */ 1054 static void 1055 iscsi_tran_dmafree(struct scsi_address *ap, struct scsi_pkt *pkt) 1056 { 1057 /* 1058 * The iSCSI interface doesn't deal with DMA 1059 */ 1060 } 1061 1062 /* 1063 * iscsi_tran_sync_pkt - This is a software driver, NO DMA 1064 */ 1065 /* ARGSUSED */ 1066 static void 1067 iscsi_tran_sync_pkt(struct scsi_address *ap, struct scsi_pkt *pkt) 1068 { 1069 /* 1070 * The iSCSI interface doesn't deal with DMA 1071 */ 1072 } 1073 1074 /* 1075 * iscsi_tran_reset_notify - We don't support BUS_RESET so there 1076 * is no point in support callback. 1077 */ 1078 /* ARGSUSED */ 1079 static int 1080 iscsi_tran_reset_notify(struct scsi_address *ap, int flag, 1081 void (*callback) (caddr_t), caddr_t arg) 1082 { 1083 1084 /* 1085 * We never do BUS_RESETS so allowing this call 1086 * back to register has no point? 1087 */ 1088 return (DDI_SUCCESS); 1089 } 1090 1091 1092 /* 1093 * iscsi_tran_bus_config - on demand device configuration 1094 * 1095 * iscsi_tran_bus_config is called by the NDI layer at the completion 1096 * of a dev_node creation. There are two primary cases defined in this 1097 * function. The first is BUS_CONFIG_ALL. In this case the NDI is trying 1098 * to identify that targets/luns are available configured at that point 1099 * in time. It is safe to just complete the process succcessfully. The 1100 * second case is a new case that was defined in S10 for devfs. BUS_CONFIG_ONE 1101 * this is to help driver the top down discovery instead of bottom up. If 1102 * we receive a BUS_CONFIG_ONE we should check to see if the <addr> exists 1103 * if so complete successfull processing. Otherwise we should call the 1104 * deamon and see if we can plumb the <addr>. If it is possible to plumb the 1105 * <addr> block until plumbing is complete. In both cases of being able to 1106 * plumb <addr> or not continue with successfull processing. 1107 */ 1108 static int 1109 iscsi_tran_bus_config(dev_info_t *parent, uint_t flags, 1110 ddi_bus_config_op_t op, void *arg, dev_info_t **childp) 1111 { 1112 int rval = NDI_SUCCESS; 1113 iscsi_hba_t *ihp = NULL; 1114 int iflags = flags; 1115 char *name = NULL; 1116 char *ptr = NULL; 1117 1118 /* get reference to soft state */ 1119 ihp = (iscsi_hba_t *)ddi_get_soft_state(iscsi_state, 1120 ddi_get_instance(parent)); 1121 if (ihp == NULL) { 1122 return (NDI_FAILURE); 1123 } 1124 1125 /* lock so only one config operation occrs */ 1126 sema_p(&iscsid_config_semaphore); 1127 1128 switch (op) { 1129 case BUS_CONFIG_ONE: 1130 /* parse target name out of name given */ 1131 if ((ptr = strchr((char *)arg, '@')) == NULL) { 1132 rval = NDI_FAILURE; 1133 break; 1134 } 1135 ptr++; /* move past '@' */ 1136 name = kmem_zalloc(MAX_GET_NAME_SIZE, KM_SLEEP); 1137 (void) strncpy(name, ptr, MAX_GET_NAME_SIZE); 1138 /* We need to strip the LUN */ 1139 if ((ptr = strchr(name, ',')) == NULL) { 1140 rval = NDI_FAILURE; 1141 kmem_free(name, MAX_GET_NAME_SIZE); 1142 name = NULL; 1143 break; 1144 } 1145 /* We also need to strip the 4 bytes of hex TPGT */ 1146 ptr -= 4; 1147 if (ptr <= name) { 1148 rval = NDI_FAILURE; 1149 kmem_free(name, MAX_GET_NAME_SIZE); 1150 name = NULL; 1151 break; 1152 } 1153 *ptr = '\0'; /* NULL terminate */ 1154 1155 /* translate name back to original iSCSI name */ 1156 iscsi_get_name_to_iqn(name, MAX_GET_NAME_SIZE); 1157 1158 /* configure target, skip 4 byte ISID */ 1159 iscsid_config_one(ihp, (name+4), B_TRUE); 1160 1161 kmem_free(name, MAX_GET_NAME_SIZE); 1162 name = NULL; 1163 1164 /* 1165 * DDI group instructed us to use this flag. 1166 */ 1167 iflags |= NDI_MDI_FALLBACK; 1168 break; 1169 case BUS_CONFIG_DRIVER: 1170 /* FALLTHRU */ 1171 case BUS_CONFIG_ALL: 1172 iscsid_config_all(ihp, B_TRUE); 1173 break; 1174 default: 1175 rval = NDI_FAILURE; 1176 break; 1177 } 1178 1179 if (rval == NDI_SUCCESS) { 1180 rval = ndi_busop_bus_config(parent, iflags, 1181 op, arg, childp, 0); 1182 } 1183 sema_v(&iscsid_config_semaphore); 1184 1185 return (rval); 1186 } 1187 1188 /* 1189 * iscsi_tran_bus_unconfig - on demand device unconfiguration 1190 * 1191 * Called by the os framework under low resource situations. 1192 * It will attempt to unload our minor nodes (logical units 1193 * ndi/mdi nodes). 1194 */ 1195 static int 1196 iscsi_tran_bus_unconfig(dev_info_t *parent, uint_t flag, 1197 ddi_bus_config_op_t op, void *arg) 1198 { 1199 return (ndi_busop_bus_unconfig(parent, flag, op, arg)); 1200 } 1201 1202 1203 /* 1204 * iscsi_tran_get_name - create private /devices name for LUN 1205 * 1206 * This creates the <addr> in /devices/iscsi/<driver>@<addr> 1207 * path. For this <addr> we return the <session/target_name>,<lun num> 1208 * Where <target_name> is an <iqn/eui/...> as defined by the iSCSI 1209 * specification. We do modify the name slightly so that it still 1210 * complies with the IEEE <addr> naming scheme. This means that we 1211 * will substitute out the ':', '@', ... and other reserved characters 1212 * defined in the IEEE definition with '%<hex value of special char>' 1213 * This routine is indirectly called by iscsi_lun_create_xxx. These 1214 * calling routines must prevent the session and lun lists from changing 1215 * during this routine. 1216 */ 1217 static int 1218 iscsi_tran_get_name(struct scsi_device *sd, char *name, int len) 1219 { 1220 int target = 0; 1221 int lun = 0; 1222 iscsi_hba_t *ihp = NULL; 1223 iscsi_sess_t *isp = NULL; 1224 iscsi_lun_t *ilp = NULL; 1225 dev_info_t *lun_dip = NULL; 1226 1227 ASSERT(sd != NULL); 1228 ASSERT(name != NULL); 1229 lun_dip = sd->sd_dev; 1230 ASSERT(lun_dip != NULL); 1231 1232 /* get reference to soft state */ 1233 ihp = (iscsi_hba_t *)ddi_get_soft_state(iscsi_state, 1234 ddi_get_instance(ddi_get_parent(lun_dip))); 1235 if (ihp == NULL) { 1236 name[0] = '\0'; 1237 return (0); 1238 } 1239 1240 /* Get the target num */ 1241 target = ddi_prop_get_int(DDI_DEV_T_ANY, sd->sd_dev, 1242 DDI_PROP_DONTPASS, TARGET_PROP, 0); 1243 1244 /* Get the target num */ 1245 lun = ddi_prop_get_int(DDI_DEV_T_ANY, sd->sd_dev, 1246 DDI_PROP_DONTPASS, LUN_PROP, 0); 1247 1248 /* 1249 * Now we need to find our ilp by walking the lists 1250 * off the ihp and isp. 1251 */ 1252 /* See if we already created this session */ 1253 1254 /* Walk the HBA's session list */ 1255 for (isp = ihp->hba_sess_list; isp; isp = isp->sess_next) { 1256 /* compare target name as the unique identifier */ 1257 if (target == isp->sess_oid) { 1258 /* found match */ 1259 break; 1260 } 1261 } 1262 1263 /* If we found matching session continue searching for tgt */ 1264 if (isp == NULL) { 1265 /* sess not found */ 1266 name[0] = '\0'; 1267 return (0); 1268 } 1269 1270 /* 1271 * Search for the matching iscsi lun structure. We don't 1272 * need to hold the READER for the lun list at this point. 1273 * because the tran_get_name is being called from the online 1274 * function which is already holding a reader on the lun 1275 * list. 1276 */ 1277 for (ilp = isp->sess_lun_list; ilp; ilp = ilp->lun_next) { 1278 if (lun == ilp->lun_num) { 1279 /* found match */ 1280 break; 1281 } 1282 } 1283 1284 if (ilp == NULL) { 1285 /* tgt not found */ 1286 name[0] = '\0'; 1287 return (0); 1288 } 1289 1290 /* Ensure enough space for lun_addr is available */ 1291 ASSERT(ilp->lun_addr != NULL); 1292 if ((strlen(ilp->lun_addr) + 1) > len) { 1293 return (0); 1294 } 1295 1296 /* copy lun_addr name */ 1297 (void) strcpy(name, ilp->lun_addr); 1298 1299 /* 1300 * Based on IEEE-1275 we can't have any ':', ' ', '@', or '/' 1301 * characters in our naming. So replace all those characters 1302 * with '-' 1303 */ 1304 iscsi_get_name_from_iqn(name, len); 1305 1306 return (1); 1307 } 1308 1309 /* 1310 * iscsi_tran_get_bus_addr - This returns a human readable string 1311 * for the bus address. Examining most other drivers fcp, etc. They 1312 * all just return the same string as tran_get_name. In our case 1313 * our tran get name is already some what usable so leave alone. 1314 */ 1315 static int 1316 iscsi_tran_get_bus_addr(struct scsi_device *sd, char *name, int len) 1317 { 1318 return (iscsi_tran_get_name(sd, name, len)); 1319 } 1320 1321 1322 /* 1323 * +--------------------------------------------------------------------+ 1324 * | End of scsi_tran routines | 1325 * +--------------------------------------------------------------------+ 1326 */ 1327 1328 /* 1329 * +--------------------------------------------------------------------+ 1330 * | Start of cb_ops routines | 1331 * +--------------------------------------------------------------------+ 1332 */ 1333 1334 /* 1335 * iscsi_open - Driver should be made IOCTL MT safe. Otherwise 1336 * this function needs updated. 1337 */ 1338 /* ARGSUSED */ 1339 static int 1340 iscsi_open(dev_t *devp, int flags, int otyp, cred_t *credp) 1341 { 1342 return (0); 1343 } 1344 1345 /* 1346 * iscsi_close - 1347 */ 1348 /* ARGSUSED */ 1349 static int 1350 iscsi_close(dev_t dev, int flags, int otyp, cred_t *credp) 1351 { 1352 return (0); 1353 } 1354 1355 /* 1356 * iscsi_ioctl - 1357 */ 1358 /* ARGSUSED */ 1359 int 1360 iscsi_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 1361 cred_t *credp, int *rvalp) 1362 { 1363 int rtn = 0; 1364 int instance = 0; 1365 int list_space = 0; 1366 int lun_sz = 0; 1367 int did; 1368 iscsi_hba_t *ihp = NULL; 1369 iscsi_sess_t *isp = NULL; 1370 iscsi_conn_t *icp = NULL; 1371 iscsi_login_params_t *params = NULL; 1372 iscsi_login_params_t *tmpParams = NULL; 1373 uchar_t *name = NULL; 1374 dev_info_t *lun_dip = NULL; 1375 1376 entry_t e; 1377 iscsi_oid_t oid; 1378 iscsi_property_t *ipp; 1379 iscsi_static_property_t *ispp; 1380 iscsi_param_get_t *ilg; 1381 iscsi_param_set_t *ils; 1382 iscsi_target_list_t idl, *idlp = NULL; 1383 iscsi_addr_list_t ial, *ialp = NULL; 1384 iscsi_chap_props_t *chap = NULL; 1385 iscsi_radius_props_t *radius = NULL; 1386 iscsi_auth_props_t *auth = NULL; 1387 iscsi_lun_list_t *ll, *llp = NULL; 1388 iscsi_lun_props_t *lun = NULL; 1389 iscsi_lun_t *ilp = NULL; 1390 iSCSIDiscoveryMethod_t method; 1391 iSCSIDiscoveryProperties_t discovery_props; 1392 iscsi_uscsi_t iu; 1393 iscsi_uscsi_t iu_caller; 1394 #ifdef _MULTI_DATAMODEL 1395 /* For use when a 32 bit app makes a call into a 64 bit ioctl */ 1396 iscsi_uscsi32_t iu32_caller; 1397 model_t model; 1398 #endif /* _MULTI_DATAMODEL */ 1399 void *void_p; 1400 iscsi_sendtgts_list_t *stl_hdr; 1401 iscsi_sendtgts_list_t *istl; 1402 int stl_sz; 1403 iscsi_target_entry_t *target; 1404 uint32_t old_oid; 1405 uint32_t target_oid; 1406 iscsi_targetparam_entry_t *curr_entry; 1407 char *initiator_node_name; 1408 char *initiator_node_alias; 1409 isns_portal_group_list_t *pg_list = NULL; 1410 isns_server_portal_group_list_t *server_pg_list_hdr = NULL; 1411 isns_server_portal_group_list_t *server_pg_list = NULL; 1412 int pg_list_sz, pg_sz_copy_out, server_pg_list_sz; 1413 iscsi_config_sess_t *ics; 1414 int size; 1415 boolean_t rval; 1416 char init_port_name[MAX_NAME_PROP_SIZE]; 1417 iscsi_sockaddr_t addr_dsc; 1418 iscsi_boot_property_t *bootProp; 1419 1420 instance = getminor(dev); 1421 ihp = (iscsi_hba_t *)ddi_get_soft_state(iscsi_state, instance); 1422 if (ihp == NULL) 1423 return (EFAULT); 1424 1425 switch (cmd) { 1426 /* 1427 * ISCSI_CREATE_OID - Create a Object IDentifier for a TargetName 1428 */ 1429 case ISCSI_CREATE_OID: 1430 if (ddi_copyin((caddr_t)arg, &oid, sizeof (oid), mode)) { 1431 rtn = EFAULT; 1432 break; 1433 } 1434 if (oid.o_vers != ISCSI_INTERFACE_VERSION) { 1435 rtn = EINVAL; 1436 break; 1437 } 1438 1439 /* Set the target that this session is associated with */ 1440 oid.o_oid = iscsi_targetparam_get_oid(oid.o_name); 1441 1442 if (ddi_copyout(&oid, (caddr_t)arg, sizeof (oid), mode)) { 1443 rtn = EFAULT; 1444 break; 1445 } 1446 break; 1447 /* 1448 * ISCSI_PARAM_GET - Get param for specified 1449 * connection/session. 1450 */ 1451 case ISCSI_PARAM_GET: 1452 /* copyin user args */ 1453 ilg = (iscsi_param_get_t *)kmem_alloc(sizeof (*ilg), KM_SLEEP); 1454 if (ddi_copyin((caddr_t)arg, ilg, sizeof (*ilg), mode)) { 1455 rtn = EFAULT; 1456 kmem_free(ilg, sizeof (*ilg)); 1457 break; 1458 } 1459 1460 if (ilg->g_vers != ISCSI_INTERFACE_VERSION) { 1461 rtn = EINVAL; 1462 kmem_free(ilg, sizeof (*ilg)); 1463 break; 1464 } 1465 1466 /* handle special case for Initiator name */ 1467 if (ilg->g_param == ISCSI_LOGIN_PARAM_INITIATOR_NAME) { 1468 (void) strlcpy((char *)ilg->g_value.v_name, 1469 (char *)ihp->hba_name, ISCSI_MAX_NAME_LEN); 1470 } else if (ilg->g_param == ISCSI_LOGIN_PARAM_INITIATOR_ALIAS) { 1471 if (ihp->hba_alias_length == 0) { 1472 rtn = EINVAL; 1473 } else { 1474 (void) strlcpy((char *)ilg->g_value.v_name, 1475 (char *)ihp->hba_alias, ISCSI_MAX_NAME_LEN); 1476 } 1477 } else { 1478 /* To describe the validity of the requested param */ 1479 boolean_t valid_flag = B_TRUE; 1480 1481 name = NULL; 1482 1483 /* 1484 * switch login based if looking for initiator 1485 * params 1486 */ 1487 rw_enter(&ihp->hba_sess_list_rwlock, RW_READER); 1488 if (ilg->g_oid == ihp->hba_oid) { 1489 /* initiator */ 1490 params = &ihp->hba_params; 1491 name = ihp->hba_name; 1492 if (iscsi_get_persisted_param(name, 1493 ilg, params) != 0) { 1494 valid_flag = B_FALSE; 1495 } 1496 } else { 1497 /* 1498 * If the oid does represent a session check 1499 * to see if it is a target oid. If so, 1500 * return the target's associated session. 1501 */ 1502 rtn = iscsi_sess_get(ilg->g_oid, ihp, &isp); 1503 if (rtn != 0) { 1504 rtn = iscsi_sess_get_by_target( 1505 ilg->g_oid, ihp, &isp); 1506 } 1507 1508 /* 1509 * If rtn is zero then we have found an 1510 * existing session. Use the session name to 1511 * do param lookup. If rtn is non-zero then 1512 * create a targetparam object and use its name 1513 * for param lookup. 1514 */ 1515 if (rtn == 0) { 1516 name = isp->sess_name; 1517 params = &isp->sess_params; 1518 } else { 1519 name = 1520 iscsi_targetparam_get_name( 1521 ilg->g_oid); 1522 if (ilg->g_param_type == 1523 ISCSI_SESS_PARAM) { 1524 tmpParams = 1525 (iscsi_login_params_t *) 1526 kmem_alloc( 1527 sizeof (*tmpParams), 1528 KM_SLEEP); 1529 params = tmpParams; 1530 } 1531 rtn = 0; 1532 } 1533 1534 if (name == NULL) { 1535 rw_exit( 1536 &ihp->hba_sess_list_rwlock); 1537 rtn = EFAULT; 1538 kmem_free(ilg, sizeof (*ilg)); 1539 if (tmpParams != NULL) 1540 kmem_free(tmpParams, 1541 sizeof (*tmpParams)); 1542 1543 break; 1544 } 1545 1546 if (ilg->g_param_type == ISCSI_SESS_PARAM) { 1547 /* session */ 1548 /* 1549 * Update sess_params with the 1550 * latest params from the 1551 * persistent store. 1552 */ 1553 if (iscsi_get_persisted_param(name, 1554 ilg, params) != 0) { 1555 /* 1556 * If the parameter in 1557 * question is not 1558 * overriden, no effect 1559 * on existing session 1560 * parameters. However, 1561 * the parameter is 1562 * marked invalid 1563 * (from the standpoint 1564 * of whether it is 1565 * overriden). 1566 */ 1567 valid_flag = B_FALSE; 1568 } 1569 } else if (ilg->g_param_type == 1570 ISCSI_CONN_PARAM && isp != NULL) { 1571 /* connection */ 1572 rw_enter(&isp->sess_conn_list_rwlock, 1573 RW_READER); 1574 /* Assuming 1 conn per sess. */ 1575 /* 1576 * MC/S - Need to be modified to 1577 * take g_conn_cid into account when 1578 * we go multi-connection. 1579 */ 1580 if ((isp->sess_conn_act != NULL) && 1581 (isp->sess_conn_act->conn_state == 1582 ISCSI_CONN_STATE_LOGGED_IN)) { 1583 params = &(isp-> 1584 sess_conn_act-> 1585 conn_params); 1586 } else { 1587 valid_flag = B_FALSE; 1588 } 1589 rw_exit(&isp->sess_conn_list_rwlock); 1590 } 1591 } 1592 1593 /* make sure we have params to get info from */ 1594 if (params) { 1595 rtn = iscsi_get_param(params, valid_flag, ilg); 1596 1597 /* 1598 * for target parameters, check if any 1599 * parameters were overridden at the initiator 1600 * level. If so, then change the default value 1601 * to the initiator's overridden value 1602 */ 1603 if ((rtn == 0) && 1604 (ilg->g_oid != ihp->hba_oid)) { 1605 iscsi_override_target_default(ihp, 1606 ilg); 1607 } 1608 } 1609 rw_exit(&ihp->hba_sess_list_rwlock); 1610 } 1611 1612 if (rtn == 0) { 1613 rtn = ddi_copyout(ilg, (caddr_t)arg, 1614 sizeof (iscsi_param_get_t), mode); 1615 } 1616 kmem_free(ilg, sizeof (*ilg)); 1617 if (tmpParams != NULL) 1618 kmem_free(tmpParams, sizeof (*tmpParams)); 1619 break; 1620 1621 /* 1622 * ISCSI_INIT_NODE_NAME_SET - Change the initiator-node name for 1623 * the specified connection/session. 1624 */ 1625 case ISCSI_INIT_NODE_NAME_SET: 1626 /* copyin user args */ 1627 ils = (iscsi_param_set_t *)kmem_alloc(sizeof (*ils), KM_SLEEP); 1628 if (ddi_copyin((caddr_t)arg, ils, sizeof (*ils), mode)) { 1629 rtn = EFAULT; 1630 kmem_free(ils, sizeof (*ils)); 1631 break; 1632 } 1633 1634 if (ils->s_vers != ISCSI_INTERFACE_VERSION) { 1635 rtn = EINVAL; 1636 kmem_free(ils, sizeof (*ils)); 1637 break; 1638 } 1639 1640 /* saving off the old initiator-node name */ 1641 initiator_node_name = kmem_zalloc(ISCSI_MAX_NAME_LEN, KM_SLEEP); 1642 rval = persistent_initiator_name_get(initiator_node_name, 1643 ISCSI_MAX_NAME_LEN); 1644 1645 rtn = iscsi_set_params(ils, ihp, B_TRUE); 1646 kmem_free(ils, sizeof (*ils)); 1647 if (rtn != 0) { 1648 kmem_free(initiator_node_name, ISCSI_MAX_NAME_LEN); 1649 return (rtn); 1650 } 1651 1652 (void) snprintf(init_port_name, MAX_NAME_PROP_SIZE, 1653 "%s,%02x%02x%02x%02x%02x%02x", 1654 (char *)ihp->hba_name, ihp->hba_isid[0], 1655 ihp->hba_isid[1], ihp->hba_isid[2], 1656 ihp->hba_isid[3], ihp->hba_isid[4], 1657 ihp->hba_isid[5]); 1658 1659 if (ddi_prop_update_string(DDI_DEV_T_NONE, 1660 ihp->hba_dip, "initiator-port", 1661 init_port_name) != DDI_PROP_SUCCESS) { 1662 cmn_err(CE_WARN, "iscsi_ioctl: Updating " 1663 "initiator-port property on iSCSI " 1664 "HBA(%s) with dip(%d) Failed", 1665 (char *)ihp->hba_name, 1666 ddi_get_instance(ihp->hba_dip)); 1667 } 1668 1669 /* 1670 * Deregister the old initiator-node name from the iSNS 1671 * server 1672 * Register the new initiator-node name with the iSNS server 1673 */ 1674 method = persistent_disc_meth_get(); 1675 if (method & iSCSIDiscoveryMethodISNS) { 1676 if (rval == B_TRUE) { 1677 if (strlen(initiator_node_name) > 0) { 1678 /* 1679 * we will attempt to offline the targets. 1680 * if logouts fail, we will still continue 1681 */ 1682 #define STRING_INNO "initiator-node name - Offline " 1683 #define STRING_FFOMD "failed for one or more devices" 1684 if ((iscsid_del( 1685 ihp, NULL, method, NULL)) 1686 != B_TRUE) { 1687 cmn_err(CE_NOTE, 1688 "Attempting to change " 1689 STRING_INNO 1690 STRING_FFOMD); 1691 } 1692 (void) isns_dereg(ihp->hba_isid, 1693 (uint8_t *)initiator_node_name); 1694 #undef STRING_INNO 1695 #undef STRING_FFOMD 1696 } 1697 } 1698 if (persistent_initiator_name_get(initiator_node_name, 1699 ISCSI_MAX_NAME_LEN) != B_TRUE) { 1700 kmem_free(initiator_node_name, 1701 ISCSI_MAX_NAME_LEN); 1702 initiator_node_name = NULL; 1703 rtn = EIO; 1704 break; 1705 } 1706 if (strlen(initiator_node_name) == 0) { 1707 kmem_free(initiator_node_name, 1708 ISCSI_MAX_NAME_LEN); 1709 initiator_node_name = NULL; 1710 rtn = EIO; 1711 break; 1712 } 1713 1714 initiator_node_alias = kmem_zalloc(ISCSI_MAX_NAME_LEN, 1715 KM_SLEEP); 1716 if (persistent_alias_name_get(initiator_node_alias, 1717 ISCSI_MAX_NAME_LEN) != B_TRUE) { 1718 initiator_node_alias[0] = '\0'; 1719 } 1720 1721 (void) isns_reg(ihp->hba_isid, 1722 (uint8_t *)initiator_node_name, 1723 ISCSI_MAX_NAME_LEN, 1724 (uint8_t *)initiator_node_alias, 1725 ISCSI_MAX_NAME_LEN, 1726 ISNS_INITIATOR_NODE_TYPE, 1727 isns_scn_callback); 1728 iscsid_do_isns_query(ihp); 1729 1730 /* Done using the name and alias - free them. */ 1731 kmem_free(initiator_node_name, ISCSI_MAX_NAME_LEN); 1732 initiator_node_name = NULL; 1733 kmem_free(initiator_node_alias, ISCSI_MAX_NAME_LEN); 1734 initiator_node_alias = NULL; 1735 } 1736 break; 1737 1738 /* 1739 * ISCSI_PARAM_SET - Set param for specified connection/session. 1740 */ 1741 case ISCSI_PARAM_SET: 1742 /* copyin user args */ 1743 ils = (iscsi_param_set_t *)kmem_alloc(sizeof (*ils), KM_SLEEP); 1744 if (ddi_copyin((caddr_t)arg, ils, sizeof (*ils), mode)) { 1745 rtn = EFAULT; 1746 kmem_free(ils, sizeof (*ils)); 1747 break; 1748 } 1749 1750 if (ils->s_vers != ISCSI_INTERFACE_VERSION) { 1751 rtn = EINVAL; 1752 kmem_free(ils, sizeof (*ils)); 1753 break; 1754 } 1755 rtn = iscsi_set_params(ils, ihp, B_TRUE); 1756 if (iscsiboot_prop) { 1757 if (iscsi_cmp_boot_sess_oid(ihp, ils->s_oid)) { 1758 /* 1759 * found active session for this object 1760 * or this is initiator's object 1761 * with mpxio enabled 1762 */ 1763 if (!iscsi_reconfig_boot_sess(ihp)) { 1764 rtn = EINVAL; 1765 kmem_free(ils, sizeof (*ils)); 1766 break; 1767 } 1768 } 1769 } 1770 kmem_free(ils, sizeof (*ils)); 1771 break; 1772 1773 /* 1774 * ISCSI_TARGET_PARAM_CLEAR 1775 * - remove custom parameter settings for a target. 1776 */ 1777 case ISCSI_TARGET_PARAM_CLEAR: 1778 if (ddi_copyin((caddr_t)arg, &e, sizeof (e), mode)) { 1779 rtn = EFAULT; 1780 break; 1781 } else if (e.e_vers != ISCSI_INTERFACE_VERSION) { 1782 rtn = EINVAL; 1783 break; 1784 } 1785 1786 if ((e.e_oid != ihp->hba_oid) && 1787 (e.e_oid != ISCSI_OID_NOTSET)) { 1788 uchar_t *t_name; 1789 iscsi_sess_t *t_isp; 1790 1791 rw_enter(&ihp->hba_sess_list_rwlock, RW_READER); 1792 /* 1793 * If the oid does represent a session check to see 1794 * if it is a target oid. If so, return the target's 1795 * associated session. 1796 */ 1797 rtn = iscsi_sess_get(e.e_oid, ihp, &isp); 1798 if (rtn != 0) { 1799 rtn = iscsi_sess_get_by_target(e.e_oid, ihp, 1800 &isp); 1801 } 1802 1803 /* 1804 * If rtn is zero then we have found an 1805 * existing session. Use the session name to 1806 * do param lookup. If rtn is non-zero then 1807 * create a targetparam object and use its name 1808 * for param lookup. 1809 */ 1810 if (rtn == 0) { 1811 t_name = isp->sess_name; 1812 } else { 1813 t_name = iscsi_targetparam_get_name(e.e_oid); 1814 rtn = 0; 1815 } 1816 1817 if (t_name == NULL) { 1818 rw_exit(&ihp->hba_sess_list_rwlock); 1819 rtn = EFAULT; 1820 break; 1821 } 1822 1823 name = kmem_zalloc(ISCSI_MAX_NAME_LEN, KM_SLEEP); 1824 (void) strncpy((char *)name, (char *)t_name, 1825 ISCSI_MAX_NAME_LEN); 1826 1827 if (persistent_param_clear((char *)name) == B_FALSE) { 1828 kmem_free(name, ISCSI_MAX_NAME_LEN); 1829 rw_exit(&ihp->hba_sess_list_rwlock); 1830 rtn = EIO; 1831 break; 1832 } 1833 1834 ics = kmem_zalloc(sizeof (*ics), KM_SLEEP); 1835 ics->ics_ver = ISCSI_INTERFACE_VERSION; 1836 ics->ics_oid = ISCSI_INITIATOR_OID; 1837 ics->ics_in = 1; 1838 1839 /* 1840 * We may have multiple sessions with different 1841 * tpgt values. So we need to loop through 1842 * the sessions and update all sessions. 1843 */ 1844 for (isp = ihp->hba_sess_list; isp; 1845 isp = t_isp) { 1846 t_isp = isp->sess_next; 1847 1848 if (strncmp((char *)isp->sess_name, 1849 (char *)name, ISCSI_MAX_NAME_LEN) == 0) { 1850 /* 1851 * When removing target-params we need 1852 * slightly different actions depending 1853 * on if the session should still exist. 1854 * Get the initiator-node value for 1855 * MS/T. If there is no initiator 1856 * value then assume the default value 1857 * of 1. If the initiator value is 1858 * less than this ISID then we need to 1859 * destroy the session. Otherwise 1860 * update the session information and 1861 * resync (N7 event). 1862 */ 1863 rtn = iscsi_ioctl_get_config_sess( 1864 ihp, ics); 1865 if (((rtn != 0) && 1866 (isp->sess_isid[5] > 0)) || 1867 ((rtn == 0) && 1868 (ics->ics_out <= 1869 isp->sess_isid[5]))) { 1870 1871 /* 1872 * This session should no 1873 * longer exist. Remove 1874 * session. 1875 */ 1876 if (!ISCSI_SUCCESS( 1877 iscsi_sess_destroy(isp))) { 1878 kmem_free(ics, 1879 sizeof (*ics)); 1880 kmem_free(name, 1881 ISCSI_MAX_NAME_LEN); 1882 rw_exit(&ihp-> 1883 hba_sess_list_rwlock); 1884 rtn = EBUSY; 1885 break; 1886 } 1887 isp = ihp->hba_sess_list; 1888 } else { 1889 /* 1890 * Reset the session 1891 * parameters. 1892 */ 1893 bcopy(&(isp->sess_hba-> 1894 hba_params), 1895 &(isp->sess_params), 1896 sizeof (isp->sess_params)); 1897 if (iscsiboot_prop && 1898 isp->sess_boot) { 1899 /* 1900 * reconfig boot 1901 * session later 1902 */ 1903 continue; 1904 } 1905 /* 1906 * Notify the session that the 1907 * login parameters have 1908 * changed. 1909 */ 1910 mutex_enter(&isp-> 1911 sess_state_mutex); 1912 iscsi_sess_state_machine(isp, 1913 ISCSI_SESS_EVENT_N7); 1914 mutex_exit(&isp-> 1915 sess_state_mutex); 1916 } 1917 } 1918 } 1919 kmem_free(ics, sizeof (*ics)); 1920 kmem_free(name, ISCSI_MAX_NAME_LEN); 1921 rw_exit(&ihp->hba_sess_list_rwlock); 1922 if (iscsiboot_prop) { 1923 if (iscsi_cmp_boot_sess_oid(ihp, e.e_oid)) { 1924 /* 1925 * found active session for this object 1926 * or this is initiator object 1927 * with mpxio enabled 1928 */ 1929 if (!iscsi_reconfig_boot_sess(ihp)) { 1930 rtn = EINVAL; 1931 break; 1932 } 1933 } 1934 } 1935 } 1936 break; 1937 1938 /* 1939 * ISCSI_TARGET_OID_LIST_GET - 1940 */ 1941 case ISCSI_TARGET_OID_LIST_GET: 1942 /* copyin user args */ 1943 if (ddi_copyin((caddr_t)arg, &idl, 1944 sizeof (idl), mode)) { 1945 rtn = EFAULT; 1946 break; 1947 } 1948 1949 if (idl.tl_vers != ISCSI_INTERFACE_VERSION) { 1950 rtn = EINVAL; 1951 break; 1952 } 1953 1954 list_space = sizeof (iscsi_target_list_t); 1955 if (idl.tl_in_cnt != 0) 1956 list_space += (sizeof (uint32_t) * 1957 (idl.tl_in_cnt - 1)); 1958 1959 idlp = kmem_zalloc(list_space, KM_SLEEP); 1960 bcopy(&idl, idlp, sizeof (idl)); 1961 idlp->tl_out_cnt = 0; 1962 1963 /* 1964 * If target list type is ISCSI_TGT_OID_LIST and discovery 1965 * has not been completed or in progress, poke the discovery 1966 * methods so target information is returned 1967 */ 1968 mutex_enter(&ihp->hba_discovery_events_mutex); 1969 method = ihp->hba_discovery_events; 1970 if ((idl.tl_tgt_list_type == ISCSI_TGT_OID_LIST) && 1971 (method != ISCSI_ALL_DISCOVERY_METHODS) && 1972 (ihp->hba_discovery_in_progress == B_FALSE)) { 1973 ihp->hba_discovery_in_progress = B_TRUE; 1974 mutex_exit(&ihp->hba_discovery_events_mutex); 1975 iscsid_poke_discovery(ihp, iSCSIDiscoveryMethodUnknown); 1976 mutex_enter(&ihp->hba_discovery_events_mutex); 1977 ihp->hba_discovery_in_progress = B_FALSE; 1978 } 1979 mutex_exit(&ihp->hba_discovery_events_mutex); 1980 1981 /* 1982 * Return the correct list information based on the type 1983 */ 1984 switch (idl.tl_tgt_list_type) { 1985 /* ISCSI_TGT_PARAM_OID_LIST - iscsiadm list target-params */ 1986 case ISCSI_TGT_PARAM_OID_LIST: 1987 /* get params from persistent store */ 1988 iscsi_targetparam_lock_list(RW_READER); 1989 curr_entry = iscsi_targetparam_get_next_entry(NULL); 1990 while (curr_entry != NULL) { 1991 if (idlp->tl_out_cnt < idlp->tl_in_cnt) { 1992 idlp->tl_oid_list[idlp->tl_out_cnt] = 1993 curr_entry->target_oid; 1994 } 1995 idlp->tl_out_cnt++; 1996 curr_entry = iscsi_targetparam_get_next_entry( 1997 curr_entry); 1998 } 1999 iscsi_targetparam_unlock_list(); 2000 break; 2001 2002 /* ISCSI_STATIC_TGT_OID_LIST - iscsiadm list static-config */ 2003 case ISCSI_STATIC_TGT_OID_LIST: 2004 { 2005 char *target_name = NULL; 2006 void *v = NULL; 2007 2008 /* get static-config from persistent store */ 2009 target_name = kmem_zalloc(ISCSI_MAX_NAME_LEN, KM_SLEEP); 2010 persistent_static_addr_lock(); 2011 while (persistent_static_addr_next(&v, 2012 (char *)target_name, &e) == B_TRUE) { 2013 2014 if (idlp->tl_out_cnt < idlp->tl_in_cnt) { 2015 idlp->tl_oid_list[idlp->tl_out_cnt] = 2016 e.e_oid; 2017 } 2018 idlp->tl_out_cnt++; 2019 2020 } 2021 2022 persistent_static_addr_unlock(); 2023 kmem_free(target_name, ISCSI_MAX_NAME_LEN); 2024 break; 2025 } 2026 2027 /* ISCSI_TGT_OID_LIST - iscsiadm list target */ 2028 case ISCSI_TGT_OID_LIST: 2029 2030 /* get sessions from hba's session list */ 2031 rw_enter(&ihp->hba_sess_list_rwlock, RW_READER); 2032 for (isp = ihp->hba_sess_list; isp; 2033 isp = isp->sess_next) { 2034 2035 if (((isp->sess_state != 2036 ISCSI_SESS_STATE_FREE) || 2037 (isp->sess_discovered_by != 2038 iSCSIDiscoveryMethodUnknown)) && 2039 (isp->sess_type == 2040 ISCSI_SESS_TYPE_NORMAL)) { 2041 if (idlp->tl_out_cnt < 2042 idlp->tl_in_cnt) { 2043 idlp->tl_oid_list[ 2044 idlp->tl_out_cnt] = 2045 isp->sess_oid; 2046 } 2047 idlp->tl_out_cnt++; 2048 } 2049 2050 } 2051 rw_exit(&ihp->hba_sess_list_rwlock); 2052 break; 2053 2054 default: 2055 ASSERT(FALSE); 2056 } 2057 2058 rtn = ddi_copyout(idlp, (caddr_t)arg, list_space, mode); 2059 kmem_free(idlp, list_space); 2060 break; 2061 2062 /* 2063 * ISCSI_TARGET_PROPS_GET - 2064 */ 2065 case ISCSI_TARGET_PROPS_GET: 2066 /* ---- fall through sense the code is almost the same ---- */ 2067 2068 /* 2069 * ISCSI_TARGET_PROPS_SET - 2070 */ 2071 case ISCSI_TARGET_PROPS_SET: 2072 /* copyin user args */ 2073 ipp = (iscsi_property_t *)kmem_alloc(sizeof (*ipp), 2074 KM_SLEEP); 2075 if (ddi_copyin((caddr_t)arg, ipp, sizeof (*ipp), mode)) { 2076 rtn = EFAULT; 2077 kmem_free(ipp, sizeof (*ipp)); 2078 break; 2079 } 2080 2081 if (ipp->p_vers != ISCSI_INTERFACE_VERSION) { 2082 rtn = EINVAL; 2083 kmem_free(ipp, sizeof (*ipp)); 2084 break; 2085 } 2086 2087 rtn = iscsi_target_prop_mod(ihp, ipp, cmd); 2088 if (rtn == 0) 2089 rtn = ddi_copyout(ipp, (caddr_t)arg, 2090 sizeof (*ipp), mode); 2091 kmem_free(ipp, sizeof (*ipp)); 2092 break; 2093 2094 /* 2095 * ISCSI_TARGET_ADDRESS_GET - 2096 */ 2097 case ISCSI_TARGET_ADDRESS_GET: 2098 if (ddi_copyin((caddr_t)arg, &ial, sizeof (ial), mode)) { 2099 rtn = EFAULT; 2100 break; 2101 } 2102 2103 if (ial.al_vers != ISCSI_INTERFACE_VERSION) { 2104 rtn = EINVAL; 2105 break; 2106 } 2107 2108 /* 2109 * Find out how much space we need to malloc for the users 2110 * request. 2111 */ 2112 list_space = sizeof (iscsi_addr_list_t); 2113 if (ial.al_in_cnt != 0) { 2114 list_space += (sizeof (iscsi_addr_t) * 2115 (ial.al_in_cnt - 1)); 2116 } 2117 ialp = (iscsi_addr_list_t *)kmem_zalloc(list_space, KM_SLEEP); 2118 2119 /* Copy in the header portion */ 2120 bcopy(&ial, ialp, sizeof (ial)); 2121 2122 /* session */ 2123 rw_enter(&ihp->hba_sess_list_rwlock, RW_READER); 2124 rtn = iscsi_sess_get(ialp->al_oid, ihp, &isp); 2125 if (rtn != 0) { 2126 rw_exit(&ihp->hba_sess_list_rwlock); 2127 rtn = EFAULT; 2128 break; 2129 } 2130 2131 ialp->al_out_cnt = 0; 2132 ialp->al_tpgt = isp->sess_tpgt_conf; 2133 rw_enter(&isp->sess_conn_list_rwlock, RW_READER); 2134 for (icp = isp->sess_conn_list; icp; icp = icp->conn_next) { 2135 if (icp->conn_state != ISCSI_CONN_STATE_LOGGED_IN) { 2136 continue; 2137 } 2138 if (ialp->al_out_cnt < ialp->al_in_cnt) { 2139 iscsi_addr_t *ap; 2140 2141 ap = &ialp->al_addrs[ialp->al_out_cnt]; 2142 if (icp->conn_base_addr.sin.sa_family 2143 == AF_INET) { 2144 2145 struct sockaddr_in *addr_in = 2146 (struct sockaddr_in *)&icp-> 2147 conn_base_addr.sin4; 2148 ap->a_addr.i_insize = 2149 sizeof (struct in_addr); 2150 bcopy(&addr_in->sin_addr.s_addr, 2151 &ap->a_addr.i_addr.in4.s_addr, 2152 sizeof (struct in_addr)); 2153 ap->a_port = addr_in->sin_port; 2154 2155 } else { 2156 2157 struct sockaddr_in6 *addr_in6 = 2158 (struct sockaddr_in6 *)&icp-> 2159 conn_base_addr.sin6; 2160 ap->a_addr.i_insize = 2161 sizeof (struct in6_addr); 2162 bcopy(&addr_in6->sin6_addr.s6_addr, 2163 &ap->a_addr.i_addr.in6.s6_addr, 2164 sizeof (struct in6_addr)); 2165 ap->a_port = addr_in6->sin6_port; 2166 2167 } 2168 } 2169 ialp->al_out_cnt++; 2170 } 2171 rw_exit(&isp->sess_conn_list_rwlock); 2172 rw_exit(&ihp->hba_sess_list_rwlock); 2173 2174 rtn = ddi_copyout(ialp, (caddr_t)arg, list_space, mode); 2175 kmem_free(ialp, list_space); 2176 break; 2177 2178 /* 2179 * ISCSI_CHAP_SET - 2180 */ 2181 case ISCSI_CHAP_SET: 2182 chap = (iscsi_chap_props_t *)kmem_zalloc(sizeof (*chap), 2183 KM_SLEEP); 2184 if (ddi_copyin((caddr_t)arg, chap, sizeof (*chap), mode)) { 2185 rtn = EFAULT; 2186 kmem_free(chap, sizeof (*chap)); 2187 break; 2188 } else if (chap->c_vers != ISCSI_INTERFACE_VERSION) { 2189 rtn = EINVAL; 2190 kmem_free(chap, sizeof (*chap)); 2191 break; 2192 } 2193 2194 rw_enter(&ihp->hba_sess_list_rwlock, RW_READER); 2195 if (chap->c_oid == ihp->hba_oid) 2196 name = ihp->hba_name; 2197 else { 2198 rtn = iscsi_sess_get(chap->c_oid, ihp, &isp); 2199 if (rtn != 0) { 2200 rtn = iscsi_sess_get_by_target( 2201 chap->c_oid, ihp, &isp); 2202 } 2203 2204 /* 2205 * If rtn is zero then we have found an 2206 * existing session. Use the session name to 2207 * do param lookup. If rtn is non-zero then 2208 * create a targetparam object and use its name 2209 * for param lookup. 2210 */ 2211 if (rtn == 0) { 2212 name = isp->sess_name; 2213 } else { 2214 name = 2215 iscsi_targetparam_get_name(chap->c_oid); 2216 rtn = 0; 2217 } 2218 } 2219 2220 if (name == NULL) { 2221 rw_exit( 2222 &ihp->hba_sess_list_rwlock); 2223 rtn = EFAULT; 2224 kmem_free(chap, sizeof (*chap)); 2225 break; 2226 } 2227 2228 if (persistent_chap_set((char *)name, chap) == 2229 B_FALSE) { 2230 rtn = EIO; 2231 } 2232 rw_exit(&ihp->hba_sess_list_rwlock); 2233 kmem_free(chap, sizeof (*chap)); 2234 break; 2235 2236 /* 2237 * ISCSI_CHAP_GET - 2238 */ 2239 case ISCSI_CHAP_GET: 2240 chap = (iscsi_chap_props_t *)kmem_zalloc(sizeof (*chap), 2241 KM_SLEEP); 2242 if (ddi_copyin((caddr_t)arg, chap, sizeof (*chap), mode)) { 2243 kmem_free(chap, sizeof (*chap)); 2244 rtn = EFAULT; 2245 break; 2246 } else if (chap->c_vers != ISCSI_INTERFACE_VERSION) { 2247 kmem_free(chap, sizeof (*chap)); 2248 rtn = EINVAL; 2249 break; 2250 } 2251 2252 rw_enter(&ihp->hba_sess_list_rwlock, RW_READER); 2253 if (chap->c_oid == ihp->hba_oid) 2254 name = ihp->hba_name; 2255 else { 2256 rtn = iscsi_sess_get(chap->c_oid, ihp, &isp); 2257 if (rtn != 0) { 2258 rtn = iscsi_sess_get_by_target( 2259 chap->c_oid, ihp, &isp); 2260 } 2261 2262 /* 2263 * If rtn is zero then we have found an 2264 * existing session. Use the session name to 2265 * do param lookup. If rtn is non-zero then 2266 * create a targetparam object and use its name 2267 * for param lookup. 2268 */ 2269 if (rtn == 0) { 2270 name = isp->sess_name; 2271 } else { 2272 rtn = 0; 2273 name = 2274 iscsi_targetparam_get_name(chap->c_oid); 2275 } 2276 2277 /* 2278 * Initialize the target-side chap name to the 2279 * session name if no chap settings have been 2280 * saved for the current session. 2281 */ 2282 if (persistent_chap_get((char *)name, 2283 chap) == B_FALSE) { 2284 int name_len = strlen((char *)name); 2285 iscsi_chap_props_t *chap = NULL; 2286 chap = (iscsi_chap_props_t *)kmem_zalloc 2287 (sizeof (iscsi_chap_props_t), KM_SLEEP); 2288 bcopy((char *)name, chap->c_user, name_len); 2289 chap->c_user_len = name_len; 2290 (void) (persistent_chap_set((char *)name, 2291 chap)); 2292 kmem_free(chap, sizeof (*chap)); 2293 } 2294 } 2295 2296 if (name == NULL) { 2297 rw_exit( 2298 &ihp->hba_sess_list_rwlock); 2299 rtn = EFAULT; 2300 break; 2301 } 2302 2303 if (persistent_chap_get((char *)name, chap) == B_FALSE) { 2304 rw_exit(&ihp->hba_sess_list_rwlock); 2305 rtn = EIO; 2306 break; 2307 } 2308 rw_exit(&ihp->hba_sess_list_rwlock); 2309 2310 rtn = ddi_copyout(chap, (caddr_t)arg, sizeof (*chap), mode); 2311 kmem_free(chap, sizeof (*chap)); 2312 break; 2313 2314 /* 2315 * ISCSI_CHAP_CLEAR - 2316 */ 2317 case ISCSI_CHAP_CLEAR: 2318 chap = (iscsi_chap_props_t *)kmem_zalloc(sizeof (*chap), 2319 KM_SLEEP); 2320 if (ddi_copyin((caddr_t)arg, chap, sizeof (*chap), mode)) { 2321 rtn = EFAULT; 2322 kmem_free(chap, sizeof (*chap)); 2323 break; 2324 } else if (chap->c_vers != ISCSI_INTERFACE_VERSION) { 2325 rtn = EINVAL; 2326 kmem_free(chap, sizeof (*chap)); 2327 break; 2328 } 2329 2330 if (chap->c_oid == ihp->hba_oid) { 2331 iscsi_sess_t *sessp; 2332 2333 name = ihp->hba_name; 2334 2335 if (persistent_chap_clear( 2336 (char *)name) == B_FALSE) { 2337 rtn = EIO; 2338 } 2339 2340 /* 2341 * Loop through all sessions and memset their 2342 * (initiator's) passwords 2343 */ 2344 rw_enter(&ihp->hba_sess_list_rwlock, RW_READER); 2345 for (sessp = ihp->hba_sess_list; sessp; 2346 sessp = sessp->sess_next) { 2347 (void) memset(sessp->sess_auth.password, 2348 0, iscsiAuthStringMaxLength); 2349 sessp->sess_auth.password_length = 0; 2350 } 2351 rw_exit(&ihp->hba_sess_list_rwlock); 2352 2353 } else { 2354 rw_enter(&ihp->hba_sess_list_rwlock, RW_READER); 2355 /* 2356 * If the oid does represent a session check to see 2357 * if it is a target oid. If so, return the target's 2358 * associated session. 2359 */ 2360 rtn = iscsi_sess_get(chap->c_oid, ihp, &isp); 2361 if (rtn != 0) { 2362 rtn = iscsi_sess_get_by_target(chap->c_oid, 2363 ihp, &isp); 2364 } 2365 2366 rw_exit(&ihp->hba_sess_list_rwlock); 2367 2368 /* 2369 * If rtn is zero then we have found an 2370 * existing session. Use the session name to 2371 * do param lookup. If rtn is non-zero then 2372 * create a targetparam object and use its name 2373 * for param lookup. 2374 */ 2375 if (rtn == 0) { 2376 name = isp->sess_name; 2377 } else { 2378 name = 2379 iscsi_targetparam_get_name(chap->c_oid); 2380 rtn = 0; 2381 } 2382 2383 if (name == NULL) { 2384 rw_exit( 2385 &ihp->hba_sess_list_rwlock); 2386 rtn = EFAULT; 2387 break; 2388 } 2389 2390 if (persistent_chap_clear( 2391 (char *)name) == B_FALSE) { 2392 rtn = EIO; 2393 } 2394 2395 /* 2396 * Clear out session chap password if we found a 2397 * session above. 2398 */ 2399 if (isp != NULL) { 2400 (void) memset(isp->sess_auth.password_in, 2401 0, iscsiAuthStringMaxLength); 2402 isp->sess_auth.password_length_in = 0; 2403 } 2404 2405 } 2406 2407 kmem_free(chap, sizeof (*chap)); 2408 break; 2409 2410 /* 2411 * ISCSI_STATIC_GET - 2412 */ 2413 case ISCSI_STATIC_GET: 2414 ispp = (iscsi_static_property_t *)kmem_alloc( 2415 sizeof (*ispp), KM_SLEEP); 2416 2417 if (ddi_copyin((caddr_t)arg, ispp, sizeof (*ispp), mode)) { 2418 rtn = EFAULT; 2419 kmem_free(ispp, sizeof (*ispp)); 2420 break; 2421 } 2422 2423 if (ispp->p_vers != ISCSI_INTERFACE_VERSION) { 2424 rtn = EINVAL; 2425 kmem_free(ispp, sizeof (*ispp)); 2426 break; 2427 } 2428 2429 { 2430 void *v = NULL; 2431 boolean_t found = B_FALSE; 2432 2433 persistent_static_addr_lock(); 2434 while (persistent_static_addr_next(&v, 2435 (char *)ispp->p_name, &e) == B_TRUE) { 2436 2437 if (ispp->p_oid == e.e_oid) { 2438 /* 2439 * In case there are multiple 2440 * addresses associated with the 2441 * given target OID, pick the first 2442 * one. 2443 */ 2444 iscsi_addr_t *ap; 2445 2446 ap = &(ispp->p_addr_list.al_addrs[0]); 2447 ap->a_port = e.e_port; 2448 ap->a_addr.i_insize = e.e_insize; 2449 bcopy(e.e_u.u_in6.s6_addr, 2450 ap->a_addr.i_addr.in6.s6_addr, 2451 e.e_insize); 2452 ispp->p_name_len = 2453 strlen((char *)ispp->p_name); 2454 ispp->p_addr_list.al_tpgt = e.e_tpgt; 2455 ispp->p_addr_list.al_out_cnt = 1; 2456 2457 found = B_TRUE; 2458 break; 2459 } 2460 } 2461 persistent_static_addr_unlock(); 2462 2463 if (found == B_TRUE) { 2464 rtn = ddi_copyout(ispp, (caddr_t)arg, 2465 sizeof (*ispp), mode); 2466 } else { 2467 rtn = ENOENT; 2468 } 2469 } 2470 kmem_free(ispp, sizeof (*ispp)); 2471 2472 break; 2473 2474 /* 2475 * ISCSI_STATIC_SET - 2476 */ 2477 case ISCSI_STATIC_SET: 2478 target = iscsi_ioctl_copyin((caddr_t)arg, mode, 2479 sizeof (*target)); 2480 if (target == NULL) { 2481 rtn = EFAULT; 2482 break; 2483 } 2484 2485 if (target->te_entry.e_vers != ISCSI_INTERFACE_VERSION) { 2486 kmem_free(target, sizeof (*target)); 2487 rtn = EINVAL; 2488 break; 2489 } 2490 2491 /* Check if the target's already been added */ 2492 { 2493 boolean_t static_target_found = B_FALSE; 2494 void *v = NULL; 2495 2496 name = kmem_zalloc(ISCSI_MAX_NAME_LEN, KM_SLEEP); 2497 persistent_static_addr_lock(); 2498 while (persistent_static_addr_next(&v, (char *)name, 2499 &e) == B_TRUE) { 2500 /* 2501 * MC/S - Need to check IP address and port 2502 * number as well when we support MC/S. 2503 */ 2504 if ((strncmp((char *)name, 2505 (char *)target->te_name, 2506 ISCSI_MAX_NAME_LEN) == 0) && 2507 (target->te_entry.e_tpgt == e.e_tpgt) && 2508 (target->te_entry.e_insize == e.e_insize) && 2509 (bcmp(&target->te_entry.e_u, &e.e_u, 2510 e.e_insize) == 0)) { 2511 /* 2512 * We don't allow MC/S for now but 2513 * we do allow adding the same target 2514 * with different TPGTs (hence, 2515 * different sessions). 2516 */ 2517 static_target_found = B_TRUE; 2518 break; 2519 } 2520 } 2521 persistent_static_addr_unlock(); 2522 kmem_free(name, ISCSI_MAX_NAME_LEN); 2523 2524 if (static_target_found == B_TRUE) { 2525 /* Duplicate entry */ 2526 kmem_free(target, sizeof (*target)); 2527 rtn = EEXIST; 2528 break; 2529 } 2530 } 2531 2532 if (target->te_entry.e_oid == ISCSI_OID_NOTSET) { 2533 mutex_enter(&iscsi_oid_mutex); 2534 target->te_entry.e_oid = iscsi_oid++; 2535 mutex_exit(&iscsi_oid_mutex); 2536 } 2537 2538 persistent_static_addr_lock(); 2539 if (persistent_static_addr_set((char *)target->te_name, 2540 &target->te_entry) == B_FALSE) { 2541 persistent_static_addr_unlock(); 2542 kmem_free(target, sizeof (*target)); 2543 rtn = EIO; 2544 break; 2545 } 2546 persistent_static_addr_unlock(); 2547 2548 /* 2549 * If Static Targets discovery is enabled, then add 2550 * target to discovery queue. Otherwise, just create 2551 * the session for potential future use. 2552 */ 2553 method = persistent_disc_meth_get(); 2554 if (method & iSCSIDiscoveryMethodStatic) { 2555 iscsid_poke_discovery(ihp, iSCSIDiscoveryMethodStatic); 2556 (void) iscsid_login_tgt(ihp, (char *)target->te_name, 2557 iSCSIDiscoveryMethodStatic, NULL); 2558 } 2559 2560 rtn = iscsi_ioctl_copyout(target, sizeof (*target), 2561 (caddr_t)arg, mode); 2562 break; 2563 2564 /* 2565 * ISCSI_STATIC_CLEAR - 2566 */ 2567 case ISCSI_STATIC_CLEAR: 2568 if (ddi_copyin((caddr_t)arg, &e, sizeof (e), mode)) { 2569 rtn = EFAULT; 2570 break; 2571 } else if (e.e_vers != ISCSI_INTERFACE_VERSION) { 2572 rtn = EINVAL; 2573 break; 2574 } 2575 2576 { 2577 boolean_t found = B_FALSE; 2578 void *v = NULL; 2579 entry_t tmp_e; 2580 char *name = NULL; 2581 2582 name = kmem_zalloc(ISCSI_MAX_NAME_LEN, KM_SLEEP); 2583 2584 /* Find name for matching static_tgt oid */ 2585 persistent_static_addr_lock(); 2586 while (persistent_static_addr_next(&v, 2587 (char *)name, &tmp_e) == B_TRUE) { 2588 if (e.e_oid == tmp_e.e_oid) { 2589 found = B_TRUE; 2590 break; 2591 } 2592 } 2593 2594 /* If static_tgt found logout and remove it */ 2595 if (found == B_TRUE) { 2596 2597 iscsid_addr_to_sockaddr(tmp_e.e_insize, 2598 &tmp_e.e_u, tmp_e.e_port, &addr_dsc.sin); 2599 2600 /* Attempt to logout of target */ 2601 if (iscsid_del(ihp, (char *)name, 2602 iSCSIDiscoveryMethodStatic, &addr_dsc.sin) 2603 == B_TRUE) { 2604 persistent_static_addr_unlock(); 2605 2606 /* remove from persistent store */ 2607 if (persistent_static_addr_clear( 2608 e.e_oid) == B_FALSE) { 2609 rtn = EIO; 2610 } 2611 2612 iscsid_poke_discovery(ihp, 2613 iSCSIDiscoveryMethodStatic); 2614 (void) iscsid_login_tgt(ihp, 2615 (char *)name, 2616 iSCSIDiscoveryMethodStatic, 2617 NULL); 2618 2619 } else { 2620 persistent_static_addr_unlock(); 2621 rtn = EBUSY; 2622 } 2623 } else { 2624 persistent_static_addr_unlock(); 2625 rtn = EIO; 2626 } 2627 kmem_free(name, ISCSI_MAX_NAME_LEN); 2628 } 2629 break; 2630 2631 /* 2632 * ISCSI_ISNS_SERVER_ADDR_SET: 2633 */ 2634 case ISCSI_ISNS_SERVER_ADDR_SET: 2635 if (ddi_copyin((caddr_t)arg, &e, sizeof (e), mode)) { 2636 rtn = EFAULT; 2637 break; 2638 } else if (e.e_vers != ISCSI_INTERFACE_VERSION) { 2639 rtn = EINVAL; 2640 break; 2641 } 2642 2643 if (persistent_isns_addr_set(&e) == B_FALSE) { 2644 rtn = EIO; 2645 break; 2646 } 2647 2648 /* 2649 * If iSNS server discovery is enabled, then kickoff 2650 * discovery of the targets advertised by the recently 2651 * added iSNS server address. 2652 */ 2653 method = persistent_disc_meth_get(); 2654 if (method & iSCSIDiscoveryMethodISNS) { 2655 initiator_node_name = kmem_zalloc(ISCSI_MAX_NAME_LEN, 2656 KM_SLEEP); 2657 if (persistent_initiator_name_get(initiator_node_name, 2658 ISCSI_MAX_NAME_LEN) != B_TRUE) { 2659 kmem_free(initiator_node_name, 2660 ISCSI_MAX_NAME_LEN); 2661 initiator_node_name = NULL; 2662 rtn = EIO; 2663 break; 2664 } 2665 if (strlen(initiator_node_name) == 0) { 2666 kmem_free(initiator_node_name, 2667 ISCSI_MAX_NAME_LEN); 2668 initiator_node_name = NULL; 2669 rtn = EIO; 2670 break; 2671 } 2672 2673 initiator_node_alias = kmem_zalloc(ISCSI_MAX_NAME_LEN, 2674 KM_SLEEP); 2675 if (persistent_alias_name_get(initiator_node_alias, 2676 ISCSI_MAX_NAME_LEN) != B_TRUE) { 2677 initiator_node_alias[0] = '\0'; 2678 } 2679 2680 /* 2681 * Register this initiator node against this iSNS 2682 * server. 2683 */ 2684 (void) isns_reg_one_server(&e, ihp->hba_isid, 2685 (uint8_t *)initiator_node_name, 2686 ISCSI_MAX_NAME_LEN, 2687 (uint8_t *)initiator_node_alias, 2688 ISCSI_MAX_NAME_LEN, 2689 ISNS_INITIATOR_NODE_TYPE, 2690 isns_scn_callback); 2691 2692 iscsid_do_isns_query_one_server(ihp, &e); 2693 2694 iscsid_addr_to_sockaddr(e.e_insize, 2695 &e.e_u, e.e_port, &addr_dsc.sin); 2696 2697 (void) iscsid_login_tgt(ihp, NULL, 2698 iSCSIDiscoveryMethodISNS, 2699 &addr_dsc.sin); 2700 2701 /* Done using the name and alias - free them. */ 2702 kmem_free(initiator_node_name, ISCSI_MAX_NAME_LEN); 2703 initiator_node_name = NULL; 2704 kmem_free(initiator_node_alias, ISCSI_MAX_NAME_LEN); 2705 initiator_node_alias = NULL; 2706 } 2707 break; 2708 2709 /* 2710 * ISCSI_DISCOVERY_ADDR_SET: 2711 */ 2712 case ISCSI_DISCOVERY_ADDR_SET: 2713 if (ddi_copyin((caddr_t)arg, &e, sizeof (e), mode)) { 2714 rtn = EFAULT; 2715 break; 2716 } else if (e.e_vers != ISCSI_INTERFACE_VERSION) { 2717 rtn = EINVAL; 2718 break; 2719 } 2720 2721 if (e.e_oid == ISCSI_OID_NOTSET) { 2722 mutex_enter(&iscsi_oid_mutex); 2723 e.e_oid = iscsi_oid++; 2724 mutex_exit(&iscsi_oid_mutex); 2725 } 2726 2727 if (persistent_disc_addr_set(&e) == B_FALSE) { 2728 rtn = EIO; 2729 break; 2730 } 2731 2732 /* 2733 * If Send Targets discovery is enabled, then kickoff 2734 * discovery of the targets advertised by the recently 2735 * added discovery address. 2736 */ 2737 method = persistent_disc_meth_get(); 2738 if (method & iSCSIDiscoveryMethodSendTargets) { 2739 2740 iscsid_addr_to_sockaddr(e.e_insize, 2741 &e.e_u, e.e_port, &addr_dsc.sin); 2742 iscsid_do_sendtgts(&e); 2743 (void) iscsid_login_tgt(ihp, NULL, 2744 iSCSIDiscoveryMethodSendTargets, 2745 &addr_dsc.sin); 2746 2747 } 2748 break; 2749 2750 /* 2751 * ISCSI_DISCOVERY_ADDR_LIST_GET 2752 */ 2753 case ISCSI_DISCOVERY_ADDR_LIST_GET: 2754 /* copyin user args */ 2755 if (ddi_copyin((caddr_t)arg, &ial, sizeof (ial), mode)) { 2756 rtn = EFAULT; 2757 break; 2758 } 2759 2760 if (ial.al_vers != ISCSI_INTERFACE_VERSION) { 2761 rtn = EINVAL; 2762 break; 2763 } 2764 2765 list_space = sizeof (iscsi_addr_list_t); 2766 if (ial.al_in_cnt != 0) { 2767 list_space += (sizeof (iscsi_addr_t) * 2768 (ial.al_in_cnt - 1)); 2769 } 2770 2771 ialp = kmem_zalloc(list_space, KM_SLEEP); 2772 bcopy(&ial, ialp, sizeof (iscsi_addr_list_t)); 2773 2774 void_p = NULL; 2775 ialp->al_out_cnt = 0; 2776 persistent_disc_addr_lock(); 2777 while (persistent_disc_addr_next(&void_p, &e) == B_TRUE) { 2778 if (ialp->al_out_cnt < ialp->al_in_cnt) { 2779 int i = ialp->al_out_cnt; 2780 iscsi_addr_t *addr = &ialp->al_addrs[i]; 2781 2782 addr->a_port = e.e_port; 2783 addr->a_addr.i_insize = e.e_insize; 2784 addr->a_oid = e.e_oid; 2785 2786 if (e.e_insize == sizeof (struct in_addr)) { 2787 /* IPv4 */ 2788 addr->a_addr.i_addr.in4.s_addr = 2789 e.e_u.u_in4.s_addr; 2790 } else if (e.e_insize == 2791 sizeof (struct in6_addr)) { 2792 /* IPv6 */ 2793 bcopy(e.e_u.u_in6.s6_addr, 2794 addr->a_addr.i_addr.in6.s6_addr, 2795 16); 2796 } 2797 } 2798 ialp->al_out_cnt++; 2799 } 2800 persistent_disc_addr_unlock(); 2801 2802 rtn = ddi_copyout(ialp, (caddr_t)arg, list_space, mode); 2803 kmem_free(ialp, list_space); 2804 break; 2805 2806 /* 2807 * ISCSI_ISNS_SERVER_ADDR_LIST_GET 2808 */ 2809 case ISCSI_ISNS_SERVER_ADDR_LIST_GET: 2810 /* copyin user args */ 2811 if (ddi_copyin((caddr_t)arg, &ial, sizeof (ial), mode)) { 2812 rtn = EFAULT; 2813 break; 2814 } 2815 2816 if (ial.al_vers != ISCSI_INTERFACE_VERSION) { 2817 rtn = EINVAL; 2818 break; 2819 } 2820 2821 list_space = sizeof (iscsi_addr_list_t); 2822 if (ial.al_in_cnt != 0) { 2823 list_space += (sizeof (iscsi_addr_t) * 2824 (ial.al_in_cnt - 1)); 2825 } 2826 2827 ialp = kmem_zalloc(list_space, KM_SLEEP); 2828 bcopy(&ial, ialp, sizeof (iscsi_addr_list_t)); 2829 2830 void_p = NULL; 2831 ialp->al_out_cnt = 0; 2832 persistent_isns_addr_lock(); 2833 while (persistent_isns_addr_next(&void_p, &e) == B_TRUE) { 2834 if (ialp->al_out_cnt < ialp->al_in_cnt) { 2835 int i = ialp->al_out_cnt; 2836 iscsi_addr_t *addr = &ialp->al_addrs[i]; 2837 2838 addr->a_port = e.e_port; 2839 addr->a_addr.i_insize = e.e_insize; 2840 if (e.e_insize == sizeof (struct in_addr)) { 2841 /* IPv4 */ 2842 addr->a_addr.i_addr.in4.s_addr = 2843 e.e_u.u_in4.s_addr; 2844 } else if (e.e_insize == 2845 sizeof (struct in6_addr)) { 2846 /* IPv6 */ 2847 bcopy(e.e_u.u_in6.s6_addr, 2848 addr->a_addr.i_addr.in6.s6_addr, 2849 16); 2850 } 2851 } 2852 ialp->al_out_cnt++; 2853 } 2854 persistent_isns_addr_unlock(); 2855 2856 rtn = ddi_copyout(ialp, (caddr_t)arg, list_space, mode); 2857 kmem_free(ialp, list_space); 2858 break; 2859 2860 /* 2861 * ISCSI_DISCOVERY_ADDR_CLEAR: 2862 */ 2863 case ISCSI_DISCOVERY_ADDR_CLEAR: 2864 if (ddi_copyin((caddr_t)arg, &e, sizeof (e), mode)) { 2865 rtn = EFAULT; 2866 break; 2867 } else if (e.e_vers != ISCSI_INTERFACE_VERSION) { 2868 rtn = EINVAL; 2869 break; 2870 } 2871 2872 iscsid_addr_to_sockaddr(e.e_insize, 2873 &e.e_u, e.e_port, &addr_dsc.sin); 2874 2875 /* Attempt to logout of associated targets */ 2876 if (iscsid_del(ihp, NULL, 2877 iSCSIDiscoveryMethodSendTargets, &addr_dsc.sin) == 2878 B_TRUE) { 2879 /* Logout successful remove disc. addr. */ 2880 if (persistent_disc_addr_clear(&e) == B_FALSE) { 2881 rtn = EIO; 2882 } 2883 } else { 2884 rtn = EBUSY; 2885 } 2886 break; 2887 2888 /* 2889 * ISCSI_ISNS_SERVER_CLEAR: 2890 */ 2891 case ISCSI_ISNS_SERVER_ADDR_CLEAR: 2892 if (ddi_copyin((caddr_t)arg, &e, sizeof (e), mode)) { 2893 rtn = EFAULT; 2894 break; 2895 } else if (e.e_vers != ISCSI_INTERFACE_VERSION) { 2896 rtn = EINVAL; 2897 break; 2898 } 2899 2900 iscsid_addr_to_sockaddr(e.e_insize, 2901 &e.e_u, e.e_port, &addr_dsc.sin); 2902 2903 /* Attempt logout of associated targets */ 2904 if (iscsid_del(ihp, NULL, iSCSIDiscoveryMethodISNS, 2905 &addr_dsc.sin) == B_TRUE) { 2906 /* Logout successful */ 2907 2908 if (persistent_isns_addr_clear(&e) == B_FALSE) { 2909 rtn = EIO; 2910 break; 2911 } 2912 2913 method = persistent_disc_meth_get(); 2914 if (method & iSCSIDiscoveryMethodISNS) { 2915 boolean_t is_last_isns_server_b = 2916 B_FALSE; 2917 int isns_server_count = 0; 2918 void *void_p = NULL; 2919 2920 /* 2921 * Check if the last iSNS server's been 2922 * removed. 2923 */ 2924 { 2925 entry_t tmp_e; 2926 persistent_isns_addr_lock(); 2927 while (persistent_isns_addr_next( 2928 &void_p, &tmp_e) == B_TRUE) { 2929 isns_server_count++; 2930 } 2931 } 2932 persistent_isns_addr_unlock(); 2933 if (isns_server_count == 0) { 2934 is_last_isns_server_b = B_TRUE; 2935 } 2936 2937 /* 2938 * Deregister this node from this iSNS 2939 * server. 2940 */ 2941 initiator_node_name = kmem_zalloc( 2942 ISCSI_MAX_NAME_LEN, KM_SLEEP); 2943 if (persistent_initiator_name_get( 2944 initiator_node_name, 2945 ISCSI_MAX_NAME_LEN) == B_TRUE) { 2946 2947 if (strlen(initiator_node_name) > 0) { 2948 (void) isns_dereg_one_server( 2949 &e, (uint8_t *) 2950 initiator_node_name, 2951 is_last_isns_server_b); 2952 } 2953 } 2954 kmem_free(initiator_node_name, 2955 ISCSI_MAX_NAME_LEN); 2956 initiator_node_name = NULL; 2957 } 2958 } else { 2959 rtn = EBUSY; 2960 } 2961 break; 2962 2963 /* 2964 * ISCSI_DISCOVERY_SET - 2965 */ 2966 case ISCSI_DISCOVERY_SET: 2967 if (ddi_copyin((caddr_t)arg, &method, sizeof (method), mode)) { 2968 rtn = EFAULT; 2969 break; 2970 } 2971 2972 if (persistent_disc_meth_set(method) == B_FALSE) { 2973 rtn = EIO; 2974 } else { 2975 (void) iscsid_enable_discovery(ihp, method, B_TRUE); 2976 iscsid_poke_discovery(ihp, method); 2977 (void) iscsid_login_tgt(ihp, NULL, method, NULL); 2978 } 2979 break; 2980 2981 /* 2982 * ISCSI_DISCOVERY_GET - 2983 */ 2984 case ISCSI_DISCOVERY_GET: 2985 method = persistent_disc_meth_get(); 2986 rtn = ddi_copyout(&method, (caddr_t)arg, 2987 sizeof (method), mode); 2988 break; 2989 2990 /* 2991 * ISCSI_DISCOVERY_CLEAR - 2992 */ 2993 case ISCSI_DISCOVERY_CLEAR: 2994 if (ddi_copyin((caddr_t)arg, &method, sizeof (method), mode)) { 2995 rtn = EFAULT; 2996 break; 2997 } 2998 2999 /* Attempt to logout of all associated targets first */ 3000 if (iscsid_disable_discovery(ihp, method) == B_FALSE) { 3001 rtn = EBUSY; 3002 break; 3003 } 3004 3005 /* 3006 * Successfully logged out of targets, Update 3007 * Persistent store. 3008 */ 3009 if (persistent_disc_meth_clear(method) == B_FALSE) { 3010 rtn = EIO; 3011 break; 3012 } 3013 break; 3014 3015 /* 3016 * ISCSI_DISCOVERY_PROPS - 3017 */ 3018 case ISCSI_DISCOVERY_PROPS: 3019 iscsid_props(&discovery_props); 3020 if (ddi_copyout(&discovery_props, (caddr_t)arg, 3021 sizeof (discovery_props), mode)) 3022 rtn = EFAULT; 3023 break; 3024 3025 /* 3026 * ISCSI_LUN_OID_LIST -- 3027 */ 3028 case ISCSI_LUN_OID_LIST_GET: 3029 ll = (iscsi_lun_list_t *)kmem_alloc(sizeof (*ll), KM_SLEEP); 3030 if (ddi_copyin((caddr_t)arg, ll, sizeof (*ll), mode)) { 3031 rtn = EFAULT; 3032 kmem_free(ll, sizeof (*ll)); 3033 break; 3034 } 3035 3036 if (ll->ll_vers != ISCSI_INTERFACE_VERSION) { 3037 rtn = EINVAL; 3038 kmem_free(ll, sizeof (*ll)); 3039 break; 3040 } 3041 3042 /* 3043 * Find out how much space the user has allocated in their 3044 * structure. Match the same space for our structure. 3045 */ 3046 lun_sz = sizeof (iscsi_lun_list_t); 3047 if (ll->ll_in_cnt > 0) { 3048 lun_sz += (ll->ll_in_cnt - 1) * sizeof (iscsi_if_lun_t); 3049 } 3050 3051 llp = kmem_zalloc(lun_sz, KM_SLEEP); 3052 bcopy(ll, llp, sizeof (*ll)); 3053 kmem_free(ll, sizeof (*ll)); 3054 3055 /* 3056 * Check to see if oid references a target-param oid. If so, 3057 * find the associated session oid before getting lu list. 3058 */ 3059 if (iscsi_targetparam_get_name(llp->ll_tgt_oid) != NULL) { 3060 for (isp = ihp->hba_sess_list; isp; 3061 isp = isp->sess_next) { 3062 if (isp->sess_target_oid == llp->ll_tgt_oid) { 3063 target_oid = isp->sess_oid; 3064 break; 3065 } 3066 } 3067 } else { 3068 target_oid = llp->ll_tgt_oid; 3069 } 3070 3071 3072 /* 3073 * Look at the LUNs attached to the specified target. If there 3074 * is space in the user structure save that information locally. 3075 * Always add up the count to the total. By always adding 3076 * the count this code can be used if ll_in_cnt == 0 and 3077 * the user just wishes to know the appropriate size to 3078 * allocate. 3079 */ 3080 rw_enter(&ihp->hba_sess_list_rwlock, RW_READER); 3081 for (isp = ihp->hba_sess_list; isp; isp = isp->sess_next) { 3082 if ((llp->ll_all_tgts == B_FALSE) && 3083 (isp->sess_oid != target_oid)) { 3084 continue; 3085 } 3086 rw_enter(&isp->sess_lun_list_rwlock, RW_READER); 3087 for (ilp = isp->sess_lun_list; ilp; 3088 ilp = ilp->lun_next) { 3089 if (ilp->lun_state == 3090 ISCSI_LUN_STATE_ONLINE) { 3091 if (llp->ll_out_cnt < 3092 llp->ll_in_cnt) { 3093 iscsi_if_lun_t *lp; 3094 lp = &llp->ll_luns[ 3095 llp->ll_out_cnt]; 3096 3097 lp->l_tgt_oid = 3098 isp->sess_oid; 3099 lp->l_oid = ilp->lun_oid; 3100 lp->l_num = ilp->lun_num; 3101 } 3102 llp->ll_out_cnt++; 3103 } 3104 } 3105 rw_exit(&isp->sess_lun_list_rwlock); 3106 } 3107 rw_exit(&ihp->hba_sess_list_rwlock); 3108 3109 if (ddi_copyout(llp, (caddr_t)arg, lun_sz, mode)) { 3110 rtn = EFAULT; 3111 } 3112 3113 kmem_free(llp, lun_sz); 3114 break; 3115 3116 /* 3117 * ISCSI_LUN_PROPS_GET -- 3118 */ 3119 case ISCSI_LUN_PROPS_GET: 3120 lun = (iscsi_lun_props_t *)kmem_zalloc(sizeof (*lun), KM_SLEEP); 3121 if (ddi_copyin((caddr_t)arg, lun, sizeof (*lun), mode)) { 3122 rtn = EFAULT; 3123 kmem_free(lun, sizeof (*lun)); 3124 break; 3125 } 3126 3127 if (lun->lp_vers != ISCSI_INTERFACE_VERSION) { 3128 rtn = EINVAL; 3129 kmem_free(lun, sizeof (*lun)); 3130 break; 3131 } 3132 3133 /* 3134 * For the target specified, find the LUN specified and 3135 * return its properties 3136 */ 3137 rw_enter(&ihp->hba_sess_list_rwlock, RW_READER); 3138 rtn = iscsi_sess_get(lun->lp_tgt_oid, ihp, &isp); 3139 if (rtn != 0) { 3140 rw_exit(&ihp->hba_sess_list_rwlock); 3141 rtn = EFAULT; 3142 kmem_free(lun, sizeof (*lun)); 3143 break; 3144 } 3145 rtn = EINVAL; /* Set bad rtn, correct only if found */ 3146 rw_enter(&isp->sess_lun_list_rwlock, RW_READER); 3147 for (ilp = isp->sess_lun_list; ilp; ilp = ilp->lun_next) { 3148 if (ilp->lun_oid == lun->lp_oid) { 3149 lun->lp_num = ilp->lun_num; 3150 lun->lp_status = LunValid; 3151 lun->lp_time_online = ilp->lun_time_online; 3152 3153 if (ilp->lun_pip != NULL) { 3154 lun_dip = mdi_pi_get_client( 3155 ilp->lun_pip); 3156 } else { 3157 lun_dip = ilp->lun_dip; 3158 } 3159 3160 if (lun_dip != NULL && 3161 i_ddi_devi_attached(lun_dip)) { 3162 (void) ddi_pathname(lun_dip, 3163 lun->lp_pathname); 3164 } else { 3165 /* 3166 * The LUN is not exported to the 3167 * OS yet. It is in the process 3168 * of being added. 3169 */ 3170 lun->lp_status = LunDoesNotExist; 3171 } 3172 bcopy(ilp->lun_vid, lun->lp_vid, 3173 sizeof (lun->lp_vid)); 3174 bcopy(ilp->lun_pid, lun->lp_pid, 3175 sizeof (lun->lp_pid)); 3176 rtn = ddi_copyout(lun, (caddr_t)arg, 3177 sizeof (*lun), mode); 3178 if (rtn == -1) { 3179 rtn = EFAULT; 3180 } 3181 break; 3182 } 3183 } 3184 rw_exit(&isp->sess_lun_list_rwlock); 3185 rw_exit(&ihp->hba_sess_list_rwlock); 3186 3187 kmem_free(lun, sizeof (*lun)); 3188 break; 3189 3190 /* 3191 * ISCSI_CONN_OID_LIST_GET -- 3192 */ 3193 #define ISCSIIOCOLGC iscsi_ioctl_conn_oid_list_get_copyout 3194 case ISCSI_CONN_OID_LIST_GET: 3195 { 3196 iscsi_conn_list_t *cl; 3197 3198 /* Asuume the worst */ 3199 rtn = EFAULT; 3200 3201 /* Copy the input argument into kernel world. */ 3202 cl = iscsi_ioctl_conn_oid_list_get_copyin( 3203 (caddr_t)arg, 3204 mode); 3205 if (cl != NULL) { 3206 if (iscsi_ioctl_conn_oid_list_get(ihp, cl) == 3207 B_TRUE) { 3208 rtn = 3209 ISCSIIOCOLGC( 3210 cl, (caddr_t)arg, mode); 3211 } 3212 } 3213 break; 3214 } 3215 #undef ISCSIIOCOLGC 3216 /* 3217 * ISCSI_CONN_OID_LIST_GET -- 3218 */ 3219 case ISCSI_CONN_PROPS_GET: 3220 { 3221 iscsi_conn_props_t *cp; 3222 3223 /* Asuume the worst */ 3224 rtn = EFAULT; 3225 3226 /* Copy the input argument into kernel world. */ 3227 cp = iscsi_ioctl_copyin( 3228 (caddr_t)arg, 3229 mode, 3230 sizeof (iscsi_conn_props_t)); 3231 3232 if (cp != NULL) { 3233 /* Get the propereties. */ 3234 if (iscsi_ioctl_conn_props_get(ihp, cp) == 3235 B_TRUE) { 3236 rtn = 3237 iscsi_ioctl_copyout( 3238 cp, 3239 sizeof (*cp), 3240 (caddr_t)arg, 3241 mode); 3242 } 3243 } 3244 break; 3245 } 3246 3247 /* 3248 * ISCSI_RADIUS_GET - 3249 */ 3250 case ISCSI_RADIUS_GET: 3251 { 3252 iscsi_nvfile_status_t status; 3253 3254 radius = (iscsi_radius_props_t *)kmem_zalloc(sizeof (*radius), 3255 KM_SLEEP); 3256 if (ddi_copyin((caddr_t)arg, radius, sizeof (*radius), mode)) { 3257 kmem_free(radius, sizeof (*radius)); 3258 rtn = EFAULT; 3259 break; 3260 } else if (radius->r_vers != ISCSI_INTERFACE_VERSION) { 3261 kmem_free(radius, sizeof (*radius)); 3262 rtn = EINVAL; 3263 break; 3264 } 3265 3266 old_oid = radius->r_oid; 3267 3268 if (radius->r_oid == ihp->hba_oid) { 3269 name = ihp->hba_name; 3270 } else { 3271 /* 3272 * RADIUS configuration should be done on a per 3273 * initiator basis. 3274 */ 3275 kmem_free(radius, sizeof (*radius)); 3276 rtn = EINVAL; 3277 break; 3278 } 3279 3280 status = persistent_radius_get(radius); 3281 if (status == ISCSI_NVFILE_SUCCESS) { 3282 /* 3283 * Restore the value for overridden (and bogus) oid. 3284 */ 3285 radius->r_oid = old_oid; 3286 rtn = ddi_copyout(radius, (caddr_t)arg, 3287 sizeof (*radius), mode); 3288 } else if (status == ISCSI_NVFILE_NAMEVAL_NOT_FOUND) { 3289 rtn = ENOENT; 3290 } else { 3291 rtn = EIO; 3292 } 3293 kmem_free(radius, sizeof (*radius)); 3294 break; 3295 } 3296 3297 /* 3298 * ISCSI_RADIUS_SET - 3299 */ 3300 case ISCSI_RADIUS_SET: 3301 radius = (iscsi_radius_props_t *)kmem_zalloc(sizeof (*radius), 3302 KM_SLEEP); 3303 if (ddi_copyin((caddr_t)arg, radius, sizeof (*radius), mode)) { 3304 rtn = EFAULT; 3305 kmem_free(radius, sizeof (*radius)); 3306 break; 3307 } else if (radius->r_vers != ISCSI_INTERFACE_VERSION) { 3308 rtn = EINVAL; 3309 kmem_free(radius, sizeof (*radius)); 3310 break; 3311 } 3312 3313 if (radius->r_oid == ihp->hba_oid) { 3314 name = ihp->hba_name; 3315 } else { 3316 /* 3317 * RADIUS configuration should be done on a per 3318 * initiator basis. 3319 */ 3320 kmem_free(radius, sizeof (*radius)); 3321 rtn = EINVAL; 3322 break; 3323 } 3324 3325 if (persistent_radius_set(radius) == B_FALSE) { 3326 rtn = EIO; 3327 } 3328 3329 kmem_free(radius, sizeof (*radius)); 3330 break; 3331 3332 /* 3333 * ISCSI_AUTH_GET - 3334 */ 3335 case ISCSI_AUTH_GET: 3336 auth = (iscsi_auth_props_t *)kmem_zalloc(sizeof (*auth), 3337 KM_SLEEP); 3338 if (ddi_copyin((caddr_t)arg, auth, sizeof (*auth), mode)) { 3339 kmem_free(auth, sizeof (*auth)); 3340 rtn = EFAULT; 3341 break; 3342 } else if (auth->a_vers != ISCSI_INTERFACE_VERSION) { 3343 kmem_free(auth, sizeof (*auth)); 3344 rtn = EINVAL; 3345 break; 3346 } 3347 3348 old_oid = auth->a_oid; 3349 3350 if (auth->a_oid == ihp->hba_oid) { 3351 name = ihp->hba_name; 3352 } else { 3353 3354 rw_enter(&ihp->hba_sess_list_rwlock, RW_READER); 3355 /* 3356 * If the oid does represent a session check to see 3357 * if it is a target oid. If so, return the target's 3358 * associated session. 3359 */ 3360 rtn = iscsi_sess_get(auth->a_oid, ihp, &isp); 3361 if (rtn != 0) { 3362 rtn = iscsi_sess_get_by_target(auth->a_oid, 3363 ihp, &isp); 3364 } 3365 rw_exit(&ihp->hba_sess_list_rwlock); 3366 3367 /* 3368 * If rtn is zero then we have found an 3369 * existing session. Use the session name to 3370 * do param lookup. If rtn is non-zero then 3371 * create a targetparam object and use its name 3372 * for param lookup. 3373 */ 3374 if (rtn == 0) { 3375 name = isp->sess_name; 3376 } else { 3377 name = 3378 iscsi_targetparam_get_name(auth->a_oid); 3379 } 3380 } 3381 3382 if (name == NULL) { 3383 rw_exit( 3384 &ihp->hba_sess_list_rwlock); 3385 rtn = EFAULT; 3386 break; 3387 } 3388 3389 if (persistent_auth_get((char *)name, auth) == B_TRUE) { 3390 /* 3391 * Restore the value for overridden (and bogus) oid. 3392 */ 3393 auth->a_oid = old_oid; 3394 rtn = ddi_copyout(auth, (caddr_t)arg, 3395 sizeof (*auth), mode); 3396 } else { 3397 rtn = EIO; 3398 } 3399 3400 kmem_free(auth, sizeof (*auth)); 3401 break; 3402 3403 /* 3404 * ISCSI_AUTH_SET - 3405 */ 3406 case ISCSI_AUTH_SET: 3407 auth = (iscsi_auth_props_t *)kmem_zalloc(sizeof (*auth), 3408 KM_SLEEP); 3409 if (ddi_copyin((caddr_t)arg, auth, sizeof (*auth), mode)) { 3410 kmem_free(auth, sizeof (*auth)); 3411 rtn = EFAULT; 3412 break; 3413 } else if (auth->a_vers != ISCSI_INTERFACE_VERSION) { 3414 kmem_free(auth, sizeof (*auth)); 3415 rtn = EINVAL; 3416 break; 3417 } 3418 3419 if (auth->a_oid == ihp->hba_oid) { 3420 name = ihp->hba_name; 3421 } else { 3422 rw_enter(&ihp->hba_sess_list_rwlock, RW_READER); 3423 /* 3424 * If the oid does represent a session check to see 3425 * if it is a target oid. If so, return the target's 3426 * associated session. 3427 */ 3428 rtn = iscsi_sess_get(auth->a_oid, ihp, &isp); 3429 if (rtn != 0) { 3430 rtn = iscsi_sess_get_by_target(auth->a_oid, 3431 ihp, &isp); 3432 } 3433 rw_exit(&ihp->hba_sess_list_rwlock); 3434 3435 /* 3436 * If rtn is zero then we have found an 3437 * existing session. Use the session name to 3438 * do param lookup. If rtn is non-zero then 3439 * create a targetparam object and use its name 3440 * for param lookup. 3441 */ 3442 if (rtn == 0) { 3443 name = isp->sess_name; 3444 } else { 3445 name = 3446 iscsi_targetparam_get_name(auth->a_oid); 3447 rtn = 0; 3448 } 3449 } 3450 3451 if (persistent_auth_set((char *)name, auth) == B_FALSE) { 3452 rtn = EIO; 3453 } 3454 3455 kmem_free(auth, sizeof (*auth)); 3456 break; 3457 3458 /* 3459 * ISCSI_AUTH_CLEAR - 3460 */ 3461 case ISCSI_AUTH_CLEAR: 3462 auth = (iscsi_auth_props_t *)kmem_alloc(sizeof (*auth), 3463 KM_SLEEP); 3464 if (ddi_copyin((caddr_t)arg, auth, sizeof (*auth), mode)) { 3465 kmem_free(auth, sizeof (*auth)); 3466 rtn = EFAULT; 3467 break; 3468 } else if (auth->a_vers != ISCSI_INTERFACE_VERSION) { 3469 kmem_free(auth, sizeof (*auth)); 3470 rtn = EINVAL; 3471 break; 3472 } 3473 3474 rw_enter(&ihp->hba_sess_list_rwlock, RW_READER); 3475 /* 3476 * If the oid does represent a session check to see 3477 * if it is a target oid. If so, return the target's 3478 * associated session. 3479 */ 3480 rtn = iscsi_sess_get(auth->a_oid, ihp, &isp); 3481 if (rtn != 0) { 3482 rtn = iscsi_sess_get_by_target(auth->a_oid, ihp, &isp); 3483 } 3484 rw_exit(&ihp->hba_sess_list_rwlock); 3485 3486 /* 3487 * If rtn is zero then we have found an 3488 * existing session. Use the session name to 3489 * do param lookup. If rtn is non-zero then 3490 * create a targetparam object and use its name 3491 * for param lookup. 3492 */ 3493 if (rtn == 0) { 3494 name = isp->sess_name; 3495 } else { 3496 name = 3497 iscsi_targetparam_get_name(auth->a_oid); 3498 rtn = 0; 3499 } 3500 3501 if (name == NULL) { 3502 rw_exit( 3503 &ihp->hba_sess_list_rwlock); 3504 rtn = EFAULT; 3505 break; 3506 } 3507 3508 if (persistent_auth_clear((char *)name) == B_FALSE) { 3509 rtn = EIO; 3510 } 3511 kmem_free(auth, sizeof (*auth)); 3512 break; 3513 3514 /* 3515 * ISCSI_DB_RELOAD - 3516 */ 3517 case ISCSI_DB_RELOAD: 3518 /* ---- database will be closed and reread ---- */ 3519 if (iscsid_init(ihp, B_TRUE) == B_FALSE) { 3520 rtn = EFAULT; 3521 } 3522 break; 3523 3524 /* 3525 * ISCSI_DB_DUMP - 3526 */ 3527 case ISCSI_DB_DUMP: 3528 persistent_dump_data(); 3529 break; 3530 3531 case ISCSI_USCSI: 3532 3533 #ifdef _MULTI_DATAMODEL 3534 model = ddi_model_convert_from(mode & FMODELS); 3535 switch (model) { 3536 case DDI_MODEL_ILP32: 3537 3538 if (ddi_copyin((caddr_t)arg, &iu32_caller, 3539 sizeof (iscsi_uscsi32_t), mode)) { 3540 rtn = EFAULT; 3541 break; 3542 } 3543 3544 /* perform conversion from 32 -> 64 */ 3545 iu_caller.iu_vers = iu32_caller.iu_vers; 3546 iu_caller.iu_oid = iu32_caller.iu_oid; 3547 iu_caller.iu_tpgt = iu32_caller.iu_tpgt; 3548 iu_caller.iu_len = iu32_caller.iu_len; 3549 iu_caller.iu_lun = iu32_caller.iu_lun; 3550 uscsi_cmd32touscsi_cmd((&iu32_caller.iu_ucmd), 3551 (&iu_caller.iu_ucmd)); 3552 3553 break; 3554 case DDI_MODEL_NONE: 3555 if (ddi_copyin((caddr_t)arg, &iu_caller, 3556 sizeof (iscsi_uscsi_t), mode)) { 3557 rtn = EFAULT; 3558 break; 3559 } 3560 break; 3561 default: 3562 ASSERT(FALSE); 3563 rtn = EINVAL; 3564 break; 3565 } 3566 #endif /* _MULTI_DATAMODEL */ 3567 3568 /* If failures earlier break */ 3569 if (rtn != 0) { 3570 break; 3571 } 3572 3573 /* copy from caller to internel cmd */ 3574 bcopy(&iu_caller, &iu, sizeof (iu)); 3575 3576 if (iu.iu_vers != ISCSI_INTERFACE_VERSION) { 3577 rtn = EINVAL; 3578 break; 3579 } 3580 /* 3581 * Check to see if oid references a target-param oid. If so, 3582 * find the associated session oid before getting lu list. 3583 */ 3584 if (iscsi_targetparam_get_name(iu.iu_oid) != NULL) { 3585 for (isp = ihp->hba_sess_list; isp; isp = 3586 isp->sess_next) { 3587 if (isp->sess_target_oid == iu.iu_oid) { 3588 target_oid = isp->sess_oid; 3589 break; 3590 } 3591 } 3592 } else { 3593 target_oid = iu.iu_oid; 3594 } 3595 3596 /* make sure we have a matching session for this command */ 3597 rw_enter(&ihp->hba_sess_list_rwlock, RW_READER); 3598 rtn = iscsi_sess_get(target_oid, ihp, &isp); 3599 if (rtn != 0) { 3600 rtn = iscsi_sess_get_by_target(target_oid, ihp, 3601 &isp); 3602 if (rtn != 0) { 3603 rw_exit(&ihp->hba_sess_list_rwlock); 3604 rtn = EFAULT; 3605 break; 3606 } 3607 } 3608 /* 3609 * If a caller buffer is present allocate duplicate 3610 * kernel space and copyin caller memory. 3611 */ 3612 if (iu.iu_ucmd.uscsi_buflen > 0) { 3613 iu.iu_ucmd.uscsi_bufaddr = (caddr_t)kmem_alloc( 3614 iu.iu_ucmd.uscsi_buflen, KM_SLEEP); 3615 if (ddi_copyin(iu_caller.iu_ucmd.uscsi_bufaddr, 3616 iu.iu_ucmd.uscsi_bufaddr, 3617 iu.iu_ucmd.uscsi_buflen, mode)) { 3618 rw_exit(&ihp->hba_sess_list_rwlock); 3619 rtn = EFAULT; 3620 break; 3621 } 3622 } 3623 3624 /* 3625 * If a caller cdb is present allocate duplicate 3626 * kernel space and copyin caller memory. 3627 */ 3628 if (iu.iu_ucmd.uscsi_cdblen > 0) { 3629 iu.iu_ucmd.uscsi_cdb = (caddr_t)kmem_alloc( 3630 iu_caller.iu_ucmd.uscsi_cdblen, KM_SLEEP); 3631 if (ddi_copyin(iu_caller.iu_ucmd.uscsi_cdb, 3632 iu.iu_ucmd.uscsi_cdb, 3633 iu.iu_ucmd.uscsi_cdblen, mode)) { 3634 if (iu.iu_ucmd.uscsi_buflen > 0) { 3635 kmem_free(iu.iu_ucmd.uscsi_bufaddr, 3636 iu_caller.iu_ucmd.uscsi_buflen); 3637 } 3638 rw_exit(&ihp->hba_sess_list_rwlock); 3639 rtn = EFAULT; 3640 break; 3641 } 3642 } 3643 3644 /* 3645 * If a caller request sense is present allocate 3646 * duplicate kernel space. No need to copyin. 3647 */ 3648 if (iu.iu_ucmd.uscsi_rqlen > 0) { 3649 iu.iu_ucmd.uscsi_rqbuf = (caddr_t)kmem_alloc( 3650 iu.iu_ucmd.uscsi_rqlen, KM_SLEEP); 3651 } 3652 3653 /* issue passthru to io path handler */ 3654 rtn = iscsi_handle_passthru(isp, iu.iu_lun, &iu.iu_ucmd); 3655 if (rtn != 0) { 3656 rtn = EFAULT; 3657 } 3658 3659 /* 3660 * If the caller had a buf we need to do a copyout 3661 * and free the kernel memory 3662 */ 3663 if (iu.iu_ucmd.uscsi_buflen > 0) { 3664 if (ddi_copyout(iu.iu_ucmd.uscsi_bufaddr, 3665 iu_caller.iu_ucmd.uscsi_bufaddr, 3666 iu.iu_ucmd.uscsi_buflen, mode) != 0) { 3667 rtn = EFAULT; 3668 } 3669 kmem_free(iu.iu_ucmd.uscsi_bufaddr, 3670 iu.iu_ucmd.uscsi_buflen); 3671 } 3672 3673 /* We need to free kernel cdb, no need to copyout */ 3674 if (iu.iu_ucmd.uscsi_cdblen > 0) { 3675 kmem_free(iu.iu_ucmd.uscsi_cdb, 3676 iu.iu_ucmd.uscsi_cdblen); 3677 } 3678 3679 /* 3680 * If the caller had a request sense we need to 3681 * do a copyout and free the kernel memory 3682 */ 3683 if (iu.iu_ucmd.uscsi_rqlen > 0) { 3684 if (ddi_copyout(iu.iu_ucmd.uscsi_rqbuf, 3685 iu_caller.iu_ucmd.uscsi_rqbuf, 3686 iu.iu_ucmd.uscsi_rqlen, mode) != 0) { 3687 rtn = EFAULT; 3688 } 3689 kmem_free(iu.iu_ucmd.uscsi_rqbuf, 3690 iu.iu_ucmd.uscsi_rqlen); 3691 } 3692 3693 #ifdef _MULTI_DATAMODEL 3694 if (iu.iu_ucmd.uscsi_status != 0) { 3695 switch (model = ddi_model_convert_from( 3696 mode & FMODELS)) { 3697 case DDI_MODEL_ILP32: 3698 iu32_caller.iu_ucmd.uscsi_status = 3699 iu.iu_ucmd.uscsi_status; 3700 if (ddi_copyout((void *)&iu32_caller, 3701 (caddr_t)arg, sizeof (iscsi_uscsi32_t), 3702 mode) != 0) { 3703 rtn = EFAULT; 3704 } 3705 break; 3706 case DDI_MODEL_NONE: 3707 iu_caller.iu_ucmd.uscsi_status = 3708 iu.iu_ucmd.uscsi_status; 3709 if (ddi_copyout((void *)&iu_caller, 3710 (caddr_t)arg, sizeof (iscsi_uscsi_t), 3711 mode) != 0) { 3712 rtn = EFAULT; 3713 } 3714 break; 3715 default: 3716 ASSERT(FALSE); 3717 } 3718 } 3719 #endif /* _MULTI_DATAMODEL */ 3720 rw_exit(&ihp->hba_sess_list_rwlock); 3721 break; 3722 3723 /* 3724 * ISCSI_DOOR_HANDLE_SET - 3725 */ 3726 case ISCSI_DOOR_HANDLE_SET: 3727 if (ddi_copyin((caddr_t)arg, &did, sizeof (int), mode) != 0) { 3728 rtn = EFAULT; 3729 } 3730 if (iscsi_door_bind(did) == B_FALSE) { 3731 rtn = EFAULT; 3732 } 3733 break; 3734 3735 case ISCSI_DISCOVERY_EVENTS: 3736 /* 3737 * If discovery has not been completed and not in progress, 3738 * poke the discovery methods 3739 */ 3740 mutex_enter(&ihp->hba_discovery_events_mutex); 3741 method = ihp->hba_discovery_events; 3742 if ((method != ISCSI_ALL_DISCOVERY_METHODS) && 3743 (ihp->hba_discovery_in_progress == B_FALSE)) { 3744 ihp->hba_discovery_in_progress = B_TRUE; 3745 mutex_exit(&ihp->hba_discovery_events_mutex); 3746 iscsid_poke_discovery(ihp, iSCSIDiscoveryMethodUnknown); 3747 mutex_enter(&ihp->hba_discovery_events_mutex); 3748 ihp->hba_discovery_in_progress = B_FALSE; 3749 method = ihp->hba_discovery_events; 3750 } 3751 mutex_exit(&ihp->hba_discovery_events_mutex); 3752 3753 if (ddi_copyout((void *)&method, (caddr_t)arg, 3754 sizeof (method), mode) != 0) 3755 rtn = EFAULT; 3756 break; 3757 3758 /* 3759 * ISCSI_SENDTGTS_GET -- 3760 */ 3761 case ISCSI_SENDTGTS_GET: 3762 stl_hdr = iscsi_ioctl_copyin((caddr_t)arg, mode, 3763 sizeof (*stl_hdr)); 3764 if (stl_hdr == NULL) { 3765 rtn = EFAULT; 3766 break; 3767 } 3768 3769 if (stl_hdr->stl_entry.e_vers != ISCSI_INTERFACE_VERSION) { 3770 rtn = EINVAL; 3771 kmem_free(stl_hdr, sizeof (*stl_hdr)); 3772 break; 3773 } 3774 3775 /* calculate how much memory user allocated for SendTgts */ 3776 stl_sz = sizeof (*stl_hdr); 3777 if (stl_hdr->stl_in_cnt > 0) { 3778 stl_sz += ((stl_hdr->stl_in_cnt - 1) * 3779 sizeof (iscsi_sendtgts_entry_t)); 3780 } 3781 3782 /* allocate local SendTgts list of the same size */ 3783 istl = kmem_zalloc(stl_sz, KM_SLEEP); 3784 bcopy(stl_hdr, istl, sizeof (*stl_hdr)); 3785 kmem_free(stl_hdr, sizeof (*stl_hdr)); 3786 3787 /* lock interface so only one SendTargets operation occurs */ 3788 sema_p(&ihp->hba_sendtgts_semaphore); 3789 3790 rtn = iscsi_ioctl_sendtgts_get(ihp, istl); 3791 3792 if (rtn == 0) { 3793 rtn = iscsi_ioctl_copyout(istl, stl_sz, 3794 (caddr_t)arg, mode); 3795 } 3796 3797 /* release lock to allow another SendTargets discovery */ 3798 sema_v(&ihp->hba_sendtgts_semaphore); 3799 3800 break; 3801 3802 /* 3803 * ISCSI_ISNS_SERVER_GET -- 3804 */ 3805 case ISCSI_ISNS_SERVER_GET: 3806 server_pg_list_hdr = iscsi_ioctl_copyin((caddr_t)arg, mode, 3807 sizeof (*server_pg_list_hdr)); 3808 if (server_pg_list_hdr == NULL) { 3809 rtn = EFAULT; 3810 break; 3811 } 3812 3813 /* If iSNS discovery mode is not set, return with zero entry */ 3814 method = persistent_disc_meth_get(); 3815 if ((method & iSCSIDiscoveryMethodISNS) == 0) { 3816 rtn = EACCES; 3817 break; 3818 } 3819 3820 initiator_node_name = kmem_zalloc(ISCSI_MAX_NAME_LEN, KM_SLEEP); 3821 if (persistent_initiator_name_get(initiator_node_name, 3822 ISCSI_MAX_NAME_LEN) != B_TRUE) { 3823 kmem_free(initiator_node_name, ISCSI_MAX_NAME_LEN); 3824 initiator_node_name = NULL; 3825 kmem_free(server_pg_list_hdr, 3826 sizeof (*server_pg_list_hdr)); 3827 rtn = EIO; 3828 break; 3829 } 3830 if (strlen(initiator_node_name) == 0) { 3831 kmem_free(initiator_node_name, ISCSI_MAX_NAME_LEN); 3832 initiator_node_name = NULL; 3833 kmem_free(server_pg_list_hdr, 3834 sizeof (*server_pg_list_hdr)); 3835 rtn = EIO; 3836 break; 3837 } 3838 3839 initiator_node_alias = kmem_zalloc( 3840 ISCSI_MAX_NAME_LEN, KM_SLEEP); 3841 if (persistent_alias_name_get(initiator_node_alias, 3842 ISCSI_MAX_NAME_LEN) != B_TRUE) { 3843 initiator_node_alias[0] = '\0'; 3844 } 3845 rtn = isns_query_one_server(&(server_pg_list_hdr->addr), 3846 ihp->hba_isid, 3847 (uint8_t *)initiator_node_name, 3848 (uint8_t *)initiator_node_alias, 3849 ISNS_INITIATOR_NODE_TYPE, 3850 &pg_list); 3851 if (rtn != isns_ok || pg_list == NULL) { 3852 kmem_free(initiator_node_name, ISCSI_MAX_NAME_LEN); 3853 initiator_node_name = NULL; 3854 kmem_free(initiator_node_alias, ISCSI_MAX_NAME_LEN); 3855 initiator_node_alias = NULL; 3856 kmem_free(server_pg_list_hdr, 3857 sizeof (*server_pg_list_hdr)); 3858 server_pg_list_hdr = NULL; 3859 rtn = EIO; 3860 break; 3861 } 3862 3863 /* 3864 * pg_list_sz is the size of the pg_list returned from the 3865 * isns_query_all 3866 * 3867 * pg_sz_copy_out is the size of the pg_list we are going to 3868 * return back to the caller 3869 * 3870 * server_pg_list_sz is total amount of data we are returning 3871 * back to the caller 3872 */ 3873 pg_list->pg_in_cnt = 3874 server_pg_list_hdr->addr_port_list.pg_in_cnt; 3875 pg_list_sz = sizeof (isns_portal_group_list_t); 3876 if (pg_list->pg_out_cnt > 0) { 3877 pg_list_sz += (pg_list->pg_out_cnt - 1) * 3878 sizeof (isns_portal_group_t); 3879 } 3880 /* 3881 * check if caller passed in a buffer with enough space 3882 * if there isn't enough space, fill the caller's buffer with 3883 * as much information as possible. 3884 * 3885 * if pg_out_cnt > pg_in_cnt, pg_out_cnt will be returned with 3886 * the total number of targets found 3887 * 3888 * if pg_out_cnt < pg_in_cnt, pg_out_cnt will be the number 3889 * of targets returned 3890 */ 3891 if (pg_list->pg_in_cnt < pg_list->pg_out_cnt) { 3892 pg_sz_copy_out = sizeof (isns_portal_group_list_t); 3893 if (pg_list->pg_in_cnt > 0) { 3894 pg_sz_copy_out += (pg_list->pg_in_cnt - 1) * 3895 sizeof (isns_portal_group_t); 3896 } 3897 server_pg_list_sz = 3898 sizeof (isns_server_portal_group_list_t); 3899 if (pg_list->pg_in_cnt > 0) { 3900 server_pg_list_sz += (pg_list->pg_in_cnt - 1) * 3901 sizeof (isns_portal_group_t); 3902 } 3903 } else { 3904 pg_sz_copy_out = pg_list_sz; 3905 server_pg_list_sz = 3906 sizeof (isns_server_portal_group_list_t); 3907 if (pg_list->pg_out_cnt > 0) { 3908 server_pg_list_sz += (pg_list->pg_out_cnt - 1) * 3909 sizeof (isns_portal_group_t); 3910 } 3911 } 3912 3913 server_pg_list = (isns_server_portal_group_list_t *)kmem_zalloc( 3914 server_pg_list_sz, KM_SLEEP); 3915 3916 bcopy(&(server_pg_list_hdr->addr), &(server_pg_list->addr), 3917 sizeof (server_pg_list->addr)); 3918 bcopy(pg_list, &server_pg_list->addr_port_list, pg_sz_copy_out); 3919 3920 if (ddi_copyout(server_pg_list, (caddr_t)arg, server_pg_list_sz, 3921 mode) != 0) { 3922 rtn = EFAULT; 3923 } 3924 DTRACE_PROBE1(iscsi_ioctl_iscsi_isns_server_get_pg_sz, 3925 int, pg_list_sz); 3926 kmem_free(pg_list, pg_list_sz); 3927 kmem_free(server_pg_list, server_pg_list_sz); 3928 kmem_free(server_pg_list_hdr, sizeof (*server_pg_list_hdr)); 3929 break; 3930 3931 /* 3932 * ISCSI_GET_CONFIG_SESSIONS -- 3933 */ 3934 case ISCSI_GET_CONFIG_SESSIONS: 3935 /* FALLTHRU */ 3936 3937 case ISCSI_SET_CONFIG_SESSIONS: 3938 size = sizeof (*ics); 3939 ics = iscsi_ioctl_copyin((caddr_t)arg, mode, size); 3940 if (ics == NULL) { 3941 rtn = EFAULT; 3942 break; 3943 } 3944 3945 /* verify version infomration */ 3946 if (ics->ics_ver != ISCSI_INTERFACE_VERSION) { 3947 rtn = EINVAL; 3948 kmem_free(ics, size); 3949 break; 3950 } 3951 3952 /* Check to see if we need to copy in more memory */ 3953 if (ics->ics_in > 1) { 3954 /* record correct size */ 3955 size = ISCSI_SESSION_CONFIG_SIZE(ics->ics_in); 3956 /* free old buffer */ 3957 kmem_free(ics, sizeof (*ics)); 3958 3959 /* copy in complete buffer size */ 3960 ics = iscsi_ioctl_copyin((caddr_t)arg, mode, size); 3961 if (ics == NULL) { 3962 rtn = EFAULT; 3963 break; 3964 } 3965 } 3966 3967 /* switch action based on get or set */ 3968 if (cmd == ISCSI_GET_CONFIG_SESSIONS) { 3969 /* get */ 3970 rtn = iscsi_ioctl_get_config_sess(ihp, ics); 3971 if (rtn == 0) { 3972 /* copyout data for gets */ 3973 rtn = iscsi_ioctl_copyout(ics, size, 3974 (caddr_t)arg, mode); 3975 } 3976 } else { 3977 /* set */ 3978 rtn = iscsi_ioctl_set_config_sess(ihp, ics); 3979 if (iscsiboot_prop) { 3980 if (iscsi_cmp_boot_sess_oid(ihp, 3981 ics->ics_oid)) { 3982 /* 3983 * found active session for this object 3984 * or this is initiator object 3985 * with mpxio enabled 3986 */ 3987 if (!iscsi_reconfig_boot_sess(ihp)) { 3988 rtn = EINVAL; 3989 break; 3990 } 3991 } 3992 } 3993 } 3994 break; 3995 3996 case ISCSI_IS_ACTIVE: 3997 /* 3998 * dhcpagent calls here to check if there are 3999 * active iSCSI sessions 4000 */ 4001 instance = 0; 4002 if (iscsiboot_prop) { 4003 instance = 1; 4004 } 4005 if (!instance) { 4006 rw_enter(&ihp->hba_sess_list_rwlock, 4007 RW_READER); 4008 for (isp = ihp->hba_sess_list; isp; 4009 isp = isp->sess_next) { 4010 if ((isp->sess_state == 4011 ISCSI_SESS_STATE_LOGGED_IN) && 4012 (isp->sess_lun_list != 4013 NULL)) { 4014 instance = 1; 4015 break; 4016 } 4017 } 4018 rw_exit(&ihp->hba_sess_list_rwlock); 4019 } 4020 size = sizeof (instance); 4021 if (ddi_copyout(&instance, (caddr_t)arg, size, 4022 mode) != 0) { 4023 rtn = EFAULT; 4024 } 4025 break; 4026 4027 case ISCSI_BOOTPROP_GET: 4028 size = sizeof (*bootProp); 4029 bootProp = iscsi_ioctl_copyin((caddr_t)arg, mode, size); 4030 if (bootProp == NULL) { 4031 rtn = EFAULT; 4032 break; 4033 } 4034 bootProp->hba_mpxio_enabled = 4035 iscsi_chk_bootlun_mpxio(ihp); 4036 if (iscsiboot_prop == NULL) { 4037 bootProp->iscsiboot = 0; 4038 rtn = iscsi_ioctl_copyout(bootProp, size, 4039 (caddr_t)arg, mode); 4040 break; 4041 } else { 4042 bootProp->iscsiboot = 1; 4043 } 4044 4045 if (iscsiboot_prop->boot_init.ini_name != NULL) { 4046 (void) strncpy((char *)bootProp->ini_name.n_name, 4047 (char *)iscsiboot_prop->boot_init.ini_name, 4048 ISCSI_MAX_NAME_LEN); 4049 } 4050 if (iscsiboot_prop->boot_init.ini_chap_name != NULL) { 4051 bootProp->auth.a_auth_method = authMethodCHAP; 4052 (void) strncpy((char *)bootProp->ini_chap.c_user, 4053 (char *)iscsiboot_prop->boot_init.ini_chap_name, 4054 ISCSI_MAX_NAME_LEN); 4055 (void) strncpy((char *)bootProp->ini_chap.c_secret, 4056 (char *)iscsiboot_prop->boot_init.ini_chap_sec, 4057 ISCSI_CHAP_SECRET_LEN); 4058 if (iscsiboot_prop->boot_tgt.tgt_chap_name != 4059 NULL) { 4060 bootProp->auth.a_bi_auth = B_TRUE; 4061 } else { 4062 bootProp->auth.a_bi_auth = B_FALSE; 4063 } 4064 } 4065 if (iscsiboot_prop->boot_tgt.tgt_name != NULL) { 4066 (void) strncpy((char *)bootProp->tgt_name.n_name, 4067 (char *)iscsiboot_prop->boot_tgt.tgt_name, 4068 ISCSI_MAX_NAME_LEN); 4069 } 4070 if (iscsiboot_prop->boot_tgt.tgt_chap_name != NULL) { 4071 (void) strncpy((char *)bootProp->tgt_chap.c_user, 4072 (char *)iscsiboot_prop->boot_tgt.tgt_chap_name, 4073 ISCSI_MAX_NAME_LEN); 4074 (void) strncpy((char *)bootProp->tgt_chap.c_secret, 4075 (char *)iscsiboot_prop->boot_tgt.tgt_chap_sec, 4076 ISCSI_CHAP_SECRET_LEN); 4077 } 4078 4079 rtn = iscsi_ioctl_copyout(bootProp, size, (caddr_t)arg, mode); 4080 break; 4081 4082 default: 4083 rtn = ENOTTY; 4084 cmn_err(CE_NOTE, "unrecognized ioctl 0x%x", cmd); 4085 } /* end of ioctl type switch/cases */ 4086 4087 return (rtn); 4088 } 4089 4090 /* 4091 * +--------------------------------------------------------------------+ 4092 * | End of cb_ops routines | 4093 * +--------------------------------------------------------------------+ 4094 */ 4095 4096 4097 /* 4098 * +--------------------------------------------------------------------+ 4099 * | Common scsi_tran support routines | 4100 * +--------------------------------------------------------------------+ 4101 */ 4102 4103 /* 4104 * iscsi_i_commoncap -- SCSA host adapter get/set capability routines. 4105 * 4106 * Need to determine if any of these can be determined through the iSCSI 4107 * protocol. For now just return error on most. 4108 */ 4109 /* ARGSUSED */ 4110 static int 4111 iscsi_i_commoncap(struct scsi_address *ap, char *cap, int val, 4112 int tgtonly, int doset) 4113 { 4114 int rtn; 4115 int cidx; 4116 iscsi_lun_t *ilp; 4117 4118 ASSERT((ap)->a_hba_tran->tran_hba_private != NULL); 4119 ilp = (iscsi_lun_t *)((ap)->a_hba_tran->tran_tgt_private); 4120 ASSERT(ilp != NULL); 4121 4122 if (cap == (char *)0) { 4123 return (FALSE); 4124 } 4125 4126 cidx = scsi_hba_lookup_capstr(cap); 4127 if (cidx == -1) { 4128 return (cidx); 4129 } 4130 4131 /* 4132 * Process setcap request. 4133 */ 4134 if (doset) { 4135 /* 4136 * At present, we can only set binary (0/1) values 4137 */ 4138 switch (cidx) { 4139 case SCSI_CAP_LUN_RESET: 4140 if (val) { 4141 ilp->lun_cap |= ISCSI_LUN_CAP_RESET; 4142 } else { 4143 ilp->lun_cap &= ~ISCSI_LUN_CAP_RESET; 4144 } 4145 rtn = TRUE; 4146 break; 4147 default: 4148 /* 4149 * None of these are settable via 4150 * the capability interface. 4151 */ 4152 rtn = FALSE; 4153 break; 4154 } 4155 4156 /* 4157 * Process getcap request. 4158 */ 4159 } else { 4160 switch (cidx) { 4161 case SCSI_CAP_DMA_MAX: 4162 /* no DMA, Psuedo value */ 4163 rtn = INT32_MAX; 4164 break; 4165 case SCSI_CAP_INITIATOR_ID: 4166 rtn = 7; 4167 break; 4168 case SCSI_CAP_ARQ: 4169 case SCSI_CAP_RESET_NOTIFICATION: 4170 case SCSI_CAP_TAGGED_QING: 4171 rtn = TRUE; 4172 break; 4173 case SCSI_CAP_SCSI_VERSION: 4174 rtn = SCSI_VERSION_3; 4175 break; 4176 case SCSI_CAP_INTERCONNECT_TYPE: 4177 rtn = INTERCONNECT_FABRIC; 4178 break; 4179 case SCSI_CAP_LUN_RESET: 4180 rtn = ((ilp->lun_cap & ISCSI_LUN_CAP_RESET) != 0) ? 4181 TRUE : FALSE; 4182 break; 4183 case SCSI_CAP_CDB_LEN: 4184 /* 4185 * iSCSI RFC 3720 defines a default 16 byte 4186 * CDB as part of the Basic Header Segment 4187 * (BHS) (10.2.1) and allows for an Additional 4188 * Header Segment (AHS) Length of 255 * 4 4189 * (10.2.1.5). The AHS length can be used 4190 * for different purposes two of which are 4191 * Extended CDB ADS (10.2.2.3) and Bidirectional 4192 * Expected Read-Data Length AHS (10.2.2.4). 4193 * The largest header of these consumes is 4194 * 32 bytes. So the total Max CDB Length is 4195 * 16 + ((255 * 4 ) - 32) = 1004. 4196 */ 4197 rtn = 1004; 4198 break; 4199 default: 4200 rtn = UNDEFINED; 4201 break; 4202 } 4203 } 4204 return (rtn); 4205 } 4206 4207 /* 4208 * iscsi_virt_lun_init - attempts to complete a mdi/scsi_vhci binding 4209 * 4210 * This routine is used to associate the tran_tgt_private to our ilp 4211 * structure. This function is indirectly called from our 4212 * iscsi_lun_create_xxx routines. These routines must prevent 4213 * the session and lun lists from changing during this call. 4214 */ 4215 /* ARGSUSED */ 4216 static int 4217 iscsi_virt_lun_init(dev_info_t *hba_dip, dev_info_t *lun_dip, 4218 scsi_hba_tran_t *hba_tran, struct scsi_device *sd) 4219 { 4220 iscsi_lun_t *ilp = NULL; 4221 iscsi_lun_t *ilp_check = NULL; 4222 iscsi_sess_t *isp = NULL; 4223 char *lun_guid = NULL; 4224 mdi_pathinfo_t *pip = NULL; 4225 iscsi_hba_t *ihp = (iscsi_hba_t *)hba_tran->tran_hba_private; 4226 char target_port_name[MAX_NAME_PROP_SIZE]; 4227 4228 /* 4229 * Here's a nice little piece of undocumented stuff. 4230 */ 4231 if ((pip = (mdi_pathinfo_t *)sd->sd_private) == NULL) { 4232 /* 4233 * Very bad news if this occurs. Somehow SCSI_vhci has 4234 * lost the pathinfo node for this target. 4235 */ 4236 return (DDI_NOT_WELL_FORMED); 4237 } 4238 4239 ilp = (iscsi_lun_t *)mdi_pi_get_phci_private(pip); 4240 4241 /* 4242 * +----------------------------------------------------+ 4243 * | Looking to find the target device via the property | 4244 * | is not required since the driver can easily get | 4245 * | this information from the mdi_phci_get_private() | 4246 * | call above. This is just a consistency check | 4247 * | which can be removed. | 4248 */ 4249 if (mdi_prop_lookup_string(pip, MDI_GUID, &lun_guid) != 4250 DDI_PROP_SUCCESS) { 4251 return (DDI_NOT_WELL_FORMED); 4252 } 4253 4254 for (isp = ihp->hba_sess_list; isp; isp = isp->sess_next) { 4255 4256 /* If this isn't the matching session continue */ 4257 if (ilp->lun_sess != isp) { 4258 continue; 4259 } 4260 4261 /* 4262 * We are already holding the lun list rwlock 4263 * for this thread on the callers side of mdi_pi_online 4264 * or ndi_devi_online. Which lead to this functions 4265 * call. 4266 */ 4267 for (ilp_check = isp->sess_lun_list; ilp_check; 4268 ilp_check = ilp_check->lun_next) { 4269 4270 /* 4271 * If this is the matching LUN and contains 4272 * the same LUN GUID then break we found our 4273 * match. 4274 */ 4275 if ((ilp == ilp_check) && 4276 (strcmp(lun_guid, ilp_check->lun_guid) == 0)) { 4277 break; 4278 } 4279 } 4280 if (ilp_check != NULL) { 4281 break; 4282 } 4283 } 4284 4285 /* 4286 * Free resource that's no longer required. 4287 */ 4288 if (lun_guid != NULL) 4289 (void) mdi_prop_free(lun_guid); 4290 4291 if (ilp_check == NULL) { 4292 /* 4293 * Failed to find iSCSI LUN in HBA chain based 4294 * on the GUID that was stored as a property on 4295 * the pathinfo node. 4296 */ 4297 return (DDI_NOT_WELL_FORMED); 4298 } 4299 4300 if (ilp != ilp_check) { 4301 /* 4302 * The iSCSI target that we found on the HBA link is 4303 * different than the iSCSI target that was stored as 4304 * private data on the pathinfo node. 4305 */ 4306 return (DDI_NOT_WELL_FORMED); 4307 } 4308 /* 4309 * | End of consistency check | 4310 * +----------------------------------------------------+ 4311 */ 4312 4313 hba_tran->tran_tgt_private = ilp; 4314 4315 target_port_name[0] = '\0'; 4316 if (ilp->lun_sess->sess_tpgt_conf == ISCSI_DEFAULT_TPGT) { 4317 (void) snprintf(target_port_name, MAX_NAME_PROP_SIZE, 4318 "%02x%02x%02x%02x%02x%02x,%s", 4319 ilp->lun_sess->sess_isid[0], ilp->lun_sess->sess_isid[1], 4320 ilp->lun_sess->sess_isid[2], ilp->lun_sess->sess_isid[3], 4321 ilp->lun_sess->sess_isid[4], ilp->lun_sess->sess_isid[5], 4322 ilp->lun_sess->sess_name); 4323 } else { 4324 (void) snprintf(target_port_name, MAX_NAME_PROP_SIZE, 4325 "%02x%02x%02x%02x%02x%02x,%s,%d", 4326 ilp->lun_sess->sess_isid[0], ilp->lun_sess->sess_isid[1], 4327 ilp->lun_sess->sess_isid[2], ilp->lun_sess->sess_isid[3], 4328 ilp->lun_sess->sess_isid[4], ilp->lun_sess->sess_isid[5], 4329 ilp->lun_sess->sess_name, ilp->lun_sess->sess_tpgt_conf); 4330 } 4331 4332 if (mdi_prop_update_string(pip, "target-port", 4333 target_port_name) != DDI_PROP_SUCCESS) { 4334 cmn_err(CE_WARN, "iscsi_virt_lun_init: Creating 'target-port' " 4335 "property on Path(%p) for Target(%s), Lun(%d) Failed", 4336 (void *)pip, ilp->lun_sess->sess_name, ilp->lun_num); 4337 } 4338 4339 return (DDI_SUCCESS); 4340 } 4341 4342 /* 4343 * iscsi_phys_lun_init - attempts to complete a ndi binding 4344 * 4345 * This routine is used to associate the tran_tgt_private to our 4346 * ilp structure. This function is indirectly called from our 4347 * iscsi_lun_create_xxx routines. These routines must prevent 4348 * the session and lun lists from changing during this call. 4349 */ 4350 static int 4351 iscsi_phys_lun_init(dev_info_t *hba_dip, dev_info_t *lun_dip, 4352 scsi_hba_tran_t *hba_tran, struct scsi_device *sd) 4353 { 4354 int rtn = DDI_SUCCESS; 4355 iscsi_hba_t *ihp = NULL; 4356 iscsi_sess_t *isp = NULL; 4357 iscsi_lun_t *ilp = NULL; 4358 char target_port_name[MAX_NAME_PROP_SIZE]; 4359 int *words = NULL; 4360 uint_t nwords = 0; 4361 4362 ASSERT(hba_dip); 4363 ASSERT(lun_dip); 4364 ASSERT(hba_tran); 4365 ASSERT(sd); 4366 ihp = (iscsi_hba_t *)hba_tran->tran_hba_private; 4367 ASSERT(ihp); 4368 4369 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, lun_dip, 4370 DDI_PROP_DONTPASS, LUN_PROP, &words, &nwords) != DDI_PROP_SUCCESS) { 4371 cmn_err(CE_WARN, "iscsi_phys_lun_init: Returning DDI_FAILURE:" 4372 "lun for %s (instance %d)", ddi_get_name(lun_dip), 4373 ddi_get_instance(lun_dip)); 4374 return (DDI_FAILURE); 4375 } 4376 4377 if (nwords == 0) { 4378 ddi_prop_free(words); 4379 return (DDI_FAILURE); 4380 } 4381 4382 ASSERT(words != NULL); 4383 4384 /* See if we already created this session */ 4385 4386 /* Walk the HBA's session list */ 4387 for (isp = ihp->hba_sess_list; isp; isp = isp->sess_next) { 4388 /* compare target name as the unique identifier */ 4389 if (sd->sd_address.a_target == isp->sess_oid) { 4390 /* found match */ 4391 break; 4392 } 4393 } 4394 4395 /* If we found matching session continue searching for tgt */ 4396 if (isp != NULL) { 4397 /* 4398 * Search for the matching iscsi lun structure. We don't 4399 * need to hold the READER for the lun list at this point. 4400 * because the tran_get_name is being called from the online 4401 * function which is already holding a reader on the lun 4402 * list. 4403 */ 4404 for (ilp = isp->sess_lun_list; ilp; ilp = ilp->lun_next) { 4405 if (*words == ilp->lun_num) { 4406 /* found match */ 4407 break; 4408 } 4409 } 4410 4411 if (ilp != NULL) { 4412 /* 4413 * tgt found path it to the tran_lun_private 4414 * this is used later for fast access on 4415 * init_pkt and start 4416 */ 4417 hba_tran->tran_tgt_private = ilp; 4418 } else { 4419 /* tgt not found */ 4420 ddi_prop_free(words); 4421 return (DDI_FAILURE); 4422 } 4423 } else { 4424 /* sess not found */ 4425 ddi_prop_free(words); 4426 return (DDI_FAILURE); 4427 } 4428 ddi_prop_free(words); 4429 4430 target_port_name[0] = '\0'; 4431 if (ilp->lun_sess->sess_tpgt_conf == ISCSI_DEFAULT_TPGT) { 4432 (void) snprintf(target_port_name, MAX_NAME_PROP_SIZE, 4433 "%02x%02x%02x%02x%02x%02x,%s", 4434 ilp->lun_sess->sess_isid[0], ilp->lun_sess->sess_isid[1], 4435 ilp->lun_sess->sess_isid[2], ilp->lun_sess->sess_isid[3], 4436 ilp->lun_sess->sess_isid[4], ilp->lun_sess->sess_isid[5], 4437 ilp->lun_sess->sess_name); 4438 } else { 4439 (void) snprintf(target_port_name, MAX_NAME_PROP_SIZE, 4440 "%02x%02x%02x%02x%02x%02x,%s,%d", 4441 ilp->lun_sess->sess_isid[0], ilp->lun_sess->sess_isid[1], 4442 ilp->lun_sess->sess_isid[2], ilp->lun_sess->sess_isid[3], 4443 ilp->lun_sess->sess_isid[4], ilp->lun_sess->sess_isid[5], 4444 ilp->lun_sess->sess_name, ilp->lun_sess->sess_tpgt_conf); 4445 } 4446 4447 if (ddi_prop_update_string(DDI_DEV_T_NONE, lun_dip, 4448 "target-port", target_port_name) != DDI_PROP_SUCCESS) { 4449 cmn_err(CE_WARN, "iscsi_phys_lun_init: Creating 'target-port' " 4450 "property on Target(%s), Lun(%d) Failed", 4451 ilp->lun_sess->sess_name, ilp->lun_num); 4452 } 4453 4454 return (rtn); 4455 } 4456 4457 /* 4458 * +--------------------------------------------------------------------+ 4459 * | End of scsi_tran support routines | 4460 * +--------------------------------------------------------------------+ 4461 */ 4462 4463 /* 4464 * +--------------------------------------------------------------------+ 4465 * | Begin of struct utility routines | 4466 * +--------------------------------------------------------------------+ 4467 */ 4468 4469 4470 /* 4471 * iscsi_set_default_login_params - This function sets the 4472 * driver default login params. This is using during the 4473 * creation of our iSCSI HBA structure initialization by 4474 * could be used at other times to reset back to the defaults. 4475 */ 4476 void 4477 iscsi_set_default_login_params(iscsi_login_params_t *params) 4478 { 4479 params->immediate_data = ISCSI_DEFAULT_IMMEDIATE_DATA; 4480 params->initial_r2t = ISCSI_DEFAULT_INITIALR2T; 4481 params->first_burst_length = ISCSI_DEFAULT_FIRST_BURST_LENGTH; 4482 params->max_burst_length = ISCSI_DEFAULT_MAX_BURST_LENGTH; 4483 params->data_pdu_in_order = ISCSI_DEFAULT_DATA_PDU_IN_ORDER; 4484 params->data_sequence_in_order = ISCSI_DEFAULT_DATA_SEQUENCE_IN_ORDER; 4485 params->default_time_to_wait = ISCSI_DEFAULT_TIME_TO_WAIT; 4486 params->default_time_to_retain = ISCSI_DEFAULT_TIME_TO_RETAIN; 4487 params->header_digest = ISCSI_DEFAULT_HEADER_DIGEST; 4488 params->data_digest = ISCSI_DEFAULT_DATA_DIGEST; 4489 params->max_recv_data_seg_len = ISCSI_DEFAULT_MAX_RECV_SEG_LEN; 4490 params->max_xmit_data_seg_len = ISCSI_DEFAULT_MAX_XMIT_SEG_LEN; 4491 params->max_connections = ISCSI_DEFAULT_MAX_CONNECTIONS; 4492 params->max_outstanding_r2t = ISCSI_DEFAULT_MAX_OUT_R2T; 4493 params->error_recovery_level = ISCSI_DEFAULT_ERROR_RECOVERY_LEVEL; 4494 params->ifmarker = ISCSI_DEFAULT_IFMARKER; 4495 params->ofmarker = ISCSI_DEFAULT_OFMARKER; 4496 } 4497 4498 4499 /* 4500 * +--------------------------------------------------------------------+ 4501 * | End of struct utility routines | 4502 * +--------------------------------------------------------------------+ 4503 */ 4504 4505 /* 4506 * +--------------------------------------------------------------------+ 4507 * | Begin of ioctl utility routines | 4508 * +--------------------------------------------------------------------+ 4509 */ 4510 4511 /* 4512 * iscsi_get_param - This function is a helper to ISCSI_GET_PARAM 4513 * IOCTL 4514 */ 4515 int 4516 iscsi_get_param(iscsi_login_params_t *params, boolean_t valid_flag, 4517 iscsi_param_get_t *ipgp) { 4518 int rtn = 0; 4519 4520 /* ---- Default to settable, possibly changed later ---- */ 4521 ipgp->g_value.v_valid = valid_flag; 4522 ipgp->g_value.v_settable = B_TRUE; 4523 4524 switch (ipgp->g_param) { 4525 /* 4526 * Boolean parameters 4527 */ 4528 case ISCSI_LOGIN_PARAM_DATA_SEQUENCE_IN_ORDER: 4529 ipgp->g_value.v_bool.b_current = 4530 params->data_sequence_in_order; 4531 ipgp->g_value.v_bool.b_default = 4532 ISCSI_DEFAULT_DATA_SEQUENCE_IN_ORDER; 4533 break; 4534 case ISCSI_LOGIN_PARAM_IMMEDIATE_DATA: 4535 ipgp->g_value.v_bool.b_current = 4536 params->immediate_data; 4537 ipgp->g_value.v_bool.b_default = 4538 ISCSI_DEFAULT_IMMEDIATE_DATA; 4539 break; 4540 case ISCSI_LOGIN_PARAM_INITIAL_R2T: 4541 ipgp->g_value.v_bool.b_current = 4542 params->initial_r2t; 4543 ipgp->g_value.v_bool.b_default = 4544 ISCSI_DEFAULT_IMMEDIATE_DATA; 4545 break; 4546 case ISCSI_LOGIN_PARAM_DATA_PDU_IN_ORDER: 4547 ipgp->g_value.v_bool.b_current = 4548 params->data_pdu_in_order; 4549 ipgp->g_value.v_bool.b_default = 4550 ISCSI_DEFAULT_DATA_PDU_IN_ORDER; 4551 break; 4552 4553 /* 4554 * Integer parameters 4555 */ 4556 case ISCSI_LOGIN_PARAM_HEADER_DIGEST: 4557 ipgp->g_value.v_integer.i_current = params->header_digest; 4558 ipgp->g_value.v_integer.i_default = ISCSI_DEFAULT_HEADER_DIGEST; 4559 ipgp->g_value.v_integer.i_min = 0; 4560 ipgp->g_value.v_integer.i_max = ISCSI_MAX_HEADER_DIGEST; 4561 ipgp->g_value.v_integer.i_incr = 1; 4562 break; 4563 case ISCSI_LOGIN_PARAM_DATA_DIGEST: 4564 ipgp->g_value.v_integer.i_current = params->data_digest; 4565 ipgp->g_value.v_integer.i_default = ISCSI_DEFAULT_DATA_DIGEST; 4566 ipgp->g_value.v_integer.i_min = 0; 4567 ipgp->g_value.v_integer.i_max = ISCSI_MAX_DATA_DIGEST; 4568 ipgp->g_value.v_integer.i_incr = 1; 4569 break; 4570 case ISCSI_LOGIN_PARAM_DEFAULT_TIME_2_RETAIN: 4571 ipgp->g_value.v_integer.i_current = 4572 params->default_time_to_retain; 4573 ipgp->g_value.v_integer.i_default = 4574 ISCSI_DEFAULT_TIME_TO_RETAIN; 4575 ipgp->g_value.v_integer.i_min = 0; 4576 ipgp->g_value.v_integer.i_max = ISCSI_MAX_TIME2RETAIN; 4577 ipgp->g_value.v_integer.i_incr = 1; 4578 break; 4579 case ISCSI_LOGIN_PARAM_DEFAULT_TIME_2_WAIT: 4580 ipgp->g_value.v_integer.i_current = 4581 params->default_time_to_wait; 4582 ipgp->g_value.v_integer.i_default = 4583 ISCSI_DEFAULT_TIME_TO_WAIT; 4584 ipgp->g_value.v_integer.i_min = 0; 4585 ipgp->g_value.v_integer.i_max = ISCSI_MAX_TIME2WAIT; 4586 ipgp->g_value.v_integer.i_incr = 1; 4587 break; 4588 case ISCSI_LOGIN_PARAM_ERROR_RECOVERY_LEVEL: 4589 ipgp->g_value.v_integer.i_current = 4590 params->error_recovery_level; 4591 ipgp->g_value.v_integer.i_default = 4592 ISCSI_DEFAULT_ERROR_RECOVERY_LEVEL; 4593 ipgp->g_value.v_integer.i_min = 0; 4594 ipgp->g_value.v_integer.i_max = ISCSI_MAX_ERROR_RECOVERY_LEVEL; 4595 ipgp->g_value.v_integer.i_incr = 1; 4596 ipgp->g_value.v_settable = B_FALSE; 4597 break; 4598 case ISCSI_LOGIN_PARAM_FIRST_BURST_LENGTH: 4599 ipgp->g_value.v_integer.i_current = 4600 params->first_burst_length; 4601 ipgp->g_value.v_integer.i_default = 4602 ISCSI_DEFAULT_FIRST_BURST_LENGTH; 4603 ipgp->g_value.v_integer.i_min = 512; 4604 ipgp->g_value.v_integer.i_max = ISCSI_MAX_FIRST_BURST_LENGTH; 4605 ipgp->g_value.v_integer.i_incr = 1; 4606 break; 4607 case ISCSI_LOGIN_PARAM_MAX_BURST_LENGTH: 4608 ipgp->g_value.v_integer.i_current = 4609 params->max_burst_length; 4610 ipgp->g_value.v_integer.i_default = 4611 ISCSI_DEFAULT_MAX_BURST_LENGTH; 4612 ipgp->g_value.v_integer.i_min = 512; 4613 ipgp->g_value.v_integer.i_max = ISCSI_MAX_BURST_LENGTH; 4614 ipgp->g_value.v_integer.i_incr = 1; 4615 break; 4616 case ISCSI_LOGIN_PARAM_MAX_CONNECTIONS: 4617 ipgp->g_value.v_integer.i_current = 4618 params->max_connections; 4619 ipgp->g_value.v_settable = B_FALSE; 4620 ipgp->g_value.v_integer.i_default = 4621 ISCSI_DEFAULT_MAX_CONNECTIONS; 4622 ipgp->g_value.v_integer.i_min = 1; 4623 ipgp->g_value.v_integer.i_max = ISCSI_MAX_CONNECTIONS; 4624 ipgp->g_value.v_integer.i_incr = 1; 4625 break; 4626 case ISCSI_LOGIN_PARAM_OUTSTANDING_R2T: 4627 ipgp->g_value.v_integer.i_current = 4628 params->max_outstanding_r2t; 4629 ipgp->g_value.v_settable = B_FALSE; 4630 ipgp->g_value.v_integer.i_default = 4631 ISCSI_DEFAULT_MAX_OUT_R2T; 4632 ipgp->g_value.v_integer.i_min = 1; 4633 ipgp->g_value.v_integer.i_max = ISCSI_MAX_OUTSTANDING_R2T; 4634 ipgp->g_value.v_integer.i_incr = 1; 4635 break; 4636 case ISCSI_LOGIN_PARAM_MAX_RECV_DATA_SEGMENT_LENGTH: 4637 ipgp->g_value.v_integer.i_current = 4638 params->max_recv_data_seg_len; 4639 ipgp->g_value.v_integer.i_default = 4640 ISCSI_DEFAULT_MAX_RECV_SEG_LEN; 4641 ipgp->g_value.v_integer.i_min = 512; 4642 ipgp->g_value.v_integer.i_max = 4643 ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH; 4644 ipgp->g_value.v_integer.i_incr = 1; 4645 break; 4646 default: 4647 rtn = EINVAL; 4648 } 4649 4650 return (rtn); 4651 } 4652 4653 /* 4654 * +--------------------------------------------------------------------+ 4655 * | End of ioctl utility routines | 4656 * +--------------------------------------------------------------------+ 4657 */ 4658 4659 /* 4660 * iscsi_get_name_from_iqn - Translates a normal iqn/eui into a 4661 * IEEE safe address. IEEE addresses have a number of characters 4662 * set aside as reserved. 4663 */ 4664 static void 4665 iscsi_get_name_from_iqn(char *name, int name_max_len) 4666 { 4667 char *tmp = NULL; 4668 char *oldch = NULL; 4669 char *newch = NULL; 4670 4671 tmp = kmem_zalloc(MAX_GET_NAME_SIZE, KM_SLEEP); 4672 4673 for (oldch = &name[0], newch = &tmp[0]; *oldch != '\0'; 4674 oldch++, newch++) { 4675 switch (*oldch) { 4676 case ':': 4677 *newch++ = '%'; 4678 *newch++ = '3'; 4679 *newch = 'A'; 4680 break; 4681 case ' ': 4682 *newch++ = '%'; 4683 *newch++ = '2'; 4684 *newch = '0'; 4685 break; 4686 case '@': 4687 *newch++ = '%'; 4688 *newch++ = '4'; 4689 *newch = '0'; 4690 break; 4691 case '/': 4692 *newch++ = '%'; 4693 *newch++ = '2'; 4694 *newch = 'F'; 4695 break; 4696 default: 4697 *newch = *oldch; 4698 } 4699 } 4700 (void) strncpy(name, tmp, name_max_len); 4701 kmem_free(tmp, MAX_GET_NAME_SIZE); 4702 } 4703 4704 /* 4705 * iscsi_get_name_to_iqn - Converts IEEE safe address back 4706 * into a iscsi iqn/eui. 4707 */ 4708 static void 4709 iscsi_get_name_to_iqn(char *name, int name_max_len) 4710 { 4711 char *tmp = NULL; 4712 char *oldch = NULL; 4713 char *newch = NULL; 4714 4715 tmp = kmem_zalloc(MAX_GET_NAME_SIZE, KM_SLEEP); 4716 4717 for (oldch = &name[0], newch = &tmp[0]; *oldch != '\0'; 4718 oldch++, newch++) { 4719 if (*oldch == '%') { 4720 switch (*(oldch+1)) { 4721 case '2': 4722 if (*(oldch+2) == '0') { 4723 *newch = ' '; 4724 oldch += 2; 4725 } else if (*(oldch+2) == 'F') { 4726 *newch = '/'; 4727 oldch += 2; 4728 } else { 4729 *newch = *oldch; 4730 } 4731 break; 4732 case '3': 4733 if (*(oldch+2) == 'A') { 4734 *newch = ':'; 4735 oldch += 2; 4736 } else { 4737 *newch = *oldch; 4738 } 4739 break; 4740 case '4': 4741 if (*(oldch+2) == '0') { 4742 *newch = '@'; 4743 oldch += 2; 4744 } else { 4745 *newch = *oldch; 4746 } 4747 break; 4748 default: 4749 *newch = *oldch; 4750 } 4751 } else { 4752 *newch = *oldch; 4753 } 4754 } 4755 (void) strncpy(name, tmp, name_max_len); 4756 kmem_free(tmp, MAX_GET_NAME_SIZE); 4757 } 4758 4759 /* 4760 * iscsi_get_persisted_param * - a helper to ISCSI_GET_PARAM ioctl 4761 * 4762 * On return 0 means persisted parameter found 4763 */ 4764 int 4765 iscsi_get_persisted_param(uchar_t *name, iscsi_param_get_t *ipgp, 4766 iscsi_login_params_t *params) 4767 { 4768 int rtn = 1; 4769 persistent_param_t *pparam; 4770 4771 if (name == NULL || strlen((char *)name) == 0) { 4772 return (rtn); 4773 } 4774 4775 pparam = (persistent_param_t *)kmem_zalloc(sizeof (*pparam), KM_SLEEP); 4776 4777 if (persistent_param_get((char *)name, pparam) == B_TRUE) { 4778 if (pparam->p_bitmap & (1 << ipgp->g_param)) { 4779 /* Found configured parameter. */ 4780 bcopy(&pparam->p_params, params, sizeof (*params)); 4781 rtn = 0; 4782 } 4783 } 4784 4785 kmem_free(pparam, sizeof (*pparam)); 4786 4787 return (rtn); 4788 } 4789 4790 /* 4791 * iscsi_override_target_default - helper function set the target's default 4792 * login parameter if there is a configured initiator parameter. 4793 * 4794 */ 4795 static void 4796 iscsi_override_target_default(iscsi_hba_t *ihp, iscsi_param_get_t *ipg) 4797 { 4798 persistent_param_t *pp; 4799 iscsi_login_params_t *params; 4800 4801 pp = (persistent_param_t *)kmem_zalloc(sizeof (*pp), KM_SLEEP); 4802 if (persistent_param_get((char *)ihp->hba_name, pp) == B_TRUE) { 4803 if (pp->p_bitmap & (1 << ipg->g_param)) { 4804 params = &pp->p_params; 4805 switch (ipg->g_param) { 4806 case ISCSI_LOGIN_PARAM_DATA_SEQUENCE_IN_ORDER: 4807 ipg->g_value.v_bool.b_default = 4808 params->data_sequence_in_order; 4809 break; 4810 case ISCSI_LOGIN_PARAM_IMMEDIATE_DATA: 4811 ipg->g_value.v_bool.b_default = 4812 params->immediate_data; 4813 break; 4814 case ISCSI_LOGIN_PARAM_INITIAL_R2T: 4815 ipg->g_value.v_bool.b_default = 4816 params->initial_r2t; 4817 break; 4818 case ISCSI_LOGIN_PARAM_DATA_PDU_IN_ORDER: 4819 ipg->g_value.v_bool.b_default = 4820 params->data_pdu_in_order; 4821 break; 4822 case ISCSI_LOGIN_PARAM_HEADER_DIGEST: 4823 ipg->g_value.v_integer.i_default = 4824 params->header_digest; 4825 break; 4826 case ISCSI_LOGIN_PARAM_DATA_DIGEST: 4827 ipg->g_value.v_integer.i_default = 4828 params->data_digest; 4829 break; 4830 case ISCSI_LOGIN_PARAM_DEFAULT_TIME_2_RETAIN: 4831 ipg->g_value.v_integer.i_default = 4832 params->default_time_to_retain; 4833 break; 4834 case ISCSI_LOGIN_PARAM_DEFAULT_TIME_2_WAIT: 4835 ipg->g_value.v_integer.i_default = 4836 params->default_time_to_wait; 4837 break; 4838 case ISCSI_LOGIN_PARAM_ERROR_RECOVERY_LEVEL: 4839 ipg->g_value.v_integer.i_default = 4840 params->error_recovery_level; 4841 break; 4842 case ISCSI_LOGIN_PARAM_FIRST_BURST_LENGTH: 4843 ipg->g_value.v_integer.i_default = 4844 params->first_burst_length; 4845 break; 4846 case ISCSI_LOGIN_PARAM_MAX_BURST_LENGTH: 4847 ipg->g_value.v_integer.i_default = 4848 params->max_burst_length; 4849 break; 4850 case ISCSI_LOGIN_PARAM_MAX_CONNECTIONS: 4851 ipg->g_value.v_integer.i_default = 4852 params->max_connections; 4853 break; 4854 case ISCSI_LOGIN_PARAM_OUTSTANDING_R2T: 4855 ipg->g_value.v_integer.i_default = 4856 params->max_outstanding_r2t; 4857 break; 4858 case ISCSI_LOGIN_PARAM_MAX_RECV_DATA_SEGMENT_LENGTH: 4859 ipg->g_value.v_integer.i_default = 4860 params->max_xmit_data_seg_len; 4861 break; 4862 default: 4863 break; 4864 } 4865 } 4866 } 4867 kmem_free(pp, sizeof (*pp)); 4868 } 4869 4870 static boolean_t 4871 iscsi_cmp_boot_sess_oid(iscsi_hba_t *ihp, uint32_t oid) 4872 { 4873 iscsi_sess_t *isp = NULL; 4874 4875 if (iscsi_chk_bootlun_mpxio(ihp)) { 4876 for (isp = ihp->hba_sess_list; isp; isp = isp->sess_next) { 4877 if ((isp->sess_oid == oid) && isp->sess_boot) { 4878 /* oid is session object */ 4879 break; 4880 } 4881 if ((isp->sess_target_oid == oid) && isp->sess_boot) { 4882 /* 4883 * oid is target object while 4884 * this session is boot session 4885 */ 4886 break; 4887 } 4888 } 4889 if (oid == ihp->hba_oid) { 4890 /* oid is initiator object id */ 4891 return (B_TRUE); 4892 } else if ((isp != NULL) && (isp->sess_boot)) { 4893 /* oid is boot session object id */ 4894 return (B_TRUE); 4895 } 4896 } 4897 return (B_FALSE); 4898 } 4899