xref: /freebsd/sys/dev/isci/isci_domain.c (revision c697fb7f)
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_domain.h>
42 #include <dev/isci/scil/scif_remote_device.h>
43 #include <dev/isci/scil/scif_controller.h>
44 #include <dev/isci/scil/scif_user_callback.h>
45 
46 /**
47  * @brief This callback method informs the framework user that something
48  *        in the supplied domain has changed (e.g. a device was added or
49  *        removed).
50  *
51  * This callback is called by the framework outside of discovery or
52  * target reset processes.  Specifically, domain changes occurring
53  * during these processes are handled by the framework.  For example,
54  * in the case of Serial Attached SCSI, reception of a BROADCAST (CHANGE)
55  * during discovery will cause discovery to restart.  Thus, discovery
56  * does not complete until all BCNs are processed. Note, during controller
57  * stopping/reset process, the framework user should not expect this call
58  * back.
59  *
60  * @param[in]  controller This parameter specifies the controller object
61  *             with which this callback is associated.
62  * @param[in]  domain This parameter specifies the domain object with
63  *             which this callback is associated.
64  *
65  * @return none
66  */
67 void
68 scif_cb_domain_change_notification(SCI_CONTROLLER_HANDLE_T controller,
69     SCI_DOMAIN_HANDLE_T domain)
70 {
71 	struct ISCI_CONTROLLER *isci_controller =
72 	    (struct ISCI_CONTROLLER *)sci_object_get_association(controller);
73 
74 	/* When the controller start is complete, we will explicitly discover
75 	 *  all of the domains then.  This is because SCIF will not allow
76 	 *  any I/O to start until the controller is ready, meaning internal SMP
77 	 *  requests triggered by domain discovery won't work until the controller
78 	 *  is ready.
79 	 */
80 	if (isci_controller->is_started == TRUE)
81 	    scif_domain_discover(domain,
82 	        scif_domain_get_suggested_discover_timeout(domain),
83 	        DEVICE_TIMEOUT);
84 }
85 
86 /**
87  * @brief This callback method informs the framework user that a previously
88  *        requested discovery operation on the domain has completed.
89  *
90  * @param[in]  controller This parameter specifies the controller object
91  *             with which this callback is associated.
92  * @param[in]  domain This parameter specifies the domain object with
93  *             which this callback is associated.
94  * @param[in]  completion_status This parameter indicates the results of the
95  *             discovery operation.
96  *
97  * @return none
98  */
99 void
100 scif_cb_domain_discovery_complete(SCI_CONTROLLER_HANDLE_T controller,
101     SCI_DOMAIN_HANDLE_T domain, SCI_STATUS completion_status)
102 {
103 
104 	if(completion_status != SCI_SUCCESS)
105 		isci_log_message(0, "ISCI",
106 		    "scif_cb_domain_discovery_complete status = 0x%x\n",
107 		    completion_status);
108 
109 	isci_controller_domain_discovery_complete(
110 	    (struct ISCI_CONTROLLER *)sci_object_get_association(controller),
111 	    (struct ISCI_DOMAIN *) sci_object_get_association(domain));
112 }
113 
114 /**
115  * @brief This callback method informs the framework user that a previously
116  *        requested reset operation on the domain has completed.
117  *
118  * @param[in]  controller This parameter specifies the controller object
119  *             with which this callback is associated.
120  * @param[in]  domain This parameter specifies the domain object with
121  *             which this callback is associated.
122  * @param[in]  completion_status This parameter indicates the results of the
123  *             reset operation.
124  *
125  * @return none
126  */
127 void
128 scif_cb_domain_reset_complete(SCI_CONTROLLER_HANDLE_T controller,
129     SCI_DOMAIN_HANDLE_T domain, SCI_STATUS completion_status)
130 {
131 
132 }
133 
134 /**
135  * @brief This callback method informs the framework user that the domain
136  *        is ready and capable of processing IO requests for devices found
137  *        inside it.
138  *
139  * @param[in]  controller This parameter specifies the controller object
140  *             with which this callback is associated.
141  * @param[in]  domain This parameter specifies the domain object with
142  *             which this callback is associated.
143  *
144  * @return none
145  */
146 void
147 scif_cb_domain_ready(SCI_CONTROLLER_HANDLE_T controller,
148     SCI_DOMAIN_HANDLE_T domain)
149 {
150 	uint32_t i;
151 	struct ISCI_DOMAIN *isci_domain = sci_object_get_association(domain);
152 	struct ISCI_CONTROLLER *isci_controller =
153 	    sci_object_get_association(controller);
154 
155 	for (i = 0; i < SCI_MAX_REMOTE_DEVICES; i++) {
156 		struct ISCI_REMOTE_DEVICE *remote_device =
157 		    isci_controller->remote_device[i];
158 
159 		if (remote_device != NULL &&
160 		    remote_device->domain == isci_domain)
161 			isci_remote_device_release_device_queue(remote_device);
162 	}
163 }
164 
165 /**
166  * @brief This callback method informs the framework user that the domain
167  *        is no longer ready. Thus, it is incapable of processing IO
168  *        requests for devices found inside it.
169  *
170  * @param[in]  controller This parameter specifies the controller object
171  *             with which this callback is associated.
172  * @param[in]  domain This parameter specifies the domain object with
173  *             which this callback is associated.
174  *
175  * @return none
176  */
177 void
178 scif_cb_domain_not_ready(SCI_CONTROLLER_HANDLE_T controller,
179     SCI_DOMAIN_HANDLE_T domain)
180 {
181 
182 }
183 
184 /**
185  * @brief This callback method informs the framework user that a new
186  *        direct attached device was found in the domain.
187  *
188  * @param[in]  controller This parameter specifies the controller object
189  *             with which this callback is associated.
190  * @param[in]  domain This parameter specifies the domain object with
191  *             which this callback is associated.
192  * @param[in]  sas_address This parameter specifies the SAS address of
193  *             the new device.
194  * @param[in]  protocols This parameter specifies the protocols
195  *             supported by the newly discovered device.
196  *
197  * @return none
198  */
199 void
200 scif_cb_domain_da_device_added(SCI_CONTROLLER_HANDLE_T controller,
201     SCI_DOMAIN_HANDLE_T domain, SCI_SAS_ADDRESS_T *sas_address,
202     SCI_SAS_IDENTIFY_ADDRESS_FRAME_PROTOCOLS_T *protocols)
203 {
204 	struct ISCI_REMOTE_DEVICE *remote_device;
205 	struct ISCI_DOMAIN *isci_domain =
206 	    (struct ISCI_DOMAIN *)sci_object_get_association(domain);
207 
208 	/*
209 	 * For direct-attached devices, do not pull the device object from
210 	 *  the pool.  Rather, use the one stored in the domain object which
211 	 *  will ensure that we always get consistent target ids for direct
212 	 *  attached devices.
213 	 */
214 	remote_device = isci_domain->da_remote_device;
215 
216 	scif_remote_device_construct(domain,
217 	    (uint8_t*)remote_device + sizeof(struct ISCI_REMOTE_DEVICE),
218 	    &(remote_device->sci_object));
219 
220 	sci_object_set_association(remote_device->sci_object, remote_device);
221 
222 	scif_remote_device_da_construct(remote_device->sci_object, sas_address,
223 	    protocols);
224 
225 	/* We do not put the device in the ISCI_CONTROLLER's device array yet.
226 	 *  That will happen once the device becomes ready (see
227 	 *  scif_cb_remote_device_ready).
228 	 */
229 
230 	remote_device->domain = isci_domain;
231 }
232 
233 /**
234  * @brief This callback method informs the framework user that a new
235  *        expander attached device was found in the domain.
236  *
237  * @param[in]  controller This parameter specifies the controller object
238  *             with which this callback is associated.
239  * @param[in]  domain This parameter specifies the domain object with
240  *             which this callback is associated.
241  * @param[in]  containing_device This parameter specifies the remote
242  *             device that contains the device that was added.
243  * @param[in]  smp_response This parameter specifies the SMP response
244  *             data associated with the newly discovered device.
245  *
246  * @return none
247  */
248 void
249 scif_cb_domain_ea_device_added(SCI_CONTROLLER_HANDLE_T controller,
250     SCI_DOMAIN_HANDLE_T domain, SCI_REMOTE_DEVICE_HANDLE_T containing_device,
251     SMP_RESPONSE_DISCOVER_T *smp_response)
252 {
253 	struct ISCI_REMOTE_DEVICE *remote_device;
254 	struct ISCI_DOMAIN *isci_domain =
255 		(struct ISCI_DOMAIN *)sci_object_get_association(domain);
256 	struct ISCI_CONTROLLER *isci_controller =
257 		(struct ISCI_CONTROLLER *)sci_object_get_association(controller);
258 
259 	sci_pool_get(isci_controller->remote_device_pool, remote_device);
260 
261 	scif_remote_device_construct( domain,
262 	    (uint8_t*)remote_device + sizeof(struct ISCI_REMOTE_DEVICE),
263 	    &(remote_device->sci_object));
264 
265 	sci_object_set_association(remote_device->sci_object, remote_device);
266 
267 	scif_remote_device_ea_construct(remote_device->sci_object,
268 	    containing_device, smp_response);
269 
270 	/* We do not put the device in the ISCI_CONTROLLER's device array yet.
271 	 *  That will happen once the device becomes ready (see
272 	 *  scif_cb_remote_device_ready).
273 	 */
274 	remote_device->domain = isci_domain;
275 }
276 
277 /**
278  * @brief This callback method informs the framework user that a device
279  *        has been removed from the domain.
280  *
281  * @param[in]  controller This parameter specifies the controller object
282  *             with which this callback is associated.
283  * @param[in]  domain This parameter specifies the domain object with
284  *             which this callback is associated.
285  * @param[in]  remote_device This parameter specifies the device object with
286  *             which this callback is associated.
287  *
288  * @return none
289  */
290 void
291 scif_cb_domain_device_removed(SCI_CONTROLLER_HANDLE_T controller,
292     SCI_DOMAIN_HANDLE_T domain, SCI_REMOTE_DEVICE_HANDLE_T remote_device)
293 {
294 	struct ISCI_REMOTE_DEVICE *isci_remote_device =
295 	    (struct ISCI_REMOTE_DEVICE *)sci_object_get_association(remote_device);
296 	struct ISCI_DOMAIN *isci_domain =
297 	    (struct ISCI_DOMAIN *)sci_object_get_association(domain);
298 	struct ISCI_CONTROLLER *isci_controller =
299 	    (struct ISCI_CONTROLLER *)sci_object_get_association(controller);
300 	uint32_t path = cam_sim_path(isci_controller->sim);
301 	union ccb *ccb = xpt_alloc_ccb_nowait();
302 
303 	isci_controller->remote_device[isci_remote_device->index] = NULL;
304 
305 	xpt_create_path(&ccb->ccb_h.path, NULL, path,
306 	    isci_remote_device->index, CAM_LUN_WILDCARD);
307 
308 	xpt_rescan(ccb);
309 
310 	scif_remote_device_destruct(remote_device);
311 
312 	/*
313 	 * Only put the remote device back into the pool if it was an
314 	 *  expander-attached device.
315 	 */
316 	if (isci_remote_device != isci_domain->da_remote_device)
317 		sci_pool_put(isci_controller->remote_device_pool,
318 		    isci_remote_device);
319 }
320 
321 void
322 isci_domain_construct(struct ISCI_DOMAIN *domain, uint32_t domain_index,
323     struct ISCI_CONTROLLER *controller)
324 {
325 
326 	scif_controller_get_domain_handle( controller->scif_controller_handle,
327 	    domain_index, &domain->sci_object);
328 
329 	domain->index = domain_index;
330 	domain->controller = controller;
331 	sci_object_set_association(domain->sci_object, (void *)domain);
332 }
333