25e8c5aa2b496d9026e958ac731a610167574f59vikram * CDDL HEADER START
25e8c5aa2b496d9026e958ac731a610167574f59vikram * The contents of this file are subject to the terms of the
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Common Development and Distribution License (the "License").
25e8c5aa2b496d9026e958ac731a610167574f59vikram * You may not use this file except in compliance with the License.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
25e8c5aa2b496d9026e958ac731a610167574f59vikram * See the License for the specific language governing permissions
25e8c5aa2b496d9026e958ac731a610167574f59vikram * and limitations under the License.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * When distributing Covered Code, include this CDDL HEADER in each
25e8c5aa2b496d9026e958ac731a610167574f59vikram * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * If applicable, add the following below this CDDL HEADER, with the
25e8c5aa2b496d9026e958ac731a610167574f59vikram * fields enclosed by brackets "[]" replaced with your own identifying
25e8c5aa2b496d9026e958ac731a610167574f59vikram * information: Portions Copyright [yyyy] [name of copyright owner]
25e8c5aa2b496d9026e958ac731a610167574f59vikram * CDDL HEADER END
2eb07f5e03e6bf6a25f9305ffda328fdb94f1425Stephen Hanson * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
25e8c5aa2b496d9026e958ac731a610167574f59vikram#undef ct_lock /* needed because clnt.h defines ct_lock as a macro */
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Device Contracts
25e8c5aa2b496d9026e958ac731a610167574f59vikram * -----------------
25e8c5aa2b496d9026e958ac731a610167574f59vikram * This file contains the core code for the device contracts framework.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * A device contract is an agreement or a contract between a process and
25e8c5aa2b496d9026e958ac731a610167574f59vikram * the kernel regarding the state of the device. A device contract may be
25e8c5aa2b496d9026e958ac731a610167574f59vikram * created when a relationship is formed between a device and a process
25e8c5aa2b496d9026e958ac731a610167574f59vikram * i.e. at open(2) time, or it may be created at some point after the device
25e8c5aa2b496d9026e958ac731a610167574f59vikram * has been opened. A device contract once formed may be broken by either party.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * A device contract can be broken by the process by an explicit abandon of the
25e8c5aa2b496d9026e958ac731a610167574f59vikram * contract or by an implicit abandon when the process exits. A device contract
25e8c5aa2b496d9026e958ac731a610167574f59vikram * can be broken by the kernel either asynchronously (without negotiation) or
25e8c5aa2b496d9026e958ac731a610167574f59vikram * synchronously (with negotiation). Exactly which happens depends on the device
25e8c5aa2b496d9026e958ac731a610167574f59vikram * state transition. The following state diagram shows the transitions between
25e8c5aa2b496d9026e958ac731a610167574f59vikram * device states. Only device state transitions currently supported by device
25e8c5aa2b496d9026e958ac731a610167574f59vikram * contracts is shown.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * <-- A -->
25e8c5aa2b496d9026e958ac731a610167574f59vikram * /-----------------> DEGRADED
25e8c5aa2b496d9026e958ac731a610167574f59vikram * v S --> v
25e8c5aa2b496d9026e958ac731a610167574f59vikram * ONLINE ------------> OFFLINE
25e8c5aa2b496d9026e958ac731a610167574f59vikram * In the figure above, the arrows indicate the direction of transition. The
25e8c5aa2b496d9026e958ac731a610167574f59vikram * letter S refers to transitions which are inherently synchronous i.e.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * require negotiation and the letter A indicates transitions which are
25e8c5aa2b496d9026e958ac731a610167574f59vikram * asynchronous i.e. are done without contract negotiations. A good example
25e8c5aa2b496d9026e958ac731a610167574f59vikram * of a synchronous transition is the ONLINE -> OFFLINE transition. This
25e8c5aa2b496d9026e958ac731a610167574f59vikram * transition cannot happen as long as there are consumers which have the
25e8c5aa2b496d9026e958ac731a610167574f59vikram * device open. Thus some form of negotiation needs to happen between the
25e8c5aa2b496d9026e958ac731a610167574f59vikram * consumers and the kernel to ensure that consumers either close devices
25e8c5aa2b496d9026e958ac731a610167574f59vikram * or disallow the move to OFFLINE. Certain other transitions such as
25e8c5aa2b496d9026e958ac731a610167574f59vikram * ONLINE --> DEGRADED for example, are inherently asynchronous i.e.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * non-negotiable. A device that suffers a fault that degrades its
25e8c5aa2b496d9026e958ac731a610167574f59vikram * capabilities will become degraded irrespective of what consumers it has,
25e8c5aa2b496d9026e958ac731a610167574f59vikram * so a negotiation in this case is pointless.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * The following device states are currently defined for device contracts:
25e8c5aa2b496d9026e958ac731a610167574f59vikram * CT_DEV_EV_ONLINE
25e8c5aa2b496d9026e958ac731a610167574f59vikram * The device is online and functioning normally
25e8c5aa2b496d9026e958ac731a610167574f59vikram * CT_DEV_EV_DEGRADED
25e8c5aa2b496d9026e958ac731a610167574f59vikram * The device is online but is functioning in a degraded capacity
25e8c5aa2b496d9026e958ac731a610167574f59vikram * CT_DEV_EV_OFFLINE
25e8c5aa2b496d9026e958ac731a610167574f59vikram * The device is offline and is no longer configured
25e8c5aa2b496d9026e958ac731a610167574f59vikram * A typical consumer of device contracts starts out with a contract
25e8c5aa2b496d9026e958ac731a610167574f59vikram * template and adds terms to that template. These include the
25e8c5aa2b496d9026e958ac731a610167574f59vikram * "acceptable set" (A-set) term, which is a bitset of device states which
25e8c5aa2b496d9026e958ac731a610167574f59vikram * are guaranteed by the contract. If the device moves out of a state in
25e8c5aa2b496d9026e958ac731a610167574f59vikram * the A-set, the contract is broken. The breaking of the contract can
25e8c5aa2b496d9026e958ac731a610167574f59vikram * be asynchronous in which case a critical contract event is sent to the
25e8c5aa2b496d9026e958ac731a610167574f59vikram * contract holder but no negotiations take place. If the breaking of the
25e8c5aa2b496d9026e958ac731a610167574f59vikram * contract is synchronous, negotations are opened between the affected
25e8c5aa2b496d9026e958ac731a610167574f59vikram * consumer and the kernel. The kernel does this by sending a critical
25e8c5aa2b496d9026e958ac731a610167574f59vikram * event to the consumer with the CTE_NEG flag set indicating that this
25e8c5aa2b496d9026e958ac731a610167574f59vikram * is a negotiation event. The consumer can accept this change by sending
25e8c5aa2b496d9026e958ac731a610167574f59vikram * a ACK message to the kernel. Alternatively, if it has the necessary
25e8c5aa2b496d9026e958ac731a610167574f59vikram * privileges, it can send a NACK message to the kernel which will block
25e8c5aa2b496d9026e958ac731a610167574f59vikram * the device state change. To NACK a negotiable event, a process must
25e8c5aa2b496d9026e958ac731a610167574f59vikram * have the {PRIV_SYS_DEVICES} privilege asserted in its effective set.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Other terms include the "minor path" term, specified explicitly if the
25e8c5aa2b496d9026e958ac731a610167574f59vikram * contract is not being created at open(2) time or specified implicitly
25e8c5aa2b496d9026e958ac731a610167574f59vikram * if the contract is being created at open time via an activated template.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * A contract event is sent on any state change to which the contract
25e8c5aa2b496d9026e958ac731a610167574f59vikram * owner has subscribed via the informative or critical event sets. Only
25e8c5aa2b496d9026e958ac731a610167574f59vikram * critical events are guaranteed to be delivered. Since all device state
25e8c5aa2b496d9026e958ac731a610167574f59vikram * changes are controlled by the kernel and cannot be arbitrarily generated
25e8c5aa2b496d9026e958ac731a610167574f59vikram * by a non-privileged user, the {PRIV_CONTRACT_EVENT} privilege does not
25e8c5aa2b496d9026e958ac731a610167574f59vikram * need to be asserted in a process's effective set to designate an event as
25e8c5aa2b496d9026e958ac731a610167574f59vikram * critical. To ensure privacy, a process must either have the same effective
25e8c5aa2b496d9026e958ac731a610167574f59vikram * userid as the contract holder or have the {PRIV_CONTRACT_OBSERVER} privilege
25e8c5aa2b496d9026e958ac731a610167574f59vikram * asserted in its effective set in order to observe device contract events
25e8c5aa2b496d9026e958ac731a610167574f59vikram * off the device contract type specific endpoint.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Yet another term available with device contracts is the "non-negotiable"
25e8c5aa2b496d9026e958ac731a610167574f59vikram * term. This term is used to pre-specify a NACK to any contract negotiation.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * This term is ignored for asynchronous state changes. For example, a
25e8c5aa2b496d9026e958ac731a610167574f59vikram * provcess may have the A-set {ONLINE|DEGRADED} and make the contract
25e8c5aa2b496d9026e958ac731a610167574f59vikram * non-negotiable. In this case, the device contract framework assumes a
25e8c5aa2b496d9026e958ac731a610167574f59vikram * NACK for any transition to OFFLINE and blocks the offline. If the A-set
25e8c5aa2b496d9026e958ac731a610167574f59vikram * is {ONLINE} and the non-negotiable term is set, transitions to OFFLINE
25e8c5aa2b496d9026e958ac731a610167574f59vikram * are NACKed but transitions to DEGRADE succeed.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * The OFFLINE negotiation (if OFFLINE state is not in the A-set for a contract)
25e8c5aa2b496d9026e958ac731a610167574f59vikram * happens just before the I/O framework attempts to offline a device
25e8c5aa2b496d9026e958ac731a610167574f59vikram * (i.e. detach a device and set the offline flag so that it cannot be
25e8c5aa2b496d9026e958ac731a610167574f59vikram * reattached). A device contract holder is expected to either NACK the offline
25e8c5aa2b496d9026e958ac731a610167574f59vikram * (if privileged) or release the device and allow the offline to proceed.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * The DEGRADE contract event (if DEGRADE is not in the A-set for a contract)
25e8c5aa2b496d9026e958ac731a610167574f59vikram * is generated just before the I/O framework transitions the device state
25e8c5aa2b496d9026e958ac731a610167574f59vikram * to "degraded" (i.e. DEVI_DEVICE_DEGRADED in I/O framework terminology).
25e8c5aa2b496d9026e958ac731a610167574f59vikram * The contract holder is expected to ACK or NACK a negotiation event
25e8c5aa2b496d9026e958ac731a610167574f59vikram * within a certain period of time. If the ACK/NACK is not received
25e8c5aa2b496d9026e958ac731a610167574f59vikram * within the timeout period, the device contract framework will behave
25e8c5aa2b496d9026e958ac731a610167574f59vikram * as if the contract does not exist and will proceed with the event.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Unlike a process contract a device contract does not need to exist
25e8c5aa2b496d9026e958ac731a610167574f59vikram * once it is abandoned, since it does not define a fault boundary. It
25e8c5aa2b496d9026e958ac731a610167574f59vikram * merely represents an agreement between a process and the kernel
25e8c5aa2b496d9026e958ac731a610167574f59vikram * regarding the state of the device. Once the process has abandoned
25e8c5aa2b496d9026e958ac731a610167574f59vikram * the contract (either implicitly via a process exit or explicitly)
25e8c5aa2b496d9026e958ac731a610167574f59vikram * the kernel has no reason to retain the contract. As a result
25e8c5aa2b496d9026e958ac731a610167574f59vikram * device contracts are neither inheritable nor need to exist in an
25e8c5aa2b496d9026e958ac731a610167574f59vikram * orphan state.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * A device unlike a process may exist in multiple contracts and has
25e8c5aa2b496d9026e958ac731a610167574f59vikram * a "life" outside a device contract. A device unlike a process
25e8c5aa2b496d9026e958ac731a610167574f59vikram * may exist without an associated contract. Unlike a process contract
25e8c5aa2b496d9026e958ac731a610167574f59vikram * a device contract may be formed after a binding relationship is
25e8c5aa2b496d9026e958ac731a610167574f59vikram * formed between a process and a device.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * IMPLEMENTATION NOTES
25e8c5aa2b496d9026e958ac731a610167574f59vikram * ====================
25e8c5aa2b496d9026e958ac731a610167574f59vikram * DATA STRUCTURES
25e8c5aa2b496d9026e958ac731a610167574f59vikram * ----------------
25e8c5aa2b496d9026e958ac731a610167574f59vikram * The heart of the device contracts implementation is the device contract
25e8c5aa2b496d9026e958ac731a610167574f59vikram * private cont_device_t (or ctd for short) data structure. It encapsulates
25e8c5aa2b496d9026e958ac731a610167574f59vikram * the generic contract_t data structure and has a number of private
25e8c5aa2b496d9026e958ac731a610167574f59vikram * These include:
25e8c5aa2b496d9026e958ac731a610167574f59vikram * cond_minor: The minor device that is the subject of the contract
25e8c5aa2b496d9026e958ac731a610167574f59vikram * cond_aset: The bitset of states which are guaranteed by the
25e8c5aa2b496d9026e958ac731a610167574f59vikram * cond_noneg: If set, indicates that the result of negotiation has
25e8c5aa2b496d9026e958ac731a610167574f59vikram * been predefined to be a NACK
25e8c5aa2b496d9026e958ac731a610167574f59vikram * In addition, there are other device identifiers such the devinfo node,
25e8c5aa2b496d9026e958ac731a610167574f59vikram * dev_t and spec_type of the minor node. There are also a few fields that
25e8c5aa2b496d9026e958ac731a610167574f59vikram * are used during negotiation to maintain state. See
25e8c5aa2b496d9026e958ac731a610167574f59vikram * for details.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * The ctd structure represents the device private part of a contract of
25e8c5aa2b496d9026e958ac731a610167574f59vikram * type "device"
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Another data structure used by device contracts is ctmpl_device. It is
25e8c5aa2b496d9026e958ac731a610167574f59vikram * the device contracts private part of the contract template structure. It
25e8c5aa2b496d9026e958ac731a610167574f59vikram * encapsulates the generic template structure "ct_template_t" and includes
25e8c5aa2b496d9026e958ac731a610167574f59vikram * the following device contract specific fields
25e8c5aa2b496d9026e958ac731a610167574f59vikram * ctd_aset: The bitset of states that should be guaranteed by a
25e8c5aa2b496d9026e958ac731a610167574f59vikram * ctd_noneg: If set, indicates that contract should NACK a
25e8c5aa2b496d9026e958ac731a610167574f59vikram * negotiation
25e8c5aa2b496d9026e958ac731a610167574f59vikram * ctd_minor: The devfs_path (without the /devices prefix) of the
25e8c5aa2b496d9026e958ac731a610167574f59vikram * minor node that is the subject of the contract.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * ALGORITHMS
25e8c5aa2b496d9026e958ac731a610167574f59vikram * ---------
25e8c5aa2b496d9026e958ac731a610167574f59vikram * There are three sets of routines in this file
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Template related routines
25e8c5aa2b496d9026e958ac731a610167574f59vikram * -------------------------
25e8c5aa2b496d9026e958ac731a610167574f59vikram * These routines provide support for template related operations initated
25e8c5aa2b496d9026e958ac731a610167574f59vikram * via the generic template operations. These include routines that dup
25e8c5aa2b496d9026e958ac731a610167574f59vikram * a template, free it, and set various terms in the template
25e8c5aa2b496d9026e958ac731a610167574f59vikram * (such as the minor node path, the acceptable state set (or A-set)
25e8c5aa2b496d9026e958ac731a610167574f59vikram * and the non-negotiable term) as well as a routine to query the
25e8c5aa2b496d9026e958ac731a610167574f59vikram * device specific portion of the template for the abovementioned terms.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * There is also a routine to create (ctmpl_device_create) that is used to
25e8c5aa2b496d9026e958ac731a610167574f59vikram * create a contract from a template. This routine calls (after initial
25e8c5aa2b496d9026e958ac731a610167574f59vikram * setup) the common function used to create a device contract
25e8c5aa2b496d9026e958ac731a610167574f59vikram * (contract_device_create).
25e8c5aa2b496d9026e958ac731a610167574f59vikram * core device contract implementation
25e8c5aa2b496d9026e958ac731a610167574f59vikram * ----------------------------------
25e8c5aa2b496d9026e958ac731a610167574f59vikram * These routines support the generic contract framework to provide
25e8c5aa2b496d9026e958ac731a610167574f59vikram * functionality that allows contracts to be created, managed and
25e8c5aa2b496d9026e958ac731a610167574f59vikram * destroyed. The contract_device_create() routine is a routine used
25e8c5aa2b496d9026e958ac731a610167574f59vikram * to create a contract from a template (either via an explicit create
25e8c5aa2b496d9026e958ac731a610167574f59vikram * operation on a template or implicitly via an open with an
25e8c5aa2b496d9026e958ac731a610167574f59vikram * activated template.). The contract_device_free() routine assists
25e8c5aa2b496d9026e958ac731a610167574f59vikram * in freeing the device contract specific parts. There are routines
25e8c5aa2b496d9026e958ac731a610167574f59vikram * used to abandon (contract_device_abandon) a device contract as well
25e8c5aa2b496d9026e958ac731a610167574f59vikram * as a routine to destroy (which despite its name does not destroy,
25e8c5aa2b496d9026e958ac731a610167574f59vikram * it only moves a contract to a dead state) a contract.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * There is also a routine to return status information about a
25e8c5aa2b496d9026e958ac731a610167574f59vikram * contract - the level of detail depends on what is requested by the
25e8c5aa2b496d9026e958ac731a610167574f59vikram * user. A value of CTD_FIXED only returns fixed length fields such
25e8c5aa2b496d9026e958ac731a610167574f59vikram * as the A-set, state of device and value of the "noneg" term. If
25e8c5aa2b496d9026e958ac731a610167574f59vikram * CTD_ALL is specified, the minor node path is returned as well.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * In addition there are interfaces (contract_device_ack/nack) which
25e8c5aa2b496d9026e958ac731a610167574f59vikram * are used to support negotiation between userland processes and
25e8c5aa2b496d9026e958ac731a610167574f59vikram * device contracts. These interfaces record the acknowledgement
25e8c5aa2b496d9026e958ac731a610167574f59vikram * or lack thereof for negotiation events and help determine if the
25e8c5aa2b496d9026e958ac731a610167574f59vikram * negotiated event should occur.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * "backend routines"
25e8c5aa2b496d9026e958ac731a610167574f59vikram * -----------------
25e8c5aa2b496d9026e958ac731a610167574f59vikram * The backend routines form the interface between the I/O framework
25e8c5aa2b496d9026e958ac731a610167574f59vikram * and the device contract subsystem. These routines, allow the I/O
25e8c5aa2b496d9026e958ac731a610167574f59vikram * framework to call into the device contract subsystem to notify it of
25e8c5aa2b496d9026e958ac731a610167574f59vikram * impending changes to a device state as well as to inform of the
25e8c5aa2b496d9026e958ac731a610167574f59vikram * final disposition of such attempted state changes. Routines in this
25e8c5aa2b496d9026e958ac731a610167574f59vikram * class include contract_device_offline() that indicates an attempt to
25e8c5aa2b496d9026e958ac731a610167574f59vikram * offline a device, contract_device_degrade() that indicates that
25e8c5aa2b496d9026e958ac731a610167574f59vikram * a device is moving to the degraded state and contract_device_negend()
25e8c5aa2b496d9026e958ac731a610167574f59vikram * that is used by the I/O framework to inform the contracts subsystem of
25e8c5aa2b496d9026e958ac731a610167574f59vikram * the final disposition of an attempted operation.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * A contract starts its life as a template. A process allocates a device
25e8c5aa2b496d9026e958ac731a610167574f59vikram * contract template and sets various terms:
25e8c5aa2b496d9026e958ac731a610167574f59vikram * The A-set
25e8c5aa2b496d9026e958ac731a610167574f59vikram * The device minor node
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Critical and informative events
25e8c5aa2b496d9026e958ac731a610167574f59vikram * The noneg i.e. no negotition term
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Setting of these terms in the template is done via the
25e8c5aa2b496d9026e958ac731a610167574f59vikram * ctmpl_device_set() entry point in this file. A process can query a
25e8c5aa2b496d9026e958ac731a610167574f59vikram * template to determine the terms already set in the template - this is
25e8c5aa2b496d9026e958ac731a610167574f59vikram * facilitated by the ctmpl_device_get() routine.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Once all the appropriate terms are set, the contract is instantiated via
25e8c5aa2b496d9026e958ac731a610167574f59vikram * one of two methods
25e8c5aa2b496d9026e958ac731a610167574f59vikram * - via an explicit create operation - this is facilitated by the
25e8c5aa2b496d9026e958ac731a610167574f59vikram * ctmpl_device_create() entry point
25e8c5aa2b496d9026e958ac731a610167574f59vikram * - synchronously with the open(2) system call - this is achieved via the
25e8c5aa2b496d9026e958ac731a610167574f59vikram * contract_device_open() routine.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * The core work for both these above functions is done by
25e8c5aa2b496d9026e958ac731a610167574f59vikram * contract_device_create()
25e8c5aa2b496d9026e958ac731a610167574f59vikram * A contract once created can be queried for its status. Support for
25e8c5aa2b496d9026e958ac731a610167574f59vikram * status info is provided by both the common contracts framework and by
25e8c5aa2b496d9026e958ac731a610167574f59vikram * the "device" contract type. If the level of detail requested is
25e8c5aa2b496d9026e958ac731a610167574f59vikram * CTD_COMMON, only the common contract framework data is used. Higher
25e8c5aa2b496d9026e958ac731a610167574f59vikram * levels of detail result in calls to contract_device_status() to supply
25e8c5aa2b496d9026e958ac731a610167574f59vikram * device contract type specific status information.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * A contract once created may be abandoned either explicitly or implictly.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * In either case, the contract_device_abandon() function is invoked. This
25e8c5aa2b496d9026e958ac731a610167574f59vikram * function merely calls contract_destroy() which moves the contract to
25e8c5aa2b496d9026e958ac731a610167574f59vikram * the DEAD state. The device contract portion of destroy processing is
25e8c5aa2b496d9026e958ac731a610167574f59vikram * provided by contract_device_destroy() which merely disassociates the
25e8c5aa2b496d9026e958ac731a610167574f59vikram * contract from its device devinfo node. A contract in the DEAD state is
25e8c5aa2b496d9026e958ac731a610167574f59vikram * not freed. It hanbgs around until all references to the contract are
25e8c5aa2b496d9026e958ac731a610167574f59vikram * gone. When that happens, the contract is finally deallocated. The
25e8c5aa2b496d9026e958ac731a610167574f59vikram * device contract specific portion of the free is done by
25e8c5aa2b496d9026e958ac731a610167574f59vikram * contract_device_free() which finally frees the device contract specific
25e8c5aa2b496d9026e958ac731a610167574f59vikram * data structure (cont_device_t).
25e8c5aa2b496d9026e958ac731a610167574f59vikram * When a device undergoes a state change, the I/O framework calls the
25e8c5aa2b496d9026e958ac731a610167574f59vikram * corresponding device contract entry point. For example, when a device
25e8c5aa2b496d9026e958ac731a610167574f59vikram * is about to go OFFLINE, the routine contract_device_offline() is
25e8c5aa2b496d9026e958ac731a610167574f59vikram * invoked. Similarly if a device moves to DEGRADED state, the routine
25e8c5aa2b496d9026e958ac731a610167574f59vikram * contract_device_degrade() function is called. These functions call the
25e8c5aa2b496d9026e958ac731a610167574f59vikram * core routine contract_device_publish(). This function determines via
25e8c5aa2b496d9026e958ac731a610167574f59vikram * the function is_sync_neg() whether an event is a synchronous (i.e.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * negotiable) event or not. In the former case contract_device_publish()
25e8c5aa2b496d9026e958ac731a610167574f59vikram * publishes a CTE_NEG event and then waits in wait_for_acks() for ACKs
25e8c5aa2b496d9026e958ac731a610167574f59vikram * and/or NACKs from contract holders. In the latter case, it simply
25e8c5aa2b496d9026e958ac731a610167574f59vikram * publishes the event and does not wait. In the negotiation case, ACKs or
25e8c5aa2b496d9026e958ac731a610167574f59vikram * NACKs from userland consumers results in contract_device_ack_nack()
25e8c5aa2b496d9026e958ac731a610167574f59vikram * being called where the result of the negotiation is recorded in the
25e8c5aa2b496d9026e958ac731a610167574f59vikram * contract data structure. Once all outstanding contract owners have
25e8c5aa2b496d9026e958ac731a610167574f59vikram * responded, the device contract code in wait_for_acks() determines the
25e8c5aa2b496d9026e958ac731a610167574f59vikram * final result of the negotiation. A single NACK overrides all other ACKs
25e8c5aa2b496d9026e958ac731a610167574f59vikram * If there is no NACK, then a single ACK will result in an overall ACK
25e8c5aa2b496d9026e958ac731a610167574f59vikram * result. If there are no ACKs or NACKs, then the result CT_NONE is
25e8c5aa2b496d9026e958ac731a610167574f59vikram * returned back to the I/O framework. Once the event is permitted or
25e8c5aa2b496d9026e958ac731a610167574f59vikram * blocked, the I/O framework proceeds or aborts the state change. The
25e8c5aa2b496d9026e958ac731a610167574f59vikram * I/O framework then calls contract_device_negend() with a result code
25e8c5aa2b496d9026e958ac731a610167574f59vikram * indicating final disposition of the event. This call releases the
25e8c5aa2b496d9026e958ac731a610167574f59vikram * barrier and other state associated with the previous negotiation,
25e8c5aa2b496d9026e958ac731a610167574f59vikram * which permits the next event (if any) to come into the device contract
25e8c5aa2b496d9026e958ac731a610167574f59vikram * framework.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Finally, a device that has outstanding contracts may be removed from
25e8c5aa2b496d9026e958ac731a610167574f59vikram * the system which results in its devinfo node being freed. The devinfo
25e8c5aa2b496d9026e958ac731a610167574f59vikram * free routine in the I/O framework, calls into the device contract
25e8c5aa2b496d9026e958ac731a610167574f59vikram * function - contract_device_remove_dip(). This routine, disassociates
25e8c5aa2b496d9026e958ac731a610167574f59vikram * the dip from all contracts associated with the contract being freed,
25e8c5aa2b496d9026e958ac731a610167574f59vikram * allowing the devinfo node to be freed.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * ---------
25e8c5aa2b496d9026e958ac731a610167574f59vikram * There are four sets of data that need to be protected by locks
25e8c5aa2b496d9026e958ac731a610167574f59vikram * i) device contract specific portion of the contract template - This data
25e8c5aa2b496d9026e958ac731a610167574f59vikram * is protected by the template lock ctmpl_lock.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * ii) device contract specific portion of the contract - This data is
25e8c5aa2b496d9026e958ac731a610167574f59vikram * protected by the contract lock ct_lock
25e8c5aa2b496d9026e958ac731a610167574f59vikram * iii) The linked list of contracts hanging off a devinfo node - This
25e8c5aa2b496d9026e958ac731a610167574f59vikram * list is protected by the per-devinfo node lock devi_ct_lock
25e8c5aa2b496d9026e958ac731a610167574f59vikram * iv) Finally there is a barrier, controlled by devi_ct_lock, devi_ct_cv
25e8c5aa2b496d9026e958ac731a610167574f59vikram * and devi_ct_count that controls state changes to a dip
25e8c5aa2b496d9026e958ac731a610167574f59vikram * The template lock is independent in that none of the other locks in this
25e8c5aa2b496d9026e958ac731a610167574f59vikram * file may be taken while holding the template lock (and vice versa).
25e8c5aa2b496d9026e958ac731a610167574f59vikram * The remaining three locks have the following lock order
25e8c5aa2b496d9026e958ac731a610167574f59vikram * devi_ct_lock -> ct_count barrier -> ct_lock
25e8c5aa2b496d9026e958ac731a610167574f59vikramstatic cont_device_t *contract_device_create(ctmpl_device_t *dtmpl, dev_t dev,
25e8c5aa2b496d9026e958ac731a610167574f59vikram/* barrier routines */
25e8c5aa2b496d9026e958ac731a610167574f59vikramstatic void ct_barrier_wait_for_release(dev_info_t *dip);
25e8c5aa2b496d9026e958ac731a610167574f59vikramstatic int ct_barrier_wait_for_empty(dev_info_t *dip, int secs);
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Macro predicates for determining when events should be sent and how.
25e8c5aa2b496d9026e958ac731a610167574f59vikram ((ctd->cond_contract.ct_ev_info | ctd->cond_contract.ct_ev_crit) & flag)
25e8c5aa2b496d9026e958ac731a610167574f59vikram * State transition table showing which transitions are synchronous and which
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Device contract template implementation
25e8c5aa2b496d9026e958ac731a610167574f59vikram * ctmpl_device_dup
25e8c5aa2b496d9026e958ac731a610167574f59vikram * The device contract template dup entry point.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * This simply copies all the fields (generic as well as device contract
25e8c5aa2b496d9026e958ac731a610167574f59vikram * specific) fields of the original.
25e8c5aa2b496d9026e958ac731a610167574f59vikramstatic struct ct_template *
25e8c5aa2b496d9026e958ac731a610167574f59vikram new = kmem_zalloc(sizeof (ctmpl_device_t), KM_SLEEP);
25e8c5aa2b496d9026e958ac731a610167574f59vikram * copy generic fields.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * ctmpl_copy returns with old template lock held
25e8c5aa2b496d9026e958ac731a610167574f59vikram bcopy(old->ctd_minor, buf, strlen(old->ctd_minor) + 1);
25e8c5aa2b496d9026e958ac731a610167574f59vikram * ctmpl_device_free
25e8c5aa2b496d9026e958ac731a610167574f59vikram * The device contract template free entry point. Just
25e8c5aa2b496d9026e958ac731a610167574f59vikram * frees the template.
25e8c5aa2b496d9026e958ac731a610167574f59vikram kmem_free(dtmpl->ctd_minor, strlen(dtmpl->ctd_minor) + 1);
25e8c5aa2b496d9026e958ac731a610167574f59vikram * SAFE_EV is the set of events which a non-privileged process is
25e8c5aa2b496d9026e958ac731a610167574f59vikram * allowed to make critical. An unprivileged device contract owner has
25e8c5aa2b496d9026e958ac731a610167574f59vikram * no control over when a device changes state, so all device events
25e8c5aa2b496d9026e958ac731a610167574f59vikram * can be in the critical set.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * EXCESS tells us if "value", a critical event set, requires
25e8c5aa2b496d9026e958ac731a610167574f59vikram * additional privilege. For device contracts EXCESS currently
25e8c5aa2b496d9026e958ac731a610167574f59vikram * evaluates to 0.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * ctmpl_device_set
25e8c5aa2b496d9026e958ac731a610167574f59vikram * The device contract template set entry point. Sets various terms in the
25e8c5aa2b496d9026e958ac731a610167574f59vikram * template. The non-negotiable term can only be set if the process has
25e8c5aa2b496d9026e958ac731a610167574f59vikram * the {PRIV_SYS_DEVICES} privilege asserted in its effective set.
c5a9a4fc75359f623d03e4eab6a03c9cabe175a3Antonello Cruzctmpl_device_set(struct ct_template *tmpl, ct_kparam_t *kparam,
c5a9a4fc75359f623d03e4eab6a03c9cabe175a3Antonello Cruz param_value = *(uint64_t *)kparam->ctpm_kbuf;
25e8c5aa2b496d9026e958ac731a610167574f59vikram * only privileged processes can designate a contract
25e8c5aa2b496d9026e958ac731a610167574f59vikram * non-negotiatble.
7b209c2cc5ea45251aba06dcc6181d3f23da807aacruz if (resolve_pathname(str_value, &dip, NULL, &spec_type) != 0) {
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Currently for device contracts, any event
25e8c5aa2b496d9026e958ac731a610167574f59vikram * may be added to the critical set. We retain the
25e8c5aa2b496d9026e958ac731a610167574f59vikram * following code however for future enhancements.
25e8c5aa2b496d9026e958ac731a610167574f59vikram return (0);
25e8c5aa2b496d9026e958ac731a610167574f59vikram * ctmpl_device_get
25e8c5aa2b496d9026e958ac731a610167574f59vikram * The device contract template get entry point. Simply fetches and
25e8c5aa2b496d9026e958ac731a610167574f59vikram * returns the value of the requested term.
c5a9a4fc75359f623d03e4eab6a03c9cabe175a3Antonello Cruzctmpl_device_get(struct ct_template *template, ct_kparam_t *kparam)
c5a9a4fc75359f623d03e4eab6a03c9cabe175a3Antonello Cruz kparam->ret_size = strlcpy((char *)kparam->ctpm_kbuf,
25e8c5aa2b496d9026e958ac731a610167574f59vikram return (0);
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Device contract type specific portion of creating a contract using
25e8c5aa2b496d9026e958ac731a610167574f59vikram * a specified template
25e8c5aa2b496d9026e958ac731a610167574f59vikram/*ARGSUSED*/
25e8c5aa2b496d9026e958ac731a610167574f59vikramctmpl_device_create(ct_template_t *template, ctid_t *ctidp)
25e8c5aa2b496d9026e958ac731a610167574f59vikram /* incomplete template */
25e8c5aa2b496d9026e958ac731a610167574f59vikram bcopy(dtmpl->ctd_minor, buf, strlen(dtmpl->ctd_minor) + 1);
25e8c5aa2b496d9026e958ac731a610167574f59vikram if (resolve_pathname(buf, NULL, &dev, &spec_type) != 0 ||
25e8c5aa2b496d9026e958ac731a610167574f59vikram dev == NODEV || dev == DDI_DEV_T_ANY || dev == DDI_DEV_T_NONE ||
25e8c5aa2b496d9026e958ac731a610167574f59vikram CT_DEBUG((CE_WARN, "Failed to create device contract for "
25e8c5aa2b496d9026e958ac731a610167574f59vikram "process (%d) with device (devt = %lu, spec_type = %s)",
25e8c5aa2b496d9026e958ac731a610167574f59vikram return (0);
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Device contract specific template entry points
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Device contract implementation
25e8c5aa2b496d9026e958ac731a610167574f59vikram * contract_device_default
25e8c5aa2b496d9026e958ac731a610167574f59vikram * The device contract default template entry point. Creates a
25e8c5aa2b496d9026e958ac731a610167574f59vikram * device contract template with a default A-set and no "noneg" ,
25e8c5aa2b496d9026e958ac731a610167574f59vikram * with informative degrade events and critical offline events.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * There is no default minor path.
25e8c5aa2b496d9026e958ac731a610167574f59vikram new = kmem_zalloc(sizeof (ctmpl_device_t), KM_SLEEP);
25e8c5aa2b496d9026e958ac731a610167574f59vikram ctmpl_init(&new->ctd_ctmpl, &ctmpl_device_ops, device_type, new);
25e8c5aa2b496d9026e958ac731a610167574f59vikram new->ctd_aset = CT_DEV_EV_ONLINE | CT_DEV_EV_DEGRADED;
25e8c5aa2b496d9026e958ac731a610167574f59vikram * contract_device_free
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Destroys the device contract specific portion of a contract and
25e8c5aa2b496d9026e958ac731a610167574f59vikram * frees the contract.
25e8c5aa2b496d9026e958ac731a610167574f59vikram kmem_free(ctd->cond_minor, strlen(ctd->cond_minor) + 1);
25e8c5aa2b496d9026e958ac731a610167574f59vikram ctd->cond_devt != DDI_DEV_T_NONE && ctd->cond_devt != NODEV);
25e8c5aa2b496d9026e958ac731a610167574f59vikram ASSERT(ctd->cond_spec == S_IFBLK || ctd->cond_spec == S_IFCHR);
25e8c5aa2b496d9026e958ac731a610167574f59vikram ASSERT(ctd->cond_noneg == 0 || ctd->cond_noneg == 1);
25e8c5aa2b496d9026e958ac731a610167574f59vikram ASSERT(!(ctd->cond_currev_ack & ~(CT_ACK | CT_NACK)));
25e8c5aa2b496d9026e958ac731a610167574f59vikram ASSERT((ctd->cond_currev_id > 0) ^ (ctd->cond_currev_type == 0));
25e8c5aa2b496d9026e958ac731a610167574f59vikram ASSERT((ctd->cond_currev_id > 0) || (ctd->cond_currev_ack == 0));
25e8c5aa2b496d9026e958ac731a610167574f59vikram * contract_device_abandon
25e8c5aa2b496d9026e958ac731a610167574f59vikram * The device contract abandon entry point.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * device contracts cannot be inherited or orphaned.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Move the contract to the DEAD_STATE. It will be freed
25e8c5aa2b496d9026e958ac731a610167574f59vikram * once all references to it are gone.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * contract_device_destroy
25e8c5aa2b496d9026e958ac731a610167574f59vikram * The device contract destroy entry point.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Called from contract_destroy() to do any type specific destroy. Note
25e8c5aa2b496d9026e958ac731a610167574f59vikram * that destroy is a misnomer - this does not free the contract, it only
25e8c5aa2b496d9026e958ac731a610167574f59vikram * moves it to the dead state. A contract is actually freed via
25e8c5aa2b496d9026e958ac731a610167574f59vikram * contract_rele() -> contract_dtor(), contop_free()
2eb07f5e03e6bf6a25f9305ffda328fdb94f1425Stephen Hanson * The dip has been removed, this is a dangling contract
2eb07f5e03e6bf6a25f9305ffda328fdb94f1425Stephen Hanson * Check that dip linkages are NULL
2eb07f5e03e6bf6a25f9305ffda328fdb94f1425Stephen Hanson CT_DEBUG((CE_NOTE, "contract_device_destroy:"
2eb07f5e03e6bf6a25f9305ffda328fdb94f1425Stephen Hanson " contract has no devinfo node. contract ctid : %d",
2eb07f5e03e6bf6a25f9305ffda328fdb94f1425Stephen Hanson * The intended lock order is : devi_ct_lock -> ct_count
2eb07f5e03e6bf6a25f9305ffda328fdb94f1425Stephen Hanson * barrier -> ct_lock.
2eb07f5e03e6bf6a25f9305ffda328fdb94f1425Stephen Hanson * However we can't do this here as dropping the ct_lock allows
2eb07f5e03e6bf6a25f9305ffda328fdb94f1425Stephen Hanson * a race condition with i_ddi_free_node()/
2eb07f5e03e6bf6a25f9305ffda328fdb94f1425Stephen Hanson * contract_device_remove_dip() which may free off dip before
2eb07f5e03e6bf6a25f9305ffda328fdb94f1425Stephen Hanson * we can take devi_ct_lock. So use mutex_tryenter to avoid
2eb07f5e03e6bf6a25f9305ffda328fdb94f1425Stephen Hanson * dropping ct_lock until we have acquired devi_ct_lock.
2eb07f5e03e6bf6a25f9305ffda328fdb94f1425Stephen Hanson if (mutex_tryenter(&(DEVI(dip)->devi_ct_lock)) != 0)
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Waiting for the barrier to be released is strictly speaking not
25e8c5aa2b496d9026e958ac731a610167574f59vikram * necessary. But it simplifies the implementation of
25e8c5aa2b496d9026e958ac731a610167574f59vikram * contract_device_publish() by establishing the invariant that
25e8c5aa2b496d9026e958ac731a610167574f59vikram * device contracts cannot go away during negotiation.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * contract_device_status
25e8c5aa2b496d9026e958ac731a610167574f59vikram * The device contract status entry point. Called when level of "detail"
25e8c5aa2b496d9026e958ac731a610167574f59vikram * is either CTD_FIXED or CTD_ALL
25e8c5aa2b496d9026e958ac731a610167574f59vikramcontract_device_status(contract_t *ct, zone_t *zone, int detail, nvlist_t *nvl,
25e8c5aa2b496d9026e958ac731a610167574f59vikram * There's no need to hold the contract lock while accessing static
25e8c5aa2b496d9026e958ac731a610167574f59vikram * data like aset or noneg. But since we need the lock to access other
25e8c5aa2b496d9026e958ac731a610167574f59vikram * data like state, we hold it anyway.
25e8c5aa2b496d9026e958ac731a610167574f59vikram VERIFY(nvlist_add_uint32(nvl, CTDS_STATE, ctd->cond_state) == 0);
25e8c5aa2b496d9026e958ac731a610167574f59vikram VERIFY(nvlist_add_uint32(nvl, CTDS_ASET, ctd->cond_aset) == 0);
25e8c5aa2b496d9026e958ac731a610167574f59vikram VERIFY(nvlist_add_uint32(nvl, CTDS_NONEG, ctd->cond_noneg) == 0);
25e8c5aa2b496d9026e958ac731a610167574f59vikram VERIFY(nvlist_add_string(nvl, CTDS_MINOR, ctd->cond_minor) == 0);
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Converts a result integer into the corresponding string. Used for printing
25e8c5aa2b496d9026e958ac731a610167574f59vikramstatic char *
25e8c5aa2b496d9026e958ac731a610167574f59vikram return ("CT_ACK");
25e8c5aa2b496d9026e958ac731a610167574f59vikram return ("CT_NACK");
25e8c5aa2b496d9026e958ac731a610167574f59vikram return ("CT_NONE");
25e8c5aa2b496d9026e958ac731a610167574f59vikram return ("UNKNOWN");
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Converts a device state integer constant into the corresponding string.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Used to print messages.
25e8c5aa2b496d9026e958ac731a610167574f59vikramstatic char *
25e8c5aa2b496d9026e958ac731a610167574f59vikram return ("ONLINE");
25e8c5aa2b496d9026e958ac731a610167574f59vikram return ("DEGRADED");
25e8c5aa2b496d9026e958ac731a610167574f59vikram return ("OFFLINE");
25e8c5aa2b496d9026e958ac731a610167574f59vikram return ("UNKNOWN");
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Routine that determines if a particular CT_DEV_EV_? event corresponds to a
25e8c5aa2b496d9026e958ac731a610167574f59vikram * synchronous state change or not.
25e8c5aa2b496d9026e958ac731a610167574f59vikram CT_DEBUG((CE_WARN, "is_sync_neg: transition to same state: %s",
25e8c5aa2b496d9026e958ac731a610167574f59vikram return (-2);
25e8c5aa2b496d9026e958ac731a610167574f59vikram CT_DEBUG((CE_WARN, "is_sync_neg: Unsupported state transition: "
25e8c5aa2b496d9026e958ac731a610167574f59vikram "old = %s -> new = %s", state_str(old), state_str(new)));
25e8c5aa2b496d9026e958ac731a610167574f59vikram return (-1);
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Used to cleanup cached dv_nodes so that when a device is released by
25e8c5aa2b496d9026e958ac731a610167574f59vikram * a contract holder, its devinfo node can be successfully detached.
25e8c5aa2b496d9026e958ac731a610167574f59vikram /* pdip can be NULL if we have contracts against the root dip */
25e8c5aa2b496d9026e958ac731a610167574f59vikram if (pdip && DEVI_BUSY_OWNED(pdip) || !pdip && DEVI_BUSY_OWNED(dip)) {
25e8c5aa2b496d9026e958ac731a610167574f59vikram CT_DEBUG((CE_WARN, "ct_dv_clean: Parent node is busy owned, "
cfc3b49fd53fba13be205e2206e0ea3b36f5f2c7Yuri Pankov (void) devfs_clean(pdip, devnm + 1, DV_CLEAN_FORCE);
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Endpoint of a ct_ctl_ack() or ct_ctl_nack() call from userland.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Results in the ACK or NACK being recorded on the dip for one particular
25e8c5aa2b496d9026e958ac731a610167574f59vikram * contract. The device contracts framework evaluates the ACK/NACKs for all
25e8c5aa2b496d9026e958ac731a610167574f59vikram * contracts against a device to determine if a particular device state change
25e8c5aa2b496d9026e958ac731a610167574f59vikram * should be allowed.
25e8c5aa2b496d9026e958ac731a610167574f59vikramcontract_device_ack_nack(contract_t *ct, uint_t evtype, uint64_t evid,
25e8c5aa2b496d9026e958ac731a610167574f59vikram CT_DEBUG((CE_NOTE, "ack_nack: entered: ctid %d", ctid));
25e8c5aa2b496d9026e958ac731a610167574f59vikram CT_DEBUG((CE_NOTE, "ack_nack: contract lock acquired: %d", ctid));
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Negotiation only if new state is not in A-set
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Negotiation only if transition is synchronous
25e8c5aa2b496d9026e958ac731a610167574f59vikram * We shouldn't be negotiating if the "noneg" flag is set
25e8c5aa2b496d9026e958ac731a610167574f59vikram * dv_clean only if !NACK and offline state change
25e8c5aa2b496d9026e958ac731a610167574f59vikram if (cmd != CT_NACK && evtype == CT_DEV_EV_OFFLINE && dip) {
25e8c5aa2b496d9026e958ac731a610167574f59vikram if (error != 0) {
25e8c5aa2b496d9026e958ac731a610167574f59vikram "(type=%s, id=%llu) on removed device",
25e8c5aa2b496d9026e958ac731a610167574f59vikram CT_DEBUG((CE_NOTE, "ack_nack: error: ESRCH, ctid: %d",
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Must follow lock order: devi_ct_lock -> ct_count barrier - >ct_lock
25e8c5aa2b496d9026e958ac731a610167574f59vikram "(type=%s, id=%llu) on device %s",
25e8c5aa2b496d9026e958ac731a610167574f59vikram CT_DEBUG((CE_NOTE, "ack_nack: setting %sACK for ctid: %d",
25e8c5aa2b496d9026e958ac731a610167574f59vikram CT_DEBUG((CE_NOTE, "ack_nack: normal exit: ctid: %d", ctid));
25e8c5aa2b496d9026e958ac731a610167574f59vikram return (0);
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Invoked when a userland contract holder approves (i.e. ACKs) a state change
25e8c5aa2b496d9026e958ac731a610167574f59vikramcontract_device_ack(contract_t *ct, uint_t evtype, uint64_t evid)
25e8c5aa2b496d9026e958ac731a610167574f59vikram return (contract_device_ack_nack(ct, evtype, evid, CT_ACK));
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Invoked when a userland contract holder blocks (i.e. NACKs) a state change
25e8c5aa2b496d9026e958ac731a610167574f59vikramcontract_device_nack(contract_t *ct, uint_t evtype, uint64_t evid)
25e8c5aa2b496d9026e958ac731a610167574f59vikram return (contract_device_ack_nack(ct, evtype, evid, CT_NACK));
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Creates a new contract synchronously with the breaking of an existing
25e8c5aa2b496d9026e958ac731a610167574f59vikram * contract. Currently not supported.
25e8c5aa2b496d9026e958ac731a610167574f59vikram/*ARGSUSED*/
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Core device contract implementation entry points
25e8c5aa2b496d9026e958ac731a610167574f59vikram * contract_device_init
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Initializes the device contract type.
25e8c5aa2b496d9026e958ac731a610167574f59vikram device_type = contract_type_init(CTT_DEVICE, "device",
25e8c5aa2b496d9026e958ac731a610167574f59vikram * contract_device_create
25e8c5aa2b496d9026e958ac731a610167574f59vikram * create a device contract given template "tmpl" and the "owner" process.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * May fail and return NULL if project.max-contracts would have been exceeded.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Common device contract creation routine called for both open-time and
25e8c5aa2b496d9026e958ac731a610167574f59vikram * non-open time device contract creation
25e8c5aa2b496d9026e958ac731a610167574f59vikramcontract_device_create(ctmpl_device_t *dtmpl, dev_t dev, int spec_type,
25e8c5aa2b496d9026e958ac731a610167574f59vikram ASSERT(dev != NODEV && dev != DDI_DEV_T_ANY && dev != DDI_DEV_T_NONE);
25e8c5aa2b496d9026e958ac731a610167574f59vikram ASSERT(spec_type == S_IFCHR || spec_type == S_IFBLK);
25e8c5aa2b496d9026e958ac731a610167574f59vikram bcopy(dtmpl->ctd_minor, path, strlen(dtmpl->ctd_minor) + 1);
25e8c5aa2b496d9026e958ac731a610167574f59vikram cmn_err(CE_WARN, "contract_create: Cannot find devinfo node "
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Lock out any parallel contract negotiations
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Only we hold a refernce to this contract. Safe to access
25e8c5aa2b496d9026e958ac731a610167574f59vikram * the fields without a ct_lock
25e8c5aa2b496d9026e958ac731a610167574f59vikram * It is safe to set the dip pointer in the contract
25e8c5aa2b496d9026e958ac731a610167574f59vikram * as the contract will always be destroyed before the dip
25e8c5aa2b496d9026e958ac731a610167574f59vikram * is released
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Since we are able to lookup the device, it is either
25e8c5aa2b496d9026e958ac731a610167574f59vikram * online or degraded
25e8c5aa2b496d9026e958ac731a610167574f59vikram * contract_ctor() initailizes the common portion of a contract
25e8c5aa2b496d9026e958ac731a610167574f59vikram * contract_dtor() destroys the common portion of a contract
25e8c5aa2b496d9026e958ac731a610167574f59vikram if (contract_ctor(&ctd->cond_contract, device_type, &dtmpl->ctd_ctmpl,
25e8c5aa2b496d9026e958ac731a610167574f59vikram * contract_device_free() destroys the type specific
25e8c5aa2b496d9026e958ac731a610167574f59vikram * portion of a contract and frees the contract.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * The "minor" path and "cred" is a part of the type specific
25e8c5aa2b496d9026e958ac731a610167574f59vikram * portion of the contract and will be freed by
25e8c5aa2b496d9026e958ac731a610167574f59vikram * contract_device_free()
25e8c5aa2b496d9026e958ac731a610167574f59vikram /* release barrier */
25e8c5aa2b496d9026e958ac731a610167574f59vikram ctd->cond_contract.ct_ntime.ctm_total = CT_DEV_ACKTIME;
25e8c5aa2b496d9026e958ac731a610167574f59vikram ctd->cond_contract.ct_qtime.ctm_total = CT_DEV_ACKTIME;
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Insert device contract into list hanging off the dip
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Bump up the ref-count on the contract to reflect this
25e8c5aa2b496d9026e958ac731a610167574f59vikram /* release barrier */
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Called when a device is successfully opened to create an open-time contract
25e8c5aa2b496d9026e958ac731a610167574f59vikram * i.e. synchronously with a device open.
25e8c5aa2b496d9026e958ac731a610167574f59vikramcontract_device_open(dev_t dev, int spec_type, contract_t **ctpp)
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Check if we are in user-context i.e. if we have an lwp
25e8c5aa2b496d9026e958ac731a610167574f59vikram CT_DEBUG((CE_NOTE, "contract_open: Not user-context"));
25e8c5aa2b496d9026e958ac731a610167574f59vikram return (0);
25e8c5aa2b496d9026e958ac731a610167574f59vikram tmpl = ctmpl_dup(lwp->lwp_ct_active[device_type->ct_type_index]);
25e8c5aa2b496d9026e958ac731a610167574f59vikram return (0);
25e8c5aa2b496d9026e958ac731a610167574f59vikram * If the user set a minor path in the template before an open,
25e8c5aa2b496d9026e958ac731a610167574f59vikram * ignore it. We use the minor path of the actual minor opened.
25e8c5aa2b496d9026e958ac731a610167574f59vikram CT_DEBUG((CE_NOTE, "contract_device_open(): Process %d: "
25e8c5aa2b496d9026e958ac731a610167574f59vikram "ignoring device minor path in active template: %s",
25e8c5aa2b496d9026e958ac731a610167574f59vikram * This is a copy of the actual activated template.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Safe to make changes such as freeing the minor
25e8c5aa2b496d9026e958ac731a610167574f59vikram * path in the template.
25e8c5aa2b496d9026e958ac731a610167574f59vikram kmem_free(dtmpl->ctd_minor, strlen(dtmpl->ctd_minor) + 1);
25e8c5aa2b496d9026e958ac731a610167574f59vikram if (ddi_dev_pathname(dev, spec_type, path) != DDI_SUCCESS) {
25e8c5aa2b496d9026e958ac731a610167574f59vikram CT_DEBUG((CE_NOTE, "contract_device_open(): Failed to derive "
25e8c5aa2b496d9026e958ac731a610167574f59vikram "minor path from dev_t,spec {%lu, %d} for process (%d)",
25e8c5aa2b496d9026e958ac731a610167574f59vikram return (1);
25e8c5aa2b496d9026e958ac731a610167574f59vikram ctd = contract_device_create(dtmpl, dev, spec_type, curproc, &error);
25e8c5aa2b496d9026e958ac731a610167574f59vikram cmn_err(CE_NOTE, "contract_device_open(): Failed to "
25e8c5aa2b496d9026e958ac731a610167574f59vikram "create device contract for process (%d) holding "
25e8c5aa2b496d9026e958ac731a610167574f59vikram "device (devt = %lu, spec_type = %d)",
25e8c5aa2b496d9026e958ac731a610167574f59vikram return (1);
25e8c5aa2b496d9026e958ac731a610167574f59vikram return (0);
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Called during contract negotiation by the device contract framework to wait
25e8c5aa2b496d9026e958ac731a610167574f59vikram * for ACKs or NACKs from contract holders. If all responses are not received
25e8c5aa2b496d9026e958ac731a610167574f59vikram * before a specified timeout, this routine times out.
25e8c5aa2b496d9026e958ac731a610167574f59vikramwait_for_acks(dev_info_t *dip, dev_t dev, int spec_type, uint_t evtype)
25e8c5aa2b496d9026e958ac731a610167574f59vikram char *f = "wait_for_acks";
25e8c5aa2b496d9026e958ac731a610167574f59vikram CT_DEBUG((CE_NOTE, "%s: entered: dip: %p", f, (void *)dip));
25e8c5aa2b496d9026e958ac731a610167574f59vikram if (ct_barrier_wait_for_empty(dip, CT_DEV_ACKTIME) == -1) {
25e8c5aa2b496d9026e958ac731a610167574f59vikram * some contract owner(s) didn't respond in time
25e8c5aa2b496d9026e958ac731a610167574f59vikram CT_DEBUG((CE_NOTE, "%s: timed out: %p", f, (void *)dip));
25e8c5aa2b496d9026e958ac731a610167574f59vikram for (ctd = list_head(&(DEVI(dip)->devi_ct)); ctd != NULL;
25e8c5aa2b496d9026e958ac731a610167574f59vikram if (dev != DDI_DEV_T_ANY && spec_type != ctd->cond_spec) {
25e8c5aa2b496d9026e958ac731a610167574f59vikram /* skip if non-negotiable contract */
25e8c5aa2b496d9026e958ac731a610167574f59vikram CT_DEBUG((CE_NOTE, "%s: found a NACK,result = NACK: %p",
25e8c5aa2b496d9026e958ac731a610167574f59vikram f, (void *)dip));
25e8c5aa2b496d9026e958ac731a610167574f59vikram f, (void *)dip));
25e8c5aa2b496d9026e958ac731a610167574f59vikram CT_DEBUG((CE_NOTE, "%s: result = ACK, dip=%p", f, (void *)dip));
25e8c5aa2b496d9026e958ac731a610167574f59vikram } else if (timed_out) {
25e8c5aa2b496d9026e958ac731a610167574f59vikram CT_DEBUG((CE_NOTE, "%s: result = NONE (timed-out), dip=%p",
25e8c5aa2b496d9026e958ac731a610167574f59vikram f, (void *)dip));
25e8c5aa2b496d9026e958ac731a610167574f59vikram f, (void *)dip));
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Determines the current state of a device (i.e a devinfo node
25e8c5aa2b496d9026e958ac731a610167574f59vikram if (DEVI_IS_DEVICE_OFFLINE(dip) || DEVI_IS_DEVICE_DOWN(dip))
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Sets the current state of a device in a device contract
25e8c5aa2b496d9026e958ac731a610167574f59vikram /* verify that barrier is held */
25e8c5aa2b496d9026e958ac731a610167574f59vikram for (ctd = list_head(&(DEVI(dip)->devi_ct)); ctd != NULL;
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Core routine called by event-specific routines when an event occurs.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Determines if an event should be be published, and if it is to be
25e8c5aa2b496d9026e958ac731a610167574f59vikram * published, whether a negotiation should take place. Also implements
25e8c5aa2b496d9026e958ac731a610167574f59vikram * NEGEND events which publish the final disposition of an event after
25e8c5aa2b496d9026e958ac731a610167574f59vikram * negotiations are complete.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * When an event occurs on a minor node, this routine walks the list of
25e8c5aa2b496d9026e958ac731a610167574f59vikram * contracts hanging off a devinfo node and for each contract on the affected
25e8c5aa2b496d9026e958ac731a610167574f59vikram * dip, evaluates the following cases
25e8c5aa2b496d9026e958ac731a610167574f59vikram * a. an event that is synchronous, breaks the contract and NONEG not set
25e8c5aa2b496d9026e958ac731a610167574f59vikram * - bumps up the outstanding negotiation counts on the dip
25e8c5aa2b496d9026e958ac731a610167574f59vikram * - marks the dip as undergoing negotiation (devi_ct_neg)
25e8c5aa2b496d9026e958ac731a610167574f59vikram * - event of type CTE_NEG is published
25e8c5aa2b496d9026e958ac731a610167574f59vikram * b. an event that is synchronous, breaks the contract and NONEG is set
25e8c5aa2b496d9026e958ac731a610167574f59vikram * - sets the final result to CT_NACK, event is blocked
25e8c5aa2b496d9026e958ac731a610167574f59vikram * - does not publish an event
25e8c5aa2b496d9026e958ac731a610167574f59vikram * c. event is asynchronous and breaks the contract
25e8c5aa2b496d9026e958ac731a610167574f59vikram * - publishes a critical event irrespect of whether the NONEG
25e8c5aa2b496d9026e958ac731a610167574f59vikram * flag is set, since the contract will be broken and contract
25e8c5aa2b496d9026e958ac731a610167574f59vikram * owner needs to be informed.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * d. No contract breakage but the owner has subscribed to the event
25e8c5aa2b496d9026e958ac731a610167574f59vikram * - publishes the event irrespective of the NONEG event as the
25e8c5aa2b496d9026e958ac731a610167574f59vikram * owner has explicitly subscribed to the event.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * e. NEGEND event
25e8c5aa2b496d9026e958ac731a610167574f59vikram * - publishes a critical event. Should only be doing this if
25e8c5aa2b496d9026e958ac731a610167574f59vikram * if NONEG is not set.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * f. all other events
25e8c5aa2b496d9026e958ac731a610167574f59vikram * - Since a contract is not broken and this event has not been
25e8c5aa2b496d9026e958ac731a610167574f59vikram * subscribed to, this event does not need to be published for
25e8c5aa2b496d9026e958ac731a610167574f59vikram * for this contract.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Once an event is published, what happens next depends on the type of
25e8c5aa2b496d9026e958ac731a610167574f59vikram * a. NEGEND event
25e8c5aa2b496d9026e958ac731a610167574f59vikram * - cleanup all state associated with the preceding negotiation
25e8c5aa2b496d9026e958ac731a610167574f59vikram * and return CT_ACK to the caller of contract_device_publish()
25e8c5aa2b496d9026e958ac731a610167574f59vikram * b. NACKed event
25e8c5aa2b496d9026e958ac731a610167574f59vikram * - One or more contracts had the NONEG term, so the event was
25e8c5aa2b496d9026e958ac731a610167574f59vikram * blocked. Return CT_NACK to the caller.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * c. Negotiated event
25e8c5aa2b496d9026e958ac731a610167574f59vikram * - Call wait_for_acks() to wait for responses from contract
25e8c5aa2b496d9026e958ac731a610167574f59vikram * holders. The end result is either CT_ACK (event is permitted),
25e8c5aa2b496d9026e958ac731a610167574f59vikram * CT_NACK (event is blocked) or CT_NONE (no contract owner)
25e8c5aa2b496d9026e958ac731a610167574f59vikram * responded. This result is returned back to the caller.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * d. All other events
25e8c5aa2b496d9026e958ac731a610167574f59vikram * - If the event was asynchronous (i.e. not negotiated) or
25e8c5aa2b496d9026e958ac731a610167574f59vikram * a contract was not broken return CT_ACK to the caller.
25e8c5aa2b496d9026e958ac731a610167574f59vikramcontract_device_publish(dev_info_t *dip, dev_t dev, int spec_type,
25e8c5aa2b496d9026e958ac731a610167574f59vikram /* Is this a synchronous state change ? */
25e8c5aa2b496d9026e958ac731a610167574f59vikram /* NOP if unsupported transition */
25e8c5aa2b496d9026e958ac731a610167574f59vikram CT_DEBUG((CE_NOTE, "publish: is%s sync state change",
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Negotiation end - set the state of the device in the contract
25e8c5aa2b496d9026e958ac731a610167574f59vikram CT_DEBUG((CE_NOTE, "publish: negend: setting cond state"));
25e8c5aa2b496d9026e958ac731a610167574f59vikram * If this device didn't go through negotiation, don't publish
25e8c5aa2b496d9026e958ac731a610167574f59vikram * a NEGEND event - simply release the barrier to allow other
25e8c5aa2b496d9026e958ac731a610167574f59vikram * device events in.
25e8c5aa2b496d9026e958ac731a610167574f59vikram if (evtype == CT_EV_NEGEND && !DEVI(dip)->devi_ct_neg) {
25e8c5aa2b496d9026e958ac731a610167574f59vikram CT_DEBUG((CE_NOTE, "publish: no negend reqd. release barrier"));
25e8c5aa2b496d9026e958ac731a610167574f59vikram * There are negotiated contract breakages that
25e8c5aa2b496d9026e958ac731a610167574f59vikram * need a NEGEND event
25e8c5aa2b496d9026e958ac731a610167574f59vikram * This is a new event, not a NEGEND event. Wait for previous
25e8c5aa2b496d9026e958ac731a610167574f59vikram * contract events to complete.
25e8c5aa2b496d9026e958ac731a610167574f59vikram for (ctd = list_head(&(DEVI(dip)->devi_ct)); ctd != NULL;
25e8c5aa2b496d9026e958ac731a610167574f59vikram if (dev != DDI_DEV_T_ANY && spec_type != ctd->cond_spec) {
25e8c5aa2b496d9026e958ac731a610167574f59vikram /* We have a matching contract */
25e8c5aa2b496d9026e958ac731a610167574f59vikram CT_DEBUG((CE_NOTE, "publish: found matching contract: %d",
25e8c5aa2b496d9026e958ac731a610167574f59vikram * There are 4 possible cases
25e8c5aa2b496d9026e958ac731a610167574f59vikram * 1. A contract is broken (dev not in acceptable state) and
25e8c5aa2b496d9026e958ac731a610167574f59vikram * the state change is synchronous - start negotiation
25e8c5aa2b496d9026e958ac731a610167574f59vikram * by sending a CTE_NEG critical event.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * 2. A contract is broken and the state change is
25e8c5aa2b496d9026e958ac731a610167574f59vikram * asynchronous - just send a critical event and
25e8c5aa2b496d9026e958ac731a610167574f59vikram * break the contract.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * 3. Contract is not broken, but consumer has subscribed
25e8c5aa2b496d9026e958ac731a610167574f59vikram * to the event as a critical or informative event
25e8c5aa2b496d9026e958ac731a610167574f59vikram * - just send the appropriate event
25e8c5aa2b496d9026e958ac731a610167574f59vikram * 4. contract waiting for negend event - just send the critical
25e8c5aa2b496d9026e958ac731a610167574f59vikram * NEGEND event.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Don't send event if
25e8c5aa2b496d9026e958ac731a610167574f59vikram * - contract is not broken AND
25e8c5aa2b496d9026e958ac731a610167574f59vikram * - contract holder has not subscribed to this event AND
25e8c5aa2b496d9026e958ac731a610167574f59vikram * - contract not waiting for a NEGEND event
25e8c5aa2b496d9026e958ac731a610167574f59vikram "contract (%d): no publish reqd: event %d",
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Note: need to kmem_zalloc() the event so mutexes are
25e8c5aa2b496d9026e958ac731a610167574f59vikram * initialized automatically
25e8c5aa2b496d9026e958ac731a610167574f59vikram /* Nothing to publish. Event has been blocked */
25e8c5aa2b496d9026e958ac731a610167574f59vikram "not publishing blocked ev: ctid: %d",
25e8c5aa2b496d9026e958ac731a610167574f59vikram event->cte_flags = CTE_NEG; /* critical neg. event */
25e8c5aa2b496d9026e958ac731a610167574f59vikram CT_DEBUG((CE_NOTE, "publish: broken + async: ctid: %d",
25e8c5aa2b496d9026e958ac731a610167574f59vikram CT_DEBUG((CE_NOTE, "publish: event suscrib: ctid: %d",
25e8c5aa2b496d9026e958ac731a610167574f59vikram CT_DEBUG((CE_NOTE, "publish: NEGEND: ctid: %d", ctid));
25e8c5aa2b496d9026e958ac731a610167574f59vikram event->cte_flags = 0; /* NEGEND is always critical */
25e8c5aa2b496d9026e958ac731a610167574f59vikram CT_DEBUG((CE_NOTE, "publish: not publishing event for "
25e8c5aa2b496d9026e958ac731a610167574f59vikram "ctid: %d, evtype: %d",
25e8c5aa2b496d9026e958ac731a610167574f59vikram "CTS_NEVID: %llu, CTS_NEWCT: %s",
25e8c5aa2b496d9026e958ac731a610167574f59vikram ctd->cond_contract.ct_ntime.ctm_start = ddi_get_lbolt();
25e8c5aa2b496d9026e958ac731a610167574f59vikram * by holding the dip's devi_ct_lock we ensure that
25e8c5aa2b496d9026e958ac731a610167574f59vikram * all ACK/NACKs are held up until we have finished
25e8c5aa2b496d9026e958ac731a610167574f59vikram * publishing to all contracts.
25e8c5aa2b496d9026e958ac731a610167574f59vikram CT_DEBUG((CE_NOTE, "publish: sync break, setting evid"
25e8c5aa2b496d9026e958ac731a610167574f59vikram } else if (negend) {
25e8c5aa2b496d9026e958ac731a610167574f59vikram * If "negend" set counter back to initial state (-1) so that
25e8c5aa2b496d9026e958ac731a610167574f59vikram * other events can be published. Also clear the negotiation flag
25e8c5aa2b496d9026e958ac731a610167574f59vikram * 0 .. n are used for counting.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * -1 indicates counter is available for use.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * devi_ct_count not necessarily 0. We may have
25e8c5aa2b496d9026e958ac731a610167574f59vikram * timed out in which case, count will be non-zero.
25e8c5aa2b496d9026e958ac731a610167574f59vikram CT_DEBUG((CE_NOTE, "publish: negend: reset dip state: dip=%p",
25e8c5aa2b496d9026e958ac731a610167574f59vikram * for non-negotiated events or subscribed events or no
25e8c5aa2b496d9026e958ac731a610167574f59vikram * matching contracts
25e8c5aa2b496d9026e958ac731a610167574f59vikram CT_DEBUG((CE_NOTE, "publish: async/non-nego/subscrib/no-match: "
25e8c5aa2b496d9026e958ac731a610167574f59vikram * only this function when called from contract_device_negend()
25e8c5aa2b496d9026e958ac731a610167574f59vikram * can reset the counter to READY state i.e. -1. This function
25e8c5aa2b496d9026e958ac731a610167574f59vikram * is so called for every event whether a NEGEND event is needed
25e8c5aa2b496d9026e958ac731a610167574f59vikram * or not, but the negend event is only published if the event
25e8c5aa2b496d9026e958ac731a610167574f59vikram * whose end they signal is a negotiated event for the contract.
25e8c5aa2b496d9026e958ac731a610167574f59vikram /* No matching contracts */
25e8c5aa2b496d9026e958ac731a610167574f59vikram CT_DEBUG((CE_NOTE, "publish: No matching contract"));
25e8c5aa2b496d9026e958ac731a610167574f59vikram /* a non-negotiable contract exists and this is a neg. event */
25e8c5aa2b496d9026e958ac731a610167574f59vikram CT_DEBUG((CE_NOTE, "publish: found 1 or more NONEG contract"));
25e8c5aa2b496d9026e958ac731a610167574f59vikram /* one or more contracts going through negotations */
25e8c5aa2b496d9026e958ac731a610167574f59vikram CT_DEBUG((CE_NOTE, "publish: sync contract: waiting"));
25e8c5aa2b496d9026e958ac731a610167574f59vikram /* no negotiated contracts or no broken contracts or NEGEND */
25e8c5aa2b496d9026e958ac731a610167574f59vikram CT_DEBUG((CE_NOTE, "publish: async/no-break/negend"));
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Release the lock only now so that the only point where we
25e8c5aa2b496d9026e958ac731a610167574f59vikram * drop the lock is in wait_for_acks(). This is so that we don't
25e8c5aa2b496d9026e958ac731a610167574f59vikram * miss cv_signal/cv_broadcast from contract holders
25e8c5aa2b496d9026e958ac731a610167574f59vikram CT_DEBUG((CE_NOTE, "publish: dropping devi_ct_lock"));
25e8c5aa2b496d9026e958ac731a610167574f59vikram CT_DEBUG((CE_NOTE, "publish: result = %s", result_str(result)));
25e8c5aa2b496d9026e958ac731a610167574f59vikram * contract_device_offline
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Event publishing routine called by I/O framework when a device is offlined.
25e8c5aa2b496d9026e958ac731a610167574f59vikramcontract_device_offline(dev_info_t *dip, dev_t dev, int spec_type)
25e8c5aa2b496d9026e958ac731a610167574f59vikram VERIFY(nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP) == 0);
25e8c5aa2b496d9026e958ac731a610167574f59vikram result = contract_device_publish(dip, dev, spec_type, evtype, nvl);
25e8c5aa2b496d9026e958ac731a610167574f59vikram * If a contract offline is NACKED, the framework expects us to call
25e8c5aa2b496d9026e958ac731a610167574f59vikram * NEGEND ourselves, since we know the final result
25e8c5aa2b496d9026e958ac731a610167574f59vikram contract_device_negend(dip, dev, spec_type, CT_EV_FAILURE);
25e8c5aa2b496d9026e958ac731a610167574f59vikram * contract_device_degrade
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Event publishing routine called by I/O framework when a device
25e8c5aa2b496d9026e958ac731a610167574f59vikram * moves to degrade state.
25e8c5aa2b496d9026e958ac731a610167574f59vikram/*ARGSUSED*/
25e8c5aa2b496d9026e958ac731a610167574f59vikramcontract_device_degrade(dev_info_t *dip, dev_t dev, int spec_type)
25e8c5aa2b496d9026e958ac731a610167574f59vikram VERIFY(nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP) == 0);
25e8c5aa2b496d9026e958ac731a610167574f59vikram (void) contract_device_publish(dip, dev, spec_type, evtype, nvl);
25e8c5aa2b496d9026e958ac731a610167574f59vikram * contract_device_undegrade
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Event publishing routine called by I/O framework when a device
25e8c5aa2b496d9026e958ac731a610167574f59vikram * moves from degraded state to online state.
25e8c5aa2b496d9026e958ac731a610167574f59vikram/*ARGSUSED*/
25e8c5aa2b496d9026e958ac731a610167574f59vikramcontract_device_undegrade(dev_info_t *dip, dev_t dev, int spec_type)
25e8c5aa2b496d9026e958ac731a610167574f59vikram VERIFY(nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP) == 0);
25e8c5aa2b496d9026e958ac731a610167574f59vikram (void) contract_device_publish(dip, dev, spec_type, evtype, nvl);
25e8c5aa2b496d9026e958ac731a610167574f59vikram * For all contracts which have undergone a negotiation (because the device
25e8c5aa2b496d9026e958ac731a610167574f59vikram * moved out of the acceptable state for that contract and the state
25e8c5aa2b496d9026e958ac731a610167574f59vikram * change is synchronous i.e. requires negotiation) this routine publishes
25e8c5aa2b496d9026e958ac731a610167574f59vikram * a CT_EV_NEGEND event with the final disposition of the event.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * This event is always a critical event.
25e8c5aa2b496d9026e958ac731a610167574f59vikramcontract_device_negend(dev_info_t *dip, dev_t dev, int spec_type, int result)
25e8c5aa2b496d9026e958ac731a610167574f59vikram ASSERT(result == CT_EV_SUCCESS || result == CT_EV_FAILURE);
25e8c5aa2b496d9026e958ac731a610167574f59vikram CT_DEBUG((CE_NOTE, "contract_device_negend(): entered: result: %d, "
25e8c5aa2b496d9026e958ac731a610167574f59vikram VERIFY(nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP) == 0);
25e8c5aa2b496d9026e958ac731a610167574f59vikram (void) contract_device_publish(dip, dev, spec_type, evtype, nvl);
25e8c5aa2b496d9026e958ac731a610167574f59vikram CT_DEBUG((CE_NOTE, "contract_device_negend(): exit dip: %p",
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Wrapper routine called by other subsystems (such as LDI) to start
25e8c5aa2b496d9026e958ac731a610167574f59vikram * negotiations when a synchronous device state change occurs.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Returns CT_ACK or CT_NACK.
25e8c5aa2b496d9026e958ac731a610167574f59vikramcontract_device_negotiate(dev_info_t *dip, dev_t dev, int spec_type,
25e8c5aa2b496d9026e958ac731a610167574f59vikram ASSERT(spec_type == S_IFBLK || spec_type == S_IFCHR);
25e8c5aa2b496d9026e958ac731a610167574f59vikram result = contract_device_offline(dip, dev, spec_type);
25e8c5aa2b496d9026e958ac731a610167574f59vikram cmn_err(CE_PANIC, "contract_device_negotiate(): Negotiation "
25e8c5aa2b496d9026e958ac731a610167574f59vikram "not supported: event (%d) for dev_t (%lu) and spec (%d), "
25e8c5aa2b496d9026e958ac731a610167574f59vikram * A wrapper routine called by other subsystems (such as the LDI) to
25e8c5aa2b496d9026e958ac731a610167574f59vikram * finalize event processing for a state change event. For synchronous
25e8c5aa2b496d9026e958ac731a610167574f59vikram * state changes, this publishes NEGEND events. For asynchronous i.e.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * non-negotiable events this publishes the event.
25e8c5aa2b496d9026e958ac731a610167574f59vikramcontract_device_finalize(dev_info_t *dip, dev_t dev, int spec_type,
25e8c5aa2b496d9026e958ac731a610167574f59vikram ASSERT(spec_type == S_IFBLK || spec_type == S_IFCHR);
25e8c5aa2b496d9026e958ac731a610167574f59vikram contract_device_negend(dip, dev, spec_type, ct_result);
25e8c5aa2b496d9026e958ac731a610167574f59vikram contract_device_negend(dip, dev, spec_type, ct_result);
25e8c5aa2b496d9026e958ac731a610167574f59vikram contract_device_negend(dip, dev, spec_type, ct_result);
25e8c5aa2b496d9026e958ac731a610167574f59vikram cmn_err(CE_PANIC, "contract_device_finalize(): Unsupported "
25e8c5aa2b496d9026e958ac731a610167574f59vikram "event (%d) for dev_t (%lu) and spec (%d), dip (%p)",
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Called by I/O framework when a devinfo node is freed to remove the
25e8c5aa2b496d9026e958ac731a610167574f59vikram * association between a devinfo node and its contracts.
25e8c5aa2b496d9026e958ac731a610167574f59vikram for (ctd = list_head(&(DEVI(dip)->devi_ct)); ctd != NULL; ctd = next) {
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Unlink the dip associated with this contract
25e8c5aa2b496d9026e958ac731a610167574f59vikram CT_DEBUG((CE_NOTE, "ct: remove_dip: removed dip from contract: "
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Barrier related routines
25e8c5aa2b496d9026e958ac731a610167574f59vikram CT_DEBUG((CE_NOTE, "ct_barrier_acquire: waiting for barrier"));
25e8c5aa2b496d9026e958ac731a610167574f59vikram cv_wait(&(DEVI(dip)->devi_ct_cv), &(DEVI(dip)->devi_ct_lock));
25e8c5aa2b496d9026e958ac731a610167574f59vikram CT_DEBUG((CE_NOTE, "ct_barrier_acquire: thread owns barrier"));
25e8c5aa2b496d9026e958ac731a610167574f59vikram CT_DEBUG((CE_NOTE, "ct_barrier_release: Released barrier"));
25e8c5aa2b496d9026e958ac731a610167574f59vikram cv_wait(&(DEVI(dip)->devi_ct_cv), &(DEVI(dip)->devi_ct_lock));
25e8c5aa2b496d9026e958ac731a610167574f59vikram CT_DEBUG((CE_NOTE, "barrier_decr: ct_count before decr: %d",
25e8c5aa2b496d9026e958ac731a610167574f59vikram abstime = ddi_get_lbolt() + drv_usectohz(secs*1000000);
25e8c5aa2b496d9026e958ac731a610167574f59vikram return (-1);
25e8c5aa2b496d9026e958ac731a610167574f59vikram return (0);