Skip to content

Instantly share code, notes, and snippets.

@jclulow
Created October 19, 2019 07:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jclulow/b2035fbead2680492a4af6e45804003e to your computer and use it in GitHub Desktop.
Save jclulow/b2035fbead2680492a4af6e45804003e to your computer and use it in GitHub Desktop.
commit 3149e4cfdaf72c0e4f2cdcda9461c0d436037306
Author: Joshua M. Clulow <josh@sysmgr.org>
Date: Tue Oct 15 01:38:49 2019 -0700
11816 iscsi initiator gets confused if attached before root file system mount
diff --git a/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi.c b/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi.c
index a35a39caa8..38795beab5 100644
--- a/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi.c
+++ b/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi.c
@@ -4,40 +4,41 @@
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2000 by Cisco Systems, Inc. All rights reserved.
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2019 Joshua M. Clulow <josh@sysmgr.org>
*
* iSCSI Software Initiator
*/
/*
* Framework interface routines for iSCSI
*/
#include "iscsi.h" /* main header */
#include <sys/iscsi_protocol.h> /* protocol structs */
#include <sys/scsi/adapters/iscsi_if.h> /* ioctl interfaces */
#include "iscsi_targetparam.h"
#include "persistent.h"
#include <sys/scsi/adapters/iscsi_door.h>
#include <sys/dlpi.h>
#include <sys/utsname.h>
#include "isns_client.h"
#include "isns_protocol.h"
#include <sys/bootprops.h>
#include <sys/types.h>
@@ -348,76 +349,86 @@ iscsi_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd,
rval = DDI_SUCCESS;
break;
default:
rval = DDI_FAILURE;
break;
}
return (rval);
}
/*
* iscsi_attach -- Attach instance of an iSCSI HBA. We
* will attempt to create our HBA and register it with
* scsi_vhci. If it's not possible to create the HBA
* or register with vhci we will fail the attach.
*/
static int
iscsi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
{
- int rval = DDI_SUCCESS;
int instance = ddi_get_instance(dip);
iscsi_hba_t *ihp = NULL;
scsi_hba_tran_t *tran = NULL;
char init_port_name[MAX_NAME_PROP_SIZE];
- switch (cmd) {
- case DDI_ATTACH:
- /* create iSCSH HBA devctl device node */
+ if (cmd == DDI_RESUME) {
+ return (DDI_SUCCESS);
+ } else if (cmd != DDI_ATTACH) {
+ return (DDI_FAILURE);
+ }
+
+ if (!modrootloaded && iscsiboot_prop == NULL) {
+ /*
+ * The root file system has not yet been mounted, and we're not
+ * trying to boot from an iSCSI device. Fail to attach now so
+ * that we can retry after root has been mounted.
+ */
+ return (DDI_FAILURE);
+ }
+
+ /* create iSCSI HBA devctl device node */
if (ddi_create_minor_node(dip, ISCSI_DEVCTL, S_IFCHR, 0,
- DDI_PSEUDO, 0) == DDI_SUCCESS) {
+ DDI_PSEUDO, 0) != DDI_SUCCESS) {
+ goto iscsi_attach_failed3;
+ }
/* allocate HBA soft state */
if (ddi_soft_state_zalloc(iscsi_state, instance) !=
DDI_SUCCESS) {
ddi_remove_minor_node(dip, NULL);
- rval = DDI_FAILURE;
- break;
+ goto iscsi_attach_failed3;
}
/* get reference to soft state */
if ((ihp = (iscsi_hba_t *)ddi_get_soft_state(
iscsi_state, instance)) == NULL) {
ddi_remove_minor_node(dip, NULL);
ddi_soft_state_free(iscsi_state, instance);
- rval = DDI_FAILURE;
- break;
+ goto iscsi_attach_failed3;
}
/* init HBA mutex used to protect discovery events */
mutex_init(&ihp->hba_discovery_events_mutex, NULL,
MUTEX_DRIVER, NULL);
- /* Get LDI ident */
- rval = ldi_ident_from_dip(dip, &ihp->hba_li);
- ASSERT(rval == 0); /* Failure indicates invalid arg */
+ VERIFY0(ldi_ident_from_dip(dip, &ihp->hba_li));
/* init HBA mutex used to protect service status */
mutex_init(&ihp->hba_service_lock, NULL,
MUTEX_DRIVER, NULL);
cv_init(&ihp->hba_service_cv, NULL, CV_DRIVER, NULL);
/*
* init SendTargets semaphore that is used to allow
* only one operation at a time
*/
sema_init(&ihp->hba_sendtgts_semaphore, 1, NULL,
SEMA_DRIVER, NULL);
ihp->hba_sess_list = NULL;
rw_init(&ihp->hba_sess_list_rwlock, NULL,
RW_DRIVER, NULL);
/* allocate scsi_hba_tran */
if ((tran = scsi_hba_tran_alloc(dip, SCSI_HBA_CANSLEEP))
== NULL) {
@@ -579,81 +590,66 @@ iscsi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
/* Setup init_port_name for MPAPI */
(void) snprintf(init_port_name, MAX_NAME_PROP_SIZE,
"%s,%02x%02x%02x%02x%02x%02x",
(char *)ihp->hba_name, ihp->hba_isid[0],
ihp->hba_isid[1], ihp->hba_isid[2],
ihp->hba_isid[3], ihp->hba_isid[4],
ihp->hba_isid[5]);
if (ddi_prop_update_string(DDI_DEV_T_NONE, dip,
SCSI_ADDR_PROP_INITIATOR_PORT, init_port_name) !=
DDI_PROP_SUCCESS) {
cmn_err(CE_WARN, "iscsi_attach: Creating "
SCSI_ADDR_PROP_INITIATOR_PORT
" property on iSCSI "
"HBA(%s) with dip(%d) Failed",
(char *)ihp->hba_name,
ddi_get_instance(dip));
}
ddi_report_dev(dip);
- } else {
- rval = DDI_FAILURE;
- }
- break;
+ return (DDI_SUCCESS);
iscsi_attach_failed0:
isns_client_cleanup();
if (ihp->stats.ks) {
(void) iscsi_hba_kstat_term(ihp);
}
if (ihp->hba_mpxio_enabled == B_TRUE) {
(void) mdi_phci_unregister(dip, 0);
}
(void) scsi_hba_detach(ihp->hba_dip);
iscsi_attach_failed1:
ddi_remove_minor_node(dip, NULL);
ddi_prop_remove_all(ihp->hba_dip);
scsi_hba_tran_free(tran);
iscsi_attach_failed2:
cv_destroy(&ihp->hba_service_cv);
mutex_destroy(&ihp->hba_service_lock);
mutex_destroy(&ihp->hba_discovery_events_mutex);
sema_destroy(&ihp->hba_sendtgts_semaphore);
rw_destroy(&ihp->hba_sess_list_rwlock);
ddi_soft_state_free(iscsi_state, instance);
- rval = DDI_FAILURE;
- break;
-
- case DDI_RESUME:
- break;
-
- default:
- rval = DDI_FAILURE;
- }
-
- if (rval != DDI_SUCCESS) {
+iscsi_attach_failed3:
cmn_err(CE_WARN, "iscsi driver unable to attach "
"hba instance %d", instance);
- }
-
- return (rval);
+ return (DDI_FAILURE);
}
/*
* iscsi_detach - called on unload of hba instance
*/
static int
iscsi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
{
int rval = DDI_SUCCESS;
scsi_hba_tran_t *tran = NULL;
iscsi_hba_t *ihp = NULL;
iscsi_hba_t *ihp_check = NULL;
int instance;
char *init_node_name;
instance = ddi_get_instance(dip);
switch (cmd) {
case DDI_DETACH:
if (!(tran = (scsi_hba_tran_t *)ddi_get_driver_private(dip))) {
@@ -4992,41 +4988,42 @@ iscsi_set_default_tunable_params(iscsi_tunable_params_t *params)
}
/*
* +--------------------------------------------------------------------+
* | End of struct utility routines |
* +--------------------------------------------------------------------+
*/
/*
* +--------------------------------------------------------------------+
* | Begin of ioctl utility routines |
* +--------------------------------------------------------------------+
*/
/*
* iscsi_get_param - This function is a helper to ISCSI_GET_PARAM
* IOCTL
*/
int
iscsi_get_param(iscsi_login_params_t *params, boolean_t valid_flag,
- iscsi_param_get_t *ipgp) {
+ iscsi_param_get_t *ipgp)
+{
int rtn = 0;
/* ---- Default to settable, possibly changed later ---- */
ipgp->g_value.v_valid = valid_flag;
ipgp->g_value.v_settable = B_TRUE;
switch (ipgp->g_param) {
/*
* Boolean parameters
*/
case ISCSI_LOGIN_PARAM_DATA_SEQUENCE_IN_ORDER:
ipgp->g_value.v_bool.b_current =
params->data_sequence_in_order;
ipgp->g_value.v_bool.b_default =
ISCSI_DEFAULT_DATA_SEQUENCE_IN_ORDER;
break;
case ISCSI_LOGIN_PARAM_IMMEDIATE_DATA:
ipgp->g_value.v_bool.b_current =
params->immediate_data;
ipgp->g_value.v_bool.b_default =
@@ -5382,132 +5379,138 @@ iscsi_cmp_boot_sess_oid(iscsi_hba_t *ihp, uint32_t oid)
}
}
if (oid == ihp->hba_oid) {
/* oid is initiator object id */
return (B_TRUE);
} else if ((isp != NULL) && (isp->sess_boot)) {
/* oid is boot session object id */
return (B_TRUE);
}
}
return (B_FALSE);
}
/*
* iscsi_client_request_service - request the iSCSI service
* returns true if the service is enabled and increases the count
* returns false if the service is disabled
* blocks until the service status is either enabled or disabled
*/
boolean_t
-iscsi_client_request_service(iscsi_hba_t *ihp) {
+iscsi_client_request_service(iscsi_hba_t *ihp)
+{
boolean_t rval = B_TRUE;
mutex_enter(&ihp->hba_service_lock);
while ((ihp->hba_service_status == ISCSI_SERVICE_TRANSITION) ||
(ihp->hba_service_client_count == UINT_MAX)) {
cv_wait(&ihp->hba_service_cv, &ihp->hba_service_lock);
}
if (ihp->hba_service_status == ISCSI_SERVICE_ENABLED) {
ihp->hba_service_client_count++;
} else {
rval = B_FALSE;
}
mutex_exit(&ihp->hba_service_lock);
return (rval);
}
/*
* iscsi_client_release_service - decrease the count and wake up
* blocking threads if the count reaches zero
*/
void
-iscsi_client_release_service(iscsi_hba_t *ihp) {
+iscsi_client_release_service(iscsi_hba_t *ihp)
+{
mutex_enter(&ihp->hba_service_lock);
ASSERT(ihp->hba_service_client_count > 0);
ihp->hba_service_client_count--;
if (ihp->hba_service_client_count == 0) {
cv_broadcast(&ihp->hba_service_cv);
}
mutex_exit(&ihp->hba_service_lock);
}
/*
* iscsi_enter_service_zone - enter the service zone, should be called
* before doing any modifications to the service status
* return TRUE if the zone is entered
* FALSE if no need to enter the zone
*/
static boolean_t
-iscsi_enter_service_zone(iscsi_hba_t *ihp, uint32_t status) {
+iscsi_enter_service_zone(iscsi_hba_t *ihp, uint32_t status)
+{
if ((status != ISCSI_SERVICE_ENABLED) &&
(status != ISCSI_SERVICE_DISABLED)) {
return (B_FALSE);
}
mutex_enter(&ihp->hba_service_lock);
while (ihp->hba_service_status == ISCSI_SERVICE_TRANSITION) {
cv_wait(&ihp->hba_service_cv, &ihp->hba_service_lock);
}
if (ihp->hba_service_status == status) {
mutex_exit(&ihp->hba_service_lock);
return (B_FALSE);
}
ihp->hba_service_status = ISCSI_SERVICE_TRANSITION;
while (ihp->hba_service_client_count > 0) {
cv_wait(&ihp->hba_service_cv, &ihp->hba_service_lock);
}
mutex_exit(&ihp->hba_service_lock);
return (B_TRUE);
}
/*
* iscsi_exit_service_zone - exits the service zone and wakes up waiters
*/
static void
-iscsi_exit_service_zone(iscsi_hba_t *ihp, uint32_t status) {
+iscsi_exit_service_zone(iscsi_hba_t *ihp, uint32_t status)
+{
if ((status != ISCSI_SERVICE_ENABLED) &&
(status != ISCSI_SERVICE_DISABLED)) {
return;
}
mutex_enter(&ihp->hba_service_lock);
ASSERT(ihp->hba_service_status == ISCSI_SERVICE_TRANSITION);
ihp->hba_service_status = status;
cv_broadcast(&ihp->hba_service_cv);
mutex_exit(&ihp->hba_service_lock);
}
static void
-iscsi_check_miniroot(iscsi_hba_t *ihp) {
+iscsi_check_miniroot(iscsi_hba_t *ihp)
+{
if (strncmp(rootfs.bo_name, "/ramdisk", 8) == 0) {
/*
* in miniroot we don't have the persistent store
* so just to need to ensure an enabled status
*/
ihp->hba_service_status = ISCSI_SERVICE_ENABLED;
}
}
static void
-iscsi_get_tunable_default(iscsi_tunable_object_t *param) {
+iscsi_get_tunable_default(iscsi_tunable_object_t *param)
+{
int param_id = 0;
param_id = 1 << (param->t_param - 1);
param->t_set = B_FALSE;
switch (param_id) {
case ISCSI_TUNABLE_PARAM_RX_TIMEOUT_VALUE:
param->t_value.v_integer = ISCSI_DEFAULT_RX_TIMEOUT_VALUE;
break;
case ISCSI_TUNABLE_PARAM_LOGIN_POLLING_DELAY:
param->t_value.v_integer = ISCSI_DEFAULT_LOGIN_POLLING_DELAY;
break;
case ISCSI_TUNABLE_PARAM_CONN_LOGIN_MAX:
param->t_value.v_integer = ISCSI_DEFAULT_CONN_DEFAULT_LOGIN_MAX;
break;
default:
break;
}
}
/*
diff --git a/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi_net.c b/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi_net.c
index 970e18b324..57944247df 100644
--- a/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi_net.c
+++ b/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi_net.c
@@ -132,41 +132,40 @@ const int is_incoming_opcode_invalid[256] = {
/* 0x1X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
/* 0x2X */ 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
/* 0x3X */ 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
/* 0x4X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
/* 0x5X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
/* 0x6X */ 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
/* 0x7X */ 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
/* 0x8X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
/* 0x9X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
/* 0xAX */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
/* 0xBX */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
/* 0xCX */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
/* 0xDX */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
/* 0xEX */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
/* 0xFX */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
};
#define IP_4_BITS 32
#define IP_6_BITS 128
-extern int modrootloaded;
extern ib_boot_prop_t *iscsiboot_prop;
/* prototypes */
static void * iscsi_net_socket(int domain, int type, int protocol);
static int iscsi_net_bind(void *socket, struct sockaddr *
name, int name_len, int backlog, int flags);
static int iscsi_net_connect(void *socket, struct sockaddr *
name, int name_len, int fflag, int flags);
static int iscsi_net_listen(void *socket, int backlog);
static void * iscsi_net_accept(void *socket, struct sockaddr *addr,
int *addr_len);
static int iscsi_net_getsockname(void *socket, struct sockaddr *, socklen_t *);
static int iscsi_net_getsockopt(void *socket, int level,
int option_name, void *option_val, int *option_len, int flags);
static int iscsi_net_setsockopt(void *socket, int level,
int option_name, void *option_val, int option_len);
static int iscsi_net_shutdown(void *socket, int how);
static void iscsi_net_close(void *socket);
static size_t iscsi_net_poll(void *socket, clock_t timeout);
diff --git a/usr/src/uts/common/io/scsi/adapters/iscsi/iscsid.c b/usr/src/uts/common/io/scsi/adapters/iscsi/iscsid.c
index 73705c0cc4..3aa24f72eb 100644
--- a/usr/src/uts/common/io/scsi/adapters/iscsi/iscsid.c
+++ b/usr/src/uts/common/io/scsi/adapters/iscsi/iscsid.c
@@ -3,40 +3,41 @@
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2019 Joshua M. Clulow <josh@sysmgr.org>
*/
/*
* ISCSID --
*
* Discovery of targets and access to the persistent storage starts here.
*/
#include <sys/thread.h>
#include <sys/types.h>
#include <sys/proc.h> /* declares: p0 */
#include <sys/cmn_err.h>
#include <sys/scsi/adapters/iscsi_if.h>
#include <netinet/in.h>
#include "iscsi_targetparam.h"
#include "isns_client.h"
#include "isns_protocol.h"
#include "persistent.h"
#include "iscsi.h"
#include <sys/ethernet.h>
@@ -238,80 +239,92 @@ iscsi_boot_session_create(iscsi_hba_t *ihp,
iscsid_do_sendtgts(&e);
(void) iscsid_login_tgt(ihp, NULL, dm,
&addr_dsc.sin);
}
}
/*
* iscsid_init -- to initialize stuffs related to iscsi daemon,
* and to create boot session if needed
*/
boolean_t
iscsid_init(iscsi_hba_t *ihp)
{
boolean_t rval = B_TRUE;
sema_init(&iscsid_config_semaphore, 1, NULL,
SEMA_DRIVER, NULL);
persistent_init();
iscsid_threads_create(ihp);
- if (modrootloaded == 1) {
- /* normal case, load the persistent store */
+ if (modrootloaded) {
+ /*
+ * The root file system is available so we can load the
+ * persistent store.
+ */
if (persistent_load() == B_TRUE) {
ihp->hba_persistent_loaded = B_TRUE;
} else {
return (B_FALSE);
}
+ } else {
+ /*
+ * If the root file system is not yet mounted then we _must_ be
+ * booting from an iSCSI device. If not, we want to fail to
+ * attach so that we can try again after the VFS root is
+ * available.
+ */
+ if (iscsiboot_prop == NULL) {
+ return (B_FALSE);
}
- if ((modrootloaded == 0) && (iscsiboot_prop != NULL)) {
if (!iscsid_boot_init_config(ihp)) {
rval = B_FALSE;
} else {
iscsi_boot_session_create(ihp, iscsiboot_prop);
iscsi_boot_wd_handle =
iscsi_thread_create(ihp->hba_dip,
"BootWD", iscsid_thread_boot_wd, ihp);
- if (iscsi_boot_wd_handle) {
+ if (iscsi_boot_wd_handle != NULL) {
rval = iscsi_thread_start(
iscsi_boot_wd_handle);
} else {
rval = B_FALSE;
}
}
if (rval == B_FALSE) {
cmn_err(CE_NOTE, "Initializaton of iscsi boot session"
" partially failed");
}
}
return (rval);
}
/*
* iscsid_start -- start the iscsi initiator daemon, actually this code
* is just to enable discovery methods which are set enabled in
* persistent store, as an economic way to present the 'daemon' funtionality
*/
boolean_t
-iscsid_start(iscsi_hba_t *ihp) {
+iscsid_start(iscsi_hba_t *ihp)
+{
boolean_t rval = B_FALSE;
iSCSIDiscoveryMethod_t dm;
iSCSIDiscoveryMethod_t *fdm;
rval = iscsid_init_config(ihp);
if (rval == B_TRUE) {
rval = iscsid_init_targets(ihp);
}
if (rval == B_TRUE) {
dm = persistent_disc_meth_get();
rval = iscsid_enable_discovery(ihp, dm, B_TRUE);
if (rval == B_TRUE) {
iscsid_poke_discovery(ihp,
iSCSIDiscoveryMethodUnknown);
(void) iscsid_login_tgt(ihp, NULL,
iSCSIDiscoveryMethodUnknown, NULL);
}
}
@@ -322,41 +335,42 @@ iscsid_start(iscsi_hba_t *ihp) {
* events have occurred.
*/
for (fdm = &for_failure[0]; *fdm !=
iSCSIDiscoveryMethodUnknown; fdm++) {
/* ---- Send both start and end events ---- */
iscsi_discovery_event(ihp, *fdm, B_TRUE);
iscsi_discovery_event(ihp, *fdm, B_FALSE);
}
}
return (rval);
}
/*
* iscsid_stop -- stop the iscsi initiator daemon, by disabling
* all the discovery methods first, and then try to stop all
* related threads. This is a try-best effort, leave any 'busy' device
* (and therefore session) there and just return.
*/
boolean_t
-iscsid_stop(iscsi_hba_t *ihp) {
+iscsid_stop(iscsi_hba_t *ihp)
+{
boolean_t rval = B_FALSE;
iscsi_sess_t *isp = NULL;
(void) iscsid_disable_discovery(ihp, ISCSI_ALL_DISCOVERY_METHODS);
/* final check */
rw_enter(&ihp->hba_sess_list_rwlock, RW_READER);
if (ihp->hba_sess_list == NULL) {
rval = B_TRUE;
} else {
/*
* If only boot session is left, that is OK.
* Otherwise, we should report that some sessions are left.
*/
rval = B_TRUE;
for (isp = ihp->hba_sess_list; isp != NULL;
isp = isp->sess_next) {
if (isp->sess_boot == B_FALSE) {
rval = B_FALSE;
break;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment