Пример #1
0
/**
 * @brief This methods check each smp device in this domain. If there is at
 *        least one smp device in discover or target reset activity, this
 *        domain is considered in smp activity. Note this routine is not
 *        called on fast IO path.
 *
 * @param[in] fw_domain The framework domain object
 *
 * @return BOOL value to indicate whether a domain is in SMP activity.
 */
BOOL scif_sas_domain_is_in_smp_activity(
   SCIF_SAS_DOMAIN_T        * fw_domain
)
{
   SCI_ABSTRACT_ELEMENT_T * current_element =
      sci_abstract_list_get_front(&fw_domain->remote_device_list);

   SCIF_SAS_REMOTE_DEVICE_T * current_device;

   while ( current_element != NULL )
   {
      SMP_DISCOVER_RESPONSE_PROTOCOLS_T  dev_protocols;

      current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
                       sci_abstract_list_get_object(current_element);

      scic_remote_device_get_protocols(current_device->core_object,
                                       &dev_protocols
      );

      if (dev_protocols.u.bits.attached_smp_target &&
          scif_sas_smp_remote_device_is_in_activity(current_device))
         return TRUE;

      current_element =
         sci_abstract_list_get_next(current_element);
   }

   return FALSE;
}
Пример #2
0
/**
 * @brief This methods finds the first device that has specific activity scheduled.
 *
 * @param[in] fw_domain The framework domain object
 * @param[in] smp_activity A specified smp activity. The valid range is [1,5].
 *
 * @return SCIF_SAS_REMOTE_DEVICE_T The device that has specified smp activity scheduled.
 */
SCIF_SAS_REMOTE_DEVICE_T * scif_sas_domain_find_device_has_scheduled_activity(
   SCIF_SAS_DOMAIN_T        * fw_domain,
   U8                         smp_activity
)
{
   SCI_ABSTRACT_ELEMENT_T * current_element =
      sci_abstract_list_get_front(&fw_domain->remote_device_list);

   SCIF_SAS_REMOTE_DEVICE_T * current_device;
   SMP_DISCOVER_RESPONSE_PROTOCOLS_T  dev_protocols;

   //config route table activity has higher priority than discover activity.
   while ( current_element != NULL )
   {
      current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
                       sci_abstract_list_get_object(current_element);

      scic_remote_device_get_protocols(current_device->core_object,
                                       &dev_protocols);

      current_element =
         sci_abstract_list_get_next(current_element);

      if ( dev_protocols.u.bits.attached_smp_target
          && current_device->protocol_device.smp_device.scheduled_activity ==
                smp_activity)
      {
         return current_device;
      }
   }

   return NULL;
}
Пример #3
0
/**
 * @brief This methods finds a expander attached device by searching the domain's
 *        device list using connected expander device and expander phy id.
 *
 * @param[in] fw_domain The framework domain object
 * @param[in] parent_device The expander device the target device attaches to.
 * @param[in] expander_phy_id The expander phy id that the target device owns.
 *
 * @return found remote device or a NULL value if no device found.
 */
SCIF_SAS_REMOTE_DEVICE_T * scif_sas_domain_get_device_by_containing_device(
   SCIF_SAS_DOMAIN_T        * fw_domain,
   SCIF_SAS_REMOTE_DEVICE_T * containing_device,
   U8                         expander_phy_id
)
{
   SCIF_SAS_REMOTE_DEVICE_T * fw_device;
   SCI_ABSTRACT_ELEMENT_T * element = sci_abstract_list_get_front(
                                         &fw_domain->remote_device_list
                                      );

   //parent device must not be NULL.
   ASSERT(containing_device != NULL);

   // Search the abstract list to see if there is a remote device meets the
   // search condition.
   while (element != NULL)
   {
      fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
                  sci_abstract_list_get_object(element);

      // Check to see if this is the device for which we are searching.
      if (
            (fw_device->containing_device == containing_device)
         && (fw_device->expander_phy_identifier == expander_phy_id)
         )
      {
         return fw_device;
      }

      element = sci_abstract_list_get_next(element);
   }

   return SCI_INVALID_HANDLE;
}
Пример #4
0
/**
 * @brief This method finds the a EA device that has target reset scheduled.
 *
 * @param[in] fw_domain The framework domain object
 *
 * @return SCIF_SAS_REMOTE_DEVICE_T The EA device that has target reset scheduled.
 */
