/*
* 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
*/
/*
* Copyright 2000 by Cisco Systems, Inc. All rights reserved.
*
* iSCSI Software Initiator
*/
/*
* Framework interface routines for iSCSI
*/
#include "iscsi.h" /* main header */
#include "iscsi_targetparam.h"
#include "persistent.h"
#include "isns_client.h"
#include "isns_protocol.h"
#include <sys/bootprops.h>
#include <sys/bootconf.h>
/*
* +--------------------------------------------------------------------+
* | iscsi globals |
* +--------------------------------------------------------------------+
*/
void *iscsi_state;
extern ib_boot_prop_t *iscsiboot_prop;
extern int modrootloaded;
/*
* +--------------------------------------------------------------------+
* | iscsi.c prototypes |
* +--------------------------------------------------------------------+
*/
/* scsi_tran prototypes */
/* bus_ops prototypes */
/* LINTED E_STATIC_UNUSED */
/* LINTED E_STATIC_UNUSED */
/* LINTED E_STATIC_UNUSED */
/* LINTED E_STATIC_UNUSED */
/* cb_ops prototypes */
/* scsi_tran helpers */
/* iscsi initiator service helpers */
/* struct helpers prototypes */
/*
* At this point this driver doesn't need this structure because nothing
* is done during the open, close or ioctl. Code put in place because
* some admin related work might be done in the ioctl routine.
*/
iscsi_open, /* open */
iscsi_close, /* close */
nodev, /* strategy */
nodev, /* print */
nodev, /* dump */
nodev, /* read */
nodev, /* write */
iscsi_ioctl, /* ioctl */
nodev, /* devmap */
nodev, /* mmap */
nodev, /* segmap */
nochpoll, /* poll */
ddi_prop_op, /* prop_op */
NULL, /* streamtab */
CB_REV, /* cb_rev */
nodev, /* aread */
nodev, /* awrite */
};
DEVO_REV, /* devo_rev */
0, /* refcnt */
iscsi_getinfo, /* getinfo */
nulldev, /* identify */
nulldev, /* probe */
iscsi_attach, /* attach */
iscsi_detach, /* detach */
nodev, /* reset */
&iscsi_cb_ops, /* driver operations */
NULL, /* bus ops */
NULL, /* power management */
ddi_quiesce_not_needed, /* quiesce */
};
&mod_driverops, /* drv_modops */
ISCSI_NAME_VERSION, /* drv_linkinfo */
&iscsi_dev_ops /* drv_dev_ops */
};
MODREV_1, /* ml_rev */
&modldrv, /* ml_linkage[] */
NULL /* NULL termination */
};
/*
* This structure is bogus. scsi_hba_attach_setup() requires, as in the kernel
* will panic if you don't pass this in to the routine, this information.
* Need to determine what the actual impact to the system is by providing
* this information if any. Since dma allocation is done in pkt_init it may
* not have any impact. These values are straight from the Writing Device
* Driver manual.
*/
DMA_ATTR_V0, /* ddi_dma_attr version */
0, /* low address */
0xffffffff, /* high address */
0x00ffffff, /* counter upper bound */
1, /* alignment requirements */
0x3f, /* burst sizes */
1, /* minimum DMA access */
0xffffffff, /* maximum DMA access */
(1 << 24) - 1, /* segment boundary restrictions */
512, /* device granularity */
0 /* DMA flags */
};
/*
* _init - General driver init entry
*/
int
_init(void)
{
int rval = 0;
/*
* Set up the soft state structures. If this driver is actually
* being attached to the system then we'll have at least one
*/
sizeof (iscsi_hba_t), 1);
if (rval != 0) {
goto init_done;
}
if (rval != 0) {
goto init_done;
}
if (rval != 0) {
goto init_done;
}
(void) iscsi_door_ini();
return (rval);
}
/*
* _fini - General driver destructor entry
*/
int
_fini(void)
{
int rval = 0;
if (rval == 0) {
(void) iscsi_door_term();
}
return (rval);
}
/*
* _info - General driver info entry
*/
int
{
int rval = 0;
return (rval);
}
/*
* +--------------------------------------------------------------------+
* | Start of dev_ops routines |
* +--------------------------------------------------------------------+
*/
/*
* iscsi_getinfo - returns general driver information
*/
/* ARGSUSED */
static int
{
switch (infocmd) {
case DDI_INFO_DEVT2DEVINFO:
return (DDI_FAILURE);
}
rval = DDI_FAILURE;
else
rval = DDI_SUCCESS;
break;
case DDI_INFO_DEVT2INSTANCE:
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
{
switch (cmd) {
case DDI_ATTACH:
/* create iSCSH HBA devctl device node */
DDI_PSEUDO, 0) == DDI_SUCCESS) {
/* allocate HBA soft state */
DDI_SUCCESS) {
rval = DDI_FAILURE;
break;
}
/* get reference to soft state */
rval = DDI_FAILURE;
break;
}
/* init HBA mutex used to protect discovery events */
MUTEX_DRIVER, NULL);
/* Get LDI ident */
/* init HBA mutex used to protect service status */
MUTEX_DRIVER, NULL);
/*
* init SendTargets semaphore that is used to allow
* only one operation at a time
*/
SEMA_DRIVER, NULL);
/* allocate scsi_hba_tran */
== NULL) {
goto iscsi_attach_failed2;
}
/* soft state setup */
if (iscsiboot_prop == NULL) {
} else {
}
ihp->hba_service_client_count = 0;
ihp->hba_name_length = 0;
ihp->hba_alias_length = 0;
0, "tcp-conn-abort-threshold",
"tcp-abort-threshold",
"config-storm-delay",
"tcp-conn-notify-threshold",
"tcp-conn-abort-threshold",
"tcp-abort-threshold",
"config-storm-delay",
/* setup hba defaults */
/* setup minimal initiator params */
/* hba set up */
/* register scsi hba with scsa */
goto iscsi_attach_failed1;
}
MDI_SUCCESS) {
} else {
}
(void) iscsi_hba_kstat_init(ihp);
/* Initialize targetparam list */
/* Initialize ISID */
/* Setup iSNS transport services and client */
/*
* initialize persistent store,
* or boot target info in case of iscsi boot
*/
goto iscsi_attach_failed0;
}
/* Setup init_port_name for MPAPI */
"%s,%02x%02x%02x%02x%02x%02x",
" property on iSCSI "
"HBA(%s) with dip(%d) Failed",
}
} else {
rval = DDI_FAILURE;
}
break;
(void) iscsi_hba_kstat_term(ihp);
}
(void) mdi_phci_unregister(dip, 0);
}
rval = DDI_FAILURE;
break;
case DDI_RESUME:
break;
default:
rval = DDI_FAILURE;
}
if (rval != DDI_SUCCESS) {
"hba instance %d", instance);
}
return (rval);
}
/*
* iscsi_detach - called on unload of hba instance
*/
static int
{
int instance;
char *init_node_name;
switch (cmd) {
case DDI_DETACH:
rval = DDI_SUCCESS;
break;
}
rval = DDI_FAILURE;
break;
}
/*
* Validate that what is stored by the DDI framework is still
* the same state structure referenced by the SCSI framework
*/
rval = DDI_FAILURE;
break;
}
/* If a session exists we can't safely detach */
rval = DDI_FAILURE;
break;
}
/* Disable all discovery services */
/* Disable failed. Fail detach */
rval = DDI_FAILURE;
break;
}
/* Deregister from iSNS server(s). */
ISCSI_MAX_NAME_LEN) == B_TRUE) {
if (strlen(init_node_name) > 0) {
(uint8_t *)init_node_name);
}
}
/* Cleanup iSNS Client */
/* Cleanup iscsid resources */
iscsid_fini();
if (rval != DDI_SUCCESS) {
break;
}
/* kstat hba. destroy */
(void) mdi_phci_unregister(dip, 0);
}
(void) iscsi_hba_kstat_term(ihp);
(void) scsi_hba_detach(dip);
}
break;
default:
break;
}
if (rval != DDI_SUCCESS) {
"detach hba instance %d", instance);
}
return (rval);
}
/*
* +--------------------------------------------------------------------+
* | End of dev_ops routines |
* +--------------------------------------------------------------------+
*/
/*
* +--------------------------------------------------------------------+
* | scsi_tran(9E) routines |
* +--------------------------------------------------------------------+
*/
/*
* iscsi_tran_lun_init - Find target device based on SCSI device
* Based on the information given (SCSI device, target dev_info) find
* the target iSCSI device and put a pointer to that information in
* the scsi_hba_tran_t structure.
*/
static int
{
int rval = 0;
int type = 0;
/*
* Child node is getting initialized. Look at the mpxio component
* type on the child device to see if this device is mpxio managed
* or not.
*/
if (type != MDI_COMPONENT_CLIENT) {
} else {
}
return (rval);
}
/*
* iscsi_tran_lun_probe - This function didn't need to be implemented.
* We could have left NULL in the tran table. Since this isn't a
* performance path this seems safe. We are just wrappering the
* function so we can see the call go through if we have debugging
* enabled.
*/
static int
{
int rval = 0;
return (rval);
}
/*
* iscsi_init_pkt - Allocate SCSI packet and fill in required info.
*/
/* ARGSUSED */
static struct scsi_pkt *
{
/*
* The software stack doesn't have DMA which means the iSCSI
* protocol layer will be doing a bcopy from bp to outgoing
* streams buffers. Make sure that the buffer is mapped in
* so that the copy won't panic the system.
*/
return (NULL);
}
return (NULL);
}
/* add the report lun addressing type on to the lun */
icmdp->cmd_misc_flags = 0;
}
pkt->pkt_statistics = 0;
pkt->pkt_reason = 0;
}
return (pkt);
}
/*
* iscsi_tran_lun_free - Free a SCSI LUN
*/
static void
{
}
/*
* iscsi_start -- Start a SCSI transaction based on the packet
* This will attempt to add the icmdp to the pending queue
* for the connection and kick the queue. If the enqueue
* fails that means the queue is full.
*/
static int
{
/*
* If the session is in the FREE state then
* all connections are down and retries have
* been exhausted. Fail command with fatal error.
*/
return (TRAN_FATAL_ERROR);
}
/*
* If we haven't received data from the target in the
* max specified period something is wrong with the
* transport. Fail IO with FATAL_ERROR.
*/
ddi_get_lbolt()) {
return (TRAN_FATAL_ERROR);
}
/*
* If the session is not in LOGGED_IN then we have
* no connections LOGGED_IN, but we haven't exhuasted
* our retries. Fail the command with busy so the
* caller might try again later. Once retries are
* exhausted the state machine will move us to FREE.
*/
return (TRAN_BUSY);
}
/*
* If we haven't received data from the target in the
* specified period something is probably wrong with
* the transport. Just return back BUSY until either
* the problem is resolved of the transport fails.
*/
ddi_get_lbolt()) {
return (TRAN_BUSY);
}
/* reset cmd values in case upper level driver is retrying cmd */
/*
* If this packet doesn't have FLAG_NOINTR set, it could have
* already run to completion (and the memory freed) at this
* point, so check our local copy of pkt_flags. Otherwise we
* have to wait for completion before returning to the caller.
*/
if (flags & FLAG_NOINTR) {
}
}
return (TRAN_ACCEPT);
}
/*
* iscsi_tran_abort - Called when an upper level application
* or driver wants to kill a scsi_pkt that was already sent to
* this driver.
*/
/* ARGSUSED */
static int
{
return (0);
}
/*
* iscsi_tran_reset - Reset target at either BUS, TARGET, or LUN
* level. This will require the issuing of a task management
*/
static int
{
switch (level) {
case RESET_LUN:
/* reset attempt will block until attempt is complete */
break;
case RESET_BUS:
/*
* What are we going to realy reset the ethernet
* network!? Just fall through to a target reset.
*/
case RESET_TARGET:
/* reset attempt will block until attempt is complete */
break;
case RESET_ALL:
default:
break;
}
}
/*
*/
static int
{
}
/*
*/
/* ARGSUSED */
static int
{
}
/*
* iscsi_tran_destroy_pkt - Clean up packet
*/
static void
{
}
/*
* iscsi_tran_dmafree - This is a software driver, NO DMA
*/
/* ARGSUSED */
static void
{
/*
* The iSCSI interface doesn't deal with DMA
*/
}
/*
* iscsi_tran_sync_pkt - This is a software driver, NO DMA
*/
/* ARGSUSED */
static void
{
/*
* The iSCSI interface doesn't deal with DMA
*/
}
/*
* iscsi_tran_reset_notify - We don't support BUS_RESET so there
* is no point in support callback.
*/
/* ARGSUSED */
static int
{
/*
* We never do BUS_RESETS so allowing this call
* back to register has no point?
*/
return (DDI_SUCCESS);
}
/*
* iscsi_tran_bus_config - on demand device configuration
*
* iscsi_tran_bus_config is called by the NDI layer at the completion
* of a dev_node creation. There are two primary cases defined in this
* function. The first is BUS_CONFIG_ALL. In this case the NDI is trying
* in time. It is safe to just complete the process succcessfully. The
* second case is a new case that was defined in S10 for devfs. BUS_CONFIG_ONE
* this is to help driver the top down discovery instead of bottom up. If
* we receive a BUS_CONFIG_ONE we should check to see if the <addr> exists
* if so complete successfull processing. Otherwise we should call the
* deamon and see if we can plumb the <addr>. If it is possible to plumb the
* <addr> block until plumbing is complete. In both cases of being able to
* plumb <addr> or not continue with successfull processing.
*/
static int
{
/* get reference to soft state */
return (NDI_FAILURE);
}
}
if (config_root == B_FALSE) {
return (NDI_FAILURE);
}
}
/* lock so only one config operation occrs */
switch (op) {
case BUS_CONFIG_ONE:
/* parse target name out of name given */
rval = NDI_FAILURE;
break;
}
ptr++; /* move past '@' */
/* We need to strip the LUN */
rval = NDI_FAILURE;
break;
}
/* We also need to strip the 4 bytes of hex TPGT */
ptr -= 4;
rval = NDI_FAILURE;
break;
}
/* translate name back to original iSCSI name */
/* configure target, skip 4 byte ISID */
/*
* DDI group instructed us to use this flag.
*/
break;
case BUS_CONFIG_DRIVER:
/* FALLTHRU */
case BUS_CONFIG_ALL:
break;
default:
rval = NDI_FAILURE;
break;
}
if (rval == NDI_SUCCESS) {
}
if (config_root == B_FALSE) {
}
return (rval);
}
/*
* iscsi_tran_bus_unconfig - on demand device unconfiguration
*
* Called by the os framework under low resource situations.
* It will attempt to unload our minor nodes (logical units
*/
static int
{
/* get reference to soft state */
return (NDI_FAILURE);
}
rval = NDI_FAILURE;
}
return (rval);
}
return (rval);
}
/*
* iscsi_tran_get_name - create private /devices name for LUN
*
* path. For this <addr> we return the <session/target_name>,<lun num>
* specification. We do modify the name slightly so that it still
* complies with the IEEE <addr> naming scheme. This means that we
* will substitute out the ':', '@', ... and other reserved characters
* defined in the IEEE definition with '%<hex value of special char>'
* This routine is indirectly called by iscsi_lun_create_xxx. These
* calling routines must prevent the session and lun lists from changing
* during this routine.
*/
static int
{
int target = 0;
int lun = 0;
/* get reference to soft state */
name[0] = '\0';
return (0);
}
/* Get the target num */
DDI_PROP_DONTPASS, TARGET_PROP, 0);
/* Get the target num */
DDI_PROP_DONTPASS, LUN_PROP, 0);
/*
* Now we need to find our ilp by walking the lists
* off the ihp and isp.
*/
/* See if we already created this session */
/* Walk the HBA's session list */
/* compare target name as the unique identifier */
/* found match */
break;
}
}
/* If we found matching session continue searching for tgt */
/* sess not found */
name[0] = '\0';
return (0);
}
/*
* Search for the matching iscsi lun structure. We don't
* need to hold the READER for the lun list at this point.
* because the tran_get_name is being called from the online
* function which is already holding a reader on the lun
* list.
*/
/* found match */
break;
}
}
/* tgt not found */
name[0] = '\0';
return (0);
}
/* Ensure enough space for lun_addr is available */
return (0);
}
/* copy lun_addr name */
/*
* Based on IEEE-1275 we can't have any ':', ' ', '@', or '/'
* characters in our naming. So replace all those characters
* with '-'
*/
return (1);
}
/*
* iscsi_tran_get_bus_addr - This returns a human readable string
* for the bus address. Examining most other drivers fcp, etc. They
* all just return the same string as tran_get_name. In our case
* our tran get name is already some what usable so leave alone.
*/
static int
{
}
/*
* +--------------------------------------------------------------------+
* | End of scsi_tran routines |
* +--------------------------------------------------------------------+
*/
/*
* +--------------------------------------------------------------------+
* | Start of cb_ops routines |
* +--------------------------------------------------------------------+
*/
/*
* iscsi_open - Driver should be made IOCTL MT safe. Otherwise
* this function needs updated.
*/
/* ARGSUSED */
static int
{
return (0);
}
/*
* iscsi_close -
*/
/* ARGSUSED */
static int
{
return (0);
}
/*
* iscsi_ioctl -
*/
/* ARGSUSED */
static int
{
int rtn = 0;
int instance = 0;
int list_space = 0;
int lun_sz = 0;
int did;
int retry;
entry_t e;
#ifdef _MULTI_DATAMODEL
/* For use when a 32 bit app makes a call into a 64 bit ioctl */
#endif /* _MULTI_DATAMODEL */
void *void_p;
int stl_sz;
char *initiator_node_name;
char *initiator_node_alias;
int size;
return (EFAULT);
(cmd != ISCSI_SMF_GET)) {
/* other cmd needs to acquire the service */
return (EFAULT);
}
}
switch (cmd) {
/*
* ISCSI_CREATE_OID - Create a Object IDentifier for a TargetName
*/
case ISCSI_CREATE_OID:
break;
}
break;
}
/* Set the target that this session is associated with */
break;
}
break;
/*
* ISCSI_PARAM_GET - Get param for specified
*/
case ISCSI_PARAM_GET:
/* copyin user args */
break;
}
break;
}
/* handle special case for Initiator name */
if (ihp->hba_alias_length == 0) {
} else {
}
} else {
/* To describe the validity of the requested param */
/*
* switch login based if looking for initiator
* params
*/
/* initiator */
}
} else {
/*
* If the oid does represent a session check
* to see if it is a target oid. If so,
* return the target's associated session.
*/
if (rtn != 0) {
}
/*
* If rtn is zero then we have found an
* existing session. Use the session name to
* do param lookup. If rtn is non-zero then
* create a targetparam object and use its name
* for param lookup.
*/
if (rtn == 0) {
} else {
name =
if (ilg->g_param_type ==
sizeof (*tmpParams),
KM_SLEEP);
}
rtn = 0;
}
sizeof (*tmpParams));
break;
}
/* session */
/*
* Update sess_params with the
* latest params from the
* persistent store.
*/
/*
* If the parameter in
* question is not
* overriden, no effect
* on existing session
* parameters. However,
* the parameter is
* marked invalid
* (from the standpoint
* of whether it is
* overriden).
*/
}
} else if (ilg->g_param_type ==
/* connection */
/* Assuming 1 conn per sess. */
/*
* MC/S - Need to be modified to
* take g_conn_cid into account when
* we go multi-connection.
*/
} else {
}
}
}
/* make sure we have params to get info from */
if (params) {
/*
* for target parameters, check if any
* parameters were overridden at the initiator
* level. If so, then change the default value
* to the initiator's overridden value
*/
if ((rtn == 0) &&
ilg);
}
}
}
if (rtn == 0) {
sizeof (iscsi_param_get_t), mode);
}
break;
/*
* ISCSI_INIT_NODE_NAME_SET - Change the initiator-node name for
* the specified connection/session.
*/
case ISCSI_INIT_NODE_NAME_SET:
/* copyin user args */
break;
}
break;
}
/* saving off the old initiator-node name */
if (rtn != 0) {
break;
}
"%s,%02x%02x%02x%02x%02x%02x",
init_port_name) != DDI_PROP_SUCCESS) {
SCSI_ADDR_PROP_INITIATOR_PORT " property on iSCSI "
"HBA(%s) with dip(%d) Failed",
}
/*
* Deregister the old initiator-node name from the iSNS
* server
* Register the new initiator-node name with the iSNS server
*/
if (method & iSCSIDiscoveryMethodISNS) {
if (strlen(initiator_node_name) > 0) {
/*
* we will attempt to offline the targets.
* if logouts fail, we will still continue
*/
if ((iscsid_del(
!= B_TRUE) {
"Attempting to change "
}
}
}
ISCSI_MAX_NAME_LEN) != B_TRUE) {
break;
}
if (strlen(initiator_node_name) == 0) {
break;
}
KM_SLEEP);
ISCSI_MAX_NAME_LEN) != B_TRUE) {
initiator_node_alias[0] = '\0';
}
}
break;
/*
* ISCSI_PARAM_SET - Set param for specified connection/session.
*/
case ISCSI_PARAM_SET:
/* copyin user args */
break;
}
break;
}
if (iscsiboot_prop) {
/*
* found active session for this object
* or this is initiator's object
* with mpxio enabled
*/
if (!iscsi_reconfig_boot_sess(ihp)) {
break;
}
}
}
break;
/*
* ISCSI_TARGET_PARAM_CLEAR
* - remove custom parameter settings for a target.
*/
case ISCSI_TARGET_PARAM_CLEAR:
break;
} else if (e.e_vers != ISCSI_INTERFACE_VERSION) {
break;
}
(e.e_oid != ISCSI_OID_NOTSET)) {
/*
* If the oid does represent a session check to see
* if it is a target oid. If so, return the target's
* associated session.
*/
if (rtn != 0) {
&isp);
}
/*
* If rtn is zero then we have found an
* existing session. Use the session name to
* do param lookup. If rtn is non-zero then
* create a targetparam object and use its name
* for param lookup.
*/
if (rtn == 0) {
} else {
rtn = 0;
}
break;
}
&t_ics);
&t_tpsg);
/* no any target parameters get */
break;
}
break;
}
/*
* We may have multiple sessions with different
* tpgt values. So we need to loop through
* the sessions and update all sessions.
*/
(char *)name, ISCSI_MAX_NAME_LEN) == 0) {
/*
* When removing target-params we need
* slightly different actions depending
* on if the session should still exist.
* Get the initiator-node value for
* MS/T. If there is no initiator
* value then assume the default value
* of 1. If the initiator value is
* less than this ISID then we need to
* destroy the session. Otherwise
* update the session information and
* resync (N7 event).
*/
if (((rtn != 0) &&
((rtn == 0) &&
/*
* This session should no
* longer exist. Remove
* session.
*/
if (!ISCSI_SUCCESS(
iscsi_sess_destroy(isp))) {
continue;
}
} else {
/*
* Reset the session
* parameters.
*/
&(isp->sess_params),
sizeof (isp->sess_params));
if (iscsiboot_prop &&
/*
* reconfig boot
* session later
*/
continue;
}
/*
* Notify the session that the
* login parameters have
* changed.
*/
&isp->
isp);
isp);
}
}
}
/* Failure!, restore target's parameters */
}
}
}
}
}
}
"target's parameters after remove "
"session related to target "
"parameters failure.");
}
}
if (iscsiboot_prop) {
/*
* found active session for this object
* or this is initiator object
* with mpxio enabled
*/
if (!iscsi_reconfig_boot_sess(ihp)) {
break;
}
}
}
}
break;
/*
* ISCSI_TARGET_OID_LIST_GET -
*/
/* copyin user args */
break;
}
break;
}
list_space = sizeof (iscsi_target_list_t);
list_space += (sizeof (uint32_t) *
idlp->tl_out_cnt = 0;
/*
* If target list type is ISCSI_TGT_OID_LIST and discovery
* has not been completed or in progress, poke the discovery
* methods so target information is returned
*/
(method != ISCSI_ALL_DISCOVERY_METHODS) &&
}
/*
* Return the correct list information based on the type
*/
switch (idl.tl_tgt_list_type) {
/* ISCSI_TGT_PARAM_OID_LIST - iscsiadm list target-params */
case ISCSI_TGT_PARAM_OID_LIST:
/* get params from persistent store */
while (curr_entry != NULL) {
}
idlp->tl_out_cnt++;
}
break;
/* ISCSI_STATIC_TGT_OID_LIST - iscsiadm list static-config */
{
void *v = NULL;
/* get static-config from persistent store */
while (persistent_static_addr_next(&v,
(char *)target_name, &e) == B_TRUE) {
e.e_oid;
}
idlp->tl_out_cnt++;
}
break;
}
/* ISCSI_TGT_OID_LIST - iscsiadm list target */
case ISCSI_TGT_OID_LIST:
/* get sessions from hba's session list */
if (((isp->sess_state !=
(isp->sess_discovered_by !=
if (idlp->tl_out_cnt <
idlp->tl_out_cnt] =
}
idlp->tl_out_cnt++;
}
}
break;
default:
}
break;
/*
* ISCSI_TARGET_PROPS_GET -
*/
case ISCSI_TARGET_PROPS_GET:
/* ---- fall through sense the code is almost the same ---- */
/*
* ISCSI_TARGET_PROPS_SET -
*/
case ISCSI_TARGET_PROPS_SET:
/* copyin user args */
KM_SLEEP);
break;
}
break;
}
if (rtn == 0)
break;
/*
* ISCSI_TARGET_ADDRESS_GET -
*/
case ISCSI_TARGET_ADDRESS_GET:
break;
}
break;
}
/*
* Find out how much space we need to malloc for the users
* request.
*/
list_space = sizeof (iscsi_addr_list_t);
list_space += (sizeof (iscsi_addr_t) *
}
/* Copy in the header portion */
/* session */
if (rtn != 0) {
break;
}
ialp->al_out_cnt = 0;
continue;
}
== AF_INET) {
(struct sockaddr_in *)&icp->
sizeof (struct in_addr);
sizeof (struct in_addr));
} else {
(struct sockaddr_in6 *)&icp->
sizeof (struct in6_addr);
sizeof (struct in6_addr));
}
}
ialp->al_out_cnt++;
}
break;
/*
* ISCSI_CHAP_SET -
*/
case ISCSI_CHAP_SET:
KM_SLEEP);
break;
break;
}
else {
if (rtn != 0) {
}
/*
* If rtn is zero then we have found an
* existing session. Use the session name to
* do param lookup. If rtn is non-zero then
* create a targetparam object and use its name
* for param lookup.
*/
if (rtn == 0) {
} else {
name =
rtn = 0;
}
}
break;
}
B_FALSE) {
}
break;
/*
* ISCSI_CHAP_GET -
*/
case ISCSI_CHAP_GET:
KM_SLEEP);
break;
break;
}
else {
if (rtn != 0) {
}
/*
* If rtn is zero then we have found an
* existing session. Use the session name to
* do param lookup. If rtn is non-zero then
* create a targetparam object and use its name
* for param lookup.
*/
if (rtn == 0) {
} else {
rtn = 0;
name =
}
break;
}
/*
* Initialize the target-side chap name to the
* session name if no chap settings have been
* saved for the current session.
*/
if (persistent_chap_get((char *)name,
(sizeof (iscsi_chap_props_t), KM_SLEEP);
(void) (persistent_chap_set((char *)name,
chap));
}
}
break;
}
break;
}
break;
/*
* ISCSI_CHAP_CLEAR -
*/
case ISCSI_CHAP_CLEAR:
KM_SLEEP);
break;
break;
}
}
/*
* Loop through all sessions and memset their
* (initiator's) passwords
*/
}
} else {
/*
* If the oid does represent a session check to see
* if it is a target oid. If so, return the target's
* associated session.
*/
if (rtn != 0) {
}
/*
* If rtn is zero then we have found an
* existing session. Use the session name to
* do param lookup. If rtn is non-zero then
* create a targetparam object and use its name
* for param lookup.
*/
if (rtn == 0) {
} else {
name =
rtn = 0;
}
break;
}
}
/*
* Clear out session chap password if we found a
* session above.
*/
}
}
break;
/*
* ISCSI_STATIC_GET -
*/
case ISCSI_STATIC_GET:
break;
}
break;
}
{
void *v = NULL;
while (persistent_static_addr_next(&v,
/*
* In case there are multiple
* addresses associated with the
* given target OID, pick the first
* one.
*/
e.e_insize);
ispp->p_name_len =
break;
}
}
} else {
}
}
break;
/*
* ISCSI_STATIC_SET -
*/
case ISCSI_STATIC_SET:
sizeof (*target));
break;
}
break;
}
/* Check if the target's already been added */
{
void *v = NULL;
while (persistent_static_addr_next(&v, (char *)name,
&e) == B_TRUE) {
/*
* MC/S - Need to check IP address and port
* number as well when we support MC/S.
*/
ISCSI_MAX_NAME_LEN) == 0) &&
e.e_insize) == 0)) {
/*
* We don't allow MC/S for now but
* we do allow adding the same target
* with different TPGTs (hence,
* different sessions).
*/
break;
}
}
if (static_target_found == B_TRUE) {
/* Duplicate entry */
break;
}
}
}
break;
}
/*
* If Static Targets discovery is enabled, then add
* target to discovery queue. Otherwise, just create
* the session for potential future use.
*/
if (method & iSCSIDiscoveryMethodStatic) {
}
break;
/*
* ISCSI_STATIC_CLEAR -
*/
case ISCSI_STATIC_CLEAR:
break;
} else if (e.e_vers != ISCSI_INTERFACE_VERSION) {
break;
}
{
void *v = NULL;
/* Find name for matching static_tgt oid */
while (persistent_static_addr_next(&v,
break;
}
}
/* If static_tgt found logout and remove it */
/*
* If discovery in progress, try few times
* before return busy
*/
retry = 0;
while (ihp->hba_discovery_in_progress ==
B_TRUE) {
if (++retry == 5) {
break;
}
}
/* remove from persistent store */
if (rtn == 0 && persistent_static_addr_clear(
}
if (rtn != 0) {
break;
}
/* Attempt to logout of target */
== B_FALSE) {
/*
* Restore static_tgt to
* persistent store
*/
(char *)name,
"restore static target "
"address after logout "
"target failure.");
}
} else {
(void) iscsid_login_tgt(ihp,
(char *)name,
NULL);
}
} else {
}
}
break;
/*
* ISCSI_ISNS_SERVER_ADDR_SET:
*/
break;
} else if (e.e_vers != ISCSI_INTERFACE_VERSION) {
break;
}
if (persistent_isns_addr_set(&e) == B_FALSE) {
break;
}
/*
* If iSNS server discovery is enabled, then kickoff
* discovery of the targets advertised by the recently
* added iSNS server address.
*/
if (method & iSCSIDiscoveryMethodISNS) {
KM_SLEEP);
ISCSI_MAX_NAME_LEN) != B_TRUE) {
break;
}
if (strlen(initiator_node_name) == 0) {
break;
}
KM_SLEEP);
ISCSI_MAX_NAME_LEN) != B_TRUE) {
initiator_node_alias[0] = '\0';
}
/*
* Register this initiator node against this iSNS
* server.
*/
/* Done using the name and alias - free them. */
}
break;
/*
* ISCSI_DISCOVERY_ADDR_SET:
*/
case ISCSI_DISCOVERY_ADDR_SET:
break;
} else if (e.e_vers != ISCSI_INTERFACE_VERSION) {
break;
}
if (e.e_oid == ISCSI_OID_NOTSET) {
}
if (persistent_disc_addr_set(&e) == B_FALSE) {
break;
}
/*
* If Send Targets discovery is enabled, then kickoff
* discovery of the targets advertised by the recently
* added discovery address.
*/
if (method & iSCSIDiscoveryMethodSendTargets) {
iscsid_do_sendtgts(&e);
}
break;
/*
* ISCSI_DISCOVERY_ADDR_LIST_GET
*/
/* copyin user args */
break;
}
break;
}
list_space = sizeof (iscsi_addr_list_t);
list_space += (sizeof (iscsi_addr_t) *
}
ialp->al_out_cnt = 0;
int i = ialp->al_out_cnt;
/* IPv4 */
} else if (e.e_insize ==
sizeof (struct in6_addr)) {
/* IPv6 */
16);
}
}
ialp->al_out_cnt++;
}
break;
/*
* ISCSI_ISNS_SERVER_ADDR_LIST_GET
*/
/* copyin user args */
break;
}
break;
}
list_space = sizeof (iscsi_addr_list_t);
list_space += (sizeof (iscsi_addr_t) *
}
ialp->al_out_cnt = 0;
int i = ialp->al_out_cnt;
/* IPv4 */
} else if (e.e_insize ==
sizeof (struct in6_addr)) {
/* IPv6 */
16);
}
}
ialp->al_out_cnt++;
}
break;
/*
* ISCSI_DISCOVERY_ADDR_CLEAR:
*/
break;
} else if (e.e_vers != ISCSI_INTERFACE_VERSION) {
break;
}
/* If discovery in progress, try few times before return busy */
retry = 0;
if (++retry == 5) {
break;
}
}
/*
* Clear discovery address first, so that any bus config
* will ignore this discovery address
*/
}
if (rtn != 0) {
break;
}
/* Attempt to logout of associated targets */
B_FALSE) {
/* Failure!, restore the discovery addr. */
if (persistent_disc_addr_set(&e) == B_FALSE) {
"discovery address after logout associated "
"targets failures.");
}
}
break;
/*
* ISCSI_ISNS_SERVER_CLEAR:
*/
break;
} else if (e.e_vers != ISCSI_INTERFACE_VERSION) {
break;
}
/* If discovery in progress, try few times before return busy */
retry = 0;
if (++retry == 5) {
break;
}
}
/*
* Clear isns server address first, so that any bus config
* will ignore any target registerd on this isns server
*/
}
if (rtn != 0) {
break;
}
/* Attempt logout of associated targets */
/* Failure!, restore the isns server addr. */
if (persistent_isns_addr_set(&e) == B_FALSE) {
" address after logout associated targets"
" failures.");
}
} else {
if (method & iSCSIDiscoveryMethodISNS) {
int isns_server_count = 0;
/*
* Check if the last iSNS server's been
* removed.
*/
{
while (persistent_isns_addr_next(
}
}
if (isns_server_count == 0) {
}
/*
* Deregister this node from this iSNS
* server.
*/
ISCSI_MAX_NAME_LEN) == B_TRUE) {
if (strlen(initiator_node_name) > 0) {
(void) isns_dereg_one_server(
&e, (uint8_t *)
}
}
}
}
break;
/*
* ISCSI_DISCOVERY_SET -
*/
case ISCSI_DISCOVERY_SET:
break;
}
} else {
}
break;
/*
* ISCSI_DISCOVERY_GET -
*/
case ISCSI_DISCOVERY_GET:
break;
/*
* ISCSI_DISCOVERY_CLEAR -
*/
case ISCSI_DISCOVERY_CLEAR:
break;
}
/* If discovery in progress, try few times before return busy */
retry = 0;
if (++retry == 5) {
break;
}
}
/*
* Clear discovery first, so that any bus config or
* discovery requests will ignore this discovery method
*/
}
if (rtn != 0) {
break;
}
/* Attempt to logout from all associated targets */
/* Failure!, reset the discovery */
"method after discovery disable failure.");
}
}
break;
/*
* ISCSI_DISCOVERY_PROPS -
*/
case ISCSI_DISCOVERY_PROPS:
sizeof (discovery_props), mode))
break;
/*
* ISCSI_LUN_OID_LIST --
*/
case ISCSI_LUN_OID_LIST_GET:
break;
}
break;
}
/*
* Find out how much space the user has allocated in their
* structure. Match the same space for our structure.
*/
lun_sz = sizeof (iscsi_lun_list_t);
}
/*
* Check to see if oid references a target-param oid. If so,
* find the associated session oid before getting lu list.
*/
break;
}
}
} else {
}
/*
* Look at the LUNs attached to the specified target. If there
* is space in the user structure save that information locally.
* Always add up the count to the total. By always adding
* the count this code can be used if ll_in_cnt == 0 and
* the user just wishes to know the appropriate size to
* allocate.
*/
continue;
}
if (llp->ll_out_cnt <
llp->ll_out_cnt];
}
llp->ll_out_cnt++;
}
}
}
}
break;
/*
* ISCSI_LUN_PROPS_GET --
*/
case ISCSI_LUN_PROPS_GET:
break;
}
break;
}
/*
* For the target specified, find the LUN specified and
* return its properties
*/
if (rtn != 0) {
break;
}
} else {
}
((i_ddi_devi_attached(lun_dip)) ||
(ddi_get_devstate(lun_dip) ==
DDI_DEVSTATE_UP))) {
(void) ddi_pathname(lun_dip,
lun->lp_pathname);
} else {
/*
* The LUN is not exported to the
* OS yet. It is in the process
* of being added.
*/
}
if (rtn == -1) {
}
break;
}
}
break;
/*
* ISCSI_CONN_OID_LIST_GET --
*/
case ISCSI_CONN_OID_LIST_GET:
{
/* Asuume the worst */
/* Copy the input argument into kernel world. */
mode);
B_TRUE) {
rtn =
}
}
break;
}
/*
* ISCSI_CONN_OID_LIST_GET --
*/
case ISCSI_CONN_PROPS_GET:
{
/* Asuume the worst */
/* Copy the input argument into kernel world. */
mode,
sizeof (iscsi_conn_props_t));
/* Get the propereties. */
B_TRUE) {
rtn =
cp,
sizeof (*cp),
mode);
} else {
}
}
break;
}
/*
* ISCSI_RADIUS_GET -
*/
case ISCSI_RADIUS_GET:
{
KM_SLEEP);
break;
break;
}
} else {
/*
* RADIUS configuration should be done on a per
* initiator basis.
*/
break;
}
if (status == ISCSI_NVFILE_SUCCESS) {
/*
* Restore the value for overridden (and bogus) oid.
*/
} else if (status == ISCSI_NVFILE_NAMEVAL_NOT_FOUND) {
} else {
}
break;
}
/*
* ISCSI_RADIUS_SET -
*/
case ISCSI_RADIUS_SET:
KM_SLEEP);
break;
break;
}
} else {
/*
* RADIUS configuration should be done on a per
* initiator basis.
*/
break;
}
}
break;
/*
* ISCSI_AUTH_GET -
*/
case ISCSI_AUTH_GET:
KM_SLEEP);
break;
break;
}
} else {
/*
* If the oid does represent a session check to see
* if it is a target oid. If so, return the target's
* associated session.
*/
if (rtn != 0) {
}
/*
* If rtn is zero then we have found an
* existing session. Use the session name to
* do param lookup. If rtn is non-zero then
* create a targetparam object and use its name
* for param lookup.
*/
if (rtn == 0) {
} else {
name =
}
}
break;
}
/*
* Restore the value for overridden (and bogus) oid.
*/
} else {
}
break;
/*
* ISCSI_AUTH_SET -
*/
case ISCSI_AUTH_SET:
KM_SLEEP);
break;
break;
}
} else {
/*
* If the oid does represent a session check to see
* if it is a target oid. If so, return the target's
* associated session.
*/
if (rtn != 0) {
}
/*
* If rtn is zero then we have found an
* existing session. Use the session name to
* do param lookup. If rtn is non-zero then
* create a targetparam object and use its name
* for param lookup.
*/
if (rtn == 0) {
} else {
name =
rtn = 0;
}
}
== B_FALSE) {
}
break;
/*
* ISCSI_AUTH_CLEAR -
*/
case ISCSI_AUTH_CLEAR:
KM_SLEEP);
break;
break;
}
/*
* If the oid does represent a session check to see
* if it is a target oid. If so, return the target's
* associated session.
*/
if (rtn != 0) {
}
/*
* If rtn is zero then we have found an
* existing session. Use the session name to
* do param lookup. If rtn is non-zero then
* create a targetparam object and use its name
* for param lookup.
*/
if (rtn == 0) {
} else {
name =
rtn = 0;
}
break;
}
}
/*
* ISCSI_TARGET_PARAM_CLEAR, ISCSI_CHAP_CLEAR and
* ISCSI_AUTH_CLEAR ioctl are called sequentially to remove
* target parameters. Here, the target that is not discovered
* by initiator should be removed from the iscsi_targets list
* residing in the memory.
*/
if (discovered == B_FALSE) {
}
break;
/*
* ISCSI_DB_DUMP -
*/
case ISCSI_DB_DUMP:
break;
case ISCSI_USCSI:
#ifdef _MULTI_DATAMODEL
switch (model) {
case DDI_MODEL_ILP32:
sizeof (iscsi_uscsi32_t), mode)) {
break;
}
/* perform conversion from 32 -> 64 */
break;
case DDI_MODEL_NONE:
sizeof (iscsi_uscsi_t), mode)) {
break;
}
break;
default:
break;
}
#endif /* _MULTI_DATAMODEL */
/* If failures earlier break */
if (rtn != 0) {
break;
}
/* copy from caller to internel cmd */
break;
}
/*
* Check to see if oid references a target-param oid. If so,
* find the associated session oid before getting lu list.
*/
break;
}
}
} else {
}
/* make sure we have a matching session for this command */
if (rtn != 0) {
&isp);
if (rtn != 0) {
break;
}
}
/*
* If a caller buffer is present allocate duplicate
* kernel space and copyin caller memory.
*/
break;
}
}
/*
* If a caller cdb is present allocate duplicate
* kernel space and copyin caller memory.
*/
}
break;
}
}
/*
* If a caller request sense is present allocate
* duplicate kernel space. No need to copyin.
*/
}
/* issue passthru to io path handler */
if (rtn != 0) {
}
/*
* If the caller had a buf we need to do a copyout
* and free the kernel memory
*/
}
}
/* We need to free kernel cdb, no need to copyout */
}
/*
* If the caller had a request sense we need to
* do a copyout and free the kernel memory
*/
mode) != 0) {
}
}
#ifdef _MULTI_DATAMODEL
case DDI_MODEL_ILP32:
}
sizeof (iscsi_uscsi32_t), mode) != 0) {
}
break;
case DDI_MODEL_NONE:
}
sizeof (iscsi_uscsi_t), mode) != 0) {
}
break;
default:
}
#endif /* _MULTI_DATAMODEL */
break;
case ISCSI_SMF_ONLINE:
break;
}
/* just a theoretical case */
break;
}
/* doesn't need to overwrite the status anymore */
}
B_FALSE) {
break;
}
}
}
} else {
}
break;
case ISCSI_SMF_OFFLINE:
== B_FALSE) {
break;
}
}
break;
case ISCSI_SMF_GET:
while (ihp->hba_service_status ==
&ihp->hba_service_lock);
}
}
break;
case ISCSI_DISCOVERY_EVENTS:
/*
* If discovery has not been completed and not in progress,
* poke the discovery methods
*/
if ((method != ISCSI_ALL_DISCOVERY_METHODS) &&
}
break;
/*
* ISCSI_SENDTGTS_GET --
*/
case ISCSI_SENDTGTS_GET:
sizeof (*stl_hdr));
break;
}
break;
}
/* calculate how much memory user allocated for SendTgts */
if (stl_hdr->stl_in_cnt > 0) {
sizeof (iscsi_sendtgts_entry_t));
}
/* allocate local SendTgts list of the same size */
/* lock interface so only one SendTargets operation occurs */
if (rtn == 0) {
}
/* release lock to allow another SendTargets discovery */
break;
/*
* ISCSI_ISNS_SERVER_GET --
*/
case ISCSI_ISNS_SERVER_GET:
sizeof (*server_pg_list_hdr));
if (server_pg_list_hdr == NULL) {
break;
}
/* If iSNS discovery mode is not set, return with zero entry */
if ((method & iSCSIDiscoveryMethodISNS) == 0) {
sizeof (*server_pg_list_hdr));
break;
}
ISCSI_MAX_NAME_LEN) != B_TRUE) {
sizeof (*server_pg_list_hdr));
break;
}
if (strlen(initiator_node_name) == 0) {
sizeof (*server_pg_list_hdr));
break;
}
ISCSI_MAX_NAME_LEN) != B_TRUE) {
initiator_node_alias[0] = '\0';
}
&pg_list);
sizeof (*server_pg_list_hdr));
break;
}
/*
* pg_list_sz is the size of the pg_list returned from the
* isns_query_all
*
* pg_sz_copy_out is the size of the pg_list we are going to
* return back to the caller
*
* server_pg_list_sz is total amount of data we are returning
* back to the caller
*/
pg_list_sz = sizeof (isns_portal_group_list_t);
if (pg_list->pg_out_cnt > 0) {
sizeof (isns_portal_group_t);
}
/*
* check if caller passed in a buffer with enough space
* if there isn't enough space, fill the caller's buffer with
* as much information as possible.
*
* if pg_out_cnt > pg_in_cnt, pg_out_cnt will be returned with
* the total number of targets found
*
* if pg_out_cnt < pg_in_cnt, pg_out_cnt will be the number
* of targets returned
*/
pg_sz_copy_out = sizeof (isns_portal_group_list_t);
sizeof (isns_portal_group_t);
}
sizeof (isns_server_portal_group_list_t);
sizeof (isns_portal_group_t);
}
} else {
sizeof (isns_server_portal_group_list_t);
if (pg_list->pg_out_cnt > 0) {
sizeof (isns_portal_group_t);
}
}
sizeof (server_pg_list->addr));
mode) != 0) {
}
int, pg_list_sz);
break;
/*
* ISCSI_GET_CONFIG_SESSIONS --
*/
/* FALLTHRU */
break;
}
/* verify version infomration */
break;
}
/* Check to see if we need to copy in more memory */
/* record correct size */
/* free old buffer */
/* copy in complete buffer size */
break;
}
}
/* switch action based on get or set */
if (cmd == ISCSI_GET_CONFIG_SESSIONS) {
/* get */
if (rtn == 0) {
/* copyout data for gets */
} else {
}
} else {
/* set */
if (iscsiboot_prop) {
/*
* found active session for this object
* or this is initiator object
* with mpxio enabled
*/
if (!iscsi_reconfig_boot_sess(ihp)) {
break;
}
}
}
}
break;
case ISCSI_IS_ACTIVE:
/*
* dhcpagent calls here to check if there are
* active iSCSI sessions
*/
instance = 0;
if (iscsiboot_prop) {
instance = 1;
}
if (!instance) {
if ((isp->sess_state ==
(isp->sess_lun_list !=
NULL)) {
instance = 1;
break;
}
}
}
mode) != 0) {
}
break;
case ISCSI_BOOTPROP_GET:
break;
}
if (iscsiboot_prop == NULL) {
break;
} else {
}
}
NULL) {
} else {
}
}
}
}
break;
case ISCSI_TARGET_REENUM:
size = sizeof (iscsi_reen_t);
break;
}
break;
}
if (rtn != 0) {
}
if (rtn != 0) {
break;
}
if ((isp->sess_state ==
== ISCSI_SESS_ENUM_SUBMITTED)) {
(void) iscsi_sess_enum_query(isp);
}
}
break;
case ISCSI_TUNABLE_PARAM_SET:
KM_SLEEP);
break;
}
break;
case ISCSI_TUNABLE_PARAM_GET:
KM_SLEEP);
break;
}
/* initiator */
tpsg) == 1) {
/*
* no persisted tunable parameters found
* for iscsi initiator, use default tunable
* params for initiator node.
*/
}
} else {
/* check whether it is a target oid */
/* invalid node name */
break;
}
tpsg) == 1) {
/*
* no persisted tunable parameters found for
* iscsi target, use initiator's configure.
*/
/*
* No initiator tunable parameters set
* use default value for target
*/
}
}
}
sizeof (iscsi_tunable_object_t), mode) != 0) {
}
break;
default:
(cmd != ISCSI_SMF_GET)) {
/* other cmds need to release the service */
}
return (rtn);
}
/*
* +--------------------------------------------------------------------+
* | End of cb_ops routines |
* +--------------------------------------------------------------------+
*/
/*
* +--------------------------------------------------------------------+
* | Common scsi_tran support routines |
* +--------------------------------------------------------------------+
*/
/*
*
* Need to determine if any of these can be determined through the iSCSI
* protocol. For now just return error on most.
*/
/* ARGSUSED */
static int
{
int rtn;
int cidx;
if (cap == (char *)0) {
return (FALSE);
}
if (cidx == -1) {
return (cidx);
}
/*
* Process setcap request.
*/
if (doset) {
/*
* At present, we can only set binary (0/1) values
*/
switch (cidx) {
case SCSI_CAP_LUN_RESET:
if (val) {
} else {
}
break;
default:
/*
* None of these are settable via
* the capability interface.
*/
break;
}
/*
* Process getcap request.
*/
} else {
switch (cidx) {
case SCSI_CAP_DMA_MAX:
/* no DMA, Psuedo value */
break;
case SCSI_CAP_INITIATOR_ID:
rtn = 7;
break;
case SCSI_CAP_ARQ:
case SCSI_CAP_TAGGED_QING:
break;
case SCSI_CAP_SCSI_VERSION:
break;
break;
case SCSI_CAP_LUN_RESET:
break;
case SCSI_CAP_CDB_LEN:
/*
* iSCSI RFC 3720 defines a default 16 byte
* CDB as part of the Basic Header Segment
* (BHS) (10.2.1) and allows for an Additional
* Header Segment (AHS) Length of 255 * 4
* (10.2.1.5). The AHS length can be used
* for different purposes two of which are
* Extended CDB ADS (10.2.2.3) and Bidirectional
* Expected Read-Data Length AHS (10.2.2.4).
* The largest header of these consumes is
* 32 bytes. So the total Max CDB Length is
* 16 + ((255 * 4 ) - 32) = 1004.
*/
rtn = 1004;
break;
default:
break;
}
}
return (rtn);
}
/*
*
* This routine is used to associate the tran_tgt_private to our ilp
* structure. This function is indirectly called from our
* iscsi_lun_create_xxx routines. These routines must prevent
* the session and lun lists from changing during this call.
*/
/* ARGSUSED */
static int
{
/*
* Here's a nice little piece of undocumented stuff.
*/
/*
* Very bad news if this occurs. Somehow SCSI_vhci has
* lost the pathinfo node for this target.
*/
return (DDI_NOT_WELL_FORMED);
}
/*
* +----------------------------------------------------+
* | Looking to find the target device via the property |
* | is not required since the driver can easily get |
* | this information from the mdi_phci_get_private() |
* | call above. This is just a consistency check |
* | which can be removed. |
*/
return (DDI_NOT_WELL_FORMED);
}
/* If this isn't the matching session continue */
continue;
}
/*
* We are already holding the lun list rwlock
* for this thread on the callers side of mdi_pi_online
* or ndi_devi_online. Which lead to this functions
* call.
*/
/*
* If this is the matching LUN and contains
* the same LUN GUID then break we found our
* match.
*/
break;
}
}
break;
}
}
/*
* Free resource that's no longer required.
*/
(void) mdi_prop_free(lun_guid);
/*
* Failed to find iSCSI LUN in HBA chain based
* on the GUID that was stored as a property on
* the pathinfo node.
*/
return (DDI_NOT_WELL_FORMED);
}
/*
* The iSCSI target that we found on the HBA link is
* different than the iSCSI target that was stored as
* private data on the pathinfo node.
*/
return (DDI_NOT_WELL_FORMED);
}
/*
* | End of consistency check |
* +----------------------------------------------------+
*/
target_port_name[0] = '\0';
"%02x%02x%02x%02x%02x%02x,%s",
} else {
"%02x%02x%02x%02x%02x%02x,%s,%d",
}
SCSI_ADDR_PROP_TARGET_PORT "' property on Path(%p) "
"for Target(%s), Lun(%d) Failed",
}
return (DDI_SUCCESS);
}
/*
* iscsi_phys_lun_init - attempts to complete a ndi binding
*
* This routine is used to associate the tran_tgt_private to our
* ilp structure. This function is indirectly called from our
* iscsi_lun_create_xxx routines. These routines must prevent
* the session and lun lists from changing during this call.
*/
static int
{
return (DDI_FAILURE);
}
if (nwords == 0) {
return (DDI_FAILURE);
}
/* See if we already created this session */
/* Walk the HBA's session list */
/* compare target name as the unique identifier */
/* found match */
break;
}
}
/* If we found matching session continue searching for tgt */
/*
* Search for the matching iscsi lun structure. We don't
* need to hold the READER for the lun list at this point.
* because the tran_get_name is being called from the online
* function which is already holding a reader on the lun
* list.
*/
/* found match */
break;
}
}
/*
* tgt found path it to the tran_lun_private
* this is used later for fast access on
* init_pkt and start
*/
} else {
/* tgt not found */
return (DDI_FAILURE);
}
} else {
/* sess not found */
return (DDI_FAILURE);
}
target_port_name[0] = '\0';
"%02x%02x%02x%02x%02x%02x,%s",
} else {
"%02x%02x%02x%02x%02x%02x,%s,%d",
}
SCSI_ADDR_PROP_TARGET_PORT "' property on Target(%s), "
}
return (rtn);
}
/*
* +--------------------------------------------------------------------+
* | End of scsi_tran support routines |
* +--------------------------------------------------------------------+
*/
/*
* +--------------------------------------------------------------------+
* | Begin of struct utility routines |
* +--------------------------------------------------------------------+
*/
/*
* iscsi_set_default_login_params - This function sets the
* driver default login params. This is using during the
* creation of our iSCSI HBA structure initialization by
* could be used at other times to reset back to the defaults.
*/
void
{
}
/* Helper function to sets the driver default tunable parameters */
static void
{
}
/*
* +--------------------------------------------------------------------+
* | End of struct utility routines |
* +--------------------------------------------------------------------+
*/
/*
* +--------------------------------------------------------------------+
* | Begin of ioctl utility routines |
* +--------------------------------------------------------------------+
*/
/*
* iscsi_get_param - This function is a helper to ISCSI_GET_PARAM
* IOCTL
*/
int
int rtn = 0;
/* ---- Default to settable, possibly changed later ---- */
/*
* Boolean parameters
*/
break;
break;
break;
break;
/*
* Integer parameters
*/
break;
break;
break;
break;
break;
break;
break;
break;
break;
break;
default:
}
return (rtn);
}
/*
* +--------------------------------------------------------------------+
* | End of ioctl utility routines |
* +--------------------------------------------------------------------+
*/
/*
* IEEE safe address. IEEE addresses have a number of characters
* set aside as reserved.
*/
static void
{
switch (*oldch) {
case ':':
*newch++ = '%';
*newch++ = '3';
*newch = 'A';
break;
case ' ':
*newch++ = '%';
*newch++ = '2';
*newch = '0';
break;
case '@':
*newch++ = '%';
*newch++ = '4';
*newch = '0';
break;
case '/':
*newch++ = '%';
*newch++ = '2';
*newch = 'F';
break;
default:
}
}
}
/*
* iscsi_get_name_to_iqn - Converts IEEE safe address back
*/
static void
{
if (*oldch == '%') {
switch (*(oldch+1)) {
case '2':
*newch = ' ';
oldch += 2;
*newch = '/';
oldch += 2;
} else {
}
break;
case '3':
*newch = ':';
oldch += 2;
} else {
}
break;
case '4':
*newch = '@';
oldch += 2;
} else {
}
break;
default:
}
} else {
}
}
}
/*
* iscsi_get_persisted_param * - a helper to ISCSI_GET_PARAM ioctl
*
* On return 0 means persisted parameter found
*/
int
{
return (rtn);
}
/* Found configured parameter. */
rtn = 0;
}
}
return (rtn);
}
/*
* iscsi_override_target_default - helper function set the target's default
* login parameter if there is a configured initiator parameter.
*
*/
static void
{
break;
break;
break;
break;
break;
break;
break;
break;
break;
break;
break;
break;
break;
break;
default:
break;
}
}
}
}
static boolean_t
{
if (iscsi_chk_bootlun_mpxio(ihp)) {
/* oid is session object */
break;
}
/*
* oid is target object while
* this session is boot session
*/
break;
}
}
/* oid is initiator object id */
return (B_TRUE);
/* 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
*/
}
} else {
}
return (rval);
}
/*
* iscsi_client_release_service - decrease the count and wake up
* blocking threads if the count reaches zero
*/
void
if (ihp->hba_service_client_count == 0) {
}
}
/*
* 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
if ((status != ISCSI_SERVICE_ENABLED) &&
(status != ISCSI_SERVICE_DISABLED)) {
return (B_FALSE);
}
}
return (B_FALSE);
}
while (ihp->hba_service_client_count > 0) {
}
return (B_TRUE);
}
/*
* iscsi_exit_service_zone - exits the service zone and wakes up waiters
*/
static void
if ((status != ISCSI_SERVICE_ENABLED) &&
(status != ISCSI_SERVICE_DISABLED)) {
return;
}
}
static void
/*
* in miniroot we don't have the persistent store
* so just to need to ensure an enabled status
*/
}
}
static void
int param_id = 0;
switch (param_id) {
break;
break;
break;
default:
break;
}
}
/*
* iscsi_get_persisted_tunable_param * - a helper to ISCSI_TUNABLE_PARAM_GET
* ioctl
* return:
* 0 persisted tunable parameter found
* 1 persisted tunable parameter not found
*/
static int
{
int param_id = 0;
return (rtn);
}
KM_SLEEP);
switch (param_id) {
break;
break;
break;
default:
break;
}
rtn = 0;
}
}
return (rtn);
}