Print this page
NEX-19489 BDD tests causes node panic during stage-vm1
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-17944 HBA drivers don't need the redundant devfs_clean step
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
NEX-3414 CLONE - Port 3339 iscsi/fs:5 causes panic on initiator
NEX-3419 CLONE - Run multi initiator sessions to a single target test can panic the initiator
Reviewed by: Steve Peng <steve.peng@nexenta.com>
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi_lun.c
+++ new/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi_lun.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
|
↓ open down ↓ |
10 lines elided |
↑ open up ↑ |
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 23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 24 * Use is subject to license terms.
24 - *
25 + */
26 +
27 +/*
28 + * Copyright 2019 Nexenta Systems, Inc.
29 + */
30 +
31 +/*
25 32 * iSCSI logical unit interfaces
26 33 */
27 34
28 35 #include "iscsi.h"
29 -#include <sys/fs/dv_node.h> /* devfs_clean */
30 36 #include <sys/bootprops.h>
31 37 #include <sys/sysevent/eventdefs.h>
32 38 #include <sys/sysevent/dev.h>
33 39
34 40 /* tpgt bytes in string form */
35 41 #define TPGT_EXT_SIZE 5
36 42
37 43 /* logical unit number bytes in string form */
38 44 #define LUN_EXT_SIZE 10
39 45
40 46 /*
41 47 * Addition addr size of size of ',' + max str form of tpgt (2 bytes) +
42 48 * ',' + max str form of logical unit number (4 bytes).
43 49 */
44 50 #define ADDR_EXT_SIZE (1 + TPGT_EXT_SIZE + 1 + LUN_EXT_SIZE)
45 51
46 52 /* internal interfaces */
47 53 static iscsi_status_t iscsi_lun_virt_create(iscsi_sess_t *isp,
48 54 uint16_t lun_num, iscsi_lun_t *ilp, struct scsi_inquiry *inq);
49 55 static iscsi_status_t iscsi_lun_phys_create(iscsi_sess_t *isp,
50 56 uint16_t lun_num, iscsi_lun_t *ilp, struct scsi_inquiry *inq);
51 57
52 58 extern dev_info_t *scsi_vhci_dip;
53 59 extern ib_boot_prop_t *iscsiboot_prop;
54 60
55 61 /*
56 62 * +--------------------------------------------------------------------+
57 63 * | External Connection Interfaces |
58 64 * +--------------------------------------------------------------------+
59 65 */
60 66
61 67
62 68 /*
63 69 * iscsi_lun_create - This function will create a lun mapping.
64 70 * logic specific to MPxIO vs. NDI node creation is switched
65 71 * out to a helper function.
66 72 */
67 73 iscsi_status_t
68 74 iscsi_lun_create(iscsi_sess_t *isp, uint16_t lun_num, uint8_t lun_addr_type,
69 75 struct scsi_inquiry *inq, char *guid)
70 76 {
71 77 iscsi_status_t rtn = ISCSI_STATUS_INTERNAL_ERROR;
72 78 iscsi_hba_t *ihp = NULL;
73 79 iscsi_lun_t *ilp = NULL;
74 80 iscsi_lun_t *ilp_tmp = NULL;
75 81 char *addr = NULL;
76 82 uint16_t boot_lun_num = 0;
77 83 uint64_t *lun_num_ptr = NULL;
78 84 uint32_t oid_tmp = 0;
79 85
80 86 ASSERT(isp != NULL);
81 87 ihp = isp->sess_hba;
82 88 ASSERT(ihp != NULL);
83 89
84 90 mutex_enter(&iscsi_oid_mutex);
85 91 oid_tmp = iscsi_oid++;
86 92 mutex_exit(&iscsi_oid_mutex);
87 93
88 94 rw_enter(&isp->sess_lun_list_rwlock, RW_WRITER);
89 95 /*
90 96 * Check whether it has already existed in the list.
91 97 */
92 98 for (ilp_tmp = isp->sess_lun_list; ilp_tmp != NULL;
93 99 ilp_tmp = ilp_tmp->lun_next) {
94 100 if (ilp_tmp->lun_num == lun_num) {
95 101 /*
96 102 * The logic unit has already existed in the list,
97 103 * return with success.
98 104 */
99 105 rw_exit(&isp->sess_lun_list_rwlock);
100 106 return (ISCSI_STATUS_SUCCESS);
101 107 }
102 108 }
103 109
104 110 addr = kmem_zalloc((strlen((char *)isp->sess_name) +
105 111 ADDR_EXT_SIZE + 1), KM_SLEEP);
106 112 (void) snprintf(addr,
107 113 (strlen((char *)isp->sess_name) +
108 114 ADDR_EXT_SIZE + 1),
109 115 "%02X%02X%s%04X,%d", isp->sess_isid[4],
110 116 isp->sess_isid[5], isp->sess_name,
111 117 isp->sess_tpgt_nego & 0xFFFF, lun_num);
112 118
113 119 /* allocate space for lun struct */
114 120 ilp = kmem_zalloc(sizeof (iscsi_lun_t), KM_SLEEP);
115 121 ilp->lun_sig = ISCSI_SIG_LUN;
|
↓ open down ↓ |
76 lines elided |
↑ open up ↑ |
116 122 ilp->lun_state &= ISCSI_LUN_STATE_CLEAR;
117 123 ilp->lun_state |= ISCSI_LUN_STATE_OFFLINE;
118 124
119 125 /* initialize common LU information */
120 126 ilp->lun_num = lun_num;
121 127 ilp->lun_addr_type = lun_addr_type;
122 128 ilp->lun_sess = isp;
123 129 ilp->lun_addr = addr;
124 130 ilp->lun_type = inq->inq_dtype & DTYPE_MASK;
125 131 ilp->lun_oid = oid_tmp;
132 + /*
133 + * Setting refcnt to 1 is the first hold for the LUN structure.
134 + */
135 + ilp->lun_refcnt = 1;
136 + mutex_init(&ilp->lun_mutex, NULL, MUTEX_DRIVER, NULL);
126 137
127 138 bcopy(inq->inq_vid, ilp->lun_vid, sizeof (inq->inq_vid));
128 139 bcopy(inq->inq_pid, ilp->lun_pid, sizeof (inq->inq_pid));
129 140
130 141 /* store GUID if valid one exists */
131 142 if (guid != NULL) {
132 143 ilp->lun_guid_size = strlen(guid) + 1;
133 144 ilp->lun_guid = kmem_zalloc(ilp->lun_guid_size, KM_SLEEP);
134 145 (void) strcpy(ilp->lun_guid, guid);
135 146 } else {
136 147 ilp->lun_guid_size = 0;
137 148 ilp->lun_guid = NULL;
138 149 }
139 150
140 151 /*
141 152 * We need to add the lun to our lists now because during the
142 153 * lun creation we will get called back into multiple times
143 154 * depending on the createion type. These callbacks will
144 155 * occur via our tran_init_lun, tran_get_name, tran_get_bus_addr,
145 156 * tran_init_pkt, tran_start.
146 157 */
147 158 if (isp->sess_lun_list == NULL) {
148 159 isp->sess_lun_list = ilp;
149 160 } else {
150 161 ilp->lun_next = isp->sess_lun_list;
151 162 isp->sess_lun_list = ilp;
152 163 }
153 164
154 165 /* Attempt to create a scsi_vhci binding if GUID is available */
155 166 if ((ihp->hba_mpxio_enabled == B_TRUE) &&
156 167 (guid != NULL)) {
157 168 rtn = iscsi_lun_virt_create(isp, lun_num, ilp, inq);
158 169 }
159 170 if (!ISCSI_SUCCESS(rtn)) {
160 171 /* unable to bind under scsi_vhci, failback to ndi */
161 172 rtn = iscsi_lun_phys_create(isp, lun_num, ilp, inq);
162 173 }
163 174
164 175 /*
165 176 * If NOT successful we need to remove the lun from the
166 177 * session and free any related resources.
167 178 */
168 179 if (!ISCSI_SUCCESS(rtn)) {
169 180 if (ilp == isp->sess_lun_list) {
170 181 /* if head, set head to our next */
171 182 isp->sess_lun_list = ilp->lun_next;
172 183 } else {
173 184 /* if not head, set prev lun's next to our next */
174 185 for (ilp_tmp = isp->sess_lun_list; ilp_tmp;
175 186 ilp_tmp = ilp_tmp->lun_next) {
176 187 if (ilp_tmp->lun_next == ilp) {
177 188 ilp_tmp->lun_next = ilp->lun_next;
178 189 break;
179 190 }
180 191 }
181 192 }
|
↓ open down ↓ |
46 lines elided |
↑ open up ↑ |
182 193
183 194 kmem_free(ilp->lun_addr,
184 195 (strlen((char *)isp->sess_name) +
185 196 ADDR_EXT_SIZE + 1));
186 197 ilp->lun_addr = NULL;
187 198
188 199 if (ilp->lun_guid != NULL) {
189 200 kmem_free(ilp->lun_guid, ilp->lun_guid_size);
190 201 ilp->lun_guid = NULL;
191 202 }
203 + mutex_destroy(&ilp->lun_mutex);
192 204 kmem_free(ilp, sizeof (iscsi_lun_t));
193 205 } else {
194 206 ilp->lun_state &= ISCSI_LUN_STATE_CLEAR;
195 207 ilp->lun_state |= ISCSI_LUN_STATE_ONLINE;
196 208 ilp->lun_time_online = ddi_get_time();
197 209
198 210 /* Check whether this is the required LUN for iscsi boot */
199 211 if (iscsiboot_prop != NULL && isp->sess_boot == B_TRUE &&
200 212 iscsiboot_prop->boot_tgt.lun_online == 0) {
201 213 lun_num_ptr =
202 214 (uint64_t *)iscsiboot_prop->boot_tgt.tgt_boot_lun;
203 215 boot_lun_num = (uint16_t)(*lun_num_ptr);
204 216 if (boot_lun_num == ilp->lun_num) {
205 217 /*
206 218 * During iscsi boot, the boot lun has been
207 219 * online, we should set the "online flag".
|
↓ open down ↓ |
6 lines elided |
↑ open up ↑ |
208 220 */
209 221 iscsiboot_prop->boot_tgt.lun_online = 1;
210 222 }
211 223 }
212 224 }
213 225 rw_exit(&isp->sess_lun_list_rwlock);
214 226
215 227 return (rtn);
216 228 }
217 229
230 +void
231 +iscsi_lun_hold(iscsi_lun_t *ilp)
232 +{
233 + mutex_enter(&ilp->lun_mutex);
234 + /*
235 + * By design lun_refcnt should never be zero when this routine
236 + * is called. When the LUN is created the refcnt is set to 1.
237 + * If iscsi_lun_rele is called and the refcnt goes to zero the
238 + * structure will be freed so this method shouldn't be called
239 + * afterwards.
240 + */
241 + ASSERT(ilp->lun_refcnt > 0);
242 + ilp->lun_refcnt++;
243 + mutex_exit(&ilp->lun_mutex);
244 +}
245 +
246 +void
247 +iscsi_lun_rele(iscsi_lun_t *ilp)
248 +{
249 + ASSERT(ilp != NULL);
250 +
251 + mutex_enter(&ilp->lun_mutex);
252 + ASSERT(ilp->lun_refcnt > 0);
253 + if (--ilp->lun_refcnt == 0) {
254 + iscsi_sess_t *isp;
255 +
256 + isp = ilp->lun_sess;
257 + ASSERT(isp != NULL);
258 +
259 + /* ---- release its memory ---- */
260 + kmem_free(ilp->lun_addr, (strlen((char *)isp->sess_name) +
261 + ADDR_EXT_SIZE + 1));
262 +
263 + if (ilp->lun_guid != NULL) {
264 + kmem_free(ilp->lun_guid, ilp->lun_guid_size);
265 + }
266 + mutex_destroy(&ilp->lun_mutex);
267 + kmem_free(ilp, sizeof (iscsi_lun_t));
268 + } else {
269 + mutex_exit(&ilp->lun_mutex);
270 + }
271 +}
272 +
218 273 /*
274 + * iscsi_lun_cmd_cancel -- as the name implies, cancel all commands for the lun
275 + *
276 + * This code is similar to the timeout function with a lot less checking of
277 + * state before sending the ABORT event for commands on the pending queue.
278 + *
279 + * This function is only used by iscsi_lun_destroy().
280 + */
281 +static void
282 +iscsi_lun_cmd_cancel(iscsi_lun_t *ilp)
283 +{
284 + iscsi_sess_t *isp;
285 + iscsi_cmd_t *icmdp, *nicmdp;
286 +
287 + isp = ilp->lun_sess;
288 + rw_enter(&isp->sess_state_rwlock, RW_READER);
289 + mutex_enter(&isp->sess_queue_pending.mutex);
290 + for (icmdp = isp->sess_queue_pending.head;
291 + icmdp; icmdp = nicmdp) {
292 + nicmdp = icmdp->cmd_next;
293 +
294 + /*
295 + * For commands on the pending queue we can go straight
296 + * to and abort request which will free the command
297 + * and call back to the complete function.
298 + */
299 + iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E4, isp);
300 + }
301 + mutex_exit(&isp->sess_queue_pending.mutex);
302 + rw_exit(&isp->sess_state_rwlock);
303 +}
304 +
305 +/*
219 306 * iscsi_lun_destroy - offline and remove lun
220 307 *
221 308 * This interface is called when a name service change has
222 309 * occured and the storage is no longer available to this
223 310 * initiator. This function will offline and free the
224 311 * solaris node resources. Then it will free all iscsi lun
225 312 * resources.
226 313 *
227 314 * This function can fail with ISCSI_STATUS_BUSY if the
228 315 * logical unit is in use. The user should unmount or
229 316 * close the device and perform the nameservice operation
230 317 * again if this occurs.
231 318 */
232 319 iscsi_status_t
|
↓ open down ↓ |
4 lines elided |
↑ open up ↑ |
233 320 iscsi_lun_destroy(iscsi_hba_t *ihp, iscsi_lun_t *ilp)
234 321 {
235 322 iscsi_status_t status = ISCSI_STATUS_SUCCESS;
236 323 iscsi_sess_t *isp = NULL;
237 324 iscsi_lun_t *t_ilp = NULL;
238 325
239 326 ASSERT(ilp != NULL);
240 327 isp = ilp->lun_sess;
241 328 ASSERT(isp != NULL);
242 329
330 + /* flush all outstanding commands first */
331 + iscsi_lun_cmd_cancel(ilp);
332 +
243 333 /* attempt to offline and free solaris node */
244 334 status = iscsi_lun_offline(ihp, ilp, B_TRUE);
245 335
246 336 /* If we successfully unplumbed the lun remove it from our lists */
247 337 if (ISCSI_SUCCESS(status)) {
248 338 if (isp->sess_lun_list == ilp) {
249 339 /* target first item in list */
250 340 isp->sess_lun_list = ilp->lun_next;
251 341 } else {
252 342 /*
253 343 * search session list for ilp pointing
254 344 * to lun being removed. Then
255 345 * update that luns next pointer.
256 346 */
257 347 t_ilp = isp->sess_lun_list;
258 348 while (t_ilp->lun_next != NULL) {
259 349 if (t_ilp->lun_next == ilp) {
260 350 break;
261 351 }
|
↓ open down ↓ |
9 lines elided |
↑ open up ↑ |
262 352 t_ilp = t_ilp->lun_next;
263 353 }
264 354 if (t_ilp->lun_next == ilp) {
265 355 t_ilp->lun_next = ilp->lun_next;
266 356 } else {
267 357 /* couldn't find session */
268 358 ASSERT(FALSE);
269 359 }
270 360 }
271 361
272 - /* release its memory */
273 - kmem_free(ilp->lun_addr, (strlen((char *)isp->sess_name) +
274 - ADDR_EXT_SIZE + 1));
275 - ilp->lun_addr = NULL;
276 - if (ilp->lun_guid != NULL) {
277 - kmem_free(ilp->lun_guid, ilp->lun_guid_size);
278 - ilp->lun_guid = NULL;
279 - }
280 - kmem_free(ilp, sizeof (iscsi_lun_t));
281 - ilp = NULL;
362 + iscsi_lun_rele(ilp);
282 363 }
283 364
284 365 return (status);
285 366 }
286 367
287 368 /*
288 369 * +--------------------------------------------------------------------+
289 370 * | External Logical Unit Interfaces |
290 371 * +--------------------------------------------------------------------+
291 372 */
292 373
293 374 /*
294 375 * iscsi_lun_virt_create - Creates solaris logical unit via MDI
295 376 */
296 377 static iscsi_status_t
297 378 iscsi_lun_virt_create(iscsi_sess_t *isp, uint16_t lun_num, iscsi_lun_t *ilp,
298 379 struct scsi_inquiry *inq)
299 380 {
300 381 iscsi_status_t rtn = ISCSI_STATUS_INTERNAL_ERROR;
301 382 int mdi_rtn = MDI_FAILURE;
302 383 iscsi_hba_t *ihp = NULL;
303 384 mdi_pathinfo_t *pip = NULL;
304 385 char *nodename = NULL;
305 386 char **compatible = NULL;
306 387 int ncompatible = 0;
307 388 int circ = 0;
308 389
309 390 ASSERT(isp != NULL);
310 391 ASSERT(ilp != NULL);
311 392 ihp = isp->sess_hba;
312 393 ASSERT(ihp != NULL);
313 394
314 395 /*
315 396 * Generate compatible property
316 397 */
317 398 scsi_hba_nodename_compatible_get(inq, "vhci",
318 399 inq->inq_dtype, NULL, &nodename, &compatible, &ncompatible);
319 400
320 401 /* if nodename can't be determined then print a message and skip it */
321 402 if (nodename == NULL) {
322 403 cmn_err(CE_WARN, "iscsi driver found no compatible driver "
323 404 "for %s lun %d dtype:0x%02x", isp->sess_name, lun_num,
324 405 inq->inq_dtype);
325 406 return (ISCSI_STATUS_INTERNAL_ERROR);
326 407 }
327 408
328 409 /*
329 410 *
330 411 */
331 412 ndi_devi_enter(scsi_vhci_dip, &circ);
332 413 mdi_rtn = mdi_pi_alloc_compatible(ihp->hba_dip, nodename,
333 414 ilp->lun_guid, ilp->lun_addr, compatible, ncompatible,
334 415 0, &pip);
335 416
336 417 if (mdi_rtn == MDI_SUCCESS) {
337 418 mdi_pi_set_phci_private(pip, (caddr_t)ilp);
338 419
339 420 if (mdi_prop_update_string(pip, MDI_GUID,
340 421 ilp->lun_guid) != DDI_SUCCESS) {
341 422 cmn_err(CE_WARN, "iscsi driver unable to create "
342 423 "property for %s lun %d (MDI_GUID)",
343 424 isp->sess_name, lun_num);
344 425 mdi_rtn = MDI_FAILURE;
345 426 goto virt_create_done;
346 427 }
347 428
348 429 if (mdi_prop_update_int(pip, TARGET_PROP,
349 430 isp->sess_oid) != DDI_SUCCESS) {
350 431 cmn_err(CE_WARN, "iscsi driver unable to create "
351 432 "property for %s lun %d (TARGET_PROP)",
352 433 isp->sess_name, lun_num);
353 434 mdi_rtn = MDI_FAILURE;
354 435 goto virt_create_done;
355 436 }
356 437
357 438 if (mdi_prop_update_int(pip, LUN_PROP,
358 439 ilp->lun_num) != DDI_SUCCESS) {
359 440 cmn_err(CE_WARN, "iscsi driver unable to create "
360 441 "property for %s lun %d (LUN_PROP)",
361 442 isp->sess_name, lun_num);
362 443 mdi_rtn = MDI_FAILURE;
363 444 goto virt_create_done;
364 445 }
365 446
366 447 if (mdi_prop_update_string_array(pip, "compatible",
367 448 compatible, ncompatible) !=
368 449 DDI_PROP_SUCCESS) {
369 450 cmn_err(CE_WARN, "iscsi driver unable to create "
370 451 "property for %s lun %d (COMPATIBLE)",
371 452 isp->sess_name, lun_num);
372 453 mdi_rtn = MDI_FAILURE;
373 454 goto virt_create_done;
374 455 }
375 456
376 457 mdi_rtn = mdi_pi_online(pip, 0);
377 458 if (mdi_rtn == MDI_NOT_SUPPORTED) {
378 459 mdi_rtn = MDI_FAILURE;
379 460 goto virt_create_done;
380 461 }
381 462
382 463 ilp->lun_pip = pip;
383 464 ilp->lun_dip = NULL;
384 465
385 466 virt_create_done:
386 467
387 468 if (pip && mdi_rtn != MDI_SUCCESS) {
388 469 ilp->lun_pip = NULL;
389 470 ilp->lun_dip = NULL;
390 471 (void) mdi_prop_remove(pip, NULL);
391 472 (void) mdi_pi_free(pip, 0);
392 473 } else {
393 474 rtn = ISCSI_STATUS_SUCCESS;
394 475 }
395 476 }
396 477 ndi_devi_exit(scsi_vhci_dip, circ);
397 478
398 479 scsi_hba_nodename_compatible_free(nodename, compatible);
399 480
400 481 return (rtn);
401 482 }
402 483
403 484
404 485 /*
405 486 * iscsi_lun_phys_create - creates solaris logical unit via NDI
406 487 */
407 488 static iscsi_status_t
408 489 iscsi_lun_phys_create(iscsi_sess_t *isp, uint16_t lun_num,
409 490 iscsi_lun_t *ilp, struct scsi_inquiry *inq)
410 491 {
411 492 iscsi_status_t rtn = ISCSI_STATUS_INTERNAL_ERROR;
412 493 int ndi_rtn = NDI_FAILURE;
413 494 iscsi_hba_t *ihp = NULL;
414 495 dev_info_t *lun_dip = NULL;
415 496 char *nodename = NULL;
416 497 char **compatible = NULL;
417 498 int ncompatible = 0;
418 499 char *scsi_binding_set = NULL;
419 500 char instance[32];
420 501 int circ = 0;
421 502
422 503 ASSERT(isp != NULL);
423 504 ASSERT(ilp != NULL);
424 505 ihp = isp->sess_hba;
425 506 ASSERT(ihp != NULL);
426 507 ASSERT(inq != NULL);
427 508
428 509 /* get the 'scsi-binding-set' property */
429 510 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, isp->sess_hba->hba_dip,
430 511 DDI_PROP_NOTPROM | DDI_PROP_DONTPASS, "scsi-binding-set",
431 512 &scsi_binding_set) != DDI_PROP_SUCCESS) {
432 513 scsi_binding_set = NULL;
433 514 }
434 515
435 516 /* generate compatible property */
436 517 scsi_hba_nodename_compatible_get(inq, scsi_binding_set,
437 518 inq->inq_dtype, NULL, &nodename, &compatible, &ncompatible);
438 519 if (scsi_binding_set)
439 520 ddi_prop_free(scsi_binding_set);
440 521
441 522 /* if nodename can't be determined then print a message and skip it */
442 523 if (nodename == NULL) {
443 524 cmn_err(CE_WARN, "iscsi driver found no compatible driver "
444 525 "for %s lun %d", isp->sess_name, lun_num);
445 526 return (ISCSI_STATUS_INTERNAL_ERROR);
446 527 }
447 528
448 529 ndi_devi_enter(ihp->hba_dip, &circ);
449 530
450 531 ndi_rtn = ndi_devi_alloc(ihp->hba_dip, nodename,
451 532 DEVI_SID_NODEID, &lun_dip);
452 533
453 534 /* if lun alloc success, set props */
454 535 if (ndi_rtn == NDI_SUCCESS) {
455 536
456 537 if (ndi_prop_update_int(DDI_DEV_T_NONE,
457 538 lun_dip, TARGET_PROP, (int)isp->sess_oid) !=
458 539 DDI_PROP_SUCCESS) {
459 540 cmn_err(CE_WARN, "iscsi driver unable to create "
460 541 "property for %s lun %d (TARGET_PROP)",
461 542 isp->sess_name, lun_num);
462 543 ndi_rtn = NDI_FAILURE;
463 544 goto phys_create_done;
464 545 }
465 546
466 547 if (ndi_prop_update_int(DDI_DEV_T_NONE,
467 548 lun_dip, LUN_PROP, (int)ilp->lun_num) !=
468 549 DDI_PROP_SUCCESS) {
469 550 cmn_err(CE_WARN, "iscsi driver unable to create "
470 551 "property for %s lun %d (LUN_PROP)",
471 552 isp->sess_name, lun_num);
472 553 ndi_rtn = NDI_FAILURE;
473 554 goto phys_create_done;
474 555 }
475 556
476 557 if (ndi_prop_update_string_array(DDI_DEV_T_NONE,
477 558 lun_dip, "compatible", compatible, ncompatible)
478 559 != DDI_PROP_SUCCESS) {
479 560 cmn_err(CE_WARN, "iscsi driver unable to create "
480 561 "property for %s lun %d (COMPATIBLE)",
481 562 isp->sess_name, lun_num);
482 563 ndi_rtn = NDI_FAILURE;
483 564 goto phys_create_done;
484 565 }
485 566
486 567 phys_create_done:
487 568 /* If props were setup ok, online the lun */
488 569 if (ndi_rtn == NDI_SUCCESS) {
489 570 /* Try to online the new node */
490 571 ndi_rtn = ndi_devi_online(lun_dip, 0);
491 572 }
492 573
493 574 /* If success set rtn flag, else unwire alloc'd lun */
494 575 if (ndi_rtn == NDI_SUCCESS) {
495 576 rtn = ISCSI_STATUS_SUCCESS;
496 577 /*
497 578 * Assign the instance number for the dev_link
498 579 * generator. This will ensure the link name is
499 580 * unique and persistent across reboots.
500 581 */
501 582 (void) snprintf(instance, 32, "%d",
502 583 ddi_get_instance(lun_dip));
503 584 (void) ndi_prop_update_string(DDI_DEV_T_NONE,
504 585 lun_dip, NDI_GUID, instance);
505 586 } else {
506 587 cmn_err(CE_WARN, "iscsi driver unable to online "
507 588 "%s lun %d", isp->sess_name, lun_num);
508 589 ndi_prop_remove_all(lun_dip);
509 590 (void) ndi_devi_free(lun_dip);
510 591 }
511 592
512 593 }
513 594 ndi_devi_exit(ihp->hba_dip, circ);
514 595
515 596 ilp->lun_dip = lun_dip;
516 597 ilp->lun_pip = NULL;
517 598
518 599 scsi_hba_nodename_compatible_free(nodename, compatible);
519 600
520 601 return (rtn);
521 602 }
522 603
523 604
524 605 /*
525 606 * iscsi_lun_online - _di_online logical unit
526 607 *
527 608 * This is called after a path has recovered it will cause
528 609 * an offline path to become online/active again.
529 610 */
530 611 void
531 612 iscsi_lun_online(iscsi_hba_t *ihp, iscsi_lun_t *ilp)
532 613 {
533 614 int circ = 0;
534 615 int rval = 0;
535 616 uint64_t *lun_num_ptr = NULL;
536 617 uint16_t boot_lun_num = 0;
537 618 iscsi_sess_t *isp = NULL;
538 619 boolean_t online = B_FALSE;
539 620 nvlist_t *attr_list = NULL;
540 621 char *pathname = NULL;
541 622 dev_info_t *lun_dip = NULL;
542 623
543 624 ASSERT(ilp != NULL);
544 625 ASSERT((ilp->lun_pip != NULL) || (ilp->lun_dip != NULL));
545 626
546 627 if (ilp->lun_pip != NULL) {
547 628 ndi_devi_enter(scsi_vhci_dip, &circ);
548 629 rval = mdi_pi_online(ilp->lun_pip, 0);
549 630 ndi_devi_exit(scsi_vhci_dip, circ);
550 631 if (rval == MDI_SUCCESS) {
551 632 ilp->lun_state &= ISCSI_LUN_STATE_CLEAR;
552 633 ilp->lun_state |= ISCSI_LUN_STATE_ONLINE;
553 634 ilp->lun_time_online = ddi_get_time();
554 635 online = B_TRUE;
555 636 }
556 637
557 638 } else if (ilp->lun_dip != NULL) {
558 639 ndi_devi_enter(ihp->hba_dip, &circ);
559 640 rval = ndi_devi_online(ilp->lun_dip, 0);
560 641 ndi_devi_exit(ihp->hba_dip, circ);
561 642 if (rval == NDI_SUCCESS) {
562 643 ilp->lun_state &= ISCSI_LUN_STATE_CLEAR;
563 644 ilp->lun_state |= ISCSI_LUN_STATE_ONLINE;
564 645 ilp->lun_time_online = ddi_get_time();
565 646 online = B_TRUE;
566 647 }
567 648 }
568 649
569 650 /* Check whether this is the required LUN for iscsi boot */
570 651 if (iscsiboot_prop != NULL &&
571 652 iscsiboot_prop->boot_tgt.lun_online == 0) {
572 653 isp = ilp->lun_sess;
573 654 if (isp->sess_boot == B_TRUE) {
574 655 lun_num_ptr =
575 656 (uint64_t *)iscsiboot_prop->boot_tgt.tgt_boot_lun;
576 657 boot_lun_num = (uint16_t)(*lun_num_ptr);
577 658 if (boot_lun_num == ilp->lun_num) {
578 659 /*
579 660 * During iscsi boot, the boot lun has been
580 661 * online, we should set the "online flag".
581 662 */
582 663 iscsiboot_prop->boot_tgt.lun_online = 1;
583 664 }
584 665 }
585 666 }
586 667
587 668 /*
588 669 * If the LUN has been online and it is a disk,
589 670 * send out a system event.
590 671 */
591 672 if (online == B_TRUE && ilp->lun_type == DTYPE_DIRECT) {
592 673 if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, KM_SLEEP) !=
593 674 DDI_SUCCESS) {
594 675 return;
595 676 }
596 677
597 678 if (ilp->lun_pip != NULL) {
598 679 lun_dip = mdi_pi_get_client(ilp->lun_pip);
599 680 } else {
600 681 lun_dip = ilp->lun_dip;
601 682 }
602 683
603 684 pathname = kmem_zalloc(MAXNAMELEN + 1, KM_SLEEP);
604 685 (void) ddi_pathname(lun_dip, pathname);
605 686
606 687 if (nvlist_add_string(attr_list, DEV_PHYS_PATH, pathname) !=
607 688 DDI_SUCCESS) {
608 689 nvlist_free(attr_list);
609 690 kmem_free(pathname, MAXNAMELEN + 1);
610 691 return;
611 692 }
612 693 iscsi_send_sysevent(ihp, EC_DEV_ADD, ESC_DISK, attr_list);
613 694 kmem_free(pathname, MAXNAMELEN + 1);
614 695 nvlist_free(attr_list);
615 696 }
616 697 }
617 698
618 699 /*
619 700 * iscsi_lun_offline - attempt _di_offline [and optional _di_free]
620 701 *
621 702 * This function is called via two paths. When a transport
622 703 * path has failed it will be called to offline the logical
623 704 * unit. When nameservice access has been removed it will
624 705 * be called to both offline and free the logical unit.
625 706 * (This operates soley on the solaris node states.
626 707 * iscsi_lun_destroy() should be called when attempting
627 708 * to free all iscsi lun resources.)
628 709 *
629 710 * This function can fail with ISCSI_STATUS_BUSY if the
630 711 * logical unit is in use. The user should unmount or
631 712 * close the device and perform the nameservice operation
632 713 * again if this occurs.
633 714 *
|
↓ open down ↓ |
342 lines elided |
↑ open up ↑ |
634 715 * If we fail to offline a LUN that we don't want to destroy,
635 716 * we will mark it with invalid state. If this LUN still
636 717 * exists on the target, we can have another chance to online
637 718 * it again when we do the LUN enumeration.
638 719 */
639 720 iscsi_status_t
640 721 iscsi_lun_offline(iscsi_hba_t *ihp, iscsi_lun_t *ilp, boolean_t lun_free)
641 722 {
642 723 iscsi_status_t status = ISCSI_STATUS_SUCCESS;
643 724 int circ = 0;
644 - dev_info_t *cdip, *pdip;
645 - char *devname = NULL;
725 + dev_info_t *cdip;
646 726 char *pathname = NULL;
647 - int rval;
648 727 boolean_t offline = B_FALSE;
649 728 nvlist_t *attr_list = NULL;
650 729
651 730 ASSERT(ilp != NULL);
652 731 ASSERT((ilp->lun_pip != NULL) || (ilp->lun_dip != NULL));
653 732
654 - /*
655 - * Since we carry the logical units parent
656 - * lock across the offline call it will not
657 - * issue devfs_clean() and may fail with a
658 - * devi_ref count > 0.
659 - */
660 - if (ilp->lun_pip == NULL) {
733 + if (ilp->lun_pip == NULL)
661 734 cdip = ilp->lun_dip;
662 - } else {
735 + else
663 736 cdip = mdi_pi_get_client(ilp->lun_pip);
664 - }
665 737
666 - if ((cdip != NULL) &&
667 - (lun_free == B_TRUE) &&
668 - (ilp->lun_state & ISCSI_LUN_STATE_ONLINE)) {
669 - /*
670 - * Make sure node is attached otherwise
671 - * it won't have related cache nodes to
672 - * clean up. i_ddi_devi_attached is
673 - * similiar to i_ddi_node_state(cdip) >=
674 - * DS_ATTACHED. We should clean up only
675 - * when lun_free is set.
676 - */
677 - if (i_ddi_devi_attached(cdip)) {
678 -
679 - /* Get parent dip */
680 - pdip = ddi_get_parent(cdip);
681 -
682 - /* Get full devname */
683 - devname = kmem_alloc(MAXNAMELEN + 1, KM_SLEEP);
684 - ndi_devi_enter(pdip, &circ);
685 - (void) ddi_deviname(cdip, devname);
686 - /* Release lock before devfs_clean() */
687 - ndi_devi_exit(pdip, circ);
688 -
689 - /* Clean cache */
690 - (void) devfs_clean(pdip, devname + 1, DV_CLEAN_FORCE);
691 - kmem_free(devname, MAXNAMELEN + 1);
692 - }
693 - }
694 -
695 738 if (cdip != NULL && ilp->lun_type == DTYPE_DIRECT) {
696 739 pathname = kmem_zalloc(MAXNAMELEN + 1, KM_SLEEP);
697 740 (void) ddi_pathname(cdip, pathname);
698 741 }
699 742
700 743 /* Attempt to offline the logical units */
701 744 if (ilp->lun_pip != NULL) {
702 -
703 745 /* virt/mdi */
704 746 ndi_devi_enter(scsi_vhci_dip, &circ);
705 - if ((lun_free == B_TRUE) &&
706 - (ilp->lun_state & ISCSI_LUN_STATE_ONLINE)) {
707 - rval = mdi_pi_offline(ilp->lun_pip,
708 - NDI_DEVI_REMOVE);
709 - } else {
710 - rval = mdi_pi_offline(ilp->lun_pip, 0);
711 - }
712 -
713 - if (rval == MDI_SUCCESS) {
747 + if (mdi_pi_offline(ilp->lun_pip, 0) == MDI_SUCCESS) {
714 748 ilp->lun_state &= ISCSI_LUN_STATE_CLEAR;
715 749 ilp->lun_state |= ISCSI_LUN_STATE_OFFLINE;
716 750 if (lun_free == B_TRUE) {
717 751 (void) mdi_prop_remove(ilp->lun_pip, NULL);
718 752 (void) mdi_pi_free(ilp->lun_pip, 0);
719 753 }
720 754 offline = B_TRUE;
721 755 } else {
722 756 status = ISCSI_STATUS_BUSY;
723 757 if (lun_free == B_FALSE) {
724 758 ilp->lun_state |= ISCSI_LUN_STATE_INVALID;
725 759 offline = B_TRUE;
726 760 }
727 761 }
728 762 ndi_devi_exit(scsi_vhci_dip, circ);
729 763
730 764 } else {
731 -
732 765 /* phys/ndi */
766 + int flags = NDI_DEVFS_CLEAN;
767 +
733 768 ndi_devi_enter(ihp->hba_dip, &circ);
734 - if ((lun_free == B_TRUE) &&
735 - (ilp->lun_state & ISCSI_LUN_STATE_ONLINE)) {
736 - rval = ndi_devi_offline(
737 - ilp->lun_dip, NDI_DEVI_REMOVE);
738 - } else {
739 - rval = ndi_devi_offline(
740 - ilp->lun_dip, 0);
741 - }
742 - if (rval != NDI_SUCCESS) {
769 + if (lun_free == B_TRUE &&
770 + (ilp->lun_state & ISCSI_LUN_STATE_ONLINE))
771 + flags |= NDI_DEVI_REMOVE;
772 + if (ndi_devi_offline(ilp->lun_dip, flags) != NDI_SUCCESS) {
743 773 status = ISCSI_STATUS_BUSY;
744 774 if (lun_free == B_FALSE) {
745 775 ilp->lun_state |= ISCSI_LUN_STATE_INVALID;
746 776 offline = B_TRUE;
747 777 }
748 778 } else {
749 779 ilp->lun_state &= ISCSI_LUN_STATE_CLEAR;
750 780 ilp->lun_state |= ISCSI_LUN_STATE_OFFLINE;
751 781 offline = B_TRUE;
752 782 }
753 783 ndi_devi_exit(ihp->hba_dip, circ);
754 784 }
755 785
756 786 if (offline == B_TRUE && pathname != NULL &&
757 787 ilp->lun_type == DTYPE_DIRECT) {
758 788 if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, KM_SLEEP) !=
759 789 DDI_SUCCESS) {
760 790 kmem_free(pathname, MAXNAMELEN + 1);
761 791 return (status);
762 792 }
763 793
764 794 if (nvlist_add_string(attr_list, DEV_PHYS_PATH, pathname) !=
765 795 DDI_SUCCESS) {
766 796 nvlist_free(attr_list);
767 797 kmem_free(pathname, MAXNAMELEN + 1);
768 798 return (status);
769 799 }
770 800
771 801 iscsi_send_sysevent(ihp, EC_DEV_REMOVE, ESC_DISK, attr_list);
772 802 nvlist_free(attr_list);
773 803 }
774 804
775 805 if (pathname != NULL) {
776 806 kmem_free(pathname, MAXNAMELEN + 1);
777 807 }
778 808
779 809 return (status);
780 810 }
|
↓ open down ↓ |
28 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX