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