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