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