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