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