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