config root man

Current Path : /sys/dev/isci/scil/

FreeBSD hs32.drive.ne.jp 9.1-RELEASE FreeBSD 9.1-RELEASE #1: Wed Jan 14 12:18:08 JST 2015 root@hs32.drive.ne.jp:/sys/amd64/compile/hs32 amd64
Upload File :
Current File : //sys/dev/isci/scil/scif_sas_domain_states.c

/*-
 * This file is provided under a dual BSD/GPLv2 license.  When using or
 * redistributing this file, you may do so under either license.
 *
 * GPL LICENSE SUMMARY
 *
 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of version 2 of the GNU General Public License as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
 * The full GNU General Public License is included in this distribution
 * in the file called LICENSE.GPL.
 *
 * BSD LICENSE
 *
 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/cdefs.h>
__FBSDID("$FreeBSD: release/9.1.0/sys/dev/isci/scil/scif_sas_domain_states.c 231689 2012-02-14 15:58:49Z jimharris $");

/**
 * @file
 *
 * @brief This file contains all of the entrance and exit methods for each
 *        of the domain states defined by the SCI_BASE_DOMAIN state
 *        machine.
 */

#include <dev/isci/scil/intel_sas.h>
#include <dev/isci/scil/scic_port.h>

#include <dev/isci/scil/scif_sas_logger.h>
#include <dev/isci/scil/scif_sas_domain.h>
#include <dev/isci/scil/scif_sas_controller.h>
#include <dev/isci/scil/scic_controller.h>

//******************************************************************************
//* P R O T E C T E D    M E T H O D S
//******************************************************************************

/**
 * @brief This method will attempt to transition to the stopped state.
 *        The transition will only occur if the criteria for transition is
 *        met (i.e. all IOs are complete and all devices are stopped).
 *
 * @param[in]  fw_domain This parameter specifies the domain in which to
 *             to attempt to perform the transition.
 *
 * @return none
 */
void scif_sas_domain_transition_to_stopped_state(
   SCIF_SAS_DOMAIN_T * fw_domain
)
{
   SCIF_LOG_TRACE((
      sci_base_object_get_logger(fw_domain),
      SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
      "scif_sas_domain_transition_to_stopped_state(0x%x) enter\n",
      fw_domain
   ));

   // If IOs are quiesced, and all remote devices are stopped,
   // then transition directly to the STOPPED state.
   if (  (fw_domain->request_list.element_count == 0)
      && (fw_domain->device_start_count == 0) )
   {
      SCIF_LOG_INFO((
         sci_base_object_get_logger(fw_domain),
         SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
         "Domain:0x%x immediate transition to STOPPED\n",
         fw_domain
      ));

      sci_base_state_machine_change_state(
         &fw_domain->parent.state_machine, SCI_BASE_DOMAIN_STATE_STOPPED
      );
   }
}


/**
 * @brief This method is called upon entrance to all states where the
 *        previous state may have been the DISCOVERING state.
 *        We issue the scif_cb_domain_discovery_complete() notification
 *        from this method, assuming pre-requisites are met, as opposed
 *        to in the exit handler of the DISCOVERING state, so that the
 *        appropriate state handlers are in place should the user decide
 *        to call scif_domain_discover() again.
 *
 * @param[in]  fw_domain This parameter specifies the domain for which
 *             the state transition has occurred.
 *
 * @return none
 */
static
void scif_sas_domain_transition_from_discovering_state(
   SCIF_SAS_DOMAIN_T * fw_domain
)
{
   SCIF_LOG_TRACE((
      sci_base_object_get_logger(fw_domain),
      SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
      "scif_sas_domain_transition_from_discovering_state(0x%x) enter\n",
      fw_domain
   ));

   if (fw_domain->parent.state_machine.previous_state_id
       == SCI_BASE_DOMAIN_STATE_DISCOVERING)
   {
      scif_sas_controller_restore_interrupt_coalescence(fw_domain->controller);

      scif_cb_timer_stop(fw_domain->controller, fw_domain->operation.timer);

      scif_cb_domain_discovery_complete(
         fw_domain->controller, fw_domain, fw_domain->operation.status
      );
   }
}


/**
 * @brief This method is called upon entrance to DISCOVERING state. Right before
 *           transitioning to DISCOVERING state, we temporarily change interrupt
 *           coalescence scheme.
 *
 * @param[in]  fw_domain This parameter specifies the domain for which
 *             the state transition has occurred.
 *
 * @return none
 */
void scif_sas_domain_transition_to_discovering_state(
   SCIF_SAS_DOMAIN_T * fw_domain
)
{
   scif_sas_controller_save_interrupt_coalescence(fw_domain->controller);

   sci_base_state_machine_change_state(
      &fw_domain->parent.state_machine, SCI_BASE_DOMAIN_STATE_DISCOVERING
   );
}


