]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/dev/isci/isci_remote_device.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / dev / isci / isci_remote_device.c
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$");
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, NULL,
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, NULL,
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, NULL,
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 }