isci_domain.c revision 230557
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 */
65void
66scif_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 */
97void
98scif_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 */
125void
126scif_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 */
144void
145scif_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 */
175void
176scif_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 */
197void
198scif_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	struct ISCI_CONTROLLER *isci_controller =
206	    (struct ISCI_CONTROLLER *)sci_object_get_association(controller);
207
208	sci_pool_get(isci_controller->remote_device_pool, remote_device);
209
210	scif_remote_device_construct(domain,
211	    (uint8_t*)remote_device + sizeof(struct ISCI_REMOTE_DEVICE),
212	    &(remote_device->sci_object));
213
214	sci_object_set_association(remote_device->sci_object, remote_device);
215
216	scif_remote_device_da_construct(remote_device->sci_object, sas_address,
217	    protocols);
218
219	/* We do not put the device in the ISCI_CONTROLLER's device array yet.
220	 *  That will happen once the device becomes ready (see
221	 *  scif_cb_remote_device_ready).
222	 */
223
224	remote_device->domain = isci_domain;
225}
226
227/**
228 * @brief This callback method informs the framework user that a new
229 *        expander attached device was found in the domain.
230 *
231 * @param[in]  controller This parameter specifies the controller object
232 *             with which this callback is associated.
233 * @param[in]  domain This parameter specifies the domain object with
234 *             which this callback is associated.
235 * @param[in]  containing_device This parameter specifies the remote
236 *             device that contains the device that was added.
237 * @param[in]  smp_response This parameter specifies the SMP response
238 *             data associated with the newly discovered device.
239 *
240 * @return none
241 */
242void
243scif_cb_domain_ea_device_added(SCI_CONTROLLER_HANDLE_T controller,
244    SCI_DOMAIN_HANDLE_T domain, SCI_REMOTE_DEVICE_HANDLE_T containing_device,
245    SMP_RESPONSE_DISCOVER_T *smp_response)
246{
247	struct ISCI_REMOTE_DEVICE *remote_device;
248	struct ISCI_DOMAIN *isci_domain =
249		(struct ISCI_DOMAIN *)sci_object_get_association(domain);
250	struct ISCI_CONTROLLER *isci_controller =
251		(struct ISCI_CONTROLLER *)sci_object_get_association(controller);
252
253	sci_pool_get(isci_controller->remote_device_pool, remote_device);
254
255	scif_remote_device_construct( domain,
256	    (uint8_t*)remote_device + sizeof(struct ISCI_REMOTE_DEVICE),
257	    &(remote_device->sci_object));
258
259	sci_object_set_association(remote_device->sci_object, remote_device);
260
261	scif_remote_device_ea_construct(remote_device->sci_object,
262	    containing_device, smp_response);
263
264	/* We do not put the device in the ISCI_CONTROLLER's device array yet.
265	 *  That will happen once the device becomes ready (see
266	 *  scif_cb_remote_device_ready).
267	 */
268	remote_device->domain = isci_domain;
269}
270
271/**
272 * @brief This callback method informs the framework user that a device
273 *        has been removed from the domain.
274 *
275 * @param[in]  controller This parameter specifies the controller object
276 *             with which this callback is associated.
277 * @param[in]  domain This parameter specifies the domain object with
278 *             which this callback is associated.
279 * @param[in]  remote_device This parameter specifies the device object with
280 *             which this callback is associated.
281 *
282 * @return none
283 */
284void
285scif_cb_domain_device_removed(SCI_CONTROLLER_HANDLE_T controller,
286    SCI_DOMAIN_HANDLE_T domain, SCI_REMOTE_DEVICE_HANDLE_T remote_device)
287{
288	struct ISCI_REMOTE_DEVICE *isci_remote_device =
289	    (struct ISCI_REMOTE_DEVICE *)sci_object_get_association(remote_device);
290	struct ISCI_CONTROLLER *isci_controller =
291	    (struct ISCI_CONTROLLER *)sci_object_get_association(controller);
292	uint32_t path = cam_sim_path(isci_controller->sim);
293	union ccb *ccb = xpt_alloc_ccb_nowait();
294
295	isci_controller->remote_device[isci_remote_device->index] = NULL;
296
297	xpt_create_path(&ccb->ccb_h.path, xpt_periph, path,
298	    isci_remote_device->index, CAM_LUN_WILDCARD);
299
300	xpt_rescan(ccb);
301
302	scif_remote_device_destruct(remote_device);
303
304	sci_pool_put(isci_controller->remote_device_pool, isci_remote_device);
305}
306
307void
308isci_domain_construct(struct ISCI_DOMAIN *domain, uint32_t domain_index,
309    struct ISCI_CONTROLLER *controller)
310{
311
312	scif_controller_get_domain_handle( controller->scif_controller_handle,
313	    domain_index, &domain->sci_object);
314
315	domain->index = domain_index;
316	domain->controller = controller;
317	sci_object_set_association(domain->sci_object, (void *)domain);
318}
319