1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * 25 * iSCSI logical unit interfaces 26 */ 27 28 #include "iscsi.h" 29 #include <sys/fs/dv_node.h> /* devfs_clean */ 30 #include <sys/bootprops.h> 31 32 /* tpgt bytes in string form */ 33 #define TPGT_EXT_SIZE 5 34 35 /* logical unit number bytes in string form */ 36 #define LUN_EXT_SIZE 10 37 38 /* 39 * Addition addr size of size of ',' + max str form of tpgt (2 bytes) + 40 * ',' + max str form of logical unit number (4 bytes). 41 */ 42 #define ADDR_EXT_SIZE (1 + TPGT_EXT_SIZE + 1 + LUN_EXT_SIZE) 43 44 /* internal interfaces */ 45 static iscsi_status_t iscsi_lun_virt_create(iscsi_sess_t *isp, 46 uint16_t lun_num, iscsi_lun_t *ilp, struct scsi_inquiry *inq); 47 static iscsi_status_t iscsi_lun_phys_create(iscsi_sess_t *isp, 48 uint16_t lun_num, iscsi_lun_t *ilp, struct scsi_inquiry *inq); 49 50 extern dev_info_t *scsi_vhci_dip; 51 extern ib_boot_prop_t *iscsiboot_prop; 52 53 /* 54 * +--------------------------------------------------------------------+ 55 * | External Connection Interfaces | 56 * +--------------------------------------------------------------------+ 57 */ 58 59 60 /* 61 * iscsi_lun_create - This function will create a lun mapping. 62 * logic specific to MPxIO vs. NDI node creation is switched 63 * out to a helper function. 64 */ 65 iscsi_status_t 66 iscsi_lun_create(iscsi_sess_t *isp, uint16_t lun_num, uint8_t lun_addr_type, 67 struct scsi_inquiry *inq, char *guid) 68 { 69 iscsi_status_t rtn = ISCSI_STATUS_INTERNAL_ERROR; 70 iscsi_hba_t *ihp = NULL; 71 iscsi_lun_t *ilp = NULL; 72 iscsi_lun_t *ilp_tmp = NULL; 73 char *addr = NULL; 74 uint16_t boot_lun_num = 0; 75 uint64_t *lun_num_ptr = NULL; 76 77 ASSERT(isp != NULL); 78 ihp = isp->sess_hba; 79 ASSERT(ihp != NULL); 80 81 addr = kmem_zalloc((strlen((char *)isp->sess_name) + 82 ADDR_EXT_SIZE + 1), KM_SLEEP); 83 (void) snprintf(addr, 84 (strlen((char *)isp->sess_name) + 85 ADDR_EXT_SIZE + 1), 86 "%02X%02X%s%04X,%d", isp->sess_isid[4], 87 isp->sess_isid[5], isp->sess_name, 88 isp->sess_tpgt_nego & 0xFFFF, lun_num); 89 90 /* allocate space for lun struct */ 91 ilp = kmem_zalloc(sizeof (iscsi_lun_t), KM_SLEEP); 92 ilp->lun_sig = ISCSI_SIG_LUN; 93 ilp->lun_state &= ISCSI_LUN_STATE_CLEAR; 94 ilp->lun_state |= ISCSI_LUN_STATE_OFFLINE; 95 96 /* initialize common LU information */ 97 ilp->lun_num = lun_num; 98 ilp->lun_addr_type = lun_addr_type; 99 ilp->lun_sess = isp; 100 ilp->lun_addr = addr; 101 102 mutex_enter(&iscsi_oid_mutex); 103 ilp->lun_oid = iscsi_oid++; 104 mutex_exit(&iscsi_oid_mutex); 105 106 bcopy(inq->inq_vid, ilp->lun_vid, sizeof (inq->inq_vid)); 107 bcopy(inq->inq_pid, ilp->lun_pid, sizeof (inq->inq_pid)); 108 109 /* store GUID if valid one exists */ 110 if (guid != NULL) { 111 ilp->lun_guid_size = strlen(guid) + 1; 112 ilp->lun_guid = kmem_zalloc(ilp->lun_guid_size, KM_SLEEP); 113 (void) strcpy(ilp->lun_guid, guid); 114 } else { 115 ilp->lun_guid_size = 0; 116 ilp->lun_guid = NULL; 117 } 118 119 /* 120 * We need to add the lun to our lists now because during the 121 * lun creation we will get called back into multiple times 122 * depending on the createion type. These callbacks will 123 * occur via our tran_init_lun, tran_get_name, tran_get_bus_addr, 124 * tran_init_pkt, tran_start. 125 */ 126 rw_enter(&isp->sess_lun_list_rwlock, RW_WRITER); 127 if (isp->sess_lun_list == NULL) { 128 isp->sess_lun_list = ilp; 129 } else { 130 ilp->lun_next = isp->sess_lun_list; 131 isp->sess_lun_list = ilp; 132 } 133 134 /* Attempt to create a scsi_vhci binding if GUID is available */ 135 if ((ihp->hba_mpxio_enabled == B_TRUE) && 136 (guid != NULL)) { 137 rtn = iscsi_lun_virt_create(isp, lun_num, ilp, inq); 138 } 139 if (!ISCSI_SUCCESS(rtn)) { 140 /* unable to bind under scsi_vhci, failback to ndi */ 141 rtn = iscsi_lun_phys_create(isp, lun_num, ilp, inq); 142 } 143 144 /* 145 * If NOT successful we need to remove the lun from the 146 * session and free any related resources. 147 */ 148 if (!ISCSI_SUCCESS(rtn)) { 149 if (ilp == isp->sess_lun_list) { 150 /* if head, set head to our next */ 151 isp->sess_lun_list = ilp->lun_next; 152 } else { 153 /* if not head, set prev lun's next to our next */ 154 for (ilp_tmp = isp->sess_lun_list; ilp_tmp; 155 ilp_tmp = ilp_tmp->lun_next) { 156 if (ilp_tmp->lun_next == ilp) { 157 ilp_tmp->lun_next = ilp->lun_next; 158 break; 159 } 160 } 161 } 162 163 kmem_free(ilp->lun_addr, 164 (strlen((char *)isp->sess_name) + 165 ADDR_EXT_SIZE + 1)); 166 ilp->lun_addr = NULL; 167 168 if (ilp->lun_guid != NULL) { 169 kmem_free(ilp->lun_guid, ilp->lun_guid_size); 170 ilp->lun_guid = NULL; 171 } 172 kmem_free(ilp, sizeof (iscsi_lun_t)); 173 } else { 174 ilp->lun_state &= ISCSI_LUN_STATE_CLEAR; 175 ilp->lun_state |= ISCSI_LUN_STATE_ONLINE; 176 ilp->lun_time_online = ddi_get_time(); 177 178 /* Check whether this is the required LUN for iscsi boot */ 179 if (iscsiboot_prop != NULL && isp->sess_boot == B_TRUE && 180 iscsiboot_prop->boot_tgt.lun_online == 0) { 181 lun_num_ptr = 182 (uint64_t *)iscsiboot_prop->boot_tgt.tgt_boot_lun; 183 boot_lun_num = (uint16_t)(*lun_num_ptr); 184 if (boot_lun_num == ilp->lun_num) { 185 /* 186 * During iscsi boot, the boot lun has been 187 * online, we should set the "online flag". 188 */ 189 iscsiboot_prop->boot_tgt.lun_online = 1; 190 } 191 } 192 } 193 rw_exit(&isp->sess_lun_list_rwlock); 194 195 return (rtn); 196 } 197 198 /* 199 * iscsi_lun_destroy - offline and remove lun 200 * 201 * This interface is called when a name service change has 202 * occured and the storage is no longer available to this 203 * initiator. This function will offline and free the 204 * solaris node resources. Then it will free all iscsi lun 205 * resources. 206 * 207 * This function can fail with ISCSI_STATUS_BUSY if the 208 * logical unit is in use. The user should unmount or 209 * close the device and perform the nameservice operation 210 * again if this occurs. 211 */ 212 iscsi_status_t 213 iscsi_lun_destroy(iscsi_hba_t *ihp, iscsi_lun_t *ilp) 214 { 215 iscsi_status_t status = ISCSI_STATUS_SUCCESS; 216 iscsi_sess_t *isp = NULL; 217 iscsi_lun_t *t_ilp = NULL; 218 219 ASSERT(ilp != NULL); 220 isp = ilp->lun_sess; 221 ASSERT(isp != NULL); 222 223 /* attempt to offline and free solaris node */ 224 status = iscsi_lun_offline(ihp, ilp, B_TRUE); 225 226 /* If we successfully unplumbed the lun remove it from our lists */ 227 if (ISCSI_SUCCESS(status)) { 228 if (isp->sess_lun_list == ilp) { 229 /* target first item in list */ 230 isp->sess_lun_list = ilp->lun_next; 231 } else { 232 /* 233 * search session list for ilp pointing 234 * to lun being removed. Then 235 * update that luns next pointer. 236 */ 237 t_ilp = isp->sess_lun_list; 238 while (t_ilp->lun_next != NULL) { 239 if (t_ilp->lun_next == ilp) { 240 break; 241 } 242 t_ilp = t_ilp->lun_next; 243 } 244 if (t_ilp->lun_next == ilp) { 245 t_ilp->lun_next = ilp->lun_next; 246 } else { 247 /* couldn't find session */ 248 ASSERT(FALSE); 249 } 250 } 251 252 /* release its memory */ 253 kmem_free(ilp->lun_addr, (strlen((char *)isp->sess_name) + 254 ADDR_EXT_SIZE + 1)); 255 ilp->lun_addr = NULL; 256 if (ilp->lun_guid != NULL) { 257 kmem_free(ilp->lun_guid, ilp->lun_guid_size); 258 ilp->lun_guid = NULL; 259 } 260 kmem_free(ilp, sizeof (iscsi_lun_t)); 261 ilp = NULL; 262 } 263 264 return (status); 265 } 266 267 /* 268 * +--------------------------------------------------------------------+ 269 * | External Logical Unit Interfaces | 270 * +--------------------------------------------------------------------+ 271 */ 272 273 /* 274 * iscsi_lun_virt_create - Creates solaris logical unit via MDI 275 */ 276 static iscsi_status_t 277 iscsi_lun_virt_create(iscsi_sess_t *isp, uint16_t lun_num, iscsi_lun_t *ilp, 278 struct scsi_inquiry *inq) 279 { 280 iscsi_status_t rtn = ISCSI_STATUS_INTERNAL_ERROR; 281 int mdi_rtn = MDI_FAILURE; 282 iscsi_hba_t *ihp = NULL; 283 mdi_pathinfo_t *pip = NULL; 284 char *nodename = NULL; 285 char **compatible = NULL; 286 int ncompatible = 0; 287 int circ = 0; 288 289 ASSERT(isp != NULL); 290 ASSERT(ilp != NULL); 291 ihp = isp->sess_hba; 292 ASSERT(ihp != NULL); 293 294 /* 295 * Generate compatible property 296 */ 297 scsi_hba_nodename_compatible_get(inq, "vhci", 298 inq->inq_dtype, NULL, &nodename, &compatible, &ncompatible); 299 300 /* if nodename can't be determined then print a message and skip it */ 301 if (nodename == NULL) { 302 cmn_err(CE_WARN, "iscsi driver found no compatible driver " 303 "for %s lun %d dtype:0x%02x", isp->sess_name, lun_num, 304 inq->inq_dtype); 305 return (ISCSI_STATUS_INTERNAL_ERROR); 306 } 307 308 /* 309 * 310 */ 311 ndi_devi_enter(scsi_vhci_dip, &circ); 312 mdi_rtn = mdi_pi_alloc_compatible(ihp->hba_dip, nodename, 313 ilp->lun_guid, ilp->lun_addr, compatible, ncompatible, 314 0, &pip); 315 316 if (mdi_rtn == MDI_SUCCESS) { 317 mdi_pi_set_phci_private(pip, (caddr_t)ilp); 318 319 if (mdi_prop_update_string(pip, MDI_GUID, 320 ilp->lun_guid) != DDI_SUCCESS) { 321 cmn_err(CE_WARN, "iscsi driver unable to create " 322 "property for %s lun %d (MDI_GUID)", 323 isp->sess_name, lun_num); 324 mdi_rtn = MDI_FAILURE; 325 goto virt_create_done; 326 } 327 328 if (mdi_prop_update_int(pip, TARGET_PROP, 329 isp->sess_oid) != DDI_SUCCESS) { 330 cmn_err(CE_WARN, "iscsi driver unable to create " 331 "property for %s lun %d (TARGET_PROP)", 332 isp->sess_name, lun_num); 333 mdi_rtn = MDI_FAILURE; 334 goto virt_create_done; 335 } 336 337 if (mdi_prop_update_int(pip, LUN_PROP, 338 ilp->lun_num) != DDI_SUCCESS) { 339 cmn_err(CE_WARN, "iscsi driver unable to create " 340 "property for %s lun %d (LUN_PROP)", 341 isp->sess_name, lun_num); 342 mdi_rtn = MDI_FAILURE; 343 goto virt_create_done; 344 } 345 346 if (mdi_prop_update_string_array(pip, "compatible", 347 compatible, ncompatible) != 348 DDI_PROP_SUCCESS) { 349 cmn_err(CE_WARN, "iscsi driver unable to create " 350 "property for %s lun %d (COMPATIBLE)", 351 isp->sess_name, lun_num); 352 mdi_rtn = MDI_FAILURE; 353 goto virt_create_done; 354 } 355 356 mdi_rtn = mdi_pi_online(pip, 0); 357 if (mdi_rtn == MDI_NOT_SUPPORTED) { 358 mdi_rtn = MDI_FAILURE; 359 goto virt_create_done; 360 } 361 362 ilp->lun_pip = pip; 363 ilp->lun_dip = NULL; 364 365 virt_create_done: 366 367 if (pip && mdi_rtn != MDI_SUCCESS) { 368 ilp->lun_pip = NULL; 369 ilp->lun_dip = NULL; 370 (void) mdi_prop_remove(pip, NULL); 371 (void) mdi_pi_free(pip, 0); 372 } else { 373 rtn = ISCSI_STATUS_SUCCESS; 374 } 375 } 376 ndi_devi_exit(scsi_vhci_dip, circ); 377 378 scsi_hba_nodename_compatible_free(nodename, compatible); 379 380 return (rtn); 381 } 382 383 384 /* 385 * iscsi_lun_phys_create - creates solaris logical unit via NDI 386 */ 387 static iscsi_status_t 388 iscsi_lun_phys_create(iscsi_sess_t *isp, uint16_t lun_num, 389 iscsi_lun_t *ilp, struct scsi_inquiry *inq) 390 { 391 iscsi_status_t rtn = ISCSI_STATUS_INTERNAL_ERROR; 392 int ndi_rtn = NDI_FAILURE; 393 iscsi_hba_t *ihp = NULL; 394 dev_info_t *lun_dip = NULL; 395 char *nodename = NULL; 396 char **compatible = NULL; 397 int ncompatible = 0; 398 char *scsi_binding_set = NULL; 399 char instance[32]; 400 int circ = 0; 401 402 ASSERT(isp != NULL); 403 ASSERT(ilp != NULL); 404 ihp = isp->sess_hba; 405 ASSERT(ihp != NULL); 406 ASSERT(inq != NULL); 407 408 /* get the 'scsi-binding-set' property */ 409 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, isp->sess_hba->hba_dip, 410 DDI_PROP_NOTPROM | DDI_PROP_DONTPASS, "scsi-binding-set", 411 &scsi_binding_set) != DDI_PROP_SUCCESS) { 412 scsi_binding_set = NULL; 413 } 414 415 /* generate compatible property */ 416 scsi_hba_nodename_compatible_get(inq, scsi_binding_set, 417 inq->inq_dtype, NULL, &nodename, &compatible, &ncompatible); 418 if (scsi_binding_set) 419 ddi_prop_free(scsi_binding_set); 420 421 /* if nodename can't be determined then print a message and skip it */ 422 if (nodename == NULL) { 423 cmn_err(CE_WARN, "iscsi driver found no compatible driver " 424 "for %s lun %d", isp->sess_name, lun_num); 425 return (ISCSI_STATUS_INTERNAL_ERROR); 426 } 427 428 ndi_devi_enter(ihp->hba_dip, &circ); 429 430 ndi_rtn = ndi_devi_alloc(ihp->hba_dip, nodename, 431 DEVI_SID_NODEID, &lun_dip); 432 433 /* if lun alloc success, set props */ 434 if (ndi_rtn == NDI_SUCCESS) { 435 436 if (ndi_prop_update_int(DDI_DEV_T_NONE, 437 lun_dip, TARGET_PROP, (int)isp->sess_oid) != 438 DDI_PROP_SUCCESS) { 439 cmn_err(CE_WARN, "iscsi driver unable to create " 440 "property for %s lun %d (TARGET_PROP)", 441 isp->sess_name, lun_num); 442 ndi_rtn = NDI_FAILURE; 443 goto phys_create_done; 444 } 445 446 if (ndi_prop_update_int(DDI_DEV_T_NONE, 447 lun_dip, LUN_PROP, (int)ilp->lun_num) != 448 DDI_PROP_SUCCESS) { 449 cmn_err(CE_WARN, "iscsi driver unable to create " 450 "property for %s lun %d (LUN_PROP)", 451 isp->sess_name, lun_num); 452 ndi_rtn = NDI_FAILURE; 453 goto phys_create_done; 454 } 455 456 if (ndi_prop_update_string_array(DDI_DEV_T_NONE, 457 lun_dip, "compatible", compatible, ncompatible) 458 != DDI_PROP_SUCCESS) { 459 cmn_err(CE_WARN, "iscsi driver unable to create " 460 "property for %s lun %d (COMPATIBLE)", 461 isp->sess_name, lun_num); 462 ndi_rtn = NDI_FAILURE; 463 goto phys_create_done; 464 } 465 466 phys_create_done: 467 /* If props were setup ok, online the lun */ 468 if (ndi_rtn == NDI_SUCCESS) { 469 /* Try to online the new node */ 470 ndi_rtn = ndi_devi_online(lun_dip, 0); 471 } 472 473 /* If success set rtn flag, else unwire alloc'd lun */ 474 if (ndi_rtn == NDI_SUCCESS) { 475 rtn = ISCSI_STATUS_SUCCESS; 476 /* 477 * Assign the instance number for the dev_link 478 * generator. This will ensure the link name is 479 * unique and persistent across reboots. 480 */ 481 (void) snprintf(instance, 32, "%d", 482 ddi_get_instance(lun_dip)); 483 (void) ndi_prop_update_string(DDI_DEV_T_NONE, 484 lun_dip, NDI_GUID, instance); 485 } else { 486 cmn_err(CE_WARN, "iscsi driver unable to online " 487 "%s lun %d", isp->sess_name, lun_num); 488 ndi_prop_remove_all(lun_dip); 489 (void) ndi_devi_free(lun_dip); 490 } 491 492 } 493 ndi_devi_exit(ihp->hba_dip, circ); 494 495 ilp->lun_dip = lun_dip; 496 ilp->lun_pip = NULL; 497 498 scsi_hba_nodename_compatible_free(nodename, compatible); 499 500 return (rtn); 501 } 502 503 504 /* 505 * iscsi_lun_online - _di_online logical unit 506 * 507 * This is called after a path has recovered it will cause 508 * an offline path to become online/active again. 509 */ 510 void 511 iscsi_lun_online(iscsi_hba_t *ihp, iscsi_lun_t *ilp) 512 { 513 int circ = 0; 514 int rval = 0; 515 uint64_t *lun_num_ptr = NULL; 516 uint16_t boot_lun_num = 0; 517 iscsi_sess_t *isp = NULL; 518 519 ASSERT(ilp != NULL); 520 ASSERT((ilp->lun_pip != NULL) || (ilp->lun_dip != NULL)); 521 522 if (ilp->lun_pip != NULL) { 523 ndi_devi_enter(scsi_vhci_dip, &circ); 524 rval = mdi_pi_online(ilp->lun_pip, 0); 525 ndi_devi_exit(scsi_vhci_dip, circ); 526 if (rval == MDI_SUCCESS) { 527 ilp->lun_state &= ISCSI_LUN_STATE_CLEAR; 528 ilp->lun_state |= ISCSI_LUN_STATE_ONLINE; 529 ilp->lun_time_online = ddi_get_time(); 530 } 531 532 } else if (ilp->lun_dip != NULL) { 533 ndi_devi_enter(ihp->hba_dip, &circ); 534 rval = ndi_devi_online(ilp->lun_dip, 0); 535 ndi_devi_exit(ihp->hba_dip, circ); 536 if (rval == NDI_SUCCESS) { 537 ilp->lun_state &= ISCSI_LUN_STATE_CLEAR; 538 ilp->lun_state |= ISCSI_LUN_STATE_ONLINE; 539 ilp->lun_time_online = ddi_get_time(); 540 } 541 } 542 543 /* Check whether this is the required LUN for iscsi boot */ 544 if (iscsiboot_prop != NULL && 545 iscsiboot_prop->boot_tgt.lun_online == 0) { 546 isp = ilp->lun_sess; 547 if (isp->sess_boot == B_TRUE) { 548 lun_num_ptr = 549 (uint64_t *)iscsiboot_prop->boot_tgt.tgt_boot_lun; 550 boot_lun_num = (uint16_t)(*lun_num_ptr); 551 if (boot_lun_num == ilp->lun_num) { 552 /* 553 * During iscsi boot, the boot lun has been 554 * online, we should set the "online flag". 555 */ 556 iscsiboot_prop->boot_tgt.lun_online = 1; 557 } 558 } 559 } 560 } 561 562 /* 563 * iscsi_lun_offline - attempt _di_offline [and optional _di_free] 564 * 565 * This function is called via two paths. When a transport 566 * path has failed it will be called to offline the logical 567 * unit. When nameservice access has been removed it will 568 * be called to both offline and free the logical unit. 569 * (This operates soley on the solaris node states. 570 * iscsi_lun_destroy() should be called when attempting 571 * to free all iscsi lun resources.) 572 * 573 * This function can fail with ISCSI_STATUS_BUSY if the 574 * logical unit is in use. The user should unmount or 575 * close the device and perform the nameservice operation 576 * again if this occurs. 577 * 578 * If we fail to offline a LUN that we don't want to destroy, 579 * we will mark it with invalid state. If this LUN still 580 * exists on the target, we can have another chance to online 581 * it again when we do the LUN enumeration. 582 */ 583 iscsi_status_t 584 iscsi_lun_offline(iscsi_hba_t *ihp, iscsi_lun_t *ilp, boolean_t lun_free) 585 { 586 iscsi_status_t status = ISCSI_STATUS_SUCCESS; 587 int circ = 0; 588 dev_info_t *cdip, *pdip; 589 char *devname; 590 int rval; 591 592 ASSERT(ilp != NULL); 593 ASSERT((ilp->lun_pip != NULL) || (ilp->lun_dip != NULL)); 594 595 /* 596 * Since we carry the logical units parent 597 * lock across the offline call it will not 598 * issue devfs_clean() and may fail with a 599 * devi_ref count > 0. 600 */ 601 if (ilp->lun_pip == NULL) { 602 cdip = ilp->lun_dip; 603 } else { 604 cdip = mdi_pi_get_client(ilp->lun_pip); 605 } 606 607 if ((cdip != NULL) && 608 (lun_free == B_TRUE) && 609 (ilp->lun_state & ISCSI_LUN_STATE_ONLINE)) { 610 /* 611 * Make sure node is attached otherwise 612 * it won't have related cache nodes to 613 * clean up. i_ddi_devi_attached is 614 * similiar to i_ddi_node_state(cdip) >= 615 * DS_ATTACHED. We should clean up only 616 * when lun_free is set. 617 */ 618 if (i_ddi_devi_attached(cdip)) { 619 620 /* Get parent dip */ 621 pdip = ddi_get_parent(cdip); 622 623 /* Get full devname */ 624 devname = kmem_alloc(MAXNAMELEN + 1, KM_SLEEP); 625 ndi_devi_enter(pdip, &circ); 626 (void) ddi_deviname(cdip, devname); 627 /* Release lock before devfs_clean() */ 628 ndi_devi_exit(pdip, circ); 629 630 /* Clean cache */ 631 rval = devfs_clean(pdip, devname + 1, 632 DV_CLEAN_FORCE); 633 kmem_free(devname, MAXNAMELEN + 1); 634 635 if ((rval != 0) && (ilp->lun_pip == NULL)) { 636 return (ISCSI_STATUS_BUSY); 637 } 638 } 639 } 640 641 /* Attempt to offline the logical units */ 642 if (ilp->lun_pip != NULL) { 643 644 /* virt/mdi */ 645 ndi_devi_enter(scsi_vhci_dip, &circ); 646 if ((lun_free == B_TRUE) && 647 (ilp->lun_state & ISCSI_LUN_STATE_ONLINE)) { 648 rval = mdi_pi_offline(ilp->lun_pip, 649 NDI_DEVI_REMOVE); 650 } else { 651 rval = mdi_pi_offline(ilp->lun_pip, 0); 652 } 653 654 if (rval == MDI_SUCCESS) { 655 ilp->lun_state &= ISCSI_LUN_STATE_CLEAR; 656 ilp->lun_state |= ISCSI_LUN_STATE_OFFLINE; 657 if (lun_free == B_TRUE) { 658 (void) mdi_prop_remove(ilp->lun_pip, NULL); 659 (void) mdi_pi_free(ilp->lun_pip, 0); 660 } 661 } else { 662 status = ISCSI_STATUS_INTERNAL_ERROR; 663 if (lun_free == B_FALSE) { 664 ilp->lun_state |= ISCSI_LUN_STATE_INVALID; 665 } 666 } 667 ndi_devi_exit(scsi_vhci_dip, circ); 668 669 } else { 670 671 /* phys/ndi */ 672 ndi_devi_enter(ihp->hba_dip, &circ); 673 if ((lun_free == B_TRUE) && 674 (ilp->lun_state & ISCSI_LUN_STATE_ONLINE)) { 675 rval = ndi_devi_offline( 676 ilp->lun_dip, NDI_DEVI_REMOVE); 677 } else { 678 rval = ndi_devi_offline( 679 ilp->lun_dip, 0); 680 } 681 if (rval != NDI_SUCCESS) { 682 status = ISCSI_STATUS_INTERNAL_ERROR; 683 if (lun_free == B_FALSE) { 684 ilp->lun_state |= ISCSI_LUN_STATE_INVALID; 685 } 686 } else { 687 ilp->lun_state &= ISCSI_LUN_STATE_CLEAR; 688 ilp->lun_state |= ISCSI_LUN_STATE_OFFLINE; 689 } 690 ndi_devi_exit(ihp->hba_dip, circ); 691 692 } 693 return (status); 694 } 695