SCIF_SAS_REMOTE_DEVICE_T * scif_sas_domain_find_next_ea_target_reset(
   SCIF_SAS_DOMAIN_T     * fw_domain
)
{
   SCI_ABSTRACT_ELEMENT_T   * current_element;
   SCIF_SAS_REMOTE_DEVICE_T * current_device;

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

   //search throught domain's device list to find the first sata device on spinup_hold
   current_element = sci_abstract_list_get_front(&fw_domain->remote_device_list);
   while (current_element != NULL )
   {
      current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
                       sci_abstract_list_get_object(current_element);

      current_element = sci_abstract_list_get_next(current_element);

      if ( current_device->ea_target_reset_request_scheduled != NULL )
      {
         return current_device;
      }
   }

   return NULL;
}
Пример #5
0
/**
 * @brief This method searches the whole domain and finds all the smp devices to
 *        cancel their smp activities if there is any.
 *
 * @param[in] fw_domain The domain that its smp activities are to be canceled.
 *
 * @return none.
 */
void scif_sas_domain_cancel_smp_activities(
   SCIF_SAS_DOMAIN_T * fw_domain
)
{
   SCI_ABSTRACT_ELEMENT_T * current_element =
      sci_abstract_list_get_front(&fw_domain->remote_device_list);

   SCIF_SAS_REMOTE_DEVICE_T * current_device;

   //purge all the outstanding internal IOs in HPQ.
   scif_sas_high_priority_request_queue_purge_domain(
      &fw_domain->controller->hprq, fw_domain
   );

   while ( current_element != NULL )
   {
      SMP_DISCOVER_RESPONSE_PROTOCOLS_T  dev_protocols;

      current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
                       sci_abstract_list_get_object(current_element);

      scic_remote_device_get_protocols(current_device->core_object,
                                       &dev_protocols
      );

      if (dev_protocols.u.bits.attached_smp_target)
      {
         scif_sas_smp_remote_device_cancel_smp_activity(current_device);
      }

      current_element =
         sci_abstract_list_get_next(current_element);
   }
}
Пример #6
0
/**
 * @brief This method schedule clear affiliation activities for smp devices in
 *           this domain.
 *
 * @param[in] fw_domain The domain that its smp devices are scheduled to clear
 *                affiliation for all the EA SATA devices.
 *
 * @return none.
 */
void scif_sas_domain_schedule_clear_affiliation(
   SCIF_SAS_DOMAIN_T * fw_domain
)
{
   SCI_ABSTRACT_ELEMENT_T * current_element =
      sci_abstract_list_get_front(&fw_domain->remote_device_list);

   SCIF_SAS_REMOTE_DEVICE_T * current_device;
   SMP_DISCOVER_RESPONSE_PROTOCOLS_T  dev_protocols;

   //config route table activity has higher priority than discover activity.
   while ( current_element != NULL )
   {
      current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
                       sci_abstract_list_get_object(current_element);

      scic_remote_device_get_protocols(current_device->core_object,
                                       &dev_protocols);

      current_element =
         sci_abstract_list_get_next(current_element);

      if ( dev_protocols.u.bits.attached_smp_target )
      {
         current_device->protocol_device.smp_device.scheduled_activity =
            SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAR_AFFILIATION;
      }
   }
}
Пример #7
0
/**
 * @brief This method starts domain's smp discover process from the top level expander.
 *
 * @param[in] fw_domain The framework domain that to start smp discover process.
 @ @param[in] top_expander The top level expander device to start smp discover process.
 *
 * @return None
 */
void scif_sas_domain_start_smp_discover(
   SCIF_SAS_DOMAIN_T        * fw_domain,
   SCIF_SAS_REMOTE_DEVICE_T * top_expander
)
{
   SCI_ABSTRACT_ELEMENT_T * current_element =
       sci_abstract_list_get_front(&fw_domain->remote_device_list);

   SCIF_SAS_REMOTE_DEVICE_T * current_device;

   // something changed behind expander
   // mark all the device behind expander to be NOT
   // is_currently_discovered.
   while ( current_element != NULL )
   {
      current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
                           sci_abstract_list_get_object(current_element);

      current_device->is_currently_discovered = FALSE;

      //reset all the devices' port witdh except the top expander.
      if (current_device->containing_device != NULL)
         current_device->device_port_width = 1;

      current_element = sci_abstract_list_get_next(current_element);
   }

   //expander device itself should be set to is_currently_discovered.
   top_expander->is_currently_discovered = TRUE;

   //kick off the smp discover process.
   scif_sas_smp_remote_device_start_discover(top_expander);
}
Пример #8
0
/**
 * @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);
}
Пример #9
0
/**
 * @brief Get the object currently pointed to by this iterator.
 *
 * @param[in] iterator_handle Handle to an iterator.
 *
 * @return void * : Object pointed to by this iterator.
 * @retval NULL If iterator is not currently pointing to a valid element.
 */
