xref: /onnv-gate/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi_lun.c (revision 11977:258a44653869)
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