/*
* CDDL HEADER START
*
* 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
* 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
*/
/*
*
* iSCSI session interfaces
*/
#include <sys/bootprops.h>
#include "iscsi.h"
#include "persistent.h"
#include "iscsi_targetparam.h"
/*
* used to store report lun information found
*
* lun_valid: if TRUE means the entry contains a valid entry
* lun_found: if TRUE means the lun has been found in the sess_lun_list
* lun_num: contains the lun_number
* lun_addr_type: indicates lun's type of addressing
*/
typedef struct replun_data {
/*
* The following private tunable, settable via
* set iscsi:iscsi_sess_max_delay = 64
* seconds of retry for a unreachable target during the login.
*/
/*
* Warning messages for the session scsi enumeration
*/
static const char *iscsi_sess_enum_warn_msgs[] = {
"completed",
"partially successful",
"IO failures",
"submitted",
"unable to submit the enumeration",
"session is gone",
"test unit ready failed"
};
/* internal interfaces */
/* LINTED E_STATIC_UNUSED */
/* internal state machine interfaces */
/* internal enumeration interfaces */
static void iscsi_sess_enumeration(void *arg);
/*
* +--------------------------------------------------------------------+
* | External Session Interfaces |
* +--------------------------------------------------------------------+
*/
{
int len = 0;
char *tq_name;
char *th_name;
(void) iscsi_sess_destroy(isp);
}
/* Match target name and LSB ISID */
/* Match TPGT */
return (isp);
}
/*
* Under rare cases wd thread is already
* freed, create it if so.
*/
(ISCSI_TH_MAX_NAME_LEN - 1),
isp);
(void) iscsi_thread_start(
}
/* No way to save it */
goto clean_failed_sess;
}
}
if (status != ISCSI_STATUS_SUCCESS) {
goto clean_failed_sess;
}
}
return (isp);
}
/*
* Also protect against creating duplicate
* sessions with different configured tpgt
* values. default vs. defined.
*/
(tpgt != ISCSI_DEFAULT_TPGT)) ||
(tpgt == ISCSI_DEFAULT_TPGT)))) {
/* Dangerous configuration. Fail Request */
return (NULL);
}
}
}
/*
* If this session is not a Send Targets session, set the target
* that this session is associated with.
*/
(uchar_t *)target_name);
}
if (method & iSCSIDiscoveryMethodBoot) {
/* This is boot session. */
} else {
}
/* Associate session with this discovery method */
sizeof (isp->sess_discovered_addr));
} else {
}
/* assign unique key for the session */
/* setup session parameters */
isp->sess_name_length = 0;
/* copy default driver login parameters */
sizeof (iscsi_login_params_t));
/* copy target name into session */
/* initialize pending and completion queues */
/* setup sessions lun list */
/* setup sessions connection list */
/* create the session task queue */
}
goto iscsi_sess_cleanup2;
}
}
goto iscsi_sess_cleanup1;
}
/* startup watchdog */
}
goto iscsi_sess_cleanup0;
}
if (status != ISCSI_STATUS_SUCCESS) {
goto iscsi_sess_cleanup1;
}
/* Add new target to the hba target list */
} else {
}
(void) iscsi_sess_kstat_init(isp);
if (type == ISCSI_SESS_TYPE_NORMAL) {
isp->sess_enum_result_count = 0;
}
isp->sess_state_event_count = 0;
return (isp);
}
}
return (NULL);
}
/*
* iscsi_sess_get - return the session structure for based on a
* passed in oid and hba instance.
*/
int
{
int rval = 0;
/* See if we already created this session */
/* compare target name as the unique identifier */
/* Found matching session */
break;
}
}
/* If not null this session is already available */
/* Existing session, return it */
} else {
}
return (rval);
}
/*
* iscsi_sess_online - initiate online of sessions connections
*/
void
{
int idx;
/*
* Stale /dev links can cause us to get floods
* of config requests. To prevent these repeated
* requests from causing unneeded login to the
* unreachable target, we won't try it during
* the delay.
*/
return;
}
/*
* Perform a crude version of round robin to
* determine which connection to use for
* this session. Since byte 5 in session ID
* is overridden for full feature session,
* the connection to be selected depends on
* the result of sess_isid[5] devided by the
* next connection ID.
* If MS/T is enabled and there are multiple
* IPs are available on the target, we can
* select different IPs to connect in this
* way.
*/
}
}
return;
}
/*
* If connection is in free state, start
* login. If already logged in, try to
* re-enumerate LUs on the session.
*/
/*
* attempt to login into the first connection in our connection
* list. If this fails, we will try the next connection
* in our list until end of the list.
*/
break;
} else {
}
}
}
/* the target for this session is unreachable */
if (isp->sess_storm_delay == 0) {
isp->sess_storm_delay++;
} else {
} else {
}
}
} else {
isp->sess_storm_delay = 0;
isp->sess_failure_lbolt = 0;
}
} else {
}
}
/*
* iscsi_sess_destroy - Destroys a iscsi session structure
* and de-associates it from the hba.
*/
{
/*
* The first step in tearing down the session
* has to be offlining all the LUNs. This will
* ensure there is no outstanding IO by upper
* level drivers. If this fails then we are
* unable to destroy the session.
*
* Try all luns and continue upon failure
* to remove what is removable before returning
* the last error.
*/
if (!ISCSI_SUCCESS(tmprval)) {
}
}
if (!ISCSI_SUCCESS(rval)) {
return (rval);
}
/* The next step is to logout of the connections. */
if (ISCSI_SUCCESS(rval)) {
/* Succes, Continue processing... */
} else {
/* Failure, Stop processing... */
return (rval);
}
}
/*
* At this point all connections should be in
* a FREE state which will have pushed the session
* to a FREE state.
*/
/* Stop watchdog before destroying connections */
if (isp->sess_wd_thread) {
}
/* Destroy connections */
if (!ISCSI_SUCCESS(rval)) {
return (rval);
}
}
/* Destroy Session ic thread */
}
/* Destroy session task queue */
/* destroy pending and completion queues */
/* Remove session from ihp */
/* session first item in list */
} else {
/*
* search hba list for isp pointing
* to session being removed. Then
* update that sessions next pointer.
*/
break;
}
}
} else {
/* couldn't find session */
}
}
/* Wait for all enum requests complete */
while (isp->sess_enum_result_count > 0) {
}
}
/* Destroy this Sessions Data */
(void) iscsi_sess_kstat_term(isp);
}
return (rval);
}
extern ib_boot_prop_t *iscsiboot_prop;
/*
* static iscsi_sess_set_auth -
*
*/
{
char *init_name;
return (B_FALSE);
}
/* Obtain initiator's name */
return (B_FALSE);
}
/* Zero out the session authentication structure */
(sizeof (iscsi_auth_props_t), KM_SLEEP);
/* Obtain target's authentication settings. */
!= B_TRUE) {
/*
* If no target authentication settings found,
* try to obtain system wide configuration
* (from the initiator).
*/
}
/*
* We do not support system wide bi-directional
* auth flag.
*/
}
(sizeof (iscsi_chap_props_t), KM_SLEEP);
/*
* Initialize the target-side chap name to the session name
* if no chap settings have been saved for the current session.
*/
== B_FALSE) {
chap));
}
/* Obtain initiator's CHAP settings. */
/* No initiator secret defined. */
/* Set authentication method to NONE */
return (B_FALSE);
}
} else {
/* Set authentication method to NONE */
}
/*
* Consider enabling bidirectional authentication only if
* authentication method is not NONE.
*/
/* Enable bi-directional authentication. */
/* Obtain target's CHAP settings. */
== B_TRUE) {
} else {
/*
* No target secret defined.
* RADIUS server should have been enabled.
*/
/* EMPTY */
}
} else {
/* Disable bi-directional authentication */
}
}
}
} else {
/*
* This session is boot session. We will use the CHAP and
* the user name got from the boot property structure instead
* of persistent sotre.
*/
if (iscsiboot_prop == NULL) {
return (B_FALSE);
}
return (B_FALSE);
}
/* CHAP secret */
/*
* If chap name is not set,
* we will use initiator name instead.
*/
} else {
}
/*
* Bidirectional authentication is required.
*/
/*
* If the target's chap name is not set, we will use
* session name instead.
*/
} else {
}
}
}
/* Set up authentication buffers only if configured */
}
return (B_TRUE);
}
/*
* iscsi_sess_reserve_itt - Used to reserve an ITT hash slot
*/
{
return (ISCSI_STATUS_INTERNAL_ERROR);
return (ISCSI_STATUS_SUCCESS);
}
/*
* iscsi_sess_release_scsi_itt - Used to release ITT hash slot
*/
void
{
}
/*
* iscsi_sess_reserve_itt - Used to reserve an ITT hash slot
*/
{
/* If no more slots are open fail reservation */
return (ISCSI_STATUS_ITT_TABLE_FULL);
}
/*
* Keep itt values out of the range used by IDM
*/
/*
* Find the next available slot. Normally its the
* slot pointed to by the session's sess_itt value.
* If this is not true the table has become fragmented.
* Fragmentation can occur during max loads and IOs
* are completed out of order. Defragmentation will
* occur when IO slows down and ITT slots are released.
*/
ISCSI_CMD_TABLE_SIZE] != NULL) {
}
/* reserve slot and update counters */
return (ISCSI_STATUS_SUCCESS);
}
/*
* iscsi_sess_release_itt - Used to release ITT hash slot
*/
void
{
/* release slot and update counters */
}
/*
* iscsi_sess_redrive_io - Used to redrive IO on connections in
* a full feature state.
*/
void
{
icp->conn_state)) {
(void) iscsi_thread_send_wakeup(
}
}
}
/*
* iscsi_sess_state_machine -
*
* 7.3.1 Session State Diagram for an Initiator
*
* Symbolic Names for States:
* Q1: FREE - State on instantiation of after cleanup
* Q3: LOGGED_IN - Waiting for all session events.
* Q4: FAILED - Waiting for session recovery or session cont.
* Q5: IN_FLUSH - A login parameter has changed. We are in the
* process of flushing active, aborting, and
* completed queues. Once flushed the iscsi_ic_thread()
* will drop of drop connections (T14) and reconnect
* to the target with new values.
* Q6: FLUSHED - Active, Aborting and Completed Queues flushed.
* Awaiting reconnect or failure. iscsi_tx/ic_threads
* are still running and might be timing-out IOs.
* State Q3/4 represent the Full Feature Phase operation of the session.
*
* The state diagram is as follows:
*
* ------ (N5/6/7 == NOOP)
* / Q1 \
* +------------------------->\ /<-------------+
* | ---+--- |
* | N5 |N1 |
* | +------+ +-------------+ | |
* | | V V | V |
* | | ----+-- -----+ |
* |N6|N5/7 / Q4 \ / Q3 \(N6 == NOOP) |
* +--+-----\ /----+--->\ /-----+---------+
* | ------- /N1 -+---- | N3|
* | (N7 == NOOP) / N7| ^ N1/3/5| |
* | / | +-------+ |
* | +-------+ / | |
* | | V / v |
* | | ------- -+---- |
* |N6|N6 / Q6 \ N5 / Q5 \ |
* +--+-----\ /<--------\ /-----+---------+
* ------- ------ | N3
* (N7 == NOOP) ^ N1/3/5|
* +-------+
*
* The state transition table is as follows:
*
* +------+------+----+--------+----+
* |Q1 |Q3 |Q4 |Q5 |Q6 |
* -----+------+------+----+--------+----+
* Q1 |N5/6/7|N1 | - | | |
* -----+------+------+----+--------+----+
* Q3 |N3 |N1/3/5|N5 |N7 | |
* -----+------+------+----+--------+----+
* Q4 |N6 |N1 |N5/7| | |
* -----+------+------+----+--------+----+
* Q5 |N3 | | |N1/3/5/7|N6 |
* -----+------+------+----+--------+----+
* Q6 |N6 |N1 |N6/7| | |
* -----+------+------+----+--------+----+
*
* Event definitions:
*
* -N1: A connection logged in
* -N3: A connection logged out
* -N5: A connection failed
* -N6: Session state timeout occurred, or a session
* reinstatement cleared this session instance. This results in
* the freeing of all associated resources and the session state
* is discarded.
* -N7: Login parameters for session have changed.
* Re-negeotation required.
*
* Any caller to the state machine (and so as a state writer) must
* enter the state zone before calling this function, and vice versa
* any caller that doesn't change the state machine shouldn't enter
* the zone, and should act as a reader for a better performance.
*
* The handler of state transition shouldn't try to enter the state
* zone in the same thread or dead lock will occur.
*/
void
{
char *, iscsi_sess_event_str(event));
/* Audit event */
"DEBUG: sess_state: isp: %p state: %d event: %d event count: %d",
switch (isp->sess_state) {
case ISCSI_SESS_STATE_FREE:
break;
break;
case ISCSI_SESS_STATE_FAILED:
break;
break;
case ISCSI_SESS_STATE_FLUSHED:
break;
default:
}
/* Audit state change */
}
}
/*
* iscsi_sess_state_str -
*
*/
char *
{
switch (state) {
case ISCSI_SESS_STATE_FREE:
return ("free");
return ("logged_in");
case ISCSI_SESS_STATE_FAILED:
return ("failed");
return ("in_flush");
case ISCSI_SESS_STATE_FLUSHED:
return ("flushed");
default:
return ("unknown");
}
}
/*
* +--------------------------------------------------------------------+
* | Internal Session Interfaces |
* +--------------------------------------------------------------------+
*/
/*
* iscsi_sess_state_free -
*
*/
static void
{
/* switch on event change */
switch (event) {
/*
* -N1: A connection logged in
*/
case ISCSI_SESS_EVENT_N1:
"!iscsi session(%u) %s online\n",
if (enum_result == ISCSI_SESS_ENUM_SUBMITTED) {
}
if (enum_result != ISCSI_SESS_ENUM_COMPLETE) {
}
}
break;
/*
* -N5: A connection failed
*/
case ISCSI_SESS_EVENT_N5:
/* NOOP - not connected */
break;
/*
* -N6: Session state timeout occurred, or a session
* reinstatement cleared this session instance. This results in
* the freeing of all associated resources and the session state
* is discarded.
*/
case ISCSI_SESS_EVENT_N6:
/* FALLTHRU */
/*
* -N7: Login parameters for session have changed.
* Re-negeotation required.
*/
case ISCSI_SESS_EVENT_N7:
/* NOOP - not connected */
break;
/* All other events are invalid for this state */
default:
}
}
/*
* iscsi_sess_logged_in -
*
*/
static void
{
/* switch on event change */
switch (event) {
/*
* -N1: At least one transport connection reached the
* LOGGED_IN state
*/
case ISCSI_SESS_EVENT_N1:
/*
* A different connection already logged in. If the
* session is NORMAL, just re-enumerate the session.
*/
if (enum_result == ISCSI_SESS_ENUM_SUBMITTED) {
}
if (enum_result != ISCSI_SESS_ENUM_COMPLETE) {
}
}
break;
/*
* -N3: A connection logged out.
*/
case ISCSI_SESS_EVENT_N3:
/* FALLTHRU */
/*
* -N5: A connection failed
*/
case ISCSI_SESS_EVENT_N5:
/*
* MC/S: If this is the last connection to
* fail then move the the failed state.
*/
if (event == ISCSI_SESS_EVENT_N3) {
} else {
}
/* no longer connected reset nego tpgt */
if (event == ISCSI_SESS_EVENT_N3) {
"!iscsi session(%u) %s offline\n",
}
/*
* During the process of offlining the LUNs
* our ic thread might be calling back into
* the driver via a target driver failure
* path to do a reset or something
* we need to release the sess_state_mutex
* while we are killing these threads so
* they don't get deadlocked.
*/
}
/* update busy luns if needed */
break;
/*
* -N6: Session state timeout occurred, or a session
* reinstatement cleared this session instance. This results in
* the freeing of all associated resources and the session state
* is discarded.
*/
case ISCSI_SESS_EVENT_N6:
/* NOOP - Not last connection */
break;
/*
* -N7: Login parameters for session have changed.
* Re-negeotation required.
*/
case ISCSI_SESS_EVENT_N7:
break;
/* All other events are invalid for this state */
default:
}
}
/*
* iscsi_sess_state_failed -
*
*/
static void
{
/* switch on event change */
switch (event) {
/* -N1: A session continuation attempt succeeded */
case ISCSI_SESS_EVENT_N1:
if (enum_result == ISCSI_SESS_ENUM_SUBMITTED) {
}
if (enum_result != ISCSI_SESS_ENUM_COMPLETE) {
}
}
break;
/*
* -N5: A connection failed
*/
case ISCSI_SESS_EVENT_N5:
/* NOOP - not connected */
break;
/*
* -N6: Session state timeout occurred, or a session
* reinstatement cleared this session instance. This results in
* the freeing of all associated resources and the session state
* is discarded.
*/
case ISCSI_SESS_EVENT_N6:
}
break;
/*
* -N7: Login parameters for session have changed.
* Re-negeotation required.
*/
case ISCSI_SESS_EVENT_N7:
/* NOOP - not connected */
break;
/* All other events are invalid for this state */
default:
}
}
/*
* iscsi_sess_state_in_flush -
*
*/
/* ARGSUSED */
static void
{
/* switch on event change */
switch (event) {
/* -N1: A session continuation attempt succeeded */
case ISCSI_SESS_EVENT_N1:
/* NOOP - connections already online */
break;
/*
* -N3: A connection logged out.
*/
case ISCSI_SESS_EVENT_N3:
/* FALLTHRU */
/*
* -N5: A connection failed
*/
case ISCSI_SESS_EVENT_N5:
/*
* MC/S: If this is the last connection to
* fail then move the the failed state.
*/
if (event == ISCSI_SESS_EVENT_N3) {
} else {
}
/* no longer connected reset nego tpgt */
if (event == ISCSI_SESS_EVENT_N3) {
"!iscsi session(%u) %s offline\n",
}
/*
* During the process of offlining the LUNs
* our ic thread might be calling back into
* the driver via a target driver failure
* path to do a reset or something
* we need to release the sess_state_mutex
* while we are killing these threads so
* they don't get deadlocked.
*/
}
/* update busy luns if needed */
break;
/*
* -N6: Session state timeout occurred, or a session
* reinstatement cleared this session instance. This results in
* the freeing of all associated resources and the session state
* is discarded.
*/
case ISCSI_SESS_EVENT_N6:
/* NOOP - Not last connection */
break;
/*
* -N7: Login parameters for session have changed.
* Re-negeotation required.
*/
case ISCSI_SESS_EVENT_N7:
/* NOOP - Already attempting to update */
break;
/* All other events are invalid for this state */
default:
}
}
/*
* iscsi_sess_state_flushed -
*
*/
static void
{
/* switch on event change */
switch (event) {
/* -N1: A session continuation attempt succeeded */
case ISCSI_SESS_EVENT_N1:
if (enum_result == ISCSI_SESS_ENUM_SUBMITTED) {
}
if (enum_result != ISCSI_SESS_ENUM_COMPLETE) {
}
}
break;
/*
* -N6: Session state timeout occurred, or a session
* reinstatement cleared this session instance. This results in
* the freeing of all associated resources and the session state
* is discarded.
*/
case ISCSI_SESS_EVENT_N6:
}
break;
/*
* -N7: Login parameters for session have changed.
* Re-negeotation required.
*/
case ISCSI_SESS_EVENT_N7:
/* NOOP - not connected */
break;
/* All other events are invalid for this state */
default:
}
}
/*
* iscsi_sess_event_str -
*
*/
static char *
{
switch (event) {
case ISCSI_SESS_EVENT_N1:
return ("N1");
case ISCSI_SESS_EVENT_N3:
return ("N3");
case ISCSI_SESS_EVENT_N5:
return ("N5");
case ISCSI_SESS_EVENT_N6:
return ("N6");
case ISCSI_SESS_EVENT_N7:
return ("N7");
default:
return ("unknown");
}
}
/*
* iscsi_sess_thread_create -
*
*/
static iscsi_status_t
{
/* Completion thread creation. */
return (ISCSI_STATUS_INTERNAL_ERROR);
}
return (ISCSI_STATUS_INTERNAL_ERROR);
}
return (ISCSI_STATUS_SUCCESS);
}
/*
* iscsi_sess_enumeration - This function is used to drive the enumeration
* of LUs on a session. It will first prepare the target by sending test
* unit ready commands, then it will issue a report luns. If the report
* luns is successful then it will process all the luns in the report.
* If report luns is not successful we will do a stepping enumeration
* of luns until no more luns are found.
*/
static void
{
/*
* Send initial TEST_UNIT_READY to target. If it fails this we
* stop our enumeration as the target is not responding properly.
*/
if (ISCSI_SUCCESS(rval)) {
/*
* Now we know the target is ready start our enumeration with
* REPORT LUNs, If this fails we will have to fall back to
* stepping
*/
if (!ISCSI_SUCCESS(rval)) {
/*
* report luns failed so lets just check for LUN 0.
* This will match fcp's enumeration support and
* avoid issues with older devices like the A5K that
* respond poorly.
*/
NULL);
}
}
} else {
}
if (isp->sess_enum_result_count != 0) {
} else {
}
}
/*
* iscsi_sess_testunitready - This is used during enumeration to
* ensure an array is ready to be enumerated.
*/
static iscsi_status_t
{
int retries = 0;
/* loop until successful sending test unit ready or retries out */
while ((retries++ < 3) &&
/* cdb is all zeros */
/* setup uscsi cmd */
/* send test unit ready to lun zero on this session */
/*
* If passthru was successful then we were able to
* communicate with the target, continue enumeration.
*/
if (ISCSI_SUCCESS(rval)) {
break;
}
}
return (rval);
}
/*
* iscsi_sess_reportluns - This is used during enumeration to
* ensure an array is ready to be enumerated.
*/
static iscsi_status_t
{
int retries = 0;
/*
* Attempt to send report luns until we successfully
* get all the data or the retries run out.
*/
while ((retries++ < 3) &&
/*
* Allocate our buffer based on current buf_len.
* buf_len may change after we received a response
* from the target.
*/
}
/* setup cdb */
cdb[0] = SCMD_REPORT_LUNS;
/* setup uscsi cmd */
/* send uscsi cmd to lun 0 on session */
/* If passthru successful but not scsi status update istatus */
if (ISCSI_SUCCESS(rval) &&
}
/* If successful, check if we have all the data */
if (ISCSI_SUCCESS(rval)) {
/* total data - header (SCSI_REPORTLUNS_ADDRESS_SIZE) */
if (buf_len >= lun_list_length +
/* we have all the data, were done */
break;
}
/*
* We don't have all the data. free up the
* memory for the next pass and update the
* buf_len
*/
} else {
retries++;
}
}
}
return (rval);
}
/* If not successful go no further */
if (!ISCSI_SUCCESS(rval)) {
return (rval);
}
/*
* find out the number of luns returned by the SCSI ReportLun call
* and allocate buffer space
*/
KM_SLEEP);
/*
* walk the isp->sess_lun_list
* for each lun in this list
* look to see if this lun is in the SCSI ReportLun list we
* just retrieved
* if it is in the SCSI ReportLun list and it is already ONLINE or
* if it is in the SCSI ReportLun list and it is OFFLINE or
* if it isn't in the SCSI ReportLunlist or then
* issue the iscsi_sess_inquiry() to handle
*
* as we walk the SCSI ReportLun list, we save this lun information
* into the buffer we just allocated. This will save us from
* having to figure out this information later
*/
lun_start = 0;
break;
lun_count++) {
/*
* if the first lun in saved_replun_ptr buffer has
* already been found we can move on and do not
* have to check this lun in the future
*/
lun_start++;
continue;
}
/*
* check to see if the lun we are looking for is in the
* saved_replun_ptr buffer
* if it is, process the lun
* if it isn't, then we must go to SCSI
* Report Lun buffer
* we retrieved to get lun info
*/
== B_TRUE) &&
/*
* the lun we are looking for is found,
* give it to iscsi_sess_inquiry()
*/
event_count, ilp);
= B_TRUE;
break;
} else {
/*
* lun information is not found in the
* saved_replun buffer, retrieve lun
* information from the SCSI Report Lun buffer
* and store this information in the
* saved_replun buffer
*/
&lun_num, &lun_addr_type) !=
continue;
}
/*
* lun is found in the SCSI Report Lun
* buffer, give it to inquiry
*/
= B_TRUE;
break;
}
}
}
/*
* this lun we found in the sess->lun_list does
* not exist anymore, need to offline this lun
*/
}
}
/*
* look for new luns that we found in the SCSI Report Lun buffer that
* we did not have in the sess->lun_list and add them into the list
*/
/*
* lun information is not in the
* saved_replun buffer, retrieve
* it from the SCSI Report Lun buffer
*/
continue;
}
} else {
/*
* lun information is in the saved_replun buffer
* if this lun has been found already,
* then we can move on
*/
continue;
}
}
/* New luns found should not conflict with existing luns */
break;
}
}
/* new lun found, add this lun */
event_count, NULL);
} else {
"!Duplicate Lun Number(%d) recieved from "
}
}
}
return (rval);
}
/*
* iscsi_sess_inquiry - Final processing of a LUN before we create a tgt
* mapping, if necessary the old lun will be deleted.
*
* We need to collect the stardard inquiry page and the
* vendor identification page for this LUN. If both of these are
* successful and the identification page contains a NAA or EUI type
* we will continue. Otherwise we fail the creation of a tgt for
* this LUN.
*
* Keep the old lun unchanged if it is online and following things are
* match, lun_addr_type, lun_type, and lun_guid.
*
* are match.
*
* Online a new lun if the old lun is offline and any of those three things
* is not match, and needs to destroy the old first.
*
* and any of those three things is not match, and then online the new lun
*/
static void
{
int retries;
/* easy case, just to create the new lun */
goto sess_inq;
}
goto offline_old;
}
goto sess_inq;
goto inq_done;
}
if (status != ISCSI_STATUS_SUCCESS) {
/* have to abort the process */
goto inq_done;
}
goto sess_inq83;
}
/*
* STANDARD INQUIRY - We need the standard inquiry information
* to feed into the scsi_hba_nodename_compatible_get function.
* This function is used to detemine which driver will bind
* on top of us, via the compatible id.
*/
cdb[0] = SCMD_INQUIRY;
/* Attempt to get inquiry information until successful or retries */
retries = 0;
while ((retries++ < ISCSI_MAX_INQUIRY_RETRIES) &&
/* issue passthru */
/* If we were successful but scsi stat failed update istatus */
if (ISCSI_SUCCESS(rval) &&
}
/* If successful break */
if (ISCSI_SUCCESS(rval)) {
break;
}
/* loop until we are successful or retries run out */
}
/* If failed don't continue */
if (!ISCSI_SUCCESS(rval)) {
"logical unit - inquiry failed lun %d",
goto inq_done;
}
/*
* T-10 SPC Section 6.4.2. Standard INQUIRY Peripheral
* qualifier of 000b is the only type we should attempt
* to plumb under the IO stack.
*/
/* shouldn't enumerate, destroy the old one if exists */
goto offline_old;
}
goto inq_done;
}
/*
* If lun type has changed
*/
goto offline_old;
}
if (inq83_ready == B_TRUE) {
goto guid_ready;
}
/*
* VENDOR IDENTIFICATION INQUIRY - This will be used to identify
* a unique lunId. This Id is passed to the mdi alloc calls so
*/
cdb[0] = SCMD_INQUIRY;
/* Attempt to get inquiry information until successful or retries */
retries = 0;
while ((retries++ < ISCSI_MAX_INQUIRY_RETRIES) &&
/* issue passthru command */
/* If we were successful but scsi stat failed update istatus */
if (ISCSI_SUCCESS(rval) &&
}
/* Break if successful */
if (ISCSI_SUCCESS(rval)) {
break;
}
}
/*
* If we were successful collecting page 83 data attempt
* to generate a GUID. If no GUID can be generated then
* the logical unit will skip attempt to plumb under
*/
if (ISCSI_SUCCESS(rval)) {
/* create DEVID from inquiry data */
DDI_SUCCESS) {
/* extract GUID from DEVID */
/* devid no longer needed */
}
}
}
}
goto offline_old;
}
}
}
} else {
}
}
/* guid is no longer needed */
}
/* free up memory now that we are done */
}
static iscsi_status_t
{
/* determine report luns addressing type */
/*
* Vendors in the field have been found to be concatenating
* of switching to flat space addressing
*/
/* 00b - peripheral device addressing method */
/* FALLTHRU */
/* 10b - logical unit addressing method */
/* FALLTHRU */
/* 01b - flat space addressing method */
/* byte0 bit0-5=msb lun byte1 bit0-7=lsb lun */
SCSI_REPORTLUNS_ADDRESS_MASK) >> 6;
return (ISCSI_STATUS_SUCCESS);
default: /* protocol error */
"to enumerate logical units - report "
"luns returned an unsupported format",
break;
}
return (ISCSI_STATUS_INTERNAL_ERROR);
}
/*
* iscsi_sess_flush - flushes remaining pending io on the session
*/
static void
{
/*
* Flush out any remaining commands in the pending
* queue.
*/
}
}
}
}
/*
* iscsi_sess_offline_luns - offline all this sessions luns
*/
static void
{
}
}
/*
* iscsi_sess_get_by_target - return the session structure for based on a
* passed in target oid and hba instance. NOTE: There may be
* multiple sessions associated with any given target. In this case,
* we will return the first matching session. This function
* is intended to be used in retrieving target info that is constant
* across sessions (target name, alias, etc.).
*/
int
iscsi_sess_t **ispp)
{
int rval = 0;
/* See if we already created this session */
/*
* Look for a session associated to the given target.
* Return the first one found.
*/
/* Found matching session */
break;
}
}
/* If not null this session is already available */
/* Existing session, return it */
} else {
}
return (rval);
}
static void
{
} else {
}
}
}
/*
* Submits the scsi enumeration request. Returns
* ISCSI_SESS_ENUM_SUBMITTED upon success, or others if failures are met.
* If the request is submitted and the wait is set to B_TRUE, the caller
* must call iscsi_sess_enum_query at a later time to unblock next enum
*/
}
/* easy case */
}
return (ISCSI_SESS_ENUM_SUBMITTED);
}
return (ISCSI_SESS_ENUM_SUBFAIL);
}
}
return (ISCSI_SESS_ENUM_SUBMITTED);
}
/*
* Wait and query the result of the enumeration.
* The last caller is responsible for kicking off the DONE status
*/
}
if (isp->sess_enum_result_count == 0) {
}
return (ret);
}
static void
}
void
}
}
void
}