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$");
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_task_request.h>
40230557Sjimharris#include <dev/isci/scil/scif_controller.h>
41230557Sjimharris#include <dev/isci/scil/scif_domain.h>
42230557Sjimharris#include <dev/isci/scil/scif_user_callback.h>
43230557Sjimharris
44230557Sjimharris#include <dev/isci/scil/scic_port.h>
45230557Sjimharris#include <dev/isci/scil/scic_phy.h>
46230557Sjimharris
47230557Sjimharris/**
48230557Sjimharris * @brief This callback method informs the framework user that the remote
49230557Sjimharris *        device is ready and capable of processing IO requests.
50230557Sjimharris *
51230557Sjimharris * @param[in]  controller This parameter specifies the controller object
52230557Sjimharris *             with which this callback is associated.
53230557Sjimharris * @param[in]  domain This parameter specifies the domain object with
54230557Sjimharris *             which this callback is associated.
55230557Sjimharris * @param[in]  remote_device This parameter specifies the device object with
56230557Sjimharris *             which this callback is associated.
57230557Sjimharris *
58230557Sjimharris * @return none
59230557Sjimharris */
60230557Sjimharrisvoid
61230557Sjimharrisscif_cb_remote_device_ready(SCI_CONTROLLER_HANDLE_T controller,
62230557Sjimharris    SCI_DOMAIN_HANDLE_T domain, SCI_REMOTE_DEVICE_HANDLE_T remote_device)
63230557Sjimharris{
64230557Sjimharris	struct ISCI_REMOTE_DEVICE *isci_remote_device =
65230557Sjimharris	    sci_object_get_association(remote_device);
66230557Sjimharris	struct ISCI_CONTROLLER *isci_controller =
67230557Sjimharris	    sci_object_get_association(controller);
68230557Sjimharris	uint32_t device_index = isci_remote_device->index;
69230557Sjimharris
70230557Sjimharris	if (isci_controller->remote_device[device_index] == NULL) {
71230557Sjimharris		/* This new device is now ready, so put it in the controller's
72230557Sjimharris		 *  remote device list so it is visible to CAM.
73230557Sjimharris		 */
74230557Sjimharris		isci_controller->remote_device[device_index] =
75230557Sjimharris		    isci_remote_device;
76230557Sjimharris
77233371Sjimharris		if (isci_controller->has_been_scanned) {
78233371Sjimharris			/* The sim object has been scanned at least once
79233371Sjimharris			 *  already.  In that case, create a CCB to instruct
80233371Sjimharris			 *  CAM to rescan this device.
81233371Sjimharris			 * If the sim object has not been scanned, this device
82233371Sjimharris			 *  will get scanned as part of the initial scan.
83230557Sjimharris			 */
84230557Sjimharris			union ccb *ccb = xpt_alloc_ccb_nowait();
85230557Sjimharris
86249468Smav			xpt_create_path(&ccb->ccb_h.path, NULL,
87230557Sjimharris			    cam_sim_path(isci_controller->sim),
88230557Sjimharris			    isci_remote_device->index, CAM_LUN_WILDCARD);
89230557Sjimharris
90230557Sjimharris			xpt_rescan(ccb);
91230557Sjimharris		}
92230557Sjimharris	}
93230557Sjimharris
94230557Sjimharris	isci_remote_device_release_device_queue(isci_remote_device);
95230557Sjimharris}
96230557Sjimharris
97230557Sjimharris/**
98230557Sjimharris * @brief This callback method informs the framework user that the remote
99230557Sjimharris *              device is not ready.  Thus, it is incapable of processing IO
100230557Sjimharris *              requests.
101230557Sjimharris *
102230557Sjimharris * @param[in]  controller This parameter specifies the controller object
103230557Sjimharris *             with which this callback is associated.
104230557Sjimharris * @param[in]  domain This parameter specifies the domain object with
105230557Sjimharris *             which this callback is associated.
106230557Sjimharris * @param[in]  remote_device This parameter specifies the device object with
107230557Sjimharris *             which this callback is associated.
108230557Sjimharris *
109230557Sjimharris * @return none
110230557Sjimharris */
111230557Sjimharrisvoid
112230557Sjimharrisscif_cb_remote_device_not_ready(SCI_CONTROLLER_HANDLE_T controller,
113230557Sjimharris    SCI_DOMAIN_HANDLE_T domain, SCI_REMOTE_DEVICE_HANDLE_T remote_device)
114230557Sjimharris{
115230557Sjimharris
116230557Sjimharris}
117230557Sjimharris
118230557Sjimharris/**
119230557Sjimharris * @brief This callback method informs the framework user that the remote
120230557Sjimharris *        device failed.  This typically occurs shortly after the device
121230557Sjimharris *        has been discovered, during the configuration phase for the device.
122230557Sjimharris *
123230557Sjimharris * @param[in]  controller This parameter specifies the controller object
124230557Sjimharris *             with which this callback is associated.
125230557Sjimharris * @param[in]  domain This parameter specifies the domain object with
126230557Sjimharris *             which this callback is associated.
127230557Sjimharris * @param[in]  remote_device This parameter specifies the device object with
128230557Sjimharris *             which this callback is associated.
129230557Sjimharris * @param[in]  status This parameter specifies the specific failure condition
130230557Sjimharris *             associated with this device failure.
131230557Sjimharris *
132230557Sjimharris * @return none
133230557Sjimharris */
134230557Sjimharrisvoid
135230557Sjimharrisscif_cb_remote_device_failed(SCI_CONTROLLER_HANDLE_T controller,
136230557Sjimharris    SCI_DOMAIN_HANDLE_T domain, SCI_REMOTE_DEVICE_HANDLE_T remote_device,
137230557Sjimharris    SCI_STATUS status)
138230557Sjimharris{
139230557Sjimharris
140230557Sjimharris}
141230557Sjimharris
142230557Sjimharrisvoid
143230557Sjimharrisisci_remote_device_reset(struct ISCI_REMOTE_DEVICE *remote_device,
144230557Sjimharris    union ccb *ccb)
145230557Sjimharris{
146230557Sjimharris	struct ISCI_CONTROLLER *controller = remote_device->domain->controller;
147230557Sjimharris	struct ISCI_REQUEST *request;
148230557Sjimharris	struct ISCI_TASK_REQUEST *task_request;
149230557Sjimharris	SCI_STATUS status;
150230557Sjimharris
151230557Sjimharris	if (remote_device->is_resetting == TRUE) {
152230557Sjimharris		/* device is already being reset, so return immediately */
153230557Sjimharris		return;
154230557Sjimharris	}
155230557Sjimharris
156230557Sjimharris	if (sci_pool_empty(controller->request_pool)) {
157230557Sjimharris		/* No requests are available in our request pool.  If this reset is tied
158230557Sjimharris		 *  to a CCB, ask CAM to requeue it.  Otherwise, we need to put it on our
159230557Sjimharris		 *  pending device reset list, so that the reset will occur when a request
160230557Sjimharris		 *  frees up.
161230557Sjimharris		 */
162230557Sjimharris		if (ccb == NULL)
163230557Sjimharris			sci_fast_list_insert_tail(
164230557Sjimharris			    &controller->pending_device_reset_list,
165230557Sjimharris			    &remote_device->pending_device_reset_element);
166230557Sjimharris		else {
167230557Sjimharris			ccb->ccb_h.status &= ~CAM_STATUS_MASK;
168230557Sjimharris			ccb->ccb_h.status |= CAM_REQUEUE_REQ;
169230557Sjimharris			xpt_done(ccb);
170230557Sjimharris		}
171230557Sjimharris		return;
172230557Sjimharris	}
173230557Sjimharris
174230557Sjimharris	isci_log_message(0, "ISCI",
175230557Sjimharris	    "Sending reset to device on controller %d domain %d CAM index %d\n",
176230557Sjimharris	    controller->index, remote_device->domain->index,
177230557Sjimharris	    remote_device->index
178230557Sjimharris	);
179230557Sjimharris
180230557Sjimharris	sci_pool_get(controller->request_pool, request);
181230557Sjimharris	task_request = (struct ISCI_TASK_REQUEST *)request;
182230557Sjimharris
183230557Sjimharris	task_request->parent.remote_device_handle = remote_device->sci_object;
184230557Sjimharris	task_request->ccb = ccb;
185230557Sjimharris
186230557Sjimharris	remote_device->is_resetting = TRUE;
187230557Sjimharris
188230557Sjimharris	status = (SCI_STATUS) scif_task_request_construct(
189230557Sjimharris	    controller->scif_controller_handle, remote_device->sci_object,
190230557Sjimharris	    SCI_CONTROLLER_INVALID_IO_TAG, (void *)task_request,
191230557Sjimharris	    (void *)((char*)task_request + sizeof(struct ISCI_TASK_REQUEST)),
192230557Sjimharris	    &task_request->sci_object);
193230557Sjimharris
194230557Sjimharris	if (status != SCI_SUCCESS) {
195230557Sjimharris		isci_task_request_complete(controller->scif_controller_handle,
196230557Sjimharris		    remote_device->sci_object, task_request->sci_object,
197231296Sjimharris		    (SCI_TASK_STATUS)status);
198230557Sjimharris		return;
199230557Sjimharris	}
200230557Sjimharris
201230557Sjimharris	status = (SCI_STATUS)scif_controller_start_task(
202230557Sjimharris	    controller->scif_controller_handle, remote_device->sci_object,
203230557Sjimharris	    task_request->sci_object, SCI_CONTROLLER_INVALID_IO_TAG);
204230557Sjimharris
205230557Sjimharris	if (status != SCI_SUCCESS) {
206230557Sjimharris		isci_task_request_complete(
207230557Sjimharris		    controller->scif_controller_handle,
208230557Sjimharris		    remote_device->sci_object, task_request->sci_object,
209231296Sjimharris		    (SCI_TASK_STATUS)status);
210230557Sjimharris		return;
211230557Sjimharris	}
212230557Sjimharris}
213230557Sjimharris
214230557Sjimharrisuint32_t
215230557Sjimharrisisci_remote_device_get_bitrate(struct ISCI_REMOTE_DEVICE *remote_device)
216230557Sjimharris{
217230557Sjimharris	struct ISCI_DOMAIN *domain = remote_device->domain;
218230557Sjimharris	struct ISCI_CONTROLLER *controller = domain->controller;
219230557Sjimharris	SCI_PORT_HANDLE_T port_handle;
220230557Sjimharris	SCIC_PORT_PROPERTIES_T port_properties;
221230557Sjimharris	uint8_t phy_index;
222230557Sjimharris	SCI_PHY_HANDLE_T phy_handle;
223230557Sjimharris	SCIC_PHY_PROPERTIES_T phy_properties;
224230557Sjimharris
225230557Sjimharris	/* get a handle to the port associated with this remote device's
226230557Sjimharris	 *  domain
227230557Sjimharris	 */
228230557Sjimharris	port_handle = scif_domain_get_scic_port_handle(domain->sci_object);
229230557Sjimharris	scic_port_get_properties(port_handle, &port_properties);
230230557Sjimharris
231230557Sjimharris	/* get the lowest numbered phy in the port */
232230557Sjimharris	phy_index = 0;
233230557Sjimharris	while ((port_properties.phy_mask != 0) &&
234230557Sjimharris	    !(port_properties.phy_mask & 0x1)) {
235230557Sjimharris
236230557Sjimharris		phy_index++;
237230557Sjimharris		port_properties.phy_mask >>= 1;
238230557Sjimharris	}
239230557Sjimharris
240230557Sjimharris	/* get the properties for the lowest numbered phy */
241230557Sjimharris	scic_controller_get_phy_handle(
242230557Sjimharris	    scif_controller_get_scic_handle(controller->scif_controller_handle),
243230557Sjimharris	    phy_index, &phy_handle);
244230557Sjimharris	scic_phy_get_properties(phy_handle, &phy_properties);
245230557Sjimharris
246230557Sjimharris	switch (phy_properties.negotiated_link_rate) {
247230557Sjimharris	case SCI_SAS_150_GB:
248230557Sjimharris		return (150000);
249230557Sjimharris	case SCI_SAS_300_GB:
250230557Sjimharris		return (300000);
251230557Sjimharris	case SCI_SAS_600_GB:
252230557Sjimharris		return (600000);
253230557Sjimharris	default:
254230557Sjimharris		return (0);
255230557Sjimharris	}
256230557Sjimharris}
257230557Sjimharris
258230557Sjimharrisvoid
259230557Sjimharrisisci_remote_device_freeze_lun_queue(struct ISCI_REMOTE_DEVICE *remote_device,
260230557Sjimharris    lun_id_t lun)
261230557Sjimharris{
262230557Sjimharris	if (!(remote_device->frozen_lun_mask & (1 << lun))) {
263230557Sjimharris		struct cam_path *path;
264230557Sjimharris
265249468Smav		xpt_create_path(&path, NULL,
266230557Sjimharris		    cam_sim_path(remote_device->domain->controller->sim),
267230557Sjimharris		    remote_device->index, lun);
268230557Sjimharris		xpt_freeze_devq(path, 1);
269230557Sjimharris		xpt_free_path(path);
270230557Sjimharris		remote_device->frozen_lun_mask |= (1 << lun);
271230557Sjimharris	}
272230557Sjimharris}
273230557Sjimharris
274230557Sjimharrisvoid
275230557Sjimharrisisci_remote_device_release_lun_queue(struct ISCI_REMOTE_DEVICE *remote_device,
276230557Sjimharris    lun_id_t lun)
277230557Sjimharris{
278230557Sjimharris	if (remote_device->frozen_lun_mask & (1 << lun)) {
279230557Sjimharris		struct cam_path *path;
280230557Sjimharris
281239665Sjimharris		remote_device->frozen_lun_mask &= ~(1 << lun);
282249468Smav		xpt_create_path(&path, NULL,
283230557Sjimharris		    cam_sim_path(remote_device->domain->controller->sim),
284230557Sjimharris		    remote_device->index, lun);
285230557Sjimharris		xpt_release_devq(path, 1, TRUE);
286230557Sjimharris		xpt_free_path(path);
287230557Sjimharris	}
288230557Sjimharris}
289230557Sjimharris
290230557Sjimharrisvoid
291230557Sjimharrisisci_remote_device_release_device_queue(
292234106Sjimharris    struct ISCI_REMOTE_DEVICE *device)
293230557Sjimharris{
294234106Sjimharris	if (TAILQ_EMPTY(&device->queued_ccbs)) {
295234106Sjimharris		lun_id_t lun;
296234106Sjimharris
297234106Sjimharris		for (lun = 0; lun < ISCI_MAX_LUN; lun++)
298234106Sjimharris			isci_remote_device_release_lun_queue(device, lun);
299234106Sjimharris	} else {
300235751Sjimharris		/*
301235751Sjimharris		 * We cannot unfreeze the devq, because there are still
302235751Sjimharris		 *  CCBs in our internal queue that need to be processed
303235751Sjimharris		 *  first.  Mark this device, and the controller, so that
304235751Sjimharris		 *  the first CCB in this device's internal queue will be
305235751Sjimharris		 *  resubmitted after the current completion context
306235751Sjimharris		 *  unwinds.
307235751Sjimharris		 */
308235751Sjimharris		device->release_queued_ccb = TRUE;
309235751Sjimharris		device->domain->controller->release_queued_ccbs = TRUE;
310234106Sjimharris
311235751Sjimharris		isci_log_message(1, "ISCI", "schedule %p for release\n",
312235751Sjimharris		    device);
313234106Sjimharris	}
314230557Sjimharris}
315