17836SJohn.Forte@Sun.COM /*
27836SJohn.Forte@Sun.COM * CDDL HEADER START
37836SJohn.Forte@Sun.COM *
47836SJohn.Forte@Sun.COM * The contents of this file are subject to the terms of the
57836SJohn.Forte@Sun.COM * Common Development and Distribution License (the "License").
67836SJohn.Forte@Sun.COM * You may not use this file except in compliance with the License.
77836SJohn.Forte@Sun.COM *
87836SJohn.Forte@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97836SJohn.Forte@Sun.COM * or http://www.opensolaris.org/os/licensing.
107836SJohn.Forte@Sun.COM * See the License for the specific language governing permissions
117836SJohn.Forte@Sun.COM * and limitations under the License.
127836SJohn.Forte@Sun.COM *
137836SJohn.Forte@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
147836SJohn.Forte@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157836SJohn.Forte@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
167836SJohn.Forte@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
177836SJohn.Forte@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
187836SJohn.Forte@Sun.COM *
197836SJohn.Forte@Sun.COM * CDDL HEADER END
207836SJohn.Forte@Sun.COM */
217836SJohn.Forte@Sun.COM /*
22*11977SJack.Meng@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
237836SJohn.Forte@Sun.COM * Use is subject to license terms.
247836SJohn.Forte@Sun.COM *
257836SJohn.Forte@Sun.COM * iSCSI logical unit interfaces
267836SJohn.Forte@Sun.COM */
277836SJohn.Forte@Sun.COM
287836SJohn.Forte@Sun.COM #include "iscsi.h"
297836SJohn.Forte@Sun.COM #include <sys/fs/dv_node.h> /* devfs_clean */
308194SJack.Meng@Sun.COM #include <sys/bootprops.h>
319371SBing.Zhao@Sun.COM #include <sys/sysevent/eventdefs.h>
329371SBing.Zhao@Sun.COM #include <sys/sysevent/dev.h>
337836SJohn.Forte@Sun.COM
347836SJohn.Forte@Sun.COM /* tpgt bytes in string form */
357836SJohn.Forte@Sun.COM #define TPGT_EXT_SIZE 5
367836SJohn.Forte@Sun.COM
377836SJohn.Forte@Sun.COM /* logical unit number bytes in string form */
387836SJohn.Forte@Sun.COM #define LUN_EXT_SIZE 10
397836SJohn.Forte@Sun.COM
407836SJohn.Forte@Sun.COM /*
417836SJohn.Forte@Sun.COM * Addition addr size of size of ',' + max str form of tpgt (2 bytes) +
427836SJohn.Forte@Sun.COM * ',' + max str form of logical unit number (4 bytes).
437836SJohn.Forte@Sun.COM */
447836SJohn.Forte@Sun.COM #define ADDR_EXT_SIZE (1 + TPGT_EXT_SIZE + 1 + LUN_EXT_SIZE)
457836SJohn.Forte@Sun.COM
467836SJohn.Forte@Sun.COM /* internal interfaces */
477836SJohn.Forte@Sun.COM static iscsi_status_t iscsi_lun_virt_create(iscsi_sess_t *isp,
487836SJohn.Forte@Sun.COM uint16_t lun_num, iscsi_lun_t *ilp, struct scsi_inquiry *inq);
497836SJohn.Forte@Sun.COM static iscsi_status_t iscsi_lun_phys_create(iscsi_sess_t *isp,
507836SJohn.Forte@Sun.COM uint16_t lun_num, iscsi_lun_t *ilp, struct scsi_inquiry *inq);
517836SJohn.Forte@Sun.COM
527836SJohn.Forte@Sun.COM extern dev_info_t *scsi_vhci_dip;
538194SJack.Meng@Sun.COM extern ib_boot_prop_t *iscsiboot_prop;
547836SJohn.Forte@Sun.COM
557836SJohn.Forte@Sun.COM /*
567836SJohn.Forte@Sun.COM * +--------------------------------------------------------------------+
577836SJohn.Forte@Sun.COM * | External Connection Interfaces |
587836SJohn.Forte@Sun.COM * +--------------------------------------------------------------------+
597836SJohn.Forte@Sun.COM */
607836SJohn.Forte@Sun.COM
617836SJohn.Forte@Sun.COM
627836SJohn.Forte@Sun.COM /*
637836SJohn.Forte@Sun.COM * iscsi_lun_create - This function will create a lun mapping.
647836SJohn.Forte@Sun.COM * logic specific to MPxIO vs. NDI node creation is switched
657836SJohn.Forte@Sun.COM * out to a helper function.
667836SJohn.Forte@Sun.COM */
677836SJohn.Forte@Sun.COM iscsi_status_t
iscsi_lun_create(iscsi_sess_t * isp,uint16_t lun_num,uint8_t lun_addr_type,struct scsi_inquiry * inq,char * guid)687836SJohn.Forte@Sun.COM iscsi_lun_create(iscsi_sess_t *isp, uint16_t lun_num, uint8_t lun_addr_type,
697836SJohn.Forte@Sun.COM struct scsi_inquiry *inq, char *guid)
707836SJohn.Forte@Sun.COM {
717836SJohn.Forte@Sun.COM iscsi_status_t rtn = ISCSI_STATUS_INTERNAL_ERROR;
727836SJohn.Forte@Sun.COM iscsi_hba_t *ihp = NULL;
737836SJohn.Forte@Sun.COM iscsi_lun_t *ilp = NULL;
747836SJohn.Forte@Sun.COM iscsi_lun_t *ilp_tmp = NULL;
757836SJohn.Forte@Sun.COM char *addr = NULL;
768194SJack.Meng@Sun.COM uint16_t boot_lun_num = 0;
778194SJack.Meng@Sun.COM uint64_t *lun_num_ptr = NULL;
789849SBing.Zhao@Sun.COM uint32_t oid_tmp = 0;
797836SJohn.Forte@Sun.COM
807836SJohn.Forte@Sun.COM ASSERT(isp != NULL);
817836SJohn.Forte@Sun.COM ihp = isp->sess_hba;
827836SJohn.Forte@Sun.COM ASSERT(ihp != NULL);
837836SJohn.Forte@Sun.COM
849849SBing.Zhao@Sun.COM mutex_enter(&iscsi_oid_mutex);
859849SBing.Zhao@Sun.COM oid_tmp = iscsi_oid++;
869849SBing.Zhao@Sun.COM mutex_exit(&iscsi_oid_mutex);
879849SBing.Zhao@Sun.COM
889849SBing.Zhao@Sun.COM rw_enter(&isp->sess_lun_list_rwlock, RW_WRITER);
899849SBing.Zhao@Sun.COM /*
909849SBing.Zhao@Sun.COM * Check whether it has already existed in the list.
919849SBing.Zhao@Sun.COM */
929849SBing.Zhao@Sun.COM for (ilp_tmp = isp->sess_lun_list; ilp_tmp != NULL;
939849SBing.Zhao@Sun.COM ilp_tmp = ilp_tmp->lun_next) {
949849SBing.Zhao@Sun.COM if (ilp_tmp->lun_num == lun_num) {
959849SBing.Zhao@Sun.COM /*
969849SBing.Zhao@Sun.COM * The logic unit has already existed in the list,
979849SBing.Zhao@Sun.COM * return with success.
989849SBing.Zhao@Sun.COM */
999849SBing.Zhao@Sun.COM rw_exit(&isp->sess_lun_list_rwlock);
1009849SBing.Zhao@Sun.COM return (ISCSI_STATUS_SUCCESS);
1019849SBing.Zhao@Sun.COM }
1029849SBing.Zhao@Sun.COM }
1039849SBing.Zhao@Sun.COM
1047836SJohn.Forte@Sun.COM addr = kmem_zalloc((strlen((char *)isp->sess_name) +
1057836SJohn.Forte@Sun.COM ADDR_EXT_SIZE + 1), KM_SLEEP);
1067836SJohn.Forte@Sun.COM (void) snprintf(addr,
1077836SJohn.Forte@Sun.COM (strlen((char *)isp->sess_name) +
1087836SJohn.Forte@Sun.COM ADDR_EXT_SIZE + 1),
1097836SJohn.Forte@Sun.COM "%02X%02X%s%04X,%d", isp->sess_isid[4],
1107836SJohn.Forte@Sun.COM isp->sess_isid[5], isp->sess_name,
1118194SJack.Meng@Sun.COM isp->sess_tpgt_nego & 0xFFFF, lun_num);
1127836SJohn.Forte@Sun.COM
1137836SJohn.Forte@Sun.COM /* allocate space for lun struct */
1147836SJohn.Forte@Sun.COM ilp = kmem_zalloc(sizeof (iscsi_lun_t), KM_SLEEP);
1157836SJohn.Forte@Sun.COM ilp->lun_sig = ISCSI_SIG_LUN;
1168531SBing.Zhao@Sun.COM ilp->lun_state &= ISCSI_LUN_STATE_CLEAR;
1178531SBing.Zhao@Sun.COM ilp->lun_state |= ISCSI_LUN_STATE_OFFLINE;
1187836SJohn.Forte@Sun.COM
1197836SJohn.Forte@Sun.COM /* initialize common LU information */
1207836SJohn.Forte@Sun.COM ilp->lun_num = lun_num;
1217836SJohn.Forte@Sun.COM ilp->lun_addr_type = lun_addr_type;
1227836SJohn.Forte@Sun.COM ilp->lun_sess = isp;
1237836SJohn.Forte@Sun.COM ilp->lun_addr = addr;
1249371SBing.Zhao@Sun.COM ilp->lun_type = inq->inq_dtype & DTYPE_MASK;
1259849SBing.Zhao@Sun.COM ilp->lun_oid = oid_tmp;
1267836SJohn.Forte@Sun.COM
1277836SJohn.Forte@Sun.COM bcopy(inq->inq_vid, ilp->lun_vid, sizeof (inq->inq_vid));
1287836SJohn.Forte@Sun.COM bcopy(inq->inq_pid, ilp->lun_pid, sizeof (inq->inq_pid));
1297836SJohn.Forte@Sun.COM
1307836SJohn.Forte@Sun.COM /* store GUID if valid one exists */
1317836SJohn.Forte@Sun.COM if (guid != NULL) {
1327836SJohn.Forte@Sun.COM ilp->lun_guid_size = strlen(guid) + 1;
1337836SJohn.Forte@Sun.COM ilp->lun_guid = kmem_zalloc(ilp->lun_guid_size, KM_SLEEP);
1347836SJohn.Forte@Sun.COM (void) strcpy(ilp->lun_guid, guid);
1357836SJohn.Forte@Sun.COM } else {
1367836SJohn.Forte@Sun.COM ilp->lun_guid_size = 0;
1377836SJohn.Forte@Sun.COM ilp->lun_guid = NULL;
1387836SJohn.Forte@Sun.COM }
1397836SJohn.Forte@Sun.COM
1407836SJohn.Forte@Sun.COM /*
1417836SJohn.Forte@Sun.COM * We need to add the lun to our lists now because during the
1427836SJohn.Forte@Sun.COM * lun creation we will get called back into multiple times
1437836SJohn.Forte@Sun.COM * depending on the createion type. These callbacks will
1447836SJohn.Forte@Sun.COM * occur via our tran_init_lun, tran_get_name, tran_get_bus_addr,
1457836SJohn.Forte@Sun.COM * tran_init_pkt, tran_start.
1467836SJohn.Forte@Sun.COM */
1477836SJohn.Forte@Sun.COM if (isp->sess_lun_list == NULL) {
1487836SJohn.Forte@Sun.COM isp->sess_lun_list = ilp;
1497836SJohn.Forte@Sun.COM } else {
1507836SJohn.Forte@Sun.COM ilp->lun_next = isp->sess_lun_list;
1517836SJohn.Forte@Sun.COM isp->sess_lun_list = ilp;
1527836SJohn.Forte@Sun.COM }
1537836SJohn.Forte@Sun.COM
1547836SJohn.Forte@Sun.COM /* Attempt to create a scsi_vhci binding if GUID is available */
1557836SJohn.Forte@Sun.COM if ((ihp->hba_mpxio_enabled == B_TRUE) &&
1567836SJohn.Forte@Sun.COM (guid != NULL)) {
1577836SJohn.Forte@Sun.COM rtn = iscsi_lun_virt_create(isp, lun_num, ilp, inq);
1587836SJohn.Forte@Sun.COM }
1597836SJohn.Forte@Sun.COM if (!ISCSI_SUCCESS(rtn)) {
1607836SJohn.Forte@Sun.COM /* unable to bind under scsi_vhci, failback to ndi */
1617836SJohn.Forte@Sun.COM rtn = iscsi_lun_phys_create(isp, lun_num, ilp, inq);
1627836SJohn.Forte@Sun.COM }
1637836SJohn.Forte@Sun.COM
1647836SJohn.Forte@Sun.COM /*
1657836SJohn.Forte@Sun.COM * If NOT successful we need to remove the lun from the
1667836SJohn.Forte@Sun.COM * session and free any related resources.
1677836SJohn.Forte@Sun.COM */
1687836SJohn.Forte@Sun.COM if (!ISCSI_SUCCESS(rtn)) {
1697836SJohn.Forte@Sun.COM if (ilp == isp->sess_lun_list) {
1707836SJohn.Forte@Sun.COM /* if head, set head to our next */
1717836SJohn.Forte@Sun.COM isp->sess_lun_list = ilp->lun_next;
1727836SJohn.Forte@Sun.COM } else {
1737836SJohn.Forte@Sun.COM /* if not head, set prev lun's next to our next */
1747836SJohn.Forte@Sun.COM for (ilp_tmp = isp->sess_lun_list; ilp_tmp;
1757836SJohn.Forte@Sun.COM ilp_tmp = ilp_tmp->lun_next) {
1767836SJohn.Forte@Sun.COM if (ilp_tmp->lun_next == ilp) {
1777836SJohn.Forte@Sun.COM ilp_tmp->lun_next = ilp->lun_next;
1787836SJohn.Forte@Sun.COM break;
1797836SJohn.Forte@Sun.COM }
1807836SJohn.Forte@Sun.COM }
1817836SJohn.Forte@Sun.COM }
1827836SJohn.Forte@Sun.COM
1837836SJohn.Forte@Sun.COM kmem_free(ilp->lun_addr,
1847836SJohn.Forte@Sun.COM (strlen((char *)isp->sess_name) +
1857836SJohn.Forte@Sun.COM ADDR_EXT_SIZE + 1));
1867836SJohn.Forte@Sun.COM ilp->lun_addr = NULL;
1877836SJohn.Forte@Sun.COM
1887836SJohn.Forte@Sun.COM if (ilp->lun_guid != NULL) {
1897836SJohn.Forte@Sun.COM kmem_free(ilp->lun_guid, ilp->lun_guid_size);
1907836SJohn.Forte@Sun.COM ilp->lun_guid = NULL;
1917836SJohn.Forte@Sun.COM }
1927836SJohn.Forte@Sun.COM kmem_free(ilp, sizeof (iscsi_lun_t));
1937836SJohn.Forte@Sun.COM } else {
1948531SBing.Zhao@Sun.COM ilp->lun_state &= ISCSI_LUN_STATE_CLEAR;
1958531SBing.Zhao@Sun.COM ilp->lun_state |= ISCSI_LUN_STATE_ONLINE;
1967836SJohn.Forte@Sun.COM ilp->lun_time_online = ddi_get_time();
1978194SJack.Meng@Sun.COM
1988194SJack.Meng@Sun.COM /* Check whether this is the required LUN for iscsi boot */
1998194SJack.Meng@Sun.COM if (iscsiboot_prop != NULL && isp->sess_boot == B_TRUE &&
2008194SJack.Meng@Sun.COM iscsiboot_prop->boot_tgt.lun_online == 0) {
2018194SJack.Meng@Sun.COM lun_num_ptr =
2028194SJack.Meng@Sun.COM (uint64_t *)iscsiboot_prop->boot_tgt.tgt_boot_lun;
2038194SJack.Meng@Sun.COM boot_lun_num = (uint16_t)(*lun_num_ptr);
2048194SJack.Meng@Sun.COM if (boot_lun_num == ilp->lun_num) {
2058194SJack.Meng@Sun.COM /*
2068194SJack.Meng@Sun.COM * During iscsi boot, the boot lun has been
2078194SJack.Meng@Sun.COM * online, we should set the "online flag".
2088194SJack.Meng@Sun.COM */
2098194SJack.Meng@Sun.COM iscsiboot_prop->boot_tgt.lun_online = 1;
2108194SJack.Meng@Sun.COM }
2118194SJack.Meng@Sun.COM }
2127836SJohn.Forte@Sun.COM }
2137836SJohn.Forte@Sun.COM rw_exit(&isp->sess_lun_list_rwlock);
2147836SJohn.Forte@Sun.COM
2157836SJohn.Forte@Sun.COM return (rtn);
2167836SJohn.Forte@Sun.COM }
2177836SJohn.Forte@Sun.COM
2187836SJohn.Forte@Sun.COM /*
2197836SJohn.Forte@Sun.COM * iscsi_lun_destroy - offline and remove lun
2207836SJohn.Forte@Sun.COM *
2217836SJohn.Forte@Sun.COM * This interface is called when a name service change has
2227836SJohn.Forte@Sun.COM * occured and the storage is no longer available to this
2237836SJohn.Forte@Sun.COM * initiator. This function will offline and free the
2247836SJohn.Forte@Sun.COM * solaris node resources. Then it will free all iscsi lun
2257836SJohn.Forte@Sun.COM * resources.
2267836SJohn.Forte@Sun.COM *
2277836SJohn.Forte@Sun.COM * This function can fail with ISCSI_STATUS_BUSY if the
2287836SJohn.Forte@Sun.COM * logical unit is in use. The user should unmount or
2297836SJohn.Forte@Sun.COM * close the device and perform the nameservice operation
2307836SJohn.Forte@Sun.COM * again if this occurs.
2317836SJohn.Forte@Sun.COM */
2327836SJohn.Forte@Sun.COM iscsi_status_t
iscsi_lun_destroy(iscsi_hba_t * ihp,iscsi_lun_t * ilp)2337836SJohn.Forte@Sun.COM iscsi_lun_destroy(iscsi_hba_t *ihp, iscsi_lun_t *ilp)
2347836SJohn.Forte@Sun.COM {
2357836SJohn.Forte@Sun.COM iscsi_status_t status = ISCSI_STATUS_SUCCESS;
2367836SJohn.Forte@Sun.COM iscsi_sess_t *isp = NULL;
2377836SJohn.Forte@Sun.COM iscsi_lun_t *t_ilp = NULL;
2387836SJohn.Forte@Sun.COM
2397836SJohn.Forte@Sun.COM ASSERT(ilp != NULL);
2407836SJohn.Forte@Sun.COM isp = ilp->lun_sess;
2417836SJohn.Forte@Sun.COM ASSERT(isp != NULL);
2427836SJohn.Forte@Sun.COM
2437836SJohn.Forte@Sun.COM /* attempt to offline and free solaris node */
2447836SJohn.Forte@Sun.COM status = iscsi_lun_offline(ihp, ilp, B_TRUE);
2457836SJohn.Forte@Sun.COM
2467836SJohn.Forte@Sun.COM /* If we successfully unplumbed the lun remove it from our lists */
2477836SJohn.Forte@Sun.COM if (ISCSI_SUCCESS(status)) {
2487836SJohn.Forte@Sun.COM if (isp->sess_lun_list == ilp) {
2497836SJohn.Forte@Sun.COM /* target first item in list */
2507836SJohn.Forte@Sun.COM isp->sess_lun_list = ilp->lun_next;
2517836SJohn.Forte@Sun.COM } else {
2527836SJohn.Forte@Sun.COM /*
2537836SJohn.Forte@Sun.COM * search session list for ilp pointing
2547836SJohn.Forte@Sun.COM * to lun being removed. Then
2557836SJohn.Forte@Sun.COM * update that luns next pointer.
2567836SJohn.Forte@Sun.COM */
2577836SJohn.Forte@Sun.COM t_ilp = isp->sess_lun_list;
2587836SJohn.Forte@Sun.COM while (t_ilp->lun_next != NULL) {
2597836SJohn.Forte@Sun.COM if (t_ilp->lun_next == ilp) {
2607836SJohn.Forte@Sun.COM break;
2617836SJohn.Forte@Sun.COM }
2627836SJohn.Forte@Sun.COM t_ilp = t_ilp->lun_next;
2637836SJohn.Forte@Sun.COM }
2647836SJohn.Forte@Sun.COM if (t_ilp->lun_next == ilp) {
2657836SJohn.Forte@Sun.COM t_ilp->lun_next = ilp->lun_next;
2667836SJohn.Forte@Sun.COM } else {
2677836SJohn.Forte@Sun.COM /* couldn't find session */
2687836SJohn.Forte@Sun.COM ASSERT(FALSE);
2697836SJohn.Forte@Sun.COM }
2707836SJohn.Forte@Sun.COM }
2717836SJohn.Forte@Sun.COM
2727836SJohn.Forte@Sun.COM /* release its memory */
2737836SJohn.Forte@Sun.COM kmem_free(ilp->lun_addr, (strlen((char *)isp->sess_name) +
2747836SJohn.Forte@Sun.COM ADDR_EXT_SIZE + 1));
2757836SJohn.Forte@Sun.COM ilp->lun_addr = NULL;
2767836SJohn.Forte@Sun.COM if (ilp->lun_guid != NULL) {
2777836SJohn.Forte@Sun.COM kmem_free(ilp->lun_guid, ilp->lun_guid_size);
2787836SJohn.Forte@Sun.COM ilp->lun_guid = NULL;
2797836SJohn.Forte@Sun.COM }
2807836SJohn.Forte@Sun.COM kmem_free(ilp, sizeof (iscsi_lun_t));
2817836SJohn.Forte@Sun.COM ilp = NULL;
2827836SJohn.Forte@Sun.COM }
2837836SJohn.Forte@Sun.COM
2847836SJohn.Forte@Sun.COM return (status);
2857836SJohn.Forte@Sun.COM }
2867836SJohn.Forte@Sun.COM
2877836SJohn.Forte@Sun.COM /*
2887836SJohn.Forte@Sun.COM * +--------------------------------------------------------------------+
2897836SJohn.Forte@Sun.COM * | External Logical Unit Interfaces |
2907836SJohn.Forte@Sun.COM * +--------------------------------------------------------------------+
2917836SJohn.Forte@Sun.COM */
2927836SJohn.Forte@Sun.COM
2937836SJohn.Forte@Sun.COM /*
2947836SJohn.Forte@Sun.COM * iscsi_lun_virt_create - Creates solaris logical unit via MDI
2957836SJohn.Forte@Sun.COM */
2967836SJohn.Forte@Sun.COM static iscsi_status_t
iscsi_lun_virt_create(iscsi_sess_t * isp,uint16_t lun_num,iscsi_lun_t * ilp,struct scsi_inquiry * inq)2977836SJohn.Forte@Sun.COM iscsi_lun_virt_create(iscsi_sess_t *isp, uint16_t lun_num, iscsi_lun_t *ilp,
2987836SJohn.Forte@Sun.COM struct scsi_inquiry *inq)
2997836SJohn.Forte@Sun.COM {
3007836SJohn.Forte@Sun.COM iscsi_status_t rtn = ISCSI_STATUS_INTERNAL_ERROR;
3017836SJohn.Forte@Sun.COM int mdi_rtn = MDI_FAILURE;
3027836SJohn.Forte@Sun.COM iscsi_hba_t *ihp = NULL;
3037836SJohn.Forte@Sun.COM mdi_pathinfo_t *pip = NULL;
3047836SJohn.Forte@Sun.COM char *nodename = NULL;
3057836SJohn.Forte@Sun.COM char **compatible = NULL;
3067836SJohn.Forte@Sun.COM int ncompatible = 0;
3077836SJohn.Forte@Sun.COM int circ = 0;
3087836SJohn.Forte@Sun.COM
3097836SJohn.Forte@Sun.COM ASSERT(isp != NULL);
3107836SJohn.Forte@Sun.COM ASSERT(ilp != NULL);
3117836SJohn.Forte@Sun.COM ihp = isp->sess_hba;
3127836SJohn.Forte@Sun.COM ASSERT(ihp != NULL);
3137836SJohn.Forte@Sun.COM
3147836SJohn.Forte@Sun.COM /*
3157836SJohn.Forte@Sun.COM * Generate compatible property
3167836SJohn.Forte@Sun.COM */
3177836SJohn.Forte@Sun.COM scsi_hba_nodename_compatible_get(inq, "vhci",
3187836SJohn.Forte@Sun.COM inq->inq_dtype, NULL, &nodename, &compatible, &ncompatible);
3197836SJohn.Forte@Sun.COM
3207836SJohn.Forte@Sun.COM /* if nodename can't be determined then print a message and skip it */
3217836SJohn.Forte@Sun.COM if (nodename == NULL) {
3227836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi driver found no compatible driver "
3237836SJohn.Forte@Sun.COM "for %s lun %d dtype:0x%02x", isp->sess_name, lun_num,
3247836SJohn.Forte@Sun.COM inq->inq_dtype);
3257836SJohn.Forte@Sun.COM return (ISCSI_STATUS_INTERNAL_ERROR);
3267836SJohn.Forte@Sun.COM }
3277836SJohn.Forte@Sun.COM
3287836SJohn.Forte@Sun.COM /*
3297836SJohn.Forte@Sun.COM *
3307836SJohn.Forte@Sun.COM */
3317836SJohn.Forte@Sun.COM ndi_devi_enter(scsi_vhci_dip, &circ);
3327836SJohn.Forte@Sun.COM mdi_rtn = mdi_pi_alloc_compatible(ihp->hba_dip, nodename,
3337836SJohn.Forte@Sun.COM ilp->lun_guid, ilp->lun_addr, compatible, ncompatible,
3347836SJohn.Forte@Sun.COM 0, &pip);
3357836SJohn.Forte@Sun.COM
3367836SJohn.Forte@Sun.COM if (mdi_rtn == MDI_SUCCESS) {
3377836SJohn.Forte@Sun.COM mdi_pi_set_phci_private(pip, (caddr_t)ilp);
3387836SJohn.Forte@Sun.COM
3397836SJohn.Forte@Sun.COM if (mdi_prop_update_string(pip, MDI_GUID,
3407836SJohn.Forte@Sun.COM ilp->lun_guid) != DDI_SUCCESS) {
3417836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi driver unable to create "
3427836SJohn.Forte@Sun.COM "property for %s lun %d (MDI_GUID)",
3437836SJohn.Forte@Sun.COM isp->sess_name, lun_num);
3447836SJohn.Forte@Sun.COM mdi_rtn = MDI_FAILURE;
3457836SJohn.Forte@Sun.COM goto virt_create_done;
3467836SJohn.Forte@Sun.COM }
3477836SJohn.Forte@Sun.COM
3487836SJohn.Forte@Sun.COM if (mdi_prop_update_int(pip, TARGET_PROP,
3497836SJohn.Forte@Sun.COM isp->sess_oid) != DDI_SUCCESS) {
3507836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi driver unable to create "
3517836SJohn.Forte@Sun.COM "property for %s lun %d (TARGET_PROP)",
3527836SJohn.Forte@Sun.COM isp->sess_name, lun_num);
3537836SJohn.Forte@Sun.COM mdi_rtn = MDI_FAILURE;
3547836SJohn.Forte@Sun.COM goto virt_create_done;
3557836SJohn.Forte@Sun.COM }
3567836SJohn.Forte@Sun.COM
3577836SJohn.Forte@Sun.COM if (mdi_prop_update_int(pip, LUN_PROP,
3587836SJohn.Forte@Sun.COM ilp->lun_num) != DDI_SUCCESS) {
3597836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi driver unable to create "
3607836SJohn.Forte@Sun.COM "property for %s lun %d (LUN_PROP)",
3617836SJohn.Forte@Sun.COM isp->sess_name, lun_num);
3627836SJohn.Forte@Sun.COM mdi_rtn = MDI_FAILURE;
3637836SJohn.Forte@Sun.COM goto virt_create_done;
3647836SJohn.Forte@Sun.COM }
3657836SJohn.Forte@Sun.COM
3667836SJohn.Forte@Sun.COM if (mdi_prop_update_string_array(pip, "compatible",
3677836SJohn.Forte@Sun.COM compatible, ncompatible) !=
3687836SJohn.Forte@Sun.COM DDI_PROP_SUCCESS) {
3697836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi driver unable to create "
3707836SJohn.Forte@Sun.COM "property for %s lun %d (COMPATIBLE)",
3717836SJohn.Forte@Sun.COM isp->sess_name, lun_num);
3727836SJohn.Forte@Sun.COM mdi_rtn = MDI_FAILURE;
3737836SJohn.Forte@Sun.COM goto virt_create_done;
3747836SJohn.Forte@Sun.COM }
3757836SJohn.Forte@Sun.COM
3767836SJohn.Forte@Sun.COM mdi_rtn = mdi_pi_online(pip, 0);
3777836SJohn.Forte@Sun.COM if (mdi_rtn == MDI_NOT_SUPPORTED) {
3787836SJohn.Forte@Sun.COM mdi_rtn = MDI_FAILURE;
3797836SJohn.Forte@Sun.COM goto virt_create_done;
3807836SJohn.Forte@Sun.COM }
3817836SJohn.Forte@Sun.COM
3827836SJohn.Forte@Sun.COM ilp->lun_pip = pip;
3837836SJohn.Forte@Sun.COM ilp->lun_dip = NULL;
3847836SJohn.Forte@Sun.COM
3857836SJohn.Forte@Sun.COM virt_create_done:
3867836SJohn.Forte@Sun.COM
3877836SJohn.Forte@Sun.COM if (pip && mdi_rtn != MDI_SUCCESS) {
3887836SJohn.Forte@Sun.COM ilp->lun_pip = NULL;
3897836SJohn.Forte@Sun.COM ilp->lun_dip = NULL;
3907836SJohn.Forte@Sun.COM (void) mdi_prop_remove(pip, NULL);
3917836SJohn.Forte@Sun.COM (void) mdi_pi_free(pip, 0);
3927836SJohn.Forte@Sun.COM } else {
3937836SJohn.Forte@Sun.COM rtn = ISCSI_STATUS_SUCCESS;
3947836SJohn.Forte@Sun.COM }
3957836SJohn.Forte@Sun.COM }
3967836SJohn.Forte@Sun.COM ndi_devi_exit(scsi_vhci_dip, circ);
3977836SJohn.Forte@Sun.COM
3987836SJohn.Forte@Sun.COM scsi_hba_nodename_compatible_free(nodename, compatible);
3997836SJohn.Forte@Sun.COM
4007836SJohn.Forte@Sun.COM return (rtn);
4017836SJohn.Forte@Sun.COM }
4027836SJohn.Forte@Sun.COM
4037836SJohn.Forte@Sun.COM
4047836SJohn.Forte@Sun.COM /*
4057836SJohn.Forte@Sun.COM * iscsi_lun_phys_create - creates solaris logical unit via NDI
4067836SJohn.Forte@Sun.COM */
4077836SJohn.Forte@Sun.COM static iscsi_status_t
iscsi_lun_phys_create(iscsi_sess_t * isp,uint16_t lun_num,iscsi_lun_t * ilp,struct scsi_inquiry * inq)4087836SJohn.Forte@Sun.COM iscsi_lun_phys_create(iscsi_sess_t *isp, uint16_t lun_num,
4097836SJohn.Forte@Sun.COM iscsi_lun_t *ilp, struct scsi_inquiry *inq)
4107836SJohn.Forte@Sun.COM {
4117836SJohn.Forte@Sun.COM iscsi_status_t rtn = ISCSI_STATUS_INTERNAL_ERROR;
4127836SJohn.Forte@Sun.COM int ndi_rtn = NDI_FAILURE;
4137836SJohn.Forte@Sun.COM iscsi_hba_t *ihp = NULL;
4147836SJohn.Forte@Sun.COM dev_info_t *lun_dip = NULL;
4157836SJohn.Forte@Sun.COM char *nodename = NULL;
4167836SJohn.Forte@Sun.COM char **compatible = NULL;
4177836SJohn.Forte@Sun.COM int ncompatible = 0;
4187836SJohn.Forte@Sun.COM char *scsi_binding_set = NULL;
4197836SJohn.Forte@Sun.COM char instance[32];
4207836SJohn.Forte@Sun.COM int circ = 0;
4217836SJohn.Forte@Sun.COM
4227836SJohn.Forte@Sun.COM ASSERT(isp != NULL);
4237836SJohn.Forte@Sun.COM ASSERT(ilp != NULL);
4247836SJohn.Forte@Sun.COM ihp = isp->sess_hba;
4257836SJohn.Forte@Sun.COM ASSERT(ihp != NULL);
4267836SJohn.Forte@Sun.COM ASSERT(inq != NULL);
4277836SJohn.Forte@Sun.COM
4287836SJohn.Forte@Sun.COM /* get the 'scsi-binding-set' property */
4297836SJohn.Forte@Sun.COM if (ddi_prop_lookup_string(DDI_DEV_T_ANY, isp->sess_hba->hba_dip,
4307836SJohn.Forte@Sun.COM DDI_PROP_NOTPROM | DDI_PROP_DONTPASS, "scsi-binding-set",
4317836SJohn.Forte@Sun.COM &scsi_binding_set) != DDI_PROP_SUCCESS) {
4327836SJohn.Forte@Sun.COM scsi_binding_set = NULL;
4337836SJohn.Forte@Sun.COM }
4347836SJohn.Forte@Sun.COM
4357836SJohn.Forte@Sun.COM /* generate compatible property */
4367836SJohn.Forte@Sun.COM scsi_hba_nodename_compatible_get(inq, scsi_binding_set,
4377836SJohn.Forte@Sun.COM inq->inq_dtype, NULL, &nodename, &compatible, &ncompatible);
4387836SJohn.Forte@Sun.COM if (scsi_binding_set)
4397836SJohn.Forte@Sun.COM ddi_prop_free(scsi_binding_set);
4407836SJohn.Forte@Sun.COM
4417836SJohn.Forte@Sun.COM /* if nodename can't be determined then print a message and skip it */
4427836SJohn.Forte@Sun.COM if (nodename == NULL) {
4437836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi driver found no compatible driver "
4447836SJohn.Forte@Sun.COM "for %s lun %d", isp->sess_name, lun_num);
4457836SJohn.Forte@Sun.COM return (ISCSI_STATUS_INTERNAL_ERROR);
4467836SJohn.Forte@Sun.COM }
4477836SJohn.Forte@Sun.COM
4487836SJohn.Forte@Sun.COM ndi_devi_enter(ihp->hba_dip, &circ);
4497836SJohn.Forte@Sun.COM
4507836SJohn.Forte@Sun.COM ndi_rtn = ndi_devi_alloc(ihp->hba_dip, nodename,
4517836SJohn.Forte@Sun.COM DEVI_SID_NODEID, &lun_dip);
4527836SJohn.Forte@Sun.COM
4537836SJohn.Forte@Sun.COM /* if lun alloc success, set props */
4547836SJohn.Forte@Sun.COM if (ndi_rtn == NDI_SUCCESS) {
4557836SJohn.Forte@Sun.COM
4567836SJohn.Forte@Sun.COM if (ndi_prop_update_int(DDI_DEV_T_NONE,
4577836SJohn.Forte@Sun.COM lun_dip, TARGET_PROP, (int)isp->sess_oid) !=
4587836SJohn.Forte@Sun.COM DDI_PROP_SUCCESS) {
4597836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi driver unable to create "
4607836SJohn.Forte@Sun.COM "property for %s lun %d (TARGET_PROP)",
4617836SJohn.Forte@Sun.COM isp->sess_name, lun_num);
4627836SJohn.Forte@Sun.COM ndi_rtn = NDI_FAILURE;
4637836SJohn.Forte@Sun.COM goto phys_create_done;
4647836SJohn.Forte@Sun.COM }
4657836SJohn.Forte@Sun.COM
4667836SJohn.Forte@Sun.COM if (ndi_prop_update_int(DDI_DEV_T_NONE,
4677836SJohn.Forte@Sun.COM lun_dip, LUN_PROP, (int)ilp->lun_num) !=
4687836SJohn.Forte@Sun.COM DDI_PROP_SUCCESS) {
4697836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi driver unable to create "
4707836SJohn.Forte@Sun.COM "property for %s lun %d (LUN_PROP)",
4717836SJohn.Forte@Sun.COM isp->sess_name, lun_num);
4727836SJohn.Forte@Sun.COM ndi_rtn = NDI_FAILURE;
4737836SJohn.Forte@Sun.COM goto phys_create_done;
4747836SJohn.Forte@Sun.COM }
4757836SJohn.Forte@Sun.COM
4767836SJohn.Forte@Sun.COM if (ndi_prop_update_string_array(DDI_DEV_T_NONE,
4777836SJohn.Forte@Sun.COM lun_dip, "compatible", compatible, ncompatible)
4787836SJohn.Forte@Sun.COM != DDI_PROP_SUCCESS) {
4797836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi driver unable to create "
4807836SJohn.Forte@Sun.COM "property for %s lun %d (COMPATIBLE)",
4817836SJohn.Forte@Sun.COM isp->sess_name, lun_num);
4827836SJohn.Forte@Sun.COM ndi_rtn = NDI_FAILURE;
4837836SJohn.Forte@Sun.COM goto phys_create_done;
4847836SJohn.Forte@Sun.COM }
4857836SJohn.Forte@Sun.COM
4867836SJohn.Forte@Sun.COM phys_create_done:
4877836SJohn.Forte@Sun.COM /* If props were setup ok, online the lun */
4887836SJohn.Forte@Sun.COM if (ndi_rtn == NDI_SUCCESS) {
4897836SJohn.Forte@Sun.COM /* Try to online the new node */
4907836SJohn.Forte@Sun.COM ndi_rtn = ndi_devi_online(lun_dip, 0);
4917836SJohn.Forte@Sun.COM }
4927836SJohn.Forte@Sun.COM
4937836SJohn.Forte@Sun.COM /* If success set rtn flag, else unwire alloc'd lun */
4947836SJohn.Forte@Sun.COM if (ndi_rtn == NDI_SUCCESS) {
4957836SJohn.Forte@Sun.COM rtn = ISCSI_STATUS_SUCCESS;
4967836SJohn.Forte@Sun.COM /*
4977836SJohn.Forte@Sun.COM * Assign the instance number for the dev_link
4987836SJohn.Forte@Sun.COM * generator. This will ensure the link name is
4997836SJohn.Forte@Sun.COM * unique and persistent across reboots.
5007836SJohn.Forte@Sun.COM */
5017836SJohn.Forte@Sun.COM (void) snprintf(instance, 32, "%d",
5027836SJohn.Forte@Sun.COM ddi_get_instance(lun_dip));
5037836SJohn.Forte@Sun.COM (void) ndi_prop_update_string(DDI_DEV_T_NONE,
5047836SJohn.Forte@Sun.COM lun_dip, NDI_GUID, instance);
5057836SJohn.Forte@Sun.COM } else {
5067836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi driver unable to online "
5077836SJohn.Forte@Sun.COM "%s lun %d", isp->sess_name, lun_num);
5087836SJohn.Forte@Sun.COM ndi_prop_remove_all(lun_dip);
5097836SJohn.Forte@Sun.COM (void) ndi_devi_free(lun_dip);
5107836SJohn.Forte@Sun.COM }
5117836SJohn.Forte@Sun.COM
5127836SJohn.Forte@Sun.COM }
5137836SJohn.Forte@Sun.COM ndi_devi_exit(ihp->hba_dip, circ);
5147836SJohn.Forte@Sun.COM
5157836SJohn.Forte@Sun.COM ilp->lun_dip = lun_dip;
5167836SJohn.Forte@Sun.COM ilp->lun_pip = NULL;
5177836SJohn.Forte@Sun.COM
5187836SJohn.Forte@Sun.COM scsi_hba_nodename_compatible_free(nodename, compatible);
5197836SJohn.Forte@Sun.COM
5207836SJohn.Forte@Sun.COM return (rtn);
5217836SJohn.Forte@Sun.COM }
5227836SJohn.Forte@Sun.COM
5237836SJohn.Forte@Sun.COM
5247836SJohn.Forte@Sun.COM /*
5257836SJohn.Forte@Sun.COM * iscsi_lun_online - _di_online logical unit
5267836SJohn.Forte@Sun.COM *
5277836SJohn.Forte@Sun.COM * This is called after a path has recovered it will cause
5287836SJohn.Forte@Sun.COM * an offline path to become online/active again.
5297836SJohn.Forte@Sun.COM */
5307836SJohn.Forte@Sun.COM void
iscsi_lun_online(iscsi_hba_t * ihp,iscsi_lun_t * ilp)5317836SJohn.Forte@Sun.COM iscsi_lun_online(iscsi_hba_t *ihp, iscsi_lun_t *ilp)
5327836SJohn.Forte@Sun.COM {
5338194SJack.Meng@Sun.COM int circ = 0;
5348194SJack.Meng@Sun.COM int rval = 0;
5358194SJack.Meng@Sun.COM uint64_t *lun_num_ptr = NULL;
5368194SJack.Meng@Sun.COM uint16_t boot_lun_num = 0;
5378194SJack.Meng@Sun.COM iscsi_sess_t *isp = NULL;
5389371SBing.Zhao@Sun.COM boolean_t online = B_FALSE;
5399371SBing.Zhao@Sun.COM nvlist_t *attr_list = NULL;
5409371SBing.Zhao@Sun.COM char *pathname = NULL;
5419371SBing.Zhao@Sun.COM dev_info_t *lun_dip = NULL;
5427836SJohn.Forte@Sun.COM
5437836SJohn.Forte@Sun.COM ASSERT(ilp != NULL);
5447836SJohn.Forte@Sun.COM ASSERT((ilp->lun_pip != NULL) || (ilp->lun_dip != NULL));
5457836SJohn.Forte@Sun.COM
5467836SJohn.Forte@Sun.COM if (ilp->lun_pip != NULL) {
5477836SJohn.Forte@Sun.COM ndi_devi_enter(scsi_vhci_dip, &circ);
5487836SJohn.Forte@Sun.COM rval = mdi_pi_online(ilp->lun_pip, 0);
5497836SJohn.Forte@Sun.COM ndi_devi_exit(scsi_vhci_dip, circ);
5507836SJohn.Forte@Sun.COM if (rval == MDI_SUCCESS) {
5518531SBing.Zhao@Sun.COM ilp->lun_state &= ISCSI_LUN_STATE_CLEAR;
5528531SBing.Zhao@Sun.COM ilp->lun_state |= ISCSI_LUN_STATE_ONLINE;
5537836SJohn.Forte@Sun.COM ilp->lun_time_online = ddi_get_time();
5549371SBing.Zhao@Sun.COM online = B_TRUE;
5557836SJohn.Forte@Sun.COM }
5567836SJohn.Forte@Sun.COM
5577836SJohn.Forte@Sun.COM } else if (ilp->lun_dip != NULL) {
5587836SJohn.Forte@Sun.COM ndi_devi_enter(ihp->hba_dip, &circ);
5597836SJohn.Forte@Sun.COM rval = ndi_devi_online(ilp->lun_dip, 0);
5607836SJohn.Forte@Sun.COM ndi_devi_exit(ihp->hba_dip, circ);
5617836SJohn.Forte@Sun.COM if (rval == NDI_SUCCESS) {
5628531SBing.Zhao@Sun.COM ilp->lun_state &= ISCSI_LUN_STATE_CLEAR;
5638531SBing.Zhao@Sun.COM ilp->lun_state |= ISCSI_LUN_STATE_ONLINE;
5647836SJohn.Forte@Sun.COM ilp->lun_time_online = ddi_get_time();
5659371SBing.Zhao@Sun.COM online = B_TRUE;
5667836SJohn.Forte@Sun.COM }
5677836SJohn.Forte@Sun.COM }
5688194SJack.Meng@Sun.COM
5698194SJack.Meng@Sun.COM /* Check whether this is the required LUN for iscsi boot */
5708194SJack.Meng@Sun.COM if (iscsiboot_prop != NULL &&
5718194SJack.Meng@Sun.COM iscsiboot_prop->boot_tgt.lun_online == 0) {
5728194SJack.Meng@Sun.COM isp = ilp->lun_sess;
5738194SJack.Meng@Sun.COM if (isp->sess_boot == B_TRUE) {
5748194SJack.Meng@Sun.COM lun_num_ptr =
5758194SJack.Meng@Sun.COM (uint64_t *)iscsiboot_prop->boot_tgt.tgt_boot_lun;
5768194SJack.Meng@Sun.COM boot_lun_num = (uint16_t)(*lun_num_ptr);
5778194SJack.Meng@Sun.COM if (boot_lun_num == ilp->lun_num) {
5788194SJack.Meng@Sun.COM /*
5798194SJack.Meng@Sun.COM * During iscsi boot, the boot lun has been
5808194SJack.Meng@Sun.COM * online, we should set the "online flag".
5818194SJack.Meng@Sun.COM */
5828194SJack.Meng@Sun.COM iscsiboot_prop->boot_tgt.lun_online = 1;
5838194SJack.Meng@Sun.COM }
5848194SJack.Meng@Sun.COM }
5858194SJack.Meng@Sun.COM }
5869371SBing.Zhao@Sun.COM
5879371SBing.Zhao@Sun.COM /*
5889371SBing.Zhao@Sun.COM * If the LUN has been online and it is a disk,
5899371SBing.Zhao@Sun.COM * send out a system event.
5909371SBing.Zhao@Sun.COM */
5919371SBing.Zhao@Sun.COM if (online == B_TRUE && ilp->lun_type == DTYPE_DIRECT) {
5929371SBing.Zhao@Sun.COM if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, KM_SLEEP) !=
5939371SBing.Zhao@Sun.COM DDI_SUCCESS) {
5949371SBing.Zhao@Sun.COM return;
5959371SBing.Zhao@Sun.COM }
5969371SBing.Zhao@Sun.COM
5979371SBing.Zhao@Sun.COM if (ilp->lun_pip != NULL) {
5989371SBing.Zhao@Sun.COM lun_dip = mdi_pi_get_client(ilp->lun_pip);
5999371SBing.Zhao@Sun.COM } else {
6009371SBing.Zhao@Sun.COM lun_dip = ilp->lun_dip;
6019371SBing.Zhao@Sun.COM }
6029371SBing.Zhao@Sun.COM
6039371SBing.Zhao@Sun.COM pathname = kmem_zalloc(MAXNAMELEN + 1, KM_SLEEP);
6049371SBing.Zhao@Sun.COM (void) ddi_pathname(lun_dip, pathname);
6059371SBing.Zhao@Sun.COM
6069371SBing.Zhao@Sun.COM if (nvlist_add_string(attr_list, DEV_PHYS_PATH, pathname) !=
6079371SBing.Zhao@Sun.COM DDI_SUCCESS) {
6089371SBing.Zhao@Sun.COM nvlist_free(attr_list);
6099371SBing.Zhao@Sun.COM kmem_free(pathname, MAXNAMELEN + 1);
6109371SBing.Zhao@Sun.COM return;
6119371SBing.Zhao@Sun.COM }
6129371SBing.Zhao@Sun.COM iscsi_send_sysevent(ihp, EC_DEV_ADD, ESC_DISK, attr_list);
6139371SBing.Zhao@Sun.COM kmem_free(pathname, MAXNAMELEN + 1);
6149371SBing.Zhao@Sun.COM nvlist_free(attr_list);
6159371SBing.Zhao@Sun.COM }
6167836SJohn.Forte@Sun.COM }
6177836SJohn.Forte@Sun.COM
6187836SJohn.Forte@Sun.COM /*
6197836SJohn.Forte@Sun.COM * iscsi_lun_offline - attempt _di_offline [and optional _di_free]
6207836SJohn.Forte@Sun.COM *
6217836SJohn.Forte@Sun.COM * This function is called via two paths. When a transport
6227836SJohn.Forte@Sun.COM * path has failed it will be called to offline the logical
6237836SJohn.Forte@Sun.COM * unit. When nameservice access has been removed it will
6247836SJohn.Forte@Sun.COM * be called to both offline and free the logical unit.
6257836SJohn.Forte@Sun.COM * (This operates soley on the solaris node states.
6267836SJohn.Forte@Sun.COM * iscsi_lun_destroy() should be called when attempting
6277836SJohn.Forte@Sun.COM * to free all iscsi lun resources.)
6287836SJohn.Forte@Sun.COM *
6297836SJohn.Forte@Sun.COM * This function can fail with ISCSI_STATUS_BUSY if the
6307836SJohn.Forte@Sun.COM * logical unit is in use. The user should unmount or
6317836SJohn.Forte@Sun.COM * close the device and perform the nameservice operation
6327836SJohn.Forte@Sun.COM * again if this occurs.
6338531SBing.Zhao@Sun.COM *
6348531SBing.Zhao@Sun.COM * If we fail to offline a LUN that we don't want to destroy,
6358531SBing.Zhao@Sun.COM * we will mark it with invalid state. If this LUN still
6368531SBing.Zhao@Sun.COM * exists on the target, we can have another chance to online
6378531SBing.Zhao@Sun.COM * it again when we do the LUN enumeration.
6387836SJohn.Forte@Sun.COM */
6397836SJohn.Forte@Sun.COM iscsi_status_t
iscsi_lun_offline(iscsi_hba_t * ihp,iscsi_lun_t * ilp,boolean_t lun_free)6407836SJohn.Forte@Sun.COM iscsi_lun_offline(iscsi_hba_t *ihp, iscsi_lun_t *ilp, boolean_t lun_free)
6417836SJohn.Forte@Sun.COM {
6429371SBing.Zhao@Sun.COM iscsi_status_t status = ISCSI_STATUS_SUCCESS;
6439371SBing.Zhao@Sun.COM int circ = 0;
6447836SJohn.Forte@Sun.COM dev_info_t *cdip, *pdip;
6459371SBing.Zhao@Sun.COM char *devname = NULL;
6469371SBing.Zhao@Sun.COM char *pathname = NULL;
6477836SJohn.Forte@Sun.COM int rval;
6489371SBing.Zhao@Sun.COM boolean_t offline = B_FALSE;
6499371SBing.Zhao@Sun.COM nvlist_t *attr_list = NULL;
6507836SJohn.Forte@Sun.COM
6517836SJohn.Forte@Sun.COM ASSERT(ilp != NULL);
6527836SJohn.Forte@Sun.COM ASSERT((ilp->lun_pip != NULL) || (ilp->lun_dip != NULL));
6537836SJohn.Forte@Sun.COM
6547836SJohn.Forte@Sun.COM /*
6557836SJohn.Forte@Sun.COM * Since we carry the logical units parent
6567836SJohn.Forte@Sun.COM * lock across the offline call it will not
6577836SJohn.Forte@Sun.COM * issue devfs_clean() and may fail with a
6587836SJohn.Forte@Sun.COM * devi_ref count > 0.
6597836SJohn.Forte@Sun.COM */
6607836SJohn.Forte@Sun.COM if (ilp->lun_pip == NULL) {
6617836SJohn.Forte@Sun.COM cdip = ilp->lun_dip;
6627836SJohn.Forte@Sun.COM } else {
6637836SJohn.Forte@Sun.COM cdip = mdi_pi_get_client(ilp->lun_pip);
6647836SJohn.Forte@Sun.COM }
6657836SJohn.Forte@Sun.COM
6667836SJohn.Forte@Sun.COM if ((cdip != NULL) &&
6677836SJohn.Forte@Sun.COM (lun_free == B_TRUE) &&
6688531SBing.Zhao@Sun.COM (ilp->lun_state & ISCSI_LUN_STATE_ONLINE)) {
6697836SJohn.Forte@Sun.COM /*
6707836SJohn.Forte@Sun.COM * Make sure node is attached otherwise
6717836SJohn.Forte@Sun.COM * it won't have related cache nodes to
6727836SJohn.Forte@Sun.COM * clean up. i_ddi_devi_attached is
6737836SJohn.Forte@Sun.COM * similiar to i_ddi_node_state(cdip) >=
6747836SJohn.Forte@Sun.COM * DS_ATTACHED. We should clean up only
6757836SJohn.Forte@Sun.COM * when lun_free is set.
6767836SJohn.Forte@Sun.COM */
6777836SJohn.Forte@Sun.COM if (i_ddi_devi_attached(cdip)) {
6787836SJohn.Forte@Sun.COM
6797836SJohn.Forte@Sun.COM /* Get parent dip */
6807836SJohn.Forte@Sun.COM pdip = ddi_get_parent(cdip);
6817836SJohn.Forte@Sun.COM
6827836SJohn.Forte@Sun.COM /* Get full devname */
6837836SJohn.Forte@Sun.COM devname = kmem_alloc(MAXNAMELEN + 1, KM_SLEEP);
6847836SJohn.Forte@Sun.COM ndi_devi_enter(pdip, &circ);
6857836SJohn.Forte@Sun.COM (void) ddi_deviname(cdip, devname);
6867836SJohn.Forte@Sun.COM /* Release lock before devfs_clean() */
6877836SJohn.Forte@Sun.COM ndi_devi_exit(pdip, circ);
6887836SJohn.Forte@Sun.COM
6897836SJohn.Forte@Sun.COM /* Clean cache */
6907836SJohn.Forte@Sun.COM rval = devfs_clean(pdip, devname + 1,
6917836SJohn.Forte@Sun.COM DV_CLEAN_FORCE);
6927836SJohn.Forte@Sun.COM kmem_free(devname, MAXNAMELEN + 1);
6937836SJohn.Forte@Sun.COM
6947836SJohn.Forte@Sun.COM if ((rval != 0) && (ilp->lun_pip == NULL)) {
6957836SJohn.Forte@Sun.COM return (ISCSI_STATUS_BUSY);
6967836SJohn.Forte@Sun.COM }
6977836SJohn.Forte@Sun.COM }
6987836SJohn.Forte@Sun.COM }
6997836SJohn.Forte@Sun.COM
7009371SBing.Zhao@Sun.COM if (cdip != NULL && ilp->lun_type == DTYPE_DIRECT) {
7019371SBing.Zhao@Sun.COM pathname = kmem_zalloc(MAXNAMELEN + 1, KM_SLEEP);
7029371SBing.Zhao@Sun.COM (void) ddi_pathname(cdip, pathname);
7039371SBing.Zhao@Sun.COM }
7049371SBing.Zhao@Sun.COM
7057836SJohn.Forte@Sun.COM /* Attempt to offline the logical units */
7067836SJohn.Forte@Sun.COM if (ilp->lun_pip != NULL) {
7077836SJohn.Forte@Sun.COM
7087836SJohn.Forte@Sun.COM /* virt/mdi */
7097836SJohn.Forte@Sun.COM ndi_devi_enter(scsi_vhci_dip, &circ);
7107836SJohn.Forte@Sun.COM if ((lun_free == B_TRUE) &&
7118531SBing.Zhao@Sun.COM (ilp->lun_state & ISCSI_LUN_STATE_ONLINE)) {
7127836SJohn.Forte@Sun.COM rval = mdi_pi_offline(ilp->lun_pip,
7137836SJohn.Forte@Sun.COM NDI_DEVI_REMOVE);
7147836SJohn.Forte@Sun.COM } else {
7157836SJohn.Forte@Sun.COM rval = mdi_pi_offline(ilp->lun_pip, 0);
7167836SJohn.Forte@Sun.COM }
7177836SJohn.Forte@Sun.COM
7187836SJohn.Forte@Sun.COM if (rval == MDI_SUCCESS) {
7198531SBing.Zhao@Sun.COM ilp->lun_state &= ISCSI_LUN_STATE_CLEAR;
7208531SBing.Zhao@Sun.COM ilp->lun_state |= ISCSI_LUN_STATE_OFFLINE;
7217836SJohn.Forte@Sun.COM if (lun_free == B_TRUE) {
7227836SJohn.Forte@Sun.COM (void) mdi_prop_remove(ilp->lun_pip, NULL);
7237836SJohn.Forte@Sun.COM (void) mdi_pi_free(ilp->lun_pip, 0);
7247836SJohn.Forte@Sun.COM }
7259371SBing.Zhao@Sun.COM offline = B_TRUE;
7267836SJohn.Forte@Sun.COM } else {
727*11977SJack.Meng@Sun.COM status = ISCSI_STATUS_BUSY;
7288531SBing.Zhao@Sun.COM if (lun_free == B_FALSE) {
7298531SBing.Zhao@Sun.COM ilp->lun_state |= ISCSI_LUN_STATE_INVALID;
7309371SBing.Zhao@Sun.COM offline = B_TRUE;
7318531SBing.Zhao@Sun.COM }
7327836SJohn.Forte@Sun.COM }
7337836SJohn.Forte@Sun.COM ndi_devi_exit(scsi_vhci_dip, circ);
7347836SJohn.Forte@Sun.COM
7357836SJohn.Forte@Sun.COM } else {
7367836SJohn.Forte@Sun.COM
7377836SJohn.Forte@Sun.COM /* phys/ndi */
7387836SJohn.Forte@Sun.COM ndi_devi_enter(ihp->hba_dip, &circ);
7397836SJohn.Forte@Sun.COM if ((lun_free == B_TRUE) &&
7408531SBing.Zhao@Sun.COM (ilp->lun_state & ISCSI_LUN_STATE_ONLINE)) {
7417836SJohn.Forte@Sun.COM rval = ndi_devi_offline(
7427836SJohn.Forte@Sun.COM ilp->lun_dip, NDI_DEVI_REMOVE);
7437836SJohn.Forte@Sun.COM } else {
7447836SJohn.Forte@Sun.COM rval = ndi_devi_offline(
7457836SJohn.Forte@Sun.COM ilp->lun_dip, 0);
7467836SJohn.Forte@Sun.COM }
7477836SJohn.Forte@Sun.COM if (rval != NDI_SUCCESS) {
748*11977SJack.Meng@Sun.COM status = ISCSI_STATUS_BUSY;
7498531SBing.Zhao@Sun.COM if (lun_free == B_FALSE) {
7508531SBing.Zhao@Sun.COM ilp->lun_state |= ISCSI_LUN_STATE_INVALID;
7519371SBing.Zhao@Sun.COM offline = B_TRUE;
7528531SBing.Zhao@Sun.COM }
7537836SJohn.Forte@Sun.COM } else {
7548531SBing.Zhao@Sun.COM ilp->lun_state &= ISCSI_LUN_STATE_CLEAR;
7558531SBing.Zhao@Sun.COM ilp->lun_state |= ISCSI_LUN_STATE_OFFLINE;
7569371SBing.Zhao@Sun.COM offline = B_TRUE;
7577836SJohn.Forte@Sun.COM }
7587836SJohn.Forte@Sun.COM ndi_devi_exit(ihp->hba_dip, circ);
7599371SBing.Zhao@Sun.COM }
7607836SJohn.Forte@Sun.COM
7619371SBing.Zhao@Sun.COM if (offline == B_TRUE && pathname != NULL &&
7629371SBing.Zhao@Sun.COM ilp->lun_type == DTYPE_DIRECT) {
7639371SBing.Zhao@Sun.COM if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, KM_SLEEP) !=
7649371SBing.Zhao@Sun.COM DDI_SUCCESS) {
7659371SBing.Zhao@Sun.COM kmem_free(pathname, MAXNAMELEN + 1);
7669371SBing.Zhao@Sun.COM return (status);
7679371SBing.Zhao@Sun.COM }
7689371SBing.Zhao@Sun.COM
7699371SBing.Zhao@Sun.COM if (nvlist_add_string(attr_list, DEV_PHYS_PATH, pathname) !=
7709371SBing.Zhao@Sun.COM DDI_SUCCESS) {
7719371SBing.Zhao@Sun.COM nvlist_free(attr_list);
7729371SBing.Zhao@Sun.COM kmem_free(pathname, MAXNAMELEN + 1);
7739371SBing.Zhao@Sun.COM return (status);
7749371SBing.Zhao@Sun.COM }
7759371SBing.Zhao@Sun.COM
7769371SBing.Zhao@Sun.COM iscsi_send_sysevent(ihp, EC_DEV_REMOVE, ESC_DISK, attr_list);
7779371SBing.Zhao@Sun.COM nvlist_free(attr_list);
7787836SJohn.Forte@Sun.COM }
7799371SBing.Zhao@Sun.COM
7809371SBing.Zhao@Sun.COM if (pathname != NULL) {
7819371SBing.Zhao@Sun.COM kmem_free(pathname, MAXNAMELEN + 1);
7829371SBing.Zhao@Sun.COM }
7839371SBing.Zhao@Sun.COM
7847836SJohn.Forte@Sun.COM return (status);
7857836SJohn.Forte@Sun.COM }
786