/**
 * @brief This method implements the actions taken when entering the
 *        INITIAL state.
 *
 * @param[in]  object This parameter specifies the base object for which
 *             the state transition is occurring.  This is cast into a
 *             SCIF_SAS_DOMAIN object in the method implementation.
 *
 * @return none
 */
static
void scif_sas_domain_initial_state_enter(
   SCI_BASE_OBJECT_T * object
)
{
   SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T *)object;

   SET_STATE_HANDLER(
      fw_domain,
      scif_sas_domain_state_handler_table,
      SCI_BASE_DOMAIN_STATE_INITIAL
   );

   SCIF_LOG_TRACE((
      sci_base_object_get_logger(fw_domain),
      SCIF_LOG_OBJECT_DOMAIN,
      "scif_sas_domain_initial_state_enter(0x%x) enter\n",
      fw_domain
   ));
}

/**
 * @brief This method implements the actions taken when entering the
 *        STARTING state.  This includes setting the state handlers and
 *        checking to see if the core port has already become READY.
 *
 * @param[in]  object This parameter specifies the base object for which
 *             the state transition is occurring.  This is cast into a
 *             SCIF_SAS_DOMAIN object in the method implementation.
 *
 * @return none
 */
static
void scif_sas_domain_starting_state_enter(
   SCI_BASE_OBJECT_T * object
)
{
   SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T *)object;

   SET_STATE_HANDLER(
      fw_domain,
      scif_sas_domain_state_handler_table,
      SCI_BASE_DOMAIN_STATE_STARTING
   );

   SCIF_LOG_TRACE((
      sci_base_object_get_logger(fw_domain),
      SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
      "scif_sas_domain_starting_state_enter(0x%x) enter\n",
      fw_domain
   ));

   scif_sas_domain_transition_from_discovering_state(fw_domain);

   // If we entered the STARTING state and the core port is actually ready,
   // then directly transition into the READY state.  This can occur
   // if we were in the middle of discovery when the port failed
   // (causing a transition to STOPPING), then before reaching STOPPED
   // the port becomes ready again.
   if (fw_domain->is_port_ready == TRUE)
   {
      sci_base_state_machine_change_state(
         &fw_domain->parent.state_machine, SCI_BASE_DOMAIN_STATE_READY
      );
   }
}

/**
 * @brief This method implements the actions taken when entering the
 *        READY state.  If the transition into this state came from:
 *        - the STARTING state, then alert the user via a
 *          scif_cb_domain_change_notification() that the domain
 *          has at least 1 device ready for discovery.
 *        - the DISCOVERING state, then alert the user that
 *          discovery is complete via the
 *          scif_cb_domain_discovery_complete() notification that
 *          discovery is finished.
 *
 * @param[in]  object This parameter specifies the base object for which
 *             the state transition is occurring.  This is cast into a
 *             SCIF_SAS_DOMAIN object in the method implementation.
 *
 * @return none
 */
static
void scif_sas_domain_ready_state_enter(
   SCI_BASE_OBJECT_T * object
)
{
   SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T *)object;

   SET_STATE_HANDLER(
      fw_domain,
      scif_sas_domain_state_handler_table,
      SCI_BASE_DOMAIN_STATE_READY
   );

   SCIF_LOG_TRACE((
      sci_base_object_get_logger(fw_domain),
      SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
      "scif_sas_domain_ready_state_enter(0x%x) enter\n",
      fw_domain
   ));

   if (fw_domain->parent.state_machine.previous_state_id
       == SCI_BASE_DOMAIN_STATE_STARTING)
   {
      scif_cb_domain_ready(fw_domain->controller, fw_domain);

      // Only indicate the domain change notification if the previous
      // state was the STARTING state.  We issue the notification here
      // as opposed to exit of the STARTING state so that the appropriate
      // state handlers are in place should the user call
      // scif_domain_discover() from scif_cb_domain_change_notification()
      scif_cb_domain_change_notification(fw_domain->controller, fw_domain);
   }
   else if (fw_domain->parent.state_machine.previous_state_id
            == SCI_BASE_DOMAIN_STATE_DISCOVERING)
   {
      //if domain discovery timed out, we will NOT go back to discover even
      //the broadcast change count is not zero. Instead we finish the discovery
      //back to user. User can check the operation status and decide to
      //retry discover all over again.
      if (fw_domain->operation.status == SCI_FAILURE_TIMEOUT)
         fw_domain->broadcast_change_count = 0;

      // Check the broadcast change count to determine if discovery
      // is indeed complete.
      if (fw_domain->broadcast_change_count == 0)
      {
         scif_sas_domain_transition_from_discovering_state(fw_domain);
         scif_cb_domain_ready(fw_domain->controller, fw_domain);
      }
      else
      {
         // The broadcast change count indicates something my have
         // changed in the domain, while a discovery was ongoing.
         // Thus, we should start discovery over again.
         sci_base_state_machine_change_state(
            &fw_domain->parent.state_machine, SCI_BASE_DOMAIN_STATE_DISCOVERING
         );
      }

      // Enable the BCN because underneath hardware may disabled any further
      // BCN.
      scic_port_enable_broadcast_change_notification(fw_domain->core_object);
   }
}

