iscsit.c revision a6d42e7d71324c5193c3b94d57d96ba2925d52e1
/*
* 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 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <sys/sysmacros.h>
#include <sys/stmf_ioctl.h>
#include <iscsit_isns.h>
#include <iscsit.h>
/*
* DDI entry points.
*/
static boolean_t iscsit_drv_busy(void);
extern struct mod_ops mod_miscops;
static struct cb_ops iscsit_cb_ops = {
iscsit_drv_open, /* cb_open */
iscsit_drv_close, /* cb_close */
nodev, /* cb_strategy */
nodev, /* cb_print */
nodev, /* cb_dump */
nodev, /* cb_read */
nodev, /* cb_write */
iscsit_drv_ioctl, /* cb_ioctl */
nodev, /* cb_devmap */
nodev, /* cb_mmap */
nodev, /* cb_segmap */
nochpoll, /* cb_chpoll */
ddi_prop_op, /* cb_prop_op */
NULL, /* cb_streamtab */
D_MP, /* cb_flag */
CB_REV, /* cb_rev */
nodev, /* cb_aread */
nodev, /* cb_awrite */
};
static struct dev_ops iscsit_dev_ops = {
DEVO_REV, /* devo_rev */
0, /* devo_refcnt */
iscsit_drv_getinfo, /* devo_getinfo */
nulldev, /* devo_identify */
nulldev, /* devo_probe */
iscsit_drv_attach, /* devo_attach */
iscsit_drv_detach, /* devo_detach */
nodev, /* devo_reset */
&iscsit_cb_ops, /* devo_cb_ops */
NULL, /* devo_bus_ops */
NULL, /* devo_power */
};
"iSCSI Target",
};
static struct modlinkage modlinkage = {
&modldrv,
NULL,
};
static void iscsit_disable_svc(void);
static void
static void
static void
void
static void
int iscsit_cmd_window();
void
static void
static void
static void
iscsit_deferred(void *rx_pdu_void);
static idm_status_t
static idm_status_t
static idm_status_t
static idm_status_t
static idm_status_t
static stmf_data_buf_t *
static void
static void
static void
static void
static stmf_status_t
static iscsit_task_t *
static void
static iscsit_task_t *
static void
static int
static void
static it_cfg_status_t
static idm_status_t
int
_init(void)
{
int rc;
return (rc);
}
return (rc);
}
int
{
}
int
_fini(void)
{
int rc;
if (rc == 0) {
}
return (rc);
}
/*
* DDI entry points.
*/
/* ARGSUSED */
static int
void **result)
{
switch (cmd) {
case DDI_INFO_DEVT2DEVINFO:
return (DDI_SUCCESS);
case DDI_INFO_DEVT2INSTANCE:
return (DDI_SUCCESS);
default:
break;
}
return (DDI_FAILURE);
}
static int
{
if (cmd != DDI_ATTACH) {
return (DDI_FAILURE);
}
if (ddi_get_instance(dip) != 0) {
/* we only allow instance 0 to attach */
return (DDI_FAILURE);
}
/* create the minor node */
DDI_PSEUDO, 0) != DDI_SUCCESS) {
"failed creating minor node");
return (DDI_FAILURE);
}
"failed to initialize");
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/*ARGSUSED*/
static int
{
if (cmd != DDI_DETACH)
return (DDI_FAILURE);
if (iscsit_drv_busy()) {
return (EBUSY);
}
return (DDI_SUCCESS);
}
/*ARGSUSED*/
static int
{
return (0);
}
/* ARGSUSED */
static int
{
return (0);
}
static boolean_t
iscsit_drv_busy(void)
{
switch (iscsit_global.global_svc_state) {
case ISE_DISABLED:
case ISE_DETACHED:
return (B_FALSE);
default:
return (B_TRUE);
}
/* NOTREACHED */
}
/* ARGSUSED */
static int
int *retval)
{
/* iscsit_ioc_get_config_t getcfg; */
char *cfg_pnvlist;
int rc = 0;
return (EPERM);
}
/*
* Validate ioctl requests against global service state
*/
switch (iscsit_global.global_svc_state) {
case ISE_ENABLED:
if (cmd == ISCSIT_IOC_DISABLE_SVC) {
} else if (cmd == ISCSIT_IOC_ENABLE_SVC) {
/* Already enabled */
return (0);
} else {
}
break;
case ISE_DISABLED:
if (cmd == ISCSIT_IOC_ENABLE_SVC) {
} else if (cmd == ISCSIT_IOC_DISABLE_SVC) {
/* Already disabled */
return (0);
} else {
}
break;
case ISE_ENABLING:
case ISE_DISABLING:
break;
case ISE_DETACHED:
default:
break;
}
if (rc != 0)
return (rc);
switch (cmd) {
case ISCSIT_IOC_SET_CONFIG:
case DDI_MODEL_ILP32:
sizeof (iscsit_ioc_set_config32_t), flag) != 0)
return (EFAULT);
break;
case DDI_MODEL_NONE:
sizeof (iscsit_ioc_set_config_t), flag) != 0)
return (EFAULT);
break;
}
/* Check API version */
return (EINVAL);
}
/* Config is in packed nvlist format so unpack it */
KM_SLEEP);
return (EFAULT);
}
&cfg_nvlist, KM_SLEEP) != 0) {
return (EINVAL);
}
/* Translate nvlist */
return (EINVAL);
}
/* Update config */
if (iscsit_config_merge(cfg) != 0) {
return (EIO);
}
/*
* Now that the reconfig is complete set our state back to
* enabled.
*/
break;
case ISCSIT_IOC_ENABLE_SVC: {
return (EFAULT);
}
return (EFAULT);
}
if (idmrc == IDM_STATUS_SUCCESS) {
} else {
}
break;
}
case ISCSIT_IOC_DISABLE_SVC:
break;
default:
}
/* Don't forget to clear ISE_BUSY state */
return (rc);
}
static idm_status_t
{
int rc;
return (IDM_STATUS_SUCCESS);
}
/*
* iscsit_enable_svc
*
* registers all the configured targets and target portals with STMF
*/
static idm_status_t
{
/*
* Make sure that can tell if we have partially allocated
* in case we need to exit and tear down anything allocated.
*/
/* Setup remaining fields in iscsit_global_t */
iscsit_sess_avl_compare, sizeof (iscsit_sess_t),
iscsit_tgt_avl_compare, sizeof (iscsit_tgt_t),
sizeof (iscsit_tgt_t),
iscsit_tpg_avl_compare, sizeof (iscsit_tpg_t),
iscsit_ini_avl_compare, sizeof (iscsit_ini_t),
/*
* Setup STMF dbuf store. Our buffers are bound to a specific
* connection so we really can't let STMF cache buffers for us.
* Consequently we'll just allocate one global buffer store.
*/
if (dbuf_store == NULL) {
goto tear_down_and_return;
}
/* Status PDU cache */
/* Default TPG and portal */
goto tear_down_and_return;
}
/* initialize isns client */
(void) iscsit_isns_init(hostinfo);
/* Register port provider */
goto tear_down_and_return;
}
pp->pp_instance = 0;
goto tear_down_and_return;
}
return (IDM_STATUS_SUCCESS);
}
if (did_iscsit_isns_init)
if (iscsit_global.global_default_tpg) {
}
if (iscsit_global.global_pp)
if (pp)
if (iscsit_status_pdu_cache) {
}
if (iscsit_global.global_dbuf_store) {
}
if (iscsit_global.global_tsih_pool) {
}
return (retval);
}
/*
* iscsit_disable_svc
*
* clean up all existing connections and deregister targets from STMF
*/
static void
iscsit_disable_svc(void)
{
/* tear down discovery sessions */
/*
* Passing NULL to iscsit_config_merge tells it to go to an empty
* config.
*/
(void) iscsit_config_merge(NULL);
/*
* Wait until there are no more global references
*/
/*
* Default TPG must be destroyed after global_refcnt is 0.
*/
}
void
{
}
void
{
}
void
{
}
/*
* IDM callbacks
*/
/*ARGSUSED*/
void
{
switch (IDM_PDU_OPCODE(rx_pdu)) {
case ISCSI_OP_SCSI_CMD:
ASSERT(0); /* Shouldn't happen */
break;
case ISCSI_OP_SNACK_CMD:
/*
* We'll need to handle this when we support ERL1/2. For
* now we treat it as a protocol error.
*/
break;
break;
case ISCSI_OP_NOOP_OUT:
case ISCSI_OP_LOGIN_CMD:
case ISCSI_OP_TEXT_CMD:
case ISCSI_OP_LOGOUT_CMD:
/*
* will be handled by iscsitd.
*/
break;
default:
/* Protocol error */
break;
}
}
/*ARGSUSED*/
void
{
}
void
{
switch (status) {
case IDM_STATUS_SUSPENDED:
break;
case IDM_STATUS_ABORTED:
if (itask->it_stmf_abort) {
/*
* STMF has already asked for this task to be aborted.
* Cleanup the task and call STMF to let it know that
* the abort is complete.
*/
/*
* STMF specification is wrong... says to return
* STMF_ABORTED, the code actually looks for
* STMF_ABORT_SUCCESS.
*/
return;
} else {
/*
* Tell STMF to stop processing the task. We will
* cleanup the task in the context of iscsit_abort
* (lport_abort).
*/
STMF_ABORTED, NULL);
return;
}
/*NOTREACHED*/
default:
ASSERT(0);
}
}
/*ARGSUSED*/
{
/*
* IDM client notifications will never occur at interrupt level
* since they are generated from the connection state machine which
* running on taskq threads.
*
*/
switch (icn) {
case CN_CONNECT_ACCEPT:
break;
case CN_FFP_ENABLED:
break;
case CN_FFP_DISABLED:
/*
* Data indicates whether this was the result of an
* explicit logout request.
*/
break;
case CN_CONNECT_LOST:
break;
case CN_CONNECT_DESTROY:
break;
case CN_LOGIN_FAIL:
/*
* Force the login state machine to completion
*/
break;
default:
break;
}
return (rc);
}
void
{
/*
* We acquired iscsit_sess_t.ist_sn_rwlock in iscsit_xfer_scsi_data
* in reader mode so we expect to be locked here
*/
/*
* Lun is only required if the opcode == ISCSI_OP_SCSI_DATA_RSP
* and the 'A' bit is to be set
*/
/* Statsn is only set during phase collapse */
/*
* IDM must set:
*
* data.flags and rtt.flags
* data.dlength
* data.datasn
* data.offset
* residual_count and cmd_status (if we ever implement phase collapse)
* rtt.rttsn
* rtt.data_offset
* rtt.data_length
*/
}
static idm_status_t
{
/*
* Allocate an associated iscsit structure to represent this
* connection. We shouldn't really create a session until we
* get the first login PDU.
*/
/*
* Initialize login state machine
*/
return (IDM_STATUS_FAIL);
}
return (IDM_STATUS_SUCCESS);
}
{
/*
* Note in new connection state that this connection is
* reinstating an existing connection.
*/
/*
* Now generate connection state machine event to existing connection
* so that it starts the cleanup process.
*/
return (result);
}
void
{
}
void
{
}
void
{
}
void
{
}
static idm_status_t
{
/* Generate login state machine event */
return (IDM_STATUS_SUCCESS);
}
static idm_status_t
{
/* Generate session state machine event */
return (IDM_STATUS_SUCCESS);
}
static idm_status_t
{
/* Generate session state machine event */
switch (disable_class) {
case FD_CONN_FAIL:
break;
case FD_CONN_LOGOUT:
break;
case FD_SESS_LOGOUT:
break;
default:
ASSERT(0);
}
return (IDM_STATUS_SUCCESS);
}
static idm_status_t
{
/*
* Make sure there aren't any PDU's transitioning from the receive
* handler to the dispatch taskq.
*/
return (IDM_STATUS_SUCCESS);
}
static idm_status_t
{
/* Generate session state machine event */
/*
* Session state machine will call iscsit_conn_destroy_done()
* when it has removed references to this connection.
*/
}
return (IDM_STATUS_SUCCESS);
}
/*
* STMF-related functions
*
* iSCSI to STMF mapping
*
* Session == ?
* Connection == bound to local port but not itself a local port
* Target
* Target portal (group?) == local port (really but we're not going to do this)
* iscsit needs to map connections to local ports (whatever we decide
* they are)
* Target == ?
*/
/*ARGSUSED*/
static stmf_data_buf_t *
{
/*
* Once the iSER picture is better understood it might make sense
* to pre-allocate some registered buffers, similar to what
* these things quickly.
*
* We can't support a transfer larger than MaxBurstLength bytes.
*/
return (NULL);
}
/* Alloc buffer */
if (idm_buffer != NULL) {
sizeof (iscsit_buf_t), 0);
/* Fill in stmf_data_buf_t */
return (result);
}
/* Couldn't get the stmf_data_buf_t so free the buffer */
}
return (NULL);
}
/*ARGSUSED*/
static void
{
if (ibuf->ibuf_is_immed) {
/*
* The iscsit_buf_t structure itself will be freed with its
* associated task. Here we just need to free the PDU that
* held the immediate data.
*/
ibuf->ibuf_immed_data_pdu = 0;
} else {
}
}
/*ARGSUSED*/
{
int idm_rc;
/*
* If it's not immediate data then start the transfer
*/
/*
* IDM will call iscsit_build_hdr so lock now to serialize
* access to the SN values. We need to lock here to enforce
* lock ordering
*/
return (iscsit_idm_to_stmf(idm_rc));
/* Grab the SN lock (see comment above) */
return (iscsit_idm_to_stmf(idm_rc));
}
/* What are we supposed to do if there is no direction? */
return (STMF_INVALID_ARG);
}
static void
{
/*
* COMSTAR currently requires port providers to support
* the DB_SEND_STATUS_GOOD flag even if phase collapse is
* not supported. So we will roll our own... pretend we are
* COMSTAR and ask for a status PDU.
*/
status == IDM_STATUS_SUCCESS) {
/*
* If iscsit_send_scsi_status succeeds then the TX PDU
* callback will call stmf_send_status_done and set
* STMF_IOF_LPORT_DONE. Consequently we don't need
* to call stmf_data_xfer_done in that case. We
* still need to call it if we get a failure.
*
* To elaborate on this some more, upon successful return
* from iscsit_send_scsi_status it's possible that itask
* and idb have been freed and are no longer valid.
*/
!= IDM_STATUS_SUCCESS) {
/* Failed to send status */
}
} else {
}
}
/*ARGSUSED*/
{
int resp_datalen;
/*
* If this task is aborted then we don't need to respond.
*/
if (itask->it_stmf_abort) {
return (STMF_SUCCESS);
}
/*
* If this is a task management status, handle it elsewhere.
*/
/*
* Don't wait for the PDU completion to tell STMF
* the task is done -- it doesn't really matter and
* it makes life complicated if STMF later asks us to
* abort the request and we don't know whether the
* status has been sent or not.
*/
return (STMF_SUCCESS);
}
(task->task_sense_length == 0) &&
(task->task_resid == 0)) {
/* PDU callback releases task hold */
/*
* Fast path. Cached status PDU's are already
* initialized. We just need to fill in
* connection and task information.
*/
return (STMF_SUCCESS);
} else {
return (IDM_STATUS_FAIL);
}
/* PDU callback releases task hold */
}
rsp->bi_residual_count = 0;
if (task->task_sense_length != 0) {
/*
* Add a byte to provide the sense length in
* the response
*/
sizeof (uint16_t),
}
return (STMF_SUCCESS);
}
}
/*ARGSUSED*/
static void
{
}
/*ARGSUSED*/
static void
{
}
void
{
/* We only call idm_task_start for regular tasks, not task management */
return;
} else {
}
}
/*ARGSUSED*/
{
/*
* If this is a task management request then there's really not much to
* do.
*/
return (STMF_ABORT_SUCCESS);
}
/*
* Regular task, start cleaning up
*/
if (iscsit_task->it_aborted) {
/*
* STMF specification is wrong... says to return
* STMF_ABORTED, the code actually looks for
* STMF_ABORT_SUCCESS.
*/
return (STMF_ABORT_SUCCESS);
} else {
/*
* Call IDM to abort the task. Due to a variety of
* circumstances the task may already be in the process of
* aborting.
* We'll let IDM worry about rationalizing all that except
* for one particular instance. If the state of the task
* is TASK_COMPLETE, we need to indicate to the framework
* that we are in fact done. This typically happens with
* framework-initiated task management type requests
* (e.g. abort task).
*/
return (STMF_ABORT_SUCCESS);
} else {
return (STMF_SUCCESS);
}
}
/*NOTREACHED*/
}
/*ARGSUSED*/
void
{
(cmd == STMF_ACK_LPORT_ONLINE_COMPLETE) ||
(cmd == STMF_CMD_LPORT_OFFLINE) ||
switch (cmd) {
case STMF_CMD_LPORT_ONLINE:
break;
case STMF_CMD_LPORT_OFFLINE:
break;
break;
break;
default:
break;
}
}
static stmf_status_t
{
switch (idmrc) {
case IDM_STATUS_SUCCESS:
return (STMF_SUCCESS);
default:
return (STMF_FAILURE);
}
/*NOTREACHED*/
}
/*
* ISCSI protocol
*/
void
{
uint16_t addl_cdb_len = 0;
return;
}
/* Finish processing request */
/*
* Note CmdSN and ITT in task. IDM will have already validated this
* request against the connection state so we don't need to check
* that (the connection may have changed state in the meantime but
* we will catch that when we try to send a response)
*/
/*
* Check for extended CDB AHS
*/
if (iscsi_scsi->hlength > 0) {
iscsi_scsi->hlength) {
/* Mangled header info, drop it */
return;
}
}
16 + addl_cdb_len, 0);
/*
* Either stmf really couldn't get memory for a task or,
* more likely, the LU is currently in reset. Either way
* we have no choice but to fail the request.
*/
return;
}
/*
* iSCSI and Comstar use the same values. Should we rely on this
* or translate them bit-wise?
*/
task->task_flags =
case ISCSI_ATTR_UNTAGGED:
break;
case ISCSI_ATTR_SIMPLE:
break;
case ISCSI_ATTR_ORDERED:
break;
case ISCSI_ATTR_HEAD_OF_QUEUE:
break;
case ISCSI_ATTR_ACA:
break;
default:
/* Protocol error but just take it, treat as untagged */
break;
}
task->task_additional_flags = 0;
task->task_priority = 0;
/*
* This "task_max_nbufs" doesn't map well to BIDI. We probably need
* parameter for each direction. "MaxOutstandingR2T" may very well
* be set to one which could prevent us from doing simultaneous
* transfers in each direction.
*/
/* Copy CDB */
if (addl_cdb_len > 0) {
}
/*
* Copy the transport header into the task handle from the PDU
* handle. The transport header describes this task's remote tagged
* buffer.
*/
if (rx_pdu->isp_transport_hdrlen != 0) {
}
/*
* Tell IDM about our new active task
*/
/*
* If we have any immediate data then setup the immediate buffer
* context that comes with the task
*/
if (rx_pdu->isp_datalen) {
} else {
}
}
/*ARGSUSED*/
void
{
/*
* If the connection has been lost then ignore new PDU's
*/
return;
}
/*
* Grab a hold on the connection to prevent it from going away
* between now and when the taskq function is called.
*/
/*
* In the unlikely scenario that we couldn't get the resources
* to dispatch the PDU then just drop it.
*/
}
}
static void
iscsit_deferred(void *rx_pdu_void)
{
switch (IDM_PDU_OPCODE(rx_pdu)) {
case ISCSI_OP_NOOP_OUT:
break;
case ISCSI_OP_LOGIN_CMD:
break;
case ISCSI_OP_TEXT_CMD:
break;
case ISCSI_OP_LOGOUT_CMD:
break;
default:
/* Protocol error. IDM should have caught this */
ASSERT(0);
break;
}
}
static void
{
idm_conn_t *ic;
}
void
{
}
void
{
/*
* Setup response PDU (response field will get filled in later)
*/
if (tm_resp_pdu == NULL) {
/* Can't respond, just drop it */
return;
}
/*
* Figure out what we're being asked to do.
*/
case ISCSI_TM_FUNC_ABORT_TASK:
/*
* STMF doesn't currently support the "abort task" task
* management command although it does support aborting
* an individual task. We'll get STMF to abort the task
* for us but handle the details of the task management
* command ourselves.
*
* Find the task associated with the referenced task tag.
*/
/*
* Task was not found. If RefCmdSN is within the CmdSN
* window and less than CmdSN of the TM function, return
* "Function Complete". Otherwise, return
* "Task Does Not Exist".
*/
} else {
}
} else {
/*
* Tell STMF to abort the task. This will do no harm
* if the task is already complete.
*/
STMF_ABORTED, NULL);
/*
* Make sure the task hasn't already completed
*/
/*
* Task is complete, return "Task Does Not
* Exist"
*/
} else {
/*
* STMF is now aborting the task, return
* "Function Complete"
*/
}
}
return;
break;
case ISCSI_TM_FUNC_CLEAR_ACA:
break;
break;
break;
break;
break;
/*
* We do not currently support allegiance reassignment. When
* we start supporting ERL1+, we will need to.
*/
return;
default:
return;
}
return;
}
0, STMF_TASK_EXT_NONE);
/*
* If this happens, either the LU is in reset, couldn't
* get memory, or some other condition in which we simply
* can't complete this request. It would be nice to return
* an error code like "busy" but the closest we have is
* "rejected".
*/
return;
}
task->task_priority = 0;
}
static void
{
int resp_datalen;
/* Get iSCSI session handle */
/* Ignore the response from initiator */
return;
/* Allocate a PDU to respond */
if (resp_datalen > 0) {
}
/* Any other field in resp to be set? */
}
static void
{
/*
* Submit PDU to login state machine. State machine will free the
* PDU.
*/
}
void
{
/* Allocate a PDU to respond */
/*
* Logout results in the immediate termination of all tasks except
* if the logout reason is ISCSI_LOGOUT_REASON_RECOVERY. The
* connection state machine will drive this task cleanup automatically
* so we don't need to handle that here.
*/
} else {
}
}
/*
* Calculate the number of outstanding commands we can process
*/
int
{
/* Will be better later */
return (1024);
}
/*
* Set local registers based on incoming PDU
*/
void
{
}
/*
* Update local StatSN and set SNs in response
*/
static void
{
/* Get iSCSI session handle */
/* Update StatSN */
switch (IDM_PDU_OPCODE(resp)) {
case ISCSI_OP_RTT_RSP:
/* Do nothing */
break;
case ISCSI_OP_NOOP_IN:
/*
* Refer to section 10.19.1, RFC3720.
* Advance only if target is responding initiator
*/
ict->ict_statsn++;
break;
case ISCSI_OP_SCSI_DATA_RSP:
ict->ict_statsn++;
else
break;
default:
ict->ict_statsn++;
break;
}
/* Set ExpCmdSN and MaxCmdSN */
}
/*
* Wrapper funtion, calls iscsi_calc_rspsn and idm_pdu_tx
*/
void
{
/*
* Protect ict->ict_statsn, ist->ist_maxcmdsn, and ist->ist_expcmdsn
* (which are used by iscsit_calc_rspsn) with the session mutex
* (ist->ist_sn_mutex).
*/
}
/*
* Internal functions
*/
void
{
/*
* Get a PDU to build the abort request.
*/
return;
}
abt->isp_datalen = 0;
switch (event) {
break;
default:
ASSERT(0);
}
}
static iscsit_task_t *
{
/*
* Possible items to pre-alloc if we cache iscsit_task_t's:
*
* Status PDU w/ sense buffer
* stmf_data_buf_t for immediate data
*/
sizeof (stmf_data_buf_t), KM_NOSLEEP);
itask->it_tm_task = 0;
return (itask);
} else {
sizeof (iscsit_buf_t) + sizeof (stmf_data_buf_t));
}
}
return (NULL);
}
static void
{
sizeof (iscsit_buf_t) + sizeof (stmf_data_buf_t));
}
static iscsit_task_t *
{
itask->it_tm_responded = 0;
}
return (itask);
}
static void
{
/*
* If we responded then the call to idm_pdu_complete will free the
* PDU. Otherwise we got aborted before the TM function could
* complete and we need to free the PDU explicitly.
*/
}
/*
* iscsit status PDU cache
*/
/*ARGSUSED*/
static int
{
/* Setup status response */
return (0);
}
/*
* iscsit private data handler
*/
/*ARGSUSED*/
static void
{
return;
}
/* Translate nvlist */
return;
}
/* Update config */
(void) iscsit_config_merge(cfg);
}
static it_cfg_status_t
{
if (in_cfg) {
} else {
/* Make empty config */
}
/*
* Update targets, initiator contexts, target portal groups,
* and iSNS client
*/
!= 0) ||
return (status);
}
/* Update other global config parameters */
if (iscsit_global.global_props) {
}
if (in_cfg) {
}
return (ITCFG_SUCCESS);
}
/*
* iscsit_sna_lt[e]
*
* Compare serial numbers using serial number arithmetic as defined in
* RFC 1982.
*
* NOTE: This code is duplicated in the isns server as well as iscsitgtd. It
* ought to be common.
*/
static int
{
}
static int
{
}
static boolean_t
{
/*
* If cmdsn is less than ist_expcmdsn - iscsit_cmd_window() or
* greater than ist_expcmdsn, it's not in the window.
*/
}
return (rval);
}