The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/isci/isci_remote_device.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * BSD LICENSE
    3  *
    4  * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  *
   11  *   * Redistributions of source code must retain the above copyright
   12  *     notice, this list of conditions and the following disclaimer.
   13  *   * Redistributions in binary form must reproduce the above copyright
   14  *     notice, this list of conditions and the following disclaimer in
   15  *     the documentation and/or other materials provided with the
   16  *     distribution.
   17  *
   18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
   22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   29  */
   30 
   31 #include <sys/cdefs.h>
   32 __FBSDID("$FreeBSD: releng/8.4/sys/dev/isci/isci_remote_device.c 239735 2012-08-27 15:52:09Z jimharris $");
   33 
   34 #include <dev/isci/isci.h>
   35 
   36 #include <cam/cam_periph.h>
   37 #include <cam/cam_xpt_periph.h>
   38 
   39 #include <dev/isci/scil/scif_task_request.h>
   40 #include <dev/isci/scil/scif_controller.h>
   41 #include <dev/isci/scil/scif_domain.h>
   42 #include <dev/isci/scil/scif_user_callback.h>
   43 
   44 #include <dev/isci/scil/scic_port.h>
   45 #include <dev/isci/scil/scic_phy.h>
   46 
   47 /**
   48  * @brief This callback method informs the framework user that the remote
   49  *        device is ready and capable of processing IO requests.
   50  *
   51  * @param[in]  controller This parameter specifies the controller object
   52  *             with which this callback is associated.
   53  * @param[in]  domain This parameter specifies the domain object with
   54  *             which this callback is associated.
   55  * @param[in]  remote_device This parameter specifies the device object with
   56  *             which this callback is associated.
   57  *
   58  * @return none
   59  */
   60 void
   61 scif_cb_remote_device_ready(SCI_CONTROLLER_HANDLE_T controller,
   62     SCI_DOMAIN_HANDLE_T domain, SCI_REMOTE_DEVICE_HANDLE_T remote_device)
   63 {
   64         struct ISCI_REMOTE_DEVICE *isci_remote_device =
   65             sci_object_get_association(remote_device);
   66         struct ISCI_CONTROLLER *isci_controller =
   67             sci_object_get_association(controller);
   68         uint32_t device_index = isci_remote_device->index;
   69 
   70         if (isci_controller->remote_device[device_index] == NULL) {
   71                 /* This new device is now ready, so put it in the controller's
   72                  *  remote device list so it is visible to CAM.
   73                  */
   74                 isci_controller->remote_device[device_index] =
   75                     isci_remote_device;
   76 
   77                 if (isci_controller->has_been_scanned) {
   78                         /* The sim object has been scanned at least once
   79                          *  already.  In that case, create a CCB to instruct
   80                          *  CAM to rescan this device.
   81                          * If the sim object has not been scanned, this device
   82                          *  will get scanned as part of the initial scan.
   83                          */
   84                         union ccb *ccb = xpt_alloc_ccb_nowait();
   85 
   86                         xpt_create_path(&ccb->ccb_h.path, xpt_periph,
   87                             cam_sim_path(isci_controller->sim),
   88                             isci_remote_device->index, CAM_LUN_WILDCARD);
   89 
   90                         xpt_rescan(ccb);
   91                 }
   92         }
   93 
   94         isci_remote_device_release_device_queue(isci_remote_device);
   95 }
   96 
   97 /**
   98  * @brief This callback method informs the framework user that the remote
   99  *              device is not ready.  Thus, it is incapable of processing IO
  100  *              requests.
  101  *
  102  * @param[in]  controller This parameter specifies the controller object
  103  *             with which this callback is associated.
  104  * @param[in]  domain This parameter specifies the domain object with
  105  *             which this callback is associated.
  106  * @param[in]  remote_device This parameter specifies the device object with
  107  *             which this callback is associated.
  108  *
  109  * @return none
  110  */
  111 void
  112 scif_cb_remote_device_not_ready(SCI_CONTROLLER_HANDLE_T controller,
  113     SCI_DOMAIN_HANDLE_T domain, SCI_REMOTE_DEVICE_HANDLE_T remote_device)
  114 {
  115 
  116 }
  117 
  118 /**
  119  * @brief This callback method informs the framework user that the remote
  120  *        device failed.  This typically occurs shortly after the device
  121  *        has been discovered, during the configuration phase for the device.
  122  *
  123  * @param[in]  controller This parameter specifies the controller object
  124  *             with which this callback is associated.
  125  * @param[in]  domain This parameter specifies the domain object with
  126  *             which this callback is associated.
  127  * @param[in]  remote_device This parameter specifies the device object with
  128  *             which this callback is associated.
  129  * @param[in]  status This parameter specifies the specific failure condition
  130  *             associated with this device failure.
  131  *
  132  * @return none
  133  */
  134 void
  135 scif_cb_remote_device_failed(SCI_CONTROLLER_HANDLE_T controller,
  136     SCI_DOMAIN_HANDLE_T domain, SCI_REMOTE_DEVICE_HANDLE_T remote_device,
  137     SCI_STATUS status)
  138 {
  139 
  140 }
  141 
  142 void
  143 isci_remote_device_reset(struct ISCI_REMOTE_DEVICE *remote_device,
  144     union ccb *ccb)
  145 {
  146         struct ISCI_CONTROLLER *controller = remote_device->domain->controller;
  147         struct ISCI_REQUEST *request;
  148         struct ISCI_TASK_REQUEST *task_request;
  149         SCI_STATUS status;
  150 
  151         if (remote_device->is_resetting == TRUE) {
  152                 /* device is already being reset, so return immediately */
  153                 return;
  154         }
  155 
  156         if (sci_pool_empty(controller->request_pool)) {
  157                 /* No requests are available in our request pool.  If this reset is tied
  158                  *  to a CCB, ask CAM to requeue it.  Otherwise, we need to put it on our
  159                  *  pending device reset list, so that the reset will occur when a request
  160                  *  frees up.
  161                  */
  162                 if (ccb == NULL)
  163                         sci_fast_list_insert_tail(
  164                             &controller->pending_device_reset_list,
  165                             &remote_device->pending_device_reset_element);
  166                 else {
  167                         ccb->ccb_h.status &= ~CAM_STATUS_MASK;
  168                         ccb->ccb_h.status |= CAM_REQUEUE_REQ;
  169                         xpt_done(ccb);
  170                 }
  171                 return;
  172         }
  173 
  174         isci_log_message(0, "ISCI",
  175             "Sending reset to device on controller %d domain %d CAM index %d\n",
  176             controller->index, remote_device->domain->index,
  177             remote_device->index
  178         );
  179 
  180         sci_pool_get(controller->request_pool, request);
  181         task_request = (struct ISCI_TASK_REQUEST *)request;
  182 
  183         task_request->parent.remote_device_handle = remote_device->sci_object;
  184         task_request->ccb = ccb;
  185 
  186         remote_device->is_resetting = TRUE;
  187 
  188         status = (SCI_STATUS) scif_task_request_construct(
  189             controller->scif_controller_handle, remote_device->sci_object,
  190             SCI_CONTROLLER_INVALID_IO_TAG, (void *)task_request,
  191             (void *)((char*)task_request + sizeof(struct ISCI_TASK_REQUEST)),
  192             &task_request->sci_object);
  193 
  194         if (status != SCI_SUCCESS) {
  195                 isci_task_request_complete(controller->scif_controller_handle,
  196                     remote_device->sci_object, task_request->sci_object,
  197                     (SCI_TASK_STATUS)status);
  198                 return;
  199         }
  200 
  201         status = (SCI_STATUS)scif_controller_start_task(
  202             controller->scif_controller_handle, remote_device->sci_object,
  203             task_request->sci_object, SCI_CONTROLLER_INVALID_IO_TAG);
  204 
  205         if (status != SCI_SUCCESS) {
  206                 isci_task_request_complete(
  207                     controller->scif_controller_handle,
  208                     remote_device->sci_object, task_request->sci_object,
  209                     (SCI_TASK_STATUS)status);
  210                 return;
  211         }
  212 }
  213 
  214 uint32_t
  215 isci_remote_device_get_bitrate(struct ISCI_REMOTE_DEVICE *remote_device)
  216 {
  217         struct ISCI_DOMAIN *domain = remote_device->domain;
  218         struct ISCI_CONTROLLER *controller = domain->controller;
  219         SCI_PORT_HANDLE_T port_handle;
  220         SCIC_PORT_PROPERTIES_T port_properties;
  221         uint8_t phy_index;
  222         SCI_PHY_HANDLE_T phy_handle;
  223         SCIC_PHY_PROPERTIES_T phy_properties;
  224 
  225         /* get a handle to the port associated with this remote device's
  226          *  domain
  227          */
  228         port_handle = scif_domain_get_scic_port_handle(domain->sci_object);
  229         scic_port_get_properties(port_handle, &port_properties);
  230 
  231         /* get the lowest numbered phy in the port */
  232         phy_index = 0;
  233         while ((port_properties.phy_mask != 0) &&
  234             !(port_properties.phy_mask & 0x1)) {
  235 
  236                 phy_index++;
  237                 port_properties.phy_mask >>= 1;
  238         }
  239 
  240         /* get the properties for the lowest numbered phy */
  241         scic_controller_get_phy_handle(
  242             scif_controller_get_scic_handle(controller->scif_controller_handle),
  243             phy_index, &phy_handle);
  244         scic_phy_get_properties(phy_handle, &phy_properties);
  245 
  246         switch (phy_properties.negotiated_link_rate) {
  247         case SCI_SAS_150_GB:
  248                 return (150000);
  249         case SCI_SAS_300_GB:
  250                 return (300000);
  251         case SCI_SAS_600_GB:
  252                 return (600000);
  253         default:
  254                 return (0);
  255         }
  256 }
  257 
  258 void
  259 isci_remote_device_freeze_lun_queue(struct ISCI_REMOTE_DEVICE *remote_device,
  260     lun_id_t lun)
  261 {
  262         if (!(remote_device->frozen_lun_mask & (1 << lun))) {
  263                 struct cam_path *path;
  264 
  265                 xpt_create_path(&path, xpt_periph,
  266                     cam_sim_path(remote_device->domain->controller->sim),
  267                     remote_device->index, lun);
  268                 xpt_freeze_devq(path, 1);
  269                 xpt_free_path(path);
  270                 remote_device->frozen_lun_mask |= (1 << lun);
  271         }
  272 }
  273 
  274 void
  275 isci_remote_device_release_lun_queue(struct ISCI_REMOTE_DEVICE *remote_device,
  276     lun_id_t lun)
  277 {
  278         if (remote_device->frozen_lun_mask & (1 << lun)) {
  279                 struct cam_path *path;
  280 
  281                 remote_device->frozen_lun_mask &= ~(1 << lun);
  282                 xpt_create_path(&path, xpt_periph,
  283                     cam_sim_path(remote_device->domain->controller->sim),
  284                     remote_device->index, lun);
  285                 xpt_release_devq(path, 1, TRUE);
  286                 xpt_free_path(path);
  287         }
  288 }
  289 
  290 void
  291 isci_remote_device_release_device_queue(
  292     struct ISCI_REMOTE_DEVICE *device)
  293 {
  294         if (TAILQ_EMPTY(&device->queued_ccbs)) {
  295                 lun_id_t lun;
  296 
  297                 for (lun = 0; lun < ISCI_MAX_LUN; lun++)
  298                         isci_remote_device_release_lun_queue(device, lun);
  299         } else {
  300                 /*
  301                  * We cannot unfreeze the devq, because there are still
  302                  *  CCBs in our internal queue that need to be processed
  303                  *  first.  Mark this device, and the controller, so that
  304                  *  the first CCB in this device's internal queue will be
  305                  *  resubmitted after the current completion context
  306                  *  unwinds.
  307                  */
  308                 device->release_queued_ccb = TRUE;
  309                 device->domain->controller->release_queued_ccbs = TRUE;
  310 
  311                 isci_log_message(1, "ISCI", "schedule %p for release\n",
  312                     device);
  313         }
  314 }

Cache object: 25d0ce28156a05daafb44923732b0b9d


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.