/**
 * @brief This method implements the actions taken when exiting the
 *        READY state.
 *
 * @param[in]  object This parameter specifies the base object for which
 *             the state transition is occurring.  This is cast into a
 *             SCIF_SAS_DOMAIN object in the method implementation.
 *
 * @return none
 */
static
void scif_sas_domain_ready_state_exit(
   SCI_BASE_OBJECT_T * object
)
{
   SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T *)object;

   SCIF_LOG_TRACE((
      sci_base_object_get_logger(fw_domain),
      SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
      "scif_sas_domain_ready_state_exit(0x%x) enter\n",
      fw_domain
   ));

   scif_cb_domain_not_ready(fw_domain->controller, fw_domain);
}

/**
 * @brief This method implements the actions taken when entering the
 *        STOPPING state.
 *
 * @param[in]  object This parameter specifies the base object for which
 *             the state transition is occurring.  This is cast into a
 *             SCIF_SAS_DOMAIN object in the method implementation.
 *
 * @return none
 */
static
void scif_sas_domain_stopping_state_enter(
   SCI_BASE_OBJECT_T * object
)
{
   SCIF_SAS_REMOTE_DEVICE_T * fw_device;
   SCIF_SAS_DOMAIN_T        * fw_domain = (SCIF_SAS_DOMAIN_T *)object;
   SCI_ABSTRACT_ELEMENT_T   * element   = sci_abstract_list_get_front(
                                             &fw_domain->remote_device_list
                                          );

   SET_STATE_HANDLER(
      fw_domain,
      scif_sas_domain_state_handler_table,
      SCI_BASE_DOMAIN_STATE_STOPPING
   );

   // This must be invoked after the state handlers are set to ensure
   // appropriate processing will occur if the user attempts to perform
   // additional actions.
   scif_sas_domain_transition_from_discovering_state(fw_domain);

   SCIF_LOG_TRACE((
      sci_base_object_get_logger(fw_domain),
      SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
      "scif_sas_domain_stopping_state_enter(0x%x) enter\n",
      fw_domain
   ));

   scif_sas_high_priority_request_queue_purge_domain(
      &fw_domain->controller->hprq, fw_domain
   );

   // Search the domain's list of devices and put them all in the STOPPING
   // state.
   while (element != NULL)
   {
      fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
                  sci_abstract_list_get_object(element);

      // This method will stop the core device.  The core will terminate
      // all IO requests currently outstanding.
      fw_device->state_handlers->parent.stop_handler(&fw_device->parent);

      element = sci_abstract_list_get_next(element);
   }

   // Attempt to transition to the stopped state.
   scif_sas_domain_transition_to_stopped_state(fw_domain);
}

/**
 * @brief This method implements the actions taken when entering the
 *        STOPPED state.
 *
 * @param[in]  object This parameter specifies the base object for which
 *             the state transition is occurring.  This is cast into a
 *             SCIF_SAS_DOMAIN object in the method implementation.
 *
 * @return none
 */
static
void scif_sas_domain_stopped_state_enter(
   SCI_BASE_OBJECT_T * object
)
{
   SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T *)object;

   SET_STATE_HANDLER(
      fw_domain,
      scif_sas_domain_state_handler_table,
      SCI_BASE_DOMAIN_STATE_STOPPED
   );

   SCIF_LOG_TRACE((
      sci_base_object_get_logger(fw_domain),
      SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
      "scif_sas_domain_stopped_state_enter(0x%x) enter\n",
      fw_domain
   ));

   // A hot unplug of the direct attached device has occurred.  Thus,
   // notify the user. Note, if the controller is not in READY state,
   // mostly likely the controller is in STOPPING or STOPPED state,
   // meaning the controller is in the process of stopping, we should
   // not call back to user in the middle of controller stopping.
   if(fw_domain->controller->parent.state_machine.current_state_id
         == SCI_BASE_CONTROLLER_STATE_READY)
      scif_cb_domain_change_notification(fw_domain->controller, fw_domain);
}

