4 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
34 #include <dev/isci/isci.h>
36 #include <cam/cam_periph.h>
37 #include <cam/cam_xpt_periph.h>
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>
44 #include <dev/isci/scil/scic_port.h>
45 #include <dev/isci/scil/scic_phy.h>
48 * @brief This callback method informs the framework user that the remote
49 * device is ready and capable of processing IO requests.
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.
61 scif_cb_remote_device_ready(SCI_CONTROLLER_HANDLE_T controller,
62 SCI_DOMAIN_HANDLE_T domain, SCI_REMOTE_DEVICE_HANDLE_T remote_device)
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;
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.
74 isci_controller->remote_device[device_index] =
77 if (isci_controller->sim != NULL) {
78 /* The sim object is not NULL, meaning we have attached
79 * the controller to CAM already. In that case, create
80 * a CCB to instruct CAM to rescan this device.
81 * If the sim object is NULL, this device will get
82 * scanned as part of the initial scan when the
83 * controller is attached to CAM.
85 union ccb *ccb = xpt_alloc_ccb_nowait();
87 xpt_create_path(&ccb->ccb_h.path, xpt_periph,
88 cam_sim_path(isci_controller->sim),
89 isci_remote_device->index, CAM_LUN_WILDCARD);
95 isci_remote_device_release_device_queue(isci_remote_device);
99 * @brief This callback method informs the framework user that the remote
100 * device is not ready. Thus, it is incapable of processing IO
103 * @param[in] controller This parameter specifies the controller object
104 * with which this callback is associated.
105 * @param[in] domain This parameter specifies the domain object with
106 * which this callback is associated.
107 * @param[in] remote_device This parameter specifies the device object with
108 * which this callback is associated.
113 scif_cb_remote_device_not_ready(SCI_CONTROLLER_HANDLE_T controller,
114 SCI_DOMAIN_HANDLE_T domain, SCI_REMOTE_DEVICE_HANDLE_T remote_device)
120 * @brief This callback method informs the framework user that the remote
121 * device failed. This typically occurs shortly after the device
122 * has been discovered, during the configuration phase for the device.
124 * @param[in] controller This parameter specifies the controller object
125 * with which this callback is associated.
126 * @param[in] domain This parameter specifies the domain object with
127 * which this callback is associated.
128 * @param[in] remote_device This parameter specifies the device object with
129 * which this callback is associated.
130 * @param[in] status This parameter specifies the specific failure condition
131 * associated with this device failure.
136 scif_cb_remote_device_failed(SCI_CONTROLLER_HANDLE_T controller,
137 SCI_DOMAIN_HANDLE_T domain, SCI_REMOTE_DEVICE_HANDLE_T remote_device,
144 isci_remote_device_reset(struct ISCI_REMOTE_DEVICE *remote_device,
147 struct ISCI_CONTROLLER *controller = remote_device->domain->controller;
148 struct ISCI_REQUEST *request;
149 struct ISCI_TASK_REQUEST *task_request;
152 if (remote_device->is_resetting == TRUE) {
153 /* device is already being reset, so return immediately */
157 if (sci_pool_empty(controller->request_pool)) {
158 /* No requests are available in our request pool. If this reset is tied
159 * to a CCB, ask CAM to requeue it. Otherwise, we need to put it on our
160 * pending device reset list, so that the reset will occur when a request
164 sci_fast_list_insert_tail(
165 &controller->pending_device_reset_list,
166 &remote_device->pending_device_reset_element);
168 ccb->ccb_h.status &= ~CAM_STATUS_MASK;
169 ccb->ccb_h.status |= CAM_REQUEUE_REQ;
175 isci_log_message(0, "ISCI",
176 "Sending reset to device on controller %d domain %d CAM index %d\n",
177 controller->index, remote_device->domain->index,
181 sci_pool_get(controller->request_pool, request);
182 task_request = (struct ISCI_TASK_REQUEST *)request;
184 task_request->parent.remote_device_handle = remote_device->sci_object;
185 task_request->ccb = ccb;
187 remote_device->is_resetting = TRUE;
189 status = (SCI_STATUS) scif_task_request_construct(
190 controller->scif_controller_handle, remote_device->sci_object,
191 SCI_CONTROLLER_INVALID_IO_TAG, (void *)task_request,
192 (void *)((char*)task_request + sizeof(struct ISCI_TASK_REQUEST)),
193 &task_request->sci_object);
195 if (status != SCI_SUCCESS) {
196 isci_task_request_complete(controller->scif_controller_handle,
197 remote_device->sci_object, task_request->sci_object,
198 (SCI_TASK_STATUS)status);
202 status = (SCI_STATUS)scif_controller_start_task(
203 controller->scif_controller_handle, remote_device->sci_object,
204 task_request->sci_object, SCI_CONTROLLER_INVALID_IO_TAG);
206 if (status != SCI_SUCCESS) {
207 isci_task_request_complete(
208 controller->scif_controller_handle,
209 remote_device->sci_object, task_request->sci_object,
210 (SCI_TASK_STATUS)status);
216 isci_remote_device_get_bitrate(struct ISCI_REMOTE_DEVICE *remote_device)
218 struct ISCI_DOMAIN *domain = remote_device->domain;
219 struct ISCI_CONTROLLER *controller = domain->controller;
220 SCI_PORT_HANDLE_T port_handle;
221 SCIC_PORT_PROPERTIES_T port_properties;
223 SCI_PHY_HANDLE_T phy_handle;
224 SCIC_PHY_PROPERTIES_T phy_properties;
226 /* get a handle to the port associated with this remote device's
229 port_handle = scif_domain_get_scic_port_handle(domain->sci_object);
230 scic_port_get_properties(port_handle, &port_properties);
232 /* get the lowest numbered phy in the port */
234 while ((port_properties.phy_mask != 0) &&
235 !(port_properties.phy_mask & 0x1)) {
238 port_properties.phy_mask >>= 1;
241 /* get the properties for the lowest numbered phy */
242 scic_controller_get_phy_handle(
243 scif_controller_get_scic_handle(controller->scif_controller_handle),
244 phy_index, &phy_handle);
245 scic_phy_get_properties(phy_handle, &phy_properties);
247 switch (phy_properties.negotiated_link_rate) {
260 isci_remote_device_freeze_lun_queue(struct ISCI_REMOTE_DEVICE *remote_device,
263 if (!(remote_device->frozen_lun_mask & (1 << lun))) {
264 struct cam_path *path;
266 xpt_create_path(&path, xpt_periph,
267 cam_sim_path(remote_device->domain->controller->sim),
268 remote_device->index, lun);
269 xpt_freeze_devq(path, 1);
271 remote_device->frozen_lun_mask |= (1 << lun);
276 isci_remote_device_release_lun_queue(struct ISCI_REMOTE_DEVICE *remote_device,
279 if (remote_device->frozen_lun_mask & (1 << lun)) {
280 struct cam_path *path;
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);
287 remote_device->frozen_lun_mask &= ~(1 << lun);
292 isci_remote_device_release_device_queue(
293 struct ISCI_REMOTE_DEVICE *remote_device)
296 for (lun = 0; lun < ISCI_MAX_LUN; lun++)
297 isci_remote_device_release_lun_queue(remote_device, lun);