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