1230557Sjimharris/*-
2230557Sjimharris * BSD LICENSE
3230557Sjimharris *
4230557Sjimharris * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
5230557Sjimharris * All rights reserved.
6230557Sjimharris *
7230557Sjimharris * Redistribution and use in source and binary forms, with or without
8230557Sjimharris * modification, are permitted provided that the following conditions
9230557Sjimharris * are met:
10230557Sjimharris *
11230557Sjimharris *   * Redistributions of source code must retain the above copyright
12230557Sjimharris *     notice, this list of conditions and the following disclaimer.
13230557Sjimharris *   * Redistributions in binary form must reproduce the above copyright
14230557Sjimharris *     notice, this list of conditions and the following disclaimer in
15230557Sjimharris *     the documentation and/or other materials provided with the
16230557Sjimharris *     distribution.
17230557Sjimharris *
18230557Sjimharris * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19230557Sjimharris * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20230557Sjimharris * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21230557Sjimharris * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22230557Sjimharris * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23230557Sjimharris * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24230557Sjimharris * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25230557Sjimharris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26230557Sjimharris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27230557Sjimharris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28230557Sjimharris * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29230557Sjimharris */
30230557Sjimharris
31230557Sjimharris#include <sys/cdefs.h>
32230557Sjimharris__FBSDID("$FreeBSD: releng/10.3/sys/dev/isci/isci_domain.c 249468 2013-04-14 09:55:48Z mav $");
33230557Sjimharris
34230557Sjimharris#include <dev/isci/isci.h>
35230557Sjimharris
36230557Sjimharris#include <cam/cam_periph.h>
37230557Sjimharris#include <cam/cam_xpt_periph.h>
38230557Sjimharris
39230557Sjimharris#include <dev/isci/scil/scif_domain.h>
40230557Sjimharris#include <dev/isci/scil/scif_remote_device.h>
41230557Sjimharris#include <dev/isci/scil/scif_controller.h>
42230557Sjimharris#include <dev/isci/scil/scif_user_callback.h>
43230557Sjimharris
44230557Sjimharris/**
45230557Sjimharris * @brief This callback method informs the framework user that something
46230557Sjimharris *        in the supplied domain has changed (e.g. a device was added or
47230557Sjimharris *        removed).
48230557Sjimharris *
49230557Sjimharris * This callback is called by the framework outside of discovery or
50230557Sjimharris * target reset processes.  Specifically, domain changes occurring
51230557Sjimharris * during these processes are handled by the framework.  For example,
52230557Sjimharris * in the case of Serial Attached SCSI, reception of a BROADCAST (CHANGE)
53230557Sjimharris * during discovery will cause discovery to restart.  Thus, discovery
54230557Sjimharris * does not complete until all BCNs are processed. Note, during controller
55230557Sjimharris * stopping/reset process, the framework user should not expect this call
56230557Sjimharris * back.
57230557Sjimharris *
58230557Sjimharris * @param[in]  controller This parameter specifies the controller object
59230557Sjimharris *             with which this callback is associated.
60230557Sjimharris * @param[in]  domain This parameter specifies the domain object with
61230557Sjimharris *             which this callback is associated.
62230557Sjimharris *
63230557Sjimharris * @return none
64230557Sjimharris */
65230557Sjimharrisvoid
66230557Sjimharrisscif_cb_domain_change_notification(SCI_CONTROLLER_HANDLE_T controller,
67230557Sjimharris    SCI_DOMAIN_HANDLE_T domain)
68230557Sjimharris{
69230557Sjimharris	struct ISCI_CONTROLLER *isci_controller =
70230557Sjimharris	    (struct ISCI_CONTROLLER *)sci_object_get_association(controller);
71230557Sjimharris
72230557Sjimharris	/* When the controller start is complete, we will explicitly discover
73230557Sjimharris	 *  all of the domains then.  This is because SCIF will not allow
74230557Sjimharris	 *  any I/O to start until the controller is ready, meaning internal SMP
75230557Sjimharris	 *  requests triggered by domain discovery won't work until the controller
76230557Sjimharris	 *  is ready.
77230557Sjimharris	 */
78230557Sjimharris	if (isci_controller->is_started == TRUE)
79230557Sjimharris	    scif_domain_discover(domain,
80230557Sjimharris	        scif_domain_get_suggested_discover_timeout(domain),
81230557Sjimharris	        DEVICE_TIMEOUT);
82230557Sjimharris}
83230557Sjimharris
84230557Sjimharris/**
85230557Sjimharris * @brief This callback method informs the framework user that a previously
86230557Sjimharris *        requested discovery operation on the domain has completed.
87230557Sjimharris *
88230557Sjimharris * @param[in]  controller This parameter specifies the controller object
89230557Sjimharris *             with which this callback is associated.
90230557Sjimharris * @param[in]  domain This parameter specifies the domain object with
91230557Sjimharris *             which this callback is associated.
92230557Sjimharris * @param[in]  completion_status This parameter indicates the results of the
93230557Sjimharris *             discovery operation.
94230557Sjimharris *
95230557Sjimharris * @return none
96230557Sjimharris */
97230557Sjimharrisvoid
98230557Sjimharrisscif_cb_domain_discovery_complete(SCI_CONTROLLER_HANDLE_T controller,
99230557Sjimharris    SCI_DOMAIN_HANDLE_T domain, SCI_STATUS completion_status)
100230557Sjimharris{
101230557Sjimharris
102230557Sjimharris	if(completion_status != SCI_SUCCESS)
103230557Sjimharris		isci_log_message(0, "ISCI",
104230557Sjimharris		    "scif_cb_domain_discovery_complete status = 0x%x\n",
105230557Sjimharris		    completion_status);
106230557Sjimharris
107230557Sjimharris	isci_controller_domain_discovery_complete(
108230557Sjimharris	    (struct ISCI_CONTROLLER *)sci_object_get_association(controller),
109230557Sjimharris	    (struct ISCI_DOMAIN *) sci_object_get_association(domain));
110230557Sjimharris}
111230557Sjimharris
112230557Sjimharris/**
113230557Sjimharris * @brief This callback method informs the framework user that a previously
114230557Sjimharris *        requested reset operation on the domain has completed.
115230557Sjimharris *
116230557Sjimharris * @param[in]  controller This parameter specifies the controller object
117230557Sjimharris *             with which this callback is associated.
118230557Sjimharris * @param[in]  domain This parameter specifies the domain object with
119230557Sjimharris *             which this callback is associated.
120230557Sjimharris * @param[in]  completion_status This parameter indicates the results of the
121230557Sjimharris *             reset operation.
122230557Sjimharris *
123230557Sjimharris * @return none
124230557Sjimharris */
125230557Sjimharrisvoid
126230557Sjimharrisscif_cb_domain_reset_complete(SCI_CONTROLLER_HANDLE_T controller,
127230557Sjimharris    SCI_DOMAIN_HANDLE_T domain, SCI_STATUS completion_status)
128230557Sjimharris{
129230557Sjimharris
130230557Sjimharris}
131230557Sjimharris
132230557Sjimharris/**
133230557Sjimharris * @brief This callback method informs the framework user that the domain
134230557Sjimharris *        is ready and capable of processing IO requests for devices found
135230557Sjimharris *        inside it.
136230557Sjimharris *
137230557Sjimharris * @param[in]  controller This parameter specifies the controller object
138230557Sjimharris *             with which this callback is associated.
139230557Sjimharris * @param[in]  domain This parameter specifies the domain object with
140230557Sjimharris *             which this callback is associated.
141230557Sjimharris *
142230557Sjimharris * @return none
143230557Sjimharris */
144230557Sjimharrisvoid
145230557Sjimharrisscif_cb_domain_ready(SCI_CONTROLLER_HANDLE_T controller,
146230557Sjimharris    SCI_DOMAIN_HANDLE_T domain)
147230557Sjimharris{
148230557Sjimharris	uint32_t i;
149230557Sjimharris	struct ISCI_DOMAIN *isci_domain = sci_object_get_association(domain);
150230557Sjimharris	struct ISCI_CONTROLLER *isci_controller =
151230557Sjimharris	    sci_object_get_association(controller);
152230557Sjimharris
153230557Sjimharris	for (i = 0; i < SCI_MAX_REMOTE_DEVICES; i++) {
154230557Sjimharris		struct ISCI_REMOTE_DEVICE *remote_device =
155230557Sjimharris		    isci_controller->remote_device[i];
156230557Sjimharris
157230557Sjimharris		if (remote_device != NULL &&
158230557Sjimharris		    remote_device->domain == isci_domain)
159230557Sjimharris			isci_remote_device_release_device_queue(remote_device);
160230557Sjimharris	}
161230557Sjimharris}
162230557Sjimharris
163230557Sjimharris/**
164230557Sjimharris * @brief This callback method informs the framework user that the domain
165230557Sjimharris *        is no longer ready. Thus, it is incapable of processing IO
166230557Sjimharris *        requests for devices found inside it.
167230557Sjimharris *
168230557Sjimharris * @param[in]  controller This parameter specifies the controller object
169230557Sjimharris *             with which this callback is associated.
170230557Sjimharris * @param[in]  domain This parameter specifies the domain object with
171230557Sjimharris *             which this callback is associated.
172230557Sjimharris *
173230557Sjimharris * @return none
174230557Sjimharris */
175230557Sjimharrisvoid
176230557Sjimharrisscif_cb_domain_not_ready(SCI_CONTROLLER_HANDLE_T controller,
177230557Sjimharris    SCI_DOMAIN_HANDLE_T domain)
178230557Sjimharris{
179230557Sjimharris
180230557Sjimharris}
181230557Sjimharris
182230557Sjimharris/**
183230557Sjimharris * @brief This callback method informs the framework user that a new
184230557Sjimharris *        direct attached device was found in the domain.
185230557Sjimharris *
186230557Sjimharris * @param[in]  controller This parameter specifies the controller object
187230557Sjimharris *             with which this callback is associated.
188230557Sjimharris * @param[in]  domain This parameter specifies the domain object with
189230557Sjimharris *             which this callback is associated.
190230557Sjimharris * @param[in]  sas_address This parameter specifies the SAS address of
191230557Sjimharris *             the new device.
192230557Sjimharris * @param[in]  protocols This parameter specifies the protocols
193230557Sjimharris *             supported by the newly discovered device.
194230557Sjimharris *
195230557Sjimharris * @return none
196230557Sjimharris */
197230557Sjimharrisvoid
198230557Sjimharrisscif_cb_domain_da_device_added(SCI_CONTROLLER_HANDLE_T controller,
199230557Sjimharris    SCI_DOMAIN_HANDLE_T domain, SCI_SAS_ADDRESS_T *sas_address,
200230557Sjimharris    SCI_SAS_IDENTIFY_ADDRESS_FRAME_PROTOCOLS_T *protocols)
201230557Sjimharris{
202230557Sjimharris	struct ISCI_REMOTE_DEVICE *remote_device;
203230557Sjimharris	struct ISCI_DOMAIN *isci_domain =
204230557Sjimharris	    (struct ISCI_DOMAIN *)sci_object_get_association(domain);
205230557Sjimharris
206233622Sjimharris	/*
207233622Sjimharris	 * For direct-attached devices, do not pull the device object from
208233622Sjimharris	 *  the pool.  Rather, use the one stored in the domain object which
209233622Sjimharris	 *  will ensure that we always get consistent target ids for direct
210233622Sjimharris	 *  attached devices.
211233622Sjimharris	 */
212233622Sjimharris	remote_device = isci_domain->da_remote_device;
213230557Sjimharris
214230557Sjimharris	scif_remote_device_construct(domain,
215230557Sjimharris	    (uint8_t*)remote_device + sizeof(struct ISCI_REMOTE_DEVICE),
216230557Sjimharris	    &(remote_device->sci_object));
217230557Sjimharris
218230557Sjimharris	sci_object_set_association(remote_device->sci_object, remote_device);
219230557Sjimharris
220230557Sjimharris	scif_remote_device_da_construct(remote_device->sci_object, sas_address,
221230557Sjimharris	    protocols);
222230557Sjimharris
223230557Sjimharris	/* We do not put the device in the ISCI_CONTROLLER's device array yet.
224230557Sjimharris	 *  That will happen once the device becomes ready (see
225230557Sjimharris	 *  scif_cb_remote_device_ready).
226230557Sjimharris	 */
227230557Sjimharris
228230557Sjimharris	remote_device->domain = isci_domain;
229230557Sjimharris}
230230557Sjimharris
231230557Sjimharris/**
232230557Sjimharris * @brief This callback method informs the framework user that a new
233230557Sjimharris *        expander attached device was found in the domain.
234230557Sjimharris *
235230557Sjimharris * @param[in]  controller This parameter specifies the controller object
236230557Sjimharris *             with which this callback is associated.
237230557Sjimharris * @param[in]  domain This parameter specifies the domain object with
238230557Sjimharris *             which this callback is associated.
239230557Sjimharris * @param[in]  containing_device This parameter specifies the remote
240230557Sjimharris *             device that contains the device that was added.
241230557Sjimharris * @param[in]  smp_response This parameter specifies the SMP response
242230557Sjimharris *             data associated with the newly discovered device.
243230557Sjimharris *
244230557Sjimharris * @return none
245230557Sjimharris */
246230557Sjimharrisvoid
247230557Sjimharrisscif_cb_domain_ea_device_added(SCI_CONTROLLER_HANDLE_T controller,
248230557Sjimharris    SCI_DOMAIN_HANDLE_T domain, SCI_REMOTE_DEVICE_HANDLE_T containing_device,
249230557Sjimharris    SMP_RESPONSE_DISCOVER_T *smp_response)
250230557Sjimharris{
251230557Sjimharris	struct ISCI_REMOTE_DEVICE *remote_device;
252230557Sjimharris	struct ISCI_DOMAIN *isci_domain =
253230557Sjimharris		(struct ISCI_DOMAIN *)sci_object_get_association(domain);
254230557Sjimharris	struct ISCI_CONTROLLER *isci_controller =
255230557Sjimharris		(struct ISCI_CONTROLLER *)sci_object_get_association(controller);
256230557Sjimharris
257230557Sjimharris	sci_pool_get(isci_controller->remote_device_pool, remote_device);
258230557Sjimharris
259230557Sjimharris	scif_remote_device_construct( domain,
260230557Sjimharris	    (uint8_t*)remote_device + sizeof(struct ISCI_REMOTE_DEVICE),
261230557Sjimharris	    &(remote_device->sci_object));
262230557Sjimharris
263230557Sjimharris	sci_object_set_association(remote_device->sci_object, remote_device);
264230557Sjimharris
265230557Sjimharris	scif_remote_device_ea_construct(remote_device->sci_object,
266230557Sjimharris	    containing_device, smp_response);
267230557Sjimharris
268230557Sjimharris	/* We do not put the device in the ISCI_CONTROLLER's device array yet.
269230557Sjimharris	 *  That will happen once the device becomes ready (see
270230557Sjimharris	 *  scif_cb_remote_device_ready).
271230557Sjimharris	 */
272230557Sjimharris	remote_device->domain = isci_domain;
273230557Sjimharris}
274230557Sjimharris
275230557Sjimharris/**
276230557Sjimharris * @brief This callback method informs the framework user that a device
277230557Sjimharris *        has been removed from the domain.
278230557Sjimharris *
279230557Sjimharris * @param[in]  controller This parameter specifies the controller object
280230557Sjimharris *             with which this callback is associated.
281230557Sjimharris * @param[in]  domain This parameter specifies the domain object with
282230557Sjimharris *             which this callback is associated.
283230557Sjimharris * @param[in]  remote_device This parameter specifies the device object with
284230557Sjimharris *             which this callback is associated.
285230557Sjimharris *
286230557Sjimharris * @return none
287230557Sjimharris */
288230557Sjimharrisvoid
289230557Sjimharrisscif_cb_domain_device_removed(SCI_CONTROLLER_HANDLE_T controller,
290230557Sjimharris    SCI_DOMAIN_HANDLE_T domain, SCI_REMOTE_DEVICE_HANDLE_T remote_device)
291230557Sjimharris{
292230557Sjimharris	struct ISCI_REMOTE_DEVICE *isci_remote_device =
293230557Sjimharris	    (struct ISCI_REMOTE_DEVICE *)sci_object_get_association(remote_device);
294233622Sjimharris	struct ISCI_DOMAIN *isci_domain =
295233622Sjimharris	    (struct ISCI_DOMAIN *)sci_object_get_association(domain);
296230557Sjimharris	struct ISCI_CONTROLLER *isci_controller =
297230557Sjimharris	    (struct ISCI_CONTROLLER *)sci_object_get_association(controller);
298230557Sjimharris	uint32_t path = cam_sim_path(isci_controller->sim);
299230557Sjimharris	union ccb *ccb = xpt_alloc_ccb_nowait();
300230557Sjimharris
301230557Sjimharris	isci_controller->remote_device[isci_remote_device->index] = NULL;
302230557Sjimharris
303249468Smav	xpt_create_path(&ccb->ccb_h.path, NULL, path,
304230557Sjimharris	    isci_remote_device->index, CAM_LUN_WILDCARD);
305230557Sjimharris
306230557Sjimharris	xpt_rescan(ccb);
307230557Sjimharris
308230557Sjimharris	scif_remote_device_destruct(remote_device);
309230557Sjimharris
310233622Sjimharris	/*
311233622Sjimharris	 * Only put the remote device back into the pool if it was an
312233622Sjimharris	 *  expander-attached device.
313233622Sjimharris	 */
314233622Sjimharris	if (isci_remote_device != isci_domain->da_remote_device)
315233622Sjimharris		sci_pool_put(isci_controller->remote_device_pool,
316233622Sjimharris		    isci_remote_device);
317230557Sjimharris}
318230557Sjimharris
319230557Sjimharrisvoid
320230557Sjimharrisisci_domain_construct(struct ISCI_DOMAIN *domain, uint32_t domain_index,
321230557Sjimharris    struct ISCI_CONTROLLER *controller)
322230557Sjimharris{
323230557Sjimharris
324230557Sjimharris	scif_controller_get_domain_handle( controller->scif_controller_handle,
325230557Sjimharris	    domain_index, &domain->sci_object);
326230557Sjimharris
327230557Sjimharris	domain->index = domain_index;
328230557Sjimharris	domain->controller = controller;
329230557Sjimharris	sci_object_set_association(domain->sci_object, (void *)domain);
330230557Sjimharris}
331