fp.c revision e20df668c56beda452ed1ddd9da1cb7a99a8e51c
/*
* 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.
*
* NOT a DDI compliant Sun Fibre Channel port driver(fp)
*
*/
#include <sys/byteorder.h>
/* These are defined in fctl.c! */
extern int did_table_size;
extern int pwwn_table_size;
fp_open, /* open */
fp_close, /* close */
nodev, /* strategy */
nodev, /* print */
nodev, /* dump */
nodev, /* read */
nodev, /* write */
fp_ioctl, /* ioctl */
nodev, /* devmap */
nodev, /* mmap */
nodev, /* segmap */
nochpoll, /* chpoll */
ddi_prop_op, /* cb_prop_op */
0, /* streamtab */
CB_REV, /* rev */
nodev, /* aread */
nodev /* awrite */
};
DEVO_REV, /* build revision */
0, /* reference count */
fp_getinfo, /* getinfo */
nulldev, /* identify - Obsoleted */
nulldev, /* probe */
fp_attach, /* attach */
fp_detach, /* detach */
nodev, /* reset */
&fp_cb_ops, /* cb_ops */
NULL, /* bus_ops */
fp_power /* power */
};
#define FP_VERSION "1.96"
char *fp_version = FP_NAME_VERSION;
&mod_driverops, /* Type of Module */
FP_NAME_VERSION, /* Name/Version of fp */
&fp_ops /* driver ops */
};
static struct modlinkage modlinkage = {
MODREV_1, /* Rev of the loadable modules system */
&modldrv, /* NULL terminated list of */
NULL /* Linkage structures */
};
static uint16_t ns_reg_cmds[] = {
};
struct fp_xlat {
int xlat_rval;
} fp_xlat [] = {
{ FC_PKT_SUCCESS, FC_SUCCESS },
{ FC_PKT_REMOTE_STOP, FC_FAILURE },
{ FC_PKT_LOCAL_RJT, FC_FAILURE },
{ FC_PKT_LOCAL_BSY, FC_TRAN_BUSY },
{ FC_PKT_TRAN_BSY, FC_TRAN_BUSY },
{ FC_PKT_NPORT_BSY, FC_PBUSY },
{ FC_PKT_FABRIC_BSY, FC_FBUSY },
{ FC_PKT_LS_RJT, FC_FAILURE },
{ FC_PKT_BA_RJT, FC_FAILURE },
{ FC_PKT_TIMEOUT, FC_FAILURE },
{ FC_PKT_FAILURE, FC_FAILURE },
};
static uchar_t fp_valid_alpas[] = {
0x01, 0x02, 0x04, 0x08, 0x0F, 0x10, 0x17, 0x18, 0x1B,
0x1D, 0x1E, 0x1F, 0x23, 0x25, 0x26, 0x27, 0x29, 0x2A,
0x2B, 0x2C, 0x2D, 0x2E, 0x31, 0x32, 0x33, 0x34, 0x35,
0x36, 0x39, 0x3A, 0x3C, 0x43, 0x45, 0x46, 0x47, 0x49,
0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x51, 0x52, 0x53, 0x54,
0x55, 0x56, 0x59, 0x5A, 0x5C, 0x63, 0x65, 0x66, 0x67,
0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x71, 0x72, 0x73,
0x74, 0x75, 0x76, 0x79, 0x7A, 0x7C, 0x80, 0x81, 0x82,
0x84, 0x88, 0x8F, 0x90, 0x97, 0x98, 0x9B, 0x9D, 0x9E,
0x9F, 0xA3, 0xA5, 0xA6, 0xA7, 0xA9, 0xAA, 0xAB, 0xAC,
0xAD, 0xAE, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB9,
0xBA, 0xBC, 0xC3, 0xC5, 0xC6, 0xC7, 0xC9, 0xCA, 0xCB,
0xCC, 0xCD, 0xCE, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
0xD9, 0xDA, 0xDC, 0xE0, 0xE1, 0xE2, 0xE4, 0xE8, 0xEF
};
static struct fp_perms {
} fp_perm_list [] = {
{ FCIO_GET_NUM_DEVS, FP_OPEN },
{ FCIO_GET_DEV_LIST, FP_OPEN },
{ FCIO_GET_SYM_PNAME, FP_OPEN },
{ FCIO_GET_SYM_NNAME, FP_OPEN },
{ FCIO_SET_SYM_PNAME, FP_EXCL },
{ FCIO_SET_SYM_NNAME, FP_EXCL },
{ FCIO_GET_LOGI_PARAMS, FP_OPEN },
{ FCIO_DEV_LOGIN, FP_EXCL },
{ FCIO_DEV_LOGOUT, FP_EXCL },
{ FCIO_GET_STATE, FP_OPEN },
{ FCIO_DEV_REMOVE, FP_EXCL },
{ FCIO_GET_FCODE_REV, FP_OPEN },
{ FCIO_GET_FW_REV, FP_OPEN },
{ FCIO_GET_DUMP_SIZE, FP_OPEN },
{ FCIO_FORCE_DUMP, FP_EXCL },
{ FCIO_GET_DUMP, FP_OPEN },
{ FCIO_GET_TOPOLOGY, FP_OPEN },
{ FCIO_RESET_LINK, FP_EXCL },
{ FCIO_RESET_HARD, FP_EXCL },
{ FCIO_RESET_HARD_CORE, FP_EXCL },
{ FCIO_DOWNLOAD_FW, FP_EXCL },
{ FCIO_DOWNLOAD_FCODE, FP_EXCL },
{ FCIO_LINK_STATUS, FP_OPEN },
{ FCIO_GET_HOST_PARAMS, FP_OPEN },
{ FCIO_GET_NODE_ID, FP_OPEN },
{ FCIO_SET_NODE_ID, FP_EXCL },
{ FCIO_SEND_NODE_ID, FP_OPEN },
{ FCIO_DELETE_NPIV_PORT, FP_OPEN },
{ FCIO_CREATE_NPIV_PORT, FP_OPEN },
};
static char *fp_pm_comps[] = {
"NAME=FC Port",
"0=Port Down",
"1=Port Up"
};
#ifdef _LITTLE_ENDIAN
#define MAKE_BE_32(x) { \
for (i = 0; i < sizeof (*(x)) / sizeof (uint32_t); i++) { \
ptr1++; \
} \
}
#else
#define MAKE_BE_32(x)
#endif
static uint32_t fp_options = 0;
static int fp_cmd_wait_cnt = FP_CMDWAIT_DELAY;
unsigned int fp_offline_ticker; /* seconds */
/*
* Driver global variable to anchor the list of soft state structs for
* all fp driver instances. Used with the Solaris DDI soft state functions.
*/
static void *fp_driver_softstate;
static clock_t fp_retry_ticks;
static clock_t fp_offline_ticks;
static int fp_retry_ticker;
static int fp_log_size = FP_LOG_SIZE;
static int fp_trace = FP_TRACE_DEFAULT;
/*
* Perform global initialization
*/
int
_init(void)
{
int ret;
sizeof (struct fc_local_port), 8)) != 0) {
return (ret);
}
return (ret);
}
}
return (ret);
}
/*
* Prepare for driver unload
*/
int
_fini(void)
{
int ret;
}
return (ret);
}
/*
* Request mod_info() to handle all cases
*/
int
{
}
/*
* fp_attach:
*
* The respective cmd handlers take care of performing
* ULP related invocations
*/
static int
{
int rval;
/*
* We check the value of fp_offline_ticker at this
* point. The variable is global for the driver and
* not specific to an instance.
*
* or fp.conf, then we use 90 seconds (FP_OFFLINE_TICKER).
* The minimum setting for this offline timeout according
* to the FC-FS2 standard (Fibre Channel Framing and
* Signalling-2, see www.t11.org) is R_T_TOV == 100msec.
*
* We do not recommend setting the value to less than 10
* seconds (RA_TOV) or more than 90 seconds. If this
* variable is greater than 90 seconds then drivers above
* fp (fcp, sd, scsi_vhci, vxdmp et al) might complain.
*/
if ((fp_offline_ticker < 10) ||
(fp_offline_ticker > 90)) {
"%d second(s). This is outside the "
"recommended range of 10..90 seconds",
}
/*
* Tick every second when there are commands to retry.
* It should tick at the least granular value of pkt_timeout
* (which is one second)
*/
fp_retry_ticker = 1;
switch (cmd) {
case DDI_ATTACH:
break;
case DDI_RESUME:
break;
default:
rval = DDI_FAILURE;
break;
}
return (rval);
}
/*
* fp_detach:
*
* If a ULP fails to handle cmd request converse of
* cmd is invoked for ULPs that previously succeeded
* cmd request.
*/
static int
{
int rval = DDI_FAILURE;
return (DDI_FAILURE);
}
if (port->fp_ulp_attach) {
return (DDI_FAILURE);
}
switch (cmd) {
case DDI_DETACH:
return (DDI_FAILURE);
}
/* Let's attempt to quit the job handler gracefully */
&modlinkage) != FC_SUCCESS) {
rval = DDI_FAILURE;
break;
}
cnt++) {
}
if (port->fp_job_head) {
rval = DDI_FAILURE;
break;
}
break;
case DDI_SUSPEND:
&modlinkage) != FC_SUCCESS) {
rval = DDI_FAILURE;
break;
}
}
break;
default:
break;
}
/*
* Use softint to perform reattach. Mark fp_ulp_attach so we
* don't attempt to do this repeatedly on behalf of some persistent
* caller.
*/
if (rval != DDI_SUCCESS) {
/*
* If the port is in the low power mode then there is
* possibility that fca too could be in low power mode.
* Try to raise the power before calling attach ulps.
*/
} else {
}
while (port->fp_ulp_attach) {
}
/*
* Mark state as detach failed so asynchronous ULP attach
* events (downstream, not the ones we're initiating with
* the call to fp_attach_ulps) are not honored. We're
* really still in pending detach.
*/
}
return (rval);
}
/*
* fp_getinfo:
* Given the device number, return either the
* dev_info_t pointer or the instance number.
*/
/* ARGSUSED */
static int
{
int rval;
rval = DDI_SUCCESS;
switch (cmd) {
case DDI_INFO_DEVT2DEVINFO:
rval = DDI_FAILURE;
break;
}
break;
case DDI_INFO_DEVT2INSTANCE:
break;
default:
rval = DDI_FAILURE;
break;
}
return (rval);
}
/*
* Entry point for power up and power down request from kernel
*/
static int
{
int rval = DDI_FAILURE;
return (rval);
}
switch (level) {
case FP_PM_PORT_UP:
rval = DDI_SUCCESS;
/*
* If the port is DDI_SUSPENDed, let the DDI_RESUME
* code complete the rediscovery.
*/
break;
}
if (rval != DDI_SUCCESS) {
}
} else {
}
break;
case FP_PM_PORT_DOWN:
/*
* PM framework goofed up. We have don't
* have any PM components. Let's never go down.
*/
break;
}
if (port->fp_ulp_attach) {
/* We shouldn't let the power go down */
break;
}
/*
* Not a whole lot to do if we are detaching
*/
rval = DDI_SUCCESS;
break;
}
if (rval != DDI_SUCCESS) {
} else {
}
}
break;
default:
break;
}
return (rval);
}
/*
* Open FC port devctl node
*/
static int
{
int instance;
return (EINVAL);
}
/*
* This is not a toy to play with. Allow only powerful
* users (hopefully knowledgeable) to access the port
* (A hacker potentially could download a sick binary
* file into FCA)
*/
return (EPERM);
}
return (ENXIO);
}
/*
* It is already open for exclusive access.
* So shut the door on this caller.
*/
return (EBUSY);
}
/*
* Exclusive operation not possible
* as it is already opened
*/
return (EBUSY);
}
}
return (0);
}
/*
* The driver close entry point is called on the last close()
* of a device. So it is perfectly alright to just clobber the
* open flag and reset it to idle (instead of having to reset
* each flag bits). For any confusion, check out close(9E).
*/
/* ARGSUSED */
static int
{
int instance;
return (EINVAL);
}
return (ENXIO);
}
return (ENODEV);
}
return (0);
}
/*
* Handle IOCTL requests
*/
/* ARGSUSED */
static int
{
int instance;
int ret = 0;
return (ENXIO);
}
return (ENXIO);
}
return (ENXIO);
}
/* this will raise power if necessary */
if (ret != 0) {
return (ret);
}
switch (cmd) {
case FCIO_CMD: {
#ifdef _MULTI_DATAMODEL
case DDI_MODEL_ILP32: {
break;
}
break;
}
case DDI_MODEL_NONE:
}
break;
}
#else /* _MULTI_DATAMODEL */
break;
}
#endif /* _MULTI_DATAMODEL */
if (!ret) {
}
break;
}
default:
}
return (ret);
}
/*
* Init Symbolic Port Name and Node Name
* LV will try to get symbolic names from FCA driver
* and register these to name server,
* if LV fails to get these,
* LV will register its default symbolic names to name server.
* The Default symbolic node name format is :
* <hostname>:<hba driver name>(instance)
* The Default symbolic port name format is :
* <fp path name>
*/
static void
{
char *sym_name;
char fcaname[50] = {0};
if (port->fp_sym_node_namelen == 0) {
}
}
if (port->fp_sym_port_namelen == 0) {
}
}
}
/*
* Perform port attach
*/
static int
{
int rval;
int instance;
int port_num;
int port_len;
char name[30];
char i_pwwn[17];
int portpro1;
if (rval != DDI_SUCCESS) {
instance);
return (DDI_FAILURE);
}
DDI_NT_NEXUS, 0) != DDI_SUCCESS) {
instance);
return (DDI_FAILURE);
}
DDI_NT_FC_ATTACHMENT_POINT, 0) != DDI_SUCCESS) {
" point minor node", instance);
return (DDI_FAILURE);
}
!= DDI_SUCCESS) {
instance);
return (DDI_FAILURE);
}
/*
* Init the starting value of fp_rscn_count. Note that if
* FC_INVALID_RSCN_COUNT is 0 (which is what it currently is), the
* actual # of RSCNs will be (fp_rscn_count - 1)
*/
"phyport-instance", -1)) != -1) {
}
/*
* Allocate the pool of fc_packet_t structs to be used with
* this fp instance.
*/
NULL, 0);
goto cache_alloc_failed;
}
/*
* Allocate the d_id and pwwn hash tables for all remote ports
* connected to this local port.
*/
/* Indicate that don't have the pm components yet */
/*
* Bind the callbacks with the FCA driver. This will open the gate
* for asynchronous callbacks, so after this call the fp_mutex
* must be held when updating the fc_local_port_t struct.
*
* This is done _before_ setting up the job thread so we can avoid
* cleaning up after the thread_create() in the error path. This
* also means fp will be operating with fp_els_resp_pkt set to NULL.
*/
goto bind_callbacks_failed;
}
if (phyport) {
if (phyport->fp_port_next) {
} else {
}
}
/*
* Init Symbolic Names
*/
instance);
goto alloc_els_packet_failed;
}
v.v_maxsyspri - 2);
i_pwwn) != DDI_PROP_SUCCESS) {
"fp(%d): Updating 'initiator-port' property"
" on fp dev_info node failed", instance);
}
i_pwwn) != DDI_PROP_SUCCESS) {
"fp(%d): Updating 'initiator-node' property"
" on fp dev_info node failed", instance);
}
/*
* Determine the count of unsolicited buffers this FCA can support
*/
/*
* Allocate unsolicited buffer tokens
*/
if (port->fp_ub_count) {
/*
* Do not fail the attach if unsolicited buffer allocation
* fails; Just try to get along with whatever the FCA can do.
*/
" Unsolicited buffers. proceeding with attach...",
instance);
}
}
/*
* Enable DDI_SUSPEND and DDI_RESUME for this instance.
*/
"pm-hardware-state", "needs-suspend-resume",
/*
* fctl maintains a list of all port handles, so
* help fctl add this one to its list now.
*/
/*
* If a state change is already in progress, set the bind state t
* OFFLINE as well, so further state change callbacks into ULPs
* will pass the appropriate states
*/
port->fp_statec_busy) {
} else {
/*
* Without dropping the mutex, ensure that the port
* startup happens ahead of state change callback
* processing
*/
}
while (port->fp_ulp_attach) {
}
"pm-components", fp_pm_comps,
sizeof (fp_pm_comps) / sizeof (fp_pm_comps[0])) !=
" components property, PM disabled on this port.");
} else {
FP_PM_PORT_UP) != DDI_SUCCESS) {
" power level");
}
/*
* Don't unset the FP_SOFT_NO_PMCOMP flag until after
* the call to pm_raise_power. The PM framework can't
* handle multiple threads calling into it during attach.
*/
}
return (DDI_SUCCESS);
/*
*/
}
port->fp_ub_tokens);
}
}
}
pwwn_table_size * sizeof (struct pwwn_hash));
}
did_table_size * sizeof (struct d_id_hash));
}
}
return (DDI_FAILURE);
}
/*
* Handle DDI_RESUME request
*/
static int
{
int rval;
#ifdef DEBUG
#endif
/*
* If the port was power suspended, raise the power level
*/
FP_PM_PORT_UP) != DDI_SUCCESS) {
"Failed to raise the power level");
return (DDI_FAILURE);
}
}
/*
* All the discovery is initiated and handled by per-port thread.
* Further all the discovery is done in handled in callback mode
* (not polled mode); In a specific case such as this, the discovery
* is required to happen in polled mode. The easiest way out is
* to bail out port thread and get started. Come back and fix this
* to do on demand discovery initiated by ULPs. ULPs such as FCP
* will do on-demand discovery during pre-power-up busctl handling
* which will only be possible when SCSA provides a new HBA vector
* for sending down the PM busctl requests.
*/
if (rval != DDI_SUCCESS) {
}
return (rval);
}
/*
* Perform FC Port power on initialization
*/
static int
{
int rval;
if (rval != DDI_SUCCESS) {
} else {
}
return (rval);
}
/*
* It is important to note that the power may possibly be removed between
* SUSPEND and the ensuing RESUME operation. In such a context the underlying
* FC port hardware would have gone through an OFFLINE to ONLINE transition
* (hardware state). In this case, the port driver may need to rediscover the
* topology, perform LOGINs, register with the name server again and perform
* any such port initialization procedures. To perform LOGINs, the driver could
* use the port device handle to see if a LOGIN needs to be performed and use
* the D_ID and WWN in it. The LOGINs may fail (if the hardware is reconfigured
* or removed) which will be reflected in the map the ULPs will see.
*/
static int
{
return (DDI_FAILURE);
}
/*
* If there are commands queued for delayed retry, instead of
* working the hard way to figure out which ones are good for
* restart and which ones not (ELSs are definitely not good
* as the port will have to go through a new spin of rediscovery
* now), so just flush them out.
*/
}
}
port->fp_dev_count) {
}
if (port->fp_job_head) {
}
} else {
struct job_request *job;
/*
* If an OFFLINE timer was running at the time of
* suspending, there is no need to restart it as
* the port is ONLINE now.
*/
if (port->fp_statec_busy == 0) {
}
port->fp_statec_busy++;
}
return (DDI_SUCCESS);
}
/*
* At this time, there shouldn't be any I/O requests on this port.
* But the unsolicited callbacks from the underlying FCA port need
* to be handled very carefully. The steps followed to handle the
* DDI_DETACH are:
* + Grab the port driver mutex, check if the unsolicited
* callback is currently under processing. If true, fail
* the DDI_DETACH request by printing a message; If false
* mark the DDI_DETACH as under progress, so that any
* further unsolicited callbacks get bounced.
* structures.
* + Get the job_handler thread to gracefully exit.
* + Unregister callbacks with the FCA port.
* + Now that some peace is found, notify all the ULPs of
* DDI_DETACH request (using ulp_port_detach entry point)
* + Free all mutexes, semaphores, conditional variables.
* + Free the soft state, return success.
*
* Important considerations:
* Port driver de-registers state change and unsolicited
* callbacks before taking up the task of notifying ULPs
* and performing PRLO and LOGOs.
*
* requested. It is expected of all FCA drivers to fail
* such requests either immediately with a FC_OFFLINE
* return code to fc_fca_transport() or return the packet
* asynchronously with pkt state set to FC_PKT_PORT_OFFLINE
*/
static int
{
/*
* In a Fabric topology with many host ports connected to
* a switch, another detaching instance of fp might have
* triggered a LOGO (which is an unsolicited request to
* this instance). So in order to be able to successfully
* detach by taking care of such cases a delay of about
* 30 seconds is introduced.
*/
delay_count = 0;
while ((port->fp_soft_state &
(delay_count < 30)) {
delay_count++;
}
if (port->fp_soft_state &
return (DDI_FAILURE);
}
/*
* If we're powered down, we need to raise power prior to submitting
* the JOB_PORT_SHUTDOWN job. Otherwise, the job handler will never
* process the shutdown job.
*/
if (fctl_busy_port(port) != 0) {
port->fp_instance);
return (DDI_FAILURE);
}
/*
* This will deallocate data structs and cause the "job" thread
* to exit, in preparation for DDI_DETACH on the instance.
* This can sleep for an arbitrary duration, since it waits for
* commands over the wire, timeout(9F) callbacks, etc.
*
* CAUTION: There is still a race here, where the "job" thread
* can still be executing code even tho the fctl_jobwait() call
* below has returned to us. In theory the fp driver could even be
* modunloaded even tho the job thread isn't done executing.
* without creating the race condition.
*/
}
if (port->fp_ub_tokens) {
}
}
}
if (port->fp_did_table) {
sizeof (struct d_id_hash));
}
if (port->fp_pwwn_table) {
sizeof (struct pwwn_hash));
}
while (orp) {
}
return (DDI_SUCCESS);
}
/*
* Steps to perform DDI_SUSPEND operation on a FC port
*
* - If already suspended return DDI_FAILURE
* - If already power-suspended return DDI_SUCCESS
* - If an unsolicited callback or state change handling is in
* in progress, throw a warning message, return DDI_FAILURE
* - Cancel timeouts
* - SUSPEND the job_handler thread (means do nothing as it is
* taken care of by the CPR frame work)
*/
static int
{
/*
* The following should never happen, but
* let the driver be more defensive here
*/
return (DDI_FAILURE);
}
/*
* If the port is already power suspended, there
* is nothing else to do, So return DDI_SUCCESS,
* but mark the SUSPEND bit in the soft state
* before leaving.
*/
return (DDI_SUCCESS);
}
/*
* Check if an unsolicited callback or state change handling is
* in progress. If true, fail the suspend operation; also throw
* a warning message notifying the failure. Note that Sun PCI
* hotplug spec recommends messages in cases of failure (but
* not flooding the console)
*
* Busy waiting for a short interval (500 millisecond ?) to see
* if the callback processing completes may be another idea. Since
* most of the callback processing involves a lot of work, it
* is safe to just fail the SUSPEND operation. It is definitely
* not bad to fail the SUSPEND operation if the driver is busy.
*/
delay_count = 0;
delay_count++;
}
return (DDI_FAILURE);
}
/*
* Check of FC port thread is busy
*/
if (port->fp_job_head) {
"FC port thread is busy: Failing suspend");
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/*
* Prepare for graceful power down of a FC port
*/
static int
{
/*
* Power down request followed by a DDI_SUSPEND should
* never happen; If it does return DDI_SUCCESS
*/
return (DDI_SUCCESS);
}
/*
* If the port is already power suspended, there
* is nothing else to do, So return DDI_SUCCESS,
*/
return (DDI_SUCCESS);
}
/*
* Check if an unsolicited callback or state change handling
* is in progress. If true, fail the PM suspend operation.
* But don't print a message unless the verbosity of the
* driver desires otherwise.
*/
"Unsolicited callback in progress: Failing power down");
return (DDI_FAILURE);
}
/*
* Check of FC port thread is busy
*/
if (port->fp_job_head) {
"FC port thread is busy: Failing power down");
return (DDI_FAILURE);
}
/*
* check if the ULPs are ready for power down
*/
&modlinkage) != FC_SUCCESS) {
/*
* Power back up the obedient ULPs that went down
*/
"ULP(s) busy, detach_ulps failed. Failing power down");
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/*
* Suspend the entire FC port
*/
static void
{
int index;
if (port->fp_wait_tid != 0) {
}
if (port->fp_offline_tid) {
}
/*
* Mark all devices as OLD, and reset the LOGIN state as well
* (this will force the ULPs to perform a LOGIN after calling
*/
pd->pd_login_count = 0;
}
}
}
/*
* fp_cache_constructor: Constructor function for kmem_cache_create(9F).
* Performs intializations for fc_packet_t structs.
* Returns 0 for success or -1 for failure.
*
* This function allocates DMA handles for both command and responses.
* Most of the ELSs used have both command and responses so it is strongly
* desired to move them to cache constructor routine.
*
* Context: Can sleep iff called with KM_SLEEP flag.
*/
static int
{
cmd->cmd_dflags = 0;
return (-1);
}
return (-1);
}
pkt->pkt_data_cookie_cnt = 0;
return (0);
}
/*
* fp_cache_destructor: Destructor function for kmem_cache_create().
* Performs un-intializations for fc_packet_t structs.
*/
/* ARGSUSED */
static void
{
if (pkt->pkt_cmd_dma) {
}
if (pkt->pkt_resp_dma) {
}
}
/*
* Packet allocation for ELS and any other port driver commands
*
* Some ELSs like FLOGI and PLOGI are critical for topology and
* device discovery and a system's inability to allocate memory
* or DVMA resources while performing some of these critical ELSs
* cause a lot of problem. While memory allocation failures are
* rare, DVMA resource failures are common as the applications
* are becoming more and more powerful on huge servers. So it
* is desirable to have a framework support to reserve a fragment
* of DVMA. So until this is fixed the correct way, the suffering
* is huge whenever a LIP happens at a time DVMA resources are
* drained out completely - So an attempt needs to be made to
* KM_SLEEP while requesting for these resources, hoping that
* the requests won't hang forever.
*
* The fc_remote_port_t argument is stored into the pkt_pd field in the
* fc_packet_t struct prior to the fc_ulp_init_packet() call. This
* ensures that the pd_ref_count for the fc_remote_port_t is valid.
* If there is no fc_remote_port_t associated with the fc_packet_t, then
* fp_alloc_pkt() must be called with pd set to NULL.
*/
static fp_cmd_t *
{
int rval;
return (cmd);
}
pkt->pkt_datalen = 0;
pkt->pkt_action = 0;
pkt->pkt_reason = 0;
/*
* Init pkt_pd with the given pointer; this must be done _before_
* the call to fc_ulp_init_packet().
*/
/* Now call the FCA driver to init its private, per-packet fields */
goto alloc_pkt_failed;
}
if (cmd_len) {
&pkt->pkt_cmd_acc);
if (rval != DDI_SUCCESS) {
goto alloc_pkt_failed;
}
goto alloc_pkt_failed;
}
if (rval != DDI_DMA_MAPPED) {
goto alloc_pkt_failed;
}
if (pkt->pkt_cmd_cookie_cnt >
goto alloc_pkt_failed;
}
goto alloc_pkt_failed;
}
*cp = pkt_cookie;
cp++;
*cp = pkt_cookie;
}
}
if (resp_len) {
&pkt->pkt_resp_acc);
if (rval != DDI_SUCCESS) {
goto alloc_pkt_failed;
}
goto alloc_pkt_failed;
}
if (rval != DDI_DMA_MAPPED) {
goto alloc_pkt_failed;
}
if (pkt->pkt_resp_cookie_cnt >
goto alloc_pkt_failed;
}
goto alloc_pkt_failed;
}
*cp = pkt_cookie;
cp++;
*cp = pkt_cookie;
}
}
return (cmd);
}
}
return (NULL);
}
/*
* Free FC packet
*/
static void
{
pkt->pkt_ulp_private = 0;
pkt->pkt_tran_flags = 0;
pkt->pkt_tran_type = 0;
sizeof (ddi_dma_cookie_t));
}
sizeof (ddi_dma_cookie_t));
}
}
/*
* Release DVMA resources
*/
static void
{
pkt->pkt_cmdlen = 0;
pkt->pkt_rsplen = 0;
pkt->pkt_tran_type = 0;
pkt->pkt_tran_flags = 0;
}
if (pkt->pkt_cmd_acc) {
}
}
}
if (pkt->pkt_resp_acc) {
}
}
cmd->cmd_dflags = 0;
}
/*
* Dedicated thread to perform various activities. One thread for
* each fc_local_port_t (driver soft state) instance.
* Note, this effectively works out to one thread for each local
* port, but there are also some Solaris taskq threads in use on a per-local
* port basis; these also need to be taken into consideration.
*/
static void
{
int rval;
#ifndef __lock_lint
/*
* Solaris-internal stuff for proper operation of kernel threads
* with Solaris CPR.
*/
callb_generic_cpr, "fp_job_handler");
#endif
/* Loop forever waiting for work to do */
for (;;) {
/*
* Sleep if no work to do right now, or if we want
* to suspend or power-down.
*/
FP_SOFT_SUSPEND))) {
}
/*
* OK, we've just been woken up, so retrieve the next entry
* from the head of the job queue for this local port.
*/
/*
* Handle all the fp driver's supported job codes here
* in this big honkin' switch.
*/
case JOB_PORT_SHUTDOWN:
/*
* fp_port_shutdown() is only called from here. This
* will prepare the local port instance (softstate)
* for detaching. This cancels timeout callbacks,
* executes LOGOs with remote ports, cleans up tables,
* and deallocates data structs.
*/
/*
* This will exit the job thread.
*/
#ifndef __lock_lint
#else
#endif
thread_exit();
/* NOTREACHED */
case JOB_ATTACH_ULP: {
/*
* This job is spawned in response to a ULP calling
* fc_ulp_add().
*/
/*
* If fp is detaching, we don't want to call
* fp_startup_done as this asynchronous
* notification may interfere with the re-attach.
*/
} else {
/*
* We are going to force the transport
* to attach to the ULPs, so set
* fp_ulp_attach. This will keep any
* potential detach from occurring until
* we are done.
*/
}
/*
* NOTE: Since we just dropped the mutex, there is now
* a race window where the fp_soft_state check above
* could change here. This race is covered because an
* additional check was added in the functions hidden
* under fp_startup_done().
*/
if (do_attach_ulps == B_TRUE) {
/*
* This goes thru a bit of a convoluted call
* chain before spawning off a DDI taskq
* request to perform the actual attach
* operations. Blocking can occur at a number
* of points.
*/
}
break;
}
case JOB_ULP_NOTIFY: {
/*
* registered ULPs.
*/
if (statec == FC_STATE_RESET_REQUESTED) {
fp_port_offline(port, 0);
}
if (--port->fp_statec_busy == 0) {
}
break;
}
case JOB_PLOGI_ONE:
/*
* Issue a PLOGI to a single remote port. Multiple
* PLOGIs to different remote ports may occur in
* parallel.
* This can create the fc_remote_port_t if it does not
* already exist.
*/
if (pd) {
pd->pd_login_count++;
break;
}
} else {
break;
}
} else {
}
}
if (rval != FC_SUCCESS) {
}
break;
case JOB_LOGO_ONE: {
/*
* Issue a PLOGO to a single remote port. Multiple
* PLOGOs to different remote ports may occur in
* parallel.
*/
#ifndef __lock_lint
#endif
break;
}
pd->pd_login_count--;
break;
}
break;
}
case JOB_FCIO_LOGIN:
/*
* PLOGI initiated at ioctl request.
*/
job->job_result =
break;
case JOB_FCIO_LOGOUT:
/*
* PLOGO initiated at ioctl request.
*/
job->job_result =
break;
case JOB_PORT_GETMAP:
case JOB_PORT_GETMAP_PLOGI_ALL: {
switch (port->fp_topology) {
case FC_TOP_PRIVATE_LOOP:
break;
case FC_TOP_PUBLIC_LOOP:
case FC_TOP_FABRIC:
break;
case FC_TOP_PT_PT:
break;
default:
break;
}
break;
}
case JOB_PORT_OFFLINE: {
fp_port_offline(port, 0);
if (--port->fp_statec_busy == 0) {
port->fp_soft_state &=
}
} else {
}
break;
}
case JOB_PORT_STARTUP: {
break;
}
"Topology discovery failed");
break;
}
/*
* Attempt building device handles in case
* of private Loop.
*/
}
/*
* Hack to avoid state changes going up early
*/
port->fp_statec_busy++;
}
break;
}
case JOB_PORT_ONLINE: {
char *newtop;
char *oldtop;
/*
* Bail out early if there are a lot of
* state changes in the pipeline
*/
--port->fp_statec_busy;
break;
}
case FC_TOP_PRIVATE_LOOP:
oldtop = "Private Loop";
break;
case FC_TOP_PUBLIC_LOOP:
oldtop = "Public Loop";
break;
case FC_TOP_PT_PT:
oldtop = "Point to Point";
break;
case FC_TOP_FABRIC:
oldtop = "Fabric";
break;
default:
break;
}
--port->fp_statec_busy;
break;
}
"Topology discovery failed");
if (--port->fp_statec_busy == 0) {
port->fp_soft_state &=
}
}
break;
}
switch (port->fp_topology) {
case FC_TOP_PRIVATE_LOOP:
newtop = "Private Loop";
break;
case FC_TOP_PUBLIC_LOOP:
newtop = "Public Loop";
break;
case FC_TOP_PT_PT:
newtop = "Point to Point";
break;
case FC_TOP_FABRIC:
newtop = "Fabric";
break;
default:
break;
}
"Change in FC Topology old = %s new = %s",
}
switch (port->fp_topology) {
case FC_TOP_PRIVATE_LOOP: {
break;
}
case FC_TOP_PUBLIC_LOOP:
/* FALLTHROUGH */
case FC_TOP_FABRIC:
break;
case FC_TOP_PT_PT:
break;
default:
if (--port->fp_statec_busy != 0) {
/*
* Watch curiously at what the next
* state transition can do.
*/
break;
}
"Topology Unknown, Offlining the port..");
}
break;
}
break;
}
case JOB_PLOGI_GROUP: {
break;
}
case JOB_UNSOL_REQUEST: {
break;
}
case JOB_NS_CMD: {
break;
}
break;
}
if (rval != FC_SUCCESS) {
}
break;
}
if (rval != FC_SUCCESS) {
}
break;
}
case JOB_LINK_RESET: {
topology == FC_TOP_PRIVATE_LOOP) {
} else {
JOB_TYPE_FP_ASYNC) == 0);
if (FC_IS_TOP_SWITCH(topology)) {
} else {
rval = FC_FAILURE;
}
if (rval != FC_SUCCESS) {
}
}
break;
}
default:
break;
}
}
/* NOTREACHED */
}
/*
* Perform FC port bring up initialization
*/
static int
{
int rval;
if (state == FC_STATE_OFFLINE) {
return (FC_OFFLINE);
}
if (state == FC_STATE_LOOP) {
"LILP map Invalid or not present");
return (FC_FAILURE);
}
if (lilp_map->lilp_length == 0) {
"LILP map length zero");
return (FC_NO_MAP);
}
} else {
int pd_recepient;
/*
* Get P2P remote port info if possible
*/
if (rval == FC_SUCCESS) {
return (FC_SUCCESS);
}
src_id = 0;
}
KM_SLEEP)) != FC_SUCCESS) {
"Couldn't transport FLOGI");
}
return (FC_FAILURE);
}
}
} else {
if (state == FC_STATE_LOOP) {
}
}
return (FC_SUCCESS);
}
/*
* Perform ULP invocations following FC port startup
*/
/* ARGSUSED */
static void
{
}
/*
* Perform ULP port attach
*/
static void
fp_ulp_port_attach(void *arg)
{
}
}
/*
* Entry point to funnel all requests down to FCAs
*/
static int
{
int rval;
FC_STATE_OFFLINE))) {
/*
* This means there is more than one state change
* at this point of time - Since they are processed
* serially, any processing of the current one should
* be failed, failed and move up in processing the next
*/
/*
* A state change that is going to be invalidated
* by another one already in the port driver's queue
* need not go up to all ULPs. This will minimize
* needless processing and ripples in ULP modules
*/
}
return (FC_STATEC_BUSY);
}
return (FC_OFFLINE);
}
if (rval != FC_SUCCESS) {
if (rval == FC_TRAN_BUSY) {
if (rval == FC_FAILURE) {
}
}
}
return (rval);
}
/*
* Each time a timeout kicks in, walk the wait queue, decrement the
* the retry_interval, when the retry_interval becomes less than
* or equal to zero, re-transport the command: If the re-transport
* fails with BUSY, enqueue the command in the wait queue.
*
* In order to prevent looping forever because of commands enqueued
* from within this function itself, save the current tail pointer
* (in cur_tail) and exit the loop after serving this command.
*/
static void
fp_resendcmd(void *port_handle)
{
int rval;
port = port_handle;
/* Check if we are detaching */
if (port->fp_soft_state &
} else if (cmd->cmd_retry_interval <= 0) {
if (rval != FC_SUCCESS) {
if (--cmd->cmd_retry_count) {
break;
}
continue;
}
} else {
}
}
} else {
}
break;
}
}
if (port->fp_wait_head) {
} else {
}
}
/*
* Handle Local, Fabric, N_Port, Transport (whatever that means) BUSY here.
*
* Yes, as you can see below, cmd_retry_count is used here too. That means
* the retries for BUSY are less if there were transport failures (transport
* failure means fca_transport failure). The goal is not to exceed overall
* retries set in the cmd_retry_count (whatever may be the reason for retry)
*
* Return Values:
* FC_SUCCESS
* FC_FAILURE
*/
static int
{
if (--cmd->cmd_retry_count) {
return (FC_SUCCESS);
} else {
return (FC_FAILURE);
}
}
/*
* Queue up FC packet for deferred retry
*/
static void
{
#ifdef DEBUG
#endif
if (port->fp_wait_tail) {
} else {
}
}
}
/*
* Handle all RJT codes
*/
static int
{
int rval = FC_FAILURE;
case FC_PKT_FABRIC_RJT:
case FC_PKT_NPORT_RJT:
if (next_class == FC_TRAN_CLASS_INVALID) {
return (rval);
}
if (rval != FC_SUCCESS) {
}
}
break;
case FC_PKT_LS_RJT:
case FC_PKT_BA_RJT:
}
break;
case FC_PKT_FS_RJT:
}
break;
case FC_PKT_LOCAL_RJT:
}
break;
default:
"fp_handle_reject(): Invalid pkt_state");
break;
}
return (rval);
}
/*
* Return the next class of service supported by the FCA
*/
static uchar_t
{
switch (cur_class) {
case FC_TRAN_CLASS_INVALID:
break;
}
/* FALLTHROUGH */
case FC_TRAN_CLASS1:
break;
}
/* FALLTHROUGH */
case FC_TRAN_CLASS2:
break;
}
/* FALLTHROUGH */
case FC_TRAN_CLASS3:
default:
break;
}
return (next_class);
}
/*
* Determine if a class of service is supported by the FCA
*/
static int
{
int rval;
switch (tran_class) {
case FC_TRAN_CLASS1:
if (cos & FC_NS_CLASS1) {
rval = FC_SUCCESS;
} else {
rval = FC_FAILURE;
}
break;
case FC_TRAN_CLASS2:
if (cos & FC_NS_CLASS2) {
rval = FC_SUCCESS;
} else {
rval = FC_FAILURE;
}
break;
case FC_TRAN_CLASS3:
if (cos & FC_NS_CLASS3) {
rval = FC_SUCCESS;
} else {
rval = FC_FAILURE;
}
break;
default:
rval = FC_FAILURE;
break;
}
return (rval);
}
/*
* Dequeue FC packet for retry
*/
static fp_cmd_t *
{
/*
* To avoid races, NULL the fp_wait_tid as
* we are about to exit the timeout thread.
*/
return (NULL);
}
}
return (cmd);
}
/*
* Wait for job completion
*/
static void
{
}
/*
* Convert FC packet state to FC errno
*/
int
{
int count;
}
}
return (FC_FAILURE);
}
/*
* For Synchronous I/O requests, the caller is
* expected to do fctl_jobdone(if necessary)
*
* We want to preserve at least one failure in the
* job_result if it happens.
*
*/
static void
{
}
if (pd) {
}
if (ulp_pkt) {
pd->pd_ref_count--;
}
}
}
}
/*
* Job completion handler
*/
static void
{
if (--job->job_counter != 0) {
return;
}
if (job->job_ulp_pkts) {
}
} else {
}
}
/*
* Try to perform shutdown of a port during a detach. No return
* value since the detach should not fail because the port shutdown
* failed.
*/
static void
{
int index;
int count;
int flags;
/*
* We must release the mutex here to ensure that other
* potential jobs can complete their processing. Many
* also need this mutex.
*/
}
if (port->fp_offline_tid) {
}
if (port->fp_wait_tid) {
} else {
}
/*
* While we cancel the timeout, let's also return the
* the outstanding requests back to the callers.
*/
}
/*
* Gracefully LOGO with all the devices logged in.
*/
count++;
}
}
}
} else {
flags = 0;
}
if (count) {
/*
* Force the counter to ONE in order
* for us to really send LOGO els.
*/
} else {
}
}
}
} else {
}
"Can't logout all devices. Proceeding with"
" port shutdown");
}
} else {
}
if (flags) {
}
}
/*
* Build the port driver's data structures based on the AL_PA list
*/
static void
{
int rval;
int flag;
int count;
return;
}
return;
}
} else {
}
continue;
}
if (pd) {
if (flag == FP_CMD_PLOGI_DONT_CARE ||
continue;
}
}
if (rval != FC_SUCCESS) {
}
}
}
/*
* Perform loop ONLINE processing
*/
static void
{
int count;
int rval;
if (lilp_map->lilp_length) {
} else {
}
continue;
}
#ifdef DEBUG
}
#endif
continue;
}
if (rval != FC_SUCCESS) {
}
}
}
listlen = 0;
changelist = NULL;
1, 0, orphan);
}
} else {
}
}
} else {
if (--port->fp_statec_busy == 0) {
}
}
}
/*
* Get an Arbitrated Loop map from the underlying FCA
*/
static int
{
int rval;
if (rval != FC_SUCCESS) {
} else if (lilp_map->lilp_length == 0 &&
/*
* Since the map length is zero, provide all
* the valid AL_PAs for NL_ports discovery.
*/
lilp_length = sizeof (fp_valid_alpas) /
sizeof (fp_valid_alpas[0]);
} else {
if (rval == FC_SUCCESS) {
}
}
FC_FCA_RESET_CORE) != FC_SUCCESS) {
"FCA reset failed after LILP map was found"
" to be invalid");
}
} else if (rval == FC_SUCCESS) {
} else {
}
lilp_map);
return (rval);
}
/*
* Perform Fabric Login:
*
* Return Values:
* FC_SUCCESS
* FC_FAILURE
* FC_NOMEM
* FC_TRANSPORT_ERROR
* and a lot others defined in fc_error.h
*/
static int
{
int rval;
if (class == FC_TRAN_CLASS_INVALID) {
return (FC_ELS_BAD);
}
return (FC_NOMEM);
}
job, LA_ELS_FLOGI);
if (rval != FC_SUCCESS) {
}
return (rval);
}
/*
* In some scenarios such as private loop device discovery period
* the fc_remote_port_t data structure isn't allocated. The allocation
* is done when the PLOGI is successful. In some other scenarios
* such as Fabric topology, the fc_remote_port_t is already created
* and initialized with appropriate values (as the NS provides
* them)
*/
static int
{
int relogin;
int found = 0;
#ifdef DEBUG
}
#endif
if (class == FC_TRAN_CLASS_INVALID) {
return (FC_ELS_BAD);
}
relogin = 1;
if (tmp_pd) {
relogin = 0;
}
}
if (!relogin) {
}
return (FC_NOMEM);
}
} else {
return (FC_NOMEM);
}
job, LA_ELS_PLOGI);
}
if (pd) {
}
/* npiv check to make sure we don't log into ourself */
if ((d_id & 0xffff00) ==
found = 1;
}
}
if (found ||
if (found) {
}
if (pd) {
}
if (ulp_pkt) {
}
}
return (FC_SUCCESS);
}
/*
* Register the LOGIN parameters with a port device
*/
static void
{
if (pd->pd_login_count == 0) {
pd->pd_login_count++;
}
if (handle) {
} else {
}
#ifndef __lock_lint
#endif
if (handle) {
} else {
}
}
/*
* Mark the remote port as OFFLINE
*/
static void
{
if (pd->pd_login_count &&
pd->pd_login_class = 0;
}
}
/*
* Deregistration of a port device
*/
static void
{
pd->pd_login_count = 0;
pd->pd_login_class = 0;
}
/*
* Handle OFFLINE state of an FCA port
*/
static void
{
int index;
int statec;
}
}
port->fp_total_devices = 0;
statec = 0;
if (notify) {
/*
* Decrement the statec busy counter as we
* are almost done with handling the state
* change
*/
if (--port->fp_statec_busy == 0) {
}
0, 0, KM_SLEEP);
if (port->fp_statec_busy) {
statec++;
}
statec++;
}
}
if (!statec) {
}
}
/*
* Offline devices and send up a state change notification to ULPs
*/
static void
fp_offline_timeout(void *port_handle)
{
int ret;
(port->fp_soft_state &
return;
}
FC_FCA_CORE)) != FC_SUCCESS) {
"Failed to force adapter dump");
} else {
"Forced adapter dump successfully");
}
FC_FCA_RESET_CORE)) != FC_SUCCESS) {
"Failed to force adapter dump and reset");
} else {
"Forced adapter dump and reset successfully");
}
}
}
/*
* Perform general purpose ELS request initialization
*/
static void
{
}
/*
*/
static void
{
}
/*
* Initialize LOGO ELS request
*/
static void
{
fp_logo_intr, job);
}
/*
* Initialize RNID ELS request
*/
static void
{
fp_rnid_intr, job);
}
/*
* Initialize RLS ELS request
*/
static void
{
fp_rls_intr, job);
}
/*
* Initialize an ADISC ELS request
*/
static void
{
fp_adisc_intr, job);
}
/*
* Send up a state change notification to ULPs.
* Spawns a call to fctl_ulp_statec_cb in a taskq thread.
*/
static int
{
int count;
return (FC_NOMEM);
}
/*
* Bump the reference count of each fc_remote_port_t in this changelist.
* This is necessary since these devices will be sitting in a taskq
* and referenced later. When the state change notification is
* complete, the reference counts will be decremented.
*/
pd->pd_ref_count++;
}
}
}
#ifdef DEBUG
/*
* Sanity check for presence of OLD devices in the hash lists
*/
if (clist->clist_size) {
}
}
}
#endif
if (state == FC_STATE_ONLINE) {
if (--port->fp_statec_busy == 0) {
}
}
return (FC_SUCCESS);
}
/*
* Send up a FC_STATE_DEVICE_CHANGE state notification to ULPs
*/
static int
{
int ret;
return (FC_NOMEM);
}
/* Send sysevents for target state changes */
if (clist->clist_size) {
int count;
/*
* Bump reference counts on all fc_remote_port_t
* structs in this list. We don't know when the task
* will fire, and we don't need these fc_remote_port_t
* structs going away behind our back.
*/
if (pd) {
pd->pd_ref_count++;
}
/* Update our state change counter */
port->fp_last_change++;
/* Additions */
port_id);
}
PORT_DEVICE_OLD) &&
/* Update our state change counter */
port->fp_last_change++;
/*
* For removals, we don't decrement
* pd_ref_count until after the ULP's
* state change callback function has
* completed.
*/
/* Removals */
}
/*
* Indicate that the ULPs are now aware of
* this device.
*/
}
#ifdef DEBUG
/*
* Sanity check for OLD devices in the hash lists
*/
/*
* This overwrites the 'pd' local variable.
* Beware of this if 'pd' ever gets
* referenced below this block.
*/
}
#endif
}
}
if (sync) {
}
while (clist->clist_wait) {
}
}
if (!ret) {
"port=%p", port);
} else {
}
return (FC_SUCCESS);
}
/*
* Perform PLOGI to the group of devices for ULPs
*/
static void
{
int offline;
int count;
int rval;
done = 0;
sizeof (la_els_logi_t));
if (offline) {
done++;
continue;
}
continue;
}
done++;
} else {
}
continue;
}
case FC_PKT_ELS_IN_PROGRESS:
/* FALLTHRU */
case FC_PKT_LOCAL_RJT:
done++;
continue;
default:
break;
}
/*
* Validate the pd corresponding to the d_id passed
* by the ULPs
*/
done++;
continue;
}
done++;
sizeof (ls_code_t), DDI_DEV_AUTOINCR);
pd->pd_login_count++;
} else {
}
}
}
return;
}
int cmd_flags;
continue;
}
} else {
#ifdef DEBUG
#endif
/*
* In the Fabric topology, use NS to create
* port device, and if that fails still try
* with PLOGI - which will make yet another
* attempt to create after successful PLOGI
*/
if (pd) {
"fp_plogi_group;"
" NS created PD port=%p, job=%p,"
}
} else {
}
"fp_plogi_group;"
"ulp_pkt's pd is NULL, get a pd %p",
pd);
pd->pd_ref_count++;
}
}
if (rval == FC_SUCCESS) {
continue;
}
if (rval == FC_STATEC_BUSY) {
} else {
}
if (pd) {
}
if (cmd_flags & FP_CMD_DELDEV_ON_ERROR) {
pd->pd_ref_count--;
}
}
}
}
/*
* Name server request initialization
*/
static void
{
int rval;
int count;
int size;
if (rval != FC_SUCCESS) {
return;
}
return;
}
/*
* At this time, we'll do NS registration for objects in the
* ns_reg_cmds (see top of this file) array.
*
* Each time a ULP module registers with the transport, the
* appropriate fc4 bit is set fc4 types and registered with
* the NS for this support. Also, ULPs and FC admin utilities
* may do registration for objects like IP address, symbolic
*/
}
}
if (size) {
}
}
sleep) == FC_SUCCESS) {
}
}
/*
* Name server finish:
* Unregister for RSCNs
* Unregister all the host port objects in the Name Server
* Perform LOGO with the NS;
*/
static void
{
FC_SUCCESS) {
}
}
} else {
}
}
}
/*
* NS Registration function.
*
* It should be seriously noted that FC-GS-2 currently doesn't support
* an Object Registration by a D_ID other than the owner of the object.
* Name registration for any N_Port Identifier by the host software.
*
* Anyway, if the second argument (fc_remote_port_t *) is NULL, this
* function treats the request as Host NS Object.
*/
static int
{
int rval;
} else {
}
if (polled) {
}
switch (cmd_code) {
case NS_RPN_ID:
case NS_RNN_ID: {
return (FC_NOMEM);
}
} else {
} else {
}
}
sizeof (rxn), DDI_DEV_AUTOINCR);
break;
}
case NS_RCS_ID: {
return (FC_NOMEM);
}
} else {
}
sizeof (rcos), DDI_DEV_AUTOINCR);
break;
}
case NS_RFT_ID: {
NULL);
return (FC_NOMEM);
}
sizeof (port->fp_fc4_types));
} else {
sizeof (pd->pd_fc4types));
}
sizeof (rfc), DDI_DEV_AUTOINCR);
break;
}
case NS_RSPN_ID: {
int pl_size;
} else {
}
return (FC_NOMEM);
}
} else {
}
break;
}
case NS_RPT_ID: {
return (FC_NOMEM);
}
} else {
}
sizeof (rpt), DDI_DEV_AUTOINCR);
break;
}
case NS_RIP_NN: {
return (FC_NOMEM);
}
sizeof (port->fp_ip_addr));
} else {
/*
* The most correct implementation should have the IP
* address in the fc_remote_node_t structure; I believe
* Node WWN and IP address should have one to one
* correlation (but guess what this is changing in
* FC-GS-2 latest draft)
*/
sizeof (pd->pd_ip_addr));
}
sizeof (rip), DDI_DEV_AUTOINCR);
break;
}
case NS_RIPA_NN: {
return (FC_NOMEM);
}
} else {
}
sizeof (ipa), DDI_DEV_AUTOINCR);
break;
}
case NS_RSNN_NN: {
int pl_size;
} else {
}
return (FC_NOMEM);
}
} else {
}
sizeof (snn), DDI_DEV_AUTOINCR);
+ sizeof (fc_ct_header_t) + sizeof (snn)),
1, DDI_DEV_AUTOINCR);
break;
}
case NS_DA_ID: {
char tmp[4] = {0};
char *ptr;
return (FC_NOMEM);
}
#if defined(_BIT_FIELDS_LTOH)
#else
#endif
sizeof (rall), DDI_DEV_AUTOINCR);
break;
}
default:
return (FC_FAILURE);
}
if (rval != FC_SUCCESS) {
}
if (polled) {
} else {
rval = FC_SUCCESS;
}
return (rval);
}
/*
* Common interrupt handler
*/
static int
{
int rval = FC_FAILURE;
/*
* Fail fast the upper layer requests if
* a state change has occurred amidst.
*/
} else if (!(port->fp_soft_state &
case FC_PKT_LOCAL_BSY:
case FC_PKT_FABRIC_BSY:
case FC_PKT_NPORT_BSY:
case FC_PKT_TIMEOUT:
FC_PKT_TIMEOUT) ? 0 : fp_retry_delay;
break;
case FC_PKT_FABRIC_RJT:
case FC_PKT_NPORT_RJT:
case FC_PKT_LOCAL_RJT:
case FC_PKT_LS_RJT:
case FC_PKT_FS_RJT:
case FC_PKT_BA_RJT:
break;
default:
if (pkt->pkt_resp_resid) {
cmd->cmd_retry_interval = 0;
}
break;
}
} else {
}
rval = FC_SUCCESS;
}
return (rval);
}
/*
* Some not so long winding theory on point to point topology:
*
* In the ACC payload, if the D_ID is ZERO and the common service
* parameters indicate N_Port, then the topology is POINT TO POINT.
*
* In a point to point topology with an N_Port, during Fabric Login,
* the destination N_Port will check with our WWN and decide if it
* needs to issue PLOGI or not. That means, FLOGI could potentially
* trigger an unsolicited PLOGI from an N_Port. The Unsolicited
* PLOGI creates the device handles.
*
* Assuming that the host port WWN is greater than the other N_Port
* WWN, then we become the master (be aware that this isn't the word
* used in the FC standards) and initiate the PLOGI.
*
*/
static void
{
int state;
int f_port;
if (FP_IS_PKT_ERROR(pkt)) {
return;
}
/*
* Currently, we don't need to swap bytes here because qlc is faking the
* response for us and so endianness is getting taken care of. But we
* have to fix this and generalize this at some point
*/
sizeof (resp), DDI_DEV_AUTOINCR);
return;
}
/*
* Let us choose 'X' as S_ID and 'Y'
* as D_ID and that'll work; hopefully
* If not, it will get changed.
*/
0, NULL, "couldn't create device"
" d_id=%X", d_id);
return;
}
/*
* We've just created this fc_remote_port_t, and
* we're about to use it to send a PLOGI, so
* bump the reference count right now. When
* the packet is freed, the reference count will
* be decremented. The ULP may also start using
* it, so mark it as given away as well.
*/
pd->pd_ref_count++;
return;
}
} else {
/*
* The device handles will be created when the
* unsolicited PLOGI is completed successfully
*/
port->fp_ptpt_master = 0;
}
}
} else {
if (f_port) {
if (state == FC_STATE_LOOP) {
} else {
sizeof (la_wwn_t),
}
} else {
}
}
}
/*
* Handle solicited PLOGI response
*/
static void
{
int nl_port;
int bailout;
nl_port = 0;
#ifndef __lock_lint
#endif
/*
* Bail out early on ULP initiated requests if the
* state change has occurred
*/
int skip_msg = 0;
int giveup = 0;
if (cmd->cmd_ulp_pkt) {
}
/*
* If an unsolicited cross login already created
* a device speed up the discovery by not retrying
* the command mindlessly.
*/
return;
}
PD_PLOGI_RECEPIENT) ? 1 : 0;
if (giveup) {
/*
* This pd is marked as plogi
* recipient, stop retrying
*/
"fp_plogi_intr: stop retry as"
" a cross login was accepted"
" from d_id=%x, port=%p.",
return;
}
}
return;
}
skip_msg++;
}
}
/*
* In case of Login Collisions, JNI HBAs returns the
* FC pkt back to the Initiator with the state set to
* FC_PKT_LS_RJT and reason to FC_REASON_LOGICAL_ERROR.
* QLC HBAs handles such cases in the FW and doesnot
* return the LS_RJT with Logical error when
* login collision happens.
*/
"PLOGI to %x failed", d_id);
}
"PLOGI to %x failed. state=%x reason=%x.",
} else {
}
return;
}
sizeof (resp), DDI_DEV_AUTOINCR);
return;
}
return;
}
"couldn't create port device handles"
" d_id=%x", d_id);
return;
}
} else {
return;
}
}
} else {
}
}
char ww_name[17];
"Possible Duplicate name or address"
" identifiers in the PLOGI response"
" D_ID=%x, PWWN=%s: Please check the"
return;
}
}
} else {
}
} else {
char old_name[17];
char new_name[17];
"fp_plogi_intr: PWWN of a device with D_ID=%x "
"changed. New PWWN = %s, OLD PWWN = %s ; tmp_pd:%p "
"pd:%p new_wwn_pd:%p, cmd_ulp_pkt:%p, bailout:0x%x",
"PWWN of a device with D_ID=%x changed."
" New PWWN = %s, OLD PWWN = %s", d_id,
int len = 1;
/* # entries in changelist */
/*
* Lets now check if there already is a pd with
* this new WWN in the table. If so, we'll mark
* it as invalid
*/
if (new_wwn_pd) {
/*
* There is another pd with in the pwwn
* table with the same WWN that we got
* in the PLOGI payload. We have to get
* it out of the pwwn table, update the
* pd's state (fp_fillout_old_map does
* this for us) and add it to the
* changelist that goes up to ULPs.
*
* len is length of changelist and so
* increment it.
*/
len++;
/*
* Odd case where pwwn and did
* tables are out of sync but
* we will handle that too. See
* more comments below.
*
* One more device that ULPs
* should know about and so len
* gets incremented again.
*/
len++;
}
sizeof (*changelist), KM_SLEEP);
/*
* Hold the fd_mutex since
* fctl_copy_portmap_held expects it.
* Preserve lock hierarchy by grabbing
* fd_mutex before pd_mutex
*/
if (rnodep) {
}
new_wwn_pd, 0);
if (rnodep) {
}
/*
* Safety check :
* Lets ensure that the pwwn and did
* tables are in sync. Ideally, we
* should not find that these two pd's
* are different.
*/
rnodep =
/* As above grab fd_mutex */
if (rnodep) {
fd_mutex);
}
if (rnodep) {
mutex_exit(&rnodep->
fd_mutex);
}
/*
* Now add "pd" (not tmp_pd)
* to fp_did_table to sync it up
* with fp_pwwn_table
*
* pd->pd_mutex is already held
* at this point
*/
}
} else {
sizeof (*changelist), KM_SLEEP);
}
&pwwn);
len, KM_NOSLEEP, 0);
return;
}
}
nl_port = 1;
}
char ww_name[17];
"Possible Duplicate name or address"
" identifiers in the PLOGI response"
" D_ID=%x, PWWN=%s: Please check the"
return;
}
}
}
if (cmd->cmd_ulp_pkt) {
"fp_plogi_intr;"
"ulp_pkt's pd is NULL, get a pd %p",
pd);
pd->pd_ref_count++;
}
}
sizeof (fc_frame_hdr_t));
sizeof (la_els_logi_t));
}
/*
* If the fc_remote_port_t pointer is not set in the given
* fc_packet_t, then this fc_remote_port_t must have just
* been created. Save the pointer and also increment the
* fc_remote_port_t reference count.
*/
}
return;
}
} else {
}
return;
}
}
}
/*
* Handle solicited ADISC response
*/
static void
{
int rval;
int bailout;
#ifndef __lock_lint
#endif
if (bailout) {
return;
}
int is_private;
}
} else {
}
}
char ww_name[17];
"NL_Port Identifier %x doesn't match"
" with Hard Address %x, Will use Port"
} else {
}
} else {
return;
}
}
} else {
return;
}
"ADISC to %x failed, cmd_flags=%x",
adiscfail = 1;
} else {
}
}
if (cmd->cmd_ulp_pkt) {
"fp_adisc__intr;"
"ulp_pkt's pd is NULL, get a pd %p",
pd);
}
sizeof (fc_frame_hdr_t));
sizeof (la_els_logi_t));
}
"fp_adisc_intr: Perform LOGO.cmd_flags=%x, "
"fp_retry_count=%x, ulp_pkt=%p",
if (adiscfail) {
else
if (initiator) {
} else {
}
"fp_adisc_intr: Dev change notification "
"to ULP port=%p, pd=%p, map_type=%x map_state=%x "
}
if (rval == FC_SUCCESS) {
return;
}
}
}
/*
* Handle solicited LOGO response
*/
static void
{
if (FP_IS_PKT_ERROR(pkt)) {
return;
}
return;
}
}
}
/*
* Handle solicited RNID response
*/
static void
{
/* If failure or LS_RJT then retry the packet, if needed */
return;
}
/* Save node_id memory allocated in ioctl code */
/* wakeup the ioctl thread and free the pkt */
}
/*
* Handle solicited RLS response
*/
static void
{
/* If failure or LS_RJT then retry the packet, if needed */
return;
}
/* Save link error status block in memory allocated in ioctl code */
/* wakeup the ioctl thread and free the pkt */
}
/*
* A solicited command completion interrupt (mostly for commands
* that require almost no post processing such as SCR ELS)
*/
static void
{
if (FP_IS_PKT_ERROR(pkt)) {
return;
}
}
/*
* Handle the underlying port's state change
*/
static void
{
/*
* If it is not possible to process the callbacks
* just drop the callback on the floor; Don't bother
* to do something that isn't safe at this time
*/
if ((port->fp_soft_state &
return;
}
if (port->fp_statec_busy == 0) {
#ifdef DEBUG
} else {
#endif
}
port->fp_statec_busy++;
/*
* For now, force the trusted method of device authentication (by
* PLOGI) when LIPs do not involve OFFLINE to ONLINE transition.
*/
fp_port_offline(port, 0);
}
switch (FC_PORT_STATE_MASK(state)) {
case FC_STATE_OFFLINE:
" fp_statec_cb() couldn't submit a job "
" to the thread: failing..");
if (--port->fp_statec_busy == 0) {
}
return;
}
/*
* Zero out this field so that we do not retain
* the fabric name as its no longer valid
*/
break;
case FC_STATE_ONLINE:
case FC_STATE_LOOP:
if (port->fp_offline_tid) {
} else {
}
"fp_statec_cb() couldn't submit a job "
"to the thread: failing..");
if (--port->fp_statec_busy == 0) {
}
return;
}
break;
case FC_STATE_RESET_REQUESTED:
/* FALLTHROUGH */
case FC_STATE_RESET:
"fp_statec_cb() couldn't submit a job"
" to the thread: failing..");
if (--port->fp_statec_busy == 0) {
}
return;
}
/* squeeze into some field in the job structure */
break;
/* FALLTHROUGH */
case FC_STATE_NAMESERVICE:
/* FALLTHROUGH */
default:
if (--port->fp_statec_busy == 0) {
}
break;
}
}
/*
* Register with the Name Server for RSCNs
*/
static int
int sleep)
{
return (FC_NOMEM);
}
}
return (FC_SUCCESS);
}
/*
* There are basically two methods to determine the total number of
* devices out in the NS database; Reading the details of the two
* methods described below, it shouldn't be hard to identify which
* of the two methods is better.
*
* Method 1.
* Iteratively issue GANs until all ports identifiers are walked
*
* Method 2.
* Issue GID_PT (get port Identifiers) with Maximum residual
* field in the request CT HEADER set to accommodate only the
* CT HEADER in the response frame. And if FC-GS2 has been
* carefully read, the NS here has a chance to FS_ACC the
* request and indicate the residual size in the FS_ACC.
*
* Method 2 is wonderful, although it's not mandatory for the NS
* (note with particular care the use of the auxiliary verb 'may')
*
*/
static int
int sleep)
{
int flags;
int rval;
sizeof (ns_resp_gid_pt_t), 0,
return (FC_NOMEM);
}
= FC_NS_PORT_NX; /* All port types */
} else {
if (create) {
}
return (FC_NOMEM);
}
ns_cmd->ns_gan_index = 0;
}
/*
* Revert to scanning the NS if NS_GID_PT isn't
* helping us figure out total number of devices.
*/
}
if (max_resid) {
/*
* Since port identifier is 4 bytes and max_resid
* is also in WORDS, max_resid simply indicates
* the total number of port identifiers not
* transferred
*/
}
}
return (rval);
}
/*
* One heck of a function to serve userland.
*/
static int
{
int rval = 0;
int jcode;
#ifdef _MULTI_DATAMODEL
case DDI_MODEL_ILP32:
break;
case DDI_MODEL_NONE:
default:
break;
}
#endif
}
return (rval);
}
}
return (rval);
}
/*
* If an exclusive open was demanded during open, don't let
* either innocuous or devil threads to share the file
* descriptor and fire down exclusive access commands
*/
return (EBUSY);
}
}
case FCIO_GET_HOST_PARAMS: {
int index;
int lilp_device_count;
break;
}
} else {
break;
}
}
break;
}
}
sizeof (port->fp_fc4_types));
sizeof (port->fp_fc4_types));
}
} else {
}
} else {
}
} else {
}
}
/* need to free "val" here */
break;
}
case FCIO_GET_OTHER_ADAPTER_PORTS: {
char *tmpPath;
break;
}
break;
}
"User supplied index out of range");
}
break;
}
MAXPATHLEN, mode) == 0) {
}
} else {
}
break;
}
case FCIO_GET_ADAPTER_ATTRIBUTES: {
break;
}
} else {
break;
}
}
sizeof (val->Manufacturer));
sizeof (val->SerialNumber));
sizeof (val->ModelDescription));
sizeof (val->NodeSymbolicName));
sizeof (val->HardwareVersion));
sizeof (val->OptionROMVersion));
sizeof (val->FirmwareVersion));
sizeof (val->DriverName));
sizeof (val->DriverVersion));
} else {
}
sizeof (val->Manufacturer));
sizeof (val->SerialNumber));
sizeof (val->ModelDescription));
sizeof (val->NodeSymbolicName));
sizeof (val->HardwareVersion));
sizeof (val->OptionROMVersion));
sizeof (val->FirmwareVersion));
sizeof (val->DriverName));
sizeof (val->DriverVersion));
}
} else {
}
} else {
}
} else {
}
}
break;
}
case FCIO_GET_NPIV_ATTRIBUTES: {
}
} else {
}
break;
}
case FCIO_DELETE_NPIV_PORT: {
char ww_pname[17];
break;
}
"Delete NPIV Port %s", ww_pname);
"Delete NPIV Port : no found");
} else {
if (ret != DDI_SUCCESS) {
break;
}
NDI_DEVI_REMOVE) != DDI_SUCCESS) {
"Delete NPIV Port failed");
tmpport->fp_npiv_state = 0;
} else {
port->fp_port_next =
}
port->fp_npiv_portnum--;
"Delete NPIV Port %d", portindex);
}
}
break;
}
case FCIO_CREATE_NPIV_PORT: {
uint32_t vportindex = 0;
int npiv_ret = 0;
break;
}
"Create NPIV Port %s %s %d",
break;
}
if (npiv_ret == NDI_SUCCESS) {
port->fp_npiv_portnum++;
if (fp_copyout((void *)&vportindex,
}
} else {
}
} else {
}
break;
}
case FCIO_GET_NPIV_PORT_LIST: {
int count;
break;
}
/* build npiv port list */
if (count < 0) {
break;
}
"Copy NPIV Port data error");
}
} else {
}
break;
}
} else {
val->MaxNumberOfNPIVPorts = 0;
}
}
} else {
}
break;
}
case FCIO_GET_ADAPTER_PORT_ATTRIBUTES: {
break;
}
} else {
break;
}
}
case FC_STATE_OFFLINE:
break;
case FC_STATE_ONLINE:
case FC_STATE_LOOP:
case FC_STATE_NAMESERVICE:
break;
default:
break;
}
/* Translate from LV to FC-HBA port type codes */
case FC_NS_PORT_N:
break;
case FC_NS_PORT_NL: /* Actually means loop for us */
break;
case FC_NS_PORT_F:
break;
case FC_NS_PORT_FL:
break;
case FC_NS_PORT_E:
break;
default:
break;
}
/*
* If fp has decided that the topology is public loop,
* we will indicate that using the appropriate
* FC HBA API constant.
*/
switch (port->fp_topology) {
case FC_TOP_PUBLIC_LOOP:
break;
case FC_TOP_PT_PT:
break;
case FC_TOP_UNKNOWN:
/*
* This should cover the case where nothing is connected
* to the port. Crystal+ is p'bly an exception here.
* For Crystal+, port 0 will come up as private loop
* (i.e fp_bind_state will be FC_STATE_LOOP) even when
* nothing is connected to it.
* Current plan is to let userland handle this.
*/
break;
default:
/*
* Do Nothing.
* Unused:
* val->PortType = FC_HBA_PORTTYPE_GPORT;
*/
break;
}
val->PortSupportedFc4Types[0] = 0;
sizeof (val->PortActiveFc4Types));
sizeof (val->PortSymbolicName));
case FC_STATE_1GBIT_SPEED:
break;
case FC_STATE_2GBIT_SPEED:
break;
case FC_STATE_4GBIT_SPEED:
break;
case FC_STATE_8GBIT_SPEED:
break;
case FC_STATE_10GBIT_SPEED:
break;
case FC_STATE_16GBIT_SPEED:
break;
default:
break;
}
sizeof (val->PortActiveFc4Types));
sizeof (val->PortSymbolicName));
}
} else {
}
} else {
}
} else {
}
}
break;
}
break;
}
} else {
break;
}
}
break;
}
"User supplied index out of range");
}
break;
}
} else {
sizeof (val->PortSymbolicName));
/*
* we will assume the sizeof these pd_fc4types and
* portActiveFc4Types will remain the same. we could
* add in a check for it, but we decided it was unneeded
*/
sizeof (tmp_pd->pd_fc4types));
val->PortSupportedFc4Types[0] = 0;
val->PortMaxFrameSize = 0;
val->NumberofDiscoveredPorts = 0;
sizeof (val->PortSymbolicName));
sizeof (tmp_pd->pd_fc4types));
val32->PortSupportedFc4Types[0] =
val->PortSupportedFc4Types[0];
if (fp_copyout((void *)val32,
if (fp_fcio_copyout(fcio,
}
} else {
}
} else {
if (fp_copyout((void *)val,
}
} else {
}
}
}
break;
}
case FCIO_GET_PORT_ATTRIBUTES: {
break;
}
} else {
break;
}
}
break;
}
} else {
sizeof (val->PortSymbolicName));
val->PortSupportedFc4Types[0] = 0;
/*
* we will assume the sizeof these pd_fc4types and
* portActiveFc4Types will remain the same. we could
* add in a check for it, but we decided it was unneeded
*/
sizeof (tmp_pd->pd_fc4types));
val->PortMaxFrameSize = 0;
val->NumberofDiscoveredPorts = 0;
sizeof (val->PortSymbolicName));
val32->PortSupportedFc4Types[0] =
val->PortSupportedFc4Types[0];
sizeof (tmp_pd->pd_fc4types));
if (fp_copyout((void *)val32,
}
} else {
}
} else {
if (fp_copyout((void *)val,
}
} else {
}
}
}
break;
}
case FCIO_GET_NUM_DEVS: {
int num_devices;
break;
}
switch (port->fp_topology) {
case FC_TOP_PRIVATE_LOOP:
case FC_TOP_PT_PT:
break;
case FC_TOP_PUBLIC_LOOP:
case FC_TOP_FABRIC:
/*
* In FC-GS-2 the Name Server doesn't send out
* RSCNs for any Name Server Database updates
* When it is finally fixed there is no need
* to probe as below and should be removed.
*/
break;
case FC_TOP_NO_NS:
/* FALLTHROUGH */
case FC_TOP_UNKNOWN:
/* FALLTHROUGH */
default:
num_devices = 0;
break;
}
if (fp_copyout((void *)&num_devices,
mode) == 0) {
}
} else {
}
break;
}
case FCIO_GET_DEV_LIST: {
int num_devices;
int new_count;
int map_size;
break;
}
if (fp_copyout((void *)&new_count,
break;
}
break;
}
break;
}
if (port->fp_total_devices <= 0) {
if (fp_copyout((void *)&new_count,
break;
}
break;
}
break;
}
switch (port->fp_topology) {
case FC_TOP_PRIVATE_LOOP:
mode) != FC_SUCCESS) {
break;
}
}
break;
case FC_TOP_PT_PT:
mode) != FC_SUCCESS) {
break;
}
}
break;
case FC_TOP_PUBLIC_LOOP:
case FC_TOP_FABRIC: {
map_size =
sizeof (ns_resp_gan_t), map_size,
KM_SLEEP);
ns_cmd->ns_gan_index = 0;
if (ret != FC_SUCCESS ||
new_count = 0;
if (fp_copyout((void *)&new_count,
break;
}
break;
}
break;
}
if (fp_copyout((void *)&new_count,
mode)) {
break;
}
break;
}
}
break;
}
case FC_TOP_NO_NS:
/* FALLTHROUGH */
case FC_TOP_UNKNOWN:
/* FALLTHROUGH */
default:
if (fp_copyout((void *)&new_count,
break;
}
break;
}
break;
}
break;
}
case FCIO_GET_SYM_PNAME: {
break;
}
case FCIO_GET_SYM_NNAME: {
break;
}
case FCIO_SET_SYM_PNAME: {
break;
}
case FCIO_SET_SYM_NNAME: {
break;
}
case FCIO_GET_LOGI_PARAMS: {
break;
}
break;
}
} else {
break;
}
}
break;
}
break;
}
} else {
}
if (ddi_copyout((void *)params32,
}
} else {
}
}
}
break;
}
case FCIO_DEV_LOGOUT:
case FCIO_DEV_LOGIN:
}
break;
}
} else {
}
KM_SLEEP);
mode)) {
}
break;
}
}
}
break;
case FCIO_GET_STATE: {
break;
}
break;
}
fcio->fcio_errno = 0;
sizeof (ns_req_gid_pn_t),
sizeof (ns_resp_gid_pn_t),
sizeof (ns_resp_gid_pn_t),
((ns_req_gid_pn_t *)
1, KM_SLEEP);
FC_SUCCESS) {
if (ret != FC_SUCCESS) {
} else {
fcio->fcio_errno =
}
} else {
}
} else {
}
} else {
}
if (!rval) {
if (ddi_copyout((void *)&state,
mode)) {
}
}
}
break;
}
case FCIO_DEV_REMOVE: {
break;
}
break;
}
}
break;
}
}
break;
}
break;
}
case FCIO_GET_FCODE_REV: {
break;
}
if (ret == FC_SUCCESS) {
if (ddi_copyout((void *)fcode_rev,
}
} else {
}
} else {
/*
* check if buffer was not large enough to obtain
* FCODE version.
*/
} else {
}
}
}
break;
}
case FCIO_GET_FW_REV: {
break;
}
if (ret == FC_SUCCESS) {
if (ddi_copyout((void *)fw_rev,
}
} else {
}
} else {
}
}
break;
}
case FCIO_GET_DUMP_SIZE: {
break;
}
if (ret == FC_SUCCESS) {
if (ddi_copyout((void *)&dump_size,
mode) == 0) {
}
} else {
}
} else {
}
}
break;
}
case FCIO_DOWNLOAD_FW: {
break;
}
break;
}
if (ret != FC_SUCCESS) {
}
}
break;
}
case FCIO_DOWNLOAD_FCODE: {
break;
}
break;
}
if (ret != FC_SUCCESS) {
}
}
break;
}
case FCIO_FORCE_DUMP:
if (ret != FC_SUCCESS) {
}
}
break;
case FCIO_GET_DUMP: {
break;
}
if (ret != FC_SUCCESS) {
}
break;
}
}
break;
}
if (ret == FC_SUCCESS) {
}
} else {
}
} else {
}
}
break;
}
case FCIO_GET_TOPOLOGY: {
break;
}
} else {
}
if (ddi_copyout((void *)&user_topology,
mode)) {
}
break;
}
case FCIO_RESET_LINK: {
/*
* Look at the output buffer field; if this field has zero
* fcio_ibuf field points to a WWN, see if it's an NL_Port,
* and if yes, determine the LFA and reset the remote LIP
* by LINIT ELS.
*/
break;
}
break;
}
break;
}
break;
}
}
}
break;
}
case FCIO_RESET_HARD:
if (ret != FC_SUCCESS) {
}
}
break;
case FCIO_RESET_HARD_CORE:
if (ret != FC_SUCCESS) {
}
}
break;
case FCIO_DIAG: {
/* Validate user buffer from ioctl call. */
break;
}
goto fp_fcio_diag_cleanup;
}
}
goto fp_fcio_diag_cleanup;
}
}
}
if (ret != FC_SUCCESS) {
if (ret == FC_INVALID_REQUEST) {
} else {
}
}
goto fp_fcio_diag_cleanup;
}
/*
* pm_stat_len will contain the number of status bytes
* an FCA driver requires to return the complete status
* of the requested diag operation. If the user buffer
* is not large enough to hold the entire status, We
* copy only the portion of data the fits in the buffer and
* return a ENOMEM to the user application.
*/
"fp:FCIO_DIAG:status buffer too small\n");
goto fp_fcio_diag_cleanup;
}
} else {
/*
* Copy only data pm_stat_len bytes of data
*/
goto fp_fcio_diag_cleanup;
}
}
}
}
}
}
break;
}
case FCIO_GET_NODE_ID: {
/* validate parameters */
break;
}
/* ioctl handling is over */
break;
}
case FCIO_SEND_NODE_ID: {
/* validate parameters */
break;
}
break;
}
/* ioctl handling is over */
break;
}
case FCIO_SET_NODE_ID: {
break;
}
break;
}
case FCIO_LINK_STATUS: {
/* validate parameters */
break;
}
break;
}
sizeof (fc_portid_t), mode)) {
break;
}
/* Determine the destination of the RLS frame */
} else {
}
/* If dest is zero OR same as FCA ID, then use port_manage() */
/* Allocate memory for link error status block */
/* Prepare the port management structure */
/* Get the adapter's link error status block */
if (ret == FC_SUCCESS) {
/* xfer link status block to userland */
if (ddi_copyout((void *)rls_acc,
mode)) {
}
} else {
}
} else {
}
}
/* ioctl handling is over */
break;
}
/*
* Send RLS to the destination port.
* Having RLS frame destination is as FPORT is not yet
* supported and will be implemented in future, if needed.
* Following call to get "pd" will fail if dest is FPORT
*/
}
break;
}
}
break;
}
/*
* Allocate job structure and set job_code as DUMMY,
* because we will not go through the job thread.
* Instead fp_sendcmd() is called directly here.
*/
}
break;
}
/* Allocate memory for link error status block */
/*
* link error status block is now available.
* Copy it to userland
*/
if (ddi_copyout((void *)rls_acc,
mode)) {
}
} else {
}
} else {
}
} else {
}
if (rval) {
}
}
}
break;
}
case FCIO_NS: {
break;
}
break;
}
} else {
break;
}
sizeof (fc_ns_cmd_t), mode)) {
break;
}
}
if (ns_req->ns_req_len <= 0) {
break;
}
ns_cmd->ns_gan_index = 0;
}
break;
}
if (rval == FC_SUCCESS) {
if (ns_req->ns_resp_len) {
break;
}
}
} else {
}
}
break;
}
default:
break;
}
/*
* If set, reset the EXCL busy bit to
* receive other exclusive access commands
*/
}
return (rval);
}
/*
* This function assumes that the response length
* is same regardless of data model (LP32 or LP64)
* which is true for all the ioctls currently
* supported.
*/
static int
{
}
/*
* This function does the set rnid
*/
static int
{
int rval = 0;
/* Allocate memory for node id block */
return (EFAULT);
}
/* Prepare the port management structure */
/* Get the adapter's node data */
if (rval != FC_SUCCESS) {
}
} else {
/* copy to the port structure */
sizeof (port->fp_rnid_params));
}
if (rval != FC_SUCCESS) {
}
return (rval);
}
/*
* This function does the local pwwn get rnid
*/
static int
{
int rval = 0;
/* Allocate memory for rnid data block */
/* xfer node info to userland */
}
} else {
}
if (rval != FC_SUCCESS) {
rval);
}
return (rval);
}
/* Prepare the port management structure */
/* Get the adapter's node data */
&pm);
if (ret == FC_SUCCESS) {
/* initialize in the port_info */
/* xfer node info to userland */
if (ddi_copyout((void *)rnid,
mode)) {
}
} else {
}
} else {
}
}
if (rval != FC_SUCCESS) {
}
return (rval);
}
static int
{
int rval = 0;
/*
* We can safely assume that the destination port
* is logged in. Either the user land will explicitly
* login before issuing RNID ioctl or the device would
* have been configured, meaning already logged in.
*/
return (ENXIO);
}
/*
* Allocate job structure and set job_code as DUMMY,
* because we will not go thorugh the job thread.
* Instead fp_sendcmd() is called directly here.
*/
}
return (rval);
}
/* Allocate memory for node id accept block */
int rnid_cnt;
/*
* node id block is now available.
* Copy it to userland
*/
/* get the response length */
} else if (ddi_copyout((void *)rnid_acc,
mode)) {
}
} else {
}
} else {
}
} else {
if (pd) {
}
}
}
if (rval != FC_SUCCESS) {
}
return (rval);
}
/*
* Copy out to userland
*/
static int
{
int rval;
#ifdef _MULTI_DATAMODEL
case DDI_MODEL_ILP32: {
break;
}
case DDI_MODEL_NONE:
break;
}
#else
#endif
return (rval);
}
static void
{
listlen = 0;
changelist = NULL;
}
}
} else {
if (--port->fp_statec_busy == 0) {
}
}
}
static int
{
int rval;
int count;
int index;
int num_devices;
continue;
}
sizeof (pd->pd_fc4types));
sizeof (la_wwn_t));
if (node) {
sizeof (la_wwn_t));
}
count++;
if (count >= num_devices) {
goto found;
}
}
}
rval = FC_FAILURE;
rval = FC_FAILURE;
} else {
rval = FC_SUCCESS;
}
return (rval);
}
/*
* Handle Fabric ONLINE
*/
static void
{
int index;
int rval;
int dbg_count;
int count = 0;
char ww_name[17];
sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t),
0, KM_SLEEP);
/*
* Check if orphans are showing up now
*/
if (port->fp_orphan_count) {
((ns_req_gid_pn_t *)
((ns_resp_gid_pn_t *)
((ns_resp_gid_pn_t *)
if (rval == FC_SUCCESS) {
d_id =
0, NULL, "N_x Port with D_ID=%x,"
" PWWN=%s reappeared in fabric",
if (prev) {
} else {
}
port->fp_orphan_count--;
count++;
} else {
}
} else {
NULL,
" Port WWN %s removed from orphan"
" list after %d scans", ww_name,
if (prev) {
} else {
}
port->fp_orphan_count--;
} else {
}
}
}
}
/*
* Walk the Port WWN hash table, reestablish LOGIN
* if a LOGIN is already performed on a particular
* device; Any failure to LOGIN should mark the
* port device OLD.
*/
/*
* Don't count in the port devices that are new
* unless the total number of devices visible
* through this port is less than FP_MAX_DEVICES
*/
continue;
}
} else {
continue;
}
}
count++;
/*
* Consult with the name server about D_ID changes
*/
((ns_req_gid_pn_t *)
((ns_resp_gid_pn_t *)
pid.priv_lilp_posit = 0;
if (rval != FC_SUCCESS) {
"fp_fabric_online: PD "
"disappeared; d_id=%x, PWWN=%s",
"N_x Port with D_ID=%x, PWWN=%s"
" disappeared from fabric", d_id,
ww_name);
continue;
}
"D_ID of a device with PWWN %s changed."
" New D_ID = %x, OLD D_ID = %x", ww_name,
}
}
}
if (ns_cmd) {
}
listlen = 0;
changelist = NULL;
if (count) {
}
dbg_count = 0;
continue;
}
dbg_count++;
/*
* If it is already marked deletion, nothing
* else to do.
*/
continue;
}
/*
* If it is freshly discovered out of
* the orphan list, nothing else to do
*/
continue;
}
/*
* Explicitly mark all devices OLD; successful
* PLOGI should reset this to either NO_CHANGE
* or CHANGED.
*/
}
if (rval != FC_SUCCESS) {
}
}
}
}
}
} else {
}
}
} else {
if (--port->fp_statec_busy == 0) {
}
}
}
/*
* Fill out device list for userland ioctl in private loop
*/
static int
{
int rval;
int count;
int index;
int num_devices;
int lilp_device_count;
} else {
}
/*
* Applications are accustomed to getting the device list in
* LILP map order. The HBA firmware usually returns the device
* map in the LILP map order and diagnostic applications would
* prefer to receive in the device list in that order too
*/
/*
* the length field corresponds to the offset in the LILP frame
* which begins with 1. The thing to note here is that the
* lilp_device_count is 1 more than fp->fp_total_devices since
* the host adapter's alpa also shows up in the lilp map. We
* don't however return details of the host adapter since
* fctl_get_remote_port_by_did fails for the host adapter's ALPA
* and applications are required to issue the FCIO_GET_HOST_PARAMS
* ioctl to obtain details about the host adapter port.
*/
continue;
}
sizeof (pd->pd_fc4types));
sizeof (la_wwn_t));
if (node) {
sizeof (la_wwn_t));
}
count++;
}
}
rval = FC_FAILURE;
}
rval = FC_FAILURE;
} else {
rval = FC_SUCCESS;
}
return (rval);
}
/*
* Completion function for responses to unsolicited commands
*/
static void
{
"couldn't post response to unsolicited request;"
}
port->fp_els_resp_pkt_busy = 0;
return;
}
}
/*
* solicited LINIT ELS completion function
*/
static void
{
if (FP_IS_PKT_ERROR(pkt)) {
return;
}
} else {
}
}
/*
* Decode the unsolicited request; For FC-4 Device and Link data frames
* notify the registered ULP of this FC-4 type right here. For Unsolicited
* ELS requests, submit a request to the job_handler thread to work on it.
* The intent is to act quickly on the FC-4 unsolicited link and data frames
* and save much of the interrupt time processing of unsolicited ELS requests
* and hand it off to the job_handler thread.
*/
static void
{
port = port_handle;
" d_id=%x, type=%x, r_ctl=%x, f_ctl=%x"
" seq_id=%x, df_ctl=%x, seq_cnt=%x, ox_id=%x, rx_id=%x"
if (type & 0x80000000) {
/*
* Huh ? Nothing much can be done without
* a valid buffer. So just exit.
*/
return;
}
/*
* If the unsolicited interrupts arrive while it isn't
* safe to handle unsolicited callbacks; Drop them, yes,
* drop them on the floor
*/
port->fp_active_ubs++;
if ((port->fp_soft_state &
"not ONLINE. s_id=%x, d_id=%x, type=%x, "
"seq_id=%x, ox_id=%x, rx_id=%x"
if (--(port->fp_active_ubs) == 0) {
}
return;
}
}
port->fp_statec_busy) {
if (pd) {
"LOGO for LOGGED IN D_ID %x",
}
}
if (--(port->fp_active_ubs) == 0) {
}
"fp_unsol_cb() bailing out LOGO for D_ID %x",
return;
}
if (port->fp_els_resp_pkt_busy == 0) {
if (r_ctl == R_CTL_ELS_REQ) {
switch (ls_code) {
case LA_ELS_PLOGI:
case LA_ELS_FLOGI:
if (--(port->fp_active_ubs) == 0) {
port->fp_soft_state &=
}
return;
case LA_ELS_RSCN:
if (++(port)->fp_rscn_count ==
++(port)->fp_rscn_count;
}
break;
default:
break;
}
}
} else if ((r_ctl == R_CTL_ELS_REQ) &&
++port->fp_rscn_count;
}
}
switch (r_ctl & R_CTL_ROUTING) {
case R_CTL_DEVICE_DATA:
/*
* If the unsolicited buffer is a CT IU,
* have the job_handler thread work on it.
*/
break;
}
/* FALLTHROUGH */
case R_CTL_FC4_SVC: {
int sendup = 0;
/*
* If a LOGIN isn't performed before this request
* shut the door on this port with a reply that a
* LOGIN is required. We make an exception however
* for IP broadcast packets and pass them through
* to the IP ULP(s) to handle broadcast requests.
* This is not a problem for private loop devices
* but for fabric topologies we don't log into the
* remote ports during port initialization and
* the ULPs need to log into requesting ports on
* demand.
*/
if (pd) {
sendup++;
}
/* brodacst IP frame - so sendup via job thread */
break;
}
/*
* Send all FC4 services via job thread too
*/
break;
}
return;
}
0, KM_NOSLEEP, pd);
}
}
}
if (--(port->fp_active_ubs) == 0) {
}
return;
}
default:
break;
}
/*
* Submit a Request to the job_handler thread to work
* on the unsolicited request. The potential side effect
* of this is that the unsolicited buffer takes a little
* longer to get released but we save interrupt time in
* the bargain.
*/
/*
* One way that the rscn_count will get used is described below :
*
* 1. fp_unsol_cb() gets an RSCN and updates fp_rscn_count.
* 2. Before mutex is released, a copy of it is stored in rscn_count.
* 3. The count is passed to job thread as JOB_UNSOL_REQUEST (below)
* by overloading the job_cb_arg to pass the rscn_count
* 4. When one of the routines processing the RSCN picks it up (ex:
* fp_validate_rscn_page()), it passes this count in the map
* structure (as part of the map_rscn_info structure member) to the
* ULPs.
* 5. When ULPs make calls back to the transport (example interfaces for
* this are fc_ulp_transport(), fc_ulp_login(), fc_issue_els()), they
* can now pass back this count as part of the fc_packet's
* pkt_ulp_rscn_count member. fcp does this currently.
* 6. When transport gets a call to transport a command on the wire, it
* will check to see if there is a valid pkt_ulp_rsvd1 field in the
* fc_packet. If there is, it will match that info with the current
* rscn_count on that instance of the port. If they don't match up
* then there was a newer RSCN. The ULP gets back an error code which
* informs it about it - FC_DEVICE_BUSY_NEW_RSCN.
* 7. At this point the ULP is free to make up its own mind as to how to
* handle this. Currently, fcp will reset its retry counters and keep
* retrying the operation it was doing in anticipation of getting a
* new state change call back for the new RSCN.
*/
"couldn't submit a job to the thread, failing..");
--port->fp_rscn_count;
}
if (--(port->fp_active_ubs) == 0) {
}
return;
}
}
/*
* Handle unsolicited requests
*/
static void
{
switch (r_ctl & R_CTL_ROUTING) {
case R_CTL_EXTENDED_SVC:
if (r_ctl != R_CTL_ELS_REQ) {
break;
}
switch (ls_code) {
case LA_ELS_LOGO:
case LA_ELS_ADISC:
case LA_ELS_PRLO:
if (!FC_IS_REAL_DEVICE(s_id)) {
break;
}
break;
}
sizeof (la_els_rjt_t), 0, KM_SLEEP,
/*
* Can this actually fail when
* given KM_SLEEP? (Could be used
* this way in a number of places.)
*/
break;
}
}
break;
}
if (ls_code == LA_ELS_LOGO) {
} else if (ls_code == LA_ELS_ADISC) {
} else {
}
break;
case LA_ELS_PLOGI:
break;
case LA_ELS_FLOGI:
break;
case LA_ELS_RSCN:
break;
default:
return;
}
break;
case R_CTL_BASIC_SVC:
/*
* The unsolicited basic link services could be ABTS
* and RMC (Or even a NOP). Just BA_RJT them until
* such time there arises a need to handle them more
* carefully.
*/
}
}
}
break;
case R_CTL_DEVICE_DATA:
/*
* Mostly this is of type FC_TYPE_FC_SERVICES.
* As we don't like any Unsolicited FC services
* requests, we would do well to RJT them as
* well.
*/
port->fp_fca_handle) !=
FC_SUCCESS) {
}
}
}
break;
}
/* FALLTHROUGH */
case R_CTL_FC4_SVC:
return;
case R_CTL_LINK_CTL:
/*
* Turn deaf ear on unsolicited link control frames.
* Typical unsolicited link control Frame is an LCR
* (to reset End to End credit to the default login
* value and abort current sequences for all classes)
* this transparently at its level and not pass all
* the way up here.
*
* Possible responses to LCR are R_RDY, F_RJT, P_RJT
* or F_BSY. P_RJT is chosen to be the most appropriate
* at this time.
*/
/* FALLTHROUGH */
default:
/*
* Just reject everything else as an invalid request.
*/
}
}
}
break;
}
if (--(port->fp_active_ubs) == 0) {
}
}
/*
* Prepare a BA_RJT and send it over.
*/
static void
{
}
/*
* Prepare an LS_RJT and send it over
*/
static void
{
}
/*
* Function: fp_prlo_acc_init
*
* Description: Initializes an Link Service Accept for a PRLO.
*
* Arguments: *port Local port through which the PRLO was
* received.
* cmd Command that will carry the accept.
* *buf Unsolicited buffer containing the PRLO
* request.
* job Job request.
* sleep Allocation mode.
*
* Return Value: *cmd Command containing the response.
*
* Context: Depends on the parameter sleep.
*/
fp_cmd_t *
{
/*
* The payload of the accept to a PRLO has to be the exact match of
* the payload of the request (at the exception of the code).
*/
if (cmd) {
/*
* The fp command was successfully allocated.
*/
/* The code is overwritten for the copy. */
/* Response code is set. */
flags &= ~SP_RESP_CODE_MASK;
}
return (cmd);
}
/*
* Prepare an ACC response to an ELS request
*/
static void
{
}
/*
* Unsolicited PRLO handler
*
* A Process Logout should be handled by the ULP that established it. However,
* some devices send a PRLO to trigger a PLOGI followed by a PRLI. This happens
* when a device implicitly logs out an initiator (for whatever reason) and
* tries to get that initiator to restablish the connection (PLOGI and PRLI).
* The logical thing to do for the device would be to send a LOGO in response
* to any FC4 frame sent by the initiator. Some devices choose, however, to send
* a PRLO instead.
*
* From a Fibre Channel standpoint a PRLO calls for a PRLI. There's no reason to
* think that the Port Login has been lost. If we follow the Fibre Channel
* protocol to the letter a PRLI should be sent after accepting the PRLO. If
* the Port Login has also been lost, the remote port will reject the PRLI
* indicating that we must PLOGI first. The initiator will then turn around and
* send a PLOGI. The way Leadville is layered and the way the ULP interface
* is defined doesn't allow this scenario to be followed easily. If FCP were to
* handle the PRLO and attempt the PRLI, the reject indicating that a PLOGI is
* needed would be received by FCP. FCP would have, then, to tell the transport
* (fp) to PLOGI. The problem is, the transport would still think the Port
* Login is valid and there is no way for FCP to tell the transport: "PLOGI even
* if you think it's not necessary". To work around that difficulty, the PRLO
* is treated by the transport as a LOGO. The downside to it is a Port Login
* may be disrupted (if a PLOGI wasn't actually needed) and another ULP (that
* has nothing to do with the PRLO) may be impacted. However, this is a
* scenario very unlikely to happen. As of today the only ULP in Leadville
* FCIP), a SCSI target would have to be running FCP and FCIP (which is very
* unlikely).
*/
static void
{
int busy;
int rval;
int retain;
(sizeof (service_parameter_page_t) + sizeof (ls_code_t))) ||
/*
* We are being very restrictive. Only on page per
* payload. If it is not the case we reject the ELS although
* we should reply indicating we handle only single page
* per PRLO.
*/
goto fp_reject_prlo;
}
/*
* This is in case the payload advertizes a size bigger than
* what it really is.
*/
goto fp_reject_prlo;
}
if (!busy) {
busy++;
}
}
if (busy) {
"pd=%p - busy",
goto fp_reject_prlo;
}
} else {
if (tolerance) {
retain = 0;
}
return;
}
if (rval != FC_SUCCESS) {
return;
}
if (retain) {
} else {
char ww_name[17];
"N_x Port with D_ID=%x, PWWN=%s logged out"
}
return;
}
}
}
}
/*
* Unsolicited LOGO handler
*/
static void
{
int busy;
int rval;
int retain;
if (!busy) {
busy++;
}
}
if (busy) {
"pd=%p - busy",
}
}
}
} else {
if (tolerance) {
retain = 0;
}
return;
}
if (rval != FC_SUCCESS) {
return;
}
if (retain) {
/*
* when get LOGO, first try to get PID from nameserver
* if failed, then we do not need
* send PLOGI to that remote port
*/
sizeof (ns_req_gid_pn_t),
sizeof (ns_resp_gid_pn_t),
sizeof (ns_resp_gid_pn_t),
0, KM_SLEEP);
int ret;
((ns_req_gid_pn_t *)
ret = fp_ns_query(
if ((ret != FC_SUCCESS) ||
"NS query failed,",
" delete pd");
goto delete_pd;
}
}
}
} else {
char ww_name[17];
"N_x Port with D_ID=%x, PWWN=%s logged out"
}
}
}
/*
* Perform general purpose preparation of a response to an unsolicited request
*/
static void
{
}
/*
* Immediate handling of unsolicited FLOGI and PLOGI requests. In the
* early development days of public loop soc+ firmware, numerous problems
* were encountered (the details are undocumented and history now) which
* led to the birth of this function.
*
* If a pre-allocated unsolicited response packet is free, send out an
* immediate response, otherwise submit the request to the port thread
* to do the deferred processing.
*/
static void
{
int sent;
int f_port;
int do_acc;
char dww_name[17];
case LA_ELS_PLOGI: {
int small;
&payload->nport_ww_name);
&payload->nport_ww_name);
if (pd) {
/*
* Most likely this means a cross login is in
* progress or a device about to be yanked out.
* Only accept the plogi if my wwn is smaller.
*/
sent = 1;
}
/*
* Stop plogi request (if any)
* attempt from local side to speedup
* the discovery progress.
* Mark the pd as PD_PLOGI_RECEPIENT.
*/
}
"Unsol PLOGI received. PD still exists in the "
"PWWN list. pd=%p PWWN=%s, sent=%x",
"fp_i_handle_unsol_els: Mark the pd"
" as plogi recipient, pd=%p, PWWN=%s"
", sent=%x",
}
} else {
sent = 0;
}
/*
* To avoid Login collisions, accept only if my WWN
* is smaller than the requester (A curious side note
* would be that this rule may not satisfy the PLOGIs
* initiated by the switch from not-so-well known
* ports such as 0xFFFC41)
*/
sizeof (la_els_rjt_t);
"fp_i_handle_unsol_els: "
"Unsupported class. "
"Rejecting PLOGI");
} else {
port->fp_els_resp_pkt_busy = 0;
return;
}
} else {
sizeof (la_els_logi_t);
/*
* Sometime later, we should validate
* the service parameters instead of
* just accepting it.
*/
"fp_i_handle_unsol_els: Accepting PLOGI,"
" f_port=%d, small=%d, do_acc=%d,"
sent);
/*
* If fp_port_id is zero and topology is
* Point-to-Point, get the local port id from
* the d_id in the PLOGI request.
* If the outgoing FLOGI hasn't been accepted,
* the topology will be unknown here. But it's
* still safe to save the d_id to fp_port_id,
* just because it will be overwritten later
* if the topology is not Point-to-Point.
*/
}
}
} else {
"fp_i_handle_unsol_els: "
"Rejecting PLOGI with Logical Busy."
"Possible Login collision.");
} else {
port->fp_els_resp_pkt_busy = 0;
return;
}
}
break;
}
case LA_ELS_FLOGI:
"fp_i_handle_unsol_els: "
"Unsupported Class. Rejecting FLOGI.");
} else {
port->fp_els_resp_pkt_busy = 0;
return;
}
} else {
sizeof (la_els_rjt_t);
NULL);
"fp_i_handle_unsol_els: "
"Invalid Link Ctrl. "
"Rejecting FLOGI.");
} else {
port->fp_els_resp_pkt_busy = 0;
return;
}
} else {
sizeof (la_els_logi_t);
/*
* Let's not aggressively validate the N_Port's
* service parameters until PLOGI. Suffice it
* to give a hint that we are an N_Port and we
* are game to some serious stuff here.
*/
NULL, KM_NOSLEEP);
"fp_i_handle_unsol_els: "
"Accepting FLOGI.");
}
}
break;
default:
return;
}
port->fp_els_resp_pkt_busy = 0;
}
}
/*
* Handle unsolicited PLOGI request
*/
static void
{
int sent;
int small;
int f_port;
int do_acc;
char dww_name[17];
"type=%x, f_ctl=%x"
" seq_id=%x, ox_id=%x, rx_id=%x"
if (pd) {
/*
* Most likely this means a cross login is in
* progress or a device about to be yanked out.
* Only accept the plogi if my wwn is smaller.
*/
sent = 1;
}
/*
* Stop plogi request (if any)
* attempt from local side to speedup
* the discovery progress.
* Mark the pd as PD_PLOGI_RECEPIENT.
*/
}
" received. PD still exists in the PWWN list. pd=%p "
"fp_handle_unsol_plogi: Mark the pd"
" as plogi recipient, pd=%p, PWWN=%s"
", sent=%x",
}
} else {
sent = 0;
}
/*
* Avoid Login collisions by accepting only if my WWN is smaller.
*
* A side note: There is no need to start a PLOGI from this end in
* this context if login isn't going to be accepted for the
* above reason as either a LIP (in private loop), RSCN (in
* fabric topology), or an FLOGI (in point to point - Huh ?
* check FC-PH) would normally drive the PLOGI from this end.
* At this point of time there is no need for an inbound PLOGI
* to kick an outbound PLOGI when it is going to be rejected
* for the reason of WWN being smaller. However it isn't hard
* to do that either (when such a need arises, start a timer
* for a duration that extends beyond a normal device discovery
* time and check if an outbound PLOGI did go before that, if
* none fire one)
*
* Unfortunately, as it turned out, during booting, it is possible
* to miss another initiator in the same loop as port driver
* instances are serially attached. While preserving the above
* comments for belly laughs, please kick an outbound PLOGI in
* a non-switch environment (which is a pt pt between N_Ports or
* a private loop)
*
* While preserving the above comments for amusement, send an
* ACC if the PLOGI is going to be rejected for WWN being smaller
* when no discovery is in progress at this end. Turn around
* and make the port device as the PLOGI initiator, so that
* the PLOGI (In fact both ends do in this particular case, but
* only one wins)
*
* Make sure the PLOGIs initiated by the switch from not-so-well-known
* ports (such as 0xFFFC41) are accepted too.
*/
return;
}
"fp_handle_unsol_plogi: "
"Unsupported class. rejecting PLOGI");
}
} else {
return;
}
/*
* Sometime later, we should validate the service
* parameters instead of just accepting it.
*/
"Accepting PLOGI, f_port=%d, small=%d, "
sent);
/*
* If fp_port_id is zero and topology is
* Point-to-Point, get the local port id from
* the d_id in the PLOGI request.
* If the outgoing FLOGI hasn't been accepted,
* the topology will be unknown here. But it's
* still safe to save the d_id to fp_port_id,
* just because it will be overwritten later
* if the topology is not Point-to-Point.
*/
}
}
} else {
return;
}
/*
* Send out Logical busy to indicate
* the detection of PLOGI collision
*/
"Rejecting Unsol PLOGI with Logical Busy."
"possible PLOGI collision. PWWN=%s, sent=%x",
} else {
return;
}
}
}
}
/*
* Handle mischievous turning over of our own FLOGI requests back to
* us by the SOC+ microcode. In other words, look at the class of such
* bone headed requests, if 1 or 2, bluntly P_RJT them, if 3 drop them
* on the floor
*/
static void
{
return;
}
} else {
return;
}
} else {
" s_id=%x, d_id=%x, type=%x, f_ctl=%x"
" seq_id=%x, ox_id=%x, rx_id=%x, ro=%x",
if (state != FC_STATE_ONLINE ||
return;
}
"fp_handle_unsol_flogi: "
"Rejecting PLOGI. Invalid Link CTRL");
} else {
return;
}
} else {
return;
}
/*
* Let's not aggressively validate the N_Port's
* service parameters until PLOGI. Suffice it
* to give a hint that we are an N_Port and we
* are game to some serious stuff here.
*/
"Accepting PLOGI");
}
}
}
}
/*
* Perform PLOGI accept
*/
static void
{
/*
* If we are sending ACC to PLOGI and we haven't already
* create port and node device handles, let's create them
* here.
*/
int small;
int do_acc;
&req->nport_ww_name);
"Couldn't create port device for d_id:0x%x",
"couldn't create port device d_id=%x",
} else {
/*
* usoc currently returns PLOGIs inline and
* the maximum buffer size is 60 bytes or so.
* So attempt not to look beyond what is in
* the unsolicited buffer
*
* JNI also traverses this path sometimes
*/
} else {
if (pd->pd_login_count == 0) {
pd->pd_login_count++;
}
}
}
}
}
}
"bufsize:0x%x sizeof(la_els_logi):0x%x "
"port's wwn:0x%01x%03x%04x%08x requestor's wwn:0x%01x%03x%04x%08x "
}
#define RSCN_EVENT_NAME_LEN 256
/*
* Handle RSCNs
*/
static void
{
int listindex;
--port->fp_rscn_count;
}
return;
}
}
}
if (len <= 0) {
--port->fp_rscn_count;
}
return;
}
sizeof (ns_resp_gpn_id_t), sizeof (ns_resp_gpn_id_t),
0, sleep);
--port->fp_rscn_count;
}
return;
}
"type=%x, f_ctl=%x seq_id=%x, ox_id=%x, rx_id=%x"
/* Only proceed if we can allocate nvname and the nvlist */
KM_NOSLEEP) == DDI_SUCCESS) {
sizeof (la_wwn_t)) == DDI_SUCCESS)) {
}
}
/* Add affected page to the event payload */
"affected_page_%d", listindex);
/* We don't want to send a partial event, so dump it */
}
}
/*
* Query the NS to get the Port WWN for this
* affected D_ID.
*/
mask = 0;
case FC_RSCN_PORT_ADDRESS:
if (listindex == 0) {
/*
* We essentially did not process this RSCN. So,
* ULPs are not going to be called and so we
* decrement the rscn_count
*/
if (--port->fp_rscn_count ==
--port->fp_rscn_count;
}
}
break;
case FC_RSCN_AREA_ADDRESS:
mask = 0xFFFF00;
/* FALLTHROUGH */
case FC_RSCN_DOMAIN_ADDRESS:
if (!mask) {
mask = 0xFF0000;
}
break;
case FC_RSCN_FABRIC_ADDRESS:
/*
* We need to discover all the devices on this
* port.
*/
break;
default:
break;
}
}
} else {
"RSCN handled, but event not sent to userland");
}
}
if (ns_cmd) {
}
if (listindex) {
#ifdef DEBUG
sizeof (fc_rscn_t));
"PORT RSCN: processed=%x, reporting=%x",
}
#endif
sleep, 0);
} else {
}
}
/*
* Fill out old map for ULPs with fp_mutex, fd_mutex and pd_mutex held
*/
static void
{
int is_switch;
int initiator;
/* This function has the following bunch of assumptions */
" removed the PD=%p from DID and PWWN tables",
}
}
/*
* Fill out old map for ULPs
*/
static void
{
int is_switch;
int initiator;
" removed the PD=%p from DID and PWWN tables",
}
}
/*
* Fillout Changed Map for ULPs
*/
static void
{
if (new_did) {
}
if (new_pwwn) {
}
}
/*
* Fillout New Name Server map
*/
static void
{
if (handle) {
} else {
sizeof (gan_resp->gan_fc4types));
}
}
/*
* Perform LINIT ELS
*/
static int
{
int rval;
rval = 0;
sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t),
0, sleep);
return (FC_NOMEM);
}
return (FC_FAILURE);
}
/*
* Given this D_ID, get the port type to see if
* we can do LINIT on the LFA
*/
sizeof (ns_resp_gpt_id_t), sizeof (ns_resp_gpt_id_t),
0, sleep);
return (FC_NOMEM);
}
((ns_req_gpt_id_t *)
return (FC_FAILURE);
}
case FC_NS_PORT_NL:
case FC_NS_PORT_F_NL:
case FC_NS_PORT_FL:
break;
default:
return (FC_FAILURE);
}
} else {
case FC_NS_PORT_NL:
case FC_NS_PORT_F_NL:
case FC_NS_PORT_FL:
break;
default:
return (FC_FAILURE);
}
}
return (FC_NOMEM);
}
/*
* How does LIP work by the way ?
* If the L_Port receives three consecutive identical ordered
* sets whose first two characters (fully decoded) are equal to
* the values shown in Table 3 of FC-AL-2 then the L_Port shall
* recognize a Loop Initialization Primitive sequence. The
* character 3 determines the type of lip:
* LIP(F7) Normal LIP
* LIP(F8) Loop Failure LIP
*
* The possible combination for the 3rd and 4th bytes are:
* F7, F7 Normal Lip - No valid AL_PA
* F8, F8 Loop Failure - No valid AL_PA
* F7, AL_PS Normal Lip - Valid source AL_PA
* F8, AL_PS Loop Failure - Valid source AL_PA
* AL_PD AL_PS Loop reset of AL_PD originated by AL_PS
* And Normal Lip for all other loop members
* 0xFF AL_PS Vendor specific reset of all loop members
*
* Now, it may not always be that we, at the source, may have an
* AL_PS (AL_PA of source) for 4th character slot, so we decide
* to do (Normal Lip, No Valid AL_PA), that means, in the LINIT
* payload we are going to set:
* lip_b3 = 0xF7; Normal LIP
* lip_b4 = 0xF7; No valid source AL_PA
*/
if (ret == FC_SUCCESS) {
} else {
rval = FC_FAILURE;
}
return (rval);
}
/*
* Fill out the device handles with GAN response
*/
static void
{
" port_id=%x, sym_len=%d fc4-type=%x",
if (pd->pd_spn_len) {
}
if (node->fd_snn_len) {
}
}
/*
* Handles all NS Queries (also means that this function
* doesn't handle NS object registration)
*/
static int
{
int rval;
if (ns_cmd->ns_cmd_size == 0) {
return (FC_FAILURE);
}
return (FC_NOMEM);
}
if (polled) {
}
if (rval != FC_SUCCESS) {
if (polled == 0) {
/*
* Return FC_SUCCESS to indicate that
* fp_iodone is performed already.
*/
rval = FC_SUCCESS;
}
}
if (polled) {
}
return (rval);
}
/*
* Initialize Common Transport request
*/
static void
{
ct.ct_options = 0;
ct.ct_reserved1 = 0;
ct.ct_reserved2 = 0;
sizeof (ct), DDI_DEV_AUTOINCR);
if (cmd_buf) {
}
}
/*
* Name Server request interrupt routine
*/
static void
{
ns_cmd = (fctl_ns_req_t *)
if (!FP_IS_PKT_ERROR(pkt)) {
/*
* On x86 architectures, make sure the resp_hdr is big endian.
* This macro is a NOP on sparc architectures mainly because
* we don't want to end up wasting time since the end result
* is going to be the same.
*/
if (ns_cmd) {
/*
* Always copy out the response CT_HDR
*/
sizeof (resp_hdr));
}
}
}
if (FP_IS_PKT_ERROR(pkt)) {
if (ns_cmd) {
/* Mark it OLD if not already done */
}
((fp_cmd_t *)
}
}
return;
}
"Bogus NS response received for D_ID=%x", d_id);
}
return;
}
if (ns_cmd) {
return;
}
}
}
}
/*
* Process NS_GAN response
*/
static void
{
int my_did;
/*
* In this case the priv_lilp_posit field in reality
* is actually represents the relative position on a private loop.
* So zero it while dealing with Port Identifiers.
*/
d_id.priv_lilp_posit = 0;
/*
* We've come a full circle; time to get out.
*/
return;
}
}
if (my_did == 0) {
"port=%p, d_id=%x, type_id=%x, "
"pwwn=%x %x %x %x %x %x %x %x, "
"nwwn=%x %x %x %x %x %x %x %x",
}
}
}
userbuf = ((fc_port_dev_t *)
ns_cmd->ns_data_buf) +
ns_cmd->ns_gan_index++;
} else {
}
map = ((fc_portmap_t *)
ns_cmd->ns_data_buf) +
ns_cmd->ns_gan_index++;
/*
* First fill it like any new map
* and update the port device info
* below.
*/
} else {
}
} else {
}
} else {
ns_cmd->ns_gan_index++;
}
return;
}
}
sizeof (gan_req), DDI_DEV_AUTOINCR);
}
}
/*
* Handle NS Query interrupt
*/
static void
{
}
}
}
}
}
}
/*
* Handle unsolicited ADISC ELS request
*/
static void
{
int rval;
}
}
}
} else {
/*
* Yes, yes, we don't have a hard address. But we
* we should still respond. Huh ? Visit 21.19.2
* of FC-PH-2 which essentially says that if an
* NL_Port doesn't have a hard address, or if a port
* does not have FC-AL capability, it shall report
* zeroes in this field.
*/
return;
}
if (rval != FC_SUCCESS) {
}
}
}
/*
* Initialize ADISC response.
*/
static void
{
}
/*
* Hold and Install the requested ULP drivers
*/
static void
{
int len;
int count;
int data_len;
DDI_PROP_DONTPASS, "load-ulp-list",
return;
}
0, NULL, "failed to load %s",
ulp_name);
}
} else {
"%s isn't a valid driver", ulp_name);
}
}
/*
* Free the memory allocated by DDI
*/
}
}
/*
* Perform LOGO operation
*/
static int
{
int rval;
if (rval != FC_SUCCESS) {
}
return (rval);
}
/*
* Perform Port attach callbacks to registered ULPs
*/
static void
{
/*
* We need to remember whether or not fctl_busy_port
* succeeded so we know whether or not to call
* fctl_idle_port when the task is complete.
*/
if (fctl_busy_port(port) == 0) {
} else {
}
}
/*
* Forward state change notifications on to interested ULPs.
* Spawns a call to fctl_ulp_statec_cb() in a taskq thread to do all the
* real work.
*/
static int
{
return (FC_NOMEM);
}
clist->clist_size = 0;
return (FC_SUCCESS);
}
/*
* Get name server map
*/
static int
{
int ret;
/*
* Don't let the allocator do anything for response;
* we have have buffer ready to fillout.
*/
sizeof (ns_resp_gan_t), 0, (FCTL_NS_FILL_NS_MAP |
ns_cmd->ns_gan_index = 0;
}
ns_cmd->ns_data_len = 0;
return (ret);
}
/*
* Create a remote port in Fabric topology by using NS services
*/
static fc_remote_port_t *
{
int rval;
#ifdef DEBUG
#endif
return (NULL);
}
sizeof (ns_resp_gan_t), 0, (FCTL_NS_CREATE_DEVICE |
return (NULL);
}
return (NULL);
}
return (pd);
}
/*
* Check for the permissions on an ioctl command. If it is required to have an
* EXCLUSIVE open performed, return a FAILURE to just shut the door on it. If
* the ioctl command isn't in one of the list built, shut the door on that too.
*
* Certain ioctls perform hardware accesses in FCA drivers, and it needs
* to be made sure that users open the port for an exclusive access while
* performing those operations.
*
* This can prevent a casual user from inflicting damage on the port by
* reason why one would need to do that) without actually realizing how
* expensive such commands could turn out to be.
*
* It is also important to note that, even with an exclusive access,
* multiple threads can share the same file descriptor and fire down
* commands in parallel. To prevent that the driver needs to make sure
* that such commands aren't in progress already. This is taken care of
* in the FP_EXCL_BUSY bit of fp_flag.
*/
static int
{
int ret = FC_FAILURE;
int count;
for (count = 0;
count++) {
ret = FC_SUCCESS;
}
break;
}
}
return (ret);
}
/*
* Bind Port driver's unsolicited, state change callbacks
*/
static int
{
fc_fca_bind_info_t bind_info = {0};
int rval = DDI_SUCCESS;
int node_namelen, port_namelen;
"fp_bind_callback fail to get node-name");
}
if (nname) {
}
"fp_bind_callback fail to get port-name");
}
if (pname) {
}
}
/*
* fca_bind_port returns the FCA driver's handle for the local
* port instance. If the port number isn't supported it returns NULL.
* It also sets up callback in the FCA for various
* things like state change, ELS etc..
*/
/*
* Hold the port driver mutex as the callbacks are bound until the
* service parameters are properly filled in (in order to be able to
* properly respond to unsolicited ELS requests)
*/
rval = DDI_FAILURE;
goto exit;
}
/* Copy from the FCA structure to the FP structure */
sizeof (port->fp_rnid_params));
} else {
port->fp_rnid_init = 0;
}
if (node_namelen) {
}
if (port_namelen) {
}
/* zero out the normally unused fields right away */
exit:
if (nname) {
}
if (pname) {
}
return (rval);
}
/*
* Retrieve FCA capabilities
*/
static void
{
int rval;
int ub_count;
switch (rval) {
case FC_CAP_FOUND:
case FC_CAP_SETTABLE:
switch (ub_count) {
case 0:
break;
case -1:
break;
default:
/* 1/4th of total buffers is my share */
ub_count =
break;
}
break;
default:
ub_count = 0;
break;
}
switch (rval) {
case FC_CAP_FOUND:
case FC_CAP_SETTABLE:
switch (action) {
case FC_RESET_RETURN_NONE:
case FC_RESET_RETURN_ALL:
break;
default:
break;
}
break;
default:
break;
}
switch (rval) {
case FC_CAP_FOUND:
switch (dma_behavior) {
case FC_ALLOW_STREAMING:
/* FALLTHROUGH */
case FC_NO_STREAMING:
break;
default:
/*
* If capability was found and the value
* was incorrect assume the worst
*/
break;
}
break;
default:
/*
* If capability was not defined - allow streaming; existing
* FCAs should not be affected.
*/
break;
}
fcp_dma != FC_DVMA_SPACE)) {
}
}
/*
* Handle Domain, Area changes in the Fabric.
*/
static void
{
#ifdef DEBUG
#endif
int rval;
int send;
int index;
int listindex;
int login;
int job_flags;
char ww_name[17];
sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t),
0, sleep);
--port->fp_rscn_count;
}
return;
}
/*
* We need to get a new count of devices from the
* name server, which will also create any new devices
* as needed.
*/
"fp_validate_area_domain: get_devcount found %d devices",
count++;
}
}
}
}
#ifdef DEBUG
#endif /* DEBUG */
/*
* Since port->fp_orphan_count is declared an 'int' it is
* theoretically possible that the count could go negative.
*
* This would be bad and if that happens we really do want
* to know.
*/
/*
* We add the port->fp_total_devices value to the count
* in the case where our port is newly attached. This is
* because we haven't done any discovery and we don't have
* any orphans in the port's orphan list. If we do not do
* this addition to count then we won't alloc enough kmem
* to do discovery with.
*/
if (count == 0) {
"0x%x orphans found, using 0x%x",
}
/*
* Allocate the change list
*/
" Not enough memory to service RSCNs"
" for %d ports, continuing...", count);
--port->fp_rscn_count;
}
return;
}
/*
* Attempt to validate or invalidate the devices that were
* already in the pwwn hash table.
*/
((ns_req_gid_pn_t *)
sleep);
if (rval != FC_SUCCESS) {
"AREA RSCN: PD disappeared; "
"N_x Port with D_ID=%x,"
" PWWN=%s disappeared from fabric",
pd, 1);
} else {
pd);
}
} else {
}
}
}
/*
* Login (if we were the initiator) or validate devices in the
* port map.
*/
continue;
}
if (login) {
"RSCN and PLOGI request;"
" pd=%p, job=%p d_id=%x, index=%d", pd,
if (rval != FC_SUCCESS) {
}
"PLOGI succeeded:no skip(1) for "
"D_ID %x", d_id);
} else {
" pd=%p, job=%p d_id=%x, index=%d", pd,
0, sleep);
if (rval != FC_SUCCESS) {
}
}
} else {
"RSCN and NO request sent; pd=%p,"
}
}
if (listindex) {
}
/*
* Orphan list validation.
*/
((ns_resp_gid_pn_t *)
if (rval == FC_SUCCESS) {
"RSCN and ORPHAN list "
"N_x Port with D_ID=%x, PWWN=%s reappeared"
if (prev) {
} else {
}
port->fp_orphan_count--;
} else {
}
} else {
}
}
/*
* One more pass through the list to delist old devices from
* the d_id and pwwn tables and possibly add to the orphan list.
*/
/*
* Update PLOGI results; For NS validation
* of orphan list, it is redundant
*
* Take care to preserve PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY if
* appropriate as fctl_copy_portmap() will clear map_flags.
*/
} else {
}
"results; pd=%p, d_id=%x pwwn=%x %x %x %x %x %x %x %x",
"results continued, pd=%p type=%x, flags=%x, state=%x",
int initiator;
PD_PLOGI_INITIATOR) ? 1 : 0;
if (initiator) {
}
} else {
/*
* Reset LOGO tolerance to zero
*/
}
}
}
if (ns_cmd) {
}
if (listindex) {
sleep, 0);
} else {
--port->fp_rscn_count;
}
}
}
/*
* Work hard to make sense out of an RSCN page.
*/
static void
{
int rval;
char ww_name[17];
"PD is BUSY; port=%p, d_id=%x, pd=%p",
return;
}
}
" in_id=%x, cmdrsp=%x, reason=%x, expln=%x",
/*
* What this means is that the D_ID
* disappeared from the Fabric.
*/
" NULL PD disappeared, rval=%x", rval);
return;
}
"N_x Port with D_ID=%x, PWWN=%s disappeared from"
return;
}
/*
* There is no change. Do PLOGI again and add it to
* ULP portmap baggage and return. Note: When RSCNs
* arrive with per page states, the need for PLOGI
* can be determined correctly.
*/
if (rval == FC_SUCCESS) {
/*
* Reset LOGO tolerance to zero
* Also we are the PLOGI initiator now.
*/
}
if (rval == FC_SUCCESS) {
struct fc_portmap *map =
"PLOGI succeeded: no skip(2)"
} else {
"N_x Port with D_ID=%x, PWWN=%s"
" disappeared from fabric",
}
} else {
}
return;
}
/*
* Hunt down the orphan list before giving up.
*/
if (port->fp_orphan_count) {
continue;
}
if (prev) {
} else {
}
port->fp_orphan_count--;
break;
}
}
if (orp) {
ww_name);
"N_x Port with D_ID=%x,"
" PWWN=%s reappeared in fabric",
}
}
return;
}
/*
* What this means is there is a new D_ID for this
* Port WWN. Take out the port device off D_ID
* list and put it back with a new D_ID. Perform
* PLOGI if already logged in.
*/
" Case THREE, pd=%p,"
"N_x Port with D_ID=%x, PWWN=%s has a new"
if (rval == FC_SUCCESS) {
}
if (rval != FC_SUCCESS) {
}
} else {
}
return;
}
char old_ww_name[17];
/*
* What this means is that there is a new Port WWN for
* this D_ID; Mark the Port device as old and provide
* the new PWWN and D_ID combination as new.
*/
"N_x Port with D_ID=%x, PWWN=%s has a new PWWN=%s now",
(*listindex)--;
}
return;
}
/*
* A weird case of Port WWN and D_ID existence but not matching up
* between them. Trust your instincts - Take the port device handle
* off Port WWN list, fix it with new Port WWN and put it back, In
* the mean time mark the port device corresponding to the old port
* WWN as OLD.
*/
" pwwn-d_id=%x pwwn-wwn=%x %x %x %x %x %x %x %x",
" d_id=%x, state=%x, did-wwn=%x %x %x %x %x %x %x %x",
if (rval == FC_SUCCESS) {
}
} else {
}
} else {
}
}
/*
* Check with NS for the presence of this port WWN
*/
static int
{
sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t),
return (FC_NOMEM);
}
}
/*
* Sanity check the LILP map returned by FCA
*/
static int
{
int count;
if (lilp_map->lilp_length == 0) {
return (FC_FAILURE);
}
FC_SUCCESS) {
return (FC_FAILURE);
}
}
return (FC_SUCCESS);
}
/*
* Sanity check if the AL_PA is a valid address
*/
static int
{
int count;
return (FC_SUCCESS);
}
}
return (FC_FAILURE);
}
/*
* Post unsolicited callbacks to ULPs
*/
static void
fp_ulp_unsol_cb(void *arg)
{
}
/*
* Perform message reporting in a consistent manner. Unless there is
* a strong reason NOT to use this function (which is very very rare)
* all message reporting should go through this.
*/
static void
{
switch (level) {
case CE_NOTE:
return;
}
break;
case CE_WARN:
return;
}
break;
}
return;
}
if (fc_errno) {
char *errmsg;
} else {
if (pkt) {
if (pkt->pkt_resp_resid) {
}
}
}
switch (dest) {
case FP_CONSOLE_ONLY:
break;
case FP_LOG_ONLY:
break;
default:
break;
}
}
static int
{
int ret;
sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t),
if (ret != FC_SUCCESS) {
} else {
}
return (EIO);
}
} else {
return (EIO);
}
}
if (pd) {
pd->pd_login_count++;
if (held_pd) {
}
return (0);
}
} else {
if (held_pd) {
}
return (EIO);
}
} else {
}
}
if (ret != FC_SUCCESS) {
if (held_pd) {
}
return (EIO);
}
if (held_pd) {
}
return (EIO);
}
return (ENODEV);
}
return (0);
}
static int
{
return (ENXIO);
}
return (EINVAL);
}
return (EBUSY);
}
pd->pd_login_count--;
return (0);
}
return (ENOMEM);
}
return (EIO);
}
return (EIO);
}
return (0);
}
/*
* Send a syslog event for adapter port level events.
*/
static void
{
KM_SLEEP) != DDI_SUCCESS) {
goto alloc_failed;
}
goto error;
}
sizeof (la_wwn_t)) != DDI_SUCCESS) {
goto error;
}
return;
}
static void
{
KM_SLEEP) != DDI_SUCCESS) {
goto alloc_failed;
}
goto error;
}
sizeof (la_wwn_t)) != DDI_SUCCESS) {
goto error;
}
goto error;
}
port_id) != DDI_SUCCESS) {
goto error;
}
return;
}
static uint32_t
{
switch (rm_state) {
case PORT_DEVICE_LOGGED_IN:
return (FC_HBA_PORTSTATE_ONLINE);
case PORT_DEVICE_VALID:
case PORT_DEVICE_INVALID:
default:
return (FC_HBA_PORTSTATE_UNKNOWN);
}
}