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 #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
scif_cb_remote_device_ready(SCI_CONTROLLER_HANDLE_T controller,SCI_DOMAIN_HANDLE_T domain,SCI_REMOTE_DEVICE_HANDLE_T remote_device)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
scif_cb_remote_device_not_ready(SCI_CONTROLLER_HANDLE_T controller,SCI_DOMAIN_HANDLE_T domain,SCI_REMOTE_DEVICE_HANDLE_T remote_device)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
scif_cb_remote_device_failed(SCI_CONTROLLER_HANDLE_T controller,SCI_DOMAIN_HANDLE_T domain,SCI_REMOTE_DEVICE_HANDLE_T remote_device,SCI_STATUS status)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
isci_remote_device_reset(struct ISCI_REMOTE_DEVICE * remote_device,union ccb * ccb)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
isci_remote_device_get_bitrate(struct ISCI_REMOTE_DEVICE * remote_device)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
isci_remote_device_freeze_lun_queue(struct ISCI_REMOTE_DEVICE * remote_device,lun_id_t lun)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
isci_remote_device_release_lun_queue(struct ISCI_REMOTE_DEVICE * remote_device,lun_id_t lun)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
isci_remote_device_release_device_queue(struct ISCI_REMOTE_DEVICE * device)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 }
315