void * sci_iterator_get_current(
   SCI_ITERATOR_HANDLE_T iterator_handle
)
{
   SCI_BASE_ITERATOR_T * iterator = (SCI_BASE_ITERATOR_T *)iterator_handle;

   void *current_object = NULL;

   if (iterator->current != NULL)
   {
      current_object = sci_abstract_list_get_object(iterator->current);
   }

   return current_object;
}
Пример #10
0
SCI_REMOTE_DEVICE_HANDLE_T scif_domain_get_device_by_sas_address(
   SCI_DOMAIN_HANDLE_T   domain,
   SCI_SAS_ADDRESS_T   * sas_address
)
{
   SCIF_SAS_DOMAIN_T        * fw_domain = (SCIF_SAS_DOMAIN_T*) domain;
   SCI_ABSTRACT_ELEMENT_T   * element   = sci_abstract_list_get_front(
                                             &fw_domain->remote_device_list
                                          );
   SCIF_SAS_REMOTE_DEVICE_T * fw_device;
   SCI_SAS_ADDRESS_T          fw_device_address;

   SCIF_LOG_TRACE((
      sci_base_object_get_logger(domain),
      SCIF_LOG_OBJECT_DOMAIN,
      "scif_domain_get_device_by_sas_address(0x%x, 0x%x) enter\n",
      domain, sas_address
   ));

   // Search the abstract list to see if there is a remote device with the
   // same SAS address.
   while (element != NULL)
   {
      fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
                  sci_abstract_list_get_object(element);

      scic_remote_device_get_sas_address(
         fw_device->core_object, &fw_device_address
      );

      // Check to see if this is the device for which we are searching.
      if (  (fw_device_address.low == sas_address->low)
         && (fw_device_address.high == sas_address->high) )
      {
         return fw_device;
      }

      element = sci_abstract_list_get_next(element);
   }

   return SCI_INVALID_HANDLE;
}
Пример #11
0
/**
 * @brief This method finishes domain's smp discover process and
 *        update domain's remote device list.
 *
 * @param[in] fw_domain The framework domain that's to finish smp discover process.
 *
 * @return None
 */
void scif_sas_domain_finish_discover(
   SCIF_SAS_DOMAIN_T * fw_domain
)
{
   SCIF_SAS_REMOTE_DEVICE_T * current_device = NULL;
   SCI_ABSTRACT_ELEMENT_T   * current_element = NULL;

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

   //need to scrub all the devices behind the expander. Check each
   //device's discover_status. if the is_currently_discovered is FALSE, means
   //the device is not been rediscovered. this device needs to be removed.
   current_element = sci_abstract_list_get_front(&fw_domain->remote_device_list);
   while (current_element != NULL )
   {
      current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
                          sci_abstract_list_get_object(current_element);

      //We must get the next element before we remove the current
      //device. Or else, we will get wrong next_element, since the erased
      //element has been put into free pool.
      current_element = sci_abstract_list_get_next(current_element);

      if ( current_device->is_currently_discovered == FALSE )
      {
         // Notify the framework user of the device removal.
         scif_cb_domain_device_removed(
            fw_domain->controller, fw_domain, current_device
         );
      }
   }

   sci_base_state_machine_change_state(
      &fw_domain->parent.state_machine, SCI_BASE_DOMAIN_STATE_READY
   );
}
Пример #12
0
/**
 * @brief This methods finds the first device that is in STOPPED state and its
 *        connection_rate is still in SPINUP_HOLD(value 3).
 *
 * @param[in] fw_domain The framework domain object
 *
 * @return SCIF_SAS_REMOTE_DEVICE_T The device that is in SPINUP_HOLD or NULL.
 */
SCIF_SAS_REMOTE_DEVICE_T * scif_sas_domain_find_device_in_spinup_hold(
   SCIF_SAS_DOMAIN_T        * fw_domain
)
{
   SCI_ABSTRACT_ELEMENT_T   * current_element;
   SCIF_SAS_REMOTE_DEVICE_T * current_device;

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

   //search throught domain's device list to find the first sata device on spinup_hold
   current_element = sci_abstract_list_get_front(&fw_domain->remote_device_list);
   while (current_element != NULL )
   {
      current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
                       sci_abstract_list_get_object(current_element);

      //We must get the next element before we remove the current
      //device. Or else, we will get wrong next_element, since the erased
      //element has been put into free pool.
      current_element = sci_abstract_list_get_next(current_element);

      if ( sci_base_state_machine_get_state(&current_device->parent.state_machine) ==
              SCI_BASE_REMOTE_DEVICE_STATE_STOPPED
          && scic_remote_device_get_connection_rate(current_device->core_object) ==
                SCI_SATA_SPINUP_HOLD )
      {
         return current_device;
      }
   }

   return NULL;
}
Пример #13
0
/**
 * @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
      );
   }
}