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_task_request.h>
40#include <dev/isci/scil/scif_controller.h>
41#include <dev/isci/scil/scif_domain.h>
42#include <dev/isci/scil/scif_user_callback.h>
43
44#include <dev/isci/scil/scic_port.h>
45#include <dev/isci/scil/scic_phy.h>
46
47/**
48 * @brief This callback method informs the framework user that the remote
49 *        device is ready and capable of processing IO requests.
50 *
51 * @param[in]  controller This parameter specifies the controller object
52 *             with which this callback is associated.
53 * @param[in]  domain This parameter specifies the domain object with
54 *             which this callback is associated.
55 * @param[in]  remote_device This parameter specifies the device object with
56 *             which this callback is associated.
57 *
58 * @return none
59 */
60void
61scif_cb_remote_device_ready(SCI_CONTROLLER_HANDLE_T controller,
62    SCI_DOMAIN_HANDLE_T domain, SCI_REMOTE_DEVICE_HANDLE_T remote_device)
63{
64	struct ISCI_REMOTE_DEVICE *isci_remote_device =
65	    sci_object_get_association(remote_device);
66	struct ISCI_CONTROLLER *isci_controller =
67	    sci_object_get_association(controller);
68	uint32_t device_index = isci_remote_device->index;
69
70	if (isci_controller->remote_device[device_index] == NULL) {
71		/* This new device is now ready, so put it in the controller's
72		 *  remote device list so it is visible to CAM.
73		 */
74		isci_controller->remote_device[device_index] =
75		    isci_remote_device;
76
77		if (isci_controller->has_been_scanned) {
78			/* The sim object has been scanned at least once
79			 *  already.  In that case, create a CCB to instruct
80			 *  CAM to rescan this device.
81			 * If the sim object has not been scanned, this device
82			 *  will get scanned as part of the initial scan.
83			 */
84			union ccb *ccb = xpt_alloc_ccb_nowait();
85
86			xpt_create_path(&ccb->ccb_h.path, NULL,
87			    cam_sim_path(isci_controller->sim),
88			    isci_remote_device->index, CAM_LUN_WILDCARD);
89
90			xpt_rescan(ccb);
91		}
92	}
93
94	isci_remote_device_release_device_queue(isci_remote_device);
95}
96
97/**
98 * @brief This callback method informs the framework user that the remote
99 *              device is not ready.  Thus, it is incapable of processing IO
100 *              requests.
101 *
102 * @param[in]  controller This parameter specifies the controller object
103 *             with which this callback is associated.
104 * @param[in]  domain This parameter specifies the domain object with
105 *             which this callback is associated.
106 * @param[in]  remote_device This parameter specifies the device object with
107 *             which this callback is associated.
108 *
109 * @return none
110 */
111void
112scif_cb_remote_device_not_ready(SCI_CONTROLLER_HANDLE_T controller,
113    SCI_DOMAIN_HANDLE_T domain, SCI_REMOTE_DEVICE_HANDLE_T remote_device)
114{
115
116}
117
118/**
119 * @brief This callback method informs the framework user that the remote
120 *        device failed.  This typically occurs shortly after the device
121 *        has been discovered, during the configuration phase for the device.
122 *
123 * @param[in]  controller This parameter specifies the controller object
124 *             with which this callback is associated.
125 * @param[in]  domain This parameter specifies the domain object with
126 *             which this callback is associated.
127 * @param[in]  remote_device This parameter specifies the device object with
128 *             which this callback is associated.
129 * @param[in]  status This parameter specifies the specific failure condition
130 *             associated with this device failure.
131 *
132 * @return none
133 */
134void
135scif_cb_remote_device_failed(SCI_CONTROLLER_HANDLE_T controller,
136    SCI_DOMAIN_HANDLE_T domain, SCI_REMOTE_DEVICE_HANDLE_T remote_device,
137    SCI_STATUS status)
138{
139
140}
141
142void
143isci_remote_device_reset(struct ISCI_REMOTE_DEVICE *remote_device,
144    union ccb *ccb)
145{
146	struct ISCI_CONTROLLER *controller = remote_device->domain->controller;
147	struct ISCI_REQUEST *request;
148	struct ISCI_TASK_REQUEST *task_request;
149	SCI_STATUS status;
150
151	if (remote_device->is_resetting == TRUE) {
152		/* device is already being reset, so return immediately */
153		return;
154	}
155
156	if (sci_pool_empty(controller->request_pool)) {
157		/* No requests are available in our request pool.  If this reset is tied
158		 *  to a CCB, ask CAM to requeue it.  Otherwise, we need to put it on our
159		 *  pending device reset list, so that the reset will occur when a request
160		 *  frees up.
161		 */
162		if (ccb == NULL)
163			sci_fast_list_insert_tail(
164			    &controller->pending_device_reset_list,
165			    &remote_device->pending_device_reset_element);
166		else {
167			ccb->ccb_h.status &= ~CAM_STATUS_MASK;
168			ccb->ccb_h.status |= CAM_REQUEUE_REQ;
169			xpt_done(ccb);
170		}
171		return;
172	}
173
174	isci_log_message(0, "ISCI",
175	    "Sending reset to device on controller %d domain %d CAM index %d\n",
176	    controller->index, remote_device->domain->index,
177	    remote_device->index
178	);
179
180	sci_pool_get(controller->request_pool, request);
181	task_request = (struct ISCI_TASK_REQUEST *)request;
182
183	task_request->parent.remote_device_handle = remote_device->sci_object;
184	task_request->ccb = ccb;
185
186	remote_device->is_resetting = TRUE;
187
188	status = (SCI_STATUS) scif_task_request_construct(
189	    controller->scif_controller_handle, remote_device->sci_object,
190	    SCI_CONTROLLER_INVALID_IO_TAG, (void *)task_request,
191	    (void *)((char*)task_request + sizeof(struct ISCI_TASK_REQUEST)),
192	    &task_request->sci_object);
193
194	if (status != SCI_SUCCESS) {
195		isci_task_request_complete(controller->scif_controller_handle,
196		    remote_device->sci_object, task_request->sci_object,
197		    (SCI_TASK_STATUS)status);
198		return;
199	}
200
201	status = (SCI_STATUS)scif_controller_start_task(
202	    controller->scif_controller_handle, remote_device->sci_object,
203	    task_request->sci_object, SCI_CONTROLLER_INVALID_IO_TAG);
204
205	if (status != SCI_SUCCESS) {
206		isci_task_request_complete(
207		    controller->scif_controller_handle,
208		    remote_device->sci_object, task_request->sci_object,
209		    (SCI_TASK_STATUS)status);
210		return;
211	}
212}
213
214uint32_t
215isci_remote_device_get_bitrate(struct ISCI_REMOTE_DEVICE *remote_device)
216{
217	struct ISCI_DOMAIN *domain = remote_device->domain;
218	struct ISCI_CONTROLLER *controller = domain->controller;
219	SCI_PORT_HANDLE_T port_handle;
220	SCIC_PORT_PROPERTIES_T port_properties;
221	uint8_t phy_index;
222	SCI_PHY_HANDLE_T phy_handle;
223	SCIC_PHY_PROPERTIES_T phy_properties;
224
225	/* get a handle to the port associated with this remote device's
226	 *  domain
227	 */
228	port_handle = scif_domain_get_scic_port_handle(domain->sci_object);
229	scic_port_get_properties(port_handle, &port_properties);
230
231	/* get the lowest numbered phy in the port */
232	phy_index = 0;
233	while ((port_properties.phy_mask != 0) &&
234	    !(port_properties.phy_mask & 0x1)) {
235
236		phy_index++;
237		port_properties.phy_mask >>= 1;
238	}
239
240	/* get the properties for the lowest numbered phy */
241	scic_controller_get_phy_handle(
242	    scif_controller_get_scic_handle(controller->scif_controller_handle),
243	    phy_index, &phy_handle);
244	scic_phy_get_properties(phy_handle, &phy_properties);
245
246	switch (phy_properties.negotiated_link_rate) {
247	case SCI_SAS_150_GB:
248		return (150000);
249	case SCI_SAS_300_GB:
250		return (300000);
251	case SCI_SAS_600_GB:
252		return (600000);
253	default:
254		return (0);
255	}
256}
257
258void
259isci_remote_device_freeze_lun_queue(struct ISCI_REMOTE_DEVICE *remote_device,
260    lun_id_t lun)
261{
262	if (!(remote_device->frozen_lun_mask & (1 << lun))) {
263		struct cam_path *path;
264
265		xpt_create_path(&path, NULL,
266		    cam_sim_path(remote_device->domain->controller->sim),
267		    remote_device->index, lun);
268		xpt_freeze_devq(path, 1);
269		xpt_free_path(path);
270		remote_device->frozen_lun_mask |= (1 << lun);
271	}
272}
273
274void
275isci_remote_device_release_lun_queue(struct ISCI_REMOTE_DEVICE *remote_device,
276    lun_id_t lun)
277{
278	if (remote_device->frozen_lun_mask & (1 << lun)) {
279		struct cam_path *path;
280
281		remote_device->frozen_lun_mask &= ~(1 << lun);
282		xpt_create_path(&path, NULL,
283		    cam_sim_path(remote_device->domain->controller->sim),
284		    remote_device->index, lun);
285		xpt_release_devq(path, 1, TRUE);
286		xpt_free_path(path);
287	}
288}
289
290void
291isci_remote_device_release_device_queue(
292    struct ISCI_REMOTE_DEVICE *device)
293{
294	if (TAILQ_EMPTY(&device->queued_ccbs)) {
295		lun_id_t lun;
296
297		for (lun = 0; lun < ISCI_MAX_LUN; lun++)
298			isci_remote_device_release_lun_queue(device, lun);
299	} else {
300		/*
301		 * We cannot unfreeze the devq, because there are still
302		 *  CCBs in our internal queue that need to be processed
303		 *  first.  Mark this device, and the controller, so that
304		 *  the first CCB in this device's internal queue will be
305		 *  resubmitted after the current completion context
306		 *  unwinds.
307		 */
308		device->release_queued_ccb = TRUE;
309		device->domain->controller->release_queued_ccbs = TRUE;
310
311		isci_log_message(1, "ISCI", "schedule %p for release\n",
312		    device);
313	}
314}
315