fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * CDDL HEADER START
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * The contents of this file are subject to the terms of the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Common Development and Distribution License (the "License").
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * You may not use this file except in compliance with the License.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * See the License for the specific language governing permissions
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * and limitations under the License.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * When distributing Covered Code, include this CDDL HEADER in each
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * If applicable, add the following below this CDDL HEADER, with the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fields enclosed by brackets "[]" replaced with your own identifying
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * information: Portions Copyright [yyyy] [name of copyright owner]
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * CDDL HEADER END
1641617f6cce96286522a449e1412c6279a956c7Sriram Popuri * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Use is subject to license terms.
cd21e7c548ae2a3b5e522244bf798f2a6b4ba02dGarrett D'Amore * Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Fibre channel Transport Library (fctl)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Function naming conventions:
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Functions called from ULPs begin with fc_ulp_
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Functions called from FCAs begin with fc_fca_
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Internal functions begin with fctl_
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Fibre channel packet layout:
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang * +---------------------+<--------+
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang * | ULP Packet private | |
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang * +---------------------+ |
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang * | |---------+
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang * | struct fc_packet |---------+
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang * +---------------------+<--------+
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang * | FCA Packet private |
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang * +---------------------+
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang * So you loved the ascii art ? It's strongly desirable to cache
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * allocate the entire packet in one common place. So we define a set a
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang * of rules. In a contiguous block of memory, the top portion of the
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang * block points to ulp packet private area, next follows the fc_packet
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * structure used extensively by all the consumers and what follows this
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang * is the FCA packet private. Note that given a packet structure, it is
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang * possible to get to the ULP and FCA Packet private fields using
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * ulp_private and fca_private fields (which hold pointers) respectively.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * It should be noted with a grain of salt that ULP Packet private size
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * varies between two different ULP types, So this poses a challenge to
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang * compute the correct size of the whole block on a per port basis. The
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * transport layer doesn't have a problem in dealing with FCA packet
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * private sizes as it is the sole manager of ports underneath. Since
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * it's not a good idea to cache allocate different sizes of memory for
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * different ULPs and have the ability to choose from one of these caches
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * based on ULP type during every packet allocation, the transport some
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang * what wisely (?) hands off this job of cache allocation to the ULPs
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * themselves.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * That means FCAs need to make their packet private size known to the
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang * transport to pass it up to the ULPs. This is done during
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fc_fca_attach(). And the transport passes this size up to ULPs during
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fc_ulp_port_attach() of each ULP.
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang * This leaves us with another possible question; How are packets
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang * allocated for ELS's started by the transport itself ? Well, the port
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang * driver during attach time, cache allocates on a per port basis to
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * handle ELSs too.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte/* These are referenced by fp.c! */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte "fctl: %s ULP same type (0x%x) as existing module.\n";
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * This lock protects the fc_ulp_module_t linked list (i.e. mod_next field)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * The fctl_mod_ports_lock protects the mod_ports element in the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fc_ulp_ports_t structure
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fctl_port_lock protects the linked list of local port structures
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang * (fctl_fca_portlist). When walking the list, this lock must be obtained
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * prior to any local port locks.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte#if !defined(lint)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte_NOTE(MUTEX_PROTECTS_DATA(fctl_nwwn_hash_mutex, fctl_nwwn_hash_table))
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte_NOTE(MUTEX_PROTECTS_DATA(fctl_ulp_list_mutex, fctl_ulp_list))
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte_NOTE(RWLOCK_PROTECTS_DATA(fctl_ulp_lock, ulp_module::mod_next))
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte_NOTE(RWLOCK_PROTECTS_DATA(fctl_mod_ports_lock, ulp_module::mod_ports
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte_NOTE(DATA_READABLE_WITHOUT_LOCK(ulp_module::mod_info))
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte_NOTE(MUTEX_PROTECTS_DATA(ulp_ports::port_mutex, ulp_ports::port_statec
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte#endif /* lint */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte#define FCTL_NAME_VERSION "SunFC Transport v" FCTL_VERSION
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang { FC_UB_BADTOKEN, "Bad Unsolicited buffer token" },
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte { FC_DEVICE_BUSY, "Port driver is working on this device" }
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte { FC_REASON_RX_BUF_TIMEOUT, "Receive Buffer Timeout" },
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte { FC_REASON_FCAL_OPN_FAIL, "FC AL Open Failed" },
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte { FC_REASON_NO_SEQ_INIT, "No Sequence Initiative" },
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte { FC_REASON_TEMP_UNAVAILABLE, "Temporarily Unavailable" },
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte { FC_REASON_PERM_UNAVAILABLE, "Permamnently Unavailable" },
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte { FC_REASON_CLASS_NOT_SUPP, "Class Not Supported", },
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang "Delimeter Usage Error" },
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte { FC_REASON_TYPE_NOT_SUPP, "Type Not Supported" },
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte { FC_REASON_INVALID_LINK_CTRL, "Invalid Link Control" },
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte { FC_REASON_INVALID_SEQ_ID, "Invalid Sequence ID" },
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte { FC_REASON_INVALID_SEQ_CNT, "Invalid Sequence count" },
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte { FC_REASON_INVALID_PARAM, "Invalid Parameter" },
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte { FC_REASON_INCORRECT_LENGTH, "Incorrect Length" },
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang { FC_REASON_UNEXPECTED_LR, "Unexpected Link reset" },
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte { FC_REASON_EXCESSIVE_SEQS, "Excessive Sequences"
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang " Attempted" },
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte { FC_REASON_ESH_NOT_SUPP, "Expiration Security Header "
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang "Not Supported" },
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte { FC_REASON_N_PORT_RESOURCE_BSY, "Resource Busy" },
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte { FC_REASON_N_PORT_VENDOR_UNIQUE, "Vendor Unique" },
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte { FC_REASON_INVALID_LA_CODE, "Invalid Link Application Code" },
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte { FC_REASON_PROTOCOL_ERROR_RJT, "Protocol Error Reject" },
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte { FC_REASON_CMD_UNABLE, "Unable to Perform Command" },
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte { FC_REASON_CMD_UNSUPPORTED, "Unsupported Command" },
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte { FC_REASON_FS_INVALID_IUSIZE, "Invalid IU Size" },
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte { FC_REASON_FS_CMD_UNABLE, "Unable to Perform Command" },
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte { FC_REASON_FS_CMD_UNSUPPORTED, "Unsupported Command" },
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte { FC_ACTION_SEQ_TERM_RETRY, "Retry terminated Sequence" },
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte { FC_ACTION_SEQ_ACTIVE_RETRY, "Retry Active Sequence" },
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte "Operation Success",
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang "Remote Stop",
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte "Local Reject",
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte "N_Port Reject",
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte "Fabric Reject",
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte "Local Busy",
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte "Transport Busy",
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte "N_Port Busy",
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte "Fabric Busy",
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte "Link Service Reject",
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte "Basic Reject",
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte "Fabric Switch Reject",
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte "Packet Transport error",
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte "Packet Failure",
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte "Port Offline",
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte "ELS is in Progress",
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte rw_init(&fctl_mod_ports_lock, NULL, RW_DRIVER, NULL);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte mutex_init(&fctl_port_lock, NULL, MUTEX_DRIVER, NULL);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte mutex_init(&fctl_nwwn_hash_mutex, NULL, MUTEX_DRIVER, NULL);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte fctl_nwwn_hash_table = kmem_zalloc(sizeof (*fctl_nwwn_hash_table) *
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte sizeof (job_request_t), 8, fctl_cache_constructor,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte sizeof (*fctl_nwwn_hash_table) * fctl_nwwn_table_size);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte sizeof (*fctl_nwwn_hash_table) * fctl_nwwn_table_size);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * The mod_uninstall code doesn't call _fini when
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * there is living dependent module on fctl. So
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * there is no need to be extra careful here ?
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte sizeof (*fctl_nwwn_hash_table) * fctl_nwwn_table_size);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte/* ARGSUSED */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_cache_constructor(void *buf, void *cdarg, int kmflag)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte mutex_init(&job->job_mutex, NULL, MUTEX_DRIVER, NULL);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte sema_init(&job->job_fctl_sema, 0, NULL, SEMA_DEFAULT, NULL);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte sema_init(&job->job_port_sema, 0, NULL, SEMA_DEFAULT, NULL);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte/* ARGSUSED */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fc_ulp_add:
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Add a ULP module
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Return Codes:
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * FC_ULP_SAMEMODULE
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * FC_SUCCESS
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * FC_FAILURE
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang * fc_ulp_add prints a warning message if there is already a
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * similar ULP type attached and this is unlikely to change as
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang * we trudge along. Further, this function returns a failure
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * code if the same module attempts to add more than once for
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * the same FC-4 type.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Make sure ulp_rev matches fctl version.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Whenever non-private data structure or non-static interface changes,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * we should use an increased FCTL_ULP_MODREV_# number here and in all
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * ulps to prevent version mismatch.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte cmn_err(CE_WARN, "fctl: ULP %s version mismatch;"
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte " ULP %s would not be loaded", ulp_info->ulp_name,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte while (rw_tryenter(&fctl_ulp_lock, RW_WRITER) == 0) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (last = NULL, list = fctl_ulp_list; list != NULL;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (mod = fctl_ulp_modules, prev = NULL; mod; mod = mod->mod_next) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (ulp_info->ulp_type == mod->mod_info->ulp_type) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte cmn_err(CE_NOTE, fctl_greeting, ulp_info->ulp_name,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Schedule a job to each port's job_handler
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * thread to attach their ports with this ULP.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (fca_port = fctl_fca_portlist; fca_port != NULL;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte job = fctl_alloc_job(JOB_ATTACH_ULP, JOB_TYPE_FCTL_ASYNC,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fc_ulp_remove
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Remove a ULP module
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * A misbehaving ULP may call this routine while I/Os are in progress.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Currently there is no mechanism to detect it to fail such a request.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Return Codes:
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * FC_SUCCESS
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * FC_FAILURE
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (last = NULL, list = fctl_ulp_list; list != NULL;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (mod = fctl_ulp_modules, prev = NULL; mod != NULL;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * The callers typically cache allocate the packet, complete the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * DMA setup for pkt_cmd and pkt_resp fields of the packet and
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * call this function to see if the FCA is interested in doing
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * its own intialization. For example, socal may like to initialize
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * the soc_hdr which is pointed to by the pkt_fca_private field
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * and sitting right below fc_packet_t in memory.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * The caller is required to ensure that pkt_pd is populated with the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * handle that it was given when the transport notified it about the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * device this packet is associated with. If there is no associated
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang * device, pkt_pd must be set to NULL. A non-NULL pkt_pd will cause an
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * increment of the reference count for said pd. When the packet is freed,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * the reference count will be decremented. This reference count, in
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * combination with the PD_GIVEN_TO_ULPS flag guarantees that the pd
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * will not wink out of existence while there is a packet outstanding.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * This function and fca_init_pkt must not perform any operations that
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * would result in a call back to the ULP, as the ULP may be required
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * to hold a mutex across this call to ensure that the pd in question
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * won't go away prior the call to fc_ulp_transport.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * ULPs are responsible for using the handles they are given during state
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * change callback processing in a manner that ensures consistency. That
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * is, they must be aware that they could be processing a state change
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * notification that tells them the device associated with a particular
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * handle has gone away at the same time they are being asked to
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * initialize a packet using that handle. ULPs must therefore ensure
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * that their state change processing and packet initialization code
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * paths are sufficiently synchronized to avoid the use of an
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * invalidated handle in any fc_packet_t struct that is passed to the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fc_ulp_init_packet() function.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefc_ulp_init_packet(opaque_t port_handle, fc_packet_t *pkt, int sleep)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* Call the FCA driver's fca_init_pkt entry point function. */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte rval = port->fp_fca_tran->fca_init_pkt(port->fp_fca_handle, pkt, sleep);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * A !NULL pd here must still be a valid
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * reference to the fc_remote_port_t.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * This function is called before destroying the cache allocated
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fc_packet to free up (and uninitialize) any resource specially
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * allocated by the FCA driver during tran_init_pkt().
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * If the pkt_pd field in the given fc_packet_t struct is not NULL, then
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * the pd_ref_count reference count is decremented for the indicated
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fc_remote_port_t struct.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefc_ulp_uninit_packet(opaque_t port_handle, fc_packet_t *pkt)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* Call the FCA driver's fca_un_init_pkt entry point function */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte rval = port->fp_fca_tran->fca_un_init_pkt(port->fp_fca_handle, pkt);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * If at this point the state of this fc_remote_port_t
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * struct is PORT_DEVICE_INVALID, it probably means somebody
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * is cleaning up old (e.g. retried) packets. If the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * pd_ref_count has also dropped to zero, it's time to
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * deallocate this fc_remote_port_t struct.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Also deallocate the associated fc_remote_node_t
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * struct if it has no other associated
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fc_remote_port_t structs.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefc_ulp_getportmap(opaque_t port_handle, fc_portmap_t **map, uint32_t *len,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte fctl_fillout_map(port, &change_list, &listlen, 1, 1, 0);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte kmem_free(change_list, listlen * sizeof (fc_portmap_t));
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Submit a job request to the job handler
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * thread to get the map and wait
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte job = fctl_alloc_job(job_code, 0, NULL, NULL, KM_SLEEP);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * The result of the last I/O operation is
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * in job_code. We don't care to look at it
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Rather we look at the number of devices
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * that are found to fill out the map for
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * If we're here, we're returning a map to the caller, which means
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * we'd better make sure every pd in that map has the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * PD_GIVEN_TO_ULPS flag set.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte while (tmp_len-- != 0) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefc_ulp_login(opaque_t port_handle, fc_packet_t **ulp_pkt, uint32_t listlen)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte (fc_ulp_rscn_info_t *)(ulp_pkt[0])->pkt_ulp_rscn_infop;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * If the port is OFFLINE, or if the port driver is
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * being SUSPENDED/PM_SUSPENDED/DETACHED, block all
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * PLOGI operations
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if ((FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) ||
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN))) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * If the rscn count in the packet is not the same as the rscn count
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * in the fc_local_port_t, then one or more new RSCNs has occurred.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte (rscnp->ulp_rscn_count != FC_INVALID_RSCN_COUNT) &&
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte (rscnp->ulp_rscn_count != port->fp_rscn_count)) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte tmp_array = kmem_zalloc(sizeof (*tmp_array) * listlen, KM_SLEEP);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte job_flags = ((ulp_pkt[0]->pkt_tran_flags) & FC_TRAN_NO_INTR)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte job = fctl_alloc_job(JOB_PLOGI_GROUP, job_flags, NULL, NULL, KM_SLEEP);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (pkt->pkt_pd->pd_flags == PD_ELS_IN_PROGRESS ||
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Set the packet state and let the port
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * driver call the completion routine
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * from its thread
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (pkt->pkt_pd->pd_state == PORT_DEVICE_INVALID ||
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefc_ulp_get_remote_port(opaque_t port_handle, la_wwn_t *pwwn, int *error,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * A ULP now knows about this pd, so mark it
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (FC_IS_TOP_SWITCH(port->fp_topology) && create) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte job = fctl_alloc_job(JOB_NS_CMD, 0, NULL, NULL, KM_SLEEP);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t),
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t),
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte ((ns_req_gid_pn_t *)(ns_cmd->ns_cmd_buf))->pwwn = *pwwn;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte d_id = ((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->pid.port_id;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t),
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte sizeof (ns_resp_gan_t), 0, FCTL_NS_CREATE_DEVICE,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte ((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.port_id = d_id - 1;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte ((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.priv_lilp_posit = 0;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Check if the port device is created now.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * A ULP now knows about this pd, so mark it
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * If a NS object exists in the host and query is performed
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * on that object, we should retrieve it from our basket
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * and return it right here, there by saving a request going
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * all the up to the Name Server.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefc_ulp_port_ns(opaque_t port_handle, opaque_t pd, fc_ns_cmd_t *ns_req)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte fabric = FC_IS_TOP_SWITCH(port->fp_topology) ? 1 : 0;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Name server query can't be performed for devices not in Fabric
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Guess what, FC-GS-2 currently prohibits (not
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * in the strongest language though) setting of
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * NS object values by other ports. But we might
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * get that changed to at least accommodate setting
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * symbolic node/port names - But if disks/tapes
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * were going to provide a method to set these
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * values directly (which in turn might register
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * with the NS when they come up; yep, for that
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * to happen the disks will have to be very well
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * behaved Fabric citizen) we won't need to
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * register the symbolic port/node names for
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * other ports too (rather send down SCSI commands
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * to the devices to set the names)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Be that as it may, let's continue to fail
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * registration requests for other ports. period.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte } else if (!fabric) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte return (fctl_retrieve_host_ns_values(port, ns_req));
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte job = fctl_alloc_job(JOB_NS_CMD, 0, NULL, NULL, KM_SLEEP);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte ns_req->ns_resp_len, ns_req->ns_resp_len, 0, KM_SLEEP);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte bcopy(ns_req->ns_req_payload, ns_cmd->ns_cmd_buf,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (ns_req->ns_resp_len >= ns_cmd->ns_data_len) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte bcopy(ns_cmd->ns_data_buf, ns_req->ns_resp_payload,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte bcopy(&ns_cmd->ns_resp_hdr, &ns_req->ns_resp_hdr,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefc_ulp_transport(opaque_t port_handle, fc_packet_t *pkt)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* A locus of race conditions */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (((FC_PORT_STATE_MASK(port->fp_state)) == FC_STATE_OFFLINE) ||
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN))) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * If the rscn count in the packet is not the same as the rscn count
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * in the fc_local_port_t, then one or more new RSCNs has occurred.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte (rscnp->ulp_rscn_count != FC_INVALID_RSCN_COUNT) &&
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte (rscnp->ulp_rscn_count != port->fp_rscn_count)) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte newpd = fctl_get_remote_port_by_pwwn_mutex_held(port,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * The remote port (pd) in the packet is no longer
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * usable, as the old pd still exists we can use the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * WWN to check if we have a current pd for the device
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * we want. Either way we continue with the old logic
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * whether we have a new pd or not, as the new pd
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * could be bad, or have become unusable.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * There is a better remote port (pd) to try,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * so we need to fix the reference counts, etc.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * This will create another PD hole
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * where we have a reference to a pd,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * but someone else could remove it.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte } else if (FC_IS_REAL_DEVICE(pkt->pkt_cmd_fhdr.d_id)) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte return (port->fp_fca_tran->fca_transport(port->fp_fca_handle, pkt));
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefc_ulp_issue_els(opaque_t port_handle, fc_packet_t *pkt)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * If the port is OFFLINE, or if the port driver is
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * being SUSPENDED/PM_SUSPENDED/DETACHED, block all
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * ELS operations
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if ((FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) ||
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN))) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * If the rscn count in the packet is not the same as the rscn count
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * in the fc_local_port_t, then one or more new RSCNs has occurred.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte (rscnp->ulp_rscn_count != FC_INVALID_RSCN_COUNT) &&
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte (rscnp->ulp_rscn_count != port->fp_rscn_count)) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte return (port->fp_fca_tran->fca_els_send(port->fp_fca_handle, pkt));
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefc_ulp_uballoc(opaque_t port_handle, uint32_t *count, uint32_t size,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte return (port->fp_fca_tran->fca_ub_alloc(port->fp_fca_handle,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefc_ulp_ubfree(opaque_t port_handle, uint32_t count, uint64_t *tokens)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte return (port->fp_fca_tran->fca_ub_free(port->fp_fca_handle,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefc_ulp_ubrelease(opaque_t port_handle, uint32_t count, uint64_t *tokens)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte return (port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefc_ulp_abort(opaque_t port_handle, fc_packet_t *pkt, int flags)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte return (port->fp_fca_tran->fca_abort(port->fp_fca_handle, pkt, flags));
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Submit an asynchronous request to the job handler if the sleep
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * flag is set to KM_NOSLEEP, as such calls could have been made
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * in interrupt contexts, and the goal is to avoid busy waiting,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * blocking on a conditional variable, a semaphore or any of the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * synchronization primitives. A noticeable draw back with this
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * asynchronous request is that an FC_SUCCESS is returned long
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * before the reset is complete (successful or not).
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefc_ulp_linkreset(opaque_t port_handle, la_wwn_t *pwwn, int sleep)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Many a times, this function is called from interrupt
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * contexts and there have been several dead locks and
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * hangs - One of the simplest work arounds is to fib
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * if a RESET is in progress.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (port->fp_soft_state & FP_SOFT_IN_LINK_RESET) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Ward off this reset if a state change is in progress.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte job = fctl_alloc_job(JOB_LINK_RESET, 0, NULL, NULL, sleep);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte job = fctl_alloc_job(JOB_LINK_RESET, JOB_TYPE_FCTL_ASYNC,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefc_ulp_port_reset(opaque_t port_handle, uint32_t cmd)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefc_ulp_get_port_login_params(opaque_t port_handle, la_els_logi_t *login_params)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* Copy the login parameters */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (cur = fctl_fca_portlist; cur; cur = cur->port_next) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (cur->port_handle->fp_instance == port_instance) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefc_ulp_pkt_error(fc_packet_t *pkt, char **state, char **reason,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte return (fctl_pkt_error(pkt, state, reason, action, expln));
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * If an ULP by the specified name exists, return FC_SUCCESS, else FC_FAILURE
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (list = fctl_ulp_list; list != NULL; list = list->ulp_next) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (strcmp(list->ulp_info->ulp_name, ulp_name) == 0) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Return port WWN for a port Identifier
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefc_ulp_get_pwwn_by_did(opaque_t port_handle, fc_portid_t d_id, la_wwn_t *pwwn)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte pd = fctl_get_remote_port_by_did(port, d_id.port_id);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Return a port map for a port WWN
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefc_ulp_pwwn_to_portmap(opaque_t port_handle, la_wwn_t *bytes, fc_portmap_t *map)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte bcopy(pd->pd_fc4types, map->map_fc4_types, sizeof (pd->pd_fc4types));
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefc_ulp_get_fca_device(opaque_t port_handle, fc_portid_t d_id)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte return (port->fp_fca_tran->fca_get_device(port->fp_fca_handle, d_id));
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefc_ulp_port_notify(opaque_t port_handle, uint32_t cmd)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte rval = port->fp_fca_tran->fca_notify(port->fp_fca_handle, cmd);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefc_ulp_disable_relogin(opaque_t *fc_port, la_wwn_t *pwwn)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte fctl_get_remote_port_by_pwwn((fc_local_port_t *)fc_port, pwwn);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefc_ulp_enable_relogin(opaque_t *fc_port, la_wwn_t *pwwn)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte fctl_get_remote_port_by_pwwn((fc_local_port_t *)fc_port, pwwn);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fc_fca_init
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang * Overload the FCA bus_ops vector in its dev_ops with
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fctl_fca_busops to handle all the INITchilds for "sf"
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * in one common place.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Should be called from FCA _init routine.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte#endif /* __lock_lint */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fc_fca_attach
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefc_fca_attach(dev_info_t *fca_dip, fc_fca_tran_t *tran)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * When we are in a position to offer downward compatibility
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * we should change the following check to allow lower revision
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * of FCAs; But we aren't there right now.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fc_fca_detach
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Check if the frame is a Link response Frame; Handle all cases (P_RJT,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * F_RJT, P_BSY, F_BSY fall into this category). Check also for some Basic
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Link Service responses such as BA_RJT and Extended Link Service response
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * such as LS_RJT. If the response is a Link_Data Frame or something that
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * this function doesn't understand return FC_FAILURE; Otherwise, fill out
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * various fields (state, action, reason, expln) from the response gotten
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * in the packet and return FC_SUCCESS.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* FALLTHROUGH */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefc_fca_pkt_error(fc_packet_t *pkt, char **state, char **reason,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte return (fctl_pkt_error(pkt, state, reason, action, expln));
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * WWN to string goodie. Unpredictable results will happen
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * if enough memory isn't supplied in str argument. If you
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * are wondering how much does this routine need, it is just
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * (2 * WWN size + 1). So for a WWN size of 8 bytes the str
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * argument should have atleast 17 bytes allocated.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (count = 0; count < FCTL_WWN_SIZE(wwn); count++, str += 2) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte (void) sprintf(str, "%02x", wwn->raw_wwn[count]);
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang#define FC_ATOB(x) (((x) >= '0' && (x) <= '9') ? ((x) - '0') : \
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * FCA driver's intercepted bus control operations.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_fca_bus_ctl(dev_info_t *fca_dip, dev_info_t *rip,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte return (fctl_initchild(fca_dip, (dev_info_t *)arg));
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte return (fctl_uninitchild(fca_dip, (dev_info_t *)arg));
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte return (ddi_ctlops(fca_dip, rip, op, arg, result));
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * FCAs indicate the maximum number of ports supported in their
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * tran structure. Fail the INITCHILD if the child port number
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * is any greater than the maximum number of ports supported
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * by the FCA.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_initchild(dev_info_t *fca_dip, dev_info_t *port_dip)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* physical port do not has this property */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte portprop = ddi_prop_get_int(DDI_DEV_T_ANY, port_dip,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if ((portprop == -1) && ndi_dev_is_persistent_node(port_dip)) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Clear any addr bindings created by fcode interpreter
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * in devi_last_addr so that a ndi_devi_find should never
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * return this fcode node.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte rval = ddi_prop_op(DDI_DEV_T_ANY, port_dip, PROP_LEN_AND_VAL_BUF,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte tran = (fc_fca_tran_t *)ddi_get_driver_private(fca_dip);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte dip = ndi_devi_find(fca_dip, ddi_binding_name(port_dip), name);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Even though we never initialize FCode nodes of fp, such a node
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * could still be there after a DR operation. There will only be
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * one FCode node, so if this is the one, clear it and issue a
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * ndi_devi_find again.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if ((portprop == -1) && dip && ndi_dev_is_persistent_node(dip)) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte dip = ndi_devi_find(fca_dip, ddi_binding_name(port_dip), name);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if ((portprop == -1) && dip && (dip != port_dip)) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Here we have a duplicate .conf entry. Clear the addr
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * set previously and return failure.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte/* ARGSUSED */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_uninitchild(dev_info_t *fca_dip, dev_info_t *port_dip)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_findchild(dev_info_t *pdip, char *cname, char *caddr)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* ASSERT(DEVI_BUSY_OWNED(pdip)); */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_check_npiv_portindex(dev_info_t *dip, int vindex)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte port = (fc_local_port_t *)fc_ulp_get_port_handle(instance);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if ((!port) || (vindex <= 0) || (vindex >= FC_NPIV_MAX_PORT)) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte port = (fc_local_port_t *)fc_ulp_get_port_handle(instance);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (i = 0; i < FC_NPIV_MAX_PORT; i++) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte return (i+1);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_set_npiv_portindex(dev_info_t *dip, int index)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte port = (fc_local_port_t *)fc_ulp_get_port_handle(instance);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte dev_info_t *phydip, char *nname, char *pname, uint32_t *vindex)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (*vindex == 0) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte portnum = fctl_check_npiv_portindex(phydip, *vindex);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte "Cann't find valid port index, fail to create devnode");
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (fctl_findchild(parent, cname, caddr) != NULL) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte ndi_devi_alloc_sleep(parent, cname, DEVI_PSEUDO_NODEID, &child);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte "fctl_create_npiv_port fail to create new devinfo");
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (ndi_prop_update_string(DDI_DEV_T_NONE, child,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte cmn_err(CE_WARN, "fctl%d: prop update bus-addr %s@%s failed",
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (ndi_prop_update_string(DDI_DEV_T_NONE, child,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (ndi_prop_update_string(DDI_DEV_T_NONE, child,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte cmn_err(CE_WARN, "fp%d: prop_update port %s@%s failed",
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte "phyport-instance", ddi_get_instance(phydip)) != DDI_PROP_SUCCESS) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte "fp%d: prop_update phyport-instance %s@%s failed",
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte rval = ndi_devi_online(child, NDI_ONLINE_ATTACH);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte cmn_err(CE_WARN, "fp%d: online_driver %s failed",
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte ASSERT((ulp_port->port_dstate & ULP_PORT_ATTACH) == 0);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte#endif /* __lock_lint */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_attach_ulps(fc_local_port_t *port, fc_attach_cmd_t cmd,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte info.port_acc_attr = port->fp_fca_tran->fca_acc_attr;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte info.port_fca_pkt_size = port->fp_fca_tran->fca_pkt_size;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * It is still possible that another thread could have gotten
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * into the detach process before we got here.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte switch (state = FC_PORT_STATE_MASK(info.port_state)) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte info.port_pwwn = port->fp_service_params.nport_ww_name;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte info.port_nwwn = port->fp_service_params.node_ww_name;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) {
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang if ((port->fp_soft_state & FP_SOFT_FCA_IS_NODMA) &&
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang (mod->mod_info->ulp_type == FC_TYPE_IS8802_SNAP)) {
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang * We don't support IP over FC on FCOE HBA
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if ((ulp_port = fctl_get_ulp_port(mod, port)) == NULL) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte ulp_port = fctl_add_ulp_port(mod, port, KM_SLEEP);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) {
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang if ((port->fp_soft_state & FP_SOFT_FCA_IS_NODMA) &&
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang (mod->mod_info->ulp_type == FC_TYPE_IS8802_SNAP)) {
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang * We don't support IP over FC on FCOE HBA
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (fctl_pre_attach(ulp_port, cmd) == FC_FAILURE) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (rval == FC_SUCCESS && cmd == FC_CMD_ATTACH &&
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte ASSERT(ddi_get_driver_private(info.port_dip) != NULL);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_pre_attach(fc_ulp_ports_t *ulp_port, fc_attach_cmd_t cmd)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte ASSERT((ulp_port->port_dstate & ULP_PORT_POWER_DOWN) == 0);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (!(ulp_port->port_dstate & ULP_PORT_ATTACH) ||
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (!(ulp_port->port_dstate & ULP_PORT_ATTACH) ||
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte !(ulp_port->port_dstate & ULP_PORT_POWER_DOWN)) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_post_attach(fc_ulp_module_t *mod, fc_ulp_ports_t *ulp_port,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte ASSERT(cmd == FC_CMD_ATTACH || cmd == FC_CMD_RESUME ||
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_detach_ulps(fc_local_port_t *port, fc_detach_cmd_t cmd,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte info.port_acc_attr = port->fp_fca_tran->fca_acc_attr;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte info.port_fca_pkt_size = port->fp_fca_tran->fca_pkt_size;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if ((ulp_port = fctl_get_ulp_port(mod, port)) == NULL) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (fctl_pre_detach(ulp_port, cmd) != FC_SUCCESS) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (cmd == FC_CMD_DETACH && strcmp(mod->mod_info->ulp_name,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte "fcp") == 0) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte ASSERT(ddi_get_driver_private(info.port_dip) == NULL);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_init_dma_attr(fc_local_port_t *port, fc_ulp_module_t *mod,
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang if ((strcmp(mod->mod_info->ulp_name, "fcp") == 0) ||
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang (strcmp(mod->mod_info->ulp_name, "ltct") == 0)) {
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang } else if (strcmp(mod->mod_info->ulp_name, "fcsm") == 0) {
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang } else if (strcmp(mod->mod_info->ulp_name, "fcip") == 0) {
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang info->port_cmd_dma_attr = info->port_data_dma_attr =
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_pre_detach(fc_ulp_ports_t *ulp_port, fc_detach_cmd_t cmd)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if ((ulp_port->port_dstate & ULP_PORT_ATTACH) == 0) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (!(ulp_port->port_dstate & ULP_PORT_ATTACH) ||
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (!(ulp_port->port_dstate & ULP_PORT_ATTACH) ||
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_post_detach(fc_ulp_module_t *mod, fc_ulp_ports_t *ulp_port,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte ASSERT(cmd == FC_CMD_DETACH || cmd == FC_CMD_SUSPEND ||
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_add_ulp_port(fc_ulp_module_t *ulp_module, fc_local_port_t *port_handle,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte mutex_init(&new->port_mutex, NULL, MUTEX_DRIVER, NULL);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_remove_ulp_port(struct ulp_module *ulp_module,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte ASSERT((next->port_dstate & ULP_PORT_ATTACH) == 0);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_get_ulp_port(struct ulp_module *ulp_module, fc_local_port_t *port_handle)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Pass state change notfications on to registered ULPs.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Can issue wakeups to client callers who might be waiting for completions
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * on other threads.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Caution: will silently deallocate any fc_remote_port_t and/or
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fc_remote_node_t structs it finds that are not in use.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * sanity check for presence of OLD devices in the hash lists
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (count = 0; count < clist->clist_len; count++) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Check for duplicate map entries
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (count = 0; count < clist->clist_len-1; count++) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (FCTL_DISALLOW_CALLBACKS(ulp_port->port_dstate)) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (count = 0; count < clist->clist_len; count++) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if ((pd = clist->clist_map[count].map_pd) == NULL) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * This fc_remote_port_t is no longer referenced
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * by any ULPs. Deallocate it if its pd_ref_count
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * has reached zero.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte sizeof (*(clist->clist_map)) * clist->clist_size);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Allocate an fc_remote_node_t struct to represent a remote node for the
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang * given nwwn. This will also add the nwwn to the global nwwn table.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Returns a pointer to the newly-allocated struct. Returns NULL if
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * the kmem_zalloc fails or if the enlist_wwn attempt fails.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_create_remote_node(la_wwn_t *nwwn, int sleep)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if ((rnodep = kmem_zalloc(sizeof (*rnodep), sleep)) == NULL) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte mutex_init(&rnodep->fd_mutex, NULL, MUTEX_DRIVER, NULL);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (fctl_enlist_nwwn_table(rnodep, sleep) != FC_SUCCESS) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Deconstruct and free the given fc_remote_node_t struct (remote node struct).
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Silently skips the deconstruct/free if there are any fc_remote_port_t
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * (remote port device) structs still referenced by the given
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fc_remote_node_t struct.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_destroy_remote_node(fc_remote_node_t *rnodep)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Look at the count and linked list of of remote ports
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * (fc_remote_port_t structs); bail if these indicate that
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * given fc_remote_node_t may be in use.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (rnodep->fd_numports != 0 || rnodep->fd_portlistp) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Add the given fc_remote_node_t to the global fctl_nwwn_hash_table[]. This
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * uses the nwwn in the fd_node_name.raw_wwn of the given struct.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * This only fails if the kmem_zalloc fails. This does not check for a
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * unique or pre-existing nwwn in the fctl_nwwn_hash_table[].
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * This is only called from fctl_create_remote_node().
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_enlist_nwwn_table(fc_remote_node_t *rnodep, int sleep)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if ((new = kmem_zalloc(sizeof (*new), sleep)) == NULL) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte ASSERT(fctl_is_wwn_zero(&rnodep->fd_node_name) == FC_FAILURE);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte index = HASH_FUNC(WWN_HASH_KEY(rnodep->fd_node_name.raw_wwn),
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* Link it in at the head of the hash list */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Remove the given fc_remote_node_t from the global fctl_nwwn_hash_table[].
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * This uses the nwwn in the fd_node_name.raw_wwn of the given struct.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte index = HASH_FUNC(WWN_HASH_KEY(rnodep->fd_node_name.raw_wwn),
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Found it -- unlink it from the list & decrement
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * the count for the hash chain.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Returns a reference to an fc_remote_node_t struct for the given node_wwn.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Looks in the global fctl_nwwn_hash_table[]. Identical to the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fctl_lock_remote_node_by_nwwn() function, except that this does NOT increment
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * the fc_count reference count in the f_device_t before returning.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * This function is called by: fctl_create_remote_port_t().
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * OLD COMMENT:
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Note: The calling thread needs to make sure it isn't holding any device
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * mutex (more so the fc_remote_node_t that could potentially have this wwn).
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte index = HASH_FUNC(WWN_HASH_KEY(node_wwn->raw_wwn),
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte ASSERT(index >= 0 && index < fctl_nwwn_table_size);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (fctl_wwn_cmp(node_wwn, &next->fd_node_name) == 0) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Returns a reference to an fc_remote_node_t struct for the given node_wwn.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Looks in the global fctl_nwwn_hash_table[]. Increments the fd_numports
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * reference count in the f_device_t before returning.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * This function is only called by fctl_create_remote_port_t().
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte index = HASH_FUNC(WWN_HASH_KEY(node_wwn->raw_wwn),
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte ASSERT(index >= 0 && index < fctl_nwwn_table_size);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (fctl_wwn_cmp(node_wwn, &next->fd_node_name) == 0) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Allocate and initialize an fc_remote_port_t struct & returns a pointer to
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang * the newly allocated struct. Only fails if the kmem_zalloc() fails.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_alloc_remote_port(fc_local_port_t *port, la_wwn_t *port_wwn,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if ((pd = kmem_zalloc(sizeof (*pd), sleep)) == NULL) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte fctl_tc_constructor(&pd->pd_logo_tc, FC_LOGO_TOLERANCE_LIMIT,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte mutex_init(&pd->pd_mutex, NULL, MUTEX_DRIVER, NULL);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Deconstruct and free the given fc_remote_port_t struct (unconditionally).
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Add the given fc_remote_port_t onto the linked list of remote port
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * devices associated with the given fc_remote_node_t. Does NOT add the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fc_remote_port_t to the list if already exists on the list.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_link_remote_port_to_remote_node(fc_remote_node_t *rnodep,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (ports = rnodep->fd_portlistp; ports != NULL;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * The given fc_remote_port_t is already on the linked
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * list chain for the given remote node, so bail now.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* Add the fc_remote_port_t to the tail of the linked list */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Link the fc_remote_port_t back to the associated fc_remote_node_t.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Remove the specified fc_remote_port_t from the linked list of remote ports
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * for the given fc_remote_node_t.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Returns a count of the _remaining_ fc_remote_port_t structs on the linked
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * list of the fc_remote_node_t.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * The fd_numports on the given fc_remote_node_t is decremented, and if
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * it hits zero then this function also removes the fc_remote_node_t from the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * global fctl_nwwn_hash_table[]. This appears to be the ONLY WAY that entries
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * are removed from the fctl_nwwn_hash_table[].
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_unlink_remote_port_from_remote_node(fc_remote_node_t *rnodep,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Go thru the linked list of fc_remote_port_t structs for the given
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fc_remote_node_t; try to find the specified fc_remote_port_t (pd).
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte break; /* Found the requested fc_remote_port_t */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* Note: this is only ever called from here */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Add the given fc_remote_port_t struct to the d_id table in the given
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fc_local_port_t struct. Hashes based upon the pd->pd_port_id.port_id in the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fc_remote_port_t.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * No memory allocs are required, so this never fails, but it does use the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * (pd->pd_aux_flags & PD_IN_DID_QUEUE) to keep duplicates off the list.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * (There does not seem to be a way to tell the caller that a duplicate
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_enlist_did_table(fc_local_port_t *port, fc_remote_port_t *pd)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte head = &port->fp_did_table[D_ID_HASH_FUNC(pd->pd_port_id.port_id,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Search down in each bucket for a duplicate pd
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Also search for duplicate D_IDs
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * This DEBUG code will force an ASSERT if a duplicate
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * is ever found.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (index = 0; index < did_table_size; index++) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte pd->pd_d_depth = getpcstack(pd->pd_d_stack, FC_STACK_DEPTH);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Remove the given fc_remote_port_t struct from the d_id table in the given
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fc_local_port_t struct. Hashes based upon the pd->pd_port_id.port_id in the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fc_remote_port_t.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Does nothing if the requested fc_remote_port_t was not found.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_delist_did_table(fc_local_port_t *port, fc_remote_port_t *pd)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte head = &port->fp_did_table[D_ID_HASH_FUNC(d_id, did_table_size)];
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte break; /* Found the given fc_remote_port_t */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Found the given fc_remote_port_t; now remove it from the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * d_id list.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Add the given fc_remote_port_t struct to the pwwn table in the given
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fc_local_port_t struct. Hashes based upon the pd->pd_port_name.raw_wwn
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * in the fc_remote_port_t.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * No memory allocs are required, so this never fails.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_enlist_pwwn_table(fc_local_port_t *port, fc_remote_port_t *pd)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte ASSERT(fctl_is_wwn_zero(&pd->pd_port_name) == FC_FAILURE);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte index = HASH_FUNC(WWN_HASH_KEY(pd->pd_port_name.raw_wwn),
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Search down in each bucket for a duplicate pd
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Search also for a duplicate WWN
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Throw an ASSERT if any duplicate is found.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (index = 0; index < pwwn_table_size; index++) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte pd->pd_w_depth = getpcstack(pd->pd_w_stack, FC_STACK_DEPTH);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte#endif /* DEBUG */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Make sure we tie fp_dev_count to the size of the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * pwwn_table
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Remove the given fc_remote_port_t struct from the pwwn table in the given
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fc_local_port_t struct. Hashes based upon the pd->pd_port_name.raw_wwn
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * in the fc_remote_port_t.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Does nothing if the requested fc_remote_port_t was not found.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_delist_pwwn_table(fc_local_port_t *port, fc_remote_port_t *pd)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte index = HASH_FUNC(WWN_HASH_KEY(pwwn.raw_wwn), pwwn_table_size);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte break; /* Found the given fc_remote_port_t */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Found the given fc_remote_port_t; now remove it from the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * pwwn list.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Make sure we tie fp_dev_count to the size of the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * pwwn_table
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Looks in the d_id table of the specified fc_local_port_t for the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fc_remote_port_t that matches the given d_id. Hashes based upon
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * the given d_id.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Returns a pointer to the fc_remote_port_t struct, but does not update any
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * reference counts or otherwise indicate that the fc_remote_port_t is in
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_get_remote_port_by_did(fc_local_port_t *port, uint32_t d_id)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte head = &port->fp_did_table[D_ID_HASH_FUNC(d_id, did_table_size)];
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* Match found -- break out of the loop */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte#ifndef __lock_lint /* uncomment when there is a consumer */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Looks in the d_id table of the specified fc_local_port_t for the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fc_remote_port_t that matches the given d_id. Hashes based upon
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * the given d_id. Returns a pointer to the fc_remote_port_t struct.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Increments pd_ref_count in the fc_remote_port_t if the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fc_remote_port_t is found at the given d_id.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * The fc_remote_port_t is ignored (treated as non-existent) if either
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * its pd_state == PORT_DEVICE_INVALID _OR_ its pd_type == PORT_DEVICE_OLD.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_hold_remote_port_by_did(fc_local_port_t *port, uint32_t d_id)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte head = &port->fp_did_table[D_ID_HASH_FUNC(d_id, did_table_size)];
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (pd->pd_port_id.port_id == d_id && pd->pd_state !=
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte PORT_DEVICE_INVALID && pd->pd_type != PORT_DEVICE_OLD) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte#endif /* __lock_lint */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Looks in the pwwn table of the specified fc_local_port_t for the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fc_remote_port_t that matches the given pwwn. Hashes based upon the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * given pwwn->raw_wwn. Returns a pointer to the fc_remote_port_t struct,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * but does not update any reference counts or otherwise indicate that
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * the fc_remote_port_t is in use.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_get_remote_port_by_pwwn(fc_local_port_t *port, la_wwn_t *pwwn)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte index = HASH_FUNC(WWN_HASH_KEY(pwwn->raw_wwn), pwwn_table_size);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (fctl_wwn_cmp(&pd->pd_port_name, pwwn) == 0) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Basically the same as fctl_get_remote_port_by_pwwn(), but requires that
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * the caller already hold the fp_mutex in the fc_local_port_t struct.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_get_remote_port_by_pwwn_mutex_held(fc_local_port_t *port, la_wwn_t *pwwn)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte index = HASH_FUNC(WWN_HASH_KEY(pwwn->raw_wwn), pwwn_table_size);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (fctl_wwn_cmp(&pd->pd_port_name, pwwn) == 0) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Looks in the pwwn table of the specified fc_local_port_t for the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fc_remote_port_t that matches the given d_id. Hashes based upon the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * given pwwn->raw_wwn. Returns a pointer to the fc_remote_port_t struct.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Increments pd_ref_count in the fc_remote_port_t if the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fc_remote_port_t is found at the given pwwn.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * The fc_remote_port_t is ignored (treated as non-existent) if either
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * its pd_state == PORT_DEVICE_INVALID _OR_ its pd_type == PORT_DEVICE_OLD.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_hold_remote_port_by_pwwn(fc_local_port_t *port, la_wwn_t *pwwn)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte index = HASH_FUNC(WWN_HASH_KEY(pwwn->raw_wwn), pwwn_table_size);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (fctl_wwn_cmp(&pd->pd_port_name, pwwn) == 0 &&
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Unconditionally decrement pd_ref_count in the given fc_remote_port_t
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * If pd_ref_count reaches zero, then this function will see if the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fc_remote_port_t has been marked for deallocation. If so (and also if there
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * are no other potential operations in progress, as indicated by the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * PD_ELS_IN_PROGRESS & PD_ELS_MARK settings in the pd_flags), then
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fctl_destroy_remote_port_t() is called to deconstruct/free the given
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fc_remote_port_t (which will also remove it from the d_id and pwwn tables
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang * on the associated fc_local_port_t). If the associated fc_remote_node_t is no
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * longer in use, then it too is deconstructed/freed.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * The fc_remote_port_t struct has to go away now, so call the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * cleanup function to get it off the various lists and remove
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * references to it in any other associated structs.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * No more fc_remote_port_t references found in the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * associated fc_remote_node_t, so deallocate the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fc_remote_node_t (if it even exists).
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_fillout_map(fc_local_port_t *port, fc_portmap_t **map, uint32_t *len,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (*len == 0) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * By design this routine mandates the callers to
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * ask for a whole map when they specify the length
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * and the listptr.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (index = 0; index < pwwn_table_size; index++) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Remove this from the PWWN hash table.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Make sure we tie fp_dev_count to the size
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * of the pwwn_table
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Remove if the port device has stealthily
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * present in the D_ID hash table
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_alloc_job(int job_code, int job_flags, void (*comp) (opaque_t, uchar_t),
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte job = (job_request_t *)kmem_cache_alloc(fctl_job_cache, sleep);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte#endif /* __lock_lint */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_enque_job(fc_local_port_t *port, job_request_t *job)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_priority_enque_job(fc_local_port_t *port, job_request_t *job)
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang * Compare two WWNs.
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang * The NAA can't be omitted for comparison.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Return Values:
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * if src == dst return 0
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * if src > dst return 1
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * if src < dst return -1
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang return (-1);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * ASCII to Integer goodie with support for base 16, 10, 2 and 8
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte return (-1);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte return (-1);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte return (-1);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte return (-1);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte return (-1);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Create the fc_remote_port_t struct for the given port_wwn and d_id.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * If the struct already exists (and is "valid"), then use it. Before using
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * it, the code below also checks: (a) if the d_id has changed, and (b) if
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * the device is maked as PORT_DEVICE_OLD.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * If no fc_remote_node_t struct exists for the given node_wwn, then that
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * struct is also created (and linked with the fc_remote_port_t).
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * The given fc_local_port_t struct is updated with the info on the new
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * struct(s). The d_id and pwwn hash tables in the port_wwn are updated.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * The global node_hash_table[] is updated (if necessary).
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_create_remote_port(fc_local_port_t *port, la_wwn_t *node_wwn,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte la_wwn_t *port_wwn, uint32_t d_id, uchar_t recepient, int sleep)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * We found an fc_remote_node_t for the remote node -- see if
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * anyone has marked it as going away or gone.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte invalid = (rnodep->fd_flags == FC_REMOTE_NODE_INVALID) ? 1 : 0;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * No valid remote node struct found -- create it.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Note: this is the only place that this func is called.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte rnodep = fctl_create_remote_node(node_wwn, sleep);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * See if there already is an fc_remote_port_t struct in existence
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang * on the specified fc_local_port_t for the given pwwn. If so, then
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * grab a reference to it. The 'held' here just means that fp_mutex
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * is held by the caller -- no reference counts are updated.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte pd = fctl_get_remote_port_by_pwwn_mutex_held(port, port_wwn);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * An fc_remote_port_t struct was found -- see if anyone has
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * marked it as "invalid", which means that it is in the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * process of going away & we don't want to use it.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte invalid = (pd->pd_state == PORT_DEVICE_INVALID) ? 1 : 0;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * No fc_remote_port_t was found (or the existing one is
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * marked as "invalid".) Allocate a new one and use that.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * This call will also update the d_id and pwwn hash tables
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * in the given fc_local_port_t struct with the newly allocated
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fc_remote_port_t.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if ((pd = fctl_alloc_remote_port(port, port_wwn, d_id,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* Just give up if the allocation fails. */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Add the new fc_remote_port_t struct to the d_id and pwwn
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * hash tables on the associated fc_local_port_t struct.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Retrieve a pointer to the fc_remote_node_t (i.e., remote
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * node) specified by the given node_wwn. This looks in the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * global fctl_nwwn_hash_table[]. The fd_numports reference
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * count in the fc_remote_node_t struct is incremented.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte rnodep = fctl_lock_remote_node_by_nwwn(node_wwn);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * An existing and valid fc_remote_port_t struct already
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * exists on the fc_local_port_t for the given pwwn.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * A very unlikely occurance in a well
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * behaved environment.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * The existing fc_remote_port_t has a different
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * d_id than what we were given. This code will
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * update the existing one with the one that was
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * just given.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte " with PWWN %s changed. New D_ID = %x,"
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Looks like we have to presume here that the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * remote port could be something entirely different
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * from what was previously existing & valid at this
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* Record (update) the new d_id for the remote port */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * OK at least the old & new d_id's match. So for
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * PORT_DEVICE_OLD, this assumes that the remote
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * port had disappeared but now has come back.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Update the pd_type and pd_state to put the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * remote port back into service.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * OK the old & new d_id's match, and the remote
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * port struct is not marked as PORT_DEVICE_OLD, so
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * presume that it's still the same device and is
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang * still in good shape. Also this presumes that we
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * do not need to update d_id or pwwn hash tables.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* sanitize device values */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte (fctl_wwn_cmp(&pd->pd_remote_nodep->fd_node_name,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Rut-roh, there is an fc_remote_node_t remote
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * node struct for the given node_wwn, but the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fc_remote_port_t remote port struct doesn't
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * know about it. This just prints a warning
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * message & fails the fc_remote_port_t
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * allocation (possible leak here?).
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang * Add the fc_remote_port_t onto the linked list of remote port
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * devices associated with the given fc_remote_node_t (remote node).
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte fctl_link_remote_port_to_remote_node(rnodep, pd);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Disassociate the given fc_local_port_t and fc_remote_port_t structs. Removes
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * the fc_remote_port_t from the associated fc_remote_node_t. Also removes any
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * references to the fc_remote_port_t from the d_id and pwwn tables in the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * given fc_local_port_t. Deallocates the given fc_remote_port_t.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Returns a count of the number of remaining fc_remote_port_t structs
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * associated with the fc_remote_node_t struct.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * If pd_ref_count in the given fc_remote_port_t is nonzero, then this
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * function just sets the pd->pd_aux_flags |= PD_NEEDS_REMOVAL and the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * pd->pd_type = PORT_DEVICE_OLD and lets some other function(s) worry about
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang * the cleanup. The function then also returns '1'
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * instead of the actual number of remaining fc_remote_port_t structs
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * If there are no more remote ports on the remote node, return 0.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Otherwise, return non-zero.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_destroy_remote_port(fc_local_port_t *port, fc_remote_port_t *pd)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * If pd_ref_count > 0, we can't pull the rug out from any
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * current users of this fc_remote_port_t. We'll mark it as old
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * and in need of removal. The same goes for any fc_remote_port_t
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * that has a reference handle(s) in a ULP(s) but for which the ULP(s)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * have not yet been notified that the handle is no longer valid
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * (i.e., PD_GIVEN_TO_ULPS is set).
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Remove the fc_remote_port_t from the linked list of remote
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * ports for the given fc_remote_node_t. This is only called
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * here and in fctl_destroy_all_remote_ports().
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte rcount = fctl_unlink_remote_port_from_remote_node(rnodep, pd);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Deconstruct & free the fc_remote_port_t. This is only called
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * here and in fctl_destroy_all_remote_ports().
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * This goes thru the d_id table on the given fc_local_port_t.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * For each fc_remote_port_t found, this will:
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * - Remove the fc_remote_port_t from the linked list of remote ports for
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang * the associated fc_remote_node_t. If the linked list goes empty, then this
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * tries to deconstruct & free the fc_remote_node_t (that also removes the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fc_remote_node_t from the global fctl_nwwn_hash_table[]).
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * - Remove the fc_remote_port_t from the pwwn list on the given
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fc_local_port_t.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * - Deconstruct and free the fc_remote_port_t.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * - Removes the link to the fc_remote_port_t in the d_id table. Note, this
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * does not appear to correctle decrement the d_id_count tho.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_destroy_all_remote_ports(fc_local_port_t *port)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (index = 0; index < did_table_size; index++) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * See if this remote port (fc_remote_port_t) has a
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * reference to a remote node (fc_remote_node_t) in its
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * pd->pd_remote_nodep pointer.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * An fc_remote_node_t reference exists. Remove
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * the fc_remote_port_t from the linked list of
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * remote ports for fc_remote_node_t.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * The fd_numports reference count
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * in the fc_remote_node_t has come
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * back as zero, so we can free the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fc_remote_node_t. This also means
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * that the fc_remote_node_t was
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * removed from the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fctl_nwwn_hash_table[].
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * This will silently skip the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * kmem_free() if either the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fd_numports is nonzero or
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * the fd_port is not NULL in
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * the fc_remote_node_t.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Clean up the entry in the fc_local_port_t's pwwn
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * table for the given fc_remote_port_t (i.e., the pd).
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Remove the current entry from the d_id list.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Deconstruct & free the fc_remote_port_t (pd)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Note: this is only called here and in
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fctl_destroy_remote_port_t().
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (count = 0; count < sizeof (la_wwn_t); count++) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_ulp_unsol_cb(fc_local_port_t *port, fc_unsol_buf_t *buf, uchar_t type)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* FALLTHROUGH */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (check_type && mod->mod_info->ulp_type != type) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (FCTL_DISALLOW_CALLBACKS(ulp_port->port_dstate)) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * We should actually RJT since nobody claimed it.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Both fd_mutex and pd_mutex are held (in that order) coming in to this func
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * With all these mutexes held, we should make sure this function does not eat
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * up much time.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_copy_portmap_held(fc_portmap_t *map, fc_remote_port_t *pd)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte bcopy(pd->pd_fc4types, map->map_fc4_types, sizeof (pd->pd_fc4types));
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_copy_portmap(fc_portmap_t *map, fc_remote_port_t *pd)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte bcopy(pd->pd_fc4types, map->map_fc4_types, sizeof (pd->pd_fc4types));
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_update_host_ns_values(fc_local_port_t *port, fc_ns_cmd_t *ns_req)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte bcopy(ipa->ipa_value, port->fp_ipa, sizeof (ipa->ipa_value));
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_retrieve_host_ns_values(fc_local_port_t *port, fc_ns_cmd_t *ns_req)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte bcopy(port->fp_ipa, ipa->ipa_value, sizeof (ipa->ipa_value));
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_alloc_ns_cmd(uint32_t cmd_len, uint32_t resp_len, uint32_t data_len,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte ns_cmd->ns_cmd_buf = kmem_zalloc(cmd_len, sleep);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte ns_cmd->ns_data_buf = kmem_zalloc(data_len, sleep);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte kmem_free(ns_cmd->ns_cmd_buf, ns_cmd->ns_cmd_size);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (ns_cmd->ns_data_len && ns_cmd->ns_data_buf) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte kmem_free(ns_cmd->ns_data_buf, ns_cmd->ns_data_len);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_ulp_port_ioctl(fc_local_port_t *port, dev_t dev, int cmd,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte intptr_t data, int mode, cred_t *credp, int *rval)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (claimed = 0, mod = fctl_ulp_modules; mod; mod = mod->mod_next) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (FCTL_DISALLOW_CALLBACKS(ulp_port->port_dstate) ||
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * raise power if necessary, and set the port busy
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * this may cause power to be raised, so no power related locks should
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefc_ulp_copy_portmap(fc_portmap_t *map, opaque_t pd)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefc_get_npiv_port(fc_local_port_t *phyport, la_wwn_t *pwwn)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (fca_port = fctl_fca_portlist; fca_port != NULL;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (bcmp(tmpPort->fp_service_params.nport_ww_name.raw_wwn,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefc_ulp_get_npiv_port_list(opaque_t port_handle, char *pathList)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (!tmpport || (port->fp_npiv_type == FC_NPIV_PORT)) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefc_delete_npiv_port(fc_local_port_t *port, la_wwn_t *pwwn)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (!tmpport || (port->fp_npiv_type == FC_NPIV_PORT)) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if ((bcmp(tmpport->fp_service_params.nport_ww_name.raw_wwn,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Get the list of Adapters. On multi-ported adapters,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * only ONE port on the adapter will be returned.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * pathList should be (count * MAXPATHLEN) long.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * The return value will be set to the number of
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang * HBAs that were found on the system. If the value
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * is greater than count, the routine should be retried
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * with a larger buffer.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefc_ulp_get_adapter_paths(char *pathList, int count)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* First figure out how many ports we have */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (fca_port = fctl_fca_portlist; fca_port != NULL;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* Now allocate a buffer to store all the pointers for comparisons */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte portList = kmem_zalloc(sizeof (fc_local_port_t *) * maxPorts, KM_SLEEP);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (fca_port = fctl_fca_portlist; fca_port != NULL;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* Lock the new port for subsequent comparisons */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte new_fru = &new_port->fp_hba_port_attrs.hba_fru_details;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* Filter out secondary ports from the list */
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang /* Guard against duplicates (should never happen) */
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang /* Same port */
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang /* Lock the already stored port for comparison */
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang /* Are these ports on the same HBA? */
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang /* Now double check driver */
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang /* we don't need to grow the list */
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang /* looking at a lower port index? */
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang /* Replace the port in list */
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang } /* Else, just skip this port */
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang * Either this is the first port for this HBA, or
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang * it's a secondary port and we haven't stored the
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang * primary/first port for that HBA. In the latter case,
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang * will just filter it out as we proceed to loop.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte kmem_free(portList, sizeof (*portList) * maxPorts);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * This function is a very similar to fctl_add_orphan except that it expects
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * that the fp_mutex and pd_mutex of the pd passed in are held coming in.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Note that there is a lock hierarchy here (fp_mutex should be held first) but
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * since this function could be called with a different pd's pd_mutex held, we
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * should take care not to release fp_mutex in this function.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_add_orphan_held(fc_local_port_t *port, fc_remote_port_t *pd)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (orp = port->fp_orphan_list; orp != NULL; orp = orp->orp_next) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte orphan = kmem_zalloc(sizeof (*orphan), KM_NOSLEEP);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_add_orphan(fc_local_port_t *port, fc_remote_port_t *pd, int sleep)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (orp = port->fp_orphan_list; orp != NULL; orp = orp->orp_next) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_remove_if_orphan(fc_local_port_t *port, la_wwn_t *pwwn)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (orp = port->fp_orphan_list; orp != NULL; orp = orp->orp_next) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_print_if_not_orphan(fc_local_port_t *port, fc_remote_port_t *pd)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (orp = port->fp_orphan_list; orp != NULL; orp = orp->orp_next) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte cmn_err(CE_WARN, "!fctl(%d): N_x Port with D_ID=%x, PWWN=%s"
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte/* ARGSUSED */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_link_reset_done(opaque_t port_handle, uchar_t result)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Return number of successful translations.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Anybody with some userland programming experience would have
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * figured it by now that the return value exactly resembles that
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * of scanf(3c). This function returns a count of successful
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * translations. It could range from 0 (no match for state, reason,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * action, expln) to 4 (successful matches for all state, reason,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * action, expln) and where translation isn't successful into a
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * friendlier message the relevent field is set to "Undefined"
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_pkt_error(fc_packet_t *pkt, char **state, char **reason,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte *state = *reason = *action = *expln = fctl_undefined;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte len = sizeof (fc_pkt_errlist) / sizeof fc_pkt_errlist[0];
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Remove all port devices that are marked OLD, remove
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * corresponding node devices (fc_remote_node_t)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Nuke all OLD devices
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (index = 0; index < pwwn_table_size; index++) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Remove this from the PWWN hash table
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Make sure we tie fp_dev_count to the size of the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * pwwn_table
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (FC_IS_TOP_SWITCH(port->fp_topology) && initiator) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (fctl_destroy_remote_port(port, old_pd) == 0) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_check_alpa_list(fc_local_port_t *port, fc_remote_port_t *pd)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte ASSERT(port->fp_topology == FC_TOP_PRIVATE_LOOP);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (fctl_is_alpa_present(port, pd->pd_port_id.port_id) == FC_SUCCESS) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte cmn_err(CE_WARN, "!fctl(%d): AL_PA=0x%x doesn't exist in LILP map",
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_is_alpa_present(fc_local_port_t *port, uchar_t alpa)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte ASSERT(port->fp_topology == FC_TOP_PRIVATE_LOOP);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (index = 0; index < port->fp_lilp_map.lilp_length; index++) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (port->fp_lilp_map.lilp_alpalist[index] == alpa) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_lookup_pd_by_did(fc_local_port_t *port, uint32_t d_id)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (index = 0; index < pwwn_table_size; index++) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * trace debugging
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefc_trace_debug(fc_trace_logq_t *logq, caddr_t name, int dflag, int dlevel,
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang char buf[FC_MAX_TRACE_BUF_LEN + 3]; /* 3 is for "\n" */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte cnt = snprintf(buf, FC_MAX_TRACE_BUF_LEN + 1, "%d=>%s::",
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte cnt = snprintf(buf, FC_MAX_TRACE_BUF_LEN + 1, "%d=>trace::",
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte cnt += vsnprintf(buf + cnt, FC_MAX_TRACE_BUF_LEN + 1 - cnt,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte cnt += snprintf(buf + cnt, FC_MAX_TRACE_BUF_LEN + 1 - cnt,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte (void) snprintf(buf + cnt, FC_MAX_TRACE_BUF_LEN + 3 - cnt, "\n");
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * We do not want to print the log numbers that appear as
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * random numbers at the console and messages files, to
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * We would have added the a string with "=>" above and so,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * ideally, we should not get here at all. But, if we do,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * we'll just use the full buf.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * This function can block
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte mutex_init(&logq->il_lock, NULL, MUTEX_DRIVER, NULL);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte/* ARGSUSED */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefc_trace_logmsg(fc_trace_logq_t *logq, caddr_t buf, int level)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte dmsg->id_buf = kmem_alloc(dmsg->id_size, KM_NOSLEEP);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Used by T11 FC-HBA to fetch discovered ports by index.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Returns NULL if the index isn't valid.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_lookup_pd_by_index(fc_local_port_t *port, uint32_t index)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Search for a matching Node or Port WWN in the discovered port list
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_lookup_pd_by_wwn(fc_local_port_t *port, la_wwn_t wwn)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (index = 0; index < pwwn_table_size; index++) {
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang sizeof (la_wwn_t)) == 0) {
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang if (bcmp(pd->pd_remote_nodep->fd_node_name.raw_wwn,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* No match */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Count the number of ports on this adapter.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * This routine will walk the port list and count up the number of adapters
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * with matching fp_hba_port_attrs.hba_fru_details.high and
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fp_hba_port_attrs.hba_fru_details.low.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * port->fp_mutex must not be held.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_count_fru_ports(fc_local_port_t *port, int npivflag)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* Detect FCA drivers that don't support linking HBA ports */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (fru->high == 0 && fru->low == 0 && fru->port_index == 0) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (fca_port = fctl_fca_portlist; fca_port != NULL;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * If an FCA driver returns unique fru->high and fru->low for
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * ports on the same card, there is no way for the transport
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * layer to determine that the two ports on the same FRU. So,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * the discovery of the ports on a same FRU is limited to what
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * the FCA driver can report back.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (tmpPort->fp_hba_port_attrs.hba_fru_details.high ==
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte tmpPort->fp_hba_port_attrs.hba_fru_details.low ==
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* Now double check driver */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte } /* Else, different FCA driver */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte } /* Else not the same HBA FRU */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_local_port_list_add(fc_fca_port_t *list, fc_local_port_t *port)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte newentry = kmem_zalloc(sizeof (fc_fca_port_t), KM_NOSLEEP);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte while (tmp->port_next != NULL) tmp = tmp->port_next;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Fetch another port on the HBA FRU based on index.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Returns NULL if index not found.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * port->fp_mutex must not be held.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefctl_get_adapter_port_by_index(fc_local_port_t *port, uint32_t port_index)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* Are we looking for this port? */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* Detect FCA drivers that don't support linking HBA ports */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (fru->high == 0 && fru->low == 0 && fru->port_index == 0) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* Loop through all known ports */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (fca_port = fctl_fca_portlist; fca_port != NULL;
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang /* Skip the port that was passed in as the argument */
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang /* See if this port is on the same HBA FRU (fast check) */
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang if (tmpPort->fp_hba_port_attrs.hba_fru_details.high ==
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte tmpPort->fp_hba_port_attrs.hba_fru_details.low ==
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang /* Now double check driver (slower check) */
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang /* Check for the matching port_index */
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang /* Found it! */
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang } /* Else, different FCA driver */
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang } /* Else not the same HBA FRU */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* scan all physical port on same chip to find virtual port */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * If fctl_busy_port() is called before we've registered our
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * PM components, we return success. We need to be aware of
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * this because the caller will eventually call fctl_idle_port.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * This wouldn't be a problem except that if we have
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * registered our PM components in the meantime, we will
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * then be idling a component that was never busied. PM
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang * will be very unhappy if we do this. Thus, we keep
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * track of this with port->fp_pm_busy_nocomp.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (pm_raise_power(port->fp_port_dip, FP_PM_COMPONENT,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * If port->fp_pm_busy_nocomp is > 0, that means somebody had
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * called fctl_busy_port prior to us registering our PM components.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * In that case, we just decrement fp_pm_busy_nocomp and return.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte (void) pm_idle_component(port->fp_port_dip, FP_PM_COMPONENT);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Function: fctl_tc_timer
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Description: Resets the value of the timed counter.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Arguments: *tc Timed counter
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Return Value: Nothing
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang * Context: Kernel context.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Function: fctl_tc_constructor
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Description: Constructs a timed counter.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Arguments: *tc Address where the timed counter will reside.
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang * max_value Maximum value the counter is allowed to take.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * timer Number of microseconds after which the counter
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * will be reset. The timer is started when the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * value of the counter goes from 0 to 1.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Return Value: Nothing
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang * Context: Kernel context.
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wangfctl_tc_constructor(timed_counter_t *tc, uint32_t max_value, clock_t timer)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte mutex_init(&tc->mutex, NULL, MUTEX_DRIVER, NULL);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Function: fctl_tc_destructor
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Description: Destroyes a timed counter.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Arguments: *tc Timed counter to destroy.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Return Value: Nothing
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang * Context: Kernel context.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Function: fctl_tc_increment
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Description: Increments a timed counter
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Arguments: *tc Timed counter to increment.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Return Value: B_TRUE Counter reached the max value.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * B_FALSE Counter hasn't reached the max value.
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang * Context: Kernel or interrupt context.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* Hasn't maxed out yet. */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* Just maxed out. */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Function: fctl_tc_reset
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Description: Resets a timed counter. The caller of this function has to
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * to make sure that while in fctl_tc_reset() fctl_tc_increment()
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * is not called.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Arguments: *tc Timed counter to reset.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Return Value: 0 Counter reached the max value.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Not 0 Counter hasn't reached the max value.
7ff836697c120cb94bd30d5c2204eb9b74718e4cZhong Wang * Context: Kernel or interrupt context.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefc_ulp_log_device_event(opaque_t port_handle, int type)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte (void) ddi_log_sysevent(port->fp_port_dip, DDI_VENDOR_SUNW, EC_SUNFC,