xref: /freebsd/sys/dev/isci/isci_remote_device.c (revision b7c60aadbbd5c846a250c05791fe7406d6d78bf4)
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->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.
84 			 */
85 			union ccb *ccb = xpt_alloc_ccb_nowait();
86 
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);
90 
91 			xpt_rescan(ccb);
92 		}
93 	}
94 
95 	isci_remote_device_release_device_queue(isci_remote_device);
96 }
97 
98 /**
99  * @brief This callback method informs the framework user that the remote
100  *              device is not ready.  Thus, it is incapable of processing IO
101  *              requests.
102  *
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.
109  *
110  * @return none
111  */
112 void
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)
115 {
116 
117 }
118 
119 /**
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.
123  *
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.
132  *
133  * @return none
134  */
135 void
136 scif_cb_remote_device_failed(SCI_CONTROLLER_HANDLE_T controller,
137     SCI_DOMAIN_HANDLE_T domain, SCI_REMOTE_DEVICE_HANDLE_T remote_device,
138     SCI_STATUS status)
139 {
140 
141 }
142 
143 void
144 isci_remote_device_reset(struct ISCI_REMOTE_DEVICE *remote_device,
145     union ccb *ccb)
146 {
147 	struct ISCI_CONTROLLER *controller = remote_device->domain->controller;
148 	struct ISCI_REQUEST *request;
149 	struct ISCI_TASK_REQUEST *task_request;
150 	SCI_STATUS status;
151 
152 	if (remote_device->is_resetting == TRUE) {
153 		/* device is already being reset, so return immediately */
154 		return;
155 	}
156 
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
161 		 *  frees up.
162 		 */
163 		if (ccb == NULL)
164 			sci_fast_list_insert_tail(
165 			    &controller->pending_device_reset_list,
166 			    &remote_device->pending_device_reset_element);
167 		else {
168 			ccb->ccb_h.status &= ~CAM_STATUS_MASK;
169 			ccb->ccb_h.status |= CAM_REQUEUE_REQ;
170 			xpt_done(ccb);
171 		}
172 		return;
173 	}
174 
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,
178 	    remote_device->index
179 	);
180 
181 	sci_pool_get(controller->request_pool, request);
182 	task_request = (struct ISCI_TASK_REQUEST *)request;
183 
184 	task_request->parent.remote_device_handle = remote_device->sci_object;
185 	task_request->ccb = ccb;
186 
187 	remote_device->is_resetting = TRUE;
188 
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);
194 
195 	if (status != SCI_SUCCESS) {
196 		isci_task_request_complete(controller->scif_controller_handle,
197 		    remote_device->sci_object, task_request->sci_object,
198 		    status);
199 		return;
200 	}
201 
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);
205 
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 		    status);
211 		return;
212 	}
213 }
214 
215 uint32_t
216 isci_remote_device_get_bitrate(struct ISCI_REMOTE_DEVICE *remote_device)
217 {
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;
222 	uint8_t phy_index;
223 	SCI_PHY_HANDLE_T phy_handle;
224 	SCIC_PHY_PROPERTIES_T phy_properties;
225 
226 	/* get a handle to the port associated with this remote device's
227 	 *  domain
228 	 */
229 	port_handle = scif_domain_get_scic_port_handle(domain->sci_object);
230 	scic_port_get_properties(port_handle, &port_properties);
231 
232 	/* get the lowest numbered phy in the port */
233 	phy_index = 0;
234 	while ((port_properties.phy_mask != 0) &&
235 	    !(port_properties.phy_mask & 0x1)) {
236 
237 		phy_index++;
238 		port_properties.phy_mask >>= 1;
239 	}
240 
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);
246 
247 	switch (phy_properties.negotiated_link_rate) {
248 	case SCI_SAS_150_GB:
249 		return (150000);
250 	case SCI_SAS_300_GB:
251 		return (300000);
252 	case SCI_SAS_600_GB:
253 		return (600000);
254 	default:
255 		return (0);
256 	}
257 }
258 
259 void
260 isci_remote_device_freeze_lun_queue(struct ISCI_REMOTE_DEVICE *remote_device,
261     lun_id_t lun)
262 {
263 	if (!(remote_device->frozen_lun_mask & (1 << lun))) {
264 		struct cam_path *path;
265 
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);
270 		xpt_free_path(path);
271 		remote_device->frozen_lun_mask |= (1 << lun);
272 	}
273 }
274 
275 void
276 isci_remote_device_release_lun_queue(struct ISCI_REMOTE_DEVICE *remote_device,
277     lun_id_t lun)
278 {
279 	if (remote_device->frozen_lun_mask & (1 << lun)) {
280 		struct cam_path *path;
281 
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 		remote_device->frozen_lun_mask &= ~(1 << lun);
288 	}
289 }
290 
291 void
292 isci_remote_device_release_device_queue(
293     struct ISCI_REMOTE_DEVICE *remote_device)
294 {
295 	lun_id_t lun;
296 	for (lun = 0; lun < ISCI_MAX_LUN; lun++)
297 		isci_remote_device_release_lun_queue(remote_device, lun);
298 }
299