/**
 * @brief This method implements the actions taken when entering the
 *        DISCOVERING state.  This includes determining from which
 *        state we entered.  If we entered from stopping that some sort
 *        of hot-remove of the port occurred.  In the hot-remove case
 *        all devices should be in the STOPPED state already and, as
 *        a result, are removed from the domain with a notification sent
 *        to the framework user.
 *
 * @note This method currently only handles hot-insert/hot-remove of
 *       direct attached SSP devices.
 *
 * @param[in]  object This parameter specifies the base object for which
 *             the state transition is occurring.  This is cast into a
 *             SCIF_SAS_DOMAIN object in the method implementation.
 *
 * @return none
 */
static
void scif_sas_domain_discovering_state_enter(
   SCI_BASE_OBJECT_T * object
)
{
   SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T *)object;

   SET_STATE_HANDLER(
      fw_domain,
      scif_sas_domain_state_handler_table,
      SCI_BASE_DOMAIN_STATE_DISCOVERING
   );

   SCIF_LOG_TRACE((
      sci_base_object_get_logger(fw_domain),
      SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
      "scif_sas_domain_discovering_state_enter(0x%x) enter\n",
      fw_domain
   ));

   fw_domain->broadcast_change_count = 0;

   // Did the domain just go through a port not ready action?  If it did,
   // then we will be entering from the STOPPED state.
   if (fw_domain->parent.state_machine.previous_state_id
       != SCI_BASE_DOMAIN_STATE_STOPPED)
   {
      SCIF_SAS_REMOTE_DEVICE_T * remote_device;
      SCIC_PORT_PROPERTIES_T     properties;

      scic_port_get_properties(fw_domain->core_object, &properties);

      // If the device has not yet been added to the domain, then
      // inform the user that the device is new.
      remote_device = (SCIF_SAS_REMOTE_DEVICE_T *)
                      scif_domain_get_device_by_sas_address(
                         fw_domain, &properties.remote.sas_address
                      );
      if (remote_device == SCI_INVALID_HANDLE)
      {
         // simply notify the user of the new DA device and be done
         // with discovery.
         scif_cb_domain_da_device_added(
            fw_domain->controller,
            fw_domain,
            &properties.remote.sas_address,
            &properties.remote.protocols
         );
      }
      else
      {
         if(properties.remote.protocols.u.bits.smp_target)
            //kick off the smp discover process.
            scif_sas_domain_start_smp_discover(fw_domain, remote_device);
      }
   }
   else  //entered from STOPPED state.
   {
      SCI_ABSTRACT_ELEMENT_T * current_element =
             sci_abstract_list_get_front(&(fw_domain->remote_device_list) );

      SCIF_SAS_REMOTE_DEVICE_T * fw_device;

      while (current_element != NULL)
      {
         fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)
                     sci_abstract_list_get_object(current_element);

         ASSERT(fw_device->parent.state_machine.current_state_id
                == SCI_BASE_REMOTE_DEVICE_STATE_STOPPED);

         current_element =
            sci_abstract_list_get_next(current_element);

         SCIF_LOG_INFO((
            sci_base_object_get_logger(fw_domain),
            SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
            "Controller:0x%x Domain:0x%x Device:0x%x removed\n",
            fw_domain->controller, fw_domain, fw_device
         ));

         // Notify the framework user of the device removal.
         scif_cb_domain_device_removed(
            fw_domain->controller, fw_domain, fw_device
         );
      }

      ASSERT(fw_domain->request_list.element_count == 0);
      ASSERT(sci_abstract_list_size(&fw_domain->remote_device_list) == 0);

      sci_base_state_machine_change_state(
         &fw_domain->parent.state_machine, SCI_BASE_DOMAIN_STATE_STARTING
      );
   }
}

SCI_BASE_STATE_T scif_sas_domain_state_table[SCI_BASE_DOMAIN_MAX_STATES] =
{
   {
      SCI_BASE_DOMAIN_STATE_INITIAL,
      scif_sas_domain_initial_state_enter,
      NULL,
   },
   {
      SCI_BASE_DOMAIN_STATE_STARTING,
      scif_sas_domain_starting_state_enter,
      NULL,
   },
   {
      SCI_BASE_DOMAIN_STATE_READY,
      scif_sas_domain_ready_state_enter,
      scif_sas_domain_ready_state_exit,
   },
   {
      SCI_BASE_DOMAIN_STATE_STOPPING,
      scif_sas_domain_stopping_state_enter,
      NULL,
   },
   {
      SCI_BASE_DOMAIN_STATE_STOPPED,
      scif_sas_domain_stopped_state_enter,
      NULL,
   },
   {
      SCI_BASE_DOMAIN_STATE_DISCOVERING,
      scif_sas_domain_discovering_state_enter,
      NULL,
   }
};


Man Man