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