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 */
67void
68scif_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 */
99void
100scif_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 */
127void
128scif_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 */
146void
147scif_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 */
177void
178scif_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 */
199void
200scif_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 */
248void
249scif_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 */
290void
291scif_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
321void
322isci_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